summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--MAINTAINERS10
-rw-r--r--arch_init.c32
-rw-r--r--audio/spiceaudio.c2
-rw-r--r--audio/wavcapture.c3
-rw-r--r--block-migration.c7
-rw-r--r--block.c213
-rw-r--r--block/curl.c79
-rw-r--r--block/iscsi.c317
-rw-r--r--block/mirror.c2
-rw-r--r--block/qapi.c2
-rw-r--r--block/qcow.c44
-rw-r--r--block/qcow2-cluster.c3
-rw-r--r--block/qcow2.c3
-rw-r--r--block/raw-posix.c2
-rw-r--r--block/rbd.c71
-rw-r--r--block/sheepdog.c153
-rw-r--r--block/ssh.c151
-rw-r--r--block/stream.c4
-rw-r--r--block/vhdx.c9
-rw-r--r--block/vmdk.c8
-rw-r--r--block/vvfat.c43
-rw-r--r--blockdev-nbd.c4
-rw-r--r--blockdev.c84
-rw-r--r--blockjob.c14
-rwxr-xr-xconfigure58
-rw-r--r--default-configs/s390x-softmmu.mak3
-rw-r--r--dma-helpers.c2
-rw-r--r--docs/multiseat.txt102
-rw-r--r--docs/qapi-code-gen.txt194
-rw-r--r--docs/specs/qcow2.txt5
-rw-r--r--hmp-commands.hx8
-rw-r--r--hmp.c21
-rw-r--r--hmp.h6
-rw-r--r--hw/alpha/dp264.c12
-rw-r--r--hw/arm/collie.c10
-rw-r--r--hw/arm/cubieboard.c11
-rw-r--r--hw/arm/digic_boards.c2
-rw-r--r--hw/arm/exynos4_boards.c22
-rw-r--r--hw/arm/gumstix.c6
-rw-r--r--hw/arm/highbank.c24
-rw-r--r--hw/arm/integratorcp.c12
-rw-r--r--hw/arm/kzm.c12
-rw-r--r--hw/arm/mainstone.c14
-rw-r--r--hw/arm/musicpal.c10
-rw-r--r--hw/arm/nseries.c22
-rw-r--r--hw/arm/omap_sx1.c21
-rw-r--r--hw/arm/palm.c10
-rw-r--r--hw/arm/realview.c44
-rw-r--r--hw/arm/spitz.c26
-rw-r--r--hw/arm/stellaris.c19
-rw-r--r--hw/arm/tosa.c10
-rw-r--r--hw/arm/versatilepb.c26
-rw-r--r--hw/arm/vexpress.c21
-rw-r--r--hw/arm/virt.c16
-rw-r--r--hw/arm/xilinx_zynq.c14
-rw-r--r--hw/arm/z2.c10
-rw-r--r--hw/audio/intel-hda.c7
-rw-r--r--hw/block/dataplane/virtio-blk.c18
-rw-r--r--hw/char/escc.c233
-rw-r--r--hw/core/machine.c280
-rw-r--r--hw/core/null-machine.c2
-rw-r--r--hw/core/qdev.c85
-rw-r--r--hw/cris/axis_dev88.c10
-rw-r--r--hw/display/jazz_led.c1
-rw-r--r--hw/display/pxa2xx_lcd.c16
-rw-r--r--hw/i386/pc_piix.c109
-rw-r--r--hw/i386/pc_q35.c67
-rw-r--r--hw/input/hid.c220
-rw-r--r--hw/input/ps2.c166
-rw-r--r--hw/intc/Makefile.objs1
-rw-r--r--hw/intc/s390_flic.c325
-rw-r--r--hw/intc/s390_flic_kvm.c420
-rw-r--r--hw/lm32/lm32_boards.c16
-rw-r--r--hw/lm32/milkymist.c10
-rw-r--r--hw/m68k/an5206.c8
-rw-r--r--hw/m68k/dummy_m68k.c8
-rw-r--r--hw/m68k/mcf5208.c8
-rw-r--r--hw/microblaze/petalogix_ml605_mmu.c8
-rw-r--r--hw/microblaze/petalogix_s3adsp1800_mmu.c8
-rw-r--r--hw/mips/mips_fulong2e.c12
-rw-r--r--hw/mips/mips_jazz.c12
-rw-r--r--hw/mips/mips_malta.c12
-rw-r--r--hw/mips/mips_mipssim.c12
-rw-r--r--hw/mips/mips_r4k.c12
-rw-r--r--hw/misc/Makefile.objs1
-rw-r--r--hw/misc/lm32_sys.c179
-rw-r--r--hw/misc/vfio.c428
-rw-r--r--hw/moxie/moxiesim.c12
-rw-r--r--hw/net/cadence_gem.c2
-rw-r--r--hw/openrisc/openrisc_sim.c8
-rw-r--r--hw/pci/pci.c4
-rw-r--r--hw/ppc/e500.c44
-rw-r--r--hw/ppc/e500.h2
-rw-r--r--hw/ppc/e500plat.c4
-rw-r--r--hw/ppc/mac_newworld.c14
-rw-r--r--hw/ppc/mac_oldworld.c14
-rw-r--r--hw/ppc/mpc8544ds.c4
-rw-r--r--hw/ppc/ppc405_boards.c18
-rw-r--r--hw/ppc/ppc440_bamboo.c12
-rw-r--r--hw/ppc/prep.c14
-rw-r--r--hw/ppc/spapr.c14
-rw-r--r--hw/ppc/virtex_ml507.c16
-rw-r--r--hw/s390x/css.c50
-rw-r--r--hw/s390x/css.h4
-rw-r--r--hw/s390x/s390-virtio-ccw.c10
-rw-r--r--hw/s390x/s390-virtio.c10
-rw-r--r--hw/s390x/virtio-ccw.c237
-rw-r--r--hw/s390x/virtio-ccw.h16
-rw-r--r--hw/scsi/megasas.c85
-rw-r--r--hw/scsi/mfi.h9
-rw-r--r--hw/scsi/scsi-bus.c2
-rw-r--r--hw/scsi/scsi-disk.c16
-rw-r--r--hw/scsi/scsi-generic.c8
-rw-r--r--hw/scsi/virtio-scsi.c3
-rw-r--r--hw/sh4/r2d.c10
-rw-r--r--hw/sh4/shix.c4
-rw-r--r--hw/sparc/leon3.c8
-rw-r--r--hw/sparc/sun4m.c68
-rw-r--r--hw/sparc64/sun4u.c36
-rw-r--r--hw/ssi/ssi.c4
-rw-r--r--hw/timer/mc146818rtc.c41
-rw-r--r--hw/unicore32/puv3.c10
-rw-r--r--hw/usb/core.c21
-rw-r--r--hw/usb/desc.c12
-rw-r--r--hw/usb/dev-hid.c13
-rw-r--r--hw/usb/dev-mtp.c28
-rw-r--r--hw/usb/hcd-ehci.c79
-rw-r--r--hw/usb/hcd-uhci.c36
-rw-r--r--hw/usb/hcd-xhci.c64
-rw-r--r--hw/usb/host-libusb.c149
-rw-r--r--hw/usb/redirect.c137
-rw-r--r--hw/virtio/virtio-balloon.c33
-rw-r--r--hw/xenpv/xen_machine_pv.c8
-rw-r--r--hw/xtensa/xtensa_lx60.c26
-rw-r--r--hw/xtensa/xtensa_sim.c8
-rw-r--r--include/block/block.h40
-rw-r--r--include/block/block_int.h10
-rw-r--r--include/block/blockjob.h3
-rw-r--r--include/exec/def-helper.h274
-rw-r--r--include/exec/exec-all.h4
-rw-r--r--include/exec/helper-gen.h70
-rw-r--r--include/exec/helper-head.h134
-rw-r--r--include/exec/helper-proto.h39
-rw-r--r--include/exec/helper-tcg.h48
-rw-r--r--include/hw/boards.h27
-rw-r--r--include/hw/i386/pc.h4
-rw-r--r--include/hw/input/hid.h4
-rw-r--r--include/hw/qdev-core.h24
-rw-r--r--include/hw/s390x/adapter.h23
-rw-r--r--include/hw/s390x/s390_flic.h65
-rw-r--r--include/hw/ssi.h2
-rw-r--r--include/hw/usb.h1
-rw-r--r--include/hw/usb/ehci-regs.h82
-rw-r--r--include/hw/usb/uhci-regs.h40
-rw-r--r--include/qapi/error.h6
-rw-r--r--include/qapi/qmp/qdict.h3
-rw-r--r--include/qapi/visitor-impl.h8
-rw-r--r--include/qapi/visitor.h5
-rw-r--r--include/qemu-common.h1
-rw-r--r--include/qemu/bswap.h45
-rw-r--r--include/qemu/int128.h5
-rw-r--r--include/qemu/typedefs.h1
-rw-r--r--include/sysemu/kvm.h6
-rw-r--r--include/ui/console.h3
-rw-r--r--include/ui/input.h10
-rw-r--r--iohandler.c1
-rw-r--r--kvm-all.c38
-rw-r--r--kvm-stub.c5
-rw-r--r--libcacard/cac.c38
-rw-r--r--libcacard/card_7816.c16
-rw-r--r--libcacard/event.c2
-rw-r--r--libcacard/vcard.c26
-rw-r--r--libcacard/vcard_emul_nss.c39
-rw-r--r--libcacard/vreader.c31
-rw-r--r--libcacard/vscclient.c11
-rw-r--r--linux-headers/asm-s390/kvm.h28
-rw-r--r--linux-headers/linux/kvm.h7
-rw-r--r--memory.c7
-rw-r--r--monitor.c153
-rw-r--r--nbd.c2
-rw-r--r--net/net.c2
-rw-r--r--pc-bios/bios-256k.binbin262144 -> 262144 bytes
-rw-r--r--pc-bios/bios.binbin131072 -> 131072 bytes
-rw-r--r--pc-bios/vgabios-cirrus.binbin37376 -> 37376 bytes
-rw-r--r--pc-bios/vgabios-qxl.binbin37376 -> 37376 bytes
-rw-r--r--pc-bios/vgabios-stdvga.binbin37376 -> 37376 bytes
-rw-r--r--pc-bios/vgabios-vmware.binbin37376 -> 37376 bytes
-rw-r--r--pc-bios/vgabios.binbin36864 -> 37376 bytes
-rw-r--r--qapi-schema.json54
-rw-r--r--qapi/opts-visitor.c5
-rw-r--r--qapi/qapi-visit-core.c259
-rw-r--r--qapi/qmp-input-visitor.c6
-rw-r--r--qapi/qmp-output-visitor.c6
-rw-r--r--qapi/string-input-visitor.c6
-rw-r--r--qdev-monitor.c16
-rw-r--r--qemu-char.c32
-rw-r--r--qemu-img.c14
-rw-r--r--qemu-io.c22
-rw-r--r--qemu-nbd.c12
-rw-r--r--qemu-nbd.texi2
-rw-r--r--qemu-options.hx77
-rw-r--r--qmp-commands.hx5
-rw-r--r--qobject/qdict.c32
-rw-r--r--qtest.c19
m---------roms/seabios0
-rw-r--r--scripts/qapi-commands.py91
-rw-r--r--scripts/qapi-visit.py232
-rw-r--r--scripts/qapi.py16
-rw-r--r--target-alpha/fpu_helper.c2
-rw-r--r--target-alpha/helper.c2
-rw-r--r--target-alpha/helper.h4
-rw-r--r--target-alpha/int_helper.c2
-rw-r--r--target-alpha/mem_helper.c2
-rw-r--r--target-alpha/sys_helper.c2
-rw-r--r--target-alpha/translate.c5
-rw-r--r--target-arm/cpu.c2
-rw-r--r--target-arm/cpu.h22
-rw-r--r--target-arm/crypto_helper.c2
-rw-r--r--target-arm/helper-a64.c14
-rw-r--r--target-arm/helper.c115
-rw-r--r--target-arm/helper.h4
-rw-r--r--target-arm/internals.h25
-rw-r--r--target-arm/iwmmxt_helper.c2
-rw-r--r--target-arm/kvm64.c4
-rw-r--r--target-arm/machine.c10
-rw-r--r--target-arm/neon_helper.c2
-rw-r--r--target-arm/op_helper.c22
-rw-r--r--target-arm/translate-a64.c18
-rw-r--r--target-arm/translate.c254
-rw-r--r--target-arm/translate.h5
-rw-r--r--target-cris/helper.h4
-rw-r--r--target-cris/op_helper.c2
-rw-r--r--target-cris/translate.c5
-rw-r--r--target-i386/cc_helper.c2
-rw-r--r--target-i386/excp_helper.c2
-rw-r--r--target-i386/fpu_helper.c2
-rw-r--r--target-i386/helper.h4
-rw-r--r--target-i386/int_helper.c2
-rw-r--r--target-i386/mem_helper.c2
-rw-r--r--target-i386/misc_helper.c2
-rw-r--r--target-i386/seg_helper.c2
-rw-r--r--target-i386/smm_helper.c2
-rw-r--r--target-i386/svm_helper.c2
-rw-r--r--target-i386/translate.c5
-rw-r--r--target-lm32/Makefile.objs1
-rw-r--r--target-lm32/README15
-rw-r--r--target-lm32/cpu.h1
-rw-r--r--target-lm32/helper.c14
-rw-r--r--target-lm32/helper.h4
-rw-r--r--target-lm32/lm32-semi.c215
-rw-r--r--target-lm32/op_helper.c2
-rw-r--r--target-lm32/translate.c5
-rw-r--r--target-m68k/helper.c2
-rw-r--r--target-m68k/helper.h4
-rw-r--r--target-m68k/op_helper.c2
-rw-r--r--target-m68k/translate.c5
-rw-r--r--target-microblaze/helper.h4
-rw-r--r--target-microblaze/op_helper.c2
-rw-r--r--target-microblaze/translate.c6
-rw-r--r--target-mips/dsp_helper.c2
-rw-r--r--target-mips/helper.h6
-rw-r--r--target-mips/lmi_helper.c2
-rw-r--r--target-mips/op_helper.c2
-rw-r--r--target-mips/translate.c5
-rw-r--r--target-moxie/helper.c2
-rw-r--r--target-moxie/helper.h4
-rw-r--r--target-moxie/translate.c5
-rw-r--r--target-openrisc/exception_helper.c2
-rw-r--r--target-openrisc/fpu_helper.c2
-rw-r--r--target-openrisc/helper.h4
-rw-r--r--target-openrisc/int_helper.c2
-rw-r--r--target-openrisc/interrupt_helper.c2
-rw-r--r--target-openrisc/sys_helper.c2
-rw-r--r--target-openrisc/translate.c5
-rw-r--r--target-ppc/excp_helper.c2
-rw-r--r--target-ppc/fpu_helper.c2
-rw-r--r--target-ppc/helper.h4
-rw-r--r--target-ppc/int_helper.c2
-rw-r--r--target-ppc/mem_helper.c2
-rw-r--r--target-ppc/misc_helper.c2
-rw-r--r--target-ppc/mmu-hash32.c2
-rw-r--r--target-ppc/mmu-hash64.c2
-rw-r--r--target-ppc/mmu_helper.c2
-rw-r--r--target-ppc/timebase_helper.c2
-rw-r--r--target-ppc/translate.c5
-rw-r--r--target-s390x/cc_helper.c2
-rw-r--r--target-s390x/cpu-qom.h1
-rw-r--r--target-s390x/fpu_helper.c2
-rw-r--r--target-s390x/helper.c12
-rw-r--r--target-s390x/helper.h4
-rw-r--r--target-s390x/int_helper.c2
-rw-r--r--target-s390x/kvm.c201
-rw-r--r--target-s390x/mem_helper.c2
-rw-r--r--target-s390x/misc_helper.c2
-rw-r--r--target-s390x/translate.c5
-rw-r--r--target-sh4/helper.h4
-rw-r--r--target-sh4/op_helper.c2
-rw-r--r--target-sh4/translate.c5
-rw-r--r--target-sparc/cc_helper.c2
-rw-r--r--target-sparc/fop_helper.c2
-rw-r--r--target-sparc/helper.c2
-rw-r--r--target-sparc/helper.h4
-rw-r--r--target-sparc/int64_helper.c2
-rw-r--r--target-sparc/ldst_helper.c2
-rw-r--r--target-sparc/translate.c5
-rw-r--r--target-sparc/vis_helper.c2
-rw-r--r--target-sparc/win_helper.c2
-rw-r--r--target-unicore32/helper.c2
-rw-r--r--target-unicore32/helper.h3
-rw-r--r--target-unicore32/op_helper.c2
-rw-r--r--target-unicore32/translate.c5
-rw-r--r--target-unicore32/ucf64_helper.c2
-rw-r--r--target-xtensa/helper.h4
-rw-r--r--target-xtensa/op_helper.c2
-rw-r--r--target-xtensa/translate.c9
-rw-r--r--target-xtensa/xtensa-semi.c2
-rw-r--r--tcg-runtime.c40
-rw-r--r--tcg/aarch64/tcg-target.c22
-rw-r--r--tcg/arm/tcg-target.c22
-rw-r--r--tcg/i386/tcg-target.c38
-rw-r--r--tcg/mips/tcg-target.c1849
-rw-r--r--tcg/mips/tcg-target.h14
-rw-r--r--tcg/optimize.c244
-rw-r--r--tcg/s390/tcg-target.c22
-rw-r--r--tcg/sparc/tcg-target.c22
-rw-r--r--tcg/tcg-op.h169
-rw-r--r--tcg/tcg-runtime.h30
-rw-r--r--tcg/tcg.c71
-rw-r--r--tcg/tcg.h6
-rw-r--r--tcg/tci/tcg-target.c3
-rw-r--r--tests/Makefile10
-rw-r--r--tests/check-qdict.c87
-rw-r--r--tests/libqos/pci.c2
-rw-r--r--tests/qapi-schema/include-repetition-sub.json2
-rw-r--r--tests/qapi-schema/include-repetition.err0
-rw-r--r--tests/qapi-schema/include-repetition.exit1
-rw-r--r--tests/qapi-schema/include-repetition.json3
-rw-r--r--tests/qapi-schema/include-repetition.out3
-rwxr-xr-xtests/qemu-iotests/0302
-rwxr-xr-xtests/qemu-iotests/03920
-rw-r--r--tests/qemu-iotests/039.out3
-rw-r--r--tests/qemu-iotests/067.out10
-rwxr-xr-xtests/qemu-iotests/0707
-rw-r--r--tests/qemu-iotests/070.out7
-rwxr-xr-xtests/qemu-iotests/089129
-rw-r--r--tests/qemu-iotests/089.out50
-rwxr-xr-xtests/qemu-iotests/0916
-rwxr-xr-xtests/qemu-iotests/09298
-rw-r--r--tests/qemu-iotests/092.out38
-rw-r--r--tests/qemu-iotests/common.filter1
-rw-r--r--tests/qemu-iotests/group2
-rw-r--r--tests/qemu-iotests/sample_images/test-disk2vhd.vhdx.bz2bin0 -> 1424 bytes
-rw-r--r--tests/qom-test.c15
-rw-r--r--tests/tcg/lm32/Makefile15
-rw-r--r--tests/tcg/lm32/crt.S4
-rw-r--r--tests/tcg/lm32/helper.S65
-rw-r--r--tests/tcg/lm32/macros.inc37
-rw-r--r--tests/tcg/lm32/test_lb.S4
-rw-r--r--tests/tcg/lm32/test_lbu.S4
-rw-r--r--tests/tcg/lm32/test_lh.S4
-rw-r--r--tests/tcg/lm32/test_lhu.S4
-rw-r--r--tests/tcg/lm32/test_lw.S2
-rw-r--r--tests/tcg/lm32/test_sb.S2
-rw-r--r--tests/tcg/lm32/test_scall.S4
-rw-r--r--tests/tcg/lm32/test_sh.S2
-rw-r--r--tests/tcg/lm32/test_sw.S3
-rw-r--r--tests/tcg/xtensa/test_mmu.S246
-rw-r--r--tests/test-qemu-opts.c441
-rw-r--r--tests/test-qmp-input-strict.c28
-rw-r--r--tests/test-qmp-input-visitor.c26
-rw-r--r--tests/test-qmp-output-visitor.c37
-rw-r--r--tests/test-thread-pool.c2
-rw-r--r--tests/test-visitor-serialization.c26
-rw-r--r--tests/usb-hcd-ehci-test.c153
-rw-r--r--thread-pool.c1
-rw-r--r--trace-events32
-rw-r--r--translate-all.c103
-rw-r--r--ui/Makefile.objs3
-rw-r--r--ui/console.c266
-rw-r--r--ui/curses.c14
-rw-r--r--ui/gtk.c1108
-rw-r--r--ui/input-keymap.c198
-rw-r--r--ui/input-legacy.c235
-rw-r--r--ui/input.c164
-rw-r--r--ui/sdl2.c89
-rw-r--r--ui/vnc-enc-tight.c8
-rw-r--r--ui/vnc.c63
-rw-r--r--util/error.c5
-rw-r--r--util/iov.c21
-rw-r--r--util/qemu-sockets.c28
-rw-r--r--vl.c33
392 files changed, 10820 insertions, 5374 deletions
diff --git a/.gitignore b/.gitignore
index 8a5270973e..c658613560 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,7 @@
 /config-host.*
 /config-target.*
 /config.status
+/config-temp
 /trace/generated-tracers.h
 /trace/generated-tracers.c
 /trace/generated-tracers-dtrace.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 97c9fa1f7f..51a6f51842 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -243,8 +243,8 @@ S: Maintained
 F: hw/*/exynos*
 
 Calxeda Highbank
-M: Mark Langsdorf <mark.langsdorf@calxeda.com>
-S: Supported
+M: Rob Herring <robh@kernel.org>
+S: Maintained
 F: hw/arm/highbank.c
 F: hw/net/xgmac.c
 
@@ -659,6 +659,12 @@ S: Supported
 F: hw/block/nvme*
 F: tests/nvme-test.c
 
+megasas
+M: Hannes Reinecke <hare@suse.de>
+S: Supported
+F: hw/scsi/megasas.c
+F: hw/scsi/mfi.h
+
 Xilinx EDK
 M: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
 M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
diff --git a/arch_init.c b/arch_init.c
index 685ba0e268..9f1a174d3a 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -975,12 +975,12 @@ static int load_xbzrle(QEMUFile *f, ram_addr_t addr, void *host)
     xh_len = qemu_get_be16(f);
 
     if (xh_flags != ENCODING_FLAG_XBZRLE) {
-        fprintf(stderr, "Failed to load XBZRLE page - wrong compression!\n");
+        error_report("Failed to load XBZRLE page - wrong compression!");
         return -1;
     }
 
     if (xh_len > TARGET_PAGE_SIZE) {
-        fprintf(stderr, "Failed to load XBZRLE page - len overflow!\n");
+        error_report("Failed to load XBZRLE page - len overflow!");
         return -1;
     }
     /* load data and decode */
@@ -989,7 +989,7 @@ static int load_xbzrle(QEMUFile *f, ram_addr_t addr, void *host)
     /* decode RLE */
     if (xbzrle_decode_buffer(xbzrle_decoded_buf, xh_len, host,
                              TARGET_PAGE_SIZE) == -1) {
-        fprintf(stderr, "Failed to load XBZRLE page - decode error!\n");
+        error_report("Failed to load XBZRLE page - decode error!");
         return -1;
     }
 
@@ -1006,7 +1006,7 @@ static inline void *host_from_stream_offset(QEMUFile *f,
 
     if (flags & RAM_SAVE_FLAG_CONTINUE) {
         if (!block) {
-            fprintf(stderr, "Ack, bad migration stream!\n");
+            error_report("Ack, bad migration stream!");
             return NULL;
         }
 
@@ -1022,7 +1022,7 @@ static inline void *host_from_stream_offset(QEMUFile *f,
             return memory_region_get_ram_ptr(block->mr) + offset;
     }
 
-    fprintf(stderr, "Can't find block %s!\n", id);
+    error_report("Can't find block %s!", id);
     return NULL;
 }
 
@@ -1075,10 +1075,9 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
                 QTAILQ_FOREACH(block, &ram_list.blocks, next) {
                     if (!strncmp(id, block->idstr, sizeof(id))) {
                         if (block->length != length) {
-                            fprintf(stderr,
-                                    "Length mismatch: %s: " RAM_ADDR_FMT
-                                    " in != " RAM_ADDR_FMT "\n", id, length,
-                                    block->length);
+                            error_report("Length mismatch: %s: " RAM_ADDR_FMT
+                                         " in != " RAM_ADDR_FMT, id, length,
+                                         block->length);
                             ret =  -EINVAL;
                             goto done;
                         }
@@ -1087,8 +1086,8 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
                 }
 
                 if (!block) {
-                    fprintf(stderr, "Unknown ramblock \"%s\", cannot "
-                            "accept migration\n", id);
+                    error_report("Unknown ramblock \"%s\", cannot "
+                                 "accept migration", id);
                     ret = -EINVAL;
                     goto done;
                 }
@@ -1243,12 +1242,11 @@ void select_soundhw(const char *optarg)
 
             if (!c->name) {
                 if (l > 80) {
-                    fprintf(stderr,
-                            "Unknown sound card name (too big to show)\n");
+                    error_report("Unknown sound card name (too big to show)");
                 }
                 else {
-                    fprintf(stderr, "Unknown sound card name `%.*s'\n",
-                            (int) l, p);
+                    error_report("Unknown sound card name `%.*s'",
+                                 (int) l, p);
                 }
                 bad_card = 1;
             }
@@ -1271,13 +1269,13 @@ void audio_init(void)
         if (c->enabled) {
             if (c->isa) {
                 if (!isa_bus) {
-                    fprintf(stderr, "ISA bus not available for %s\n", c->name);
+                    error_report("ISA bus not available for %s", c->name);
                     exit(1);
                 }
                 c->init.init_isa(isa_bus);
             } else {
                 if (!pci_bus) {
-                    fprintf(stderr, "PCI bus not available for %s\n", c->name);
+                    error_report("PCI bus not available for %s", c->name);
                     exit(1);
                 }
                 c->init.init_pci(pci_bus);
diff --git a/audio/spiceaudio.c b/audio/spiceaudio.c
index fceee50adb..7b79bedca2 100644
--- a/audio/spiceaudio.c
+++ b/audio/spiceaudio.c
@@ -105,7 +105,7 @@ static int rate_get_samples (struct audio_pcm_info *info, SpiceRateCtl *rate)
     bytes = muldiv64 (ticks, info->bytes_per_second, get_ticks_per_sec ());
     samples = (bytes - rate->bytes_sent) >> info->shift;
     if (samples < 0 || samples > 65536) {
-        fprintf (stderr, "Resetting rate control (%" PRId64 " samples)\n", samples);
+        error_report("Resetting rate control (%" PRId64 " samples)", samples);
         rate_start (rate);
         samples = 0;
     }
diff --git a/audio/wavcapture.c b/audio/wavcapture.c
index 9d94623225..6f6d792691 100644
--- a/audio/wavcapture.c
+++ b/audio/wavcapture.c
@@ -63,8 +63,7 @@ static void wav_destroy (void *opaque)
         }
     doclose:
         if (fclose (wav->f)) {
-            fprintf (stderr, "wav_destroy: fclose failed: %s",
-                     strerror (errno));
+            error_report("wav_destroy: fclose failed: %s", strerror(errno));
         }
     }
 
diff --git a/block-migration.c b/block-migration.c
index 56951e09ae..16562709c8 100644
--- a/block-migration.c
+++ b/block-migration.c
@@ -59,6 +59,7 @@ typedef struct BlkMigDevState {
     unsigned long *aio_bitmap;
     int64_t completed_sectors;
     BdrvDirtyBitmap *dirty_bitmap;
+    Error *blocker;
 } BlkMigDevState;
 
 typedef struct BlkMigBlock {
@@ -361,7 +362,8 @@ static void init_blk_migration_it(void *opaque, BlockDriverState *bs)
         bmds->completed_sectors = 0;
         bmds->shared_base = block_mig_state.shared_base;
         alloc_aio_bitmap(bmds);
-        bdrv_set_in_use(bs, 1);
+        error_setg(&bmds->blocker, "block device is in use by migration");
+        bdrv_op_block_all(bs, bmds->blocker);
         bdrv_ref(bs);
 
         block_mig_state.total_sector_sum += sectors;
@@ -599,7 +601,8 @@ static void blk_mig_cleanup(void)
     blk_mig_lock();
     while ((bmds = QSIMPLEQ_FIRST(&block_mig_state.bmds_list)) != NULL) {
         QSIMPLEQ_REMOVE_HEAD(&block_mig_state.bmds_list, entry);
-        bdrv_set_in_use(bmds->bs, 0);
+        bdrv_op_unblock_all(bmds->bs, bmds->blocker);
+        error_free(bmds->blocker);
         bdrv_unref(bmds->bs);
         g_free(bmds->aio_bitmap);
         g_free(bmds);
diff --git a/block.c b/block.c
index c90c71aa32..310ea89fce 100644
--- a/block.c
+++ b/block.c
@@ -335,6 +335,7 @@ void bdrv_register(BlockDriver *bdrv)
 BlockDriverState *bdrv_new(const char *device_name, Error **errp)
 {
     BlockDriverState *bs;
+    int i;
 
     if (bdrv_find(device_name)) {
         error_setg(errp, "Device with id '%s' already exists",
@@ -353,6 +354,9 @@ BlockDriverState *bdrv_new(const char *device_name, Error **errp)
     if (device_name[0] != '\0') {
         QTAILQ_INSERT_TAIL(&bdrv_states, bs, device_list);
     }
+    for (i = 0; i < BLOCK_OP_TYPE_MAX; i++) {
+        QLIST_INIT(&bs->op_blockers[i]);
+    }
     bdrv_iostatus_disable(bs);
     notifier_list_init(&bs->close_notifiers);
     notifier_with_return_list_init(&bs->before_write_notifiers);
@@ -1090,6 +1094,37 @@ fail:
     return ret;
 }
 
+void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd)
+{
+
+    if (bs->backing_hd) {
+        assert(bs->backing_blocker);
+        bdrv_op_unblock_all(bs->backing_hd, bs->backing_blocker);
+    } else if (backing_hd) {
+        error_setg(&bs->backing_blocker,
+                   "device is used as backing hd of '%s'",
+                   bs->device_name);
+    }
+
+    bs->backing_hd = backing_hd;
+    if (!backing_hd) {
+        error_free(bs->backing_blocker);
+        bs->backing_blocker = NULL;
+        goto out;
+    }
+    bs->open_flags &= ~BDRV_O_NO_BACKING;
+    pstrcpy(bs->backing_file, sizeof(bs->backing_file), backing_hd->filename);
+    pstrcpy(bs->backing_format, sizeof(bs->backing_format),
+            backing_hd->drv ? backing_hd->drv->format_name : "");
+
+    bdrv_op_block_all(bs->backing_hd, bs->backing_blocker);
+    /* Otherwise we won't be able to commit due to check in bdrv_commit */
+    bdrv_op_unblock(bs->backing_hd, BLOCK_OP_TYPE_COMMIT,
+                    bs->backing_blocker);
+out:
+    bdrv_refresh_limits(bs);
+}
+
 /*
  * Opens the backing file for a BlockDriverState if not yet open
  *
@@ -1103,6 +1138,7 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
     char *backing_filename = g_malloc0(PATH_MAX);
     int ret = 0;
     BlockDriver *back_drv = NULL;
+    BlockDriverState *backing_hd;
     Error *local_err = NULL;
 
     if (bs->backing_hd != NULL) {
@@ -1125,30 +1161,26 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
         bdrv_get_full_backing_filename(bs, backing_filename, PATH_MAX);
     }
 
+    backing_hd = bdrv_new("", errp);
+
     if (bs->backing_format[0] != '\0') {
         back_drv = bdrv_find_format(bs->backing_format);
     }
 
     assert(bs->backing_hd == NULL);
-    ret = bdrv_open(&bs->backing_hd,
+    ret = bdrv_open(&backing_hd,
                     *backing_filename ? backing_filename : NULL, NULL, options,
                     bdrv_backing_flags(bs->open_flags), back_drv, &local_err);
     if (ret < 0) {
-        bs->backing_hd = NULL;
+        bdrv_unref(backing_hd);
+        backing_hd = NULL;
         bs->open_flags |= BDRV_O_NO_BACKING;
         error_setg(errp, "Could not open backing file: %s",
                    error_get_pretty(local_err));
         error_free(local_err);
         goto free_exit;
     }
-
-    if (bs->backing_hd->file) {
-        pstrcpy(bs->backing_file, sizeof(bs->backing_file),
-                bs->backing_hd->file->filename);
-    }
-
-    /* Recalculate the BlockLimits with the backing file */
-    bdrv_refresh_limits(bs);
+    bdrv_set_backing_hd(bs, backing_hd);
 
 free_exit:
     g_free(backing_filename);
@@ -1196,6 +1228,7 @@ int bdrv_open_image(BlockDriverState **pbs, const char *filename,
                        bdref_key);
             ret = -EINVAL;
         }
+        QDECREF(image_options);
         goto done;
     }
 
@@ -1274,6 +1307,33 @@ out:
     g_free(tmp_filename);
 }
 
+static QDict *parse_json_filename(const char *filename, Error **errp)
+{
+    QObject *options_obj;
+    QDict *options;
+    int ret;
+
+    ret = strstart(filename, "json:", &filename);
+    assert(ret);
+
+    options_obj = qobject_from_json(filename);
+    if (!options_obj) {
+        error_setg(errp, "Could not parse the JSON options");
+        return NULL;
+    }
+
+    if (qobject_type(options_obj) != QTYPE_QDICT) {
+        qobject_decref(options_obj);
+        error_setg(errp, "Invalid JSON object given");
+        return NULL;
+    }
+
+    options = qobject_to_qdict(options_obj);
+    qdict_flatten(options);
+
+    return options;
+}
+
 /*
  * Opens a disk image (raw, qcow2, vmdk, ...)
  *
@@ -1337,6 +1397,20 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
         options = qdict_new();
     }
 
+    if (filename && g_str_has_prefix(filename, "json:")) {
+        QDict *json_options = parse_json_filename(filename, &local_err);
+        if (local_err) {
+            ret = -EINVAL;
+            goto fail;
+        }
+
+        /* Options given in the filename have lower priority than options
+         * specified directly */
+        qdict_join(options, json_options, false);
+        QDECREF(json_options);
+        filename = NULL;
+    }
+
     bs->options = options;
     options = qdict_clone_shallow(options);
 
@@ -1743,8 +1817,9 @@ void bdrv_close(BlockDriverState *bs)
 
     if (bs->drv) {
         if (bs->backing_hd) {
-            bdrv_unref(bs->backing_hd);
-            bs->backing_hd = NULL;
+            BlockDriverState *backing_hd = bs->backing_hd;
+            bdrv_set_backing_hd(bs, NULL);
+            bdrv_unref(backing_hd);
         }
         bs->drv->bdrv_close(bs);
         g_free(bs->opaque);
@@ -1904,13 +1979,14 @@ static void bdrv_move_feature_fields(BlockDriverState *bs_dest,
     bs_dest->refcnt             = bs_src->refcnt;
 
     /* job */
-    bs_dest->in_use             = bs_src->in_use;
     bs_dest->job                = bs_src->job;
 
     /* keep the same entry in bdrv_states */
     pstrcpy(bs_dest->device_name, sizeof(bs_dest->device_name),
             bs_src->device_name);
     bs_dest->device_list = bs_src->device_list;
+    memcpy(bs_dest->op_blockers, bs_src->op_blockers,
+           sizeof(bs_dest->op_blockers));
 }
 
 /*
@@ -1945,7 +2021,6 @@ void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old)
     assert(QLIST_EMPTY(&bs_new->dirty_bitmaps));
     assert(bs_new->job == NULL);
     assert(bs_new->dev == NULL);
-    assert(bs_new->in_use == 0);
     assert(bs_new->io_limits_enabled == false);
     assert(!throttle_have_timer(&bs_new->throttle_state));
 
@@ -1964,7 +2039,6 @@ void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old)
     /* Check a few fields that should remain attached to the device */
     assert(bs_new->dev == NULL);
     assert(bs_new->job == NULL);
-    assert(bs_new->in_use == 0);
     assert(bs_new->io_limits_enabled == false);
     assert(!throttle_have_timer(&bs_new->throttle_state));
 
@@ -1997,19 +2071,14 @@ void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top)
 
     /* The contents of 'tmp' will become bs_top, as we are
      * swapping bs_new and bs_top contents. */
-    bs_top->backing_hd = bs_new;
-    bs_top->open_flags &= ~BDRV_O_NO_BACKING;
-    pstrcpy(bs_top->backing_file, sizeof(bs_top->backing_file),
-            bs_new->filename);
-    pstrcpy(bs_top->backing_format, sizeof(bs_top->backing_format),
-            bs_new->drv ? bs_new->drv->format_name : "");
+    bdrv_set_backing_hd(bs_top, bs_new);
 }
 
 static void bdrv_delete(BlockDriverState *bs)
 {
     assert(!bs->dev);
     assert(!bs->job);
-    assert(!bs->in_use);
+    assert(bdrv_op_blocker_is_empty(bs));
     assert(!bs->refcnt);
     assert(QLIST_EMPTY(&bs->dirty_bitmaps));
 
@@ -2191,7 +2260,8 @@ int bdrv_commit(BlockDriverState *bs)
         return -ENOTSUP;
     }
 
-    if (bdrv_in_use(bs) || bdrv_in_use(bs->backing_hd)) {
+    if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_COMMIT, NULL) ||
+        bdrv_op_is_blocked(bs->backing_hd, BLOCK_OP_TYPE_COMMIT, NULL)) {
         return -EBUSY;
     }
 
@@ -2595,13 +2665,11 @@ int bdrv_drop_intermediate(BlockDriverState *active, BlockDriverState *top,
     if (ret) {
         goto exit;
     }
-    new_top_bs->backing_hd = base_bs;
-
-    bdrv_refresh_limits(new_top_bs);
+    bdrv_set_backing_hd(new_top_bs, base_bs);
 
     QSIMPLEQ_FOREACH_SAFE(intermediate_state, &states_to_delete, entry, next) {
         /* so that bdrv_close() does not recursively close the chain */
-        intermediate_state->bs->backing_hd = NULL;
+        bdrv_set_backing_hd(intermediate_state->bs, NULL);
         bdrv_unref(intermediate_state->bs);
     }
     ret = 0;
@@ -3248,6 +3316,15 @@ static int coroutine_fn bdrv_aligned_pwritev(BlockDriverState *bs,
 
     ret = notifier_with_return_list_notify(&bs->before_write_notifiers, req);
 
+    if (!ret && bs->detect_zeroes != BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF &&
+        !(flags & BDRV_REQ_ZERO_WRITE) && drv->bdrv_co_write_zeroes &&
+        qemu_iovec_is_zero(qiov)) {
+        flags |= BDRV_REQ_ZERO_WRITE;
+        if (bs->detect_zeroes == BLOCKDEV_DETECT_ZEROES_OPTIONS_UNMAP) {
+            flags |= BDRV_REQ_MAY_UNMAP;
+        }
+    }
+
     if (ret < 0) {
         /* Do nothing, write notifier decided to fail this request */
     } else if (flags & BDRV_REQ_ZERO_WRITE) {
@@ -3444,8 +3521,9 @@ int bdrv_truncate(BlockDriverState *bs, int64_t offset)
         return -ENOTSUP;
     if (bs->read_only)
         return -EACCES;
-    if (bdrv_in_use(bs))
+    if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_RESIZE, NULL)) {
         return -EBUSY;
+    }
     ret = drv->bdrv_truncate(bs, offset);
     if (ret == 0) {
         ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS);
@@ -3864,7 +3942,7 @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
 
     if (!bs->drv->bdrv_co_get_block_status) {
         *pnum = nb_sectors;
-        ret = BDRV_BLOCK_DATA;
+        ret = BDRV_BLOCK_DATA | BDRV_BLOCK_ALLOCATED;
         if (bs->drv->protocol_name) {
             ret |= BDRV_BLOCK_OFFSET_VALID | (sector_num * BDRV_SECTOR_SIZE);
         }
@@ -3883,6 +3961,10 @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
                                      *pnum, pnum);
     }
 
+    if (ret & (BDRV_BLOCK_DATA | BDRV_BLOCK_ZERO)) {
+        ret |= BDRV_BLOCK_ALLOCATED;
+    }
+
     if (!(ret & BDRV_BLOCK_DATA) && !(ret & BDRV_BLOCK_ZERO)) {
         if (bdrv_unallocated_blocks_are_zero(bs)) {
             ret |= BDRV_BLOCK_ZERO;
@@ -3959,9 +4041,7 @@ int coroutine_fn bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num,
     if (ret < 0) {
         return ret;
     }
-    return
-        (ret & BDRV_BLOCK_DATA) ||
-        ((ret & BDRV_BLOCK_ZERO) && !bdrv_has_zero_init(bs));
+    return (ret & BDRV_BLOCK_ALLOCATED);
 }
 
 /*
@@ -5273,15 +5353,74 @@ void bdrv_unref(BlockDriverState *bs)
     }
 }
 
-void bdrv_set_in_use(BlockDriverState *bs, int in_use)
+struct BdrvOpBlocker {
+    Error *reason;
+    QLIST_ENTRY(BdrvOpBlocker) list;
+};
+
+bool bdrv_op_is_blocked(BlockDriverState *bs, BlockOpType op, Error **errp)
 {
-    assert(bs->in_use != in_use);
-    bs->in_use = in_use;
+    BdrvOpBlocker *blocker;
+    assert((int) op >= 0 && op < BLOCK_OP_TYPE_MAX);
+    if (!QLIST_EMPTY(&bs->op_blockers[op])) {
+        blocker = QLIST_FIRST(&bs->op_blockers[op]);
+        if (errp) {
+            error_setg(errp, "Device '%s' is busy: %s",
+                       bs->device_name, error_get_pretty(blocker->reason));
+        }
+        return true;
+    }
+    return false;
 }
 
-int bdrv_in_use(BlockDriverState *bs)
+void bdrv_op_block(BlockDriverState *bs, BlockOpType op, Error *reason)
 {
-    return bs->in_use;
+    BdrvOpBlocker *blocker;
+    assert((int) op >= 0 && op < BLOCK_OP_TYPE_MAX);
+
+    blocker = g_malloc0(sizeof(BdrvOpBlocker));
+    blocker->reason = reason;
+    QLIST_INSERT_HEAD(&bs->op_blockers[op], blocker, list);
+}
+
+void bdrv_op_unblock(BlockDriverState *bs, BlockOpType op, Error *reason)
+{
+    BdrvOpBlocker *blocker, *next;
+    assert((int) op >= 0 && op < BLOCK_OP_TYPE_MAX);
+    QLIST_FOREACH_SAFE(blocker, &bs->op_blockers[op], list, next) {
+        if (blocker->reason == reason) {
+            QLIST_REMOVE(blocker, list);
+            g_free(blocker);
+        }
+    }
+}
+
+void bdrv_op_block_all(BlockDriverState *bs, Error *reason)
+{
+    int i;
+    for (i = 0; i < BLOCK_OP_TYPE_MAX; i++) {
+        bdrv_op_block(bs, i, reason);
+    }
+}
+
+void bdrv_op_unblock_all(BlockDriverState *bs, Error *reason)
+{
+    int i;
+    for (i = 0; i < BLOCK_OP_TYPE_MAX; i++) {
+        bdrv_op_unblock(bs, i, reason);
+    }
+}
+
+bool bdrv_op_blocker_is_empty(BlockDriverState *bs)
+{
+    int i;
+
+    for (i = 0; i < BLOCK_OP_TYPE_MAX; i++) {
+        if (!QLIST_EMPTY(&bs->op_blockers[i])) {
+            return false;
+        }
+    }
+    return true;
 }
 
 void bdrv_iostatus_enable(BlockDriverState *bs)
diff --git a/block/curl.c b/block/curl.c
index d2f1084b91..f491b0ba4c 100644
--- a/block/curl.c
+++ b/block/curl.c
@@ -23,6 +23,7 @@
  */
 #include "qemu-common.h"
 #include "block/block_int.h"
+#include "qapi/qmp/qbool.h"
 #include <curl/curl.h>
 
 // #define DEBUG
@@ -37,6 +38,21 @@
 #if LIBCURL_VERSION_NUM >= 0x071000
 /* The multi interface timer callback was introduced in 7.16.0 */
 #define NEED_CURL_TIMER_CALLBACK
+#define HAVE_SOCKET_ACTION
+#endif
+
+#ifndef HAVE_SOCKET_ACTION
+/* If curl_multi_socket_action isn't available, define it statically here in
+ * terms of curl_multi_socket. Note that ev_bitmask will be ignored, which is
+ * less efficient but still safe. */
+static CURLMcode __curl_multi_socket_action(CURLM *multi_handle,
+                                            curl_socket_t sockfd,
+                                            int ev_bitmask,
+                                            int *running_handles)
+{
+    return curl_multi_socket(multi_handle, sockfd, running_handles);
+}
+#define curl_multi_socket_action __curl_multi_socket_action
 #endif
 
 #define PROTOCOLS (CURLPROTO_HTTP | CURLPROTO_HTTPS | \
@@ -46,12 +62,16 @@
 #define CURL_NUM_STATES 8
 #define CURL_NUM_ACB    8
 #define SECTOR_SIZE     512
-#define READ_AHEAD_SIZE (256 * 1024)
+#define READ_AHEAD_DEFAULT (256 * 1024)
 
 #define FIND_RET_NONE   0
 #define FIND_RET_OK     1
 #define FIND_RET_WAIT   2
 
+#define CURL_BLOCK_OPT_URL       "url"
+#define CURL_BLOCK_OPT_READAHEAD "readahead"
+#define CURL_BLOCK_OPT_SSLVERIFY "sslverify"
+
 struct BDRVCURLState;
 
 typedef struct CURLAIOCB {
@@ -88,6 +108,7 @@ typedef struct BDRVCURLState {
     CURLState states[CURL_NUM_STATES];
     char *url;
     size_t readahead_size;
+    bool sslverify;
     bool accept_range;
 } BDRVCURLState;
 
@@ -354,6 +375,8 @@ static CURLState *curl_init_state(BDRVCURLState *s)
             return NULL;
         }
         curl_easy_setopt(state->curl, CURLOPT_URL, s->url);
+        curl_easy_setopt(state->curl, CURLOPT_SSL_VERIFYPEER,
+                         (long) s->sslverify);
         curl_easy_setopt(state->curl, CURLOPT_TIMEOUT, 5);
         curl_easy_setopt(state->curl, CURLOPT_WRITEFUNCTION,
                          (void *)curl_read_cb);
@@ -396,43 +419,7 @@ static void curl_clean_state(CURLState *s)
 static void curl_parse_filename(const char *filename, QDict *options,
                                 Error **errp)
 {
-
-    #define RA_OPTSTR ":readahead="
-    char *file;
-    char *ra;
-    const char *ra_val;
-    int parse_state = 0;
-
-    file = g_strdup(filename);
-
-    /* Parse a trailing ":readahead=#:" param, if present. */
-    ra = file + strlen(file) - 1;
-    while (ra >= file) {
-        if (parse_state == 0) {
-            if (*ra == ':') {
-                parse_state++;
-            } else {
-                break;
-            }
-        } else if (parse_state == 1) {
-            if (*ra > '9' || *ra < '0') {
-                char *opt_start = ra - strlen(RA_OPTSTR) + 1;
-                if (opt_start > file &&
-                    strncmp(opt_start, RA_OPTSTR, strlen(RA_OPTSTR)) == 0) {
-                    ra_val = ra + 1;
-                    ra -= strlen(RA_OPTSTR) - 1;
-                    *ra = '\0';
-                    qdict_put(options, "readahead", qstring_from_str(ra_val));
-                }
-                break;
-            }
-        }
-        ra--;
-    }
-
-    qdict_put(options, "url", qstring_from_str(file));
-
-    g_free(file);
+    qdict_put(options, CURL_BLOCK_OPT_URL, qstring_from_str(filename));
 }
 
 static QemuOptsList runtime_opts = {
@@ -440,15 +427,20 @@ static QemuOptsList runtime_opts = {
     .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
     .desc = {
         {
-            .name = "url",
+            .name = CURL_BLOCK_OPT_URL,
             .type = QEMU_OPT_STRING,
             .help = "URL to open",
         },
         {
-            .name = "readahead",
+            .name = CURL_BLOCK_OPT_READAHEAD,
             .type = QEMU_OPT_SIZE,
             .help = "Readahead size",
         },
+        {
+            .name = CURL_BLOCK_OPT_SSLVERIFY,
+            .type = QEMU_OPT_BOOL,
+            .help = "Verify SSL certificate"
+        },
         { /* end of list */ }
     },
 };
@@ -477,14 +469,17 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
         goto out_noclean;
     }
 
-    s->readahead_size = qemu_opt_get_size(opts, "readahead", READ_AHEAD_SIZE);
+    s->readahead_size = qemu_opt_get_size(opts, CURL_BLOCK_OPT_READAHEAD,
+                                          READ_AHEAD_DEFAULT);
     if ((s->readahead_size & 0x1ff) != 0) {
         error_setg(errp, "HTTP_READAHEAD_SIZE %zd is not a multiple of 512",
                    s->readahead_size);
         goto out_noclean;
     }
 
-    file = qemu_opt_get(opts, "url");
+    s->sslverify = qemu_opt_get_bool(opts, CURL_BLOCK_OPT_SSLVERIFY, true);
+
+    file = qemu_opt_get(opts, CURL_BLOCK_OPT_URL);
     if (file == NULL) {
         error_setg(errp, "curl block driver requires an 'url' option");
         goto out_noclean;
diff --git a/block/iscsi.c b/block/iscsi.c
index 52355b8bce..3892cc551e 100644
--- a/block/iscsi.c
+++ b/block/iscsi.c
@@ -30,6 +30,8 @@
 #include "qemu-common.h"
 #include "qemu/config-file.h"
 #include "qemu/error-report.h"
+#include "qemu/bitops.h"
+#include "qemu/bitmap.h"
 #include "block/block_int.h"
 #include "trace.h"
 #include "block/scsi.h"
@@ -59,6 +61,8 @@ typedef struct IscsiLun {
     struct scsi_inquiry_logical_block_provisioning lbp;
     struct scsi_inquiry_block_limits bl;
     unsigned char *zeroblock;
+    unsigned long *allocationmap;
+    int cluster_sectors;
 } IscsiLun;
 
 typedef struct IscsiTask {
@@ -92,6 +96,15 @@ typedef struct IscsiAIOCB {
 #define MAX_NOP_FAILURES 3
 #define ISCSI_CMD_RETRIES 5
 
+/* this threshhold is a trade-off knob to choose between
+ * the potential additional overhead of an extra GET_LBA_STATUS request
+ * vs. unnecessarily reading a lot of zero sectors over the wire.
+ * If a read request is greater or equal than ISCSI_CHECKALLOC_THRES
+ * sectors we check the allocation status of the area covered by the
+ * request first if the allocationmap indicates that the area might be
+ * unallocated. */
+#define ISCSI_CHECKALLOC_THRES 64
+
 static void
 iscsi_bh_cb(void *p)
 {
@@ -273,6 +286,32 @@ static bool is_request_lun_aligned(int64_t sector_num, int nb_sectors,
     return 1;
 }
 
+static void iscsi_allocationmap_set(IscsiLun *iscsilun, int64_t sector_num,
+                                    int nb_sectors)
+{
+    if (iscsilun->allocationmap == NULL) {
+        return;
+    }
+    bitmap_set(iscsilun->allocationmap,
+               sector_num / iscsilun->cluster_sectors,
+               DIV_ROUND_UP(nb_sectors, iscsilun->cluster_sectors));
+}
+
+static void iscsi_allocationmap_clear(IscsiLun *iscsilun, int64_t sector_num,
+                                      int nb_sectors)
+{
+    int64_t cluster_num, nb_clusters;
+    if (iscsilun->allocationmap == NULL) {
+        return;
+    }
+    cluster_num = DIV_ROUND_UP(sector_num, iscsilun->cluster_sectors);
+    nb_clusters = (sector_num + nb_sectors) / iscsilun->cluster_sectors
+                  - cluster_num;
+    if (nb_clusters > 0) {
+        bitmap_clear(iscsilun->allocationmap, cluster_num, nb_clusters);
+    }
+}
+
 static int coroutine_fn iscsi_co_writev(BlockDriverState *bs,
                                         int64_t sector_num, int nb_sectors,
                                         QEMUIOVector *iov)
@@ -336,9 +375,125 @@ retry:
         return -EIO;
     }
 
+    iscsi_allocationmap_set(iscsilun, sector_num, nb_sectors);
+
     return 0;
 }
 
+
+#if defined(LIBISCSI_FEATURE_IOVECTOR)
+static bool iscsi_allocationmap_is_allocated(IscsiLun *iscsilun,
+                                             int64_t sector_num, int nb_sectors)
+{
+    unsigned long size;
+    if (iscsilun->allocationmap == NULL) {
+        return true;
+    }
+    size = DIV_ROUND_UP(sector_num + nb_sectors, iscsilun->cluster_sectors);
+    return !(find_next_bit(iscsilun->allocationmap, size,
+                           sector_num / iscsilun->cluster_sectors) == size);
+}
+
+static int64_t coroutine_fn iscsi_co_get_block_status(BlockDriverState *bs,
+                                                  int64_t sector_num,
+                                                  int nb_sectors, int *pnum)
+{
+    IscsiLun *iscsilun = bs->opaque;
+    struct scsi_get_lba_status *lbas = NULL;
+    struct scsi_lba_status_descriptor *lbasd = NULL;
+    struct IscsiTask iTask;
+    int64_t ret;
+
+    iscsi_co_init_iscsitask(iscsilun, &iTask);
+
+    if (!is_request_lun_aligned(sector_num, nb_sectors, iscsilun)) {
+        ret = -EINVAL;
+        goto out;
+    }
+
+    /* default to all sectors allocated */
+    ret = BDRV_BLOCK_DATA;
+    ret |= (sector_num << BDRV_SECTOR_BITS) | BDRV_BLOCK_OFFSET_VALID;
+    *pnum = nb_sectors;
+
+    /* LUN does not support logical block provisioning */
+    if (iscsilun->lbpme == 0) {
+        goto out;
+    }
+
+retry:
+    if (iscsi_get_lba_status_task(iscsilun->iscsi, iscsilun->lun,
+                                  sector_qemu2lun(sector_num, iscsilun),
+                                  8 + 16, iscsi_co_generic_cb,
+                                  &iTask) == NULL) {
+        ret = -ENOMEM;
+        goto out;
+    }
+
+    while (!iTask.complete) {
+        iscsi_set_events(iscsilun);
+        qemu_coroutine_yield();
+    }
+
+    if (iTask.do_retry) {
+        if (iTask.task != NULL) {
+            scsi_free_scsi_task(iTask.task);
+            iTask.task = NULL;
+        }
+        iTask.complete = 0;
+        goto retry;
+    }
+
+    if (iTask.status != SCSI_STATUS_GOOD) {
+        /* in case the get_lba_status_callout fails (i.e.
+         * because the device is busy or the cmd is not
+         * supported) we pretend all blocks are allocated
+         * for backwards compatibility */
+        goto out;
+    }
+
+    lbas = scsi_datain_unmarshall(iTask.task);
+    if (lbas == NULL) {
+        ret = -EIO;
+        goto out;
+    }
+
+    lbasd = &lbas->descriptors[0];
+
+    if (sector_qemu2lun(sector_num, iscsilun) != lbasd->lba) {
+        ret = -EIO;
+        goto out;
+    }
+
+    *pnum = sector_lun2qemu(lbasd->num_blocks, iscsilun);
+
+    if (lbasd->provisioning == SCSI_PROVISIONING_TYPE_DEALLOCATED ||
+        lbasd->provisioning == SCSI_PROVISIONING_TYPE_ANCHORED) {
+        ret &= ~BDRV_BLOCK_DATA;
+        if (iscsilun->lbprz) {
+            ret |= BDRV_BLOCK_ZERO;
+        }
+    }
+
+    if (ret & BDRV_BLOCK_ZERO) {
+        iscsi_allocationmap_clear(iscsilun, sector_num, *pnum);
+    } else {
+        iscsi_allocationmap_set(iscsilun, sector_num, *pnum);
+    }
+
+    if (*pnum > nb_sectors) {
+        *pnum = nb_sectors;
+    }
+out:
+    if (iTask.task != NULL) {
+        scsi_free_scsi_task(iTask.task);
+    }
+    return ret;
+}
+
+#endif /* LIBISCSI_FEATURE_IOVECTOR */
+
+
 static int coroutine_fn iscsi_co_readv(BlockDriverState *bs,
                                        int64_t sector_num, int nb_sectors,
                                        QEMUIOVector *iov)
@@ -355,6 +510,22 @@ static int coroutine_fn iscsi_co_readv(BlockDriverState *bs,
         return -EINVAL;
     }
 
+#if defined(LIBISCSI_FEATURE_IOVECTOR)
+    if (iscsilun->lbprz && nb_sectors >= ISCSI_CHECKALLOC_THRES &&
+        !iscsi_allocationmap_is_allocated(iscsilun, sector_num, nb_sectors)) {
+        int64_t ret;
+        int pnum;
+        ret = iscsi_co_get_block_status(bs, sector_num, INT_MAX, &pnum);
+        if (ret < 0) {
+            return ret;
+        }
+        if (ret & BDRV_BLOCK_ZERO && pnum >= nb_sectors) {
+            qemu_iovec_memset(iov, 0, 0x00, iov->size);
+            return 0;
+        }
+    }
+#endif
+
     lba = sector_qemu2lun(sector_num, iscsilun);
     num_sectors = sector_qemu2lun(nb_sectors, iscsilun);
 
@@ -643,101 +814,6 @@ iscsi_getlength(BlockDriverState *bs)
     return len;
 }
 
-#if defined(LIBISCSI_FEATURE_IOVECTOR)
-
-static int64_t coroutine_fn iscsi_co_get_block_status(BlockDriverState *bs,
-                                                  int64_t sector_num,
-                                                  int nb_sectors, int *pnum)
-{
-    IscsiLun *iscsilun = bs->opaque;
-    struct scsi_get_lba_status *lbas = NULL;
-    struct scsi_lba_status_descriptor *lbasd = NULL;
-    struct IscsiTask iTask;
-    int64_t ret;
-
-    iscsi_co_init_iscsitask(iscsilun, &iTask);
-
-    if (!is_request_lun_aligned(sector_num, nb_sectors, iscsilun)) {
-        ret = -EINVAL;
-        goto out;
-    }
-
-    /* default to all sectors allocated */
-    ret = BDRV_BLOCK_DATA;
-    ret |= (sector_num << BDRV_SECTOR_BITS) | BDRV_BLOCK_OFFSET_VALID;
-    *pnum = nb_sectors;
-
-    /* LUN does not support logical block provisioning */
-    if (iscsilun->lbpme == 0) {
-        goto out;
-    }
-
-retry:
-    if (iscsi_get_lba_status_task(iscsilun->iscsi, iscsilun->lun,
-                                  sector_qemu2lun(sector_num, iscsilun),
-                                  8 + 16, iscsi_co_generic_cb,
-                                  &iTask) == NULL) {
-        ret = -ENOMEM;
-        goto out;
-    }
-
-    while (!iTask.complete) {
-        iscsi_set_events(iscsilun);
-        qemu_coroutine_yield();
-    }
-
-    if (iTask.do_retry) {
-        if (iTask.task != NULL) {
-            scsi_free_scsi_task(iTask.task);
-            iTask.task = NULL;
-        }
-        iTask.complete = 0;
-        goto retry;
-    }
-
-    if (iTask.status != SCSI_STATUS_GOOD) {
-        /* in case the get_lba_status_callout fails (i.e.
-         * because the device is busy or the cmd is not
-         * supported) we pretend all blocks are allocated
-         * for backwards compatibility */
-        goto out;
-    }
-
-    lbas = scsi_datain_unmarshall(iTask.task);
-    if (lbas == NULL) {
-        ret = -EIO;
-        goto out;
-    }
-
-    lbasd = &lbas->descriptors[0];
-
-    if (sector_qemu2lun(sector_num, iscsilun) != lbasd->lba) {
-        ret = -EIO;
-        goto out;
-    }
-
-    *pnum = sector_lun2qemu(lbasd->num_blocks, iscsilun);
-    if (*pnum > nb_sectors) {
-        *pnum = nb_sectors;
-    }
-
-    if (lbasd->provisioning == SCSI_PROVISIONING_TYPE_DEALLOCATED ||
-        lbasd->provisioning == SCSI_PROVISIONING_TYPE_ANCHORED) {
-        ret &= ~BDRV_BLOCK_DATA;
-        if (iscsilun->lbprz) {
-            ret |= BDRV_BLOCK_ZERO;
-        }
-    }
-
-out:
-    if (iTask.task != NULL) {
-        scsi_free_scsi_task(iTask.task);
-    }
-    return ret;
-}
-
-#endif /* LIBISCSI_FEATURE_IOVECTOR */
-
 static int
 coroutine_fn iscsi_co_discard(BlockDriverState *bs, int64_t sector_num,
                                    int nb_sectors)
@@ -791,6 +867,8 @@ retry:
         return -EIO;
     }
 
+    iscsi_allocationmap_clear(iscsilun, sector_num, nb_sectors);
+
     return 0;
 }
 
@@ -809,13 +887,14 @@ coroutine_fn iscsi_co_write_zeroes(BlockDriverState *bs, int64_t sector_num,
         return -EINVAL;
     }
 
-    if (!(flags & BDRV_REQ_MAY_UNMAP) && !iscsilun->has_write_same) {
-        /* WRITE SAME without UNMAP is not supported by the target */
-        return -ENOTSUP;
+    if ((flags & BDRV_REQ_MAY_UNMAP) && !iscsilun->lbp.lbpws) {
+        /* WRITE SAME with UNMAP is not supported by the target,
+         * fall back and try WRITE SAME without UNMAP */
+        flags &= ~BDRV_REQ_MAY_UNMAP;
     }
 
-    if ((flags & BDRV_REQ_MAY_UNMAP) && !iscsilun->lbp.lbpws) {
-        /* WRITE SAME with UNMAP is not supported by the target */
+    if (!(flags & BDRV_REQ_MAY_UNMAP) && !iscsilun->has_write_same) {
+        /* WRITE SAME without UNMAP is not supported by the target */
         return -ENOTSUP;
     }
 
@@ -864,6 +943,12 @@ retry:
         return -EIO;
     }
 
+    if (flags & BDRV_REQ_MAY_UNMAP) {
+        iscsi_allocationmap_clear(iscsilun, sector_num, nb_sectors);
+    } else {
+        iscsi_allocationmap_set(iscsilun, sector_num, nb_sectors);
+    }
+
     return 0;
 }
 
@@ -1295,6 +1380,22 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
     timer_mod(iscsilun->nop_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + NOP_INTERVAL);
 #endif
 
+    /* Guess the internal cluster (page) size of the iscsi target by the means
+     * of opt_unmap_gran. Transfer the unmap granularity only if it has a
+     * reasonable size */
+    if (iscsilun->bl.opt_unmap_gran * iscsilun->block_size >= 4 * 1024 &&
+        iscsilun->bl.opt_unmap_gran * iscsilun->block_size <= 16 * 1024 * 1024) {
+        iscsilun->cluster_sectors = (iscsilun->bl.opt_unmap_gran *
+                                     iscsilun->block_size) >> BDRV_SECTOR_BITS;
+#if defined(LIBISCSI_FEATURE_IOVECTOR)
+        if (iscsilun->lbprz && !(bs->open_flags & BDRV_O_NOCACHE)) {
+            iscsilun->allocationmap =
+                bitmap_new(DIV_ROUND_UP(bs->total_sectors,
+                                        iscsilun->cluster_sectors));
+        }
+#endif
+    }
+
 out:
     qemu_opts_del(opts);
     if (initiator_name != NULL) {
@@ -1328,6 +1429,7 @@ static void iscsi_close(BlockDriverState *bs)
     qemu_aio_set_fd_handler(iscsi_get_fd(iscsi), NULL, NULL, NULL);
     iscsi_destroy_context(iscsi);
     g_free(iscsilun->zeroblock);
+    g_free(iscsilun->allocationmap);
     memset(iscsilun, 0, sizeof(IscsiLun));
 }
 
@@ -1388,6 +1490,13 @@ static int iscsi_truncate(BlockDriverState *bs, int64_t offset)
         return -EINVAL;
     }
 
+    if (iscsilun->allocationmap != NULL) {
+        g_free(iscsilun->allocationmap);
+        iscsilun->allocationmap =
+            bitmap_new(DIV_ROUND_UP(bs->total_sectors,
+                                    iscsilun->cluster_sectors));
+    }
+
     return 0;
 }
 
@@ -1450,13 +1559,7 @@ static int iscsi_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
     IscsiLun *iscsilun = bs->opaque;
     bdi->unallocated_blocks_are_zero = !!iscsilun->lbprz;
     bdi->can_write_zeroes_with_unmap = iscsilun->lbprz && iscsilun->lbp.lbpws;
-    /* Guess the internal cluster (page) size of the iscsi target by the means
-     * of opt_unmap_gran. Transfer the unmap granularity only if it has a
-     * reasonable size for bdi->cluster_size */
-    if (iscsilun->bl.opt_unmap_gran * iscsilun->block_size >= 64 * 1024 &&
-        iscsilun->bl.opt_unmap_gran * iscsilun->block_size <= 16 * 1024 * 1024) {
-        bdi->cluster_size = iscsilun->bl.opt_unmap_gran * iscsilun->block_size;
-    }
+    bdi->cluster_size = iscsilun->cluster_sectors * BDRV_SECTOR_SIZE;
     return 0;
 }
 
diff --git a/block/mirror.c b/block/mirror.c
index 1c38aa8f77..94c8661777 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -498,7 +498,7 @@ immediate_exit:
             /* drop the bs loop chain formed by the swap: break the loop then
              * trigger the unref from the top one */
             BlockDriverState *p = s->base->backing_hd;
-            s->base->backing_hd = NULL;
+            bdrv_set_backing_hd(s->base, NULL);
             bdrv_unref(p);
         }
     }
diff --git a/block/qapi.c b/block/qapi.c
index af114452e0..97e16418ef 100644
--- a/block/qapi.c
+++ b/block/qapi.c
@@ -50,6 +50,7 @@ BlockDeviceInfo *bdrv_block_device_info(BlockDriverState *bs)
     }
 
     info->backing_file_depth = bdrv_get_backing_file_depth(bs);
+    info->detect_zeroes = bs->detect_zeroes;
 
     if (bs->io_limits_enabled) {
         ThrottleConfig cfg;
@@ -474,6 +475,7 @@ static void dump_qobject(fprintf_function func_fprintf, void *f,
         case QTYPE_QERROR: {
             QString *value = qerror_human((QError *)obj);
             func_fprintf(f, "%s", qstring_get_str(value));
+            QDECREF(value);
             break;
         }
         case QTYPE_NONE:
diff --git a/block/qcow.c b/block/qcow.c
index 937dd6dd1c..7fd57d744a 100644
--- a/block/qcow.c
+++ b/block/qcow.c
@@ -48,9 +48,10 @@ typedef struct QCowHeader {
     uint64_t size; /* in bytes */
     uint8_t cluster_bits;
     uint8_t l2_bits;
+    uint16_t padding;
     uint32_t crypt_method;
     uint64_t l1_table_offset;
-} QCowHeader;
+} QEMU_PACKED QCowHeader;
 
 #define L2_CACHE_SIZE 16
 
@@ -60,7 +61,7 @@ typedef struct BDRVQcowState {
     int cluster_sectors;
     int l2_bits;
     int l2_size;
-    int l1_size;
+    unsigned int l1_size;
     uint64_t cluster_offset_mask;
     uint64_t l1_table_offset;
     uint64_t *l1_table;
@@ -96,7 +97,8 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
                      Error **errp)
 {
     BDRVQcowState *s = bs->opaque;
-    int len, i, shift, ret;
+    unsigned int len, i, shift;
+    int ret;
     QCowHeader header;
 
     ret = bdrv_pread(bs->file, 0, &header, sizeof(header));
@@ -127,11 +129,25 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
         goto fail;
     }
 
-    if (header.size <= 1 || header.cluster_bits < 9) {
-        error_setg(errp, "invalid value in qcow header");
+    if (header.size <= 1) {
+        error_setg(errp, "Image size is too small (must be at least 2 bytes)");
+        ret = -EINVAL;
+        goto fail;
+    }
+    if (header.cluster_bits < 9 || header.cluster_bits > 16) {
+        error_setg(errp, "Cluster size must be between 512 and 64k");
+        ret = -EINVAL;
+        goto fail;
+    }
+
+    /* l2_bits specifies number of entries; storing a uint64_t in each entry,
+     * so bytes = num_entries << 3. */
+    if (header.l2_bits < 9 - 3 || header.l2_bits > 16 - 3) {
+        error_setg(errp, "L2 table size must be between 512 and 64k");
         ret = -EINVAL;
         goto fail;
     }
+
     if (header.crypt_method > QCOW_CRYPT_AES) {
         error_setg(errp, "invalid encryption method in qcow header");
         ret = -EINVAL;
@@ -151,7 +167,19 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
 
     /* read the level 1 table */
     shift = s->cluster_bits + s->l2_bits;
-    s->l1_size = (header.size + (1LL << shift) - 1) >> shift;
+    if (header.size > UINT64_MAX - (1LL << shift)) {
+        error_setg(errp, "Image too large");
+        ret = -EINVAL;
+        goto fail;
+    } else {
+        uint64_t l1_size = (header.size + (1LL << shift) - 1) >> shift;
+        if (l1_size > INT_MAX / sizeof(uint64_t)) {
+            error_setg(errp, "Image too large");
+            ret = -EINVAL;
+            goto fail;
+        }
+        s->l1_size = l1_size;
+    }
 
     s->l1_table_offset = header.l1_table_offset;
     s->l1_table = g_malloc(s->l1_size * sizeof(uint64_t));
@@ -175,7 +203,9 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
     if (header.backing_file_offset != 0) {
         len = header.backing_file_size;
         if (len > 1023) {
-            len = 1023;
+            error_setg(errp, "Backing file name too long");
+            ret = -EINVAL;
+            goto fail;
         }
         ret = bdrv_pread(bs->file, header.backing_file_offset,
                    bs->backing_file, len);
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 76d2bcf63a..4208dc08b5 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -379,7 +379,8 @@ static int coroutine_fn copy_sectors(BlockDriverState *bs,
     BLKDBG_EVENT(bs->file, BLKDBG_COW_READ);
 
     if (!bs->drv) {
-        return -ENOMEDIUM;
+        ret = -ENOMEDIUM;
+        goto out;
     }
 
     /* Call .bdrv_co_readv() directly instead of using the public block-layer
diff --git a/block/qcow2.c b/block/qcow2.c
index a4b97e8263..a54d2ba897 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -1308,6 +1308,7 @@ static void qcow2_invalidate_cache(BlockDriverState *bs, Error **errp)
     options = qdict_clone_shallow(bs->options);
 
     ret = qcow2_open(bs, options, flags, &local_err);
+    QDECREF(options);
     if (local_err) {
         error_setg(errp, "Could not reopen qcow2 layer: %s",
                    error_get_pretty(local_err));
@@ -1318,8 +1319,6 @@ static void qcow2_invalidate_cache(BlockDriverState *bs, Error **errp)
         return;
     }
 
-    QDECREF(options);
-
     if (crypt_method) {
         s->crypt_method = crypt_method;
         memcpy(&s->aes_encrypt_key, &aes_encrypt_key, sizeof(aes_encrypt_key));
diff --git a/block/raw-posix.c b/block/raw-posix.c
index 6586a0c9e1..b7f0f2624b 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -1192,7 +1192,7 @@ again:
         if (size == 0)
 #endif
 #if defined(__APPLE__) && defined(__MACH__)
-        size = LONG_LONG_MAX;
+        size = LLONG_MAX;
 #else
         size = lseek(fd, 0LL, SEEK_END);
 #endif
diff --git a/block/rbd.c b/block/rbd.c
index dbc79f4525..09af48426e 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -105,7 +105,7 @@ typedef struct BDRVRBDState {
 static int qemu_rbd_next_tok(char *dst, int dst_len,
                              char *src, char delim,
                              const char *name,
-                             char **p)
+                             char **p, Error **errp)
 {
     int l;
     char *end;
@@ -128,10 +128,10 @@ static int qemu_rbd_next_tok(char *dst, int dst_len,
     }
     l = strlen(src);
     if (l >= dst_len) {
-        error_report("%s too long", name);
+        error_setg(errp, "%s too long", name);
         return -EINVAL;
     } else if (l == 0) {
-        error_report("%s too short", name);
+        error_setg(errp, "%s too short", name);
         return -EINVAL;
     }
 
@@ -157,13 +157,15 @@ static int qemu_rbd_parsename(const char *filename,
                               char *pool, int pool_len,
                               char *snap, int snap_len,
                               char *name, int name_len,
-                              char *conf, int conf_len)
+                              char *conf, int conf_len,
+                              Error **errp)
 {
     const char *start;
     char *p, *buf;
     int ret;
 
     if (!strstart(filename, "rbd:", &start)) {
+        error_setg(errp, "File name must start with 'rbd:'");
         return -EINVAL;
     }
 
@@ -172,7 +174,8 @@ static int qemu_rbd_parsename(const char *filename,
     *snap = '\0';
     *conf = '\0';
 
-    ret = qemu_rbd_next_tok(pool, pool_len, p, '/', "pool name", &p);
+    ret = qemu_rbd_next_tok(pool, pool_len, p,
+                            '/', "pool name", &p, errp);
     if (ret < 0 || !p) {
         ret = -EINVAL;
         goto done;
@@ -180,21 +183,25 @@ static int qemu_rbd_parsename(const char *filename,
     qemu_rbd_unescape(pool);
 
     if (strchr(p, '@')) {
-        ret = qemu_rbd_next_tok(name, name_len, p, '@', "object name", &p);
+        ret = qemu_rbd_next_tok(name, name_len, p,
+                                '@', "object name", &p, errp);
         if (ret < 0) {
             goto done;
         }
-        ret = qemu_rbd_next_tok(snap, snap_len, p, ':', "snap name", &p);
+        ret = qemu_rbd_next_tok(snap, snap_len, p,
+                                ':', "snap name", &p, errp);
         qemu_rbd_unescape(snap);
     } else {
-        ret = qemu_rbd_next_tok(name, name_len, p, ':', "object name", &p);
+        ret = qemu_rbd_next_tok(name, name_len, p,
+                                ':', "object name", &p, errp);
     }
     qemu_rbd_unescape(name);
     if (ret < 0 || !p) {
         goto done;
     }
 
-    ret = qemu_rbd_next_tok(conf, conf_len, p, '\0', "configuration", &p);
+    ret = qemu_rbd_next_tok(conf, conf_len, p,
+                            '\0', "configuration", &p, errp);
 
 done:
     g_free(buf);
@@ -229,7 +236,7 @@ static char *qemu_rbd_parse_clientname(const char *conf, char *clientname)
     return NULL;
 }
 
-static int qemu_rbd_set_conf(rados_t cluster, const char *conf)
+static int qemu_rbd_set_conf(rados_t cluster, const char *conf, Error **errp)
 {
     char *p, *buf;
     char name[RBD_MAX_CONF_NAME_SIZE];
@@ -241,20 +248,20 @@ static int qemu_rbd_set_conf(rados_t cluster, const char *conf)
 
     while (p) {
         ret = qemu_rbd_next_tok(name, sizeof(name), p,
-                                '=', "conf option name", &p);
+                                '=', "conf option name", &p, errp);
         if (ret < 0) {
             break;
         }
         qemu_rbd_unescape(name);
 
         if (!p) {
-            error_report("conf option %s has no value", name);
+            error_setg(errp, "conf option %s has no value", name);
             ret = -EINVAL;
             break;
         }
 
         ret = qemu_rbd_next_tok(value, sizeof(value), p,
-                                ':', "conf option value", &p);
+                                ':', "conf option value", &p, errp);
         if (ret < 0) {
             break;
         }
@@ -263,7 +270,7 @@ static int qemu_rbd_set_conf(rados_t cluster, const char *conf)
         if (strcmp(name, "conf") == 0) {
             ret = rados_conf_read_file(cluster, value);
             if (ret < 0) {
-                error_report("error reading conf file %s", value);
+                error_setg(errp, "error reading conf file %s", value);
                 break;
             }
         } else if (strcmp(name, "id") == 0) {
@@ -271,7 +278,7 @@ static int qemu_rbd_set_conf(rados_t cluster, const char *conf)
         } else {
             ret = rados_conf_set(cluster, name, value);
             if (ret < 0) {
-                error_report("invalid conf option %s", name);
+                error_setg(errp, "invalid conf option %s", name);
                 ret = -EINVAL;
                 break;
             }
@@ -285,6 +292,7 @@ static int qemu_rbd_set_conf(rados_t cluster, const char *conf)
 static int qemu_rbd_create(const char *filename, QEMUOptionParameter *options,
                            Error **errp)
 {
+    Error *local_err = NULL;
     int64_t bytes = 0;
     int64_t objsize;
     int obj_order = 0;
@@ -301,7 +309,8 @@ static int qemu_rbd_create(const char *filename, QEMUOptionParameter *options,
     if (qemu_rbd_parsename(filename, pool, sizeof(pool),
                            snap_buf, sizeof(snap_buf),
                            name, sizeof(name),
-                           conf, sizeof(conf)) < 0) {
+                           conf, sizeof(conf), &local_err) < 0) {
+        error_propagate(errp, local_err);
         return -EINVAL;
     }
 
@@ -313,11 +322,11 @@ static int qemu_rbd_create(const char *filename, QEMUOptionParameter *options,
             if (options->value.n) {
                 objsize = options->value.n;
                 if ((objsize - 1) & objsize) {    /* not a power of 2? */
-                    error_report("obj size needs to be power of 2");
+                    error_setg(errp, "obj size needs to be power of 2");
                     return -EINVAL;
                 }
                 if (objsize < 4096) {
-                    error_report("obj size too small");
+                    error_setg(errp, "obj size too small");
                     return -EINVAL;
                 }
                 obj_order = ffs(objsize) - 1;
@@ -328,7 +337,7 @@ static int qemu_rbd_create(const char *filename, QEMUOptionParameter *options,
 
     clientname = qemu_rbd_parse_clientname(conf, clientname_buf);
     if (rados_create(&cluster, clientname) < 0) {
-        error_report("error initializing");
+        error_setg(errp, "error initializing");
         return -EIO;
     }
 
@@ -338,20 +347,20 @@ static int qemu_rbd_create(const char *filename, QEMUOptionParameter *options,
     }
 
     if (conf[0] != '\0' &&
-        qemu_rbd_set_conf(cluster, conf) < 0) {
-        error_report("error setting config options");
+        qemu_rbd_set_conf(cluster, conf, &local_err) < 0) {
         rados_shutdown(cluster);
+        error_propagate(errp, local_err);
         return -EIO;
     }
 
     if (rados_connect(cluster) < 0) {
-        error_report("error connecting");
+        error_setg(errp, "error connecting");
         rados_shutdown(cluster);
         return -EIO;
     }
 
     if (rados_ioctx_create(cluster, pool, &io_ctx) < 0) {
-        error_report("error opening pool %s", pool);
+        error_setg(errp, "error opening pool %s", pool);
         rados_shutdown(cluster);
         return -EIO;
     }
@@ -441,8 +450,7 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
     opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
     qemu_opts_absorb_qdict(opts, options, &local_err);
     if (local_err) {
-        qerror_report_err(local_err);
-        error_free(local_err);
+        error_propagate(errp, local_err);
         qemu_opts_del(opts);
         return -EINVAL;
     }
@@ -452,7 +460,7 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
     if (qemu_rbd_parsename(filename, pool, sizeof(pool),
                            snap_buf, sizeof(snap_buf),
                            s->name, sizeof(s->name),
-                           conf, sizeof(conf)) < 0) {
+                           conf, sizeof(conf), errp) < 0) {
         r = -EINVAL;
         goto failed_opts;
     }
@@ -460,7 +468,7 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
     clientname = qemu_rbd_parse_clientname(conf, clientname_buf);
     r = rados_create(&s->cluster, clientname);
     if (r < 0) {
-        error_report("error initializing");
+        error_setg(&local_err, "error initializing");
         goto failed_opts;
     }
 
@@ -488,28 +496,27 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
     }
 
     if (conf[0] != '\0') {
-        r = qemu_rbd_set_conf(s->cluster, conf);
+        r = qemu_rbd_set_conf(s->cluster, conf, errp);
         if (r < 0) {
-            error_report("error setting config options");
             goto failed_shutdown;
         }
     }
 
     r = rados_connect(s->cluster);
     if (r < 0) {
-        error_report("error connecting");
+        error_setg(&local_err, "error connecting");
         goto failed_shutdown;
     }
 
     r = rados_ioctx_create(s->cluster, pool, &s->io_ctx);
     if (r < 0) {
-        error_report("error opening pool %s", pool);
+        error_setg(&local_err, "error opening pool %s", pool);
         goto failed_shutdown;
     }
 
     r = rbd_open(s->io_ctx, s->name, &s->image, s->snap);
     if (r < 0) {
-        error_report("error reading header from %s", s->name);
+        error_setg(&local_err, "error reading header from %s", s->name);
         goto failed_open;
     }
 
diff --git a/block/sheepdog.c b/block/sheepdog.c
index 2c3fb016a8..4ecbf5f498 100644
--- a/block/sheepdog.c
+++ b/block/sheepdog.c
@@ -526,17 +526,16 @@ static SheepdogAIOCB *sd_aio_setup(BlockDriverState *bs, QEMUIOVector *qiov,
     return acb;
 }
 
-static int connect_to_sdog(BDRVSheepdogState *s)
+static int connect_to_sdog(BDRVSheepdogState *s, Error **errp)
 {
     int fd;
-    Error *err = NULL;
 
     if (s->is_unix) {
-        fd = unix_connect(s->host_spec, &err);
+        fd = unix_connect(s->host_spec, errp);
     } else {
-        fd = inet_connect(s->host_spec, &err);
+        fd = inet_connect(s->host_spec, errp);
 
-        if (err == NULL) {
+        if (fd >= 0) {
             int ret = socket_set_nodelay(fd);
             if (ret < 0) {
                 error_report("%s", strerror(errno));
@@ -544,10 +543,7 @@ static int connect_to_sdog(BDRVSheepdogState *s)
         }
     }
 
-    if (err != NULL) {
-        qerror_report_err(err);
-        error_free(err);
-    } else {
+    if (fd >= 0) {
         qemu_set_nonblock(fd);
     }
 
@@ -672,7 +668,7 @@ static void coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
                            enum AIOCBState aiocb_type);
 static void coroutine_fn resend_aioreq(BDRVSheepdogState *s, AIOReq *aio_req);
 static int reload_inode(BDRVSheepdogState *s, uint32_t snapid, const char *tag);
-static int get_sheep_fd(BDRVSheepdogState *s);
+static int get_sheep_fd(BDRVSheepdogState *s, Error **errp);
 static void co_write_request(void *opaque);
 
 static AIOReq *find_pending_req(BDRVSheepdogState *s, uint64_t oid)
@@ -709,6 +705,7 @@ static void coroutine_fn send_pending_req(BDRVSheepdogState *s, uint64_t oid)
 
 static coroutine_fn void reconnect_to_sdog(void *opaque)
 {
+    Error *local_err = NULL;
     BDRVSheepdogState *s = opaque;
     AIOReq *aio_req, *next;
 
@@ -723,9 +720,11 @@ static coroutine_fn void reconnect_to_sdog(void *opaque)
 
     /* Try to reconnect the sheepdog server every one second. */
     while (s->fd < 0) {
-        s->fd = get_sheep_fd(s);
+        s->fd = get_sheep_fd(s, &local_err);
         if (s->fd < 0) {
             DPRINTF("Wait for connection to be established\n");
+            error_report("%s", error_get_pretty(local_err));
+            error_free(local_err);
             co_aio_sleep_ns(bdrv_get_aio_context(s->bs), QEMU_CLOCK_REALTIME,
                             1000000000ULL);
         }
@@ -914,11 +913,11 @@ static void co_write_request(void *opaque)
  * We cannot use this descriptor for other operations because
  * the block driver may be on waiting response from the server.
  */
-static int get_sheep_fd(BDRVSheepdogState *s)
+static int get_sheep_fd(BDRVSheepdogState *s, Error **errp)
 {
     int fd;
 
-    fd = connect_to_sdog(s);
+    fd = connect_to_sdog(s, errp);
     if (fd < 0) {
         return fd;
     }
@@ -1061,7 +1060,7 @@ static int parse_vdiname(BDRVSheepdogState *s, const char *filename,
 
 static int find_vdi_name(BDRVSheepdogState *s, const char *filename,
                          uint32_t snapid, const char *tag, uint32_t *vid,
-                         bool lock)
+                         bool lock, Error **errp)
 {
     int ret, fd;
     SheepdogVdiReq hdr;
@@ -1069,7 +1068,7 @@ static int find_vdi_name(BDRVSheepdogState *s, const char *filename,
     unsigned int wlen, rlen = 0;
     char buf[SD_MAX_VDI_LEN + SD_MAX_VDI_TAG_LEN];
 
-    fd = connect_to_sdog(s);
+    fd = connect_to_sdog(s, errp);
     if (fd < 0) {
         return fd;
     }
@@ -1095,12 +1094,13 @@ static int find_vdi_name(BDRVSheepdogState *s, const char *filename,
 
     ret = do_req(fd, (SheepdogReq *)&hdr, buf, &wlen, &rlen);
     if (ret) {
+        error_setg_errno(errp, -ret, "cannot get vdi info");
         goto out;
     }
 
     if (rsp->result != SD_RES_SUCCESS) {
-        error_report("cannot get vdi info, %s, %s %" PRIu32 " %s",
-                     sd_strerror(rsp->result), filename, snapid, tag);
+        error_setg(errp, "cannot get vdi info, %s, %s %" PRIu32 " %s",
+                   sd_strerror(rsp->result), filename, snapid, tag);
         if (rsp->result == SD_RES_NO_VDI) {
             ret = -ENOENT;
         } else {
@@ -1263,19 +1263,24 @@ static int write_object(int fd, char *buf, uint64_t oid, uint8_t copies,
 /* update inode with the latest state */
 static int reload_inode(BDRVSheepdogState *s, uint32_t snapid, const char *tag)
 {
+    Error *local_err = NULL;
     SheepdogInode *inode;
     int ret = 0, fd;
     uint32_t vid = 0;
 
-    fd = connect_to_sdog(s);
+    fd = connect_to_sdog(s, &local_err);
     if (fd < 0) {
+        error_report("%s", error_get_pretty(local_err));;
+        error_free(local_err);
         return -EIO;
     }
 
     inode = g_malloc(sizeof(s->inode));
 
-    ret = find_vdi_name(s, s->name, snapid, tag, &vid, false);
+    ret = find_vdi_name(s, s->name, snapid, tag, &vid, false, &local_err);
     if (ret) {
+        error_report("%s", error_get_pretty(local_err));;
+        error_free(local_err);
         goto out;
     }
 
@@ -1386,8 +1391,7 @@ static int sd_open(BlockDriverState *bs, QDict *options, int flags,
     opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
     qemu_opts_absorb_qdict(opts, options, &local_err);
     if (local_err) {
-        qerror_report_err(local_err);
-        error_free(local_err);
+        error_propagate(errp, local_err);
         ret = -EINVAL;
         goto out;
     }
@@ -1408,15 +1412,16 @@ static int sd_open(BlockDriverState *bs, QDict *options, int flags,
         ret = parse_vdiname(s, filename, vdi, &snapid, tag);
     }
     if (ret < 0) {
+        error_setg(errp, "Can't parse filename");
         goto out;
     }
-    s->fd = get_sheep_fd(s);
+    s->fd = get_sheep_fd(s, errp);
     if (s->fd < 0) {
         ret = s->fd;
         goto out;
     }
 
-    ret = find_vdi_name(s, vdi, snapid, tag, &vid, true);
+    ret = find_vdi_name(s, vdi, snapid, tag, &vid, true, errp);
     if (ret) {
         goto out;
     }
@@ -1436,7 +1441,7 @@ static int sd_open(BlockDriverState *bs, QDict *options, int flags,
         s->is_snapshot = true;
     }
 
-    fd = connect_to_sdog(s);
+    fd = connect_to_sdog(s, errp);
     if (fd < 0) {
         ret = fd;
         goto out;
@@ -1449,6 +1454,7 @@ static int sd_open(BlockDriverState *bs, QDict *options, int flags,
     closesocket(fd);
 
     if (ret) {
+        error_setg(errp, "Can't read snapshot inode");
         goto out;
     }
 
@@ -1472,7 +1478,8 @@ out:
     return ret;
 }
 
-static int do_sd_create(BDRVSheepdogState *s, uint32_t *vdi_id, int snapshot)
+static int do_sd_create(BDRVSheepdogState *s, uint32_t *vdi_id, int snapshot,
+                        Error **errp)
 {
     SheepdogVdiReq hdr;
     SheepdogVdiRsp *rsp = (SheepdogVdiRsp *)&hdr;
@@ -1480,7 +1487,7 @@ static int do_sd_create(BDRVSheepdogState *s, uint32_t *vdi_id, int snapshot)
     unsigned int wlen, rlen = 0;
     char buf[SD_MAX_VDI_LEN];
 
-    fd = connect_to_sdog(s);
+    fd = connect_to_sdog(s, errp);
     if (fd < 0) {
         return fd;
     }
@@ -1510,11 +1517,12 @@ static int do_sd_create(BDRVSheepdogState *s, uint32_t *vdi_id, int snapshot)
     closesocket(fd);
 
     if (ret) {
+        error_setg_errno(errp, -ret, "create failed");
         return ret;
     }
 
     if (rsp->result != SD_RES_SUCCESS) {
-        error_report("%s, %s", sd_strerror(rsp->result), s->inode.name);
+        error_setg(errp, "%s, %s", sd_strerror(rsp->result), s->inode.name);
         return -EIO;
     }
 
@@ -1525,21 +1533,18 @@ static int do_sd_create(BDRVSheepdogState *s, uint32_t *vdi_id, int snapshot)
     return 0;
 }
 
-static int sd_prealloc(const char *filename)
+static int sd_prealloc(const char *filename, Error **errp)
 {
     BlockDriverState *bs = NULL;
     uint32_t idx, max_idx;
     int64_t vdi_size;
     void *buf = g_malloc0(SD_DATA_OBJ_SIZE);
-    Error *local_err = NULL;
     int ret;
 
     ret = bdrv_open(&bs, filename, NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL,
-                    NULL, &local_err);
+                    NULL, errp);
     if (ret < 0) {
-        qerror_report_err(local_err);
-        error_free(local_err);
-        goto out;
+        goto out_with_err_set;
     }
 
     vdi_size = bdrv_getlength(bs);
@@ -1563,7 +1568,12 @@ static int sd_prealloc(const char *filename)
             goto out;
         }
     }
+
 out:
+    if (ret < 0) {
+        error_setg_errno(errp, -ret, "Can't pre-allocate");
+    }
+out_with_err_set:
     if (bs) {
         bdrv_unref(bs);
     }
@@ -1636,7 +1646,6 @@ static int sd_create(const char *filename, QEMUOptionParameter *options,
     char tag[SD_MAX_VDI_TAG_LEN];
     uint32_t snapid;
     bool prealloc = false;
-    Error *local_err = NULL;
 
     s = g_malloc0(sizeof(BDRVSheepdogState));
 
@@ -1647,6 +1656,7 @@ static int sd_create(const char *filename, QEMUOptionParameter *options,
         ret = parse_vdiname(s, filename, s->name, &snapid, tag);
     }
     if (ret < 0) {
+        error_setg(errp, "Can't parse filename");
         goto out;
     }
 
@@ -1661,8 +1671,8 @@ static int sd_create(const char *filename, QEMUOptionParameter *options,
             } else if (!strcmp(options->value.s, "full")) {
                 prealloc = true;
             } else {
-                error_report("Invalid preallocation mode: '%s'",
-                             options->value.s);
+                error_setg(errp, "Invalid preallocation mode: '%s'",
+                           options->value.s);
                 ret = -EINVAL;
                 goto out;
             }
@@ -1670,6 +1680,8 @@ static int sd_create(const char *filename, QEMUOptionParameter *options,
             if (options->value.s) {
                 ret = parse_redundancy(s, options->value.s);
                 if (ret < 0) {
+                    error_setg(errp, "Invalid redundancy mode: '%s'",
+                               options->value.s);
                     goto out;
                 }
             }
@@ -1678,7 +1690,7 @@ static int sd_create(const char *filename, QEMUOptionParameter *options,
     }
 
     if (s->inode.vdi_size > SD_MAX_VDI_SIZE) {
-        error_report("too big image size");
+        error_setg(errp, "too big image size");
         ret = -EINVAL;
         goto out;
     }
@@ -1691,24 +1703,22 @@ static int sd_create(const char *filename, QEMUOptionParameter *options,
         /* Currently, only Sheepdog backing image is supported. */
         drv = bdrv_find_protocol(backing_file, true);
         if (!drv || strcmp(drv->protocol_name, "sheepdog") != 0) {
-            error_report("backing_file must be a sheepdog image");
+            error_setg(errp, "backing_file must be a sheepdog image");
             ret = -EINVAL;
             goto out;
         }
 
         bs = NULL;
         ret = bdrv_open(&bs, backing_file, NULL, NULL, BDRV_O_PROTOCOL, NULL,
-                        &local_err);
+                        errp);
         if (ret < 0) {
-            qerror_report_err(local_err);
-            error_free(local_err);
             goto out;
         }
 
         base = bs->opaque;
 
         if (!is_snapshot(&base->inode)) {
-            error_report("cannot clone from a non snapshot vdi");
+            error_setg(errp, "cannot clone from a non snapshot vdi");
             bdrv_unref(bs);
             ret = -EINVAL;
             goto out;
@@ -1717,12 +1727,14 @@ static int sd_create(const char *filename, QEMUOptionParameter *options,
         bdrv_unref(bs);
     }
 
-    ret = do_sd_create(s, &vid, 0);
-    if (!prealloc || ret) {
+    ret = do_sd_create(s, &vid, 0, errp);
+    if (ret) {
         goto out;
     }
 
-    ret = sd_prealloc(filename);
+    if (prealloc) {
+        ret = sd_prealloc(filename, errp);
+    }
 out:
     g_free(s);
     return ret;
@@ -1730,6 +1742,7 @@ out:
 
 static void sd_close(BlockDriverState *bs)
 {
+    Error *local_err = NULL;
     BDRVSheepdogState *s = bs->opaque;
     SheepdogVdiReq hdr;
     SheepdogVdiRsp *rsp = (SheepdogVdiRsp *)&hdr;
@@ -1738,8 +1751,10 @@ static void sd_close(BlockDriverState *bs)
 
     DPRINTF("%s\n", s->name);
 
-    fd = connect_to_sdog(s);
+    fd = connect_to_sdog(s, &local_err);
     if (fd < 0) {
+        error_report("%s", error_get_pretty(local_err));;
+        error_free(local_err);
         return;
     }
 
@@ -1774,6 +1789,7 @@ static int64_t sd_getlength(BlockDriverState *bs)
 
 static int sd_truncate(BlockDriverState *bs, int64_t offset)
 {
+    Error *local_err = NULL;
     BDRVSheepdogState *s = bs->opaque;
     int ret, fd;
     unsigned int datalen;
@@ -1786,8 +1802,10 @@ static int sd_truncate(BlockDriverState *bs, int64_t offset)
         return -EINVAL;
     }
 
-    fd = connect_to_sdog(s);
+    fd = connect_to_sdog(s, &local_err);
     if (fd < 0) {
+        error_report("%s", error_get_pretty(local_err));;
+        error_free(local_err);
         return fd;
     }
 
@@ -1846,6 +1864,7 @@ static void coroutine_fn sd_write_done(SheepdogAIOCB *acb)
 /* Delete current working VDI on the snapshot chain */
 static bool sd_delete(BDRVSheepdogState *s)
 {
+    Error *local_err = NULL;
     unsigned int wlen = SD_MAX_VDI_LEN, rlen = 0;
     SheepdogVdiReq hdr = {
         .opcode = SD_OP_DEL_VDI,
@@ -1856,8 +1875,10 @@ static bool sd_delete(BDRVSheepdogState *s)
     SheepdogVdiRsp *rsp = (SheepdogVdiRsp *)&hdr;
     int fd, ret;
 
-    fd = connect_to_sdog(s);
+    fd = connect_to_sdog(s, &local_err);
     if (fd < 0) {
+        error_report("%s", error_get_pretty(local_err));;
+        error_free(local_err);
         return false;
     }
 
@@ -1885,6 +1906,7 @@ static bool sd_delete(BDRVSheepdogState *s)
  */
 static int sd_create_branch(BDRVSheepdogState *s)
 {
+    Error *local_err = NULL;
     int ret, fd;
     uint32_t vid;
     char *buf;
@@ -1900,15 +1922,19 @@ static int sd_create_branch(BDRVSheepdogState *s)
      * false bail out.
      */
     deleted = sd_delete(s);
-    ret = do_sd_create(s, &vid, !deleted);
+    ret = do_sd_create(s, &vid, !deleted, &local_err);
     if (ret) {
+        error_report("%s", error_get_pretty(local_err));;
+        error_free(local_err);
         goto out;
     }
 
     DPRINTF("%" PRIx32 " is created.\n", vid);
 
-    fd = connect_to_sdog(s);
+    fd = connect_to_sdog(s, &local_err);
     if (fd < 0) {
+        error_report("%s", error_get_pretty(local_err));;
+        error_free(local_err);
         ret = fd;
         goto out;
     }
@@ -2122,6 +2148,7 @@ static int coroutine_fn sd_co_flush_to_disk(BlockDriverState *bs)
 
 static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
 {
+    Error *local_err = NULL;
     BDRVSheepdogState *s = bs->opaque;
     int ret, fd;
     uint32_t new_vid;
@@ -2149,10 +2176,13 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
     strncpy(s->inode.tag, sn_info->name, sizeof(s->inode.tag));
     /* we don't need to update entire object */
     datalen = SD_INODE_SIZE - sizeof(s->inode.data_vdi_id);
+    inode = g_malloc(datalen);
 
     /* refresh inode. */
-    fd = connect_to_sdog(s);
+    fd = connect_to_sdog(s, &local_err);
     if (fd < 0) {
+        error_report("%s", error_get_pretty(local_err));;
+        error_free(local_err);
         ret = fd;
         goto cleanup;
     }
@@ -2164,15 +2194,15 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
         goto cleanup;
     }
 
-    ret = do_sd_create(s, &new_vid, 1);
+    ret = do_sd_create(s, &new_vid, 1, &local_err);
     if (ret < 0) {
+        error_report("%s", error_get_pretty(local_err));;
+        error_free(local_err);
         error_report("failed to create inode for snapshot. %s",
                      strerror(errno));
         goto cleanup;
     }
 
-    inode = (SheepdogInode *)g_malloc(datalen);
-
     ret = read_object(fd, (char *)inode, vid_to_vdi_oid(new_vid),
                       s->inode.nr_copies, datalen, 0, s->cache_flags);
 
@@ -2186,6 +2216,7 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
             s->inode.name, s->inode.snap_id, s->inode.vdi_id);
 
 cleanup:
+    g_free(inode);
     closesocket(fd);
     return ret;
 }
@@ -2249,6 +2280,7 @@ static int sd_snapshot_delete(BlockDriverState *bs,
 
 static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
 {
+    Error *local_err = NULL;
     BDRVSheepdogState *s = bs->opaque;
     SheepdogReq req;
     int fd, nr = 1024, ret, max = BITS_TO_LONGS(SD_NR_VDIS) * sizeof(long);
@@ -2263,8 +2295,10 @@ static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
 
     vdi_inuse = g_malloc(max);
 
-    fd = connect_to_sdog(s);
+    fd = connect_to_sdog(s, &local_err);
     if (fd < 0) {
+        error_report("%s", error_get_pretty(local_err));;
+        error_free(local_err);
         ret = fd;
         goto out;
     }
@@ -2290,8 +2324,10 @@ static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
     hval = fnv_64a_buf(s->name, strlen(s->name), FNV1A_64_INIT);
     start_nr = hval & (SD_NR_VDIS - 1);
 
-    fd = connect_to_sdog(s);
+    fd = connect_to_sdog(s, &local_err);
     if (fd < 0) {
+        error_report("%s", error_get_pretty(local_err));;
+        error_free(local_err);
         ret = fd;
         goto out;
     }
@@ -2341,6 +2377,7 @@ out:
 static int do_load_save_vmstate(BDRVSheepdogState *s, uint8_t *data,
                                 int64_t pos, int size, int load)
 {
+    Error *local_err = NULL;
     bool create;
     int fd, ret = 0, remaining = size;
     unsigned int data_len;
@@ -2349,8 +2386,10 @@ static int do_load_save_vmstate(BDRVSheepdogState *s, uint8_t *data,
     uint32_t vdi_index;
     uint32_t vdi_id = load ? s->inode.parent_vdi_id : s->inode.vdi_id;
 
-    fd = connect_to_sdog(s);
+    fd = connect_to_sdog(s, &local_err);
     if (fd < 0) {
+        error_report("%s", error_get_pretty(local_err));;
+        error_free(local_err);
         return fd;
     }
 
diff --git a/block/ssh.c b/block/ssh.c
index aa63c9d20e..b2129714bc 100644
--- a/block/ssh.c
+++ b/block/ssh.c
@@ -106,30 +106,59 @@ static void ssh_state_free(BDRVSSHState *s)
     }
 }
 
-/* Wrappers around error_report which make sure to dump as much
- * information from libssh2 as possible.
- */
-static void GCC_FMT_ATTR(2, 3)
-session_error_report(BDRVSSHState *s, const char *fs, ...)
+static void GCC_FMT_ATTR(3, 4)
+session_error_setg(Error **errp, BDRVSSHState *s, const char *fs, ...)
 {
     va_list args;
+    char *msg;
 
     va_start(args, fs);
-    error_vprintf(fs, args);
+    msg = g_strdup_vprintf(fs, args);
+    va_end(args);
 
-    if ((s)->session) {
+    if (s->session) {
         char *ssh_err;
         int ssh_err_code;
 
-        libssh2_session_last_error((s)->session, &ssh_err, NULL, 0);
         /* This is not an errno.  See <libssh2.h>. */
-        ssh_err_code = libssh2_session_last_errno((s)->session);
-
-        error_printf(": %s (libssh2 error code: %d)", ssh_err, ssh_err_code);
+        ssh_err_code = libssh2_session_last_error(s->session,
+                                                  &ssh_err, NULL, 0);
+        error_setg(errp, "%s: %s (libssh2 error code: %d)",
+                   msg, ssh_err, ssh_err_code);
+    } else {
+        error_setg(errp, "%s", msg);
     }
+    g_free(msg);
+}
+
+static void GCC_FMT_ATTR(3, 4)
+sftp_error_setg(Error **errp, BDRVSSHState *s, const char *fs, ...)
+{
+    va_list args;
+    char *msg;
 
+    va_start(args, fs);
+    msg = g_strdup_vprintf(fs, args);
     va_end(args);
-    error_printf("\n");
+
+    if (s->sftp) {
+        char *ssh_err;
+        int ssh_err_code;
+        unsigned long sftp_err_code;
+
+        /* This is not an errno.  See <libssh2.h>. */
+        ssh_err_code = libssh2_session_last_error(s->session,
+                                                  &ssh_err, NULL, 0);
+        /* See <libssh2_sftp.h>. */
+        sftp_err_code = libssh2_sftp_last_error((s)->sftp);
+
+        error_setg(errp,
+                   "%s: %s (libssh2 error code: %d, sftp error code: %lu)",
+                   msg, ssh_err, ssh_err_code, sftp_err_code);
+    } else {
+        error_setg(errp, "%s", msg);
+    }
+    g_free(msg);
 }
 
 static void GCC_FMT_ATTR(2, 3)
@@ -145,9 +174,9 @@ sftp_error_report(BDRVSSHState *s, const char *fs, ...)
         int ssh_err_code;
         unsigned long sftp_err_code;
 
-        libssh2_session_last_error((s)->session, &ssh_err, NULL, 0);
         /* This is not an errno.  See <libssh2.h>. */
-        ssh_err_code = libssh2_session_last_errno((s)->session);
+        ssh_err_code = libssh2_session_last_error(s->session,
+                                                  &ssh_err, NULL, 0);
         /* See <libssh2_sftp.h>. */
         sftp_err_code = libssh2_sftp_last_error((s)->sftp);
 
@@ -243,7 +272,7 @@ static void ssh_parse_filename(const char *filename, QDict *options,
 }
 
 static int check_host_key_knownhosts(BDRVSSHState *s,
-                                     const char *host, int port)
+                                     const char *host, int port, Error **errp)
 {
     const char *home;
     char *knh_file = NULL;
@@ -257,14 +286,15 @@ static int check_host_key_knownhosts(BDRVSSHState *s,
     hostkey = libssh2_session_hostkey(s->session, &len, &type);
     if (!hostkey) {
         ret = -EINVAL;
-        session_error_report(s, "failed to read remote host key");
+        session_error_setg(errp, s, "failed to read remote host key");
         goto out;
     }
 
     knh = libssh2_knownhost_init(s->session);
     if (!knh) {
         ret = -EINVAL;
-        session_error_report(s, "failed to initialize known hosts support");
+        session_error_setg(errp, s,
+                           "failed to initialize known hosts support");
         goto out;
     }
 
@@ -289,21 +319,23 @@ static int check_host_key_knownhosts(BDRVSSHState *s,
         break;
     case LIBSSH2_KNOWNHOST_CHECK_MISMATCH:
         ret = -EINVAL;
-        session_error_report(s, "host key does not match the one in known_hosts (found key %s)",
-                             found->key);
+        session_error_setg(errp, s,
+                      "host key does not match the one in known_hosts"
+                      " (found key %s)", found->key);
         goto out;
     case LIBSSH2_KNOWNHOST_CHECK_NOTFOUND:
         ret = -EINVAL;
-        session_error_report(s, "no host key was found in known_hosts");
+        session_error_setg(errp, s, "no host key was found in known_hosts");
         goto out;
     case LIBSSH2_KNOWNHOST_CHECK_FAILURE:
         ret = -EINVAL;
-        session_error_report(s, "failure matching the host key with known_hosts");
+        session_error_setg(errp, s,
+                      "failure matching the host key with known_hosts");
         goto out;
     default:
         ret = -EINVAL;
-        session_error_report(s, "unknown error matching the host key with known_hosts (%d)",
-                             r);
+        session_error_setg(errp, s, "unknown error matching the host key"
+                      " with known_hosts (%d)", r);
         goto out;
     }
 
@@ -358,20 +390,20 @@ static int compare_fingerprint(const unsigned char *fingerprint, size_t len,
 
 static int
 check_host_key_hash(BDRVSSHState *s, const char *hash,
-                    int hash_type, size_t fingerprint_len)
+                    int hash_type, size_t fingerprint_len, Error **errp)
 {
     const char *fingerprint;
 
     fingerprint = libssh2_hostkey_hash(s->session, hash_type);
     if (!fingerprint) {
-        session_error_report(s, "failed to read remote host key");
+        session_error_setg(errp, s, "failed to read remote host key");
         return -EINVAL;
     }
 
     if(compare_fingerprint((unsigned char *) fingerprint, fingerprint_len,
                            hash) != 0) {
-        error_report("remote host key does not match host_key_check '%s'",
-                     hash);
+        error_setg(errp, "remote host key does not match host_key_check '%s'",
+                   hash);
         return -EPERM;
     }
 
@@ -379,7 +411,7 @@ check_host_key_hash(BDRVSSHState *s, const char *hash,
 }
 
 static int check_host_key(BDRVSSHState *s, const char *host, int port,
-                          const char *host_key_check)
+                          const char *host_key_check, Error **errp)
 {
     /* host_key_check=no */
     if (strcmp(host_key_check, "no") == 0) {
@@ -389,25 +421,25 @@ static int check_host_key(BDRVSSHState *s, const char *host, int port,
     /* host_key_check=md5:xx:yy:zz:... */
     if (strncmp(host_key_check, "md5:", 4) == 0) {
         return check_host_key_hash(s, &host_key_check[4],
-                                   LIBSSH2_HOSTKEY_HASH_MD5, 16);
+                                   LIBSSH2_HOSTKEY_HASH_MD5, 16, errp);
     }
 
     /* host_key_check=sha1:xx:yy:zz:... */
     if (strncmp(host_key_check, "sha1:", 5) == 0) {
         return check_host_key_hash(s, &host_key_check[5],
-                                   LIBSSH2_HOSTKEY_HASH_SHA1, 20);
+                                   LIBSSH2_HOSTKEY_HASH_SHA1, 20, errp);
     }
 
     /* host_key_check=yes */
     if (strcmp(host_key_check, "yes") == 0) {
-        return check_host_key_knownhosts(s, host, port);
+        return check_host_key_knownhosts(s, host, port, errp);
     }
 
-    error_report("unknown host_key_check setting (%s)", host_key_check);
+    error_setg(errp, "unknown host_key_check setting (%s)", host_key_check);
     return -EINVAL;
 }
 
-static int authenticate(BDRVSSHState *s, const char *user)
+static int authenticate(BDRVSSHState *s, const char *user, Error **errp)
 {
     int r, ret;
     const char *userauthlist;
@@ -418,7 +450,8 @@ static int authenticate(BDRVSSHState *s, const char *user)
     userauthlist = libssh2_userauth_list(s->session, user, strlen(user));
     if (strstr(userauthlist, "publickey") == NULL) {
         ret = -EPERM;
-        error_report("remote server does not support \"publickey\" authentication");
+        error_setg(errp,
+                "remote server does not support \"publickey\" authentication");
         goto out;
     }
 
@@ -426,17 +459,18 @@ static int authenticate(BDRVSSHState *s, const char *user)
     agent = libssh2_agent_init(s->session);
     if (!agent) {
         ret = -EINVAL;
-        session_error_report(s, "failed to initialize ssh-agent support");
+        session_error_setg(errp, s, "failed to initialize ssh-agent support");
         goto out;
     }
     if (libssh2_agent_connect(agent)) {
         ret = -ECONNREFUSED;
-        session_error_report(s, "failed to connect to ssh-agent");
+        session_error_setg(errp, s, "failed to connect to ssh-agent");
         goto out;
     }
     if (libssh2_agent_list_identities(agent)) {
         ret = -EINVAL;
-        session_error_report(s, "failed requesting identities from ssh-agent");
+        session_error_setg(errp, s,
+                           "failed requesting identities from ssh-agent");
         goto out;
     }
 
@@ -447,7 +481,8 @@ static int authenticate(BDRVSSHState *s, const char *user)
         }
         if (r < 0) {
             ret = -EINVAL;
-            session_error_report(s, "failed to obtain identity from ssh-agent");
+            session_error_setg(errp, s,
+                               "failed to obtain identity from ssh-agent");
             goto out;
         }
         r = libssh2_agent_userauth(agent, user, identity);
@@ -461,8 +496,8 @@ static int authenticate(BDRVSSHState *s, const char *user)
     }
 
     ret = -EPERM;
-    error_report("failed to authenticate using publickey authentication "
-                 "and the identities held by your ssh-agent");
+    error_setg(errp, "failed to authenticate using publickey authentication "
+               "and the identities held by your ssh-agent");
 
  out:
     if (agent != NULL) {
@@ -476,10 +511,9 @@ static int authenticate(BDRVSSHState *s, const char *user)
 }
 
 static int connect_to_ssh(BDRVSSHState *s, QDict *options,
-                          int ssh_flags, int creat_mode)
+                          int ssh_flags, int creat_mode, Error **errp)
 {
     int r, ret;
-    Error *err = NULL;
     const char *host, *user, *path, *host_key_check;
     int port;
 
@@ -498,6 +532,7 @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options,
     } else {
         user = g_get_user_name();
         if (!user) {
+            error_setg_errno(errp, errno, "Can't get user name");
             ret = -errno;
             goto err;
         }
@@ -514,11 +549,9 @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options,
     s->hostport = g_strdup_printf("%s:%d", host, port);
 
     /* Open the socket and connect. */
-    s->sock = inet_connect(s->hostport, &err);
-    if (err != NULL) {
+    s->sock = inet_connect(s->hostport, errp);
+    if (s->sock < 0) {
         ret = -errno;
-        qerror_report_err(err);
-        error_free(err);
         goto err;
     }
 
@@ -526,7 +559,7 @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options,
     s->session = libssh2_session_init();
     if (!s->session) {
         ret = -EINVAL;
-        session_error_report(s, "failed to initialize libssh2 session");
+        session_error_setg(errp, s, "failed to initialize libssh2 session");
         goto err;
     }
 
@@ -537,18 +570,18 @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options,
     r = libssh2_session_handshake(s->session, s->sock);
     if (r != 0) {
         ret = -EINVAL;
-        session_error_report(s, "failed to establish SSH session");
+        session_error_setg(errp, s, "failed to establish SSH session");
         goto err;
     }
 
     /* Check the remote host's key against known_hosts. */
-    ret = check_host_key(s, host, port, host_key_check);
+    ret = check_host_key(s, host, port, host_key_check, errp);
     if (ret < 0) {
         goto err;
     }
 
     /* Authenticate. */
-    ret = authenticate(s, user);
+    ret = authenticate(s, user, errp);
     if (ret < 0) {
         goto err;
     }
@@ -556,7 +589,7 @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options,
     /* Start SFTP. */
     s->sftp = libssh2_sftp_init(s->session);
     if (!s->sftp) {
-        session_error_report(s, "failed to initialize sftp handle");
+        session_error_setg(errp, s, "failed to initialize sftp handle");
         ret = -EINVAL;
         goto err;
     }
@@ -566,14 +599,14 @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options,
             path, ssh_flags, creat_mode);
     s->sftp_handle = libssh2_sftp_open(s->sftp, path, ssh_flags, creat_mode);
     if (!s->sftp_handle) {
-        session_error_report(s, "failed to open remote file '%s'", path);
+        session_error_setg(errp, s, "failed to open remote file '%s'", path);
         ret = -EINVAL;
         goto err;
     }
 
     r = libssh2_sftp_fstat(s->sftp_handle, &s->attrs);
     if (r < 0) {
-        sftp_error_report(s, "failed to read file attributes");
+        sftp_error_setg(errp, s, "failed to read file attributes");
         return -EINVAL;
     }
 
@@ -623,7 +656,7 @@ static int ssh_file_open(BlockDriverState *bs, QDict *options, int bdrv_flags,
     }
 
     /* Start up SSH. */
-    ret = connect_to_ssh(s, options, ssh_flags, 0);
+    ret = connect_to_ssh(s, options, ssh_flags, 0, errp);
     if (ret < 0) {
         goto err;
     }
@@ -655,7 +688,6 @@ static int ssh_create(const char *filename, QEMUOptionParameter *options,
                       Error **errp)
 {
     int r, ret;
-    Error *local_err = NULL;
     int64_t total_size = 0;
     QDict *uri_options = NULL;
     BDRVSSHState s;
@@ -674,17 +706,16 @@ static int ssh_create(const char *filename, QEMUOptionParameter *options,
     DPRINTF("total_size=%" PRIi64, total_size);
 
     uri_options = qdict_new();
-    r = parse_uri(filename, uri_options, &local_err);
+    r = parse_uri(filename, uri_options, errp);
     if (r < 0) {
-        qerror_report_err(local_err);
-        error_free(local_err);
         ret = r;
         goto out;
     }
 
     r = connect_to_ssh(&s, uri_options,
                        LIBSSH2_FXF_READ|LIBSSH2_FXF_WRITE|
-                       LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC, 0644);
+                       LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC,
+                       0644, errp);
     if (r < 0) {
         ret = r;
         goto out;
@@ -694,7 +725,7 @@ static int ssh_create(const char *filename, QEMUOptionParameter *options,
         libssh2_sftp_seek64(s.sftp_handle, total_size-1);
         r2 = libssh2_sftp_write(s.sftp_handle, c, 1);
         if (r2 < 0) {
-            sftp_error_report(&s, "truncate failed");
+            sftp_error_setg(errp, &s, "truncate failed");
             ret = -EINVAL;
             goto out;
         }
diff --git a/block/stream.c b/block/stream.c
index dd0b4ac3d2..91d18a2db7 100644
--- a/block/stream.c
+++ b/block/stream.c
@@ -60,7 +60,7 @@ static void close_unused_images(BlockDriverState *top, BlockDriverState *base,
     /* Must assign before bdrv_delete() to prevent traversing dangling pointer
      * while we delete backing image instances.
      */
-    top->backing_hd = base;
+    bdrv_set_backing_hd(top, base);
 
     while (intermediate) {
         BlockDriverState *unused;
@@ -72,7 +72,7 @@ static void close_unused_images(BlockDriverState *top, BlockDriverState *base,
 
         unused = intermediate;
         intermediate = intermediate->backing_hd;
-        unused->backing_hd = NULL;
+        bdrv_set_backing_hd(unused, NULL);
         bdrv_unref(unused);
     }
 
diff --git a/block/vhdx.c b/block/vhdx.c
index 509baaf484..353c74d35f 100644
--- a/block/vhdx.c
+++ b/block/vhdx.c
@@ -473,7 +473,14 @@ static void vhdx_parse_header(BlockDriverState *bs, BDRVVHDXState *s,
         } else if (h2_seq > h1_seq) {
             s->curr_header = 1;
         } else {
-            goto fail;
+            /* The Microsoft Disk2VHD tool will create 2 identical
+             * headers, with identical sequence numbers.  If the headers are
+             * identical, don't consider the file corrupt */
+            if (!memcmp(header1, header2, sizeof(VHDXHeader))) {
+                s->curr_header = 0;
+            } else {
+                goto fail;
+            }
         }
     }
 
diff --git a/block/vmdk.c b/block/vmdk.c
index 480ea37d7c..2b38f61fcd 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -1534,7 +1534,7 @@ static int vmdk_create_extent(const char *filename, int64_t filesize,
     int ret, i;
     BlockDriverState *bs = NULL;
     VMDK4Header header;
-    Error *local_err;
+    Error *local_err = NULL;
     uint32_t tmp, magic, grains, gd_sectors, gt_size, gt_count;
     uint32_t *gd_buf = NULL;
     int gd_buf_size;
@@ -1700,7 +1700,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options,
 {
     int idx = 0;
     BlockDriverState *new_bs = NULL;
-    Error *local_err;
+    Error *local_err = NULL;
     char *desc = NULL;
     int64_t total_size = 0, filesize;
     const char *adapter_type = NULL;
@@ -1881,7 +1881,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options,
     } else {
         ret = bdrv_create_file(filename, options, &local_err);
         if (ret < 0) {
-            error_setg_errno(errp, -ret, "Could not create image file");
+            error_propagate(errp, local_err);
             goto exit;
         }
     }
@@ -1889,7 +1889,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options,
     ret = bdrv_open(&new_bs, filename, NULL, NULL,
                     BDRV_O_RDWR | BDRV_O_PROTOCOL, NULL, &local_err);
     if (ret < 0) {
-        error_setg_errno(errp, -ret, "Could not write description");
+        error_propagate(errp, local_err);
         goto exit;
     }
     ret = bdrv_pwrite(new_bs, desc_offset, desc, desc_len);
diff --git a/block/vvfat.c b/block/vvfat.c
index c3af7ff4c5..3cda19f2f3 100644
--- a/block/vvfat.c
+++ b/block/vvfat.c
@@ -787,7 +787,9 @@ static int read_directory(BDRVVVFATState* s, int mapping_index)
 	    s->current_mapping->path=buffer;
 	    s->current_mapping->read_only =
 		(st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) == 0;
-	}
+        } else {
+            g_free(buffer);
+        }
     }
     closedir(dir);
 
@@ -831,7 +833,8 @@ static inline off_t cluster2sector(BDRVVVFATState* s, uint32_t cluster_num)
 }
 
 static int init_directories(BDRVVVFATState* s,
-                            const char *dirname, int heads, int secs)
+                            const char *dirname, int heads, int secs,
+                            Error **errp)
 {
     bootsector_t* bootsector;
     mapping_t* mapping;
@@ -892,8 +895,8 @@ static int init_directories(BDRVVVFATState* s,
         if (mapping->mode & MODE_DIRECTORY) {
 	    mapping->begin = cluster;
 	    if(read_directory(s, i)) {
-		fprintf(stderr, "Could not read directory %s\n",
-			mapping->path);
+                error_setg(errp, "Could not read directory %s",
+                           mapping->path);
 		return -1;
 	    }
 	    mapping = array_get(&(s->mapping), i);
@@ -919,9 +922,10 @@ static int init_directories(BDRVVVFATState* s,
 	cluster = mapping->end;
 
 	if(cluster > s->cluster_count) {
-	    fprintf(stderr,"Directory does not fit in FAT%d (capacity %.2f MB)\n",
-		    s->fat_type, s->sector_count / 2000.0);
-	    return -EINVAL;
+            error_setg(errp,
+                       "Directory does not fit in FAT%d (capacity %.2f MB)",
+                       s->fat_type, s->sector_count / 2000.0);
+            return -1;
 	}
 
 	/* fix fat for entry */
@@ -979,7 +983,7 @@ static int init_directories(BDRVVVFATState* s,
 static BDRVVVFATState *vvv = NULL;
 #endif
 
-static int enable_write_target(BDRVVVFATState *s);
+static int enable_write_target(BDRVVVFATState *s, Error **errp);
 static int is_consistent(BDRVVVFATState *s);
 
 static void vvfat_rebind(BlockDriverState *bs)
@@ -1160,7 +1164,7 @@ DLOG(if (stderr == NULL) {
     s->sector_count = cyls * heads * secs - (s->first_sectors_number - 1);
 
     if (qemu_opt_get_bool(opts, "rw", false)) {
-        ret = enable_write_target(s);
+        ret = enable_write_target(s, errp);
         if (ret < 0) {
             goto fail;
         }
@@ -1169,7 +1173,7 @@ DLOG(if (stderr == NULL) {
 
     bs->total_sectors = cyls * heads * secs;
 
-    if (init_directories(s, dirname, heads, secs)) {
+    if (init_directories(s, dirname, heads, secs, errp)) {
         ret = -EIO;
         goto fail;
     }
@@ -1864,7 +1868,7 @@ static int check_directory_consistency(BDRVVVFATState *s,
 
 	if (s->used_clusters[cluster_num] & USED_ANY) {
 	    fprintf(stderr, "cluster %d used more than once\n", (int)cluster_num);
-	    return 0;
+            goto fail;
 	}
 	s->used_clusters[cluster_num] = USED_DIRECTORY;
 
@@ -2904,11 +2908,10 @@ static BlockDriver vvfat_write_target = {
     .bdrv_close         = write_target_close,
 };
 
-static int enable_write_target(BDRVVVFATState *s)
+static int enable_write_target(BDRVVVFATState *s, Error **errp)
 {
     BlockDriver *bdrv_qcow;
     QEMUOptionParameter *options;
-    Error *local_err = NULL;
     int ret;
     int size = sector2cluster(s, s->sector_count);
     s->used_clusters = calloc(size, 1);
@@ -2918,6 +2921,7 @@ static int enable_write_target(BDRVVVFATState *s)
     s->qcow_filename = g_malloc(1024);
     ret = get_tmp_filename(s->qcow_filename, 1024);
     if (ret < 0) {
+        error_setg_errno(errp, -ret, "can't create temporary file");
         goto err;
     }
 
@@ -2926,20 +2930,17 @@ static int enable_write_target(BDRVVVFATState *s)
     set_option_parameter_int(options, BLOCK_OPT_SIZE, s->sector_count * 512);
     set_option_parameter(options, BLOCK_OPT_BACKING_FILE, "fat:");
 
-    ret = bdrv_create(bdrv_qcow, s->qcow_filename, options, &local_err);
+    ret = bdrv_create(bdrv_qcow, s->qcow_filename, options, errp);
+    free_option_parameters(options);
     if (ret < 0) {
-        qerror_report_err(local_err);
-        error_free(local_err);
         goto err;
     }
 
     s->qcow = NULL;
     ret = bdrv_open(&s->qcow, s->qcow_filename, NULL, NULL,
-            BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH, bdrv_qcow,
-            &local_err);
+                    BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH,
+                    bdrv_qcow, errp);
     if (ret < 0) {
-        qerror_report_err(local_err);
-        error_free(local_err);
         goto err;
     }
 
@@ -2947,7 +2948,7 @@ static int enable_write_target(BDRVVVFATState *s)
     unlink(s->qcow_filename);
 #endif
 
-    s->bs->backing_hd = bdrv_new("", &error_abort);
+    bdrv_set_backing_hd(s->bs, bdrv_new("", &error_abort));
     s->bs->backing_hd->drv = &vvfat_write_target;
     s->bs->backing_hd->opaque = g_malloc(sizeof(void*));
     *(void**)s->bs->backing_hd->opaque = s;
diff --git a/blockdev-nbd.c b/blockdev-nbd.c
index 922cf5657b..b60b66d66c 100644
--- a/blockdev-nbd.c
+++ b/blockdev-nbd.c
@@ -27,8 +27,8 @@ static void nbd_accept(void *opaque)
     socklen_t addr_len = sizeof(addr);
 
     int fd = accept(server_fd, (struct sockaddr *)&addr, &addr_len);
-    if (fd >= 0) {
-        nbd_client_new(NULL, fd, nbd_client_put);
+    if (fd >= 0 && !nbd_client_new(NULL, fd, nbd_client_put)) {
+        close(fd);
     }
 }
 
diff --git a/blockdev.c b/blockdev.c
index 7810e9fb68..9b5261b765 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -34,7 +34,6 @@
 #include "hw/block/block.h"
 #include "block/blockjob.h"
 #include "monitor/monitor.h"
-#include "qapi/qmp/qerror.h"
 #include "qemu/option.h"
 #include "qemu/config-file.h"
 #include "qapi/qmp/types.h"
@@ -288,6 +287,25 @@ static int parse_block_error_action(const char *buf, bool is_read, Error **errp)
     }
 }
 
+static inline int parse_enum_option(const char *lookup[], const char *buf,
+                                    int max, int def, Error **errp)
+{
+    int i;
+
+    if (!buf) {
+        return def;
+    }
+
+    for (i = 0; i < max; i++) {
+        if (!strcmp(buf, lookup[i])) {
+            return i;
+        }
+    }
+
+    error_setg(errp, "invalid parameter value: %s", buf);
+    return def;
+}
+
 static bool check_throttle_config(ThrottleConfig *cfg, Error **errp)
 {
     if (throttle_conflicting(cfg)) {
@@ -324,6 +342,7 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
     QemuOpts *opts;
     const char *id;
     bool has_driver_specific_opts;
+    BlockdevDetectZeroesOptions detect_zeroes;
     BlockDriver *drv = NULL;
 
     /* Check common options by copying from bs_opts to opts, all other options
@@ -332,7 +351,7 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
     opts = qemu_opts_create(&qemu_common_drive_opts, id, 1, &error);
     if (error) {
         error_propagate(errp, error);
-        return NULL;
+        goto err_no_opts;
     }
 
     qemu_opts_absorb_qdict(opts, bs_opts, &error);
@@ -452,6 +471,24 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
         }
     }
 
+    detect_zeroes =
+        parse_enum_option(BlockdevDetectZeroesOptions_lookup,
+                          qemu_opt_get(opts, "detect-zeroes"),
+                          BLOCKDEV_DETECT_ZEROES_OPTIONS_MAX,
+                          BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF,
+                          &error);
+    if (error) {
+        error_propagate(errp, error);
+        goto early_err;
+    }
+
+    if (detect_zeroes == BLOCKDEV_DETECT_ZEROES_OPTIONS_UNMAP &&
+        !(bdrv_flags & BDRV_O_UNMAP)) {
+        error_setg(errp, "setting detect-zeroes to unmap is not allowed "
+                         "without setting discard operation to unmap");
+        goto early_err;
+    }
+
     /* init */
     dinfo = g_malloc0(sizeof(*dinfo));
     dinfo->id = g_strdup(qemu_opts_id(opts));
@@ -462,6 +499,7 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
     }
     dinfo->bdrv->open_flags = snapshot ? BDRV_O_SNAPSHOT : 0;
     dinfo->bdrv->read_only = ro;
+    dinfo->bdrv->detect_zeroes = detect_zeroes;
     dinfo->refcount = 1;
     if (serial != NULL) {
         dinfo->serial = g_strdup(serial);
@@ -526,8 +564,9 @@ bdrv_new_err:
     g_free(dinfo->id);
     g_free(dinfo);
 early_err:
-    QDECREF(bs_opts);
     qemu_opts_del(opts);
+err_no_opts:
+    QDECREF(bs_opts);
     return NULL;
 }
 
@@ -691,7 +730,7 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type)
                                    &error_abort);
     qemu_opts_absorb_qdict(legacy_opts, bs_opts, &local_err);
     if (local_err) {
-        qerror_report_err(local_err);
+        error_report("%s", error_get_pretty(local_err));
         error_free(local_err);
         goto fail;
     }
@@ -901,9 +940,10 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type)
 
     /* Actual block device init: Functionality shared with blockdev-add */
     dinfo = blockdev_init(filename, bs_opts, &local_err);
+    bs_opts = NULL;
     if (dinfo == NULL) {
         if (local_err) {
-            qerror_report_err(local_err);
+            error_report("%s", error_get_pretty(local_err));
             error_free(local_err);
         }
         goto fail;
@@ -938,6 +978,7 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type)
 
 fail:
     qemu_opts_del(legacy_opts);
+    QDECREF(bs_opts);
     return dinfo;
 }
 
@@ -1295,8 +1336,8 @@ static void external_snapshot_prepare(BlkTransactionState *common,
         return;
     }
 
-    if (bdrv_in_use(state->old_bs)) {
-        error_set(errp, QERR_DEVICE_IN_USE, device);
+    if (bdrv_op_is_blocked(state->old_bs,
+                           BLOCK_OP_TYPE_EXTERNAL_SNAPSHOT, errp)) {
         return;
     }
 
@@ -1518,8 +1559,7 @@ exit:
 
 static void eject_device(BlockDriverState *bs, int force, Error **errp)
 {
-    if (bdrv_in_use(bs)) {
-        error_set(errp, QERR_DEVICE_IN_USE, bdrv_get_device_name(bs));
+    if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_EJECT, errp)) {
         return;
     }
     if (!bdrv_dev_has_removable_media(bs)) {
@@ -1721,14 +1761,16 @@ int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
 {
     const char *id = qdict_get_str(qdict, "id");
     BlockDriverState *bs;
+    Error *local_err = NULL;
 
     bs = bdrv_find(id);
     if (!bs) {
-        qerror_report(QERR_DEVICE_NOT_FOUND, id);
+        error_report("Device '%s' not found", id);
         return -1;
     }
-    if (bdrv_in_use(bs)) {
-        qerror_report(QERR_DEVICE_IN_USE, id);
+    if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_DRIVE_DEL, &local_err)) {
+        error_report("%s", error_get_pretty(local_err));
+        error_free(local_err);
         return -1;
     }
 
@@ -1849,6 +1891,10 @@ void qmp_block_stream(const char *device, bool has_base,
         return;
     }
 
+    if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_STREAM, errp)) {
+        return;
+    }
+
     if (base) {
         base_bs = bdrv_find_backing_image(bs, base);
         if (base_bs == NULL) {
@@ -1893,6 +1939,10 @@ void qmp_block_commit(const char *device,
         return;
     }
 
+    if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_COMMIT, errp)) {
+        return;
+    }
+
     /* default top_bs is the active layer */
     top_bs = bs;
 
@@ -1984,8 +2034,7 @@ void qmp_drive_backup(const char *device, const char *target,
         }
     }
 
-    if (bdrv_in_use(bs)) {
-        error_set(errp, QERR_DEVICE_IN_USE, device);
+    if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_BACKUP_SOURCE, errp)) {
         return;
     }
 
@@ -2118,8 +2167,7 @@ void qmp_drive_mirror(const char *device, const char *target,
         }
     }
 
-    if (bdrv_in_use(bs)) {
-        error_set(errp, QERR_DEVICE_IN_USE, device);
+    if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_MIRROR, errp)) {
         return;
     }
 
@@ -2455,6 +2503,10 @@ QemuOptsList qemu_common_drive_opts = {
             .name = "copy-on-read",
             .type = QEMU_OPT_BOOL,
             .help = "copy read data from backing file into image file",
+        },{
+            .name = "detect-zeroes",
+            .type = QEMU_OPT_STRING,
+            .help = "try to optimize zero writes (off, on, unmap)",
         },
         { /* end of list */ }
     },
diff --git a/blockjob.c b/blockjob.c
index cd4784f053..7d84ca1d6c 100644
--- a/blockjob.c
+++ b/blockjob.c
@@ -41,14 +41,16 @@ void *block_job_create(const BlockJobDriver *driver, BlockDriverState *bs,
 {
     BlockJob *job;
 
-    if (bs->job || bdrv_in_use(bs)) {
+    if (bs->job) {
         error_set(errp, QERR_DEVICE_IN_USE, bdrv_get_device_name(bs));
         return NULL;
     }
     bdrv_ref(bs);
-    bdrv_set_in_use(bs, 1);
-
     job = g_malloc0(driver->instance_size);
+    error_setg(&job->blocker, "block device is in use by block job: %s",
+               BlockJobType_lookup[driver->job_type]);
+    bdrv_op_block_all(bs, job->blocker);
+
     job->driver        = driver;
     job->bs            = bs;
     job->cb            = cb;
@@ -63,8 +65,9 @@ void *block_job_create(const BlockJobDriver *driver, BlockDriverState *bs,
         block_job_set_speed(job, speed, &local_err);
         if (local_err) {
             bs->job = NULL;
+            bdrv_op_unblock_all(bs, job->blocker);
+            error_free(job->blocker);
             g_free(job);
-            bdrv_set_in_use(bs, 0);
             error_propagate(errp, local_err);
             return NULL;
         }
@@ -79,8 +82,9 @@ void block_job_completed(BlockJob *job, int ret)
     assert(bs->job == job);
     job->cb(job->opaque, ret);
     bs->job = NULL;
+    bdrv_op_unblock_all(bs, job->blocker);
+    error_free(job->blocker);
     g_free(job);
-    bdrv_set_in_use(bs, 0);
 }
 
 void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp)
diff --git a/configure b/configure
index 605a0ece0c..0e516f9e2a 100755
--- a/configure
+++ b/configure
@@ -2,26 +2,28 @@
 #
 # qemu configure script (c) 2003 Fabrice Bellard
 #
-# set temporary file name
-if test ! -z "$TMPDIR" ; then
-    TMPDIR1="${TMPDIR}"
-elif test ! -z "$TEMPDIR" ; then
-    TMPDIR1="${TEMPDIR}"
-else
-    TMPDIR1="/tmp"
+
+# Temporary directory used for files created while
+# configure runs. Since it is in the build directory
+# we can safely blow away any previous version of it
+# (and we need not jump through hoops to try to delete
+# it when configure exits.)
+TMPDIR1="config-temp"
+rm -rf "${TMPDIR1}"
+mkdir -p "${TMPDIR1}"
+if [ $? -ne 0 ]; then
+    echo "ERROR: failed to create temporary directory"
+    exit 1
 fi
 
-TMPC="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.c"
-TMPB="qemu-conf-${RANDOM}-$$-${RANDOM}"
+TMPB="qemu-conf"
+TMPC="${TMPDIR1}/${TMPB}.c"
 TMPO="${TMPDIR1}/${TMPB}.o"
 TMPCXX="${TMPDIR1}/${TMPB}.cxx"
 TMPL="${TMPDIR1}/${TMPB}.lo"
 TMPA="${TMPDIR1}/lib${TMPB}.la"
-TMPE="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.exe"
+TMPE="${TMPDIR1}/${TMPB}.exe"
 
-# NB: do not call "exit" in the trap handler; this is buggy with some shells;
-# see <1285349658-3122-1-git-send-email-loic.minier@linaro.org>
-trap "rm -f $TMPC $TMPO $TMPCXX $TMPE" EXIT INT QUIT TERM
 rm -f config.log
 
 # Print a helpful header at the top of config.log
@@ -317,7 +319,7 @@ glusterfs_discard="no"
 glusterfs_zerofill="no"
 virtio_blk_data_plane=""
 gtk=""
-gtkabi="2.0"
+gtkabi=""
 vte=""
 tpm="no"
 libssh2=""
@@ -1970,6 +1972,18 @@ fi
 ##########################################
 # GTK probe
 
+if test "$gtkabi" = ""; then
+    # The GTK ABI was not specified explicitly, so try whether 2.0 is available.
+    # Use 3.0 as a fallback if that is available.
+    if $pkg_config --exists "gtk+-2.0 >= 2.18.0"; then
+        gtkabi=2.0
+    elif $pkg_config --exists "gtk+-3.0 >= 3.0.0"; then
+        gtkabi=3.0
+    else
+        gtkabi=2.0
+    fi
+fi
+
 if test "$gtk" != "no"; then
     gtkpackage="gtk+-$gtkabi"
     if test "$gtkabi" = "3.0" ; then
@@ -1983,7 +1997,7 @@ if test "$gtk" != "no"; then
         libs_softmmu="$gtk_libs $libs_softmmu"
         gtk="yes"
     elif test "$gtk" = "yes"; then
-        feature_not_found "gtk" "Install gtk2 or gtk3 (requires --with-gtkabi=3.0 option to configure) devel"
+        feature_not_found "gtk" "Install gtk2 or gtk3 devel"
     else
         gtk="no"
     fi
@@ -2006,7 +2020,11 @@ if test "$vte" != "no"; then
         libs_softmmu="$vte_libs $libs_softmmu"
         vte="yes"
     elif test "$vte" = "yes"; then
-        feature_not_found "vte" "Install libvte or libvte-2.90 (requires --with-gtkabi=3.0 option to configure) devel"
+        if test "$gtkabi" = "3.0"; then
+            feature_not_found "vte" "Install libvte-2.90 devel"
+        else
+            feature_not_found "vte" "Install libvte devel"
+        fi
     else
         vte="no"
     fi
@@ -4029,11 +4047,14 @@ fi
 if test "$pie" = "no" ; then
   textseg_addr=
   case "$cpu" in
-    arm | hppa | i386 | m68k | ppc | ppc64 | s390* | sparc | sparc64 | x86_64 | x32)
+    arm | i386 | ppc* | s390* | sparc* | x86_64 | x32)
+      # ??? Rationale for choosing this address
       textseg_addr=0x60000000
       ;;
     mips)
-      textseg_addr=0x400000
+      # A 256M aligned address, high in the address space, with enough
+      # room for the code_gen_buffer above it before the stack.
+      textseg_addr=0x60000000
       ;;
   esac
   if [ -n "$textseg_addr" ]; then
@@ -5219,3 +5240,4 @@ printf " '%s'" "$0" "$@" >>config.status
 echo >>config.status
 chmod +x config.status
 
+rm -r "$TMPDIR1"
diff --git a/default-configs/s390x-softmmu.mak b/default-configs/s390x-softmmu.mak
index d843dc0d57..126d88dc15 100644
--- a/default-configs/s390x-softmmu.mak
+++ b/default-configs/s390x-softmmu.mak
@@ -1,3 +1,4 @@
 CONFIG_VIRTIO=y
 CONFIG_SCLPCONSOLE=y
-CONFIG_S390_FLIC=$(CONFIG_KVM)
+CONFIG_S390_FLIC=y
+CONFIG_S390_FLIC_KVM=$(CONFIG_KVM)
diff --git a/dma-helpers.c b/dma-helpers.c
index 5f421e9814..53cbe925d1 100644
--- a/dma-helpers.c
+++ b/dma-helpers.c
@@ -143,12 +143,12 @@ static void dma_bdrv_cb(void *opaque, int ret)
 
     dbs->acb = NULL;
     dbs->sector_num += dbs->iov.size / 512;
-    dma_bdrv_unmap(dbs);
 
     if (dbs->sg_cur_index == dbs->sg->nsg || ret < 0) {
         dma_complete(dbs, ret);
         return;
     }
+    dma_bdrv_unmap(dbs);
 
     while (dbs->sg_cur_index < dbs->sg->nsg) {
         cur_addr = dbs->sg->sg[dbs->sg_cur_index].base + dbs->sg_cur_byte;
diff --git a/docs/multiseat.txt b/docs/multiseat.txt
new file mode 100644
index 0000000000..67151e0849
--- /dev/null
+++ b/docs/multiseat.txt
@@ -0,0 +1,102 @@
+
+multiseat howto (with some multihead coverage)
+==============================================
+
+host side
+---------
+
+First you must compile qemu with a user interface supporting
+multihead/multiseat and input event routing.  Right now this
+list includes sdl2 and gtk (both 2+3):
+
+  ./configure --enable-sdl --with-sdlabi=2.0
+
+or
+
+  ./configure --enable-gtk
+
+
+Next put together the qemu command line:
+
+qemu	-enable-kvm -usb $memory $disk $whatever \
+	-display [ sdl | gtk ] \
+	-vga std \
+	-device usb-tablet
+
+That is it for the first head, which will use the standard vga, the
+standard ps/2 keyboard (implicitly there) and the usb-tablet.  Now the
+additional switches for the second head:
+
+	-device pci-bridge,addr=12.0,chassis_nr=2,id=head.2 \
+	-device secondary-vga,bus=head.2,addr=02.0,id=video.2 \
+	-device nec-usb-xhci,bus=head.2,addr=0f.0,id=usb.2 \
+	-device usb-kbd,bus=usb.2.0,port=1,display=video.2 \
+	-device usb-tablet,bus=usb.2.0,port=2,display=video.2
+
+This places a pci bridge in slot 12, connects a display adapter and
+xhci (usb) controller to the bridge.  Then it adds a usb keyboard and
+usb mouse, both connected to the xhci and linked to the display.
+
+The "display=video2" sets up the input routing.  Any input coming from
+the window which belongs to the video.2 display adapter will be routed
+to these input devices.
+
+The sdl2 ui will start up with two windows, one for each display
+device.  The gtk ui will start with a single window and each display
+in a separate tab.  You can either simply switch tabs to switch heads,
+or use the "View / Detach tab" menu item to move one of the displays
+to its own window so you can see both display devices side-by-side.
+
+Note on spice: Spice handles multihead just fine.  But it can't do
+multiseat.  For tablet events the event source is sent to the spice
+agent.  But qemu can't figure it, so it can't do input routing.
+Fixing this needs a new or extended input interface between
+libspice-server and qemu.  For keyboard events it is even worse:  The
+event source isn't included in the spice protocol, so the wire
+protocol must be extended to support this.
+
+
+guest side
+----------
+
+You need a pretty recent linux guest.  systemd with loginctl.  kernel
+3.14+ with CONFIG_DRM_BOCHS enabled.  Fedora 20 will do.  Must be
+fully updated for the new kernel though, i.e. the live iso doesn't cut
+it.
+
+Now we'll have to configure the guest.  Boot and login.  "lspci -vt"
+should list the pci bridge with the display adapter and usb controller:
+
+    [root@fedora ~]# lspci -vt
+    -[0000:00]-+-00.0  Intel Corporation 440FX - 82441FX PMC [Natoma]
+               [ ... ]
+               \-12.0-[01]--+-02.0  Device 1234:1111
+                            \-0f.0  NEC Corporation USB 3.0 Host Controller
+
+Good.  Now lets tell the system that the pci bridge and all devices
+below it belong to a separate seat by dropping a file into
+/etc/udev/rules.d:
+
+    [root@fedora ~]# cat /etc/udev/rules.d/70-qemu-autoseat.rules
+    SUBSYSTEMS=="pci", DEVPATH=="*/0000:00:12.0", TAG+="seat", ENV{ID_AUTOSEAT}="1"
+
+Reboot.  System should come up with two seats.  With loginctl you can
+check the configuration:
+
+    [root@fedora ~]# loginctl list-seats
+    SEAT
+    seat0
+    seat-pci-pci-0000_00_12_0
+
+    2 seats listed.
+
+You can use "loginctl seat-status seat-pci-pci-0000_00_12_0" to list
+the devices attached to the seat.
+
+Background info is here:
+  http://www.freedesktop.org/wiki/Software/systemd/multiseat/
+
+Enjoy!
+
+--
+Gerd Hoffmann <kraxel@redhat.com>
diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt
index 26312d84e8..dea0d505a7 100644
--- a/docs/qapi-code-gen.txt
+++ b/docs/qapi-code-gen.txt
@@ -48,7 +48,7 @@ The QAPI schema definitions can be modularized using the 'include' directive:
  { 'include': 'path/to/file.json'}
 
 The directive is evaluated recursively, and include paths are relative to the
-file using the directive.
+file using the directive. Multiple includes of the same file are safe.
 
 
 === Complex types ===
@@ -230,14 +230,13 @@ node structure that can be used to chain together a list of such types in
 case we want to accept/return a list of this type with a command), and a
 command which takes that type as a parameter and returns the same type:
 
-    mdroth@illuin:~/w/qemu2.git$ cat example-schema.json
+    $ cat example-schema.json
     { 'type': 'UserDefOne',
       'data': { 'integer': 'int', 'string': 'str' } }
 
     { 'command': 'my-command',
       'data':    {'arg1': 'UserDefOne'},
       'returns': 'UserDefOne' }
-    mdroth@illuin:~/w/qemu2.git$
 
 === scripts/qapi-types.py ===
 
@@ -255,14 +254,25 @@ created code.
 
 Example:
 
-    mdroth@illuin:~/w/qemu2.git$ python scripts/qapi-types.py \
-      --output-dir="qapi-generated" --prefix="example-" --input-file=example-schema.json
-    mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-types.c
-    /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
+    $ python scripts/qapi-types.py --output-dir="qapi-generated" \
+    --prefix="example-" --input-file=example-schema.json
+    $ cat qapi-generated/example-qapi-types.c
+[Uninteresting stuff omitted...]
 
-    #include "qapi/qapi-dealloc-visitor.h"
-    #include "example-qapi-types.h"
-    #include "example-qapi-visit.h"
+    void qapi_free_UserDefOneList(UserDefOneList * obj)
+    {
+        QapiDeallocVisitor *md;
+        Visitor *v;
+
+        if (!obj) {
+            return;
+        }
+
+        md = qapi_dealloc_visitor_new();
+        v = qapi_dealloc_get_visitor(md);
+        visit_type_UserDefOneList(v, &obj, NULL, NULL);
+        qapi_dealloc_visitor_cleanup(md);
+    }
 
     void qapi_free_UserDefOne(UserDefOne * obj)
     {
@@ -279,32 +289,38 @@ Example:
         qapi_dealloc_visitor_cleanup(md);
     }
 
-    mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-types.h
-    /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
-    #ifndef QAPI_GENERATED_EXAMPLE_QAPI_TYPES
-    #define QAPI_GENERATED_EXAMPLE_QAPI_TYPES
+    $ cat qapi-generated/example-qapi-types.h
+[Uninteresting stuff omitted...]
+
+    #ifndef EXAMPLE_QAPI_TYPES_H
+    #define EXAMPLE_QAPI_TYPES_H
 
-    #include "qapi/qapi-types-core.h"
+[Builtin types omitted...]
 
     typedef struct UserDefOne UserDefOne;
 
     typedef struct UserDefOneList
     {
-        UserDefOne *value;
+        union {
+            UserDefOne *value;
+            uint64_t padding;
+        };
         struct UserDefOneList *next;
     } UserDefOneList;
 
+[Functions on builtin types omitted...]
+
     struct UserDefOne
     {
         int64_t integer;
         char * string;
     };
 
+    void qapi_free_UserDefOneList(UserDefOneList * obj);
     void qapi_free_UserDefOne(UserDefOne * obj);
 
     #endif
 
-
 === scripts/qapi-visit.py ===
 
 Used to generate the visitor functions used to walk through and convert
@@ -325,51 +341,78 @@ $(prefix)qapi-visit.h: declarations for previously mentioned visitor
 
 Example:
 
-    mdroth@illuin:~/w/qemu2.git$ python scripts/qapi-visit.py \
-        --output-dir="qapi-generated" --prefix="example-" --input-file=example-schema.json
-    mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-visit.c
-    /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
+    $ python scripts/qapi-visit.py --output-dir="qapi-generated"
+    --prefix="example-" --input-file=example-schema.json
+    $ cat qapi-generated/example-qapi-visit.c
+[Uninteresting stuff omitted...]
 
-    #include "example-qapi-visit.h"
+    static void visit_type_UserDefOne_fields(Visitor *m, UserDefOne ** obj, Error **errp)
+    {
+        Error *err = NULL;
+        visit_type_int(m, &(*obj)->integer, "integer", &err);
+        if (err) {
+            goto out;
+        }
+        visit_type_str(m, &(*obj)->string, "string", &err);
+        if (err) {
+            goto out;
+        }
+
+    out:
+        error_propagate(errp, err);
+    }
 
     void visit_type_UserDefOne(Visitor *m, UserDefOne ** obj, const char *name, Error **errp)
     {
-        visit_start_struct(m, (void **)obj, "UserDefOne", name, sizeof(UserDefOne), errp);
-        visit_type_int(m, (obj && *obj) ? &(*obj)->integer : NULL, "integer", errp);
-        visit_type_str(m, (obj && *obj) ? &(*obj)->string : NULL, "string", errp);
-        visit_end_struct(m, errp);
+        Error *err = NULL;
+
+        visit_start_struct(m, (void **)obj, "UserDefOne", name, sizeof(UserDefOne), &err);
+        if (!err) {
+            if (*obj) {
+                visit_type_UserDefOne_fields(m, obj, errp);
+            }
+            visit_end_struct(m, &err);
+        }
+        error_propagate(errp, err);
     }
 
     void visit_type_UserDefOneList(Visitor *m, UserDefOneList ** obj, const char *name, Error **errp)
     {
-        GenericList *i, **prev = (GenericList **)obj;
+        Error *err = NULL;
+        GenericList *i, **prev;
 
-        visit_start_list(m, name, errp);
+        visit_start_list(m, name, &err);
+        if (err) {
+            goto out;
+        }
 
-        for (; (i = visit_next_list(m, prev, errp)) != NULL; prev = &i) {
+        for (prev = (GenericList **)obj;
+             !err && (i = visit_next_list(m, prev, &err)) != NULL;
+             prev = &i) {
             UserDefOneList *native_i = (UserDefOneList *)i;
-            visit_type_UserDefOne(m, &native_i->value, NULL, errp);
+            visit_type_UserDefOne(m, &native_i->value, NULL, &err);
         }
 
-        visit_end_list(m, errp);
+        error_propagate(errp, err);
+        err = NULL;
+        visit_end_list(m, &err);
+    out:
+        error_propagate(errp, err);
     }
-    mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-visit.h
-    /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
+    $ python scripts/qapi-commands.py --output-dir="qapi-generated" \
+    --prefix="example-" --input-file=example-schema.json
+    $ cat qapi-generated/example-qapi-visit.h
+[Uninteresting stuff omitted...]
 
-    #ifndef QAPI_GENERATED_EXAMPLE_QAPI_VISIT
-    #define QAPI_GENERATED_EXAMPLE_QAPI_VISIT
+    #ifndef EXAMPLE_QAPI_VISIT_H
+    #define EXAMPLE_QAPI_VISIT_H
 
-    #include "qapi/qapi-visit-core.h"
-    #include "example-qapi-types.h"
+[Visitors for builtin types omitted...]
 
     void visit_type_UserDefOne(Visitor *m, UserDefOne ** obj, const char *name, Error **errp);
     void visit_type_UserDefOneList(Visitor *m, UserDefOneList ** obj, const char *name, Error **errp);
 
     #endif
-    mdroth@illuin:~/w/qemu2.git$
-
-(The actual structure of the visit_type_* functions is a bit more complex
-in order to propagate errors correctly and avoid leaking memory).
 
 === scripts/qapi-commands.py ===
 
@@ -390,77 +433,80 @@ $(prefix)qmp-commands.h: Function prototypes for the QMP commands
 
 Example:
 
-    mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qmp-marshal.c
-    /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
-
-    #include "qemu-objects.h"
-    #include "qapi/qmp-core.h"
-    #include "qapi/qapi-visit-core.h"
-    #include "qapi/qmp-output-visitor.h"
-    #include "qapi/qmp-input-visitor.h"
-    #include "qapi/qapi-dealloc-visitor.h"
-    #include "example-qapi-types.h"
-    #include "example-qapi-visit.h"
+    $ cat qapi-generated/example-qmp-marshal.c
+[Uninteresting stuff omitted...]
 
-    #include "example-qmp-commands.h"
     static void qmp_marshal_output_my_command(UserDefOne * ret_in, QObject **ret_out, Error **errp)
     {
-        QapiDeallocVisitor *md = qapi_dealloc_visitor_new();
+        Error *local_err = NULL;
         QmpOutputVisitor *mo = qmp_output_visitor_new();
+        QapiDeallocVisitor *md;
         Visitor *v;
 
         v = qmp_output_get_visitor(mo);
-        visit_type_UserDefOne(v, &ret_in, "unused", errp);
+        visit_type_UserDefOne(v, &ret_in, "unused", &local_err);
+        if (local_err) {
+            goto out;
+        }
+        *ret_out = qmp_output_get_qobject(mo);
+
+    out:
+        error_propagate(errp, local_err);
+        qmp_output_visitor_cleanup(mo);
+        md = qapi_dealloc_visitor_new();
         v = qapi_dealloc_get_visitor(md);
-        visit_type_UserDefOne(v, &ret_in, "unused", errp);
+        visit_type_UserDefOne(v, &ret_in, "unused", NULL);
         qapi_dealloc_visitor_cleanup(md);
-
-
-        *ret_out = qmp_output_get_qobject(mo);
     }
 
-    static void qmp_marshal_input_my_command(QmpState *qmp__sess, QDict *args, QObject **ret, Error **errp)
+    static void qmp_marshal_input_my_command(QDict *args, QObject **ret, Error **errp)
     {
+        Error *local_err = NULL;
         UserDefOne * retval = NULL;
-        QmpInputVisitor *mi;
+        QmpInputVisitor *mi = qmp_input_visitor_new_strict(QOBJECT(args));
         QapiDeallocVisitor *md;
         Visitor *v;
         UserDefOne * arg1 = NULL;
 
-        mi = qmp_input_visitor_new(QOBJECT(args));
         v = qmp_input_get_visitor(mi);
-        visit_type_UserDefOne(v, &arg1, "arg1", errp);
+        visit_type_UserDefOne(v, &arg1, "arg1", &local_err);
+        if (local_err) {
+            goto out;
+        }
 
-        if (error_is_set(errp)) {
+        retval = qmp_my_command(arg1, &local_err);
+        if (local_err) {
             goto out;
         }
-        retval = qmp_my_command(arg1, errp);
-        qmp_marshal_output_my_command(retval, ret, errp);
+
+        qmp_marshal_output_my_command(retval, ret, &local_err);
 
     out:
+        error_propagate(errp, local_err);
+        qmp_input_visitor_cleanup(mi);
         md = qapi_dealloc_visitor_new();
         v = qapi_dealloc_get_visitor(md);
-        visit_type_UserDefOne(v, &arg1, "arg1", errp);
+        visit_type_UserDefOne(v, &arg1, "arg1", NULL);
         qapi_dealloc_visitor_cleanup(md);
         return;
     }
 
     static void qmp_init_marshal(void)
     {
-        qmp_register_command("my-command", qmp_marshal_input_my_command);
+        qmp_register_command("my-command", qmp_marshal_input_my_command, QCO_NO_OPTIONS);
     }
 
     qapi_init(qmp_init_marshal);
-    mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qmp-commands.h
-    /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
+    $ cat qapi-generated/example-qmp-commands.h
+[Uninteresting stuff omitted...]
 
-    #ifndef QAPI_GENERATED_EXAMPLE_QMP_COMMANDS
-    #define QAPI_GENERATED_EXAMPLE_QMP_COMMANDS
+    #ifndef EXAMPLE_QMP_COMMANDS_H
+    #define EXAMPLE_QMP_COMMANDS_H
 
     #include "example-qapi-types.h"
-    #include "error.h"
+    #include "qapi/qmp/qdict.h"
+    #include "qapi/error.h"
 
     UserDefOne * qmp_my_command(UserDefOne * arg1, Error **errp);
 
     #endif
-    mdroth@illuin:~/w/qemu2.git$
diff --git a/docs/specs/qcow2.txt b/docs/specs/qcow2.txt
index f19536a46f..3f713a6447 100644
--- a/docs/specs/qcow2.txt
+++ b/docs/specs/qcow2.txt
@@ -107,8 +107,9 @@ in the description of a field.
 
          96 -  99:  refcount_order
                     Describes the width of a reference count block entry (width
-                    in bits = 1 << refcount_order). For version 2 images, the
-                    order is always assumed to be 4 (i.e. the width is 16 bits).
+                    in bits: refcount_bits = 1 << refcount_order). For version 2
+                    images, the order is always assumed to be 4
+                    (i.e. refcount_bits = 16).
 
         100 - 103:  header_length
                     Length of the header structure in bytes. For version 2
diff --git a/hmp-commands.hx b/hmp-commands.hx
index 8971f1b153..2e462c04aa 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -556,6 +556,7 @@ ETEXI
         .params     = "keys [hold_ms]",
         .help       = "send keys to the VM (e.g. 'sendkey ctrl-alt-f1', default hold time=100 ms)",
         .mhandler.cmd = hmp_send_key,
+        .command_completion = sendkey_completion,
     },
 
 STEXI
@@ -1233,9 +1234,10 @@ ETEXI
     {
         .name       = "netdev_add",
         .args_type  = "netdev:O",
-        .params     = "[user|tap|socket|hubport|netmap],id=str[,prop=value][,...]",
+        .params     = "[user|tap|socket|vde|bridge|hubport|netmap],id=str[,prop=value][,...]",
         .help       = "add host network device",
         .mhandler.cmd = hmp_netdev_add,
+        .command_completion = netdev_add_completion,
     },
 
 STEXI
@@ -1250,6 +1252,7 @@ ETEXI
         .params     = "id",
         .help       = "remove host network device",
         .mhandler.cmd = hmp_netdev_del,
+        .command_completion = netdev_del_completion,
     },
 
 STEXI
@@ -1339,6 +1342,7 @@ ETEXI
         .params     = "name on|off",
         .help       = "change the link status of a network adapter",
         .mhandler.cmd = hmp_set_link,
+        .command_completion = set_link_completion,
     },
 
 STEXI
@@ -1622,6 +1626,7 @@ ETEXI
         .params     = "args",
         .help       = "add chardev",
         .mhandler.cmd = hmp_chardev_add,
+        .command_completion = chardev_add_completion,
     },
 
 STEXI
@@ -1638,6 +1643,7 @@ ETEXI
         .params     = "id",
         .help       = "remove chardev",
         .mhandler.cmd = hmp_chardev_remove,
+        .command_completion = chardev_remove_completion,
     },
 
 STEXI
diff --git a/hmp.c b/hmp.c
index 5c4d612294..ccc35d41a1 100644
--- a/hmp.c
+++ b/hmp.c
@@ -341,6 +341,11 @@ void hmp_info_block(Monitor *mon, const QDict *qdict)
                            info->value->inserted->backing_file_depth);
         }
 
+        if (info->value->inserted->detect_zeroes != BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF) {
+            monitor_printf(mon, "    Detect zeroes:    %s\n",
+                           BlockdevDetectZeroesOptions_lookup[info->value->inserted->detect_zeroes]);
+        }
+
         if (info->value->inserted->bps
             || info->value->inserted->bps_rd
             || info->value->inserted->bps_wr
@@ -1388,6 +1393,7 @@ void hmp_netdev_del(Monitor *mon, const QDict *qdict)
 void hmp_object_add(Monitor *mon, const QDict *qdict)
 {
     Error *err = NULL;
+    Error *err_end = NULL;
     QemuOpts *opts;
     char *type = NULL;
     char *id = NULL;
@@ -1411,24 +1417,23 @@ void hmp_object_add(Monitor *mon, const QDict *qdict)
     qdict_del(pdict, "qom-type");
     visit_type_str(opts_get_visitor(ov), &type, "qom-type", &err);
     if (err) {
-        goto out_clean;
+        goto out_end;
     }
 
     qdict_del(pdict, "id");
     visit_type_str(opts_get_visitor(ov), &id, "id", &err);
     if (err) {
-        goto out_clean;
+        goto out_end;
     }
 
     object_add(type, id, pdict, opts_get_visitor(ov), &err);
-    if (err) {
-        goto out_clean;
-    }
-    visit_end_struct(opts_get_visitor(ov), &err);
-    if (err) {
+
+out_end:
+    visit_end_struct(opts_get_visitor(ov), &err_end);
+    if (!err && err_end) {
         qmp_object_del(id, NULL);
     }
-
+    error_propagate(&err, err_end);
 out_clean:
     opts_visitor_cleanup(ov);
 
diff --git a/hmp.h b/hmp.h
index 20ef454b4a..aba59e95f0 100644
--- a/hmp.h
+++ b/hmp.h
@@ -97,5 +97,11 @@ void object_add_completion(ReadLineState *rs, int nb_args, const char *str);
 void object_del_completion(ReadLineState *rs, int nb_args, const char *str);
 void device_add_completion(ReadLineState *rs, int nb_args, const char *str);
 void device_del_completion(ReadLineState *rs, int nb_args, const char *str);
+void sendkey_completion(ReadLineState *rs, int nb_args, const char *str);
+void chardev_remove_completion(ReadLineState *rs, int nb_args, const char *str);
+void chardev_add_completion(ReadLineState *rs, int nb_args, const char *str);
+void set_link_completion(ReadLineState *rs, int nb_args, const char *str);
+void netdev_add_completion(ReadLineState *rs, int nb_args, const char *str);
+void netdev_del_completion(ReadLineState *rs, int nb_args, const char *str);
 
 #endif
diff --git a/hw/alpha/dp264.c b/hw/alpha/dp264.c
index 1351ba55bd..b178a03604 100644
--- a/hw/alpha/dp264.c
+++ b/hw/alpha/dp264.c
@@ -43,13 +43,13 @@ static int clipper_pci_map_irq(PCIDevice *d, int irq_num)
     return (slot + 1) * 4 + irq_num;
 }
 
-static void clipper_init(QEMUMachineInitArgs *args)
+static void clipper_init(MachineState *machine)
 {
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
+    ram_addr_t ram_size = machine->ram_size;
+    const char *cpu_model = machine->cpu_model;
+    const char *kernel_filename = machine->kernel_filename;
+    const char *kernel_cmdline = machine->kernel_cmdline;
+    const char *initrd_filename = machine->initrd_filename;
     AlphaCPU *cpus[4];
     PCIBus *pci_bus;
     ISABus *isa_bus;
diff --git a/hw/arm/collie.c b/hw/arm/collie.c
index 8878b0ed9a..ed7851fe06 100644
--- a/hw/arm/collie.c
+++ b/hw/arm/collie.c
@@ -23,12 +23,12 @@ static struct arm_boot_info collie_binfo = {
     .ram_size = 0x20000000,
 };
 
-static void collie_init(QEMUMachineInitArgs *args)
+static void collie_init(MachineState *machine)
 {
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
+    const char *cpu_model = machine->cpu_model;
+    const char *kernel_filename = machine->kernel_filename;
+    const char *kernel_cmdline = machine->kernel_cmdline;
+    const char *initrd_filename = machine->initrd_filename;
     StrongARMState *s;
     DriveInfo *dinfo;
     MemoryRegion *sysmem = get_system_memory();
diff --git a/hw/arm/cubieboard.c b/hw/arm/cubieboard.c
index 9d158c7248..e2260e379f 100644
--- a/hw/arm/cubieboard.c
+++ b/hw/arm/cubieboard.c
@@ -30,7 +30,7 @@ typedef struct CubieBoardState {
     MemoryRegion sdram;
 } CubieBoardState;
 
-static void cubieboard_init(QEMUMachineInitArgs *args)
+static void cubieboard_init(MachineState *machine)
 {
     CubieBoardState *s = g_new(CubieBoardState, 1);
     Error *err = NULL;
@@ -63,14 +63,15 @@ static void cubieboard_init(QEMUMachineInitArgs *args)
         exit(1);
     }
 
-    memory_region_init_ram(&s->sdram, NULL, "cubieboard.ram", args->ram_size);
+    memory_region_init_ram(&s->sdram, NULL, "cubieboard.ram",
+                           machine->ram_size);
     vmstate_register_ram_global(&s->sdram);
     memory_region_add_subregion(get_system_memory(), AW_A10_SDRAM_BASE,
                                 &s->sdram);
 
-    cubieboard_binfo.ram_size = args->ram_size;
-    cubieboard_binfo.kernel_filename = args->kernel_filename;
-    cubieboard_binfo.kernel_cmdline = args->kernel_cmdline;
+    cubieboard_binfo.ram_size = machine->ram_size;
+    cubieboard_binfo.kernel_filename = machine->kernel_filename;
+    cubieboard_binfo.kernel_cmdline = machine->kernel_cmdline;
     arm_load_kernel(&s->a10->cpu, &cubieboard_binfo);
 }
 
diff --git a/hw/arm/digic_boards.c b/hw/arm/digic_boards.c
index 32fc30a69d..d1424eee20 100644
--- a/hw/arm/digic_boards.c
+++ b/hw/arm/digic_boards.c
@@ -143,7 +143,7 @@ static DigicBoard digic4_board_canon_a1100 = {
     .rom1_def_filename = "canon-a1100-rom1.bin",
 };
 
-static void canon_a1100_init(QEMUMachineInitArgs *args)
+static void canon_a1100_init(MachineState *machine)
 {
     digic4_board_init(&digic4_board_canon_a1100);
 }
diff --git a/hw/arm/exynos4_boards.c b/hw/arm/exynos4_boards.c
index 26cedecee3..d644db1ef9 100644
--- a/hw/arm/exynos4_boards.c
+++ b/hw/arm/exynos4_boards.c
@@ -94,7 +94,7 @@ static void lan9215_init(uint32_t base, qemu_irq irq)
     }
 }
 
-static Exynos4210State *exynos4_boards_init_common(QEMUMachineInitArgs *args,
+static Exynos4210State *exynos4_boards_init_common(MachineState *machine,
                                                    Exynos4BoardType board_type)
 {
     if (smp_cpus != EXYNOS4210_NCPUS && !qtest_enabled()) {
@@ -108,9 +108,9 @@ static Exynos4210State *exynos4_boards_init_common(QEMUMachineInitArgs *args,
     exynos4_board_binfo.board_id = exynos4_board_id[board_type];
     exynos4_board_binfo.smp_bootreg_addr =
             exynos4_board_smp_bootreg_addr[board_type];
-    exynos4_board_binfo.kernel_filename = args->kernel_filename;
-    exynos4_board_binfo.initrd_filename = args->initrd_filename;
-    exynos4_board_binfo.kernel_cmdline = args->kernel_cmdline;
+    exynos4_board_binfo.kernel_filename = machine->kernel_filename;
+    exynos4_board_binfo.initrd_filename = machine->initrd_filename;
+    exynos4_board_binfo.kernel_cmdline = machine->kernel_cmdline;
     exynos4_board_binfo.gic_cpu_if_addr =
             EXYNOS4210_SMP_PRIVATE_BASE_ADDR + 0x100;
 
@@ -120,24 +120,24 @@ static Exynos4210State *exynos4_boards_init_common(QEMUMachineInitArgs *args,
             " initrd_filename: %s\n",
             exynos4_board_ram_size[board_type] / 1048576,
             exynos4_board_ram_size[board_type],
-            args->kernel_filename,
-            args->kernel_cmdline,
-            args->initrd_filename);
+            machine->kernel_filename,
+            machine->kernel_cmdline,
+            machine->initrd_filename);
 
     return exynos4210_init(get_system_memory(),
             exynos4_board_ram_size[board_type]);
 }
 
-static void nuri_init(QEMUMachineInitArgs *args)
+static void nuri_init(MachineState *machine)
 {
-    exynos4_boards_init_common(args, EXYNOS4_BOARD_NURI);
+    exynos4_boards_init_common(machine, EXYNOS4_BOARD_NURI);
 
     arm_load_kernel(ARM_CPU(first_cpu), &exynos4_board_binfo);
 }
 
-static void smdkc210_init(QEMUMachineInitArgs *args)
+static void smdkc210_init(MachineState *machine)
 {
-    Exynos4210State *s = exynos4_boards_init_common(args,
+    Exynos4210State *s = exynos4_boards_init_common(machine,
                                                     EXYNOS4_BOARD_SMDKC210);
 
     lan9215_init(SMDK_LAN9118_BASE_ADDR,
diff --git a/hw/arm/gumstix.c b/hw/arm/gumstix.c
index aeea17295b..3f8465ebc0 100644
--- a/hw/arm/gumstix.c
+++ b/hw/arm/gumstix.c
@@ -46,7 +46,7 @@
 
 static const int sector_len = 128 * 1024;
 
-static void connex_init(QEMUMachineInitArgs *args)
+static void connex_init(MachineState *machine)
 {
     PXA2xxState *cpu;
     DriveInfo *dinfo;
@@ -83,9 +83,9 @@ static void connex_init(QEMUMachineInitArgs *args)
                     qdev_get_gpio_in(cpu->gpio, 36));
 }
 
-static void verdex_init(QEMUMachineInitArgs *args)
+static void verdex_init(MachineState *machine)
 {
-    const char *cpu_model = args->cpu_model;
+    const char *cpu_model = machine->cpu_model;
     PXA2xxState *cpu;
     DriveInfo *dinfo;
     int be;
diff --git a/hw/arm/highbank.c b/hw/arm/highbank.c
index 24231e5448..8340434210 100644
--- a/hw/arm/highbank.c
+++ b/hw/arm/highbank.c
@@ -199,13 +199,13 @@ enum cxmachines {
  * 32-bit host, set the reg value of memory to 0xf7ff00000 in the
  * device tree and pass -m 2047 to QEMU.
  */
-static void calxeda_init(QEMUMachineInitArgs *args, enum cxmachines machine)
+static void calxeda_init(MachineState *machine, enum cxmachines machine_id)
 {
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
+    ram_addr_t ram_size = machine->ram_size;
+    const char *cpu_model = machine->cpu_model;
+    const char *kernel_filename = machine->kernel_filename;
+    const char *kernel_cmdline = machine->kernel_cmdline;
+    const char *initrd_filename = machine->initrd_filename;
     DeviceState *dev = NULL;
     SysBusDevice *busdev;
     qemu_irq pic[128];
@@ -217,7 +217,7 @@ static void calxeda_init(QEMUMachineInitArgs *args, enum cxmachines machine)
     char *sysboot_filename;
 
     if (!cpu_model) {
-        switch (machine) {
+        switch (machine_id) {
         case CALXEDA_HIGHBANK:
             cpu_model = "cortex-a9";
             break;
@@ -274,7 +274,7 @@ static void calxeda_init(QEMUMachineInitArgs *args, enum cxmachines machine)
         }
     }
 
-    switch (machine) {
+    switch (machine_id) {
     case CALXEDA_HIGHBANK:
         dev = qdev_create(NULL, "l2x0");
         qdev_init_nofail(dev);
@@ -359,14 +359,14 @@ static void calxeda_init(QEMUMachineInitArgs *args, enum cxmachines machine)
     arm_load_kernel(ARM_CPU(first_cpu), &highbank_binfo);
 }
 
-static void highbank_init(QEMUMachineInitArgs *args)
+static void highbank_init(MachineState *machine)
 {
-    calxeda_init(args, CALXEDA_HIGHBANK);
+    calxeda_init(machine, CALXEDA_HIGHBANK);
 }
 
-static void midway_init(QEMUMachineInitArgs *args)
+static void midway_init(MachineState *machine)
 {
-    calxeda_init(args, CALXEDA_MIDWAY);
+    calxeda_init(machine, CALXEDA_MIDWAY);
 }
 
 static QEMUMachine highbank_machine = {
diff --git a/hw/arm/integratorcp.c b/hw/arm/integratorcp.c
index 912af96ee6..0e476c3db4 100644
--- a/hw/arm/integratorcp.c
+++ b/hw/arm/integratorcp.c
@@ -461,13 +461,13 @@ static struct arm_boot_info integrator_binfo = {
     .board_id = 0x113,
 };
 
-static void integratorcp_init(QEMUMachineInitArgs *args)
+static void integratorcp_init(MachineState *machine)
 {
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
+    ram_addr_t ram_size = machine->ram_size;
+    const char *cpu_model = machine->cpu_model;
+    const char *kernel_filename = machine->kernel_filename;
+    const char *kernel_cmdline = machine->kernel_cmdline;
+    const char *initrd_filename = machine->initrd_filename;
     ARMCPU *cpu;
     MemoryRegion *address_space_mem = get_system_memory();
     MemoryRegion *ram = g_new(MemoryRegion, 1);
diff --git a/hw/arm/kzm.c b/hw/arm/kzm.c
index 99d33cb9d0..0555d12658 100644
--- a/hw/arm/kzm.c
+++ b/hw/arm/kzm.c
@@ -70,13 +70,13 @@ static struct arm_boot_info kzm_binfo = {
     .board_id = 1722,
 };
 
-static void kzm_init(QEMUMachineInitArgs *args)
+static void kzm_init(MachineState *machine)
 {
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
+    ram_addr_t ram_size = machine->ram_size;
+    const char *cpu_model = machine->cpu_model;
+    const char *kernel_filename = machine->kernel_filename;
+    const char *kernel_cmdline = machine->kernel_cmdline;
+    const char *initrd_filename = machine->initrd_filename;
     ARMCPU *cpu;
     MemoryRegion *address_space_mem = get_system_memory();
     MemoryRegion *ram = g_new(MemoryRegion, 1);
diff --git a/hw/arm/mainstone.c b/hw/arm/mainstone.c
index d8e075e26d..44f1873106 100644
--- a/hw/arm/mainstone.c
+++ b/hw/arm/mainstone.c
@@ -105,7 +105,7 @@ static struct arm_boot_info mainstone_binfo = {
 };
 
 static void mainstone_common_init(MemoryRegion *address_space_mem,
-                                  QEMUMachineInitArgs *args,
+                                  MachineState *machine,
                                   enum mainstone_model_e model, int arm_id)
 {
     uint32_t sector_len = 256 * 1024;
@@ -116,7 +116,7 @@ static void mainstone_common_init(MemoryRegion *address_space_mem,
     int i;
     int be;
     MemoryRegion *rom = g_new(MemoryRegion, 1);
-    const char *cpu_model = args->cpu_model;
+    const char *cpu_model = machine->cpu_model;
 
     if (!cpu_model)
         cpu_model = "pxa270-c5";
@@ -175,16 +175,16 @@ static void mainstone_common_init(MemoryRegion *address_space_mem,
     smc91c111_init(&nd_table[0], MST_ETH_PHYS,
                     qdev_get_gpio_in(mst_irq, ETHERNET_IRQ));
 
-    mainstone_binfo.kernel_filename = args->kernel_filename;
-    mainstone_binfo.kernel_cmdline = args->kernel_cmdline;
-    mainstone_binfo.initrd_filename = args->initrd_filename;
+    mainstone_binfo.kernel_filename = machine->kernel_filename;
+    mainstone_binfo.kernel_cmdline = machine->kernel_cmdline;
+    mainstone_binfo.initrd_filename = machine->initrd_filename;
     mainstone_binfo.board_id = arm_id;
     arm_load_kernel(mpu->cpu, &mainstone_binfo);
 }
 
-static void mainstone_init(QEMUMachineInitArgs *args)
+static void mainstone_init(MachineState *machine)
 {
-    mainstone_common_init(get_system_memory(), args, mainstone, 0x196);
+    mainstone_common_init(get_system_memory(), machine, mainstone, 0x196);
 }
 
 static QEMUMachine mainstone2_machine = {
diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c
index 2a27a19d76..6a134f23da 100644
--- a/hw/arm/musicpal.c
+++ b/hw/arm/musicpal.c
@@ -1569,12 +1569,12 @@ static struct arm_boot_info musicpal_binfo = {
     .board_id = 0x20e,
 };
 
-static void musicpal_init(QEMUMachineInitArgs *args)
+static void musicpal_init(MachineState *machine)
 {
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
+    const char *cpu_model = machine->cpu_model;
+    const char *kernel_filename = machine->kernel_filename;
+    const char *kernel_cmdline = machine->kernel_cmdline;
+    const char *initrd_filename = machine->initrd_filename;
     ARMCPU *cpu;
     qemu_irq pic[32];
     DeviceState *dev;
diff --git a/hw/arm/nseries.c b/hw/arm/nseries.c
index c28f895c7a..82772c657e 100644
--- a/hw/arm/nseries.c
+++ b/hw/arm/nseries.c
@@ -1278,14 +1278,14 @@ static int n810_atag_setup(const struct arm_boot_info *info, void *p)
     return n8x0_atag_setup(p, 810);
 }
 
-static void n8x0_init(QEMUMachineInitArgs *args,
+static void n8x0_init(MachineState *machine,
                       struct arm_boot_info *binfo, int model)
 {
     MemoryRegion *sysmem = get_system_memory();
     struct n800_s *s = (struct n800_s *) g_malloc0(sizeof(*s));
     int sdram_size = binfo->ram_size;
 
-    s->mpu = omap2420_mpu_init(sysmem, sdram_size, args->cpu_model);
+    s->mpu = omap2420_mpu_init(sysmem, sdram_size, machine->cpu_model);
 
     /* Setup peripherals
      *
@@ -1329,18 +1329,18 @@ static void n8x0_init(QEMUMachineInitArgs *args,
         n8x0_usb_setup(s);
     }
 
-    if (args->kernel_filename) {
+    if (machine->kernel_filename) {
         /* Or at the linux loader.  */
-        binfo->kernel_filename = args->kernel_filename;
-        binfo->kernel_cmdline = args->kernel_cmdline;
-        binfo->initrd_filename = args->initrd_filename;
+        binfo->kernel_filename = machine->kernel_filename;
+        binfo->kernel_cmdline = machine->kernel_cmdline;
+        binfo->initrd_filename = machine->initrd_filename;
         arm_load_kernel(s->mpu->cpu, binfo);
 
         qemu_register_reset(n8x0_boot_init, s);
     }
 
     if (option_rom[0].name &&
-        (args->boot_order[0] == 'n' || !args->kernel_filename)) {
+        (machine->boot_order[0] == 'n' || !machine->kernel_filename)) {
         uint8_t nolo_tags[0x10000];
         /* No, wait, better start at the ROM.  */
         s->mpu->cpu->env.regs[15] = OMAP2_Q2_BASE + 0x400000;
@@ -1382,14 +1382,14 @@ static struct arm_boot_info n810_binfo = {
     .atag_board = n810_atag_setup,
 };
 
-static void n800_init(QEMUMachineInitArgs *args)
+static void n800_init(MachineState *machine)
 {
-    return n8x0_init(args, &n800_binfo, 800);
+    return n8x0_init(machine, &n800_binfo, 800);
 }
 
-static void n810_init(QEMUMachineInitArgs *args)
+static void n810_init(MachineState *machine)
 {
-    return n8x0_init(args, &n810_binfo, 810);
+    return n8x0_init(machine, &n810_binfo, 810);
 }
 
 static QEMUMachine n800_machine = {
diff --git a/hw/arm/omap_sx1.c b/hw/arm/omap_sx1.c
index 3ba263ab4d..b4f6da6063 100644
--- a/hw/arm/omap_sx1.c
+++ b/hw/arm/omap_sx1.c
@@ -98,7 +98,7 @@ static struct arm_boot_info sx1_binfo = {
     .board_id = 0x265,
 };
 
-static void sx1_init(QEMUMachineInitArgs *args, const int version)
+static void sx1_init(MachineState *machine, const int version)
 {
     struct omap_mpu_state_s *mpu;
     MemoryRegion *address_space = get_system_memory();
@@ -118,7 +118,8 @@ static void sx1_init(QEMUMachineInitArgs *args, const int version)
         flash_size = flash2_size;
     }
 
-    mpu = omap310_mpu_init(address_space, sx1_binfo.ram_size, args->cpu_model);
+    mpu = omap310_mpu_init(address_space, sx1_binfo.ram_size,
+                           machine->cpu_model);
 
     /* External Flash (EMIFS) */
     memory_region_init_ram(flash, NULL, "omap_sx1.flash0-0", flash_size);
@@ -189,29 +190,29 @@ static void sx1_init(QEMUMachineInitArgs *args, const int version)
                                 OMAP_CS1_BASE, &cs[1]);
     }
 
-    if (!args->kernel_filename && !fl_idx && !qtest_enabled()) {
+    if (!machine->kernel_filename && !fl_idx && !qtest_enabled()) {
         fprintf(stderr, "Kernel or Flash image must be specified\n");
         exit(1);
     }
 
     /* Load the kernel.  */
-    sx1_binfo.kernel_filename = args->kernel_filename;
-    sx1_binfo.kernel_cmdline = args->kernel_cmdline;
-    sx1_binfo.initrd_filename = args->initrd_filename;
+    sx1_binfo.kernel_filename = machine->kernel_filename;
+    sx1_binfo.kernel_cmdline = machine->kernel_cmdline;
+    sx1_binfo.initrd_filename = machine->initrd_filename;
     arm_load_kernel(mpu->cpu, &sx1_binfo);
 
     /* TODO: fix next line */
     //~ qemu_console_resize(ds, 640, 480);
 }
 
-static void sx1_init_v1(QEMUMachineInitArgs *args)
+static void sx1_init_v1(MachineState *machine)
 {
-    sx1_init(args, 1);
+    sx1_init(machine, 1);
 }
 
-static void sx1_init_v2(QEMUMachineInitArgs *args)
+static void sx1_init_v2(MachineState *machine)
 {
-    sx1_init(args, 2);
+    sx1_init(machine, 2);
 }
 
 static QEMUMachine sx1_machine_v2 = {
diff --git a/hw/arm/palm.c b/hw/arm/palm.c
index fac4f69807..e61995f96c 100644
--- a/hw/arm/palm.c
+++ b/hw/arm/palm.c
@@ -191,12 +191,12 @@ static struct arm_boot_info palmte_binfo = {
     .board_id = 0x331,
 };
 
-static void palmte_init(QEMUMachineInitArgs *args)
+static void palmte_init(MachineState *machine)
 {
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
+    const char *cpu_model = machine->cpu_model;
+    const char *kernel_filename = machine->kernel_filename;
+    const char *kernel_cmdline = machine->kernel_cmdline;
+    const char *initrd_filename = machine->initrd_filename;
     MemoryRegion *address_space_mem = get_system_memory();
     struct omap_mpu_state_s *mpu;
     int flash_size = 0x00800000;
diff --git a/hw/arm/realview.c b/hw/arm/realview.c
index 7e04e507f9..64b92518dd 100644
--- a/hw/arm/realview.c
+++ b/hw/arm/realview.c
@@ -45,7 +45,7 @@ static const int realview_board_id[] = {
     0x76d
 };
 
-static void realview_init(QEMUMachineInitArgs *args,
+static void realview_init(MachineState *machine,
                           enum realview_board_type board_type)
 {
     ARMCPU *cpu = NULL;
@@ -71,7 +71,7 @@ static void realview_init(QEMUMachineInitArgs *args,
     uint32_t proc_id = 0;
     uint32_t sys_id;
     ram_addr_t low_ram_size;
-    ram_addr_t ram_size = args->ram_size;
+    ram_addr_t ram_size = machine->ram_size;
     hwaddr periphbase = 0;
 
     switch (board_type) {
@@ -91,7 +91,7 @@ static void realview_init(QEMUMachineInitArgs *args,
         break;
     }
 
-    cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, args->cpu_model);
+    cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, machine->cpu_model);
     if (!cpu_oc) {
         fprintf(stderr, "Unable to find CPU definition\n");
         exit(1);
@@ -342,45 +342,45 @@ static void realview_init(QEMUMachineInitArgs *args,
     memory_region_add_subregion(sysmem, SMP_BOOT_ADDR, ram_hack);
 
     realview_binfo.ram_size = ram_size;
-    realview_binfo.kernel_filename = args->kernel_filename;
-    realview_binfo.kernel_cmdline = args->kernel_cmdline;
-    realview_binfo.initrd_filename = args->initrd_filename;
+    realview_binfo.kernel_filename = machine->kernel_filename;
+    realview_binfo.kernel_cmdline = machine->kernel_cmdline;
+    realview_binfo.initrd_filename = machine->initrd_filename;
     realview_binfo.nb_cpus = smp_cpus;
     realview_binfo.board_id = realview_board_id[board_type];
     realview_binfo.loader_start = (board_type == BOARD_PB_A8 ? 0x70000000 : 0);
     arm_load_kernel(ARM_CPU(first_cpu), &realview_binfo);
 }
 
-static void realview_eb_init(QEMUMachineInitArgs *args)
+static void realview_eb_init(MachineState *machine)
 {
-    if (!args->cpu_model) {
-        args->cpu_model = "arm926";
+    if (!machine->cpu_model) {
+        machine->cpu_model = "arm926";
     }
-    realview_init(args, BOARD_EB);
+    realview_init(machine, BOARD_EB);
 }
 
-static void realview_eb_mpcore_init(QEMUMachineInitArgs *args)
+static void realview_eb_mpcore_init(MachineState *machine)
 {
-    if (!args->cpu_model) {
-        args->cpu_model = "arm11mpcore";
+    if (!machine->cpu_model) {
+        machine->cpu_model = "arm11mpcore";
     }
-    realview_init(args, BOARD_EB_MPCORE);
+    realview_init(machine, BOARD_EB_MPCORE);
 }
 
-static void realview_pb_a8_init(QEMUMachineInitArgs *args)
+static void realview_pb_a8_init(MachineState *machine)
 {
-    if (!args->cpu_model) {
-        args->cpu_model = "cortex-a8";
+    if (!machine->cpu_model) {
+        machine->cpu_model = "cortex-a8";
     }
-    realview_init(args, BOARD_PB_A8);
+    realview_init(machine, BOARD_PB_A8);
 }
 
-static void realview_pbx_a9_init(QEMUMachineInitArgs *args)
+static void realview_pbx_a9_init(MachineState *machine)
 {
-    if (!args->cpu_model) {
-        args->cpu_model = "cortex-a9";
+    if (!machine->cpu_model) {
+        machine->cpu_model = "cortex-a9";
     }
-    realview_init(args, BOARD_PBX_A9);
+    realview_init(machine, BOARD_PBX_A9);
 }
 
 static QEMUMachine realview_eb_machine = {
diff --git a/hw/arm/spitz.c b/hw/arm/spitz.c
index a179c1d694..5455dbf326 100644
--- a/hw/arm/spitz.c
+++ b/hw/arm/spitz.c
@@ -887,14 +887,14 @@ static struct arm_boot_info spitz_binfo = {
     .ram_size = 0x04000000,
 };
 
-static void spitz_common_init(QEMUMachineInitArgs *args,
+static void spitz_common_init(MachineState *machine,
                               enum spitz_model_e model, int arm_id)
 {
     PXA2xxState *mpu;
     DeviceState *scp0, *scp1 = NULL;
     MemoryRegion *address_space_mem = get_system_memory();
     MemoryRegion *rom = g_new(MemoryRegion, 1);
-    const char *cpu_model = args->cpu_model;
+    const char *cpu_model = machine->cpu_model;
 
     if (!cpu_model)
         cpu_model = (model == terrier) ? "pxa270-c5" : "pxa270-c0";
@@ -935,32 +935,32 @@ static void spitz_common_init(QEMUMachineInitArgs *args,
         /* A 4.0 GB microdrive is permanently sitting in CF slot 0.  */
         spitz_microdrive_attach(mpu, 0);
 
-    spitz_binfo.kernel_filename = args->kernel_filename;
-    spitz_binfo.kernel_cmdline = args->kernel_cmdline;
-    spitz_binfo.initrd_filename = args->initrd_filename;
+    spitz_binfo.kernel_filename = machine->kernel_filename;
+    spitz_binfo.kernel_cmdline = machine->kernel_cmdline;
+    spitz_binfo.initrd_filename = machine->initrd_filename;
     spitz_binfo.board_id = arm_id;
     arm_load_kernel(mpu->cpu, &spitz_binfo);
     sl_bootparam_write(SL_PXA_PARAM_BASE);
 }
 
-static void spitz_init(QEMUMachineInitArgs *args)
+static void spitz_init(MachineState *machine)
 {
-    spitz_common_init(args, spitz, 0x2c9);
+    spitz_common_init(machine, spitz, 0x2c9);
 }
 
-static void borzoi_init(QEMUMachineInitArgs *args)
+static void borzoi_init(MachineState *machine)
 {
-    spitz_common_init(args, borzoi, 0x33f);
+    spitz_common_init(machine, borzoi, 0x33f);
 }
 
-static void akita_init(QEMUMachineInitArgs *args)
+static void akita_init(MachineState *machine)
 {
-    spitz_common_init(args, akita, 0x2e8);
+    spitz_common_init(machine, akita, 0x2e8);
 }
 
-static void terrier_init(QEMUMachineInitArgs *args)
+static void terrier_init(MachineState *machine)
 {
-    spitz_common_init(args, terrier, 0x33f);
+    spitz_common_init(machine, terrier, 0x33f);
 }
 
 static QEMUMachine akitapda_machine = {
diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c
index a2095c0e84..80028e80cf 100644
--- a/hw/arm/stellaris.c
+++ b/hw/arm/stellaris.c
@@ -1290,9 +1290,10 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model,
 
             sddev = ssi_create_slave(bus, "ssi-sd");
             ssddev = ssi_create_slave(bus, "ssd0323");
-            gpio_out[GPIO_D][0] = qemu_irq_split(qdev_get_gpio_in(sddev, 0),
-                                                 qdev_get_gpio_in(ssddev, 0));
-            gpio_out[GPIO_C][7] = qdev_get_gpio_in(ssddev, 1);
+            gpio_out[GPIO_D][0] = qemu_irq_split(
+                    qdev_get_gpio_in_named(sddev, SSI_GPIO_CS, 0),
+                    qdev_get_gpio_in_named(ssddev, SSI_GPIO_CS, 0));
+            gpio_out[GPIO_C][7] = qdev_get_gpio_in(ssddev, 0);
 
             /* Make sure the select pin is high.  */
             qemu_irq_raise(gpio_out[GPIO_D][0]);
@@ -1333,17 +1334,17 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model,
 }
 
 /* FIXME: Figure out how to generate these from stellaris_boards.  */
-static void lm3s811evb_init(QEMUMachineInitArgs *args)
+static void lm3s811evb_init(MachineState *machine)
 {
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
+    const char *cpu_model = machine->cpu_model;
+    const char *kernel_filename = machine->kernel_filename;
     stellaris_init(kernel_filename, cpu_model, &stellaris_boards[0]);
 }
 
-static void lm3s6965evb_init(QEMUMachineInitArgs *args)
+static void lm3s6965evb_init(MachineState *machine)
 {
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
+    const char *cpu_model = machine->cpu_model;
+    const char *kernel_filename = machine->kernel_filename;
     stellaris_init(kernel_filename, cpu_model, &stellaris_boards[1]);
 }
 
diff --git a/hw/arm/tosa.c b/hw/arm/tosa.c
index 2069f55432..abc0f2a96b 100644
--- a/hw/arm/tosa.c
+++ b/hw/arm/tosa.c
@@ -211,12 +211,12 @@ static struct arm_boot_info tosa_binfo = {
     .ram_size = 0x04000000,
 };
 
-static void tosa_init(QEMUMachineInitArgs *args)
+static void tosa_init(MachineState *machine)
 {
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
+    const char *cpu_model = machine->cpu_model;
+    const char *kernel_filename = machine->kernel_filename;
+    const char *kernel_cmdline = machine->kernel_cmdline;
+    const char *initrd_filename = machine->initrd_filename;
     MemoryRegion *address_space_mem = get_system_memory();
     MemoryRegion *rom = g_new(MemoryRegion, 1);
     PXA2xxState *mpu;
diff --git a/hw/arm/versatilepb.c b/hw/arm/versatilepb.c
index e5493b428f..dea5fc7a95 100644
--- a/hw/arm/versatilepb.c
+++ b/hw/arm/versatilepb.c
@@ -173,7 +173,7 @@ static int vpb_sic_init(SysBusDevice *sbd)
 
 static struct arm_boot_info versatile_binfo;
 
-static void versatile_init(QEMUMachineInitArgs *args, int board_id)
+static void versatile_init(MachineState *machine, int board_id)
 {
     ARMCPU *cpu;
     MemoryRegion *sysmem = get_system_memory();
@@ -190,15 +190,15 @@ static void versatile_init(QEMUMachineInitArgs *args, int board_id)
     int done_smc = 0;
     DriveInfo *dinfo;
 
-    if (!args->cpu_model) {
-        args->cpu_model = "arm926";
+    if (!machine->cpu_model) {
+        machine->cpu_model = "arm926";
     }
-    cpu = cpu_arm_init(args->cpu_model);
+    cpu = cpu_arm_init(machine->cpu_model);
     if (!cpu) {
         fprintf(stderr, "Unable to find CPU definition\n");
         exit(1);
     }
-    memory_region_init_ram(ram, NULL, "versatile.ram", args->ram_size);
+    memory_region_init_ram(ram, NULL, "versatile.ram", machine->ram_size);
     vmstate_register_ram_global(ram);
     /* ??? RAM should repeat to fill physical memory space.  */
     /* SDRAM at address zero.  */
@@ -344,22 +344,22 @@ static void versatile_init(QEMUMachineInitArgs *args, int board_id)
         fprintf(stderr, "qemu: Error registering flash memory.\n");
     }
 
-    versatile_binfo.ram_size = args->ram_size;
-    versatile_binfo.kernel_filename = args->kernel_filename;
-    versatile_binfo.kernel_cmdline = args->kernel_cmdline;
-    versatile_binfo.initrd_filename = args->initrd_filename;
+    versatile_binfo.ram_size = machine->ram_size;
+    versatile_binfo.kernel_filename = machine->kernel_filename;
+    versatile_binfo.kernel_cmdline = machine->kernel_cmdline;
+    versatile_binfo.initrd_filename = machine->initrd_filename;
     versatile_binfo.board_id = board_id;
     arm_load_kernel(cpu, &versatile_binfo);
 }
 
-static void vpb_init(QEMUMachineInitArgs *args)
+static void vpb_init(MachineState *machine)
 {
-    versatile_init(args, 0x183);
+    versatile_init(machine, 0x183);
 }
 
-static void vab_init(QEMUMachineInitArgs *args)
+static void vab_init(MachineState *machine)
 {
-    versatile_init(args, 0x25e);
+    versatile_init(machine, 0x25e);
 }
 
 static QEMUMachine versatilepb_machine = {
diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c
index 169eb061a3..33ff422542 100644
--- a/hw/arm/vexpress.c
+++ b/hw/arm/vexpress.c
@@ -509,7 +509,7 @@ static pflash_t *ve_pflash_cfi01_register(hwaddr base, const char *name,
 }
 
 static void vexpress_common_init(VEDBoardInfo *daughterboard,
-                                 QEMUMachineInitArgs *args)
+                                 MachineState *machine)
 {
     DeviceState *dev, *sysctl, *pl041;
     qemu_irq pic[64];
@@ -525,7 +525,8 @@ static void vexpress_common_init(VEDBoardInfo *daughterboard,
     const hwaddr *map = daughterboard->motherboard_map;
     int i;
 
-    daughterboard->init(daughterboard, args->ram_size, args->cpu_model, pic);
+    daughterboard->init(daughterboard, machine->ram_size, machine->cpu_model,
+                        pic);
 
     /* Motherboard peripherals: the wiring is the same but the
      * addresses vary between the legacy and A-Series memory maps.
@@ -639,10 +640,10 @@ static void vexpress_common_init(VEDBoardInfo *daughterboard,
                              pic[40 + i]);
     }
 
-    daughterboard->bootinfo.ram_size = args->ram_size;
-    daughterboard->bootinfo.kernel_filename = args->kernel_filename;
-    daughterboard->bootinfo.kernel_cmdline = args->kernel_cmdline;
-    daughterboard->bootinfo.initrd_filename = args->initrd_filename;
+    daughterboard->bootinfo.ram_size = machine->ram_size;
+    daughterboard->bootinfo.kernel_filename = machine->kernel_filename;
+    daughterboard->bootinfo.kernel_cmdline = machine->kernel_cmdline;
+    daughterboard->bootinfo.initrd_filename = machine->initrd_filename;
     daughterboard->bootinfo.nb_cpus = smp_cpus;
     daughterboard->bootinfo.board_id = VEXPRESS_BOARD_ID;
     daughterboard->bootinfo.loader_start = daughterboard->loader_start;
@@ -653,14 +654,14 @@ static void vexpress_common_init(VEDBoardInfo *daughterboard,
     arm_load_kernel(ARM_CPU(first_cpu), &daughterboard->bootinfo);
 }
 
-static void vexpress_a9_init(QEMUMachineInitArgs *args)
+static void vexpress_a9_init(MachineState *machine)
 {
-    vexpress_common_init(&a9_daughterboard, args);
+    vexpress_common_init(&a9_daughterboard, machine);
 }
 
-static void vexpress_a15_init(QEMUMachineInitArgs *args)
+static void vexpress_a15_init(MachineState *machine)
 {
-    vexpress_common_init(&a15_daughterboard, args);
+    vexpress_common_init(&a15_daughterboard, machine);
 }
 
 static QEMUMachine vexpress_a9_machine = {
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index ea4f02d32e..3b55a4bf7d 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -383,13 +383,13 @@ static void *machvirt_dtb(const struct arm_boot_info *binfo, int *fdt_size)
     return board->fdt;
 }
 
-static void machvirt_init(QEMUMachineInitArgs *args)
+static void machvirt_init(MachineState *machine)
 {
     qemu_irq pic[NUM_IRQS];
     MemoryRegion *sysmem = get_system_memory();
     int n;
     MemoryRegion *ram = g_new(MemoryRegion, 1);
-    const char *cpu_model = args->cpu_model;
+    const char *cpu_model = machine->cpu_model;
     VirtBoardInfo *vbi;
 
     if (!cpu_model) {
@@ -415,7 +415,7 @@ static void machvirt_init(QEMUMachineInitArgs *args)
         exit(1);
     }
 
-    if (args->ram_size > vbi->memmap[VIRT_MEM].size) {
+    if (machine->ram_size > vbi->memmap[VIRT_MEM].size) {
         error_report("mach-virt: cannot model more than 30GB RAM");
         exit(1);
     }
@@ -447,7 +447,7 @@ static void machvirt_init(QEMUMachineInitArgs *args)
     }
     fdt_add_cpu_nodes(vbi);
 
-    memory_region_init_ram(ram, NULL, "mach-virt.ram", args->ram_size);
+    memory_region_init_ram(ram, NULL, "mach-virt.ram", machine->ram_size);
     vmstate_register_ram_global(ram);
     memory_region_add_subregion(sysmem, vbi->memmap[VIRT_MEM].base, ram);
 
@@ -461,10 +461,10 @@ static void machvirt_init(QEMUMachineInitArgs *args)
      */
     create_virtio_devices(vbi, pic);
 
-    vbi->bootinfo.ram_size = args->ram_size;
-    vbi->bootinfo.kernel_filename = args->kernel_filename;
-    vbi->bootinfo.kernel_cmdline = args->kernel_cmdline;
-    vbi->bootinfo.initrd_filename = args->initrd_filename;
+    vbi->bootinfo.ram_size = machine->ram_size;
+    vbi->bootinfo.kernel_filename = machine->kernel_filename;
+    vbi->bootinfo.kernel_cmdline = machine->kernel_cmdline;
+    vbi->bootinfo.initrd_filename = machine->initrd_filename;
     vbi->bootinfo.nb_cpus = smp_cpus;
     vbi->bootinfo.board_id = -1;
     vbi->bootinfo.loader_start = vbi->memmap[VIRT_MEM].base;
diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c
index 9ee21e726a..ba5aa82cd5 100644
--- a/hw/arm/xilinx_zynq.c
+++ b/hw/arm/xilinx_zynq.c
@@ -94,20 +94,20 @@ static inline void zynq_init_spi_flashes(uint32_t base_addr, qemu_irq irq,
         for (j = 0; j < num_ss; ++j) {
             flash_dev = ssi_create_slave(spi, "n25q128");
 
-            cs_line = qdev_get_gpio_in(flash_dev, 0);
+            cs_line = qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0);
             sysbus_connect_irq(busdev, i * num_ss + j + 1, cs_line);
         }
     }
 
 }
 
-static void zynq_init(QEMUMachineInitArgs *args)
+static void zynq_init(MachineState *machine)
 {
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
+    ram_addr_t ram_size = machine->ram_size;
+    const char *cpu_model = machine->cpu_model;
+    const char *kernel_filename = machine->kernel_filename;
+    const char *kernel_cmdline = machine->kernel_cmdline;
+    const char *initrd_filename = machine->initrd_filename;
     ObjectClass *cpu_oc;
     ARMCPU *cpu;
     MemoryRegion *address_space_mem = get_system_memory();
diff --git a/hw/arm/z2.c b/hw/arm/z2.c
index 5df014b15e..ab9e4c9e79 100644
--- a/hw/arm/z2.c
+++ b/hw/arm/z2.c
@@ -300,12 +300,12 @@ static const TypeInfo aer915_info = {
     .class_init    = aer915_class_init,
 };
 
-static void z2_init(QEMUMachineInitArgs *args)
+static void z2_init(MachineState *machine)
 {
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
+    const char *cpu_model = machine->cpu_model;
+    const char *kernel_filename = machine->kernel_filename;
+    const char *kernel_cmdline = machine->kernel_cmdline;
+    const char *initrd_filename = machine->initrd_filename;
     MemoryRegion *address_space_mem = get_system_memory();
     uint32_t sector_len = 0x10000;
     PXA2xxState *mpu;
diff --git a/hw/audio/intel-hda.c b/hw/audio/intel-hda.c
index d41f82cec4..3cfb66c5d8 100644
--- a/hw/audio/intel-hda.c
+++ b/hw/audio/intel-hda.c
@@ -245,7 +245,7 @@ static void intel_hda_update_int_sts(IntelHDAState *d)
 
     /* update global status */
     if (sts & d->int_ctl) {
-        sts |= (1 << 31);
+        sts |= (1U << 31);
     }
 
     d->int_sts = sts;
@@ -257,7 +257,7 @@ static void intel_hda_update_irq(IntelHDAState *d)
     int level;
 
     intel_hda_update_int_sts(d);
-    if (d->int_sts & (1 << 31) && d->int_ctl & (1 << 31)) {
+    if (d->int_sts & (1U << 31) && d->int_ctl & (1U << 31)) {
         level = 1;
     } else {
         level = 0;
@@ -574,7 +574,7 @@ static void intel_hda_set_st_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint3
     if (st->ctl & 0x01) {
         /* reset */
         dprint(d, 1, "st #%d: reset\n", reg->stream);
-        st->ctl = 0;
+        st->ctl = SD_STS_FIFO_READY << 24;
     }
     if ((st->ctl & 0x02) != (old & 0x02)) {
         uint32_t stnr = (st->ctl >> 20) & 0x0f;
@@ -829,6 +829,7 @@ static const struct IntelHDAReg regtab[] = {
         .wclear   = 0x1c000000,                                       \
         .offset   = offsetof(IntelHDAState, st[_i].ctl),              \
         .whandler = intel_hda_set_st_ctl,                             \
+        .reset    = SD_STS_FIFO_READY << 24                           \
     },                                                                \
     [ ST_REG(_i, ICH6_REG_SD_LPIB) ] = {                              \
         .stream   = _i,                                               \
diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c
index 70b8a5ab75..e49c2536b1 100644
--- a/hw/block/dataplane/virtio-blk.c
+++ b/hw/block/dataplane/virtio-blk.c
@@ -70,6 +70,9 @@ struct VirtIOBlockDataPlane {
                                              queue */
 
     unsigned int num_reqs;
+
+    /* Operation blocker on BDS */
+    Error *blocker;
 };
 
 /* Raise an interrupt to signal guest, if necessary */
@@ -350,6 +353,7 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk,
 {
     VirtIOBlockDataPlane *s;
     int fd;
+    Error *local_err = NULL;
 
     *dataplane = NULL;
 
@@ -372,9 +376,10 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk,
     /* If dataplane is (re-)enabled while the guest is running there could be
      * block jobs that can conflict.
      */
-    if (bdrv_in_use(blk->conf.bs)) {
-        error_setg(errp,
-                   "cannot start dataplane thread while device is in use");
+    if (bdrv_op_is_blocked(blk->conf.bs, BLOCK_OP_TYPE_DATAPLANE, &local_err)) {
+        error_report("cannot start dataplane thread: %s",
+                      error_get_pretty(local_err));
+        error_free(local_err);
         return;
     }
 
@@ -406,8 +411,8 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk,
     }
     s->ctx = iothread_get_aio_context(s->iothread);
 
-    /* Prevent block operations that conflict with data plane thread */
-    bdrv_set_in_use(blk->conf.bs, 1);
+    error_setg(&s->blocker, "block device is in use by data plane");
+    bdrv_op_block_all(blk->conf.bs, s->blocker);
 
     *dataplane = s;
 }
@@ -420,7 +425,8 @@ void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s)
     }
 
     virtio_blk_data_plane_stop(s);
-    bdrv_set_in_use(s->blk->conf.bs, 0);
+    bdrv_op_unblock_all(s->blk->conf.bs, s->blocker);
+    error_free(s->blocker);
     object_unref(OBJECT(s->iothread));
     g_free(s);
 }
diff --git a/hw/char/escc.c b/hw/char/escc.c
index 6397f6f282..d9a20aa931 100644
--- a/hw/char/escc.c
+++ b/hw/char/escc.c
@@ -27,6 +27,7 @@
 #include "hw/char/escc.h"
 #include "sysemu/char.h"
 #include "ui/console.h"
+#include "ui/input.h"
 #include "trace.h"
 
 /*
@@ -94,6 +95,7 @@ typedef struct ChannelState {
     ChnID chn; // this channel, A (base+4) or B (base+0)
     ChnType type;
     uint8_t rx, tx;
+    QemuInputHandlerState *hs;
 } ChannelState;
 
 #define ESCC(obj) OBJECT_CHECK(ESCCState, (obj), TYPE_ESCC)
@@ -714,71 +716,181 @@ MemoryRegion *escc_init(hwaddr base, qemu_irq irqA, qemu_irq irqB,
     return &d->mmio;
 }
 
-static const uint8_t keycodes[128] = {
-    127, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 43, 53,
-    54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 89, 76, 77, 78,
-    79, 80, 81, 82, 83, 84, 85, 86, 87, 42, 99, 88, 100, 101, 102, 103,
-    104, 105, 106, 107, 108, 109, 110, 47, 19, 121, 119, 5, 6, 8, 10, 12,
-    14, 16, 17, 18, 7, 98, 23, 68, 69, 70, 71, 91, 92, 93, 125, 112,
-    113, 114, 94, 50, 0, 0, 124, 9, 11, 0, 0, 0, 0, 0, 0, 0,
-    90, 0, 46, 22, 13, 111, 52, 20, 96, 24, 28, 74, 27, 123, 44, 66,
-    0, 45, 2, 4, 48, 0, 0, 21, 0, 0, 0, 0, 0, 120, 122, 67,
+static const uint8_t qcode_to_keycode[Q_KEY_CODE_MAX] = {
+    [Q_KEY_CODE_SHIFT]         = 99,
+    [Q_KEY_CODE_SHIFT_R]       = 110,
+    [Q_KEY_CODE_ALT]           = 19,
+    [Q_KEY_CODE_ALT_R]         = 13,
+    [Q_KEY_CODE_ALTGR]         = 13,
+    [Q_KEY_CODE_CTRL]          = 76,
+    [Q_KEY_CODE_CTRL_R]        = 76,
+    [Q_KEY_CODE_ESC]           = 29,
+    [Q_KEY_CODE_1]             = 30,
+    [Q_KEY_CODE_2]             = 31,
+    [Q_KEY_CODE_3]             = 32,
+    [Q_KEY_CODE_4]             = 33,
+    [Q_KEY_CODE_5]             = 34,
+    [Q_KEY_CODE_6]             = 35,
+    [Q_KEY_CODE_7]             = 36,
+    [Q_KEY_CODE_8]             = 37,
+    [Q_KEY_CODE_9]             = 38,
+    [Q_KEY_CODE_0]             = 39,
+    [Q_KEY_CODE_MINUS]         = 40,
+    [Q_KEY_CODE_EQUAL]         = 41,
+    [Q_KEY_CODE_BACKSPACE]     = 43,
+    [Q_KEY_CODE_TAB]           = 53,
+    [Q_KEY_CODE_Q]             = 54,
+    [Q_KEY_CODE_W]             = 55,
+    [Q_KEY_CODE_E]             = 56,
+    [Q_KEY_CODE_R]             = 57,
+    [Q_KEY_CODE_T]             = 58,
+    [Q_KEY_CODE_Y]             = 59,
+    [Q_KEY_CODE_U]             = 60,
+    [Q_KEY_CODE_I]             = 61,
+    [Q_KEY_CODE_O]             = 62,
+    [Q_KEY_CODE_P]             = 63,
+    [Q_KEY_CODE_BRACKET_LEFT]  = 64,
+    [Q_KEY_CODE_BRACKET_RIGHT] = 65,
+    [Q_KEY_CODE_RET]           = 89,
+    [Q_KEY_CODE_A]             = 77,
+    [Q_KEY_CODE_S]             = 78,
+    [Q_KEY_CODE_D]             = 79,
+    [Q_KEY_CODE_F]             = 80,
+    [Q_KEY_CODE_G]             = 81,
+    [Q_KEY_CODE_H]             = 82,
+    [Q_KEY_CODE_J]             = 83,
+    [Q_KEY_CODE_K]             = 84,
+    [Q_KEY_CODE_L]             = 85,
+    [Q_KEY_CODE_SEMICOLON]     = 86,
+    [Q_KEY_CODE_APOSTROPHE]    = 87,
+    [Q_KEY_CODE_GRAVE_ACCENT]  = 42,
+    [Q_KEY_CODE_BACKSLASH]     = 88,
+    [Q_KEY_CODE_Z]             = 100,
+    [Q_KEY_CODE_X]             = 101,
+    [Q_KEY_CODE_C]             = 102,
+    [Q_KEY_CODE_V]             = 103,
+    [Q_KEY_CODE_B]             = 104,
+    [Q_KEY_CODE_N]             = 105,
+    [Q_KEY_CODE_M]             = 106,
+    [Q_KEY_CODE_COMMA]         = 107,
+    [Q_KEY_CODE_DOT]           = 108,
+    [Q_KEY_CODE_SLASH]         = 109,
+    [Q_KEY_CODE_ASTERISK]      = 47,
+    [Q_KEY_CODE_SPC]           = 121,
+    [Q_KEY_CODE_CAPS_LOCK]     = 119,
+    [Q_KEY_CODE_F1]            = 5,
+    [Q_KEY_CODE_F2]            = 6,
+    [Q_KEY_CODE_F3]            = 8,
+    [Q_KEY_CODE_F4]            = 10,
+    [Q_KEY_CODE_F5]            = 12,
+    [Q_KEY_CODE_F6]            = 14,
+    [Q_KEY_CODE_F7]            = 16,
+    [Q_KEY_CODE_F8]            = 17,
+    [Q_KEY_CODE_F9]            = 18,
+    [Q_KEY_CODE_F10]           = 7,
+    [Q_KEY_CODE_NUM_LOCK]      = 98,
+    [Q_KEY_CODE_SCROLL_LOCK]   = 23,
+    [Q_KEY_CODE_KP_DIVIDE]     = 46,
+    [Q_KEY_CODE_KP_MULTIPLY]   = 47,
+    [Q_KEY_CODE_KP_SUBTRACT]   = 71,
+    [Q_KEY_CODE_KP_ADD]        = 125,
+    [Q_KEY_CODE_KP_ENTER]      = 90,
+    [Q_KEY_CODE_KP_DECIMAL]    = 50,
+    [Q_KEY_CODE_KP_0]          = 94,
+    [Q_KEY_CODE_KP_1]          = 112,
+    [Q_KEY_CODE_KP_2]          = 113,
+    [Q_KEY_CODE_KP_3]          = 114,
+    [Q_KEY_CODE_KP_4]          = 91,
+    [Q_KEY_CODE_KP_5]          = 92,
+    [Q_KEY_CODE_KP_6]          = 93,
+    [Q_KEY_CODE_KP_7]          = 68,
+    [Q_KEY_CODE_KP_8]          = 69,
+    [Q_KEY_CODE_KP_9]          = 70,
+    [Q_KEY_CODE_LESS]          = 124,
+    [Q_KEY_CODE_F11]           = 9,
+    [Q_KEY_CODE_F12]           = 11,
+    [Q_KEY_CODE_HOME]          = 52,
+    [Q_KEY_CODE_PGUP]          = 96,
+    [Q_KEY_CODE_PGDN]          = 123,
+    [Q_KEY_CODE_END]           = 74,
+    [Q_KEY_CODE_LEFT]          = 24,
+    [Q_KEY_CODE_UP]            = 20,
+    [Q_KEY_CODE_DOWN]          = 27,
+    [Q_KEY_CODE_RIGHT]         = 28,
+    [Q_KEY_CODE_INSERT]        = 44,
+    [Q_KEY_CODE_DELETE]        = 66,
+    [Q_KEY_CODE_STOP]          = 1,
+    [Q_KEY_CODE_AGAIN]         = 3,
+    [Q_KEY_CODE_PROPS]         = 25,
+    [Q_KEY_CODE_UNDO]          = 26,
+    [Q_KEY_CODE_FRONT]         = 49,
+    [Q_KEY_CODE_COPY]          = 51,
+    [Q_KEY_CODE_OPEN]          = 72,
+    [Q_KEY_CODE_PASTE]         = 73,
+    [Q_KEY_CODE_FIND]          = 95,
+    [Q_KEY_CODE_CUT]           = 97,
+    [Q_KEY_CODE_LF]            = 111,
+    [Q_KEY_CODE_HELP]          = 118,
+    [Q_KEY_CODE_META_L]        = 120,
+    [Q_KEY_CODE_META_R]        = 122,
+    [Q_KEY_CODE_COMPOSE]       = 67,
+    [Q_KEY_CODE_PRINT]         = 22,
+    [Q_KEY_CODE_SYSRQ]         = 21,
 };
 
-static const uint8_t e0_keycodes[128] = {
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 90, 76, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 109, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 68, 69, 70, 0, 91, 0, 93, 0, 112,
-    113, 114, 94, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    1, 3, 25, 26, 49, 52, 72, 73, 97, 99, 111, 118, 120, 122, 67, 0,
-};
-
-static void sunkbd_event(void *opaque, int ch)
+static void sunkbd_handle_event(DeviceState *dev, QemuConsole *src,
+                                InputEvent *evt)
 {
-    ChannelState *s = opaque;
-    int release = ch & 0x80;
-
-    trace_escc_sunkbd_event_in(ch);
-    switch (ch) {
-    case 58: // Caps lock press
-        s->caps_lock_mode ^= 1;
-        if (s->caps_lock_mode == 2)
-            return; // Drop second press
-        break;
-    case 69: // Num lock press
-        s->num_lock_mode ^= 1;
-        if (s->num_lock_mode == 2)
-            return; // Drop second press
-        break;
-    case 186: // Caps lock release
-        s->caps_lock_mode ^= 2;
-        if (s->caps_lock_mode == 3)
-            return; // Drop first release
-        break;
-    case 197: // Num lock release
-        s->num_lock_mode ^= 2;
-        if (s->num_lock_mode == 3)
-            return; // Drop first release
-        break;
-    case 0xe0:
-        s->e0_mode = 1;
-        return;
-    default:
-        break;
+    ChannelState *s = (ChannelState *)dev;
+    int qcode, keycode;
+
+    assert(evt->kind == INPUT_EVENT_KIND_KEY);
+    qcode = qemu_input_key_value_to_qcode(evt->key->key);
+    trace_escc_sunkbd_event_in(qcode, QKeyCode_lookup[qcode],
+                               evt->key->down);
+
+    if (qcode == Q_KEY_CODE_CAPS_LOCK) {
+        if (evt->key->down) {
+            s->caps_lock_mode ^= 1;
+            if (s->caps_lock_mode == 2) {
+                return; /* Drop second press */
+            }
+        } else {
+            s->caps_lock_mode ^= 2;
+            if (s->caps_lock_mode == 3) {
+                return; /* Drop first release */
+            }
+        }
     }
-    if (s->e0_mode) {
-        s->e0_mode = 0;
-        ch = e0_keycodes[ch & 0x7f];
-    } else {
-        ch = keycodes[ch & 0x7f];
+
+    if (qcode == Q_KEY_CODE_NUM_LOCK) {
+        if (evt->key->down) {
+            s->num_lock_mode ^= 1;
+            if (s->num_lock_mode == 2) {
+                return; /* Drop second press */
+            }
+        } else {
+            s->num_lock_mode ^= 2;
+            if (s->num_lock_mode == 3) {
+                return; /* Drop first release */
+            }
+        }
+    }
+
+    keycode = qcode_to_keycode[qcode];
+    if (!evt->key->down) {
+        keycode |= 0x80;
     }
-    trace_escc_sunkbd_event_out(ch);
-    put_queue(s, ch | release);
+    trace_escc_sunkbd_event_out(keycode);
+    put_queue(s, keycode);
 }
 
+static QemuInputHandler sunkbd_handler = {
+    .name  = "sun keyboard",
+    .mask  = INPUT_EVENT_MASK_KEY,
+    .event = sunkbd_handle_event,
+};
+
 static void handle_kbd_command(ChannelState *s, int val)
 {
     trace_escc_kbd_command(val);
@@ -800,7 +912,7 @@ static void handle_kbd_command(ChannelState *s, int val)
     case 0xf:
         clear_queue(s);
         put_queue(s, 0xfe);
-        put_queue(s, 0); // XXX, layout?
+        put_queue(s, 0x21); /*  en-us layout */
         break;
     default:
         break;
@@ -898,7 +1010,8 @@ static int escc_init1(SysBusDevice *dev)
                                      "QEMU Sun Mouse");
     }
     if (s->chn[1].type == kbd) {
-        qemu_add_kbd_event_handler(sunkbd_event, &s->chn[1]);
+        s->chn[1].hs = qemu_input_handler_register((DeviceState *)(&s->chn[1]),
+                                                   &sunkbd_handler);
     }
 
     return 0;
diff --git a/hw/core/machine.c b/hw/core/machine.c
index d3ffef7e07..cbba6791d2 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -11,6 +11,284 @@
  */
 
 #include "hw/boards.h"
+#include "qapi/visitor.h"
+
+static char *machine_get_accel(Object *obj, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+
+    return g_strdup(ms->accel);
+}
+
+static void machine_set_accel(Object *obj, const char *value, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+
+    ms->accel = g_strdup(value);
+}
+
+static bool machine_get_kernel_irqchip(Object *obj, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+
+    return ms->kernel_irqchip;
+}
+
+static void machine_set_kernel_irqchip(Object *obj, bool value, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+
+    ms->kernel_irqchip = value;
+}
+
+static void machine_get_kvm_shadow_mem(Object *obj, Visitor *v,
+                                       void *opaque, const char *name,
+                                       Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+    int64_t value = ms->kvm_shadow_mem;
+
+    visit_type_int(v, &value, name, errp);
+}
+
+static void machine_set_kvm_shadow_mem(Object *obj, Visitor *v,
+                                       void *opaque, const char *name,
+                                       Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+    Error *error = NULL;
+    int64_t value;
+
+    visit_type_int(v, &value, name, &error);
+    if (error) {
+        error_propagate(errp, error);
+        return;
+    }
+
+    ms->kvm_shadow_mem = value;
+}
+
+static char *machine_get_kernel(Object *obj, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+
+    return g_strdup(ms->kernel_filename);
+}
+
+static void machine_set_kernel(Object *obj, const char *value, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+
+    ms->kernel_filename = g_strdup(value);
+}
+
+static char *machine_get_initrd(Object *obj, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+
+    return g_strdup(ms->initrd_filename);
+}
+
+static void machine_set_initrd(Object *obj, const char *value, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+
+    ms->initrd_filename = g_strdup(value);
+}
+
+static char *machine_get_append(Object *obj, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+
+    return g_strdup(ms->kernel_cmdline);
+}
+
+static void machine_set_append(Object *obj, const char *value, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+
+    ms->kernel_cmdline = g_strdup(value);
+}
+
+static char *machine_get_dtb(Object *obj, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+
+    return g_strdup(ms->dtb);
+}
+
+static void machine_set_dtb(Object *obj, const char *value, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+
+    ms->dtb = g_strdup(value);
+}
+
+static char *machine_get_dumpdtb(Object *obj, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+
+    return g_strdup(ms->dumpdtb);
+}
+
+static void machine_set_dumpdtb(Object *obj, const char *value, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+
+    ms->dumpdtb = g_strdup(value);
+}
+
+static void machine_get_phandle_start(Object *obj, Visitor *v,
+                                       void *opaque, const char *name,
+                                       Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+    int64_t value = ms->phandle_start;
+
+    visit_type_int(v, &value, name, errp);
+}
+
+static void machine_set_phandle_start(Object *obj, Visitor *v,
+                                       void *opaque, const char *name,
+                                       Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+    Error *error = NULL;
+    int64_t value;
+
+    visit_type_int(v, &value, name, &error);
+    if (error) {
+        error_propagate(errp, error);
+        return;
+    }
+
+    ms->phandle_start = value;
+}
+
+static char *machine_get_dt_compatible(Object *obj, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+
+    return g_strdup(ms->dt_compatible);
+}
+
+static void machine_set_dt_compatible(Object *obj, const char *value, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+
+    ms->dt_compatible = g_strdup(value);
+}
+
+static bool machine_get_dump_guest_core(Object *obj, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+
+    return ms->dump_guest_core;
+}
+
+static void machine_set_dump_guest_core(Object *obj, bool value, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+
+    ms->dump_guest_core = value;
+}
+
+static bool machine_get_mem_merge(Object *obj, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+
+    return ms->mem_merge;
+}
+
+static void machine_set_mem_merge(Object *obj, bool value, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+
+    ms->mem_merge = value;
+}
+
+static bool machine_get_usb(Object *obj, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+
+    return ms->usb;
+}
+
+static void machine_set_usb(Object *obj, bool value, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+
+    ms->usb = value;
+}
+
+static char *machine_get_firmware(Object *obj, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+
+    return g_strdup(ms->firmware);
+}
+
+static void machine_set_firmware(Object *obj, const char *value, Error **errp)
+{
+    MachineState *ms = MACHINE(obj);
+
+    ms->firmware = g_strdup(value);
+}
+
+static void machine_initfn(Object *obj)
+{
+    object_property_add_str(obj, "accel",
+                            machine_get_accel, machine_set_accel, NULL);
+    object_property_add_bool(obj, "kernel_irqchip",
+                             machine_get_kernel_irqchip,
+                             machine_set_kernel_irqchip,
+                             NULL);
+    object_property_add(obj, "kvm_shadow_mem", "int",
+                        machine_get_kvm_shadow_mem,
+                        machine_set_kvm_shadow_mem,
+                        NULL, NULL, NULL);
+    object_property_add_str(obj, "kernel",
+                            machine_get_kernel, machine_set_kernel, NULL);
+    object_property_add_str(obj, "initrd",
+                            machine_get_initrd, machine_set_initrd, NULL);
+    object_property_add_str(obj, "append",
+                            machine_get_append, machine_set_append, NULL);
+    object_property_add_str(obj, "dtb",
+                            machine_get_dtb, machine_set_dtb, NULL);
+    object_property_add_str(obj, "dumpdtb",
+                            machine_get_dumpdtb, machine_set_dumpdtb, NULL);
+    object_property_add(obj, "phandle_start", "int",
+                        machine_get_phandle_start,
+                        machine_set_phandle_start,
+                        NULL, NULL, NULL);
+    object_property_add_str(obj, "dt_compatible",
+                            machine_get_dt_compatible,
+                            machine_set_dt_compatible,
+                            NULL);
+    object_property_add_bool(obj, "dump-guest-core",
+                             machine_get_dump_guest_core,
+                             machine_set_dump_guest_core,
+                             NULL);
+    object_property_add_bool(obj, "mem-merge",
+                             machine_get_mem_merge, machine_set_mem_merge, NULL);
+    object_property_add_bool(obj, "usb", machine_get_usb, machine_set_usb, NULL);
+    object_property_add_str(obj, "firmware",
+                            machine_get_firmware, machine_set_firmware, NULL);
+}
+
+static void machine_finalize(Object *obj)
+{
+    MachineState *ms = MACHINE(obj);
+
+    g_free(ms->accel);
+    g_free(ms->kernel_filename);
+    g_free(ms->initrd_filename);
+    g_free(ms->kernel_cmdline);
+    g_free(ms->dtb);
+    g_free(ms->dumpdtb);
+    g_free(ms->dt_compatible);
+    g_free(ms->firmware);
+}
 
 static const TypeInfo machine_info = {
     .name = TYPE_MACHINE,
@@ -18,6 +296,8 @@ static const TypeInfo machine_info = {
     .abstract = true,
     .class_size = sizeof(MachineClass),
     .instance_size = sizeof(MachineState),
+    .instance_init = machine_initfn,
+    .instance_finalize = machine_finalize,
 };
 
 static void machine_register_types(void)
diff --git a/hw/core/null-machine.c b/hw/core/null-machine.c
index d813c089e7..1ec7c3bbe0 100644
--- a/hw/core/null-machine.c
+++ b/hw/core/null-machine.c
@@ -15,7 +15,7 @@
 #include "hw/hw.h"
 #include "hw/boards.h"
 
-static void machine_none_init(QEMUMachineInitArgs *args)
+static void machine_none_init(MachineState *machine)
 {
 }
 
diff --git a/hw/core/qdev.c b/hw/core/qdev.c
index 936eae6412..e65a5aa3a8 100644
--- a/hw/core/qdev.c
+++ b/hw/core/qdev.c
@@ -312,30 +312,82 @@ BusState *qdev_get_parent_bus(DeviceState *dev)
     return dev->parent_bus;
 }
 
+static NamedGPIOList *qdev_get_named_gpio_list(DeviceState *dev,
+                                               const char *name)
+{
+    NamedGPIOList *ngl;
+
+    QLIST_FOREACH(ngl, &dev->gpios, node) {
+        /* NULL is a valid and matchable name, otherwise do a normal
+         * strcmp match.
+         */
+        if ((!ngl->name && !name) ||
+                (name && ngl->name && strcmp(name, ngl->name) == 0)) {
+            return ngl;
+        }
+    }
+
+    ngl = g_malloc0(sizeof(*ngl));
+    ngl->name = g_strdup(name);
+    QLIST_INSERT_HEAD(&dev->gpios, ngl, node);
+    return ngl;
+}
+
+void qdev_init_gpio_in_named(DeviceState *dev, qemu_irq_handler handler,
+                             const char *name, int n)
+{
+    NamedGPIOList *gpio_list = qdev_get_named_gpio_list(dev, name);
+
+    gpio_list->in = qemu_extend_irqs(gpio_list->in, gpio_list->num_in, handler,
+                                     dev, n);
+    gpio_list->num_in += n;
+}
+
 void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
 {
-    dev->gpio_in = qemu_extend_irqs(dev->gpio_in, dev->num_gpio_in, handler,
-                                        dev, n);
-    dev->num_gpio_in += n;
+    qdev_init_gpio_in_named(dev, handler, NULL, n);
+}
+
+void qdev_init_gpio_out_named(DeviceState *dev, qemu_irq *pins,
+                              const char *name, int n)
+{
+    NamedGPIOList *gpio_list = qdev_get_named_gpio_list(dev, name);
+
+    assert(gpio_list->num_out == 0);
+    gpio_list->num_out = n;
+    gpio_list->out = pins;
 }
 
 void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
 {
-    assert(dev->num_gpio_out == 0);
-    dev->num_gpio_out = n;
-    dev->gpio_out = pins;
+    qdev_init_gpio_out_named(dev, pins, NULL, n);
+}
+
+qemu_irq qdev_get_gpio_in_named(DeviceState *dev, const char *name, int n)
+{
+    NamedGPIOList *gpio_list = qdev_get_named_gpio_list(dev, name);
+
+    assert(n >= 0 && n < gpio_list->num_in);
+    return gpio_list->in[n];
 }
 
 qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
 {
-    assert(n >= 0 && n < dev->num_gpio_in);
-    return dev->gpio_in[n];
+    return qdev_get_gpio_in_named(dev, NULL, n);
+}
+
+void qdev_connect_gpio_out_named(DeviceState *dev, const char *name, int n,
+                                 qemu_irq pin)
+{
+    NamedGPIOList *gpio_list = qdev_get_named_gpio_list(dev, name);
+
+    assert(n >= 0 && n < gpio_list->num_out);
+    gpio_list->out[n] = pin;
 }
 
 void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
 {
-    assert(n >= 0 && n < dev->num_gpio_out);
-    dev->gpio_out[n] = pin;
+    qdev_connect_gpio_out_named(dev, NULL, n, pin);
 }
 
 BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
@@ -844,6 +896,7 @@ static void device_initfn(Object *obj)
     object_property_add_link(OBJECT(dev), "parent_bus", TYPE_BUS,
                              (Object **)&dev->parent_bus, NULL, 0,
                              &error_abort);
+    QLIST_INIT(&dev->gpios);
 }
 
 static void device_post_init(Object *obj)
@@ -854,10 +907,22 @@ static void device_post_init(Object *obj)
 /* Unlink device from bus and free the structure.  */
 static void device_finalize(Object *obj)
 {
+    NamedGPIOList *ngl, *next;
+
     DeviceState *dev = DEVICE(obj);
     if (dev->opts) {
         qemu_opts_del(dev->opts);
     }
+
+    QLIST_FOREACH_SAFE(ngl, &dev->gpios, node, next) {
+        QLIST_REMOVE(ngl, node);
+        qemu_free_irqs(ngl->in);
+        g_free(ngl->name);
+        g_free(ngl);
+        /* ngl->out irqs are owned by the other end and should not be freed
+         * here
+         */
+    }
 }
 
 static void device_class_base_init(ObjectClass *class, void *data)
diff --git a/hw/cris/axis_dev88.c b/hw/cris/axis_dev88.c
index 645e45ccdf..1849338013 100644
--- a/hw/cris/axis_dev88.c
+++ b/hw/cris/axis_dev88.c
@@ -243,12 +243,12 @@ static const MemoryRegionOps gpio_ops = {
 static struct cris_load_info li;
 
 static
-void axisdev88_init(QEMUMachineInitArgs *args)
+void axisdev88_init(MachineState *machine)
 {
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
+    ram_addr_t ram_size = machine->ram_size;
+    const char *cpu_model = machine->cpu_model;
+    const char *kernel_filename = machine->kernel_filename;
+    const char *kernel_cmdline = machine->kernel_cmdline;
     CRISCPU *cpu;
     CPUCRISState *env;
     DeviceState *dev;
diff --git a/hw/display/jazz_led.c b/hw/display/jazz_led.c
index e9bb005413..12b1707cb2 100644
--- a/hw/display/jazz_led.c
+++ b/hw/display/jazz_led.c
@@ -173,6 +173,7 @@ static void jazz_led_update_display(void *opaque)
             case 16:
                 color_segment = rgb_to_pixel16(0xaa, 0xaa, 0xaa);
                 color_led = rgb_to_pixel16(0x00, 0xff, 0x00);
+                break;
             case 24:
                 color_segment = rgb_to_pixel24(0xaa, 0xaa, 0xaa);
                 color_led = rgb_to_pixel24(0x00, 0xff, 0x00);
diff --git a/hw/display/pxa2xx_lcd.c b/hw/display/pxa2xx_lcd.c
index 80edb70676..611fb174cd 100644
--- a/hw/display/pxa2xx_lcd.c
+++ b/hw/display/pxa2xx_lcd.c
@@ -620,24 +620,24 @@ static void pxa2xx_palette_parse(PXA2xxLCDState *s, int ch, int bpp)
             src += 2;
             break;
         case 1: /* 16 bpp plus transparency */
-            alpha = *(uint16_t *) src & (1 << 24);
+            alpha = *(uint32_t *) src & (1 << 24);
             if (s->control[0] & LCCR0_CMS)
-                r = g = b = *(uint16_t *) src & 0xff;
+                r = g = b = *(uint32_t *) src & 0xff;
             else {
-                r = (*(uint16_t *) src & 0xf800) >> 8;
-                g = (*(uint16_t *) src & 0x07e0) >> 3;
-                b = (*(uint16_t *) src & 0x001f) << 3;
+                r = (*(uint32_t *) src & 0xf80000) >> 16;
+                g = (*(uint32_t *) src & 0x00fc00) >> 8;
+                b = (*(uint32_t *) src & 0x0000f8);
             }
-            src += 2;
+            src += 4;
             break;
         case 2: /* 18 bpp plus transparency */
             alpha = *(uint32_t *) src & (1 << 24);
             if (s->control[0] & LCCR0_CMS)
                 r = g = b = *(uint32_t *) src & 0xff;
             else {
-                r = (*(uint32_t *) src & 0xf80000) >> 16;
+                r = (*(uint32_t *) src & 0xfc0000) >> 16;
                 g = (*(uint32_t *) src & 0x00fc00) >> 8;
-                b = (*(uint32_t *) src & 0x0000f8);
+                b = (*(uint32_t *) src & 0x0000fc);
             }
             src += 4;
             break;
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index eaf3e61994..a48e26367d 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -69,7 +69,7 @@ static bool smbios_legacy_mode;
 static bool gigabyte_align = true;
 
 /* PC hardware initialisation */
-static void pc_init1(QEMUMachineInitArgs *args,
+static void pc_init1(MachineState *machine,
                      int pci_enabled,
                      int kvmclock_enabled)
 {
@@ -106,7 +106,7 @@ static void pc_init1(QEMUMachineInitArgs *args,
     object_property_add_child(qdev_get_machine(), "icc-bridge",
                               OBJECT(icc_bridge), NULL);
 
-    pc_cpus_init(args->cpu_model, icc_bridge);
+    pc_cpus_init(machine->cpu_model, icc_bridge);
 
     if (kvm_enabled() && kvmclock_enabled) {
         kvmclock_create();
@@ -119,13 +119,13 @@ static void pc_init1(QEMUMachineInitArgs *args,
      * For old machine types, use whatever split we used historically to avoid
      * breaking migration.
      */
-    if (args->ram_size >= 0xe0000000) {
+    if (machine->ram_size >= 0xe0000000) {
         ram_addr_t lowmem = gigabyte_align ? 0xc0000000 : 0xe0000000;
-        above_4g_mem_size = args->ram_size - lowmem;
+        above_4g_mem_size = machine->ram_size - lowmem;
         below_4g_mem_size = lowmem;
     } else {
         above_4g_mem_size = 0;
-        below_4g_mem_size = args->ram_size;
+        below_4g_mem_size = machine->ram_size;
     }
 
     if (pci_enabled) {
@@ -145,16 +145,17 @@ static void pc_init1(QEMUMachineInitArgs *args,
     guest_info->isapc_ram_fw = !pci_enabled;
 
     if (smbios_defaults) {
+        MachineClass *mc = MACHINE_GET_CLASS(machine);
         /* These values are guest ABI, do not change */
         smbios_set_defaults("QEMU", "Standard PC (i440FX + PIIX, 1996)",
-                            args->machine->name, smbios_legacy_mode);
+                            mc->name, smbios_legacy_mode);
     }
 
     /* allocate ram and load rom/bios */
     if (!xen_enabled()) {
         fw_cfg = pc_memory_init(system_memory,
-                       args->kernel_filename, args->kernel_cmdline,
-                       args->initrd_filename,
+                       machine->kernel_filename, machine->kernel_cmdline,
+                       machine->initrd_filename,
                        below_4g_mem_size, above_4g_mem_size,
                        rom_memory, &ram_memory, guest_info);
     }
@@ -170,7 +171,7 @@ static void pc_init1(QEMUMachineInitArgs *args,
 
     if (pci_enabled) {
         pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, &isa_bus, gsi,
-                              system_memory, system_io, args->ram_size,
+                              system_memory, system_io, machine->ram_size,
                               below_4g_mem_size,
                               above_4g_mem_size,
                               pci_memory, ram_memory);
@@ -235,7 +236,7 @@ static void pc_init1(QEMUMachineInitArgs *args,
         }
     }
 
-    pc_cmos_init(below_4g_mem_size, above_4g_mem_size, args->boot_order,
+    pc_cmos_init(below_4g_mem_size, above_4g_mem_size, machine->boot_order,
                  floppy, idebus[0], idebus[1], rtc_state);
 
     if (pci_enabled && usb_enabled(false)) {
@@ -258,131 +259,131 @@ static void pc_init1(QEMUMachineInitArgs *args,
     }
 }
 
-static void pc_init_pci(QEMUMachineInitArgs *args)
+static void pc_init_pci(MachineState *machine)
 {
-    pc_init1(args, 1, 1);
+    pc_init1(machine, 1, 1);
 }
 
-static void pc_compat_2_0(QEMUMachineInitArgs *args)
+static void pc_compat_2_0(MachineState *machine)
 {
     smbios_legacy_mode = true;
 }
 
-static void pc_compat_1_7(QEMUMachineInitArgs *args)
+static void pc_compat_1_7(MachineState *machine)
 {
-    pc_compat_2_0(args);
+    pc_compat_2_0(machine);
     smbios_defaults = false;
     gigabyte_align = false;
     option_rom_has_mr = true;
     x86_cpu_compat_disable_kvm_features(FEAT_1_ECX, CPUID_EXT_X2APIC);
 }
 
-static void pc_compat_1_6(QEMUMachineInitArgs *args)
+static void pc_compat_1_6(MachineState *machine)
 {
-    pc_compat_1_7(args);
+    pc_compat_1_7(machine);
     has_pci_info = false;
     rom_file_has_mr = false;
     has_acpi_build = false;
 }
 
-static void pc_compat_1_5(QEMUMachineInitArgs *args)
+static void pc_compat_1_5(MachineState *machine)
 {
-    pc_compat_1_6(args);
+    pc_compat_1_6(machine);
 }
 
-static void pc_compat_1_4(QEMUMachineInitArgs *args)
+static void pc_compat_1_4(MachineState *machine)
 {
-    pc_compat_1_5(args);
+    pc_compat_1_5(machine);
     x86_cpu_compat_set_features("n270", FEAT_1_ECX, 0, CPUID_EXT_MOVBE);
     x86_cpu_compat_set_features("Westmere", FEAT_1_ECX, 0, CPUID_EXT_PCLMULQDQ);
 }
 
-static void pc_compat_1_3(QEMUMachineInitArgs *args)
+static void pc_compat_1_3(MachineState *machine)
 {
-    pc_compat_1_4(args);
+    pc_compat_1_4(machine);
     enable_compat_apic_id_mode();
 }
 
 /* PC compat function for pc-0.14 to pc-1.2 */
-static void pc_compat_1_2(QEMUMachineInitArgs *args)
+static void pc_compat_1_2(MachineState *machine)
 {
-    pc_compat_1_3(args);
+    pc_compat_1_3(machine);
     x86_cpu_compat_disable_kvm_features(FEAT_KVM, KVM_FEATURE_PV_EOI);
 }
 
-static void pc_init_pci_2_0(QEMUMachineInitArgs *args)
+static void pc_init_pci_2_0(MachineState *machine)
 {
-    pc_compat_2_0(args);
-    pc_init_pci(args);
+    pc_compat_2_0(machine);
+    pc_init_pci(machine);
 }
 
-static void pc_init_pci_1_7(QEMUMachineInitArgs *args)
+static void pc_init_pci_1_7(MachineState *machine)
 {
-    pc_compat_1_7(args);
-    pc_init_pci(args);
+    pc_compat_1_7(machine);
+    pc_init_pci(machine);
 }
 
-static void pc_init_pci_1_6(QEMUMachineInitArgs *args)
+static void pc_init_pci_1_6(MachineState *machine)
 {
-    pc_compat_1_6(args);
-    pc_init_pci(args);
+    pc_compat_1_6(machine);
+    pc_init_pci(machine);
 }
 
-static void pc_init_pci_1_5(QEMUMachineInitArgs *args)
+static void pc_init_pci_1_5(MachineState *machine)
 {
-    pc_compat_1_5(args);
-    pc_init_pci(args);
+    pc_compat_1_5(machine);
+    pc_init_pci(machine);
 }
 
-static void pc_init_pci_1_4(QEMUMachineInitArgs *args)
+static void pc_init_pci_1_4(MachineState *machine)
 {
-    pc_compat_1_4(args);
-    pc_init_pci(args);
+    pc_compat_1_4(machine);
+    pc_init_pci(machine);
 }
 
-static void pc_init_pci_1_3(QEMUMachineInitArgs *args)
+static void pc_init_pci_1_3(MachineState *machine)
 {
-    pc_compat_1_3(args);
-    pc_init_pci(args);
+    pc_compat_1_3(machine);
+    pc_init_pci(machine);
 }
 
 /* PC machine init function for pc-0.14 to pc-1.2 */
-static void pc_init_pci_1_2(QEMUMachineInitArgs *args)
+static void pc_init_pci_1_2(MachineState *machine)
 {
-    pc_compat_1_2(args);
-    pc_init_pci(args);
+    pc_compat_1_2(machine);
+    pc_init_pci(machine);
 }
 
 /* PC init function for pc-0.10 to pc-0.13, and reused by xenfv */
-static void pc_init_pci_no_kvmclock(QEMUMachineInitArgs *args)
+static void pc_init_pci_no_kvmclock(MachineState *machine)
 {
     has_pci_info = false;
     has_acpi_build = false;
     smbios_defaults = false;
     x86_cpu_compat_disable_kvm_features(FEAT_KVM, KVM_FEATURE_PV_EOI);
     enable_compat_apic_id_mode();
-    pc_init1(args, 1, 0);
+    pc_init1(machine, 1, 0);
 }
 
-static void pc_init_isa(QEMUMachineInitArgs *args)
+static void pc_init_isa(MachineState *machine)
 {
     has_pci_info = false;
     has_acpi_build = false;
     smbios_defaults = false;
-    if (!args->cpu_model) {
-        args->cpu_model = "486";
+    if (!machine->cpu_model) {
+        machine->cpu_model = "486";
     }
     x86_cpu_compat_disable_kvm_features(FEAT_KVM, KVM_FEATURE_PV_EOI);
     enable_compat_apic_id_mode();
-    pc_init1(args, 0, 1);
+    pc_init1(machine, 0, 1);
 }
 
 #ifdef CONFIG_XEN
-static void pc_xen_hvm_init(QEMUMachineInitArgs *args)
+static void pc_xen_hvm_init(MachineState *machine)
 {
     PCIBus *bus;
 
-    pc_init_pci(args);
+    pc_init_pci(machine);
 
     bus = pci_find_primary_bus();
     if (bus != NULL) {
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index 9517ec653f..b3c02c163d 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -59,7 +59,7 @@ static bool smbios_legacy_mode;
 static bool gigabyte_align = true;
 
 /* PC hardware initialisation */
-static void pc_q35_init(QEMUMachineInitArgs *args)
+static void pc_q35_init(MachineState *machine)
 {
     ram_addr_t below_4g_mem_size, above_4g_mem_size;
     Q35PCIHost *q35_host;
@@ -93,7 +93,7 @@ static void pc_q35_init(QEMUMachineInitArgs *args)
     object_property_add_child(qdev_get_machine(), "icc-bridge",
                               OBJECT(icc_bridge), NULL);
 
-    pc_cpus_init(args->cpu_model, icc_bridge);
+    pc_cpus_init(machine->cpu_model, icc_bridge);
     pc_acpi_init("q35-acpi-dsdt.aml");
 
     kvmclock_create();
@@ -107,13 +107,13 @@ static void pc_q35_init(QEMUMachineInitArgs *args)
      * For old machine types, use whatever split we used historically to avoid
      * breaking migration.
      */
-    if (args->ram_size >= 0xb0000000) {
+    if (machine->ram_size >= 0xb0000000) {
         ram_addr_t lowmem = gigabyte_align ? 0x80000000 : 0xb0000000;
-        above_4g_mem_size = args->ram_size - lowmem;
+        above_4g_mem_size = machine->ram_size - lowmem;
         below_4g_mem_size = lowmem;
     } else {
         above_4g_mem_size = 0;
-        below_4g_mem_size = args->ram_size;
+        below_4g_mem_size = machine->ram_size;
     }
 
     /* pci enabled */
@@ -132,16 +132,17 @@ static void pc_q35_init(QEMUMachineInitArgs *args)
     guest_info->has_acpi_build = has_acpi_build;
 
     if (smbios_defaults) {
+        MachineClass *mc = MACHINE_GET_CLASS(machine);
         /* These values are guest ABI, do not change */
         smbios_set_defaults("QEMU", "Standard PC (Q35 + ICH9, 2009)",
-                            args->machine->name, smbios_legacy_mode);
+                            mc->name, smbios_legacy_mode);
     }
 
     /* allocate ram and load rom/bios */
     if (!xen_enabled()) {
         pc_memory_init(get_system_memory(),
-                       args->kernel_filename, args->kernel_cmdline,
-                       args->initrd_filename,
+                       machine->kernel_filename, machine->kernel_cmdline,
+                       machine->initrd_filename,
                        below_4g_mem_size, above_4g_mem_size,
                        rom_memory, &ram_memory, guest_info);
     }
@@ -230,7 +231,7 @@ static void pc_q35_init(QEMUMachineInitArgs *args)
                                     0xb100),
                       8, NULL, 0);
 
-    pc_cmos_init(below_4g_mem_size, above_4g_mem_size, args->boot_order,
+    pc_cmos_init(below_4g_mem_size, above_4g_mem_size, machine->boot_order,
                  floppy, idebus[0], idebus[1], rtc_state);
 
     /* the rest devices to which pci devfn is automatically assigned */
@@ -241,68 +242,68 @@ static void pc_q35_init(QEMUMachineInitArgs *args)
     }
 }
 
-static void pc_compat_2_0(QEMUMachineInitArgs *args)
+static void pc_compat_2_0(MachineState *machine)
 {
     smbios_legacy_mode = true;
 }
 
-static void pc_compat_1_7(QEMUMachineInitArgs *args)
+static void pc_compat_1_7(MachineState *machine)
 {
-    pc_compat_2_0(args);
+    pc_compat_2_0(machine);
     smbios_defaults = false;
     gigabyte_align = false;
     option_rom_has_mr = true;
     x86_cpu_compat_disable_kvm_features(FEAT_1_ECX, CPUID_EXT_X2APIC);
 }
 
-static void pc_compat_1_6(QEMUMachineInitArgs *args)
+static void pc_compat_1_6(MachineState *machine)
 {
-    pc_compat_1_7(args);
+    pc_compat_1_7(machine);
     has_pci_info = false;
     rom_file_has_mr = false;
     has_acpi_build = false;
 }
 
-static void pc_compat_1_5(QEMUMachineInitArgs *args)
+static void pc_compat_1_5(MachineState *machine)
 {
-    pc_compat_1_6(args);
+    pc_compat_1_6(machine);
 }
 
-static void pc_compat_1_4(QEMUMachineInitArgs *args)
+static void pc_compat_1_4(MachineState *machine)
 {
-    pc_compat_1_5(args);
+    pc_compat_1_5(machine);
     x86_cpu_compat_set_features("n270", FEAT_1_ECX, 0, CPUID_EXT_MOVBE);
     x86_cpu_compat_set_features("Westmere", FEAT_1_ECX, 0, CPUID_EXT_PCLMULQDQ);
 }
 
-static void pc_q35_init_2_0(QEMUMachineInitArgs *args)
+static void pc_q35_init_2_0(MachineState *machine)
 {
-    pc_compat_2_0(args);
-    pc_q35_init(args);
+    pc_compat_2_0(machine);
+    pc_q35_init(machine);
 }
 
-static void pc_q35_init_1_7(QEMUMachineInitArgs *args)
+static void pc_q35_init_1_7(MachineState *machine)
 {
-    pc_compat_1_7(args);
-    pc_q35_init(args);
+    pc_compat_1_7(machine);
+    pc_q35_init(machine);
 }
 
-static void pc_q35_init_1_6(QEMUMachineInitArgs *args)
+static void pc_q35_init_1_6(MachineState *machine)
 {
-    pc_compat_1_6(args);
-    pc_q35_init(args);
+    pc_compat_1_6(machine);
+    pc_q35_init(machine);
 }
 
-static void pc_q35_init_1_5(QEMUMachineInitArgs *args)
+static void pc_q35_init_1_5(MachineState *machine)
 {
-    pc_compat_1_5(args);
-    pc_q35_init(args);
+    pc_compat_1_5(machine);
+    pc_q35_init(machine);
 }
 
-static void pc_q35_init_1_4(QEMUMachineInitArgs *args)
+static void pc_q35_init_1_4(MachineState *machine)
 {
-    pc_compat_1_4(args);
-    pc_q35_init(args);
+    pc_compat_1_4(machine);
+    pc_q35_init(machine);
 }
 
 #define PC_Q35_MACHINE_OPTIONS \
diff --git a/hw/input/hid.c b/hw/input/hid.c
index bb0fa6a619..295bdab652 100644
--- a/hw/input/hid.c
+++ b/hw/input/hid.c
@@ -105,70 +105,135 @@ void hid_set_next_idle(HIDState *hs)
     }
 }
 
-static void hid_pointer_event_clear(HIDPointerEvent *e, int buttons)
+static void hid_pointer_event(DeviceState *dev, QemuConsole *src,
+                              InputEvent *evt)
 {
-    e->xdx = e->ydy = e->dz = 0;
-    e->buttons_state = buttons;
-}
+    static const int bmap[INPUT_BUTTON_MAX] = {
+        [INPUT_BUTTON_LEFT]   = 0x01,
+        [INPUT_BUTTON_RIGHT]  = 0x02,
+        [INPUT_BUTTON_MIDDLE] = 0x04,
+    };
+    HIDState *hs = (HIDState *)dev;
+    HIDPointerEvent *e;
 
-static void hid_pointer_event_combine(HIDPointerEvent *e, int xyrel,
-                                      int x1, int y1, int z1) {
-    if (xyrel) {
-        e->xdx += x1;
-        e->ydy += y1;
-    } else {
-        e->xdx = x1;
-        e->ydy = y1;
-        /* Windows drivers do not like the 0/0 position and ignore such
-         * events. */
-        if (!(x1 | y1)) {
-            e->xdx = 1;
+    assert(hs->n < QUEUE_LENGTH);
+    e = &hs->ptr.queue[(hs->head + hs->n) & QUEUE_MASK];
+
+    switch (evt->kind) {
+    case INPUT_EVENT_KIND_REL:
+        if (evt->rel->axis == INPUT_AXIS_X) {
+            e->xdx += evt->rel->value;
+        } else if (evt->rel->axis == INPUT_AXIS_Y) {
+            e->ydy -= evt->rel->value;
+        }
+        break;
+
+    case INPUT_EVENT_KIND_ABS:
+        if (evt->rel->axis == INPUT_AXIS_X) {
+            e->xdx = evt->rel->value;
+        } else if (evt->rel->axis == INPUT_AXIS_Y) {
+            e->ydy = evt->rel->value;
         }
+        break;
+
+    case INPUT_EVENT_KIND_BTN:
+        if (evt->btn->down) {
+            e->buttons_state |= bmap[evt->btn->button];
+            if (evt->btn->button == INPUT_BUTTON_WHEEL_UP) {
+                e->dz--;
+            } else if (evt->btn->button == INPUT_BUTTON_WHEEL_DOWN) {
+                e->dz++;
+            }
+        } else {
+            e->buttons_state &= ~bmap[evt->btn->button];
+        }
+        break;
+
+    default:
+        /* keep gcc happy */
+        break;
     }
-    e->dz += z1;
+
 }
 
-static void hid_pointer_event(void *opaque,
-                              int x1, int y1, int z1, int buttons_state)
+static void hid_pointer_sync(DeviceState *dev)
 {
-    HIDState *hs = opaque;
-    unsigned use_slot = (hs->head + hs->n - 1) & QUEUE_MASK;
-    unsigned previous_slot = (use_slot - 1) & QUEUE_MASK;
-
-    /* We combine events where feasible to keep the queue small.  We shouldn't
-     * combine anything with the first event of a particular button state, as
-     * that would change the location of the button state change.  When the
-     * queue is empty, a second event is needed because we don't know if
-     * the first event changed the button state.  */
-    if (hs->n == QUEUE_LENGTH) {
-        /* Queue full.  Discard old button state, combine motion normally.  */
-        hs->ptr.queue[use_slot].buttons_state = buttons_state;
-    } else if (hs->n < 2 ||
-               hs->ptr.queue[use_slot].buttons_state != buttons_state ||
-               hs->ptr.queue[previous_slot].buttons_state !=
-               hs->ptr.queue[use_slot].buttons_state) {
-        /* Cannot or should not combine, so add an empty item to the queue.  */
-        QUEUE_INCR(use_slot);
+    HIDState *hs = (HIDState *)dev;
+    HIDPointerEvent *prev, *curr, *next;
+    bool event_compression = false;
+
+    if (hs->n == QUEUE_LENGTH-1) {
+        /*
+         * Queue full.  We are loosing information, but we at least
+         * keep track of most recent button state.
+         */
+        return;
+    }
+
+    prev = &hs->ptr.queue[(hs->head + hs->n - 1) & QUEUE_MASK];
+    curr = &hs->ptr.queue[(hs->head + hs->n) & QUEUE_MASK];
+    next = &hs->ptr.queue[(hs->head + hs->n + 1) & QUEUE_MASK];
+
+    if (hs->n > 0) {
+        /*
+         * No button state change between previous and current event
+         * (and previous wasn't seen by the guest yet), so there is
+         * motion information only and we can combine the two event
+         * into one.
+         */
+        if (curr->buttons_state == prev->buttons_state) {
+            event_compression = true;
+        }
+    }
+
+    if (event_compression) {
+        /* add current motion to previous, clear current */
+        if (hs->kind == HID_MOUSE) {
+            prev->xdx += curr->xdx;
+            curr->xdx = 0;
+            prev->ydy -= curr->ydy;
+            curr->ydy = 0;
+        } else {
+            prev->xdx = curr->xdx;
+            prev->ydy = curr->ydy;
+        }
+        prev->dz += curr->dz;
+        curr->dz = 0;
+    } else {
+        /* prepate next (clear rel, copy abs + btns) */
+        if (hs->kind == HID_MOUSE) {
+            next->xdx = 0;
+            next->ydy = 0;
+        } else {
+            next->xdx = curr->xdx;
+            next->ydy = curr->ydy;
+        }
+        next->dz = 0;
+        next->buttons_state = curr->buttons_state;
+        /* make current guest visible, notify guest */
         hs->n++;
-        hid_pointer_event_clear(&hs->ptr.queue[use_slot], buttons_state);
+        hs->event(hs);
     }
-    hid_pointer_event_combine(&hs->ptr.queue[use_slot],
-                              hs->kind == HID_MOUSE,
-                              x1, y1, z1);
-    hs->event(hs);
 }
 
-static void hid_keyboard_event(void *opaque, int keycode)
+static void hid_keyboard_event(DeviceState *dev, QemuConsole *src,
+                               InputEvent *evt)
 {
-    HIDState *hs = opaque;
+    HIDState *hs = (HIDState *)dev;
+    int scancodes[3], i, count;
     int slot;
 
-    if (hs->n == QUEUE_LENGTH) {
+    count = qemu_input_key_value_to_scancode(evt->key->key,
+                                             evt->key->down,
+                                             scancodes);
+    if (hs->n + count > QUEUE_LENGTH) {
         fprintf(stderr, "usb-kbd: warning: key event queue full\n");
         return;
     }
-    slot = (hs->head + hs->n) & QUEUE_MASK; hs->n++;
-    hs->kbd.keycodes[slot] = keycode;
+    for (i = 0; i < count; i++) {
+        slot = (hs->head + hs->n) & QUEUE_MASK; hs->n++;
+        hs->kbd.keycodes[slot] = scancodes[i];
+    }
     hs->event(hs);
 }
 
@@ -247,14 +312,14 @@ static inline int int_clamp(int val, int vmin, int vmax)
 void hid_pointer_activate(HIDState *hs)
 {
     if (!hs->ptr.mouse_grabbed) {
-        qemu_activate_mouse_event_handler(hs->ptr.eh_entry);
+        qemu_input_handler_activate(hs->s);
         hs->ptr.mouse_grabbed = 1;
     }
 }
 
 int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len)
 {
-    int dx, dy, dz, b, l;
+    int dx, dy, dz, l;
     int index;
     HIDPointerEvent *e;
 
@@ -279,17 +344,6 @@ int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len)
     dz = int_clamp(e->dz, -127, 127);
     e->dz -= dz;
 
-    b = 0;
-    if (e->buttons_state & MOUSE_EVENT_LBUTTON) {
-        b |= 0x01;
-    }
-    if (e->buttons_state & MOUSE_EVENT_RBUTTON) {
-        b |= 0x02;
-    }
-    if (e->buttons_state & MOUSE_EVENT_MBUTTON) {
-        b |= 0x04;
-    }
-
     if (hs->n &&
         !e->dz &&
         (hs->kind == HID_TABLET || (!e->xdx && !e->ydy))) {
@@ -304,7 +358,7 @@ int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len)
     switch (hs->kind) {
     case HID_MOUSE:
         if (len > l) {
-            buf[l++] = b;
+            buf[l++] = e->buttons_state;
         }
         if (len > l) {
             buf[l++] = dx;
@@ -319,7 +373,7 @@ int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len)
 
     case HID_TABLET:
         if (len > l) {
-            buf[l++] = b;
+            buf[l++] = e->buttons_state;
         }
         if (len > l) {
             buf[l++] = dx & 0xff;
@@ -413,31 +467,45 @@ void hid_reset(HIDState *hs)
 
 void hid_free(HIDState *hs)
 {
-    switch (hs->kind) {
-    case HID_KEYBOARD:
-        qemu_remove_kbd_event_handler(hs->kbd.eh_entry);
-        break;
-    case HID_MOUSE:
-    case HID_TABLET:
-        qemu_remove_mouse_event_handler(hs->ptr.eh_entry);
-        break;
-    }
+    qemu_input_handler_unregister(hs->s);
     hid_del_idle_timer(hs);
 }
 
+static QemuInputHandler hid_keyboard_handler = {
+    .name  = "QEMU HID Keyboard",
+    .mask  = INPUT_EVENT_MASK_KEY,
+    .event = hid_keyboard_event,
+};
+
+static QemuInputHandler hid_mouse_handler = {
+    .name  = "QEMU HID Mouse",
+    .mask  = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL,
+    .event = hid_pointer_event,
+    .sync  = hid_pointer_sync,
+};
+
+static QemuInputHandler hid_tablet_handler = {
+    .name  = "QEMU HID Tablet",
+    .mask  = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_ABS,
+    .event = hid_pointer_event,
+    .sync  = hid_pointer_sync,
+};
+
 void hid_init(HIDState *hs, int kind, HIDEventFunc event)
 {
     hs->kind = kind;
     hs->event = event;
 
     if (hs->kind == HID_KEYBOARD) {
-        hs->kbd.eh_entry = qemu_add_kbd_event_handler(hid_keyboard_event, hs);
+        hs->s = qemu_input_handler_register((DeviceState *)hs,
+                                            &hid_keyboard_handler);
+        qemu_input_handler_activate(hs->s);
     } else if (hs->kind == HID_MOUSE) {
-        hs->ptr.eh_entry = qemu_add_mouse_event_handler(hid_pointer_event, hs,
-                                                        0, "QEMU HID Mouse");
+        hs->s = qemu_input_handler_register((DeviceState *)hs,
+                                            &hid_mouse_handler);
     } else if (hs->kind == HID_TABLET) {
-        hs->ptr.eh_entry = qemu_add_mouse_event_handler(hid_pointer_event, hs,
-                                                        1, "QEMU HID Tablet");
+        hs->s = qemu_input_handler_register((DeviceState *)hs,
+                                            &hid_tablet_handler);
     }
 }
 
diff --git a/hw/input/ps2.c b/hw/input/ps2.c
index 34120796b1..22b77dfe5c 100644
--- a/hw/input/ps2.c
+++ b/hw/input/ps2.c
@@ -24,6 +24,7 @@
 #include "hw/hw.h"
 #include "hw/input/ps2.h"
 #include "ui/console.h"
+#include "ui/input.h"
 #include "sysemu/sysemu.h"
 
 /* debug PC keyboard */
@@ -71,10 +72,12 @@
 #define MOUSE_STATUS_ENABLED    0x20
 #define MOUSE_STATUS_SCALE21    0x10
 
-#define PS2_QUEUE_SIZE 256
+#define PS2_QUEUE_SIZE 16  /* Buffer size required by PS/2 protocol */
 
 typedef struct {
-    uint8_t data[PS2_QUEUE_SIZE];
+    /* Keep the data array 256 bytes long, which compatibility
+     with older qemu versions. */
+    uint8_t data[256];
     int rptr, wptr, count;
 } PS2Queue;
 
@@ -137,7 +140,7 @@ void ps2_queue(void *opaque, int b)
     PS2State *s = (PS2State *)opaque;
     PS2Queue *q = &s->queue;
 
-    if (q->count >= PS2_QUEUE_SIZE)
+    if (q->count >= PS2_QUEUE_SIZE - 1)
         return;
     q->data[q->wptr] = b;
     if (++q->wptr == PS2_QUEUE_SIZE)
@@ -170,6 +173,21 @@ static void ps2_put_keycode(void *opaque, int keycode)
     ps2_queue(&s->common, keycode);
 }
 
+static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
+                               InputEvent *evt)
+{
+    PS2KbdState *s = (PS2KbdState *)dev;
+    int scancodes[3], i, count;
+
+    qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
+    count = qemu_input_key_value_to_scancode(evt->key->key,
+                                             evt->key->down,
+                                             scancodes);
+    for (i = 0; i < count; i++) {
+        ps2_put_keycode(s, scancodes[i]);
+    }
+}
+
 uint32_t ps2_read_data(void *opaque)
 {
     PS2State *s = (PS2State *)opaque;
@@ -352,31 +370,57 @@ static void ps2_mouse_send_packet(PS2MouseState *s)
     s->mouse_dz -= dz1;
 }
 
-static void ps2_mouse_event(void *opaque,
-                            int dx, int dy, int dz, int buttons_state)
+static void ps2_mouse_event(DeviceState *dev, QemuConsole *src,
+                            InputEvent *evt)
 {
-    PS2MouseState *s = opaque;
+    static const int bmap[INPUT_BUTTON_MAX] = {
+        [INPUT_BUTTON_LEFT]   = MOUSE_EVENT_LBUTTON,
+        [INPUT_BUTTON_MIDDLE] = MOUSE_EVENT_MBUTTON,
+        [INPUT_BUTTON_RIGHT]  = MOUSE_EVENT_RBUTTON,
+    };
+    PS2MouseState *s = (PS2MouseState *)dev;
 
     /* check if deltas are recorded when disabled */
     if (!(s->mouse_status & MOUSE_STATUS_ENABLED))
         return;
 
-    s->mouse_dx += dx;
-    s->mouse_dy -= dy;
-    s->mouse_dz += dz;
-    /* XXX: SDL sometimes generates nul events: we delete them */
-    if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0 &&
-        s->mouse_buttons == buttons_state)
-	return;
-    s->mouse_buttons = buttons_state;
+    switch (evt->kind) {
+    case INPUT_EVENT_KIND_REL:
+        if (evt->rel->axis == INPUT_AXIS_X) {
+            s->mouse_dx += evt->rel->value;
+        } else if (evt->rel->axis == INPUT_AXIS_Y) {
+            s->mouse_dy -= evt->rel->value;
+        }
+        break;
 
-    if (buttons_state) {
-        qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
+    case INPUT_EVENT_KIND_BTN:
+        if (evt->btn->down) {
+            s->mouse_buttons |= bmap[evt->btn->button];
+            if (evt->btn->button == INPUT_BUTTON_WHEEL_UP) {
+                s->mouse_dz--;
+            } else if (evt->btn->button == INPUT_BUTTON_WHEEL_DOWN) {
+                s->mouse_dz++;
+            }
+        } else {
+            s->mouse_buttons &= ~bmap[evt->btn->button];
+        }
+        break;
+
+    default:
+        /* keep gcc happy */
+        break;
     }
+}
 
-    if (!(s->mouse_status & MOUSE_STATUS_REMOTE) &&
-        (s->common.queue.count < (PS2_QUEUE_SIZE - 16))) {
-        for(;;) {
+static void ps2_mouse_sync(DeviceState *dev)
+{
+    PS2MouseState *s = (PS2MouseState *)dev;
+
+    if (s->mouse_buttons) {
+        qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
+    }
+    if (!(s->mouse_status & MOUSE_STATUS_REMOTE)) {
+        while (s->common.queue.count < PS2_QUEUE_SIZE - 4) {
             /* if not remote, send event. Multiple events are sent if
                too big deltas */
             ps2_mouse_send_packet(s);
@@ -388,7 +432,9 @@ static void ps2_mouse_event(void *opaque,
 
 void ps2_mouse_fake_event(void *opaque)
 {
-    ps2_mouse_event(opaque, 1, 0, 0, 0);
+    PS2MouseState *s = opaque;
+    s->mouse_dx++;
+    ps2_mouse_sync(opaque);
 }
 
 void ps2_write_mouse(void *opaque, int val)
@@ -528,6 +574,34 @@ static void ps2_common_reset(PS2State *s)
     s->update_irq(s->update_arg, 0);
 }
 
+static void ps2_common_post_load(PS2State *s)
+{
+    PS2Queue *q = &s->queue;
+    int size;
+    int i;
+    int tmp_data[PS2_QUEUE_SIZE];
+
+    /* set the useful data buffer queue size, < PS2_QUEUE_SIZE */
+    size = q->count > PS2_QUEUE_SIZE ? 0 : q->count;
+
+    /* move the queue elements to the start of data array */
+    if (size > 0) {
+        for (i = 0; i < size; i++) {
+            /* move the queue elements to the temporary buffer */
+            tmp_data[i] = q->data[q->rptr];
+            if (++q->rptr == 256) {
+                q->rptr = 0;
+            }
+        }
+        memcpy(q->data, tmp_data, size);
+    }
+    /* reset rptr/wptr/count */
+    q->rptr = 0;
+    q->wptr = size;
+    q->count = size;
+    s->update_irq(s->update_arg, q->count != 0);
+}
+
 static void ps2_kbd_reset(void *opaque)
 {
     PS2KbdState *s = (PS2KbdState *) opaque;
@@ -600,18 +674,31 @@ static const VMStateDescription vmstate_ps2_keyboard_ledstate = {
 static int ps2_kbd_post_load(void* opaque, int version_id)
 {
     PS2KbdState *s = (PS2KbdState*)opaque;
+    PS2State *ps2 = &s->common;
 
     if (version_id == 2)
         s->scancode_set=2;
+
+    ps2_common_post_load(ps2);
+
     return 0;
 }
 
+static void ps2_kbd_pre_save(void *opaque)
+{
+    PS2KbdState *s = (PS2KbdState *)opaque;
+    PS2State *ps2 = &s->common;
+
+    ps2_common_post_load(ps2);
+}
+
 static const VMStateDescription vmstate_ps2_keyboard = {
     .name = "ps2kbd",
     .version_id = 3,
     .minimum_version_id = 2,
     .minimum_version_id_old = 2,
     .post_load = ps2_kbd_post_load,
+    .pre_save = ps2_kbd_pre_save,
     .fields      = (VMStateField []) {
         VMSTATE_STRUCT(common, PS2KbdState, 0, vmstate_ps2_common, PS2State),
         VMSTATE_INT32(scan_enabled, PS2KbdState),
@@ -629,11 +716,31 @@ static const VMStateDescription vmstate_ps2_keyboard = {
     }
 };
 
+static int ps2_mouse_post_load(void *opaque, int version_id)
+{
+    PS2MouseState *s = (PS2MouseState *)opaque;
+    PS2State *ps2 = &s->common;
+
+    ps2_common_post_load(ps2);
+
+    return 0;
+}
+
+static void ps2_mouse_pre_save(void *opaque)
+{
+    PS2MouseState *s = (PS2MouseState *)opaque;
+    PS2State *ps2 = &s->common;
+
+    ps2_common_post_load(ps2);
+}
+
 static const VMStateDescription vmstate_ps2_mouse = {
     .name = "ps2mouse",
     .version_id = 2,
     .minimum_version_id = 2,
     .minimum_version_id_old = 2,
+    .post_load = ps2_mouse_post_load,
+    .pre_save = ps2_mouse_pre_save,
     .fields      = (VMStateField []) {
         VMSTATE_STRUCT(common, PS2MouseState, 0, vmstate_ps2_common, PS2State),
         VMSTATE_UINT8(mouse_status, PS2MouseState),
@@ -650,6 +757,12 @@ static const VMStateDescription vmstate_ps2_mouse = {
     }
 };
 
+static QemuInputHandler ps2_keyboard_handler = {
+    .name  = "QEMU PS/2 Keyboard",
+    .mask  = INPUT_EVENT_MASK_KEY,
+    .event = ps2_keyboard_event,
+};
+
 void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg)
 {
     PS2KbdState *s = (PS2KbdState *)g_malloc0(sizeof(PS2KbdState));
@@ -658,11 +771,19 @@ void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg)
     s->common.update_arg = update_arg;
     s->scancode_set = 2;
     vmstate_register(NULL, 0, &vmstate_ps2_keyboard, s);
-    qemu_add_kbd_event_handler(ps2_put_keycode, s);
+    qemu_input_handler_register((DeviceState *)s,
+                                &ps2_keyboard_handler);
     qemu_register_reset(ps2_kbd_reset, s);
     return s;
 }
 
+static QemuInputHandler ps2_mouse_handler = {
+    .name  = "QEMU PS/2 Mouse",
+    .mask  = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL,
+    .event = ps2_mouse_event,
+    .sync  = ps2_mouse_sync,
+};
+
 void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg)
 {
     PS2MouseState *s = (PS2MouseState *)g_malloc0(sizeof(PS2MouseState));
@@ -670,7 +791,8 @@ void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg)
     s->common.update_irq = update_irq;
     s->common.update_arg = update_arg;
     vmstate_register(NULL, 0, &vmstate_ps2_mouse, s);
-    qemu_add_mouse_event_handler(ps2_mouse_event, s, 0, "QEMU PS/2 Mouse");
+    qemu_input_handler_register((DeviceState *)s,
+                                &ps2_mouse_handler);
     qemu_register_reset(ps2_mouse_reset, s);
     return s;
 }
diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs
index c8a2318d56..843864a3ef 100644
--- a/hw/intc/Makefile.objs
+++ b/hw/intc/Makefile.objs
@@ -26,3 +26,4 @@ obj-$(CONFIG_XICS) += xics.o
 obj-$(CONFIG_XICS_KVM) += xics_kvm.o
 obj-$(CONFIG_ALLWINNER_A10_PIC) += allwinner-a10-pic.o
 obj-$(CONFIG_S390_FLIC) += s390_flic.o
+obj-$(CONFIG_S390_FLIC_KVM) += s390_flic_kvm.o
diff --git a/hw/intc/s390_flic.c b/hw/intc/s390_flic.c
index b2ef3e3f8e..03c5e89f4e 100644
--- a/hw/intc/s390_flic.c
+++ b/hw/intc/s390_flic.c
@@ -1,322 +1,103 @@
 /*
- * QEMU S390x KVM floating interrupt controller (flic)
+ * QEMU S390x floating interrupt controller (flic)
  *
  * Copyright 2014 IBM Corp.
  * Author(s): Jens Freimann <jfrei@linux.vnet.ibm.com>
+ *            Cornelia Huck <cornelia.huck@de.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 <sys/ioctl.h>
 #include "qemu/error-report.h"
 #include "hw/sysbus.h"
-#include "sysemu/kvm.h"
 #include "migration/qemu-file.h"
 #include "hw/s390x/s390_flic.h"
 #include "trace.h"
 
-#define FLIC_SAVE_INITIAL_SIZE getpagesize()
-#define FLIC_FAILED (-1UL)
-#define FLIC_SAVEVM_VERSION 1
-
-void s390_flic_init(void)
-{
-    DeviceState *dev;
-    int r;
-
-    if (kvm_enabled()) {
-        dev = qdev_create(NULL, "s390-flic");
-        object_property_add_child(qdev_get_machine(), "s390-flic",
-                                OBJECT(dev), NULL);
-        r = qdev_init(dev);
-        if (r) {
-            error_report("flic: couldn't create qdev");
-        }
-    }
-}
-
-/**
- * flic_get_all_irqs - store all pending irqs in buffer
- * @buf: pointer to buffer which is passed to kernel
- * @len: length of buffer
- * @flic: pointer to flic device state
- *
- * Returns: -ENOMEM if buffer is too small,
- * -EINVAL if attr.group is invalid,
- * -EFAULT if copying to userspace failed,
- * on success return number of stored interrupts
- */
-static int flic_get_all_irqs(KVMS390FLICState *flic,
-                             void *buf, int len)
+S390FLICState *s390_get_flic(void)
 {
-    struct kvm_device_attr attr = {
-        .group = KVM_DEV_FLIC_GET_ALL_IRQS,
-        .addr = (uint64_t) buf,
-        .attr = len,
-    };
-    int rc;
-
-    rc = ioctl(flic->fd, KVM_GET_DEVICE_ATTR, &attr);
-
-    return rc == -1 ? -errno : rc;
-}
+    S390FLICState *fs;
 
-static void flic_enable_pfault(KVMS390FLICState *flic)
-{
-    struct kvm_device_attr attr = {
-        .group = KVM_DEV_FLIC_APF_ENABLE,
-    };
-    int rc;
-
-    rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
-
-    if (rc) {
-        fprintf(stderr, "flic: couldn't enable pfault\n");
+    fs = S390_FLIC_COMMON(object_resolve_path(TYPE_KVM_S390_FLIC, NULL));
+    if (!fs) {
+        fs = S390_FLIC_COMMON(object_resolve_path(TYPE_QEMU_S390_FLIC, NULL));
     }
+    return fs;
 }
 
-static void flic_disable_wait_pfault(KVMS390FLICState *flic)
-{
-    struct kvm_device_attr attr = {
-        .group = KVM_DEV_FLIC_APF_DISABLE_WAIT,
-    };
-    int rc;
-
-    rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
-
-    if (rc) {
-        fprintf(stderr, "flic: couldn't disable pfault\n");
-    }
-}
-
-/** flic_enqueue_irqs - returns 0 on success
- * @buf: pointer to buffer which is passed to kernel
- * @len: length of buffer
- * @flic: pointer to flic device state
- *
- * Returns: -EINVAL if attr.group is unknown
- */
-static int flic_enqueue_irqs(void *buf, uint64_t len,
-                            KVMS390FLICState *flic)
-{
-    int rc;
-    struct kvm_device_attr attr = {
-        .group = KVM_DEV_FLIC_ENQUEUE,
-        .addr = (uint64_t) buf,
-        .attr = len,
-    };
-
-    rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
-
-    return rc ? -errno : 0;
-}
-
-/**
- * __get_all_irqs - store all pending irqs in buffer
- * @flic: pointer to flic device state
- * @buf: pointer to pointer to a buffer
- * @len: length of buffer
- *
- * Returns: return value of flic_get_all_irqs
- * Note: Retry and increase buffer size until flic_get_all_irqs
- * either returns a value >= 0 or a negative error code.
- * -ENOMEM is an exception, which means the buffer is too small
- * and we should try again. Other negative error codes can be
- * -EFAULT and -EINVAL which we ignore at this point
- */
-static int __get_all_irqs(KVMS390FLICState *flic,
-                          void **buf, int len)
+void s390_flic_init(void)
 {
+    DeviceState *dev;
     int r;
 
-    do {
-        /* returns -ENOMEM if buffer is too small and number
-         * of queued interrupts on success */
-        r = flic_get_all_irqs(flic, *buf, len);
-        if (r >= 0) {
-            break;
-        }
-        len *= 2;
-        *buf = g_try_realloc(*buf, len);
-        if (!buf) {
-            return -ENOMEM;
-        }
-    } while (r == -ENOMEM && len <= KVM_S390_FLIC_MAX_BUFFER);
-
-    return r;
-}
-
-/**
- * kvm_flic_save - Save pending floating interrupts
- * @f: QEMUFile containing migration state
- * @opaque: pointer to flic device state
- *
- * Note: Pass buf and len to kernel. Start with one page and
- * increase until buffer is sufficient or maxium size is
- * reached
- */
-static void kvm_flic_save(QEMUFile *f, void *opaque)
-{
-    KVMS390FLICState *flic = opaque;
-    int len = FLIC_SAVE_INITIAL_SIZE;
-    void *buf;
-    int count;
-
-    flic_disable_wait_pfault((struct KVMS390FLICState *) opaque);
-
-    buf = g_try_malloc0(len);
-    if (!buf) {
-        /* Storing FLIC_FAILED into the count field here will cause the
-         * target system to fail when attempting to load irqs from the
-         * migration state */
-        error_report("flic: couldn't allocate memory");
-        qemu_put_be64(f, FLIC_FAILED);
-        return;
+    dev = s390_flic_kvm_create();
+    if (!dev) {
+        dev = qdev_create(NULL, TYPE_QEMU_S390_FLIC);
+        object_property_add_child(qdev_get_machine(), TYPE_QEMU_S390_FLIC,
+                                  OBJECT(dev), NULL);
     }
-
-    count = __get_all_irqs(flic, &buf, len);
-    if (count < 0) {
-        error_report("flic: couldn't retrieve irqs from kernel, rc %d",
-                     count);
-        /* Storing FLIC_FAILED into the count field here will cause the
-         * target system to fail when attempting to load irqs from the
-         * migration state */
-        qemu_put_be64(f, FLIC_FAILED);
-    } else {
-        qemu_put_be64(f, count);
-        qemu_put_buffer(f, (uint8_t *) buf,
-                        count * sizeof(struct kvm_s390_irq));
+    r = qdev_init(dev);
+    if (r) {
+        error_report("flic: couldn't create qdev");
     }
-    g_free(buf);
 }
 
-/**
- * kvm_flic_load - Load pending floating interrupts
- * @f: QEMUFile containing migration state
- * @opaque: pointer to flic device state
- * @version_id: version id for migration
- *
- * Returns: value of flic_enqueue_irqs, -EINVAL on error
- * Note: Do nothing when no interrupts where stored
- * in QEMUFile
- */
-static int kvm_flic_load(QEMUFile *f, void *opaque, int version_id)
+static int qemu_s390_register_io_adapter(S390FLICState *fs, uint32_t id,
+                                         uint8_t isc, bool swap,
+                                         bool is_maskable)
 {
-    uint64_t len = 0;
-    uint64_t count = 0;
-    void *buf = NULL;
-    int r = 0;
-
-    if (version_id != FLIC_SAVEVM_VERSION) {
-        r = -EINVAL;
-        goto out;
-    }
-
-    flic_enable_pfault((struct KVMS390FLICState *) opaque);
-
-    count = qemu_get_be64(f);
-    len = count * sizeof(struct kvm_s390_irq);
-    if (count == FLIC_FAILED) {
-        r = -EINVAL;
-        goto out;
-    }
-    if (count == 0) {
-        r = 0;
-        goto out;
-    }
-    buf = g_try_malloc0(len);
-    if (!buf) {
-        r = -ENOMEM;
-        goto out;
-    }
-
-    if (qemu_get_buffer(f, (uint8_t *) buf, len) != len) {
-        r = -EINVAL;
-        goto out_free;
-    }
-    r = flic_enqueue_irqs(buf, len, (struct KVMS390FLICState *) opaque);
-
-out_free:
-    g_free(buf);
-out:
-    return r;
+    /* nothing to do */
+    return 0;
 }
 
-static void kvm_s390_flic_realize(DeviceState *dev, Error **errp)
+static int qemu_s390_io_adapter_map(S390FLICState *fs, uint32_t id,
+                                    uint64_t map_addr, bool do_map)
 {
-    KVMS390FLICState *flic_state = KVM_S390_FLIC(dev);
-    struct kvm_create_device cd = {0};
-    int ret;
-
-    flic_state->fd = -1;
-    if (!kvm_check_extension(kvm_state, KVM_CAP_DEVICE_CTRL)) {
-        trace_flic_no_device_api(errno);
-        return;
-    }
-
-    cd.type = KVM_DEV_TYPE_FLIC;
-    ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd);
-    if (ret < 0) {
-        trace_flic_create_device(errno);
-        return;
-    }
-    flic_state->fd = cd.fd;
-
-    /* Register savevm handler for floating interrupts */
-    register_savevm(NULL, "s390-flic", 0, 1, kvm_flic_save,
-                    kvm_flic_load, (void *) flic_state);
+    /* nothing to do */
+    return 0;
 }
 
-static void kvm_s390_flic_unrealize(DeviceState *dev, Error **errp)
+static int qemu_s390_add_adapter_routes(S390FLICState *fs,
+                                        AdapterRoutes *routes)
 {
-    KVMS390FLICState *flic_state = KVM_S390_FLIC(dev);
-
-    unregister_savevm(DEVICE(flic_state), "s390-flic", flic_state);
+    return -ENOSYS;
 }
 
-static void kvm_s390_flic_reset(DeviceState *dev)
+static void qemu_s390_release_adapter_routes(S390FLICState *fs,
+                                             AdapterRoutes *routes)
 {
-    KVMS390FLICState *flic = KVM_S390_FLIC(dev);
-    struct kvm_device_attr attr = {
-        .group = KVM_DEV_FLIC_CLEAR_IRQS,
-    };
-    int rc = 0;
-
-    if (flic->fd == -1) {
-        return;
-    }
-
-    flic_disable_wait_pfault(flic);
-
-    rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
-    if (rc) {
-        trace_flic_reset_failed(errno);
-    }
-
-    flic_enable_pfault(flic);
 }
 
-static void kvm_s390_flic_class_init(ObjectClass *oc, void *data)
+static void qemu_s390_flic_class_init(ObjectClass *oc, void *data)
 {
-    DeviceClass *dc = DEVICE_CLASS(oc);
+    S390FLICStateClass *fsc = S390_FLIC_COMMON_CLASS(oc);
 
-    dc->realize = kvm_s390_flic_realize;
-    dc->unrealize = kvm_s390_flic_unrealize;
-    dc->reset = kvm_s390_flic_reset;
+    fsc->register_io_adapter = qemu_s390_register_io_adapter;
+    fsc->io_adapter_map = qemu_s390_io_adapter_map;
+    fsc->add_adapter_routes = qemu_s390_add_adapter_routes;
+    fsc->release_adapter_routes = qemu_s390_release_adapter_routes;
 }
 
-static const TypeInfo kvm_s390_flic_info = {
-    .name          = TYPE_KVM_S390_FLIC,
+static const TypeInfo qemu_s390_flic_info = {
+    .name          = TYPE_QEMU_S390_FLIC,
+    .parent        = TYPE_S390_FLIC_COMMON,
+    .instance_size = sizeof(QEMUS390FLICState),
+    .class_init    = qemu_s390_flic_class_init,
+};
+
+static const TypeInfo s390_flic_common_info = {
+    .name          = TYPE_S390_FLIC_COMMON,
     .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(KVMS390FLICState),
-    .class_init    = kvm_s390_flic_class_init,
+    .instance_size = sizeof(S390FLICState),
+    .class_size    = sizeof(S390FLICStateClass),
 };
 
-static void kvm_s390_flic_register_types(void)
+static void qemu_s390_flic_register_types(void)
 {
-    type_register_static(&kvm_s390_flic_info);
+    type_register_static(&s390_flic_common_info);
+    type_register_static(&qemu_s390_flic_info);
 }
 
-type_init(kvm_s390_flic_register_types)
+type_init(qemu_s390_flic_register_types)
diff --git a/hw/intc/s390_flic_kvm.c b/hw/intc/s390_flic_kvm.c
new file mode 100644
index 0000000000..46c9e612d1
--- /dev/null
+++ b/hw/intc/s390_flic_kvm.c
@@ -0,0 +1,420 @@
+/*
+ * QEMU S390x KVM floating interrupt controller (flic)
+ *
+ * Copyright 2014 IBM Corp.
+ * Author(s): Jens Freimann <jfrei@linux.vnet.ibm.com>
+ *            Cornelia Huck <cornelia.huck@de.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 <sys/ioctl.h>
+#include "qemu/error-report.h"
+#include "hw/sysbus.h"
+#include "sysemu/kvm.h"
+#include "migration/qemu-file.h"
+#include "hw/s390x/s390_flic.h"
+#include "hw/s390x/adapter.h"
+#include "trace.h"
+
+#define FLIC_SAVE_INITIAL_SIZE getpagesize()
+#define FLIC_FAILED (-1UL)
+#define FLIC_SAVEVM_VERSION 1
+
+typedef struct KVMS390FLICState {
+    S390FLICState parent_obj;
+
+    uint32_t fd;
+} KVMS390FLICState;
+
+DeviceState *s390_flic_kvm_create(void)
+{
+    DeviceState *dev = NULL;
+
+    if (kvm_enabled()) {
+        dev = qdev_create(NULL, TYPE_KVM_S390_FLIC);
+        object_property_add_child(qdev_get_machine(), TYPE_KVM_S390_FLIC,
+                                  OBJECT(dev), NULL);
+    }
+    return dev;
+}
+
+/**
+ * flic_get_all_irqs - store all pending irqs in buffer
+ * @buf: pointer to buffer which is passed to kernel
+ * @len: length of buffer
+ * @flic: pointer to flic device state
+ *
+ * Returns: -ENOMEM if buffer is too small,
+ * -EINVAL if attr.group is invalid,
+ * -EFAULT if copying to userspace failed,
+ * on success return number of stored interrupts
+ */
+static int flic_get_all_irqs(KVMS390FLICState *flic,
+                             void *buf, int len)
+{
+    struct kvm_device_attr attr = {
+        .group = KVM_DEV_FLIC_GET_ALL_IRQS,
+        .addr = (uint64_t) buf,
+        .attr = len,
+    };
+    int rc;
+
+    rc = ioctl(flic->fd, KVM_GET_DEVICE_ATTR, &attr);
+
+    return rc == -1 ? -errno : rc;
+}
+
+static void flic_enable_pfault(KVMS390FLICState *flic)
+{
+    struct kvm_device_attr attr = {
+        .group = KVM_DEV_FLIC_APF_ENABLE,
+    };
+    int rc;
+
+    rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
+
+    if (rc) {
+        fprintf(stderr, "flic: couldn't enable pfault\n");
+    }
+}
+
+static void flic_disable_wait_pfault(KVMS390FLICState *flic)
+{
+    struct kvm_device_attr attr = {
+        .group = KVM_DEV_FLIC_APF_DISABLE_WAIT,
+    };
+    int rc;
+
+    rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
+
+    if (rc) {
+        fprintf(stderr, "flic: couldn't disable pfault\n");
+    }
+}
+
+/** flic_enqueue_irqs - returns 0 on success
+ * @buf: pointer to buffer which is passed to kernel
+ * @len: length of buffer
+ * @flic: pointer to flic device state
+ *
+ * Returns: -EINVAL if attr.group is unknown
+ */
+static int flic_enqueue_irqs(void *buf, uint64_t len,
+                            KVMS390FLICState *flic)
+{
+    int rc;
+    struct kvm_device_attr attr = {
+        .group = KVM_DEV_FLIC_ENQUEUE,
+        .addr = (uint64_t) buf,
+        .attr = len,
+    };
+
+    rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
+
+    return rc ? -errno : 0;
+}
+
+/**
+ * __get_all_irqs - store all pending irqs in buffer
+ * @flic: pointer to flic device state
+ * @buf: pointer to pointer to a buffer
+ * @len: length of buffer
+ *
+ * Returns: return value of flic_get_all_irqs
+ * Note: Retry and increase buffer size until flic_get_all_irqs
+ * either returns a value >= 0 or a negative error code.
+ * -ENOMEM is an exception, which means the buffer is too small
+ * and we should try again. Other negative error codes can be
+ * -EFAULT and -EINVAL which we ignore at this point
+ */
+static int __get_all_irqs(KVMS390FLICState *flic,
+                          void **buf, int len)
+{
+    int r;
+
+    do {
+        /* returns -ENOMEM if buffer is too small and number
+         * of queued interrupts on success */
+        r = flic_get_all_irqs(flic, *buf, len);
+        if (r >= 0) {
+            break;
+        }
+        len *= 2;
+        *buf = g_try_realloc(*buf, len);
+        if (!buf) {
+            return -ENOMEM;
+        }
+    } while (r == -ENOMEM && len <= KVM_S390_FLIC_MAX_BUFFER);
+
+    return r;
+}
+
+static int kvm_s390_register_io_adapter(S390FLICState *fs, uint32_t id,
+                                        uint8_t isc, bool swap,
+                                        bool is_maskable)
+{
+    struct kvm_s390_io_adapter adapter = {
+        .id = id,
+        .isc = isc,
+        .maskable = is_maskable,
+        .swap = swap,
+    };
+    KVMS390FLICState *flic = KVM_S390_FLIC(fs);
+    int r, ret;
+    struct kvm_device_attr attr = {
+        .group = KVM_DEV_FLIC_ADAPTER_REGISTER,
+        .addr = (uint64_t)&adapter,
+    };
+
+    if (!kvm_check_extension(kvm_state, KVM_CAP_IRQ_ROUTING)) {
+        return -ENOSYS;
+    }
+
+    r = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
+
+    ret = r ? -errno : 0;
+    return ret;
+}
+
+static int kvm_s390_io_adapter_map(S390FLICState *fs, uint32_t id,
+                                   uint64_t map_addr, bool do_map)
+{
+    struct kvm_s390_io_adapter_req req = {
+        .id = id,
+        .type = do_map ? KVM_S390_IO_ADAPTER_MAP : KVM_S390_IO_ADAPTER_UNMAP,
+        .addr = map_addr,
+    };
+    struct kvm_device_attr attr = {
+        .group = KVM_DEV_FLIC_ADAPTER_MODIFY,
+        .addr = (uint64_t)&req,
+    };
+    KVMS390FLICState *flic = KVM_S390_FLIC(fs);
+    int r;
+
+    if (!kvm_check_extension(kvm_state, KVM_CAP_IRQ_ROUTING)) {
+        return -ENOSYS;
+    }
+
+    r = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
+    return r ? -errno : 0;
+}
+
+static int kvm_s390_add_adapter_routes(S390FLICState *fs,
+                                       AdapterRoutes *routes)
+{
+    int ret, i;
+    uint64_t ind_offset = routes->adapter.ind_offset;
+
+    for (i = 0; i < routes->num_routes; i++) {
+        ret = kvm_irqchip_add_adapter_route(kvm_state, &routes->adapter);
+        if (ret < 0) {
+            goto out_undo;
+        }
+        routes->gsi[i] = ret;
+        routes->adapter.ind_offset++;
+    }
+    /* Restore passed-in structure to original state. */
+    routes->adapter.ind_offset = ind_offset;
+    return 0;
+out_undo:
+    while (--i >= 0) {
+        kvm_irqchip_release_virq(kvm_state, routes->gsi[i]);
+        routes->gsi[i] = -1;
+    }
+    routes->adapter.ind_offset = ind_offset;
+    return ret;
+}
+
+static void kvm_s390_release_adapter_routes(S390FLICState *fs,
+                                            AdapterRoutes *routes)
+{
+    int i;
+
+    for (i = 0; i < routes->num_routes; i++) {
+        if (routes->gsi[i] >= 0) {
+            kvm_irqchip_release_virq(kvm_state, routes->gsi[i]);
+            routes->gsi[i] = -1;
+        }
+    }
+}
+
+/**
+ * kvm_flic_save - Save pending floating interrupts
+ * @f: QEMUFile containing migration state
+ * @opaque: pointer to flic device state
+ *
+ * Note: Pass buf and len to kernel. Start with one page and
+ * increase until buffer is sufficient or maxium size is
+ * reached
+ */
+static void kvm_flic_save(QEMUFile *f, void *opaque)
+{
+    KVMS390FLICState *flic = opaque;
+    int len = FLIC_SAVE_INITIAL_SIZE;
+    void *buf;
+    int count;
+
+    flic_disable_wait_pfault((struct KVMS390FLICState *) opaque);
+
+    buf = g_try_malloc0(len);
+    if (!buf) {
+        /* Storing FLIC_FAILED into the count field here will cause the
+         * target system to fail when attempting to load irqs from the
+         * migration state */
+        error_report("flic: couldn't allocate memory");
+        qemu_put_be64(f, FLIC_FAILED);
+        return;
+    }
+
+    count = __get_all_irqs(flic, &buf, len);
+    if (count < 0) {
+        error_report("flic: couldn't retrieve irqs from kernel, rc %d",
+                     count);
+        /* Storing FLIC_FAILED into the count field here will cause the
+         * target system to fail when attempting to load irqs from the
+         * migration state */
+        qemu_put_be64(f, FLIC_FAILED);
+    } else {
+        qemu_put_be64(f, count);
+        qemu_put_buffer(f, (uint8_t *) buf,
+                        count * sizeof(struct kvm_s390_irq));
+    }
+    g_free(buf);
+}
+
+/**
+ * kvm_flic_load - Load pending floating interrupts
+ * @f: QEMUFile containing migration state
+ * @opaque: pointer to flic device state
+ * @version_id: version id for migration
+ *
+ * Returns: value of flic_enqueue_irqs, -EINVAL on error
+ * Note: Do nothing when no interrupts where stored
+ * in QEMUFile
+ */
+static int kvm_flic_load(QEMUFile *f, void *opaque, int version_id)
+{
+    uint64_t len = 0;
+    uint64_t count = 0;
+    void *buf = NULL;
+    int r = 0;
+
+    if (version_id != FLIC_SAVEVM_VERSION) {
+        r = -EINVAL;
+        goto out;
+    }
+
+    flic_enable_pfault((struct KVMS390FLICState *) opaque);
+
+    count = qemu_get_be64(f);
+    len = count * sizeof(struct kvm_s390_irq);
+    if (count == FLIC_FAILED) {
+        r = -EINVAL;
+        goto out;
+    }
+    if (count == 0) {
+        r = 0;
+        goto out;
+    }
+    buf = g_try_malloc0(len);
+    if (!buf) {
+        r = -ENOMEM;
+        goto out;
+    }
+
+    if (qemu_get_buffer(f, (uint8_t *) buf, len) != len) {
+        r = -EINVAL;
+        goto out_free;
+    }
+    r = flic_enqueue_irqs(buf, len, (struct KVMS390FLICState *) opaque);
+
+out_free:
+    g_free(buf);
+out:
+    return r;
+}
+
+static void kvm_s390_flic_realize(DeviceState *dev, Error **errp)
+{
+    KVMS390FLICState *flic_state = KVM_S390_FLIC(dev);
+    struct kvm_create_device cd = {0};
+    int ret;
+
+    flic_state->fd = -1;
+    if (!kvm_check_extension(kvm_state, KVM_CAP_DEVICE_CTRL)) {
+        trace_flic_no_device_api(errno);
+        return;
+    }
+
+    cd.type = KVM_DEV_TYPE_FLIC;
+    ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd);
+    if (ret < 0) {
+        trace_flic_create_device(errno);
+        return;
+    }
+    flic_state->fd = cd.fd;
+
+    /* Register savevm handler for floating interrupts */
+    register_savevm(NULL, "s390-flic", 0, 1, kvm_flic_save,
+                    kvm_flic_load, (void *) flic_state);
+}
+
+static void kvm_s390_flic_unrealize(DeviceState *dev, Error **errp)
+{
+    KVMS390FLICState *flic_state = KVM_S390_FLIC(dev);
+
+    unregister_savevm(DEVICE(flic_state), "s390-flic", flic_state);
+}
+
+static void kvm_s390_flic_reset(DeviceState *dev)
+{
+    KVMS390FLICState *flic = KVM_S390_FLIC(dev);
+    struct kvm_device_attr attr = {
+        .group = KVM_DEV_FLIC_CLEAR_IRQS,
+    };
+    int rc = 0;
+
+    if (flic->fd == -1) {
+        return;
+    }
+
+    flic_disable_wait_pfault(flic);
+
+    rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
+    if (rc) {
+        trace_flic_reset_failed(errno);
+    }
+
+    flic_enable_pfault(flic);
+}
+
+static void kvm_s390_flic_class_init(ObjectClass *oc, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(oc);
+    S390FLICStateClass *fsc = S390_FLIC_COMMON_CLASS(oc);
+
+    dc->realize = kvm_s390_flic_realize;
+    dc->unrealize = kvm_s390_flic_unrealize;
+    dc->reset = kvm_s390_flic_reset;
+    fsc->register_io_adapter = kvm_s390_register_io_adapter;
+    fsc->io_adapter_map = kvm_s390_io_adapter_map;
+    fsc->add_adapter_routes = kvm_s390_add_adapter_routes;
+    fsc->release_adapter_routes = kvm_s390_release_adapter_routes;
+}
+
+static const TypeInfo kvm_s390_flic_info = {
+    .name          = TYPE_KVM_S390_FLIC,
+    .parent        = TYPE_S390_FLIC_COMMON,
+    .instance_size = sizeof(KVMS390FLICState),
+    .class_init    = kvm_s390_flic_class_init,
+};
+
+static void kvm_s390_flic_register_types(void)
+{
+    type_register_static(&kvm_s390_flic_info);
+}
+
+type_init(kvm_s390_flic_register_types)
diff --git a/hw/lm32/lm32_boards.c b/hw/lm32/lm32_boards.c
index 5e22e9b4d7..0e013408f1 100644
--- a/hw/lm32/lm32_boards.c
+++ b/hw/lm32/lm32_boards.c
@@ -69,10 +69,10 @@ static void main_cpu_reset(void *opaque)
     env->deba = reset_info->flash_base;
 }
 
-static void lm32_evr_init(QEMUMachineInitArgs *args)
+static void lm32_evr_init(MachineState *machine)
 {
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
+    const char *cpu_model = machine->cpu_model;
+    const char *kernel_filename = machine->kernel_filename;
     LM32CPU *cpu;
     CPULM32State *env;
     DriveInfo *dinfo;
@@ -162,12 +162,12 @@ static void lm32_evr_init(QEMUMachineInitArgs *args)
     qemu_register_reset(main_cpu_reset, reset_info);
 }
 
-static void lm32_uclinux_init(QEMUMachineInitArgs *args)
+static void lm32_uclinux_init(MachineState *machine)
 {
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
+    const char *cpu_model = machine->cpu_model;
+    const char *kernel_filename = machine->kernel_filename;
+    const char *kernel_cmdline = machine->kernel_cmdline;
+    const char *initrd_filename = machine->initrd_filename;
     LM32CPU *cpu;
     CPULM32State *env;
     DriveInfo *dinfo;
diff --git a/hw/lm32/milkymist.c b/hw/lm32/milkymist.c
index baf234ce04..81c3933e63 100644
--- a/hw/lm32/milkymist.c
+++ b/hw/lm32/milkymist.c
@@ -74,12 +74,12 @@ static void main_cpu_reset(void *opaque)
 }
 
 static void
-milkymist_init(QEMUMachineInitArgs *args)
+milkymist_init(MachineState *machine)
 {
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
+    const char *cpu_model = machine->cpu_model;
+    const char *kernel_filename = machine->kernel_filename;
+    const char *kernel_cmdline = machine->kernel_cmdline;
+    const char *initrd_filename = machine->initrd_filename;
     LM32CPU *cpu;
     CPULM32State *env;
     int kernel_size;
diff --git a/hw/m68k/an5206.c b/hw/m68k/an5206.c
index 24f2068559..684496a946 100644
--- a/hw/m68k/an5206.c
+++ b/hw/m68k/an5206.c
@@ -20,11 +20,11 @@
 
 /* Board init.  */
 
-static void an5206_init(QEMUMachineInitArgs *args)
+static void an5206_init(MachineState *machine)
 {
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
+    ram_addr_t ram_size = machine->ram_size;
+    const char *cpu_model = machine->cpu_model;
+    const char *kernel_filename = machine->kernel_filename;
     M68kCPU *cpu;
     CPUM68KState *env;
     int kernel_size;
diff --git a/hw/m68k/dummy_m68k.c b/hw/m68k/dummy_m68k.c
index 86e2e6e065..6db1b7164e 100644
--- a/hw/m68k/dummy_m68k.c
+++ b/hw/m68k/dummy_m68k.c
@@ -16,11 +16,11 @@
 
 /* Board init.  */
 
-static void dummy_m68k_init(QEMUMachineInitArgs *args)
+static void dummy_m68k_init(MachineState *machine)
 {
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
+    ram_addr_t ram_size = machine->ram_size;
+    const char *cpu_model = machine->cpu_model;
+    const char *kernel_filename = machine->kernel_filename;
     CPUM68KState *env;
     MemoryRegion *address_space_mem =  get_system_memory();
     MemoryRegion *ram = g_new(MemoryRegion, 1);
diff --git a/hw/m68k/mcf5208.c b/hw/m68k/mcf5208.c
index 6e30c0b393..2ef617f2b7 100644
--- a/hw/m68k/mcf5208.c
+++ b/hw/m68k/mcf5208.c
@@ -188,11 +188,11 @@ static void mcf5208_sys_init(MemoryRegion *address_space, qemu_irq *pic)
     }
 }
 
-static void mcf5208evb_init(QEMUMachineInitArgs *args)
+static void mcf5208evb_init(MachineState *machine)
 {
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
+    ram_addr_t ram_size = machine->ram_size;
+    const char *cpu_model = machine->cpu_model;
+    const char *kernel_filename = machine->kernel_filename;
     M68kCPU *cpu;
     CPUM68KState *env;
     int kernel_size;
diff --git a/hw/microblaze/petalogix_ml605_mmu.c b/hw/microblaze/petalogix_ml605_mmu.c
index 40a9f5ccdb..aea9c5b49f 100644
--- a/hw/microblaze/petalogix_ml605_mmu.c
+++ b/hw/microblaze/petalogix_ml605_mmu.c
@@ -79,9 +79,9 @@ static void machine_cpu_reset(MicroBlazeCPU *cpu)
 }
 
 static void
-petalogix_ml605_init(QEMUMachineInitArgs *args)
+petalogix_ml605_init(MachineState *machine)
 {
-    ram_addr_t ram_size = args->ram_size;
+    ram_addr_t ram_size = machine->ram_size;
     MemoryRegion *address_space_mem = get_system_memory();
     DeviceState *dev, *dma, *eth0;
     Object *ds, *cs;
@@ -196,13 +196,13 @@ petalogix_ml605_init(QEMUMachineInitArgs *args)
             qemu_irq cs_line;
 
             dev = ssi_create_slave(spi, "n25q128");
-            cs_line = qdev_get_gpio_in(dev, 0);
+            cs_line = qdev_get_gpio_in_named(dev, SSI_GPIO_CS, 0);
             sysbus_connect_irq(busdev, i+1, cs_line);
         }
     }
 
     microblaze_load_kernel(cpu, ddr_base, ram_size,
-                           args->initrd_filename,
+                           machine->initrd_filename,
                            BINARY_DEVICE_TREE_FILE,
                            machine_cpu_reset);
 
diff --git a/hw/microblaze/petalogix_s3adsp1800_mmu.c b/hw/microblaze/petalogix_s3adsp1800_mmu.c
index 6c45e206ec..49dc6d1949 100644
--- a/hw/microblaze/petalogix_s3adsp1800_mmu.c
+++ b/hw/microblaze/petalogix_s3adsp1800_mmu.c
@@ -59,10 +59,10 @@ static void machine_cpu_reset(MicroBlazeCPU *cpu)
 }
 
 static void
-petalogix_s3adsp1800_init(QEMUMachineInitArgs *args)
+petalogix_s3adsp1800_init(MachineState *machine)
 {
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
+    ram_addr_t ram_size = machine->ram_size;
+    const char *cpu_model = machine->cpu_model;
     DeviceState *dev;
     MicroBlazeCPU *cpu;
     DriveInfo *dinfo;
@@ -128,7 +128,7 @@ petalogix_s3adsp1800_init(QEMUMachineInitArgs *args)
     sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq[ETHLITE_IRQ]);
 
     microblaze_load_kernel(cpu, ddr_base, ram_size,
-                           args->initrd_filename,
+                           machine->initrd_filename,
                            BINARY_DEVICE_TREE_FILE,
                            machine_cpu_reset);
 }
diff --git a/hw/mips/mips_fulong2e.c b/hw/mips/mips_fulong2e.c
index 30d9f19df7..5ad7a410a9 100644
--- a/hw/mips/mips_fulong2e.c
+++ b/hw/mips/mips_fulong2e.c
@@ -259,13 +259,13 @@ static void cpu_request_exit(void *opaque, int irq, int level)
     }
 }
 
-static void mips_fulong2e_init(QEMUMachineInitArgs *args)
+static void mips_fulong2e_init(MachineState *machine)
 {
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
+    ram_addr_t ram_size = machine->ram_size;
+    const char *cpu_model = machine->cpu_model;
+    const char *kernel_filename = machine->kernel_filename;
+    const char *kernel_cmdline = machine->kernel_cmdline;
+    const char *initrd_filename = machine->initrd_filename;
     char *filename;
     MemoryRegion *address_space_mem = get_system_memory();
     MemoryRegion *ram = g_new(MemoryRegion, 1);
diff --git a/hw/mips/mips_jazz.c b/hw/mips/mips_jazz.c
index 5f6dd9f588..c113a8082b 100644
--- a/hw/mips/mips_jazz.c
+++ b/hw/mips/mips_jazz.c
@@ -329,19 +329,19 @@ static void mips_jazz_init(MemoryRegion *address_space,
 }
 
 static
-void mips_magnum_init(QEMUMachineInitArgs *args)
+void mips_magnum_init(MachineState *machine)
 {
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
+    ram_addr_t ram_size = machine->ram_size;
+    const char *cpu_model = machine->cpu_model;
         mips_jazz_init(get_system_memory(), get_system_io(),
                        ram_size, cpu_model, JAZZ_MAGNUM);
 }
 
 static
-void mips_pica61_init(QEMUMachineInitArgs *args)
+void mips_pica61_init(MachineState *machine)
 {
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
+    ram_addr_t ram_size = machine->ram_size;
+    const char *cpu_model = machine->cpu_model;
     mips_jazz_init(get_system_memory(), get_system_io(),
                    ram_size, cpu_model, JAZZ_PICA61);
 }
diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c
index ac5ec44db0..9fe775ea88 100644
--- a/hw/mips/mips_malta.c
+++ b/hw/mips/mips_malta.c
@@ -875,13 +875,13 @@ static void cpu_request_exit(void *opaque, int irq, int level)
 }
 
 static
-void mips_malta_init(QEMUMachineInitArgs *args)
+void mips_malta_init(MachineState *machine)
 {
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
+    ram_addr_t ram_size = machine->ram_size;
+    const char *cpu_model = machine->cpu_model;
+    const char *kernel_filename = machine->kernel_filename;
+    const char *kernel_cmdline = machine->kernel_cmdline;
+    const char *initrd_filename = machine->initrd_filename;
     char *filename;
     pflash_t *fl;
     MemoryRegion *system_memory = get_system_memory();
diff --git a/hw/mips/mips_mipssim.c b/hw/mips/mips_mipssim.c
index 239aa6ac8c..413e64d16b 100644
--- a/hw/mips/mips_mipssim.c
+++ b/hw/mips/mips_mipssim.c
@@ -133,13 +133,13 @@ static void mipsnet_init(int base, qemu_irq irq, NICInfo *nd)
 }
 
 static void
-mips_mipssim_init(QEMUMachineInitArgs *args)
+mips_mipssim_init(MachineState *machine)
 {
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
+    ram_addr_t ram_size = machine->ram_size;
+    const char *cpu_model = machine->cpu_model;
+    const char *kernel_filename = machine->kernel_filename;
+    const char *kernel_cmdline = machine->kernel_cmdline;
+    const char *initrd_filename = machine->initrd_filename;
     char *filename;
     MemoryRegion *address_space_mem = get_system_memory();
     MemoryRegion *isa = g_new(MemoryRegion, 1);
diff --git a/hw/mips/mips_r4k.c b/hw/mips/mips_r4k.c
index e94b543e80..71202931bf 100644
--- a/hw/mips/mips_r4k.c
+++ b/hw/mips/mips_r4k.c
@@ -153,13 +153,13 @@ static void main_cpu_reset(void *opaque)
 
 static const int sector_len = 32 * 1024;
 static
-void mips_r4k_init(QEMUMachineInitArgs *args)
+void mips_r4k_init(MachineState *machine)
 {
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
+    ram_addr_t ram_size = machine->ram_size;
+    const char *cpu_model = machine->cpu_model;
+    const char *kernel_filename = machine->kernel_filename;
+    const char *kernel_cmdline = machine->kernel_cmdline;
+    const char *initrd_filename = machine->initrd_filename;
     char *filename;
     MemoryRegion *address_space_mem = get_system_memory();
     MemoryRegion *ram = g_new(MemoryRegion, 1);
diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
index f6743659f7..979e532fdf 100644
--- a/hw/misc/Makefile.objs
+++ b/hw/misc/Makefile.objs
@@ -29,7 +29,6 @@ obj-$(CONFIG_NSERIES) += cbus.o
 obj-$(CONFIG_ECCMEMCTL) += eccmemctl.o
 obj-$(CONFIG_EXYNOS4) += exynos4210_pmu.o
 obj-$(CONFIG_IMX) += imx_ccm.o
-obj-$(CONFIG_LM32) += lm32_sys.o
 obj-$(CONFIG_MILKYMIST) += milkymist-hpdmc.o
 obj-$(CONFIG_MILKYMIST) += milkymist-pfpu.o
 obj-$(CONFIG_MAINSTONE) += mst_fpga.o
diff --git a/hw/misc/lm32_sys.c b/hw/misc/lm32_sys.c
deleted file mode 100644
index 778eb6e042..0000000000
--- a/hw/misc/lm32_sys.c
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- *  QEMU model of the LatticeMico32 system control block.
- *
- *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * This model is mainly intended for testing purposes and doesn't fit to any
- * real hardware. On the one hand it provides a control register (R_CTRL) on
- * the other hand it supports the lm32 tests.
- *
- * A write to the control register causes a system shutdown.
- * Tests first write the pointer to a test name to the test name register
- * (R_TESTNAME) and then write a zero to the pass/fail register (R_PASSFAIL) if
- * the test is passed or any non-zero value to it if the test is failed.
- */
-
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-#include "qemu/log.h"
-#include "qemu/error-report.h"
-#include "sysemu/sysemu.h"
-
-enum {
-    R_CTRL = 0,
-    R_PASSFAIL,
-    R_TESTNAME,
-    R_MAX
-};
-
-#define MAX_TESTNAME_LEN 32
-
-#define TYPE_LM32_SYS "lm32-sys"
-#define LM32_SYS(obj) OBJECT_CHECK(LM32SysState, (obj), TYPE_LM32_SYS)
-
-struct LM32SysState {
-    SysBusDevice parent_obj;
-
-    MemoryRegion iomem;
-    uint32_t base;
-    uint32_t regs[R_MAX];
-    uint8_t testname[MAX_TESTNAME_LEN];
-};
-typedef struct LM32SysState LM32SysState;
-
-static void copy_testname(LM32SysState *s)
-{
-    cpu_physical_memory_read(s->regs[R_TESTNAME], s->testname,
-            MAX_TESTNAME_LEN);
-    s->testname[MAX_TESTNAME_LEN - 1] = '\0';
-}
-
-static void sys_write(void *opaque, hwaddr addr,
-                      uint64_t value, unsigned size)
-{
-    LM32SysState *s = opaque;
-    char *testname;
-
-    trace_lm32_sys_memory_write(addr, value);
-
-    addr >>= 2;
-    switch (addr) {
-    case R_CTRL:
-        qemu_system_shutdown_request();
-        break;
-    case R_PASSFAIL:
-        s->regs[addr] = value;
-        testname = (char *)s->testname;
-        fprintf(stderr, "TC  %-*s %s\n", MAX_TESTNAME_LEN,
-                testname, (value) ? "FAILED" : "OK");
-        if (value) {
-            cpu_dump_state(qemu_get_cpu(0), stderr, fprintf, 0);
-        }
-        break;
-    case R_TESTNAME:
-        s->regs[addr] = value;
-        copy_testname(s);
-        break;
-
-    default:
-        error_report("lm32_sys: write access to unknown register 0x"
-                TARGET_FMT_plx, addr << 2);
-        break;
-    }
-}
-
-static bool sys_ops_accepts(void *opaque, hwaddr addr,
-                            unsigned size, bool is_write)
-{
-    return is_write && size == 4;
-}
-
-static const MemoryRegionOps sys_ops = {
-    .write = sys_write,
-    .valid.accepts = sys_ops_accepts,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void sys_reset(DeviceState *d)
-{
-    LM32SysState *s = LM32_SYS(d);
-    int i;
-
-    for (i = 0; i < R_MAX; i++) {
-        s->regs[i] = 0;
-    }
-    memset(s->testname, 0, MAX_TESTNAME_LEN);
-}
-
-static int lm32_sys_init(SysBusDevice *dev)
-{
-    LM32SysState *s = LM32_SYS(dev);
-
-    memory_region_init_io(&s->iomem, OBJECT(dev), &sys_ops , s,
-                          "sys", R_MAX * 4);
-    sysbus_init_mmio(dev, &s->iomem);
-
-    /* Note: This device is not created in the board initialization,
-     * instead it has to be added with the -device parameter. Therefore,
-     * the device maps itself. */
-    sysbus_mmio_map(dev, 0, s->base);
-
-    return 0;
-}
-
-static const VMStateDescription vmstate_lm32_sys = {
-    .name = "lm32-sys",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32_ARRAY(regs, LM32SysState, R_MAX),
-        VMSTATE_BUFFER(testname, LM32SysState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static Property lm32_sys_properties[] = {
-    DEFINE_PROP_UINT32("base", LM32SysState, base, 0xffff0000),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void lm32_sys_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = lm32_sys_init;
-    dc->reset = sys_reset;
-    dc->vmsd = &vmstate_lm32_sys;
-    dc->props = lm32_sys_properties;
-}
-
-static const TypeInfo lm32_sys_info = {
-    .name          = TYPE_LM32_SYS,
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(LM32SysState),
-    .class_init    = lm32_sys_class_init,
-};
-
-static void lm32_sys_register_types(void)
-{
-    type_register_static(&lm32_sys_info);
-}
-
-type_init(lm32_sys_register_types)
diff --git a/hw/misc/vfio.c b/hw/misc/vfio.c
index 9cf5b84045..7437c2e3c3 100644
--- a/hw/misc/vfio.c
+++ b/hw/misc/vfio.c
@@ -133,6 +133,15 @@ enum {
     VFIO_INT_MSIX = 3,
 };
 
+typedef struct VFIOAddressSpace {
+    AddressSpace *as;
+    QLIST_HEAD(, VFIOContainer) containers;
+    QLIST_ENTRY(VFIOAddressSpace) list;
+} VFIOAddressSpace;
+
+static QLIST_HEAD(, VFIOAddressSpace) vfio_address_spaces =
+    QLIST_HEAD_INITIALIZER(vfio_address_spaces);
+
 struct VFIOGroup;
 
 typedef struct VFIOType1 {
@@ -142,6 +151,7 @@ typedef struct VFIOType1 {
 } VFIOType1;
 
 typedef struct VFIOContainer {
+    VFIOAddressSpace *space;
     int fd; /* /dev/vfio/vfio, empowered by the attached groups */
     struct {
         /* enable abstraction to support various iommu backends */
@@ -150,10 +160,18 @@ typedef struct VFIOContainer {
         };
         void (*release)(struct VFIOContainer *);
     } iommu_data;
+    QLIST_HEAD(, VFIOGuestIOMMU) giommu_list;
     QLIST_HEAD(, VFIOGroup) group_list;
     QLIST_ENTRY(VFIOContainer) next;
 } VFIOContainer;
 
+typedef struct VFIOGuestIOMMU {
+    VFIOContainer *container;
+    MemoryRegion *iommu;
+    Notifier n;
+    QLIST_ENTRY(VFIOGuestIOMMU) giommu_next;
+} VFIOGuestIOMMU;
+
 /* Cache of MSI-X setup plus extra mmap and memory region for split BAR map */
 typedef struct VFIOMSIXInfo {
     uint8_t table_bar;
@@ -234,9 +252,6 @@ static const VFIORomBlacklistEntry romblacklist[] = {
 
 #define MSIX_CAP_LENGTH 12
 
-static QLIST_HEAD(, VFIOContainer)
-    container_list = QLIST_HEAD_INITIALIZER(container_list);
-
 static QLIST_HEAD(, VFIOGroup)
     group_list = QLIST_HEAD_INITIALIZER(group_list);
 
@@ -1668,6 +1683,149 @@ static void vfio_probe_ati_bar4_window_quirk(VFIODevice *vdev, int nr)
             vdev->host.function);
 }
 
+#define PCI_VENDOR_ID_REALTEK 0x10ec
+
+/*
+ * RTL8168 devices have a backdoor that can access the MSI-X table.  At BAR2
+ * offset 0x70 there is a dword data register, offset 0x74 is a dword address
+ * register.  According to the Linux r8169 driver, the MSI-X table is addressed
+ * when the "type" portion of the address register is set to 0x1.  This appears
+ * to be bits 16:30.  Bit 31 is both a write indicator and some sort of
+ * "address latched" indicator.  Bits 12:15 are a mask field, which we can
+ * ignore because the MSI-X table should always be accessed as a dword (full
+ * mask).  Bits 0:11 is offset within the type.
+ *
+ * Example trace:
+ *
+ * Read from MSI-X table offset 0
+ * vfio: vfio_bar_write(0000:05:00.0:BAR2+0x74, 0x1f000, 4) // store read addr
+ * vfio: vfio_bar_read(0000:05:00.0:BAR2+0x74, 4) = 0x8001f000 // latch
+ * vfio: vfio_bar_read(0000:05:00.0:BAR2+0x70, 4) = 0xfee00398 // read data
+ *
+ * Write 0xfee00000 to MSI-X table offset 0
+ * vfio: vfio_bar_write(0000:05:00.0:BAR2+0x70, 0xfee00000, 4) // write data
+ * vfio: vfio_bar_write(0000:05:00.0:BAR2+0x74, 0x8001f000, 4) // do write
+ * vfio: vfio_bar_read(0000:05:00.0:BAR2+0x74, 4) = 0x1f000 // complete
+ */
+
+static uint64_t vfio_rtl8168_window_quirk_read(void *opaque,
+                                               hwaddr addr, unsigned size)
+{
+    VFIOQuirk *quirk = opaque;
+    VFIODevice *vdev = quirk->vdev;
+
+    switch (addr) {
+    case 4: /* address */
+        if (quirk->data.flags) {
+            DPRINTF("%s fake read(%04x:%02x:%02x.%d)\n",
+                    memory_region_name(&quirk->mem), vdev->host.domain,
+                    vdev->host.bus, vdev->host.slot, vdev->host.function);
+
+            return quirk->data.address_match ^ 0x10000000U;
+        }
+        break;
+    case 0: /* data */
+        if (quirk->data.flags) {
+            uint64_t val;
+
+            DPRINTF("%s MSI-X table read(%04x:%02x:%02x.%d)\n",
+                    memory_region_name(&quirk->mem), vdev->host.domain,
+                    vdev->host.bus, vdev->host.slot, vdev->host.function);
+
+            if (!(vdev->pdev.cap_present & QEMU_PCI_CAP_MSIX)) {
+                return 0;
+            }
+
+            io_mem_read(&vdev->pdev.msix_table_mmio,
+                        (hwaddr)(quirk->data.address_match & 0xfff),
+                        &val, size);
+            return val;
+        }
+    }
+
+    DPRINTF("%s direct read(%04x:%02x:%02x.%d)\n",
+            memory_region_name(&quirk->mem), vdev->host.domain,
+            vdev->host.bus, vdev->host.slot, vdev->host.function);
+
+    return vfio_bar_read(&vdev->bars[quirk->data.bar], addr + 0x70, size);
+}
+
+static void vfio_rtl8168_window_quirk_write(void *opaque, hwaddr addr,
+                                            uint64_t data, unsigned size)
+{
+    VFIOQuirk *quirk = opaque;
+    VFIODevice *vdev = quirk->vdev;
+
+    switch (addr) {
+    case 4: /* address */
+        if ((data & 0x7fff0000) == 0x10000) {
+            if (data & 0x10000000U &&
+                vdev->pdev.cap_present & QEMU_PCI_CAP_MSIX) {
+
+                DPRINTF("%s MSI-X table write(%04x:%02x:%02x.%d)\n",
+                        memory_region_name(&quirk->mem), vdev->host.domain,
+                        vdev->host.bus, vdev->host.slot, vdev->host.function);
+
+                io_mem_write(&vdev->pdev.msix_table_mmio,
+                             (hwaddr)(quirk->data.address_match & 0xfff),
+                             data, size);
+            }
+
+            quirk->data.flags = 1;
+            quirk->data.address_match = data;
+
+            return;
+        }
+        quirk->data.flags = 0;
+        break;
+    case 0: /* data */
+        quirk->data.address_mask = data;
+        break;
+    }
+
+    DPRINTF("%s direct write(%04x:%02x:%02x.%d)\n",
+            memory_region_name(&quirk->mem), vdev->host.domain,
+            vdev->host.bus, vdev->host.slot, vdev->host.function);
+
+    vfio_bar_write(&vdev->bars[quirk->data.bar], addr + 0x70, data, size);
+}
+
+static const MemoryRegionOps vfio_rtl8168_window_quirk = {
+    .read = vfio_rtl8168_window_quirk_read,
+    .write = vfio_rtl8168_window_quirk_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+        .unaligned = false,
+    },
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void vfio_probe_rtl8168_bar2_window_quirk(VFIODevice *vdev, int nr)
+{
+    PCIDevice *pdev = &vdev->pdev;
+    VFIOQuirk *quirk;
+
+    if (pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_REALTEK ||
+        pci_get_word(pdev->config + PCI_DEVICE_ID) != 0x8168 || nr != 2) {
+        return;
+    }
+
+    quirk = g_malloc0(sizeof(*quirk));
+    quirk->vdev = vdev;
+    quirk->data.bar = nr;
+
+    memory_region_init_io(&quirk->mem, OBJECT(vdev), &vfio_rtl8168_window_quirk,
+                          quirk, "vfio-rtl8168-window-quirk", 8);
+    memory_region_add_subregion_overlap(&vdev->bars[nr].mem,
+                                        0x70, &quirk->mem, 1);
+
+    QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
+
+    DPRINTF("Enabled RTL8168 BAR2 window quirk for device %04x:%02x:%02x.%x\n",
+            vdev->host.domain, vdev->host.bus, vdev->host.slot,
+            vdev->host.function);
+}
 /*
  * Trap the BAR2 MMIO window to config space as well.
  */
@@ -2071,6 +2229,7 @@ static void vfio_bar_quirk_setup(VFIODevice *vdev, int nr)
     vfio_probe_nvidia_bar5_window_quirk(vdev, nr);
     vfio_probe_nvidia_bar0_88000_quirk(vdev, nr);
     vfio_probe_nvidia_bar0_1800_quirk(vdev, nr);
+    vfio_probe_rtl8168_bar2_window_quirk(vdev, nr);
 }
 
 static void vfio_bar_quirk_teardown(VFIODevice *vdev, int nr)
@@ -2232,7 +2391,8 @@ static int vfio_dma_map(VFIOContainer *container, hwaddr iova,
 
 static bool vfio_listener_skipped_section(MemoryRegionSection *section)
 {
-    return !memory_region_is_ram(section->mr) ||
+    return (!memory_region_is_ram(section->mr) &&
+            !memory_region_is_iommu(section->mr)) ||
            /*
             * Sizing an enabled 64-bit BAR can cause spurious mappings to
             * addresses in the upper part of the 64-bit address space.  These
@@ -2242,17 +2402,75 @@ static bool vfio_listener_skipped_section(MemoryRegionSection *section)
            section->offset_within_address_space & (1ULL << 63);
 }
 
+static void vfio_iommu_map_notify(Notifier *n, void *data)
+{
+    VFIOGuestIOMMU *giommu = container_of(n, VFIOGuestIOMMU, n);
+    VFIOContainer *container = giommu->container;
+    IOMMUTLBEntry *iotlb = data;
+    MemoryRegion *mr;
+    hwaddr xlat;
+    hwaddr len = iotlb->addr_mask + 1;
+    void *vaddr;
+    int ret;
+
+    DPRINTF("iommu map @ %"HWADDR_PRIx" - %"HWADDR_PRIx"\n",
+            iotlb->iova, iotlb->iova + iotlb->addr_mask);
+
+    /*
+     * The IOMMU TLB entry we have just covers translation through
+     * this IOMMU to its immediate target.  We need to translate
+     * it the rest of the way through to memory.
+     */
+    mr = address_space_translate(&address_space_memory,
+                                 iotlb->translated_addr,
+                                 &xlat, &len, iotlb->perm & IOMMU_WO);
+    if (!memory_region_is_ram(mr)) {
+        DPRINTF("iommu map to non memory area %"HWADDR_PRIx"\n",
+                xlat);
+        return;
+    }
+    /*
+     * Translation truncates length to the IOMMU page size,
+     * check that it did not truncate too much.
+     */
+    if (len & iotlb->addr_mask) {
+        DPRINTF("iommu has granularity incompatible with target AS\n");
+        return;
+    }
+
+    if (iotlb->perm != IOMMU_NONE) {
+        vaddr = memory_region_get_ram_ptr(mr) + xlat;
+
+        ret = vfio_dma_map(container, iotlb->iova,
+                           iotlb->addr_mask + 1, vaddr,
+                           !(iotlb->perm & IOMMU_WO) || mr->readonly);
+        if (ret) {
+            error_report("vfio_dma_map(%p, 0x%"HWADDR_PRIx", "
+                         "0x%"HWADDR_PRIx", %p) = %d (%m)",
+                         container, iotlb->iova,
+                         iotlb->addr_mask + 1, vaddr, ret);
+        }
+    } else {
+        ret = vfio_dma_unmap(container, iotlb->iova, iotlb->addr_mask + 1);
+        if (ret) {
+            error_report("vfio_dma_unmap(%p, 0x%"HWADDR_PRIx", "
+                         "0x%"HWADDR_PRIx") = %d (%m)",
+                         container, iotlb->iova,
+                         iotlb->addr_mask + 1, ret);
+        }
+    }
+}
+
 static void vfio_listener_region_add(MemoryListener *listener,
                                      MemoryRegionSection *section)
 {
     VFIOContainer *container = container_of(listener, VFIOContainer,
                                             iommu_data.type1.listener);
     hwaddr iova, end;
+    Int128 llend;
     void *vaddr;
     int ret;
 
-    assert(!memory_region_is_iommu(section->mr));
-
     if (vfio_listener_skipped_section(section)) {
         DPRINTF("SKIPPING region_add %"HWADDR_PRIx" - %"PRIx64"\n",
                 section->offset_within_address_space,
@@ -2268,21 +2486,65 @@ static void vfio_listener_region_add(MemoryListener *listener,
     }
 
     iova = TARGET_PAGE_ALIGN(section->offset_within_address_space);
-    end = (section->offset_within_address_space + int128_get64(section->size)) &
-          TARGET_PAGE_MASK;
+    llend = int128_make64(section->offset_within_address_space);
+    llend = int128_add(llend, section->size);
+    llend = int128_and(llend, int128_exts64(TARGET_PAGE_MASK));
 
-    if (iova >= end) {
+    if (int128_ge(int128_make64(iova), llend)) {
         return;
     }
 
+    memory_region_ref(section->mr);
+
+    if (memory_region_is_iommu(section->mr)) {
+        VFIOGuestIOMMU *giommu;
+
+        DPRINTF("region_add [iommu] %"HWADDR_PRIx" - %"HWADDR_PRIx"\n",
+                iova, int128_get64(int128_sub(llend, int128_one())));
+        /*
+         * FIXME: We should do some checking to see if the
+         * capabilities of the host VFIO IOMMU are adequate to model
+         * the guest IOMMU
+         *
+         * FIXME: For VFIO iommu types which have KVM acceleration to
+         * avoid bouncing all map/unmaps through qemu this way, this
+         * would be the right place to wire that up (tell the KVM
+         * device emulation the VFIO iommu handles to use).
+         */
+        /*
+         * This assumes that the guest IOMMU is empty of
+         * mappings at this point.
+         *
+         * One way of doing this is:
+         * 1. Avoid sharing IOMMUs between emulated devices or different
+         * IOMMU groups.
+         * 2. Implement VFIO_IOMMU_ENABLE in the host kernel to fail if
+         * there are some mappings in IOMMU.
+         *
+         * VFIO on SPAPR does that. Other IOMMU models may do that different,
+         * they must make sure there are no existing mappings or
+         * loop through existing mappings to map them into VFIO.
+         */
+        giommu = g_malloc0(sizeof(*giommu));
+        giommu->iommu = section->mr;
+        giommu->container = container;
+        giommu->n.notify = vfio_iommu_map_notify;
+        QLIST_INSERT_HEAD(&container->giommu_list, giommu, giommu_next);
+        memory_region_register_iommu_notifier(giommu->iommu, &giommu->n);
+
+        return;
+    }
+
+    /* Here we assume that memory_region_is_ram(section->mr)==true */
+
+    end = int128_get64(llend);
     vaddr = memory_region_get_ram_ptr(section->mr) +
             section->offset_within_region +
             (iova - section->offset_within_address_space);
 
-    DPRINTF("region_add %"HWADDR_PRIx" - %"HWADDR_PRIx" [%p]\n",
+    DPRINTF("region_add [ram] %"HWADDR_PRIx" - %"HWADDR_PRIx" [%p]\n",
             iova, end - 1, vaddr);
 
-    memory_region_ref(section->mr);
     ret = vfio_dma_map(container, iova, end - iova, vaddr, section->readonly);
     if (ret) {
         error_report("vfio_dma_map(%p, 0x%"HWADDR_PRIx", "
@@ -2326,6 +2588,27 @@ static void vfio_listener_region_del(MemoryListener *listener,
         return;
     }
 
+    if (memory_region_is_iommu(section->mr)) {
+        VFIOGuestIOMMU *giommu;
+
+        QLIST_FOREACH(giommu, &container->giommu_list, giommu_next) {
+            if (giommu->iommu == section->mr) {
+                memory_region_unregister_iommu_notifier(&giommu->n);
+                QLIST_REMOVE(giommu, giommu_next);
+                g_free(giommu);
+                break;
+            }
+        }
+
+        /*
+         * FIXME: We assume the one big unmap below is adequate to
+         * remove any individual page mappings in the IOMMU which
+         * might have been copied into VFIO. This works for a page table
+         * based IOMMU where a big unmap flattens a large range of IO-PTEs.
+         * That may not be true for all IOMMU types.
+         */
+    }
+
     iova = TARGET_PAGE_ALIGN(section->offset_within_address_space);
     end = (section->offset_within_address_space + int128_get64(section->size)) &
           TARGET_PAGE_MASK;
@@ -3274,16 +3557,43 @@ static void vfio_kvm_device_del_group(VFIOGroup *group)
 #endif
 }
 
-static int vfio_connect_container(VFIOGroup *group)
+static VFIOAddressSpace *vfio_get_address_space(AddressSpace *as)
+{
+    VFIOAddressSpace *space;
+
+    QLIST_FOREACH(space, &vfio_address_spaces, list) {
+        if (space->as == as) {
+            return space;
+        }
+    }
+
+    /* No suitable VFIOAddressSpace, create a new one */
+    space = g_malloc0(sizeof(*space));
+    space->as = as;
+    QLIST_INIT(&space->containers);
+
+    QLIST_INSERT_HEAD(&vfio_address_spaces, space, list);
+
+    return space;
+}
+
+static void vfio_put_address_space(VFIOAddressSpace *space)
+{
+    if (QLIST_EMPTY(&space->containers)) {
+        QLIST_REMOVE(space, list);
+        g_free(space);
+    }
+}
+
+static int vfio_connect_container(VFIOGroup *group, AddressSpace *as)
 {
     VFIOContainer *container;
     int ret, fd;
+    VFIOAddressSpace *space;
 
-    if (group->container) {
-        return 0;
-    }
+    space = vfio_get_address_space(as);
 
-    QLIST_FOREACH(container, &container_list, next) {
+    QLIST_FOREACH(container, &space->containers, next) {
         if (!ioctl(group->fd, VFIO_GROUP_SET_CONTAINER, &container->fd)) {
             group->container = container;
             QLIST_INSERT_HEAD(&container->group_list, group, container_next);
@@ -3294,35 +3604,35 @@ static int vfio_connect_container(VFIOGroup *group)
     fd = qemu_open("/dev/vfio/vfio", O_RDWR);
     if (fd < 0) {
         error_report("vfio: failed to open /dev/vfio/vfio: %m");
-        return -errno;
+        ret = -errno;
+        goto put_space_exit;
     }
 
     ret = ioctl(fd, VFIO_GET_API_VERSION);
     if (ret != VFIO_API_VERSION) {
         error_report("vfio: supported vfio version: %d, "
                      "reported version: %d", VFIO_API_VERSION, ret);
-        close(fd);
-        return -EINVAL;
+        ret = -EINVAL;
+        goto close_fd_exit;
     }
 
     container = g_malloc0(sizeof(*container));
+    container->space = space;
     container->fd = fd;
 
     if (ioctl(fd, VFIO_CHECK_EXTENSION, VFIO_TYPE1_IOMMU)) {
         ret = ioctl(group->fd, VFIO_GROUP_SET_CONTAINER, &fd);
         if (ret) {
             error_report("vfio: failed to set group container: %m");
-            g_free(container);
-            close(fd);
-            return -errno;
+            ret = -errno;
+            goto free_container_exit;
         }
 
         ret = ioctl(fd, VFIO_SET_IOMMU, VFIO_TYPE1_IOMMU);
         if (ret) {
             error_report("vfio: failed to set iommu for container: %m");
-            g_free(container);
-            close(fd);
-            return -errno;
+            ret = -errno;
+            goto free_container_exit;
         }
 
         container->iommu_data.type1.listener = vfio_memory_listener;
@@ -3333,29 +3643,39 @@ static int vfio_connect_container(VFIOGroup *group)
 
         if (container->iommu_data.type1.error) {
             ret = container->iommu_data.type1.error;
-            vfio_listener_release(container);
-            g_free(container);
-            close(fd);
             error_report("vfio: memory listener initialization failed for container");
-            return ret;
+            goto listener_release_exit;
         }
 
         container->iommu_data.type1.initialized = true;
 
     } else {
         error_report("vfio: No available IOMMU models");
-        g_free(container);
-        close(fd);
-        return -EINVAL;
+        ret = -EINVAL;
+        goto free_container_exit;
     }
 
     QLIST_INIT(&container->group_list);
-    QLIST_INSERT_HEAD(&container_list, container, next);
+    QLIST_INSERT_HEAD(&space->containers, container, next);
 
     group->container = container;
     QLIST_INSERT_HEAD(&container->group_list, group, container_next);
 
     return 0;
+
+listener_release_exit:
+    vfio_listener_release(container);
+
+free_container_exit:
+    g_free(container);
+
+close_fd_exit:
+    close(fd);
+
+put_space_exit:
+    vfio_put_address_space(space);
+
+    return ret;
 }
 
 static void vfio_disconnect_container(VFIOGroup *group)
@@ -3371,6 +3691,8 @@ static void vfio_disconnect_container(VFIOGroup *group)
     group->container = NULL;
 
     if (QLIST_EMPTY(&container->group_list)) {
+        VFIOAddressSpace *space = container->space;
+
         if (container->iommu_data.release) {
             container->iommu_data.release(container);
         }
@@ -3378,10 +3700,12 @@ static void vfio_disconnect_container(VFIOGroup *group)
         DPRINTF("vfio_disconnect_container: close container->fd\n");
         close(container->fd);
         g_free(container);
+
+        vfio_put_address_space(space);
     }
 }
 
-static VFIOGroup *vfio_get_group(int groupid)
+static VFIOGroup *vfio_get_group(int groupid, AddressSpace *as)
 {
     VFIOGroup *group;
     char path[32];
@@ -3389,7 +3713,14 @@ static VFIOGroup *vfio_get_group(int groupid)
 
     QLIST_FOREACH(group, &group_list, next) {
         if (group->groupid == groupid) {
-            return group;
+            /* Found it.  Now is it already in the right context? */
+            if (group->container->space->as == as) {
+                return group;
+            } else {
+                error_report("vfio: group %d used in multiple address spaces",
+                             group->groupid);
+                return NULL;
+            }
         }
     }
 
@@ -3399,34 +3730,27 @@ static VFIOGroup *vfio_get_group(int groupid)
     group->fd = qemu_open(path, O_RDWR);
     if (group->fd < 0) {
         error_report("vfio: error opening %s: %m", path);
-        g_free(group);
-        return NULL;
+        goto free_group_exit;
     }
 
     if (ioctl(group->fd, VFIO_GROUP_GET_STATUS, &status)) {
         error_report("vfio: error getting group status: %m");
-        close(group->fd);
-        g_free(group);
-        return NULL;
+        goto close_fd_exit;
     }
 
     if (!(status.flags & VFIO_GROUP_FLAGS_VIABLE)) {
         error_report("vfio: error, group %d is not viable, please ensure "
                      "all devices within the iommu_group are bound to their "
                      "vfio bus driver.", groupid);
-        close(group->fd);
-        g_free(group);
-        return NULL;
+        goto close_fd_exit;
     }
 
     group->groupid = groupid;
     QLIST_INIT(&group->device_list);
 
-    if (vfio_connect_container(group)) {
+    if (vfio_connect_container(group, as)) {
         error_report("vfio: failed to setup container for group %d", groupid);
-        close(group->fd);
-        g_free(group);
-        return NULL;
+        goto close_fd_exit;
     }
 
     if (QLIST_EMPTY(&group_list)) {
@@ -3438,6 +3762,14 @@ static VFIOGroup *vfio_get_group(int groupid)
     vfio_kvm_device_add_group(group);
 
     return group;
+
+close_fd_exit:
+    close(group->fd);
+
+free_group_exit:
+    g_free(group);
+
+    return NULL;
 }
 
 static void vfio_put_group(VFIOGroup *group)
@@ -3768,7 +4100,7 @@ static int vfio_initfn(PCIDevice *pdev)
     DPRINTF("%s(%04x:%02x:%02x.%x) group %d\n", __func__, vdev->host.domain,
             vdev->host.bus, vdev->host.slot, vdev->host.function, groupid);
 
-    group = vfio_get_group(groupid);
+    group = vfio_get_group(groupid, pci_device_iommu_address_space(pdev));
     if (!group) {
         error_report("vfio: failed to get group %d", groupid);
         return -ENOENT;
diff --git a/hw/moxie/moxiesim.c b/hw/moxie/moxiesim.c
index a87ca6ddcc..f4357cf0d8 100644
--- a/hw/moxie/moxiesim.c
+++ b/hw/moxie/moxiesim.c
@@ -107,14 +107,14 @@ moxie_intc_create(hwaddr base, qemu_irq irq, int kind_of_intr)
     return dev;
 }
 
-static void moxiesim_init(QEMUMachineInitArgs *args)
+static void moxiesim_init(MachineState *machine)
 {
     MoxieCPU *cpu = NULL;
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
+    ram_addr_t ram_size = machine->ram_size;
+    const char *cpu_model = machine->cpu_model;
+    const char *kernel_filename = machine->kernel_filename;
+    const char *kernel_cmdline = machine->kernel_cmdline;
+    const char *initrd_filename = machine->initrd_filename;
     CPUMoxieState *env;
     MemoryRegion *address_space_mem = get_system_memory();
     MemoryRegion *ram = g_new(MemoryRegion, 1);
diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c
index 47e70381fe..a26861e2ae 100644
--- a/hw/net/cadence_gem.c
+++ b/hw/net/cadence_gem.c
@@ -1,5 +1,5 @@
 /*
- * QEMU Xilinx GEM emulation
+ * QEMU Cadence GEM emulation
  *
  * Copyright (c) 2011 Xilinx, Inc.
  *
diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c
index 8e1af8bf2e..b2b4f9b860 100644
--- a/hw/openrisc/openrisc_sim.c
+++ b/hw/openrisc/openrisc_sim.c
@@ -90,11 +90,11 @@ static void cpu_openrisc_load_kernel(ram_addr_t ram_size,
     }
 }
 
-static void openrisc_sim_init(QEMUMachineInitArgs *args)
+static void openrisc_sim_init(MachineState *machine)
 {
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
+    ram_addr_t ram_size = machine->ram_size;
+    const char *cpu_model = machine->cpu_model;
+    const char *kernel_filename = machine->kernel_filename;
     OpenRISCCPU *cpu = NULL;
     MemoryRegion *ram;
     int n;
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index 22fe5eec36..8d6a8d4e74 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -605,13 +605,13 @@ PCIBus *pci_get_bus_devfn(int *devfnp, PCIBus *root, const char *devaddr)
     int dom, bus;
     unsigned slot;
 
-    assert(!root->parent_dev);
-
     if (!root) {
         fprintf(stderr, "No primary PCI bus\n");
         return NULL;
     }
 
+    assert(!root->parent_dev);
+
     if (!devaddr) {
         *devfnp = -1;
         return pci_find_bus_nr(root, 0);
diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index f984b3e9a9..223bab9eea 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -123,7 +123,7 @@ static void dt_serial_create(void *fdt, unsigned long long offset,
     }
 }
 
-static int ppce500_load_device_tree(QEMUMachineInitArgs *args,
+static int ppce500_load_device_tree(MachineState *machine,
                                     PPCE500Params *params,
                                     hwaddr addr,
                                     hwaddr initrd_base,
@@ -132,7 +132,7 @@ static int ppce500_load_device_tree(QEMUMachineInitArgs *args,
 {
     CPUPPCState *env = first_cpu->env_ptr;
     int ret = -1;
-    uint64_t mem_reg_property[] = { 0, cpu_to_be64(args->ram_size) };
+    uint64_t mem_reg_property[] = { 0, cpu_to_be64(machine->ram_size) };
     int fdt_size;
     void *fdt;
     uint8_t hypercall[16];
@@ -207,7 +207,7 @@ static int ppce500_load_device_tree(QEMUMachineInitArgs *args,
     }
 
     ret = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs",
-                                      args->kernel_cmdline);
+                                      machine->kernel_cmdline);
     if (ret < 0)
         fprintf(stderr, "couldn't set /chosen/bootargs\n");
 
@@ -387,7 +387,7 @@ out:
 }
 
 typedef struct DeviceTreeParams {
-    QEMUMachineInitArgs args;
+    MachineState *machine;
     PPCE500Params params;
     hwaddr addr;
     hwaddr initrd_base;
@@ -397,18 +397,18 @@ typedef struct DeviceTreeParams {
 static void ppce500_reset_device_tree(void *opaque)
 {
     DeviceTreeParams *p = opaque;
-    ppce500_load_device_tree(&p->args, &p->params, p->addr, p->initrd_base,
+    ppce500_load_device_tree(p->machine, &p->params, p->addr, p->initrd_base,
                              p->initrd_size, false);
 }
 
-static int ppce500_prep_device_tree(QEMUMachineInitArgs *args,
+static int ppce500_prep_device_tree(MachineState *machine,
                                     PPCE500Params *params,
                                     hwaddr addr,
                                     hwaddr initrd_base,
                                     hwaddr initrd_size)
 {
     DeviceTreeParams *p = g_new(DeviceTreeParams, 1);
-    p->args = *args;
+    p->machine = machine;
     p->params = *params;
     p->addr = addr;
     p->initrd_base = initrd_base;
@@ -417,7 +417,7 @@ static int ppce500_prep_device_tree(QEMUMachineInitArgs *args,
     qemu_register_reset(ppce500_reset_device_tree, p);
 
     /* Issue the device tree loader once, so that we get the size of the blob */
-    return ppce500_load_device_tree(args, params, addr, initrd_base,
+    return ppce500_load_device_tree(machine, params, addr, initrd_base,
                                     initrd_size, true);
 }
 
@@ -597,7 +597,7 @@ static qemu_irq *ppce500_init_mpic(PPCE500Params *params, MemoryRegion *ccsr,
     return mpic;
 }
 
-void ppce500_init(QEMUMachineInitArgs *args, PPCE500Params *params)
+void ppce500_init(MachineState *machine, PPCE500Params *params)
 {
     MemoryRegion *address_space_mem = get_system_memory();
     MemoryRegion *ram = g_new(MemoryRegion, 1);
@@ -622,8 +622,8 @@ void ppce500_init(QEMUMachineInitArgs *args, PPCE500Params *params)
     PPCE500CCSRState *ccsr;
 
     /* Setup CPUs */
-    if (args->cpu_model == NULL) {
-        args->cpu_model = "e500v2_v30";
+    if (machine->cpu_model == NULL) {
+        machine->cpu_model = "e500v2_v30";
     }
 
     irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *));
@@ -633,7 +633,7 @@ void ppce500_init(QEMUMachineInitArgs *args, PPCE500Params *params)
         CPUState *cs;
         qemu_irq *input;
 
-        cpu = cpu_ppc_init(args->cpu_model);
+        cpu = cpu_ppc_init(machine->cpu_model);
         if (cpu == NULL) {
             fprintf(stderr, "Unable to initialize CPU!\n");
             exit(1);
@@ -672,7 +672,7 @@ void ppce500_init(QEMUMachineInitArgs *args, PPCE500Params *params)
 
     /* Fixup Memory size on a alignment boundary */
     ram_size &= ~(RAM_SIZES_ALIGN - 1);
-    args->ram_size = ram_size;
+    machine->ram_size = ram_size;
 
     /* Register Memory */
     memory_region_init_ram(ram, NULL, "mpc8544ds.ram", ram_size);
@@ -739,11 +739,11 @@ void ppce500_init(QEMUMachineInitArgs *args, PPCE500Params *params)
     sysbus_create_simple("e500-spin", MPC8544_SPIN_BASE, NULL);
 
     /* Load kernel. */
-    if (args->kernel_filename) {
-        kernel_size = load_uimage(args->kernel_filename, &entry,
+    if (machine->kernel_filename) {
+        kernel_size = load_uimage(machine->kernel_filename, &entry,
                                   &loadaddr, NULL);
         if (kernel_size < 0) {
-            kernel_size = load_elf(args->kernel_filename, NULL, NULL,
+            kernel_size = load_elf(machine->kernel_filename, NULL, NULL,
                                    &elf_entry, &elf_lowaddr, NULL, 1,
                                    ELF_MACHINE, 0);
             entry = elf_entry;
@@ -752,7 +752,7 @@ void ppce500_init(QEMUMachineInitArgs *args, PPCE500Params *params)
         /* XXX try again as binary */
         if (kernel_size < 0) {
             fprintf(stderr, "qemu: could not load kernel '%s'\n",
-                    args->kernel_filename);
+                    machine->kernel_filename);
             exit(1);
         }
 
@@ -764,14 +764,14 @@ void ppce500_init(QEMUMachineInitArgs *args, PPCE500Params *params)
     }
 
     /* Load initrd. */
-    if (args->initrd_filename) {
+    if (machine->initrd_filename) {
         initrd_base = (cur_base + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK;
-        initrd_size = load_image_targphys(args->initrd_filename, initrd_base,
+        initrd_size = load_image_targphys(machine->initrd_filename, initrd_base,
                                           ram_size - initrd_base);
 
         if (initrd_size < 0) {
             fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
-                    args->initrd_filename);
+                    machine->initrd_filename);
             exit(1);
         }
 
@@ -779,11 +779,11 @@ void ppce500_init(QEMUMachineInitArgs *args, PPCE500Params *params)
     }
 
     /* If we're loading a kernel directly, we must load the device tree too. */
-    if (args->kernel_filename) {
+    if (machine->kernel_filename) {
         struct boot_info *boot_info;
         int dt_size;
 
-        dt_size = ppce500_prep_device_tree(args, params, dt_base,
+        dt_size = ppce500_prep_device_tree(machine, params, dt_base,
                                            initrd_base, initrd_size);
         if (dt_size < 0) {
             fprintf(stderr, "couldn't load device tree\n");
diff --git a/hw/ppc/e500.h b/hw/ppc/e500.h
index 52726a2ec0..08b25fab49 100644
--- a/hw/ppc/e500.h
+++ b/hw/ppc/e500.h
@@ -13,6 +13,6 @@ typedef struct PPCE500Params {
     int mpic_version;
 } PPCE500Params;
 
-void ppce500_init(QEMUMachineInitArgs *args, PPCE500Params *params);
+void ppce500_init(MachineState *machine, PPCE500Params *params);
 
 #endif
diff --git a/hw/ppc/e500plat.c b/hw/ppc/e500plat.c
index 7d5357e83b..27df31ddb0 100644
--- a/hw/ppc/e500plat.c
+++ b/hw/ppc/e500plat.c
@@ -28,7 +28,7 @@ static void e500plat_fixup_devtree(PPCE500Params *params, void *fdt)
                      sizeof(compatible));
 }
 
-static void e500plat_init(QEMUMachineInitArgs *args)
+static void e500plat_init(MachineState *machine)
 {
     PPCE500Params params = {
         .pci_first_slot = 0x1,
@@ -43,7 +43,7 @@ static void e500plat_init(QEMUMachineInitArgs *args)
         params.mpic_version = OPENPIC_MODEL_FSL_MPIC_20;
     }
 
-    ppce500_init(args, &params);
+    ppce500_init(machine, &params);
 }
 
 static QEMUMachine e500plat_machine = {
diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c
index 5e79575165..4bdaa8d398 100644
--- a/hw/ppc/mac_newworld.c
+++ b/hw/ppc/mac_newworld.c
@@ -140,14 +140,14 @@ static void ppc_core99_reset(void *opaque)
 }
 
 /* PowerPC Mac99 hardware initialisation */
-static void ppc_core99_init(QEMUMachineInitArgs *args)
+static void ppc_core99_init(MachineState *machine)
 {
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
-    const char *boot_device = args->boot_order;
+    ram_addr_t ram_size = machine->ram_size;
+    const char *cpu_model = machine->cpu_model;
+    const char *kernel_filename = machine->kernel_filename;
+    const char *kernel_cmdline = machine->kernel_cmdline;
+    const char *initrd_filename = machine->initrd_filename;
+    const char *boot_device = machine->boot_order;
     PowerPCCPU *cpu = NULL;
     CPUPPCState *env = NULL;
     char *filename;
diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c
index 2f27754c6c..77598e44cc 100644
--- a/hw/ppc/mac_oldworld.c
+++ b/hw/ppc/mac_oldworld.c
@@ -71,14 +71,14 @@ static void ppc_heathrow_reset(void *opaque)
     cpu_reset(CPU(cpu));
 }
 
-static void ppc_heathrow_init(QEMUMachineInitArgs *args)
+static void ppc_heathrow_init(MachineState *machine)
 {
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
-    const char *boot_device = args->boot_order;
+    ram_addr_t ram_size = machine->ram_size;
+    const char *cpu_model = machine->cpu_model;
+    const char *kernel_filename = machine->kernel_filename;
+    const char *kernel_cmdline = machine->kernel_cmdline;
+    const char *initrd_filename = machine->initrd_filename;
+    const char *boot_device = machine->boot_order;
     MemoryRegion *sysmem = get_system_memory();
     PowerPCCPU *cpu = NULL;
     CPUPPCState *env = NULL;
diff --git a/hw/ppc/mpc8544ds.c b/hw/ppc/mpc8544ds.c
index 292c70953b..b99f74af75 100644
--- a/hw/ppc/mpc8544ds.c
+++ b/hw/ppc/mpc8544ds.c
@@ -26,7 +26,7 @@ static void mpc8544ds_fixup_devtree(PPCE500Params *params, void *fdt)
                      sizeof(compatible));
 }
 
-static void mpc8544ds_init(QEMUMachineInitArgs *args)
+static void mpc8544ds_init(MachineState *machine)
 {
     PPCE500Params params = {
         .pci_first_slot = 0x11,
@@ -35,7 +35,7 @@ static void mpc8544ds_init(QEMUMachineInitArgs *args)
         .mpic_version = OPENPIC_MODEL_FSL_MPIC_20,
     };
 
-    ppce500_init(args, &params);
+    ppce500_init(machine, &params);
 }
 
 
diff --git a/hw/ppc/ppc405_boards.c b/hw/ppc/ppc405_boards.c
index f1a8f6734a..98ad2d75e7 100644
--- a/hw/ppc/ppc405_boards.c
+++ b/hw/ppc/ppc405_boards.c
@@ -172,12 +172,12 @@ static void ref405ep_fpga_init(MemoryRegion *sysmem, uint32_t base)
     qemu_register_reset(&ref405ep_fpga_reset, fpga);
 }
 
-static void ref405ep_init(QEMUMachineInitArgs *args)
+static void ref405ep_init(MachineState *machine)
 {
-    ram_addr_t ram_size = args->ram_size;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
+    ram_addr_t ram_size = machine->ram_size;
+    const char *kernel_filename = machine->kernel_filename;
+    const char *kernel_cmdline = machine->kernel_cmdline;
+    const char *initrd_filename = machine->initrd_filename;
     char *filename;
     ppc4xx_bd_info_t bd;
     CPUPPCState *env;
@@ -499,11 +499,11 @@ static void taihu_cpld_init(MemoryRegion *sysmem, uint32_t base)
     qemu_register_reset(&taihu_cpld_reset, cpld);
 }
 
-static void taihu_405ep_init(QEMUMachineInitArgs *args)
+static void taihu_405ep_init(MachineState *machine)
 {
-    ram_addr_t ram_size = args->ram_size;
-    const char *kernel_filename = args->kernel_filename;
-    const char *initrd_filename = args->initrd_filename;
+    ram_addr_t ram_size = machine->ram_size;
+    const char *kernel_filename = machine->kernel_filename;
+    const char *initrd_filename = machine->initrd_filename;
     char *filename;
     qemu_irq *pic;
     MemoryRegion *sysmem = get_system_memory();
diff --git a/hw/ppc/ppc440_bamboo.c b/hw/ppc/ppc440_bamboo.c
index 2ddc2ed4b9..81a06d310d 100644
--- a/hw/ppc/ppc440_bamboo.c
+++ b/hw/ppc/ppc440_bamboo.c
@@ -156,13 +156,13 @@ static void main_cpu_reset(void *opaque)
     mmubooke_create_initial_mapping(env, 0, 0);
 }
 
-static void bamboo_init(QEMUMachineInitArgs *args)
+static void bamboo_init(MachineState *machine)
 {
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
+    ram_addr_t ram_size = machine->ram_size;
+    const char *cpu_model = machine->cpu_model;
+    const char *kernel_filename = machine->kernel_filename;
+    const char *kernel_cmdline = machine->kernel_cmdline;
+    const char *initrd_filename = machine->initrd_filename;
     unsigned int pci_irq_nrs[4] = { 28, 27, 26, 25 };
     MemoryRegion *address_space_mem = get_system_memory();
     MemoryRegion *isa = g_new(MemoryRegion, 1);
diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c
index 585937321f..2383254f49 100644
--- a/hw/ppc/prep.c
+++ b/hw/ppc/prep.c
@@ -364,14 +364,14 @@ static const MemoryRegionPortio prep_portio_list[] = {
 static PortioList prep_port_list;
 
 /* PowerPC PREP hardware initialisation */
-static void ppc_prep_init(QEMUMachineInitArgs *args)
+static void ppc_prep_init(MachineState *machine)
 {
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
-    const char *boot_device = args->boot_order;
+    ram_addr_t ram_size = machine->ram_size;
+    const char *cpu_model = machine->cpu_model;
+    const char *kernel_filename = machine->kernel_filename;
+    const char *kernel_cmdline = machine->kernel_cmdline;
+    const char *initrd_filename = machine->initrd_filename;
+    const char *boot_device = machine->boot_order;
     MemoryRegion *sysmem = get_system_memory();
     PowerPCCPU *cpu = NULL;
     CPUPPCState *env = NULL;
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index b4ce950bbd..57e95780c8 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -1140,14 +1140,14 @@ static SaveVMHandlers savevm_htab_handlers = {
 };
 
 /* pSeries LPAR / sPAPR hardware init */
-static void ppc_spapr_init(QEMUMachineInitArgs *args)
+static void ppc_spapr_init(MachineState *machine)
 {
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
-    const char *boot_device = args->boot_order;
+    ram_addr_t ram_size = machine->ram_size;
+    const char *cpu_model = machine->cpu_model;
+    const char *kernel_filename = machine->kernel_filename;
+    const char *kernel_cmdline = machine->kernel_cmdline;
+    const char *initrd_filename = machine->initrd_filename;
+    const char *boot_device = machine->boot_order;
     PowerPCCPU *cpu;
     CPUPPCState *env;
     PCIHostState *phb;
diff --git a/hw/ppc/virtex_ml507.c b/hw/ppc/virtex_ml507.c
index 3e3569d4b8..02b4f828d3 100644
--- a/hw/ppc/virtex_ml507.c
+++ b/hw/ppc/virtex_ml507.c
@@ -194,12 +194,12 @@ static int xilinx_load_device_tree(hwaddr addr,
     return fdt_size;
 }
 
-static void virtex_init(QEMUMachineInitArgs *args)
+static void virtex_init(MachineState *machine)
 {
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
+    ram_addr_t ram_size = machine->ram_size;
+    const char *cpu_model = machine->cpu_model;
+    const char *kernel_filename = machine->kernel_filename;
+    const char *kernel_cmdline = machine->kernel_cmdline;
     hwaddr initrd_base = 0;
     int initrd_size = 0;
     MemoryRegion *address_space_mem = get_system_memory();
@@ -275,14 +275,14 @@ static void virtex_init(QEMUMachineInitArgs *args)
         boot_info.ima_size = kernel_size;
 
         /* Load initrd. */
-        if (args->initrd_filename) {
+        if (machine->initrd_filename) {
             initrd_base = high = ROUND_UP(high, 4);
-            initrd_size = load_image_targphys(args->initrd_filename,
+            initrd_size = load_image_targphys(machine->initrd_filename,
                                               high, ram_size - high);
 
             if (initrd_size < 0) {
                 error_report("couldn't load ram disk '%s'",
-                             args->initrd_filename);
+                             machine->initrd_filename);
                 exit(1);
             }
             high = ROUND_UP(high + initrd_size, 4);
diff --git a/hw/s390x/css.c b/hw/s390x/css.c
index 122cc7e66f..2678e4432c 100644
--- a/hw/s390x/css.c
+++ b/hw/s390x/css.c
@@ -16,6 +16,7 @@
 #include "ioinst.h"
 #include "css.h"
 #include "trace.h"
+#include "hw/s390x/s390_flic.h"
 
 typedef struct CrwContainer {
     CRW crw;
@@ -39,6 +40,13 @@ typedef struct CssImage {
     ChpInfo chpids[MAX_CHPID + 1];
 } CssImage;
 
+typedef struct IoAdapter {
+    uint32_t id;
+    uint8_t type;
+    uint8_t isc;
+    QTAILQ_ENTRY(IoAdapter) sibling;
+} IoAdapter;
+
 typedef struct ChannelSubSys {
     QTAILQ_HEAD(, CrwContainer) pending_crws;
     bool do_crw_mchk;
@@ -49,6 +57,7 @@ typedef struct ChannelSubSys {
     uint64_t chnmon_area;
     CssImage *css[MAX_CSSID + 1];
     uint8_t default_cssid;
+    QTAILQ_HEAD(, IoAdapter) io_adapters;
 } ChannelSubSys;
 
 static ChannelSubSys *channel_subsys;
@@ -69,6 +78,46 @@ int css_create_css_image(uint8_t cssid, bool default_image)
     return 0;
 }
 
+int css_register_io_adapter(uint8_t type, uint8_t isc, bool swap,
+                            bool maskable, uint32_t *id)
+{
+    IoAdapter *adapter;
+    bool found = false;
+    int ret;
+    S390FLICState *fs = s390_get_flic();
+    S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs);
+
+    *id = 0;
+    QTAILQ_FOREACH(adapter, &channel_subsys->io_adapters, sibling) {
+        if ((adapter->type == type) && (adapter->isc == isc)) {
+            *id = adapter->id;
+            found = true;
+            ret = 0;
+            break;
+        }
+        if (adapter->id >= *id) {
+            *id = adapter->id + 1;
+        }
+    }
+    if (found) {
+        goto out;
+    }
+    adapter = g_new0(IoAdapter, 1);
+    ret = fsc->register_io_adapter(fs, *id, isc, swap, maskable);
+    if (ret == 0) {
+        adapter->id = *id;
+        adapter->isc = isc;
+        adapter->type = type;
+        QTAILQ_INSERT_TAIL(&channel_subsys->io_adapters, adapter, sibling);
+    } else {
+        g_free(adapter);
+        fprintf(stderr, "Unexpected error %d when registering adapter %d\n",
+                ret, *id);
+    }
+out:
+    return ret;
+}
+
 uint16_t css_build_subchannel_id(SubchDev *sch)
 {
     if (channel_subsys->max_cssid > 0) {
@@ -1235,6 +1284,7 @@ static void css_init(void)
     channel_subsys->do_crw_mchk = true;
     channel_subsys->crws_lost = false;
     channel_subsys->chnmon_active = false;
+    QTAILQ_INIT(&channel_subsys->io_adapters);
 }
 machine_init(css_init);
 
diff --git a/hw/s390x/css.h b/hw/s390x/css.h
index 220169e7c3..6586106fa7 100644
--- a/hw/s390x/css.h
+++ b/hw/s390x/css.h
@@ -98,4 +98,8 @@ void css_generate_sch_crws(uint8_t cssid, uint8_t ssid, uint16_t schid,
                            int hotplugged, int add);
 void css_generate_chp_crws(uint8_t cssid, uint8_t chpid);
 void css_adapter_interrupt(uint8_t isc);
+
+#define CSS_IO_ADAPTER_VIRTIO 1
+int css_register_io_adapter(uint8_t type, uint8_t isc, bool swap,
+                            bool maskable, uint32_t *id);
 #endif
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index 0d4f6ae2f3..42f5cec4c1 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -79,9 +79,9 @@ static void virtio_ccw_register_hcalls(void)
                                    virtio_ccw_hcall_early_printk);
 }
 
-static void ccw_init(QEMUMachineInitArgs *args)
+static void ccw_init(MachineState *machine)
 {
-    ram_addr_t my_ram_size = args->ram_size;
+    ram_addr_t my_ram_size = machine->ram_size;
     MemoryRegion *sysmem = get_system_memory();
     MemoryRegion *ram = g_new(MemoryRegion, 1);
     int shift = 0;
@@ -102,8 +102,8 @@ static void ccw_init(QEMUMachineInitArgs *args)
     /* get a BUS */
     css_bus = virtual_css_bus_init();
     s390_sclp_init();
-    s390_init_ipl_dev(args->kernel_filename, args->kernel_cmdline,
-                      args->initrd_filename, "s390-ccw.img");
+    s390_init_ipl_dev(machine->kernel_filename, machine->kernel_cmdline,
+                      machine->initrd_filename, "s390-ccw.img");
     s390_flic_init();
 
     /* register hypercalls */
@@ -118,7 +118,7 @@ static void ccw_init(QEMUMachineInitArgs *args)
     storage_keys = g_malloc0(my_ram_size / TARGET_PAGE_SIZE);
 
     /* init CPUs */
-    s390_init_cpus(args->cpu_model, storage_keys);
+    s390_init_cpus(machine->cpu_model, storage_keys);
 
     if (kvm_enabled()) {
         kvm_s390_enable_css_support(s390_cpu_addr2state(0));
diff --git a/hw/s390x/s390-virtio.c b/hw/s390x/s390-virtio.c
index aef200310c..93c7acea72 100644
--- a/hw/s390x/s390-virtio.c
+++ b/hw/s390x/s390-virtio.c
@@ -224,9 +224,9 @@ void s390_create_virtio_net(BusState *bus, const char *name)
 }
 
 /* PC hardware initialisation */
-static void s390_init(QEMUMachineInitArgs *args)
+static void s390_init(MachineState *machine)
 {
-    ram_addr_t my_ram_size = args->ram_size;
+    ram_addr_t my_ram_size = machine->ram_size;
     MemoryRegion *sysmem = get_system_memory();
     MemoryRegion *ram = g_new(MemoryRegion, 1);
     int shift = 0;
@@ -248,8 +248,8 @@ static void s390_init(QEMUMachineInitArgs *args)
     /* get a BUS */
     s390_bus = s390_virtio_bus_init(&my_ram_size);
     s390_sclp_init();
-    s390_init_ipl_dev(args->kernel_filename, args->kernel_cmdline,
-                      args->initrd_filename, ZIPL_FILENAME);
+    s390_init_ipl_dev(machine->kernel_filename, machine->kernel_cmdline,
+                      machine->initrd_filename, ZIPL_FILENAME);
     s390_flic_init();
 
     /* register hypercalls */
@@ -273,7 +273,7 @@ static void s390_init(QEMUMachineInitArgs *args)
     storage_keys = g_malloc0(my_ram_size / TARGET_PAGE_SIZE);
 
     /* init CPUs */
-    s390_init_cpus(args->cpu_model, storage_keys);
+    s390_init_cpus(machine->cpu_model, storage_keys);
 
     /* Create VirtIO network adapters */
     s390_create_virtio_net((BusState *)s390_bus, "virtio-net-s390");
diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c
index 1cb4e2c2f8..c4f21d3816 100644
--- a/hw/s390x/virtio-ccw.c
+++ b/hw/s390x/virtio-ccw.c
@@ -21,12 +21,77 @@
 #include "hw/sysbus.h"
 #include "qemu/bitops.h"
 #include "hw/virtio/virtio-bus.h"
+#include "hw/s390x/adapter.h"
+#include "hw/s390x/s390_flic.h"
 
 #include "ioinst.h"
 #include "css.h"
 #include "virtio-ccw.h"
 #include "trace.h"
 
+static QTAILQ_HEAD(, IndAddr) indicator_addresses =
+    QTAILQ_HEAD_INITIALIZER(indicator_addresses);
+
+static IndAddr *get_indicator(hwaddr ind_addr, int len)
+{
+    IndAddr *indicator;
+
+    QTAILQ_FOREACH(indicator, &indicator_addresses, sibling) {
+        if (indicator->addr == ind_addr) {
+            indicator->refcnt++;
+            return indicator;
+        }
+    }
+    indicator = g_new0(IndAddr, 1);
+    indicator->addr = ind_addr;
+    indicator->len = len;
+    indicator->refcnt = 1;
+    QTAILQ_INSERT_TAIL(&indicator_addresses, indicator, sibling);
+    return indicator;
+}
+
+static int s390_io_adapter_map(AdapterInfo *adapter, uint64_t map_addr,
+                               bool do_map)
+{
+    S390FLICState *fs = s390_get_flic();
+    S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs);
+
+    return fsc->io_adapter_map(fs, adapter->adapter_id, map_addr, do_map);
+}
+
+static void release_indicator(AdapterInfo *adapter, IndAddr *indicator)
+{
+    assert(indicator->refcnt > 0);
+    indicator->refcnt--;
+    if (indicator->refcnt > 0) {
+        return;
+    }
+    QTAILQ_REMOVE(&indicator_addresses, indicator, sibling);
+    if (indicator->map) {
+        s390_io_adapter_map(adapter, indicator->map, false);
+    }
+    g_free(indicator);
+}
+
+static int map_indicator(AdapterInfo *adapter, IndAddr *indicator)
+{
+    int ret;
+
+    if (indicator->map) {
+        return 0; /* already mapped is not an error */
+    }
+    indicator->map = indicator->addr;
+    ret = s390_io_adapter_map(adapter, indicator->map, true);
+    if ((ret != 0) && (ret != -ENOSYS)) {
+        goto out_err;
+    }
+    return 0;
+
+out_err:
+    indicator->map = 0;
+    return ret;
+}
+
 static void virtio_ccw_bus_new(VirtioBusState *bus, size_t bus_size,
                                VirtioCcwDevice *dev);
 
@@ -445,7 +510,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
             ret = -EFAULT;
         } else {
             indicators = ldq_phys(&address_space_memory, ccw.cda);
-            dev->indicators = indicators;
+            dev->indicators = get_indicator(indicators, sizeof(uint64_t));
             sch->curr_status.scsw.count = ccw.count - sizeof(indicators);
             ret = 0;
         }
@@ -465,7 +530,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
             ret = -EFAULT;
         } else {
             indicators = ldq_phys(&address_space_memory, ccw.cda);
-            dev->indicators2 = indicators;
+            dev->indicators2 = get_indicator(indicators, sizeof(uint64_t));
             sch->curr_status.scsw.count = ccw.count - sizeof(indicators);
             ret = 0;
         }
@@ -517,13 +582,20 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
                 ret = -EFAULT;
             } else {
                 len = hw_len;
-                dev->summary_indicator = thinint->summary_indicator;
-                dev->indicators = thinint->device_indicator;
+                dev->summary_indicator =
+                    get_indicator(thinint->summary_indicator, sizeof(uint8_t));
+                dev->indicators = get_indicator(thinint->device_indicator,
+                                                thinint->ind_bit / 8 + 1);
                 dev->thinint_isc = thinint->isc;
-                dev->ind_bit = thinint->ind_bit;
+                dev->routes.adapter.ind_offset = thinint->ind_bit;
+                dev->routes.adapter.summary_offset = 7;
                 cpu_physical_memory_unmap(thinint, hw_len, 0, hw_len);
-                sch->thinint_active = ((dev->indicators != 0) &&
-                                       (dev->summary_indicator != 0));
+                ret = css_register_io_adapter(CSS_IO_ADAPTER_VIRTIO,
+                                              dev->thinint_isc, true, false,
+                                              &dev->routes.adapter.adapter_id);
+                assert(ret == 0);
+                sch->thinint_active = ((dev->indicators != NULL) &&
+                                       (dev->summary_indicator != NULL));
                 sch->curr_status.scsw.count = ccw.count - len;
                 ret = 0;
             }
@@ -554,7 +626,7 @@ static int virtio_ccw_device_init(VirtioCcwDevice *dev, VirtIODevice *vdev)
     sch->driver_data = dev;
     dev->sch = sch;
 
-    dev->indicators = 0;
+    dev->indicators = NULL;
 
     /* Initialize subchannel structure. */
     sch->channel_prog = 0x0;
@@ -693,7 +765,10 @@ static int virtio_ccw_exit(VirtioCcwDevice *dev)
         css_subch_assign(sch->cssid, sch->ssid, sch->schid, sch->devno, NULL);
         g_free(sch);
     }
-    dev->indicators = 0;
+    if (dev->indicators) {
+        release_indicator(&dev->routes.adapter, dev->indicators);
+        dev->indicators = NULL;
+    }
     return 0;
 }
 
@@ -950,17 +1025,19 @@ static void virtio_ccw_notify(DeviceState *d, uint16_t vector)
              * ind_bit indicates the start of the indicators in a big
              * endian notation.
              */
-            virtio_set_ind_atomic(sch, dev->indicators +
-                                  (dev->ind_bit + vector) / 8,
-                                  0x80 >> ((dev->ind_bit + vector) % 8));
-            if (!virtio_set_ind_atomic(sch, dev->summary_indicator,
+            uint64_t ind_bit = dev->routes.adapter.ind_offset;
+
+            virtio_set_ind_atomic(sch, dev->indicators->addr +
+                                  (ind_bit + vector) / 8,
+                                  0x80 >> ((ind_bit + vector) % 8));
+            if (!virtio_set_ind_atomic(sch, dev->summary_indicator->addr,
                                        0x01)) {
                 css_adapter_interrupt(dev->thinint_isc);
             }
         } else {
-            indicators = ldq_phys(&address_space_memory, dev->indicators);
+            indicators = ldq_phys(&address_space_memory, dev->indicators->addr);
             indicators |= 1ULL << vector;
-            stq_phys(&address_space_memory, dev->indicators, indicators);
+            stq_phys(&address_space_memory, dev->indicators->addr, indicators);
             css_conditional_io_interrupt(sch);
         }
     } else {
@@ -968,9 +1045,9 @@ static void virtio_ccw_notify(DeviceState *d, uint16_t vector)
             return;
         }
         vector = 0;
-        indicators = ldq_phys(&address_space_memory, dev->indicators2);
+        indicators = ldq_phys(&address_space_memory, dev->indicators2->addr);
         indicators |= 1ULL << vector;
-        stq_phys(&address_space_memory, dev->indicators2, indicators);
+        stq_phys(&address_space_memory, dev->indicators2->addr, indicators);
         css_conditional_io_interrupt(sch);
     }
 }
@@ -991,9 +1068,18 @@ static void virtio_ccw_reset(DeviceState *d)
     virtio_ccw_stop_ioeventfd(dev);
     virtio_reset(vdev);
     css_reset_sch(dev->sch);
-    dev->indicators = 0;
-    dev->indicators2 = 0;
-    dev->summary_indicator = 0;
+    if (dev->indicators) {
+        release_indicator(&dev->routes.adapter, dev->indicators);
+        dev->indicators = NULL;
+    }
+    if (dev->indicators2) {
+        release_indicator(&dev->routes.adapter, dev->indicators2);
+        dev->indicators2 = NULL;
+    }
+    if (dev->summary_indicator) {
+        release_indicator(&dev->routes.adapter, dev->summary_indicator);
+        dev->summary_indicator = NULL;
+    }
 }
 
 static void virtio_ccw_vmstate_change(DeviceState *d, bool running)
@@ -1027,6 +1113,79 @@ static int virtio_ccw_set_host_notifier(DeviceState *d, int n, bool assign)
     return virtio_ccw_set_guest2host_notifier(dev, n, assign, false);
 }
 
+static int virtio_ccw_get_mappings(VirtioCcwDevice *dev)
+{
+    int r;
+
+    if (!dev->sch->thinint_active) {
+        return -EINVAL;
+    }
+
+    r = map_indicator(&dev->routes.adapter, dev->summary_indicator);
+    if (r) {
+        return r;
+    }
+    r = map_indicator(&dev->routes.adapter, dev->indicators);
+    if (r) {
+        return r;
+    }
+    dev->routes.adapter.summary_addr = dev->summary_indicator->map;
+    dev->routes.adapter.ind_addr = dev->indicators->map;
+
+    return 0;
+}
+
+static int virtio_ccw_setup_irqroutes(VirtioCcwDevice *dev, int nvqs)
+{
+    int i;
+    VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
+    int ret;
+    S390FLICState *fs = s390_get_flic();
+    S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs);
+
+    ret = virtio_ccw_get_mappings(dev);
+    if (ret) {
+        return ret;
+    }
+    for (i = 0; i < nvqs; i++) {
+        if (!virtio_queue_get_num(vdev, i)) {
+            break;
+        }
+    }
+    dev->routes.num_routes = i;
+    return fsc->add_adapter_routes(fs, &dev->routes);
+}
+
+static void virtio_ccw_release_irqroutes(VirtioCcwDevice *dev, int nvqs)
+{
+    S390FLICState *fs = s390_get_flic();
+    S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs);
+
+    fsc->release_adapter_routes(fs, &dev->routes);
+}
+
+static int virtio_ccw_add_irqfd(VirtioCcwDevice *dev, int n)
+{
+    VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
+    VirtQueue *vq = virtio_get_queue(vdev, n);
+    EventNotifier *notifier = virtio_queue_get_guest_notifier(vq);
+
+    return kvm_irqchip_add_irqfd_notifier(kvm_state, notifier, NULL,
+                                          dev->routes.gsi[n]);
+}
+
+static void virtio_ccw_remove_irqfd(VirtioCcwDevice *dev, int n)
+{
+    VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
+    VirtQueue *vq = virtio_get_queue(vdev, n);
+    EventNotifier *notifier = virtio_queue_get_guest_notifier(vq);
+    int ret;
+
+    ret = kvm_irqchip_remove_irqfd_notifier(kvm_state, notifier,
+                                            dev->routes.gsi[n]);
+    assert(ret == 0);
+}
+
 static int virtio_ccw_set_guest_notifier(VirtioCcwDevice *dev, int n,
                                          bool assign, bool with_irqfd)
 {
@@ -1042,11 +1201,17 @@ static int virtio_ccw_set_guest_notifier(VirtioCcwDevice *dev, int n,
             return r;
         }
         virtio_queue_set_guest_notifier_fd_handler(vq, true, with_irqfd);
-        /* We do not support irqfd for classic I/O interrupts, because the
-         * classic interrupts are intermixed with the subchannel status, that
-         * is queried with test subchannel. We want to use vhost, though.
-         * Lets make sure to have vhost running and wire up the irq fd to
-         * land in qemu (and only the irq fd) in this code.
+        if (with_irqfd) {
+            r = virtio_ccw_add_irqfd(dev, n);
+            if (r) {
+                virtio_queue_set_guest_notifier_fd_handler(vq, false,
+                                                           with_irqfd);
+                return r;
+            }
+        }
+        /*
+         * We do not support individual masking for channel devices, so we
+         * need to manually trigger any guest masking callbacks here.
          */
         if (k->guest_notifier_mask) {
             k->guest_notifier_mask(vdev, n, false);
@@ -1060,6 +1225,9 @@ static int virtio_ccw_set_guest_notifier(VirtioCcwDevice *dev, int n,
         if (k->guest_notifier_mask) {
             k->guest_notifier_mask(vdev, n, true);
         }
+        if (with_irqfd) {
+            virtio_ccw_remove_irqfd(dev, n);
+        }
         virtio_queue_set_guest_notifier_fd_handler(vq, false, with_irqfd);
         event_notifier_cleanup(notifier);
     }
@@ -1071,24 +1239,39 @@ static int virtio_ccw_set_guest_notifiers(DeviceState *d, int nvqs,
 {
     VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
     VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
+    bool with_irqfd = dev->sch->thinint_active && kvm_irqfds_enabled();
     int r, n;
 
+    if (with_irqfd && assigned) {
+        /* irq routes need to be set up before assigning irqfds */
+        r = virtio_ccw_setup_irqroutes(dev, nvqs);
+        if (r < 0) {
+            goto irqroute_error;
+        }
+    }
     for (n = 0; n < nvqs; n++) {
         if (!virtio_queue_get_num(vdev, n)) {
             break;
         }
-        /* false -> true, as soon as irqfd works */
-        r = virtio_ccw_set_guest_notifier(dev, n, assigned, false);
+        r = virtio_ccw_set_guest_notifier(dev, n, assigned, with_irqfd);
         if (r < 0) {
             goto assign_error;
         }
     }
+    if (with_irqfd && !assigned) {
+        /* release irq routes after irqfds have been released */
+        virtio_ccw_release_irqroutes(dev, nvqs);
+    }
     return 0;
 
 assign_error:
     while (--n >= 0) {
         virtio_ccw_set_guest_notifier(dev, n, !assigned, false);
     }
+irqroute_error:
+    if (with_irqfd && assigned) {
+        virtio_ccw_release_irqroutes(dev, nvqs);
+    }
     return r;
 }
 
diff --git a/hw/s390x/virtio-ccw.h b/hw/s390x/virtio-ccw.h
index 4393e44814..b8b8a8abaa 100644
--- a/hw/s390x/virtio-ccw.h
+++ b/hw/s390x/virtio-ccw.h
@@ -22,6 +22,7 @@
 #include <hw/virtio/virtio-balloon.h>
 #include <hw/virtio/virtio-rng.h>
 #include <hw/virtio/virtio-bus.h>
+#include <hw/s390x/s390_flic.h>
 
 #define VIRTUAL_CSSID 0xfe
 
@@ -75,6 +76,14 @@ typedef struct VirtIOCCWDeviceClass {
 #define VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT 1
 #define VIRTIO_CCW_FLAG_USE_IOEVENTFD   (1 << VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT)
 
+typedef struct IndAddr {
+    hwaddr addr;
+    uint64_t map;
+    unsigned long refcnt;
+    int len;
+    QTAILQ_ENTRY(IndAddr) sibling;
+} IndAddr;
+
 struct VirtioCcwDevice {
     DeviceState parent_obj;
     SubchDev *sch;
@@ -85,10 +94,11 @@ struct VirtioCcwDevice {
     bool ioeventfd_disabled;
     uint32_t flags;
     uint8_t thinint_isc;
+    AdapterRoutes routes;
     /* Guest provided values: */
-    hwaddr indicators;
-    hwaddr indicators2;
-    hwaddr summary_indicator;
+    IndAddr *indicators;
+    IndAddr *indicators2;
+    IndAddr *summary_indicator;
     uint64_t ind_bit;
 };
 
diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c
index e6e1ffd1bb..0e109a2844 100644
--- a/hw/scsi/megasas.c
+++ b/hw/scsi/megasas.c
@@ -21,6 +21,7 @@
 #include "hw/hw.h"
 #include "hw/pci/pci.h"
 #include "sysemu/dma.h"
+#include "hw/pci/msi.h"
 #include "hw/pci/msix.h"
 #include "qemu/iov.h"
 #include "hw/scsi/scsi.h"
@@ -43,9 +44,11 @@
 
 #define MEGASAS_FLAG_USE_JBOD      0
 #define MEGASAS_MASK_USE_JBOD      (1 << MEGASAS_FLAG_USE_JBOD)
-#define MEGASAS_FLAG_USE_MSIX      1
+#define MEGASAS_FLAG_USE_MSI       1
+#define MEGASAS_MASK_USE_MSI       (1 << MEGASAS_FLAG_USE_MSI)
+#define MEGASAS_FLAG_USE_MSIX      2
 #define MEGASAS_MASK_USE_MSIX      (1 << MEGASAS_FLAG_USE_MSIX)
-#define MEGASAS_FLAG_USE_QUEUE64   2
+#define MEGASAS_FLAG_USE_QUEUE64   3
 #define MEGASAS_MASK_USE_QUEUE64   (1 << MEGASAS_FLAG_USE_QUEUE64)
 
 static const char *mfi_frame_desc[] = {
@@ -132,6 +135,11 @@ static bool megasas_use_queue64(MegasasState *s)
     return s->flags & MEGASAS_MASK_USE_QUEUE64;
 }
 
+static bool megasas_use_msi(MegasasState *s)
+{
+    return s->flags & MEGASAS_MASK_USE_MSI;
+}
+
 static bool megasas_use_msix(MegasasState *s)
 {
     return s->flags & MEGASAS_MASK_USE_MSIX;
@@ -538,6 +546,9 @@ static void megasas_complete_frame(MegasasState *s, uint64_t context)
             if (msix_enabled(pci_dev)) {
                 trace_megasas_msix_raise(0);
                 msix_notify(pci_dev, 0);
+            } else if (msi_enabled(pci_dev)) {
+                trace_megasas_msi_raise(0);
+                msi_notify(pci_dev, 0);
             } else {
                 trace_megasas_irq_raise();
                 pci_irq_assert(pci_dev);
@@ -717,8 +728,8 @@ static int megasas_ctrl_get_info(MegasasState *s, MegasasCmd *cmd)
     snprintf(info.package_version, 0x60, "%s-QEMU", QEMU_VERSION);
     memcpy(info.image_component[0].name, "APP", 3);
     memcpy(info.image_component[0].version, MEGASAS_VERSION "-QEMU", 9);
-    memcpy(info.image_component[0].build_date, __DATE__, 11);
-    memcpy(info.image_component[0].build_time, __TIME__, 8);
+    memcpy(info.image_component[0].build_date, "Apr  1 2014", 11);
+    memcpy(info.image_component[0].build_time, "12:34:56", 8);
     info.image_component_count = 1;
     if (pci_dev->has_rom) {
         uint8_t biosver[32];
@@ -1106,6 +1117,21 @@ static int megasas_dcmd_ld_get_list(MegasasState *s, MegasasCmd *cmd)
     return MFI_STAT_OK;
 }
 
+static int megasas_dcmd_ld_list_query(MegasasState *s, MegasasCmd *cmd)
+{
+    uint16_t flags;
+
+    /* mbox0 contains flags */
+    flags = le16_to_cpu(cmd->frame->dcmd.mbox[0]);
+    trace_megasas_dcmd_ld_list_query(cmd->index, flags);
+    if (flags == MR_LD_QUERY_TYPE_ALL ||
+        flags == MR_LD_QUERY_TYPE_EXPOSED_TO_HOST) {
+        return megasas_dcmd_ld_get_list(s, cmd);
+    }
+
+    return MFI_STAT_OK;
+}
+
 static int megasas_ld_get_info_submit(SCSIDevice *sdev, int lun,
                                       MegasasCmd *cmd)
 {
@@ -1409,6 +1435,8 @@ static const struct dcmd_cmd_tbl_t {
       megasas_dcmd_dummy },
     { MFI_DCMD_LD_GET_LIST, "LD_GET_LIST",
       megasas_dcmd_ld_get_list},
+    { MFI_DCMD_LD_LIST_QUERY, "LD_LIST_QUERY",
+      megasas_dcmd_ld_list_query },
     { MFI_DCMD_LD_GET_INFO, "LD_GET_INFO",
       megasas_dcmd_ld_get_info },
     { MFI_DCMD_LD_GET_PROP, "LD_GET_PROP",
@@ -1939,12 +1967,20 @@ static void megasas_mmio_write(void *opaque, hwaddr addr,
         break;
     case MFI_OMSK:
         s->intr_mask = val;
-        if (!megasas_intr_enabled(s) && !msix_enabled(pci_dev)) {
+        if (!megasas_intr_enabled(s) &&
+            !msi_enabled(pci_dev) &&
+            !msix_enabled(pci_dev)) {
             trace_megasas_irq_lower();
             pci_irq_deassert(pci_dev);
         }
         if (megasas_intr_enabled(s)) {
-            trace_megasas_intr_enabled();
+            if (msix_enabled(pci_dev)) {
+                trace_megasas_msix_enabled(0);
+            } else if (msi_enabled(pci_dev)) {
+                trace_megasas_msi_enabled(0);
+            } else {
+                trace_megasas_intr_enabled();
+            }
         } else {
             trace_megasas_intr_disabled();
         }
@@ -2068,6 +2104,7 @@ static const VMStateDescription vmstate_megasas = {
     .minimum_version_id_old = 0,
     .fields      = (VMStateField[]) {
         VMSTATE_PCI_DEVICE(parent_obj, MegasasState),
+        VMSTATE_MSIX(parent_obj, MegasasState),
 
         VMSTATE_INT32(fw_state, MegasasState),
         VMSTATE_INT32(intr_mask, MegasasState),
@@ -2083,9 +2120,12 @@ static void megasas_scsi_uninit(PCIDevice *d)
 {
     MegasasState *s = MEGASAS(d);
 
-#ifdef USE_MSIX
-    msix_uninit(d, &s->mmio_io);
-#endif
+    if (megasas_use_msix(s)) {
+        msix_uninit(d, &s->mmio_io, &s->mmio_io);
+    }
+    if (megasas_use_msi(s)) {
+        msi_uninit(d);
+    }
     memory_region_destroy(&s->mmio_io);
     memory_region_destroy(&s->port_io);
     memory_region_destroy(&s->queue_io);
@@ -2124,15 +2164,15 @@ static int megasas_scsi_init(PCIDevice *dev)
     memory_region_init_io(&s->queue_io, OBJECT(s), &megasas_queue_ops, s,
                           "megasas-queue", 0x40000);
 
-#ifdef USE_MSIX
-    /* MSI-X support is currently broken */
+    if (megasas_use_msi(s) &&
+        msi_init(dev, 0x50, 1, true, false)) {
+        s->flags &= ~MEGASAS_MASK_USE_MSI;
+    }
     if (megasas_use_msix(s) &&
-        msix_init(dev, 15, &s->mmio_io, 0, 0x2000)) {
+        msix_init(dev, 15, &s->mmio_io, 0, 0x2000,
+                  &s->mmio_io, 0, 0x3800, 0x68)) {
         s->flags &= ~MEGASAS_MASK_USE_MSIX;
     }
-#else
-    s->flags &= ~MEGASAS_MASK_USE_MSIX;
-#endif
 
     bar_type = PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64;
     pci_register_bar(dev, 0, bar_type, &s->mmio_io);
@@ -2151,7 +2191,7 @@ static int megasas_scsi_init(PCIDevice *dev)
         s->sas_addr |= PCI_FUNC(dev->devfn);
     }
     if (!s->hba_serial) {
-	s->hba_serial = g_strdup(MEGASAS_HBA_SERIAL);
+        s->hba_serial = g_strdup(MEGASAS_HBA_SERIAL);
     }
     if (s->fw_sge >= MEGASAS_MAX_SGE - MFI_PASS_FRAME_SIZE) {
         s->fw_sge = MEGASAS_MAX_SGE - MFI_PASS_FRAME_SIZE;
@@ -2164,7 +2204,6 @@ static int megasas_scsi_init(PCIDevice *dev)
         s->fw_cmds = MEGASAS_MAX_FRAMES;
     }
     trace_megasas_init(s->fw_sge, s->fw_cmds,
-                       megasas_use_msix(s) ? "MSI-X" : "INTx",
                        megasas_is_jbod(s) ? "jbod" : "raid");
     s->fw_luns = (MFI_MAX_LD > MAX_SCSI_DEVS) ?
         MAX_SCSI_DEVS : MFI_MAX_LD;
@@ -2189,6 +2228,13 @@ static int megasas_scsi_init(PCIDevice *dev)
     return 0;
 }
 
+static void
+megasas_write_config(PCIDevice *pci, uint32_t addr, uint32_t val, int len)
+{
+    pci_default_write_config(pci, addr, val, len);
+    msi_write_config(pci, addr, val, len);
+}
+
 static Property megasas_properties[] = {
     DEFINE_PROP_UINT32("max_sge", MegasasState, fw_sge,
                        MEGASAS_DEFAULT_SGE),
@@ -2196,10 +2242,10 @@ static Property megasas_properties[] = {
                        MEGASAS_DEFAULT_FRAMES),
     DEFINE_PROP_STRING("hba_serial", MegasasState, hba_serial),
     DEFINE_PROP_UINT64("sas_address", MegasasState, sas_addr, 0),
-#ifdef USE_MSIX
+    DEFINE_PROP_BIT("use_msi", MegasasState, flags,
+                    MEGASAS_FLAG_USE_MSI, false),
     DEFINE_PROP_BIT("use_msix", MegasasState, flags,
                     MEGASAS_FLAG_USE_MSIX, false),
-#endif
     DEFINE_PROP_BIT("use_jbod", MegasasState, flags,
                     MEGASAS_FLAG_USE_JBOD, false),
     DEFINE_PROP_END_OF_LIST(),
@@ -2222,6 +2268,7 @@ static void megasas_class_init(ObjectClass *oc, void *data)
     dc->vmsd = &vmstate_megasas;
     set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
     dc->desc = "LSI MegaRAID SAS 1078";
+    pc->config_write = megasas_write_config;
 }
 
 static const TypeInfo megasas_info = {
diff --git a/hw/scsi/mfi.h b/hw/scsi/mfi.h
index cd8355badf..a3034f6239 100644
--- a/hw/scsi/mfi.h
+++ b/hw/scsi/mfi.h
@@ -164,6 +164,7 @@ typedef enum {
     MFI_DCMD_PD_BLINK =                 0x02070100,
     MFI_DCMD_PD_UNBLINK =               0x02070200,
     MFI_DCMD_LD_GET_LIST =              0x03010000,
+    MFI_DCMD_LD_LIST_QUERY =            0x03010100,
     MFI_DCMD_LD_GET_INFO =              0x03020000,
     MFI_DCMD_LD_GET_PROP =              0x03030000,
     MFI_DCMD_LD_SET_PROP =              0x03040000,
@@ -411,6 +412,14 @@ typedef enum {
     MR_PD_QUERY_TYPE_EXPOSED_TO_HOST =  5, /*query for system drives */
 } mfi_pd_query_type;
 
+typedef enum {
+    MR_LD_QUERY_TYPE_ALL =              0,
+    MR_LD_QUERY_TYPE_EXPOSED_TO_HOST =  1,
+    MR_LD_QUERY_TYPE_USED_TGT_IDS =     2,
+    MR_LD_QUERY_TYPE_CLUSTER_ACCESS =   3,
+    MR_LD_QUERY_TYPE_CLUSTER_LOCALE =   4,
+} mfi_ld_query_type;
+
 /*
  * Other propertities and definitions
  */
diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
index abe73022c0..06399fa37e 100644
--- a/hw/scsi/scsi-bus.c
+++ b/hw/scsi/scsi-bus.c
@@ -938,6 +938,7 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
         if (cmd->xfer == 0) {
             cmd->xfer = 256;
         }
+        /* fall through */
     case WRITE_10:
     case WRITE_VERIFY_10:
     case WRITE_12:
@@ -952,6 +953,7 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
         if (cmd->xfer == 0) {
             cmd->xfer = 256;
         }
+        /* fall through */
     case READ_10:
     case RECOVER_BUFFERED_DATA:
     case READ_12:
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
index 48a28ae199..4bcef551a6 100644
--- a/hw/scsi/scsi-disk.c
+++ b/hw/scsi/scsi-disk.c
@@ -2458,21 +2458,27 @@ static int scsi_block_initfn(SCSIDevice *dev)
     int rc;
 
     if (!s->qdev.conf.bs) {
-        error_report("scsi-block: drive property not set");
+        error_report("drive property not set");
         return -1;
     }
 
     /* check we are using a driver managing SG_IO (version 3 and after) */
-    if (bdrv_ioctl(s->qdev.conf.bs, SG_GET_VERSION_NUM, &sg_version) < 0 ||
-        sg_version < 30000) {
-        error_report("scsi-block: scsi generic interface too old");
+    rc = bdrv_ioctl(s->qdev.conf.bs, SG_GET_VERSION_NUM, &sg_version);
+    if (rc < 0) {
+        error_report("cannot get SG_IO version number: %s.  "
+                     "Is this a SCSI device?",
+                     strerror(-rc));
+        return -1;
+    }
+    if (sg_version < 30000) {
+        error_report("scsi generic interface too old");
         return -1;
     }
 
     /* get device type from INQUIRY data */
     rc = get_device_type(s);
     if (rc < 0) {
-        error_report("scsi-block: INQUIRY failed");
+        error_report("INQUIRY failed");
         return -1;
     }
 
diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c
index 8d92e0da15..3733d2c36c 100644
--- a/hw/scsi/scsi-generic.c
+++ b/hw/scsi/scsi-generic.c
@@ -394,6 +394,7 @@ static void scsi_destroy(SCSIDevice *s)
 
 static int scsi_generic_initfn(SCSIDevice *s)
 {
+    int rc;
     int sg_version;
     struct sg_scsi_id scsiid;
 
@@ -412,8 +413,11 @@ static int scsi_generic_initfn(SCSIDevice *s)
     }
 
     /* check we are using a driver managing SG_IO (version 3 and after */
-    if (bdrv_ioctl(s->conf.bs, SG_GET_VERSION_NUM, &sg_version) < 0) {
-        error_report("scsi generic interface not supported");
+    rc = bdrv_ioctl(s->conf.bs, SG_GET_VERSION_NUM, &sg_version);
+    if (rc < 0) {
+        error_report("cannot get SG_IO version number: %s.  "
+                     "Is this a SCSI device?",
+                     strerror(-rc));
         return -1;
     }
     if (sg_version < 30000) {
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
index 175219376c..14261fb1a7 100644
--- a/hw/scsi/virtio-scsi.c
+++ b/hw/scsi/virtio-scsi.c
@@ -498,7 +498,7 @@ static void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev,
                                    uint32_t event, uint32_t reason)
 {
     VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
-    VirtIOSCSIReq *req = virtio_scsi_pop_req(s, vs->event_vq);
+    VirtIOSCSIReq *req;
     VirtIOSCSIEvent *evt;
     VirtIODevice *vdev = VIRTIO_DEVICE(s);
     int in_size;
@@ -507,6 +507,7 @@ static void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev,
         return;
     }
 
+    req = virtio_scsi_pop_req(s, vs->event_vq);
     if (!req) {
         s->events_dropped = true;
         return;
diff --git a/hw/sh4/r2d.c b/hw/sh4/r2d.c
index eaeb7ede4e..95c0246d47 100644
--- a/hw/sh4/r2d.c
+++ b/hw/sh4/r2d.c
@@ -219,12 +219,12 @@ static struct QEMU_PACKED
     char kernel_cmdline[256];
 } boot_params;
 
-static void r2d_init(QEMUMachineInitArgs *args)
+static void r2d_init(MachineState *machine)
 {
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
+    const char *cpu_model = machine->cpu_model;
+    const char *kernel_filename = machine->kernel_filename;
+    const char *kernel_cmdline = machine->kernel_cmdline;
+    const char *initrd_filename = machine->initrd_filename;
     SuperHCPU *cpu;
     CPUSH4State *env;
     ResetData *reset_info;
diff --git a/hw/sh4/shix.c b/hw/sh4/shix.c
index 904a966700..7c152b4a3a 100644
--- a/hw/sh4/shix.c
+++ b/hw/sh4/shix.c
@@ -39,9 +39,9 @@
 #define BIOS_FILENAME "shix_bios.bin"
 #define BIOS_ADDRESS 0xA0000000
 
-static void shix_init(QEMUMachineInitArgs *args)
+static void shix_init(MachineState *machine)
 {
-    const char *cpu_model = args->cpu_model;
+    const char *cpu_model = machine->cpu_model;
     int ret;
     SuperHCPU *cpu;
     struct SH7750State *s;
diff --git a/hw/sparc/leon3.c b/hw/sparc/leon3.c
index c16e9e4c81..827383b02f 100644
--- a/hw/sparc/leon3.c
+++ b/hw/sparc/leon3.c
@@ -101,11 +101,11 @@ static void leon3_set_pil_in(void *opaque, uint32_t pil_in)
     }
 }
 
-static void leon3_generic_hw_init(QEMUMachineInitArgs *args)
+static void leon3_generic_hw_init(MachineState *machine)
 {
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
+    ram_addr_t ram_size = machine->ram_size;
+    const char *cpu_model = machine->cpu_model;
+    const char *kernel_filename = machine->kernel_filename;
     SPARCCPU *cpu;
     CPUSPARCState   *env;
     MemoryRegion *address_space_mem = get_system_memory();
diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c
index 75adb68abc..4e793c2760 100644
--- a/hw/sparc/sun4m.c
+++ b/hw/sparc/sun4m.c
@@ -867,9 +867,9 @@ static void dummy_fdc_tc(void *opaque, int irq, int level)
 }
 
 static void sun4m_hw_init(const struct sun4m_hwdef *hwdef,
-                          QEMUMachineInitArgs *args)
+                          MachineState *machine)
 {
-    const char *cpu_model = args->cpu_model;
+    const char *cpu_model = machine->cpu_model;
     unsigned int i;
     void *iommu, *espdma, *ledma, *nvram;
     qemu_irq *cpu_irqs[MAX_CPUS], slavio_irq[32], slavio_cpu_irq[MAX_CPUS],
@@ -895,10 +895,10 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef,
 
 
     /* set up devices */
-    ram_init(0, args->ram_size, hwdef->max_mem);
+    ram_init(0, machine->ram_size, hwdef->max_mem);
     /* models without ECC don't trap when missing ram is accessed */
     if (!hwdef->ecc_base) {
-        empty_slot_init(args->ram_size, hwdef->max_mem - args->ram_size);
+        empty_slot_init(machine->ram_size, hwdef->max_mem - machine->ram_size);
     }
 
     prom_init(hwdef->slavio_base, bios_name);
@@ -1051,14 +1051,14 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef,
         empty_slot_init(hwdef->bpp_base, 0x20);
     }
 
-    kernel_size = sun4m_load_kernel(args->kernel_filename,
-                                    args->initrd_filename,
-                                    args->ram_size);
+    kernel_size = sun4m_load_kernel(machine->kernel_filename,
+                                    machine->initrd_filename,
+                                    machine->ram_size);
 
-    nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, args->kernel_cmdline,
-               args->boot_order, args->ram_size, kernel_size, graphic_width,
-               graphic_height, graphic_depth, hwdef->nvram_machine_id,
-               "Sun4m");
+    nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, machine->kernel_cmdline,
+               machine->boot_order, machine->ram_size, kernel_size,
+               graphic_width, graphic_height, graphic_depth,
+               hwdef->nvram_machine_id, "Sun4m");
 
     if (hwdef->ecc_base)
         ecc_init(hwdef->ecc_base, slavio_irq[28],
@@ -1074,20 +1074,20 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef,
     fw_cfg_add_i16(fw_cfg, FW_CFG_SUN4M_HEIGHT, graphic_height);
     fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, KERNEL_LOAD_ADDR);
     fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
-    if (args->kernel_cmdline) {
+    if (machine->kernel_cmdline) {
         fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, CMDLINE_ADDR);
         pstrcpy_targphys("cmdline", CMDLINE_ADDR, TARGET_PAGE_SIZE,
-                         args->kernel_cmdline);
-        fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, args->kernel_cmdline);
+                         machine->kernel_cmdline);
+        fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, machine->kernel_cmdline);
         fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE,
-                       strlen(args->kernel_cmdline) + 1);
+                       strlen(machine->kernel_cmdline) + 1);
     } else {
         fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, 0);
         fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, 0);
     }
     fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, INITRD_LOAD_ADDR);
     fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, 0); // not used
-    fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, args->boot_order[0]);
+    fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, machine->boot_order[0]);
     qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
 }
 
@@ -1349,57 +1349,57 @@ static const struct sun4m_hwdef sun4m_hwdefs[] = {
 };
 
 /* SPARCstation 5 hardware initialisation */
-static void ss5_init(QEMUMachineInitArgs *args)
+static void ss5_init(MachineState *machine)
 {
-    sun4m_hw_init(&sun4m_hwdefs[0], args);
+    sun4m_hw_init(&sun4m_hwdefs[0], machine);
 }
 
 /* SPARCstation 10 hardware initialisation */
-static void ss10_init(QEMUMachineInitArgs *args)
+static void ss10_init(MachineState *machine)
 {
-    sun4m_hw_init(&sun4m_hwdefs[1], args);
+    sun4m_hw_init(&sun4m_hwdefs[1], machine);
 }
 
 /* SPARCserver 600MP hardware initialisation */
-static void ss600mp_init(QEMUMachineInitArgs *args)
+static void ss600mp_init(MachineState *machine)
 {
-    sun4m_hw_init(&sun4m_hwdefs[2], args);
+    sun4m_hw_init(&sun4m_hwdefs[2], machine);
 }
 
 /* SPARCstation 20 hardware initialisation */
-static void ss20_init(QEMUMachineInitArgs *args)
+static void ss20_init(MachineState *machine)
 {
-    sun4m_hw_init(&sun4m_hwdefs[3], args);
+    sun4m_hw_init(&sun4m_hwdefs[3], machine);
 }
 
 /* SPARCstation Voyager hardware initialisation */
-static void vger_init(QEMUMachineInitArgs *args)
+static void vger_init(MachineState *machine)
 {
-    sun4m_hw_init(&sun4m_hwdefs[4], args);
+    sun4m_hw_init(&sun4m_hwdefs[4], machine);
 }
 
 /* SPARCstation LX hardware initialisation */
-static void ss_lx_init(QEMUMachineInitArgs *args)
+static void ss_lx_init(MachineState *machine)
 {
-    sun4m_hw_init(&sun4m_hwdefs[5], args);
+    sun4m_hw_init(&sun4m_hwdefs[5], machine);
 }
 
 /* SPARCstation 4 hardware initialisation */
-static void ss4_init(QEMUMachineInitArgs *args)
+static void ss4_init(MachineState *machine)
 {
-    sun4m_hw_init(&sun4m_hwdefs[6], args);
+    sun4m_hw_init(&sun4m_hwdefs[6], machine);
 }
 
 /* SPARCClassic hardware initialisation */
-static void scls_init(QEMUMachineInitArgs *args)
+static void scls_init(MachineState *machine)
 {
-    sun4m_hw_init(&sun4m_hwdefs[7], args);
+    sun4m_hw_init(&sun4m_hwdefs[7], machine);
 }
 
 /* SPARCbook hardware initialisation */
-static void sbook_init(QEMUMachineInitArgs *args)
+static void sbook_init(MachineState *machine)
 {
-    sun4m_hw_init(&sun4m_hwdefs[8], args);
+    sun4m_hw_init(&sun4m_hwdefs[8], machine);
 }
 
 static QEMUMachine ss5_machine = {
diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c
index 6f271d9cfc..33c311bf28 100644
--- a/hw/sparc64/sun4u.c
+++ b/hw/sparc64/sun4u.c
@@ -811,7 +811,7 @@ static SPARCCPU *cpu_devinit(const char *cpu_model, const struct hwdef *hwdef)
 }
 
 static void sun4uv_init(MemoryRegion *address_space_mem,
-                        QEMUMachineInitArgs *args,
+                        MachineState *machine,
                         const struct hwdef *hwdef)
 {
     SPARCCPU *cpu;
@@ -826,10 +826,10 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
     FWCfgState *fw_cfg;
 
     /* init CPUs */
-    cpu = cpu_devinit(args->cpu_model, hwdef);
+    cpu = cpu_devinit(machine->cpu_model, hwdef);
 
     /* set up devices */
-    ram_init(0, args->ram_size);
+    ram_init(0, machine->ram_size);
 
     prom_init(hwdef->prom_addr, bios_name);
 
@@ -875,15 +875,15 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
 
     initrd_size = 0;
     initrd_addr = 0;
-    kernel_size = sun4u_load_kernel(args->kernel_filename,
-                                    args->initrd_filename,
+    kernel_size = sun4u_load_kernel(machine->kernel_filename,
+                                    machine->initrd_filename,
                                     ram_size, &initrd_size, &initrd_addr,
                                     &kernel_addr, &kernel_entry);
 
-    sun4u_NVRAM_set_params(nvram, NVRAM_SIZE, "Sun4u", args->ram_size,
-                           args->boot_order,
+    sun4u_NVRAM_set_params(nvram, NVRAM_SIZE, "Sun4u", machine->ram_size,
+                           machine->boot_order,
                            kernel_addr, kernel_size,
-                           args->kernel_cmdline,
+                           machine->kernel_cmdline,
                            initrd_addr, initrd_size,
                            /* XXX: need an option to load a NVRAM image */
                            0,
@@ -897,16 +897,16 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
     fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, hwdef->machine_id);
     fw_cfg_add_i64(fw_cfg, FW_CFG_KERNEL_ADDR, kernel_entry);
     fw_cfg_add_i64(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
-    if (args->kernel_cmdline) {
+    if (machine->kernel_cmdline) {
         fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE,
-                       strlen(args->kernel_cmdline) + 1);
-        fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, args->kernel_cmdline);
+                       strlen(machine->kernel_cmdline) + 1);
+        fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, machine->kernel_cmdline);
     } else {
         fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, 0);
     }
     fw_cfg_add_i64(fw_cfg, FW_CFG_INITRD_ADDR, initrd_addr);
     fw_cfg_add_i64(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size);
-    fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, args->boot_order[0]);
+    fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, machine->boot_order[0]);
 
     fw_cfg_add_i16(fw_cfg, FW_CFG_SPARC64_WIDTH, graphic_width);
     fw_cfg_add_i16(fw_cfg, FW_CFG_SPARC64_HEIGHT, graphic_height);
@@ -946,21 +946,21 @@ static const struct hwdef hwdefs[] = {
 };
 
 /* Sun4u hardware initialisation */
-static void sun4u_init(QEMUMachineInitArgs *args)
+static void sun4u_init(MachineState *machine)
 {
-    sun4uv_init(get_system_memory(), args, &hwdefs[0]);
+    sun4uv_init(get_system_memory(), machine, &hwdefs[0]);
 }
 
 /* Sun4v hardware initialisation */
-static void sun4v_init(QEMUMachineInitArgs *args)
+static void sun4v_init(MachineState *machine)
 {
-    sun4uv_init(get_system_memory(), args, &hwdefs[1]);
+    sun4uv_init(get_system_memory(), machine, &hwdefs[1]);
 }
 
 /* Niagara hardware initialisation */
-static void niagara_init(QEMUMachineInitArgs *args)
+static void niagara_init(MachineState *machine)
 {
-    sun4uv_init(get_system_memory(), args, &hwdefs[2]);
+    sun4uv_init(get_system_memory(), machine, &hwdefs[2]);
 }
 
 static QEMUMachine sun4u_machine = {
diff --git a/hw/ssi/ssi.c b/hw/ssi/ssi.c
index 1c82a93590..2aab79ba7f 100644
--- a/hw/ssi/ssi.c
+++ b/hw/ssi/ssi.c
@@ -60,7 +60,7 @@ static int ssi_slave_init(DeviceState *dev)
 
     if (ssc->transfer_raw == ssi_transfer_raw_default &&
             ssc->cs_polarity != SSI_CS_NONE) {
-        qdev_init_gpio_in(dev, ssi_cs_default, 1);
+        qdev_init_gpio_in_named(dev, ssi_cs_default, SSI_GPIO_CS, 1);
     }
 
     return ssc->init(s);
@@ -155,7 +155,7 @@ static int ssi_auto_connect_slave(Object *child, void *opaque)
         return 0;
     }
 
-    cs_line = qdev_get_gpio_in(DEVICE(dev), 0);
+    cs_line = qdev_get_gpio_in_named(DEVICE(dev), SSI_GPIO_CS, 0);
     qdev_set_parent_bus(DEVICE(dev), BUS(arg->bus));
     **arg->cs_linep = cs_line;
     (*arg->cs_linep)++;
diff --git a/hw/timer/mc146818rtc.c b/hw/timer/mc146818rtc.c
index 8509309fa7..df54546562 100644
--- a/hw/timer/mc146818rtc.c
+++ b/hw/timer/mc146818rtc.c
@@ -793,19 +793,46 @@ static const MemoryRegionOps cmos_ops = {
 static void rtc_get_date(Object *obj, Visitor *v, void *opaque,
                          const char *name, Error **errp)
 {
+    Error *err = NULL;
     RTCState *s = MC146818_RTC(obj);
     struct tm current_tm;
 
     rtc_update_time(s);
     rtc_get_time(s, &current_tm);
-    visit_start_struct(v, NULL, "struct tm", name, 0, errp);
-    visit_type_int32(v, &current_tm.tm_year, "tm_year", errp);
-    visit_type_int32(v, &current_tm.tm_mon, "tm_mon", errp);
-    visit_type_int32(v, &current_tm.tm_mday, "tm_mday", errp);
-    visit_type_int32(v, &current_tm.tm_hour, "tm_hour", errp);
-    visit_type_int32(v, &current_tm.tm_min, "tm_min", errp);
-    visit_type_int32(v, &current_tm.tm_sec, "tm_sec", errp);
+    visit_start_struct(v, NULL, "struct tm", name, 0, &err);
+    if (err) {
+        goto out;
+    }
+    visit_type_int32(v, &current_tm.tm_year, "tm_year", &err);
+    if (err) {
+        goto out_end;
+    }
+    visit_type_int32(v, &current_tm.tm_mon, "tm_mon", &err);
+    if (err) {
+        goto out_end;
+    }
+    visit_type_int32(v, &current_tm.tm_mday, "tm_mday", &err);
+    if (err) {
+        goto out_end;
+    }
+    visit_type_int32(v, &current_tm.tm_hour, "tm_hour", &err);
+    if (err) {
+        goto out_end;
+    }
+    visit_type_int32(v, &current_tm.tm_min, "tm_min", &err);
+    if (err) {
+        goto out_end;
+    }
+    visit_type_int32(v, &current_tm.tm_sec, "tm_sec", &err);
+    if (err) {
+        goto out_end;
+    }
+out_end:
+    error_propagate(errp, err);
+    err = NULL;
     visit_end_struct(v, errp);
+out:
+    error_propagate(errp, err);
 }
 
 static void rtc_realizefn(DeviceState *dev, Error **errp)
diff --git a/hw/unicore32/puv3.c b/hw/unicore32/puv3.c
index 42913b6a5a..08dd4d04cb 100644
--- a/hw/unicore32/puv3.c
+++ b/hw/unicore32/puv3.c
@@ -101,12 +101,12 @@ static void puv3_load_kernel(const char *kernel_filename)
     graphic_console_init(NULL, 0, &no_ops, NULL);
 }
 
-static void puv3_init(QEMUMachineInitArgs *args)
+static void puv3_init(MachineState *machine)
 {
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *initrd_filename = args->initrd_filename;
+    ram_addr_t ram_size = machine->ram_size;
+    const char *cpu_model = machine->cpu_model;
+    const char *kernel_filename = machine->kernel_filename;
+    const char *initrd_filename = machine->initrd_filename;
     CPUUniCore32State *env;
 
     if (initrd_filename) {
diff --git a/hw/usb/core.c b/hw/usb/core.c
index 67ba7d6018..cf34755bba 100644
--- a/hw/usb/core.c
+++ b/hw/usb/core.c
@@ -28,6 +28,26 @@
 #include "qemu/iov.h"
 #include "trace.h"
 
+void usb_pick_speed(USBPort *port)
+{
+    static const int speeds[] = {
+        USB_SPEED_SUPER,
+        USB_SPEED_HIGH,
+        USB_SPEED_FULL,
+        USB_SPEED_LOW,
+    };
+    USBDevice *udev = port->dev;
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(speeds); i++) {
+        if ((udev->speedmask & (1 << speeds[i])) &&
+            (port->speedmask & (1 << speeds[i]))) {
+            udev->speed = speeds[i];
+            return;
+        }
+    }
+}
+
 void usb_attach(USBPort *port)
 {
     USBDevice *dev = port->dev;
@@ -35,6 +55,7 @@ void usb_attach(USBPort *port)
     assert(dev != NULL);
     assert(dev->attached);
     assert(dev->state == USB_STATE_NOTATTACHED);
+    usb_pick_speed(port);
     port->ops->attach(port);
     dev->state = USB_STATE_ATTACHED;
     usb_device_handle_attach(dev);
diff --git a/hw/usb/desc.c b/hw/usb/desc.c
index ab48691363..b82c397ef9 100644
--- a/hw/usb/desc.c
+++ b/hw/usb/desc.c
@@ -518,18 +518,6 @@ void usb_desc_init(USBDevice *dev)
 
 void usb_desc_attach(USBDevice *dev)
 {
-    const USBDesc *desc = usb_device_get_usb_desc(dev);
-
-    assert(desc != NULL);
-    if (desc->super && (dev->port->speedmask & USB_SPEED_MASK_SUPER)) {
-        dev->speed = USB_SPEED_SUPER;
-    } else if (desc->high && (dev->port->speedmask & USB_SPEED_MASK_HIGH)) {
-        dev->speed = USB_SPEED_HIGH;
-    } else if (desc->full && (dev->port->speedmask & USB_SPEED_MASK_FULL)) {
-        dev->speed = USB_SPEED_FULL;
-    } else {
-        return;
-    }
     usb_desc_setdefaults(dev);
 }
 
diff --git a/hw/usb/dev-hid.c b/hw/usb/dev-hid.c
index d097d937ea..67a57f1dcd 100644
--- a/hw/usb/dev-hid.c
+++ b/hw/usb/dev-hid.c
@@ -47,6 +47,8 @@ typedef struct USBHIDState {
     USBEndpoint *intr;
     HIDState hid;
     uint32_t usb_version;
+    char *display;
+    uint32_t head;
 } USBHIDState;
 
 enum {
@@ -574,6 +576,9 @@ static int usb_hid_initfn(USBDevice *dev, int kind)
     usb_desc_init(dev);
     us->intr = usb_ep_get(dev, USB_TOKEN_IN, 1);
     hid_init(&us->hid, kind, usb_hid_changed);
+    if (us->display && us->hid.s) {
+        qemu_input_handler_bind(us->hid.s, us->display, us->head, NULL);
+    }
     return 0;
 }
 
@@ -653,6 +658,8 @@ static void usb_hid_class_initfn(ObjectClass *klass, void *data)
 
 static Property usb_tablet_properties[] = {
         DEFINE_PROP_UINT32("usb_version", USBHIDState, usb_version, 2),
+        DEFINE_PROP_STRING("display", USBHIDState, display),
+        DEFINE_PROP_UINT32("head", USBHIDState, head, 0),
         DEFINE_PROP_END_OF_LIST(),
 };
 
@@ -696,6 +703,11 @@ static const TypeInfo usb_mouse_info = {
     .class_init    = usb_mouse_class_initfn,
 };
 
+static Property usb_keyboard_properties[] = {
+        DEFINE_PROP_STRING("display", USBHIDState, display),
+        DEFINE_PROP_END_OF_LIST(),
+};
+
 static void usb_keyboard_class_initfn(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
@@ -706,6 +718,7 @@ static void usb_keyboard_class_initfn(ObjectClass *klass, void *data)
     uc->product_desc   = "QEMU USB Keyboard";
     uc->usb_desc       = &desc_keyboard;
     dc->vmsd = &vmstate_usb_kbd;
+    dc->props = usb_keyboard_properties;
     set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
 }
 
diff --git a/hw/usb/dev-mtp.c b/hw/usb/dev-mtp.c
index 943f930404..380b465621 100644
--- a/hw/usb/dev-mtp.c
+++ b/hw/usb/dev-mtp.c
@@ -46,6 +46,7 @@ enum mtp_code {
 
     /* response codes */
     RES_OK                         = 0x2001,
+    RES_GENERAL_ERROR              = 0x2002,
     RES_SESSION_NOT_OPEN           = 0x2003,
     RES_INVALID_TRANSACTION_ID     = 0x2004,
     RES_OPERATION_NOT_SUPPORTED    = 0x2005,
@@ -109,7 +110,8 @@ struct MTPObject {
     struct stat  stat;
     MTPObject    *parent;
     MTPObject    **children;
-    int32_t      nchildren;
+    uint32_t     nchildren;
+    bool         have_children;
     QTAILQ_ENTRY(MTPObject) next;
 };
 
@@ -273,7 +275,6 @@ static MTPObject *usb_mtp_object_alloc(MTPState *s, uint32_t handle,
     o->handle = handle;
     o->parent = parent;
     o->name = g_strdup(name);
-    o->nchildren = -1;
     if (parent == NULL) {
         o->path = g_strdup(name);
     } else {
@@ -340,7 +341,11 @@ static void usb_mtp_object_readdir(MTPState *s, MTPObject *o)
     struct dirent *entry;
     DIR *dir;
 
-    o->nchildren = 0;
+    if (o->have_children) {
+        return;
+    }
+    o->have_children = true;
+
     dir = opendir(o->path);
     if (!dir) {
         return;
@@ -698,7 +703,10 @@ static MTPData *usb_mtp_get_partial_object(MTPState *s, MTPControl *c,
     if (offset > o->stat.st_size) {
         offset = o->stat.st_size;
     }
-    lseek(d->fd, offset, SEEK_SET);
+    if (lseek(d->fd, offset, SEEK_SET) < 0) {
+        usb_mtp_data_free(d);
+        return NULL;
+    }
 
     d->length = c->argv[2];
     if (d->length > o->stat.st_size - offset) {
@@ -789,9 +797,7 @@ static void usb_mtp_command(MTPState *s, MTPControl *c)
                                  c->trans, 0, 0, 0);
             return;
         }
-        if (o->nchildren == -1) {
-            usb_mtp_object_readdir(s, o);
-        }
+        usb_mtp_object_readdir(s, o);
         if (c->code == CMD_GET_NUM_OBJECTS) {
             trace_usb_mtp_op_get_num_objects(s->dev.addr, o->handle, o->path);
             nres = 1;
@@ -823,7 +829,9 @@ static void usb_mtp_command(MTPState *s, MTPControl *c)
         }
         data_in = usb_mtp_get_object(s, c, o);
         if (NULL == data_in) {
-            fprintf(stderr, "%s: TODO: handle error\n", __func__);
+            usb_mtp_queue_result(s, RES_GENERAL_ERROR,
+                                 c->trans, 0, 0, 0);
+            return;
         }
         break;
     case CMD_GET_PARTIAL_OBJECT:
@@ -840,7 +848,9 @@ static void usb_mtp_command(MTPState *s, MTPControl *c)
         }
         data_in = usb_mtp_get_partial_object(s, c, o);
         if (NULL == data_in) {
-            fprintf(stderr, "%s: TODO: handle error\n", __func__);
+            usb_mtp_queue_result(s, RES_GENERAL_ERROR,
+                                 c->trans, 0, 0, 0);
+            return;
         }
         nres = 1;
         res0 = data_in->length;
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index a3ae9f260a..a00a93c3eb 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -27,87 +27,10 @@
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
+#include "hw/usb/ehci-regs.h"
 #include "hw/usb/hcd-ehci.h"
 #include "trace.h"
 
-/* Capability Registers Base Address - section 2.2 */
-#define CAPLENGTH        0x0000  /* 1-byte, 0x0001 reserved */
-#define HCIVERSION       0x0002  /* 2-bytes, i/f version # */
-#define HCSPARAMS        0x0004  /* 4-bytes, structural params */
-#define HCCPARAMS        0x0008  /* 4-bytes, capability params */
-#define EECP             HCCPARAMS + 1
-#define HCSPPORTROUTE1   0x000c
-#define HCSPPORTROUTE2   0x0010
-
-#define USBCMD           0x0000
-#define USBCMD_RUNSTOP   (1 << 0)      // run / Stop
-#define USBCMD_HCRESET   (1 << 1)      // HC Reset
-#define USBCMD_FLS       (3 << 2)      // Frame List Size
-#define USBCMD_FLS_SH    2             // Frame List Size Shift
-#define USBCMD_PSE       (1 << 4)      // Periodic Schedule Enable
-#define USBCMD_ASE       (1 << 5)      // Asynch Schedule Enable
-#define USBCMD_IAAD      (1 << 6)      // Int Asynch Advance Doorbell
-#define USBCMD_LHCR      (1 << 7)      // Light Host Controller Reset
-#define USBCMD_ASPMC     (3 << 8)      // Async Sched Park Mode Count
-#define USBCMD_ASPME     (1 << 11)     // Async Sched Park Mode Enable
-#define USBCMD_ITC       (0x7f << 16)  // Int Threshold Control
-#define USBCMD_ITC_SH    16            // Int Threshold Control Shift
-
-#define USBSTS           0x0004
-#define USBSTS_RO_MASK   0x0000003f
-#define USBSTS_INT       (1 << 0)      // USB Interrupt
-#define USBSTS_ERRINT    (1 << 1)      // Error Interrupt
-#define USBSTS_PCD       (1 << 2)      // Port Change Detect
-#define USBSTS_FLR       (1 << 3)      // Frame List Rollover
-#define USBSTS_HSE       (1 << 4)      // Host System Error
-#define USBSTS_IAA       (1 << 5)      // Interrupt on Async Advance
-#define USBSTS_HALT      (1 << 12)     // HC Halted
-#define USBSTS_REC       (1 << 13)     // Reclamation
-#define USBSTS_PSS       (1 << 14)     // Periodic Schedule Status
-#define USBSTS_ASS       (1 << 15)     // Asynchronous Schedule Status
-
-/*
- *  Interrupt enable bits correspond to the interrupt active bits in USBSTS
- *  so no need to redefine here.
- */
-#define USBINTR              0x0008
-#define USBINTR_MASK         0x0000003f
-
-#define FRINDEX              0x000c
-#define CTRLDSSEGMENT        0x0010
-#define PERIODICLISTBASE     0x0014
-#define ASYNCLISTADDR        0x0018
-#define ASYNCLISTADDR_MASK   0xffffffe0
-
-#define CONFIGFLAG           0x0040
-
-/*
- * Bits that are reserved or are read-only are masked out of values
- * written to us by software
- */
-#define PORTSC_RO_MASK       0x007001c0
-#define PORTSC_RWC_MASK      0x0000002a
-#define PORTSC_WKOC_E        (1 << 22)    // Wake on Over Current Enable
-#define PORTSC_WKDS_E        (1 << 21)    // Wake on Disconnect Enable
-#define PORTSC_WKCN_E        (1 << 20)    // Wake on Connect Enable
-#define PORTSC_PTC           (15 << 16)   // Port Test Control
-#define PORTSC_PTC_SH        16           // Port Test Control shift
-#define PORTSC_PIC           (3 << 14)    // Port Indicator Control
-#define PORTSC_PIC_SH        14           // Port Indicator Control Shift
-#define PORTSC_POWNER        (1 << 13)    // Port Owner
-#define PORTSC_PPOWER        (1 << 12)    // Port Power
-#define PORTSC_LINESTAT      (3 << 10)    // Port Line Status
-#define PORTSC_LINESTAT_SH   10           // Port Line Status Shift
-#define PORTSC_PRESET        (1 << 8)     // Port Reset
-#define PORTSC_SUSPEND       (1 << 7)     // Port Suspend
-#define PORTSC_FPRES         (1 << 6)     // Force Port Resume
-#define PORTSC_OCC           (1 << 5)     // Over Current Change
-#define PORTSC_OCA           (1 << 4)     // Over Current Active
-#define PORTSC_PEDC          (1 << 3)     // Port Enable/Disable Change
-#define PORTSC_PED           (1 << 2)     // Port Enable/Disable
-#define PORTSC_CSC           (1 << 1)     // Connect Status Change
-#define PORTSC_CONNECT       (1 << 0)     // Current Connect Status
-
 #define FRAME_TIMER_FREQ 1000
 #define FRAME_TIMER_NS   (1000000000 / FRAME_TIMER_FREQ)
 #define UFRAME_TIMER_NS  (FRAME_TIMER_NS / 8)
diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c
index 9b1166b2ef..c3bf72cc17 100644
--- a/hw/usb/hcd-uhci.c
+++ b/hw/usb/hcd-uhci.c
@@ -27,6 +27,7 @@
  */
 #include "hw/hw.h"
 #include "hw/usb.h"
+#include "hw/usb/uhci-regs.h"
 #include "hw/pci/pci.h"
 #include "qemu/timer.h"
 #include "qemu/iov.h"
@@ -37,41 +38,6 @@
 //#define DEBUG
 //#define DEBUG_DUMP_DATA
 
-#define UHCI_CMD_FGR      (1 << 4)
-#define UHCI_CMD_EGSM     (1 << 3)
-#define UHCI_CMD_GRESET   (1 << 2)
-#define UHCI_CMD_HCRESET  (1 << 1)
-#define UHCI_CMD_RS       (1 << 0)
-
-#define UHCI_STS_HCHALTED (1 << 5)
-#define UHCI_STS_HCPERR   (1 << 4)
-#define UHCI_STS_HSERR    (1 << 3)
-#define UHCI_STS_RD       (1 << 2)
-#define UHCI_STS_USBERR   (1 << 1)
-#define UHCI_STS_USBINT   (1 << 0)
-
-#define TD_CTRL_SPD     (1 << 29)
-#define TD_CTRL_ERROR_SHIFT  27
-#define TD_CTRL_IOS     (1 << 25)
-#define TD_CTRL_IOC     (1 << 24)
-#define TD_CTRL_ACTIVE  (1 << 23)
-#define TD_CTRL_STALL   (1 << 22)
-#define TD_CTRL_BABBLE  (1 << 20)
-#define TD_CTRL_NAK     (1 << 19)
-#define TD_CTRL_TIMEOUT (1 << 18)
-
-#define UHCI_PORT_SUSPEND (1 << 12)
-#define UHCI_PORT_RESET (1 << 9)
-#define UHCI_PORT_LSDA  (1 << 8)
-#define UHCI_PORT_RD    (1 << 6)
-#define UHCI_PORT_ENC   (1 << 3)
-#define UHCI_PORT_EN    (1 << 2)
-#define UHCI_PORT_CSC   (1 << 1)
-#define UHCI_PORT_CCS   (1 << 0)
-
-#define UHCI_PORT_READ_ONLY    (0x1bb)
-#define UHCI_PORT_WRITE_CLEAR  (UHCI_PORT_CSC | UHCI_PORT_ENC)
-
 #define FRAME_TIMER_FREQ 1000
 
 #define FRAME_MAX_LOOPS  256
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
index ef3177aee9..7f2af8925f 100644
--- a/hw/usb/hcd-xhci.c
+++ b/hw/usb/hcd-xhci.c
@@ -498,6 +498,7 @@ typedef struct XHCIEvRingSeg {
 enum xhci_flags {
     XHCI_FLAG_USE_MSI = 1,
     XHCI_FLAG_USE_MSI_X,
+    XHCI_FLAG_SS_FIRST,
 };
 
 static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid,
@@ -621,6 +622,11 @@ static const char *ep_state_name(uint32_t state)
                        ARRAY_SIZE(ep_state_names));
 }
 
+static bool xhci_get_flag(XHCIState *xhci, enum xhci_flags bit)
+{
+    return xhci->flags & (1 << bit);
+}
+
 static uint64_t xhci_mfindex_get(XHCIState *xhci)
 {
     int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
@@ -709,10 +715,18 @@ static XHCIPort *xhci_lookup_port(XHCIState *xhci, struct USBPort *uport)
     case USB_SPEED_LOW:
     case USB_SPEED_FULL:
     case USB_SPEED_HIGH:
-        index = uport->index;
+        if (xhci_get_flag(xhci, XHCI_FLAG_SS_FIRST)) {
+            index = uport->index + xhci->numports_3;
+        } else {
+            index = uport->index;
+        }
         break;
     case USB_SPEED_SUPER:
-        index = uport->index + xhci->numports_2;
+        if (xhci_get_flag(xhci, XHCI_FLAG_SS_FIRST)) {
+            index = uport->index;
+        } else {
+            index = uport->index + xhci->numports_2;
+        }
         break;
     default:
         return NULL;
@@ -2851,7 +2865,7 @@ static void xhci_port_update(XHCIPort *port, int is_detach)
 
 static void xhci_port_reset(XHCIPort *port, bool warm_reset)
 {
-    trace_usb_xhci_port_reset(port->portnr);
+    trace_usb_xhci_port_reset(port->portnr, warm_reset);
 
     if (!xhci_port_have_device(port)) {
         return;
@@ -2967,7 +2981,11 @@ static uint64_t xhci_cap_read(void *ptr, hwaddr reg, unsigned size)
         ret = 0x20425355; /* "USB " */
         break;
     case 0x28: /* Supported Protocol:08 */
-        ret = 0x00000001 | (xhci->numports_2<<8);
+        if (xhci_get_flag(xhci, XHCI_FLAG_SS_FIRST)) {
+            ret = (xhci->numports_2<<8) | (xhci->numports_3+1);
+        } else {
+            ret = (xhci->numports_2<<8) | 1;
+        }
         break;
     case 0x2c: /* Supported Protocol:0c */
         ret = 0x00000000; /* reserved */
@@ -2979,7 +2997,11 @@ static uint64_t xhci_cap_read(void *ptr, hwaddr reg, unsigned size)
         ret = 0x20425355; /* "USB " */
         break;
     case 0x38: /* Supported Protocol:08 */
-        ret = 0x00000000 | (xhci->numports_2+1) | (xhci->numports_3<<8);
+        if (xhci_get_flag(xhci, XHCI_FLAG_SS_FIRST)) {
+            ret = (xhci->numports_3<<8) | 1;
+        } else {
+            ret = (xhci->numports_3<<8) | (xhci->numports_2+1);
+        }
         break;
     case 0x3c: /* Supported Protocol:0c */
         ret = 0x00000000; /* reserved */
@@ -3435,7 +3457,7 @@ static void xhci_child_detach(USBPort *uport, USBDevice *child)
     USBBus *bus = usb_bus_from_device(child);
     XHCIState *xhci = container_of(bus, XHCIState, bus);
 
-    xhci_detach_slot(xhci, uport);
+    xhci_detach_slot(xhci, child->port);
 }
 
 static USBPortOps xhci_uport_ops = {
@@ -3512,8 +3534,13 @@ static void usb_xhci_init(XHCIState *xhci)
     for (i = 0; i < usbports; i++) {
         speedmask = 0;
         if (i < xhci->numports_2) {
-            port = &xhci->ports[i];
-            port->portnr = i + 1;
+            if (xhci_get_flag(xhci, XHCI_FLAG_SS_FIRST)) {
+                port = &xhci->ports[i + xhci->numports_3];
+                port->portnr = i + 1 + xhci->numports_3;
+            } else {
+                port = &xhci->ports[i];
+                port->portnr = i + 1;
+            }
             port->uport = &xhci->uports[i];
             port->speedmask =
                 USB_SPEED_MASK_LOW  |
@@ -3523,8 +3550,13 @@ static void usb_xhci_init(XHCIState *xhci)
             speedmask |= port->speedmask;
         }
         if (i < xhci->numports_3) {
-            port = &xhci->ports[i + xhci->numports_2];
-            port->portnr = i + 1 + xhci->numports_2;
+            if (xhci_get_flag(xhci, XHCI_FLAG_SS_FIRST)) {
+                port = &xhci->ports[i];
+                port->portnr = i + 1;
+            } else {
+                port = &xhci->ports[i + xhci->numports_2];
+                port->portnr = i + 1 + xhci->numports_2;
+            }
             port->uport = &xhci->uports[i];
             port->speedmask = USB_SPEED_MASK_SUPER;
             snprintf(port->name, sizeof(port->name), "usb3 port #%d", i+1);
@@ -3594,13 +3626,15 @@ static int usb_xhci_initfn(struct PCIDevice *dev)
                      PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64,
                      &xhci->mem);
 
-    ret = pcie_endpoint_cap_init(dev, 0xa0);
-    assert(ret >= 0);
+    if (pci_bus_is_express(dev->bus)) {
+        ret = pcie_endpoint_cap_init(dev, 0xa0);
+        assert(ret >= 0);
+    }
 
-    if (xhci->flags & (1 << XHCI_FLAG_USE_MSI)) {
+    if (xhci_get_flag(xhci, XHCI_FLAG_USE_MSI)) {
         msi_init(dev, 0x70, xhci->numintrs, true, false);
     }
-    if (xhci->flags & (1 << XHCI_FLAG_USE_MSI_X)) {
+    if (xhci_get_flag(xhci, XHCI_FLAG_USE_MSI_X)) {
         msix_init(dev, xhci->numintrs,
                   &xhci->mem, 0, OFF_MSIX_TABLE,
                   &xhci->mem, 0, OFF_MSIX_PBA,
@@ -3781,6 +3815,8 @@ static const VMStateDescription vmstate_xhci = {
 static Property xhci_properties[] = {
     DEFINE_PROP_BIT("msi",      XHCIState, flags, XHCI_FLAG_USE_MSI, true),
     DEFINE_PROP_BIT("msix",     XHCIState, flags, XHCI_FLAG_USE_MSI_X, true),
+    DEFINE_PROP_BIT("superspeed-ports-first",
+                    XHCIState, flags, XHCI_FLAG_SS_FIRST, true),
     DEFINE_PROP_UINT32("intrs", XHCIState, numintrs, MAXINTRS),
     DEFINE_PROP_UINT32("slots", XHCIState, numslots, MAXSLOTS),
     DEFINE_PROP_UINT32("p2",    XHCIState, numports_2, 4),
diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c
index 57bed09a1e..afbf1563f4 100644
--- a/hw/usb/host-libusb.c
+++ b/hw/usb/host-libusb.c
@@ -111,6 +111,7 @@ struct USBHostRequest {
     unsigned char                    *buffer;
     unsigned char                    *cbuf;
     unsigned int                     clen;
+    bool                             usb3ep0quirk;
     QTAILQ_ENTRY(USBHostRequest)     next;
 };
 
@@ -146,6 +147,10 @@ static void usb_host_attach_kernel(USBHostDevice *s);
 #define BULK_TIMEOUT         0        /* unlimited */
 #define INTR_TIMEOUT         0        /* unlimited */
 
+#if LIBUSBX_API_VERSION >= 0x01000103
+# define HAVE_STREAMS 1
+#endif
+
 static const char *speed_name[] = {
     [LIBUSB_SPEED_UNKNOWN] = "?",
     [LIBUSB_SPEED_LOW]     = "1.5",
@@ -346,6 +351,13 @@ static void usb_host_req_complete_ctrl(struct libusb_transfer *xfer)
     r->p->actual_length = xfer->actual_length;
     if (r->in && xfer->actual_length) {
         memcpy(r->cbuf, r->buffer + 8, xfer->actual_length);
+
+        /* Fix up USB-3 ep0 maxpacket size to allow superspeed connected devices
+         * to work redirected to a not superspeed capable hcd */
+        if (r->usb3ep0quirk && xfer->actual_length >= 18 &&
+            r->cbuf[7] == 9) {
+            r->cbuf[7] = 64;
+        }
     }
     trace_usb_host_req_complete(s->bus_num, s->addr, r->p,
                                 r->p->status, r->p->actual_length);
@@ -672,11 +684,17 @@ static void usb_host_iso_data_out(USBHostDevice *s, USBPacket *p)
 
 /* ------------------------------------------------------------------------ */
 
-static bool usb_host_full_speed_compat(USBHostDevice *s)
+static void usb_host_speed_compat(USBHostDevice *s)
 {
+    USBDevice *udev = USB_DEVICE(s);
     struct libusb_config_descriptor *conf;
     const struct libusb_interface_descriptor *intf;
     const struct libusb_endpoint_descriptor *endp;
+#ifdef HAVE_STREAMS
+    struct libusb_ss_endpoint_companion_descriptor *endp_ss_comp;
+#endif
+    bool compat_high = true;
+    bool compat_full = true;
     uint8_t type;
     int rc, c, i, a, e;
 
@@ -693,10 +711,27 @@ static bool usb_host_full_speed_compat(USBHostDevice *s)
                     type = endp->bmAttributes & 0x3;
                     switch (type) {
                     case 0x01: /* ISO */
-                        return false;
+                        compat_full = false;
+                        compat_high = false;
+                        break;
+                    case 0x02: /* BULK */
+#ifdef HAVE_STREAMS
+                        rc = libusb_get_ss_endpoint_companion_descriptor
+                            (ctx, endp, &endp_ss_comp);
+                        if (rc == LIBUSB_SUCCESS) {
+                            libusb_free_ss_endpoint_companion_descriptor
+                                (endp_ss_comp);
+                            compat_full = false;
+                            compat_high = false;
+                        }
+#endif
+                        break;
                     case 0x03: /* INTERRUPT */
                         if (endp->wMaxPacketSize > 64) {
-                            return false;
+                            compat_full = false;
+                        }
+                        if (endp->wMaxPacketSize > 1024) {
+                            compat_high = false;
                         }
                         break;
                     }
@@ -705,7 +740,17 @@ static bool usb_host_full_speed_compat(USBHostDevice *s)
         }
         libusb_free_config_descriptor(conf);
     }
-    return true;
+
+    udev->speedmask = (1 << udev->speed);
+    if (udev->speed == USB_SPEED_SUPER && compat_high) {
+        udev->speedmask |= USB_SPEED_HIGH;
+    }
+    if (udev->speed == USB_SPEED_SUPER && compat_full) {
+        udev->speedmask |= USB_SPEED_FULL;
+    }
+    if (udev->speed == USB_SPEED_HIGH && compat_full) {
+        udev->speedmask |= USB_SPEED_FULL;
+    }
 }
 
 static void usb_host_ep_update(USBHostDevice *s)
@@ -720,6 +765,9 @@ static void usb_host_ep_update(USBHostDevice *s)
     struct libusb_config_descriptor *conf;
     const struct libusb_interface_descriptor *intf;
     const struct libusb_endpoint_descriptor *endp;
+#ifdef HAVE_STREAMS
+    struct libusb_ss_endpoint_companion_descriptor *endp_ss_comp;
+#endif
     uint8_t devep, type;
     int pid, ep;
     int rc, i, e;
@@ -765,6 +813,15 @@ static void usb_host_ep_update(USBHostDevice *s)
             usb_ep_set_type(udev, pid, ep, type);
             usb_ep_set_ifnum(udev, pid, ep, i);
             usb_ep_set_halted(udev, pid, ep, 0);
+#ifdef HAVE_STREAMS
+            if (type == LIBUSB_TRANSFER_TYPE_BULK &&
+                    libusb_get_ss_endpoint_companion_descriptor(ctx, endp,
+                        &endp_ss_comp) == LIBUSB_SUCCESS) {
+                usb_ep_set_max_streams(udev, pid, ep,
+                                       endp_ss_comp->bmAttributes);
+                libusb_free_ss_endpoint_companion_descriptor(endp_ss_comp);
+            }
+#endif
         }
     }
 
@@ -801,10 +858,7 @@ static int usb_host_open(USBHostDevice *s, libusb_device *dev)
     usb_host_ep_update(s);
 
     udev->speed     = speed_map[libusb_get_device_speed(dev)];
-    udev->speedmask = (1 << udev->speed);
-    if (udev->speed == USB_SPEED_HIGH && usb_host_full_speed_compat(s)) {
-        udev->speedmask |= USB_SPEED_MASK_FULL;
-    }
+    usb_host_speed_compat(s);
 
     if (s->ddesc.iProduct) {
         libusb_get_string_descriptor_ascii(s->dh, s->ddesc.iProduct,
@@ -1150,6 +1204,14 @@ static void usb_host_handle_control(USBDevice *udev, USBPacket *p,
         memcpy(r->buffer + 8, r->cbuf, r->clen);
     }
 
+    /* Fix up USB-3 ep0 maxpacket size to allow superspeed connected devices
+     * to work redirected to a not superspeed capable hcd */
+    if (udev->speed == USB_SPEED_SUPER &&
+        !((udev->port->speedmask & USB_SPEED_MASK_SUPER)) &&
+        request == 0x8006 && value == 0x100 && index == 0) {
+        r->usb3ep0quirk = true;
+    }
+
     libusb_fill_control_transfer(r->xfer, s->dh, r->buffer,
                                  usb_host_req_complete_ctrl, r,
                                  CONTROL_TIMEOUT);
@@ -1202,10 +1264,23 @@ static void usb_host_handle_data(USBDevice *udev, USBPacket *p)
             usb_packet_copy(p, r->buffer, size);
         }
         ep = p->ep->nr | (r->in ? USB_DIR_IN : 0);
-        libusb_fill_bulk_transfer(r->xfer, s->dh, ep,
-                                  r->buffer, size,
-                                  usb_host_req_complete_data, r,
-                                  BULK_TIMEOUT);
+        if (p->stream) {
+#ifdef HAVE_STREAMS
+            libusb_fill_bulk_stream_transfer(r->xfer, s->dh, ep, p->stream,
+                                             r->buffer, size,
+                                             usb_host_req_complete_data, r,
+                                             BULK_TIMEOUT);
+#else
+            usb_host_req_free(r);
+            p->status = USB_RET_STALL;
+            return;
+#endif
+        } else {
+            libusb_fill_bulk_transfer(r->xfer, s->dh, ep,
+                                      r->buffer, size,
+                                      usb_host_req_complete_data, r,
+                                      BULK_TIMEOUT);
+        }
         break;
     case USB_ENDPOINT_XFER_INT:
         r = usb_host_req_alloc(s, p, p->pid == USB_TOKEN_IN, p->iov.size);
@@ -1268,6 +1343,54 @@ static void usb_host_handle_reset(USBDevice *udev)
     }
 }
 
+static int usb_host_alloc_streams(USBDevice *udev, USBEndpoint **eps,
+                                  int nr_eps, int streams)
+{
+#ifdef HAVE_STREAMS
+    USBHostDevice *s = USB_HOST_DEVICE(udev);
+    unsigned char endpoints[30];
+    int i, rc;
+
+    for (i = 0; i < nr_eps; i++) {
+        endpoints[i] = eps[i]->nr;
+        if (eps[i]->pid == USB_TOKEN_IN) {
+            endpoints[i] |= 0x80;
+        }
+    }
+    rc = libusb_alloc_streams(s->dh, streams, endpoints, nr_eps);
+    if (rc < 0) {
+        usb_host_libusb_error("libusb_alloc_streams", rc);
+    } else if (rc != streams) {
+        fprintf(stderr,
+            "libusb_alloc_streams: got less streams then requested %d < %d\n",
+            rc, streams);
+    }
+
+    return (rc == streams) ? 0 : -1;
+#else
+    fprintf(stderr, "libusb_alloc_streams: error not implemented\n");
+    return -1;
+#endif
+}
+
+static void usb_host_free_streams(USBDevice *udev, USBEndpoint **eps,
+                                  int nr_eps)
+{
+#ifdef HAVE_STREAMS
+    USBHostDevice *s = USB_HOST_DEVICE(udev);
+    unsigned char endpoints[30];
+    int i;
+
+    for (i = 0; i < nr_eps; i++) {
+        endpoints[i] = eps[i]->nr;
+        if (eps[i]->pid == USB_TOKEN_IN) {
+            endpoints[i] |= 0x80;
+        }
+    }
+    libusb_free_streams(s->dh, endpoints, nr_eps);
+#endif
+}
+
 /*
  * This is *NOT* about restoring state.  We have absolutely no idea
  * what state the host device is in at the moment and whenever it is
@@ -1349,6 +1472,8 @@ static void usb_host_class_initfn(ObjectClass *klass, void *data)
     uc->handle_reset   = usb_host_handle_reset;
     uc->handle_destroy = usb_host_handle_destroy;
     uc->flush_ep_queue = usb_host_flush_ep_queue;
+    uc->alloc_streams  = usb_host_alloc_streams;
+    uc->free_streams   = usb_host_free_streams;
     dc->vmsd = &vmstate_usb_host;
     dc->props = usb_host_dev_properties;
     set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
index 287a505b48..4c6187bebd 100644
--- a/hw/usb/redirect.c
+++ b/hw/usb/redirect.c
@@ -50,6 +50,10 @@
                        ((i) & 0x10) ? USB_TOKEN_IN : USB_TOKEN_OUT, \
                        (i) & 0x0f))
 
+#ifndef USBREDIR_VERSION /* This is not defined in older usbredir versions */
+#define USBREDIR_VERSION 0
+#endif
+
 typedef struct USBRedirDevice USBRedirDevice;
 
 /* Struct to hold buffered packets */
@@ -68,6 +72,7 @@ struct endp_data {
     uint8_t interval;
     uint8_t interface; /* bInterfaceNumber this ep belongs to */
     uint16_t max_packet_size; /* In bytes, not wMaxPacketSize format !! */
+    uint32_t max_streams;
     uint8_t iso_started;
     uint8_t iso_error; /* For reporting iso errors to the HC */
     uint8_t interrupt_started;
@@ -106,8 +111,9 @@ struct USBRedirDevice {
     int read_buf_size;
     /* Active chardev-watch-tag */
     guint watch;
-    /* For async handling of close */
+    /* For async handling of close / reject */
     QEMUBH *chardev_close_bh;
+    QEMUBH *device_reject_bh;
     /* To delay the usb attach in case of quick chardev close + open */
     QEMUTimer *attach_timer;
     int64_t next_attach_time;
@@ -780,11 +786,12 @@ static void usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p,
         dev->endpoint[EP2I(ep)].bulk_receiving_enabled = 0;
     }
 
-    DPRINTF("bulk-out ep %02X len %zd id %"PRIu64"\n", ep, size, p->id);
+    DPRINTF("bulk-out ep %02X stream %u len %zd id %"PRIu64"\n",
+            ep, p->stream, size, p->id);
 
     bulk_packet.endpoint  = ep;
     bulk_packet.length    = size;
-    bulk_packet.stream_id = 0;
+    bulk_packet.stream_id = p->stream;
     bulk_packet.length_high = size >> 16;
     assert(bulk_packet.length_high == 0 ||
            usbredirparser_peer_has_cap(dev->parser,
@@ -1091,6 +1098,66 @@ static void usbredir_handle_control(USBDevice *udev, USBPacket *p,
     p->status = USB_RET_ASYNC;
 }
 
+static int usbredir_alloc_streams(USBDevice *udev, USBEndpoint **eps,
+                                  int nr_eps, int streams)
+{
+    USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev);
+#if USBREDIR_VERSION >= 0x000700
+    struct usb_redir_alloc_bulk_streams_header alloc_streams;
+    int i;
+
+    if (!usbredirparser_peer_has_cap(dev->parser,
+                                     usb_redir_cap_bulk_streams)) {
+        ERROR("peer does not support streams\n");
+        goto reject;
+    }
+
+    if (streams == 0) {
+        ERROR("request to allocate 0 streams\n");
+        return -1;
+    }
+
+    alloc_streams.no_streams = streams;
+    alloc_streams.endpoints = 0;
+    for (i = 0; i < nr_eps; i++) {
+        alloc_streams.endpoints |= 1 << USBEP2I(eps[i]);
+    }
+    usbredirparser_send_alloc_bulk_streams(dev->parser, 0, &alloc_streams);
+    usbredirparser_do_write(dev->parser);
+
+    return 0;
+#else
+    ERROR("usbredir_alloc_streams not implemented\n");
+    goto reject;
+#endif
+reject:
+    ERROR("streams are not available, disconnecting\n");
+    qemu_bh_schedule(dev->device_reject_bh);
+    return -1;
+}
+
+static void usbredir_free_streams(USBDevice *udev, USBEndpoint **eps,
+                                  int nr_eps)
+{
+#if USBREDIR_VERSION >= 0x000700
+    USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev);
+    struct usb_redir_free_bulk_streams_header free_streams;
+    int i;
+
+    if (!usbredirparser_peer_has_cap(dev->parser,
+                                     usb_redir_cap_bulk_streams)) {
+        return;
+    }
+
+    free_streams.endpoints = 0;
+    for (i = 0; i < nr_eps; i++) {
+        free_streams.endpoints |= 1 << USBEP2I(eps[i]);
+    }
+    usbredirparser_send_free_bulk_streams(dev->parser, 0, &free_streams);
+    usbredirparser_do_write(dev->parser);
+#endif
+}
+
 /*
  * Close events can be triggered by usbredirparser_do_write which gets called
  * from within the USBDevice data / control packet callbacks and doing a
@@ -1102,6 +1169,7 @@ static void usbredir_chardev_close_bh(void *opaque)
 {
     USBRedirDevice *dev = opaque;
 
+    qemu_bh_cancel(dev->device_reject_bh);
     usbredir_device_disconnect(dev);
 
     if (dev->parser) {
@@ -1153,6 +1221,9 @@ static void usbredir_create_parser(USBRedirDevice *dev)
     usbredirparser_caps_set_cap(caps, usb_redir_cap_64bits_ids);
     usbredirparser_caps_set_cap(caps, usb_redir_cap_32bits_bulk_length);
     usbredirparser_caps_set_cap(caps, usb_redir_cap_bulk_receiving);
+#if USBREDIR_VERSION >= 0x000700
+    usbredirparser_caps_set_cap(caps, usb_redir_cap_bulk_streams);
+#endif
 
     if (runstate_check(RUN_STATE_INMIGRATE)) {
         flags |= usbredirparser_fl_no_hello;
@@ -1171,6 +1242,17 @@ static void usbredir_reject_device(USBRedirDevice *dev)
     }
 }
 
+/*
+ * We may need to reject the device when the hcd calls alloc_streams, doing
+ * an usb_detach from within a hcd call is not a good idea, hence this bh.
+ */
+static void usbredir_device_reject_bh(void *opaque)
+{
+    USBRedirDevice *dev = opaque;
+
+    usbredir_reject_device(dev);
+}
+
 static void usbredir_do_attach(void *opaque)
 {
     USBRedirDevice *dev = opaque;
@@ -1297,6 +1379,7 @@ static int usbredir_initfn(USBDevice *udev)
     }
 
     dev->chardev_close_bh = qemu_bh_new(usbredir_chardev_close_bh, dev);
+    dev->device_reject_bh = qemu_bh_new(usbredir_device_reject_bh, dev);
     dev->attach_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, usbredir_do_attach, dev);
 
     packet_id_queue_init(&dev->cancelled, dev, "cancelled");
@@ -1337,6 +1420,7 @@ static void usbredir_handle_destroy(USBDevice *udev)
     dev->cs = NULL;
     /* Note must be done after qemu_chr_close, as that causes a close event */
     qemu_bh_delete(dev->chardev_close_bh);
+    qemu_bh_delete(dev->device_reject_bh);
 
     timer_del(dev->attach_timer);
     timer_free(dev->attach_timer);
@@ -1628,6 +1712,7 @@ static void usbredir_setup_usb_eps(USBRedirDevice *dev)
         usb_ep->type = dev->endpoint[i].type;
         usb_ep->ifnum = dev->endpoint[i].interface;
         usb_ep->max_packet_size = dev->endpoint[i].max_packet_size;
+        usb_ep->max_streams = dev->endpoint[i].max_streams;
         usbredir_set_pipeline(dev, usb_ep);
     }
 }
@@ -1646,6 +1731,12 @@ static void usbredir_ep_info(void *priv,
                                      usb_redir_cap_ep_info_max_packet_size)) {
             dev->endpoint[i].max_packet_size = ep_info->max_packet_size[i];
         }
+#if USBREDIR_VERSION >= 0x000700
+        if (usbredirparser_peer_has_cap(dev->parser,
+                                        usb_redir_cap_bulk_streams)) {
+            dev->endpoint[i].max_streams = ep_info->max_streams[i];
+        }
+#endif
         switch (dev->endpoint[i].type) {
         case usb_redir_type_invalid:
             break;
@@ -1779,6 +1870,20 @@ static void usbredir_interrupt_receiving_status(void *priv, uint64_t id,
 static void usbredir_bulk_streams_status(void *priv, uint64_t id,
     struct usb_redir_bulk_streams_status_header *bulk_streams_status)
 {
+#if USBREDIR_VERSION >= 0x000700
+    USBRedirDevice *dev = priv;
+
+    if (bulk_streams_status->status == usb_redir_success) {
+        DPRINTF("bulk streams status %d eps %08x\n",
+                bulk_streams_status->status, bulk_streams_status->endpoints);
+    } else {
+        ERROR("bulk streams %s failed status %d eps %08x\n",
+              (bulk_streams_status->no_streams == 0) ? "free" : "alloc",
+              bulk_streams_status->status, bulk_streams_status->endpoints);
+        ERROR("usb-redir-host does not provide streams, disconnecting\n");
+        usbredir_reject_device(dev);
+    }
+#endif
 }
 
 static void usbredir_bulk_receiving_status(void *priv, uint64_t id,
@@ -1850,8 +1955,8 @@ static void usbredir_bulk_packet(void *priv, uint64_t id,
     int len = (bulk_packet->length_high << 16) | bulk_packet->length;
     USBPacket *p;
 
-    DPRINTF("bulk-in status %d ep %02X len %d id %"PRIu64"\n",
-            bulk_packet->status, ep, len, id);
+    DPRINTF("bulk-in status %d ep %02X stream %u len %d id %"PRIu64"\n",
+            bulk_packet->status, ep, bulk_packet->stream_id, len, id);
 
     p = usbredir_find_packet_by_id(dev, ep, id);
     if (p) {
@@ -2165,6 +2270,23 @@ static bool usbredir_bulk_receiving_needed(void *priv)
     return endp->bulk_receiving_started;
 }
 
+static const VMStateDescription usbredir_stream_vmstate = {
+    .name = "usb-redir-ep/stream-state",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(max_streams, struct endp_data),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static bool usbredir_stream_needed(void *priv)
+{
+    struct endp_data *endp = priv;
+
+    return endp->max_streams;
+}
+
 static const VMStateDescription usbredir_ep_vmstate = {
     .name = "usb-redir-ep",
     .version_id = 1,
@@ -2197,6 +2319,9 @@ static const VMStateDescription usbredir_ep_vmstate = {
             .vmsd = &usbredir_bulk_receiving_vmstate,
             .needed = usbredir_bulk_receiving_needed,
         }, {
+            .vmsd = &usbredir_stream_vmstate,
+            .needed = usbredir_stream_needed,
+        }, {
             /* empty */
         }
     }
@@ -2361,6 +2486,8 @@ static void usbredir_class_initfn(ObjectClass *klass, void *data)
     uc->handle_control = usbredir_handle_control;
     uc->flush_ep_queue = usbredir_flush_ep_queue;
     uc->ep_stopped     = usbredir_ep_stopped;
+    uc->alloc_streams  = usbredir_alloc_streams;
+    uc->free_streams   = usbredir_free_streams;
     dc->vmsd           = &usbredir_vmstate;
     dc->props          = usbredir_properties;
     set_bit(DEVICE_CATEGORY_MISC, dc->categories);
diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c
index 971a921777..bf2b588b24 100644
--- a/hw/virtio/virtio-balloon.c
+++ b/hw/virtio/virtio-balloon.c
@@ -108,6 +108,7 @@ static void balloon_stats_poll_cb(void *opaque)
 static void balloon_stats_get_all(Object *obj, struct Visitor *v,
                                   void *opaque, const char *name, Error **errp)
 {
+    Error *err = NULL;
     VirtIOBalloon *s = opaque;
     int i;
 
@@ -116,17 +117,33 @@ static void balloon_stats_get_all(Object *obj, struct Visitor *v,
         return;
     }
 
-    visit_start_struct(v, NULL, "guest-stats", name, 0, errp);
-    visit_type_int(v, &s->stats_last_update, "last-update", errp);
+    visit_start_struct(v, NULL, "guest-stats", name, 0, &err);
+    if (err) {
+        goto out;
+    }
+    visit_type_int(v, &s->stats_last_update, "last-update", &err);
+    if (err) {
+        goto out_end;
+    }
 
-    visit_start_struct(v, NULL, NULL, "stats", 0, errp);
-    for (i = 0; i < VIRTIO_BALLOON_S_NR; i++) {
+    visit_start_struct(v, NULL, NULL, "stats", 0, &err);
+    if (err) {
+        goto out_end;
+    }
+    for (i = 0; !err && i < VIRTIO_BALLOON_S_NR; i++) {
         visit_type_int64(v, (int64_t *) &s->stats[i], balloon_stat_names[i],
-                         errp);
+                         &err);
     }
-    visit_end_struct(v, errp);
-
-    visit_end_struct(v, errp);
+    error_propagate(errp, err);
+    err = NULL;
+    visit_end_struct(v, &err);
+
+out_end:
+    error_propagate(errp, err);
+    err = NULL;
+    visit_end_struct(v, &err);
+out:
+    error_propagate(errp, err);
 }
 
 static void balloon_stats_get_poll_interval(Object *obj, struct Visitor *v,
diff --git a/hw/xenpv/xen_machine_pv.c b/hw/xenpv/xen_machine_pv.c
index 9adb57fc14..31500643a2 100644
--- a/hw/xenpv/xen_machine_pv.c
+++ b/hw/xenpv/xen_machine_pv.c
@@ -28,11 +28,11 @@
 #include "xen_domainbuild.h"
 #include "sysemu/blockdev.h"
 
-static void xen_init_pv(QEMUMachineInitArgs *args)
+static void xen_init_pv(MachineState *machine)
 {
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
-    const char *initrd_filename = args->initrd_filename;
+    const char *kernel_filename = machine->kernel_filename;
+    const char *kernel_cmdline = machine->kernel_cmdline;
+    const char *initrd_filename = machine->initrd_filename;
     DriveInfo *dinfo;
     int i;
 
diff --git a/hw/xtensa/xtensa_lx60.c b/hw/xtensa/xtensa_lx60.c
index 49c58d11a3..507dd88452 100644
--- a/hw/xtensa/xtensa_lx60.c
+++ b/hw/xtensa/xtensa_lx60.c
@@ -159,7 +159,7 @@ static void lx60_reset(void *opaque)
     cpu_reset(CPU(cpu));
 }
 
-static void lx_init(const LxBoardDesc *board, QEMUMachineInitArgs *args)
+static void lx_init(const LxBoardDesc *board, MachineState *machine)
 {
 #ifdef TARGET_WORDS_BIGENDIAN
     int be = 1;
@@ -172,9 +172,9 @@ static void lx_init(const LxBoardDesc *board, QEMUMachineInitArgs *args)
     MemoryRegion *ram, *rom, *system_io;
     DriveInfo *dinfo;
     pflash_t *flash = NULL;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
-    const char *kernel_cmdline = args->kernel_cmdline;
+    const char *cpu_model = machine->cpu_model;
+    const char *kernel_filename = machine->kernel_filename;
+    const char *kernel_cmdline = machine->kernel_cmdline;
     int n;
 
     if (!cpu_model) {
@@ -198,7 +198,7 @@ static void lx_init(const LxBoardDesc *board, QEMUMachineInitArgs *args)
     }
 
     ram = g_malloc(sizeof(*ram));
-    memory_region_init_ram(ram, NULL, "lx60.dram", args->ram_size);
+    memory_region_init_ram(ram, NULL, "lx60.dram", machine->ram_size);
     vmstate_register_ram_global(ram);
     memory_region_add_subregion(system_memory, 0, ram);
 
@@ -275,7 +275,7 @@ static void lx_init(const LxBoardDesc *board, QEMUMachineInitArgs *args)
     }
 }
 
-static void xtensa_lx60_init(QEMUMachineInitArgs *args)
+static void xtensa_lx60_init(MachineState *machine)
 {
     static const LxBoardDesc lx60_board = {
         .flash_base = 0xf8000000,
@@ -283,10 +283,10 @@ static void xtensa_lx60_init(QEMUMachineInitArgs *args)
         .flash_sector_size = 0x10000,
         .sram_size = 0x20000,
     };
-    lx_init(&lx60_board, args);
+    lx_init(&lx60_board, machine);
 }
 
-static void xtensa_lx200_init(QEMUMachineInitArgs *args)
+static void xtensa_lx200_init(MachineState *machine)
 {
     static const LxBoardDesc lx200_board = {
         .flash_base = 0xf8000000,
@@ -294,10 +294,10 @@ static void xtensa_lx200_init(QEMUMachineInitArgs *args)
         .flash_sector_size = 0x20000,
         .sram_size = 0x2000000,
     };
-    lx_init(&lx200_board, args);
+    lx_init(&lx200_board, machine);
 }
 
-static void xtensa_ml605_init(QEMUMachineInitArgs *args)
+static void xtensa_ml605_init(MachineState *machine)
 {
     static const LxBoardDesc ml605_board = {
         .flash_base = 0xf8000000,
@@ -305,10 +305,10 @@ static void xtensa_ml605_init(QEMUMachineInitArgs *args)
         .flash_sector_size = 0x20000,
         .sram_size = 0x2000000,
     };
-    lx_init(&ml605_board, args);
+    lx_init(&ml605_board, machine);
 }
 
-static void xtensa_kc705_init(QEMUMachineInitArgs *args)
+static void xtensa_kc705_init(MachineState *machine)
 {
     static const LxBoardDesc kc705_board = {
         .flash_base = 0xf0000000,
@@ -316,7 +316,7 @@ static void xtensa_kc705_init(QEMUMachineInitArgs *args)
         .flash_sector_size = 0x20000,
         .sram_size = 0x2000000,
     };
-    lx_init(&kc705_board, args);
+    lx_init(&kc705_board, machine);
 }
 
 static QEMUMachine xtensa_lx60_machine = {
diff --git a/hw/xtensa/xtensa_sim.c b/hw/xtensa/xtensa_sim.c
index 1192ce7134..89da43c160 100644
--- a/hw/xtensa/xtensa_sim.c
+++ b/hw/xtensa/xtensa_sim.c
@@ -46,14 +46,14 @@ static void sim_reset(void *opaque)
     cpu_reset(CPU(cpu));
 }
 
-static void xtensa_sim_init(QEMUMachineInitArgs *args)
+static void xtensa_sim_init(MachineState *machine)
 {
     XtensaCPU *cpu = NULL;
     CPUXtensaState *env = NULL;
     MemoryRegion *ram, *rom;
-    ram_addr_t ram_size = args->ram_size;
-    const char *cpu_model = args->cpu_model;
-    const char *kernel_filename = args->kernel_filename;
+    ram_addr_t ram_size = machine->ram_size;
+    const char *cpu_model = machine->cpu_model;
+    const char *kernel_filename = machine->kernel_filename;
     int n;
 
     if (!cpu_model) {
diff --git a/include/block/block.h b/include/block/block.h
index 1b119aac24..faee3aa246 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -120,6 +120,8 @@ typedef enum {
 /* BDRV_BLOCK_DATA: data is read from bs->file or another file
  * BDRV_BLOCK_ZERO: sectors read as zero
  * BDRV_BLOCK_OFFSET_VALID: sector stored in bs->file as raw data
+ * BDRV_BLOCK_ALLOCATED: the content of the block is determined by this
+ *                       layer (as opposed to the backing file)
  * BDRV_BLOCK_RAW: used internally to indicate that the request
  *                 was answered by the raw driver and that one
  *                 should look in bs->file directly.
@@ -141,10 +143,11 @@ typedef enum {
  *  f    t        f       not allocated or unknown offset, read as zero
  *  f    f        f       not allocated or unknown offset, read from backing_hd
  */
-#define BDRV_BLOCK_DATA         1
-#define BDRV_BLOCK_ZERO         2
-#define BDRV_BLOCK_OFFSET_VALID 4
-#define BDRV_BLOCK_RAW          8
+#define BDRV_BLOCK_DATA         0x01
+#define BDRV_BLOCK_ZERO         0x02
+#define BDRV_BLOCK_OFFSET_VALID 0x04
+#define BDRV_BLOCK_RAW          0x08
+#define BDRV_BLOCK_ALLOCATED    0x10
 #define BDRV_BLOCK_OFFSET_MASK  BDRV_SECTOR_MASK
 
 typedef enum {
@@ -159,6 +162,25 @@ typedef struct BDRVReopenState {
     void *opaque;
 } BDRVReopenState;
 
+/*
+ * Block operation types
+ */
+typedef enum BlockOpType {
+    BLOCK_OP_TYPE_BACKUP_SOURCE,
+    BLOCK_OP_TYPE_BACKUP_TARGET,
+    BLOCK_OP_TYPE_CHANGE,
+    BLOCK_OP_TYPE_COMMIT,
+    BLOCK_OP_TYPE_DATAPLANE,
+    BLOCK_OP_TYPE_DRIVE_DEL,
+    BLOCK_OP_TYPE_EJECT,
+    BLOCK_OP_TYPE_EXTERNAL_SNAPSHOT,
+    BLOCK_OP_TYPE_INTERNAL_SNAPSHOT,
+    BLOCK_OP_TYPE_INTERNAL_SNAPSHOT_DELETE,
+    BLOCK_OP_TYPE_MIRROR,
+    BLOCK_OP_TYPE_RESIZE,
+    BLOCK_OP_TYPE_STREAM,
+    BLOCK_OP_TYPE_MAX,
+} BlockOpType;
 
 void bdrv_iostatus_enable(BlockDriverState *bs);
 void bdrv_iostatus_reset(BlockDriverState *bs);
@@ -194,6 +216,7 @@ int bdrv_parse_discard_flags(const char *mode, int *flags);
 int bdrv_open_image(BlockDriverState **pbs, const char *filename,
                     QDict *options, const char *bdref_key, int flags,
                     bool allow_none, Error **errp);
+void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd);
 int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp);
 void bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp);
 int bdrv_open(BlockDriverState **pbs, const char *filename,
@@ -450,8 +473,13 @@ void bdrv_disable_copy_on_read(BlockDriverState *bs);
 
 void bdrv_ref(BlockDriverState *bs);
 void bdrv_unref(BlockDriverState *bs);
-void bdrv_set_in_use(BlockDriverState *bs, int in_use);
-int bdrv_in_use(BlockDriverState *bs);
+
+bool bdrv_op_is_blocked(BlockDriverState *bs, BlockOpType op, Error **errp);
+void bdrv_op_block(BlockDriverState *bs, BlockOpType op, Error *reason);
+void bdrv_op_unblock(BlockDriverState *bs, BlockOpType op, Error *reason);
+void bdrv_op_block_all(BlockDriverState *bs, Error *reason);
+void bdrv_op_unblock_all(BlockDriverState *bs, Error *reason);
+bool bdrv_op_blocker_is_empty(BlockDriverState *bs);
 
 #ifdef CONFIG_LINUX_AIO
 int raw_get_aio_fd(BlockDriverState *bs);
diff --git a/include/block/block_int.h b/include/block/block_int.h
index 9ffcb698d0..f2e753f632 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -270,6 +270,8 @@ typedef struct BlockLimits {
     size_t opt_mem_alignment;
 } BlockLimits;
 
+typedef struct BdrvOpBlocker BdrvOpBlocker;
+
 /*
  * Note: the function bdrv_append() copies and swaps contents of
  * BlockDriverStates, so if you add new fields to this struct, please
@@ -356,14 +358,20 @@ struct BlockDriverState {
     QTAILQ_ENTRY(BlockDriverState) device_list;
     QLIST_HEAD(, BdrvDirtyBitmap) dirty_bitmaps;
     int refcnt;
-    int in_use; /* users other than guest access, eg. block migration */
 
     QLIST_HEAD(, BdrvTrackedRequest) tracked_requests;
 
+    /* operation blockers */
+    QLIST_HEAD(, BdrvOpBlocker) op_blockers[BLOCK_OP_TYPE_MAX];
+
     /* long-running background operation */
     BlockJob *job;
 
     QDict *options;
+    BlockdevDetectZeroesOptions detect_zeroes;
+
+    /* The error object in use for blocking operations on backing_hd */
+    Error *backing_blocker;
 };
 
 int get_tmp_filename(char *filename, int size);
diff --git a/include/block/blockjob.h b/include/block/blockjob.h
index d76de62a46..c0a787530b 100644
--- a/include/block/blockjob.h
+++ b/include/block/blockjob.h
@@ -106,6 +106,9 @@ struct BlockJob {
     /** The completion function that will be called when the job completes.  */
     BlockDriverCompletionFunc *cb;
 
+    /** Block other operations when block job is running */
+    Error *blocker;
+
     /** The opaque value that is passed to the completion function.  */
     void *opaque;
 };
diff --git a/include/exec/def-helper.h b/include/exec/def-helper.h
deleted file mode 100644
index 255b58bb03..0000000000
--- a/include/exec/def-helper.h
+++ /dev/null
@@ -1,274 +0,0 @@
-/* Helper file for declaring TCG helper functions.
-   Should be included at the start and end of target-foo/helper.h.
-
-   Targets should use DEF_HELPER_N and DEF_HELPER_FLAGS_N to declare helper
-   functions.  Names should be specified without the helper_ prefix, and
-   the return and argument types specified.  3 basic types are understood
-   (i32, i64 and ptr).  Additional aliases are provided for convenience and
-   to match the types used by the C helper implementation.
-
-   The target helper.h should be included in all files that use/define
-   helper functions.  THis will ensure that function prototypes are
-   consistent.  In addition it should be included an extra two times for
-   helper.c, defining:
-    GEN_HELPER 1 to produce op generation functions (gen_helper_*)
-    GEN_HELPER 2 to do runtime registration helper functions.
- */
-
-#ifndef DEF_HELPER_H
-#define DEF_HELPER_H 1
-
-#define HELPER(name) glue(helper_, name)
-
-#define GET_TCGV_i32 GET_TCGV_I32
-#define GET_TCGV_i64 GET_TCGV_I64
-#define GET_TCGV_ptr GET_TCGV_PTR
-
-/* Some types that make sense in C, but not for TCG.  */
-#define dh_alias_i32 i32
-#define dh_alias_s32 i32
-#define dh_alias_int i32
-#define dh_alias_i64 i64
-#define dh_alias_s64 i64
-#define dh_alias_f32 i32
-#define dh_alias_f64 i64
-#if TARGET_LONG_BITS == 32
-#define dh_alias_tl i32
-#else
-#define dh_alias_tl i64
-#endif
-#define dh_alias_ptr ptr
-#define dh_alias_void void
-#define dh_alias_noreturn noreturn
-#define dh_alias_env ptr
-#define dh_alias(t) glue(dh_alias_, t)
-
-#define dh_ctype_i32 uint32_t
-#define dh_ctype_s32 int32_t
-#define dh_ctype_int int
-#define dh_ctype_i64 uint64_t
-#define dh_ctype_s64 int64_t
-#define dh_ctype_f32 float32
-#define dh_ctype_f64 float64
-#define dh_ctype_tl target_ulong
-#define dh_ctype_ptr void *
-#define dh_ctype_void void
-#define dh_ctype_noreturn void QEMU_NORETURN
-#define dh_ctype_env CPUArchState *
-#define dh_ctype(t) dh_ctype_##t
-
-/* We can't use glue() here because it falls foul of C preprocessor
-   recursive expansion rules.  */
-#define dh_retvar_decl0_void void
-#define dh_retvar_decl0_noreturn void
-#define dh_retvar_decl0_i32 TCGv_i32 retval
-#define dh_retvar_decl0_i64 TCGv_i64 retval
-#define dh_retvar_decl0_ptr TCGv_ptr retval
-#define dh_retvar_decl0(t) glue(dh_retvar_decl0_, dh_alias(t))
-
-#define dh_retvar_decl_void
-#define dh_retvar_decl_noreturn
-#define dh_retvar_decl_i32 TCGv_i32 retval,
-#define dh_retvar_decl_i64 TCGv_i64 retval,
-#define dh_retvar_decl_ptr TCGv_ptr retval,
-#define dh_retvar_decl(t) glue(dh_retvar_decl_, dh_alias(t))
-
-#define dh_retvar_void TCG_CALL_DUMMY_ARG
-#define dh_retvar_noreturn TCG_CALL_DUMMY_ARG
-#define dh_retvar_i32 GET_TCGV_i32(retval)
-#define dh_retvar_i64 GET_TCGV_i64(retval)
-#define dh_retvar_ptr GET_TCGV_ptr(retval)
-#define dh_retvar(t) glue(dh_retvar_, dh_alias(t))
-
-#define dh_is_64bit_void 0
-#define dh_is_64bit_noreturn 0
-#define dh_is_64bit_i32 0
-#define dh_is_64bit_i64 1
-#define dh_is_64bit_ptr (sizeof(void *) == 8)
-#define dh_is_64bit(t) glue(dh_is_64bit_, dh_alias(t))
-
-#define dh_is_signed_void 0
-#define dh_is_signed_noreturn 0
-#define dh_is_signed_i32 0
-#define dh_is_signed_s32 1
-#define dh_is_signed_i64 0
-#define dh_is_signed_s64 1
-#define dh_is_signed_f32 0
-#define dh_is_signed_f64 0
-#define dh_is_signed_tl  0
-#define dh_is_signed_int 1
-/* ??? This is highly specific to the host cpu.  There are even special
-   extension instructions that may be required, e.g. ia64's addp4.  But
-   for now we don't support any 64-bit targets with 32-bit pointers.  */
-#define dh_is_signed_ptr 0
-#define dh_is_signed_env dh_is_signed_ptr
-#define dh_is_signed(t) dh_is_signed_##t
-
-#define dh_sizemask(t, n) \
-  sizemask |= dh_is_64bit(t) << (n*2); \
-  sizemask |= dh_is_signed(t) << (n*2+1)
-
-#define dh_arg(t, n) \
-  args[n - 1] = glue(GET_TCGV_, dh_alias(t))(glue(arg, n)); \
-  dh_sizemask(t, n)
-
-#define dh_arg_decl(t, n) glue(TCGv_, dh_alias(t)) glue(arg, n)
-
-
-#define DEF_HELPER_0(name, ret) \
-    DEF_HELPER_FLAGS_0(name, 0, ret)
-#define DEF_HELPER_1(name, ret, t1) \
-    DEF_HELPER_FLAGS_1(name, 0, ret, t1)
-#define DEF_HELPER_2(name, ret, t1, t2) \
-    DEF_HELPER_FLAGS_2(name, 0, ret, t1, t2)
-#define DEF_HELPER_3(name, ret, t1, t2, t3) \
-    DEF_HELPER_FLAGS_3(name, 0, ret, t1, t2, t3)
-#define DEF_HELPER_4(name, ret, t1, t2, t3, t4) \
-    DEF_HELPER_FLAGS_4(name, 0, ret, t1, t2, t3, t4)
-#define DEF_HELPER_5(name, ret, t1, t2, t3, t4, t5) \
-    DEF_HELPER_FLAGS_5(name, 0, ret, t1, t2, t3, t4, t5)
-
-/* MAX_OPC_PARAM_IARGS must be set to n if last entry is DEF_HELPER_FLAGS_n. */
-
-#endif /* DEF_HELPER_H */
-
-#ifndef GEN_HELPER
-/* Function prototypes.  */
-
-#define DEF_HELPER_FLAGS_0(name, flags, ret) \
-dh_ctype(ret) HELPER(name) (void);
-
-#define DEF_HELPER_FLAGS_1(name, flags, ret, t1) \
-dh_ctype(ret) HELPER(name) (dh_ctype(t1));
-
-#define DEF_HELPER_FLAGS_2(name, flags, ret, t1, t2) \
-dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2));
-
-#define DEF_HELPER_FLAGS_3(name, flags, ret, t1, t2, t3) \
-dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2), dh_ctype(t3));
-
-#define DEF_HELPER_FLAGS_4(name, flags, ret, t1, t2, t3, t4) \
-dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2), dh_ctype(t3), \
-                                   dh_ctype(t4));
-
-#define DEF_HELPER_FLAGS_5(name, flags, ret, t1, t2, t3, t4, t5) \
-dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2), dh_ctype(t3), \
-                            dh_ctype(t4), dh_ctype(t5));
-
-#undef GEN_HELPER
-#define GEN_HELPER -1
-
-#elif GEN_HELPER == 1
-/* Gen functions.  */
-
-#define DEF_HELPER_FLAGS_0(name, flags, ret) \
-static inline void glue(gen_helper_, name)(dh_retvar_decl0(ret)) \
-{ \
-  int sizemask; \
-  sizemask = dh_is_64bit(ret); \
-  tcg_gen_helperN(HELPER(name), flags, sizemask, dh_retvar(ret), 0, NULL); \
-}
-
-#define DEF_HELPER_FLAGS_1(name, flags, ret, t1) \
-static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) dh_arg_decl(t1, 1)) \
-{ \
-  TCGArg args[1]; \
-  int sizemask = 0; \
-  dh_sizemask(ret, 0); \
-  dh_arg(t1, 1); \
-  tcg_gen_helperN(HELPER(name), flags, sizemask, dh_retvar(ret), 1, args); \
-}
-
-#define DEF_HELPER_FLAGS_2(name, flags, ret, t1, t2) \
-static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) dh_arg_decl(t1, 1), \
-    dh_arg_decl(t2, 2)) \
-{ \
-  TCGArg args[2]; \
-  int sizemask = 0; \
-  dh_sizemask(ret, 0); \
-  dh_arg(t1, 1); \
-  dh_arg(t2, 2); \
-  tcg_gen_helperN(HELPER(name), flags, sizemask, dh_retvar(ret), 2, args); \
-}
-
-#define DEF_HELPER_FLAGS_3(name, flags, ret, t1, t2, t3) \
-static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) dh_arg_decl(t1, 1), \
-    dh_arg_decl(t2, 2), dh_arg_decl(t3, 3)) \
-{ \
-  TCGArg args[3]; \
-  int sizemask = 0; \
-  dh_sizemask(ret, 0); \
-  dh_arg(t1, 1); \
-  dh_arg(t2, 2); \
-  dh_arg(t3, 3); \
-  tcg_gen_helperN(HELPER(name), flags, sizemask, dh_retvar(ret), 3, args); \
-}
-
-#define DEF_HELPER_FLAGS_4(name, flags, ret, t1, t2, t3, t4) \
-static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) dh_arg_decl(t1, 1), \
-    dh_arg_decl(t2, 2), dh_arg_decl(t3, 3), dh_arg_decl(t4, 4)) \
-{ \
-  TCGArg args[4]; \
-  int sizemask = 0; \
-  dh_sizemask(ret, 0); \
-  dh_arg(t1, 1); \
-  dh_arg(t2, 2); \
-  dh_arg(t3, 3); \
-  dh_arg(t4, 4); \
-  tcg_gen_helperN(HELPER(name), flags, sizemask, dh_retvar(ret), 4, args); \
-}
-
-#define DEF_HELPER_FLAGS_5(name, flags, ret, t1, t2, t3, t4, t5) \
-static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) \
-    dh_arg_decl(t1, 1),  dh_arg_decl(t2, 2), dh_arg_decl(t3, 3), \
-    dh_arg_decl(t4, 4), dh_arg_decl(t5, 5)) \
-{ \
-  TCGArg args[5]; \
-  int sizemask = 0; \
-  dh_sizemask(ret, 0); \
-  dh_arg(t1, 1); \
-  dh_arg(t2, 2); \
-  dh_arg(t3, 3); \
-  dh_arg(t4, 4); \
-  dh_arg(t5, 5); \
-  tcg_gen_helperN(HELPER(name), flags, sizemask, dh_retvar(ret), 5, args); \
-}
-
-#undef GEN_HELPER
-#define GEN_HELPER -1
-
-#elif GEN_HELPER == 2
-/* Register helpers.  */
-
-#define DEF_HELPER_FLAGS_0(name, flags, ret)  { HELPER(name), #name },
-
-#define DEF_HELPER_FLAGS_1(name, flags, ret, t1) \
-DEF_HELPER_FLAGS_0(name, flags, ret)
-
-#define DEF_HELPER_FLAGS_2(name, flags, ret, t1, t2) \
-DEF_HELPER_FLAGS_0(name, flags, ret)
-
-#define DEF_HELPER_FLAGS_3(name, flags, ret, t1, t2, t3) \
-DEF_HELPER_FLAGS_0(name, flags, ret)
-
-#define DEF_HELPER_FLAGS_4(name, flags, ret, t1, t2, t3, t4) \
-DEF_HELPER_FLAGS_0(name, flags, ret)
-
-#define DEF_HELPER_FLAGS_5(name, flags, ret, t1, t2, t3, t4, t5) \
-DEF_HELPER_FLAGS_0(name, flags, ret)
-
-#undef GEN_HELPER
-#define GEN_HELPER -1
-
-#elif GEN_HELPER == -1
-/* Undefine macros.  */
-
-#undef DEF_HELPER_FLAGS_0
-#undef DEF_HELPER_FLAGS_1
-#undef DEF_HELPER_FLAGS_2
-#undef DEF_HELPER_FLAGS_3
-#undef DEF_HELPER_FLAGS_4
-#undef DEF_HELPER_FLAGS_5
-#undef GEN_HELPER
-
-#endif
diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
index 8bc2eb663e..c964ca4f0b 100644
--- a/include/exec/exec-all.h
+++ b/include/exec/exec-all.h
@@ -131,7 +131,7 @@ static inline void tlb_flush(CPUState *cpu, int flush_global)
 #if defined(__arm__) || defined(_ARCH_PPC) \
     || defined(__x86_64__) || defined(__i386__) \
     || defined(__sparc__) || defined(__aarch64__) \
-    || defined(__s390x__) \
+    || defined(__s390x__) || defined(__mips__) \
     || defined(CONFIG_TCG_INTERPRETER)
 #define USE_DIRECT_JUMP
 #endif
@@ -268,7 +268,7 @@ static inline void tb_set_jmp_target1(uintptr_t jmp_addr, uintptr_t addr)
     __asm __volatile__ ("swi 0x9f0002" : : "r" (_beg), "r" (_end), "r" (_flg));
 #endif
 }
-#elif defined(__sparc__)
+#elif defined(__sparc__) || defined(__mips__)
 void tb_set_jmp_target1(uintptr_t jmp_addr, uintptr_t addr);
 #else
 #error tb_set_jmp_target1 is missing
diff --git a/include/exec/helper-gen.h b/include/exec/helper-gen.h
new file mode 100644
index 0000000000..a04a0341e2
--- /dev/null
+++ b/include/exec/helper-gen.h
@@ -0,0 +1,70 @@
+/* Helper file for declaring TCG helper functions.
+   This one expands generation functions for tcg opcodes.  */
+
+#ifndef HELPER_GEN_H
+#define HELPER_GEN_H 1
+
+#include <exec/helper-head.h>
+
+#define DEF_HELPER_FLAGS_0(name, flags, ret)                            \
+static inline void glue(gen_helper_, name)(dh_retvar_decl0(ret))        \
+{                                                                       \
+  tcg_gen_callN(&tcg_ctx, HELPER(name), dh_retvar(ret), 0, NULL);       \
+}
+
+#define DEF_HELPER_FLAGS_1(name, flags, ret, t1)                        \
+static inline void glue(gen_helper_, name)(dh_retvar_decl(ret)          \
+    dh_arg_decl(t1, 1))                                                 \
+{                                                                       \
+  TCGArg args[1] = { dh_arg(t1, 1) };                                   \
+  tcg_gen_callN(&tcg_ctx, HELPER(name), dh_retvar(ret), 1, args);       \
+}
+
+#define DEF_HELPER_FLAGS_2(name, flags, ret, t1, t2)                    \
+static inline void glue(gen_helper_, name)(dh_retvar_decl(ret)          \
+    dh_arg_decl(t1, 1), dh_arg_decl(t2, 2))                             \
+{                                                                       \
+  TCGArg args[2] = { dh_arg(t1, 1), dh_arg(t2, 2) };                    \
+  tcg_gen_callN(&tcg_ctx, HELPER(name), dh_retvar(ret), 2, args);       \
+}
+
+#define DEF_HELPER_FLAGS_3(name, flags, ret, t1, t2, t3)                \
+static inline void glue(gen_helper_, name)(dh_retvar_decl(ret)          \
+    dh_arg_decl(t1, 1), dh_arg_decl(t2, 2), dh_arg_decl(t3, 3))         \
+{                                                                       \
+  TCGArg args[3] = { dh_arg(t1, 1), dh_arg(t2, 2), dh_arg(t3, 3) };     \
+  tcg_gen_callN(&tcg_ctx, HELPER(name), dh_retvar(ret), 3, args);       \
+}
+
+#define DEF_HELPER_FLAGS_4(name, flags, ret, t1, t2, t3, t4)            \
+static inline void glue(gen_helper_, name)(dh_retvar_decl(ret)          \
+    dh_arg_decl(t1, 1), dh_arg_decl(t2, 2),                             \
+    dh_arg_decl(t3, 3), dh_arg_decl(t4, 4))                             \
+{                                                                       \
+  TCGArg args[4] = { dh_arg(t1, 1), dh_arg(t2, 2),                      \
+                     dh_arg(t3, 3), dh_arg(t4, 4) };                    \
+  tcg_gen_callN(&tcg_ctx, HELPER(name), dh_retvar(ret), 4, args);       \
+}
+
+#define DEF_HELPER_FLAGS_5(name, flags, ret, t1, t2, t3, t4, t5)        \
+static inline void glue(gen_helper_, name)(dh_retvar_decl(ret)          \
+    dh_arg_decl(t1, 1),  dh_arg_decl(t2, 2), dh_arg_decl(t3, 3),        \
+    dh_arg_decl(t4, 4), dh_arg_decl(t5, 5))                             \
+{                                                                       \
+  TCGArg args[5] = { dh_arg(t1, 1), dh_arg(t2, 2), dh_arg(t3, 3),       \
+                     dh_arg(t4, 4), dh_arg(t5, 5) };                    \
+  tcg_gen_callN(&tcg_ctx, HELPER(name), dh_retvar(ret), 5, args);       \
+}
+
+#include "helper.h"
+#include "tcg-runtime.h"
+
+#undef DEF_HELPER_FLAGS_0
+#undef DEF_HELPER_FLAGS_1
+#undef DEF_HELPER_FLAGS_2
+#undef DEF_HELPER_FLAGS_3
+#undef DEF_HELPER_FLAGS_4
+#undef DEF_HELPER_FLAGS_5
+#undef GEN_HELPER
+
+#endif /* HELPER_GEN_H */
diff --git a/include/exec/helper-head.h b/include/exec/helper-head.h
new file mode 100644
index 0000000000..b009ccb11a
--- /dev/null
+++ b/include/exec/helper-head.h
@@ -0,0 +1,134 @@
+/* Helper file for declaring TCG helper functions.
+   Used by other helper files.
+
+   Targets should use DEF_HELPER_N and DEF_HELPER_FLAGS_N to declare helper
+   functions.  Names should be specified without the helper_ prefix, and
+   the return and argument types specified.  3 basic types are understood
+   (i32, i64 and ptr).  Additional aliases are provided for convenience and
+   to match the types used by the C helper implementation.
+
+   The target helper.h should be included in all files that use/define
+   helper functions.  THis will ensure that function prototypes are
+   consistent.  In addition it should be included an extra two times for
+   helper.c, defining:
+    GEN_HELPER 1 to produce op generation functions (gen_helper_*)
+    GEN_HELPER 2 to do runtime registration helper functions.
+ */
+
+#ifndef DEF_HELPER_H
+#define DEF_HELPER_H 1
+
+#include "qemu/osdep.h"
+
+#define HELPER(name) glue(helper_, name)
+
+#define GET_TCGV_i32 GET_TCGV_I32
+#define GET_TCGV_i64 GET_TCGV_I64
+#define GET_TCGV_ptr GET_TCGV_PTR
+
+/* Some types that make sense in C, but not for TCG.  */
+#define dh_alias_i32 i32
+#define dh_alias_s32 i32
+#define dh_alias_int i32
+#define dh_alias_i64 i64
+#define dh_alias_s64 i64
+#define dh_alias_f32 i32
+#define dh_alias_f64 i64
+#ifdef TARGET_LONG_BITS
+# if TARGET_LONG_BITS == 32
+#  define dh_alias_tl i32
+# else
+#  define dh_alias_tl i64
+# endif
+#endif
+#define dh_alias_ptr ptr
+#define dh_alias_void void
+#define dh_alias_noreturn noreturn
+#define dh_alias_env ptr
+#define dh_alias(t) glue(dh_alias_, t)
+
+#define dh_ctype_i32 uint32_t
+#define dh_ctype_s32 int32_t
+#define dh_ctype_int int
+#define dh_ctype_i64 uint64_t
+#define dh_ctype_s64 int64_t
+#define dh_ctype_f32 float32
+#define dh_ctype_f64 float64
+#define dh_ctype_tl target_ulong
+#define dh_ctype_ptr void *
+#define dh_ctype_void void
+#define dh_ctype_noreturn void QEMU_NORETURN
+#define dh_ctype_env CPUArchState *
+#define dh_ctype(t) dh_ctype_##t
+
+/* We can't use glue() here because it falls foul of C preprocessor
+   recursive expansion rules.  */
+#define dh_retvar_decl0_void void
+#define dh_retvar_decl0_noreturn void
+#define dh_retvar_decl0_i32 TCGv_i32 retval
+#define dh_retvar_decl0_i64 TCGv_i64 retval
+#define dh_retvar_decl0_ptr TCGv_ptr retval
+#define dh_retvar_decl0(t) glue(dh_retvar_decl0_, dh_alias(t))
+
+#define dh_retvar_decl_void
+#define dh_retvar_decl_noreturn
+#define dh_retvar_decl_i32 TCGv_i32 retval,
+#define dh_retvar_decl_i64 TCGv_i64 retval,
+#define dh_retvar_decl_ptr TCGv_ptr retval,
+#define dh_retvar_decl(t) glue(dh_retvar_decl_, dh_alias(t))
+
+#define dh_retvar_void TCG_CALL_DUMMY_ARG
+#define dh_retvar_noreturn TCG_CALL_DUMMY_ARG
+#define dh_retvar_i32 GET_TCGV_i32(retval)
+#define dh_retvar_i64 GET_TCGV_i64(retval)
+#define dh_retvar_ptr GET_TCGV_ptr(retval)
+#define dh_retvar(t) glue(dh_retvar_, dh_alias(t))
+
+#define dh_is_64bit_void 0
+#define dh_is_64bit_noreturn 0
+#define dh_is_64bit_i32 0
+#define dh_is_64bit_i64 1
+#define dh_is_64bit_ptr (sizeof(void *) == 8)
+#define dh_is_64bit(t) glue(dh_is_64bit_, dh_alias(t))
+
+#define dh_is_signed_void 0
+#define dh_is_signed_noreturn 0
+#define dh_is_signed_i32 0
+#define dh_is_signed_s32 1
+#define dh_is_signed_i64 0
+#define dh_is_signed_s64 1
+#define dh_is_signed_f32 0
+#define dh_is_signed_f64 0
+#define dh_is_signed_tl  0
+#define dh_is_signed_int 1
+/* ??? This is highly specific to the host cpu.  There are even special
+   extension instructions that may be required, e.g. ia64's addp4.  But
+   for now we don't support any 64-bit targets with 32-bit pointers.  */
+#define dh_is_signed_ptr 0
+#define dh_is_signed_env dh_is_signed_ptr
+#define dh_is_signed(t) dh_is_signed_##t
+
+#define dh_sizemask(t, n) \
+  ((dh_is_64bit(t) << (n*2)) | (dh_is_signed(t) << (n*2+1)))
+
+#define dh_arg(t, n) \
+  glue(GET_TCGV_, dh_alias(t))(glue(arg, n))
+
+#define dh_arg_decl(t, n) glue(TCGv_, dh_alias(t)) glue(arg, n)
+
+#define DEF_HELPER_0(name, ret) \
+    DEF_HELPER_FLAGS_0(name, 0, ret)
+#define DEF_HELPER_1(name, ret, t1) \
+    DEF_HELPER_FLAGS_1(name, 0, ret, t1)
+#define DEF_HELPER_2(name, ret, t1, t2) \
+    DEF_HELPER_FLAGS_2(name, 0, ret, t1, t2)
+#define DEF_HELPER_3(name, ret, t1, t2, t3) \
+    DEF_HELPER_FLAGS_3(name, 0, ret, t1, t2, t3)
+#define DEF_HELPER_4(name, ret, t1, t2, t3, t4) \
+    DEF_HELPER_FLAGS_4(name, 0, ret, t1, t2, t3, t4)
+#define DEF_HELPER_5(name, ret, t1, t2, t3, t4, t5) \
+    DEF_HELPER_FLAGS_5(name, 0, ret, t1, t2, t3, t4, t5)
+
+/* MAX_OPC_PARAM_IARGS must be set to n if last entry is DEF_HELPER_FLAGS_n. */
+
+#endif /* DEF_HELPER_H */
diff --git a/include/exec/helper-proto.h b/include/exec/helper-proto.h
new file mode 100644
index 0000000000..828951c609
--- /dev/null
+++ b/include/exec/helper-proto.h
@@ -0,0 +1,39 @@
+/* Helper file for declaring TCG helper functions.
+   This one expands prototypes for the helper functions.  */
+
+#ifndef HELPER_PROTO_H
+#define HELPER_PROTO_H 1
+
+#include <exec/helper-head.h>
+
+#define DEF_HELPER_FLAGS_0(name, flags, ret) \
+dh_ctype(ret) HELPER(name) (void);
+
+#define DEF_HELPER_FLAGS_1(name, flags, ret, t1) \
+dh_ctype(ret) HELPER(name) (dh_ctype(t1));
+
+#define DEF_HELPER_FLAGS_2(name, flags, ret, t1, t2) \
+dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2));
+
+#define DEF_HELPER_FLAGS_3(name, flags, ret, t1, t2, t3) \
+dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2), dh_ctype(t3));
+
+#define DEF_HELPER_FLAGS_4(name, flags, ret, t1, t2, t3, t4) \
+dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2), dh_ctype(t3), \
+                                   dh_ctype(t4));
+
+#define DEF_HELPER_FLAGS_5(name, flags, ret, t1, t2, t3, t4, t5) \
+dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2), dh_ctype(t3), \
+                            dh_ctype(t4), dh_ctype(t5));
+
+#include "helper.h"
+#include "tcg-runtime.h"
+
+#undef DEF_HELPER_FLAGS_0
+#undef DEF_HELPER_FLAGS_1
+#undef DEF_HELPER_FLAGS_2
+#undef DEF_HELPER_FLAGS_3
+#undef DEF_HELPER_FLAGS_4
+#undef DEF_HELPER_FLAGS_5
+
+#endif /* HELPER_PROTO_H */
diff --git a/include/exec/helper-tcg.h b/include/exec/helper-tcg.h
new file mode 100644
index 0000000000..d704c81126
--- /dev/null
+++ b/include/exec/helper-tcg.h
@@ -0,0 +1,48 @@
+/* Helper file for declaring TCG helper functions.
+   This one defines data structures private to tcg.c.  */
+
+#ifndef HELPER_TCG_H
+#define HELPER_TCG_H 1
+
+#include <exec/helper-head.h>
+
+#define DEF_HELPER_FLAGS_0(NAME, FLAGS, ret) \
+  { .func = HELPER(NAME), .name = #NAME, .flags = FLAGS, \
+    .sizemask = dh_sizemask(ret, 0) },
+
+#define DEF_HELPER_FLAGS_1(NAME, FLAGS, ret, t1) \
+  { .func = HELPER(NAME), .name = #NAME, .flags = FLAGS, \
+    .sizemask = dh_sizemask(ret, 0) | dh_sizemask(t1, 1) },
+
+#define DEF_HELPER_FLAGS_2(NAME, FLAGS, ret, t1, t2) \
+  { .func = HELPER(NAME), .name = #NAME, .flags = FLAGS, \
+    .sizemask = dh_sizemask(ret, 0) | dh_sizemask(t1, 1) \
+    | dh_sizemask(t2, 2) },
+
+#define DEF_HELPER_FLAGS_3(NAME, FLAGS, ret, t1, t2, t3) \
+  { .func = HELPER(NAME), .name = #NAME, .flags = FLAGS, \
+    .sizemask = dh_sizemask(ret, 0) | dh_sizemask(t1, 1) \
+    | dh_sizemask(t2, 2) | dh_sizemask(t3, 3) },
+
+#define DEF_HELPER_FLAGS_4(NAME, FLAGS, ret, t1, t2, t3, t4) \
+  { .func = HELPER(NAME), .name = #NAME, .flags = FLAGS, \
+    .sizemask = dh_sizemask(ret, 0) | dh_sizemask(t1, 1) \
+    | dh_sizemask(t2, 2) | dh_sizemask(t3, 3) | dh_sizemask(t4, 4) },
+
+#define DEF_HELPER_FLAGS_5(NAME, FLAGS, ret, t1, t2, t3, t4, t5) \
+  { .func = HELPER(NAME), .name = #NAME, .flags = FLAGS, \
+    .sizemask = dh_sizemask(ret, 0) | dh_sizemask(t1, 1) \
+    | dh_sizemask(t2, 2) | dh_sizemask(t3, 3) | dh_sizemask(t4, 4) \
+    | dh_sizemask(t5, 5) },
+
+#include "helper.h"
+#include "tcg-runtime.h"
+
+#undef DEF_HELPER_FLAGS_0
+#undef DEF_HELPER_FLAGS_1
+#undef DEF_HELPER_FLAGS_2
+#undef DEF_HELPER_FLAGS_3
+#undef DEF_HELPER_FLAGS_4
+#undef DEF_HELPER_FLAGS_5
+
+#endif /* HELPER_TCG_H */
diff --git a/include/hw/boards.h b/include/hw/boards.h
index 4345bd04fa..2d2e2bef19 100644
--- a/include/hw/boards.h
+++ b/include/hw/boards.h
@@ -8,17 +8,10 @@
 #include "hw/qdev.h"
 #include "qom/object.h"
 
-typedef struct QEMUMachineInitArgs {
-    const MachineClass *machine;
-    ram_addr_t ram_size;
-    const char *boot_order;
-    const char *kernel_filename;
-    const char *kernel_cmdline;
-    const char *initrd_filename;
-    const char *cpu_model;
-} QEMUMachineInitArgs;
 
-typedef void QEMUMachineInitFunc(QEMUMachineInitArgs *args);
+typedef struct MachineState MachineState;
+
+typedef void QEMUMachineInitFunc(MachineState *ms);
 
 typedef void QEMUMachineResetFunc(void);
 
@@ -62,8 +55,6 @@ int qemu_register_machine(QEMUMachine *m);
 #define MACHINE_CLASS(klass) \
     OBJECT_CLASS_CHECK(MachineClass, (klass), TYPE_MACHINE)
 
-typedef struct MachineState MachineState;
-
 MachineClass *find_default_machine(void);
 extern MachineState *current_machine;
 
@@ -80,7 +71,7 @@ struct MachineClass {
     const char *alias;
     const char *desc;
 
-    void (*init)(QEMUMachineInitArgs *args);
+    void (*init)(MachineState *state);
     void (*reset)(void);
     void (*hot_add_cpu)(const int64_t id, Error **errp);
     int (*kvm_type)(const char *arg);
@@ -112,9 +103,6 @@ struct MachineState {
     char *accel;
     bool kernel_irqchip;
     int kvm_shadow_mem;
-    char *kernel;
-    char *initrd;
-    char *append;
     char *dtb;
     char *dumpdtb;
     int phandle_start;
@@ -124,7 +112,12 @@ struct MachineState {
     bool usb;
     char *firmware;
 
-    QEMUMachineInitArgs init_args;
+    ram_addr_t ram_size;
+    const char *boot_order;
+    char *kernel_filename;
+    char *kernel_cmdline;
+    char *initrd_filename;
+    const char *cpu_model;
 };
 
 #endif
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index 32a76876c7..31328a8157 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -271,6 +271,10 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
             .driver   = "apic",\
             .property = "version",\
             .value    = stringify(0x11),\
+        },{\
+            .driver   = "nec-usb-xhci",\
+            .property = "superspeed-ports-first",\
+            .value    = "off",\
         }
 
 #define PC_COMPAT_1_7 \
diff --git a/include/hw/input/hid.h b/include/hw/input/hid.h
index 2567879399..2127c7ce45 100644
--- a/include/hw/input/hid.h
+++ b/include/hw/input/hid.h
@@ -2,6 +2,7 @@
 #define QEMU_HID_H
 
 #include "migration/vmstate.h"
+#include "ui/input.h"
 
 #define HID_MOUSE     1
 #define HID_TABLET    2
@@ -22,7 +23,6 @@ typedef void (*HIDEventFunc)(HIDState *s);
 typedef struct HIDMouseState {
     HIDPointerEvent queue[QUEUE_LENGTH];
     int mouse_grabbed;
-    QEMUPutMouseEntry *eh_entry;
 } HIDMouseState;
 
 typedef struct HIDKeyboardState {
@@ -31,7 +31,6 @@ typedef struct HIDKeyboardState {
     uint8_t leds;
     uint8_t key[16];
     int32_t keys;
-    QEMUPutKbdEntry *eh_entry;
 } HIDKeyboardState;
 
 struct HIDState {
@@ -47,6 +46,7 @@ struct HIDState {
     bool idle_pending;
     QEMUTimer *idle_timer;
     HIDEventFunc event;
+    QemuInputHandlerState *s;
 };
 
 void hid_init(HIDState *hs, int kind, HIDEventFunc event);
diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h
index dbe473c344..ae31575577 100644
--- a/include/hw/qdev-core.h
+++ b/include/hw/qdev-core.h
@@ -131,6 +131,17 @@ typedef struct DeviceClass {
     const char *bus_type;
 } DeviceClass;
 
+typedef struct NamedGPIOList NamedGPIOList;
+
+struct NamedGPIOList {
+    char *name;
+    qemu_irq *in;
+    int num_in;
+    qemu_irq *out;
+    int num_out;
+    QLIST_ENTRY(NamedGPIOList) node;
+};
+
 /**
  * DeviceState:
  * @realized: Indicates whether the device has been fully constructed.
@@ -148,10 +159,7 @@ struct DeviceState {
     QemuOpts *opts;
     int hotplugged;
     BusState *parent_bus;
-    int num_gpio_out;
-    qemu_irq *gpio_out;
-    int num_gpio_in;
-    qemu_irq *gpio_in;
+    QLIST_HEAD(, NamedGPIOList) gpios;
     QLIST_HEAD(, BusState) child_bus;
     int num_child_bus;
     int instance_id_alias;
@@ -252,7 +260,11 @@ void qdev_machine_creation_done(void);
 bool qdev_machine_modified(void);
 
 qemu_irq qdev_get_gpio_in(DeviceState *dev, int n);
+qemu_irq qdev_get_gpio_in_named(DeviceState *dev, const char *name, int n);
+
 void qdev_connect_gpio_out(DeviceState *dev, int n, qemu_irq pin);
+void qdev_connect_gpio_out_named(DeviceState *dev, const char *name, int n,
+                                 qemu_irq pin);
 
 BusState *qdev_get_child_bus(DeviceState *dev, const char *name);
 
@@ -262,6 +274,10 @@ BusState *qdev_get_child_bus(DeviceState *dev, const char *name);
 /* GPIO inputs also double as IRQ sinks.  */
 void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n);
 void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n);
+void qdev_init_gpio_in_named(DeviceState *dev, qemu_irq_handler handler,
+                             const char *name, int n);
+void qdev_init_gpio_out_named(DeviceState *dev, qemu_irq *pins,
+                              const char *name, int n);
 
 BusState *qdev_get_parent_bus(DeviceState *dev);
 
diff --git a/include/hw/s390x/adapter.h b/include/hw/s390x/adapter.h
new file mode 100644
index 0000000000..7f1703508c
--- /dev/null
+++ b/include/hw/s390x/adapter.h
@@ -0,0 +1,23 @@
+/*
+ * s390 adapter definitions
+ *
+ * Copyright 2013,2014 IBM Corp.
+ * Author(s): Cornelia Huck <cornelia.huck@de.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 S390X_ADAPTER_H
+#define S390X_ADAPTER_H
+
+struct AdapterInfo {
+    uint64_t ind_addr;
+    uint64_t summary_addr;
+    uint64_t ind_offset;
+    uint32_t summary_offset;
+    uint32_t adapter_id;
+};
+
+#endif
diff --git a/include/hw/s390x/s390_flic.h b/include/hw/s390x/s390_flic.h
index 497b219e30..489d73b9b3 100644
--- a/include/hw/s390x/s390_flic.h
+++ b/include/hw/s390x/s390_flic.h
@@ -1,33 +1,76 @@
 /*
- * QEMU S390x KVM floating interrupt controller (flic)
+ * QEMU S390x floating interrupt controller (flic)
  *
  * Copyright 2014 IBM Corp.
  * Author(s): Jens Freimann <jfrei@linux.vnet.ibm.com>
+ *            Cornelia Huck <cornelia.huck@de.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 __KVM_S390_FLIC_H
-#define __KVM_S390_FLIC_H
+#ifndef __HW_S390_FLIC_H
+#define __HW_S390_FLIC_H
 
 #include "hw/sysbus.h"
+#include "hw/s390x/adapter.h"
+#include "hw/virtio/virtio.h"
 
-#define TYPE_KVM_S390_FLIC "s390-flic"
+typedef struct AdapterRoutes {
+    AdapterInfo adapter;
+    int num_routes;
+    int gsi[VIRTIO_PCI_QUEUE_MAX];
+} AdapterRoutes;
+
+#define TYPE_S390_FLIC_COMMON "s390-flic"
+#define S390_FLIC_COMMON(obj) \
+    OBJECT_CHECK(S390FLICState, (obj), TYPE_S390_FLIC_COMMON)
+
+typedef struct S390FLICState {
+    SysBusDevice parent_obj;
+
+} S390FLICState;
+
+#define S390_FLIC_COMMON_CLASS(klass) \
+    OBJECT_CLASS_CHECK(S390FLICStateClass, (klass), TYPE_S390_FLIC_COMMON)
+#define S390_FLIC_COMMON_GET_CLASS(obj) \
+    OBJECT_GET_CLASS(S390FLICStateClass, (obj), TYPE_S390_FLIC_COMMON)
+
+typedef struct S390FLICStateClass {
+    DeviceClass parent_class;
+
+    int (*register_io_adapter)(S390FLICState *fs, uint32_t id, uint8_t isc,
+                               bool swap, bool maskable);
+    int (*io_adapter_map)(S390FLICState *fs, uint32_t id, uint64_t map_addr,
+                          bool do_map);
+    int (*add_adapter_routes)(S390FLICState *fs, AdapterRoutes *routes);
+    void (*release_adapter_routes)(S390FLICState *fs, AdapterRoutes *routes);
+} S390FLICStateClass;
+
+#define TYPE_KVM_S390_FLIC "s390-flic-kvm"
 #define KVM_S390_FLIC(obj) \
     OBJECT_CHECK(KVMS390FLICState, (obj), TYPE_KVM_S390_FLIC)
 
-typedef struct KVMS390FLICState {
-    SysBusDevice parent_obj;
+#define TYPE_QEMU_S390_FLIC "s390-flic-qemu"
+#define QEMU_S390_FLIC(obj) \
+    OBJECT_CHECK(QEMUS390FLICState, (obj), TYPE_QEMU_S390_FLIC)
 
-    uint32_t fd;
-} KVMS390FLICState;
+typedef struct QEMUS390FLICState {
+    S390FLICState parent_obj;
+} QEMUS390FLICState;
 
-#ifdef CONFIG_KVM
 void s390_flic_init(void);
+
+S390FLICState *s390_get_flic(void);
+
+#ifdef CONFIG_KVM
+DeviceState *s390_flic_kvm_create(void);
 #else
-static inline void s390_flic_init(void) { }
+static inline DeviceState *s390_flic_kvm_create(void)
+{
+    return NULL;
+}
 #endif
 
-#endif /* __KVM_S390_FLIC_H */
+#endif /* __HW_S390_FLIC_H */
diff --git a/include/hw/ssi.h b/include/hw/ssi.h
index 6c13fb2e44..df0f838510 100644
--- a/include/hw/ssi.h
+++ b/include/hw/ssi.h
@@ -23,6 +23,8 @@ typedef struct SSISlave SSISlave;
 #define SSI_SLAVE_GET_CLASS(obj) \
      OBJECT_GET_CLASS(SSISlaveClass, (obj), TYPE_SSI_SLAVE)
 
+#define SSI_GPIO_CS "ssi-gpio-cs"
+
 typedef enum {
     SSI_CS_NONE = 0,
     SSI_CS_LOW,
diff --git a/include/hw/usb.h b/include/hw/usb.h
index 1919bdc09d..8bcab48d29 100644
--- a/include/hw/usb.h
+++ b/include/hw/usb.h
@@ -458,6 +458,7 @@ void usb_ep_combine_input_packets(USBEndpoint *ep);
 void usb_combined_input_packet_complete(USBDevice *dev, USBPacket *p);
 void usb_combined_packet_cancel(USBDevice *dev, USBPacket *p);
 
+void usb_pick_speed(USBPort *port);
 void usb_attach(USBPort *port);
 void usb_detach(USBPort *port);
 void usb_port_reset(USBPort *port);
diff --git a/include/hw/usb/ehci-regs.h b/include/hw/usb/ehci-regs.h
new file mode 100644
index 0000000000..616f1b88cc
--- /dev/null
+++ b/include/hw/usb/ehci-regs.h
@@ -0,0 +1,82 @@
+#ifndef HW_USB_EHCI_REGS_H
+#define HW_USB_EHCI_REGS_H 1
+
+/* Capability Registers Base Address - section 2.2 */
+#define CAPLENGTH        0x0000  /* 1-byte, 0x0001 reserved */
+#define HCIVERSION       0x0002  /* 2-bytes, i/f version # */
+#define HCSPARAMS        0x0004  /* 4-bytes, structural params */
+#define HCCPARAMS        0x0008  /* 4-bytes, capability params */
+#define EECP             HCCPARAMS + 1
+#define HCSPPORTROUTE1   0x000c
+#define HCSPPORTROUTE2   0x0010
+
+#define USBCMD           0x0000
+#define USBCMD_RUNSTOP   (1 << 0)      // run / Stop
+#define USBCMD_HCRESET   (1 << 1)      // HC Reset
+#define USBCMD_FLS       (3 << 2)      // Frame List Size
+#define USBCMD_FLS_SH    2             // Frame List Size Shift
+#define USBCMD_PSE       (1 << 4)      // Periodic Schedule Enable
+#define USBCMD_ASE       (1 << 5)      // Asynch Schedule Enable
+#define USBCMD_IAAD      (1 << 6)      // Int Asynch Advance Doorbell
+#define USBCMD_LHCR      (1 << 7)      // Light Host Controller Reset
+#define USBCMD_ASPMC     (3 << 8)      // Async Sched Park Mode Count
+#define USBCMD_ASPME     (1 << 11)     // Async Sched Park Mode Enable
+#define USBCMD_ITC       (0x7f << 16)  // Int Threshold Control
+#define USBCMD_ITC_SH    16            // Int Threshold Control Shift
+
+#define USBSTS           0x0004
+#define USBSTS_RO_MASK   0x0000003f
+#define USBSTS_INT       (1 << 0)      // USB Interrupt
+#define USBSTS_ERRINT    (1 << 1)      // Error Interrupt
+#define USBSTS_PCD       (1 << 2)      // Port Change Detect
+#define USBSTS_FLR       (1 << 3)      // Frame List Rollover
+#define USBSTS_HSE       (1 << 4)      // Host System Error
+#define USBSTS_IAA       (1 << 5)      // Interrupt on Async Advance
+#define USBSTS_HALT      (1 << 12)     // HC Halted
+#define USBSTS_REC       (1 << 13)     // Reclamation
+#define USBSTS_PSS       (1 << 14)     // Periodic Schedule Status
+#define USBSTS_ASS       (1 << 15)     // Asynchronous Schedule Status
+
+/*
+ *  Interrupt enable bits correspond to the interrupt active bits in USBSTS
+ *  so no need to redefine here.
+ */
+#define USBINTR              0x0008
+#define USBINTR_MASK         0x0000003f
+
+#define FRINDEX              0x000c
+#define CTRLDSSEGMENT        0x0010
+#define PERIODICLISTBASE     0x0014
+#define ASYNCLISTADDR        0x0018
+#define ASYNCLISTADDR_MASK   0xffffffe0
+
+#define CONFIGFLAG           0x0040
+
+/*
+ * Bits that are reserved or are read-only are masked out of values
+ * written to us by software
+ */
+#define PORTSC_RO_MASK       0x007001c0
+#define PORTSC_RWC_MASK      0x0000002a
+#define PORTSC_WKOC_E        (1 << 22)    // Wake on Over Current Enable
+#define PORTSC_WKDS_E        (1 << 21)    // Wake on Disconnect Enable
+#define PORTSC_WKCN_E        (1 << 20)    // Wake on Connect Enable
+#define PORTSC_PTC           (15 << 16)   // Port Test Control
+#define PORTSC_PTC_SH        16           // Port Test Control shift
+#define PORTSC_PIC           (3 << 14)    // Port Indicator Control
+#define PORTSC_PIC_SH        14           // Port Indicator Control Shift
+#define PORTSC_POWNER        (1 << 13)    // Port Owner
+#define PORTSC_PPOWER        (1 << 12)    // Port Power
+#define PORTSC_LINESTAT      (3 << 10)    // Port Line Status
+#define PORTSC_LINESTAT_SH   10           // Port Line Status Shift
+#define PORTSC_PRESET        (1 << 8)     // Port Reset
+#define PORTSC_SUSPEND       (1 << 7)     // Port Suspend
+#define PORTSC_FPRES         (1 << 6)     // Force Port Resume
+#define PORTSC_OCC           (1 << 5)     // Over Current Change
+#define PORTSC_OCA           (1 << 4)     // Over Current Active
+#define PORTSC_PEDC          (1 << 3)     // Port Enable/Disable Change
+#define PORTSC_PED           (1 << 2)     // Port Enable/Disable
+#define PORTSC_CSC           (1 << 1)     // Connect Status Change
+#define PORTSC_CONNECT       (1 << 0)     // Current Connect Status
+
+#endif /* HW_USB_EHCI_REGS_H */
diff --git a/include/hw/usb/uhci-regs.h b/include/hw/usb/uhci-regs.h
new file mode 100644
index 0000000000..c7315c5e1f
--- /dev/null
+++ b/include/hw/usb/uhci-regs.h
@@ -0,0 +1,40 @@
+#ifndef HW_USB_UHCI_REGS_H
+#define HW_USB_UHCI_REGS_H 1
+
+#define UHCI_CMD_FGR      (1 << 4)
+#define UHCI_CMD_EGSM     (1 << 3)
+#define UHCI_CMD_GRESET   (1 << 2)
+#define UHCI_CMD_HCRESET  (1 << 1)
+#define UHCI_CMD_RS       (1 << 0)
+
+#define UHCI_STS_HCHALTED (1 << 5)
+#define UHCI_STS_HCPERR   (1 << 4)
+#define UHCI_STS_HSERR    (1 << 3)
+#define UHCI_STS_RD       (1 << 2)
+#define UHCI_STS_USBERR   (1 << 1)
+#define UHCI_STS_USBINT   (1 << 0)
+
+#define TD_CTRL_SPD     (1 << 29)
+#define TD_CTRL_ERROR_SHIFT  27
+#define TD_CTRL_IOS     (1 << 25)
+#define TD_CTRL_IOC     (1 << 24)
+#define TD_CTRL_ACTIVE  (1 << 23)
+#define TD_CTRL_STALL   (1 << 22)
+#define TD_CTRL_BABBLE  (1 << 20)
+#define TD_CTRL_NAK     (1 << 19)
+#define TD_CTRL_TIMEOUT (1 << 18)
+
+#define UHCI_PORT_SUSPEND (1 << 12)
+#define UHCI_PORT_RESET (1 << 9)
+#define UHCI_PORT_LSDA  (1 << 8)
+#define UHCI_PORT_RSVD1 (1 << 7)
+#define UHCI_PORT_RD    (1 << 6)
+#define UHCI_PORT_ENC   (1 << 3)
+#define UHCI_PORT_EN    (1 << 2)
+#define UHCI_PORT_CSC   (1 << 1)
+#define UHCI_PORT_CCS   (1 << 0)
+
+#define UHCI_PORT_READ_ONLY    (0x1bb)
+#define UHCI_PORT_WRITE_CLEAR  (UHCI_PORT_CSC | UHCI_PORT_ENC)
+
+#endif /* HW_USB_UHCI_REGS_H */
diff --git a/include/qapi/error.h b/include/qapi/error.h
index 79958011db..d712089f1a 100644
--- a/include/qapi/error.h
+++ b/include/qapi/error.h
@@ -67,12 +67,6 @@ void error_set_win32(Error **errp, int win32_err, ErrorClass err_class,
  */
 void error_setg_file_open(Error **errp, int os_errno, const char *filename);
 
-/**
- * Returns true if an indirect pointer to an error is pointing to a valid
- * error object.
- */
-bool error_is_set(Error **errp);
-
 /*
  * Get the error class of an error object.
  */
diff --git a/include/qapi/qmp/qdict.h b/include/qapi/qmp/qdict.h
index 1ddf97b1c3..d68f4eb4d5 100644
--- a/include/qapi/qmp/qdict.h
+++ b/include/qapi/qmp/qdict.h
@@ -16,6 +16,7 @@
 #include "qapi/qmp/qobject.h"
 #include "qapi/qmp/qlist.h"
 #include "qemu/queue.h"
+#include <stdbool.h>
 #include <stdint.h>
 
 #define QDICT_BUCKET_MAX 512
@@ -70,4 +71,6 @@ void qdict_flatten(QDict *qdict);
 void qdict_extract_subqdict(QDict *src, QDict **dst, const char *start);
 void qdict_array_split(QDict *src, QList **dst);
 
+void qdict_join(QDict *dest, QDict *src, bool overwrite);
+
 #endif /* QDICT_H */
diff --git a/include/qapi/visitor-impl.h b/include/qapi/visitor-impl.h
index f3fa420245..ecc0183196 100644
--- a/include/qapi/visitor-impl.h
+++ b/include/qapi/visitor-impl.h
@@ -42,13 +42,9 @@ struct Visitor
                         Error **errp);
 
     /* May be NULL */
-    void (*start_optional)(Visitor *v, bool *present, const char *name,
-                           Error **errp);
-    void (*end_optional)(Visitor *v, Error **errp);
+    void (*optional)(Visitor *v, bool *present, const char *name,
+                     Error **errp);
 
-    void (*start_handle)(Visitor *v, void **obj, const char *kind,
-                         const char *name, Error **errp);
-    void (*end_handle)(Visitor *v, Error **errp);
     void (*type_uint8)(Visitor *v, uint8_t *obj, const char *name, Error **errp);
     void (*type_uint16)(Visitor *v, uint16_t *obj, const char *name, Error **errp);
     void (*type_uint32)(Visitor *v, uint32_t *obj, const char *name, Error **errp);
diff --git a/include/qapi/visitor.h b/include/qapi/visitor.h
index 29da211b47..4a0178fa46 100644
--- a/include/qapi/visitor.h
+++ b/include/qapi/visitor.h
@@ -39,9 +39,8 @@ void visit_end_implicit_struct(Visitor *v, Error **errp);
 void visit_start_list(Visitor *v, const char *name, Error **errp);
 GenericList *visit_next_list(Visitor *v, GenericList **list, Error **errp);
 void visit_end_list(Visitor *v, Error **errp);
-void visit_start_optional(Visitor *v, bool *present, const char *name,
-                          Error **errp);
-void visit_end_optional(Visitor *v, Error **errp);
+void visit_optional(Visitor *v, bool *present, const char *name,
+                    Error **errp);
 void visit_get_next_type(Visitor *v, int *obj, const int *qtypes,
                          const char *name, Error **errp);
 void visit_type_enum(Visitor *v, int *obj, const char *strings[],
diff --git a/include/qemu-common.h b/include/qemu-common.h
index 3f3fd60f5b..66ceceb2ad 100644
--- a/include/qemu-common.h
+++ b/include/qemu-common.h
@@ -318,6 +318,7 @@ void qemu_iovec_concat(QEMUIOVector *dst,
 void qemu_iovec_concat_iov(QEMUIOVector *dst,
                            struct iovec *src_iov, unsigned int src_cnt,
                            size_t soffset, size_t sbytes);
+bool qemu_iovec_is_zero(QEMUIOVector *qiov);
 void qemu_iovec_destroy(QEMUIOVector *qiov);
 void qemu_iovec_reset(QEMUIOVector *qiov);
 size_t qemu_iovec_to_buf(QEMUIOVector *qiov, size_t offset,
diff --git a/include/qemu/bswap.h b/include/qemu/bswap.h
index 0f9c6cf15d..78c1ced4e7 100644
--- a/include/qemu/bswap.h
+++ b/include/qemu/bswap.h
@@ -215,9 +215,10 @@ typedef union {
  *   q: 64 bits
  *
  * endian is:
- * (empty): host endian
+ *   he   : host endian
  *   be   : big endian
  *   le   : little endian
+ * (except for byte accesses, which have no endian infix).
  */
 
 static inline int ldub_p(const void *ptr)
@@ -239,82 +240,82 @@ static inline void stb_p(void *ptr, uint8_t v)
    operations.  Thus we don't need to play games with packed attributes, or
    inline byte-by-byte stores.  */
 
-static inline int lduw_p(const void *ptr)
+static inline int lduw_he_p(const void *ptr)
 {
     uint16_t r;
     memcpy(&r, ptr, sizeof(r));
     return r;
 }
 
-static inline int ldsw_p(const void *ptr)
+static inline int ldsw_he_p(const void *ptr)
 {
     int16_t r;
     memcpy(&r, ptr, sizeof(r));
     return r;
 }
 
-static inline void stw_p(void *ptr, uint16_t v)
+static inline void stw_he_p(void *ptr, uint16_t v)
 {
     memcpy(ptr, &v, sizeof(v));
 }
 
-static inline int ldl_p(const void *ptr)
+static inline int ldl_he_p(const void *ptr)
 {
     int32_t r;
     memcpy(&r, ptr, sizeof(r));
     return r;
 }
 
-static inline void stl_p(void *ptr, uint32_t v)
+static inline void stl_he_p(void *ptr, uint32_t v)
 {
     memcpy(ptr, &v, sizeof(v));
 }
 
-static inline uint64_t ldq_p(const void *ptr)
+static inline uint64_t ldq_he_p(const void *ptr)
 {
     uint64_t r;
     memcpy(&r, ptr, sizeof(r));
     return r;
 }
 
-static inline void stq_p(void *ptr, uint64_t v)
+static inline void stq_he_p(void *ptr, uint64_t v)
 {
     memcpy(ptr, &v, sizeof(v));
 }
 
 static inline int lduw_le_p(const void *ptr)
 {
-    return (uint16_t)le_bswap(lduw_p(ptr), 16);
+    return (uint16_t)le_bswap(lduw_he_p(ptr), 16);
 }
 
 static inline int ldsw_le_p(const void *ptr)
 {
-    return (int16_t)le_bswap(lduw_p(ptr), 16);
+    return (int16_t)le_bswap(lduw_he_p(ptr), 16);
 }
 
 static inline int ldl_le_p(const void *ptr)
 {
-    return le_bswap(ldl_p(ptr), 32);
+    return le_bswap(ldl_he_p(ptr), 32);
 }
 
 static inline uint64_t ldq_le_p(const void *ptr)
 {
-    return le_bswap(ldq_p(ptr), 64);
+    return le_bswap(ldq_he_p(ptr), 64);
 }
 
 static inline void stw_le_p(void *ptr, uint16_t v)
 {
-    stw_p(ptr, le_bswap(v, 16));
+    stw_he_p(ptr, le_bswap(v, 16));
 }
 
 static inline void stl_le_p(void *ptr, uint32_t v)
 {
-    stl_p(ptr, le_bswap(v, 32));
+    stl_he_p(ptr, le_bswap(v, 32));
 }
 
 static inline void stq_le_p(void *ptr, uint64_t v)
 {
-    stq_p(ptr, le_bswap(v, 64));
+    stq_he_p(ptr, le_bswap(v, 64));
 }
 
 /* float access */
@@ -349,37 +350,37 @@ static inline void stfq_le_p(void *ptr, float64 v)
 
 static inline int lduw_be_p(const void *ptr)
 {
-    return (uint16_t)be_bswap(lduw_p(ptr), 16);
+    return (uint16_t)be_bswap(lduw_he_p(ptr), 16);
 }
 
 static inline int ldsw_be_p(const void *ptr)
 {
-    return (int16_t)be_bswap(lduw_p(ptr), 16);
+    return (int16_t)be_bswap(lduw_he_p(ptr), 16);
 }
 
 static inline int ldl_be_p(const void *ptr)
 {
-    return be_bswap(ldl_p(ptr), 32);
+    return be_bswap(ldl_he_p(ptr), 32);
 }
 
 static inline uint64_t ldq_be_p(const void *ptr)
 {
-    return be_bswap(ldq_p(ptr), 64);
+    return be_bswap(ldq_he_p(ptr), 64);
 }
 
 static inline void stw_be_p(void *ptr, uint16_t v)
 {
-    stw_p(ptr, be_bswap(v, 16));
+    stw_he_p(ptr, be_bswap(v, 16));
 }
 
 static inline void stl_be_p(void *ptr, uint32_t v)
 {
-    stl_p(ptr, be_bswap(v, 32));
+    stl_he_p(ptr, be_bswap(v, 32));
 }
 
 static inline void stq_be_p(void *ptr, uint64_t v)
 {
-    stq_p(ptr, be_bswap(v, 64));
+    stq_he_p(ptr, be_bswap(v, 64));
 }
 
 /* float access */
diff --git a/include/qemu/int128.h b/include/qemu/int128.h
index f59703143a..fb782aaddd 100644
--- a/include/qemu/int128.h
+++ b/include/qemu/int128.h
@@ -38,6 +38,11 @@ static inline Int128 int128_2_64(void)
     return (Int128) { 0, 1 };
 }
 
+static inline Int128 int128_exts64(int64_t a)
+{
+    return (Int128) { .lo = a, .hi = (a < 0) ? -1 : 0 };
+}
+
 static inline Int128 int128_and(Int128 a, Int128 b)
 {
     return (Int128) { a.lo & b.lo, a.hi & b.hi };
diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h
index 86bab123a4..5f20b0e263 100644
--- a/include/qemu/typedefs.h
+++ b/include/qemu/typedefs.h
@@ -74,5 +74,6 @@ typedef struct SHPCDevice SHPCDevice;
 typedef struct FWCfgState FWCfgState;
 typedef struct PcGuestInfo PcGuestInfo;
 typedef struct Range Range;
+typedef struct AdapterInfo AdapterInfo;
 
 #endif /* QEMU_TYPEDEFS_H */
diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h
index e7ad9d159a..e79e92c50e 100644
--- a/include/sysemu/kvm.h
+++ b/include/sysemu/kvm.h
@@ -300,7 +300,7 @@ int kvm_check_extension(KVMState *s, unsigned int extension);
         };                                                           \
         uint64_t args_tmp[] = { __VA_ARGS__ };                       \
         int i;                                                       \
-        for (i = 0; i < ARRAY_SIZE(args_tmp) &&                      \
+        for (i = 0; i < (int)ARRAY_SIZE(args_tmp) &&                 \
                      i < ARRAY_SIZE(cap.args); i++) {                \
             cap.args[i] = args_tmp[i];                               \
         }                                                            \
@@ -315,7 +315,7 @@ int kvm_check_extension(KVMState *s, unsigned int extension);
         };                                                           \
         uint64_t args_tmp[] = { __VA_ARGS__ };                       \
         int i;                                                       \
-        for (i = 0; i < ARRAY_SIZE(args_tmp) &&                      \
+        for (i = 0; i < (int)ARRAY_SIZE(args_tmp) &&                 \
                      i < ARRAY_SIZE(cap.args); i++) {                \
             cap.args[i] = args_tmp[i];                               \
         }                                                            \
@@ -363,6 +363,8 @@ int kvm_irqchip_add_msi_route(KVMState *s, MSIMessage msg);
 int kvm_irqchip_update_msi_route(KVMState *s, int virq, MSIMessage msg);
 void kvm_irqchip_release_virq(KVMState *s, int virq);
 
+int kvm_irqchip_add_adapter_route(KVMState *s, AdapterInfo *adapter);
+
 int kvm_irqchip_add_irqfd_notifier(KVMState *s, EventNotifier *n,
                                    EventNotifier *rn, int virq);
 int kvm_irqchip_remove_irqfd_notifier(KVMState *s, EventNotifier *n, int virq);
diff --git a/include/ui/console.h b/include/ui/console.h
index 8a866176db..edbaa9b475 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -81,6 +81,9 @@ void do_mouse_set(Monitor *mon, const QDict *qdict);
 #define QEMU_KEY_CTRL_PAGEUP     0xe406
 #define QEMU_KEY_CTRL_PAGEDOWN   0xe407
 
+void kbd_put_keysym_console(QemuConsole *s, int keysym);
+bool kbd_put_qcode_console(QemuConsole *s, int qcode);
+void kbd_put_string_console(QemuConsole *s, const char *str, int len);
 void kbd_put_keysym(int keysym);
 
 /* consoles */
diff --git a/include/ui/input.h b/include/ui/input.h
index 4976f3da2c..5d5ac00663 100644
--- a/include/ui/input.h
+++ b/include/ui/input.h
@@ -27,7 +27,11 @@ struct QemuInputHandler {
 QemuInputHandlerState *qemu_input_handler_register(DeviceState *dev,
                                                    QemuInputHandler *handler);
 void qemu_input_handler_activate(QemuInputHandlerState *s);
+void qemu_input_handler_deactivate(QemuInputHandlerState *s);
 void qemu_input_handler_unregister(QemuInputHandlerState *s);
+void qemu_input_handler_bind(QemuInputHandlerState *s,
+                             const char *device_id, int head,
+                             Error **errp);
 void qemu_input_event_send(QemuConsole *src, InputEvent *evt);
 void qemu_input_event_sync(void);
 
@@ -35,6 +39,12 @@ InputEvent *qemu_input_event_new_key(KeyValue *key, bool down);
 void qemu_input_event_send_key(QemuConsole *src, KeyValue *key, bool down);
 void qemu_input_event_send_key_number(QemuConsole *src, int num, bool down);
 void qemu_input_event_send_key_qcode(QemuConsole *src, QKeyCode q, bool down);
+void qemu_input_event_send_key_delay(uint32_t delay_ms);
+int qemu_input_key_number_to_qcode(uint8_t nr);
+int qemu_input_key_value_to_number(const KeyValue *value);
+int qemu_input_key_value_to_qcode(const KeyValue *value);
+int qemu_input_key_value_to_scancode(const KeyValue *value, bool down,
+                                     int *codes);
 
 InputEvent *qemu_input_event_new_btn(InputButton btn, bool down);
 void qemu_input_queue_btn(QemuConsole *src, InputButton btn, bool down);
diff --git a/iohandler.c b/iohandler.c
index ae2ef8f966..cca614f087 100644
--- a/iohandler.c
+++ b/iohandler.c
@@ -191,6 +191,7 @@ static void qemu_init_child_watch(void)
     struct sigaction act;
     sigchld_bh = qemu_bh_new(sigchld_bh_handler, NULL);
 
+    memset(&act, 0, sizeof(act));
     act.sa_handler = sigchld_handler;
     act.sa_flags = SA_NOCLDSTOP;
     sigaction(SIGCHLD, &act, NULL);
diff --git a/kvm-all.c b/kvm-all.c
index f7fe9c6cd9..4e19eff0ef 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -27,6 +27,7 @@
 #include "sysemu/sysemu.h"
 #include "hw/hw.h"
 #include "hw/pci/msi.h"
+#include "hw/s390x/adapter.h"
 #include "exec/gdbstub.h"
 #include "sysemu/kvm.h"
 #include "qemu/bswap.h"
@@ -1236,6 +1237,35 @@ static int kvm_irqchip_assign_irqfd(KVMState *s, int fd, int rfd, int virq,
     return kvm_vm_ioctl(s, KVM_IRQFD, &irqfd);
 }
 
+int kvm_irqchip_add_adapter_route(KVMState *s, AdapterInfo *adapter)
+{
+    struct kvm_irq_routing_entry kroute;
+    int virq;
+
+    if (!kvm_gsi_routing_enabled()) {
+        return -ENOSYS;
+    }
+
+    virq = kvm_irqchip_get_virq(s);
+    if (virq < 0) {
+        return virq;
+    }
+
+    kroute.gsi = virq;
+    kroute.type = KVM_IRQ_ROUTING_S390_ADAPTER;
+    kroute.flags = 0;
+    kroute.u.adapter.summary_addr = adapter->summary_addr;
+    kroute.u.adapter.ind_addr = adapter->ind_addr;
+    kroute.u.adapter.summary_offset = adapter->summary_offset;
+    kroute.u.adapter.ind_offset = adapter->ind_offset;
+    kroute.u.adapter.adapter_id = adapter->adapter_id;
+
+    kvm_add_routing_entry(s, &kroute);
+    kvm_irqchip_commit_routes(s);
+
+    return virq;
+}
+
 #else /* !KVM_CAP_IRQ_ROUTING */
 
 void kvm_init_irq_routing(KVMState *s)
@@ -1256,6 +1286,11 @@ int kvm_irqchip_add_msi_route(KVMState *s, MSIMessage msg)
     return -ENOSYS;
 }
 
+int kvm_irqchip_add_adapter_route(KVMState *s, AdapterInfo *adapter)
+{
+    return -ENOSYS;
+}
+
 static int kvm_irqchip_assign_irqfd(KVMState *s, int fd, int virq, bool assign)
 {
     abort();
@@ -1285,7 +1320,8 @@ static int kvm_irqchip_create(KVMState *s)
     int ret;
 
     if (!qemu_opt_get_bool(qemu_get_machine_opts(), "kernel_irqchip", true) ||
-        !kvm_check_extension(s, KVM_CAP_IRQCHIP)) {
+        (!kvm_check_extension(s, KVM_CAP_IRQCHIP) &&
+         (kvm_vm_enable_cap(s, KVM_CAP_S390_IRQCHIP, 0) < 0))) {
         return 0;
     }
 
diff --git a/kvm-stub.c b/kvm-stub.c
index 8acda86ced..ac33d8666d 100644
--- a/kvm-stub.c
+++ b/kvm-stub.c
@@ -136,6 +136,11 @@ int kvm_irqchip_update_msi_route(KVMState *s, int virq, MSIMessage msg)
     return -ENOSYS;
 }
 
+int kvm_irqchip_add_adapter_route(KVMState *s, AdapterInfo *adapter)
+{
+    return -ENOSYS;
+}
+
 int kvm_irqchip_add_irqfd_notifier(KVMState *s, EventNotifier *n,
                                    EventNotifier *rn, int virq)
 {
diff --git a/libcacard/cac.c b/libcacard/cac.c
index 74ef3e3cec..0a0163d3eb 100644
--- a/libcacard/cac.c
+++ b/libcacard/cac.c
@@ -93,8 +93,8 @@ cac_common_process_apdu(VCard *card, VCardAPDU *apdu, VCardResponse **response)
 static VCardStatus
 cac_applet_pki_reset(VCard *card, int channel)
 {
-    VCardAppletPrivate *applet_private = NULL;
-    CACPKIAppletData *pki_applet = NULL;
+    VCardAppletPrivate *applet_private;
+    CACPKIAppletData *pki_applet;
     applet_private = vcard_get_current_applet_private(card, channel);
     assert(applet_private);
     pki_applet = &(applet_private->u.pki_data);
@@ -113,8 +113,8 @@ static VCardStatus
 cac_applet_pki_process_apdu(VCard *card, VCardAPDU *apdu,
                             VCardResponse **response)
 {
-    CACPKIAppletData *pki_applet = NULL;
-    VCardAppletPrivate *applet_private = NULL;
+    CACPKIAppletData *pki_applet;
+    VCardAppletPrivate *applet_private;
     int size, next;
     unsigned char *sign_buffer;
     vcard_7816_status_t status;
@@ -169,17 +169,8 @@ cac_applet_pki_process_apdu(VCard *card, VCardAPDU *apdu,
         }
         size = apdu->a_Lc;
 
-        sign_buffer = realloc(pki_applet->sign_buffer,
-                      pki_applet->sign_buffer_len+size);
-        if (sign_buffer == NULL) {
-            g_free(pki_applet->sign_buffer);
-            pki_applet->sign_buffer = NULL;
-            pki_applet->sign_buffer_len = 0;
-            *response = vcard_make_response(
-                            VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE);
-            ret = VCARD_DONE;
-            break;
-        }
+        sign_buffer = g_realloc(pki_applet->sign_buffer,
+                                pki_applet->sign_buffer_len + size);
         memcpy(sign_buffer+pki_applet->sign_buffer_len, apdu->a_body, size);
         size += pki_applet->sign_buffer_len;
         switch (apdu->a_p1) {
@@ -288,7 +279,7 @@ cac_applet_container_process_apdu(VCard *card, VCardAPDU *apdu,
 static void
 cac_delete_pki_applet_private(VCardAppletPrivate *applet_private)
 {
-    CACPKIAppletData *pki_applet_data = NULL;
+    CACPKIAppletData *pki_applet_data;
 
     if (applet_private == NULL) {
         return;
@@ -310,16 +301,11 @@ static VCardAppletPrivate *
 cac_new_pki_applet_private(const unsigned char *cert,
                            int cert_len, VCardKey *key)
 {
-    CACPKIAppletData *pki_applet_data = NULL;
-    VCardAppletPrivate *applet_private = NULL;
-    applet_private = (VCardAppletPrivate *)g_malloc(sizeof(VCardAppletPrivate));
+    CACPKIAppletData *pki_applet_data;
+    VCardAppletPrivate *applet_private;
 
+    applet_private = g_new0(VCardAppletPrivate, 1);
     pki_applet_data = &(applet_private->u.pki_data);
-    pki_applet_data->cert_buffer = NULL;
-    pki_applet_data->cert_buffer_len = 0;
-    pki_applet_data->sign_buffer = NULL;
-    pki_applet_data->sign_buffer_len = 0;
-    pki_applet_data->key = NULL;
     pki_applet_data->cert = (unsigned char *)g_malloc(cert_len+1);
     /*
      * if we want to support compression, then we simply change the 0 to a 1
@@ -341,8 +327,8 @@ static VCardApplet *
 cac_new_pki_applet(int i, const unsigned char *cert,
                    int cert_len, VCardKey *key)
 {
-    VCardAppletPrivate *applet_private = NULL;
-    VCardApplet *applet = NULL;
+    VCardAppletPrivate *applet_private;
+    VCardApplet *applet;
     unsigned char pki_aid[] = { 0xa0, 0x00, 0x00, 0x00, 0x79, 0x01, 0x00 };
     int pki_aid_len = sizeof(pki_aid);
 
diff --git a/libcacard/card_7816.c b/libcacard/card_7816.c
index c28bb60fe6..a54f880390 100644
--- a/libcacard/card_7816.c
+++ b/libcacard/card_7816.c
@@ -51,7 +51,7 @@ vcard_response_new_data(unsigned char *buf, int len)
 {
     VCardResponse *new_response;
 
-    new_response = (VCardResponse *)g_malloc(sizeof(VCardResponse));
+    new_response = g_new(VCardResponse, 1);
     new_response->b_data = g_malloc(len + 2);
     memcpy(new_response->b_data, buf, len);
     new_response->b_total_len = len+2;
@@ -132,7 +132,7 @@ vcard_response_new_status(vcard_7816_status_t status)
 {
     VCardResponse *new_response;
 
-    new_response = (VCardResponse *)g_malloc(sizeof(VCardResponse));
+    new_response = g_new(VCardResponse, 1);
     new_response->b_data = &new_response->b_sw1;
     new_response->b_len = 0;
     new_response->b_total_len = 2;
@@ -149,7 +149,7 @@ vcard_response_new_status_bytes(unsigned char sw1, unsigned char sw2)
 {
     VCardResponse *new_response;
 
-    new_response = (VCardResponse *)g_malloc(sizeof(VCardResponse));
+    new_response = g_new(VCardResponse, 1);
     new_response->b_data = &new_response->b_sw1;
     new_response->b_len = 0;
     new_response->b_total_len = 2;
@@ -336,9 +336,8 @@ vcard_apdu_new(unsigned char *raw_apdu, int len, vcard_7816_status_t *status)
         return NULL;
     }
 
-    new_apdu = (VCardAPDU *)g_malloc(sizeof(VCardAPDU));
-    new_apdu->a_data = g_malloc(len);
-    memcpy(new_apdu->a_data, raw_apdu, len);
+    new_apdu = g_new(VCardAPDU, 1);
+    new_apdu->a_data = g_memdup(raw_apdu, len);
     new_apdu->a_len = len;
     *status = vcard_apdu_set_class(new_apdu);
     if (*status != VCARD7816_STATUS_SUCCESS) {
@@ -417,7 +416,7 @@ VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_GENERAL)
 VCardResponse *
 vcard_make_response(vcard_7816_status_t status)
 {
-    VCardResponse *response = NULL;
+    VCardResponse *response;
 
     switch (status) {
     /* known 7816 response codes */
@@ -544,9 +543,8 @@ vcard_make_response(vcard_7816_status_t status)
             return VCARD_RESPONSE_GET_STATIC(
                         VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE);
         }
+        return response;
     }
-    assert(response);
-    return response;
 }
 
 /*
diff --git a/libcacard/event.c b/libcacard/event.c
index 2d7500fac0..a2e6c7dcd0 100644
--- a/libcacard/event.c
+++ b/libcacard/event.c
@@ -17,7 +17,7 @@ vevent_new(VEventType type, VReader *reader, VCard *card)
 {
     VEvent *new_vevent;
 
-    new_vevent = (VEvent *)g_malloc(sizeof(VEvent));
+    new_vevent = g_new(VEvent, 1);
     new_vevent->next = NULL;
     new_vevent->type = type;
     new_vevent->reader = vreader_reference(reader);
diff --git a/libcacard/vcard.c b/libcacard/vcard.c
index 539177bb4c..6aaf085ecc 100644
--- a/libcacard/vcard.c
+++ b/libcacard/vcard.c
@@ -37,9 +37,8 @@ vcard_buffer_response_new(unsigned char *buffer, int size)
 {
     VCardBufferResponse *new_buffer;
 
-    new_buffer = (VCardBufferResponse *)g_malloc(sizeof(VCardBufferResponse));
-    new_buffer->buffer = (unsigned char *)g_malloc(size);
-    memcpy(new_buffer->buffer, buffer, size);
+    new_buffer = g_new(VCardBufferResponse, 1);
+    new_buffer->buffer = (unsigned char *)g_memdup(buffer, size);
     new_buffer->buffer_len = size;
     new_buffer->current = new_buffer->buffer;
     new_buffer->len = size;
@@ -102,15 +101,11 @@ vcard_new_applet(VCardProcessAPDU applet_process_function,
 {
     VCardApplet *applet;
 
-    applet = (VCardApplet *)g_malloc(sizeof(VCardApplet));
-    applet->next = NULL;
-    applet->applet_private = NULL;
-    applet->applet_private_free = NULL;
+    applet = g_new0(VCardApplet, 1);
     applet->process_apdu = applet_process_function;
     applet->reset_applet = applet_reset_function;
 
-    applet->aid = g_malloc(aid_len);
-    memcpy(applet->aid, aid, aid_len);
+    applet->aid = g_memdup(aid, aid_len);
     applet->aid_len = aid_len;
     return applet;
 }
@@ -149,18 +144,11 @@ VCard *
 vcard_new(VCardEmul *private, VCardEmulFree private_free)
 {
     VCard *new_card;
-    int i;
 
-    new_card = (VCard *)g_malloc(sizeof(VCard));
-    new_card->applet_list = NULL;
-    for (i = 0; i < MAX_CHANNEL; i++) {
-        new_card->current_applet[i] = NULL;
-    }
-    new_card->vcard_buffer_response = NULL;
+    new_card = g_new0(VCard, 1);
     new_card->type = VCARD_VM;
     new_card->vcard_private = private;
     new_card->vcard_private_free = private_free;
-    new_card->vcard_get_atr = NULL;
     new_card->reference_count = 1;
     return new_card;
 }
@@ -178,8 +166,8 @@ vcard_reference(VCard *vcard)
 void
 vcard_free(VCard *vcard)
 {
-    VCardApplet *current_applet = NULL;
-    VCardApplet *next_applet = NULL;
+    VCardApplet *current_applet;
+    VCardApplet *next_applet;
 
     if (vcard == NULL) {
         return;
diff --git a/libcacard/vcard_emul_nss.c b/libcacard/vcard_emul_nss.c
index e2b196d8c5..cefc38333f 100644
--- a/libcacard/vcard_emul_nss.c
+++ b/libcacard/vcard_emul_nss.c
@@ -94,9 +94,9 @@ static void
 vcard_emul_alloc_arrays(unsigned char ***certsp, int **cert_lenp,
                         VCardKey ***keysp, int cert_count)
 {
-    *certsp = (unsigned char **)g_malloc(sizeof(unsigned char *)*cert_count);
-    *cert_lenp = (int *)g_malloc(sizeof(int)*cert_count);
-    *keysp = (VCardKey **)g_malloc(sizeof(VCardKey *)*cert_count);
+    *certsp = g_new(unsigned char *, cert_count);
+    *cert_lenp = g_new(int, cert_count);
+    *keysp = g_new(VCardKey *, cert_count);
 }
 
 /*
@@ -139,7 +139,7 @@ vcard_emul_make_key(PK11SlotInfo *slot, CERTCertificate *cert)
 {
     VCardKey *key;
 
-    key = (VCardKey *)g_malloc(sizeof(VCardKey));
+    key = g_new(VCardKey, 1);
     key->slot = PK11_ReferenceSlot(slot);
     key->cert = CERT_DupCertificate(cert);
     /* NOTE: if we aren't logged into the token, this could return NULL */
@@ -367,7 +367,7 @@ vcard_7816_status_t
 vcard_emul_login(VCard *card, unsigned char *pin, int pin_len)
 {
     PK11SlotInfo *slot;
-    unsigned char *pin_string = NULL;
+    unsigned char *pin_string;
     int i;
     SECStatus rv;
 
@@ -423,7 +423,7 @@ static VReader *
 vcard_emul_find_vreader_from_slot(PK11SlotInfo *slot)
 {
     VReaderList *reader_list = vreader_get_reader_list();
-    VReaderListEntry *current_entry = NULL;
+    VReaderListEntry *current_entry;
 
     if (reader_list == NULL) {
         return NULL;
@@ -433,11 +433,13 @@ vcard_emul_find_vreader_from_slot(PK11SlotInfo *slot)
         VReader *reader = vreader_list_get_reader(current_entry);
         VReaderEmul *reader_emul = vreader_get_private(reader);
         if (reader_emul->slot == slot) {
+            vreader_list_delete(reader_list);
             return reader;
         }
         vreader_free(reader);
     }
 
+    vreader_list_delete(reader_list);
     return NULL;
 }
 
@@ -449,7 +451,7 @@ vreader_emul_new(PK11SlotInfo *slot, VCardEmulType type, const char *params)
 {
     VReaderEmul *new_reader_emul;
 
-    new_reader_emul = (VReaderEmul *)g_malloc(sizeof(VReaderEmul));
+    new_reader_emul = g_new(VReaderEmul, 1);
 
     new_reader_emul->slot = PK11_ReferenceSlot(slot);
     new_reader_emul->default_type = type;
@@ -616,11 +618,6 @@ vcard_emul_mirror_card(VReader *vreader)
         cert_count++;
     }
 
-    if (cert_count == 0) {
-        PK11_DestroyGenericObjects(firstObj);
-        return NULL;
-    }
-
     /* allocate the arrays */
     vcard_emul_alloc_arrays(&certs, &cert_len, &keys, cert_count);
 
@@ -1050,7 +1047,7 @@ void
 vcard_emul_replay_insertion_events(void)
 {
     VReaderListEntry *current_entry;
-    VReaderListEntry *next_entry = NULL;
+    VReaderListEntry *next_entry;
     VReaderList *list = vreader_get_reader_list();
 
     for (current_entry = vreader_list_get_first(list); current_entry;
@@ -1059,6 +1056,8 @@ vcard_emul_replay_insertion_events(void)
         next_entry = vreader_list_get_next(current_entry);
         vreader_queue_card_event(vreader);
     }
+
+    vreader_list_delete(list);
 }
 
 /*
@@ -1150,7 +1149,7 @@ vcard_emul_options(const char *args)
             char type_str[100];
             VCardEmulType type;
             int count, i;
-            VirtualReaderOptions *vreaderOpt = NULL;
+            VirtualReaderOptions *vreaderOpt;
 
             args = strip(args + 5);
             if (*args != '(') {
@@ -1174,14 +1173,10 @@ vcard_emul_options(const char *args)
 
             if (opts->vreader_count >= reader_count) {
                 reader_count += READER_STEP;
-                vreaderOpt = realloc(opts->vreader,
-                                reader_count * sizeof(*vreaderOpt));
-                if (vreaderOpt == NULL) {
-                    return opts; /* we're done */
-                }
+                opts->vreader = g_renew(VirtualReaderOptions, opts->vreader,
+                                        reader_count);
             }
-            opts->vreader = vreaderOpt;
-            vreaderOpt = &vreaderOpt[opts->vreader_count];
+            vreaderOpt = &opts->vreader[opts->vreader_count];
             vreaderOpt->name = g_strndup(name, name_length);
             vreaderOpt->vname = g_strndup(vname, vname_length);
             vreaderOpt->card_type = type;
@@ -1189,7 +1184,7 @@ vcard_emul_options(const char *args)
                 g_strndup(type_params, type_params_length);
             count = count_tokens(args, ',', ')') + 1;
             vreaderOpt->cert_count = count;
-            vreaderOpt->cert_name = (char **)g_malloc(count*sizeof(char *));
+            vreaderOpt->cert_name = g_new(char *, count);
             for (i = 0; i < count; i++) {
                 const char *cert = args;
                 args = strpbrk(args, ",)");
diff --git a/libcacard/vreader.c b/libcacard/vreader.c
index 77202951fb..d2a9b7df41 100644
--- a/libcacard/vreader.c
+++ b/libcacard/vreader.c
@@ -115,7 +115,7 @@ vreader_new(const char *name, VReaderEmul *private,
 {
     VReader *reader;
 
-    reader = (VReader *)g_malloc(sizeof(VReader));
+    reader = g_new(VReader, 1);
     qemu_mutex_init(&reader->lock);
     reader->reference_count = 1;
     reader->name = g_strdup(name);
@@ -283,12 +283,10 @@ vreader_xfr_bytes(VReader *reader,
                   response->b_sw2, response->b_len, response->b_total_len);
         }
     }
-    assert(card_status == VCARD_DONE);
-    if (card_status == VCARD_DONE) {
-        int size = MIN(*receive_buf_len, response->b_total_len);
-        memcpy(receive_buf, response->b_data, size);
-        *receive_buf_len = size;
-    }
+    assert(card_status == VCARD_DONE && response);
+    int size = MIN(*receive_buf_len, response->b_total_len);
+    memcpy(receive_buf, response->b_data, size);
+    *receive_buf_len = size;
     vcard_response_delete(response);
     vcard_apdu_delete(apdu);
     vcard_free(card); /* free our reference */
@@ -312,10 +310,7 @@ vreader_list_entry_new(VReader *reader)
 {
     VReaderListEntry *new_reader_list_entry;
 
-    new_reader_list_entry = (VReaderListEntry *)
-                               g_malloc(sizeof(VReaderListEntry));
-    new_reader_list_entry->next = NULL;
-    new_reader_list_entry->prev = NULL;
+    new_reader_list_entry = g_new0(VReaderListEntry, 1);
     new_reader_list_entry->reader = vreader_reference(reader);
     return new_reader_list_entry;
 }
@@ -336,9 +331,7 @@ vreader_list_new(void)
 {
     VReaderList *new_reader_list;
 
-    new_reader_list = (VReaderList *)g_malloc(sizeof(VReaderList));
-    new_reader_list->head = NULL;
-    new_reader_list->tail = NULL;
+    new_reader_list = g_new0(VReaderList, 1);
     return new_reader_list;
 }
 
@@ -346,7 +339,7 @@ void
 vreader_list_delete(VReaderList *list)
 {
     VReaderListEntry *current_entry;
-    VReaderListEntry *next_entry = NULL;
+    VReaderListEntry *next_entry;
     for (current_entry = vreader_list_get_first(list); current_entry;
          current_entry = next_entry) {
         next_entry = vreader_list_get_next(current_entry);
@@ -437,8 +430,8 @@ vreader_list_unlock(void)
 static VReaderList *
 vreader_copy_list(VReaderList *list)
 {
-    VReaderList *new_list = NULL;
-    VReaderListEntry *current_entry = NULL;
+    VReaderList *new_list;
+    VReaderListEntry *current_entry;
 
     new_list = vreader_list_new();
     if (new_list == NULL) {
@@ -470,7 +463,7 @@ VReader *
 vreader_get_reader_by_id(vreader_id_t id)
 {
     VReader *reader = NULL;
-    VReaderListEntry *current_entry = NULL;
+    VReaderListEntry *current_entry;
 
     if (id == (vreader_id_t) -1) {
         return NULL;
@@ -494,7 +487,7 @@ VReader *
 vreader_get_reader_by_name(const char *name)
 {
     VReader *reader = NULL;
-    VReaderListEntry *current_entry = NULL;
+    VReaderListEntry *current_entry;
 
     vreader_list_lock();
     for (current_entry = vreader_list_get_first(vreader_list); current_entry;
diff --git a/libcacard/vscclient.c b/libcacard/vscclient.c
index 3477ab3e1b..6693900201 100644
--- a/libcacard/vscclient.c
+++ b/libcacard/vscclient.c
@@ -131,8 +131,8 @@ static void *
 event_thread(void *arg)
 {
     unsigned char atr[MAX_ATR_LEN];
-    int atr_len = MAX_ATR_LEN;
-    VEvent *event = NULL;
+    int atr_len;
+    VEvent *event;
     unsigned int reader_id;
 
 
@@ -502,8 +502,7 @@ do_command(GIOChannel *source,
             if (reader != NULL) {
                 error = vcard_emul_force_card_insert(reader);
                 printf("insert %s, returned %d\n",
-                       reader ? vreader_get_name(reader)
-                       : "invalid reader", error);
+                       vreader_get_name(reader), error);
             } else {
                 printf("no reader by id %u found\n", reader_id);
             }
@@ -515,8 +514,7 @@ do_command(GIOChannel *source,
             if (reader != NULL) {
                 error = vcard_emul_force_card_remove(reader);
                 printf("remove %s, returned %d\n",
-                        reader ? vreader_get_name(reader)
-                        : "invalid reader", error);
+                       vreader_get_name(reader), error);
             } else {
                 printf("no reader by id %u found\n", reader_id);
             }
@@ -572,6 +570,7 @@ do_command(GIOChannel *source,
                        "CARD_PRESENT" : "            ",
                        vreader_get_name(reader));
             }
+            vreader_list_delete(list);
         } else if (*string != 0) {
             printf("valid commands:\n");
             printf("insert [reader_id]\n");
diff --git a/linux-headers/asm-s390/kvm.h b/linux-headers/asm-s390/kvm.h
index c003c6a73b..98bedf3c18 100644
--- a/linux-headers/asm-s390/kvm.h
+++ b/linux-headers/asm-s390/kvm.h
@@ -15,6 +15,7 @@
 #include <linux/types.h>
 
 #define __KVM_S390
+#define __KVM_HAVE_GUEST_DEBUG
 
 /* Device control API: s390-specific devices */
 #define KVM_DEV_FLIC_GET_ALL_IRQS	1
@@ -54,6 +55,13 @@ struct kvm_s390_io_adapter_req {
 	__u64 addr;
 };
 
+/* kvm attr_group  on vm fd */
+#define KVM_S390_VM_MEM_CTRL		0
+
+/* kvm attributes for mem_ctrl */
+#define KVM_S390_VM_MEM_ENABLE_CMMA	0
+#define KVM_S390_VM_MEM_CLR_CMMA	1
+
 /* for KVM_GET_REGS and KVM_SET_REGS */
 struct kvm_regs {
 	/* general purpose regs for s390 */
@@ -72,11 +80,31 @@ struct kvm_fpu {
 	__u64 fprs[16];
 };
 
+#define KVM_GUESTDBG_USE_HW_BP		0x00010000
+
+#define KVM_HW_BP			1
+#define KVM_HW_WP_WRITE			2
+#define KVM_SINGLESTEP			4
+
 struct kvm_debug_exit_arch {
+	__u64 addr;
+	__u8 type;
+	__u8 pad[7]; /* Should be set to 0 */
+};
+
+struct kvm_hw_breakpoint {
+	__u64 addr;
+	__u64 phys_addr;
+	__u64 len;
+	__u8 type;
+	__u8 pad[7]; /* Should be set to 0 */
 };
 
 /* for KVM_SET_GUEST_DEBUG */
 struct kvm_guest_debug_arch {
+	__u32 nr_hw_bp;
+	__u32 pad; /* Should be set to 0 */
+	struct kvm_hw_breakpoint *hw_bp;
 };
 
 #define KVM_SYNC_PREFIX (1UL << 0)
diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index b278ab3326..42ddc2cabb 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -416,6 +416,8 @@ struct kvm_s390_psw {
 #define KVM_S390_INT_PFAULT_INIT	0xfffe0004u
 #define KVM_S390_INT_PFAULT_DONE	0xfffe0005u
 #define KVM_S390_MCHK			0xfffe1000u
+#define KVM_S390_INT_CLOCK_COMP		0xffff1004u
+#define KVM_S390_INT_CPU_TIMER		0xffff1005u
 #define KVM_S390_INT_VIRTIO		0xffff2603u
 #define KVM_S390_INT_SERVICE		0xffff2401u
 #define KVM_S390_INT_EMERGENCY		0xffff1201u
@@ -515,6 +517,7 @@ enum {
 	kvm_ioeventfd_flag_nr_pio,
 	kvm_ioeventfd_flag_nr_deassign,
 	kvm_ioeventfd_flag_nr_virtio_ccw_notify,
+	kvm_ioeventfd_flag_nr_fast_mmio,
 	kvm_ioeventfd_flag_nr_max,
 };
 
@@ -529,7 +532,7 @@ enum {
 struct kvm_ioeventfd {
 	__u64 datamatch;
 	__u64 addr;        /* legal pio/mmio address */
-	__u32 len;         /* 1, 2, 4, or 8 bytes    */
+	__u32 len;         /* 1, 2, 4, or 8 bytes; or 0 to ignore length */
 	__s32 fd;
 	__u32 flags;
 	__u8  pad[36];
@@ -743,6 +746,8 @@ struct kvm_ppc_smmu_info {
 #define KVM_CAP_IOAPIC_POLARITY_IGNORED 97
 #define KVM_CAP_ENABLE_CAP_VM 98
 #define KVM_CAP_S390_IRQCHIP 99
+#define KVM_CAP_IOEVENTFD_NO_LENGTH 100
+#define KVM_CAP_VM_ATTRIBUTES 101
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
diff --git a/memory.c b/memory.c
index 3f1df238e2..678661e2bb 100644
--- a/memory.c
+++ b/memory.c
@@ -1722,12 +1722,19 @@ void address_space_init(AddressSpace *as, MemoryRegion *root, const char *name)
 
 void address_space_destroy(AddressSpace *as)
 {
+    MemoryListener *listener;
+
     /* Flush out anything from MemoryListeners listening in on this */
     memory_region_transaction_begin();
     as->root = NULL;
     memory_region_transaction_commit();
     QTAILQ_REMOVE(&address_spaces, as, address_spaces_link);
     address_space_destroy_dispatch(as);
+
+    QTAILQ_FOREACH(listener, &memory_listeners, link) {
+        assert(listener->address_space_filter != as);
+    }
+
     flatview_unref(as->current_map);
     g_free(as->name);
     g_free(as->ioeventfds);
diff --git a/monitor.c b/monitor.c
index 9af6b0ad66..593679a17a 100644
--- a/monitor.c
+++ b/monitor.c
@@ -4269,6 +4269,55 @@ static const char *next_arg_type(const char *typestr)
     return (p != NULL ? ++p : typestr);
 }
 
+static void add_completion_option(ReadLineState *rs, const char *str,
+                                  const char *option)
+{
+    if (!str || !option) {
+        return;
+    }
+    if (!strncmp(option, str, strlen(str))) {
+        readline_add_completion(rs, option);
+    }
+}
+
+void chardev_add_completion(ReadLineState *rs, int nb_args, const char *str)
+{
+    size_t len;
+    ChardevBackendInfoList *list, *start;
+
+    if (nb_args != 2) {
+        return;
+    }
+    len = strlen(str);
+    readline_set_completion_index(rs, len);
+
+    start = list = qmp_query_chardev_backends(NULL);
+    while (list) {
+        const char *chr_name = list->value->name;
+
+        if (!strncmp(chr_name, str, len)) {
+            readline_add_completion(rs, chr_name);
+        }
+        list = list->next;
+    }
+    qapi_free_ChardevBackendInfoList(start);
+}
+
+void netdev_add_completion(ReadLineState *rs, int nb_args, const char *str)
+{
+    size_t len;
+    int i;
+
+    if (nb_args != 2) {
+        return;
+    }
+    len = strlen(str);
+    readline_set_completion_index(rs, len);
+    for (i = 0; NetClientOptionsKind_lookup[i]; i++) {
+        add_completion_option(rs, str, NetClientOptionsKind_lookup[i]);
+    }
+}
+
 void device_add_completion(ReadLineState *rs, int nb_args, const char *str)
 {
     GSList *list, *elt;
@@ -4339,6 +4388,29 @@ static void device_del_bus_completion(ReadLineState *rs,  BusState *bus,
     }
 }
 
+void chardev_remove_completion(ReadLineState *rs, int nb_args, const char *str)
+{
+    size_t len;
+    ChardevInfoList *list, *start;
+
+    if (nb_args != 2) {
+        return;
+    }
+    len = strlen(str);
+    readline_set_completion_index(rs, len);
+
+    start = list = qmp_query_chardev(NULL);
+    while (list) {
+        ChardevInfo *chr = list->value;
+
+        if (!strncmp(chr->label, str, len)) {
+            readline_add_completion(rs, chr->label);
+        }
+        list = list->next;
+    }
+    qapi_free_ChardevInfoList(start);
+}
+
 void device_del_completion(ReadLineState *rs, int nb_args, const char *str)
 {
     size_t len;
@@ -4376,6 +4448,77 @@ void object_del_completion(ReadLineState *rs, int nb_args, const char *str)
     qapi_free_ObjectPropertyInfoList(start);
 }
 
+void sendkey_completion(ReadLineState *rs, int nb_args, const char *str)
+{
+    int i;
+    char *sep;
+    size_t len;
+
+    if (nb_args != 2) {
+        return;
+    }
+    sep = strrchr(str, '-');
+    if (sep) {
+        str = sep + 1;
+    }
+    len = strlen(str);
+    readline_set_completion_index(rs, len);
+    for (i = 0; i < Q_KEY_CODE_MAX; i++) {
+        if (!strncmp(str, QKeyCode_lookup[i], len)) {
+            readline_add_completion(rs, QKeyCode_lookup[i]);
+        }
+    }
+}
+
+void set_link_completion(ReadLineState *rs, int nb_args, const char *str)
+{
+    size_t len;
+
+    len = strlen(str);
+    readline_set_completion_index(rs, len);
+    if (nb_args == 2) {
+        NetClientState *ncs[255];
+        int count, i;
+        count = qemu_find_net_clients_except(NULL, ncs,
+                                             NET_CLIENT_OPTIONS_KIND_NONE, 255);
+        for (i = 0; i < count; i++) {
+            const char *name = ncs[i]->name;
+            if (!strncmp(str, name, len)) {
+                readline_add_completion(rs, name);
+            }
+        }
+    } else if (nb_args == 3) {
+        add_completion_option(rs, str, "on");
+        add_completion_option(rs, str, "off");
+    }
+}
+
+void netdev_del_completion(ReadLineState *rs, int nb_args, const char *str)
+{
+    int len, count, i;
+    NetClientState *ncs[255];
+
+    if (nb_args != 2) {
+        return;
+    }
+
+    len = strlen(str);
+    readline_set_completion_index(rs, len);
+    count = qemu_find_net_clients_except(NULL, ncs, NET_CLIENT_OPTIONS_KIND_NIC,
+                                         255);
+    for (i = 0; i < count; i++) {
+        QemuOpts *opts;
+        const char *name = ncs[i]->name;
+        if (strncmp(str, name, len)) {
+            continue;
+        }
+        opts = qemu_opts_find(qemu_find_opts_err("netdev", NULL), name);
+        if (opts) {
+            readline_add_completion(rs, name);
+        }
+    }
+}
+
 static void monitor_find_completion_by_table(Monitor *mon,
                                              const mon_cmd_t *cmd_table,
                                              char **args,
@@ -4444,15 +4587,7 @@ static void monitor_find_completion_by_table(Monitor *mon,
             break;
         case 's':
         case 'S':
-            if (!strcmp(cmd->name, "sendkey")) {
-                char *sep = strrchr(str, '-');
-                if (sep)
-                    str = sep + 1;
-                readline_set_completion_index(mon->rs, strlen(str));
-                for (i = 0; i < Q_KEY_CODE_MAX; i++) {
-                    cmd_completion(mon, str, QKeyCode_lookup[i]);
-                }
-            } else if (!strcmp(cmd->name, "help|?")) {
+            if (!strcmp(cmd->name, "help|?")) {
                 monitor_find_completion_by_table(mon, cmd_table,
                                                  &args[1], nb_args - 1);
             }
diff --git a/nbd.c b/nbd.c
index e5084b6e7c..e0d032c252 100644
--- a/nbd.c
+++ b/nbd.c
@@ -306,7 +306,7 @@ static int nbd_send_negotiate(NBDClient *client)
         [ 8 ..  15]   magic        (NBD_CLIENT_MAGIC)
         [16 ..  23]   size
         [24 ..  25]   server flags (0)
-        [24 ..  27]   export flags
+        [26 ..  27]   export flags
         [28 .. 151]   reserved     (0)
 
        Negotiation header with options, part 1:
diff --git a/net/net.c b/net/net.c
index 9db4dba769..0ff2e40f35 100644
--- a/net/net.c
+++ b/net/net.c
@@ -633,7 +633,7 @@ int qemu_find_net_clients_except(const char *id, NetClientState **ncs,
         if (nc->info->type == type) {
             continue;
         }
-        if (!strcmp(nc->name, id)) {
+        if (!id || !strcmp(nc->name, id)) {
             if (ret < max) {
                 ncs[ret] = nc;
             }
diff --git a/pc-bios/bios-256k.bin b/pc-bios/bios-256k.bin
index 3e60a3dddb..09686a3814 100644
--- a/pc-bios/bios-256k.bin
+++ b/pc-bios/bios-256k.bin
Binary files differdiff --git a/pc-bios/bios.bin b/pc-bios/bios.bin
index d360d0a232..2314027c3c 100644
--- a/pc-bios/bios.bin
+++ b/pc-bios/bios.bin
Binary files differdiff --git a/pc-bios/vgabios-cirrus.bin b/pc-bios/vgabios-cirrus.bin
index 2ddef2ee5d..57a5f954af 100644
--- a/pc-bios/vgabios-cirrus.bin
+++ b/pc-bios/vgabios-cirrus.bin
Binary files differdiff --git a/pc-bios/vgabios-qxl.bin b/pc-bios/vgabios-qxl.bin
index f84a984954..ed79993ad5 100644
--- a/pc-bios/vgabios-qxl.bin
+++ b/pc-bios/vgabios-qxl.bin
Binary files differdiff --git a/pc-bios/vgabios-stdvga.bin b/pc-bios/vgabios-stdvga.bin
index 833c464d58..d3579b4fb9 100644
--- a/pc-bios/vgabios-stdvga.bin
+++ b/pc-bios/vgabios-stdvga.bin
Binary files differdiff --git a/pc-bios/vgabios-vmware.bin b/pc-bios/vgabios-vmware.bin
index c4bf32260b..f89845e75c 100644
--- a/pc-bios/vgabios-vmware.bin
+++ b/pc-bios/vgabios-vmware.bin
Binary files differdiff --git a/pc-bios/vgabios.bin b/pc-bios/vgabios.bin
index 55c6db3b8e..d3038f4184 100644
--- a/pc-bios/vgabios.bin
+++ b/pc-bios/vgabios.bin
Binary files differdiff --git a/qapi-schema.json b/qapi-schema.json
index 36cb964dfd..7bc33ea717 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -691,7 +691,7 @@
 # Information about current migration process.
 #
 # @status: #optional string describing the current migration status.
-#          As of 0.14.0 this can be 'active', 'completed', 'failed' or
+#          As of 0.14.0 this can be 'setup', 'active', 'completed', 'failed' or
 #          'cancelled'. If this field is not returned, no migration process
 #          has been initiated
 #
@@ -942,6 +942,8 @@
 # @encryption_key_missing: true if the backing device is encrypted but an
 #                          valid encryption key is missing
 #
+# @detect_zeroes: detect and optimize zero writes (Since 2.1)
+#
 # @bps: total throughput limit in bytes per second is specified
 #
 # @bps_rd: read throughput limit in bytes per second is specified
@@ -977,6 +979,7 @@
   'data': { 'file': 'str', '*node-name': 'str', 'ro': 'bool', 'drv': 'str',
             '*backing_file': 'str', 'backing_file_depth': 'int',
             'encrypted': 'bool', 'encryption_key_missing': 'bool',
+            'detect_zeroes': 'BlockdevDetectZeroesOptions',
             'bps': 'int', 'bps_rd': 'int', 'bps_wr': 'int',
             'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int',
             'image': 'ImageInfo',
@@ -4255,6 +4258,22 @@
   'data': [ 'ignore', 'unmap' ] }
 
 ##
+# @BlockdevDetectZeroesOptions
+#
+# Describes the operation mode for the automatic conversion of plain
+# zero writes by the OS to driver specific optimized zero write commands.
+#
+# @off:      Disabled (default)
+# @on:       Enabled
+# @unmap:    Enabled and even try to unmap blocks if possible. This requires
+#            also that @BlockdevDiscardOptions is set to unmap for this device.
+#
+# Since: 2.1
+##
+{ 'enum': 'BlockdevDetectZeroesOptions',
+  'data': [ 'off', 'on', 'unmap' ] }
+
+##
 # @BlockdevAioOptions
 #
 # Selects the AIO backend to handle I/O requests
@@ -4306,20 +4325,22 @@
 # Options that are available for all block devices, independent of the block
 # driver.
 #
-# @driver:      block driver name
-# @id:          #optional id by which the new block device can be referred to.
-#               This is a required option on the top level of blockdev-add, and
-#               currently not allowed on any other level.
-# @node-name:   #optional the name of a block driver state node (Since 2.0)
-# @discard:     #optional discard-related options (default: ignore)
-# @cache:       #optional cache-related options
-# @aio:         #optional AIO backend (default: threads)
-# @rerror:      #optional how to handle read errors on the device
-#               (default: report)
-# @werror:      #optional how to handle write errors on the device
-#               (default: enospc)
-# @read-only:   #optional whether the block device should be read-only
-#               (default: false)
+# @driver:        block driver name
+# @id:            #optional id by which the new block device can be referred to.
+#                 This is a required option on the top level of blockdev-add, and
+#                 currently not allowed on any other level.
+# @node-name:     #optional the name of a block driver state node (Since 2.0)
+# @discard:       #optional discard-related options (default: ignore)
+# @cache:         #optional cache-related options
+# @aio:           #optional AIO backend (default: threads)
+# @rerror:        #optional how to handle read errors on the device
+#                 (default: report)
+# @werror:        #optional how to handle write errors on the device
+#                 (default: enospc)
+# @read-only:     #optional whether the block device should be read-only
+#                 (default: false)
+# @detect-zeroes: #optional detect and optimize zero writes (Since 2.1)
+#                 (default: off)
 #
 # Since: 1.7
 ##
@@ -4332,7 +4353,8 @@
             '*aio': 'BlockdevAioOptions',
             '*rerror': 'BlockdevOnError',
             '*werror': 'BlockdevOnError',
-            '*read-only': 'bool' } }
+            '*read-only': 'bool',
+            '*detect-zeroes': 'BlockdevDetectZeroesOptions' } }
 
 ##
 # @BlockdevOptionsFile
diff --git a/qapi/opts-visitor.c b/qapi/opts-visitor.c
index 87c1c789c9..16382e7a65 100644
--- a/qapi/opts-visitor.c
+++ b/qapi/opts-visitor.c
@@ -484,8 +484,7 @@ opts_type_size(Visitor *v, uint64_t *obj, const char *name, Error **errp)
 
 
 static void
-opts_start_optional(Visitor *v, bool *present, const char *name,
-                       Error **errp)
+opts_optional(Visitor *v, bool *present, const char *name, Error **errp)
 {
     OptsVisitor *ov = DO_UPCAST(OptsVisitor, visitor, v);
 
@@ -528,7 +527,7 @@ opts_visitor_new(const QemuOpts *opts)
     /* type_number() is not filled in, but this is not the first visitor to
      * skip some mandatory methods... */
 
-    ov->visitor.start_optional = &opts_start_optional;
+    ov->visitor.optional = &opts_optional;
 
     ov->opts_root = opts;
 
diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c
index 6451a21a28..55f8d4068c 100644
--- a/qapi/qapi-visit-core.c
+++ b/qapi/qapi-visit-core.c
@@ -17,46 +17,27 @@
 #include "qapi/visitor.h"
 #include "qapi/visitor-impl.h"
 
-void visit_start_handle(Visitor *v, void **obj, const char *kind,
-                        const char *name, Error **errp)
-{
-    if (!error_is_set(errp) && v->start_handle) {
-        v->start_handle(v, obj, kind, name, errp);
-    }
-}
-
-void visit_end_handle(Visitor *v, Error **errp)
-{
-    if (!error_is_set(errp) && v->end_handle) {
-        v->end_handle(v, errp);
-    }
-}
-
 void visit_start_struct(Visitor *v, void **obj, const char *kind,
                         const char *name, size_t size, Error **errp)
 {
-    if (!error_is_set(errp)) {
-        v->start_struct(v, obj, kind, name, size, errp);
-    }
+    v->start_struct(v, obj, kind, name, size, errp);
 }
 
 void visit_end_struct(Visitor *v, Error **errp)
 {
-    assert(!error_is_set(errp));
     v->end_struct(v, errp);
 }
 
 void visit_start_implicit_struct(Visitor *v, void **obj, size_t size,
                                  Error **errp)
 {
-    if (!error_is_set(errp) && v->start_implicit_struct) {
+    if (v->start_implicit_struct) {
         v->start_implicit_struct(v, obj, size, errp);
     }
 }
 
 void visit_end_implicit_struct(Visitor *v, Error **errp)
 {
-    assert(!error_is_set(errp));
     if (v->end_implicit_struct) {
         v->end_implicit_struct(v, errp);
     }
@@ -64,45 +45,31 @@ void visit_end_implicit_struct(Visitor *v, Error **errp)
 
 void visit_start_list(Visitor *v, const char *name, Error **errp)
 {
-    if (!error_is_set(errp)) {
-        v->start_list(v, name, errp);
-    }
+    v->start_list(v, name, errp);
 }
 
 GenericList *visit_next_list(Visitor *v, GenericList **list, Error **errp)
 {
-    if (!error_is_set(errp)) {
-        return v->next_list(v, list, errp);
-    }
-
-    return 0;
+    return v->next_list(v, list, errp);
 }
 
 void visit_end_list(Visitor *v, Error **errp)
 {
-    assert(!error_is_set(errp));
     v->end_list(v, errp);
 }
 
-void visit_start_optional(Visitor *v, bool *present, const char *name,
-                          Error **errp)
+void visit_optional(Visitor *v, bool *present, const char *name,
+                    Error **errp)
 {
-    if (!error_is_set(errp) && v->start_optional) {
-        v->start_optional(v, present, name, errp);
-    }
-}
-
-void visit_end_optional(Visitor *v, Error **errp)
-{
-    if (!error_is_set(errp) && v->end_optional) {
-        v->end_optional(v, errp);
+    if (v->optional) {
+        v->optional(v, present, name, errp);
     }
 }
 
 void visit_get_next_type(Visitor *v, int *obj, const int *qtypes,
                          const char *name, Error **errp)
 {
-    if (!error_is_set(errp) && v->get_next_type) {
+    if (v->get_next_type) {
         v->get_next_type(v, obj, qtypes, name, errp);
     }
 }
@@ -110,192 +77,172 @@ void visit_get_next_type(Visitor *v, int *obj, const int *qtypes,
 void visit_type_enum(Visitor *v, int *obj, const char *strings[],
                      const char *kind, const char *name, Error **errp)
 {
-    if (!error_is_set(errp)) {
-        v->type_enum(v, obj, strings, kind, name, errp);
-    }
+    v->type_enum(v, obj, strings, kind, name, errp);
 }
 
 void visit_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp)
 {
-    if (!error_is_set(errp)) {
-        v->type_int(v, obj, name, errp);
-    }
+    v->type_int(v, obj, name, errp);
 }
 
 void visit_type_uint8(Visitor *v, uint8_t *obj, const char *name, Error **errp)
 {
     int64_t value;
-    if (!error_is_set(errp)) {
-        if (v->type_uint8) {
-            v->type_uint8(v, obj, name, errp);
-        } else {
-            value = *obj;
-            v->type_int(v, &value, name, errp);
-            if (value < 0 || value > UINT8_MAX) {
-                error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
-                          "uint8_t");
-                return;
-            }
-            *obj = value;
+
+    if (v->type_uint8) {
+        v->type_uint8(v, obj, name, errp);
+    } else {
+        value = *obj;
+        v->type_int(v, &value, name, errp);
+        if (value < 0 || value > UINT8_MAX) {
+            error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
+                      "uint8_t");
+            return;
         }
+        *obj = value;
     }
 }
 
 void visit_type_uint16(Visitor *v, uint16_t *obj, const char *name, Error **errp)
 {
     int64_t value;
-    if (!error_is_set(errp)) {
-        if (v->type_uint16) {
-            v->type_uint16(v, obj, name, errp);
-        } else {
-            value = *obj;
-            v->type_int(v, &value, name, errp);
-            if (value < 0 || value > UINT16_MAX) {
-                error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
-                          "uint16_t");
-                return;
-            }
-            *obj = value;
+
+    if (v->type_uint16) {
+        v->type_uint16(v, obj, name, errp);
+    } else {
+        value = *obj;
+        v->type_int(v, &value, name, errp);
+        if (value < 0 || value > UINT16_MAX) {
+            error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
+                      "uint16_t");
+            return;
         }
+        *obj = value;
     }
 }
 
 void visit_type_uint32(Visitor *v, uint32_t *obj, const char *name, Error **errp)
 {
     int64_t value;
-    if (!error_is_set(errp)) {
-        if (v->type_uint32) {
-            v->type_uint32(v, obj, name, errp);
-        } else {
-            value = *obj;
-            v->type_int(v, &value, name, errp);
-            if (value < 0 || value > UINT32_MAX) {
-                error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
-                          "uint32_t");
-                return;
-            }
-            *obj = value;
+
+    if (v->type_uint32) {
+        v->type_uint32(v, obj, name, errp);
+    } else {
+        value = *obj;
+        v->type_int(v, &value, name, errp);
+        if (value < 0 || value > UINT32_MAX) {
+            error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
+                      "uint32_t");
+            return;
         }
+        *obj = value;
     }
 }
 
 void visit_type_uint64(Visitor *v, uint64_t *obj, const char *name, Error **errp)
 {
     int64_t value;
-    if (!error_is_set(errp)) {
-        if (v->type_uint64) {
-            v->type_uint64(v, obj, name, errp);
-        } else {
-            value = *obj;
-            v->type_int(v, &value, name, errp);
-            *obj = value;
-        }
+
+    if (v->type_uint64) {
+        v->type_uint64(v, obj, name, errp);
+    } else {
+        value = *obj;
+        v->type_int(v, &value, name, errp);
+        *obj = value;
     }
 }
 
 void visit_type_int8(Visitor *v, int8_t *obj, const char *name, Error **errp)
 {
     int64_t value;
-    if (!error_is_set(errp)) {
-        if (v->type_int8) {
-            v->type_int8(v, obj, name, errp);
-        } else {
-            value = *obj;
-            v->type_int(v, &value, name, errp);
-            if (value < INT8_MIN || value > INT8_MAX) {
-                error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
-                          "int8_t");
-                return;
-            }
-            *obj = value;
+
+    if (v->type_int8) {
+        v->type_int8(v, obj, name, errp);
+    } else {
+        value = *obj;
+        v->type_int(v, &value, name, errp);
+        if (value < INT8_MIN || value > INT8_MAX) {
+            error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
+                      "int8_t");
+            return;
         }
+        *obj = value;
     }
 }
 
 void visit_type_int16(Visitor *v, int16_t *obj, const char *name, Error **errp)
 {
     int64_t value;
-    if (!error_is_set(errp)) {
-        if (v->type_int16) {
-            v->type_int16(v, obj, name, errp);
-        } else {
-            value = *obj;
-            v->type_int(v, &value, name, errp);
-            if (value < INT16_MIN || value > INT16_MAX) {
-                error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
-                          "int16_t");
-                return;
-            }
-            *obj = value;
+
+    if (v->type_int16) {
+        v->type_int16(v, obj, name, errp);
+    } else {
+        value = *obj;
+        v->type_int(v, &value, name, errp);
+        if (value < INT16_MIN || value > INT16_MAX) {
+            error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
+                      "int16_t");
+            return;
         }
+        *obj = value;
     }
 }
 
 void visit_type_int32(Visitor *v, int32_t *obj, const char *name, Error **errp)
 {
     int64_t value;
-    if (!error_is_set(errp)) {
-        if (v->type_int32) {
-            v->type_int32(v, obj, name, errp);
-        } else {
-            value = *obj;
-            v->type_int(v, &value, name, errp);
-            if (value < INT32_MIN || value > INT32_MAX) {
-                error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
-                          "int32_t");
-                return;
-            }
-            *obj = value;
+
+    if (v->type_int32) {
+        v->type_int32(v, obj, name, errp);
+    } else {
+        value = *obj;
+        v->type_int(v, &value, name, errp);
+        if (value < INT32_MIN || value > INT32_MAX) {
+            error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
+                      "int32_t");
+            return;
         }
+        *obj = value;
     }
 }
 
 void visit_type_int64(Visitor *v, int64_t *obj, const char *name, Error **errp)
 {
-    if (!error_is_set(errp)) {
-        if (v->type_int64) {
-            v->type_int64(v, obj, name, errp);
-        } else {
-            v->type_int(v, obj, name, errp);
-        }
+    if (v->type_int64) {
+        v->type_int64(v, obj, name, errp);
+    } else {
+        v->type_int(v, obj, name, errp);
     }
 }
 
 void visit_type_size(Visitor *v, uint64_t *obj, const char *name, Error **errp)
 {
     int64_t value;
-    if (!error_is_set(errp)) {
-        if (v->type_size) {
-            v->type_size(v, obj, name, errp);
-        } else if (v->type_uint64) {
-            v->type_uint64(v, obj, name, errp);
-        } else {
-            value = *obj;
-            v->type_int(v, &value, name, errp);
-            *obj = value;
-        }
+
+    if (v->type_size) {
+        v->type_size(v, obj, name, errp);
+    } else if (v->type_uint64) {
+        v->type_uint64(v, obj, name, errp);
+    } else {
+        value = *obj;
+        v->type_int(v, &value, name, errp);
+        *obj = value;
     }
 }
 
 void visit_type_bool(Visitor *v, bool *obj, const char *name, Error **errp)
 {
-    if (!error_is_set(errp)) {
-        v->type_bool(v, obj, name, errp);
-    }
+    v->type_bool(v, obj, name, errp);
 }
 
 void visit_type_str(Visitor *v, char **obj, const char *name, Error **errp)
 {
-    if (!error_is_set(errp)) {
-        v->type_str(v, obj, name, errp);
-    }
+    v->type_str(v, obj, name, errp);
 }
 
 void visit_type_number(Visitor *v, double *obj, const char *name, Error **errp)
 {
-    if (!error_is_set(errp)) {
-        v->type_number(v, obj, name, errp);
-    }
+    v->type_number(v, obj, name, errp);
 }
 
 void output_type_enum(Visitor *v, int *obj, const char *strings[],
@@ -321,13 +268,15 @@ void input_type_enum(Visitor *v, int *obj, const char *strings[],
                      const char *kind, const char *name,
                      Error **errp)
 {
+    Error *local_err = NULL;
     int64_t value = 0;
     char *enum_str;
 
     assert(strings);
 
-    visit_type_str(v, &enum_str, name, errp);
-    if (error_is_set(errp)) {
+    visit_type_str(v, &enum_str, name, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
         return;
     }
 
diff --git a/qapi/qmp-input-visitor.c b/qapi/qmp-input-visitor.c
index a2bed1ef10..d8612062f1 100644
--- a/qapi/qmp-input-visitor.c
+++ b/qapi/qmp-input-visitor.c
@@ -286,8 +286,8 @@ static void qmp_input_type_number(Visitor *v, double *obj, const char *name,
     }
 }
 
-static void qmp_input_start_optional(Visitor *v, bool *present,
-                                     const char *name, Error **errp)
+static void qmp_input_optional(Visitor *v, bool *present, const char *name,
+                               Error **errp)
 {
     QmpInputVisitor *qiv = to_qiv(v);
     QObject *qobj = qmp_input_get_object(qiv, name, true);
@@ -329,7 +329,7 @@ QmpInputVisitor *qmp_input_visitor_new(QObject *obj)
     v->visitor.type_bool = qmp_input_type_bool;
     v->visitor.type_str = qmp_input_type_str;
     v->visitor.type_number = qmp_input_type_number;
-    v->visitor.start_optional = qmp_input_start_optional;
+    v->visitor.optional = qmp_input_optional;
     v->visitor.get_next_type = qmp_input_get_next_type;
 
     qmp_input_push(v, obj, NULL);
diff --git a/qapi/qmp-output-visitor.c b/qapi/qmp-output-visitor.c
index 74a5684ed3..96b338463e 100644
--- a/qapi/qmp-output-visitor.c
+++ b/qapi/qmp-output-visitor.c
@@ -66,6 +66,12 @@ static QObject *qmp_output_pop(QmpOutputVisitor *qov)
 static QObject *qmp_output_first(QmpOutputVisitor *qov)
 {
     QStackEntry *e = QTAILQ_LAST(&qov->stack, QStack);
+
+    /* FIXME - find a better way to deal with NULL values */
+    if (!e) {
+        return NULL;
+    }
+
     return e->value;
 }
 
diff --git a/qapi/string-input-visitor.c b/qapi/string-input-visitor.c
index 793548ae3a..5780944792 100644
--- a/qapi/string-input-visitor.c
+++ b/qapi/string-input-visitor.c
@@ -120,8 +120,8 @@ static void parse_type_number(Visitor *v, double *obj, const char *name,
     *obj = val;
 }
 
-static void parse_start_optional(Visitor *v, bool *present,
-                                 const char *name, Error **errp)
+static void parse_optional(Visitor *v, bool *present, const char *name,
+                           Error **errp)
 {
     StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v);
 
@@ -155,7 +155,7 @@ StringInputVisitor *string_input_visitor_new(const char *str)
     v->visitor.type_bool = parse_type_bool;
     v->visitor.type_str = parse_type_str;
     v->visitor.type_number = parse_type_number;
-    v->visitor.start_optional = parse_start_optional;
+    v->visitor.optional = parse_optional;
 
     v->string = str;
     return v;
diff --git a/qdev-monitor.c b/qdev-monitor.c
index 02cbe43bce..f87f3d89cd 100644
--- a/qdev-monitor.c
+++ b/qdev-monitor.c
@@ -613,14 +613,20 @@ static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
 {
     ObjectClass *class;
     BusState *child;
+    NamedGPIOList *ngl;
+
     qdev_printf("dev: %s, id \"%s\"\n", object_get_typename(OBJECT(dev)),
                 dev->id ? dev->id : "");
     indent += 2;
-    if (dev->num_gpio_in) {
-        qdev_printf("gpio-in %d\n", dev->num_gpio_in);
-    }
-    if (dev->num_gpio_out) {
-        qdev_printf("gpio-out %d\n", dev->num_gpio_out);
+    QLIST_FOREACH(ngl, &dev->gpios, node) {
+        if (ngl->num_in) {
+            qdev_printf("gpio-in \"%s\" %d\n", ngl->name ? ngl->name : "",
+                        ngl->num_in);
+        }
+        if (ngl->num_out) {
+            qdev_printf("gpio-out \"%s\" %d\n", ngl->name ? ngl->name : "",
+                        ngl->num_out);
+        }
     }
     class = object_get_class(OBJECT(dev));
     do {
diff --git a/qemu-char.c b/qemu-char.c
index 54ed244542..17b476edf0 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -3204,6 +3204,7 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts,
                                     void (*init)(struct CharDriverState *s),
                                     Error **errp)
 {
+    Error *local_err = NULL;
     CharDriver *cd;
     CharDriverState *chr;
     GSList *i;
@@ -3245,13 +3246,14 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts,
         chr = NULL;
         backend->kind = cd->kind;
         if (cd->parse) {
-            cd->parse(opts, backend, errp);
-            if (error_is_set(errp)) {
+            cd->parse(opts, backend, &local_err);
+            if (local_err) {
+                error_propagate(errp, local_err);
                 goto qapi_out;
             }
         }
         ret = qmp_chardev_add(bid ? bid : id, backend, errp);
-        if (error_is_set(errp)) {
+        if (!ret) {
             goto qapi_out;
         }
 
@@ -3263,7 +3265,7 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts,
             backend->kind = CHARDEV_BACKEND_KIND_MUX;
             backend->mux->chardev = g_strdup(bid);
             ret = qmp_chardev_add(id, backend, errp);
-            if (error_is_set(errp)) {
+            if (!ret) {
                 chr = qemu_chr_find(bid);
                 qemu_chr_delete(chr);
                 chr = NULL;
@@ -3620,18 +3622,18 @@ static int qmp_chardev_open_file_source(char *src, int flags,
 
 static CharDriverState *qmp_chardev_open_file(ChardevFile *file, Error **errp)
 {
-    int flags, in = -1, out = -1;
+    int flags, in = -1, out;
 
     flags = O_WRONLY | O_TRUNC | O_CREAT | O_BINARY;
     out = qmp_chardev_open_file_source(file->out, flags, errp);
-    if (error_is_set(errp)) {
+    if (out < 0) {
         return NULL;
     }
 
     if (file->has_in) {
         flags = O_RDONLY;
         in = qmp_chardev_open_file_source(file->in, flags, errp);
-        if (error_is_set(errp)) {
+        if (in < 0) {
             qemu_close(out);
             return NULL;
         }
@@ -3647,7 +3649,7 @@ static CharDriverState *qmp_chardev_open_serial(ChardevHostdev *serial,
     int fd;
 
     fd = qmp_chardev_open_file_source(serial->device, O_RDWR, errp);
-    if (error_is_set(errp)) {
+    if (fd < 0) {
         return NULL;
     }
     qemu_set_nonblock(fd);
@@ -3665,7 +3667,7 @@ static CharDriverState *qmp_chardev_open_parallel(ChardevHostdev *parallel,
     int fd;
 
     fd = qmp_chardev_open_file_source(parallel->device, O_RDWR, errp);
-    if (error_is_set(errp)) {
+    if (fd < 0) {
         return NULL;
     }
     return qemu_chr_open_pp_fd(fd);
@@ -3692,7 +3694,7 @@ static CharDriverState *qmp_chardev_open_socket(ChardevSocket *sock,
     } else {
         fd = socket_connect(addr, errp, NULL, NULL);
     }
-    if (error_is_set(errp)) {
+    if (fd < 0) {
         return NULL;
     }
     return qemu_chr_open_socket_fd(fd, do_nodelay, is_listen,
@@ -3705,7 +3707,7 @@ static CharDriverState *qmp_chardev_open_udp(ChardevUdp *udp,
     int fd;
 
     fd = socket_dgram(udp->remote, udp->local, errp);
-    if (error_is_set(errp)) {
+    if (fd < 0) {
         return NULL;
     }
     return qemu_chr_open_udp_fd(fd);
@@ -3796,7 +3798,13 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
         break;
     }
 
-    if (chr == NULL && !error_is_set(errp)) {
+    /*
+     * Character backend open hasn't been fully converted to the Error
+     * API.  Some opens fail without setting an error.  Set a generic
+     * error then.
+     * TODO full conversion to Error API
+     */
+    if (chr == NULL && errp && !*errp) {
         error_setg(errp, "Failed to create chardev");
     }
     if (chr) {
diff --git a/qemu-img.c b/qemu-img.c
index 04ce02aeb4..b3d2bc6f02 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -70,11 +70,8 @@ static void add_format_to_seq(void *opaque, const char *fmt_name)
 {
     GSequence *seq = opaque;
 
-    if (!g_sequence_lookup(seq, (gpointer)fmt_name,
-                           compare_data, NULL)) {
-        g_sequence_insert_sorted(seq, (gpointer)fmt_name,
-                                 compare_data, NULL);
-    }
+    g_sequence_insert_sorted(seq, (gpointer)fmt_name,
+                             compare_data, NULL);
 }
 
 static void QEMU_NORETURN GCC_FMT_ATTR(1, 2) error_exit(const char *fmt, ...)
@@ -290,6 +287,7 @@ static int print_block_option_help(const char *filename, const char *fmt)
         proto_drv = bdrv_find_protocol(filename, true);
         if (!proto_drv) {
             error_report("Unknown protocol '%s'", filename);
+            free_option_parameters(create_options);
             return 1;
         }
         create_options = append_option_parameters(create_options,
@@ -665,9 +663,7 @@ static int img_check(int argc, char **argv)
     ret = collect_image_check(bs, check, filename, fmt, fix);
 
     if (ret == -ENOTSUP) {
-        if (output_format == OFORMAT_HUMAN) {
-            error_report("This image format does not support checks");
-        }
+        error_report("This image format does not support checks");
         ret = 63;
         goto fail;
     }
@@ -1457,7 +1453,7 @@ static int img_convert(int argc, char **argv)
     ret = bdrv_parse_cache_flags(cache, &flags);
     if (ret < 0) {
         error_report("Invalid cache option: %s", cache);
-        return -1;
+        goto out;
     }
 
     out_bs = bdrv_new_open("target", out_filename, out_fmt, flags, true, quiet);
diff --git a/qemu-io.c b/qemu-io.c
index 9fcd72bb10..795cf46c6e 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -54,6 +54,7 @@ static int openfile(char *name, int flags, int growable, QDict *opts)
 
     if (qemuio_bs) {
         fprintf(stderr, "file open already, try 'help close'\n");
+        QDECREF(opts);
         return 1;
     }
 
@@ -61,7 +62,8 @@ static int openfile(char *name, int flags, int growable, QDict *opts)
         if (bdrv_open(&qemuio_bs, name, NULL, opts, flags | BDRV_O_PROTOCOL,
                       NULL, &local_err))
         {
-            fprintf(stderr, "%s: can't open device %s: %s\n", progname, name,
+            fprintf(stderr, "%s: can't open%s%s: %s\n", progname,
+                    name ? " device " : "", name ?: "",
                     error_get_pretty(local_err));
             error_free(local_err);
             return 1;
@@ -72,7 +74,8 @@ static int openfile(char *name, int flags, int growable, QDict *opts)
         if (bdrv_open(&qemuio_bs, name, NULL, opts, flags, NULL, &local_err)
             < 0)
         {
-            fprintf(stderr, "%s: can't open device %s: %s\n", progname, name,
+            fprintf(stderr, "%s: can't open%s%s: %s\n", progname,
+                    name ? " device " : "", name ?: "",
                     error_get_pretty(local_err));
             error_free(local_err);
             bdrv_unref(qemuio_bs);
@@ -118,6 +121,7 @@ static const cmdinfo_t open_cmd = {
 
 static QemuOptsList empty_opts = {
     .name = "drive",
+    .merge_lists = true,
     .head = QTAILQ_HEAD_INITIALIZER(empty_opts.head),
     .desc = {
         /* no elements => accept any params */
@@ -132,7 +136,7 @@ static int open_f(BlockDriverState *bs, int argc, char **argv)
     int growable = 0;
     int c;
     QemuOpts *qopts;
-    QDict *opts = NULL;
+    QDict *opts;
 
     while ((c = getopt(argc, argv, "snrgo:")) != EOF) {
         switch (c) {
@@ -149,15 +153,14 @@ static int open_f(BlockDriverState *bs, int argc, char **argv)
             growable = 1;
             break;
         case 'o':
-            qopts = qemu_opts_parse(&empty_opts, optarg, 0);
-            if (qopts == NULL) {
+            if (!qemu_opts_parse(&empty_opts, optarg, 0)) {
                 printf("could not parse option list -- %s\n", optarg);
+                qemu_opts_reset(&empty_opts);
                 return 0;
             }
-            opts = qemu_opts_to_qdict(qopts, opts);
-            qemu_opts_del(qopts);
             break;
         default:
+            qemu_opts_reset(&empty_opts);
             return qemuio_command_usage(&open_cmd);
         }
     }
@@ -166,11 +169,16 @@ static int open_f(BlockDriverState *bs, int argc, char **argv)
         flags |= BDRV_O_RDWR;
     }
 
+    qopts = qemu_opts_find(&empty_opts, NULL);
+    opts = qopts ? qemu_opts_to_qdict(qopts, NULL) : NULL;
+    qemu_opts_reset(&empty_opts);
+
     if (optind == argc - 1) {
         return openfile(argv[optind], flags, growable, opts);
     } else if (optind == argc) {
         return openfile(NULL, flags, growable, opts);
     } else {
+        QDECREF(opts);
         return qemuio_command_usage(&open_cmd);
     }
 }
diff --git a/qemu-nbd.c b/qemu-nbd.c
index eed79fa15e..ba6043680a 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -223,7 +223,7 @@ static int tcp_socket_incoming(const char *address, uint16_t port)
     int fd = inet_listen(address_and_port, NULL, 0, SOCK_STREAM, 0, &local_err);
 
     if (local_err != NULL) {
-        qerror_report_err(local_err);
+        error_report("%s", error_get_pretty(local_err));
         error_free(local_err);
     }
     return fd;
@@ -235,7 +235,7 @@ static int unix_socket_incoming(const char *path)
     int fd = unix_listen(path, NULL, 0, &local_err);
 
     if (local_err != NULL) {
-        qerror_report_err(local_err);
+        error_report("%s", error_get_pretty(local_err));
         error_free(local_err);
     }
     return fd;
@@ -247,7 +247,7 @@ static int unix_socket_outgoing(const char *path)
     int fd = unix_connect(path, &local_err);
 
     if (local_err != NULL) {
-        qerror_report_err(local_err);
+        error_report("%s", error_get_pretty(local_err));
         error_free(local_err);
     }
     return fd;
@@ -294,7 +294,7 @@ static void *nbd_client_thread(void *arg)
     fd = open(device, O_RDWR);
     if (fd < 0) {
         /* Linux-only, we can use %m in printf.  */
-        fprintf(stderr, "Failed to open %s: %m", device);
+        fprintf(stderr, "Failed to open %s: %m\n", device);
         goto out_socket;
     }
 
@@ -369,8 +369,10 @@ static void nbd_accept(void *opaque)
         return;
     }
 
-    if (fd >= 0 && nbd_client_new(exp, fd, nbd_client_closed)) {
+    if (nbd_client_new(exp, fd, nbd_client_closed)) {
         nb_fds++;
+    } else {
+        close(fd);
     }
 }
 
diff --git a/qemu-nbd.texi b/qemu-nbd.texi
index 0a7e01385c..46fd483eb8 100644
--- a/qemu-nbd.texi
+++ b/qemu-nbd.texi
@@ -15,7 +15,7 @@ Export QEMU disk image using NBD protocol.
 @item @var{filename}
  is a disk image filename
 @item -p, --port=@var{port}
-  port to listen on (default @samp{1024})
+  port to listen on (default @samp{10809})
 @item -o, --offset=@var{offset}
   offset into the image
 @item -b, --bind=@var{iface}
diff --git a/qemu-options.hx b/qemu-options.hx
index 781af14bf5..4011d46d62 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -414,6 +414,7 @@ DEF("drive", HAS_ARG, QEMU_OPTION_drive,
     "       [,serial=s][,addr=A][,rerror=ignore|stop|report]\n"
     "       [,werror=ignore|stop|report|enospc][,id=name][,aio=threads|native]\n"
     "       [,readonly=on|off][,copy-on-read=on|off]\n"
+    "       [,detect-zeroes=on|off|unmap]\n"
     "       [[,bps=b]|[[,bps_rd=r][,bps_wr=w]]]\n"
     "       [[,iops=i]|[[,iops_rd=r][,iops_wr=w]]]\n"
     "       [[,bps_max=bm]|[[,bps_rd_max=rm][,bps_wr_max=wm]]]\n"
@@ -475,6 +476,11 @@ Open drive @option{file} as read-only. Guest write attempts will fail.
 @item copy-on-read=@var{copy-on-read}
 @var{copy-on-read} is "on" or "off" and enables whether to copy read backing
 file sectors into the image file.
+@item detect-zeroes=@var{detect-zeroes}
+@var{detect-zeroes} is "off", "on" or "unmap" and enables the automatic
+conversion of plain zero writes by the OS to driver specific optimized
+zero write commands. You may even choose "unmap" if @var{discard} is set
+to "unmap" to allow a zero write to be converted to an UNMAP operation.
 @end table
 
 By default, the @option{cache=writeback} mode is used. It will report data
@@ -2191,6 +2197,74 @@ qemu-system-x86_64 --drive file=gluster://192.0.2.1/testvol/a.img
 @end example
 
 See also @url{http://www.gluster.org}.
+
+@item HTTP/HTTPS/FTP/FTPS/TFTP
+QEMU supports read-only access to files accessed over http(s), ftp(s) and tftp.
+
+Syntax using a single filename:
+@example
+<protocol>://[<username>[:<password>]@@]<host>/<path>
+@end example
+
+where:
+@table @option
+@item protocol
+'http', 'https', 'ftp', 'ftps', or 'tftp'.
+
+@item username
+Optional username for authentication to the remote server.
+
+@item password
+Optional password for authentication to the remote server.
+
+@item host
+Address of the remote server.
+
+@item path
+Path on the remote server, including any query string.
+@end table
+
+The following options are also supported:
+@table @option
+@item url
+The full URL when passing options to the driver explicitly.
+
+@item readahead
+The amount of data to read ahead with each range request to the remote server.
+This value may optionally have the suffix 'T', 'G', 'M', 'K', 'k' or 'b'. If it
+does not have a suffix, it will be assumed to be in bytes. The value must be a
+multiple of 512 bytes. It defaults to 256k.
+
+@item sslverify
+Whether to verify the remote server's certificate when connecting over SSL. It
+can have the value 'on' or 'off'. It defaults to 'on'.
+@end table
+
+Note that when passing options to qemu explicitly, @option{driver} is the value
+of <protocol>.
+
+Example: boot from a remote Fedora 20 live ISO image
+@example
+qemu-system-x86_64 --drive media=cdrom,file=http://dl.fedoraproject.org/pub/fedora/linux/releases/20/Live/x86_64/Fedora-Live-Desktop-x86_64-20-1.iso,readonly
+
+qemu-system-x86_64 --drive media=cdrom,file.driver=http,file.url=http://dl.fedoraproject.org/pub/fedora/linux/releases/20/Live/x86_64/Fedora-Live-Desktop-x86_64-20-1.iso,readonly
+@end example
+
+Example: boot from a remote Fedora 20 cloud image using a local overlay for
+writes, copy-on-read, and a readahead of 64k
+@example
+qemu-img create -f qcow2 -o backing_file='json:@{"file.driver":"http",, "file.url":"https://dl.fedoraproject.org/pub/fedora/linux/releases/20/Images/x86_64/Fedora-x86_64-20-20131211.1-sda.qcow2",, "file.readahead":"64k"@}' /tmp/Fedora-x86_64-20-20131211.1-sda.qcow2
+
+qemu-system-x86_64 -drive file=/tmp/Fedora-x86_64-20-20131211.1-sda.qcow2,copy-on-read=on
+@end example
+
+Example: boot from an image stored on a VMware vSphere server with a self-signed
+certificate using a local overlay for writes and a readahead of 64k
+@example
+qemu-img create -f qcow2 -o backing_file='json:@{"file.driver":"https",, "file.url":"https://user:password@@vsphere.example.com/folder/test/test-flat.vmdk?dcPath=Datacenter&dsName=datastore1",, "file.sslverify":"off",, "file.readahead":"64k"@}' /tmp/test.qcow2
+
+qemu-system-x86_64 -drive file=/tmp/test.qcow2
+@end example
 ETEXI
 
 STEXI
@@ -2997,7 +3071,8 @@ STEXI
 Set OpenBIOS nvram @var{variable} to given @var{value} (PPC, SPARC only).
 ETEXI
 DEF("semihosting", 0, QEMU_OPTION_semihosting,
-    "-semihosting    semihosting mode\n", QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA)
+    "-semihosting    semihosting mode\n",
+    QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | QEMU_ARCH_LM32)
 STEXI
 @item -semihosting
 @findex -semihosting
diff --git a/qmp-commands.hx b/qmp-commands.hx
index cae890ee5d..d8aa4edabe 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -2032,6 +2032,8 @@ Each json-object contain the following:
          - "iops_rd_max":  read I/O operations max (json-int)
          - "iops_wr_max":  write I/O operations max (json-int)
          - "iops_size": I/O size when limiting by iops (json-int)
+         - "detect_zeroes": detect and optimize zero writing (json-string)
+             - Possible values: "off", "on", "unmap"
          - "image": the detail of the image, it is a json-object containing
             the following:
              - "filename": image file name (json-string)
@@ -2108,6 +2110,7 @@ Example:
                "iops_rd_max": 0,
                "iops_wr_max": 0,
                "iops_size": 0,
+               "detect_zeroes": "on",
                "image":{
                   "filename":"disks/test.qcow2",
                   "format":"qcow2",
@@ -2937,7 +2940,7 @@ block migration status.
 The main json-object contains the following:
 
 - "status": migration status (json-string)
-     - Possible values: "active", "completed", "failed", "cancelled"
+     - Possible values: "setup", "active", "completed", "failed", "cancelled"
 - "total-time": total amount of ms since migration started.  If
                 migration has ended, it returns the total migration
                 time (json-int)
diff --git a/qobject/qdict.c b/qobject/qdict.c
index 42ec4c0d2c..ea239f082e 100644
--- a/qobject/qdict.c
+++ b/qobject/qdict.c
@@ -665,3 +665,35 @@ void qdict_array_split(QDict *src, QList **dst)
         qlist_append_obj(*dst, subqobj ?: QOBJECT(subqdict));
     }
 }
+
+/**
+ * qdict_join(): Absorb the src QDict into the dest QDict, that is, move all
+ * elements from src to dest.
+ *
+ * If an element from src has a key already present in dest, it will not be
+ * moved unless overwrite is true.
+ *
+ * If overwrite is true, the conflicting values in dest will be discarded and
+ * replaced by the corresponding values from src.
+ *
+ * Therefore, with overwrite being true, the src QDict will always be empty when
+ * this function returns. If overwrite is false, the src QDict will be empty
+ * iff there were no conflicts.
+ */
+void qdict_join(QDict *dest, QDict *src, bool overwrite)
+{
+    const QDictEntry *entry, *next;
+
+    entry = qdict_first(src);
+    while (entry) {
+        next = qdict_next(src, entry);
+
+        if (overwrite || !qdict_haskey(dest, entry->key)) {
+            qobject_incref(entry->value);
+            qdict_put_obj(dest, entry->key, entry->value);
+            qdict_del(src, entry->key);
+        }
+
+        entry = next;
+    }
+}
diff --git a/qtest.c b/qtest.c
index 2aba20d104..f9695a8ff6 100644
--- a/qtest.c
+++ b/qtest.c
@@ -233,7 +233,8 @@ static void qtest_process_command(CharDriverState *chr, gchar **words)
     g_assert(command);
     if (strcmp(words[0], "irq_intercept_out") == 0
         || strcmp(words[0], "irq_intercept_in") == 0) {
-	DeviceState *dev;
+        DeviceState *dev;
+        NamedGPIOList *ngl;
 
         g_assert(words[1]);
         dev = DEVICE(object_resolve_path(words[1], NULL));
@@ -253,10 +254,18 @@ static void qtest_process_command(CharDriverState *chr, gchar **words)
 	    return;
         }
 
-        if (words[0][14] == 'o') {
-            qemu_irq_intercept_out(&dev->gpio_out, qtest_irq_handler, dev->num_gpio_out);
-        } else {
-            qemu_irq_intercept_in(dev->gpio_in, qtest_irq_handler, dev->num_gpio_in);
+        QLIST_FOREACH(ngl, &dev->gpios, node) {
+            /* We don't support intercept of named GPIOs yet */
+            if (ngl->name) {
+                continue;
+            }
+            if (words[0][14] == 'o') {
+                qemu_irq_intercept_out(&ngl->out, qtest_irq_handler,
+                                       ngl->num_out);
+            } else {
+                qemu_irq_intercept_in(ngl->in, qtest_irq_handler,
+                                      ngl->num_in);
+            }
         }
         irq_intercept_dev = dev;
         qtest_send_prefix(chr);
diff --git a/roms/seabios b/roms/seabios
-Subproject b1d4dc908401719c5de78c25313cf82c7cd1d60
+Subproject e51488c5f8800a52ac5c8da7a31b85cca5cc95d
diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py
index 8d9096f65c..7d93d01ed2 100644
--- a/scripts/qapi-commands.py
+++ b/scripts/qapi-commands.py
@@ -2,16 +2,19 @@
 # QAPI command marshaller generator
 #
 # Copyright IBM, Corp. 2011
+# Copyright (C) 2014 Red Hat, Inc.
 #
 # Authors:
 #  Anthony Liguori <aliguori@us.ibm.com>
 #  Michael Roth    <mdroth@linux.vnet.ibm.com>
+#  Markus Armbruster <armbru@redhat.com>
 #
 # This work is licensed under the terms of the GNU GPL, version 2.
 # See the COPYING file in the top-level directory.
 
 from ordereddict import OrderedDict
 from qapi import *
+import re
 import sys
 import os
 import getopt
@@ -37,6 +40,15 @@ def generate_command_decl(name, args, ret_type):
 ''',
                  ret_type=c_type(ret_type), name=c_fun(name), args=arglist).strip()
 
+def gen_err_check(errvar):
+    if errvar:
+        return mcgen('''
+if (local_err) {
+    goto out;
+}
+''')
+    return ''
+
 def gen_sync_call(name, args, ret_type, indent=0):
     ret = ""
     arglist=""
@@ -49,15 +61,14 @@ def gen_sync_call(name, args, ret_type, indent=0):
         arglist += "%s, " % (c_var(argname))
     push_indent(indent)
     ret = mcgen('''
-%(retval)sqmp_%(name)s(%(args)serrp);
+%(retval)sqmp_%(name)s(%(args)s&local_err);
 
 ''',
                 name=c_fun(name), args=arglist, retval=retval).rstrip()
     if ret_type:
+        ret += "\n" + gen_err_check('local_err')
         ret += "\n" + mcgen(''''
-if (!error_is_set(errp)) {
-    %(marshal_output_call)s
-}
+%(marshal_output_call)s
 ''',
                             marshal_output_call=gen_marshal_output_call(name, ret_type)).rstrip()
     pop_indent(indent)
@@ -67,18 +78,19 @@ if (!error_is_set(errp)) {
 def gen_marshal_output_call(name, ret_type):
     if not ret_type:
         return ""
-    return "qmp_marshal_output_%s(retval, ret, errp);" % c_fun(name)
+    return "qmp_marshal_output_%s(retval, ret, &local_err);" % c_fun(name)
 
-def gen_visitor_input_containers_decl(args):
+def gen_visitor_input_containers_decl(args, obj):
     ret = ""
 
     push_indent()
     if len(args) > 0:
         ret += mcgen('''
-QmpInputVisitor *mi;
+QmpInputVisitor *mi = qmp_input_visitor_new_strict(%(obj)s);
 QapiDeallocVisitor *md;
 Visitor *v;
-''')
+''',
+                     obj=obj)
     pop_indent()
 
     return ret.rstrip()
@@ -99,16 +111,17 @@ bool has_%(argname)s = false;
                          argname=c_var(argname), argtype=c_type(argtype))
         else:
             ret += mcgen('''
-%(argtype)s %(argname)s;
+%(argtype)s %(argname)s = {0};
 ''',
                          argname=c_var(argname), argtype=c_type(argtype))
 
     pop_indent()
     return ret.rstrip()
 
-def gen_visitor_input_block(args, obj, dealloc=False):
+def gen_visitor_input_block(args, dealloc=False):
     ret = ""
-    errparg = 'errp'
+    errparg = '&local_err'
+    errarg = 'local_err'
 
     if len(args) == 0:
         return ret
@@ -117,45 +130,45 @@ def gen_visitor_input_block(args, obj, dealloc=False):
 
     if dealloc:
         errparg = 'NULL'
+        errarg = None;
         ret += mcgen('''
+qmp_input_visitor_cleanup(mi);
 md = qapi_dealloc_visitor_new();
 v = qapi_dealloc_get_visitor(md);
 ''')
     else:
         ret += mcgen('''
-mi = qmp_input_visitor_new_strict(%(obj)s);
 v = qmp_input_get_visitor(mi);
-''',
-                     obj=obj)
+''')
 
     for argname, argtype, optional, structured in parse_args(args):
         if optional:
             ret += mcgen('''
-visit_start_optional(v, &has_%(c_name)s, "%(name)s", %(errp)s);
-if (has_%(c_name)s) {
+visit_optional(v, &has_%(c_name)s, "%(name)s", %(errp)s);
 ''',
                          c_name=c_var(argname), name=argname, errp=errparg)
+            ret += gen_err_check(errarg)
+            ret += mcgen('''
+if (has_%(c_name)s) {
+''',
+                         c_name=c_var(argname))
             push_indent()
         ret += mcgen('''
 %(visitor)s(v, &%(c_name)s, "%(name)s", %(errp)s);
 ''',
                      c_name=c_var(argname), name=argname, argtype=argtype,
                      visitor=type_visitor(argtype), errp=errparg)
+        ret += gen_err_check(errarg)
         if optional:
             pop_indent()
             ret += mcgen('''
 }
-visit_end_optional(v, %(errp)s);
-''', errp=errparg)
+''')
 
     if dealloc:
         ret += mcgen('''
 qapi_dealloc_visitor_cleanup(md);
 ''')
-    else:
-        ret += mcgen('''
-qmp_input_visitor_cleanup(mi);
-''')
     pop_indent()
     return ret.rstrip()
 
@@ -166,16 +179,22 @@ def gen_marshal_output(name, args, ret_type, middle_mode):
     ret = mcgen('''
 static void qmp_marshal_output_%(c_name)s(%(c_ret_type)s ret_in, QObject **ret_out, Error **errp)
 {
-    QapiDeallocVisitor *md = qapi_dealloc_visitor_new();
+    Error *local_err = NULL;
     QmpOutputVisitor *mo = qmp_output_visitor_new();
+    QapiDeallocVisitor *md;
     Visitor *v;
 
     v = qmp_output_get_visitor(mo);
-    %(visitor)s(v, &ret_in, "unused", errp);
-    if (!error_is_set(errp)) {
-        *ret_out = qmp_output_get_qobject(mo);
+    %(visitor)s(v, &ret_in, "unused", &local_err);
+    if (local_err) {
+        goto out;
     }
+    *ret_out = qmp_output_get_qobject(mo);
+
+out:
+    error_propagate(errp, local_err);
     qmp_output_visitor_cleanup(mo);
+    md = qapi_dealloc_visitor_new();
     v = qapi_dealloc_get_visitor(md);
     %(visitor)s(v, &ret_in, "unused", NULL);
     qapi_dealloc_visitor_cleanup(md);
@@ -200,13 +219,12 @@ def gen_marshal_input(name, args, ret_type, middle_mode):
     ret = mcgen('''
 %(header)s
 {
+    Error *local_err = NULL;
 ''',
                 header=hdr)
 
     if middle_mode:
         ret += mcgen('''
-    Error *local_err = NULL;
-    Error **errp = &local_err;
     QDict *args = (QDict *)qdict;
 ''')
 
@@ -228,29 +246,32 @@ def gen_marshal_input(name, args, ret_type, middle_mode):
 %(visitor_input_block)s
 
 ''',
-                     visitor_input_containers_decl=gen_visitor_input_containers_decl(args),
+                     visitor_input_containers_decl=gen_visitor_input_containers_decl(args, "QOBJECT(args)"),
                      visitor_input_vars_decl=gen_visitor_input_vars_decl(args),
-                     visitor_input_block=gen_visitor_input_block(args, "QOBJECT(args)"))
+                     visitor_input_block=gen_visitor_input_block(args))
     else:
         ret += mcgen('''
+
     (void)args;
 ''')
 
     ret += mcgen('''
-    if (error_is_set(errp)) {
-        goto out;
-    }
 %(sync_call)s
 ''',
                  sync_call=gen_sync_call(name, args, ret_type, indent=4))
-    ret += mcgen('''
+    if re.search('^ *goto out\\;', ret, re.MULTILINE):
+        ret += mcgen('''
 
 out:
 ''')
+    if not middle_mode:
+        ret += mcgen('''
+    error_propagate(errp, local_err);
+''')
     ret += mcgen('''
 %(visitor_input_block_cleanup)s
 ''',
-                 visitor_input_block_cleanup=gen_visitor_input_block(args, None,
+                 visitor_input_block_cleanup=gen_visitor_input_block(args,
                                                                      dealloc=True))
 
     if middle_mode:
diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
index c6579beed5..06a79f1631 100644
--- a/scripts/qapi-visit.py
+++ b/scripts/qapi-visit.py
@@ -2,21 +2,47 @@
 # QAPI visitor generator
 #
 # Copyright IBM, Corp. 2011
+# Copyright (C) 2014 Red Hat, Inc.
 #
 # Authors:
 #  Anthony Liguori <aliguori@us.ibm.com>
 #  Michael Roth    <mdroth@linux.vnet.ibm.com>
+#  Markus Armbruster <armbru@redhat.com>
 #
 # This work is licensed under the terms of the GNU GPL, version 2.
 # See the COPYING file in the top-level directory.
 
 from ordereddict import OrderedDict
 from qapi import *
+import re
 import sys
 import os
 import getopt
 import errno
 
+implicit_structs = []
+
+def generate_visit_implicit_struct(type):
+    global implicit_structs
+    if type in implicit_structs:
+        return ''
+    implicit_structs.append(type)
+    return mcgen('''
+
+static void visit_type_implicit_%(c_type)s(Visitor *m, %(c_type)s **obj, Error **errp)
+{
+    Error *err = NULL;
+
+    visit_start_implicit_struct(m, (void **)obj, sizeof(%(c_type)s), &err);
+    if (!err) {
+        visit_type_%(c_type)s_fields(m, obj, errp);
+        visit_end_implicit_struct(m, &err);
+    }
+    error_propagate(errp, err);
+}
+''',
+                 c_type=type_name(type))
+
 def generate_visit_struct_fields(name, field_prefix, fn_prefix, members, base = None):
     substructs = []
     ret = ''
@@ -35,6 +61,19 @@ def generate_visit_struct_fields(name, field_prefix, fn_prefix, members, base =
             nested_field_prefix = "%s%s." % (field_prefix, argname)
             ret += generate_visit_struct_fields(name, nested_field_prefix,
                                                 nested_fn_prefix, argentry)
+            ret += mcgen('''
+
+static void visit_type_%(full_name)s_field_%(c_name)s(Visitor *m, %(name)s **obj, Error **errp)
+{
+''',
+                         name=name, full_name=full_name, c_name=c_var(argname))
+            ret += generate_visit_struct_body(full_name, argname, argentry)
+            ret += mcgen('''
+}
+''')
+
+    if base:
+        ret += generate_visit_implicit_struct(base)
 
     ret += mcgen('''
 
@@ -47,12 +86,9 @@ static void visit_type_%(full_name)s_fields(Visitor *m, %(name)s ** obj, Error *
 
     if base:
         ret += mcgen('''
-visit_start_implicit_struct(m, (void**) &(*obj)->%(c_name)s, sizeof(%(type)s), &err);
-if (!err) {
-    visit_type_%(type)s_fields(m, &(*obj)->%(c_prefix)s%(c_name)s, &err);
-    error_propagate(errp, err);
-    err = NULL;
-    visit_end_implicit_struct(m, &err);
+visit_type_implicit_%(type)s(m, &(*obj)->%(c_prefix)s%(c_name)s, &err);
+if (err) {
+    goto out;
 }
 ''',
                      c_prefix=c_var(field_prefix),
@@ -61,15 +97,18 @@ if (!err) {
     for argname, argentry, optional, structured in parse_args(members):
         if optional:
             ret += mcgen('''
-visit_start_optional(m, &(*obj)->%(c_prefix)shas_%(c_name)s, "%(name)s", &err);
-if ((*obj)->%(prefix)shas_%(c_name)s) {
+visit_optional(m, &(*obj)->%(c_prefix)shas_%(c_name)s, "%(name)s", &err);
+if (!err && (*obj)->%(prefix)shas_%(c_name)s) {
 ''',
                          c_prefix=c_var(field_prefix), prefix=field_prefix,
                          c_name=c_var(argname), name=argname)
             push_indent()
 
         if structured:
-            ret += generate_visit_struct_body(full_name, argname, argentry)
+            ret += mcgen('''
+visit_type_%(full_name)s_field_%(c_name)s(m, obj, &err);
+''',
+                         full_name=full_name, c_name=c_var(argname))
         else:
             ret += mcgen('''
 visit_type_%(type)s(m, &(*obj)->%(c_prefix)s%(c_name)s, "%(name)s", &err);
@@ -82,12 +121,20 @@ visit_type_%(type)s(m, &(*obj)->%(c_prefix)s%(c_name)s, "%(name)s", &err);
             pop_indent()
             ret += mcgen('''
 }
-visit_end_optional(m, &err);
+''')
+        ret += mcgen('''
+if (err) {
+    goto out;
+}
 ''')
 
     pop_indent()
-    ret += mcgen('''
+    if re.search('^ *goto out\\;', ret, re.MULTILINE):
+        ret += mcgen('''
 
+out:
+''')
+    ret += mcgen('''
     error_propagate(errp, err);
 }
 ''')
@@ -96,9 +143,9 @@ visit_end_optional(m, &err);
 
 def generate_visit_struct_body(field_prefix, name, members):
     ret = mcgen('''
-if (!error_is_set(errp)) {
+    Error *err = NULL;
+
 ''')
-    push_indent()
 
     if not field_prefix:
         full_name = name
@@ -107,36 +154,26 @@ if (!error_is_set(errp)) {
 
     if len(field_prefix):
         ret += mcgen('''
-Error **errp = &err; /* from outer scope */
-Error *err = NULL;
-visit_start_struct(m, NULL, "", "%(name)s", 0, &err);
+    visit_start_struct(m, NULL, "", "%(name)s", 0, &err);
 ''',
                 name=name)
     else:
         ret += mcgen('''
-Error *err = NULL;
-visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err);
+    visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err);
 ''',
                 name=name)
 
     ret += mcgen('''
-if (!err) {
-    if (*obj) {
-        visit_type_%(name)s_fields(m, obj, &err);
-        error_propagate(errp, err);
-        err = NULL;
+    if (!err) {
+        if (*obj) {
+            visit_type_%(name)s_fields(m, obj, errp);
+        }
+        visit_end_struct(m, &err);
     }
+    error_propagate(errp, err);
 ''',
         name=full_name)
 
-    pop_indent()
-    ret += mcgen('''
-        /* Always call end_struct if start_struct succeeded.  */
-        visit_end_struct(m, &err);
-    }
-    error_propagate(errp, err);
-}
-''')
     return ret
 
 def generate_visit_struct(expr):
@@ -154,9 +191,7 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **
 ''',
                 name=name)
 
-    push_indent()
     ret += generate_visit_struct_body("", name, members)
-    pop_indent()
 
     ret += mcgen('''
 }
@@ -168,24 +203,26 @@ def generate_visit_list(name, members):
 
 void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp)
 {
-    GenericList *i, **prev = (GenericList **)obj;
     Error *err = NULL;
+    GenericList *i, **prev;
 
-    if (!error_is_set(errp)) {
-        visit_start_list(m, name, &err);
-        if (!err) {
-            for (; (i = visit_next_list(m, prev, &err)) != NULL; prev = &i) {
-                %(name)sList *native_i = (%(name)sList *)i;
-                visit_type_%(name)s(m, &native_i->value, NULL, &err);
-            }
-            error_propagate(errp, err);
-            err = NULL;
-
-            /* Always call end_list if start_list succeeded.  */
-            visit_end_list(m, &err);
-        }
-        error_propagate(errp, err);
+    visit_start_list(m, name, &err);
+    if (err) {
+        goto out;
     }
+
+    for (prev = (GenericList **)obj;
+         !err && (i = visit_next_list(m, prev, &err)) != NULL;
+         prev = &i) {
+        %(name)sList *native_i = (%(name)sList *)i;
+        visit_type_%(name)s(m, &native_i->value, NULL, &err);
+    }
+
+    error_propagate(errp, err);
+    err = NULL;
+    visit_end_list(m, &err);
+out:
+    error_propagate(errp, err);
 }
 ''',
                 name=name)
@@ -207,10 +244,15 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **
 {
     Error *err = NULL;
 
-    if (!error_is_set(errp)) {
-        visit_start_implicit_struct(m, (void**) obj, sizeof(%(name)s), &err);
-        visit_get_next_type(m, (int*) &(*obj)->kind, %(name)s_qtypes, name, &err);
-        switch ((*obj)->kind) {
+    visit_start_implicit_struct(m, (void**) obj, sizeof(%(name)s), &err);
+    if (err) {
+        goto out;
+    }
+    visit_get_next_type(m, (int*) &(*obj)->kind, %(name)s_qtypes, name, &err);
+    if (err) {
+        goto out_end;
+    }
+    switch ((*obj)->kind) {
 ''',
     name=name)
 
@@ -225,22 +267,24 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **
 
         enum_full_value = generate_enum_full_value(disc_type, key)
         ret += mcgen('''
-        case %(enum_full_value)s:
-            visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, name, &err);
-            break;
+    case %(enum_full_value)s:
+        visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, name, &err);
+        break;
 ''',
                 enum_full_value = enum_full_value,
                 c_type = type_name(members[key]),
                 c_name = c_fun(key))
 
     ret += mcgen('''
-        default:
-            abort();
-        }
-        error_propagate(errp, err);
-        err = NULL;
-        visit_end_implicit_struct(m, &err);
+    default:
+        abort();
     }
+out_end:
+    error_propagate(errp, err);
+    err = NULL;
+    visit_end_implicit_struct(m, &err);
+out:
+    error_propagate(errp, err);
 }
 ''')
 
@@ -277,40 +321,43 @@ def generate_visit_union(expr):
             del base_fields[discriminator]
         ret += generate_visit_struct_fields(name, "", "", base_fields)
 
+    if discriminator:
+        for key in members:
+            ret += generate_visit_implicit_struct(members[key])
+
     ret += mcgen('''
 
 void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp)
 {
     Error *err = NULL;
 
-    if (!error_is_set(errp)) {
-        visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err);
-        if (!err) {
-            if (*obj) {
+    visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err);
+    if (err) {
+        goto out;
+    }
+    if (*obj) {
 ''',
                  name=name)
 
-
-    push_indent()
-    push_indent()
-    push_indent()
-
     if base:
         ret += mcgen('''
-    visit_type_%(name)s_fields(m, obj, &err);
+        visit_type_%(name)s_fields(m, obj, &err);
+        if (err) {
+            goto out_obj;
+        }
 ''',
             name=name)
 
-    pop_indent()
-
     if not discriminator:
         disc_key = "type"
     else:
         disc_key = discriminator
     ret += mcgen('''
         visit_type_%(disc_type)s(m, &(*obj)->kind, "%(disc_key)s", &err);
-        if (!err) {
-            switch ((*obj)->kind) {
+        if (err) {
+            goto out_obj;
+        }
+        switch ((*obj)->kind) {
 ''',
                  disc_type = disc_type,
                  disc_key = disc_key)
@@ -319,47 +366,32 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **
         if not discriminator:
             fmt = 'visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, "data", &err);'
         else:
-            fmt = '''visit_start_implicit_struct(m, (void**) &(*obj)->%(c_name)s, sizeof(%(c_type)s), &err);
-                if (!err) {
-                    visit_type_%(c_type)s_fields(m, &(*obj)->%(c_name)s, &err);
-                    error_propagate(errp, err);
-                    err = NULL;
-                    visit_end_implicit_struct(m, &err);
-                }'''
+            fmt = 'visit_type_implicit_%(c_type)s(m, &(*obj)->%(c_name)s, &err);'
 
         enum_full_value = generate_enum_full_value(disc_type, key)
         ret += mcgen('''
-            case %(enum_full_value)s:
-                ''' + fmt + '''
-                break;
+        case %(enum_full_value)s:
+            ''' + fmt + '''
+            break;
 ''',
                 enum_full_value = enum_full_value,
                 c_type=type_name(members[key]),
                 c_name=c_fun(key))
 
     ret += mcgen('''
-            default:
-                abort();
-            }
+        default:
+            abort();
         }
+out_obj:
         error_propagate(errp, err);
         err = NULL;
     }
-''')
-    pop_indent()
-    ret += mcgen('''
-        /* Always call end_struct if start_struct succeeded.  */
-        visit_end_struct(m, &err);
-    }
+    visit_end_struct(m, &err);
+out:
     error_propagate(errp, err);
 }
 ''')
 
-    pop_indent();
-    ret += mcgen('''
-}
-''')
-
     return ret
 
 def generate_declaration(name, members, genlist=True, builtin_type=False):
@@ -476,7 +508,7 @@ fdecl.write(mcgen('''
 /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
 
 /*
- * schema-defined QAPI visitor function
+ * schema-defined QAPI visitor functions
  *
  * Copyright IBM, Corp. 2011
  *
diff --git a/scripts/qapi.py b/scripts/qapi.py
index ec806aabeb..86e96089af 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -73,13 +73,18 @@ class QAPIExprError(Exception):
 
 class QAPISchema:
 
-    def __init__(self, fp, input_relname=None, include_hist=[], parent_info=None):
+    def __init__(self, fp, input_relname=None, include_hist=[],
+                 previously_included=[], parent_info=None):
+        """ include_hist is a stack used to detect inclusion cycles
+            previously_included is a global state used to avoid multiple
+                                inclusions of the same file"""
         input_fname = os.path.abspath(fp.name)
         if input_relname is None:
             input_relname = fp.name
         self.input_dir = os.path.dirname(input_fname)
         self.input_file = input_relname
         self.include_hist = include_hist + [(input_relname, input_fname)]
+        previously_included.append(input_fname)
         self.parent_info = parent_info
         self.src = fp.read()
         if self.src == '' or self.src[-1] != '\n':
@@ -106,13 +111,16 @@ class QAPISchema:
                        for elem in self.include_hist):
                     raise QAPIExprError(expr_info, "Inclusion loop for %s"
                                         % include)
+                # skip multiple include of the same file
+                if include_path in previously_included:
+                    continue
                 try:
                     fobj = open(include_path, 'r')
-                except IOError as e:
+                except IOError, e:
                     raise QAPIExprError(expr_info,
                                         '%s: %s' % (e.strerror, include))
-                exprs_include = QAPISchema(fobj, include,
-                                           self.include_hist, expr_info)
+                exprs_include = QAPISchema(fobj, include, self.include_hist,
+                                           previously_included, expr_info)
                 self.exprs.extend(exprs_include.exprs)
             else:
                 expr_elem = {'expr': expr,
diff --git a/target-alpha/fpu_helper.c b/target-alpha/fpu_helper.c
index ee731555d3..d2d776c446 100644
--- a/target-alpha/fpu_helper.c
+++ b/target-alpha/fpu_helper.c
@@ -18,7 +18,7 @@
  */
 
 #include "cpu.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 #include "fpu/softfloat.h"
 
 #define FP_STATUS (env->fp_status)
diff --git a/target-alpha/helper.c b/target-alpha/helper.c
index cbd03c415b..7c053a3eae 100644
--- a/target-alpha/helper.c
+++ b/target-alpha/helper.c
@@ -23,7 +23,7 @@
 
 #include "cpu.h"
 #include "fpu/softfloat.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 
 uint64_t cpu_alpha_load_fpcr (CPUAlphaState *env)
 {
diff --git a/target-alpha/helper.h b/target-alpha/helper.h
index 2389e96ea3..a451cfeeec 100644
--- a/target-alpha/helper.h
+++ b/target-alpha/helper.h
@@ -1,5 +1,3 @@
-#include "exec/def-helper.h"
-
 DEF_HELPER_3(excp, noreturn, env, int, int)
 DEF_HELPER_FLAGS_1(load_pcc, TCG_CALL_NO_RWG_SE, i64, env)
 
@@ -121,5 +119,3 @@ DEF_HELPER_FLAGS_0(get_vmtime, TCG_CALL_NO_RWG, i64)
 DEF_HELPER_FLAGS_0(get_walltime, TCG_CALL_NO_RWG, i64)
 DEF_HELPER_FLAGS_2(set_alarm, TCG_CALL_NO_RWG, void, env, i64)
 #endif
-
-#include "exec/def-helper.h"
diff --git a/target-alpha/int_helper.c b/target-alpha/int_helper.c
index 51ccd41bd2..7a205eb9fa 100644
--- a/target-alpha/int_helper.c
+++ b/target-alpha/int_helper.c
@@ -18,7 +18,7 @@
  */
 
 #include "cpu.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 #include "qemu/host-utils.h"
 
 
diff --git a/target-alpha/mem_helper.c b/target-alpha/mem_helper.c
index 5964bdcda8..ef6b7058cb 100644
--- a/target-alpha/mem_helper.c
+++ b/target-alpha/mem_helper.c
@@ -18,7 +18,7 @@
  */
 
 #include "cpu.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 
 
 /* Softmmu support */
diff --git a/target-alpha/sys_helper.c b/target-alpha/sys_helper.c
index 187ccf7297..ae2e174f32 100644
--- a/target-alpha/sys_helper.c
+++ b/target-alpha/sys_helper.c
@@ -18,7 +18,7 @@
  */
 
 #include "cpu.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 #include "sysemu/sysemu.h"
 #include "qemu/timer.h"
 
diff --git a/target-alpha/translate.c b/target-alpha/translate.c
index 91c3ed1dd4..e31d56c629 100644
--- a/target-alpha/translate.c
+++ b/target-alpha/translate.c
@@ -22,9 +22,8 @@
 #include "qemu/host-utils.h"
 #include "tcg-op.h"
 
-#include "helper.h"
-#define GEN_HELPER 1
-#include "helper.h"
+#include "exec/helper-proto.h"
+#include "exec/helper-gen.h"
 
 #undef ALPHA_DEBUG_DISAS
 #define CONFIG_SOFTFLOAT_INLINE
diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index 6c6f2b3d46..794dcb9fb7 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -370,8 +370,8 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
 
     init_cpreg_list(cpu);
 
-    cpu_reset(cs);
     qemu_init_vcpu(cs);
+    cpu_reset(cs);
 
     acc->parent_realize(dev, errp);
 }
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index c83f2495a8..8d04385261 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -143,7 +143,7 @@ typedef struct CPUARMState {
     uint32_t spsr;
 
     /* Banked registers.  */
-    uint64_t banked_spsr[6];
+    uint64_t banked_spsr[8];
     uint32_t banked_r13[6];
     uint32_t banked_r14[6];
 
@@ -162,8 +162,8 @@ typedef struct CPUARMState {
     uint32_t condexec_bits; /* IT bits.  cpsr[15:10,26:25].  */
     uint64_t daif; /* exception masks, in the bits they are in in PSTATE */
 
-    uint64_t elr_el1; /* AArch64 ELR_EL1 */
-    uint64_t sp_el[2]; /* AArch64 banked stack pointers */
+    uint64_t elr_el[4]; /* AArch64 exception link regs  */
+    uint64_t sp_el[4]; /* AArch64 banked stack pointers */
 
     /* System control coprocessor (cp15) */
     struct {
@@ -185,7 +185,7 @@ typedef struct CPUARMState {
         uint32_t pmsav5_data_ap; /* PMSAv5 MPU data access permissions */
         uint32_t pmsav5_insn_ap; /* PMSAv5 MPU insn access permissions */
         uint32_t ifsr_el2; /* Fault status registers.  */
-        uint64_t esr_el1;
+        uint64_t esr_el[2];
         uint32_t c6_region[8]; /* MPU base/size registers.  */
         uint64_t far_el1; /* Fault address registers.  */
         uint64_t par_el1;  /* Translation result. */
@@ -198,7 +198,7 @@ typedef struct CPUARMState {
         uint32_t c9_pmuserenr; /* perf monitor user enable */
         uint32_t c9_pminten; /* perf monitor interrupt enables */
         uint64_t mair_el1;
-        uint64_t c12_vbar; /* vector base address register */
+        uint64_t vbar_el[4]; /* vector base address register */
         uint32_t c13_fcse; /* FCSE PID.  */
         uint64_t contextidr_el1; /* Context ID.  */
         uint64_t tpidr_el0; /* User RW Thread register.  */
@@ -563,7 +563,9 @@ enum arm_cpu_mode {
   ARM_CPU_MODE_FIQ = 0x11,
   ARM_CPU_MODE_IRQ = 0x12,
   ARM_CPU_MODE_SVC = 0x13,
+  ARM_CPU_MODE_MON = 0x16,
   ARM_CPU_MODE_ABT = 0x17,
+  ARM_CPU_MODE_HYP = 0x1a,
   ARM_CPU_MODE_UND = 0x1b,
   ARM_CPU_MODE_SYS = 0x1f
 };
@@ -631,6 +633,8 @@ enum arm_features {
     ARM_FEATURE_CBAR, /* has cp15 CBAR */
     ARM_FEATURE_CRC, /* ARMv8 CRC instructions */
     ARM_FEATURE_CBAR_RO, /* has cp15 CBAR and it is read-only */
+    ARM_FEATURE_EL2, /* has EL2 Virtualization support */
+    ARM_FEATURE_EL3, /* has EL3 Secure monitor support */
 };
 
 static inline int arm_feature(CPUARMState *env, int feature)
@@ -1080,12 +1084,12 @@ static inline CPUARMState *cpu_init(const char *cpu_model)
 #define cpu_list arm_cpu_list
 
 /* MMU modes definitions */
-#define MMU_MODE0_SUFFIX _kernel
-#define MMU_MODE1_SUFFIX _user
-#define MMU_USER_IDX 1
+#define MMU_MODE0_SUFFIX _user
+#define MMU_MODE1_SUFFIX _kernel
+#define MMU_USER_IDX 0
 static inline int cpu_mmu_index (CPUARMState *env)
 {
-    return arm_current_pl(env) ? 0 : 1;
+    return arm_current_pl(env);
 }
 
 #include "exec/cpu-all.h"
diff --git a/target-arm/crypto_helper.c b/target-arm/crypto_helper.c
index f94be69ac5..d8898ed805 100644
--- a/target-arm/crypto_helper.c
+++ b/target-arm/crypto_helper.c
@@ -13,7 +13,7 @@
 
 #include "cpu.h"
 #include "exec/exec-all.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 
 union AES_STATE {
     uint8_t    bytes[16];
diff --git a/target-arm/helper-a64.c b/target-arm/helper-a64.c
index bf921ccdc0..cccda74113 100644
--- a/target-arm/helper-a64.c
+++ b/target-arm/helper-a64.c
@@ -19,7 +19,7 @@
 
 #include "cpu.h"
 #include "exec/gdbstub.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 #include "qemu/host-utils.h"
 #include "sysemu/sysemu.h"
 #include "qemu/bitops.h"
@@ -443,7 +443,7 @@ void aarch64_cpu_do_interrupt(CPUState *cs)
 {
     ARMCPU *cpu = ARM_CPU(cs);
     CPUARMState *env = &cpu->env;
-    target_ulong addr = env->cp15.c12_vbar;
+    target_ulong addr = env->cp15.vbar_el[1];
     int i;
 
     if (arm_current_pl(env) == 0) {
@@ -464,7 +464,7 @@ void aarch64_cpu_do_interrupt(CPUState *cs)
                       env->exception.syndrome);
     }
 
-    env->cp15.esr_el1 = env->exception.syndrome;
+    env->cp15.esr_el[1] = env->exception.syndrome;
     env->cp15.far_el1 = env->exception.vaddress;
 
     switch (cs->exception_index) {
@@ -488,16 +488,16 @@ void aarch64_cpu_do_interrupt(CPUState *cs)
     }
 
     if (is_a64(env)) {
-        env->banked_spsr[0] = pstate_read(env);
+        env->banked_spsr[aarch64_banked_spsr_index(1)] = pstate_read(env);
         env->sp_el[arm_current_pl(env)] = env->xregs[31];
         env->xregs[31] = env->sp_el[1];
-        env->elr_el1 = env->pc;
+        env->elr_el[1] = env->pc;
     } else {
         env->banked_spsr[0] = cpsr_read(env);
         if (!env->thumb) {
-            env->cp15.esr_el1 |= 1 << 25;
+            env->cp15.esr_el[1] |= 1 << 25;
         }
-        env->elr_el1 = env->regs[15];
+        env->elr_el[1] = env->regs[15];
 
         for (i = 0; i < 15; i++) {
             env->xregs[i] = env->regs[i];
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 417161e216..ec031f5947 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -1,7 +1,7 @@
 #include "cpu.h"
 #include "internals.h"
 #include "exec/gdbstub.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 #include "qemu/host-utils.h"
 #include "sysemu/arch_init.h"
 #include "sysemu/sysemu.h"
@@ -477,11 +477,35 @@ static const ARMCPRegInfo not_v7_cp_reginfo[] = {
 static void cpacr_write(CPUARMState *env, const ARMCPRegInfo *ri,
                         uint64_t value)
 {
-    if (env->cp15.c1_coproc != value) {
-        env->cp15.c1_coproc = value;
-        /* ??? Is this safe when called from within a TB?  */
-        tb_flush(env);
+    uint32_t mask = 0;
+
+    /* In ARMv8 most bits of CPACR_EL1 are RES0. */
+    if (!arm_feature(env, ARM_FEATURE_V8)) {
+        /* ARMv7 defines bits for unimplemented coprocessors as RAZ/WI.
+         * ASEDIS [31] and D32DIS [30] are both UNK/SBZP without VFP.
+         * TRCDIS [28] is RAZ/WI since we do not implement a trace macrocell.
+         */
+        if (arm_feature(env, ARM_FEATURE_VFP)) {
+            /* VFP coprocessor: cp10 & cp11 [23:20] */
+            mask |= (1 << 31) | (1 << 30) | (0xf << 20);
+
+            if (!arm_feature(env, ARM_FEATURE_NEON)) {
+                /* ASEDIS [31] bit is RAO/WI */
+                value |= (1 << 31);
+            }
+
+            /* VFPv3 and upwards with NEON implement 32 double precision
+             * registers (D0-D31).
+             */
+            if (!arm_feature(env, ARM_FEATURE_NEON) ||
+                    !arm_feature(env, ARM_FEATURE_VFP3)) {
+                /* D32DIS [30] is RAO/WI if D16-31 are not implemented. */
+                value |= (1 << 30);
+            }
+        }
+        value &= mask;
     }
+    env->cp15.c1_coproc = value;
 }
 
 static const ARMCPRegInfo v6_cp_reginfo[] = {
@@ -657,7 +681,7 @@ static void vbar_write(CPUARMState *env, const ARMCPRegInfo *ri,
      * contexts. (ARMv8 would permit us to do no masking at all, but ARMv7
      * requires the bottom five bits to be RAZ/WI because they're UNK/SBZP.)
      */
-    env->cp15.c12_vbar = value & ~0x1FULL;
+    raw_write(env, ri, value & ~0x1FULL);
 }
 
 static uint64_t ccsidr_read(CPUARMState *env, const ARMCPRegInfo *ri)
@@ -766,7 +790,7 @@ static const ARMCPRegInfo v7_cp_reginfo[] = {
     { .name = "VBAR", .state = ARM_CP_STATE_BOTH,
       .opc0 = 3, .crn = 12, .crm = 0, .opc1 = 0, .opc2 = 0,
       .access = PL1_RW, .writefn = vbar_write,
-      .fieldoffset = offsetof(CPUARMState, cp15.c12_vbar),
+      .fieldoffset = offsetof(CPUARMState, cp15.vbar_el[1]),
       .resetvalue = 0 },
     { .name = "SCR", .cp = 15, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 0,
       .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c1_scr),
@@ -1452,7 +1476,7 @@ static void vmsa_ttbr_write(CPUARMState *env, const ARMCPRegInfo *ri,
 static const ARMCPRegInfo vmsa_cp_reginfo[] = {
     { .name = "DFSR", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 0,
       .access = PL1_RW, .type = ARM_CP_NO_MIGRATE,
-      .fieldoffset = offsetoflow32(CPUARMState, cp15.esr_el1),
+      .fieldoffset = offsetoflow32(CPUARMState, cp15.esr_el[1]),
       .resetfn = arm_cp_reset_ignore, },
     { .name = "IFSR", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 1,
       .access = PL1_RW,
@@ -1460,7 +1484,7 @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = {
     { .name = "ESR_EL1", .state = ARM_CP_STATE_AA64,
       .opc0 = 3, .crn = 5, .crm = 2, .opc1 = 0, .opc2 = 0,
       .access = PL1_RW,
-      .fieldoffset = offsetof(CPUARMState, cp15.esr_el1), .resetvalue = 0, },
+      .fieldoffset = offsetof(CPUARMState, cp15.esr_el[1]), .resetvalue = 0, },
     { .name = "TTBR0_EL1", .state = ARM_CP_STATE_BOTH,
       .opc0 = 3, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 0,
       .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.ttbr0_el1),
@@ -1521,7 +1545,7 @@ static void omap_cachemaint_write(CPUARMState *env, const ARMCPRegInfo *ri,
 static const ARMCPRegInfo omap_cp_reginfo[] = {
     { .name = "DFSR", .cp = 15, .crn = 5, .crm = CP_ANY,
       .opc1 = CP_ANY, .opc2 = CP_ANY, .access = PL1_RW, .type = ARM_CP_OVERRIDE,
-      .fieldoffset = offsetoflow32(CPUARMState, cp15.esr_el1),
+      .fieldoffset = offsetoflow32(CPUARMState, cp15.esr_el[1]),
       .resetvalue = 0, },
     { .name = "", .cp = 15, .crn = 15, .crm = 0, .opc1 = 0, .opc2 = 0,
       .access = PL1_RW, .type = ARM_CP_NOP },
@@ -2055,7 +2079,8 @@ static const ARMCPRegInfo v8_cp_reginfo[] = {
     { .name = "ELR_EL1", .state = ARM_CP_STATE_AA64,
       .type = ARM_CP_NO_MIGRATE,
       .opc0 = 3, .opc1 = 0, .crn = 4, .crm = 0, .opc2 = 1,
-      .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, elr_el1) },
+      .access = PL1_RW,
+      .fieldoffset = offsetof(CPUARMState, elr_el[1]) },
     { .name = "SPSR_EL1", .state = ARM_CP_STATE_AA64,
       .type = ARM_CP_NO_MIGRATE,
       .opc0 = 3, .opc1 = 0, .crn = 4, .crm = 0, .opc2 = 0,
@@ -2076,6 +2101,51 @@ static const ARMCPRegInfo v8_cp_reginfo[] = {
     REGINFO_SENTINEL
 };
 
+/* Used to describe the behaviour of EL2 regs when EL2 does not exist.  */
+static const ARMCPRegInfo v8_el3_no_el2_cp_reginfo[] = {
+    { .name = "VBAR_EL2", .state = ARM_CP_STATE_AA64,
+      .opc0 = 3, .opc1 = 4, .crn = 12, .crm = 0, .opc2 = 0,
+      .access = PL2_RW,
+      .readfn = arm_cp_read_zero, .writefn = arm_cp_write_ignore },
+    REGINFO_SENTINEL
+};
+
+static const ARMCPRegInfo v8_el2_cp_reginfo[] = {
+    { .name = "ELR_EL2", .state = ARM_CP_STATE_AA64,
+      .type = ARM_CP_NO_MIGRATE,
+      .opc0 = 3, .opc1 = 4, .crn = 4, .crm = 0, .opc2 = 1,
+      .access = PL2_RW,
+      .fieldoffset = offsetof(CPUARMState, elr_el[2]) },
+    { .name = "SPSR_EL2", .state = ARM_CP_STATE_AA64,
+      .type = ARM_CP_NO_MIGRATE,
+      .opc0 = 3, .opc1 = 4, .crn = 4, .crm = 0, .opc2 = 0,
+      .access = PL2_RW, .fieldoffset = offsetof(CPUARMState, banked_spsr[6]) },
+    { .name = "VBAR_EL2", .state = ARM_CP_STATE_AA64,
+      .opc0 = 3, .opc1 = 4, .crn = 12, .crm = 0, .opc2 = 0,
+      .access = PL2_RW, .writefn = vbar_write,
+      .fieldoffset = offsetof(CPUARMState, cp15.vbar_el[2]),
+      .resetvalue = 0 },
+    REGINFO_SENTINEL
+};
+
+static const ARMCPRegInfo v8_el3_cp_reginfo[] = {
+    { .name = "ELR_EL3", .state = ARM_CP_STATE_AA64,
+      .type = ARM_CP_NO_MIGRATE,
+      .opc0 = 3, .opc1 = 6, .crn = 4, .crm = 0, .opc2 = 1,
+      .access = PL3_RW,
+      .fieldoffset = offsetof(CPUARMState, elr_el[3]) },
+    { .name = "SPSR_EL3", .state = ARM_CP_STATE_AA64,
+      .type = ARM_CP_NO_MIGRATE,
+      .opc0 = 3, .opc1 = 6, .crn = 4, .crm = 0, .opc2 = 0,
+      .access = PL3_RW, .fieldoffset = offsetof(CPUARMState, banked_spsr[7]) },
+    { .name = "VBAR_EL3", .state = ARM_CP_STATE_AA64,
+      .opc0 = 3, .opc1 = 6, .crn = 12, .crm = 0, .opc2 = 0,
+      .access = PL3_RW, .writefn = vbar_write,
+      .fieldoffset = offsetof(CPUARMState, cp15.vbar_el[3]),
+      .resetvalue = 0 },
+    REGINFO_SENTINEL
+};
+
 static void sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri,
                         uint64_t value)
 {
@@ -2327,6 +2397,19 @@ void register_cp_regs_for_features(ARMCPU *cpu)
         define_arm_cp_regs(cpu, v8_cp_reginfo);
         define_aarch64_debug_regs(cpu);
     }
+    if (arm_feature(env, ARM_FEATURE_EL2)) {
+        define_arm_cp_regs(cpu, v8_el2_cp_reginfo);
+    } else {
+        /* If EL2 is missing but higher ELs are enabled, we need to
+         * register the no_el2 reginfos.
+         */
+        if (arm_feature(env, ARM_FEATURE_EL3)) {
+            define_arm_cp_regs(cpu, v8_el3_no_el2_cp_reginfo);
+        }
+    }
+    if (arm_feature(env, ARM_FEATURE_EL3)) {
+        define_arm_cp_regs(cpu, v8_el3_cp_reginfo);
+    }
     if (arm_feature(env, ARM_FEATURE_MPU)) {
         /* These are the MPU registers prior to PMSAv6. Any new
          * PMSA core later than the ARM946 will require that we
@@ -3083,6 +3166,10 @@ int bank_number(int mode)
         return 4;
     case ARM_CPU_MODE_FIQ:
         return 5;
+    case ARM_CPU_MODE_HYP:
+        return 6;
+    case ARM_CPU_MODE_MON:
+        return 7;
     }
     hw_error("bank number requested for bad CPSR mode value 0x%x\n", mode);
 }
@@ -3337,11 +3424,11 @@ void arm_cpu_do_interrupt(CPUState *cs)
         offset = 4;
         break;
     case EXCP_DATA_ABORT:
-        env->cp15.esr_el1 = env->exception.fsr;
+        env->cp15.esr_el[1] = env->exception.fsr;
         env->cp15.far_el1 = deposit64(env->cp15.far_el1, 0, 32,
                                       env->exception.vaddress);
         qemu_log_mask(CPU_LOG_INT, "...with DFSR 0x%x DFAR 0x%x\n",
-                      (uint32_t)env->cp15.esr_el1,
+                      (uint32_t)env->cp15.esr_el[1],
                       (uint32_t)env->exception.vaddress);
         new_mode = ARM_CPU_MODE_ABT;
         addr = 0x10;
@@ -3378,7 +3465,7 @@ void arm_cpu_do_interrupt(CPUState *cs)
          * and is never in monitor mode this feature is always active.
          * Note: only bits 31:5 are valid.
          */
-        addr += env->cp15.c12_vbar;
+        addr += env->cp15.vbar_el[1];
     }
     switch_mode (env, new_mode);
     env->spsr = cpsr_read(env);
diff --git a/target-arm/helper.h b/target-arm/helper.h
index a5449e7b6f..b63fd0ff1c 100644
--- a/target-arm/helper.h
+++ b/target-arm/helper.h
@@ -1,5 +1,3 @@
-#include "exec/def-helper.h"
-
 DEF_HELPER_FLAGS_1(clz, TCG_CALL_NO_RWG_SE, i32, i32)
 DEF_HELPER_FLAGS_1(sxtb16, TCG_CALL_NO_RWG_SE, i32, i32)
 DEF_HELPER_FLAGS_1(uxtb16, TCG_CALL_NO_RWG_SE, i32, i32)
@@ -521,5 +519,3 @@ DEF_HELPER_2(dc_zva, void, env, i64)
 #ifdef TARGET_AARCH64
 #include "helper-a64.h"
 #endif
-
-#include "exec/def-helper.h"
diff --git a/target-arm/internals.h b/target-arm/internals.h
index d63a975a7e..564b5fa602 100644
--- a/target-arm/internals.h
+++ b/target-arm/internals.h
@@ -75,6 +75,20 @@ static inline void arm_log_exception(int idx)
  */
 #define GTIMER_SCALE 16
 
+/*
+ * For AArch64, map a given EL to an index in the banked_spsr array.
+ */
+static inline unsigned int aarch64_banked_spsr_index(unsigned int el)
+{
+    static const unsigned int map[4] = {
+        [1] = 0, /* EL1.  */
+        [2] = 6, /* EL2.  */
+        [3] = 7, /* EL3.  */
+    };
+    assert(el >= 1 && el <= 3);
+    return map[el];
+}
+
 int bank_number(int mode);
 void switch_mode(CPUARMState *, int);
 void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu);
@@ -93,6 +107,7 @@ int arm_rmode_to_sf(int rmode);
 
 static inline void update_spsel(CPUARMState *env, uint32_t imm)
 {
+    unsigned int cur_el = arm_current_pl(env);
     /* Update PSTATE SPSel bit; this requires us to update the
      * working stack pointer in xregs[31].
      */
@@ -101,17 +116,17 @@ static inline void update_spsel(CPUARMState *env, uint32_t imm)
     }
     env->pstate = deposit32(env->pstate, 0, 1, imm);
 
-    /* EL0 has no access rights to update SPSel, and this code
-     * assumes we are updating SP for EL1 while running as EL1.
+    /* We rely on illegal updates to SPsel from EL0 to get trapped
+     * at translation time.
      */
-    assert(arm_current_pl(env) == 1);
+    assert(cur_el >= 1 && cur_el <= 3);
     if (env->pstate & PSTATE_SP) {
         /* Switch from using SP_EL0 to using SP_ELx */
         env->sp_el[0] = env->xregs[31];
-        env->xregs[31] = env->sp_el[1];
+        env->xregs[31] = env->sp_el[cur_el];
     } else {
         /* Switch from SP_EL0 to SP_ELx */
-        env->sp_el[1] = env->xregs[31];
+        env->sp_el[cur_el] = env->xregs[31];
         env->xregs[31] = env->sp_el[0];
     }
 }
diff --git a/target-arm/iwmmxt_helper.c b/target-arm/iwmmxt_helper.c
index e6cfa62da8..398cbcbec7 100644
--- a/target-arm/iwmmxt_helper.c
+++ b/target-arm/iwmmxt_helper.c
@@ -24,7 +24,7 @@
 
 #include "cpu.h"
 #include "exec/exec-all.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 
 /* iwMMXt macros extracted from GNU gdb.  */
 
diff --git a/target-arm/kvm64.c b/target-arm/kvm64.c
index c729b9ec9f..70f311bed6 100644
--- a/target-arm/kvm64.c
+++ b/target-arm/kvm64.c
@@ -161,7 +161,7 @@ int kvm_arch_put_registers(CPUState *cs, int level)
     }
 
     reg.id = AARCH64_CORE_REG(elr_el1);
-    reg.addr = (uintptr_t) &env->elr_el1;
+    reg.addr = (uintptr_t) &env->elr_el[1];
     ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
     if (ret) {
         return ret;
@@ -241,7 +241,7 @@ int kvm_arch_get_registers(CPUState *cs)
     }
 
     reg.id = AARCH64_CORE_REG(elr_el1);
-    reg.addr = (uintptr_t) &env->elr_el1;
+    reg.addr = (uintptr_t) &env->elr_el[1];
     ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
     if (ret) {
         return ret;
diff --git a/target-arm/machine.c b/target-arm/machine.c
index 5092dcda79..3bcc7cc833 100644
--- a/target-arm/machine.c
+++ b/target-arm/machine.c
@@ -218,8 +218,8 @@ static int cpu_post_load(void *opaque, int version_id)
 
 const VMStateDescription vmstate_arm_cpu = {
     .name = "cpu",
-    .version_id = 17,
-    .minimum_version_id = 17,
+    .version_id = 20,
+    .minimum_version_id = 20,
     .pre_save = cpu_pre_save,
     .post_load = cpu_post_load,
     .fields = (VMStateField[]) {
@@ -233,13 +233,13 @@ const VMStateDescription vmstate_arm_cpu = {
             .offset = 0,
         },
         VMSTATE_UINT32(env.spsr, ARMCPU),
-        VMSTATE_UINT64_ARRAY(env.banked_spsr, ARMCPU, 6),
+        VMSTATE_UINT64_ARRAY(env.banked_spsr, ARMCPU, 8),
         VMSTATE_UINT32_ARRAY(env.banked_r13, ARMCPU, 6),
         VMSTATE_UINT32_ARRAY(env.banked_r14, ARMCPU, 6),
         VMSTATE_UINT32_ARRAY(env.usr_regs, ARMCPU, 5),
         VMSTATE_UINT32_ARRAY(env.fiq_regs, ARMCPU, 5),
-        VMSTATE_UINT64(env.elr_el1, ARMCPU),
-        VMSTATE_UINT64_ARRAY(env.sp_el, ARMCPU, 2),
+        VMSTATE_UINT64_ARRAY(env.elr_el, ARMCPU, 4),
+        VMSTATE_UINT64_ARRAY(env.sp_el, ARMCPU, 4),
         /* The length-check must come before the arrays to avoid
          * incoming data possibly overflowing the array.
          */
diff --git a/target-arm/neon_helper.c b/target-arm/neon_helper.c
index 8d6f9a92f2..492e500700 100644
--- a/target-arm/neon_helper.c
+++ b/target-arm/neon_helper.c
@@ -11,7 +11,7 @@
 
 #include "cpu.h"
 #include "exec/exec-all.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 
 #define SIGNBIT (uint32_t)0x80000000
 #define SIGNBIT64 ((uint64_t)1 << 63)
diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
index fb90676bd5..b28f694d00 100644
--- a/target-arm/op_helper.c
+++ b/target-arm/op_helper.c
@@ -17,7 +17,7 @@
  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  */
 #include "cpu.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 #include "internals.h"
 
 #define SIGNBIT (uint32_t)0x80000000
@@ -386,11 +386,13 @@ void HELPER(msr_i_pstate)(CPUARMState *env, uint32_t op, uint32_t imm)
 
 void HELPER(exception_return)(CPUARMState *env)
 {
-    uint32_t spsr = env->banked_spsr[0];
+    int cur_el = arm_current_pl(env);
+    unsigned int spsr_idx = aarch64_banked_spsr_index(cur_el);
+    uint32_t spsr = env->banked_spsr[spsr_idx];
     int new_el, i;
 
     if (env->pstate & PSTATE_SP) {
-        env->sp_el[1] = env->xregs[31];
+        env->sp_el[cur_el] = env->xregs[31];
     } else {
         env->sp_el[0] = env->xregs[31];
     }
@@ -398,6 +400,7 @@ void HELPER(exception_return)(CPUARMState *env)
     env->exclusive_addr = -1;
 
     if (spsr & PSTATE_nRW) {
+        /* TODO: We currently assume EL1/2/3 are running in AArch64.  */
         env->aarch64 = 0;
         new_el = 0;
         env->uncached_cpsr = 0x10;
@@ -406,11 +409,14 @@ void HELPER(exception_return)(CPUARMState *env)
             env->regs[i] = env->xregs[i];
         }
 
-        env->regs[15] = env->elr_el1 & ~0x1;
+        env->regs[15] = env->elr_el[1] & ~0x1;
     } else {
         new_el = extract32(spsr, 2, 2);
-        if (new_el > 1) {
-            /* Return to unimplemented EL */
+        if (new_el > cur_el
+            || (new_el == 2 && !arm_feature(env, ARM_FEATURE_EL2))) {
+            /* Disallow return to an EL which is unimplemented or higher
+             * than the current one.
+             */
             goto illegal_return;
         }
         if (extract32(spsr, 1, 1)) {
@@ -424,7 +430,7 @@ void HELPER(exception_return)(CPUARMState *env)
         env->aarch64 = 1;
         pstate_write(env, spsr);
         env->xregs[31] = env->sp_el[new_el];
-        env->pc = env->elr_el1;
+        env->pc = env->elr_el[cur_el];
     }
 
     return;
@@ -438,7 +444,7 @@ illegal_return:
      * no change to exception level, execution state or stack pointer
      */
     env->pstate |= PSTATE_IL;
-    env->pc = env->elr_el1;
+    env->pc = env->elr_el[cur_el];
     spsr &= PSTATE_NZCV | PSTATE_DAIF;
     spsr |= pstate_read(env) & ~(PSTATE_NZCV | PSTATE_DAIF);
     pstate_write(env, spsr);
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index b62db4d566..9f964dfd5d 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -31,9 +31,8 @@
 
 #include "exec/gen-icount.h"
 
-#include "helper.h"
-#define GEN_HELPER 1
-#include "helper.h"
+#include "exec/helper-proto.h"
+#include "exec/helper-gen.h"
 
 static TCGv_i64 cpu_X[32];
 static TCGv_i64 cpu_pc;
@@ -162,15 +161,6 @@ void aarch64_cpu_dump_state(CPUState *cs, FILE *f,
     }
 }
 
-static int get_mem_index(DisasContext *s)
-{
-#ifdef CONFIG_USER_ONLY
-    return 1;
-#else
-    return s->user;
-#endif
-}
-
 void gen_a64_set_pc_im(uint64_t val)
 {
     tcg_gen_movi_i64(cpu_pc, val);
@@ -1516,6 +1506,10 @@ static void disas_uncond_b_reg(DisasContext *s, uint32_t insn)
         tcg_gen_movi_i64(cpu_reg(s, 30), s->pc);
         break;
     case 4: /* ERET */
+        if (s->current_pl == 0) {
+            unallocated_encoding(s);
+            return;
+        }
         gen_helper_exception_return(cpu_env);
         s->is_jmp = DISAS_JUMP;
         return;
diff --git a/target-arm/translate.c b/target-arm/translate.c
index a4d920b629..7f6fcd699e 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -31,9 +31,8 @@
 #include "qemu/log.h"
 #include "qemu/bitops.h"
 
-#include "helper.h"
-#define GEN_HELPER 1
-#include "helper.h"
+#include "exec/helper-proto.h"
+#include "exec/helper-gen.h"
 
 #define ENABLE_ARCH_4T    arm_feature(env, ARM_FEATURE_V4T)
 #define ENABLE_ARCH_5     arm_feature(env, ARM_FEATURE_V5)
@@ -1165,18 +1164,18 @@ VFP_GEN_FIX(ulto, )
 static inline void gen_vfp_ld(DisasContext *s, int dp, TCGv_i32 addr)
 {
     if (dp) {
-        gen_aa32_ld64(cpu_F0d, addr, IS_USER(s));
+        gen_aa32_ld64(cpu_F0d, addr, get_mem_index(s));
     } else {
-        gen_aa32_ld32u(cpu_F0s, addr, IS_USER(s));
+        gen_aa32_ld32u(cpu_F0s, addr, get_mem_index(s));
     }
 }
 
 static inline void gen_vfp_st(DisasContext *s, int dp, TCGv_i32 addr)
 {
     if (dp) {
-        gen_aa32_st64(cpu_F0d, addr, IS_USER(s));
+        gen_aa32_st64(cpu_F0d, addr, get_mem_index(s));
     } else {
-        gen_aa32_st32(cpu_F0s, addr, IS_USER(s));
+        gen_aa32_st32(cpu_F0s, addr, get_mem_index(s));
     }
 }
 
@@ -1514,24 +1513,24 @@ static int disas_iwmmxt_insn(CPUARMState *env, DisasContext *s, uint32_t insn)
         if (insn & ARM_CP_RW_BIT) {
             if ((insn >> 28) == 0xf) {			/* WLDRW wCx */
                 tmp = tcg_temp_new_i32();
-                gen_aa32_ld32u(tmp, addr, IS_USER(s));
+                gen_aa32_ld32u(tmp, addr, get_mem_index(s));
                 iwmmxt_store_creg(wrd, tmp);
             } else {
                 i = 1;
                 if (insn & (1 << 8)) {
                     if (insn & (1 << 22)) {		/* WLDRD */
-                        gen_aa32_ld64(cpu_M0, addr, IS_USER(s));
+                        gen_aa32_ld64(cpu_M0, addr, get_mem_index(s));
                         i = 0;
                     } else {				/* WLDRW wRd */
                         tmp = tcg_temp_new_i32();
-                        gen_aa32_ld32u(tmp, addr, IS_USER(s));
+                        gen_aa32_ld32u(tmp, addr, get_mem_index(s));
                     }
                 } else {
                     tmp = tcg_temp_new_i32();
                     if (insn & (1 << 22)) {		/* WLDRH */
-                        gen_aa32_ld16u(tmp, addr, IS_USER(s));
+                        gen_aa32_ld16u(tmp, addr, get_mem_index(s));
                     } else {				/* WLDRB */
-                        gen_aa32_ld8u(tmp, addr, IS_USER(s));
+                        gen_aa32_ld8u(tmp, addr, get_mem_index(s));
                     }
                 }
                 if (i) {
@@ -1543,24 +1542,24 @@ static int disas_iwmmxt_insn(CPUARMState *env, DisasContext *s, uint32_t insn)
         } else {
             if ((insn >> 28) == 0xf) {			/* WSTRW wCx */
                 tmp = iwmmxt_load_creg(wrd);
-                gen_aa32_st32(tmp, addr, IS_USER(s));
+                gen_aa32_st32(tmp, addr, get_mem_index(s));
             } else {
                 gen_op_iwmmxt_movq_M0_wRn(wrd);
                 tmp = tcg_temp_new_i32();
                 if (insn & (1 << 8)) {
                     if (insn & (1 << 22)) {		/* WSTRD */
-                        gen_aa32_st64(cpu_M0, addr, IS_USER(s));
+                        gen_aa32_st64(cpu_M0, addr, get_mem_index(s));
                     } else {				/* WSTRW wRd */
                         tcg_gen_trunc_i64_i32(tmp, cpu_M0);
-                        gen_aa32_st32(tmp, addr, IS_USER(s));
+                        gen_aa32_st32(tmp, addr, get_mem_index(s));
                     }
                 } else {
                     if (insn & (1 << 22)) {		/* WSTRH */
                         tcg_gen_trunc_i64_i32(tmp, cpu_M0);
-                        gen_aa32_st16(tmp, addr, IS_USER(s));
+                        gen_aa32_st16(tmp, addr, get_mem_index(s));
                     } else {				/* WSTRB */
                         tcg_gen_trunc_i64_i32(tmp, cpu_M0);
-                        gen_aa32_st8(tmp, addr, IS_USER(s));
+                        gen_aa32_st8(tmp, addr, get_mem_index(s));
                     }
                 }
             }
@@ -2625,15 +2624,15 @@ static TCGv_i32 gen_load_and_replicate(DisasContext *s, TCGv_i32 addr, int size)
     TCGv_i32 tmp = tcg_temp_new_i32();
     switch (size) {
     case 0:
-        gen_aa32_ld8u(tmp, addr, IS_USER(s));
+        gen_aa32_ld8u(tmp, addr, get_mem_index(s));
         gen_neon_dup_u8(tmp, 0);
         break;
     case 1:
-        gen_aa32_ld16u(tmp, addr, IS_USER(s));
+        gen_aa32_ld16u(tmp, addr, get_mem_index(s));
         gen_neon_dup_low16(tmp);
         break;
     case 2:
-        gen_aa32_ld32u(tmp, addr, IS_USER(s));
+        gen_aa32_ld32u(tmp, addr, get_mem_index(s));
         break;
     default: /* Avoid compiler warnings.  */
         abort();
@@ -4304,11 +4303,11 @@ static int disas_neon_ls_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
             if (size == 3) {
                 tmp64 = tcg_temp_new_i64();
                 if (load) {
-                    gen_aa32_ld64(tmp64, addr, IS_USER(s));
+                    gen_aa32_ld64(tmp64, addr, get_mem_index(s));
                     neon_store_reg64(tmp64, rd);
                 } else {
                     neon_load_reg64(tmp64, rd);
-                    gen_aa32_st64(tmp64, addr, IS_USER(s));
+                    gen_aa32_st64(tmp64, addr, get_mem_index(s));
                 }
                 tcg_temp_free_i64(tmp64);
                 tcg_gen_addi_i32(addr, addr, stride);
@@ -4317,21 +4316,21 @@ static int disas_neon_ls_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
                     if (size == 2) {
                         if (load) {
                             tmp = tcg_temp_new_i32();
-                            gen_aa32_ld32u(tmp, addr, IS_USER(s));
+                            gen_aa32_ld32u(tmp, addr, get_mem_index(s));
                             neon_store_reg(rd, pass, tmp);
                         } else {
                             tmp = neon_load_reg(rd, pass);
-                            gen_aa32_st32(tmp, addr, IS_USER(s));
+                            gen_aa32_st32(tmp, addr, get_mem_index(s));
                             tcg_temp_free_i32(tmp);
                         }
                         tcg_gen_addi_i32(addr, addr, stride);
                     } else if (size == 1) {
                         if (load) {
                             tmp = tcg_temp_new_i32();
-                            gen_aa32_ld16u(tmp, addr, IS_USER(s));
+                            gen_aa32_ld16u(tmp, addr, get_mem_index(s));
                             tcg_gen_addi_i32(addr, addr, stride);
                             tmp2 = tcg_temp_new_i32();
-                            gen_aa32_ld16u(tmp2, addr, IS_USER(s));
+                            gen_aa32_ld16u(tmp2, addr, get_mem_index(s));
                             tcg_gen_addi_i32(addr, addr, stride);
                             tcg_gen_shli_i32(tmp2, tmp2, 16);
                             tcg_gen_or_i32(tmp, tmp, tmp2);
@@ -4341,10 +4340,10 @@ static int disas_neon_ls_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
                             tmp = neon_load_reg(rd, pass);
                             tmp2 = tcg_temp_new_i32();
                             tcg_gen_shri_i32(tmp2, tmp, 16);
-                            gen_aa32_st16(tmp, addr, IS_USER(s));
+                            gen_aa32_st16(tmp, addr, get_mem_index(s));
                             tcg_temp_free_i32(tmp);
                             tcg_gen_addi_i32(addr, addr, stride);
-                            gen_aa32_st16(tmp2, addr, IS_USER(s));
+                            gen_aa32_st16(tmp2, addr, get_mem_index(s));
                             tcg_temp_free_i32(tmp2);
                             tcg_gen_addi_i32(addr, addr, stride);
                         }
@@ -4353,7 +4352,7 @@ static int disas_neon_ls_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
                             TCGV_UNUSED_I32(tmp2);
                             for (n = 0; n < 4; n++) {
                                 tmp = tcg_temp_new_i32();
-                                gen_aa32_ld8u(tmp, addr, IS_USER(s));
+                                gen_aa32_ld8u(tmp, addr, get_mem_index(s));
                                 tcg_gen_addi_i32(addr, addr, stride);
                                 if (n == 0) {
                                     tmp2 = tmp;
@@ -4373,7 +4372,7 @@ static int disas_neon_ls_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
                                 } else {
                                     tcg_gen_shri_i32(tmp, tmp2, n * 8);
                                 }
-                                gen_aa32_st8(tmp, addr, IS_USER(s));
+                                gen_aa32_st8(tmp, addr, get_mem_index(s));
                                 tcg_temp_free_i32(tmp);
                                 tcg_gen_addi_i32(addr, addr, stride);
                             }
@@ -4497,13 +4496,13 @@ static int disas_neon_ls_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
                     tmp = tcg_temp_new_i32();
                     switch (size) {
                     case 0:
-                        gen_aa32_ld8u(tmp, addr, IS_USER(s));
+                        gen_aa32_ld8u(tmp, addr, get_mem_index(s));
                         break;
                     case 1:
-                        gen_aa32_ld16u(tmp, addr, IS_USER(s));
+                        gen_aa32_ld16u(tmp, addr, get_mem_index(s));
                         break;
                     case 2:
-                        gen_aa32_ld32u(tmp, addr, IS_USER(s));
+                        gen_aa32_ld32u(tmp, addr, get_mem_index(s));
                         break;
                     default: /* Avoid compiler warnings.  */
                         abort();
@@ -4521,13 +4520,13 @@ static int disas_neon_ls_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
                         tcg_gen_shri_i32(tmp, tmp, shift);
                     switch (size) {
                     case 0:
-                        gen_aa32_st8(tmp, addr, IS_USER(s));
+                        gen_aa32_st8(tmp, addr, get_mem_index(s));
                         break;
                     case 1:
-                        gen_aa32_st16(tmp, addr, IS_USER(s));
+                        gen_aa32_st16(tmp, addr, get_mem_index(s));
                         break;
                     case 2:
-                        gen_aa32_st32(tmp, addr, IS_USER(s));
+                        gen_aa32_st32(tmp, addr, get_mem_index(s));
                         break;
                     }
                     tcg_temp_free_i32(tmp);
@@ -7173,14 +7172,14 @@ static void gen_load_exclusive(DisasContext *s, int rt, int rt2,
 
     switch (size) {
     case 0:
-        gen_aa32_ld8u(tmp, addr, IS_USER(s));
+        gen_aa32_ld8u(tmp, addr, get_mem_index(s));
         break;
     case 1:
-        gen_aa32_ld16u(tmp, addr, IS_USER(s));
+        gen_aa32_ld16u(tmp, addr, get_mem_index(s));
         break;
     case 2:
     case 3:
-        gen_aa32_ld32u(tmp, addr, IS_USER(s));
+        gen_aa32_ld32u(tmp, addr, get_mem_index(s));
         break;
     default:
         abort();
@@ -7191,7 +7190,7 @@ static void gen_load_exclusive(DisasContext *s, int rt, int rt2,
         TCGv_i32 tmp3 = tcg_temp_new_i32();
 
         tcg_gen_addi_i32(tmp2, addr, 4);
-        gen_aa32_ld32u(tmp3, tmp2, IS_USER(s));
+        gen_aa32_ld32u(tmp3, tmp2, get_mem_index(s));
         tcg_temp_free_i32(tmp2);
         tcg_gen_concat_i32_i64(cpu_exclusive_val, tmp, tmp3);
         store_reg(s, rt2, tmp3);
@@ -7242,14 +7241,14 @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
     tmp = tcg_temp_new_i32();
     switch (size) {
     case 0:
-        gen_aa32_ld8u(tmp, addr, IS_USER(s));
+        gen_aa32_ld8u(tmp, addr, get_mem_index(s));
         break;
     case 1:
-        gen_aa32_ld16u(tmp, addr, IS_USER(s));
+        gen_aa32_ld16u(tmp, addr, get_mem_index(s));
         break;
     case 2:
     case 3:
-        gen_aa32_ld32u(tmp, addr, IS_USER(s));
+        gen_aa32_ld32u(tmp, addr, get_mem_index(s));
         break;
     default:
         abort();
@@ -7260,7 +7259,7 @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
         TCGv_i32 tmp2 = tcg_temp_new_i32();
         TCGv_i32 tmp3 = tcg_temp_new_i32();
         tcg_gen_addi_i32(tmp2, addr, 4);
-        gen_aa32_ld32u(tmp3, tmp2, IS_USER(s));
+        gen_aa32_ld32u(tmp3, tmp2, get_mem_index(s));
         tcg_temp_free_i32(tmp2);
         tcg_gen_concat_i32_i64(val64, tmp, tmp3);
         tcg_temp_free_i32(tmp3);
@@ -7275,14 +7274,14 @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
     tmp = load_reg(s, rt);
     switch (size) {
     case 0:
-        gen_aa32_st8(tmp, addr, IS_USER(s));
+        gen_aa32_st8(tmp, addr, get_mem_index(s));
         break;
     case 1:
-        gen_aa32_st16(tmp, addr, IS_USER(s));
+        gen_aa32_st16(tmp, addr, get_mem_index(s));
         break;
     case 2:
     case 3:
-        gen_aa32_st32(tmp, addr, IS_USER(s));
+        gen_aa32_st32(tmp, addr, get_mem_index(s));
         break;
     default:
         abort();
@@ -7291,7 +7290,7 @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
     if (size == 3) {
         tcg_gen_addi_i32(addr, addr, 4);
         tmp = load_reg(s, rt2);
-        gen_aa32_st32(tmp, addr, IS_USER(s));
+        gen_aa32_st32(tmp, addr, get_mem_index(s));
         tcg_temp_free_i32(tmp);
     }
     tcg_gen_movi_i32(cpu_R[rd], 0);
@@ -7338,11 +7337,11 @@ static void gen_srs(DisasContext *s,
     }
     tcg_gen_addi_i32(addr, addr, offset);
     tmp = load_reg(s, 14);
-    gen_aa32_st32(tmp, addr, 0);
+    gen_aa32_st32(tmp, addr, get_mem_index(s));
     tcg_temp_free_i32(tmp);
     tmp = load_cpu_field(spsr);
     tcg_gen_addi_i32(addr, addr, 4);
-    gen_aa32_st32(tmp, addr, 0);
+    gen_aa32_st32(tmp, addr, get_mem_index(s));
     tcg_temp_free_i32(tmp);
     if (writeback) {
         switch (amode) {
@@ -7495,10 +7494,10 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s)
                 tcg_gen_addi_i32(addr, addr, offset);
             /* Load PC into tmp and CPSR into tmp2.  */
             tmp = tcg_temp_new_i32();
-            gen_aa32_ld32u(tmp, addr, 0);
+            gen_aa32_ld32u(tmp, addr, get_mem_index(s));
             tcg_gen_addi_i32(addr, addr, 4);
             tmp2 = tcg_temp_new_i32();
-            gen_aa32_ld32u(tmp2, addr, 0);
+            gen_aa32_ld32u(tmp2, addr, get_mem_index(s));
             if (insn & (1 << 21)) {
                 /* Base writeback.  */
                 switch (i) {
@@ -8087,13 +8086,13 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s)
                                 tmp = tcg_temp_new_i32();
                                 switch (op1) {
                                 case 0: /* lda */
-                                    gen_aa32_ld32u(tmp, addr, IS_USER(s));
+                                    gen_aa32_ld32u(tmp, addr, get_mem_index(s));
                                     break;
                                 case 2: /* ldab */
-                                    gen_aa32_ld8u(tmp, addr, IS_USER(s));
+                                    gen_aa32_ld8u(tmp, addr, get_mem_index(s));
                                     break;
                                 case 3: /* ldah */
-                                    gen_aa32_ld16u(tmp, addr, IS_USER(s));
+                                    gen_aa32_ld16u(tmp, addr, get_mem_index(s));
                                     break;
                                 default:
                                     abort();
@@ -8104,13 +8103,13 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s)
                                 tmp = load_reg(s, rm);
                                 switch (op1) {
                                 case 0: /* stl */
-                                    gen_aa32_st32(tmp, addr, IS_USER(s));
+                                    gen_aa32_st32(tmp, addr, get_mem_index(s));
                                     break;
                                 case 2: /* stlb */
-                                    gen_aa32_st8(tmp, addr, IS_USER(s));
+                                    gen_aa32_st8(tmp, addr, get_mem_index(s));
                                     break;
                                 case 3: /* stlh */
-                                    gen_aa32_st16(tmp, addr, IS_USER(s));
+                                    gen_aa32_st16(tmp, addr, get_mem_index(s));
                                     break;
                                 default:
                                     abort();
@@ -8165,11 +8164,11 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s)
                         tmp = load_reg(s, rm);
                         tmp2 = tcg_temp_new_i32();
                         if (insn & (1 << 22)) {
-                            gen_aa32_ld8u(tmp2, addr, IS_USER(s));
-                            gen_aa32_st8(tmp, addr, IS_USER(s));
+                            gen_aa32_ld8u(tmp2, addr, get_mem_index(s));
+                            gen_aa32_st8(tmp, addr, get_mem_index(s));
                         } else {
-                            gen_aa32_ld32u(tmp2, addr, IS_USER(s));
-                            gen_aa32_st32(tmp, addr, IS_USER(s));
+                            gen_aa32_ld32u(tmp2, addr, get_mem_index(s));
+                            gen_aa32_st32(tmp, addr, get_mem_index(s));
                         }
                         tcg_temp_free_i32(tmp);
                         tcg_temp_free_i32(addr);
@@ -8191,14 +8190,14 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s)
                     tmp = tcg_temp_new_i32();
                     switch(sh) {
                     case 1:
-                        gen_aa32_ld16u(tmp, addr, IS_USER(s));
+                        gen_aa32_ld16u(tmp, addr, get_mem_index(s));
                         break;
                     case 2:
-                        gen_aa32_ld8s(tmp, addr, IS_USER(s));
+                        gen_aa32_ld8s(tmp, addr, get_mem_index(s));
                         break;
                     default:
                     case 3:
-                        gen_aa32_ld16s(tmp, addr, IS_USER(s));
+                        gen_aa32_ld16s(tmp, addr, get_mem_index(s));
                         break;
                     }
                     load = 1;
@@ -8208,21 +8207,21 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s)
                     if (sh & 1) {
                         /* store */
                         tmp = load_reg(s, rd);
-                        gen_aa32_st32(tmp, addr, IS_USER(s));
+                        gen_aa32_st32(tmp, addr, get_mem_index(s));
                         tcg_temp_free_i32(tmp);
                         tcg_gen_addi_i32(addr, addr, 4);
                         tmp = load_reg(s, rd + 1);
-                        gen_aa32_st32(tmp, addr, IS_USER(s));
+                        gen_aa32_st32(tmp, addr, get_mem_index(s));
                         tcg_temp_free_i32(tmp);
                         load = 0;
                     } else {
                         /* load */
                         tmp = tcg_temp_new_i32();
-                        gen_aa32_ld32u(tmp, addr, IS_USER(s));
+                        gen_aa32_ld32u(tmp, addr, get_mem_index(s));
                         store_reg(s, rd, tmp);
                         tcg_gen_addi_i32(addr, addr, 4);
                         tmp = tcg_temp_new_i32();
-                        gen_aa32_ld32u(tmp, addr, IS_USER(s));
+                        gen_aa32_ld32u(tmp, addr, get_mem_index(s));
                         rd++;
                         load = 1;
                     }
@@ -8230,7 +8229,7 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s)
                 } else {
                     /* store */
                     tmp = load_reg(s, rd);
-                    gen_aa32_st16(tmp, addr, IS_USER(s));
+                    gen_aa32_st16(tmp, addr, get_mem_index(s));
                     tcg_temp_free_i32(tmp);
                     load = 0;
                 }
@@ -8568,7 +8567,12 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s)
             rn = (insn >> 16) & 0xf;
             rd = (insn >> 12) & 0xf;
             tmp2 = load_reg(s, rn);
-            i = (IS_USER(s) || (insn & 0x01200000) == 0x00200000);
+            if ((insn & 0x01200000) == 0x00200000) {
+                /* ldrt/strt */
+                i = MMU_USER_IDX;
+            } else {
+                i = get_mem_index(s);
+            }
             if (insn & (1 << 24))
                 gen_add_data_offset(s, insn, tmp2);
             if (insn & (1 << 20)) {
@@ -8652,7 +8656,7 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s)
                         if (insn & (1 << 20)) {
                             /* load */
                             tmp = tcg_temp_new_i32();
-                            gen_aa32_ld32u(tmp, addr, IS_USER(s));
+                            gen_aa32_ld32u(tmp, addr, get_mem_index(s));
                             if (user) {
                                 tmp2 = tcg_const_i32(i);
                                 gen_helper_set_user_reg(cpu_env, tmp2, tmp);
@@ -8679,7 +8683,7 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s)
                             } else {
                                 tmp = load_reg(s, i);
                             }
-                            gen_aa32_st32(tmp, addr, IS_USER(s));
+                            gen_aa32_st32(tmp, addr, get_mem_index(s));
                             tcg_temp_free_i32(tmp);
                         }
                         j++;
@@ -8945,20 +8949,20 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
                 if (insn & (1 << 20)) {
                     /* ldrd */
                     tmp = tcg_temp_new_i32();
-                    gen_aa32_ld32u(tmp, addr, IS_USER(s));
+                    gen_aa32_ld32u(tmp, addr, get_mem_index(s));
                     store_reg(s, rs, tmp);
                     tcg_gen_addi_i32(addr, addr, 4);
                     tmp = tcg_temp_new_i32();
-                    gen_aa32_ld32u(tmp, addr, IS_USER(s));
+                    gen_aa32_ld32u(tmp, addr, get_mem_index(s));
                     store_reg(s, rd, tmp);
                 } else {
                     /* strd */
                     tmp = load_reg(s, rs);
-                    gen_aa32_st32(tmp, addr, IS_USER(s));
+                    gen_aa32_st32(tmp, addr, get_mem_index(s));
                     tcg_temp_free_i32(tmp);
                     tcg_gen_addi_i32(addr, addr, 4);
                     tmp = load_reg(s, rd);
-                    gen_aa32_st32(tmp, addr, IS_USER(s));
+                    gen_aa32_st32(tmp, addr, get_mem_index(s));
                     tcg_temp_free_i32(tmp);
                 }
                 if (insn & (1 << 21)) {
@@ -8996,11 +9000,11 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
                     tcg_gen_add_i32(addr, addr, tmp);
                     tcg_temp_free_i32(tmp);
                     tmp = tcg_temp_new_i32();
-                    gen_aa32_ld16u(tmp, addr, IS_USER(s));
+                    gen_aa32_ld16u(tmp, addr, get_mem_index(s));
                 } else { /* tbb */
                     tcg_temp_free_i32(tmp);
                     tmp = tcg_temp_new_i32();
-                    gen_aa32_ld8u(tmp, addr, IS_USER(s));
+                    gen_aa32_ld8u(tmp, addr, get_mem_index(s));
                 }
                 tcg_temp_free_i32(addr);
                 tcg_gen_shli_i32(tmp, tmp, 1);
@@ -9037,13 +9041,13 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
                         tmp = tcg_temp_new_i32();
                         switch (op) {
                         case 0: /* ldab */
-                            gen_aa32_ld8u(tmp, addr, IS_USER(s));
+                            gen_aa32_ld8u(tmp, addr, get_mem_index(s));
                             break;
                         case 1: /* ldah */
-                            gen_aa32_ld16u(tmp, addr, IS_USER(s));
+                            gen_aa32_ld16u(tmp, addr, get_mem_index(s));
                             break;
                         case 2: /* lda */
-                            gen_aa32_ld32u(tmp, addr, IS_USER(s));
+                            gen_aa32_ld32u(tmp, addr, get_mem_index(s));
                             break;
                         default:
                             abort();
@@ -9053,13 +9057,13 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
                         tmp = load_reg(s, rs);
                         switch (op) {
                         case 0: /* stlb */
-                            gen_aa32_st8(tmp, addr, IS_USER(s));
+                            gen_aa32_st8(tmp, addr, get_mem_index(s));
                             break;
                         case 1: /* stlh */
-                            gen_aa32_st16(tmp, addr, IS_USER(s));
+                            gen_aa32_st16(tmp, addr, get_mem_index(s));
                             break;
                         case 2: /* stl */
-                            gen_aa32_st32(tmp, addr, IS_USER(s));
+                            gen_aa32_st32(tmp, addr, get_mem_index(s));
                             break;
                         default:
                             abort();
@@ -9087,10 +9091,10 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
                         tcg_gen_addi_i32(addr, addr, -8);
                     /* Load PC into tmp and CPSR into tmp2.  */
                     tmp = tcg_temp_new_i32();
-                    gen_aa32_ld32u(tmp, addr, 0);
+                    gen_aa32_ld32u(tmp, addr, get_mem_index(s));
                     tcg_gen_addi_i32(addr, addr, 4);
                     tmp2 = tcg_temp_new_i32();
-                    gen_aa32_ld32u(tmp2, addr, 0);
+                    gen_aa32_ld32u(tmp2, addr, get_mem_index(s));
                     if (insn & (1 << 21)) {
                         /* Base writeback.  */
                         if (insn & (1 << 24)) {
@@ -9129,7 +9133,7 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
                     if (insn & (1 << 20)) {
                         /* Load.  */
                         tmp = tcg_temp_new_i32();
-                        gen_aa32_ld32u(tmp, addr, IS_USER(s));
+                        gen_aa32_ld32u(tmp, addr, get_mem_index(s));
                         if (i == 15) {
                             gen_bx(s, tmp);
                         } else if (i == rn) {
@@ -9141,7 +9145,7 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
                     } else {
                         /* Store.  */
                         tmp = load_reg(s, i);
-                        gen_aa32_st32(tmp, addr, IS_USER(s));
+                        gen_aa32_st32(tmp, addr, get_mem_index(s));
                         tcg_temp_free_i32(tmp);
                     }
                     tcg_gen_addi_i32(addr, addr, 4);
@@ -9841,7 +9845,7 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
         {
         int postinc = 0;
         int writeback = 0;
-        int user;
+        int memidx;
         if ((insn & 0x01100000) == 0x01000000) {
             if (disas_neon_ls_insn(env, s, insn))
                 goto illegal_op;
@@ -9885,7 +9889,7 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
                 return 1;
             }
         }
-        user = IS_USER(s);
+        memidx = get_mem_index(s);
         if (rn == 15) {
             addr = tcg_temp_new_i32();
             /* PC relative.  */
@@ -9922,7 +9926,7 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
                     break;
                 case 0xe: /* User privilege.  */
                     tcg_gen_addi_i32(addr, addr, imm);
-                    user = 1;
+                    memidx = MMU_USER_IDX;
                     break;
                 case 0x9: /* Post-decrement.  */
                     imm = -imm;
@@ -9949,19 +9953,19 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
             tmp = tcg_temp_new_i32();
             switch (op) {
             case 0:
-                gen_aa32_ld8u(tmp, addr, user);
+                gen_aa32_ld8u(tmp, addr, memidx);
                 break;
             case 4:
-                gen_aa32_ld8s(tmp, addr, user);
+                gen_aa32_ld8s(tmp, addr, memidx);
                 break;
             case 1:
-                gen_aa32_ld16u(tmp, addr, user);
+                gen_aa32_ld16u(tmp, addr, memidx);
                 break;
             case 5:
-                gen_aa32_ld16s(tmp, addr, user);
+                gen_aa32_ld16s(tmp, addr, memidx);
                 break;
             case 2:
-                gen_aa32_ld32u(tmp, addr, user);
+                gen_aa32_ld32u(tmp, addr, memidx);
                 break;
             default:
                 tcg_temp_free_i32(tmp);
@@ -9978,13 +9982,13 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
             tmp = load_reg(s, rs);
             switch (op) {
             case 0:
-                gen_aa32_st8(tmp, addr, user);
+                gen_aa32_st8(tmp, addr, memidx);
                 break;
             case 1:
-                gen_aa32_st16(tmp, addr, user);
+                gen_aa32_st16(tmp, addr, memidx);
                 break;
             case 2:
-                gen_aa32_st32(tmp, addr, user);
+                gen_aa32_st32(tmp, addr, memidx);
                 break;
             default:
                 tcg_temp_free_i32(tmp);
@@ -10121,7 +10125,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
             addr = tcg_temp_new_i32();
             tcg_gen_movi_i32(addr, val);
             tmp = tcg_temp_new_i32();
-            gen_aa32_ld32u(tmp, addr, IS_USER(s));
+            gen_aa32_ld32u(tmp, addr, get_mem_index(s));
             tcg_temp_free_i32(addr);
             store_reg(s, rd, tmp);
             break;
@@ -10324,28 +10328,28 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
 
         switch (op) {
         case 0: /* str */
-            gen_aa32_st32(tmp, addr, IS_USER(s));
+            gen_aa32_st32(tmp, addr, get_mem_index(s));
             break;
         case 1: /* strh */
-            gen_aa32_st16(tmp, addr, IS_USER(s));
+            gen_aa32_st16(tmp, addr, get_mem_index(s));
             break;
         case 2: /* strb */
-            gen_aa32_st8(tmp, addr, IS_USER(s));
+            gen_aa32_st8(tmp, addr, get_mem_index(s));
             break;
         case 3: /* ldrsb */
-            gen_aa32_ld8s(tmp, addr, IS_USER(s));
+            gen_aa32_ld8s(tmp, addr, get_mem_index(s));
             break;
         case 4: /* ldr */
-            gen_aa32_ld32u(tmp, addr, IS_USER(s));
+            gen_aa32_ld32u(tmp, addr, get_mem_index(s));
             break;
         case 5: /* ldrh */
-            gen_aa32_ld16u(tmp, addr, IS_USER(s));
+            gen_aa32_ld16u(tmp, addr, get_mem_index(s));
             break;
         case 6: /* ldrb */
-            gen_aa32_ld8u(tmp, addr, IS_USER(s));
+            gen_aa32_ld8u(tmp, addr, get_mem_index(s));
             break;
         case 7: /* ldrsh */
-            gen_aa32_ld16s(tmp, addr, IS_USER(s));
+            gen_aa32_ld16s(tmp, addr, get_mem_index(s));
             break;
         }
         if (op >= 3) { /* load */
@@ -10367,12 +10371,12 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
         if (insn & (1 << 11)) {
             /* load */
             tmp = tcg_temp_new_i32();
-            gen_aa32_ld32u(tmp, addr, IS_USER(s));
+            gen_aa32_ld32u(tmp, addr, get_mem_index(s));
             store_reg(s, rd, tmp);
         } else {
             /* store */
             tmp = load_reg(s, rd);
-            gen_aa32_st32(tmp, addr, IS_USER(s));
+            gen_aa32_st32(tmp, addr, get_mem_index(s));
             tcg_temp_free_i32(tmp);
         }
         tcg_temp_free_i32(addr);
@@ -10389,12 +10393,12 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
         if (insn & (1 << 11)) {
             /* load */
             tmp = tcg_temp_new_i32();
-            gen_aa32_ld8u(tmp, addr, IS_USER(s));
+            gen_aa32_ld8u(tmp, addr, get_mem_index(s));
             store_reg(s, rd, tmp);
         } else {
             /* store */
             tmp = load_reg(s, rd);
-            gen_aa32_st8(tmp, addr, IS_USER(s));
+            gen_aa32_st8(tmp, addr, get_mem_index(s));
             tcg_temp_free_i32(tmp);
         }
         tcg_temp_free_i32(addr);
@@ -10411,12 +10415,12 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
         if (insn & (1 << 11)) {
             /* load */
             tmp = tcg_temp_new_i32();
-            gen_aa32_ld16u(tmp, addr, IS_USER(s));
+            gen_aa32_ld16u(tmp, addr, get_mem_index(s));
             store_reg(s, rd, tmp);
         } else {
             /* store */
             tmp = load_reg(s, rd);
-            gen_aa32_st16(tmp, addr, IS_USER(s));
+            gen_aa32_st16(tmp, addr, get_mem_index(s));
             tcg_temp_free_i32(tmp);
         }
         tcg_temp_free_i32(addr);
@@ -10432,12 +10436,12 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
         if (insn & (1 << 11)) {
             /* load */
             tmp = tcg_temp_new_i32();
-            gen_aa32_ld32u(tmp, addr, IS_USER(s));
+            gen_aa32_ld32u(tmp, addr, get_mem_index(s));
             store_reg(s, rd, tmp);
         } else {
             /* store */
             tmp = load_reg(s, rd);
-            gen_aa32_st32(tmp, addr, IS_USER(s));
+            gen_aa32_st32(tmp, addr, get_mem_index(s));
             tcg_temp_free_i32(tmp);
         }
         tcg_temp_free_i32(addr);
@@ -10505,12 +10509,12 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
                     if (insn & (1 << 11)) {
                         /* pop */
                         tmp = tcg_temp_new_i32();
-                        gen_aa32_ld32u(tmp, addr, IS_USER(s));
+                        gen_aa32_ld32u(tmp, addr, get_mem_index(s));
                         store_reg(s, i, tmp);
                     } else {
                         /* push */
                         tmp = load_reg(s, i);
-                        gen_aa32_st32(tmp, addr, IS_USER(s));
+                        gen_aa32_st32(tmp, addr, get_mem_index(s));
                         tcg_temp_free_i32(tmp);
                     }
                     /* advance to the next address.  */
@@ -10522,13 +10526,13 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
                 if (insn & (1 << 11)) {
                     /* pop pc */
                     tmp = tcg_temp_new_i32();
-                    gen_aa32_ld32u(tmp, addr, IS_USER(s));
+                    gen_aa32_ld32u(tmp, addr, get_mem_index(s));
                     /* don't set the pc until the rest of the instruction
                        has completed */
                 } else {
                     /* push lr */
                     tmp = load_reg(s, 14);
-                    gen_aa32_st32(tmp, addr, IS_USER(s));
+                    gen_aa32_st32(tmp, addr, get_mem_index(s));
                     tcg_temp_free_i32(tmp);
                 }
                 tcg_gen_addi_i32(addr, addr, 4);
@@ -10657,7 +10661,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
                 if (insn & (1 << 11)) {
                     /* load */
                     tmp = tcg_temp_new_i32();
-                    gen_aa32_ld32u(tmp, addr, IS_USER(s));
+                    gen_aa32_ld32u(tmp, addr, get_mem_index(s));
                     if (i == rn) {
                         loaded_var = tmp;
                     } else {
@@ -10666,7 +10670,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
                 } else {
                     /* store */
                     tmp = load_reg(s, i);
-                    gen_aa32_st32(tmp, addr, IS_USER(s));
+                    gen_aa32_st32(tmp, addr, get_mem_index(s));
                     tcg_temp_free_i32(tmp);
                 }
                 /* advance to the next address */
@@ -11047,8 +11051,8 @@ void gen_intermediate_code_pc(CPUARMState *env, TranslationBlock *tb)
 }
 
 static const char *cpu_mode_names[16] = {
-  "usr", "fiq", "irq", "svc", "???", "???", "???", "abt",
-  "???", "???", "???", "und", "???", "???", "???", "sys"
+  "usr", "fiq", "irq", "svc", "???", "???", "mon", "abt",
+  "???", "???", "hyp", "und", "???", "???", "???", "sys"
 };
 
 void arm_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
diff --git a/target-arm/translate.h b/target-arm/translate.h
index 34328f4660..31a0104b58 100644
--- a/target-arm/translate.h
+++ b/target-arm/translate.h
@@ -52,6 +52,11 @@ static inline int arm_dc_feature(DisasContext *dc, int feature)
     return (dc->features & (1ULL << feature)) != 0;
 }
 
+static inline int get_mem_index(DisasContext *s)
+{
+    return s->current_pl;
+}
+
 /* target-specific extra values for is_jmp */
 /* These instructions trap after executing, so the A32/T32 decoder must
  * defer them until after the conditional execution state has been updated.
diff --git a/target-cris/helper.h b/target-cris/helper.h
index 0ac31f5670..0b383b25a4 100644
--- a/target-cris/helper.h
+++ b/target-cris/helper.h
@@ -1,5 +1,3 @@
-#include "exec/def-helper.h"
-
 DEF_HELPER_2(raise_exception, void, env, i32)
 DEF_HELPER_2(tlb_flush_pid, void, env, i32)
 DEF_HELPER_2(spc_write, void, env, i32)
@@ -25,5 +23,3 @@ DEF_HELPER_FLAGS_3(evaluate_flags_move_4, TCG_CALL_NO_SE, i32, env, i32, i32)
 DEF_HELPER_FLAGS_3(evaluate_flags_move_2, TCG_CALL_NO_SE, i32, env, i32, i32)
 DEF_HELPER_1(evaluate_flags, void, env)
 DEF_HELPER_1(top_evaluate_flags, void, env)
-
-#include "exec/def-helper.h"
diff --git a/target-cris/op_helper.c b/target-cris/op_helper.c
index bd9a583f9a..a9bd742d3b 100644
--- a/target-cris/op_helper.c
+++ b/target-cris/op_helper.c
@@ -20,7 +20,7 @@
 
 #include "cpu.h"
 #include "mmu.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 #include "qemu/host-utils.h"
 
 //#define CRIS_OP_HELPER_DEBUG
diff --git a/target-cris/translate.c b/target-cris/translate.c
index 724f920e92..90fe0a24b5 100644
--- a/target-cris/translate.c
+++ b/target-cris/translate.c
@@ -26,12 +26,11 @@
 #include "cpu.h"
 #include "disas/disas.h"
 #include "tcg-op.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 #include "mmu.h"
 #include "crisv32-decode.h"
 
-#define GEN_HELPER 1
-#include "helper.h"
+#include "exec/helper-gen.h"
 
 #define DISAS_CRIS 0
 #if DISAS_CRIS
diff --git a/target-i386/cc_helper.c b/target-i386/cc_helper.c
index 05dd12b5a7..ecbf0ec09c 100644
--- a/target-i386/cc_helper.c
+++ b/target-i386/cc_helper.c
@@ -18,7 +18,7 @@
  */
 
 #include "cpu.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 
 const uint8_t parity_table[256] = {
     CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
diff --git a/target-i386/excp_helper.c b/target-i386/excp_helper.c
index f337fd20fb..99fca847dd 100644
--- a/target-i386/excp_helper.c
+++ b/target-i386/excp_helper.c
@@ -20,7 +20,7 @@
 #include "cpu.h"
 #include "qemu/log.h"
 #include "sysemu/sysemu.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 
 #if 0
 #define raise_exception_err(env, a, b)                                  \
diff --git a/target-i386/fpu_helper.c b/target-i386/fpu_helper.c
index de7ba76a49..a04e754e61 100644
--- a/target-i386/fpu_helper.c
+++ b/target-i386/fpu_helper.c
@@ -19,7 +19,7 @@
 
 #include <math.h>
 #include "cpu.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 #include "qemu/aes.h"
 #include "qemu/host-utils.h"
 
diff --git a/target-i386/helper.h b/target-i386/helper.h
index 3775abeba7..8eb0145039 100644
--- a/target-i386/helper.h
+++ b/target-i386/helper.h
@@ -1,5 +1,3 @@
-#include "exec/def-helper.h"
-
 DEF_HELPER_FLAGS_4(cc_compute_all, TCG_CALL_NO_RWG_SE, tl, tl, tl, tl, int)
 DEF_HELPER_FLAGS_4(cc_compute_c, TCG_CALL_NO_RWG_SE, tl, tl, tl, tl, int)
 
@@ -219,5 +217,3 @@ DEF_HELPER_3(rcrl, tl, env, tl, tl)
 DEF_HELPER_3(rclq, tl, env, tl, tl)
 DEF_HELPER_3(rcrq, tl, env, tl, tl)
 #endif
-
-#include "exec/def-helper.h"
diff --git a/target-i386/int_helper.c b/target-i386/int_helper.c
index 0555318938..b0d78e6eee 100644
--- a/target-i386/int_helper.c
+++ b/target-i386/int_helper.c
@@ -19,7 +19,7 @@
 
 #include "cpu.h"
 #include "qemu/host-utils.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 
 //#define DEBUG_MULDIV
 
diff --git a/target-i386/mem_helper.c b/target-i386/mem_helper.c
index b3b811bc8c..83aa1038d7 100644
--- a/target-i386/mem_helper.c
+++ b/target-i386/mem_helper.c
@@ -18,7 +18,7 @@
  */
 
 #include "cpu.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 
 #if !defined(CONFIG_USER_ONLY)
 #include "exec/softmmu_exec.h"
diff --git a/target-i386/misc_helper.c b/target-i386/misc_helper.c
index 1e2da1ed68..9cfa25f9ec 100644
--- a/target-i386/misc_helper.c
+++ b/target-i386/misc_helper.c
@@ -19,7 +19,7 @@
 
 #include "cpu.h"
 #include "exec/ioport.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 
 #if !defined(CONFIG_USER_ONLY)
 #include "exec/softmmu_exec.h"
diff --git a/target-i386/seg_helper.c b/target-i386/seg_helper.c
index 0b19a8ce64..51c2833ea5 100644
--- a/target-i386/seg_helper.c
+++ b/target-i386/seg_helper.c
@@ -20,7 +20,7 @@
 
 #include "cpu.h"
 #include "qemu/log.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 
 //#define DEBUG_PCALL
 
diff --git a/target-i386/smm_helper.c b/target-i386/smm_helper.c
index 1e5f5ce07e..58051d3bcc 100644
--- a/target-i386/smm_helper.c
+++ b/target-i386/smm_helper.c
@@ -18,7 +18,7 @@
  */
 
 #include "cpu.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 
 /* SMM support */
 
diff --git a/target-i386/svm_helper.c b/target-i386/svm_helper.c
index 8dc6f8ccda..ea5de6fa94 100644
--- a/target-i386/svm_helper.c
+++ b/target-i386/svm_helper.c
@@ -19,7 +19,7 @@
 
 #include "cpu.h"
 #include "exec/cpu-all.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 
 #if !defined(CONFIG_USER_ONLY)
 #include "exec/softmmu_exec.h"
diff --git a/target-i386/translate.c b/target-i386/translate.c
index 032b0fdffc..3aa52eb795 100644
--- a/target-i386/translate.c
+++ b/target-i386/translate.c
@@ -28,9 +28,8 @@
 #include "disas/disas.h"
 #include "tcg-op.h"
 
-#include "helper.h"
-#define GEN_HELPER 1
-#include "helper.h"
+#include "exec/helper-proto.h"
+#include "exec/helper-gen.h"
 
 #define PREFIX_REPZ   0x01
 #define PREFIX_REPNZ  0x02
diff --git a/target-lm32/Makefile.objs b/target-lm32/Makefile.objs
index 40236876c8..c3e1bd6bd6 100644
--- a/target-lm32/Makefile.objs
+++ b/target-lm32/Makefile.objs
@@ -1,3 +1,4 @@
 obj-y += translate.o op_helper.o helper.o cpu.o
 obj-y += gdbstub.o
+obj-y += lm32-semi.o
 obj-$(CONFIG_SOFTMMU) += machine.o
diff --git a/target-lm32/README b/target-lm32/README
index a1c2c7eb1e..ba3508a711 100644
--- a/target-lm32/README
+++ b/target-lm32/README
@@ -16,14 +16,13 @@ This will make serial0 (the lm32_uart) and serial1 (the JTAG UART)
 available as virtual consoles.
 
 
-Programmatically terminate the emulator
-----------------------------------------
-Originally neither the LatticeMico32 nor its peripherals support a
-mechanism to shut down the machine. Emulation aware programs can write to a
-to a special register within the system control block to shut down the
-virtual machine.  For more details see hw/lm32_sys.c. The lm32-evr is the
-first BSP which instantiate this model. A (32 bit) write to 0xfff0000
-causes a vm shutdown.
+Semihosting
+-----------
+Semihosting on this target is supported. Some system calls like read, write
+and exit are executed on the host if semihosting is enabled. See
+target/lm32-semi.c for all supported system calls. Emulation aware programs
+can use this mechanism to shut down the virtual machine and print to the
+host console. See the tcg tests for an example.
 
 
 Special instructions
diff --git a/target-lm32/cpu.h b/target-lm32/cpu.h
index 24bde78502..70600aa47a 100644
--- a/target-lm32/cpu.h
+++ b/target-lm32/cpu.h
@@ -217,6 +217,7 @@ void lm32_breakpoint_remove(CPULM32State *env, int index);
 void lm32_watchpoint_insert(CPULM32State *env, int index, target_ulong address,
         lm32_wp_t wp_type);
 void lm32_watchpoint_remove(CPULM32State *env, int index);
+bool lm32_cpu_do_semihosting(CPUState *cs);
 
 static inline CPULM32State *cpu_init(const char *cpu_model)
 {
diff --git a/target-lm32/helper.c b/target-lm32/helper.c
index 783aa16a45..1bca1961af 100644
--- a/target-lm32/helper.c
+++ b/target-lm32/helper.c
@@ -1,7 +1,7 @@
 /*
  *  LatticeMico32 helper routines.
  *
- *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
+ *  Copyright (c) 2010-2014 Michael Walle <michael@walle.cc>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -19,6 +19,7 @@
 
 #include "cpu.h"
 #include "qemu/host-utils.h"
+#include "sysemu/sysemu.h"
 
 int lm32_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw,
                               int mmu_idx)
@@ -159,11 +160,20 @@ void lm32_cpu_do_interrupt(CPUState *cs)
             "exception at pc=%x type=%x\n", env->pc, cs->exception_index);
 
     switch (cs->exception_index) {
+    case EXCP_SYSTEMCALL:
+        if (unlikely(semihosting_enabled)) {
+            /* do_semicall() returns true if call was handled. Otherwise
+             * do the normal exception handling. */
+            if (lm32_cpu_do_semihosting(cs)) {
+                env->pc += 4;
+                break;
+            }
+        }
+        /* fall through */
     case EXCP_INSN_BUS_ERROR:
     case EXCP_DATA_BUS_ERROR:
     case EXCP_DIVIDE_BY_ZERO:
     case EXCP_IRQ:
-    case EXCP_SYSTEMCALL:
         /* non-debug exceptions */
         env->regs[R_EA] = env->pc;
         env->ie |= (env->ie & IE_IE) ? IE_EIE : 0;
diff --git a/target-lm32/helper.h b/target-lm32/helper.h
index f4442e0a93..445578c439 100644
--- a/target-lm32/helper.h
+++ b/target-lm32/helper.h
@@ -1,5 +1,3 @@
-#include "exec/def-helper.h"
-
 DEF_HELPER_2(raise_exception, void, env, i32)
 DEF_HELPER_1(hlt, void, env)
 DEF_HELPER_3(wcsr_bp, void, env, i32, i32)
@@ -14,5 +12,3 @@ DEF_HELPER_1(rcsr_ip, i32, env)
 DEF_HELPER_1(rcsr_jtx, i32, env)
 DEF_HELPER_1(rcsr_jrx, i32, env)
 DEF_HELPER_1(ill, void, env)
-
-#include "exec/def-helper.h"
diff --git a/target-lm32/lm32-semi.c b/target-lm32/lm32-semi.c
new file mode 100644
index 0000000000..ec6524f376
--- /dev/null
+++ b/target-lm32/lm32-semi.c
@@ -0,0 +1,215 @@
+/*
+ *  Lattice Mico32 semihosting syscall interface
+ *
+ *  Copyright (c) 2014 Michael Walle <michael@walle.cc>
+ *
+ * Based on target-m68k/m68k-semi.c, which is
+ *  Copyright (c) 2005-2007 CodeSourcery.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <stddef.h>
+#include "cpu.h"
+#include "exec/helper-proto.h"
+#include "qemu/log.h"
+#include "exec/softmmu-semi.h"
+
+enum {
+    TARGET_SYS_exit    = 1,
+    TARGET_SYS_open    = 2,
+    TARGET_SYS_close   = 3,
+    TARGET_SYS_read    = 4,
+    TARGET_SYS_write   = 5,
+    TARGET_SYS_lseek   = 6,
+    TARGET_SYS_fstat   = 10,
+    TARGET_SYS_stat    = 15,
+};
+
+enum {
+    NEWLIB_O_RDONLY    =   0x0,
+    NEWLIB_O_WRONLY    =   0x1,
+    NEWLIB_O_RDWR      =   0x2,
+    NEWLIB_O_APPEND    =   0x8,
+    NEWLIB_O_CREAT     = 0x200,
+    NEWLIB_O_TRUNC     = 0x400,
+    NEWLIB_O_EXCL      = 0x800,
+};
+
+static int translate_openflags(int flags)
+{
+    int hf;
+
+    if (flags & NEWLIB_O_WRONLY) {
+        hf = O_WRONLY;
+    } else if (flags & NEWLIB_O_RDWR) {
+        hf = O_RDWR;
+    } else {
+        hf = O_RDONLY;
+    }
+
+    if (flags & NEWLIB_O_APPEND) {
+        hf |= O_APPEND;
+    }
+
+    if (flags & NEWLIB_O_CREAT) {
+        hf |= O_CREAT;
+    }
+
+    if (flags & NEWLIB_O_TRUNC) {
+        hf |= O_TRUNC;
+    }
+
+    if (flags & NEWLIB_O_EXCL) {
+        hf |= O_EXCL;
+    }
+
+    return hf;
+}
+
+struct newlib_stat {
+    int16_t     newlib_st_dev;     /* device */
+    uint16_t    newlib_st_ino;     /* inode */
+    uint16_t    newlib_st_mode;    /* protection */
+    uint16_t    newlib_st_nlink;   /* number of hard links */
+    uint16_t    newlib_st_uid;     /* user ID of owner */
+    uint16_t    newlib_st_gid;     /* group ID of owner */
+    int16_t     newlib_st_rdev;    /* device type (if inode device) */
+    int32_t     newlib_st_size;    /* total size, in bytes */
+    int32_t     newlib_st_atime;   /* time of last access */
+    uint32_t    newlib_st_spare1;
+    int32_t     newlib_st_mtime;   /* time of last modification */
+    uint32_t    newlib_st_spare2;
+    int32_t     newlib_st_ctime;   /* time of last change */
+    uint32_t    newlib_st_spare3;
+} QEMU_PACKED;
+
+static int translate_stat(CPULM32State *env, target_ulong addr,
+        struct stat *s)
+{
+    struct newlib_stat *p;
+
+    p = lock_user(VERIFY_WRITE, addr, sizeof(struct newlib_stat), 0);
+    if (!p) {
+        return 0;
+    }
+    p->newlib_st_dev = cpu_to_be16(s->st_dev);
+    p->newlib_st_ino = cpu_to_be16(s->st_ino);
+    p->newlib_st_mode = cpu_to_be16(s->st_mode);
+    p->newlib_st_nlink = cpu_to_be16(s->st_nlink);
+    p->newlib_st_uid = cpu_to_be16(s->st_uid);
+    p->newlib_st_gid = cpu_to_be16(s->st_gid);
+    p->newlib_st_rdev = cpu_to_be16(s->st_rdev);
+    p->newlib_st_size = cpu_to_be32(s->st_size);
+    p->newlib_st_atime = cpu_to_be32(s->st_atime);
+    p->newlib_st_mtime = cpu_to_be32(s->st_mtime);
+    p->newlib_st_ctime = cpu_to_be32(s->st_ctime);
+    unlock_user(p, addr, sizeof(struct newlib_stat));
+
+    return 1;
+}
+
+bool lm32_cpu_do_semihosting(CPUState *cs)
+{
+    LM32CPU *cpu = LM32_CPU(cs);
+    CPULM32State *env = &cpu->env;
+
+    int ret = -1;
+    target_ulong nr, arg0, arg1, arg2;
+    void *p;
+    struct stat s;
+
+    nr = env->regs[R_R8];
+    arg0 = env->regs[R_R1];
+    arg1 = env->regs[R_R2];
+    arg2 = env->regs[R_R3];
+
+    switch (nr) {
+    case TARGET_SYS_exit:
+        /* void _exit(int rc) */
+        exit(arg0);
+
+    case TARGET_SYS_open:
+        /* int open(const char *pathname, int flags) */
+        p = lock_user_string(arg0);
+        if (!p) {
+            ret = -1;
+        } else {
+            ret = open(p, translate_openflags(arg2));
+            unlock_user(p, arg0, 0);
+        }
+        break;
+
+    case TARGET_SYS_read:
+        /* ssize_t read(int fd, const void *buf, size_t count) */
+        p = lock_user(VERIFY_WRITE, arg1, arg2, 0);
+        if (!p) {
+            ret = -1;
+        } else {
+            ret = read(arg0, p, arg2);
+            unlock_user(p, arg1, arg2);
+        }
+        break;
+
+    case TARGET_SYS_write:
+        /* ssize_t write(int fd, const void *buf, size_t count) */
+        p = lock_user(VERIFY_READ, arg1, arg2, 1);
+        if (!p) {
+            ret = -1;
+        } else {
+            ret = write(arg0, p, arg2);
+            unlock_user(p, arg1, 0);
+        }
+        break;
+
+    case TARGET_SYS_close:
+        /* int close(int fd) */
+        /* don't close stdin/stdout/stderr */
+        if (arg0 > 2) {
+            ret = close(arg0);
+        } else {
+            ret = 0;
+        }
+        break;
+
+    case TARGET_SYS_lseek:
+        /* off_t lseek(int fd, off_t offset, int whence */
+        ret = lseek(arg0, arg1, arg2);
+        break;
+
+    case TARGET_SYS_stat:
+        /* int stat(const char *path, struct stat *buf) */
+        p = lock_user_string(arg0);
+        if (!p) {
+            ret = -1;
+        } else {
+            ret = stat(p, &s);
+            unlock_user(p, arg0, 0);
+            if (translate_stat(env, arg1, &s) == 0) {
+                ret = -1;
+            }
+        }
+        break;
+
+    case TARGET_SYS_fstat:
+        /* int stat(int fd, struct stat *buf) */
+        ret = fstat(arg0, &s);
+        if (ret == 0) {
+            if (translate_stat(env, arg1, &s) == 0) {
+                ret = -1;
+            }
+        }
+        break;
+
+    default:
+        /* unhandled */
+        return false;
+    }
+
+    env->regs[R_R1] = ret;
+    return true;
+}
diff --git a/target-lm32/op_helper.c b/target-lm32/op_helper.c
index 2f36b7b053..40fbed64c3 100644
--- a/target-lm32/op_helper.c
+++ b/target-lm32/op_helper.c
@@ -1,6 +1,6 @@
 #include <assert.h>
 #include "cpu.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 #include "qemu/host-utils.h"
 
 #include "hw/lm32/lm32_pic.h"
diff --git a/target-lm32/translate.c b/target-lm32/translate.c
index c8abd1f27e..51eca06591 100644
--- a/target-lm32/translate.c
+++ b/target-lm32/translate.c
@@ -19,13 +19,12 @@
 
 #include "cpu.h"
 #include "disas/disas.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 #include "tcg-op.h"
 
 #include "hw/lm32/lm32_pic.h"
 
-#define GEN_HELPER 1
-#include "helper.h"
+#include "exec/helper-gen.h"
 
 #define DISAS_LM32 1
 #if DISAS_LM32
diff --git a/target-m68k/helper.c b/target-m68k/helper.c
index 077b653f24..8be9745697 100644
--- a/target-m68k/helper.c
+++ b/target-m68k/helper.c
@@ -21,7 +21,7 @@
 #include "cpu.h"
 #include "exec/gdbstub.h"
 
-#include "helper.h"
+#include "exec/helper-proto.h"
 
 #define SIGNBIT (1u << 31)
 
diff --git a/target-m68k/helper.h b/target-m68k/helper.h
index 2b024502ba..f4e5fdf021 100644
--- a/target-m68k/helper.h
+++ b/target-m68k/helper.h
@@ -1,5 +1,3 @@
-#include "exec/def-helper.h"
-
 DEF_HELPER_1(bitrev, i32, i32)
 DEF_HELPER_1(ff1, i32, i32)
 DEF_HELPER_2(sats, i32, i32, i32)
@@ -50,5 +48,3 @@ DEF_HELPER_3(set_mac_extu, void, env, i32, i32)
 
 DEF_HELPER_2(flush_flags, void, env, i32)
 DEF_HELPER_2(raise_exception, void, env, i32)
-
-#include "exec/def-helper.h"
diff --git a/target-m68k/op_helper.c b/target-m68k/op_helper.c
index 06302b1071..f1ac139c51 100644
--- a/target-m68k/op_helper.c
+++ b/target-m68k/op_helper.c
@@ -17,7 +17,7 @@
  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  */
 #include "cpu.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 
 #if defined(CONFIG_USER_ONLY)
 
diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index cd662891c8..fa248d96b5 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -23,9 +23,8 @@
 #include "tcg-op.h"
 #include "qemu/log.h"
 
-#include "helper.h"
-#define GEN_HELPER 1
-#include "helper.h"
+#include "exec/helper-proto.h"
+#include "exec/helper-gen.h"
 
 //#define DEBUG_DISPATCH 1
 
diff --git a/target-microblaze/helper.h b/target-microblaze/helper.h
index 4e51429498..bd13826de0 100644
--- a/target-microblaze/helper.h
+++ b/target-microblaze/helper.h
@@ -1,5 +1,3 @@
-#include "exec/def-helper.h"
-
 DEF_HELPER_2(raise_exception, void, env, i32)
 DEF_HELPER_1(debug, void, env)
 DEF_HELPER_FLAGS_3(carry, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32)
@@ -37,5 +35,3 @@ DEF_HELPER_2(stackprot, void, env, i32)
 
 DEF_HELPER_2(get, i32, i32, i32)
 DEF_HELPER_3(put, void, i32, i32, i32)
-
-#include "exec/def-helper.h"
diff --git a/target-microblaze/op_helper.c b/target-microblaze/op_helper.c
index f8fb7f9169..b24b878919 100644
--- a/target-microblaze/op_helper.c
+++ b/target-microblaze/op_helper.c
@@ -20,7 +20,7 @@
 
 #include <assert.h>
 #include "cpu.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 #include "qemu/host-utils.h"
 
 #define D(x)
diff --git a/target-microblaze/translate.c b/target-microblaze/translate.c
index 782a489016..488df2d60d 100644
--- a/target-microblaze/translate.c
+++ b/target-microblaze/translate.c
@@ -21,11 +21,9 @@
 #include "cpu.h"
 #include "disas/disas.h"
 #include "tcg-op.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 #include "microblaze-decode.h"
-
-#define GEN_HELPER 1
-#include "helper.h"
+#include "exec/helper-gen.h"
 
 #define SIM_COMPAT 0
 #define DISAS_GNU 1
diff --git a/target-mips/dsp_helper.c b/target-mips/dsp_helper.c
index a2f46d9637..94083fb424 100644
--- a/target-mips/dsp_helper.c
+++ b/target-mips/dsp_helper.c
@@ -18,7 +18,7 @@
  */
 
 #include "cpu.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 #include "qemu/bitops.h"
 
 /* As the byte ordering doesn't matter, i.e. all columns are treated
diff --git a/target-mips/helper.h b/target-mips/helper.h
index 8c7921a724..74ef09485f 100644
--- a/target-mips/helper.h
+++ b/target-mips/helper.h
@@ -1,5 +1,3 @@
-#include "exec/def-helper.h"
-
 DEF_HELPER_3(raise_exception_err, noreturn, env, i32, int)
 DEF_HELPER_2(raise_exception, noreturn, env, i32)
 
@@ -691,7 +689,3 @@ DEF_HELPER_FLAGS_3(dmthlip, 0, void, tl, tl, env)
 #endif
 DEF_HELPER_FLAGS_3(wrdsp, 0, void, tl, tl, env)
 DEF_HELPER_FLAGS_2(rddsp, 0, tl, tl, env)
-
-
-
-#include "exec/def-helper.h"
diff --git a/target-mips/lmi_helper.c b/target-mips/lmi_helper.c
index 1b24353519..bbfcd59cdb 100644
--- a/target-mips/lmi_helper.c
+++ b/target-mips/lmi_helper.c
@@ -18,7 +18,7 @@
  */
 
 #include "cpu.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 
 /* If the byte ordering doesn't matter, i.e. all columns are treated
    identically, then this union can be used directly.  If byte ordering
diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
index 4edec6c617..8af931abd9 100644
--- a/target-mips/op_helper.c
+++ b/target-mips/op_helper.c
@@ -20,7 +20,7 @@
 #include "cpu.h"
 #include "qemu/host-utils.h"
 
-#include "helper.h"
+#include "exec/helper-proto.h"
 
 #if !defined(CONFIG_USER_ONLY)
 #include "exec/softmmu_exec.h"
diff --git a/target-mips/translate.c b/target-mips/translate.c
index 05f82d2f9b..13cf29b9d9 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -25,9 +25,8 @@
 #include "disas/disas.h"
 #include "tcg-op.h"
 
-#include "helper.h"
-#define GEN_HELPER 1
-#include "helper.h"
+#include "exec/helper-proto.h"
+#include "exec/helper-gen.h"
 
 #define MIPS_DEBUG_DISAS 0
 //#define MIPS_DEBUG_SIGN_EXTENSIONS
diff --git a/target-moxie/helper.c b/target-moxie/helper.c
index 3d0c34dd0a..d1efdedf9d 100644
--- a/target-moxie/helper.c
+++ b/target-moxie/helper.c
@@ -27,7 +27,7 @@
 #include "exec/exec-all.h"
 #include "exec/softmmu_exec.h"
 #include "qemu/host-utils.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 
 #define MMUSUFFIX _mmu
 
diff --git a/target-moxie/helper.h b/target-moxie/helper.h
index 3aa55499f5..d94ef7a17e 100644
--- a/target-moxie/helper.h
+++ b/target-moxie/helper.h
@@ -1,9 +1,5 @@
-#include "exec/def-helper.h"
-
 DEF_HELPER_2(raise_exception, void, env, int)
 DEF_HELPER_1(debug, void, env)
 
 DEF_HELPER_FLAGS_3(div, TCG_CALL_NO_WG, i32, env, i32, i32)
 DEF_HELPER_FLAGS_3(udiv, TCG_CALL_NO_WG, i32, env, i32, i32)
-
-#include "exec/def-helper.h"
diff --git a/target-moxie/translate.c b/target-moxie/translate.c
index 63f889fd7f..7f0dfb66f2 100644
--- a/target-moxie/translate.c
+++ b/target-moxie/translate.c
@@ -33,9 +33,8 @@
 #include "disas/disas.h"
 #include "tcg-op.h"
 
-#include "helper.h"
-#define GEN_HELPER 1
-#include "helper.h"
+#include "exec/helper-proto.h"
+#include "exec/helper-gen.h"
 
 /* This is the state at translation time.  */
 typedef struct DisasContext {
diff --git a/target-openrisc/exception_helper.c b/target-openrisc/exception_helper.c
index 0c53b7755b..6093953c97 100644
--- a/target-openrisc/exception_helper.c
+++ b/target-openrisc/exception_helper.c
@@ -18,7 +18,7 @@
  */
 
 #include "cpu.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 #include "exception.h"
 
 void HELPER(exception)(CPUOpenRISCState *env, uint32_t excp)
diff --git a/target-openrisc/fpu_helper.c b/target-openrisc/fpu_helper.c
index 4615a366d1..c94ed35afb 100644
--- a/target-openrisc/fpu_helper.c
+++ b/target-openrisc/fpu_helper.c
@@ -19,7 +19,7 @@
  */
 
 #include "cpu.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 #include "exception.h"
 
 static inline uint32_t ieee_ex_to_openrisc(OpenRISCCPU *cpu, int fexcp)
diff --git a/target-openrisc/helper.h b/target-openrisc/helper.h
index 2af97901ce..f53fa21344 100644
--- a/target-openrisc/helper.h
+++ b/target-openrisc/helper.h
@@ -17,8 +17,6 @@
  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "exec/def-helper.h"
-
 /* exception */
 DEF_HELPER_FLAGS_2(exception, 0, void, env, i32)
 
@@ -66,5 +64,3 @@ DEF_HELPER_FLAGS_1(rfe, 0, void, env)
 /* sys */
 DEF_HELPER_FLAGS_4(mtspr, 0, void, env, tl, tl, tl)
 DEF_HELPER_FLAGS_4(mfspr, 0, tl, env, tl, tl, tl)
-
-#include "exec/def-helper.h"
diff --git a/target-openrisc/int_helper.c b/target-openrisc/int_helper.c
index 16cb5abfcd..6e27aebd9f 100644
--- a/target-openrisc/int_helper.c
+++ b/target-openrisc/int_helper.c
@@ -19,7 +19,7 @@
  */
 
 #include "cpu.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 #include "exception.h"
 #include "qemu/host-utils.h"
 
diff --git a/target-openrisc/interrupt_helper.c b/target-openrisc/interrupt_helper.c
index 819405701d..55a780c7b5 100644
--- a/target-openrisc/interrupt_helper.c
+++ b/target-openrisc/interrupt_helper.c
@@ -19,7 +19,7 @@
  */
 
 #include "cpu.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 
 void HELPER(rfe)(CPUOpenRISCState *env)
 {
diff --git a/target-openrisc/sys_helper.c b/target-openrisc/sys_helper.c
index fedcbed4f7..53ca6bcef9 100644
--- a/target-openrisc/sys_helper.c
+++ b/target-openrisc/sys_helper.c
@@ -19,7 +19,7 @@
  */
 
 #include "cpu.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 
 #define TO_SPR(group, number) (((group) << 11) + (number))
 
diff --git a/target-openrisc/translate.c b/target-openrisc/translate.c
index 852b5e6107..40084f9a52 100644
--- a/target-openrisc/translate.c
+++ b/target-openrisc/translate.c
@@ -27,9 +27,8 @@
 #include "config.h"
 #include "qemu/bitops.h"
 
-#include "helper.h"
-#define GEN_HELPER 1
-#include "helper.h"
+#include "exec/helper-proto.h"
+#include "exec/helper-gen.h"
 
 #define OPENRISC_DISAS
 
diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c
index 4fa297d7dd..a0c9fdc84b 100644
--- a/target-ppc/excp_helper.c
+++ b/target-ppc/excp_helper.c
@@ -17,7 +17,7 @@
  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  */
 #include "cpu.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 
 #include "helper_regs.h"
 
diff --git a/target-ppc/fpu_helper.c b/target-ppc/fpu_helper.c
index c6f484fc34..cd8f015bd7 100644
--- a/target-ppc/fpu_helper.c
+++ b/target-ppc/fpu_helper.c
@@ -17,7 +17,7 @@
  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  */
 #include "cpu.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 
 /*****************************************************************************/
 /* Floating point operations helpers */
diff --git a/target-ppc/helper.h b/target-ppc/helper.h
index 99f10deee1..08f3916e74 100644
--- a/target-ppc/helper.h
+++ b/target-ppc/helper.h
@@ -1,5 +1,3 @@
-#include "exec/def-helper.h"
-
 DEF_HELPER_3(raise_exception_err, void, env, i32, i32)
 DEF_HELPER_2(raise_exception, void, env, i32)
 DEF_HELPER_4(tw, void, env, tl, tl, i32)
@@ -613,5 +611,3 @@ DEF_HELPER_3(store_dbatu, void, env, i32, tl)
 DEF_HELPER_3(store_601_batl, void, env, i32, tl)
 DEF_HELPER_3(store_601_batu, void, env, i32, tl)
 #endif
-
-#include "exec/def-helper.h"
diff --git a/target-ppc/int_helper.c b/target-ppc/int_helper.c
index 18b54f060a..588f6a9b95 100644
--- a/target-ppc/int_helper.c
+++ b/target-ppc/int_helper.c
@@ -18,7 +18,7 @@
  */
 #include "cpu.h"
 #include "qemu/host-utils.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 
 #include "helper_regs.h"
 /*****************************************************************************/
diff --git a/target-ppc/mem_helper.c b/target-ppc/mem_helper.c
index f35ed037c7..d9c8c36712 100644
--- a/target-ppc/mem_helper.c
+++ b/target-ppc/mem_helper.c
@@ -18,7 +18,7 @@
  */
 #include "cpu.h"
 #include "qemu/host-utils.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 
 #include "helper_regs.h"
 
diff --git a/target-ppc/misc_helper.c b/target-ppc/misc_helper.c
index 2eb2fa6e20..7331b1b240 100644
--- a/target-ppc/misc_helper.c
+++ b/target-ppc/misc_helper.c
@@ -17,7 +17,7 @@
  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  */
 #include "cpu.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 
 #include "helper_regs.h"
 
diff --git a/target-ppc/mmu-hash32.c b/target-ppc/mmu-hash32.c
index 1cc19162b7..0a13a81dba 100644
--- a/target-ppc/mmu-hash32.c
+++ b/target-ppc/mmu-hash32.c
@@ -19,7 +19,7 @@
  */
 
 #include "cpu.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 #include "sysemu/kvm.h"
 #include "kvm_ppc.h"
 #include "mmu-hash32.h"
diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
index 1fefe5881e..c72198abde 100644
--- a/target-ppc/mmu-hash64.c
+++ b/target-ppc/mmu-hash64.c
@@ -18,7 +18,7 @@
  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  */
 #include "cpu.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 #include "sysemu/kvm.h"
 #include "kvm_ppc.h"
 #include "mmu-hash64.h"
diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c
index 1771863dff..a238bb2731 100644
--- a/target-ppc/mmu_helper.c
+++ b/target-ppc/mmu_helper.c
@@ -17,7 +17,7 @@
  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  */
 #include "cpu.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 #include "sysemu/kvm.h"
 #include "kvm_ppc.h"
 #include "mmu-hash64.h"
diff --git a/target-ppc/timebase_helper.c b/target-ppc/timebase_helper.c
index fad738a4af..865dcbed22 100644
--- a/target-ppc/timebase_helper.c
+++ b/target-ppc/timebase_helper.c
@@ -17,7 +17,7 @@
  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  */
 #include "cpu.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 
 /*****************************************************************************/
 /* SPR accesses */
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index e3fcb03c26..6283b2c36c 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -23,9 +23,8 @@
 #include "tcg-op.h"
 #include "qemu/host-utils.h"
 
-#include "helper.h"
-#define GEN_HELPER 1
-#include "helper.h"
+#include "exec/helper-proto.h"
+#include "exec/helper-gen.h"
 
 #define CPU_SINGLE_STEP 0x1
 #define CPU_BRANCH_STEP 0x2
diff --git a/target-s390x/cc_helper.c b/target-s390x/cc_helper.c
index 9e676a5ca7..373eb176a1 100644
--- a/target-s390x/cc_helper.c
+++ b/target-s390x/cc_helper.c
@@ -19,7 +19,7 @@
  */
 
 #include "cpu.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 #include "qemu/host-utils.h"
 
 /* #define DEBUG_HELPER */
diff --git a/target-s390x/cpu-qom.h b/target-s390x/cpu-qom.h
index ac0460eb30..f9c96d13a9 100644
--- a/target-s390x/cpu-qom.h
+++ b/target-s390x/cpu-qom.h
@@ -86,6 +86,7 @@ int s390_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs,
 int s390_cpu_write_elf64_qemunote(WriteCoreDumpFunction f,
                                   CPUState *cpu, void *opaque);
 hwaddr s390_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
+hwaddr s390_cpu_get_phys_addr_debug(CPUState *cpu, vaddr addr);
 int s390_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
 int s390_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
 
diff --git a/target-s390x/fpu_helper.c b/target-s390x/fpu_helper.c
index 3e9c7b2d68..d879ad63a1 100644
--- a/target-s390x/fpu_helper.c
+++ b/target-s390x/fpu_helper.c
@@ -19,7 +19,7 @@
  */
 
 #include "cpu.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 
 #if !defined(CONFIG_USER_ONLY)
 #include "exec/softmmu_exec.h"
diff --git a/target-s390x/helper.c b/target-s390x/helper.c
index 7c76fc149b..3d756cae6c 100644
--- a/target-s390x/helper.c
+++ b/target-s390x/helper.c
@@ -489,6 +489,18 @@ hwaddr s390_cpu_get_phys_page_debug(CPUState *cs, vaddr vaddr)
     return raddr;
 }
 
+hwaddr s390_cpu_get_phys_addr_debug(CPUState *cs, vaddr vaddr)
+{
+    hwaddr phys_addr;
+    target_ulong page;
+
+    page = vaddr & TARGET_PAGE_MASK;
+    phys_addr = cpu_get_phys_page_debug(cs, page);
+    phys_addr += (vaddr & ~TARGET_PAGE_MASK);
+
+    return phys_addr;
+}
+
 void load_psw(CPUS390XState *env, uint64_t mask, uint64_t addr)
 {
     if (mask & PSW_MASK_WAIT) {
diff --git a/target-s390x/helper.h b/target-s390x/helper.h
index 0d80aa046f..faebfd96aa 100644
--- a/target-s390x/helper.h
+++ b/target-s390x/helper.h
@@ -1,5 +1,3 @@
-#include "exec/def-helper.h"
-
 DEF_HELPER_2(exception, noreturn, env, i32)
 DEF_HELPER_FLAGS_4(nc, TCG_CALL_NO_WG, i32, env, i32, i64, i64)
 DEF_HELPER_FLAGS_4(oc, TCG_CALL_NO_WG, i32, env, i32, i64, i64)
@@ -115,5 +113,3 @@ DEF_HELPER_FLAGS_1(ptlb, TCG_CALL_NO_RWG, void, env)
 DEF_HELPER_2(lra, i64, env, i64)
 DEF_HELPER_FLAGS_3(stura, TCG_CALL_NO_WG, void, env, i64, i64)
 #endif
-
-#include "exec/def-helper.h"
diff --git a/target-s390x/int_helper.c b/target-s390x/int_helper.c
index 6a929ca1f3..cb8dd98542 100644
--- a/target-s390x/int_helper.c
+++ b/target-s390x/int_helper.c
@@ -20,7 +20,7 @@
 
 #include "cpu.h"
 #include "qemu/host-utils.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 
 /* #define DEBUG_HELPER */
 #ifdef DEBUG_HELPER
diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c
index 56179afece..7a07f9d753 100644
--- a/target-s390x/kvm.c
+++ b/target-s390x/kvm.c
@@ -36,6 +36,7 @@
 #include "sysemu/device_tree.h"
 #include "qapi/qmp/qjson.h"
 #include "monitor/monitor.h"
+#include "exec/gdbstub.h"
 #include "trace.h"
 
 /* #define DEBUG_KVM */
@@ -86,6 +87,14 @@
 #define ICPT_CPU_STOP                   0x28
 #define ICPT_IO                         0x40
 
+static CPUWatchpoint hw_watchpoint;
+/*
+ * We don't use a list because this structure is also used to transmit the
+ * hardware breakpoints to the kernel.
+ */
+static struct kvm_hw_breakpoint *hw_breakpoints;
+static int nb_hw_breakpoints;
+
 const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
     KVM_CAP_LAST_INFO
 };
@@ -320,12 +329,16 @@ static void *legacy_s390_alloc(size_t size)
     return mem == MAP_FAILED ? NULL : mem;
 }
 
+/* DIAG 501 is used for sw breakpoints */
+static const uint8_t diag_501[] = {0x83, 0x24, 0x05, 0x01};
+
 int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
 {
-    static const uint8_t diag_501[] = {0x83, 0x24, 0x05, 0x01};
 
-    if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 4, 0) ||
-        cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)diag_501, 4, 1)) {
+    if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn,
+                            sizeof(diag_501), 0) ||
+        cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)diag_501,
+                            sizeof(diag_501), 1)) {
         return -EINVAL;
     }
     return 0;
@@ -333,38 +346,140 @@ int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
 
 int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
 {
-    uint8_t t[4];
-    static const uint8_t diag_501[] = {0x83, 0x24, 0x05, 0x01};
+    uint8_t t[sizeof(diag_501)];
 
-    if (cpu_memory_rw_debug(cs, bp->pc, t, 4, 0)) {
+    if (cpu_memory_rw_debug(cs, bp->pc, t, sizeof(diag_501), 0)) {
         return -EINVAL;
-    } else if (memcmp(t, diag_501, 4)) {
+    } else if (memcmp(t, diag_501, sizeof(diag_501))) {
         return -EINVAL;
-    } else if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 1, 1)) {
+    } else if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn,
+                                   sizeof(diag_501), 1)) {
         return -EINVAL;
     }
 
     return 0;
 }
 
+static struct kvm_hw_breakpoint *find_hw_breakpoint(target_ulong addr,
+                                                    int len, int type)
+{
+    int n;
+
+    for (n = 0; n < nb_hw_breakpoints; n++) {
+        if (hw_breakpoints[n].addr == addr && hw_breakpoints[n].type == type &&
+            (hw_breakpoints[n].len == len || len == -1)) {
+            return &hw_breakpoints[n];
+        }
+    }
+
+    return NULL;
+}
+
+static int insert_hw_breakpoint(target_ulong addr, int len, int type)
+{
+    int size;
+
+    if (find_hw_breakpoint(addr, len, type)) {
+        return -EEXIST;
+    }
+
+    size = (nb_hw_breakpoints + 1) * sizeof(struct kvm_hw_breakpoint);
+
+    if (!hw_breakpoints) {
+        nb_hw_breakpoints = 0;
+        hw_breakpoints = (struct kvm_hw_breakpoint *)g_try_malloc(size);
+    } else {
+        hw_breakpoints =
+            (struct kvm_hw_breakpoint *)g_try_realloc(hw_breakpoints, size);
+    }
+
+    if (!hw_breakpoints) {
+        nb_hw_breakpoints = 0;
+        return -ENOMEM;
+    }
+
+    hw_breakpoints[nb_hw_breakpoints].addr = addr;
+    hw_breakpoints[nb_hw_breakpoints].len = len;
+    hw_breakpoints[nb_hw_breakpoints].type = type;
+
+    nb_hw_breakpoints++;
+
+    return 0;
+}
+
 int kvm_arch_insert_hw_breakpoint(target_ulong addr,
                                   target_ulong len, int type)
 {
-    return -ENOSYS;
+    switch (type) {
+    case GDB_BREAKPOINT_HW:
+        type = KVM_HW_BP;
+        break;
+    case GDB_WATCHPOINT_WRITE:
+        if (len < 1) {
+            return -EINVAL;
+        }
+        type = KVM_HW_WP_WRITE;
+        break;
+    default:
+        return -ENOSYS;
+    }
+    return insert_hw_breakpoint(addr, len, type);
 }
 
 int kvm_arch_remove_hw_breakpoint(target_ulong addr,
                                   target_ulong len, int type)
 {
-    return -ENOSYS;
+    int size;
+    struct kvm_hw_breakpoint *bp = find_hw_breakpoint(addr, len, type);
+
+    if (bp == NULL) {
+        return -ENOENT;
+    }
+
+    nb_hw_breakpoints--;
+    if (nb_hw_breakpoints > 0) {
+        /*
+         * In order to trim the array, move the last element to the position to
+         * be removed - if necessary.
+         */
+        if (bp != &hw_breakpoints[nb_hw_breakpoints]) {
+            *bp = hw_breakpoints[nb_hw_breakpoints];
+        }
+        size = nb_hw_breakpoints * sizeof(struct kvm_hw_breakpoint);
+        hw_breakpoints =
+             (struct kvm_hw_breakpoint *)g_realloc(hw_breakpoints, size);
+    } else {
+        g_free(hw_breakpoints);
+        hw_breakpoints = NULL;
+    }
+
+    return 0;
 }
 
 void kvm_arch_remove_all_hw_breakpoints(void)
 {
+    nb_hw_breakpoints = 0;
+    g_free(hw_breakpoints);
+    hw_breakpoints = NULL;
 }
 
 void kvm_arch_update_guest_debug(CPUState *cpu, struct kvm_guest_debug *dbg)
 {
+    int i;
+
+    if (nb_hw_breakpoints > 0) {
+        dbg->arch.nr_hw_bp = nb_hw_breakpoints;
+        dbg->arch.hw_bp = hw_breakpoints;
+
+        for (i = 0; i < nb_hw_breakpoints; ++i) {
+            hw_breakpoints[i].phys_addr = s390_cpu_get_phys_addr_debug(cpu,
+                                                       hw_breakpoints[i].addr);
+        }
+        dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_HW_BP;
+    } else {
+        dbg->arch.nr_hw_bp = 0;
+        dbg->arch.hw_bp = NULL;
+    }
 }
 
 void kvm_arch_pre_run(CPUState *cpu, struct kvm_run *run)
@@ -579,6 +694,22 @@ static void kvm_handle_diag_308(S390CPU *cpu, struct kvm_run *run)
     handle_diag_308(&cpu->env, r1, r3);
 }
 
+static int handle_sw_breakpoint(S390CPU *cpu, struct kvm_run *run)
+{
+    CPUS390XState *env = &cpu->env;
+    unsigned long pc;
+
+    cpu_synchronize_state(CPU(cpu));
+
+    pc = env->psw.addr - 4;
+    if (kvm_find_sw_breakpoint(CPU(cpu), pc)) {
+        env->psw.addr = pc;
+        return EXCP_DEBUG;
+    }
+
+    return -ENOENT;
+}
+
 #define DIAG_KVM_CODE_MASK 0x000000000000ffff
 
 static int handle_diag(S390CPU *cpu, struct kvm_run *run, uint32_t ipb)
@@ -599,7 +730,7 @@ static int handle_diag(S390CPU *cpu, struct kvm_run *run, uint32_t ipb)
         r = handle_hypercall(cpu, run);
         break;
     case DIAG_KVM_BREAKPOINT:
-        sleep(10);
+        r = handle_sw_breakpoint(cpu, run);
         break;
     default:
         DPRINTF("KVM: unknown DIAG: 0x%x\n", func_code);
@@ -701,7 +832,7 @@ out:
     return 0;
 }
 
-static void handle_instruction(S390CPU *cpu, struct kvm_run *run)
+static int handle_instruction(S390CPU *cpu, struct kvm_run *run)
 {
     unsigned int ipa0 = (run->s390_sieic.ipa & 0xff00);
     uint8_t ipa1 = run->s390_sieic.ipa & 0x00ff;
@@ -728,8 +859,11 @@ static void handle_instruction(S390CPU *cpu, struct kvm_run *run)
     }
 
     if (r < 0) {
+        r = 0;
         enter_pgmcheck(cpu, 0x0001);
     }
+
+    return r;
 }
 
 static bool is_special_wait_psw(CPUState *cs)
@@ -749,7 +883,7 @@ static int handle_intercept(S390CPU *cpu)
             (long)cs->kvm_run->psw_addr);
     switch (icpt_code) {
         case ICPT_INSTRUCTION:
-            handle_instruction(cpu, run);
+            r = handle_instruction(cpu, run);
             break;
         case ICPT_WAITPSW:
             /* disabled wait, since enabled wait is handled in kernel */
@@ -830,7 +964,36 @@ static int handle_tsch(S390CPU *cpu)
 
 static int kvm_arch_handle_debug_exit(S390CPU *cpu)
 {
-    return -ENOSYS;
+    CPUState *cs = CPU(cpu);
+    struct kvm_run *run = cs->kvm_run;
+
+    int ret = 0;
+    struct kvm_debug_exit_arch *arch_info = &run->debug.arch;
+
+    switch (arch_info->type) {
+    case KVM_HW_WP_WRITE:
+        if (find_hw_breakpoint(arch_info->addr, -1, arch_info->type)) {
+            cs->watchpoint_hit = &hw_watchpoint;
+            hw_watchpoint.vaddr = arch_info->addr;
+            hw_watchpoint.flags = BP_MEM_WRITE;
+            ret = EXCP_DEBUG;
+        }
+        break;
+    case KVM_HW_BP:
+        if (find_hw_breakpoint(arch_info->addr, -1, arch_info->type)) {
+            ret = EXCP_DEBUG;
+        }
+        break;
+    case KVM_SINGLESTEP:
+        if (cs->singlestep_enabled) {
+            ret = EXCP_DEBUG;
+        }
+        break;
+    default:
+        ret = -ENOSYS;
+    }
+
+    return ret;
 }
 
 int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
@@ -911,6 +1074,16 @@ void kvm_s390_enable_css_support(S390CPU *cpu)
 
 void kvm_arch_init_irq_routing(KVMState *s)
 {
+    /*
+     * Note that while irqchip capabilities generally imply that cpustates
+     * are handled in-kernel, it is not true for s390 (yet); therefore, we
+     * have to override the common code kvm_halt_in_kernel_allowed setting.
+     */
+    if (kvm_check_extension(s, KVM_CAP_IRQ_ROUTING)) {
+        kvm_irqfds_allowed = true;
+        kvm_gsi_routing_allowed = true;
+        kvm_halt_in_kernel_allowed = false;
+    }
 }
 
 int kvm_s390_assign_subch_ioeventfd(EventNotifier *notifier, uint32_t sch,
diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c
index d8ca3007f8..5a29841d71 100644
--- a/target-s390x/mem_helper.c
+++ b/target-s390x/mem_helper.c
@@ -19,7 +19,7 @@
  */
 
 #include "cpu.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 
 /*****************************************************************************/
 /* Softmmu support */
diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c
index cdbbb79314..44c08f370d 100644
--- a/target-s390x/misc_helper.c
+++ b/target-s390x/misc_helper.c
@@ -21,7 +21,7 @@
 #include "cpu.h"
 #include "exec/memory.h"
 #include "qemu/host-utils.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 #include <string.h>
 #include "sysemu/kvm.h"
 #include "qemu/timer.h"
diff --git a/target-s390x/translate.c b/target-s390x/translate.c
index 81b7e330ab..cf65f01f60 100644
--- a/target-s390x/translate.c
+++ b/target-s390x/translate.c
@@ -38,9 +38,8 @@
 static TCGv_ptr cpu_env;
 
 #include "exec/gen-icount.h"
-#include "helper.h"
-#define GEN_HELPER 1
-#include "helper.h"
+#include "exec/helper-proto.h"
+#include "exec/helper-gen.h"
 
 
 /* Information that (most) every instruction needs to manipulate.  */
diff --git a/target-sh4/helper.h b/target-sh4/helper.h
index 7162448497..3b5c436ab4 100644
--- a/target-sh4/helper.h
+++ b/target-sh4/helper.h
@@ -1,5 +1,3 @@
-#include "exec/def-helper.h"
-
 DEF_HELPER_1(ldtlb, void, env)
 DEF_HELPER_1(raise_illegal_instruction, noreturn, env)
 DEF_HELPER_1(raise_slot_illegal_instruction, noreturn, env)
@@ -46,5 +44,3 @@ DEF_HELPER_2(ftrc_FT, i32, env, f32)
 DEF_HELPER_2(ftrc_DT, i32, env, f64)
 DEF_HELPER_3(fipr, void, env, i32, i32)
 DEF_HELPER_2(ftrv, void, env, i32)
-
-#include "exec/def-helper.h"
diff --git a/target-sh4/op_helper.c b/target-sh4/op_helper.c
index 720a97b1d1..39e1e7cbef 100644
--- a/target-sh4/op_helper.c
+++ b/target-sh4/op_helper.c
@@ -19,7 +19,7 @@
 #include <assert.h>
 #include <stdlib.h>
 #include "cpu.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 
 #ifndef CONFIG_USER_ONLY
 #include "exec/softmmu_exec.h"
diff --git a/target-sh4/translate.c b/target-sh4/translate.c
index 2360609a0a..169c87fc1b 100644
--- a/target-sh4/translate.c
+++ b/target-sh4/translate.c
@@ -24,9 +24,8 @@
 #include "disas/disas.h"
 #include "tcg-op.h"
 
-#include "helper.h"
-#define GEN_HELPER 1
-#include "helper.h"
+#include "exec/helper-proto.h"
+#include "exec/helper-gen.h"
 
 typedef struct DisasContext {
     struct TranslationBlock *tb;
diff --git a/target-sparc/cc_helper.c b/target-sparc/cc_helper.c
index 63bab077d6..35dab73216 100644
--- a/target-sparc/cc_helper.c
+++ b/target-sparc/cc_helper.c
@@ -18,7 +18,7 @@
  */
 
 #include "cpu.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 
 static uint32_t compute_all_flags(CPUSPARCState *env)
 {
diff --git a/target-sparc/fop_helper.c b/target-sparc/fop_helper.c
index f4b62a5ba2..ee4592ef2b 100644
--- a/target-sparc/fop_helper.c
+++ b/target-sparc/fop_helper.c
@@ -18,7 +18,7 @@
  */
 
 #include "cpu.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 
 #define QT0 (env->qt0)
 #define QT1 (env->qt1)
diff --git a/target-sparc/helper.c b/target-sparc/helper.c
index ae7740bca1..4850c7cec7 100644
--- a/target-sparc/helper.c
+++ b/target-sparc/helper.c
@@ -19,7 +19,7 @@
 
 #include "cpu.h"
 #include "qemu/host-utils.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 #include "sysemu/sysemu.h"
 
 void helper_raise_exception(CPUSPARCState *env, int tt)
diff --git a/target-sparc/helper.h b/target-sparc/helper.h
index cd8d3fa9f4..1ad23e8dbc 100644
--- a/target-sparc/helper.h
+++ b/target-sparc/helper.h
@@ -1,5 +1,3 @@
-#include "exec/def-helper.h"
-
 #ifndef TARGET_SPARC64
 DEF_HELPER_1(rett, void, env)
 DEF_HELPER_2(wrpsr, void, env, tl)
@@ -175,5 +173,3 @@ VIS_CMPHELPER(cmpne)
 #undef VIS_CMPHELPER
 DEF_HELPER_1(compute_psr, void, env)
 DEF_HELPER_1(compute_C_icc, i32, env)
-
-#include "exec/def-helper.h"
diff --git a/target-sparc/int64_helper.c b/target-sparc/int64_helper.c
index bf242323a4..b02d22b199 100644
--- a/target-sparc/int64_helper.c
+++ b/target-sparc/int64_helper.c
@@ -18,7 +18,7 @@
  */
 
 #include "cpu.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 #include "trace.h"
 
 #define DEBUG_PCALL
diff --git a/target-sparc/ldst_helper.c b/target-sparc/ldst_helper.c
index ec14802573..b6b9866b93 100644
--- a/target-sparc/ldst_helper.c
+++ b/target-sparc/ldst_helper.c
@@ -18,7 +18,7 @@
  */
 
 #include "cpu.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 
 //#define DEBUG_MMU
 //#define DEBUG_MXCC
diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index 2de1c4a58d..652a181763 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -26,11 +26,10 @@
 
 #include "cpu.h"
 #include "disas/disas.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 #include "tcg-op.h"
 
-#define GEN_HELPER 1
-#include "helper.h"
+#include "exec/helper-gen.h"
 
 #define DEBUG_DISAS
 
diff --git a/target-sparc/vis_helper.c b/target-sparc/vis_helper.c
index 9d2edb09bd..383cc8bdff 100644
--- a/target-sparc/vis_helper.c
+++ b/target-sparc/vis_helper.c
@@ -18,7 +18,7 @@
  */
 
 #include "cpu.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 
 /* This function uses non-native bit order */
 #define GET_FIELD(X, FROM, TO)                                  \
diff --git a/target-sparc/win_helper.c b/target-sparc/win_helper.c
index 3e82eb71d6..f01ae08f6c 100644
--- a/target-sparc/win_helper.c
+++ b/target-sparc/win_helper.c
@@ -18,7 +18,7 @@
  */
 
 #include "cpu.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 #include "trace.h"
 
 static inline void memcpy32(target_ulong *dst, const target_ulong *src)
diff --git a/target-unicore32/helper.c b/target-unicore32/helper.c
index 169c85cb4d..e5ebbf4b18 100644
--- a/target-unicore32/helper.c
+++ b/target-unicore32/helper.c
@@ -11,7 +11,7 @@
 
 #include "cpu.h"
 #include "exec/gdbstub.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 #include "qemu/host-utils.h"
 #ifndef CONFIG_USER_ONLY
 #include "ui/console.h"
diff --git a/target-unicore32/helper.h b/target-unicore32/helper.h
index e85ce6c201..941813749d 100644
--- a/target-unicore32/helper.h
+++ b/target-unicore32/helper.h
@@ -6,7 +6,6 @@
  * published by the Free Software Foundation, or (at your option) any
  * later version. See the COPYING file in the top-level directory.
  */
-#include "exec/def-helper.h"
 
 #ifndef CONFIG_USER_ONLY
 DEF_HELPER_4(cp0_set, void, env, i32, i32, i32)
@@ -64,5 +63,3 @@ DEF_HELPER_2(ucf64_si2df, f64, f32, env)
 
 DEF_HELPER_2(ucf64_sf2si, f32, f32, env)
 DEF_HELPER_2(ucf64_df2si, f32, f64, env)
-
-#include "exec/def-helper.h"
diff --git a/target-unicore32/op_helper.c b/target-unicore32/op_helper.c
index 4c6950d506..4f96ed350b 100644
--- a/target-unicore32/op_helper.c
+++ b/target-unicore32/op_helper.c
@@ -9,7 +9,7 @@
  * later version. See the COPYING file in the top-level directory.
  */
 #include "cpu.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 
 #define SIGNBIT (uint32_t)0x80000000
 #define SIGNBIT64 ((uint64_t)1 << 63)
diff --git a/target-unicore32/translate.c b/target-unicore32/translate.c
index c2402cf942..3cccafe5ad 100644
--- a/target-unicore32/translate.c
+++ b/target-unicore32/translate.c
@@ -19,9 +19,8 @@
 #include "tcg-op.h"
 #include "qemu/log.h"
 
-#include "helper.h"
-#define GEN_HELPER 1
-#include "helper.h"
+#include "exec/helper-proto.h"
+#include "exec/helper-gen.h"
 
 /* internal defines */
 typedef struct DisasContext {
diff --git a/target-unicore32/ucf64_helper.c b/target-unicore32/ucf64_helper.c
index 34fa2a5b40..0c7ea2693c 100644
--- a/target-unicore32/ucf64_helper.c
+++ b/target-unicore32/ucf64_helper.c
@@ -9,7 +9,7 @@
  * See the COPYING file in the top-level directory.
  */
 #include "cpu.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 
 /*
  * The convention used for UniCore-F64 instructions:
diff --git a/target-xtensa/helper.h b/target-xtensa/helper.h
index 322b04cd0a..ed3af0b737 100644
--- a/target-xtensa/helper.h
+++ b/target-xtensa/helper.h
@@ -1,5 +1,3 @@
-#include "exec/def-helper.h"
-
 DEF_HELPER_2(exception, noreturn, env, i32)
 DEF_HELPER_3(exception_cause, noreturn, env, i32, i32)
 DEF_HELPER_4(exception_cause_vaddr, noreturn, env, i32, i32, i32)
@@ -58,5 +56,3 @@ DEF_HELPER_4(olt_s, void, env, i32, f32, f32)
 DEF_HELPER_4(ult_s, void, env, i32, f32, f32)
 DEF_HELPER_4(ole_s, void, env, i32, f32, f32)
 DEF_HELPER_4(ule_s, void, env, i32, f32, f32)
-
-#include "exec/def-helper.h"
diff --git a/target-xtensa/op_helper.c b/target-xtensa/op_helper.c
index b531019488..01edab4082 100644
--- a/target-xtensa/op_helper.c
+++ b/target-xtensa/op_helper.c
@@ -26,7 +26,7 @@
  */
 
 #include "cpu.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 #include "qemu/host-utils.h"
 #include "exec/softmmu_exec.h"
 #include "exec/address-spaces.h"
diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
index 764cee96f3..57e56bd34d 100644
--- a/target-xtensa/translate.c
+++ b/target-xtensa/translate.c
@@ -37,9 +37,8 @@
 #include "qemu/log.h"
 #include "sysemu/sysemu.h"
 
-#include "helper.h"
-#define GEN_HELPER 1
-#include "helper.h"
+#include "exec/helper-proto.h"
+#include "exec/helper-gen.h"
 
 typedef struct DisasContext {
     const XtensaConfig *config;
@@ -419,7 +418,7 @@ static void gen_jump(DisasContext *dc, TCGv dest)
 static void gen_jumpi(DisasContext *dc, uint32_t dest, int slot)
 {
     TCGv_i32 tmp = tcg_const_i32(dest);
-    if (((dc->pc ^ dest) & TARGET_PAGE_MASK) != 0) {
+    if (((dc->tb->pc ^ dest) & TARGET_PAGE_MASK) != 0) {
         slot = -1;
     }
     gen_jump_slot(dc, tmp, slot);
@@ -447,7 +446,7 @@ static void gen_callw(DisasContext *dc, int callinc, TCGv_i32 dest)
 static void gen_callwi(DisasContext *dc, int callinc, uint32_t dest, int slot)
 {
     TCGv_i32 tmp = tcg_const_i32(dest);
-    if (((dc->pc ^ dest) & TARGET_PAGE_MASK) != 0) {
+    if (((dc->tb->pc ^ dest) & TARGET_PAGE_MASK) != 0) {
         slot = -1;
     }
     gen_callw_slot(dc, callinc, tmp, slot);
diff --git a/target-xtensa/xtensa-semi.c b/target-xtensa/xtensa-semi.c
index 424253d1f3..16e9d8c7b8 100644
--- a/target-xtensa/xtensa-semi.c
+++ b/target-xtensa/xtensa-semi.c
@@ -30,7 +30,7 @@
 #include <string.h>
 #include <stddef.h>
 #include "cpu.h"
-#include "helper.h"
+#include "exec/helper-proto.h"
 #include "qemu/log.h"
 
 enum {
diff --git a/tcg-runtime.c b/tcg-runtime.c
index 4b66e51ce7..9daba6945e 100644
--- a/tcg-runtime.c
+++ b/tcg-runtime.c
@@ -23,75 +23,85 @@
  */
 #include <stdint.h>
 #include "qemu/host-utils.h"
-#include "tcg/tcg-runtime.h"
+
+/* This file is compiled once, and thus we can't include the standard
+   "exec/helper-proto.h", which has includes that are target specific.  */
+
+#include "exec/helper-head.h"
+
+#define DEF_HELPER_FLAGS_2(name, flags, ret, t1, t2) \
+  dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2));
+
+#include "tcg-runtime.h"
+
 
 /* 32-bit helpers */
 
-int32_t tcg_helper_div_i32(int32_t arg1, int32_t arg2)
+int32_t HELPER(div_i32)(int32_t arg1, int32_t arg2)
 {
     return arg1 / arg2;
 }
 
-int32_t tcg_helper_rem_i32(int32_t arg1, int32_t arg2)
+int32_t HELPER(rem_i32)(int32_t arg1, int32_t arg2)
 {
     return arg1 % arg2;
 }
 
-uint32_t tcg_helper_divu_i32(uint32_t arg1, uint32_t arg2)
+uint32_t HELPER(divu_i32)(uint32_t arg1, uint32_t arg2)
 {
     return arg1 / arg2;
 }
 
-uint32_t tcg_helper_remu_i32(uint32_t arg1, uint32_t arg2)
+uint32_t HELPER(remu_i32)(uint32_t arg1, uint32_t arg2)
 {
     return arg1 % arg2;
 }
 
 /* 64-bit helpers */
 
-int64_t tcg_helper_shl_i64(int64_t arg1, int64_t arg2)
+uint64_t HELPER(shl_i64)(uint64_t arg1, uint64_t arg2)
 {
     return arg1 << arg2;
 }
 
-int64_t tcg_helper_shr_i64(int64_t arg1, int64_t arg2)
+uint64_t HELPER(shr_i64)(uint64_t arg1, uint64_t arg2)
 {
-    return (uint64_t)arg1 >> arg2;
+    return arg1 >> arg2;
 }
 
-int64_t tcg_helper_sar_i64(int64_t arg1, int64_t arg2)
+int64_t HELPER(sar_i64)(int64_t arg1, int64_t arg2)
 {
     return arg1 >> arg2;
 }
 
-int64_t tcg_helper_div_i64(int64_t arg1, int64_t arg2)
+int64_t HELPER(div_i64)(int64_t arg1, int64_t arg2)
 {
     return arg1 / arg2;
 }
 
-int64_t tcg_helper_rem_i64(int64_t arg1, int64_t arg2)
+int64_t HELPER(rem_i64)(int64_t arg1, int64_t arg2)
 {
     return arg1 % arg2;
 }
 
-uint64_t tcg_helper_divu_i64(uint64_t arg1, uint64_t arg2)
+uint64_t HELPER(divu_i64)(uint64_t arg1, uint64_t arg2)
 {
     return arg1 / arg2;
 }
 
-uint64_t tcg_helper_remu_i64(uint64_t arg1, uint64_t arg2)
+uint64_t HELPER(remu_i64)(uint64_t arg1, uint64_t arg2)
 {
     return arg1 % arg2;
 }
 
-uint64_t tcg_helper_muluh_i64(uint64_t arg1, uint64_t arg2)
+uint64_t HELPER(muluh_i64)(uint64_t arg1, uint64_t arg2)
 {
     uint64_t l, h;
     mulu64(&l, &h, arg1, arg2);
     return h;
 }
 
-int64_t tcg_helper_mulsh_i64(int64_t arg1, int64_t arg2)
+int64_t HELPER(mulsh_i64)(int64_t arg1, int64_t arg2)
 {
     uint64_t l, h;
     muls64(&l, &h, arg1, arg2);
diff --git a/tcg/aarch64/tcg-target.c b/tcg/aarch64/tcg-target.c
index 77bb6d97de..56dae66a3f 100644
--- a/tcg/aarch64/tcg-target.c
+++ b/tcg/aarch64/tcg-target.c
@@ -1809,24 +1809,23 @@ static void tcg_target_qemu_prologue(TCGContext *s)
 }
 
 typedef struct {
-    DebugFrameCIE cie;
-    DebugFrameFDEHeader fde;
+    DebugFrameHeader h;
     uint8_t fde_def_cfa[4];
     uint8_t fde_reg_ofs[24];
 } DebugFrame;
 
 #define ELF_HOST_MACHINE EM_AARCH64
 
-static DebugFrame debug_frame = {
-    .cie.len = sizeof(DebugFrameCIE)-4, /* length after .len member */
-    .cie.id = -1,
-    .cie.version = 1,
-    .cie.code_align = 1,
-    .cie.data_align = 0x78,             /* sleb128 -8 */
-    .cie.return_column = TCG_REG_LR,
+static const DebugFrame debug_frame = {
+    .h.cie.len = sizeof(DebugFrameCIE)-4, /* length after .len member */
+    .h.cie.id = -1,
+    .h.cie.version = 1,
+    .h.cie.code_align = 1,
+    .h.cie.data_align = 0x78,             /* sleb128 -8 */
+    .h.cie.return_column = TCG_REG_LR,
 
     /* Total FDE size does not include the "len" member.  */
-    .fde.len = sizeof(DebugFrame) - offsetof(DebugFrame, fde.cie_offset),
+    .h.fde.len = sizeof(DebugFrame) - offsetof(DebugFrame, h.fde.cie_offset),
 
     .fde_def_cfa = {
         12, TCG_REG_SP,                 /* DW_CFA_def_cfa sp, ... */
@@ -1851,8 +1850,5 @@ static DebugFrame debug_frame = {
 
 void tcg_register_jit(void *buf, size_t buf_size)
 {
-    debug_frame.fde.func_start = (intptr_t)buf;
-    debug_frame.fde.func_len = buf_size;
-
     tcg_register_jit_int(buf, buf_size, &debug_frame, sizeof(debug_frame));
 }
diff --git a/tcg/arm/tcg-target.c b/tcg/arm/tcg-target.c
index 538ca2aed0..e40301c78b 100644
--- a/tcg/arm/tcg-target.c
+++ b/tcg/arm/tcg-target.c
@@ -2077,8 +2077,7 @@ static void tcg_target_qemu_prologue(TCGContext *s)
 }
 
 typedef struct {
-    DebugFrameCIE cie;
-    DebugFrameFDEHeader fde;
+    DebugFrameHeader h;
     uint8_t fde_def_cfa[4];
     uint8_t fde_reg_ofs[18];
 } DebugFrame;
@@ -2088,16 +2087,16 @@ typedef struct {
 /* We're expecting a 2 byte uleb128 encoded value.  */
 QEMU_BUILD_BUG_ON(FRAME_SIZE >= (1 << 14));
 
-static DebugFrame debug_frame = {
-    .cie.len = sizeof(DebugFrameCIE)-4, /* length after .len member */
-    .cie.id = -1,
-    .cie.version = 1,
-    .cie.code_align = 1,
-    .cie.data_align = 0x7c,             /* sleb128 -4 */
-    .cie.return_column = 14,
+static const DebugFrame debug_frame = {
+    .h.cie.len = sizeof(DebugFrameCIE)-4, /* length after .len member */
+    .h.cie.id = -1,
+    .h.cie.version = 1,
+    .h.cie.code_align = 1,
+    .h.cie.data_align = 0x7c,             /* sleb128 -4 */
+    .h.cie.return_column = 14,
 
     /* Total FDE size does not include the "len" member.  */
-    .fde.len = sizeof(DebugFrame) - offsetof(DebugFrame, fde.cie_offset),
+    .h.fde.len = sizeof(DebugFrame) - offsetof(DebugFrame, h.fde.cie_offset),
 
     .fde_def_cfa = {
         12, 13,                         /* DW_CFA_def_cfa sp, ... */
@@ -2120,8 +2119,5 @@ static DebugFrame debug_frame = {
 
 void tcg_register_jit(void *buf, size_t buf_size)
 {
-    debug_frame.fde.func_start = (tcg_target_long) buf;
-    debug_frame.fde.func_len = buf_size;
-
     tcg_register_jit_int(buf, buf_size, &debug_frame, sizeof(debug_frame));
 }
diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c
index a373073ff8..d9102335f9 100644
--- a/tcg/i386/tcg-target.c
+++ b/tcg/i386/tcg-target.c
@@ -2341,8 +2341,7 @@ static void tcg_target_init(TCGContext *s)
 }
 
 typedef struct {
-    DebugFrameCIE cie;
-    DebugFrameFDEHeader fde;
+    DebugFrameHeader h;
     uint8_t fde_def_cfa[4];
     uint8_t fde_reg_ofs[14];
 } DebugFrame;
@@ -2354,16 +2353,16 @@ QEMU_BUILD_BUG_ON(FRAME_SIZE >= (1 << 14));
     /* Host machine without ELF. */
 #elif TCG_TARGET_REG_BITS == 64
 #define ELF_HOST_MACHINE EM_X86_64
-static DebugFrame debug_frame = {
-    .cie.len = sizeof(DebugFrameCIE)-4, /* length after .len member */
-    .cie.id = -1,
-    .cie.version = 1,
-    .cie.code_align = 1,
-    .cie.data_align = 0x78,             /* sleb128 -8 */
-    .cie.return_column = 16,
+static const DebugFrame debug_frame = {
+    .h.cie.len = sizeof(DebugFrameCIE)-4, /* length after .len member */
+    .h.cie.id = -1,
+    .h.cie.version = 1,
+    .h.cie.code_align = 1,
+    .h.cie.data_align = 0x78,             /* sleb128 -8 */
+    .h.cie.return_column = 16,
 
     /* Total FDE size does not include the "len" member.  */
-    .fde.len = sizeof(DebugFrame) - offsetof(DebugFrame, fde.cie_offset),
+    .h.fde.len = sizeof(DebugFrame) - offsetof(DebugFrame, h.fde.cie_offset),
 
     .fde_def_cfa = {
         12, 7,                          /* DW_CFA_def_cfa %rsp, ... */
@@ -2383,16 +2382,16 @@ static DebugFrame debug_frame = {
 };
 #else
 #define ELF_HOST_MACHINE EM_386
-static DebugFrame debug_frame = {
-    .cie.len = sizeof(DebugFrameCIE)-4, /* length after .len member */
-    .cie.id = -1,
-    .cie.version = 1,
-    .cie.code_align = 1,
-    .cie.data_align = 0x7c,             /* sleb128 -4 */
-    .cie.return_column = 8,
+static const DebugFrame debug_frame = {
+    .h.cie.len = sizeof(DebugFrameCIE)-4, /* length after .len member */
+    .h.cie.id = -1,
+    .h.cie.version = 1,
+    .h.cie.code_align = 1,
+    .h.cie.data_align = 0x7c,             /* sleb128 -4 */
+    .h.cie.return_column = 8,
 
     /* Total FDE size does not include the "len" member.  */
-    .fde.len = sizeof(DebugFrame) - offsetof(DebugFrame, fde.cie_offset),
+    .h.fde.len = sizeof(DebugFrame) - offsetof(DebugFrame, h.fde.cie_offset),
 
     .fde_def_cfa = {
         12, 4,                          /* DW_CFA_def_cfa %esp, ... */
@@ -2413,9 +2412,6 @@ static DebugFrame debug_frame = {
 #if defined(ELF_HOST_MACHINE)
 void tcg_register_jit(void *buf, size_t buf_size)
 {
-    debug_frame.fde.func_start = (uintptr_t)buf;
-    debug_frame.fde.func_len = buf_size;
-
     tcg_register_jit_int(buf, buf_size, &debug_frame, sizeof(debug_frame));
 }
 #endif
diff --git a/tcg/mips/tcg-target.c b/tcg/mips/tcg-target.c
index 0ae495c586..8855d5039d 100644
--- a/tcg/mips/tcg-target.c
+++ b/tcg/mips/tcg-target.c
@@ -24,14 +24,17 @@
  * THE SOFTWARE.
  */
 
-#include "tcg-be-null.h"
+#include "tcg-be-ldst.h"
 
-#if defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
-# define TCG_NEED_BSWAP 0
+#ifdef HOST_WORDS_BIGENDIAN
+# define MIPS_BE  1
 #else
-# define TCG_NEED_BSWAP 1
+# define MIPS_BE  0
 #endif
 
+#define LO_OFF    (MIPS_BE * 4)
+#define HI_OFF    (4 - LO_OFF)
+
 #ifndef NDEBUG
 static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
     "zero",
@@ -64,13 +67,17 @@ static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
     "k1",
     "gp",
     "sp",
-    "fp",
+    "s8",
     "ra",
 };
 #endif
 
+#define TCG_TMP0  TCG_REG_AT
+#define TCG_TMP1  TCG_REG_T9
+
 /* check if we really need so many registers :P */
 static const TCGReg tcg_target_reg_alloc_order[] = {
+    /* Call saved registers.  */
     TCG_REG_S0,
     TCG_REG_S1,
     TCG_REG_S2,
@@ -79,6 +86,10 @@ static const TCGReg tcg_target_reg_alloc_order[] = {
     TCG_REG_S5,
     TCG_REG_S6,
     TCG_REG_S7,
+    TCG_REG_S8,
+
+    /* Call clobbered registers.  */
+    TCG_REG_T0,
     TCG_REG_T1,
     TCG_REG_T2,
     TCG_REG_T3,
@@ -88,12 +99,14 @@ static const TCGReg tcg_target_reg_alloc_order[] = {
     TCG_REG_T7,
     TCG_REG_T8,
     TCG_REG_T9,
-    TCG_REG_A0,
-    TCG_REG_A1,
-    TCG_REG_A2,
-    TCG_REG_A3,
+    TCG_REG_V1,
     TCG_REG_V0,
-    TCG_REG_V1
+
+    /* Argument registers, opposite order of allocation.  */
+    TCG_REG_A3,
+    TCG_REG_A2,
+    TCG_REG_A1,
+    TCG_REG_A0,
 };
 
 static const TCGReg tcg_target_call_iarg_regs[4] = {
@@ -142,6 +155,17 @@ static void patch_reloc(tcg_insn_unit *code_ptr, int type,
     reloc_pc16(code_ptr, (tcg_insn_unit *)value);
 }
 
+#define TCG_CT_CONST_ZERO 0x100
+#define TCG_CT_CONST_U16  0x200    /* Unsigned 16-bit: 0 - 0xffff.  */
+#define TCG_CT_CONST_S16  0x400    /* Signed 16-bit: -32768 - 32767 */
+#define TCG_CT_CONST_P2M1 0x800    /* Power of 2 minus 1.  */
+#define TCG_CT_CONST_N16  0x1000   /* "Negatable" 16-bit: -32767 - 32767 */
+
+static inline bool is_p2m1(tcg_target_long val)
+{
+    return val && ((val + 1) & val) == 0;
+}
+
 /* parse target specific constraints */
 static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
 {
@@ -161,11 +185,11 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
     case 'l': /* qemu_ld input arg constraint */
         ct->ct |= TCG_CT_REG;
         tcg_regset_set(ct->u.regs, 0xffffffff);
-#if defined(CONFIG_SOFTMMU)
         tcg_regset_reset_reg(ct->u.regs, TCG_REG_A0);
-# if (TARGET_LONG_BITS == 64)
-        tcg_regset_reset_reg(ct->u.regs, TCG_REG_A2);
-# endif
+#if defined(CONFIG_SOFTMMU)
+        if (TARGET_LONG_BITS == 64) {
+            tcg_regset_reset_reg(ct->u.regs, TCG_REG_A2);
+        }
 #endif
         break;
     case 'S': /* qemu_st constraint */
@@ -173,13 +197,12 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
         tcg_regset_set(ct->u.regs, 0xffffffff);
         tcg_regset_reset_reg(ct->u.regs, TCG_REG_A0);
 #if defined(CONFIG_SOFTMMU)
-# if (TARGET_LONG_BITS == 32)
-        tcg_regset_reset_reg(ct->u.regs, TCG_REG_A1);
-# endif
-        tcg_regset_reset_reg(ct->u.regs, TCG_REG_A2);
-# if TARGET_LONG_BITS == 64
-        tcg_regset_reset_reg(ct->u.regs, TCG_REG_A3);
-# endif
+        if (TARGET_LONG_BITS == 32) {
+            tcg_regset_reset_reg(ct->u.regs, TCG_REG_A1);
+        } else {
+            tcg_regset_reset_reg(ct->u.regs, TCG_REG_A2);
+            tcg_regset_reset_reg(ct->u.regs, TCG_REG_A3);
+        }
 #endif
         break;
     case 'I':
@@ -188,6 +211,12 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
     case 'J':
         ct->ct |= TCG_CT_CONST_S16;
         break;
+    case 'K':
+        ct->ct |= TCG_CT_CONST_P2M1;
+        break;
+    case 'N':
+        ct->ct |= TCG_CT_CONST_N16;
+        break;
     case 'Z':
         /* We are cheating a bit here, using the fact that the register
            ZERO is also the register number 0. Hence there is no need
@@ -208,20 +237,27 @@ static inline int tcg_target_const_match(tcg_target_long val, TCGType type,
 {
     int ct;
     ct = arg_ct->ct;
-    if (ct & TCG_CT_CONST)
+    if (ct & TCG_CT_CONST) {
+        return 1;
+    } else if ((ct & TCG_CT_CONST_ZERO) && val == 0) {
         return 1;
-    else if ((ct & TCG_CT_CONST_ZERO) && val == 0)
+    } else if ((ct & TCG_CT_CONST_U16) && val == (uint16_t)val) {
         return 1;
-    else if ((ct & TCG_CT_CONST_U16) && val == (uint16_t)val)
+    } else if ((ct & TCG_CT_CONST_S16) && val == (int16_t)val) {
         return 1;
-    else if ((ct & TCG_CT_CONST_S16) && val == (int16_t)val)
+    } else if ((ct & TCG_CT_CONST_N16) && val >= -32767 && val <= 32767) {
         return 1;
-    else
-        return 0;
+    } else if ((ct & TCG_CT_CONST_P2M1)
+               && use_mips32r2_instructions && is_p2m1(val)) {
+        return 1;
+    }
+    return 0;
 }
 
 /* instruction opcodes */
-enum {
+typedef enum {
+    OPC_J        = 0x02 << 26,
+    OPC_JAL      = 0x03 << 26,
     OPC_BEQ      = 0x04 << 26,
     OPC_BNE      = 0x05 << 26,
     OPC_BLEZ     = 0x06 << 26,
@@ -279,16 +315,17 @@ enum {
     OPC_MUL      = OPC_SPECIAL2 | 0x002,
 
     OPC_SPECIAL3 = 0x1f << 26,
+    OPC_EXT      = OPC_SPECIAL3 | 0x000,
     OPC_INS      = OPC_SPECIAL3 | 0x004,
     OPC_WSBH     = OPC_SPECIAL3 | 0x0a0,
     OPC_SEB      = OPC_SPECIAL3 | 0x420,
     OPC_SEH      = OPC_SPECIAL3 | 0x620,
-};
+} MIPSInsn;
 
 /*
  * Type reg
  */
-static inline void tcg_out_opc_reg(TCGContext *s, int opc,
+static inline void tcg_out_opc_reg(TCGContext *s, MIPSInsn opc,
                                    TCGReg rd, TCGReg rs, TCGReg rt)
 {
     int32_t inst;
@@ -303,7 +340,7 @@ static inline void tcg_out_opc_reg(TCGContext *s, int opc,
 /*
  * Type immediate
  */
-static inline void tcg_out_opc_imm(TCGContext *s, int opc,
+static inline void tcg_out_opc_imm(TCGContext *s, MIPSInsn opc,
                                    TCGReg rt, TCGReg rs, TCGArg imm)
 {
     int32_t inst;
@@ -316,9 +353,25 @@ static inline void tcg_out_opc_imm(TCGContext *s, int opc,
 }
 
 /*
+ * Type bitfield
+ */
+static inline void tcg_out_opc_bf(TCGContext *s, MIPSInsn opc, TCGReg rt,
+                                  TCGReg rs, int msb, int lsb)
+{
+    int32_t inst;
+
+    inst = opc;
+    inst |= (rs & 0x1F) << 21;
+    inst |= (rt & 0x1F) << 16;
+    inst |= (msb & 0x1F) << 11;
+    inst |= (lsb & 0x1F) << 6;
+    tcg_out32(s, inst);
+}
+
+/*
  * Type branch
  */
-static inline void tcg_out_opc_br(TCGContext *s, int opc,
+static inline void tcg_out_opc_br(TCGContext *s, MIPSInsn opc,
                                   TCGReg rt, TCGReg rs)
 {
     /* We pay attention here to not modify the branch target by reading
@@ -332,7 +385,7 @@ static inline void tcg_out_opc_br(TCGContext *s, int opc,
 /*
  * Type sa
  */
-static inline void tcg_out_opc_sa(TCGContext *s, int opc,
+static inline void tcg_out_opc_sa(TCGContext *s, MIPSInsn opc,
                                   TCGReg rd, TCGReg rt, TCGArg sa)
 {
     int32_t inst;
@@ -345,6 +398,29 @@ static inline void tcg_out_opc_sa(TCGContext *s, int opc,
 
 }
 
+/*
+ * Type jump.
+ * Returns true if the branch was in range and the insn was emitted.
+ */
+static bool tcg_out_opc_jmp(TCGContext *s, MIPSInsn opc, void *target)
+{
+    uintptr_t dest = (uintptr_t)target;
+    uintptr_t from = (uintptr_t)s->code_ptr + 4;
+    int32_t inst;
+
+    /* The pc-region branch happens within the 256MB region of
+       the delay slot (thus the +4).  */
+    if ((from ^ dest) & -(1 << 28)) {
+        return false;
+    }
+    assert((dest & 3) == 0);
+
+    inst = opc;
+    inst |= (dest >> 2) & 0x3ffffff;
+    tcg_out32(s, inst);
+    return true;
+}
+
 static inline void tcg_out_nop(TCGContext *s)
 {
     tcg_out32(s, 0);
@@ -367,8 +443,10 @@ static inline void tcg_out_movi(TCGContext *s, TCGType type,
     } else if (arg == (uint16_t)arg) {
         tcg_out_opc_imm(s, OPC_ORI, reg, TCG_REG_ZERO, arg);
     } else {
-        tcg_out_opc_imm(s, OPC_LUI, reg, 0, arg >> 16);
-        tcg_out_opc_imm(s, OPC_ORI, reg, reg, arg & 0xffff);
+        tcg_out_opc_imm(s, OPC_LUI, reg, TCG_REG_ZERO, arg >> 16);
+        if (arg & 0xffff) {
+            tcg_out_opc_imm(s, OPC_ORI, reg, reg, arg & 0xffff);
+        }
     }
 }
 
@@ -378,14 +456,14 @@ static inline void tcg_out_bswap16(TCGContext *s, TCGReg ret, TCGReg arg)
         tcg_out_opc_reg(s, OPC_WSBH, ret, 0, arg);
     } else {
         /* ret and arg can't be register at */
-        if (ret == TCG_REG_AT || arg == TCG_REG_AT) {
+        if (ret == TCG_TMP0 || arg == TCG_TMP0) {
             tcg_abort();
         }
 
-        tcg_out_opc_sa(s, OPC_SRL, TCG_REG_AT, arg, 8);
+        tcg_out_opc_sa(s, OPC_SRL, TCG_TMP0, arg, 8);
         tcg_out_opc_sa(s, OPC_SLL, ret, arg, 8);
         tcg_out_opc_imm(s, OPC_ANDI, ret, ret, 0xff00);
-        tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT);
+        tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_TMP0);
     }
 }
 
@@ -396,14 +474,14 @@ static inline void tcg_out_bswap16s(TCGContext *s, TCGReg ret, TCGReg arg)
         tcg_out_opc_reg(s, OPC_SEH, ret, 0, ret);
     } else {
         /* ret and arg can't be register at */
-        if (ret == TCG_REG_AT || arg == TCG_REG_AT) {
+        if (ret == TCG_TMP0 || arg == TCG_TMP0) {
             tcg_abort();
         }
 
-        tcg_out_opc_sa(s, OPC_SRL, TCG_REG_AT, arg, 8);
+        tcg_out_opc_sa(s, OPC_SRL, TCG_TMP0, arg, 8);
         tcg_out_opc_sa(s, OPC_SLL, ret, arg, 24);
         tcg_out_opc_sa(s, OPC_SRA, ret, ret, 16);
-        tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT);
+        tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_TMP0);
     }
 }
 
@@ -414,22 +492,22 @@ static inline void tcg_out_bswap32(TCGContext *s, TCGReg ret, TCGReg arg)
         tcg_out_opc_sa(s, OPC_ROTR, ret, ret, 16);
     } else {
         /* ret and arg must be different and can't be register at */
-        if (ret == arg || ret == TCG_REG_AT || arg == TCG_REG_AT) {
+        if (ret == arg || ret == TCG_TMP0 || arg == TCG_TMP0) {
             tcg_abort();
         }
 
         tcg_out_opc_sa(s, OPC_SLL, ret, arg, 24);
 
-        tcg_out_opc_sa(s, OPC_SRL, TCG_REG_AT, arg, 24);
-        tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT);
+        tcg_out_opc_sa(s, OPC_SRL, TCG_TMP0, arg, 24);
+        tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_TMP0);
 
-        tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_AT, arg, 0xff00);
-        tcg_out_opc_sa(s, OPC_SLL, TCG_REG_AT, TCG_REG_AT, 8);
-        tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT);
+        tcg_out_opc_imm(s, OPC_ANDI, TCG_TMP0, arg, 0xff00);
+        tcg_out_opc_sa(s, OPC_SLL, TCG_TMP0, TCG_TMP0, 8);
+        tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_TMP0);
 
-        tcg_out_opc_sa(s, OPC_SRL, TCG_REG_AT, arg, 8);
-        tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_AT, TCG_REG_AT, 0xff00);
-        tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT);
+        tcg_out_opc_sa(s, OPC_SRL, TCG_TMP0, arg, 8);
+        tcg_out_opc_imm(s, OPC_ANDI, TCG_TMP0, TCG_TMP0, 0xff00);
+        tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_TMP0);
     }
 }
 
@@ -453,16 +531,18 @@ static inline void tcg_out_ext16s(TCGContext *s, TCGReg ret, TCGReg arg)
     }
 }
 
-static inline void tcg_out_ldst(TCGContext *s, int opc, TCGArg arg,
-                                TCGReg arg1, TCGArg arg2)
+static void tcg_out_ldst(TCGContext *s, MIPSInsn opc, TCGReg data,
+                         TCGReg addr, intptr_t ofs)
 {
-    if (arg2 == (int16_t) arg2) {
-        tcg_out_opc_imm(s, opc, arg, arg1, arg2);
-    } else {
-        tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_AT, arg2);
-        tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_AT, TCG_REG_AT, arg1);
-        tcg_out_opc_imm(s, opc, arg, TCG_REG_AT, 0);
+    int16_t lo = ofs;
+    if (ofs != lo) {
+        tcg_out_movi(s, TCG_TYPE_PTR, TCG_TMP0, ofs - lo);
+        if (addr != TCG_REG_ZERO) {
+            tcg_out_opc_reg(s, OPC_ADDU, TCG_TMP0, TCG_TMP0, addr);
+        }
+        addr = TCG_TMP0;
     }
+    tcg_out_opc_imm(s, opc, data, addr, lo);
 }
 
 static inline void tcg_out_ld(TCGContext *s, TCGType type, TCGReg arg,
@@ -482,1051 +562,1008 @@ static inline void tcg_out_addi(TCGContext *s, TCGReg reg, TCGArg val)
     if (val == (int16_t)val) {
         tcg_out_opc_imm(s, OPC_ADDIU, reg, reg, val);
     } else {
-        tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_AT, val);
-        tcg_out_opc_reg(s, OPC_ADDU, reg, reg, TCG_REG_AT);
+        tcg_out_movi(s, TCG_TYPE_PTR, TCG_TMP0, val);
+        tcg_out_opc_reg(s, OPC_ADDU, reg, reg, TCG_TMP0);
     }
 }
 
-/* Helper routines for marshalling helper function arguments into
- * the correct registers and stack.
- * arg_num is where we want to put this argument, and is updated to be ready
- * for the next call. arg is the argument itself. Note that arg_num 0..3 is
- * real registers, 4+ on stack.
- *
- * We provide routines for arguments which are: immediate, 32 bit
- * value in register, 16 and 8 bit values in register (which must be zero
- * extended before use) and 64 bit value in a lo:hi register pair.
- */
-#define DEFINE_TCG_OUT_CALL_IARG(NAME, ARGPARAM)                               \
-    static inline void NAME(TCGContext *s, int *arg_num, ARGPARAM)             \
-    {                                                                          \
-    if (*arg_num < 4) {                                                        \
-        DEFINE_TCG_OUT_CALL_IARG_GET_ARG(tcg_target_call_iarg_regs[*arg_num]); \
-    } else {                                                                   \
-        DEFINE_TCG_OUT_CALL_IARG_GET_ARG(TCG_REG_AT);                          \
-        tcg_out_st(s, TCG_TYPE_I32, TCG_REG_AT, TCG_REG_SP, 4 * (*arg_num));   \
-    }                                                                          \
-    (*arg_num)++;                                                              \
-}
-#define DEFINE_TCG_OUT_CALL_IARG_GET_ARG(A) \
-    tcg_out_opc_imm(s, OPC_ANDI, A, arg, 0xff);
-DEFINE_TCG_OUT_CALL_IARG(tcg_out_call_iarg_reg8, TCGReg arg)
-#undef DEFINE_TCG_OUT_CALL_IARG_GET_ARG
-#define DEFINE_TCG_OUT_CALL_IARG_GET_ARG(A) \
-    tcg_out_opc_imm(s, OPC_ANDI, A, arg, 0xffff);
-DEFINE_TCG_OUT_CALL_IARG(tcg_out_call_iarg_reg16, TCGReg arg)
-#undef DEFINE_TCG_OUT_CALL_IARG_GET_ARG
-#define DEFINE_TCG_OUT_CALL_IARG_GET_ARG(A) \
-    tcg_out_movi(s, TCG_TYPE_I32, A, arg);
-DEFINE_TCG_OUT_CALL_IARG(tcg_out_call_iarg_imm32, TCGArg arg)
-#undef DEFINE_TCG_OUT_CALL_IARG_GET_ARG
-
-/* We don't use the macro for this one to avoid an unnecessary reg-reg
-   move when storing to the stack. */
-static inline void tcg_out_call_iarg_reg32(TCGContext *s, int *arg_num,
-                                           TCGReg arg)
-{
-    if (*arg_num < 4) {
-        tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[*arg_num], arg);
-    } else {
-        tcg_out_st(s, TCG_TYPE_I32, arg, TCG_REG_SP, 4 * (*arg_num));
-    }
-    (*arg_num)++;
-}
-
-static inline void tcg_out_call_iarg_reg64(TCGContext *s, int *arg_num,
-                                           TCGReg arg_low, TCGReg arg_high)
-{
-    (*arg_num) = (*arg_num + 1) & ~1;
-
-#if defined(HOST_WORDS_BIGENDIAN)
-    tcg_out_call_iarg_reg32(s, arg_num, arg_high);
-    tcg_out_call_iarg_reg32(s, arg_num, arg_low);
-#else
-    tcg_out_call_iarg_reg32(s, arg_num, arg_low);
-    tcg_out_call_iarg_reg32(s, arg_num, arg_high);
-#endif
-}
+/* Bit 0 set if inversion required; bit 1 set if swapping required.  */
+#define MIPS_CMP_INV  1
+#define MIPS_CMP_SWAP 2
+
+static const uint8_t mips_cmp_map[16] = {
+    [TCG_COND_LT]  = 0,
+    [TCG_COND_LTU] = 0,
+    [TCG_COND_GE]  = MIPS_CMP_INV,
+    [TCG_COND_GEU] = MIPS_CMP_INV,
+    [TCG_COND_LE]  = MIPS_CMP_INV | MIPS_CMP_SWAP,
+    [TCG_COND_LEU] = MIPS_CMP_INV | MIPS_CMP_SWAP,
+    [TCG_COND_GT]  = MIPS_CMP_SWAP,
+    [TCG_COND_GTU] = MIPS_CMP_SWAP,
+};
 
-static void tcg_out_brcond(TCGContext *s, TCGCond cond, TCGArg arg1,
-                           TCGArg arg2, int label_index)
+static void tcg_out_setcond(TCGContext *s, TCGCond cond, TCGReg ret,
+                            TCGReg arg1, TCGReg arg2)
 {
-    TCGLabel *l = &s->labels[label_index];
+    MIPSInsn s_opc = OPC_SLTU;
+    int cmp_map;
 
     switch (cond) {
     case TCG_COND_EQ:
-        tcg_out_opc_br(s, OPC_BEQ, arg1, arg2);
+        if (arg2 != 0) {
+            tcg_out_opc_reg(s, OPC_XOR, ret, arg1, arg2);
+            arg1 = ret;
+        }
+        tcg_out_opc_imm(s, OPC_SLTIU, ret, arg1, 1);
         break;
+
     case TCG_COND_NE:
-        tcg_out_opc_br(s, OPC_BNE, arg1, arg2);
-        break;
-    case TCG_COND_LT:
-        if (arg2 == 0) {
-            tcg_out_opc_br(s, OPC_BLTZ, 0, arg1);
-        } else {
-            tcg_out_opc_reg(s, OPC_SLT, TCG_REG_AT, arg1, arg2);
-            tcg_out_opc_br(s, OPC_BNE, TCG_REG_AT, TCG_REG_ZERO);
+        if (arg2 != 0) {
+            tcg_out_opc_reg(s, OPC_XOR, ret, arg1, arg2);
+            arg1 = ret;
         }
+        tcg_out_opc_reg(s, OPC_SLTU, ret, TCG_REG_ZERO, arg1);
         break;
-    case TCG_COND_LTU:
-        tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_AT, arg1, arg2);
-        tcg_out_opc_br(s, OPC_BNE, TCG_REG_AT, TCG_REG_ZERO);
-        break;
+
+    case TCG_COND_LT:
     case TCG_COND_GE:
-        if (arg2 == 0) {
-            tcg_out_opc_br(s, OPC_BGEZ, 0, arg1);
-        } else {
-            tcg_out_opc_reg(s, OPC_SLT, TCG_REG_AT, arg1, arg2);
-            tcg_out_opc_br(s, OPC_BEQ, TCG_REG_AT, TCG_REG_ZERO);
-        }
-        break;
-    case TCG_COND_GEU:
-        tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_AT, arg1, arg2);
-        tcg_out_opc_br(s, OPC_BEQ, TCG_REG_AT, TCG_REG_ZERO);
-        break;
     case TCG_COND_LE:
-        if (arg2 == 0) {
-            tcg_out_opc_br(s, OPC_BLEZ, 0, arg1);
-        } else {
-            tcg_out_opc_reg(s, OPC_SLT, TCG_REG_AT, arg2, arg1);
-            tcg_out_opc_br(s, OPC_BEQ, TCG_REG_AT, TCG_REG_ZERO);
-        }
-        break;
-    case TCG_COND_LEU:
-        tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_AT, arg2, arg1);
-        tcg_out_opc_br(s, OPC_BEQ, TCG_REG_AT, TCG_REG_ZERO);
-        break;
     case TCG_COND_GT:
-        if (arg2 == 0) {
-            tcg_out_opc_br(s, OPC_BGTZ, 0, arg1);
-        } else {
-            tcg_out_opc_reg(s, OPC_SLT, TCG_REG_AT, arg2, arg1);
-            tcg_out_opc_br(s, OPC_BNE, TCG_REG_AT, TCG_REG_ZERO);
-        }
-        break;
+        s_opc = OPC_SLT;
+        /* FALLTHRU */
+
+    case TCG_COND_LTU:
+    case TCG_COND_GEU:
+    case TCG_COND_LEU:
     case TCG_COND_GTU:
-        tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_AT, arg2, arg1);
-        tcg_out_opc_br(s, OPC_BNE, TCG_REG_AT, TCG_REG_ZERO);
-        break;
-    default:
-        tcg_abort();
+        cmp_map = mips_cmp_map[cond];
+        if (cmp_map & MIPS_CMP_SWAP) {
+            TCGReg t = arg1;
+            arg1 = arg2;
+            arg2 = t;
+        }
+        tcg_out_opc_reg(s, s_opc, ret, arg1, arg2);
+        if (cmp_map & MIPS_CMP_INV) {
+            tcg_out_opc_imm(s, OPC_XORI, ret, ret, 1);
+        }
         break;
-    }
-    if (l->has_value) {
-        reloc_pc16(s->code_ptr - 1, l->u.value_ptr);
-    } else {
-        tcg_out_reloc(s, s->code_ptr - 1, R_MIPS_PC16, label_index, 0);
-    }
-    tcg_out_nop(s);
+
+     default:
+         tcg_abort();
+         break;
+     }
 }
 
-/* XXX: we implement it at the target level to avoid having to
-   handle cross basic blocks temporaries */
-static void tcg_out_brcond2(TCGContext *s, TCGCond cond, TCGArg arg1,
-                            TCGArg arg2, TCGArg arg3, TCGArg arg4,
-                            int label_index)
+static void tcg_out_brcond(TCGContext *s, TCGCond cond, TCGReg arg1,
+                           TCGReg arg2, int label_index)
 {
-    tcg_insn_unit *label_ptr;
+    static const MIPSInsn b_zero[16] = {
+        [TCG_COND_LT] = OPC_BLTZ,
+        [TCG_COND_GT] = OPC_BGTZ,
+        [TCG_COND_LE] = OPC_BLEZ,
+        [TCG_COND_GE] = OPC_BGEZ,
+    };
+
+    TCGLabel *l;
+    MIPSInsn s_opc = OPC_SLTU;
+    MIPSInsn b_opc;
+    int cmp_map;
 
-    switch(cond) {
-    case TCG_COND_NE:
-        tcg_out_brcond(s, TCG_COND_NE, arg2, arg4, label_index);
-        tcg_out_brcond(s, TCG_COND_NE, arg1, arg3, label_index);
-        return;
+    switch (cond) {
     case TCG_COND_EQ:
+        b_opc = OPC_BEQ;
         break;
-    case TCG_COND_LT:
-    case TCG_COND_LE:
-        tcg_out_brcond(s, TCG_COND_LT, arg2, arg4, label_index);
+    case TCG_COND_NE:
+        b_opc = OPC_BNE;
         break;
+
+    case TCG_COND_LT:
     case TCG_COND_GT:
+    case TCG_COND_LE:
     case TCG_COND_GE:
-        tcg_out_brcond(s, TCG_COND_GT, arg2, arg4, label_index);
-        break;
-    case TCG_COND_LTU:
-    case TCG_COND_LEU:
-        tcg_out_brcond(s, TCG_COND_LTU, arg2, arg4, label_index);
-        break;
-    case TCG_COND_GTU:
-    case TCG_COND_GEU:
-        tcg_out_brcond(s, TCG_COND_GTU, arg2, arg4, label_index);
-        break;
-    default:
-        tcg_abort();
-    }
-
-    label_ptr = s->code_ptr;
-    tcg_out_opc_br(s, OPC_BNE, arg2, arg4);
-    tcg_out_nop(s);
+        if (arg2 == 0) {
+            b_opc = b_zero[cond];
+            arg2 = arg1;
+            arg1 = 0;
+            break;
+        }
+        s_opc = OPC_SLT;
+        /* FALLTHRU */
 
-    switch(cond) {
-    case TCG_COND_EQ:
-        tcg_out_brcond(s, TCG_COND_EQ, arg1, arg3, label_index);
-        break;
-    case TCG_COND_LT:
     case TCG_COND_LTU:
-        tcg_out_brcond(s, TCG_COND_LTU, arg1, arg3, label_index);
-        break;
-    case TCG_COND_LE:
-    case TCG_COND_LEU:
-        tcg_out_brcond(s, TCG_COND_LEU, arg1, arg3, label_index);
-        break;
-    case TCG_COND_GT:
     case TCG_COND_GTU:
-        tcg_out_brcond(s, TCG_COND_GTU, arg1, arg3, label_index);
-        break;
-    case TCG_COND_GE:
+    case TCG_COND_LEU:
     case TCG_COND_GEU:
-        tcg_out_brcond(s, TCG_COND_GEU, arg1, arg3, label_index);
+        cmp_map = mips_cmp_map[cond];
+        if (cmp_map & MIPS_CMP_SWAP) {
+            TCGReg t = arg1;
+            arg1 = arg2;
+            arg2 = t;
+        }
+        tcg_out_opc_reg(s, s_opc, TCG_TMP0, arg1, arg2);
+        b_opc = (cmp_map & MIPS_CMP_INV ? OPC_BEQ : OPC_BNE);
+        arg1 = TCG_TMP0;
+        arg2 = TCG_REG_ZERO;
         break;
+
     default:
         tcg_abort();
+        break;
     }
 
-    reloc_pc16(label_ptr, s->code_ptr);
+    tcg_out_opc_br(s, b_opc, arg1, arg2);
+    l = &s->labels[label_index];
+    if (l->has_value) {
+        reloc_pc16(s->code_ptr - 1, l->u.value_ptr);
+    } else {
+        tcg_out_reloc(s, s->code_ptr - 1, R_MIPS_PC16, label_index, 0);
+    }
+    tcg_out_nop(s);
 }
 
-static void tcg_out_movcond(TCGContext *s, TCGCond cond, TCGReg ret,
-                            TCGArg c1, TCGArg c2, TCGArg v)
+static TCGReg tcg_out_reduce_eq2(TCGContext *s, TCGReg tmp0, TCGReg tmp1,
+                                 TCGReg al, TCGReg ah,
+                                 TCGReg bl, TCGReg bh)
 {
-    switch (cond) {
-    case TCG_COND_EQ:
-        if (c1 == 0) {
-            tcg_out_opc_reg(s, OPC_MOVZ, ret, v, c2);
-        } else if (c2 == 0) {
-            tcg_out_opc_reg(s, OPC_MOVZ, ret, v, c1);
+    /* Merge highpart comparison into AH.  */
+    if (bh != 0) {
+        if (ah != 0) {
+            tcg_out_opc_reg(s, OPC_XOR, tmp0, ah, bh);
+            ah = tmp0;
         } else {
-            tcg_out_opc_reg(s, OPC_XOR, TCG_REG_AT, c1, c2);
-            tcg_out_opc_reg(s, OPC_MOVZ, ret, v, TCG_REG_AT);
+            ah = bh;
         }
-        break;
-    case TCG_COND_NE:
-        if (c1 == 0) {
-            tcg_out_opc_reg(s, OPC_MOVN, ret, v, c2);
-        } else if (c2 == 0) {
-            tcg_out_opc_reg(s, OPC_MOVN, ret, v, c1);
+    }
+    /* Merge lowpart comparison into AL.  */
+    if (bl != 0) {
+        if (al != 0) {
+            tcg_out_opc_reg(s, OPC_XOR, tmp1, al, bl);
+            al = tmp1;
         } else {
-            tcg_out_opc_reg(s, OPC_XOR, TCG_REG_AT, c1, c2);
-            tcg_out_opc_reg(s, OPC_MOVN, ret, v, TCG_REG_AT);
+            al = bl;
+        }
+    }
+    /* Merge high and low part comparisons into AL.  */
+    if (ah != 0) {
+        if (al != 0) {
+            tcg_out_opc_reg(s, OPC_OR, tmp0, ah, al);
+            al = tmp0;
+        } else {
+            al = ah;
         }
-        break;
-    case TCG_COND_LT:
-        tcg_out_opc_reg(s, OPC_SLT, TCG_REG_AT, c1, c2);
-        tcg_out_opc_reg(s, OPC_MOVN, ret, v, TCG_REG_AT);
-        break;
-    case TCG_COND_LTU:
-        tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_AT, c1, c2);
-        tcg_out_opc_reg(s, OPC_MOVN, ret, v, TCG_REG_AT);
-        break;
-    case TCG_COND_GE:
-        tcg_out_opc_reg(s, OPC_SLT, TCG_REG_AT, c1, c2);
-        tcg_out_opc_reg(s, OPC_MOVZ, ret, v, TCG_REG_AT);
-        break;
-    case TCG_COND_GEU:
-        tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_AT, c1, c2);
-        tcg_out_opc_reg(s, OPC_MOVZ, ret, v, TCG_REG_AT);
-        break;
-    case TCG_COND_LE:
-        tcg_out_opc_reg(s, OPC_SLT, TCG_REG_AT, c2, c1);
-        tcg_out_opc_reg(s, OPC_MOVZ, ret, v, TCG_REG_AT);
-        break;
-    case TCG_COND_LEU:
-        tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_AT, c2, c1);
-        tcg_out_opc_reg(s, OPC_MOVZ, ret, v, TCG_REG_AT);
-        break;
-    case TCG_COND_GT:
-        tcg_out_opc_reg(s, OPC_SLT, TCG_REG_AT, c2, c1);
-        tcg_out_opc_reg(s, OPC_MOVN, ret, v, TCG_REG_AT);
-        break;
-    case TCG_COND_GTU:
-        tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_AT, c2, c1);
-        tcg_out_opc_reg(s, OPC_MOVN, ret, v, TCG_REG_AT);
-        break;
-    default:
-        tcg_abort();
-        break;
     }
+    return al;
 }
 
-static void tcg_out_setcond(TCGContext *s, TCGCond cond, TCGReg ret,
-                            TCGArg arg1, TCGArg arg2)
+static void tcg_out_setcond2(TCGContext *s, TCGCond cond, TCGReg ret,
+                             TCGReg al, TCGReg ah, TCGReg bl, TCGReg bh)
 {
+    TCGReg tmp0 = TCG_TMP0;
+    TCGReg tmp1 = ret;
+
+    assert(ret != TCG_TMP0);
+    if (ret == ah || ret == bh) {
+        assert(ret != TCG_TMP1);
+        tmp1 = TCG_TMP1;
+    }
+
     switch (cond) {
     case TCG_COND_EQ:
-        if (arg1 == 0) {
-            tcg_out_opc_imm(s, OPC_SLTIU, ret, arg2, 1);
-        } else if (arg2 == 0) {
-            tcg_out_opc_imm(s, OPC_SLTIU, ret, arg1, 1);
-        } else {
-            tcg_out_opc_reg(s, OPC_XOR, ret, arg1, arg2);
-            tcg_out_opc_imm(s, OPC_SLTIU, ret, ret, 1);
-        }
-        break;
     case TCG_COND_NE:
-        if (arg1 == 0) {
-            tcg_out_opc_reg(s, OPC_SLTU, ret, TCG_REG_ZERO, arg2);
-        } else if (arg2 == 0) {
-            tcg_out_opc_reg(s, OPC_SLTU, ret, TCG_REG_ZERO, arg1);
-        } else {
-            tcg_out_opc_reg(s, OPC_XOR, ret, arg1, arg2);
-            tcg_out_opc_reg(s, OPC_SLTU, ret, TCG_REG_ZERO, ret);
-        }
-        break;
-    case TCG_COND_LT:
-        tcg_out_opc_reg(s, OPC_SLT, ret, arg1, arg2);
-        break;
-    case TCG_COND_LTU:
-        tcg_out_opc_reg(s, OPC_SLTU, ret, arg1, arg2);
-        break;
-    case TCG_COND_GE:
-        tcg_out_opc_reg(s, OPC_SLT, ret, arg1, arg2);
-        tcg_out_opc_imm(s, OPC_XORI, ret, ret, 1);
-        break;
-    case TCG_COND_GEU:
-        tcg_out_opc_reg(s, OPC_SLTU, ret, arg1, arg2);
-        tcg_out_opc_imm(s, OPC_XORI, ret, ret, 1);
+        tmp1 = tcg_out_reduce_eq2(s, tmp0, tmp1, al, ah, bl, bh);
+        tcg_out_setcond(s, cond, ret, tmp1, TCG_REG_ZERO);
         break;
-    case TCG_COND_LE:
-        tcg_out_opc_reg(s, OPC_SLT, ret, arg2, arg1);
-        tcg_out_opc_imm(s, OPC_XORI, ret, ret, 1);
-        break;
-    case TCG_COND_LEU:
-        tcg_out_opc_reg(s, OPC_SLTU, ret, arg2, arg1);
-        tcg_out_opc_imm(s, OPC_XORI, ret, ret, 1);
-        break;
-    case TCG_COND_GT:
-        tcg_out_opc_reg(s, OPC_SLT, ret, arg2, arg1);
+
+    default:
+        tcg_out_setcond(s, TCG_COND_EQ, tmp0, ah, bh);
+        tcg_out_setcond(s, tcg_unsigned_cond(cond), tmp1, al, bl);
+        tcg_out_opc_reg(s, OPC_AND, tmp1, tmp1, tmp0);
+        tcg_out_setcond(s, tcg_high_cond(cond), tmp0, ah, bh);
+        tcg_out_opc_reg(s, OPC_OR, ret, tmp1, tmp0);
         break;
-    case TCG_COND_GTU:
-        tcg_out_opc_reg(s, OPC_SLTU, ret, arg2, arg1);
+    }
+}
+
+static void tcg_out_brcond2(TCGContext *s, TCGCond cond, TCGReg al, TCGReg ah,
+                            TCGReg bl, TCGReg bh, int label_index)
+{
+    TCGCond b_cond = TCG_COND_NE;
+    TCGReg tmp = TCG_TMP1;
+
+    /* With branches, we emit between 4 and 9 insns with 2 or 3 branches.
+       With setcond, we emit between 3 and 10 insns and only 1 branch,
+       which ought to get better branch prediction.  */
+     switch (cond) {
+     case TCG_COND_EQ:
+     case TCG_COND_NE:
+        b_cond = cond;
+        tmp = tcg_out_reduce_eq2(s, TCG_TMP0, TCG_TMP1, al, ah, bl, bh);
         break;
+
     default:
-        tcg_abort();
+        /* Minimize code size by prefering a compare not requiring INV.  */
+        if (mips_cmp_map[cond] & MIPS_CMP_INV) {
+            cond = tcg_invert_cond(cond);
+            b_cond = TCG_COND_EQ;
+        }
+        tcg_out_setcond2(s, cond, tmp, al, ah, bl, bh);
         break;
     }
+
+    tcg_out_brcond(s, b_cond, tmp, TCG_REG_ZERO, label_index);
 }
 
-/* XXX: we implement it at the target level to avoid having to
-   handle cross basic blocks temporaries */
-static void tcg_out_setcond2(TCGContext *s, TCGCond cond, TCGReg ret,
-                             TCGArg arg1, TCGArg arg2, TCGArg arg3, TCGArg arg4)
+static void tcg_out_movcond(TCGContext *s, TCGCond cond, TCGReg ret,
+                            TCGReg c1, TCGReg c2, TCGReg v)
 {
+    MIPSInsn m_opc = OPC_MOVN;
+
     switch (cond) {
     case TCG_COND_EQ:
-        tcg_out_setcond(s, TCG_COND_EQ, TCG_REG_AT, arg2, arg4);
-        tcg_out_setcond(s, TCG_COND_EQ, TCG_REG_T0, arg1, arg3);
-        tcg_out_opc_reg(s, OPC_AND, ret, TCG_REG_AT, TCG_REG_T0);
-        return;
+        m_opc = OPC_MOVZ;
+        /* FALLTHRU */
     case TCG_COND_NE:
-        tcg_out_setcond(s, TCG_COND_NE, TCG_REG_AT, arg2, arg4);
-        tcg_out_setcond(s, TCG_COND_NE, TCG_REG_T0, arg1, arg3);
-        tcg_out_opc_reg(s, OPC_OR, ret, TCG_REG_AT, TCG_REG_T0);
-        return;
-    case TCG_COND_LT:
-    case TCG_COND_LE:
-        tcg_out_setcond(s, TCG_COND_LT, TCG_REG_AT, arg2, arg4);
-        break;
-    case TCG_COND_GT:
-    case TCG_COND_GE:
-        tcg_out_setcond(s, TCG_COND_GT, TCG_REG_AT, arg2, arg4);
-        break;
-    case TCG_COND_LTU:
-    case TCG_COND_LEU:
-        tcg_out_setcond(s, TCG_COND_LTU, TCG_REG_AT, arg2, arg4);
-        break;
-    case TCG_COND_GTU:
-    case TCG_COND_GEU:
-        tcg_out_setcond(s, TCG_COND_GTU, TCG_REG_AT, arg2, arg4);
+        if (c2 != 0) {
+            tcg_out_opc_reg(s, OPC_XOR, TCG_TMP0, c1, c2);
+            c1 = TCG_TMP0;
+        }
         break;
+
     default:
-        tcg_abort();
+        /* Minimize code size by prefering a compare not requiring INV.  */
+        if (mips_cmp_map[cond] & MIPS_CMP_INV) {
+            cond = tcg_invert_cond(cond);
+            m_opc = OPC_MOVZ;
+        }
+        tcg_out_setcond(s, cond, TCG_TMP0, c1, c2);
+        c1 = TCG_TMP0;
         break;
     }
 
-    tcg_out_setcond(s, TCG_COND_EQ, TCG_REG_T0, arg2, arg4);
+    tcg_out_opc_reg(s, m_opc, ret, v, c1);
+}
 
-    switch(cond) {
-    case TCG_COND_LT:
-    case TCG_COND_LTU:
-        tcg_out_setcond(s, TCG_COND_LTU, ret, arg1, arg3);
-        break;
-    case TCG_COND_LE:
-    case TCG_COND_LEU:
-        tcg_out_setcond(s, TCG_COND_LEU, ret, arg1, arg3);
-        break;
-    case TCG_COND_GT:
-    case TCG_COND_GTU:
-        tcg_out_setcond(s, TCG_COND_GTU, ret, arg1, arg3);
-        break;
-    case TCG_COND_GE:
-    case TCG_COND_GEU:
-        tcg_out_setcond(s, TCG_COND_GEU, ret, arg1, arg3);
-        break;
-    default:
-        tcg_abort();
+static void tcg_out_call_int(TCGContext *s, tcg_insn_unit *arg, bool tail)
+{
+    /* Note that the ABI requires the called function's address to be
+       loaded into T9, even if a direct branch is in range.  */
+    tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_T9, (uintptr_t)arg);
+
+    /* But do try a direct branch, allowing the cpu better insn prefetch.  */
+    if (tail) {
+        if (!tcg_out_opc_jmp(s, OPC_J, arg)) {
+            tcg_out_opc_reg(s, OPC_JR, 0, TCG_REG_T9, 0);
+        }
+    } else {
+        if (!tcg_out_opc_jmp(s, OPC_JAL, arg)) {
+            tcg_out_opc_reg(s, OPC_JALR, TCG_REG_RA, TCG_REG_T9, 0);
+        }
     }
+}
 
-    tcg_out_opc_reg(s, OPC_AND, ret, ret, TCG_REG_T0);
-    tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT);
+static void tcg_out_call(TCGContext *s, tcg_insn_unit *arg)
+{
+    tcg_out_call_int(s, arg, false);
+    tcg_out_nop(s);
 }
 
 #if defined(CONFIG_SOFTMMU)
-/* helper signature: helper_ld_mmu(CPUState *env, target_ulong addr,
-   int mmu_idx) */
-static const void * const qemu_ld_helpers[4] = {
-    helper_ldb_mmu,
-    helper_ldw_mmu,
-    helper_ldl_mmu,
-    helper_ldq_mmu,
+static void * const qemu_ld_helpers[16] = {
+    [MO_UB]   = helper_ret_ldub_mmu,
+    [MO_SB]   = helper_ret_ldsb_mmu,
+    [MO_LEUW] = helper_le_lduw_mmu,
+    [MO_LESW] = helper_le_ldsw_mmu,
+    [MO_LEUL] = helper_le_ldul_mmu,
+    [MO_LEQ]  = helper_le_ldq_mmu,
+    [MO_BEUW] = helper_be_lduw_mmu,
+    [MO_BESW] = helper_be_ldsw_mmu,
+    [MO_BEUL] = helper_be_ldul_mmu,
+    [MO_BEQ]  = helper_be_ldq_mmu,
 };
 
-/* helper signature: helper_st_mmu(CPUState *env, target_ulong addr,
-   uintxx_t val, int mmu_idx) */
-static const void * const qemu_st_helpers[4] = {
-    helper_stb_mmu,
-    helper_stw_mmu,
-    helper_stl_mmu,
-    helper_stq_mmu,
+static void * const qemu_st_helpers[16] = {
+    [MO_UB]   = helper_ret_stb_mmu,
+    [MO_LEUW] = helper_le_stw_mmu,
+    [MO_LEUL] = helper_le_stl_mmu,
+    [MO_LEQ]  = helper_le_stq_mmu,
+    [MO_BEUW] = helper_be_stw_mmu,
+    [MO_BEUL] = helper_be_stl_mmu,
+    [MO_BEQ]  = helper_be_stq_mmu,
 };
-#endif
 
-static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
-                            int opc)
+/* Helper routines for marshalling helper function arguments into
+ * the correct registers and stack.
+ * I is where we want to put this argument, and is updated and returned
+ * for the next call. ARG is the argument itself.
+ *
+ * We provide routines for arguments which are: immediate, 32 bit
+ * value in register, 16 and 8 bit values in register (which must be zero
+ * extended before use) and 64 bit value in a lo:hi register pair.
+ */
+
+static int tcg_out_call_iarg_reg(TCGContext *s, int i, TCGReg arg)
 {
-    TCGReg addr_regl, data_regl, data_regh, data_reg1, data_reg2;
-#if defined(CONFIG_SOFTMMU)
-    tcg_insn_unit *label1_ptr, *label2_ptr;
-    int arg_num;
-    int mem_index, s_bits;
-    int addr_meml;
-# if TARGET_LONG_BITS == 64
-    tcg_insn_unit *label3_ptr;
-    TCGReg addr_regh;
-    int addr_memh;
-# endif
-#endif
-    data_regl = *args++;
-    if (opc == 3)
-        data_regh = *args++;
-    else
-        data_regh = 0;
-    addr_regl = *args++;
-#if defined(CONFIG_SOFTMMU)
-# if TARGET_LONG_BITS == 64
-    addr_regh = *args++;
-#  if defined(HOST_WORDS_BIGENDIAN)
-    addr_memh = 0;
-    addr_meml = 4;
-#  else
-    addr_memh = 4;
-    addr_meml = 0;
-#  endif
-# else
-    addr_meml = 0;
-# endif
-    mem_index = *args;
-    s_bits = opc & 3;
-#endif
+    if (i < ARRAY_SIZE(tcg_target_call_iarg_regs)) {
+        tcg_out_mov(s, TCG_TYPE_REG, tcg_target_call_iarg_regs[i], arg);
+    } else {
+        tcg_out_st(s, TCG_TYPE_REG, arg, TCG_REG_SP, 4 * i);
+    }
+    return i + 1;
+}
 
-    if (opc == 3) {
-#if defined(HOST_WORDS_BIGENDIAN)
-        data_reg1 = data_regh;
-        data_reg2 = data_regl;
-#else
-        data_reg1 = data_regl;
-        data_reg2 = data_regh;
-#endif
+static int tcg_out_call_iarg_reg8(TCGContext *s, int i, TCGReg arg)
+{
+    TCGReg tmp = TCG_TMP0;
+    if (i < ARRAY_SIZE(tcg_target_call_iarg_regs)) {
+        tmp = tcg_target_call_iarg_regs[i];
+    }
+    tcg_out_opc_imm(s, OPC_ANDI, tmp, arg, 0xff);
+    return tcg_out_call_iarg_reg(s, i, tmp);
+}
+
+static int tcg_out_call_iarg_reg16(TCGContext *s, int i, TCGReg arg)
+{
+    TCGReg tmp = TCG_TMP0;
+    if (i < ARRAY_SIZE(tcg_target_call_iarg_regs)) {
+        tmp = tcg_target_call_iarg_regs[i];
+    }
+    tcg_out_opc_imm(s, OPC_ANDI, tmp, arg, 0xffff);
+    return tcg_out_call_iarg_reg(s, i, tmp);
+}
+
+static int tcg_out_call_iarg_imm(TCGContext *s, int i, TCGArg arg)
+{
+    TCGReg tmp = TCG_TMP0;
+    if (arg == 0) {
+        tmp = TCG_REG_ZERO;
     } else {
-        data_reg1 = data_regl;
-        data_reg2 = 0;
+        if (i < ARRAY_SIZE(tcg_target_call_iarg_regs)) {
+            tmp = tcg_target_call_iarg_regs[i];
+        }
+        tcg_out_movi(s, TCG_TYPE_REG, tmp, arg);
     }
-#if defined(CONFIG_SOFTMMU)
-    tcg_out_opc_sa(s, OPC_SRL, TCG_REG_A0, addr_regl, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS);
-    tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_A0, TCG_REG_A0, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS);
+    return tcg_out_call_iarg_reg(s, i, tmp);
+}
+
+static int tcg_out_call_iarg_reg2(TCGContext *s, int i, TCGReg al, TCGReg ah)
+{
+    i = (i + 1) & ~1;
+    i = tcg_out_call_iarg_reg(s, i, (MIPS_BE ? ah : al));
+    i = tcg_out_call_iarg_reg(s, i, (MIPS_BE ? al : ah));
+    return i;
+}
+
+/* Perform the tlb comparison operation.  The complete host address is
+   placed in BASE.  Clobbers AT, T0, A0.  */
+static void tcg_out_tlb_load(TCGContext *s, TCGReg base, TCGReg addrl,
+                             TCGReg addrh, int mem_index, TCGMemOp s_bits,
+                             tcg_insn_unit *label_ptr[2], bool is_load)
+{
+    int cmp_off
+        = (is_load
+           ? offsetof(CPUArchState, tlb_table[mem_index][0].addr_read)
+           : offsetof(CPUArchState, tlb_table[mem_index][0].addr_write));
+    int add_off = offsetof(CPUArchState, tlb_table[mem_index][0].addend);
+
+    tcg_out_opc_sa(s, OPC_SRL, TCG_REG_A0, addrl,
+                   TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS);
+    tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_A0, TCG_REG_A0,
+                    (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS);
     tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_A0, TCG_REG_A0, TCG_AREG0);
-    tcg_out_opc_imm(s, OPC_LW, TCG_REG_AT, TCG_REG_A0,
-                    offsetof(CPUArchState, tlb_table[mem_index][0].addr_read) + addr_meml);
-    tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_T0, TARGET_PAGE_MASK | ((1 << s_bits) - 1));
-    tcg_out_opc_reg(s, OPC_AND, TCG_REG_T0, TCG_REG_T0, addr_regl);
-
-# if TARGET_LONG_BITS == 64
-    label3_ptr = s->code_ptr;
-    tcg_out_opc_br(s, OPC_BNE, TCG_REG_T0, TCG_REG_AT);
-    tcg_out_nop(s);
 
-    tcg_out_opc_imm(s, OPC_LW, TCG_REG_AT, TCG_REG_A0,
-                    offsetof(CPUArchState, tlb_table[mem_index][0].addr_read) + addr_memh);
+    /* Compensate for very large offsets.  */
+    if (add_off >= 0x8000) {
+        /* Most target env are smaller than 32k; none are larger than 64k.
+           Simplify the logic here merely to offset by 0x7ff0, giving us a
+           range just shy of 64k.  Check this assumption.  */
+        QEMU_BUILD_BUG_ON(offsetof(CPUArchState,
+                                   tlb_table[NB_MMU_MODES - 1][1])
+                          > 0x7ff0 + 0x7fff);
+        tcg_out_opc_imm(s, OPC_ADDIU, TCG_REG_A0, TCG_REG_A0, 0x7ff0);
+        cmp_off -= 0x7ff0;
+        add_off -= 0x7ff0;
+    }
 
-    label1_ptr = s->code_ptr;
-    tcg_out_opc_br(s, OPC_BEQ, addr_regh, TCG_REG_AT);
-    tcg_out_nop(s);
+    /* Load the tlb comparator.  */
+    tcg_out_opc_imm(s, OPC_LW, TCG_TMP0, TCG_REG_A0, cmp_off + LO_OFF);
+    if (TARGET_LONG_BITS == 64) {
+        tcg_out_opc_imm(s, OPC_LW, base, TCG_REG_A0, cmp_off + HI_OFF);
+    }
 
-    reloc_pc16(label3_ptr, s->code_ptr);
-# else
-    label1_ptr = s->code_ptr;
-    tcg_out_opc_br(s, OPC_BEQ, TCG_REG_T0, TCG_REG_AT);
-    tcg_out_nop(s);
-# endif
-
-    /* slow path */
-    arg_num = 0;
-    tcg_out_call_iarg_reg32(s, &arg_num, TCG_AREG0);
-# if TARGET_LONG_BITS == 64
-    tcg_out_call_iarg_reg64(s, &arg_num, addr_regl, addr_regh);
-# else
-    tcg_out_call_iarg_reg32(s, &arg_num, addr_regl);
-# endif
-    tcg_out_call_iarg_imm32(s, &arg_num, mem_index);
-    tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_T9, (tcg_target_long)qemu_ld_helpers[s_bits]);
-    tcg_out_opc_reg(s, OPC_JALR, TCG_REG_RA, TCG_REG_T9, 0);
-    tcg_out_nop(s);
+    /* Mask the page bits, keeping the alignment bits to compare against.
+       In between, load the tlb addend for the fast path.  */
+    tcg_out_movi(s, TCG_TYPE_I32, TCG_TMP1,
+                 TARGET_PAGE_MASK | ((1 << s_bits) - 1));
+    tcg_out_opc_imm(s, OPC_LW, TCG_REG_A0, TCG_REG_A0, add_off);
+    tcg_out_opc_reg(s, OPC_AND, TCG_TMP1, TCG_TMP1, addrl);
 
-    switch(opc) {
-    case 0:
-        tcg_out_opc_imm(s, OPC_ANDI, data_reg1, TCG_REG_V0, 0xff);
-        break;
-    case 0 | 4:
-        tcg_out_ext8s(s, data_reg1, TCG_REG_V0);
-        break;
-    case 1:
-        tcg_out_opc_imm(s, OPC_ANDI, data_reg1, TCG_REG_V0, 0xffff);
-        break;
-    case 1 | 4:
-        tcg_out_ext16s(s, data_reg1, TCG_REG_V0);
-        break;
-    case 2:
-        tcg_out_mov(s, TCG_TYPE_I32, data_reg1, TCG_REG_V0);
-        break;
-    case 3:
-        tcg_out_mov(s, TCG_TYPE_I32, data_reg2, TCG_REG_V1);
-        tcg_out_mov(s, TCG_TYPE_I32, data_reg1, TCG_REG_V0);
-        break;
-    default:
-        tcg_abort();
+    label_ptr[0] = s->code_ptr;
+    tcg_out_opc_br(s, OPC_BNE, TCG_TMP1, TCG_TMP0);
+
+    if (TARGET_LONG_BITS == 64) {
+        /* delay slot */
+        tcg_out_nop(s);
+
+        label_ptr[1] = s->code_ptr;
+        tcg_out_opc_br(s, OPC_BNE, addrh, base);
     }
 
-    label2_ptr = s->code_ptr;
+    /* delay slot */
+    tcg_out_opc_reg(s, OPC_ADDU, base, TCG_REG_A0, addrl);
+}
+
+static void add_qemu_ldst_label(TCGContext *s, int is_ld, TCGMemOp opc,
+                                TCGReg datalo, TCGReg datahi,
+                                TCGReg addrlo, TCGReg addrhi,
+                                int mem_index, void *raddr,
+                                tcg_insn_unit *label_ptr[2])
+{
+    TCGLabelQemuLdst *label = new_ldst_label(s);
+
+    label->is_ld = is_ld;
+    label->opc = opc;
+    label->datalo_reg = datalo;
+    label->datahi_reg = datahi;
+    label->addrlo_reg = addrlo;
+    label->addrhi_reg = addrhi;
+    label->mem_index = mem_index;
+    label->raddr = raddr;
+    label->label_ptr[0] = label_ptr[0];
+    if (TARGET_LONG_BITS == 64) {
+        label->label_ptr[1] = label_ptr[1];
+    }
+}
+
+static void tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
+{
+    TCGMemOp opc = l->opc;
+    TCGReg v0;
+    int i;
+
+    /* resolve label address */
+    reloc_pc16(l->label_ptr[0], s->code_ptr);
+    if (TARGET_LONG_BITS == 64) {
+        reloc_pc16(l->label_ptr[1], s->code_ptr);
+    }
+
+    i = 1;
+    if (TARGET_LONG_BITS == 64) {
+        i = tcg_out_call_iarg_reg2(s, i, l->addrlo_reg, l->addrhi_reg);
+    } else {
+        i = tcg_out_call_iarg_reg(s, i, l->addrlo_reg);
+    }
+    i = tcg_out_call_iarg_imm(s, i, l->mem_index);
+    i = tcg_out_call_iarg_imm(s, i, (intptr_t)l->raddr);
+    tcg_out_call_int(s, qemu_ld_helpers[opc], false);
+    /* delay slot */
+    tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0], TCG_AREG0);
+
+    v0 = l->datalo_reg;
+    if ((opc & MO_SIZE) == MO_64) {
+        /* We eliminated V0 from the possible output registers, so it
+           cannot be clobbered here.  So we must move V1 first.  */
+        if (MIPS_BE) {
+            tcg_out_mov(s, TCG_TYPE_I32, v0, TCG_REG_V1);
+            v0 = l->datahi_reg;
+        } else {
+            tcg_out_mov(s, TCG_TYPE_I32, l->datahi_reg, TCG_REG_V1);
+        }
+    }
+
+    reloc_pc16(s->code_ptr, l->raddr);
     tcg_out_opc_br(s, OPC_BEQ, TCG_REG_ZERO, TCG_REG_ZERO);
-    tcg_out_nop(s);
+    /* delay slot */
+    tcg_out_mov(s, TCG_TYPE_REG, v0, TCG_REG_V0);
+}
 
-    /* label1: fast path */
-    reloc_pc16(label1_ptr, s->code_ptr);
+static void tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
+{
+    TCGMemOp opc = l->opc;
+    TCGMemOp s_bits = opc & MO_SIZE;
+    int i;
+
+    /* resolve label address */
+    reloc_pc16(l->label_ptr[0], s->code_ptr);
+    if (TARGET_LONG_BITS == 64) {
+        reloc_pc16(l->label_ptr[1], s->code_ptr);
+    }
 
-    tcg_out_opc_imm(s, OPC_LW, TCG_REG_A0, TCG_REG_A0,
-                    offsetof(CPUArchState, tlb_table[mem_index][0].addend));
-    tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_V0, TCG_REG_A0, addr_regl);
-#else
-    if (GUEST_BASE == (int16_t)GUEST_BASE) {
-        tcg_out_opc_imm(s, OPC_ADDIU, TCG_REG_V0, addr_regl, GUEST_BASE);
+    i = 1;
+    if (TARGET_LONG_BITS == 64) {
+        i = tcg_out_call_iarg_reg2(s, i, l->addrlo_reg, l->addrhi_reg);
     } else {
-        tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_V0, GUEST_BASE);
-        tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_V0, TCG_REG_V0, addr_regl);
+        i = tcg_out_call_iarg_reg(s, i, l->addrlo_reg);
+    }
+    switch (s_bits) {
+    case MO_8:
+        i = tcg_out_call_iarg_reg8(s, i, l->datalo_reg);
+        break;
+    case MO_16:
+        i = tcg_out_call_iarg_reg16(s, i, l->datalo_reg);
+        break;
+    case MO_32:
+        i = tcg_out_call_iarg_reg(s, i, l->datalo_reg);
+        break;
+    case MO_64:
+        i = tcg_out_call_iarg_reg2(s, i, l->datalo_reg, l->datahi_reg);
+        break;
+    default:
+        tcg_abort();
     }
+    i = tcg_out_call_iarg_imm(s, i, l->mem_index);
+
+    /* Tail call to the store helper.  Thus force the return address
+       computation to take place in the return address register.  */
+    tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_RA, (intptr_t)l->raddr);
+    i = tcg_out_call_iarg_reg(s, i, TCG_REG_RA);
+    tcg_out_call_int(s, qemu_st_helpers[opc], true);
+    /* delay slot */
+    tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0], TCG_AREG0);
+}
 #endif
 
-    switch(opc) {
-    case 0:
-        tcg_out_opc_imm(s, OPC_LBU, data_reg1, TCG_REG_V0, 0);
+static void tcg_out_qemu_ld_direct(TCGContext *s, TCGReg datalo, TCGReg datahi,
+                                   TCGReg base, TCGMemOp opc)
+{
+    switch (opc) {
+    case MO_UB:
+        tcg_out_opc_imm(s, OPC_LBU, datalo, base, 0);
         break;
-    case 0 | 4:
-        tcg_out_opc_imm(s, OPC_LB, data_reg1, TCG_REG_V0, 0);
+    case MO_SB:
+        tcg_out_opc_imm(s, OPC_LB, datalo, base, 0);
         break;
-    case 1:
-        if (TCG_NEED_BSWAP) {
-            tcg_out_opc_imm(s, OPC_LHU, TCG_REG_T0, TCG_REG_V0, 0);
-            tcg_out_bswap16(s, data_reg1, TCG_REG_T0);
-        } else {
-            tcg_out_opc_imm(s, OPC_LHU, data_reg1, TCG_REG_V0, 0);
-        }
+    case MO_UW | MO_BSWAP:
+        tcg_out_opc_imm(s, OPC_LHU, TCG_TMP1, base, 0);
+        tcg_out_bswap16(s, datalo, TCG_TMP1);
         break;
-    case 1 | 4:
-        if (TCG_NEED_BSWAP) {
-            tcg_out_opc_imm(s, OPC_LHU, TCG_REG_T0, TCG_REG_V0, 0);
-            tcg_out_bswap16s(s, data_reg1, TCG_REG_T0);
-        } else {
-            tcg_out_opc_imm(s, OPC_LH, data_reg1, TCG_REG_V0, 0);
-        }
+    case MO_UW:
+        tcg_out_opc_imm(s, OPC_LHU, datalo, base, 0);
         break;
-    case 2:
-        if (TCG_NEED_BSWAP) {
-            tcg_out_opc_imm(s, OPC_LW, TCG_REG_T0, TCG_REG_V0, 0);
-            tcg_out_bswap32(s, data_reg1, TCG_REG_T0);
-        } else {
-            tcg_out_opc_imm(s, OPC_LW, data_reg1, TCG_REG_V0, 0);
-        }
+    case MO_SW | MO_BSWAP:
+        tcg_out_opc_imm(s, OPC_LHU, TCG_TMP1, base, 0);
+        tcg_out_bswap16s(s, datalo, TCG_TMP1);
         break;
-    case 3:
-        if (TCG_NEED_BSWAP) {
-            tcg_out_opc_imm(s, OPC_LW, TCG_REG_T0, TCG_REG_V0, 4);
-            tcg_out_bswap32(s, data_reg1, TCG_REG_T0);
-            tcg_out_opc_imm(s, OPC_LW, TCG_REG_T0, TCG_REG_V0, 0);
-            tcg_out_bswap32(s, data_reg2, TCG_REG_T0);
-        } else {
-            tcg_out_opc_imm(s, OPC_LW, data_reg1, TCG_REG_V0, 0);
-            tcg_out_opc_imm(s, OPC_LW, data_reg2, TCG_REG_V0, 4);
-        }
+    case MO_SW:
+        tcg_out_opc_imm(s, OPC_LH, datalo, base, 0);
+        break;
+    case MO_UL | MO_BSWAP:
+        tcg_out_opc_imm(s, OPC_LW, TCG_TMP1, base, 0);
+        tcg_out_bswap32(s, datalo, TCG_TMP1);
+        break;
+    case MO_UL:
+        tcg_out_opc_imm(s, OPC_LW, datalo, base, 0);
+        break;
+    case MO_Q | MO_BSWAP:
+        tcg_out_opc_imm(s, OPC_LW, TCG_TMP1, base, HI_OFF);
+        tcg_out_bswap32(s, datalo, TCG_TMP1);
+        tcg_out_opc_imm(s, OPC_LW, TCG_TMP1, base, LO_OFF);
+        tcg_out_bswap32(s, datahi, TCG_TMP1);
+        break;
+    case MO_Q:
+        tcg_out_opc_imm(s, OPC_LW, datalo, base, LO_OFF);
+        tcg_out_opc_imm(s, OPC_LW, datahi, base, HI_OFF);
         break;
     default:
         tcg_abort();
     }
-
-#if defined(CONFIG_SOFTMMU)
-    reloc_pc16(label2_ptr, s->code_ptr);
-#endif
 }
 
-static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
-                            int opc)
+static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, bool is_64)
 {
-    TCGReg addr_regl, data_regl, data_regh, data_reg1, data_reg2;
+    TCGReg addr_regl, addr_regh __attribute__((unused));
+    TCGReg data_regl, data_regh;
+    TCGMemOp opc;
 #if defined(CONFIG_SOFTMMU)
-    tcg_insn_unit *label1_ptr, *label2_ptr;
-    int arg_num;
-    int mem_index, s_bits;
-    int addr_meml;
-#endif
-#if TARGET_LONG_BITS == 64
-# if defined(CONFIG_SOFTMMU)
-    tcg_insn_unit *label3_ptr;
-    TCGReg addr_regh;
-    int addr_memh;
-# endif
+    tcg_insn_unit *label_ptr[2];
+    int mem_index;
+    TCGMemOp s_bits;
 #endif
+    /* Note that we've eliminated V0 from the output registers,
+       so we won't overwrite the base register during loading.  */
+    TCGReg base = TCG_REG_V0;
+
     data_regl = *args++;
-    if (opc == 3) {
-        data_regh = *args++;
-    } else {
-        data_regh = 0;
-    }
+    data_regh = (is_64 ? *args++ : 0);
     addr_regl = *args++;
+    addr_regh = (TARGET_LONG_BITS == 64 ? *args++ : 0);
+    opc = *args++;
+
 #if defined(CONFIG_SOFTMMU)
-# if TARGET_LONG_BITS == 64
-    addr_regh = *args++;
-#  if defined(HOST_WORDS_BIGENDIAN)
-    addr_memh = 0;
-    addr_meml = 4;
-#  else
-    addr_memh = 4;
-    addr_meml = 0;
-#  endif
-# else
-    addr_meml = 0;
-# endif
     mem_index = *args;
-    s_bits = opc;
-#endif
+    s_bits = opc & MO_SIZE;
 
-    if (opc == 3) {
-#if defined(HOST_WORDS_BIGENDIAN)
-        data_reg1 = data_regh;
-        data_reg2 = data_regl;
+    tcg_out_tlb_load(s, base, addr_regl, addr_regh, mem_index,
+                     s_bits, label_ptr, 1);
+    tcg_out_qemu_ld_direct(s, data_regl, data_regh, base, opc);
+    add_qemu_ldst_label(s, 1, opc, data_regl, data_regh, addr_regl, addr_regh,
+                        mem_index, s->code_ptr, label_ptr);
 #else
-        data_reg1 = data_regl;
-        data_reg2 = data_regh;
-#endif
+    if (GUEST_BASE == 0 && data_regl != addr_regl) {
+        base = addr_regl;
+    } else if (GUEST_BASE == (int16_t)GUEST_BASE) {
+        tcg_out_opc_imm(s, OPC_ADDIU, base, addr_regl, GUEST_BASE);
     } else {
-        data_reg1 = data_regl;
-        data_reg2 = 0;
+        tcg_out_movi(s, TCG_TYPE_PTR, base, GUEST_BASE);
+        tcg_out_opc_reg(s, OPC_ADDU, base, base, addr_regl);
     }
+    tcg_out_qemu_ld_direct(s, data_regl, data_regh, base, opc);
+#endif
+}
 
-#if defined(CONFIG_SOFTMMU)
-    tcg_out_opc_sa(s, OPC_SRL, TCG_REG_A0, addr_regl, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS);
-    tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_A0, TCG_REG_A0, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS);
-    tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_A0, TCG_REG_A0, TCG_AREG0);
-    tcg_out_opc_imm(s, OPC_LW, TCG_REG_AT, TCG_REG_A0,
-                    offsetof(CPUArchState, tlb_table[mem_index][0].addr_write) + addr_meml);
-    tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_T0, TARGET_PAGE_MASK | ((1 << s_bits) - 1));
-    tcg_out_opc_reg(s, OPC_AND, TCG_REG_T0, TCG_REG_T0, addr_regl);
-
-# if TARGET_LONG_BITS == 64
-    label3_ptr = s->code_ptr;
-    tcg_out_opc_br(s, OPC_BNE, TCG_REG_T0, TCG_REG_AT);
-    tcg_out_nop(s);
-
-    tcg_out_opc_imm(s, OPC_LW, TCG_REG_AT, TCG_REG_A0,
-                    offsetof(CPUArchState, tlb_table[mem_index][0].addr_write) + addr_memh);
-
-    label1_ptr = s->code_ptr;
-    tcg_out_opc_br(s, OPC_BEQ, addr_regh, TCG_REG_AT);
-    tcg_out_nop(s);
-
-    reloc_pc16(label3_ptr, s->code_ptr);
-# else
-    label1_ptr = s->code_ptr;
-    tcg_out_opc_br(s, OPC_BEQ, TCG_REG_T0, TCG_REG_AT);
-    tcg_out_nop(s);
-# endif
+static void tcg_out_qemu_st_direct(TCGContext *s, TCGReg datalo, TCGReg datahi,
+                                   TCGReg base, TCGMemOp opc)
+{
+    switch (opc) {
+    case MO_8:
+        tcg_out_opc_imm(s, OPC_SB, datalo, base, 0);
+        break;
 
-    /* slow path */
-    arg_num = 0;
-    tcg_out_call_iarg_reg32(s, &arg_num, TCG_AREG0);
-# if TARGET_LONG_BITS == 64
-    tcg_out_call_iarg_reg64(s, &arg_num, addr_regl, addr_regh);
-# else
-    tcg_out_call_iarg_reg32(s, &arg_num, addr_regl);
-# endif
-    switch(opc) {
-    case 0:
-        tcg_out_call_iarg_reg8(s, &arg_num, data_regl);
+    case MO_16 | MO_BSWAP:
+        tcg_out_opc_imm(s, OPC_ANDI, TCG_TMP1, datalo, 0xffff);
+        tcg_out_bswap16(s, TCG_TMP1, TCG_TMP1);
+        datalo = TCG_TMP1;
+        /* FALLTHRU */
+    case MO_16:
+        tcg_out_opc_imm(s, OPC_SH, datalo, base, 0);
         break;
-    case 1:
-        tcg_out_call_iarg_reg16(s, &arg_num, data_regl);
+
+    case MO_32 | MO_BSWAP:
+        tcg_out_bswap32(s, TCG_TMP1, datalo);
+        datalo = TCG_TMP1;
+        /* FALLTHRU */
+    case MO_32:
+        tcg_out_opc_imm(s, OPC_SW, datalo, base, 0);
         break;
-    case 2:
-        tcg_out_call_iarg_reg32(s, &arg_num, data_regl);
+
+    case MO_64 | MO_BSWAP:
+        tcg_out_bswap32(s, TCG_TMP1, datalo);
+        tcg_out_opc_imm(s, OPC_SW, TCG_TMP1, base, HI_OFF);
+        tcg_out_bswap32(s, TCG_TMP1, datahi);
+        tcg_out_opc_imm(s, OPC_SW, TCG_TMP1, base, LO_OFF);
         break;
-    case 3:
-        tcg_out_call_iarg_reg64(s, &arg_num, data_regl, data_regh);
+    case MO_64:
+        tcg_out_opc_imm(s, OPC_SW, datalo, base, LO_OFF);
+        tcg_out_opc_imm(s, OPC_SW, datahi, base, HI_OFF);
         break;
+
     default:
         tcg_abort();
     }
-    tcg_out_call_iarg_imm32(s, &arg_num, mem_index);
-    tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_T9, (tcg_target_long)qemu_st_helpers[s_bits]);
-    tcg_out_opc_reg(s, OPC_JALR, TCG_REG_RA, TCG_REG_T9, 0);
-    tcg_out_nop(s);
-
-    label2_ptr = s->code_ptr;
-    tcg_out_opc_br(s, OPC_BEQ, TCG_REG_ZERO, TCG_REG_ZERO);
-    tcg_out_nop(s);
+}
 
-    /* label1: fast path */
-    reloc_pc16(label1_ptr, s->code_ptr);
+static void tcg_out_addsub2(TCGContext *s, TCGReg rl, TCGReg rh, TCGReg al,
+                            TCGReg ah, TCGArg bl, TCGArg bh, bool cbl,
+                            bool cbh, bool is_sub)
+{
+    TCGReg th = TCG_TMP1;
+
+    /* If we have a negative constant such that negating it would
+       make the high part zero, we can (usually) eliminate one insn.  */
+    if (cbl && cbh && bh == -1 && bl != 0) {
+        bl = -bl;
+        bh = 0;
+        is_sub = !is_sub;
+    }
 
-    tcg_out_opc_imm(s, OPC_LW, TCG_REG_A0, TCG_REG_A0,
-                    offsetof(CPUArchState, tlb_table[mem_index][0].addend));
-    tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_A0, TCG_REG_A0, addr_regl);
-#else
-    if (GUEST_BASE == (int16_t)GUEST_BASE) {
-        tcg_out_opc_imm(s, OPC_ADDIU, TCG_REG_A0, addr_regl, GUEST_BASE);
+    /* By operating on the high part first, we get to use the final
+       carry operation to move back from the temporary.  */
+    if (!cbh) {
+        tcg_out_opc_reg(s, (is_sub ? OPC_SUBU : OPC_ADDU), th, ah, bh);
+    } else if (bh != 0 || ah == rl) {
+        tcg_out_opc_imm(s, OPC_ADDIU, th, ah, (is_sub ? -bh : bh));
     } else {
-        tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_A0, GUEST_BASE);
-        tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_A0, TCG_REG_A0, addr_regl);
+        th = ah;
     }
 
-#endif
-
-    switch(opc) {
-    case 0:
-        tcg_out_opc_imm(s, OPC_SB, data_reg1, TCG_REG_A0, 0);
-        break;
-    case 1:
-        if (TCG_NEED_BSWAP) {
-            tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_T0, data_reg1, 0xffff);
-            tcg_out_bswap16(s, TCG_REG_T0, TCG_REG_T0);
-            tcg_out_opc_imm(s, OPC_SH, TCG_REG_T0, TCG_REG_A0, 0);
+    /* Note that tcg optimization should eliminate the bl == 0 case.  */
+    if (is_sub) {
+        if (cbl) {
+            tcg_out_opc_imm(s, OPC_SLTIU, TCG_TMP0, al, bl);
+            tcg_out_opc_imm(s, OPC_ADDIU, rl, al, -bl);
         } else {
-            tcg_out_opc_imm(s, OPC_SH, data_reg1, TCG_REG_A0, 0);
+            tcg_out_opc_reg(s, OPC_SLTU, TCG_TMP0, al, bl);
+            tcg_out_opc_reg(s, OPC_SUBU, rl, al, bl);
         }
-        break;
-    case 2:
-        if (TCG_NEED_BSWAP) {
-            tcg_out_bswap32(s, TCG_REG_T0, data_reg1);
-            tcg_out_opc_imm(s, OPC_SW, TCG_REG_T0, TCG_REG_A0, 0);
-        } else {
-            tcg_out_opc_imm(s, OPC_SW, data_reg1, TCG_REG_A0, 0);
-        }
-        break;
-    case 3:
-        if (TCG_NEED_BSWAP) {
-            tcg_out_bswap32(s, TCG_REG_T0, data_reg2);
-            tcg_out_opc_imm(s, OPC_SW, TCG_REG_T0, TCG_REG_A0, 0);
-            tcg_out_bswap32(s, TCG_REG_T0, data_reg1);
-            tcg_out_opc_imm(s, OPC_SW, TCG_REG_T0, TCG_REG_A0, 4);
+        tcg_out_opc_reg(s, OPC_SUBU, rh, th, TCG_TMP0);
+    } else {
+        if (cbl) {
+            tcg_out_opc_imm(s, OPC_ADDIU, rl, al, bl);
+            tcg_out_opc_imm(s, OPC_SLTIU, TCG_TMP0, rl, bl);
         } else {
-            tcg_out_opc_imm(s, OPC_SW, data_reg1, TCG_REG_A0, 0);
-            tcg_out_opc_imm(s, OPC_SW, data_reg2, TCG_REG_A0, 4);
+            tcg_out_opc_reg(s, OPC_ADDU, rl, al, bl);
+            tcg_out_opc_reg(s, OPC_SLTU, TCG_TMP0, rl, (rl == bl ? al : bl));
         }
-        break;
-    default:
-        tcg_abort();
+        tcg_out_opc_reg(s, OPC_ADDU, rh, th, TCG_TMP0);
     }
+}
 
+static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is_64)
+{
+    TCGReg addr_regl, addr_regh __attribute__((unused));
+    TCGReg data_regl, data_regh, base;
+    TCGMemOp opc;
 #if defined(CONFIG_SOFTMMU)
-    reloc_pc16(label2_ptr, s->code_ptr);
+    tcg_insn_unit *label_ptr[2];
+    int mem_index;
+    TCGMemOp s_bits;
 #endif
-}
 
-static void tcg_out_call(TCGContext *s, tcg_insn_unit *target)
-{
-    tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_T9, (intptr_t)target);
-    tcg_out_opc_reg(s, OPC_JALR, TCG_REG_RA, TCG_REG_T9, 0);
-    tcg_out_nop(s);
+    data_regl = *args++;
+    data_regh = (is_64 ? *args++ : 0);
+    addr_regl = *args++;
+    addr_regh = (TARGET_LONG_BITS == 64 ? *args++ : 0);
+    opc = *args++;
+
+#if defined(CONFIG_SOFTMMU)
+    mem_index = *args;
+    s_bits = opc & 3;
+
+    /* Note that we eliminated the helper's address argument,
+       so we can reuse that for the base.  */
+    base = (TARGET_LONG_BITS == 32 ? TCG_REG_A1 : TCG_REG_A2);
+    tcg_out_tlb_load(s, base, addr_regl, addr_regh, mem_index,
+                     s_bits, label_ptr, 1);
+    tcg_out_qemu_st_direct(s, data_regl, data_regh, base, opc);
+    add_qemu_ldst_label(s, 0, opc, data_regl, data_regh, addr_regl, addr_regh,
+                        mem_index, s->code_ptr, label_ptr);
+#else
+    if (GUEST_BASE == 0) {
+        base = addr_regl;
+    } else {
+        base = TCG_REG_A0;
+        if (GUEST_BASE == (int16_t)GUEST_BASE) {
+            tcg_out_opc_imm(s, OPC_ADDIU, base, addr_regl, GUEST_BASE);
+        } else {
+            tcg_out_movi(s, TCG_TYPE_PTR, base, GUEST_BASE);
+            tcg_out_opc_reg(s, OPC_ADDU, base, base, addr_regl);
+        }
+    }
+    tcg_out_qemu_st_direct(s, data_regl, data_regh, base, opc);
+#endif
 }
 
 static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
                               const TCGArg *args, const int *const_args)
 {
-    switch(opc) {
+    MIPSInsn i1, i2;
+    TCGArg a0, a1, a2;
+    int c2;
+
+    a0 = args[0];
+    a1 = args[1];
+    a2 = args[2];
+    c2 = const_args[2];
+
+    switch (opc) {
     case INDEX_op_exit_tb:
-        tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_V0, args[0]);
-        tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_AT, (uintptr_t)tb_ret_addr);
-        tcg_out_opc_reg(s, OPC_JR, 0, TCG_REG_AT, 0);
-        tcg_out_nop(s);
+        {
+            TCGReg b0 = TCG_REG_ZERO;
+
+            if (a0 & ~0xffff) {
+                tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_V0, a0 & ~0xffff);
+                b0 = TCG_REG_V0;
+            }
+            if (!tcg_out_opc_jmp(s, OPC_J, tb_ret_addr)) {
+                tcg_out_movi(s, TCG_TYPE_PTR, TCG_TMP0,
+                             (uintptr_t)tb_ret_addr);
+                tcg_out_opc_reg(s, OPC_JR, 0, TCG_TMP0, 0);
+            }
+            tcg_out_opc_imm(s, OPC_ORI, TCG_REG_V0, b0, a0 & 0xffff);
+        }
         break;
     case INDEX_op_goto_tb:
         if (s->tb_jmp_offset) {
             /* direct jump method */
-            tcg_abort();
+            s->tb_jmp_offset[a0] = tcg_current_code_size(s);
+            /* Avoid clobbering the address during retranslation.  */
+            tcg_out32(s, OPC_J | (*(uint32_t *)s->code_ptr & 0x3ffffff));
         } else {
             /* indirect jump method */
-            tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_AT,
-                         (uintptr_t)(s->tb_next + args[0]));
-            tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_AT, TCG_REG_AT, 0);
-            tcg_out_opc_reg(s, OPC_JR, 0, TCG_REG_AT, 0);
+            tcg_out_ld(s, TCG_TYPE_PTR, TCG_TMP0, TCG_REG_ZERO,
+                       (uintptr_t)(s->tb_next + a0));
+            tcg_out_opc_reg(s, OPC_JR, 0, TCG_TMP0, 0);
         }
         tcg_out_nop(s);
-        s->tb_next_offset[args[0]] = tcg_current_code_size(s);
+        s->tb_next_offset[a0] = tcg_current_code_size(s);
         break;
     case INDEX_op_br:
-        tcg_out_brcond(s, TCG_COND_EQ, TCG_REG_ZERO, TCG_REG_ZERO, args[0]);
+        tcg_out_brcond(s, TCG_COND_EQ, TCG_REG_ZERO, TCG_REG_ZERO, a0);
         break;
 
     case INDEX_op_ld8u_i32:
-        tcg_out_ldst(s, OPC_LBU, args[0], args[1], args[2]);
-        break;
+        i1 = OPC_LBU;
+        goto do_ldst;
     case INDEX_op_ld8s_i32:
-        tcg_out_ldst(s, OPC_LB, args[0], args[1], args[2]);
-        break;
+        i1 = OPC_LB;
+        goto do_ldst;
     case INDEX_op_ld16u_i32:
-        tcg_out_ldst(s, OPC_LHU, args[0], args[1], args[2]);
-        break;
+        i1 = OPC_LHU;
+        goto do_ldst;
     case INDEX_op_ld16s_i32:
-        tcg_out_ldst(s, OPC_LH, args[0], args[1], args[2]);
-        break;
+        i1 = OPC_LH;
+        goto do_ldst;
     case INDEX_op_ld_i32:
-        tcg_out_ldst(s, OPC_LW, args[0], args[1], args[2]);
-        break;
+        i1 = OPC_LW;
+        goto do_ldst;
     case INDEX_op_st8_i32:
-        tcg_out_ldst(s, OPC_SB, args[0], args[1], args[2]);
-        break;
+        i1 = OPC_SB;
+        goto do_ldst;
     case INDEX_op_st16_i32:
-        tcg_out_ldst(s, OPC_SH, args[0], args[1], args[2]);
-        break;
+        i1 = OPC_SH;
+        goto do_ldst;
     case INDEX_op_st_i32:
-        tcg_out_ldst(s, OPC_SW, args[0], args[1], args[2]);
+        i1 = OPC_SW;
+    do_ldst:
+        tcg_out_ldst(s, i1, a0, a1, a2);
         break;
 
     case INDEX_op_add_i32:
-        if (const_args[2]) {
-            tcg_out_opc_imm(s, OPC_ADDIU, args[0], args[1], args[2]);
-        } else {
-            tcg_out_opc_reg(s, OPC_ADDU, args[0], args[1], args[2]);
-        }
-        break;
-    case INDEX_op_add2_i32:
-        if (const_args[4]) {
-            tcg_out_opc_imm(s, OPC_ADDIU, TCG_REG_AT, args[2], args[4]);
-        } else {
-            tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_AT, args[2], args[4]);
-        }
-        tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_T0, TCG_REG_AT, args[2]);
-        if (const_args[5]) {
-            tcg_out_opc_imm(s, OPC_ADDIU, args[1], args[3], args[5]);
-        } else {
-             tcg_out_opc_reg(s, OPC_ADDU, args[1], args[3], args[5]);
+        i1 = OPC_ADDU, i2 = OPC_ADDIU;
+        goto do_binary;
+    case INDEX_op_or_i32:
+        i1 = OPC_OR, i2 = OPC_ORI;
+        goto do_binary;
+    case INDEX_op_xor_i32:
+        i1 = OPC_XOR, i2 = OPC_XORI;
+    do_binary:
+        if (c2) {
+            tcg_out_opc_imm(s, i2, a0, a1, a2);
+            break;
         }
-        tcg_out_opc_reg(s, OPC_ADDU, args[1], args[1], TCG_REG_T0);
-        tcg_out_mov(s, TCG_TYPE_I32, args[0], TCG_REG_AT);
+    do_binaryv:
+        tcg_out_opc_reg(s, i1, a0, a1, a2);
         break;
+
     case INDEX_op_sub_i32:
-        if (const_args[2]) {
-            tcg_out_opc_imm(s, OPC_ADDIU, args[0], args[1], -args[2]);
-        } else {
-            tcg_out_opc_reg(s, OPC_SUBU, args[0], args[1], args[2]);
+        if (c2) {
+            tcg_out_opc_imm(s, OPC_ADDIU, a0, a1, -a2);
+            break;
         }
-        break;
-    case INDEX_op_sub2_i32:
-        if (const_args[4]) {
-            tcg_out_opc_imm(s, OPC_ADDIU, TCG_REG_AT, args[2], -args[4]);
-        } else {
-            tcg_out_opc_reg(s, OPC_SUBU, TCG_REG_AT, args[2], args[4]);
-        }
-        tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_T0, args[2], TCG_REG_AT);
-        if (const_args[5]) {
-            tcg_out_opc_imm(s, OPC_ADDIU, args[1], args[3], -args[5]);
-        } else {
-             tcg_out_opc_reg(s, OPC_SUBU, args[1], args[3], args[5]);
+        i1 = OPC_SUBU;
+        goto do_binary;
+    case INDEX_op_and_i32:
+        if (c2 && a2 != (uint16_t)a2) {
+            int msb = ctz32(~a2) - 1;
+            assert(use_mips32r2_instructions);
+            assert(is_p2m1(a2));
+            tcg_out_opc_bf(s, OPC_EXT, a0, a1, msb, 0);
+            break;
         }
-        tcg_out_opc_reg(s, OPC_SUBU, args[1], args[1], TCG_REG_T0);
-        tcg_out_mov(s, TCG_TYPE_I32, args[0], TCG_REG_AT);
-        break;
+        i1 = OPC_AND, i2 = OPC_ANDI;
+        goto do_binary;
+    case INDEX_op_nor_i32:
+        i1 = OPC_NOR;
+        goto do_binaryv;
+
     case INDEX_op_mul_i32:
         if (use_mips32_instructions) {
-            tcg_out_opc_reg(s, OPC_MUL, args[0], args[1], args[2]);
-        } else {
-            tcg_out_opc_reg(s, OPC_MULT, 0, args[1], args[2]);
-            tcg_out_opc_reg(s, OPC_MFLO, args[0], 0, 0);
+            tcg_out_opc_reg(s, OPC_MUL, a0, a1, a2);
+            break;
         }
-        break;
-    case INDEX_op_muls2_i32:
-        tcg_out_opc_reg(s, OPC_MULT, 0, args[2], args[3]);
-        tcg_out_opc_reg(s, OPC_MFLO, args[0], 0, 0);
-        tcg_out_opc_reg(s, OPC_MFHI, args[1], 0, 0);
-        break;
-    case INDEX_op_mulu2_i32:
-        tcg_out_opc_reg(s, OPC_MULTU, 0, args[2], args[3]);
-        tcg_out_opc_reg(s, OPC_MFLO, args[0], 0, 0);
-        tcg_out_opc_reg(s, OPC_MFHI, args[1], 0, 0);
-        break;
+        i1 = OPC_MULT, i2 = OPC_MFLO;
+        goto do_hilo1;
     case INDEX_op_mulsh_i32:
-        tcg_out_opc_reg(s, OPC_MULT, 0, args[1], args[2]);
-        tcg_out_opc_reg(s, OPC_MFHI, args[0], 0, 0);
-        break;
+        i1 = OPC_MULT, i2 = OPC_MFHI;
+        goto do_hilo1;
     case INDEX_op_muluh_i32:
-        tcg_out_opc_reg(s, OPC_MULTU, 0, args[1], args[2]);
-        tcg_out_opc_reg(s, OPC_MFHI, args[0], 0, 0);
-        break;
+        i1 = OPC_MULTU, i2 = OPC_MFHI;
+        goto do_hilo1;
     case INDEX_op_div_i32:
-        tcg_out_opc_reg(s, OPC_DIV, 0, args[1], args[2]);
-        tcg_out_opc_reg(s, OPC_MFLO, args[0], 0, 0);
-        break;
+        i1 = OPC_DIV, i2 = OPC_MFLO;
+        goto do_hilo1;
     case INDEX_op_divu_i32:
-        tcg_out_opc_reg(s, OPC_DIVU, 0, args[1], args[2]);
-        tcg_out_opc_reg(s, OPC_MFLO, args[0], 0, 0);
-        break;
+        i1 = OPC_DIVU, i2 = OPC_MFLO;
+        goto do_hilo1;
     case INDEX_op_rem_i32:
-        tcg_out_opc_reg(s, OPC_DIV, 0, args[1], args[2]);
-        tcg_out_opc_reg(s, OPC_MFHI, args[0], 0, 0);
-        break;
+        i1 = OPC_DIV, i2 = OPC_MFHI;
+        goto do_hilo1;
     case INDEX_op_remu_i32:
-        tcg_out_opc_reg(s, OPC_DIVU, 0, args[1], args[2]);
-        tcg_out_opc_reg(s, OPC_MFHI, args[0], 0, 0);
+        i1 = OPC_DIVU, i2 = OPC_MFHI;
+    do_hilo1:
+        tcg_out_opc_reg(s, i1, 0, a1, a2);
+        tcg_out_opc_reg(s, i2, a0, 0, 0);
         break;
 
-    case INDEX_op_and_i32:
-        if (const_args[2]) {
-            tcg_out_opc_imm(s, OPC_ANDI, args[0], args[1], args[2]);
-        } else {
-            tcg_out_opc_reg(s, OPC_AND, args[0], args[1], args[2]);
-        }
-        break;
-    case INDEX_op_or_i32:
-        if (const_args[2]) {
-            tcg_out_opc_imm(s, OPC_ORI, args[0], args[1], args[2]);
-        } else {
-            tcg_out_opc_reg(s, OPC_OR, args[0], args[1], args[2]);
-        }
-        break;
-    case INDEX_op_nor_i32:
-        tcg_out_opc_reg(s, OPC_NOR, args[0], args[1], args[2]);
+    case INDEX_op_muls2_i32:
+        i1 = OPC_MULT;
+        goto do_hilo2;
+    case INDEX_op_mulu2_i32:
+        i1 = OPC_MULTU;
+    do_hilo2:
+        tcg_out_opc_reg(s, i1, 0, a2, args[3]);
+        tcg_out_opc_reg(s, OPC_MFLO, a0, 0, 0);
+        tcg_out_opc_reg(s, OPC_MFHI, a1, 0, 0);
         break;
+
     case INDEX_op_not_i32:
-        tcg_out_opc_reg(s, OPC_NOR, args[0], TCG_REG_ZERO, args[1]);
-        break;
-    case INDEX_op_xor_i32:
-        if (const_args[2]) {
-            tcg_out_opc_imm(s, OPC_XORI, args[0], args[1], args[2]);
-        } else {
-            tcg_out_opc_reg(s, OPC_XOR, args[0], args[1], args[2]);
-        }
+        i1 = OPC_NOR;
+        goto do_unary;
+    case INDEX_op_bswap16_i32:
+        i1 = OPC_WSBH;
+        goto do_unary;
+    case INDEX_op_ext8s_i32:
+        i1 = OPC_SEB;
+        goto do_unary;
+    case INDEX_op_ext16s_i32:
+        i1 = OPC_SEH;
+    do_unary:
+        tcg_out_opc_reg(s, i1, a0, TCG_REG_ZERO, a1);
         break;
 
     case INDEX_op_sar_i32:
-        if (const_args[2]) {
-            tcg_out_opc_sa(s, OPC_SRA, args[0], args[1], args[2]);
-        } else {
-            tcg_out_opc_reg(s, OPC_SRAV, args[0], args[2], args[1]);
-        }
-        break;
+        i1 = OPC_SRAV, i2 = OPC_SRA;
+        goto do_shift;
     case INDEX_op_shl_i32:
-        if (const_args[2]) {
-            tcg_out_opc_sa(s, OPC_SLL, args[0], args[1], args[2]);
-        } else {
-            tcg_out_opc_reg(s, OPC_SLLV, args[0], args[2], args[1]);
-        }
-        break;
+        i1 = OPC_SLLV, i2 = OPC_SLL;
+        goto do_shift;
     case INDEX_op_shr_i32:
-        if (const_args[2]) {
-            tcg_out_opc_sa(s, OPC_SRL, args[0], args[1], args[2]);
+        i1 = OPC_SRLV, i2 = OPC_SRL;
+        goto do_shift;
+    case INDEX_op_rotr_i32:
+        i1 = OPC_ROTRV, i2 = OPC_ROTR;
+    do_shift:
+        if (c2) {
+            tcg_out_opc_sa(s, i2, a0, a1, a2);
         } else {
-            tcg_out_opc_reg(s, OPC_SRLV, args[0], args[2], args[1]);
+            tcg_out_opc_reg(s, i1, a0, a2, a1);
         }
         break;
     case INDEX_op_rotl_i32:
-        if (const_args[2]) {
-            tcg_out_opc_sa(s, OPC_ROTR, args[0], args[1], 0x20 - args[2]);
-        } else {
-            tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_AT, 32);
-            tcg_out_opc_reg(s, OPC_SUBU, TCG_REG_AT, TCG_REG_AT, args[2]);
-            tcg_out_opc_reg(s, OPC_ROTRV, args[0], TCG_REG_AT, args[1]);
-        }
-        break;
-    case INDEX_op_rotr_i32:
-        if (const_args[2]) {
-            tcg_out_opc_sa(s, OPC_ROTR, args[0], args[1], args[2]);
+        if (c2) {
+            tcg_out_opc_sa(s, OPC_ROTR, a0, a1, 32 - a2);
         } else {
-            tcg_out_opc_reg(s, OPC_ROTRV, args[0], args[2], args[1]);
+            tcg_out_opc_reg(s, OPC_SUBU, TCG_TMP0, TCG_REG_ZERO, a2);
+            tcg_out_opc_reg(s, OPC_ROTRV, a0, TCG_TMP0, a1);
         }
         break;
 
-    case INDEX_op_bswap16_i32:
-        tcg_out_opc_reg(s, OPC_WSBH, args[0], 0, args[1]);
-        break;
     case INDEX_op_bswap32_i32:
-        tcg_out_opc_reg(s, OPC_WSBH, args[0], 0, args[1]);
-        tcg_out_opc_sa(s, OPC_ROTR, args[0], args[0], 16);
-        break;
-
-    case INDEX_op_ext8s_i32:
-        tcg_out_opc_reg(s, OPC_SEB, args[0], 0, args[1]);
-        break;
-    case INDEX_op_ext16s_i32:
-        tcg_out_opc_reg(s, OPC_SEH, args[0], 0, args[1]);
+        tcg_out_opc_reg(s, OPC_WSBH, a0, 0, a1);
+        tcg_out_opc_sa(s, OPC_ROTR, a0, a0, 16);
         break;
 
     case INDEX_op_deposit_i32:
-        tcg_out_opc_imm(s, OPC_INS, args[0], args[2],
-                        ((args[3] + args[4] - 1) << 11) | (args[3] << 6));
+        tcg_out_opc_bf(s, OPC_INS, a0, a2, args[3] + args[4] - 1, args[3]);
         break;
 
     case INDEX_op_brcond_i32:
-        tcg_out_brcond(s, args[2], args[0], args[1], args[3]);
+        tcg_out_brcond(s, a2, a0, a1, args[3]);
         break;
     case INDEX_op_brcond2_i32:
-        tcg_out_brcond2(s, args[4], args[0], args[1], args[2], args[3], args[5]);
+        tcg_out_brcond2(s, args[4], a0, a1, a2, args[3], args[5]);
         break;
 
     case INDEX_op_movcond_i32:
-        tcg_out_movcond(s, args[5], args[0], args[1], args[2], args[3]);
+        tcg_out_movcond(s, args[5], a0, a1, a2, args[3]);
         break;
 
     case INDEX_op_setcond_i32:
-        tcg_out_setcond(s, args[3], args[0], args[1], args[2]);
+        tcg_out_setcond(s, args[3], a0, a1, a2);
         break;
     case INDEX_op_setcond2_i32:
-        tcg_out_setcond2(s, args[5], args[0], args[1], args[2], args[3], args[4]);
+        tcg_out_setcond2(s, args[5], a0, a1, a2, args[3], args[4]);
         break;
 
-    case INDEX_op_qemu_ld8u:
-        tcg_out_qemu_ld(s, args, 0);
-        break;
-    case INDEX_op_qemu_ld8s:
-        tcg_out_qemu_ld(s, args, 0 | 4);
-        break;
-    case INDEX_op_qemu_ld16u:
-        tcg_out_qemu_ld(s, args, 1);
+    case INDEX_op_qemu_ld_i32:
+        tcg_out_qemu_ld(s, args, false);
         break;
-    case INDEX_op_qemu_ld16s:
-        tcg_out_qemu_ld(s, args, 1 | 4);
+    case INDEX_op_qemu_ld_i64:
+        tcg_out_qemu_ld(s, args, true);
         break;
-    case INDEX_op_qemu_ld32:
-        tcg_out_qemu_ld(s, args, 2);
+    case INDEX_op_qemu_st_i32:
+        tcg_out_qemu_st(s, args, false);
         break;
-    case INDEX_op_qemu_ld64:
-        tcg_out_qemu_ld(s, args, 3);
+    case INDEX_op_qemu_st_i64:
+        tcg_out_qemu_st(s, args, true);
         break;
-    case INDEX_op_qemu_st8:
-        tcg_out_qemu_st(s, args, 0);
-        break;
-    case INDEX_op_qemu_st16:
-        tcg_out_qemu_st(s, args, 1);
-        break;
-    case INDEX_op_qemu_st32:
-        tcg_out_qemu_st(s, args, 2);
+
+    case INDEX_op_add2_i32:
+        tcg_out_addsub2(s, a0, a1, a2, args[3], args[4], args[5],
+                        const_args[4], const_args[5], false);
         break;
-    case INDEX_op_qemu_st64:
-        tcg_out_qemu_st(s, args, 3);
+    case INDEX_op_sub2_i32:
+        tcg_out_addsub2(s, a0, a1, a2, args[3], args[4], args[5],
+                        const_args[4], const_args[5], true);
         break;
 
     case INDEX_op_mov_i32:  /* Always emitted via tcg_out_mov.  */
@@ -1561,9 +1598,9 @@ static const TCGTargetOpDef mips_op_defs[] = {
     { INDEX_op_divu_i32, { "r", "rZ", "rZ" } },
     { INDEX_op_rem_i32, { "r", "rZ", "rZ" } },
     { INDEX_op_remu_i32, { "r", "rZ", "rZ" } },
-    { INDEX_op_sub_i32, { "r", "rZ", "rJ" } },
+    { INDEX_op_sub_i32, { "r", "rZ", "rN" } },
 
-    { INDEX_op_and_i32, { "r", "rZ", "rI" } },
+    { INDEX_op_and_i32, { "r", "rZ", "rIK" } },
     { INDEX_op_nor_i32, { "r", "rZ", "rZ" } },
     { INDEX_op_not_i32, { "r", "rZ" } },
     { INDEX_op_or_i32, { "r", "rZ", "rIZ" } },
@@ -1588,34 +1625,20 @@ static const TCGTargetOpDef mips_op_defs[] = {
     { INDEX_op_setcond_i32, { "r", "rZ", "rZ" } },
     { INDEX_op_setcond2_i32, { "r", "rZ", "rZ", "rZ", "rZ" } },
 
-    { INDEX_op_add2_i32, { "r", "r", "rZ", "rZ", "rJ", "rJ" } },
-    { INDEX_op_sub2_i32, { "r", "r", "rZ", "rZ", "rJ", "rJ" } },
+    { INDEX_op_add2_i32, { "r", "r", "rZ", "rZ", "rN", "rN" } },
+    { INDEX_op_sub2_i32, { "r", "r", "rZ", "rZ", "rN", "rN" } },
     { INDEX_op_brcond2_i32, { "rZ", "rZ", "rZ", "rZ" } },
 
 #if TARGET_LONG_BITS == 32
-    { INDEX_op_qemu_ld8u, { "L", "lZ" } },
-    { INDEX_op_qemu_ld8s, { "L", "lZ" } },
-    { INDEX_op_qemu_ld16u, { "L", "lZ" } },
-    { INDEX_op_qemu_ld16s, { "L", "lZ" } },
-    { INDEX_op_qemu_ld32, { "L", "lZ" } },
-    { INDEX_op_qemu_ld64, { "L", "L", "lZ" } },
-
-    { INDEX_op_qemu_st8, { "SZ", "SZ" } },
-    { INDEX_op_qemu_st16, { "SZ", "SZ" } },
-    { INDEX_op_qemu_st32, { "SZ", "SZ" } },
-    { INDEX_op_qemu_st64, { "SZ", "SZ", "SZ" } },
+    { INDEX_op_qemu_ld_i32, { "L", "lZ" } },
+    { INDEX_op_qemu_st_i32, { "SZ", "SZ" } },
+    { INDEX_op_qemu_ld_i64, { "L", "L", "lZ" } },
+    { INDEX_op_qemu_st_i64, { "SZ", "SZ", "SZ" } },
 #else
-    { INDEX_op_qemu_ld8u, { "L", "lZ", "lZ" } },
-    { INDEX_op_qemu_ld8s, { "L", "lZ", "lZ" } },
-    { INDEX_op_qemu_ld16u, { "L", "lZ", "lZ" } },
-    { INDEX_op_qemu_ld16s, { "L", "lZ", "lZ" } },
-    { INDEX_op_qemu_ld32, { "L", "lZ", "lZ" } },
-    { INDEX_op_qemu_ld64, { "L", "L", "lZ", "lZ" } },
-
-    { INDEX_op_qemu_st8, { "SZ", "SZ", "SZ" } },
-    { INDEX_op_qemu_st16, { "SZ", "SZ", "SZ" } },
-    { INDEX_op_qemu_st32, { "SZ", "SZ", "SZ" } },
-    { INDEX_op_qemu_st64, { "SZ", "SZ", "SZ", "SZ" } },
+    { INDEX_op_qemu_ld_i32, { "L", "lZ", "lZ" } },
+    { INDEX_op_qemu_st_i32, { "SZ", "SZ", "SZ" } },
+    { INDEX_op_qemu_ld_i64, { "L", "L", "lZ", "lZ" } },
+    { INDEX_op_qemu_st_i64, { "SZ", "SZ", "SZ", "SZ" } },
 #endif
     { -1 },
 };
@@ -1629,7 +1652,7 @@ static int tcg_target_callee_save_regs[] = {
     TCG_REG_S5,
     TCG_REG_S6,
     TCG_REG_S7,
-    TCG_REG_FP,
+    TCG_REG_S8,
     TCG_REG_RA,       /* should be last for ABI compliance */
 };
 
@@ -1761,6 +1784,7 @@ static void tcg_target_init(TCGContext *s)
                    (1 << TCG_REG_A1) |
                    (1 << TCG_REG_A2) |
                    (1 << TCG_REG_A3) |
+                   (1 << TCG_REG_T0) |
                    (1 << TCG_REG_T1) |
                    (1 << TCG_REG_T2) |
                    (1 << TCG_REG_T3) |
@@ -1775,11 +1799,18 @@ static void tcg_target_init(TCGContext *s)
     tcg_regset_set_reg(s->reserved_regs, TCG_REG_ZERO); /* zero register */
     tcg_regset_set_reg(s->reserved_regs, TCG_REG_K0);   /* kernel use only */
     tcg_regset_set_reg(s->reserved_regs, TCG_REG_K1);   /* kernel use only */
-    tcg_regset_set_reg(s->reserved_regs, TCG_REG_AT);   /* internal use */
-    tcg_regset_set_reg(s->reserved_regs, TCG_REG_T0);   /* internal use */
+    tcg_regset_set_reg(s->reserved_regs, TCG_TMP0);     /* internal use */
+    tcg_regset_set_reg(s->reserved_regs, TCG_TMP1);     /* internal use */
     tcg_regset_set_reg(s->reserved_regs, TCG_REG_RA);   /* return address */
     tcg_regset_set_reg(s->reserved_regs, TCG_REG_SP);   /* stack pointer */
     tcg_regset_set_reg(s->reserved_regs, TCG_REG_GP);   /* global pointer */
 
     tcg_add_target_add_op_defs(mips_op_defs);
 }
+
+void tb_set_jmp_target1(uintptr_t jmp_addr, uintptr_t addr)
+{
+    uint32_t *ptr = (uint32_t *)jmp_addr;
+    *ptr = deposit32(*ptr, 0, 26, addr >> 2);
+    flush_icache_range(jmp_addr, jmp_addr + 4);
+}
diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h
index c6d2267d77..b5face8b4d 100644
--- a/tcg/mips/tcg-target.h
+++ b/tcg/mips/tcg-target.h
@@ -60,16 +60,14 @@ typedef enum {
     TCG_REG_K1,
     TCG_REG_GP,
     TCG_REG_SP,
-    TCG_REG_FP,
+    TCG_REG_S8,
     TCG_REG_RA,
-} TCGReg;
 
-#define TCG_CT_CONST_ZERO 0x100
-#define TCG_CT_CONST_U16  0x200
-#define TCG_CT_CONST_S16  0x400
+    TCG_REG_CALL_STACK = TCG_REG_SP,
+    TCG_AREG0 = TCG_REG_S0,
+} TCGReg;
 
 /* used for function call generation */
-#define TCG_REG_CALL_STACK TCG_REG_SP
 #define TCG_TARGET_STACK_ALIGN 8
 #define TCG_TARGET_CALL_STACK_OFFSET 16
 #define TCG_TARGET_CALL_ALIGN_ARGS 1
@@ -120,15 +118,13 @@ extern bool use_mips32r2_instructions;
 #define TCG_TARGET_HAS_ext16s_i32       use_mips32r2_instructions
 #define TCG_TARGET_HAS_rot_i32          use_mips32r2_instructions
 
-#define TCG_TARGET_HAS_new_ldst         0
+#define TCG_TARGET_HAS_new_ldst         1
 
 /* optional instructions automatically implemented */
 #define TCG_TARGET_HAS_neg_i32          0 /* sub  rd, zero, rt   */
 #define TCG_TARGET_HAS_ext8u_i32        0 /* andi rt, rs, 0xff   */
 #define TCG_TARGET_HAS_ext16u_i32       0 /* andi rt, rs, 0xffff */
 
-#define TCG_AREG0 TCG_REG_S0
-
 #ifdef __OpenBSD__
 #include <machine/sysarch.h>
 #else
diff --git a/tcg/optimize.c b/tcg/optimize.c
index 3a504a1961..77da2f942a 100644
--- a/tcg/optimize.c
+++ b/tcg/optimize.c
@@ -83,6 +83,20 @@ static int op_bits(TCGOpcode op)
     return def->flags & TCG_OPF_64BIT ? 64 : 32;
 }
 
+static TCGOpcode op_to_mov(TCGOpcode op)
+{
+    switch (op_bits(op)) {
+    case 32:
+        return INDEX_op_mov_i32;
+    case 64:
+        return INDEX_op_mov_i64;
+    default:
+        fprintf(stderr, "op_to_mov: unexpected return value of "
+                "function op_bits.\n");
+        tcg_abort();
+    }
+}
+
 static TCGOpcode op_to_movi(TCGOpcode op)
 {
     switch (op_bits(op)) {
@@ -148,11 +162,22 @@ static bool temps_are_copies(TCGArg arg1, TCGArg arg2)
     return false;
 }
 
-static void tcg_opt_gen_mov(TCGContext *s, TCGArg *gen_args,
-                            TCGArg dst, TCGArg src)
+static void tcg_opt_gen_mov(TCGContext *s, int op_index, TCGArg *gen_args,
+                            TCGOpcode old_op, TCGArg dst, TCGArg src)
 {
+    TCGOpcode new_op = op_to_mov(old_op);
+    tcg_target_ulong mask;
+
+    s->gen_opc_buf[op_index] = new_op;
+
     reset_temp(dst);
-    temps[dst].mask = temps[src].mask;
+    mask = temps[src].mask;
+    if (TCG_TARGET_REG_BITS > 32 && new_op == INDEX_op_mov_i32) {
+        /* High bits of the destination are now garbage.  */
+        mask |= ~0xffffffffull;
+    }
+    temps[dst].mask = mask;
+
     assert(temps[src].state != TCG_TEMP_CONST);
 
     if (s->temps[src].type == s->temps[dst].type) {
@@ -172,30 +197,28 @@ static void tcg_opt_gen_mov(TCGContext *s, TCGArg *gen_args,
     gen_args[1] = src;
 }
 
-static void tcg_opt_gen_movi(TCGArg *gen_args, TCGArg dst, TCGArg val)
+static void tcg_opt_gen_movi(TCGContext *s, int op_index, TCGArg *gen_args,
+                             TCGOpcode old_op, TCGArg dst, TCGArg val)
 {
+    TCGOpcode new_op = op_to_movi(old_op);
+    tcg_target_ulong mask;
+
+    s->gen_opc_buf[op_index] = new_op;
+
     reset_temp(dst);
     temps[dst].state = TCG_TEMP_CONST;
     temps[dst].val = val;
-    temps[dst].mask = val;
+    mask = val;
+    if (TCG_TARGET_REG_BITS > 32 && new_op == INDEX_op_mov_i32) {
+        /* High bits of the destination are now garbage.  */
+        mask |= ~0xffffffffull;
+    }
+    temps[dst].mask = mask;
+
     gen_args[0] = dst;
     gen_args[1] = val;
 }
 
-static TCGOpcode op_to_mov(TCGOpcode op)
-{
-    switch (op_bits(op)) {
-    case 32:
-        return INDEX_op_mov_i32;
-    case 64:
-        return INDEX_op_mov_i64;
-    default:
-        fprintf(stderr, "op_to_mov: unexpected return value of "
-                "function op_bits.\n");
-        tcg_abort();
-    }
-}
-
 static TCGArg do_constant_folding_2(TCGOpcode op, TCGArg x, TCGArg y)
 {
     uint64_t l64, h64;
@@ -530,7 +553,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
     for (op_index = 0; op_index < nb_ops; op_index++) {
         TCGOpcode op = s->gen_opc_buf[op_index];
         const TCGOpDef *def = &tcg_op_defs[op];
-        tcg_target_ulong mask, affected;
+        tcg_target_ulong mask, partmask, affected;
         int nb_oargs, nb_iargs, nb_args, i;
         TCGArg tmp;
 
@@ -619,8 +642,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
         CASE_OP_32_64(rotr):
             if (temps[args[1]].state == TCG_TEMP_CONST
                 && temps[args[1]].val == 0) {
-                s->gen_opc_buf[op_index] = op_to_movi(op);
-                tcg_opt_gen_movi(gen_args, args[0], 0);
+                tcg_opt_gen_movi(s, op_index, gen_args, op, args[0], 0);
                 args += 3;
                 gen_args += 2;
                 continue;
@@ -749,8 +771,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
             if (temps_are_copies(args[0], args[1])) {
                 s->gen_opc_buf[op_index] = INDEX_op_nop;
             } else {
-                s->gen_opc_buf[op_index] = op_to_mov(op);
-                tcg_opt_gen_mov(s, gen_args, args[0], args[1]);
+                tcg_opt_gen_mov(s, op_index, gen_args, op, args[0], args[1]);
                 gen_args += 2;
             }
             args += 3;
@@ -859,6 +880,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
             break;
 
         CASE_OP_32_64(setcond):
+        case INDEX_op_setcond2_i32:
             mask = 1;
             break;
 
@@ -894,16 +916,20 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
             break;
         }
 
-        /* 32-bit ops (non 64-bit ops and non load/store ops) generate 32-bit
-           results */
+        /* 32-bit ops (non 64-bit ops and non load/store ops) generate
+           32-bit results.  For the result is zero test below, we can
+           ignore high bits, but for further optimizations we need to
+           record that the high bits contain garbage.  */
+        partmask = mask;
         if (!(def->flags & (TCG_OPF_CALL_CLOBBER | TCG_OPF_64BIT))) {
-            mask &= 0xffffffffu;
+            mask |= ~(tcg_target_ulong)0xffffffffu;
+            partmask &= 0xffffffffu;
+            affected &= 0xffffffffu;
         }
 
-        if (mask == 0) {
+        if (partmask == 0) {
             assert(nb_oargs == 1);
-            s->gen_opc_buf[op_index] = op_to_movi(op);
-            tcg_opt_gen_movi(gen_args, args[0], 0);
+            tcg_opt_gen_movi(s, op_index, gen_args, op, args[0], 0);
             args += nb_args;
             gen_args += 2;
             continue;
@@ -913,12 +939,11 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
             if (temps_are_copies(args[0], args[1])) {
                 s->gen_opc_buf[op_index] = INDEX_op_nop;
             } else if (temps[args[1]].state != TCG_TEMP_CONST) {
-                s->gen_opc_buf[op_index] = op_to_mov(op);
-                tcg_opt_gen_mov(s, gen_args, args[0], args[1]);
+                tcg_opt_gen_mov(s, op_index, gen_args, op, args[0], args[1]);
                 gen_args += 2;
             } else {
-                s->gen_opc_buf[op_index] = op_to_movi(op);
-                tcg_opt_gen_movi(gen_args, args[0], temps[args[1]].val);
+                tcg_opt_gen_movi(s, op_index, gen_args, op,
+                                 args[0], temps[args[1]].val);
                 gen_args += 2;
             }
             args += nb_args;
@@ -933,8 +958,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
         CASE_OP_32_64(mulsh):
             if ((temps[args[2]].state == TCG_TEMP_CONST
                 && temps[args[2]].val == 0)) {
-                s->gen_opc_buf[op_index] = op_to_movi(op);
-                tcg_opt_gen_movi(gen_args, args[0], 0);
+                tcg_opt_gen_movi(s, op_index, gen_args, op, args[0], 0);
                 args += 3;
                 gen_args += 2;
                 continue;
@@ -952,8 +976,8 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
                 if (temps_are_copies(args[0], args[1])) {
                     s->gen_opc_buf[op_index] = INDEX_op_nop;
                 } else {
-                    s->gen_opc_buf[op_index] = op_to_mov(op);
-                    tcg_opt_gen_mov(s, gen_args, args[0], args[1]);
+                    tcg_opt_gen_mov(s, op_index, gen_args, op,
+                                    args[0], args[1]);
                     gen_args += 2;
                 }
                 args += 3;
@@ -970,8 +994,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
         CASE_OP_32_64(sub):
         CASE_OP_32_64(xor):
             if (temps_are_copies(args[1], args[2])) {
-                s->gen_opc_buf[op_index] = op_to_movi(op);
-                tcg_opt_gen_movi(gen_args, args[0], 0);
+                tcg_opt_gen_movi(s, op_index, gen_args, op, args[0], 0);
                 gen_args += 2;
                 args += 3;
                 continue;
@@ -992,19 +1015,17 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
                 break;
             }
             if (temps[args[1]].state != TCG_TEMP_CONST) {
-                tcg_opt_gen_mov(s, gen_args, args[0], args[1]);
+                tcg_opt_gen_mov(s, op_index, gen_args, op, args[0], args[1]);
                 gen_args += 2;
                 args += 2;
                 break;
             }
             /* Source argument is constant.  Rewrite the operation and
                let movi case handle it. */
-            op = op_to_movi(op);
-            s->gen_opc_buf[op_index] = op;
             args[1] = temps[args[1]].val;
             /* fallthrough */
         CASE_OP_32_64(movi):
-            tcg_opt_gen_movi(gen_args, args[0], args[1]);
+            tcg_opt_gen_movi(s, op_index, gen_args, op, args[0], args[1]);
             gen_args += 2;
             args += 2;
             break;
@@ -1018,9 +1039,8 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
         case INDEX_op_ext32s_i64:
         case INDEX_op_ext32u_i64:
             if (temps[args[1]].state == TCG_TEMP_CONST) {
-                s->gen_opc_buf[op_index] = op_to_movi(op);
                 tmp = do_constant_folding(op, temps[args[1]].val, 0);
-                tcg_opt_gen_movi(gen_args, args[0], tmp);
+                tcg_opt_gen_movi(s, op_index, gen_args, op, args[0], tmp);
                 gen_args += 2;
                 args += 2;
                 break;
@@ -1029,9 +1049,8 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
 
         case INDEX_op_trunc_shr_i32:
             if (temps[args[1]].state == TCG_TEMP_CONST) {
-                s->gen_opc_buf[op_index] = op_to_movi(op);
                 tmp = do_constant_folding(op, temps[args[1]].val, args[2]);
-                tcg_opt_gen_movi(gen_args, args[0], tmp);
+                tcg_opt_gen_movi(s, op_index, gen_args, op, args[0], tmp);
                 gen_args += 2;
                 args += 3;
                 break;
@@ -1062,10 +1081,9 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
         CASE_OP_32_64(remu):
             if (temps[args[1]].state == TCG_TEMP_CONST
                 && temps[args[2]].state == TCG_TEMP_CONST) {
-                s->gen_opc_buf[op_index] = op_to_movi(op);
                 tmp = do_constant_folding(op, temps[args[1]].val,
                                           temps[args[2]].val);
-                tcg_opt_gen_movi(gen_args, args[0], tmp);
+                tcg_opt_gen_movi(s, op_index, gen_args, op, args[0], tmp);
                 gen_args += 2;
                 args += 3;
                 break;
@@ -1075,10 +1093,9 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
         CASE_OP_32_64(deposit):
             if (temps[args[1]].state == TCG_TEMP_CONST
                 && temps[args[2]].state == TCG_TEMP_CONST) {
-                s->gen_opc_buf[op_index] = op_to_movi(op);
                 tmp = deposit64(temps[args[1]].val, args[3], args[4],
                                 temps[args[2]].val);
-                tcg_opt_gen_movi(gen_args, args[0], tmp);
+                tcg_opt_gen_movi(s, op_index, gen_args, op, args[0], tmp);
                 gen_args += 2;
                 args += 5;
                 break;
@@ -1088,8 +1105,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
         CASE_OP_32_64(setcond):
             tmp = do_constant_folding_cond(op, args[1], args[2], args[3]);
             if (tmp != 2) {
-                s->gen_opc_buf[op_index] = op_to_movi(op);
-                tcg_opt_gen_movi(gen_args, args[0], tmp);
+                tcg_opt_gen_movi(s, op_index, gen_args, op, args[0], tmp);
                 gen_args += 2;
                 args += 4;
                 break;
@@ -1118,12 +1134,12 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
                 if (temps_are_copies(args[0], args[4-tmp])) {
                     s->gen_opc_buf[op_index] = INDEX_op_nop;
                 } else if (temps[args[4-tmp]].state == TCG_TEMP_CONST) {
-                    s->gen_opc_buf[op_index] = op_to_movi(op);
-                    tcg_opt_gen_movi(gen_args, args[0], temps[args[4-tmp]].val);
+                    tcg_opt_gen_movi(s, op_index, gen_args, op,
+                                     args[0], temps[args[4-tmp]].val);
                     gen_args += 2;
                 } else {
-                    s->gen_opc_buf[op_index] = op_to_mov(op);
-                    tcg_opt_gen_mov(s, gen_args, args[0], args[4-tmp]);
+                    tcg_opt_gen_mov(s, op_index, gen_args, op,
+                                    args[0], args[4-tmp]);
                     gen_args += 2;
                 }
                 args += 6;
@@ -1156,10 +1172,10 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
 
                 rl = args[0];
                 rh = args[1];
-                s->gen_opc_buf[op_index] = INDEX_op_movi_i32;
-                s->gen_opc_buf[++op_index] = INDEX_op_movi_i32;
-                tcg_opt_gen_movi(&gen_args[0], rl, (uint32_t)a);
-                tcg_opt_gen_movi(&gen_args[2], rh, (uint32_t)(a >> 32));
+                tcg_opt_gen_movi(s, op_index, &gen_args[0],
+                                 op, rl, (uint32_t)a);
+                tcg_opt_gen_movi(s, ++op_index, &gen_args[2],
+                                 op, rh, (uint32_t)(a >> 32));
                 gen_args += 4;
                 args += 6;
                 break;
@@ -1179,10 +1195,10 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
 
                 rl = args[0];
                 rh = args[1];
-                s->gen_opc_buf[op_index] = INDEX_op_movi_i32;
-                s->gen_opc_buf[++op_index] = INDEX_op_movi_i32;
-                tcg_opt_gen_movi(&gen_args[0], rl, (uint32_t)r);
-                tcg_opt_gen_movi(&gen_args[2], rh, (uint32_t)(r >> 32));
+                tcg_opt_gen_movi(s, op_index, &gen_args[0],
+                                 op, rl, (uint32_t)r);
+                tcg_opt_gen_movi(s, ++op_index, &gen_args[2],
+                                 op, rh, (uint32_t)(r >> 32));
                 gen_args += 4;
                 args += 4;
                 break;
@@ -1193,11 +1209,13 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
             tmp = do_constant_folding_cond2(&args[0], &args[2], args[4]);
             if (tmp != 2) {
                 if (tmp) {
+            do_brcond_true:
                     reset_all_temps(nb_temps);
                     s->gen_opc_buf[op_index] = INDEX_op_br;
                     gen_args[0] = args[5];
                     gen_args += 1;
                 } else {
+            do_brcond_false:
                     s->gen_opc_buf[op_index] = INDEX_op_nop;
                 }
             } else if ((args[4] == TCG_COND_LT || args[4] == TCG_COND_GE)
@@ -1207,6 +1225,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
                        && temps[args[3]].val == 0) {
                 /* Simplify LT/GE comparisons vs zero to a single compare
                    vs the high word of the input.  */
+            do_brcond_high:
                 reset_all_temps(nb_temps);
                 s->gen_opc_buf[op_index] = INDEX_op_brcond_i32;
                 gen_args[0] = args[1];
@@ -1214,6 +1233,49 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
                 gen_args[2] = args[4];
                 gen_args[3] = args[5];
                 gen_args += 4;
+            } else if (args[4] == TCG_COND_EQ) {
+                /* Simplify EQ comparisons where one of the pairs
+                   can be simplified.  */
+                tmp = do_constant_folding_cond(INDEX_op_brcond_i32,
+                                               args[0], args[2], TCG_COND_EQ);
+                if (tmp == 0) {
+                    goto do_brcond_false;
+                } else if (tmp == 1) {
+                    goto do_brcond_high;
+                }
+                tmp = do_constant_folding_cond(INDEX_op_brcond_i32,
+                                               args[1], args[3], TCG_COND_EQ);
+                if (tmp == 0) {
+                    goto do_brcond_false;
+                } else if (tmp != 1) {
+                    goto do_default;
+                }
+            do_brcond_low:
+                reset_all_temps(nb_temps);
+                s->gen_opc_buf[op_index] = INDEX_op_brcond_i32;
+                gen_args[0] = args[0];
+                gen_args[1] = args[2];
+                gen_args[2] = args[4];
+                gen_args[3] = args[5];
+                gen_args += 4;
+            } else if (args[4] == TCG_COND_NE) {
+                /* Simplify NE comparisons where one of the pairs
+                   can be simplified.  */
+                tmp = do_constant_folding_cond(INDEX_op_brcond_i32,
+                                               args[0], args[2], TCG_COND_NE);
+                if (tmp == 0) {
+                    goto do_brcond_high;
+                } else if (tmp == 1) {
+                    goto do_brcond_true;
+                }
+                tmp = do_constant_folding_cond(INDEX_op_brcond_i32,
+                                               args[1], args[3], TCG_COND_NE);
+                if (tmp == 0) {
+                    goto do_brcond_low;
+                } else if (tmp == 1) {
+                    goto do_brcond_true;
+                }
+                goto do_default;
             } else {
                 goto do_default;
             }
@@ -1223,8 +1285,8 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
         case INDEX_op_setcond2_i32:
             tmp = do_constant_folding_cond2(&args[1], &args[3], args[5]);
             if (tmp != 2) {
-                s->gen_opc_buf[op_index] = INDEX_op_movi_i32;
-                tcg_opt_gen_movi(gen_args, args[0], tmp);
+            do_setcond_const:
+                tcg_opt_gen_movi(s, op_index, gen_args, op, args[0], tmp);
                 gen_args += 2;
             } else if ((args[5] == TCG_COND_LT || args[5] == TCG_COND_GE)
                        && temps[args[3]].state == TCG_TEMP_CONST
@@ -1233,13 +1295,59 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
                        && temps[args[4]].val == 0) {
                 /* Simplify LT/GE comparisons vs zero to a single compare
                    vs the high word of the input.  */
+            do_setcond_high:
                 s->gen_opc_buf[op_index] = INDEX_op_setcond_i32;
                 reset_temp(args[0]);
+                temps[args[0]].mask = 1;
                 gen_args[0] = args[0];
                 gen_args[1] = args[2];
                 gen_args[2] = args[4];
                 gen_args[3] = args[5];
                 gen_args += 4;
+            } else if (args[5] == TCG_COND_EQ) {
+                /* Simplify EQ comparisons where one of the pairs
+                   can be simplified.  */
+                tmp = do_constant_folding_cond(INDEX_op_setcond_i32,
+                                               args[1], args[3], TCG_COND_EQ);
+                if (tmp == 0) {
+                    goto do_setcond_const;
+                } else if (tmp == 1) {
+                    goto do_setcond_high;
+                }
+                tmp = do_constant_folding_cond(INDEX_op_setcond_i32,
+                                               args[2], args[4], TCG_COND_EQ);
+                if (tmp == 0) {
+                    goto do_setcond_high;
+                } else if (tmp != 1) {
+                    goto do_default;
+                }
+            do_setcond_low:
+                reset_temp(args[0]);
+                temps[args[0]].mask = 1;
+                s->gen_opc_buf[op_index] = INDEX_op_setcond_i32;
+                gen_args[0] = args[0];
+                gen_args[1] = args[1];
+                gen_args[2] = args[3];
+                gen_args[3] = args[5];
+                gen_args += 4;
+            } else if (args[5] == TCG_COND_NE) {
+                /* Simplify NE comparisons where one of the pairs
+                   can be simplified.  */
+                tmp = do_constant_folding_cond(INDEX_op_setcond_i32,
+                                               args[1], args[3], TCG_COND_NE);
+                if (tmp == 0) {
+                    goto do_setcond_high;
+                } else if (tmp == 1) {
+                    goto do_setcond_const;
+                }
+                tmp = do_constant_folding_cond(INDEX_op_setcond_i32,
+                                               args[2], args[4], TCG_COND_NE);
+                if (tmp == 0) {
+                    goto do_setcond_low;
+                } else if (tmp == 1) {
+                    goto do_setcond_const;
+                }
+                goto do_default;
             } else {
                 goto do_default;
             }
diff --git a/tcg/s390/tcg-target.c b/tcg/s390/tcg-target.c
index 07164e544d..63e9c82cb3 100644
--- a/tcg/s390/tcg-target.c
+++ b/tcg/s390/tcg-target.c
@@ -2344,8 +2344,7 @@ static void tcg_target_qemu_prologue(TCGContext *s)
 }
 
 typedef struct {
-    DebugFrameCIE cie;
-    DebugFrameFDEHeader fde;
+    DebugFrameHeader h;
     uint8_t fde_def_cfa[4];
     uint8_t fde_reg_ofs[18];
 } DebugFrame;
@@ -2355,16 +2354,16 @@ QEMU_BUILD_BUG_ON(FRAME_SIZE >= (1 << 14));
 
 #define ELF_HOST_MACHINE  EM_S390
 
-static DebugFrame debug_frame = {
-    .cie.len = sizeof(DebugFrameCIE)-4, /* length after .len member */
-    .cie.id = -1,
-    .cie.version = 1,
-    .cie.code_align = 1,
-    .cie.data_align = 8,                /* sleb128 8 */
-    .cie.return_column = TCG_REG_R14,
+static const DebugFrame debug_frame = {
+    .h.cie.len = sizeof(DebugFrameCIE)-4, /* length after .len member */
+    .h.cie.id = -1,
+    .h.cie.version = 1,
+    .h.cie.code_align = 1,
+    .h.cie.data_align = 8,                /* sleb128 8 */
+    .h.cie.return_column = TCG_REG_R14,
 
     /* Total FDE size does not include the "len" member.  */
-    .fde.len = sizeof(DebugFrame) - offsetof(DebugFrame, fde.cie_offset),
+    .h.fde.len = sizeof(DebugFrame) - offsetof(DebugFrame, h.fde.cie_offset),
 
     .fde_def_cfa = {
         12, TCG_REG_CALL_STACK,         /* DW_CFA_def_cfa %r15, ... */
@@ -2386,8 +2385,5 @@ static DebugFrame debug_frame = {
 
 void tcg_register_jit(void *buf, size_t buf_size)
 {
-    debug_frame.fde.func_start = (uintptr_t)buf;
-    debug_frame.fde.func_len = buf_size;
-
     tcg_register_jit_int(buf, buf_size, &debug_frame, sizeof(debug_frame));
 }
diff --git a/tcg/sparc/tcg-target.c b/tcg/sparc/tcg-target.c
index 17ff5773ad..40f2ec1027 100644
--- a/tcg/sparc/tcg-target.c
+++ b/tcg/sparc/tcg-target.c
@@ -1499,23 +1499,22 @@ static void tcg_target_init(TCGContext *s)
 #endif
 
 typedef struct {
-    DebugFrameCIE cie;
-    DebugFrameFDEHeader fde;
+    DebugFrameHeader h;
     uint8_t fde_def_cfa[SPARC64 ? 4 : 2];
     uint8_t fde_win_save;
     uint8_t fde_ret_save[3];
 } DebugFrame;
 
-static DebugFrame debug_frame = {
-    .cie.len = sizeof(DebugFrameCIE)-4, /* length after .len member */
-    .cie.id = -1,
-    .cie.version = 1,
-    .cie.code_align = 1,
-    .cie.data_align = -sizeof(void *) & 0x7f,
-    .cie.return_column = 15,            /* o7 */
+static const DebugFrame debug_frame = {
+    .h.cie.len = sizeof(DebugFrameCIE)-4, /* length after .len member */
+    .h.cie.id = -1,
+    .h.cie.version = 1,
+    .h.cie.code_align = 1,
+    .h.cie.data_align = -sizeof(void *) & 0x7f,
+    .h.cie.return_column = 15,            /* o7 */
 
     /* Total FDE size does not include the "len" member.  */
-    .fde.len = sizeof(DebugFrame) - offsetof(DebugFrame, fde.cie_offset),
+    .h.fde.len = sizeof(DebugFrame) - offsetof(DebugFrame, h.fde.cie_offset),
 
     .fde_def_cfa = {
 #if SPARC64
@@ -1531,9 +1530,6 @@ static DebugFrame debug_frame = {
 
 void tcg_register_jit(void *buf, size_t buf_size)
 {
-    debug_frame.fde.func_start = (uintptr_t)buf;
-    debug_frame.fde.func_len = buf_size;
-
     tcg_register_jit_int(buf, buf_size, &debug_frame, sizeof(debug_frame));
 }
 
diff --git a/tcg/tcg-op.h b/tcg/tcg-op.h
index bdd0139482..719533ac39 100644
--- a/tcg/tcg-op.h
+++ b/tcg/tcg-op.h
@@ -22,6 +22,8 @@
  * THE SOFTWARE.
  */
 #include "tcg.h"
+#include "exec/helper-proto.h"
+#include "exec/helper-gen.h"
 
 int gen_new_label(void);
 
@@ -379,47 +381,6 @@ static inline void tcg_gen_movi_i32(TCGv_i32 ret, int32_t arg)
     tcg_gen_op2i_i32(INDEX_op_movi_i32, ret, arg);
 }
 
-/* A version of dh_sizemask from def-helper.h that doesn't rely on
-   preprocessor magic.  */
-static inline int tcg_gen_sizemask(int n, int is_64bit, int is_signed)
-{
-    return (is_64bit << n*2) | (is_signed << (n*2 + 1));
-}
-
-/* helper calls */
-static inline void tcg_gen_helperN(void *func, int flags, int sizemask,
-                                   TCGArg ret, int nargs, TCGArg *args)
-{
-    tcg_gen_callN(&tcg_ctx, func, flags, sizemask, ret, nargs, args);
-}
-
-/* Note: Both tcg_gen_helper32() and tcg_gen_helper64() are currently
-   reserved for helpers in tcg-runtime.c. These helpers all do not read
-   globals and do not have side effects, hence the call to tcg_gen_callN()
-   with TCG_CALL_NO_READ_GLOBALS | TCG_CALL_NO_SIDE_EFFECTS. This may need
-   to be adjusted if these functions start to be used with other helpers. */
-static inline void tcg_gen_helper32(void *func, int sizemask, TCGv_i32 ret,
-                                    TCGv_i32 a, TCGv_i32 b)
-{
-    TCGArg args[2];
-    args[0] = GET_TCGV_I32(a);
-    args[1] = GET_TCGV_I32(b);
-    tcg_gen_callN(&tcg_ctx, func,
-                  TCG_CALL_NO_READ_GLOBALS | TCG_CALL_NO_SIDE_EFFECTS,
-                  sizemask, GET_TCGV_I32(ret), 2, args);
-}
-
-static inline void tcg_gen_helper64(void *func, int sizemask, TCGv_i64 ret,
-                                    TCGv_i64 a, TCGv_i64 b)
-{
-    TCGArg args[2];
-    args[0] = GET_TCGV_I64(a);
-    args[1] = GET_TCGV_I64(b);
-    tcg_gen_callN(&tcg_ctx, func,
-                  TCG_CALL_NO_READ_GLOBALS | TCG_CALL_NO_SIDE_EFFECTS,
-                  sizemask, GET_TCGV_I64(ret), 2, args);
-}
-
 /* 32 bit ops */
 
 static inline void tcg_gen_ld8u_i32(TCGv_i32 ret, TCGv_ptr arg2, tcg_target_long offset)
@@ -707,12 +668,7 @@ static inline void tcg_gen_div_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
         tcg_gen_op5_i32(INDEX_op_div2_i32, ret, t0, arg1, t0, arg2);
         tcg_temp_free_i32(t0);
     } else {
-        int sizemask = 0;
-        /* Return value and both arguments are 32-bit and signed.  */
-        sizemask |= tcg_gen_sizemask(0, 0, 1);
-        sizemask |= tcg_gen_sizemask(1, 0, 1);
-        sizemask |= tcg_gen_sizemask(2, 0, 1);
-        tcg_gen_helper32(tcg_helper_div_i32, sizemask, ret, arg1, arg2);
+        gen_helper_div_i32(ret, arg1, arg2);
     }
 }
 
@@ -732,12 +688,7 @@ static inline void tcg_gen_rem_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
         tcg_gen_op5_i32(INDEX_op_div2_i32, t0, ret, arg1, t0, arg2);
         tcg_temp_free_i32(t0);
     } else {
-        int sizemask = 0;
-        /* Return value and both arguments are 32-bit and signed.  */
-        sizemask |= tcg_gen_sizemask(0, 0, 1);
-        sizemask |= tcg_gen_sizemask(1, 0, 1);
-        sizemask |= tcg_gen_sizemask(2, 0, 1);
-        tcg_gen_helper32(tcg_helper_rem_i32, sizemask, ret, arg1, arg2);
+        gen_helper_rem_i32(ret, arg1, arg2);
     }
 }
 
@@ -751,12 +702,7 @@ static inline void tcg_gen_divu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
         tcg_gen_op5_i32(INDEX_op_divu2_i32, ret, t0, arg1, t0, arg2);
         tcg_temp_free_i32(t0);
     } else {
-        int sizemask = 0;
-        /* Return value and both arguments are 32-bit and unsigned.  */
-        sizemask |= tcg_gen_sizemask(0, 0, 0);
-        sizemask |= tcg_gen_sizemask(1, 0, 0);
-        sizemask |= tcg_gen_sizemask(2, 0, 0);
-        tcg_gen_helper32(tcg_helper_divu_i32, sizemask, ret, arg1, arg2);
+        gen_helper_divu_i32(ret, arg1, arg2);
     }
 }
 
@@ -776,12 +722,7 @@ static inline void tcg_gen_remu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
         tcg_gen_op5_i32(INDEX_op_divu2_i32, t0, ret, arg1, t0, arg2);
         tcg_temp_free_i32(t0);
     } else {
-        int sizemask = 0;
-        /* Return value and both arguments are 32-bit and unsigned.  */
-        sizemask |= tcg_gen_sizemask(0, 0, 0);
-        sizemask |= tcg_gen_sizemask(1, 0, 0);
-        sizemask |= tcg_gen_sizemask(2, 0, 0);
-        tcg_gen_helper32(tcg_helper_remu_i32, sizemask, ret, arg1, arg2);
+        gen_helper_remu_i32(ret, arg1, arg2);
     }
 }
 
@@ -945,13 +886,7 @@ static inline void tcg_gen_xori_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
    specific code (x86) */
 static inline void tcg_gen_shl_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
 {
-    int sizemask = 0;
-    /* Return value and both arguments are 64-bit and signed.  */
-    sizemask |= tcg_gen_sizemask(0, 1, 1);
-    sizemask |= tcg_gen_sizemask(1, 1, 1);
-    sizemask |= tcg_gen_sizemask(2, 1, 1);
-
-    tcg_gen_helper64(tcg_helper_shl_i64, sizemask, ret, arg1, arg2);
+    gen_helper_shl_i64(ret, arg1, arg2);
 }
 
 static inline void tcg_gen_shli_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
@@ -961,13 +896,7 @@ static inline void tcg_gen_shli_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
 
 static inline void tcg_gen_shr_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
 {
-    int sizemask = 0;
-    /* Return value and both arguments are 64-bit and signed.  */
-    sizemask |= tcg_gen_sizemask(0, 1, 1);
-    sizemask |= tcg_gen_sizemask(1, 1, 1);
-    sizemask |= tcg_gen_sizemask(2, 1, 1);
-
-    tcg_gen_helper64(tcg_helper_shr_i64, sizemask, ret, arg1, arg2);
+    gen_helper_shr_i64(ret, arg1, arg2);
 }
 
 static inline void tcg_gen_shri_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
@@ -977,13 +906,7 @@ static inline void tcg_gen_shri_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
 
 static inline void tcg_gen_sar_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
 {
-    int sizemask = 0;
-    /* Return value and both arguments are 64-bit and signed.  */
-    sizemask |= tcg_gen_sizemask(0, 1, 1);
-    sizemask |= tcg_gen_sizemask(1, 1, 1);
-    sizemask |= tcg_gen_sizemask(2, 1, 1);
-
-    tcg_gen_helper64(tcg_helper_sar_i64, sizemask, ret, arg1, arg2);
+    gen_helper_sar_i64(ret, arg1, arg2);
 }
 
 static inline void tcg_gen_sari_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2)
@@ -1051,46 +974,22 @@ static inline void tcg_gen_mul_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
 
 static inline void tcg_gen_div_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
 {
-    int sizemask = 0;
-    /* Return value and both arguments are 64-bit and signed.  */
-    sizemask |= tcg_gen_sizemask(0, 1, 1);
-    sizemask |= tcg_gen_sizemask(1, 1, 1);
-    sizemask |= tcg_gen_sizemask(2, 1, 1);
-
-    tcg_gen_helper64(tcg_helper_div_i64, sizemask, ret, arg1, arg2);
+    gen_helper_div_i64(ret, arg1, arg2);
 }
 
 static inline void tcg_gen_rem_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
 {
-    int sizemask = 0;
-    /* Return value and both arguments are 64-bit and signed.  */
-    sizemask |= tcg_gen_sizemask(0, 1, 1);
-    sizemask |= tcg_gen_sizemask(1, 1, 1);
-    sizemask |= tcg_gen_sizemask(2, 1, 1);
-
-    tcg_gen_helper64(tcg_helper_rem_i64, sizemask, ret, arg1, arg2);
+    gen_helper_rem_i64(ret, arg1, arg2);
 }
 
 static inline void tcg_gen_divu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
 {
-    int sizemask = 0;
-    /* Return value and both arguments are 64-bit and unsigned.  */
-    sizemask |= tcg_gen_sizemask(0, 1, 0);
-    sizemask |= tcg_gen_sizemask(1, 1, 0);
-    sizemask |= tcg_gen_sizemask(2, 1, 0);
-
-    tcg_gen_helper64(tcg_helper_divu_i64, sizemask, ret, arg1, arg2);
+    gen_helper_divu_i64(ret, arg1, arg2);
 }
 
 static inline void tcg_gen_remu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
 {
-    int sizemask = 0;
-    /* Return value and both arguments are 64-bit and unsigned.  */
-    sizemask |= tcg_gen_sizemask(0, 1, 0);
-    sizemask |= tcg_gen_sizemask(1, 1, 0);
-    sizemask |= tcg_gen_sizemask(2, 1, 0);
-
-    tcg_gen_helper64(tcg_helper_remu_i64, sizemask, ret, arg1, arg2);
+    gen_helper_remu_i64(ret, arg1, arg2);
 }
 
 #else
@@ -1357,12 +1256,7 @@ static inline void tcg_gen_div_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
         tcg_gen_op5_i64(INDEX_op_div2_i64, ret, t0, arg1, t0, arg2);
         tcg_temp_free_i64(t0);
     } else {
-        int sizemask = 0;
-        /* Return value and both arguments are 64-bit and signed.  */
-        sizemask |= tcg_gen_sizemask(0, 1, 1);
-        sizemask |= tcg_gen_sizemask(1, 1, 1);
-        sizemask |= tcg_gen_sizemask(2, 1, 1);
-        tcg_gen_helper64(tcg_helper_div_i64, sizemask, ret, arg1, arg2);
+        gen_helper_div_i64(ret, arg1, arg2);
     }
 }
 
@@ -1382,12 +1276,7 @@ static inline void tcg_gen_rem_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
         tcg_gen_op5_i64(INDEX_op_div2_i64, t0, ret, arg1, t0, arg2);
         tcg_temp_free_i64(t0);
     } else {
-        int sizemask = 0;
-        /* Return value and both arguments are 64-bit and signed.  */
-        sizemask |= tcg_gen_sizemask(0, 1, 1);
-        sizemask |= tcg_gen_sizemask(1, 1, 1);
-        sizemask |= tcg_gen_sizemask(2, 1, 1);
-        tcg_gen_helper64(tcg_helper_rem_i64, sizemask, ret, arg1, arg2);
+        gen_helper_rem_i64(ret, arg1, arg2);
     }
 }
 
@@ -1401,12 +1290,7 @@ static inline void tcg_gen_divu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
         tcg_gen_op5_i64(INDEX_op_divu2_i64, ret, t0, arg1, t0, arg2);
         tcg_temp_free_i64(t0);
     } else {
-        int sizemask = 0;
-        /* Return value and both arguments are 64-bit and unsigned.  */
-        sizemask |= tcg_gen_sizemask(0, 1, 0);
-        sizemask |= tcg_gen_sizemask(1, 1, 0);
-        sizemask |= tcg_gen_sizemask(2, 1, 0);
-        tcg_gen_helper64(tcg_helper_divu_i64, sizemask, ret, arg1, arg2);
+        gen_helper_divu_i64(ret, arg1, arg2);
     }
 }
 
@@ -1426,12 +1310,7 @@ static inline void tcg_gen_remu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2)
         tcg_gen_op5_i64(INDEX_op_divu2_i64, t0, ret, arg1, t0, arg2);
         tcg_temp_free_i64(t0);
     } else {
-        int sizemask = 0;
-        /* Return value and both arguments are 64-bit and unsigned.  */
-        sizemask |= tcg_gen_sizemask(0, 1, 0);
-        sizemask |= tcg_gen_sizemask(1, 1, 0);
-        sizemask |= tcg_gen_sizemask(2, 1, 0);
-        tcg_gen_helper64(tcg_helper_remu_i64, sizemask, ret, arg1, arg2);
+        gen_helper_remu_i64(ret, arg1, arg2);
     }
 }
 #endif /* TCG_TARGET_REG_BITS == 32 */
@@ -2530,13 +2409,8 @@ static inline void tcg_gen_mulu2_i64(TCGv_i64 rl, TCGv_i64 rh,
         tcg_temp_free_i64(t);
     } else {
         TCGv_i64 t0 = tcg_temp_new_i64();
-        int sizemask = 0;
-        /* Return value and both arguments are 64-bit and unsigned.  */
-        sizemask |= tcg_gen_sizemask(0, 1, 0);
-        sizemask |= tcg_gen_sizemask(1, 1, 0);
-        sizemask |= tcg_gen_sizemask(2, 1, 0);
         tcg_gen_mul_i64(t0, arg1, arg2);
-        tcg_gen_helper64(tcg_helper_muluh_i64, sizemask, rh, arg1, arg2);
+        gen_helper_muluh_i64(rh, arg1, arg2);
         tcg_gen_mov_i64(rl, t0);
         tcg_temp_free_i64(t0);
     }
@@ -2575,13 +2449,8 @@ static inline void tcg_gen_muls2_i64(TCGv_i64 rl, TCGv_i64 rh,
         tcg_temp_free_i64(t3);
     } else {
         TCGv_i64 t0 = tcg_temp_new_i64();
-        int sizemask = 0;
-        /* Return value and both arguments are 64-bit and signed.  */
-        sizemask |= tcg_gen_sizemask(0, 1, 1);
-        sizemask |= tcg_gen_sizemask(1, 1, 1);
-        sizemask |= tcg_gen_sizemask(2, 1, 1);
         tcg_gen_mul_i64(t0, arg1, arg2);
-        tcg_gen_helper64(tcg_helper_mulsh_i64, sizemask, rh, arg1, arg2);
+        gen_helper_mulsh_i64(rh, arg1, arg2);
         tcg_gen_mov_i64(rl, t0);
         tcg_temp_free_i64(t0);
     }
diff --git a/tcg/tcg-runtime.h b/tcg/tcg-runtime.h
index a1ebef9f9c..23a0c37711 100644
--- a/tcg/tcg-runtime.h
+++ b/tcg/tcg-runtime.h
@@ -1,20 +1,16 @@
-#ifndef TCG_RUNTIME_H
-#define TCG_RUNTIME_H
+DEF_HELPER_FLAGS_2(div_i32, TCG_CALL_NO_RWG_SE, s32, s32, s32)
+DEF_HELPER_FLAGS_2(rem_i32, TCG_CALL_NO_RWG_SE, s32, s32, s32)
+DEF_HELPER_FLAGS_2(divu_i32, TCG_CALL_NO_RWG_SE, i32, i32, i32)
+DEF_HELPER_FLAGS_2(remu_i32, TCG_CALL_NO_RWG_SE, i32, i32, i32)
 
-/* tcg-runtime.c */
-int32_t tcg_helper_div_i32(int32_t arg1, int32_t arg2);
-int32_t tcg_helper_rem_i32(int32_t arg1, int32_t arg2);
-uint32_t tcg_helper_divu_i32(uint32_t arg1, uint32_t arg2);
-uint32_t tcg_helper_remu_i32(uint32_t arg1, uint32_t arg2);
+DEF_HELPER_FLAGS_2(div_i64, TCG_CALL_NO_RWG_SE, s64, s64, s64)
+DEF_HELPER_FLAGS_2(rem_i64, TCG_CALL_NO_RWG_SE, s64, s64, s64)
+DEF_HELPER_FLAGS_2(divu_i64, TCG_CALL_NO_RWG_SE, i64, i64, i64)
+DEF_HELPER_FLAGS_2(remu_i64, TCG_CALL_NO_RWG_SE, i64, i64, i64)
 
-int64_t tcg_helper_shl_i64(int64_t arg1, int64_t arg2);
-int64_t tcg_helper_shr_i64(int64_t arg1, int64_t arg2);
-int64_t tcg_helper_sar_i64(int64_t arg1, int64_t arg2);
-int64_t tcg_helper_div_i64(int64_t arg1, int64_t arg2);
-int64_t tcg_helper_rem_i64(int64_t arg1, int64_t arg2);
-int64_t tcg_helper_mulsh_i64(int64_t arg1, int64_t arg2);
-uint64_t tcg_helper_divu_i64(uint64_t arg1, uint64_t arg2);
-uint64_t tcg_helper_remu_i64(uint64_t arg1, uint64_t arg2);
-uint64_t tcg_helper_muluh_i64(uint64_t arg1, uint64_t arg2);
+DEF_HELPER_FLAGS_2(shl_i64, TCG_CALL_NO_RWG_SE, i64, i64, i64)
+DEF_HELPER_FLAGS_2(shr_i64, TCG_CALL_NO_RWG_SE, i64, i64, i64)
+DEF_HELPER_FLAGS_2(sar_i64, TCG_CALL_NO_RWG_SE, s64, s64, s64)
 
-#endif
+DEF_HELPER_FLAGS_2(mulsh_i64, TCG_CALL_NO_RWG_SE, s64, s64, s64)
+DEF_HELPER_FLAGS_2(muluh_i64, TCG_CALL_NO_RWG_SE, i64, i64, i64)
diff --git a/tcg/tcg.c b/tcg/tcg.c
index ea8aa70c16..2c5732da17 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -86,8 +86,14 @@ typedef struct QEMU_PACKED {
     uintptr_t func_len;
 } DebugFrameFDEHeader;
 
+typedef struct QEMU_PACKED {
+    DebugFrameCIE cie;
+    DebugFrameFDEHeader fde;
+} DebugFrameHeader;
+
 static void tcg_register_jit_int(void *buf, size_t size,
-                                 void *debug_frame, size_t debug_frame_size)
+                                 const void *debug_frame,
+                                 size_t debug_frame_size)
     __attribute__((unused));
 
 /* Forward declarations for functions declared and used in tcg-target.c. */
@@ -307,32 +313,17 @@ void tcg_pool_reset(TCGContext *s)
     s->pool_current = NULL;
 }
 
-#include "helper.h"
-
 typedef struct TCGHelperInfo {
     void *func;
     const char *name;
+    unsigned flags;
+    unsigned sizemask;
 } TCGHelperInfo;
 
+#include "exec/helper-proto.h"
+
 static const TCGHelperInfo all_helpers[] = {
-#define GEN_HELPER 2
-#include "helper.h"
-
-    /* Include tcg-runtime.c functions.  */
-    { tcg_helper_div_i32, "div_i32" },
-    { tcg_helper_rem_i32, "rem_i32" },
-    { tcg_helper_divu_i32, "divu_i32" },
-    { tcg_helper_remu_i32, "remu_i32" },
-
-    { tcg_helper_shl_i64, "shl_i64" },
-    { tcg_helper_shr_i64, "shr_i64" },
-    { tcg_helper_sar_i64, "sar_i64" },
-    { tcg_helper_div_i64, "div_i64" },
-    { tcg_helper_rem_i64, "rem_i64" },
-    { tcg_helper_divu_i64, "divu_i64" },
-    { tcg_helper_remu_i64, "remu_i64" },
-    { tcg_helper_mulsh_i64, "mulsh_i64" },
-    { tcg_helper_muluh_i64, "muluh_i64" },
+#include "exec/helper-tcg.h"
 };
 
 void tcg_context_init(TCGContext *s)
@@ -373,7 +364,7 @@ void tcg_context_init(TCGContext *s)
 
     for (i = 0; i < ARRAY_SIZE(all_helpers); ++i) {
         g_hash_table_insert(helper_table, (gpointer)all_helpers[i].func,
-                            (gpointer)all_helpers[i].name);
+                            (gpointer)&all_helpers[i]);
     }
 
     tcg_target_init(s);
@@ -706,13 +697,17 @@ int tcg_check_temp_count(void)
 /* Note: we convert the 64 bit args to 32 bit and do some alignment
    and endian swap. Maybe it would be better to do the alignment
    and endian swap in tcg_reg_alloc_call(). */
-void tcg_gen_callN(TCGContext *s, void *func, unsigned int flags,
-                   int sizemask, TCGArg ret, int nargs, TCGArg *args)
+void tcg_gen_callN(TCGContext *s, void *func, TCGArg ret,
+                   int nargs, TCGArg *args)
 {
-    int i;
-    int real_args;
-    int nb_rets;
+    int i, real_args, nb_rets;
+    unsigned sizemask, flags;
     TCGArg *nparam;
+    TCGHelperInfo *info;
+
+    info = g_hash_table_lookup(s->helpers, (gpointer)func);
+    flags = info->flags;
+    sizemask = info->sizemask;
 
 #if defined(__sparc__) && !defined(__arch64__) \
     && !defined(CONFIG_TCG_INTERPRETER)
@@ -798,9 +793,8 @@ void tcg_gen_callN(TCGContext *s, void *func, unsigned int flags,
     }
     real_args = 0;
     for (i = 0; i < nargs; i++) {
-#if TCG_TARGET_REG_BITS < 64
         int is_64bit = sizemask & (1 << (i+1)*2);
-        if (is_64bit) {
+        if (TCG_TARGET_REG_BITS < 64 && is_64bit) {
 #ifdef TCG_TARGET_CALL_ALIGN_ARGS
             /* some targets want aligned 64 bit args */
             if (real_args & 1) {
@@ -828,7 +822,6 @@ void tcg_gen_callN(TCGContext *s, void *func, unsigned int flags,
             real_args += 2;
             continue;
         }
-#endif /* TCG_TARGET_REG_BITS < 64 */
 
         *s->gen_opparam_ptr++ = args[i];
         real_args++;
@@ -1166,7 +1159,10 @@ static inline const char *tcg_find_helper(TCGContext *s, uintptr_t val)
 {
     const char *ret = NULL;
     if (s->helpers) {
-        ret = g_hash_table_lookup(s->helpers, (gpointer)val);
+        TCGHelperInfo *info = g_hash_table_lookup(s->helpers, (gpointer)val);
+        if (info) {
+            ret = info->name;
+        }
     }
     return ret;
 }
@@ -2787,7 +2783,8 @@ static int find_string(const char *strtab, const char *str)
 }
 
 static void tcg_register_jit_int(void *buf_ptr, size_t buf_size,
-                                 void *debug_frame, size_t debug_frame_size)
+                                 const void *debug_frame,
+                                 size_t debug_frame_size)
 {
     struct __attribute__((packed)) DebugInfo {
         uint32_t  len;
@@ -2925,10 +2922,10 @@ static void tcg_register_jit_int(void *buf_ptr, size_t buf_size,
 
     uintptr_t buf = (uintptr_t)buf_ptr;
     size_t img_size = sizeof(struct ElfImage) + debug_frame_size;
+    DebugFrameHeader *dfh;
 
     img = g_malloc(img_size);
     *img = img_template;
-    memcpy(img + 1, debug_frame, debug_frame_size);
 
     img->phdr.p_vaddr = buf;
     img->phdr.p_paddr = buf;
@@ -2956,6 +2953,11 @@ static void tcg_register_jit_int(void *buf_ptr, size_t buf_size,
     img->di.fn_low_pc = buf;
     img->di.fn_high_pc = buf + buf_size;
 
+    dfh = (DebugFrameHeader *)(img + 1);
+    memcpy(dfh, debug_frame, debug_frame_size);
+    dfh->fde.func_start = buf;
+    dfh->fde.func_len = buf_size;
+
 #ifdef DEBUG_JIT
     /* Enable this block to be able to debug the ELF image file creation.
        One can use readelf, objdump, or other inspection utilities.  */
@@ -2983,7 +2985,8 @@ static void tcg_register_jit_int(void *buf_ptr, size_t buf_size,
    and implement the internal function we declared earlier.  */
 
 static void tcg_register_jit_int(void *buf, size_t size,
-                                 void *debug_frame, size_t debug_frame_size)
+                                 const void *debug_frame,
+                                 size_t debug_frame_size)
 {
 }
 
diff --git a/tcg/tcg.h b/tcg/tcg.h
index fbc93101cf..2efa333166 100644
--- a/tcg/tcg.h
+++ b/tcg/tcg.h
@@ -54,8 +54,6 @@ typedef uint64_t tcg_target_ulong;
 #error unsupported
 #endif
 
-#include "tcg-runtime.h"
-
 #if TCG_TARGET_NB_REGS <= 32
 typedef uint32_t TCGRegSet;
 #elif TCG_TARGET_NB_REGS <= 64
@@ -725,8 +723,8 @@ void tcg_add_target_add_op_defs(const TCGTargetOpDef *tdefs);
 #define tcg_temp_free_ptr(T) tcg_temp_free_i64(TCGV_PTR_TO_NAT(T))
 #endif
 
-void tcg_gen_callN(TCGContext *s, void *func, unsigned int flags,
-                   int sizemask, TCGArg ret, int nargs, TCGArg *args);
+void tcg_gen_callN(TCGContext *s, void *func,
+                   TCGArg ret, int nargs, TCGArg *args);
 
 void tcg_gen_shifti_i64(TCGv_i64 ret, TCGv_i64 arg1,
                         int c, int right, int arith);
diff --git a/tcg/tci/tcg-target.c b/tcg/tci/tcg-target.c
index 9b39231c15..375e590d2b 100644
--- a/tcg/tci/tcg-target.c
+++ b/tcg/tci/tcg-target.c
@@ -544,7 +544,10 @@ static void tcg_out_movi(TCGContext *s, TCGType type,
 
 static inline void tcg_out_call(TCGContext *s, tcg_insn_unit *arg)
 {
+    uint8_t *old_code_ptr = s->code_ptr;
+    tcg_out_op_t(s, INDEX_op_call);
     tcg_out_ri(s, 1, (uintptr_t)arg);
+    old_code_ptr[1] = s->code_ptr - old_code_ptr;
 }
 
 static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
diff --git a/tests/Makefile b/tests/Makefile
index 6b8b6f273a..6b294a7dbc 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -60,6 +60,8 @@ check-unit-y += tests/test-qdev-global-props$(EXESUF)
 check-unit-y += tests/check-qom-interface$(EXESUF)
 gcov-files-check-qom-interface-y = qom/object.c
 check-unit-$(CONFIG_POSIX) += tests/test-vmstate$(EXESUF)
+check-unit-y += tests/test-qemu-opts$(EXESUF)
+gcov-files-test-qemu-opts-y = qom/test-qemu-opts.c
 
 check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh
 
@@ -152,6 +154,8 @@ gcov-files-i386-y += hw/pci-bridge/ioh3420.c
 check-qtest-i386-y += tests/usb-hcd-ehci-test$(EXESUF)
 gcov-files-i386-y += hw/usb/hcd-ehci.c
 gcov-files-i386-y += hw/usb/hcd-uhci.c
+gcov-files-i386-y += hw/usb/dev-hid.c
+gcov-files-i386-y += hw/usb/dev-storage.c
 check-qtest-x86_64-y = $(check-qtest-i386-y)
 gcov-files-i386-y += i386-softmmu/hw/timer/mc146818rtc.c
 gcov-files-x86_64-y = $(subst i386-softmmu/,x86_64-softmmu/,$(gcov-files-i386-y))
@@ -193,7 +197,8 @@ check-qapi-schema-y := $(addprefix tests/qapi-schema/, \
         flat-union-string-discriminator.json \
         include-simple.json include-relpath.json include-format-err.json \
         include-non-file.json include-no-file.json include-before-err.json \
-        include-nested-err.json include-self-cycle.json include-cycle.json)
+        include-nested-err.json include-self-cycle.json include-cycle.json \
+        include-repetition.json)
 
 GENERATED_HEADERS += tests/test-qapi-types.h tests/test-qapi-visit.h tests/test-qmp-commands.h
 
@@ -316,8 +321,9 @@ tests/ac97-test$(EXESUF): tests/ac97-test.o
 tests/es1370-test$(EXESUF): tests/es1370-test.o
 tests/intel-hda-test$(EXESUF): tests/intel-hda-test.o
 tests/ioh3420-test$(EXESUF): tests/ioh3420-test.o
-tests/usb-hcd-ehci-test$(EXESUF): tests/usb-hcd-ehci-test.o
+tests/usb-hcd-ehci-test$(EXESUF): tests/usb-hcd-ehci-test.o $(libqos-pc-obj-y)
 tests/qemu-iotests/socket_scm_helper$(EXESUF): tests/qemu-iotests/socket_scm_helper.o
+tests/test-qemu-opts$(EXESUF): tests/test-qemu-opts.o libqemuutil.a libqemustub.a
 
 # QTest rules
 
diff --git a/tests/check-qdict.c b/tests/check-qdict.c
index 2ad0f7827e..a9296f0833 100644
--- a/tests/check-qdict.c
+++ b/tests/check-qdict.c
@@ -444,6 +444,92 @@ static void qdict_array_split_test(void)
     QDECREF(test_dict);
 }
 
+static void qdict_join_test(void)
+{
+    QDict *dict1, *dict2;
+    bool overwrite = false;
+    int i;
+
+    dict1 = qdict_new();
+    dict2 = qdict_new();
+
+
+    /* Test everything once without overwrite and once with */
+    do
+    {
+        /* Test empty dicts */
+        qdict_join(dict1, dict2, overwrite);
+
+        g_assert(qdict_size(dict1) == 0);
+        g_assert(qdict_size(dict2) == 0);
+
+
+        /* First iteration: Test movement */
+        /* Second iteration: Test empty source and non-empty destination */
+        qdict_put(dict2, "foo", qint_from_int(42));
+
+        for (i = 0; i < 2; i++) {
+            qdict_join(dict1, dict2, overwrite);
+
+            g_assert(qdict_size(dict1) == 1);
+            g_assert(qdict_size(dict2) == 0);
+
+            g_assert(qdict_get_int(dict1, "foo") == 42);
+        }
+
+
+        /* Test non-empty source and destination without conflict */
+        qdict_put(dict2, "bar", qint_from_int(23));
+
+        qdict_join(dict1, dict2, overwrite);
+
+        g_assert(qdict_size(dict1) == 2);
+        g_assert(qdict_size(dict2) == 0);
+
+        g_assert(qdict_get_int(dict1, "foo") == 42);
+        g_assert(qdict_get_int(dict1, "bar") == 23);
+
+
+        /* Test conflict */
+        qdict_put(dict2, "foo", qint_from_int(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, "bar") == 23);
+
+        if (!overwrite) {
+            g_assert(qdict_get_int(dict2, "foo") == 84);
+        }
+
+
+        /* Check the references */
+        g_assert(qdict_get(dict1, "foo")->refcnt == 1);
+        g_assert(qdict_get(dict1, "bar")->refcnt == 1);
+
+        if (!overwrite) {
+            g_assert(qdict_get(dict2, "foo")->refcnt == 1);
+        }
+
+
+        /* Clean up */
+        qdict_del(dict1, "foo");
+        qdict_del(dict1, "bar");
+
+        if (!overwrite) {
+            qdict_del(dict2, "foo");
+        }
+    }
+    while (overwrite ^= true);
+
+
+    QDECREF(dict1);
+    QDECREF(dict2);
+}
+
 /*
  * Errors test-cases
  */
@@ -584,6 +670,7 @@ int main(int argc, char **argv)
     g_test_add_func("/public/iterapi", qdict_iterapi_test);
     g_test_add_func("/public/flatten", qdict_flatten_test);
     g_test_add_func("/public/array_split", qdict_array_split_test);
+    g_test_add_func("/public/join", qdict_join_test);
 
     g_test_add_func("/errors/put_exists", qdict_put_exists_test);
     g_test_add_func("/errors/get_not_exists", qdict_get_not_exists_test);
diff --git a/tests/libqos/pci.c b/tests/libqos/pci.c
index 7e0907b514..c9a0b9134a 100644
--- a/tests/libqos/pci.c
+++ b/tests/libqos/pci.c
@@ -103,7 +103,7 @@ void qpci_config_writew(QPCIDevice *dev, uint8_t offset, uint16_t value)
 
 void qpci_config_writel(QPCIDevice *dev, uint8_t offset, uint32_t value)
 {
-    dev->bus->config_writew(dev->bus, dev->devfn, offset, value);
+    dev->bus->config_writel(dev->bus, dev->devfn, offset, value);
 }
 
 
diff --git a/tests/qapi-schema/include-repetition-sub.json b/tests/qapi-schema/include-repetition-sub.json
new file mode 100644
index 0000000000..6bfffdfd55
--- /dev/null
+++ b/tests/qapi-schema/include-repetition-sub.json
@@ -0,0 +1,2 @@
+{ 'include': 'comments.json' }
+{ 'include': 'comments.json' }
diff --git a/tests/qapi-schema/include-repetition.err b/tests/qapi-schema/include-repetition.err
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/qapi-schema/include-repetition.err
diff --git a/tests/qapi-schema/include-repetition.exit b/tests/qapi-schema/include-repetition.exit
new file mode 100644
index 0000000000..573541ac97
--- /dev/null
+++ b/tests/qapi-schema/include-repetition.exit
@@ -0,0 +1 @@
+0
diff --git a/tests/qapi-schema/include-repetition.json b/tests/qapi-schema/include-repetition.json
new file mode 100644
index 0000000000..ec329dde58
--- /dev/null
+++ b/tests/qapi-schema/include-repetition.json
@@ -0,0 +1,3 @@
+{ 'include': 'comments.json' }
+{ 'include': 'include-repetition-sub.json' }
+{ 'include': 'comments.json' }
diff --git a/tests/qapi-schema/include-repetition.out b/tests/qapi-schema/include-repetition.out
new file mode 100644
index 0000000000..4ce3dcf12f
--- /dev/null
+++ b/tests/qapi-schema/include-repetition.out
@@ -0,0 +1,3 @@
+[OrderedDict([('enum', 'Status'), ('data', ['good', 'bad', 'ugly'])])]
+[{'enum_name': 'Status', 'enum_values': ['good', 'bad', 'ugly']}]
+[]
diff --git a/tests/qemu-iotests/030 b/tests/qemu-iotests/030
index 8cb61fd7ec..8ce2373cf5 100755
--- a/tests/qemu-iotests/030
+++ b/tests/qemu-iotests/030
@@ -35,7 +35,7 @@ class TestSingleDrive(iotests.QMPTestCase):
         qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, mid_img)
         qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % mid_img, test_img)
         qemu_io('-c', 'write -P 0x1 0 512', backing_img)
-        self.vm = iotests.VM().add_drive(test_img)
+        self.vm = iotests.VM().add_drive("blkdebug::" + test_img)
         self.vm.launch()
 
     def tearDown(self):
diff --git a/tests/qemu-iotests/039 b/tests/qemu-iotests/039
index b9cbe99560..27fe4bdacc 100755
--- a/tests/qemu-iotests/039
+++ b/tests/qemu-iotests/039
@@ -47,6 +47,11 @@ _supported_os Linux
 _default_cache_mode "writethrough"
 _supported_cache_modes "writethrough"
 
+_no_dump_exec()
+{
+    (ulimit -c 0; exec "$@")
+}
+
 size=128M
 
 echo
@@ -67,10 +72,7 @@ echo "== Creating a dirty image file =="
 IMGOPTS="compat=1.1,lazy_refcounts=on"
 _make_test_img $size
 
-old_ulimit=$(ulimit -c)
-ulimit -c 0 # do not produce a core dump on abort(3)
-$QEMU_IO -c "write -P 0x5a 0 512" -c "abort" "$TEST_IMG" | _filter_qemu_io
-ulimit -c "$old_ulimit"
+_no_dump_exec $QEMU_IO -c "write -P 0x5a 0 512" -c "abort" "$TEST_IMG" 2>&1 | _filter_qemu_io
 
 # The dirty bit must be set
 ./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
@@ -103,10 +105,7 @@ echo "== Opening a dirty image read/write should repair it =="
 IMGOPTS="compat=1.1,lazy_refcounts=on"
 _make_test_img $size
 
-old_ulimit=$(ulimit -c)
-ulimit -c 0 # do not produce a core dump on abort(3)
-$QEMU_IO -c "write -P 0x5a 0 512" -c "abort" "$TEST_IMG" | _filter_qemu_io
-ulimit -c "$old_ulimit"
+_no_dump_exec $QEMU_IO -c "write -P 0x5a 0 512" -c "abort" "$TEST_IMG" 2>&1 | _filter_qemu_io
 
 # The dirty bit must be set
 ./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
@@ -122,10 +121,7 @@ echo "== Creating an image file with lazy_refcounts=off =="
 IMGOPTS="compat=1.1,lazy_refcounts=off"
 _make_test_img $size
 
-old_ulimit=$(ulimit -c)
-ulimit -c 0 # do not produce a core dump on abort(3)
-$QEMU_IO -c "write -P 0x5a 0 512" -c "abort" "$TEST_IMG" | _filter_qemu_io
-ulimit -c "$old_ulimit"
+_no_dump_exec $QEMU_IO -c "write -P 0x5a 0 512" -c "abort" "$TEST_IMG" 2>&1 | _filter_qemu_io
 
 # The dirty bit must not be set since lazy_refcounts=off
 ./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
diff --git a/tests/qemu-iotests/039.out b/tests/qemu-iotests/039.out
index fb31ae0624..67e774430f 100644
--- a/tests/qemu-iotests/039.out
+++ b/tests/qemu-iotests/039.out
@@ -11,6 +11,7 @@ No errors were found on the image.
 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 
 wrote 512/512 bytes at offset 0
 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+./039: Aborted                 ( ulimit -c 0; exec "$@" )
 incompatible_features     0x1
 ERROR cluster 5 refcount=0 reference=1
 ERROR OFLAG_COPIED data cluster: l2_entry=8000000000050000 refcount=0
@@ -42,6 +43,7 @@ read 512/512 bytes at offset 0
 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 
 wrote 512/512 bytes at offset 0
 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+./039: Aborted                 ( ulimit -c 0; exec "$@" )
 incompatible_features     0x1
 Repairing cluster 5 refcount=0 reference=1
 wrote 512/512 bytes at offset 0
@@ -52,6 +54,7 @@ incompatible_features     0x0
 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 
 wrote 512/512 bytes at offset 0
 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+./039: Aborted                 ( ulimit -c 0; exec "$@" )
 incompatible_features     0x0
 No errors were found on the image.
 
diff --git a/tests/qemu-iotests/067.out b/tests/qemu-iotests/067.out
index 8d271cc41a..7e090b95ab 100644
--- a/tests/qemu-iotests/067.out
+++ b/tests/qemu-iotests/067.out
@@ -6,7 +6,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
 Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk -device virtio-blk-pci,drive=disk,id=virtio0
 QMP_VERSION
 {"return": {}}
-{"return": [{"io-status": "ok", "device": "disk", "locked": false, "removable": false, "inserted": {"iops_rd": 0, "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "type": "unknown"}, {"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}]}
+{"return": [{"io-status": "ok", "device": "disk", "locked": false, "removable": false, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "type": "unknown"}, {"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}]}
 {"return": {}}
 {"return": {}}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "DEVICE_DELETED", "data": {"path": "/machine/peripheral/virtio0/virtio-backend"}}
@@ -24,7 +24,7 @@ QMP_VERSION
 Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk
 QMP_VERSION
 {"return": {}}
-{"return": [{"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}, {"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}]}
+{"return": [{"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}, {"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}]}
 {"return": {}}
 {"return": {}}
 {"return": {}}
@@ -44,7 +44,7 @@ Testing:
 QMP_VERSION
 {"return": {}}
 {"return": "OK\r\n"}
-{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]}
+{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]}
 {"return": {}}
 {"return": {}}
 {"return": {}}
@@ -64,14 +64,14 @@ Testing:
 QMP_VERSION
 {"return": {}}
 {"return": {}}
-{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]}
+{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]}
 {"return": {}}
 {"return": {}}
 {"return": {}}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "DEVICE_DELETED", "data": {"path": "/machine/peripheral/virtio0/virtio-backend"}}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "DEVICE_DELETED", "data": {"device": "virtio0", "path": "/machine/peripheral/virtio0"}}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "RESET"}
-{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"io-status": "ok", "device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]}
+{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"io-status": "ok", "device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]}
 {"return": {}}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN"}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}}
diff --git a/tests/qemu-iotests/070 b/tests/qemu-iotests/070
index ce71fa4a22..ea0dae7e9c 100755
--- a/tests/qemu-iotests/070
+++ b/tests/qemu-iotests/070
@@ -72,6 +72,13 @@ echo "=== Verify open image read-only succeeds after log replay ==="
 $QEMU_IO -r -c "read -pP 0xa5 0 18M" "$TEST_IMG" 2>&1 | _filter_testdir \
                                                       | _filter_qemu_io
 
+_cleanup_test_img
+_use_sample_img test-disk2vhd.vhdx.bz2
+
+echo
+echo "=== Verify image created by Disk2VHD can be opened ==="
+$QEMU_IMG info "$TEST_IMG" 2>&1 | _filter_testdir | _filter_qemu
+
 # success, all done
 echo "*** done"
 rm -f $seq.full
diff --git a/tests/qemu-iotests/070.out b/tests/qemu-iotests/070.out
index 922d62cb51..15f1fc1471 100644
--- a/tests/qemu-iotests/070.out
+++ b/tests/qemu-iotests/070.out
@@ -18,4 +18,11 @@ No errors were found on the image.
 === Verify open image read-only succeeds after log replay ===
 read 18874368/18874368 bytes at offset 0
 18 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+=== Verify image created by Disk2VHD can be opened ===
+image: TEST_DIR/test-disk2vhd.vhdx
+file format: vhdx
+virtual size: 256M (268435456 bytes)
+disk size: 260M
+cluster_size: 2097152
 *** done
diff --git a/tests/qemu-iotests/089 b/tests/qemu-iotests/089
new file mode 100755
index 0000000000..dffc977e1c
--- /dev/null
+++ b/tests/qemu-iotests/089
@@ -0,0 +1,129 @@
+#!/bin/bash
+#
+# Test case for support of JSON filenames
+#
+# Copyright (C) 2014 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+# creator
+owner=mreitz@redhat.com
+
+seq="$(basename $0)"
+echo "QA output created by $seq"
+
+here="$PWD"
+tmp=/tmp/$$
+status=1	# failure is the default!
+
+_cleanup()
+{
+	_cleanup_test_img
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+
+_supported_fmt qcow2
+_supported_proto file
+_supported_os Linux
+
+# Using an image filename containing quotation marks will render the JSON data
+# below invalid. In that case, we have little choice but simply not to run this
+# test.
+case $TEST_IMG in
+    *'"'*)
+        _notrun "image filename may not contain quotation marks"
+        ;;
+esac
+
+IMG_SIZE=64M
+
+# Taken from test 072
+echo
+echo "=== Testing nested image formats ==="
+echo
+
+TEST_IMG="$TEST_IMG.base" _make_test_img $IMG_SIZE
+
+$QEMU_IO -c 'write -P 42 0 512' -c 'write -P 23 512 512' \
+         -c 'write -P 66 1024 512' "$TEST_IMG.base" | _filter_qemu_io
+
+$QEMU_IMG convert -f raw -O $IMGFMT "$TEST_IMG.base" "$TEST_IMG"
+
+$QEMU_IO -c 'read -P 42 0 512' -c 'read -P 23 512 512' \
+         -c 'read -P 66 1024 512' "json:{
+    \"driver\": \"$IMGFMT\",
+    \"file\": {
+        \"driver\": \"$IMGFMT\",
+        \"file\": {
+            \"filename\": \"$TEST_IMG\"
+        }
+    }
+}" | _filter_qemu_io
+
+# This should fail (see test 072)
+$QEMU_IO -c 'read -P 42 0 512' "$TEST_IMG" | _filter_qemu_io
+
+
+# Taken from test 071
+echo
+echo "=== Testing blkdebug ==="
+echo
+
+_make_test_img $IMG_SIZE
+
+$QEMU_IO -c 'write -P 42 0x38000 512' "$TEST_IMG" | _filter_qemu_io
+
+# The "image.filename" part tests whether "a": { "b": "c" } and "a.b": "c" do
+# the same (which they should).
+$QEMU_IO -c 'read -P 42 0x38000 512' "json:{
+    \"driver\": \"$IMGFMT\",
+    \"file\": {
+        \"driver\": \"blkdebug\",
+        \"inject-error\": [{
+            \"event\": \"l2_load\"
+        }],
+        \"image.filename\": \"$TEST_IMG\"
+    }
+}" | _filter_qemu_io
+
+
+echo
+echo "=== Testing qemu-img info output ==="
+echo
+
+TEST_IMG="json:{\"driver\":\"qcow2\",\"file.filename\":\"$TEST_IMG\"}" _img_info
+
+
+echo
+echo "=== Testing option merging ==="
+echo
+
+# Both options given directly and those given in the filename should be used
+$QEMU_IO -c "open -o driver=qcow2 json:{\"file.filename\":\"$TEST_IMG\"}" \
+         -c "info" 2>&1 | _filter_testdir | _filter_imgfmt
+
+# Options given directly should be prioritized over those given in the filename
+$QEMU_IO -c "open -o driver=qcow2 json:{\"driver\":\"raw\",\"file.filename\":\"$TEST_IMG\"}" \
+         -c "info" 2>&1 | _filter_testdir | _filter_imgfmt
+
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/089.out b/tests/qemu-iotests/089.out
new file mode 100644
index 0000000000..4ca2f88e6a
--- /dev/null
+++ b/tests/qemu-iotests/089.out
@@ -0,0 +1,50 @@
+QA output created by 089
+
+=== Testing nested image formats ===
+
+Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 
+wrote 512/512 bytes at offset 0
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 512/512 bytes at offset 512
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 512/512 bytes at offset 1024
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 0
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 512
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 1024
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+Pattern verification failed at offset 0, 512 bytes
+read 512/512 bytes at offset 0
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+=== Testing blkdebug ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 
+wrote 512/512 bytes at offset 229376
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read failed: Input/output error
+
+=== Testing qemu-img info output ===
+
+image: TEST_DIR/t.IMGFMT
+file format: IMGFMT
+virtual size: 64M (67108864 bytes)
+cluster_size: 65536
+
+=== Testing option merging ===
+
+format name: IMGFMT
+cluster size: 64 KiB
+vm state offset: 512 MiB
+Format specific information:
+    compat: 1.1
+    lazy refcounts: false
+format name: IMGFMT
+cluster size: 64 KiB
+vm state offset: 512 MiB
+Format specific information:
+    compat: 1.1
+    lazy refcounts: false
+*** done
diff --git a/tests/qemu-iotests/091 b/tests/qemu-iotests/091
index 384b3ace54..32bbd56975 100755
--- a/tests/qemu-iotests/091
+++ b/tests/qemu-iotests/091
@@ -47,6 +47,8 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 _supported_fmt qcow2
 _supported_proto file
 _supported_os Linux
+_default_cache_mode "none"
+_supported_cache_modes "writethrough" "none" "writeback"
 
 size=1G
 
@@ -59,13 +61,13 @@ echo === Starting QEMU VM1 ===
 echo
 
 qemu_comm_method="monitor"
-_launch_qemu -drive file="${TEST_IMG}",cache=none,id=disk
+_launch_qemu -drive file="${TEST_IMG}",cache=${CACHEMODE},id=disk
 h1=$QEMU_HANDLE
 
 echo
 echo === Starting QEMU VM2 ===
 echo
-_launch_qemu -drive file="${TEST_IMG}",cache=none,id=disk \
+_launch_qemu -drive file="${TEST_IMG}",cache=${CACHEMODE},id=disk \
              -incoming "exec: cat '${MIG_FIFO}'"
 h2=$QEMU_HANDLE
 
diff --git a/tests/qemu-iotests/092 b/tests/qemu-iotests/092
new file mode 100755
index 0000000000..a8c0c9ca2b
--- /dev/null
+++ b/tests/qemu-iotests/092
@@ -0,0 +1,98 @@
+#!/bin/bash
+#
+# qcow1 format input validation tests
+#
+# Copyright (C) 2014 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+# creator
+owner=kwolf@redhat.com
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1	# failure is the default!
+
+_cleanup()
+{
+    rm -f $TEST_IMG.snap
+    _cleanup_test_img
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+
+_supported_fmt qcow
+_supported_proto generic
+_supported_os Linux
+
+offset_backing_file_offset=8
+offset_backing_file_size=16
+offset_size=24
+offset_cluster_bits=32
+offset_l2_bits=33
+
+echo
+echo "== Invalid cluster size =="
+_make_test_img 64M
+poke_file "$TEST_IMG" "$offset_cluster_bits" "\xff"
+{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
+poke_file "$TEST_IMG" "$offset_cluster_bits" "\x1f"
+{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
+poke_file "$TEST_IMG" "$offset_cluster_bits" "\x08"
+{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
+poke_file "$TEST_IMG" "$offset_cluster_bits" "\x11"
+{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
+
+echo
+echo "== Invalid L2 table size =="
+_make_test_img 64M
+poke_file "$TEST_IMG" "$offset_l2_bits" "\xff"
+{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
+poke_file "$TEST_IMG" "$offset_l2_bits" "\x05"
+{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
+poke_file "$TEST_IMG" "$offset_l2_bits" "\x0e"
+{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
+
+# 1 << 0x1b = 2^31 / L2_CACHE_SIZE
+poke_file "$TEST_IMG" "$offset_l2_bits" "\x1b"
+{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
+
+echo
+echo "== Invalid size =="
+_make_test_img 64M
+poke_file "$TEST_IMG" "$offset_size" "\xee\xee\xee\xee\xee\xee\xee\xee"
+{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
+poke_file "$TEST_IMG" "$offset_size" "\x7f\xff\xff\xff\xff\xff\xff\xff"
+{ $QEMU_IO -c "write 0 64M" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
+
+echo
+echo "== Invalid backing file length =="
+_make_test_img 64M
+poke_file "$TEST_IMG" "$offset_backing_file_offset" "\x00\x00\x00\xff"
+poke_file "$TEST_IMG" "$offset_backing_file_size" "\xff\xff\xff\xff"
+{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
+poke_file "$TEST_IMG" "$offset_backing_file_size" "\x7f\xff\xff\xff"
+{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/092.out b/tests/qemu-iotests/092.out
new file mode 100644
index 0000000000..496d8f0a63
--- /dev/null
+++ b/tests/qemu-iotests/092.out
@@ -0,0 +1,38 @@
+QA output created by 092
+
+== Invalid cluster size ==
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 
+qemu-io: can't open device TEST_DIR/t.qcow: Cluster size must be between 512 and 64k
+no file open, try 'help open'
+qemu-io: can't open device TEST_DIR/t.qcow: Cluster size must be between 512 and 64k
+no file open, try 'help open'
+qemu-io: can't open device TEST_DIR/t.qcow: Cluster size must be between 512 and 64k
+no file open, try 'help open'
+qemu-io: can't open device TEST_DIR/t.qcow: Cluster size must be between 512 and 64k
+no file open, try 'help open'
+
+== Invalid L2 table size ==
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 
+qemu-io: can't open device TEST_DIR/t.qcow: L2 table size must be between 512 and 64k
+no file open, try 'help open'
+qemu-io: can't open device TEST_DIR/t.qcow: L2 table size must be between 512 and 64k
+no file open, try 'help open'
+qemu-io: can't open device TEST_DIR/t.qcow: L2 table size must be between 512 and 64k
+no file open, try 'help open'
+qemu-io: can't open device TEST_DIR/t.qcow: L2 table size must be between 512 and 64k
+no file open, try 'help open'
+
+== Invalid size ==
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 
+qemu-io: can't open device TEST_DIR/t.qcow: Image too large
+no file open, try 'help open'
+qemu-io: can't open device TEST_DIR/t.qcow: Image too large
+no file open, try 'help open'
+
+== Invalid backing file length ==
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 
+qemu-io: can't open device TEST_DIR/t.qcow: Backing file name too long
+no file open, try 'help open'
+qemu-io: can't open device TEST_DIR/t.qcow: Backing file name too long
+no file open, try 'help open'
+*** done
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
index 776985d15e..a04df7f6dc 100644
--- a/tests/qemu-iotests/common.filter
+++ b/tests/qemu-iotests/common.filter
@@ -150,6 +150,7 @@ _filter_win32()
 _filter_qemu_io()
 {
     _filter_win32 | sed -e "s/[0-9]* ops\; [0-9/:. sec]* ([0-9/.inf]* [EPTGMKiBbytes]*\/sec and [0-9/.inf]* ops\/sec)/X ops\; XX:XX:XX.X (XXX YYY\/sec and XXX ops\/sec)/" \
+        -e "s/: line [0-9][0-9]*:  *[0-9][0-9]*\( Aborted\)/:\1/" \
         -e "s/qemu-io> //g"
 }
 
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index cd3e4d2c27..0f074403ae 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -95,5 +95,7 @@
 086 rw auto quick
 087 rw auto
 088 rw auto
+089 rw auto quick
 090 rw auto quick
 091 rw auto
+092 rw auto quick
diff --git a/tests/qemu-iotests/sample_images/test-disk2vhd.vhdx.bz2 b/tests/qemu-iotests/sample_images/test-disk2vhd.vhdx.bz2
new file mode 100644
index 0000000000..2891c9a6d6
--- /dev/null
+++ b/tests/qemu-iotests/sample_images/test-disk2vhd.vhdx.bz2
Binary files differdiff --git a/tests/qom-test.c b/tests/qom-test.c
index 6d9a00b448..d8d1d8d9ff 100644
--- a/tests/qom-test.c
+++ b/tests/qom-test.c
@@ -44,7 +44,7 @@ static bool is_blacklisted(const char *arch, const char *mach)
     return false;
 }
 
-static void test_properties(const char *path)
+static void test_properties(const char *path, bool recurse)
 {
     char *child_path;
     QDict *response, *tuple;
@@ -56,14 +56,21 @@ static void test_properties(const char *path)
                    "  'arguments': { 'path': '%s' } }", path);
     g_assert(response);
 
+    if (!recurse) {
+        return;
+    }
+
     g_assert(qdict_haskey(response, "return"));
     list = qobject_to_qlist(qdict_get(response, "return"));
     QLIST_FOREACH_ENTRY(list, entry) {
         tuple = qobject_to_qdict(qlist_entry_obj(entry));
-        if (strstart(qdict_get_str(tuple, "type"), "child<", NULL)) {
+        bool is_child = strstart(qdict_get_str(tuple, "type"), "child<", NULL);
+        bool is_link = strstart(qdict_get_str(tuple, "type"), "link<", NULL);
+
+        if (is_child || is_link) {
             child_path = g_strdup_printf("%s/%s",
                                          path, qdict_get_str(tuple, "name"));
-            test_properties(child_path);
+            test_properties(child_path, is_child);
             g_free(child_path);
         } else {
             const char *prop = qdict_get_str(tuple, "name");
@@ -87,7 +94,7 @@ static void test_machine(gconstpointer data)
     args = g_strdup_printf("-machine %s", machine);
     qtest_start(args);
 
-    test_properties("/machine");
+    test_properties("/machine", true);
 
     response = qmp("{ 'execute': 'quit' }");
     g_assert(qdict_haskey(response, "return"));
diff --git a/tests/tcg/lm32/Makefile b/tests/tcg/lm32/Makefile
index 8e5d405459..57e7363b2c 100644
--- a/tests/tcg/lm32/Makefile
+++ b/tests/tcg/lm32/Makefile
@@ -3,7 +3,7 @@
 CROSS=lm32-elf-
 
 SIM = qemu-system-lm32
-SIMFLAGS = -M lm32-evr -nographic -device lm32-sys -net none -kernel
+SIMFLAGS = -M lm32-evr -nographic -semihosting -net none -kernel
 
 CC      = $(CROSS)gcc
 AS      = $(CROSS)as
@@ -18,6 +18,7 @@ LDFLAGS = -T$(TSRC_PATH)/linker.ld
 ASFLAGS += -Wa,-I,$(TSRC_PATH)/
 
 CRT        = crt.o
+HELPER     = helper.o
 TESTCASES += test_add.tst
 TESTCASES += test_addi.tst
 TESTCASES += test_and.tst
@@ -91,15 +92,15 @@ all: build
 %.o: $(TSRC_PATH)/%.S
 	$(AS) $(ASFLAGS) -c $< -o $@
 
-%.tst: %.o $(TSRC_PATH)/macros.inc $(CRT)
-	$(LD) $(LDFLAGS) $(NOSTDFLAGS) $(CRT) $< -o $@
+%.tst: %.o $(TSRC_PATH)/macros.inc $(CRT) $(HELPER)
+	$(LD) $(LDFLAGS) $(NOSTDFLAGS) $(CRT) $(HELPER) $< -o $@
 
-build: $(CRT) $(TESTCASES)
+build: $(TESTCASES)
 
 check: $(TESTCASES:test_%.tst=check_%)
 
-check_%: test_%.tst $(CRT) $(SYS)
-	$(SIM) $(SIMFLAGS) $<
+check_%: test_%.tst
+	@$(SIM) $(SIMFLAGS) $<
 
 clean:
-	$(RM) -fr $(TESTCASES) $(CRT)
+	$(RM) -fr $(TESTCASES) $(CRT) $(HELPER)
diff --git a/tests/tcg/lm32/crt.S b/tests/tcg/lm32/crt.S
index 5f9cfd95d3..fc437a3de1 100644
--- a/tests/tcg/lm32/crt.S
+++ b/tests/tcg/lm32/crt.S
@@ -8,9 +8,9 @@ _reset_handler:
 	ori r1, r1, lo(_start)
 	wcsr eba, r1
 	wcsr deba, r1
+	mvhi sp, hi(_fstack)
+	ori sp, sp, lo(_fstack)
 	bi _main
-	nop
-	nop
 
 _breakpoint_handler:
 	ori r25, r25, 1
diff --git a/tests/tcg/lm32/helper.S b/tests/tcg/lm32/helper.S
new file mode 100644
index 0000000000..3351d41e84
--- /dev/null
+++ b/tests/tcg/lm32/helper.S
@@ -0,0 +1,65 @@
+.text
+.global _start, _write, _exit
+.global _tc_fail, _tc_pass
+
+_write:
+	addi sp, sp, -4
+	sw (sp+4), r8
+	mvi r8, 5
+	scall
+	lw r8, (sp+4)
+	addi sp, sp, 4
+	ret
+
+_exit:
+	mvi r8, 1
+	scall
+1:
+	bi 1b
+
+_tc_pass:
+.data
+1:
+	.ascii "OK\n"
+2:
+.text
+	addi sp, sp, -16
+	sw (sp+4), ra
+	sw (sp+8), r1
+	sw (sp+12), r2
+	sw (sp+16), r3
+	mvi r1, 1
+	mvhi r2, hi(1b)
+	ori r2, r2, lo(1b)
+	mvi r3, (2b - 1b)
+	calli _write
+	lw r3, (sp+16)
+	lw r2, (sp+12)
+	lw r1, (sp+8)
+	lw ra, (sp+4)
+	addi sp, sp, 16
+	ret
+
+_tc_fail:
+.data
+1:
+	.ascii "FAILED\n"
+2:
+.text
+	addi sp, sp, -16
+	sw (sp+4), ra
+	sw (sp+8), r1
+	sw (sp+12), r2
+	sw (sp+16), r3
+	sw (sp+4), ra
+	mvi r1, 1
+	mvhi r2, hi(1b)
+	ori r2, r2, lo(1b)
+	mvi r3, (2b - 1b)
+	calli _write
+	lw r3, (sp+16)
+	lw r2, (sp+12)
+	lw r1, (sp+8)
+	lw ra, (sp+4)
+	addi sp, sp, 16
+	ret
diff --git a/tests/tcg/lm32/macros.inc b/tests/tcg/lm32/macros.inc
index 367c7c50d8..360ad53c9f 100644
--- a/tests/tcg/lm32/macros.inc
+++ b/tests/tcg/lm32/macros.inc
@@ -1,12 +1,26 @@
 
+.equ MAX_TESTNAME_LEN, 32
 .macro test_name name
 	.data
 tn_\name:
-	.asciz "\name"
+	.ascii "\name"
+	.space MAX_TESTNAME_LEN - (. - tn_\name), ' '
 	.text
-	mvhi r13, hi(tn_\name)
-	ori r13, r13, lo(tn_\name)
-	sw (r12+8), r13
+	.global \name
+\name:
+	addi sp, sp, -12
+	sw (sp+4), r1
+	sw (sp+8), r2
+	sw (sp+12), r3
+	mvi r1, 1
+	mvhi r2, hi(tn_\name)
+	ori r2, r2, lo(tn_\name)
+	mvi r3, MAX_TESTNAME_LEN
+	calli _write
+	lw r3, (sp+12)
+	lw r2, (sp+8)
+	lw r1, (sp+4)
+	addi sp, sp, 12
 .endm
 
 .macro load reg val
@@ -15,13 +29,12 @@ tn_\name:
 .endm
 
 .macro tc_pass
-	mvi r13, 0
-	sw (r12+4), r13
+	calli _tc_pass
 .endm
 
 .macro tc_fail
-	mvi r13, 1
-	sw (r12+4), r13
+	addi r12, r12, 1
+	calli _tc_fail
 .endm
 
 .macro check_r3 val
@@ -63,14 +76,12 @@ tn_\name:
 	.global _main
 	.text
 _main:
-	mvhi r12, hi(0xffff0000)      # base address of test block
-	ori r12, r12, lo(0xffff0000)
+	mvi r12, 0
 .endm
 
 .macro end
-	sw (r12+0), r0
-1:
-	bi 1b
+	mv r1, r12
+	calli _exit
 .endm
 
 # base +
diff --git a/tests/tcg/lm32/test_lb.S b/tests/tcg/lm32/test_lb.S
index f84d21ead9..d677eea4c4 100644
--- a/tests/tcg/lm32/test_lb.S
+++ b/tests/tcg/lm32/test_lb.S
@@ -8,10 +8,12 @@ lb r3, (r1+0)
 check_r3 0x7e
 
 test_name LB_2
+load r1 data
 lb r3, (r1+1)
 check_r3 0x7f
 
 test_name LB_3
+load r1 data
 lb r3, (r1+-1)
 check_r3 0x7d
 
@@ -21,10 +23,12 @@ lb r3, (r1+0)
 check_r3 0xfffffffe
 
 test_name LB_5
+load r1 data_msb
 lb r3, (r1+1)
 check_r3 0xffffffff
 
 test_name LB_6
+load r1 data_msb
 lb r3, (r1+-1)
 check_r3 0xfffffffd
 
diff --git a/tests/tcg/lm32/test_lbu.S b/tests/tcg/lm32/test_lbu.S
index 4c1786ad71..dc5d5f67d3 100644
--- a/tests/tcg/lm32/test_lbu.S
+++ b/tests/tcg/lm32/test_lbu.S
@@ -8,10 +8,12 @@ lbu r3, (r1+0)
 check_r3 0x7e
 
 test_name LBU_2
+load r1 data
 lbu r3, (r1+1)
 check_r3 0x7f
 
 test_name LBU_3
+load r1 data
 lbu r3, (r1+-1)
 check_r3 0x7d
 
@@ -21,10 +23,12 @@ lbu r3, (r1+0)
 check_r3 0xfe
 
 test_name LBU_5
+load r1 data_msb
 lbu r3, (r1+1)
 check_r3 0xff
 
 test_name LBU_6
+load r1 data_msb
 lbu r3, (r1+-1)
 check_r3 0xfd
 
diff --git a/tests/tcg/lm32/test_lh.S b/tests/tcg/lm32/test_lh.S
index e57d9e35cf..397996bddd 100644
--- a/tests/tcg/lm32/test_lh.S
+++ b/tests/tcg/lm32/test_lh.S
@@ -8,10 +8,12 @@ lh r3, (r1+0)
 check_r3 0x7e7f
 
 test_name LH_2
+load r1 data
 lh r3, (r1+2)
 check_r3 0x7071
 
 test_name LH_3
+load r1 data
 lh r3, (r1+-2)
 check_r3 0x7c7d
 
@@ -21,10 +23,12 @@ lh r3, (r1+0)
 check_r3 0xfffffeff
 
 test_name LH_5
+load r1 data_msb
 lh r3, (r1+2)
 check_r3 0xfffff0f1
 
 test_name LH_6
+load r1 data_msb
 lh r3, (r1+-2)
 check_r3 0xfffffcfd
 
diff --git a/tests/tcg/lm32/test_lhu.S b/tests/tcg/lm32/test_lhu.S
index e648775d94..8de7c52560 100644
--- a/tests/tcg/lm32/test_lhu.S
+++ b/tests/tcg/lm32/test_lhu.S
@@ -8,10 +8,12 @@ lhu r3, (r1+0)
 check_r3 0x7e7f
 
 test_name LHU_2
+load r1 data
 lhu r3, (r1+2)
 check_r3 0x7071
 
 test_name LHU_3
+load r1 data
 lhu r3, (r1+-2)
 check_r3 0x7c7d
 
@@ -21,10 +23,12 @@ lhu r3, (r1+0)
 check_r3 0xfeff
 
 test_name LHU_5
+load r1 data_msb
 lhu r3, (r1+2)
 check_r3 0xf0f1
 
 test_name LHU_6
+load r1 data_msb
 lhu r3, (r1+-2)
 check_r3 0xfcfd
 
diff --git a/tests/tcg/lm32/test_lw.S b/tests/tcg/lm32/test_lw.S
index f8c919d2b8..996e5f8c88 100644
--- a/tests/tcg/lm32/test_lw.S
+++ b/tests/tcg/lm32/test_lw.S
@@ -8,10 +8,12 @@ lw r3, (r1+0)
 check_r3 0x7e7f7071
 
 test_name LW_2
+load r1 data
 lw r3, (r1+4)
 check_r3 0x72737475
 
 test_name LW_3
+load r1 data
 lw r3, (r1+-4)
 check_r3 0x7a7b7c7d
 
diff --git a/tests/tcg/lm32/test_sb.S b/tests/tcg/lm32/test_sb.S
index 89e39d621d..b15a89d342 100644
--- a/tests/tcg/lm32/test_sb.S
+++ b/tests/tcg/lm32/test_sb.S
@@ -9,11 +9,13 @@ sb (r1+0), r2
 check_mem data 0xaa000000
 
 test_name SB_2
+load r1 data
 load r2 0xf0f1f2bb
 sb (r1+1), r2
 check_mem data 0xaabb0000
 
 test_name SB_3
+load r1 data
 load r2 0xf0f1f2cc
 sb (r1+-1), r2
 check_mem data0 0x000000cc
diff --git a/tests/tcg/lm32/test_scall.S b/tests/tcg/lm32/test_scall.S
index b442e32374..46032f841d 100644
--- a/tests/tcg/lm32/test_scall.S
+++ b/tests/tcg/lm32/test_scall.S
@@ -5,6 +5,10 @@ start
 test_name SCALL_1
 mvi r1, 1
 wcsr IE, r1
+# we are running in a semi hosted environment
+# therefore we have to set r8 to some unused system
+# call
+mvi r8, 0
 insn:
 scall
 check_excp 64
diff --git a/tests/tcg/lm32/test_sh.S b/tests/tcg/lm32/test_sh.S
index ea8b3f2067..bba10224f6 100644
--- a/tests/tcg/lm32/test_sh.S
+++ b/tests/tcg/lm32/test_sh.S
@@ -9,11 +9,13 @@ sh (r1+0), r2
 check_mem data 0xaaaa0000
 
 test_name SH_2
+load r1 data
 load r2 0xf0f1bbbb
 sh (r1+2), r2
 check_mem data 0xaaaabbbb
 
 test_name SH_3
+load r1 data
 load r2 0xf0f1cccc
 sh (r1+-2), r2
 check_mem data0 0x0000cccc
diff --git a/tests/tcg/lm32/test_sw.S b/tests/tcg/lm32/test_sw.S
index d1fdadce61..2b1c017e7b 100644
--- a/tests/tcg/lm32/test_sw.S
+++ b/tests/tcg/lm32/test_sw.S
@@ -9,16 +9,19 @@ sw (r1+0), r2
 check_mem data 0xaabbccdd
 
 test_name SW_2
+load r1 data
 load r2 0x00112233
 sw (r1+4), r2
 check_mem data1 0x00112233
 
 test_name SW_3
+load r1 data
 load r2 0x44556677
 sw (r1+-4), r2
 check_mem data0 0x44556677
 
 test_name SW_4
+load r1 data
 sw (r1+0), r1
 lw r3, (r1+0)
 check_r3 data
diff --git a/tests/tcg/xtensa/test_mmu.S b/tests/tcg/xtensa/test_mmu.S
index 099031fd14..58c5bca30e 100644
--- a/tests/tcg/xtensa/test_mmu.S
+++ b/tests/tcg/xtensa/test_mmu.S
@@ -4,16 +4,28 @@ test_suite mmu
 
 .purgem test_init
 
-.macro test_init
-    movi    a2, 0x00000004
-    idtlb   a2
-    movi    a2, 0x00100004
+.macro clean_tlb_way way, page_size, n_entries
+    movi    a2, \way
+    movi    a3, \page_size
+    movi    a4, \n_entries
+    loop    a4, 1f
     idtlb   a2
-    movi    a2, 0x00200004
+    iitlb   a2
+    add     a2, a2, a3
+1:
+.endm
+
+.macro test_init
+    clean_tlb_way 0, 0x00001000, 4
+    clean_tlb_way 1, 0x00001000, 4
+    clean_tlb_way 2, 0x00001000, 4
+    clean_tlb_way 3, 0x00001000, 4
+    clean_tlb_way 4, 0x00100000, 4
+    movi    a2, 0x00000007
     idtlb   a2
-    movi    a2, 0x00300004
+    movi    a2, 0x00000008
     idtlb   a2
-    movi    a2, 0x00000007
+    movi    a2, 0x00000009
     idtlb   a2
 .endm
 
@@ -508,4 +520,224 @@ test autoload_3_level_pt
     assert_sr exccause, 24
 test_end
 
+test cross_page_insn
+    set_vector kernel, 2f
+
+    movi    a2, 0x04000003 /* PPN */
+    movi    a3, 0x00007000 /* VPN */
+    witlb   a2, a3
+    wdtlb   a2, a3
+    movi    a3, 0x00008000 /* VPN */
+    witlb   a2, a3
+    wdtlb   a2, a3
+
+    movi    a2, 0x00007fff
+    movi    a3, 20f
+    movi    a4, 21f
+    sub     a4, a4, a3
+    loop    a4, 1f
+    l8ui    a5, a3, 0
+    s8i     a5, a2, 0
+    addi    a2, a2, 1
+    addi    a3, a3, 1
+1:
+    movi    a2, 0x00007fff
+    movi    a3, 0x00008000
+    /* DTLB: OK, ITLB: OK */
+    jx      a2
+
+    .begin  no-transform
+20:
+    l32i    a2, a3, 0
+    syscall
+21:
+    .end    no-transform
+
+2:
+    rsr     a2, exccause
+    movi    a3, 1
+    assert  eq, a2, a3
+    rsr     a2, epc1
+    movi    a3, 0x8002
+    assert  eq, a2, a3
+    rsr     a2, excsave1
+    movi    a3, 0x00007fff
+    assert  ne, a2, a3
+
+    reset_ps
+    set_vector kernel, 3f
+
+    movi    a2, 0x0400000c /* PPN */
+    movi    a3, 0x00008000 /* VPN */
+    wdtlb   a2, a3
+    movi    a2, 0x00007fff
+    movi    a3, 0x00008000
+    /* DTLB: FAIL, ITLB: OK */
+    jx      a2
+3:
+    rsr     a2, exccause
+    movi    a3, 28
+    assert  eq, a2, a3
+    rsr     a2, epc1
+    movi    a3, 0x7fff
+    assert  eq, a2, a3
+    rsr     a2, excsave1
+    movi    a3, 0x00007fff
+    assert  eq, a2, a3
+
+    reset_ps
+    set_vector kernel, 4f
+
+    movi    a2, 0x0400000c /* PPN */
+    movi    a3, 0x00008000 /* VPN */
+    witlb   a2, a3
+    movi    a2, 0x04000003 /* PPN */
+    wdtlb   a2, a3
+    movi    a2, 0x00007fff
+    movi    a3, 0x00008000
+    /* DTLB: OK, ITLB: FAIL */
+    jx      a2
+4:
+    rsr     a2, exccause
+    movi    a3, 20
+    assert  eq, a2, a3
+    rsr     a2, epc1
+    movi    a3, 0x7fff
+    assert  eq, a2, a3
+    rsr     a2, excsave1
+    movi    a3, 0x00007fff
+    assert  eq, a2, a3
+
+    reset_ps
+    set_vector kernel, 5f
+
+    movi    a2, 0x0400000c /* PPN */
+    movi    a3, 0x00008000 /* VPN */
+    wdtlb   a2, a3
+    movi    a2, 0x00007fff
+    movi    a3, 0x00008000
+    /* DTLB: FAIL, ITLB: FAIL */
+    jx      a2
+5:
+    rsr     a2, exccause
+    movi    a3, 20
+    assert  eq, a2, a3
+    rsr     a2, epc1
+    movi    a3, 0x7fff
+    assert  eq, a2, a3
+    rsr     a2, excsave1
+    movi    a3, 0x00007fff
+    assert  eq, a2, a3
+test_end
+
+test cross_page_tb
+    set_vector kernel, 2f
+
+    movi    a2, 0x04000003 /* PPN */
+    movi    a3, 0x00007000 /* VPN */
+    witlb   a2, a3
+    wdtlb   a2, a3
+    movi    a3, 0x00008000 /* VPN */
+    witlb   a2, a3
+    wdtlb   a2, a3
+
+    movi    a2, 0x00007ffd
+    movi    a3, 20f
+    movi    a4, 21f
+    sub     a4, a4, a3
+    loop    a4, 1f
+    l8ui    a5, a3, 0
+    s8i     a5, a2, 0
+    addi    a2, a2, 1
+    addi    a3, a3, 1
+1:
+    movi    a2, 0x00007ffd
+    movi    a3, 0x00008000
+    /* DTLB: OK, ITLB: OK */
+    jx      a2
+
+    .begin  no-transform
+20:
+    l32i    a2, a3, 0
+    syscall
+21:
+    .end    no-transform
+
+2:
+    rsr     a2, exccause
+    movi    a3, 1
+    assert  eq, a2, a3
+    rsr     a2, epc1
+    movi    a3, 0x8000
+    assert  eq, a2, a3
+    rsr     a2, excsave1
+    movi    a3, 0x00007ffd
+    assert  ne, a2, a3
+
+    reset_ps
+    set_vector kernel, 3f
+
+    movi    a2, 0x0400000c /* PPN */
+    movi    a3, 0x00008000 /* VPN */
+    wdtlb   a2, a3
+    movi    a2, 0x00007ffd
+    movi    a3, 0x00008000
+    /* DTLB: FAIL, ITLB: OK */
+    jx      a2
+3:
+    rsr     a2, exccause
+    movi    a3, 28
+    assert  eq, a2, a3
+    rsr     a2, epc1
+    movi    a3, 0x7ffd
+    assert  eq, a2, a3
+    rsr     a2, excsave1
+    movi    a3, 0x00007ffd
+    assert  eq, a2, a3
+
+    reset_ps
+    set_vector kernel, 4f
+
+    movi    a2, 0x0400000c /* PPN */
+    movi    a3, 0x00008000 /* VPN */
+    witlb   a2, a3
+    movi    a2, 0x04000003 /* PPN */
+    wdtlb   a2, a3
+    movi    a2, 0x00007ffd
+    movi    a3, 0x00008000
+    /* DTLB: OK, ITLB: FAIL */
+    jx      a2
+4:
+    rsr     a2, exccause
+    movi    a3, 20
+    assert  eq, a2, a3
+    rsr     a2, epc1
+    movi    a3, 0x8000
+    assert  eq, a2, a3
+    rsr     a2, excsave1
+    movi    a3, 0x00007ffd
+    assert  ne, a2, a3
+
+    reset_ps
+    set_vector kernel, 5f
+
+    movi    a2, 0x0400000c /* PPN */
+    movi    a3, 0x00008000 /* VPN */
+    wdtlb   a2, a3
+    movi    a2, 0x00007ffd
+    movi    a3, 0x00008000
+    /* DTLB: FAIL, ITLB: FAIL */
+    jx      a2
+5:
+    rsr     a2, exccause
+    movi    a3, 28
+    assert  eq, a2, a3
+    rsr     a2, epc1
+    movi    a3, 0x7ffd
+    assert  eq, a2, a3
+    rsr     a2, excsave1
+    movi    a3, 0x00007ffd
+    assert  eq, a2, a3
+test_end
+
 test_suite_end
diff --git a/tests/test-qemu-opts.c b/tests/test-qemu-opts.c
new file mode 100644
index 0000000000..3653507f56
--- /dev/null
+++ b/tests/test-qemu-opts.c
@@ -0,0 +1,441 @@
+/*
+ * QemuOpts unit-tests.
+ *
+ * Copyright (C) 2014 Leandro Dorileo <l@dorileo.org>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+
+#include "qapi/error.h"
+#include "qapi/qmp/qstring.h"
+#include "qemu/config-file.h"
+
+#include <glib.h>
+#include <string.h>
+
+static QemuOptsList opts_list_01 = {
+    .name = "opts_list_01",
+    .head = QTAILQ_HEAD_INITIALIZER(opts_list_01.head),
+    .desc = {
+        {
+            .name = "str1",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "str2",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "str3",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "number1",
+            .type = QEMU_OPT_NUMBER,
+        },
+        { /* end of list */ }
+    },
+};
+
+static QemuOptsList opts_list_02 = {
+    .name = "opts_list_02",
+    .head = QTAILQ_HEAD_INITIALIZER(opts_list_02.head),
+    .desc = {
+        {
+            .name = "str1",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "bool1",
+            .type = QEMU_OPT_BOOL,
+        },{
+            .name = "str2",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "size1",
+            .type = QEMU_OPT_SIZE,
+        },
+        { /* end of list */ }
+    },
+};
+
+QemuOptsList opts_list_03 = {
+    .name = "opts_list_03",
+    .head = QTAILQ_HEAD_INITIALIZER(opts_list_03.head),
+    .desc = {
+        /* no elements => accept any params */
+        { /* end of list */ }
+    },
+};
+
+static void register_opts(void)
+{
+    qemu_add_opts(&opts_list_01);
+    qemu_add_opts(&opts_list_02);
+    qemu_add_opts(&opts_list_03);
+}
+
+static void test_find_unknown_opts(void)
+{
+    QemuOptsList *list;
+    Error *err = NULL;
+
+    /* should not return anything, we don't have an "unknown" option */
+    list = qemu_find_opts_err("unknown", &err);
+    g_assert(list == NULL);
+    g_assert(err);
+    error_free(err);
+}
+
+static void test_qemu_find_opts(void)
+{
+    QemuOptsList *list;
+
+    /* we have an "opts_list_01" option, should return it */
+    list = qemu_find_opts("opts_list_01");
+    g_assert(list != NULL);
+    g_assert_cmpstr(list->name, ==, "opts_list_01");
+}
+
+static void test_qemu_opts_create(void)
+{
+    QemuOptsList *list;
+    QemuOpts *opts;
+
+    list = qemu_find_opts("opts_list_01");
+    g_assert(list != NULL);
+    g_assert(QTAILQ_EMPTY(&list->head));
+    g_assert_cmpstr(list->name, ==, "opts_list_01");
+
+    /* should not find anything at this point */
+    opts = qemu_opts_find(list, NULL);
+    g_assert(opts == NULL);
+
+    /* create the opts */
+    opts = qemu_opts_create(list, NULL, 0, &error_abort);
+    g_assert(opts != NULL);
+    g_assert(!QTAILQ_EMPTY(&list->head));
+
+    /* now we've create the opts, must find it */
+    opts = qemu_opts_find(list, NULL);
+    g_assert(opts != NULL);
+
+    qemu_opts_del(opts);
+
+    /* should not find anything at this point */
+    opts = qemu_opts_find(list, NULL);
+    g_assert(opts == NULL);
+}
+
+static void test_qemu_opt_get(void)
+{
+    QemuOptsList *list;
+    QemuOpts *opts;
+    const char *opt = NULL;
+
+    list = qemu_find_opts("opts_list_01");
+    g_assert(list != NULL);
+    g_assert(QTAILQ_EMPTY(&list->head));
+    g_assert_cmpstr(list->name, ==, "opts_list_01");
+
+    /* should not find anything at this point */
+    opts = qemu_opts_find(list, NULL);
+    g_assert(opts == NULL);
+
+    /* create the opts */
+    opts = qemu_opts_create(list, NULL, 0, &error_abort);
+    g_assert(opts != NULL);
+    g_assert(!QTAILQ_EMPTY(&list->head));
+
+    /* haven't set anything to str2 yet */
+    opt = qemu_opt_get(opts, "str2");
+    g_assert(opt == NULL);
+
+    qemu_opt_set(opts, "str2", "value");
+
+    /* now we have set str2, should know about it */
+    opt = qemu_opt_get(opts, "str2");
+    g_assert_cmpstr(opt, ==, "value");
+
+    qemu_opt_set(opts, "str2", "value2");
+
+    /* having reset the value, the returned should be the reset one */
+    opt = qemu_opt_get(opts, "str2");
+    g_assert_cmpstr(opt, ==, "value2");
+
+    qemu_opts_del(opts);
+
+    /* should not find anything at this point */
+    opts = qemu_opts_find(list, NULL);
+    g_assert(opts == NULL);
+}
+
+static void test_qemu_opt_get_bool(void)
+{
+    QemuOptsList *list;
+    QemuOpts *opts;
+    bool opt;
+    int ret;
+
+    list = qemu_find_opts("opts_list_02");
+    g_assert(list != NULL);
+    g_assert(QTAILQ_EMPTY(&list->head));
+    g_assert_cmpstr(list->name, ==, "opts_list_02");
+
+    /* should not find anything at this point */
+    opts = qemu_opts_find(list, NULL);
+    g_assert(opts == NULL);
+
+    /* create the opts */
+    opts = qemu_opts_create(list, NULL, 0, &error_abort);
+    g_assert(opts != NULL);
+    g_assert(!QTAILQ_EMPTY(&list->head));
+
+    /* haven't set anything to bool1 yet, so defval should be returned */
+    opt = qemu_opt_get_bool(opts, "bool1", false);
+    g_assert(opt == false);
+
+    ret = qemu_opt_set_bool(opts, "bool1", true);
+    g_assert(ret == 0);
+
+    /* now we have set bool1, should know about it */
+    opt = qemu_opt_get_bool(opts, "bool1", false);
+    g_assert(opt == true);
+
+    /* having reset the value, opt should be the reset one not defval */
+    ret = qemu_opt_set_bool(opts, "bool1", false);
+    g_assert(ret == 0);
+
+    opt = qemu_opt_get_bool(opts, "bool1", true);
+    g_assert(opt == false);
+
+    qemu_opts_del(opts);
+
+    /* should not find anything at this point */
+    opts = qemu_opts_find(list, NULL);
+    g_assert(opts == NULL);
+}
+
+static void test_qemu_opt_get_number(void)
+{
+    QemuOptsList *list;
+    QemuOpts *opts;
+    uint64_t opt;
+    int ret;
+
+    list = qemu_find_opts("opts_list_01");
+    g_assert(list != NULL);
+    g_assert(QTAILQ_EMPTY(&list->head));
+    g_assert_cmpstr(list->name, ==, "opts_list_01");
+
+    /* should not find anything at this point */
+    opts = qemu_opts_find(list, NULL);
+    g_assert(opts == NULL);
+
+    /* create the opts */
+    opts = qemu_opts_create(list, NULL, 0, &error_abort);
+    g_assert(opts != NULL);
+    g_assert(!QTAILQ_EMPTY(&list->head));
+
+    /* haven't set anything to number1 yet, so defval should be returned */
+    opt = qemu_opt_get_number(opts, "number1", 5);
+    g_assert(opt == 5);
+
+    ret = qemu_opt_set_number(opts, "number1", 10);
+    g_assert(ret == 0);
+
+    /* now we have set number1, should know about it */
+    opt = qemu_opt_get_number(opts, "number1", 5);
+    g_assert(opt == 10);
+
+    /* having reset it, the returned should be the reset one not defval */
+    ret = qemu_opt_set_number(opts, "number1", 15);
+    g_assert(ret == 0);
+
+    opt = qemu_opt_get_number(opts, "number1", 5);
+    g_assert(opt == 15);
+
+    qemu_opts_del(opts);
+
+    /* should not find anything at this point */
+    opts = qemu_opts_find(list, NULL);
+    g_assert(opts == NULL);
+}
+
+static void test_qemu_opt_get_size(void)
+{
+    QemuOptsList *list;
+    QemuOpts *opts;
+    uint64_t opt;
+    QDict *dict;
+
+    list = qemu_find_opts("opts_list_02");
+    g_assert(list != NULL);
+    g_assert(QTAILQ_EMPTY(&list->head));
+    g_assert_cmpstr(list->name, ==, "opts_list_02");
+
+    /* should not find anything at this point */
+    opts = qemu_opts_find(list, NULL);
+    g_assert(opts == NULL);
+
+    /* create the opts */
+    opts = qemu_opts_create(list, NULL, 0, &error_abort);
+    g_assert(opts != NULL);
+    g_assert(!QTAILQ_EMPTY(&list->head));
+
+    /* haven't set anything to size1 yet, so defval should be returned */
+    opt = qemu_opt_get_size(opts, "size1", 5);
+    g_assert(opt == 5);
+
+    dict = qdict_new();
+    g_assert(dict != NULL);
+
+    qdict_put(dict, "size1", qstring_from_str("10"));
+
+    qemu_opts_absorb_qdict(opts, dict, &error_abort);
+    g_assert(error_abort == NULL);
+
+    /* now we have set size1, should know about it */
+    opt = qemu_opt_get_size(opts, "size1", 5);
+    g_assert(opt == 10);
+
+    /* reset value */
+    qdict_put(dict, "size1", qstring_from_str("15"));
+
+    qemu_opts_absorb_qdict(opts, dict, &error_abort);
+    g_assert(error_abort == NULL);
+
+    /* test the reset value */
+    opt = qemu_opt_get_size(opts, "size1", 5);
+    g_assert(opt == 15);
+
+    qdict_del(dict, "size1");
+    g_free(dict);
+
+    qemu_opts_del(opts);
+
+    /* should not find anything at this point */
+    opts = qemu_opts_find(list, NULL);
+    g_assert(opts == NULL);
+}
+
+static void test_qemu_opt_unset(void)
+{
+    QemuOpts *opts;
+    const char *value;
+    int ret;
+
+    /* dynamically initialized (parsed) opts */
+    opts = qemu_opts_parse(&opts_list_03, "key=value", 0);
+    g_assert(opts != NULL);
+
+    /* check default/parsed value */
+    value = qemu_opt_get(opts, "key");
+    g_assert_cmpstr(value, ==, "value");
+
+    /* reset it to value2 */
+    qemu_opt_set(opts, "key", "value2");
+
+    value = qemu_opt_get(opts, "key");
+    g_assert_cmpstr(value, ==, "value2");
+
+    /* unset, valid only for "accept any" */
+    ret = qemu_opt_unset(opts, "key");
+    g_assert(ret == 0);
+
+    /* after reset the value should be the parsed/default one */
+    value = qemu_opt_get(opts, "key");
+    g_assert_cmpstr(value, ==, "value");
+
+    qemu_opts_del(opts);
+}
+
+static void test_qemu_opts_reset(void)
+{
+    QemuOptsList *list;
+    QemuOpts *opts;
+    uint64_t opt;
+    int ret;
+
+    list = qemu_find_opts("opts_list_01");
+    g_assert(list != NULL);
+    g_assert(QTAILQ_EMPTY(&list->head));
+    g_assert_cmpstr(list->name, ==, "opts_list_01");
+
+    /* should not find anything at this point */
+    opts = qemu_opts_find(list, NULL);
+    g_assert(opts == NULL);
+
+    /* create the opts */
+    opts = qemu_opts_create(list, NULL, 0, &error_abort);
+    g_assert(opts != NULL);
+    g_assert(!QTAILQ_EMPTY(&list->head));
+
+    /* haven't set anything to number1 yet, so defval should be returned */
+    opt = qemu_opt_get_number(opts, "number1", 5);
+    g_assert(opt == 5);
+
+    ret = qemu_opt_set_number(opts, "number1", 10);
+    g_assert(ret == 0);
+
+    /* now we have set number1, should know about it */
+    opt = qemu_opt_get_number(opts, "number1", 5);
+    g_assert(opt == 10);
+
+    qemu_opts_reset(list);
+
+    /* should not find anything at this point */
+    opts = qemu_opts_find(list, NULL);
+    g_assert(opts == NULL);
+}
+
+static void test_qemu_opts_set(void)
+{
+    QemuOptsList *list;
+    QemuOpts *opts;
+    int ret;
+    const char *opt;
+
+    list = qemu_find_opts("opts_list_01");
+    g_assert(list != NULL);
+    g_assert(QTAILQ_EMPTY(&list->head));
+    g_assert_cmpstr(list->name, ==, "opts_list_01");
+
+    /* should not find anything at this point */
+    opts = qemu_opts_find(list, NULL);
+    g_assert(opts == NULL);
+
+    /* implicitly create opts and set str3 value */
+    ret = qemu_opts_set(list, NULL, "str3", "value");
+    g_assert(ret == 0);
+    g_assert(!QTAILQ_EMPTY(&list->head));
+
+    /* get the just created opts */
+    opts = qemu_opts_find(list, NULL);
+    g_assert(opts != NULL);
+
+    /* check the str3 value */
+    opt = qemu_opt_get(opts, "str3");
+    g_assert_cmpstr(opt, ==, "value");
+
+    qemu_opts_del(opts);
+
+    /* should not find anything at this point */
+    opts = qemu_opts_find(list, NULL);
+    g_assert(opts == NULL);
+}
+
+int main(int argc, char *argv[])
+{
+    register_opts();
+    g_test_init(&argc, &argv, NULL);
+    g_test_add_func("/qemu-opts/find_unknown_opts", test_find_unknown_opts);
+    g_test_add_func("/qemu-opts/find_opts", test_qemu_find_opts);
+    g_test_add_func("/qemu-opts/opts_create", test_qemu_opts_create);
+    g_test_add_func("/qemu-opts/opt_get", test_qemu_opt_get);
+    g_test_add_func("/qemu-opts/opt_get_bool", test_qemu_opt_get_bool);
+    g_test_add_func("/qemu-opts/opt_get_number", test_qemu_opt_get_number);
+    g_test_add_func("/qemu-opts/opt_get_size", test_qemu_opt_get_size);
+    g_test_add_func("/qemu-opts/opt_unset", test_qemu_opt_unset);
+    g_test_add_func("/qemu-opts/opts_reset", test_qemu_opts_reset);
+    g_test_add_func("/qemu-opts/opts_set", test_qemu_opts_set);
+    g_test_run();
+    return 0;
+}
diff --git a/tests/test-qmp-input-strict.c b/tests/test-qmp-input-strict.c
index 449d285e56..0f770034b1 100644
--- a/tests/test-qmp-input-strict.c
+++ b/tests/test-qmp-input-strict.c
@@ -72,14 +72,30 @@ typedef struct TestStruct
 static void visit_type_TestStruct(Visitor *v, TestStruct **obj,
                                   const char *name, Error **errp)
 {
-    visit_start_struct(v, (void **)obj, "TestStruct", name, sizeof(TestStruct),
-                       errp);
+    Error *err = NULL;
 
-    visit_type_int(v, &(*obj)->integer, "integer", errp);
-    visit_type_bool(v, &(*obj)->boolean, "boolean", errp);
-    visit_type_str(v, &(*obj)->string, "string", errp);
+    visit_start_struct(v, (void **)obj, "TestStruct", name, sizeof(TestStruct),
+                       &err);
+    if (err) {
+        goto out;
+    }
 
-    visit_end_struct(v, errp);
+    visit_type_int(v, &(*obj)->integer, "integer", &err);
+    if (err) {
+        goto out_end;
+    }
+    visit_type_bool(v, &(*obj)->boolean, "boolean", &err);
+    if (err) {
+        goto out_end;
+    }
+    visit_type_str(v, &(*obj)->string, "string", &err);
+
+out_end:
+    error_propagate(errp, err);
+    err = NULL;
+    visit_end_struct(v, &err);
+out:
+    error_propagate(errp, err);
 }
 
 static void test_validate_struct(TestInputVisitorData *data,
diff --git a/tests/test-qmp-input-visitor.c b/tests/test-qmp-input-visitor.c
index a58a3e6fdb..1c8e87295c 100644
--- a/tests/test-qmp-input-visitor.c
+++ b/tests/test-qmp-input-visitor.c
@@ -199,16 +199,24 @@ static void visit_type_TestStruct(Visitor *v, TestStruct **obj,
 
     visit_start_struct(v, (void **)obj, "TestStruct", name, sizeof(TestStruct),
                        &err);
-    if (!err) {
-        visit_type_int(v, &(*obj)->integer, "integer", &err);
-        visit_type_bool(v, &(*obj)->boolean, "boolean", &err);
-        visit_type_str(v, &(*obj)->string, "string", &err);
-
-        /* Always call end_struct if start_struct succeeded.  */
-        error_propagate(errp, err);
-        err = NULL;
-        visit_end_struct(v, &err);
+    if (err) {
+        goto out;
     }
+    visit_type_int(v, &(*obj)->integer, "integer", &err);
+    if (err) {
+        goto out_end;
+    }
+    visit_type_bool(v, &(*obj)->boolean, "boolean", &err);
+    if (err) {
+        goto out_end;
+    }
+    visit_type_str(v, &(*obj)->string, "string", &err);
+
+out_end:
+    error_propagate(errp, err);
+    err = NULL;
+    visit_end_struct(v, &err);
+out:
     error_propagate(errp, err);
 }
 
diff --git a/tests/test-qmp-output-visitor.c b/tests/test-qmp-output-visitor.c
index 2580f3debf..74020de5e7 100644
--- a/tests/test-qmp-output-visitor.c
+++ b/tests/test-qmp-output-visitor.c
@@ -176,14 +176,30 @@ typedef struct TestStruct
 static void visit_type_TestStruct(Visitor *v, TestStruct **obj,
                                   const char *name, Error **errp)
 {
+    Error *err = NULL;
+
     visit_start_struct(v, (void **)obj, "TestStruct", name, sizeof(TestStruct),
-                       errp);
+                       &err);
+    if (err) {
+        goto out;
+    }
 
-    visit_type_int(v, &(*obj)->integer, "integer", errp);
-    visit_type_bool(v, &(*obj)->boolean, "boolean", errp);
-    visit_type_str(v, &(*obj)->string, "string", errp);
+    visit_type_int(v, &(*obj)->integer, "integer", &err);
+    if (err) {
+        goto out_end;
+    }
+    visit_type_bool(v, &(*obj)->boolean, "boolean", &err);
+    if (err) {
+        goto out_end;
+    }
+    visit_type_str(v, &(*obj)->string, "string", &err);
 
-    visit_end_struct(v, errp);
+out_end:
+    error_propagate(errp, err);
+    err = NULL;
+    visit_end_struct(v, &err);
+out:
+    error_propagate(errp, err);
 }
 
 static void test_visitor_out_struct(TestOutputVisitorData *data,
@@ -491,6 +507,15 @@ static void test_visitor_out_union_anon(TestOutputVisitorData *data,
     qapi_free_UserDefAnonUnion(tmp);
 }
 
+static void test_visitor_out_empty(TestOutputVisitorData *data,
+                                   const void *unused)
+{
+    QObject *arg;
+
+    arg = qmp_output_get_qobject(data->qov);
+    g_assert(!arg);
+}
+
 static void init_native_list(UserDefNativeListUnion *cvalue)
 {
     int i;
@@ -843,6 +868,8 @@ int main(int argc, char **argv)
                             &out_visitor_data, test_visitor_out_union_flat);
     output_visitor_test_add("/visitor/output/union-anon",
                             &out_visitor_data, test_visitor_out_union_anon);
+    output_visitor_test_add("/visitor/output/empty",
+                            &out_visitor_data, test_visitor_out_empty);
     output_visitor_test_add("/visitor/output/native_list/int",
                             &out_visitor_data, test_visitor_out_native_list_int);
     output_visitor_test_add("/visitor/output/native_list/int8",
diff --git a/tests/test-thread-pool.c b/tests/test-thread-pool.c
index c1f8e13a9f..aa156bcd32 100644
--- a/tests/test-thread-pool.c
+++ b/tests/test-thread-pool.c
@@ -180,7 +180,7 @@ static void test_cancel(void)
 
     /* Canceling the others will be a blocking operation.  */
     for (i = 0; i < 100; i++) {
-        if (data[i].n != 3) {
+        if (data[i].aiocb && data[i].n != 3) {
             bdrv_aio_cancel(data[i].aiocb);
         }
     }
diff --git a/tests/test-visitor-serialization.c b/tests/test-visitor-serialization.c
index 8166cf1b05..74d6481992 100644
--- a/tests/test-visitor-serialization.c
+++ b/tests/test-visitor-serialization.c
@@ -195,13 +195,29 @@ typedef struct TestStruct
 static void visit_type_TestStruct(Visitor *v, TestStruct **obj,
                                   const char *name, Error **errp)
 {
-    visit_start_struct(v, (void **)obj, NULL, name, sizeof(TestStruct), errp);
+    Error *err = NULL;
 
-    visit_type_int(v, &(*obj)->integer, "integer", errp);
-    visit_type_bool(v, &(*obj)->boolean, "boolean", errp);
-    visit_type_str(v, &(*obj)->string, "string", errp);
+    visit_start_struct(v, (void **)obj, NULL, name, sizeof(TestStruct), &err);
+    if (err) {
+        goto out;
+    }
 
-    visit_end_struct(v, errp);
+    visit_type_int(v, &(*obj)->integer, "integer", &err);
+    if (err) {
+        goto out_end;
+    }
+    visit_type_bool(v, &(*obj)->boolean, "boolean", &err);
+    if (err) {
+        goto out_end;
+    }
+    visit_type_str(v, &(*obj)->string, "string", &err);
+
+out_end:
+    error_propagate(errp, err);
+    err = NULL;
+    visit_end_struct(v, &err);
+out:
+    error_propagate(errp, err);
 }
 
 static TestStruct *struct_create(void)
diff --git a/tests/usb-hcd-ehci-test.c b/tests/usb-hcd-ehci-test.c
index bc56ba7707..bcdf62fc3b 100644
--- a/tests/usb-hcd-ehci-test.c
+++ b/tests/usb-hcd-ehci-test.c
@@ -9,12 +9,149 @@
 
 #include <glib.h>
 #include <string.h>
+#include <stdio.h>
 #include "libqtest.h"
+#include "libqos/pci-pc.h"
 #include "qemu/osdep.h"
+#include "hw/usb/uhci-regs.h"
+#include "hw/usb/ehci-regs.h"
 
-/* Tests only initialization so far. TODO: Replace with functional tests */
-static void pci_nop(void)
+struct qhc {
+    QPCIDevice *dev;
+    void *base;
+};
+
+static QPCIBus *pcibus;
+static struct qhc uhci1;
+static struct qhc uhci2;
+static struct qhc uhci3;
+static struct qhc ehci1;
+
+/* helpers */
+
+static void pci_init_one(struct qhc *hc, uint32_t devfn, int bar)
+{
+    hc->dev = qpci_device_find(pcibus, devfn);
+    g_assert(hc->dev != NULL);
+    qpci_device_enable(hc->dev);
+    hc->base = qpci_iomap(hc->dev, bar);
+    g_assert(hc->base != NULL);
+}
+
+#if 0
+static void uhci_port_update(struct qhc *hc, int port,
+                             uint16_t set, uint16_t clear)
 {
+    void *addr = hc->base + 0x10 + 2 * port;
+    uint16_t value;
+
+    value = qpci_io_readw(hc->dev, addr);
+    value |= set;
+    value &= ~clear;
+    qpci_io_writew(hc->dev, addr, value);
+}
+#endif
+
+static void uhci_port_test(struct qhc *hc, int port, uint16_t expect)
+{
+    void *addr = hc->base + 0x10 + 2 * port;
+    uint16_t value = qpci_io_readw(hc->dev, addr);
+    uint16_t mask = ~(UHCI_PORT_WRITE_CLEAR | UHCI_PORT_RSVD1);
+
+#if 0
+    fprintf(stderr, "%s: %d, have 0x%04x, want 0x%04x\n",
+            __func__, port, value & mask, expect & mask);
+#endif
+    g_assert((value & mask) == (expect & mask));
+}
+
+static void ehci_port_test(struct qhc *hc, int port, uint32_t expect)
+{
+    void *addr = hc->base + 0x64 + 4 * port;
+    uint32_t value = qpci_io_readl(hc->dev, addr);
+    uint16_t mask = ~(PORTSC_CSC | PORTSC_PEDC | PORTSC_OCC);
+
+#if 0
+    fprintf(stderr, "%s: %d, have 0x%08x, want 0x%08x\n",
+            __func__, port, value & mask, expect & mask);
+#endif
+    g_assert((value & mask) == (expect & mask));
+}
+
+/* tests */
+
+static void pci_init(void)
+{
+    if (pcibus) {
+        return;
+    }
+    pcibus = qpci_init_pc();
+    g_assert(pcibus != NULL);
+
+    pci_init_one(&uhci1, QPCI_DEVFN(0x1d, 0), 4);
+    pci_init_one(&uhci2, QPCI_DEVFN(0x1d, 1), 4);
+    pci_init_one(&uhci3, QPCI_DEVFN(0x1d, 2), 4);
+    pci_init_one(&ehci1, QPCI_DEVFN(0x1d, 7), 0);
+}
+
+static void pci_uhci_port_1(void)
+{
+    g_assert(pcibus != NULL);
+
+    uhci_port_test(&uhci1, 0, UHCI_PORT_CCS); /* usb-tablet  */
+    uhci_port_test(&uhci1, 1, UHCI_PORT_CCS); /* usb-storage */
+    uhci_port_test(&uhci2, 0, 0);
+    uhci_port_test(&uhci2, 1, 0);
+    uhci_port_test(&uhci3, 0, 0);
+    uhci_port_test(&uhci3, 1, 0);
+}
+
+static void pci_ehci_port_1(void)
+{
+    int i;
+
+    g_assert(pcibus != NULL);
+
+    for (i = 0; i < 6; i++) {
+        ehci_port_test(&ehci1, i, PORTSC_POWNER | PORTSC_PPOWER);
+    }
+}
+
+static void pci_ehci_config(void)
+{
+    /* hands over all ports from companion uhci to ehci */
+    qpci_io_writew(ehci1.dev, ehci1.base + 0x60, 1);
+}
+
+static void pci_uhci_port_2(void)
+{
+    g_assert(pcibus != NULL);
+
+    uhci_port_test(&uhci1, 0, 0); /* usb-tablet,  @ehci */
+    uhci_port_test(&uhci1, 1, 0); /* usb-storage, @ehci */
+    uhci_port_test(&uhci2, 0, 0);
+    uhci_port_test(&uhci2, 1, 0);
+    uhci_port_test(&uhci3, 0, 0);
+    uhci_port_test(&uhci3, 1, 0);
+}
+
+static void pci_ehci_port_2(void)
+{
+    static uint32_t expect[] = {
+        PORTSC_PPOWER | PORTSC_CONNECT, /* usb-tablet  */
+        PORTSC_PPOWER | PORTSC_CONNECT, /* usb-storage */
+        PORTSC_PPOWER,
+        PORTSC_PPOWER,
+        PORTSC_PPOWER,
+        PORTSC_PPOWER,
+    };
+    int i;
+
+    g_assert(pcibus != NULL);
+
+    for (i = 0; i < 6; i++) {
+        ehci_port_test(&ehci1, i, expect[i]);
+    }
 }
 
 int main(int argc, char **argv)
@@ -22,7 +159,12 @@ int main(int argc, char **argv)
     int ret;
 
     g_test_init(&argc, &argv, NULL);
-    qtest_add_func("/ehci/pci/nop", pci_nop);
+    qtest_add_func("/ehci/pci/init", pci_init);
+    qtest_add_func("/ehci/pci/uhci-port-1", pci_uhci_port_1);
+    qtest_add_func("/ehci/pci/ehci-port-1", pci_ehci_port_1);
+    qtest_add_func("/ehci/pci/ehci-config", pci_ehci_config);
+    qtest_add_func("/ehci/pci/uhci-port-2", pci_uhci_port_2);
+    qtest_add_func("/ehci/pci/ehci-port-2", pci_ehci_port_2);
 
     qtest_start("-machine q35 -device ich9-usb-ehci1,bus=pcie.0,addr=1d.7,"
                 "multifunction=on,id=ich9-ehci-1 "
@@ -31,7 +173,10 @@ int main(int argc, char **argv)
                 "-device ich9-usb-uhci2,bus=pcie.0,addr=1d.1,"
                 "multifunction=on,masterbus=ich9-ehci-1.0,firstport=2 "
                 "-device ich9-usb-uhci3,bus=pcie.0,addr=1d.2,"
-                "multifunction=on,masterbus=ich9-ehci-1.0,firstport=4");
+                "multifunction=on,masterbus=ich9-ehci-1.0,firstport=4 "
+                "-drive if=none,id=usbcdrom,media=cdrom "
+                "-device usb-tablet,bus=ich9-ehci-1.0,port=1,usb_version=1 "
+                "-device usb-storage,bus=ich9-ehci-1.0,port=2,drive=usbcdrom ");
     ret = g_test_run();
 
     qtest_end();
diff --git a/thread-pool.c b/thread-pool.c
index fbdd3ffa3a..dfb699dd94 100644
--- a/thread-pool.c
+++ b/thread-pool.c
@@ -224,6 +224,7 @@ static void thread_pool_cancel(BlockDriverAIOCB *acb)
         pool->pending_cancellations--;
     }
     qemu_mutex_unlock(&pool->lock);
+    event_notifier_ready(&pool->notifier);
 }
 
 static const AIOCBInfo thread_pool_aiocb_info = {
diff --git a/trace-events b/trace-events
index 2c5b30763e..ffe6e62031 100644
--- a/trace-events
+++ b/trace-events
@@ -371,7 +371,7 @@ usb_xhci_irq_msix_use(uint32_t nr) "nr %d"
 usb_xhci_irq_msix_unuse(uint32_t nr) "nr %d"
 usb_xhci_queue_event(uint32_t vector, uint32_t idx, const char *trb, const char *evt, uint64_t param, uint32_t status, uint32_t control) "v %d, idx %d, %s, %s, p %016" PRIx64 ", s %08x, c 0x%08x"
 usb_xhci_fetch_trb(uint64_t addr, const char *name, uint64_t param, uint32_t status, uint32_t control) "addr %016" PRIx64 ", %s, p %016" PRIx64 ", s %08x, c 0x%08x"
-usb_xhci_port_reset(uint32_t port) "port %d"
+usb_xhci_port_reset(uint32_t port, bool warm) "port %d, warm %d"
 usb_xhci_port_link(uint32_t port, uint32_t pls) "port %d, pls %d"
 usb_xhci_port_notify(uint32_t port, uint32_t pls) "port %d, bits %x"
 usb_xhci_slot_enable(uint32_t slotid) "slotid %d"
@@ -627,9 +627,6 @@ lm32_uart_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
 lm32_uart_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
 lm32_uart_irq_state(int level) "irq state %d"
 
-# hw/misc/lm32_sys.c
-lm32_sys_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
-
 # hw/scsi/megasas.c
 megasas_init_firmware(uint64_t pa) "pa %" PRIx64 " "
 megasas_init_queue(uint64_t queue_pa, int queue_len, uint64_t head, uint64_t tail, uint32_t flags) "queue at %" PRIx64 " len %d head %" PRIx64 " tail %" PRIx64 " flags %x"
@@ -688,17 +685,21 @@ megasas_dcmd_ld_get_list(int cmd, int num, int max) "scmd %d: DCMD LD get list:
 megasas_dcmd_ld_get_info(int cmd, int ld_id) "scmd %d: DCMD LD get info for dev %d"
 megasas_dcmd_pd_get_info(int cmd, int pd_id) "scmd %d: DCMD PD get info for dev %d"
 megasas_dcmd_pd_list_query(int cmd, int flags) "scmd %d: DCMD PD list query flags %x"
+megasas_dcmd_ld_list_query(int cmd, int flags) "scmd %d: DCMD LD list query flags %x"
 megasas_dcmd_unsupported(int cmd, unsigned long size) "scmd %d: set properties len %ld"
 megasas_abort_frame(int cmd, int abort_cmd) "scmd %d: aborting frame %x"
 megasas_abort_no_cmd(int cmd, uint64_t context) "scmd %d: no active command for frame context %" PRIx64 ""
 megasas_abort_invalid_context(int cmd, uint64_t context, int abort_cmd) "scmd %d: invalid frame context %" PRIx64 " for abort frame %x"
 megasas_reset(void) "Reset"
-megasas_init(int sges, int cmds, const char *intr, const char *mode) "Using %d sges, %d cmds, %s, %s mode"
+megasas_init(int sges, int cmds, const char *mode) "Using %d sges, %d cmds, %s mode"
 megasas_msix_raise(int vector) "vector %d"
+megasas_msi_raise(int vector) "vector %d"
 megasas_irq_lower(void) "INTx"
 megasas_irq_raise(void) "INTx"
 megasas_intr_enabled(void) "Interrupts enabled"
 megasas_intr_disabled(void) "Interrupts disabled"
+megasas_msix_enabled(int vector) "vector %d"
+megasas_msi_enabled(int vector) "vector %d"
 megasas_mmio_readl(unsigned long addr, uint32_t val) "addr 0x%lx: 0x%x"
 megasas_mmio_invalid_readl(unsigned long addr) "addr 0x%lx"
 megasas_mmio_writel(uint32_t addr, uint32_t val) "addr 0x%x: 0x%x"
@@ -862,8 +863,8 @@ escc_mem_writeb_data(char channel, uint32_t val) "Write channel %c, ch %d"
 escc_mem_readb_ctrl(char channel, uint32_t reg, uint8_t val) "Read channel %c, reg[%d] = %2.2x"
 escc_mem_readb_data(char channel, uint32_t ret) "Read channel %c, ch %d"
 escc_serial_receive_byte(char channel, int ch) "channel %c put ch %d"
-escc_sunkbd_event_in(int ch) "Untranslated keycode %2.2x"
-escc_sunkbd_event_out(int ch) "Translated keycode %2.2x"
+escc_sunkbd_event_in(int ch, const char *name, int down) "QKeyCode 0x%2.2x [%s], down %d"
+escc_sunkbd_event_out(int ch) "Translated keycode 0x%2.2x"
 escc_kbd_command(int val) "Command %d"
 escc_sunmouse_event(int dx, int dy, int buttons_state) "dx=%d dy=%d buttons=%01x"
 
@@ -1041,12 +1042,21 @@ displaychangelistener_unregister(void *dcl, const char *name) "%p [ %s ]"
 ppm_save(const char *filename, void *display_surface) "%s surface=%p"
 
 # ui/gtk.c
-gd_switch(int width, int height) "width=%d, height=%d"
-gd_update(int x, int y, int w, int h) "x=%d, y=%d, w=%d, h=%d"
-gd_key_event(int gdk_keycode, int qemu_keycode, const char *action) "translated GDK keycode %d to QEMU keycode %d (%s)"
+gd_switch(const char *tab, int width, int height) "tab=%s, width=%d, height=%d"
+gd_update(const char *tab, int x, int y, int w, int h) "tab=%s, x=%d, y=%d, w=%d, h=%d"
+gd_key_event(const char *tab, int gdk_keycode, int qemu_keycode, const char *action) "tab=%s, translated GDK keycode %d to QEMU keycode %d (%s)"
+gd_grab(const char *tab, const char *device, bool on) "tab=%s, %s %d"
+
+# ui/vnc.c
+vnc_key_guest_leds(bool caps, bool num, bool scroll) "caps %d, num %d, scroll %d"
+vnc_key_map_init(const char *layout) "%s"
+vnc_key_event_ext(bool down, int sym, int keycode, const char *name) "down %d, sym 0x%x, keycode 0x%x [%s]"
+vnc_key_event_map(bool down, int sym, int keycode, const char *name) "down %d, sym 0x%x -> keycode 0x%x [%s]"
+vnc_key_sync_numlock(bool on) "%d"
+vnc_key_sync_capslock(bool on) "%d"
 
 # ui/input.c
-input_event_key_number(int conidx, int number, bool down) "con %d, key number 0x%x, down %d"
+input_event_key_number(int conidx, int number, const char *qcode, bool down) "con %d, key number 0x%x [%s], down %d"
 input_event_key_qcode(int conidx, const char *qcode, bool down) "con %d, key qcode %s, down %d"
 input_event_btn(int conidx, const char *btn, bool down) "con %d, button %s, down %d"
 input_event_rel(int conidx, const char *axis, int value) "con %d, axis %s, value %d"
diff --git a/translate-all.c b/translate-all.c
index 5549a85ed5..6b7b46e761 100644
--- a/translate-all.c
+++ b/translate-all.c
@@ -475,6 +475,10 @@ static inline PageDesc *page_find(tb_page_addr_t index)
 #elif defined(__s390x__)
   /* We have a +- 4GB range on the branches; leave some slop.  */
 # define MAX_CODE_GEN_BUFFER_SIZE  (3ul * 1024 * 1024 * 1024)
+#elif defined(__mips__)
+  /* We have a 256MB branch region, but leave room to make sure the
+     main executable is also within that region.  */
+# define MAX_CODE_GEN_BUFFER_SIZE  (128ul * 1024 * 1024)
 #else
 # define MAX_CODE_GEN_BUFFER_SIZE  ((size_t)-1)
 #endif
@@ -509,14 +513,47 @@ static inline size_t size_code_gen_buffer(size_t tb_size)
     return tb_size;
 }
 
+#ifdef __mips__
+/* In order to use J and JAL within the code_gen_buffer, we require
+   that the buffer not cross a 256MB boundary.  */
+static inline bool cross_256mb(void *addr, size_t size)
+{
+    return ((uintptr_t)addr ^ ((uintptr_t)addr + size)) & 0xf0000000;
+}
+
+/* We weren't able to allocate a buffer without crossing that boundary,
+   so make do with the larger portion of the buffer that doesn't cross.
+   Returns the new base of the buffer, and adjusts code_gen_buffer_size.  */
+static inline void *split_cross_256mb(void *buf1, size_t size1)
+{
+    void *buf2 = (void *)(((uintptr_t)buf1 + size1) & 0xf0000000);
+    size_t size2 = buf1 + size1 - buf2;
+
+    size1 = buf2 - buf1;
+    if (size1 < size2) {
+        size1 = size2;
+        buf1 = buf2;
+    }
+
+    tcg_ctx.code_gen_buffer_size = size1;
+    return buf1;
+}
+#endif
+
 #ifdef USE_STATIC_CODE_GEN_BUFFER
 static uint8_t static_code_gen_buffer[DEFAULT_CODE_GEN_BUFFER_SIZE]
     __attribute__((aligned(CODE_GEN_ALIGN)));
 
 static inline void *alloc_code_gen_buffer(void)
 {
-    map_exec(static_code_gen_buffer, tcg_ctx.code_gen_buffer_size);
-    return static_code_gen_buffer;
+    void *buf = static_code_gen_buffer;
+#ifdef __mips__
+    if (cross_256mb(buf, tcg_ctx.code_gen_buffer_size)) {
+        buf = split_cross_256mb(buf, tcg_ctx.code_gen_buffer_size);
+    }
+#endif
+    map_exec(buf, tcg_ctx.code_gen_buffer_size);
+    return buf;
 }
 #elif defined(USE_MMAP)
 static inline void *alloc_code_gen_buffer(void)
@@ -545,20 +582,76 @@ static inline void *alloc_code_gen_buffer(void)
     start = 0x40000000ul;
 # elif defined(__s390x__)
     start = 0x90000000ul;
+# elif defined(__mips__)
+    /* ??? We ought to more explicitly manage layout for softmmu too.  */
+#  ifdef CONFIG_USER_ONLY
+    start = 0x68000000ul;
+#  elif _MIPS_SIM == _ABI64
+    start = 0x128000000ul;
+#  else
+    start = 0x08000000ul;
+#  endif
 # endif
 
     buf = mmap((void *)start, tcg_ctx.code_gen_buffer_size,
                PROT_WRITE | PROT_READ | PROT_EXEC, flags, -1, 0);
-    return buf == MAP_FAILED ? NULL : buf;
+    if (buf == MAP_FAILED) {
+        return NULL;
+    }
+
+#ifdef __mips__
+    if (cross_256mb(buf, tcg_ctx.code_gen_buffer_size)) {
+        /* Try again, with the original still mapped, to avoid re-aquiring
+           that 256mb crossing.  This time don't specify an address.  */
+        size_t size2, size1 = tcg_ctx.code_gen_buffer_size;
+        void *buf2 = mmap(NULL, size1, PROT_WRITE | PROT_READ | PROT_EXEC,
+                          flags, -1, 0);
+        if (buf2 != MAP_FAILED) {
+            if (!cross_256mb(buf2, size1)) {
+                /* Success!  Use the new buffer.  */
+                munmap(buf, size1);
+                return buf2;
+            }
+            /* Failure.  Work with what we had.  */
+            munmap(buf2, size1);
+        }
+
+        /* Split the original buffer.  Free the smaller half.  */
+        buf2 = split_cross_256mb(buf, size1);
+        size2 = tcg_ctx.code_gen_buffer_size;
+        munmap(buf + (buf == buf2 ? size2 : 0), size1 - size2);
+        return buf2;
+    }
+#endif
+
+    return buf;
 }
 #else
 static inline void *alloc_code_gen_buffer(void)
 {
     void *buf = g_malloc(tcg_ctx.code_gen_buffer_size);
 
-    if (buf) {
-        map_exec(buf, tcg_ctx.code_gen_buffer_size);
+    if (buf == NULL) {
+        return NULL;
     }
+
+#ifdef __mips__
+    if (cross_256mb(buf, tcg_ctx.code_gen_buffer_size)) {
+        void *buf2 = g_malloc(tcg_ctx.code_gen_buffer_size);
+        if (buf2 != NULL && !cross_256mb(buf2, size1)) {
+            /* Success!  Use the new buffer.  */
+            free(buf);
+            buf = buf2;
+        } else {
+            /* Failure.  Work with what we had.  Since this is malloc
+               and not mmap, we can't free the other half.  */
+            free(buf2);
+            buf = split_cross_256mb(buf, tcg_ctx.code_gen_buffer_size);
+        }
+    }
+#endif
+
+    map_exec(buf, tcg_ctx.code_gen_buffer_size);
     return buf;
 }
 #endif /* USE_STATIC_CODE_GEN_BUFFER, USE_MMAP */
diff --git a/ui/Makefile.objs b/ui/Makefile.objs
index 4af420bfa8..6afb52a93c 100644
--- a/ui/Makefile.objs
+++ b/ui/Makefile.objs
@@ -7,7 +7,8 @@ vnc-obj-$(CONFIG_VNC_SASL) += vnc-auth-sasl.o
 vnc-obj-$(CONFIG_VNC_WS) += vnc-ws.o
 vnc-obj-y += vnc-jobs.o
 
-common-obj-y += keymaps.o console.o cursor.o input.o input-legacy.o qemu-pixman.o
+common-obj-y += keymaps.o console.o cursor.o qemu-pixman.o
+common-obj-y += input.o input-keymap.o input-legacy.o
 common-obj-$(CONFIG_SPICE) += spice-core.o spice-input.o spice-display.o
 common-obj-$(CONFIG_SDL) += sdl.o sdl_zoom.o x_keymap.o sdl2.o
 common-obj-$(CONFIG_COCOA) += cocoa.o
diff --git a/ui/console.c b/ui/console.c
index 34d1eaa955..2ce55a69d0 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -143,8 +143,6 @@ struct QemuConsole {
     TextCell *cells;
     int text_x[2], text_y[2], cursor_invalidate;
     int echo;
-    bool cursor_visible_phase;
-    QEMUTimer *cursor_timer;
 
     int update_x0;
     int update_y0;
@@ -177,10 +175,14 @@ static DisplayState *display_state;
 static QemuConsole *active_console;
 static QemuConsole *consoles[MAX_CONSOLES];
 static int nb_consoles = 0;
+static bool cursor_visible_phase;
+static QEMUTimer *cursor_timer;
 
 static void text_console_do_init(CharDriverState *chr, DisplayState *ds);
 static void dpy_refresh(DisplayState *s);
 static DisplayState *get_alloc_displaystate(void);
+static void text_console_update_cursor_timer(void);
+static void text_console_update_cursor(void *opaque);
 
 static void gui_update(void *opaque)
 {
@@ -475,6 +477,9 @@ static inline void text_update_xy(QemuConsole *s, int x, int y)
 
 static void invalidate_xy(QemuConsole *s, int x, int y)
 {
+    if (!qemu_console_is_visible(s)) {
+        return;
+    }
     if (s->update_x0 > x * FONT_WIDTH)
         s->update_x0 = x * FONT_WIDTH;
     if (s->update_y0 > y * FONT_HEIGHT)
@@ -490,25 +495,20 @@ static void update_xy(QemuConsole *s, int x, int y)
     TextCell *c;
     int y1, y2;
 
-    if (!qemu_console_is_visible(s)) {
-        return;
-    }
-
     if (s->ds->have_text) {
         text_update_xy(s, x, y);
     }
 
-    if (s->ds->have_gfx) {
-        y1 = (s->y_base + y) % s->total_height;
-        y2 = y1 - s->y_displayed;
-        if (y2 < 0)
-            y2 += s->total_height;
-        if (y2 < s->height) {
-            c = &s->cells[y1 * s->width + x];
-            vga_putcharxy(s, x, y2, c->ch,
-                          &(c->t_attrib));
-            invalidate_xy(s, x, y2);
-        }
+    y1 = (s->y_base + y) % s->total_height;
+    y2 = y1 - s->y_displayed;
+    if (y2 < 0) {
+        y2 += s->total_height;
+    }
+    if (y2 < s->height) {
+        c = &s->cells[y1 * s->width + x];
+        vga_putcharxy(s, x, y2, c->ch,
+                      &(c->t_attrib));
+        invalidate_xy(s, x, y2);
     }
 }
 
@@ -518,33 +518,28 @@ static void console_show_cursor(QemuConsole *s, int show)
     int y, y1;
     int x = s->x;
 
-    if (!qemu_console_is_visible(s)) {
-        return;
-    }
-
     if (s->ds->have_text) {
         s->cursor_invalidate = 1;
     }
 
-    if (s->ds->have_gfx) {
-        if (x >= s->width) {
-            x = s->width - 1;
-        }
-        y1 = (s->y_base + s->y) % s->total_height;
-        y = y1 - s->y_displayed;
-        if (y < 0)
-            y += s->total_height;
-        if (y < s->height) {
-            c = &s->cells[y1 * s->width + x];
-            if (show && s->cursor_visible_phase) {
-                TextAttributes t_attrib = s->t_attrib_default;
-                t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
-                vga_putcharxy(s, x, y, c->ch, &t_attrib);
-            } else {
-                vga_putcharxy(s, x, y, c->ch, &(c->t_attrib));
-            }
-            invalidate_xy(s, x, y);
+    if (x >= s->width) {
+        x = s->width - 1;
+    }
+    y1 = (s->y_base + s->y) % s->total_height;
+    y = y1 - s->y_displayed;
+    if (y < 0) {
+        y += s->total_height;
+    }
+    if (y < s->height) {
+        c = &s->cells[y1 * s->width + x];
+        if (show && cursor_visible_phase) {
+            TextAttributes t_attrib = s->t_attrib_default;
+            t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
+            vga_putcharxy(s, x, y, c->ch, &t_attrib);
+        } else {
+            vga_putcharxy(s, x, y, c->ch, &(c->t_attrib));
         }
+        invalidate_xy(s, x, y);
     }
 }
 
@@ -554,10 +549,6 @@ static void console_refresh(QemuConsole *s)
     TextCell *c;
     int x, y, y1;
 
-    if (!qemu_console_is_visible(s)) {
-        return;
-    }
-
     if (s->ds->have_text) {
         s->text_x[0] = 0;
         s->text_y[0] = 0;
@@ -566,25 +557,23 @@ static void console_refresh(QemuConsole *s)
         s->cursor_invalidate = 1;
     }
 
-    if (s->ds->have_gfx) {
-        vga_fill_rect(s, 0, 0, surface_width(surface), surface_height(surface),
-                      color_table_rgb[0][COLOR_BLACK]);
-        y1 = s->y_displayed;
-        for (y = 0; y < s->height; y++) {
-            c = s->cells + y1 * s->width;
-            for (x = 0; x < s->width; x++) {
-                vga_putcharxy(s, x, y, c->ch,
-                              &(c->t_attrib));
-                c++;
-            }
-            if (++y1 == s->total_height) {
-                y1 = 0;
-            }
+    vga_fill_rect(s, 0, 0, surface_width(surface), surface_height(surface),
+                  color_table_rgb[0][COLOR_BLACK]);
+    y1 = s->y_displayed;
+    for (y = 0; y < s->height; y++) {
+        c = s->cells + y1 * s->width;
+        for (x = 0; x < s->width; x++) {
+            vga_putcharxy(s, x, y, c->ch,
+                          &(c->t_attrib));
+            c++;
+        }
+        if (++y1 == s->total_height) {
+            y1 = 0;
         }
-        console_show_cursor(s, 1);
-        dpy_gfx_update(s, 0, 0,
-                       surface_width(surface), surface_height(surface));
     }
+    console_show_cursor(s, 1);
+    dpy_gfx_update(s, 0, 0,
+                   surface_width(surface), surface_height(surface));
 }
 
 static void console_scroll(QemuConsole *s, int ydelta)
@@ -640,7 +629,7 @@ static void console_put_lf(QemuConsole *s)
             c->t_attrib = s->t_attrib_default;
             c++;
         }
-        if (qemu_console_is_visible(s) && s->y_displayed == s->y_base) {
+        if (s->y_displayed == s->y_base) {
             if (s->ds->have_text) {
                 s->text_x[0] = 0;
                 s->text_y[0] = 0;
@@ -648,18 +637,16 @@ static void console_put_lf(QemuConsole *s)
                 s->text_y[1] = s->height - 1;
             }
 
-            if (s->ds->have_gfx) {
-                vga_bitblt(s, 0, FONT_HEIGHT, 0, 0,
-                           s->width * FONT_WIDTH,
-                           (s->height - 1) * FONT_HEIGHT);
-                vga_fill_rect(s, 0, (s->height - 1) * FONT_HEIGHT,
-                              s->width * FONT_WIDTH, FONT_HEIGHT,
-                              color_table_rgb[0][s->t_attrib_default.bgcol]);
-                s->update_x0 = 0;
-                s->update_y0 = 0;
-                s->update_x1 = s->width * FONT_WIDTH;
-                s->update_y1 = s->height * FONT_HEIGHT;
-            }
+            vga_bitblt(s, 0, FONT_HEIGHT, 0, 0,
+                       s->width * FONT_WIDTH,
+                       (s->height - 1) * FONT_HEIGHT);
+            vga_fill_rect(s, 0, (s->height - 1) * FONT_HEIGHT,
+                          s->width * FONT_WIDTH, FONT_HEIGHT,
+                          color_table_rgb[0][s->t_attrib_default.bgcol]);
+            s->update_x0 = 0;
+            s->update_y0 = 0;
+            s->update_x1 = s->width * FONT_WIDTH;
+            s->update_y1 = s->height * FONT_HEIGHT;
         }
     }
 }
@@ -1004,9 +991,6 @@ void console_select(unsigned int index)
     if (s) {
         DisplayState *ds = s->ds;
 
-        if (active_console && active_console->cursor_timer) {
-            timer_del(active_console->cursor_timer);
-        }
         active_console = s;
         if (ds->have_gfx) {
             QLIST_FOREACH(dcl, &ds->listeners, next) {
@@ -1023,10 +1007,7 @@ void console_select(unsigned int index)
         if (ds->have_text) {
             dpy_text_resize(s, s->width, s->height);
         }
-        if (s->cursor_timer) {
-            timer_mod(s->cursor_timer,
-                   qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + CONSOLE_CURSOR_PERIOD / 2);
-        }
+        text_console_update_cursor(NULL);
     }
 }
 
@@ -1075,13 +1056,11 @@ static void kbd_send_chars(void *opaque)
 }
 
 /* called when an ascii key is pressed */
-void kbd_put_keysym(int keysym)
+void kbd_put_keysym_console(QemuConsole *s, int keysym)
 {
-    QemuConsole *s;
     uint8_t buf[16], *q;
     int c;
 
-    s = active_console;
     if (!s || (s->console_type == GRAPHIC_CONSOLE))
         return;
 
@@ -1130,6 +1109,44 @@ void kbd_put_keysym(int keysym)
     }
 }
 
+static const int qcode_to_keysym[Q_KEY_CODE_MAX] = {
+    [Q_KEY_CODE_UP]     = QEMU_KEY_UP,
+    [Q_KEY_CODE_DOWN]   = QEMU_KEY_DOWN,
+    [Q_KEY_CODE_RIGHT]  = QEMU_KEY_RIGHT,
+    [Q_KEY_CODE_LEFT]   = QEMU_KEY_LEFT,
+    [Q_KEY_CODE_HOME]   = QEMU_KEY_HOME,
+    [Q_KEY_CODE_END]    = QEMU_KEY_END,
+    [Q_KEY_CODE_PGUP]   = QEMU_KEY_PAGEUP,
+    [Q_KEY_CODE_PGDN]   = QEMU_KEY_PAGEDOWN,
+    [Q_KEY_CODE_DELETE] = QEMU_KEY_DELETE,
+};
+
+bool kbd_put_qcode_console(QemuConsole *s, int qcode)
+{
+    int keysym;
+
+    keysym = qcode_to_keysym[qcode];
+    if (keysym == 0) {
+        return false;
+    }
+    kbd_put_keysym_console(s, keysym);
+    return true;
+}
+
+void kbd_put_string_console(QemuConsole *s, const char *str, int len)
+{
+    int i;
+
+    for (i = 0; i < len && str[i]; i++) {
+        kbd_put_keysym_console(s, str[i]);
+    }
+}
+
+void kbd_put_keysym(int keysym)
+{
+    kbd_put_keysym_console(active_console, keysym);
+}
+
 static void text_console_invalidate(void *opaque)
 {
     QemuConsole *s = (QemuConsole *) opaque;
@@ -1167,9 +1184,9 @@ static void text_console_update(void *opaque, console_ch_t *chardata)
     }
 }
 
-static QemuConsole *new_console(DisplayState *ds, console_type_t console_type)
+static QemuConsole *new_console(DisplayState *ds, console_type_t console_type,
+                                uint32_t head)
 {
-    Error *local_err = NULL;
     Object *obj;
     QemuConsole *s;
     int i;
@@ -1179,13 +1196,14 @@ static QemuConsole *new_console(DisplayState *ds, console_type_t console_type)
 
     obj = object_new(TYPE_QEMU_CONSOLE);
     s = QEMU_CONSOLE(obj);
+    s->head = head;
     object_property_add_link(obj, "device", TYPE_DEVICE,
                              (Object **)&s->device,
                              object_property_allow_set_link,
                              OBJ_PROP_LINK_UNREF_ON_RELEASE,
-                             &local_err);
+                             &error_abort);
     object_property_add_uint32_ptr(obj, "head",
-                                   &s->head, &local_err);
+                                   &s->head, &error_abort);
 
     if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
         (console_type == GRAPHIC_CONSOLE))) {
@@ -1270,19 +1288,18 @@ DisplaySurface *qemu_create_displaysurface_from(int width, int height, int bpp,
     return surface;
 }
 
-static DisplaySurface *qemu_create_dummy_surface(void)
+static DisplaySurface *qemu_create_message_surface(int w, int h,
+                                                   const char *msg)
 {
-    static const char msg[] =
-        "This VM has no graphic display device.";
-    DisplaySurface *surface = qemu_create_displaysurface(640, 480);
+    DisplaySurface *surface = qemu_create_displaysurface(w, h);
     pixman_color_t bg = color_table_rgb[0][COLOR_BLACK];
     pixman_color_t fg = color_table_rgb[0][COLOR_WHITE];
     pixman_image_t *glyph;
     int len, x, y, i;
 
     len = strlen(msg);
-    x = (640/FONT_WIDTH  - len) / 2;
-    y = (480/FONT_HEIGHT - 1)   / 2;
+    x = (w / FONT_WIDTH  - len) / 2;
+    y = (h / FONT_HEIGHT - 1)   / 2;
     for (i = 0; i < len; i++) {
         glyph = qemu_pixman_glyph_from_vgafont(FONT_HEIGHT, vgafont16, msg[i]);
         qemu_pixman_glyph_render(glyph, surface->image, &fg, &bg,
@@ -1304,6 +1321,8 @@ void qemu_free_displaysurface(DisplaySurface *surface)
 
 void register_displaychangelistener(DisplayChangeListener *dcl)
 {
+    static const char nodev[] =
+        "This VM has no graphic display device.";
     static DisplaySurface *dummy;
     QemuConsole *con;
 
@@ -1322,11 +1341,12 @@ void register_displaychangelistener(DisplayChangeListener *dcl)
             dcl->ops->dpy_gfx_switch(dcl, con->surface);
         } else {
             if (!dummy) {
-                dummy = qemu_create_dummy_surface();
+                dummy = qemu_create_message_surface(640, 480, nodev);
             }
             dcl->ops->dpy_gfx_switch(dcl, dummy);
         }
     }
+    text_console_update_cursor(NULL);
 }
 
 void update_displaychangelistener(DisplayChangeListener *dcl,
@@ -1550,6 +1570,8 @@ static DisplayState *get_alloc_displaystate(void)
 {
     if (!display_state) {
         display_state = g_new0(DisplayState, 1);
+        cursor_timer = timer_new_ms(QEMU_CLOCK_REALTIME,
+                                    text_console_update_cursor, NULL);
     }
     return display_state;
 }
@@ -1560,7 +1582,6 @@ static DisplayState *get_alloc_displaystate(void)
  */
 DisplayState *init_displaystate(void)
 {
-    Error *local_err = NULL;
     gchar *name;
     int i;
 
@@ -1579,7 +1600,7 @@ DisplayState *init_displaystate(void)
          * doesn't change any more */
         name = g_strdup_printf("console[%d]", i);
         object_property_add_child(container_get(object_get_root(), "/backend"),
-                                  name, OBJECT(consoles[i]), &local_err);
+                                  name, OBJECT(consoles[i]), &error_abort);
         g_free(name);
     }
 
@@ -1590,7 +1611,8 @@ QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head,
                                   const GraphicHwOps *hw_ops,
                                   void *opaque)
 {
-    Error *local_err = NULL;
+    static const char noinit[] =
+        "Guest has not initialized the display (yet).";
     int width = 640;
     int height = 480;
     QemuConsole *s;
@@ -1598,17 +1620,15 @@ QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head,
 
     ds = get_alloc_displaystate();
     trace_console_gfx_new();
-    s = new_console(ds, GRAPHIC_CONSOLE);
+    s = new_console(ds, GRAPHIC_CONSOLE, head);
     s->hw_ops = hw_ops;
     s->hw = opaque;
     if (dev) {
-        object_property_set_link(OBJECT(s), OBJECT(dev),
-                                 "device", &local_err);
-        object_property_set_int(OBJECT(s), head,
-                                "head", &local_err);
+        object_property_set_link(OBJECT(s), OBJECT(dev), "device",
+                                 &error_abort);
     }
 
-    s->surface = qemu_create_displaysurface(width, height);
+    s->surface = qemu_create_message_surface(width, height, noinit);
     return s;
 }
 
@@ -1622,7 +1642,6 @@ QemuConsole *qemu_console_lookup_by_index(unsigned int index)
 
 QemuConsole *qemu_console_lookup_by_device(DeviceState *dev, uint32_t head)
 {
-    Error *local_err = NULL;
     Object *obj;
     uint32_t h;
     int i;
@@ -1632,12 +1651,12 @@ QemuConsole *qemu_console_lookup_by_device(DeviceState *dev, uint32_t head)
             continue;
         }
         obj = object_property_get_link(OBJECT(consoles[i]),
-                                       "device", &local_err);
+                                       "device", &error_abort);
         if (DEVICE(obj) != dev) {
             continue;
         }
         h = object_property_get_int(OBJECT(consoles[i]),
-                                    "head", &local_err);
+                                    "head", &error_abort);
         if (h != head) {
             continue;
         }
@@ -1712,14 +1731,32 @@ static void text_console_set_echo(CharDriverState *chr, bool echo)
     s->echo = echo;
 }
 
+static void text_console_update_cursor_timer(void)
+{
+    timer_mod(cursor_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME)
+              + CONSOLE_CURSOR_PERIOD / 2);
+}
+
 static void text_console_update_cursor(void *opaque)
 {
-    QemuConsole *s = opaque;
+    QemuConsole *s;
+    int i, count = 0;
 
-    s->cursor_visible_phase = !s->cursor_visible_phase;
-    graphic_hw_invalidate(s);
-    timer_mod(s->cursor_timer,
-                   qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + CONSOLE_CURSOR_PERIOD / 2);
+    cursor_visible_phase = !cursor_visible_phase;
+
+    for (i = 0; i < nb_consoles; i++) {
+        s = consoles[i];
+        if (qemu_console_is_graphic(s) ||
+            !qemu_console_is_visible(s)) {
+            continue;
+        }
+        count++;
+        graphic_hw_invalidate(s);
+    }
+
+    if (count) {
+        text_console_update_cursor_timer();
+    }
 }
 
 static const GraphicHwOps text_console_ops = {
@@ -1755,9 +1792,6 @@ static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
         s->surface = qemu_create_displaysurface(g_width, g_height);
     }
 
-    s->cursor_timer =
-        timer_new_ms(QEMU_CLOCK_REALTIME, text_console_update_cursor, s);
-
     s->hw_ops = &text_console_ops;
     s->hw = s;
 
@@ -1811,9 +1845,9 @@ static CharDriverState *text_console_init(ChardevVC *vc)
 
     trace_console_txt_new(width, height);
     if (width == 0 || height == 0) {
-        s = new_console(NULL, TEXT_CONSOLE);
+        s = new_console(NULL, TEXT_CONSOLE, 0);
     } else {
-        s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE);
+        s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE, 0);
         s->surface = qemu_create_displaysurface(width, height);
     }
 
diff --git a/ui/curses.c b/ui/curses.c
index b044790e43..8edb038bb3 100644
--- a/ui/curses.c
+++ b/ui/curses.c
@@ -277,31 +277,41 @@ static void curses_refresh(DisplayChangeListener *dcl)
              * events, we need to emit both for each key received */
             if (keycode & SHIFT) {
                 qemu_input_event_send_key_number(NULL, SHIFT_CODE, true);
+                qemu_input_event_send_key_delay(0);
             }
             if (keycode & CNTRL) {
                 qemu_input_event_send_key_number(NULL, CNTRL_CODE, true);
+                qemu_input_event_send_key_delay(0);
             }
             if (keycode & ALT) {
                 qemu_input_event_send_key_number(NULL, ALT_CODE, true);
+                qemu_input_event_send_key_delay(0);
             }
             if (keycode & ALTGR) {
                 qemu_input_event_send_key_number(NULL, GREY | ALT_CODE, true);
+                qemu_input_event_send_key_delay(0);
             }
 
-            qemu_input_event_send_key_number(NULL, keycode, true);
-            qemu_input_event_send_key_number(NULL, keycode, false);
+            qemu_input_event_send_key_number(NULL, keycode & KEY_MASK, true);
+            qemu_input_event_send_key_delay(0);
+            qemu_input_event_send_key_number(NULL, keycode & KEY_MASK, false);
+            qemu_input_event_send_key_delay(0);
 
             if (keycode & ALTGR) {
                 qemu_input_event_send_key_number(NULL, GREY | ALT_CODE, false);
+                qemu_input_event_send_key_delay(0);
             }
             if (keycode & ALT) {
                 qemu_input_event_send_key_number(NULL, ALT_CODE, false);
+                qemu_input_event_send_key_delay(0);
             }
             if (keycode & CNTRL) {
                 qemu_input_event_send_key_number(NULL, CNTRL_CODE, false);
+                qemu_input_event_send_key_delay(0);
             }
             if (keycode & SHIFT) {
                 qemu_input_event_send_key_number(NULL, SHIFT_CODE, false);
+                qemu_input_event_send_key_delay(0);
             }
         } else {
             keysym = curses2qemu[chr];
diff --git a/ui/gtk.c b/ui/gtk.c
index 9f5061a1be..b9089360f0 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -67,13 +67,38 @@
 #include "x_keymap.h"
 #include "keymaps.h"
 #include "sysemu/char.h"
+#include "qom/object.h"
+#ifndef _WIN32
+#include <gdk/gdkx.h>
+#include <X11/XKBlib.h>
+#endif
 
 #define MAX_VCS 10
+#define VC_WINDOW_X_MIN  320
+#define VC_WINDOW_Y_MIN  240
+#define VC_TERM_X_MIN     80
+#define VC_TERM_Y_MIN     25
+#define VC_SCALE_MIN    0.25
+#define VC_SCALE_STEP   0.25
 
 #if !defined(CONFIG_VTE)
 # define VTE_CHECK_VERSION(a, b, c) 0
 #endif
 
+#if defined(CONFIG_VTE) && !GTK_CHECK_VERSION(3, 0, 0)
+/*
+ * The gtk2 vte terminal widget seriously messes up the window resize
+ * for some reason.  You basically can't make the qemu window smaller
+ * any more because the toplevel window geoemtry hints are overridden.
+ *
+ * Workaround that by hiding all vte widgets, except the one in the
+ * current tab.
+ *
+ * Luckily everything works smooth in gtk3.
+ */
+# define VTE_RESIZE_HACK 1
+#endif
+
 /* Compatibility define to let us build on both Gtk2 and Gtk3 */
 #if GTK_CHECK_VERSION(3, 0, 0)
 static inline void gdk_drawable_get_size(GdkWindow *w, gint *ww, gint *wh)
@@ -105,18 +130,48 @@ static const int modifier_keycode[] = {
     0x2a, 0x36, 0x1d, 0x9d, 0x38, 0xb8, 0xdb, 0xdd,
 };
 
-typedef struct VirtualConsole
-{
-    GtkWidget *menu_item;
-    GtkWidget *terminal;
+typedef struct GtkDisplayState GtkDisplayState;
+
+typedef struct VirtualGfxConsole {
+    GtkWidget *drawing_area;
+    DisplayChangeListener dcl;
+    DisplaySurface *ds;
+    pixman_image_t *convert;
+    cairo_surface_t *surface;
+    double scale_x;
+    double scale_y;
+} VirtualGfxConsole;
+
 #if defined(CONFIG_VTE)
-    GtkWidget *scrolled_window;
+typedef struct VirtualVteConsole {
+    GtkWidget *box;
+    GtkWidget *scrollbar;
+    GtkWidget *terminal;
     CharDriverState *chr;
+} VirtualVteConsole;
 #endif
+
+typedef enum VirtualConsoleType {
+    GD_VC_GFX,
+    GD_VC_VTE,
+} VirtualConsoleType;
+
+typedef struct VirtualConsole {
+    GtkDisplayState *s;
+    char *label;
+    GtkWidget *window;
+    GtkWidget *menu_item;
+    GtkWidget *tab_item;
+    VirtualConsoleType type;
+    union {
+        VirtualGfxConsole gfx;
+#if defined(CONFIG_VTE)
+        VirtualVteConsole vte;
+#endif
+    };
 } VirtualConsole;
 
-typedef struct GtkDisplayState
-{
+struct GtkDisplayState {
     GtkWidget *window;
 
     GtkWidget *menu_bar;
@@ -139,29 +194,24 @@ typedef struct GtkDisplayState
     GtkWidget *zoom_fit_item;
     GtkWidget *grab_item;
     GtkWidget *grab_on_hover_item;
-    GtkWidget *vga_item;
 
     int nb_vcs;
     VirtualConsole vc[MAX_VCS];
 
     GtkWidget *show_tabs_item;
+    GtkWidget *untabify_item;
 
     GtkWidget *vbox;
     GtkWidget *notebook;
-    GtkWidget *drawing_area;
-    cairo_surface_t *surface;
-    pixman_image_t *convert;
-    DisplayChangeListener dcl;
-    DisplaySurface *ds;
     int button_mask;
     gboolean last_set;
     int last_x;
     int last_y;
     int grab_x_root;
     int grab_y_root;
+    VirtualConsole *kbd_owner;
+    VirtualConsole *ptr_owner;
 
-    double scale_x;
-    double scale_y;
     gboolean full_screen;
 
     GdkCursor *null_cursor;
@@ -171,12 +221,52 @@ typedef struct GtkDisplayState
     bool external_pause_update;
 
     bool modifier_pressed[ARRAY_SIZE(modifier_keycode)];
-} GtkDisplayState;
+    bool has_evdev;
+};
 
-static GtkDisplayState *global_state;
+static void gd_grab_pointer(VirtualConsole *vc);
+static void gd_ungrab_pointer(GtkDisplayState *s);
 
 /** Utility Functions **/
 
+static VirtualConsole *gd_vc_find_by_menu(GtkDisplayState *s)
+{
+    VirtualConsole *vc;
+    gint i;
+
+    for (i = 0; i < s->nb_vcs; i++) {
+        vc = &s->vc[i];
+        if (gtk_check_menu_item_get_active
+            (GTK_CHECK_MENU_ITEM(vc->menu_item))) {
+            return vc;
+        }
+    }
+    return NULL;
+}
+
+static VirtualConsole *gd_vc_find_by_page(GtkDisplayState *s, gint page)
+{
+    VirtualConsole *vc;
+    gint i, p;
+
+    for (i = 0; i < s->nb_vcs; i++) {
+        vc = &s->vc[i];
+        p = gtk_notebook_page_num(GTK_NOTEBOOK(s->notebook), vc->tab_item);
+        if (p == page) {
+            return vc;
+        }
+    }
+    return NULL;
+}
+
+static VirtualConsole *gd_vc_find_current(GtkDisplayState *s)
+{
+    gint page;
+
+    page = gtk_notebook_get_current_page(GTK_NOTEBOOK(s->notebook));
+    return gd_vc_find_by_page(s, page);
+}
+
 static bool gd_is_grab_active(GtkDisplayState *s)
 {
     return gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->grab_item));
@@ -187,22 +277,17 @@ static bool gd_grab_on_hover(GtkDisplayState *s)
     return gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->grab_on_hover_item));
 }
 
-static bool gd_on_vga(GtkDisplayState *s)
-{
-    return gtk_notebook_get_current_page(GTK_NOTEBOOK(s->notebook)) == 0;
-}
-
-static void gd_update_cursor(GtkDisplayState *s, gboolean override)
+static void gd_update_cursor(VirtualConsole *vc)
 {
+    GtkDisplayState *s = vc->s;
     GdkWindow *window;
-    bool on_vga;
 
-    window = gtk_widget_get_window(GTK_WIDGET(s->drawing_area));
-
-    on_vga = gd_on_vga(s);
+    if (vc->type != GD_VC_GFX) {
+        return;
+    }
 
-    if ((override || on_vga) &&
-        (s->full_screen || qemu_input_is_absolute() || gd_is_grab_active(s))) {
+    window = gtk_widget_get_window(GTK_WIDGET(vc->gfx.drawing_area));
+    if (s->full_screen || qemu_input_is_absolute() || s->ptr_owner == vc) {
         gdk_window_set_cursor(window, s->null_cursor);
     } else {
         gdk_window_set_cursor(window, NULL);
@@ -212,11 +297,20 @@ static void gd_update_cursor(GtkDisplayState *s, gboolean override)
 static void gd_update_caption(GtkDisplayState *s)
 {
     const char *status = "";
+    gchar *prefix;
     gchar *title;
     const char *grab = "";
     bool is_paused = !runstate_is_running();
+    int i;
 
-    if (gd_is_grab_active(s)) {
+    if (qemu_name) {
+        prefix = g_strdup_printf("QEMU (%s)", qemu_name);
+    } else {
+        prefix = g_strdup_printf("QEMU");
+    }
+
+    if (s->ptr_owner != NULL &&
+        s->ptr_owner->window == NULL) {
         grab = _(" - Press Ctrl+Alt+G to release grab");
     }
 
@@ -228,60 +322,100 @@ static void gd_update_caption(GtkDisplayState *s)
                                    is_paused);
     s->external_pause_update = false;
 
-    if (qemu_name) {
-        title = g_strdup_printf("QEMU (%s)%s%s", qemu_name, status, grab);
-    } else {
-        title = g_strdup_printf("QEMU%s%s", status, grab);
-    }
-
+    title = g_strdup_printf("%s%s%s", prefix, status, grab);
     gtk_window_set_title(GTK_WINDOW(s->window), title);
-
     g_free(title);
+
+    for (i = 0; i < s->nb_vcs; i++) {
+        VirtualConsole *vc = &s->vc[i];
+
+        if (!vc->window) {
+            continue;
+        }
+        title = g_strdup_printf("%s: %s%s%s", prefix, vc->label,
+                                vc == s->kbd_owner ? " +kbd" : "",
+                                vc == s->ptr_owner ? " +ptr" : "");
+        gtk_window_set_title(GTK_WINDOW(vc->window), title);
+        g_free(title);
+    }
+
+    g_free(prefix);
 }
 
-static void gd_update_windowsize(GtkDisplayState *s)
+static void gd_update_geometry_hints(VirtualConsole *vc)
 {
-    if (!s->full_screen) {
-        GtkRequisition req;
-        double sx, sy;
+    GtkDisplayState *s = vc->s;
+    GdkWindowHints mask = 0;
+    GdkGeometry geo = {};
+    GtkWidget *geo_widget = NULL;
+    GtkWindow *geo_window;
 
+    if (vc->type == GD_VC_GFX) {
         if (s->free_scale) {
-            sx = s->scale_x;
-            sy = s->scale_y;
-
-            s->scale_y = 1.0;
-            s->scale_x = 1.0;
+            geo.min_width  = surface_width(vc->gfx.ds) * VC_SCALE_MIN;
+            geo.min_height = surface_height(vc->gfx.ds) * VC_SCALE_MIN;
+            mask |= GDK_HINT_MIN_SIZE;
         } else {
-            sx = 1.0;
-            sy = 1.0;
+            geo.min_width  = surface_width(vc->gfx.ds) * vc->gfx.scale_x;
+            geo.min_height = surface_height(vc->gfx.ds) * vc->gfx.scale_y;
+            mask |= GDK_HINT_MIN_SIZE;
         }
+        geo_widget = vc->gfx.drawing_area;
+        gtk_widget_set_size_request(geo_widget, geo.min_width, geo.min_height);
 
-        gtk_widget_set_size_request(s->drawing_area,
-                                    surface_width(s->ds) * s->scale_x,
-                                    surface_height(s->ds) * s->scale_y);
-#if GTK_CHECK_VERSION(3, 0, 0)
-        gtk_widget_get_preferred_size(s->vbox, NULL, &req);
-#else
-        gtk_widget_size_request(s->vbox, &req);
+#if defined(CONFIG_VTE)
+    } else if (vc->type == GD_VC_VTE) {
+        VteTerminal *term = VTE_TERMINAL(vc->vte.terminal);
+        GtkBorder *ib;
+
+        geo.width_inc  = vte_terminal_get_char_width(term);
+        geo.height_inc = vte_terminal_get_char_height(term);
+        mask |= GDK_HINT_RESIZE_INC;
+        geo.base_width  = geo.width_inc;
+        geo.base_height = geo.height_inc;
+        mask |= GDK_HINT_BASE_SIZE;
+        geo.min_width  = geo.width_inc * VC_TERM_X_MIN;
+        geo.min_height = geo.height_inc * VC_TERM_Y_MIN;
+        mask |= GDK_HINT_MIN_SIZE;
+        gtk_widget_style_get(vc->vte.terminal, "inner-border", &ib, NULL);
+        geo.base_width  += ib->left + ib->right;
+        geo.base_height += ib->top + ib->bottom;
+        geo.min_width   += ib->left + ib->right;
+        geo.min_height  += ib->top + ib->bottom;
+        geo_widget = vc->vte.terminal;
 #endif
+    }
+
+    geo_window = GTK_WINDOW(vc->window ? vc->window : s->window);
+    gtk_window_set_geometry_hints(geo_window, geo_widget, &geo, mask);
+}
+
+static void gd_update_windowsize(VirtualConsole *vc)
+{
+    GtkDisplayState *s = vc->s;
+
+    gd_update_geometry_hints(vc);
 
-        gtk_window_resize(GTK_WINDOW(s->window),
-                          req.width * sx, req.height * sy);
+    if (vc->type == GD_VC_GFX && !s->full_screen && !s->free_scale) {
+        gtk_window_resize(GTK_WINDOW(vc->window ? vc->window : s->window),
+                          VC_WINDOW_X_MIN, VC_WINDOW_Y_MIN);
     }
 }
 
-static void gd_update_full_redraw(GtkDisplayState *s)
+static void gd_update_full_redraw(VirtualConsole *vc)
 {
+    GtkWidget *area = vc->gfx.drawing_area;
     int ww, wh;
-    gdk_drawable_get_size(gtk_widget_get_window(s->drawing_area), &ww, &wh);
-    gtk_widget_queue_draw_area(s->drawing_area, 0, 0, ww, wh);
+    gdk_drawable_get_size(gtk_widget_get_window(area), &ww, &wh);
+    gtk_widget_queue_draw_area(area, 0, 0, ww, wh);
 }
 
 static void gtk_release_modifiers(GtkDisplayState *s)
 {
+    VirtualConsole *vc = gd_vc_find_current(s);
     int i, keycode;
 
-    if (!gd_on_vga(s)) {
+    if (vc->type != GD_VC_GFX) {
         return;
     }
     for (i = 0; i < ARRAY_SIZE(modifier_keycode); i++) {
@@ -289,7 +423,7 @@ static void gtk_release_modifiers(GtkDisplayState *s)
         if (!s->modifier_pressed[i]) {
             continue;
         }
-        qemu_input_event_send_key_number(s->dcl.con, keycode, false);
+        qemu_input_event_send_key_number(vc->gfx.dcl.con, keycode, false);
         s->modifier_pressed[i] = false;
     }
 }
@@ -299,29 +433,31 @@ static void gtk_release_modifiers(GtkDisplayState *s)
 static void gd_update(DisplayChangeListener *dcl,
                       int x, int y, int w, int h)
 {
-    GtkDisplayState *s = container_of(dcl, GtkDisplayState, dcl);
+    VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
     int x1, x2, y1, y2;
     int mx, my;
     int fbw, fbh;
     int ww, wh;
 
-    trace_gd_update(x, y, w, h);
+    trace_gd_update(vc->label, x, y, w, h);
 
-    if (s->convert) {
-        pixman_image_composite(PIXMAN_OP_SRC, s->ds->image, NULL, s->convert,
+    if (vc->gfx.convert) {
+        pixman_image_composite(PIXMAN_OP_SRC, vc->gfx.ds->image,
+                               NULL, vc->gfx.convert,
                                x, y, 0, 0, x, y, w, h);
     }
 
-    x1 = floor(x * s->scale_x);
-    y1 = floor(y * s->scale_y);
+    x1 = floor(x * vc->gfx.scale_x);
+    y1 = floor(y * vc->gfx.scale_y);
 
-    x2 = ceil(x * s->scale_x + w * s->scale_x);
-    y2 = ceil(y * s->scale_y + h * s->scale_y);
+    x2 = ceil(x * vc->gfx.scale_x + w * vc->gfx.scale_x);
+    y2 = ceil(y * vc->gfx.scale_y + h * vc->gfx.scale_y);
 
-    fbw = surface_width(s->ds) * s->scale_x;
-    fbh = surface_height(s->ds) * s->scale_y;
+    fbw = surface_width(vc->gfx.ds) * vc->gfx.scale_x;
+    fbh = surface_height(vc->gfx.ds) * vc->gfx.scale_y;
 
-    gdk_drawable_get_size(gtk_widget_get_window(s->drawing_area), &ww, &wh);
+    gdk_drawable_get_size(gtk_widget_get_window(vc->gfx.drawing_area),
+                          &ww, &wh);
 
     mx = my = 0;
     if (ww > fbw) {
@@ -331,7 +467,8 @@ static void gd_update(DisplayChangeListener *dcl,
         my = (wh - fbh) / 2;
     }
 
-    gtk_widget_queue_draw_area(s->drawing_area, mx + x1, my + y1, (x2 - x1), (y2 - y1));
+    gtk_widget_queue_draw_area(vc->gfx.drawing_area,
+                               mx + x1, my + y1, (x2 - x1), (y2 - y1));
 }
 
 static void gd_refresh(DisplayChangeListener *dcl)
@@ -343,7 +480,7 @@ static void gd_refresh(DisplayChangeListener *dcl)
 static void gd_mouse_set(DisplayChangeListener *dcl,
                          int x, int y, int visible)
 {
-    GtkDisplayState *s = container_of(dcl, GtkDisplayState, dcl);
+    VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
     GdkDisplay *dpy;
     GdkDeviceManager *mgr;
     gint x_root, y_root;
@@ -352,29 +489,29 @@ static void gd_mouse_set(DisplayChangeListener *dcl,
         return;
     }
 
-    dpy = gtk_widget_get_display(s->drawing_area);
+    dpy = gtk_widget_get_display(vc->gfx.drawing_area);
     mgr = gdk_display_get_device_manager(dpy);
-    gdk_window_get_root_coords(gtk_widget_get_window(s->drawing_area),
+    gdk_window_get_root_coords(gtk_widget_get_window(vc->gfx.drawing_area),
                                x, y, &x_root, &y_root);
     gdk_device_warp(gdk_device_manager_get_client_pointer(mgr),
-                    gtk_widget_get_screen(s->drawing_area),
+                    gtk_widget_get_screen(vc->gfx.drawing_area),
                     x_root, y_root);
 }
 #else
 static void gd_mouse_set(DisplayChangeListener *dcl,
                          int x, int y, int visible)
 {
-    GtkDisplayState *s = container_of(dcl, GtkDisplayState, dcl);
+    VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
     gint x_root, y_root;
 
     if (qemu_input_is_absolute()) {
         return;
     }
 
-    gdk_window_get_root_coords(gtk_widget_get_window(s->drawing_area),
+    gdk_window_get_root_coords(gtk_widget_get_window(vc->gfx.drawing_area),
                                x, y, &x_root, &y_root);
-    gdk_display_warp_pointer(gtk_widget_get_display(s->drawing_area),
-                             gtk_widget_get_screen(s->drawing_area),
+    gdk_display_warp_pointer(gtk_widget_get_display(vc->gfx.drawing_area),
+                             gtk_widget_get_screen(vc->gfx.drawing_area),
                              x_root, y_root);
 }
 #endif
@@ -382,7 +519,7 @@ static void gd_mouse_set(DisplayChangeListener *dcl,
 static void gd_cursor_define(DisplayChangeListener *dcl,
                              QEMUCursor *c)
 {
-    GtkDisplayState *s = container_of(dcl, GtkDisplayState, dcl);
+    VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
     GdkPixbuf *pixbuf;
     GdkCursor *cursor;
 
@@ -390,9 +527,10 @@ static void gd_cursor_define(DisplayChangeListener *dcl,
                                       GDK_COLORSPACE_RGB, true, 8,
                                       c->width, c->height, c->width * 4,
                                       NULL, NULL);
-    cursor = gdk_cursor_new_from_pixbuf(gtk_widget_get_display(s->drawing_area),
-                                        pixbuf, c->hot_x, c->hot_y);
-    gdk_window_set_cursor(gtk_widget_get_window(s->drawing_area), cursor);
+    cursor = gdk_cursor_new_from_pixbuf
+        (gtk_widget_get_display(vc->gfx.drawing_area),
+         pixbuf, c->hot_x, c->hot_y);
+    gdk_window_set_cursor(gtk_widget_get_window(vc->gfx.drawing_area), cursor);
     g_object_unref(pixbuf);
 #if !GTK_CHECK_VERSION(3, 0, 0)
     gdk_cursor_unref(cursor);
@@ -404,25 +542,25 @@ static void gd_cursor_define(DisplayChangeListener *dcl,
 static void gd_switch(DisplayChangeListener *dcl,
                       DisplaySurface *surface)
 {
-    GtkDisplayState *s = container_of(dcl, GtkDisplayState, dcl);
+    VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
     bool resized = true;
 
-    trace_gd_switch(surface_width(surface), surface_height(surface));
+    trace_gd_switch(vc->label, surface_width(surface), surface_height(surface));
 
-    if (s->surface) {
-        cairo_surface_destroy(s->surface);
+    if (vc->gfx.surface) {
+        cairo_surface_destroy(vc->gfx.surface);
     }
 
-    if (s->ds &&
-        surface_width(s->ds) == surface_width(surface) &&
-        surface_height(s->ds) == surface_height(surface)) {
+    if (vc->gfx.ds &&
+        surface_width(vc->gfx.ds) == surface_width(surface) &&
+        surface_height(vc->gfx.ds) == surface_height(surface)) {
         resized = false;
     }
-    s->ds = surface;
+    vc->gfx.ds = surface;
 
-    if (s->convert) {
-        pixman_image_unref(s->convert);
-        s->convert = NULL;
+    if (vc->gfx.convert) {
+        pixman_image_unref(vc->gfx.convert);
+        vc->gfx.convert = NULL;
     }
 
     if (surface->format == PIXMAN_x8r8g8b8) {
@@ -432,7 +570,7 @@ static void gd_switch(DisplayChangeListener *dcl,
          * No need to convert, use surface directly.  Should be the
          * common case as this is qemu_default_pixelformat(32) too.
          */
-        s->surface = cairo_image_surface_create_for_data
+        vc->gfx.surface = cairo_image_surface_create_for_data
             (surface_data(surface),
              CAIRO_FORMAT_RGB24,
              surface_width(surface),
@@ -440,26 +578,27 @@ static void gd_switch(DisplayChangeListener *dcl,
              surface_stride(surface));
     } else {
         /* Must convert surface, use pixman to do it. */
-        s->convert = pixman_image_create_bits(PIXMAN_x8r8g8b8,
-                                              surface_width(surface),
-                                              surface_height(surface),
-                                              NULL, 0);
-        s->surface = cairo_image_surface_create_for_data
-            ((void *)pixman_image_get_data(s->convert),
+        vc->gfx.convert = pixman_image_create_bits(PIXMAN_x8r8g8b8,
+                                                   surface_width(surface),
+                                                   surface_height(surface),
+                                                   NULL, 0);
+        vc->gfx.surface = cairo_image_surface_create_for_data
+            ((void *)pixman_image_get_data(vc->gfx.convert),
              CAIRO_FORMAT_RGB24,
-             pixman_image_get_width(s->convert),
-             pixman_image_get_height(s->convert),
-             pixman_image_get_stride(s->convert));
-        pixman_image_composite(PIXMAN_OP_SRC, s->ds->image, NULL, s->convert,
+             pixman_image_get_width(vc->gfx.convert),
+             pixman_image_get_height(vc->gfx.convert),
+             pixman_image_get_stride(vc->gfx.convert));
+        pixman_image_composite(PIXMAN_OP_SRC, vc->gfx.ds->image,
+                               NULL, vc->gfx.convert,
                                0, 0, 0, 0, 0, 0,
-                               pixman_image_get_width(s->convert),
-                               pixman_image_get_height(s->convert));
+                               pixman_image_get_width(vc->gfx.convert),
+                               pixman_image_get_height(vc->gfx.convert));
     }
 
     if (resized) {
-        gd_update_windowsize(s);
+        gd_update_windowsize(vc);
     } else {
-        gd_update_full_redraw(s);
+        gd_update_full_redraw(vc);
     }
 }
 
@@ -475,6 +614,7 @@ static void gd_change_runstate(void *opaque, int running, RunState state)
 static void gd_mouse_mode_change(Notifier *notify, void *data)
 {
     GtkDisplayState *s;
+    int i;
 
     s = container_of(notify, GtkDisplayState, mouse_mode_notifier);
     /* release the grab at switching to absolute mode */
@@ -482,7 +622,10 @@ static void gd_mouse_mode_change(Notifier *notify, void *data)
         gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item),
                                        FALSE);
     }
-    gd_update_cursor(s, FALSE);
+    for (i = 0; i < s->nb_vcs; i++) {
+        VirtualConsole *vc = &s->vc[i];
+        gd_update_cursor(vc);
+    }
 }
 
 /** GTK Events **/
@@ -491,9 +634,15 @@ static gboolean gd_window_close(GtkWidget *widget, GdkEvent *event,
                                 void *opaque)
 {
     GtkDisplayState *s = opaque;
+    int i;
 
     if (!no_quit) {
-        unregister_displaychangelistener(&s->dcl);
+        for (i = 0; i < s->nb_vcs; i++) {
+            if (s->vc[i].type != GD_VC_GFX) {
+                continue;
+            }
+            unregister_displaychangelistener(&s->vc[i].gfx.dcl);
+        }
         qmp_quit(NULL);
         return FALSE;
     }
@@ -503,7 +652,8 @@ static gboolean gd_window_close(GtkWidget *widget, GdkEvent *event,
 
 static gboolean gd_draw_event(GtkWidget *widget, cairo_t *cr, void *opaque)
 {
-    GtkDisplayState *s = opaque;
+    VirtualConsole *vc = opaque;
+    GtkDisplayState *s = vc->s;
     int mx, my;
     int ww, wh;
     int fbw, fbh;
@@ -512,25 +662,25 @@ static gboolean gd_draw_event(GtkWidget *widget, cairo_t *cr, void *opaque)
         return FALSE;
     }
 
-    fbw = surface_width(s->ds);
-    fbh = surface_height(s->ds);
+    fbw = surface_width(vc->gfx.ds);
+    fbh = surface_height(vc->gfx.ds);
 
     gdk_drawable_get_size(gtk_widget_get_window(widget), &ww, &wh);
 
     if (s->full_screen) {
-        s->scale_x = (double)ww / fbw;
-        s->scale_y = (double)wh / fbh;
+        vc->gfx.scale_x = (double)ww / fbw;
+        vc->gfx.scale_y = (double)wh / fbh;
     } else if (s->free_scale) {
         double sx, sy;
 
         sx = (double)ww / fbw;
         sy = (double)wh / fbh;
 
-        s->scale_x = s->scale_y = MIN(sx, sy);
+        vc->gfx.scale_x = vc->gfx.scale_y = MIN(sx, sy);
     }
 
-    fbw *= s->scale_x;
-    fbh *= s->scale_y;
+    fbw *= vc->gfx.scale_x;
+    fbh *= vc->gfx.scale_y;
 
     mx = my = 0;
     if (ww > fbw) {
@@ -551,8 +701,9 @@ static gboolean gd_draw_event(GtkWidget *widget, cairo_t *cr, void *opaque)
                     -1 * fbw, fbh);
     cairo_fill(cr);
 
-    cairo_scale(cr, s->scale_x, s->scale_y);
-    cairo_set_source_surface(cr, s->surface, mx / s->scale_x, my / s->scale_y);
+    cairo_scale(cr, vc->gfx.scale_x, vc->gfx.scale_y);
+    cairo_set_source_surface(cr, vc->gfx.surface,
+                             mx / vc->gfx.scale_x, my / vc->gfx.scale_y);
     cairo_paint(cr);
 
     return TRUE;
@@ -584,16 +735,18 @@ static gboolean gd_expose_event(GtkWidget *widget, GdkEventExpose *expose,
 static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion,
                                 void *opaque)
 {
-    GtkDisplayState *s = opaque;
+    VirtualConsole *vc = opaque;
+    GtkDisplayState *s = vc->s;
     int x, y;
     int mx, my;
     int fbh, fbw;
     int ww, wh;
 
-    fbw = surface_width(s->ds) * s->scale_x;
-    fbh = surface_height(s->ds) * s->scale_y;
+    fbw = surface_width(vc->gfx.ds) * vc->gfx.scale_x;
+    fbh = surface_height(vc->gfx.ds) * vc->gfx.scale_y;
 
-    gdk_drawable_get_size(gtk_widget_get_window(s->drawing_area), &ww, &wh);
+    gdk_drawable_get_size(gtk_widget_get_window(vc->gfx.drawing_area),
+                          &ww, &wh);
 
     mx = my = 0;
     if (ww > fbw) {
@@ -603,31 +756,31 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion,
         my = (wh - fbh) / 2;
     }
 
-    x = (motion->x - mx) / s->scale_x;
-    y = (motion->y - my) / s->scale_y;
+    x = (motion->x - mx) / vc->gfx.scale_x;
+    y = (motion->y - my) / vc->gfx.scale_y;
 
     if (qemu_input_is_absolute()) {
         if (x < 0 || y < 0 ||
-            x >= surface_width(s->ds) ||
-            y >= surface_height(s->ds)) {
+            x >= surface_width(vc->gfx.ds) ||
+            y >= surface_height(vc->gfx.ds)) {
             return TRUE;
         }
-        qemu_input_queue_abs(s->dcl.con, INPUT_AXIS_X, x,
-                             surface_width(s->ds));
-        qemu_input_queue_abs(s->dcl.con, INPUT_AXIS_Y, y,
-                             surface_height(s->ds));
+        qemu_input_queue_abs(vc->gfx.dcl.con, INPUT_AXIS_X, x,
+                             surface_width(vc->gfx.ds));
+        qemu_input_queue_abs(vc->gfx.dcl.con, INPUT_AXIS_Y, y,
+                             surface_height(vc->gfx.ds));
         qemu_input_event_sync();
-    } else if (s->last_set && gd_is_grab_active(s)) {
-        qemu_input_queue_rel(s->dcl.con, INPUT_AXIS_X, x - s->last_x);
-        qemu_input_queue_rel(s->dcl.con, INPUT_AXIS_Y, y - s->last_y);
+    } else if (s->last_set && s->ptr_owner == vc) {
+        qemu_input_queue_rel(vc->gfx.dcl.con, INPUT_AXIS_X, x - s->last_x);
+        qemu_input_queue_rel(vc->gfx.dcl.con, INPUT_AXIS_Y, y - s->last_y);
         qemu_input_event_sync();
     }
     s->last_x = x;
     s->last_y = y;
     s->last_set = TRUE;
 
-    if (!qemu_input_is_absolute() && gd_is_grab_active(s)) {
-        GdkScreen *screen = gtk_widget_get_screen(s->drawing_area);
+    if (!qemu_input_is_absolute() && s->ptr_owner == vc) {
+        GdkScreen *screen = gtk_widget_get_screen(vc->gfx.drawing_area);
         int x = (int)motion->x_root;
         int y = (int)motion->y_root;
 
@@ -669,14 +822,21 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion,
 static gboolean gd_button_event(GtkWidget *widget, GdkEventButton *button,
                                 void *opaque)
 {
-    GtkDisplayState *s = opaque;
+    VirtualConsole *vc = opaque;
+    GtkDisplayState *s = vc->s;
     InputButton btn;
 
     /* implicitly grab the input at the first click in the relative mode */
     if (button->button == 1 && button->type == GDK_BUTTON_PRESS &&
-        !qemu_input_is_absolute() && !gd_is_grab_active(s)) {
-        gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item),
-                                       TRUE);
+        !qemu_input_is_absolute() && s->ptr_owner != vc) {
+        gd_ungrab_pointer(s);
+        if (!vc->window) {
+            gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item),
+                                           TRUE);
+        } else {
+            gd_grab_pointer(vc);
+            gd_update_caption(s);
+        }
         return TRUE;
     }
 
@@ -690,7 +850,8 @@ static gboolean gd_button_event(GtkWidget *widget, GdkEventButton *button,
         return TRUE;
     }
 
-    qemu_input_queue_btn(s->dcl.con, btn, button->type == GDK_BUTTON_PRESS);
+    qemu_input_queue_btn(vc->gfx.dcl.con, btn,
+                         button->type == GDK_BUTTON_PRESS);
     qemu_input_event_sync();
     return TRUE;
 }
@@ -698,7 +859,7 @@ static gboolean gd_button_event(GtkWidget *widget, GdkEventButton *button,
 static gboolean gd_scroll_event(GtkWidget *widget, GdkEventScroll *scroll,
                                 void *opaque)
 {
-    GtkDisplayState *s = opaque;
+    VirtualConsole *vc = opaque;
     InputButton btn;
 
     if (scroll->direction == GDK_SCROLL_UP) {
@@ -709,16 +870,17 @@ static gboolean gd_scroll_event(GtkWidget *widget, GdkEventScroll *scroll,
         return TRUE;
     }
 
-    qemu_input_queue_btn(s->dcl.con, btn, true);
+    qemu_input_queue_btn(vc->gfx.dcl.con, btn, true);
     qemu_input_event_sync();
-    qemu_input_queue_btn(s->dcl.con, btn, false);
+    qemu_input_queue_btn(vc->gfx.dcl.con, btn, false);
     qemu_input_event_sync();
     return TRUE;
 }
 
 static gboolean gd_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque)
 {
-    GtkDisplayState *s = opaque;
+    VirtualConsole *vc = opaque;
+    GtkDisplayState *s = vc->s;
     int gdk_keycode = key->hardware_keycode;
     int i;
 
@@ -737,7 +899,11 @@ static gboolean gd_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque)
     } else if (gdk_keycode < 97) {
         qemu_keycode = gdk_keycode - 8;
     } else if (gdk_keycode < 158) {
-        qemu_keycode = translate_evdev_keycode(gdk_keycode - 97);
+        if (s->has_evdev) {
+            qemu_keycode = translate_evdev_keycode(gdk_keycode - 97);
+        } else {
+            qemu_keycode = translate_xfree86_keycode(gdk_keycode - 97);
+        }
     } else if (gdk_keycode == 208) { /* Hiragana_Katakana */
         qemu_keycode = 0x70;
     } else if (gdk_keycode == 211) { /* backslash */
@@ -747,7 +913,7 @@ static gboolean gd_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque)
     }
 #endif
 
-    trace_gd_key_event(gdk_keycode, qemu_keycode,
+    trace_gd_key_event(vc->label, gdk_keycode, qemu_keycode,
                        (key->type == GDK_KEY_PRESS) ? "down" : "up");
 
     for (i = 0; i < ARRAY_SIZE(modifier_keycode); i++) {
@@ -756,7 +922,7 @@ static gboolean gd_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque)
         }
     }
 
-    qemu_input_event_send_key_number(s->dcl.con, qemu_keycode,
+    qemu_input_event_send_key_number(vc->gfx.dcl.con, qemu_keycode,
                                      key->type == GDK_KEY_PRESS);
 
     return TRUE;
@@ -804,19 +970,14 @@ static void gd_menu_quit(GtkMenuItem *item, void *opaque)
 static void gd_menu_switch_vc(GtkMenuItem *item, void *opaque)
 {
     GtkDisplayState *s = opaque;
+    VirtualConsole *vc = gd_vc_find_by_menu(s);
+    gint page;
 
-    if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->vga_item))) {
-        gtk_notebook_set_current_page(GTK_NOTEBOOK(s->notebook), 0);
-    } else {
-        int i;
-
-        gtk_release_modifiers(s);
-        for (i = 0; i < s->nb_vcs; i++) {
-            if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->vc[i].menu_item))) {
-                gtk_notebook_set_current_page(GTK_NOTEBOOK(s->notebook), i + 1);
-                break;
-            }
-        }
+    gtk_release_modifiers(s);
+    if (vc) {
+        page = gtk_notebook_page_num(GTK_NOTEBOOK(s->notebook),
+                                     vc->tab_item);
+        gtk_notebook_set_current_page(GTK_NOTEBOOK(s->notebook), page);
     }
 }
 
@@ -831,94 +992,159 @@ static void gd_menu_show_tabs(GtkMenuItem *item, void *opaque)
     }
 }
 
+static gboolean gd_tab_window_close(GtkWidget *widget, GdkEvent *event,
+                                    void *opaque)
+{
+    VirtualConsole *vc = opaque;
+    GtkDisplayState *s = vc->s;
+
+    gtk_widget_set_sensitive(vc->menu_item, true);
+    gtk_widget_reparent(vc->tab_item, s->notebook);
+    gtk_notebook_set_tab_label_text(GTK_NOTEBOOK(s->notebook),
+                                    vc->tab_item, vc->label);
+    gtk_widget_destroy(vc->window);
+    vc->window = NULL;
+    return TRUE;
+}
+
+static gboolean gd_win_grab(void *opaque)
+{
+    VirtualConsole *vc = opaque;
+
+    fprintf(stderr, "%s: %s\n", __func__, vc->label);
+    if (vc->s->ptr_owner) {
+        gd_ungrab_pointer(vc->s);
+    } else {
+        gd_grab_pointer(vc);
+    }
+    gd_update_caption(vc->s);
+    return TRUE;
+}
+
+static void gd_menu_untabify(GtkMenuItem *item, void *opaque)
+{
+    GtkDisplayState *s = opaque;
+    VirtualConsole *vc = gd_vc_find_current(s);
+
+    if (vc->type == GD_VC_GFX) {
+        gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item),
+                                       FALSE);
+    }
+    if (!vc->window) {
+        gtk_widget_set_sensitive(vc->menu_item, false);
+        vc->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+        gtk_widget_reparent(vc->tab_item, vc->window);
+
+        g_signal_connect(vc->window, "delete-event",
+                         G_CALLBACK(gd_tab_window_close), vc);
+        gtk_widget_show_all(vc->window);
+
+        GtkAccelGroup *ag = gtk_accel_group_new();
+        gtk_window_add_accel_group(GTK_WINDOW(vc->window), ag);
+
+        GClosure *cb = g_cclosure_new_swap(G_CALLBACK(gd_win_grab), vc, NULL);
+        gtk_accel_group_connect(ag, GDK_KEY_g, HOTKEY_MODIFIERS, 0, cb);
+
+        gd_update_geometry_hints(vc);
+        gd_update_caption(s);
+    }
+}
+
 static void gd_menu_full_screen(GtkMenuItem *item, void *opaque)
 {
     GtkDisplayState *s = opaque;
+    VirtualConsole *vc = gd_vc_find_current(s);
 
     if (!s->full_screen) {
         gtk_notebook_set_show_tabs(GTK_NOTEBOOK(s->notebook), FALSE);
         gtk_widget_set_size_request(s->menu_bar, 0, 0);
-        gtk_widget_set_size_request(s->drawing_area, -1, -1);
-        gtk_window_fullscreen(GTK_WINDOW(s->window));
-        if (gd_on_vga(s)) {
-            gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item), TRUE);
+        if (vc->type == GD_VC_GFX) {
+            gtk_widget_set_size_request(vc->gfx.drawing_area, -1, -1);
+            gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item),
+                                           TRUE);
         }
+        gtk_window_fullscreen(GTK_WINDOW(s->window));
         s->full_screen = TRUE;
     } else {
         gtk_window_unfullscreen(GTK_WINDOW(s->window));
         gd_menu_show_tabs(GTK_MENU_ITEM(s->show_tabs_item), s);
         gtk_widget_set_size_request(s->menu_bar, -1, -1);
-        gtk_widget_set_size_request(s->drawing_area,
-                                    surface_width(s->ds),
-                                    surface_height(s->ds));
-        gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item), FALSE);
         s->full_screen = FALSE;
-        s->scale_x = 1.0;
-        s->scale_y = 1.0;
+        if (vc->type == GD_VC_GFX) {
+            vc->gfx.scale_x = 1.0;
+            vc->gfx.scale_y = 1.0;
+            gd_update_windowsize(vc);
+            gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item),
+                                           FALSE);
+        }
     }
 
-    gd_update_cursor(s, FALSE);
+    gd_update_cursor(vc);
 }
 
 static void gd_menu_zoom_in(GtkMenuItem *item, void *opaque)
 {
     GtkDisplayState *s = opaque;
+    VirtualConsole *vc = gd_vc_find_current(s);
 
     gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->zoom_fit_item),
                                    FALSE);
 
-    s->scale_x += .25;
-    s->scale_y += .25;
+    vc->gfx.scale_x += VC_SCALE_STEP;
+    vc->gfx.scale_y += VC_SCALE_STEP;
 
-    gd_update_windowsize(s);
+    gd_update_windowsize(vc);
 }
 
 static void gd_menu_zoom_out(GtkMenuItem *item, void *opaque)
 {
     GtkDisplayState *s = opaque;
+    VirtualConsole *vc = gd_vc_find_current(s);
 
     gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->zoom_fit_item),
                                    FALSE);
 
-    s->scale_x -= .25;
-    s->scale_y -= .25;
+    vc->gfx.scale_x -= VC_SCALE_STEP;
+    vc->gfx.scale_y -= VC_SCALE_STEP;
 
-    s->scale_x = MAX(s->scale_x, .25);
-    s->scale_y = MAX(s->scale_y, .25);
+    vc->gfx.scale_x = MAX(vc->gfx.scale_x, VC_SCALE_MIN);
+    vc->gfx.scale_y = MAX(vc->gfx.scale_y, VC_SCALE_MIN);
 
-    gd_update_windowsize(s);
+    gd_update_windowsize(vc);
 }
 
 static void gd_menu_zoom_fixed(GtkMenuItem *item, void *opaque)
 {
     GtkDisplayState *s = opaque;
+    VirtualConsole *vc = gd_vc_find_current(s);
 
-    s->scale_x = 1.0;
-    s->scale_y = 1.0;
+    vc->gfx.scale_x = 1.0;
+    vc->gfx.scale_y = 1.0;
 
-    gd_update_windowsize(s);
+    gd_update_windowsize(vc);
 }
 
 static void gd_menu_zoom_fit(GtkMenuItem *item, void *opaque)
 {
     GtkDisplayState *s = opaque;
+    VirtualConsole *vc = gd_vc_find_current(s);
 
     if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->zoom_fit_item))) {
         s->free_scale = TRUE;
     } else {
         s->free_scale = FALSE;
-        s->scale_x = 1.0;
-        s->scale_y = 1.0;
-        gd_update_windowsize(s);
+        vc->gfx.scale_x = 1.0;
+        vc->gfx.scale_y = 1.0;
     }
 
-    gd_update_full_redraw(s);
+    gd_update_windowsize(vc);
+    gd_update_full_redraw(vc);
 }
 
-static void gd_grab_keyboard(GtkDisplayState *s)
+static void gd_grab_keyboard(VirtualConsole *vc)
 {
 #if GTK_CHECK_VERSION(3, 0, 0)
-    GdkDisplay *display = gtk_widget_get_display(s->drawing_area);
+    GdkDisplay *display = gtk_widget_get_display(vc->gfx.drawing_area);
     GdkDeviceManager *mgr = gdk_display_get_device_manager(display);
     GList *devices = gdk_device_manager_list_devices(mgr,
                                                      GDK_DEVICE_TYPE_MASTER);
@@ -927,7 +1153,7 @@ static void gd_grab_keyboard(GtkDisplayState *s)
         GdkDevice *dev = tmp->data;
         if (gdk_device_get_source(dev) == GDK_SOURCE_KEYBOARD) {
             gdk_device_grab(dev,
-                            gtk_widget_get_window(s->drawing_area),
+                            gtk_widget_get_window(vc->gfx.drawing_area),
                             GDK_OWNERSHIP_NONE,
                             FALSE,
                             GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK,
@@ -938,16 +1164,25 @@ static void gd_grab_keyboard(GtkDisplayState *s)
     }
     g_list_free(devices);
 #else
-    gdk_keyboard_grab(gtk_widget_get_window(s->drawing_area),
+    gdk_keyboard_grab(gtk_widget_get_window(vc->gfx.drawing_area),
                       FALSE,
                       GDK_CURRENT_TIME);
 #endif
+    vc->s->kbd_owner = vc;
+    trace_gd_grab(vc->label, "kbd", true);
 }
 
 static void gd_ungrab_keyboard(GtkDisplayState *s)
 {
+    VirtualConsole *vc = s->kbd_owner;
+
+    if (vc == NULL) {
+        return;
+    }
+    s->kbd_owner = NULL;
+
 #if GTK_CHECK_VERSION(3, 0, 0)
-    GdkDisplay *display = gtk_widget_get_display(s->drawing_area);
+    GdkDisplay *display = gtk_widget_get_display(vc->gfx.drawing_area);
     GdkDeviceManager *mgr = gdk_display_get_device_manager(display);
     GList *devices = gdk_device_manager_list_devices(mgr,
                                                      GDK_DEVICE_TYPE_MASTER);
@@ -964,11 +1199,12 @@ static void gd_ungrab_keyboard(GtkDisplayState *s)
 #else
     gdk_keyboard_ungrab(GDK_CURRENT_TIME);
 #endif
+    trace_gd_grab(vc->label, "kbd", false);
 }
 
-static void gd_grab_pointer(GtkDisplayState *s)
+static void gd_grab_pointer(VirtualConsole *vc)
 {
-    GdkDisplay *display = gtk_widget_get_display(s->drawing_area);
+    GdkDisplay *display = gtk_widget_get_display(vc->gfx.drawing_area);
 #if GTK_CHECK_VERSION(3, 0, 0)
     GdkDeviceManager *mgr = gdk_display_get_device_manager(display);
     GList *devices = gdk_device_manager_list_devices(mgr,
@@ -978,7 +1214,7 @@ static void gd_grab_pointer(GtkDisplayState *s)
         GdkDevice *dev = tmp->data;
         if (gdk_device_get_source(dev) == GDK_SOURCE_MOUSE) {
             gdk_device_grab(dev,
-                            gtk_widget_get_window(s->drawing_area),
+                            gtk_widget_get_window(vc->gfx.drawing_area),
                             GDK_OWNERSHIP_NONE,
                             FALSE, /* All events to come to our
                                       window directly */
@@ -987,16 +1223,16 @@ static void gd_grab_pointer(GtkDisplayState *s)
                             GDK_BUTTON_RELEASE_MASK |
                             GDK_BUTTON_MOTION_MASK |
                             GDK_SCROLL_MASK,
-                            s->null_cursor,
+                            vc->s->null_cursor,
                             GDK_CURRENT_TIME);
         }
         tmp = tmp->next;
     }
     g_list_free(devices);
     gdk_device_get_position(gdk_device_manager_get_client_pointer(mgr),
-                            NULL, &s->grab_x_root, &s->grab_y_root);
+                            NULL, &vc->s->grab_x_root, &vc->s->grab_y_root);
 #else
-    gdk_pointer_grab(gtk_widget_get_window(s->drawing_area),
+    gdk_pointer_grab(gtk_widget_get_window(vc->gfx.drawing_area),
                      FALSE, /* All events to come to our window directly */
                      GDK_POINTER_MOTION_MASK |
                      GDK_BUTTON_PRESS_MASK |
@@ -1004,16 +1240,25 @@ static void gd_grab_pointer(GtkDisplayState *s)
                      GDK_BUTTON_MOTION_MASK |
                      GDK_SCROLL_MASK,
                      NULL, /* Allow cursor to move over entire desktop */
-                     s->null_cursor,
+                     vc->s->null_cursor,
                      GDK_CURRENT_TIME);
     gdk_display_get_pointer(display, NULL,
-                            &s->grab_x_root, &s->grab_y_root, NULL);
+                            &vc->s->grab_x_root, &vc->s->grab_y_root, NULL);
 #endif
+    vc->s->ptr_owner = vc;
+    trace_gd_grab(vc->label, "ptr", true);
 }
 
 static void gd_ungrab_pointer(GtkDisplayState *s)
 {
-    GdkDisplay *display = gtk_widget_get_display(s->drawing_area);
+    VirtualConsole *vc = s->ptr_owner;
+
+    if (vc == NULL) {
+        return;
+    }
+    s->ptr_owner = NULL;
+
+    GdkDisplay *display = gtk_widget_get_display(vc->gfx.drawing_area);
 #if GTK_CHECK_VERSION(3, 0, 0)
     GdkDeviceManager *mgr = gdk_display_get_device_manager(display);
     GList *devices = gdk_device_manager_list_devices(mgr,
@@ -1029,51 +1274,65 @@ static void gd_ungrab_pointer(GtkDisplayState *s)
     }
     g_list_free(devices);
     gdk_device_warp(gdk_device_manager_get_client_pointer(mgr),
-                    gtk_widget_get_screen(s->drawing_area),
-                    s->grab_x_root, s->grab_y_root);
+                    gtk_widget_get_screen(vc->gfx.drawing_area),
+                    vc->s->grab_x_root, vc->s->grab_y_root);
 #else
     gdk_pointer_ungrab(GDK_CURRENT_TIME);
     gdk_display_warp_pointer(display,
-                             gtk_widget_get_screen(s->drawing_area),
-                             s->grab_x_root, s->grab_y_root);
+                             gtk_widget_get_screen(vc->gfx.drawing_area),
+                             vc->s->grab_x_root, vc->s->grab_y_root);
 #endif
+    trace_gd_grab(vc->label, "ptr", false);
 }
 
 static void gd_menu_grab_input(GtkMenuItem *item, void *opaque)
 {
     GtkDisplayState *s = opaque;
+    VirtualConsole *vc = gd_vc_find_current(s);
 
     if (gd_is_grab_active(s)) {
-        gd_grab_keyboard(s);
-        gd_grab_pointer(s);
+        if (!gd_grab_on_hover(s)) {
+            gd_grab_keyboard(vc);
+        }
+        gd_grab_pointer(vc);
     } else {
         gd_ungrab_keyboard(s);
         gd_ungrab_pointer(s);
     }
 
     gd_update_caption(s);
-    gd_update_cursor(s, FALSE);
+    gd_update_cursor(vc);
 }
 
 static void gd_change_page(GtkNotebook *nb, gpointer arg1, guint arg2,
                            gpointer data)
 {
     GtkDisplayState *s = data;
-    guint last_page;
+    VirtualConsole *vc;
     gboolean on_vga;
 
     if (!gtk_widget_get_realized(s->notebook)) {
         return;
     }
 
-    last_page = gtk_notebook_get_current_page(nb);
-
-    if (last_page) {
-        gtk_widget_set_size_request(s->vc[last_page - 1].terminal, -1, -1);
+#ifdef VTE_RESIZE_HACK
+    vc = gd_vc_find_current(s);
+    if (vc && vc->type == GD_VC_VTE) {
+        gtk_widget_hide(vc->vte.terminal);
     }
-
-    on_vga = arg2 == 0;
-
+#endif
+    vc = gd_vc_find_by_page(s, arg2);
+    if (!vc) {
+        return;
+    }
+#ifdef VTE_RESIZE_HACK
+    if (vc->type == GD_VC_VTE) {
+        gtk_widget_show(vc->vte.terminal);
+    }
+#endif
+    gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(vc->menu_item),
+                                   TRUE);
+    on_vga = (vc->type == GD_VC_GFX);
     if (!on_vga) {
         gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item),
                                        FALSE);
@@ -1081,71 +1340,88 @@ static void gd_change_page(GtkNotebook *nb, gpointer arg1, guint arg2,
         gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item),
                                        TRUE);
     }
-
-    if (arg2 == 0) {
-        gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->vga_item), TRUE);
-    } else {
-#if defined(CONFIG_VTE)
-        VirtualConsole *vc = &s->vc[arg2 - 1];
-        VteTerminal *term = VTE_TERMINAL(vc->terminal);
-        int width, height;
-
-        width = 80 * vte_terminal_get_char_width(term);
-        height = 25 * vte_terminal_get_char_height(term);
-
-        gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(vc->menu_item), TRUE);
-        gtk_widget_set_size_request(vc->terminal, width, height);
-#else
-        g_assert_not_reached();
-#endif
-    }
-
     gtk_widget_set_sensitive(s->grab_item, on_vga);
 
-    gd_update_cursor(s, TRUE);
+    gd_update_windowsize(vc);
+    gd_update_cursor(vc);
 }
 
-static gboolean gd_enter_event(GtkWidget *widget, GdkEventCrossing *crossing, gpointer data)
+static gboolean gd_enter_event(GtkWidget *widget, GdkEventCrossing *crossing,
+                               gpointer opaque)
 {
-    GtkDisplayState *s = data;
+    VirtualConsole *vc = opaque;
+    GtkDisplayState *s = vc->s;
 
-    if (!gd_is_grab_active(s) && gd_grab_on_hover(s)) {
-        gd_grab_keyboard(s);
+    if (gd_grab_on_hover(s)) {
+        gd_ungrab_keyboard(s);
+        gd_grab_keyboard(vc);
+        gd_update_caption(s);
     }
-
     return TRUE;
 }
 
-static gboolean gd_leave_event(GtkWidget *widget, GdkEventCrossing *crossing, gpointer data)
+static gboolean gd_leave_event(GtkWidget *widget, GdkEventCrossing *crossing,
+                               gpointer opaque)
 {
-    GtkDisplayState *s = data;
+    VirtualConsole *vc = opaque;
+    GtkDisplayState *s = vc->s;
 
-    if (!gd_is_grab_active(s) && gd_grab_on_hover(s)) {
+    if (gd_grab_on_hover(s)) {
         gd_ungrab_keyboard(s);
+        gd_update_caption(s);
     }
-
     return TRUE;
 }
 
 static gboolean gd_focus_out_event(GtkWidget *widget,
-                                   GdkEventCrossing *crossing, gpointer data)
+                                   GdkEventCrossing *crossing, gpointer opaque)
 {
-    GtkDisplayState *s = data;
+    VirtualConsole *vc = opaque;
+    GtkDisplayState *s = vc->s;
 
     gtk_release_modifiers(s);
-
     return TRUE;
 }
 
 /** Virtual Console Callbacks **/
 
-static int gd_vc_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+static GSList *gd_vc_menu_init(GtkDisplayState *s, VirtualConsole *vc,
+                               int idx, GSList *group, GtkWidget *view_menu)
 {
+    char path[32];
+
+    snprintf(path, sizeof(path), "<QEMU>/View/VC%d", idx);
+
+    vc->menu_item = gtk_radio_menu_item_new_with_mnemonic(group, vc->label);
+    group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(vc->menu_item));
+    gtk_menu_item_set_accel_path(GTK_MENU_ITEM(vc->menu_item), path);
+    gtk_accel_map_add_entry(path, GDK_KEY_1 + idx, HOTKEY_MODIFIERS);
+
+    g_signal_connect(vc->menu_item, "activate",
+                     G_CALLBACK(gd_menu_switch_vc), s);
+    gtk_menu_shell_append(GTK_MENU_SHELL(view_menu), vc->menu_item);
+
+    return group;
+}
+
 #if defined(CONFIG_VTE)
+static void gd_vc_adjustment_changed(GtkAdjustment *adjustment, void *opaque)
+{
+    VirtualConsole *vc = opaque;
+
+    if (gtk_adjustment_get_upper(adjustment) >
+        gtk_adjustment_get_page_size(adjustment)) {
+        gtk_widget_show(vc->vte.scrollbar);
+    } else {
+        gtk_widget_hide(vc->vte.scrollbar);
+    }
+}
+
+static int gd_vc_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+{
     VirtualConsole *vc = chr->opaque;
 
-    vte_terminal_feed(VTE_TERMINAL(vc->terminal), (const char *)buf, len);
-#endif
+    vte_terminal_feed(VTE_TERMINAL(vc->vte.terminal), (const char *)buf, len);
     return len;
 }
 
@@ -1166,115 +1442,132 @@ static CharDriverState *gd_vc_handler(ChardevVC *unused)
     return chr;
 }
 
-void early_gtk_display_init(void)
-{
-    register_vc_handler(gd_vc_handler);
-}
-
-#if defined(CONFIG_VTE)
 static gboolean gd_vc_in(VteTerminal *terminal, gchar *text, guint size,
                          gpointer user_data)
 {
     VirtualConsole *vc = user_data;
 
-    qemu_chr_be_write(vc->chr, (uint8_t  *)text, (unsigned int)size);
+    qemu_chr_be_write(vc->vte.chr, (uint8_t  *)text, (unsigned int)size);
     return TRUE;
 }
-#endif
 
-static GSList *gd_vc_init(GtkDisplayState *s, VirtualConsole *vc, int index, GSList *group,
-                          GtkWidget *view_menu)
+static GSList *gd_vc_vte_init(GtkDisplayState *s, VirtualConsole *vc,
+                              CharDriverState *chr, int idx,
+                              GSList *group, GtkWidget *view_menu)
 {
-#if defined(CONFIG_VTE)
-    const char *label;
     char buffer[32];
-    char path[32];
-    GtkWidget *scrolled_window;
+    GtkWidget *box;
+    GtkWidget *scrollbar;
     GtkAdjustment *vadjustment;
 
-    snprintf(buffer, sizeof(buffer), "vc%d", index);
-    snprintf(path, sizeof(path), "<QEMU>/View/VC%d", index);
-
-    vc->chr = vcs[index];
-
-    if (vc->chr->label) {
-        label = vc->chr->label;
-    } else {
-        label = buffer;
-    }
+    vc->s = s;
+    vc->vte.chr = chr;
 
-    vc->menu_item = gtk_radio_menu_item_new_with_mnemonic(group, label);
-    group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(vc->menu_item));
-    gtk_menu_item_set_accel_path(GTK_MENU_ITEM(vc->menu_item), path);
-    gtk_accel_map_add_entry(path, GDK_KEY_2 + index, HOTKEY_MODIFIERS);
+    snprintf(buffer, sizeof(buffer), "vc%d", idx);
+    vc->label = g_strdup_printf("%s", vc->vte.chr->label
+                                ? vc->vte.chr->label : buffer);
+    group = gd_vc_menu_init(s, vc, idx, group, view_menu);
 
-    vc->terminal = vte_terminal_new();
-    g_signal_connect(vc->terminal, "commit", G_CALLBACK(gd_vc_in), vc);
+    vc->vte.terminal = vte_terminal_new();
+    g_signal_connect(vc->vte.terminal, "commit", G_CALLBACK(gd_vc_in), vc);
 
-    vte_terminal_set_scrollback_lines(VTE_TERMINAL(vc->terminal), -1);
+    vte_terminal_set_scrollback_lines(VTE_TERMINAL(vc->vte.terminal), -1);
+    vte_terminal_set_size(VTE_TERMINAL(vc->vte.terminal),
+                          VC_TERM_X_MIN, VC_TERM_Y_MIN);
 
 #if VTE_CHECK_VERSION(0, 28, 0) && GTK_CHECK_VERSION(3, 0, 0)
-    vadjustment = gtk_scrollable_get_vadjustment(GTK_SCROLLABLE(vc->terminal));
+    vadjustment = gtk_scrollable_get_vadjustment
+        (GTK_SCROLLABLE(vc->vte.terminal));
 #else
-    vadjustment = vte_terminal_get_adjustment(VTE_TERMINAL(vc->terminal));
+    vadjustment = vte_terminal_get_adjustment(VTE_TERMINAL(vc->vte.terminal));
 #endif
 
-    scrolled_window = gtk_scrolled_window_new(NULL, vadjustment);
-    gtk_container_add(GTK_CONTAINER(scrolled_window), vc->terminal);
-
-    vte_terminal_set_size(VTE_TERMINAL(vc->terminal), 80, 25);
+#if GTK_CHECK_VERSION(3, 0, 0)
+    box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 2);
+    scrollbar = gtk_scrollbar_new(GTK_ORIENTATION_VERTICAL, vadjustment);
+#else
+    box = gtk_hbox_new(false, 2);
+    scrollbar = gtk_vscrollbar_new(vadjustment);
+#endif
 
-    vc->chr->opaque = vc;
-    vc->scrolled_window = scrolled_window;
+    gtk_box_pack_start(GTK_BOX(box), vc->vte.terminal, TRUE, TRUE, 0);
+    gtk_box_pack_start(GTK_BOX(box), scrollbar, FALSE, FALSE, 0);
 
-    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(vc->scrolled_window),
-                                   GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+    vc->vte.chr->opaque = vc;
+    vc->vte.box = box;
+    vc->vte.scrollbar = scrollbar;
 
-    gtk_notebook_append_page(GTK_NOTEBOOK(s->notebook), scrolled_window, gtk_label_new(label));
-    g_signal_connect(vc->menu_item, "activate",
-                     G_CALLBACK(gd_menu_switch_vc), s);
+    g_signal_connect(vadjustment, "changed",
+                     G_CALLBACK(gd_vc_adjustment_changed), vc);
 
-    gtk_menu_shell_append(GTK_MENU_SHELL(view_menu), vc->menu_item);
+    vc->type = GD_VC_VTE;
+    vc->tab_item = box;
+    gtk_notebook_append_page(GTK_NOTEBOOK(s->notebook), vc->tab_item,
+                             gtk_label_new(vc->label));
 
-    qemu_chr_be_generic_open(vc->chr);
-    if (vc->chr->init) {
-        vc->chr->init(vc->chr);
+    qemu_chr_be_generic_open(vc->vte.chr);
+    if (vc->vte.chr->init) {
+        vc->vte.chr->init(vc->vte.chr);
     }
 
-#endif /* CONFIG_VTE */
     return group;
 }
 
+static void gd_vcs_init(GtkDisplayState *s, GSList *group,
+                        GtkWidget *view_menu)
+{
+    int i;
+
+    for (i = 0; i < nb_vcs; i++) {
+        VirtualConsole *vc = &s->vc[s->nb_vcs];
+        group = gd_vc_vte_init(s, vc, vcs[i], s->nb_vcs, group, view_menu);
+        s->nb_vcs++;
+    }
+}
+#endif /* CONFIG_VTE */
+
 /** Window Creation **/
 
+static void gd_connect_vc_gfx_signals(VirtualConsole *vc)
+{
+#if GTK_CHECK_VERSION(3, 0, 0)
+    g_signal_connect(vc->gfx.drawing_area, "draw",
+                     G_CALLBACK(gd_draw_event), vc);
+#else
+    g_signal_connect(vc->gfx.drawing_area, "expose-event",
+                     G_CALLBACK(gd_expose_event), vc);
+#endif
+    g_signal_connect(vc->gfx.drawing_area, "event",
+                     G_CALLBACK(gd_event), vc);
+    g_signal_connect(vc->gfx.drawing_area, "button-press-event",
+                     G_CALLBACK(gd_button_event), vc);
+    g_signal_connect(vc->gfx.drawing_area, "button-release-event",
+                     G_CALLBACK(gd_button_event), vc);
+    g_signal_connect(vc->gfx.drawing_area, "scroll-event",
+                     G_CALLBACK(gd_scroll_event), vc);
+    g_signal_connect(vc->gfx.drawing_area, "key-press-event",
+                     G_CALLBACK(gd_key_event), vc);
+    g_signal_connect(vc->gfx.drawing_area, "key-release-event",
+                     G_CALLBACK(gd_key_event), vc);
+
+    g_signal_connect(vc->gfx.drawing_area, "enter-notify-event",
+                     G_CALLBACK(gd_enter_event), vc);
+    g_signal_connect(vc->gfx.drawing_area, "leave-notify-event",
+                     G_CALLBACK(gd_leave_event), vc);
+    g_signal_connect(vc->gfx.drawing_area, "focus-out-event",
+                     G_CALLBACK(gd_focus_out_event), vc);
+}
+
 static void gd_connect_signals(GtkDisplayState *s)
 {
     g_signal_connect(s->show_tabs_item, "activate",
                      G_CALLBACK(gd_menu_show_tabs), s);
+    g_signal_connect(s->untabify_item, "activate",
+                     G_CALLBACK(gd_menu_untabify), s);
 
     g_signal_connect(s->window, "delete-event",
                      G_CALLBACK(gd_window_close), s);
 
-#if GTK_CHECK_VERSION(3, 0, 0)
-    g_signal_connect(s->drawing_area, "draw",
-                     G_CALLBACK(gd_draw_event), s);
-#else
-    g_signal_connect(s->drawing_area, "expose-event",
-                     G_CALLBACK(gd_expose_event), s);
-#endif
-    g_signal_connect(s->drawing_area, "event",
-                     G_CALLBACK(gd_event), s);
-    g_signal_connect(s->drawing_area, "button-press-event",
-                     G_CALLBACK(gd_button_event), s);
-    g_signal_connect(s->drawing_area, "button-release-event",
-                     G_CALLBACK(gd_button_event), s);
-    g_signal_connect(s->drawing_area, "scroll-event",
-                     G_CALLBACK(gd_scroll_event), s);
-    g_signal_connect(s->drawing_area, "key-press-event",
-                     G_CALLBACK(gd_key_event), s);
-    g_signal_connect(s->drawing_area, "key-release-event",
-                     G_CALLBACK(gd_key_event), s);
-
     g_signal_connect(s->pause_item, "activate",
                      G_CALLBACK(gd_menu_pause), s);
     g_signal_connect(s->reset_item, "activate",
@@ -1293,18 +1586,10 @@ static void gd_connect_signals(GtkDisplayState *s)
                      G_CALLBACK(gd_menu_zoom_fixed), s);
     g_signal_connect(s->zoom_fit_item, "activate",
                      G_CALLBACK(gd_menu_zoom_fit), s);
-    g_signal_connect(s->vga_item, "activate",
-                     G_CALLBACK(gd_menu_switch_vc), s);
     g_signal_connect(s->grab_item, "activate",
                      G_CALLBACK(gd_menu_grab_input), s);
     g_signal_connect(s->notebook, "switch-page",
                      G_CALLBACK(gd_change_page), s);
-    g_signal_connect(s->drawing_area, "enter-notify-event",
-                     G_CALLBACK(gd_enter_event), s);
-    g_signal_connect(s->drawing_area, "leave-notify-event",
-                     G_CALLBACK(gd_leave_event), s);
-    g_signal_connect(s->drawing_area, "focus-out-event",
-                     G_CALLBACK(gd_focus_out_event), s);
 }
 
 static GtkWidget *gd_create_menu_machine(GtkDisplayState *s, GtkAccelGroup *accel_group)
@@ -1340,12 +1625,68 @@ static GtkWidget *gd_create_menu_machine(GtkDisplayState *s, GtkAccelGroup *acce
     return machine_menu;
 }
 
+static const DisplayChangeListenerOps dcl_ops = {
+    .dpy_name          = "gtk",
+    .dpy_gfx_update    = gd_update,
+    .dpy_gfx_switch    = gd_switch,
+    .dpy_refresh       = gd_refresh,
+    .dpy_mouse_set     = gd_mouse_set,
+    .dpy_cursor_define = gd_cursor_define,
+};
+
+static GSList *gd_vc_gfx_init(GtkDisplayState *s, VirtualConsole *vc,
+                              QemuConsole *con, int idx,
+                              GSList *group, GtkWidget *view_menu)
+{
+    Error *local_err = NULL;
+    Object *obj;
+
+    obj = object_property_get_link(OBJECT(con), "device", &local_err);
+    if (obj) {
+        vc->label = g_strdup_printf("%s", object_get_typename(obj));
+    } else {
+        vc->label = g_strdup_printf("VGA");
+    }
+
+    vc->s = s;
+    vc->gfx.scale_x = 1.0;
+    vc->gfx.scale_y = 1.0;
+
+    vc->gfx.drawing_area = gtk_drawing_area_new();
+    gtk_widget_add_events(vc->gfx.drawing_area,
+                          GDK_POINTER_MOTION_MASK |
+                          GDK_BUTTON_PRESS_MASK |
+                          GDK_BUTTON_RELEASE_MASK |
+                          GDK_BUTTON_MOTION_MASK |
+                          GDK_ENTER_NOTIFY_MASK |
+                          GDK_LEAVE_NOTIFY_MASK |
+                          GDK_SCROLL_MASK |
+                          GDK_KEY_PRESS_MASK);
+    gtk_widget_set_double_buffered(vc->gfx.drawing_area, FALSE);
+    gtk_widget_set_can_focus(vc->gfx.drawing_area, TRUE);
+
+    vc->type = GD_VC_GFX;
+    vc->tab_item = vc->gfx.drawing_area;
+    gtk_notebook_append_page(GTK_NOTEBOOK(s->notebook),
+                             vc->tab_item, gtk_label_new(vc->label));
+    gd_connect_vc_gfx_signals(vc);
+
+    group = gd_vc_menu_init(s, vc, idx, group, view_menu);
+
+    vc->gfx.dcl.ops = &dcl_ops;
+    vc->gfx.dcl.con = con;
+    register_displaychangelistener(&vc->gfx.dcl);
+
+    return group;
+}
+
 static GtkWidget *gd_create_menu_view(GtkDisplayState *s, GtkAccelGroup *accel_group)
 {
     GSList *group = NULL;
     GtkWidget *view_menu;
     GtkWidget *separator;
-    int i;
+    QemuConsole *con;
+    int vc;
 
     view_menu = gtk_menu_new();
     gtk_menu_set_accel_group(GTK_MENU(view_menu), accel_group);
@@ -1400,26 +1741,31 @@ static GtkWidget *gd_create_menu_view(GtkDisplayState *s, GtkAccelGroup *accel_g
     separator = gtk_separator_menu_item_new();
     gtk_menu_shell_append(GTK_MENU_SHELL(view_menu), separator);
 
-    s->vga_item = gtk_radio_menu_item_new_with_mnemonic(group, "_VGA");
-    group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(s->vga_item));
-    gtk_menu_item_set_accel_path(GTK_MENU_ITEM(s->vga_item),
-                                 "<QEMU>/View/VGA");
-    gtk_accel_map_add_entry("<QEMU>/View/VGA", GDK_KEY_1, HOTKEY_MODIFIERS);
-    gtk_menu_shell_append(GTK_MENU_SHELL(view_menu), s->vga_item);
-
-    for (i = 0; i < nb_vcs; i++) {
-        VirtualConsole *vc = &s->vc[i];
-
-        group = gd_vc_init(s, vc, i, group, view_menu);
+    /* gfx */
+    for (vc = 0;; vc++) {
+        con = qemu_console_lookup_by_index(vc);
+        if (!con || !qemu_console_is_graphic(con)) {
+            break;
+        }
+        group = gd_vc_gfx_init(s, &s->vc[vc], con,
+                               vc, group, view_menu);
         s->nb_vcs++;
     }
 
+#if defined(CONFIG_VTE)
+    /* vte */
+    gd_vcs_init(s, group, view_menu);
+#endif
+
     separator = gtk_separator_menu_item_new();
     gtk_menu_shell_append(GTK_MENU_SHELL(view_menu), separator);
 
     s->show_tabs_item = gtk_check_menu_item_new_with_mnemonic(_("Show _Tabs"));
     gtk_menu_shell_append(GTK_MENU_SHELL(view_menu), s->show_tabs_item);
 
+    s->untabify_item = gtk_menu_item_new_with_mnemonic(_("Detach Tab"));
+    gtk_menu_shell_append(GTK_MENU_SHELL(view_menu), s->untabify_item);
+
     return view_menu;
 }
 
@@ -1445,14 +1791,28 @@ static void gd_create_menus(GtkDisplayState *s)
     s->accel_group = accel_group;
 }
 
-static const DisplayChangeListenerOps dcl_ops = {
-    .dpy_name          = "gtk",
-    .dpy_gfx_update    = gd_update,
-    .dpy_gfx_switch    = gd_switch,
-    .dpy_refresh       = gd_refresh,
-    .dpy_mouse_set     = gd_mouse_set,
-    .dpy_cursor_define = gd_cursor_define,
-};
+static void gd_set_keycode_type(GtkDisplayState *s)
+{
+#ifndef _WIN32
+    char *keycodes = NULL;
+    GdkDisplay *display = gtk_widget_get_display(s->window);
+    Display *x11_display = gdk_x11_display_get_xdisplay(display);
+    XkbDescPtr desc = XkbGetKeyboard(x11_display, XkbGBN_AllComponentsMask,
+                                     XkbUseCoreKbd);
+
+    if (desc && desc->names) {
+        keycodes = XGetAtomName(x11_display, desc->names->keycodes);
+    }
+    if (keycodes == NULL) {
+        fprintf(stderr, "could not lookup keycode name\n");
+    } else if (strstart(keycodes, "evdev", NULL)) {
+        s->has_evdev = true;
+    } else if (!strstart(keycodes, "xfree86", NULL)) {
+        fprintf(stderr, "unknown keycodes `%s', please report to "
+                "qemu-devel@nongnu.org\n", keycodes);
+    }
+#endif
+}
 
 void gtk_display_init(DisplayState *ds, bool full_screen, bool grab_on_hover)
 {
@@ -1461,9 +1821,6 @@ void gtk_display_init(DisplayState *ds, bool full_screen, bool grab_on_hover)
 
     gtk_init(NULL, NULL);
 
-    s->dcl.ops = &dcl_ops;
-    s->dcl.con = qemu_console_lookup_by_index(0);
-
     s->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 #if GTK_CHECK_VERSION(3, 2, 0)
     s->vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
@@ -1471,11 +1828,8 @@ void gtk_display_init(DisplayState *ds, bool full_screen, bool grab_on_hover)
     s->vbox = gtk_vbox_new(FALSE, 0);
 #endif
     s->notebook = gtk_notebook_new();
-    s->drawing_area = gtk_drawing_area_new();
     s->menu_bar = gtk_menu_bar_new();
 
-    s->scale_x = 1.0;
-    s->scale_y = 1.0;
     s->free_scale = FALSE;
 
     setlocale(LC_ALL, "");
@@ -1488,8 +1842,6 @@ void gtk_display_init(DisplayState *ds, bool full_screen, bool grab_on_hover)
     qemu_add_mouse_mode_change_notifier(&s->mouse_mode_notifier);
     qemu_add_vm_change_state_handler(gd_change_runstate, s);
 
-    gtk_notebook_append_page(GTK_NOTEBOOK(s->notebook), s->drawing_area, gtk_label_new("VGA"));
-
     filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "qemu_logo_no_text.svg");
     if (filename) {
         GError *error = NULL;
@@ -1506,18 +1858,6 @@ void gtk_display_init(DisplayState *ds, bool full_screen, bool grab_on_hover)
 
     gd_connect_signals(s);
 
-    gtk_widget_add_events(s->drawing_area,
-                          GDK_POINTER_MOTION_MASK |
-                          GDK_BUTTON_PRESS_MASK |
-                          GDK_BUTTON_RELEASE_MASK |
-                          GDK_BUTTON_MOTION_MASK |
-                          GDK_ENTER_NOTIFY_MASK |
-                          GDK_LEAVE_NOTIFY_MASK |
-                          GDK_SCROLL_MASK |
-                          GDK_KEY_PRESS_MASK);
-    gtk_widget_set_double_buffered(s->drawing_area, FALSE);
-    gtk_widget_set_can_focus(s->drawing_area, TRUE);
-
     gtk_notebook_set_show_tabs(GTK_NOTEBOOK(s->notebook), FALSE);
     gtk_notebook_set_show_border(GTK_NOTEBOOK(s->notebook), FALSE);
 
@@ -1530,6 +1870,21 @@ void gtk_display_init(DisplayState *ds, bool full_screen, bool grab_on_hover)
 
     gtk_widget_show_all(s->window);
 
+#ifdef VTE_RESIZE_HACK
+    {
+        VirtualConsole *cur = gd_vc_find_current(s);
+        int i;
+
+        for (i = 0; i < s->nb_vcs; i++) {
+            VirtualConsole *vc = &s->vc[i];
+            if (vc && vc->type == GD_VC_VTE && vc != cur) {
+                gtk_widget_hide(vc->vte.terminal);
+            }
+        }
+        gd_update_windowsize(cur);
+    }
+#endif
+
     if (full_screen) {
         gtk_menu_item_activate(GTK_MENU_ITEM(s->full_screen_item));
     }
@@ -1537,7 +1892,12 @@ void gtk_display_init(DisplayState *ds, bool full_screen, bool grab_on_hover)
         gtk_menu_item_activate(GTK_MENU_ITEM(s->grab_on_hover_item));
     }
 
-    register_displaychangelistener(&s->dcl);
+    gd_set_keycode_type(s);
+}
 
-    global_state = s;
+void early_gtk_display_init(void)
+{
+#if defined(CONFIG_VTE)
+    register_vc_handler(gd_vc_handler);
+#endif
 }
diff --git a/ui/input-keymap.c b/ui/input-keymap.c
new file mode 100644
index 0000000000..5d299353a8
--- /dev/null
+++ b/ui/input-keymap.c
@@ -0,0 +1,198 @@
+#include "sysemu/sysemu.h"
+#include "ui/keymaps.h"
+#include "ui/input.h"
+
+static const int qcode_to_number[] = {
+    [Q_KEY_CODE_SHIFT] = 0x2a,
+    [Q_KEY_CODE_SHIFT_R] = 0x36,
+
+    [Q_KEY_CODE_ALT] = 0x38,
+    [Q_KEY_CODE_ALT_R] = 0xb8,
+    [Q_KEY_CODE_ALTGR] = 0x64,
+    [Q_KEY_CODE_ALTGR_R] = 0xe4,
+    [Q_KEY_CODE_CTRL] = 0x1d,
+    [Q_KEY_CODE_CTRL_R] = 0x9d,
+
+    [Q_KEY_CODE_META_L] = 0xdb,
+    [Q_KEY_CODE_META_R] = 0xdc,
+    [Q_KEY_CODE_MENU] = 0xdd,
+
+    [Q_KEY_CODE_ESC] = 0x01,
+
+    [Q_KEY_CODE_1] = 0x02,
+    [Q_KEY_CODE_2] = 0x03,
+    [Q_KEY_CODE_3] = 0x04,
+    [Q_KEY_CODE_4] = 0x05,
+    [Q_KEY_CODE_5] = 0x06,
+    [Q_KEY_CODE_6] = 0x07,
+    [Q_KEY_CODE_7] = 0x08,
+    [Q_KEY_CODE_8] = 0x09,
+    [Q_KEY_CODE_9] = 0x0a,
+    [Q_KEY_CODE_0] = 0x0b,
+    [Q_KEY_CODE_MINUS] = 0x0c,
+    [Q_KEY_CODE_EQUAL] = 0x0d,
+    [Q_KEY_CODE_BACKSPACE] = 0x0e,
+
+    [Q_KEY_CODE_TAB] = 0x0f,
+    [Q_KEY_CODE_Q] = 0x10,
+    [Q_KEY_CODE_W] = 0x11,
+    [Q_KEY_CODE_E] = 0x12,
+    [Q_KEY_CODE_R] = 0x13,
+    [Q_KEY_CODE_T] = 0x14,
+    [Q_KEY_CODE_Y] = 0x15,
+    [Q_KEY_CODE_U] = 0x16,
+    [Q_KEY_CODE_I] = 0x17,
+    [Q_KEY_CODE_O] = 0x18,
+    [Q_KEY_CODE_P] = 0x19,
+    [Q_KEY_CODE_BRACKET_LEFT] = 0x1a,
+    [Q_KEY_CODE_BRACKET_RIGHT] = 0x1b,
+    [Q_KEY_CODE_RET] = 0x1c,
+
+    [Q_KEY_CODE_A] = 0x1e,
+    [Q_KEY_CODE_S] = 0x1f,
+    [Q_KEY_CODE_D] = 0x20,
+    [Q_KEY_CODE_F] = 0x21,
+    [Q_KEY_CODE_G] = 0x22,
+    [Q_KEY_CODE_H] = 0x23,
+    [Q_KEY_CODE_J] = 0x24,
+    [Q_KEY_CODE_K] = 0x25,
+    [Q_KEY_CODE_L] = 0x26,
+    [Q_KEY_CODE_SEMICOLON] = 0x27,
+    [Q_KEY_CODE_APOSTROPHE] = 0x28,
+    [Q_KEY_CODE_GRAVE_ACCENT] = 0x29,
+
+    [Q_KEY_CODE_BACKSLASH] = 0x2b,
+    [Q_KEY_CODE_Z] = 0x2c,
+    [Q_KEY_CODE_X] = 0x2d,
+    [Q_KEY_CODE_C] = 0x2e,
+    [Q_KEY_CODE_V] = 0x2f,
+    [Q_KEY_CODE_B] = 0x30,
+    [Q_KEY_CODE_N] = 0x31,
+    [Q_KEY_CODE_M] = 0x32,
+    [Q_KEY_CODE_COMMA] = 0x33,
+    [Q_KEY_CODE_DOT] = 0x34,
+    [Q_KEY_CODE_SLASH] = 0x35,
+
+    [Q_KEY_CODE_ASTERISK] = 0x37,
+
+    [Q_KEY_CODE_SPC] = 0x39,
+    [Q_KEY_CODE_CAPS_LOCK] = 0x3a,
+    [Q_KEY_CODE_F1] = 0x3b,
+    [Q_KEY_CODE_F2] = 0x3c,
+    [Q_KEY_CODE_F3] = 0x3d,
+    [Q_KEY_CODE_F4] = 0x3e,
+    [Q_KEY_CODE_F5] = 0x3f,
+    [Q_KEY_CODE_F6] = 0x40,
+    [Q_KEY_CODE_F7] = 0x41,
+    [Q_KEY_CODE_F8] = 0x42,
+    [Q_KEY_CODE_F9] = 0x43,
+    [Q_KEY_CODE_F10] = 0x44,
+    [Q_KEY_CODE_NUM_LOCK] = 0x45,
+    [Q_KEY_CODE_SCROLL_LOCK] = 0x46,
+
+    [Q_KEY_CODE_KP_DIVIDE] = 0xb5,
+    [Q_KEY_CODE_KP_MULTIPLY] = 0x37,
+    [Q_KEY_CODE_KP_SUBTRACT] = 0x4a,
+    [Q_KEY_CODE_KP_ADD] = 0x4e,
+    [Q_KEY_CODE_KP_ENTER] = 0x9c,
+    [Q_KEY_CODE_KP_DECIMAL] = 0x53,
+    [Q_KEY_CODE_SYSRQ] = 0x54,
+
+    [Q_KEY_CODE_KP_0] = 0x52,
+    [Q_KEY_CODE_KP_1] = 0x4f,
+    [Q_KEY_CODE_KP_2] = 0x50,
+    [Q_KEY_CODE_KP_3] = 0x51,
+    [Q_KEY_CODE_KP_4] = 0x4b,
+    [Q_KEY_CODE_KP_5] = 0x4c,
+    [Q_KEY_CODE_KP_6] = 0x4d,
+    [Q_KEY_CODE_KP_7] = 0x47,
+    [Q_KEY_CODE_KP_8] = 0x48,
+    [Q_KEY_CODE_KP_9] = 0x49,
+
+    [Q_KEY_CODE_LESS] = 0x56,
+
+    [Q_KEY_CODE_F11] = 0x57,
+    [Q_KEY_CODE_F12] = 0x58,
+
+    [Q_KEY_CODE_PRINT] = 0xb7,
+
+    [Q_KEY_CODE_HOME] = 0xc7,
+    [Q_KEY_CODE_PGUP] = 0xc9,
+    [Q_KEY_CODE_PGDN] = 0xd1,
+    [Q_KEY_CODE_END] = 0xcf,
+
+    [Q_KEY_CODE_LEFT] = 0xcb,
+    [Q_KEY_CODE_UP] = 0xc8,
+    [Q_KEY_CODE_DOWN] = 0xd0,
+    [Q_KEY_CODE_RIGHT] = 0xcd,
+
+    [Q_KEY_CODE_INSERT] = 0xd2,
+    [Q_KEY_CODE_DELETE] = 0xd3,
+    [Q_KEY_CODE_MAX] = 0,
+};
+
+static int number_to_qcode[0x100];
+
+int qemu_input_key_value_to_number(const KeyValue *value)
+{
+    if (value->kind == KEY_VALUE_KIND_QCODE) {
+        return qcode_to_number[value->qcode];
+    } else {
+        assert(value->kind == KEY_VALUE_KIND_NUMBER);
+        return value->number;
+    }
+}
+
+int qemu_input_key_number_to_qcode(uint8_t nr)
+{
+    static int first = true;
+
+    if (first) {
+        int qcode, number;
+        first = false;
+        for (qcode = 0; qcode < Q_KEY_CODE_MAX; qcode++) {
+            number = qcode_to_number[qcode];
+            assert(number < ARRAY_SIZE(number_to_qcode));
+            number_to_qcode[number] = qcode;
+        }
+    }
+
+    return number_to_qcode[nr];
+}
+
+int qemu_input_key_value_to_qcode(const KeyValue *value)
+{
+    if (value->kind == KEY_VALUE_KIND_QCODE) {
+        return value->qcode;
+    } else {
+        assert(value->kind == KEY_VALUE_KIND_NUMBER);
+        return qemu_input_key_number_to_qcode(value->number);
+    }
+}
+
+int qemu_input_key_value_to_scancode(const KeyValue *value, bool down,
+                                     int *codes)
+{
+    int keycode = qemu_input_key_value_to_number(value);
+    int count = 0;
+
+    if (value->kind == KEY_VALUE_KIND_QCODE &&
+        value->qcode == Q_KEY_CODE_PAUSE) {
+        /* specific case */
+        int v = down ? 0 : 0x80;
+        codes[count++] = 0xe1;
+        codes[count++] = 0x1d | v;
+        codes[count++] = 0x45 | v;
+        return count;
+    }
+    if (keycode & SCANCODE_GREY) {
+        codes[count++] = SCANCODE_EMUL0;
+        keycode &= ~SCANCODE_GREY;
+    }
+    if (!down) {
+        keycode |= SCANCODE_UP;
+    }
+    codes[count++] = keycode;
+
+    return count;
+}
diff --git a/ui/input-legacy.c b/ui/input-legacy.c
index 1aa2605b75..3025f50f49 100644
--- a/ui/input-legacy.c
+++ b/ui/input-legacy.c
@@ -60,152 +60,6 @@ static QTAILQ_HEAD(, QEMUPutLEDEntry) led_handlers =
 static QTAILQ_HEAD(, QEMUPutMouseEntry) mouse_handlers =
     QTAILQ_HEAD_INITIALIZER(mouse_handlers);
 
-static const int key_defs[] = {
-    [Q_KEY_CODE_SHIFT] = 0x2a,
-    [Q_KEY_CODE_SHIFT_R] = 0x36,
-
-    [Q_KEY_CODE_ALT] = 0x38,
-    [Q_KEY_CODE_ALT_R] = 0xb8,
-    [Q_KEY_CODE_ALTGR] = 0x64,
-    [Q_KEY_CODE_ALTGR_R] = 0xe4,
-    [Q_KEY_CODE_CTRL] = 0x1d,
-    [Q_KEY_CODE_CTRL_R] = 0x9d,
-
-    [Q_KEY_CODE_MENU] = 0xdd,
-
-    [Q_KEY_CODE_ESC] = 0x01,
-
-    [Q_KEY_CODE_1] = 0x02,
-    [Q_KEY_CODE_2] = 0x03,
-    [Q_KEY_CODE_3] = 0x04,
-    [Q_KEY_CODE_4] = 0x05,
-    [Q_KEY_CODE_5] = 0x06,
-    [Q_KEY_CODE_6] = 0x07,
-    [Q_KEY_CODE_7] = 0x08,
-    [Q_KEY_CODE_8] = 0x09,
-    [Q_KEY_CODE_9] = 0x0a,
-    [Q_KEY_CODE_0] = 0x0b,
-    [Q_KEY_CODE_MINUS] = 0x0c,
-    [Q_KEY_CODE_EQUAL] = 0x0d,
-    [Q_KEY_CODE_BACKSPACE] = 0x0e,
-
-    [Q_KEY_CODE_TAB] = 0x0f,
-    [Q_KEY_CODE_Q] = 0x10,
-    [Q_KEY_CODE_W] = 0x11,
-    [Q_KEY_CODE_E] = 0x12,
-    [Q_KEY_CODE_R] = 0x13,
-    [Q_KEY_CODE_T] = 0x14,
-    [Q_KEY_CODE_Y] = 0x15,
-    [Q_KEY_CODE_U] = 0x16,
-    [Q_KEY_CODE_I] = 0x17,
-    [Q_KEY_CODE_O] = 0x18,
-    [Q_KEY_CODE_P] = 0x19,
-    [Q_KEY_CODE_BRACKET_LEFT] = 0x1a,
-    [Q_KEY_CODE_BRACKET_RIGHT] = 0x1b,
-    [Q_KEY_CODE_RET] = 0x1c,
-
-    [Q_KEY_CODE_A] = 0x1e,
-    [Q_KEY_CODE_S] = 0x1f,
-    [Q_KEY_CODE_D] = 0x20,
-    [Q_KEY_CODE_F] = 0x21,
-    [Q_KEY_CODE_G] = 0x22,
-    [Q_KEY_CODE_H] = 0x23,
-    [Q_KEY_CODE_J] = 0x24,
-    [Q_KEY_CODE_K] = 0x25,
-    [Q_KEY_CODE_L] = 0x26,
-    [Q_KEY_CODE_SEMICOLON] = 0x27,
-    [Q_KEY_CODE_APOSTROPHE] = 0x28,
-    [Q_KEY_CODE_GRAVE_ACCENT] = 0x29,
-
-    [Q_KEY_CODE_BACKSLASH] = 0x2b,
-    [Q_KEY_CODE_Z] = 0x2c,
-    [Q_KEY_CODE_X] = 0x2d,
-    [Q_KEY_CODE_C] = 0x2e,
-    [Q_KEY_CODE_V] = 0x2f,
-    [Q_KEY_CODE_B] = 0x30,
-    [Q_KEY_CODE_N] = 0x31,
-    [Q_KEY_CODE_M] = 0x32,
-    [Q_KEY_CODE_COMMA] = 0x33,
-    [Q_KEY_CODE_DOT] = 0x34,
-    [Q_KEY_CODE_SLASH] = 0x35,
-
-    [Q_KEY_CODE_ASTERISK] = 0x37,
-
-    [Q_KEY_CODE_SPC] = 0x39,
-    [Q_KEY_CODE_CAPS_LOCK] = 0x3a,
-    [Q_KEY_CODE_F1] = 0x3b,
-    [Q_KEY_CODE_F2] = 0x3c,
-    [Q_KEY_CODE_F3] = 0x3d,
-    [Q_KEY_CODE_F4] = 0x3e,
-    [Q_KEY_CODE_F5] = 0x3f,
-    [Q_KEY_CODE_F6] = 0x40,
-    [Q_KEY_CODE_F7] = 0x41,
-    [Q_KEY_CODE_F8] = 0x42,
-    [Q_KEY_CODE_F9] = 0x43,
-    [Q_KEY_CODE_F10] = 0x44,
-    [Q_KEY_CODE_NUM_LOCK] = 0x45,
-    [Q_KEY_CODE_SCROLL_LOCK] = 0x46,
-
-    [Q_KEY_CODE_KP_DIVIDE] = 0xb5,
-    [Q_KEY_CODE_KP_MULTIPLY] = 0x37,
-    [Q_KEY_CODE_KP_SUBTRACT] = 0x4a,
-    [Q_KEY_CODE_KP_ADD] = 0x4e,
-    [Q_KEY_CODE_KP_ENTER] = 0x9c,
-    [Q_KEY_CODE_KP_DECIMAL] = 0x53,
-    [Q_KEY_CODE_SYSRQ] = 0x54,
-
-    [Q_KEY_CODE_KP_0] = 0x52,
-    [Q_KEY_CODE_KP_1] = 0x4f,
-    [Q_KEY_CODE_KP_2] = 0x50,
-    [Q_KEY_CODE_KP_3] = 0x51,
-    [Q_KEY_CODE_KP_4] = 0x4b,
-    [Q_KEY_CODE_KP_5] = 0x4c,
-    [Q_KEY_CODE_KP_6] = 0x4d,
-    [Q_KEY_CODE_KP_7] = 0x47,
-    [Q_KEY_CODE_KP_8] = 0x48,
-    [Q_KEY_CODE_KP_9] = 0x49,
-
-    [Q_KEY_CODE_LESS] = 0x56,
-
-    [Q_KEY_CODE_F11] = 0x57,
-    [Q_KEY_CODE_F12] = 0x58,
-
-    [Q_KEY_CODE_PRINT] = 0xb7,
-
-    [Q_KEY_CODE_HOME] = 0xc7,
-    [Q_KEY_CODE_PGUP] = 0xc9,
-    [Q_KEY_CODE_PGDN] = 0xd1,
-    [Q_KEY_CODE_END] = 0xcf,
-
-    [Q_KEY_CODE_LEFT] = 0xcb,
-    [Q_KEY_CODE_UP] = 0xc8,
-    [Q_KEY_CODE_DOWN] = 0xd0,
-    [Q_KEY_CODE_RIGHT] = 0xcd,
-
-    [Q_KEY_CODE_INSERT] = 0xd2,
-    [Q_KEY_CODE_DELETE] = 0xd3,
-#ifdef NEED_CPU_H
-#if defined(TARGET_SPARC) && !defined(TARGET_SPARC64)
-    [Q_KEY_CODE_STOP] = 0xf0,
-    [Q_KEY_CODE_AGAIN] = 0xf1,
-    [Q_KEY_CODE_PROPS] = 0xf2,
-    [Q_KEY_CODE_UNDO] = 0xf3,
-    [Q_KEY_CODE_FRONT] = 0xf4,
-    [Q_KEY_CODE_COPY] = 0xf5,
-    [Q_KEY_CODE_OPEN] = 0xf6,
-    [Q_KEY_CODE_PASTE] = 0xf7,
-    [Q_KEY_CODE_FIND] = 0xf8,
-    [Q_KEY_CODE_CUT] = 0xf9,
-    [Q_KEY_CODE_LF] = 0xfa,
-    [Q_KEY_CODE_HELP] = 0xfb,
-    [Q_KEY_CODE_META_L] = 0xfc,
-    [Q_KEY_CODE_META_R] = 0xfd,
-    [Q_KEY_CODE_COMPOSE] = 0xfe,
-#endif
-#endif
-    [Q_KEY_CODE_MAX] = 0,
-};
-
 int index_from_key(const char *key)
 {
     int i;
@@ -220,102 +74,47 @@ int index_from_key(const char *key)
     return i;
 }
 
-static int *keycodes;
-static int keycodes_size;
-static QEMUTimer *key_timer;
-
-static int keycode_from_keyvalue(const KeyValue *value)
-{
-    if (value->kind == KEY_VALUE_KIND_QCODE) {
-        return key_defs[value->qcode];
-    } else {
-        assert(value->kind == KEY_VALUE_KIND_NUMBER);
-        return value->number;
-    }
-}
-
-static void free_keycodes(void)
+static KeyValue *copy_key_value(KeyValue *src)
 {
-    g_free(keycodes);
-    keycodes = NULL;
-    keycodes_size = 0;
-}
-
-static void release_keys(void *opaque)
-{
-    while (keycodes_size > 0) {
-        qemu_input_event_send_key_number(NULL, keycodes[--keycodes_size],
-                                         false);
-    }
-
-    free_keycodes();
+    KeyValue *dst = g_new(KeyValue, 1);
+    memcpy(dst, src, sizeof(*src));
+    return dst;
 }
 
 void qmp_send_key(KeyValueList *keys, bool has_hold_time, int64_t hold_time,
                   Error **errp)
 {
-    int keycode;
     KeyValueList *p;
 
-    if (!key_timer) {
-        key_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, release_keys, NULL);
-    }
-
-    if (keycodes != NULL) {
-        timer_del(key_timer);
-        release_keys(NULL);
-    }
-
     if (!has_hold_time) {
-        hold_time = 100;
+        hold_time = 0; /* use default */
     }
 
     for (p = keys; p != NULL; p = p->next) {
-        /* key down events */
-        keycode = keycode_from_keyvalue(p->value);
-        if (keycode < 0x01 || keycode > 0xff) {
-            error_setg(errp, "invalid hex keycode 0x%x", keycode);
-            free_keycodes();
-            return;
-        }
-
-        qemu_input_event_send_key_number(NULL, keycode, true);
-
-        keycodes = g_realloc(keycodes, sizeof(int) * (keycodes_size + 1));
-        keycodes[keycodes_size++] = keycode;
+        qemu_input_event_send_key(NULL, copy_key_value(p->value), true);
+        qemu_input_event_send_key_delay(hold_time);
+    }
+    for (p = keys; p != NULL; p = p->next) {
+        qemu_input_event_send_key(NULL, copy_key_value(p->value), false);
+        qemu_input_event_send_key_delay(hold_time);
     }
-
-    /* delayed key up events */
-    timer_mod(key_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
-                   muldiv64(get_ticks_per_sec(), hold_time, 1000));
 }
 
 static void legacy_kbd_event(DeviceState *dev, QemuConsole *src,
                              InputEvent *evt)
 {
     QEMUPutKbdEntry *entry = (QEMUPutKbdEntry *)dev;
-    int keycode = keycode_from_keyvalue(evt->key->key);
+    int scancodes[3], i, count;
 
     if (!entry || !entry->put_kbd) {
         return;
     }
-    if (evt->key->key->kind == KEY_VALUE_KIND_QCODE &&
-        evt->key->key->qcode == Q_KEY_CODE_PAUSE) {
-        /* specific case */
-        int v = evt->key->down ? 0 : 0x80;
-        entry->put_kbd(entry->opaque, 0xe1);
-        entry->put_kbd(entry->opaque, 0x1d | v);
-        entry->put_kbd(entry->opaque, 0x45 | v);
-        return;
-    }
-    if (keycode & SCANCODE_GREY) {
-        entry->put_kbd(entry->opaque, SCANCODE_EMUL0);
-        keycode &= ~SCANCODE_GREY;
-    }
-    if (!evt->key->down) {
-        keycode |= SCANCODE_UP;
+    count = qemu_input_key_value_to_scancode(evt->key->key,
+                                             evt->key->down,
+                                             scancodes);
+    for (i = 0; i < count; i++) {
+        entry->put_kbd(entry->opaque, scancodes[i]);
     }
-    entry->put_kbd(entry->opaque, keycode);
 }
 
 static QemuInputHandler legacy_kbd_handler = {
diff --git a/ui/input.c b/ui/input.c
index 1ed0e783b1..89d9db78c0 100644
--- a/ui/input.c
+++ b/ui/input.c
@@ -1,3 +1,4 @@
+#include "hw/qdev.h"
 #include "sysemu/sysemu.h"
 #include "qapi-types.h"
 #include "qmp-commands.h"
@@ -10,13 +11,34 @@ struct QemuInputHandlerState {
     QemuInputHandler  *handler;
     int               id;
     int               events;
+    QemuConsole       *con;
     QTAILQ_ENTRY(QemuInputHandlerState) node;
 };
+
+typedef struct QemuInputEventQueue QemuInputEventQueue;
+struct QemuInputEventQueue {
+    enum {
+        QEMU_INPUT_QUEUE_DELAY = 1,
+        QEMU_INPUT_QUEUE_EVENT,
+        QEMU_INPUT_QUEUE_SYNC,
+    } type;
+    QEMUTimer *timer;
+    uint32_t delay_ms;
+    QemuConsole *src;
+    InputEvent *evt;
+    QTAILQ_ENTRY(QemuInputEventQueue) node;
+};
+
 static QTAILQ_HEAD(, QemuInputHandlerState) handlers =
     QTAILQ_HEAD_INITIALIZER(handlers);
 static NotifierList mouse_mode_notifiers =
     NOTIFIER_LIST_INITIALIZER(mouse_mode_notifiers);
 
+static QTAILQ_HEAD(QemuInputEventQueueHead, QemuInputEventQueue) kbd_queue =
+    QTAILQ_HEAD_INITIALIZER(kbd_queue);
+static QEMUTimer *kbd_timer;
+static uint32_t kbd_default_delay_ms = 10;
+
 QemuInputHandlerState *qemu_input_handler_register(DeviceState *dev,
                                                    QemuInputHandler *handler)
 {
@@ -39,6 +61,13 @@ void qemu_input_handler_activate(QemuInputHandlerState *s)
     qemu_input_check_mode_change();
 }
 
+void qemu_input_handler_deactivate(QemuInputHandlerState *s)
+{
+    QTAILQ_REMOVE(&handlers, s, node);
+    QTAILQ_INSERT_TAIL(&handlers, s, node);
+    qemu_input_check_mode_change();
+}
+
 void qemu_input_handler_unregister(QemuInputHandlerState *s)
 {
     QTAILQ_REMOVE(&handlers, s, node);
@@ -46,12 +75,46 @@ void qemu_input_handler_unregister(QemuInputHandlerState *s)
     qemu_input_check_mode_change();
 }
 
+void qemu_input_handler_bind(QemuInputHandlerState *s,
+                             const char *device_id, int head,
+                             Error **errp)
+{
+    DeviceState *dev;
+    QemuConsole *con;
+
+    dev = qdev_find_recursive(sysbus_get_default(), device_id);
+    if (dev == NULL) {
+        error_set(errp, QERR_DEVICE_NOT_FOUND, device_id);
+        return;
+    }
+
+    con = qemu_console_lookup_by_device(dev, head);
+    if (con == NULL) {
+        error_setg(errp, "Device %s is not bound to a QemuConsole", device_id);
+        return;
+    }
+
+    s->con = con;
+}
+
 static QemuInputHandlerState*
-qemu_input_find_handler(uint32_t mask)
+qemu_input_find_handler(uint32_t mask, QemuConsole *con)
 {
     QemuInputHandlerState *s;
 
     QTAILQ_FOREACH(s, &handlers, node) {
+        if (s->con == NULL || s->con != con) {
+            continue;
+        }
+        if (mask & s->handler->mask) {
+            return s;
+        }
+    }
+
+    QTAILQ_FOREACH(s, &handlers, node) {
+        if (s->con != NULL) {
+            continue;
+        }
         if (mask & s->handler->mask) {
             return s;
         }
@@ -87,7 +150,7 @@ static void qemu_input_transform_abs_rotate(InputEvent *evt)
 static void qemu_input_event_trace(QemuConsole *src, InputEvent *evt)
 {
     const char *name;
-    int idx = -1;
+    int qcode, idx = -1;
 
     if (src) {
         idx = qemu_console_get_index(src);
@@ -96,8 +159,10 @@ static void qemu_input_event_trace(QemuConsole *src, InputEvent *evt)
     case INPUT_EVENT_KIND_KEY:
         switch (evt->key->key->kind) {
         case KEY_VALUE_KIND_NUMBER:
+            qcode = qemu_input_key_number_to_qcode(evt->key->key->number);
+            name = QKeyCode_lookup[qcode];
             trace_input_event_key_number(idx, evt->key->key->number,
-                                         evt->key->down);
+                                         name, evt->key->down);
             break;
         case KEY_VALUE_KIND_QCODE:
             name = QKeyCode_lookup[evt->key->key->qcode];
@@ -126,6 +191,73 @@ static void qemu_input_event_trace(QemuConsole *src, InputEvent *evt)
     }
 }
 
+static void qemu_input_queue_process(void *opaque)
+{
+    struct QemuInputEventQueueHead *queue = opaque;
+    QemuInputEventQueue *item;
+
+    g_assert(!QTAILQ_EMPTY(queue));
+    item = QTAILQ_FIRST(queue);
+    g_assert(item->type == QEMU_INPUT_QUEUE_DELAY);
+    QTAILQ_REMOVE(queue, item, node);
+    g_free(item);
+
+    while (!QTAILQ_EMPTY(queue)) {
+        item = QTAILQ_FIRST(queue);
+        switch (item->type) {
+        case QEMU_INPUT_QUEUE_DELAY:
+            timer_mod(item->timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL)
+                      + item->delay_ms);
+            return;
+        case QEMU_INPUT_QUEUE_EVENT:
+            qemu_input_event_send(item->src, item->evt);
+            qapi_free_InputEvent(item->evt);
+            break;
+        case QEMU_INPUT_QUEUE_SYNC:
+            qemu_input_event_sync();
+            break;
+        }
+        QTAILQ_REMOVE(queue, item, node);
+        g_free(item);
+    }
+}
+
+static void qemu_input_queue_delay(struct QemuInputEventQueueHead *queue,
+                                   QEMUTimer *timer, uint32_t delay_ms)
+{
+    QemuInputEventQueue *item = g_new0(QemuInputEventQueue, 1);
+    bool start_timer = QTAILQ_EMPTY(queue);
+
+    item->type = QEMU_INPUT_QUEUE_DELAY;
+    item->delay_ms = delay_ms;
+    item->timer = timer;
+    QTAILQ_INSERT_TAIL(queue, item, node);
+
+    if (start_timer) {
+        timer_mod(item->timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL)
+                  + item->delay_ms);
+    }
+}
+
+static void qemu_input_queue_event(struct QemuInputEventQueueHead *queue,
+                                   QemuConsole *src, InputEvent *evt)
+{
+    QemuInputEventQueue *item = g_new0(QemuInputEventQueue, 1);
+
+    item->type = QEMU_INPUT_QUEUE_EVENT;
+    item->src = src;
+    item->evt = evt;
+    QTAILQ_INSERT_TAIL(queue, item, node);
+}
+
+static void qemu_input_queue_sync(struct QemuInputEventQueueHead *queue)
+{
+    QemuInputEventQueue *item = g_new0(QemuInputEventQueue, 1);
+
+    item->type = QEMU_INPUT_QUEUE_SYNC;
+    QTAILQ_INSERT_TAIL(queue, item, node);
+}
+
 void qemu_input_event_send(QemuConsole *src, InputEvent *evt)
 {
     QemuInputHandlerState *s;
@@ -142,7 +274,7 @@ void qemu_input_event_send(QemuConsole *src, InputEvent *evt)
     }
 
     /* send event */
-    s = qemu_input_find_handler(1 << evt->kind);
+    s = qemu_input_find_handler(1 << evt->kind, src);
     if (!s) {
         return;
     }
@@ -185,9 +317,14 @@ void qemu_input_event_send_key(QemuConsole *src, KeyValue *key, bool down)
 {
     InputEvent *evt;
     evt = qemu_input_event_new_key(key, down);
-    qemu_input_event_send(src, evt);
-    qemu_input_event_sync();
-    qapi_free_InputEvent(evt);
+    if (QTAILQ_EMPTY(&kbd_queue)) {
+        qemu_input_event_send(src, evt);
+        qemu_input_event_sync();
+        qapi_free_InputEvent(evt);
+    } else {
+        qemu_input_queue_event(&kbd_queue, src, evt);
+        qemu_input_queue_sync(&kbd_queue);
+    }
 }
 
 void qemu_input_event_send_key_number(QemuConsole *src, int num, bool down)
@@ -206,6 +343,16 @@ void qemu_input_event_send_key_qcode(QemuConsole *src, QKeyCode q, bool down)
     qemu_input_event_send_key(src, key, down);
 }
 
+void qemu_input_event_send_key_delay(uint32_t delay_ms)
+{
+    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);
+}
+
 InputEvent *qemu_input_event_new_btn(InputButton btn, bool down)
 {
     InputEvent *evt = g_new0(InputEvent, 1);
@@ -243,7 +390,8 @@ bool qemu_input_is_absolute(void)
 {
     QemuInputHandlerState *s;
 
-    s = qemu_input_find_handler(INPUT_EVENT_MASK_REL | INPUT_EVENT_MASK_ABS);
+    s = qemu_input_find_handler(INPUT_EVENT_MASK_REL | INPUT_EVENT_MASK_ABS,
+                                NULL);
     return (s != NULL) && (s->handler->mask & INPUT_EVENT_MASK_ABS);
 }
 
diff --git a/ui/sdl2.c b/ui/sdl2.c
index 361de619fa..fcac87b4be 100644
--- a/ui/sdl2.c
+++ b/ui/sdl2.c
@@ -49,6 +49,7 @@ static struct sdl2_state {
     int idx;
     int last_vm_running; /* per console for caption reasons */
     int x, y;
+    int hidden;
 } *sdl2_console;
 
 static SDL_Surface *guest_sprite_surface;
@@ -136,6 +137,9 @@ static void do_sdl_resize(struct sdl2_state *scon, int width, int height,
         } else {
             flags |= SDL_WINDOW_RESIZABLE;
         }
+        if (scon->hidden) {
+            flags |= SDL_WINDOW_HIDDEN;
+        }
 
         scon->real_window = SDL_CreateWindow("", SDL_WINDOWPOS_UNDEFINED,
                                              SDL_WINDOWPOS_UNDEFINED,
@@ -190,30 +194,50 @@ static void sdl_switch(DisplayChangeListener *dcl,
     }
 }
 
-static void reset_keys(void)
+static void reset_keys(struct sdl2_state *scon)
 {
+    QemuConsole *con = scon ? scon->dcl.con : NULL;
     int i;
 
     for (i = 0; i < 256; i++) {
         if (modifiers_state[i]) {
             int qcode = sdl2_scancode_to_qcode[i];
-            qemu_input_event_send_key_qcode(NULL, qcode, false);
+            qemu_input_event_send_key_qcode(con, qcode, false);
             modifiers_state[i] = 0;
         }
     }
 }
 
-static void sdl_process_key(SDL_KeyboardEvent *ev)
+static void sdl_process_key(struct sdl2_state *scon,
+                            SDL_KeyboardEvent *ev)
 {
     int qcode = sdl2_scancode_to_qcode[ev->keysym.scancode];
+    QemuConsole *con = scon ? scon->dcl.con : NULL;
+
+    if (!qemu_console_is_graphic(con)) {
+        if (ev->type == SDL_KEYDOWN) {
+            switch (ev->keysym.scancode) {
+            case SDL_SCANCODE_RETURN:
+                kbd_put_keysym_console(con, '\n');
+                break;
+            case SDL_SCANCODE_BACKSPACE:
+                kbd_put_keysym_console(con, QEMU_KEY_BACKSPACE);
+                break;
+            default:
+                kbd_put_qcode_console(con, qcode);
+                break;
+            }
+        }
+        return;
+    }
 
     switch (ev->keysym.scancode) {
 #if 0
     case SDL_SCANCODE_NUMLOCKCLEAR:
     case SDL_SCANCODE_CAPSLOCK:
         /* SDL does not send the key up event, so we generate it */
-        qemu_input_event_send_key_qcode(NULL, qcode, true);
-        qemu_input_event_send_key_qcode(NULL, qcode, false);
+        qemu_input_event_send_key_qcode(con, qcode, true);
+        qemu_input_event_send_key_qcode(con, qcode, false);
         return;
 #endif
     case SDL_SCANCODE_LCTRL:
@@ -231,7 +255,7 @@ static void sdl_process_key(SDL_KeyboardEvent *ev)
         }
         /* fall though */
     default:
-        qemu_input_event_send_key_qcode(NULL, qcode,
+        qemu_input_event_send_key_qcode(con, qcode,
                                         ev->type == SDL_KEYDOWN);
     }
 }
@@ -302,6 +326,11 @@ static void sdl_show_cursor(void)
 
 static void sdl_grab_start(struct sdl2_state *scon)
 {
+    QemuConsole *con = scon ? scon->dcl.con : NULL;
+
+    if (!con || !qemu_console_is_graphic(con)) {
+        return;
+    }
     /*
      * If the application is not active, do not try to enter grab state. This
      * prevents 'SDL_WM_GrabInput(SDL_GRAB_ON)' from blocking all the
@@ -455,7 +484,7 @@ static void toggle_full_screen(struct sdl2_state *scon)
 
 static void handle_keydown(SDL_Event *ev)
 {
-    int mod_state;
+    int mod_state, win;
     struct sdl2_state *scon = get_scon_from_window(ev->key.windowID);
 
     if (alt_grab) {
@@ -470,6 +499,27 @@ static void handle_keydown(SDL_Event *ev)
 
     if (gui_key_modifier_pressed) {
         switch (ev->key.keysym.scancode) {
+        case SDL_SCANCODE_2:
+        case SDL_SCANCODE_3:
+        case SDL_SCANCODE_4:
+        case SDL_SCANCODE_5:
+        case SDL_SCANCODE_6:
+        case SDL_SCANCODE_7:
+        case SDL_SCANCODE_8:
+        case SDL_SCANCODE_9:
+            win = ev->key.keysym.scancode - SDL_SCANCODE_1;
+            if (win < sdl2_num_outputs) {
+                sdl2_console[win].hidden = !sdl2_console[win].hidden;
+                if (sdl2_console[win].real_window) {
+                    if (sdl2_console[win].hidden) {
+                        SDL_HideWindow(sdl2_console[win].real_window);
+                    } else {
+                        SDL_ShowWindow(sdl2_console[win].real_window);
+                    }
+                }
+                gui_keysym = 1;
+            }
+            break;
         case SDL_SCANCODE_F:
             toggle_full_screen(scon);
             gui_keysym = 1;
@@ -506,7 +556,7 @@ static void handle_keydown(SDL_Event *ev)
         }
     }
     if (!gui_keysym) {
-        sdl_process_key(&ev->key);
+        sdl_process_key(scon, &ev->key);
     }
 }
 
@@ -531,16 +581,27 @@ static void handle_keyup(SDL_Event *ev)
             }
             /* SDL does not send back all the modifiers key, so we must
              * correct it. */
-            reset_keys();
+            reset_keys(scon);
             return;
         }
         gui_keysym = 0;
     }
     if (!gui_keysym) {
-        sdl_process_key(&ev->key);
+        sdl_process_key(scon, &ev->key);
     }
 }
 
+static void handle_textinput(SDL_Event *ev)
+{
+    struct sdl2_state *scon = get_scon_from_window(ev->key.windowID);
+    QemuConsole *con = scon ? scon->dcl.con : NULL;
+
+    if (qemu_console_is_graphic(con)) {
+        return;
+    }
+    kbd_put_string_console(con, ev->text.text, strlen(ev->text.text));
+}
+
 static void handle_mousemotion(SDL_Event *ev)
 {
     int max_x, max_y;
@@ -677,6 +738,9 @@ static void sdl_refresh(DisplayChangeListener *dcl)
         case SDL_KEYUP:
             handle_keyup(ev);
             break;
+        case SDL_TEXTINPUT:
+            handle_textinput(ev);
+            break;
         case SDL_QUIT:
             if (!no_quit) {
                 no_shutdown = 0;
@@ -805,7 +869,7 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
 
     for (i = 0;; i++) {
         QemuConsole *con = qemu_console_lookup_by_index(i);
-        if (!con || !qemu_console_is_graphic(con)) {
+        if (!con) {
             break;
         }
     }
@@ -813,6 +877,9 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
     sdl2_console = g_new0(struct sdl2_state, sdl2_num_outputs);
     for (i = 0; i < sdl2_num_outputs; i++) {
         QemuConsole *con = qemu_console_lookup_by_index(i);
+        if (!qemu_console_is_graphic(con)) {
+            sdl2_console[i].hidden = true;
+        }
         sdl2_console[i].dcl.ops = &dcl_ops;
         sdl2_console[i].dcl.con = con;
         register_displaychangelistener(&sdl2_console[i].dcl);
diff --git a/ui/vnc-enc-tight.c b/ui/vnc-enc-tight.c
index 59b59c0c79..f02352cc46 100644
--- a/ui/vnc-enc-tight.c
+++ b/ui/vnc-enc-tight.c
@@ -181,6 +181,10 @@ tight_detect_smooth_image24(VncState *vs, int w, int h)
         }
     }
 
+    if (pixels == 0) {
+        return 0;
+    }
+
     /* 95% smooth or more ... */
     if (stats[0] * 33 / pixels >= 95) {
         return 0;
@@ -267,7 +271,9 @@ tight_detect_smooth_image24(VncState *vs, int w, int h)
                 y += w;                                                 \
             }                                                           \
         }                                                               \
-                                                                        \
+        if (pixels == 0) {                                              \
+            return 0;                                                   \
+        }                                                               \
         if ((stats[0] + stats[1]) * 100 / pixels >= 90) {               \
             return 0;                                                   \
         }                                                               \
diff --git a/ui/vnc.c b/ui/vnc.c
index 2d7def9aa2..1684206184 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -26,6 +26,7 @@
 
 #include "vnc.h"
 #include "vnc-jobs.h"
+#include "trace.h"
 #include "sysemu/sysemu.h"
 #include "qemu/sockets.h"
 #include "qemu/timer.h"
@@ -1552,7 +1553,9 @@ static void press_key(VncState *vs, int keysym)
 {
     int keycode = keysym2scancode(vs->vd->kbd_layout, keysym) & SCANCODE_KEYMASK;
     qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, true);
+    qemu_input_event_send_key_delay(0);
     qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, false);
+    qemu_input_event_send_key_delay(0);
 }
 
 static int current_led_state(VncState *vs)
@@ -1597,6 +1600,10 @@ static void kbd_leds(void *opaque, int ledstate)
     int caps, num, scr;
     bool has_changed = (ledstate != current_led_state(vs));
 
+    trace_vnc_key_guest_leds((ledstate & QEMU_CAPS_LOCK_LED),
+                             (ledstate & QEMU_NUM_LOCK_LED),
+                             (ledstate & QEMU_SCROLL_LOCK_LED));
+
     caps = ledstate & QEMU_CAPS_LOCK_LED ? 1 : 0;
     num  = ledstate & QEMU_NUM_LOCK_LED  ? 1 : 0;
     scr  = ledstate & QEMU_SCROLL_LOCK_LED ? 1 : 0;
@@ -1659,11 +1666,13 @@ static void do_key_event(VncState *vs, int down, int keycode, int sym)
         */
         if (keysym_is_numlock(vs->vd->kbd_layout, sym & 0xFFFF)) {
             if (!vs->modifiers_state[0x45]) {
+                trace_vnc_key_sync_numlock(true);
                 vs->modifiers_state[0x45] = 1;
                 press_key(vs, 0xff7f);
             }
         } else {
             if (vs->modifiers_state[0x45]) {
+                trace_vnc_key_sync_numlock(false);
                 vs->modifiers_state[0x45] = 0;
                 press_key(vs, 0xff7f);
             }
@@ -1682,11 +1691,13 @@ static void do_key_event(VncState *vs, int down, int keycode, int sym)
         int capslock = !!(vs->modifiers_state[0x3a]);
         if (capslock) {
             if (uppercase == shift) {
+                trace_vnc_key_sync_capslock(false);
                 vs->modifiers_state[0x3a] = 0;
                 press_key(vs, 0xffe5);
             }
         } else {
             if (uppercase != shift) {
+                trace_vnc_key_sync_capslock(true);
                 vs->modifiers_state[0x3a] = 1;
                 press_key(vs, 0xffe5);
             }
@@ -1819,6 +1830,11 @@ static void vnc_release_modifiers(VncState *vs)
     }
 }
 
+static const char *code2name(int keycode)
+{
+    return QKeyCode_lookup[qemu_input_key_number_to_qcode(keycode)];
+}
+
 static void key_event(VncState *vs, int down, uint32_t sym)
 {
     int keycode;
@@ -1829,6 +1845,7 @@ static void key_event(VncState *vs, int down, uint32_t sym)
     }
 
     keycode = keysym2scancode(vs->vd->kbd_layout, lsym & 0xFFFF) & SCANCODE_KEYMASK;
+    trace_vnc_key_event_map(down, sym, keycode, code2name(keycode));
     do_key_event(vs, down, keycode, sym);
 }
 
@@ -1836,10 +1853,12 @@ static void ext_key_event(VncState *vs, int down,
                           uint32_t sym, uint16_t keycode)
 {
     /* if the user specifies a keyboard layout, always use it */
-    if (keyboard_layout)
+    if (keyboard_layout) {
         key_event(vs, down, sym);
-    else
+    } else {
+        trace_vnc_key_event_ext(down, sym, keycode, code2name(keycode));
         do_key_event(vs, down, keycode, sym);
+    }
 }
 
 static void framebuffer_update_request(VncState *vs, int incremental,
@@ -2929,10 +2948,12 @@ void vnc_display_init(DisplayState *ds)
     QTAILQ_INIT(&vs->clients);
     vs->expires = TIME_MAX;
 
-    if (keyboard_layout)
+    if (keyboard_layout) {
+        trace_vnc_key_map_init(keyboard_layout);
         vs->kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout);
-    else
+    } else {
         vs->kbd_layout = init_keyboard_layout(name2keysym, "en-us");
+    }
 
     if (!vs->kbd_layout)
         exit(1);
@@ -2976,26 +2997,6 @@ static void vnc_display_close(DisplayState *ds)
 #endif
 }
 
-static int vnc_display_disable_login(DisplayState *ds)
-{
-    VncDisplay *vs = vnc_display;
-
-    if (!vs) {
-        return -1;
-    }
-
-    if (vs->password) {
-        g_free(vs->password);
-    }
-
-    vs->password = NULL;
-    if (vs->auth == VNC_AUTH_NONE) {
-        vs->auth = VNC_AUTH_VNC;
-    }
-
-    return 0;
-}
-
 int vnc_display_password(DisplayState *ds, const char *password)
 {
     VncDisplay *vs = vnc_display;
@@ -3003,20 +3004,18 @@ int vnc_display_password(DisplayState *ds, const char *password)
     if (!vs) {
         return -EINVAL;
     }
-
-    if (!password) {
-        /* This is not the intention of this interface but err on the side
-           of being safe */
-        return vnc_display_disable_login(ds);
+    if (vs->auth == VNC_AUTH_NONE) {
+        error_printf_unless_qmp("If you want use passwords please enable "
+                                "password auth using '-vnc ${dpy},password'.");
+        return -EINVAL;
     }
 
     if (vs->password) {
         g_free(vs->password);
         vs->password = NULL;
     }
-    vs->password = g_strdup(password);
-    if (vs->auth == VNC_AUTH_NONE) {
-        vs->auth = VNC_AUTH_VNC;
+    if (password) {
+        vs->password = g_strdup(password);
     }
 
     return 0;
diff --git a/util/error.c b/util/error.c
index 66245ccd1f..2ace0d8dd9 100644
--- a/util/error.c
+++ b/util/error.c
@@ -142,11 +142,6 @@ Error *error_copy(const Error *err)
     return err_new;
 }
 
-bool error_is_set(Error **errp)
-{
-    return (errp && *errp);
-}
-
 ErrorClass error_get_class(const Error *err)
 {
     return err->err_class;
diff --git a/util/iov.c b/util/iov.c
index 6569b5aae1..49f88388f8 100644
--- a/util/iov.c
+++ b/util/iov.c
@@ -335,6 +335,27 @@ void qemu_iovec_concat(QEMUIOVector *dst,
     qemu_iovec_concat_iov(dst, src->iov, src->niov, soffset, sbytes);
 }
 
+/*
+ * Check if the contents of the iovecs are all zero
+ */
+bool qemu_iovec_is_zero(QEMUIOVector *qiov)
+{
+    int i;
+    for (i = 0; i < qiov->niov; i++) {
+        size_t offs = QEMU_ALIGN_DOWN(qiov->iov[i].iov_len, 4 * sizeof(long));
+        uint8_t *ptr = qiov->iov[i].iov_base;
+        if (offs && !buffer_is_zero(qiov->iov[i].iov_base, offs)) {
+            return false;
+        }
+        for (; offs < qiov->iov[i].iov_len; offs++) {
+            if (ptr[offs]) {
+                return false;
+            }
+        }
+    }
+    return true;
+}
+
 void qemu_iovec_destroy(QEMUIOVector *qiov)
 {
     assert(qiov->nalloc != -1);
diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c
index 8818d7c0de..627e60931a 100644
--- a/util/qemu-sockets.c
+++ b/util/qemu-sockets.c
@@ -354,6 +354,7 @@ static struct addrinfo *inet_parse_connect_opts(QemuOpts *opts, Error **errp)
 int inet_connect_opts(QemuOpts *opts, Error **errp,
                       NonBlockingConnectHandler *callback, void *opaque)
 {
+    Error *local_err = NULL;
     struct addrinfo *res, *e;
     int sock = -1;
     bool in_progress;
@@ -372,24 +373,27 @@ int inet_connect_opts(QemuOpts *opts, Error **errp,
     }
 
     for (e = res; e != NULL; e = e->ai_next) {
-        if (error_is_set(errp)) {
-            error_free(*errp);
-            *errp = NULL;
-        }
+        error_free(local_err);
+        local_err = NULL;
         if (connect_state != NULL) {
             connect_state->current_addr = e;
         }
-        sock = inet_connect_addr(e, &in_progress, connect_state, errp);
-        if (in_progress) {
-            return sock;
-        } else if (sock >= 0) {
-            /* non blocking socket immediate success, call callback */
-            if (callback != NULL) {
-                callback(sock, opaque);
-            }
+        sock = inet_connect_addr(e, &in_progress, connect_state, &local_err);
+        if (sock >= 0) {
             break;
         }
     }
+
+    if (sock < 0) {
+        error_propagate(errp, local_err);
+    } else if (in_progress) {
+        /* wait_for_connect() will do the rest */
+        return sock;
+    } else {
+        if (callback) {
+            callback(sock, opaque);
+        }
+    }
     g_free(connect_state);
     freeaddrinfo(res);
     return sock;
diff --git a/vl.c b/vl.c
index 709d8cda8d..0c15608bcb 100644
--- a/vl.c
+++ b/vl.c
@@ -965,7 +965,7 @@ static int parse_sandbox(QemuOpts *opts, void *opaque)
     return 0;
 }
 
-static void parse_name(QemuOpts *opts)
+static int parse_name(QemuOpts *opts, void *opaque)
 {
     const char *proc_name;
 
@@ -978,6 +978,8 @@ static void parse_name(QemuOpts *opts)
     if (proc_name) {
         os_set_proc_name(proc_name);
     }
+
+    return 0;
 }
 
 bool usb_enabled(bool default_usb)
@@ -2889,7 +2891,8 @@ static int object_set_property(const char *name, const char *value, void *opaque
     StringInputVisitor *siv;
     Error *local_err = NULL;
 
-    if (strcmp(name, "qom-type") == 0 || strcmp(name, "id") == 0) {
+    if (strcmp(name, "qom-type") == 0 || strcmp(name, "id") == 0 ||
+        strcmp(name, "type") == 0) {
         return 0;
     }
 
@@ -3796,7 +3799,6 @@ int main(int argc, char **argv, char **envp)
                 if (!opts) {
                     exit(1);
                 }
-                parse_name(opts);
                 break;
             case QEMU_OPTION_prom_env:
                 if (nb_prom_envs >= MAX_PROM_ENVS) {
@@ -3971,6 +3973,10 @@ int main(int argc, char **argv, char **envp)
         exit(1);
     }
 
+    if (qemu_opts_foreach(qemu_find_opts("name"), parse_name, NULL, 1)) {
+        exit(1);
+    }
+
 #ifndef _WIN32
     if (qemu_opts_foreach(qemu_find_opts("add-fd"), parse_add_fd, NULL, 1)) {
         exit(1);
@@ -4214,6 +4220,13 @@ int main(int argc, char **argv, char **envp)
         exit(0);
     }
 
+    machine_opts = qemu_get_machine_opts();
+    if (qemu_opt_foreach(machine_opts, object_set_property, current_machine,
+                         1) < 0) {
+        object_unref(OBJECT(current_machine));
+        exit(1);
+    }
+
     configure_accelerator(machine_class);
 
     if (qtest_chrdev) {
@@ -4258,6 +4271,7 @@ int main(int argc, char **argv, char **envp)
 
     if (!kernel_cmdline) {
         kernel_cmdline = "";
+        current_machine->kernel_cmdline = (char *)kernel_cmdline;
     }
 
     linux_boot = (kernel_filename != NULL);
@@ -4420,16 +4434,11 @@ int main(int argc, char **argv, char **envp)
 
     qdev_machine_init();
 
-    current_machine->init_args = (QEMUMachineInitArgs) {
-        .machine = machine_class,
-        .ram_size = ram_size,
-        .boot_order = boot_order,
-        .kernel_filename = kernel_filename,
-        .kernel_cmdline = kernel_cmdline,
-        .initrd_filename = initrd_filename,
-        .cpu_model = cpu_model };
+    current_machine->ram_size = ram_size;
+    current_machine->boot_order = boot_order;
+    current_machine->cpu_model = cpu_model;
 
-    machine_class->init(&current_machine->init_args);
+    machine_class->init(current_machine);
 
     audio_init();