summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS12
-rw-r--r--Makefile14
-rw-r--r--Makefile.objs2
-rw-r--r--QMP/qmp-events.txt291
-rw-r--r--QMP/qmp-spec.txt10
-rw-r--r--arch_init.c248
-rw-r--r--arch_init.h1
-rw-r--r--block.c1
-rw-r--r--block.h1
-rw-r--r--block/iscsi.c59
-rw-r--r--block/qcow2-cluster.c5
-rw-r--r--block/qcow2.c139
-rw-r--r--block/qcow2.h21
-rw-r--r--block/qed-check.c26
-rw-r--r--block/qed.c11
-rw-r--r--block/qed.h5
-rw-r--r--block_int.h27
-rw-r--r--blockdev.c1
-rw-r--r--compiler.h1
-rwxr-xr-xconfigure63
-rw-r--r--cpu-exec.c6
-rw-r--r--cpus.c3
-rw-r--r--cutils.c42
-rw-r--r--default-configs/arm-softmmu.mak18
-rw-r--r--default-configs/pci.mak1
-rw-r--r--default-configs/unicore32-softmmu.mak4
-rw-r--r--dma-helpers.c1
-rw-r--r--docs/specs/qcow2.txt14
-rw-r--r--docs/writing-qmp-commands.txt47
-rw-r--r--docs/xbzrle.txt128
-rw-r--r--error.c93
-rw-r--r--error.h34
-rw-r--r--error_int.h29
-rw-r--r--exec-all.h2
-rw-r--r--exec.c2
-rw-r--r--hmp-commands.hx40
-rw-r--r--hmp.c172
-rw-r--r--hmp.h5
-rw-r--r--hw/Makefile.objs29
-rw-r--r--hw/acpi.c2
-rw-r--r--hw/arm/Makefile.objs15
-rw-r--r--hw/armv7m.c5
-rw-r--r--hw/armv7m_nvic.c21
-rw-r--r--hw/esp-pci.c518
-rw-r--r--hw/esp.c487
-rw-r--r--hw/esp.h119
-rw-r--r--hw/ide/ahci.c44
-rw-r--r--hw/ide/internal.h1
-rw-r--r--hw/ide/qdev.c3
-rw-r--r--hw/kvm/i8259.c2
-rw-r--r--hw/kvm/ioapic.c2
-rw-r--r--hw/pc.c1
-rw-r--r--hw/pci-stub.c15
-rw-r--r--hw/petalogix_ml605_mmu.c24
-rw-r--r--hw/puv3.c131
-rw-r--r--hw/puv3.h49
-rw-r--r--hw/puv3_dma.c109
-rw-r--r--hw/puv3_gpio.c141
-rw-r--r--hw/puv3_intc.c135
-rw-r--r--hw/puv3_ost.c151
-rw-r--r--hw/puv3_pm.c149
-rw-r--r--hw/scsi-bus.c1
-rw-r--r--hw/scsi-disk.c115
-rw-r--r--hw/sd.c72
-rw-r--r--hw/sd.h6
-rw-r--r--hw/ssd0323.c4
-rw-r--r--hw/stream.c23
-rw-r--r--hw/stream.h31
-rw-r--r--hw/sun4m.c18
-rw-r--r--hw/unicore32/Makefile.objs6
-rw-r--r--hw/usb/dev-storage.c11
-rw-r--r--hw/virtio-blk.c31
-rw-r--r--hw/virtio-blk.h4
-rw-r--r--hw/virtio-pci.c4
-rw-r--r--hw/virtio-scsi.c10
-rw-r--r--hw/xilinx.h22
-rw-r--r--hw/xilinx_axidma.c74
-rw-r--r--hw/xilinx_axidma.h39
-rw-r--r--hw/xilinx_axienet.c33
-rw-r--r--hw/xtensa_lx60.c6
-rw-r--r--hw/xtensa_sim.c5
-rw-r--r--include/qemu/object.h46
-rw-r--r--include/qemu/page_cache.h79
-rw-r--r--kvm-all.c54
-rw-r--r--kvm-stub.c9
-rw-r--r--kvm.h60
-rw-r--r--linux-user/main.c3
-rw-r--r--linux-user/signal.c8
-rw-r--r--migration-tcp.c22
-rw-r--r--migration.c112
-rw-r--r--migration.h21
-rw-r--r--monitor.c98
-rw-r--r--monitor.h1
-rw-r--r--nbd.c2
-rw-r--r--net/slirp.c6
-rw-r--r--page_cache.c218
-rw-r--r--qapi-schema.json328
-rw-r--r--qapi/qmp-core.h1
-rw-r--r--qapi/qmp-dispatch.c11
-rw-r--r--qemu-char.c2
-rw-r--r--qemu-common.h22
-rw-r--r--qemu-doc.texi5
-rw-r--r--qemu-ga.c5
-rw-r--r--qemu-img.c30
-rw-r--r--qemu-io.c12
-rw-r--r--qemu-options.hx8
-rw-r--r--qemu-sockets.c14
-rw-r--r--qemu-timer.c10
-rw-r--r--qemu-tool.c5
-rw-r--r--qemu_socket.h4
-rw-r--r--qerror.c516
-rw-r--r--qerror.h168
-rw-r--r--qmp-commands.hx182
-rw-r--r--qmp.c56
-rw-r--r--qom/object.c220
-rw-r--r--savevm.c159
-rw-r--r--scripts/qapi-commands.py1
-rw-r--r--scripts/qapi-types.py17
-rw-r--r--scripts/qapi.py16
-rw-r--r--target-arm/arm-semi.c2
-rw-r--r--target-arm/cpu.h2
-rw-r--r--target-arm/helper.c6
-rw-r--r--target-arm/neon_helper.c26
-rw-r--r--target-arm/op_helper.c2
-rw-r--r--target-arm/translate.c12
-rw-r--r--target-i386/Makefile.objs1
-rw-r--r--target-i386/cpu.c32
-rw-r--r--target-i386/cpu.h1
-rw-r--r--target-i386/helper.c16
-rw-r--r--target-i386/kvm-stub.c18
-rw-r--r--target-i386/kvm.c13
-rw-r--r--target-i386/kvm_i386.h16
-rw-r--r--target-mips/translate.c1
-rw-r--r--target-ppc/translate_init.c26
-rw-r--r--target-unicore32/Makefile.objs4
-rw-r--r--target-unicore32/cpu.c19
-rw-r--r--target-unicore32/cpu.h18
-rw-r--r--target-unicore32/helper.c511
-rw-r--r--target-unicore32/helper.h17
-rw-r--r--target-unicore32/machine.c23
-rw-r--r--target-unicore32/op_helper.c44
-rw-r--r--target-unicore32/softmmu.c267
-rw-r--r--target-unicore32/translate.c159
-rw-r--r--target-unicore32/ucf64_helper.c345
-rw-r--r--target-xtensa/cpu.h6
-rw-r--r--target-xtensa/helper.c8
-rw-r--r--tests/qemu-iotests/031.out20
-rw-r--r--tests/qemu-iotests/036.out4
-rwxr-xr-xtests/qemu-iotests/039137
-rw-r--r--tests/qemu-iotests/039.out59
-rw-r--r--tests/qemu-iotests/common.rc33
-rw-r--r--tests/qemu-iotests/group1
-rwxr-xr-xtests/qemu-iotests/qed.py235
-rw-r--r--ui/vnc.c2
-rw-r--r--user-exec.c17
-rw-r--r--vl.c72
156 files changed, 6341 insertions, 2612 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 2d219d2ea0..6d864c1ceb 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -405,6 +405,14 @@ M: Alexander Graf <agraf@suse.de>
 S: Maintained
 F: hw/s390-*.c
 
+UniCore32 Machines
+-------------
+PKUnity-3 SoC initramfs-with-busybox
+M: Guan Xuetao <gxt@mprc.pku.edu.cn>
+S: Maintained
+F: hw/puv3*
+F: hw/unicore32/
+
 X86 Machines
 ------------
 PC
@@ -560,7 +568,7 @@ F: monitor.c
 
 Network device layer
 M: Anthony Liguori <aliguori@us.ibm.com>
-M: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
+M: Stefan Hajnoczi <stefanha@gmail.com>
 S: Maintained
 F: net/
 T: git git://github.com/stefanha/qemu.git net
@@ -580,7 +588,7 @@ F: slirp/
 T: git git://git.kiszka.org/qemu.git queues/slirp
 
 Tracing
-M: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
+M: Stefan Hajnoczi <stefanha@gmail.com>
 S: Maintained
 F: trace/
 F: scripts/tracetool.py
diff --git a/Makefile b/Makefile
index 000b46c379..d736ea5311 100644
--- a/Makefile
+++ b/Makefile
@@ -181,24 +181,26 @@ ifneq ($(wildcard config-host.mak),)
 include $(SRC_PATH)/tests/Makefile
 endif
 
+qapi-py = $(SRC_PATH)/scripts/qapi.py $(SRC_PATH)/scripts/ordereddict.py
+
 qga/qapi-generated/qga-qapi-types.c qga/qapi-generated/qga-qapi-types.h :\
-$(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-types.py
+$(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py)
 	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py $(gen-out-type) -o qga/qapi-generated -p "qga-" < $<, "  GEN   $@")
 qga/qapi-generated/qga-qapi-visit.c qga/qapi-generated/qga-qapi-visit.h :\
-$(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-visit.py
+$(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py)
 	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py $(gen-out-type) -o qga/qapi-generated -p "qga-" < $<, "  GEN   $@")
 qga/qapi-generated/qga-qmp-commands.h qga/qapi-generated/qga-qmp-marshal.c :\
-$(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-commands.py
+$(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py)
 	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -o qga/qapi-generated -p "qga-" < $<, "  GEN   $@")
 
 qapi-types.c qapi-types.h :\
-$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-types.py
+$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py)
 	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py $(gen-out-type) -o "." < $<, "  GEN   $@")
 qapi-visit.c qapi-visit.h :\
-$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-visit.py
+$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py)
 	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py $(gen-out-type) -o "."  < $<, "  GEN   $@")
 qmp-commands.h qmp-marshal.c :\
-$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py
+$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py)
 	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -m -o "." < $<, "  GEN   $@")
 
 QGALIB_GEN=$(addprefix qga/qapi-generated/, qga-qapi-types.h qga-qapi-visit.h qga-qmp-commands.h)
diff --git a/Makefile.objs b/Makefile.objs
index 5ebbcfa171..309d066286 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -77,6 +77,7 @@ common-obj-y += qemu-char.o #aio.o
 common-obj-y += block-migration.o iohandler.o
 common-obj-y += pflib.o
 common-obj-y += bitmap.o bitops.o
+common-obj-y += page_cache.o
 
 common-obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o migration-fd.o
 common-obj-$(CONFIG_WIN32) += version.o
@@ -211,6 +212,7 @@ common-obj-$(CONFIG_SMARTCARD_NSS) += $(libcacard-y)
 # qapi
 
 qapi-obj-y = qapi/
+qapi-obj-y += qapi-types.o qapi-visit.o
 
 common-obj-y += qmp-marshal.o qapi-visit.o qapi-types.o
 common-obj-y += qmp.o hmp.o
diff --git a/QMP/qmp-events.txt b/QMP/qmp-events.txt
index 9ba7079589..287805825f 100644
--- a/QMP/qmp-events.txt
+++ b/QMP/qmp-events.txt
@@ -1,6 +1,23 @@
                    QEMU Monitor Protocol Events
                    ============================
 
+BALLOON_CHANGE
+--------------
+
+Emitted when the guest changes the actual BALLOON level. This
+value is equivalent to the 'actual' field return by the
+'query-balloon' command
+
+Data:
+
+- "actual": actual level of the guest memory balloon in bytes (json-number)
+
+Example:
+
+{ "event": "BALLOON_CHANGE",
+    "data": { "actual": 944766976 },
+    "timestamp": { "seconds": 1267020223, "microseconds": 435656 } }
+
 BLOCK_IO_ERROR
 --------------
 
@@ -26,6 +43,57 @@ Example:
 Note: If action is "stop", a STOP event will eventually follow the
 BLOCK_IO_ERROR event.
 
+BLOCK_JOB_CANCELLED
+-------------------
+
+Emitted when a block job has been cancelled.
+
+Data:
+
+- "type":     Job type ("stream" for image streaming, json-string)
+- "device":   Device name (json-string)
+- "len":      Maximum progress value (json-int)
+- "offset":   Current progress value (json-int)
+              On success this is equal to len.
+              On failure this is less than len.
+- "speed":    Rate limit, bytes per second (json-int)
+
+Example:
+
+{ "event": "BLOCK_JOB_CANCELLED",
+     "data": { "type": "stream", "device": "virtio-disk0",
+               "len": 10737418240, "offset": 134217728,
+               "speed": 0 },
+     "timestamp": { "seconds": 1267061043, "microseconds": 959568 } }
+
+BLOCK_JOB_COMPLETED
+-------------------
+
+Emitted when a block job has completed.
+
+Data:
+
+- "type":     Job type ("stream" for image streaming, json-string)
+- "device":   Device name (json-string)
+- "len":      Maximum progress value (json-int)
+- "offset":   Current progress value (json-int)
+              On success this is equal to len.
+              On failure this is less than len.
+- "speed":    Rate limit, bytes per second (json-int)
+- "error":    Error message (json-string, optional)
+              Only present on failure.  This field contains a human-readable
+              error message.  There are no semantics other than that streaming
+              has failed and clients should not try to interpret the error
+              string.
+
+Example:
+
+{ "event": "BLOCK_JOB_COMPLETED",
+     "data": { "type": "stream", "device": "virtio-disk0",
+               "len": 10737418240, "offset": 10737418240,
+               "speed": 0 },
+     "timestamp": { "seconds": 1267061043, "microseconds": 959568 } }
+
 DEVICE_TRAY_MOVED
 -----------------
 
@@ -98,6 +166,68 @@ Example:
 Note: If the command-line option "-no-shutdown" has been specified, a STOP
 event will eventually follow the SHUTDOWN event.
 
+SPICE_CONNECTED, SPICE_DISCONNECTED
+-----------------------------------
+
+Emitted when a SPICE client connects or disconnects.
+
+Data:
+
+- "server": Server information (json-object)
+  - "host": IP address (json-string)
+  - "port": port number (json-string)
+  - "family": address family (json-string, "ipv4" or "ipv6")
+- "client": Client information (json-object)
+  - "host": IP address (json-string)
+  - "port": port number (json-string)
+  - "family": address family (json-string, "ipv4" or "ipv6")
+
+Example:
+
+{ "timestamp": {"seconds": 1290688046, "microseconds": 388707},
+  "event": "SPICE_CONNECTED",
+  "data": {
+    "server": { "port": "5920", "family": "ipv4", "host": "127.0.0.1"},
+    "client": {"port": "52873", "family": "ipv4", "host": "127.0.0.1"}
+}}
+
+SPICE_INITIALIZED
+-----------------
+
+Emitted after initial handshake and authentication takes place (if any)
+and the SPICE channel is up'n'running
+
+Data:
+
+- "server": Server information (json-object)
+  - "host": IP address (json-string)
+  - "port": port number (json-string)
+  - "family": address family (json-string, "ipv4" or "ipv6")
+  - "auth": authentication method (json-string, optional)
+- "client": Client information (json-object)
+  - "host": IP address (json-string)
+  - "port": port number (json-string)
+  - "family": address family (json-string, "ipv4" or "ipv6")
+  - "connection-id": spice connection id.  All channels with the same id
+                     belong to the same spice session (json-int)
+  - "channel-type": channel type.  "1" is the main control channel, filter for
+                    this one if you want track spice sessions only (json-int)
+  - "channel-id": channel id.  Usually "0", might be different needed when
+                  multiple channels of the same type exist, such as multiple
+                  display channels in a multihead setup (json-int)
+  - "tls": whevener the channel is encrypted (json-bool)
+
+Example:
+
+{ "timestamp": {"seconds": 1290688046, "microseconds": 417172},
+  "event": "SPICE_INITIALIZED",
+  "data": {"server": {"auth": "spice", "port": "5921",
+                      "family": "ipv4", "host": "127.0.0.1"},
+           "client": {"port": "49004", "family": "ipv4", "channel-type": 3,
+                      "connection-id": 1804289383, "host": "127.0.0.1",
+                      "channel-id": 0, "tls": true}
+}}
+
 STOP
 ----
 
@@ -110,6 +240,32 @@ Example:
 { "event": "STOP",
     "timestamp": { "seconds": 1267041730, "microseconds": 281295 } }
 
+SUSPEND
+-------
+
+Emitted when guest enters S3 state.
+
+Data: None.
+
+Example:
+
+{ "event": "SUSPEND",
+     "timestamp": { "seconds": 1344456160, "microseconds": 309119 } }
+
+SUSPEND_DISK
+------------
+
+Emitted when the guest makes a request to enter S4 state.
+
+Data: None.
+
+Example:
+
+{ "event": "SUSPEND_DISK",
+     "timestamp": { "seconds": 1344456160, "microseconds": 309119 } }
+
+Note: QEMU shuts down when entering S4 state.
+
 VNC_CONNECTED
 -------------
 
@@ -200,69 +356,17 @@ Example:
                     "host": "127.0.0.1", "sasl_username": "luiz" } },
         "timestamp": { "seconds": 1263475302, "microseconds": 150772 } }
 
-SPICE_CONNECTED, SPICE_DISCONNECTED
------------------------------------
-
-Emitted when a SPICE client connects or disconnects.
-
-Data:
-
-- "server": Server information (json-object)
-  - "host": IP address (json-string)
-  - "port": port number (json-string)
-  - "family": address family (json-string, "ipv4" or "ipv6")
-- "client": Client information (json-object)
-  - "host": IP address (json-string)
-  - "port": port number (json-string)
-  - "family": address family (json-string, "ipv4" or "ipv6")
-
-Example:
-
-{ "timestamp": {"seconds": 1290688046, "microseconds": 388707},
-  "event": "SPICE_CONNECTED",
-  "data": {
-    "server": { "port": "5920", "family": "ipv4", "host": "127.0.0.1"},
-    "client": {"port": "52873", "family": "ipv4", "host": "127.0.0.1"}
-}}
-
-
-SPICE_INITIALIZED
------------------
-
-Emitted after initial handshake and authentication takes place (if any)
-and the SPICE channel is up'n'running
+WAKEUP
+------
 
-Data:
+Emitted when the guest has woken up from S3 and is running.
 
-- "server": Server information (json-object)
-  - "host": IP address (json-string)
-  - "port": port number (json-string)
-  - "family": address family (json-string, "ipv4" or "ipv6")
-  - "auth": authentication method (json-string, optional)
-- "client": Client information (json-object)
-  - "host": IP address (json-string)
-  - "port": port number (json-string)
-  - "family": address family (json-string, "ipv4" or "ipv6")
-  - "connection-id": spice connection id.  All channels with the same id
-                     belong to the same spice session (json-int)
-  - "channel-type": channel type.  "1" is the main control channel, filter for
-                    this one if you want track spice sessions only (json-int)
-  - "channel-id": channel id.  Usually "0", might be different needed when
-                  multiple channels of the same type exist, such as multiple
-                  display channels in a multihead setup (json-int)
-  - "tls": whevener the channel is encrypted (json-bool)
+Data: None.
 
 Example:
 
-{ "timestamp": {"seconds": 1290688046, "microseconds": 417172},
-  "event": "SPICE_INITIALIZED",
-  "data": {"server": {"auth": "spice", "port": "5921",
-                      "family": "ipv4", "host": "127.0.0.1"},
-           "client": {"port": "49004", "family": "ipv4", "channel-type": 3,
-                      "connection-id": 1804289383, "host": "127.0.0.1",
-                      "channel-id": 0, "tls": true}
-}}
-
+{ "event": "WATCHDOG",
+     "timestamp": { "seconds": 1344522075, "microseconds": 745528 } }
 
 WATCHDOG
 --------
@@ -282,74 +386,3 @@ Example:
 
 Note: If action is "reset", "shutdown", or "pause" the WATCHDOG event is
 followed respectively by the RESET, SHUTDOWN, or STOP events.
-
-
-BLOCK_JOB_COMPLETED
--------------------
-
-Emitted when a block job has completed.
-
-Data:
-
-- "type":     Job type ("stream" for image streaming, json-string)
-- "device":   Device name (json-string)
-- "len":      Maximum progress value (json-int)
-- "offset":   Current progress value (json-int)
-              On success this is equal to len.
-              On failure this is less than len.
-- "speed":    Rate limit, bytes per second (json-int)
-- "error":    Error message (json-string, optional)
-              Only present on failure.  This field contains a human-readable
-              error message.  There are no semantics other than that streaming
-              has failed and clients should not try to interpret the error
-              string.
-
-Example:
-
-{ "event": "BLOCK_JOB_COMPLETED",
-     "data": { "type": "stream", "device": "virtio-disk0",
-               "len": 10737418240, "offset": 10737418240,
-               "speed": 0 },
-     "timestamp": { "seconds": 1267061043, "microseconds": 959568 } }
-
-
-BLOCK_JOB_CANCELLED
--------------------
-
-Emitted when a block job has been cancelled.
-
-Data:
-
-- "type":     Job type ("stream" for image streaming, json-string)
-- "device":   Device name (json-string)
-- "len":      Maximum progress value (json-int)
-- "offset":   Current progress value (json-int)
-              On success this is equal to len.
-              On failure this is less than len.
-- "speed":    Rate limit, bytes per second (json-int)
-
-Example:
-
-{ "event": "BLOCK_JOB_CANCELLED",
-     "data": { "type": "stream", "device": "virtio-disk0",
-               "len": 10737418240, "offset": 134217728,
-               "speed": 0 },
-     "timestamp": { "seconds": 1267061043, "microseconds": 959568 } }
-
-
-BALLOON_CHANGE
-----------
-
-Emitted when the guest changes the actual BALLOON level. This
-value is equivalent to the 'actual' field return by the
-'query-balloon' command
-
-Data:
-
-- "actual": actual level of the guest memory balloon in bytes (json-number)
-
-Example:
-
-{ "event": "BALLOON_CHANGE",
-    "data": { "actual": 944766976 },
-    "timestamp": { "seconds": 1267020223, "microseconds": 435656 } }
diff --git a/QMP/qmp-spec.txt b/QMP/qmp-spec.txt
index 1ba916c9f2..a27789692b 100644
--- a/QMP/qmp-spec.txt
+++ b/QMP/qmp-spec.txt
@@ -106,14 +106,11 @@ completed because of an error condition.
 
 The format is:
 
-{ "error": { "class": json-string, "data": json-object, "desc": json-string },
-  "id": json-value }
+{ "error": { "class": json-string, "desc": json-string }, "id": json-value }
 
  Where,
 
-- The "class" member contains the error class name (eg. "ServiceUnavailable")
-- The "data" member contains specific error data and is defined in a
-  per-command basis, it will be an empty json-object if the error has no data
+- The "class" member contains the error class name (eg. "GenericError")
 - The "desc" member is a human-readable error message. Clients should
   not attempt to parse this message.
 - The "id" member contains the transaction identification associated with
@@ -173,8 +170,7 @@ S: {"return": {"enabled": true, "present": true}, "id": "example"}
 ------------------
 
 C: { "execute": }
-S: {"error": {"class": "JSONParsing", "desc": "Invalid JSON syntax", "data":
-{}}}
+S: {"error": {"class": "GenericError", "desc": "Invalid JSON syntax" } }
 
 3.5 Powerdown event
 -------------------
diff --git a/arch_init.c b/arch_init.c
index 60823baabd..9b46bfcaa5 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -43,6 +43,7 @@
 #include "hw/smbios.h"
 #include "exec-memory.h"
 #include "hw/pcspk.h"
+#include "qemu/page_cache.h"
 
 #ifdef DEBUG_ARCH_INIT
 #define DPRINTF(fmt, ...) \
@@ -91,6 +92,8 @@ int graphic_depth = 15;
 #define QEMU_ARCH QEMU_ARCH_SPARC
 #elif defined(TARGET_XTENSA)
 #define QEMU_ARCH QEMU_ARCH_XTENSA
+#elif defined(TARGET_UNICORE32)
+#define QEMU_ARCH QEMU_ARCH_UNICORE32
 #endif
 
 const uint32_t arch_type = QEMU_ARCH;
@@ -104,6 +107,7 @@ const uint32_t arch_type = QEMU_ARCH;
 #define RAM_SAVE_FLAG_PAGE     0x08
 #define RAM_SAVE_FLAG_EOS      0x10
 #define RAM_SAVE_FLAG_CONTINUE 0x20
+#define RAM_SAVE_FLAG_XBZRLE   0x40
 
 #ifdef __ALTIVEC__
 #include <altivec.h>
@@ -171,6 +175,92 @@ static int is_dup_page(uint8_t *page)
     return 1;
 }
 
+/* struct contains XBZRLE cache and a static page
+   used by the compression */
+static struct {
+    /* buffer used for XBZRLE encoding */
+    uint8_t *encoded_buf;
+    /* buffer for storing page content */
+    uint8_t *current_buf;
+    /* buffer used for XBZRLE decoding */
+    uint8_t *decoded_buf;
+    /* Cache for XBZRLE */
+    PageCache *cache;
+} XBZRLE = {
+    .encoded_buf = NULL,
+    .current_buf = NULL,
+    .decoded_buf = NULL,
+    .cache = NULL,
+};
+
+
+int64_t xbzrle_cache_resize(int64_t new_size)
+{
+    if (XBZRLE.cache != NULL) {
+        return cache_resize(XBZRLE.cache, new_size / TARGET_PAGE_SIZE) *
+            TARGET_PAGE_SIZE;
+    }
+    return pow2floor(new_size);
+}
+
+/* accounting for migration statistics */
+typedef struct AccountingInfo {
+    uint64_t dup_pages;
+    uint64_t norm_pages;
+    uint64_t iterations;
+    uint64_t xbzrle_bytes;
+    uint64_t xbzrle_pages;
+    uint64_t xbzrle_cache_miss;
+    uint64_t xbzrle_overflows;
+} AccountingInfo;
+
+static AccountingInfo acct_info;
+
+static void acct_clear(void)
+{
+    memset(&acct_info, 0, sizeof(acct_info));
+}
+
+uint64_t dup_mig_bytes_transferred(void)
+{
+    return acct_info.dup_pages * TARGET_PAGE_SIZE;
+}
+
+uint64_t dup_mig_pages_transferred(void)
+{
+    return acct_info.dup_pages;
+}
+
+uint64_t norm_mig_bytes_transferred(void)
+{
+    return acct_info.norm_pages * TARGET_PAGE_SIZE;
+}
+
+uint64_t norm_mig_pages_transferred(void)
+{
+    return acct_info.norm_pages;
+}
+
+uint64_t xbzrle_mig_bytes_transferred(void)
+{
+    return acct_info.xbzrle_bytes;
+}
+
+uint64_t xbzrle_mig_pages_transferred(void)
+{
+    return acct_info.xbzrle_pages;
+}
+
+uint64_t xbzrle_mig_pages_cache_miss(void)
+{
+    return acct_info.xbzrle_cache_miss;
+}
+
+uint64_t xbzrle_mig_pages_overflow(void)
+{
+    return acct_info.xbzrle_overflows;
+}
+
 static void save_block_hdr(QEMUFile *f, RAMBlock *block, ram_addr_t offset,
         int cont, int flag)
 {
@@ -183,6 +273,61 @@ static void save_block_hdr(QEMUFile *f, RAMBlock *block, ram_addr_t offset,
 
 }
 
+#define ENCODING_FLAG_XBZRLE 0x1
+
+static int save_xbzrle_page(QEMUFile *f, uint8_t *current_data,
+                            ram_addr_t current_addr, RAMBlock *block,
+                            ram_addr_t offset, int cont, bool last_stage)
+{
+    int encoded_len = 0, bytes_sent = -1;
+    uint8_t *prev_cached_page;
+
+    if (!cache_is_cached(XBZRLE.cache, current_addr)) {
+        if (!last_stage) {
+            cache_insert(XBZRLE.cache, current_addr,
+                         g_memdup(current_data, TARGET_PAGE_SIZE));
+        }
+        acct_info.xbzrle_cache_miss++;
+        return -1;
+    }
+
+    prev_cached_page = get_cached_data(XBZRLE.cache, current_addr);
+
+    /* save current buffer into memory */
+    memcpy(XBZRLE.current_buf, current_data, TARGET_PAGE_SIZE);
+
+    /* XBZRLE encoding (if there is no overflow) */
+    encoded_len = xbzrle_encode_buffer(prev_cached_page, XBZRLE.current_buf,
+                                       TARGET_PAGE_SIZE, XBZRLE.encoded_buf,
+                                       TARGET_PAGE_SIZE);
+    if (encoded_len == 0) {
+        DPRINTF("Skipping unmodified page\n");
+        return 0;
+    } else if (encoded_len == -1) {
+        DPRINTF("Overflow\n");
+        acct_info.xbzrle_overflows++;
+        /* update data in the cache */
+        memcpy(prev_cached_page, current_data, TARGET_PAGE_SIZE);
+        return -1;
+    }
+
+    /* we need to update the data in the cache, in order to get the same data */
+    if (!last_stage) {
+        memcpy(prev_cached_page, XBZRLE.current_buf, TARGET_PAGE_SIZE);
+    }
+
+    /* Send XBZRLE based compressed page */
+    save_block_hdr(f, block, offset, cont, RAM_SAVE_FLAG_XBZRLE);
+    qemu_put_byte(f, ENCODING_FLAG_XBZRLE);
+    qemu_put_be16(f, encoded_len);
+    qemu_put_buffer(f, XBZRLE.encoded_buf, encoded_len);
+    bytes_sent = encoded_len + 1 + 2;
+    acct_info.xbzrle_pages++;
+    acct_info.xbzrle_bytes += bytes_sent;
+
+    return bytes_sent;
+}
+
 static RAMBlock *last_block;
 static ram_addr_t last_offset;
 
@@ -194,12 +339,13 @@ static ram_addr_t last_offset;
  *           n: the amount of bytes written in other case
  */
 
-static int ram_save_block(QEMUFile *f)
+static int ram_save_block(QEMUFile *f, bool last_stage)
 {
     RAMBlock *block = last_block;
     ram_addr_t offset = last_offset;
     int bytes_sent = -1;
     MemoryRegion *mr;
+    ram_addr_t current_addr;
 
     if (!block)
         block = QLIST_FIRST(&ram_list.blocks);
@@ -217,16 +363,31 @@ static int ram_save_block(QEMUFile *f)
             p = memory_region_get_ram_ptr(mr) + offset;
 
             if (is_dup_page(p)) {
+                acct_info.dup_pages++;
                 save_block_hdr(f, block, offset, cont, RAM_SAVE_FLAG_COMPRESS);
                 qemu_put_byte(f, *p);
                 bytes_sent = 1;
-            } else {
+            } else if (migrate_use_xbzrle()) {
+                current_addr = block->offset + offset;
+                bytes_sent = save_xbzrle_page(f, p, current_addr, block,
+                                              offset, cont, last_stage);
+                if (!last_stage) {
+                    p = get_cached_data(XBZRLE.cache, current_addr);
+                }
+            }
+
+            /* either we didn't send yet (we may have had XBZRLE overflow) */
+            if (bytes_sent == -1) {
                 save_block_hdr(f, block, offset, cont, RAM_SAVE_FLAG_PAGE);
                 qemu_put_buffer(f, p, TARGET_PAGE_SIZE);
                 bytes_sent = TARGET_PAGE_SIZE;
+                acct_info.norm_pages++;
             }
 
-            break;
+            /* if page is unmodified, continue to the next */
+            if (bytes_sent != 0) {
+                break;
+            }
         }
 
         offset += TARGET_PAGE_SIZE;
@@ -304,6 +465,15 @@ static void sort_ram_list(void)
 static void migration_end(void)
 {
     memory_global_dirty_log_stop();
+
+    if (migrate_use_xbzrle()) {
+        cache_fini(XBZRLE.cache);
+        g_free(XBZRLE.cache);
+        g_free(XBZRLE.encoded_buf);
+        g_free(XBZRLE.current_buf);
+        g_free(XBZRLE.decoded_buf);
+        XBZRLE.cache = NULL;
+    }
 }
 
 static void ram_migration_cancel(void *opaque)
@@ -323,6 +493,19 @@ static int ram_save_setup(QEMUFile *f, void *opaque)
     last_offset = 0;
     sort_ram_list();
 
+    if (migrate_use_xbzrle()) {
+        XBZRLE.cache = cache_init(migrate_xbzrle_cache_size() /
+                                  TARGET_PAGE_SIZE,
+                                  TARGET_PAGE_SIZE);
+        if (!XBZRLE.cache) {
+            DPRINTF("Error creating cache\n");
+            return -1;
+        }
+        XBZRLE.encoded_buf = g_malloc0(TARGET_PAGE_SIZE);
+        XBZRLE.current_buf = g_malloc(TARGET_PAGE_SIZE);
+        acct_clear();
+    }
+
     /* Make sure all dirty bits are set */
     QLIST_FOREACH(block, &ram_list.blocks, next) {
         for (addr = 0; addr < block->length; addr += TARGET_PAGE_SIZE) {
@@ -363,12 +546,13 @@ static int ram_save_iterate(QEMUFile *f, void *opaque)
     while ((ret = qemu_file_rate_limit(f)) == 0) {
         int bytes_sent;
 
-        bytes_sent = ram_save_block(f);
+        bytes_sent = ram_save_block(f, false);
         /* no more blocks to sent */
         if (bytes_sent < 0) {
             break;
         }
         bytes_transferred += bytes_sent;
+        acct_info.iterations++;
         /* we want to check in the 1st loop, just in case it was the 1st time
            and we had to sync the dirty bitmap.
            qemu_get_clock_ns() is a bit expensive, so we only check each some
@@ -424,7 +608,7 @@ static int ram_save_complete(QEMUFile *f, void *opaque)
     while (true) {
         int bytes_sent;
 
-        bytes_sent = ram_save_block(f);
+        bytes_sent = ram_save_block(f, true);
         /* no more blocks to sent */
         if (bytes_sent < 0) {
             break;
@@ -438,6 +622,47 @@ static int ram_save_complete(QEMUFile *f, void *opaque)
     return 0;
 }
 
+static int load_xbzrle(QEMUFile *f, ram_addr_t addr, void *host)
+{
+    int ret, rc = 0;
+    unsigned int xh_len;
+    int xh_flags;
+
+    if (!XBZRLE.decoded_buf) {
+        XBZRLE.decoded_buf = g_malloc(TARGET_PAGE_SIZE);
+    }
+
+    /* extract RLE header */
+    xh_flags = qemu_get_byte(f);
+    xh_len = qemu_get_be16(f);
+
+    if (xh_flags != ENCODING_FLAG_XBZRLE) {
+        fprintf(stderr, "Failed to load XBZRLE page - wrong compression!\n");
+        return -1;
+    }
+
+    if (xh_len > TARGET_PAGE_SIZE) {
+        fprintf(stderr, "Failed to load XBZRLE page - len overflow!\n");
+        return -1;
+    }
+    /* load data and decode */
+    qemu_get_buffer(f, XBZRLE.decoded_buf, xh_len);
+
+    /* decode RLE */
+    ret = xbzrle_decode_buffer(XBZRLE.decoded_buf, xh_len, host,
+                               TARGET_PAGE_SIZE);
+    if (ret == -1) {
+        fprintf(stderr, "Failed to load XBZRLE page - decode error!\n");
+        rc = -1;
+    } else  if (ret > TARGET_PAGE_SIZE) {
+        fprintf(stderr, "Failed to load XBZRLE page - size %d exceeds %d!\n",
+                ret, TARGET_PAGE_SIZE);
+        abort();
+    }
+
+    return rc;
+}
+
 static inline void *host_from_stream_offset(QEMUFile *f,
                                             ram_addr_t offset,
                                             int flags)
@@ -551,6 +776,19 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
             }
 
             qemu_get_buffer(f, host, TARGET_PAGE_SIZE);
+        } else if (flags & RAM_SAVE_FLAG_XBZRLE) {
+            if (!migrate_use_xbzrle()) {
+                return -EINVAL;
+            }
+            void *host = host_from_stream_offset(f, addr, flags);
+            if (!host) {
+                return -EINVAL;
+            }
+
+            if (load_xbzrle(f, addr, host) < 0) {
+                ret = -EINVAL;
+                goto done;
+            }
         }
         error = qemu_file_get_error(f);
         if (error) {
diff --git a/arch_init.h b/arch_init.h
index 3dfea3b4f3..547f93cd1d 100644
--- a/arch_init.h
+++ b/arch_init.h
@@ -17,6 +17,7 @@ enum {
     QEMU_ARCH_SPARC = 2048,
     QEMU_ARCH_XTENSA = 4096,
     QEMU_ARCH_OPENRISC = 8192,
+    QEMU_ARCH_UNICORE32 = 0x4000,
 };
 
 extern const uint32_t arch_type;
diff --git a/block.c b/block.c
index 24323c11d0..016858bf8c 100644
--- a/block.c
+++ b/block.c
@@ -2445,6 +2445,7 @@ BlockInfoList *qmp_query_block(Error **errp)
             info->value->inserted->ro = bs->read_only;
             info->value->inserted->drv = g_strdup(bs->drv->format_name);
             info->value->inserted->encrypted = bs->encrypted;
+            info->value->inserted->encryption_key_missing = bdrv_key_required(bs);
             if (bs->backing_file[0]) {
                 info->value->inserted->has_backing_file = true;
                 info->value->inserted->backing_file = g_strdup(bs->backing_file);
diff --git a/block.h b/block.h
index 650d872f46..2e2be11071 100644
--- a/block.h
+++ b/block.h
@@ -79,6 +79,7 @@ typedef struct BlockDevOps {
 #define BDRV_O_NO_FLUSH    0x0200 /* disable flushing on this disk */
 #define BDRV_O_COPY_ON_READ 0x0400 /* copy read backing sectors into image */
 #define BDRV_O_INCOMING    0x0800  /* consistency hint for incoming migration */
+#define BDRV_O_CHECK       0x1000  /* open solely for consistency check */
 
 #define BDRV_O_CACHE_MASK  (BDRV_O_NOCACHE | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH)
 
diff --git a/block/iscsi.c b/block/iscsi.c
index 993a86d829..219f927823 100644
--- a/block/iscsi.c
+++ b/block/iscsi.c
@@ -896,26 +896,26 @@ static char *parse_initiator_name(const char *target)
     QemuOptsList *list;
     QemuOpts *opts;
     const char *name = NULL;
+    const char *iscsi_name = qemu_get_vm_name();
 
     list = qemu_find_opts("iscsi");
-    if (!list) {
-        return g_strdup("iqn.2008-11.org.linux-kvm");
-    }
-
-    opts = qemu_opts_find(list, target);
-    if (opts == NULL) {
-        opts = QTAILQ_FIRST(&list->head);
+    if (list) {
+        opts = qemu_opts_find(list, target);
         if (!opts) {
-            return g_strdup("iqn.2008-11.org.linux-kvm");
+            opts = QTAILQ_FIRST(&list->head);
+        }
+        if (opts) {
+            name = qemu_opt_get(opts, "initiator-name");
         }
     }
 
-    name = qemu_opt_get(opts, "initiator-name");
-    if (!name) {
-        return g_strdup("iqn.2008-11.org.linux-kvm");
+    if (name) {
+        return g_strdup(name);
+    } else {
+        return g_strdup_printf("iqn.2008-11.org.linux-kvm%s%s",
+                               iscsi_name ? ":" : "",
+                               iscsi_name ? iscsi_name : "");
     }
-
-    return g_strdup(name);
 }
 
 /*
@@ -943,7 +943,7 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)
         error_report("Failed to parse URL : %s %s", filename,
                      iscsi_get_error(iscsi));
         ret = -EINVAL;
-        goto failed;
+        goto out;
     }
 
     memset(iscsilun, 0, sizeof(IscsiLun));
@@ -954,13 +954,13 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)
     if (iscsi == NULL) {
         error_report("iSCSI: Failed to create iSCSI context.");
         ret = -ENOMEM;
-        goto failed;
+        goto out;
     }
 
     if (iscsi_set_targetname(iscsi, iscsi_url->target)) {
         error_report("iSCSI: Failed to set target name.");
         ret = -EINVAL;
-        goto failed;
+        goto out;
     }
 
     if (iscsi_url->user != NULL) {
@@ -969,7 +969,7 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)
         if (ret != 0) {
             error_report("Failed to set initiator username and password");
             ret = -EINVAL;
-            goto failed;
+            goto out;
         }
     }
 
@@ -977,13 +977,13 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)
     if (parse_chap(iscsi, iscsi_url->target) != 0) {
         error_report("iSCSI: Failed to set CHAP user/password");
         ret = -EINVAL;
-        goto failed;
+        goto out;
     }
 
     if (iscsi_set_session_type(iscsi, ISCSI_SESSION_NORMAL) != 0) {
         error_report("iSCSI: Failed to set session type to normal.");
         ret = -EINVAL;
-        goto failed;
+        goto out;
     }
 
     iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C);
@@ -1004,7 +1004,7 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)
         != 0) {
         error_report("iSCSI: Failed to start async connect.");
         ret = -EINVAL;
-        goto failed;
+        goto out;
     }
 
     while (!task.complete) {
@@ -1015,11 +1015,7 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)
         error_report("iSCSI: Failed to connect to LUN : %s",
                      iscsi_get_error(iscsi));
         ret = -EINVAL;
-        goto failed;
-    }
-
-    if (iscsi_url != NULL) {
-        iscsi_destroy_url(iscsi_url);
+        goto out;
     }
 
     /* Medium changer or tape. We dont have any emulation for this so this must
@@ -1031,19 +1027,22 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)
         bs->sg = 1;
     }
 
-    return 0;
+    ret = 0;
 
-failed:
+out:
     if (initiator_name != NULL) {
         g_free(initiator_name);
     }
     if (iscsi_url != NULL) {
         iscsi_destroy_url(iscsi_url);
     }
-    if (iscsi != NULL) {
-        iscsi_destroy_context(iscsi);
+
+    if (ret) {
+        if (iscsi != NULL) {
+            iscsi_destroy_context(iscsi);
+        }
+        memset(iscsilun, 0, sizeof(IscsiLun));
     }
-    memset(iscsilun, 0, sizeof(IscsiLun));
     return ret;
 }
 
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index d7e0e19d9c..e179211c57 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -662,7 +662,10 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
         qcow2_cache_depends_on_flush(s->l2_table_cache);
     }
 
-    qcow2_cache_set_dependency(bs, s->l2_table_cache, s->refcount_block_cache);
+    if (qcow2_need_accurate_refcounts(s)) {
+        qcow2_cache_set_dependency(bs, s->l2_table_cache,
+                                   s->refcount_block_cache);
+    }
     ret = get_cluster_table(bs, m->offset, &l2_table, &l2_index);
     if (ret < 0) {
         goto err;
diff --git a/block/qcow2.c b/block/qcow2.c
index 870148ddf8..8f183f1465 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -214,6 +214,76 @@ static void report_unsupported_feature(BlockDriverState *bs,
     }
 }
 
+/*
+ * Sets the dirty bit and flushes afterwards if necessary.
+ *
+ * The incompatible_features bit is only set if the image file header was
+ * updated successfully.  Therefore it is not required to check the return
+ * value of this function.
+ */
+static int qcow2_mark_dirty(BlockDriverState *bs)
+{
+    BDRVQcowState *s = bs->opaque;
+    uint64_t val;
+    int ret;
+
+    assert(s->qcow_version >= 3);
+
+    if (s->incompatible_features & QCOW2_INCOMPAT_DIRTY) {
+        return 0; /* already dirty */
+    }
+
+    val = cpu_to_be64(s->incompatible_features | QCOW2_INCOMPAT_DIRTY);
+    ret = bdrv_pwrite(bs->file, offsetof(QCowHeader, incompatible_features),
+                      &val, sizeof(val));
+    if (ret < 0) {
+        return ret;
+    }
+    ret = bdrv_flush(bs->file);
+    if (ret < 0) {
+        return ret;
+    }
+
+    /* Only treat image as dirty if the header was updated successfully */
+    s->incompatible_features |= QCOW2_INCOMPAT_DIRTY;
+    return 0;
+}
+
+/*
+ * Clears the dirty bit and flushes before if necessary.  Only call this
+ * function when there are no pending requests, it does not guard against
+ * concurrent requests dirtying the image.
+ */
+static int qcow2_mark_clean(BlockDriverState *bs)
+{
+    BDRVQcowState *s = bs->opaque;
+
+    if (s->incompatible_features & QCOW2_INCOMPAT_DIRTY) {
+        int ret = bdrv_flush(bs);
+        if (ret < 0) {
+            return ret;
+        }
+
+        s->incompatible_features &= ~QCOW2_INCOMPAT_DIRTY;
+        return qcow2_update_header(bs);
+    }
+    return 0;
+}
+
+static int qcow2_check(BlockDriverState *bs, BdrvCheckResult *result,
+                       BdrvCheckMode fix)
+{
+    int ret = qcow2_check_refcounts(bs, result, fix);
+    if (ret < 0) {
+        return ret;
+    }
+
+    if (fix && result->check_errors == 0 && result->corruptions == 0) {
+        return qcow2_mark_clean(bs);
+    }
+    return ret;
+}
+
 static int qcow2_open(BlockDriverState *bs, int flags)
 {
     BDRVQcowState *s = bs->opaque;
@@ -287,12 +357,13 @@ static int qcow2_open(BlockDriverState *bs, int flags)
     s->compatible_features      = header.compatible_features;
     s->autoclear_features       = header.autoclear_features;
 
-    if (s->incompatible_features != 0) {
+    if (s->incompatible_features & ~QCOW2_INCOMPAT_MASK) {
         void *feature_table = NULL;
         qcow2_read_extensions(bs, header.header_length, ext_end,
                               &feature_table);
         report_unsupported_feature(bs, feature_table,
-                                   s->incompatible_features);
+                                   s->incompatible_features &
+                                   ~QCOW2_INCOMPAT_MASK);
         ret = -ENOTSUP;
         goto fail;
     }
@@ -412,6 +483,17 @@ static int qcow2_open(BlockDriverState *bs, int flags)
     /* Initialise locks */
     qemu_co_mutex_init(&s->lock);
 
+    /* Repair image if dirty */
+    if (!(flags & BDRV_O_CHECK) && !bs->read_only &&
+        (s->incompatible_features & QCOW2_INCOMPAT_DIRTY)) {
+        BdrvCheckResult result = {0};
+
+        ret = qcow2_check(bs, &result, BDRV_FIX_ERRORS);
+        if (ret < 0) {
+            goto fail;
+        }
+    }
+
 #ifdef DEBUG_ALLOC
     {
         BdrvCheckResult result = {0};
@@ -714,6 +796,11 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState *bs,
             goto fail;
         }
 
+        if (l2meta.nb_clusters > 0 &&
+            (s->compatible_features & QCOW2_COMPAT_LAZY_REFCOUNTS)) {
+            qcow2_mark_dirty(bs);
+        }
+
         cluster_offset = l2meta.cluster_offset;
         assert((cluster_offset & 511) == 0);
 
@@ -785,6 +872,8 @@ static void qcow2_close(BlockDriverState *bs)
     qcow2_cache_flush(bs, s->l2_table_cache);
     qcow2_cache_flush(bs, s->refcount_block_cache);
 
+    qcow2_mark_clean(bs);
+
     qcow2_cache_destroy(bs, s->l2_table_cache);
     qcow2_cache_destroy(bs, s->refcount_block_cache);
 
@@ -949,7 +1038,16 @@ int qcow2_update_header(BlockDriverState *bs)
 
     /* Feature table */
     Qcow2Feature features[] = {
-        /* no feature defined yet */
+        {
+            .type = QCOW2_FEAT_TYPE_INCOMPATIBLE,
+            .bit  = QCOW2_INCOMPAT_DIRTY_BITNR,
+            .name = "dirty bit",
+        },
+        {
+            .type = QCOW2_FEAT_TYPE_COMPATIBLE,
+            .bit  = QCOW2_COMPAT_LAZY_REFCOUNTS_BITNR,
+            .name = "lazy refcounts",
+        },
     };
 
     ret = header_ext_add(buf, QCOW2_EXT_MAGIC_FEATURE_TABLE,
@@ -1132,6 +1230,11 @@ static int qcow2_create2(const char *filename, int64_t total_size,
         header.crypt_method = cpu_to_be32(QCOW_CRYPT_NONE);
     }
 
+    if (flags & BLOCK_FLAG_LAZY_REFCOUNTS) {
+        header.compatible_features |=
+            cpu_to_be64(QCOW2_COMPAT_LAZY_REFCOUNTS);
+    }
+
     ret = bdrv_pwrite(bs, 0, &header, sizeof(header));
     if (ret < 0) {
         goto out;
@@ -1245,6 +1348,8 @@ static int qcow2_create(const char *filename, QEMUOptionParameter *options)
                     options->value.s);
                 return -EINVAL;
             }
+        } else if (!strcmp(options->name, BLOCK_OPT_LAZY_REFCOUNTS)) {
+            flags |= options->value.n ? BLOCK_FLAG_LAZY_REFCOUNTS : 0;
         }
         options++;
     }
@@ -1255,6 +1360,12 @@ static int qcow2_create(const char *filename, QEMUOptionParameter *options)
         return -EINVAL;
     }
 
+    if (version < 3 && (flags & BLOCK_FLAG_LAZY_REFCOUNTS)) {
+        fprintf(stderr, "Lazy refcounts only supported with compatibility "
+                "level 1.1 and above (use compat=1.1 or greater)\n");
+        return -EINVAL;
+    }
+
     return qcow2_create2(filename, sectors, backing_file, backing_fmt, flags,
                          cluster_size, prealloc, options, version);
 }
@@ -1441,10 +1552,12 @@ static coroutine_fn int qcow2_co_flush_to_os(BlockDriverState *bs)
         return ret;
     }
 
-    ret = qcow2_cache_flush(bs, s->refcount_block_cache);
-    if (ret < 0) {
-        qemu_co_mutex_unlock(&s->lock);
-        return ret;
+    if (qcow2_need_accurate_refcounts(s)) {
+        ret = qcow2_cache_flush(bs, s->refcount_block_cache);
+        if (ret < 0) {
+            qemu_co_mutex_unlock(&s->lock);
+            return ret;
+        }
     }
     qemu_co_mutex_unlock(&s->lock);
 
@@ -1464,13 +1577,6 @@ static int qcow2_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
     return 0;
 }
 
-
-static int qcow2_check(BlockDriverState *bs, BdrvCheckResult *result,
-                       BdrvCheckMode fix)
-{
-    return qcow2_check_refcounts(bs, result, fix);
-}
-
 #if 0
 static void dump_refcounts(BlockDriverState *bs)
 {
@@ -1559,6 +1665,11 @@ static QEMUOptionParameter qcow2_create_options[] = {
         .type = OPT_STRING,
         .help = "Preallocation mode (allowed values: off, metadata)"
     },
+    {
+        .name = BLOCK_OPT_LAZY_REFCOUNTS,
+        .type = OPT_FLAG,
+        .help = "Postpone refcount updates",
+    },
     { NULL }
 };
 
diff --git a/block/qcow2.h b/block/qcow2.h
index 455b6d7cfe..b4eb65470e 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -110,6 +110,22 @@ enum {
     QCOW2_FEAT_TYPE_AUTOCLEAR       = 2,
 };
 
+/* Incompatible feature bits */
+enum {
+    QCOW2_INCOMPAT_DIRTY_BITNR   = 0,
+    QCOW2_INCOMPAT_DIRTY         = 1 << QCOW2_INCOMPAT_DIRTY_BITNR,
+
+    QCOW2_INCOMPAT_MASK          = QCOW2_INCOMPAT_DIRTY,
+};
+
+/* Compatible feature bits */
+enum {
+    QCOW2_COMPAT_LAZY_REFCOUNTS_BITNR = 0,
+    QCOW2_COMPAT_LAZY_REFCOUNTS       = 1 << QCOW2_COMPAT_LAZY_REFCOUNTS_BITNR,
+
+    QCOW2_COMPAT_FEAT_MASK            = QCOW2_COMPAT_LAZY_REFCOUNTS,
+};
+
 typedef struct Qcow2Feature {
     uint8_t type;
     uint8_t bit;
@@ -237,6 +253,11 @@ static inline int qcow2_get_cluster_type(uint64_t l2_entry)
     }
 }
 
+/* Check whether refcounts are eager or lazy */
+static inline bool qcow2_need_accurate_refcounts(BDRVQcowState *s)
+{
+    return !(s->incompatible_features & QCOW2_INCOMPAT_DIRTY);
+}
 
 // FIXME Need qcow2_ prefix to global functions
 
diff --git a/block/qed-check.c b/block/qed-check.c
index 5edf60775b..b473dcd61f 100644
--- a/block/qed-check.c
+++ b/block/qed-check.c
@@ -194,6 +194,28 @@ static void qed_check_for_leaks(QEDCheck *check)
     }
 }
 
+/**
+ * Mark an image clean once it passes check or has been repaired
+ */
+static void qed_check_mark_clean(BDRVQEDState *s, BdrvCheckResult *result)
+{
+    /* Skip if there were unfixable corruptions or I/O errors */
+    if (result->corruptions > 0 || result->check_errors > 0) {
+        return;
+    }
+
+    /* Skip if image is already marked clean */
+    if (!(s->header.features & QED_F_NEED_CHECK)) {
+        return;
+    }
+
+    /* Ensure fixes reach storage before clearing check bit */
+    bdrv_flush(s->bs);
+
+    s->header.features &= ~QED_F_NEED_CHECK;
+    qed_write_header_sync(s);
+}
+
 int qed_check(BDRVQEDState *s, BdrvCheckResult *result, bool fix)
 {
     QEDCheck check = {
@@ -215,6 +237,10 @@ int qed_check(BDRVQEDState *s, BdrvCheckResult *result, bool fix)
     if (ret == 0) {
         /* Only check for leaks if entire image was scanned successfully */
         qed_check_for_leaks(&check);
+
+        if (fix) {
+            qed_check_mark_clean(s, result);
+        }
     }
 
     g_free(check.used_clusters);
diff --git a/block/qed.c b/block/qed.c
index 5f3eefa3af..a02dbfd72d 100644
--- a/block/qed.c
+++ b/block/qed.c
@@ -89,7 +89,7 @@ static void qed_header_cpu_to_le(const QEDHeader *cpu, QEDHeader *le)
     le->backing_filename_size = cpu_to_le32(cpu->backing_filename_size);
 }
 
-static int qed_write_header_sync(BDRVQEDState *s)
+int qed_write_header_sync(BDRVQEDState *s)
 {
     QEDHeader le;
     int ret;
@@ -477,7 +477,7 @@ static int bdrv_qed_open(BlockDriverState *bs, int flags)
     }
 
     /* If image was not closed cleanly, check consistency */
-    if (s->header.features & QED_F_NEED_CHECK) {
+    if (!(flags & BDRV_O_CHECK) && (s->header.features & QED_F_NEED_CHECK)) {
         /* Read-only images cannot be fixed.  There is no risk of corruption
          * since write operations are not possible.  Therefore, allow
          * potentially inconsistent images to be opened read-only.  This can
@@ -491,13 +491,6 @@ static int bdrv_qed_open(BlockDriverState *bs, int flags)
             if (ret) {
                 goto out;
             }
-            if (!result.corruptions && !result.check_errors) {
-                /* Ensure fixes reach storage before clearing check bit */
-                bdrv_flush(s->bs);
-
-                s->header.features &= ~QED_F_NEED_CHECK;
-                qed_write_header_sync(s);
-            }
         }
     }
 
diff --git a/block/qed.h b/block/qed.h
index c716772ad7..a063bf70af 100644
--- a/block/qed.h
+++ b/block/qed.h
@@ -211,6 +211,11 @@ void *gencb_alloc(size_t len, BlockDriverCompletionFunc *cb, void *opaque);
 void gencb_complete(void *opaque, int ret);
 
 /**
+ * Header functions
+ */
+int qed_write_header_sync(BDRVQEDState *s);
+
+/**
  * L2 cache functions
  */
 void qed_init_l2_cache(L2TableCache *l2_cache);
diff --git a/block_int.h b/block_int.h
index d72317fbe3..4452f6f398 100644
--- a/block_int.h
+++ b/block_int.h
@@ -30,9 +30,11 @@
 #include "qemu-coroutine.h"
 #include "qemu-timer.h"
 #include "qapi-types.h"
+#include "qerror.h"
 
-#define BLOCK_FLAG_ENCRYPT	1
-#define BLOCK_FLAG_COMPAT6	4
+#define BLOCK_FLAG_ENCRYPT          1
+#define BLOCK_FLAG_COMPAT6          4
+#define BLOCK_FLAG_LAZY_REFCOUNTS   8
 
 #define BLOCK_IO_LIMIT_READ     0
 #define BLOCK_IO_LIMIT_WRITE    1
@@ -41,16 +43,17 @@
 #define BLOCK_IO_SLICE_TIME     100000000
 #define NANOSECONDS_PER_SECOND  1000000000.0
 
-#define BLOCK_OPT_SIZE          "size"
-#define BLOCK_OPT_ENCRYPT       "encryption"
-#define BLOCK_OPT_COMPAT6       "compat6"
-#define BLOCK_OPT_BACKING_FILE  "backing_file"
-#define BLOCK_OPT_BACKING_FMT   "backing_fmt"
-#define BLOCK_OPT_CLUSTER_SIZE  "cluster_size"
-#define BLOCK_OPT_TABLE_SIZE    "table_size"
-#define BLOCK_OPT_PREALLOC      "preallocation"
-#define BLOCK_OPT_SUBFMT        "subformat"
-#define BLOCK_OPT_COMPAT_LEVEL  "compat"
+#define BLOCK_OPT_SIZE              "size"
+#define BLOCK_OPT_ENCRYPT           "encryption"
+#define BLOCK_OPT_COMPAT6           "compat6"
+#define BLOCK_OPT_BACKING_FILE      "backing_file"
+#define BLOCK_OPT_BACKING_FMT       "backing_fmt"
+#define BLOCK_OPT_CLUSTER_SIZE      "cluster_size"
+#define BLOCK_OPT_TABLE_SIZE        "table_size"
+#define BLOCK_OPT_PREALLOC          "preallocation"
+#define BLOCK_OPT_SUBFMT            "subformat"
+#define BLOCK_OPT_COMPAT_LEVEL      "compat"
+#define BLOCK_OPT_LAZY_REFCOUNTS    "lazy_refcounts"
 
 typedef struct BdrvTrackedRequest BdrvTrackedRequest;
 
diff --git a/blockdev.c b/blockdev.c
index 8669142704..7c83baa353 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -377,6 +377,7 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
 	}
     }
 
+    bdrv_flags |= BDRV_O_CACHE_WB;
     if ((buf = qemu_opt_get(opts, "cache")) != NULL) {
         if (bdrv_parse_cache_flags(buf, &bdrv_flags) != 0) {
             error_report("invalid cache option");
diff --git a/compiler.h b/compiler.h
index 736e77075a..f76921e5b0 100644
--- a/compiler.h
+++ b/compiler.h
@@ -45,6 +45,7 @@
 #  define GCC_ATTR __attribute__((__unused__, format(gnu_printf, 1, 2)))
 #  define GCC_FMT_ATTR(n, m) __attribute__((format(gnu_printf, n, m)))
 # endif
+#define GCC_WEAK __attribute__((weak))
 #else
 #define GCC_ATTR /**/
 #define GCC_FMT_ATTR(n, m)
diff --git a/configure b/configure
index 280726c3f8..fea62f1d29 100755
--- a/configure
+++ b/configure
@@ -27,16 +27,40 @@ printf " '%s'" "$0" "$@" >> config.log
 echo >> config.log
 echo "#" >> config.log
 
+do_cc() {
+    # Run the compiler, capturing its output to the log.
+    echo $cc "$@" >> config.log
+    $cc "$@" >> config.log 2>&1 || return $?
+    # Test passed. If this is an --enable-werror build, rerun
+    # the test with -Werror and bail out if it fails. This
+    # makes warning-generating-errors in configure test code
+    # obvious to developers.
+    if test "$werror" != "yes"; then
+        return 0
+    fi
+    # Don't bother rerunning the compile if we were already using -Werror
+    case "$*" in
+        *-Werror*)
+           return 0
+        ;;
+    esac
+    echo $cc -Werror "$@" >> config.log
+    $cc -Werror "$@" >> config.log 2>&1 && return $?
+    echo "ERROR: configure test passed without -Werror but failed with -Werror."
+    echo "This is probably a bug in the configure script. The failing command"
+    echo "will be at the bottom of config.log."
+    echo "You can run configure with --disable-werror to bypass this check."
+    exit 1
+}
+
 compile_object() {
-  echo $cc $QEMU_CFLAGS -c -o $TMPO $TMPC >> config.log
-  $cc $QEMU_CFLAGS -c -o $TMPO $TMPC >> config.log 2>&1
+  do_cc $QEMU_CFLAGS -c -o $TMPO $TMPC
 }
 
 compile_prog() {
   local_cflags="$1"
   local_ldflags="$2"
-  echo $cc $QEMU_CFLAGS $local_cflags -o $TMPE $TMPC $LDFLAGS $local_ldflags >> config.log
-  $cc $QEMU_CFLAGS $local_cflags -o $TMPE $TMPC $LDFLAGS $local_ldflags >> config.log 2>&1
+  do_cc $QEMU_CFLAGS $local_cflags -o $TMPE $TMPC $LDFLAGS $local_ldflags
 }
 
 # symbolically link $1 to $2.  Portable version of "ln -sf".
@@ -147,7 +171,6 @@ vhost_net="no"
 kvm="no"
 gprof="no"
 debug_tcg="no"
-debug_mon="no"
 debug="no"
 strip_opt="yes"
 tcg_interpreter="no"
@@ -633,14 +656,9 @@ for opt do
   ;;
   --disable-debug-tcg) debug_tcg="no"
   ;;
-  --enable-debug-mon) debug_mon="yes"
-  ;;
-  --disable-debug-mon) debug_mon="no"
-  ;;
   --enable-debug)
       # Enable debugging options that aren't excessively noisy
       debug_tcg="yes"
-      debug_mon="yes"
       debug="yes"
       strip_opt="no"
   ;;
@@ -935,6 +953,7 @@ sparc64-softmmu \
 s390x-softmmu \
 xtensa-softmmu \
 xtensaeb-softmmu \
+unicore32-softmmu \
 "
 fi
 # the following are Linux specific
@@ -2231,7 +2250,7 @@ cat > $TMPC <<EOF
 #include <sys/types.h>
 #include <sys/uio.h>
 #include <unistd.h>
-int main(void) { return preadv == preadv; }
+int main(void) { return preadv(0, 0, 0, 0); }
 EOF
 preadv=no
 if compile_prog "" "" ; then
@@ -2527,7 +2546,7 @@ int main(void)
      * warning but not an error, and will proceed to fail the
      * qemu compile where we compile with -Werror.)
      */
-    return epoll_create1 == epoll_create1;
+    return (int)(uintptr_t)&epoll_create1;
 }
 EOF
 if compile_prog "" "" ; then
@@ -2920,7 +2939,7 @@ has_environ=no
 cat > $TMPC << EOF
 #include <unistd.h>
 int main(void) {
-    environ = environ;
+    environ = 0;
     return 0;
 }
 EOF
@@ -3039,7 +3058,6 @@ echo "host CPU          $cpu"
 echo "host big endian   $bigendian"
 echo "target list       $target_list"
 echo "tcg debug enabled $debug_tcg"
-echo "Mon debug enabled $debug_mon"
 echo "gprof enabled     $gprof"
 echo "sparse enabled    $sparse"
 echo "strip binaries    $strip_opt"
@@ -3132,9 +3150,6 @@ echo "ARCH=$ARCH" >> $config_host_mak
 if test "$debug_tcg" = "yes" ; then
   echo "CONFIG_DEBUG_TCG=y" >> $config_host_mak
 fi
-if test "$debug_mon" = "yes" ; then
-  echo "CONFIG_DEBUG_MONITOR=y" >> $config_host_mak
-fi
 if test "$debug" = "yes" ; then
   echo "CONFIG_DEBUG_EXEC=y" >> $config_host_mak
 fi
@@ -3538,15 +3553,23 @@ if test "$linux" = "yes" ; then
   mkdir -p linux-headers
   case "$cpu" in
   i386|x86_64)
-    symlink "$source_path/linux-headers/asm-x86" linux-headers/asm
+    linux_arch=x86
     ;;
   ppcemb|ppc|ppc64)
-    symlink "$source_path/linux-headers/asm-powerpc" linux-headers/asm
+    linux_arch=powerpc
     ;;
   s390x)
-    symlink "$source_path/linux-headers/asm-s390" linux-headers/asm
+    linux_arch=s390
+    ;;
+  *)
+    # For most CPUs the kernel architecture name and QEMU CPU name match.
+    linux_arch="$cpu"
     ;;
   esac
+    # For non-KVM architectures we will not have asm headers
+    if [ -e "$source_path/linux-headers/asm-$linux_arch" ]; then
+      symlink "$source_path/linux-headers/asm-$linux_arch" linux-headers/asm
+    fi
 fi
 
 for target in $target_list; do
diff --git a/cpu-exec.c b/cpu-exec.c
index 543460c34c..134b3c4fcf 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -156,12 +156,9 @@ static inline TranslationBlock *tb_find_fast(CPUArchState *env)
 
 static CPUDebugExcpHandler *debug_excp_handler;
 
-CPUDebugExcpHandler *cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler)
+void cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler)
 {
-    CPUDebugExcpHandler *old_handler = debug_excp_handler;
-
     debug_excp_handler = handler;
-    return old_handler;
 }
 
 static void cpu_handle_debug_exception(CPUArchState *env)
@@ -447,6 +444,7 @@ int cpu_exec(CPUArchState *env)
 #elif defined(TARGET_UNICORE32)
                     if (interrupt_request & CPU_INTERRUPT_HARD
                         && !(env->uncached_asr & ASR_I)) {
+                        env->exception_index = UC32_EXCP_INTR;
                         do_interrupt(env);
                         next_tb = 0;
                     }
diff --git a/cpus.c b/cpus.c
index 3de2e27f41..e476a3cd5e 100644
--- a/cpus.c
+++ b/cpus.c
@@ -70,7 +70,8 @@ static bool cpu_thread_is_idle(CPUArchState *env)
     if (env->stopped || !runstate_is_running()) {
         return true;
     }
-    if (!env->halted || qemu_cpu_has_work(env) || kvm_irqchip_in_kernel()) {
+    if (!env->halted || qemu_cpu_has_work(env) ||
+        kvm_async_interrupts_enabled()) {
         return false;
     }
     return true;
diff --git a/cutils.c b/cutils.c
index 9d4c570939..ee4614d378 100644
--- a/cutils.c
+++ b/cutils.c
@@ -382,3 +382,45 @@ int qemu_parse_fd(const char *param)
     }
     return fd;
 }
+
+/* round down to the nearest power of 2*/
+int64_t pow2floor(int64_t value)
+{
+    if (!is_power_of_2(value)) {
+        value = 0x8000000000000000ULL >> clz64(value);
+    }
+    return value;
+}
+
+/*
+ * Implementation of  ULEB128 (http://en.wikipedia.org/wiki/LEB128)
+ * Input is limited to 14-bit numbers
+ */
+int uleb128_encode_small(uint8_t *out, uint32_t n)
+{
+    g_assert(n <= 0x3fff);
+    if (n < 0x80) {
+        *out++ = n;
+        return 1;
+    } else {
+        *out++ = (n & 0x7f) | 0x80;
+        *out++ = n >> 7;
+        return 2;
+    }
+}
+
+int uleb128_decode_small(const uint8_t *in, uint32_t *n)
+{
+    if (!(*in & 0x80)) {
+        *n = *in++;
+        return 1;
+    } else {
+        *n = *in++ & 0x7f;
+        /* we exceed 14 bit number */
+        if (*in & 0x80) {
+            return -1;
+        }
+        *n |= *in++ << 7;
+        return 2;
+    }
+}
diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index e542b4f8ee..f335a725f0 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -27,3 +27,21 @@ CONFIG_SMC91C111=y
 CONFIG_DS1338=y
 CONFIG_PFLASH_CFI01=y
 CONFIG_PFLASH_CFI02=y
+
+CONFIG_ARM_TIMER=y
+CONFIG_PL011=y
+CONFIG_PL022=y
+CONFIG_PL031=y
+CONFIG_PL041=y
+CONFIG_PL050=y
+CONFIG_PL061=y
+CONFIG_PL080=y
+CONFIG_PL110=y
+CONFIG_PL181=y
+CONFIG_PL190=y
+CONFIG_PL310=y
+CONFIG_CADENCE=y
+CONFIG_XGMAC=y
+
+CONFIG_VERSATILE_PCI=y
+CONFIG_VERSATILE_I2C=y
diff --git a/default-configs/pci.mak b/default-configs/pci.mak
index 9febb47ae6..69e18f1428 100644
--- a/default-configs/pci.mak
+++ b/default-configs/pci.mak
@@ -18,3 +18,4 @@ CONFIG_IDE_QDEV=y
 CONFIG_IDE_PCI=y
 CONFIG_AHCI=y
 CONFIG_ESP=y
+CONFIG_ESP_PCI=y
diff --git a/default-configs/unicore32-softmmu.mak b/default-configs/unicore32-softmmu.mak
new file mode 100644
index 0000000000..de38577a35
--- /dev/null
+++ b/default-configs/unicore32-softmmu.mak
@@ -0,0 +1,4 @@
+# Default configuration for unicore32-softmmu
+CONFIG_PUV3=y
+CONFIG_PTIMER=y
+CONFIG_PCKBD=y
diff --git a/dma-helpers.c b/dma-helpers.c
index 35cb500581..13593d1b42 100644
--- a/dma-helpers.c
+++ b/dma-helpers.c
@@ -65,6 +65,7 @@ void qemu_sglist_add(QEMUSGList *qsg, dma_addr_t base, dma_addr_t len)
 void qemu_sglist_destroy(QEMUSGList *qsg)
 {
     g_free(qsg->sg);
+    memset(qsg, 0, sizeof(*qsg));
 }
 
 typedef struct {
diff --git a/docs/specs/qcow2.txt b/docs/specs/qcow2.txt
index 87bf785fe0..36a559d886 100644
--- a/docs/specs/qcow2.txt
+++ b/docs/specs/qcow2.txt
@@ -75,13 +75,23 @@ in the description of a field.
                     Bitmask of incompatible features. An implementation must
                     fail to open an image if an unknown bit is set.
 
-                    Bits 0-63:  Reserved (set to 0)
+                    Bit 0:      Dirty bit.  If this bit is set then refcounts
+                                may be inconsistent, make sure to scan L1/L2
+                                tables to repair refcounts before accessing the
+                                image.
+
+                    Bits 1-63:  Reserved (set to 0)
 
          80 -  87:  compatible_features
                     Bitmask of compatible features. An implementation can
                     safely ignore any unknown bits that are set.
 
-                    Bits 0-63:  Reserved (set to 0)
+                    Bit 0:      Lazy refcounts bit.  If this bit is set then
+                                lazy refcount updates can be used.  This means
+                                marking the image file dirty and postponing
+                                refcount metadata updates.
+
+                    Bits 1-63:  Reserved (set to 0)
 
          88 -  95:  autoclear_features
                     Bitmask of auto-clear features. An implementation may only
diff --git a/docs/writing-qmp-commands.txt b/docs/writing-qmp-commands.txt
index 0ad51aa22a..8349dec8af 100644
--- a/docs/writing-qmp-commands.txt
+++ b/docs/writing-qmp-commands.txt
@@ -210,19 +210,17 @@ if you don't see these strings, then something went wrong.
 === Errors ===
 
 QMP commands should use the error interface exported by the error.h header
-file. The basic function used to set an error is the error_set() one.
+file. Basically, errors are set by calling the error_set() function.
 
 Let's say we don't accept the string "message" to contain the word "love". If
-it does contain it, we want the "hello-world" command to the return the
-InvalidParameter error.
-
-Only one change is required, and it's in the C implementation:
+it does contain it, we want the "hello-world" command to return an error:
 
 void qmp_hello_world(bool has_message, const char *message, Error **errp)
 {
     if (has_message) {
         if (strstr(message, "love")) {
-            error_set(errp, QERR_INVALID_PARAMETER, "message");
+            error_set(errp, ERROR_CLASS_GENERIC_ERROR,
+                      "the word 'love' is not allowed");
             return;
         }
         printf("%s\n", message);
@@ -231,30 +229,40 @@ void qmp_hello_world(bool has_message, const char *message, Error **errp)
     }
 }
 
-Let's test it. Build qemu, run it as defined in the "Testing" section, and
-then issue the following command:
+The first argument to the error_set() function is the Error pointer to pointer,
+which is passed to all QMP functions. The second argument is a ErrorClass
+value, which should be ERROR_CLASS_GENERIC_ERROR most of the time (more
+details about error classes are given below). The third argument is a human
+description of the error, this is a free-form printf-like string.
+
+Let's test the example above. Build qemu, run it as defined in the "Testing"
+section, and then issue the following command:
 
-{ "execute": "hello-world", "arguments": { "message": "we love qemu" } }
+{ "execute": "hello-world", "arguments": { "message": "all you need is love" } }
 
 The QMP server's response should be:
 
 {
     "error": {
-        "class": "InvalidParameter",
-        "desc": "Invalid parameter 'message'",
-        "data": {
-            "name": "message"
-        }
+        "class": "GenericError",
+        "desc": "the word 'love' is not allowed"
     }
 }
 
-Which is the InvalidParameter error.
+As a general rule, all QMP errors should use ERROR_CLASS_GENERIC_ERROR. There
+are two exceptions to this rule:
+
+ 1. A non-generic ErrorClass value exists* for the failure you want to report
+    (eg. DeviceNotFound)
+
+ 2. Management applications have to take special action on the failure you
+    want to report, hence you have to add a new ErrorClass value so that they
+    can check for it
 
-When you have to return an error but you're unsure what error to return or
-which arguments an error takes, you should look at the qerror.h file. Note
-that you might be required to add new errors if needed.
+If the failure you want to report doesn't fall in one of the two cases above,
+just report ERROR_CLASS_GENERIC_ERROR.
 
-FIXME: describe better the error API and how to add new errors.
+ * All existing ErrorClass values are defined in the qapi-schema.json file
 
 === Command Documentation ===
 
@@ -275,7 +283,6 @@ here goes "hello-world"'s new entry for the qapi-schema.json file:
 # @message: #optional string to be printed
 #
 # Returns: Nothing on success.
-#          If @message contains "love", InvalidParameter
 #
 # Notes: if @message is not provided, the "Hello, world" string will
 #        be printed instead
diff --git a/docs/xbzrle.txt b/docs/xbzrle.txt
new file mode 100644
index 0000000000..cc3a26a91d
--- /dev/null
+++ b/docs/xbzrle.txt
@@ -0,0 +1,128 @@
+XBZRLE (Xor Based Zero Run Length Encoding)
+===========================================
+
+Using XBZRLE (Xor Based Zero Run Length Encoding) allows for the reduction
+of VM downtime and the total live-migration time of Virtual machines.
+It is particularly useful for virtual machines running memory write intensive
+workloads that are typical of large enterprise applications such as SAP ERP
+Systems, and generally speaking for any application that uses a sparse memory
+update pattern.
+
+Instead of sending the changed guest memory page this solution will send a
+compressed version of the updates, thus reducing the amount of data sent during
+live migration.
+In order to be able to calculate the update, the previous memory pages need to
+be stored on the source. Those pages are stored in a dedicated cache
+(hash table) and are accessed by their address.
+The larger the cache size the better the chances are that the page has already
+been stored in the cache.
+A small cache size will result in high cache miss rate.
+Cache size can be changed before and during migration.
+
+Format
+=======
+
+The compression format performs a XOR between the previous and current content
+of the page, where zero represents an unchanged value.
+The page data delta is represented by zero and non zero runs.
+A zero run is represented by its length (in bytes).
+A non zero run is represented by its length (in bytes) and the new data.
+The run length is encoded using ULEB128 (http://en.wikipedia.org/wiki/LEB128)
+
+There can be more than one valid encoding, the sender may send a longer encoding
+for the benefit of reducing computation cost.
+
+page = zrun nzrun
+       | zrun nzrun page
+
+zrun = length
+
+nzrun = length byte...
+
+length = uleb128 encoded integer
+
+On the sender side XBZRLE is used as a compact delta encoding of page updates,
+retrieving the old page content from the cache (default size of 512 MB). The
+receiving side uses the existing page's content and XBZRLE to decode the new
+page's content.
+
+This work was originally based on research results published
+VEE 2011: Evaluation of Delta Compression Techniques for Efficient Live
+Migration of Large Virtual Machines by Benoit, Svard, Tordsson and Elmroth.
+Additionally the delta encoder XBRLE was improved further using the XBZRLE
+instead.
+
+XBZRLE has a sustained bandwidth of 2-2.5 GB/s for typical workloads making it
+ideal for in-line, real-time encoding such as is needed for live-migration.
+
+Example
+old buffer:
+1001 zeros
+05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 68 00 00 6b 00 6d
+3074 zeros
+
+new buffer:
+1001 zeros
+01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 68 00 00 67 00 69
+3074 zeros
+
+encoded buffer:
+
+encoded length 24
+e9 07 0f 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 03 01 67 01 01 69
+
+Usage
+======================
+1. Verify the destination QEMU version is able to decode the new format.
+    {qemu} info migrate_capabilities
+    {qemu} xbzrle: off , ...
+
+2. Activate xbzrle on both source and destination:
+   {qemu} migrate_set_capability xbzrle on
+
+3. Set the XBZRLE cache size - the cache size is in MBytes and should be a
+power of 2. The cache default value is 64MBytes. (on source only)
+    {qemu} migrate_set_cache_size 256m
+
+4. Start outgoing migration
+    {qemu} migrate -d tcp:destination.host:4444
+    {qemu} info migrate
+    capabilities: xbzrle: on
+    Migration status: active
+    transferred ram: A kbytes
+    remaining ram: B kbytes
+    total ram: C kbytes
+    total time: D milliseconds
+    duplicate: E pages
+    normal: F pages
+    normal bytes: G kbytes
+    cache size: H bytes
+    xbzrle transferred: I kbytes
+    xbzrle pages: J pages
+    xbzrle cache miss: K
+    xbzrle overflow : L
+
+xbzrle cache-miss: the number of cache misses to date - high cache-miss rate
+indicates that the cache size is set too low.
+xbzrle overflow: the number of overflows in the decoding which where the delta
+could not be compressed. This can happen if the changes in the pages are too
+large or there are many short changes; for example, changing every second byte
+(half a page).
+
+Testing: Testing indicated that live migration with XBZRLE was completed in 110
+seconds, whereas without it would not be able to complete.
+
+A simple synthetic memory r/w load generator:
+..    include <stdlib.h>
+..    include <stdio.h>
+..    int main()
+..    {
+..        char *buf = (char *) calloc(4096, 4096);
+..        while (1) {
+..            int i;
+..            for (i = 0; i < 4096 * 4; i++) {
+..                buf[i * 4096 / 4]++;
+..            }
+..            printf(".");
+..        }
+..    }
diff --git a/error.c b/error.c
index 58f55a012e..1f05fc466e 100644
--- a/error.c
+++ b/error.c
@@ -14,17 +14,16 @@
 #include "error.h"
 #include "qjson.h"
 #include "qdict.h"
-#include "error_int.h"
+#include "qapi-types.h"
 #include "qerror.h"
 
 struct Error
 {
-    QDict *obj;
-    const char *fmt;
     char *msg;
+    ErrorClass err_class;
 };
 
-void error_set(Error **errp, const char *fmt, ...)
+void error_set(Error **errp, ErrorClass err_class, const char *fmt, ...)
 {
     Error *err;
     va_list ap;
@@ -37,9 +36,9 @@ void error_set(Error **errp, const char *fmt, ...)
     err = g_malloc0(sizeof(*err));
 
     va_start(ap, fmt);
-    err->obj = qobject_to_qdict(qobject_from_jsonv(fmt, &ap));
+    err->msg = g_strdup_vprintf(fmt, ap);
     va_end(ap);
-    err->fmt = fmt;
+    err->err_class = err_class;
 
     *errp = err;
 }
@@ -50,9 +49,7 @@ Error *error_copy(const Error *err)
 
     err_new = g_malloc0(sizeof(*err));
     err_new->msg = g_strdup(err->msg);
-    err_new->fmt = err->fmt;
-    err_new->obj = err->obj;
-    QINCREF(err_new->obj);
+    err_new->err_class = err->err_class;
 
     return err_new;
 }
@@ -62,75 +59,24 @@ bool error_is_set(Error **errp)
     return (errp && *errp);
 }
 
-const char *error_get_pretty(Error *err)
-{
-    if (err->msg == NULL) {
-        QString *str;
-        str = qerror_format(err->fmt, err->obj);
-        err->msg = g_strdup(qstring_get_str(str));
-        QDECREF(str);
-    }
-
-    return err->msg;
-}
-
-const char *error_get_field(Error *err, const char *field)
-{
-    if (strcmp(field, "class") == 0) {
-        return qdict_get_str(err->obj, field);
-    } else {
-        QDict *dict = qdict_get_qdict(err->obj, "data");
-        return qdict_get_str(dict, field);
-    }
-}
-
-QDict *error_get_data(Error *err)
+ErrorClass error_get_class(const Error *err)
 {
-    QDict *data = qdict_get_qdict(err->obj, "data");
-    QINCREF(data);
-    return data;
+    return err->err_class;
 }
 
-void error_set_field(Error *err, const char *field, const char *value)
+const char *error_get_pretty(Error *err)
 {
-    QDict *dict = qdict_get_qdict(err->obj, "data");
-    qdict_put(dict, field, qstring_from_str(value));
+    return err->msg;
 }
 
 void error_free(Error *err)
 {
     if (err) {
-        QDECREF(err->obj);
         g_free(err->msg);
         g_free(err);
     }
 }
 
-bool error_is_type(Error *err, const char *fmt)
-{
-    const char *error_class;
-    char *ptr;
-    char *end;
-
-    if (!err) {
-        return false;
-    }
-
-    ptr = strstr(fmt, "'class': '");
-    assert(ptr != NULL);
-    ptr += strlen("'class': '");
-
-    end = strchr(ptr, '\'');
-    assert(end != NULL);
-
-    error_class = error_get_field(err, "class");
-    if (strlen(error_class) != end - ptr) {
-        return false;
-    }
-
-    return strncmp(ptr, error_class, end - ptr) == 0;
-}
-
 void error_propagate(Error **dst_err, Error *local_err)
 {
     if (dst_err && !*dst_err) {
@@ -139,22 +85,3 @@ void error_propagate(Error **dst_err, Error *local_err)
         error_free(local_err);
     }
 }
-
-QObject *error_get_qobject(Error *err)
-{
-    QINCREF(err->obj);
-    return QOBJECT(err->obj);
-}
-
-void error_set_qobject(Error **errp, QObject *obj)
-{
-    Error *err;
-    if (errp == NULL) {
-        return;
-    }
-    err = g_malloc0(sizeof(*err));
-    err->obj = qobject_to_qdict(obj);
-    qobject_incref(obj);
-
-    *errp = err;
-}
diff --git a/error.h b/error.h
index 3d9d96def0..96fc20328f 100644
--- a/error.h
+++ b/error.h
@@ -13,20 +13,21 @@
 #define ERROR_H
 
 #include "compiler.h"
+#include "qapi-types.h"
 #include <stdbool.h>
 
 /**
- * A class representing internal errors within QEMU.  An error has a string
- * typename and optionally a set of named string parameters.
+ * A class representing internal errors within QEMU.  An error has a ErrorClass
+ * code and a human message.
  */
 typedef struct Error Error;
 
 /**
- * Set an indirect pointer to an error given a printf-style format parameter.
- * Currently, qerror.h defines these error formats.  This function is not
- * meant to be used outside of QEMU.
+ * Set an indirect pointer to an error given a ErrorClass value and a
+ * printf-style human message.  This function is not meant to be used outside
+ * of QEMU.
  */
-void error_set(Error **err, const char *fmt, ...) GCC_FMT_ATTR(2, 3);
+void error_set(Error **err, ErrorClass err_class, const char *fmt, ...) GCC_FMT_ATTR(3, 4);
 
 /**
  * Returns true if an indirect pointer to an error is pointing to a valid
@@ -34,6 +35,11 @@ void error_set(Error **err, const char *fmt, ...) GCC_FMT_ATTR(2, 3);
  */
 bool error_is_set(Error **err);
 
+/*
+ * Get the error class of an error object.
+ */
+ErrorClass error_get_class(const Error *err);
+
 /**
  * Returns an exact copy of the error passed as an argument.
  */
@@ -45,16 +51,6 @@ Error *error_copy(const Error *err);
 const char *error_get_pretty(Error *err);
 
 /**
- * Get an individual named error field.
- */
-const char *error_get_field(Error *err, const char *field);
-
-/**
- * Get an individual named error field.
- */
-void error_set_field(Error *err, const char *field, const char *value);
-
-/**
  * Propagate an error to an indirect pointer to an error.  This function will
  * always transfer ownership of the error reference and handles the case where
  * dst_err is NULL correctly.  Errors after the first are discarded.
@@ -66,10 +62,4 @@ void error_propagate(Error **dst_err, Error *local_err);
  */
 void error_free(Error *err);
 
-/**
- * Determine if an error is of a speific type (based on the qerror format).
- * Non-QEMU users should get the `class' field to identify the error type.
- */
-bool error_is_type(Error *err, const char *fmt);
-
 #endif
diff --git a/error_int.h b/error_int.h
deleted file mode 100644
index 5e3942405a..0000000000
--- a/error_int.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * QEMU Error Objects
- *
- * Copyright IBM, Corp. 2011
- *
- * Authors:
- *  Anthony Liguori   <aliguori@us.ibm.com>
- *
- * This work is licensed under the terms of the GNU LGPL, version 2.  See
- * the COPYING.LIB file in the top-level directory.
- */
-#ifndef QEMU_ERROR_INT_H
-#define QEMU_ERROR_INT_H
-
-#include "qemu-common.h"
-#include "qobject.h"
-#include "qdict.h"
-#include "error.h"
-
-/**
- * Internal QEMU functions for working with Error.
- *
- * These are used to convert QErrors to Errors
- */
-QDict *error_get_data(Error *err);
-QObject *error_get_qobject(Error *err);
-void error_set_qobject(Error **errp, QObject *obj);
-  
-#endif
diff --git a/exec-all.h b/exec-all.h
index 9bda7f7354..c5ec8e1158 100644
--- a/exec-all.h
+++ b/exec-all.h
@@ -357,7 +357,7 @@ tb_page_addr_t get_page_addr_code(CPUArchState *env1, target_ulong addr);
 
 typedef void (CPUDebugExcpHandler)(CPUArchState *env);
 
-CPUDebugExcpHandler *cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler);
+void cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler);
 
 /* vl.c */
 extern int singlestep;
diff --git a/exec.c b/exec.c
index a42a0b5b78..929db5cf0a 100644
--- a/exec.c
+++ b/exec.c
@@ -2550,6 +2550,8 @@ ram_addr_t qemu_ram_alloc_from_ptr(ram_addr_t size, void *host,
 
     ram_list.phys_dirty = g_realloc(ram_list.phys_dirty,
                                        last_ram_offset() >> TARGET_PAGE_BITS);
+    memset(ram_list.phys_dirty + (new_block->offset >> TARGET_PAGE_BITS),
+           0, size >> TARGET_PAGE_BITS);
     cpu_physical_memory_set_dirty_range(new_block->offset, size, 0xff);
 
     if (kvm_enabled())
diff --git a/hmp-commands.hx b/hmp-commands.hx
index eea8b32894..f6104b099f 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -101,7 +101,7 @@ ETEXI
         .name       = "block_job_cancel",
         .args_type  = "device:B",
         .params     = "device",
-        .help       = "stop an active block streaming operation",
+        .help       = "stop an active background block operation",
         .mhandler.cmd = hmp_block_job_cancel,
     },
 
@@ -829,6 +829,26 @@ STEXI
 @item migrate_cancel
 @findex migrate_cancel
 Cancel the current VM migration.
+
+ETEXI
+
+    {
+        .name       = "migrate_set_cache_size",
+        .args_type  = "value:o",
+        .params     = "value",
+        .help       = "set cache size (in bytes) for XBZRLE migrations,"
+                      "the cache size will be rounded down to the nearest "
+                      "power of 2.\n"
+                      "The cache size affects the number of cache misses."
+                      "In case of a high cache miss ratio you need to increase"
+                      " the cache size",
+        .mhandler.cmd = hmp_migrate_set_cache_size,
+    },
+
+STEXI
+@item migrate_set_cache_size @var{value}
+@findex migrate_set_cache_size
+Set cache size to @var{value} (in bytes) for xbzrle migrations.
 ETEXI
 
     {
@@ -861,6 +881,20 @@ Set maximum tolerated downtime (in seconds) for migration.
 ETEXI
 
     {
+        .name       = "migrate_set_capability",
+        .args_type  = "capability:s,state:b",
+        .params     = "capability state",
+        .help       = "Enable/Disable the usage of a capability for migration",
+        .mhandler.cmd = hmp_migrate_set_capability,
+    },
+
+STEXI
+@item migrate_set_capability @var{capability} @var{state}
+@findex migrate_set_capability
+Enable/Disable the usage of a capability @var{capability} for migration.
+ETEXI
+
+    {
         .name       = "client_migrate_info",
         .args_type  = "protocol:s,hostname:s,port:i?,tls-port:i?,cert-subject:s?",
         .params     = "protocol hostname port tls-port cert-subject",
@@ -1417,6 +1451,10 @@ show CPU statistics
 show user network stack connection states
 @item info migrate
 show migration status
+@item info migrate_capabilities
+show current migration capabilities
+@item info migrate_cache_size
+show current migration XBZRLE cache size
 @item info balloon
 show balloon information
 @item info qtree
diff --git a/hmp.c b/hmp.c
index 25688ab0e2..a9d5675fc8 100644
--- a/hmp.c
+++ b/hmp.c
@@ -131,8 +131,21 @@ void hmp_info_mice(Monitor *mon)
 void hmp_info_migrate(Monitor *mon)
 {
     MigrationInfo *info;
+    MigrationCapabilityStatusList *caps, *cap;
 
     info = qmp_query_migrate(NULL);
+    caps = qmp_query_migrate_capabilities(NULL);
+
+    /* do not display parameters during setup */
+    if (info->has_status && caps) {
+        monitor_printf(mon, "capabilities: ");
+        for (cap = caps; cap; cap = cap->next) {
+            monitor_printf(mon, "%s: %s ",
+                           MigrationCapability_lookup[cap->value->capability],
+                           cap->value->state ? "on" : "off");
+        }
+        monitor_printf(mon, "\n");
+    }
 
     if (info->has_status) {
         monitor_printf(mon, "Migration status: %s\n", info->status);
@@ -147,6 +160,12 @@ void hmp_info_migrate(Monitor *mon)
                        info->ram->total >> 10);
         monitor_printf(mon, "total time: %" PRIu64 " milliseconds\n",
                        info->ram->total_time);
+        monitor_printf(mon, "duplicate: %" PRIu64 " pages\n",
+                       info->ram->duplicate);
+        monitor_printf(mon, "normal: %" PRIu64 " pages\n",
+                       info->ram->normal);
+        monitor_printf(mon, "normal bytes: %" PRIu64 " kbytes\n",
+                       info->ram->normal_bytes >> 10);
     }
 
     if (info->has_disk) {
@@ -158,7 +177,46 @@ void hmp_info_migrate(Monitor *mon)
                        info->disk->total >> 10);
     }
 
+    if (info->has_xbzrle_cache) {
+        monitor_printf(mon, "cache size: %" PRIu64 " bytes\n",
+                       info->xbzrle_cache->cache_size);
+        monitor_printf(mon, "xbzrle transferred: %" PRIu64 " kbytes\n",
+                       info->xbzrle_cache->bytes >> 10);
+        monitor_printf(mon, "xbzrle pages: %" PRIu64 " pages\n",
+                       info->xbzrle_cache->pages);
+        monitor_printf(mon, "xbzrle cache miss: %" PRIu64 "\n",
+                       info->xbzrle_cache->cache_miss);
+        monitor_printf(mon, "xbzrle overflow : %" PRIu64 "\n",
+                       info->xbzrle_cache->overflow);
+    }
+
     qapi_free_MigrationInfo(info);
+    qapi_free_MigrationCapabilityStatusList(caps);
+}
+
+void hmp_info_migrate_capabilities(Monitor *mon)
+{
+    MigrationCapabilityStatusList *caps, *cap;
+
+    caps = qmp_query_migrate_capabilities(NULL);
+
+    if (caps) {
+        monitor_printf(mon, "capabilities: ");
+        for (cap = caps; cap; cap = cap->next) {
+            monitor_printf(mon, "%s: %s ",
+                           MigrationCapability_lookup[cap->value->capability],
+                           cap->value->state ? "on" : "off");
+        }
+        monitor_printf(mon, "\n");
+    }
+
+    qapi_free_MigrationCapabilityStatusList(caps);
+}
+
+void hmp_info_migrate_cache_size(Monitor *mon)
+{
+    monitor_printf(mon, "xbzrel cache size: %" PRId64 " kbytes\n",
+                   qmp_query_migrate_cache_size(NULL) >> 10);
 }
 
 void hmp_info_cpus(Monitor *mon)
@@ -612,34 +670,35 @@ void hmp_pmemsave(Monitor *mon, const QDict *qdict)
 
 static void hmp_cont_cb(void *opaque, int err)
 {
-    Monitor *mon = opaque;
-
     if (!err) {
-        hmp_cont(mon, NULL);
+        qmp_cont(NULL);
     }
 }
 
+static bool key_is_missing(const BlockInfo *bdev)
+{
+    return (bdev->inserted && bdev->inserted->encryption_key_missing);
+}
+
 void hmp_cont(Monitor *mon, const QDict *qdict)
 {
+    BlockInfoList *bdev_list, *bdev;
     Error *errp = NULL;
 
-    qmp_cont(&errp);
-    if (error_is_set(&errp)) {
-        if (error_is_type(errp, QERR_DEVICE_ENCRYPTED)) {
-            const char *device;
-
-            /* The device is encrypted. Ask the user for the password
-               and retry */
-
-            device = error_get_field(errp, "device");
-            assert(device != NULL);
-
-            monitor_read_block_device_key(mon, device, hmp_cont_cb, mon);
-            error_free(errp);
-            return;
+    bdev_list = qmp_query_block(NULL);
+    for (bdev = bdev_list; bdev; bdev = bdev->next) {
+        if (key_is_missing(bdev->value)) {
+            monitor_read_block_device_key(mon, bdev->value->device,
+                                          hmp_cont_cb, NULL);
+            goto out;
         }
-        hmp_handle_error(mon, &errp);
     }
+
+    qmp_cont(&errp);
+    hmp_handle_error(mon, &errp);
+
+out:
+    qapi_free_BlockInfoList(bdev_list);
 }
 
 void hmp_system_wakeup(Monitor *mon, const QDict *qdict)
@@ -731,12 +790,57 @@ void hmp_migrate_set_downtime(Monitor *mon, const QDict *qdict)
     qmp_migrate_set_downtime(value, NULL);
 }
 
+void hmp_migrate_set_cache_size(Monitor *mon, const QDict *qdict)
+{
+    int64_t value = qdict_get_int(qdict, "value");
+    Error *err = NULL;
+
+    qmp_migrate_set_cache_size(value, &err);
+    if (err) {
+        monitor_printf(mon, "%s\n", error_get_pretty(err));
+        error_free(err);
+        return;
+    }
+}
+
 void hmp_migrate_set_speed(Monitor *mon, const QDict *qdict)
 {
     int64_t value = qdict_get_int(qdict, "value");
     qmp_migrate_set_speed(value, NULL);
 }
 
+void hmp_migrate_set_capability(Monitor *mon, const QDict *qdict)
+{
+    const char *cap = qdict_get_str(qdict, "capability");
+    bool state = qdict_get_bool(qdict, "state");
+    Error *err = NULL;
+    MigrationCapabilityStatusList *caps = g_malloc0(sizeof(*caps));
+    int i;
+
+    for (i = 0; i < MIGRATION_CAPABILITY_MAX; i++) {
+        if (strcmp(cap, MigrationCapability_lookup[i]) == 0) {
+            caps->value = g_malloc0(sizeof(*caps->value));
+            caps->value->capability = i;
+            caps->value->state = state;
+            caps->next = NULL;
+            qmp_migrate_set_capabilities(caps, &err);
+            break;
+        }
+    }
+
+    if (i == MIGRATION_CAPABILITY_MAX) {
+        error_set(&err, QERR_INVALID_PARAMETER, cap);
+    }
+
+    qapi_free_MigrationCapabilityStatusList(caps);
+
+    if (err) {
+        monitor_printf(mon, "migrate_set_parameter: %s\n",
+                       error_get_pretty(err));
+        error_free(err);
+    }
+}
+
 void hmp_set_password(Monitor *mon, const QDict *qdict)
 {
     const char *protocol  = qdict_get_str(qdict, "protocol");
@@ -775,22 +879,6 @@ static void hmp_change_read_arg(Monitor *mon, const char *password,
     monitor_read_command(mon, 1);
 }
 
-static void cb_hmp_change_bdrv_pwd(Monitor *mon, const char *password,
-                                   void *opaque)
-{
-    Error *encryption_err = opaque;
-    Error *err = NULL;
-    const char *device;
-
-    device = error_get_field(encryption_err, "device");
-
-    qmp_block_passwd(device, password, &err);
-    hmp_handle_error(mon, &err);
-    error_free(encryption_err);
-
-    monitor_read_command(mon, 1);
-}
-
 void hmp_change(Monitor *mon, const QDict *qdict)
 {
     const char *device = qdict_get_str(qdict, "device");
@@ -808,18 +896,10 @@ void hmp_change(Monitor *mon, const QDict *qdict)
     }
 
     qmp_change(device, target, !!arg, arg, &err);
-    if (error_is_type(err, QERR_DEVICE_ENCRYPTED)) {
-        monitor_printf(mon, "%s (%s) is encrypted.\n",
-                       error_get_field(err, "device"),
-                       error_get_field(err, "filename"));
-        if (!monitor_get_rs(mon)) {
-            monitor_printf(mon,
-                    "terminal does not support password prompting\n");
-            error_free(err);
-            return;
-        }
-        readline_start(monitor_get_rs(mon), "Password: ", 1,
-                       cb_hmp_change_bdrv_pwd, err);
+    if (error_is_set(&err) &&
+        error_get_class(err) == ERROR_CLASS_DEVICE_ENCRYPTED) {
+        error_free(err);
+        monitor_read_block_device_key(mon, device, NULL, NULL);
         return;
     }
     hmp_handle_error(mon, &err);
diff --git a/hmp.h b/hmp.h
index 8d2b0d76da..7dd93bf0f4 100644
--- a/hmp.h
+++ b/hmp.h
@@ -16,6 +16,7 @@
 
 #include "qemu-common.h"
 #include "qapi-types.h"
+#include "qdict.h"
 
 void hmp_info_name(Monitor *mon);
 void hmp_info_version(Monitor *mon);
@@ -25,6 +26,8 @@ void hmp_info_uuid(Monitor *mon);
 void hmp_info_chardev(Monitor *mon);
 void hmp_info_mice(Monitor *mon);
 void hmp_info_migrate(Monitor *mon);
+void hmp_info_migrate_capabilities(Monitor *mon);
+void hmp_info_migrate_cache_size(Monitor *mon);
 void hmp_info_cpus(Monitor *mon);
 void hmp_info_block(Monitor *mon);
 void hmp_info_blockstats(Monitor *mon);
@@ -51,6 +54,8 @@ void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict);
 void hmp_migrate_cancel(Monitor *mon, const QDict *qdict);
 void hmp_migrate_set_downtime(Monitor *mon, const QDict *qdict);
 void hmp_migrate_set_speed(Monitor *mon, const QDict *qdict);
+void hmp_migrate_set_capability(Monitor *mon, const QDict *qdict);
+void hmp_migrate_set_cache_size(Monitor *mon, const QDict *qdict);
 void hmp_set_password(Monitor *mon, const QDict *qdict);
 void hmp_expire_password(Monitor *mon, const QDict *qdict);
 void hmp_eject(Monitor *mon, const QDict *qdict);
diff --git a/hw/Makefile.objs b/hw/Makefile.objs
index 8327e55c03..7f57ed58e2 100644
--- a/hw/Makefile.objs
+++ b/hw/Makefile.objs
@@ -65,6 +65,34 @@ hw-obj-$(CONFIG_XILINX) += xilinx_timer.o
 hw-obj-$(CONFIG_XILINX) += xilinx_uartlite.o
 hw-obj-$(CONFIG_XILINX_AXI) += xilinx_axidma.o
 hw-obj-$(CONFIG_XILINX_AXI) += xilinx_axienet.o
+hw-obj-$(CONFIG_XILINX_AXI) += stream.o
+
+# PKUnity SoC devices
+hw-obj-$(CONFIG_PUV3) += puv3_intc.o
+hw-obj-$(CONFIG_PUV3) += puv3_ost.o
+hw-obj-$(CONFIG_PUV3) += puv3_gpio.o
+hw-obj-$(CONFIG_PUV3) += puv3_pm.o
+hw-obj-$(CONFIG_PUV3) += puv3_dma.o
+
+# ARM devices
+hw-obj-$(CONFIG_ARM_TIMER) += arm_timer.o
+hw-obj-$(CONFIG_PL011) += pl011.o
+hw-obj-$(CONFIG_PL022) += pl022.o
+hw-obj-$(CONFIG_PL031) += pl031.o
+hw-obj-$(CONFIG_PL041) += pl041.o lm4549.o
+hw-obj-$(CONFIG_PL050) += pl050.o
+hw-obj-$(CONFIG_PL061) += pl061.o
+hw-obj-$(CONFIG_PL080) += pl080.o
+hw-obj-$(CONFIG_PL110) += pl110.o
+hw-obj-$(CONFIG_PL181) += pl181.o
+hw-obj-$(CONFIG_PL190) += pl190.o
+hw-obj-$(CONFIG_PL310) += arm_l2x0.o
+hw-obj-$(CONFIG_VERSATILE_PCI) += versatile_pci.o
+hw-obj-$(CONFIG_VERSATILE_I2C) += versatile_i2c.o
+hw-obj-$(CONFIG_CADENCE) += cadence_uart.o
+hw-obj-$(CONFIG_CADENCE) += cadence_ttc.o
+hw-obj-$(CONFIG_CADENCE) += cadence_gem.o
+hw-obj-$(CONFIG_XGMAC) += xgmac.o
 
 # PCI watchdog devices
 hw-obj-$(CONFIG_PCI) += wdt_i6300esb.o
@@ -88,6 +116,7 @@ hw-obj-$(CONFIG_OPENCORES_ETH) += opencores_eth.o
 hw-obj-$(CONFIG_LSI_SCSI_PCI) += lsi53c895a.o
 hw-obj-$(CONFIG_MEGASAS_SCSI_PCI) += megasas.o
 hw-obj-$(CONFIG_ESP) += esp.o
+hw-obj-$(CONFIG_ESP_PCI) += esp-pci.o
 
 hw-obj-y += sysbus.o isa-bus.o
 hw-obj-y += qdev-addr.o
diff --git a/hw/acpi.c b/hw/acpi.c
index effc7ec23e..f7950be267 100644
--- a/hw/acpi.c
+++ b/hw/acpi.c
@@ -22,6 +22,7 @@
 #include "hw.h"
 #include "pc.h"
 #include "acpi.h"
+#include "monitor.h"
 
 struct acpi_table_header {
     uint16_t _length;         /* our length, not actual part of the hdr */
@@ -386,6 +387,7 @@ void acpi_pm1_cnt_write(ACPIREGS *ar, uint16_t val, char s4)
             break;
         default:
             if (sus_typ == s4) { /* S4 request */
+                monitor_protocol_event(QEVENT_SUSPEND_DISK, NULL);
                 qemu_system_shutdown_request();
             }
             break;
diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index c413780784..2b39fb3c85 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -1,10 +1,5 @@
-obj-y = integratorcp.o versatilepb.o arm_pic.o arm_timer.o
-obj-y += arm_boot.o pl011.o pl031.o pl050.o pl080.o pl110.o pl181.o pl190.o
-obj-y += versatile_pci.o
-obj-y += versatile_i2c.o
-obj-y += cadence_uart.o
-obj-y += cadence_ttc.o
-obj-y += cadence_gem.o
+obj-y = integratorcp.o versatilepb.o arm_pic.o
+obj-y += arm_boot.o
 obj-y += xilinx_zynq.o zynq_slcr.o
 obj-y += arm_gic.o arm_gic_common.o
 obj-y += realview_gic.o realview.o arm_sysctl.o arm11mpcore.o a9mpcore.o
@@ -12,12 +7,9 @@ obj-y += exynos4210_gic.o exynos4210_combiner.o exynos4210.o
 obj-y += exynos4_boards.o exynos4210_uart.o exynos4210_pwm.o
 obj-y += exynos4210_pmu.o exynos4210_mct.o exynos4210_fimd.o
 obj-y += exynos4210_rtc.o exynos4210_i2c.o
-obj-y += arm_l2x0.o
 obj-y += arm_mptimer.o a15mpcore.o
-obj-y += armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o
+obj-y += armv7m.o armv7m_nvic.o stellaris.o stellaris_enet.o
 obj-y += highbank.o
-obj-y += pl061.o
-obj-y += xgmac.o
 obj-y += pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o
 obj-y += pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o pxa2xx_keypad.o
 obj-y += gumstix.o
@@ -37,7 +29,6 @@ obj-y += strongarm.o
 obj-y += collie.o
 obj-y += imx_serial.o imx_ccm.o imx_timer.o imx_avic.o
 obj-y += kzm.o
-obj-y += pl041.o lm4549.o
 obj-$(CONFIG_FDT) += ../device_tree.o
 
 obj-y := $(addprefix ../,$(obj-y))
diff --git a/hw/armv7m.c b/hw/armv7m.c
index 8cec78db96..9f66667c6d 100644
--- a/hw/armv7m.c
+++ b/hw/armv7m.c
@@ -227,6 +227,11 @@ qemu_irq *armv7m_init(MemoryRegion *address_space_mem,
     big_endian = 0;
 #endif
 
+    if (!kernel_filename) {
+        fprintf(stderr, "Guest image must be specified (using -kernel)\n");
+        exit(1);
+    }
+
     image_size = load_elf(kernel_filename, NULL, NULL, &entry, &lowaddr,
                           NULL, big_endian, ELF_MACHINE, 1);
     if (image_size < 0) {
diff --git a/hw/armv7m_nvic.c b/hw/armv7m_nvic.c
index 4867c1d5fa..6a0832eb3f 100644
--- a/hw/armv7m_nvic.c
+++ b/hw/armv7m_nvic.c
@@ -467,7 +467,7 @@ static int armv7m_nvic_init(SysBusDevice *dev)
     s->gic.num_cpu = 1;
     /* Tell the common code we're an NVIC */
     s->gic.revision = 0xffffffff;
-    s->gic.num_irq = s->num_irq;
+    s->num_irq = s->gic.num_irq;
     nc->parent_init(dev);
     gic_init_irqs_and_distributor(&s->gic, s->num_irq);
     /* The NVIC and system controller register area looks like this:
@@ -498,14 +498,21 @@ static int armv7m_nvic_init(SysBusDevice *dev)
     return 0;
 }
 
-static Property armv7m_nvic_properties[] = {
+static void armv7m_nvic_instance_init(Object *obj)
+{
+    /* We have a different default value for the num-irq property
+     * than our superclass. This function runs after qdev init
+     * has set the defaults from the Property array and before
+     * any user-specified property setting, so just modify the
+     * value in the gic_state struct.
+     */
+    gic_state *s = ARM_GIC_COMMON(obj);
     /* The ARM v7m may have anything from 0 to 496 external interrupt
      * IRQ lines. We default to 64. Other boards may differ and should
-     * set this property appropriately.
+     * set the num-irq property appropriately.
      */
-    DEFINE_PROP_UINT32("num-irq", nvic_state, num_irq, 64),
-    DEFINE_PROP_END_OF_LIST(),
-};
+    s->num_irq = 64;
+}
 
 static void armv7m_nvic_class_init(ObjectClass *klass, void *data)
 {
@@ -518,12 +525,12 @@ static void armv7m_nvic_class_init(ObjectClass *klass, void *data)
     sdc->init = armv7m_nvic_init;
     dc->vmsd  = &vmstate_nvic;
     dc->reset = armv7m_nvic_reset;
-    dc->props = armv7m_nvic_properties;
 }
 
 static TypeInfo armv7m_nvic_info = {
     .name          = TYPE_NVIC,
     .parent        = TYPE_ARM_GIC_COMMON,
+    .instance_init = armv7m_nvic_instance_init,
     .instance_size = sizeof(nvic_state),
     .class_init    = armv7m_nvic_class_init,
     .class_size    = sizeof(NVICClass),
diff --git a/hw/esp-pci.c b/hw/esp-pci.c
new file mode 100644
index 0000000000..170e007be9
--- /dev/null
+++ b/hw/esp-pci.c
@@ -0,0 +1,518 @@
+/*
+ * QEMU ESP/NCR53C9x emulation
+ *
+ * Copyright (c) 2005-2006 Fabrice Bellard
+ * Copyright (c) 2012 Herve Poussineau
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "pci.h"
+#include "eeprom93xx.h"
+#include "esp.h"
+#include "trace.h"
+#include "qemu-log.h"
+
+#define TYPE_AM53C974_DEVICE "am53c974"
+
+#define DMA_CMD   0x0
+#define DMA_STC   0x1
+#define DMA_SPA   0x2
+#define DMA_WBC   0x3
+#define DMA_WAC   0x4
+#define DMA_STAT  0x5
+#define DMA_SMDLA 0x6
+#define DMA_WMAC  0x7
+
+#define DMA_CMD_MASK   0x03
+#define DMA_CMD_DIAG   0x04
+#define DMA_CMD_MDL    0x10
+#define DMA_CMD_INTE_P 0x20
+#define DMA_CMD_INTE_D 0x40
+#define DMA_CMD_DIR    0x80
+
+#define DMA_STAT_PWDN    0x01
+#define DMA_STAT_ERROR   0x02
+#define DMA_STAT_ABORT   0x04
+#define DMA_STAT_DONE    0x08
+#define DMA_STAT_SCSIINT 0x10
+#define DMA_STAT_BCMBLT  0x20
+
+#define SBAC_STATUS 0x1000
+
+typedef struct PCIESPState {
+    PCIDevice dev;
+    MemoryRegion io;
+    uint32_t dma_regs[8];
+    uint32_t sbac;
+    ESPState esp;
+} PCIESPState;
+
+static void esp_pci_handle_idle(PCIESPState *pci, uint32_t val)
+{
+    trace_esp_pci_dma_idle(val);
+    esp_dma_enable(&pci->esp, 0, 0);
+}
+
+static void esp_pci_handle_blast(PCIESPState *pci, uint32_t val)
+{
+    trace_esp_pci_dma_blast(val);
+    qemu_log_mask(LOG_UNIMP, "am53c974: cmd BLAST not implemented\n");
+}
+
+static void esp_pci_handle_abort(PCIESPState *pci, uint32_t val)
+{
+    trace_esp_pci_dma_abort(val);
+    if (pci->esp.current_req) {
+        scsi_req_cancel(pci->esp.current_req);
+    }
+}
+
+static void esp_pci_handle_start(PCIESPState *pci, uint32_t val)
+{
+    trace_esp_pci_dma_start(val);
+
+    pci->dma_regs[DMA_WBC] = pci->dma_regs[DMA_STC];
+    pci->dma_regs[DMA_WAC] = pci->dma_regs[DMA_SPA];
+    pci->dma_regs[DMA_WMAC] = pci->dma_regs[DMA_SMDLA];
+
+    pci->dma_regs[DMA_STAT] &= ~(DMA_STAT_BCMBLT | DMA_STAT_SCSIINT
+                               | DMA_STAT_DONE | DMA_STAT_ABORT
+                               | DMA_STAT_ERROR | DMA_STAT_PWDN);
+
+    esp_dma_enable(&pci->esp, 0, 1);
+}
+
+static void esp_pci_dma_write(PCIESPState *pci, uint32_t saddr, uint32_t val)
+{
+    trace_esp_pci_dma_write(saddr, pci->dma_regs[saddr], val);
+    switch (saddr) {
+    case DMA_CMD:
+        pci->dma_regs[saddr] = val;
+        switch (val & DMA_CMD_MASK) {
+        case 0x0: /* IDLE */
+            esp_pci_handle_idle(pci, val);
+            break;
+        case 0x1: /* BLAST */
+            esp_pci_handle_blast(pci, val);
+            break;
+        case 0x2: /* ABORT */
+            esp_pci_handle_abort(pci, val);
+            break;
+        case 0x3: /* START */
+            esp_pci_handle_start(pci, val);
+            break;
+        default: /* can't happen */
+            abort();
+        }
+        break;
+    case DMA_STC:
+    case DMA_SPA:
+    case DMA_SMDLA:
+        pci->dma_regs[saddr] = val;
+        break;
+    case DMA_STAT:
+        if (!(pci->sbac & SBAC_STATUS)) {
+            /* clear some bits on write */
+            uint32_t mask = DMA_STAT_ERROR | DMA_STAT_ABORT | DMA_STAT_DONE;
+            pci->dma_regs[DMA_STAT] &= ~(val & mask);
+        }
+        break;
+    default:
+        trace_esp_pci_error_invalid_write_dma(val, saddr);
+        return;
+    }
+}
+
+static uint32_t esp_pci_dma_read(PCIESPState *pci, uint32_t saddr)
+{
+    uint32_t val;
+
+    val = pci->dma_regs[saddr];
+    if (saddr == DMA_STAT) {
+        if (pci->esp.rregs[ESP_RSTAT] & STAT_INT) {
+            val |= DMA_STAT_SCSIINT;
+        }
+        if (pci->sbac & SBAC_STATUS) {
+            pci->dma_regs[DMA_STAT] &= ~(DMA_STAT_ERROR | DMA_STAT_ABORT |
+                                         DMA_STAT_DONE);
+        }
+    }
+
+    trace_esp_pci_dma_read(saddr, val);
+    return val;
+}
+
+static void esp_pci_io_write(void *opaque, target_phys_addr_t addr,
+                             uint64_t val, unsigned int size)
+{
+    PCIESPState *pci = opaque;
+
+    if (size < 4 || addr & 3) {
+        /* need to upgrade request: we only support 4-bytes accesses */
+        uint32_t current = 0, mask;
+        int shift;
+
+        if (addr < 0x40) {
+            current = pci->esp.wregs[addr >> 2];
+        } else if (addr < 0x60) {
+            current = pci->dma_regs[(addr - 0x40) >> 2];
+        } else if (addr < 0x74) {
+            current = pci->sbac;
+        }
+
+        shift = (4 - size) * 8;
+        mask = (~(uint32_t)0 << shift) >> shift;
+
+        shift = ((4 - (addr & 3)) & 3) * 8;
+        val <<= shift;
+        val |= current & ~(mask << shift);
+        addr &= ~3;
+        size = 4;
+    }
+
+    if (addr < 0x40) {
+        /* SCSI core reg */
+        esp_reg_write(&pci->esp, addr >> 2, val);
+    } else if (addr < 0x60) {
+        /* PCI DMA CCB */
+        esp_pci_dma_write(pci, (addr - 0x40) >> 2, val);
+    } else if (addr == 0x70) {
+        /* DMA SCSI Bus and control */
+        trace_esp_pci_sbac_write(pci->sbac, val);
+        pci->sbac = val;
+    } else {
+        trace_esp_pci_error_invalid_write((int)addr);
+    }
+}
+
+static uint64_t esp_pci_io_read(void *opaque, target_phys_addr_t addr,
+                                unsigned int size)
+{
+    PCIESPState *pci = opaque;
+    uint32_t ret;
+
+    if (addr < 0x40) {
+        /* SCSI core reg */
+        ret = esp_reg_read(&pci->esp, addr >> 2);
+    } else if (addr < 0x60) {
+        /* PCI DMA CCB */
+        ret = esp_pci_dma_read(pci, (addr - 0x40) >> 2);
+    } else if (addr == 0x70) {
+        /* DMA SCSI Bus and control */
+        trace_esp_pci_sbac_read(pci->sbac);
+        ret = pci->sbac;
+    } else {
+        /* Invalid region */
+        trace_esp_pci_error_invalid_read((int)addr);
+        ret = 0;
+    }
+
+    /* give only requested data */
+    ret >>= (addr & 3) * 8;
+    ret &= ~(~(uint64_t)0 << (8 * size));
+
+    return ret;
+}
+
+static void esp_pci_dma_memory_rw(PCIESPState *pci, uint8_t *buf, int len,
+                                  DMADirection dir)
+{
+    dma_addr_t addr;
+    DMADirection expected_dir;
+
+    if (pci->dma_regs[DMA_CMD] & DMA_CMD_DIR) {
+        expected_dir = DMA_DIRECTION_FROM_DEVICE;
+    } else {
+        expected_dir = DMA_DIRECTION_TO_DEVICE;
+    }
+
+    if (dir != expected_dir) {
+        trace_esp_pci_error_invalid_dma_direction();
+        return;
+    }
+
+    if (pci->dma_regs[DMA_STAT] & DMA_CMD_MDL) {
+        qemu_log_mask(LOG_UNIMP, "am53c974: MDL transfer not implemented\n");
+    }
+
+    addr = pci->dma_regs[DMA_SPA];
+    if (pci->dma_regs[DMA_WBC] < len) {
+        len = pci->dma_regs[DMA_WBC];
+    }
+
+    pci_dma_rw(&pci->dev, addr, buf, len, dir);
+
+    /* update status registers */
+    pci->dma_regs[DMA_WBC] -= len;
+    pci->dma_regs[DMA_WAC] += len;
+}
+
+static void esp_pci_dma_memory_read(void *opaque, uint8_t *buf, int len)
+{
+    PCIESPState *pci = opaque;
+    esp_pci_dma_memory_rw(pci, buf, len, DMA_DIRECTION_TO_DEVICE);
+}
+
+static void esp_pci_dma_memory_write(void *opaque, uint8_t *buf, int len)
+{
+    PCIESPState *pci = opaque;
+    esp_pci_dma_memory_rw(pci, buf, len, DMA_DIRECTION_FROM_DEVICE);
+}
+
+static const MemoryRegionOps esp_pci_io_ops = {
+    .read = esp_pci_io_read,
+    .write = esp_pci_io_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 4,
+    },
+};
+
+static void esp_pci_hard_reset(DeviceState *dev)
+{
+    PCIESPState *pci = DO_UPCAST(PCIESPState, dev.qdev, dev);
+    esp_hard_reset(&pci->esp);
+    pci->dma_regs[DMA_CMD] &= ~(DMA_CMD_DIR | DMA_CMD_INTE_D | DMA_CMD_INTE_P
+                              | DMA_CMD_MDL | DMA_CMD_DIAG | DMA_CMD_MASK);
+    pci->dma_regs[DMA_WBC] &= ~0xffff;
+    pci->dma_regs[DMA_WAC] = 0xffffffff;
+    pci->dma_regs[DMA_STAT] &= ~(DMA_STAT_BCMBLT | DMA_STAT_SCSIINT
+                               | DMA_STAT_DONE | DMA_STAT_ABORT
+                               | DMA_STAT_ERROR);
+    pci->dma_regs[DMA_WMAC] = 0xfffffffd;
+}
+
+static const VMStateDescription vmstate_esp_pci_scsi = {
+    .name = "pciespscsi",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields = (VMStateField[]) {
+        VMSTATE_PCI_DEVICE(dev, PCIESPState),
+        VMSTATE_BUFFER_UNSAFE(dma_regs, PCIESPState, 0, 8 * sizeof(uint32_t)),
+        VMSTATE_STRUCT(esp, PCIESPState, 0, vmstate_esp, ESPState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void esp_pci_command_complete(SCSIRequest *req, uint32_t status,
+                                     size_t resid)
+{
+    ESPState *s = req->hba_private;
+    PCIESPState *pci = container_of(s, PCIESPState, esp);
+
+    esp_command_complete(req, status, resid);
+    pci->dma_regs[DMA_WBC] = 0;
+    pci->dma_regs[DMA_STAT] |= DMA_STAT_DONE;
+}
+
+static const struct SCSIBusInfo esp_pci_scsi_info = {
+    .tcq = false,
+    .max_target = ESP_MAX_DEVS,
+    .max_lun = 7,
+
+    .transfer_data = esp_transfer_data,
+    .complete = esp_pci_command_complete,
+    .cancel = esp_request_cancelled,
+};
+
+static int esp_pci_scsi_init(PCIDevice *dev)
+{
+    PCIESPState *pci = DO_UPCAST(PCIESPState, dev, dev);
+    ESPState *s = &pci->esp;
+    uint8_t *pci_conf;
+
+    pci_conf = pci->dev.config;
+
+    /* Interrupt pin A */
+    pci_conf[PCI_INTERRUPT_PIN] = 0x01;
+
+    s->dma_memory_read = esp_pci_dma_memory_read;
+    s->dma_memory_write = esp_pci_dma_memory_write;
+    s->dma_opaque = pci;
+    s->chip_id = TCHI_AM53C974;
+    memory_region_init_io(&pci->io, &esp_pci_io_ops, pci, "esp-io", 0x80);
+
+    pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &pci->io);
+    s->irq = pci->dev.irq[0];
+
+    scsi_bus_new(&s->bus, &dev->qdev, &esp_pci_scsi_info);
+    if (!dev->qdev.hotplugged) {
+        return scsi_bus_legacy_handle_cmdline(&s->bus);
+    }
+    return 0;
+}
+
+static void esp_pci_scsi_uninit(PCIDevice *d)
+{
+    PCIESPState *pci = DO_UPCAST(PCIESPState, dev, d);
+
+    memory_region_destroy(&pci->io);
+}
+
+static void esp_pci_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = esp_pci_scsi_init;
+    k->exit = esp_pci_scsi_uninit;
+    k->vendor_id = PCI_VENDOR_ID_AMD;
+    k->device_id = PCI_DEVICE_ID_AMD_SCSI;
+    k->revision = 0x10;
+    k->class_id = PCI_CLASS_STORAGE_SCSI;
+    dc->desc = "AMD Am53c974 PCscsi-PCI SCSI adapter";
+    dc->reset = esp_pci_hard_reset;
+    dc->vmsd = &vmstate_esp_pci_scsi;
+}
+
+static const TypeInfo esp_pci_info = {
+    .name = TYPE_AM53C974_DEVICE,
+    .parent = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIESPState),
+    .class_init = esp_pci_class_init,
+};
+
+typedef struct {
+    PCIESPState pci;
+    eeprom_t *eeprom;
+} DC390State;
+
+#define TYPE_DC390_DEVICE "dc390"
+#define DC390(obj) \
+    OBJECT_CHECK(DC390State, obj, TYPE_DC390_DEVICE)
+
+#define EE_ADAPT_SCSI_ID 64
+#define EE_MODE2         65
+#define EE_DELAY         66
+#define EE_TAG_CMD_NUM   67
+#define EE_ADAPT_OPTIONS 68
+#define EE_BOOT_SCSI_ID  69
+#define EE_BOOT_SCSI_LUN 70
+#define EE_CHKSUM1       126
+#define EE_CHKSUM2       127
+
+#define EE_ADAPT_OPTION_F6_F8_AT_BOOT   0x01
+#define EE_ADAPT_OPTION_BOOT_FROM_CDROM 0x02
+#define EE_ADAPT_OPTION_INT13           0x04
+#define EE_ADAPT_OPTION_SCAM_SUPPORT    0x08
+
+
+static uint32_t dc390_read_config(PCIDevice *dev, uint32_t addr, int l)
+{
+    DC390State *pci = DC390(dev);
+    uint32_t val;
+
+    val = pci_default_read_config(dev, addr, l);
+
+    if (addr == 0x00 && l == 1) {
+        /* First byte of address space is AND-ed with EEPROM DO line */
+        if (!eeprom93xx_read(pci->eeprom)) {
+            val &= ~0xff;
+        }
+    }
+
+    return val;
+}
+
+static void dc390_write_config(PCIDevice *dev,
+                               uint32_t addr, uint32_t val, int l)
+{
+    DC390State *pci = DC390(dev);
+    if (addr == 0x80) {
+        /* EEPROM write */
+        int eesk = val & 0x80 ? 1 : 0;
+        int eedi = val & 0x40 ? 1 : 0;
+        eeprom93xx_write(pci->eeprom, 1, eesk, eedi);
+    } else if (addr == 0xc0) {
+        /* EEPROM CS low */
+        eeprom93xx_write(pci->eeprom, 0, 0, 0);
+    } else {
+        pci_default_write_config(dev, addr, val, l);
+    }
+}
+
+static int dc390_scsi_init(PCIDevice *dev)
+{
+    DC390State *pci = DC390(dev);
+    uint8_t *contents;
+    uint16_t chksum = 0;
+    int i, ret;
+
+    /* init base class */
+    ret = esp_pci_scsi_init(dev);
+    if (ret < 0) {
+        return ret;
+    }
+
+    /* EEPROM */
+    pci->eeprom = eeprom93xx_new(DEVICE(dev), 64);
+
+    /* set default eeprom values */
+    contents = (uint8_t *)eeprom93xx_data(pci->eeprom);
+
+    for (i = 0; i < 16; i++) {
+        contents[i * 2] = 0x57;
+        contents[i * 2 + 1] = 0x00;
+    }
+    contents[EE_ADAPT_SCSI_ID] = 7;
+    contents[EE_MODE2] = 0x0f;
+    contents[EE_TAG_CMD_NUM] = 0x04;
+    contents[EE_ADAPT_OPTIONS] = EE_ADAPT_OPTION_F6_F8_AT_BOOT
+                               | EE_ADAPT_OPTION_BOOT_FROM_CDROM
+                               | EE_ADAPT_OPTION_INT13;
+
+    /* update eeprom checksum */
+    for (i = 0; i < EE_CHKSUM1; i += 2) {
+        chksum += contents[i] + (((uint16_t)contents[i + 1]) << 8);
+    }
+    chksum = 0x1234 - chksum;
+    contents[EE_CHKSUM1] = chksum & 0xff;
+    contents[EE_CHKSUM2] = chksum >> 8;
+
+    return 0;
+}
+
+static void dc390_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = dc390_scsi_init;
+    k->config_read = dc390_read_config;
+    k->config_write = dc390_write_config;
+    dc->desc = "Tekram DC-390 SCSI adapter";
+}
+
+static const TypeInfo dc390_info = {
+    .name = "dc390",
+    .parent = TYPE_AM53C974_DEVICE,
+    .instance_size = sizeof(DC390State),
+    .class_init = dc390_class_init,
+};
+
+static void esp_pci_register_types(void)
+{
+    type_register_static(&esp_pci_info);
+    type_register_static(&dc390_info);
+}
+
+type_init(esp_pci_register_types)
diff --git a/hw/esp.c b/hw/esp.c
index 77f57076c7..52c46e615f 100644
--- a/hw/esp.c
+++ b/hw/esp.c
@@ -24,8 +24,6 @@
  */
 
 #include "sysbus.h"
-#include "pci.h"
-#include "scsi.h"
 #include "esp.h"
 #include "trace.h"
 #include "qemu-log.h"
@@ -38,114 +36,6 @@
  * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR53C9X.txt
  */
 
-#define ESP_REGS 16
-#define TI_BUFSZ 16
-
-typedef struct ESPState ESPState;
-
-struct ESPState {
-    uint8_t rregs[ESP_REGS];
-    uint8_t wregs[ESP_REGS];
-    qemu_irq irq;
-    uint8_t chip_id;
-    int32_t ti_size;
-    uint32_t ti_rptr, ti_wptr;
-    uint32_t status;
-    uint32_t dma;
-    uint8_t ti_buf[TI_BUFSZ];
-    SCSIBus bus;
-    SCSIDevice *current_dev;
-    SCSIRequest *current_req;
-    uint8_t cmdbuf[TI_BUFSZ];
-    uint32_t cmdlen;
-    uint32_t do_cmd;
-
-    /* The amount of data left in the current DMA transfer.  */
-    uint32_t dma_left;
-    /* The size of the current DMA transfer.  Zero if no transfer is in
-       progress.  */
-    uint32_t dma_counter;
-    int dma_enabled;
-
-    uint32_t async_len;
-    uint8_t *async_buf;
-
-    ESPDMAMemoryReadWriteFunc dma_memory_read;
-    ESPDMAMemoryReadWriteFunc dma_memory_write;
-    void *dma_opaque;
-    void (*dma_cb)(ESPState *s);
-};
-
-#define ESP_TCLO   0x0
-#define ESP_TCMID  0x1
-#define ESP_FIFO   0x2
-#define ESP_CMD    0x3
-#define ESP_RSTAT  0x4
-#define ESP_WBUSID 0x4
-#define ESP_RINTR  0x5
-#define ESP_WSEL   0x5
-#define ESP_RSEQ   0x6
-#define ESP_WSYNTP 0x6
-#define ESP_RFLAGS 0x7
-#define ESP_WSYNO  0x7
-#define ESP_CFG1   0x8
-#define ESP_RRES1  0x9
-#define ESP_WCCF   0x9
-#define ESP_RRES2  0xa
-#define ESP_WTEST  0xa
-#define ESP_CFG2   0xb
-#define ESP_CFG3   0xc
-#define ESP_RES3   0xd
-#define ESP_TCHI   0xe
-#define ESP_RES4   0xf
-
-#define CMD_DMA 0x80
-#define CMD_CMD 0x7f
-
-#define CMD_NOP      0x00
-#define CMD_FLUSH    0x01
-#define CMD_RESET    0x02
-#define CMD_BUSRESET 0x03
-#define CMD_TI       0x10
-#define CMD_ICCS     0x11
-#define CMD_MSGACC   0x12
-#define CMD_PAD      0x18
-#define CMD_SATN     0x1a
-#define CMD_RSTATN   0x1b
-#define CMD_SEL      0x41
-#define CMD_SELATN   0x42
-#define CMD_SELATNS  0x43
-#define CMD_ENSEL    0x44
-#define CMD_DISSEL   0x45
-
-#define STAT_DO 0x00
-#define STAT_DI 0x01
-#define STAT_CD 0x02
-#define STAT_ST 0x03
-#define STAT_MO 0x06
-#define STAT_MI 0x07
-#define STAT_PIO_MASK 0x06
-
-#define STAT_TC 0x10
-#define STAT_PE 0x20
-#define STAT_GE 0x40
-#define STAT_INT 0x80
-
-#define BUSID_DID 0x07
-
-#define INTR_FC 0x08
-#define INTR_BS 0x10
-#define INTR_DC 0x20
-#define INTR_RST 0x80
-
-#define SEQ_0 0x0
-#define SEQ_CD 0x4
-
-#define CFG1_RESREPT 0x40
-
-#define TCHI_FAS100A 0x4
-#define TCHI_AM53C974 0x12
-
 static void esp_raise_irq(ESPState *s)
 {
     if (!(s->rregs[ESP_RSTAT] & STAT_INT)) {
@@ -164,7 +54,7 @@ static void esp_lower_irq(ESPState *s)
     }
 }
 
-static void esp_dma_enable(ESPState *s, int irq, int level)
+void esp_dma_enable(ESPState *s, int irq, int level)
 {
     if (level) {
         s->dma_enabled = 1;
@@ -179,7 +69,7 @@ static void esp_dma_enable(ESPState *s, int irq, int level)
     }
 }
 
-static void esp_request_cancelled(SCSIRequest *req)
+void esp_request_cancelled(SCSIRequest *req)
 {
     ESPState *s = req->hba_private;
 
@@ -388,7 +278,7 @@ static void esp_do_dma(ESPState *s)
     esp_dma_done(s);
 }
 
-static void esp_command_complete(SCSIRequest *req, uint32_t status,
+void esp_command_complete(SCSIRequest *req, uint32_t status,
                                  size_t resid)
 {
     ESPState *s = req->hba_private;
@@ -413,7 +303,7 @@ static void esp_command_complete(SCSIRequest *req, uint32_t status,
     }
 }
 
-static void esp_transfer_data(SCSIRequest *req, uint32_t len)
+void esp_transfer_data(SCSIRequest *req, uint32_t len)
 {
     ESPState *s = req->hba_private;
 
@@ -465,7 +355,7 @@ static void handle_ti(ESPState *s)
     }
 }
 
-static void esp_hard_reset(ESPState *s)
+void esp_hard_reset(ESPState *s)
 {
     memset(s->rregs, 0, ESP_REGS);
     memset(s->wregs, 0, ESP_REGS);
@@ -493,7 +383,7 @@ static void parent_esp_reset(ESPState *s, int irq, int level)
     }
 }
 
-static uint64_t esp_reg_read(ESPState *s, uint32_t saddr)
+uint64_t esp_reg_read(ESPState *s, uint32_t saddr)
 {
     uint32_t old_val;
 
@@ -533,7 +423,7 @@ static uint64_t esp_reg_read(ESPState *s, uint32_t saddr)
     return s->rregs[saddr];
 }
 
-static void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
+void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
 {
     trace_esp_mem_writeb(saddr, s->wregs[saddr], val);
     switch (saddr) {
@@ -660,7 +550,7 @@ static bool esp_mem_accepts(void *opaque, target_phys_addr_t addr,
     return (size == 1) || (is_write && size == 4);
 }
 
-static const VMStateDescription vmstate_esp = {
+const VMStateDescription vmstate_esp = {
     .name ="esp",
     .version_id = 3,
     .minimum_version_id = 3,
@@ -823,370 +713,9 @@ static const TypeInfo sysbus_esp_info = {
     .class_init    = sysbus_esp_class_init,
 };
 
-#define DMA_CMD   0x0
-#define DMA_STC   0x1
-#define DMA_SPA   0x2
-#define DMA_WBC   0x3
-#define DMA_WAC   0x4
-#define DMA_STAT  0x5
-#define DMA_SMDLA 0x6
-#define DMA_WMAC  0x7
-
-#define DMA_CMD_MASK   0x03
-#define DMA_CMD_DIAG   0x04
-#define DMA_CMD_MDL    0x10
-#define DMA_CMD_INTE_P 0x20
-#define DMA_CMD_INTE_D 0x40
-#define DMA_CMD_DIR    0x80
-
-#define DMA_STAT_PWDN    0x01
-#define DMA_STAT_ERROR   0x02
-#define DMA_STAT_ABORT   0x04
-#define DMA_STAT_DONE    0x08
-#define DMA_STAT_SCSIINT 0x10
-#define DMA_STAT_BCMBLT  0x20
-
-#define SBAC_STATUS 0x1000
-
-typedef struct PCIESPState {
-    PCIDevice dev;
-    MemoryRegion io;
-    uint32_t dma_regs[8];
-    uint32_t sbac;
-    ESPState esp;
-} PCIESPState;
-
-static void esp_pci_handle_idle(PCIESPState *pci, uint32_t val)
-{
-    trace_esp_pci_dma_idle(val);
-    esp_dma_enable(&pci->esp, 0, 0);
-}
-
-static void esp_pci_handle_blast(PCIESPState *pci, uint32_t val)
-{
-    trace_esp_pci_dma_blast(val);
-    qemu_log_mask(LOG_UNIMP, "am53c974: cmd BLAST not implemented\n");
-}
-
-static void esp_pci_handle_abort(PCIESPState *pci, uint32_t val)
-{
-    trace_esp_pci_dma_abort(val);
-    if (pci->esp.current_req) {
-        scsi_req_cancel(pci->esp.current_req);
-    }
-}
-
-static void esp_pci_handle_start(PCIESPState *pci, uint32_t val)
-{
-    trace_esp_pci_dma_start(val);
-
-    pci->dma_regs[DMA_WBC] = pci->dma_regs[DMA_STC];
-    pci->dma_regs[DMA_WAC] = pci->dma_regs[DMA_SPA];
-    pci->dma_regs[DMA_WMAC] = pci->dma_regs[DMA_SMDLA];
-
-    pci->dma_regs[DMA_STAT] &= ~(DMA_STAT_BCMBLT | DMA_STAT_SCSIINT
-                               | DMA_STAT_DONE | DMA_STAT_ABORT
-                               | DMA_STAT_ERROR | DMA_STAT_PWDN);
-
-    esp_dma_enable(&pci->esp, 0, 1);
-}
-
-static void esp_pci_dma_write(PCIESPState *pci, uint32_t saddr, uint32_t val)
-{
-    trace_esp_pci_dma_write(saddr, pci->dma_regs[saddr], val);
-    switch (saddr) {
-    case DMA_CMD:
-        pci->dma_regs[saddr] = val;
-        switch (val & DMA_CMD_MASK) {
-        case 0x0: /* IDLE */
-            esp_pci_handle_idle(pci, val);
-            break;
-        case 0x1: /* BLAST */
-            esp_pci_handle_blast(pci, val);
-            break;
-        case 0x2: /* ABORT */
-            esp_pci_handle_abort(pci, val);
-            break;
-        case 0x3: /* START */
-            esp_pci_handle_start(pci, val);
-            break;
-        default: /* can't happen */
-            abort();
-        }
-        break;
-    case DMA_STC:
-    case DMA_SPA:
-    case DMA_SMDLA:
-        pci->dma_regs[saddr] = val;
-        break;
-    case DMA_STAT:
-        if (!(pci->sbac & SBAC_STATUS)) {
-            /* clear some bits on write */
-            uint32_t mask = DMA_STAT_ERROR | DMA_STAT_ABORT | DMA_STAT_DONE;
-            pci->dma_regs[DMA_STAT] &= ~(val & mask);
-        }
-        break;
-    default:
-        trace_esp_pci_error_invalid_write_dma(val, saddr);
-        return;
-    }
-}
-
-static uint32_t esp_pci_dma_read(PCIESPState *pci, uint32_t saddr)
-{
-    uint32_t val;
-
-    val = pci->dma_regs[saddr];
-    if (saddr == DMA_STAT) {
-        if (pci->esp.rregs[ESP_RSTAT] & STAT_INT) {
-            val |= DMA_STAT_SCSIINT;
-        }
-        if (pci->sbac & SBAC_STATUS) {
-            pci->dma_regs[DMA_STAT] &= ~(DMA_STAT_ERROR | DMA_STAT_ABORT |
-                                         DMA_STAT_DONE);
-        }
-    }
-
-    trace_esp_pci_dma_read(saddr, val);
-    return val;
-}
-
-static void esp_pci_io_write(void *opaque, target_phys_addr_t addr,
-                             uint64_t val, unsigned int size)
-{
-    PCIESPState *pci = opaque;
-
-    if (size < 4 || addr & 3) {
-        /* need to upgrade request: we only support 4-bytes accesses */
-        uint32_t current = 0, mask;
-        int shift;
-
-        if (addr < 0x40) {
-            current = pci->esp.wregs[addr >> 2];
-        } else if (addr < 0x60) {
-            current = pci->dma_regs[(addr - 0x40) >> 2];
-        } else if (addr < 0x74) {
-            current = pci->sbac;
-        }
-
-        shift = (4 - size) * 8;
-        mask = (~(uint32_t)0 << shift) >> shift;
-
-        shift = ((4 - (addr & 3)) & 3) * 8;
-        val <<= shift;
-        val |= current & ~(mask << shift);
-        addr &= ~3;
-        size = 4;
-    }
-
-    if (addr < 0x40) {
-        /* SCSI core reg */
-        esp_reg_write(&pci->esp, addr >> 2, val);
-    } else if (addr < 0x60) {
-        /* PCI DMA CCB */
-        esp_pci_dma_write(pci, (addr - 0x40) >> 2, val);
-    } else if (addr == 0x70) {
-        /* DMA SCSI Bus and control */
-        trace_esp_pci_sbac_write(pci->sbac, val);
-        pci->sbac = val;
-    } else {
-        trace_esp_pci_error_invalid_write((int)addr);
-    }
-}
-
-static uint64_t esp_pci_io_read(void *opaque, target_phys_addr_t addr,
-                                unsigned int size)
-{
-    PCIESPState *pci = opaque;
-    uint32_t ret;
-
-    if (addr < 0x40) {
-        /* SCSI core reg */
-        ret = esp_reg_read(&pci->esp, addr >> 2);
-    } else if (addr < 0x60) {
-        /* PCI DMA CCB */
-        ret = esp_pci_dma_read(pci, (addr - 0x40) >> 2);
-    } else if (addr == 0x70) {
-        /* DMA SCSI Bus and control */
-        trace_esp_pci_sbac_read(pci->sbac);
-        ret = pci->sbac;
-    } else {
-        /* Invalid region */
-        trace_esp_pci_error_invalid_read((int)addr);
-        ret = 0;
-    }
-
-    /* give only requested data */
-    ret >>= (addr & 3) * 8;
-    ret &= ~(~(uint64_t)0 << (8 * size));
-
-    return ret;
-}
-
-static void esp_pci_dma_memory_rw(PCIESPState *pci, uint8_t *buf, int len,
-                                  DMADirection dir)
-{
-    dma_addr_t addr;
-    DMADirection expected_dir;
-
-    if (pci->dma_regs[DMA_CMD] & DMA_CMD_DIR) {
-        expected_dir = DMA_DIRECTION_FROM_DEVICE;
-    } else {
-        expected_dir = DMA_DIRECTION_TO_DEVICE;
-    }
-
-    if (dir != expected_dir) {
-        trace_esp_pci_error_invalid_dma_direction();
-        return;
-    }
-
-    if (pci->dma_regs[DMA_STAT] & DMA_CMD_MDL) {
-        qemu_log_mask(LOG_UNIMP, "am53c974: MDL transfer not implemented\n");
-    }
-
-    addr = pci->dma_regs[DMA_SPA];
-    if (pci->dma_regs[DMA_WBC] < len) {
-        len = pci->dma_regs[DMA_WBC];
-    }
-
-    pci_dma_rw(&pci->dev, addr, buf, len, dir);
-
-    /* update status registers */
-    pci->dma_regs[DMA_WBC] -= len;
-    pci->dma_regs[DMA_WAC] += len;
-}
-
-static void esp_pci_dma_memory_read(void *opaque, uint8_t *buf, int len)
-{
-    PCIESPState *pci = opaque;
-    esp_pci_dma_memory_rw(pci, buf, len, DMA_DIRECTION_TO_DEVICE);
-}
-
-static void esp_pci_dma_memory_write(void *opaque, uint8_t *buf, int len)
-{
-    PCIESPState *pci = opaque;
-    esp_pci_dma_memory_rw(pci, buf, len, DMA_DIRECTION_FROM_DEVICE);
-}
-
-static const MemoryRegionOps esp_pci_io_ops = {
-    .read = esp_pci_io_read,
-    .write = esp_pci_io_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-    .impl = {
-        .min_access_size = 1,
-        .max_access_size = 4,
-    },
-};
-
-static void esp_pci_hard_reset(DeviceState *dev)
-{
-    PCIESPState *pci = DO_UPCAST(PCIESPState, dev.qdev, dev);
-    esp_hard_reset(&pci->esp);
-    pci->dma_regs[DMA_CMD] &= ~(DMA_CMD_DIR | DMA_CMD_INTE_D | DMA_CMD_INTE_P
-                              | DMA_CMD_MDL | DMA_CMD_DIAG | DMA_CMD_MASK);
-    pci->dma_regs[DMA_WBC] &= ~0xffff;
-    pci->dma_regs[DMA_WAC] = 0xffffffff;
-    pci->dma_regs[DMA_STAT] &= ~(DMA_STAT_BCMBLT | DMA_STAT_SCSIINT
-                               | DMA_STAT_DONE | DMA_STAT_ABORT
-                               | DMA_STAT_ERROR);
-    pci->dma_regs[DMA_WMAC] = 0xfffffffd;
-}
-
-static const VMStateDescription vmstate_esp_pci_scsi = {
-    .name = "pciespscsi",
-    .version_id = 0,
-    .minimum_version_id = 0,
-    .minimum_version_id_old = 0,
-    .fields = (VMStateField[]) {
-        VMSTATE_PCI_DEVICE(dev, PCIESPState),
-        VMSTATE_BUFFER_UNSAFE(dma_regs, PCIESPState, 0, 8 * sizeof(uint32_t)),
-        VMSTATE_STRUCT(esp, PCIESPState, 0, vmstate_esp, ESPState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void esp_pci_command_complete(SCSIRequest *req, uint32_t status,
-                                     size_t resid)
-{
-    ESPState *s = req->hba_private;
-    PCIESPState *pci = container_of(s, PCIESPState, esp);
-
-    esp_command_complete(req, status, resid);
-    pci->dma_regs[DMA_WBC] = 0;
-    pci->dma_regs[DMA_STAT] |= DMA_STAT_DONE;
-}
-
-static const struct SCSIBusInfo esp_pci_scsi_info = {
-    .tcq = false,
-    .max_target = ESP_MAX_DEVS,
-    .max_lun = 7,
-
-    .transfer_data = esp_transfer_data,
-    .complete = esp_pci_command_complete,
-    .cancel = esp_request_cancelled,
-};
-
-static int esp_pci_scsi_init(PCIDevice *dev)
-{
-    PCIESPState *pci = DO_UPCAST(PCIESPState, dev, dev);
-    ESPState *s = &pci->esp;
-    uint8_t *pci_conf;
-
-    pci_conf = pci->dev.config;
-
-    /* Interrupt pin A */
-    pci_conf[PCI_INTERRUPT_PIN] = 0x01;
-
-    s->dma_memory_read = esp_pci_dma_memory_read;
-    s->dma_memory_write = esp_pci_dma_memory_write;
-    s->dma_opaque = pci;
-    s->chip_id = TCHI_AM53C974;
-    memory_region_init_io(&pci->io, &esp_pci_io_ops, pci, "esp-io", 0x80);
-
-    pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &pci->io);
-    s->irq = pci->dev.irq[0];
-
-    scsi_bus_new(&s->bus, &dev->qdev, &esp_pci_scsi_info);
-    if (!dev->qdev.hotplugged) {
-        return scsi_bus_legacy_handle_cmdline(&s->bus);
-    }
-    return 0;
-}
-
-static void esp_pci_scsi_uninit(PCIDevice *d)
-{
-    PCIESPState *pci = DO_UPCAST(PCIESPState, dev, d);
-
-    memory_region_destroy(&pci->io);
-}
-
-static void esp_pci_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->init = esp_pci_scsi_init;
-    k->exit = esp_pci_scsi_uninit;
-    k->vendor_id = PCI_VENDOR_ID_AMD;
-    k->device_id = PCI_DEVICE_ID_AMD_SCSI;
-    k->revision = 0x10;
-    k->class_id = PCI_CLASS_STORAGE_SCSI;
-    dc->desc = "AMD Am53c974 PCscsi-PCI SCSI adapter";
-    dc->reset = esp_pci_hard_reset;
-    dc->vmsd = &vmstate_esp_pci_scsi;
-}
-
-static const TypeInfo esp_pci_info = {
-    .name = "am53c974",
-    .parent = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(PCIESPState),
-    .class_init = esp_pci_class_init,
-};
-
 static void esp_register_types(void)
 {
     type_register_static(&sysbus_esp_info);
-    type_register_static(&esp_pci_info);
 }
 
 type_init(esp_register_types)
diff --git a/hw/esp.h b/hw/esp.h
index 62bfd4d129..fa855e2fdf 100644
--- a/hw/esp.h
+++ b/hw/esp.h
@@ -1,6 +1,8 @@
 #ifndef QEMU_HW_ESP_H
 #define QEMU_HW_ESP_H
 
+#include "scsi.h"
+
 /* esp.c */
 #define ESP_MAX_DEVS 7
 typedef void (*ESPDMAMemoryReadWriteFunc)(void *opaque, uint8_t *buf, int len);
@@ -10,4 +12,121 @@ void esp_init(target_phys_addr_t espaddr, int it_shift,
               void *dma_opaque, qemu_irq irq, qemu_irq *reset,
               qemu_irq *dma_enable);
 
+#define ESP_REGS 16
+#define TI_BUFSZ 16
+
+typedef struct ESPState ESPState;
+
+struct ESPState {
+    uint8_t rregs[ESP_REGS];
+    uint8_t wregs[ESP_REGS];
+    qemu_irq irq;
+    uint8_t chip_id;
+    int32_t ti_size;
+    uint32_t ti_rptr, ti_wptr;
+    uint32_t status;
+    uint32_t dma;
+    uint8_t ti_buf[TI_BUFSZ];
+    SCSIBus bus;
+    SCSIDevice *current_dev;
+    SCSIRequest *current_req;
+    uint8_t cmdbuf[TI_BUFSZ];
+    uint32_t cmdlen;
+    uint32_t do_cmd;
+
+    /* The amount of data left in the current DMA transfer.  */
+    uint32_t dma_left;
+    /* The size of the current DMA transfer.  Zero if no transfer is in
+       progress.  */
+    uint32_t dma_counter;
+    int dma_enabled;
+
+    uint32_t async_len;
+    uint8_t *async_buf;
+
+    ESPDMAMemoryReadWriteFunc dma_memory_read;
+    ESPDMAMemoryReadWriteFunc dma_memory_write;
+    void *dma_opaque;
+    void (*dma_cb)(ESPState *s);
+};
+
+#define ESP_TCLO   0x0
+#define ESP_TCMID  0x1
+#define ESP_FIFO   0x2
+#define ESP_CMD    0x3
+#define ESP_RSTAT  0x4
+#define ESP_WBUSID 0x4
+#define ESP_RINTR  0x5
+#define ESP_WSEL   0x5
+#define ESP_RSEQ   0x6
+#define ESP_WSYNTP 0x6
+#define ESP_RFLAGS 0x7
+#define ESP_WSYNO  0x7
+#define ESP_CFG1   0x8
+#define ESP_RRES1  0x9
+#define ESP_WCCF   0x9
+#define ESP_RRES2  0xa
+#define ESP_WTEST  0xa
+#define ESP_CFG2   0xb
+#define ESP_CFG3   0xc
+#define ESP_RES3   0xd
+#define ESP_TCHI   0xe
+#define ESP_RES4   0xf
+
+#define CMD_DMA 0x80
+#define CMD_CMD 0x7f
+
+#define CMD_NOP      0x00
+#define CMD_FLUSH    0x01
+#define CMD_RESET    0x02
+#define CMD_BUSRESET 0x03
+#define CMD_TI       0x10
+#define CMD_ICCS     0x11
+#define CMD_MSGACC   0x12
+#define CMD_PAD      0x18
+#define CMD_SATN     0x1a
+#define CMD_RSTATN   0x1b
+#define CMD_SEL      0x41
+#define CMD_SELATN   0x42
+#define CMD_SELATNS  0x43
+#define CMD_ENSEL    0x44
+#define CMD_DISSEL   0x45
+
+#define STAT_DO 0x00
+#define STAT_DI 0x01
+#define STAT_CD 0x02
+#define STAT_ST 0x03
+#define STAT_MO 0x06
+#define STAT_MI 0x07
+#define STAT_PIO_MASK 0x06
+
+#define STAT_TC 0x10
+#define STAT_PE 0x20
+#define STAT_GE 0x40
+#define STAT_INT 0x80
+
+#define BUSID_DID 0x07
+
+#define INTR_FC 0x08
+#define INTR_BS 0x10
+#define INTR_DC 0x20
+#define INTR_RST 0x80
+
+#define SEQ_0 0x0
+#define SEQ_CD 0x4
+
+#define CFG1_RESREPT 0x40
+
+#define TCHI_FAS100A 0x4
+#define TCHI_AM53C974 0x12
+
+void esp_dma_enable(ESPState *s, int irq, int level);
+void esp_request_cancelled(SCSIRequest *req);
+void esp_command_complete(SCSIRequest *req, uint32_t status, size_t resid);
+void esp_transfer_data(SCSIRequest *req, uint32_t len);
+void esp_hard_reset(ESPState *s);
+uint64_t esp_reg_read(ESPState *s, uint32_t saddr);
+void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val);
+extern const VMStateDescription vmstate_esp;
+
 #endif
diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index efea93f0b4..5ea3cadb01 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -636,7 +636,7 @@ static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis)
     }
 }
 
-static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist)
+static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist, int offset)
 {
     AHCICmdHdr *cmd = ad->cur_cmd;
     uint32_t opts = le32_to_cpu(cmd->opts);
@@ -647,6 +647,10 @@ static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist)
     uint8_t *prdt;
     int i;
     int r = 0;
+    int sum = 0;
+    int off_idx = -1;
+    int off_pos = -1;
+    int tbl_entry_size;
 
     if (!sglist_alloc_hint) {
         DPRINTF(ad->port_no, "no sg list given by guest: 0x%08x\n", opts);
@@ -669,10 +673,31 @@ static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist)
     /* Get entries in the PRDT, init a qemu sglist accordingly */
     if (sglist_alloc_hint > 0) {
         AHCI_SG *tbl = (AHCI_SG *)prdt;
-
-        qemu_sglist_init(sglist, sglist_alloc_hint, ad->hba->dma);
+        sum = 0;
         for (i = 0; i < sglist_alloc_hint; i++) {
             /* flags_size is zero-based */
+            tbl_entry_size = (le32_to_cpu(tbl[i].flags_size) + 1);
+            if (offset <= (sum + tbl_entry_size)) {
+                off_idx = i;
+                off_pos = offset - sum;
+                break;
+            }
+            sum += tbl_entry_size;
+        }
+        if ((off_idx == -1) || (off_pos < 0) || (off_pos > tbl_entry_size)) {
+            DPRINTF(ad->port_no, "%s: Incorrect offset! "
+                            "off_idx: %d, off_pos: %d\n",
+                            __func__, off_idx, off_pos);
+            r = -1;
+            goto out;
+        }
+
+        qemu_sglist_init(sglist, (sglist_alloc_hint - off_idx), ad->hba->dma);
+        qemu_sglist_add(sglist, le64_to_cpu(tbl[off_idx].addr + off_pos),
+                        le32_to_cpu(tbl[off_idx].flags_size) + 1 - off_pos);
+
+        for (i = off_idx + 1; i < sglist_alloc_hint; i++) {
+            /* flags_size is zero-based */
             qemu_sglist_add(sglist, le64_to_cpu(tbl[i].addr),
                             le32_to_cpu(tbl[i].flags_size) + 1);
         }
@@ -745,7 +770,7 @@ static void process_ncq_command(AHCIState *s, int port, uint8_t *cmd_fis,
             ncq_tfs->lba, ncq_tfs->lba + ncq_tfs->sector_count - 2,
             s->dev[port].port.ifs[0].nb_sectors - 1);
 
-    ahci_populate_sglist(&s->dev[port], &ncq_tfs->sglist);
+    ahci_populate_sglist(&s->dev[port], &ncq_tfs->sglist, 0);
     ncq_tfs->tag = tag;
 
     switch(ncq_fis->command) {
@@ -970,7 +995,7 @@ static int ahci_start_transfer(IDEDMA *dma)
         goto out;
     }
 
-    if (!ahci_populate_sglist(ad, &s->sg)) {
+    if (!ahci_populate_sglist(ad, &s->sg, 0)) {
         has_sglist = 1;
     }
 
@@ -1015,6 +1040,7 @@ static void ahci_start_dma(IDEDMA *dma, IDEState *s,
     DPRINTF(ad->port_no, "\n");
     ad->dma_cb = dma_cb;
     ad->dma_status |= BM_STATUS_DMAING;
+    s->io_buffer_offset = 0;
     dma_cb(s, 0);
 }
 
@@ -1023,7 +1049,7 @@ static int ahci_dma_prepare_buf(IDEDMA *dma, int is_write)
     AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
     IDEState *s = &ad->port.ifs[0];
 
-    ahci_populate_sglist(ad, &s->sg);
+    ahci_populate_sglist(ad, &s->sg, 0);
     s->io_buffer_size = s->sg.size;
 
     DPRINTF(ad->port_no, "len=%#x\n", s->io_buffer_size);
@@ -1037,7 +1063,7 @@ static int ahci_dma_rw_buf(IDEDMA *dma, int is_write)
     uint8_t *p = s->io_buffer + s->io_buffer_index;
     int l = s->io_buffer_size - s->io_buffer_index;
 
-    if (ahci_populate_sglist(ad, &s->sg)) {
+    if (ahci_populate_sglist(ad, &s->sg, s->io_buffer_offset)) {
         return 0;
     }
 
@@ -1047,9 +1073,13 @@ static int ahci_dma_rw_buf(IDEDMA *dma, int is_write)
         dma_buf_write(p, l, &s->sg);
     }
 
+    /* free sglist that was created in ahci_populate_sglist() */
+    qemu_sglist_destroy(&s->sg);
+
     /* update number of transferred bytes */
     ad->cur_cmd->status = cpu_to_le32(le32_to_cpu(ad->cur_cmd->status) + l);
     s->io_buffer_index += l;
+    s->io_buffer_offset += l;
 
     DPRINTF(ad->port_no, "len=%#x\n", l);
 
diff --git a/hw/ide/internal.h b/hw/ide/internal.h
index 7170bd9cd0..bf7d313cf4 100644
--- a/hw/ide/internal.h
+++ b/hw/ide/internal.h
@@ -393,6 +393,7 @@ struct IDEState {
     struct iovec iov;
     QEMUIOVector qiov;
     /* ATA DMA state */
+    int io_buffer_offset;
     int io_buffer_size;
     QEMUSGList sg;
     /* PIO transfer handling */
diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c
index 22e58dfc8a..5ea9b8f4b2 100644
--- a/hw/ide/qdev.c
+++ b/hw/ide/qdev.c
@@ -149,7 +149,8 @@ static int ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind)
     }
 
     blkconf_serial(&dev->conf, &dev->serial);
-    if (blkconf_geometry(&dev->conf, &dev->chs_trans, 65536, 16, 255) < 0) {
+    if (kind != IDE_CD
+        && blkconf_geometry(&dev->conf, &dev->chs_trans, 65536, 16, 255) < 0) {
         return -1;
     }
 
diff --git a/hw/kvm/i8259.c b/hw/kvm/i8259.c
index 94d1b9aa95..1e24cd4f36 100644
--- a/hw/kvm/i8259.c
+++ b/hw/kvm/i8259.c
@@ -94,7 +94,7 @@ static void kvm_pic_set_irq(void *opaque, int irq, int level)
 {
     int delivered;
 
-    delivered = kvm_irqchip_set_irq(kvm_state, irq, level);
+    delivered = kvm_set_irq(kvm_state, irq, level);
     apic_report_irq_delivered(delivered);
 }
 
diff --git a/hw/kvm/ioapic.c b/hw/kvm/ioapic.c
index 3ae3175403..6c3b8fe39a 100644
--- a/hw/kvm/ioapic.c
+++ b/hw/kvm/ioapic.c
@@ -82,7 +82,7 @@ static void kvm_ioapic_set_irq(void *opaque, int irq, int level)
     KVMIOAPICState *s = opaque;
     int delivered;
 
-    delivered = kvm_irqchip_set_irq(kvm_state, s->kvm_gsi_base + irq, level);
+    delivered = kvm_set_irq(kvm_state, s->kvm_gsi_base + irq, level);
     apic_report_irq_delivered(delivered);
 }
 
diff --git a/hw/pc.c b/hw/pc.c
index 81c391cd6a..e8bcfc0b4b 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -42,6 +42,7 @@
 #include "sysbus.h"
 #include "sysemu.h"
 #include "kvm.h"
+#include "kvm_i386.h"
 #include "xen.h"
 #include "blockdev.h"
 #include "hw/block-common.h"
diff --git a/hw/pci-stub.c b/hw/pci-stub.c
index e083191529..134c4484b6 100644
--- a/hw/pci-stub.c
+++ b/hw/pci-stub.c
@@ -34,21 +34,6 @@ static void pci_error_message(Monitor *mon)
     monitor_printf(mon, "PCI devices not supported\n");
 }
 
-void pci_register_bar(PCIDevice *pci_dev, int region_num,
-                      uint8_t type, MemoryRegion *memory)
-{
-}
-
-const VMStateDescription vmstate_pci_device = {
-    .name = "PCIDeviceStub",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_END_OF_LIST()
-    }
-};
-
 int do_pcie_aer_inject_error(Monitor *mon,
                              const QDict *qdict, QObject **ret_data)
 {
diff --git a/hw/petalogix_ml605_mmu.c b/hw/petalogix_ml605_mmu.c
index 6a7d0c0bff..dced648f45 100644
--- a/hw/petalogix_ml605_mmu.c
+++ b/hw/petalogix_ml605_mmu.c
@@ -39,7 +39,8 @@
 
 #include "microblaze_boot.h"
 #include "microblaze_pic_cpu.h"
-#include "xilinx_axidma.h"
+
+#include "stream.h"
 
 #define LMB_BRAM_SIZE  (128 * 1024)
 #define FLASH_SIZE     (32 * 1024 * 1024)
@@ -76,7 +77,7 @@ petalogix_ml605_init(ram_addr_t ram_size,
                           const char *initrd_filename, const char *cpu_model)
 {
     MemoryRegion *address_space_mem = get_system_memory();
-    DeviceState *dev;
+    DeviceState *dev, *dma, *eth0;
     MicroBlazeCPU *cpu;
     CPUMBState *env;
     DriveInfo *dinfo;
@@ -125,15 +126,18 @@ petalogix_ml605_init(ram_addr_t ram_size,
     /* 2 timers at irq 2 @ 100 Mhz.  */
     xilinx_timer_create(TIMER_BASEADDR, irq[2], 0, 100 * 1000000);
 
-    /* axi ethernet and dma initialization. TODO: Dynamically connect them.  */
-    {
-        static struct XilinxDMAConnection dmach;
+    /* axi ethernet and dma initialization. */
+    dma = qdev_create(NULL, "xlnx.axi-dma");
 
-        xilinx_axiethernet_create(&dmach, &nd_table[0], 0x82780000,
-                                  irq[3], 0x1000, 0x1000);
-        xilinx_axiethernetdma_create(&dmach, 0x84600000,
-                                     irq[1], irq[0], 100 * 1000000);
-    }
+    /* FIXME: attach to the sysbus instead */
+    object_property_add_child(container_get(qdev_get_machine(), "/unattached"),
+                                  "xilinx-dma", OBJECT(dma), NULL);
+
+    eth0 = xilinx_axiethernet_create(&nd_table[0], STREAM_SLAVE(dma),
+                                     0x82780000, irq[3], 0x1000, 0x1000);
+
+    xilinx_axiethernetdma_init(dma, STREAM_SLAVE(eth0),
+                               0x84600000, irq[1], irq[0], 100 * 1000000);
 
     microblaze_load_kernel(cpu, ddr_base, ram_size, BINARY_DEVICE_TREE_FILE,
                                                             machine_cpu_reset);
diff --git a/hw/puv3.c b/hw/puv3.c
new file mode 100644
index 0000000000..43f7216e4e
--- /dev/null
+++ b/hw/puv3.c
@@ -0,0 +1,131 @@
+/*
+ * Generic PKUnity SoC machine and board descriptor
+ *
+ * Copyright (C) 2010-2012 Guan Xuetao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or any later version.
+ * See the COPYING file in the top-level directory.
+ */
+#include "console.h"
+#include "elf.h"
+#include "exec-memory.h"
+#include "sysbus.h"
+#include "boards.h"
+#include "loader.h"
+#include "pc.h"
+
+#undef DEBUG_PUV3
+#include "puv3.h"
+
+#define KERNEL_LOAD_ADDR        0x03000000
+#define KERNEL_MAX_SIZE         0x00800000 /* Just a guess */
+
+static void puv3_intc_cpu_handler(void *opaque, int irq, int level)
+{
+    CPUUniCore32State *env = opaque;
+
+    assert(irq == 0);
+    if (level) {
+        cpu_interrupt(env, CPU_INTERRUPT_HARD);
+    } else {
+        cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+    }
+}
+
+static void puv3_soc_init(CPUUniCore32State *env)
+{
+    qemu_irq *cpu_intc, irqs[PUV3_IRQS_NR];
+    DeviceState *dev;
+    MemoryRegion *i8042 = g_new(MemoryRegion, 1);
+    int i;
+
+    /* Initialize interrupt controller */
+    cpu_intc = qemu_allocate_irqs(puv3_intc_cpu_handler, env, 1);
+    dev = sysbus_create_simple("puv3_intc", PUV3_INTC_BASE, *cpu_intc);
+    for (i = 0; i < PUV3_IRQS_NR; i++) {
+        irqs[i] = qdev_get_gpio_in(dev, i);
+    }
+
+    /* Initialize minimal necessary devices for kernel booting */
+    sysbus_create_simple("puv3_pm", PUV3_PM_BASE, NULL);
+    sysbus_create_simple("puv3_dma", PUV3_DMA_BASE, NULL);
+    sysbus_create_simple("puv3_ost", PUV3_OST_BASE, irqs[PUV3_IRQS_OST0]);
+    sysbus_create_varargs("puv3_gpio", PUV3_GPIO_BASE,
+            irqs[PUV3_IRQS_GPIOLOW0], irqs[PUV3_IRQS_GPIOLOW1],
+            irqs[PUV3_IRQS_GPIOLOW2], irqs[PUV3_IRQS_GPIOLOW3],
+            irqs[PUV3_IRQS_GPIOLOW4], irqs[PUV3_IRQS_GPIOLOW5],
+            irqs[PUV3_IRQS_GPIOLOW6], irqs[PUV3_IRQS_GPIOLOW7],
+            irqs[PUV3_IRQS_GPIOHIGH], NULL);
+
+    /* Keyboard (i8042), mouse disabled for nographic */
+    i8042_mm_init(irqs[PUV3_IRQS_PS2_KBD], NULL, i8042, PUV3_REGS_OFFSET, 4);
+    memory_region_add_subregion(get_system_memory(), PUV3_PS2_BASE, i8042);
+}
+
+static void puv3_board_init(CPUUniCore32State *env, ram_addr_t ram_size)
+{
+    MemoryRegion *ram_memory = g_new(MemoryRegion, 1);
+
+    /* SDRAM at address zero.  */
+    memory_region_init_ram(ram_memory, "puv3.ram", ram_size);
+    vmstate_register_ram_global(ram_memory);
+    memory_region_add_subregion(get_system_memory(), 0, ram_memory);
+}
+
+static void puv3_load_kernel(const char *kernel_filename)
+{
+    int size;
+
+    assert(kernel_filename != NULL);
+
+    /* only zImage format supported */
+    size = load_image_targphys(kernel_filename, KERNEL_LOAD_ADDR,
+            KERNEL_MAX_SIZE);
+    if (size < 0) {
+        hw_error("Load kernel error: '%s'\n", kernel_filename);
+    }
+
+    /* cheat curses that we have a graphic console, only under ocd console */
+    graphic_console_init(NULL, NULL, NULL, NULL, NULL);
+}
+
+static void puv3_init(ram_addr_t ram_size, const char *boot_device,
+                     const char *kernel_filename, const char *kernel_cmdline,
+                     const char *initrd_filename, const char *cpu_model)
+{
+    CPUUniCore32State *env;
+
+    if (initrd_filename) {
+        hw_error("Please use kernel built-in initramdisk.\n");
+    }
+
+    if (!cpu_model) {
+        cpu_model = "UniCore-II";
+    }
+
+    env = cpu_init(cpu_model);
+    if (!env) {
+        hw_error("Unable to find CPU definition\n");
+    }
+
+    puv3_soc_init(env);
+    puv3_board_init(env, ram_size);
+    puv3_load_kernel(kernel_filename);
+}
+
+static QEMUMachine puv3_machine = {
+    .name = "puv3",
+    .desc = "PKUnity Version-3 based on UniCore32",
+    .init = puv3_init,
+    .is_default = 1,
+    .use_scsi = 0,
+};
+
+static void puv3_machine_init(void)
+{
+    qemu_register_machine(&puv3_machine);
+}
+
+machine_init(puv3_machine_init)
diff --git a/hw/puv3.h b/hw/puv3.h
new file mode 100644
index 0000000000..f37adcb665
--- /dev/null
+++ b/hw/puv3.h
@@ -0,0 +1,49 @@
+/*
+ * Misc PKUnity SoC declarations
+ *
+ * Copyright (C) 2010-2012 Guan Xuetao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or any later version.
+ * See the COPYING file in the top-level directory.
+ */
+#ifndef QEMU_HW_PUV3_H
+#define QEMU_HW_PUV3_H
+
+#define PUV3_REGS_OFFSET        (0x1000) /* 4K is reasonable */
+
+/* PKUnity System bus (AHB): 0xc0000000 - 0xedffffff (640MB) */
+#define PUV3_DMA_BASE           (0xc0200000) /* AHB-4 */
+
+/* PKUnity Peripheral bus (APB): 0xee000000 - 0xefffffff (128MB) */
+#define PUV3_GPIO_BASE          (0xee500000) /* APB-5 */
+#define PUV3_INTC_BASE          (0xee600000) /* APB-6 */
+#define PUV3_OST_BASE           (0xee800000) /* APB-8 */
+#define PUV3_PM_BASE            (0xeea00000) /* APB-10 */
+#define PUV3_PS2_BASE           (0xeeb00000) /* APB-11 */
+
+/* Hardware interrupts */
+#define PUV3_IRQS_NR            (32)
+
+#define PUV3_IRQS_GPIOLOW0      (0)
+#define PUV3_IRQS_GPIOLOW1      (1)
+#define PUV3_IRQS_GPIOLOW2      (2)
+#define PUV3_IRQS_GPIOLOW3      (3)
+#define PUV3_IRQS_GPIOLOW4      (4)
+#define PUV3_IRQS_GPIOLOW5      (5)
+#define PUV3_IRQS_GPIOLOW6      (6)
+#define PUV3_IRQS_GPIOLOW7      (7)
+#define PUV3_IRQS_GPIOHIGH      (8)
+#define PUV3_IRQS_PS2_KBD       (22)
+#define PUV3_IRQS_PS2_AUX       (23)
+#define PUV3_IRQS_OST0          (26)
+
+/* All puv3_*.c use DPRINTF for debug. */
+#ifdef DEBUG_PUV3
+#define DPRINTF(fmt, ...) printf("%s: " fmt , __func__, ## __VA_ARGS__)
+#else
+#define DPRINTF(fmt, ...) do {} while (0)
+#endif
+
+#endif /* !QEMU_HW_PUV3_H */
diff --git a/hw/puv3_dma.c b/hw/puv3_dma.c
new file mode 100644
index 0000000000..85b97bfdeb
--- /dev/null
+++ b/hw/puv3_dma.c
@@ -0,0 +1,109 @@
+/*
+ * DMA device simulation in PKUnity SoC
+ *
+ * Copyright (C) 2010-2012 Guan Xuetao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or any later version.
+ * See the COPYING file in the top-level directory.
+ */
+#include "hw.h"
+#include "sysbus.h"
+
+#undef DEBUG_PUV3
+#include "puv3.h"
+
+#define PUV3_DMA_CH_NR          (6)
+#define PUV3_DMA_CH_MASK        (0xff)
+#define PUV3_DMA_CH(offset)     ((offset) >> 8)
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    uint32_t reg_CFG[PUV3_DMA_CH_NR];
+} PUV3DMAState;
+
+static uint64_t puv3_dma_read(void *opaque, target_phys_addr_t offset,
+        unsigned size)
+{
+    PUV3DMAState *s = opaque;
+    uint32_t ret = 0;
+
+    assert(PUV3_DMA_CH(offset) < PUV3_DMA_CH_NR);
+
+    switch (offset & PUV3_DMA_CH_MASK) {
+    case 0x10:
+        ret = s->reg_CFG[PUV3_DMA_CH(offset)];
+        break;
+    default:
+        DPRINTF("Bad offset 0x%x\n", offset);
+    }
+    DPRINTF("offset 0x%x, value 0x%x\n", offset, ret);
+
+    return ret;
+}
+
+static void puv3_dma_write(void *opaque, target_phys_addr_t offset,
+        uint64_t value, unsigned size)
+{
+    PUV3DMAState *s = opaque;
+
+    assert(PUV3_DMA_CH(offset) < PUV3_DMA_CH_NR);
+
+    switch (offset & PUV3_DMA_CH_MASK) {
+    case 0x10:
+        s->reg_CFG[PUV3_DMA_CH(offset)] = value;
+        break;
+    default:
+        DPRINTF("Bad offset 0x%x\n", offset);
+    }
+    DPRINTF("offset 0x%x, value 0x%x\n", offset, value);
+}
+
+static const MemoryRegionOps puv3_dma_ops = {
+    .read = puv3_dma_read,
+    .write = puv3_dma_write,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int puv3_dma_init(SysBusDevice *dev)
+{
+    PUV3DMAState *s = FROM_SYSBUS(PUV3DMAState, dev);
+    int i;
+
+    for (i = 0; i < PUV3_DMA_CH_NR; i++) {
+        s->reg_CFG[i] = 0x0;
+    }
+
+    memory_region_init_io(&s->iomem, &puv3_dma_ops, s, "puv3_dma",
+            PUV3_REGS_OFFSET);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    return 0;
+}
+
+static void puv3_dma_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = puv3_dma_init;
+}
+
+static const TypeInfo puv3_dma_info = {
+    .name = "puv3_dma",
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(PUV3DMAState),
+    .class_init = puv3_dma_class_init,
+};
+
+static void puv3_dma_register_type(void)
+{
+    type_register_static(&puv3_dma_info);
+}
+
+type_init(puv3_dma_register_type)
diff --git a/hw/puv3_gpio.c b/hw/puv3_gpio.c
new file mode 100644
index 0000000000..9436e6c62c
--- /dev/null
+++ b/hw/puv3_gpio.c
@@ -0,0 +1,141 @@
+/*
+ * GPIO device simulation in PKUnity SoC
+ *
+ * Copyright (C) 2010-2012 Guan Xuetao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or any later version.
+ * See the COPYING file in the top-level directory.
+ */
+#include "hw.h"
+#include "sysbus.h"
+
+#undef DEBUG_PUV3
+#include "puv3.h"
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    qemu_irq irq[9];
+
+    uint32_t reg_GPLR;
+    uint32_t reg_GPDR;
+    uint32_t reg_GPIR;
+} PUV3GPIOState;
+
+static uint64_t puv3_gpio_read(void *opaque, target_phys_addr_t offset,
+        unsigned size)
+{
+    PUV3GPIOState *s = opaque;
+    uint32_t ret = 0;
+
+    switch (offset) {
+    case 0x00:
+        ret = s->reg_GPLR;
+        break;
+    case 0x04:
+        ret = s->reg_GPDR;
+        break;
+    case 0x20:
+        ret = s->reg_GPIR;
+        break;
+    default:
+        DPRINTF("Bad offset 0x%x\n", offset);
+    }
+    DPRINTF("offset 0x%x, value 0x%x\n", offset, ret);
+
+    return ret;
+}
+
+static void puv3_gpio_write(void *opaque, target_phys_addr_t offset,
+        uint64_t value, unsigned size)
+{
+    PUV3GPIOState *s = opaque;
+
+    DPRINTF("offset 0x%x, value 0x%x\n", offset, value);
+    switch (offset) {
+    case 0x04:
+        s->reg_GPDR = value;
+        break;
+    case 0x08:
+        if (s->reg_GPDR & value) {
+            s->reg_GPLR |= value;
+        } else {
+            DPRINTF("Write gpio input port error!");
+        }
+        break;
+    case 0x0c:
+        if (s->reg_GPDR & value) {
+            s->reg_GPLR &= ~value;
+        } else {
+            DPRINTF("Write gpio input port error!");
+        }
+        break;
+    case 0x10: /* GRER */
+    case 0x14: /* GFER */
+    case 0x18: /* GEDR */
+        break;
+    case 0x20: /* GPIR */
+        s->reg_GPIR = value;
+        break;
+    default:
+        DPRINTF("Bad offset 0x%x\n", offset);
+    }
+}
+
+static const MemoryRegionOps puv3_gpio_ops = {
+    .read = puv3_gpio_read,
+    .write = puv3_gpio_write,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int puv3_gpio_init(SysBusDevice *dev)
+{
+    PUV3GPIOState *s = FROM_SYSBUS(PUV3GPIOState, dev);
+
+    s->reg_GPLR = 0;
+    s->reg_GPDR = 0;
+
+    /* FIXME: these irqs not handled yet */
+    sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW0]);
+    sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW1]);
+    sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW2]);
+    sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW3]);
+    sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW4]);
+    sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW5]);
+    sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW6]);
+    sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW7]);
+    sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOHIGH]);
+
+    memory_region_init_io(&s->iomem, &puv3_gpio_ops, s, "puv3_gpio",
+            PUV3_REGS_OFFSET);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    return 0;
+}
+
+static void puv3_gpio_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = puv3_gpio_init;
+}
+
+static const TypeInfo puv3_gpio_info = {
+    .name = "puv3_gpio",
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(PUV3GPIOState),
+    .class_init = puv3_gpio_class_init,
+};
+
+static void puv3_gpio_register_type(void)
+{
+    type_register_static(&puv3_gpio_info);
+}
+
+type_init(puv3_gpio_register_type)
diff --git a/hw/puv3_intc.c b/hw/puv3_intc.c
new file mode 100644
index 0000000000..9e0b975ea2
--- /dev/null
+++ b/hw/puv3_intc.c
@@ -0,0 +1,135 @@
+/*
+ * INTC device simulation in PKUnity SoC
+ *
+ * Copyright (C) 2010-2012 Guan Xuetao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or any later version.
+ * See the COPYING file in the top-level directory.
+ */
+#include "sysbus.h"
+
+#undef DEBUG_PUV3
+#include "puv3.h"
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    qemu_irq parent_irq;
+
+    uint32_t reg_ICMR;
+    uint32_t reg_ICPR;
+} PUV3INTCState;
+
+/* Update interrupt status after enabled or pending bits have been changed.  */
+static void puv3_intc_update(PUV3INTCState *s)
+{
+    if (s->reg_ICMR & s->reg_ICPR) {
+        qemu_irq_raise(s->parent_irq);
+    } else {
+        qemu_irq_lower(s->parent_irq);
+    }
+}
+
+/* Process a change in an external INTC input. */
+static void puv3_intc_handler(void *opaque, int irq, int level)
+{
+    PUV3INTCState *s = opaque;
+
+    DPRINTF("irq 0x%x, level 0x%x\n", irq, level);
+    if (level) {
+        s->reg_ICPR |= (1 << irq);
+    } else {
+        s->reg_ICPR &= ~(1 << irq);
+    }
+    puv3_intc_update(s);
+}
+
+static uint64_t puv3_intc_read(void *opaque, target_phys_addr_t offset,
+        unsigned size)
+{
+    PUV3INTCState *s = opaque;
+    uint32_t ret = 0;
+
+    switch (offset) {
+    case 0x04: /* INTC_ICMR */
+        ret = s->reg_ICMR;
+        break;
+    case 0x0c: /* INTC_ICIP */
+        ret = s->reg_ICPR; /* the same value with ICPR */
+        break;
+    default:
+        DPRINTF("Bad offset %x\n", (int)offset);
+    }
+    DPRINTF("offset 0x%x, value 0x%x\n", offset, ret);
+    return ret;
+}
+
+static void puv3_intc_write(void *opaque, target_phys_addr_t offset,
+        uint64_t value, unsigned size)
+{
+    PUV3INTCState *s = opaque;
+
+    DPRINTF("offset 0x%x, value 0x%x\n", offset, value);
+    switch (offset) {
+    case 0x00: /* INTC_ICLR */
+    case 0x14: /* INTC_ICCR */
+        break;
+    case 0x04: /* INTC_ICMR */
+        s->reg_ICMR = value;
+        break;
+    default:
+        DPRINTF("Bad offset 0x%x\n", (int)offset);
+        return;
+    }
+    puv3_intc_update(s);
+}
+
+static const MemoryRegionOps puv3_intc_ops = {
+    .read = puv3_intc_read,
+    .write = puv3_intc_write,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int puv3_intc_init(SysBusDevice *dev)
+{
+    PUV3INTCState *s = FROM_SYSBUS(PUV3INTCState, dev);
+
+    qdev_init_gpio_in(&s->busdev.qdev, puv3_intc_handler, PUV3_IRQS_NR);
+    sysbus_init_irq(&s->busdev, &s->parent_irq);
+
+    s->reg_ICMR = 0;
+    s->reg_ICPR = 0;
+
+    memory_region_init_io(&s->iomem, &puv3_intc_ops, s, "puv3_intc",
+            PUV3_REGS_OFFSET);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    return 0;
+}
+
+static void puv3_intc_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = puv3_intc_init;
+}
+
+static const TypeInfo puv3_intc_info = {
+    .name = "puv3_intc",
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(PUV3INTCState),
+    .class_init = puv3_intc_class_init,
+};
+
+static void puv3_intc_register_type(void)
+{
+    type_register_static(&puv3_intc_info);
+}
+
+type_init(puv3_intc_register_type)
diff --git a/hw/puv3_ost.c b/hw/puv3_ost.c
new file mode 100644
index 0000000000..dd30cad0e2
--- /dev/null
+++ b/hw/puv3_ost.c
@@ -0,0 +1,151 @@
+/*
+ * OSTimer device simulation in PKUnity SoC
+ *
+ * Copyright (C) 2010-2012 Guan Xuetao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or any later version.
+ * See the COPYING file in the top-level directory.
+ */
+#include "sysbus.h"
+#include "ptimer.h"
+
+#undef DEBUG_PUV3
+#include "puv3.h"
+
+/* puv3 ostimer implementation. */
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    QEMUBH *bh;
+    qemu_irq irq;
+    ptimer_state *ptimer;
+
+    uint32_t reg_OSMR0;
+    uint32_t reg_OSCR;
+    uint32_t reg_OSSR;
+    uint32_t reg_OIER;
+} PUV3OSTState;
+
+static uint64_t puv3_ost_read(void *opaque, target_phys_addr_t offset,
+        unsigned size)
+{
+    PUV3OSTState *s = opaque;
+    uint32_t ret = 0;
+
+    switch (offset) {
+    case 0x10: /* Counter Register */
+        ret = s->reg_OSMR0 - (uint32_t)ptimer_get_count(s->ptimer);
+        break;
+    case 0x14: /* Status Register */
+        ret = s->reg_OSSR;
+        break;
+    case 0x1c: /* Interrupt Enable Register */
+        ret = s->reg_OIER;
+        break;
+    default:
+        DPRINTF("Bad offset %x\n", (int)offset);
+    }
+    DPRINTF("offset 0x%x, value 0x%x\n", offset, ret);
+    return ret;
+}
+
+static void puv3_ost_write(void *opaque, target_phys_addr_t offset,
+        uint64_t value, unsigned size)
+{
+    PUV3OSTState *s = opaque;
+
+    DPRINTF("offset 0x%x, value 0x%x\n", offset, value);
+    switch (offset) {
+    case 0x00: /* Match Register 0 */
+        s->reg_OSMR0 = value;
+        if (s->reg_OSMR0 > s->reg_OSCR) {
+            ptimer_set_count(s->ptimer, s->reg_OSMR0 - s->reg_OSCR);
+        } else {
+            ptimer_set_count(s->ptimer, s->reg_OSMR0 +
+                    (0xffffffff - s->reg_OSCR));
+        }
+        ptimer_run(s->ptimer, 2);
+        break;
+    case 0x14: /* Status Register */
+        assert(value == 0);
+        if (s->reg_OSSR) {
+            s->reg_OSSR = value;
+            qemu_irq_lower(s->irq);
+        }
+        break;
+    case 0x1c: /* Interrupt Enable Register */
+        s->reg_OIER = value;
+        break;
+    default:
+        DPRINTF("Bad offset %x\n", (int)offset);
+    }
+}
+
+static const MemoryRegionOps puv3_ost_ops = {
+    .read = puv3_ost_read,
+    .write = puv3_ost_write,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void puv3_ost_tick(void *opaque)
+{
+    PUV3OSTState *s = opaque;
+
+    DPRINTF("ost hit when ptimer counter from 0x%x to 0x%x!\n",
+            s->reg_OSCR, s->reg_OSMR0);
+
+    s->reg_OSCR = s->reg_OSMR0;
+    if (s->reg_OIER) {
+        s->reg_OSSR = 1;
+        qemu_irq_raise(s->irq);
+    }
+}
+
+static int puv3_ost_init(SysBusDevice *dev)
+{
+    PUV3OSTState *s = FROM_SYSBUS(PUV3OSTState, dev);
+
+    s->reg_OIER = 0;
+    s->reg_OSSR = 0;
+    s->reg_OSMR0 = 0;
+    s->reg_OSCR = 0;
+
+    sysbus_init_irq(dev, &s->irq);
+
+    s->bh = qemu_bh_new(puv3_ost_tick, s);
+    s->ptimer = ptimer_init(s->bh);
+    ptimer_set_freq(s->ptimer, 50 * 1000 * 1000);
+
+    memory_region_init_io(&s->iomem, &puv3_ost_ops, s, "puv3_ost",
+            PUV3_REGS_OFFSET);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    return 0;
+}
+
+static void puv3_ost_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = puv3_ost_init;
+}
+
+static const TypeInfo puv3_ost_info = {
+    .name = "puv3_ost",
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(PUV3OSTState),
+    .class_init = puv3_ost_class_init,
+};
+
+static void puv3_ost_register_type(void)
+{
+    type_register_static(&puv3_ost_info);
+}
+
+type_init(puv3_ost_register_type)
diff --git a/hw/puv3_pm.c b/hw/puv3_pm.c
new file mode 100644
index 0000000000..621c96875c
--- /dev/null
+++ b/hw/puv3_pm.c
@@ -0,0 +1,149 @@
+/*
+ * Power Management device simulation in PKUnity SoC
+ *
+ * Copyright (C) 2010-2012 Guan Xuetao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or any later version.
+ * See the COPYING file in the top-level directory.
+ */
+#include "hw.h"
+#include "sysbus.h"
+
+#undef DEBUG_PUV3
+#include "puv3.h"
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+
+    uint32_t reg_PMCR;
+    uint32_t reg_PCGR;
+    uint32_t reg_PLL_SYS_CFG;
+    uint32_t reg_PLL_DDR_CFG;
+    uint32_t reg_PLL_VGA_CFG;
+    uint32_t reg_DIVCFG;
+} PUV3PMState;
+
+static uint64_t puv3_pm_read(void *opaque, target_phys_addr_t offset,
+        unsigned size)
+{
+    PUV3PMState *s = opaque;
+    uint32_t ret = 0;
+
+    switch (offset) {
+    case 0x14:
+        ret = s->reg_PCGR;
+        break;
+    case 0x18:
+        ret = s->reg_PLL_SYS_CFG;
+        break;
+    case 0x1c:
+        ret = s->reg_PLL_DDR_CFG;
+        break;
+    case 0x20:
+        ret = s->reg_PLL_VGA_CFG;
+        break;
+    case 0x24:
+        ret = s->reg_DIVCFG;
+        break;
+    case 0x28: /* PLL SYS STATUS */
+        ret = 0x00002401;
+        break;
+    case 0x2c: /* PLL DDR STATUS */
+        ret = 0x00100c00;
+        break;
+    case 0x30: /* PLL VGA STATUS */
+        ret = 0x00003801;
+        break;
+    case 0x34: /* DIV STATUS */
+        ret = 0x22f52015;
+        break;
+    case 0x38: /* SW RESET */
+        ret = 0x0;
+        break;
+    case 0x44: /* PLL DFC DONE */
+        ret = 0x7;
+        break;
+    default:
+        DPRINTF("Bad offset 0x%x\n", offset);
+    }
+    DPRINTF("offset 0x%x, value 0x%x\n", offset, ret);
+
+    return ret;
+}
+
+static void puv3_pm_write(void *opaque, target_phys_addr_t offset,
+        uint64_t value, unsigned size)
+{
+    PUV3PMState *s = opaque;
+
+    switch (offset) {
+    case 0x0:
+        s->reg_PMCR = value;
+        break;
+    case 0x14:
+        s->reg_PCGR = value;
+        break;
+    case 0x18:
+        s->reg_PLL_SYS_CFG = value;
+        break;
+    case 0x1c:
+        s->reg_PLL_DDR_CFG = value;
+        break;
+    case 0x20:
+        s->reg_PLL_VGA_CFG = value;
+        break;
+    case 0x24:
+    case 0x38:
+        break;
+    default:
+        DPRINTF("Bad offset 0x%x\n", offset);
+    }
+    DPRINTF("offset 0x%x, value 0x%x\n", offset, value);
+}
+
+static const MemoryRegionOps puv3_pm_ops = {
+    .read = puv3_pm_read,
+    .write = puv3_pm_write,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int puv3_pm_init(SysBusDevice *dev)
+{
+    PUV3PMState *s = FROM_SYSBUS(PUV3PMState, dev);
+
+    s->reg_PCGR = 0x0;
+
+    memory_region_init_io(&s->iomem, &puv3_pm_ops, s, "puv3_pm",
+            PUV3_REGS_OFFSET);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    return 0;
+}
+
+static void puv3_pm_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = puv3_pm_init;
+}
+
+static const TypeInfo puv3_pm_info = {
+    .name = "puv3_pm",
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(PUV3PMState),
+    .class_init = puv3_pm_class_init,
+};
+
+static void puv3_pm_register_type(void)
+{
+    type_register_static(&puv3_pm_info);
+}
+
+type_init(puv3_pm_register_type)
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index 6120cc83c1..b8a857d145 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -1437,7 +1437,6 @@ static const char *scsi_command_name(uint8_t cmd)
         [ ATA_PASSTHROUGH_12       ] = "BLANK/ATA_PASSTHROUGH_12",
         [ MOVE_MEDIUM              ] = "MOVE_MEDIUM",
         [ EXCHANGE_MEDIUM          ] = "EXCHANGE MEDIUM",
-        [ LOAD_UNLOAD              ] = "LOAD_UNLOAD",
         [ READ_12                  ] = "READ_12",
         [ WRITE_12                 ] = "WRITE_12",
         [ ERASE_12                 ] = "ERASE_12/GET_PERFORMANCE",
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index a9c727905a..409f760ef7 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -175,6 +175,8 @@ static void scsi_aio_complete(void *opaque, int ret)
     SCSIDiskReq *r = (SCSIDiskReq *)opaque;
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
 
+    assert(r->req.aiocb != NULL);
+    r->req.aiocb = NULL;
     bdrv_acct_done(s->qdev.conf.bs, &r->acct);
 
     if (ret < 0) {
@@ -238,10 +240,9 @@ static void scsi_dma_complete(void *opaque, int ret)
     SCSIDiskReq *r = (SCSIDiskReq *)opaque;
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
 
-    if (r->req.aiocb != NULL) {
-        r->req.aiocb = NULL;
-        bdrv_acct_done(s->qdev.conf.bs, &r->acct);
-    }
+    assert(r->req.aiocb != NULL);
+    r->req.aiocb = NULL;
+    bdrv_acct_done(s->qdev.conf.bs, &r->acct);
 
     if (ret < 0) {
         if (scsi_handle_rw_error(r, -ret)) {
@@ -270,10 +271,9 @@ static void scsi_read_complete(void * opaque, int ret)
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
     int n;
 
-    if (r->req.aiocb != NULL) {
-        r->req.aiocb = NULL;
-        bdrv_acct_done(s->qdev.conf.bs, &r->acct);
-    }
+    assert(r->req.aiocb != NULL);
+    r->req.aiocb = NULL;
+    bdrv_acct_done(s->qdev.conf.bs, &r->acct);
 
     if (ret < 0) {
         if (scsi_handle_rw_error(r, -ret)) {
@@ -637,7 +637,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
         {
             buflen = 8;
             outbuf[4] = 0;
-            outbuf[5] = 0x60; /* write_same 10/16 supported */
+            outbuf[5] = 0xe0; /* unmap & write_same 10/16 all supported */
             outbuf[6] = s->qdev.conf.discard_granularity ? 2 : 1;
             outbuf[7] = 0;
             break;
@@ -1449,6 +1449,89 @@ invalid_field:
     return;
 }
 
+typedef struct UnmapCBData {
+    SCSIDiskReq *r;
+    uint8_t *inbuf;
+    int count;
+} UnmapCBData;
+
+static void scsi_unmap_complete(void *opaque, int ret)
+{
+    UnmapCBData *data = opaque;
+    SCSIDiskReq *r = data->r;
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+    uint64_t sector_num;
+    uint32 nb_sectors;
+
+    r->req.aiocb = NULL;
+    if (ret < 0) {
+        if (scsi_handle_rw_error(r, -ret)) {
+            goto done;
+        }
+    }
+
+    if (data->count > 0 && !r->req.io_canceled) {
+        sector_num = ldq_be_p(&data->inbuf[0]);
+        nb_sectors = ldl_be_p(&data->inbuf[8]) & 0xffffffffULL;
+        if (sector_num > sector_num + nb_sectors ||
+            sector_num + nb_sectors - 1 > s->qdev.max_lba) {
+            scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE));
+            goto done;
+        }
+
+        r->req.aiocb = bdrv_aio_discard(s->qdev.conf.bs,
+                                        sector_num * (s->qdev.blocksize / 512),
+                                        nb_sectors * (s->qdev.blocksize / 512),
+                                        scsi_unmap_complete, data);
+        data->count--;
+        data->inbuf += 16;
+        return;
+    }
+
+done:
+    if (data->count == 0) {
+        scsi_req_complete(&r->req, GOOD);
+    }
+    if (!r->req.io_canceled) {
+        scsi_req_unref(&r->req);
+    }
+    g_free(data);
+}
+
+static void scsi_disk_emulate_unmap(SCSIDiskReq *r, uint8_t *inbuf)
+{
+    uint8_t *p = inbuf;
+    int len = r->req.cmd.xfer;
+    UnmapCBData *data;
+
+    if (len < 8) {
+        goto invalid_param_len;
+    }
+    if (len < lduw_be_p(&p[0]) + 2) {
+        goto invalid_param_len;
+    }
+    if (len < lduw_be_p(&p[2]) + 8) {
+        goto invalid_param_len;
+    }
+    if (lduw_be_p(&p[2]) & 15) {
+        goto invalid_param_len;
+    }
+
+    data = g_new0(UnmapCBData, 1);
+    data->r = r;
+    data->inbuf = &p[8];
+    data->count = lduw_be_p(&p[2]) >> 4;
+
+    /* The matching unref is in scsi_unmap_complete, before data is freed.  */
+    scsi_req_ref(&r->req);
+    scsi_unmap_complete(data, 0);
+    return;
+
+invalid_param_len:
+    scsi_check_condition(r, SENSE_CODE(INVALID_PARAM_LEN));
+    return;
+}
+
 static void scsi_disk_emulate_write_data(SCSIRequest *req)
 {
     SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
@@ -1468,6 +1551,10 @@ static void scsi_disk_emulate_write_data(SCSIRequest *req)
         scsi_disk_emulate_mode_select(r, r->iov.iov_base);
         break;
 
+    case UNMAP:
+        scsi_disk_emulate_unmap(r, r->iov.iov_base);
+        break;
+
     default:
         abort();
     }
@@ -1702,6 +1789,9 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
     case MODE_SELECT_10:
         DPRINTF("Mode Select(10) (len %lu)\n", (long)r->req.cmd.xfer);
         break;
+    case UNMAP:
+        DPRINTF("Unmap (len %lu)\n", (long)r->req.cmd.xfer);
+        break;
     case WRITE_SAME_10:
         nb_sectors = lduw_be_p(&req->cmd.buf[7]);
         goto write_same;
@@ -1712,7 +1802,8 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
             scsi_check_condition(r, SENSE_CODE(WRITE_PROTECTED));
             return 0;
         }
-        if (r->req.cmd.lba > s->qdev.max_lba) {
+        if (r->req.cmd.lba > r->req.cmd.lba + nb_sectors ||
+            r->req.cmd.lba + nb_sectors - 1 > s->qdev.max_lba) {
             goto illegal_lba;
         }
 
@@ -1958,7 +2049,8 @@ static int scsi_initfn(SCSIDevice *dev)
     }
 
     blkconf_serial(&s->qdev.conf, &s->serial);
-    if (blkconf_geometry(&dev->conf, NULL, 65535, 255, 255) < 0) {
+    if (dev->type == TYPE_DISK
+        && blkconf_geometry(&dev->conf, NULL, 65535, 255, 255) < 0) {
         return -1;
     }
 
@@ -2066,6 +2158,7 @@ static const SCSIReqOps *const scsi_disk_reqops_dispatch[256] = {
     [SEEK_10]                         = &scsi_disk_emulate_reqops,
     [MODE_SELECT]                     = &scsi_disk_emulate_reqops,
     [MODE_SELECT_10]                  = &scsi_disk_emulate_reqops,
+    [UNMAP]                           = &scsi_disk_emulate_reqops,
     [WRITE_SAME_10]                   = &scsi_disk_emulate_reqops,
     [WRITE_SAME_16]                   = &scsi_disk_emulate_reqops,
 
diff --git a/hw/sd.c b/hw/sd.c
index 07eb263388..ec26407543 100644
--- a/hw/sd.c
+++ b/hw/sd.c
@@ -32,6 +32,7 @@
 #include "hw.h"
 #include "block.h"
 #include "sd.h"
+#include "bitmap.h"
 
 //#define DEBUG_SD 1
 
@@ -80,8 +81,8 @@ struct SDState {
     uint32_t card_status;
     uint8_t sd_status[64];
     uint32_t vhs;
-    int wp_switch;
-    int *wp_groups;
+    bool wp_switch;
+    unsigned long *wp_groups;
     uint64_t size;
     int blk_len;
     uint32_t erase_start;
@@ -90,12 +91,12 @@ struct SDState {
     int pwd_len;
     int function_group[6];
 
-    int spi;
+    bool spi;
     int current_cmd;
     /* True if we will handle the next command as an ACMD. Note that this does
      * *not* track the APP_CMD status bit!
      */
-    int expecting_acmd;
+    bool expecting_acmd;
     int blk_written;
     uint64_t data_start;
     uint32_t data_offset;
@@ -105,7 +106,7 @@ struct SDState {
     BlockDriverState *bdrv;
     uint8_t *buf;
 
-    int enable;
+    bool enable;
 };
 
 static void sd_set_mode(SDState *sd)
@@ -387,6 +388,11 @@ static void sd_response_r7_make(SDState *sd, uint8_t *response)
     response[3] = (sd->vhs >>  0) & 0xff;
 }
 
+static inline uint64_t sd_addr_to_wpnum(uint64_t addr)
+{
+    return addr >> (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT);
+}
+
 static void sd_reset(SDState *sd, BlockDriverState *bdrv)
 {
     uint64_t size;
@@ -399,7 +405,7 @@ static void sd_reset(SDState *sd, BlockDriverState *bdrv)
     }
     size = sect << 9;
 
-    sect = (size >> (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT)) + 1;
+    sect = sd_addr_to_wpnum(size) + 1;
 
     sd->state = sd_idle_state;
     sd->rca = 0x0000;
@@ -414,15 +420,15 @@ static void sd_reset(SDState *sd, BlockDriverState *bdrv)
 
     if (sd->wp_groups)
         g_free(sd->wp_groups);
-    sd->wp_switch = bdrv ? bdrv_is_read_only(bdrv) : 0;
-    sd->wp_groups = (int *) g_malloc0(sizeof(int) * sect);
+    sd->wp_switch = bdrv ? bdrv_is_read_only(bdrv) : false;
+    sd->wp_groups = bitmap_new(sect);
     memset(sd->function_group, 0, sizeof(int) * 6);
     sd->erase_start = 0;
     sd->erase_end = 0;
     sd->size = size;
     sd->blk_len = 0x200;
     sd->pwd_len = 0;
-    sd->expecting_acmd = 0;
+    sd->expecting_acmd = false;
 }
 
 static void sd_cardchange(void *opaque, bool load)
@@ -444,14 +450,14 @@ static const BlockDevOps sd_block_ops = {
    whether card should be in SSI or MMC/SD mode.  It is also up to the
    board to ensure that ssi transfers only occur when the chip select
    is asserted.  */
-SDState *sd_init(BlockDriverState *bs, int is_spi)
+SDState *sd_init(BlockDriverState *bs, bool is_spi)
 {
     SDState *sd;
 
     sd = (SDState *) g_malloc0(sizeof(SDState));
     sd->buf = qemu_blockalign(bs, 512);
     sd->spi = is_spi;
-    sd->enable = 1;
+    sd->enable = true;
     sd_reset(sd, bs);
     if (sd->bdrv) {
         bdrv_attach_dev_nofail(sd->bdrv, sd);
@@ -476,17 +482,17 @@ static void sd_erase(SDState *sd)
         return;
     }
 
-    start = sd->erase_start >>
-            (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT);
-    end = sd->erase_end >>
-            (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT);
+    start = sd_addr_to_wpnum(sd->erase_start);
+    end = sd_addr_to_wpnum(sd->erase_end);
     sd->erase_start = 0;
     sd->erase_end = 0;
     sd->csd[14] |= 0x40;
 
-    for (i = start; i <= end; i ++)
-        if (sd->wp_groups[i])
+    for (i = start; i <= end; i++) {
+        if (test_bit(i, sd->wp_groups)) {
             sd->card_status |= WP_ERASE_SKIP;
+        }
+    }
 }
 
 static uint32_t sd_wpbits(SDState *sd, uint64_t addr)
@@ -494,11 +500,13 @@ static uint32_t sd_wpbits(SDState *sd, uint64_t addr)
     uint32_t i, wpnum;
     uint32_t ret = 0;
 
-    wpnum = addr >> (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT);
+    wpnum = sd_addr_to_wpnum(addr);
 
-    for (i = 0; i < 32; i ++, wpnum ++, addr += WPGROUP_SIZE)
-        if (addr < sd->size && sd->wp_groups[wpnum])
+    for (i = 0; i < 32; i++, wpnum++, addr += WPGROUP_SIZE) {
+        if (addr < sd->size && test_bit(wpnum, sd->wp_groups)) {
             ret |= (1 << i);
+        }
+    }
 
     return ret;
 }
@@ -534,10 +542,9 @@ static void sd_function_switch(SDState *sd, uint32_t arg)
     sd->data[66] = crc & 0xff;
 }
 
-static inline int sd_wp_addr(SDState *sd, uint32_t addr)
+static inline bool sd_wp_addr(SDState *sd, uint64_t addr)
 {
-    return sd->wp_groups[addr >>
-            (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT)];
+    return test_bit(sd_addr_to_wpnum(addr), sd->wp_groups);
 }
 
 static void sd_lock_command(SDState *sd)
@@ -560,8 +567,7 @@ static void sd_lock_command(SDState *sd)
             sd->card_status |= LOCK_UNLOCK_FAILED;
             return;
         }
-        memset(sd->wp_groups, 0, sizeof(int) * (sd->size >>
-                        (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT)));
+        bitmap_zero(sd->wp_groups, sd_addr_to_wpnum(sd->size) + 1);
         sd->csd[14] &= ~0x10;
         sd->card_status &= ~CARD_IS_LOCKED;
         sd->pwd_len = 0;
@@ -1007,8 +1013,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd,
             }
 
             sd->state = sd_programming_state;
-            sd->wp_groups[addr >> (HWBLOCK_SHIFT +
-                            SECTOR_SHIFT + WPGROUP_SHIFT)] = 1;
+            set_bit(sd_addr_to_wpnum(addr), sd->wp_groups);
             /* Bzzzzzzztt .... Operation complete.  */
             sd->state = sd_transfer_state;
             return sd_r1b;
@@ -1027,8 +1032,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd,
             }
 
             sd->state = sd_programming_state;
-            sd->wp_groups[addr >> (HWBLOCK_SHIFT +
-                            SECTOR_SHIFT + WPGROUP_SHIFT)] = 0;
+            clear_bit(sd_addr_to_wpnum(addr), sd->wp_groups);
             /* Bzzzzzzztt .... Operation complete.  */
             sd->state = sd_transfer_state;
             return sd_r1b;
@@ -1125,7 +1129,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd,
         if (sd->rca != rca)
             return sd_r0;
 
-        sd->expecting_acmd = 1;
+        sd->expecting_acmd = true;
         sd->card_status |= APP_CMD;
         return sd_r1;
 
@@ -1307,7 +1311,7 @@ int sd_do_command(SDState *sd, SDRequest *req,
     if (sd->card_status & CARD_IS_LOCKED) {
         if (!cmd_valid_while_locked(sd, req)) {
             sd->card_status |= ILLEGAL_COMMAND;
-            sd->expecting_acmd = 0;
+            sd->expecting_acmd = false;
             fprintf(stderr, "SD: Card is locked\n");
             rtype = sd_illegal;
             goto send_response;
@@ -1318,7 +1322,7 @@ int sd_do_command(SDState *sd, SDRequest *req,
     sd_set_mode(sd);
 
     if (sd->expecting_acmd) {
-        sd->expecting_acmd = 0;
+        sd->expecting_acmd = false;
         rtype = sd_app_command(sd, *req);
     } else {
         rtype = sd_normal_command(sd, *req);
@@ -1699,12 +1703,12 @@ uint8_t sd_read_data(SDState *sd)
     return ret;
 }
 
-int sd_data_ready(SDState *sd)
+bool sd_data_ready(SDState *sd)
 {
     return sd->state == sd_sendingdata_state;
 }
 
-void sd_enable(SDState *sd, int enable)
+void sd_enable(SDState *sd, bool enable)
 {
     sd->enable = enable;
 }
diff --git a/hw/sd.h b/hw/sd.h
index ac4b7c4dfa..4eb9679acd 100644
--- a/hw/sd.h
+++ b/hw/sd.h
@@ -67,13 +67,13 @@ typedef struct {
 
 typedef struct SDState SDState;
 
-SDState *sd_init(BlockDriverState *bs, int is_spi);
+SDState *sd_init(BlockDriverState *bs, bool is_spi);
 int sd_do_command(SDState *sd, SDRequest *req,
                   uint8_t *response);
 void sd_write_data(SDState *sd, uint8_t value);
 uint8_t sd_read_data(SDState *sd);
 void sd_set_cb(SDState *sd, qemu_irq readonly, qemu_irq insert);
-int sd_data_ready(SDState *sd);
-void sd_enable(SDState *sd, int enable);
+bool sd_data_ready(SDState *sd);
+void sd_enable(SDState *sd, bool enable);
 
 #endif	/* __hw_sd_h */
diff --git a/hw/ssd0323.c b/hw/ssd0323.c
index b0b2e94a81..b101c5112c 100644
--- a/hw/ssd0323.c
+++ b/hw/ssd0323.c
@@ -19,7 +19,9 @@
 #define DPRINTF(fmt, ...) \
 do { printf("ssd0323: " fmt , ## __VA_ARGS__); } while (0)
 #define BADF(fmt, ...) \
-do { fprintf(stderr, "ssd0323: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
+do { \
+    fprintf(stderr, "ssd0323: error: " fmt , ## __VA_ARGS__); abort(); \
+} while (0)
 #else
 #define DPRINTF(fmt, ...) do {} while(0)
 #define BADF(fmt, ...) \
diff --git a/hw/stream.c b/hw/stream.c
new file mode 100644
index 0000000000..be57e8b247
--- /dev/null
+++ b/hw/stream.c
@@ -0,0 +1,23 @@
+#include "stream.h"
+
+void
+stream_push(StreamSlave *sink, uint8_t *buf, size_t len, uint32_t *app)
+{
+    StreamSlaveClass *k =  STREAM_SLAVE_GET_CLASS(sink);
+
+    k->push(sink, buf, len, app);
+}
+
+static TypeInfo stream_slave_info = {
+    .name          = TYPE_STREAM_SLAVE,
+    .parent        = TYPE_INTERFACE,
+    .class_size = sizeof(StreamSlaveClass),
+};
+
+
+static void stream_slave_register_types(void)
+{
+    type_register_static(&stream_slave_info);
+}
+
+type_init(stream_slave_register_types)
diff --git a/hw/stream.h b/hw/stream.h
new file mode 100644
index 0000000000..21123a9089
--- /dev/null
+++ b/hw/stream.h
@@ -0,0 +1,31 @@
+#ifndef STREAM_H
+#define STREAM_H 1
+
+#include "qemu-common.h"
+#include "qemu/object.h"
+
+/* stream slave. Used until qdev provides a generic way.  */
+#define TYPE_STREAM_SLAVE "stream-slave"
+
+#define STREAM_SLAVE_CLASS(klass) \
+     OBJECT_CLASS_CHECK(StreamSlaveClass, (klass), TYPE_STREAM_SLAVE)
+#define STREAM_SLAVE_GET_CLASS(obj) \
+    OBJECT_GET_CLASS(StreamSlaveClass, (obj), TYPE_STREAM_SLAVE)
+#define STREAM_SLAVE(obj) \
+     INTERFACE_CHECK(StreamSlave, (obj), TYPE_STREAM_SLAVE)
+
+typedef struct StreamSlave {
+    Object Parent;
+} StreamSlave;
+
+typedef struct StreamSlaveClass {
+    InterfaceClass parent;
+
+    void (*push)(StreamSlave *obj, unsigned char *buf, size_t len,
+                                                    uint32_t *app);
+} StreamSlaveClass;
+
+void
+stream_push(StreamSlave *sink, uint8_t *buf, size_t len, uint32_t *app);
+
+#endif /* STREAM_H */
diff --git a/hw/sun4m.c b/hw/sun4m.c
index a959261209..0f909b5f86 100644
--- a/hw/sun4m.c
+++ b/hw/sun4m.c
@@ -832,6 +832,10 @@ static void cpu_devinit(const char *cpu_model, unsigned int id,
     env->prom_addr = prom_addr;
 }
 
+static void dummy_fdc_tc(void *opaque, int irq, int level)
+{
+}
+
 static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, ram_addr_t RAM_size,
                           const char *boot_device,
                           const char *kernel_filename,
@@ -942,9 +946,6 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, ram_addr_t RAM_size,
               serial_hds[0], serial_hds[1], ESCC_CLOCK, 1);
 
     cpu_halt = qemu_allocate_irqs(cpu_halt_signal, NULL, 1);
-    slavio_misc_init(hwdef->slavio_base, hwdef->aux1_base, hwdef->aux2_base,
-                     slavio_irq[30], fdc_tc);
-
     if (hwdef->apc_base) {
         apc_init(hwdef->apc_base, cpu_halt[0]);
     }
@@ -955,8 +956,13 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, ram_addr_t RAM_size,
         fd[0] = drive_get(IF_FLOPPY, 0, 0);
         sun4m_fdctrl_init(slavio_irq[22], hwdef->fd_base, fd,
                           &fdc_tc);
+    } else {
+        fdc_tc = *qemu_allocate_irqs(dummy_fdc_tc, NULL, 1);
     }
 
+    slavio_misc_init(hwdef->slavio_base, hwdef->aux1_base, hwdef->aux2_base,
+                     slavio_irq[30], fdc_tc);
+
     if (drive_get_max_bus(IF_SCSI) > 0) {
         fprintf(stderr, "qemu: too many SCSI bus\n");
         exit(1);
@@ -1772,16 +1778,18 @@ static void sun4c_hw_init(const struct sun4c_hwdef *hwdef, ram_addr_t RAM_size,
               slavio_irq[1], serial_hds[0], serial_hds[1],
               ESCC_CLOCK, 1);
 
-    slavio_misc_init(0, hwdef->aux1_base, 0, slavio_irq[1], fdc_tc);
-
     if (hwdef->fd_base != (target_phys_addr_t)-1) {
         /* there is zero or one floppy drive */
         memset(fd, 0, sizeof(fd));
         fd[0] = drive_get(IF_FLOPPY, 0, 0);
         sun4m_fdctrl_init(slavio_irq[1], hwdef->fd_base, fd,
                           &fdc_tc);
+    } else {
+        fdc_tc = *qemu_allocate_irqs(dummy_fdc_tc, NULL, 1);
     }
 
+    slavio_misc_init(0, hwdef->aux1_base, 0, slavio_irq[1], fdc_tc);
+
     if (drive_get_max_bus(IF_SCSI) > 0) {
         fprintf(stderr, "qemu: too many SCSI bus\n");
         exit(1);
diff --git a/hw/unicore32/Makefile.objs b/hw/unicore32/Makefile.objs
new file mode 100644
index 0000000000..0725ce3ca7
--- /dev/null
+++ b/hw/unicore32/Makefile.objs
@@ -0,0 +1,6 @@
+# For UniCore32 machines and boards
+
+# PKUnity-v3 SoC and board information
+obj-${CONFIG_PUV3} += puv3.o
+
+obj-y := $(addprefix ../,$(obj-y))
diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c
index 7fa8b83d2e..ff48d91049 100644
--- a/hw/usb/dev-storage.c
+++ b/hw/usb/dev-storage.c
@@ -247,6 +247,9 @@ static void usb_msd_command_complete(SCSIRequest *req, uint32_t status, size_t r
                the status read packet.  */
             usb_msd_send_status(s, p);
             s->mode = USB_MSDM_CBW;
+        } else if (s->mode == USB_MSDM_CSW) {
+            usb_msd_send_status(s, p);
+            s->mode = USB_MSDM_CBW;
         } else {
             if (s->data_len) {
                 int len = (p->iov.size - p->result);
@@ -383,6 +386,9 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
             assert(le32_to_cpu(s->csw.residue) == 0);
             s->scsi_len = 0;
             s->req = scsi_req_new(s->scsi_dev, tag, 0, cbw.cmd, NULL);
+#ifdef DEBUG_MSD
+            scsi_req_print(s->req);
+#endif
             scsi_req_enqueue(s->req);
             if (s->req && s->req->cmd.xfer != SCSI_XFER_NONE) {
                 scsi_req_continue(s->req);
@@ -410,7 +416,7 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
                 }
             }
             if (p->result < p->iov.size) {
-                DPRINTF("Deferring packet %p\n", p);
+                DPRINTF("Deferring packet %p [wait data-out]\n", p);
                 s->packet = p;
                 ret = USB_RET_ASYNC;
             } else {
@@ -445,6 +451,7 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
 
             if (s->req) {
                 /* still in flight */
+                DPRINTF("Deferring packet %p [wait status]\n", p);
                 s->packet = p;
                 ret = USB_RET_ASYNC;
             } else {
@@ -471,7 +478,7 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
                 }
             }
             if (p->result < p->iov.size) {
-                DPRINTF("Deferring packet %p\n", p);
+                DPRINTF("Deferring packet %p [wait data-in]\n", p);
                 s->packet = p;
                 ret = USB_RET_ASYNC;
             } else {
diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c
index f21757ed55..fd8fa90792 100644
--- a/hw/virtio-blk.c
+++ b/hw/virtio-blk.c
@@ -254,6 +254,7 @@ static void virtio_blk_handle_scsi(VirtIOBlockReq *req)
 
     virtio_blk_req_complete(req, status);
     g_free(req);
+    return;
 #else
     abort();
 #endif
@@ -509,9 +510,19 @@ static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config)
     blkcfg.size_max = 0;
     blkcfg.physical_block_exp = get_physical_block_exp(s->conf);
     blkcfg.alignment_offset = 0;
+    blkcfg.wce = bdrv_enable_write_cache(s->bs);
     memcpy(config, &blkcfg, sizeof(struct virtio_blk_config));
 }
 
+static void virtio_blk_set_config(VirtIODevice *vdev, const uint8_t *config)
+{
+    VirtIOBlock *s = to_virtio_blk(vdev);
+    struct virtio_blk_config blkcfg;
+
+    memcpy(&blkcfg, config, sizeof(blkcfg));
+    bdrv_set_enable_write_cache(s->bs, blkcfg.wce != 0);
+}
+
 static uint32_t virtio_blk_get_features(VirtIODevice *vdev, uint32_t features)
 {
     VirtIOBlock *s = to_virtio_blk(vdev);
@@ -522,15 +533,29 @@ static uint32_t virtio_blk_get_features(VirtIODevice *vdev, uint32_t features)
     features |= (1 << VIRTIO_BLK_F_BLK_SIZE);
     features |= (1 << VIRTIO_BLK_F_SCSI);
 
+    features |= (1 << VIRTIO_BLK_F_CONFIG_WCE);
     if (bdrv_enable_write_cache(s->bs))
-        features |= (1 << VIRTIO_BLK_F_WCACHE);
-    
+        features |= (1 << VIRTIO_BLK_F_WCE);
+
     if (bdrv_is_read_only(s->bs))
         features |= 1 << VIRTIO_BLK_F_RO;
 
     return features;
 }
 
+static void virtio_blk_set_status(VirtIODevice *vdev, uint8_t status)
+{
+    VirtIOBlock *s = to_virtio_blk(vdev);
+    uint32_t features;
+
+    if (!(status & VIRTIO_CONFIG_S_DRIVER_OK)) {
+        return;
+    }
+
+    features = vdev->guest_features;
+    bdrv_set_enable_write_cache(s->bs, !!(features & (1 << VIRTIO_BLK_F_WCE)));
+}
+
 static void virtio_blk_save(QEMUFile *f, void *opaque)
 {
     VirtIOBlock *s = opaque;
@@ -609,7 +634,9 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, VirtIOBlkConf *blk)
                                           sizeof(VirtIOBlock));
 
     s->vdev.get_config = virtio_blk_update_config;
+    s->vdev.set_config = virtio_blk_set_config;
     s->vdev.get_features = virtio_blk_get_features;
+    s->vdev.set_status = virtio_blk_set_status;
     s->vdev.reset = virtio_blk_reset;
     s->bs = blk->conf.bs;
     s->conf = &blk->conf;
diff --git a/hw/virtio-blk.h b/hw/virtio-blk.h
index 79ebccc95b..35834cf493 100644
--- a/hw/virtio-blk.h
+++ b/hw/virtio-blk.h
@@ -31,8 +31,9 @@
 #define VIRTIO_BLK_F_BLK_SIZE   6       /* Block size of disk is available*/
 #define VIRTIO_BLK_F_SCSI       7       /* Supports scsi command passthru */
 /* #define VIRTIO_BLK_F_IDENTIFY   8       ATA IDENTIFY supported, DEPRECATED */
-#define VIRTIO_BLK_F_WCACHE     9       /* write cache enabled */
+#define VIRTIO_BLK_F_WCE        9       /* write cache enabled */
 #define VIRTIO_BLK_F_TOPOLOGY   10      /* Topology information is available */
+#define VIRTIO_BLK_F_CONFIG_WCE 11      /* write cache configurable */
 
 #define VIRTIO_BLK_ID_BYTES     20      /* ID string length */
 
@@ -49,6 +50,7 @@ struct virtio_blk_config
     uint8_t alignment_offset;
     uint16_t min_io_size;
     uint32_t opt_io_size;
+    uint8_t wce;
 } QEMU_PACKED;
 
 /* These two define direction. */
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index 125eded9ca..5e6e09efb7 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -627,7 +627,7 @@ static int virtio_pci_set_guest_notifiers(void *opaque, bool assign)
     int r, n;
 
     /* Must unset vector notifier while guest notifier is still assigned */
-    if (kvm_irqchip_in_kernel() && !assign) {
+    if (kvm_msi_via_irqfd_enabled() && !assign) {
         msix_unset_vector_notifiers(&proxy->pci_dev);
         g_free(proxy->vector_irqfd);
         proxy->vector_irqfd = NULL;
@@ -645,7 +645,7 @@ static int virtio_pci_set_guest_notifiers(void *opaque, bool assign)
     }
 
     /* Must set vector notifier after guest notifier has been assigned */
-    if (kvm_irqchip_in_kernel() && assign) {
+    if (kvm_msi_via_irqfd_enabled() && assign) {
         proxy->vector_irqfd =
             g_malloc0(sizeof(*proxy->vector_irqfd) *
                       msix_nr_vectors_allocated(&proxy->pci_dev));
diff --git a/hw/virtio-scsi.c b/hw/virtio-scsi.c
index c4a5b22f94..5f737acd97 100644
--- a/hw/virtio-scsi.c
+++ b/hw/virtio-scsi.c
@@ -305,11 +305,17 @@ static void virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req)
             goto incorrect_lun;
         }
         QTAILQ_FOREACH_SAFE(r, &d->requests, next, next) {
-            if (r->tag == req->req.tmf->tag) {
+            VirtIOSCSIReq *cmd_req = r->hba_private;
+            if (cmd_req && cmd_req->req.cmd->tag == req->req.tmf->tag) {
                 break;
             }
         }
-        if (r && r->hba_private) {
+        if (r) {
+            /*
+             * Assert that the request has not been completed yet, we
+             * check for it in the loop above.
+             */
+            assert(r->hba_private);
             if (req->req.tmf->subtype == VIRTIO_SCSI_T_TMF_QUERY_TASK) {
                 /* "If the specified command is present in the task set, then
                  * return a service response set to FUNCTION SUCCEEDED".
diff --git a/hw/xilinx.h b/hw/xilinx.h
index 7df21eb958..556c5aa9f1 100644
--- a/hw/xilinx.h
+++ b/hw/xilinx.h
@@ -1,3 +1,4 @@
+#include "stream.h"
 #include "qemu-common.h"
 #include "net.h"
 
@@ -49,8 +50,8 @@ xilinx_ethlite_create(NICInfo *nd, target_phys_addr_t base, qemu_irq irq,
 }
 
 static inline DeviceState *
-xilinx_axiethernet_create(void *dmach,
-                          NICInfo *nd, target_phys_addr_t base, qemu_irq irq,
+xilinx_axiethernet_create(NICInfo *nd, StreamSlave *peer,
+                          target_phys_addr_t base, qemu_irq irq,
                           int txmem, int rxmem)
 {
     DeviceState *dev;
@@ -60,7 +61,7 @@ xilinx_axiethernet_create(void *dmach,
     qdev_set_nic_properties(dev, nd);
     qdev_prop_set_uint32(dev, "rxmem", rxmem);
     qdev_prop_set_uint32(dev, "txmem", txmem);
-    qdev_prop_set_ptr(dev, "dmach", dmach);
+    object_property_set_link(OBJECT(dev), OBJECT(peer), "tx_dev", NULL);
     qdev_init_nofail(dev);
     sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
     sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq);
@@ -68,21 +69,16 @@ xilinx_axiethernet_create(void *dmach,
     return dev;
 }
 
-static inline DeviceState *
-xilinx_axiethernetdma_create(void *dmach,
-                             target_phys_addr_t base, qemu_irq irq,
-                             qemu_irq irq2, int freqhz)
+static inline void
+xilinx_axiethernetdma_init(DeviceState *dev, StreamSlave *peer,
+                           target_phys_addr_t base, qemu_irq irq,
+                           qemu_irq irq2, int freqhz)
 {
-    DeviceState *dev = NULL;
-
-    dev = qdev_create(NULL, "xlnx.axi-dma");
     qdev_prop_set_uint32(dev, "freqhz", freqhz);
-    qdev_prop_set_ptr(dev, "dmach", dmach);
+    object_property_set_link(OBJECT(dev), OBJECT(peer), "tx_dev", NULL);
     qdev_init_nofail(dev);
 
     sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
     sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq);
     sysbus_connect_irq(sysbus_from_qdev(dev), 1, irq2);
-
-    return dev;
 }
diff --git a/hw/xilinx_axidma.c b/hw/xilinx_axidma.c
index f4bec37c7a..0e28c51738 100644
--- a/hw/xilinx_axidma.c
+++ b/hw/xilinx_axidma.c
@@ -29,7 +29,7 @@
 #include "qemu-log.h"
 #include "qdev-addr.h"
 
-#include "xilinx_axidma.h"
+#include "stream.h"
 
 #define D(x)
 
@@ -77,7 +77,7 @@ enum {
     SDESC_STATUS_COMPLETE = (1 << 31)
 };
 
-struct AXIStream {
+struct Stream {
     QEMUBH *bh;
     ptimer_state *ptimer;
     qemu_irq irq;
@@ -94,9 +94,9 @@ struct XilinxAXIDMA {
     SysBusDevice busdev;
     MemoryRegion iomem;
     uint32_t freqhz;
-    void *dmach;
+    StreamSlave *tx_dev;
 
-    struct AXIStream streams[2];
+    struct Stream streams[2];
 };
 
 /*
@@ -113,27 +113,27 @@ static inline int stream_desc_eof(struct SDesc *d)
     return d->control & SDESC_CTRL_EOF;
 }
 
-static inline int stream_resetting(struct AXIStream *s)
+static inline int stream_resetting(struct Stream *s)
 {
     return !!(s->regs[R_DMACR] & DMACR_RESET);
 }
 
-static inline int stream_running(struct AXIStream *s)
+static inline int stream_running(struct Stream *s)
 {
     return s->regs[R_DMACR] & DMACR_RUNSTOP;
 }
 
-static inline int stream_halted(struct AXIStream *s)
+static inline int stream_halted(struct Stream *s)
 {
     return s->regs[R_DMASR] & DMASR_HALTED;
 }
 
-static inline int stream_idle(struct AXIStream *s)
+static inline int stream_idle(struct Stream *s)
 {
     return !!(s->regs[R_DMASR] & DMASR_IDLE);
 }
 
-static void stream_reset(struct AXIStream *s)
+static void stream_reset(struct Stream *s)
 {
     s->regs[R_DMASR] = DMASR_HALTED;  /* starts up halted.  */
     s->regs[R_DMACR] = 1 << 16; /* Starts with one in compl threshold.  */
@@ -159,7 +159,7 @@ static void stream_desc_show(struct SDesc *d)
 }
 #endif
 
-static void stream_desc_load(struct AXIStream *s, target_phys_addr_t addr)
+static void stream_desc_load(struct Stream *s, target_phys_addr_t addr)
 {
     struct SDesc *d = &s->desc;
     int i;
@@ -176,7 +176,7 @@ static void stream_desc_load(struct AXIStream *s, target_phys_addr_t addr)
     }
 }
 
-static void stream_desc_store(struct AXIStream *s, target_phys_addr_t addr)
+static void stream_desc_store(struct Stream *s, target_phys_addr_t addr)
 {
     struct SDesc *d = &s->desc;
     int i;
@@ -192,7 +192,7 @@ static void stream_desc_store(struct AXIStream *s, target_phys_addr_t addr)
     cpu_physical_memory_write(addr, (void *) d, sizeof *d);
 }
 
-static void stream_update_irq(struct AXIStream *s)
+static void stream_update_irq(struct Stream *s)
 {
     unsigned int pending, mask, irq;
 
@@ -204,7 +204,7 @@ static void stream_update_irq(struct AXIStream *s)
     qemu_set_irq(s->irq, !!irq);
 }
 
-static void stream_reload_complete_cnt(struct AXIStream *s)
+static void stream_reload_complete_cnt(struct Stream *s)
 {
     unsigned int comp_th;
     comp_th = (s->regs[R_DMACR] >> 16) & 0xff;
@@ -213,14 +213,14 @@ static void stream_reload_complete_cnt(struct AXIStream *s)
 
 static void timer_hit(void *opaque)
 {
-    struct AXIStream *s = opaque;
+    struct Stream *s = opaque;
 
     stream_reload_complete_cnt(s);
     s->regs[R_DMASR] |= DMASR_DLY_IRQ;
     stream_update_irq(s);
 }
 
-static void stream_complete(struct AXIStream *s)
+static void stream_complete(struct Stream *s)
 {
     unsigned int comp_delay;
 
@@ -240,8 +240,8 @@ static void stream_complete(struct AXIStream *s)
     }
 }
 
-static void stream_process_mem2s(struct AXIStream *s,
-                                 struct XilinxDMAConnection *dmach)
+static void stream_process_mem2s(struct Stream *s,
+                                 StreamSlave *tx_dev)
 {
     uint32_t prev_d;
     unsigned char txbuf[16 * 1024];
@@ -276,7 +276,7 @@ static void stream_process_mem2s(struct AXIStream *s,
         s->pos += txlen;
 
         if (stream_desc_eof(&s->desc)) {
-            xlx_dma_push_to_client(dmach, txbuf, s->pos, app);
+            stream_push(tx_dev, txbuf, s->pos, app);
             s->pos = 0;
             stream_complete(s);
         }
@@ -295,7 +295,7 @@ static void stream_process_mem2s(struct AXIStream *s,
     }
 }
 
-static void stream_process_s2mem(struct AXIStream *s,
+static void stream_process_s2mem(struct Stream *s,
                                  unsigned char *buf, size_t len, uint32_t *app)
 {
     uint32_t prev_d;
@@ -351,11 +351,11 @@ static void stream_process_s2mem(struct AXIStream *s,
     }
 }
 
-static
-void axidma_push(void *opaque, unsigned char *buf, size_t len, uint32_t *app)
+static void
+axidma_push(StreamSlave *obj, unsigned char *buf, size_t len, uint32_t *app)
 {
-    struct XilinxAXIDMA *d = opaque;
-    struct AXIStream *s = &d->streams[1];
+    struct XilinxAXIDMA *d = FROM_SYSBUS(typeof(*d), SYS_BUS_DEVICE(obj));
+    struct Stream *s = &d->streams[1];
 
     if (!app) {
         hw_error("No stream app data!\n");
@@ -368,7 +368,7 @@ static uint64_t axidma_read(void *opaque, target_phys_addr_t addr,
                             unsigned size)
 {
     struct XilinxAXIDMA *d = opaque;
-    struct AXIStream *s;
+    struct Stream *s;
     uint32_t r = 0;
     int sid;
 
@@ -403,7 +403,7 @@ static void axidma_write(void *opaque, target_phys_addr_t addr,
                          uint64_t value, unsigned size)
 {
     struct XilinxAXIDMA *d = opaque;
-    struct AXIStream *s;
+    struct Stream *s;
     int sid;
 
     sid = streamid_from_addr(addr);
@@ -440,7 +440,7 @@ static void axidma_write(void *opaque, target_phys_addr_t addr,
             s->regs[addr] = value;
             s->regs[R_DMASR] &= ~DMASR_IDLE; /* Not idle.  */
             if (!sid) {
-                stream_process_mem2s(s, d->dmach);
+                stream_process_mem2s(s, d->tx_dev);
             }
             break;
         default:
@@ -466,12 +466,6 @@ static int xilinx_axidma_init(SysBusDevice *dev)
     sysbus_init_irq(dev, &s->streams[0].irq);
     sysbus_init_irq(dev, &s->streams[1].irq);
 
-    if (!s->dmach) {
-        hw_error("Unconnected DMA channel.\n");
-    }
-
-    xlx_dma_connect_dma(s->dmach, s, axidma_push);
-
     memory_region_init_io(&s->iomem, &axidma_ops, s,
                           "xlnx.axi-dma", R_MAX * 4 * 2);
     sysbus_init_mmio(dev, &s->iomem);
@@ -486,9 +480,16 @@ static int xilinx_axidma_init(SysBusDevice *dev)
     return 0;
 }
 
+static void xilinx_axidma_initfn(Object *obj)
+{
+    struct XilinxAXIDMA *s = FROM_SYSBUS(typeof(*s), SYS_BUS_DEVICE(obj));
+
+    object_property_add_link(obj, "axistream-connected", TYPE_STREAM_SLAVE,
+                             (Object **) &s->tx_dev, NULL);
+}
+
 static Property axidma_properties[] = {
     DEFINE_PROP_UINT32("freqhz", struct XilinxAXIDMA, freqhz, 50000000),
-    DEFINE_PROP_PTR("dmach", struct XilinxAXIDMA, dmach),
     DEFINE_PROP_END_OF_LIST(),
 };
 
@@ -496,9 +497,11 @@ static void axidma_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+    StreamSlaveClass *ssc = STREAM_SLAVE_CLASS(klass);
 
     k->init = xilinx_axidma_init;
     dc->props = axidma_properties;
+    ssc->push = axidma_push;
 }
 
 static TypeInfo axidma_info = {
@@ -506,6 +509,11 @@ static TypeInfo axidma_info = {
     .parent        = TYPE_SYS_BUS_DEVICE,
     .instance_size = sizeof(struct XilinxAXIDMA),
     .class_init    = axidma_class_init,
+    .instance_init = xilinx_axidma_initfn,
+    .interfaces = (InterfaceInfo[]) {
+        { TYPE_STREAM_SLAVE },
+        { }
+    }
 };
 
 static void xilinx_axidma_register_types(void)
diff --git a/hw/xilinx_axidma.h b/hw/xilinx_axidma.h
deleted file mode 100644
index 37cb6f0911..0000000000
--- a/hw/xilinx_axidma.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/* AXI DMA connection. Used until qdev provides a generic way.  */
-typedef void (*DMAPushFn)(void *opaque,
-                            unsigned char *buf, size_t len, uint32_t *app);
-
-struct XilinxDMAConnection {
-    void *dma;
-    void *client;
-
-    DMAPushFn to_dma;
-    DMAPushFn to_client;
-};
-
-static inline void xlx_dma_connect_client(struct XilinxDMAConnection *dmach,
-                                          void *c, DMAPushFn f)
-{
-    dmach->client = c;
-    dmach->to_client = f;
-}
-
-static inline void xlx_dma_connect_dma(struct XilinxDMAConnection *dmach,
-                                       void *d, DMAPushFn f)
-{
-    dmach->dma = d;
-    dmach->to_dma = f;
-}
-
-static inline
-void xlx_dma_push_to_dma(struct XilinxDMAConnection *dmach,
-                         uint8_t *buf, size_t len, uint32_t *app)
-{
-    dmach->to_dma(dmach->dma, buf, len, app);
-}
-static inline
-void xlx_dma_push_to_client(struct XilinxDMAConnection *dmach,
-                            uint8_t *buf, size_t len, uint32_t *app)
-{
-    dmach->to_client(dmach->client, buf, len, app);
-}
-
diff --git a/hw/xilinx_axienet.c b/hw/xilinx_axienet.c
index adfaf2c50e..eec155d440 100644
--- a/hw/xilinx_axienet.c
+++ b/hw/xilinx_axienet.c
@@ -28,7 +28,7 @@
 #include "net.h"
 #include "net/checksum.h"
 
-#include "xilinx_axidma.h"
+#include "stream.h"
 
 #define DPHY(x)
 
@@ -310,7 +310,7 @@ struct XilinxAXIEnet {
     SysBusDevice busdev;
     MemoryRegion iomem;
     qemu_irq irq;
-    void *dmach;
+    StreamSlave *tx_dev;
     NICState *nic;
     NICConf conf;
 
@@ -648,7 +648,6 @@ static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size)
     uint16_t csum16;
     int i;
 
-    s = s;
     DENET(qemu_log("%s: %zd bytes\n", __func__, size));
 
     unicast = ~buf[0] & 0x1;
@@ -773,7 +772,7 @@ static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size)
     /* Good frame.  */
     app[2] |= 1 << 6;
 
-    xlx_dma_push_to_dma(s->dmach, (void *)s->rxmem, size, app);
+    stream_push(s->tx_dev, (void *)s->rxmem, size, app);
 
     s->regs[R_IS] |= IS_RX_COMPLETE;
     enet_update_irq(s);
@@ -789,9 +788,9 @@ static void eth_cleanup(NetClientState *nc)
 }
 
 static void
-axienet_stream_push(void *opaque, uint8_t *buf, size_t size, uint32_t *hdr)
+axienet_stream_push(StreamSlave *obj, uint8_t *buf, size_t size, uint32_t *hdr)
 {
-    struct XilinxAXIEnet *s = opaque;
+    struct XilinxAXIEnet *s = FROM_SYSBUS(typeof(*s), SYS_BUS_DEVICE(obj));
 
     /* TX enable ?  */
     if (!(s->tc & TC_TX)) {
@@ -845,12 +844,6 @@ static int xilinx_enet_init(SysBusDevice *dev)
 
     sysbus_init_irq(dev, &s->irq);
 
-    if (!s->dmach) {
-        hw_error("Unconnected Xilinx Ethernet MAC.\n");
-    }
-
-    xlx_dma_connect_client(s->dmach, s, axienet_stream_push);
-
     memory_region_init_io(&s->iomem, &enet_ops, s, "enet", 0x40000);
     sysbus_init_mmio(dev, &s->iomem);
 
@@ -870,11 +863,18 @@ static int xilinx_enet_init(SysBusDevice *dev)
     return 0;
 }
 
+static void xilinx_enet_initfn(Object *obj)
+{
+    struct XilinxAXIEnet *s = FROM_SYSBUS(typeof(*s), SYS_BUS_DEVICE(obj));
+
+    object_property_add_link(obj, "axistream-connected", TYPE_STREAM_SLAVE,
+                             (Object **) &s->tx_dev, NULL);
+}
+
 static Property xilinx_enet_properties[] = {
     DEFINE_PROP_UINT32("phyaddr", struct XilinxAXIEnet, c_phyaddr, 7),
     DEFINE_PROP_UINT32("rxmem", struct XilinxAXIEnet, c_rxmem, 0x1000),
     DEFINE_PROP_UINT32("txmem", struct XilinxAXIEnet, c_txmem, 0x1000),
-    DEFINE_PROP_PTR("dmach", struct XilinxAXIEnet, dmach),
     DEFINE_NIC_PROPERTIES(struct XilinxAXIEnet, conf),
     DEFINE_PROP_END_OF_LIST(),
 };
@@ -883,9 +883,11 @@ static void xilinx_enet_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+    StreamSlaveClass *ssc = STREAM_SLAVE_CLASS(klass);
 
     k->init = xilinx_enet_init;
     dc->props = xilinx_enet_properties;
+    ssc->push = axienet_stream_push;
 }
 
 static TypeInfo xilinx_enet_info = {
@@ -893,6 +895,11 @@ static TypeInfo xilinx_enet_info = {
     .parent        = TYPE_SYS_BUS_DEVICE,
     .instance_size = sizeof(struct XilinxAXIEnet),
     .class_init    = xilinx_enet_class_init,
+    .instance_init = xilinx_enet_initfn,
+    .interfaces = (InterfaceInfo[]) {
+            { TYPE_STREAM_SLAVE },
+            { }
+    }
 };
 
 static void xilinx_enet_register_types(void)
diff --git a/hw/xtensa_lx60.c b/hw/xtensa_lx60.c
index c4f616f4fb..3653f65b1e 100644
--- a/hw/xtensa_lx60.c
+++ b/hw/xtensa_lx60.c
@@ -173,7 +173,7 @@ static void lx_init(const LxBoardDesc *board,
     int n;
 
     if (!cpu_model) {
-        cpu_model = "dc232b";
+        cpu_model = XTENSA_DEFAULT_CPU_MODEL;
     }
 
     for (n = 0; n < smp_cpus; n++) {
@@ -300,14 +300,14 @@ static void xtensa_lx200_init(ram_addr_t ram_size,
 
 static QEMUMachine xtensa_lx60_machine = {
     .name = "lx60",
-    .desc = "lx60 EVB (dc232b)",
+    .desc = "lx60 EVB (" XTENSA_DEFAULT_CPU_MODEL ")",
     .init = xtensa_lx60_init,
     .max_cpus = 4,
 };
 
 static QEMUMachine xtensa_lx200_machine = {
     .name = "lx200",
-    .desc = "lx200 EVB (dc232b)",
+    .desc = "lx200 EVB (" XTENSA_DEFAULT_CPU_MODEL ")",
     .init = xtensa_lx200_init,
     .max_cpus = 4,
 };
diff --git a/hw/xtensa_sim.c b/hw/xtensa_sim.c
index 1ce07fb899..831460b7c4 100644
--- a/hw/xtensa_sim.c
+++ b/hw/xtensa_sim.c
@@ -102,7 +102,7 @@ static void xtensa_sim_init(ram_addr_t ram_size,
                      const char *initrd_filename, const char *cpu_model)
 {
     if (!cpu_model) {
-        cpu_model = "dc232b";
+        cpu_model = XTENSA_DEFAULT_CPU_MODEL;
     }
     sim_init(ram_size, boot_device, kernel_filename, kernel_cmdline,
             initrd_filename, cpu_model);
@@ -110,7 +110,8 @@ static void xtensa_sim_init(ram_addr_t ram_size,
 
 static QEMUMachine xtensa_sim_machine = {
     .name = "sim",
-    .desc = "sim machine (dc232b)",
+    .desc = "sim machine (" XTENSA_DEFAULT_CPU_MODEL ")",
+    .is_default = true,
     .init = xtensa_sim_init,
     .max_cpus = 4,
 };
diff --git a/include/qemu/object.h b/include/qemu/object.h
index 8b17776bb3..cc75feed66 100644
--- a/include/qemu/object.h
+++ b/include/qemu/object.h
@@ -239,6 +239,7 @@ struct ObjectClass
 {
     /*< private >*/
     Type type;
+    GSList *interfaces;
 };
 
 /**
@@ -260,7 +261,6 @@ struct Object
 {
     /*< private >*/
     ObjectClass *class;
-    GSList *interfaces;
     QTAILQ_HEAD(, ObjectProperty) properties;
     uint32_t ref;
     Object *parent;
@@ -387,6 +387,16 @@ struct TypeInfo
     OBJECT_CLASS_CHECK(class, object_get_class(OBJECT(obj)), name)
 
 /**
+ * InterfaceInfo:
+ * @type: The name of the interface.
+ *
+ * The information associated with an interface.
+ */
+struct InterfaceInfo {
+    const char *type;
+};
+
+/**
  * InterfaceClass:
  * @parent_class: the base class
  *
@@ -396,26 +406,30 @@ struct TypeInfo
 struct InterfaceClass
 {
     ObjectClass parent_class;
+    /*< private >*/
+    ObjectClass *concrete_class;
 };
 
+#define TYPE_INTERFACE "interface"
+
 /**
- * InterfaceInfo:
- * @type: The name of the interface.
- * @interface_initfn: This method is called during class initialization and is
- *   used to initialize an interface associated with a class.  This function
- *   should initialize any default virtual functions for a class and/or override
- *   virtual functions in a parent class.
- *
- * The information associated with an interface.
+ * INTERFACE_CLASS:
+ * @klass: class to cast from
+ * Returns: An #InterfaceClass or raise an error if cast is invalid
  */
-struct InterfaceInfo
-{
-    const char *type;
+#define INTERFACE_CLASS(klass) \
+    OBJECT_CLASS_CHECK(InterfaceClass, klass, TYPE_INTERFACE)
 
-    void (*interface_initfn)(ObjectClass *class, void *data);
-};
-
-#define TYPE_INTERFACE "interface"
+/**
+ * INTERFACE_CHECK:
+ * @interface: the type to return
+ * @obj: the object to convert to an interface
+ * @name: the interface type name
+ *
+ * Returns: @obj casted to @interface if cast is valid, otherwise raise error.
+ */
+#define INTERFACE_CHECK(interface, obj, name) \
+    ((interface *)object_dynamic_cast_assert(OBJECT((obj)), (name)))
 
 /**
  * object_new:
diff --git a/include/qemu/page_cache.h b/include/qemu/page_cache.h
new file mode 100644
index 0000000000..3839ac7726
--- /dev/null
+++ b/include/qemu/page_cache.h
@@ -0,0 +1,79 @@
+/*
+ * Page cache for QEMU
+ * The cache is base on a hash of the page address
+ *
+ * Copyright 2012 Red Hat, Inc. and/or its affiliates
+ *
+ * Authors:
+ *  Orit Wasserman  <owasserm@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef PAGE_CACHE_H
+#define PAGE_CACHE_H
+
+/* Page cache for storing guest pages */
+typedef struct PageCache PageCache;
+
+/**
+ * cache_init: Initialize the page cache
+ *
+ *
+ * Returns new allocated cache or NULL on error
+ *
+ * @cache pointer to the PageCache struct
+ * @num_pages: cache maximal number of cached pages
+ * @page_size: cache page size
+ */
+PageCache *cache_init(int64_t num_pages, unsigned int page_size);
+
+/**
+ * cache_fini: free all cache resources
+ * @cache pointer to the PageCache struct
+ */
+void cache_fini(PageCache *cache);
+
+/**
+ * cache_is_cached: Checks to see if the page is cached
+ *
+ * Returns %true if page is cached
+ *
+ * @cache pointer to the PageCache struct
+ * @addr: page addr
+ */
+bool cache_is_cached(const PageCache *cache, uint64_t addr);
+
+/**
+ * get_cached_data: Get the data cached for an addr
+ *
+ * Returns pointer to the data cached or NULL if not cached
+ *
+ * @cache pointer to the PageCache struct
+ * @addr: page addr
+ */
+uint8_t *get_cached_data(const PageCache *cache, uint64_t addr);
+
+/**
+ * cache_insert: insert the page into the cache. the previous value will be overwritten
+ *
+ * @cache pointer to the PageCache struct
+ * @addr: page address
+ * @pdata: pointer to the page
+ */
+void cache_insert(PageCache *cache, uint64_t addr, uint8_t *pdata);
+
+/**
+ * cache_resize: resize the page cache. In case of size reduction the extra
+ * pages will be freed
+ *
+ * Returns -1 on error new cache size on success
+ *
+ * @cache pointer to the PageCache struct
+ * @num_pages: new page cache size (in pages)
+ */
+int64_t cache_resize(PageCache *cache, int64_t num_pages);
+
+#endif
diff --git a/kvm-all.c b/kvm-all.c
index 2148b20bdb..34b02c1fba 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -100,6 +100,10 @@ struct KVMState
 
 KVMState *kvm_state;
 bool kvm_kernel_irqchip;
+bool kvm_async_interrupts_allowed;
+bool kvm_irqfds_allowed;
+bool kvm_msi_via_irqfd_allowed;
+bool kvm_gsi_routing_allowed;
 
 static const KVMCapabilityInfo kvm_required_capabilites[] = {
     KVM_CAP_INFO(USER_MEMORY),
@@ -852,18 +856,18 @@ static void kvm_handle_interrupt(CPUArchState *env, int mask)
     }
 }
 
-int kvm_irqchip_set_irq(KVMState *s, int irq, int level)
+int kvm_set_irq(KVMState *s, int irq, int level)
 {
     struct kvm_irq_level event;
     int ret;
 
-    assert(kvm_irqchip_in_kernel());
+    assert(kvm_async_interrupts_enabled());
 
     event.level = level;
     event.irq = irq;
     ret = kvm_vm_ioctl(s, s->irqchip_inject_ioctl, &event);
     if (ret < 0) {
-        perror("kvm_set_irqchip_line");
+        perror("kvm_set_irq");
         abort();
     }
 
@@ -1088,7 +1092,7 @@ int kvm_irqchip_send_msi(KVMState *s, MSIMessage msg)
 
     assert(route->kroute.type == KVM_IRQ_ROUTING_MSI);
 
-    return kvm_irqchip_set_irq(s, route->kroute.gsi, 1);
+    return kvm_set_irq(s, route->kroute.gsi, 1);
 }
 
 int kvm_irqchip_add_msi_route(KVMState *s, MSIMessage msg)
@@ -1096,7 +1100,7 @@ int kvm_irqchip_add_msi_route(KVMState *s, MSIMessage msg)
     struct kvm_irq_routing_entry kroute;
     int virq;
 
-    if (!kvm_irqchip_in_kernel()) {
+    if (!kvm_gsi_routing_enabled()) {
         return -ENOSYS;
     }
 
@@ -1125,7 +1129,7 @@ static int kvm_irqchip_assign_irqfd(KVMState *s, int fd, int virq, bool assign)
         .flags = assign ? 0 : KVM_IRQFD_FLAG_DEASSIGN,
     };
 
-    if (!kvm_irqchip_in_kernel()) {
+    if (!kvm_irqfds_enabled()) {
         return -ENOSYS;
     }
 
@@ -1201,12 +1205,36 @@ static int kvm_irqchip_create(KVMState *s)
         s->irqchip_inject_ioctl = KVM_IRQ_LINE_STATUS;
     }
     kvm_kernel_irqchip = true;
+    /* If we have an in-kernel IRQ chip then we must have asynchronous
+     * interrupt delivery (though the reverse is not necessarily true)
+     */
+    kvm_async_interrupts_allowed = true;
 
     kvm_init_irq_routing(s);
 
     return 0;
 }
 
+static int kvm_max_vcpus(KVMState *s)
+{
+    int ret;
+
+    /* Find number of supported CPUs using the recommended
+     * procedure from the kernel API documentation to cope with
+     * older kernels that may be missing capabilities.
+     */
+    ret = kvm_check_extension(s, KVM_CAP_MAX_VCPUS);
+    if (ret) {
+        return ret;
+    }
+    ret = kvm_check_extension(s, KVM_CAP_NR_VCPUS);
+    if (ret) {
+        return ret;
+    }
+
+    return 4;
+}
+
 int kvm_init(void)
 {
     static const char upgrade_note[] =
@@ -1216,6 +1244,7 @@ int kvm_init(void)
     const KVMCapabilityInfo *missing_cap;
     int ret;
     int i;
+    int max_vcpus;
 
     s = g_malloc0(sizeof(KVMState));
 
@@ -1256,6 +1285,14 @@ int kvm_init(void)
         goto err;
     }
 
+    max_vcpus = kvm_max_vcpus(s);
+    if (smp_cpus > max_vcpus) {
+        ret = -EINVAL;
+        fprintf(stderr, "Number of SMP cpus requested (%d) exceeds max cpus "
+                "supported by KVM (%d)\n", smp_cpus, max_vcpus);
+        goto err;
+    }
+
     s->vmfd = kvm_ioctl(s, KVM_CREATE_VM, 0);
     if (s->vmfd < 0) {
 #ifdef TARGET_S390X
@@ -1667,11 +1704,6 @@ int kvm_has_gsi_routing(void)
 #endif
 }
 
-int kvm_allows_irq0_override(void)
-{
-    return !kvm_irqchip_in_kernel() || kvm_has_gsi_routing();
-}
-
 void *kvm_vmalloc(ram_addr_t size)
 {
 #ifdef TARGET_S390X
diff --git a/kvm-stub.c b/kvm-stub.c
index d23b11c020..94c9ea15b0 100644
--- a/kvm-stub.c
+++ b/kvm-stub.c
@@ -19,6 +19,10 @@
 
 KVMState *kvm_state;
 bool kvm_kernel_irqchip;
+bool kvm_async_interrupts_allowed;
+bool kvm_irqfds_allowed;
+bool kvm_msi_via_irqfd_allowed;
+bool kvm_gsi_routing_allowed;
 
 int kvm_init_vcpu(CPUArchState *env)
 {
@@ -71,11 +75,6 @@ int kvm_has_many_ioeventfds(void)
     return 0;
 }
 
-int kvm_allows_irq0_override(void)
-{
-    return 1;
-}
-
 int kvm_has_pit_state2(void)
 {
     return 0;
diff --git a/kvm.h b/kvm.h
index 2617dd5acd..5b8f588813 100644
--- a/kvm.h
+++ b/kvm.h
@@ -24,13 +24,69 @@
 
 extern int kvm_allowed;
 extern bool kvm_kernel_irqchip;
+extern bool kvm_async_interrupts_allowed;
+extern bool kvm_irqfds_allowed;
+extern bool kvm_msi_via_irqfd_allowed;
+extern bool kvm_gsi_routing_allowed;
 
 #if defined CONFIG_KVM || !defined NEED_CPU_H
 #define kvm_enabled()           (kvm_allowed)
+/**
+ * kvm_irqchip_in_kernel:
+ *
+ * Returns: true if the user asked us to create an in-kernel
+ * irqchip via the "kernel_irqchip=on" machine option.
+ * What this actually means is architecture and machine model
+ * specific: on PC, for instance, it means that the LAPIC,
+ * IOAPIC and PIT are all in kernel. This function should never
+ * be used from generic target-independent code: use one of the
+ * following functions or some other specific check instead.
+ */
 #define kvm_irqchip_in_kernel() (kvm_kernel_irqchip)
+
+/**
+ * kvm_async_interrupts_enabled:
+ *
+ * Returns: true if we can deliver interrupts to KVM
+ * asynchronously (ie by ioctl from any thread at any time)
+ * rather than having to do interrupt delivery synchronously
+ * (where the vcpu must be stopped at a suitable point first).
+ */
+#define kvm_async_interrupts_enabled() (kvm_async_interrupts_allowed)
+
+/**
+ * kvm_irqfds_enabled:
+ *
+ * Returns: true if we can use irqfds to inject interrupts into
+ * a KVM CPU (ie the kernel supports irqfds and we are running
+ * with a configuration where it is meaningful to use them).
+ */
+#define kvm_irqfds_enabled() (kvm_irqfds_allowed)
+
+/**
+ * kvm_msi_via_irqfd_enabled:
+ *
+ * Returns: true if we can route a PCI MSI (Message Signaled Interrupt)
+ * to a KVM CPU via an irqfd. This requires that the kernel supports
+ * this and that we're running in a configuration that permits it.
+ */
+#define kvm_msi_via_irqfd_enabled() (kvm_msi_via_irqfd_allowed)
+
+/**
+ * kvm_gsi_routing_enabled:
+ *
+ * Returns: true if GSI routing is enabled (ie the kernel supports
+ * it and we're running in a configuration that permits it).
+ */
+#define kvm_gsi_routing_enabled() (kvm_gsi_routing_allowed)
+
 #else
 #define kvm_enabled()           (0)
 #define kvm_irqchip_in_kernel() (false)
+#define kvm_async_interrupts_enabled() (false)
+#define kvm_irqfds_enabled() (false)
+#define kvm_msi_via_irqfd_enabled() (false)
+#define kvm_gsi_routing_allowed() (false)
 #endif
 
 struct kvm_run;
@@ -62,8 +118,6 @@ int kvm_has_pit_state2(void);
 int kvm_has_many_ioeventfds(void);
 int kvm_has_gsi_routing(void);
 
-int kvm_allows_irq0_override(void);
-
 #ifdef NEED_CPU_H
 int kvm_init_vcpu(CPUArchState *env);
 
@@ -133,7 +187,7 @@ int kvm_arch_on_sigbus(int code, void *addr);
 
 void kvm_arch_init_irq_routing(KVMState *s);
 
-int kvm_irqchip_set_irq(KVMState *s, int irq, int level);
+int kvm_set_irq(KVMState *s, int irq, int level);
 int kvm_irqchip_send_msi(KVMState *s, MSIMessage msg);
 
 void kvm_irqchip_add_irq_route(KVMState *s, int gsi, int irqchip, int pin);
diff --git a/linux-user/main.c b/linux-user/main.c
index 53714de0d4..9d921aa4f0 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -958,7 +958,8 @@ void cpu_loop(CPUUniCore32State *env)
                 }
             }
             break;
-        case UC32_EXCP_TRAP:
+        case UC32_EXCP_DTRAP:
+        case UC32_EXCP_ITRAP:
             info.si_signo = SIGSEGV;
             info.si_errno = 0;
             /* XXX: check env->error_code */
diff --git a/linux-user/signal.c b/linux-user/signal.c
index 9be5ac0788..78691473fa 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -1844,7 +1844,7 @@ typedef struct {
 } __siginfo_t;
 
 typedef struct {
-        unsigned   long si_float_regs [32];
+        abi_ulong       si_float_regs[32];
         unsigned   long si_fsr;
         unsigned   long si_fpqdepth;
         struct {
@@ -2056,11 +2056,9 @@ restore_fpu_state(CPUSPARCState *env, qemu_siginfo_fpu_t *fpu)
                 return -EFAULT;
 #endif
 
-#if 0
         /* XXX: incorrect */
-        err = __copy_from_user(&env->fpr[0], &fpu->si_float_regs[0],
-	                             (sizeof(unsigned long) * 32));
-#endif
+        err = copy_from_user(&env->fpr[0], fpu->si_float_regs[0],
+                             (sizeof(abi_ulong) * 32));
         err |= __get_user(env->fsr, &fpu->si_fsr);
 #if 0
         err |= __get_user(current->thread.fpqdepth, &fpu->si_fpqdepth);
diff --git a/migration-tcp.c b/migration-tcp.c
index 440804db75..ac891c38a3 100644
--- a/migration-tcp.c
+++ b/migration-tcp.c
@@ -82,27 +82,23 @@ static void tcp_wait_for_connect(void *opaque)
 int tcp_start_outgoing_migration(MigrationState *s, const char *host_port,
                                  Error **errp)
 {
+    bool in_progress;
+
     s->get_error = socket_errno;
     s->write = socket_write;
     s->close = tcp_close;
 
-    s->fd = inet_connect(host_port, false, errp);
+    s->fd = inet_connect(host_port, false, &in_progress, errp);
+    if (error_is_set(errp)) {
+        migrate_fd_error(s);
+        return -1;
+    }
 
-    if (!error_is_set(errp)) {
-        migrate_fd_connect(s);
-    } else if (error_is_type(*errp, QERR_SOCKET_CONNECT_IN_PROGRESS)) {
+    if (in_progress) {
         DPRINTF("connect in progress\n");
         qemu_set_fd_handler2(s->fd, NULL, NULL, tcp_wait_for_connect, s);
-    } else if (error_is_type(*errp, QERR_SOCKET_CREATE_FAILED)) {
-        DPRINTF("connect failed\n");
-        return -1;
-    } else if (error_is_type(*errp, QERR_SOCKET_CONNECT_FAILED)) {
-        DPRINTF("connect failed\n");
-        migrate_fd_error(s);
-        return -1;
     } else {
-        DPRINTF("unknown error\n");
-        return -1;
+        migrate_fd_connect(s);
     }
 
     return 0;
diff --git a/migration.c b/migration.c
index 8db1b433f0..653a3c1a88 100644
--- a/migration.c
+++ b/migration.c
@@ -43,6 +43,9 @@ enum {
 
 #define MAX_THROTTLE  (32 << 20)      /* Migration speed throttling */
 
+/* Migration XBZRLE default cache size */
+#define DEFAULT_MIGRATE_CACHE_SIZE (64 * 1024 * 1024)
+
 static NotifierList migration_state_notifiers =
     NOTIFIER_LIST_INITIALIZER(migration_state_notifiers);
 
@@ -55,6 +58,7 @@ static MigrationState *migrate_get_current(void)
     static MigrationState current_migration = {
         .state = MIG_STATE_SETUP,
         .bandwidth_limit = MAX_THROTTLE,
+        .xbzrle_cache_size = DEFAULT_MIGRATE_CACHE_SIZE,
     };
 
     return &current_migration;
@@ -113,6 +117,43 @@ uint64_t migrate_max_downtime(void)
     return max_downtime;
 }
 
+MigrationCapabilityStatusList *qmp_query_migrate_capabilities(Error **errp)
+{
+    MigrationCapabilityStatusList *head = NULL;
+    MigrationCapabilityStatusList *caps;
+    MigrationState *s = migrate_get_current();
+    int i;
+
+    for (i = 0; i < MIGRATION_CAPABILITY_MAX; i++) {
+        if (head == NULL) {
+            head = g_malloc0(sizeof(*caps));
+            caps = head;
+        } else {
+            caps->next = g_malloc0(sizeof(*caps));
+            caps = caps->next;
+        }
+        caps->value =
+            g_malloc(sizeof(*caps->value));
+        caps->value->capability = i;
+        caps->value->state = s->enabled_capabilities[i];
+    }
+
+    return head;
+}
+
+static void get_xbzrle_cache_stats(MigrationInfo *info)
+{
+    if (migrate_use_xbzrle()) {
+        info->has_xbzrle_cache = true;
+        info->xbzrle_cache = g_malloc0(sizeof(*info->xbzrle_cache));
+        info->xbzrle_cache->cache_size = migrate_xbzrle_cache_size();
+        info->xbzrle_cache->bytes = xbzrle_mig_bytes_transferred();
+        info->xbzrle_cache->pages = xbzrle_mig_pages_transferred();
+        info->xbzrle_cache->cache_miss = xbzrle_mig_pages_cache_miss();
+        info->xbzrle_cache->overflow = xbzrle_mig_pages_overflow();
+    }
+}
+
 MigrationInfo *qmp_query_migrate(Error **errp)
 {
     MigrationInfo *info = g_malloc0(sizeof(*info));
@@ -133,6 +174,9 @@ MigrationInfo *qmp_query_migrate(Error **errp)
         info->ram->total = ram_bytes_total();
         info->ram->total_time = qemu_get_clock_ms(rt_clock)
             - s->total_time;
+        info->ram->duplicate = dup_mig_pages_transferred();
+        info->ram->normal = norm_mig_pages_transferred();
+        info->ram->normal_bytes = norm_mig_bytes_transferred();
 
         if (blk_mig_active()) {
             info->has_disk = true;
@@ -141,8 +185,12 @@ MigrationInfo *qmp_query_migrate(Error **errp)
             info->disk->remaining = blk_mig_bytes_remaining();
             info->disk->total = blk_mig_bytes_total();
         }
+
+        get_xbzrle_cache_stats(info);
         break;
     case MIG_STATE_COMPLETED:
+        get_xbzrle_cache_stats(info);
+
         info->has_status = true;
         info->status = g_strdup("completed");
 
@@ -152,6 +200,9 @@ MigrationInfo *qmp_query_migrate(Error **errp)
         info->ram->remaining = 0;
         info->ram->total = ram_bytes_total();
         info->ram->total_time = s->total_time;
+        info->ram->duplicate = dup_mig_pages_transferred();
+        info->ram->normal = norm_mig_pages_transferred();
+        info->ram->normal_bytes = norm_mig_bytes_transferred();
         break;
     case MIG_STATE_ERROR:
         info->has_status = true;
@@ -166,6 +217,22 @@ MigrationInfo *qmp_query_migrate(Error **errp)
     return info;
 }
 
+void qmp_migrate_set_capabilities(MigrationCapabilityStatusList *params,
+                                  Error **errp)
+{
+    MigrationState *s = migrate_get_current();
+    MigrationCapabilityStatusList *cap;
+
+    if (s->state == MIG_STATE_ACTIVE) {
+        error_set(errp, QERR_MIGRATION_ACTIVE);
+        return;
+    }
+
+    for (cap = params; cap; cap = cap->next) {
+        s->enabled_capabilities[cap->value->capability] = cap->value->state;
+    }
+}
+
 /* shared migration helpers */
 
 static int migrate_fd_cleanup(MigrationState *s)
@@ -375,10 +442,18 @@ static MigrationState *migrate_init(const MigrationParams *params)
 {
     MigrationState *s = migrate_get_current();
     int64_t bandwidth_limit = s->bandwidth_limit;
+    bool enabled_capabilities[MIGRATION_CAPABILITY_MAX];
+    int64_t xbzrle_cache_size = s->xbzrle_cache_size;
+
+    memcpy(enabled_capabilities, s->enabled_capabilities,
+           sizeof(enabled_capabilities));
 
     memset(s, 0, sizeof(*s));
     s->bandwidth_limit = bandwidth_limit;
     s->params = *params;
+    memcpy(s->enabled_capabilities, enabled_capabilities,
+           sizeof(enabled_capabilities));
+    s->xbzrle_cache_size = xbzrle_cache_size;
 
     s->bandwidth_limit = bandwidth_limit;
     s->state = MIG_STATE_SETUP;
@@ -459,6 +534,25 @@ void qmp_migrate_cancel(Error **errp)
     migrate_fd_cancel(migrate_get_current());
 }
 
+void qmp_migrate_set_cache_size(int64_t value, Error **errp)
+{
+    MigrationState *s = migrate_get_current();
+
+    /* Check for truncation */
+    if (value != (size_t)value) {
+        error_set(errp, QERR_INVALID_PARAMETER_VALUE, "cache size",
+                  "exceeding address space");
+        return;
+    }
+
+    s->xbzrle_cache_size = xbzrle_cache_resize(value);
+}
+
+int64_t qmp_query_migrate_cache_size(Error **errp)
+{
+    return migrate_xbzrle_cache_size();
+}
+
 void qmp_migrate_set_speed(int64_t value, Error **errp)
 {
     MigrationState *s;
@@ -478,3 +572,21 @@ void qmp_migrate_set_downtime(double value, Error **errp)
     value = MAX(0, MIN(UINT64_MAX, value));
     max_downtime = (uint64_t)value;
 }
+
+int migrate_use_xbzrle(void)
+{
+    MigrationState *s;
+
+    s = migrate_get_current();
+
+    return s->enabled_capabilities[MIGRATION_CAPABILITY_XBZRLE];
+}
+
+int64_t migrate_xbzrle_cache_size(void)
+{
+    MigrationState *s;
+
+    s = migrate_get_current();
+
+    return s->xbzrle_cache_size;
+}
diff --git a/migration.h b/migration.h
index 57572a61e9..a9852fcae0 100644
--- a/migration.h
+++ b/migration.h
@@ -19,6 +19,7 @@
 #include "notify.h"
 #include "error.h"
 #include "vmstate.h"
+#include "qapi-types.h"
 
 struct MigrationParams {
     bool blk;
@@ -39,6 +40,8 @@ struct MigrationState
     void *opaque;
     MigrationParams params;
     int64_t total_time;
+    bool enabled_capabilities[MIGRATION_CAPABILITY_MAX];
+    int64_t xbzrle_cache_size;
 };
 
 void process_incoming_migration(QEMUFile *f);
@@ -84,6 +87,15 @@ uint64_t ram_bytes_total(void);
 
 extern SaveVMHandlers savevm_ram_handlers;
 
+uint64_t dup_mig_bytes_transferred(void);
+uint64_t dup_mig_pages_transferred(void);
+uint64_t norm_mig_bytes_transferred(void);
+uint64_t norm_mig_pages_transferred(void);
+uint64_t xbzrle_mig_bytes_transferred(void);
+uint64_t xbzrle_mig_pages_transferred(void);
+uint64_t xbzrle_mig_pages_overflow(void);
+uint64_t xbzrle_mig_pages_cache_miss(void);
+
 /**
  * @migrate_add_blocker - prevent migration from proceeding
  *
@@ -98,4 +110,13 @@ void migrate_add_blocker(Error *reason);
  */
 void migrate_del_blocker(Error *reason);
 
+int xbzrle_encode_buffer(uint8_t *old_buf, uint8_t *new_buf, int slen,
+                         uint8_t *dst, int dlen);
+int xbzrle_decode_buffer(uint8_t *src, int slen, uint8_t *dst, int dlen);
+
+int migrate_use_xbzrle(void);
+int64_t migrate_xbzrle_cache_size(void);
+
+int64_t xbzrle_cache_resize(int64_t new_size);
+
 #endif
diff --git a/monitor.c b/monitor.c
index 49dccfe854..dd63f1d640 100644
--- a/monitor.c
+++ b/monitor.c
@@ -172,41 +172,11 @@ struct Monitor {
     CPUArchState *mon_cpu;
     BlockDriverCompletionFunc *password_completion_cb;
     void *password_opaque;
-#ifdef CONFIG_DEBUG_MONITOR
-    int print_calls_nr;
-#endif
     QError *error;
     QLIST_HEAD(,mon_fd_t) fds;
     QLIST_ENTRY(Monitor) entry;
 };
 
-#ifdef CONFIG_DEBUG_MONITOR
-#define MON_DEBUG(fmt, ...) do {    \
-    fprintf(stderr, "Monitor: ");       \
-    fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
-
-static inline void mon_print_count_inc(Monitor *mon)
-{
-    mon->print_calls_nr++;
-}
-
-static inline void mon_print_count_init(Monitor *mon)
-{
-    mon->print_calls_nr = 0;
-}
-
-static inline int mon_print_count_get(const Monitor *mon)
-{
-    return mon->print_calls_nr;
-}
-
-#else /* !CONFIG_DEBUG_MONITOR */
-#define MON_DEBUG(fmt, ...) do { } while (0)
-static inline void mon_print_count_inc(Monitor *mon) { }
-static inline void mon_print_count_init(Monitor *mon) { }
-static inline int mon_print_count_get(const Monitor *mon) { return 0; }
-#endif /* CONFIG_DEBUG_MONITOR */
-
 /* QMP checker flags */
 #define QMP_ACCEPT_UNKNOWNS 1
 
@@ -299,8 +269,6 @@ void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap)
     if (!mon)
         return;
 
-    mon_print_count_inc(mon);
-
     if (monitor_ctrl_mode(mon)) {
         return;
     }
@@ -385,16 +353,26 @@ static void monitor_json_emitter(Monitor *mon, const QObject *data)
     QDECREF(json);
 }
 
+static QDict *build_qmp_error_dict(const QError *err)
+{
+    QObject *obj;
+
+    obj = qobject_from_jsonf("{ 'error': { 'class': %s, 'desc': %p } }",
+                             ErrorClass_lookup[err->err_class],
+                             qerror_human(err));
+
+    return qobject_to_qdict(obj);
+}
+
 static void monitor_protocol_emitter(Monitor *mon, QObject *data)
 {
     QDict *qmp;
 
     trace_monitor_protocol_emitter(mon);
 
-    qmp = qdict_new();
-
     if (!monitor_has_error(mon)) {
         /* success response */
+        qmp = qdict_new();
         if (data) {
             qobject_incref(data);
             qdict_put_obj(qmp, "return", data);
@@ -404,9 +382,7 @@ static void monitor_protocol_emitter(Monitor *mon, QObject *data)
         }
     } else {
         /* error response */
-        qdict_put(mon->error->error, "desc", qerror_human(mon->error));
-        qdict_put(qmp, "error", mon->error->error);
-        QINCREF(mon->error->error);
+        qmp = build_qmp_error_dict(mon->error);
         QDECREF(mon->error);
         mon->error = NULL;
     }
@@ -456,6 +432,7 @@ static const char *monitor_event_names[] = {
     [QEVENT_BLOCK_JOB_CANCELLED] = "BLOCK_JOB_CANCELLED",
     [QEVENT_DEVICE_TRAY_MOVED] = "DEVICE_TRAY_MOVED",
     [QEVENT_SUSPEND] = "SUSPEND",
+    [QEVENT_SUSPEND_DISK] = "SUSPEND_DISK",
     [QEVENT_WAKEUP] = "WAKEUP",
     [QEVENT_BALLOON_CHANGE] = "BALLOON_CHANGE",
 };
@@ -2655,6 +2632,20 @@ static mon_cmd_t info_cmds[] = {
         .mhandler.info = hmp_info_migrate,
     },
     {
+        .name       = "migrate_capabilities",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show current migration capabilities",
+        .mhandler.info = hmp_info_migrate_capabilities,
+    },
+    {
+        .name       = "migrate_cache_size",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show current migration xbzrle cache size",
+        .mhandler.info = hmp_info_migrate_cache_size,
+    },
+    {
         .name       = "balloon",
         .args_type  = "",
         .params     = "",
@@ -3860,8 +3851,6 @@ void monitor_set_error(Monitor *mon, QError *qerror)
     if (!mon->error) {
         mon->error = qerror;
     } else {
-        MON_DEBUG("Additional error report at %s:%d\n",
-                  qerror->file, qerror->linenr);
         QDECREF(qerror);
     }
 }
@@ -3875,36 +3864,7 @@ static void handler_audit(Monitor *mon, const mon_cmd_t *cmd, int ret)
          * Action: Report an internal error to the client if in QMP.
          */
         qerror_report(QERR_UNDEFINED_ERROR);
-        MON_DEBUG("command '%s' returned failure but did not pass an error\n",
-                  cmd->name);
     }
-
-#ifdef CONFIG_DEBUG_MONITOR
-    if (!ret && monitor_has_error(mon)) {
-        /*
-         * If it returns success, it must not have passed an error.
-         *
-         * Action: Report the passed error to the client.
-         */
-        MON_DEBUG("command '%s' returned success but passed an error\n",
-                  cmd->name);
-    }
-
-    if (mon_print_count_get(mon) > 0 && strcmp(cmd->name, "info") != 0) {
-        /*
-         * Handlers should not call Monitor print functions.
-         *
-         * Action: Ignore them in QMP.
-         *
-         * (XXX: we don't check any 'info' or 'query' command here
-         * because the user print function _is_ called by do_info(), hence
-         * we will trigger this check. This problem will go away when we
-         * make 'query' commands real and kill do_info())
-         */
-        MON_DEBUG("command '%s' called print functions %d time(s)\n",
-                  cmd->name, mon_print_count_get(mon));
-    }
-#endif
 }
 
 static void handle_user_command(Monitor *mon, const char *cmdline)
@@ -4433,8 +4393,6 @@ static void qmp_call_cmd(Monitor *mon, const mon_cmd_t *cmd,
     int ret;
     QObject *data = NULL;
 
-    mon_print_count_init(mon);
-
     ret = cmd->mhandler.cmd_new(mon, params, &data);
     handler_audit(mon, cmd, ret);
     monitor_protocol_emitter(mon, data);
diff --git a/monitor.h b/monitor.h
index 5f4de1b3da..4ef9a046f8 100644
--- a/monitor.h
+++ b/monitor.h
@@ -40,6 +40,7 @@ typedef enum MonitorEvent {
     QEVENT_BLOCK_JOB_CANCELLED,
     QEVENT_DEVICE_TRAY_MOVED,
     QEVENT_SUSPEND,
+    QEVENT_SUSPEND_DISK,
     QEVENT_WAKEUP,
     QEVENT_BALLOON_CHANGE,
 
diff --git a/nbd.c b/nbd.c
index dc0adf90ed..0dd60c5f4c 100644
--- a/nbd.c
+++ b/nbd.c
@@ -162,7 +162,7 @@ int tcp_socket_outgoing(const char *address, uint16_t port)
 
 int tcp_socket_outgoing_spec(const char *address_and_port)
 {
-    return inet_connect(address_and_port, true, NULL);
+    return inet_connect(address_and_port, true, NULL, NULL);
 }
 
 int tcp_socket_incoming(const char *address, uint16_t port)
diff --git a/net/slirp.c b/net/slirp.c
index 08adb97da5..8db66ea539 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -718,9 +718,9 @@ int net_init_slirp(const NetClientOptions *opts, const char *name,
     net_init_slirp_configs(user->hostfwd, SLIRP_CFG_HOSTFWD);
     net_init_slirp_configs(user->guestfwd, 0);
 
-    ret = net_slirp_init(peer, "user", name, user->restrict, vnet, user->host,
-                         user->hostname, user->tftp, user->bootfile,
-                         user->dhcpstart, user->dns, user->smb,
+    ret = net_slirp_init(peer, "user", name, user->q_restrict, vnet,
+                         user->host, user->hostname, user->tftp,
+                         user->bootfile, user->dhcpstart, user->dns, user->smb,
                          user->smbserver);
 
     while (slirp_configs) {
diff --git a/page_cache.c b/page_cache.c
new file mode 100644
index 0000000000..0294f7e9f6
--- /dev/null
+++ b/page_cache.c
@@ -0,0 +1,218 @@
+/*
+ * Page cache for QEMU
+ * The cache is base on a hash of the page address
+ *
+ * Copyright 2012 Red Hat, Inc. and/or its affiliates
+ *
+ * Authors:
+ *  Orit Wasserman  <owasserm@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <stdbool.h>
+#include <glib.h>
+#include <strings.h>
+
+#include "qemu-common.h"
+#include "qemu/page_cache.h"
+
+#ifdef DEBUG_CACHE
+#define DPRINTF(fmt, ...) \
+    do { fprintf(stdout, "cache: " fmt, ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) \
+    do { } while (0)
+#endif
+
+typedef struct CacheItem CacheItem;
+
+struct CacheItem {
+    uint64_t it_addr;
+    uint64_t it_age;
+    uint8_t *it_data;
+};
+
+struct PageCache {
+    CacheItem *page_cache;
+    unsigned int page_size;
+    int64_t max_num_items;
+    uint64_t max_item_age;
+    int64_t num_items;
+};
+
+PageCache *cache_init(int64_t num_pages, unsigned int page_size)
+{
+    int64_t i;
+
+    PageCache *cache;
+
+    if (num_pages <= 0) {
+        DPRINTF("invalid number of pages\n");
+        return NULL;
+    }
+
+    cache = g_malloc(sizeof(*cache));
+
+    /* round down to the nearest power of 2 */
+    if (!is_power_of_2(num_pages)) {
+        num_pages = pow2floor(num_pages);
+        DPRINTF("rounding down to %" PRId64 "\n", num_pages);
+    }
+    cache->page_size = page_size;
+    cache->num_items = 0;
+    cache->max_item_age = 0;
+    cache->max_num_items = num_pages;
+
+    DPRINTF("Setting cache buckets to %" PRId64 "\n", cache->max_num_items);
+
+    cache->page_cache = g_malloc((cache->max_num_items) *
+                                 sizeof(*cache->page_cache));
+
+    for (i = 0; i < cache->max_num_items; i++) {
+        cache->page_cache[i].it_data = NULL;
+        cache->page_cache[i].it_age = 0;
+        cache->page_cache[i].it_addr = -1;
+    }
+
+    return cache;
+}
+
+void cache_fini(PageCache *cache)
+{
+    int64_t i;
+
+    g_assert(cache);
+    g_assert(cache->page_cache);
+
+    for (i = 0; i < cache->max_num_items; i++) {
+        g_free(cache->page_cache[i].it_data);
+    }
+
+    g_free(cache->page_cache);
+    cache->page_cache = NULL;
+}
+
+static size_t cache_get_cache_pos(const PageCache *cache,
+                                  uint64_t address)
+{
+    size_t pos;
+
+    g_assert(cache->max_num_items);
+    pos = (address / cache->page_size) & (cache->max_num_items - 1);
+    return pos;
+}
+
+bool cache_is_cached(const PageCache *cache, uint64_t addr)
+{
+    size_t pos;
+
+    g_assert(cache);
+    g_assert(cache->page_cache);
+
+    pos = cache_get_cache_pos(cache, addr);
+
+    return (cache->page_cache[pos].it_addr == addr);
+}
+
+static CacheItem *cache_get_by_addr(const PageCache *cache, uint64_t addr)
+{
+    size_t pos;
+
+    g_assert(cache);
+    g_assert(cache->page_cache);
+
+    pos = cache_get_cache_pos(cache, addr);
+
+    return &cache->page_cache[pos];
+}
+
+uint8_t *get_cached_data(const PageCache *cache, uint64_t addr)
+{
+    return cache_get_by_addr(cache, addr)->it_data;
+}
+
+void cache_insert(PageCache *cache, uint64_t addr, uint8_t *pdata)
+{
+
+    CacheItem *it = NULL;
+
+    g_assert(cache);
+    g_assert(cache->page_cache);
+
+    /* actual update of entry */
+    it = cache_get_by_addr(cache, addr);
+
+    if (!it->it_data) {
+        cache->num_items++;
+    }
+
+    it->it_data = pdata;
+    it->it_age = ++cache->max_item_age;
+    it->it_addr = addr;
+}
+
+int64_t cache_resize(PageCache *cache, int64_t new_num_pages)
+{
+    PageCache *new_cache;
+    int64_t i;
+
+    CacheItem *old_it, *new_it;
+
+    g_assert(cache);
+
+    /* cache was not inited */
+    if (cache->page_cache == NULL) {
+        return -1;
+    }
+
+    /* same size */
+    if (pow2floor(new_num_pages) == cache->max_num_items) {
+        return cache->max_num_items;
+    }
+
+    new_cache = cache_init(new_num_pages, cache->page_size);
+    if (!(new_cache)) {
+        DPRINTF("Error creating new cache\n");
+        return -1;
+    }
+
+    /* move all data from old cache */
+    for (i = 0; i < cache->max_num_items; i++) {
+        old_it = &cache->page_cache[i];
+        if (old_it->it_addr != -1) {
+            /* check for collision, if there is, keep MRU page */
+            new_it = cache_get_by_addr(new_cache, old_it->it_addr);
+            if (new_it->it_data) {
+                /* keep the MRU page */
+                if (new_it->it_age >= old_it->it_age) {
+                    g_free(old_it->it_data);
+                } else {
+                    g_free(new_it->it_data);
+                    new_it->it_data = old_it->it_data;
+                    new_it->it_age = old_it->it_age;
+                    new_it->it_addr = old_it->it_addr;
+                }
+            } else {
+                cache_insert(new_cache, old_it->it_addr, old_it->it_data);
+            }
+        }
+    }
+
+    cache->page_cache = new_cache->page_cache;
+    cache->max_num_items = new_cache->max_num_items;
+    cache->num_items = new_cache->num_items;
+
+    g_free(new_cache);
+
+    return cache->max_num_items;
+}
diff --git a/qapi-schema.json b/qapi-schema.json
index cddf63a878..53bbe46e4d 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -3,6 +3,36 @@
 # QAPI Schema
 
 ##
+# @ErrorClass
+#
+# QEMU error classes
+#
+# @GenericError: this is used for errors that don't require a specific error
+#                class. This should be the default case for most errors
+#
+# @CommandNotFound: the requested command has not been found
+#
+# @DeviceEncrypted: the requested operation can't be fulfilled because the
+#                   selected device is encrypted
+#
+# @DeviceNotActive: a device has failed to be become active
+#
+# @DeviceNotFound: the requested device has not been found
+#
+# @KVMMissingCap: the requested operation can't be fulfilled because a
+#                 required KVM capability is missing
+#
+# @MigrationExpected: the requested operation can't be fulfilled because a
+#                     migration process is expected
+#
+# Since: 1.2
+##
+{ 'enum': 'ErrorClass',
+  'data': [ 'GenericError', 'CommandNotFound', 'DeviceEncrypted',
+            'DeviceNotActive', 'DeviceNotFound', 'KVMMissingCap',
+            'MigrationExpected' ] }
+
+##
 # @NameInfo:
 #
 # Guest name information.
@@ -260,15 +290,43 @@
 #
 # @total: total amount of bytes involved in the migration process
 #
-# @total_time: tota0l amount of ms since migration started.  If
+# @total-time: total amount of ms since migration started.  If
 #        migration has ended, it returns the total migration
 #        time. (since 1.2)
 #
-# Since: 0.14.0.
+# @duplicate: number of duplicate pages (since 1.2)
+#
+# @normal : number of normal pages (since 1.2)
+#
+# @normal-bytes : number of normal bytes sent (since 1.2)
+#
+# Since: 0.14.0
 ##
 { 'type': 'MigrationStats',
   'data': {'transferred': 'int', 'remaining': 'int', 'total': 'int' ,
-           'total_time': 'int' } }
+           'total-time': 'int', 'duplicate': 'int', 'normal': 'int',
+           'normal-bytes': 'int' } }
+
+##
+# @XBZRLECacheStats
+#
+# Detailed XBZRLE migration cache statistics
+#
+# @cache-size: XBZRLE cache size
+#
+# @bytes: amount of bytes already transferred to the target VM
+#
+# @pages: amount of pages transferred to the target VM
+#
+# @cache-miss: number of cache miss
+#
+# @overflow: number of overflows
+#
+# Since: 1.2
+##
+{ 'type': 'XBZRLECacheStats',
+  'data': {'cache-size': 'int', 'bytes': 'int', 'pages': 'int',
+           'cache-miss': 'int', 'overflow': 'int' } }
 
 ##
 # @MigrationInfo
@@ -288,11 +346,16 @@
 #        status, only returned if status is 'active' and it is a block
 #        migration
 #
+# @xbzrle-cache: #optional @XBZRLECacheStats containing detailed XBZRLE
+#                migration statistics, only returned if XBZRLE feature is on and
+#                status is 'active' or 'completed' (since 1.2)
+#
 # Since: 0.14.0
 ##
 { 'type': 'MigrationInfo',
   'data': {'*status': 'str', '*ram': 'MigrationStats',
-           '*disk': 'MigrationStats'} }
+           '*disk': 'MigrationStats',
+           '*xbzrle-cache': 'XBZRLECacheStats'} }
 
 ##
 # @query-migrate
@@ -306,6 +369,57 @@
 { 'command': 'query-migrate', 'returns': 'MigrationInfo' }
 
 ##
+# @MigrationCapability
+#
+# Migration capabilities enumeration
+#
+# @xbzrle: Migration supports xbzrle (Xor Based Zero Run Length Encoding).
+#          This feature allows us to minimize migration traffic for certain work
+#          loads, by sending compressed difference of the pages
+#
+# Since: 1.2
+##
+{ 'enum': 'MigrationCapability',
+  'data': ['xbzrle'] }
+
+##
+# @MigrationCapabilityStatus
+#
+# Migration capability information
+#
+# @capability: capability enum
+#
+# @state: capability state bool
+#
+# Since: 1.2
+##
+{ 'type': 'MigrationCapabilityStatus',
+  'data': { 'capability' : 'MigrationCapability', 'state' : 'bool' } }
+
+##
+# @migrate-set-capabilities
+#
+# Enable/Disable the following migration capabilities (like xbzrle)
+#
+# @capabilities: json array of capability modifications to make
+#
+# Since: 1.2
+##
+{ 'command': 'migrate-set-capabilities',
+  'data': { 'capabilities': ['MigrationCapabilityStatus'] } }
+
+##
+# @query-migrate-capabilities
+#
+# Returns information about the current migration capabilities status
+#
+# Returns: @MigrationCapabilitiesStatus
+#
+# Since: 1.2
+##
+{ 'command': 'query-migrate-capabilities', 'returns':   ['MigrationCapabilityStatus']}
+
+##
 # @MouseInfo:
 #
 # Information about a mouse device.
@@ -402,6 +516,9 @@
 #
 # @encrypted: true if the backing device is encrypted
 #
+# @encryption_key_missing: true if the backing device is encrypted but an
+#                          valid encryption key is missing
+#
 # @bps: total throughput limit in bytes per second is specified
 #
 # @bps_rd: read throughput limit in bytes per second is specified
@@ -421,9 +538,9 @@
 { 'type': 'BlockDeviceInfo',
   'data': { 'file': 'str', 'ro': 'bool', 'drv': 'str',
             '*backing_file': 'str', 'backing_file_depth': 'int',
-            'encrypted': 'bool', 'bps': 'int', 'bps_rd': 'int',
-            'bps_wr': 'int', 'iops': 'int', 'iops_rd': 'int',
-            'iops_wr': 'int'} }
+            'encrypted': 'bool', 'encryption_key_missing': 'bool',
+            'bps': 'int', 'bps_rd': 'int', 'bps_wr': 'int',
+            'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int'} }
 
 ##
 # @BlockDeviceIoStatus:
@@ -625,7 +742,6 @@
 # Returns information about the current VNC server
 #
 # Returns: @VncInfo
-#          If VNC support is not compiled in, FeatureDisabled
 #
 # Since: 0.14.0
 ##
@@ -1009,9 +1125,6 @@
 #                       virtual address (defaults to CPU 0)
 #
 # Returns: Nothing on success
-#          If @cpu is not a valid VCPU, InvalidParameterValue
-#          If @filename cannot be opened, OpenFileFailed
-#          If an I/O error occurs while writing the file, IOError
 #
 # Since: 0.14.0
 #
@@ -1032,8 +1145,6 @@
 # @filename: the file to save the memory to as binary data
 #
 # Returns: Nothing on success
-#          If @filename cannot be opened, OpenFileFailed
-#          If an I/O error occurs while writing the file, IOError
 #
 # Since: 0.14.0
 #
@@ -1075,7 +1186,6 @@
 # Injects an Non-Maskable Interrupt into all guest's VCPUs.
 #
 # Returns:  If successful, nothing
-#           If the Virtual Machine doesn't support NMI injection, Unsupported
 #
 # Since:  0.14.0
 #
@@ -1126,7 +1236,6 @@
 # Returns: nothing on success
 #          If @device is not a valid block device, DeviceNotFound
 #          If @device is not encrypted, DeviceNotEncrypted
-#          If @password is not valid for this device, InvalidPassword
 #
 # Notes:  Not all block formats support encryption and some that do are not
 #         able to validate that a password is correct.  Disk corruption may
@@ -1167,11 +1276,6 @@
 #
 # Returns: nothing on success
 #          If @device is not a valid block device, DeviceNotFound
-#          If @size is negative, InvalidParameterValue
-#          If the block device has no medium inserted, DeviceHasNoMedium
-#          If the block device does not support resize, Unsupported
-#          If the block device is read-only, DeviceIsReadOnly
-#          If a long-running operation is using the device, DeviceInUse
 #
 # Since: 0.14.0
 ##
@@ -1233,10 +1337,6 @@
 #
 # Returns: nothing on success
 #          If @device is not a valid block device, DeviceNotFound
-#          If @device is busy, DeviceInUse will be returned
-#          If @snapshot-file can't be created, OpenFileFailed
-#          If @snapshot-file can't be opened, OpenFileFailed
-#          If @format is invalid, InvalidBlockFormat
 #
 # Note: The transaction aborts on the first failure.  Therefore, there will
 # be only one device or snapshot file returned in an error condition, and
@@ -1265,8 +1365,6 @@
 #
 # Returns: nothing on success
 #          If @device is not a valid block device, DeviceNotFound
-#          If @snapshot-file can't be opened, OpenFileFailed
-#          If @format is invalid, InvalidBlockFormat
 #
 # Since 0.14.0
 ##
@@ -1344,6 +1442,33 @@
 { 'command': 'migrate_set_speed', 'data': {'value': 'int'} }
 
 ##
+# @migrate-set-cache-size
+#
+# Set XBZRLE cache size
+#
+# @value: cache size in bytes
+#
+# The size will be rounded down to the nearest power of 2.
+# The cache size can be modified before and during ongoing migration
+#
+# Returns: nothing on success
+#
+# Since: 1.2
+##
+{ 'command': 'migrate-set-cache-size', 'data': {'value': 'int'} }
+
+##
+# @query-migrate-cache-size
+#
+# query XBZRLE cache size
+#
+# Returns: XBZRLE cache size in bytes
+#
+# Since: 1.2
+##
+{ 'command': 'query-migrate-cache-size', 'returns': 'int' }
+
+##
 # @ObjectPropertyInfo:
 #
 # @name: the name of the property
@@ -1363,9 +1488,7 @@
 #        4) A link type in the form 'link<subtype>' where subtype is a qdev
 #           device type name.  Link properties form the device model graph.
 #
-# Since: 1.1
-#
-# Notes: This type is experimental.  Its syntax may change in future releases.
+# Since: 1.2
 ##
 { 'type': 'ObjectPropertyInfo',
   'data': { 'name': 'str', 'type': 'str' } }
@@ -1382,10 +1505,7 @@
 # Returns: a list of @ObjectPropertyInfo that describe the properties of the
 #          object.
 #
-# Since: 1.1
-#
-# Notes: This command is experimental.  It's syntax may change in future
-#        releases.
+# Since: 1.2
 ##
 { 'command': 'qom-list',
   'data': { 'path': 'str' },
@@ -1421,9 +1541,7 @@
 #          returns as #str pathnames.  All integer property types (u8, u16, etc)
 #          are returned as #int.
 #
-# Since: 1.1
-#
-# Notes: This command is experimental and may change syntax in future releases.
+# Since: 1.2
 ##
 { 'command': 'qom-get',
   'data': { 'path': 'str', 'property': 'str' },
@@ -1442,9 +1560,7 @@
 # @value: a value who's type is appropriate for the property type.  See @qom-get
 #         for a description of type mapping.
 #
-# Since: 1.1
-#
-# Notes: This command is experimental and may change syntax in future releases.
+# Since: 1.2
 ##
 { 'command': 'qom-set',
   'data': { 'path': 'str', 'property': 'str', 'value': 'visitor' },
@@ -1468,11 +1584,6 @@
 #
 # Returns: Nothing on success
 #          If Spice is not enabled, DeviceNotFound
-#          If @protocol does not support connected, InvalidParameter
-#          If @protocol is invalid, InvalidParameter
-#          If any other error occurs, SetPasswdFailed
-#
-# Notes: If VNC is not enabled, SetPasswdFailed is returned.
 #
 # Since: 0.14.0
 ##
@@ -1494,8 +1605,6 @@
 #
 # Returns: Nothing on success
 #          If @protocol is `spice' and Spice is not active, DeviceNotFound
-#          If an error occurs setting password expiration, SetPasswdFailed
-#          If @protocol is not `spice' or 'vnc', InvalidParameter
 #
 # Since: 0.14.0
 #
@@ -1518,8 +1627,6 @@
 #
 # Returns:  Nothing on success
 #           If @device is not a valid block device, DeviceNotFound
-#           If @device is not removable and @force is false, DeviceNotRemovable
-#           If @force is false and @device is locked, DeviceLocked
 #
 # Notes:    Ejecting a device will no media results in success
 #
@@ -1562,7 +1669,6 @@
 #
 # Returns: Nothing on success.
 #          If @device is not a valid block device, DeviceNotFound
-#          If @format is not a valid block format, InvalidBlockFormat
 #          If the new block device is encrypted, DeviceEncrypted.  Note that
 #          if this error is returned, the device has been opened successfully
 #          and an additional call to @block_passwd is required to set the
@@ -1598,7 +1704,6 @@
 #
 # Returns: Nothing on success
 #          If @device is not a valid block device, DeviceNotFound
-#          If the argument combination is invalid, InvalidParameterCombination
 #
 # Since: 1.1
 ##
@@ -1632,11 +1737,7 @@
 # @speed:  #optional the maximum speed, in bytes per second
 #
 # Returns: Nothing on success
-#          If streaming is already active on this device, DeviceInUse
 #          If @device does not exist, DeviceNotFound
-#          If image streaming is not supported by this device, NotSupported
-#          If @base does not exist, BaseNotFound
-#          If @speed is invalid, InvalidParameter
 #
 # Since: 1.1
 ##
@@ -1658,9 +1759,7 @@
 #          Defaults to 0.
 #
 # Returns: Nothing on success
-#          If the job type does not support throttling, NotSupported
-#          If the speed value is invalid, InvalidParameter
-#          If streaming is not active on this device, DeviceNotActive
+#          If no background operation is active on this device, DeviceNotActive
 #
 # Since: 1.1
 ##
@@ -1670,9 +1769,9 @@
 ##
 # @block-job-cancel:
 #
-# Stop an active block streaming operation.
+# Stop an active background block operation.
 #
-# This command returns immediately after marking the active block streaming
+# This command returns immediately after marking the active background block
 # operation for cancellation.  It is an error to call this command if no
 # operation is in progress.
 #
@@ -1680,17 +1779,15 @@
 # BLOCK_JOB_CANCELLED event.  Before that happens the job is still visible when
 # enumerated using query-block-jobs.
 #
-# The image file retains its backing file unless the streaming operation happens
-# to complete just as it is being cancelled.
-#
-# A new block streaming operation can be started at a later time to finish
-# copying all data from the backing file.
+# For streaming, the image file retains its backing file unless the streaming
+# operation happens to complete just as it is being cancelled.  A new streaming
+# operation can be started at a later time to finish copying all data from the
+# backing file.
 #
 # @device: the device name
 #
 # Returns: Nothing on success
-#          If streaming is not active on this device, DeviceNotActive
-#          If cancellation already in progress, DeviceInUse
+#          If no background operation is active on this device, DeviceNotActive
 #
 # Since: 1.1
 ##
@@ -1722,14 +1819,40 @@
 # Returns: a list of @ObjectTypeInfo or an empty list if no results are found
 #
 # Since: 1.1
-#
-# Notes: This command is experimental and may change syntax in future releases.
 ##
 { 'command': 'qom-list-types',
   'data': { '*implements': 'str', '*abstract': 'bool' },
   'returns': [ 'ObjectTypeInfo' ] }
 
 ##
+# @DevicePropertyInfo:
+#
+# Information about device properties.
+#
+# @name: the name of the property
+# @type: the typename of the property
+#
+# Since: 1.2
+##
+{ 'type': 'DevicePropertyInfo',
+  'data': { 'name': 'str', 'type': 'str' } }
+
+##
+# @device-list-properties:
+#
+# List properties associated with a device.
+#
+# @typename: the type name of a device
+#
+# Returns: a list of DevicePropertyInfo describing a devices properties
+#
+# Since: 1.2
+##
+{ 'command': 'device-list-properties',
+  'data': { 'typename': 'str'},
+  'returns': [ 'DevicePropertyInfo' ] }
+
+##
 # @migrate
 #
 # Migrates the current running guest to another Virtual Machine.
@@ -1760,8 +1883,6 @@
 # format.
 #
 # Returns: Nothing on success
-#          If @filename cannot be opened, OpenFileFailed
-#          If an I/O error occurs while writing the file, IOError
 #
 # Since: 1.1
 ##
@@ -1776,7 +1897,6 @@
 #
 # Returns: Nothing on success
 #          If @id is not a valid device, DeviceNotFound
-#          If the device does not support unplug, BusNoHotplug
 #
 # Notes: When this command completes, the device may not be removed from the
 #        guest.  Hot removal is an operation that requires guest cooperation.
@@ -1817,14 +1937,6 @@
 # want to dump all guest's memory, please specify the start @begin and @length
 #
 # Returns: nothing on success
-#          If @begin contains an invalid address, InvalidParameter
-#          If only one of @begin and @length is specified, MissingParameter
-#          If @protocol stats with "fd:", and the fd cannot be found, FdNotFound
-#          If @protocol starts with "file:", and the file cannot be
-#             opened, OpenFileFailed
-#          If @protocol does not start with "fd:" or "file:", InvalidParameter
-#          If an I/O error occurs while writing the file, IOError
-#          If the target does not support this command, Unsupported
 #
 # Since: 1.2
 ##
@@ -1851,10 +1963,6 @@
 #
 # Returns: Nothing on success
 #          If @type is not a valid network backend, DeviceNotFound
-#          If @id is not a valid identifier, InvalidParameterValue
-#          if @id already exists, DuplicateId
-#          If @props contains an invalid parameter for this backend,
-#            InvalidParameter
 ##
 { 'command': 'netdev_add',
   'data': {'type': 'str', 'id': 'str', '*props': '**'},
@@ -2174,8 +2282,6 @@
 # @fdname: file descriptor name
 #
 # Returns: Nothing on success
-#          If file descriptor was not received, FdNotSupplied
-#          If @fdname is not valid, InvalidParameterType
 #
 # Since: 0.14.0
 #
@@ -2195,8 +2301,58 @@
 # @fdname: file descriptor name
 #
 # Returns: Nothing on success
-#          If @fdname is not found, FdNotFound
 #
 # Since: 0.14.0
 ##
 { 'command': 'closefd', 'data': {'fdname': 'str'} }
+
+##
+# @MachineInfo:
+#
+# Information describing a machine.
+#
+# @name: the name of the machine
+#
+# @alias: #optional an alias for the machine name
+#
+# @default: #optional whether the machine is default
+#
+# Since: 1.2.0
+##
+{ 'type': 'MachineInfo',
+  'data': { 'name': 'str', '*alias': 'str',
+            '*is-default': 'bool' } }
+
+##
+# @query-machines:
+#
+# Return a list of supported machines
+#
+# Returns: a list of MachineInfo
+#
+# Since: 1.2.0
+##
+{ 'command': 'query-machines', 'returns': ['MachineInfo'] }
+
+##
+# @CpuDefinitionInfo:
+#
+# Virtual CPU definition.
+#
+# @name: the name of the CPU definition
+#
+# Since: 1.2.0
+##
+{ 'type': 'CpuDefinitionInfo',
+  'data': { 'name': 'str' } }
+
+##
+# @query-cpu-definitions:
+#
+# Return a list of supported virtual CPU definitions
+#
+# Returns: a list of CpuDefInfo
+#
+# Since: 1.2.0
+##
+{ 'command': 'query-cpu-definitions', 'returns': ['CpuDefinitionInfo'] }
diff --git a/qapi/qmp-core.h b/qapi/qmp-core.h
index b0f64ba1ee..00446cff9b 100644
--- a/qapi/qmp-core.h
+++ b/qapi/qmp-core.h
@@ -49,6 +49,7 @@ void qmp_disable_command(const char *name);
 void qmp_enable_command(const char *name);
 bool qmp_command_is_enabled(const char *name);
 char **qmp_get_command_list(void);
+QObject *qmp_build_error_object(Error *errp);
 
 #endif
 
diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
index 122c1a29ba..4085994686 100644
--- a/qapi/qmp-dispatch.c
+++ b/qapi/qmp-dispatch.c
@@ -14,8 +14,8 @@
 #include "qemu-objects.h"
 #include "qapi/qmp-core.h"
 #include "json-parser.h"
+#include "qapi-types.h"
 #include "error.h"
-#include "error_int.h"
 #include "qerror.h"
 
 static QDict *qmp_dispatch_check_obj(const QObject *request, Error **errp)
@@ -109,6 +109,13 @@ static QObject *do_qmp_dispatch(QObject *request, Error **errp)
     return ret;
 }
 
+QObject *qmp_build_error_object(Error *errp)
+{
+    return qobject_from_jsonf("{ 'class': %s, 'desc': %s }",
+                              ErrorClass_lookup[error_get_class(errp)],
+                              error_get_pretty(errp));
+}
+
 QObject *qmp_dispatch(QObject *request)
 {
     Error *err = NULL;
@@ -119,7 +126,7 @@ QObject *qmp_dispatch(QObject *request)
 
     rsp = qdict_new();
     if (err) {
-        qdict_put_obj(rsp, "error", error_get_qobject(err));
+        qdict_put_obj(rsp, "error", qmp_build_error_object(err));
         error_free(err);
     } else if (ret) {
         qdict_put_obj(rsp, "return", ret);
diff --git a/qemu-char.c b/qemu-char.c
index c2aaaeeb8f..382c71ebcd 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -2446,7 +2446,7 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
         if (is_listen) {
             fd = inet_listen_opts(opts, 0, NULL);
         } else {
-            fd = inet_connect_opts(opts, NULL);
+            fd = inet_connect_opts(opts, NULL, NULL);
         }
     }
     if (fd < 0) {
diff --git a/qemu-common.h b/qemu-common.h
index f16079f432..095e28d89a 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -1,3 +1,4 @@
+
 /* Common header file that is included by all of qemu.  */
 #ifndef QEMU_COMMON_H
 #define QEMU_COMMON_H
@@ -376,6 +377,7 @@ bool buffer_is_zero(const void *buf, size_t len);
 void qemu_progress_init(int enabled, float min_skip);
 void qemu_progress_end(void);
 void qemu_progress_print(float delta, int max);
+const char *qemu_get_vm_name(void);
 
 #define QEMU_FILE_TYPE_BIOS   0
 #define QEMU_FILE_TYPE_KEYMAP 1
@@ -428,6 +430,26 @@ static inline uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c)
 /* Round number up to multiple */
 #define QEMU_ALIGN_UP(n, m) QEMU_ALIGN_DOWN((n) + (m) - 1, (m))
 
+static inline bool is_power_of_2(uint64_t value)
+{
+    if (!value) {
+        return 0;
+    }
+
+    return !(value & (value - 1));
+}
+
+/* round down to the nearest power of 2*/
+int64_t pow2floor(int64_t value);
+
 #include "module.h"
 
+/*
+ * Implementation of ULEB128 (http://en.wikipedia.org/wiki/LEB128)
+ * Input is limited to 14-bit numbers
+ */
+
+int uleb128_encode_small(uint8_t *out, uint32_t n);
+int uleb128_decode_small(const uint8_t *in, uint32_t *n);
+
 #endif
diff --git a/qemu-doc.texi b/qemu-doc.texi
index f32e9e2fb9..35cabbcb9e 100644
--- a/qemu-doc.texi
+++ b/qemu-doc.texi
@@ -734,6 +734,11 @@ Various session related parameters can be set via special options, either
 in a configuration file provided via '-readconfig' or directly on the
 command line.
 
+If the initiator-name is not specified qemu will use a default name
+of 'iqn.2008-11.org.linux-kvm[:<name>'] where <name> is the name of the
+virtual machine.
+
+
 @example
 Setting a specific initiator name to use when logging in to the target
 -iscsi initiator-name=iqn.qemu.test:my-initiator
diff --git a/qemu-ga.c b/qemu-ga.c
index f1a39ec3a6..8f87621ae4 100644
--- a/qemu-ga.c
+++ b/qemu-ga.c
@@ -28,7 +28,6 @@
 #include "module.h"
 #include "signal.h"
 #include "qerror.h"
-#include "error_int.h"
 #include "qapi/qmp-core.h"
 #include "qga/channel.h"
 #ifdef _WIN32
@@ -515,7 +514,7 @@ static void process_event(JSONMessageParser *parser, QList *tokens)
         } else {
             g_warning("failed to parse event: %s", error_get_pretty(err));
         }
-        qdict_put_obj(qdict, "error", error_get_qobject(err));
+        qdict_put_obj(qdict, "error", qmp_build_error_object(err));
         error_free(err);
     } else {
         qdict = qobject_to_qdict(obj);
@@ -532,7 +531,7 @@ static void process_event(JSONMessageParser *parser, QList *tokens)
             qdict = qdict_new();
             g_warning("unrecognized payload format");
             error_set(&err, QERR_UNSUPPORTED);
-            qdict_put_obj(qdict, "error", error_get_qobject(err));
+            qdict_put_obj(qdict, "error", qmp_build_error_object(err));
             error_free(err);
         }
         ret = send_response(s, QOBJECT(qdict));
diff --git a/qemu-img.c b/qemu-img.c
index b866f8081e..b41e670a61 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -379,7 +379,7 @@ static int img_check(int argc, char **argv)
     BlockDriverState *bs;
     BdrvCheckResult result;
     int fix = 0;
-    int flags = BDRV_O_FLAGS;
+    int flags = BDRV_O_FLAGS | BDRV_O_CHECK;
 
     fmt = NULL;
     for(;;) {
@@ -1567,14 +1567,19 @@ static int img_resize(int argc, char **argv)
     const char *filename, *fmt, *size;
     int64_t n, total_size;
     BlockDriverState *bs = NULL;
-    QEMUOptionParameter *param;
-    QEMUOptionParameter resize_options[] = {
-        {
-            .name = BLOCK_OPT_SIZE,
-            .type = OPT_SIZE,
-            .help = "Virtual disk size"
+    QemuOpts *param;
+    static QemuOptsList resize_options = {
+        .name = "resize_options",
+        .head = QTAILQ_HEAD_INITIALIZER(resize_options.head),
+        .desc = {
+            {
+                .name = BLOCK_OPT_SIZE,
+                .type = QEMU_OPT_SIZE,
+                .help = "Virtual disk size"
+            }, {
+                /* end of list */
+            }
         },
-        { NULL }
     };
 
     /* Remove size from argv manually so that negative numbers are not treated
@@ -1624,14 +1629,15 @@ static int img_resize(int argc, char **argv)
     }
 
     /* Parse size */
-    param = parse_option_parameters("", resize_options, NULL);
-    if (set_option_parameter(param, BLOCK_OPT_SIZE, size)) {
+    param = qemu_opts_create(&resize_options, NULL, 0, NULL);
+    if (qemu_opt_set(param, BLOCK_OPT_SIZE, size)) {
         /* Error message already printed when size parsing fails */
         ret = -1;
+        qemu_opts_del(param);
         goto out;
     }
-    n = get_option_parameter(param, BLOCK_OPT_SIZE)->value.n;
-    free_option_parameters(param);
+    n = qemu_opt_get_size(param, BLOCK_OPT_SIZE, 0);
+    qemu_opts_del(param);
 
     bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS | BDRV_O_RDWR);
     if (!bs) {
diff --git a/qemu-io.c b/qemu-io.c
index 8f3b94b838..d0f4fb70c7 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -1652,6 +1652,17 @@ static const cmdinfo_t map_cmd = {
        .oneline        = "prints the allocated areas of a file",
 };
 
+static int abort_f(int argc, char **argv)
+{
+    abort();
+}
+
+static const cmdinfo_t abort_cmd = {
+       .name           = "abort",
+       .cfunc          = abort_f,
+       .flags          = CMD_NOFILE_OK,
+       .oneline        = "simulate a program crash using abort(3)",
+};
 
 static int close_f(int argc, char **argv)
 {
@@ -1905,6 +1916,7 @@ int main(int argc, char **argv)
     add_command(&discard_cmd);
     add_command(&alloc_cmd);
     add_command(&map_cmd);
+    add_command(&abort_cmd);
 
     add_args_command(init_args_command);
     add_check_command(init_check_command);
diff --git a/qemu-options.hx b/qemu-options.hx
index 5e7d0dc035..47cb5bd311 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1897,6 +1897,11 @@ images for the guest storage. Both disk and cdrom images are supported.
 Syntax for specifying iSCSI LUNs is
 ``iscsi://<target-ip>[:<port>]/<target-iqn>/<lun>''
 
+By default qemu will use the iSCSI initiator-name
+'iqn.2008-11.org.linux-kvm[:<name>]' but this can also be set from the command
+line or a configuration file.
+
+
 Example (without authentication):
 @example
 qemu-system-i386 -iscsi initiator-name=iqn.2001-04.com.example:my-initiator \
@@ -1926,6 +1931,9 @@ DEF("iscsi", HAS_ARG, QEMU_OPTION_iscsi,
     "                iSCSI session parameters\n", QEMU_ARCH_ALL)
 STEXI
 
+iSCSI parameters such as username and password can also be specified via
+a configuration file. See qemu-doc for more information and examples.
+
 @item NBD
 QEMU supports NBD (Network Block Devices) both using TCP protocol as well
 as Unix Domain Sockets.
diff --git a/qemu-sockets.c b/qemu-sockets.c
index beb2bb6f4a..361d890da3 100644
--- a/qemu-sockets.c
+++ b/qemu-sockets.c
@@ -209,7 +209,7 @@ listen:
     return slisten;
 }
 
-int inet_connect_opts(QemuOpts *opts, Error **errp)
+int inet_connect_opts(QemuOpts *opts, bool *in_progress, Error **errp)
 {
     struct addrinfo ai,*res,*e;
     const char *addr;
@@ -224,6 +224,10 @@ int inet_connect_opts(QemuOpts *opts, Error **errp)
     ai.ai_family = PF_UNSPEC;
     ai.ai_socktype = SOCK_STREAM;
 
+    if (in_progress) {
+        *in_progress = false;
+    }
+
     addr = qemu_opt_get(opts, "host");
     port = qemu_opt_get(opts, "port");
     block = qemu_opt_get_bool(opts, "block", 0);
@@ -277,7 +281,9 @@ int inet_connect_opts(QemuOpts *opts, Error **errp)
   #else
         if (!block && (rc == -EINPROGRESS)) {
   #endif
-            error_set(errp, QERR_SOCKET_CONNECT_IN_PROGRESS);
+            if (in_progress) {
+                *in_progress = true;
+            }
         } else if (rc < 0) {
             if (NULL == e->ai_next)
                 fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n", __FUNCTION__,
@@ -487,7 +493,7 @@ int inet_listen(const char *str, char *ostr, int olen,
     return sock;
 }
 
-int inet_connect(const char *str, bool block, Error **errp)
+int inet_connect(const char *str, bool block, bool *in_progress, Error **errp)
 {
     QemuOpts *opts;
     int sock = -1;
@@ -497,7 +503,7 @@ int inet_connect(const char *str, bool block, Error **errp)
         if (block) {
             qemu_opt_set(opts, "block", "on");
         }
-        sock = inet_connect_opts(opts, errp);
+        sock = inet_connect_opts(opts, in_progress, errp);
     } else {
         error_set(errp, QERR_SOCKET_CREATE_FAILED);
     }
diff --git a/qemu-timer.c b/qemu-timer.c
index 062fdf2cb9..5aea94e8e0 100644
--- a/qemu-timer.c
+++ b/qemu-timer.c
@@ -112,14 +112,10 @@ static int64_t qemu_next_alarm_deadline(void)
 
 static void qemu_rearm_alarm_timer(struct qemu_alarm_timer *t)
 {
-    int64_t nearest_delta_ns;
-    if (!rt_clock->active_timers &&
-        !vm_clock->active_timers &&
-        !host_clock->active_timers) {
-        return;
+    int64_t nearest_delta_ns = qemu_next_alarm_deadline();
+    if (nearest_delta_ns < INT64_MAX) {
+        t->rearm(t, nearest_delta_ns);
     }
-    nearest_delta_ns = qemu_next_alarm_deadline();
-    t->rearm(t, nearest_delta_ns);
 }
 
 /* TODO: MIN_TIMER_REARM_NS should be optimized */
diff --git a/qemu-tool.c b/qemu-tool.c
index 318c5fcbca..64b5e88bc7 100644
--- a/qemu-tool.c
+++ b/qemu-tool.c
@@ -30,6 +30,11 @@ struct QEMUBH
     void *opaque;
 };
 
+const char *qemu_get_vm_name(void)
+{
+    return NULL;
+}
+
 Monitor *cur_mon;
 
 int monitor_cur_is_qmp(void)
diff --git a/qemu_socket.h b/qemu_socket.h
index 4689ff340d..30ae6af8b8 100644
--- a/qemu_socket.h
+++ b/qemu_socket.h
@@ -42,8 +42,8 @@ int send_all(int fd, const void *buf, int len1);
 int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp);
 int inet_listen(const char *str, char *ostr, int olen,
                 int socktype, int port_offset, Error **errp);
-int inet_connect_opts(QemuOpts *opts, Error **errp);
-int inet_connect(const char *str, bool block, Error **errp);
+int inet_connect_opts(QemuOpts *opts, bool *in_progress, Error **errp);
+int inet_connect(const char *str, bool block, bool *in_progress, Error **errp);
 int inet_dgram_opts(QemuOpts *opts);
 const char *inet_strfamily(int family);
 
diff --git a/qerror.c b/qerror.c
index 92c4eff179..08185047b4 100644
--- a/qerror.c
+++ b/qerror.c
@@ -23,320 +23,11 @@ static const QType qerror_type = {
 };
 
 /**
- * The 'desc' parameter is a printf-like string, the format of the format
- * string is:
- *
- * %(KEY)
- *
- * Where KEY is a QDict key, which has to be passed to qerror_from_info().
- *
- * Example:
- *
- * "foo error on device: %(device) slot: %(slot_nr)"
- *
- * A single percent sign can be printed if followed by a second one,
- * for example:
- *
- * "running out of foo: %(foo)%%"
- *
- * Please keep the entries in alphabetical order.
- * Use scripts/check-qerror.sh to check.
- */
-static const QErrorStringTable qerror_table[] = {
-    {
-        .error_fmt = QERR_ADD_CLIENT_FAILED,
-        .desc      = "Could not add client",
-    },
-    {
-        .error_fmt = QERR_AMBIGUOUS_PATH,
-        .desc      = "Path '%(path)' does not uniquely identify a %(object)"
-    },
-    {
-        .error_fmt = QERR_BAD_BUS_FOR_DEVICE,
-        .desc      = "Device '%(device)' can't go on a %(bad_bus_type) bus",
-    },
-    {
-        .error_fmt = QERR_BASE_NOT_FOUND,
-        .desc      = "Base '%(base)' not found",
-    },
-    {
-        .error_fmt = QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
-        .desc      = "Block format '%(format)' used by device '%(name)' does not support feature '%(feature)'",
-    },
-    {
-        .error_fmt = QERR_BUS_NO_HOTPLUG,
-        .desc      = "Bus '%(bus)' does not support hotplugging",
-    },
-    {
-        .error_fmt = QERR_BUS_NOT_FOUND,
-        .desc      = "Bus '%(bus)' not found",
-    },
-    {
-        .error_fmt = QERR_COMMAND_DISABLED,
-        .desc      = "The command %(name) has been disabled for this instance",
-    },
-    {
-        .error_fmt = QERR_COMMAND_NOT_FOUND,
-        .desc      = "The command %(name) has not been found",
-    },
-    {
-        .error_fmt = QERR_DEVICE_ENCRYPTED,
-        .desc      = "Device '%(device)' is encrypted",
-    },
-    {
-        .error_fmt = QERR_DEVICE_FEATURE_BLOCKS_MIGRATION,
-        .desc      = "Migration is disabled when using feature '%(feature)' in device '%(device)'",
-    },
-    {
-        .error_fmt = QERR_DEVICE_HAS_NO_MEDIUM,
-        .desc      = "Device '%(device)' has no medium",
-    },
-    {
-        .error_fmt = QERR_DEVICE_INIT_FAILED,
-        .desc      = "Device '%(device)' could not be initialized",
-    },
-    {
-        .error_fmt = QERR_DEVICE_IN_USE,
-        .desc      = "Device '%(device)' is in use",
-    },
-    {
-        .error_fmt = QERR_DEVICE_IS_READ_ONLY,
-        .desc      = "Device '%(device)' is read only",
-    },
-    {
-        .error_fmt = QERR_DEVICE_LOCKED,
-        .desc      = "Device '%(device)' is locked",
-    },
-    {
-        .error_fmt = QERR_DEVICE_MULTIPLE_BUSSES,
-        .desc      = "Device '%(device)' has multiple child busses",
-    },
-    {
-        .error_fmt = QERR_DEVICE_NO_BUS,
-        .desc      = "Device '%(device)' has no child bus",
-    },
-    {
-        .error_fmt = QERR_DEVICE_NO_HOTPLUG,
-        .desc      = "Device '%(device)' does not support hotplugging",
-    },
-    {
-        .error_fmt = QERR_DEVICE_NOT_ACTIVE,
-        .desc      = "Device '%(device)' has not been activated",
-    },
-    {
-        .error_fmt = QERR_DEVICE_NOT_ENCRYPTED,
-        .desc      = "Device '%(device)' is not encrypted",
-    },
-    {
-        .error_fmt = QERR_DEVICE_NOT_FOUND,
-        .desc      = "Device '%(device)' not found",
-    },
-    {
-        .error_fmt = QERR_DEVICE_NOT_REMOVABLE,
-        .desc      = "Device '%(device)' is not removable",
-    },
-    {
-        .error_fmt = QERR_DUPLICATE_ID,
-        .desc      = "Duplicate ID '%(id)' for %(object)",
-    },
-    {
-        .error_fmt = QERR_FD_NOT_FOUND,
-        .desc      = "File descriptor named '%(name)' not found",
-    },
-    {
-        .error_fmt = QERR_FD_NOT_SUPPLIED,
-        .desc      = "No file descriptor supplied via SCM_RIGHTS",
-    },
-    {
-        .error_fmt = QERR_FEATURE_DISABLED,
-        .desc      = "The feature '%(name)' is not enabled",
-    },
-    {
-        .error_fmt = QERR_INVALID_BLOCK_FORMAT,
-        .desc      = "Invalid block format '%(name)'",
-    },
-    {
-        .error_fmt = QERR_INVALID_OPTION_GROUP,
-        .desc      = "There is no option group '%(group)'",
-    },
-    {
-        .error_fmt = QERR_INVALID_PARAMETER,
-        .desc      = "Invalid parameter '%(name)'",
-    },
-    {
-        .error_fmt = QERR_INVALID_PARAMETER_COMBINATION,
-        .desc      = "Invalid parameter combination",
-    },
-    {
-        .error_fmt = QERR_INVALID_PARAMETER_TYPE,
-        .desc      = "Invalid parameter type for '%(name)', expected: %(expected)",
-    },
-    {
-        .error_fmt = QERR_INVALID_PARAMETER_VALUE,
-        .desc      = "Parameter '%(name)' expects %(expected)",
-    },
-    {
-        .error_fmt = QERR_INVALID_PASSWORD,
-        .desc      = "Password incorrect",
-    },
-    {
-        .error_fmt = QERR_IO_ERROR,
-        .desc      = "An IO error has occurred",
-    },
-    {
-        .error_fmt = QERR_JSON_PARSE_ERROR,
-        .desc      = "JSON parse error, %(message)",
-
-    },
-    {
-        .error_fmt = QERR_JSON_PARSING,
-        .desc      = "Invalid JSON syntax",
-    },
-    {
-        .error_fmt = QERR_KVM_MISSING_CAP,
-        .desc      = "Using KVM without %(capability), %(feature) unavailable",
-    },
-    {
-        .error_fmt = QERR_MIGRATION_ACTIVE,
-        .desc      = "There's a migration process in progress",
-    },
-    {
-        .error_fmt = QERR_MIGRATION_NOT_SUPPORTED,
-        .desc      = "State blocked by non-migratable device '%(device)'",
-    },
-    {
-        .error_fmt = QERR_MIGRATION_EXPECTED,
-        .desc      = "An incoming migration is expected before this command can be executed",
-    },
-    {
-        .error_fmt = QERR_MISSING_PARAMETER,
-        .desc      = "Parameter '%(name)' is missing",
-    },
-    {
-        .error_fmt = QERR_NO_BUS_FOR_DEVICE,
-        .desc      = "No '%(bus)' bus found for device '%(device)'",
-    },
-    {
-        .error_fmt = QERR_NOT_SUPPORTED,
-        .desc      = "Not supported",
-    },
-    {
-        .error_fmt = QERR_OPEN_FILE_FAILED,
-        .desc      = "Could not open '%(filename)'",
-    },
-    {
-        .error_fmt = QERR_PERMISSION_DENIED,
-        .desc      = "Insufficient permission to perform this operation",
-    },
-    {
-        .error_fmt = QERR_PROPERTY_NOT_FOUND,
-        .desc      = "Property '%(device).%(property)' not found",
-    },
-    {
-        .error_fmt = QERR_PROPERTY_VALUE_BAD,
-        .desc      = "Property '%(device).%(property)' doesn't take value '%(value)'",
-    },
-    {
-        .error_fmt = QERR_PROPERTY_VALUE_IN_USE,
-        .desc      = "Property '%(device).%(property)' can't take value '%(value)', it's in use",
-    },
-    {
-        .error_fmt = QERR_PROPERTY_VALUE_NOT_FOUND,
-        .desc      = "Property '%(device).%(property)' can't find value '%(value)'",
-    },
-    {
-        .error_fmt = QERR_PROPERTY_VALUE_NOT_POWER_OF_2,
-        .desc      = "Property '%(device).%(property)' doesn't take "
-                     "value '%(value)', it's not a power of 2",
-    },
-    {
-        .error_fmt = QERR_PROPERTY_VALUE_OUT_OF_RANGE,
-        .desc      = "Property '%(device).%(property)' doesn't take "
-                     "value %(value) (minimum: %(min), maximum: %(max))",
-    },
-    {
-        .error_fmt = QERR_QGA_COMMAND_FAILED,
-        .desc      = "Guest agent command failed, error was '%(message)'",
-    },
-    {
-        .error_fmt = QERR_QGA_LOGGING_FAILED,
-        .desc      = "Guest agent failed to log non-optional log statement",
-    },
-    {
-        .error_fmt = QERR_QMP_BAD_INPUT_OBJECT,
-        .desc      = "Expected '%(expected)' in QMP input",
-    },
-    {
-        .error_fmt = QERR_QMP_BAD_INPUT_OBJECT_MEMBER,
-        .desc      = "QMP input object member '%(member)' expects '%(expected)'",
-    },
-    {
-        .error_fmt = QERR_QMP_EXTRA_MEMBER,
-        .desc      = "QMP input object member '%(member)' is unexpected",
-    },
-    {
-        .error_fmt = QERR_RESET_REQUIRED,
-        .desc      = "Resetting the Virtual Machine is required",
-    },
-    {
-        .error_fmt = QERR_SET_PASSWD_FAILED,
-        .desc      = "Could not set password",
-    },
-    {
-        .error_fmt = QERR_TOO_MANY_FILES,
-        .desc      = "Too many open files",
-    },
-    {
-        .error_fmt = QERR_UNDEFINED_ERROR,
-        .desc      = "An undefined error has occurred",
-    },
-    {
-        .error_fmt = QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
-        .desc      = "'%(device)' uses a %(format) feature which is not "
-                     "supported by this qemu version: %(feature)",
-    },
-    {
-        .error_fmt = QERR_UNSUPPORTED,
-        .desc      = "this feature or command is not currently supported",
-    },
-    {
-        .error_fmt = QERR_VIRTFS_FEATURE_BLOCKS_MIGRATION,
-        .desc      = "Migration is disabled when VirtFS export path '%(path)' "
-                     "is mounted in the guest using mount_tag '%(tag)'",
-    },
-    {
-        .error_fmt = QERR_VNC_SERVER_FAILED,
-        .desc      = "Could not start VNC server on %(target)",
-    },
-    {
-        .error_fmt = QERR_SOCKET_CONNECT_IN_PROGRESS,
-        .desc      = "Connection can not be completed immediately",
-    },
-    {
-        .error_fmt = QERR_SOCKET_CONNECT_FAILED,
-        .desc      = "Failed to connect to socket",
-    },
-    {
-        .error_fmt = QERR_SOCKET_LISTEN_FAILED,
-        .desc      = "Failed to set socket to listening mode",
-    },
-    {
-        .error_fmt = QERR_SOCKET_BIND_FAILED,
-        .desc      = "Failed to bind socket",
-    },
-    {
-        .error_fmt = QERR_SOCKET_CREATE_FAILED,
-        .desc      = "Failed to create socket",
-    },
-    {}
-};
-
-/**
  * qerror_new(): Create a new QError
  *
  * Return strong reference.
  */
-QError *qerror_new(void)
+static QError *qerror_new(void)
 {
     QError *qerr;
 
@@ -346,200 +37,31 @@ QError *qerror_new(void)
     return qerr;
 }
 
-static void GCC_FMT_ATTR(2, 3) qerror_abort(const QError *qerr,
-                                            const char *fmt, ...)
-{
-    va_list ap;
-
-    fprintf(stderr, "qerror: bad call in function '%s':\n", qerr->func);
-    fprintf(stderr, "qerror: -> ");
-
-    va_start(ap, fmt);
-    vfprintf(stderr, fmt, ap);
-    va_end(ap);
-
-    fprintf(stderr, "\nqerror: call at %s:%d\n", qerr->file, qerr->linenr);
-    abort();
-}
-
-static void GCC_FMT_ATTR(2, 0) qerror_set_data(QError *qerr,
-                                               const char *fmt, va_list *va)
-{
-    QObject *obj;
-
-    obj = qobject_from_jsonv(fmt, va);
-    if (!obj) {
-        qerror_abort(qerr, "invalid format '%s'", fmt);
-    }
-    if (qobject_type(obj) != QTYPE_QDICT) {
-        qerror_abort(qerr, "error format is not a QDict '%s'", fmt);
-    }
-
-    qerr->error = qobject_to_qdict(obj);
-
-    obj = qdict_get(qerr->error, "class");
-    if (!obj) {
-        qerror_abort(qerr, "missing 'class' key in '%s'", fmt);
-    }
-    if (qobject_type(obj) != QTYPE_QSTRING) {
-        qerror_abort(qerr, "'class' key value should be a QString");
-    }
-    
-    obj = qdict_get(qerr->error, "data");
-    if (!obj) {
-        qerror_abort(qerr, "missing 'data' key in '%s'", fmt);
-    }
-    if (qobject_type(obj) != QTYPE_QDICT) {
-        qerror_abort(qerr, "'data' key value should be a QDICT");
-    }
-}
-
-static void qerror_set_desc(QError *qerr, const char *fmt)
-{
-    int i;
-
-    // FIXME: inefficient loop
-
-    for (i = 0; qerror_table[i].error_fmt; i++) {
-        if (strcmp(qerror_table[i].error_fmt, fmt) == 0) {
-            qerr->entry = &qerror_table[i];
-            return;
-        }
-    }
-
-    qerror_abort(qerr, "error format '%s' not found", fmt);
-}
-
 /**
  * qerror_from_info(): Create a new QError from error information
  *
- * The information consists of:
- *
- * - file   the file name of where the error occurred
- * - linenr the line number of where the error occurred
- * - func   the function name of where the error occurred
- * - fmt    JSON printf-like dictionary, there must exist keys 'class' and
- *          'data'
- * - va     va_list of all arguments specified by fmt
- *
  * Return strong reference.
  */
-QError *qerror_from_info(const char *file, int linenr, const char *func,
-                         const char *fmt, va_list *va)
+static QError *qerror_from_info(ErrorClass err_class, const char *fmt,
+                                va_list *va)
 {
     QError *qerr;
 
     qerr = qerror_new();
     loc_save(&qerr->loc);
-    qerr->linenr = linenr;
-    qerr->file = file;
-    qerr->func = func;
-
-    if (!fmt) {
-        qerror_abort(qerr, "QDict not specified");
-    }
 
-    qerror_set_data(qerr, fmt, va);
-    qerror_set_desc(qerr, fmt);
+    qerr->err_msg = g_strdup_vprintf(fmt, *va);
+    qerr->err_class = err_class;
 
     return qerr;
 }
 
-static void parse_error(const QErrorStringTable *entry, int c)
-{
-    fprintf(stderr, "expected '%c' in '%s'", c, entry->desc);
-    abort();
-}
-
-static const char *append_field(QDict *error, QString *outstr,
-                                const QErrorStringTable *entry,
-                                const char *start)
-{
-    QObject *obj;
-    QDict *qdict;
-    QString *key_qs;
-    const char *end, *key;
-
-    if (*start != '%')
-        parse_error(entry, '%');
-    start++;
-    if (*start != '(')
-        parse_error(entry, '(');
-    start++;
-
-    end = strchr(start, ')');
-    if (!end)
-        parse_error(entry, ')');
-
-    key_qs = qstring_from_substr(start, 0, end - start - 1);
-    key = qstring_get_str(key_qs);
-
-    qdict = qobject_to_qdict(qdict_get(error, "data"));
-    obj = qdict_get(qdict, key);
-    if (!obj) {
-        abort();
-    }
-
-    switch (qobject_type(obj)) {
-        case QTYPE_QSTRING:
-            qstring_append(outstr, qdict_get_str(qdict, key));
-            break;
-        case QTYPE_QINT:
-            qstring_append_int(outstr, qdict_get_int(qdict, key));
-            break;
-        default:
-            abort();
-    }
-
-    QDECREF(key_qs);
-    return ++end;
-}
-
-static QString *qerror_format_desc(QDict *error,
-                                   const QErrorStringTable *entry)
-{
-    QString *qstring;
-    const char *p;
-
-    assert(entry != NULL);
-
-    qstring = qstring_new();
-
-    for (p = entry->desc; *p != '\0';) {
-        if (*p != '%') {
-            qstring_append_chr(qstring, *p++);
-        } else if (*(p + 1) == '%') {
-            qstring_append_chr(qstring, '%');
-            p += 2;
-        } else {
-            p = append_field(error, qstring, entry, p);
-        }
-    }
-
-    return qstring;
-}
-
-QString *qerror_format(const char *fmt, QDict *error)
-{
-    const QErrorStringTable *entry = NULL;
-    int i;
-
-    for (i = 0; qerror_table[i].error_fmt; i++) {
-        if (strcmp(qerror_table[i].error_fmt, fmt) == 0) {
-            entry = &qerror_table[i];
-            break;
-        }
-    }
-
-    return qerror_format_desc(error, entry);
-}
-
 /**
  * qerror_human(): Format QError data into human-readable string.
  */
 QString *qerror_human(const QError *qerror)
 {
-    return qerror_format_desc(qerror->error, qerror->entry);
+    return qstring_from_str(qerror->err_msg);
 }
 
 /**
@@ -549,7 +71,7 @@ QString *qerror_human(const QError *qerror)
  * it uses error_report() for this, so that the output is routed to the right
  * place (ie. stderr or Monitor's device).
  */
-void qerror_print(QError *qerror)
+static void qerror_print(QError *qerror)
 {
     QString *qstring = qerror_human(qerror);
     loc_push_restore(&qerror->loc);
@@ -558,14 +80,13 @@ void qerror_print(QError *qerror)
     QDECREF(qstring);
 }
 
-void qerror_report_internal(const char *file, int linenr, const char *func,
-                            const char *fmt, ...)
+void qerror_report(ErrorClass eclass, const char *fmt, ...)
 {
     va_list va;
     QError *qerror;
 
     va_start(va, fmt);
-    qerror = qerror_from_info(file, linenr, func, fmt, &va);
+    qerror = qerror_from_info(eclass, fmt, &va);
     va_end(va);
 
     if (monitor_cur_is_qmp()) {
@@ -579,27 +100,18 @@ void qerror_report_internal(const char *file, int linenr, const char *func,
 /* Evil... */
 struct Error
 {
-    QDict *obj;
-    const char *fmt;
     char *msg;
+    ErrorClass err_class;
 };
 
 void qerror_report_err(Error *err)
 {
     QError *qerr;
-    int i;
 
     qerr = qerror_new();
     loc_save(&qerr->loc);
-    QINCREF(err->obj);
-    qerr->error = err->obj;
-
-    for (i = 0; qerror_table[i].error_fmt; i++) {
-        if (strcmp(qerror_table[i].error_fmt, err->fmt) == 0) {
-            qerr->entry = &qerror_table[i];
-            break;
-        }
-    }
+    qerr->err_msg = g_strdup(err->msg);
+    qerr->err_class = err->err_class;
 
     if (monitor_cur_is_qmp()) {
         monitor_set_error(cur_mon, qerr);
@@ -620,7 +132,7 @@ void assert_no_error(Error *err)
 /**
  * qobject_to_qerror(): Convert a QObject into a QError
  */
-QError *qobject_to_qerror(const QObject *obj)
+static QError *qobject_to_qerror(const QObject *obj)
 {
     if (qobject_type(obj) != QTYPE_QERROR) {
         return NULL;
@@ -639,6 +151,6 @@ static void qerror_destroy_obj(QObject *obj)
     assert(obj != NULL);
     qerr = qobject_to_qerror(obj);
 
-    QDECREF(qerr->error);
+    g_free(qerr->err_msg);
     g_free(qerr);
 }
diff --git a/qerror.h b/qerror.h
index b4c8758f40..d0a76a4f71 100644
--- a/qerror.h
+++ b/qerror.h
@@ -16,36 +16,20 @@
 #include "qstring.h"
 #include "qemu-error.h"
 #include "error.h"
+#include "qapi-types.h"
 #include <stdarg.h>
 
-typedef struct QErrorStringTable {
-    const char *desc;
-    const char *error_fmt;
-} QErrorStringTable;
-
 typedef struct QError {
     QObject_HEAD;
-    QDict *error;
     Location loc;
-    int linenr;
-    const char *file;
-    const char *func;
-    const QErrorStringTable *entry;
+    char *err_msg;
+    ErrorClass err_class;
 } QError;
 
-QError *qerror_new(void);
-QError *qerror_from_info(const char *file, int linenr, const char *func,
-                         const char *fmt, va_list *va) GCC_FMT_ATTR(4, 0);
 QString *qerror_human(const QError *qerror);
-void qerror_print(QError *qerror);
-void qerror_report_internal(const char *file, int linenr, const char *func,
-                            const char *fmt, ...) GCC_FMT_ATTR(4, 5);
+void qerror_report(ErrorClass err_class, const char *fmt, ...) GCC_FMT_ATTR(2, 3);
 void qerror_report_err(Error *err);
 void assert_no_error(Error *err);
-QString *qerror_format(const char *fmt, QDict *error);
-#define qerror_report(fmt, ...) \
-    qerror_report_internal(__FILE__, __LINE__, __func__, fmt, ## __VA_ARGS__)
-QError *qobject_to_qerror(const QObject *obj);
 
 /*
  * QError class list
@@ -53,217 +37,213 @@ QError *qobject_to_qerror(const QObject *obj);
  * Use scripts/check-qerror.sh to check.
  */
 #define QERR_ADD_CLIENT_FAILED \
-    "{ 'class': 'AddClientFailed', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "Could not add client"
 
 #define QERR_AMBIGUOUS_PATH \
-    "{ 'class': 'AmbiguousPath', 'data': { 'path': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Path '%s' does not uniquely identify an object"
 
 #define QERR_BAD_BUS_FOR_DEVICE \
-    "{ 'class': 'BadBusForDevice', 'data': { 'device': %s, 'bad_bus_type': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Device '%s' can't go on a %s bus"
 
 #define QERR_BASE_NOT_FOUND \
-    "{ 'class': 'BaseNotFound', 'data': { 'base': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Base '%s' not found"
 
 #define QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED \
-    "{ 'class': 'BlockFormatFeatureNotSupported', 'data': { 'format': %s, 'name': %s, 'feature': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Block format '%s' used by device '%s' does not support feature '%s'"
 
 #define QERR_BUFFER_OVERRUN \
-    "{ 'class': 'BufferOverrun', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "An internal buffer overran"
 
 #define QERR_BUS_NO_HOTPLUG \
-    "{ 'class': 'BusNoHotplug', 'data': { 'bus': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Bus '%s' does not support hotplugging"
 
 #define QERR_BUS_NOT_FOUND \
-    "{ 'class': 'BusNotFound', 'data': { 'bus': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Bus '%s' not found"
 
 #define QERR_COMMAND_DISABLED \
-    "{ 'class': 'CommandDisabled', 'data': { 'name': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "The command %s has been disabled for this instance"
 
 #define QERR_COMMAND_NOT_FOUND \
-    "{ 'class': 'CommandNotFound', 'data': { 'name': %s } }"
+    ERROR_CLASS_COMMAND_NOT_FOUND, "The command %s has not been found"
 
 #define QERR_DEVICE_ENCRYPTED \
-    "{ 'class': 'DeviceEncrypted', 'data': { 'device': %s, 'filename': %s } }"
+    ERROR_CLASS_DEVICE_ENCRYPTED, "'%s' (%s) is encrypted"
 
 #define QERR_DEVICE_FEATURE_BLOCKS_MIGRATION \
-    "{ 'class': 'DeviceFeatureBlocksMigration', 'data': { 'device': %s, 'feature': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Migration is disabled when using feature '%s' in device '%s'"
 
 #define QERR_DEVICE_HAS_NO_MEDIUM \
-    "{ 'class': 'DeviceHasNoMedium', 'data': { 'device': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Device '%s' has no medium"
 
 #define QERR_DEVICE_INIT_FAILED \
-    "{ 'class': 'DeviceInitFailed', 'data': { 'device': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Device '%s' could not be initialized"
 
 #define QERR_DEVICE_IN_USE \
-    "{ 'class': 'DeviceInUse', 'data': { 'device': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Device '%s' is in use"
 
 #define QERR_DEVICE_IS_READ_ONLY \
-    "{ 'class': 'DeviceIsReadOnly', 'data': { 'device': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Device '%s' is read only"
 
 #define QERR_DEVICE_LOCKED \
-    "{ 'class': 'DeviceLocked', 'data': { 'device': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Device '%s' is locked"
 
 #define QERR_DEVICE_MULTIPLE_BUSSES \
-    "{ 'class': 'DeviceMultipleBusses', 'data': { 'device': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Device '%s' has multiple child busses"
 
 #define QERR_DEVICE_NO_BUS \
-    "{ 'class': 'DeviceNoBus', 'data': { 'device': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Device '%s' has no child bus"
 
 #define QERR_DEVICE_NO_HOTPLUG \
-    "{ 'class': 'DeviceNoHotplug', 'data': { 'device': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Device '%s' does not support hotplugging"
 
 #define QERR_DEVICE_NOT_ACTIVE \
-    "{ 'class': 'DeviceNotActive', 'data': { 'device': %s } }"
+    ERROR_CLASS_DEVICE_NOT_ACTIVE, "Device '%s' has not been activated"
 
 #define QERR_DEVICE_NOT_ENCRYPTED \
-    "{ 'class': 'DeviceNotEncrypted', 'data': { 'device': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Device '%s' is not encrypted"
 
 #define QERR_DEVICE_NOT_FOUND \
-    "{ 'class': 'DeviceNotFound', 'data': { 'device': %s } }"
+    ERROR_CLASS_DEVICE_NOT_FOUND, "Device '%s' not found"
 
 #define QERR_DEVICE_NOT_REMOVABLE \
-    "{ 'class': 'DeviceNotRemovable', 'data': { 'device': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Device '%s' is not removable"
 
 #define QERR_DUPLICATE_ID \
-    "{ 'class': 'DuplicateId', 'data': { 'id': %s, 'object': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Duplicate ID '%s' for %s"
 
 #define QERR_FD_NOT_FOUND \
-    "{ 'class': 'FdNotFound', 'data': { 'name': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "File descriptor named '%s' not found"
 
 #define QERR_FD_NOT_SUPPLIED \
-    "{ 'class': 'FdNotSupplied', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "No file descriptor supplied via SCM_RIGHTS"
 
 #define QERR_FEATURE_DISABLED \
-    "{ 'class': 'FeatureDisabled', 'data': { 'name': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "The feature '%s' is not enabled"
 
 #define QERR_INVALID_BLOCK_FORMAT \
-    "{ 'class': 'InvalidBlockFormat', 'data': { 'name': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Invalid block format '%s'"
 
 #define QERR_INVALID_OPTION_GROUP \
-    "{ 'class': 'InvalidOptionGroup', 'data': { 'group': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "There is no option group '%s'"
 
 #define QERR_INVALID_PARAMETER \
-    "{ 'class': 'InvalidParameter', 'data': { 'name': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Invalid parameter '%s'"
 
 #define QERR_INVALID_PARAMETER_COMBINATION \
-    "{ 'class': 'InvalidParameterCombination', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "Invalid parameter combination"
 
 #define QERR_INVALID_PARAMETER_TYPE \
-    "{ 'class': 'InvalidParameterType', 'data': { 'name': %s,'expected': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Invalid parameter type for '%s', expected: %s"
 
 #define QERR_INVALID_PARAMETER_VALUE \
-    "{ 'class': 'InvalidParameterValue', 'data': { 'name': %s, 'expected': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Parameter '%s' expects %s"
 
 #define QERR_INVALID_PASSWORD \
-    "{ 'class': 'InvalidPassword', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "Password incorrect"
 
 #define QERR_IO_ERROR \
-    "{ 'class': 'IOError', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "An IO error has occurred"
 
 #define QERR_JSON_PARSE_ERROR \
-    "{ 'class': 'JSONParseError', 'data': { 'message': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "JSON parse error, %s"
 
 #define QERR_JSON_PARSING \
-    "{ 'class': 'JSONParsing', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "Invalid JSON syntax"
 
 #define QERR_KVM_MISSING_CAP \
-    "{ 'class': 'KVMMissingCap', 'data': { 'capability': %s, 'feature': %s } }"
+    ERROR_CLASS_K_V_M_MISSING_CAP, "Using KVM without %s, %s unavailable"
 
 #define QERR_MIGRATION_ACTIVE \
-    "{ 'class': 'MigrationActive', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "There's a migration process in progress"
 
 #define QERR_MIGRATION_NOT_SUPPORTED \
-    "{ 'class': 'MigrationNotSupported', 'data': {'device': %s} }"
+    ERROR_CLASS_GENERIC_ERROR, "State blocked by non-migratable device '%s'"
 
 #define QERR_MIGRATION_EXPECTED \
-    "{ 'class': 'MigrationExpected', 'data': {} }"
+    ERROR_CLASS_MIGRATION_EXPECTED, "An incoming migration is expected before this command can be executed"
 
 #define QERR_MISSING_PARAMETER \
-    "{ 'class': 'MissingParameter', 'data': { 'name': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Parameter '%s' is missing"
 
 #define QERR_NO_BUS_FOR_DEVICE \
-    "{ 'class': 'NoBusForDevice', 'data': { 'device': %s, 'bus': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "No '%s' bus found for device '%s'"
 
 #define QERR_NOT_SUPPORTED \
-    "{ 'class': 'NotSupported', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "Not supported"
 
 #define QERR_OPEN_FILE_FAILED \
-    "{ 'class': 'OpenFileFailed', 'data': { 'filename': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Could not open '%s'"
 
 #define QERR_PERMISSION_DENIED \
-    "{ 'class': 'PermissionDenied', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "Insufficient permission to perform this operation"
 
 #define QERR_PROPERTY_NOT_FOUND \
-    "{ 'class': 'PropertyNotFound', 'data': { 'device': %s, 'property': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Property '%s.%s' not found"
 
 #define QERR_PROPERTY_VALUE_BAD \
-    "{ 'class': 'PropertyValueBad', 'data': { 'device': %s, 'property': %s, 'value': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Property '%s.%s' doesn't take value '%s'"
 
 #define QERR_PROPERTY_VALUE_IN_USE \
-    "{ 'class': 'PropertyValueInUse', 'data': { 'device': %s, 'property': %s, 'value': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Property '%s.%s' can't take value '%s', it's in use"
 
 #define QERR_PROPERTY_VALUE_NOT_FOUND \
-    "{ 'class': 'PropertyValueNotFound', 'data': { 'device': %s, 'property': %s, 'value': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Property '%s.%s' can't find value '%s'"
 
 #define QERR_PROPERTY_VALUE_NOT_POWER_OF_2 \
-    "{ 'class': 'PropertyValueNotPowerOf2', 'data': { " \
-    "'device': %s, 'property': %s, 'value': %"PRId64" } }"
+    ERROR_CLASS_GENERIC_ERROR, "Property %s.%s doesn't take value '%" PRId64 "', it's not a power of 2"
 
 #define QERR_PROPERTY_VALUE_OUT_OF_RANGE \
-    "{ 'class': 'PropertyValueOutOfRange', 'data': { 'device': %s, 'property': %s, 'value': %"PRId64", 'min': %"PRId64", 'max': %"PRId64" } }"
+    ERROR_CLASS_GENERIC_ERROR, "Property %s.%s doesn't take value %" PRId64 " (minimum: %" PRId64 ", maximum: %" PRId64 ")"
 
 #define QERR_QGA_COMMAND_FAILED \
-    "{ 'class': 'QgaCommandFailed', 'data': { 'message': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Guest agent command failed, error was '%s'"
 
 #define QERR_QGA_LOGGING_FAILED \
-    "{ 'class': 'QgaLoggingFailed', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "Guest agent failed to log non-optional log statement"
 
 #define QERR_QMP_BAD_INPUT_OBJECT \
-    "{ 'class': 'QMPBadInputObject', 'data': { 'expected': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Expected '%s' in QMP input"
 
 #define QERR_QMP_BAD_INPUT_OBJECT_MEMBER \
-    "{ 'class': 'QMPBadInputObjectMember', 'data': { 'member': %s, 'expected': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "QMP input object member '%s' expects '%s'"
 
 #define QERR_QMP_EXTRA_MEMBER \
-    "{ 'class': 'QMPExtraInputObjectMember', 'data': { 'member': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "QMP input object member '%s' is unexpected"
 
 #define QERR_RESET_REQUIRED \
-    "{ 'class': 'ResetRequired', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "Resetting the Virtual Machine is required"
 
 #define QERR_SET_PASSWD_FAILED \
-    "{ 'class': 'SetPasswdFailed', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "Could not set password"
 
 #define QERR_TOO_MANY_FILES \
-    "{ 'class': 'TooManyFiles', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "Too many open files"
 
 #define QERR_UNDEFINED_ERROR \
-    "{ 'class': 'UndefinedError', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "An undefined error has occurred"
 
 #define QERR_UNKNOWN_BLOCK_FORMAT_FEATURE \
-    "{ 'class': 'UnknownBlockFormatFeature', 'data': { 'device': %s, 'format': %s, 'feature': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "'%s' uses a %s feature which is not supported by this qemu version: %s"
 
 #define QERR_UNSUPPORTED \
-    "{ 'class': 'Unsupported', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "this feature or command is not currently supported"
 
 #define QERR_VIRTFS_FEATURE_BLOCKS_MIGRATION \
-    "{ 'class': 'VirtFSFeatureBlocksMigration', 'data': { 'path': %s, 'tag': %s } }"
+    ERROR_CLASS_GENERIC_ERROR, "Migration is disabled when VirtFS export path '%s' is mounted in the guest using mount_tag '%s'"
 
 #define QERR_VNC_SERVER_FAILED \
-    "{ 'class': 'VNCServerFailed', 'data': { 'target': %s } }"
-
-#define QERR_SOCKET_CONNECT_IN_PROGRESS \
-    "{ 'class': 'SockConnectInprogress', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "Could not start VNC server on %s"
 
 #define QERR_SOCKET_CONNECT_FAILED \
-    "{ 'class': 'SockConnectFailed', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "Failed to connect to socket"
 
 #define QERR_SOCKET_LISTEN_FAILED \
-    "{ 'class': 'SockListenFailed', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "Failed to set socket to listening mode"
 
 #define QERR_SOCKET_BIND_FAILED \
-    "{ 'class': 'SockBindFailed', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "Failed to bind socket"
 
 #define QERR_SOCKET_CREATE_FAILED \
-    "{ 'class': 'SockCreateFailed', 'data': {} }"
+    ERROR_CLASS_GENERIC_ERROR, "Failed to create socket"
 
 #endif /* QERROR_H */
diff --git a/qmp-commands.hx b/qmp-commands.hx
index ac466382c0..527b9f7c24 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -435,8 +435,8 @@ Example:
 -> { "execute": "inject-nmi" }
 <- { "return": {} }
 
-Note: inject-nmi is only supported for x86 guest currently, it will
-      returns "Unsupported" error for non-x86 guest.
+Note: inject-nmi fails when the guest doesn't support injecting.
+      Currently, only x86 guests do.
 
 EQMP
 
@@ -520,6 +520,50 @@ Example:
 <- { "return": {} }
 
 EQMP
+{
+        .name       = "migrate-set-cache-size",
+        .args_type  = "value:o",
+        .mhandler.cmd_new = qmp_marshal_input_migrate_set_cache_size,
+    },
+
+SQMP
+migrate-set-cache-size
+---------------------
+
+Set cache size to be used by XBZRLE migration, the cache size will be rounded
+down to the nearest power of 2
+
+Arguments:
+
+- "value": cache size in bytes (json-int)
+
+Example:
+
+-> { "execute": "migrate-set-cache-size", "arguments": { "value": 536870912 } }
+<- { "return": {} }
+
+EQMP
+    {
+        .name       = "query-migrate-cache-size",
+        .args_type  = "",
+        .mhandler.cmd_new = qmp_marshal_input_query_migrate_cache_size,
+    },
+
+SQMP
+query-migrate-cache-size
+---------------------
+
+Show cache size to be used by XBZRLE migration
+
+returns a json-object with the following information:
+- "size" : json-int
+
+Example:
+
+-> { "execute": "query-migrate-cache-size" }
+<- { "return": 67108864 }
+
+EQMP
 
     {
         .name       = "migrate_set_speed",
@@ -2078,12 +2122,24 @@ The main json-object contains the following:
          - "transferred": amount transferred (json-int)
          - "remaining": amount remaining (json-int)
          - "total": total (json-int)
+         - "total-time": total amount of ms since migration started.  If
+                         migration has ended, it returns the total migration time
+                         (json-int)
+         - "duplicate": number of duplicated pages (json-int)
+         - "normal" : number of normal pages transferred (json-int)
+         - "normal-bytes" : number of normal bytes transferred (json-int)
 - "disk": only present if "status" is "active" and it is a block migration,
   it is a json-object with the following disk information (in bytes):
          - "transferred": amount transferred (json-int)
          - "remaining": amount remaining (json-int)
          - "total": total (json-int)
-
+- "xbzrle-cache": only present if XBZRLE is active.
+  It is a json-object with the following XBZRLE information:
+         - "cache-size": XBZRLE cache size
+         - "bytes": total XBZRLE bytes transferred
+         - "pages": number of XBZRLE compressed pages
+         - "cache-miss": number of cache misses
+         - "overflow": number of XBZRLE overflows
 Examples:
 
 1. Before the first migration
@@ -2094,7 +2150,19 @@ Examples:
 2. Migration is done and has succeeded
 
 -> { "execute": "query-migrate" }
-<- { "return": { "status": "completed" } }
+<- { "return": {
+        "status": "completed",
+        "ram":{
+          "transferred":123,
+          "remaining":123,
+          "total":246,
+          "total-time":12345,
+          "duplicate":123,
+          "normal":123,
+          "normal-bytes":123456
+        }
+     }
+   }
 
 3. Migration is done and has failed
 
@@ -2110,7 +2178,11 @@ Examples:
          "ram":{
             "transferred":123,
             "remaining":123,
-            "total":246
+            "total":246,
+            "total-time":12345,
+            "duplicate":123,
+            "normal":123,
+            "normal-bytes":123456
          }
       }
    }
@@ -2124,7 +2196,11 @@ Examples:
          "ram":{
             "total":1057024,
             "remaining":1053304,
-            "transferred":3720
+            "transferred":3720,
+            "total-time":12345,
+            "duplicate":123,
+            "normal":123,
+            "normal-bytes":123456
          },
          "disk":{
             "total":20971520,
@@ -2134,6 +2210,32 @@ Examples:
       }
    }
 
+6. Migration is being performed and XBZRLE is active:
+
+-> { "execute": "query-migrate" }
+<- {
+      "return":{
+         "status":"active",
+         "capabilities" : [ { "capability": "xbzrle", "state" : true } ],
+         "ram":{
+            "total":1057024,
+            "remaining":1053304,
+            "transferred":3720,
+            "total-time":12345,
+            "duplicate":10,
+            "normal":3333,
+            "normal-bytes":3412992
+         },
+         "xbzrle-cache":{
+            "cache-size":67108864,
+            "bytes":20971520,
+            "pages":2444343,
+            "cache-miss":2244,
+            "overflow":34434
+         }
+      }
+   }
+
 EQMP
 
     {
@@ -2143,6 +2245,55 @@ EQMP
     },
 
 SQMP
+migrate-set-capabilities
+-------
+
+Enable/Disable migration capabilities
+
+- "xbzrle": xbzrle support
+
+Arguments:
+
+Example:
+
+-> { "execute": "migrate-set-capabilities" , "arguments":
+     { "capabilities": [ { "capability": "xbzrle", "state": true } ] } }
+
+EQMP
+
+    {
+        .name       = "migrate-set-capabilities",
+        .args_type  = "capabilities:O",
+        .params     = "capability:s,state:b",
+	.mhandler.cmd_new = qmp_marshal_input_migrate_set_capabilities,
+    },
+SQMP
+query-migrate-capabilities
+-------
+
+Query current migration capabilities
+
+- "capabilities": migration capabilities state
+         - "xbzrle" : XBZRLE state (json-bool)
+
+Arguments:
+
+Example:
+
+-> { "execute": "query-migrate-capabilities" }
+<- { "return": {
+        "capabilities" :  [ { "capability" : "xbzrle", "state" : false } ]
+     }
+   }
+EQMP
+
+    {
+        .name       = "query-migrate-capabilities",
+        .args_type  = "",
+        .mhandler.cmd_new = qmp_marshal_input_query_migrate_capabilities,
+    },
+
+SQMP
 query-balloon
 -------------
 
@@ -2217,3 +2368,22 @@ EQMP
         .args_type  = "implements:s?,abstract:b?",
         .mhandler.cmd_new = qmp_marshal_input_qom_list_types,
     },
+
+    {
+        .name       = "device-list-properties",
+        .args_type  = "typename:s",
+        .mhandler.cmd_new = qmp_marshal_input_device_list_properties,
+    },
+
+    {
+        .name       = "query-machines",
+        .args_type  = "",
+        .mhandler.cmd_new = qmp_marshal_input_query_machines,
+    },
+
+    {
+        .name       = "query-cpu-definitions",
+        .args_type  = "",
+        .mhandler.cmd_new = qmp_marshal_input_query_cpu_definitions,
+    },
+
diff --git a/qmp.c b/qmp.c
index fee9fb2a9d..6c1e4e8978 100644
--- a/qmp.c
+++ b/qmp.c
@@ -417,3 +417,59 @@ ObjectTypeInfoList *qmp_qom_list_types(bool has_implements,
 
     return ret;
 }
+
+DevicePropertyInfoList *qmp_device_list_properties(const char *typename,
+                                                   Error **errp)
+{
+    ObjectClass *klass;
+    Property *prop;
+    DevicePropertyInfoList *prop_list = NULL;
+
+    klass = object_class_by_name(typename);
+    if (klass == NULL) {
+        error_set(errp, QERR_DEVICE_NOT_FOUND, typename);
+        return NULL;
+    }
+
+    klass = object_class_dynamic_cast(klass, TYPE_DEVICE);
+    if (klass == NULL) {
+        error_set(errp, QERR_INVALID_PARAMETER_VALUE,
+                  "name", TYPE_DEVICE);
+        return NULL;
+    }
+
+    do {
+        for (prop = DEVICE_CLASS(klass)->props; prop && prop->name; prop++) {
+            DevicePropertyInfoList *entry;
+            DevicePropertyInfo *info;
+
+            /*
+             * TODO Properties without a parser are just for dirty hacks.
+             * qdev_prop_ptr is the only such PropertyInfo.  It's marked
+             * for removal.  This conditional should be removed along with
+             * it.
+             */
+            if (!prop->info->set) {
+                continue;           /* no way to set it, don't show */
+            }
+
+            info = g_malloc0(sizeof(*info));
+            info->name = g_strdup(prop->name);
+            info->type = g_strdup(prop->info->legacy_name ?: prop->info->name);
+
+            entry = g_malloc0(sizeof(*entry));
+            entry->value = info;
+            entry->next = prop_list;
+            prop_list = entry;
+        }
+        klass = object_class_get_parent(klass);
+    } while (klass != object_class_by_name(TYPE_DEVICE));
+
+    return prop_list;
+}
+
+CpuDefinitionInfoList GCC_WEAK *qmp_query_cpu_definitions(Error **errp)
+{
+    error_set(errp, QERR_NOT_SUPPORTED);
+    return NULL;
+}
diff --git a/qom/object.c b/qom/object.c
index 00bb3b029c..a552be258e 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -31,9 +31,7 @@ typedef struct TypeImpl TypeImpl;
 
 struct InterfaceImpl
 {
-    const char *parent;
-    void (*interface_initfn)(ObjectClass *class, void *data);
-    TypeImpl *type;
+    const char *typename;
 };
 
 struct TypeImpl
@@ -64,14 +62,6 @@ struct TypeImpl
     InterfaceImpl interfaces[MAX_INTERFACES];
 };
 
-typedef struct Interface
-{
-    Object parent;
-    Object *obj;
-} Interface;
-
-#define INTERFACE(obj) OBJECT_CHECK(Interface, obj, TYPE_INTERFACE)
-
 static Type type_interface;
 
 static GHashTable *type_table_get(void)
@@ -98,6 +88,7 @@ static TypeImpl *type_table_lookup(const char *name)
 static TypeImpl *type_register_internal(const TypeInfo *info)
 {
     TypeImpl *ti = g_malloc0(sizeof(*ti));
+    int i;
 
     g_assert(info->name != NULL);
 
@@ -122,15 +113,10 @@ static TypeImpl *type_register_internal(const TypeInfo *info)
 
     ti->abstract = info->abstract;
 
-    if (info->interfaces) {
-        int i;
-
-        for (i = 0; info->interfaces[i].type; i++) {
-            ti->interfaces[i].parent = info->interfaces[i].type;
-            ti->interfaces[i].interface_initfn = info->interfaces[i].interface_initfn;
-            ti->num_interfaces++;
-        }
+    for (i = 0; info->interfaces && info->interfaces[i].type; i++) {
+        ti->interfaces[i].typename = g_strdup(info->interfaces[i].type);
     }
+    ti->num_interfaces = i;
 
     type_table_add(ti);
 
@@ -198,26 +184,48 @@ static size_t type_object_get_size(TypeImpl *ti)
     return 0;
 }
 
-static void type_class_interface_init(TypeImpl *ti, InterfaceImpl *iface)
+static bool type_is_ancestor(TypeImpl *type, TypeImpl *target_type)
 {
-    TypeInfo info = {
-        .instance_size = sizeof(Interface),
-        .parent = iface->parent,
-        .class_size = sizeof(InterfaceClass),
-        .class_init = iface->interface_initfn,
-        .abstract = true,
-    };
-    char *name = g_strdup_printf("<%s::%s>", ti->name, iface->parent);
+    assert(target_type);
+
+    /* Check if typename is a direct ancestor of type */
+    while (type) {
+        if (type == target_type) {
+            return true;
+        }
 
-    info.name = name;
-    iface->type = type_register_internal(&info);
-    g_free(name);
+        type = type_get_parent(type);
+    }
+
+    return false;
+}
+
+static void type_initialize(TypeImpl *ti);
+
+static void type_initialize_interface(TypeImpl *ti, const char *parent)
+{
+    InterfaceClass *new_iface;
+    TypeInfo info = { };
+    TypeImpl *iface_impl;
+
+    info.parent = parent;
+    info.name = g_strdup_printf("%s::%s", ti->name, info.parent);
+    info.abstract = true;
+
+    iface_impl = type_register(&info);
+    type_initialize(iface_impl);
+    g_free((char *)info.name);
+
+    new_iface = (InterfaceClass *)iface_impl->class;
+    new_iface->concrete_class = ti->class;
+
+    ti->class->interfaces = g_slist_append(ti->class->interfaces,
+                                           iface_impl->class);
 }
 
 static void type_initialize(TypeImpl *ti)
 {
     TypeImpl *parent;
-    int i;
 
     if (ti->class) {
         return;
@@ -231,9 +239,33 @@ static void type_initialize(TypeImpl *ti)
     parent = type_get_parent(ti);
     if (parent) {
         type_initialize(parent);
+        GSList *e;
+        int i;
 
         g_assert(parent->class_size <= ti->class_size);
         memcpy(ti->class, parent->class, parent->class_size);
+
+        for (e = parent->class->interfaces; e; e = e->next) {
+            ObjectClass *iface = e->data;
+            type_initialize_interface(ti, object_class_get_name(iface));
+        }
+
+        for (i = 0; i < ti->num_interfaces; i++) {
+            TypeImpl *t = type_get_by_name(ti->interfaces[i].typename);
+            for (e = ti->class->interfaces; e; e = e->next) {
+                TypeImpl *target_type = OBJECT_CLASS(e->data)->type;
+
+                if (type_is_ancestor(target_type, t)) {
+                    break;
+                }
+            }
+
+            if (e) {
+                continue;
+            }
+
+            type_initialize_interface(ti, ti->interfaces[i].typename);
+        }
     }
 
     ti->class->type = ti;
@@ -245,38 +277,19 @@ static void type_initialize(TypeImpl *ti)
         parent = type_get_parent(parent);
     }
 
-    for (i = 0; i < ti->num_interfaces; i++) {
-        type_class_interface_init(ti, &ti->interfaces[i]);
-    }
-
     if (ti->class_init) {
         ti->class_init(ti->class, ti->class_data);
     }
-}
 
-static void object_interface_init(Object *obj, InterfaceImpl *iface)
-{
-    TypeImpl *ti = iface->type;
-    Interface *iface_obj;
-
-    iface_obj = INTERFACE(object_new(ti->name));
-    iface_obj->obj = obj;
 
-    obj->interfaces = g_slist_prepend(obj->interfaces, iface_obj);
 }
 
 static void object_init_with_type(Object *obj, TypeImpl *ti)
 {
-    int i;
-
     if (type_has_parent(ti)) {
         object_init_with_type(obj, type_get_parent(ti));
     }
 
-    for (i = 0; i < ti->num_interfaces; i++) {
-        object_interface_init(obj, &ti->interfaces[i]);
-    }
-
     if (ti->instance_init) {
         ti->instance_init(obj);
     }
@@ -357,12 +370,6 @@ static void object_deinit(Object *obj, TypeImpl *type)
         type->instance_finalize(obj);
     }
 
-    while (obj->interfaces) {
-        Interface *iface_obj = obj->interfaces->data;
-        obj->interfaces = g_slist_delete_link(obj->interfaces, obj->interfaces);
-        object_delete(OBJECT(iface_obj));
-    }
-
     if (type_has_parent(type)) {
         object_deinit(obj, type_get_parent(type));
     }
@@ -409,74 +416,15 @@ void object_delete(Object *obj)
     g_free(obj);
 }
 
-static bool type_is_ancestor(TypeImpl *type, TypeImpl *target_type)
-{
-    assert(target_type);
-
-    /* Check if typename is a direct ancestor of type */
-    while (type) {
-        if (type == target_type) {
-            return true;
-        }
-
-        type = type_get_parent(type);
-    }
-
-    return false;
-}
-
-static bool object_is_type(Object *obj, TypeImpl *target_type)
-{
-    return !target_type || type_is_ancestor(obj->class->type, target_type);
-}
-
 Object *object_dynamic_cast(Object *obj, const char *typename)
 {
-    TypeImpl *target_type = type_get_by_name(typename);
-    GSList *i;
-
-    /* Check if typename is a direct ancestor.  Special-case TYPE_OBJECT,
-     * we want to go back from interfaces to the parent.
-    */
-    if (target_type && object_is_type(obj, target_type)) {
+    if (object_class_dynamic_cast(object_get_class(obj), typename)) {
         return obj;
     }
 
-    /* Check if obj is an interface and its containing object is a direct
-     * ancestor of typename.  In principle we could do this test at the very
-     * beginning of object_dynamic_cast, avoiding a second call to
-     * object_is_type.  However, casting between interfaces is relatively
-     * rare, and object_is_type(obj, type_interface) would fail almost always.
-     *
-     * Perhaps we could add a magic value to the object header for increased
-     * (run-time) type safety and to speed up tests like this one.  If we ever
-     * do that we can revisit the order here.
-     */
-    if (object_is_type(obj, type_interface)) {
-        assert(!obj->interfaces);
-        obj = INTERFACE(obj)->obj;
-        if (object_is_type(obj, target_type)) {
-            return obj;
-        }
-    }
-
-    if (!target_type) {
-        return obj;
-    }
-
-    /* Check if obj has an interface of typename */
-    for (i = obj->interfaces; i; i = i->next) {
-        Interface *iface = i->data;
-
-        if (object_is_type(OBJECT(iface), target_type)) {
-            return OBJECT(iface);
-        }
-    }
-
     return NULL;
 }
 
-
 Object *object_dynamic_cast_assert(Object *obj, const char *typename)
 {
     Object *inst;
@@ -497,16 +445,30 @@ ObjectClass *object_class_dynamic_cast(ObjectClass *class,
 {
     TypeImpl *target_type = type_get_by_name(typename);
     TypeImpl *type = class->type;
+    ObjectClass *ret = NULL;
 
-    while (type) {
-        if (type == target_type) {
-            return class;
-        }
+    if (type->num_interfaces && type_is_ancestor(target_type, type_interface)) {
+        int found = 0;
+        GSList *i;
 
-        type = type_get_parent(type);
+        for (i = class->interfaces; i; i = i->next) {
+            ObjectClass *target_class = i->data;
+
+            if (type_is_ancestor(target_class->type, target_type)) {
+                ret = target_class;
+                found++;
+            }
+         }
+
+        /* The match was ambiguous, don't allow a cast */
+        if (found > 1) {
+            ret = NULL;
+        }
+    } else if (type_is_ancestor(type, target_type)) {
+        ret = class;
     }
 
-    return NULL;
+    return ret;
 }
 
 ObjectClass *object_class_dynamic_cast_assert(ObjectClass *class,
@@ -920,12 +882,6 @@ void object_property_add_child(Object *obj, const char *name,
 {
     gchar *type;
 
-    /* Registering an interface object in the composition tree will mightily
-     * confuse object_get_canonical_path (which, on the other hand, knows how
-     * to get the canonical path of an interface object).
-     */
-    assert(!object_is_type(obj, type_interface));
-
     type = g_strdup_printf("child<%s>", object_get_typename(OBJECT(child)));
 
     object_property_add(obj, name, type, object_get_child_property,
@@ -1022,10 +978,6 @@ gchar *object_get_canonical_path(Object *obj)
     Object *root = object_get_root();
     char *newpath = NULL, *path = NULL;
 
-    if (object_is_type(obj, type_interface)) {
-        obj = INTERFACE(obj)->obj;
-    }
-
     while (obj != root) {
         ObjectProperty *prop = NULL;
 
@@ -1246,7 +1198,7 @@ static void register_types(void)
 {
     static TypeInfo interface_info = {
         .name = TYPE_INTERFACE,
-        .instance_size = sizeof(Interface),
+        .class_size = sizeof(InterfaceClass),
         .abstract = true,
     };
 
diff --git a/savevm.c b/savevm.c
index 6e82b2d3e3..0ea10c9b66 100644
--- a/savevm.c
+++ b/savevm.c
@@ -2392,3 +2392,162 @@ void vmstate_register_ram_global(MemoryRegion *mr)
 {
     vmstate_register_ram(mr, NULL);
 }
+
+/*
+  page = zrun nzrun
+       | zrun nzrun page
+
+  zrun = length
+
+  nzrun = length byte...
+
+  length = uleb128 encoded integer
+ */
+int xbzrle_encode_buffer(uint8_t *old_buf, uint8_t *new_buf, int slen,
+                         uint8_t *dst, int dlen)
+{
+    uint32_t zrun_len = 0, nzrun_len = 0;
+    int d = 0, i = 0;
+    long res, xor;
+    uint8_t *nzrun_start = NULL;
+
+    g_assert(!(((uintptr_t)old_buf | (uintptr_t)new_buf | slen) %
+               sizeof(long)));
+
+    while (i < slen) {
+        /* overflow */
+        if (d + 2 > dlen) {
+            return -1;
+        }
+
+        /* not aligned to sizeof(long) */
+        res = (slen - i) % sizeof(long);
+        while (res && old_buf[i] == new_buf[i]) {
+            zrun_len++;
+            i++;
+            res--;
+        }
+
+        /* word at a time for speed */
+        if (!res) {
+            while (i < slen &&
+                   (*(long *)(old_buf + i)) == (*(long *)(new_buf + i))) {
+                i += sizeof(long);
+                zrun_len += sizeof(long);
+            }
+
+            /* go over the rest */
+            while (i < slen && old_buf[i] == new_buf[i]) {
+                zrun_len++;
+                i++;
+            }
+        }
+
+        /* buffer unchanged */
+        if (zrun_len == slen) {
+            return 0;
+        }
+
+        /* skip last zero run */
+        if (i == slen) {
+            return d;
+        }
+
+        d += uleb128_encode_small(dst + d, zrun_len);
+
+        zrun_len = 0;
+        nzrun_start = new_buf + i;
+
+        /* overflow */
+        if (d + 2 > dlen) {
+            return -1;
+        }
+        /* not aligned to sizeof(long) */
+        res = (slen - i) % sizeof(long);
+        while (res && old_buf[i] != new_buf[i]) {
+            i++;
+            nzrun_len++;
+            res--;
+        }
+
+        /* word at a time for speed, use of 32-bit long okay */
+        if (!res) {
+            /* truncation to 32-bit long okay */
+            long mask = 0x0101010101010101ULL;
+            while (i < slen) {
+                xor = *(long *)(old_buf + i) ^ *(long *)(new_buf + i);
+                if ((xor - mask) & ~xor & (mask << 7)) {
+                    /* found the end of an nzrun within the current long */
+                    while (old_buf[i] != new_buf[i]) {
+                        nzrun_len++;
+                        i++;
+                    }
+                    break;
+                } else {
+                    i += sizeof(long);
+                    nzrun_len += sizeof(long);
+                }
+            }
+        }
+
+        d += uleb128_encode_small(dst + d, nzrun_len);
+        /* overflow */
+        if (d + nzrun_len > dlen) {
+            return -1;
+        }
+        memcpy(dst + d, nzrun_start, nzrun_len);
+        d += nzrun_len;
+        nzrun_len = 0;
+    }
+
+    return d;
+}
+
+int xbzrle_decode_buffer(uint8_t *src, int slen, uint8_t *dst, int dlen)
+{
+    int i = 0, d = 0;
+    int ret;
+    uint32_t count = 0;
+
+    while (i < slen) {
+
+        /* zrun */
+        if ((slen - i) < 2) {
+            return -1;
+        }
+
+        ret = uleb128_decode_small(src + i, &count);
+        if (ret < 0 || (i && !count)) {
+            return -1;
+        }
+        i += ret;
+        d += count;
+
+        /* overflow */
+        if (d > dlen) {
+            return -1;
+        }
+
+        /* nzrun */
+        if ((slen - i) < 2) {
+            return -1;
+        }
+
+        ret = uleb128_decode_small(src + i, &count);
+        if (ret < 0 || !count) {
+            return -1;
+        }
+        i += ret;
+
+        /* overflow */
+        if (d + count > dlen || i + count > slen) {
+            return -1;
+        }
+
+        memcpy(dst + d, src + i, count);
+        d += count;
+        i += count;
+    }
+
+    return d;
+}
diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py
index 9eed40e18a..3c4678dbf1 100644
--- a/scripts/qapi-commands.py
+++ b/scripts/qapi-commands.py
@@ -342,6 +342,7 @@ def gen_command_decl_prologue(header, guard, prefix=""):
 #define %(guard)s
 
 #include "%(prefix)sqapi-types.h"
+#include "qdict.h"
 #include "error.h"
 
 ''',
diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
index 4a734f58d5..cf601ae2d2 100644
--- a/scripts/qapi-types.py
+++ b/scripts/qapi-types.py
@@ -70,7 +70,7 @@ const char *%(name)s_lookup[] = {
         ret += mcgen('''
     "%(value)s",
 ''',
-                     value=value.lower())
+                     value=value)
 
     ret += mcgen('''
     NULL,
@@ -79,6 +79,16 @@ const char *%(name)s_lookup[] = {
 ''')
     return ret
 
+def generate_enum_name(name):
+    if name.isupper():
+        return c_fun(name)
+    new_name = ''
+    for c in c_fun(name):
+        if c.isupper():
+            new_name += '_'
+        new_name += c
+    return new_name.lstrip('_').upper()
+
 def generate_enum(name, values):
     lookup_decl = mcgen('''
 extern const char *%(name)s_lookup[];
@@ -100,7 +110,7 @@ typedef enum %(name)s
     %(abbrev)s_%(value)s = %(i)d,
 ''',
                      abbrev=de_camel_case(name).upper(),
-                     value=c_fun(value).upper(),
+                     value=generate_enum_name(value),
                      i=i)
         i += 1
 
@@ -253,7 +263,8 @@ fdecl.write(mcgen('''
 #ifndef %(guard)s
 #define %(guard)s
 
-#include "qapi/qapi-types-core.h"
+#include "qemu-common.h"
+
 ''',
                   guard=guardname(h_file)))
 
diff --git a/scripts/qapi.py b/scripts/qapi.py
index d3b8b4d851..122b4cb6d1 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -142,6 +142,22 @@ def camel_case(name):
     return new_name
 
 def c_var(name):
+    # ANSI X3J11/88-090, 3.1.1
+    c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
+                     'default', 'do', 'double', 'else', 'enum', 'extern', 'float',
+                     'for', 'goto', 'if', 'int', 'long', 'register', 'return',
+                     'short', 'signed', 'sizeof', 'static', 'struct', 'switch',
+                     'typedef', 'union', 'unsigned', 'void', 'volatile', 'while'])
+    # ISO/IEC 9899:1999, 6.4.1
+    c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
+    # ISO/IEC 9899:2011, 6.4.1
+    c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic', '_Noreturn',
+                     '_Static_assert', '_Thread_local'])
+    # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
+    # excluding _.*
+    gcc_words = set(['asm', 'typeof'])
+    if name in c89_words | c99_words | c11_words | gcc_words:
+        return "q_" + name
     return name.replace('-', '_').lstrip("*")
 
 def c_fun(name):
diff --git a/target-arm/arm-semi.c b/target-arm/arm-semi.c
index 88ca9bb1b7..24952061cf 100644
--- a/target-arm/arm-semi.c
+++ b/target-arm/arm-semi.c
@@ -281,7 +281,7 @@ uint32_t do_arm_semihosting(CPUARMState *env)
             return len - ret;
         }
     case TARGET_SYS_READC:
-       /* XXX: Read from debug cosole. Not implemented.  */
+       /* XXX: Read from debug console. Not implemented.  */
         return 0;
     case TARGET_SYS_ISTTY:
         if (use_gdb_syscalls()) {
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 191895cca8..d7f93d98f0 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -79,7 +79,7 @@ struct arm_boot_info;
 typedef struct CPUARMState {
     /* Regs for current mode.  */
     uint32_t regs[16];
-    /* Frequently accessed CPSR bits are stored separately for efficiently.
+    /* Frequently accessed CPSR bits are stored separately for efficiency.
        This contains all the other bits.  Use cpsr_{read,write} to access
        the whole CPSR.  */
     uint32_t uncached_cpsr;
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 5727da296c..dceaa95c80 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -988,7 +988,7 @@ static void ttbr164_reset(CPUARMState *env, const ARMCPRegInfo *ri)
 }
 
 static const ARMCPRegInfo lpae_cp_reginfo[] = {
-    /* NOP AMAIR0/1: the override is because these clash with tha rather
+    /* NOP AMAIR0/1: the override is because these clash with the rather
      * broadly specified TLB_LOCKDOWN entry in the generic cp_reginfo.
      */
     { .name = "AMAIR0", .cp = 15, .crn = 10, .crm = 3, .opc1 = 0, .opc2 = 0,
@@ -2899,8 +2899,8 @@ uint32_t HELPER(logicq_cc)(uint64_t val)
     return (val >> 32) | (val != 0);
 }
 
-/* VFP support.  We follow the convention used for VFP instrunctions:
-   Single precition routines have a "s" suffix, double precision a
+/* VFP support.  We follow the convention used for VFP instructions:
+   Single precision routines have a "s" suffix, double precision a
    "d" suffix.  */
 
 /* Convert host exception flags to vfp form.  */
diff --git a/target-arm/neon_helper.c b/target-arm/neon_helper.c
index e0b9dbf67e..8bb5129d6a 100644
--- a/target-arm/neon_helper.c
+++ b/target-arm/neon_helper.c
@@ -530,7 +530,7 @@ NEON_VOP(rshl_s16, neon_s16, 2)
 #undef NEON_FN
 
 /* The addition of the rounding constant may overflow, so we use an
- * intermediate 64 bits accumulator.  */
+ * intermediate 64 bit accumulator.  */
 uint32_t HELPER(neon_rshl_s32)(uint32_t valop, uint32_t shiftop)
 {
     int32_t dest;
@@ -547,8 +547,8 @@ uint32_t HELPER(neon_rshl_s32)(uint32_t valop, uint32_t shiftop)
     return dest;
 }
 
-/* Handling addition overflow with 64 bits inputs values is more
- * tricky than with 32 bits values.  */
+/* Handling addition overflow with 64 bit input values is more
+ * tricky than with 32 bit values.  */
 uint64_t HELPER(neon_rshl_s64)(uint64_t valop, uint64_t shiftop)
 {
     int8_t shift = (int8_t)shiftop;
@@ -590,7 +590,7 @@ NEON_VOP(rshl_u16, neon_u16, 2)
 #undef NEON_FN
 
 /* The addition of the rounding constant may overflow, so we use an
- * intermediate 64 bits accumulator.  */
+ * intermediate 64 bit accumulator.  */
 uint32_t HELPER(neon_rshl_u32)(uint32_t val, uint32_t shiftop)
 {
     uint32_t dest;
@@ -608,8 +608,8 @@ uint32_t HELPER(neon_rshl_u32)(uint32_t val, uint32_t shiftop)
     return dest;
 }
 
-/* Handling addition overflow with 64 bits inputs values is more
- * tricky than with 32 bits values.  */
+/* Handling addition overflow with 64 bit input values is more
+ * tricky than with 32 bit values.  */
 uint64_t HELPER(neon_rshl_u64)(uint64_t val, uint64_t shiftop)
 {
     int8_t shift = (uint8_t)shiftop;
@@ -817,7 +817,7 @@ NEON_VOP_ENV(qrshl_u16, neon_u16, 2)
 #undef NEON_FN
 
 /* The addition of the rounding constant may overflow, so we use an
- * intermediate 64 bits accumulator.  */
+ * intermediate 64 bit accumulator.  */
 uint32_t HELPER(neon_qrshl_u32)(CPUARMState *env, uint32_t val, uint32_t shiftop)
 {
     uint32_t dest;
@@ -846,8 +846,8 @@ uint32_t HELPER(neon_qrshl_u32)(CPUARMState *env, uint32_t val, uint32_t shiftop
     return dest;
 }
 
-/* Handling addition overflow with 64 bits inputs values is more
- * tricky than with 32 bits values.  */
+/* Handling addition overflow with 64 bit input values is more
+ * tricky than with 32 bit values.  */
 uint64_t HELPER(neon_qrshl_u64)(CPUARMState *env, uint64_t val, uint64_t shiftop)
 {
     int8_t shift = (int8_t)shiftop;
@@ -914,7 +914,7 @@ NEON_VOP_ENV(qrshl_s16, neon_s16, 2)
 #undef NEON_FN
 
 /* The addition of the rounding constant may overflow, so we use an
- * intermediate 64 bits accumulator.  */
+ * intermediate 64 bit accumulator.  */
 uint32_t HELPER(neon_qrshl_s32)(CPUARMState *env, uint32_t valop, uint32_t shiftop)
 {
     int32_t dest;
@@ -942,8 +942,8 @@ uint32_t HELPER(neon_qrshl_s32)(CPUARMState *env, uint32_t valop, uint32_t shift
     return dest;
 }
 
-/* Handling addition overflow with 64 bits inputs values is more
- * tricky than with 32 bits values.  */
+/* Handling addition overflow with 64 bit input values is more
+ * tricky than with 32 bit values.  */
 uint64_t HELPER(neon_qrshl_s64)(CPUARMState *env, uint64_t valop, uint64_t shiftop)
 {
     int8_t shift = (uint8_t)shiftop;
@@ -1671,7 +1671,7 @@ uint64_t HELPER(neon_negl_u64)(uint64_t x)
     return -x;
 }
 
-/* Saturnating sign manuipulation.  */
+/* Saturating sign manipulation.  */
 /* ??? Make these use NEON_VOP1 */
 #define DO_QABS8(x) do { \
     if (x == (int8_t)0x80) { \
diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
index 490111c22f..d77bfab771 100644
--- a/target-arm/op_helper.c
+++ b/target-arm/op_helper.c
@@ -99,7 +99,7 @@ void tlb_fill(CPUARMState *env1, target_ulong addr, int is_write, int mmu_idx,
 }
 #endif
 
-/* FIXME: Pass an axplicit pointer to QF to CPUARMState, and move saturating
+/* FIXME: Pass an explicit pointer to QF to CPUARMState, and move saturating
    instructions into helper.c  */
 uint32_t HELPER(add_setq)(uint32_t a, uint32_t b)
 {
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 29008a4b34..edef79a2cf 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -53,7 +53,7 @@ typedef struct DisasContext {
     int condjmp;
     /* The label that will be jumped to when the instruction is skipped.  */
     int condlabel;
-    /* Thumb-2 condtional execution bits.  */
+    /* Thumb-2 conditional execution bits.  */
     int condexec_mask;
     int condexec_cond;
     struct TranslationBlock *tb;
@@ -77,7 +77,7 @@ static uint32_t gen_opc_condexec_bits[OPC_BUF_SIZE];
 #endif
 
 /* These instructions trap after executing, so defer them until after the
-   conditional executions state has been updated.  */
+   conditional execution state has been updated.  */
 #define DISAS_WFI 4
 #define DISAS_SWI 5
 
@@ -155,7 +155,7 @@ static void load_reg_var(DisasContext *s, TCGv var, int reg)
 {
     if (reg == 15) {
         uint32_t addr;
-        /* normaly, since we updated PC, we need only to add one insn */
+        /* normally, since we updated PC, we need only to add one insn */
         if (s->thumb)
             addr = (long)s->pc + 2;
         else
@@ -4897,7 +4897,7 @@ static int disas_neon_data_insn(CPUARMState * env, DisasContext *s, uint32_t ins
                     size--;
             }
             shift = (insn >> 16) & ((1 << (3 + size)) - 1);
-            /* To avoid excessive dumplication of ops we implement shift
+            /* To avoid excessive duplication of ops we implement shift
                by immediate using the variable shift operations.  */
             if (op < 8) {
                 /* Shift by immediate:
@@ -6402,7 +6402,7 @@ static void gen_logicq_cc(TCGv_i64 val)
 
 /* Load/Store exclusive instructions are implemented by remembering
    the value/address loaded, and seeing if these are the same
-   when the store is performed. This should be is sufficient to implement
+   when the store is performed. This should be sufficient to implement
    the architecturally mandated semantics, and avoids having to monitor
    regular stores.
 
@@ -9892,7 +9892,7 @@ static inline void gen_intermediate_code_internal(CPUARMState *env,
     } else {
         /* While branches must always occur at the end of an IT block,
            there are a few other things that can cause us to terminate
-           the TB in the middel of an IT block:
+           the TB in the middle of an IT block:
             - Exception generating instructions (bkpt, swi, undefined).
             - Page boundaries.
             - Hardware watchpoints.
diff --git a/target-i386/Makefile.objs b/target-i386/Makefile.objs
index 683fd59af9..0715f58a8e 100644
--- a/target-i386/Makefile.objs
+++ b/target-i386/Makefile.objs
@@ -3,6 +3,7 @@ obj-y += excp_helper.o fpu_helper.o cc_helper.o int_helper.o svm_helper.o
 obj-y += smm_helper.o misc_helper.o mem_helper.o seg_helper.o
 obj-$(CONFIG_SOFTMMU) += machine.o arch_memory_mapping.o arch_dump.o
 obj-$(CONFIG_KVM) += kvm.o hyperv.o
+obj-$(CONFIG_NO_KVM) += kvm-stub.o
 obj-$(CONFIG_LINUX_USER) += ioport-user.o
 obj-$(CONFIG_BSD_USER) += ioport-user.o
 
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index 857b94ea87..6d5d0d6e10 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -28,6 +28,7 @@
 #include "qemu-config.h"
 
 #include "qapi/qapi-visit-core.h"
+#include "qmp-commands.h"
 
 #include "hyperv.h"
 
@@ -1125,6 +1126,27 @@ void x86_cpu_list(FILE *f, fprintf_function cpu_fprintf, const char *optarg)
     }
 }
 
+CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
+{
+    CpuDefinitionInfoList *cpu_list = NULL;
+    x86_def_t *def;
+
+    for (def = x86_defs; def; def = def->next) {
+        CpuDefinitionInfoList *entry;
+        CpuDefinitionInfo *info;
+
+        info = g_malloc0(sizeof(*info));
+        info->name = g_strdup(def->name);
+
+        entry = g_malloc0(sizeof(*entry));
+        entry->value = info;
+        entry->next = cpu_list;
+        cpu_list = entry;
+    }
+
+    return cpu_list;
+}
+
 int cpu_x86_register(X86CPU *cpu, const char *cpu_model)
 {
     CPUX86State *env = &cpu->env;
@@ -1746,6 +1768,7 @@ static void x86_cpu_initfn(Object *obj)
 {
     X86CPU *cpu = X86_CPU(obj);
     CPUX86State *env = &cpu->env;
+    static int inited;
 
     cpu_exec_init(env);
 
@@ -1775,6 +1798,15 @@ static void x86_cpu_initfn(Object *obj)
                         x86_cpuid_set_tsc_freq, NULL, NULL, NULL);
 
     env->cpuid_apic_id = env->cpu_index;
+
+    /* init various static tables used in TCG mode */
+    if (tcg_enabled() && !inited) {
+        inited = 1;
+        optimize_flags_init();
+#ifndef CONFIG_USER_ONLY
+        cpu_set_debug_excp_handler(breakpoint_handler);
+#endif
+    }
 }
 
 static void x86_cpu_common_class_init(ObjectClass *oc, void *data)
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 2a61c810bb..60f9e972bd 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -935,6 +935,7 @@ static inline int hw_breakpoint_len(unsigned long dr7, int index)
 void hw_breakpoint_insert(CPUX86State *env, int index);
 void hw_breakpoint_remove(CPUX86State *env, int index);
 int check_hw_breakpoints(CPUX86State *env, int force_dr6_update);
+void breakpoint_handler(CPUX86State *env);
 
 /* will be suppressed */
 void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0);
diff --git a/target-i386/helper.c b/target-i386/helper.c
index b748d90063..8a5da3d7c0 100644
--- a/target-i386/helper.c
+++ b/target-i386/helper.c
@@ -941,9 +941,7 @@ int check_hw_breakpoints(CPUX86State *env, int force_dr6_update)
     return hit_enabled;
 }
 
-static CPUDebugExcpHandler *prev_debug_excp_handler;
-
-static void breakpoint_handler(CPUX86State *env)
+void breakpoint_handler(CPUX86State *env)
 {
     CPUBreakpoint *bp;
 
@@ -965,8 +963,6 @@ static void breakpoint_handler(CPUX86State *env)
                 break;
             }
     }
-    if (prev_debug_excp_handler)
-        prev_debug_excp_handler(env);
 }
 
 typedef struct MCEInjectionParams {
@@ -1155,21 +1151,11 @@ X86CPU *cpu_x86_init(const char *cpu_model)
 {
     X86CPU *cpu;
     CPUX86State *env;
-    static int inited;
 
     cpu = X86_CPU(object_new(TYPE_X86_CPU));
     env = &cpu->env;
     env->cpu_model_str = cpu_model;
 
-    /* init various static tables used in TCG mode */
-    if (tcg_enabled() && !inited) {
-        inited = 1;
-        optimize_flags_init();
-#ifndef CONFIG_USER_ONLY
-        prev_debug_excp_handler =
-            cpu_set_debug_excp_handler(breakpoint_handler);
-#endif
-    }
     if (cpu_x86_register(cpu, cpu_model) < 0) {
         object_delete(OBJECT(cpu));
         return NULL;
diff --git a/target-i386/kvm-stub.c b/target-i386/kvm-stub.c
new file mode 100644
index 0000000000..11429c461e
--- /dev/null
+++ b/target-i386/kvm-stub.c
@@ -0,0 +1,18 @@
+/*
+ * QEMU KVM x86 specific function stubs
+ *
+ * Copyright Linaro Limited 2012
+ *
+ * Author: Peter Maydell <peter.maydell@linaro.org>
+ *
+ * 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 "qemu-common.h"
+#include "kvm_i386.h"
+
+bool kvm_allows_irq0_override(void)
+{
+    return 1;
+}
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index 4cfb3faf01..696b14a04a 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -23,6 +23,7 @@
 #include "qemu-common.h"
 #include "sysemu.h"
 #include "kvm.h"
+#include "kvm_i386.h"
 #include "cpu.h"
 #include "gdbstub.h"
 #include "host-utils.h"
@@ -65,6 +66,11 @@ static bool has_msr_async_pf_en;
 static bool has_msr_misc_enable;
 static int lm_capable_kernel;
 
+bool kvm_allows_irq0_override(void)
+{
+    return !kvm_irqchip_in_kernel() || kvm_has_gsi_routing();
+}
+
 static struct kvm_cpuid2 *try_get_cpuid(KVMState *s, int max)
 {
     struct kvm_cpuid2 *cpuid;
@@ -2041,4 +2047,11 @@ void kvm_arch_init_irq_routing(KVMState *s)
          */
         no_hpet = 1;
     }
+    /* We know at this point that we're using the in-kernel
+     * irqchip, so we can use irqfds, and on x86 we know
+     * we can use msi via irqfd and GSI routing.
+     */
+    kvm_irqfds_allowed = true;
+    kvm_msi_via_irqfd_allowed = true;
+    kvm_gsi_routing_allowed = true;
 }
diff --git a/target-i386/kvm_i386.h b/target-i386/kvm_i386.h
new file mode 100644
index 0000000000..b82bbf401e
--- /dev/null
+++ b/target-i386/kvm_i386.h
@@ -0,0 +1,16 @@
+/*
+ * QEMU KVM support -- x86 specific functions.
+ *
+ * Copyright (c) 2012 Linaro Limited
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef QEMU_KVM_I386_H
+#define QEMU_KVM_I386_H
+
+bool kvm_allows_irq0_override(void);
+
+#endif
diff --git a/target-mips/translate.c b/target-mips/translate.c
index 4e15ee36b8..47daf8574f 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -12763,6 +12763,7 @@ void cpu_state_reset(CPUMIPSState *env)
     env->CP0_SRSConf3 = env->cpu_model->CP0_SRSConf3;
     env->CP0_SRSConf4_rw_bitmask = env->cpu_model->CP0_SRSConf4_rw_bitmask;
     env->CP0_SRSConf4 = env->cpu_model->CP0_SRSConf4;
+    env->active_fpu.fcr0 = env->cpu_model->CP1_fcr0;
     env->insn_flags = env->cpu_model->insn_flags;
 
 #if defined(CONFIG_USER_ONLY)
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index 5742229197..6fe4168dc0 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -27,6 +27,7 @@
 #include "gdbstub.h"
 #include <kvm.h>
 #include "kvm_ppc.h"
+#include "qmp-commands.h"
 
 //#define PPC_DUMP_CPU
 //#define PPC_DEBUG_SPR
@@ -10345,6 +10346,31 @@ void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf)
     }
 }
 
+CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
+{
+    CpuDefinitionInfoList *cpu_list = NULL;
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(ppc_defs); i++) {
+        CpuDefinitionInfoList *entry;
+        CpuDefinitionInfo *info;
+
+        if (!ppc_cpu_usable(&ppc_defs[i])) {
+            continue;
+        }
+
+        info = g_malloc0(sizeof(*info));
+        info->name = g_strdup(ppc_defs[i].name);
+
+        entry = g_malloc0(sizeof(*entry));
+        entry->value = info;
+        entry->next = cpu_list;
+        cpu_list = entry;
+    }
+
+    return cpu_list;
+}
+
 /* CPUClass::reset() */
 static void ppc_cpu_reset(CPUState *s)
 {
diff --git a/target-unicore32/Makefile.objs b/target-unicore32/Makefile.objs
index 2e0e093e1f..777f01fef8 100644
--- a/target-unicore32/Makefile.objs
+++ b/target-unicore32/Makefile.objs
@@ -1,4 +1,6 @@
 obj-y += translate.o op_helper.o helper.o cpu.o
-obj-$(CONFIG_SOFTMMU) += machine.o
+obj-y += ucf64_helper.o
+
+obj-$(CONFIG_SOFTMMU) += machine.o softmmu.o
 
 $(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
diff --git a/target-unicore32/cpu.c b/target-unicore32/cpu.c
index de63f58dda..3425bbeac9 100644
--- a/target-unicore32/cpu.c
+++ b/target-unicore32/cpu.c
@@ -1,7 +1,7 @@
 /*
  * QEMU UniCore32 CPU
  *
- * Copyright (c) 2010-2011 GUAN Xue-tao
+ * Copyright (c) 2010-2012 Guan Xuetao
  * Copyright (c) 2012 SUSE LINUX Products GmbH
  *
  * This program is free software; you can redistribute it and/or modify
@@ -32,13 +32,16 @@ static void unicore_ii_cpu_initfn(Object *obj)
     UniCore32CPU *cpu = UNICORE32_CPU(obj);
     CPUUniCore32State *env = &cpu->env;
 
-    env->cp0.c0_cpuid = 0x40010863;
+    env->cp0.c0_cpuid = 0x4d000863;
+    env->cp0.c0_cachetype = 0x0d152152;
+    env->cp0.c1_sys = 0x2000;
+    env->cp0.c2_base = 0x0;
+    env->cp0.c3_faultstatus = 0x0;
+    env->cp0.c4_faultaddr = 0x0;
+    env->ucf64.xregs[UC32_UCF64_FPSCR] = 0;
 
     set_feature(env, UC32_HWCAP_CMOV);
     set_feature(env, UC32_HWCAP_UCF64);
-    env->ucf64.xregs[UC32_UCF64_FPSCR] = 0;
-    env->cp0.c0_cachetype = 0x1dd20d2;
-    env->cp0.c1_sys = 0x00090078;
 }
 
 static void uc32_any_cpu_initfn(Object *obj)
@@ -47,6 +50,7 @@ static void uc32_any_cpu_initfn(Object *obj)
     CPUUniCore32State *env = &cpu->env;
 
     env->cp0.c0_cpuid = 0xffffffff;
+    env->ucf64.xregs[UC32_UCF64_FPSCR] = 0;
 
     set_feature(env, UC32_HWCAP_CMOV);
     set_feature(env, UC32_HWCAP_UCF64);
@@ -65,8 +69,13 @@ static void uc32_cpu_initfn(Object *obj)
     cpu_exec_init(env);
     env->cpu_model_str = object_get_typename(obj);
 
+#ifdef CONFIG_USER_ONLY
     env->uncached_asr = ASR_MODE_USER;
     env->regs[31] = 0;
+#else
+    env->uncached_asr = ASR_MODE_PRIV;
+    env->regs[31] = 0x03000000;
+#endif
 
     tlb_flush(env, 1);
 }
diff --git a/target-unicore32/cpu.h b/target-unicore32/cpu.h
index 81c14ffd77..06508a1278 100644
--- a/target-unicore32/cpu.h
+++ b/target-unicore32/cpu.h
@@ -1,15 +1,15 @@
 /*
  * UniCore32 virtual CPU header
  *
- * Copyright (C) 2010-2011 GUAN Xue-tao
+ * Copyright (C) 2010-2012 Guan Xuetao
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation, or (at your option) any
  * later version. See the COPYING file in the top-level directory.
  */
-#ifndef __CPU_UC32_H__
-#define __CPU_UC32_H__
+#ifndef QEMU_UNICORE32_CPU_H
+#define QEMU_UNICORE32_CPU_H
 
 #define TARGET_LONG_BITS                32
 #define TARGET_PAGE_BITS                12
@@ -89,8 +89,10 @@ typedef struct CPUUniCore32State {
 #define ASR_NZCV                (ASR_N | ASR_Z | ASR_C | ASR_V)
 #define ASR_RESERVED            (~(ASR_M | ASR_I | ASR_NZCV))
 
-#define UC32_EXCP_PRIV          (ASR_MODE_PRIV)
-#define UC32_EXCP_TRAP          (ASR_MODE_TRAP)
+#define UC32_EXCP_PRIV          (1)
+#define UC32_EXCP_ITRAP         (2)
+#define UC32_EXCP_DTRAP         (3)
+#define UC32_EXCP_INTR          (4)
 
 /* Return the current ASR value.  */
 target_ulong cpu_asr_read(CPUUniCore32State *env1);
@@ -120,10 +122,6 @@ void cpu_asr_write(CPUUniCore32State *env1, target_ulong val, target_ulong mask)
 #define UC32_HWCAP_CMOV                 4 /* 1 << 2 */
 #define UC32_HWCAP_UCF64                8 /* 1 << 3 */
 
-#define UC32_CPUID(env)                 (env->cp0.c0_cpuid)
-#define UC32_CPUID_UCV2                 0x40010863
-#define UC32_CPUID_ANY                  0xffffffff
-
 #define cpu_init                        uc32_cpu_init
 #define cpu_exec                        uc32_cpu_exec
 #define cpu_signal_handler              uc32_cpu_signal_handler
@@ -189,4 +187,4 @@ static inline bool cpu_has_work(CPUUniCore32State *env)
         (CPU_INTERRUPT_HARD | CPU_INTERRUPT_EXITTB);
 }
 
-#endif /* __CPU_UC32_H__ */
+#endif /* QEMU_UNICORE32_CPU_H */
diff --git a/target-unicore32/helper.c b/target-unicore32/helper.c
index 9fe4a375e4..a9e226bde4 100644
--- a/target-unicore32/helper.c
+++ b/target-unicore32/helper.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010-2011 GUAN Xue-tao
+ * Copyright (C) 2010-2012 Guan Xuetao
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -13,6 +13,15 @@
 #include "gdbstub.h"
 #include "helper.h"
 #include "host-utils.h"
+#include "console.h"
+
+#undef DEBUG_UC32
+
+#ifdef DEBUG_UC32
+#define DPRINTF(fmt, ...) printf("%s: " fmt , __func__, ## __VA_ARGS__)
+#else
+#define DPRINTF(fmt, ...) do {} while (0)
+#endif
 
 CPUUniCore32State *uc32_cpu_init(const char *cpu_model)
 {
@@ -45,389 +54,203 @@ uint32_t HELPER(clz)(uint32_t x)
     return clz32(x);
 }
 
-void do_interrupt(CPUUniCore32State *env)
-{
-    env->exception_index = -1;
-}
-
-int uc32_cpu_handle_mmu_fault(CPUUniCore32State *env, target_ulong address, int rw,
-                              int mmu_idx)
-{
-    env->exception_index = UC32_EXCP_TRAP;
-    env->cp0.c4_faultaddr = address;
-    return 1;
-}
-
-/* These should probably raise undefined insn exceptions.  */
-void HELPER(set_cp)(CPUUniCore32State *env, uint32_t insn, uint32_t val)
-{
-    int op1 = (insn >> 8) & 0xf;
-    cpu_abort(env, "cp%i insn %08x\n", op1, insn);
-    return;
-}
-
-uint32_t HELPER(get_cp)(CPUUniCore32State *env, uint32_t insn)
-{
-    int op1 = (insn >> 8) & 0xf;
-    cpu_abort(env, "cp%i insn %08x\n", op1, insn);
-    return 0;
-}
-
-void HELPER(set_cp0)(CPUUniCore32State *env, uint32_t insn, uint32_t val)
-{
-    cpu_abort(env, "cp0 insn %08x\n", insn);
-}
-
-uint32_t HELPER(get_cp0)(CPUUniCore32State *env, uint32_t insn)
-{
-    cpu_abort(env, "cp0 insn %08x\n", insn);
-    return 0;
-}
-
-void switch_mode(CPUUniCore32State *env, int mode)
-{
-    if (mode != ASR_MODE_USER) {
-        cpu_abort(env, "Tried to switch out of user mode\n");
-    }
-}
-
-void HELPER(set_r29_banked)(CPUUniCore32State *env, uint32_t mode, uint32_t val)
-{
-    cpu_abort(env, "banked r29 write\n");
-}
-
-uint32_t HELPER(get_r29_banked)(CPUUniCore32State *env, uint32_t mode)
-{
-    cpu_abort(env, "banked r29 read\n");
-    return 0;
-}
-
-/* UniCore-F64 support.  We follow the convention used for F64 instrunctions:
-   Single precition routines have a "s" suffix, double precision a
-   "d" suffix.  */
-
-/* Convert host exception flags to f64 form.  */
-static inline int ucf64_exceptbits_from_host(int host_bits)
-{
-    int target_bits = 0;
-
-    if (host_bits & float_flag_invalid) {
-        target_bits |= UCF64_FPSCR_FLAG_INVALID;
-    }
-    if (host_bits & float_flag_divbyzero) {
-        target_bits |= UCF64_FPSCR_FLAG_DIVZERO;
-    }
-    if (host_bits & float_flag_overflow) {
-        target_bits |= UCF64_FPSCR_FLAG_OVERFLOW;
-    }
-    if (host_bits & float_flag_underflow) {
-        target_bits |= UCF64_FPSCR_FLAG_UNDERFLOW;
-    }
-    if (host_bits & float_flag_inexact) {
-        target_bits |= UCF64_FPSCR_FLAG_INEXACT;
-    }
-    return target_bits;
-}
-
-uint32_t HELPER(ucf64_get_fpscr)(CPUUniCore32State *env)
-{
-    int i;
-    uint32_t fpscr;
-
-    fpscr = (env->ucf64.xregs[UC32_UCF64_FPSCR] & UCF64_FPSCR_MASK);
-    i = get_float_exception_flags(&env->ucf64.fp_status);
-    fpscr |= ucf64_exceptbits_from_host(i);
-    return fpscr;
-}
-
-/* Convert ucf64 exception flags to target form.  */
-static inline int ucf64_exceptbits_to_host(int target_bits)
-{
-    int host_bits = 0;
-
-    if (target_bits & UCF64_FPSCR_FLAG_INVALID) {
-        host_bits |= float_flag_invalid;
-    }
-    if (target_bits & UCF64_FPSCR_FLAG_DIVZERO) {
-        host_bits |= float_flag_divbyzero;
-    }
-    if (target_bits & UCF64_FPSCR_FLAG_OVERFLOW) {
-        host_bits |= float_flag_overflow;
-    }
-    if (target_bits & UCF64_FPSCR_FLAG_UNDERFLOW) {
-        host_bits |= float_flag_underflow;
-    }
-    if (target_bits & UCF64_FPSCR_FLAG_INEXACT) {
-        host_bits |= float_flag_inexact;
-    }
-    return host_bits;
-}
-
-void HELPER(ucf64_set_fpscr)(CPUUniCore32State *env, uint32_t val)
-{
-    int i;
-    uint32_t changed;
-
-    changed = env->ucf64.xregs[UC32_UCF64_FPSCR];
-    env->ucf64.xregs[UC32_UCF64_FPSCR] = (val & UCF64_FPSCR_MASK);
-
-    changed ^= val;
-    if (changed & (UCF64_FPSCR_RND_MASK)) {
-        i = UCF64_FPSCR_RND(val);
-        switch (i) {
-        case 0:
-            i = float_round_nearest_even;
-            break;
-        case 1:
-            i = float_round_to_zero;
-            break;
-        case 2:
-            i = float_round_up;
-            break;
-        case 3:
-            i = float_round_down;
-            break;
-        default: /* 100 and 101 not implement */
-            cpu_abort(env, "Unsupported UniCore-F64 round mode");
-        }
-        set_float_rounding_mode(i, &env->ucf64.fp_status);
-    }
-
-    i = ucf64_exceptbits_to_host(UCF64_FPSCR_TRAPEN(val));
-    set_float_exception_flags(i, &env->ucf64.fp_status);
-}
-
-float32 HELPER(ucf64_adds)(float32 a, float32 b, CPUUniCore32State *env)
-{
-    return float32_add(a, b, &env->ucf64.fp_status);
-}
-
-float64 HELPER(ucf64_addd)(float64 a, float64 b, CPUUniCore32State *env)
-{
-    return float64_add(a, b, &env->ucf64.fp_status);
-}
-
-float32 HELPER(ucf64_subs)(float32 a, float32 b, CPUUniCore32State *env)
-{
-    return float32_sub(a, b, &env->ucf64.fp_status);
-}
-
-float64 HELPER(ucf64_subd)(float64 a, float64 b, CPUUniCore32State *env)
-{
-    return float64_sub(a, b, &env->ucf64.fp_status);
-}
-
-float32 HELPER(ucf64_muls)(float32 a, float32 b, CPUUniCore32State *env)
-{
-    return float32_mul(a, b, &env->ucf64.fp_status);
-}
-
-float64 HELPER(ucf64_muld)(float64 a, float64 b, CPUUniCore32State *env)
-{
-    return float64_mul(a, b, &env->ucf64.fp_status);
-}
-
-float32 HELPER(ucf64_divs)(float32 a, float32 b, CPUUniCore32State *env)
-{
-    return float32_div(a, b, &env->ucf64.fp_status);
-}
-
-float64 HELPER(ucf64_divd)(float64 a, float64 b, CPUUniCore32State *env)
-{
-    return float64_div(a, b, &env->ucf64.fp_status);
-}
-
-float32 HELPER(ucf64_negs)(float32 a)
-{
-    return float32_chs(a);
-}
-
-float64 HELPER(ucf64_negd)(float64 a)
-{
-    return float64_chs(a);
-}
-
-float32 HELPER(ucf64_abss)(float32 a)
-{
-    return float32_abs(a);
-}
-
-float64 HELPER(ucf64_absd)(float64 a)
-{
-    return float64_abs(a);
-}
-
-/* XXX: check quiet/signaling case */
-void HELPER(ucf64_cmps)(float32 a, float32 b, uint32_t c, CPUUniCore32State *env)
-{
-    int flag;
-    flag = float32_compare_quiet(a, b, &env->ucf64.fp_status);
-    env->CF = 0;
-    switch (c & 0x7) {
-    case 0: /* F */
-        break;
-    case 1: /* UN */
-        if (flag == 2) {
-            env->CF = 1;
+#ifndef CONFIG_USER_ONLY
+void helper_cp0_set(CPUUniCore32State *env, uint32_t val, uint32_t creg,
+        uint32_t cop)
+{
+    /*
+     * movc pp.nn, rn, #imm9
+     *      rn: UCOP_REG_D
+     *      nn: UCOP_REG_N
+     *          1: sys control reg.
+     *          2: page table base reg.
+     *          3: data fault status reg.
+     *          4: insn fault status reg.
+     *          5: cache op. reg.
+     *          6: tlb op. reg.
+     *      imm9: split UCOP_IMM10 with bit5 is 0
+     */
+    switch (creg) {
+    case 1:
+        if (cop != 0) {
+            goto unrecognized;
         }
+        env->cp0.c1_sys = val;
         break;
-    case 2: /* EQ */
-        if (flag == 0) {
-            env->CF = 1;
+    case 2:
+        if (cop != 0) {
+            goto unrecognized;
         }
+        env->cp0.c2_base = val;
         break;
-    case 3: /* UEQ */
-        if ((flag == 0) || (flag == 2)) {
-            env->CF = 1;
+    case 3:
+        if (cop != 0) {
+            goto unrecognized;
         }
+        env->cp0.c3_faultstatus = val;
         break;
-    case 4: /* OLT */
-        if (flag == -1) {
-            env->CF = 1;
+    case 4:
+        if (cop != 0) {
+            goto unrecognized;
         }
+        env->cp0.c4_faultaddr = val;
         break;
-    case 5: /* ULT */
-        if ((flag == -1) || (flag == 2)) {
-            env->CF = 1;
+    case 5:
+        switch (cop) {
+        case 28:
+            DPRINTF("Invalidate Entire I&D cache\n");
+            return;
+        case 20:
+            DPRINTF("Invalidate Entire Icache\n");
+            return;
+        case 12:
+            DPRINTF("Invalidate Entire Dcache\n");
+            return;
+        case 10:
+            DPRINTF("Clean Entire Dcache\n");
+            return;
+        case 14:
+            DPRINTF("Flush Entire Dcache\n");
+            return;
+        case 13:
+            DPRINTF("Invalidate Dcache line\n");
+            return;
+        case 11:
+            DPRINTF("Clean Dcache line\n");
+            return;
+        case 15:
+            DPRINTF("Flush Dcache line\n");
+            return;
         }
         break;
-    case 6: /* OLE */
-        if ((flag == -1) || (flag == 0)) {
-            env->CF = 1;
-        }
-        break;
-    case 7: /* ULE */
-        if (flag != 1) {
-            env->CF = 1;
+    case 6:
+        if ((cop <= 6) && (cop >= 2)) {
+            /* invalid all tlb */
+            tlb_flush(env, 1);
+            return;
         }
         break;
+    default:
+        goto unrecognized;
     }
-    env->ucf64.xregs[UC32_UCF64_FPSCR] = (env->CF << 29)
-                    | (env->ucf64.xregs[UC32_UCF64_FPSCR] & 0x0fffffff);
-}
-
-void HELPER(ucf64_cmpd)(float64 a, float64 b, uint32_t c, CPUUniCore32State *env)
-{
-    int flag;
-    flag = float64_compare_quiet(a, b, &env->ucf64.fp_status);
-    env->CF = 0;
-    switch (c & 0x7) {
-    case 0: /* F */
-        break;
-    case 1: /* UN */
-        if (flag == 2) {
-            env->CF = 1;
-        }
-        break;
-    case 2: /* EQ */
-        if (flag == 0) {
-            env->CF = 1;
-        }
-        break;
-    case 3: /* UEQ */
-        if ((flag == 0) || (flag == 2)) {
-            env->CF = 1;
+    return;
+unrecognized:
+    DPRINTF("Wrong register (%d) or wrong operation (%d) in cp0_set!\n",
+            creg, cop);
+}
+
+uint32_t helper_cp0_get(CPUUniCore32State *env, uint32_t creg, uint32_t cop)
+{
+    /*
+     * movc rd, pp.nn, #imm9
+     *      rd: UCOP_REG_D
+     *      nn: UCOP_REG_N
+     *          0: cpuid and cachetype
+     *          1: sys control reg.
+     *          2: page table base reg.
+     *          3: data fault status reg.
+     *          4: insn fault status reg.
+     *      imm9: split UCOP_IMM10 with bit5 is 0
+     */
+    switch (creg) {
+    case 0:
+        switch (cop) {
+        case 0:
+            return env->cp0.c0_cpuid;
+        case 1:
+            return env->cp0.c0_cachetype;
         }
         break;
-    case 4: /* OLT */
-        if (flag == -1) {
-            env->CF = 1;
+    case 1:
+        if (cop == 0) {
+            return env->cp0.c1_sys;
         }
         break;
-    case 5: /* ULT */
-        if ((flag == -1) || (flag == 2)) {
-            env->CF = 1;
+    case 2:
+        if (cop == 0) {
+            return env->cp0.c2_base;
         }
         break;
-    case 6: /* OLE */
-        if ((flag == -1) || (flag == 0)) {
-            env->CF = 1;
+    case 3:
+        if (cop == 0) {
+            return env->cp0.c3_faultstatus;
         }
         break;
-    case 7: /* ULE */
-        if (flag != 1) {
-            env->CF = 1;
+    case 4:
+        if (cop == 0) {
+            return env->cp0.c4_faultaddr;
         }
         break;
     }
-    env->ucf64.xregs[UC32_UCF64_FPSCR] = (env->CF << 29)
-                    | (env->ucf64.xregs[UC32_UCF64_FPSCR] & 0x0fffffff);
-}
-
-/* Helper routines to perform bitwise copies between float and int.  */
-static inline float32 ucf64_itos(uint32_t i)
-{
-    union {
-        uint32_t i;
-        float32 s;
-    } v;
-
-    v.i = i;
-    return v.s;
-}
-
-static inline uint32_t ucf64_stoi(float32 s)
-{
-    union {
-        uint32_t i;
-        float32 s;
-    } v;
-
-    v.s = s;
-    return v.i;
-}
-
-static inline float64 ucf64_itod(uint64_t i)
-{
-    union {
-        uint64_t i;
-        float64 d;
-    } v;
-
-    v.i = i;
-    return v.d;
+    DPRINTF("Wrong register (%d) or wrong operation (%d) in cp0_set!\n",
+            creg, cop);
+    return 0;
 }
 
-static inline uint64_t ucf64_dtoi(float64 d)
+#ifdef CONFIG_CURSES
+/*
+ * FIXME:
+ *     1. curses windows will be blank when switching back
+ *     2. backspace is not handled yet
+ */
+static void putc_on_screen(unsigned char ch)
 {
-    union {
-        uint64_t i;
-        float64 d;
-    } v;
+    static WINDOW *localwin;
+    static int init;
 
-    v.d = d;
-    return v.i;
-}
+    if (!init) {
+        /* Assume 80 * 30 screen to minimize the implementation */
+        localwin = newwin(30, 80, 0, 0);
+        scrollok(localwin, TRUE);
+        init = TRUE;
+    }
 
-/* Integer to float conversion.  */
-float32 HELPER(ucf64_si2sf)(float32 x, CPUUniCore32State *env)
-{
-    return int32_to_float32(ucf64_stoi(x), &env->ucf64.fp_status);
-}
+    if (isprint(ch)) {
+        wprintw(localwin, "%c", ch);
+    } else {
+        switch (ch) {
+        case '\n':
+            wprintw(localwin, "%c", ch);
+            break;
+        case '\r':
+            /* If '\r' is put before '\n', the curses window will destroy the
+             * last print line. And meanwhile, '\n' implifies '\r' inside. */
+            break;
+        default: /* Not handled, so just print it hex code */
+            wprintw(localwin, "-- 0x%x --", ch);
+        }
+    }
 
-float64 HELPER(ucf64_si2df)(float32 x, CPUUniCore32State *env)
-{
-    return int32_to_float64(ucf64_stoi(x), &env->ucf64.fp_status);
+    wrefresh(localwin);
 }
+#else
+#define putc_on_screen(c)               do { } while (0)
+#endif
 
-/* Float to integer conversion.  */
-float32 HELPER(ucf64_sf2si)(float32 x, CPUUniCore32State *env)
+void helper_cp1_putc(target_ulong x)
 {
-    return ucf64_itos(float32_to_int32(x, &env->ucf64.fp_status));
+    putc_on_screen((unsigned char)x);   /* Output to screen */
+    DPRINTF("%c", x);                   /* Output to stdout */
 }
+#endif
 
-float32 HELPER(ucf64_df2si)(float64 x, CPUUniCore32State *env)
+#ifdef CONFIG_USER_ONLY
+void switch_mode(CPUUniCore32State *env, int mode)
 {
-    return ucf64_itos(float64_to_int32(x, &env->ucf64.fp_status));
+    if (mode != ASR_MODE_USER) {
+        cpu_abort(env, "Tried to switch out of user mode\n");
+    }
 }
 
-/* floating point conversion */
-float64 HELPER(ucf64_sf2df)(float32 x, CPUUniCore32State *env)
+void do_interrupt(CPUUniCore32State *env)
 {
-    return float32_to_float64(x, &env->ucf64.fp_status);
+    cpu_abort(env, "NO interrupt in user mode\n");
 }
 
-float32 HELPER(ucf64_df2sf)(float64 x, CPUUniCore32State *env)
+int uc32_cpu_handle_mmu_fault(CPUUniCore32State *env, target_ulong address,
+                              int access_type, int mmu_idx)
 {
-    return float64_to_float32(x, &env->ucf64.fp_status);
+    cpu_abort(env, "NO mmu fault in user mode\n");
+    return 1;
 }
+#endif
diff --git a/target-unicore32/helper.h b/target-unicore32/helper.h
index 5a3b8a41ea..305318ae59 100644
--- a/target-unicore32/helper.h
+++ b/target-unicore32/helper.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010-2011 GUAN Xue-tao
+ * Copyright (C) 2010-2012 Guan Xuetao
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -8,6 +8,12 @@
  */
 #include "def-helper.h"
 
+#ifndef CONFIG_USER_ONLY
+DEF_HELPER_4(cp0_set, void, env, i32, i32, i32)
+DEF_HELPER_3(cp0_get, i32, env, i32, i32)
+DEF_HELPER_1(cp1_putc, void, i32)
+#endif
+
 DEF_HELPER_1(clz, i32, i32)
 DEF_HELPER_1(clo, i32, i32)
 
@@ -16,12 +22,6 @@ DEF_HELPER_1(exception, void, i32)
 DEF_HELPER_2(asr_write, void, i32, i32)
 DEF_HELPER_0(asr_read, i32)
 
-DEF_HELPER_3(set_cp0, void, env, i32, i32)
-DEF_HELPER_2(get_cp0, i32, env, i32)
-
-DEF_HELPER_3(set_cp, void, env, i32, i32)
-DEF_HELPER_2(get_cp, i32, env, i32)
-
 DEF_HELPER_1(get_user_reg, i32, i32)
 DEF_HELPER_2(set_user_reg, void, i32, i32)
 
@@ -38,9 +38,6 @@ DEF_HELPER_2(shr_cc, i32, i32, i32)
 DEF_HELPER_2(sar_cc, i32, i32, i32)
 DEF_HELPER_2(ror_cc, i32, i32, i32)
 
-DEF_HELPER_2(get_r29_banked, i32, env, i32)
-DEF_HELPER_3(set_r29_banked, void, env, i32, i32)
-
 DEF_HELPER_1(ucf64_get_fpscr, i32, env)
 DEF_HELPER_2(ucf64_set_fpscr, void, env, i32)
 
diff --git a/target-unicore32/machine.c b/target-unicore32/machine.c
new file mode 100644
index 0000000000..60b2ec1771
--- /dev/null
+++ b/target-unicore32/machine.c
@@ -0,0 +1,23 @@
+/*
+ * Generic machine functions for UniCore32 ISA
+ *
+ * Copyright (C) 2010-2012 Guan Xuetao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or any later version.
+ * See the COPYING file in the top-level directory.
+ */
+#include "hw/hw.h"
+
+void cpu_save(QEMUFile *f, void *opaque)
+{
+    hw_error("%s not supported yet.\n", __func__);
+}
+
+int cpu_load(QEMUFile *f, void *opaque, int version_id)
+{
+    hw_error("%s not supported yet.\n", __func__);
+
+    return 0;
+}
diff --git a/target-unicore32/op_helper.c b/target-unicore32/op_helper.c
index b954c30a84..c63789d6cb 100644
--- a/target-unicore32/op_helper.c
+++ b/target-unicore32/op_helper.c
@@ -1,7 +1,7 @@
 /*
  *  UniCore32 helper routines
  *
- * Copyright (C) 2010-2011 GUAN Xue-tao
+ * Copyright (C) 2010-2012 Guan Xuetao
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -248,3 +248,45 @@ uint32_t HELPER(ror_cc)(uint32_t x, uint32_t i)
         return ((uint32_t)x >> shift) | (x << (32 - shift));
     }
 }
+
+#ifndef CONFIG_USER_ONLY
+#define MMUSUFFIX _mmu
+
+#define SHIFT 0
+#include "softmmu_template.h"
+
+#define SHIFT 1
+#include "softmmu_template.h"
+
+#define SHIFT 2
+#include "softmmu_template.h"
+
+#define SHIFT 3
+#include "softmmu_template.h"
+
+void tlb_fill(CPUUniCore32State *env1, target_ulong addr, int is_write,
+        int mmu_idx, uintptr_t retaddr)
+{
+    TranslationBlock *tb;
+    CPUUniCore32State *saved_env;
+    unsigned long pc;
+    int ret;
+
+    saved_env = env;
+    env = env1;
+    ret = uc32_cpu_handle_mmu_fault(env, addr, is_write, mmu_idx);
+    if (unlikely(ret)) {
+        if (retaddr) {
+            /* now we have a real cpu fault */
+            pc = (unsigned long)retaddr;
+            tb = tb_find_pc(pc);
+            if (tb) {/* the PC is inside the translated code.
+                        It means that we have a virtual CPU fault */
+                cpu_restore_state(tb, env, pc);
+            }
+        }
+        cpu_loop_exit(env);
+    }
+    env = saved_env;
+}
+#endif
diff --git a/target-unicore32/softmmu.c b/target-unicore32/softmmu.c
new file mode 100644
index 0000000000..373f94b274
--- /dev/null
+++ b/target-unicore32/softmmu.c
@@ -0,0 +1,267 @@
+/*
+ * Softmmu related functions
+ *
+ * Copyright (C) 2010-2012 Guan Xuetao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or any later version.
+ * See the COPYING file in the top-level directory.
+ */
+#ifdef CONFIG_USER_ONLY
+#error This file only exist under softmmu circumstance
+#endif
+
+#include <cpu.h>
+
+#undef DEBUG_UC32
+
+#ifdef DEBUG_UC32
+#define DPRINTF(fmt, ...) printf("%s: " fmt , __func__, ## __VA_ARGS__)
+#else
+#define DPRINTF(fmt, ...) do {} while (0)
+#endif
+
+#define SUPERPAGE_SIZE             (1 << 22)
+#define UC32_PAGETABLE_READ        (1 << 8)
+#define UC32_PAGETABLE_WRITE       (1 << 7)
+#define UC32_PAGETABLE_EXEC        (1 << 6)
+#define UC32_PAGETABLE_EXIST       (1 << 2)
+#define PAGETABLE_TYPE(x)          ((x) & 3)
+
+
+/* Map CPU modes onto saved register banks.  */
+static inline int bank_number(int mode)
+{
+    switch (mode) {
+    case ASR_MODE_USER:
+    case ASR_MODE_SUSR:
+        return 0;
+    case ASR_MODE_PRIV:
+        return 1;
+    case ASR_MODE_TRAP:
+        return 2;
+    case ASR_MODE_EXTN:
+        return 3;
+    case ASR_MODE_INTR:
+        return 4;
+    }
+    cpu_abort(cpu_single_env, "Bad mode %x\n", mode);
+    return -1;
+}
+
+void switch_mode(CPUUniCore32State *env, int mode)
+{
+    int old_mode;
+    int i;
+
+    old_mode = env->uncached_asr & ASR_M;
+    if (mode == old_mode) {
+        return;
+    }
+
+    i = bank_number(old_mode);
+    env->banked_r29[i] = env->regs[29];
+    env->banked_r30[i] = env->regs[30];
+    env->banked_bsr[i] = env->bsr;
+
+    i = bank_number(mode);
+    env->regs[29] = env->banked_r29[i];
+    env->regs[30] = env->banked_r30[i];
+    env->bsr = env->banked_bsr[i];
+}
+
+/* Handle a CPU exception.  */
+void do_interrupt(CPUUniCore32State *env)
+{
+    uint32_t addr;
+    int new_mode;
+
+    switch (env->exception_index) {
+    case UC32_EXCP_PRIV:
+        new_mode = ASR_MODE_PRIV;
+        addr = 0x08;
+        break;
+    case UC32_EXCP_ITRAP:
+        DPRINTF("itrap happened at %x\n", env->regs[31]);
+        new_mode = ASR_MODE_TRAP;
+        addr = 0x0c;
+        break;
+    case UC32_EXCP_DTRAP:
+        DPRINTF("dtrap happened at %x\n", env->regs[31]);
+        new_mode = ASR_MODE_TRAP;
+        addr = 0x10;
+        break;
+    case UC32_EXCP_INTR:
+        new_mode = ASR_MODE_INTR;
+        addr = 0x18;
+        break;
+    default:
+        cpu_abort(env, "Unhandled exception 0x%x\n", env->exception_index);
+        return;
+    }
+    /* High vectors.  */
+    if (env->cp0.c1_sys & (1 << 13)) {
+        addr += 0xffff0000;
+    }
+
+    switch_mode(env, new_mode);
+    env->bsr = cpu_asr_read(env);
+    env->uncached_asr = (env->uncached_asr & ~ASR_M) | new_mode;
+    env->uncached_asr |= ASR_I;
+    /* The PC already points to the proper instruction.  */
+    env->regs[30] = env->regs[31];
+    env->regs[31] = addr;
+    env->interrupt_request |= CPU_INTERRUPT_EXITTB;
+}
+
+static int get_phys_addr_ucv2(CPUUniCore32State *env, uint32_t address,
+        int access_type, int is_user, uint32_t *phys_ptr, int *prot,
+        target_ulong *page_size)
+{
+    int code;
+    uint32_t table;
+    uint32_t desc;
+    uint32_t phys_addr;
+
+    /* Pagetable walk.  */
+    /* Lookup l1 descriptor.  */
+    table = env->cp0.c2_base & 0xfffff000;
+    table |= (address >> 20) & 0xffc;
+    desc = ldl_phys(table);
+    code = 0;
+    switch (PAGETABLE_TYPE(desc)) {
+    case 3:
+        /* Superpage  */
+        if (!(desc & UC32_PAGETABLE_EXIST)) {
+            code = 0x0b; /* superpage miss */
+            goto do_fault;
+        }
+        phys_addr = (desc & 0xffc00000) | (address & 0x003fffff);
+        *page_size = SUPERPAGE_SIZE;
+        break;
+    case 0:
+        /* Lookup l2 entry.  */
+        if (is_user) {
+            DPRINTF("PGD address %x, desc %x\n", table, desc);
+        }
+        if (!(desc & UC32_PAGETABLE_EXIST)) {
+            code = 0x05; /* second pagetable miss */
+            goto do_fault;
+        }
+        table = (desc & 0xfffff000) | ((address >> 10) & 0xffc);
+        desc = ldl_phys(table);
+        /* 4k page.  */
+        if (is_user) {
+            DPRINTF("PTE address %x, desc %x\n", table, desc);
+        }
+        if (!(desc & UC32_PAGETABLE_EXIST)) {
+            code = 0x08; /* page miss */
+            goto do_fault;
+        }
+        switch (PAGETABLE_TYPE(desc)) {
+        case 0:
+            phys_addr = (desc & 0xfffff000) | (address & 0xfff);
+            *page_size = TARGET_PAGE_SIZE;
+            break;
+        default:
+            cpu_abort(env, "wrong page type!");
+        }
+        break;
+    default:
+        cpu_abort(env, "wrong page type!");
+    }
+
+    *phys_ptr = phys_addr;
+    *prot = 0;
+    /* Check access permissions.  */
+    if (desc & UC32_PAGETABLE_READ) {
+        *prot |= PAGE_READ;
+    } else {
+        if (is_user && (access_type == 0)) {
+            code = 0x11; /* access unreadable area */
+            goto do_fault;
+        }
+    }
+
+    if (desc & UC32_PAGETABLE_WRITE) {
+        *prot |= PAGE_WRITE;
+    } else {
+        if (is_user && (access_type == 1)) {
+            code = 0x12; /* access unwritable area */
+            goto do_fault;
+        }
+    }
+
+    if (desc & UC32_PAGETABLE_EXEC) {
+        *prot |= PAGE_EXEC;
+    } else {
+        if (is_user && (access_type == 2)) {
+            code = 0x13; /* access unexecutable area */
+            goto do_fault;
+        }
+    }
+
+do_fault:
+    return code;
+}
+
+int uc32_cpu_handle_mmu_fault(CPUUniCore32State *env, target_ulong address,
+                              int access_type, int mmu_idx)
+{
+    uint32_t phys_addr;
+    target_ulong page_size;
+    int prot;
+    int ret, is_user;
+
+    ret = 1;
+    is_user = mmu_idx == MMU_USER_IDX;
+
+    if ((env->cp0.c1_sys & 1) == 0) {
+        /* MMU disabled.  */
+        phys_addr = address;
+        prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+        page_size = TARGET_PAGE_SIZE;
+        ret = 0;
+    } else {
+        if ((address & (1 << 31)) || (is_user)) {
+            ret = get_phys_addr_ucv2(env, address, access_type, is_user,
+                                    &phys_addr, &prot, &page_size);
+            if (is_user) {
+                DPRINTF("user space access: ret %x, address %x, "
+                        "access_type %x, phys_addr %x, prot %x\n",
+                        ret, address, access_type, phys_addr, prot);
+            }
+        } else {
+            /*IO memory */
+            phys_addr = address | (1 << 31);
+            prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+            page_size = TARGET_PAGE_SIZE;
+            ret = 0;
+        }
+    }
+
+    if (ret == 0) {
+        /* Map a single page.  */
+        phys_addr &= TARGET_PAGE_MASK;
+        address &= TARGET_PAGE_MASK;
+        tlb_set_page(env, address, phys_addr, prot, mmu_idx, page_size);
+        return 0;
+    }
+
+    env->cp0.c3_faultstatus = ret;
+    env->cp0.c4_faultaddr = address;
+    if (access_type == 2) {
+        env->exception_index = UC32_EXCP_ITRAP;
+    } else {
+        env->exception_index = UC32_EXCP_DTRAP;
+    }
+    return ret;
+}
+
+target_phys_addr_t cpu_get_phys_page_debug(CPUUniCore32State *env,
+        target_ulong addr)
+{
+    cpu_abort(env, "%s not supported yet\n", __func__);
+    return addr;
+}
diff --git a/target-unicore32/translate.c b/target-unicore32/translate.c
index 9793d14c1b..188bf8c52a 100644
--- a/target-unicore32/translate.c
+++ b/target-unicore32/translate.c
@@ -1,7 +1,7 @@
 /*
  *  UniCore32 translation
  *
- * Copyright (C) 2010-2011 GUAN Xue-tao
+ * Copyright (C) 2010-2012 Guan Xuetao
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -33,9 +33,16 @@ typedef struct DisasContext {
     int condlabel;
     struct TranslationBlock *tb;
     int singlestep_enabled;
+#ifndef CONFIG_USER_ONLY
+    int user;
+#endif
 } DisasContext;
 
-#define IS_USER(s) 1
+#ifndef CONFIG_USER_ONLY
+#define IS_USER(s)      (s->user)
+#else
+#define IS_USER(s)      1
+#endif
 
 /* These instructions trap after executing, so defer them until after the
    conditional executions state has been updated.  */
@@ -176,6 +183,73 @@ static void store_reg(DisasContext *s, int reg, TCGv var)
                         "Illegal UniCore32 instruction %x at line %d!", \
                         insn, __LINE__)
 
+#ifndef CONFIG_USER_ONLY
+static void disas_cp0_insn(CPUUniCore32State *env, DisasContext *s,
+        uint32_t insn)
+{
+    TCGv tmp, tmp2, tmp3;
+    if ((insn & 0xfe000000) == 0xe0000000) {
+        tmp2 = new_tmp();
+        tmp3 = new_tmp();
+        tcg_gen_movi_i32(tmp2, UCOP_REG_N);
+        tcg_gen_movi_i32(tmp3, UCOP_IMM10);
+        if (UCOP_SET_L) {
+            tmp = new_tmp();
+            gen_helper_cp0_get(tmp, cpu_env, tmp2, tmp3);
+            store_reg(s, UCOP_REG_D, tmp);
+        } else {
+            tmp = load_reg(s, UCOP_REG_D);
+            gen_helper_cp0_set(cpu_env, tmp, tmp2, tmp3);
+            dead_tmp(tmp);
+        }
+        dead_tmp(tmp2);
+        dead_tmp(tmp3);
+        return;
+    }
+    ILLEGAL;
+}
+
+static void disas_ocd_insn(CPUUniCore32State *env, DisasContext *s,
+        uint32_t insn)
+{
+    TCGv tmp;
+
+    if ((insn & 0xff003fff) == 0xe1000400) {
+        /*
+         * movc rd, pp.nn, #imm9
+         *      rd: UCOP_REG_D
+         *      nn: UCOP_REG_N (must be 0)
+         *      imm9: 0
+         */
+        if (UCOP_REG_N == 0) {
+            tmp = new_tmp();
+            tcg_gen_movi_i32(tmp, 0);
+            store_reg(s, UCOP_REG_D, tmp);
+            return;
+        } else {
+            ILLEGAL;
+        }
+    }
+    if ((insn & 0xff003fff) == 0xe0000401) {
+        /*
+         * movc pp.nn, rn, #imm9
+         *      rn: UCOP_REG_D
+         *      nn: UCOP_REG_N (must be 1)
+         *      imm9: 1
+         */
+        if (UCOP_REG_N == 1) {
+            tmp = load_reg(s, UCOP_REG_D);
+            gen_helper_cp1_putc(tmp);
+            dead_tmp(tmp);
+            return;
+        } else {
+            ILLEGAL;
+        }
+    }
+    ILLEGAL;
+}
+#endif
+
 static inline void gen_set_asr(TCGv var, uint32_t mask)
 {
     TCGv tmp_mask = tcg_const_i32(mask);
@@ -1124,9 +1198,18 @@ static void gen_exception_return(DisasContext *s, TCGv pc)
     s->is_jmp = DISAS_UPDATE;
 }
 
-static void disas_coproc_insn(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
+static void disas_coproc_insn(CPUUniCore32State *env, DisasContext *s,
+        uint32_t insn)
 {
     switch (UCOP_CPNUM) {
+#ifndef CONFIG_USER_ONLY
+    case 0:
+        disas_cp0_insn(env, s, insn);
+        break;
+    case 1:
+        disas_ocd_insn(env, s, insn);
+        break;
+#endif
     case 2:
         disas_ucf64_insn(env, s, insn);
         break;
@@ -1478,12 +1561,12 @@ static void do_misc(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
 /* load/store I_offset and R_offset */
 static void do_ldst_ir(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
 {
-    unsigned int i;
+    unsigned int mmu_idx;
     TCGv tmp;
     TCGv tmp2;
 
     tmp2 = load_reg(s, UCOP_REG_N);
-    i = (IS_USER(s) || (!UCOP_SET_P && UCOP_SET_W));
+    mmu_idx = (IS_USER(s) || (!UCOP_SET_P && UCOP_SET_W));
 
     /* immediate */
     if (UCOP_SET_P) {
@@ -1493,17 +1576,17 @@ static void do_ldst_ir(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
     if (UCOP_SET_L) {
         /* load */
         if (UCOP_SET_B) {
-            tmp = gen_ld8u(tmp2, i);
+            tmp = gen_ld8u(tmp2, mmu_idx);
         } else {
-            tmp = gen_ld32(tmp2, i);
+            tmp = gen_ld32(tmp2, mmu_idx);
         }
     } else {
         /* store */
         tmp = load_reg(s, UCOP_REG_D);
         if (UCOP_SET_B) {
-            gen_st8(tmp, tmp2, i);
+            gen_st8(tmp, tmp2, mmu_idx);
         } else {
-            gen_st32(tmp, tmp2, i);
+            gen_st32(tmp, tmp2, mmu_idx);
         }
     }
     if (!UCOP_SET_P) {
@@ -1606,7 +1689,7 @@ static void do_ldst_hwsb(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
 /* load/store multiple words */
 static void do_ldst_m(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
 {
-    unsigned int val, i;
+    unsigned int val, i, mmu_idx;
     int j, n, reg, user, loaded_base;
     TCGv tmp;
     TCGv tmp2;
@@ -1627,6 +1710,7 @@ static void do_ldst_m(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
         }
     }
 
+    mmu_idx = (IS_USER(s) || (!UCOP_SET_P && UCOP_SET_W));
     addr = load_reg(s, UCOP_REG_N);
 
     /* compute total size */
@@ -1671,7 +1755,7 @@ static void do_ldst_m(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
         }
         if (UCOP_SET(i)) {
             if (UCOP_SET_L) { /* load */
-                tmp = gen_ld32(addr, IS_USER(s));
+                tmp = gen_ld32(addr, mmu_idx);
                 if (reg == 31) {
                     gen_bx(s, tmp);
                 } else if (user) {
@@ -1699,7 +1783,7 @@ static void do_ldst_m(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
                 } else {
                     tmp = load_reg(s, reg);
                 }
-                gen_st32(tmp, addr, IS_USER(s));
+                gen_st32(tmp, addr, mmu_idx);
             }
             j++;
             /* no need to add after the last transfer */
@@ -1888,6 +1972,14 @@ static inline void gen_intermediate_code_internal(CPUUniCore32State *env,
         max_insns = CF_COUNT_MASK;
     }
 
+#ifndef CONFIG_USER_ONLY
+    if ((env->uncached_asr & ASR_M) == ASR_MODE_USER) {
+        dc->user = 1;
+    } else {
+        dc->user = 0;
+    }
+#endif
+
     gen_icount_start();
     do {
         if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
@@ -2046,12 +2138,12 @@ static const char *cpu_mode_names[16] = {
     "UM18", "UM19", "UM1A", "EXTN", "UM1C", "UM1D", "UM1E", "SUSR"
 };
 
-#define UCF64_DUMP_STATE
-void cpu_dump_state(CPUUniCore32State *env, FILE *f, fprintf_function cpu_fprintf,
-        int flags)
+#undef UCF64_DUMP_STATE
+#ifdef UCF64_DUMP_STATE
+static void cpu_dump_state_ucf64(CPUUniCore32State *env, FILE *f,
+        fprintf_function cpu_fprintf, int flags)
 {
     int i;
-#ifdef UCF64_DUMP_STATE
     union {
         uint32_t i;
         float s;
@@ -2063,7 +2155,28 @@ void cpu_dump_state(CPUUniCore32State *env, FILE *f, fprintf_function cpu_fprint
         float64 f64;
         double d;
     } d0;
+
+    for (i = 0; i < 16; i++) {
+        d.d = env->ucf64.regs[i];
+        s0.i = d.l.lower;
+        s1.i = d.l.upper;
+        d0.f64 = d.d;
+        cpu_fprintf(f, "s%02d=%08x(%8g) s%02d=%08x(%8g)",
+                    i * 2, (int)s0.i, s0.s,
+                    i * 2 + 1, (int)s1.i, s1.s);
+        cpu_fprintf(f, " d%02d=%" PRIx64 "(%8g)\n",
+                    i, (uint64_t)d0.f64, d0.d);
+    }
+    cpu_fprintf(f, "FPSCR: %08x\n", (int)env->ucf64.xregs[UC32_UCF64_FPSCR]);
+}
+#else
+#define cpu_dump_state_ucf64(env, file, pr, flags)      do { } while (0)
 #endif
+
+void cpu_dump_state(CPUUniCore32State *env, FILE *f,
+        fprintf_function cpu_fprintf, int flags)
+{
+    int i;
     uint32_t psr;
 
     for (i = 0; i < 32; i++) {
@@ -2083,19 +2196,7 @@ void cpu_dump_state(CPUUniCore32State *env, FILE *f, fprintf_function cpu_fprint
                 psr & (1 << 28) ? 'V' : '-',
                 cpu_mode_names[psr & 0xf]);
 
-#ifdef UCF64_DUMP_STATE
-    for (i = 0; i < 16; i++) {
-        d.d = env->ucf64.regs[i];
-        s0.i = d.l.lower;
-        s1.i = d.l.upper;
-        d0.f64 = d.d;
-        cpu_fprintf(f, "s%02d=%08x(%8g) s%02d=%08x(%8g) d%02d=%" PRIx64 "(%8g)\n",
-                    i * 2, (int)s0.i, s0.s,
-                    i * 2 + 1, (int)s1.i, s1.s,
-                    i, (uint64_t)d0.f64, d0.d);
-    }
-    cpu_fprintf(f, "FPSCR: %08x\n", (int)env->ucf64.xregs[UC32_UCF64_FPSCR]);
-#endif
+    cpu_dump_state_ucf64(env, f, cpu_fprintf, flags);
 }
 
 void restore_state_to_opc(CPUUniCore32State *env, TranslationBlock *tb, int pc_pos)
diff --git a/target-unicore32/ucf64_helper.c b/target-unicore32/ucf64_helper.c
new file mode 100644
index 0000000000..a516edd319
--- /dev/null
+++ b/target-unicore32/ucf64_helper.c
@@ -0,0 +1,345 @@
+/*
+ * UniCore-F64 simulation helpers for QEMU.
+ *
+ * Copyright (C) 2010-2012 Guan Xuetao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or any later version.
+ * See the COPYING file in the top-level directory.
+ */
+#include "cpu.h"
+#include "helper.h"
+
+/*
+ * The convention used for UniCore-F64 instructions:
+ *  Single precition routines have a "s" suffix
+ *  Double precision routines have a "d" suffix.
+ */
+
+/* Convert host exception flags to f64 form.  */
+static inline int ucf64_exceptbits_from_host(int host_bits)
+{
+    int target_bits = 0;
+
+    if (host_bits & float_flag_invalid) {
+        target_bits |= UCF64_FPSCR_FLAG_INVALID;
+    }
+    if (host_bits & float_flag_divbyzero) {
+        target_bits |= UCF64_FPSCR_FLAG_DIVZERO;
+    }
+    if (host_bits & float_flag_overflow) {
+        target_bits |= UCF64_FPSCR_FLAG_OVERFLOW;
+    }
+    if (host_bits & float_flag_underflow) {
+        target_bits |= UCF64_FPSCR_FLAG_UNDERFLOW;
+    }
+    if (host_bits & float_flag_inexact) {
+        target_bits |= UCF64_FPSCR_FLAG_INEXACT;
+    }
+    return target_bits;
+}
+
+uint32_t HELPER(ucf64_get_fpscr)(CPUUniCore32State *env)
+{
+    int i;
+    uint32_t fpscr;
+
+    fpscr = (env->ucf64.xregs[UC32_UCF64_FPSCR] & UCF64_FPSCR_MASK);
+    i = get_float_exception_flags(&env->ucf64.fp_status);
+    fpscr |= ucf64_exceptbits_from_host(i);
+    return fpscr;
+}
+
+/* Convert ucf64 exception flags to target form.  */
+static inline int ucf64_exceptbits_to_host(int target_bits)
+{
+    int host_bits = 0;
+
+    if (target_bits & UCF64_FPSCR_FLAG_INVALID) {
+        host_bits |= float_flag_invalid;
+    }
+    if (target_bits & UCF64_FPSCR_FLAG_DIVZERO) {
+        host_bits |= float_flag_divbyzero;
+    }
+    if (target_bits & UCF64_FPSCR_FLAG_OVERFLOW) {
+        host_bits |= float_flag_overflow;
+    }
+    if (target_bits & UCF64_FPSCR_FLAG_UNDERFLOW) {
+        host_bits |= float_flag_underflow;
+    }
+    if (target_bits & UCF64_FPSCR_FLAG_INEXACT) {
+        host_bits |= float_flag_inexact;
+    }
+    return host_bits;
+}
+
+void HELPER(ucf64_set_fpscr)(CPUUniCore32State *env, uint32_t val)
+{
+    int i;
+    uint32_t changed;
+
+    changed = env->ucf64.xregs[UC32_UCF64_FPSCR];
+    env->ucf64.xregs[UC32_UCF64_FPSCR] = (val & UCF64_FPSCR_MASK);
+
+    changed ^= val;
+    if (changed & (UCF64_FPSCR_RND_MASK)) {
+        i = UCF64_FPSCR_RND(val);
+        switch (i) {
+        case 0:
+            i = float_round_nearest_even;
+            break;
+        case 1:
+            i = float_round_to_zero;
+            break;
+        case 2:
+            i = float_round_up;
+            break;
+        case 3:
+            i = float_round_down;
+            break;
+        default: /* 100 and 101 not implement */
+            cpu_abort(env, "Unsupported UniCore-F64 round mode");
+        }
+        set_float_rounding_mode(i, &env->ucf64.fp_status);
+    }
+
+    i = ucf64_exceptbits_to_host(UCF64_FPSCR_TRAPEN(val));
+    set_float_exception_flags(i, &env->ucf64.fp_status);
+}
+
+float32 HELPER(ucf64_adds)(float32 a, float32 b, CPUUniCore32State *env)
+{
+    return float32_add(a, b, &env->ucf64.fp_status);
+}
+
+float64 HELPER(ucf64_addd)(float64 a, float64 b, CPUUniCore32State *env)
+{
+    return float64_add(a, b, &env->ucf64.fp_status);
+}
+
+float32 HELPER(ucf64_subs)(float32 a, float32 b, CPUUniCore32State *env)
+{
+    return float32_sub(a, b, &env->ucf64.fp_status);
+}
+
+float64 HELPER(ucf64_subd)(float64 a, float64 b, CPUUniCore32State *env)
+{
+    return float64_sub(a, b, &env->ucf64.fp_status);
+}
+
+float32 HELPER(ucf64_muls)(float32 a, float32 b, CPUUniCore32State *env)
+{
+    return float32_mul(a, b, &env->ucf64.fp_status);
+}
+
+float64 HELPER(ucf64_muld)(float64 a, float64 b, CPUUniCore32State *env)
+{
+    return float64_mul(a, b, &env->ucf64.fp_status);
+}
+
+float32 HELPER(ucf64_divs)(float32 a, float32 b, CPUUniCore32State *env)
+{
+    return float32_div(a, b, &env->ucf64.fp_status);
+}
+
+float64 HELPER(ucf64_divd)(float64 a, float64 b, CPUUniCore32State *env)
+{
+    return float64_div(a, b, &env->ucf64.fp_status);
+}
+
+float32 HELPER(ucf64_negs)(float32 a)
+{
+    return float32_chs(a);
+}
+
+float64 HELPER(ucf64_negd)(float64 a)
+{
+    return float64_chs(a);
+}
+
+float32 HELPER(ucf64_abss)(float32 a)
+{
+    return float32_abs(a);
+}
+
+float64 HELPER(ucf64_absd)(float64 a)
+{
+    return float64_abs(a);
+}
+
+void HELPER(ucf64_cmps)(float32 a, float32 b, uint32_t c,
+        CPUUniCore32State *env)
+{
+    int flag;
+    flag = float32_compare_quiet(a, b, &env->ucf64.fp_status);
+    env->CF = 0;
+    switch (c & 0x7) {
+    case 0: /* F */
+        break;
+    case 1: /* UN */
+        if (flag == 2) {
+            env->CF = 1;
+        }
+        break;
+    case 2: /* EQ */
+        if (flag == 0) {
+            env->CF = 1;
+        }
+        break;
+    case 3: /* UEQ */
+        if ((flag == 0) || (flag == 2)) {
+            env->CF = 1;
+        }
+        break;
+    case 4: /* OLT */
+        if (flag == -1) {
+            env->CF = 1;
+        }
+        break;
+    case 5: /* ULT */
+        if ((flag == -1) || (flag == 2)) {
+            env->CF = 1;
+        }
+        break;
+    case 6: /* OLE */
+        if ((flag == -1) || (flag == 0)) {
+            env->CF = 1;
+        }
+        break;
+    case 7: /* ULE */
+        if (flag != 1) {
+            env->CF = 1;
+        }
+        break;
+    }
+    env->ucf64.xregs[UC32_UCF64_FPSCR] = (env->CF << 29)
+                    | (env->ucf64.xregs[UC32_UCF64_FPSCR] & 0x0fffffff);
+}
+
+void HELPER(ucf64_cmpd)(float64 a, float64 b, uint32_t c,
+        CPUUniCore32State *env)
+{
+    int flag;
+    flag = float64_compare_quiet(a, b, &env->ucf64.fp_status);
+    env->CF = 0;
+    switch (c & 0x7) {
+    case 0: /* F */
+        break;
+    case 1: /* UN */
+        if (flag == 2) {
+            env->CF = 1;
+        }
+        break;
+    case 2: /* EQ */
+        if (flag == 0) {
+            env->CF = 1;
+        }
+        break;
+    case 3: /* UEQ */
+        if ((flag == 0) || (flag == 2)) {
+            env->CF = 1;
+        }
+        break;
+    case 4: /* OLT */
+        if (flag == -1) {
+            env->CF = 1;
+        }
+        break;
+    case 5: /* ULT */
+        if ((flag == -1) || (flag == 2)) {
+            env->CF = 1;
+        }
+        break;
+    case 6: /* OLE */
+        if ((flag == -1) || (flag == 0)) {
+            env->CF = 1;
+        }
+        break;
+    case 7: /* ULE */
+        if (flag != 1) {
+            env->CF = 1;
+        }
+        break;
+    }
+    env->ucf64.xregs[UC32_UCF64_FPSCR] = (env->CF << 29)
+                    | (env->ucf64.xregs[UC32_UCF64_FPSCR] & 0x0fffffff);
+}
+
+/* Helper routines to perform bitwise copies between float and int.  */
+static inline float32 ucf64_itos(uint32_t i)
+{
+    union {
+        uint32_t i;
+        float32 s;
+    } v;
+
+    v.i = i;
+    return v.s;
+}
+
+static inline uint32_t ucf64_stoi(float32 s)
+{
+    union {
+        uint32_t i;
+        float32 s;
+    } v;
+
+    v.s = s;
+    return v.i;
+}
+
+static inline float64 ucf64_itod(uint64_t i)
+{
+    union {
+        uint64_t i;
+        float64 d;
+    } v;
+
+    v.i = i;
+    return v.d;
+}
+
+static inline uint64_t ucf64_dtoi(float64 d)
+{
+    union {
+        uint64_t i;
+        float64 d;
+    } v;
+
+    v.d = d;
+    return v.i;
+}
+
+/* Integer to float conversion.  */
+float32 HELPER(ucf64_si2sf)(float32 x, CPUUniCore32State *env)
+{
+    return int32_to_float32(ucf64_stoi(x), &env->ucf64.fp_status);
+}
+
+float64 HELPER(ucf64_si2df)(float32 x, CPUUniCore32State *env)
+{
+    return int32_to_float64(ucf64_stoi(x), &env->ucf64.fp_status);
+}
+
+/* Float to integer conversion.  */
+float32 HELPER(ucf64_sf2si)(float32 x, CPUUniCore32State *env)
+{
+    return ucf64_itos(float32_to_int32(x, &env->ucf64.fp_status));
+}
+
+float32 HELPER(ucf64_df2si)(float64 x, CPUUniCore32State *env)
+{
+    return ucf64_itos(float64_to_int32(x, &env->ucf64.fp_status));
+}
+
+/* floating point conversion */
+float64 HELPER(ucf64_sf2df)(float32 x, CPUUniCore32State *env)
+{
+    return float32_to_float64(x, &env->ucf64.fp_status);
+}
+
+float32 HELPER(ucf64_df2sf)(float64 x, CPUUniCore32State *env)
+{
+    return float64_to_float32(x, &env->ucf64.fp_status);
+}
diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h
index f7db116400..177094ae9a 100644
--- a/target-xtensa/cpu.h
+++ b/target-xtensa/cpu.h
@@ -351,6 +351,12 @@ typedef struct CPUXtensaState {
 #define cpu_signal_handler cpu_xtensa_signal_handler
 #define cpu_list xtensa_cpu_list
 
+#ifdef TARGET_WORDS_BIGENDIAN
+#define XTENSA_DEFAULT_CPU_MODEL "fsf"
+#else
+#define XTENSA_DEFAULT_CPU_MODEL "dc232b"
+#endif
+
 XtensaCPU *cpu_xtensa_init(const char *cpu_model);
 
 static inline CPUXtensaState *cpu_init(const char *cpu_model)
diff --git a/target-xtensa/helper.c b/target-xtensa/helper.c
index 044ce18364..d5bb171fcd 100644
--- a/target-xtensa/helper.c
+++ b/target-xtensa/helper.c
@@ -54,8 +54,6 @@ static uint32_t check_hw_breakpoints(CPUXtensaState *env)
     return 0;
 }
 
-static CPUDebugExcpHandler *prev_debug_excp_handler;
-
 static void breakpoint_handler(CPUXtensaState *env)
 {
     if (env->watchpoint_hit) {
@@ -70,9 +68,6 @@ static void breakpoint_handler(CPUXtensaState *env)
             cpu_resume_from_signal(env, NULL);
         }
     }
-    if (prev_debug_excp_handler) {
-        prev_debug_excp_handler(env);
-    }
 }
 
 XtensaCPU *cpu_xtensa_init(const char *cpu_model)
@@ -105,8 +100,7 @@ XtensaCPU *cpu_xtensa_init(const char *cpu_model)
 
     if (!debug_handler_inited && tcg_enabled()) {
         debug_handler_inited = 1;
-        prev_debug_excp_handler =
-            cpu_set_debug_excp_handler(breakpoint_handler);
+        cpu_set_debug_excp_handler(breakpoint_handler);
     }
 
     xtensa_irq_init(env);
diff --git a/tests/qemu-iotests/031.out b/tests/qemu-iotests/031.out
index d3cab301d4..796c993df2 100644
--- a/tests/qemu-iotests/031.out
+++ b/tests/qemu-iotests/031.out
@@ -54,8 +54,8 @@ header_length             72
 
 Header extension:
 magic                     0x6803f857
-length                    0
-data                      ''
+length                    96
+data                      <binary>
 
 Header extension:
 magic                     0x12345678
@@ -68,7 +68,7 @@ No errors were found on the image.
 
 magic                     0x514649fb
 version                   2
-backing_file_offset       0x98
+backing_file_offset       0xf8
 backing_file_size         0x17
 cluster_bits              16
 size                      67108864
@@ -92,8 +92,8 @@ data                      'host_device'
 
 Header extension:
 magic                     0x6803f857
-length                    0
-data                      ''
+length                    96
+data                      <binary>
 
 Header extension:
 magic                     0x12345678
@@ -155,8 +155,8 @@ header_length             104
 
 Header extension:
 magic                     0x6803f857
-length                    0
-data                      ''
+length                    96
+data                      <binary>
 
 Header extension:
 magic                     0x12345678
@@ -169,7 +169,7 @@ No errors were found on the image.
 
 magic                     0x514649fb
 version                   3
-backing_file_offset       0xb8
+backing_file_offset       0x118
 backing_file_size         0x17
 cluster_bits              16
 size                      67108864
@@ -193,8 +193,8 @@ data                      'host_device'
 
 Header extension:
 magic                     0x6803f857
-length                    0
-data                      ''
+length                    96
+data                      <binary>
 
 Header extension:
 magic                     0x12345678
diff --git a/tests/qemu-iotests/036.out b/tests/qemu-iotests/036.out
index 6953e37ab6..063ca22d66 100644
--- a/tests/qemu-iotests/036.out
+++ b/tests/qemu-iotests/036.out
@@ -46,7 +46,7 @@ header_length             104
 
 Header extension:
 magic                     0x6803f857
-length                    0
-data                      ''
+length                    96
+data                      <binary>
 
 *** done
diff --git a/tests/qemu-iotests/039 b/tests/qemu-iotests/039
new file mode 100755
index 0000000000..c5ae806ecb
--- /dev/null
+++ b/tests/qemu-iotests/039
@@ -0,0 +1,137 @@
+#!/bin/bash
+#
+# Test qcow2 lazy refcounts
+#
+# Copyright (C) 2012 Red Hat, Inc.
+# Copyright IBM, Corp. 2010
+#
+# Based on test 038.
+#
+# 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=stefanha@linux.vnet.ibm.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 generic
+_supported_os Linux
+_unsupported_qemu_io_options --nocache
+
+size=128M
+
+echo
+echo "== Checking that image is clean on shutdown =="
+
+IMGOPTS="compat=1.1,lazy_refcounts=on"
+_make_test_img $size
+
+$QEMU_IO -c "write -P 0x5a 0 512" $TEST_IMG | _filter_qemu_io
+
+# The dirty bit must not be set
+./qcow2.py $TEST_IMG dump-header | grep incompatible_features
+_check_test_img
+
+echo
+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"
+
+# The dirty bit must be set
+./qcow2.py $TEST_IMG dump-header | grep incompatible_features
+_check_test_img
+
+echo
+echo "== Read-only access must still work =="
+
+$QEMU_IO -r -c "read -P 0x5a 0 512" $TEST_IMG | _filter_qemu_io
+
+# The dirty bit must be set
+./qcow2.py $TEST_IMG dump-header | grep incompatible_features
+
+echo
+echo "== Repairing the image file must succeed =="
+
+$QEMU_IMG check -r all $TEST_IMG
+
+# The dirty bit must not be set
+./qcow2.py $TEST_IMG dump-header | grep incompatible_features
+
+echo
+echo "== Data should still be accessible after repair =="
+
+$QEMU_IO -c "read -P 0x5a 0 512" $TEST_IMG | _filter_qemu_io
+
+echo
+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"
+
+# The dirty bit must be set
+./qcow2.py $TEST_IMG dump-header | grep incompatible_features
+
+$QEMU_IO -c "write 0 512" $TEST_IMG | _filter_qemu_io
+
+# The dirty bit must not be set
+./qcow2.py $TEST_IMG dump-header | grep incompatible_features
+
+echo
+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"
+
+# The dirty bit must not be set since lazy_refcounts=off
+./qcow2.py $TEST_IMG dump-header | grep incompatible_features
+_check_test_img
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
+
diff --git a/tests/qemu-iotests/039.out b/tests/qemu-iotests/039.out
new file mode 100644
index 0000000000..cb510d6716
--- /dev/null
+++ b/tests/qemu-iotests/039.out
@@ -0,0 +1,59 @@
+QA output created by 039
+
+== Checking that image is clean on shutdown ==
+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)
+incompatible_features     0x0
+No errors were found on the image.
+
+== Creating a dirty image file ==
+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)
+incompatible_features     0x1
+ERROR OFLAG_COPIED: offset=8000000000050000 refcount=0
+ERROR cluster 5 refcount=0 reference=1
+
+2 errors were found on the image.
+Data may be corrupted, or further writes to the image may corrupt it.
+
+== Read-only access must still work ==
+read 512/512 bytes at offset 0
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+incompatible_features     0x1
+
+== Repairing the image file must succeed ==
+ERROR OFLAG_COPIED: offset=8000000000050000 refcount=0
+Repairing cluster 5 refcount=0 reference=1
+The following inconsistencies were found and repaired:
+
+    0 leaked clusters
+    1 corruptions
+
+Double checking the fixed image now...
+No errors were found on the image.
+incompatible_features     0x0
+
+== Data should still be accessible after repair ==
+read 512/512 bytes at offset 0
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+== Opening a dirty image read/write should repair it ==
+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)
+incompatible_features     0x1
+ERROR OFLAG_COPIED: offset=8000000000050000 refcount=0
+Repairing cluster 5 refcount=0 reference=1
+wrote 512/512 bytes at offset 0
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+incompatible_features     0x0
+
+== Creating an image file with lazy_refcounts=off ==
+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)
+incompatible_features     0x0
+No errors were found on the image.
+*** done
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
index 5e3a524bc8..d534e9466d 100644
--- a/tests/qemu-iotests/common.rc
+++ b/tests/qemu-iotests/common.rc
@@ -105,15 +105,16 @@ _make_test_img()
 
     # XXX(hch): have global image options?
     $QEMU_IMG create -f $IMGFMT $extra_img_options $TEST_IMG $image_size | \
-    	sed -e "s#$IMGPROTO:$TEST_DIR#TEST_DIR#g" | \
-    	sed -e "s#$TEST_DIR#TEST_DIR#g" | \
-    	sed -e "s#$IMGFMT#IMGFMT#g" | \
-	sed -e "s# encryption=off##g" | \
-	sed -e "s# cluster_size=[0-9]\\+##g" | \
-	sed -e "s# table_size=0##g" | \
-	sed -e "s# compat='[^']*'##g" | \
-	sed -e "s# compat6=off##g" | \
-	sed -e "s# static=off##g"
+        sed -e "s#$IMGPROTO:$TEST_DIR#TEST_DIR#g" \
+            -e "s#$TEST_DIR#TEST_DIR#g" \
+            -e "s#$IMGFMT#IMGFMT#g" \
+            -e "s# encryption=off##g" \
+            -e "s# cluster_size=[0-9]\\+##g" \
+            -e "s# table_size=[0-9]\\+##g" \
+            -e "s# compat='[^']*'##g" \
+            -e "s# compat6=\\(on\\|off\\)##g" \
+            -e "s# static=\\(on\\|off\\)##g" \
+            -e "s# lazy_refcounts=\\(on\\|off\\)##g"
 }
 
 _cleanup_test_img()
@@ -296,6 +297,20 @@ _supported_os()
     _notrun "not suitable for this OS: $HOSTOS"
 }
 
+_unsupported_qemu_io_options()
+{
+    for bad_opt
+    do
+        for opt in $QEMU_IO_OPTIONS
+        do
+            if [ "$bad_opt" = "$opt" ]
+            then
+                _notrun "not suitable for qemu-io option: $bad_opt"
+            fi
+        done
+    done
+}
+
 # this test requires that a specified command (executable) exists
 #
 _require_command()
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index 7a2c92b6e9..ebb5ca4b41 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -45,3 +45,4 @@
 036 rw auto quick
 037 rw auto backing
 038 rw auto backing
+039 rw auto
diff --git a/tests/qemu-iotests/qed.py b/tests/qemu-iotests/qed.py
new file mode 100755
index 0000000000..52ff845590
--- /dev/null
+++ b/tests/qemu-iotests/qed.py
@@ -0,0 +1,235 @@
+#!/usr/bin/env python
+#
+# Tool to manipulate QED image files
+#
+# Copyright (C) 2010 IBM, Corp.
+#
+# Authors:
+#  Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or later.
+# See the COPYING file in the top-level directory.
+
+import sys
+import struct
+import random
+import optparse
+
+# This can be used as a module
+__all__ = ['QED_F_NEED_CHECK', 'QED']
+
+QED_F_NEED_CHECK = 0x02
+
+header_fmt = '<IIIIQQQQQII'
+header_size = struct.calcsize(header_fmt)
+field_names = ['magic', 'cluster_size', 'table_size',
+               'header_size', 'features', 'compat_features',
+               'autoclear_features', 'l1_table_offset', 'image_size',
+               'backing_filename_offset', 'backing_filename_size']
+table_elem_fmt = '<Q'
+table_elem_size = struct.calcsize(table_elem_fmt)
+
+def err(msg):
+    sys.stderr.write(msg + '\n')
+    sys.exit(1)
+
+def unpack_header(s):
+    fields = struct.unpack(header_fmt, s)
+    return dict((field_names[idx], val) for idx, val in enumerate(fields))
+
+def pack_header(header):
+    fields = tuple(header[x] for x in field_names)
+    return struct.pack(header_fmt, *fields)
+
+def unpack_table_elem(s):
+    return struct.unpack(table_elem_fmt, s)[0]
+
+def pack_table_elem(elem):
+    return struct.pack(table_elem_fmt, elem)
+
+class QED(object):
+    def __init__(self, f):
+        self.f = f
+
+        self.f.seek(0, 2)
+        self.filesize = f.tell()
+
+        self.load_header()
+        self.load_l1_table()
+
+    def raw_pread(self, offset, size):
+        self.f.seek(offset)
+        return self.f.read(size)
+
+    def raw_pwrite(self, offset, data):
+        self.f.seek(offset)
+        return self.f.write(data)
+
+    def load_header(self):
+        self.header = unpack_header(self.raw_pread(0, header_size))
+
+    def store_header(self):
+        self.raw_pwrite(0, pack_header(self.header))
+
+    def read_table(self, offset):
+        size = self.header['table_size'] * self.header['cluster_size']
+        s = self.raw_pread(offset, size)
+        table = [unpack_table_elem(s[i:i + table_elem_size]) for i in xrange(0, size, table_elem_size)]
+        return table
+
+    def load_l1_table(self):
+        self.l1_table = self.read_table(self.header['l1_table_offset'])
+        self.table_nelems = self.header['table_size'] * self.header['cluster_size'] / table_elem_size
+
+    def write_table(self, offset, table):
+        s = ''.join(pack_table_elem(x) for x in table)
+        self.raw_pwrite(offset, s)
+
+def random_table_item(table):
+    vals = [(index, offset) for index, offset in enumerate(table) if offset != 0]
+    if not vals:
+        err('cannot pick random item because table is empty')
+    return random.choice(vals)
+
+def corrupt_table_duplicate(table):
+    '''Corrupt a table by introducing a duplicate offset'''
+    victim_idx, victim_val = random_table_item(table)
+    unique_vals = set(table)
+    if len(unique_vals) == 1:
+        err('no duplication corruption possible in table')
+    dup_val = random.choice(list(unique_vals.difference([victim_val])))
+    table[victim_idx] = dup_val
+
+def corrupt_table_invalidate(qed, table):
+    '''Corrupt a table by introducing an invalid offset'''
+    index, _ = random_table_item(table)
+    table[index] = qed.filesize + random.randint(0, 100 * 1024 * 1024 * 1024 * 1024)
+
+def cmd_show(qed, *args):
+    '''show [header|l1|l2 <offset>]- Show header or l1/l2 tables'''
+    if not args or args[0] == 'header':
+        print qed.header
+    elif args[0] == 'l1':
+        print qed.l1_table
+    elif len(args) == 2 and args[0] == 'l2':
+        offset = int(args[1])
+        print qed.read_table(offset)
+    else:
+        err('unrecognized sub-command')
+
+def cmd_duplicate(qed, table_level):
+    '''duplicate l1|l2 - Duplicate a random table element'''
+    if table_level == 'l1':
+        offset = qed.header['l1_table_offset']
+        table = qed.l1_table
+    elif table_level == 'l2':
+        _, offset = random_table_item(qed.l1_table)
+        table = qed.read_table(offset)
+    else:
+        err('unrecognized sub-command')
+    corrupt_table_duplicate(table)
+    qed.write_table(offset, table)
+
+def cmd_invalidate(qed, table_level):
+    '''invalidate l1|l2 - Plant an invalid table element at random'''
+    if table_level == 'l1':
+        offset = qed.header['l1_table_offset']
+        table = qed.l1_table
+    elif table_level == 'l2':
+        _, offset = random_table_item(qed.l1_table)
+        table = qed.read_table(offset)
+    else:
+        err('unrecognized sub-command')
+    corrupt_table_invalidate(qed, table)
+    qed.write_table(offset, table)
+
+def cmd_need_check(qed, *args):
+    '''need-check [on|off] - Test, set, or clear the QED_F_NEED_CHECK header bit'''
+    if not args:
+        print bool(qed.header['features'] & QED_F_NEED_CHECK)
+        return
+
+    if args[0] == 'on':
+        qed.header['features'] |= QED_F_NEED_CHECK
+    elif args[0] == 'off':
+        qed.header['features'] &= ~QED_F_NEED_CHECK
+    else:
+        err('unrecognized sub-command')
+    qed.store_header()
+
+def cmd_zero_cluster(qed, pos, *args):
+    '''zero-cluster <pos> [<n>] - Zero data clusters'''
+    pos, n = int(pos), 1
+    if args:
+        if len(args) != 1:
+            err('expected one argument')
+        n = int(args[0])
+
+    for i in xrange(n):
+        l1_index = pos / qed.header['cluster_size'] / len(qed.l1_table)
+        if qed.l1_table[l1_index] == 0:
+            err('no l2 table allocated')
+
+        l2_offset = qed.l1_table[l1_index]
+        l2_table = qed.read_table(l2_offset)
+
+        l2_index = (pos / qed.header['cluster_size']) % len(qed.l1_table)
+        l2_table[l2_index] = 1 # zero the data cluster
+        qed.write_table(l2_offset, l2_table)
+        pos += qed.header['cluster_size']
+
+def cmd_copy_metadata(qed, outfile):
+    '''copy-metadata <outfile> - Copy metadata only (for scrubbing corrupted images)'''
+    out = open(outfile, 'wb')
+
+    # Match file size
+    out.seek(qed.filesize - 1)
+    out.write('\0')
+
+    # Copy header clusters
+    out.seek(0)
+    header_size_bytes = qed.header['header_size'] * qed.header['cluster_size']
+    out.write(qed.raw_pread(0, header_size_bytes))
+
+    # Copy L1 table
+    out.seek(qed.header['l1_table_offset'])
+    s = ''.join(pack_table_elem(x) for x in qed.l1_table)
+    out.write(s)
+
+    # Copy L2 tables
+    for l2_offset in qed.l1_table:
+        if l2_offset == 0:
+            continue
+        l2_table = qed.read_table(l2_offset)
+        out.seek(l2_offset)
+        s = ''.join(pack_table_elem(x) for x in l2_table)
+        out.write(s)
+
+    out.close()
+
+def usage():
+    print 'Usage: %s <file> <cmd> [<arg>, ...]' % sys.argv[0]
+    print
+    print 'Supported commands:'
+    for cmd in sorted(x for x in globals() if x.startswith('cmd_')):
+        print globals()[cmd].__doc__
+    sys.exit(1)
+
+def main():
+    if len(sys.argv) < 3:
+        usage()
+    filename, cmd = sys.argv[1:3]
+
+    cmd = 'cmd_' + cmd.replace('-', '_')
+    if cmd not in globals():
+        usage()
+
+    qed = QED(open(filename, 'r+b'))
+    try:
+        globals()[cmd](qed, *sys.argv[3:])
+    except TypeError, e:
+        sys.stderr.write(globals()[cmd].__doc__ + '\n')
+        sys.exit(1)
+
+if __name__ == '__main__':
+    main()
diff --git a/ui/vnc.c b/ui/vnc.c
index 312ad7fe36..385e345c31 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -3061,7 +3061,7 @@ int vnc_display_open(DisplayState *ds, const char *display)
         if (strncmp(display, "unix:", 5) == 0)
             vs->lsock = unix_connect(display+5);
         else
-            vs->lsock = inet_connect(display, true, NULL);
+            vs->lsock = inet_connect(display, true, NULL, NULL);
         if (-1 == vs->lsock) {
             g_free(vs->display);
             vs->display = NULL;
diff --git a/user-exec.c b/user-exec.c
index 1a9c276eb3..b9ea9dd32f 100644
--- a/user-exec.c
+++ b/user-exec.c
@@ -18,7 +18,9 @@
  */
 #include "config.h"
 #include "cpu.h"
+#ifndef CONFIG_TCG_PASS_AREG0
 #include "dyngen-exec.h"
+#endif
 #include "disas.h"
 #include "tcg.h"
 
@@ -58,9 +60,11 @@ void cpu_resume_from_signal(CPUArchState *env1, void *puc)
     struct sigcontext *uc = puc;
 #endif
 
+#ifndef CONFIG_TCG_PASS_AREG0
     env = env1;
 
     /* XXX: restore cpu registers saved in host registers */
+#endif
 
     if (puc) {
         /* XXX: use siglongjmp ? */
@@ -74,8 +78,8 @@ void cpu_resume_from_signal(CPUArchState *env1, void *puc)
         sigprocmask(SIG_SETMASK, &uc->sc_mask, NULL);
 #endif
     }
-    env->exception_index = -1;
-    longjmp(env->jmp_env, 1);
+    env1->exception_index = -1;
+    longjmp(env1->jmp_env, 1);
 }
 
 /* 'pc' is the host PC at which the exception was raised. 'address' is
@@ -89,9 +93,11 @@ static inline int handle_cpu_signal(uintptr_t pc, unsigned long address,
     TranslationBlock *tb;
     int ret;
 
+#ifndef CONFIG_TCG_PASS_AREG0
     if (cpu_single_env) {
         env = cpu_single_env; /* XXX: find a correct solution for multithread */
     }
+#endif
 #if defined(DEBUG_SIGNAL)
     qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
                 pc, address, is_write, *(unsigned long *)old_set);
@@ -103,7 +109,8 @@ static inline int handle_cpu_signal(uintptr_t pc, unsigned long address,
     }
 
     /* see if it is an MMU fault */
-    ret = cpu_handle_mmu_fault(env, address, is_write, MMU_USER_IDX);
+    ret = cpu_handle_mmu_fault(cpu_single_env, address, is_write,
+                               MMU_USER_IDX);
     if (ret < 0) {
         return 0; /* not an MMU fault */
     }
@@ -115,13 +122,13 @@ static inline int handle_cpu_signal(uintptr_t pc, unsigned long address,
     if (tb) {
         /* the PC is inside the translated code. It means that we have
            a virtual CPU fault */
-        cpu_restore_state(tb, env, pc);
+        cpu_restore_state(tb, cpu_single_env, pc);
     }
 
     /* we restore the process signal mask as the sigreturn should
        do it (XXX: use sigsetjmp) */
     sigprocmask(SIG_SETMASK, old_set, NULL);
-    exception_action(env);
+    exception_action(cpu_single_env);
 
     /* never comes here */
     return 1;
diff --git a/vl.c b/vl.c
index e71cb30ecf..d01256a6a3 100644
--- a/vl.c
+++ b/vl.c
@@ -293,6 +293,11 @@ static struct {
     { .driver = "qxl-vga",              .flag = &default_vga       },
 };
 
+const char *qemu_get_vm_name(void)
+{
+    return qemu_name;
+}
+
 static void res_free(void)
 {
     if (boot_splash_filedata != NULL) {
@@ -1208,6 +1213,37 @@ QEMUMachine *find_default_machine(void)
     return NULL;
 }
 
+MachineInfoList *qmp_query_machines(Error **errp)
+{
+    MachineInfoList *mach_list = NULL;
+    QEMUMachine *m;
+
+    for (m = first_machine; m; m = m->next) {
+        MachineInfoList *entry;
+        MachineInfo *info;
+
+        info = g_malloc0(sizeof(*info));
+        if (m->is_default) {
+            info->has_is_default = true;
+            info->is_default = true;
+        }
+
+        if (m->alias) {
+            info->has_alias = true;
+            info->alias = g_strdup(m->alias);
+        }
+
+        info->name = g_strdup(m->name);
+
+        entry = g_malloc0(sizeof(*entry));
+        entry->value = info;
+        entry->next = mach_list;
+        mach_list = entry;
+    }
+
+    return mach_list;
+}
+
 /***********************************************************/
 /* main execution loop */
 
@@ -1293,6 +1329,7 @@ static pid_t shutdown_pid;
 static int powerdown_requested;
 static int debug_requested;
 static int suspend_requested;
+static int wakeup_requested;
 static NotifierList suspend_notifiers =
     NOTIFIER_LIST_INITIALIZER(suspend_notifiers);
 static NotifierList wakeup_notifiers =
@@ -1347,6 +1384,13 @@ static int qemu_suspend_requested(void)
     return r;
 }
 
+static int qemu_wakeup_requested(void)
+{
+    int r = wakeup_requested;
+    wakeup_requested = 0;
+    return r;
+}
+
 int qemu_powerdown_requested(void)
 {
     int r = powerdown_requested;
@@ -1452,9 +1496,8 @@ void qemu_system_wakeup_request(WakeupReason reason)
         return;
     }
     runstate_set(RUN_STATE_RUNNING);
-    monitor_protocol_event(QEVENT_WAKEUP, NULL);
     notifier_list_notify(&wakeup_notifiers, &reason);
-    reset_requested = 1;
+    wakeup_requested = 1;
     qemu_notify_event();
 }
 
@@ -1534,6 +1577,13 @@ static bool main_loop_should_exit(void)
             runstate_set(RUN_STATE_PAUSED);
         }
     }
+    if (qemu_wakeup_requested()) {
+        pause_all_vcpus();
+        cpu_synchronize_all_states();
+        qemu_system_reset(VMRESET_SILENT);
+        resume_all_vcpus();
+        monitor_protocol_event(QEVENT_WAKEUP, NULL);
+    }
     if (qemu_powerdown_requested()) {
         monitor_protocol_event(QEVENT_POWERDOWN, NULL);
         qemu_irq_raise(qemu_system_powerdown);
@@ -3204,6 +3254,11 @@ int main(int argc, char **argv, char **envp)
     }
     loc_set_none();
 
+    if (machine == NULL) {
+        fprintf(stderr, "No machine found.\n");
+        exit(1);
+    }
+
     if (machine->hw_version) {
         qemu_set_version(machine->hw_version);
     }
@@ -3246,11 +3301,6 @@ int main(int argc, char **argv, char **envp)
         data_dir = CONFIG_QEMU_DATADIR;
     }
 
-    if (machine == NULL) {
-        fprintf(stderr, "No machine found.\n");
-        exit(1);
-    }
-
     /*
      * Default to max_cpus = smp_cpus, in case the user doesn't
      * specify a max_cpus value.
@@ -3345,6 +3395,11 @@ int main(int argc, char **argv, char **envp)
         ram_size = DEFAULT_RAM_SIZE * 1024 * 1024;
     }
 
+    if (qemu_opts_foreach(qemu_find_opts("device"), device_help_func, NULL, 0)
+        != 0) {
+        exit(0);
+    }
+
     configure_accelerator();
 
     qemu_init_cpu_loop();
@@ -3500,9 +3555,6 @@ int main(int argc, char **argv, char **envp)
     }
     select_vgahw(vga_model);
 
-    if (qemu_opts_foreach(qemu_find_opts("device"), device_help_func, NULL, 0) != 0)
-        exit(0);
-
     if (watchdog) {
         i = select_watchdog(watchdog);
         if (i > 0)