summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml4
-rw-r--r--.travis.yml1
-rw-r--r--MAINTAINERS5
-rw-r--r--Makefile43
-rw-r--r--Makefile.objs22
-rw-r--r--Makefile.target6
-rw-r--r--block.c174
-rw-r--r--block/backup.c8
-rw-r--r--block/block-backend.c55
-rw-r--r--block/file-posix.c29
-rw-r--r--block/io.c6
-rw-r--r--block/mirror.c10
-rw-r--r--block/qcow2-cluster.c5
-rw-r--r--block/qcow2-refcount.c25
-rw-r--r--block/qcow2.c3
-rw-r--r--block/qcow2.h4
-rw-r--r--blockjob.c77
-rwxr-xr-xconfigure4
-rw-r--r--contrib/libvhost-user/libvhost-user.c2
-rw-r--r--contrib/vhost-user-blk/vhost-user-blk.c3
-rw-r--r--docs/interop/index.rst2
-rw-r--r--docs/interop/vhost-user.rst1351
-rw-r--r--docs/interop/vhost-user.txt1219
-rw-r--r--fsdev/file-op-9p.h1
-rw-r--r--fsdev/qemu-fsdev.c97
-rw-r--r--fsdev/qemu-fsdev.h25
-rw-r--r--hw/acpi/pcihp.c32
-rw-r--r--hw/acpi/piix4.c27
-rw-r--r--hw/acpi/trace-events16
-rw-r--r--hw/arm/virt-acpi-build.c22
-rw-r--r--hw/block/nvme.c2
-rw-r--r--hw/block/vhost-user-blk.c175
-rw-r--r--hw/char/Kconfig6
-rw-r--r--hw/char/Makefile.objs1
-rw-r--r--hw/char/escc.c7
-rw-r--r--hw/char/grlib_apbuart.c4
-rw-r--r--hw/char/serial-pci-multi.c208
-rw-r--r--hw/char/serial-pci.c170
-rw-r--r--hw/core/loader.c1
-rw-r--r--hw/core/machine.c23
-rw-r--r--hw/display/virtio-gpu-pci.c4
-rw-r--r--hw/display/virtio-vga.c4
-rw-r--r--hw/i386/acpi-build.c54
-rw-r--r--hw/input/Kconfig5
-rw-r--r--hw/input/Makefile.objs2
-rw-r--r--hw/intc/grlib_irqmp.c3
-rw-r--r--hw/intc/ioapic.c57
-rw-r--r--hw/intc/trace-events1
-rw-r--r--hw/isa/lpc_ich9.c11
-rw-r--r--hw/mips/mips_fulong2e.c10
-rw-r--r--hw/misc/Makefile.objs2
-rw-r--r--hw/misc/grlib_ahb_apb_pnp.c269
-rw-r--r--hw/net/Kconfig7
-rw-r--r--hw/net/Makefile.objs3
-rw-r--r--hw/net/e1000.c1
-rw-r--r--hw/net/ne2000-pci.c132
-rw-r--r--hw/net/ne2000.c105
-rw-r--r--hw/net/vhost_net.c10
-rw-r--r--hw/pci-bridge/pci_expander_bridge.c6
-rw-r--r--hw/pci/pci.c14
-rw-r--r--hw/pci/pcie_host.c10
-rw-r--r--hw/scsi/megasas.c2
-rw-r--r--hw/sparc/leon3.c157
-rw-r--r--hw/sparc/sun4m.c6
-rw-r--r--hw/timer/grlib_gptimer.c4
-rw-r--r--hw/virtio/virtio-crypto-pci.c4
-rw-r--r--hw/virtio/virtio-input-pci.c4
-rw-r--r--hw/virtio/virtio-pci.c27
-rw-r--r--hw/virtio/virtio-pci.h31
-rw-r--r--hw/virtio/virtio.c59
-rw-r--r--include/block/block.h10
-rw-r--r--include/block/block_int.h25
-rw-r--r--include/hw/acpi/pci.h33
-rw-r--r--include/hw/acpi/piix4.h2
-rw-r--r--include/hw/i386/ich9.h2
-rw-r--r--include/hw/i386/ioapic_internal.h3
-rw-r--r--include/hw/misc/grlib_ahb_apb_pnp.h60
-rw-r--r--include/hw/pci/pci.h1
-rw-r--r--include/hw/pci/pci_bus.h12
-rw-r--r--include/hw/qdev-core.h3
-rw-r--r--include/hw/sparc/grlib.h78
-rw-r--r--include/hw/virtio/vhost-user-blk.h3
-rw-r--r--include/hw/virtio/virtio.h3
-rw-r--r--include/sysemu/block-backend.h1
-rw-r--r--linux-user/syscall.c106
-rw-r--r--linux-user/syscall_defs.h3
-rw-r--r--memory.c4
-rw-r--r--net/colo-compare.c3
-rw-r--r--net/slirp.c3
-rw-r--r--net/vhost-user.c1
-rw-r--r--qemu-deprecated.texi10
-rw-r--r--qemu-img.texi52
-rw-r--r--qemu-io-cmds.c7
-rw-r--r--qemu-options.hx96
-rw-r--r--qmp.c3
-rw-r--r--qom/object.c3
-rw-r--r--target/alpha/cpu.h42
-rw-r--r--target/alpha/fpu_helper.c21
-rw-r--r--target/alpha/helper.c39
-rw-r--r--target/i386/hvf/hvf.c1
-rw-r--r--target/m68k/cpu.c2
-rw-r--r--target/m68k/cpu.h7
-rw-r--r--target/m68k/helper.c84
-rw-r--r--target/m68k/op_helper.c20
-rw-r--r--target/m68k/translate.c9
-rw-r--r--target/s390x/Makefile.objs2
-rw-r--r--target/xtensa/cpu.c2
-rw-r--r--target/xtensa/cpu.h58
-rw-r--r--target/xtensa/helper.c1
-rw-r--r--target/xtensa/helper.h6
-rw-r--r--target/xtensa/mmu_helper.c532
-rw-r--r--target/xtensa/op_helper.c42
-rw-r--r--target/xtensa/overlay_tool.h43
-rw-r--r--target/xtensa/translate.c2947
-rw-r--r--tests/Makefile.include116
-rw-r--r--tests/acpi-utils.c68
-rw-r--r--tests/acpi-utils.h7
-rw-r--r--tests/bios-tables-test.c130
-rwxr-xr-xtests/data/acpi/rebuild-expected-aml.sh23
-rw-r--r--tests/device-introspect-test.c85
-rw-r--r--tests/hd-geo-test.c76
-rw-r--r--tests/libqos/virtio-mmio.c2
-rw-r--r--tests/libqos/virtio-pci.c3
-rw-r--r--tests/libqos/virtio.c18
-rw-r--r--tests/libqos/virtio.h3
-rw-r--r--tests/libqtest.c11
-rw-r--r--tests/libqtest.h112
-rw-r--r--tests/numa-test.c53
-rw-r--r--tests/q35-test.c39
-rwxr-xr-xtests/qemu-iotests/0011
-rwxr-xr-xtests/qemu-iotests/0021
-rwxr-xr-xtests/qemu-iotests/0031
-rwxr-xr-xtests/qemu-iotests/0041
-rwxr-xr-xtests/qemu-iotests/0059
-rwxr-xr-xtests/qemu-iotests/0071
-rwxr-xr-xtests/qemu-iotests/0081
-rwxr-xr-xtests/qemu-iotests/0091
-rwxr-xr-xtests/qemu-iotests/0101
-rwxr-xr-xtests/qemu-iotests/0111
-rwxr-xr-xtests/qemu-iotests/0121
-rwxr-xr-xtests/qemu-iotests/0151
-rwxr-xr-xtests/qemu-iotests/0171
-rwxr-xr-xtests/qemu-iotests/0201
-rwxr-xr-xtests/qemu-iotests/0211
-rwxr-xr-xtests/qemu-iotests/0221
-rwxr-xr-xtests/qemu-iotests/0251
-rwxr-xr-xtests/qemu-iotests/0261
-rwxr-xr-xtests/qemu-iotests/0271
-rwxr-xr-xtests/qemu-iotests/0291
-rwxr-xr-xtests/qemu-iotests/0311
-rwxr-xr-xtests/qemu-iotests/0321
-rwxr-xr-xtests/qemu-iotests/0331
-rwxr-xr-xtests/qemu-iotests/0351
-rwxr-xr-xtests/qemu-iotests/0361
-rwxr-xr-xtests/qemu-iotests/0371
-rwxr-xr-xtests/qemu-iotests/0421
-rwxr-xr-xtests/qemu-iotests/0431
-rwxr-xr-xtests/qemu-iotests/0461
-rwxr-xr-xtests/qemu-iotests/0471
-rwxr-xr-xtests/qemu-iotests/0491
-rwxr-xr-xtests/qemu-iotests/0501
-rwxr-xr-xtests/qemu-iotests/0511
-rwxr-xr-xtests/qemu-iotests/0521
-rwxr-xr-xtests/qemu-iotests/0531
-rwxr-xr-xtests/qemu-iotests/0541
-rwxr-xr-xtests/qemu-iotests/0621
-rwxr-xr-xtests/qemu-iotests/0631
-rwxr-xr-xtests/qemu-iotests/0661
-rwxr-xr-xtests/qemu-iotests/0671
-rwxr-xr-xtests/qemu-iotests/0681
-rwxr-xr-xtests/qemu-iotests/0691
-rwxr-xr-xtests/qemu-iotests/0711
-rwxr-xr-xtests/qemu-iotests/0721
-rwxr-xr-xtests/qemu-iotests/0731
-rwxr-xr-xtests/qemu-iotests/0791
-rwxr-xr-xtests/qemu-iotests/0821
-rwxr-xr-xtests/qemu-iotests/0851
-rwxr-xr-xtests/qemu-iotests/0891
-rwxr-xr-xtests/qemu-iotests/0901
-rwxr-xr-xtests/qemu-iotests/0941
-rwxr-xr-xtests/qemu-iotests/0951
-rwxr-xr-xtests/qemu-iotests/0981
-rwxr-xr-xtests/qemu-iotests/1021
-rwxr-xr-xtests/qemu-iotests/1031
-rwxr-xr-xtests/qemu-iotests/1041
-rwxr-xr-xtests/qemu-iotests/1051
-rwxr-xr-xtests/qemu-iotests/1071
-rwxr-xr-xtests/qemu-iotests/1101
-rwxr-xr-xtests/qemu-iotests/1111
-rwxr-xr-xtests/qemu-iotests/1121
-rwxr-xr-xtests/qemu-iotests/1141
-rwxr-xr-xtests/qemu-iotests/1151
-rwxr-xr-xtests/qemu-iotests/1171
-rwxr-xr-xtests/qemu-iotests/1201
-rwxr-xr-xtests/qemu-iotests/1251
-rwxr-xr-xtests/qemu-iotests/1261
-rwxr-xr-xtests/qemu-iotests/1271
-rwxr-xr-xtests/qemu-iotests/1331
-rwxr-xr-xtests/qemu-iotests/1341
-rwxr-xr-xtests/qemu-iotests/1421
-rwxr-xr-xtests/qemu-iotests/1431
-rwxr-xr-xtests/qemu-iotests/1441
-rwxr-xr-xtests/qemu-iotests/1451
-rwxr-xr-xtests/qemu-iotests/1531
-rwxr-xr-xtests/qemu-iotests/1561
-rwxr-xr-xtests/qemu-iotests/1571
-rwxr-xr-xtests/qemu-iotests/1581
-rwxr-xr-xtests/qemu-iotests/1591
-rwxr-xr-xtests/qemu-iotests/1621
-rwxr-xr-xtests/qemu-iotests/1697
-rwxr-xr-xtests/qemu-iotests/1701
-rwxr-xr-xtests/qemu-iotests/1731
-rwxr-xr-xtests/qemu-iotests/1821
-rwxr-xr-xtests/qemu-iotests/1831
-rwxr-xr-xtests/qemu-iotests/1861
-rwxr-xr-xtests/qemu-iotests/1871
-rwxr-xr-xtests/qemu-iotests/1901
-rwxr-xr-xtests/qemu-iotests/1911
-rwxr-xr-xtests/qemu-iotests/1921
-rwxr-xr-xtests/qemu-iotests/1951
-rwxr-xr-xtests/qemu-iotests/1971
-rwxr-xr-xtests/qemu-iotests/2001
-rwxr-xr-xtests/qemu-iotests/2141
-rwxr-xr-xtests/qemu-iotests/2151
-rwxr-xr-xtests/qemu-iotests/2171
-rwxr-xr-xtests/qemu-iotests/2214
-rwxr-xr-xtests/qemu-iotests/2271
-rwxr-xr-xtests/qemu-iotests/2311
-rwxr-xr-xtests/qemu-iotests/2331
-rwxr-xr-xtests/qemu-iotests/2392
-rwxr-xr-xtests/qemu-iotests/2403
-rwxr-xr-xtests/qemu-iotests/2412
-rwxr-xr-xtests/qemu-iotests/2432
-rwxr-xr-xtests/qemu-iotests/2442
-rw-r--r--tests/qemu-iotests/24522
-rw-r--r--tests/qemu-iotests/245.out12
-rwxr-xr-xtests/qemu-iotests/2471
-rwxr-xr-xtests/qemu-iotests/25384
-rw-r--r--tests/qemu-iotests/253.out14
-rwxr-xr-xtests/qemu-iotests/check13
-rw-r--r--tests/qemu-iotests/group1
-rw-r--r--tests/qemu-iotests/iotests.py20
-rw-r--r--tests/qom-test.c28
-rw-r--r--tests/tcg/xtensa/test_exclusive.S48
-rw-r--r--tests/test-block-iothread.c202
-rw-r--r--tests/vmgenid-test.c6
-rw-r--r--ui/console-gl.c18
-rw-r--r--ui/curses.c194
-rw-r--r--ui/kbd-state.c6
-rw-r--r--vl.c26
250 files changed, 7000 insertions, 3833 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index 47ef5bc604..8326a3a4b1 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -7,7 +7,7 @@ freebsd_12_task:
     cpu: 8
     memory: 8G
   install_script: pkg install -y
-    bison curl cyrus-sasl git glib gmake gnutls
+    bash bison curl cyrus-sasl git glib gmake gnutls gsed
     nettle perl5 pixman pkgconf png usbredir
   script:
     - mkdir build
@@ -20,7 +20,7 @@ macos_task:
   osx_instance:
     image: mojave-base
   install_script:
-    - brew install pkg-config python glib pixman make sdl2
+    - brew install pkg-config python gnu-sed glib pixman make sdl2
   script:
     - ./configure --python=/usr/local/bin/python3 || { cat config.log; exit 1; }
     - gmake -j$(sysctl -n hw.ncpu)
diff --git a/.travis.yml b/.travis.yml
index 66448d99d6..6fd89b3d91 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -42,6 +42,7 @@ addons:
     packages:
       - glib
       - pixman
+      - gnu-sed
 
 
 # The channel name "irc.oftc.net#qemu" is encrypted against qemu/qemu
diff --git a/MAINTAINERS b/MAINTAINERS
index a73a61a546..a6948ebc63 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1158,10 +1158,11 @@ F: include/hw/timer/sun4v-rtc.h
 
 Leon3
 M: Fabien Chouteau <chouteau@adacore.com>
+M: KONRAD Frederic <frederic.konrad@adacore.com>
 S: Maintained
 F: hw/sparc/leon3.c
 F: hw/*/grlib*
-F: include/hw/sparc/grlib.h
+F: include/hw/*/grlib*
 
 S390 Machines
 -------------
@@ -1483,7 +1484,7 @@ M: Michael S. Tsirkin <mst@redhat.com>
 S: Supported
 F: hw/*/*vhost*
 F: docs/interop/vhost-user.json
-F: docs/interop/vhost-user.txt
+F: docs/interop/vhost-user.rst
 F: contrib/vhost-user-*/
 F: backends/vhost-user.c
 F: include/sysemu/vhost-user-backend.h
diff --git a/Makefile b/Makefile
index 66d5c65156..155f066a20 100644
--- a/Makefile
+++ b/Makefile
@@ -87,6 +87,10 @@ endif
 
 include $(SRC_PATH)/rules.mak
 
+# notempy and lor are defined in rules.mak
+CONFIG_TOOLS := $(call notempty,$(TOOLS))
+CONFIG_BLOCK := $(call lor,$(CONFIG_SOFTMMU),$(CONFIG_TOOLS))
+
 # Create QEMU_PKGVERSION and FULL_VERSION strings
 # If PKGVERSION is set, use that; otherwise get version and -dirty status from git
 QEMU_PKGVERSION := $(if $(PKGVERSION),$(PKGVERSION),$(shell \
@@ -101,7 +105,7 @@ QEMU_PKGVERSION := $(if $(PKGVERSION),$(PKGVERSION),$(shell \
 # Either "version (pkgversion)", or just "version" if pkgversion not set
 FULL_VERSION := $(if $(QEMU_PKGVERSION),$(VERSION) ($(QEMU_PKGVERSION)),$(VERSION))
 
-GENERATED_FILES = qemu-version.h config-host.h qemu-options.def
+generated-files-y = qemu-version.h config-host.h qemu-options.def
 
 GENERATED_QAPI_FILES = qapi/qapi-builtin-types.h qapi/qapi-builtin-types.c
 GENERATED_QAPI_FILES += qapi/qapi-types.h qapi/qapi-types.c
@@ -121,20 +125,18 @@ GENERATED_QAPI_FILES += $(QAPI_MODULES:%=qapi/qapi-events-%.c)
 GENERATED_QAPI_FILES += qapi/qapi-introspect.c qapi/qapi-introspect.h
 GENERATED_QAPI_FILES += qapi/qapi-doc.texi
 
-GENERATED_FILES += $(GENERATED_QAPI_FILES)
+generated-files-y += $(GENERATED_QAPI_FILES)
 
-GENERATED_FILES += trace/generated-tcg-tracers.h
+generated-files-y += trace/generated-tcg-tracers.h
 
-GENERATED_FILES += trace/generated-helpers-wrappers.h
-GENERATED_FILES += trace/generated-helpers.h
-GENERATED_FILES += trace/generated-helpers.c
+generated-files-y += trace/generated-helpers-wrappers.h
+generated-files-y += trace/generated-helpers.h
+generated-files-y += trace/generated-helpers.c
 
-ifdef CONFIG_TRACE_UST
-GENERATED_FILES += trace-ust-all.h
-GENERATED_FILES += trace-ust-all.c
-endif
+generated-files-$(CONFIG_TRACE_UST) += trace-ust-all.h
+generated-files-$(CONFIG_TRACE_UST) += trace-ust-all.c
 
-GENERATED_FILES += module_block.h
+generated-files-y += module_block.h
 
 TRACE_HEADERS = trace-root.h $(trace-events-subdirs:%=%/trace.h)
 TRACE_SOURCES = trace-root.c $(trace-events-subdirs:%=%/trace.c)
@@ -147,10 +149,10 @@ ifdef CONFIG_TRACE_UST
 TRACE_HEADERS += trace-ust-root.h $(trace-events-subdirs:%=%/trace-ust.h)
 endif
 
-GENERATED_FILES += $(TRACE_HEADERS)
-GENERATED_FILES += $(TRACE_SOURCES)
-GENERATED_FILES += $(BUILD_DIR)/trace-events-all
-GENERATED_FILES += .git-submodule-status
+generated-files-y += $(TRACE_HEADERS)
+generated-files-y += $(TRACE_SOURCES)
+generated-files-y += $(BUILD_DIR)/trace-events-all
+generated-files-y += .git-submodule-status
 
 trace-group-name = $(shell dirname $1 | sed -e 's/[^a-zA-Z0-9]/_/g')
 
@@ -281,7 +283,7 @@ KEYCODEMAP_FILES = \
 		 ui/input-keymap-osx-to-qcode.c \
 		 $(NULL)
 
-GENERATED_FILES += $(KEYCODEMAP_FILES)
+generated-files-$(CONFIG_SOFTMMU) += $(KEYCODEMAP_FILES)
 
 ui/input-keymap-%.c: $(KEYCODEMAP_GEN) $(KEYCODEMAP_CSV) $(SRC_PATH)/ui/Makefile.objs
 	$(call quiet-command,\
@@ -446,6 +448,7 @@ SOFTMMU_SUBDIR_RULES=$(filter %-softmmu,$(SUBDIR_RULES))
 
 $(SOFTMMU_SUBDIR_RULES): $(authz-obj-y)
 $(SOFTMMU_SUBDIR_RULES): $(block-obj-y)
+$(SOFTMMU_SUBDIR_RULES): $(chardev-obj-y)
 $(SOFTMMU_SUBDIR_RULES): $(crypto-obj-y)
 $(SOFTMMU_SUBDIR_RULES): $(io-obj-y)
 $(SOFTMMU_SUBDIR_RULES): config-all-devices.mak
@@ -482,7 +485,7 @@ subdir-capstone: .git-submodule-status
 subdir-slirp: .git-submodule-status
 	$(call quiet-command,$(MAKE) -C $(SRC_PATH)/slirp BUILD_DIR="$(BUILD_DIR)/slirp" CC="$(CC)" AR="$(AR)" LD="$(LD)" RANLIB="$(RANLIB)" CFLAGS="$(QEMU_CFLAGS) $(CFLAGS)" LDFLAGS="$(LDFLAGS)")
 
-$(SUBDIR_RULES): libqemuutil.a $(common-obj-y) $(chardev-obj-y) \
+$(SUBDIR_RULES): libqemuutil.a $(common-obj-y) \
 	$(qom-obj-y) $(crypto-aes-obj-$(CONFIG_USER_ONLY))
 
 ROMSUBDIR_RULES=$(patsubst %,romsubdir-%, $(ROMS))
@@ -643,10 +646,10 @@ clean:
 	rm -f fsdev/*.pod scsi/*.pod
 	rm -f qemu-img-cmds.h
 	rm -f ui/shader/*-vert.h ui/shader/*-frag.h
-	@# May not be present in GENERATED_FILES
+	@# May not be present in generated-files-y
 	rm -f trace/generated-tracers-dtrace.dtrace*
 	rm -f trace/generated-tracers-dtrace.h*
-	rm -f $(foreach f,$(GENERATED_FILES),$(f) $(f)-timestamp)
+	rm -f $(foreach f,$(generated-files-y),$(f) $(f)-timestamp)
 	rm -f qapi-gen-timestamp
 	rm -rf qga/qapi-generated
 	for d in $(ALL_SUBDIRS); do \
@@ -1062,7 +1065,7 @@ endif # CONFIG_WIN
 # rebuilt before other object files
 ifneq ($(wildcard config-host.mak),)
 ifneq ($(filter-out $(UNCHECKED_GOALS),$(MAKECMDGOALS)),$(if $(MAKECMDGOALS),,fail))
-Makefile: $(GENERATED_FILES)
+Makefile: $(generated-files-y)
 endif
 endif
 
diff --git a/Makefile.objs b/Makefile.objs
index cf065de5ed..2b0793ecc9 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -127,11 +127,20 @@ rdmacm-mux-obj-y = contrib/rdmacm-mux/
 trace-events-subdirs =
 trace-events-subdirs += accel/kvm
 trace-events-subdirs += accel/tcg
-trace-events-subdirs += audio
+trace-events-subdirs += crypto
+ifeq ($(CONFIG_USER_ONLY),y)
+trace-events-subdirs += linux-user
+endif
+ifeq ($(CONFIG_BLOCK),y)
 trace-events-subdirs += authz
 trace-events-subdirs += block
+trace-events-subdirs += io
+trace-events-subdirs += nbd
+trace-events-subdirs += scsi
+endif
+ifeq ($(CONFIG_SOFTMMU),y)
 trace-events-subdirs += chardev
-trace-events-subdirs += crypto
+trace-events-subdirs += audio
 trace-events-subdirs += hw/9pfs
 trace-events-subdirs += hw/acpi
 trace-events-subdirs += hw/alpha
@@ -140,7 +149,6 @@ trace-events-subdirs += hw/audio
 trace-events-subdirs += hw/block
 trace-events-subdirs += hw/block/dataplane
 trace-events-subdirs += hw/char
-trace-events-subdirs += hw/display
 trace-events-subdirs += hw/dma
 trace-events-subdirs += hw/hppa
 trace-events-subdirs += hw/i2c
@@ -173,14 +181,13 @@ trace-events-subdirs += hw/virtio
 trace-events-subdirs += hw/watchdog
 trace-events-subdirs += hw/xen
 trace-events-subdirs += hw/gpio
-trace-events-subdirs += io
-trace-events-subdirs += linux-user
 trace-events-subdirs += migration
-trace-events-subdirs += nbd
 trace-events-subdirs += net
+trace-events-subdirs += ui
+endif
+trace-events-subdirs += hw/display
 trace-events-subdirs += qapi
 trace-events-subdirs += qom
-trace-events-subdirs += scsi
 trace-events-subdirs += target/arm
 trace-events-subdirs += target/hppa
 trace-events-subdirs += target/i386
@@ -189,7 +196,6 @@ trace-events-subdirs += target/ppc
 trace-events-subdirs += target/riscv
 trace-events-subdirs += target/s390x
 trace-events-subdirs += target/sparc
-trace-events-subdirs += ui
 trace-events-subdirs += util
 
 trace-events-files = $(SRC_PATH)/trace-events $(trace-events-subdirs:%=$(SRC_PATH)/%/trace-events)
diff --git a/Makefile.target b/Makefile.target
index ae02495951..fdbe7c89f4 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -166,7 +166,7 @@ else
 obj-y += hw/$(TARGET_BASE_ARCH)/
 endif
 
-GENERATED_FILES += hmp-commands.h hmp-commands-info.h
+generated-files-y += hmp-commands.h hmp-commands-info.h
 
 endif # CONFIG_SOFTMMU
 
@@ -236,5 +236,5 @@ ifdef CONFIG_TRACE_SYSTEMTAP
 	$(INSTALL_DATA) $(QEMU_PROG)-log.stp "$(DESTDIR)$(qemu_datadir)/../systemtap/tapset/$(QEMU_PROG)-log.stp"
 endif
 
-GENERATED_FILES += config-target.h
-Makefile: $(GENERATED_FILES)
+generated-files-y += config-target.h
+Makefile: $(generated-files-y)
diff --git a/block.c b/block.c
index 6999aad446..cb11537029 100644
--- a/block.c
+++ b/block.c
@@ -936,6 +936,20 @@ static int bdrv_child_cb_inactivate(BdrvChild *child)
     return 0;
 }
 
+static bool bdrv_child_cb_can_set_aio_ctx(BdrvChild *child, AioContext *ctx,
+                                          GSList **ignore, Error **errp)
+{
+    BlockDriverState *bs = child->opaque;
+    return bdrv_can_set_aio_context(bs, ctx, ignore, errp);
+}
+
+static void bdrv_child_cb_set_aio_ctx(BdrvChild *child, AioContext *ctx,
+                                      GSList **ignore)
+{
+    BlockDriverState *bs = child->opaque;
+    return bdrv_set_aio_context_ignore(bs, ctx, ignore);
+}
+
 /*
  * Returns the options and flags that a temporary snapshot should get, based on
  * the originally requested flags (the originally requested image will have
@@ -1003,6 +1017,8 @@ const BdrvChildRole child_file = {
     .attach          = bdrv_child_cb_attach,
     .detach          = bdrv_child_cb_detach,
     .inactivate      = bdrv_child_cb_inactivate,
+    .can_set_aio_ctx = bdrv_child_cb_can_set_aio_ctx,
+    .set_aio_ctx     = bdrv_child_cb_set_aio_ctx,
 };
 
 /*
@@ -1029,6 +1045,8 @@ const BdrvChildRole child_format = {
     .attach          = bdrv_child_cb_attach,
     .detach          = bdrv_child_cb_detach,
     .inactivate      = bdrv_child_cb_inactivate,
+    .can_set_aio_ctx = bdrv_child_cb_can_set_aio_ctx,
+    .set_aio_ctx     = bdrv_child_cb_set_aio_ctx,
 };
 
 static void bdrv_backing_attach(BdrvChild *c)
@@ -1152,6 +1170,8 @@ const BdrvChildRole child_backing = {
     .drained_end     = bdrv_child_cb_drained_end,
     .inactivate      = bdrv_child_cb_inactivate,
     .update_filename = bdrv_backing_update_filename,
+    .can_set_aio_ctx = bdrv_child_cb_can_set_aio_ctx,
+    .set_aio_ctx     = bdrv_child_cb_set_aio_ctx,
 };
 
 static int bdrv_open_flags(BlockDriverState *bs, int flags)
@@ -1689,6 +1709,8 @@ static int bdrv_child_check_perm(BdrvChild *c, BlockReopenQueue *q,
                                  GSList *ignore_children, Error **errp);
 static void bdrv_child_abort_perm_update(BdrvChild *c);
 static void bdrv_child_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared);
+static void bdrv_get_cumulative_perm(BlockDriverState *bs, uint64_t *perm,
+                                     uint64_t *shared_perm);
 
 typedef struct BlockReopenQueueEntry {
      bool prepared;
@@ -1775,7 +1797,20 @@ static int bdrv_check_perm(BlockDriverState *bs, BlockReopenQueue *q,
     if ((cumulative_perms & (BLK_PERM_WRITE | BLK_PERM_WRITE_UNCHANGED)) &&
         !bdrv_is_writable_after_reopen(bs, q))
     {
-        error_setg(errp, "Block node is read-only");
+        if (!bdrv_is_writable_after_reopen(bs, NULL)) {
+            error_setg(errp, "Block node is read-only");
+        } else {
+            uint64_t current_perms, current_shared;
+            bdrv_get_cumulative_perm(bs, &current_perms, &current_shared);
+            if (current_perms & (BLK_PERM_WRITE | BLK_PERM_WRITE_UNCHANGED)) {
+                error_setg(errp, "Cannot make block node read-only, there is "
+                           "a writer on it");
+            } else {
+                error_setg(errp, "Cannot make block node read-only and create "
+                           "a writer on it");
+            }
+        }
+
         return -EPERM;
     }
 
@@ -5666,10 +5701,9 @@ static void bdrv_do_remove_aio_context_notifier(BdrvAioNotifier *ban)
     g_free(ban);
 }
 
-void bdrv_detach_aio_context(BlockDriverState *bs)
+static void bdrv_detach_aio_context(BlockDriverState *bs)
 {
     BdrvAioNotifier *baf, *baf_tmp;
-    BdrvChild *child;
 
     assert(!bs->walking_aio_notifiers);
     bs->walking_aio_notifiers = true;
@@ -5688,9 +5722,6 @@ void bdrv_detach_aio_context(BlockDriverState *bs)
     if (bs->drv && bs->drv->bdrv_detach_aio_context) {
         bs->drv->bdrv_detach_aio_context(bs);
     }
-    QLIST_FOREACH(child, &bs->children, next) {
-        bdrv_detach_aio_context(child->bs);
-    }
 
     if (bs->quiesce_counter) {
         aio_enable_external(bs->aio_context);
@@ -5698,11 +5729,10 @@ void bdrv_detach_aio_context(BlockDriverState *bs)
     bs->aio_context = NULL;
 }
 
-void bdrv_attach_aio_context(BlockDriverState *bs,
-                             AioContext *new_context)
+static void bdrv_attach_aio_context(BlockDriverState *bs,
+                                    AioContext *new_context)
 {
     BdrvAioNotifier *ban, *ban_tmp;
-    BdrvChild *child;
 
     if (bs->quiesce_counter) {
         aio_disable_external(new_context);
@@ -5710,9 +5740,6 @@ void bdrv_attach_aio_context(BlockDriverState *bs,
 
     bs->aio_context = new_context;
 
-    QLIST_FOREACH(child, &bs->children, next) {
-        bdrv_attach_aio_context(child->bs, new_context);
-    }
     if (bs->drv && bs->drv->bdrv_attach_aio_context) {
         bs->drv->bdrv_attach_aio_context(bs, new_context);
     }
@@ -5729,16 +5756,36 @@ void bdrv_attach_aio_context(BlockDriverState *bs,
     bs->walking_aio_notifiers = false;
 }
 
-/* The caller must own the AioContext lock for the old AioContext of bs, but it
- * must not own the AioContext lock for new_context (unless new_context is
- * the same as the current context of bs). */
-void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context)
+/* @ignore will accumulate all visited BdrvChild object. The caller is
+ * responsible for freeing the list afterwards. */
+void bdrv_set_aio_context_ignore(BlockDriverState *bs,
+                                 AioContext *new_context, GSList **ignore)
 {
+    BdrvChild *child;
+
     if (bdrv_get_aio_context(bs) == new_context) {
         return;
     }
 
     bdrv_drained_begin(bs);
+
+    QLIST_FOREACH(child, &bs->children, next) {
+        if (g_slist_find(*ignore, child)) {
+            continue;
+        }
+        *ignore = g_slist_prepend(*ignore, child);
+        bdrv_set_aio_context_ignore(child->bs, new_context, ignore);
+    }
+    QLIST_FOREACH(child, &bs->parents, next_parent) {
+        if (g_slist_find(*ignore, child)) {
+            continue;
+        }
+        if (child->role->set_aio_ctx) {
+            *ignore = g_slist_prepend(*ignore, child);
+            child->role->set_aio_ctx(child, new_context, ignore);
+        }
+    }
+
     bdrv_detach_aio_context(bs);
 
     /* This function executes in the old AioContext so acquire the new one in
@@ -5750,6 +5797,101 @@ void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context)
     aio_context_release(new_context);
 }
 
+/* The caller must own the AioContext lock for the old AioContext of bs, but it
+ * must not own the AioContext lock for new_context (unless new_context is
+ * the same as the current context of bs). */
+void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context)
+{
+    GSList *ignore_list = NULL;
+    bdrv_set_aio_context_ignore(bs, new_context, &ignore_list);
+    g_slist_free(ignore_list);
+}
+
+static bool bdrv_parent_can_set_aio_context(BdrvChild *c, AioContext *ctx,
+                                            GSList **ignore, Error **errp)
+{
+    if (g_slist_find(*ignore, c)) {
+        return true;
+    }
+    *ignore = g_slist_prepend(*ignore, c);
+
+    /* A BdrvChildRole that doesn't handle AioContext changes cannot
+     * tolerate any AioContext changes */
+    if (!c->role->can_set_aio_ctx) {
+        char *user = bdrv_child_user_desc(c);
+        error_setg(errp, "Changing iothreads is not supported by %s", user);
+        g_free(user);
+        return false;
+    }
+    if (!c->role->can_set_aio_ctx(c, ctx, ignore, errp)) {
+        assert(!errp || *errp);
+        return false;
+    }
+    return true;
+}
+
+bool bdrv_child_can_set_aio_context(BdrvChild *c, AioContext *ctx,
+                                    GSList **ignore, Error **errp)
+{
+    if (g_slist_find(*ignore, c)) {
+        return true;
+    }
+    *ignore = g_slist_prepend(*ignore, c);
+    return bdrv_can_set_aio_context(c->bs, ctx, ignore, errp);
+}
+
+/* @ignore will accumulate all visited BdrvChild object. The caller is
+ * responsible for freeing the list afterwards. */
+bool bdrv_can_set_aio_context(BlockDriverState *bs, AioContext *ctx,
+                              GSList **ignore, Error **errp)
+{
+    BdrvChild *c;
+
+    if (bdrv_get_aio_context(bs) == ctx) {
+        return true;
+    }
+
+    QLIST_FOREACH(c, &bs->parents, next_parent) {
+        if (!bdrv_parent_can_set_aio_context(c, ctx, ignore, errp)) {
+            return false;
+        }
+    }
+    QLIST_FOREACH(c, &bs->children, next) {
+        if (!bdrv_child_can_set_aio_context(c, ctx, ignore, errp)) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+int bdrv_child_try_set_aio_context(BlockDriverState *bs, AioContext *ctx,
+                                   BdrvChild *ignore_child, Error **errp)
+{
+    GSList *ignore;
+    bool ret;
+
+    ignore = ignore_child ? g_slist_prepend(NULL, ignore_child) : NULL;
+    ret = bdrv_can_set_aio_context(bs, ctx, &ignore, errp);
+    g_slist_free(ignore);
+
+    if (!ret) {
+        return -EPERM;
+    }
+
+    ignore = ignore_child ? g_slist_prepend(NULL, ignore_child) : NULL;
+    bdrv_set_aio_context_ignore(bs, ctx, &ignore);
+    g_slist_free(ignore);
+
+    return 0;
+}
+
+int bdrv_try_set_aio_context(BlockDriverState *bs, AioContext *ctx,
+                             Error **errp)
+{
+    return bdrv_child_try_set_aio_context(bs, ctx, NULL, errp);
+}
+
 void bdrv_add_aio_context_notifier(BlockDriverState *bs,
         void (*attached_aio_context)(AioContext *new_context, void *opaque),
         void (*detach_aio_context)(void *opaque), void *opaque)
diff --git a/block/backup.c b/block/backup.c
index 910ed764aa..916817d8b1 100644
--- a/block/backup.c
+++ b/block/backup.c
@@ -300,13 +300,6 @@ static void backup_clean(Job *job)
     s->target = NULL;
 }
 
-static void backup_attached_aio_context(BlockJob *job, AioContext *aio_context)
-{
-    BackupBlockJob *s = container_of(job, BackupBlockJob, common);
-
-    blk_set_aio_context(s->target, aio_context);
-}
-
 void backup_do_checkpoint(BlockJob *job, Error **errp)
 {
     BackupBlockJob *backup_job = container_of(job, BackupBlockJob, common);
@@ -558,7 +551,6 @@ static const BlockJobDriver backup_job_driver = {
         .abort                  = backup_abort,
         .clean                  = backup_clean,
     },
-    .attached_aio_context   = backup_attached_aio_context,
     .drain                  = backup_drain,
 };
 
diff --git a/block/block-backend.c b/block/block-backend.c
index f78e82a707..4c0a8ef88d 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -71,6 +71,7 @@ struct BlockBackend {
     uint64_t shared_perm;
     bool disable_perm;
 
+    bool allow_aio_context_change;
     bool allow_write_beyond_eof;
 
     NotifierList remove_bs_notifiers, insert_bs_notifiers;
@@ -124,6 +125,11 @@ static void blk_root_drained_end(BdrvChild *child);
 static void blk_root_change_media(BdrvChild *child, bool load);
 static void blk_root_resize(BdrvChild *child);
 
+static bool blk_root_can_set_aio_ctx(BdrvChild *child, AioContext *ctx,
+                                     GSList **ignore, Error **errp);
+static void blk_root_set_aio_ctx(BdrvChild *child, AioContext *ctx,
+                                 GSList **ignore);
+
 static char *blk_root_get_parent_desc(BdrvChild *child)
 {
     BlockBackend *blk = child->opaque;
@@ -300,6 +306,9 @@ static const BdrvChildRole child_root = {
 
     .attach             = blk_root_attach,
     .detach             = blk_root_detach,
+
+    .can_set_aio_ctx    = blk_root_can_set_aio_ctx,
+    .set_aio_ctx        = blk_root_set_aio_ctx,
 };
 
 /*
@@ -1084,6 +1093,11 @@ void blk_set_allow_write_beyond_eof(BlockBackend *blk, bool allow)
     blk->allow_write_beyond_eof = allow;
 }
 
+void blk_set_allow_aio_context_change(BlockBackend *blk, bool allow)
+{
+    blk->allow_aio_context_change = allow;
+}
+
 static int blk_check_byte_request(BlockBackend *blk, int64_t offset,
                                   size_t size)
 {
@@ -1852,7 +1866,8 @@ static AioContext *blk_aiocb_get_aio_context(BlockAIOCB *acb)
     return blk_get_aio_context(blk_acb->blk);
 }
 
-void blk_set_aio_context(BlockBackend *blk, AioContext *new_context)
+static void blk_do_set_aio_context(BlockBackend *blk, AioContext *new_context,
+                                   bool update_root_node)
 {
     BlockDriverState *bs = blk_bs(blk);
     ThrottleGroupMember *tgm = &blk->public.throttle_group_member;
@@ -1864,10 +1879,46 @@ void blk_set_aio_context(BlockBackend *blk, AioContext *new_context)
             throttle_group_attach_aio_context(tgm, new_context);
             bdrv_drained_end(bs);
         }
-        bdrv_set_aio_context(bs, new_context);
+        if (update_root_node) {
+            GSList *ignore = g_slist_prepend(NULL, blk->root);
+            bdrv_set_aio_context_ignore(bs, new_context, &ignore);
+            g_slist_free(ignore);
+        }
     }
 }
 
+void blk_set_aio_context(BlockBackend *blk, AioContext *new_context)
+{
+    blk_do_set_aio_context(blk, new_context, true);
+}
+
+static bool blk_root_can_set_aio_ctx(BdrvChild *child, AioContext *ctx,
+                                     GSList **ignore, Error **errp)
+{
+    BlockBackend *blk = child->opaque;
+
+    if (blk->allow_aio_context_change) {
+        return true;
+    }
+
+    /* Only manually created BlockBackends that are not attached to anything
+     * can change their AioContext without updating their user. */
+    if (!blk->name || blk->dev) {
+        /* TODO Add BB name/QOM path */
+        error_setg(errp, "Cannot change iothread of active block backend");
+        return false;
+    }
+
+    return true;
+}
+
+static void blk_root_set_aio_ctx(BdrvChild *child, AioContext *ctx,
+                                 GSList **ignore)
+{
+    BlockBackend *blk = child->opaque;
+    blk_do_set_aio_context(blk, ctx, false);
+}
+
 void blk_add_aio_context_notifier(BlockBackend *blk,
         void (*attached_aio_context)(AioContext *new_context, void *opaque),
         void (*detach_aio_context)(void *opaque), void *opaque)
diff --git a/block/file-posix.c b/block/file-posix.c
index 1cf4ee49eb..d018429672 100644
--- a/block/file-posix.c
+++ b/block/file-posix.c
@@ -1444,9 +1444,22 @@ out:
 #ifdef CONFIG_XFS
 static int xfs_write_zeroes(BDRVRawState *s, int64_t offset, uint64_t bytes)
 {
+    int64_t len;
     struct xfs_flock64 fl;
     int err;
 
+    len = lseek(s->fd, 0, SEEK_END);
+    if (len < 0) {
+        return -errno;
+    }
+
+    if (offset + bytes > len) {
+        /* XFS_IOC_ZERO_RANGE does not increase the file length */
+        if (ftruncate(s->fd, offset + bytes) < 0) {
+            return -errno;
+        }
+    }
+
     memset(&fl, 0, sizeof(fl));
     fl.l_whence = SEEK_SET;
     fl.l_start = offset;
@@ -2475,6 +2488,8 @@ static int coroutine_fn raw_co_block_status(BlockDriverState *bs,
     off_t data = 0, hole = 0;
     int ret;
 
+    assert(QEMU_IS_ALIGNED(offset | bytes, bs->bl.request_alignment));
+
     ret = fd_open(bs);
     if (ret < 0) {
         return ret;
@@ -2500,6 +2515,20 @@ static int coroutine_fn raw_co_block_status(BlockDriverState *bs,
         /* On a data extent, compute bytes to the end of the extent,
          * possibly including a partial sector at EOF. */
         *pnum = MIN(bytes, hole - offset);
+
+        /*
+         * We are not allowed to return partial sectors, though, so
+         * round up if necessary.
+         */
+        if (!QEMU_IS_ALIGNED(*pnum, bs->bl.request_alignment)) {
+            int64_t file_length = raw_getlength(bs);
+            if (file_length > 0) {
+                /* Ignore errors, this is just a safeguard */
+                assert(hole == file_length);
+            }
+            *pnum = ROUND_UP(*pnum, bs->bl.request_alignment);
+        }
+
         ret = BDRV_BLOCK_DATA;
     } else {
         /* On a hole, compute bytes to the beginning of the next extent.  */
diff --git a/block/io.c b/block/io.c
index aeebc9c23c..3134a60a48 100644
--- a/block/io.c
+++ b/block/io.c
@@ -769,7 +769,7 @@ static bool coroutine_fn wait_serialising_requests(BdrvTrackedRequest *self)
 static int bdrv_check_byte_request(BlockDriverState *bs, int64_t offset,
                                    size_t size)
 {
-    if (size > BDRV_REQUEST_MAX_SECTORS << BDRV_SECTOR_BITS) {
+    if (size > BDRV_REQUEST_MAX_BYTES) {
         return -EIO;
     }
 
@@ -1017,7 +1017,7 @@ static int coroutine_fn bdrv_driver_preadv(BlockDriverState *bs,
 
     assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0);
     assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0);
-    assert((bytes >> BDRV_SECTOR_BITS) <= BDRV_REQUEST_MAX_SECTORS);
+    assert(bytes <= BDRV_REQUEST_MAX_BYTES);
     assert(drv->bdrv_co_readv);
 
     return drv->bdrv_co_readv(bs, sector_num, nb_sectors, qiov);
@@ -1070,7 +1070,7 @@ static int coroutine_fn bdrv_driver_pwritev(BlockDriverState *bs,
 
     assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0);
     assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0);
-    assert((bytes >> BDRV_SECTOR_BITS) <= BDRV_REQUEST_MAX_SECTORS);
+    assert(bytes <= BDRV_REQUEST_MAX_BYTES);
 
     assert(drv->bdrv_co_writev);
     ret = drv->bdrv_co_writev(bs, sector_num, nb_sectors, qiov,
diff --git a/block/mirror.c b/block/mirror.c
index ff15cfb197..ec4bd9f404 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -1142,13 +1142,6 @@ static bool mirror_drained_poll(BlockJob *job)
     return !!s->in_flight;
 }
 
-static void mirror_attached_aio_context(BlockJob *job, AioContext *new_context)
-{
-    MirrorBlockJob *s = container_of(job, MirrorBlockJob, common);
-
-    blk_set_aio_context(s->target, new_context);
-}
-
 static void mirror_drain(BlockJob *job)
 {
     MirrorBlockJob *s = container_of(job, MirrorBlockJob, common);
@@ -1178,7 +1171,6 @@ static const BlockJobDriver mirror_job_driver = {
         .complete               = mirror_complete,
     },
     .drained_poll           = mirror_drained_poll,
-    .attached_aio_context   = mirror_attached_aio_context,
     .drain                  = mirror_drain,
 };
 
@@ -1196,7 +1188,6 @@ static const BlockJobDriver commit_active_job_driver = {
         .complete               = mirror_complete,
     },
     .drained_poll           = mirror_drained_poll,
-    .attached_aio_context   = mirror_attached_aio_context,
     .drain                  = mirror_drain,
 };
 
@@ -1612,6 +1603,7 @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs,
          * ensure that. */
         blk_set_force_allow_inactivate(s->target);
     }
+    blk_set_allow_aio_context_change(s->target, true);
 
     s->replaces = g_strdup(replaces);
     s->on_source_error = on_source_error;
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 974a4e8656..b36f4aa84a 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -796,8 +796,9 @@ int qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
         return cluster_offset;
     }
 
-    nb_csectors = ((cluster_offset + compressed_size - 1) >> 9) -
-                  (cluster_offset >> 9);
+    nb_csectors =
+        (cluster_offset + compressed_size - 1) / QCOW2_COMPRESSED_SECTOR_SIZE -
+        (cluster_offset / QCOW2_COMPRESSED_SECTOR_SIZE);
 
     cluster_offset |= QCOW_OFLAG_COMPRESSED |
                       ((uint64_t)nb_csectors << s->csize_shift);
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index 7481903396..0b09d6838b 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -1172,12 +1172,11 @@ void qcow2_free_any_clusters(BlockDriverState *bs, uint64_t l2_entry,
     switch (ctype) {
     case QCOW2_CLUSTER_COMPRESSED:
         {
-            int nb_csectors;
-            nb_csectors = ((l2_entry >> s->csize_shift) &
-                           s->csize_mask) + 1;
-            qcow2_free_clusters(bs,
-                (l2_entry & s->cluster_offset_mask) & ~511,
-                nb_csectors * 512, type);
+            int64_t offset = (l2_entry & s->cluster_offset_mask)
+                & QCOW2_COMPRESSED_SECTOR_MASK;
+            int size = QCOW2_COMPRESSED_SECTOR_SIZE *
+                (((l2_entry >> s->csize_shift) & s->csize_mask) + 1);
+            qcow2_free_clusters(bs, offset, size, type);
         }
         break;
     case QCOW2_CLUSTER_NORMAL:
@@ -1317,9 +1316,12 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
                         nb_csectors = ((entry >> s->csize_shift) &
                                        s->csize_mask) + 1;
                         if (addend != 0) {
+                            uint64_t coffset = (entry & s->cluster_offset_mask)
+                                & QCOW2_COMPRESSED_SECTOR_MASK;
                             ret = update_refcount(
-                                bs, (entry & s->cluster_offset_mask) & ~511,
-                                nb_csectors * 512, abs(addend), addend < 0,
+                                bs, coffset,
+                                nb_csectors * QCOW2_COMPRESSED_SECTOR_SIZE,
+                                abs(addend), addend < 0,
                                 QCOW2_DISCARD_SNAPSHOT);
                             if (ret < 0) {
                                 goto fail;
@@ -1635,9 +1637,10 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
             nb_csectors = ((l2_entry >> s->csize_shift) &
                            s->csize_mask) + 1;
             l2_entry &= s->cluster_offset_mask;
-            ret = qcow2_inc_refcounts_imrt(bs, res,
-                                           refcount_table, refcount_table_size,
-                                           l2_entry & ~511, nb_csectors * 512);
+            ret = qcow2_inc_refcounts_imrt(
+                bs, res, refcount_table, refcount_table_size,
+                l2_entry & QCOW2_COMPRESSED_SECTOR_MASK,
+                nb_csectors * QCOW2_COMPRESSED_SECTOR_SIZE);
             if (ret < 0) {
                 goto fail;
             }
diff --git a/block/qcow2.c b/block/qcow2.c
index 8e024007db..d39882785d 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -4187,7 +4187,8 @@ qcow2_co_preadv_compressed(BlockDriverState *bs,
 
     coffset = file_cluster_offset & s->cluster_offset_mask;
     nb_csectors = ((file_cluster_offset >> s->csize_shift) & s->csize_mask) + 1;
-    csize = nb_csectors * 512 - (coffset & 511);
+    csize = nb_csectors * QCOW2_COMPRESSED_SECTOR_SIZE -
+        (coffset & ~QCOW2_COMPRESSED_SECTOR_MASK);
 
     buf = g_try_malloc(csize);
     if (!buf) {
diff --git a/block/qcow2.h b/block/qcow2.h
index e62508d1ce..8d92ef1fee 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -74,6 +74,10 @@
 #define MIN_CLUSTER_BITS 9
 #define MAX_CLUSTER_BITS 21
 
+/* Defined in the qcow2 spec (compressed cluster descriptor) */
+#define QCOW2_COMPRESSED_SECTOR_SIZE 512U
+#define QCOW2_COMPRESSED_SECTOR_MASK (~(QCOW2_COMPRESSED_SECTOR_SIZE - 1))
+
 /* Must be at least 2 to cover COW */
 #define MIN_L2_CACHE_SIZE 2 /* cache entries */
 
diff --git a/blockjob.c b/blockjob.c
index 730101d282..9ca942ba01 100644
--- a/blockjob.c
+++ b/blockjob.c
@@ -81,10 +81,6 @@ BlockJob *block_job_get(const char *id)
     }
 }
 
-static void block_job_attached_aio_context(AioContext *new_context,
-                                           void *opaque);
-static void block_job_detach_aio_context(void *opaque);
-
 void block_job_free(Job *job)
 {
     BlockJob *bjob = container_of(job, BlockJob, job);
@@ -92,28 +88,10 @@ void block_job_free(Job *job)
 
     bs->job = NULL;
     block_job_remove_all_bdrv(bjob);
-    blk_remove_aio_context_notifier(bjob->blk,
-                                    block_job_attached_aio_context,
-                                    block_job_detach_aio_context, bjob);
     blk_unref(bjob->blk);
     error_free(bjob->blocker);
 }
 
-static void block_job_attached_aio_context(AioContext *new_context,
-                                           void *opaque)
-{
-    BlockJob *job = opaque;
-    const JobDriver *drv = job->job.driver;
-    BlockJobDriver *bjdrv = container_of(drv, BlockJobDriver, job_driver);
-
-    job->job.aio_context = new_context;
-    if (bjdrv->attached_aio_context) {
-        bjdrv->attached_aio_context(job, new_context);
-    }
-
-    job_resume(&job->job);
-}
-
 void block_job_drain(Job *job)
 {
     BlockJob *bjob = container_of(job, BlockJob, job);
@@ -126,23 +104,6 @@ void block_job_drain(Job *job)
     }
 }
 
-static void block_job_detach_aio_context(void *opaque)
-{
-    BlockJob *job = opaque;
-
-    /* In case the job terminates during aio_poll()... */
-    job_ref(&job->job);
-
-    job_pause(&job->job);
-
-    while (!job->job.paused && !job_is_completed(&job->job)) {
-        job_drain(&job->job);
-    }
-
-    job->job.aio_context = NULL;
-    job_unref(&job->job);
-}
-
 static char *child_job_get_parent_desc(BdrvChild *c)
 {
     BlockJob *job = c->opaque;
@@ -183,11 +144,46 @@ static void child_job_drained_end(BdrvChild *c)
     job_resume(&job->job);
 }
 
+static bool child_job_can_set_aio_ctx(BdrvChild *c, AioContext *ctx,
+                                      GSList **ignore, Error **errp)
+{
+    BlockJob *job = c->opaque;
+    GSList *l;
+
+    for (l = job->nodes; l; l = l->next) {
+        BdrvChild *sibling = l->data;
+        if (!bdrv_child_can_set_aio_context(sibling, ctx, ignore, errp)) {
+            return false;
+        }
+    }
+    return true;
+}
+
+static void child_job_set_aio_ctx(BdrvChild *c, AioContext *ctx,
+                                  GSList **ignore)
+{
+    BlockJob *job = c->opaque;
+    GSList *l;
+
+    for (l = job->nodes; l; l = l->next) {
+        BdrvChild *sibling = l->data;
+        if (g_slist_find(*ignore, sibling)) {
+            continue;
+        }
+        *ignore = g_slist_prepend(*ignore, sibling);
+        bdrv_set_aio_context_ignore(sibling->bs, ctx, ignore);
+    }
+
+    job->job.aio_context = ctx;
+}
+
 static const BdrvChildRole child_job = {
     .get_parent_desc    = child_job_get_parent_desc,
     .drained_begin      = child_job_drained_begin,
     .drained_poll       = child_job_drained_poll,
     .drained_end        = child_job_drained_end,
+    .can_set_aio_ctx    = child_job_can_set_aio_ctx,
+    .set_aio_ctx        = child_job_set_aio_ctx,
     .stay_at_node       = true,
 };
 
@@ -438,8 +434,7 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
 
     bdrv_op_unblock(bs, BLOCK_OP_TYPE_DATAPLANE, job->blocker);
 
-    blk_add_aio_context_notifier(blk, block_job_attached_aio_context,
-                                 block_job_detach_aio_context, job);
+    blk_set_allow_aio_context_change(blk, true);
 
     /* Only set speed when necessary to avoid NotSupported error */
     if (speed != 0) {
diff --git a/configure b/configure
index 8999698bc2..d2fc346302 100755
--- a/configure
+++ b/configure
@@ -6079,7 +6079,9 @@ fi
 # Probe for guest agent support/options
 
 if [ "$guest_agent" != "no" ]; then
-  if [ "$linux" = "yes" -o "$bsd" = "yes" -o "$solaris" = "yes" -o "$mingw32" = "yes" ] ; then
+  if [ "$softmmu" = no -a "$want_tools" = no ] ; then
+      guest_agent=no
+  elif [ "$linux" = "yes" -o "$bsd" = "yes" -o "$solaris" = "yes" -o "$mingw32" = "yes" ] ; then
       tools="qemu-ga $tools"
       guest_agent=yes
   elif [ "$guest_agent" != yes ]; then
diff --git a/contrib/libvhost-user/libvhost-user.c b/contrib/libvhost-user/libvhost-user.c
index 74d42177c5..3825b1cacf 100644
--- a/contrib/libvhost-user/libvhost-user.c
+++ b/contrib/libvhost-user/libvhost-user.c
@@ -433,7 +433,7 @@ vu_log_write(VuDev *dev, uint64_t address, uint64_t length)
     page = address / VHOST_LOG_PAGE;
     while (page * VHOST_LOG_PAGE < address + length) {
         vu_log_page(dev->log_table, page);
-        page += VHOST_LOG_PAGE;
+        page += 1;
     }
 
     vu_log_kick(dev);
diff --git a/contrib/vhost-user-blk/vhost-user-blk.c b/contrib/vhost-user-blk/vhost-user-blk.c
index 43583f2659..86a3987744 100644
--- a/contrib/vhost-user-blk/vhost-user-blk.c
+++ b/contrib/vhost-user-blk/vhost-user-blk.c
@@ -398,7 +398,8 @@ vub_get_features(VuDev *dev)
 static uint64_t
 vub_get_protocol_features(VuDev *dev)
 {
-    return 1ull << VHOST_USER_PROTOCOL_F_CONFIG;
+    return 1ull << VHOST_USER_PROTOCOL_F_CONFIG |
+           1ull << VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD;
 }
 
 static int
diff --git a/docs/interop/index.rst b/docs/interop/index.rst
index 2df977dd52..a037bd67ec 100644
--- a/docs/interop/index.rst
+++ b/docs/interop/index.rst
@@ -15,4 +15,4 @@ Contents:
    bitmaps
    live-block-operations
    pr-helper
-
+   vhost-user
diff --git a/docs/interop/vhost-user.rst b/docs/interop/vhost-user.rst
new file mode 100644
index 0000000000..7f3232c798
--- /dev/null
+++ b/docs/interop/vhost-user.rst
@@ -0,0 +1,1351 @@
+===================
+Vhost-user Protocol
+===================
+:Copyright: 2014 Virtual Open Systems Sarl.
+:Licence: This work is licensed under the terms of the GNU GPL,
+          version 2 or later. See the COPYING file in the top-level
+          directory.
+
+.. contents:: Table of Contents
+
+Introduction
+============
+
+This protocol is aiming to complement the ``ioctl`` interface used to
+control the vhost implementation in the Linux kernel. It implements
+the control plane needed to establish virtqueue sharing with a user
+space process on the same host. It uses communication over a Unix
+domain socket to share file descriptors in the ancillary data of the
+message.
+
+The protocol defines 2 sides of the communication, *master* and
+*slave*. *Master* is the application that shares its virtqueues, in
+our case QEMU. *Slave* is the consumer of the virtqueues.
+
+In the current implementation QEMU is the *master*, and the *slave* is
+the external process consuming the virtio queues, for example a
+software Ethernet switch running in user space, such as Snabbswitch,
+or a block device backend processing read & write to a virtual
+disk. In order to facilitate interoperability between various backend
+implementations, it is recommended to follow the :ref:`Backend program
+conventions <backend_conventions>`.
+
+*Master* and *slave* can be either a client (i.e. connecting) or
+server (listening) in the socket communication.
+
+Message Specification
+=====================
+
+.. Note:: All numbers are in the machine native byte order.
+
+A vhost-user message consists of 3 header fields and a payload.
+
++---------+-------+------+---------+
+| request | flags | size | payload |
++---------+-------+------+---------+
+
+Header
+------
+
+:request: 32-bit type of the request
+
+:flags: 32-bit bit field
+
+- Lower 2 bits are the version (currently 0x01)
+- Bit 2 is the reply flag - needs to be sent on each reply from the slave
+- Bit 3 is the need_reply flag - see :ref:`REPLY_ACK <reply_ack>` for
+  details.
+
+:size: 32-bit size of the payload
+
+Payload
+-------
+
+Depending on the request type, **payload** can be:
+
+A single 64-bit integer
+^^^^^^^^^^^^^^^^^^^^^^^
+
++-----+
+| u64 |
++-----+
+
+:u64: a 64-bit unsigned integer
+
+A vring state description
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
++-------+-----+
+| index | num |
++-------+-----+
+
+:index: a 32-bit index
+
+:num: a 32-bit number
+
+A vring address description
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
++-------+-------+------+------------+------+-----------+-----+
+| index | flags | size | descriptor | used | available | log |
++-------+-------+------+------------+------+-----------+-----+
+
+:index: a 32-bit vring index
+
+:flags: a 32-bit vring flags
+
+:descriptor: a 64-bit ring address of the vring descriptor table
+
+:used: a 64-bit ring address of the vring used ring
+
+:available: a 64-bit ring address of the vring available ring
+
+:log: a 64-bit guest address for logging
+
+Note that a ring address is an IOVA if ``VIRTIO_F_IOMMU_PLATFORM`` has
+been negotiated. Otherwise it is a user address.
+
+Memory regions description
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
++-------------+---------+---------+-----+---------+
+| num regions | padding | region0 | ... | region7 |
++-------------+---------+---------+-----+---------+
+
+:num regions: a 32-bit number of regions
+
+:padding: 32-bit
+
+A region is:
+
++---------------+------+--------------+-------------+
+| guest address | size | user address | mmap offset |
++---------------+------+--------------+-------------+
+
+:guest address: a 64-bit guest address of the region
+
+:size: a 64-bit size
+
+:user address: a 64-bit user address
+
+:mmap offset: 64-bit offset where region starts in the mapped memory
+
+Log description
+^^^^^^^^^^^^^^^
+
++----------+------------+
+| log size | log offset |
++----------+------------+
+
+:log size: size of area used for logging
+
+:log offset: offset from start of supplied file descriptor where
+             logging starts (i.e. where guest address 0 would be
+             logged)
+
+An IOTLB message
+^^^^^^^^^^^^^^^^
+
++------+------+--------------+-------------------+------+
+| iova | size | user address | permissions flags | type |
++------+------+--------------+-------------------+------+
+
+:iova: a 64-bit I/O virtual address programmed by the guest
+
+:size: a 64-bit size
+
+:user address: a 64-bit user address
+
+:permissions flags: an 8-bit value:
+  - 0: No access
+  - 1: Read access
+  - 2: Write access
+  - 3: Read/Write access
+
+:type: an 8-bit IOTLB message type:
+  - 1: IOTLB miss
+  - 2: IOTLB update
+  - 3: IOTLB invalidate
+  - 4: IOTLB access fail
+
+Virtio device config space
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
++--------+------+-------+---------+
+| offset | size | flags | payload |
++--------+------+-------+---------+
+
+:offset: a 32-bit offset of virtio device's configuration space
+
+:size: a 32-bit configuration space access size in bytes
+
+:flags: a 32-bit value:
+  - 0: Vhost master messages used for writeable fields
+  - 1: Vhost master messages used for live migration
+
+:payload: Size bytes array holding the contents of the virtio
+          device's configuration space
+
+Vring area description
+^^^^^^^^^^^^^^^^^^^^^^
+
++-----+------+--------+
+| u64 | size | offset |
++-----+------+--------+
+
+:u64: a 64-bit integer contains vring index and flags
+
+:size: a 64-bit size of this area
+
+:offset: a 64-bit offset of this area from the start of the
+         supplied file descriptor
+
+Inflight description
+^^^^^^^^^^^^^^^^^^^^
+
++-----------+-------------+------------+------------+
+| mmap size | mmap offset | num queues | queue size |
++-----------+-------------+------------+------------+
+
+:mmap size: a 64-bit size of area to track inflight I/O
+
+:mmap offset: a 64-bit offset of this area from the start
+              of the supplied file descriptor
+
+:num queues: a 16-bit number of virtqueues
+
+:queue size: a 16-bit size of virtqueues
+
+C structure
+-----------
+
+In QEMU the vhost-user message is implemented with the following struct:
+
+.. code:: c
+
+  typedef struct VhostUserMsg {
+      VhostUserRequest request;
+      uint32_t flags;
+      uint32_t size;
+      union {
+          uint64_t u64;
+          struct vhost_vring_state state;
+          struct vhost_vring_addr addr;
+          VhostUserMemory memory;
+          VhostUserLog log;
+          struct vhost_iotlb_msg iotlb;
+          VhostUserConfig config;
+          VhostUserVringArea area;
+          VhostUserInflight inflight;
+      };
+  } QEMU_PACKED VhostUserMsg;
+
+Communication
+=============
+
+The protocol for vhost-user is based on the existing implementation of
+vhost for the Linux Kernel. Most messages that can be sent via the
+Unix domain socket implementing vhost-user have an equivalent ioctl to
+the kernel implementation.
+
+The communication consists of *master* sending message requests and
+*slave* sending message replies. Most of the requests don't require
+replies. Here is a list of the ones that do:
+
+* ``VHOST_USER_GET_FEATURES``
+* ``VHOST_USER_GET_PROTOCOL_FEATURES``
+* ``VHOST_USER_GET_VRING_BASE``
+* ``VHOST_USER_SET_LOG_BASE`` (if ``VHOST_USER_PROTOCOL_F_LOG_SHMFD``)
+* ``VHOST_USER_GET_INFLIGHT_FD`` (if ``VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD``)
+
+.. seealso::
+
+   :ref:`REPLY_ACK <reply_ack>`
+       The section on ``REPLY_ACK`` protocol extension.
+
+There are several messages that the master sends with file descriptors passed
+in the ancillary data:
+
+* ``VHOST_USER_SET_MEM_TABLE``
+* ``VHOST_USER_SET_LOG_BASE`` (if ``VHOST_USER_PROTOCOL_F_LOG_SHMFD``)
+* ``VHOST_USER_SET_LOG_FD``
+* ``VHOST_USER_SET_VRING_KICK``
+* ``VHOST_USER_SET_VRING_CALL``
+* ``VHOST_USER_SET_VRING_ERR``
+* ``VHOST_USER_SET_SLAVE_REQ_FD``
+* ``VHOST_USER_SET_INFLIGHT_FD`` (if ``VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD``)
+
+If *master* is unable to send the full message or receives a wrong
+reply it will close the connection. An optional reconnection mechanism
+can be implemented.
+
+Any protocol extensions are gated by protocol feature bits, which
+allows full backwards compatibility on both master and slave.  As
+older slaves don't support negotiating protocol features, a feature
+bit was dedicated for this purpose::
+
+  #define VHOST_USER_F_PROTOCOL_FEATURES 30
+
+Starting and stopping rings
+---------------------------
+
+Client must only process each ring when it is started.
+
+Client must only pass data between the ring and the backend, when the
+ring is enabled.
+
+If ring is started but disabled, client must process the ring without
+talking to the backend.
+
+For example, for a networking device, in the disabled state client
+must not supply any new RX packets, but must process and discard any
+TX packets.
+
+If ``VHOST_USER_F_PROTOCOL_FEATURES`` has not been negotiated, the
+ring is initialized in an enabled state.
+
+If ``VHOST_USER_F_PROTOCOL_FEATURES`` has been negotiated, the ring is
+initialized in a disabled state. Client must not pass data to/from the
+backend until ring is enabled by ``VHOST_USER_SET_VRING_ENABLE`` with
+parameter 1, or after it has been disabled by
+``VHOST_USER_SET_VRING_ENABLE`` with parameter 0.
+
+Each ring is initialized in a stopped state, client must not process
+it until ring is started, or after it has been stopped.
+
+Client must start ring upon receiving a kick (that is, detecting that
+file descriptor is readable) on the descriptor specified by
+``VHOST_USER_SET_VRING_KICK``, and stop ring upon receiving
+``VHOST_USER_GET_VRING_BASE``.
+
+While processing the rings (whether they are enabled or not), client
+must support changing some configuration aspects on the fly.
+
+Multiple queue support
+----------------------
+
+Multiple queue is treated as a protocol extension, hence the slave has
+to implement protocol features first. The multiple queues feature is
+supported only when the protocol feature ``VHOST_USER_PROTOCOL_F_MQ``
+(bit 0) is set.
+
+The max number of queue pairs the slave supports can be queried with
+message ``VHOST_USER_GET_QUEUE_NUM``. Master should stop when the
+number of requested queues is bigger than that.
+
+As all queues share one connection, the master uses a unique index for each
+queue in the sent message to identify a specified queue. One queue pair
+is enabled initially. More queues are enabled dynamically, by sending
+message ``VHOST_USER_SET_VRING_ENABLE``.
+
+Migration
+---------
+
+During live migration, the master may need to track the modifications
+the slave makes to the memory mapped regions. The client should mark
+the dirty pages in a log. Once it complies to this logging, it may
+declare the ``VHOST_F_LOG_ALL`` vhost feature.
+
+To start/stop logging of data/used ring writes, server may send
+messages ``VHOST_USER_SET_FEATURES`` with ``VHOST_F_LOG_ALL`` and
+``VHOST_USER_SET_VRING_ADDR`` with ``VHOST_VRING_F_LOG`` in ring's
+flags set to 1/0, respectively.
+
+All the modifications to memory pointed by vring "descriptor" should
+be marked. Modifications to "used" vring should be marked if
+``VHOST_VRING_F_LOG`` is part of ring's flags.
+
+Dirty pages are of size::
+
+  #define VHOST_LOG_PAGE 0x1000
+
+The log memory fd is provided in the ancillary data of
+``VHOST_USER_SET_LOG_BASE`` message when the slave has
+``VHOST_USER_PROTOCOL_F_LOG_SHMFD`` protocol feature.
+
+The size of the log is supplied as part of ``VhostUserMsg`` which
+should be large enough to cover all known guest addresses. Log starts
+at the supplied offset in the supplied file descriptor.  The log
+covers from address 0 to the maximum of guest regions. In pseudo-code,
+to mark page at ``addr`` as dirty::
+
+  page = addr / VHOST_LOG_PAGE
+  log[page / 8] |= 1 << page % 8
+
+Where ``addr`` is the guest physical address.
+
+Use atomic operations, as the log may be concurrently manipulated.
+
+Note that when logging modifications to the used ring (when
+``VHOST_VRING_F_LOG`` is set for this ring), ``log_guest_addr`` should
+be used to calculate the log offset: the write to first byte of the
+used ring is logged at this offset from log start. Also note that this
+value might be outside the legal guest physical address range
+(i.e. does not have to be covered by the ``VhostUserMemory`` table), but
+the bit offset of the last byte of the ring must fall within the size
+supplied by ``VhostUserLog``.
+
+``VHOST_USER_SET_LOG_FD`` is an optional message with an eventfd in
+ancillary data, it may be used to inform the master that the log has
+been modified.
+
+Once the source has finished migration, rings will be stopped by the
+source. No further update must be done before rings are restarted.
+
+In postcopy migration the slave is started before all the memory has
+been received from the source host, and care must be taken to avoid
+accessing pages that have yet to be received.  The slave opens a
+'userfault'-fd and registers the memory with it; this fd is then
+passed back over to the master.  The master services requests on the
+userfaultfd for pages that are accessed and when the page is available
+it performs WAKE ioctl's on the userfaultfd to wake the stalled
+slave.  The client indicates support for this via the
+``VHOST_USER_PROTOCOL_F_PAGEFAULT`` feature.
+
+Memory access
+-------------
+
+The master sends a list of vhost memory regions to the slave using the
+``VHOST_USER_SET_MEM_TABLE`` message.  Each region has two base
+addresses: a guest address and a user address.
+
+Messages contain guest addresses and/or user addresses to reference locations
+within the shared memory.  The mapping of these addresses works as follows.
+
+User addresses map to the vhost memory region containing that user address.
+
+When the ``VIRTIO_F_IOMMU_PLATFORM`` feature has not been negotiated:
+
+* Guest addresses map to the vhost memory region containing that guest
+  address.
+
+When the ``VIRTIO_F_IOMMU_PLATFORM`` feature has been negotiated:
+
+* Guest addresses are also called I/O virtual addresses (IOVAs).  They are
+  translated to user addresses via the IOTLB.
+
+* The vhost memory region guest address is not used.
+
+IOMMU support
+-------------
+
+When the ``VIRTIO_F_IOMMU_PLATFORM`` feature has been negotiated, the
+master sends IOTLB entries update & invalidation by sending
+``VHOST_USER_IOTLB_MSG`` requests to the slave with a ``struct
+vhost_iotlb_msg`` as payload. For update events, the ``iotlb`` payload
+has to be filled with the update message type (2), the I/O virtual
+address, the size, the user virtual address, and the permissions
+flags. Addresses and size must be within vhost memory regions set via
+the ``VHOST_USER_SET_MEM_TABLE`` request. For invalidation events, the
+``iotlb`` payload has to be filled with the invalidation message type
+(3), the I/O virtual address and the size. On success, the slave is
+expected to reply with a zero payload, non-zero otherwise.
+
+The slave relies on the slave communcation channel (see :ref:`Slave
+communication <slave_communication>` section below) to send IOTLB miss
+and access failure events, by sending ``VHOST_USER_SLAVE_IOTLB_MSG``
+requests to the master with a ``struct vhost_iotlb_msg`` as
+payload. For miss events, the iotlb payload has to be filled with the
+miss message type (1), the I/O virtual address and the permissions
+flags. For access failure event, the iotlb payload has to be filled
+with the access failure message type (4), the I/O virtual address and
+the permissions flags.  For synchronization purpose, the slave may
+rely on the reply-ack feature, so the master may send a reply when
+operation is completed if the reply-ack feature is negotiated and
+slaves requests a reply. For miss events, completed operation means
+either master sent an update message containing the IOTLB entry
+containing requested address and permission, or master sent nothing if
+the IOTLB miss message is invalid (invalid IOVA or permission).
+
+The master isn't expected to take the initiative to send IOTLB update
+messages, as the slave sends IOTLB miss messages for the guest virtual
+memory areas it needs to access.
+
+.. _slave_communication:
+
+Slave communication
+-------------------
+
+An optional communication channel is provided if the slave declares
+``VHOST_USER_PROTOCOL_F_SLAVE_REQ`` protocol feature, to allow the
+slave to make requests to the master.
+
+The fd is provided via ``VHOST_USER_SET_SLAVE_REQ_FD`` ancillary data.
+
+A slave may then send ``VHOST_USER_SLAVE_*`` messages to the master
+using this fd communication channel.
+
+If ``VHOST_USER_PROTOCOL_F_SLAVE_SEND_FD`` protocol feature is
+negotiated, slave can send file descriptors (at most 8 descriptors in
+each message) to master via ancillary data using this fd communication
+channel.
+
+Inflight I/O tracking
+---------------------
+
+To support reconnecting after restart or crash, slave may need to
+resubmit inflight I/Os. If virtqueue is processed in order, we can
+easily achieve that by getting the inflight descriptors from
+descriptor table (split virtqueue) or descriptor ring (packed
+virtqueue). However, it can't work when we process descriptors
+out-of-order because some entries which store the information of
+inflight descriptors in available ring (split virtqueue) or descriptor
+ring (packed virtqueue) might be overrided by new entries. To solve
+this problem, slave need to allocate an extra buffer to store this
+information of inflight descriptors and share it with master for
+persistent. ``VHOST_USER_GET_INFLIGHT_FD`` and
+``VHOST_USER_SET_INFLIGHT_FD`` are used to transfer this buffer
+between master and slave. And the format of this buffer is described
+below:
+
++---------------+---------------+-----+---------------+
+| queue0 region | queue1 region | ... | queueN region |
++---------------+---------------+-----+---------------+
+
+N is the number of available virtqueues. Slave could get it from num
+queues field of ``VhostUserInflight``.
+
+For split virtqueue, queue region can be implemented as:
+
+.. code:: c
+
+  typedef struct DescStateSplit {
+      /* Indicate whether this descriptor is inflight or not.
+       * Only available for head-descriptor. */
+      uint8_t inflight;
+
+      /* Padding */
+      uint8_t padding[5];
+
+      /* Maintain a list for the last batch of used descriptors.
+       * Only available when batching is used for submitting */
+      uint16_t next;
+
+      /* Used to preserve the order of fetching available descriptors.
+       * Only available for head-descriptor. */
+      uint64_t counter;
+  } DescStateSplit;
+
+  typedef struct QueueRegionSplit {
+      /* The feature flags of this region. Now it's initialized to 0. */
+      uint64_t features;
+
+      /* The version of this region. It's 1 currently.
+       * Zero value indicates an uninitialized buffer */
+      uint16_t version;
+
+      /* The size of DescStateSplit array. It's equal to the virtqueue
+       * size. Slave could get it from queue size field of VhostUserInflight. */
+      uint16_t desc_num;
+
+      /* The head of list that track the last batch of used descriptors. */
+      uint16_t last_batch_head;
+
+      /* Store the idx value of used ring */
+      uint16_t used_idx;
+
+      /* Used to track the state of each descriptor in descriptor table */
+      DescStateSplit desc[0];
+  } QueueRegionSplit;
+
+To track inflight I/O, the queue region should be processed as follows:
+
+When receiving available buffers from the driver:
+
+#. Get the next available head-descriptor index from available ring, ``i``
+
+#. Set ``desc[i].counter`` to the value of global counter
+
+#. Increase global counter by 1
+
+#. Set ``desc[i].inflight`` to 1
+
+When supplying used buffers to the driver:
+
+1. Get corresponding used head-descriptor index, i
+
+2. Set ``desc[i].next`` to ``last_batch_head``
+
+3. Set ``last_batch_head`` to ``i``
+
+#. Steps 1,2,3 may be performed repeatedly if batching is possible
+
+#. Increase the ``idx`` value of used ring by the size of the batch
+
+#. Set the ``inflight`` field of each ``DescStateSplit`` entry in the batch to 0
+
+#. Set ``used_idx`` to the ``idx`` value of used ring
+
+When reconnecting:
+
+#. If the value of ``used_idx`` does not match the ``idx`` value of
+   used ring (means the inflight field of ``DescStateSplit`` entries in
+   last batch may be incorrect),
+
+   a. Subtract the value of ``used_idx`` from the ``idx`` value of
+      used ring to get last batch size of ``DescStateSplit`` entries
+
+   #. Set the ``inflight`` field of each ``DescStateSplit`` entry to 0 in last batch
+      list which starts from ``last_batch_head``
+
+   #. Set ``used_idx`` to the ``idx`` value of used ring
+
+#. Resubmit inflight ``DescStateSplit`` entries in order of their
+   counter value
+
+For packed virtqueue, queue region can be implemented as:
+
+.. code:: c
+
+  typedef struct DescStatePacked {
+      /* Indicate whether this descriptor is inflight or not.
+       * Only available for head-descriptor. */
+      uint8_t inflight;
+
+      /* Padding */
+      uint8_t padding;
+
+      /* Link to the next free entry */
+      uint16_t next;
+
+      /* Link to the last entry of descriptor list.
+       * Only available for head-descriptor. */
+      uint16_t last;
+
+      /* The length of descriptor list.
+       * Only available for head-descriptor. */
+      uint16_t num;
+
+      /* Used to preserve the order of fetching available descriptors.
+       * Only available for head-descriptor. */
+      uint64_t counter;
+
+      /* The buffer id */
+      uint16_t id;
+
+      /* The descriptor flags */
+      uint16_t flags;
+
+      /* The buffer length */
+      uint32_t len;
+
+      /* The buffer address */
+      uint64_t addr;
+  } DescStatePacked;
+
+  typedef struct QueueRegionPacked {
+      /* The feature flags of this region. Now it's initialized to 0. */
+      uint64_t features;
+
+      /* The version of this region. It's 1 currently.
+       * Zero value indicates an uninitialized buffer */
+      uint16_t version;
+
+      /* The size of DescStatePacked array. It's equal to the virtqueue
+       * size. Slave could get it from queue size field of VhostUserInflight. */
+      uint16_t desc_num;
+
+      /* The head of free DescStatePacked entry list */
+      uint16_t free_head;
+
+      /* The old head of free DescStatePacked entry list */
+      uint16_t old_free_head;
+
+      /* The used index of descriptor ring */
+      uint16_t used_idx;
+
+      /* The old used index of descriptor ring */
+      uint16_t old_used_idx;
+
+      /* Device ring wrap counter */
+      uint8_t used_wrap_counter;
+
+      /* The old device ring wrap counter */
+      uint8_t old_used_wrap_counter;
+
+      /* Padding */
+      uint8_t padding[7];
+
+      /* Used to track the state of each descriptor fetched from descriptor ring */
+      DescStatePacked desc[0];
+  } QueueRegionPacked;
+
+To track inflight I/O, the queue region should be processed as follows:
+
+When receiving available buffers from the driver:
+
+#. Get the next available descriptor entry from descriptor ring, ``d``
+
+#. If ``d`` is head descriptor,
+
+   a. Set ``desc[old_free_head].num`` to 0
+
+   #. Set ``desc[old_free_head].counter`` to the value of global counter
+
+   #. Increase global counter by 1
+
+   #. Set ``desc[old_free_head].inflight`` to 1
+
+#. If ``d`` is last descriptor, set ``desc[old_free_head].last`` to
+   ``free_head``
+
+#. Increase ``desc[old_free_head].num`` by 1
+
+#. Set ``desc[free_head].addr``, ``desc[free_head].len``,
+   ``desc[free_head].flags``, ``desc[free_head].id`` to ``d.addr``,
+   ``d.len``, ``d.flags``, ``d.id``
+
+#. Set ``free_head`` to ``desc[free_head].next``
+
+#. If ``d`` is last descriptor, set ``old_free_head`` to ``free_head``
+
+When supplying used buffers to the driver:
+
+1. Get corresponding used head-descriptor entry from descriptor ring,
+   ``d``
+
+2. Get corresponding ``DescStatePacked`` entry, ``e``
+
+3. Set ``desc[e.last].next`` to ``free_head``
+
+4. Set ``free_head`` to the index of ``e``
+
+#. Steps 1,2,3,4 may be performed repeatedly if batching is possible
+
+#. Increase ``used_idx`` by the size of the batch and update
+   ``used_wrap_counter`` if needed
+
+#. Update ``d.flags``
+
+#. Set the ``inflight`` field of each head ``DescStatePacked`` entry
+   in the batch to 0
+
+#. Set ``old_free_head``,  ``old_used_idx``, ``old_used_wrap_counter``
+   to ``free_head``, ``used_idx``, ``used_wrap_counter``
+
+When reconnecting:
+
+#. If ``used_idx`` does not match ``old_used_idx`` (means the
+   ``inflight`` field of ``DescStatePacked`` entries in last batch may
+   be incorrect),
+
+   a. Get the next descriptor ring entry through ``old_used_idx``, ``d``
+
+   #. Use ``old_used_wrap_counter`` to calculate the available flags
+
+   #. If ``d.flags`` is not equal to the calculated flags value (means
+      slave has submitted the buffer to guest driver before crash, so
+      it has to commit the in-progres update), set ``old_free_head``,
+      ``old_used_idx``, ``old_used_wrap_counter`` to ``free_head``,
+      ``used_idx``, ``used_wrap_counter``
+
+#. Set ``free_head``, ``used_idx``, ``used_wrap_counter`` to
+   ``old_free_head``, ``old_used_idx``, ``old_used_wrap_counter``
+   (roll back any in-progress update)
+
+#. Set the ``inflight`` field of each ``DescStatePacked`` entry in
+   free list to 0
+
+#. Resubmit inflight ``DescStatePacked`` entries in order of their
+   counter value
+
+Protocol features
+-----------------
+
+.. code:: c
+
+  #define VHOST_USER_PROTOCOL_F_MQ             0
+  #define VHOST_USER_PROTOCOL_F_LOG_SHMFD      1
+  #define VHOST_USER_PROTOCOL_F_RARP           2
+  #define VHOST_USER_PROTOCOL_F_REPLY_ACK      3
+  #define VHOST_USER_PROTOCOL_F_MTU            4
+  #define VHOST_USER_PROTOCOL_F_SLAVE_REQ      5
+  #define VHOST_USER_PROTOCOL_F_CROSS_ENDIAN   6
+  #define VHOST_USER_PROTOCOL_F_CRYPTO_SESSION 7
+  #define VHOST_USER_PROTOCOL_F_PAGEFAULT      8
+  #define VHOST_USER_PROTOCOL_F_CONFIG         9
+  #define VHOST_USER_PROTOCOL_F_SLAVE_SEND_FD  10
+  #define VHOST_USER_PROTOCOL_F_HOST_NOTIFIER  11
+  #define VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD 12
+
+Master message types
+--------------------
+
+``VHOST_USER_GET_FEATURES``
+  :id: 1
+  :equivalent ioctl: ``VHOST_GET_FEATURES``
+  :master payload: N/A
+  :slave payload: ``u64``
+
+  Get from the underlying vhost implementation the features bitmask.
+  Feature bit ``VHOST_USER_F_PROTOCOL_FEATURES`` signals slave support
+  for ``VHOST_USER_GET_PROTOCOL_FEATURES`` and
+  ``VHOST_USER_SET_PROTOCOL_FEATURES``.
+
+``VHOST_USER_SET_FEATURES``
+  :id: 2
+  :equivalent ioctl: ``VHOST_SET_FEATURES``
+  :master payload: ``u64``
+
+  Enable features in the underlying vhost implementation using a
+  bitmask.  Feature bit ``VHOST_USER_F_PROTOCOL_FEATURES`` signals
+  slave support for ``VHOST_USER_GET_PROTOCOL_FEATURES`` and
+  ``VHOST_USER_SET_PROTOCOL_FEATURES``.
+
+``VHOST_USER_GET_PROTOCOL_FEATURES``
+  :id: 15
+  :equivalent ioctl: ``VHOST_GET_FEATURES``
+  :master payload: N/A
+  :slave payload: ``u64``
+
+  Get the protocol feature bitmask from the underlying vhost
+  implementation.  Only legal if feature bit
+  ``VHOST_USER_F_PROTOCOL_FEATURES`` is present in
+  ``VHOST_USER_GET_FEATURES``.
+
+.. Note::
+   Slave that reported ``VHOST_USER_F_PROTOCOL_FEATURES`` must
+   support this message even before ``VHOST_USER_SET_FEATURES`` was
+   called.
+
+``VHOST_USER_SET_PROTOCOL_FEATURES``
+  :id: 16
+  :equivalent ioctl: ``VHOST_SET_FEATURES``
+  :master payload: ``u64``
+
+  Enable protocol features in the underlying vhost implementation.
+
+  Only legal if feature bit ``VHOST_USER_F_PROTOCOL_FEATURES`` is present in
+  ``VHOST_USER_GET_FEATURES``.
+
+.. Note::
+   Slave that reported ``VHOST_USER_F_PROTOCOL_FEATURES`` must support
+   this message even before ``VHOST_USER_SET_FEATURES`` was called.
+
+``VHOST_USER_SET_OWNER``
+  :id: 3
+  :equivalent ioctl: ``VHOST_SET_OWNER``
+  :master payload: N/A
+
+  Issued when a new connection is established. It sets the current
+  *master* as an owner of the session. This can be used on the *slave*
+  as a "session start" flag.
+
+``VHOST_USER_RESET_OWNER``
+  :id: 4
+  :master payload: N/A
+
+.. admonition:: Deprecated
+
+   This is no longer used. Used to be sent to request disabling all
+   rings, but some clients interpreted it to also discard connection
+   state (this interpretation would lead to bugs).  It is recommended
+   that clients either ignore this message, or use it to disable all
+   rings.
+
+``VHOST_USER_SET_MEM_TABLE``
+  :id: 5
+  :equivalent ioctl: ``VHOST_SET_MEM_TABLE``
+  :master payload: memory regions description
+  :slave payload: (postcopy only) memory regions description
+
+  Sets the memory map regions on the slave so it can translate the
+  vring addresses. In the ancillary data there is an array of file
+  descriptors for each memory mapped region. The size and ordering of
+  the fds matches the number and ordering of memory regions.
+
+  When ``VHOST_USER_POSTCOPY_LISTEN`` has been received,
+  ``SET_MEM_TABLE`` replies with the bases of the memory mapped
+  regions to the master.  The slave must have mmap'd the regions but
+  not yet accessed them and should not yet generate a userfault
+  event.
+
+.. Note::
+   ``NEED_REPLY_MASK`` is not set in this case.  QEMU will then
+   reply back to the list of mappings with an empty
+   ``VHOST_USER_SET_MEM_TABLE`` as an acknowledgement; only upon
+   reception of this message may the guest start accessing the memory
+   and generating faults.
+
+``VHOST_USER_SET_LOG_BASE``
+  :id: 6
+  :equivalent ioctl: ``VHOST_SET_LOG_BASE``
+  :master payload: u64
+  :slave payload: N/A
+
+  Sets logging shared memory space.
+
+  When slave has ``VHOST_USER_PROTOCOL_F_LOG_SHMFD`` protocol feature,
+  the log memory fd is provided in the ancillary data of
+  ``VHOST_USER_SET_LOG_BASE`` message, the size and offset of shared
+  memory area provided in the message.
+
+``VHOST_USER_SET_LOG_FD``
+  :id: 7
+  :equivalent ioctl: ``VHOST_SET_LOG_FD``
+  :master payload: N/A
+
+  Sets the logging file descriptor, which is passed as ancillary data.
+
+``VHOST_USER_SET_VRING_NUM``
+  :id: 8
+  :equivalent ioctl: ``VHOST_SET_VRING_NUM``
+  :master payload: vring state description
+
+  Set the size of the queue.
+
+``VHOST_USER_SET_VRING_ADDR``
+  :id: 9
+  :equivalent ioctl: ``VHOST_SET_VRING_ADDR``
+  :master payload: vring address description
+  :slave payload: N/A
+
+  Sets the addresses of the different aspects of the vring.
+
+``VHOST_USER_SET_VRING_BASE``
+  :id: 10
+  :equivalent ioctl: ``VHOST_SET_VRING_BASE``
+  :master payload: vring state description
+
+  Sets the base offset in the available vring.
+
+``VHOST_USER_GET_VRING_BASE``
+  :id: 11
+  :equivalent ioctl: ``VHOST_USER_GET_VRING_BASE``
+  :master payload: vring state description
+  :slave payload: vring state description
+
+  Get the available vring base offset.
+
+``VHOST_USER_SET_VRING_KICK``
+  :id: 12
+  :equivalent ioctl: ``VHOST_SET_VRING_KICK``
+  :master payload: ``u64``
+
+  Set the event file descriptor for adding buffers to the vring. It is
+  passed in the ancillary data.
+
+  Bits (0-7) of the payload contain the vring index. Bit 8 is the
+  invalid FD flag. This flag is set when there is no file descriptor
+  in the ancillary data. This signals that polling should be used
+  instead of waiting for a kick.
+
+``VHOST_USER_SET_VRING_CALL``
+  :id: 13
+  :equivalent ioctl: ``VHOST_SET_VRING_CALL``
+  :master payload: ``u64``
+
+  Set the event file descriptor to signal when buffers are used. It is
+  passed in the ancillary data.
+
+  Bits (0-7) of the payload contain the vring index. Bit 8 is the
+  invalid FD flag. This flag is set when there is no file descriptor
+  in the ancillary data. This signals that polling will be used
+  instead of waiting for the call.
+
+``VHOST_USER_SET_VRING_ERR``
+  :id: 14
+  :equivalent ioctl: ``VHOST_SET_VRING_ERR``
+  :master payload: ``u64``
+
+  Set the event file descriptor to signal when error occurs. It is
+  passed in the ancillary data.
+
+  Bits (0-7) of the payload contain the vring index. Bit 8 is the
+  invalid FD flag. This flag is set when there is no file descriptor
+  in the ancillary data.
+
+``VHOST_USER_GET_QUEUE_NUM``
+  :id: 17
+  :equivalent ioctl: N/A
+  :master payload: N/A
+  :slave payload: u64
+
+  Query how many queues the backend supports.
+
+  This request should be sent only when ``VHOST_USER_PROTOCOL_F_MQ``
+  is set in queried protocol features by
+  ``VHOST_USER_GET_PROTOCOL_FEATURES``.
+
+``VHOST_USER_SET_VRING_ENABLE``
+  :id: 18
+  :equivalent ioctl: N/A
+  :master payload: vring state description
+
+  Signal slave to enable or disable corresponding vring.
+
+  This request should be sent only when
+  ``VHOST_USER_F_PROTOCOL_FEATURES`` has been negotiated.
+
+``VHOST_USER_SEND_RARP``
+  :id: 19
+  :equivalent ioctl: N/A
+  :master payload: ``u64``
+
+  Ask vhost user backend to broadcast a fake RARP to notify the migration
+  is terminated for guest that does not support GUEST_ANNOUNCE.
+
+  Only legal if feature bit ``VHOST_USER_F_PROTOCOL_FEATURES`` is
+  present in ``VHOST_USER_GET_FEATURES`` and protocol feature bit
+  ``VHOST_USER_PROTOCOL_F_RARP`` is present in
+  ``VHOST_USER_GET_PROTOCOL_FEATURES``.  The first 6 bytes of the
+  payload contain the mac address of the guest to allow the vhost user
+  backend to construct and broadcast the fake RARP.
+
+``VHOST_USER_NET_SET_MTU``
+  :id: 20
+  :equivalent ioctl: N/A
+  :master payload: ``u64``
+
+  Set host MTU value exposed to the guest.
+
+  This request should be sent only when ``VIRTIO_NET_F_MTU`` feature
+  has been successfully negotiated, ``VHOST_USER_F_PROTOCOL_FEATURES``
+  is present in ``VHOST_USER_GET_FEATURES`` and protocol feature bit
+  ``VHOST_USER_PROTOCOL_F_NET_MTU`` is present in
+  ``VHOST_USER_GET_PROTOCOL_FEATURES``.
+
+  If ``VHOST_USER_PROTOCOL_F_REPLY_ACK`` is negotiated, slave must
+  respond with zero in case the specified MTU is valid, or non-zero
+  otherwise.
+
+``VHOST_USER_SET_SLAVE_REQ_FD``
+  :id: 21
+  :equivalent ioctl: N/A
+  :master payload: N/A
+
+  Set the socket file descriptor for slave initiated requests. It is passed
+  in the ancillary data.
+
+  This request should be sent only when
+  ``VHOST_USER_F_PROTOCOL_FEATURES`` has been negotiated, and protocol
+  feature bit ``VHOST_USER_PROTOCOL_F_SLAVE_REQ`` bit is present in
+  ``VHOST_USER_GET_PROTOCOL_FEATURES``.  If
+  ``VHOST_USER_PROTOCOL_F_REPLY_ACK`` is negotiated, slave must
+  respond with zero for success, non-zero otherwise.
+
+``VHOST_USER_IOTLB_MSG``
+  :id: 22
+  :equivalent ioctl: N/A (equivalent to ``VHOST_IOTLB_MSG`` message type)
+  :master payload: ``struct vhost_iotlb_msg``
+  :slave payload: ``u64``
+
+  Send IOTLB messages with ``struct vhost_iotlb_msg`` as payload.
+
+  Master sends such requests to update and invalidate entries in the
+  device IOTLB. The slave has to acknowledge the request with sending
+  zero as ``u64`` payload for success, non-zero otherwise.
+
+  This request should be send only when ``VIRTIO_F_IOMMU_PLATFORM``
+  feature has been successfully negotiated.
+
+``VHOST_USER_SET_VRING_ENDIAN``
+  :id: 23
+  :equivalent ioctl: ``VHOST_SET_VRING_ENDIAN``
+  :master payload: vring state description
+
+  Set the endianness of a VQ for legacy devices. Little-endian is
+  indicated with state.num set to 0 and big-endian is indicated with
+  state.num set to 1. Other values are invalid.
+
+  This request should be sent only when
+  ``VHOST_USER_PROTOCOL_F_CROSS_ENDIAN`` has been negotiated.
+  Backends that negotiated this feature should handle both
+  endiannesses and expect this message once (per VQ) during device
+  configuration (ie. before the master starts the VQ).
+
+``VHOST_USER_GET_CONFIG``
+  :id: 24
+  :equivalent ioctl: N/A
+  :master payload: virtio device config space
+  :slave payload: virtio device config space
+
+  When ``VHOST_USER_PROTOCOL_F_CONFIG`` is negotiated, this message is
+  submitted by the vhost-user master to fetch the contents of the
+  virtio device configuration space, vhost-user slave's payload size
+  MUST match master's request, vhost-user slave uses zero length of
+  payload to indicate an error to vhost-user master. The vhost-user
+  master may cache the contents to avoid repeated
+  ``VHOST_USER_GET_CONFIG`` calls.
+
+``VHOST_USER_SET_CONFIG``
+  :id: 25
+  :equivalent ioctl: N/A
+  :master payload: virtio device config space
+  :slave payload: N/A
+
+  When ``VHOST_USER_PROTOCOL_F_CONFIG`` is negotiated, this message is
+  submitted by the vhost-user master when the Guest changes the virtio
+  device configuration space and also can be used for live migration
+  on the destination host. The vhost-user slave must check the flags
+  field, and slaves MUST NOT accept SET_CONFIG for read-only
+  configuration space fields unless the live migration bit is set.
+
+``VHOST_USER_CREATE_CRYPTO_SESSION``
+  :id: 26
+  :equivalent ioctl: N/A
+  :master payload: crypto session description
+  :slave payload: crypto session description
+
+  Create a session for crypto operation. The server side must return
+  the session id, 0 or positive for success, negative for failure.
+  This request should be sent only when
+  ``VHOST_USER_PROTOCOL_F_CRYPTO_SESSION`` feature has been
+  successfully negotiated.  It's a required feature for crypto
+  devices.
+
+``VHOST_USER_CLOSE_CRYPTO_SESSION``
+  :id: 27
+  :equivalent ioctl: N/A
+  :master payload: ``u64``
+
+  Close a session for crypto operation which was previously
+  created by ``VHOST_USER_CREATE_CRYPTO_SESSION``.
+
+  This request should be sent only when
+  ``VHOST_USER_PROTOCOL_F_CRYPTO_SESSION`` feature has been
+  successfully negotiated.  It's a required feature for crypto
+  devices.
+
+``VHOST_USER_POSTCOPY_ADVISE``
+  :id: 28
+  :master payload: N/A
+  :slave payload: userfault fd
+
+  When ``VHOST_USER_PROTOCOL_F_PAGEFAULT`` is supported, the master
+  advises slave that a migration with postcopy enabled is underway,
+  the slave must open a userfaultfd for later use.  Note that at this
+  stage the migration is still in precopy mode.
+
+``VHOST_USER_POSTCOPY_LISTEN``
+  :id: 29
+  :master payload: N/A
+
+  Master advises slave that a transition to postcopy mode has
+  happened.  The slave must ensure that shared memory is registered
+  with userfaultfd to cause faulting of non-present pages.
+
+  This is always sent sometime after a ``VHOST_USER_POSTCOPY_ADVISE``,
+  and thus only when ``VHOST_USER_PROTOCOL_F_PAGEFAULT`` is supported.
+
+``VHOST_USER_POSTCOPY_END``
+  :id: 30
+  :slave payload: ``u64``
+
+  Master advises that postcopy migration has now completed.  The slave
+  must disable the userfaultfd. The response is an acknowledgement
+  only.
+
+  When ``VHOST_USER_PROTOCOL_F_PAGEFAULT`` is supported, this message
+  is sent at the end of the migration, after
+  ``VHOST_USER_POSTCOPY_LISTEN`` was previously sent.
+
+  The value returned is an error indication; 0 is success.
+
+``VHOST_USER_GET_INFLIGHT_FD``
+  :id: 31
+  :equivalent ioctl: N/A
+  :master payload: inflight description
+
+  When ``VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD`` protocol feature has
+  been successfully negotiated, this message is submitted by master to
+  get a shared buffer from slave. The shared buffer will be used to
+  track inflight I/O by slave. QEMU should retrieve a new one when vm
+  reset.
+
+``VHOST_USER_SET_INFLIGHT_FD``
+  :id: 32
+  :equivalent ioctl: N/A
+  :master payload: inflight description
+
+  When ``VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD`` protocol feature has
+  been successfully negotiated, this message is submitted by master to
+  send the shared inflight buffer back to slave so that slave could
+  get inflight I/O after a crash or restart.
+
+Slave message types
+-------------------
+
+``VHOST_USER_SLAVE_IOTLB_MSG``
+  :id: 1
+  :equivalent ioctl: N/A (equivalent to ``VHOST_IOTLB_MSG`` message type)
+  :slave payload: ``struct vhost_iotlb_msg``
+  :master payload: N/A
+
+  Send IOTLB messages with ``struct vhost_iotlb_msg`` as payload.
+  Slave sends such requests to notify of an IOTLB miss, or an IOTLB
+  access failure. If ``VHOST_USER_PROTOCOL_F_REPLY_ACK`` is
+  negotiated, and slave set the ``VHOST_USER_NEED_REPLY`` flag, master
+  must respond with zero when operation is successfully completed, or
+  non-zero otherwise.  This request should be send only when
+  ``VIRTIO_F_IOMMU_PLATFORM`` feature has been successfully
+  negotiated.
+
+``VHOST_USER_SLAVE_CONFIG_CHANGE_MSG``
+  :id: 2
+  :equivalent ioctl: N/A
+  :slave payload: N/A
+  :master payload: N/A
+
+  When ``VHOST_USER_PROTOCOL_F_CONFIG`` is negotiated, vhost-user
+  slave sends such messages to notify that the virtio device's
+  configuration space has changed, for those host devices which can
+  support such feature, host driver can send ``VHOST_USER_GET_CONFIG``
+  message to slave to get the latest content. If
+  ``VHOST_USER_PROTOCOL_F_REPLY_ACK`` is negotiated, and slave set the
+  ``VHOST_USER_NEED_REPLY`` flag, master must respond with zero when
+  operation is successfully completed, or non-zero otherwise.
+
+``VHOST_USER_SLAVE_VRING_HOST_NOTIFIER_MSG``
+  :id: 3
+  :equivalent ioctl: N/A
+  :slave payload: vring area description
+  :master payload: N/A
+
+  Sets host notifier for a specified queue. The queue index is
+  contained in the ``u64`` field of the vring area description. The
+  host notifier is described by the file descriptor (typically it's a
+  VFIO device fd) which is passed as ancillary data and the size
+  (which is mmap size and should be the same as host page size) and
+  offset (which is mmap offset) carried in the vring area
+  description. QEMU can mmap the file descriptor based on the size and
+  offset to get a memory range. Registering a host notifier means
+  mapping this memory range to the VM as the specified queue's notify
+  MMIO region. Slave sends this request to tell QEMU to de-register
+  the existing notifier if any and register the new notifier if the
+  request is sent with a file descriptor.
+
+  This request should be sent only when
+  ``VHOST_USER_PROTOCOL_F_HOST_NOTIFIER`` protocol feature has been
+  successfully negotiated.
+
+.. _reply_ack:
+
+VHOST_USER_PROTOCOL_F_REPLY_ACK
+-------------------------------
+
+The original vhost-user specification only demands replies for certain
+commands. This differs from the vhost protocol implementation where
+commands are sent over an ``ioctl()`` call and block until the client
+has completed.
+
+With this protocol extension negotiated, the sender (QEMU) can set the
+``need_reply`` [Bit 3] flag to any command. This indicates that the
+client MUST respond with a Payload ``VhostUserMsg`` indicating success
+or failure. The payload should be set to zero on success or non-zero
+on failure, unless the message already has an explicit reply body.
+
+The response payload gives QEMU a deterministic indication of the result
+of the command. Today, QEMU is expected to terminate the main vhost-user
+loop upon receiving such errors. In future, qemu could be taught to be more
+resilient for selective requests.
+
+For the message types that already solicit a reply from the client,
+the presence of ``VHOST_USER_PROTOCOL_F_REPLY_ACK`` or need_reply bit
+being set brings no behavioural change. (See the Communication_
+section for details.)
+
+.. _backend_conventions:
+
+Backend program conventions
+===========================
+
+vhost-user backends can provide various devices & services and may
+need to be configured manually depending on the use case. However, it
+is a good idea to follow the conventions listed here when
+possible. Users, QEMU or libvirt, can then rely on some common
+behaviour to avoid heterogenous configuration and management of the
+backend programs and facilitate interoperability.
+
+Each backend installed on a host system should come with at least one
+JSON file that conforms to the vhost-user.json schema. Each file
+informs the management applications about the backend type, and binary
+location. In addition, it defines rules for management apps for
+picking the highest priority backend when multiple match the search
+criteria (see ``@VhostUserBackend`` documentation in the schema file).
+
+If the backend is not capable of enabling a requested feature on the
+host (such as 3D acceleration with virgl), or the initialization
+failed, the backend should fail to start early and exit with a status
+!= 0. It may also print a message to stderr for further details.
+
+The backend program must not daemonize itself, but it may be
+daemonized by the management layer. It may also have a restricted
+access to the system.
+
+File descriptors 0, 1 and 2 will exist, and have regular
+stdin/stdout/stderr usage (they may have been redirected to /dev/null
+by the management layer, or to a log handler).
+
+The backend program must end (as quickly and cleanly as possible) when
+the SIGTERM signal is received. Eventually, it may receive SIGKILL by
+the management layer after a few seconds.
+
+The following command line options have an expected behaviour. They
+are mandatory, unless explicitly said differently:
+
+--socket-path=PATH
+
+  This option specify the location of the vhost-user Unix domain socket.
+  It is incompatible with --fd.
+
+--fd=FDNUM
+
+  When this argument is given, the backend program is started with the
+  vhost-user socket as file descriptor FDNUM. It is incompatible with
+  --socket-path.
+
+--print-capabilities
+
+  Output to stdout the backend capabilities in JSON format, and then
+  exit successfully. Other options and arguments should be ignored, and
+  the backend program should not perform its normal function.  The
+  capabilities can be reported dynamically depending on the host
+  capabilities.
+
+The JSON output is described in the ``vhost-user.json`` schema, by
+```@VHostUserBackendCapabilities``.  Example:
+
+.. code:: json
+
+  {
+    "type": "foo",
+    "features": [
+      "feature-a",
+      "feature-b"
+    ]
+  }
+
+vhost-user-input
+----------------
+
+Command line options:
+
+--evdev-path=PATH
+
+  Specify the linux input device.
+
+  (optional)
+
+--no-grab
+
+  Do no request exclusive access to the input device.
+
+  (optional)
+
+vhost-user-gpu
+--------------
+
+Command line options:
+
+--render-node=PATH
+
+  Specify the GPU DRM render node.
+
+  (optional)
+
+--virgl
+
+  Enable virgl rendering support.
+
+  (optional)
diff --git a/docs/interop/vhost-user.txt b/docs/interop/vhost-user.txt
deleted file mode 100644
index 4dbd530cb9..0000000000
--- a/docs/interop/vhost-user.txt
+++ /dev/null
@@ -1,1219 +0,0 @@
-Vhost-user Protocol
-===================
-
-Copyright (c) 2014 Virtual Open Systems Sarl.
-
-This work is licensed under the terms of the GNU GPL, version 2 or later.
-See the COPYING file in the top-level directory.
-===================
-
-This protocol is aiming to complement the ioctl interface used to control the
-vhost implementation in the Linux kernel. It implements the control plane needed
-to establish virtqueue sharing with a user space process on the same host. It
-uses communication over a Unix domain socket to share file descriptors in the
-ancillary data of the message.
-
-The protocol defines 2 sides of the communication, master and slave. Master is
-the application that shares its virtqueues, in our case QEMU. Slave is the
-consumer of the virtqueues.
-
-In the current implementation QEMU is the Master, and the Slave is the
-external process consuming the virtio queues, for example a software
-Ethernet switch running in user space, such as Snabbswitch, or a block
-device backend processing read & write to a virtual disk. In order to
-facilitate interoperability between various backend implementations,
-it is recommended to follow the "Backend program conventions"
-described in this document.
-
-Master and slave can be either a client (i.e. connecting) or server (listening)
-in the socket communication.
-
-Message Specification
----------------------
-
-Note that all numbers are in the machine native byte order. A vhost-user message
-consists of 3 header fields and a payload:
-
-------------------------------------
-| request | flags | size | payload |
-------------------------------------
-
- * Request: 32-bit type of the request
- * Flags: 32-bit bit field:
-   - Lower 2 bits are the version (currently 0x01)
-   - Bit 2 is the reply flag - needs to be sent on each reply from the slave
-   - Bit 3 is the need_reply flag - see VHOST_USER_PROTOCOL_F_REPLY_ACK for
-     details.
- * Size - 32-bit size of the payload
-
-
-Depending on the request type, payload can be:
-
- * A single 64-bit integer
-   -------
-   | u64 |
-   -------
-
-   u64: a 64-bit unsigned integer
-
- * A vring state description
-   ---------------
-   | index | num |
-   ---------------
-
-   Index: a 32-bit index
-   Num: a 32-bit number
-
- * A vring address description
-   --------------------------------------------------------------
-   | index | flags | size | descriptor | used | available | log |
-   --------------------------------------------------------------
-
-   Index: a 32-bit vring index
-   Flags: a 32-bit vring flags
-   Descriptor: a 64-bit ring address of the vring descriptor table
-   Used: a 64-bit ring address of the vring used ring
-   Available: a 64-bit ring address of the vring available ring
-   Log: a 64-bit guest address for logging
-
-   Note that a ring address is an IOVA if VIRTIO_F_IOMMU_PLATFORM has been
-   negotiated.  Otherwise it is a user address.
-
- * Memory regions description
-   ---------------------------------------------------
-   | num regions | padding | region0 | ... | region7 |
-   ---------------------------------------------------
-
-   Num regions: a 32-bit number of regions
-   Padding: 32-bit
-
-   A region is:
-   -----------------------------------------------------
-   | guest address | size | user address | mmap offset |
-   -----------------------------------------------------
-
-   Guest address: a 64-bit guest address of the region
-   Size: a 64-bit size
-   User address: a 64-bit user address
-   mmap offset: 64-bit offset where region starts in the mapped memory
-
-* Log description
-   ---------------------------
-   | log size | log offset |
-   ---------------------------
-   log size: size of area used for logging
-   log offset: offset from start of supplied file descriptor
-       where logging starts (i.e. where guest address 0 would be logged)
-
- * An IOTLB message
-   ---------------------------------------------------------
-   | iova | size | user address | permissions flags | type |
-   ---------------------------------------------------------
-
-   IOVA: a 64-bit I/O virtual address programmed by the guest
-   Size: a 64-bit size
-   User address: a 64-bit user address
-   Permissions: an 8-bit value:
-    - 0: No access
-    - 1: Read access
-    - 2: Write access
-    - 3: Read/Write access
-   Type: an 8-bit IOTLB message type:
-    - 1: IOTLB miss
-    - 2: IOTLB update
-    - 3: IOTLB invalidate
-    - 4: IOTLB access fail
-
- * Virtio device config space
-   -----------------------------------
-   | offset | size | flags | payload |
-   -----------------------------------
-
-   Offset: a 32-bit offset of virtio device's configuration space
-   Size: a 32-bit configuration space access size in bytes
-   Flags: a 32-bit value:
-    - 0: Vhost master messages used for writeable fields
-    - 1: Vhost master messages used for live migration
-   Payload: Size bytes array holding the contents of the virtio
-       device's configuration space
-
- * Vring area description
-   -----------------------
-   | u64 | size | offset |
-   -----------------------
-
-   u64: a 64-bit integer contains vring index and flags
-   Size: a 64-bit size of this area
-   Offset: a 64-bit offset of this area from the start of the
-       supplied file descriptor
-
- * Inflight description
-   -----------------------------------------------------
-   | mmap size | mmap offset | num queues | queue size |
-   -----------------------------------------------------
-
-   mmap size: a 64-bit size of area to track inflight I/O
-   mmap offset: a 64-bit offset of this area from the start
-                of the supplied file descriptor
-   num queues: a 16-bit number of virtqueues
-   queue size: a 16-bit size of virtqueues
-
-In QEMU the vhost-user message is implemented with the following struct:
-
-typedef struct VhostUserMsg {
-    VhostUserRequest request;
-    uint32_t flags;
-    uint32_t size;
-    union {
-        uint64_t u64;
-        struct vhost_vring_state state;
-        struct vhost_vring_addr addr;
-        VhostUserMemory memory;
-        VhostUserLog log;
-        struct vhost_iotlb_msg iotlb;
-        VhostUserConfig config;
-        VhostUserVringArea area;
-        VhostUserInflight inflight;
-    };
-} QEMU_PACKED VhostUserMsg;
-
-Communication
--------------
-
-The protocol for vhost-user is based on the existing implementation of vhost
-for the Linux Kernel. Most messages that can be sent via the Unix domain socket
-implementing vhost-user have an equivalent ioctl to the kernel implementation.
-
-The communication consists of master sending message requests and slave sending
-message replies. Most of the requests don't require replies. Here is a list of
-the ones that do:
-
- * VHOST_USER_GET_FEATURES
- * VHOST_USER_GET_PROTOCOL_FEATURES
- * VHOST_USER_GET_VRING_BASE
- * VHOST_USER_SET_LOG_BASE (if VHOST_USER_PROTOCOL_F_LOG_SHMFD)
- * VHOST_USER_GET_INFLIGHT_FD (if VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD)
-
-[ Also see the section on REPLY_ACK protocol extension. ]
-
-There are several messages that the master sends with file descriptors passed
-in the ancillary data:
-
- * VHOST_USER_SET_MEM_TABLE
- * VHOST_USER_SET_LOG_BASE (if VHOST_USER_PROTOCOL_F_LOG_SHMFD)
- * VHOST_USER_SET_LOG_FD
- * VHOST_USER_SET_VRING_KICK
- * VHOST_USER_SET_VRING_CALL
- * VHOST_USER_SET_VRING_ERR
- * VHOST_USER_SET_SLAVE_REQ_FD
- * VHOST_USER_SET_INFLIGHT_FD (if VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD)
-
-If Master is unable to send the full message or receives a wrong reply it will
-close the connection. An optional reconnection mechanism can be implemented.
-
-Any protocol extensions are gated by protocol feature bits,
-which allows full backwards compatibility on both master
-and slave.
-As older slaves don't support negotiating protocol features,
-a feature bit was dedicated for this purpose:
-#define VHOST_USER_F_PROTOCOL_FEATURES 30
-
-Starting and stopping rings
-----------------------
-Client must only process each ring when it is started.
-
-Client must only pass data between the ring and the
-backend, when the ring is enabled.
-
-If ring is started but disabled, client must process the
-ring without talking to the backend.
-
-For example, for a networking device, in the disabled state
-client must not supply any new RX packets, but must process
-and discard any TX packets.
-
-If VHOST_USER_F_PROTOCOL_FEATURES has not been negotiated, the ring is initialized
-in an enabled state.
-
-If VHOST_USER_F_PROTOCOL_FEATURES has been negotiated, the ring is initialized
-in a disabled state. Client must not pass data to/from the backend until ring is enabled by
-VHOST_USER_SET_VRING_ENABLE with parameter 1, or after it has been disabled by
-VHOST_USER_SET_VRING_ENABLE with parameter 0.
-
-Each ring is initialized in a stopped state, client must not process it until
-ring is started, or after it has been stopped.
-
-Client must start ring upon receiving a kick (that is, detecting that file
-descriptor is readable) on the descriptor specified by
-VHOST_USER_SET_VRING_KICK, and stop ring upon receiving
-VHOST_USER_GET_VRING_BASE.
-
-While processing the rings (whether they are enabled or not), client must
-support changing some configuration aspects on the fly.
-
-Multiple queue support
-----------------------
-
-Multiple queue is treated as a protocol extension, hence the slave has to
-implement protocol features first. The multiple queues feature is supported
-only when the protocol feature VHOST_USER_PROTOCOL_F_MQ (bit 0) is set.
-
-The max number of queue pairs the slave supports can be queried with message
-VHOST_USER_GET_QUEUE_NUM. Master should stop when the number of
-requested queues is bigger than that.
-
-As all queues share one connection, the master uses a unique index for each
-queue in the sent message to identify a specified queue. One queue pair
-is enabled initially. More queues are enabled dynamically, by sending
-message VHOST_USER_SET_VRING_ENABLE.
-
-Migration
----------
-
-During live migration, the master may need to track the modifications
-the slave makes to the memory mapped regions. The client should mark
-the dirty pages in a log. Once it complies to this logging, it may
-declare the VHOST_F_LOG_ALL vhost feature.
-
-To start/stop logging of data/used ring writes, server may send messages
-VHOST_USER_SET_FEATURES with VHOST_F_LOG_ALL and VHOST_USER_SET_VRING_ADDR with
-VHOST_VRING_F_LOG in ring's flags set to 1/0, respectively.
-
-All the modifications to memory pointed by vring "descriptor" should
-be marked. Modifications to "used" vring should be marked if
-VHOST_VRING_F_LOG is part of ring's flags.
-
-Dirty pages are of size:
-#define VHOST_LOG_PAGE 0x1000
-
-The log memory fd is provided in the ancillary data of
-VHOST_USER_SET_LOG_BASE message when the slave has
-VHOST_USER_PROTOCOL_F_LOG_SHMFD protocol feature.
-
-The size of the log is supplied as part of VhostUserMsg
-which should be large enough to cover all known guest
-addresses. Log starts at the supplied offset in the
-supplied file descriptor.
-The log covers from address 0 to the maximum of guest
-regions. In pseudo-code, to mark page at "addr" as dirty:
-
-page = addr / VHOST_LOG_PAGE
-log[page / 8] |= 1 << page % 8
-
-Where addr is the guest physical address.
-
-Use atomic operations, as the log may be concurrently manipulated.
-
-Note that when logging modifications to the used ring (when VHOST_VRING_F_LOG
-is set for this ring), log_guest_addr should be used to calculate the log
-offset: the write to first byte of the used ring is logged at this offset from
-log start. Also note that this value might be outside the legal guest physical
-address range (i.e. does not have to be covered by the VhostUserMemory table),
-but the bit offset of the last byte of the ring must fall within
-the size supplied by VhostUserLog.
-
-VHOST_USER_SET_LOG_FD is an optional message with an eventfd in
-ancillary data, it may be used to inform the master that the log has
-been modified.
-
-Once the source has finished migration, rings will be stopped by
-the source. No further update must be done before rings are
-restarted.
-
-In postcopy migration the slave is started before all the memory has been
-received from the source host, and care must be taken to avoid accessing pages
-that have yet to be received.  The slave opens a 'userfault'-fd and registers
-the memory with it; this fd is then passed back over to the master.
-The master services requests on the userfaultfd for pages that are accessed
-and when the page is available it performs WAKE ioctl's on the userfaultfd
-to wake the stalled slave.  The client indicates support for this via the
-VHOST_USER_PROTOCOL_F_PAGEFAULT feature.
-
-Memory access
--------------
-
-The master sends a list of vhost memory regions to the slave using the
-VHOST_USER_SET_MEM_TABLE message.  Each region has two base addresses: a guest
-address and a user address.
-
-Messages contain guest addresses and/or user addresses to reference locations
-within the shared memory.  The mapping of these addresses works as follows.
-
-User addresses map to the vhost memory region containing that user address.
-
-When the VIRTIO_F_IOMMU_PLATFORM feature has not been negotiated:
-
- * Guest addresses map to the vhost memory region containing that guest
-   address.
-
-When the VIRTIO_F_IOMMU_PLATFORM feature has been negotiated:
-
- * Guest addresses are also called I/O virtual addresses (IOVAs).  They are
-   translated to user addresses via the IOTLB.
-
- * The vhost memory region guest address is not used.
-
-IOMMU support
--------------
-
-When the VIRTIO_F_IOMMU_PLATFORM feature has been negotiated, the master
-sends IOTLB entries update & invalidation by sending VHOST_USER_IOTLB_MSG
-requests to the slave with a struct vhost_iotlb_msg as payload. For update
-events, the iotlb payload has to be filled with the update message type (2),
-the I/O virtual address, the size, the user virtual address, and the
-permissions flags. Addresses and size must be within vhost memory regions set
-via the VHOST_USER_SET_MEM_TABLE request. For invalidation events, the iotlb
-payload has to be filled with the invalidation message type (3), the I/O virtual
-address and the size. On success, the slave is expected to reply with a zero
-payload, non-zero otherwise.
-
-The slave relies on the slave communcation channel (see "Slave communication"
-section below) to send IOTLB miss and access failure events, by sending
-VHOST_USER_SLAVE_IOTLB_MSG requests to the master with a struct vhost_iotlb_msg
-as payload. For miss events, the iotlb payload has to be filled with the miss
-message type (1), the I/O virtual address and the permissions flags. For access
-failure event, the iotlb payload has to be filled with the access failure
-message type (4), the I/O virtual address and the permissions flags.
-For synchronization purpose, the slave may rely on the reply-ack feature,
-so the master may send a reply when operation is completed if the reply-ack
-feature is negotiated and slaves requests a reply. For miss events, completed
-operation means either master sent an update message containing the IOTLB entry
-containing requested address and permission, or master sent nothing if the IOTLB
-miss message is invalid (invalid IOVA or permission).
-
-The master isn't expected to take the initiative to send IOTLB update messages,
-as the slave sends IOTLB miss messages for the guest virtual memory areas it
-needs to access.
-
-Slave communication
--------------------
-
-An optional communication channel is provided if the slave declares
-VHOST_USER_PROTOCOL_F_SLAVE_REQ protocol feature, to allow the slave to make
-requests to the master.
-
-The fd is provided via VHOST_USER_SET_SLAVE_REQ_FD ancillary data.
-
-A slave may then send VHOST_USER_SLAVE_* messages to the master
-using this fd communication channel.
-
-If VHOST_USER_PROTOCOL_F_SLAVE_SEND_FD protocol feature is negotiated,
-slave can send file descriptors (at most 8 descriptors in each message)
-to master via ancillary data using this fd communication channel.
-
-Inflight I/O tracking
----------------------
-
-To support reconnecting after restart or crash, slave may need to resubmit
-inflight I/Os. If virtqueue is processed in order, we can easily achieve
-that by getting the inflight descriptors from descriptor table (split virtqueue)
-or descriptor ring (packed virtqueue). However, it can't work when we process
-descriptors out-of-order because some entries which store the information of
-inflight descriptors in available ring (split virtqueue) or descriptor
-ring (packed virtqueue) might be overrided by new entries. To solve this
-problem, slave need to allocate an extra buffer to store this information of inflight
-descriptors and share it with master for persistent. VHOST_USER_GET_INFLIGHT_FD and
-VHOST_USER_SET_INFLIGHT_FD are used to transfer this buffer between master
-and slave. And the format of this buffer is described below:
-
--------------------------------------------------------
-| queue0 region | queue1 region | ... | queueN region |
--------------------------------------------------------
-
-N is the number of available virtqueues. Slave could get it from num queues
-field of VhostUserInflight.
-
-For split virtqueue, queue region can be implemented as:
-
-typedef struct DescStateSplit {
-    /* Indicate whether this descriptor is inflight or not.
-     * Only available for head-descriptor. */
-    uint8_t inflight;
-
-    /* Padding */
-    uint8_t padding[5];
-
-    /* Maintain a list for the last batch of used descriptors.
-     * Only available when batching is used for submitting */
-    uint16_t next;
-
-    /* Used to preserve the order of fetching available descriptors.
-     * Only available for head-descriptor. */
-    uint64_t counter;
-} DescStateSplit;
-
-typedef struct QueueRegionSplit {
-    /* The feature flags of this region. Now it's initialized to 0. */
-    uint64_t features;
-
-    /* The version of this region. It's 1 currently.
-     * Zero value indicates an uninitialized buffer */
-    uint16_t version;
-
-    /* The size of DescStateSplit array. It's equal to the virtqueue
-     * size. Slave could get it from queue size field of VhostUserInflight. */
-    uint16_t desc_num;
-
-    /* The head of list that track the last batch of used descriptors. */
-    uint16_t last_batch_head;
-
-    /* Store the idx value of used ring */
-    uint16_t used_idx;
-
-    /* Used to track the state of each descriptor in descriptor table */
-    DescStateSplit desc[0];
-} QueueRegionSplit;
-
-To track inflight I/O, the queue region should be processed as follows:
-
-When receiving available buffers from the driver:
-
-    1. Get the next available head-descriptor index from available ring, i
-
-    2. Set desc[i].counter to the value of global counter
-
-    3. Increase global counter by 1
-
-    4. Set desc[i].inflight to 1
-
-When supplying used buffers to the driver:
-
-    1. Get corresponding used head-descriptor index, i
-
-    2. Set desc[i].next to last_batch_head
-
-    3. Set last_batch_head to i
-
-    4. Steps 1,2,3 may be performed repeatedly if batching is possible
-
-    5. Increase the idx value of used ring by the size of the batch
-
-    6. Set the inflight field of each DescStateSplit entry in the batch to 0
-
-    7. Set used_idx to the idx value of used ring
-
-When reconnecting:
-
-    1. If the value of used_idx does not match the idx value of used ring (means
-    the inflight field of DescStateSplit entries in last batch may be incorrect),
-
-        (a) Subtract the value of used_idx from the idx value of used ring to get
-        last batch size of DescStateSplit entries
-
-        (b) Set the inflight field of each DescStateSplit entry to 0 in last batch
-        list which starts from last_batch_head
-
-        (c) Set used_idx to the idx value of used ring
-
-    2. Resubmit inflight DescStateSplit entries in order of their counter value
-
-For packed virtqueue, queue region can be implemented as:
-
-typedef struct DescStatePacked {
-    /* Indicate whether this descriptor is inflight or not.
-     * Only available for head-descriptor. */
-    uint8_t inflight;
-
-    /* Padding */
-    uint8_t padding;
-
-    /* Link to the next free entry */
-    uint16_t next;
-
-    /* Link to the last entry of descriptor list.
-     * Only available for head-descriptor. */
-    uint16_t last;
-
-    /* The length of descriptor list.
-     * Only available for head-descriptor. */
-    uint16_t num;
-
-    /* Used to preserve the order of fetching available descriptors.
-     * Only available for head-descriptor. */
-    uint64_t counter;
-
-    /* The buffer id */
-    uint16_t id;
-
-    /* The descriptor flags */
-    uint16_t flags;
-
-    /* The buffer length */
-    uint32_t len;
-
-    /* The buffer address */
-    uint64_t addr;
-} DescStatePacked;
-
-typedef struct QueueRegionPacked {
-    /* The feature flags of this region. Now it's initialized to 0. */
-    uint64_t features;
-
-    /* The version of this region. It's 1 currently.
-     * Zero value indicates an uninitialized buffer */
-    uint16_t version;
-
-    /* The size of DescStatePacked array. It's equal to the virtqueue
-     * size. Slave could get it from queue size field of VhostUserInflight. */
-    uint16_t desc_num;
-
-    /* The head of free DescStatePacked entry list */
-    uint16_t free_head;
-
-    /* The old head of free DescStatePacked entry list */
-    uint16_t old_free_head;
-
-    /* The used index of descriptor ring */
-    uint16_t used_idx;
-
-    /* The old used index of descriptor ring */
-    uint16_t old_used_idx;
-
-    /* Device ring wrap counter */
-    uint8_t used_wrap_counter;
-
-    /* The old device ring wrap counter */
-    uint8_t old_used_wrap_counter;
-
-    /* Padding */
-    uint8_t padding[7];
-
-    /* Used to track the state of each descriptor fetched from descriptor ring */
-    DescStatePacked desc[0];
-} QueueRegionPacked;
-
-To track inflight I/O, the queue region should be processed as follows:
-
-When receiving available buffers from the driver:
-
-    1. Get the next available descriptor entry from descriptor ring, d
-
-    2. If d is head descriptor,
-
-        (a) Set desc[old_free_head].num to 0
-
-        (b) Set desc[old_free_head].counter to the value of global counter
-
-        (c) Increase global counter by 1
-
-        (d) Set desc[old_free_head].inflight to 1
-
-    3. If d is last descriptor, set desc[old_free_head].last to free_head
-
-    4. Increase desc[old_free_head].num by 1
-
-    5. Set desc[free_head].addr, desc[free_head].len, desc[free_head].flags,
-    desc[free_head].id to d.addr, d.len, d.flags, d.id
-
-    6. Set free_head to desc[free_head].next
-
-    7. If d is last descriptor, set old_free_head to free_head
-
-When supplying used buffers to the driver:
-
-    1. Get corresponding used head-descriptor entry from descriptor ring, d
-
-    2. Get corresponding DescStatePacked entry, e
-
-    3. Set desc[e.last].next to free_head
-
-    4. Set free_head to the index of e
-
-    5. Steps 1,2,3,4 may be performed repeatedly if batching is possible
-
-    6. Increase used_idx by the size of the batch and update used_wrap_counter if needed
-
-    7. Update d.flags
-
-    8. Set the inflight field of each head DescStatePacked entry in the batch to 0
-
-    9. Set old_free_head, old_used_idx, old_used_wrap_counter to free_head, used_idx,
-    used_wrap_counter
-
-When reconnecting:
-
-    1. If used_idx does not match old_used_idx (means the inflight field of DescStatePacked
-    entries in last batch may be incorrect),
-
-        (a) Get the next descriptor ring entry through old_used_idx, d
-
-        (b) Use old_used_wrap_counter to calculate the available flags
-
-        (c) If d.flags is not equal to the calculated flags value (means slave has
-        submitted the buffer to guest driver before crash, so it has to commit the
-        in-progres update), set old_free_head, old_used_idx, old_used_wrap_counter
-        to free_head, used_idx, used_wrap_counter
-
-    2. Set free_head, used_idx, used_wrap_counter to old_free_head, old_used_idx,
-    old_used_wrap_counter (roll back any in-progress update)
-
-    3. Set the inflight field of each DescStatePacked entry in free list to 0
-
-    4. Resubmit inflight DescStatePacked entries in order of their counter value
-
-Protocol features
------------------
-
-#define VHOST_USER_PROTOCOL_F_MQ             0
-#define VHOST_USER_PROTOCOL_F_LOG_SHMFD      1
-#define VHOST_USER_PROTOCOL_F_RARP           2
-#define VHOST_USER_PROTOCOL_F_REPLY_ACK      3
-#define VHOST_USER_PROTOCOL_F_MTU            4
-#define VHOST_USER_PROTOCOL_F_SLAVE_REQ      5
-#define VHOST_USER_PROTOCOL_F_CROSS_ENDIAN   6
-#define VHOST_USER_PROTOCOL_F_CRYPTO_SESSION 7
-#define VHOST_USER_PROTOCOL_F_PAGEFAULT      8
-#define VHOST_USER_PROTOCOL_F_CONFIG         9
-#define VHOST_USER_PROTOCOL_F_SLAVE_SEND_FD  10
-#define VHOST_USER_PROTOCOL_F_HOST_NOTIFIER  11
-#define VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD 12
-
-Master message types
---------------------
-
- * VHOST_USER_GET_FEATURES
-
-      Id: 1
-      Equivalent ioctl: VHOST_GET_FEATURES
-      Master payload: N/A
-      Slave payload: u64
-
-      Get from the underlying vhost implementation the features bitmask.
-      Feature bit VHOST_USER_F_PROTOCOL_FEATURES signals slave support for
-      VHOST_USER_GET_PROTOCOL_FEATURES and VHOST_USER_SET_PROTOCOL_FEATURES.
-
- * VHOST_USER_SET_FEATURES
-
-      Id: 2
-      Ioctl: VHOST_SET_FEATURES
-      Master payload: u64
-
-      Enable features in the underlying vhost implementation using a bitmask.
-      Feature bit VHOST_USER_F_PROTOCOL_FEATURES signals slave support for
-      VHOST_USER_GET_PROTOCOL_FEATURES and VHOST_USER_SET_PROTOCOL_FEATURES.
-
- * VHOST_USER_GET_PROTOCOL_FEATURES
-
-      Id: 15
-      Equivalent ioctl: VHOST_GET_FEATURES
-      Master payload: N/A
-      Slave payload: u64
-
-      Get the protocol feature bitmask from the underlying vhost implementation.
-      Only legal if feature bit VHOST_USER_F_PROTOCOL_FEATURES is present in
-      VHOST_USER_GET_FEATURES.
-      Note: slave that reported VHOST_USER_F_PROTOCOL_FEATURES must support
-      this message even before VHOST_USER_SET_FEATURES was called.
-
- * VHOST_USER_SET_PROTOCOL_FEATURES
-
-      Id: 16
-      Ioctl: VHOST_SET_FEATURES
-      Master payload: u64
-
-      Enable protocol features in the underlying vhost implementation.
-      Only legal if feature bit VHOST_USER_F_PROTOCOL_FEATURES is present in
-      VHOST_USER_GET_FEATURES.
-      Note: slave that reported VHOST_USER_F_PROTOCOL_FEATURES must support
-      this message even before VHOST_USER_SET_FEATURES was called.
-
- * VHOST_USER_SET_OWNER
-
-      Id: 3
-      Equivalent ioctl: VHOST_SET_OWNER
-      Master payload: N/A
-
-      Issued when a new connection is established. It sets the current Master
-      as an owner of the session. This can be used on the Slave as a
-      "session start" flag.
-
- * VHOST_USER_RESET_OWNER
-
-      Id: 4
-      Master payload: N/A
-
-      This is no longer used. Used to be sent to request disabling
-      all rings, but some clients interpreted it to also discard
-      connection state (this interpretation would lead to bugs).
-      It is recommended that clients either ignore this message,
-      or use it to disable all rings.
-
- * VHOST_USER_SET_MEM_TABLE
-
-      Id: 5
-      Equivalent ioctl: VHOST_SET_MEM_TABLE
-      Master payload: memory regions description
-      Slave payload: (postcopy only) memory regions description
-
-      Sets the memory map regions on the slave so it can translate the vring
-      addresses. In the ancillary data there is an array of file descriptors
-      for each memory mapped region. The size and ordering of the fds matches
-      the number and ordering of memory regions.
-
-      When VHOST_USER_POSTCOPY_LISTEN has been received, SET_MEM_TABLE replies with
-      the bases of the memory mapped regions to the master.  The slave must
-      have mmap'd the regions but not yet accessed them and should not yet generate
-      a userfault event. Note NEED_REPLY_MASK is not set in this case.
-      QEMU will then reply back to the list of mappings with an empty
-      VHOST_USER_SET_MEM_TABLE as an acknowledgment; only upon reception of this
-      message may the guest start accessing the memory and generating faults.
-
- * VHOST_USER_SET_LOG_BASE
-
-      Id: 6
-      Equivalent ioctl: VHOST_SET_LOG_BASE
-      Master payload: u64
-      Slave payload: N/A
-
-      Sets logging shared memory space.
-      When slave has VHOST_USER_PROTOCOL_F_LOG_SHMFD protocol
-      feature, the log memory fd is provided in the ancillary data of
-      VHOST_USER_SET_LOG_BASE message, the size and offset of shared
-      memory area provided in the message.
-
-
- * VHOST_USER_SET_LOG_FD
-
-      Id: 7
-      Equivalent ioctl: VHOST_SET_LOG_FD
-      Master payload: N/A
-
-      Sets the logging file descriptor, which is passed as ancillary data.
-
- * VHOST_USER_SET_VRING_NUM
-
-      Id: 8
-      Equivalent ioctl: VHOST_SET_VRING_NUM
-      Master payload: vring state description
-
-      Set the size of the queue.
-
- * VHOST_USER_SET_VRING_ADDR
-
-      Id: 9
-      Equivalent ioctl: VHOST_SET_VRING_ADDR
-      Master payload: vring address description
-      Slave payload: N/A
-
-      Sets the addresses of the different aspects of the vring.
-
- * VHOST_USER_SET_VRING_BASE
-
-      Id: 10
-      Equivalent ioctl: VHOST_SET_VRING_BASE
-      Master payload: vring state description
-
-      Sets the base offset in the available vring.
-
- * VHOST_USER_GET_VRING_BASE
-
-      Id: 11
-      Equivalent ioctl: VHOST_USER_GET_VRING_BASE
-      Master payload: vring state description
-      Slave payload: vring state description
-
-      Get the available vring base offset.
-
- * VHOST_USER_SET_VRING_KICK
-
-      Id: 12
-      Equivalent ioctl: VHOST_SET_VRING_KICK
-      Master payload: u64
-
-      Set the event file descriptor for adding buffers to the vring. It
-      is passed in the ancillary data.
-      Bits (0-7) of the payload contain the vring index. Bit 8 is the
-      invalid FD flag. This flag is set when there is no file descriptor
-      in the ancillary data. This signals that polling should be used
-      instead of waiting for a kick.
-
- * VHOST_USER_SET_VRING_CALL
-
-      Id: 13
-      Equivalent ioctl: VHOST_SET_VRING_CALL
-      Master payload: u64
-
-      Set the event file descriptor to signal when buffers are used. It
-      is passed in the ancillary data.
-      Bits (0-7) of the payload contain the vring index. Bit 8 is the
-      invalid FD flag. This flag is set when there is no file descriptor
-      in the ancillary data. This signals that polling will be used
-      instead of waiting for the call.
-
- * VHOST_USER_SET_VRING_ERR
-
-      Id: 14
-      Equivalent ioctl: VHOST_SET_VRING_ERR
-      Master payload: u64
-
-      Set the event file descriptor to signal when error occurs. It
-      is passed in the ancillary data.
-      Bits (0-7) of the payload contain the vring index. Bit 8 is the
-      invalid FD flag. This flag is set when there is no file descriptor
-      in the ancillary data.
-
- * VHOST_USER_GET_QUEUE_NUM
-
-      Id: 17
-      Equivalent ioctl: N/A
-      Master payload: N/A
-      Slave payload: u64
-
-      Query how many queues the backend supports. This request should be
-      sent only when VHOST_USER_PROTOCOL_F_MQ is set in queried protocol
-      features by VHOST_USER_GET_PROTOCOL_FEATURES.
-
- * VHOST_USER_SET_VRING_ENABLE
-
-      Id: 18
-      Equivalent ioctl: N/A
-      Master payload: vring state description
-
-      Signal slave to enable or disable corresponding vring.
-      This request should be sent only when VHOST_USER_F_PROTOCOL_FEATURES
-      has been negotiated.
-
- * VHOST_USER_SEND_RARP
-
-      Id: 19
-      Equivalent ioctl: N/A
-      Master payload: u64
-
-      Ask vhost user backend to broadcast a fake RARP to notify the migration
-      is terminated for guest that does not support GUEST_ANNOUNCE.
-      Only legal if feature bit VHOST_USER_F_PROTOCOL_FEATURES is present in
-      VHOST_USER_GET_FEATURES and protocol feature bit VHOST_USER_PROTOCOL_F_RARP
-      is present in VHOST_USER_GET_PROTOCOL_FEATURES.
-      The first 6 bytes of the payload contain the mac address of the guest to
-      allow the vhost user backend to construct and broadcast the fake RARP.
-
- * VHOST_USER_NET_SET_MTU
-
-      Id: 20
-      Equivalent ioctl: N/A
-      Master payload: u64
-
-      Set host MTU value exposed to the guest.
-      This request should be sent only when VIRTIO_NET_F_MTU feature has been
-      successfully negotiated, VHOST_USER_F_PROTOCOL_FEATURES is present in
-      VHOST_USER_GET_FEATURES and protocol feature bit
-      VHOST_USER_PROTOCOL_F_NET_MTU is present in
-      VHOST_USER_GET_PROTOCOL_FEATURES.
-      If VHOST_USER_PROTOCOL_F_REPLY_ACK is negotiated, slave must respond
-      with zero in case the specified MTU is valid, or non-zero otherwise.
-
- * VHOST_USER_SET_SLAVE_REQ_FD
-
-      Id: 21
-      Equivalent ioctl: N/A
-      Master payload: N/A
-
-      Set the socket file descriptor for slave initiated requests. It is passed
-      in the ancillary data.
-      This request should be sent only when VHOST_USER_F_PROTOCOL_FEATURES
-      has been negotiated, and protocol feature bit VHOST_USER_PROTOCOL_F_SLAVE_REQ
-      bit is present in VHOST_USER_GET_PROTOCOL_FEATURES.
-      If VHOST_USER_PROTOCOL_F_REPLY_ACK is negotiated, slave must respond
-      with zero for success, non-zero otherwise.
-
- * VHOST_USER_IOTLB_MSG
-
-      Id: 22
-      Equivalent ioctl: N/A (equivalent to VHOST_IOTLB_MSG message type)
-      Master payload: struct vhost_iotlb_msg
-      Slave payload: u64
-
-      Send IOTLB messages with struct vhost_iotlb_msg as payload.
-      Master sends such requests to update and invalidate entries in the device
-      IOTLB. The slave has to acknowledge the request with sending zero as u64
-      payload for success, non-zero otherwise.
-      This request should be send only when VIRTIO_F_IOMMU_PLATFORM feature
-      has been successfully negotiated.
-
- * VHOST_USER_SET_VRING_ENDIAN
-
-      Id: 23
-      Equivalent ioctl: VHOST_SET_VRING_ENDIAN
-      Master payload: vring state description
-
-      Set the endianness of a VQ for legacy devices. Little-endian is indicated
-      with state.num set to 0 and big-endian is indicated with state.num set
-      to 1. Other values are invalid.
-      This request should be sent only when VHOST_USER_PROTOCOL_F_CROSS_ENDIAN
-      has been negotiated.
-      Backends that negotiated this feature should handle both endiannesses
-      and expect this message once (per VQ) during device configuration
-      (ie. before the master starts the VQ).
-
- * VHOST_USER_GET_CONFIG
-
-      Id: 24
-      Equivalent ioctl: N/A
-      Master payload: virtio device config space
-      Slave payload: virtio device config space
-
-      When VHOST_USER_PROTOCOL_F_CONFIG is negotiated, this message is
-      submitted by the vhost-user master to fetch the contents of the virtio
-      device configuration space, vhost-user slave's payload size MUST match
-      master's request, vhost-user slave uses zero length of payload to
-      indicate an error to vhost-user master. The vhost-user master may
-      cache the contents to avoid repeated VHOST_USER_GET_CONFIG calls.
-
-* VHOST_USER_SET_CONFIG
-
-      Id: 25
-      Equivalent ioctl: N/A
-      Master payload: virtio device config space
-      Slave payload: N/A
-
-      When VHOST_USER_PROTOCOL_F_CONFIG is negotiated, this message is
-      submitted by the vhost-user master when the Guest changes the virtio
-      device configuration space and also can be used for live migration
-      on the destination host. The vhost-user slave must check the flags
-      field, and slaves MUST NOT accept SET_CONFIG for read-only
-      configuration space fields unless the live migration bit is set.
-
-* VHOST_USER_CREATE_CRYPTO_SESSION
-
-     Id: 26
-     Equivalent ioctl: N/A
-     Master payload: crypto session description
-     Slave payload: crypto session description
-
-     Create a session for crypto operation. The server side must return the
-     session id, 0 or positive for success, negative for failure.
-     This request should be sent only when VHOST_USER_PROTOCOL_F_CRYPTO_SESSION
-     feature has been successfully negotiated.
-     It's a required feature for crypto devices.
-
-* VHOST_USER_CLOSE_CRYPTO_SESSION
-
-     Id: 27
-     Equivalent ioctl: N/A
-     Master payload: u64
-
-     Close a session for crypto operation which was previously
-     created by VHOST_USER_CREATE_CRYPTO_SESSION.
-     This request should be sent only when VHOST_USER_PROTOCOL_F_CRYPTO_SESSION
-     feature has been successfully negotiated.
-     It's a required feature for crypto devices.
-
- * VHOST_USER_POSTCOPY_ADVISE
-      Id: 28
-      Master payload: N/A
-      Slave payload: userfault fd
-
-      When VHOST_USER_PROTOCOL_F_PAGEFAULT is supported, the
-      master advises slave that a migration with postcopy enabled is underway,
-      the slave must open a userfaultfd for later use.
-      Note that at this stage the migration is still in precopy mode.
-
- * VHOST_USER_POSTCOPY_LISTEN
-      Id: 29
-      Master payload: N/A
-
-      Master advises slave that a transition to postcopy mode has happened.
-      The slave must ensure that shared memory is registered with userfaultfd
-      to cause faulting of non-present pages.
-
-      This is always sent sometime after a VHOST_USER_POSTCOPY_ADVISE, and
-      thus only when VHOST_USER_PROTOCOL_F_PAGEFAULT is supported.
-
- * VHOST_USER_POSTCOPY_END
-      Id: 30
-      Slave payload: u64
-
-      Master advises that postcopy migration has now completed.  The
-      slave must disable the userfaultfd. The response is an acknowledgement
-      only.
-      When VHOST_USER_PROTOCOL_F_PAGEFAULT is supported, this message
-      is sent at the end of the migration, after VHOST_USER_POSTCOPY_LISTEN
-      was previously sent.
-      The value returned is an error indication; 0 is success.
-
- * VHOST_USER_GET_INFLIGHT_FD
-      Id: 31
-      Equivalent ioctl: N/A
-      Master payload: inflight description
-
-      When VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD protocol feature has been
-      successfully negotiated, this message is submitted by master to get
-      a shared buffer from slave. The shared buffer will be used to track
-      inflight I/O by slave. QEMU should retrieve a new one when vm reset.
-
- * VHOST_USER_SET_INFLIGHT_FD
-      Id: 32
-      Equivalent ioctl: N/A
-      Master payload: inflight description
-
-      When VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD protocol feature has been
-      successfully negotiated, this message is submitted by master to send
-      the shared inflight buffer back to slave so that slave could get
-      inflight I/O after a crash or restart.
-
-Slave message types
--------------------
-
- * VHOST_USER_SLAVE_IOTLB_MSG
-
-      Id: 1
-      Equivalent ioctl: N/A (equivalent to VHOST_IOTLB_MSG message type)
-      Slave payload: struct vhost_iotlb_msg
-      Master payload: N/A
-
-      Send IOTLB messages with struct vhost_iotlb_msg as payload.
-      Slave sends such requests to notify of an IOTLB miss, or an IOTLB
-      access failure. If VHOST_USER_PROTOCOL_F_REPLY_ACK is negotiated,
-      and slave set the VHOST_USER_NEED_REPLY flag, master must respond with
-      zero when operation is successfully completed, or non-zero otherwise.
-      This request should be send only when VIRTIO_F_IOMMU_PLATFORM feature
-      has been successfully negotiated.
-
-* VHOST_USER_SLAVE_CONFIG_CHANGE_MSG
-
-     Id: 2
-     Equivalent ioctl: N/A
-     Slave payload: N/A
-     Master payload: N/A
-
-     When VHOST_USER_PROTOCOL_F_CONFIG is negotiated, vhost-user slave sends
-     such messages to notify that the virtio device's configuration space has
-     changed, for those host devices which can support such feature, host
-     driver can send VHOST_USER_GET_CONFIG message to slave to get the latest
-     content. If VHOST_USER_PROTOCOL_F_REPLY_ACK is negotiated, and slave set
-     the VHOST_USER_NEED_REPLY flag, master must respond with zero when
-     operation is successfully completed, or non-zero otherwise.
-
- * VHOST_USER_SLAVE_VRING_HOST_NOTIFIER_MSG
-
-      Id: 3
-      Equivalent ioctl: N/A
-      Slave payload: vring area description
-      Master payload: N/A
-
-      Sets host notifier for a specified queue. The queue index is contained
-      in the u64 field of the vring area description. The host notifier is
-      described by the file descriptor (typically it's a VFIO device fd) which
-      is passed as ancillary data and the size (which is mmap size and should
-      be the same as host page size) and offset (which is mmap offset) carried
-      in the vring area description. QEMU can mmap the file descriptor based
-      on the size and offset to get a memory range. Registering a host notifier
-      means mapping this memory range to the VM as the specified queue's notify
-      MMIO region. Slave sends this request to tell QEMU to de-register the
-      existing notifier if any and register the new notifier if the request is
-      sent with a file descriptor.
-      This request should be sent only when VHOST_USER_PROTOCOL_F_HOST_NOTIFIER
-      protocol feature has been successfully negotiated.
-
-VHOST_USER_PROTOCOL_F_REPLY_ACK:
--------------------------------
-The original vhost-user specification only demands replies for certain
-commands. This differs from the vhost protocol implementation where commands
-are sent over an ioctl() call and block until the client has completed.
-
-With this protocol extension negotiated, the sender (QEMU) can set the
-"need_reply" [Bit 3] flag to any command. This indicates that
-the client MUST respond with a Payload VhostUserMsg indicating success or
-failure. The payload should be set to zero on success or non-zero on failure,
-unless the message already has an explicit reply body.
-
-The response payload gives QEMU a deterministic indication of the result
-of the command. Today, QEMU is expected to terminate the main vhost-user
-loop upon receiving such errors. In future, qemu could be taught to be more
-resilient for selective requests.
-
-For the message types that already solicit a reply from the client, the
-presence of VHOST_USER_PROTOCOL_F_REPLY_ACK or need_reply bit being set brings
-no behavioural change. (See the 'Communication' section for details.)
-
-Backend program conventions
----------------------------
-
-vhost-user backends can provide various devices & services and may
-need to be configured manually depending on the use case. However, it
-is a good idea to follow the conventions listed here when
-possible. Users, QEMU or libvirt, can then rely on some common
-behaviour to avoid heterogenous configuration and management of the
-backend programs and facilitate interoperability.
-
-Each backend installed on a host system should come with at least one
-JSON file that conforms to the vhost-user.json schema. Each file
-informs the management applications about the backend type, and binary
-location. In addition, it defines rules for management apps for
-picking the highest priority backend when multiple match the search
-criteria (see @VhostUserBackend documentation in the schema file).
-
-If the backend is not capable of enabling a requested feature on the
-host (such as 3D acceleration with virgl), or the initialization
-failed, the backend should fail to start early and exit with a status
-!= 0. It may also print a message to stderr for further details.
-
-The backend program must not daemonize itself, but it may be
-daemonized by the management layer. It may also have a restricted
-access to the system.
-
-File descriptors 0, 1 and 2 will exist, and have regular
-stdin/stdout/stderr usage (they may have been redirected to /dev/null
-by the management layer, or to a log handler).
-
-The backend program must end (as quickly and cleanly as possible) when
-the SIGTERM signal is received. Eventually, it may receive SIGKILL by
-the management layer after a few seconds.
-
-The following command line options have an expected behaviour. They
-are mandatory, unless explicitly said differently:
-
-* --socket-path=PATH
-
-This option specify the location of the vhost-user Unix domain socket.
-It is incompatible with --fd.
-
-* --fd=FDNUM
-
-When this argument is given, the backend program is started with the
-vhost-user socket as file descriptor FDNUM. It is incompatible with
---socket-path.
-
-* --print-capabilities
-
-Output to stdout the backend capabilities in JSON format, and then
-exit successfully. Other options and arguments should be ignored, and
-the backend program should not perform its normal function.  The
-capabilities can be reported dynamically depending on the host
-capabilities.
-
-The JSON output is described in the vhost-user.json schema, by
-@VHostUserBackendCapabilities.  Example:
-{
-  "type": "foo",
-  "features": [
-    "feature-a",
-    "feature-b"
-  ]
-}
-
-vhost-user-input
-----------------
-
-Command line options:
-
-* --evdev-path=PATH (optional)
-
-Specify the linux input device.
-
-* --no-grab (optional)
-
-Do no request exclusive access to the input device.
-
-vhost-user-gpu
---------------
-
-Command line options:
-
-* --render-node=PATH (optional)
-
-Specify the GPU DRM render node.
-
-* --virgl (optional)
-
-Enable virgl rendering support.
diff --git a/fsdev/file-op-9p.h b/fsdev/file-op-9p.h
index 3fa062b39f..c757c8099f 100644
--- a/fsdev/file-op-9p.h
+++ b/fsdev/file-op-9p.h
@@ -147,7 +147,6 @@ struct FileOperations
     int (*renameat)(FsContext *ctx, V9fsPath *olddir, const char *old_name,
                     V9fsPath *newdir, const char *new_name);
     int (*unlinkat)(FsContext *ctx, V9fsPath *dir, const char *name, int flags);
-    void *opaque;
 };
 
 #endif
diff --git a/fsdev/qemu-fsdev.c b/fsdev/qemu-fsdev.c
index 54cb36a212..077a8c4e2b 100644
--- a/fsdev/qemu-fsdev.c
+++ b/fsdev/qemu-fsdev.c
@@ -18,15 +18,102 @@
 #include "qemu/error-report.h"
 #include "qemu/option.h"
 
+/*
+ * A table to store the various file systems and their callback operations.
+ * -----------------
+ * fstype | ops
+ * -----------------
+ *  local | local_ops
+ *  .     |
+ *  .     |
+ *  .     |
+ *  .     |
+ * -----------------
+ *  etc
+ */
+typedef struct FsDriverTable {
+    const char *name;
+    FileOperations *ops;
+    const char **opts;
+} FsDriverTable;
+
+typedef struct FsDriverListEntry {
+    FsDriverEntry fse;
+    QTAILQ_ENTRY(FsDriverListEntry) next;
+} FsDriverListEntry;
+
 static QTAILQ_HEAD(, FsDriverListEntry) fsdriver_entries =
     QTAILQ_HEAD_INITIALIZER(fsdriver_entries);
 
+#define COMMON_FS_DRIVER_OPTIONS "id", "fsdriver", "readonly"
+
 static FsDriverTable FsDrivers[] = {
-    { .name = "local", .ops = &local_ops},
-    { .name = "synth", .ops = &synth_ops},
-    { .name = "proxy", .ops = &proxy_ops},
+    {
+        .name = "local",
+        .ops = &local_ops,
+        .opts = (const char * []) {
+            COMMON_FS_DRIVER_OPTIONS,
+            "security_model",
+            "path",
+            "writeout",
+            "fmode",
+            "dmode",
+            "throttling.bps-total",
+            "throttling.bps-read",
+            "throttling.bps-write",
+            "throttling.iops-total",
+            "throttling.iops-read",
+            "throttling.iops-write",
+            "throttling.bps-total-max",
+            "throttling.bps-read-max",
+            "throttling.bps-write-max",
+            "throttling.iops-total-max",
+            "throttling.iops-read-max",
+            "throttling.iops-write-max",
+            "throttling.bps-total-max-length",
+            "throttling.bps-read-max-length",
+            "throttling.bps-write-max-length",
+            "throttling.iops-total-max-length",
+            "throttling.iops-read-max-length",
+            "throttling.iops-write-max-length",
+            "throttling.iops-size",
+        },
+    },
+    {
+        .name = "synth",
+        .ops = &synth_ops,
+        .opts = (const char * []) {
+            COMMON_FS_DRIVER_OPTIONS,
+        },
+    },
+    {
+        .name = "proxy",
+        .ops = &proxy_ops,
+        .opts = (const char * []) {
+            COMMON_FS_DRIVER_OPTIONS,
+            "socket",
+            "sock_fd",
+            "writeout",
+        },
+    },
 };
 
+static int validate_opt(void *opaque, const char *name, const char *value,
+                        Error **errp)
+{
+    FsDriverTable *drv = opaque;
+    const char **opt;
+
+    for (opt = drv->opts; *opt; opt++) {
+        if (!strcmp(*opt, name)) {
+            return 0;
+        }
+    }
+
+    error_setg(errp, "'%s' is invalid for fsdriver '%s'", name, drv->name);
+    return -1;
+}
+
 int qemu_fsdev_add(QemuOpts *opts, Error **errp)
 {
     int i;
@@ -57,6 +144,10 @@ int qemu_fsdev_add(QemuOpts *opts, Error **errp)
         return -1;
     }
 
+    if (qemu_opt_foreach(opts, validate_opt, &FsDrivers[i], errp)) {
+        return -1;
+    }
+
     fsle = g_malloc0(sizeof(*fsle));
     fsle->fse.fsdev_id = g_strdup(fsdev_id);
     fsle->fse.ops = FsDrivers[i].ops;
diff --git a/fsdev/qemu-fsdev.h b/fsdev/qemu-fsdev.h
index d9716b4144..52a5397770 100644
--- a/fsdev/qemu-fsdev.h
+++ b/fsdev/qemu-fsdev.h
@@ -14,34 +14,9 @@
 #define QEMU_FSDEV_H
 #include "file-op-9p.h"
 
-
-/*
- * A table to store the various file systems and their callback operations.
- * -----------------
- * fstype | ops
- * -----------------
- *  local | local_ops
- *  .     |
- *  .     |
- *  .     |
- *  .     |
- * -----------------
- *  etc
- */
-typedef struct FsDriverTable {
-    const char *name;
-    FileOperations *ops;
-} FsDriverTable;
-
-typedef struct FsDriverListEntry {
-    FsDriverEntry fse;
-    QTAILQ_ENTRY(FsDriverListEntry) next;
-} FsDriverListEntry;
-
 int qemu_fsdev_add(QemuOpts *opts, Error **errp);
 FsDriverEntry *get_fsdev_fsentry(char *id);
 extern FileOperations local_ops;
-extern FileOperations handle_ops;
 extern FileOperations synth_ops;
 extern FileOperations proxy_ops;
 #endif
diff --git a/hw/acpi/pcihp.c b/hw/acpi/pcihp.c
index 88e4ae1bcd..613406d09b 100644
--- a/hw/acpi/pcihp.c
+++ b/hw/acpi/pcihp.c
@@ -37,14 +37,7 @@
 #include "hw/pci/pci_bus.h"
 #include "qapi/error.h"
 #include "qom/qom-qobject.h"
-
-//#define DEBUG
-
-#ifdef DEBUG
-# define ACPI_PCIHP_DPRINTF(format, ...)     printf(format, ## __VA_ARGS__)
-#else
-# define ACPI_PCIHP_DPRINTF(format, ...)     do { } while (0)
-#endif
+#include "trace.h"
 
 #define ACPI_PCIHP_ADDR 0xae00
 #define ACPI_PCIHP_SIZE 0x0014
@@ -159,6 +152,8 @@ static void acpi_pcihp_eject_slot(AcpiPciHpState *s, unsigned bsel, unsigned slo
     int slot = ctz32(slots);
     PCIBus *bus = acpi_pcihp_find_hotplug_bus(s, bsel);
 
+    trace_acpi_pci_eject_slot(bsel, slot);
+
     if (!bus) {
         return;
     }
@@ -270,6 +265,8 @@ void acpi_pcihp_device_plug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s,
 void acpi_pcihp_device_unplug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s,
                                  DeviceState *dev, Error **errp)
 {
+    trace_acpi_pci_unplug(PCI_SLOT(PCI_DEVICE(dev)->devfn),
+                          acpi_pcihp_get_bsel(pci_get_bus(PCI_DEVICE(dev))));
     object_property_set_bool(OBJECT(dev), false, "realized", NULL);
 }
 
@@ -280,6 +277,9 @@ void acpi_pcihp_device_unplug_request_cb(HotplugHandler *hotplug_dev,
     PCIDevice *pdev = PCI_DEVICE(dev);
     int slot = PCI_SLOT(pdev->devfn);
     int bsel = acpi_pcihp_get_bsel(pci_get_bus(pdev));
+
+    trace_acpi_pci_unplug_request(bsel, slot);
+
     if (bsel < 0) {
         error_setg(errp, "Unsupported bus. Bus doesn't have property '"
                    ACPI_PCIHP_PROP_BSEL "' set");
@@ -306,23 +306,23 @@ static uint64_t pci_read(void *opaque, hwaddr addr, unsigned int size)
         if (!s->legacy_piix) {
             s->acpi_pcihp_pci_status[bsel].up = 0;
         }
-        ACPI_PCIHP_DPRINTF("pci_up_read %" PRIu32 "\n", val);
+        trace_acpi_pci_up_read(val);
         break;
     case PCI_DOWN_BASE:
         val = s->acpi_pcihp_pci_status[bsel].down;
-        ACPI_PCIHP_DPRINTF("pci_down_read %" PRIu32 "\n", val);
+        trace_acpi_pci_down_read(val);
         break;
     case PCI_EJ_BASE:
         /* No feature defined yet */
-        ACPI_PCIHP_DPRINTF("pci_features_read %" PRIu32 "\n", val);
+        trace_acpi_pci_features_read(val);
         break;
     case PCI_RMV_BASE:
         val = s->acpi_pcihp_pci_status[bsel].hotplug_enable;
-        ACPI_PCIHP_DPRINTF("pci_rmv_read %" PRIu32 "\n", val);
+        trace_acpi_pci_rmv_read(val);
         break;
     case PCI_SEL_BASE:
         val = s->hotplug_select;
-        ACPI_PCIHP_DPRINTF("pci_sel_read %" PRIu32 "\n", val);
+        trace_acpi_pci_sel_read(val);
     default:
         break;
     }
@@ -340,13 +340,11 @@ static void pci_write(void *opaque, hwaddr addr, uint64_t data,
             break;
         }
         acpi_pcihp_eject_slot(s, s->hotplug_select, data);
-        ACPI_PCIHP_DPRINTF("pciej write %" HWADDR_PRIx " <== %" PRIu64 "\n",
-                      addr, data);
+        trace_acpi_pci_ej_write(addr, data);
         break;
     case PCI_SEL_BASE:
         s->hotplug_select = s->legacy_piix ? ACPI_PCIHP_BSEL_DEFAULT : data;
-        ACPI_PCIHP_DPRINTF("pcisel write %" HWADDR_PRIx " <== %" PRIu64 "\n",
-                      addr, data);
+        trace_acpi_pci_sel_write(addr, data);
     default:
         break;
     }
diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c
index 9c079d6834..ec4e186cec 100644
--- a/hw/acpi/piix4.c
+++ b/hw/acpi/piix4.c
@@ -39,14 +39,7 @@
 #include "hw/acpi/acpi_dev_interface.h"
 #include "hw/xen/xen.h"
 #include "qom/cpu.h"
-
-//#define DEBUG
-
-#ifdef DEBUG
-# define PIIX4_DPRINTF(format, ...)     printf(format, ## __VA_ARGS__)
-#else
-# define PIIX4_DPRINTF(format, ...)     do { } while (0)
-#endif
+#include "trace.h"
 
 #define GPE_BASE 0xafe0
 #define GPE_LEN 4
@@ -92,8 +85,6 @@ typedef struct PIIX4PMState {
     MemHotplugState acpi_memory_hotplug;
 } PIIX4PMState;
 
-#define TYPE_PIIX4_PM "PIIX4_PM"
-
 #define PIIX4_PM(obj) \
     OBJECT_CHECK(PIIX4PMState, (obj), TYPE_PIIX4_PM)
 
@@ -554,17 +545,6 @@ static void piix4_pm_realize(PCIDevice *dev, Error **errp)
     piix4_pm_add_propeties(s);
 }
 
-Object *piix4_pm_find(void)
-{
-    bool ambig;
-    Object *o = object_resolve_path_type("", TYPE_PIIX4_PM, &ambig);
-
-    if (ambig || !o) {
-        return NULL;
-    }
-    return o;
-}
-
 I2CBus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
                       qemu_irq sci_irq, qemu_irq smi_irq,
                       int smm_enabled, DeviceState **piix4_pm)
@@ -596,7 +576,7 @@ static uint64_t gpe_readb(void *opaque, hwaddr addr, unsigned width)
     PIIX4PMState *s = opaque;
     uint32_t val = acpi_gpe_ioport_readb(&s->ar, addr);
 
-    PIIX4_DPRINTF("gpe read %" HWADDR_PRIx " == %" PRIu32 "\n", addr, val);
+    trace_piix4_gpe_readb(addr, width, val);
     return val;
 }
 
@@ -605,10 +585,9 @@ static void gpe_writeb(void *opaque, hwaddr addr, uint64_t val,
 {
     PIIX4PMState *s = opaque;
 
+    trace_piix4_gpe_writeb(addr, width, val);
     acpi_gpe_ioport_writeb(&s->ar, addr, val);
     acpi_update_sci(&s->ar, s->irq);
-
-    PIIX4_DPRINTF("gpe write %" HWADDR_PRIx " <== %" PRIu64 "\n", addr, val);
 }
 
 static const MemoryRegionOps piix4_gpe_ops = {
diff --git a/hw/acpi/trace-events b/hw/acpi/trace-events
index 6272d8a9e7..96b8273297 100644
--- a/hw/acpi/trace-events
+++ b/hw/acpi/trace-events
@@ -31,6 +31,22 @@ cpuhp_acpi_ejecting_cpu(uint32_t idx) "0x%"PRIx32
 cpuhp_acpi_write_ost_ev(uint32_t slot, uint32_t ev) "idx[0x%"PRIx32"] OST EVENT: 0x%"PRIx32
 cpuhp_acpi_write_ost_status(uint32_t slot, uint32_t st) "idx[0x%"PRIx32"] OST STATUS: 0x%"PRIx32
 
+# pcihp.c
+acpi_pci_eject_slot(unsigned bsel, unsigned slot) "bsel: %u slot: %u"
+acpi_pci_unplug(int bsel, int slot) "bsel: %d slot: %d"
+acpi_pci_unplug_request(int bsel, int slot) "bsel: %d slot: %d"
+acpi_pci_up_read(uint32_t val) "%" PRIu32
+acpi_pci_down_read(uint32_t val) "%" PRIu32
+acpi_pci_features_read(uint32_t val) "%" PRIu32
+acpi_pci_rmv_read(uint32_t val) "%" PRIu32
+acpi_pci_sel_read(uint32_t val) "%" PRIu32
+acpi_pci_ej_write(uint64_t addr, uint64_t data) "0x%" PRIx64 " <== %" PRIu64
+acpi_pci_sel_write(uint64_t addr, uint64_t data) "0x%" PRIx64 " <== %" PRIu64
+
+# piix4.c
+piix4_gpe_readb(uint64_t addr, unsigned width, uint64_t val) "addr: 0x%" PRIx64 " width: %d ==> 0x%" PRIx64
+piix4_gpe_writeb(uint64_t addr, unsigned width, uint64_t val) "addr: 0x%" PRIx64 " width: %d <== 0x%" PRIx64
+
 # tco.c
 tco_timer_reload(int ticks, int msec) "ticks=%d (%d ms)"
 tco_timer_expired(int timeouts_no, bool strap, bool no_reboot) "timeouts_no=%d no_reboot=%d/%d"
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index bf9c0bc2f4..e7c96d658e 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -40,6 +40,7 @@
 #include "hw/loader.h"
 #include "hw/hw.h"
 #include "hw/acpi/aml-build.h"
+#include "hw/acpi/pci.h"
 #include "hw/pci/pcie_host.h"
 #include "hw/pci/pci.h"
 #include "hw/arm/virt.h"
@@ -546,25 +547,20 @@ build_srat(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
 }
 
 static void
-build_mcfg(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
+build_mcfg(GArray *table_data, BIOSLinker *linker, AcpiMcfgInfo *info)
 {
     AcpiTableMcfg *mcfg;
-    const MemMapEntry *memmap = vms->memmap;
-    int ecam_id = VIRT_ECAM_ID(vms->highmem_ecam);
     int len = sizeof(*mcfg) + sizeof(mcfg->allocation[0]);
-    int mcfg_start = table_data->len;
 
     mcfg = acpi_data_push(table_data, len);
-    mcfg->allocation[0].address = cpu_to_le64(memmap[ecam_id].base);
+    mcfg->allocation[0].address = cpu_to_le64(info->base);
 
     /* Only a single allocation so no need to play with segments */
     mcfg->allocation[0].pci_segment = cpu_to_le16(0);
     mcfg->allocation[0].start_bus_number = 0;
-    mcfg->allocation[0].end_bus_number =
-        PCIE_MMCFG_BUS(memmap[ecam_id].size - 1);
+    mcfg->allocation[0].end_bus_number = PCIE_MMCFG_BUS(info->size - 1);
 
-    build_header(linker, table_data, (void *)(table_data->data + mcfg_start),
-                 "MCFG", table_data->len - mcfg_start, 1, NULL, NULL);
+    build_header(linker, table_data, (void *)mcfg, "MCFG", len, 1, NULL, NULL);
 }
 
 /* GTDT */
@@ -803,7 +799,13 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables)
     build_gtdt(tables_blob, tables->linker, vms);
 
     acpi_add_table(table_offsets, tables_blob);
-    build_mcfg(tables_blob, tables->linker, vms);
+    {
+        AcpiMcfgInfo mcfg = {
+           .base = vms->memmap[VIRT_ECAM_ID(vms->highmem_ecam)].base,
+           .size = vms->memmap[VIRT_ECAM_ID(vms->highmem_ecam)].size,
+        };
+        build_mcfg(tables_blob, tables->linker, &mcfg);
+    }
 
     acpi_add_table(table_offsets, tables_blob);
     build_spcr(tables_blob, tables->linker, vms);
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
index 7caf92532a..63a5b58849 100644
--- a/hw/block/nvme.c
+++ b/hw/block/nvme.c
@@ -238,7 +238,7 @@ static uint16_t nvme_dma_read_prp(NvmeCtrl *n, uint8_t *ptr, uint32_t len,
         }
         qemu_sglist_destroy(&qsg);
     } else {
-        if (unlikely(qemu_iovec_to_buf(&iov, 0, ptr, len) != len)) {
+        if (unlikely(qemu_iovec_from_buf(&iov, 0, ptr, len) != len)) {
             trace_nvme_err_invalid_dma();
             status = NVME_INVALID_FIELD | NVME_DNR;
         }
diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c
index 28b81368f7..9cb61336a6 100644
--- a/hw/block/vhost-user-blk.c
+++ b/hw/block/vhost-user-blk.c
@@ -103,7 +103,7 @@ const VhostDevConfigOps blk_ops = {
     .vhost_dev_config_notifier = vhost_user_blk_handle_config_change,
 };
 
-static void vhost_user_blk_start(VirtIODevice *vdev)
+static int vhost_user_blk_start(VirtIODevice *vdev)
 {
     VHostUserBlk *s = VHOST_USER_BLK(vdev);
     BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
@@ -112,13 +112,13 @@ static void vhost_user_blk_start(VirtIODevice *vdev)
 
     if (!k->set_guest_notifiers) {
         error_report("binding does not support guest notifiers");
-        return;
+        return -ENOSYS;
     }
 
     ret = vhost_dev_enable_notifiers(&s->dev, vdev);
     if (ret < 0) {
         error_report("Error enabling host notifiers: %d", -ret);
-        return;
+        return ret;
     }
 
     ret = k->set_guest_notifiers(qbus->parent, s->dev.nvqs, true);
@@ -157,12 +157,13 @@ static void vhost_user_blk_start(VirtIODevice *vdev)
         vhost_virtqueue_mask(&s->dev, vdev, i, false);
     }
 
-    return;
+    return ret;
 
 err_guest_notifiers:
     k->set_guest_notifiers(qbus->parent, s->dev.nvqs, false);
 err_host_notifiers:
     vhost_dev_disable_notifiers(&s->dev, vdev);
+    return ret;
 }
 
 static void vhost_user_blk_stop(VirtIODevice *vdev)
@@ -190,18 +191,28 @@ static void vhost_user_blk_stop(VirtIODevice *vdev)
 static void vhost_user_blk_set_status(VirtIODevice *vdev, uint8_t status)
 {
     VHostUserBlk *s = VHOST_USER_BLK(vdev);
-    bool should_start = status & VIRTIO_CONFIG_S_DRIVER_OK;
+    bool should_start = vdev->started;
+    int ret;
 
     if (!vdev->vm_running) {
         should_start = false;
     }
 
+    if (!s->connected) {
+        return;
+    }
+
     if (s->dev.started == should_start) {
         return;
     }
 
     if (should_start) {
-        vhost_user_blk_start(vdev);
+        ret = vhost_user_blk_start(vdev);
+        if (ret < 0) {
+            error_report("vhost-user-blk: vhost start failed: %s",
+                         strerror(-ret));
+            qemu_chr_fe_disconnect(&s->chardev);
+        }
     } else {
         vhost_user_blk_stop(vdev);
     }
@@ -237,10 +248,13 @@ static uint64_t vhost_user_blk_get_features(VirtIODevice *vdev,
 static void vhost_user_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq)
 {
     VHostUserBlk *s = VHOST_USER_BLK(vdev);
-    int i;
+    int i, ret;
 
-    if (!(virtio_host_has_feature(vdev, VIRTIO_F_VERSION_1) &&
-        !virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1))) {
+    if (!vdev->start_on_kick) {
+        return;
+    }
+
+    if (!s->connected) {
         return;
     }
 
@@ -251,7 +265,13 @@ static void vhost_user_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq)
     /* Some guests kick before setting VIRTIO_CONFIG_S_DRIVER_OK so start
      * vhost here instead of waiting for .set_status().
      */
-    vhost_user_blk_start(vdev);
+    ret = vhost_user_blk_start(vdev);
+    if (ret < 0) {
+        error_report("vhost-user-blk: vhost start failed: %s",
+                     strerror(-ret));
+        qemu_chr_fe_disconnect(&s->chardev);
+        return;
+    }
 
     /* Kick right away to begin processing requests already in vring */
     for (i = 0; i < s->dev.nvqs; i++) {
@@ -271,11 +291,103 @@ static void vhost_user_blk_reset(VirtIODevice *vdev)
     vhost_dev_free_inflight(s->inflight);
 }
 
+static int vhost_user_blk_connect(DeviceState *dev)
+{
+    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+    VHostUserBlk *s = VHOST_USER_BLK(vdev);
+    int ret = 0;
+
+    if (s->connected) {
+        return 0;
+    }
+    s->connected = true;
+
+    s->dev.nvqs = s->num_queues;
+    s->dev.vqs = s->vqs;
+    s->dev.vq_index = 0;
+    s->dev.backend_features = 0;
+
+    vhost_dev_set_config_notifier(&s->dev, &blk_ops);
+
+    ret = vhost_dev_init(&s->dev, &s->vhost_user, VHOST_BACKEND_TYPE_USER, 0);
+    if (ret < 0) {
+        error_report("vhost-user-blk: vhost initialization failed: %s",
+                     strerror(-ret));
+        return ret;
+    }
+
+    /* restore vhost state */
+    if (vdev->started) {
+        ret = vhost_user_blk_start(vdev);
+        if (ret < 0) {
+            error_report("vhost-user-blk: vhost start failed: %s",
+                         strerror(-ret));
+            return ret;
+        }
+    }
+
+    return 0;
+}
+
+static void vhost_user_blk_disconnect(DeviceState *dev)
+{
+    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+    VHostUserBlk *s = VHOST_USER_BLK(vdev);
+
+    if (!s->connected) {
+        return;
+    }
+    s->connected = false;
+
+    if (s->dev.started) {
+        vhost_user_blk_stop(vdev);
+    }
+
+    vhost_dev_cleanup(&s->dev);
+}
+
+static gboolean vhost_user_blk_watch(GIOChannel *chan, GIOCondition cond,
+                                     void *opaque)
+{
+    DeviceState *dev = opaque;
+    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+    VHostUserBlk *s = VHOST_USER_BLK(vdev);
+
+    qemu_chr_fe_disconnect(&s->chardev);
+
+    return true;
+}
+
+static void vhost_user_blk_event(void *opaque, int event)
+{
+    DeviceState *dev = opaque;
+    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+    VHostUserBlk *s = VHOST_USER_BLK(vdev);
+
+    switch (event) {
+    case CHR_EVENT_OPENED:
+        if (vhost_user_blk_connect(dev) < 0) {
+            qemu_chr_fe_disconnect(&s->chardev);
+            return;
+        }
+        s->watch = qemu_chr_fe_add_watch(&s->chardev, G_IO_HUP,
+                                         vhost_user_blk_watch, dev);
+        break;
+    case CHR_EVENT_CLOSED:
+        vhost_user_blk_disconnect(dev);
+        if (s->watch) {
+            g_source_remove(s->watch);
+            s->watch = 0;
+        }
+        break;
+    }
+}
+
 static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp)
 {
     VirtIODevice *vdev = VIRTIO_DEVICE(dev);
     VHostUserBlk *s = VHOST_USER_BLK(vdev);
-    struct vhost_virtqueue *vqs = NULL;
+    Error *err = NULL;
     int i, ret;
 
     if (!s->chardev.chr) {
@@ -306,27 +418,29 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp)
     }
 
     s->inflight = g_new0(struct vhost_inflight, 1);
+    s->vqs = g_new(struct vhost_virtqueue, s->num_queues);
+    s->watch = 0;
+    s->connected = false;
 
-    s->dev.nvqs = s->num_queues;
-    s->dev.vqs = g_new(struct vhost_virtqueue, s->dev.nvqs);
-    s->dev.vq_index = 0;
-    s->dev.backend_features = 0;
-    vqs = s->dev.vqs;
-
-    vhost_dev_set_config_notifier(&s->dev, &blk_ops);
+    qemu_chr_fe_set_handlers(&s->chardev,  NULL, NULL, vhost_user_blk_event,
+                             NULL, (void *)dev, NULL, true);
 
-    ret = vhost_dev_init(&s->dev, &s->vhost_user, VHOST_BACKEND_TYPE_USER, 0);
-    if (ret < 0) {
-        error_setg(errp, "vhost-user-blk: vhost initialization failed: %s",
-                   strerror(-ret));
+reconnect:
+    if (qemu_chr_fe_wait_connected(&s->chardev, &err) < 0) {
+        error_report_err(err);
         goto virtio_err;
     }
 
+    /* check whether vhost_user_blk_connect() failed or not */
+    if (!s->connected) {
+        goto reconnect;
+    }
+
     ret = vhost_dev_get_config(&s->dev, (uint8_t *)&s->blkcfg,
-                              sizeof(struct virtio_blk_config));
+                               sizeof(struct virtio_blk_config));
     if (ret < 0) {
-        error_setg(errp, "vhost-user-blk: get block config failed");
-        goto vhost_err;
+        error_report("vhost-user-blk: get block config failed");
+        goto reconnect;
     }
 
     if (s->blkcfg.num_queues != s->num_queues) {
@@ -335,10 +449,8 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp)
 
     return;
 
-vhost_err:
-    vhost_dev_cleanup(&s->dev);
 virtio_err:
-    g_free(vqs);
+    g_free(s->vqs);
     g_free(s->inflight);
     virtio_cleanup(vdev);
     vhost_user_cleanup(&s->vhost_user);
@@ -348,12 +460,13 @@ static void vhost_user_blk_device_unrealize(DeviceState *dev, Error **errp)
 {
     VirtIODevice *vdev = VIRTIO_DEVICE(dev);
     VHostUserBlk *s = VHOST_USER_BLK(dev);
-    struct vhost_virtqueue *vqs = s->dev.vqs;
 
-    vhost_user_blk_set_status(vdev, 0);
+    virtio_set_status(vdev, 0);
+    qemu_chr_fe_set_handlers(&s->chardev,  NULL, NULL, NULL,
+                             NULL, NULL, NULL, false);
     vhost_dev_cleanup(&s->dev);
     vhost_dev_free_inflight(s->inflight);
-    g_free(vqs);
+    g_free(s->vqs);
     g_free(s->inflight);
     virtio_cleanup(vdev);
     vhost_user_cleanup(&s->vhost_user);
diff --git a/hw/char/Kconfig b/hw/char/Kconfig
index 6360c9fffa..40e7a8b8bb 100644
--- a/hw/char/Kconfig
+++ b/hw/char/Kconfig
@@ -24,6 +24,12 @@ config SERIAL_PCI
     depends on PCI
     select SERIAL
 
+config SERIAL_PCI_MULTI
+    bool
+    default y if PCI_DEVICES
+    depends on PCI
+    select SERIAL
+
 config VIRTIO_SERIAL
     bool
     default y
diff --git a/hw/char/Makefile.objs b/hw/char/Makefile.objs
index cf086e7114..02d8a66925 100644
--- a/hw/char/Makefile.objs
+++ b/hw/char/Makefile.objs
@@ -7,6 +7,7 @@ common-obj-$(CONFIG_PL011) += pl011.o
 common-obj-$(CONFIG_SERIAL) += serial.o
 common-obj-$(CONFIG_SERIAL_ISA) += serial-isa.o
 common-obj-$(CONFIG_SERIAL_PCI) += serial-pci.o
+common-obj-$(CONFIG_SERIAL_PCI_MULTI) += serial-pci-multi.o
 common-obj-$(CONFIG_VIRTIO_SERIAL) += virtio-console.o
 common-obj-$(CONFIG_XILINX) += xilinx_uartlite.o
 common-obj-$(CONFIG_XEN) += xen_console.o
diff --git a/hw/char/escc.c b/hw/char/escc.c
index 628f5f81f7..c5b05a63f1 100644
--- a/hw/char/escc.c
+++ b/hw/char/escc.c
@@ -509,6 +509,13 @@ static void escc_mem_write(void *opaque, hwaddr addr,
         break;
     case SERIAL_DATA:
         trace_escc_mem_writeb_data(CHN_C(s), val);
+        /*
+         * Lower the irq when data is written to the Tx buffer and no other
+         * interrupts are currently pending. The irq will be raised again once
+         * the Tx buffer becomes empty below.
+         */
+        s->txint = 0;
+        escc_update_irq(s);
         s->tx = val;
         if (s->wregs[W_TXCTRL2] & TXCTRL2_TXEN) { // tx enabled
             if (qemu_chr_fe_backend_connected(&s->chr)) {
diff --git a/hw/char/grlib_apbuart.c b/hw/char/grlib_apbuart.c
index e1d258b611..9623016d56 100644
--- a/hw/char/grlib_apbuart.c
+++ b/hw/char/grlib_apbuart.c
@@ -1,7 +1,7 @@
 /*
  * QEMU GRLIB APB UART Emulator
  *
- * Copyright (c) 2010-2011 AdaCore
+ * Copyright (c) 2010-2019 AdaCore
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
@@ -23,6 +23,7 @@
  */
 
 #include "qemu/osdep.h"
+#include "hw/sparc/grlib.h"
 #include "hw/sysbus.h"
 #include "chardev/char-fe.h"
 
@@ -68,7 +69,6 @@
 
 #define FIFO_LENGTH 1024
 
-#define TYPE_GRLIB_APB_UART "grlib,apbuart"
 #define GRLIB_APB_UART(obj) \
     OBJECT_CHECK(UART, (obj), TYPE_GRLIB_APB_UART)
 
diff --git a/hw/char/serial-pci-multi.c b/hw/char/serial-pci-multi.c
new file mode 100644
index 0000000000..63dcbaa984
--- /dev/null
+++ b/hw/char/serial-pci-multi.c
@@ -0,0 +1,208 @@
+/*
+ * QEMU 16550A multi UART emulation
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ * Copyright (c) 2008 Citrix Systems, Inc.
+ *
+ * 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.
+ */
+
+/* see docs/specs/pci-serial.txt */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/char/serial.h"
+#include "hw/pci/pci.h"
+
+#define PCI_SERIAL_MAX_PORTS 4
+
+typedef struct PCIMultiSerialState {
+    PCIDevice    dev;
+    MemoryRegion iobar;
+    uint32_t     ports;
+    char         *name[PCI_SERIAL_MAX_PORTS];
+    SerialState  state[PCI_SERIAL_MAX_PORTS];
+    uint32_t     level[PCI_SERIAL_MAX_PORTS];
+    qemu_irq     *irqs;
+    uint8_t      prog_if;
+} PCIMultiSerialState;
+
+static void multi_serial_pci_exit(PCIDevice *dev)
+{
+    PCIMultiSerialState *pci = DO_UPCAST(PCIMultiSerialState, dev, dev);
+    SerialState *s;
+    int i;
+
+    for (i = 0; i < pci->ports; i++) {
+        s = pci->state + i;
+        serial_exit_core(s);
+        memory_region_del_subregion(&pci->iobar, &s->io);
+        g_free(pci->name[i]);
+    }
+    qemu_free_irqs(pci->irqs, pci->ports);
+}
+
+static void multi_serial_irq_mux(void *opaque, int n, int level)
+{
+    PCIMultiSerialState *pci = opaque;
+    int i, pending = 0;
+
+    pci->level[n] = level;
+    for (i = 0; i < pci->ports; i++) {
+        if (pci->level[i]) {
+            pending = 1;
+        }
+    }
+    pci_set_irq(&pci->dev, pending);
+}
+
+static void multi_serial_pci_realize(PCIDevice *dev, Error **errp)
+{
+    PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
+    PCIMultiSerialState *pci = DO_UPCAST(PCIMultiSerialState, dev, dev);
+    SerialState *s;
+    Error *err = NULL;
+    int i, nr_ports = 0;
+
+    switch (pc->device_id) {
+    case 0x0003:
+        nr_ports = 2;
+        break;
+    case 0x0004:
+        nr_ports = 4;
+        break;
+    }
+    assert(nr_ports > 0);
+    assert(nr_ports <= PCI_SERIAL_MAX_PORTS);
+
+    pci->dev.config[PCI_CLASS_PROG] = pci->prog_if;
+    pci->dev.config[PCI_INTERRUPT_PIN] = 0x01;
+    memory_region_init(&pci->iobar, OBJECT(pci), "multiserial", 8 * nr_ports);
+    pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &pci->iobar);
+    pci->irqs = qemu_allocate_irqs(multi_serial_irq_mux, pci,
+                                   nr_ports);
+
+    for (i = 0; i < nr_ports; i++) {
+        s = pci->state + i;
+        s->baudbase = 115200;
+        serial_realize_core(s, &err);
+        if (err != NULL) {
+            error_propagate(errp, err);
+            multi_serial_pci_exit(dev);
+            return;
+        }
+        s->irq = pci->irqs[i];
+        pci->name[i] = g_strdup_printf("uart #%d", i + 1);
+        memory_region_init_io(&s->io, OBJECT(pci), &serial_io_ops, s,
+                              pci->name[i], 8);
+        memory_region_add_subregion(&pci->iobar, 8 * i, &s->io);
+        pci->ports++;
+    }
+}
+
+static const VMStateDescription vmstate_pci_multi_serial = {
+    .name = "pci-serial-multi",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_PCI_DEVICE(dev, PCIMultiSerialState),
+        VMSTATE_STRUCT_ARRAY(state, PCIMultiSerialState, PCI_SERIAL_MAX_PORTS,
+                             0, vmstate_serial, SerialState),
+        VMSTATE_UINT32_ARRAY(level, PCIMultiSerialState, PCI_SERIAL_MAX_PORTS),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property multi_2x_serial_pci_properties[] = {
+    DEFINE_PROP_CHR("chardev1",  PCIMultiSerialState, state[0].chr),
+    DEFINE_PROP_CHR("chardev2",  PCIMultiSerialState, state[1].chr),
+    DEFINE_PROP_UINT8("prog_if",  PCIMultiSerialState, prog_if, 0x02),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static Property multi_4x_serial_pci_properties[] = {
+    DEFINE_PROP_CHR("chardev1",  PCIMultiSerialState, state[0].chr),
+    DEFINE_PROP_CHR("chardev2",  PCIMultiSerialState, state[1].chr),
+    DEFINE_PROP_CHR("chardev3",  PCIMultiSerialState, state[2].chr),
+    DEFINE_PROP_CHR("chardev4",  PCIMultiSerialState, state[3].chr),
+    DEFINE_PROP_UINT8("prog_if",  PCIMultiSerialState, prog_if, 0x02),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void multi_2x_serial_pci_class_initfn(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass);
+    pc->realize = multi_serial_pci_realize;
+    pc->exit = multi_serial_pci_exit;
+    pc->vendor_id = PCI_VENDOR_ID_REDHAT;
+    pc->device_id = PCI_DEVICE_ID_REDHAT_SERIAL2;
+    pc->revision = 1;
+    pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL;
+    dc->vmsd = &vmstate_pci_multi_serial;
+    dc->props = multi_2x_serial_pci_properties;
+    set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
+}
+
+static void multi_4x_serial_pci_class_initfn(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass);
+    pc->realize = multi_serial_pci_realize;
+    pc->exit = multi_serial_pci_exit;
+    pc->vendor_id = PCI_VENDOR_ID_REDHAT;
+    pc->device_id = PCI_DEVICE_ID_REDHAT_SERIAL4;
+    pc->revision = 1;
+    pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL;
+    dc->vmsd = &vmstate_pci_multi_serial;
+    dc->props = multi_4x_serial_pci_properties;
+    set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
+}
+
+static const TypeInfo multi_2x_serial_pci_info = {
+    .name          = "pci-serial-2x",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIMultiSerialState),
+    .class_init    = multi_2x_serial_pci_class_initfn,
+    .interfaces = (InterfaceInfo[]) {
+        { INTERFACE_CONVENTIONAL_PCI_DEVICE },
+        { },
+    },
+};
+
+static const TypeInfo multi_4x_serial_pci_info = {
+    .name          = "pci-serial-4x",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIMultiSerialState),
+    .class_init    = multi_4x_serial_pci_class_initfn,
+    .interfaces = (InterfaceInfo[]) {
+        { INTERFACE_CONVENTIONAL_PCI_DEVICE },
+        { },
+    },
+};
+
+static void multi_serial_pci_register_types(void)
+{
+    type_register_static(&multi_2x_serial_pci_info);
+    type_register_static(&multi_4x_serial_pci_info);
+}
+
+type_init(multi_serial_pci_register_types)
diff --git a/hw/char/serial-pci.c b/hw/char/serial-pci.c
index cb0d04c1d9..2d5ffae5cf 100644
--- a/hw/char/serial-pci.c
+++ b/hw/char/serial-pci.c
@@ -30,26 +30,12 @@
 #include "hw/char/serial.h"
 #include "hw/pci/pci.h"
 
-#define PCI_SERIAL_MAX_PORTS 4
-
 typedef struct PCISerialState {
     PCIDevice dev;
     SerialState state;
     uint8_t prog_if;
 } PCISerialState;
 
-typedef struct PCIMultiSerialState {
-    PCIDevice    dev;
-    MemoryRegion iobar;
-    uint32_t     ports;
-    char         *name[PCI_SERIAL_MAX_PORTS];
-    SerialState  state[PCI_SERIAL_MAX_PORTS];
-    uint32_t     level[PCI_SERIAL_MAX_PORTS];
-    qemu_irq     *irqs;
-    uint8_t      prog_if;
-} PCIMultiSerialState;
-
-static void multi_serial_pci_exit(PCIDevice *dev);
 
 static void serial_pci_realize(PCIDevice *dev, Error **errp)
 {
@@ -72,64 +58,6 @@ static void serial_pci_realize(PCIDevice *dev, Error **errp)
     pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io);
 }
 
-static void multi_serial_irq_mux(void *opaque, int n, int level)
-{
-    PCIMultiSerialState *pci = opaque;
-    int i, pending = 0;
-
-    pci->level[n] = level;
-    for (i = 0; i < pci->ports; i++) {
-        if (pci->level[i]) {
-            pending = 1;
-        }
-    }
-    pci_set_irq(&pci->dev, pending);
-}
-
-static void multi_serial_pci_realize(PCIDevice *dev, Error **errp)
-{
-    PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
-    PCIMultiSerialState *pci = DO_UPCAST(PCIMultiSerialState, dev, dev);
-    SerialState *s;
-    Error *err = NULL;
-    int i, nr_ports = 0;
-
-    switch (pc->device_id) {
-    case 0x0003:
-        nr_ports = 2;
-        break;
-    case 0x0004:
-        nr_ports = 4;
-        break;
-    }
-    assert(nr_ports > 0);
-    assert(nr_ports <= PCI_SERIAL_MAX_PORTS);
-
-    pci->dev.config[PCI_CLASS_PROG] = pci->prog_if;
-    pci->dev.config[PCI_INTERRUPT_PIN] = 0x01;
-    memory_region_init(&pci->iobar, OBJECT(pci), "multiserial", 8 * nr_ports);
-    pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &pci->iobar);
-    pci->irqs = qemu_allocate_irqs(multi_serial_irq_mux, pci,
-                                   nr_ports);
-
-    for (i = 0; i < nr_ports; i++) {
-        s = pci->state + i;
-        s->baudbase = 115200;
-        serial_realize_core(s, &err);
-        if (err != NULL) {
-            error_propagate(errp, err);
-            multi_serial_pci_exit(dev);
-            return;
-        }
-        s->irq = pci->irqs[i];
-        pci->name[i] = g_strdup_printf("uart #%d", i+1);
-        memory_region_init_io(&s->io, OBJECT(pci), &serial_io_ops, s,
-                              pci->name[i], 8);
-        memory_region_add_subregion(&pci->iobar, 8 * i, &s->io);
-        pci->ports++;
-    }
-}
-
 static void serial_pci_exit(PCIDevice *dev)
 {
     PCISerialState *pci = DO_UPCAST(PCISerialState, dev, dev);
@@ -139,21 +67,6 @@ static void serial_pci_exit(PCIDevice *dev)
     qemu_free_irq(s->irq);
 }
 
-static void multi_serial_pci_exit(PCIDevice *dev)
-{
-    PCIMultiSerialState *pci = DO_UPCAST(PCIMultiSerialState, dev, dev);
-    SerialState *s;
-    int i;
-
-    for (i = 0; i < pci->ports; i++) {
-        s = pci->state + i;
-        serial_exit_core(s);
-        memory_region_del_subregion(&pci->iobar, &s->io);
-        g_free(pci->name[i]);
-    }
-    qemu_free_irqs(pci->irqs, pci->ports);
-}
-
 static const VMStateDescription vmstate_pci_serial = {
     .name = "pci-serial",
     .version_id = 1,
@@ -165,41 +78,12 @@ static const VMStateDescription vmstate_pci_serial = {
     }
 };
 
-static const VMStateDescription vmstate_pci_multi_serial = {
-    .name = "pci-serial-multi",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_PCI_DEVICE(dev, PCIMultiSerialState),
-        VMSTATE_STRUCT_ARRAY(state, PCIMultiSerialState, PCI_SERIAL_MAX_PORTS,
-                             0, vmstate_serial, SerialState),
-        VMSTATE_UINT32_ARRAY(level, PCIMultiSerialState, PCI_SERIAL_MAX_PORTS),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
 static Property serial_pci_properties[] = {
     DEFINE_PROP_CHR("chardev",  PCISerialState, state.chr),
     DEFINE_PROP_UINT8("prog_if",  PCISerialState, prog_if, 0x02),
     DEFINE_PROP_END_OF_LIST(),
 };
 
-static Property multi_2x_serial_pci_properties[] = {
-    DEFINE_PROP_CHR("chardev1",  PCIMultiSerialState, state[0].chr),
-    DEFINE_PROP_CHR("chardev2",  PCIMultiSerialState, state[1].chr),
-    DEFINE_PROP_UINT8("prog_if",  PCIMultiSerialState, prog_if, 0x02),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static Property multi_4x_serial_pci_properties[] = {
-    DEFINE_PROP_CHR("chardev1",  PCIMultiSerialState, state[0].chr),
-    DEFINE_PROP_CHR("chardev2",  PCIMultiSerialState, state[1].chr),
-    DEFINE_PROP_CHR("chardev3",  PCIMultiSerialState, state[2].chr),
-    DEFINE_PROP_CHR("chardev4",  PCIMultiSerialState, state[3].chr),
-    DEFINE_PROP_UINT8("prog_if",  PCIMultiSerialState, prog_if, 0x02),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
 static void serial_pci_class_initfn(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
@@ -215,36 +99,6 @@ static void serial_pci_class_initfn(ObjectClass *klass, void *data)
     set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
 }
 
-static void multi_2x_serial_pci_class_initfn(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass);
-    pc->realize = multi_serial_pci_realize;
-    pc->exit = multi_serial_pci_exit;
-    pc->vendor_id = PCI_VENDOR_ID_REDHAT;
-    pc->device_id = PCI_DEVICE_ID_REDHAT_SERIAL2;
-    pc->revision = 1;
-    pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL;
-    dc->vmsd = &vmstate_pci_multi_serial;
-    dc->props = multi_2x_serial_pci_properties;
-    set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
-}
-
-static void multi_4x_serial_pci_class_initfn(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass);
-    pc->realize = multi_serial_pci_realize;
-    pc->exit = multi_serial_pci_exit;
-    pc->vendor_id = PCI_VENDOR_ID_REDHAT;
-    pc->device_id = PCI_DEVICE_ID_REDHAT_SERIAL4;
-    pc->revision = 1;
-    pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL;
-    dc->vmsd = &vmstate_pci_multi_serial;
-    dc->props = multi_4x_serial_pci_properties;
-    set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
-}
-
 static const TypeInfo serial_pci_info = {
     .name          = "pci-serial",
     .parent        = TYPE_PCI_DEVICE,
@@ -256,33 +110,9 @@ static const TypeInfo serial_pci_info = {
     },
 };
 
-static const TypeInfo multi_2x_serial_pci_info = {
-    .name          = "pci-serial-2x",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(PCIMultiSerialState),
-    .class_init    = multi_2x_serial_pci_class_initfn,
-    .interfaces = (InterfaceInfo[]) {
-        { INTERFACE_CONVENTIONAL_PCI_DEVICE },
-        { },
-    },
-};
-
-static const TypeInfo multi_4x_serial_pci_info = {
-    .name          = "pci-serial-4x",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(PCIMultiSerialState),
-    .class_init    = multi_4x_serial_pci_class_initfn,
-    .interfaces = (InterfaceInfo[]) {
-        { INTERFACE_CONVENTIONAL_PCI_DEVICE },
-        { },
-    },
-};
-
 static void serial_pci_register_types(void)
 {
     type_register_static(&serial_pci_info);
-    type_register_static(&multi_2x_serial_pci_info);
-    type_register_static(&multi_4x_serial_pci_info);
 }
 
 type_init(serial_pci_register_types)
diff --git a/hw/core/loader.c b/hw/core/loader.c
index fe5cb24122..a097bbe30a 100644
--- a/hw/core/loader.c
+++ b/hw/core/loader.c
@@ -1025,6 +1025,7 @@ MemoryRegion *rom_add_blob(const char *name, const void *blob, size_t len,
     rom->addr     = addr;
     rom->romsize  = max_len ? max_len : len;
     rom->datasize = len;
+    g_assert(rom->romsize >= rom->datasize);
     rom->data     = g_malloc0(rom->datasize);
     memcpy(rom->data, blob, len);
     rom_insert(rom);
diff --git a/hw/core/machine.c b/hw/core/machine.c
index 5d046a43e3..934c1bcceb 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -102,9 +102,26 @@ const size_t hw_compat_2_7_len = G_N_ELEMENTS(hw_compat_2_7);
 
 GlobalProperty hw_compat_2_6[] = {
     { "virtio-mmio", "format_transport_address", "off" },
-    /* Optional because not all virtio-pci devices support legacy mode */
-    { "virtio-pci", "disable-modern", "on",  .optional = true },
-    { "virtio-pci", "disable-legacy", "off", .optional = true },
+    /*
+     * don't include devices which are modern-only
+     * ie keyboard, mouse, tablet, gpu, vga & crypto
+     */
+    { "virtio-9p-pci", "disable-modern", "on" },
+    { "virtio-9p-pci", "disable-legacy", "off" },
+    { "virtio-balloon-pci", "disable-modern", "on" },
+    { "virtio-balloon-pci", "disable-legacy", "off" },
+    { "virtio-blk-pci", "disable-modern", "on" },
+    { "virtio-blk-pci", "disable-legacy", "off" },
+    { "virtio-input-host-pci", "disable-modern", "on" },
+    { "virtio-input-host-pci", "disable-legacy", "off" },
+    { "virtio-net-pci", "disable-modern", "on" },
+    { "virtio-net-pci", "disable-legacy", "off" },
+    { "virtio-rng-pci", "disable-modern", "on" },
+    { "virtio-rng-pci", "disable-legacy", "off" },
+    { "virtio-scsi-pci", "disable-modern", "on" },
+    { "virtio-scsi-pci", "disable-legacy", "off" },
+    { "virtio-serial-pci", "disable-modern", "on" },
+    { "virtio-serial-pci", "disable-legacy", "off" },
 };
 const size_t hw_compat_2_6_len = G_N_ELEMENTS(hw_compat_2_6);
 
diff --git a/hw/display/virtio-gpu-pci.c b/hw/display/virtio-gpu-pci.c
index bdcd33c925..0bc4d9d424 100644
--- a/hw/display/virtio-gpu-pci.c
+++ b/hw/display/virtio-gpu-pci.c
@@ -47,7 +47,9 @@ static void virtio_gpu_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
     Error *local_error = NULL;
 
     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
-    virtio_pci_force_virtio_1(vpci_dev);
+    if (!virtio_pci_force_virtio_1(vpci_dev, errp)) {
+        return;
+    }
     object_property_set_bool(OBJECT(vdev), true, "realized", &local_error);
 
     if (local_error) {
diff --git a/hw/display/virtio-vga.c b/hw/display/virtio-vga.c
index a2b803b75f..5d57bf5b0c 100644
--- a/hw/display/virtio-vga.c
+++ b/hw/display/virtio-vga.c
@@ -154,7 +154,9 @@ static void virtio_vga_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
 
     /* init virtio bits */
     qdev_set_parent_bus(DEVICE(g), BUS(&vpci_dev->bus));
-    virtio_pci_force_virtio_1(vpci_dev);
+    if (!virtio_pci_force_virtio_1(vpci_dev, errp)) {
+        return;
+    }
     object_property_set_bool(OBJECT(g), true, "realized", &err);
     if (err) {
         error_propagate(errp, err);
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 416da318ae..0d78d73894 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -35,6 +35,7 @@
 #include "hw/acpi/acpi-defs.h"
 #include "hw/acpi/acpi.h"
 #include "hw/acpi/cpu.h"
+#include "hw/acpi/piix4.h"
 #include "hw/nvram/fw_cfg.h"
 #include "hw/acpi/bios-linker-loader.h"
 #include "hw/loader.h"
@@ -58,6 +59,7 @@
 #include "hw/i386/x86-iommu.h"
 
 #include "hw/acpi/aml-build.h"
+#include "hw/acpi/pci.h"
 
 #include "qom/qom-qobject.h"
 #include "hw/i386/amd_iommu.h"
@@ -86,11 +88,6 @@
 /* Default IOAPIC ID */
 #define ACPI_BUILD_IOAPIC_ID 0x0
 
-typedef struct AcpiMcfgInfo {
-    uint64_t mcfg_base;
-    uint32_t mcfg_size;
-} AcpiMcfgInfo;
-
 typedef struct AcpiPmInfo {
     bool s3_disabled;
     bool s4_disabled;
@@ -164,16 +161,28 @@ static void init_common_fadt_data(Object *o, AcpiFadtData *data)
     *data = fadt;
 }
 
+static Object *object_resolve_type_unambiguous(const char *typename)
+{
+    bool ambig;
+    Object *o = object_resolve_path_type("", typename, &ambig);
+
+    if (ambig || !o) {
+        return NULL;
+    }
+    return o;
+}
+
 static void acpi_get_pm_info(AcpiPmInfo *pm)
 {
-    Object *piix = piix4_pm_find();
-    Object *lpc = ich9_lpc_find();
+    Object *piix = object_resolve_type_unambiguous(TYPE_PIIX4_PM);
+    Object *lpc = object_resolve_type_unambiguous(TYPE_ICH9_LPC_DEVICE);
     Object *obj = piix ? piix : lpc;
     QObject *o;
     pm->cpu_hp_io_base = 0;
     pm->pcihp_io_base = 0;
     pm->pcihp_io_len = 0;
 
+    assert(obj);
     init_common_fadt_data(obj, &pm->fadt);
     if (piix) {
         /* w2k requires FADT(rev1) or it won't boot, keep PC compatible */
@@ -192,7 +201,6 @@ static void acpi_get_pm_info(AcpiPmInfo *pm)
         pm->fadt.flags |= 1 << ACPI_FADT_F_RESET_REG_SUP;
         pm->cpu_hp_io_base = ICH9_CPU_HOTPLUG_IO_BASE;
     }
-    assert(obj);
 
     /* The above need not be conditional on machine type because the reset port
      * happens to be the same on PIIX (pc) and ICH9 (q35). */
@@ -228,8 +236,8 @@ static void acpi_get_pm_info(AcpiPmInfo *pm)
 
 static void acpi_get_misc_info(AcpiMiscInfo *info)
 {
-    Object *piix = piix4_pm_find();
-    Object *lpc = ich9_lpc_find();
+    Object *piix = object_resolve_type_unambiguous(TYPE_PIIX4_PM);
+    Object *lpc = object_resolve_type_unambiguous(TYPE_ICH9_LPC_DEVICE);
     assert(!!piix != !!lpc);
 
     if (piix) {
@@ -2401,29 +2409,16 @@ static void
 build_mcfg_q35(GArray *table_data, BIOSLinker *linker, AcpiMcfgInfo *info)
 {
     AcpiTableMcfg *mcfg;
-    const char *sig;
     int len = sizeof(*mcfg) + 1 * sizeof(mcfg->allocation[0]);
 
     mcfg = acpi_data_push(table_data, len);
-    mcfg->allocation[0].address = cpu_to_le64(info->mcfg_base);
+    mcfg->allocation[0].address = cpu_to_le64(info->base);
     /* Only a single allocation so no need to play with segments */
     mcfg->allocation[0].pci_segment = cpu_to_le16(0);
     mcfg->allocation[0].start_bus_number = 0;
-    mcfg->allocation[0].end_bus_number = PCIE_MMCFG_BUS(info->mcfg_size - 1);
+    mcfg->allocation[0].end_bus_number = PCIE_MMCFG_BUS(info->size - 1);
 
-    /* MCFG is used for ECAM which can be enabled or disabled by guest.
-     * To avoid table size changes (which create migration issues),
-     * always create the table even if there are no allocations,
-     * but set the signature to a reserved value in this case.
-     * ACPI spec requires OSPMs to ignore such tables.
-     */
-    if (info->mcfg_base == PCIE_BASE_ADDR_UNMAPPED) {
-        /* Reserved signature: ignored by OSPM */
-        sig = "QEMU";
-    } else {
-        sig = "MCFG";
-    }
-    build_header(linker, table_data, (void *)mcfg, sig, len, 1, NULL, NULL);
+    build_header(linker, table_data, (void *)mcfg, "MCFG", len, 1, NULL, NULL);
 }
 
 /*
@@ -2590,12 +2585,15 @@ static bool acpi_get_mcfg(AcpiMcfgInfo *mcfg)
     if (!o) {
         return false;
     }
-    mcfg->mcfg_base = qnum_get_uint(qobject_to(QNum, o));
+    mcfg->base = qnum_get_uint(qobject_to(QNum, o));
     qobject_unref(o);
+    if (mcfg->base == PCIE_BASE_ADDR_UNMAPPED) {
+        return false;
+    }
 
     o = object_property_get_qobject(pci_host, PCIE_HOST_MCFG_SIZE, NULL);
     assert(o);
-    mcfg->mcfg_size = qnum_get_uint(qobject_to(QNum, o));
+    mcfg->size = qnum_get_uint(qobject_to(QNum, o));
     qobject_unref(o);
     return true;
 }
diff --git a/hw/input/Kconfig b/hw/input/Kconfig
index 889363d8ae..287f08887b 100644
--- a/hw/input/Kconfig
+++ b/hw/input/Kconfig
@@ -8,10 +8,15 @@ config LM832X
 config PCKBD
     bool
     default y
+    select PS2
     depends on ISA_BUS
 
 config PL050
     bool
+    select PS2
+
+config PS2
+    bool
 
 config STELLARIS_INPUT
     bool
diff --git a/hw/input/Makefile.objs b/hw/input/Makefile.objs
index d1de307708..a1bc502ed0 100644
--- a/hw/input/Makefile.objs
+++ b/hw/input/Makefile.objs
@@ -3,7 +3,7 @@ common-obj-y += hid.o
 common-obj-$(CONFIG_LM832X) += lm832x.o
 common-obj-$(CONFIG_PCKBD) += pckbd.o
 common-obj-$(CONFIG_PL050) += pl050.o
-common-obj-y += ps2.o
+common-obj-$(CONFIG_PS2) += ps2.o
 common-obj-$(CONFIG_STELLARIS_INPUT) += stellaris_input.o
 common-obj-$(CONFIG_TSC2005) += tsc2005.o
 
diff --git a/hw/intc/grlib_irqmp.c b/hw/intc/grlib_irqmp.c
index d6f9cb3692..20accb6c4d 100644
--- a/hw/intc/grlib_irqmp.c
+++ b/hw/intc/grlib_irqmp.c
@@ -3,7 +3,7 @@
  *
  * (Multiprocessor and extended interrupt not supported)
  *
- * Copyright (c) 2010-2011 AdaCore
+ * Copyright (c) 2010-2019 AdaCore
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
@@ -47,7 +47,6 @@
 #define FORCE_OFFSET     0x80
 #define EXTENDED_OFFSET  0xC0
 
-#define TYPE_GRLIB_IRQMP "grlib,irqmp"
 #define GRLIB_IRQMP(obj) OBJECT_CHECK(IRQMP, (obj), TYPE_GRLIB_IRQMP)
 
 typedef struct IRQMPState IRQMPState;
diff --git a/hw/intc/ioapic.c b/hw/intc/ioapic.c
index 9d75f84d3b..7074489fdf 100644
--- a/hw/intc/ioapic.c
+++ b/hw/intc/ioapic.c
@@ -139,6 +139,15 @@ static void ioapic_service(IOAPICCommonState *s)
     }
 }
 
+#define SUCCESSIVE_IRQ_MAX_COUNT 10000
+
+static void delayed_ioapic_service_cb(void *opaque)
+{
+    IOAPICCommonState *s = opaque;
+
+    ioapic_service(s);
+}
+
 static void ioapic_set_irq(void *opaque, int vector, int level)
 {
     IOAPICCommonState *s = opaque;
@@ -222,13 +231,39 @@ void ioapic_eoi_broadcast(int vector)
         }
         for (n = 0; n < IOAPIC_NUM_PINS; n++) {
             entry = s->ioredtbl[n];
-            if ((entry & IOAPIC_LVT_REMOTE_IRR)
-                && (entry & IOAPIC_VECTOR_MASK) == vector) {
-                trace_ioapic_clear_remote_irr(n, vector);
-                s->ioredtbl[n] = entry & ~IOAPIC_LVT_REMOTE_IRR;
-                if (!(entry & IOAPIC_LVT_MASKED) && (s->irr & (1 << n))) {
+
+            if ((entry & IOAPIC_VECTOR_MASK) != vector ||
+                ((entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1) != IOAPIC_TRIGGER_LEVEL) {
+                continue;
+            }
+
+            if (!(entry & IOAPIC_LVT_REMOTE_IRR)) {
+                continue;
+            }
+
+            trace_ioapic_clear_remote_irr(n, vector);
+            s->ioredtbl[n] = entry & ~IOAPIC_LVT_REMOTE_IRR;
+
+            if (!(entry & IOAPIC_LVT_MASKED) && (s->irr & (1 << n))) {
+                ++s->irq_eoi[vector];
+                if (s->irq_eoi[vector] >= SUCCESSIVE_IRQ_MAX_COUNT) {
+                    /*
+                     * Real hardware does not deliver the interrupt immediately
+                     * during eoi broadcast, and this lets a buggy guest make
+                     * slow progress even if it does not correctly handle a
+                     * level-triggered interrupt. Emulate this behavior if we
+                     * detect an interrupt storm.
+                     */
+                    s->irq_eoi[vector] = 0;
+                    timer_mod_anticipate(s->delayed_ioapic_service_timer,
+                                         qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
+                                         NANOSECONDS_PER_SECOND / 100);
+                    trace_ioapic_eoi_delayed_reassert(vector);
+                } else {
                     ioapic_service(s);
                 }
+            } else {
+                s->irq_eoi[vector] = 0;
             }
         }
     }
@@ -401,6 +436,9 @@ static void ioapic_realize(DeviceState *dev, Error **errp)
     memory_region_init_io(&s->io_memory, OBJECT(s), &ioapic_io_ops, s,
                           "ioapic", 0x1000);
 
+    s->delayed_ioapic_service_timer =
+        timer_new_ns(QEMU_CLOCK_VIRTUAL, delayed_ioapic_service_cb, s);
+
     qdev_init_gpio_in(dev, ioapic_set_irq, IOAPIC_NUM_PINS);
 
     ioapics[ioapic_no] = s;
@@ -408,6 +446,14 @@ static void ioapic_realize(DeviceState *dev, Error **errp)
     qemu_add_machine_init_done_notifier(&s->machine_done);
 }
 
+static void ioapic_unrealize(DeviceState *dev, Error **errp)
+{
+    IOAPICCommonState *s = IOAPIC_COMMON(dev);
+
+    timer_del(s->delayed_ioapic_service_timer);
+    timer_free(s->delayed_ioapic_service_timer);
+}
+
 static Property ioapic_properties[] = {
     DEFINE_PROP_UINT8("version", IOAPICCommonState, version, IOAPIC_VER_DEF),
     DEFINE_PROP_END_OF_LIST(),
@@ -419,6 +465,7 @@ static void ioapic_class_init(ObjectClass *klass, void *data)
     DeviceClass *dc = DEVICE_CLASS(klass);
 
     k->realize = ioapic_realize;
+    k->unrealize = ioapic_unrealize;
     /*
      * If APIC is in kernel, we need to update the kernel cache after
      * migration, otherwise first 24 gsi routes will be invalid.
diff --git a/hw/intc/trace-events b/hw/intc/trace-events
index a28bdce925..90c9d07c1a 100644
--- a/hw/intc/trace-events
+++ b/hw/intc/trace-events
@@ -25,6 +25,7 @@ apic_mem_writel(uint64_t addr, uint32_t val) "0x%"PRIx64" = 0x%08x"
 ioapic_set_remote_irr(int n) "set remote irr for pin %d"
 ioapic_clear_remote_irr(int n, int vector) "clear remote irr for pin %d vector %d"
 ioapic_eoi_broadcast(int vector) "EOI broadcast for vector %d"
+ioapic_eoi_delayed_reassert(int vector) "delayed reassert on EOI broadcast for vector %d"
 ioapic_mem_read(uint8_t addr, uint8_t regsel, uint8_t size, uint32_t val) "ioapic mem read addr 0x%"PRIx8" regsel: 0x%"PRIx8" size 0x%"PRIx8" retval 0x%"PRIx32
 ioapic_mem_write(uint8_t addr, uint8_t regsel, uint8_t size, uint32_t val) "ioapic mem write addr 0x%"PRIx8" regsel: 0x%"PRIx8" size 0x%"PRIx8" val 0x%"PRIx32
 ioapic_set_irq(int vector, int level) "vector: %d level: %d"
diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c
index ac44aa53be..031ee9cd93 100644
--- a/hw/isa/lpc_ich9.c
+++ b/hw/isa/lpc_ich9.c
@@ -624,17 +624,6 @@ static const MemoryRegionOps ich9_rst_cnt_ops = {
     .endianness = DEVICE_LITTLE_ENDIAN
 };
 
-Object *ich9_lpc_find(void)
-{
-    bool ambig;
-    Object *o = object_resolve_path_type("", TYPE_ICH9_LPC_DEVICE, &ambig);
-
-    if (ambig) {
-        return NULL;
-    }
-    return o;
-}
-
 static void ich9_lpc_get_sci_int(Object *obj, Visitor *v, const char *name,
                                  void *opaque, Error **errp)
 {
diff --git a/hw/mips/mips_fulong2e.c b/hw/mips/mips_fulong2e.c
index 9d7480ed31..05a5a823a1 100644
--- a/hw/mips/mips_fulong2e.c
+++ b/hw/mips/mips_fulong2e.c
@@ -349,10 +349,12 @@ static void mips_fulong2e_init(MachineState *machine)
                                &smbus, &isa_bus);
 
     /* GPU */
-    dev = DEVICE(pci_create(pci_bus, -1, "ati-vga"));
-    qdev_prop_set_uint32(dev, "vgamem_mb", 16);
-    qdev_prop_set_uint16(dev, "x-device-id", 0x5159);
-    qdev_init_nofail(dev);
+    if (vga_interface_type != VGA_NONE) {
+        dev = DEVICE(pci_create(pci_bus, -1, "ati-vga"));
+        qdev_prop_set_uint32(dev, "vgamem_mb", 16);
+        qdev_prop_set_uint16(dev, "x-device-id", 0x5159);
+        qdev_init_nofail(dev);
+    }
 
     /* Populate SPD eeprom data */
     spd_data = spd_data_generate(DDR, ram_size, &err);
diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
index c71e07ae35..77b9df9796 100644
--- a/hw/misc/Makefile.objs
+++ b/hw/misc/Makefile.objs
@@ -77,3 +77,5 @@ obj-$(CONFIG_AUX) += auxbus.o
 obj-$(CONFIG_ASPEED_SOC) += aspeed_scu.o aspeed_sdmc.o
 obj-$(CONFIG_MSF2) += msf2-sysreg.o
 obj-$(CONFIG_NRF51_SOC) += nrf51_rng.o
+
+obj-$(CONFIG_GRLIB) += grlib_ahb_apb_pnp.o
diff --git a/hw/misc/grlib_ahb_apb_pnp.c b/hw/misc/grlib_ahb_apb_pnp.c
new file mode 100644
index 0000000000..7338461694
--- /dev/null
+++ b/hw/misc/grlib_ahb_apb_pnp.c
@@ -0,0 +1,269 @@
+/*
+ * GRLIB AHB APB PNP
+ *
+ *  Copyright (C) 2019 AdaCore
+ *
+ *  Developed by :
+ *  Frederic Konrad   <frederic.konrad@adacore.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "hw/sysbus.h"
+#include "hw/misc/grlib_ahb_apb_pnp.h"
+
+#define GRLIB_PNP_VENDOR_SHIFT (24)
+#define GRLIB_PNP_VENDOR_SIZE   (8)
+#define GRLIB_PNP_DEV_SHIFT    (12)
+#define GRLIB_PNP_DEV_SIZE     (12)
+#define GRLIB_PNP_VER_SHIFT     (5)
+#define GRLIB_PNP_VER_SIZE      (5)
+#define GRLIB_PNP_IRQ_SHIFT     (0)
+#define GRLIB_PNP_IRQ_SIZE      (5)
+#define GRLIB_PNP_ADDR_SHIFT   (20)
+#define GRLIB_PNP_ADDR_SIZE    (12)
+#define GRLIB_PNP_MASK_SHIFT    (4)
+#define GRLIB_PNP_MASK_SIZE    (12)
+
+#define GRLIB_AHB_DEV_ADDR_SHIFT   (20)
+#define GRLIB_AHB_DEV_ADDR_SIZE    (12)
+#define GRLIB_AHB_ENTRY_SIZE       (0x20)
+#define GRLIB_AHB_MAX_DEV          (64)
+#define GRLIB_AHB_SLAVE_OFFSET     (0x800)
+
+#define GRLIB_APB_DEV_ADDR_SHIFT   (8)
+#define GRLIB_APB_DEV_ADDR_SIZE    (12)
+#define GRLIB_APB_ENTRY_SIZE       (0x08)
+#define GRLIB_APB_MAX_DEV          (512)
+
+#define GRLIB_PNP_MAX_REGS         (0x1000)
+
+typedef struct AHBPnp {
+    SysBusDevice parent_obj;
+    MemoryRegion iomem;
+
+    uint32_t regs[GRLIB_PNP_MAX_REGS >> 2];
+    uint8_t master_count;
+    uint8_t slave_count;
+} AHBPnp;
+
+void grlib_ahb_pnp_add_entry(AHBPnp *dev, uint32_t address, uint32_t mask,
+                             uint8_t vendor, uint16_t device, int slave,
+                             int type)
+{
+    unsigned int reg_start;
+
+    /*
+     * AHB entries look like this:
+     *
+     * 31 -------- 23 -------- 11 ----- 9 -------- 4 --- 0
+     *  | VENDOR ID | DEVICE ID | IRQ ? | VERSION  | IRQ |
+     *  --------------------------------------------------
+     *  |                      USER                      |
+     *  --------------------------------------------------
+     *  |                      USER                      |
+     *  --------------------------------------------------
+     *  |                      USER                      |
+     *  --------------------------------------------------
+     *  |                      USER                      |
+     *  --------------------------------------------------
+     * 31 ----------- 20 --- 15 ----------------- 3 ---- 0
+     *  | ADDR[31..12] | 00PC |        MASK       | TYPE |
+     *  --------------------------------------------------
+     * 31 ----------- 20 --- 15 ----------------- 3 ---- 0
+     *  | ADDR[31..12] | 00PC |        MASK       | TYPE |
+     *  --------------------------------------------------
+     * 31 ----------- 20 --- 15 ----------------- 3 ---- 0
+     *  | ADDR[31..12] | 00PC |        MASK       | TYPE |
+     *  --------------------------------------------------
+     * 31 ----------- 20 --- 15 ----------------- 3 ---- 0
+     *  | ADDR[31..12] | 00PC |        MASK       | TYPE |
+     *  --------------------------------------------------
+     */
+
+    if (slave) {
+        assert(dev->slave_count < GRLIB_AHB_MAX_DEV);
+        reg_start = (GRLIB_AHB_SLAVE_OFFSET
+                  + (dev->slave_count * GRLIB_AHB_ENTRY_SIZE)) >> 2;
+        dev->slave_count++;
+    } else {
+        assert(dev->master_count < GRLIB_AHB_MAX_DEV);
+        reg_start = (dev->master_count * GRLIB_AHB_ENTRY_SIZE) >> 2;
+        dev->master_count++;
+    }
+
+    dev->regs[reg_start] = deposit32(dev->regs[reg_start],
+                                     GRLIB_PNP_VENDOR_SHIFT,
+                                     GRLIB_PNP_VENDOR_SIZE,
+                                     vendor);
+    dev->regs[reg_start] = deposit32(dev->regs[reg_start],
+                                     GRLIB_PNP_DEV_SHIFT,
+                                     GRLIB_PNP_DEV_SIZE,
+                                     device);
+    reg_start += 4;
+    /* AHB Memory Space */
+    dev->regs[reg_start] = type;
+    dev->regs[reg_start] = deposit32(dev->regs[reg_start],
+                                     GRLIB_PNP_ADDR_SHIFT,
+                                     GRLIB_PNP_ADDR_SIZE,
+                                     extract32(address,
+                                               GRLIB_AHB_DEV_ADDR_SHIFT,
+                                               GRLIB_AHB_DEV_ADDR_SIZE));
+    dev->regs[reg_start] = deposit32(dev->regs[reg_start],
+                                     GRLIB_PNP_MASK_SHIFT,
+                                     GRLIB_PNP_MASK_SIZE,
+                                     mask);
+}
+
+static uint64_t grlib_ahb_pnp_read(void *opaque, hwaddr offset, unsigned size)
+{
+    AHBPnp *ahb_pnp = GRLIB_AHB_PNP(opaque);
+
+    return ahb_pnp->regs[offset >> 2];
+}
+
+static const MemoryRegionOps grlib_ahb_pnp_ops = {
+    .read       = grlib_ahb_pnp_read,
+    .endianness = DEVICE_BIG_ENDIAN,
+};
+
+static void grlib_ahb_pnp_realize(DeviceState *dev, Error **errp)
+{
+    AHBPnp *ahb_pnp = GRLIB_AHB_PNP(dev);
+    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+
+    memory_region_init_io(&ahb_pnp->iomem, OBJECT(dev), &grlib_ahb_pnp_ops,
+                          ahb_pnp, TYPE_GRLIB_AHB_PNP, GRLIB_PNP_MAX_REGS);
+    sysbus_init_mmio(sbd, &ahb_pnp->iomem);
+}
+
+static void grlib_ahb_pnp_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->realize = grlib_ahb_pnp_realize;
+}
+
+static const TypeInfo grlib_ahb_pnp_info = {
+    .name          = TYPE_GRLIB_AHB_PNP,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(AHBPnp),
+    .class_init    = grlib_ahb_pnp_class_init,
+};
+
+/* APBPnp */
+
+typedef struct APBPnp {
+    SysBusDevice parent_obj;
+    MemoryRegion iomem;
+
+    uint32_t regs[GRLIB_PNP_MAX_REGS >> 2];
+    uint32_t entry_count;
+} APBPnp;
+
+void grlib_apb_pnp_add_entry(APBPnp *dev, uint32_t address, uint32_t mask,
+                             uint8_t vendor, uint16_t device, uint8_t version,
+                             uint8_t irq, int type)
+{
+    unsigned int reg_start;
+
+    /*
+     * APB entries look like this:
+     *
+     * 31 -------- 23 -------- 11 ----- 9 ------- 4 --- 0
+     *  | VENDOR ID | DEVICE ID | IRQ ? | VERSION | IRQ |
+     *
+     * 31 ---------- 20 --- 15 ----------------- 3 ---- 0
+     *  | ADDR[20..8] | 0000 |        MASK       | TYPE |
+     */
+
+    assert(dev->entry_count < GRLIB_APB_MAX_DEV);
+    reg_start = (dev->entry_count * GRLIB_APB_ENTRY_SIZE) >> 2;
+    dev->entry_count++;
+
+    dev->regs[reg_start] = deposit32(dev->regs[reg_start],
+                                     GRLIB_PNP_VENDOR_SHIFT,
+                                     GRLIB_PNP_VENDOR_SIZE,
+                                     vendor);
+    dev->regs[reg_start] = deposit32(dev->regs[reg_start],
+                                     GRLIB_PNP_DEV_SHIFT,
+                                     GRLIB_PNP_DEV_SIZE,
+                                     device);
+    dev->regs[reg_start] = deposit32(dev->regs[reg_start],
+                                     GRLIB_PNP_VER_SHIFT,
+                                     GRLIB_PNP_VER_SIZE,
+                                     version);
+    dev->regs[reg_start] = deposit32(dev->regs[reg_start],
+                                     GRLIB_PNP_IRQ_SHIFT,
+                                     GRLIB_PNP_IRQ_SIZE,
+                                     irq);
+    reg_start += 1;
+    dev->regs[reg_start] = type;
+    dev->regs[reg_start] = deposit32(dev->regs[reg_start],
+                                     GRLIB_PNP_ADDR_SHIFT,
+                                     GRLIB_PNP_ADDR_SIZE,
+                                     extract32(address,
+                                               GRLIB_APB_DEV_ADDR_SHIFT,
+                                               GRLIB_APB_DEV_ADDR_SIZE));
+    dev->regs[reg_start] = deposit32(dev->regs[reg_start],
+                                     GRLIB_PNP_MASK_SHIFT,
+                                     GRLIB_PNP_MASK_SIZE,
+                                     mask);
+}
+
+static uint64_t grlib_apb_pnp_read(void *opaque, hwaddr offset, unsigned size)
+{
+    APBPnp *apb_pnp = GRLIB_APB_PNP(opaque);
+
+    return apb_pnp->regs[offset >> 2];
+}
+
+static const MemoryRegionOps grlib_apb_pnp_ops = {
+    .read       = grlib_apb_pnp_read,
+    .endianness = DEVICE_BIG_ENDIAN,
+};
+
+static void grlib_apb_pnp_realize(DeviceState *dev, Error **errp)
+{
+    APBPnp *apb_pnp = GRLIB_APB_PNP(dev);
+    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+
+    memory_region_init_io(&apb_pnp->iomem, OBJECT(dev), &grlib_apb_pnp_ops,
+                          apb_pnp, TYPE_GRLIB_APB_PNP, GRLIB_PNP_MAX_REGS);
+    sysbus_init_mmio(sbd, &apb_pnp->iomem);
+}
+
+static void grlib_apb_pnp_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->realize = grlib_apb_pnp_realize;
+}
+
+static const TypeInfo grlib_apb_pnp_info = {
+    .name          = TYPE_GRLIB_APB_PNP,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(APBPnp),
+    .class_init    = grlib_apb_pnp_class_init,
+};
+
+static void grlib_ahb_apb_pnp_register_types(void)
+{
+    type_register_static(&grlib_ahb_pnp_info);
+    type_register_static(&grlib_apb_pnp_info);
+}
+
+type_init(grlib_ahb_apb_pnp_register_types)
diff --git a/hw/net/Kconfig b/hw/net/Kconfig
index 7d7bbc5d7c..4ef86dc3a5 100644
--- a/hw/net/Kconfig
+++ b/hw/net/Kconfig
@@ -1,10 +1,14 @@
 config DP8393X
     bool
 
+config NE2000_COMMON
+    bool
+
 config NE2000_PCI
     bool
     default y if PCI_DEVICES
     depends on PCI
+    select NE2000_COMMON
 
 config EEPRO100_PCI
     bool
@@ -51,8 +55,7 @@ config NE2000_ISA
     bool
     default y
     depends on ISA_BUS
-    depends on PCI # for NE2000State
-    select NE2000_PCI
+    select NE2000_COMMON
 
 config OPENCORES_ETH
     bool
diff --git a/hw/net/Makefile.objs b/hw/net/Makefile.objs
index ea63715780..9904273b06 100644
--- a/hw/net/Makefile.objs
+++ b/hw/net/Makefile.objs
@@ -1,8 +1,9 @@
 common-obj-$(CONFIG_DP8393X) += dp8393x.o
 common-obj-$(CONFIG_XEN) += xen_nic.o
+common-obj-$(CONFIG_NE2000_COMMON) += ne2000.o
 
 # PCI network cards
-common-obj-$(CONFIG_NE2000_PCI) += ne2000.o
+common-obj-$(CONFIG_NE2000_PCI) += ne2000-pci.o
 common-obj-$(CONFIG_EEPRO100_PCI) += eepro100.o
 common-obj-$(CONFIG_PCNET_PCI) += pcnet-pci.o
 common-obj-$(CONFIG_PCNET_COMMON) += pcnet.o
diff --git a/hw/net/e1000.c b/hw/net/e1000.c
index 9b39bccfb2..121452d508 100644
--- a/hw/net/e1000.c
+++ b/hw/net/e1000.c
@@ -901,7 +901,6 @@ e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt)
     if (size < sizeof(min_buf)) {
         iov_to_buf(iov, iovcnt, 0, min_buf, size);
         memset(&min_buf[size], 0, sizeof(min_buf) - size);
-        e1000x_inc_reg_if_not_full(s->mac_reg, RUC);
         min_iov.iov_base = filter_buf = min_buf;
         min_iov.iov_len = size = sizeof(min_buf);
         iovcnt = 1;
diff --git a/hw/net/ne2000-pci.c b/hw/net/ne2000-pci.c
new file mode 100644
index 0000000000..cb05744f3c
--- /dev/null
+++ b/hw/net/ne2000-pci.c
@@ -0,0 +1,132 @@
+/*
+ * QEMU NE2000 emulation (PCI bus)
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ *
+ * 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 "qemu/osdep.h"
+#include "hw/pci/pci.h"
+#include "ne2000.h"
+#include "sysemu/sysemu.h"
+
+typedef struct PCINE2000State {
+    PCIDevice dev;
+    NE2000State ne2000;
+} PCINE2000State;
+
+static const VMStateDescription vmstate_pci_ne2000 = {
+    .name = "ne2000",
+    .version_id = 3,
+    .minimum_version_id = 3,
+    .fields = (VMStateField[]) {
+        VMSTATE_PCI_DEVICE(dev, PCINE2000State),
+        VMSTATE_STRUCT(ne2000, PCINE2000State, 0, vmstate_ne2000, NE2000State),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static NetClientInfo net_ne2000_info = {
+    .type = NET_CLIENT_DRIVER_NIC,
+    .size = sizeof(NICState),
+    .receive = ne2000_receive,
+};
+
+static void pci_ne2000_realize(PCIDevice *pci_dev, Error **errp)
+{
+    PCINE2000State *d = DO_UPCAST(PCINE2000State, dev, pci_dev);
+    NE2000State *s;
+    uint8_t *pci_conf;
+
+    pci_conf = d->dev.config;
+    pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin A */
+
+    s = &d->ne2000;
+    ne2000_setup_io(s, DEVICE(pci_dev), 0x100);
+    pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io);
+    s->irq = pci_allocate_irq(&d->dev);
+
+    qemu_macaddr_default_if_unset(&s->c.macaddr);
+    ne2000_reset(s);
+
+    s->nic = qemu_new_nic(&net_ne2000_info, &s->c,
+                          object_get_typename(OBJECT(pci_dev)),
+                          pci_dev->qdev.id, s);
+    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->c.macaddr.a);
+}
+
+static void pci_ne2000_exit(PCIDevice *pci_dev)
+{
+    PCINE2000State *d = DO_UPCAST(PCINE2000State, dev, pci_dev);
+    NE2000State *s = &d->ne2000;
+
+    qemu_del_nic(s->nic);
+    qemu_free_irq(s->irq);
+}
+
+static void ne2000_instance_init(Object *obj)
+{
+    PCIDevice *pci_dev = PCI_DEVICE(obj);
+    PCINE2000State *d = DO_UPCAST(PCINE2000State, dev, pci_dev);
+    NE2000State *s = &d->ne2000;
+
+    device_add_bootindex_property(obj, &s->c.bootindex,
+                                  "bootindex", "/ethernet-phy@0",
+                                  &pci_dev->qdev, NULL);
+}
+
+static Property ne2000_properties[] = {
+    DEFINE_NIC_PROPERTIES(PCINE2000State, ne2000.c),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ne2000_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->realize = pci_ne2000_realize;
+    k->exit = pci_ne2000_exit;
+    k->romfile = "efi-ne2k_pci.rom",
+    k->vendor_id = PCI_VENDOR_ID_REALTEK;
+    k->device_id = PCI_DEVICE_ID_REALTEK_8029;
+    k->class_id = PCI_CLASS_NETWORK_ETHERNET;
+    dc->vmsd = &vmstate_pci_ne2000;
+    dc->props = ne2000_properties;
+    set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
+}
+
+static const TypeInfo ne2000_info = {
+    .name          = "ne2k_pci",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCINE2000State),
+    .class_init    = ne2000_class_init,
+    .instance_init = ne2000_instance_init,
+    .interfaces = (InterfaceInfo[]) {
+        { INTERFACE_CONVENTIONAL_PCI_DEVICE },
+        { },
+    },
+};
+
+static void ne2000_register_types(void)
+{
+    type_register_static(&ne2000_info);
+}
+
+type_init(ne2000_register_types)
diff --git a/hw/net/ne2000.c b/hw/net/ne2000.c
index 037afc8052..ca792d96f1 100644
--- a/hw/net/ne2000.c
+++ b/hw/net/ne2000.c
@@ -22,7 +22,6 @@
  * THE SOFTWARE.
  */
 #include "qemu/osdep.h"
-#include "hw/pci/pci.h"
 #include "net/eth.h"
 #include "ne2000.h"
 #include "sysemu/sysemu.h"
@@ -118,11 +117,6 @@
 #define ENTSR_CDH 0x40	/* The collision detect "heartbeat" signal was lost. */
 #define ENTSR_OWC 0x80  /* There was an out-of-window collision. */
 
-typedef struct PCINE2000State {
-    PCIDevice dev;
-    NE2000State ne2000;
-} PCINE2000State;
-
 void ne2000_reset(NE2000State *s)
 {
     int i;
@@ -644,17 +638,6 @@ const VMStateDescription vmstate_ne2000 = {
     }
 };
 
-static const VMStateDescription vmstate_pci_ne2000 = {
-    .name = "ne2000",
-    .version_id = 3,
-    .minimum_version_id = 3,
-    .fields = (VMStateField[]) {
-        VMSTATE_PCI_DEVICE(dev, PCINE2000State),
-        VMSTATE_STRUCT(ne2000, PCINE2000State, 0, vmstate_ne2000, NE2000State),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
 static uint64_t ne2000_read(void *opaque, hwaddr addr,
                             unsigned size)
 {
@@ -711,91 +694,3 @@ void ne2000_setup_io(NE2000State *s, DeviceState *dev, unsigned size)
 {
     memory_region_init_io(&s->io, OBJECT(dev), &ne2000_ops, s, "ne2000", size);
 }
-
-static NetClientInfo net_ne2000_info = {
-    .type = NET_CLIENT_DRIVER_NIC,
-    .size = sizeof(NICState),
-    .receive = ne2000_receive,
-};
-
-static void pci_ne2000_realize(PCIDevice *pci_dev, Error **errp)
-{
-    PCINE2000State *d = DO_UPCAST(PCINE2000State, dev, pci_dev);
-    NE2000State *s;
-    uint8_t *pci_conf;
-
-    pci_conf = d->dev.config;
-    pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin A */
-
-    s = &d->ne2000;
-    ne2000_setup_io(s, DEVICE(pci_dev), 0x100);
-    pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io);
-    s->irq = pci_allocate_irq(&d->dev);
-
-    qemu_macaddr_default_if_unset(&s->c.macaddr);
-    ne2000_reset(s);
-
-    s->nic = qemu_new_nic(&net_ne2000_info, &s->c,
-                          object_get_typename(OBJECT(pci_dev)), pci_dev->qdev.id, s);
-    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->c.macaddr.a);
-}
-
-static void pci_ne2000_exit(PCIDevice *pci_dev)
-{
-    PCINE2000State *d = DO_UPCAST(PCINE2000State, dev, pci_dev);
-    NE2000State *s = &d->ne2000;
-
-    qemu_del_nic(s->nic);
-    qemu_free_irq(s->irq);
-}
-
-static void ne2000_instance_init(Object *obj)
-{
-    PCIDevice *pci_dev = PCI_DEVICE(obj);
-    PCINE2000State *d = DO_UPCAST(PCINE2000State, dev, pci_dev);
-    NE2000State *s = &d->ne2000;
-
-    device_add_bootindex_property(obj, &s->c.bootindex,
-                                  "bootindex", "/ethernet-phy@0",
-                                  &pci_dev->qdev, NULL);
-}
-
-static Property ne2000_properties[] = {
-    DEFINE_NIC_PROPERTIES(PCINE2000State, ne2000.c),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void ne2000_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->realize = pci_ne2000_realize;
-    k->exit = pci_ne2000_exit;
-    k->romfile = "efi-ne2k_pci.rom",
-    k->vendor_id = PCI_VENDOR_ID_REALTEK;
-    k->device_id = PCI_DEVICE_ID_REALTEK_8029;
-    k->class_id = PCI_CLASS_NETWORK_ETHERNET;
-    dc->vmsd = &vmstate_pci_ne2000;
-    dc->props = ne2000_properties;
-    set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
-}
-
-static const TypeInfo ne2000_info = {
-    .name          = "ne2k_pci",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(PCINE2000State),
-    .class_init    = ne2000_class_init,
-    .instance_init = ne2000_instance_init,
-    .interfaces = (InterfaceInfo[]) {
-        { INTERFACE_CONVENTIONAL_PCI_DEVICE },
-        { },
-    },
-};
-
-static void ne2000_register_types(void)
-{
-    type_register_static(&ne2000_info);
-}
-
-type_init(ne2000_register_types)
diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
index be3cc88370..a6b719035c 100644
--- a/hw/net/vhost_net.c
+++ b/hw/net/vhost_net.c
@@ -244,6 +244,11 @@ static int vhost_net_start_one(struct vhost_net *net,
         qemu_set_fd_handler(net->backend, NULL, NULL, NULL);
         file.fd = net->backend;
         for (file.index = 0; file.index < net->dev.nvqs; ++file.index) {
+            if (!virtio_queue_enabled(dev, net->dev.vq_index +
+                                      file.index)) {
+                /* Queue might not be ready for start */
+                continue;
+            }
             r = vhost_net_set_backend(&net->dev, &file);
             if (r < 0) {
                 r = -errno;
@@ -256,6 +261,11 @@ fail:
     file.fd = -1;
     if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) {
         while (file.index-- > 0) {
+            if (!virtio_queue_enabled(dev, net->dev.vq_index +
+                                      file.index)) {
+                /* Queue might not be ready for start */
+                continue;
+            }
             int r = vhost_net_set_backend(&net->dev, &file);
             assert(r >= 0);
         }
diff --git a/hw/pci-bridge/pci_expander_bridge.c b/hw/pci-bridge/pci_expander_bridge.c
index e62de4218f..ca66bc721a 100644
--- a/hw/pci-bridge/pci_expander_bridge.c
+++ b/hw/pci-bridge/pci_expander_bridge.c
@@ -66,11 +66,6 @@ static int pxb_bus_num(PCIBus *bus)
     return pxb->bus_nr;
 }
 
-static bool pxb_is_root(PCIBus *bus)
-{
-    return true; /* by definition */
-}
-
 static uint16_t pxb_bus_numa_node(PCIBus *bus)
 {
     PXBDev *pxb = convert_to_pxb(bus->parent_dev);
@@ -83,7 +78,6 @@ static void pxb_bus_class_init(ObjectClass *class, void *data)
     PCIBusClass *pbc = PCI_BUS_CLASS(class);
 
     pbc->bus_num = pxb_bus_num;
-    pbc->is_root = pxb_is_root;
     pbc->numa_node = pxb_bus_numa_node;
 }
 
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index a78023f669..b386777045 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -129,14 +129,9 @@ static void pci_bus_unrealize(BusState *qbus, Error **errp)
     vmstate_unregister(NULL, &vmstate_pcibus, bus);
 }
 
-static bool pcibus_is_root(PCIBus *bus)
-{
-    return !bus->parent_dev;
-}
-
 static int pcibus_num(PCIBus *bus)
 {
-    if (pcibus_is_root(bus)) {
+    if (pci_bus_is_root(bus)) {
         return 0; /* pci host bridge */
     }
     return bus->parent_dev->config[PCI_SECONDARY_BUS];
@@ -164,7 +159,6 @@ static void pci_bus_class_init(ObjectClass *klass, void *data)
     k->unrealize = pci_bus_unrealize;
     k->reset = pcibus_reset;
 
-    pbc->is_root = pcibus_is_root;
     pbc->bus_num = pcibus_num;
     pbc->numa_node = pcibus_numa_node;
     pbc->allows_extended_config_space = pcibus_allows_extended_config_space;
@@ -398,6 +392,7 @@ static void pci_root_bus_init(PCIBus *bus, DeviceState *parent,
     bus->slot_reserved_mask = 0x0;
     bus->address_space_mem = address_space_mem;
     bus->address_space_io = address_space_io;
+    bus->flags |= PCI_BUS_IS_ROOT;
 
     /* host bridge */
     QLIST_INIT(&bus->child);
@@ -415,11 +410,6 @@ bool pci_bus_is_express(PCIBus *bus)
     return object_dynamic_cast(OBJECT(bus), TYPE_PCIE_BUS);
 }
 
-bool pci_bus_is_root(PCIBus *bus)
-{
-    return PCI_BUS_GET_CLASS(bus)->is_root(bus);
-}
-
 bool pci_bus_allows_extended_config_space(PCIBus *bus)
 {
     return PCI_BUS_GET_CLASS(bus)->allows_extended_config_space(bus);
diff --git a/hw/pci/pcie_host.c b/hw/pci/pcie_host.c
index 553db56778..1ee4945a6d 100644
--- a/hw/pci/pcie_host.c
+++ b/hw/pci/pcie_host.c
@@ -47,11 +47,6 @@ static void pcie_mmcfg_data_write(void *opaque, hwaddr mmcfg_addr,
     }
     addr = PCIE_MMCFG_CONFOFFSET(mmcfg_addr);
     limit = pci_config_size(pci_dev);
-    if (limit <= addr) {
-        /* conventional pci device can be behind pcie-to-pci bridge.
-           256 <= addr < 4K has no effects. */
-        return;
-    }
     pci_host_config_write_common(pci_dev, addr, limit, val, len);
 }
 
@@ -70,11 +65,6 @@ static uint64_t pcie_mmcfg_data_read(void *opaque,
     }
     addr = PCIE_MMCFG_CONFOFFSET(mmcfg_addr);
     limit = pci_config_size(pci_dev);
-    if (limit <= addr) {
-        /* conventional pci device can be behind pcie-to-pci bridge.
-           256 <= addr < 4K has no effects. */
-        return ~0x0;
-    }
     return pci_host_config_read_common(pci_dev, addr, limit, len);
 }
 
diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c
index a56317e026..5ad762de23 100644
--- a/hw/scsi/megasas.c
+++ b/hw/scsi/megasas.c
@@ -477,7 +477,7 @@ static MegasasCmd *megasas_enqueue_frame(MegasasState *s,
 {
     PCIDevice *pcid = PCI_DEVICE(s);
     MegasasCmd *cmd = NULL;
-    int frame_size = MFI_FRAME_SIZE * 16;
+    int frame_size = MEGASAS_MAX_SGE * sizeof(union mfi_sgl);
     hwaddr frame_size_p = frame_size;
     unsigned long index;
 
diff --git a/hw/sparc/leon3.c b/hw/sparc/leon3.c
index 0383b17c29..bdead85a93 100644
--- a/hw/sparc/leon3.c
+++ b/hw/sparc/leon3.c
@@ -1,7 +1,7 @@
 /*
  * QEMU Leon3 System Emulator
  *
- * Copyright (c) 2010-2011 AdaCore
+ * Copyright (c) 2010-2019 AdaCore
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
@@ -39,20 +39,88 @@
 #include "exec/address-spaces.h"
 
 #include "hw/sparc/grlib.h"
+#include "hw/misc/grlib_ahb_apb_pnp.h"
 
 /* Default system clock.  */
 #define CPU_CLK (40 * 1000 * 1000)
 
-#define PROM_FILENAME        "u-boot.bin"
+#define LEON3_PROM_FILENAME "u-boot.bin"
+#define LEON3_PROM_OFFSET    (0x00000000)
+#define LEON3_RAM_OFFSET     (0x40000000)
 
 #define MAX_PILS 16
 
+#define LEON3_UART_OFFSET  (0x80000100)
+#define LEON3_UART_IRQ     (3)
+
+#define LEON3_IRQMP_OFFSET (0x80000200)
+
+#define LEON3_TIMER_OFFSET (0x80000300)
+#define LEON3_TIMER_IRQ    (6)
+#define LEON3_TIMER_COUNT  (2)
+
+#define LEON3_APB_PNP_OFFSET (0x800FF000)
+#define LEON3_AHB_PNP_OFFSET (0xFFFFF000)
+
 typedef struct ResetData {
     SPARCCPU *cpu;
     uint32_t  entry;            /* save kernel entry in case of reset */
     target_ulong sp;            /* initial stack pointer */
 } ResetData;
 
+static uint32_t *gen_store_u32(uint32_t *code, hwaddr addr, uint32_t val)
+{
+    stl_p(code++, 0x82100000); /* mov %g0, %g1                */
+    stl_p(code++, 0x84100000); /* mov %g0, %g2                */
+    stl_p(code++, 0x03000000 +
+      extract32(addr, 10, 22));
+                               /* sethi %hi(addr), %g1        */
+    stl_p(code++, 0x82106000 +
+      extract32(addr, 0, 10));
+                               /* or %g1, addr, %g1           */
+    stl_p(code++, 0x05000000 +
+      extract32(val, 10, 22));
+                               /* sethi %hi(val), %g2         */
+    stl_p(code++, 0x8410a000 +
+      extract32(val, 0, 10));
+                               /* or %g2, val, %g2            */
+    stl_p(code++, 0xc4204000); /* st %g2, [ %g1 ]             */
+
+    return code;
+}
+
+/*
+ * When loading a kernel in RAM the machine is expected to be in a different
+ * state (eg: initialized by the bootloader). This little code reproduces
+ * this behavior.
+ */
+static void write_bootloader(CPUSPARCState *env, uint8_t *base,
+                             hwaddr kernel_addr)
+{
+    uint32_t *p = (uint32_t *) base;
+
+    /* Initialize the UARTs                                        */
+    /* *UART_CONTROL = UART_RECEIVE_ENABLE | UART_TRANSMIT_ENABLE; */
+    p = gen_store_u32(p, 0x80000108, 3);
+
+    /* Initialize the TIMER 0                                      */
+    /* *GPTIMER_SCALER_RELOAD = 40 - 1;                            */
+    p = gen_store_u32(p, 0x80000304, 39);
+    /* *GPTIMER0_COUNTER_RELOAD = 0xFFFE;                          */
+    p = gen_store_u32(p, 0x80000314, 0xFFFFFFFE);
+    /* *GPTIMER0_CONFIG = GPTIMER_ENABLE | GPTIMER_RESTART;        */
+    p = gen_store_u32(p, 0x80000318, 3);
+
+    /* JUMP to the entry point                                     */
+    stl_p(p++, 0x82100000); /* mov %g0, %g1 */
+    stl_p(p++, 0x03000000 + extract32(kernel_addr, 10, 22));
+                            /* sethi %hi(kernel_addr), %g1 */
+    stl_p(p++, 0x82106000 + extract32(kernel_addr, 0, 10));
+                            /* or kernel_addr, %g1 */
+    stl_p(p++, 0x81c04000); /* jmp  %g1 */
+    stl_p(p++, 0x01000000); /* nop */
+}
+
 static void main_cpu_reset(void *opaque)
 {
     ResetData *s   = (ResetData *)opaque;
@@ -121,6 +189,10 @@ static void leon3_generic_hw_init(MachineState *machine)
     int         bios_size;
     int         prom_size;
     ResetData  *reset_info;
+    DeviceState *dev;
+    int i;
+    AHBPnp *ahb_pnp;
+    APBPnp *apb_pnp;
 
     /* Init CPU */
     cpu = SPARC_CPU(cpu_create(machine->cpu_type));
@@ -131,13 +203,35 @@ static void leon3_generic_hw_init(MachineState *machine)
     /* Reset data */
     reset_info        = g_malloc0(sizeof(ResetData));
     reset_info->cpu   = cpu;
-    reset_info->sp    = 0x40000000 + ram_size;
+    reset_info->sp    = LEON3_RAM_OFFSET + ram_size;
     qemu_register_reset(main_cpu_reset, reset_info);
 
-    /* Allocate IRQ manager */
-    grlib_irqmp_create(0x80000200, env, &cpu_irqs, MAX_PILS, &leon3_set_pil_in);
+    ahb_pnp = GRLIB_AHB_PNP(object_new(TYPE_GRLIB_AHB_PNP));
+    object_property_set_bool(OBJECT(ahb_pnp), true, "realized", &error_fatal);
+    sysbus_mmio_map(SYS_BUS_DEVICE(ahb_pnp), 0, LEON3_AHB_PNP_OFFSET);
+    grlib_ahb_pnp_add_entry(ahb_pnp, 0, 0, GRLIB_VENDOR_GAISLER,
+                            GRLIB_LEON3_DEV, GRLIB_AHB_MASTER,
+                            GRLIB_CPU_AREA);
 
+    apb_pnp = GRLIB_APB_PNP(object_new(TYPE_GRLIB_APB_PNP));
+    object_property_set_bool(OBJECT(apb_pnp), true, "realized", &error_fatal);
+    sysbus_mmio_map(SYS_BUS_DEVICE(apb_pnp), 0, LEON3_APB_PNP_OFFSET);
+    grlib_ahb_pnp_add_entry(ahb_pnp, LEON3_APB_PNP_OFFSET, 0xFFF,
+                            GRLIB_VENDOR_GAISLER, GRLIB_APBMST_DEV,
+                            GRLIB_AHB_SLAVE, GRLIB_AHBMEM_AREA);
+
+    /* Allocate IRQ manager */
+    dev = qdev_create(NULL, TYPE_GRLIB_IRQMP);
+    qdev_prop_set_ptr(dev, "set_pil_in", leon3_set_pil_in);
+    qdev_prop_set_ptr(dev, "set_pil_in_opaque", env);
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, LEON3_IRQMP_OFFSET);
+    env->irq_manager = dev;
     env->qemu_irq_ack = leon3_irq_manager;
+    cpu_irqs = qemu_allocate_irqs(grlib_irqmp_set_irq, dev, MAX_PILS);
+    grlib_apb_pnp_add_entry(apb_pnp, LEON3_IRQMP_OFFSET, 0xFFF,
+                            GRLIB_VENDOR_GAISLER, GRLIB_IRQMP_DEV,
+                            2, 0, GRLIB_APBIO_AREA);
 
     /* Allocate RAM */
     if (ram_size > 1 * GiB) {
@@ -148,17 +242,17 @@ static void leon3_generic_hw_init(MachineState *machine)
     }
 
     memory_region_allocate_system_memory(ram, NULL, "leon3.ram", ram_size);
-    memory_region_add_subregion(address_space_mem, 0x40000000, ram);
+    memory_region_add_subregion(address_space_mem, LEON3_RAM_OFFSET, ram);
 
     /* Allocate BIOS */
     prom_size = 8 * MiB;
     memory_region_init_ram(prom, NULL, "Leon3.bios", prom_size, &error_fatal);
     memory_region_set_readonly(prom, true);
-    memory_region_add_subregion(address_space_mem, 0x00000000, prom);
+    memory_region_add_subregion(address_space_mem, LEON3_PROM_OFFSET, prom);
 
     /* Load boot prom */
     if (bios_name == NULL) {
-        bios_name = PROM_FILENAME;
+        bios_name = LEON3_PROM_FILENAME;
     }
     filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
 
@@ -174,13 +268,15 @@ static void leon3_generic_hw_init(MachineState *machine)
     }
 
     if (bios_size > 0) {
-        ret = load_image_targphys(filename, 0x00000000, bios_size);
+        ret = load_image_targphys(filename, LEON3_PROM_OFFSET, bios_size);
         if (ret < 0 || ret > prom_size) {
             error_report("could not load prom '%s'", filename);
             exit(1);
         }
     } else if (kernel_filename == NULL && !qtest_enabled()) {
-        error_report("Can't read bios image %s", filename);
+        error_report("Can't read bios image '%s'", filename
+                                                   ? filename
+                                                   : LEON3_PROM_FILENAME);
         exit(1);
     }
     g_free(filename);
@@ -202,19 +298,48 @@ static void leon3_generic_hw_init(MachineState *machine)
             exit(1);
         }
         if (bios_size <= 0) {
-            /* If there is no bios/monitor, start the application.  */
-            env->pc = entry;
-            env->npc = entry + 4;
-            reset_info->entry = entry;
+            /*
+             * If there is no bios/monitor just start the application but put
+             * the machine in an initialized state through a little
+             * bootloader.
+             */
+            uint8_t *bootloader_entry;
+
+            bootloader_entry = memory_region_get_ram_ptr(prom);
+            write_bootloader(env, bootloader_entry, entry);
+            env->pc = LEON3_PROM_OFFSET;
+            env->npc = LEON3_PROM_OFFSET + 4;
+            reset_info->entry = LEON3_PROM_OFFSET;
         }
     }
 
     /* Allocate timers */
-    grlib_gptimer_create(0x80000300, 2, CPU_CLK, cpu_irqs, 6);
+    dev = qdev_create(NULL, TYPE_GRLIB_GPTIMER);
+    qdev_prop_set_uint32(dev, "nr-timers", LEON3_TIMER_COUNT);
+    qdev_prop_set_uint32(dev, "frequency", CPU_CLK);
+    qdev_prop_set_uint32(dev, "irq-line", LEON3_TIMER_IRQ);
+    qdev_init_nofail(dev);
+
+    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, LEON3_TIMER_OFFSET);
+    for (i = 0; i < LEON3_TIMER_COUNT; i++) {
+        sysbus_connect_irq(SYS_BUS_DEVICE(dev), i,
+                           cpu_irqs[LEON3_TIMER_IRQ + i]);
+    }
+
+    grlib_apb_pnp_add_entry(apb_pnp, LEON3_TIMER_OFFSET, 0xFFF,
+                            GRLIB_VENDOR_GAISLER, GRLIB_GPTIMER_DEV,
+                            0, LEON3_TIMER_IRQ, GRLIB_APBIO_AREA);
 
     /* Allocate uart */
     if (serial_hd(0)) {
-        grlib_apbuart_create(0x80000100, serial_hd(0), cpu_irqs[3]);
+        dev = qdev_create(NULL, TYPE_GRLIB_APB_UART);
+        qdev_prop_set_chr(dev, "chrdev", serial_hd(0));
+        qdev_init_nofail(dev);
+        sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, LEON3_UART_OFFSET);
+        sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, cpu_irqs[LEON3_UART_IRQ]);
+        grlib_apb_pnp_add_entry(apb_pnp, LEON3_UART_OFFSET, 0xFFF,
+                                GRLIB_VENDOR_GAISLER, GRLIB_APBUART_DEV, 1,
+                                LEON3_UART_IRQ, GRLIB_APBIO_AREA);
     }
 }
 
diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c
index ca1e3825d5..07d126aea8 100644
--- a/hw/sparc/sun4m.c
+++ b/hw/sparc/sun4m.c
@@ -850,7 +850,6 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef,
     uint32_t initrd_size;
     DriveInfo *fd[MAX_FD];
     FWCfgState *fw_cfg;
-    unsigned int num_vsimms;
     DeviceState *dev;
     SysBusDevice *s;
 
@@ -909,8 +908,7 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef,
         error_report("Unsupported depth: %d", graphic_depth);
         exit (1);
     }
-    num_vsimms = 0;
-    if (num_vsimms == 0) {
+    if (vga_interface_type != VGA_NONE) {
         if (vga_interface_type == VGA_CG3) {
             if (graphic_depth != 8) {
                 error_report("Unsupported depth: %d", graphic_depth);
@@ -945,7 +943,7 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef,
         }
     }
 
-    for (i = num_vsimms; i < MAX_VSIMMS; i++) {
+    for (i = 0; i < MAX_VSIMMS; i++) {
         /* vsimm registers probed by OBP */
         if (hwdef->vsimm[i].reg_base) {
             empty_slot_init(hwdef->vsimm[i].reg_base, 0x2000);
diff --git a/hw/timer/grlib_gptimer.c b/hw/timer/grlib_gptimer.c
index 183eddc073..4b7088fc84 100644
--- a/hw/timer/grlib_gptimer.c
+++ b/hw/timer/grlib_gptimer.c
@@ -1,7 +1,7 @@
 /*
  * QEMU GRLIB GPTimer Emulator
  *
- * Copyright (c) 2010-2011 AdaCore
+ * Copyright (c) 2010-2019 AdaCore
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
@@ -23,6 +23,7 @@
  */
 
 #include "qemu/osdep.h"
+#include "hw/sparc/grlib.h"
 #include "hw/sysbus.h"
 #include "qemu/timer.h"
 #include "hw/ptimer.h"
@@ -52,7 +53,6 @@
 #define COUNTER_RELOAD_OFFSET 0x04
 #define TIMER_BASE            0x10
 
-#define TYPE_GRLIB_GPTIMER "grlib,gptimer"
 #define GRLIB_GPTIMER(obj) \
     OBJECT_CHECK(GPTimerUnit, (obj), TYPE_GRLIB_GPTIMER)
 
diff --git a/hw/virtio/virtio-crypto-pci.c b/hw/virtio/virtio-crypto-pci.c
index 90a6e0dc2e..13807e538b 100644
--- a/hw/virtio/virtio-crypto-pci.c
+++ b/hw/virtio/virtio-crypto-pci.c
@@ -51,7 +51,9 @@ static void virtio_crypto_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
     }
 
     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
-    virtio_pci_force_virtio_1(vpci_dev);
+    if (!virtio_pci_force_virtio_1(vpci_dev, errp)) {
+        return;
+    }
     object_property_set_bool(OBJECT(vdev), true, "realized", errp);
     object_property_set_link(OBJECT(vcrypto),
                  OBJECT(vcrypto->vdev.conf.cryptodev), "cryptodev",
diff --git a/hw/virtio/virtio-input-pci.c b/hw/virtio/virtio-input-pci.c
index 2c1397842b..28477729a3 100644
--- a/hw/virtio/virtio-input-pci.c
+++ b/hw/virtio/virtio-input-pci.c
@@ -48,7 +48,9 @@ static void virtio_input_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
     DeviceState *vdev = DEVICE(&vinput->vdev);
 
     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
-    virtio_pci_force_virtio_1(vpci_dev);
+    if (!virtio_pci_force_virtio_1(vpci_dev, errp)) {
+        return;
+    }
     object_property_set_bool(OBJECT(vdev), true, "realized", errp);
 }
 
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index cb44e19b67..9056cdfa3c 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -20,6 +20,7 @@
 #include "standard-headers/linux/virtio_pci.h"
 #include "hw/virtio/virtio.h"
 #include "hw/pci/pci.h"
+#include "hw/pci/pci_bus.h"
 #include "qapi/error.h"
 #include "qemu/error-report.h"
 #include "hw/pci/msi.h"
@@ -1721,16 +1722,22 @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp)
                        /* PCI BAR regions must be powers of 2 */
                        pow2ceil(proxy->notify.offset + proxy->notify.size));
 
-    if (proxy->disable_legacy == ON_OFF_AUTO_AUTO) {
-        proxy->disable_legacy = pcie_port ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF;
-    }
-
-    if (!virtio_pci_modern(proxy) && !virtio_pci_legacy(proxy)) {
-        error_setg(errp, "device cannot work as neither modern nor legacy mode"
-                   " is enabled");
-        error_append_hint(errp, "Set either disable-modern or disable-legacy"
-                          " to off\n");
-        return;
+    if ((proxy->disable_legacy == ON_OFF_AUTO_ON) ||
+        ((proxy->disable_legacy == ON_OFF_AUTO_AUTO) && pcie_port)) {
+        if (proxy->disable_modern) {
+            error_setg(errp, "device cannot work as neither modern nor "
+                       "legacy mode is enabled");
+            error_append_hint(errp, "Set either disable-modern or "
+                              "disable-legacy to off\n");
+            return;
+        }
+        proxy->mode = VIRTIO_PCI_MODE_MODERN;
+    } else {
+        if (proxy->disable_modern) {
+            proxy->mode = VIRTIO_PCI_MODE_LEGACY;
+        } else {
+            proxy->mode = VIRTIO_PCI_MODE_TRANSITIONAL;
+        }
     }
 
     if (pcie_port && pci_is_express(pci_dev)) {
diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h
index 18581854ca..bfea2892a5 100644
--- a/hw/virtio/virtio-pci.h
+++ b/hw/virtio/virtio-pci.h
@@ -15,6 +15,7 @@
 #ifndef QEMU_VIRTIO_PCI_H
 #define QEMU_VIRTIO_PCI_H
 
+#include "qapi/error.h"
 #include "hw/pci/msi.h"
 #include "hw/virtio/virtio-bus.h"
 
@@ -118,6 +119,12 @@ typedef struct VirtIOPCIQueue {
   uint32_t used[2];
 } VirtIOPCIQueue;
 
+typedef enum {
+    VIRTIO_PCI_MODE_LEGACY,
+    VIRTIO_PCI_MODE_TRANSITIONAL,
+    VIRTIO_PCI_MODE_MODERN,
+} VirtIOPCIMode;
+
 struct VirtIOPCIProxy {
     PCIDevice pci_dev;
     MemoryRegion bar;
@@ -142,6 +149,7 @@ struct VirtIOPCIProxy {
     bool disable_modern;
     bool ignore_backend_features;
     OnOffAuto disable_legacy;
+    VirtIOPCIMode mode;
     uint32_t class_code;
     uint32_t nvectors;
     uint32_t dfselect;
@@ -156,23 +164,34 @@ struct VirtIOPCIProxy {
 
 static inline bool virtio_pci_modern(VirtIOPCIProxy *proxy)
 {
-    return !proxy->disable_modern;
+    return proxy->mode != VIRTIO_PCI_MODE_LEGACY;
 }
 
 static inline bool virtio_pci_legacy(VirtIOPCIProxy *proxy)
 {
-    return proxy->disable_legacy == ON_OFF_AUTO_OFF;
+    return proxy->mode != VIRTIO_PCI_MODE_MODERN;
 }
 
-static inline void virtio_pci_force_virtio_1(VirtIOPCIProxy *proxy)
+static inline bool virtio_pci_force_virtio_1(VirtIOPCIProxy *proxy,
+                                             Error **errp)
 {
-    proxy->disable_modern = false;
-    proxy->disable_legacy = ON_OFF_AUTO_ON;
+    if (proxy->disable_legacy == ON_OFF_AUTO_OFF) {
+        error_setg(errp, "Unable to set disable-legacy=off on a virtio-1.0 "
+                   "only device");
+        return false;
+    }
+    if (proxy->disable_modern == true) {
+        error_setg(errp, "Unable to set disable-modern=on on a virtio-1.0 "
+                   "only device");
+        return false;
+    }
+    proxy->mode = VIRTIO_PCI_MODE_MODERN;
+    return true;
 }
 
 static inline void virtio_pci_disable_modern(VirtIOPCIProxy *proxy)
 {
-    proxy->disable_modern = true;
+    proxy->mode = VIRTIO_PCI_MODE_LEGACY;
 }
 
 /*
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 2626a895cb..4805727b53 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -1162,10 +1162,16 @@ int virtio_set_status(VirtIODevice *vdev, uint8_t val)
             }
         }
     }
+    vdev->started = val & VIRTIO_CONFIG_S_DRIVER_OK;
+    if (unlikely(vdev->start_on_kick && vdev->started)) {
+        vdev->start_on_kick = false;
+    }
+
     if (k->set_status) {
         k->set_status(vdev, val);
     }
     vdev->status = val;
+
     return 0;
 }
 
@@ -1208,6 +1214,9 @@ void virtio_reset(void *opaque)
         k->reset(vdev);
     }
 
+    vdev->start_on_kick = (virtio_host_has_feature(vdev, VIRTIO_F_VERSION_1) &&
+                          !virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1));
+    vdev->started = false;
     vdev->broken = false;
     vdev->guest_features = 0;
     vdev->queue_sel = 0;
@@ -1518,14 +1527,21 @@ void virtio_queue_set_align(VirtIODevice *vdev, int n, int align)
 
 static bool virtio_queue_notify_aio_vq(VirtQueue *vq)
 {
+    bool ret = false;
+
     if (vq->vring.desc && vq->handle_aio_output) {
         VirtIODevice *vdev = vq->vdev;
 
         trace_virtio_queue_notify(vdev, vq - vdev->vq, vq);
-        return vq->handle_aio_output(vdev, vq);
+        ret = vq->handle_aio_output(vdev, vq);
+
+        if (unlikely(vdev->start_on_kick)) {
+            vdev->started = true;
+            vdev->start_on_kick = false;
+        }
     }
 
-    return false;
+    return ret;
 }
 
 static void virtio_queue_notify_vq(VirtQueue *vq)
@@ -1539,6 +1555,11 @@ static void virtio_queue_notify_vq(VirtQueue *vq)
 
         trace_virtio_queue_notify(vdev, vq - vdev->vq, vq);
         vq->handle_output(vdev, vq);
+
+        if (unlikely(vdev->start_on_kick)) {
+            vdev->started = true;
+            vdev->start_on_kick = false;
+        }
     }
 }
 
@@ -1556,6 +1577,11 @@ void virtio_queue_notify(VirtIODevice *vdev, int n)
     } else if (vq->handle_output) {
         vq->handle_output(vdev, vq);
     }
+
+    if (unlikely(vdev->start_on_kick)) {
+        vdev->started = true;
+        vdev->start_on_kick = false;
+    }
 }
 
 uint16_t virtio_queue_vector(VirtIODevice *vdev, int n)
@@ -1770,6 +1796,13 @@ static bool virtio_broken_needed(void *opaque)
     return vdev->broken;
 }
 
+static bool virtio_started_needed(void *opaque)
+{
+    VirtIODevice *vdev = opaque;
+
+    return vdev->started;
+}
+
 static const VMStateDescription vmstate_virtqueue = {
     .name = "virtqueue_state",
     .version_id = 1,
@@ -1898,6 +1931,17 @@ static const VMStateDescription vmstate_virtio_broken = {
     }
 };
 
+static const VMStateDescription vmstate_virtio_started = {
+    .name = "virtio/started",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .needed = &virtio_started_needed,
+    .fields = (VMStateField[]) {
+        VMSTATE_BOOL(started, VirtIODevice),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 static const VMStateDescription vmstate_virtio = {
     .name = "virtio",
     .version_id = 1,
@@ -1913,6 +1957,7 @@ static const VMStateDescription vmstate_virtio = {
         &vmstate_virtio_ringsize,
         &vmstate_virtio_broken,
         &vmstate_virtio_extra_state,
+        &vmstate_virtio_started,
         NULL
     }
 };
@@ -2246,7 +2291,7 @@ static void virtio_vmstate_change(void *opaque, int running, RunState state)
     VirtIODevice *vdev = opaque;
     BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
     VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
-    bool backend_run = running && (vdev->status & VIRTIO_CONFIG_S_DRIVER_OK);
+    bool backend_run = running && vdev->started;
     vdev->vm_running = running;
 
     if (backend_run) {
@@ -2286,6 +2331,9 @@ void virtio_init(VirtIODevice *vdev, const char *name,
             g_malloc0(sizeof(*vdev->vector_queues) * nvectors);
     }
 
+    vdev->start_on_kick = (virtio_host_has_feature(vdev, VIRTIO_F_VERSION_1) &&
+                          !virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1));
+    vdev->started = false;
     vdev->device_id = device_id;
     vdev->status = 0;
     atomic_set(&vdev->isr, 0);
@@ -2318,6 +2366,11 @@ hwaddr virtio_queue_get_desc_addr(VirtIODevice *vdev, int n)
     return vdev->vq[n].vring.desc;
 }
 
+bool virtio_queue_enabled(VirtIODevice *vdev, int n)
+{
+    return virtio_queue_get_desc_addr(vdev, n) != 0;
+}
+
 hwaddr virtio_queue_get_avail_addr(VirtIODevice *vdev, int n)
 {
     return vdev->vq[n].vring.avail;
diff --git a/include/block/block.h b/include/block/block.h
index 5e2b98b0ee..9b083e2bca 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -586,6 +586,16 @@ void bdrv_coroutine_enter(BlockDriverState *bs, Coroutine *co);
  * This function must be called with iothread lock held.
  */
 void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context);
+void bdrv_set_aio_context_ignore(BlockDriverState *bs,
+                                 AioContext *new_context, GSList **ignore);
+int bdrv_try_set_aio_context(BlockDriverState *bs, AioContext *ctx,
+                             Error **errp);
+int bdrv_child_try_set_aio_context(BlockDriverState *bs, AioContext *ctx,
+                                   BdrvChild *ignore_child, Error **errp);
+bool bdrv_child_can_set_aio_context(BdrvChild *c, AioContext *ctx,
+                                    GSList **ignore, Error **errp);
+bool bdrv_can_set_aio_context(BlockDriverState *bs, AioContext *ctx,
+                              GSList **ignore, Error **errp);
 int bdrv_probe_blocksizes(BlockDriverState *bs, BlockSizes *bsz);
 int bdrv_probe_geometry(BlockDriverState *bs, HDGeometry *geo);
 
diff --git a/include/block/block_int.h b/include/block/block_int.h
index 94d45c9708..1eebc7c8f3 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -691,6 +691,10 @@ struct BdrvChildRole {
      * can update its reference. */
     int (*update_filename)(BdrvChild *child, BlockDriverState *new_base,
                            const char *filename, Error **errp);
+
+    bool (*can_set_aio_ctx)(BdrvChild *child, AioContext *ctx,
+                            GSList **ignore, Error **errp);
+    void (*set_aio_ctx)(BdrvChild *child, AioContext *ctx, GSList **ignore);
 };
 
 extern const BdrvChildRole child_file;
@@ -963,27 +967,6 @@ void bdrv_add_before_write_notifier(BlockDriverState *bs,
                                     NotifierWithReturn *notifier);
 
 /**
- * bdrv_detach_aio_context:
- *
- * May be called from .bdrv_detach_aio_context() to detach children from the
- * current #AioContext.  This is only needed by block drivers that manage their
- * own children.  Both ->file and ->backing are automatically handled and
- * block drivers should not call this function on them explicitly.
- */
-void bdrv_detach_aio_context(BlockDriverState *bs);
-
-/**
- * bdrv_attach_aio_context:
- *
- * May be called from .bdrv_attach_aio_context() to attach children to the new
- * #AioContext.  This is only needed by block drivers that manage their own
- * children.  Both ->file and ->backing are automatically handled and block
- * drivers should not call this function on them explicitly.
- */
-void bdrv_attach_aio_context(BlockDriverState *bs,
-                             AioContext *new_context);
-
-/**
  * bdrv_add_aio_context_notifier:
  *
  * If a long-running job intends to be always run in the same AioContext as a
diff --git a/include/hw/acpi/pci.h b/include/hw/acpi/pci.h
new file mode 100644
index 0000000000..124af7d32a
--- /dev/null
+++ b/include/hw/acpi/pci.h
@@ -0,0 +1,33 @@
+/*
+ * Support for generating PCI related ACPI tables and passing them to Guests
+ *
+ * Copyright (C) 2006 Fabrice Bellard
+ * Copyright (C) 2008-2010  Kevin O'Connor <kevin@koconnor.net>
+ * Copyright (C) 2013-2019 Red Hat Inc
+ * Copyright (C) 2019 Intel Corporation
+ *
+ * Author: Wei Yang <richardw.yang@linux.intel.com>
+ * Author: Michael S. Tsirkin <mst@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef HW_ACPI_PCI_H
+#define HW_ACPI_PCI_H
+
+typedef struct AcpiMcfgInfo {
+    uint64_t base;
+    uint32_t size;
+} AcpiMcfgInfo;
+
+#endif
diff --git a/include/hw/acpi/piix4.h b/include/hw/acpi/piix4.h
index 26c2370e30..028bb53e3d 100644
--- a/include/hw/acpi/piix4.h
+++ b/include/hw/acpi/piix4.h
@@ -1,6 +1,6 @@
 #ifndef HW_ACPI_PIIX4_H
 #define HW_ACPI_PIIX4_H
 
-Object *piix4_pm_find(void);
+#define TYPE_PIIX4_PM "PIIX4_PM"
 
 #endif
diff --git a/include/hw/i386/ich9.h b/include/hw/i386/ich9.h
index 673d13d28f..046bcf33be 100644
--- a/include/hw/i386/ich9.h
+++ b/include/hw/i386/ich9.h
@@ -81,8 +81,6 @@ typedef struct ICH9LPCState {
     qemu_irq gsi[GSI_NUM_PINS];
 } ICH9LPCState;
 
-Object *ich9_lpc_find(void);
-
 #define Q35_MASK(bit, ms_bit, ls_bit) \
 ((uint##bit##_t)(((1ULL << ((ms_bit) + 1)) - 1) & ~((1ULL << ls_bit) - 1)))
 
diff --git a/include/hw/i386/ioapic_internal.h b/include/hw/i386/ioapic_internal.h
index 9848f391bb..07002f9662 100644
--- a/include/hw/i386/ioapic_internal.h
+++ b/include/hw/i386/ioapic_internal.h
@@ -96,6 +96,7 @@ typedef struct IOAPICCommonClass {
     SysBusDeviceClass parent_class;
 
     DeviceRealize realize;
+    DeviceUnrealize unrealize;
     void (*pre_save)(IOAPICCommonState *s);
     void (*post_load)(IOAPICCommonState *s);
 } IOAPICCommonClass;
@@ -111,6 +112,8 @@ struct IOAPICCommonState {
     uint8_t version;
     uint64_t irq_count[IOAPIC_NUM_PINS];
     int irq_level[IOAPIC_NUM_PINS];
+    int irq_eoi[IOAPIC_NUM_PINS];
+    QEMUTimer *delayed_ioapic_service_timer;
 };
 
 void ioapic_reset_common(DeviceState *dev);
diff --git a/include/hw/misc/grlib_ahb_apb_pnp.h b/include/hw/misc/grlib_ahb_apb_pnp.h
new file mode 100644
index 0000000000..a0f6dcfda7
--- /dev/null
+++ b/include/hw/misc/grlib_ahb_apb_pnp.h
@@ -0,0 +1,60 @@
+/*
+ * GRLIB AHB APB PNP
+ *
+ *  Copyright (C) 2019 AdaCore
+ *
+ *  Developed by :
+ *  Frederic Konrad   <frederic.konrad@adacore.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef GRLIB_AHB_APB_PNP_H
+#define GRLIB_AHB_APB_PNP_H
+
+#define TYPE_GRLIB_AHB_PNP "grlib,ahbpnp"
+#define GRLIB_AHB_PNP(obj) \
+    OBJECT_CHECK(AHBPnp, (obj), TYPE_GRLIB_AHB_PNP)
+typedef struct AHBPnp AHBPnp;
+
+#define TYPE_GRLIB_APB_PNP "grlib,apbpnp"
+#define GRLIB_APB_PNP(obj) \
+    OBJECT_CHECK(APBPnp, (obj), TYPE_GRLIB_APB_PNP)
+typedef struct APBPnp APBPnp;
+
+void grlib_ahb_pnp_add_entry(AHBPnp *dev, uint32_t address, uint32_t mask,
+                             uint8_t vendor, uint16_t device, int slave,
+                             int type);
+void grlib_apb_pnp_add_entry(APBPnp *dev, uint32_t address, uint32_t mask,
+                             uint8_t vendor, uint16_t device, uint8_t version,
+                             uint8_t irq, int type);
+
+/* VENDORS */
+#define GRLIB_VENDOR_GAISLER (0x01)
+/* DEVICES */
+#define GRLIB_LEON3_DEV      (0x03)
+#define GRLIB_APBMST_DEV     (0x06)
+#define GRLIB_APBUART_DEV    (0x0C)
+#define GRLIB_IRQMP_DEV      (0x0D)
+#define GRLIB_GPTIMER_DEV    (0x11)
+/* TYPE */
+#define GRLIB_CPU_AREA       (0x00)
+#define GRLIB_APBIO_AREA     (0x01)
+#define GRLIB_AHBMEM_AREA    (0x02)
+
+#define GRLIB_AHB_MASTER     (0x00)
+#define GRLIB_AHB_SLAVE      (0x01)
+
+#endif /* GRLIB_AHB_APB_PNP_H */
diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h
index fdd4c43d3a..edf44de21d 100644
--- a/include/hw/pci/pci.h
+++ b/include/hw/pci/pci.h
@@ -395,7 +395,6 @@ typedef PCIINTxRoute (*pci_route_irq_fn)(void *opaque, int pin);
 #define TYPE_PCIE_BUS "PCIE"
 
 bool pci_bus_is_express(PCIBus *bus);
-bool pci_bus_is_root(PCIBus *bus);
 bool pci_bus_allows_extended_config_space(PCIBus *bus);
 
 void pci_root_bus_new_inplace(PCIBus *bus, size_t bus_size, DeviceState *parent,
diff --git a/include/hw/pci/pci_bus.h b/include/hw/pci/pci_bus.h
index f6df834170..aea98d5040 100644
--- a/include/hw/pci/pci_bus.h
+++ b/include/hw/pci/pci_bus.h
@@ -15,14 +15,19 @@ typedef struct PCIBusClass {
     BusClass parent_class;
     /*< public >*/
 
-    bool (*is_root)(PCIBus *bus);
     int (*bus_num)(PCIBus *bus);
     uint16_t (*numa_node)(PCIBus *bus);
     bool (*allows_extended_config_space)(PCIBus *bus);
 } PCIBusClass;
 
+enum PCIBusFlags {
+    /* This bus is the root of a PCI domain */
+    PCI_BUS_IS_ROOT                                         = 0x0001,
+};
+
 struct PCIBus {
     BusState qbus;
+    enum PCIBusFlags flags;
     PCIIOMMUFunc iommu_fn;
     void *iommu_opaque;
     uint8_t devfn_min;
@@ -47,4 +52,9 @@ struct PCIBus {
     Notifier machine_done;
 };
 
+static inline bool pci_bus_is_root(PCIBus *bus)
+{
+    return !!(bus->flags & PCI_BUS_IS_ROOT);
+}
+
 #endif /* QEMU_PCI_BUS_H */
diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h
index 33ed3b8dde..fa55dc10ae 100644
--- a/include/hw/qdev-core.h
+++ b/include/hw/qdev-core.h
@@ -251,8 +251,6 @@ struct PropertyInfo {
 /**
  * GlobalProperty:
  * @used: Set to true if property was used when initializing a device.
- * @optional: If set to true, GlobalProperty will be skipped without errors
- *            if the property doesn't exist.
  *
  * An error is fatal for non-hotplugged devices, when the global is applied.
  */
@@ -261,7 +259,6 @@ typedef struct GlobalProperty {
     const char *property;
     const char *value;
     bool used;
-    bool optional;
 } GlobalProperty;
 
 static inline void
diff --git a/include/hw/sparc/grlib.h b/include/hw/sparc/grlib.h
index 61a345c269..5606ff0a97 100644
--- a/include/hw/sparc/grlib.h
+++ b/include/hw/sparc/grlib.h
@@ -1,7 +1,7 @@
 /*
  * QEMU GRLIB Components
  *
- * Copyright (c) 2010-2011 AdaCore
+ * Copyright (c) 2010-2019 AdaCore
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
@@ -33,6 +33,7 @@
  */
 
 /* IRQMP */
+#define TYPE_GRLIB_IRQMP "grlib,irqmp"
 
 typedef void (*set_pil_in_fn) (void *opaque, uint32_t pil_in);
 
@@ -40,81 +41,10 @@ void grlib_irqmp_set_irq(void *opaque, int irq, int level);
 
 void grlib_irqmp_ack(DeviceState *dev, int intno);
 
-static inline
-DeviceState *grlib_irqmp_create(hwaddr   base,
-                                CPUSPARCState            *env,
-                                qemu_irq           **cpu_irqs,
-                                uint32_t             nr_irqs,
-                                set_pil_in_fn        set_pil_in)
-{
-    DeviceState *dev;
-
-    assert(cpu_irqs != NULL);
-
-    dev = qdev_create(NULL, "grlib,irqmp");
-    qdev_prop_set_ptr(dev, "set_pil_in", set_pil_in);
-    qdev_prop_set_ptr(dev, "set_pil_in_opaque", env);
-
-    qdev_init_nofail(dev);
-
-    env->irq_manager = dev;
-
-    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
-
-    *cpu_irqs = qemu_allocate_irqs(grlib_irqmp_set_irq,
-                                   dev,
-                                   nr_irqs);
-
-    return dev;
-}
-
 /* GPTimer */
-
-static inline
-DeviceState *grlib_gptimer_create(hwaddr  base,
-                                  uint32_t            nr_timers,
-                                  uint32_t            freq,
-                                  qemu_irq           *cpu_irqs,
-                                  int                 base_irq)
-{
-    DeviceState *dev;
-    int i;
-
-    dev = qdev_create(NULL, "grlib,gptimer");
-    qdev_prop_set_uint32(dev, "nr-timers", nr_timers);
-    qdev_prop_set_uint32(dev, "frequency", freq);
-    qdev_prop_set_uint32(dev, "irq-line", base_irq);
-
-    qdev_init_nofail(dev);
-
-    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
-
-    for (i = 0; i < nr_timers; i++) {
-        sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, cpu_irqs[base_irq + i]);
-    }
-
-    return dev;
-}
+#define TYPE_GRLIB_GPTIMER "grlib,gptimer"
 
 /* APB UART */
-
-static inline
-DeviceState *grlib_apbuart_create(hwaddr  base,
-                                  Chardev    *serial,
-                                  qemu_irq            irq)
-{
-    DeviceState *dev;
-
-    dev = qdev_create(NULL, "grlib,apbuart");
-    qdev_prop_set_chr(dev, "chrdev", serial);
-
-    qdev_init_nofail(dev);
-
-    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
-
-    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
-
-    return dev;
-}
+#define TYPE_GRLIB_APB_UART "grlib,apbuart"
 
 #endif /* GRLIB_H */
diff --git a/include/hw/virtio/vhost-user-blk.h b/include/hw/virtio/vhost-user-blk.h
index 68634bee61..51457fb857 100644
--- a/include/hw/virtio/vhost-user-blk.h
+++ b/include/hw/virtio/vhost-user-blk.h
@@ -38,6 +38,9 @@ typedef struct VHostUserBlk {
     struct vhost_dev dev;
     struct vhost_inflight *inflight;
     VhostUserState vhost_user;
+    struct vhost_virtqueue *vqs;
+    guint watch;
+    bool connected;
 } VHostUserBlk;
 
 #endif
diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
index ce9516236a..27c0efc3d0 100644
--- a/include/hw/virtio/virtio.h
+++ b/include/hw/virtio/virtio.h
@@ -105,6 +105,8 @@ struct VirtIODevice
     uint16_t device_id;
     bool vm_running;
     bool broken; /* device in invalid state, needs reset */
+    bool started;
+    bool start_on_kick; /* virtio 1.0 transitional devices support that */
     VMChangeStateEntry *vmstate;
     char *bus_name;
     uint8_t device_endian;
@@ -282,6 +284,7 @@ typedef struct VirtIORNGConf VirtIORNGConf;
                       VIRTIO_F_IOMMU_PLATFORM, false)
 
 hwaddr virtio_queue_get_desc_addr(VirtIODevice *vdev, int n);
+bool virtio_queue_enabled(VirtIODevice *vdev, int n);
 hwaddr virtio_queue_get_avail_addr(VirtIODevice *vdev, int n);
 hwaddr virtio_queue_get_used_addr(VirtIODevice *vdev, int n);
 hwaddr virtio_queue_get_desc_size(VirtIODevice *vdev, int n);
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
index 5be6224226..938de34fe9 100644
--- a/include/sysemu/block-backend.h
+++ b/include/sysemu/block-backend.h
@@ -103,6 +103,7 @@ int blk_set_perm(BlockBackend *blk, uint64_t perm, uint64_t shared_perm,
 void blk_get_perm(BlockBackend *blk, uint64_t *perm, uint64_t *shared_perm);
 
 void blk_set_allow_write_beyond_eof(BlockBackend *blk, bool allow);
+void blk_set_allow_aio_context_change(BlockBackend *blk, bool allow);
 void blk_iostatus_enable(BlockBackend *blk);
 bool blk_iostatus_is_enabled(const BlockBackend *blk);
 BlockDeviceIoStatus blk_iostatus(const BlockBackend *blk);
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index f5ff6f5dc8..efa3ec2837 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -10223,18 +10223,11 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
         switch (arg1) {
           case TARGET_GSI_IEEE_FP_CONTROL:
             {
-                uint64_t swcr, fpcr = cpu_alpha_load_fpcr (cpu_env);
-
-                /* Copied from linux ieee_fpcr_to_swcr.  */
-                swcr = (fpcr >> 35) & SWCR_STATUS_MASK;
-                swcr |= (fpcr >> 36) & SWCR_MAP_DMZ;
-                swcr |= (~fpcr >> 48) & (SWCR_TRAP_ENABLE_INV
-                                        | SWCR_TRAP_ENABLE_DZE
-                                        | SWCR_TRAP_ENABLE_OVF);
-                swcr |= (~fpcr >> 57) & (SWCR_TRAP_ENABLE_UNF
-                                        | SWCR_TRAP_ENABLE_INE);
-                swcr |= (fpcr >> 47) & SWCR_MAP_UMZ;
-                swcr |= (~fpcr >> 41) & SWCR_TRAP_ENABLE_DNO;
+                uint64_t fpcr = cpu_alpha_load_fpcr(cpu_env);
+                uint64_t swcr = ((CPUAlphaState *)cpu_env)->swcr;
+
+                swcr &= ~SWCR_STATUS_MASK;
+                swcr |= (fpcr >> 35) & SWCR_STATUS_MASK;
 
                 if (put_user_u64 (swcr, arg2))
                         return -TARGET_EFAULT;
@@ -10261,25 +10254,24 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
         switch (arg1) {
           case TARGET_SSI_IEEE_FP_CONTROL:
             {
-                uint64_t swcr, fpcr, orig_fpcr;
+                uint64_t swcr, fpcr;
 
                 if (get_user_u64 (swcr, arg2)) {
                     return -TARGET_EFAULT;
                 }
-                orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
-                fpcr = orig_fpcr & FPCR_DYN_MASK;
-
-                /* Copied from linux ieee_swcr_to_fpcr.  */
-                fpcr |= (swcr & SWCR_STATUS_MASK) << 35;
-                fpcr |= (swcr & SWCR_MAP_DMZ) << 36;
-                fpcr |= (~swcr & (SWCR_TRAP_ENABLE_INV
-                                  | SWCR_TRAP_ENABLE_DZE
-                                  | SWCR_TRAP_ENABLE_OVF)) << 48;
-                fpcr |= (~swcr & (SWCR_TRAP_ENABLE_UNF
-                                  | SWCR_TRAP_ENABLE_INE)) << 57;
-                fpcr |= (swcr & SWCR_MAP_UMZ ? FPCR_UNDZ | FPCR_UNFD : 0);
-                fpcr |= (~swcr & SWCR_TRAP_ENABLE_DNO) << 41;
 
+                /*
+                 * The kernel calls swcr_update_status to update the
+                 * status bits from the fpcr at every point that it
+                 * could be queried.  Therefore, we store the status
+                 * bits only in FPCR.
+                 */
+                ((CPUAlphaState *)cpu_env)->swcr
+                    = swcr & (SWCR_TRAP_ENABLE_MASK | SWCR_MAP_MASK);
+
+                fpcr = cpu_alpha_load_fpcr(cpu_env);
+                fpcr &= ((uint64_t)FPCR_DYN_MASK << 32);
+                fpcr |= alpha_ieee_swcr_to_fpcr(swcr);
                 cpu_alpha_store_fpcr(cpu_env, fpcr);
                 ret = 0;
             }
@@ -10287,44 +10279,47 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
 
           case TARGET_SSI_IEEE_RAISE_EXCEPTION:
             {
-                uint64_t exc, fpcr, orig_fpcr;
-                int si_code;
+                uint64_t exc, fpcr, fex;
 
                 if (get_user_u64(exc, arg2)) {
                     return -TARGET_EFAULT;
                 }
+                exc &= SWCR_STATUS_MASK;
+                fpcr = cpu_alpha_load_fpcr(cpu_env);
 
-                orig_fpcr = cpu_alpha_load_fpcr(cpu_env);
-
-                /* We only add to the exception status here.  */
-                fpcr = orig_fpcr | ((exc & SWCR_STATUS_MASK) << 35);
+                /* Old exceptions are not signaled.  */
+                fex = alpha_ieee_fpcr_to_swcr(fpcr);
+                fex = exc & ~fex;
+                fex >>= SWCR_STATUS_TO_EXCSUM_SHIFT;
+                fex &= ((CPUArchState *)cpu_env)->swcr;
 
+                /* Update the hardware fpcr.  */
+                fpcr |= alpha_ieee_swcr_to_fpcr(exc);
                 cpu_alpha_store_fpcr(cpu_env, fpcr);
-                ret = 0;
 
-                /* Old exceptions are not signaled.  */
-                fpcr &= ~(orig_fpcr & FPCR_STATUS_MASK);
-
-                /* If any exceptions set by this call,
-                   and are unmasked, send a signal.  */
-                si_code = 0;
-                if ((fpcr & (FPCR_INE | FPCR_INED)) == FPCR_INE) {
-                    si_code = TARGET_FPE_FLTRES;
-                }
-                if ((fpcr & (FPCR_UNF | FPCR_UNFD)) == FPCR_UNF) {
-                    si_code = TARGET_FPE_FLTUND;
-                }
-                if ((fpcr & (FPCR_OVF | FPCR_OVFD)) == FPCR_OVF) {
-                    si_code = TARGET_FPE_FLTOVF;
-                }
-                if ((fpcr & (FPCR_DZE | FPCR_DZED)) == FPCR_DZE) {
-                    si_code = TARGET_FPE_FLTDIV;
-                }
-                if ((fpcr & (FPCR_INV | FPCR_INVD)) == FPCR_INV) {
-                    si_code = TARGET_FPE_FLTINV;
-                }
-                if (si_code != 0) {
+                if (fex) {
+                    int si_code = TARGET_FPE_FLTUNK;
                     target_siginfo_t info;
+
+                    if (fex & SWCR_TRAP_ENABLE_DNO) {
+                        si_code = TARGET_FPE_FLTUND;
+                    }
+                    if (fex & SWCR_TRAP_ENABLE_INE) {
+                        si_code = TARGET_FPE_FLTRES;
+                    }
+                    if (fex & SWCR_TRAP_ENABLE_UNF) {
+                        si_code = TARGET_FPE_FLTUND;
+                    }
+                    if (fex & SWCR_TRAP_ENABLE_OVF) {
+                        si_code = TARGET_FPE_FLTOVF;
+                    }
+                    if (fex & SWCR_TRAP_ENABLE_DZE) {
+                        si_code = TARGET_FPE_FLTDIV;
+                    }
+                    if (fex & SWCR_TRAP_ENABLE_INV) {
+                        si_code = TARGET_FPE_FLTINV;
+                    }
+
                     info.si_signo = SIGFPE;
                     info.si_errno = 0;
                     info.si_code = si_code;
@@ -10333,6 +10328,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
                     queue_signal((CPUArchState *)cpu_env, info.si_signo,
                                  QEMU_SI_FAULT, &info);
                 }
+                ret = 0;
             }
             break;
 
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index 12c8407144..1f5b2d18db 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -635,7 +635,8 @@ typedef struct target_siginfo {
 #define TARGET_FPE_FLTRES      (6)  /* floating point inexact result */
 #define TARGET_FPE_FLTINV      (7)  /* floating point invalid operation */
 #define TARGET_FPE_FLTSUB      (8)  /* subscript out of range */
-#define TARGET_NSIGFPE         8
+#define TARGET_FPE_FLTUNK      (14) /* undiagnosed fp exception */
+#define TARGET_NSIGFPE         15
 
 /*
  * SIGSEGV si_codes
diff --git a/memory.c b/memory.c
index bb2b71ee38..3071c4bdad 100644
--- a/memory.c
+++ b/memory.c
@@ -2584,7 +2584,7 @@ void memory_global_dirty_log_start(void)
 
     MEMORY_LISTENER_CALL_GLOBAL(log_global_start, Forward);
 
-    /* Refresh DIRTY_LOG_MIGRATION bit.  */
+    /* Refresh DIRTY_MEMORY_MIGRATION bit.  */
     memory_region_transaction_begin();
     memory_region_update_pending = true;
     memory_region_transaction_commit();
@@ -2594,7 +2594,7 @@ static void memory_global_dirty_log_do_stop(void)
 {
     global_dirty_log = false;
 
-    /* Refresh DIRTY_LOG_MIGRATION bit.  */
+    /* Refresh DIRTY_MEMORY_MIGRATION bit.  */
     memory_region_transaction_begin();
     memory_region_update_pending = true;
     memory_region_transaction_commit();
diff --git a/net/colo-compare.c b/net/colo-compare.c
index bf10526f05..fcb491121b 100644
--- a/net/colo-compare.c
+++ b/net/colo-compare.c
@@ -813,9 +813,8 @@ static void colo_compare_handle_event(void *opaque)
         break;
     }
 
-    assert(event_unhandled_count > 0);
-
     qemu_mutex_lock(&event_mtx);
+    assert(event_unhandled_count > 0);
     event_unhandled_count--;
     qemu_cond_broadcast(&event_complete_cond);
     qemu_mutex_unlock(&event_mtx);
diff --git a/net/slirp.c b/net/slirp.c
index 95934fb36d..b34cb29276 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -498,7 +498,8 @@ static int net_slirp_init(NetClientState *peer, const char *model,
     }
     if (vprefix6_len < 0 || vprefix6_len > 126) {
         error_setg(errp,
-                   "Invalid prefix provided (prefix len must be in range 0-126");
+                   "Invalid IPv6 prefix provided "
+                   "(IPv6 prefix length must be between 0 and 126)");
         return -1;
     }
 
diff --git a/net/vhost-user.c b/net/vhost-user.c
index 5a26a24708..51921de443 100644
--- a/net/vhost-user.c
+++ b/net/vhost-user.c
@@ -236,7 +236,6 @@ static void chr_closed_bh(void *opaque)
     s = DO_UPCAST(NetVhostUserState, nc, ncs[0]);
 
     qmp_set_link(name, false, &err);
-    vhost_user_stop(queues, ncs);
 
     qemu_chr_fe_set_handlers(&s->chr, NULL, NULL, net_vhost_user_event,
                              NULL, opaque, NULL, true);
diff --git a/qemu-deprecated.texi b/qemu-deprecated.texi
index 842e71b11d..90cb677849 100644
--- a/qemu-deprecated.texi
+++ b/qemu-deprecated.texi
@@ -72,6 +72,16 @@ backend settings instead of environment variables.  To ease migration to
 the new format, the ``-audiodev-help'' option can be used to convert
 the current values of the environment variables to ``-audiodev'' options.
 
+@subsection -realtime (since 4.1)
+
+The @code{-realtime mlock=on|off} argument has been replaced by the
+@code{-overcommit mem-lock=on|off} argument.
+
+@subsection -virtfs_synth (since 4.1)
+
+The ``-virtfs_synth'' argument is now deprecated. Please use ``-fsdev synth''
+and ``-device virtio-9p-...'' instead.
+
 @section QEMU Machine Protocol (QMP) commands
 
 @subsection block-dirty-bitmap-add "autoload" parameter (since 2.12.0)
diff --git a/qemu-img.texi b/qemu-img.texi
index 724f244ba1..e8bc0fd7a2 100644
--- a/qemu-img.texi
+++ b/qemu-img.texi
@@ -230,6 +230,7 @@ overridden with a pattern byte specified by @var{pattern}.
 
 Perform a consistency check on the disk image @var{filename}. The command can
 output in the format @var{ofmt} which is either @code{human} or @code{json}.
+The JSON output is an object of QAPI type @code{ImageCheck}.
 
 If @code{-r} is specified, qemu-img tries to repair any inconsistencies found
 during the check. @code{-r leaks} repairs only cluster leaks, whereas
@@ -406,8 +407,7 @@ The size syntax is similar to dd(1)'s size syntax.
 Give information about the disk image @var{filename}. Use it in
 particular to know the size reserved on disk which can be different
 from the displayed size. If VM snapshots are stored in the disk image,
-they are displayed too. The command can output in the format @var{ofmt}
-which is either @code{human} or @code{json}.
+they are displayed too.
 
 If a disk image has a backing file chain, information about each disk image in
 the chain can be recursively enumerated by using the option @code{--backing-chain}.
@@ -424,6 +424,51 @@ To enumerate information about each disk image in the above chain, starting from
 qemu-img info --backing-chain snap2.qcow2
 @end example
 
+The command can output in the format @var{ofmt} which is either @code{human} or
+@code{json}.  The JSON output is an object of QAPI type @code{ImageInfo}; with
+@code{--backing-chain}, it is an array of @code{ImageInfo} objects.
+
+@code{--output=human} reports the following information (for every image in the
+chain):
+@table @var
+@item image
+The image file name
+
+@item file format
+The image format
+
+@item virtual size
+The size of the guest disk
+
+@item disk size
+How much space the image file occupies on the host file system (may be shown as
+0 if this information is unavailable, e.g. because there is no file system)
+
+@item cluster_size
+Cluster size of the image format, if applicable
+
+@item encrypted
+Whether the image is encrypted (only present if so)
+
+@item cleanly shut down
+This is shown as @code{no} if the image is dirty and will have to be
+auto-repaired the next time it is opened in qemu.
+
+@item backing file
+The backing file name, if present
+
+@item backing file format
+The format of the backing file, if the image enforces it
+
+@item Snapshot list
+A list of all internal snapshots
+
+@item Format specific information
+Further information whose structure depends on the image format.  This section
+is a textual representation of the respective @code{ImageInfoSpecific*} QAPI
+object (e.g. @code{ImageInfoSpecificQCow2} for qcow2 images).
+@end table
+
 @item map [--object @var{objectdef}] [--image-opts] [-f @var{fmt}] [--output=@var{ofmt}] [-U] @var{filename}
 
 Dump the metadata of image @var{filename} and its backing file chain.
@@ -485,7 +530,8 @@ Calculate the file size required for a new image.  This information can be used
 to size logical volumes or SAN LUNs appropriately for the image that will be
 placed in them.  The values reported are guaranteed to be large enough to fit
 the image.  The command can output in the format @var{ofmt} which is either
-@code{human} or @code{json}.
+@code{human} or @code{json}.  The JSON output is an object of QAPI type
+@code{BlockMeasureInfo}.
 
 If the size @var{N} is given then act as if creating a new empty image file
 using @command{qemu-img create}.  If @var{filename} is given then act as if
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
index 8826bebaf6..30a7d9a13b 100644
--- a/qemu-io-cmds.c
+++ b/qemu-io-cmds.c
@@ -538,7 +538,7 @@ static int do_write_compressed(BlockBackend *blk, char *buf, int64_t offset,
 {
     int ret;
 
-    if (bytes >> 9 > BDRV_REQUEST_MAX_SECTORS) {
+    if (bytes > BDRV_REQUEST_MAX_BYTES) {
         return -ERANGE;
     }
 
@@ -1781,10 +1781,9 @@ static int discard_f(BlockBackend *blk, int argc, char **argv)
     if (bytes < 0) {
         print_cvtnum_err(bytes, argv[optind]);
         return bytes;
-    } else if (bytes >> BDRV_SECTOR_BITS > BDRV_REQUEST_MAX_SECTORS) {
+    } else if (bytes > BDRV_REQUEST_MAX_BYTES) {
         printf("length cannot exceed %"PRIu64", given %s\n",
-               (uint64_t)BDRV_REQUEST_MAX_SECTORS << BDRV_SECTOR_BITS,
-               argv[optind]);
+               (uint64_t)BDRV_REQUEST_MAX_BYTES, argv[optind]);
         return -EINVAL;
     }
 
diff --git a/qemu-options.hx b/qemu-options.hx
index 3faa935929..5daa5a8fb0 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1232,26 +1232,35 @@ the write back by pressing @key{C-a s} (@pxref{disk_images}).
 ETEXI
 
 DEF("fsdev", HAS_ARG, QEMU_OPTION_fsdev,
-    "-fsdev fsdriver,id=id[,path=path,][security_model={mapped-xattr|mapped-file|passthrough|none}]\n"
-    " [,writeout=immediate][,readonly][,socket=socket|sock_fd=sock_fd][,fmode=fmode][,dmode=dmode]\n"
+    "-fsdev local,id=id,path=path,security_model=mapped-xattr|mapped-file|passthrough|none\n"
+    " [,writeout=immediate][,readonly][,fmode=fmode][,dmode=dmode]\n"
     " [[,throttling.bps-total=b]|[[,throttling.bps-read=r][,throttling.bps-write=w]]]\n"
     " [[,throttling.iops-total=i]|[[,throttling.iops-read=r][,throttling.iops-write=w]]]\n"
     " [[,throttling.bps-total-max=bm]|[[,throttling.bps-read-max=rm][,throttling.bps-write-max=wm]]]\n"
     " [[,throttling.iops-total-max=im]|[[,throttling.iops-read-max=irm][,throttling.iops-write-max=iwm]]]\n"
-    " [[,throttling.iops-size=is]]\n",
+    " [[,throttling.iops-size=is]]\n"
+    "-fsdev proxy,id=id,socket=socket[,writeout=immediate][,readonly]\n"
+    "-fsdev proxy,id=id,sock_fd=sock_fd[,writeout=immediate][,readonly]\n"
+    "-fsdev synth,id=id\n",
     QEMU_ARCH_ALL)
 
 STEXI
 
-@item -fsdev @var{fsdriver},id=@var{id},path=@var{path},[security_model=@var{security_model}][,writeout=@var{writeout}][,readonly][,socket=@var{socket}|sock_fd=@var{sock_fd}][,fmode=@var{fmode}][,dmode=@var{dmode}]
+@item -fsdev local,id=@var{id},path=@var{path},security_model=@var{security_model} [,writeout=@var{writeout}][,readonly][,fmode=@var{fmode}][,dmode=@var{dmode}] [,throttling.@var{option}=@var{value}[,throttling.@var{option}=@var{value}[,...]]]
+@itemx -fsdev proxy,id=@var{id},socket=@var{socket}[,writeout=@var{writeout}][,readonly]
+@itemx -fsdev proxy,id=@var{id},sock_fd=@var{sock_fd}[,writeout=@var{writeout}][,readonly]
+@itemx -fsdev synth,id=@var{id}[,readonly]
 @findex -fsdev
 Define a new file system device. Valid options are:
 @table @option
-@item @var{fsdriver}
-This option specifies the fs driver backend to use.
-Currently "local" and "proxy" file system drivers are supported.
+@item local
+Accesses to the filesystem are done by QEMU.
+@item proxy
+Accesses to the filesystem are done by virtfs-proxy-helper(1).
+@item synth
+Synthetic filesystem, only used by QTests.
 @item id=@var{id}
-Specifies identifier for this device
+Specifies identifier for this device.
 @item path=@var{path}
 Specifies the export path for the file system device. Files under
 this path will be available to the 9p client on the guest.
@@ -1279,48 +1288,76 @@ Enables exporting 9p share as a readonly mount for guests. By default
 read-write access is given.
 @item socket=@var{socket}
 Enables proxy filesystem driver to use passed socket file for communicating
-with virtfs-proxy-helper
+with virtfs-proxy-helper(1).
 @item sock_fd=@var{sock_fd}
 Enables proxy filesystem driver to use passed socket descriptor for
-communicating with virtfs-proxy-helper. Usually a helper like libvirt
-will create socketpair and pass one of the fds as sock_fd
+communicating with virtfs-proxy-helper(1). Usually a helper like libvirt
+will create socketpair and pass one of the fds as sock_fd.
 @item fmode=@var{fmode}
 Specifies the default mode for newly created files on the host. Works only
 with security models "mapped-xattr" and "mapped-file".
 @item dmode=@var{dmode}
 Specifies the default mode for newly created directories on the host. Works
 only with security models "mapped-xattr" and "mapped-file".
+@item throttling.bps-total=@var{b},throttling.bps-read=@var{r},throttling.bps-write=@var{w}
+Specify bandwidth throttling limits in bytes per second, either for all request
+types or for reads or writes only.
+@item throttling.bps-total-max=@var{bm},bps-read-max=@var{rm},bps-write-max=@var{wm}
+Specify bursts in bytes per second, either for all request types or for reads
+or writes only.  Bursts allow the guest I/O to spike above the limit
+temporarily.
+@item throttling.iops-total=@var{i},throttling.iops-read=@var{r}, throttling.iops-write=@var{w}
+Specify request rate limits in requests per second, either for all request
+types or for reads or writes only.
+@item throttling.iops-total-max=@var{im},throttling.iops-read-max=@var{irm}, throttling.iops-write-max=@var{iwm}
+Specify bursts in requests per second, either for all request types or for reads
+or writes only.  Bursts allow the guest I/O to spike above the limit temporarily.
+@item throttling.iops-size=@var{is}
+Let every @var{is} bytes of a request count as a new request for iops
+throttling purposes.
 @end table
 
--fsdev option is used along with -device driver "virtio-9p-pci".
-@item -device virtio-9p-pci,fsdev=@var{id},mount_tag=@var{mount_tag}
-Options for virtio-9p-pci driver are:
+-fsdev option is used along with -device driver "virtio-9p-...".
+@item -device virtio-9p-@var{type},fsdev=@var{id},mount_tag=@var{mount_tag}
+Options for virtio-9p-... driver are:
 @table @option
+@item @var{type}
+Specifies the variant to be used. Supported values are "pci", "ccw" or "device",
+depending on the machine type.
 @item fsdev=@var{id}
-Specifies the id value specified along with -fsdev option
+Specifies the id value specified along with -fsdev option.
 @item mount_tag=@var{mount_tag}
-Specifies the tag name to be used by the guest to mount this export point
+Specifies the tag name to be used by the guest to mount this export point.
 @end table
 
 ETEXI
 
 DEF("virtfs", HAS_ARG, QEMU_OPTION_virtfs,
-    "-virtfs local,path=path,mount_tag=tag,security_model=[mapped-xattr|mapped-file|passthrough|none]\n"
-    "        [,id=id][,writeout=immediate][,readonly][,socket=socket|sock_fd=sock_fd][,fmode=fmode][,dmode=dmode]\n",
+    "-virtfs local,path=path,mount_tag=tag,security_model=mapped-xattr|mapped-file|passthrough|none\n"
+    "        [,id=id][,writeout=immediate][,readonly][,fmode=fmode][,dmode=dmode]\n"
+    "-virtfs proxy,mount_tag=tag,socket=socket[,id=id][,writeout=immediate][,readonly]\n"
+    "-virtfs proxy,mount_tag=tag,sock_fd=sock_fd[,id=id][,writeout=immediate][,readonly]\n"
+    "-virtfs synth,mount_tag=tag[,id=id][,readonly]\n",
     QEMU_ARCH_ALL)
 
 STEXI
 
-@item -virtfs @var{fsdriver}[,path=@var{path}],mount_tag=@var{mount_tag}[,security_model=@var{security_model}][,writeout=@var{writeout}][,readonly][,socket=@var{socket}|sock_fd=@var{sock_fd}][,fmode=@var{fmode}][,dmode=@var{dmode}]
+@item -virtfs local,path=@var{path},mount_tag=@var{mount_tag} ,security_model=@var{security_model}[,writeout=@var{writeout}][,readonly] [,fmode=@var{fmode}][,dmode=@var{dmode}]
+@itemx -virtfs proxy,socket=@var{socket},mount_tag=@var{mount_tag} [,writeout=@var{writeout}][,readonly]
+@itemx -virtfs proxy,sock_fd=@var{sock_fd},mount_tag=@var{mount_tag} [,writeout=@var{writeout}][,readonly]
+@itemx -virtfs synth,mount_tag=@var{mount_tag}
 @findex -virtfs
 
-The general form of a Virtual File system pass-through options are:
+Define a new filesystem device and expose it to the guest using a virtio-9p-device. The general form of a Virtual File system pass-through options are:
 @table @option
-@item @var{fsdriver}
-This option specifies the fs driver backend to use.
-Currently "local" and "proxy" file system drivers are supported.
+@item local
+Accesses to the filesystem are done by QEMU.
+@item proxy
+Accesses to the filesystem are done by virtfs-proxy-helper(1).
+@item synth
+Synthetic filesystem, only used by QTests.
 @item id=@var{id}
-Specifies identifier for this device
+Specifies identifier for the filesystem device
 @item path=@var{path}
 Specifies the export path for the file system device. Files under
 this path will be available to the 9p client on the guest.
@@ -1348,17 +1385,19 @@ Enables exporting 9p share as a readonly mount for guests. By default
 read-write access is given.
 @item socket=@var{socket}
 Enables proxy filesystem driver to use passed socket file for
-communicating with virtfs-proxy-helper. Usually a helper like libvirt
-will create socketpair and pass one of the fds as sock_fd
+communicating with virtfs-proxy-helper(1). Usually a helper like libvirt
+will create socketpair and pass one of the fds as sock_fd.
 @item sock_fd
 Enables proxy filesystem driver to use passed 'sock_fd' as the socket
-descriptor for interfacing with virtfs-proxy-helper
+descriptor for interfacing with virtfs-proxy-helper(1).
 @item fmode=@var{fmode}
 Specifies the default mode for newly created files on the host. Works only
 with security models "mapped-xattr" and "mapped-file".
 @item dmode=@var{dmode}
 Specifies the default mode for newly created directories on the host. Works
 only with security models "mapped-xattr" and "mapped-file".
+@item mount_tag=@var{mount_tag}
+Specifies the tag name to be used by the guest to mount this export point.
 @end table
 ETEXI
 
@@ -1368,7 +1407,8 @@ DEF("virtfs_synth", 0, QEMU_OPTION_virtfs_synth,
 STEXI
 @item -virtfs_synth
 @findex -virtfs_synth
-Create synthetic file system image
+Create synthetic file system image. Note that this option is now deprecated.
+Please use @code{-fsdev synth} and @code{-device virtio-9p-...} instead.
 ETEXI
 
 DEF("iscsi", HAS_ARG, QEMU_OPTION_iscsi,
diff --git a/qmp.c b/qmp.c
index b92d62cd5f..fa1b3c1577 100644
--- a/qmp.c
+++ b/qmp.c
@@ -156,6 +156,9 @@ void qmp_cont(Error **errp)
         return;
     } else if (runstate_check(RUN_STATE_SUSPENDED)) {
         return;
+    } else if (runstate_check(RUN_STATE_FINISH_MIGRATE)) {
+        error_setg(errp, "Migration is not finalized yet");
+        return;
     }
 
     for (blk = blk_next(NULL); blk; blk = blk_next(blk)) {
diff --git a/qom/object.c b/qom/object.c
index d3412e7fdc..99c4fa707e 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -385,9 +385,6 @@ void object_apply_global_props(Object *obj, const GPtrArray *props, Error **errp
         if (object_dynamic_cast(obj, p->driver) == NULL) {
             continue;
         }
-        if (p->optional && !object_property_find(obj, p->property, NULL)) {
-            continue;
-        }
         p->used = true;
         object_property_parse(obj, p->value, p->property, &err);
         if (err != NULL) {
diff --git a/target/alpha/cpu.h b/target/alpha/cpu.h
index cf09112b6a..ba6bc31b15 100644
--- a/target/alpha/cpu.h
+++ b/target/alpha/cpu.h
@@ -198,6 +198,8 @@ enum {
 #define SWCR_STATUS_DNO         (1U << 22)
 #define SWCR_STATUS_MASK        ((1U << 23) - (1U << 17))
 
+#define SWCR_STATUS_TO_EXCSUM_SHIFT  16
+
 #define SWCR_MASK  (SWCR_TRAP_ENABLE_MASK | SWCR_MAP_MASK | SWCR_STATUS_MASK)
 
 /* MMU modes definitions */
@@ -235,6 +237,9 @@ struct CPUAlphaState {
 
     /* The FPCR, and disassembled portions thereof.  */
     uint32_t fpcr;
+#ifdef CONFIG_USER_ONLY
+    uint32_t swcr;
+#endif
     uint32_t fpcr_exc_enable;
     float_status fp_status;
     uint8_t fpcr_dyn_round;
@@ -501,4 +506,41 @@ static inline void cpu_get_tb_cpu_state(CPUAlphaState *env, target_ulong *pc,
     *pflags = env->flags & ENV_FLAG_TB_MASK;
 }
 
+#ifdef CONFIG_USER_ONLY
+/* Copied from linux ieee_swcr_to_fpcr.  */
+static inline uint64_t alpha_ieee_swcr_to_fpcr(uint64_t swcr)
+{
+    uint64_t fpcr = 0;
+
+    fpcr |= (swcr & SWCR_STATUS_MASK) << 35;
+    fpcr |= (swcr & SWCR_MAP_DMZ) << 36;
+    fpcr |= (~swcr & (SWCR_TRAP_ENABLE_INV
+                      | SWCR_TRAP_ENABLE_DZE
+                      | SWCR_TRAP_ENABLE_OVF)) << 48;
+    fpcr |= (~swcr & (SWCR_TRAP_ENABLE_UNF
+                      | SWCR_TRAP_ENABLE_INE)) << 57;
+    fpcr |= (swcr & SWCR_MAP_UMZ ? FPCR_UNDZ | FPCR_UNFD : 0);
+    fpcr |= (~swcr & SWCR_TRAP_ENABLE_DNO) << 41;
+
+    return fpcr;
+}
+
+/* Copied from linux ieee_fpcr_to_swcr.  */
+static inline uint64_t alpha_ieee_fpcr_to_swcr(uint64_t fpcr)
+{
+    uint64_t swcr = 0;
+
+    swcr |= (fpcr >> 35) & SWCR_STATUS_MASK;
+    swcr |= (fpcr >> 36) & SWCR_MAP_DMZ;
+    swcr |= (~fpcr >> 48) & (SWCR_TRAP_ENABLE_INV
+                             | SWCR_TRAP_ENABLE_DZE
+                             | SWCR_TRAP_ENABLE_OVF);
+    swcr |= (~fpcr >> 57) & (SWCR_TRAP_ENABLE_UNF | SWCR_TRAP_ENABLE_INE);
+    swcr |= (fpcr >> 47) & SWCR_MAP_UMZ;
+    swcr |= (~fpcr >> 41) & SWCR_TRAP_ENABLE_DNO;
+
+    return swcr;
+}
+#endif /* CONFIG_USER_ONLY */
+
 #endif /* ALPHA_CPU_H */
diff --git a/target/alpha/fpu_helper.c b/target/alpha/fpu_helper.c
index 9645978aaa..62a066d902 100644
--- a/target/alpha/fpu_helper.c
+++ b/target/alpha/fpu_helper.c
@@ -91,10 +91,25 @@ void helper_fp_exc_raise_s(CPUAlphaState *env, uint32_t ignore, uint32_t regno)
     if (exc) {
         env->fpcr |= exc;
         exc &= ~ignore;
-        if (exc) {
-            exc &= env->fpcr_exc_enable;
-            fp_exc_raise1(env, GETPC(), exc, regno, EXC_M_SWC);
+#ifdef CONFIG_USER_ONLY
+        /*
+         * In user mode, the kernel's software handler only
+         * delivers a signal if the exception is enabled.
+         */
+        if (!(exc & env->fpcr_exc_enable)) {
+            return;
+        }
+#else
+        /*
+         * In system mode, the software handler gets invoked
+         * for any non-ignored exception.
+         */
+        if (!exc) {
+            return;
         }
+#endif
+        exc &= env->fpcr_exc_enable;
+        fp_exc_raise1(env, GETPC(), exc, regno, EXC_M_SWC);
     }
 }
 
diff --git a/target/alpha/helper.c b/target/alpha/helper.c
index 5fe9c87912..2134ee1e9d 100644
--- a/target/alpha/helper.c
+++ b/target/alpha/helper.c
@@ -29,12 +29,12 @@
 #define CONVERT_BIT(X, SRC, DST) \
     (SRC > DST ? (X) / (SRC / DST) & (DST) : ((X) & SRC) * (DST / SRC))
 
-uint64_t cpu_alpha_load_fpcr (CPUAlphaState *env)
+uint64_t cpu_alpha_load_fpcr(CPUAlphaState *env)
 {
     return (uint64_t)env->fpcr << 32;
 }
 
-void cpu_alpha_store_fpcr (CPUAlphaState *env, uint64_t val)
+void cpu_alpha_store_fpcr(CPUAlphaState *env, uint64_t val)
 {
     uint32_t fpcr = val >> 32;
     uint32_t t = 0;
@@ -67,6 +67,22 @@ void cpu_alpha_store_fpcr (CPUAlphaState *env, uint64_t val)
 
     env->fpcr_flush_to_zero = (fpcr & FPCR_UNFD) && (fpcr & FPCR_UNDZ);
     env->fp_status.flush_inputs_to_zero = (fpcr & FPCR_DNZ) != 0;
+
+#ifdef CONFIG_USER_ONLY
+    /*
+     * Override some of these bits with the contents of ENV->SWCR.
+     * In system mode, some of these would trap to the kernel, at
+     * which point the kernel's handler would emulate and apply
+     * the software exception mask.
+     */
+    if (env->swcr & SWCR_MAP_DMZ) {
+        env->fp_status.flush_inputs_to_zero = 1;
+    }
+    if (env->swcr & SWCR_MAP_UMZ) {
+        env->fp_status.flush_to_zero = 1;
+    }
+    env->fpcr_exc_enable &= ~(alpha_ieee_swcr_to_fpcr(env->swcr) >> 32);
+#endif
 }
 
 uint64_t helper_load_fpcr(CPUAlphaState *env)
@@ -435,32 +451,33 @@ bool alpha_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
 
 void alpha_cpu_dump_state(CPUState *cs, FILE *f, int flags)
 {
-    static const char *linux_reg_names[] = {
-        "v0 ", "t0 ", "t1 ", "t2 ", "t3 ", "t4 ", "t5 ", "t6 ",
-        "t7 ", "s0 ", "s1 ", "s2 ", "s3 ", "s4 ", "s5 ", "fp ",
-        "a0 ", "a1 ", "a2 ", "a3 ", "a4 ", "a5 ", "t8 ", "t9 ",
-        "t10", "t11", "ra ", "t12", "at ", "gp ", "sp ", "zero",
+    static const char linux_reg_names[31][4] = {
+        "v0",  "t0",  "t1", "t2",  "t3", "t4", "t5", "t6",
+        "t7",  "s0",  "s1", "s2",  "s3", "s4", "s5", "fp",
+        "a0",  "a1",  "a2", "a3",  "a4", "a5", "t8", "t9",
+        "t10", "t11", "ra", "t12", "at", "gp", "sp"
     };
     AlphaCPU *cpu = ALPHA_CPU(cs);
     CPUAlphaState *env = &cpu->env;
     int i;
 
-    qemu_fprintf(f, "     PC  " TARGET_FMT_lx "      PS  %02x\n",
+    qemu_fprintf(f, "PC      " TARGET_FMT_lx " PS      %02x\n",
                  env->pc, extract32(env->flags, ENV_FLAG_PS_SHIFT, 8));
     for (i = 0; i < 31; i++) {
-        qemu_fprintf(f, "IR%02d %s " TARGET_FMT_lx "%c", i,
+        qemu_fprintf(f, "%-8s" TARGET_FMT_lx "%c",
                      linux_reg_names[i], cpu_alpha_load_gr(env, i),
                      (i % 3) == 2 ? '\n' : ' ');
     }
 
-    qemu_fprintf(f, "lock_a   " TARGET_FMT_lx " lock_v   " TARGET_FMT_lx "\n",
+    qemu_fprintf(f, "lock_a  " TARGET_FMT_lx " lock_v  " TARGET_FMT_lx "\n",
                  env->lock_addr, env->lock_value);
 
     if (flags & CPU_DUMP_FPU) {
         for (i = 0; i < 31; i++) {
-            qemu_fprintf(f, "FIR%02d    %016" PRIx64 "%c", i, env->fir[i],
+            qemu_fprintf(f, "f%-7d%016" PRIx64 "%c", i, env->fir[i],
                          (i % 3) == 2 ? '\n' : ' ');
         }
+        qemu_fprintf(f, "fpcr    %016" PRIx64 "\n", cpu_alpha_load_fpcr(env));
     }
     qemu_fprintf(f, "\n");
 }
diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c
index 42f9447303..2751c8125c 100644
--- a/target/i386/hvf/hvf.c
+++ b/target/i386/hvf/hvf.c
@@ -708,6 +708,7 @@ int hvf_vcpu_exec(CPUState *cpu)
                 !(idtvec_info & VMCS_IDT_VEC_VALID)) {
                 cpu->halted = 1;
                 ret = EXCP_HLT;
+                break;
             }
             ret = EXCP_INTERRUPT;
             break;
diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c
index 6f441bc973..b16957934a 100644
--- a/target/m68k/cpu.c
+++ b/target/m68k/cpu.c
@@ -271,7 +271,7 @@ static void m68k_cpu_class_init(ObjectClass *c, void *data)
     cc->gdb_write_register = m68k_cpu_gdb_write_register;
     cc->tlb_fill = m68k_cpu_tlb_fill;
 #if defined(CONFIG_SOFTMMU)
-    cc->do_unassigned_access = m68k_cpu_unassigned_access;
+    cc->do_transaction_failed = m68k_cpu_transaction_failed;
     cc->get_phys_page_debug = m68k_cpu_get_phys_page_debug;
 #endif
     cc->disas_set_info = m68k_cpu_disas_set_info;
diff --git a/target/m68k/cpu.h b/target/m68k/cpu.h
index 683d3e2f79..9deff9e234 100644
--- a/target/m68k/cpu.h
+++ b/target/m68k/cpu.h
@@ -545,9 +545,10 @@ static inline int cpu_mmu_index (CPUM68KState *env, bool ifetch)
 bool m68k_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
                        MMUAccessType access_type, int mmu_idx,
                        bool probe, uintptr_t retaddr);
-void m68k_cpu_unassigned_access(CPUState *cs, hwaddr addr,
-                                bool is_write, bool is_exec, int is_asi,
-                                unsigned size);
+void m68k_cpu_transaction_failed(CPUState *cs, hwaddr physaddr, vaddr addr,
+                                 unsigned size, MMUAccessType access_type,
+                                 int mmu_idx, MemTxAttrs attrs,
+                                 MemTxResult response, uintptr_t retaddr);
 
 #include "exec/cpu-all.h"
 
diff --git a/target/m68k/helper.c b/target/m68k/helper.c
index 9fc9e646ff..6db93bdd81 100644
--- a/target/m68k/helper.c
+++ b/target/m68k/helper.c
@@ -390,6 +390,7 @@ static void dump_address_map(CPUM68KState *env, uint32_t root_pointer)
     int last_attr = -1, attr = -1;
     M68kCPU *cpu = m68k_env_get_cpu(env);
     CPUState *cs = CPU(cpu);
+    MemTxResult txres;
 
     if (env->mmu.tcr & M68K_TCR_PAGE_8K) {
         /* 8k page */
@@ -403,22 +404,29 @@ static void dump_address_map(CPUM68KState *env, uint32_t root_pointer)
         tib_mask = M68K_4K_PAGE_MASK;
     }
     for (i = 0; i < M68K_ROOT_POINTER_ENTRIES; i++) {
-        tia = ldl_phys(cs->as, M68K_POINTER_BASE(root_pointer) + i * 4);
-        if (!M68K_UDT_VALID(tia)) {
+        tia = address_space_ldl(cs->as, M68K_POINTER_BASE(root_pointer) + i * 4,
+                                MEMTXATTRS_UNSPECIFIED, &txres);
+        if (txres != MEMTX_OK || !M68K_UDT_VALID(tia)) {
             continue;
         }
         for (j = 0; j < M68K_ROOT_POINTER_ENTRIES; j++) {
-            tib = ldl_phys(cs->as, M68K_POINTER_BASE(tia) + j * 4);
-            if (!M68K_UDT_VALID(tib)) {
+            tib = address_space_ldl(cs->as, M68K_POINTER_BASE(tia) + j * 4,
+                                    MEMTXATTRS_UNSPECIFIED, &txres);
+            if (txres != MEMTX_OK || !M68K_UDT_VALID(tib)) {
                 continue;
             }
             for (k = 0; k < tic_size; k++) {
-                tic = ldl_phys(cs->as, (tib & tib_mask) + k * 4);
-                if (!M68K_PDT_VALID(tic)) {
+                tic = address_space_ldl(cs->as, (tib & tib_mask) + k * 4,
+                                        MEMTXATTRS_UNSPECIFIED, &txres);
+                if (txres != MEMTX_OK || !M68K_PDT_VALID(tic)) {
                     continue;
                 }
                 if (M68K_PDT_INDIRECT(tic)) {
-                    tic = ldl_phys(cs->as, M68K_INDIRECT_POINTER(tic));
+                    tic = address_space_ldl(cs->as, M68K_INDIRECT_POINTER(tic),
+                                            MEMTXATTRS_UNSPECIFIED, &txres);
+                    if (txres != MEMTX_OK) {
+                        continue;
+                    }
                 }
 
                 last_logical = logical;
@@ -630,6 +638,7 @@ static int get_physical_address(CPUM68KState *env, hwaddr *physical,
     bool debug = access_type & ACCESS_DEBUG;
     int page_bits;
     int i;
+    MemTxResult txres;
 
     /* Transparent Translation (physical = logical) */
     for (i = 0; i < M68K_MAX_TTR; i++) {
@@ -659,12 +668,19 @@ static int get_physical_address(CPUM68KState *env, hwaddr *physical,
     /* Root Index */
     entry = M68K_POINTER_BASE(next) | M68K_ROOT_INDEX(address);
 
-    next = ldl_phys(cs->as, entry);
+    next = address_space_ldl(cs->as, entry, MEMTXATTRS_UNSPECIFIED, &txres);
+    if (txres != MEMTX_OK) {
+        goto txfail;
+    }
     if (!M68K_UDT_VALID(next)) {
         return -1;
     }
     if (!(next & M68K_DESC_USED) && !debug) {
-        stl_phys(cs->as, entry, next | M68K_DESC_USED);
+        address_space_stl(cs->as, entry, next | M68K_DESC_USED,
+                          MEMTXATTRS_UNSPECIFIED, &txres);
+        if (txres != MEMTX_OK) {
+            goto txfail;
+        }
     }
     if (next & M68K_DESC_WRITEPROT) {
         if (access_type & ACCESS_PTEST) {
@@ -679,12 +695,19 @@ static int get_physical_address(CPUM68KState *env, hwaddr *physical,
     /* Pointer Index */
     entry = M68K_POINTER_BASE(next) | M68K_POINTER_INDEX(address);
 
-    next = ldl_phys(cs->as, entry);
+    next = address_space_ldl(cs->as, entry, MEMTXATTRS_UNSPECIFIED, &txres);
+    if (txres != MEMTX_OK) {
+        goto txfail;
+    }
     if (!M68K_UDT_VALID(next)) {
         return -1;
     }
     if (!(next & M68K_DESC_USED) && !debug) {
-        stl_phys(cs->as, entry, next | M68K_DESC_USED);
+        address_space_stl(cs->as, entry, next | M68K_DESC_USED,
+                          MEMTXATTRS_UNSPECIFIED, &txres);
+        if (txres != MEMTX_OK) {
+            goto txfail;
+        }
     }
     if (next & M68K_DESC_WRITEPROT) {
         if (access_type & ACCESS_PTEST) {
@@ -703,27 +726,46 @@ static int get_physical_address(CPUM68KState *env, hwaddr *physical,
         entry = M68K_4K_PAGE_BASE(next) | M68K_4K_PAGE_INDEX(address);
     }
 
-    next = ldl_phys(cs->as, entry);
+    next = address_space_ldl(cs->as, entry, MEMTXATTRS_UNSPECIFIED, &txres);
+    if (txres != MEMTX_OK) {
+        goto txfail;
+    }
 
     if (!M68K_PDT_VALID(next)) {
         return -1;
     }
     if (M68K_PDT_INDIRECT(next)) {
-        next = ldl_phys(cs->as, M68K_INDIRECT_POINTER(next));
+        next = address_space_ldl(cs->as, M68K_INDIRECT_POINTER(next),
+                                 MEMTXATTRS_UNSPECIFIED, &txres);
+        if (txres != MEMTX_OK) {
+            goto txfail;
+        }
     }
     if (access_type & ACCESS_STORE) {
         if (next & M68K_DESC_WRITEPROT) {
             if (!(next & M68K_DESC_USED) && !debug) {
-                stl_phys(cs->as, entry, next | M68K_DESC_USED);
+                address_space_stl(cs->as, entry, next | M68K_DESC_USED,
+                                  MEMTXATTRS_UNSPECIFIED, &txres);
+                if (txres != MEMTX_OK) {
+                    goto txfail;
+                }
             }
         } else if ((next & (M68K_DESC_MODIFIED | M68K_DESC_USED)) !=
                            (M68K_DESC_MODIFIED | M68K_DESC_USED) && !debug) {
-                stl_phys(cs->as, entry,
-                         next | (M68K_DESC_MODIFIED | M68K_DESC_USED));
+            address_space_stl(cs->as, entry,
+                              next | (M68K_DESC_MODIFIED | M68K_DESC_USED),
+                              MEMTXATTRS_UNSPECIFIED, &txres);
+            if (txres != MEMTX_OK) {
+                goto txfail;
+            }
         }
     } else {
         if (!(next & M68K_DESC_USED) && !debug) {
-            stl_phys(cs->as, entry, next | M68K_DESC_USED);
+            address_space_stl(cs->as, entry, next | M68K_DESC_USED,
+                              MEMTXATTRS_UNSPECIFIED, &txres);
+            if (txres != MEMTX_OK) {
+                goto txfail;
+            }
         }
     }
 
@@ -755,6 +797,14 @@ static int get_physical_address(CPUM68KState *env, hwaddr *physical,
     }
 
     return 0;
+
+txfail:
+    /*
+     * A page table load/store failed. TODO: we should really raise a
+     * suitable guest fault here if this is not a debug access.
+     * For now just return that the translation failed.
+     */
+    return -1;
 }
 
 hwaddr m68k_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
diff --git a/target/m68k/op_helper.c b/target/m68k/op_helper.c
index d421614727..1ecc772b5c 100644
--- a/target/m68k/op_helper.c
+++ b/target/m68k/op_helper.c
@@ -439,19 +439,15 @@ static inline void do_interrupt_m68k_hardirq(CPUM68KState *env)
     do_interrupt_all(env, 1);
 }
 
-void m68k_cpu_unassigned_access(CPUState *cs, hwaddr addr, bool is_write,
-                                bool is_exec, int is_asi, unsigned size)
+void m68k_cpu_transaction_failed(CPUState *cs, hwaddr physaddr, vaddr addr,
+                                 unsigned size, MMUAccessType access_type,
+                                 int mmu_idx, MemTxAttrs attrs,
+                                 MemTxResult response, uintptr_t retaddr)
 {
     M68kCPU *cpu = M68K_CPU(cs);
     CPUM68KState *env = &cpu->env;
-#ifdef DEBUG_UNASSIGNED
-    qemu_log_mask(CPU_LOG_INT, "Unassigned " TARGET_FMT_plx " wr=%d exe=%d\n",
-             addr, is_write, is_exec);
-#endif
-    if (env == NULL) {
-        /* when called from gdb, env is NULL */
-        return;
-    }
+
+    cpu_restore_state(cs, retaddr, true);
 
     if (m68k_feature(env, M68K_FEATURE_M68040)) {
         env->mmu.mmusr = 0;
@@ -461,7 +457,7 @@ void m68k_cpu_unassigned_access(CPUState *cs, hwaddr addr, bool is_write,
         if (env->sr & SR_S) { /* SUPERVISOR */
             env->mmu.ssw |= M68K_TM_040_SUPER;
         }
-        if (is_exec) { /* instruction or data */
+        if (access_type == MMU_INST_FETCH) { /* instruction or data */
             env->mmu.ssw |= M68K_TM_040_CODE;
         } else {
             env->mmu.ssw |= M68K_TM_040_DATA;
@@ -479,7 +475,7 @@ void m68k_cpu_unassigned_access(CPUState *cs, hwaddr addr, bool is_write,
             break;
         }
 
-        if (!is_write) {
+        if (access_type != MMU_DATA_STORE) {
             env->mmu.ssw |= M68K_RW_040;
         }
 
diff --git a/target/m68k/translate.c b/target/m68k/translate.c
index 58596278c2..f0534a4ba0 100644
--- a/target/m68k/translate.c
+++ b/target/m68k/translate.c
@@ -2227,6 +2227,7 @@ static TCGv gen_get_sr(DisasContext *s)
     sr = tcg_temp_new();
     tcg_gen_andi_i32(sr, QREG_SR, 0xffe0);
     tcg_gen_or_i32(sr, sr, ccr);
+    tcg_temp_free(ccr);
     return sr;
 }
 
@@ -3020,7 +3021,6 @@ DISAS_INSN(branch)
     int32_t offset;
     uint32_t base;
     int op;
-    TCGLabel *l1;
 
     base = s->pc;
     op = (insn >> 8) & 0xf;
@@ -3036,7 +3036,7 @@ DISAS_INSN(branch)
     }
     if (op > 1) {
         /* Bcc */
-        l1 = gen_new_label();
+        TCGLabel *l1 = gen_new_label();
         gen_jmpcc(s, ((insn >> 8) & 0xf) ^ 1, l1);
         gen_jmp_tb(s, 1, base + offset);
         gen_set_label(l1);
@@ -3693,6 +3693,7 @@ static TCGv rotate_x(TCGv reg, TCGv shift, int left, int size)
         tcg_gen_sub_i32(shl, shl, shift); /* shl = size + 1 - shift */
         tcg_gen_sub_i32(shx, sz, shift); /* shx = size - shift */
     }
+    tcg_temp_free_i32(sz);
 
     /* reg = (reg << shl) | (reg >> shr) | (x << shx); */
 
@@ -3708,9 +3709,7 @@ static TCGv rotate_x(TCGv reg, TCGv shift, int left, int size)
     /* X = (reg >> size) & 1 */
 
     X = tcg_temp_new();
-    tcg_gen_shr_i32(X, reg, sz);
-    tcg_gen_andi_i32(X, X, 1);
-    tcg_temp_free(sz);
+    tcg_gen_extract_i32(X, reg, size, 1);
 
     return X;
 }
diff --git a/target/s390x/Makefile.objs b/target/s390x/Makefile.objs
index 993ac93ed6..0316457880 100644
--- a/target/s390x/Makefile.objs
+++ b/target/s390x/Makefile.objs
@@ -12,7 +12,7 @@ obj-$(call lnot,$(CONFIG_TCG)) += tcg-stub.o
 feat-src = $(SRC_PATH)/target/$(TARGET_BASE_ARCH)/
 feat-dst = $(BUILD_DIR)/$(TARGET_DIR)
 ifneq ($(MAKECMDGOALS),clean)
-GENERATED_FILES += $(feat-dst)gen-features.h
+generated-files-y += $(feat-dst)gen-features.h
 endif
 
 $(feat-dst)gen-features.h: $(feat-dst)gen-features.h-timestamp
diff --git a/target/xtensa/cpu.c b/target/xtensa/cpu.c
index da1236377e..c79dc75bfe 100644
--- a/target/xtensa/cpu.c
+++ b/target/xtensa/cpu.c
@@ -78,11 +78,11 @@ static void xtensa_cpu_reset(CPUState *s)
     env->sregs[VECBASE] = env->config->vecbase;
     env->sregs[IBREAKENABLE] = 0;
     env->sregs[MEMCTL] = MEMCTL_IL0EN & env->config->memctl_mask;
-    env->sregs[CACHEATTR] = 0x22222222;
     env->sregs[ATOMCTL] = xtensa_option_enabled(env->config,
             XTENSA_OPTION_ATOMCTL) ? 0x28 : 0x15;
     env->sregs[CONFIGID0] = env->config->configid[0];
     env->sregs[CONFIGID1] = env->config->configid[1];
+    env->exclusive_addr = -1;
 
 #ifndef CONFIG_USER_ONLY
     reset_mmu(env);
diff --git a/target/xtensa/cpu.h b/target/xtensa/cpu.h
index 68d89f8faf..a0df46f73b 100644
--- a/target/xtensa/cpu.h
+++ b/target/xtensa/cpu.h
@@ -99,6 +99,7 @@ enum {
     /* Memory protection and translation */
     XTENSA_OPTION_REGION_PROTECTION,
     XTENSA_OPTION_REGION_TRANSLATION,
+    XTENSA_OPTION_MPU,
     XTENSA_OPTION_MMU,
     XTENSA_OPTION_CACHEATTR,
 
@@ -137,13 +138,23 @@ enum {
     PTEVADDR = 83,
     MMID = 89,
     RASID = 90,
+    MPUENB = 90,
     ITLBCFG = 91,
     DTLBCFG = 92,
+    MPUCFG = 92,
+    ERACCESS = 95,
     IBREAKENABLE = 96,
     MEMCTL = 97,
     CACHEATTR = 98,
+    CACHEADRDIS = 98,
     ATOMCTL = 99,
     DDR = 104,
+    MEPC = 106,
+    MEPS = 107,
+    MESAVE = 108,
+    MESR = 109,
+    MECR = 110,
+    MEVADDR = 111,
     IBREAKA = 128,
     DBREAKA = 144,
     DBREAKC = 160,
@@ -228,6 +239,7 @@ enum {
 #define MAX_TLB_WAY_SIZE 8
 #define MAX_NDBREAK 2
 #define MAX_NMEMORY 4
+#define MAX_MPU_FOREGROUND_SEGMENTS 32
 
 #define REGION_PAGE_MASK 0xe0000000
 
@@ -268,14 +280,15 @@ enum {
     LEVEL1_INTERRUPT_CAUSE,
     ALLOCA_CAUSE,
     INTEGER_DIVIDE_BY_ZERO_CAUSE,
-    PRIVILEGED_CAUSE = 8,
+    PC_VALUE_ERROR_CAUSE,
+    PRIVILEGED_CAUSE,
     LOAD_STORE_ALIGNMENT_CAUSE,
-
-    INSTR_PIF_DATA_ERROR_CAUSE = 12,
+    EXTERNAL_REG_PRIVILEGE_CAUSE,
+    EXCLUSIVE_ERROR_CAUSE,
+    INSTR_PIF_DATA_ERROR_CAUSE,
     LOAD_STORE_PIF_DATA_ERROR_CAUSE,
     INSTR_PIF_ADDR_ERROR_CAUSE,
     LOAD_STORE_PIF_ADDR_ERROR_CAUSE,
-
     INST_TLB_MISS_CAUSE,
     INST_TLB_MULTI_HIT_CAUSE,
     INST_FETCH_PRIVILEGE_CAUSE,
@@ -298,6 +311,9 @@ typedef enum {
     INTTYPE_DEBUG,
     INTTYPE_WRITE_ERR,
     INTTYPE_PROFILING,
+    INTTYPE_IDMA_DONE,
+    INTTYPE_IDMA_ERR,
+    INTTYPE_GS_ERR,
     INTTYPE_MAX
 } interrupt_type;
 
@@ -318,6 +334,11 @@ typedef struct xtensa_tlb {
     unsigned nrefillentries;
 } xtensa_tlb;
 
+typedef struct xtensa_mpu_entry {
+    uint32_t vaddr;
+    uint32_t attr;
+} xtensa_mpu_entry;
+
 typedef struct XtensaGdbReg {
     int targno;
     unsigned flags;
@@ -446,6 +467,7 @@ struct XtensaConfig {
 
     unsigned icache_ways;
     unsigned dcache_ways;
+    unsigned dcache_line_bytes;
     uint32_t memctl_mask;
 
     XtensaMemory instrom;
@@ -468,6 +490,11 @@ struct XtensaConfig {
 
     xtensa_tlb itlb;
     xtensa_tlb dtlb;
+
+    uint32_t mpu_align;
+    unsigned n_mpu_fg_segments;
+    unsigned n_mpu_bg_segments;
+    const xtensa_mpu_entry *mpu_bg;
 };
 
 typedef struct XtensaConfigList {
@@ -500,10 +527,13 @@ typedef struct CPUXtensaState {
     } fregs[16];
     float_status fp_status;
     uint32_t windowbase_next;
+    uint32_t exclusive_addr;
+    uint32_t exclusive_val;
 
 #ifndef CONFIG_USER_ONLY
     xtensa_tlb_entry itlb[7][MAX_TLB_WAY_SIZE];
     xtensa_tlb_entry dtlb[10][MAX_TLB_WAY_SIZE];
+    xtensa_mpu_entry mpu_fg[MAX_MPU_FOREGROUND_SEGMENTS];
     unsigned autorefill_idx;
     bool runstall;
     AddressSpace *address_space_er;
@@ -590,6 +620,7 @@ void xtensa_cpu_do_unaligned_access(CPUState *cpu, vaddr addr,
 #define XTENSA_DEFAULT_CPU_NOMMU_TYPE \
     XTENSA_CPU_TYPE_NAME(XTENSA_DEFAULT_CPU_NOMMU_MODEL)
 
+void xtensa_collect_sr_names(const XtensaConfig *config);
 void xtensa_translate_init(void);
 void **xtensa_get_regfile_by_name(const char *name);
 void xtensa_breakpoint_handler(CPUState *cs);
@@ -658,17 +689,6 @@ static inline int xtensa_get_cring(const CPUXtensaState *env)
 }
 
 #ifndef CONFIG_USER_ONLY
-uint32_t xtensa_tlb_get_addr_mask(const CPUXtensaState *env,
-                                  bool dtlb, uint32_t way);
-void split_tlb_entry_spec_way(const CPUXtensaState *env, uint32_t v, bool dtlb,
-        uint32_t *vpn, uint32_t wi, uint32_t *ei);
-int xtensa_tlb_lookup(const CPUXtensaState *env, uint32_t addr, bool dtlb,
-        uint32_t *pwi, uint32_t *pei, uint8_t *pring);
-void xtensa_tlb_set_entry_mmu(const CPUXtensaState *env,
-        xtensa_tlb_entry *entry, bool dtlb,
-        unsigned wi, unsigned ei, uint32_t vpn, uint32_t pte);
-void xtensa_tlb_set_entry(CPUXtensaState *env, bool dtlb,
-        unsigned wi, unsigned ei, uint32_t vpn, uint32_t pte);
 int xtensa_get_physical_addr(CPUXtensaState *env, bool update_tlb,
         uint32_t vaddr, int is_write, int mmu_idx,
         uint32_t *paddr, uint32_t *page_size, unsigned *access);
@@ -679,14 +699,6 @@ static inline MemoryRegion *xtensa_get_er_region(CPUXtensaState *env)
 {
     return env->system_er;
 }
-
-static inline xtensa_tlb_entry *xtensa_tlb_get_entry(CPUXtensaState *env,
-        bool dtlb, unsigned wi, unsigned ei)
-{
-    return dtlb ?
-        env->dtlb[wi] + ei :
-        env->itlb[wi] + ei;
-}
 #endif
 
 static inline uint32_t xtensa_replicate_windowstart(CPUXtensaState *env)
diff --git a/target/xtensa/helper.c b/target/xtensa/helper.c
index efb966b3bf..f2d07e4a2f 100644
--- a/target/xtensa/helper.c
+++ b/target/xtensa/helper.c
@@ -141,6 +141,7 @@ static void init_libisa(XtensaConfig *config)
         }
 #endif
     }
+    xtensa_collect_sr_names(config);
 }
 
 static void xtensa_finalize_config(XtensaConfig *config)
diff --git a/target/xtensa/helper.h b/target/xtensa/helper.h
index 0b9ec670c8..8532de0b35 100644
--- a/target/xtensa/helper.h
+++ b/target/xtensa/helper.h
@@ -24,6 +24,7 @@ DEF_HELPER_1(check_interrupts, void, env)
 DEF_HELPER_2(intset, void, env, i32)
 DEF_HELPER_2(intclear, void, env, i32)
 DEF_HELPER_3(check_atomctl, void, env, i32, i32)
+DEF_HELPER_4(check_exclusive, void, env, i32, i32, i32)
 DEF_HELPER_2(wsr_memctl, void, env, i32)
 
 DEF_HELPER_2(itlb_hit_test, void, env, i32)
@@ -33,6 +34,11 @@ DEF_HELPER_FLAGS_3(rtlb1, TCG_CALL_NO_RWG_SE, i32, env, i32, i32)
 DEF_HELPER_3(itlb, void, env, i32, i32)
 DEF_HELPER_3(ptlb, i32, env, i32, i32)
 DEF_HELPER_4(wtlb, void, env, i32, i32, i32)
+DEF_HELPER_2(wsr_mpuenb, void, env, i32)
+DEF_HELPER_3(wptlb, void, env, i32, i32)
+DEF_HELPER_FLAGS_2(rptlb0, TCG_CALL_NO_RWG_SE, i32, env, i32)
+DEF_HELPER_FLAGS_2(rptlb1, TCG_CALL_NO_RWG_SE, i32, env, i32)
+DEF_HELPER_2(pptlb, i32, env, i32)
 
 DEF_HELPER_2(wsr_ibreakenable, void, env, i32)
 DEF_HELPER_3(wsr_ibreaka, void, env, i32, i32)
diff --git a/target/xtensa/mmu_helper.c b/target/xtensa/mmu_helper.c
index 79a10da231..cab39f687a 100644
--- a/target/xtensa/mmu_helper.c
+++ b/target/xtensa/mmu_helper.c
@@ -35,6 +35,31 @@
 #include "exec/exec-all.h"
 #include "exec/cpu_ldst.h"
 
+#define XTENSA_MPU_SEGMENT_MASK 0x0000001f
+#define XTENSA_MPU_ACC_RIGHTS_MASK 0x00000f00
+#define XTENSA_MPU_ACC_RIGHTS_SHIFT 8
+#define XTENSA_MPU_MEM_TYPE_MASK 0x001ff000
+#define XTENSA_MPU_MEM_TYPE_SHIFT 12
+#define XTENSA_MPU_ATTR_MASK 0x001fff00
+
+#define XTENSA_MPU_PROBE_B 0x40000000
+#define XTENSA_MPU_PROBE_V 0x80000000
+
+#define XTENSA_MPU_SYSTEM_TYPE_DEVICE 0x0001
+#define XTENSA_MPU_SYSTEM_TYPE_NC     0x0002
+#define XTENSA_MPU_SYSTEM_TYPE_C      0x0003
+#define XTENSA_MPU_SYSTEM_TYPE_MASK   0x0003
+
+#define XTENSA_MPU_TYPE_SYS_C     0x0010
+#define XTENSA_MPU_TYPE_SYS_W     0x0020
+#define XTENSA_MPU_TYPE_SYS_R     0x0040
+#define XTENSA_MPU_TYPE_CPU_C     0x0100
+#define XTENSA_MPU_TYPE_CPU_W     0x0200
+#define XTENSA_MPU_TYPE_CPU_R     0x0400
+#define XTENSA_MPU_TYPE_CPU_CACHE 0x0800
+#define XTENSA_MPU_TYPE_B         0x1000
+#define XTENSA_MPU_TYPE_INT       0x2000
+
 void HELPER(itlb_hit_test)(CPUXtensaState *env, uint32_t vaddr)
 {
     /*
@@ -78,8 +103,8 @@ static uint32_t get_page_size(const CPUXtensaState *env,
 /*!
  * Get bit mask for the virtual address bits translated by the TLB way
  */
-uint32_t xtensa_tlb_get_addr_mask(const CPUXtensaState *env,
-                                  bool dtlb, uint32_t way)
+static uint32_t xtensa_tlb_get_addr_mask(const CPUXtensaState *env,
+                                         bool dtlb, uint32_t way)
 {
     if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
         bool varway56 = dtlb ?
@@ -145,8 +170,9 @@ static uint32_t get_vpn_mask(const CPUXtensaState *env, bool dtlb, uint32_t way)
  * Split virtual address into VPN (with index) and entry index
  * for the given TLB way
  */
-void split_tlb_entry_spec_way(const CPUXtensaState *env, uint32_t v, bool dtlb,
-        uint32_t *vpn, uint32_t wi, uint32_t *ei)
+static void split_tlb_entry_spec_way(const CPUXtensaState *env, uint32_t v,
+                                     bool dtlb, uint32_t *vpn,
+                                     uint32_t wi, uint32_t *ei)
 {
     bool varway56 = dtlb ?
         env->config->dtlb.varway56 :
@@ -213,6 +239,14 @@ static void split_tlb_entry_spec(CPUXtensaState *env, uint32_t v, bool dtlb,
     }
 }
 
+static xtensa_tlb_entry *xtensa_tlb_get_entry(CPUXtensaState *env, bool dtlb,
+                                              unsigned wi, unsigned ei)
+{
+    return dtlb ?
+        env->dtlb[wi] + ei :
+        env->itlb[wi] + ei;
+}
+
 static xtensa_tlb_entry *get_tlb_entry(CPUXtensaState *env,
         uint32_t v, bool dtlb, uint32_t *pwi)
 {
@@ -227,65 +261,10 @@ static xtensa_tlb_entry *get_tlb_entry(CPUXtensaState *env,
     return xtensa_tlb_get_entry(env, dtlb, wi, ei);
 }
 
-uint32_t HELPER(rtlb0)(CPUXtensaState *env, uint32_t v, uint32_t dtlb)
-{
-    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
-        uint32_t wi;
-        const xtensa_tlb_entry *entry = get_tlb_entry(env, v, dtlb, &wi);
-        return (entry->vaddr & get_vpn_mask(env, dtlb, wi)) | entry->asid;
-    } else {
-        return v & REGION_PAGE_MASK;
-    }
-}
-
-uint32_t HELPER(rtlb1)(CPUXtensaState *env, uint32_t v, uint32_t dtlb)
-{
-    const xtensa_tlb_entry *entry = get_tlb_entry(env, v, dtlb, NULL);
-    return entry->paddr | entry->attr;
-}
-
-void HELPER(itlb)(CPUXtensaState *env, uint32_t v, uint32_t dtlb)
-{
-    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
-        uint32_t wi;
-        xtensa_tlb_entry *entry = get_tlb_entry(env, v, dtlb, &wi);
-        if (entry->variable && entry->asid) {
-            tlb_flush_page(CPU(xtensa_env_get_cpu(env)), entry->vaddr);
-            entry->asid = 0;
-        }
-    }
-}
-
-uint32_t HELPER(ptlb)(CPUXtensaState *env, uint32_t v, uint32_t dtlb)
-{
-    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
-        uint32_t wi;
-        uint32_t ei;
-        uint8_t ring;
-        int res = xtensa_tlb_lookup(env, v, dtlb, &wi, &ei, &ring);
-
-        switch (res) {
-        case 0:
-            if (ring >= xtensa_get_ring(env)) {
-                return (v & 0xfffff000) | wi | (dtlb ? 0x10 : 0x8);
-            }
-            break;
-
-        case INST_TLB_MULTI_HIT_CAUSE:
-        case LOAD_STORE_TLB_MULTI_HIT_CAUSE:
-            HELPER(exception_cause_vaddr)(env, env->pc, res, v);
-            break;
-        }
-        return 0;
-    } else {
-        return (v & REGION_PAGE_MASK) | 0x1;
-    }
-}
-
-void xtensa_tlb_set_entry_mmu(const CPUXtensaState *env,
-                              xtensa_tlb_entry *entry, bool dtlb,
-                              unsigned wi, unsigned ei, uint32_t vpn,
-                              uint32_t pte)
+static void xtensa_tlb_set_entry_mmu(const CPUXtensaState *env,
+                                     xtensa_tlb_entry *entry, bool dtlb,
+                                     unsigned wi, unsigned ei, uint32_t vpn,
+                                     uint32_t pte)
 {
     entry->vaddr = vpn;
     entry->paddr = pte & xtensa_tlb_get_addr_mask(env, dtlb, wi);
@@ -293,8 +272,9 @@ void xtensa_tlb_set_entry_mmu(const CPUXtensaState *env,
     entry->attr = pte & 0xf;
 }
 
-void xtensa_tlb_set_entry(CPUXtensaState *env, bool dtlb,
-                          unsigned wi, unsigned ei, uint32_t vpn, uint32_t pte)
+static void xtensa_tlb_set_entry(CPUXtensaState *env, bool dtlb,
+                                 unsigned wi, unsigned ei,
+                                 uint32_t vpn, uint32_t pte)
 {
     XtensaCPU *cpu = xtensa_env_get_cpu(env);
     CPUState *cs = CPU(cpu);
@@ -322,15 +302,6 @@ void xtensa_tlb_set_entry(CPUXtensaState *env, bool dtlb,
     }
 }
 
-void HELPER(wtlb)(CPUXtensaState *env, uint32_t p, uint32_t v, uint32_t dtlb)
-{
-    uint32_t vpn;
-    uint32_t wi;
-    uint32_t ei;
-    split_tlb_entry_spec(env, v, dtlb, &vpn, &wi, &ei);
-    xtensa_tlb_set_entry(env, dtlb, wi, ei, vpn, p);
-}
-
 hwaddr xtensa_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
 {
     XtensaCPU *cpu = XTENSA_CPU(cs);
@@ -436,7 +407,20 @@ void reset_mmu(CPUXtensaState *env)
         reset_tlb_mmu_all_ways(env, &env->config->dtlb, env->dtlb);
         reset_tlb_mmu_ways56(env, &env->config->itlb, env->itlb);
         reset_tlb_mmu_ways56(env, &env->config->dtlb, env->dtlb);
+    } else if (xtensa_option_enabled(env->config, XTENSA_OPTION_MPU)) {
+        unsigned i;
+
+        env->sregs[MPUENB] = 0;
+        env->sregs[MPUCFG] = env->config->n_mpu_fg_segments;
+        env->sregs[CACHEADRDIS] = 0;
+        assert(env->config->n_mpu_bg_segments > 0 &&
+               env->config->mpu_bg[0].vaddr == 0);
+        for (i = 1; i < env->config->n_mpu_bg_segments; ++i) {
+            assert(env->config->mpu_bg[i].vaddr >=
+                   env->config->mpu_bg[i - 1].vaddr);
+        }
     } else {
+        env->sregs[CACHEATTR] = 0x22222222;
         reset_tlb_region_way0(env, env->itlb);
         reset_tlb_region_way0(env, env->dtlb);
     }
@@ -462,8 +446,9 @@ static unsigned get_ring(const CPUXtensaState *env, uint8_t asid)
  * \param pring: [out] access ring
  * \return 0 if ok, exception cause code otherwise
  */
-int xtensa_tlb_lookup(const CPUXtensaState *env, uint32_t addr, bool dtlb,
-                      uint32_t *pwi, uint32_t *pei, uint8_t *pring)
+static int xtensa_tlb_lookup(const CPUXtensaState *env,
+                             uint32_t addr, bool dtlb,
+                             uint32_t *pwi, uint32_t *pei, uint8_t *pring)
 {
     const xtensa_tlb *tlb = dtlb ?
         &env->config->dtlb : &env->config->itlb;
@@ -495,6 +480,70 @@ int xtensa_tlb_lookup(const CPUXtensaState *env, uint32_t addr, bool dtlb,
         (dtlb ? LOAD_STORE_TLB_MISS_CAUSE : INST_TLB_MISS_CAUSE);
 }
 
+uint32_t HELPER(rtlb0)(CPUXtensaState *env, uint32_t v, uint32_t dtlb)
+{
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
+        uint32_t wi;
+        const xtensa_tlb_entry *entry = get_tlb_entry(env, v, dtlb, &wi);
+        return (entry->vaddr & get_vpn_mask(env, dtlb, wi)) | entry->asid;
+    } else {
+        return v & REGION_PAGE_MASK;
+    }
+}
+
+uint32_t HELPER(rtlb1)(CPUXtensaState *env, uint32_t v, uint32_t dtlb)
+{
+    const xtensa_tlb_entry *entry = get_tlb_entry(env, v, dtlb, NULL);
+    return entry->paddr | entry->attr;
+}
+
+void HELPER(itlb)(CPUXtensaState *env, uint32_t v, uint32_t dtlb)
+{
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
+        uint32_t wi;
+        xtensa_tlb_entry *entry = get_tlb_entry(env, v, dtlb, &wi);
+        if (entry->variable && entry->asid) {
+            tlb_flush_page(CPU(xtensa_env_get_cpu(env)), entry->vaddr);
+            entry->asid = 0;
+        }
+    }
+}
+
+uint32_t HELPER(ptlb)(CPUXtensaState *env, uint32_t v, uint32_t dtlb)
+{
+    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
+        uint32_t wi;
+        uint32_t ei;
+        uint8_t ring;
+        int res = xtensa_tlb_lookup(env, v, dtlb, &wi, &ei, &ring);
+
+        switch (res) {
+        case 0:
+            if (ring >= xtensa_get_ring(env)) {
+                return (v & 0xfffff000) | wi | (dtlb ? 0x10 : 0x8);
+            }
+            break;
+
+        case INST_TLB_MULTI_HIT_CAUSE:
+        case LOAD_STORE_TLB_MULTI_HIT_CAUSE:
+            HELPER(exception_cause_vaddr)(env, env->pc, res, v);
+            break;
+        }
+        return 0;
+    } else {
+        return (v & REGION_PAGE_MASK) | 0x1;
+    }
+}
+
+void HELPER(wtlb)(CPUXtensaState *env, uint32_t p, uint32_t v, uint32_t dtlb)
+{
+    uint32_t vpn;
+    uint32_t wi;
+    uint32_t ei;
+    split_tlb_entry_spec(env, v, dtlb, &vpn, &wi, &ei);
+    xtensa_tlb_set_entry(env, dtlb, wi, ei, vpn, p);
+}
+
 /*!
  * Convert MMU ATTR to PAGE_{READ,WRITE,EXEC} mask.
  * See ISA, 4.6.5.10
@@ -568,6 +617,149 @@ static unsigned cacheattr_attr_to_access(uint32_t attr)
     return access[attr & 0xf];
 }
 
+struct attr_pattern {
+    uint32_t mask;
+    uint32_t value;
+};
+
+static int attr_pattern_match(uint32_t attr,
+                              const struct attr_pattern *pattern,
+                              size_t n)
+{
+    size_t i;
+
+    for (i = 0; i < n; ++i) {
+        if ((attr & pattern[i].mask) == pattern[i].value) {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+static unsigned mpu_attr_to_cpu_cache(uint32_t attr)
+{
+    static const struct attr_pattern cpu_c[] = {
+        { .mask = 0x18f, .value = 0x089 },
+        { .mask = 0x188, .value = 0x080 },
+        { .mask = 0x180, .value = 0x180 },
+    };
+
+    unsigned type = 0;
+
+    if (attr_pattern_match(attr, cpu_c, ARRAY_SIZE(cpu_c))) {
+        type |= XTENSA_MPU_TYPE_CPU_CACHE;
+        if (attr & 0x10) {
+            type |= XTENSA_MPU_TYPE_CPU_C;
+        }
+        if (attr & 0x20) {
+            type |= XTENSA_MPU_TYPE_CPU_W;
+        }
+        if (attr & 0x40) {
+            type |= XTENSA_MPU_TYPE_CPU_R;
+        }
+    }
+    return type;
+}
+
+static unsigned mpu_attr_to_type(uint32_t attr)
+{
+    static const struct attr_pattern device_type[] = {
+        { .mask = 0x1f6, .value = 0x000 },
+        { .mask = 0x1f6, .value = 0x006 },
+    };
+    static const struct attr_pattern sys_nc_type[] = {
+        { .mask = 0x1fe, .value = 0x018 },
+        { .mask = 0x1fe, .value = 0x01e },
+        { .mask = 0x18f, .value = 0x089 },
+    };
+    static const struct attr_pattern sys_c_type[] = {
+        { .mask = 0x1f8, .value = 0x010 },
+        { .mask = 0x188, .value = 0x080 },
+        { .mask = 0x1f0, .value = 0x030 },
+        { .mask = 0x180, .value = 0x180 },
+    };
+    static const struct attr_pattern b[] = {
+        { .mask = 0x1f7, .value = 0x001 },
+        { .mask = 0x1f7, .value = 0x007 },
+        { .mask = 0x1ff, .value = 0x019 },
+        { .mask = 0x1ff, .value = 0x01f },
+    };
+
+    unsigned type = 0;
+
+    attr = (attr & XTENSA_MPU_MEM_TYPE_MASK) >> XTENSA_MPU_MEM_TYPE_SHIFT;
+    if (attr_pattern_match(attr, device_type, ARRAY_SIZE(device_type))) {
+        type |= XTENSA_MPU_SYSTEM_TYPE_DEVICE;
+        if (attr & 0x80) {
+            type |= XTENSA_MPU_TYPE_INT;
+        }
+    }
+    if (attr_pattern_match(attr, sys_nc_type, ARRAY_SIZE(sys_nc_type))) {
+        type |= XTENSA_MPU_SYSTEM_TYPE_NC;
+    }
+    if (attr_pattern_match(attr, sys_c_type, ARRAY_SIZE(sys_c_type))) {
+        type |= XTENSA_MPU_SYSTEM_TYPE_C;
+        if (attr & 0x1) {
+            type |= XTENSA_MPU_TYPE_SYS_C;
+        }
+        if (attr & 0x2) {
+            type |= XTENSA_MPU_TYPE_SYS_W;
+        }
+        if (attr & 0x4) {
+            type |= XTENSA_MPU_TYPE_SYS_R;
+        }
+    }
+    if (attr_pattern_match(attr, b, ARRAY_SIZE(b))) {
+        type |= XTENSA_MPU_TYPE_B;
+    }
+    type |= mpu_attr_to_cpu_cache(attr);
+
+    return type;
+}
+
+static unsigned mpu_attr_to_access(uint32_t attr, unsigned ring)
+{
+    static const unsigned access[2][16] = {
+        [0] = {
+             [4] = PAGE_READ,
+             [5] = PAGE_READ              | PAGE_EXEC,
+             [6] = PAGE_READ | PAGE_WRITE,
+             [7] = PAGE_READ | PAGE_WRITE | PAGE_EXEC,
+             [8] =             PAGE_WRITE,
+             [9] = PAGE_READ | PAGE_WRITE,
+            [10] = PAGE_READ | PAGE_WRITE,
+            [11] = PAGE_READ | PAGE_WRITE | PAGE_EXEC,
+            [12] = PAGE_READ,
+            [13] = PAGE_READ              | PAGE_EXEC,
+            [14] = PAGE_READ | PAGE_WRITE,
+            [15] = PAGE_READ | PAGE_WRITE | PAGE_EXEC,
+        },
+        [1] = {
+             [8] =             PAGE_WRITE,
+             [9] = PAGE_READ | PAGE_WRITE | PAGE_EXEC,
+            [10] = PAGE_READ,
+            [11] = PAGE_READ              | PAGE_EXEC,
+            [12] = PAGE_READ,
+            [13] = PAGE_READ              | PAGE_EXEC,
+            [14] = PAGE_READ | PAGE_WRITE,
+            [15] = PAGE_READ | PAGE_WRITE | PAGE_EXEC,
+        },
+    };
+    unsigned rv;
+    unsigned type;
+
+    type = mpu_attr_to_cpu_cache(attr);
+    rv = access[ring != 0][(attr & XTENSA_MPU_ACC_RIGHTS_MASK) >>
+        XTENSA_MPU_ACC_RIGHTS_SHIFT];
+
+    if (type & XTENSA_MPU_TYPE_CPU_CACHE) {
+        rv |= (type & XTENSA_MPU_TYPE_CPU_C) ? PAGE_CACHE_WB : PAGE_CACHE_WT;
+    } else {
+        rv |= PAGE_CACHE_BYPASS;
+    }
+    return rv;
+}
+
 static bool is_access_granted(unsigned access, int is_write)
 {
     switch (is_write) {
@@ -712,6 +904,129 @@ static int get_physical_addr_region(CPUXtensaState *env,
     return 0;
 }
 
+static int xtensa_mpu_lookup(const xtensa_mpu_entry *entry, unsigned n,
+                             uint32_t vaddr, unsigned *segment)
+{
+    unsigned nhits = 0;
+    unsigned i;
+
+    for (i = 0; i < n; ++i) {
+        if (vaddr >= entry[i].vaddr &&
+            (i == n - 1 || vaddr < entry[i + 1].vaddr)) {
+            if (nhits++) {
+                break;
+            }
+            *segment = i;
+        }
+    }
+    return nhits;
+}
+
+void HELPER(wsr_mpuenb)(CPUXtensaState *env, uint32_t v)
+{
+    XtensaCPU *cpu = xtensa_env_get_cpu(env);
+
+    v &= (2u << (env->config->n_mpu_fg_segments - 1)) - 1;
+
+    if (v != env->sregs[MPUENB]) {
+        env->sregs[MPUENB] = v;
+        tlb_flush(CPU(cpu));
+    }
+}
+
+void HELPER(wptlb)(CPUXtensaState *env, uint32_t p, uint32_t v)
+{
+    unsigned segment = p & XTENSA_MPU_SEGMENT_MASK;
+
+    if (segment < env->config->n_mpu_fg_segments) {
+        env->mpu_fg[segment].vaddr = v & -env->config->mpu_align;
+        env->mpu_fg[segment].attr = p & XTENSA_MPU_ATTR_MASK;
+        env->sregs[MPUENB] = deposit32(env->sregs[MPUENB], segment, 1, v);
+        tlb_flush(CPU(xtensa_env_get_cpu(env)));
+    }
+}
+
+uint32_t HELPER(rptlb0)(CPUXtensaState *env, uint32_t s)
+{
+    unsigned segment = s & XTENSA_MPU_SEGMENT_MASK;
+
+    if (segment < env->config->n_mpu_fg_segments) {
+        return env->mpu_fg[segment].vaddr |
+            extract32(env->sregs[MPUENB], segment, 1);
+    } else {
+        return 0;
+    }
+}
+
+uint32_t HELPER(rptlb1)(CPUXtensaState *env, uint32_t s)
+{
+    unsigned segment = s & XTENSA_MPU_SEGMENT_MASK;
+
+    if (segment < env->config->n_mpu_fg_segments) {
+        return env->mpu_fg[segment].attr;
+    } else {
+        return 0;
+    }
+}
+
+uint32_t HELPER(pptlb)(CPUXtensaState *env, uint32_t v)
+{
+    unsigned nhits;
+    unsigned segment = XTENSA_MPU_PROBE_B;
+    unsigned bg_segment;
+
+    nhits = xtensa_mpu_lookup(env->mpu_fg, env->config->n_mpu_fg_segments,
+                              v, &segment);
+    if (nhits > 1) {
+        HELPER(exception_cause_vaddr)(env, env->pc,
+                                      LOAD_STORE_TLB_MULTI_HIT_CAUSE, v);
+    } else if (nhits == 1 && (env->sregs[MPUENB] & (1u << segment))) {
+        return env->mpu_fg[segment].attr | segment | XTENSA_MPU_PROBE_V;
+    } else {
+        xtensa_mpu_lookup(env->config->mpu_bg,
+                          env->config->n_mpu_bg_segments,
+                          v, &bg_segment);
+        return env->config->mpu_bg[bg_segment].attr | segment;
+    }
+}
+
+static int get_physical_addr_mpu(CPUXtensaState *env,
+                                 uint32_t vaddr, int is_write, int mmu_idx,
+                                 uint32_t *paddr, uint32_t *page_size,
+                                 unsigned *access)
+{
+    unsigned nhits;
+    unsigned segment;
+    uint32_t attr;
+
+    nhits = xtensa_mpu_lookup(env->mpu_fg, env->config->n_mpu_fg_segments,
+                              vaddr, &segment);
+    if (nhits > 1) {
+        return is_write < 2 ?
+            LOAD_STORE_TLB_MULTI_HIT_CAUSE :
+            INST_TLB_MULTI_HIT_CAUSE;
+    } else if (nhits == 1 && (env->sregs[MPUENB] & (1u << segment))) {
+        attr = env->mpu_fg[segment].attr;
+    } else {
+        xtensa_mpu_lookup(env->config->mpu_bg,
+                          env->config->n_mpu_bg_segments,
+                          vaddr, &segment);
+        attr = env->config->mpu_bg[segment].attr;
+    }
+
+    *access = mpu_attr_to_access(attr, mmu_idx);
+    if (!is_access_granted(*access, is_write)) {
+        return is_write < 2 ?
+            (is_write ?
+             STORE_PROHIBITED_CAUSE :
+             LOAD_PROHIBITED_CAUSE) :
+            INST_FETCH_PROHIBITED_CAUSE;
+    }
+    *paddr = vaddr;
+    *page_size = env->config->mpu_align;
+    return 0;
+}
+
 /*!
  * Convert virtual address to physical addr.
  * MMU may issue pagewalk and change xtensa autorefill TLB way entry.
@@ -732,6 +1047,9 @@ int xtensa_get_physical_addr(CPUXtensaState *env, bool update_tlb,
                 XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_TRANSLATION))) {
         return get_physical_addr_region(env, vaddr, is_write, mmu_idx,
                                         paddr, page_size, access);
+    } else if (xtensa_option_enabled(env->config, XTENSA_OPTION_MPU)) {
+        return get_physical_addr_mpu(env, vaddr, is_write, mmu_idx,
+                                     paddr, page_size, access);
     } else {
         *paddr = vaddr;
         *page_size = TARGET_PAGE_SIZE;
@@ -799,6 +1117,63 @@ static void dump_tlb(CPUXtensaState *env, bool dtlb)
     }
 }
 
+static void dump_mpu(CPUXtensaState *env,
+                     const xtensa_mpu_entry *entry, unsigned n)
+{
+    unsigned i;
+
+    qemu_printf("\t%s  Vaddr       Attr        Ring0  Ring1  System Type    CPU cache\n"
+                "\t%s  ----------  ----------  -----  -----  -------------  ---------\n",
+                env ? "En" : "  ",
+                env ? "--" : "  ");
+
+    for (i = 0; i < n; ++i) {
+        uint32_t attr = entry[i].attr;
+        unsigned access0 = mpu_attr_to_access(attr, 0);
+        unsigned access1 = mpu_attr_to_access(attr, 1);
+        unsigned type = mpu_attr_to_type(attr);
+        char cpu_cache = (type & XTENSA_MPU_TYPE_CPU_CACHE) ? '-' : ' ';
+
+        qemu_printf("\t %c  0x%08x  0x%08x   %c%c%c    %c%c%c   ",
+                    env ?
+                    ((env->sregs[MPUENB] & (1u << i)) ? '+' : '-') : ' ',
+                    entry[i].vaddr, attr,
+                    (access0 & PAGE_READ) ? 'R' : '-',
+                    (access0 & PAGE_WRITE) ? 'W' : '-',
+                    (access0 & PAGE_EXEC) ? 'X' : '-',
+                    (access1 & PAGE_READ) ? 'R' : '-',
+                    (access1 & PAGE_WRITE) ? 'W' : '-',
+                    (access1 & PAGE_EXEC) ? 'X' : '-');
+
+        switch (type & XTENSA_MPU_SYSTEM_TYPE_MASK) {
+        case XTENSA_MPU_SYSTEM_TYPE_DEVICE:
+            qemu_printf("Device %cB %3s\n",
+                        (type & XTENSA_MPU_TYPE_B) ? ' ' : 'n',
+                        (type & XTENSA_MPU_TYPE_INT) ? "int" : "");
+            break;
+        case XTENSA_MPU_SYSTEM_TYPE_NC:
+            qemu_printf("Sys NC %cB      %c%c%c\n",
+                        (type & XTENSA_MPU_TYPE_B) ? ' ' : 'n',
+                        (type & XTENSA_MPU_TYPE_CPU_R) ? 'r' : cpu_cache,
+                        (type & XTENSA_MPU_TYPE_CPU_W) ? 'w' : cpu_cache,
+                        (type & XTENSA_MPU_TYPE_CPU_C) ? 'c' : cpu_cache);
+            break;
+        case XTENSA_MPU_SYSTEM_TYPE_C:
+            qemu_printf("Sys  C %c%c%c     %c%c%c\n",
+                        (type & XTENSA_MPU_TYPE_SYS_R) ? 'R' : '-',
+                        (type & XTENSA_MPU_TYPE_SYS_W) ? 'W' : '-',
+                        (type & XTENSA_MPU_TYPE_SYS_C) ? 'C' : '-',
+                        (type & XTENSA_MPU_TYPE_CPU_R) ? 'r' : cpu_cache,
+                        (type & XTENSA_MPU_TYPE_CPU_W) ? 'w' : cpu_cache,
+                        (type & XTENSA_MPU_TYPE_CPU_C) ? 'c' : cpu_cache);
+            break;
+        default:
+            qemu_printf("Unknown\n");
+            break;
+        }
+    }
+}
+
 void dump_mmu(CPUXtensaState *env)
 {
     if (xtensa_option_bits_enabled(env->config,
@@ -810,6 +1185,11 @@ void dump_mmu(CPUXtensaState *env)
         dump_tlb(env, false);
         qemu_printf("\nDTLB:\n");
         dump_tlb(env, true);
+    } else if (xtensa_option_enabled(env->config, XTENSA_OPTION_MPU)) {
+        qemu_printf("Foreground map:\n");
+        dump_mpu(env, env->mpu_fg, env->config->n_mpu_fg_segments);
+        qemu_printf("\nBackground map:\n");
+        dump_mpu(NULL, env->config->mpu_bg, env->config->n_mpu_bg_segments);
     } else {
         qemu_printf("No TLB for this CPU core\n");
     }
diff --git a/target/xtensa/op_helper.c b/target/xtensa/op_helper.c
index 04971b044f..09f4962d00 100644
--- a/target/xtensa/op_helper.c
+++ b/target/xtensa/op_helper.c
@@ -130,6 +130,48 @@ void HELPER(check_atomctl)(CPUXtensaState *env, uint32_t pc, uint32_t vaddr)
     }
 }
 
+void HELPER(check_exclusive)(CPUXtensaState *env, uint32_t pc, uint32_t vaddr,
+                             uint32_t is_write)
+{
+    uint32_t paddr, page_size, access;
+    uint32_t atomctl = env->sregs[ATOMCTL];
+    int rc = xtensa_get_physical_addr(env, true, vaddr, is_write,
+                                      xtensa_get_cring(env), &paddr,
+                                      &page_size, &access);
+
+    if (rc) {
+        HELPER(exception_cause_vaddr)(env, pc, rc, vaddr);
+    }
+
+    /* When data cache is not configured use ATOMCTL bypass field. */
+    if (!xtensa_option_enabled(env->config, XTENSA_OPTION_DCACHE)) {
+        access = PAGE_CACHE_BYPASS;
+    }
+
+    switch (access & PAGE_CACHE_MASK) {
+    case PAGE_CACHE_WB:
+        atomctl >>= 2;
+        /* fall through */
+    case PAGE_CACHE_WT:
+        atomctl >>= 2;
+        /* fall through */
+    case PAGE_CACHE_BYPASS:
+        if ((atomctl & 0x3) == 0) {
+            HELPER(exception_cause_vaddr)(env, pc,
+                                          EXCLUSIVE_ERROR_CAUSE, vaddr);
+        }
+        break;
+
+    case PAGE_CACHE_ISOLATE:
+        HELPER(exception_cause_vaddr)(env, pc,
+                LOAD_STORE_ERROR_CAUSE, vaddr);
+        break;
+
+    default:
+        break;
+    }
+}
+
 void HELPER(wsr_memctl)(CPUXtensaState *env, uint32_t v)
 {
     if (xtensa_option_enabled(env->config, XTENSA_OPTION_ICACHE)) {
diff --git a/target/xtensa/overlay_tool.h b/target/xtensa/overlay_tool.h
index ea07576bc9..f0cc33adfe 100644
--- a/target/xtensa/overlay_tool.h
+++ b/target/xtensa/overlay_tool.h
@@ -72,6 +72,14 @@
 #define XCHAL_HAVE_EXTERN_REGS 0
 #endif
 
+#ifndef XCHAL_HAVE_MPU
+#define XCHAL_HAVE_MPU 0
+#endif
+
+#ifndef XCHAL_HAVE_EXCLUSIVE
+#define XCHAL_HAVE_EXCLUSIVE 0
+#endif
+
 #define XCHAL_OPTION(xchal, qemu) ((xchal) ? XTENSA_OPTION_BIT(qemu) : 0)
 
 #define XTENSA_OPTIONS ( \
@@ -92,8 +100,8 @@
     XCHAL_OPTION(XCHAL_HAVE_FP, XTENSA_OPTION_FP_COPROCESSOR) | \
     XCHAL_OPTION(XCHAL_HAVE_RELEASE_SYNC, XTENSA_OPTION_MP_SYNCHRO) | \
     XCHAL_OPTION(XCHAL_HAVE_S32C1I, XTENSA_OPTION_CONDITIONAL_STORE) | \
-    XCHAL_OPTION(XCHAL_HAVE_S32C1I && XCHAL_HW_MIN_VERSION >= 230000, \
-        XTENSA_OPTION_ATOMCTL) | \
+    XCHAL_OPTION(((XCHAL_HAVE_S32C1I && XCHAL_HW_MIN_VERSION >= 230000) || \
+                  XCHAL_HAVE_EXCLUSIVE), XTENSA_OPTION_ATOMCTL) | \
     XCHAL_OPTION(XCHAL_HAVE_DEPBITS, XTENSA_OPTION_DEPBITS) | \
     /* Interrupts and exceptions */ \
     XCHAL_OPTION(XCHAL_HAVE_EXCEPTIONS, XTENSA_OPTION_EXCEPTION) | \
@@ -112,11 +120,14 @@
     XCHAL_OPTION(XCHAL_DCACHE_LINE_LOCKABLE, \
             XTENSA_OPTION_DCACHE_INDEX_LOCK) | \
     XCHAL_OPTION(XCHAL_UNALIGNED_LOAD_HW, XTENSA_OPTION_HW_ALIGNMENT) | \
+    XCHAL_OPTION(XCHAL_HAVE_MEM_ECC_PARITY, \
+                 XTENSA_OPTION_MEMORY_ECC_PARITY) | \
     /* Memory protection and translation */ \
     XCHAL_OPTION(XCHAL_HAVE_MIMIC_CACHEATTR, \
             XTENSA_OPTION_REGION_PROTECTION) | \
     XCHAL_OPTION(XCHAL_HAVE_XLT_CACHEATTR, \
             XTENSA_OPTION_REGION_TRANSLATION) | \
+    XCHAL_OPTION(XCHAL_HAVE_MPU, XTENSA_OPTION_MPU) | \
     XCHAL_OPTION(XCHAL_HAVE_PTP_MMU, XTENSA_OPTION_MMU) | \
     XCHAL_OPTION(XCHAL_HAVE_CACHEATTR, XTENSA_OPTION_CACHEATTR) | \
     /* Other, TODO */ \
@@ -200,6 +211,9 @@
 #define XTHAL_INTTYPE_TBD2 INTTYPE_WRITE_ERR
 #define XTHAL_INTTYPE_WRITE_ERROR INTTYPE_WRITE_ERR
 #define XTHAL_INTTYPE_PROFILING INTTYPE_PROFILING
+#define XTHAL_INTTYPE_IDMA_DONE INTTYPE_IDMA_DONE
+#define XTHAL_INTTYPE_IDMA_ERR INTTYPE_IDMA_ERR
+#define XTHAL_INTTYPE_GS_ERR INTTYPE_GS_ERR
 
 
 #define INTERRUPT(i) { \
@@ -356,6 +370,30 @@
 #define XCHAL_SYSRAM0_SIZE  0x04000000
 #endif
 
+#elif XCHAL_HAVE_MPU
+
+#ifndef XTENSA_MPU_BG_MAP
+#define XTENSA_MPU_BG_MAP (xtensa_mpu_entry []){\
+    { .vaddr = 0, .attr = 0x00006700, }, \
+}
+#endif
+
+#define TLB_SECTION \
+    .mpu_align = XCHAL_MPU_ALIGN, \
+    .n_mpu_fg_segments = XCHAL_MPU_ENTRIES, \
+    .n_mpu_bg_segments = 1, \
+    .mpu_bg = XTENSA_MPU_BG_MAP
+
+#ifndef XCHAL_SYSROM0_PADDR
+#define XCHAL_SYSROM0_PADDR 0x50000000
+#define XCHAL_SYSROM0_SIZE  0x04000000
+#endif
+
+#ifndef XCHAL_SYSRAM0_PADDR
+#define XCHAL_SYSRAM0_PADDR 0x60000000
+#define XCHAL_SYSRAM0_SIZE  0x04000000
+#endif
+
 #else
 
 #ifndef XCHAL_SYSROM0_PADDR
@@ -391,6 +429,7 @@
 #define CACHE_SECTION \
     .icache_ways = XCHAL_ICACHE_WAYS, \
     .dcache_ways = XCHAL_DCACHE_WAYS, \
+    .dcache_line_bytes = XCHAL_DCACHE_LINESIZE, \
     .memctl_mask = \
         (XCHAL_ICACHE_SIZE ? MEMCTL_IUSEWAYS_MASK : 0) | \
         (XCHAL_DCACHE_SIZE ? \
diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c
index b063fa85f2..53dce470c1 100644
--- a/target/xtensa/translate.c
+++ b/target/xtensa/translate.c
@@ -87,133 +87,47 @@ static TCGv_i32 cpu_BR8[2];
 static TCGv_i32 cpu_SR[256];
 static TCGv_i32 cpu_UR[256];
 static TCGv_i32 cpu_windowbase_next;
+static TCGv_i32 cpu_exclusive_addr;
+static TCGv_i32 cpu_exclusive_val;
 
 static GHashTable *xtensa_regfile_table;
 
 #include "exec/gen-icount.h"
 
-typedef struct XtensaReg {
-    const char *name;
-    uint64_t opt_bits;
-    enum {
-        SR_R = 1,
-        SR_W = 2,
-        SR_X = 4,
-        SR_RW = 3,
-        SR_RWX = 7,
-    } access;
-} XtensaReg;
-
-#define XTENSA_REG_ACCESS(regname, opt, acc) { \
-        .name = (regname), \
-        .opt_bits = XTENSA_OPTION_BIT(opt), \
-        .access = (acc), \
-    }
+static char *sr_name[256];
+static char *ur_name[256];
 
-#define XTENSA_REG(regname, opt) XTENSA_REG_ACCESS(regname, opt, SR_RWX)
+void xtensa_collect_sr_names(const XtensaConfig *config)
+{
+    xtensa_isa isa = config->isa;
+    int n = xtensa_isa_num_sysregs(isa);
+    int i;
 
-#define XTENSA_REG_BITS_ACCESS(regname, opt, acc) { \
-        .name = (regname), \
-        .opt_bits = (opt), \
-        .access = (acc), \
+    for (i = 0; i < n; ++i) {
+        int sr = xtensa_sysreg_number(isa, i);
+
+        if (sr >= 0 && sr < 256) {
+            const char *name = xtensa_sysreg_name(isa, i);
+            char **pname =
+                (xtensa_sysreg_is_user(isa, i) ? ur_name : sr_name) + sr;
+
+            if (*pname) {
+                if (strstr(*pname, name) == NULL) {
+                    char *new_name =
+                        malloc(strlen(*pname) + strlen(name) + 2);
+
+                    strcpy(new_name, *pname);
+                    strcat(new_name, "/");
+                    strcat(new_name, name);
+                    free(*pname);
+                    *pname = new_name;
+                }
+            } else {
+                *pname = strdup(name);
+            }
+        }
     }
-
-#define XTENSA_REG_BITS(regname, opt) \
-    XTENSA_REG_BITS_ACCESS(regname, opt, SR_RWX)
-
-static const XtensaReg sregnames[256] = {
-    [LBEG] = XTENSA_REG("LBEG", XTENSA_OPTION_LOOP),
-    [LEND] = XTENSA_REG("LEND", XTENSA_OPTION_LOOP),
-    [LCOUNT] = XTENSA_REG("LCOUNT", XTENSA_OPTION_LOOP),
-    [SAR] = XTENSA_REG_BITS("SAR", XTENSA_OPTION_ALL),
-    [BR] = XTENSA_REG("BR", XTENSA_OPTION_BOOLEAN),
-    [LITBASE] = XTENSA_REG("LITBASE", XTENSA_OPTION_EXTENDED_L32R),
-    [SCOMPARE1] = XTENSA_REG("SCOMPARE1", XTENSA_OPTION_CONDITIONAL_STORE),
-    [ACCLO] = XTENSA_REG("ACCLO", XTENSA_OPTION_MAC16),
-    [ACCHI] = XTENSA_REG("ACCHI", XTENSA_OPTION_MAC16),
-    [MR] = XTENSA_REG("MR0", XTENSA_OPTION_MAC16),
-    [MR + 1] = XTENSA_REG("MR1", XTENSA_OPTION_MAC16),
-    [MR + 2] = XTENSA_REG("MR2", XTENSA_OPTION_MAC16),
-    [MR + 3] = XTENSA_REG("MR3", XTENSA_OPTION_MAC16),
-    [PREFCTL] = XTENSA_REG_BITS("PREFCTL", XTENSA_OPTION_ALL),
-    [WINDOW_BASE] = XTENSA_REG("WINDOW_BASE", XTENSA_OPTION_WINDOWED_REGISTER),
-    [WINDOW_START] = XTENSA_REG("WINDOW_START",
-            XTENSA_OPTION_WINDOWED_REGISTER),
-    [PTEVADDR] = XTENSA_REG("PTEVADDR", XTENSA_OPTION_MMU),
-    [MMID] = XTENSA_REG_BITS("MMID", XTENSA_OPTION_ALL),
-    [RASID] = XTENSA_REG("RASID", XTENSA_OPTION_MMU),
-    [ITLBCFG] = XTENSA_REG("ITLBCFG", XTENSA_OPTION_MMU),
-    [DTLBCFG] = XTENSA_REG("DTLBCFG", XTENSA_OPTION_MMU),
-    [IBREAKENABLE] = XTENSA_REG("IBREAKENABLE", XTENSA_OPTION_DEBUG),
-    [MEMCTL] = XTENSA_REG_BITS("MEMCTL", XTENSA_OPTION_ALL),
-    [CACHEATTR] = XTENSA_REG("CACHEATTR", XTENSA_OPTION_CACHEATTR),
-    [ATOMCTL] = XTENSA_REG("ATOMCTL", XTENSA_OPTION_ATOMCTL),
-    [DDR] = XTENSA_REG("DDR", XTENSA_OPTION_DEBUG),
-    [IBREAKA] = XTENSA_REG("IBREAKA0", XTENSA_OPTION_DEBUG),
-    [IBREAKA + 1] = XTENSA_REG("IBREAKA1", XTENSA_OPTION_DEBUG),
-    [DBREAKA] = XTENSA_REG("DBREAKA0", XTENSA_OPTION_DEBUG),
-    [DBREAKA + 1] = XTENSA_REG("DBREAKA1", XTENSA_OPTION_DEBUG),
-    [DBREAKC] = XTENSA_REG("DBREAKC0", XTENSA_OPTION_DEBUG),
-    [DBREAKC + 1] = XTENSA_REG("DBREAKC1", XTENSA_OPTION_DEBUG),
-    [CONFIGID0] = XTENSA_REG_BITS_ACCESS("CONFIGID0", XTENSA_OPTION_ALL, SR_R),
-    [EPC1] = XTENSA_REG("EPC1", XTENSA_OPTION_EXCEPTION),
-    [EPC1 + 1] = XTENSA_REG("EPC2", XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT),
-    [EPC1 + 2] = XTENSA_REG("EPC3", XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT),
-    [EPC1 + 3] = XTENSA_REG("EPC4", XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT),
-    [EPC1 + 4] = XTENSA_REG("EPC5", XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT),
-    [EPC1 + 5] = XTENSA_REG("EPC6", XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT),
-    [EPC1 + 6] = XTENSA_REG("EPC7", XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT),
-    [DEPC] = XTENSA_REG("DEPC", XTENSA_OPTION_EXCEPTION),
-    [EPS2] = XTENSA_REG("EPS2", XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT),
-    [EPS2 + 1] = XTENSA_REG("EPS3", XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT),
-    [EPS2 + 2] = XTENSA_REG("EPS4", XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT),
-    [EPS2 + 3] = XTENSA_REG("EPS5", XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT),
-    [EPS2 + 4] = XTENSA_REG("EPS6", XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT),
-    [EPS2 + 5] = XTENSA_REG("EPS7", XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT),
-    [CONFIGID1] = XTENSA_REG_BITS_ACCESS("CONFIGID1", XTENSA_OPTION_ALL, SR_R),
-    [EXCSAVE1] = XTENSA_REG("EXCSAVE1", XTENSA_OPTION_EXCEPTION),
-    [EXCSAVE1 + 1] = XTENSA_REG("EXCSAVE2",
-            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT),
-    [EXCSAVE1 + 2] = XTENSA_REG("EXCSAVE3",
-            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT),
-    [EXCSAVE1 + 3] = XTENSA_REG("EXCSAVE4",
-            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT),
-    [EXCSAVE1 + 4] = XTENSA_REG("EXCSAVE5",
-            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT),
-    [EXCSAVE1 + 5] = XTENSA_REG("EXCSAVE6",
-            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT),
-    [EXCSAVE1 + 6] = XTENSA_REG("EXCSAVE7",
-            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT),
-    [CPENABLE] = XTENSA_REG("CPENABLE", XTENSA_OPTION_COPROCESSOR),
-    [INTSET] = XTENSA_REG_ACCESS("INTSET", XTENSA_OPTION_INTERRUPT, SR_RW),
-    [INTCLEAR] = XTENSA_REG_ACCESS("INTCLEAR", XTENSA_OPTION_INTERRUPT, SR_W),
-    [INTENABLE] = XTENSA_REG("INTENABLE", XTENSA_OPTION_INTERRUPT),
-    [PS] = XTENSA_REG_BITS("PS", XTENSA_OPTION_ALL),
-    [VECBASE] = XTENSA_REG("VECBASE", XTENSA_OPTION_RELOCATABLE_VECTOR),
-    [EXCCAUSE] = XTENSA_REG("EXCCAUSE", XTENSA_OPTION_EXCEPTION),
-    [DEBUGCAUSE] = XTENSA_REG_ACCESS("DEBUGCAUSE", XTENSA_OPTION_DEBUG, SR_R),
-    [CCOUNT] = XTENSA_REG("CCOUNT", XTENSA_OPTION_TIMER_INTERRUPT),
-    [PRID] = XTENSA_REG_ACCESS("PRID", XTENSA_OPTION_PROCESSOR_ID, SR_R),
-    [ICOUNT] = XTENSA_REG("ICOUNT", XTENSA_OPTION_DEBUG),
-    [ICOUNTLEVEL] = XTENSA_REG("ICOUNTLEVEL", XTENSA_OPTION_DEBUG),
-    [EXCVADDR] = XTENSA_REG("EXCVADDR", XTENSA_OPTION_EXCEPTION),
-    [CCOMPARE] = XTENSA_REG("CCOMPARE0", XTENSA_OPTION_TIMER_INTERRUPT),
-    [CCOMPARE + 1] = XTENSA_REG("CCOMPARE1",
-            XTENSA_OPTION_TIMER_INTERRUPT),
-    [CCOMPARE + 2] = XTENSA_REG("CCOMPARE2",
-            XTENSA_OPTION_TIMER_INTERRUPT),
-    [MISC] = XTENSA_REG("MISC0", XTENSA_OPTION_MISC_SR),
-    [MISC + 1] = XTENSA_REG("MISC1", XTENSA_OPTION_MISC_SR),
-    [MISC + 2] = XTENSA_REG("MISC2", XTENSA_OPTION_MISC_SR),
-    [MISC + 3] = XTENSA_REG("MISC3", XTENSA_OPTION_MISC_SR),
-};
-
-static const XtensaReg uregnames[256] = {
-    [EXPSTATE] = XTENSA_REG_BITS("EXPSTATE", XTENSA_OPTION_ALL),
-    [THREADPTR] = XTENSA_REG("THREADPTR", XTENSA_OPTION_THREAD_POINTER),
-    [FCR] = XTENSA_REG("FCR", XTENSA_OPTION_FP_COPROCESSOR),
-    [FSR] = XTENSA_REG("FSR", XTENSA_OPTION_FP_COPROCESSOR),
-};
+}
 
 void xtensa_translate_init(void)
 {
@@ -283,18 +197,20 @@ void xtensa_translate_init(void)
     }
 
     for (i = 0; i < 256; ++i) {
-        if (sregnames[i].name) {
+        if (sr_name[i]) {
             cpu_SR[i] = tcg_global_mem_new_i32(cpu_env,
-                    offsetof(CPUXtensaState, sregs[i]),
-                    sregnames[i].name);
+                                               offsetof(CPUXtensaState,
+                                                        sregs[i]),
+                                               sr_name[i]);
         }
     }
 
     for (i = 0; i < 256; ++i) {
-        if (uregnames[i].name) {
+        if (ur_name[i]) {
             cpu_UR[i] = tcg_global_mem_new_i32(cpu_env,
-                    offsetof(CPUXtensaState, uregs[i]),
-                    uregnames[i].name);
+                                               offsetof(CPUXtensaState,
+                                                        uregs[i]),
+                                               ur_name[i]);
         }
     }
 
@@ -302,6 +218,14 @@ void xtensa_translate_init(void)
         tcg_global_mem_new_i32(cpu_env,
                                offsetof(CPUXtensaState, windowbase_next),
                                "windowbase_next");
+    cpu_exclusive_addr =
+        tcg_global_mem_new_i32(cpu_env,
+                               offsetof(CPUXtensaState, exclusive_addr),
+                               "exclusive_addr");
+    cpu_exclusive_val =
+        tcg_global_mem_new_i32(cpu_env,
+                               offsetof(CPUXtensaState, exclusive_val),
+                               "exclusive_val");
 }
 
 void **xtensa_get_regfile_by_name(const char *name)
@@ -536,313 +460,57 @@ static void gen_brcondi(DisasContext *dc, TCGCond cond,
     tcg_temp_free(tmp);
 }
 
-static bool check_sr(DisasContext *dc, uint32_t sr, unsigned access)
-{
-    if (!xtensa_option_bits_enabled(dc->config, sregnames[sr].opt_bits)) {
-        if (sregnames[sr].name) {
-            qemu_log_mask(LOG_GUEST_ERROR, "SR %s is not configured\n", sregnames[sr].name);
-        } else {
-            qemu_log_mask(LOG_UNIMP, "SR %d is not implemented\n", sr);
-        }
-        return false;
-    } else if (!(sregnames[sr].access & access)) {
-        static const char * const access_text[] = {
-            [SR_R] = "rsr",
-            [SR_W] = "wsr",
-            [SR_X] = "xsr",
-        };
-        assert(access < ARRAY_SIZE(access_text) && access_text[access]);
-        qemu_log_mask(LOG_GUEST_ERROR, "SR %s is not available for %s\n", sregnames[sr].name,
-                      access_text[access]);
-        return false;
-    }
-    return true;
-}
-
-#ifndef CONFIG_USER_ONLY
-static void gen_rsr_ccount(DisasContext *dc, TCGv_i32 d, uint32_t sr)
-{
-    if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) {
-        gen_io_start();
-    }
-    gen_helper_update_ccount(cpu_env);
-    tcg_gen_mov_i32(d, cpu_SR[sr]);
-    if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) {
-        gen_io_end();
-    }
-}
-
-static void gen_rsr_ptevaddr(DisasContext *dc, TCGv_i32 d, uint32_t sr)
-{
-    tcg_gen_shri_i32(d, cpu_SR[EXCVADDR], 10);
-    tcg_gen_or_i32(d, d, cpu_SR[sr]);
-    tcg_gen_andi_i32(d, d, 0xfffffffc);
-}
-#endif
-
-static void gen_rsr(DisasContext *dc, TCGv_i32 d, uint32_t sr)
-{
-    static void (* const rsr_handler[256])(DisasContext *dc,
-                                           TCGv_i32 d, uint32_t sr) = {
-#ifndef CONFIG_USER_ONLY
-        [CCOUNT] = gen_rsr_ccount,
-        [INTSET] = gen_rsr_ccount,
-        [PTEVADDR] = gen_rsr_ptevaddr,
-#endif
-    };
-
-    if (rsr_handler[sr]) {
-        rsr_handler[sr](dc, d, sr);
-    } else {
-        tcg_gen_mov_i32(d, cpu_SR[sr]);
-    }
-}
-
-static void gen_wsr_sar(DisasContext *dc, uint32_t sr, TCGv_i32 s)
-{
-    tcg_gen_andi_i32(cpu_SR[sr], s, 0x3f);
-    if (dc->sar_m32_5bit) {
-        tcg_gen_discard_i32(dc->sar_m32);
-    }
-    dc->sar_5bit = false;
-    dc->sar_m32_5bit = false;
-}
-
-static void gen_wsr_br(DisasContext *dc, uint32_t sr, TCGv_i32 s)
-{
-    tcg_gen_andi_i32(cpu_SR[sr], s, 0xffff);
-}
-
-static void gen_wsr_litbase(DisasContext *dc, uint32_t sr, TCGv_i32 s)
-{
-    tcg_gen_andi_i32(cpu_SR[sr], s, 0xfffff001);
-}
-
-static void gen_wsr_acchi(DisasContext *dc, uint32_t sr, TCGv_i32 s)
-{
-    tcg_gen_ext8s_i32(cpu_SR[sr], s);
-}
-
-#ifndef CONFIG_USER_ONLY
-static void gen_wsr_windowbase(DisasContext *dc, uint32_t sr, TCGv_i32 v)
-{
-    tcg_gen_mov_i32(cpu_windowbase_next, v);
-}
-
-static void gen_wsr_windowstart(DisasContext *dc, uint32_t sr, TCGv_i32 v)
-{
-    tcg_gen_andi_i32(cpu_SR[sr], v, (1 << dc->config->nareg / 4) - 1);
-}
-
-static void gen_wsr_ptevaddr(DisasContext *dc, uint32_t sr, TCGv_i32 v)
-{
-    tcg_gen_andi_i32(cpu_SR[sr], v, 0xffc00000);
-}
-
-static void gen_wsr_rasid(DisasContext *dc, uint32_t sr, TCGv_i32 v)
-{
-    gen_helper_wsr_rasid(cpu_env, v);
-}
-
-static void gen_wsr_tlbcfg(DisasContext *dc, uint32_t sr, TCGv_i32 v)
-{
-    tcg_gen_andi_i32(cpu_SR[sr], v, 0x01130000);
-}
-
-static void gen_wsr_ibreakenable(DisasContext *dc, uint32_t sr, TCGv_i32 v)
-{
-    gen_helper_wsr_ibreakenable(cpu_env, v);
-}
-
-static void gen_wsr_memctl(DisasContext *dc, uint32_t sr, TCGv_i32 v)
-{
-    gen_helper_wsr_memctl(cpu_env, v);
-}
-
-static void gen_wsr_atomctl(DisasContext *dc, uint32_t sr, TCGv_i32 v)
-{
-    tcg_gen_andi_i32(cpu_SR[sr], v, 0x3f);
-}
-
-static void gen_wsr_ibreaka(DisasContext *dc, uint32_t sr, TCGv_i32 v)
-{
-    unsigned id = sr - IBREAKA;
-    TCGv_i32 tmp = tcg_const_i32(id);
-
-    assert(id < dc->config->nibreak);
-    gen_helper_wsr_ibreaka(cpu_env, tmp, v);
-    tcg_temp_free(tmp);
-}
-
-static void gen_wsr_dbreaka(DisasContext *dc, uint32_t sr, TCGv_i32 v)
-{
-    unsigned id = sr - DBREAKA;
-    TCGv_i32 tmp = tcg_const_i32(id);
-
-    assert(id < dc->config->ndbreak);
-    gen_helper_wsr_dbreaka(cpu_env, tmp, v);
-    tcg_temp_free(tmp);
-}
-
-static void gen_wsr_dbreakc(DisasContext *dc, uint32_t sr, TCGv_i32 v)
-{
-    unsigned id = sr - DBREAKC;
-    TCGv_i32 tmp = tcg_const_i32(id);
-
-    assert(id < dc->config->ndbreak);
-    gen_helper_wsr_dbreakc(cpu_env, tmp, v);
-    tcg_temp_free(tmp);
-}
-
-static void gen_wsr_cpenable(DisasContext *dc, uint32_t sr, TCGv_i32 v)
-{
-    tcg_gen_andi_i32(cpu_SR[sr], v, 0xff);
-}
-
-static void gen_check_interrupts(DisasContext *dc)
-{
-    if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) {
-        gen_io_start();
-    }
-    gen_helper_check_interrupts(cpu_env);
-    if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) {
-        gen_io_end();
-    }
-}
-
-static void gen_wsr_intset(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+static bool test_ill_sr(DisasContext *dc, const OpcodeArg arg[],
+                        const uint32_t par[])
 {
-    gen_helper_intset(cpu_env, v);
+    return !xtensa_option_enabled(dc->config, par[1]);
 }
 
-static void gen_wsr_intclear(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+static bool test_ill_ccompare(DisasContext *dc, const OpcodeArg arg[],
+                              const uint32_t par[])
 {
-    gen_helper_intclear(cpu_env, v);
-}
+    unsigned n = par[0] - CCOMPARE;
 
-static void gen_wsr_intenable(DisasContext *dc, uint32_t sr, TCGv_i32 v)
-{
-    tcg_gen_mov_i32(cpu_SR[sr], v);
+    return test_ill_sr(dc, arg, par) || n >= dc->config->nccompare;
 }
 
-static void gen_wsr_ps(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+static bool test_ill_dbreak(DisasContext *dc, const OpcodeArg arg[],
+                            const uint32_t par[])
 {
-    uint32_t mask = PS_WOE | PS_CALLINC | PS_OWB |
-        PS_UM | PS_EXCM | PS_INTLEVEL;
+    unsigned n = MAX_NDBREAK;
 
-    if (option_enabled(dc, XTENSA_OPTION_MMU)) {
-        mask |= PS_RING;
+    if (par[0] >= DBREAKA && par[0] < DBREAKA + MAX_NDBREAK) {
+        n = par[0] - DBREAKA;
     }
-    tcg_gen_andi_i32(cpu_SR[sr], v, mask);
-}
-
-static void gen_wsr_ccount(DisasContext *dc, uint32_t sr, TCGv_i32 v)
-{
-    if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) {
-        gen_io_start();
-    }
-    gen_helper_wsr_ccount(cpu_env, v);
-    if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) {
-        gen_io_end();
+    if (par[0] >= DBREAKC && par[0] < DBREAKC + MAX_NDBREAK) {
+        n = par[0] - DBREAKC;
     }
+    return test_ill_sr(dc, arg, par) || n >= dc->config->ndbreak;
 }
 
-static void gen_wsr_icount(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+static bool test_ill_ibreak(DisasContext *dc, const OpcodeArg arg[],
+                            const uint32_t par[])
 {
-    if (dc->icount) {
-        tcg_gen_mov_i32(dc->next_icount, v);
-    } else {
-        tcg_gen_mov_i32(cpu_SR[sr], v);
-    }
-}
+    unsigned n = par[0] - IBREAKA;
 
-static void gen_wsr_icountlevel(DisasContext *dc, uint32_t sr, TCGv_i32 v)
-{
-    tcg_gen_andi_i32(cpu_SR[sr], v, 0xf);
+    return test_ill_sr(dc, arg, par) || n >= dc->config->nibreak;
 }
 
-static void gen_wsr_ccompare(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+static bool test_ill_hpi(DisasContext *dc, const OpcodeArg arg[],
+                         const uint32_t par[])
 {
-    uint32_t id = sr - CCOMPARE;
-    TCGv_i32 tmp = tcg_const_i32(id);
+    unsigned n = MAX_NLEVEL + 1;
 
-    assert(id < dc->config->nccompare);
-    tcg_gen_mov_i32(cpu_SR[sr], v);
-    if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) {
-        gen_io_start();
+    if (par[0] >= EXCSAVE1 && par[0] < EXCSAVE1 + MAX_NLEVEL) {
+        n = par[0] - EXCSAVE1 + 1;
     }
-    gen_helper_update_ccompare(cpu_env, tmp);
-    tcg_temp_free(tmp);
-    if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) {
-        gen_io_end();
+    if (par[0] >= EPC1 && par[0] < EPC1 + MAX_NLEVEL) {
+        n = par[0] - EPC1 + 1;
     }
-}
-#else
-static void gen_check_interrupts(DisasContext *dc)
-{
-}
-#endif
-
-static void gen_wsr(DisasContext *dc, uint32_t sr, TCGv_i32 s)
-{
-    static void (* const wsr_handler[256])(DisasContext *dc,
-                                           uint32_t sr, TCGv_i32 v) = {
-        [SAR] = gen_wsr_sar,
-        [BR] = gen_wsr_br,
-        [LITBASE] = gen_wsr_litbase,
-        [ACCHI] = gen_wsr_acchi,
-#ifndef CONFIG_USER_ONLY
-        [WINDOW_BASE] = gen_wsr_windowbase,
-        [WINDOW_START] = gen_wsr_windowstart,
-        [PTEVADDR] = gen_wsr_ptevaddr,
-        [RASID] = gen_wsr_rasid,
-        [ITLBCFG] = gen_wsr_tlbcfg,
-        [DTLBCFG] = gen_wsr_tlbcfg,
-        [IBREAKENABLE] = gen_wsr_ibreakenable,
-        [MEMCTL] = gen_wsr_memctl,
-        [ATOMCTL] = gen_wsr_atomctl,
-        [IBREAKA] = gen_wsr_ibreaka,
-        [IBREAKA + 1] = gen_wsr_ibreaka,
-        [DBREAKA] = gen_wsr_dbreaka,
-        [DBREAKA + 1] = gen_wsr_dbreaka,
-        [DBREAKC] = gen_wsr_dbreakc,
-        [DBREAKC + 1] = gen_wsr_dbreakc,
-        [CPENABLE] = gen_wsr_cpenable,
-        [INTSET] = gen_wsr_intset,
-        [INTCLEAR] = gen_wsr_intclear,
-        [INTENABLE] = gen_wsr_intenable,
-        [PS] = gen_wsr_ps,
-        [CCOUNT] = gen_wsr_ccount,
-        [ICOUNT] = gen_wsr_icount,
-        [ICOUNTLEVEL] = gen_wsr_icountlevel,
-        [CCOMPARE] = gen_wsr_ccompare,
-        [CCOMPARE + 1] = gen_wsr_ccompare,
-        [CCOMPARE + 2] = gen_wsr_ccompare,
-#endif
-    };
-
-    if (wsr_handler[sr]) {
-        wsr_handler[sr](dc, sr, s);
-    } else {
-        tcg_gen_mov_i32(cpu_SR[sr], s);
-    }
-}
-
-static void gen_wur(uint32_t ur, TCGv_i32 s)
-{
-    switch (ur) {
-    case FCR:
-        gen_helper_wur_fcr(cpu_env, s);
-        break;
-
-    case FSR:
-        tcg_gen_andi_i32(cpu_UR[ur], s, 0xffffff80);
-        break;
-
-    default:
-        tcg_gen_mov_i32(cpu_UR[ur], s);
-        break;
+    if (par[0] >= EPS2 && par[0] < EPS2 + MAX_NLEVEL - 1) {
+        n = par[0] - EPS2 + 2;
     }
+    return test_ill_sr(dc, arg, par) || n > dc->config->nlevel;
 }
 
 static void gen_load_store_alignment(DisasContext *dc, int shift,
@@ -925,9 +593,17 @@ static int gen_postprocess(DisasContext *dc, int slot)
 {
     uint32_t op_flags = dc->op_flags;
 
+#ifndef CONFIG_USER_ONLY
     if (op_flags & XTENSA_OP_CHECK_INTERRUPTS) {
-        gen_check_interrupts(dc);
+        if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) {
+            gen_io_start();
+        }
+        gen_helper_check_interrupts(cpu_env);
+        if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) {
+            gen_io_end();
+        }
     }
+#endif
     if (op_flags & XTENSA_OP_SYNC_REGISTER_WINDOW) {
         gen_helper_sync_windowbase(cpu_env);
     }
@@ -1645,24 +1321,20 @@ void xtensa_cpu_dump_state(CPUState *cs, FILE *f, int flags)
 {
     XtensaCPU *cpu = XTENSA_CPU(cs);
     CPUXtensaState *env = &cpu->env;
+    xtensa_isa isa = env->config->isa;
     int i, j;
 
     qemu_fprintf(f, "PC=%08x\n\n", env->pc);
 
-    for (i = j = 0; i < 256; ++i) {
-        if (xtensa_option_bits_enabled(env->config, sregnames[i].opt_bits)) {
-            qemu_fprintf(f, "%12s=%08x%c",
-                         sregnames[i].name, env->sregs[i],
-                         (j++ % 4) == 3 ? '\n' : ' ');
-        }
-    }
-
-    qemu_fprintf(f, (j % 4) == 0 ? "\n" : "\n\n");
+    for (i = j = 0; i < xtensa_isa_num_sysregs(isa); ++i) {
+        const uint32_t *reg =
+            xtensa_sysreg_is_user(isa, i) ? env->uregs : env->sregs;
+        int regno = xtensa_sysreg_number(isa, i);
 
-    for (i = j = 0; i < 256; ++i) {
-        if (xtensa_option_bits_enabled(env->config, uregnames[i].opt_bits)) {
-            qemu_fprintf(f, "%s=%08x%c",
-                         uregnames[i].name, env->uregs[i],
+        if (regno >= 0) {
+            qemu_fprintf(f, "%12s=%08x%c",
+                         xtensa_sysreg_name(isa, i),
+                         reg[regno],
                          (j++ % 4) == 3 ? '\n' : ' ');
         }
     }
@@ -1923,6 +1595,12 @@ static void translate_clrb_expstate(DisasContext *dc, const OpcodeArg arg[],
     tcg_gen_andi_i32(cpu_UR[EXPSTATE], cpu_UR[EXPSTATE], ~(1u << arg[0].imm));
 }
 
+static void translate_clrex(DisasContext *dc, const OpcodeArg arg[],
+                            const uint32_t par[])
+{
+    tcg_gen_movi_i32(cpu_exclusive_addr, -1);
+}
+
 static void translate_const16(DisasContext *dc, const OpcodeArg arg[],
                              const uint32_t par[])
 {
@@ -1951,6 +1629,12 @@ static void translate_depbits(DisasContext *dc, const OpcodeArg arg[],
                         arg[2].imm, arg[3].imm);
 }
 
+static void translate_diwbuip(DisasContext *dc, const OpcodeArg arg[],
+                              const uint32_t par[])
+{
+    tcg_gen_addi_i32(arg[0].out, arg[0].in, dc->config->dcache_line_bytes);
+}
+
 static bool test_ill_entry(DisasContext *dc, const OpcodeArg arg[],
                            const uint32_t par[])
 {
@@ -1992,6 +1676,17 @@ static void translate_extui(DisasContext *dc, const OpcodeArg arg[],
     tcg_temp_free(tmp);
 }
 
+static void translate_getex(DisasContext *dc, const OpcodeArg arg[],
+                            const uint32_t par[])
+{
+    TCGv_i32 tmp = tcg_temp_new_i32();
+
+    tcg_gen_extract_i32(tmp, cpu_SR[ATOMCTL], 8, 1);
+    tcg_gen_deposit_i32(cpu_SR[ATOMCTL], cpu_SR[ATOMCTL], arg[0].in, 8, 1);
+    tcg_gen_mov_i32(arg[0].out, tmp);
+    tcg_temp_free(tmp);
+}
+
 static void translate_icache(DisasContext *dc, const OpcodeArg arg[],
                              const uint32_t par[])
 {
@@ -2039,6 +1734,38 @@ static void translate_l32e(DisasContext *dc, const OpcodeArg arg[],
     tcg_temp_free(addr);
 }
 
+#ifdef CONFIG_USER_ONLY
+static void gen_check_exclusive(DisasContext *dc, TCGv_i32 addr, bool is_write)
+{
+}
+#else
+static void gen_check_exclusive(DisasContext *dc, TCGv_i32 addr, bool is_write)
+{
+    if (!option_enabled(dc, XTENSA_OPTION_MPU)) {
+        TCGv_i32 tpc = tcg_const_i32(dc->pc);
+        TCGv_i32 write = tcg_const_i32(is_write);
+
+        gen_helper_check_exclusive(cpu_env, tpc, addr, write);
+        tcg_temp_free(tpc);
+        tcg_temp_free(write);
+    }
+}
+#endif
+
+static void translate_l32ex(DisasContext *dc, const OpcodeArg arg[],
+                            const uint32_t par[])
+{
+    TCGv_i32 addr = tcg_temp_new_i32();
+
+    tcg_gen_mov_i32(addr, arg[1].in);
+    gen_load_store_alignment(dc, 2, addr, true);
+    gen_check_exclusive(dc, addr, false);
+    tcg_gen_qemu_ld_i32(arg[0].out, addr, dc->ring, MO_TEUL);
+    tcg_gen_mov_i32(cpu_exclusive_addr, addr);
+    tcg_gen_mov_i32(cpu_exclusive_val, arg[0].out);
+    tcg_temp_free(addr);
+}
+
 static void translate_ldst(DisasContext *dc, const OpcodeArg arg[],
                            const uint32_t par[])
 {
@@ -2323,6 +2050,15 @@ static void translate_ptlb(DisasContext *dc, const OpcodeArg arg[],
 #endif
 }
 
+static void translate_pptlb(DisasContext *dc, const OpcodeArg arg[],
+                            const uint32_t par[])
+{
+#ifndef CONFIG_USER_ONLY
+    tcg_gen_movi_i32(cpu_pc, dc->pc);
+    gen_helper_pptlb(arg[0].out, cpu_env, arg[1].in);
+#endif
+}
+
 static void translate_quos(DisasContext *dc, const OpcodeArg arg[],
                            const uint32_t par[])
 {
@@ -2465,16 +2201,38 @@ static void translate_rsil(DisasContext *dc, const OpcodeArg arg[],
     tcg_gen_ori_i32(cpu_SR[PS], cpu_SR[PS], arg[1].imm);
 }
 
-static bool test_ill_rsr(DisasContext *dc, const OpcodeArg arg[],
-                         const uint32_t par[])
+static void translate_rsr(DisasContext *dc, const OpcodeArg arg[],
+                          const uint32_t par[])
 {
-    return !check_sr(dc, par[0], SR_R);
+    tcg_gen_mov_i32(arg[0].out, cpu_SR[par[0]]);
 }
 
-static void translate_rsr(DisasContext *dc, const OpcodeArg arg[],
-                          const uint32_t par[])
+static void translate_rsr_ccount(DisasContext *dc, const OpcodeArg arg[],
+                                 const uint32_t par[])
 {
-    gen_rsr(dc, arg[0].out, par[0]);
+#ifndef CONFIG_USER_ONLY
+    if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) {
+        gen_io_start();
+    }
+    gen_helper_update_ccount(cpu_env);
+    tcg_gen_mov_i32(arg[0].out, cpu_SR[par[0]]);
+    if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) {
+        gen_io_end();
+    }
+#endif
+}
+
+static void translate_rsr_ptevaddr(DisasContext *dc, const OpcodeArg arg[],
+                                   const uint32_t par[])
+{
+#ifndef CONFIG_USER_ONLY
+    TCGv_i32 tmp = tcg_temp_new_i32();
+
+    tcg_gen_shri_i32(tmp, cpu_SR[EXCVADDR], 10);
+    tcg_gen_or_i32(tmp, tmp, cpu_SR[PTEVADDR]);
+    tcg_gen_andi_i32(arg[0].out, tmp, 0xfffffffc);
+    tcg_temp_free(tmp);
+#endif
 }
 
 static void translate_rtlb(DisasContext *dc, const OpcodeArg arg[],
@@ -2493,14 +2251,26 @@ static void translate_rtlb(DisasContext *dc, const OpcodeArg arg[],
 #endif
 }
 
+static void translate_rptlb0(DisasContext *dc, const OpcodeArg arg[],
+                             const uint32_t par[])
+{
+#ifndef CONFIG_USER_ONLY
+    gen_helper_rptlb0(arg[0].out, cpu_env, arg[1].in);
+#endif
+}
+
+static void translate_rptlb1(DisasContext *dc, const OpcodeArg arg[],
+                             const uint32_t par[])
+{
+#ifndef CONFIG_USER_ONLY
+    gen_helper_rptlb1(arg[0].out, cpu_env, arg[1].in);
+#endif
+}
+
 static void translate_rur(DisasContext *dc, const OpcodeArg arg[],
                           const uint32_t par[])
 {
-    if (uregnames[par[0]].name) {
-        tcg_gen_mov_i32(arg[0].out, cpu_UR[par[0]]);
-    } else {
-        qemu_log_mask(LOG_UNIMP, "RUR %d not implemented\n", par[0]);
-    }
+    tcg_gen_mov_i32(arg[0].out, cpu_UR[par[0]]);
 }
 
 static void translate_setb_expstate(DisasContext *dc, const OpcodeArg arg[],
@@ -2551,6 +2321,33 @@ static void translate_s32e(DisasContext *dc, const OpcodeArg arg[],
     tcg_temp_free(addr);
 }
 
+static void translate_s32ex(DisasContext *dc, const OpcodeArg arg[],
+                            const uint32_t par[])
+{
+    TCGv_i32 prev = tcg_temp_new_i32();
+    TCGv_i32 addr = tcg_temp_local_new_i32();
+    TCGv_i32 res = tcg_temp_local_new_i32();
+    TCGLabel *label = gen_new_label();
+
+    tcg_gen_movi_i32(res, 0);
+    tcg_gen_mov_i32(addr, arg[1].in);
+    gen_load_store_alignment(dc, 2, addr, true);
+    tcg_gen_brcond_i32(TCG_COND_NE, addr, cpu_exclusive_addr, label);
+    gen_check_exclusive(dc, addr, true);
+    tcg_gen_atomic_cmpxchg_i32(prev, cpu_exclusive_addr, cpu_exclusive_val,
+                               arg[0].in, dc->cring, MO_TEUL);
+    tcg_gen_setcond_i32(TCG_COND_EQ, res, prev, cpu_exclusive_val);
+    tcg_gen_movcond_i32(TCG_COND_EQ, cpu_exclusive_val,
+                        prev, cpu_exclusive_val, prev, cpu_exclusive_val);
+    tcg_gen_movi_i32(cpu_exclusive_addr, -1);
+    gen_set_label(label);
+    tcg_gen_extract_i32(arg[0].out, cpu_SR[ATOMCTL], 8, 1);
+    tcg_gen_deposit_i32(cpu_SR[ATOMCTL], cpu_SR[ATOMCTL], res, 8, 1);
+    tcg_temp_free(prev);
+    tcg_temp_free(addr);
+    tcg_temp_free(res);
+}
+
 static void translate_salt(DisasContext *dc, const OpcodeArg arg[],
                            const uint32_t par[])
 {
@@ -2758,6 +2555,14 @@ static void translate_wtlb(DisasContext *dc, const OpcodeArg arg[],
 #endif
 }
 
+static void translate_wptlb(DisasContext *dc, const OpcodeArg arg[],
+                            const uint32_t par[])
+{
+#ifndef CONFIG_USER_ONLY
+    gen_helper_wptlb(cpu_env, arg[0].in, arg[1].in);
+#endif
+}
+
 static void translate_wer(DisasContext *dc, const OpcodeArg arg[],
                           const uint32_t par[])
 {
@@ -2771,38 +2576,221 @@ static void translate_wrmsk_expstate(DisasContext *dc, const OpcodeArg arg[],
     tcg_gen_and_i32(cpu_UR[EXPSTATE], arg[0].in, arg[1].in);
 }
 
-static bool test_ill_wsr(DisasContext *dc, const OpcodeArg arg[],
-                         const uint32_t par[])
+static void translate_wsr(DisasContext *dc, const OpcodeArg arg[],
+                          const uint32_t par[])
 {
-    return !check_sr(dc, par[0], SR_W);
+    tcg_gen_mov_i32(cpu_SR[par[0]], arg[0].in);
 }
 
-static void translate_wsr(DisasContext *dc, const OpcodeArg arg[],
-                          const uint32_t par[])
+static void translate_wsr_mask(DisasContext *dc, const OpcodeArg arg[],
+                               const uint32_t par[])
 {
-    gen_wsr(dc, par[0], arg[0].in);
+    tcg_gen_andi_i32(cpu_SR[par[0]], arg[0].in, par[2]);
 }
 
-static void translate_wur(DisasContext *dc, const OpcodeArg arg[],
-                          const uint32_t par[])
+static void translate_wsr_acchi(DisasContext *dc, const OpcodeArg arg[],
+                                const uint32_t par[])
 {
-    if (uregnames[par[0]].name) {
-        gen_wur(par[0], arg[0].in);
+    tcg_gen_ext8s_i32(cpu_SR[par[0]], arg[0].in);
+}
+
+static void translate_wsr_ccompare(DisasContext *dc, const OpcodeArg arg[],
+                                   const uint32_t par[])
+{
+#ifndef CONFIG_USER_ONLY
+    uint32_t id = par[0] - CCOMPARE;
+    TCGv_i32 tmp = tcg_const_i32(id);
+
+    assert(id < dc->config->nccompare);
+    if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) {
+        gen_io_start();
+    }
+    tcg_gen_mov_i32(cpu_SR[par[0]], arg[0].in);
+    gen_helper_update_ccompare(cpu_env, tmp);
+    tcg_temp_free(tmp);
+    if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) {
+        gen_io_end();
+    }
+#endif
+}
+
+static void translate_wsr_ccount(DisasContext *dc, const OpcodeArg arg[],
+                                 const uint32_t par[])
+{
+#ifndef CONFIG_USER_ONLY
+    if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) {
+        gen_io_start();
+    }
+    gen_helper_wsr_ccount(cpu_env, arg[0].in);
+    if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) {
+        gen_io_end();
+    }
+#endif
+}
+
+static void translate_wsr_dbreaka(DisasContext *dc, const OpcodeArg arg[],
+                                  const uint32_t par[])
+{
+#ifndef CONFIG_USER_ONLY
+    unsigned id = par[0] - DBREAKA;
+    TCGv_i32 tmp = tcg_const_i32(id);
+
+    assert(id < dc->config->ndbreak);
+    gen_helper_wsr_dbreaka(cpu_env, tmp, arg[0].in);
+    tcg_temp_free(tmp);
+#endif
+}
+
+static void translate_wsr_dbreakc(DisasContext *dc, const OpcodeArg arg[],
+                                  const uint32_t par[])
+{
+#ifndef CONFIG_USER_ONLY
+    unsigned id = par[0] - DBREAKC;
+    TCGv_i32 tmp = tcg_const_i32(id);
+
+    assert(id < dc->config->ndbreak);
+    gen_helper_wsr_dbreakc(cpu_env, tmp, arg[0].in);
+    tcg_temp_free(tmp);
+#endif
+}
+
+static void translate_wsr_ibreaka(DisasContext *dc, const OpcodeArg arg[],
+                                  const uint32_t par[])
+{
+#ifndef CONFIG_USER_ONLY
+    unsigned id = par[0] - IBREAKA;
+    TCGv_i32 tmp = tcg_const_i32(id);
+
+    assert(id < dc->config->nibreak);
+    gen_helper_wsr_ibreaka(cpu_env, tmp, arg[0].in);
+    tcg_temp_free(tmp);
+#endif
+}
+
+static void translate_wsr_ibreakenable(DisasContext *dc, const OpcodeArg arg[],
+                                       const uint32_t par[])
+{
+#ifndef CONFIG_USER_ONLY
+    gen_helper_wsr_ibreakenable(cpu_env, arg[0].in);
+#endif
+}
+
+static void translate_wsr_icount(DisasContext *dc, const OpcodeArg arg[],
+                                 const uint32_t par[])
+{
+#ifndef CONFIG_USER_ONLY
+    if (dc->icount) {
+        tcg_gen_mov_i32(dc->next_icount, arg[0].in);
     } else {
-        qemu_log_mask(LOG_UNIMP, "WUR %d not implemented\n", par[0]);
+        tcg_gen_mov_i32(cpu_SR[par[0]], arg[0].in);
     }
+#endif
 }
 
-static void translate_xor(DisasContext *dc, const OpcodeArg arg[],
+static void translate_wsr_intclear(DisasContext *dc, const OpcodeArg arg[],
+                                   const uint32_t par[])
+{
+#ifndef CONFIG_USER_ONLY
+    gen_helper_intclear(cpu_env, arg[0].in);
+#endif
+}
+
+static void translate_wsr_intset(DisasContext *dc, const OpcodeArg arg[],
+                                 const uint32_t par[])
+{
+#ifndef CONFIG_USER_ONLY
+    gen_helper_intset(cpu_env, arg[0].in);
+#endif
+}
+
+static void translate_wsr_memctl(DisasContext *dc, const OpcodeArg arg[],
+                                 const uint32_t par[])
+{
+#ifndef CONFIG_USER_ONLY
+    gen_helper_wsr_memctl(cpu_env, arg[0].in);
+#endif
+}
+
+static void translate_wsr_mpuenb(DisasContext *dc, const OpcodeArg arg[],
+                                 const uint32_t par[])
+{
+#ifndef CONFIG_USER_ONLY
+    gen_helper_wsr_mpuenb(cpu_env, arg[0].in);
+#endif
+}
+
+static void translate_wsr_ps(DisasContext *dc, const OpcodeArg arg[],
+                             const uint32_t par[])
+{
+#ifndef CONFIG_USER_ONLY
+    uint32_t mask = PS_WOE | PS_CALLINC | PS_OWB |
+        PS_UM | PS_EXCM | PS_INTLEVEL;
+
+    if (option_enabled(dc, XTENSA_OPTION_MMU)) {
+        mask |= PS_RING;
+    }
+    tcg_gen_andi_i32(cpu_SR[par[0]], arg[0].in, mask);
+#endif
+}
+
+static void translate_wsr_rasid(DisasContext *dc, const OpcodeArg arg[],
+                                const uint32_t par[])
+{
+#ifndef CONFIG_USER_ONLY
+    gen_helper_wsr_rasid(cpu_env, arg[0].in);
+#endif
+}
+
+static void translate_wsr_sar(DisasContext *dc, const OpcodeArg arg[],
+                              const uint32_t par[])
+{
+    tcg_gen_andi_i32(cpu_SR[par[0]], arg[0].in, 0x3f);
+    if (dc->sar_m32_5bit) {
+        tcg_gen_discard_i32(dc->sar_m32);
+    }
+    dc->sar_5bit = false;
+    dc->sar_m32_5bit = false;
+}
+
+static void translate_wsr_windowbase(DisasContext *dc, const OpcodeArg arg[],
+                                     const uint32_t par[])
+{
+#ifndef CONFIG_USER_ONLY
+    tcg_gen_mov_i32(cpu_windowbase_next, arg[0].in);
+#endif
+}
+
+static void translate_wsr_windowstart(DisasContext *dc, const OpcodeArg arg[],
+                                      const uint32_t par[])
+{
+#ifndef CONFIG_USER_ONLY
+    tcg_gen_andi_i32(cpu_SR[par[0]], arg[0].in,
+                     (1 << dc->config->nareg / 4) - 1);
+#endif
+}
+
+static void translate_wur(DisasContext *dc, const OpcodeArg arg[],
                           const uint32_t par[])
 {
-    tcg_gen_xor_i32(arg[0].out, arg[1].in, arg[2].in);
+    tcg_gen_mov_i32(cpu_UR[par[0]], arg[0].in);
 }
 
-static bool test_ill_xsr(DisasContext *dc, const OpcodeArg arg[],
-                         const uint32_t par[])
+static void translate_wur_fcr(DisasContext *dc, const OpcodeArg arg[],
+                              const uint32_t par[])
 {
-    return !check_sr(dc, par[0], SR_X);
+    gen_helper_wur_fcr(cpu_env, arg[0].in);
+}
+
+static void translate_wur_fsr(DisasContext *dc, const OpcodeArg arg[],
+                              const uint32_t par[])
+{
+    tcg_gen_andi_i32(cpu_UR[par[0]], arg[0].in, 0xffffff80);
+}
+
+static void translate_xor(DisasContext *dc, const OpcodeArg arg[],
+                          const uint32_t par[])
+{
+    tcg_gen_xor_i32(arg[0].out, arg[1].in, arg[2].in);
 }
 
 static void translate_xsr(DisasContext *dc, const OpcodeArg arg[],
@@ -2811,11 +2799,73 @@ static void translate_xsr(DisasContext *dc, const OpcodeArg arg[],
     TCGv_i32 tmp = tcg_temp_new_i32();
 
     tcg_gen_mov_i32(tmp, arg[0].in);
-    gen_rsr(dc, arg[0].out, par[0]);
-    gen_wsr(dc, par[0], tmp);
+    tcg_gen_mov_i32(arg[0].out, cpu_SR[par[0]]);
+    tcg_gen_mov_i32(cpu_SR[par[0]], tmp);
+    tcg_temp_free(tmp);
+}
+
+static void translate_xsr_mask(DisasContext *dc, const OpcodeArg arg[],
+                               const uint32_t par[])
+{
+    TCGv_i32 tmp = tcg_temp_new_i32();
+
+    tcg_gen_mov_i32(tmp, arg[0].in);
+    tcg_gen_mov_i32(arg[0].out, cpu_SR[par[0]]);
+    tcg_gen_andi_i32(cpu_SR[par[0]], tmp, par[2]);
     tcg_temp_free(tmp);
 }
 
+static void translate_xsr_ccount(DisasContext *dc, const OpcodeArg arg[],
+                                 const uint32_t par[])
+{
+#ifndef CONFIG_USER_ONLY
+    TCGv_i32 tmp = tcg_temp_new_i32();
+
+    if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) {
+        gen_io_start();
+    }
+
+    gen_helper_update_ccount(cpu_env);
+    tcg_gen_mov_i32(tmp, cpu_SR[par[0]]);
+    gen_helper_wsr_ccount(cpu_env, arg[0].in);
+    tcg_gen_mov_i32(arg[0].out, tmp);
+    tcg_temp_free(tmp);
+
+    if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) {
+        gen_io_end();
+    }
+#endif
+}
+
+#define gen_translate_xsr(name) \
+    static void translate_xsr_##name(DisasContext *dc, const OpcodeArg arg[], \
+                                     const uint32_t par[]) \
+{ \
+    TCGv_i32 tmp = tcg_temp_new_i32(); \
+ \
+    tcg_gen_mov_i32(tmp, cpu_SR[par[0]]); \
+    translate_wsr_##name(dc, arg, par); \
+    tcg_gen_mov_i32(arg[0].out, tmp); \
+    tcg_temp_free(tmp); \
+}
+
+gen_translate_xsr(acchi)
+gen_translate_xsr(ccompare)
+gen_translate_xsr(dbreaka)
+gen_translate_xsr(dbreakc)
+gen_translate_xsr(ibreaka)
+gen_translate_xsr(ibreakenable)
+gen_translate_xsr(icount)
+gen_translate_xsr(memctl)
+gen_translate_xsr(mpuenb)
+gen_translate_xsr(ps)
+gen_translate_xsr(rasid)
+gen_translate_xsr(sar)
+gen_translate_xsr(windowbase)
+gen_translate_xsr(windowstart)
+
+#undef gen_translate_xsr
+
 static const XtensaOpcodeOps core_ops[] = {
     {
         .name = "abs",
@@ -3097,6 +3147,9 @@ static const XtensaOpcodeOps core_ops[] = {
         .name = "clrb_expstate",
         .translate = translate_clrb_expstate,
     }, {
+        .name = "clrex",
+        .translate = translate_clrex,
+    }, {
         .name = "const16",
         .translate = translate_const16,
     }, {
@@ -3107,6 +3160,9 @@ static const XtensaOpcodeOps core_ops[] = {
         .translate = translate_dcache,
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
+        .name = "dhi.b",
+        .translate = translate_nop,
+    }, {
         .name = "dhu",
         .translate = translate_dcache,
         .op_flags = XTENSA_OP_PRIVILEGED,
@@ -3114,9 +3170,15 @@ static const XtensaOpcodeOps core_ops[] = {
         .name = "dhwb",
         .translate = translate_dcache,
     }, {
+        .name = "dhwb.b",
+        .translate = translate_nop,
+    }, {
         .name = "dhwbi",
         .translate = translate_dcache,
     }, {
+        .name = "dhwbi.b",
+        .translate = translate_nop,
+    }, {
         .name = "dii",
         .translate = translate_nop,
         .op_flags = XTENSA_OP_PRIVILEGED,
@@ -3133,19 +3195,41 @@ static const XtensaOpcodeOps core_ops[] = {
         .translate = translate_nop,
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
+        .name = "diwbui.p",
+        .translate = translate_diwbuip,
+        .op_flags = XTENSA_OP_PRIVILEGED,
+    }, {
         .name = "dpfl",
         .translate = translate_dcache,
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
+        .name = "dpfm.b",
+        .translate = translate_nop,
+    }, {
+        .name = "dpfm.bf",
+        .translate = translate_nop,
+    }, {
         .name = "dpfr",
         .translate = translate_nop,
     }, {
+        .name = "dpfr.b",
+        .translate = translate_nop,
+    }, {
+        .name = "dpfr.bf",
+        .translate = translate_nop,
+    }, {
         .name = "dpfro",
         .translate = translate_nop,
     }, {
         .name = "dpfw",
         .translate = translate_nop,
     }, {
+        .name = "dpfw.b",
+        .translate = translate_nop,
+    }, {
+        .name = "dpfw.bf",
+        .translate = translate_nop,
+    }, {
         .name = "dpfwo",
         .translate = translate_nop,
     }, {
@@ -3171,6 +3255,9 @@ static const XtensaOpcodeOps core_ops[] = {
         .name = "extw",
         .translate = translate_memw,
     }, {
+        .name = "getex",
+        .translate = translate_getex,
+    }, {
         .name = "hwwdtlba",
         .op_flags = XTENSA_OP_ILL,
     }, {
@@ -3242,6 +3329,10 @@ static const XtensaOpcodeOps core_ops[] = {
         .translate = translate_l32e,
         .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_LOAD,
     }, {
+        .name = "l32ex",
+        .translate = translate_l32ex,
+        .op_flags = XTENSA_OP_LOAD,
+    }, {
         .name = (const char * const[]) {
             "l32i", "l32i.n", NULL,
         },
@@ -3653,11 +3744,30 @@ static const XtensaOpcodeOps core_ops[] = {
         .par = (const uint32_t[]){true},
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
+        .name = "pfend.a",
+        .translate = translate_nop,
+    }, {
+        .name = "pfend.o",
+        .translate = translate_nop,
+    }, {
+        .name = "pfnxt.f",
+        .translate = translate_nop,
+    }, {
+        .name = "pfwait.a",
+        .translate = translate_nop,
+    }, {
+        .name = "pfwait.o",
+        .translate = translate_nop,
+    }, {
         .name = "pitlb",
         .translate = translate_ptlb,
         .par = (const uint32_t[]){false},
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
+        .name = "pptlb",
+        .translate = translate_pptlb,
+        .op_flags = XTENSA_OP_PRIVILEGED,
+    }, {
         .name = "quos",
         .translate = translate_quos,
         .par = (const uint32_t[]){true},
@@ -3744,6 +3854,14 @@ static const XtensaOpcodeOps core_ops[] = {
         .par = (const uint32_t[]){false, 1},
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
+        .name = "rptlb0",
+        .translate = translate_rptlb0,
+        .op_flags = XTENSA_OP_PRIVILEGED,
+    }, {
+        .name = "rptlb1",
+        .translate = translate_rptlb1,
+        .op_flags = XTENSA_OP_PRIVILEGED,
+    }, {
         .name = "rotw",
         .translate = translate_rotw,
         .op_flags = XTENSA_OP_PRIVILEGED |
@@ -3759,450 +3877,739 @@ static const XtensaOpcodeOps core_ops[] = {
     }, {
         .name = "rsr.176",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
         .par = (const uint32_t[]){176},
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.208",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
         .par = (const uint32_t[]){208},
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.acchi",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){ACCHI},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            ACCHI,
+            XTENSA_OPTION_MAC16,
+        },
     }, {
         .name = "rsr.acclo",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){ACCLO},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            ACCLO,
+            XTENSA_OPTION_MAC16,
+        },
     }, {
         .name = "rsr.atomctl",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){ATOMCTL},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            ATOMCTL,
+            XTENSA_OPTION_ATOMCTL,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.br",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){BR},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            BR,
+            XTENSA_OPTION_BOOLEAN,
+        },
+    }, {
+        .name = "rsr.cacheadrdis",
+        .translate = translate_rsr,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            CACHEADRDIS,
+            XTENSA_OPTION_MPU,
+        },
+        .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.cacheattr",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){CACHEATTR},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            CACHEATTR,
+            XTENSA_OPTION_CACHEATTR,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.ccompare0",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){CCOMPARE},
+        .test_ill = test_ill_ccompare,
+        .par = (const uint32_t[]){
+            CCOMPARE,
+            XTENSA_OPTION_TIMER_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.ccompare1",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){CCOMPARE + 1},
+        .test_ill = test_ill_ccompare,
+        .par = (const uint32_t[]){
+            CCOMPARE + 1,
+            XTENSA_OPTION_TIMER_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.ccompare2",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){CCOMPARE + 2},
+        .test_ill = test_ill_ccompare,
+        .par = (const uint32_t[]){
+            CCOMPARE + 2,
+            XTENSA_OPTION_TIMER_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.ccount",
-        .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){CCOUNT},
+        .translate = translate_rsr_ccount,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            CCOUNT,
+            XTENSA_OPTION_TIMER_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_0,
     }, {
         .name = "rsr.configid0",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
         .par = (const uint32_t[]){CONFIGID0},
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.configid1",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
         .par = (const uint32_t[]){CONFIGID1},
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.cpenable",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){CPENABLE},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            CPENABLE,
+            XTENSA_OPTION_COPROCESSOR,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.dbreaka0",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){DBREAKA},
+        .test_ill = test_ill_dbreak,
+        .par = (const uint32_t[]){
+            DBREAKA,
+            XTENSA_OPTION_DEBUG,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.dbreaka1",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){DBREAKA + 1},
+        .test_ill = test_ill_dbreak,
+        .par = (const uint32_t[]){
+            DBREAKA + 1,
+            XTENSA_OPTION_DEBUG,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.dbreakc0",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){DBREAKC},
+        .test_ill = test_ill_dbreak,
+        .par = (const uint32_t[]){
+            DBREAKC,
+            XTENSA_OPTION_DEBUG,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.dbreakc1",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){DBREAKC + 1},
+        .test_ill = test_ill_dbreak,
+        .par = (const uint32_t[]){
+            DBREAKC + 1,
+            XTENSA_OPTION_DEBUG,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.ddr",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){DDR},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            DDR,
+            XTENSA_OPTION_DEBUG,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.debugcause",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){DEBUGCAUSE},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            DEBUGCAUSE,
+            XTENSA_OPTION_DEBUG,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.depc",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){DEPC},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            DEPC,
+            XTENSA_OPTION_EXCEPTION,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.dtlbcfg",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){DTLBCFG},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            DTLBCFG,
+            XTENSA_OPTION_MMU,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.epc1",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){EPC1},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            EPC1,
+            XTENSA_OPTION_EXCEPTION,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.epc2",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){EPC1 + 1},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EPC1 + 1,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.epc3",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){EPC1 + 2},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EPC1 + 2,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.epc4",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){EPC1 + 3},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EPC1 + 3,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.epc5",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){EPC1 + 4},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EPC1 + 4,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.epc6",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){EPC1 + 5},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EPC1 + 5,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.epc7",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){EPC1 + 6},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EPC1 + 6,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.eps2",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){EPS2},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EPS2,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.eps3",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){EPS2 + 1},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EPS2 + 1,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.eps4",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){EPS2 + 2},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EPS2 + 2,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.eps5",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){EPS2 + 3},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EPS2 + 3,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.eps6",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){EPS2 + 4},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EPS2 + 4,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.eps7",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){EPS2 + 5},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EPS2 + 5,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
+        .op_flags = XTENSA_OP_PRIVILEGED,
+    }, {
+        .name = "rsr.eraccess",
+        .translate = translate_rsr,
+        .par = (const uint32_t[]){ERACCESS},
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.exccause",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){EXCCAUSE},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            EXCCAUSE,
+            XTENSA_OPTION_EXCEPTION,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.excsave1",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){EXCSAVE1},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            EXCSAVE1,
+            XTENSA_OPTION_EXCEPTION,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.excsave2",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){EXCSAVE1 + 1},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EXCSAVE1 + 1,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.excsave3",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){EXCSAVE1 + 2},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EXCSAVE1 + 2,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.excsave4",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){EXCSAVE1 + 3},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EXCSAVE1 + 3,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.excsave5",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){EXCSAVE1 + 4},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EXCSAVE1 + 4,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.excsave6",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){EXCSAVE1 + 5},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EXCSAVE1 + 5,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.excsave7",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){EXCSAVE1 + 6},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EXCSAVE1 + 6,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.excvaddr",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){EXCVADDR},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            EXCVADDR,
+            XTENSA_OPTION_EXCEPTION,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.ibreaka0",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){IBREAKA},
+        .test_ill = test_ill_ibreak,
+        .par = (const uint32_t[]){
+            IBREAKA,
+            XTENSA_OPTION_DEBUG,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.ibreaka1",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){IBREAKA + 1},
+        .test_ill = test_ill_ibreak,
+        .par = (const uint32_t[]){
+            IBREAKA + 1,
+            XTENSA_OPTION_DEBUG,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.ibreakenable",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){IBREAKENABLE},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            IBREAKENABLE,
+            XTENSA_OPTION_DEBUG,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.icount",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){ICOUNT},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            ICOUNT,
+            XTENSA_OPTION_DEBUG,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.icountlevel",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){ICOUNTLEVEL},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            ICOUNTLEVEL,
+            XTENSA_OPTION_DEBUG,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.intclear",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){INTCLEAR},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            INTCLEAR,
+            XTENSA_OPTION_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.intenable",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){INTENABLE},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            INTENABLE,
+            XTENSA_OPTION_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.interrupt",
-        .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){INTSET},
+        .translate = translate_rsr_ccount,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            INTSET,
+            XTENSA_OPTION_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_0,
     }, {
         .name = "rsr.intset",
-        .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){INTSET},
+        .translate = translate_rsr_ccount,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            INTSET,
+            XTENSA_OPTION_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_0,
     }, {
         .name = "rsr.itlbcfg",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){ITLBCFG},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            ITLBCFG,
+            XTENSA_OPTION_MMU,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.lbeg",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){LBEG},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            LBEG,
+            XTENSA_OPTION_LOOP,
+        },
     }, {
         .name = "rsr.lcount",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){LCOUNT},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            LCOUNT,
+            XTENSA_OPTION_LOOP,
+        },
     }, {
         .name = "rsr.lend",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){LEND},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            LEND,
+            XTENSA_OPTION_LOOP,
+        },
     }, {
         .name = "rsr.litbase",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){LITBASE},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            LITBASE,
+            XTENSA_OPTION_EXTENDED_L32R,
+        },
     }, {
         .name = "rsr.m0",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){MR},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            MR,
+            XTENSA_OPTION_MAC16,
+        },
     }, {
         .name = "rsr.m1",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){MR + 1},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            MR + 1,
+            XTENSA_OPTION_MAC16,
+        },
     }, {
         .name = "rsr.m2",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){MR + 2},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            MR + 2,
+            XTENSA_OPTION_MAC16,
+        },
     }, {
         .name = "rsr.m3",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){MR + 3},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            MR + 3,
+            XTENSA_OPTION_MAC16,
+        },
     }, {
         .name = "rsr.memctl",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
         .par = (const uint32_t[]){MEMCTL},
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
+        .name = "rsr.mecr",
+        .translate = translate_rsr,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            MECR,
+            XTENSA_OPTION_MEMORY_ECC_PARITY,
+        },
+        .op_flags = XTENSA_OP_PRIVILEGED,
+    }, {
+        .name = "rsr.mepc",
+        .translate = translate_rsr,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            MEPC,
+            XTENSA_OPTION_MEMORY_ECC_PARITY,
+        },
+        .op_flags = XTENSA_OP_PRIVILEGED,
+    }, {
+        .name = "rsr.meps",
+        .translate = translate_rsr,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            MEPS,
+            XTENSA_OPTION_MEMORY_ECC_PARITY,
+        },
+        .op_flags = XTENSA_OP_PRIVILEGED,
+    }, {
+        .name = "rsr.mesave",
+        .translate = translate_rsr,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            MESAVE,
+            XTENSA_OPTION_MEMORY_ECC_PARITY,
+        },
+        .op_flags = XTENSA_OP_PRIVILEGED,
+    }, {
+        .name = "rsr.mesr",
+        .translate = translate_rsr,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            MESR,
+            XTENSA_OPTION_MEMORY_ECC_PARITY,
+        },
+        .op_flags = XTENSA_OP_PRIVILEGED,
+    }, {
+        .name = "rsr.mevaddr",
+        .translate = translate_rsr,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            MESR,
+            XTENSA_OPTION_MEMORY_ECC_PARITY,
+        },
+        .op_flags = XTENSA_OP_PRIVILEGED,
+    }, {
         .name = "rsr.misc0",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){MISC},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            MISC,
+            XTENSA_OPTION_MISC_SR,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.misc1",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){MISC + 1},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            MISC + 1,
+            XTENSA_OPTION_MISC_SR,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.misc2",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){MISC + 2},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            MISC + 2,
+            XTENSA_OPTION_MISC_SR,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.misc3",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){MISC + 3},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            MISC + 3,
+            XTENSA_OPTION_MISC_SR,
+        },
+        .op_flags = XTENSA_OP_PRIVILEGED,
+    }, {
+        .name = "rsr.mpucfg",
+        .translate = translate_rsr,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            MPUCFG,
+            XTENSA_OPTION_MPU,
+        },
+        .op_flags = XTENSA_OP_PRIVILEGED,
+    }, {
+        .name = "rsr.mpuenb",
+        .translate = translate_rsr,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            MPUENB,
+            XTENSA_OPTION_MPU,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.prefctl",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
         .par = (const uint32_t[]){PREFCTL},
     }, {
         .name = "rsr.prid",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){PRID},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            PRID,
+            XTENSA_OPTION_PROCESSOR_ID,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.ps",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){PS},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            PS,
+            XTENSA_OPTION_EXCEPTION,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.ptevaddr",
-        .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){PTEVADDR},
+        .translate = translate_rsr_ptevaddr,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            PTEVADDR,
+            XTENSA_OPTION_MMU,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.rasid",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){RASID},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            RASID,
+            XTENSA_OPTION_MMU,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.sar",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
         .par = (const uint32_t[]){SAR},
     }, {
         .name = "rsr.scompare1",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){SCOMPARE1},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            SCOMPARE1,
+            XTENSA_OPTION_CONDITIONAL_STORE,
+        },
     }, {
         .name = "rsr.vecbase",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){VECBASE},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            VECBASE,
+            XTENSA_OPTION_RELOCATABLE_VECTOR,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.windowbase",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){WINDOW_BASE},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            WINDOW_BASE,
+            XTENSA_OPTION_WINDOWED_REGISTER,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsr.windowstart",
         .translate = translate_rsr,
-        .test_ill = test_ill_rsr,
-        .par = (const uint32_t[]){WINDOW_START},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            WINDOW_START,
+            XTENSA_OPTION_WINDOWED_REGISTER,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "rsync",
@@ -4239,6 +4646,10 @@ static const XtensaOpcodeOps core_ops[] = {
         .translate = translate_s32e,
         .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_STORE,
     }, {
+        .name = "s32ex",
+        .translate = translate_s32ex,
+        .op_flags = XTENSA_OP_LOAD | XTENSA_OP_STORE,
+    }, {
         .name = (const char * const[]) {
             "s32i", "s32i.n", "s32nb", NULL,
         },
@@ -4363,304 +4774,452 @@ static const XtensaOpcodeOps core_ops[] = {
         .par = (const uint32_t[]){false},
         .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_M1,
     }, {
+        .name = "wptlb",
+        .translate = translate_wptlb,
+        .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_M1,
+    }, {
         .name = "wrmsk_expstate",
         .translate = translate_wrmsk_expstate,
     }, {
         .name = "wsr.176",
-        .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){176},
-        .op_flags = XTENSA_OP_PRIVILEGED,
+        .op_flags = XTENSA_OP_ILL,
     }, {
         .name = "wsr.208",
-        .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){208},
-        .op_flags = XTENSA_OP_PRIVILEGED,
+        .op_flags = XTENSA_OP_ILL,
     }, {
         .name = "wsr.acchi",
-        .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){ACCHI},
+        .translate = translate_wsr_acchi,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            ACCHI,
+            XTENSA_OPTION_MAC16,
+        },
     }, {
         .name = "wsr.acclo",
         .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){ACCLO},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            ACCLO,
+            XTENSA_OPTION_MAC16,
+        },
     }, {
         .name = "wsr.atomctl",
-        .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){ATOMCTL},
+        .translate = translate_wsr_mask,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            ATOMCTL,
+            XTENSA_OPTION_ATOMCTL,
+            0x3f,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "wsr.br",
-        .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){BR},
+        .translate = translate_wsr_mask,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            BR,
+            XTENSA_OPTION_BOOLEAN,
+            0xffff,
+        },
+    }, {
+        .name = "wsr.cacheadrdis",
+        .translate = translate_wsr_mask,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            CACHEADRDIS,
+            XTENSA_OPTION_MPU,
+            0xff,
+        },
+        .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "wsr.cacheattr",
         .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){CACHEATTR},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            CACHEATTR,
+            XTENSA_OPTION_CACHEATTR,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "wsr.ccompare0",
-        .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){CCOMPARE},
+        .translate = translate_wsr_ccompare,
+        .test_ill = test_ill_ccompare,
+        .par = (const uint32_t[]){
+            CCOMPARE,
+            XTENSA_OPTION_TIMER_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_0,
     }, {
         .name = "wsr.ccompare1",
-        .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){CCOMPARE + 1},
+        .translate = translate_wsr_ccompare,
+        .test_ill = test_ill_ccompare,
+        .par = (const uint32_t[]){
+            CCOMPARE + 1,
+            XTENSA_OPTION_TIMER_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_0,
     }, {
         .name = "wsr.ccompare2",
-        .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){CCOMPARE + 2},
+        .translate = translate_wsr_ccompare,
+        .test_ill = test_ill_ccompare,
+        .par = (const uint32_t[]){
+            CCOMPARE + 2,
+            XTENSA_OPTION_TIMER_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_0,
     }, {
         .name = "wsr.ccount",
-        .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){CCOUNT},
+        .translate = translate_wsr_ccount,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            CCOUNT,
+            XTENSA_OPTION_TIMER_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_0,
     }, {
         .name = "wsr.configid0",
-        .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){CONFIGID0},
-        .op_flags = XTENSA_OP_PRIVILEGED,
+        .op_flags = XTENSA_OP_ILL,
     }, {
         .name = "wsr.configid1",
-        .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){CONFIGID1},
-        .op_flags = XTENSA_OP_PRIVILEGED,
+        .op_flags = XTENSA_OP_ILL,
     }, {
         .name = "wsr.cpenable",
-        .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){CPENABLE},
+        .translate = translate_wsr_mask,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            CPENABLE,
+            XTENSA_OPTION_COPROCESSOR,
+            0xff,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_M1,
     }, {
         .name = "wsr.dbreaka0",
-        .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){DBREAKA},
+        .translate = translate_wsr_dbreaka,
+        .test_ill = test_ill_dbreak,
+        .par = (const uint32_t[]){
+            DBREAKA,
+            XTENSA_OPTION_DEBUG,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "wsr.dbreaka1",
-        .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){DBREAKA + 1},
+        .translate = translate_wsr_dbreaka,
+        .test_ill = test_ill_dbreak,
+        .par = (const uint32_t[]){
+            DBREAKA + 1,
+            XTENSA_OPTION_DEBUG,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "wsr.dbreakc0",
-        .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){DBREAKC},
+        .translate = translate_wsr_dbreakc,
+        .test_ill = test_ill_dbreak,
+        .par = (const uint32_t[]){
+            DBREAKC,
+            XTENSA_OPTION_DEBUG,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "wsr.dbreakc1",
-        .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){DBREAKC + 1},
+        .translate = translate_wsr_dbreakc,
+        .test_ill = test_ill_dbreak,
+        .par = (const uint32_t[]){
+            DBREAKC + 1,
+            XTENSA_OPTION_DEBUG,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "wsr.ddr",
         .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){DDR},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            DDR,
+            XTENSA_OPTION_DEBUG,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "wsr.debugcause",
-        .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){DEBUGCAUSE},
-        .op_flags = XTENSA_OP_PRIVILEGED,
+        .op_flags = XTENSA_OP_ILL,
     }, {
         .name = "wsr.depc",
         .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){DEPC},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            DEPC,
+            XTENSA_OPTION_EXCEPTION,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "wsr.dtlbcfg",
-        .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){DTLBCFG},
+        .translate = translate_wsr_mask,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            DTLBCFG,
+            XTENSA_OPTION_MMU,
+            0x01130000,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "wsr.epc1",
         .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){EPC1},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            EPC1,
+            XTENSA_OPTION_EXCEPTION,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "wsr.epc2",
         .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){EPC1 + 1},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EPC1 + 1,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "wsr.epc3",
         .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){EPC1 + 2},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EPC1 + 2,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "wsr.epc4",
         .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){EPC1 + 3},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EPC1 + 3,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "wsr.epc5",
         .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){EPC1 + 4},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EPC1 + 4,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "wsr.epc6",
         .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){EPC1 + 5},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EPC1 + 5,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "wsr.epc7",
         .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){EPC1 + 6},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EPC1 + 6,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "wsr.eps2",
         .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){EPS2},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EPS2,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "wsr.eps3",
         .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){EPS2 + 1},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EPS2 + 1,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "wsr.eps4",
         .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){EPS2 + 2},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EPS2 + 2,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "wsr.eps5",
         .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){EPS2 + 3},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EPS2 + 3,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "wsr.eps6",
         .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){EPS2 + 4},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EPS2 + 4,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "wsr.eps7",
         .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){EPS2 + 5},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EPS2 + 5,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
+        .op_flags = XTENSA_OP_PRIVILEGED,
+    }, {
+        .name = "wsr.eraccess",
+        .translate = translate_wsr_mask,
+        .par = (const uint32_t[]){
+            ERACCESS,
+            0,
+            0xffff,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "wsr.exccause",
         .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){EXCCAUSE},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            EXCCAUSE,
+            XTENSA_OPTION_EXCEPTION,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "wsr.excsave1",
         .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){EXCSAVE1},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            EXCSAVE1,
+            XTENSA_OPTION_EXCEPTION,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "wsr.excsave2",
         .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){EXCSAVE1 + 1},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EXCSAVE1 + 1,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "wsr.excsave3",
         .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){EXCSAVE1 + 2},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EXCSAVE1 + 2,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "wsr.excsave4",
         .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){EXCSAVE1 + 3},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EXCSAVE1 + 3,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "wsr.excsave5",
         .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){EXCSAVE1 + 4},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EXCSAVE1 + 4,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "wsr.excsave6",
         .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){EXCSAVE1 + 5},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EXCSAVE1 + 5,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "wsr.excsave7",
         .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){EXCSAVE1 + 6},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EXCSAVE1 + 6,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "wsr.excvaddr",
         .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){EXCVADDR},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            EXCVADDR,
+            XTENSA_OPTION_EXCEPTION,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "wsr.ibreaka0",
-        .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){IBREAKA},
+        .translate = translate_wsr_ibreaka,
+        .test_ill = test_ill_ibreak,
+        .par = (const uint32_t[]){
+            IBREAKA,
+            XTENSA_OPTION_DEBUG,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_0,
     }, {
         .name = "wsr.ibreaka1",
-        .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){IBREAKA + 1},
+        .translate = translate_wsr_ibreaka,
+        .test_ill = test_ill_ibreak,
+        .par = (const uint32_t[]){
+            IBREAKA + 1,
+            XTENSA_OPTION_DEBUG,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_0,
     }, {
         .name = "wsr.ibreakenable",
-        .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){IBREAKENABLE},
+        .translate = translate_wsr_ibreakenable,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            IBREAKENABLE,
+            XTENSA_OPTION_DEBUG,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_0,
     }, {
         .name = "wsr.icount",
-        .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){ICOUNT},
+        .translate = translate_wsr_icount,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            ICOUNT,
+            XTENSA_OPTION_DEBUG,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "wsr.icountlevel",
-        .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){ICOUNTLEVEL},
+        .translate = translate_wsr_mask,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            ICOUNTLEVEL,
+            XTENSA_OPTION_DEBUG,
+            0xf,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_M1,
     }, {
         .name = "wsr.intclear",
-        .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){INTCLEAR},
+        .translate = translate_wsr_intclear,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            INTCLEAR,
+            XTENSA_OPTION_INTERRUPT,
+        },
         .op_flags =
             XTENSA_OP_PRIVILEGED |
             XTENSA_OP_EXIT_TB_0 |
@@ -4668,8 +5227,11 @@ static const XtensaOpcodeOps core_ops[] = {
     }, {
         .name = "wsr.intenable",
         .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){INTENABLE},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            INTENABLE,
+            XTENSA_OPTION_INTERRUPT,
+        },
         .op_flags =
             XTENSA_OP_PRIVILEGED |
             XTENSA_OP_EXIT_TB_0 |
@@ -4677,167 +5239,296 @@ static const XtensaOpcodeOps core_ops[] = {
     }, {
         .name = "wsr.interrupt",
         .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){INTSET},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            INTSET,
+            XTENSA_OPTION_INTERRUPT,
+        },
         .op_flags =
             XTENSA_OP_PRIVILEGED |
             XTENSA_OP_EXIT_TB_0 |
             XTENSA_OP_CHECK_INTERRUPTS,
     }, {
         .name = "wsr.intset",
-        .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){INTSET},
+        .translate = translate_wsr_intset,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            INTSET,
+            XTENSA_OPTION_INTERRUPT,
+        },
         .op_flags =
             XTENSA_OP_PRIVILEGED |
             XTENSA_OP_EXIT_TB_0 |
             XTENSA_OP_CHECK_INTERRUPTS,
     }, {
         .name = "wsr.itlbcfg",
-        .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){ITLBCFG},
+        .translate = translate_wsr_mask,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            ITLBCFG,
+            XTENSA_OPTION_MMU,
+            0x01130000,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "wsr.lbeg",
         .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){LBEG},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            LBEG,
+            XTENSA_OPTION_LOOP,
+        },
         .op_flags = XTENSA_OP_EXIT_TB_M1,
     }, {
         .name = "wsr.lcount",
         .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){LCOUNT},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            LCOUNT,
+            XTENSA_OPTION_LOOP,
+        },
     }, {
         .name = "wsr.lend",
         .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){LEND},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            LEND,
+            XTENSA_OPTION_LOOP,
+        },
         .op_flags = XTENSA_OP_EXIT_TB_M1,
     }, {
         .name = "wsr.litbase",
-        .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){LITBASE},
+        .translate = translate_wsr_mask,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            LITBASE,
+            XTENSA_OPTION_EXTENDED_L32R,
+            0xfffff001,
+        },
         .op_flags = XTENSA_OP_EXIT_TB_M1,
     }, {
         .name = "wsr.m0",
         .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){MR},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            MR,
+            XTENSA_OPTION_MAC16,
+        },
     }, {
         .name = "wsr.m1",
         .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){MR + 1},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            MR + 1,
+            XTENSA_OPTION_MAC16,
+        },
     }, {
         .name = "wsr.m2",
         .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){MR + 2},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            MR + 2,
+            XTENSA_OPTION_MAC16,
+        },
     }, {
         .name = "wsr.m3",
         .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){MR + 3},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            MR + 3,
+            XTENSA_OPTION_MAC16,
+        },
     }, {
         .name = "wsr.memctl",
-        .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
+        .translate = translate_wsr_memctl,
         .par = (const uint32_t[]){MEMCTL},
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
+        .name = "wsr.mecr",
+        .translate = translate_wsr,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            MECR,
+            XTENSA_OPTION_MEMORY_ECC_PARITY,
+        },
+        .op_flags = XTENSA_OP_PRIVILEGED,
+    }, {
+        .name = "wsr.mepc",
+        .translate = translate_wsr,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            MEPC,
+            XTENSA_OPTION_MEMORY_ECC_PARITY,
+        },
+        .op_flags = XTENSA_OP_PRIVILEGED,
+    }, {
+        .name = "wsr.meps",
+        .translate = translate_wsr,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            MEPS,
+            XTENSA_OPTION_MEMORY_ECC_PARITY,
+        },
+        .op_flags = XTENSA_OP_PRIVILEGED,
+    }, {
+        .name = "wsr.mesave",
+        .translate = translate_wsr,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            MESAVE,
+            XTENSA_OPTION_MEMORY_ECC_PARITY,
+        },
+        .op_flags = XTENSA_OP_PRIVILEGED,
+    }, {
+        .name = "wsr.mesr",
+        .translate = translate_wsr,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            MESR,
+            XTENSA_OPTION_MEMORY_ECC_PARITY,
+        },
+        .op_flags = XTENSA_OP_PRIVILEGED,
+    }, {
+        .name = "wsr.mevaddr",
+        .translate = translate_wsr,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            MESR,
+            XTENSA_OPTION_MEMORY_ECC_PARITY,
+        },
+        .op_flags = XTENSA_OP_PRIVILEGED,
+    }, {
         .name = "wsr.misc0",
         .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){MISC},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            MISC,
+            XTENSA_OPTION_MISC_SR,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "wsr.misc1",
         .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){MISC + 1},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            MISC + 1,
+            XTENSA_OPTION_MISC_SR,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "wsr.misc2",
         .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){MISC + 2},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            MISC + 2,
+            XTENSA_OPTION_MISC_SR,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "wsr.misc3",
         .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){MISC + 3},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            MISC + 3,
+            XTENSA_OPTION_MISC_SR,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "wsr.mmid",
         .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){MMID},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            MMID,
+            XTENSA_OPTION_TRACE_PORT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
+        .name = "wsr.mpuenb",
+        .translate = translate_wsr_mpuenb,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            MPUENB,
+            XTENSA_OPTION_MPU,
+        },
+        .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_M1,
+    }, {
         .name = "wsr.prefctl",
         .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
         .par = (const uint32_t[]){PREFCTL},
     }, {
         .name = "wsr.prid",
-        .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){PRID},
-        .op_flags = XTENSA_OP_PRIVILEGED,
+        .op_flags = XTENSA_OP_ILL,
     }, {
         .name = "wsr.ps",
-        .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){PS},
+        .translate = translate_wsr_ps,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            PS,
+            XTENSA_OPTION_EXCEPTION,
+        },
         .op_flags =
             XTENSA_OP_PRIVILEGED |
             XTENSA_OP_EXIT_TB_M1 |
             XTENSA_OP_CHECK_INTERRUPTS,
     }, {
         .name = "wsr.ptevaddr",
-        .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){PTEVADDR},
+        .translate = translate_wsr_mask,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            PTEVADDR,
+            XTENSA_OPTION_MMU,
+            0xffc00000,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "wsr.rasid",
-        .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){RASID},
+        .translate = translate_wsr_rasid,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            RASID,
+            XTENSA_OPTION_MMU,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_M1,
     }, {
         .name = "wsr.sar",
-        .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
+        .translate = translate_wsr_sar,
         .par = (const uint32_t[]){SAR},
     }, {
         .name = "wsr.scompare1",
         .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){SCOMPARE1},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            SCOMPARE1,
+            XTENSA_OPTION_CONDITIONAL_STORE,
+        },
     }, {
         .name = "wsr.vecbase",
         .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){VECBASE},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            VECBASE,
+            XTENSA_OPTION_RELOCATABLE_VECTOR,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "wsr.windowbase",
-        .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){WINDOW_BASE},
+        .translate = translate_wsr_windowbase,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            WINDOW_BASE,
+            XTENSA_OPTION_WINDOWED_REGISTER,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED |
             XTENSA_OP_EXIT_TB_M1 |
             XTENSA_OP_SYNC_REGISTER_WINDOW,
     }, {
         .name = "wsr.windowstart",
-        .translate = translate_wsr,
-        .test_ill = test_ill_wsr,
-        .par = (const uint32_t[]){WINDOW_START},
+        .translate = translate_wsr_windowstart,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            WINDOW_START,
+            XTENSA_OPTION_WINDOWED_REGISTER,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_M1,
     }, {
         .name = "wur.expstate",
@@ -4845,12 +5536,12 @@ static const XtensaOpcodeOps core_ops[] = {
         .par = (const uint32_t[]){EXPSTATE},
     }, {
         .name = "wur.fcr",
-        .translate = translate_wur,
+        .translate = translate_wur_fcr,
         .par = (const uint32_t[]){FCR},
         .coprocessor = 0x1,
     }, {
         .name = "wur.fsr",
-        .translate = translate_wur,
+        .translate = translate_wur_fsr,
         .par = (const uint32_t[]){FSR},
         .coprocessor = 0x1,
     }, {
@@ -4866,471 +5557,717 @@ static const XtensaOpcodeOps core_ops[] = {
         .par = (const uint32_t[]){BOOLEAN_XOR},
     }, {
         .name = "xsr.176",
-        .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){176},
-        .op_flags = XTENSA_OP_PRIVILEGED,
+        .op_flags = XTENSA_OP_ILL,
     }, {
         .name = "xsr.208",
-        .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){208},
-        .op_flags = XTENSA_OP_PRIVILEGED,
+        .op_flags = XTENSA_OP_ILL,
     }, {
         .name = "xsr.acchi",
-        .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){ACCHI},
+        .translate = translate_xsr_acchi,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            ACCHI,
+            XTENSA_OPTION_MAC16,
+        },
     }, {
         .name = "xsr.acclo",
         .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){ACCLO},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            ACCLO,
+            XTENSA_OPTION_MAC16,
+        },
     }, {
         .name = "xsr.atomctl",
-        .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){ATOMCTL},
+        .translate = translate_xsr_mask,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            ATOMCTL,
+            XTENSA_OPTION_ATOMCTL,
+            0x3f,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "xsr.br",
-        .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){BR},
+        .translate = translate_xsr_mask,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            BR,
+            XTENSA_OPTION_BOOLEAN,
+            0xffff,
+        },
+    }, {
+        .name = "xsr.cacheadrdis",
+        .translate = translate_xsr_mask,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            CACHEADRDIS,
+            XTENSA_OPTION_MPU,
+            0xff,
+        },
+        .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "xsr.cacheattr",
         .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){CACHEATTR},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            CACHEATTR,
+            XTENSA_OPTION_CACHEATTR,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "xsr.ccompare0",
-        .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){CCOMPARE},
+        .translate = translate_xsr_ccompare,
+        .test_ill = test_ill_ccompare,
+        .par = (const uint32_t[]){
+            CCOMPARE,
+            XTENSA_OPTION_TIMER_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_0,
     }, {
         .name = "xsr.ccompare1",
-        .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){CCOMPARE + 1},
+        .translate = translate_xsr_ccompare,
+        .test_ill = test_ill_ccompare,
+        .par = (const uint32_t[]){
+            CCOMPARE + 1,
+            XTENSA_OPTION_TIMER_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_0,
     }, {
         .name = "xsr.ccompare2",
-        .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){CCOMPARE + 2},
+        .translate = translate_xsr_ccompare,
+        .test_ill = test_ill_ccompare,
+        .par = (const uint32_t[]){
+            CCOMPARE + 2,
+            XTENSA_OPTION_TIMER_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_0,
     }, {
         .name = "xsr.ccount",
-        .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){CCOUNT},
+        .translate = translate_xsr_ccount,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            CCOUNT,
+            XTENSA_OPTION_TIMER_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_0,
     }, {
         .name = "xsr.configid0",
-        .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){CONFIGID0},
-        .op_flags = XTENSA_OP_PRIVILEGED,
+        .op_flags = XTENSA_OP_ILL,
     }, {
         .name = "xsr.configid1",
-        .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){CONFIGID1},
-        .op_flags = XTENSA_OP_PRIVILEGED,
+        .op_flags = XTENSA_OP_ILL,
     }, {
         .name = "xsr.cpenable",
-        .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){CPENABLE},
+        .translate = translate_xsr_mask,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            CPENABLE,
+            XTENSA_OPTION_COPROCESSOR,
+            0xff,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_M1,
     }, {
         .name = "xsr.dbreaka0",
-        .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){DBREAKA},
+        .translate = translate_xsr_dbreaka,
+        .test_ill = test_ill_dbreak,
+        .par = (const uint32_t[]){
+            DBREAKA,
+            XTENSA_OPTION_DEBUG,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "xsr.dbreaka1",
-        .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){DBREAKA + 1},
+        .translate = translate_xsr_dbreaka,
+        .test_ill = test_ill_dbreak,
+        .par = (const uint32_t[]){
+            DBREAKA + 1,
+            XTENSA_OPTION_DEBUG,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "xsr.dbreakc0",
-        .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){DBREAKC},
+        .translate = translate_xsr_dbreakc,
+        .test_ill = test_ill_dbreak,
+        .par = (const uint32_t[]){
+            DBREAKC,
+            XTENSA_OPTION_DEBUG,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "xsr.dbreakc1",
-        .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){DBREAKC + 1},
+        .translate = translate_xsr_dbreakc,
+        .test_ill = test_ill_dbreak,
+        .par = (const uint32_t[]){
+            DBREAKC + 1,
+            XTENSA_OPTION_DEBUG,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "xsr.ddr",
         .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){DDR},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            DDR,
+            XTENSA_OPTION_DEBUG,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "xsr.debugcause",
-        .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){DEBUGCAUSE},
-        .op_flags = XTENSA_OP_PRIVILEGED,
+        .op_flags = XTENSA_OP_ILL,
     }, {
         .name = "xsr.depc",
         .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){DEPC},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            DEPC,
+            XTENSA_OPTION_EXCEPTION,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "xsr.dtlbcfg",
-        .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){DTLBCFG},
+        .translate = translate_xsr_mask,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            DTLBCFG,
+            XTENSA_OPTION_MMU,
+            0x01130000,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "xsr.epc1",
         .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){EPC1},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            EPC1,
+            XTENSA_OPTION_EXCEPTION,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "xsr.epc2",
         .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){EPC1 + 1},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EPC1 + 1,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "xsr.epc3",
         .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){EPC1 + 2},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EPC1 + 2,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "xsr.epc4",
         .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){EPC1 + 3},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EPC1 + 3,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "xsr.epc5",
         .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){EPC1 + 4},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EPC1 + 4,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "xsr.epc6",
         .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){EPC1 + 5},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EPC1 + 5,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "xsr.epc7",
         .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){EPC1 + 6},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EPC1 + 6,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "xsr.eps2",
         .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){EPS2},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EPS2,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "xsr.eps3",
         .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){EPS2 + 1},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EPS2 + 1,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "xsr.eps4",
         .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){EPS2 + 2},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EPS2 + 2,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "xsr.eps5",
         .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){EPS2 + 3},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EPS2 + 3,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "xsr.eps6",
         .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){EPS2 + 4},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EPS2 + 4,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "xsr.eps7",
         .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){EPS2 + 5},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EPS2 + 5,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
+        .op_flags = XTENSA_OP_PRIVILEGED,
+    }, {
+        .name = "xsr.eraccess",
+        .translate = translate_xsr_mask,
+        .par = (const uint32_t[]){
+            ERACCESS,
+            0,
+            0xffff,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "xsr.exccause",
         .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){EXCCAUSE},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            EXCCAUSE,
+            XTENSA_OPTION_EXCEPTION,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "xsr.excsave1",
         .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){EXCSAVE1},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            EXCSAVE1,
+            XTENSA_OPTION_EXCEPTION,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "xsr.excsave2",
         .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){EXCSAVE1 + 1},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EXCSAVE1 + 1,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "xsr.excsave3",
         .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){EXCSAVE1 + 2},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EXCSAVE1 + 2,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "xsr.excsave4",
         .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){EXCSAVE1 + 3},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EXCSAVE1 + 3,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "xsr.excsave5",
         .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){EXCSAVE1 + 4},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EXCSAVE1 + 4,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "xsr.excsave6",
         .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){EXCSAVE1 + 5},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EXCSAVE1 + 5,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "xsr.excsave7",
         .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){EXCSAVE1 + 6},
+        .test_ill = test_ill_hpi,
+        .par = (const uint32_t[]){
+            EXCSAVE1 + 6,
+            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "xsr.excvaddr",
         .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){EXCVADDR},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            EXCVADDR,
+            XTENSA_OPTION_EXCEPTION,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "xsr.ibreaka0",
-        .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){IBREAKA},
+        .translate = translate_xsr_ibreaka,
+        .test_ill = test_ill_ibreak,
+        .par = (const uint32_t[]){
+            IBREAKA,
+            XTENSA_OPTION_DEBUG,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_0,
     }, {
         .name = "xsr.ibreaka1",
-        .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){IBREAKA + 1},
+        .translate = translate_xsr_ibreaka,
+        .test_ill = test_ill_ibreak,
+        .par = (const uint32_t[]){
+            IBREAKA + 1,
+            XTENSA_OPTION_DEBUG,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_0,
     }, {
         .name = "xsr.ibreakenable",
-        .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){IBREAKENABLE},
+        .translate = translate_xsr_ibreakenable,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            IBREAKENABLE,
+            XTENSA_OPTION_DEBUG,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_0,
     }, {
         .name = "xsr.icount",
-        .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){ICOUNT},
+        .translate = translate_xsr_icount,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            ICOUNT,
+            XTENSA_OPTION_DEBUG,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "xsr.icountlevel",
-        .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){ICOUNTLEVEL},
+        .translate = translate_xsr_mask,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            ICOUNTLEVEL,
+            XTENSA_OPTION_DEBUG,
+            0xf,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_M1,
     }, {
         .name = "xsr.intclear",
-        .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){INTCLEAR},
-        .op_flags =
-            XTENSA_OP_PRIVILEGED |
-            XTENSA_OP_EXIT_TB_0 |
-            XTENSA_OP_CHECK_INTERRUPTS,
+        .op_flags = XTENSA_OP_ILL,
     }, {
         .name = "xsr.intenable",
         .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){INTENABLE},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            INTENABLE,
+            XTENSA_OPTION_INTERRUPT,
+        },
         .op_flags =
             XTENSA_OP_PRIVILEGED |
             XTENSA_OP_EXIT_TB_0 |
             XTENSA_OP_CHECK_INTERRUPTS,
     }, {
         .name = "xsr.interrupt",
-        .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){INTSET},
-        .op_flags =
-            XTENSA_OP_PRIVILEGED |
-            XTENSA_OP_EXIT_TB_0 |
-            XTENSA_OP_CHECK_INTERRUPTS,
+        .op_flags = XTENSA_OP_ILL,
     }, {
         .name = "xsr.intset",
-        .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){INTSET},
-        .op_flags =
-            XTENSA_OP_PRIVILEGED |
-            XTENSA_OP_EXIT_TB_0 |
-            XTENSA_OP_CHECK_INTERRUPTS,
+        .op_flags = XTENSA_OP_ILL,
     }, {
         .name = "xsr.itlbcfg",
-        .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){ITLBCFG},
+        .translate = translate_xsr_mask,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            ITLBCFG,
+            XTENSA_OPTION_MMU,
+            0x01130000,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "xsr.lbeg",
         .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){LBEG},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            LBEG,
+            XTENSA_OPTION_LOOP,
+        },
         .op_flags = XTENSA_OP_EXIT_TB_M1,
     }, {
         .name = "xsr.lcount",
         .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){LCOUNT},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            LCOUNT,
+            XTENSA_OPTION_LOOP,
+        },
     }, {
         .name = "xsr.lend",
         .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){LEND},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            LEND,
+            XTENSA_OPTION_LOOP,
+        },
         .op_flags = XTENSA_OP_EXIT_TB_M1,
     }, {
         .name = "xsr.litbase",
-        .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){LITBASE},
+        .translate = translate_xsr_mask,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            LITBASE,
+            XTENSA_OPTION_EXTENDED_L32R,
+            0xfffff001,
+        },
         .op_flags = XTENSA_OP_EXIT_TB_M1,
     }, {
         .name = "xsr.m0",
         .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){MR},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            MR,
+            XTENSA_OPTION_MAC16,
+        },
     }, {
         .name = "xsr.m1",
         .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){MR + 1},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            MR + 1,
+            XTENSA_OPTION_MAC16,
+        },
     }, {
         .name = "xsr.m2",
         .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){MR + 2},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            MR + 2,
+            XTENSA_OPTION_MAC16,
+        },
     }, {
         .name = "xsr.m3",
         .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){MR + 3},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            MR + 3,
+            XTENSA_OPTION_MAC16,
+        },
     }, {
         .name = "xsr.memctl",
-        .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
+        .translate = translate_xsr_memctl,
         .par = (const uint32_t[]){MEMCTL},
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
+        .name = "xsr.mecr",
+        .translate = translate_xsr,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            MECR,
+            XTENSA_OPTION_MEMORY_ECC_PARITY,
+        },
+        .op_flags = XTENSA_OP_PRIVILEGED,
+    }, {
+        .name = "xsr.mepc",
+        .translate = translate_xsr,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            MEPC,
+            XTENSA_OPTION_MEMORY_ECC_PARITY,
+        },
+        .op_flags = XTENSA_OP_PRIVILEGED,
+    }, {
+        .name = "xsr.meps",
+        .translate = translate_xsr,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            MEPS,
+            XTENSA_OPTION_MEMORY_ECC_PARITY,
+        },
+        .op_flags = XTENSA_OP_PRIVILEGED,
+    }, {
+        .name = "xsr.mesave",
+        .translate = translate_xsr,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            MESAVE,
+            XTENSA_OPTION_MEMORY_ECC_PARITY,
+        },
+        .op_flags = XTENSA_OP_PRIVILEGED,
+    }, {
+        .name = "xsr.mesr",
+        .translate = translate_xsr,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            MESR,
+            XTENSA_OPTION_MEMORY_ECC_PARITY,
+        },
+        .op_flags = XTENSA_OP_PRIVILEGED,
+    }, {
+        .name = "xsr.mevaddr",
+        .translate = translate_xsr,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            MESR,
+            XTENSA_OPTION_MEMORY_ECC_PARITY,
+        },
+        .op_flags = XTENSA_OP_PRIVILEGED,
+    }, {
         .name = "xsr.misc0",
         .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){MISC},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            MISC,
+            XTENSA_OPTION_MISC_SR,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "xsr.misc1",
         .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){MISC + 1},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            MISC + 1,
+            XTENSA_OPTION_MISC_SR,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "xsr.misc2",
         .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){MISC + 2},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            MISC + 2,
+            XTENSA_OPTION_MISC_SR,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "xsr.misc3",
         .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){MISC + 3},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            MISC + 3,
+            XTENSA_OPTION_MISC_SR,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
+        .name = "xsr.mpuenb",
+        .translate = translate_xsr_mpuenb,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            MPUENB,
+            XTENSA_OPTION_MPU,
+        },
+        .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_M1,
+    }, {
         .name = "xsr.prefctl",
         .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
         .par = (const uint32_t[]){PREFCTL},
     }, {
         .name = "xsr.prid",
-        .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){PRID},
-        .op_flags = XTENSA_OP_PRIVILEGED,
+        .op_flags = XTENSA_OP_ILL,
     }, {
         .name = "xsr.ps",
-        .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){PS},
+        .translate = translate_xsr_ps,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            PS,
+            XTENSA_OPTION_EXCEPTION,
+        },
         .op_flags =
             XTENSA_OP_PRIVILEGED |
             XTENSA_OP_EXIT_TB_M1 |
             XTENSA_OP_CHECK_INTERRUPTS,
     }, {
         .name = "xsr.ptevaddr",
-        .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){PTEVADDR},
+        .translate = translate_xsr_mask,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            PTEVADDR,
+            XTENSA_OPTION_MMU,
+            0xffc00000,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "xsr.rasid",
-        .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){RASID},
+        .translate = translate_xsr_rasid,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            RASID,
+            XTENSA_OPTION_MMU,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_M1,
     }, {
         .name = "xsr.sar",
-        .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
+        .translate = translate_xsr_sar,
         .par = (const uint32_t[]){SAR},
     }, {
         .name = "xsr.scompare1",
         .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){SCOMPARE1},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            SCOMPARE1,
+            XTENSA_OPTION_CONDITIONAL_STORE,
+        },
     }, {
         .name = "xsr.vecbase",
         .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){VECBASE},
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            VECBASE,
+            XTENSA_OPTION_RELOCATABLE_VECTOR,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED,
     }, {
         .name = "xsr.windowbase",
-        .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){WINDOW_BASE},
+        .translate = translate_xsr_windowbase,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            WINDOW_BASE,
+            XTENSA_OPTION_WINDOWED_REGISTER,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED |
             XTENSA_OP_EXIT_TB_M1 |
             XTENSA_OP_SYNC_REGISTER_WINDOW,
     }, {
         .name = "xsr.windowstart",
-        .translate = translate_xsr,
-        .test_ill = test_ill_xsr,
-        .par = (const uint32_t[]){WINDOW_START},
+        .translate = translate_xsr_windowstart,
+        .test_ill = test_ill_sr,
+        .par = (const uint32_t[]){
+            WINDOW_START,
+            XTENSA_OPTION_WINDOWED_REGISTER,
+        },
         .op_flags = XTENSA_OP_PRIVILEGED | XTENSA_OP_EXIT_TB_M1,
     },
 };
diff --git a/tests/Makefile.include b/tests/Makefile.include
index 60de085ee1..1865f6b322 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -45,7 +45,7 @@ SYSEMU_TARGET_LIST := $(subst -softmmu.mak,,$(notdir \
 
 check-unit-y += tests/check-qdict$(EXESUF)
 check-unit-y += tests/check-block-qdict$(EXESUF)
-check-unit-y += tests/test-char$(EXESUF)
+check-unit-$(CONFIG_SOFTMMU) += tests/test-char$(EXESUF)
 check-unit-y += tests/check-qnum$(EXESUF)
 check-unit-y += tests/check-qstring$(EXESUF)
 check-unit-y += tests/check-qlist$(EXESUF)
@@ -61,21 +61,21 @@ check-unit-y += tests/test-string-input-visitor$(EXESUF)
 check-unit-y += tests/test-string-output-visitor$(EXESUF)
 check-unit-y += tests/test-qmp-event$(EXESUF)
 check-unit-y += tests/test-opts-visitor$(EXESUF)
-check-unit-y += tests/test-coroutine$(EXESUF)
+check-unit-$(CONFIG_BLOCK) += tests/test-coroutine$(EXESUF)
 check-unit-y += tests/test-visitor-serialization$(EXESUF)
 check-unit-y += tests/test-iov$(EXESUF)
-check-unit-y += tests/test-aio$(EXESUF)
-check-unit-y += tests/test-aio-multithread$(EXESUF)
-check-unit-y += tests/test-throttle$(EXESUF)
-check-unit-y += tests/test-thread-pool$(EXESUF)
-check-unit-y += tests/test-hbitmap$(EXESUF)
-check-unit-y += tests/test-bdrv-drain$(EXESUF)
-check-unit-y += tests/test-bdrv-graph-mod$(EXESUF)
-check-unit-y += tests/test-blockjob$(EXESUF)
-check-unit-y += tests/test-blockjob-txn$(EXESUF)
-check-unit-y += tests/test-block-backend$(EXESUF)
-check-unit-y += tests/test-block-iothread$(EXESUF)
-check-unit-y += tests/test-image-locking$(EXESUF)
+check-unit-$(CONFIG_BLOCK) += tests/test-aio$(EXESUF)
+check-unit-$(CONFIG_BLOCK) += tests/test-aio-multithread$(EXESUF)
+check-unit-$(CONFIG_BLOCK) += tests/test-throttle$(EXESUF)
+check-unit-$(CONFIG_BLOCK) += tests/test-thread-pool$(EXESUF)
+check-unit-$(CONFIG_BLOCK) += tests/test-hbitmap$(EXESUF)
+check-unit-$(CONFIG_BLOCK) += tests/test-bdrv-drain$(EXESUF)
+check-unit-$(CONFIG_BLOCK) += tests/test-bdrv-graph-mod$(EXESUF)
+check-unit-$(CONFIG_BLOCK) += tests/test-blockjob$(EXESUF)
+check-unit-$(CONFIG_BLOCK) += tests/test-blockjob-txn$(EXESUF)
+check-unit-$(CONFIG_BLOCK) += tests/test-block-backend$(EXESUF)
+check-unit-$(CONFIG_BLOCK) += tests/test-block-iothread$(EXESUF)
+check-unit-$(CONFIG_BLOCK) += tests/test-image-locking$(EXESUF)
 check-unit-y += tests/test-x86-cpuid$(EXESUF)
 # all code tested by test-x86-cpuid is inside topology.h
 ifeq ($(CONFIG_SOFTMMU),y)
@@ -101,40 +101,40 @@ check-unit-y += tests/check-qom-interface$(EXESUF)
 check-unit-y += tests/check-qom-proplist$(EXESUF)
 check-unit-y += tests/test-qemu-opts$(EXESUF)
 check-unit-y += tests/test-keyval$(EXESUF)
-check-unit-y += tests/test-write-threshold$(EXESUF)
-check-unit-y += tests/test-crypto-hash$(EXESUF)
-check-speed-y += tests/benchmark-crypto-hash$(EXESUF)
-check-unit-y += tests/test-crypto-hmac$(EXESUF)
-check-speed-y += tests/benchmark-crypto-hmac$(EXESUF)
-check-unit-y += tests/test-crypto-cipher$(EXESUF)
-check-speed-y += tests/benchmark-crypto-cipher$(EXESUF)
-check-unit-y += tests/test-crypto-secret$(EXESUF)
-check-unit-$(CONFIG_GNUTLS) += tests/test-crypto-tlscredsx509$(EXESUF)
-check-unit-$(CONFIG_GNUTLS) += tests/test-crypto-tlssession$(EXESUF)
+check-unit-$(CONFIG_BLOCK) += tests/test-write-threshold$(EXESUF)
+check-unit-$(CONFIG_BLOCK) += tests/test-crypto-hash$(EXESUF)
+check-speed-$(CONFIG_BLOCK) += tests/benchmark-crypto-hash$(EXESUF)
+check-unit-$(CONFIG_BLOCK) += tests/test-crypto-hmac$(EXESUF)
+check-speed-$(CONFIG_BLOCK) += tests/benchmark-crypto-hmac$(EXESUF)
+check-unit-$(CONFIG_BLOCK) += tests/test-crypto-cipher$(EXESUF)
+check-speed-$(CONFIG_BLOCK) += tests/benchmark-crypto-cipher$(EXESUF)
+check-unit-$(CONFIG_BLOCK) += tests/test-crypto-secret$(EXESUF)
+check-unit-$(call land,$(CONFIG_BLOCK),$(CONFIG_GNUTLS)) += tests/test-crypto-tlscredsx509$(EXESUF)
+check-unit-$(call land,$(CONFIG_BLOCK),$(CONFIG_GNUTLS)) += tests/test-crypto-tlssession$(EXESUF)
 ifneq (,$(findstring qemu-ga,$(TOOLS)))
 check-unit-$(call land,$(CONFIG_LINUX),$(CONFIG_VIRTIO_SERIAL)) += tests/test-qga$(EXESUF)
 endif
 check-unit-y += tests/test-timed-average$(EXESUF)
 check-unit-$(CONFIG_INOTIFY1) += tests/test-util-filemonitor$(EXESUF)
 check-unit-y += tests/test-util-sockets$(EXESUF)
-check-unit-y += tests/test-authz-simple$(EXESUF)
-check-unit-y += tests/test-authz-list$(EXESUF)
-check-unit-y += tests/test-authz-listfile$(EXESUF)
-check-unit-$(CONFIG_AUTH_PAM) += tests/test-authz-pam$(EXESUF)
-check-unit-y += tests/test-io-task$(EXESUF)
-check-unit-y += tests/test-io-channel-socket$(EXESUF)
-check-unit-y += tests/test-io-channel-file$(EXESUF)
-check-unit-$(CONFIG_GNUTLS) += tests/test-io-channel-tls$(EXESUF)
-check-unit-y += tests/test-io-channel-command$(EXESUF)
-check-unit-y += tests/test-io-channel-buffer$(EXESUF)
+check-unit-$(CONFIG_BLOCK) += tests/test-authz-simple$(EXESUF)
+check-unit-$(CONFIG_BLOCK) += tests/test-authz-list$(EXESUF)
+check-unit-$(CONFIG_BLOCK) += tests/test-authz-listfile$(EXESUF)
+check-unit-$(call land,$(CONFIG_BLOCK),$(CONFIG_AUTH_PAM)) += tests/test-authz-pam$(EXESUF)
+check-unit-$(CONFIG_BLOCK) += tests/test-io-task$(EXESUF)
+check-unit-$(CONFIG_BLOCK) += tests/test-io-channel-socket$(EXESUF)
+check-unit-$(CONFIG_BLOCK) += tests/test-io-channel-file$(EXESUF)
+check-unit-$(call land,$(CONFIG_BLOCK),$(CONFIG_GNUTLS)) += tests/test-io-channel-tls$(EXESUF)
+check-unit-$(CONFIG_BLOCK) += tests/test-io-channel-command$(EXESUF)
+check-unit-$(CONFIG_BLOCK) += tests/test-io-channel-buffer$(EXESUF)
 check-unit-y += tests/test-base64$(EXESUF)
-check-unit-$(if $(CONFIG_NETTLE),y,$(CONFIG_GCRYPT)) += tests/test-crypto-pbkdf$(EXESUF)
-check-unit-y += tests/test-crypto-ivgen$(EXESUF)
-check-unit-y += tests/test-crypto-afsplit$(EXESUF)
-check-unit-y += tests/test-crypto-xts$(EXESUF)
-check-unit-y += tests/test-crypto-block$(EXESUF)
+check-unit-$(call land,$(CONFIG_BLOCK),$(if $(CONFIG_NETTLE),y,$(CONFIG_GCRYPT))) += tests/test-crypto-pbkdf$(EXESUF)
+check-unit-$(CONFIG_BLOCK) += tests/test-crypto-ivgen$(EXESUF)
+check-unit-$(CONFIG_BLOCK)  += tests/test-crypto-afsplit$(EXESUF)
+check-unit-$(CONFIG_BLOCK)  += tests/test-crypto-xts$(EXESUF)
+check-unit-$(CONFIG_BLOCK)  += tests/test-crypto-block$(EXESUF)
 check-unit-y += tests/test-logging$(EXESUF)
-check-unit-$(CONFIG_REPLICATION) += tests/test-replication$(EXESUF)
+check-unit-$(call land,$(CONFIG_BLOCK),$(CONFIG_REPLICATION)) += tests/test-replication$(EXESUF)
 check-unit-y += tests/test-bufferiszero$(EXESUF)
 check-unit-y += tests/test-uuid$(EXESUF)
 check-unit-y += tests/ptimer-test$(EXESUF)
@@ -468,19 +468,19 @@ qapi-schema += unknown-expr-key.json
 
 check-qapi-schema-y := $(addprefix tests/qapi-schema/, $(qapi-schema))
 
-GENERATED_FILES += tests/test-qapi-types.h \
-	tests/include/test-qapi-types-sub-module.h \
-	tests/test-qapi-types-sub-sub-module.h \
-	tests/test-qapi-visit.h \
-	tests/include/test-qapi-visit-sub-module.h \
-	tests/test-qapi-visit-sub-sub-module.h \
-	tests/test-qapi-commands.h \
-	tests/include/test-qapi-commands-sub-module.h \
-	tests/test-qapi-commands-sub-sub-module.h \
-	tests/test-qapi-events.h \
-	tests/include/test-qapi-events-sub-module.h \
-	tests/test-qapi-events-sub-sub-module.h \
-	tests/test-qapi-introspect.h
+generated-files-y += tests/test-qapi-types.h
+generated-files-y += tests/include/test-qapi-types-sub-module.h
+generated-files-y += tests/test-qapi-types-sub-sub-module.h
+generated-files-y += tests/test-qapi-visit.h
+generated-files-y += tests/include/test-qapi-visit-sub-module.h
+generated-files-y += tests/test-qapi-visit-sub-sub-module.h
+generated-files-y += tests/test-qapi-commands.h
+generated-files-y += tests/include/test-qapi-commands-sub-module.h
+generated-files-y += tests/test-qapi-commands-sub-sub-module.h
+generated-files-y += tests/test-qapi-events.h
+generated-files-y += tests/include/test-qapi-events-sub-module.h
+generated-files-y += tests/test-qapi-events-sub-sub-module.h
+generated-files-y += tests/test-qapi-introspect.h
 
 QEMU_CFLAGS += -I$(SRC_PATH)/tests
 
@@ -496,11 +496,11 @@ test-qapi-obj-y = tests/test-qapi-types.o \
 	tests/test-qapi-visit-sub-sub-module.o \
 	tests/test-qapi-introspect.o \
 	$(test-qom-obj-y)
-benchmark-crypto-obj-y = $(authz-obj-y) $(crypto-obj-y) $(test-qom-obj-y)
-test-crypto-obj-y = $(authz-obj-y) $(crypto-obj-y) $(test-qom-obj-y)
-test-io-obj-y = $(io-obj-y) $(test-crypto-obj-y)
-test-authz-obj-y = $(test-qom-obj-y) $(authz-obj-y)
-test-block-obj-y = $(block-obj-y) $(test-io-obj-y) tests/iothread.o
+benchmark-crypto-obj-$(CONFIG_BLOCK) = $(authz-obj-y) $(crypto-obj-y) $(test-qom-obj-y)
+test-crypto-obj-$(CONFIG_BLOCK) = $(authz-obj-y) $(crypto-obj-y) $(test-qom-obj-y)
+test-io-obj-$(CONFIG_BLOCK) = $(io-obj-y) $(test-crypto-obj-y)
+test-authz-obj-$(CONFIG_BLOCK) = $(test-qom-obj-y) $(authz-obj-y)
+test-block-obj-$(CONFIG_BLOCK) = $(block-obj-y) $(test-io-obj-y) tests/iothread.o
 
 tests/check-qnum$(EXESUF): tests/check-qnum.o $(test-util-obj-y)
 tests/check-qstring$(EXESUF): tests/check-qstring.o $(test-util-obj-y)
diff --git a/tests/acpi-utils.c b/tests/acpi-utils.c
index cc33b460ab..d2a202efca 100644
--- a/tests/acpi-utils.c
+++ b/tests/acpi-utils.c
@@ -51,19 +51,7 @@ uint32_t acpi_find_rsdp_address(QTestState *qts)
     return off;
 }
 
-uint64_t acpi_get_xsdt_address(uint8_t *rsdp_table)
-{
-    uint64_t xsdt_physical_address;
-    uint8_t revision = rsdp_table[15 /* Revision offset */];
-
-    /* We must have revision 2 if we're looking for an XSDT pointer */
-    g_assert(revision == 2);
-
-    memcpy(&xsdt_physical_address, &rsdp_table[24 /* XsdtAddress offset */], 8);
-    return le64_to_cpu(xsdt_physical_address);
-}
-
-void acpi_parse_rsdp_table(QTestState *qts, uint32_t addr, uint8_t *rsdp_table)
+void acpi_fetch_rsdp_table(QTestState *qts, uint64_t addr, uint8_t *rsdp_table)
 {
     uint8_t revision;
 
@@ -91,13 +79,15 @@ void acpi_parse_rsdp_table(QTestState *qts, uint32_t addr, uint8_t *rsdp_table)
  *  actual one.
  */
 void acpi_fetch_table(QTestState *qts, uint8_t **aml, uint32_t *aml_len,
-                      const uint8_t *addr_ptr, const char *sig,
+                      const uint8_t *addr_ptr, int addr_size, const char *sig,
                       bool verify_checksum)
 {
-    uint32_t addr, len;
+    uint32_t len;
+    uint64_t addr = 0;
 
-    memcpy(&addr, addr_ptr , sizeof(addr));
-    addr = le32_to_cpu(addr);
+    g_assert(addr_size == 4 || addr_size == 8);
+    memcpy(&addr, addr_ptr , addr_size);
+    addr = le64_to_cpu(addr);
     qtest_memread(qts, addr + 4, &len, 4); /* Length of ACPI table */
     *aml_len = le32_to_cpu(len);
     *aml = g_malloc0(*aml_len);
@@ -111,3 +101,47 @@ void acpi_fetch_table(QTestState *qts, uint8_t **aml, uint32_t *aml_len,
         g_assert(!acpi_calc_checksum(*aml, *aml_len));
     }
 }
+
+#define GUID_SIZE 16
+static const uint8_t AcpiTestSupportGuid[GUID_SIZE] = {
+       0xb1, 0xa6, 0x87, 0xab,
+       0x34, 0x20,
+       0xa0, 0xbd,
+       0x71, 0xbd, 0x37, 0x50, 0x07, 0x75, 0x77, 0x85 };
+
+typedef struct {
+    uint8_t signature_guid[GUID_SIZE];
+    uint64_t rsdp10;
+    uint64_t rsdp20;
+} __attribute__((packed)) UefiTestSupport;
+
+/* Wait at most 600 seconds (test is slow with TCG and --enable-debug) */
+#define TEST_DELAY (1 * G_USEC_PER_SEC / 10)
+#define TEST_CYCLES MAX((600 * G_USEC_PER_SEC / TEST_DELAY), 1)
+#define MB 0x100000ULL
+uint64_t acpi_find_rsdp_address_uefi(QTestState *qts, uint64_t start,
+                                     uint64_t size)
+{
+    int i, j;
+    uint8_t data[GUID_SIZE];
+
+    for (i = 0; i < TEST_CYCLES; ++i) {
+        for (j = 0; j < size / MB; j++) {
+            /* look for GUID at every 1Mb block */
+            uint64_t addr = start + j * MB;
+
+            qtest_memread(qts, addr, data, sizeof(data));
+            if (!memcmp(AcpiTestSupportGuid, data, sizeof(data))) {
+                UefiTestSupport ret;
+
+                qtest_memread(qts, addr, &ret, sizeof(ret));
+                ret.rsdp10 = le64_to_cpu(ret.rsdp10);
+                ret.rsdp20 = le64_to_cpu(ret.rsdp20);
+                return ret.rsdp20 ? ret.rsdp20 : ret.rsdp10;
+            }
+        }
+        g_usleep(TEST_DELAY);
+    }
+    g_assert_not_reached();
+    return 0;
+}
diff --git a/tests/acpi-utils.h b/tests/acpi-utils.h
index 73fe24f044..0c86780689 100644
--- a/tests/acpi-utils.h
+++ b/tests/acpi-utils.h
@@ -46,10 +46,11 @@ typedef struct {
 
 uint8_t acpi_calc_checksum(const uint8_t *data, int len);
 uint32_t acpi_find_rsdp_address(QTestState *qts);
-uint64_t acpi_get_xsdt_address(uint8_t *rsdp_table);
-void acpi_parse_rsdp_table(QTestState *qts, uint32_t addr, uint8_t *rsdp_table);
+uint64_t acpi_find_rsdp_address_uefi(QTestState *qts, uint64_t start,
+                                     uint64_t size);
+void acpi_fetch_rsdp_table(QTestState *qts, uint64_t addr, uint8_t *rsdp_table);
 void acpi_fetch_table(QTestState *qts, uint8_t **aml, uint32_t *aml_len,
-                      const uint8_t *addr_ptr, const char *sig,
+                      const uint8_t *addr_ptr, int addr_size, const char *sig,
                       bool verify_checksum);
 
 #endif /* TEST_ACPI_UTILS_H */
diff --git a/tests/bios-tables-test.c b/tests/bios-tables-test.c
index a506dcbb29..11e07be093 100644
--- a/tests/bios-tables-test.c
+++ b/tests/bios-tables-test.c
@@ -24,9 +24,15 @@
 #define ACPI_REBUILD_EXPECTED_AML "TEST_ACPI_REBUILD_AML"
 
 typedef struct {
+    const char *accel;
     const char *machine;
     const char *variant;
-    uint32_t rsdp_addr;
+    const char *uefi_fl1;
+    const char *uefi_fl2;
+    const char *cd;
+    const uint64_t ram_start;
+    const uint64_t scan_len;
+    uint64_t rsdp_addr;
     uint8_t rsdp_table[36 /* ACPI 2.0+ RSDP size */];
     GArray *tables;
     uint32_t smbios_ep_addr;
@@ -77,22 +83,13 @@ static void free_test_data(test_data *data)
     g_array_free(data->tables, true);
 }
 
-static void test_acpi_rsdp_address(test_data *data)
-{
-    uint32_t off = acpi_find_rsdp_address(data->qts);
-    g_assert_cmphex(off, <, 0x100000);
-    data->rsdp_addr = off;
-}
-
 static void test_acpi_rsdp_table(test_data *data)
 {
-    uint8_t *rsdp_table = data->rsdp_table, revision;
-    uint32_t addr = data->rsdp_addr;
+    uint8_t *rsdp_table = data->rsdp_table;
 
-    acpi_parse_rsdp_table(data->qts, addr, rsdp_table);
-    revision = rsdp_table[15 /* Revision offset */];
+    acpi_fetch_rsdp_table(data->qts, data->rsdp_addr, rsdp_table);
 
-    switch (revision) {
+    switch (rsdp_table[15 /* Revision offset */]) {
     case 0: /* ACPI 1.0 RSDP */
         /* With rev 1, checksum is only for the first 20 bytes */
         g_assert(!acpi_calc_checksum(rsdp_table,  20));
@@ -107,21 +104,29 @@ static void test_acpi_rsdp_table(test_data *data)
     }
 }
 
-static void test_acpi_rsdt_table(test_data *data)
+static void test_acpi_rxsdt_table(test_data *data)
 {
+    const char *sig = "RSDT";
     AcpiSdtTable rsdt = {};
+    int entry_size = 4;
+    int addr_off = 16 /* RsdtAddress */;
     uint8_t *ent;
 
-    /* read RSDT table */
+    if (data->rsdp_table[15 /* Revision offset */] != 0) {
+        addr_off = 24 /* XsdtAddress */;
+        entry_size = 8;
+        sig = "XSDT";
+    }
+    /* read [RX]SDT table */
     acpi_fetch_table(data->qts, &rsdt.aml, &rsdt.aml_len,
-                     &data->rsdp_table[16 /* RsdtAddress */], "RSDT", true);
+                     &data->rsdp_table[addr_off], entry_size, sig, true);
 
     /* Load all tables and add to test list directly RSDT referenced tables */
-    ACPI_FOREACH_RSDT_ENTRY(rsdt.aml, rsdt.aml_len, ent, 4 /* Entry size */) {
+    ACPI_FOREACH_RSDT_ENTRY(rsdt.aml, rsdt.aml_len, ent, entry_size) {
         AcpiSdtTable ssdt_table = {};
 
         acpi_fetch_table(data->qts, &ssdt_table.aml, &ssdt_table.aml_len, ent,
-                         NULL, true);
+                         entry_size, NULL, true);
         /* Add table to ASL test tables list */
         g_array_append_val(data->tables, ssdt_table);
     }
@@ -134,16 +139,29 @@ static void test_acpi_fadt_table(test_data *data)
     AcpiSdtTable table = g_array_index(data->tables, typeof(table), 0);
     uint8_t *fadt_aml = table.aml;
     uint32_t fadt_len = table.aml_len;
+    uint32_t val;
+    int dsdt_offset = 40 /* DSDT */;
+    int dsdt_entry_size = 4;
 
     g_assert(compare_signature(&table, "FACP"));
 
     /* Since DSDT/FACS isn't in RSDT, add them to ASL test list manually */
-    acpi_fetch_table(data->qts, &table.aml, &table.aml_len,
-                     fadt_aml + 36 /* FIRMWARE_CTRL */, "FACS", false);
-    g_array_append_val(data->tables, table);
+    memcpy(&val, fadt_aml + 112 /* Flags */, 4);
+    val = le32_to_cpu(val);
+    if (!(val & 1UL << 20 /* HW_REDUCED_ACPI */)) {
+        acpi_fetch_table(data->qts, &table.aml, &table.aml_len,
+                         fadt_aml + 36 /* FIRMWARE_CTRL */, 4, "FACS", false);
+        g_array_append_val(data->tables, table);
+    }
 
+    memcpy(&val, fadt_aml + dsdt_offset, 4);
+    val = le32_to_cpu(val);
+    if (!val) {
+        dsdt_offset = 140 /* X_DSDT */;
+        dsdt_entry_size = 8;
+    }
     acpi_fetch_table(data->qts, &table.aml, &table.aml_len,
-                     fadt_aml + 40 /* DSDT */, "DSDT", true);
+                     fadt_aml + dsdt_offset, dsdt_entry_size, "DSDT", true);
     g_array_append_val(data->tables, table);
 
     memset(fadt_aml + 36, 0, 4); /* sanitize FIRMWARE_CTRL ptr */
@@ -177,11 +195,14 @@ static void dump_aml_files(test_data *data, bool rebuild)
                                        sdt->aml, ext);
             fd = g_open(aml_file, O_WRONLY|O_TRUNC|O_CREAT,
                         S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH);
+            if (fd < 0) {
+                perror(aml_file);
+            }
+            g_assert(fd >= 0);
         } else {
             fd = g_file_open_tmp("aml-XXXXXX", &sdt->aml_file, &error);
             g_assert_no_error(error);
         }
-        g_assert(fd >= 0);
 
         ret = qemu_write_full(fd, sdt->aml, sdt->aml_len);
         g_assert(ret == sdt->aml_len);
@@ -505,23 +526,44 @@ static void test_smbios_structs(test_data *data)
 static void test_acpi_one(const char *params, test_data *data)
 {
     char *args;
-
-    /* Disable kernel irqchip to be able to override apic irq0. */
-    args = g_strdup_printf("-machine %s,accel=%s,kernel-irqchip=off "
-                           "-net none -display none %s "
-                           "-drive id=hd0,if=none,file=%s,format=raw "
-                           "-device ide-hd,drive=hd0 ",
-                           data->machine, "kvm:tcg",
-                           params ? params : "", disk);
+    bool use_uefi = data->uefi_fl1 && data->uefi_fl2;
+
+    if (use_uefi) {
+        /*
+         * TODO: convert '-drive if=pflash' to new syntax (see e33763be7cd3)
+         * when arm/virt boad starts to support it.
+         */
+        args = g_strdup_printf("-machine %s,accel=%s -nodefaults -nographic "
+            "-drive if=pflash,format=raw,file=%s,readonly "
+            "-drive if=pflash,format=raw,file=%s,snapshot=on -cdrom %s %s",
+            data->machine, data->accel ? data->accel : "kvm:tcg",
+            data->uefi_fl1, data->uefi_fl2, data->cd, params ? params : "");
+
+    } else {
+        /* Disable kernel irqchip to be able to override apic irq0. */
+        args = g_strdup_printf("-machine %s,accel=%s,kernel-irqchip=off "
+            "-net none -display none %s "
+            "-drive id=hd0,if=none,file=%s,format=raw "
+            "-device ide-hd,drive=hd0 ",
+             data->machine, data->accel ? data->accel : "kvm:tcg",
+             params ? params : "", disk);
+    }
 
     data->qts = qtest_init(args);
 
-    boot_sector_test(data->qts);
+    if (use_uefi) {
+        g_assert(data->scan_len);
+        data->rsdp_addr = acpi_find_rsdp_address_uefi(data->qts,
+            data->ram_start, data->scan_len);
+    } else {
+        boot_sector_test(data->qts);
+        data->rsdp_addr = acpi_find_rsdp_address(data->qts);
+        g_assert_cmphex(data->rsdp_addr, <, 0x100000);
+    }
 
     data->tables = g_array_new(false, true, sizeof(AcpiSdtTable));
-    test_acpi_rsdp_address(data);
     test_acpi_rsdp_table(data);
-    test_acpi_rsdt_table(data);
+    test_acpi_rxsdt_table(data);
     test_acpi_fadt_table(data);
 
     if (iasl) {
@@ -532,8 +574,15 @@ static void test_acpi_one(const char *params, test_data *data)
         }
     }
 
-    test_smbios_entry_point(data);
-    test_smbios_structs(data);
+    /*
+     * TODO: make SMBIOS tests work with UEFI firmware,
+     * Bug on uefi-test-tools to provide entry point:
+     * https://bugs.launchpad.net/qemu/+bug/1821884
+     */
+    if (!use_uefi) {
+        test_smbios_entry_point(data);
+        test_smbios_structs(data);
+    }
 
     assert(!global_qtest);
     qtest_quit(data->qts);
@@ -769,13 +818,14 @@ int main(int argc, char *argv[])
     const char *arch = qtest_get_arch();
     int ret;
 
-    ret = boot_sector_init(disk);
-    if(ret)
-        return ret;
-
     g_test_init(&argc, &argv, NULL);
 
     if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
+        ret = boot_sector_init(disk);
+        if (ret) {
+            return ret;
+        }
+
         qtest_add_func("acpi/piix4", test_acpi_piix4_tcg);
         qtest_add_func("acpi/piix4/bridge", test_acpi_piix4_tcg_bridge);
         qtest_add_func("acpi/q35", test_acpi_q35_tcg);
diff --git a/tests/data/acpi/rebuild-expected-aml.sh b/tests/data/acpi/rebuild-expected-aml.sh
index abdff70a0d..ff7e62249d 100755
--- a/tests/data/acpi/rebuild-expected-aml.sh
+++ b/tests/data/acpi/rebuild-expected-aml.sh
@@ -7,21 +7,12 @@
 #
 # Authors:
 #  Marcel Apfelbaum <marcel.a@redhat.com>
+#  Igor Mammedov <imammedo@redhat.com>
 #
 # This work is licensed under the terms of the GNU GPLv2.
 # See the COPYING.LIB file in the top-level directory.
 
-qemu=
-
-if [ -e x86_64-softmmu/qemu-system-x86_64 ]; then
-    qemu="x86_64-softmmu/qemu-system-x86_64"
-elif [ -e i386-softmmu/qemu-system-i386 ]; then
-    qemu="i386-softmmu/qemu-system-i386"
-else
-    echo "Run 'make' to build the qemu exectutable!"
-    echo "Run this script from the build directory."
-    exit 1;
-fi
+qemu_bins="x86_64-softmmu/qemu-system-x86_64"
 
 if [ ! -e "tests/bios-tables-test" ]; then
     echo "Test: bios-tables-test is required! Run make check before this script."
@@ -29,6 +20,14 @@ if [ ! -e "tests/bios-tables-test" ]; then
     exit 1;
 fi
 
-TEST_ACPI_REBUILD_AML=y QTEST_QEMU_BINARY=$qemu tests/bios-tables-test
+for qemu in $qemu_bins; do
+    if [ ! -e $qemu ]; then
+        echo "Run 'make' to build the following QEMU executables: $qemu_bins"
+        echo "Also, run this script from the build directory."
+        exit 1;
+    fi
+    TEST_ACPI_REBUILD_AML=y QTEST_QEMU_BINARY=$qemu tests/bios-tables-test
+done
+
 
 echo "The files were rebuilt and can be added to git."
diff --git a/tests/device-introspect-test.c b/tests/device-introspect-test.c
index a25092dfaa..04f22903b0 100644
--- a/tests/device-introspect-test.c
+++ b/tests/device-introspect-test.c
@@ -26,7 +26,8 @@
 
 const char common_args[] = "-nodefaults -machine none";
 
-static QList *qom_list_types(const char *implements, bool abstract)
+static QList *qom_list_types(QTestState * qts, const char *implements,
+                             bool abstract)
 {
     QDict *resp;
     QList *ret;
@@ -36,8 +37,8 @@ static QList *qom_list_types(const char *implements, bool abstract)
     if (implements) {
         qdict_put_str(args, "implements", implements);
     }
-    resp = qmp("{'execute': 'qom-list-types',"
-               " 'arguments': %p }", args);
+    resp = qtest_qmp(qts, "{'execute': 'qom-list-types', 'arguments': %p }",
+                     args);
     g_assert(qdict_haskey(resp, "return"));
     ret = qdict_get_qlist(resp, "return");
     qobject_ref(ret);
@@ -95,12 +96,12 @@ static QDict *type_list_find(QList *types, const char *name)
     return NULL;
 }
 
-static QList *device_type_list(bool abstract)
+static QList *device_type_list(QTestState *qts, bool abstract)
 {
-    return qom_list_types("device", abstract);
+    return qom_list_types(qts, "device", abstract);
 }
 
-static void test_one_device(const char *type)
+static void test_one_device(QTestState *qts, const char *type)
 {
     QDict *resp;
     char *help;
@@ -109,15 +110,15 @@ static void test_one_device(const char *type)
 
     g_test_message("Testing device '%s'", type);
 
-    qom_tree_start = hmp("info qom-tree");
-    qtree_start = hmp("info qtree");
+    qom_tree_start = qtest_hmp(qts, "info qom-tree");
+    qtree_start = qtest_hmp(qts, "info qtree");
 
-    resp = qmp("{'execute': 'device-list-properties',"
-               " 'arguments': {'typename': %s}}",
+    resp = qtest_qmp(qts, "{'execute': 'device-list-properties',"
+                          " 'arguments': {'typename': %s}}",
                type);
     qobject_unref(resp);
 
-    help = hmp("device_add \"%s,help\"", type);
+    help = qtest_hmp(qts, "device_add \"%s,help\"", type);
     g_free(help);
 
     /*
@@ -125,12 +126,12 @@ static void test_one_device(const char *type)
      * "info qom-tree" or "info qtree" have a good chance at crashing then.
      * Also make sure that the tree did not change.
      */
-    qom_tree_end = hmp("info qom-tree");
+    qom_tree_end = qtest_hmp(qts, "info qom-tree");
     g_assert_cmpstr(qom_tree_start, ==, qom_tree_end);
     g_free(qom_tree_start);
     g_free(qom_tree_end);
 
-    qtree_end = hmp("info qtree");
+    qtree_end = qtest_hmp(qts, "info qtree");
     g_assert_cmpstr(qtree_start, ==, qtree_end);
     g_free(qtree_start);
     g_free(qtree_end);
@@ -140,29 +141,30 @@ static void test_device_intro_list(void)
 {
     QList *types;
     char *help;
+    QTestState *qts;
 
-    qtest_start(common_args);
+    qts = qtest_init(common_args);
 
-    types = device_type_list(true);
+    types = device_type_list(qts, true);
     qobject_unref(types);
 
-    help = hmp("device_add help");
+    help = qtest_hmp(qts, "device_add help");
     g_free(help);
 
-    qtest_end();
+    qtest_quit(qts);
 }
 
 /*
  * Ensure all entries returned by qom-list-types implements=<parent>
  * have <parent> as a parent.
  */
-static void test_qom_list_parents(const char *parent)
+static void test_qom_list_parents(QTestState *qts, const char *parent)
 {
     QList *types;
     QListEntry *e;
     QDict *index;
 
-    types = qom_list_types(parent, true);
+    types = qom_list_types(qts, parent, true);
     index = qom_type_index(types);
 
     QLIST_FOREACH_ENTRY(types, e) {
@@ -181,11 +183,12 @@ static void test_qom_list_fields(void)
     QList *all_types;
     QList *non_abstract;
     QListEntry *e;
+    QTestState *qts;
 
-    qtest_start(common_args);
+    qts = qtest_init(common_args);
 
-    all_types = qom_list_types(NULL, true);
-    non_abstract = qom_list_types(NULL, false);
+    all_types = qom_list_types(qts, NULL, true);
+    non_abstract = qom_list_types(qts, NULL, false);
 
     QLIST_FOREACH_ENTRY(all_types, e) {
         QDict *d = qobject_to(QDict, qlist_entry_obj(e));
@@ -198,27 +201,29 @@ static void test_qom_list_fields(void)
         g_assert(abstract == expected_abstract);
     }
 
-    test_qom_list_parents("object");
-    test_qom_list_parents("device");
-    test_qom_list_parents("sys-bus-device");
+    test_qom_list_parents(qts, "object");
+    test_qom_list_parents(qts, "device");
+    test_qom_list_parents(qts, "sys-bus-device");
 
     qobject_unref(all_types);
     qobject_unref(non_abstract);
-    qtest_end();
+    qtest_quit(qts);
 }
 
 static void test_device_intro_none(void)
 {
-    qtest_start(common_args);
-    test_one_device("nonexistent");
-    qtest_end();
+    QTestState *qts = qtest_init(common_args);
+
+    test_one_device(qts, "nonexistent");
+    qtest_quit(qts);
 }
 
 static void test_device_intro_abstract(void)
 {
-    qtest_start(common_args);
-    test_one_device("device");
-    qtest_end();
+    QTestState *qts = qtest_init(common_args);
+
+    test_one_device(qts, "device");
+    qtest_quit(qts);
 }
 
 static void test_device_intro_concrete(const void *args)
@@ -226,19 +231,20 @@ static void test_device_intro_concrete(const void *args)
     QList *types;
     QListEntry *entry;
     const char *type;
+    QTestState *qts;
 
-    qtest_start(args);
-    types = device_type_list(false);
+    qts = qtest_init(args);
+    types = device_type_list(qts, false);
 
     QLIST_FOREACH_ENTRY(types, entry) {
         type = qdict_get_try_str(qobject_to(QDict, qlist_entry_obj(entry)),
                                  "name");
         g_assert(type);
-        test_one_device(type);
+        test_one_device(qts, type);
     }
 
     qobject_unref(types);
-    qtest_end();
+    qtest_quit(qts);
     g_free((void *)args);
 }
 
@@ -247,10 +253,11 @@ static void test_abstract_interfaces(void)
     QList *all_types;
     QListEntry *e;
     QDict *index;
+    QTestState *qts;
 
-    qtest_start(common_args);
+    qts = qtest_init(common_args);
 
-    all_types = qom_list_types("interface", true);
+    all_types = qom_list_types(qts, "interface", true);
     index = qom_type_index(all_types);
 
     QLIST_FOREACH_ENTRY(all_types, e) {
@@ -273,7 +280,7 @@ static void test_abstract_interfaces(void)
 
     qobject_unref(all_types);
     qobject_unref(index);
-    qtest_end();
+    qtest_quit(qts);
 }
 
 static void add_machine_test_case(const char *mname)
diff --git a/tests/hd-geo-test.c b/tests/hd-geo-test.c
index ce665f1f83..62eb624726 100644
--- a/tests/hd-geo-test.c
+++ b/tests/hd-geo-test.c
@@ -77,33 +77,35 @@ static bool is_hd(const CHST *expected_chst)
     return expected_chst && expected_chst->cyls;
 }
 
-static void test_cmos_byte(int reg, int expected)
+static void test_cmos_byte(QTestState *qts, int reg, int expected)
 {
     enum { cmos_base = 0x70 };
     int actual;
 
-    outb(cmos_base + 0, reg);
-    actual = inb(cmos_base + 1);
+    qtest_outb(qts, cmos_base + 0, reg);
+    actual = qtest_inb(qts, cmos_base + 1);
     g_assert(actual == expected);
 }
 
-static void test_cmos_bytes(int reg0, int n, uint8_t expected[])
+static void test_cmos_bytes(QTestState *qts, int reg0, int n,
+                            uint8_t expected[])
 {
     int i;
 
     for (i = 0; i < 9; i++) {
-        test_cmos_byte(reg0 + i, expected[i]);
+        test_cmos_byte(qts, reg0 + i, expected[i]);
     }
 }
 
-static void test_cmos_disk_data(void)
+static void test_cmos_disk_data(QTestState *qts)
 {
-    test_cmos_byte(0x12,
+    test_cmos_byte(qts, 0x12,
                    (is_hd(cur_ide[0]) ? 0xf0 : 0) |
                    (is_hd(cur_ide[1]) ? 0x0f : 0));
 }
 
-static void test_cmos_drive_cyl(int reg0, const CHST *expected_chst)
+static void test_cmos_drive_cyl(QTestState *qts, int reg0,
+                                const CHST *expected_chst)
 {
     if (is_hd(expected_chst)) {
         int c = expected_chst->cyls;
@@ -113,29 +115,29 @@ static void test_cmos_drive_cyl(int reg0, const CHST *expected_chst)
             c & 0xff, c >> 8, h, 0xff, 0xff, 0xc0 | ((h > 8) << 3),
             c & 0xff, c >> 8, s
         };
-        test_cmos_bytes(reg0, 9, expected_bytes);
+        test_cmos_bytes(qts, reg0, 9, expected_bytes);
     } else {
         int i;
 
         for (i = 0; i < 9; i++) {
-            test_cmos_byte(reg0 + i, 0);
+            test_cmos_byte(qts, reg0 + i, 0);
         }
     }
 }
 
-static void test_cmos_drive1(void)
+static void test_cmos_drive1(QTestState *qts)
 {
-    test_cmos_byte(0x19, is_hd(cur_ide[0]) ? 47 : 0);
-    test_cmos_drive_cyl(0x1b, cur_ide[0]);
+    test_cmos_byte(qts, 0x19, is_hd(cur_ide[0]) ? 47 : 0);
+    test_cmos_drive_cyl(qts, 0x1b, cur_ide[0]);
 }
 
-static void test_cmos_drive2(void)
+static void test_cmos_drive2(QTestState *qts)
 {
-    test_cmos_byte(0x1a, is_hd(cur_ide[1]) ? 47 : 0);
-    test_cmos_drive_cyl(0x24, cur_ide[1]);
+    test_cmos_byte(qts, 0x1a, is_hd(cur_ide[1]) ? 47 : 0);
+    test_cmos_drive_cyl(qts, 0x24, cur_ide[1]);
 }
 
-static void test_cmos_disktransflag(void)
+static void test_cmos_disktransflag(QTestState *qts)
 {
     int val, i;
 
@@ -145,15 +147,15 @@ static void test_cmos_disktransflag(void)
             val |= cur_ide[i]->trans << (2 * i);
         }
     }
-    test_cmos_byte(0x39, val);
+    test_cmos_byte(qts, 0x39, val);
 }
 
-static void test_cmos(void)
+static void test_cmos(QTestState *qts)
 {
-    test_cmos_disk_data();
-    test_cmos_drive1();
-    test_cmos_drive2();
-    test_cmos_disktransflag();
+    test_cmos_disk_data(qts);
+    test_cmos_drive1(qts);
+    test_cmos_drive2(qts);
+    test_cmos_disktransflag(qts);
 }
 
 static int append_arg(int argc, char *argv[], int argv_sz, char *arg)
@@ -238,14 +240,15 @@ static void test_ide_none(void)
 {
     char **argv = g_new0(char *, ARGV_SIZE);
     char *args;
+    QTestState *qts;
 
     setup_common(argv, ARGV_SIZE);
     args = g_strjoinv(" ", argv);
-    qtest_start(args);
+    qts = qtest_init(args);
     g_strfreev(argv);
     g_free(args);
-    test_cmos();
-    qtest_end();
+    test_cmos(qts);
+    qtest_quit(qts);
 }
 
 static void test_ide_mbr(bool use_device, MBRcontents mbr)
@@ -255,6 +258,7 @@ static void test_ide_mbr(bool use_device, MBRcontents mbr)
     int argc;
     Backend i;
     const char *dev;
+    QTestState *qts;
 
     argc = setup_common(argv, ARGV_SIZE);
     for (i = 0; i < backend_last; i++) {
@@ -263,11 +267,11 @@ static void test_ide_mbr(bool use_device, MBRcontents mbr)
         argc = setup_ide(argc, argv, ARGV_SIZE, i, dev, i, mbr);
     }
     args = g_strjoinv(" ", argv);
-    qtest_start(args);
+    qts = qtest_init(args);
     g_strfreev(argv);
     g_free(args);
-    test_cmos();
-    qtest_end();
+    test_cmos(qts);
+    qtest_quit(qts);
 }
 
 /*
@@ -325,6 +329,7 @@ static void test_ide_drive_user(const char *dev, bool trans)
     int argc;
     int secs = img_secs[backend_small];
     const CHST expected_chst = { secs / (4 * 32) , 4, 32, trans };
+    QTestState *qts;
 
     argc = setup_common(argv, ARGV_SIZE);
     opts = g_strdup_printf("%s,%scyls=%d,heads=%d,secs=%d",
@@ -335,11 +340,11 @@ static void test_ide_drive_user(const char *dev, bool trans)
     argc = setup_ide(argc, argv, ARGV_SIZE, 0, opts, backend_small, mbr_chs);
     g_free(opts);
     args = g_strjoinv(" ", argv);
-    qtest_start(args);
+    qts = qtest_init(args);
     g_strfreev(argv);
     g_free(args);
-    test_cmos();
-    qtest_end();
+    test_cmos(qts);
+    qtest_quit(qts);
 }
 
 /*
@@ -367,6 +372,7 @@ static void test_ide_drive_cd_0(void)
     char *args;
     int argc, ide_idx;
     Backend i;
+    QTestState *qts;
 
     argc = setup_common(argv, ARGV_SIZE);
     for (i = 0; i <= backend_empty; i++) {
@@ -375,11 +381,11 @@ static void test_ide_drive_cd_0(void)
         argc = setup_ide(argc, argv, ARGV_SIZE, ide_idx, NULL, i, mbr_blank);
     }
     args = g_strjoinv(" ", argv);
-    qtest_start(args);
+    qts = qtest_init(args);
     g_strfreev(argv);
     g_free(args);
-    test_cmos();
-    qtest_end();
+    test_cmos(qts);
+    qtest_quit(qts);
 }
 
 int main(int argc, char **argv)
diff --git a/tests/libqos/virtio-mmio.c b/tests/libqos/virtio-mmio.c
index 3678c07ef0..213a5f9de0 100644
--- a/tests/libqos/virtio-mmio.c
+++ b/tests/libqos/virtio-mmio.c
@@ -148,7 +148,7 @@ static QVirtQueue *qvirtio_mmio_virtqueue_setup(QVirtioDevice *d,
     g_assert_cmpint(vq->size & (vq->size - 1), ==, 0);
 
     addr = guest_alloc(alloc, qvring_size(vq->size, dev->page_size));
-    qvring_init(alloc, vq, addr);
+    qvring_init(dev->qts, alloc, vq, addr);
     qvirtio_mmio_set_queue_address(d, vq->desc / dev->page_size);
 
     return vq;
diff --git a/tests/libqos/virtio-pci.c b/tests/libqos/virtio-pci.c
index 993d347830..a622ca26ca 100644
--- a/tests/libqos/virtio-pci.c
+++ b/tests/libqos/virtio-pci.c
@@ -199,6 +199,7 @@ static QVirtQueue *qvirtio_pci_virtqueue_setup(QVirtioDevice *d,
     uint32_t feat;
     uint64_t addr;
     QVirtQueuePCI *vqpci;
+    QVirtioPCIDevice *qvpcidev = container_of(d, QVirtioPCIDevice, vdev);
 
     vqpci = g_malloc0(sizeof(*vqpci));
     feat = qvirtio_pci_get_guest_features(d);
@@ -224,7 +225,7 @@ static QVirtQueue *qvirtio_pci_virtqueue_setup(QVirtioDevice *d,
 
     addr = guest_alloc(alloc, qvring_size(vqpci->vq.size,
                                           VIRTIO_PCI_VRING_ALIGN));
-    qvring_init(alloc, &vqpci->vq, addr);
+    qvring_init(qvpcidev->pdev->bus->qts, alloc, &vqpci->vq, addr);
     qvirtio_pci_set_queue_address(d, vqpci->vq.desc / VIRTIO_PCI_VRING_ALIGN);
 
     return &vqpci->vq;
diff --git a/tests/libqos/virtio.c b/tests/libqos/virtio.c
index 5e8f39b4d3..b4c01dc0c1 100644
--- a/tests/libqos/virtio.c
+++ b/tests/libqos/virtio.c
@@ -162,7 +162,8 @@ void qvirtio_wait_config_isr(QVirtioDevice *d, gint64 timeout_us)
     }
 }
 
-void qvring_init(const QGuestAllocator *alloc, QVirtQueue *vq, uint64_t addr)
+void qvring_init(QTestState *qts, const QGuestAllocator *alloc, QVirtQueue *vq,
+                 uint64_t addr)
 {
     int i;
 
@@ -173,22 +174,23 @@ void qvring_init(const QGuestAllocator *alloc, QVirtQueue *vq, uint64_t addr)
 
     for (i = 0; i < vq->size - 1; i++) {
         /* vq->desc[i].addr */
-        writeq(vq->desc + (16 * i), 0);
+        qtest_writeq(qts, vq->desc + (16 * i), 0);
         /* vq->desc[i].next */
-        writew(vq->desc + (16 * i) + 14, i + 1);
+        qtest_writew(qts, vq->desc + (16 * i) + 14, i + 1);
     }
 
     /* vq->avail->flags */
-    writew(vq->avail, 0);
+    qtest_writew(qts, vq->avail, 0);
     /* vq->avail->idx */
-    writew(vq->avail + 2, 0);
+    qtest_writew(qts, vq->avail + 2, 0);
     /* vq->avail->used_event */
-    writew(vq->avail + 4 + (2 * vq->size), 0);
+    qtest_writew(qts, vq->avail + 4 + (2 * vq->size), 0);
 
     /* vq->used->flags */
-    writew(vq->used, 0);
+    qtest_writew(qts, vq->used, 0);
     /* vq->used->avail_event */
-    writew(vq->used + 2 + sizeof(struct vring_used_elem) * vq->size, 0);
+    qtest_writew(qts, vq->used + 2 + sizeof(struct vring_used_elem) * vq->size,
+                 0);
 }
 
 QVRingIndirectDesc *qvring_indirect_desc_setup(QVirtioDevice *d,
diff --git a/tests/libqos/virtio.h b/tests/libqos/virtio.h
index 51d2359ace..7b97f5e567 100644
--- a/tests/libqos/virtio.h
+++ b/tests/libqos/virtio.h
@@ -129,7 +129,8 @@ QVirtQueue *qvirtqueue_setup(QVirtioDevice *d,
 void qvirtqueue_cleanup(const QVirtioBus *bus, QVirtQueue *vq,
                         QGuestAllocator *alloc);
 
-void qvring_init(const QGuestAllocator *alloc, QVirtQueue *vq, uint64_t addr);
+void qvring_init(QTestState *qts, const QGuestAllocator *alloc, QVirtQueue *vq,
+                 uint64_t addr);
 QVRingIndirectDesc *qvring_indirect_desc_setup(QVirtioDevice *d,
                                         QGuestAllocator *alloc, uint16_t elem);
 void qvring_indirect_desc_add(QVRingIndirectDesc *indirect, uint64_t data,
diff --git a/tests/libqtest.c b/tests/libqtest.c
index c49b85482d..8ac0c02af4 100644
--- a/tests/libqtest.c
+++ b/tests/libqtest.c
@@ -1038,15 +1038,6 @@ QDict *qmp(const char *fmt, ...)
     return response;
 }
 
-void qmp_send(const char *fmt, ...)
-{
-    va_list ap;
-
-    va_start(ap, fmt);
-    qtest_qmp_vsend(global_qtest, fmt, ap);
-    va_end(ap);
-}
-
 char *hmp(const char *fmt, ...)
 {
     va_list ap;
@@ -1232,7 +1223,7 @@ void qtest_qmp_device_del(const char *id)
                                     &got_event);
     qobject_unref(rsp);
     if (!got_event) {
-        rsp = qmp_receive();
+        rsp = qtest_qmp_receive(global_qtest);
         g_assert_cmpstr(qdict_get_try_str(rsp, "event"),
                         ==, "DEVICE_DELETED");
         qobject_unref(rsp);
diff --git a/tests/libqtest.h b/tests/libqtest.h
index a16acd58a6..a98ea15b7d 100644
--- a/tests/libqtest.h
+++ b/tests/libqtest.h
@@ -29,7 +29,7 @@ extern QTestState *global_qtest;
  * @fmt...: Format for creating other arguments to pass to QEMU, formatted
  * like sprintf().
  *
- * Convenience wrapper around qtest_start().
+ * Convenience wrapper around qtest_init().
  *
  * Returns: #QTestState instance.
  */
@@ -41,7 +41,7 @@ QTestState *qtest_initf(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
  * like vsprintf().
  * @ap: Format arguments.
  *
- * Convenience wrapper around qtest_start().
+ * Convenience wrapper around qtest_init().
  *
  * Returns: #QTestState instance.
  */
@@ -619,26 +619,6 @@ static inline void qtest_end(void)
 QDict *qmp(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
 
 /**
- * qmp_send:
- * @fmt...: QMP message to send to qemu, formatted like
- * qobject_from_jsonf_nofail().  See parse_escape() for what's
- * supported after '%'.
- *
- * Sends a QMP message to QEMU and leaves the response in the stream.
- */
-void qmp_send(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
-
-/**
- * qmp_receive:
- *
- * Reads a QMP message from QEMU and returns the response.
- */
-static inline QDict *qmp_receive(void)
-{
-    return qtest_qmp_receive(global_qtest);
-}
-
-/**
  * qmp_eventwait:
  * @s: #event event to wait for.
  *
@@ -650,18 +630,6 @@ static inline void qmp_eventwait(const char *event)
 }
 
 /**
- * qmp_eventwait_ref:
- * @s: #event event to wait for.
- *
- * Continuously polls for QMP responses until it receives the desired event.
- * Returns a copy of the event for further investigation.
- */
-static inline QDict *qmp_eventwait_ref(const char *event)
-{
-    return qtest_qmp_eventwait_ref(global_qtest, event);
-}
-
-/**
  * hmp:
  * @fmt...: HMP command to send to QEMU, formats arguments like sprintf().
  *
@@ -683,30 +651,6 @@ static inline bool get_irq(int num)
 }
 
 /**
- * irq_intercept_in:
- * @string: QOM path of a device.
- *
- * Associate qtest irqs with the GPIO-in pins of the device
- * whose path is specified by @string.
- */
-static inline void irq_intercept_in(const char *string)
-{
-    qtest_irq_intercept_in(global_qtest, string);
-}
-
-/**
- * qtest_irq_intercept_out:
- * @string: QOM path of a device.
- *
- * Associate qtest irqs with the GPIO-out pins of the device
- * whose path is specified by @string.
- */
-static inline void irq_intercept_out(const char *string)
-{
-    qtest_irq_intercept_out(global_qtest, string);
-}
-
-/**
  * outb:
  * @addr: I/O port to write to.
  * @value: Value being written.
@@ -895,19 +839,6 @@ static inline void memread(uint64_t addr, void *data, size_t size)
 }
 
 /**
- * bufread:
- * @addr: Guest address to read from.
- * @data: Pointer to where memory contents will be stored.
- * @size: Number of bytes to read.
- *
- * Read guest memory into a buffer, receive using a base64 encoding.
- */
-static inline void bufread(uint64_t addr, void *data, size_t size)
-{
-    qtest_bufread(global_qtest, addr, data, size);
-}
-
-/**
  * memwrite:
  * @addr: Guest address to write to.
  * @data: Pointer to the bytes that will be written to guest memory.
@@ -921,32 +852,6 @@ static inline void memwrite(uint64_t addr, const void *data, size_t size)
 }
 
 /**
- * bufwrite:
- * @addr: Guest address to write to.
- * @data: Pointer to the bytes that will be written to guest memory.
- * @size: Number of bytes to write.
- *
- * Write a buffer to guest memory, transmit using a base64 encoding.
- */
-static inline void bufwrite(uint64_t addr, const void *data, size_t size)
-{
-    qtest_bufwrite(global_qtest, addr, data, size);
-}
-
-/**
- * qmemset:
- * @addr: Guest address to write to.
- * @patt: Byte pattern to fill the guest memory region with.
- * @size: Number of bytes to write.
- *
- * Write a pattern to guest memory.
- */
-static inline void qmemset(uint64_t addr, uint8_t patt, size_t size)
-{
-    qtest_memset(global_qtest, addr, patt, size);
-}
-
-/**
  * clock_step_next:
  *
  * Advance the QEMU_CLOCK_VIRTUAL to the next deadline.
@@ -971,19 +876,6 @@ static inline int64_t clock_step(int64_t step)
     return qtest_clock_step(global_qtest, step);
 }
 
-/**
- * clock_set:
- * @val: Nanoseconds value to advance the clock to.
- *
- * Advance the QEMU_CLOCK_VIRTUAL to @val nanoseconds since the VM was launched.
- *
- * Returns: The current value of the QEMU_CLOCK_VIRTUAL in nanoseconds.
- */
-static inline int64_t clock_set(int64_t val)
-{
-    return qtest_clock_set(global_qtest, val);
-}
-
 QDict *qmp_fd_receive(int fd);
 void qmp_fd_vsend(int fd, const char *fmt, va_list ap) GCC_FMT_ATTR(2, 0);
 void qmp_fd_send(int fd, const char *fmt, ...) GCC_FMT_ATTR(2, 3);
diff --git a/tests/numa-test.c b/tests/numa-test.c
index 9824fdd587..8de8581231 100644
--- a/tests/numa-test.c
+++ b/tests/numa-test.c
@@ -23,18 +23,19 @@ static void test_mon_explicit(const void *data)
 {
     char *s;
     char *cli;
+    QTestState *qts;
 
     cli = make_cli(data, "-smp 8 "
                    "-numa node,nodeid=0,cpus=0-3 "
                    "-numa node,nodeid=1,cpus=4-7 ");
-    qtest_start(cli);
+    qts = qtest_init(cli);
 
-    s = hmp("info numa");
+    s = qtest_hmp(qts, "info numa");
     g_assert(strstr(s, "node 0 cpus: 0 1 2 3"));
     g_assert(strstr(s, "node 1 cpus: 4 5 6 7"));
     g_free(s);
 
-    qtest_end();
+    qtest_quit(qts);
     g_free(cli);
 }
 
@@ -42,16 +43,17 @@ static void test_mon_default(const void *data)
 {
     char *s;
     char *cli;
+    QTestState *qts;
 
     cli = make_cli(data, "-smp 8 -numa node -numa node");
-    qtest_start(cli);
+    qts = qtest_init(cli);
 
-    s = hmp("info numa");
+    s = qtest_hmp(qts, "info numa");
     g_assert(strstr(s, "node 0 cpus: 0 2 4 6"));
     g_assert(strstr(s, "node 1 cpus: 1 3 5 7"));
     g_free(s);
 
-    qtest_end();
+    qtest_quit(qts);
     g_free(cli);
 }
 
@@ -59,24 +61,25 @@ static void test_mon_partial(const void *data)
 {
     char *s;
     char *cli;
+    QTestState *qts;
 
     cli = make_cli(data, "-smp 8 "
                    "-numa node,nodeid=0,cpus=0-1 "
                    "-numa node,nodeid=1,cpus=4-5 ");
-    qtest_start(cli);
+    qts = qtest_init(cli);
 
-    s = hmp("info numa");
+    s = qtest_hmp(qts, "info numa");
     g_assert(strstr(s, "node 0 cpus: 0 1 2 3 6 7"));
     g_assert(strstr(s, "node 1 cpus: 4 5"));
     g_free(s);
 
-    qtest_end();
+    qtest_quit(qts);
     g_free(cli);
 }
 
-static QList *get_cpus(QDict **resp)
+static QList *get_cpus(QTestState *qts, QDict **resp)
 {
-    *resp = qmp("{ 'execute': 'query-cpus' }");
+    *resp = qtest_qmp(qts, "{ 'execute': 'query-cpus' }");
     g_assert(*resp);
     g_assert(qdict_haskey(*resp, "return"));
     return qdict_get_qlist(*resp, "return");
@@ -88,10 +91,11 @@ static void test_query_cpus(const void *data)
     QDict *resp;
     QList *cpus;
     QObject *e;
+    QTestState *qts;
 
     cli = make_cli(data, "-smp 8 -numa node,cpus=0-3 -numa node,cpus=4-7");
-    qtest_start(cli);
-    cpus = get_cpus(&resp);
+    qts = qtest_init(cli);
+    cpus = get_cpus(qts, &resp);
     g_assert(cpus);
 
     while ((e = qlist_pop(cpus))) {
@@ -115,7 +119,7 @@ static void test_query_cpus(const void *data)
     }
 
     qobject_unref(resp);
-    qtest_end();
+    qtest_quit(qts);
     g_free(cli);
 }
 
@@ -125,6 +129,7 @@ static void pc_numa_cpu(const void *data)
     QDict *resp;
     QList *cpus;
     QObject *e;
+    QTestState *qts;
 
     cli = make_cli(data, "-cpu pentium -smp 8,sockets=2,cores=2,threads=2 "
         "-numa node,nodeid=0 -numa node,nodeid=1 "
@@ -132,8 +137,8 @@ static void pc_numa_cpu(const void *data)
         "-numa cpu,node-id=0,socket-id=1,core-id=0 "
         "-numa cpu,node-id=0,socket-id=1,core-id=1,thread-id=0 "
         "-numa cpu,node-id=1,socket-id=1,core-id=1,thread-id=1");
-    qtest_start(cli);
-    cpus = get_cpus(&resp);
+    qts = qtest_init(cli);
+    cpus = get_cpus(qts, &resp);
     g_assert(cpus);
 
     while ((e = qlist_pop(cpus))) {
@@ -168,7 +173,7 @@ static void pc_numa_cpu(const void *data)
     }
 
     qobject_unref(resp);
-    qtest_end();
+    qtest_quit(qts);
     g_free(cli);
 }
 
@@ -178,6 +183,7 @@ static void spapr_numa_cpu(const void *data)
     QDict *resp;
     QList *cpus;
     QObject *e;
+    QTestState *qts;
 
     cli = make_cli(data, "-smp 4,cores=4 "
         "-numa node,nodeid=0 -numa node,nodeid=1 "
@@ -185,8 +191,8 @@ static void spapr_numa_cpu(const void *data)
         "-numa cpu,node-id=0,core-id=1 "
         "-numa cpu,node-id=0,core-id=2 "
         "-numa cpu,node-id=1,core-id=3");
-    qtest_start(cli);
-    cpus = get_cpus(&resp);
+    qts = qtest_init(cli);
+    cpus = get_cpus(qts, &resp);
     g_assert(cpus);
 
     while ((e = qlist_pop(cpus))) {
@@ -213,7 +219,7 @@ static void spapr_numa_cpu(const void *data)
     }
 
     qobject_unref(resp);
-    qtest_end();
+    qtest_quit(qts);
     g_free(cli);
 }
 
@@ -223,13 +229,14 @@ static void aarch64_numa_cpu(const void *data)
     QDict *resp;
     QList *cpus;
     QObject *e;
+    QTestState *qts;
 
     cli = make_cli(data, "-smp 2 "
         "-numa node,nodeid=0 -numa node,nodeid=1 "
         "-numa cpu,node-id=1,thread-id=0 "
         "-numa cpu,node-id=0,thread-id=1");
-    qtest_start(cli);
-    cpus = get_cpus(&resp);
+    qts = qtest_init(cli);
+    cpus = get_cpus(qts, &resp);
     g_assert(cpus);
 
     while ((e = qlist_pop(cpus))) {
@@ -256,7 +263,7 @@ static void aarch64_numa_cpu(const void *data)
     }
 
     qobject_unref(resp);
-    qtest_end();
+    qtest_quit(qts);
     g_free(cli);
 }
 
diff --git a/tests/q35-test.c b/tests/q35-test.c
index 34b34bc2b9..a68183d513 100644
--- a/tests/q35-test.c
+++ b/tests/q35-test.c
@@ -84,10 +84,11 @@ static void test_smram_lock(void)
     QPCIBus *pcibus;
     QPCIDevice *pcidev;
     QDict *response;
+    QTestState *qts;
 
-    qtest_start("-M q35");
+    qts = qtest_init("-M q35");
 
-    pcibus = qpci_new_pc(global_qtest, NULL);
+    pcibus = qpci_new_pc(qts, NULL);
     g_assert(pcibus != NULL);
 
     pcidev = qpci_device_find(pcibus, 0);
@@ -106,7 +107,7 @@ static void test_smram_lock(void)
     g_assert(smram_test_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN) == false);
 
     /* reset */
-    response = qmp("{'execute': 'system_reset', 'arguments': {} }");
+    response = qtest_qmp(qts, "{'execute': 'system_reset', 'arguments': {} }");
     g_assert(response);
     g_assert(!qdict_haskey(response, "error"));
     qobject_unref(response);
@@ -120,33 +121,29 @@ static void test_smram_lock(void)
     g_free(pcidev);
     qpci_free_pc(pcibus);
 
-    qtest_end();
+    qtest_quit(qts);
 }
 
 static void test_tseg_size(const void *data)
 {
     const TsegSizeArgs *args = data;
-    char *cmdline;
     QPCIBus *pcibus;
     QPCIDevice *pcidev;
     uint8_t smram_val;
     uint8_t esmramc_val;
     uint32_t ram_offs;
+    QTestState *qts;
 
     if (args->esmramc_tseg_sz == MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_MASK) {
-        cmdline = g_strdup_printf("-M q35 -m %uM "
-                                  "-global mch.extended-tseg-mbytes=%u",
-                                  TSEG_SIZE_TEST_GUEST_RAM_MBYTES,
-                                  args->extended_tseg_mbytes);
+        qts = qtest_initf("-M q35 -m %uM -global mch.extended-tseg-mbytes=%u",
+                          TSEG_SIZE_TEST_GUEST_RAM_MBYTES,
+                          args->extended_tseg_mbytes);
     } else {
-        cmdline = g_strdup_printf("-M q35 -m %uM",
-                                  TSEG_SIZE_TEST_GUEST_RAM_MBYTES);
+        qts = qtest_initf("-M q35 -m %uM", TSEG_SIZE_TEST_GUEST_RAM_MBYTES);
     }
-    qtest_start(cmdline);
-    g_free(cmdline);
 
     /* locate the DRAM controller */
-    pcibus = qpci_new_pc(global_qtest, NULL);
+    pcibus = qpci_new_pc(qts, NULL);
     g_assert(pcibus != NULL);
     pcidev = qpci_device_find(pcibus, 0);
     g_assert(pcidev != NULL);
@@ -175,18 +172,18 @@ static void test_tseg_size(const void *data)
      */
     ram_offs = (TSEG_SIZE_TEST_GUEST_RAM_MBYTES - args->expected_tseg_mbytes) *
                1024 * 1024 - 1;
-    g_assert_cmpint(readb(ram_offs), ==, 0);
-    writeb(ram_offs, 1);
-    g_assert_cmpint(readb(ram_offs), ==, 1);
+    g_assert_cmpint(qtest_readb(qts, ram_offs), ==, 0);
+    qtest_writeb(qts, ram_offs, 1);
+    g_assert_cmpint(qtest_readb(qts, ram_offs), ==, 1);
 
     ram_offs++;
-    g_assert_cmpint(readb(ram_offs), ==, 0xff);
-    writeb(ram_offs, 1);
-    g_assert_cmpint(readb(ram_offs), ==, 0xff);
+    g_assert_cmpint(qtest_readb(qts, ram_offs), ==, 0xff);
+    qtest_writeb(qts, ram_offs, 1);
+    g_assert_cmpint(qtest_readb(qts, ram_offs), ==, 0xff);
 
     g_free(pcidev);
     qpci_free_pc(pcibus);
-    qtest_end();
+    qtest_quit(qts);
 }
 
 int main(int argc, char **argv)
diff --git a/tests/qemu-iotests/001 b/tests/qemu-iotests/001
index 5d266e170a..d87a535c33 100755
--- a/tests/qemu-iotests/001
+++ b/tests/qemu-iotests/001
@@ -38,7 +38,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt generic
 _supported_proto generic
-_supported_os Linux
 
 
 size=128M
diff --git a/tests/qemu-iotests/002 b/tests/qemu-iotests/002
index 7fb85084a1..fd413bce48 100755
--- a/tests/qemu-iotests/002
+++ b/tests/qemu-iotests/002
@@ -38,7 +38,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt generic
 _supported_proto generic
-_supported_os Linux
 
 
 size=128M
diff --git a/tests/qemu-iotests/003 b/tests/qemu-iotests/003
index f008c57cdc..ccd3a39dfb 100755
--- a/tests/qemu-iotests/003
+++ b/tests/qemu-iotests/003
@@ -38,7 +38,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt generic
 _supported_proto generic
-_supported_os Linux
 
 size=128M
 offset=67M
diff --git a/tests/qemu-iotests/004 b/tests/qemu-iotests/004
index 64fab3e714..d308dc4b49 100755
--- a/tests/qemu-iotests/004
+++ b/tests/qemu-iotests/004
@@ -38,7 +38,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt raw qcow qcow2 qed vdi vmdk vhdx luks
 _supported_proto generic
-_supported_os Linux
 
 
 size=128M
diff --git a/tests/qemu-iotests/005 b/tests/qemu-iotests/005
index 2fef63af88..9c7681c19b 100755
--- a/tests/qemu-iotests/005
+++ b/tests/qemu-iotests/005
@@ -55,6 +55,15 @@ if [ "$IMGPROTO" = "sheepdog" ]; then
     _notrun "image protocol $IMGPROTO does not support large image sizes"
 fi
 
+# Sanity check: For raw, we require a file system that permits the creation
+# of a HUGE (but very sparse) file. Check we can create it before continuing.
+if [ "$IMGFMT" = "raw" ]; then
+    if ! truncate --size=5T "$TEST_IMG"; then
+        _notrun "file system on $TEST_DIR does not support large enough files"
+    fi
+    rm "$TEST_IMG"
+fi
+
 echo
 echo "creating large image"
 _make_test_img 5000G
diff --git a/tests/qemu-iotests/007 b/tests/qemu-iotests/007
index 3ab5490db3..6abd402423 100755
--- a/tests/qemu-iotests/007
+++ b/tests/qemu-iotests/007
@@ -40,7 +40,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 # currently only qcow2 allows for consistency checks using qemu-img
 _supported_fmt qcow2
 _supported_proto generic
-_supported_os Linux
 # refcount_bits must be at least 4 so we can create ten internal snapshots
 # (1 bit supports none, 2 bits support two, 4 bits support 14)
 _unsupported_imgopts 'refcount_bits=\(1\|2\)[^0-9]'
diff --git a/tests/qemu-iotests/008 b/tests/qemu-iotests/008
index 75067e36ad..2b81b119bf 100755
--- a/tests/qemu-iotests/008
+++ b/tests/qemu-iotests/008
@@ -38,7 +38,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt generic
 _supported_proto generic
-_supported_os Linux
 
 
 size=128M
diff --git a/tests/qemu-iotests/009 b/tests/qemu-iotests/009
index bc4b461122..51b200db1d 100755
--- a/tests/qemu-iotests/009
+++ b/tests/qemu-iotests/009
@@ -38,7 +38,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt generic
 _supported_proto generic
-_supported_os Linux
 
 
 size=6G
diff --git a/tests/qemu-iotests/010 b/tests/qemu-iotests/010
index 6920408d28..48c533f632 100755
--- a/tests/qemu-iotests/010
+++ b/tests/qemu-iotests/010
@@ -38,7 +38,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt generic
 _supported_proto generic
-_supported_os Linux
 
 
 size=6G
diff --git a/tests/qemu-iotests/011 b/tests/qemu-iotests/011
index b4c7e8f799..8b1fce069a 100755
--- a/tests/qemu-iotests/011
+++ b/tests/qemu-iotests/011
@@ -38,7 +38,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt generic
 _supported_proto generic
-_supported_os Linux
 
 
 size=6G
diff --git a/tests/qemu-iotests/012 b/tests/qemu-iotests/012
index 2c3b42d9dd..12957285b3 100755
--- a/tests/qemu-iotests/012
+++ b/tests/qemu-iotests/012
@@ -40,7 +40,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt generic
 _supported_proto file
-_supported_os Linux
 
 # Remove once all tests are fixed to use TEST_IMG_FILE
 # correctly and common.rc sets it unconditionally
diff --git a/tests/qemu-iotests/015 b/tests/qemu-iotests/015
index 5a4063e4f5..eec5387f3d 100755
--- a/tests/qemu-iotests/015
+++ b/tests/qemu-iotests/015
@@ -40,7 +40,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 # actually any format that supports snapshots
 _supported_fmt qcow2
 _supported_proto generic
-_supported_os Linux
 # Internal snapshots are (currently) impossible with refcount_bits=1
 _unsupported_imgopts 'refcount_bits=1[^0-9]'
 
diff --git a/tests/qemu-iotests/017 b/tests/qemu-iotests/017
index 83744f29a3..79875de454 100755
--- a/tests/qemu-iotests/017
+++ b/tests/qemu-iotests/017
@@ -41,7 +41,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 _supported_fmt qcow qcow2 vmdk qed
 _supported_proto generic
 _unsupported_proto vxhs
-_supported_os Linux
 _unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat"
 
 TEST_OFFSETS="0 4294967296"
diff --git a/tests/qemu-iotests/020 b/tests/qemu-iotests/020
index 71fa753b4e..6b0ebb37d2 100755
--- a/tests/qemu-iotests/020
+++ b/tests/qemu-iotests/020
@@ -42,7 +42,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 # Any format supporting backing files
 _supported_fmt qcow qcow2 vmdk qed
 _supported_proto file
-_supported_os Linux
 _unsupported_imgopts "subformat=monolithicFlat" \
                      "subformat=twoGbMaxExtentFlat" \
                      "subformat=twoGbMaxExtentSparse"
diff --git a/tests/qemu-iotests/021 b/tests/qemu-iotests/021
index f6555f3b74..f888269fd4 100755
--- a/tests/qemu-iotests/021
+++ b/tests/qemu-iotests/021
@@ -38,7 +38,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt generic
 _supported_proto generic
-_supported_os Linux
 
 
 size=128M
diff --git a/tests/qemu-iotests/022 b/tests/qemu-iotests/022
index b68cd64b33..99eb08f57f 100755
--- a/tests/qemu-iotests/022
+++ b/tests/qemu-iotests/022
@@ -42,7 +42,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 # Any format that supports snapshots
 _supported_fmt qcow2
 _supported_proto generic
-_supported_os Linux
 
 TEST_OFFSETS="10485760 4294967296"
 CLUSTER_SIZE="4096"
diff --git a/tests/qemu-iotests/025 b/tests/qemu-iotests/025
index d9a4ebc5e7..e05d833452 100755
--- a/tests/qemu-iotests/025
+++ b/tests/qemu-iotests/025
@@ -39,7 +39,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt raw qcow2 qed luks
 _supported_proto file sheepdog rbd nfs
-_supported_os Linux
 
 echo "=== Creating image"
 echo
diff --git a/tests/qemu-iotests/026 b/tests/qemu-iotests/026
index ca89ad7048..e30243608b 100755
--- a/tests/qemu-iotests/026
+++ b/tests/qemu-iotests/026
@@ -41,7 +41,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 # Currently only qcow2 supports rebasing
 _supported_fmt qcow2
 _supported_proto file
-_supported_os Linux
 _default_cache_mode "writethrough"
 _supported_cache_modes "writethrough" "none"
 # The refcount table tests expect a certain minimum width for refcount entries
diff --git a/tests/qemu-iotests/027 b/tests/qemu-iotests/027
index b7df9701f7..4cb638022a 100755
--- a/tests/qemu-iotests/027
+++ b/tests/qemu-iotests/027
@@ -38,7 +38,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt vmdk qcow qcow2 qed
 _supported_proto generic
-_supported_os Linux
 
 
 size=128M
diff --git a/tests/qemu-iotests/029 b/tests/qemu-iotests/029
index 5f42f76cc6..94c2713132 100755
--- a/tests/qemu-iotests/029
+++ b/tests/qemu-iotests/029
@@ -42,7 +42,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 _supported_fmt qcow2
 _supported_proto generic
 _unsupported_proto vxhs
-_supported_os Linux
 # Internal snapshots are (currently) impossible with refcount_bits=1
 _unsupported_imgopts 'refcount_bits=1[^0-9]'
 
diff --git a/tests/qemu-iotests/031 b/tests/qemu-iotests/031
index ef92d8eee3..a3c25ec237 100755
--- a/tests/qemu-iotests/031
+++ b/tests/qemu-iotests/031
@@ -40,7 +40,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 # This tests qcow2-specific low-level functionality
 _supported_fmt qcow2
 _supported_proto file
-_supported_os Linux
 
 CLUSTER_SIZE=65536
 
diff --git a/tests/qemu-iotests/032 b/tests/qemu-iotests/032
index a1757bb15e..23c216c549 100755
--- a/tests/qemu-iotests/032
+++ b/tests/qemu-iotests/032
@@ -42,7 +42,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 # This works for any image format (though unlikely to segfault for raw)
 _supported_fmt generic
 _supported_proto generic
-_supported_os Linux
 
 echo
 echo === Prepare image ===
diff --git a/tests/qemu-iotests/033 b/tests/qemu-iotests/033
index cfdf1ec2ba..362a48c0a0 100755
--- a/tests/qemu-iotests/033
+++ b/tests/qemu-iotests/033
@@ -38,7 +38,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt generic
 _supported_proto generic
-_supported_os Linux
 
 
 size=128M
diff --git a/tests/qemu-iotests/035 b/tests/qemu-iotests/035
index 46aa835936..ad6fa3115a 100755
--- a/tests/qemu-iotests/035
+++ b/tests/qemu-iotests/035
@@ -39,7 +39,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt qcow2
 _supported_proto generic
-_supported_os Linux
 
 
 size=6G
diff --git a/tests/qemu-iotests/036 b/tests/qemu-iotests/036
index 1b56394129..f06ff67408 100755
--- a/tests/qemu-iotests/036
+++ b/tests/qemu-iotests/036
@@ -43,7 +43,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 # This tests qcow2-specific low-level functionality
 _supported_fmt qcow2
 _supported_proto file
-_supported_os Linux
 
 # Only qcow2v3 and later supports feature bits
 IMGOPTS="compat=1.1"
diff --git a/tests/qemu-iotests/037 b/tests/qemu-iotests/037
index 0781bebefe..819a2a52d2 100755
--- a/tests/qemu-iotests/037
+++ b/tests/qemu-iotests/037
@@ -38,7 +38,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt qcow qcow2 vmdk qed
 _supported_proto file
-_supported_os Linux
 _unsupported_imgopts "subformat=monolithicFlat" \
                      "subformat=twoGbMaxExtentFlat" \
                      "subformat=twoGbMaxExtentSparse"
diff --git a/tests/qemu-iotests/042 b/tests/qemu-iotests/042
index a9a7fc3041..0e85b356b7 100755
--- a/tests/qemu-iotests/042
+++ b/tests/qemu-iotests/042
@@ -38,7 +38,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt qcow2 qed
 _supported_proto file
-_supported_os Linux
 
 echo
 echo "== Creating zero size image =="
diff --git a/tests/qemu-iotests/043 b/tests/qemu-iotests/043
index 9894b154ec..67cc7e74c2 100755
--- a/tests/qemu-iotests/043
+++ b/tests/qemu-iotests/043
@@ -40,7 +40,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 # Any format supporting backing files
 _supported_fmt qcow2 qed
 _supported_proto file
-_supported_os Linux
 
 
 size=128M
diff --git a/tests/qemu-iotests/046 b/tests/qemu-iotests/046
index 95160bea4c..543355c64f 100755
--- a/tests/qemu-iotests/046
+++ b/tests/qemu-iotests/046
@@ -38,7 +38,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt qcow2
 _supported_proto file
-_supported_os Linux
 
 CLUSTER_SIZE=64k
 size=128M
diff --git a/tests/qemu-iotests/047 b/tests/qemu-iotests/047
index ce81fc6fa7..4528465fb0 100755
--- a/tests/qemu-iotests/047
+++ b/tests/qemu-iotests/047
@@ -39,7 +39,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt qcow2
 _supported_proto generic
-_supported_os Linux
 
 size=128M
 
diff --git a/tests/qemu-iotests/049 b/tests/qemu-iotests/049
index bc09cd6717..c100d30ed0 100755
--- a/tests/qemu-iotests/049
+++ b/tests/qemu-iotests/049
@@ -38,7 +38,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt qcow2
 _supported_proto file
-_supported_os Linux
 
 filter_test_dir()
 {
diff --git a/tests/qemu-iotests/050 b/tests/qemu-iotests/050
index dd7b2c72eb..211fc00797 100755
--- a/tests/qemu-iotests/050
+++ b/tests/qemu-iotests/050
@@ -40,7 +40,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt qcow2 qed
 _supported_proto file
-_supported_os Linux
 
 if test "$IMGFMT" = qcow2 && test $IMGOPTS = ""; then
   IMGOPTS=compat=1.1
diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051
index 02ac960da4..a3deb1fcad 100755
--- a/tests/qemu-iotests/051
+++ b/tests/qemu-iotests/051
@@ -38,7 +38,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt qcow2
 _supported_proto file
-_supported_os Linux
 # A compat=0.10 image is created in this test which does not support anything
 # other than refcount_bits=16
 _unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)'
diff --git a/tests/qemu-iotests/052 b/tests/qemu-iotests/052
index b3a2dc1143..6e2ecbfe21 100755
--- a/tests/qemu-iotests/052
+++ b/tests/qemu-iotests/052
@@ -38,7 +38,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt generic
 _supported_proto file
-_supported_os Linux
 
 # Don't do O_DIRECT on tmpfs
 _supported_cache_modes "writeback" "writethrough" "unsafe"
diff --git a/tests/qemu-iotests/053 b/tests/qemu-iotests/053
index 50c62f0f56..e82bb69881 100755
--- a/tests/qemu-iotests/053
+++ b/tests/qemu-iotests/053
@@ -39,7 +39,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt qcow2 qcow
 _supported_proto file
-_supported_os Linux
 
 echo
 echo "== Creating single sector image =="
diff --git a/tests/qemu-iotests/054 b/tests/qemu-iotests/054
index 0d5e14f847..a8905b60d0 100755
--- a/tests/qemu-iotests/054
+++ b/tests/qemu-iotests/054
@@ -38,7 +38,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt qcow2
 _supported_proto file
-_supported_os Linux
 
 echo
 echo "creating too large image (1 EB)"
diff --git a/tests/qemu-iotests/062 b/tests/qemu-iotests/062
index ed7400fed2..d5f818fcce 100755
--- a/tests/qemu-iotests/062
+++ b/tests/qemu-iotests/062
@@ -40,7 +40,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 # This tests qocw2-specific low-level functionality
 _supported_fmt qcow2
 _supported_proto generic
-_supported_os Linux
 
 IMGOPTS="compat=1.1"
 IMG_SIZE=64M
diff --git a/tests/qemu-iotests/063 b/tests/qemu-iotests/063
index 2d5c0ce9fb..fe4892e467 100755
--- a/tests/qemu-iotests/063
+++ b/tests/qemu-iotests/063
@@ -41,7 +41,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt qcow qcow2 vmdk qed raw
 _supported_proto file
-_supported_os Linux
 _unsupported_imgopts "subformat=monolithicFlat" \
                      "subformat=twoGbMaxExtentFlat" \
                      "subformat=twoGbMaxExtentSparse"
diff --git a/tests/qemu-iotests/066 b/tests/qemu-iotests/066
index f480986e35..28f8c98412 100755
--- a/tests/qemu-iotests/066
+++ b/tests/qemu-iotests/066
@@ -39,7 +39,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 # This tests qocw2-specific low-level functionality
 _supported_fmt qcow2
 _supported_proto generic
-_supported_os Linux
 
 # Intentionally create an unaligned image
 IMGOPTS="compat=1.1"
diff --git a/tests/qemu-iotests/067 b/tests/qemu-iotests/067
index fda16a6b0d..926c79b37c 100755
--- a/tests/qemu-iotests/067
+++ b/tests/qemu-iotests/067
@@ -32,7 +32,6 @@ status=1	# failure is the default!
 
 _supported_fmt qcow2
 _supported_proto file
-_supported_os Linux
 # Because anything other than 16 would change the output of query-block
 _unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)'
 
diff --git a/tests/qemu-iotests/068 b/tests/qemu-iotests/068
index 881a022107..22f5ca3ba6 100755
--- a/tests/qemu-iotests/068
+++ b/tests/qemu-iotests/068
@@ -39,7 +39,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 # This tests qocw2-specific low-level functionality
 _supported_fmt qcow2
 _supported_proto generic
-_supported_os Linux
 
 IMGOPTS="compat=1.1"
 IMG_SIZE=128K
diff --git a/tests/qemu-iotests/069 b/tests/qemu-iotests/069
index 6a8e4aa22e..3974714852 100755
--- a/tests/qemu-iotests/069
+++ b/tests/qemu-iotests/069
@@ -38,7 +38,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt qed qcow qcow2 vmdk
 _supported_proto file
-_supported_os Linux
 _unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat"
 
 IMG_SIZE=128K
diff --git a/tests/qemu-iotests/071 b/tests/qemu-iotests/071
index 7f3e5abd57..1cca9233d0 100755
--- a/tests/qemu-iotests/071
+++ b/tests/qemu-iotests/071
@@ -38,7 +38,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt qcow2
 _supported_proto file
-_supported_os Linux
 
 do_run_qemu()
 {
diff --git a/tests/qemu-iotests/072 b/tests/qemu-iotests/072
index 6f9f247fa5..661b36da2d 100755
--- a/tests/qemu-iotests/072
+++ b/tests/qemu-iotests/072
@@ -38,7 +38,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt vpc vmdk vhdx vdi qed qcow2 qcow
 _supported_proto file
-_supported_os Linux
 
 IMG_SIZE=64M
 
diff --git a/tests/qemu-iotests/073 b/tests/qemu-iotests/073
index 990f90acbd..e684b1b780 100755
--- a/tests/qemu-iotests/073
+++ b/tests/qemu-iotests/073
@@ -39,7 +39,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 _supported_fmt qcow2
 _supported_proto generic
 _unsupported_proto vxhs
-_supported_os Linux
 
 CLUSTER_SIZE=64k
 size=128M
diff --git a/tests/qemu-iotests/079 b/tests/qemu-iotests/079
index 1b6594ebef..81f0c21f53 100755
--- a/tests/qemu-iotests/079
+++ b/tests/qemu-iotests/079
@@ -38,7 +38,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt qcow2
 _supported_proto file nfs
-_supported_os Linux
 
 echo "=== Check option preallocation and cluster_size ==="
 echo
diff --git a/tests/qemu-iotests/082 b/tests/qemu-iotests/082
index 278511dba4..bbbdf555dc 100755
--- a/tests/qemu-iotests/082
+++ b/tests/qemu-iotests/082
@@ -38,7 +38,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt qcow2
 _supported_proto file nfs
-_supported_os Linux
 
 run_qemu_img()
 {
diff --git a/tests/qemu-iotests/085 b/tests/qemu-iotests/085
index 68cb665987..d40fdab542 100755
--- a/tests/qemu-iotests/085
+++ b/tests/qemu-iotests/085
@@ -56,7 +56,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt qcow2
 _supported_proto file
-_supported_os Linux
 
 
 # ${1}: unique identifier for the snapshot filename
diff --git a/tests/qemu-iotests/089 b/tests/qemu-iotests/089
index 6609954908..ad029f1f09 100755
--- a/tests/qemu-iotests/089
+++ b/tests/qemu-iotests/089
@@ -38,7 +38,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt qcow2
 _supported_proto file
-_supported_os Linux
 # Because anything other than 16 would change the output of qemu_io -c info
 _unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)'
 
diff --git a/tests/qemu-iotests/090 b/tests/qemu-iotests/090
index 193bae7d77..9f8cfbb80f 100755
--- a/tests/qemu-iotests/090
+++ b/tests/qemu-iotests/090
@@ -38,7 +38,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt qcow2
 _supported_proto file nfs
-_supported_os Linux
 
 IMG_SIZE=128K
 
diff --git a/tests/qemu-iotests/094 b/tests/qemu-iotests/094
index 0bcca77261..9343e09492 100755
--- a/tests/qemu-iotests/094
+++ b/tests/qemu-iotests/094
@@ -42,7 +42,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt generic
 _supported_proto nbd
-_supported_os Linux
 _unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat"
 
 _make_test_img 64M
diff --git a/tests/qemu-iotests/095 b/tests/qemu-iotests/095
index 18505b7181..58fe174b5e 100755
--- a/tests/qemu-iotests/095
+++ b/tests/qemu-iotests/095
@@ -44,7 +44,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt qcow2
 _supported_proto file
-_supported_os Linux
 
 size_smaller=5M
 size_larger=100M
diff --git a/tests/qemu-iotests/098 b/tests/qemu-iotests/098
index 461144c831..1c1d1c468f 100755
--- a/tests/qemu-iotests/098
+++ b/tests/qemu-iotests/098
@@ -40,7 +40,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt qcow2
 _supported_proto file
-_supported_os Linux
 
 IMGOPTS="compat=1.1"
 
diff --git a/tests/qemu-iotests/102 b/tests/qemu-iotests/102
index cedd2b25dc..749ff66b8a 100755
--- a/tests/qemu-iotests/102
+++ b/tests/qemu-iotests/102
@@ -40,7 +40,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt qcow2
 _supported_proto file
-_supported_os Linux
 
 IMG_SIZE=64K
 
diff --git a/tests/qemu-iotests/103 b/tests/qemu-iotests/103
index 6773e94d9f..554b9de054 100755
--- a/tests/qemu-iotests/103
+++ b/tests/qemu-iotests/103
@@ -38,7 +38,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt qcow2
 _supported_proto file nfs
-_supported_os Linux
 # Internal snapshots are (currently) impossible with refcount_bits=1
 _unsupported_imgopts 'refcount_bits=1[^0-9]'
 
diff --git a/tests/qemu-iotests/104 b/tests/qemu-iotests/104
index 390167bad4..c70f28a9a1 100755
--- a/tests/qemu-iotests/104
+++ b/tests/qemu-iotests/104
@@ -34,7 +34,6 @@ trap "exit \$status" 0 1 2 3 15
 
 _supported_fmt raw qcow qcow2 qed vdi vmdk vhdx
 _supported_proto generic
-_supported_os Linux
 
 echo "=== Check qemu-img info output ==="
 echo
diff --git a/tests/qemu-iotests/105 b/tests/qemu-iotests/105
index 3b5a596844..3346e8cb25 100755
--- a/tests/qemu-iotests/105
+++ b/tests/qemu-iotests/105
@@ -38,7 +38,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt qcow2 vmdk vhdx qed
 _supported_proto generic
-_supported_os Linux
 _unsupported_imgopts "subformat=twoGbMaxExtentFlat" \
                      "subformat=twoGbMaxExtentSparse"
 
diff --git a/tests/qemu-iotests/107 b/tests/qemu-iotests/107
index fcd5a24dfe..268ba27688 100755
--- a/tests/qemu-iotests/107
+++ b/tests/qemu-iotests/107
@@ -38,7 +38,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt qcow2
 _supported_proto file nfs
-_supported_os Linux
 
 
 IMG_SIZE=64K
diff --git a/tests/qemu-iotests/110 b/tests/qemu-iotests/110
index 33b169ffd4..2cdc7c8a72 100755
--- a/tests/qemu-iotests/110
+++ b/tests/qemu-iotests/110
@@ -40,7 +40,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 # Any format supporting backing files
 _supported_fmt qed qcow qcow2 vmdk
 _supported_proto file
-_supported_os Linux
 _unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat"
 
 TEST_IMG_REL=$(basename "$TEST_IMG")
diff --git a/tests/qemu-iotests/111 b/tests/qemu-iotests/111
index 57395be64c..490a5bbcb5 100755
--- a/tests/qemu-iotests/111
+++ b/tests/qemu-iotests/111
@@ -39,7 +39,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt qed qcow qcow2 vmdk
 _supported_proto file
-_supported_os Linux
 _unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat"
 
 $QEMU_IMG create -f $IMGFMT -b "$TEST_IMG.inexistent" "$TEST_IMG" 2>&1 \
diff --git a/tests/qemu-iotests/112 b/tests/qemu-iotests/112
index 6d81c75a9c..706c10b600 100755
--- a/tests/qemu-iotests/112
+++ b/tests/qemu-iotests/112
@@ -39,7 +39,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 # This tests qcow2-specific low-level functionality
 _supported_fmt qcow2
 _supported_proto file
-_supported_os Linux
 # This test will set refcount_bits on its own which would conflict with the
 # manual setting; compat will be overridden as well
 _unsupported_imgopts refcount_bits 'compat=0.10'
diff --git a/tests/qemu-iotests/114 b/tests/qemu-iotests/114
index f36b88f3f3..f90a744fc0 100755
--- a/tests/qemu-iotests/114
+++ b/tests/qemu-iotests/114
@@ -39,7 +39,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 _supported_fmt qcow2
 _supported_proto generic
 _unsupported_proto vxhs
-_supported_os Linux
 
 
 TEST_IMG="$TEST_IMG.base" _make_test_img 64M
diff --git a/tests/qemu-iotests/115 b/tests/qemu-iotests/115
index 7ed347010f..9ed3cb6a83 100755
--- a/tests/qemu-iotests/115
+++ b/tests/qemu-iotests/115
@@ -38,7 +38,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt qcow2
 _supported_proto file
-_supported_os Linux
 # This test relies on refcounts being 64 bits wide (which does not work with
 # compat=0.10)
 _unsupported_imgopts 'refcount_bits=\([^6]\|.\([^4]\|$\)\)' 'compat=0.10'
diff --git a/tests/qemu-iotests/117 b/tests/qemu-iotests/117
index 0af0f31c5a..f37b34f8b1 100755
--- a/tests/qemu-iotests/117
+++ b/tests/qemu-iotests/117
@@ -40,7 +40,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt qcow2
 _supported_proto file
-_supported_os Linux
 
 _make_test_img 64k
 
diff --git a/tests/qemu-iotests/120 b/tests/qemu-iotests/120
index ca95b9276e..e9b4fbb009 100755
--- a/tests/qemu-iotests/120
+++ b/tests/qemu-iotests/120
@@ -39,7 +39,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt generic
 _supported_proto file
-_supported_os Linux
 _unsupported_fmt luks
 
 _make_test_img 64M
diff --git a/tests/qemu-iotests/125 b/tests/qemu-iotests/125
index 212dcd8f0d..dc4b8f5fb9 100755
--- a/tests/qemu-iotests/125
+++ b/tests/qemu-iotests/125
@@ -44,7 +44,6 @@ get_image_size_on_host()
 
 _supported_fmt qcow2
 _supported_proto file
-_supported_os Linux
 
 if [ -z "$TEST_IMG_FILE" ]; then
     TEST_IMG_FILE=$TEST_IMG
diff --git a/tests/qemu-iotests/126 b/tests/qemu-iotests/126
index e3ee65c606..9b0dcf9255 100755
--- a/tests/qemu-iotests/126
+++ b/tests/qemu-iotests/126
@@ -37,7 +37,6 @@ _supported_fmt qcow qcow2 qed vmdk
 # colons which separate a protocol prefix from the rest and colons which are
 # just part of the filename, so we cannot test protocols which require a prefix)
 _supported_proto file
-_supported_os Linux
 
 echo
 echo '=== Testing plain files ==='
diff --git a/tests/qemu-iotests/127 b/tests/qemu-iotests/127
index 3e941f74d4..b64926ab31 100755
--- a/tests/qemu-iotests/127
+++ b/tests/qemu-iotests/127
@@ -42,7 +42,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt qcow2
 _supported_proto file
-_supported_os Linux
 
 IMG_SIZE=64K
 
diff --git a/tests/qemu-iotests/133 b/tests/qemu-iotests/133
index 1f6056d144..6f7cacc091 100755
--- a/tests/qemu-iotests/133
+++ b/tests/qemu-iotests/133
@@ -38,7 +38,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt qcow2
 _supported_proto file
-_supported_os Linux
 
 TEST_IMG="$TEST_IMG.base" _make_test_img 64M
 _make_test_img -b "$TEST_IMG.base"
diff --git a/tests/qemu-iotests/134 b/tests/qemu-iotests/134
index e9e3e84c2a..141a2eaa7e 100755
--- a/tests/qemu-iotests/134
+++ b/tests/qemu-iotests/134
@@ -39,7 +39,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 _supported_fmt qcow qcow2
 _supported_proto generic
 _unsupported_proto vxhs
-_supported_os Linux
 
 
 size=128M
diff --git a/tests/qemu-iotests/142 b/tests/qemu-iotests/142
index d9b98cf60a..6b62271876 100755
--- a/tests/qemu-iotests/142
+++ b/tests/qemu-iotests/142
@@ -39,7 +39,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt qcow2
 _supported_proto file
-_supported_os Linux
 
 # We test all cache modes anyway, but O_DIRECT needs to be supported
 _default_cache_mode none
diff --git a/tests/qemu-iotests/143 b/tests/qemu-iotests/143
index c223867cb3..92249ac8da 100755
--- a/tests/qemu-iotests/143
+++ b/tests/qemu-iotests/143
@@ -40,7 +40,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt generic
 _supported_proto generic
-_supported_os Linux
 
 keep_stderr=y \
 _launch_qemu 2> >(_filter_nbd)
diff --git a/tests/qemu-iotests/144 b/tests/qemu-iotests/144
index 15157f33d7..011ed4f2bc 100755
--- a/tests/qemu-iotests/144
+++ b/tests/qemu-iotests/144
@@ -46,7 +46,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt qcow2
 _supported_proto file
-_supported_os Linux
 
 size=512M
 
diff --git a/tests/qemu-iotests/145 b/tests/qemu-iotests/145
index 28878dc8a1..9427549651 100755
--- a/tests/qemu-iotests/145
+++ b/tests/qemu-iotests/145
@@ -39,7 +39,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt generic
 _supported_proto generic
-_supported_os Linux
 
 _make_test_img 1M
 
diff --git a/tests/qemu-iotests/153 b/tests/qemu-iotests/153
index 08ad8a6730..c969a1a16f 100755
--- a/tests/qemu-iotests/153
+++ b/tests/qemu-iotests/153
@@ -62,7 +62,6 @@ _check_ofd || _notrun "OFD lock not available"
 
 _supported_fmt qcow2
 _supported_proto file
-_supported_os Linux
 
 _run_cmd()
 {
diff --git a/tests/qemu-iotests/156 b/tests/qemu-iotests/156
index 8d134029c6..2ffa3ca942 100755
--- a/tests/qemu-iotests/156
+++ b/tests/qemu-iotests/156
@@ -49,7 +49,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 _supported_fmt qcow2 qed
 _supported_proto generic
 _unsupported_proto vxhs
-_supported_os Linux
 
 # Create source disk
 TEST_IMG="$TEST_IMG.backing" _make_test_img 1M
diff --git a/tests/qemu-iotests/157 b/tests/qemu-iotests/157
index 69b25cab30..7cbac38099 100755
--- a/tests/qemu-iotests/157
+++ b/tests/qemu-iotests/157
@@ -38,7 +38,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt generic
 _supported_proto file
-_supported_os Linux
 
 do_run_qemu()
 {
diff --git a/tests/qemu-iotests/158 b/tests/qemu-iotests/158
index 8c0928a7f9..ba4db6116a 100755
--- a/tests/qemu-iotests/158
+++ b/tests/qemu-iotests/158
@@ -39,7 +39,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 _supported_fmt qcow qcow2
 _supported_proto generic
 _unsupported_proto vxhs
-_supported_os Linux
 
 
 size=128M
diff --git a/tests/qemu-iotests/159 b/tests/qemu-iotests/159
index 29066eebde..2557140ac2 100755
--- a/tests/qemu-iotests/159
+++ b/tests/qemu-iotests/159
@@ -38,7 +38,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt generic
 _supported_proto file
-_supported_os Linux
 _unsupported_fmt luks
 
 TEST_SIZES="5 512 1024 1999 1K 64K 1M"
diff --git a/tests/qemu-iotests/162 b/tests/qemu-iotests/162
index 2e9947fd9a..4e5ed74fd5 100755
--- a/tests/qemu-iotests/162
+++ b/tests/qemu-iotests/162
@@ -39,7 +39,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 . ./common.filter
 
 _supported_fmt generic
-_supported_os Linux
 
 test_ssh=$($QEMU_IMG --help | grep '^Supported formats:.* ssh\( \|$\)')
 [ "$test_ssh" = "" ] && _notrun "ssh support required"
diff --git a/tests/qemu-iotests/169 b/tests/qemu-iotests/169
index 527aebd0cb..7e06cc1145 100755
--- a/tests/qemu-iotests/169
+++ b/tests/qemu-iotests/169
@@ -102,12 +102,17 @@ class TestDirtyBitmapMigration(iotests.QMPTestCase):
             event = self.vm_a.event_wait('MIGRATION')
             if event['data']['status'] == 'completed':
                 break
+        while True:
+            result = self.vm_a.qmp('query-status')
+            if (result['return']['status'] == 'postmigrate'):
+                break
 
         # test that bitmap is still here
         removed = (not migrate_bitmaps) and persistent
         self.check_bitmap(self.vm_a, False if removed else sha256)
 
-        self.vm_a.qmp('cont')
+        result = self.vm_a.qmp('cont')
+        self.assert_qmp(result, 'return', {})
 
         # test that bitmap is still here after invalidation
         self.check_bitmap(self.vm_a, sha256)
diff --git a/tests/qemu-iotests/170 b/tests/qemu-iotests/170
index 7deb7563c9..05dd6ed6c3 100755
--- a/tests/qemu-iotests/170
+++ b/tests/qemu-iotests/170
@@ -38,7 +38,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt generic
 _supported_proto file
-_supported_os Linux
 _unsupported_fmt luks
 
 echo
diff --git a/tests/qemu-iotests/173 b/tests/qemu-iotests/173
index 47036a5564..9e2fa2e73c 100755
--- a/tests/qemu-iotests/173
+++ b/tests/qemu-iotests/173
@@ -41,7 +41,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt qcow2
 _supported_proto nfs
-_supported_os Linux
 
 size=100M
 
diff --git a/tests/qemu-iotests/182 b/tests/qemu-iotests/182
index 38959bf276..3a90ebfbfd 100755
--- a/tests/qemu-iotests/182
+++ b/tests/qemu-iotests/182
@@ -42,7 +42,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt qcow2
 _supported_proto file
-_supported_os Linux
 
 size=32M
 
diff --git a/tests/qemu-iotests/183 b/tests/qemu-iotests/183
index 93b7bd798a..fbe5a99beb 100755
--- a/tests/qemu-iotests/183
+++ b/tests/qemu-iotests/183
@@ -44,7 +44,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt qcow2 raw qed quorum
 _supported_proto file
-_supported_os Linux
 
 size=64M
 _make_test_img $size
diff --git a/tests/qemu-iotests/186 b/tests/qemu-iotests/186
index 5dd2177b89..7e7d45babc 100755
--- a/tests/qemu-iotests/186
+++ b/tests/qemu-iotests/186
@@ -38,7 +38,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt qcow2
 _supported_proto file
-_supported_os Linux
 
 if [ "$QEMU_DEFAULT_MACHINE" != "pc" ]; then
     _notrun "Requires a PC machine"
diff --git a/tests/qemu-iotests/187 b/tests/qemu-iotests/187
index a45addde09..2fcef9e2bd 100755
--- a/tests/qemu-iotests/187
+++ b/tests/qemu-iotests/187
@@ -40,7 +40,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt qcow2
 _supported_proto file
-_supported_os Linux
 
 size=64M
 _make_test_img $size
diff --git a/tests/qemu-iotests/190 b/tests/qemu-iotests/190
index e1c1d407f0..eb766ad09f 100755
--- a/tests/qemu-iotests/190
+++ b/tests/qemu-iotests/190
@@ -41,7 +41,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 # See 178 for more extensive tests across more formats
 _supported_fmt qcow2
 _supported_proto file
-_supported_os Linux
 
 echo "== Huge file =="
 echo
diff --git a/tests/qemu-iotests/191 b/tests/qemu-iotests/191
index 1ea908ce3d..528022e8d8 100755
--- a/tests/qemu-iotests/191
+++ b/tests/qemu-iotests/191
@@ -43,7 +43,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt qcow2
 _supported_proto file
-_supported_os Linux
 
 size=64M
 
diff --git a/tests/qemu-iotests/192 b/tests/qemu-iotests/192
index 61a88ac88d..6193257764 100755
--- a/tests/qemu-iotests/192
+++ b/tests/qemu-iotests/192
@@ -42,7 +42,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt generic
 _supported_proto file
-_supported_os Linux
 
 if [ "$QEMU_DEFAULT_MACHINE" != "pc" ]; then
     _notrun "Requires a PC machine"
diff --git a/tests/qemu-iotests/195 b/tests/qemu-iotests/195
index bd1b71ae5e..ef7b9a94e2 100755
--- a/tests/qemu-iotests/195
+++ b/tests/qemu-iotests/195
@@ -39,7 +39,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt qcow2
 _supported_proto file
-_supported_os Linux
 
 do_run_qemu()
 {
diff --git a/tests/qemu-iotests/197 b/tests/qemu-iotests/197
index 2c664793f4..383d7d7f61 100755
--- a/tests/qemu-iotests/197
+++ b/tests/qemu-iotests/197
@@ -51,7 +51,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 # Test is supported for any backing file; but we force qcow2 for our wrapper.
 _supported_fmt generic
 _supported_proto generic
-_supported_os Linux
 # LUKS support may be possible, but it complicates things.
 _unsupported_fmt luks
 
diff --git a/tests/qemu-iotests/200 b/tests/qemu-iotests/200
index 1c0f8cafc2..72d431f251 100755
--- a/tests/qemu-iotests/200
+++ b/tests/qemu-iotests/200
@@ -42,7 +42,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt qcow2 qed
 _supported_proto file
-_supported_os Linux
 
 BACKING_IMG="${TEST_DIR}/backing.img"
 TEST_IMG="${TEST_DIR}/test.img"
diff --git a/tests/qemu-iotests/214 b/tests/qemu-iotests/214
index c1a452ff9a..21ec8a2ad8 100755
--- a/tests/qemu-iotests/214
+++ b/tests/qemu-iotests/214
@@ -36,7 +36,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt qcow2
 _supported_proto file
-_supported_os Linux
 
 # Repairing the corrupted image requires qemu-img check to store a
 # refcount up to 3, which requires at least two refcount bits.
diff --git a/tests/qemu-iotests/215 b/tests/qemu-iotests/215
index 7b063d7cfa..958c14f5a0 100755
--- a/tests/qemu-iotests/215
+++ b/tests/qemu-iotests/215
@@ -48,7 +48,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 # Test is supported for any backing file; but we force qcow2 for our wrapper.
 _supported_fmt generic
 _supported_proto generic
-_supported_os Linux
 # LUKS support may be possible, but it complicates things.
 _unsupported_fmt luks
 
diff --git a/tests/qemu-iotests/217 b/tests/qemu-iotests/217
index f5482bb669..58a78a6098 100755
--- a/tests/qemu-iotests/217
+++ b/tests/qemu-iotests/217
@@ -37,7 +37,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 # This test is specific to qcow2
 _supported_fmt qcow2
 _supported_proto file
-_supported_os Linux
 
 # This test needs clusters with at least a refcount of 2 so that
 # OFLAG_COPIED is not set.  refcount_bits=1 is therefore unsupported.
diff --git a/tests/qemu-iotests/221 b/tests/qemu-iotests/221
index 25dd47bcfe..0e9096fec7 100755
--- a/tests/qemu-iotests/221
+++ b/tests/qemu-iotests/221
@@ -1,6 +1,7 @@
 #!/usr/bin/env bash
 #
 # Test qemu-img vs. unaligned images
+# (See also 253, which is the O_DIRECT version)
 #
 # Copyright (C) 2018-2019 Red Hat, Inc.
 #
@@ -37,6 +38,9 @@ _supported_fmt raw
 _supported_proto file
 _supported_os Linux
 
+_default_cache_mode writeback
+_supported_cache_modes writeback writethrough unsafe
+
 echo
 echo "=== Check mapping of unaligned raw image ==="
 echo
diff --git a/tests/qemu-iotests/227 b/tests/qemu-iotests/227
index 10cf144eb0..bdd727a721 100755
--- a/tests/qemu-iotests/227
+++ b/tests/qemu-iotests/227
@@ -38,7 +38,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt generic
 _supported_proto file
-_supported_os Linux
 
 do_run_qemu()
 {
diff --git a/tests/qemu-iotests/231 b/tests/qemu-iotests/231
index 5b2cbab9ac..c0b053ac30 100755
--- a/tests/qemu-iotests/231
+++ b/tests/qemu-iotests/231
@@ -40,7 +40,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 
 _supported_fmt generic
 _supported_proto rbd
-_supported_os Linux
 
 BOGUS_CONF=${TEST_DIR}/ceph-$$.conf
 touch "${BOGUS_CONF}"
diff --git a/tests/qemu-iotests/233 b/tests/qemu-iotests/233
index 41b4d46560..057cad2044 100755
--- a/tests/qemu-iotests/233
+++ b/tests/qemu-iotests/233
@@ -47,7 +47,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 _supported_fmt raw qcow2
 _supported_proto file
 # If porting to non-Linux, consider using socat instead of ss in common.nbd
-_supported_os Linux
 _require_command QEMU_NBD
 
 nbd_server_set_tcp_port
diff --git a/tests/qemu-iotests/239 b/tests/qemu-iotests/239
index 6f085d573d..b0991ffe59 100755
--- a/tests/qemu-iotests/239
+++ b/tests/qemu-iotests/239
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
 #
 # Test case for dmg
 #
diff --git a/tests/qemu-iotests/240 b/tests/qemu-iotests/240
index 65cc3b39b1..b4cf95096d 100755
--- a/tests/qemu-iotests/240
+++ b/tests/qemu-iotests/240
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
 #
 # Test hot plugging and unplugging with iothreads
 #
@@ -33,7 +33,6 @@ status=1	# failure is the default!
 
 _supported_fmt generic
 _supported_proto generic
-_supported_os Linux
 
 do_run_qemu()
 {
diff --git a/tests/qemu-iotests/241 b/tests/qemu-iotests/241
index 017a736aab..58b64ebf41 100755
--- a/tests/qemu-iotests/241
+++ b/tests/qemu-iotests/241
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
 #
 # Test qemu-nbd vs. unaligned images
 #
diff --git a/tests/qemu-iotests/243 b/tests/qemu-iotests/243
index 5838c6e89c..e563761307 100755
--- a/tests/qemu-iotests/243
+++ b/tests/qemu-iotests/243
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
 #
 # Test qcow2 preallocation
 #
diff --git a/tests/qemu-iotests/244 b/tests/qemu-iotests/244
index d8e7122305..13978f93d2 100755
--- a/tests/qemu-iotests/244
+++ b/tests/qemu-iotests/244
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
 #
 # Test qcow2 with external data files
 #
diff --git a/tests/qemu-iotests/245 b/tests/qemu-iotests/245
index a04c6235c1..349b94aace 100644
--- a/tests/qemu-iotests/245
+++ b/tests/qemu-iotests/245
@@ -862,7 +862,8 @@ class TestBlockdevReopen(iotests.QMPTestCase):
 
         # hd2 <- hd0
         result = self.vm.qmp('block-stream', conv_keys = True, job_id = 'stream0',
-                             device = 'hd0', base_node = 'hd2', speed = 512 * 1024)
+                             device = 'hd0', base_node = 'hd2',
+                             auto_finalize = False)
         self.assert_qmp(result, 'return', {})
 
         # We can't remove hd2 while the stream job is ongoing
@@ -873,7 +874,7 @@ class TestBlockdevReopen(iotests.QMPTestCase):
         opts['backing'] = None
         self.reopen(opts, {}, "Cannot change 'backing' link from 'hd0' to 'hd1'")
 
-        self.wait_until_completed(drive = 'stream0')
+        self.vm.run_job('stream0', auto_finalize = False, auto_dismiss = True)
 
     # Reopen the chain during a block-stream job (from hd2 to hd1)
     def test_block_stream_4(self):
@@ -886,12 +887,16 @@ class TestBlockdevReopen(iotests.QMPTestCase):
 
         # hd1 <- hd0
         result = self.vm.qmp('block-stream', conv_keys = True, job_id = 'stream0',
-                             device = 'hd1', speed = 512 * 1024)
+                             device = 'hd1', auto_finalize = False)
         self.assert_qmp(result, 'return', {})
 
         # We can't reopen with the original options because that would
         # make hd1 read-only and block-stream requires it to be read-write
-        self.reopen(opts, {}, "Can't set node 'hd1' to r/o with copy-on-read enabled")
+        # (Which error message appears depends on whether the stream job is
+        # already done with copying at this point.)
+        self.reopen(opts, {},
+            ["Can't set node 'hd1' to r/o with copy-on-read enabled",
+             "Cannot make block node read-only, there is a writer on it"])
 
         # We can't remove hd2 while the stream job is ongoing
         opts['backing']['backing'] = None
@@ -901,7 +906,7 @@ class TestBlockdevReopen(iotests.QMPTestCase):
         opts['backing'] = None
         self.reopen(opts)
 
-        self.wait_until_completed(drive = 'stream0')
+        self.vm.run_job('stream0', auto_finalize = False, auto_dismiss = True)
 
     # Reopen the chain during a block-commit job (from hd0 to hd2)
     def test_block_commit_1(self):
@@ -913,7 +918,7 @@ class TestBlockdevReopen(iotests.QMPTestCase):
         self.assert_qmp(result, 'return', {})
 
         result = self.vm.qmp('block-commit', conv_keys = True, job_id = 'commit0',
-                             device = 'hd0', speed = 1024 * 1024)
+                             device = 'hd0')
         self.assert_qmp(result, 'return', {})
 
         # We can't remove hd2 while the commit job is ongoing
@@ -944,7 +949,8 @@ class TestBlockdevReopen(iotests.QMPTestCase):
         self.assert_qmp(result, 'return', {})
 
         result = self.vm.qmp('block-commit', conv_keys = True, job_id = 'commit0',
-                             device = 'hd0', top_node = 'hd1', speed = 1024 * 1024)
+                             device = 'hd0', top_node = 'hd1',
+                             auto_finalize = False)
         self.assert_qmp(result, 'return', {})
 
         # We can't remove hd2 while the commit job is ongoing
@@ -956,7 +962,7 @@ class TestBlockdevReopen(iotests.QMPTestCase):
         self.reopen(opts, {}, "Cannot change backing link if 'hd0' has an implicit backing file")
 
         # hd2 <- hd0
-        self.wait_until_completed(drive = 'commit0')
+        self.vm.run_job('commit0', auto_finalize = False, auto_dismiss = True)
 
         self.assert_qmp(self.get_node('hd0'), 'ro', False)
         self.assertEqual(self.get_node('hd1'), None)
diff --git a/tests/qemu-iotests/245.out b/tests/qemu-iotests/245.out
index 71009c239f..a19de5214d 100644
--- a/tests/qemu-iotests/245.out
+++ b/tests/qemu-iotests/245.out
@@ -3,3 +3,15 @@
 Ran 18 tests
 
 OK
+{"execute": "job-finalize", "arguments": {"id": "commit0"}}
+{"return": {}}
+{"data": {"id": "commit0", "type": "commit"}, "event": "BLOCK_JOB_PENDING", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
+{"data": {"device": "commit0", "len": 3145728, "offset": 3145728, "speed": 0, "type": "commit"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
+{"execute": "job-finalize", "arguments": {"id": "stream0"}}
+{"return": {}}
+{"data": {"id": "stream0", "type": "stream"}, "event": "BLOCK_JOB_PENDING", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
+{"data": {"device": "stream0", "len": 3145728, "offset": 3145728, "speed": 0, "type": "stream"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
+{"execute": "job-finalize", "arguments": {"id": "stream0"}}
+{"return": {}}
+{"data": {"id": "stream0", "type": "stream"}, "event": "BLOCK_JOB_PENDING", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
+{"data": {"device": "stream0", "len": 3145728, "offset": 3145728, "speed": 0, "type": "stream"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
diff --git a/tests/qemu-iotests/247 b/tests/qemu-iotests/247
index fc50eb5dc1..546a794d3d 100755
--- a/tests/qemu-iotests/247
+++ b/tests/qemu-iotests/247
@@ -40,7 +40,6 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 # Requires backing files and .bdrv_change_backing_file support
 _supported_fmt qcow2 qed
 _supported_proto file
-_supported_os Linux
 
 size=128M
 
diff --git a/tests/qemu-iotests/253 b/tests/qemu-iotests/253
new file mode 100755
index 0000000000..d88d5afa45
--- /dev/null
+++ b/tests/qemu-iotests/253
@@ -0,0 +1,84 @@
+#!/usr/bin/env bash
+#
+# Test qemu-img vs. unaligned images; O_DIRECT version
+# (Originates from 221)
+#
+# Copyright (C) 2019 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+seq="$(basename $0)"
+echo "QA output created by $seq"
+
+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 raw
+_supported_proto file
+_supported_os Linux
+
+_default_cache_mode none
+_supported_cache_modes none directsync
+
+echo
+echo "=== Check mapping of unaligned raw image ==="
+echo
+
+# We do not know how large a physical sector is, but it is certainly
+# going to be a factor of 1 MB
+size=$((1 * 1024 * 1024 - 1))
+
+# qemu-img create rounds size up to BDRV_SECTOR_SIZE
+_make_test_img $size
+$QEMU_IMG map --output=json --image-opts \
+    "driver=$IMGFMT,file.driver=file,file.filename=$TEST_IMG,cache.direct=on" \
+    | _filter_qemu_img_map
+
+# so we resize it and check again
+truncate --size=$size "$TEST_IMG"
+$QEMU_IMG map --output=json --image-opts \
+    "driver=$IMGFMT,file.driver=file,file.filename=$TEST_IMG,cache.direct=on" \
+    | _filter_qemu_img_map
+
+# qemu-io with O_DIRECT always writes whole physical sectors.  Again,
+# we do not know how large a physical sector is, so we just start
+# writing from a 64 kB boundary, which should always be aligned.
+offset=$((1 * 1024 * 1024 - 64 * 1024))
+$QEMU_IO -c "w $offset $((size - offset))" "$TEST_IMG" | _filter_qemu_io
+$QEMU_IMG map --output=json --image-opts \
+    "driver=$IMGFMT,file.driver=file,file.filename=$TEST_IMG,cache.direct=on" \
+    | _filter_qemu_img_map
+
+# Resize it and check again -- contrary to 221, we may not get partial
+# sectors here, so there should be only two areas (one zero, one
+# data).
+truncate --size=$size "$TEST_IMG"
+$QEMU_IMG map --output=json --image-opts \
+    "driver=$IMGFMT,file.driver=file,file.filename=$TEST_IMG,cache.direct=on" \
+    | _filter_qemu_img_map
+
+# success, all done
+echo '*** done'
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/253.out b/tests/qemu-iotests/253.out
new file mode 100644
index 0000000000..607c0baa0b
--- /dev/null
+++ b/tests/qemu-iotests/253.out
@@ -0,0 +1,14 @@
+QA output created by 253
+
+=== Check mapping of unaligned raw image ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048575
+[{ "start": 0, "length": 1048576, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
+[{ "start": 0, "length": 1048576, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
+wrote 65535/65535 bytes at offset 983040
+63.999 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+[{ "start": 0, "length": 983040, "depth": 0, "zero": true, "data": false, "offset": OFFSET},
+{ "start": 983040, "length": 65536, "depth": 0, "zero": false, "data": true, "offset": OFFSET}]
+[{ "start": 0, "length": 983040, "depth": 0, "zero": true, "data": false, "offset": OFFSET},
+{ "start": 983040, "length": 65536, "depth": 0, "zero": false, "data": true, "offset": OFFSET}]
+*** done
diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check
index f9c24b6753..922c5d1d3d 100755
--- a/tests/qemu-iotests/check
+++ b/tests/qemu-iotests/check
@@ -130,7 +130,6 @@ export CACHEMODE="writeback"
 export QEMU_IO_OPTIONS=""
 export QEMU_IO_OPTIONS_NO_FMT=""
 export CACHEMODE_IS_DEFAULT=true
-export QEMU_OPTIONS="-nodefaults -machine accel=qtest"
 export VALGRIND_QEMU=
 export IMGKEYSECRET=
 export IMGOPTSSYNTAX=false
@@ -564,6 +563,18 @@ then
 fi
 export QEMU_PROG="$(type -p "$QEMU_PROG")"
 
+case "$QEMU_PROG" in
+    *qemu-system-arm|*qemu-system-aarch64)
+        export QEMU_OPTIONS="-nodefaults -machine virt,accel=qtest"
+        ;;
+    *qemu-system-tricore)
+        export QEMU_OPTIONS="-nodefaults -machine tricore_testboard,accel=qtest"
+        ;;
+    *)
+        export QEMU_OPTIONS="-nodefaults -machine accel=qtest"
+        ;;
+esac
+
 if [ -z "$QEMU_IMG_PROG" ]; then
     if [ -x "$build_iotests/qemu-img" ]; then
         export QEMU_IMG_PROG="$build_iotests/qemu-img"
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index 00e474ab0a..52b7c16e15 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -250,3 +250,4 @@
 248 rw auto quick
 249 rw auto quick
 252 rw auto backing quick
+253 rw auto quick
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
index f811f69135..7bde380d96 100644
--- a/tests/qemu-iotests/iotests.py
+++ b/tests/qemu-iotests/iotests.py
@@ -552,7 +552,7 @@ class VM(qtest.QEMUQtestMachine):
                     elif status == 'null':
                         return error
                 else:
-                    iotests.log(ev)
+                    log(ev)
 
     def node_info(self, node_name):
         nodes = self.qmp('query-named-block-nodes')
@@ -596,9 +596,23 @@ class QMPTestCase(unittest.TestCase):
         self.fail('path "%s" has value "%s"' % (path, str(result)))
 
     def assert_qmp(self, d, path, value):
-        '''Assert that the value for a specific path in a QMP dict matches'''
+        '''Assert that the value for a specific path in a QMP dict
+           matches.  When given a list of values, assert that any of
+           them matches.'''
+
         result = self.dictpath(d, path)
-        self.assertEqual(result, value, 'values not equal "%s" and "%s"' % (str(result), str(value)))
+
+        # [] makes no sense as a list of valid values, so treat it as
+        # an actual single value.
+        if isinstance(value, list) and value != []:
+            for v in value:
+                if result == v:
+                    return
+            self.fail('no match for "%s" in %s' % (str(result), str(value)))
+        else:
+            self.assertEqual(result, value,
+                             'values not equal "%s" and "%s"'
+                                 % (str(result), str(value)))
 
     def assert_no_active_block_jobs(self):
         result = self.vm.qmp('query-block-jobs')
diff --git a/tests/qom-test.c b/tests/qom-test.c
index 73c52af3bb..4f94cc678c 100644
--- a/tests/qom-test.c
+++ b/tests/qom-test.c
@@ -44,7 +44,7 @@ static bool is_blacklisted(const char *arch, const char *mach)
     return false;
 }
 
-static void test_properties(const char *path, bool recurse)
+static void test_properties(QTestState *qts, const char *path, bool recurse)
 {
     char *child_path;
     QDict *response, *tuple, *tmp;
@@ -52,8 +52,8 @@ static void test_properties(const char *path, bool recurse)
     QListEntry *entry;
 
     g_test_message("Obtaining properties of %s", path);
-    response = qmp("{ 'execute': 'qom-list',"
-                   "  'arguments': { 'path': %s } }", path);
+    response = qtest_qmp(qts, "{ 'execute': 'qom-list',"
+                              "  'arguments': { 'path': %s } }", path);
     g_assert(response);
 
     if (!recurse) {
@@ -71,15 +71,15 @@ static void test_properties(const char *path, bool recurse)
         if (is_child || is_link) {
             child_path = g_strdup_printf("%s/%s",
                                          path, qdict_get_str(tuple, "name"));
-            test_properties(child_path, is_child);
+            test_properties(qts, child_path, is_child);
             g_free(child_path);
         } else {
             const char *prop = qdict_get_str(tuple, "name");
             g_test_message("Testing property %s.%s", path, prop);
-            tmp = qmp("{ 'execute': 'qom-get',"
-                      "  'arguments': { 'path': %s,"
-                      "                 'property': %s } }",
-                      path, prop);
+            tmp = qtest_qmp(qts,
+                            "{ 'execute': 'qom-get',"
+                            "  'arguments': { 'path': %s, 'property': %s } }",
+                            path, prop);
             /* qom-get may fail but should not, e.g., segfault. */
             g_assert(tmp);
             qobject_unref(tmp);
@@ -91,20 +91,18 @@ static void test_properties(const char *path, bool recurse)
 static void test_machine(gconstpointer data)
 {
     const char *machine = data;
-    char *args;
     QDict *response;
+    QTestState *qts;
 
-    args = g_strdup_printf("-machine %s", machine);
-    qtest_start(args);
+    qts = qtest_initf("-machine %s", machine);
 
-    test_properties("/machine", true);
+    test_properties(qts, "/machine", true);
 
-    response = qmp("{ 'execute': 'quit' }");
+    response = qtest_qmp(qts, "{ 'execute': 'quit' }");
     g_assert(qdict_haskey(response, "return"));
     qobject_unref(response);
 
-    qtest_end();
-    g_free(args);
+    qtest_quit(qts);
     g_free((void *)machine);
 }
 
diff --git a/tests/tcg/xtensa/test_exclusive.S b/tests/tcg/xtensa/test_exclusive.S
new file mode 100644
index 0000000000..7757a552ea
--- /dev/null
+++ b/tests/tcg/xtensa/test_exclusive.S
@@ -0,0 +1,48 @@
+#include "macros.inc"
+
+test_suite exclusive
+
+#if XCHAL_HAVE_EXCLUSIVE
+
+test exclusive_nowrite
+    movi    a2, 0x29
+    wsr     a2, atomctl
+    clrex
+    movi    a2, 1f
+    movi    a3, 1
+    s32ex   a3, a2
+    getex   a3
+    assert  eqi, a3, 0
+    l32i    a3, a2, 0
+    assert  eqi, a3, 3
+
+.data
+.align 4
+1:
+    .word   3
+.text
+test_end
+
+test exclusive_write
+    movi    a2, 0x29
+    wsr     a2, atomctl
+    movi    a2, 1f
+    l32ex   a3, a2
+    assert  eqi, a3, 3
+    movi    a3, 2
+    s32ex   a3, a2
+    getex   a3
+    assert  eqi, a3, 1
+    l32i    a3, a2, 0
+    assert  eqi, a3, 2
+
+.data
+.align 4
+1:
+    .word   3
+.text
+test_end
+
+#endif
+
+test_suite_end
diff --git a/tests/test-block-iothread.c b/tests/test-block-iothread.c
index 036ed9a3b3..59f692892e 100644
--- a/tests/test-block-iothread.c
+++ b/tests/test-block-iothread.c
@@ -27,6 +27,7 @@
 #include "block/blockjob_int.h"
 #include "sysemu/block-backend.h"
 #include "qapi/error.h"
+#include "qapi/qmp/qdict.h"
 #include "iothread.h"
 
 static int coroutine_fn bdrv_test_co_prwv(BlockDriverState *bs,
@@ -459,6 +460,204 @@ static void test_attach_blockjob(void)
     blk_unref(blk);
 }
 
+/*
+ * Test that changing the AioContext for one node in a tree (here through blk)
+ * changes all other nodes as well:
+ *
+ *  blk
+ *   |
+ *   |  bs_verify [blkverify]
+ *   |   /               \
+ *   |  /                 \
+ *  bs_a [bdrv_test]    bs_b [bdrv_test]
+ *
+ */
+static void test_propagate_basic(void)
+{
+    IOThread *iothread = iothread_new();
+    AioContext *ctx = iothread_get_aio_context(iothread);
+    BlockBackend *blk;
+    BlockDriverState *bs_a, *bs_b, *bs_verify;
+    QDict *options;
+
+    /* Create bs_a and its BlockBackend */
+    blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
+    bs_a = bdrv_new_open_driver(&bdrv_test, "bs_a", BDRV_O_RDWR, &error_abort);
+    blk_insert_bs(blk, bs_a, &error_abort);
+
+    /* Create bs_b */
+    bs_b = bdrv_new_open_driver(&bdrv_test, "bs_b", BDRV_O_RDWR, &error_abort);
+
+    /* Create blkverify filter that references both bs_a and bs_b */
+    options = qdict_new();
+    qdict_put_str(options, "driver", "blkverify");
+    qdict_put_str(options, "test", "bs_a");
+    qdict_put_str(options, "raw", "bs_b");
+
+    bs_verify = bdrv_open(NULL, NULL, options, BDRV_O_RDWR, &error_abort);
+
+    /* Switch the AioContext */
+    blk_set_aio_context(blk, ctx);
+    g_assert(blk_get_aio_context(blk) == ctx);
+    g_assert(bdrv_get_aio_context(bs_a) == ctx);
+    g_assert(bdrv_get_aio_context(bs_verify) == ctx);
+    g_assert(bdrv_get_aio_context(bs_b) == ctx);
+
+    /* Switch the AioContext back */
+    ctx = qemu_get_aio_context();
+    blk_set_aio_context(blk, ctx);
+    g_assert(blk_get_aio_context(blk) == ctx);
+    g_assert(bdrv_get_aio_context(bs_a) == ctx);
+    g_assert(bdrv_get_aio_context(bs_verify) == ctx);
+    g_assert(bdrv_get_aio_context(bs_b) == ctx);
+
+    bdrv_unref(bs_verify);
+    bdrv_unref(bs_b);
+    bdrv_unref(bs_a);
+    blk_unref(blk);
+}
+
+/*
+ * Test that diamonds in the graph don't lead to endless recursion:
+ *
+ *              blk
+ *               |
+ *      bs_verify [blkverify]
+ *       /              \
+ *      /                \
+ *   bs_b [raw]         bs_c[raw]
+ *      \                /
+ *       \              /
+ *       bs_a [bdrv_test]
+ */
+static void test_propagate_diamond(void)
+{
+    IOThread *iothread = iothread_new();
+    AioContext *ctx = iothread_get_aio_context(iothread);
+    BlockBackend *blk;
+    BlockDriverState *bs_a, *bs_b, *bs_c, *bs_verify;
+    QDict *options;
+
+    /* Create bs_a */
+    bs_a = bdrv_new_open_driver(&bdrv_test, "bs_a", BDRV_O_RDWR, &error_abort);
+
+    /* Create bs_b and bc_c */
+    options = qdict_new();
+    qdict_put_str(options, "driver", "raw");
+    qdict_put_str(options, "file", "bs_a");
+    qdict_put_str(options, "node-name", "bs_b");
+    bs_b = bdrv_open(NULL, NULL, options, BDRV_O_RDWR, &error_abort);
+
+    options = qdict_new();
+    qdict_put_str(options, "driver", "raw");
+    qdict_put_str(options, "file", "bs_a");
+    qdict_put_str(options, "node-name", "bs_c");
+    bs_c = bdrv_open(NULL, NULL, options, BDRV_O_RDWR, &error_abort);
+
+    /* Create blkverify filter that references both bs_b and bs_c */
+    options = qdict_new();
+    qdict_put_str(options, "driver", "blkverify");
+    qdict_put_str(options, "test", "bs_b");
+    qdict_put_str(options, "raw", "bs_c");
+
+    bs_verify = bdrv_open(NULL, NULL, options, BDRV_O_RDWR, &error_abort);
+    blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
+    blk_insert_bs(blk, bs_verify, &error_abort);
+
+    /* Switch the AioContext */
+    blk_set_aio_context(blk, ctx);
+    g_assert(blk_get_aio_context(blk) == ctx);
+    g_assert(bdrv_get_aio_context(bs_verify) == ctx);
+    g_assert(bdrv_get_aio_context(bs_a) == ctx);
+    g_assert(bdrv_get_aio_context(bs_b) == ctx);
+    g_assert(bdrv_get_aio_context(bs_c) == ctx);
+
+    /* Switch the AioContext back */
+    ctx = qemu_get_aio_context();
+    blk_set_aio_context(blk, ctx);
+    g_assert(blk_get_aio_context(blk) == ctx);
+    g_assert(bdrv_get_aio_context(bs_verify) == ctx);
+    g_assert(bdrv_get_aio_context(bs_a) == ctx);
+    g_assert(bdrv_get_aio_context(bs_b) == ctx);
+    g_assert(bdrv_get_aio_context(bs_c) == ctx);
+
+    blk_unref(blk);
+    bdrv_unref(bs_verify);
+    bdrv_unref(bs_c);
+    bdrv_unref(bs_b);
+    bdrv_unref(bs_a);
+}
+
+static void test_propagate_mirror(void)
+{
+    IOThread *iothread = iothread_new();
+    AioContext *ctx = iothread_get_aio_context(iothread);
+    AioContext *main_ctx = qemu_get_aio_context();
+    BlockDriverState *src, *target;
+    BlockBackend *blk;
+    Job *job;
+    Error *local_err = NULL;
+
+    /* Create src and target*/
+    src = bdrv_new_open_driver(&bdrv_test, "src", BDRV_O_RDWR, &error_abort);
+    target = bdrv_new_open_driver(&bdrv_test, "target", BDRV_O_RDWR,
+                                  &error_abort);
+
+    /* Start a mirror job */
+    mirror_start("job0", src, target, NULL, JOB_DEFAULT, 0, 0, 0,
+                 MIRROR_SYNC_MODE_NONE, MIRROR_OPEN_BACKING_CHAIN,
+                 BLOCKDEV_ON_ERROR_REPORT, BLOCKDEV_ON_ERROR_REPORT,
+                 false, "filter_node", MIRROR_COPY_MODE_BACKGROUND,
+                 &error_abort);
+    job = job_get("job0");
+
+    /* Change the AioContext of src */
+    bdrv_try_set_aio_context(src, ctx, &error_abort);
+    g_assert(bdrv_get_aio_context(src) == ctx);
+    g_assert(bdrv_get_aio_context(target) == ctx);
+    g_assert(job->aio_context == ctx);
+
+    /* Change the AioContext of target */
+    aio_context_acquire(ctx);
+    bdrv_try_set_aio_context(target, main_ctx, &error_abort);
+    aio_context_release(ctx);
+    g_assert(bdrv_get_aio_context(src) == main_ctx);
+    g_assert(bdrv_get_aio_context(target) == main_ctx);
+
+    /* With a BlockBackend on src, changing target must fail */
+    blk = blk_new(0, BLK_PERM_ALL);
+    blk_insert_bs(blk, src, &error_abort);
+
+    bdrv_try_set_aio_context(target, ctx, &local_err);
+    g_assert(local_err);
+    error_free(local_err);
+
+    g_assert(blk_get_aio_context(blk) == main_ctx);
+    g_assert(bdrv_get_aio_context(src) == main_ctx);
+    g_assert(bdrv_get_aio_context(target) == main_ctx);
+
+    /* ...unless we explicitly allow it */
+    aio_context_acquire(ctx);
+    blk_set_allow_aio_context_change(blk, true);
+    bdrv_try_set_aio_context(target, ctx, &error_abort);
+    aio_context_release(ctx);
+
+    g_assert(blk_get_aio_context(blk) == ctx);
+    g_assert(bdrv_get_aio_context(src) == ctx);
+    g_assert(bdrv_get_aio_context(target) == ctx);
+
+    job_cancel_sync_all();
+
+    aio_context_acquire(ctx);
+    blk_set_aio_context(blk, main_ctx);
+    bdrv_try_set_aio_context(target, main_ctx, &error_abort);
+    aio_context_release(ctx);
+
+    blk_unref(blk);
+    bdrv_unref(src);
+    bdrv_unref(target);
+}
+
 int main(int argc, char **argv)
 {
     int i;
@@ -474,6 +673,9 @@ int main(int argc, char **argv)
     }
 
     g_test_add_func("/attach/blockjob", test_attach_blockjob);
+    g_test_add_func("/propagate/basic", test_propagate_basic);
+    g_test_add_func("/propagate/diamond", test_propagate_diamond);
+    g_test_add_func("/propagate/mirror", test_propagate_mirror);
 
     return g_test_run();
 }
diff --git a/tests/vmgenid-test.c b/tests/vmgenid-test.c
index ae38ee5ac0..85d8e6463e 100644
--- a/tests/vmgenid-test.c
+++ b/tests/vmgenid-test.c
@@ -40,14 +40,14 @@ static uint32_t acpi_find_vgia(QTestState *qts)
     g_assert_cmphex(rsdp_offset, <, RSDP_ADDR_INVALID);
 
 
-    acpi_parse_rsdp_table(qts, rsdp_offset, rsdp_table);
+    acpi_fetch_rsdp_table(qts, rsdp_offset, rsdp_table);
     acpi_fetch_table(qts, &rsdt, &rsdt_len, &rsdp_table[16 /* RsdtAddress */],
-                     "RSDT", true);
+                     4, "RSDT", true);
 
     ACPI_FOREACH_RSDT_ENTRY(rsdt, rsdt_len, ent, 4 /* Entry size */) {
         uint8_t *table_aml;
 
-        acpi_fetch_table(qts, &table_aml, &table_length, ent, NULL, true);
+        acpi_fetch_table(qts, &table_aml, &table_length, ent, 4, NULL, true);
         if (!memcmp(table_aml + 16 /* OEM Table ID */, "VMGENID", 7)) {
             uint32_t vgia_val;
             uint8_t *aml = &table_aml[36 /* AML byte-code start */];
diff --git a/ui/console-gl.c b/ui/console-gl.c
index a56e1cd8eb..c1cb3bd673 100644
--- a/ui/console-gl.c
+++ b/ui/console-gl.c
@@ -92,13 +92,17 @@ void surface_gl_update_texture(QemuGLShader *gls,
 
     assert(gls);
 
-    glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT,
-                  surface_stride(surface) / surface_bytes_per_pixel(surface));
-    glTexSubImage2D(GL_TEXTURE_2D, 0,
-                    x, y, w, h,
-                    surface->glformat, surface->gltype,
-                    data + surface_stride(surface) * y
-                    + surface_bytes_per_pixel(surface) * x);
+    if (surface->texture) {
+        glBindTexture(GL_TEXTURE_2D, surface->texture);
+        glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT,
+                      surface_stride(surface)
+                      / surface_bytes_per_pixel(surface));
+        glTexSubImage2D(GL_TEXTURE_2D, 0,
+                        x, y, w, h,
+                        surface->glformat, surface->gltype,
+                        data + surface_stride(surface) * y
+                        + surface_bytes_per_pixel(surface) * x);
+    }
 }
 
 void surface_gl_render_texture(QemuGLShader *gls,
diff --git a/ui/curses.c b/ui/curses.c
index fb63945188..1f3fcabb00 100644
--- a/ui/curses.c
+++ b/ui/curses.c
@@ -66,20 +66,22 @@ static void curses_update(DisplayChangeListener *dcl,
 {
     console_ch_t *line;
     cchar_t curses_line[width];
+    wchar_t wch[CCHARW_MAX];
+    attr_t attrs;
+    short colors;
+    int ret;
 
     line = screen + y * width;
     for (h += y; y < h; y ++, line += width) {
         for (x = 0; x < width; x++) {
             chtype ch = line[x] & 0xff;
             chtype at = line[x] & ~0xff;
-            if (vga_to_curses[ch].chars[0]) {
-                curses_line[x] = vga_to_curses[ch];
-            } else {
-                curses_line[x] = (cchar_t) {
-                    .chars[0] = ch,
-                };
+            ret = getcchar(&vga_to_curses[ch], wch, &attrs, &colors, NULL);
+            if (ret == ERR || wch[0] == 0) {
+                wch[0] = ch;
+                wch[1] = 0;
             }
-            curses_line[x].attr |= at;
+            setcchar(&curses_line[x], wch, at, 0, NULL);
         }
         mvwadd_wchnstr(screenpad, y, 0, curses_line, width);
     }
@@ -400,65 +402,112 @@ static void curses_atexit(void)
     endwin();
 }
 
+/*
+ * In the following:
+ * - fch is the font glyph number
+ * - uch is the unicode value
+ * - wch is the wchar_t value (may not be unicode, e.g. on BSD/solaris)
+ * - mbch is the native local-dependent multibyte representation
+ */
+
 /* Setup wchar glyph for one UCS-2 char */
-static void convert_ucs(int glyph, uint16_t ch, iconv_t conv)
+static void convert_ucs(unsigned char fch, uint16_t uch, iconv_t conv)
 {
-    wchar_t wch;
-    char *pch, *pwch;
-    size_t sch, swch;
-
-    pch = (char *) &ch;
-    pwch = (char *) &wch;
-    sch = sizeof(ch);
-    swch = sizeof(wch);
-
-    if (iconv(conv, &pch, &sch, &pwch, &swch) == (size_t) -1) {
-        fprintf(stderr, "Could not convert 0x%04x from UCS-2 to WCHAR_T: %s\n",
-                        ch, strerror(errno));
-    } else {
-        vga_to_curses[glyph].chars[0] = wch;
+    char mbch[MB_LEN_MAX];
+    wchar_t wch[2];
+    char *puch, *pmbch;
+    size_t such, smbch;
+    mbstate_t ps;
+
+    puch = (char *) &uch;
+    pmbch = (char *) mbch;
+    such = sizeof(uch);
+    smbch = sizeof(mbch);
+
+    if (iconv(conv, &puch, &such, &pmbch, &smbch) == (size_t) -1) {
+        fprintf(stderr, "Could not convert 0x%04x "
+                        "from UCS-2 to a multibyte character: %s\n",
+                        uch, strerror(errno));
+        return;
+    }
+
+    memset(&ps, 0, sizeof(ps));
+    if (mbrtowc(&wch[0], mbch, sizeof(mbch) - smbch, &ps) == -1) {
+        fprintf(stderr, "Could not convert 0x%04x "
+                        "from a multibyte character to wchar_t: %s\n",
+                        uch, strerror(errno));
+        return;
     }
+
+    wch[1] = 0;
+    setcchar(&vga_to_curses[fch], wch, 0, 0, NULL);
 }
 
 /* Setup wchar glyph for one font character */
-static void convert_font(unsigned char ch, iconv_t conv)
+static void convert_font(unsigned char fch, iconv_t conv)
 {
-    wchar_t wch;
-    char *pch, *pwch;
-    size_t sch, swch;
-
-    pch = (char *) &ch;
-    pwch = (char *) &wch;
-    sch = sizeof(ch);
-    swch = sizeof(wch);
-
-    if (iconv(conv, &pch, &sch, &pwch, &swch) == (size_t) -1) {
-        fprintf(stderr, "Could not convert 0x%02x from %s to WCHAR_T: %s\n",
-                        ch, font_charset, strerror(errno));
-    } else {
-        vga_to_curses[ch].chars[0] = wch;
+    char mbch[MB_LEN_MAX];
+    wchar_t wch[2];
+    char *pfch, *pmbch;
+    size_t sfch, smbch;
+    mbstate_t ps;
+
+    pfch = (char *) &fch;
+    pmbch = (char *) &mbch;
+    sfch = sizeof(fch);
+    smbch = sizeof(mbch);
+
+    if (iconv(conv, &pfch, &sfch, &pmbch, &smbch) == (size_t) -1) {
+        fprintf(stderr, "Could not convert font glyph 0x%02x "
+                        "from %s to a multibyte character: %s\n",
+                        fch, font_charset, strerror(errno));
+        return;
+    }
+
+    memset(&ps, 0, sizeof(ps));
+    if (mbrtowc(&wch[0], mbch, sizeof(mbch) - smbch, &ps) == -1) {
+        fprintf(stderr, "Could not convert font glyph 0x%02x "
+                        "from a multibyte character to wchar_t: %s\n",
+                        fch, strerror(errno));
+        return;
     }
+
+    wch[1] = 0;
+    setcchar(&vga_to_curses[fch], wch, 0, 0, NULL);
 }
 
 /* Convert one wchar to UCS-2 */
 static uint16_t get_ucs(wchar_t wch, iconv_t conv)
 {
-    uint16_t ch;
-    char *pch, *pwch;
-    size_t sch, swch;
-
-    pch = (char *) &ch;
-    pwch = (char *) &wch;
-    sch = sizeof(ch);
-    swch = sizeof(wch);
-
-    if (iconv(conv, &pwch, &swch, &pch, &sch) == (size_t) -1) {
-        fprintf(stderr, "Could not convert 0x%02lx from WCHAR_T to UCS-2: %s\n",
-                (unsigned long)wch, strerror(errno));
+    char mbch[MB_LEN_MAX];
+    uint16_t uch;
+    char *pmbch, *puch;
+    size_t smbch, such;
+    mbstate_t ps;
+    int ret;
+
+    memset(&ps, 0, sizeof(ps));
+    ret = wcrtomb(mbch, wch, &ps);
+    if (ret == -1) {
+        fprintf(stderr, "Could not convert 0x%04x "
+                        "from wchar_t to a multibyte character: %s\n",
+                        wch, strerror(errno));
         return 0xFFFD;
     }
 
-    return ch;
+    pmbch = (char *) mbch;
+    puch = (char *) &uch;
+    smbch = ret;
+    such = sizeof(uch);
+
+    if (iconv(conv, &pmbch, &smbch, &puch, &such) == (size_t) -1) {
+        fprintf(stderr, "Could not convert 0x%04x "
+                        "from a multibyte character to UCS-2 : %s\n",
+                        wch, strerror(errno));
+        return 0xFFFD;
+    }
+
+    return uch;
 }
 
 /*
@@ -466,6 +515,11 @@ static uint16_t get_ucs(wchar_t wch, iconv_t conv)
  */
 static void font_setup(void)
 {
+    iconv_t ucs2_to_nativecharset;
+    iconv_t nativecharset_to_ucs2;
+    iconv_t font_conv;
+    int i;
+
     /*
      * Control characters are normally non-printable, but VGA does have
      * well-known glyphs for them.
@@ -505,30 +559,25 @@ static void font_setup(void)
       0x25bc
     };
 
-    iconv_t ucs_to_wchar_conv;
-    iconv_t wchar_to_ucs_conv;
-    iconv_t font_conv;
-    int i;
-
-    ucs_to_wchar_conv = iconv_open("WCHAR_T", "UCS-2");
-    if (ucs_to_wchar_conv == (iconv_t) -1) {
+    ucs2_to_nativecharset = iconv_open(nl_langinfo(CODESET), "UCS-2");
+    if (ucs2_to_nativecharset == (iconv_t) -1) {
         fprintf(stderr, "Could not convert font glyphs from UCS-2: '%s'\n",
                         strerror(errno));
         exit(1);
     }
 
-    wchar_to_ucs_conv = iconv_open("UCS-2", "WCHAR_T");
-    if (wchar_to_ucs_conv == (iconv_t) -1) {
-        iconv_close(ucs_to_wchar_conv);
+    nativecharset_to_ucs2 = iconv_open("UCS-2", nl_langinfo(CODESET));
+    if (nativecharset_to_ucs2 == (iconv_t) -1) {
+        iconv_close(ucs2_to_nativecharset);
         fprintf(stderr, "Could not convert font glyphs to UCS-2: '%s'\n",
                         strerror(errno));
         exit(1);
     }
 
-    font_conv = iconv_open("WCHAR_T", font_charset);
+    font_conv = iconv_open(nl_langinfo(CODESET), font_charset);
     if (font_conv == (iconv_t) -1) {
-        iconv_close(ucs_to_wchar_conv);
-        iconv_close(wchar_to_ucs_conv);
+        iconv_close(ucs2_to_nativecharset);
+        iconv_close(nativecharset_to_ucs2);
         fprintf(stderr, "Could not convert font glyphs from %s: '%s'\n",
                         font_charset, strerror(errno));
         exit(1);
@@ -536,7 +585,7 @@ static void font_setup(void)
 
     /* Control characters */
     for (i = 0; i <= 0x1F; i++) {
-        convert_ucs(i, control_characters[i], ucs_to_wchar_conv);
+        convert_ucs(i, control_characters[i], ucs2_to_nativecharset);
     }
 
     for (i = 0x20; i <= 0xFF; i++) {
@@ -544,12 +593,21 @@ static void font_setup(void)
     }
 
     /* DEL */
-    convert_ucs(0x7F, 0x2302, ucs_to_wchar_conv);
+    convert_ucs(0x7F, 0x2302, ucs2_to_nativecharset);
 
     if (strcmp(nl_langinfo(CODESET), "UTF-8")) {
         /* Non-Unicode capable, use termcap equivalents for those available */
         for (i = 0; i <= 0xFF; i++) {
-            switch (get_ucs(vga_to_curses[i].chars[0], wchar_to_ucs_conv)) {
+            wchar_t wch[CCHARW_MAX];
+            attr_t attr;
+            short color;
+            int ret;
+
+            ret = getcchar(&vga_to_curses[i], wch, &attr, &color, NULL);
+            if (ret == ERR)
+                continue;
+
+            switch (get_ucs(wch[0], nativecharset_to_ucs2)) {
             case 0x00a3:
                 vga_to_curses[i] = *WACS_STERLING;
                 break;
@@ -649,8 +707,8 @@ static void font_setup(void)
             }
         }
     }
-    iconv_close(ucs_to_wchar_conv);
-    iconv_close(wchar_to_ucs_conv);
+    iconv_close(ucs2_to_nativecharset);
+    iconv_close(nativecharset_to_ucs2);
     iconv_close(font_conv);
 }
 
diff --git a/ui/kbd-state.c b/ui/kbd-state.c
index f3ab2d7a66..1668d17dda 100644
--- a/ui/kbd-state.c
+++ b/ui/kbd-state.c
@@ -59,7 +59,11 @@ void qkbd_state_key_event(QKbdState *kbd, QKeyCode qcode, bool down)
     }
 
     /* update key and modifier state */
-    change_bit(qcode, kbd->keys);
+    if (down) {
+        set_bit(qcode, kbd->keys);
+    } else {
+        clear_bit(qcode, kbd->keys);
+    }
     switch (qcode) {
     case Q_KEY_CODE_SHIFT:
     case Q_KEY_CODE_SHIFT_R:
diff --git a/vl.c b/vl.c
index b6709514c1..201144b162 100644
--- a/vl.c
+++ b/vl.c
@@ -2018,6 +2018,7 @@ typedef struct VGAInterfaceInfo {
 static const VGAInterfaceInfo vga_interfaces[VGA_TYPE_MAX] = {
     [VGA_NONE] = {
         .opt_name = "none",
+        .name = "no graphic card",
     },
     [VGA_STD] = {
         .opt_name = "std",
@@ -2056,6 +2057,7 @@ static const VGAInterfaceInfo vga_interfaces[VGA_TYPE_MAX] = {
     },
     [VGA_XENFB] = {
         .opt_name = "xenfb",
+        .name = "Xen paravirtualized framebuffer",
     },
 };
 
@@ -3535,6 +3537,10 @@ int main(int argc, char **argv, char **envp)
                 QemuOpts *fsdev;
                 QemuOpts *device;
 
+                warn_report("'-virtfs_synth' is deprecated, please use "
+                             "'-fsdev synth' and '-device virtio-9p-...' "
+                            "instead");
+
                 fsdev = qemu_opts_create(qemu_find_opts("fsdev"), "v_synth",
                                          1, NULL);
                 if (!fsdev) {
@@ -3894,17 +3900,19 @@ int main(int argc, char **argv, char **envp)
                 qtest_log = optarg;
                 break;
             case QEMU_OPTION_sandbox:
-#ifdef CONFIG_SECCOMP
-                opts = qemu_opts_parse_noisily(qemu_find_opts("sandbox"),
-                                               optarg, true);
+                olist = qemu_find_opts("sandbox");
+                if (!olist) {
+#ifndef CONFIG_SECCOMP
+                    error_report("-sandbox support is not enabled "
+                                 "in this QEMU binary");
+#endif
+                    exit(1);
+                }
+
+                opts = qemu_opts_parse_noisily(olist, optarg, true);
                 if (!opts) {
                     exit(1);
                 }
-#else
-                error_report("-sandbox support is not enabled "
-                             "in this QEMU binary");
-                exit(1);
-#endif
                 break;
             case QEMU_OPTION_add_fd:
 #ifndef _WIN32
@@ -3927,6 +3935,8 @@ int main(int argc, char **argv, char **envp)
                 }
                 break;
             case QEMU_OPTION_realtime:
+                warn_report("'-realtime mlock=...' is deprecated, please use "
+                             "'-overcommit mem-lock=...' instead");
                 opts = qemu_opts_parse_noisily(qemu_find_opts("realtime"),
                                                optarg, false);
                 if (!opts) {