Bug#798969: jessie-pu: package qemu/1:2.1+dfsg-12+deb8u4
Package: release.debian.org
Severity: normal
Tags: jessie
User: release.debian.org@packages.debian.org
Usertags: pu
I'd like to update qemu in jessie to the next upstream stable point release.
Initially jessie has been released with qemu based on upstream version 2.1.2,
but later on upstream released next (and last) stable point release, 2.1.3.
This update contains a number of various, mostly small, fixes in numerous places
in qemu source code, including a few security hardening and additional checks,
possible data corruption fixes, reliability fixes, leak fixes and other things.
There's at least one (set of) fix which has been asked numerous times to be
included in jessie/stable qemu, that's migration fixes, #786789. This particular
bug requires several patches to be applied.
So the proposed change includes a new patch, d/patches/v2.1.3.diff, which is
a difference between upstream 2.1.0 and 2.1.3 releases, which superceeedes
(includes) the previously used d/patches/v2.1.2.diff, plus it includes a few
fixes which were previously applied separately, namely, several patches for
CVE-2014-3689 (#765496) vmware-vga fix and tcg-mips-fix-store-softmmu-slow-path.patch.
Due to this shuffling around, the debdiff becomes quite large (esp. due to
rename of v2.1.2.diff->2.1.3.diff), while actual changes are much smaller while
still significant, due to amount of other changes which were included in
upstream 2.1.3 release.
Complete list of changes in 2.1.3 can be seen in the upstream git tree,
http://git.qemu-project.org/?p=qemu.git;a=shortlog;h=refs/tags/v2.1.3 ,
it contains 94 patches in total.
>From there, 6 patches for CVE-2014-3689 (#765496) issue and one tcg-mips
fix has been in debian already, so these are now removed.
Besides the inclusion of the next upstream stable point release, there
are currently 2 more fixes taken from later releases of qemu, which bite
our users in jessie. These are:
block-fix-max-nb_sectors-in-bdrv_make_zero.patch (#797221), this
fixes qemu-img create, convert and similar for large devices/files.
qemu-char-handle-EINTR-for-TCP-character-devices.patch and
qemu-char-fix-missed-data-on-unix-socket.patch (#793817), this fixes
logic when reading control data from sockets, in particular this
makes cloudstack happy.
Alternative to applying whole v2.1.3.diff was to backport only "important"
fixes to version 2.1.2. However, due to the amount of various fixes went
into 2.1.3, because the "imoprtant" fixes aren't simple ones (see #786789),
and because 2.1.3 has been extensively tested in various environments (since
it's upstream stable version), I think including whole 2.1.3 in debian is
better than trying to cherry-pick something.
There is, however, one possibility to reduce the debdiff which I didn't
follow. I could put additional diff, from 2.1.2 to 2.1.3, together with
already existing 2.1.2, it'd be much smaller than deletion of 2.1.2 and
introduction of 2.1.3. However, while the debdiff is reduced this way,
it is more confusing to the users, and more difficult to verify against
upstream. If the release team thinks this way is better I can redo the
packaging ofcourse.
The attached debdiff is made on the debian-jessie-proposed branch of qemu
alioth git tree,
http://anonscm.debian.org/cgit/pkg-qemu/qemu.git/log/?h=debian-jessie-proposed
and is made on top of not-yet-available in public archives jessie-security
version, 2.1+dfsg-12+deb8u3, which should be available shortly. Due to
the amount of security bugs discovered in qemu recently, I'm not sure this
version will be right at the time of the next jessie point release, so
the changes might need to be rebased on top of further security changes.
Thank you for your time!
/mjt
diff -Nru qemu-2.1+dfsg/debian/changelog qemu-2.1+dfsg/debian/changelog
--- qemu-2.1+dfsg/debian/changelog 2015-09-12 11:43:21.000000000 +0300
+++ qemu-2.1+dfsg/debian/changelog 2015-09-14 17:40:58.000000000 +0300
@@ -1,3 +1,17 @@
+qemu (1:2.1+dfsg-12+deb8u4) UNRELEASED; urgency=medium
+
+ * apply block-fix-max-nb_sectors-in-bdrv_make_zero.patch from upstream
+ (Closes: #797221)
+ * apply qemu-char-handle-EINTR-for-TCP-character-devices.patch and
+ qemu-char-fix-missed-data-on-unix-socket.patch from upstream
+ (Closes: #793817)
+ * update upstream stable patch from v2.1.3 tag (Closes: #786789)
+ v2.1.3 incorporates CVE-2014-3689 (#765496) vmware-vga fix and
+ tcg-mips-fix-store-softmmu-slow-path.patch, and brings up many
+ other fixes in various places
+
+ -- Michael Tokarev <mjt@tls.msk.ru> Mon, 14 Sep 2015 13:45:59 +0300
+
qemu (1:2.1+dfsg-12+deb8u3) jessie-security; urgency=high
* Acknowlege the previous update. Thank you Salvatore for the hard
diff -Nru qemu-2.1+dfsg/debian/patches/block-fix-max-nb_sectors-in-bdrv_make_zero.patch qemu-2.1+dfsg/debian/patches/block-fix-max-nb_sectors-in-bdrv_make_zero.patch
--- qemu-2.1+dfsg/debian/patches/block-fix-max-nb_sectors-in-bdrv_make_zero.patch 1970-01-01 03:00:00.000000000 +0300
+++ qemu-2.1+dfsg/debian/patches/block-fix-max-nb_sectors-in-bdrv_make_zero.patch 2015-09-14 17:40:58.000000000 +0300
@@ -0,0 +1,35 @@
+From f3a9cfddaec127078ac1898de6b063db8ac3bb48 Mon Sep 17 00:00:00 2001
+From: Fam Zheng <famz@redhat.com>
+Date: Mon, 10 Nov 2014 15:07:44 +0800
+Subject: block: Fix max nb_sectors in bdrv_make_zero
+Bug-Debian: http://bugs.debian.org/797221
+
+In bdrv_rw_co we report -EINVAL for nb_sectors > INT_MAX /
+BDRV_SECTOR_SIZE, so a caller shouldn't exceed it.
+
+Signed-off-by: Fam Zheng <famz@redhat.com>
+Reviewed-by: Markus Armbruster <armbru@redhat.com>
+Message-id: 1415603264-21497-1-git-send-email-famz@redhat.com
+Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
+---
+ block.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/block.c b/block.c
+index c612826..a612594 100644
+--- a/block.c
++++ b/block.c
+@@ -2790,8 +2790,8 @@ int bdrv_make_zero(BlockDriverState *bs, BdrvRequestFlags flags)
+ if (nb_sectors <= 0) {
+ return 0;
+ }
+- if (nb_sectors > INT_MAX) {
+- nb_sectors = INT_MAX;
++ if (nb_sectors > INT_MAX / BDRV_SECTOR_SIZE) {
++ nb_sectors = INT_MAX / BDRV_SECTOR_SIZE;
+ }
+ ret = bdrv_get_block_status(bs, sector_num, nb_sectors, &n);
+ if (ret < 0) {
+--
+2.1.4
+
diff -Nru qemu-2.1+dfsg/debian/patches/CVE-2014-3689-vmware-vga/1-CVE-2014-3689-turn-off-hw-accel.patch qemu-2.1+dfsg/debian/patches/CVE-2014-3689-vmware-vga/1-CVE-2014-3689-turn-off-hw-accel.patch
--- qemu-2.1+dfsg/debian/patches/CVE-2014-3689-vmware-vga/1-CVE-2014-3689-turn-off-hw-accel.patch 2015-09-12 11:43:21.000000000 +0300
+++ qemu-2.1+dfsg/debian/patches/CVE-2014-3689-vmware-vga/1-CVE-2014-3689-turn-off-hw-accel.patch 1970-01-01 03:00:00.000000000 +0300
@@ -1,38 +0,0 @@
-From 83afa38eb20ca27e30683edc7729880e091387fc Mon Sep 17 00:00:00 2001
-From: Gerd Hoffmann <kraxel@redhat.com>
-Date: Mon, 6 Oct 2014 11:42:34 +0200
-Subject: vmware-vga: CVE-2014-3689: turn off hw accel
-
-Quick & easy stopgap for CVE-2014-3689: We just compile out the
-hardware acceleration functions which lack sanity checks. Thankfully
-we have capability bits for them (SVGA_CAP_RECT_COPY and
-SVGA_CAP_RECT_FILL), so guests should deal just fine, in theory.
-
-Subsequent patches will add the missing checks and re-enable the
-hardware acceleration emulation.
-
-Cc: qemu-stable@nongnu.org
-Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
-Reviewed-by: Don Koch <dkoch@verizon.com>
----
- hw/display/vmware_vga.c | 2 ++
- 1 file changed, 2 insertions(+)
-
-diff --git a/hw/display/vmware_vga.c b/hw/display/vmware_vga.c
-index 0c36c72..ec63290 100644
---- a/hw/display/vmware_vga.c
-+++ b/hw/display/vmware_vga.c
-@@ -29,8 +29,10 @@
- #include "hw/pci/pci.h"
-
- #undef VERBOSE
-+#if 0
- #define HW_RECT_ACCEL
- #define HW_FILL_ACCEL
-+#endif
- #define HW_MOUSE_ACCEL
-
- #include "vga_int.h"
---
-1.7.10.4
-
diff -Nru qemu-2.1+dfsg/debian/patches/CVE-2014-3689-vmware-vga/2-add-vmsvga_verify_rect.patch qemu-2.1+dfsg/debian/patches/CVE-2014-3689-vmware-vga/2-add-vmsvga_verify_rect.patch
--- qemu-2.1+dfsg/debian/patches/CVE-2014-3689-vmware-vga/2-add-vmsvga_verify_rect.patch 2015-09-12 11:43:21.000000000 +0300
+++ qemu-2.1+dfsg/debian/patches/CVE-2014-3689-vmware-vga/2-add-vmsvga_verify_rect.patch 1970-01-01 03:00:00.000000000 +0300
@@ -1,83 +0,0 @@
-From 07258900fd45b646f5b69048d64c4490b3243e1b Mon Sep 17 00:00:00 2001
-From: Gerd Hoffmann <kraxel@redhat.com>
-Date: Mon, 6 Oct 2014 11:51:54 +0200
-Subject: vmware-vga: add vmsvga_verify_rect
-
-Add verification function for rectangles, returning
-true if verification passes and false otherwise.
-
-Cc: qemu-stable@nongnu.org
-Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
-Reviewed-by: Don Koch <dkoch@verizon.com>
----
- hw/display/vmware_vga.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++-
- 1 file changed, 52 insertions(+), 1 deletion(-)
-
-diff --git a/hw/display/vmware_vga.c b/hw/display/vmware_vga.c
-index ec63290..ba73a1c 100644
---- a/hw/display/vmware_vga.c
-+++ b/hw/display/vmware_vga.c
-@@ -294,8 +294,59 @@ enum {
- SVGA_CURSOR_ON_RESTORE_TO_FB = 3,
- };
-
-+static inline bool vmsvga_verify_rect(DisplaySurface *surface,
-+ const char *name,
-+ int x, int y, int w, int h)
-+{
-+ if (x < 0) {
-+ fprintf(stderr, "%s: x was < 0 (%d)\n", name, x);
-+ return false;
-+ }
-+ if (x > SVGA_MAX_WIDTH) {
-+ fprintf(stderr, "%s: x was > %d (%d)\n", name, SVGA_MAX_WIDTH, x);
-+ return false;
-+ }
-+ if (w < 0) {
-+ fprintf(stderr, "%s: w was < 0 (%d)\n", name, w);
-+ return false;
-+ }
-+ if (w > SVGA_MAX_WIDTH) {
-+ fprintf(stderr, "%s: w was > %d (%d)\n", name, SVGA_MAX_WIDTH, w);
-+ return false;
-+ }
-+ if (x + w > surface_width(surface)) {
-+ fprintf(stderr, "%s: width was > %d (x: %d, w: %d)\n",
-+ name, surface_width(surface), x, w);
-+ return false;
-+ }
-+
-+ if (y < 0) {
-+ fprintf(stderr, "%s: y was < 0 (%d)\n", name, y);
-+ return false;
-+ }
-+ if (y > SVGA_MAX_HEIGHT) {
-+ fprintf(stderr, "%s: y was > %d (%d)\n", name, SVGA_MAX_HEIGHT, y);
-+ return false;
-+ }
-+ if (h < 0) {
-+ fprintf(stderr, "%s: h was < 0 (%d)\n", name, h);
-+ return false;
-+ }
-+ if (h > SVGA_MAX_HEIGHT) {
-+ fprintf(stderr, "%s: h was > %d (%d)\n", name, SVGA_MAX_HEIGHT, h);
-+ return false;
-+ }
-+ if (y + h > surface_height(surface)) {
-+ fprintf(stderr, "%s: update height > %d (y: %d, h: %d)\n",
-+ name, surface_height(surface), y, h);
-+ return false;
-+ }
-+
-+ return true;
-+}
-+
- static inline void vmsvga_update_rect(struct vmsvga_state_s *s,
-- int x, int y, int w, int h)
-+ int x, int y, int w, int h)
- {
- DisplaySurface *surface = qemu_console_surface(s->vga.con);
- int line;
---
-1.7.10.4
-
diff -Nru qemu-2.1+dfsg/debian/patches/CVE-2014-3689-vmware-vga/3-use-vmsvga_verify_rect-in-vmsvga_update_rect.patch qemu-2.1+dfsg/debian/patches/CVE-2014-3689-vmware-vga/3-use-vmsvga_verify_rect-in-vmsvga_update_rect.patch
--- qemu-2.1+dfsg/debian/patches/CVE-2014-3689-vmware-vga/3-use-vmsvga_verify_rect-in-vmsvga_update_rect.patch 2015-09-12 11:43:21.000000000 +0300
+++ qemu-2.1+dfsg/debian/patches/CVE-2014-3689-vmware-vga/3-use-vmsvga_verify_rect-in-vmsvga_update_rect.patch 1970-01-01 03:00:00.000000000 +0300
@@ -1,65 +0,0 @@
-From 1735fe1edba9cc86bc0f26937ed5a62d3cb47c9c Mon Sep 17 00:00:00 2001
-From: Gerd Hoffmann <kraxel@redhat.com>
-Date: Mon, 6 Oct 2014 11:58:22 +0200
-Subject: vmware-vga: use vmsvga_verify_rect in vmsvga_update_rect
-
-Switch vmsvga_update_rect over to use vmsvga_verify_rect. Slight change
-in behavior: We don't try to automatically fixup rectangles any more.
-In case we find invalid update requests we'll do a full-screen update
-instead.
-
-Cc: qemu-stable@nongnu.org
-Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
-Reviewed-by: Don Koch <dkoch@verizon.com>
----
- hw/display/vmware_vga.c | 32 ++++----------------------------
- 1 file changed, 4 insertions(+), 28 deletions(-)
-
-diff --git a/hw/display/vmware_vga.c b/hw/display/vmware_vga.c
-index ba73a1c..9d79de6 100644
---- a/hw/display/vmware_vga.c
-+++ b/hw/display/vmware_vga.c
-@@ -356,36 +356,12 @@ static inline void vmsvga_update_rect(struct vmsvga_state_s *s,
- uint8_t *src;
- uint8_t *dst;
-
-- if (x < 0) {
-- fprintf(stderr, "%s: update x was < 0 (%d)\n", __func__, x);
-- w += x;
-+ if (!vmsvga_verify_rect(surface, __func__, x, y, w, h)) {
-+ /* go for a fullscreen update as fallback */
- x = 0;
-- }
-- if (w < 0) {
-- fprintf(stderr, "%s: update w was < 0 (%d)\n", __func__, w);
-- w = 0;
-- }
-- if (x + w > surface_width(surface)) {
-- fprintf(stderr, "%s: update width too large x: %d, w: %d\n",
-- __func__, x, w);
-- x = MIN(x, surface_width(surface));
-- w = surface_width(surface) - x;
-- }
--
-- if (y < 0) {
-- fprintf(stderr, "%s: update y was < 0 (%d)\n", __func__, y);
-- h += y;
- y = 0;
-- }
-- if (h < 0) {
-- fprintf(stderr, "%s: update h was < 0 (%d)\n", __func__, h);
-- h = 0;
-- }
-- if (y + h > surface_height(surface)) {
-- fprintf(stderr, "%s: update height too large y: %d, h: %d\n",
-- __func__, y, h);
-- y = MIN(y, surface_height(surface));
-- h = surface_height(surface) - y;
-+ w = surface_width(surface);
-+ h = surface_height(surface);
- }
-
- bypl = surface_stride(surface);
---
-1.7.10.4
-
diff -Nru qemu-2.1+dfsg/debian/patches/CVE-2014-3689-vmware-vga/4-use-vmsvga_verify_rect-in-vmsvga_copy_rect.patch qemu-2.1+dfsg/debian/patches/CVE-2014-3689-vmware-vga/4-use-vmsvga_verify_rect-in-vmsvga_copy_rect.patch
--- qemu-2.1+dfsg/debian/patches/CVE-2014-3689-vmware-vga/4-use-vmsvga_verify_rect-in-vmsvga_copy_rect.patch 2015-09-12 11:43:21.000000000 +0300
+++ qemu-2.1+dfsg/debian/patches/CVE-2014-3689-vmware-vga/4-use-vmsvga_verify_rect-in-vmsvga_copy_rect.patch 1970-01-01 03:00:00.000000000 +0300
@@ -1,79 +0,0 @@
-From 61b41b4c20eba08d2185297767e69153d7f3e09d Mon Sep 17 00:00:00 2001
-From: Gerd Hoffmann <kraxel@redhat.com>
-Date: Mon, 6 Oct 2014 11:58:51 +0200
-Subject: vmware-vga: use vmsvga_verify_rect in vmsvga_copy_rect
-
-Add verification to vmsvga_copy_rect, re-enable HW_RECT_ACCEL.
-
-Cc: qemu-stable@nongnu.org
-Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
-Reviewed-by: Don Koch <dkoch@verizon.com>
----
- hw/display/vmware_vga.c | 20 ++++++++++++++------
- 1 file changed, 14 insertions(+), 6 deletions(-)
-
-diff --git a/hw/display/vmware_vga.c b/hw/display/vmware_vga.c
-index 9d79de6..73a1b52 100644
---- a/hw/display/vmware_vga.c
-+++ b/hw/display/vmware_vga.c
-@@ -29,8 +29,8 @@
- #include "hw/pci/pci.h"
-
- #undef VERBOSE
--#if 0
- #define HW_RECT_ACCEL
-+#if 0
- #define HW_FILL_ACCEL
- #endif
- #define HW_MOUSE_ACCEL
-@@ -406,7 +406,7 @@ static inline void vmsvga_update_rect_flush(struct vmsvga_state_s *s)
- }
-
- #ifdef HW_RECT_ACCEL
--static inline void vmsvga_copy_rect(struct vmsvga_state_s *s,
-+static inline int vmsvga_copy_rect(struct vmsvga_state_s *s,
- int x0, int y0, int x1, int y1, int w, int h)
- {
- DisplaySurface *surface = qemu_console_surface(s->vga.con);
-@@ -417,6 +417,13 @@ static inline void vmsvga_copy_rect(struct vmsvga_state_s *s,
- int line = h;
- uint8_t *ptr[2];
-
-+ if (!vmsvga_verify_rect(surface, "vmsvga_copy_rect/src", x0, y0, w, h)) {
-+ return -1;
-+ }
-+ if (!vmsvga_verify_rect(surface, "vmsvga_copy_rect/dst", x1, y1, w, h)) {
-+ return -1;
-+ }
-+
- if (y1 > y0) {
- ptr[0] = vram + bypp * x0 + bypl * (y0 + h - 1);
- ptr[1] = vram + bypp * x1 + bypl * (y1 + h - 1);
-@@ -432,6 +439,7 @@ static inline void vmsvga_copy_rect(struct vmsvga_state_s *s,
- }
-
- vmsvga_update_rect_delayed(s, x1, y1, w, h);
-+ return 0;
- }
- #endif
-
-@@ -625,12 +633,12 @@ static void vmsvga_fifo_run(struct vmsvga_state_s *s)
- width = vmsvga_fifo_read(s);
- height = vmsvga_fifo_read(s);
- #ifdef HW_RECT_ACCEL
-- vmsvga_copy_rect(s, x, y, dx, dy, width, height);
-- break;
--#else
-+ if (vmsvga_copy_rect(s, x, y, dx, dy, width, height) == 0) {
-+ break;
-+ }
-+#endif
- args = 0;
- goto badcmd;
--#endif
-
- case SVGA_CMD_DEFINE_CURSOR:
- len -= 8;
---
-1.7.10.4
-
diff -Nru qemu-2.1+dfsg/debian/patches/CVE-2014-3689-vmware-vga/5-use-vmsvga_verify_rect-in-vmsvga_fill_rect.patch qemu-2.1+dfsg/debian/patches/CVE-2014-3689-vmware-vga/5-use-vmsvga_verify_rect-in-vmsvga_fill_rect.patch
--- qemu-2.1+dfsg/debian/patches/CVE-2014-3689-vmware-vga/5-use-vmsvga_verify_rect-in-vmsvga_fill_rect.patch 2015-09-12 11:43:21.000000000 +0300
+++ qemu-2.1+dfsg/debian/patches/CVE-2014-3689-vmware-vga/5-use-vmsvga_verify_rect-in-vmsvga_fill_rect.patch 1970-01-01 03:00:00.000000000 +0300
@@ -1,76 +0,0 @@
-From bd9ccd8517e83b7c33a9167815dbfffb30d70b13 Mon Sep 17 00:00:00 2001
-From: Gerd Hoffmann <kraxel@redhat.com>
-Date: Mon, 6 Oct 2014 11:59:51 +0200
-Subject: vmware-vga: use vmsvga_verify_rect in vmsvga_fill_rect
-
-Add verification to vmsvga_fill_rect, re-enable HW_FILL_ACCEL.
-
-Cc: qemu-stable@nongnu.org
-Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
-Reviewed-by: Don Koch <dkoch@verizon.com>
----
- hw/display/vmware_vga.c | 17 ++++++++++-------
- 1 file changed, 10 insertions(+), 7 deletions(-)
-
-diff --git a/hw/display/vmware_vga.c b/hw/display/vmware_vga.c
-index 73a1b52..1751f19 100644
---- a/hw/display/vmware_vga.c
-+++ b/hw/display/vmware_vga.c
-@@ -30,9 +30,7 @@
-
- #undef VERBOSE
- #define HW_RECT_ACCEL
--#if 0
- #define HW_FILL_ACCEL
--#endif
- #define HW_MOUSE_ACCEL
-
- #include "vga_int.h"
-@@ -444,7 +442,7 @@ static inline int vmsvga_copy_rect(struct vmsvga_state_s *s,
- #endif
-
- #ifdef HW_FILL_ACCEL
--static inline void vmsvga_fill_rect(struct vmsvga_state_s *s,
-+static inline int vmsvga_fill_rect(struct vmsvga_state_s *s,
- uint32_t c, int x, int y, int w, int h)
- {
- DisplaySurface *surface = qemu_console_surface(s->vga.con);
-@@ -457,6 +455,10 @@ static inline void vmsvga_fill_rect(struct vmsvga_state_s *s,
- uint8_t *src;
- uint8_t col[4];
-
-+ if (!vmsvga_verify_rect(surface, __func__, x, y, w, h)) {
-+ return -1;
-+ }
-+
- col[0] = c;
- col[1] = c >> 8;
- col[2] = c >> 16;
-@@ -481,6 +483,7 @@ static inline void vmsvga_fill_rect(struct vmsvga_state_s *s,
- }
-
- vmsvga_update_rect_delayed(s, x, y, w, h);
-+ return 0;
- }
- #endif
-
-@@ -613,12 +616,12 @@ static void vmsvga_fifo_run(struct vmsvga_state_s *s)
- width = vmsvga_fifo_read(s);
- height = vmsvga_fifo_read(s);
- #ifdef HW_FILL_ACCEL
-- vmsvga_fill_rect(s, colour, x, y, width, height);
-- break;
--#else
-+ if (vmsvga_fill_rect(s, colour, x, y, width, height) == 0) {
-+ break;
-+ }
-+#endif
- args = 0;
- goto badcmd;
--#endif
-
- case SVGA_CMD_RECT_COPY:
- len -= 7;
---
-1.7.10.4
-
diff -Nru qemu-2.1+dfsg/debian/patches/qemu-char-fix-missed-data-on-unix-socket.patch qemu-2.1+dfsg/debian/patches/qemu-char-fix-missed-data-on-unix-socket.patch
--- qemu-2.1+dfsg/debian/patches/qemu-char-fix-missed-data-on-unix-socket.patch 1970-01-01 03:00:00.000000000 +0300
+++ qemu-2.1+dfsg/debian/patches/qemu-char-fix-missed-data-on-unix-socket.patch 2015-09-14 17:40:58.000000000 +0300
@@ -0,0 +1,67 @@
+From 4bf1cb03fbc43b0055af60d4ff093d6894aa4338 Mon Sep 17 00:00:00 2001
+From: Nils Carlson <pyssling@ludd.ltu.se>
+Date: Sun, 19 Jul 2015 20:39:56 +0000
+Subject: [PATCH 2/2] qemu-char: Fix missed data on unix socket
+Bug-Debian: http://bugs.debian.org/793817
+
+Commit 812c1057 introduced HUP detection on unix and tcp sockets prior
+to a read in tcp_chr_read. This unfortunately broke CloudStack 4.2
+which relied on the old behaviour where data on a socket was readable
+even if a HUP was present.
+
+A working solution is to properly check the return values from recv,
+handling a closed socket once there is no more data to read.
+
+Also enable polling for G_IO_NVAL to ensure the callback is called
+for all possible events as these should now be possible to handle
+with the improved error detection.
+
+Signed-off-by: Nils Carlson <pyssling@ludd.ltu.se>
+Message-Id: <1437338396-22336-1-git-send-email-pyssling@ludd.ltu.se>
+[Do not handle EINTR; use socket_error(). - Paolo]
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+---
+ qemu-char.c | 13 +++++--------
+ 1 file changed, 5 insertions(+), 8 deletions(-)
+
+diff --git a/qemu-char.c b/qemu-char.c
+index 3200200..d956f8d 100644
+--- a/qemu-char.c
++++ b/qemu-char.c
+@@ -807,7 +807,8 @@ static gboolean io_watch_poll_prepare(GSource *source, gint *timeout_)
+ }
+
+ if (now_active) {
+- iwp->src = g_io_create_watch(iwp->channel, G_IO_IN | G_IO_ERR | G_IO_HUP);
++ iwp->src = g_io_create_watch(iwp->channel,
++ G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL);
+ g_source_set_callback(iwp->src, iwp->fd_read, iwp->opaque, NULL);
+ g_source_attach(iwp->src, NULL);
+ } else {
+@@ -2856,12 +2857,6 @@ static gboolean tcp_chr_read(GIOChannel *chan, GIOCondition cond, void *opaque)
+ uint8_t buf[READ_BUF_LEN];
+ int len, size;
+
+- if (cond & G_IO_HUP) {
+- /* connection closed */
+- tcp_chr_disconnect(chr);
+- return TRUE;
+- }
+-
+ if (!s->connected || s->max_size <= 0) {
+ return TRUE;
+ }
+@@ -2869,7 +2864,9 @@ static gboolean tcp_chr_read(GIOChannel *chan, GIOCondition cond, void *opaque)
+ if (len > s->max_size)
+ len = s->max_size;
+ size = tcp_chr_recv(chr, (void *)buf, len);
+- if (size == 0) {
++ if (size == 0 ||
++ (size < 0 &&
++ socket_error() != EAGAIN && socket_error() != EWOULDBLOCK)) {
+ /* connection closed */
+ tcp_chr_disconnect(chr);
+ } else if (size > 0) {
+--
+2.1.4
+
diff -Nru qemu-2.1+dfsg/debian/patches/qemu-char-handle-EINTR-for-TCP-character-devices.patch qemu-2.1+dfsg/debian/patches/qemu-char-handle-EINTR-for-TCP-character-devices.patch
--- qemu-2.1+dfsg/debian/patches/qemu-char-handle-EINTR-for-TCP-character-devices.patch 1970-01-01 03:00:00.000000000 +0300
+++ qemu-2.1+dfsg/debian/patches/qemu-char-handle-EINTR-for-TCP-character-devices.patch 2015-09-14 17:40:58.000000000 +0300
@@ -0,0 +1,45 @@
+From 9172f428afc1461b1d9b33ebca3a679b9adf7c3a Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini@redhat.com>
+Date: Tue, 21 Jul 2015 09:25:54 +0200
+Subject: [PATCH 1/2] qemu-char: handle EINTR for TCP character devices
+Bug-Debian: http://bugs.debian.org/793817
+
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+---
+ qemu-char.c | 13 +++++++++++--
+ 1 file changed, 11 insertions(+), 2 deletions(-)
+
+diff --git a/qemu-char.c b/qemu-char.c
+index 617e034..3200200 100644
+--- a/qemu-char.c
++++ b/qemu-char.c
+@@ -2797,7 +2797,10 @@ static ssize_t tcp_chr_recv(CharDriverState *chr, char *buf, size_t len)
+ #ifdef MSG_CMSG_CLOEXEC
+ flags |= MSG_CMSG_CLOEXEC;
+ #endif
+- ret = recvmsg(s->fd, &msg, flags);
++ do {
++ ret = recvmsg(s->fd, &msg, flags);
++ } while (ret == -1 && errno == EINTR);
++
+ if (ret > 0 && s->is_unix) {
+ unix_process_msgfd(chr, &msg);
+ }
+@@ -2808,7 +2811,13 @@ static ssize_t tcp_chr_recv(CharDriverState *chr, char *buf, size_t len)
+ static ssize_t tcp_chr_recv(CharDriverState *chr, char *buf, size_t len)
+ {
+ TCPCharDriver *s = chr->opaque;
+- return qemu_recv(s->fd, buf, len, 0);
++ ssize_t ret;
++
++ do {
++ ret = qemu_recv(s->fd, buf, len, 0);
++ } while (ret == -1 && socket_error() == EINTR);
++
++ return ret;
+ }
+ #endif
+
+--
+2.1.4
+
diff -Nru qemu-2.1+dfsg/debian/patches/series qemu-2.1+dfsg/debian/patches/series
--- qemu-2.1+dfsg/debian/patches/series 2015-09-12 11:43:21.000000000 +0300
+++ qemu-2.1+dfsg/debian/patches/series 2015-09-14 17:40:58.000000000 +0300
@@ -1,5 +1,5 @@
-# upstream 2.1.2 stable patch
-v2.1.2.diff
+# upstream 2.1.3 stable patch
+v2.1.3.diff
02_kfreebsd.patch
use-fixed-data-path.patch
@@ -9,12 +9,6 @@
9p-readdir.patch
9p-use-little-endian-format-for-xattr-values.patch
qemu-options-add-missing--drive-discard-option-to-cmdline-help.diff
-# 5 patches to fix CVE-2014-3689 from upstream, #765496
-CVE-2014-3689-vmware-vga/1-CVE-2014-3689-turn-off-hw-accel.patch
-CVE-2014-3689-vmware-vga/2-add-vmsvga_verify_rect.patch
-CVE-2014-3689-vmware-vga/3-use-vmsvga_verify_rect-in-vmsvga_update_rect.patch
-CVE-2014-3689-vmware-vga/4-use-vmsvga_verify_rect-in-vmsvga_copy_rect.patch
-CVE-2014-3689-vmware-vga/5-use-vmsvga_verify_rect-in-vmsvga_fill_rect.patch
vnc-sanitize-bits_per_pixel-from-the-client-CVE-2014-7815.patch
@@ -23,7 +17,6 @@
block-raw-posix-Fix-disk-corruption-in-try_fiemap.patch
block-raw-posix-use-seek_hole-ahead-of-fiemap.patch
-tcg-mips-fix-store-softmmu-slow-path.patch
# CVE-2014-7840
migration-fix-parameter-validation-on-ram-load.patch
usb-host-fix-usb_host_speed_compat-tyops.patch
@@ -69,3 +62,9 @@
rtl8139-check-TCP-data-offset-field-CVE-2015-5165.patch
e1000-avoid-infinite-loop-in-transmit-CVE-2015-6815.patch
ide-fix-ATAPI-command-permissions-CVE-2015-6855.patch
+
+#797221
+block-fix-max-nb_sectors-in-bdrv_make_zero.patch
+#793817
+qemu-char-handle-EINTR-for-TCP-character-devices.patch
+qemu-char-fix-missed-data-on-unix-socket.patch
diff -Nru qemu-2.1+dfsg/debian/patches/tcg-mips-fix-store-softmmu-slow-path.patch qemu-2.1+dfsg/debian/patches/tcg-mips-fix-store-softmmu-slow-path.patch
--- qemu-2.1+dfsg/debian/patches/tcg-mips-fix-store-softmmu-slow-path.patch 2015-09-12 11:43:21.000000000 +0300
+++ qemu-2.1+dfsg/debian/patches/tcg-mips-fix-store-softmmu-slow-path.patch 1970-01-01 03:00:00.000000000 +0300
@@ -1,35 +0,0 @@
-From 0a2923f8488498000eec54871456aa64a4391da4 Mon Sep 17 00:00:00 2001
-From: Aurelien Jarno <aurelien@aurel32.net>
-Date: Mon, 27 Oct 2014 15:53:35 +0100
-Subject: tcg/mips: fix store softmmu slow path
-Bug-Debian: http://bugs.debian.org/769470
-
-Commit 9d8bf2d1 moved the softmmu slow path out of line and introduce a
-regression at the same time by always calling tcg_out_tlb_load with
-is_load=1. This makes impossible to run any significant code under
-qemu-system-mips*.
-
-Cc: Paolo Bonzini <pbonzini@redhat.com>
-Cc: qemu-stable@nongnu.org
-Reviewed-by: Richard Henderson <rth@twiddle.net>
-Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
----
- tcg/mips/tcg-target.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/tcg/mips/tcg-target.c b/tcg/mips/tcg-target.c
-index 9cce356..b7f4d67 100644
---- a/tcg/mips/tcg-target.c
-+++ b/tcg/mips/tcg-target.c
-@@ -1302,7 +1302,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is_64)
- so we can reuse that for the base. */
- base = (TARGET_LONG_BITS == 32 ? TCG_REG_A1 : TCG_REG_A2);
- tcg_out_tlb_load(s, base, addr_regl, addr_regh, mem_index,
-- s_bits, label_ptr, 1);
-+ s_bits, label_ptr, 0);
- tcg_out_qemu_st_direct(s, data_regl, data_regh, base, opc);
- add_qemu_ldst_label(s, 0, opc, data_regl, data_regh, addr_regl, addr_regh,
- mem_index, s->code_ptr, label_ptr);
---
-2.1.3
-
diff -Nru qemu-2.1+dfsg/debian/patches/v2.1.2.diff qemu-2.1+dfsg/debian/patches/v2.1.2.diff
--- qemu-2.1+dfsg/debian/patches/v2.1.2.diff 2015-09-12 11:43:21.000000000 +0300
+++ qemu-2.1+dfsg/debian/patches/v2.1.2.diff 1970-01-01 03:00:00.000000000 +0300
@@ -1,2068 +0,0 @@
-Subject: upstream 2.1.2 patch
-From: Michael Roth <mdroth@linux.vnet.ibm.com>
-Date: Thu, 25 Sep 2014 16:13:51 -0500
-
-diff --git a/VERSION b/VERSION
-index 7ec1d6d..eca07e4 100644
---- a/VERSION
-+++ b/VERSION
-@@ -1 +1 @@
--2.1.0
-+2.1.2
-diff --git a/backends/hostmem.c b/backends/hostmem.c
-index ca10c51..a9905c0 100644
---- a/backends/hostmem.c
-+++ b/backends/hostmem.c
-@@ -304,7 +304,7 @@ host_memory_backend_memory_complete(UserCreatable *uc, Error **errp)
- /* ensure policy won't be ignored in case memory is preallocated
- * before mbind(). note: MPOL_MF_STRICT is ignored on hugepages so
- * this doesn't catch hugepage case. */
-- unsigned flags = MPOL_MF_STRICT;
-+ unsigned flags = MPOL_MF_STRICT | MPOL_MF_MOVE;
-
- /* check for invalid host-nodes and policies and give more verbose
- * error messages than mbind(). */
-diff --git a/backends/rng-egd.c b/backends/rng-egd.c
-index 25bb3b4..2962795 100644
---- a/backends/rng-egd.c
-+++ b/backends/rng-egd.c
-@@ -169,6 +169,7 @@ static void rng_egd_set_chardev(Object *obj, const char *value, Error **errp)
- if (b->opened) {
- error_set(errp, QERR_PERMISSION_DENIED);
- } else {
-+ g_free(s->chr_name);
- s->chr_name = g_strdup(value);
- }
- }
-diff --git a/block/blkdebug.c b/block/blkdebug.c
-index f51407d..01b8e73 100644
---- a/block/blkdebug.c
-+++ b/block/blkdebug.c
-@@ -449,6 +449,10 @@ static void error_callback_bh(void *opaque)
- static void blkdebug_aio_cancel(BlockDriverAIOCB *blockacb)
- {
- BlkdebugAIOCB *acb = container_of(blockacb, BlkdebugAIOCB, common);
-+ if (acb->bh) {
-+ qemu_bh_delete(acb->bh);
-+ acb->bh = NULL;
-+ }
- qemu_aio_release(acb);
- }
-
-diff --git a/block/iscsi.c b/block/iscsi.c
-index a7bb697..ed883c3 100644
---- a/block/iscsi.c
-+++ b/block/iscsi.c
-@@ -1509,7 +1509,8 @@ static int iscsi_truncate(BlockDriverState *bs, int64_t offset)
- if (iscsilun->allocationmap != NULL) {
- g_free(iscsilun->allocationmap);
- iscsilun->allocationmap =
-- bitmap_new(DIV_ROUND_UP(bs->total_sectors,
-+ bitmap_new(DIV_ROUND_UP(sector_lun2qemu(iscsilun->num_blocks,
-+ iscsilun),
- iscsilun->cluster_sectors));
- }
-
-diff --git a/block/raw-posix.c b/block/raw-posix.c
-index 8e9758e..87fc170 100644
---- a/block/raw-posix.c
-+++ b/block/raw-posix.c
-@@ -747,6 +747,15 @@ static ssize_t handle_aiocb_rw_linear(RawPosixAIOData *aiocb, char *buf)
- }
- if (len == -1 && errno == EINTR) {
- continue;
-+ } else if (len == -1 && errno == EINVAL &&
-+ (aiocb->bs->open_flags & BDRV_O_NOCACHE) &&
-+ !(aiocb->aio_type & QEMU_AIO_WRITE) &&
-+ offset > 0) {
-+ /* O_DIRECT pread() may fail with EINVAL when offset is unaligned
-+ * after a short read. Assume that O_DIRECT short reads only occur
-+ * at EOF. Therefore this is a short read, not an I/O error.
-+ */
-+ break;
- } else if (len == -1) {
- offset = -errno;
- break;
-diff --git a/configure b/configure
-index f7685b5..f49e618 100755
---- a/configure
-+++ b/configure
-@@ -1723,6 +1723,7 @@ fi
-
- cat > $TMPC <<EOF
- #include <sys/socket.h>
-+#include <linux/ip.h>
- int main(void) { return sizeof(struct mmsghdr); }
- EOF
- if compile_prog "" "" ; then
-diff --git a/exec.c b/exec.c
-index 765bd94..307bc24 100644
---- a/exec.c
-+++ b/exec.c
-@@ -430,15 +430,50 @@ static int cpu_common_post_load(void *opaque, int version_id)
- return 0;
- }
-
-+static int cpu_common_pre_load(void *opaque)
-+{
-+ CPUState *cpu = opaque;
-+
-+ cpu->exception_index = 0;
-+
-+ return 0;
-+}
-+
-+static bool cpu_common_exception_index_needed(void *opaque)
-+{
-+ CPUState *cpu = opaque;
-+
-+ return cpu->exception_index != 0;
-+}
-+
-+static const VMStateDescription vmstate_cpu_common_exception_index = {
-+ .name = "cpu_common/exception_index",
-+ .version_id = 1,
-+ .minimum_version_id = 1,
-+ .fields = (VMStateField[]) {
-+ VMSTATE_INT32(exception_index, CPUState),
-+ VMSTATE_END_OF_LIST()
-+ }
-+};
-+
- const VMStateDescription vmstate_cpu_common = {
- .name = "cpu_common",
- .version_id = 1,
- .minimum_version_id = 1,
-+ .pre_load = cpu_common_pre_load,
- .post_load = cpu_common_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(halted, CPUState),
- VMSTATE_UINT32(interrupt_request, CPUState),
- VMSTATE_END_OF_LIST()
-+ },
-+ .subsections = (VMStateSubsection[]) {
-+ {
-+ .vmsd = &vmstate_cpu_common_exception_index,
-+ .needed = cpu_common_exception_index_needed,
-+ } , {
-+ /* empty */
-+ }
- }
- };
-
-diff --git a/hw/acpi/pcihp.c b/hw/acpi/pcihp.c
-index fae663a..34dedf1 100644
---- a/hw/acpi/pcihp.c
-+++ b/hw/acpi/pcihp.c
-@@ -231,7 +231,7 @@ static uint64_t pci_read(void *opaque, hwaddr addr, unsigned int size)
- uint32_t val = 0;
- int bsel = s->hotplug_select;
-
-- if (bsel < 0 || bsel > ACPI_PCIHP_MAX_HOTPLUG_BUS) {
-+ if (bsel < 0 || bsel >= ACPI_PCIHP_MAX_HOTPLUG_BUS) {
- return 0;
- }
-
-diff --git a/hw/arm/virt.c b/hw/arm/virt.c
-index 89532bd..c8fdac4 100644
---- a/hw/arm/virt.c
-+++ b/hw/arm/virt.c
-@@ -194,20 +194,41 @@ static void fdt_add_psci_node(const VirtBoardInfo *vbi)
-
- /* No PSCI for TCG yet */
- if (kvm_enabled()) {
-+ uint32_t cpu_suspend_fn;
-+ uint32_t cpu_off_fn;
-+ uint32_t cpu_on_fn;
-+ uint32_t migrate_fn;
-+
- qemu_fdt_add_subnode(fdt, "/psci");
- if (armcpu->psci_version == 2) {
- const char comp[] = "arm,psci-0.2\0arm,psci";
- qemu_fdt_setprop(fdt, "/psci", "compatible", comp, sizeof(comp));
-+
-+ cpu_off_fn = QEMU_PSCI_0_2_FN_CPU_OFF;
-+ if (arm_feature(&armcpu->env, ARM_FEATURE_AARCH64)) {
-+ cpu_suspend_fn = QEMU_PSCI_0_2_FN64_CPU_SUSPEND;
-+ cpu_on_fn = QEMU_PSCI_0_2_FN64_CPU_ON;
-+ migrate_fn = QEMU_PSCI_0_2_FN64_MIGRATE;
-+ } else {
-+ cpu_suspend_fn = QEMU_PSCI_0_2_FN_CPU_SUSPEND;
-+ cpu_on_fn = QEMU_PSCI_0_2_FN_CPU_ON;
-+ migrate_fn = QEMU_PSCI_0_2_FN_MIGRATE;
-+ }
- } else {
- qemu_fdt_setprop_string(fdt, "/psci", "compatible", "arm,psci");
-+
-+ cpu_suspend_fn = QEMU_PSCI_0_1_FN_CPU_SUSPEND;
-+ cpu_off_fn = QEMU_PSCI_0_1_FN_CPU_OFF;
-+ cpu_on_fn = QEMU_PSCI_0_1_FN_CPU_ON;
-+ migrate_fn = QEMU_PSCI_0_1_FN_MIGRATE;
- }
-
- qemu_fdt_setprop_string(fdt, "/psci", "method", "hvc");
-- qemu_fdt_setprop_cell(fdt, "/psci", "cpu_suspend",
-- PSCI_FN_CPU_SUSPEND);
-- qemu_fdt_setprop_cell(fdt, "/psci", "cpu_off", PSCI_FN_CPU_OFF);
-- qemu_fdt_setprop_cell(fdt, "/psci", "cpu_on", PSCI_FN_CPU_ON);
-- qemu_fdt_setprop_cell(fdt, "/psci", "migrate", PSCI_FN_MIGRATE);
-+
-+ qemu_fdt_setprop_cell(fdt, "/psci", "cpu_suspend", cpu_suspend_fn);
-+ qemu_fdt_setprop_cell(fdt, "/psci", "cpu_off", cpu_off_fn);
-+ qemu_fdt_setprop_cell(fdt, "/psci", "cpu_on", cpu_on_fn);
-+ qemu_fdt_setprop_cell(fdt, "/psci", "migrate", migrate_fn);
- }
- }
-
-diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
-index c241c50..0e3925b 100644
---- a/hw/block/virtio-blk.c
-+++ b/hw/block/virtio-blk.c
-@@ -469,8 +469,9 @@ static void virtio_blk_dma_restart_bh(void *opaque)
- s->rq = NULL;
-
- while (req) {
-+ VirtIOBlockReq *next = req->next;
- virtio_blk_handle_request(req, &mrb);
-- req = req->next;
-+ req = next;
- }
-
- virtio_submit_multiwrite(s->bs, &mrb);
-diff --git a/hw/core/machine.c b/hw/core/machine.c
-index 7a66c57..d145aca 100644
---- a/hw/core/machine.c
-+++ b/hw/core/machine.c
-@@ -24,6 +24,7 @@ static void machine_set_accel(Object *obj, const char *value, Error **errp)
- {
- MachineState *ms = MACHINE(obj);
-
-+ g_free(ms->accel);
- ms->accel = g_strdup(value);
- }
-
-@@ -79,6 +80,7 @@ static void machine_set_kernel(Object *obj, const char *value, Error **errp)
- {
- MachineState *ms = MACHINE(obj);
-
-+ g_free(ms->kernel_filename);
- ms->kernel_filename = g_strdup(value);
- }
-
-@@ -93,6 +95,7 @@ static void machine_set_initrd(Object *obj, const char *value, Error **errp)
- {
- MachineState *ms = MACHINE(obj);
-
-+ g_free(ms->initrd_filename);
- ms->initrd_filename = g_strdup(value);
- }
-
-@@ -107,6 +110,7 @@ static void machine_set_append(Object *obj, const char *value, Error **errp)
- {
- MachineState *ms = MACHINE(obj);
-
-+ g_free(ms->kernel_cmdline);
- ms->kernel_cmdline = g_strdup(value);
- }
-
-@@ -121,6 +125,7 @@ static void machine_set_dtb(Object *obj, const char *value, Error **errp)
- {
- MachineState *ms = MACHINE(obj);
-
-+ g_free(ms->dtb);
- ms->dtb = g_strdup(value);
- }
-
-@@ -135,6 +140,7 @@ static void machine_set_dumpdtb(Object *obj, const char *value, Error **errp)
- {
- MachineState *ms = MACHINE(obj);
-
-+ g_free(ms->dumpdtb);
- ms->dumpdtb = g_strdup(value);
- }
-
-@@ -176,6 +182,7 @@ static void machine_set_dt_compatible(Object *obj, const char *value, Error **er
- {
- MachineState *ms = MACHINE(obj);
-
-+ g_free(ms->dt_compatible);
- ms->dt_compatible = g_strdup(value);
- }
-
-@@ -232,6 +239,7 @@ static void machine_set_firmware(Object *obj, const char *value, Error **errp)
- {
- MachineState *ms = MACHINE(obj);
-
-+ g_free(ms->firmware);
- ms->firmware = g_strdup(value);
- }
-
-diff --git a/hw/display/qxl-render.c b/hw/display/qxl-render.c
-index cc2c2b1..bcc5c37 100644
---- a/hw/display/qxl-render.c
-+++ b/hw/display/qxl-render.c
-@@ -138,7 +138,9 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl)
- if (qemu_spice_rect_is_empty(qxl->dirty+i)) {
- break;
- }
-- if (qxl->dirty[i].left > qxl->dirty[i].right ||
-+ if (qxl->dirty[i].left < 0 ||
-+ qxl->dirty[i].top < 0 ||
-+ qxl->dirty[i].left > qxl->dirty[i].right ||
- qxl->dirty[i].top > qxl->dirty[i].bottom ||
- qxl->dirty[i].right > qxl->guest_primary.surface.width ||
- qxl->dirty[i].bottom > qxl->guest_primary.surface.height) {
-diff --git a/hw/display/qxl.c b/hw/display/qxl.c
-index d43aa49..652af99 100644
---- a/hw/display/qxl.c
-+++ b/hw/display/qxl.c
-@@ -2063,6 +2063,7 @@ static int qxl_init_primary(PCIDevice *dev)
-
- qxl->id = 0;
- qxl_init_ramsize(qxl);
-+ vga->vbe_size = qxl->vgamem_size;
- vga->vram_size_mb = qxl->vga.vram_size >> 20;
- vga_common_init(vga, OBJECT(dev), true);
- vga_init(vga, OBJECT(dev),
-diff --git a/hw/display/vga.c b/hw/display/vga.c
-index 4b089a3..e82420d 100644
---- a/hw/display/vga.c
-+++ b/hw/display/vga.c
-@@ -580,6 +580,93 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
- }
- }
-
-+/*
-+ * Sanity check vbe register writes.
-+ *
-+ * As we don't have a way to signal errors to the guest in the bochs
-+ * dispi interface we'll go adjust the registers to the closest valid
-+ * value.
-+ */
-+static void vbe_fixup_regs(VGACommonState *s)
-+{
-+ uint16_t *r = s->vbe_regs;
-+ uint32_t bits, linelength, maxy, offset;
-+
-+ if (!(r[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
-+ /* vbe is turned off -- nothing to do */
-+ return;
-+ }
-+
-+ /* check depth */
-+ switch (r[VBE_DISPI_INDEX_BPP]) {
-+ case 4:
-+ case 8:
-+ case 16:
-+ case 24:
-+ case 32:
-+ bits = r[VBE_DISPI_INDEX_BPP];
-+ break;
-+ case 15:
-+ bits = 16;
-+ break;
-+ default:
-+ bits = r[VBE_DISPI_INDEX_BPP] = 8;
-+ break;
-+ }
-+
-+ /* check width */
-+ r[VBE_DISPI_INDEX_XRES] &= ~7u;
-+ if (r[VBE_DISPI_INDEX_XRES] == 0) {
-+ r[VBE_DISPI_INDEX_XRES] = 8;
-+ }
-+ if (r[VBE_DISPI_INDEX_XRES] > VBE_DISPI_MAX_XRES) {
-+ r[VBE_DISPI_INDEX_XRES] = VBE_DISPI_MAX_XRES;
-+ }
-+ r[VBE_DISPI_INDEX_VIRT_WIDTH] &= ~7u;
-+ if (r[VBE_DISPI_INDEX_VIRT_WIDTH] > VBE_DISPI_MAX_XRES) {
-+ r[VBE_DISPI_INDEX_VIRT_WIDTH] = VBE_DISPI_MAX_XRES;
-+ }
-+ if (r[VBE_DISPI_INDEX_VIRT_WIDTH] < r[VBE_DISPI_INDEX_XRES]) {
-+ r[VBE_DISPI_INDEX_VIRT_WIDTH] = r[VBE_DISPI_INDEX_XRES];
-+ }
-+
-+ /* check height */
-+ linelength = r[VBE_DISPI_INDEX_VIRT_WIDTH] * bits / 8;
-+ maxy = s->vbe_size / linelength;
-+ if (r[VBE_DISPI_INDEX_YRES] == 0) {
-+ r[VBE_DISPI_INDEX_YRES] = 1;
-+ }
-+ if (r[VBE_DISPI_INDEX_YRES] > VBE_DISPI_MAX_YRES) {
-+ r[VBE_DISPI_INDEX_YRES] = VBE_DISPI_MAX_YRES;
-+ }
-+ if (r[VBE_DISPI_INDEX_YRES] > maxy) {
-+ r[VBE_DISPI_INDEX_YRES] = maxy;
-+ }
-+
-+ /* check offset */
-+ if (r[VBE_DISPI_INDEX_X_OFFSET] > VBE_DISPI_MAX_XRES) {
-+ r[VBE_DISPI_INDEX_X_OFFSET] = VBE_DISPI_MAX_XRES;
-+ }
-+ if (r[VBE_DISPI_INDEX_Y_OFFSET] > VBE_DISPI_MAX_YRES) {
-+ r[VBE_DISPI_INDEX_Y_OFFSET] = VBE_DISPI_MAX_YRES;
-+ }
-+ offset = r[VBE_DISPI_INDEX_X_OFFSET] * bits / 8;
-+ offset += r[VBE_DISPI_INDEX_Y_OFFSET] * linelength;
-+ if (offset + r[VBE_DISPI_INDEX_YRES] * linelength > s->vbe_size) {
-+ r[VBE_DISPI_INDEX_Y_OFFSET] = 0;
-+ offset = r[VBE_DISPI_INDEX_X_OFFSET] * bits / 8;
-+ if (offset + r[VBE_DISPI_INDEX_YRES] * linelength > s->vbe_size) {
-+ r[VBE_DISPI_INDEX_X_OFFSET] = 0;
-+ offset = 0;
-+ }
-+ }
-+
-+ /* update vga state */
-+ r[VBE_DISPI_INDEX_VIRT_HEIGHT] = maxy;
-+ s->vbe_line_offset = linelength;
-+ s->vbe_start_addr = offset / 4;
-+}
-+
- static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
- {
- VGACommonState *s = opaque;
-@@ -614,7 +701,7 @@ uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr)
- val = s->vbe_regs[s->vbe_index];
- }
- } else if (s->vbe_index == VBE_DISPI_INDEX_VIDEO_MEMORY_64K) {
-- val = s->vram_size / (64 * 1024);
-+ val = s->vbe_size / (64 * 1024);
- } else {
- val = 0;
- }
-@@ -649,22 +736,13 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
- }
- break;
- case VBE_DISPI_INDEX_XRES:
-- if ((val <= VBE_DISPI_MAX_XRES) && ((val & 7) == 0)) {
-- s->vbe_regs[s->vbe_index] = val;
-- }
-- break;
- case VBE_DISPI_INDEX_YRES:
-- if (val <= VBE_DISPI_MAX_YRES) {
-- s->vbe_regs[s->vbe_index] = val;
-- }
-- break;
- case VBE_DISPI_INDEX_BPP:
-- if (val == 0)
-- val = 8;
-- if (val == 4 || val == 8 || val == 15 ||
-- val == 16 || val == 24 || val == 32) {
-- s->vbe_regs[s->vbe_index] = val;
-- }
-+ case VBE_DISPI_INDEX_VIRT_WIDTH:
-+ case VBE_DISPI_INDEX_X_OFFSET:
-+ case VBE_DISPI_INDEX_Y_OFFSET:
-+ s->vbe_regs[s->vbe_index] = val;
-+ vbe_fixup_regs(s);
- break;
- case VBE_DISPI_INDEX_BANK:
- if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
-@@ -681,19 +759,11 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
- !(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
- int h, shift_control;
-
-- s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] =
-- s->vbe_regs[VBE_DISPI_INDEX_XRES];
-- s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] =
-- s->vbe_regs[VBE_DISPI_INDEX_YRES];
-+ s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = 0;
- s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
- s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
--
-- if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
-- s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1;
-- else
-- s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] *
-- ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
-- s->vbe_start_addr = 0;
-+ s->vbe_regs[VBE_DISPI_INDEX_ENABLE] |= VBE_DISPI_ENABLED;
-+ vbe_fixup_regs(s);
-
- /* clear the screen (should be done in BIOS) */
- if (!(val & VBE_DISPI_NOCLEARMEM)) {
-@@ -742,40 +812,6 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
- s->vbe_regs[s->vbe_index] = val;
- vga_update_memory_access(s);
- break;
-- case VBE_DISPI_INDEX_VIRT_WIDTH:
-- {
-- int w, h, line_offset;
--
-- if (val < s->vbe_regs[VBE_DISPI_INDEX_XRES])
-- return;
-- w = val;
-- if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
-- line_offset = w >> 1;
-- else
-- line_offset = w * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
-- h = s->vram_size / line_offset;
-- /* XXX: support weird bochs semantics ? */
-- if (h < s->vbe_regs[VBE_DISPI_INDEX_YRES])
-- return;
-- s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = w;
-- s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = h;
-- s->vbe_line_offset = line_offset;
-- }
-- break;
-- case VBE_DISPI_INDEX_X_OFFSET:
-- case VBE_DISPI_INDEX_Y_OFFSET:
-- {
-- int x;
-- s->vbe_regs[s->vbe_index] = val;
-- s->vbe_start_addr = s->vbe_line_offset * s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET];
-- x = s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET];
-- if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
-- s->vbe_start_addr += x >> 1;
-- else
-- s->vbe_start_addr += x * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
-- s->vbe_start_addr >>= 2;
-- }
-- break;
- default:
- break;
- }
-@@ -2289,6 +2325,9 @@ void vga_common_init(VGACommonState *s, Object *obj, bool global_vmstate)
- s->vram_size <<= 1;
- }
- s->vram_size_mb = s->vram_size >> 20;
-+ if (!s->vbe_size) {
-+ s->vbe_size = s->vram_size;
-+ }
-
- s->is_vbe_vmstate = 1;
- memory_region_init_ram(&s->vram, obj, "vga.vram", s->vram_size);
-diff --git a/hw/display/vga_int.h b/hw/display/vga_int.h
-index 5320abd..cb6d8f6 100644
---- a/hw/display/vga_int.h
-+++ b/hw/display/vga_int.h
-@@ -93,6 +93,7 @@ typedef struct VGACommonState {
- MemoryRegion vram_vbe;
- uint32_t vram_size;
- uint32_t vram_size_mb; /* property */
-+ uint32_t vbe_size;
- uint32_t latch;
- MemoryRegion *chain4_alias;
- uint8_t sr_index;
-diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
-index 816c6d9..8609871 100644
---- a/hw/i386/acpi-build.c
-+++ b/hw/i386/acpi-build.c
-@@ -546,6 +546,12 @@ static void fadt_setup(AcpiFadtDescriptorRev1 *fadt, AcpiPmInfo *pm)
- (1 << ACPI_FADT_F_SLP_BUTTON) |
- (1 << ACPI_FADT_F_RTC_S4));
- fadt->flags |= cpu_to_le32(1 << ACPI_FADT_F_USE_PLATFORM_CLOCK);
-+ /* APIC destination mode ("Flat Logical") has an upper limit of 8 CPUs
-+ * For more than 8 CPUs, "Clustered Logical" mode has to be used
-+ */
-+ if (max_cpus > 8) {
-+ fadt->flags |= cpu_to_le32(1 << ACPI_FADT_F_FORCE_APIC_CLUSTER_MODEL);
-+ }
- }
-
-
-@@ -1393,7 +1399,7 @@ build_rsdp(GArray *rsdp_table, GArray *linker, unsigned rsdt)
- {
- AcpiRsdpDescriptor *rsdp = acpi_data_push(rsdp_table, sizeof *rsdp);
-
-- bios_linker_loader_alloc(linker, ACPI_BUILD_RSDP_FILE, 1,
-+ bios_linker_loader_alloc(linker, ACPI_BUILD_RSDP_FILE, 16,
- true /* fseg memory */);
-
- memcpy(&rsdp->signature, "RSD PTR ", 8);
-diff --git a/hw/i386/acpi-dsdt.dsl b/hw/i386/acpi-dsdt.dsl
-index 6ba0170..559f4b6 100644
---- a/hw/i386/acpi-dsdt.dsl
-+++ b/hw/i386/acpi-dsdt.dsl
-@@ -302,7 +302,7 @@ DefinitionBlock (
- /****************************************************************
- * General purpose events
- ****************************************************************/
-- External(\_SB.PCI0.MEMORY_HOPTLUG_DEVICE.MEMORY_SLOT_SCAN_METHOD, MethodObj)
-+ External(\_SB.PCI0.MEMORY_HOTPLUG_DEVICE.MEMORY_SLOT_SCAN_METHOD, MethodObj)
-
- Scope(\_GPE) {
- Name(_HID, "ACPI0006")
-@@ -321,7 +321,7 @@ DefinitionBlock (
- }
- Method(_E03) {
- // Memory hotplug event
-- \_SB.PCI0.MEMORY_HOPTLUG_DEVICE.MEMORY_SLOT_SCAN_METHOD()
-+ \_SB.PCI0.MEMORY_HOTPLUG_DEVICE.MEMORY_SLOT_SCAN_METHOD()
- }
- Method(_L04) {
- }
-diff --git a/hw/i386/acpi-dsdt.hex.generated b/hw/i386/acpi-dsdt.hex.generated
-index 6c8a1fc..a21bf41 100644
---- a/hw/i386/acpi-dsdt.hex.generated
-+++ b/hw/i386/acpi-dsdt.hex.generated
-@@ -8,7 +8,7 @@ static unsigned char AcpiDsdtAmlCode[] = {
- 0x0,
- 0x0,
- 0x1,
--0x2e,
-+0x1f,
- 0x42,
- 0x58,
- 0x50,
-@@ -31,9 +31,9 @@ static unsigned char AcpiDsdtAmlCode[] = {
- 0x4e,
- 0x54,
- 0x4c,
--0x13,
--0x9,
--0x12,
-+0x28,
-+0x5,
-+0x10,
- 0x20,
- 0x10,
- 0x49,
-diff --git a/hw/i386/pc.c b/hw/i386/pc.c
-index 2cf22b1..ef9fad8 100644
---- a/hw/i386/pc.c
-+++ b/hw/i386/pc.c
-@@ -72,8 +72,15 @@
- #define DPRINTF(fmt, ...)
- #endif
-
--/* Leave a chunk of memory at the top of RAM for the BIOS ACPI tables. */
--#define ACPI_DATA_SIZE 0x10000
-+/* Leave a chunk of memory at the top of RAM for the BIOS ACPI tables
-+ * (128K) and other BIOS datastructures (less than 4K reported to be used at
-+ * the moment, 32K should be enough for a while). */
-+unsigned acpi_data_size = 0x20000 + 0x8000;
-+void pc_set_legacy_acpi_data_size(void)
-+{
-+ acpi_data_size = 0x10000;
-+}
-+
- #define BIOS_CFG_IOPORT 0x510
- #define FW_CFG_ACPI_TABLES (FW_CFG_ARCH_LOCAL + 0)
- #define FW_CFG_SMBIOS_ENTRIES (FW_CFG_ARCH_LOCAL + 1)
-@@ -811,8 +818,9 @@ static void load_linux(FWCfgState *fw_cfg,
- initrd_max = 0x37ffffff;
- }
-
-- if (initrd_max >= max_ram_size-ACPI_DATA_SIZE)
-- initrd_max = max_ram_size-ACPI_DATA_SIZE-1;
-+ if (initrd_max >= max_ram_size - acpi_data_size) {
-+ initrd_max = max_ram_size - acpi_data_size - 1;
-+ }
-
- fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_ADDR, cmdline_addr);
- fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, strlen(kernel_cmdline)+1);
-diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
-index 9694f88..8dc8290 100644
---- a/hw/i386/pc_piix.c
-+++ b/hw/i386/pc_piix.c
-@@ -318,6 +318,7 @@ static void pc_compat_2_0(MachineState *machine)
- legacy_acpi_table_size = 6652;
- smbios_legacy_mode = true;
- has_reserved_memory = false;
-+ pc_set_legacy_acpi_data_size();
- }
-
- static void pc_compat_1_7(MachineState *machine)
-diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
-index c39ee98..4e2dd49 100644
---- a/hw/i386/pc_q35.c
-+++ b/hw/i386/pc_q35.c
-@@ -282,6 +282,7 @@ static void pc_compat_2_0(MachineState *machine)
- {
- smbios_legacy_mode = true;
- has_reserved_memory = false;
-+ pc_set_legacy_acpi_data_size();
- }
-
- static void pc_compat_1_7(MachineState *machine)
-diff --git a/hw/i386/q35-acpi-dsdt.dsl b/hw/i386/q35-acpi-dsdt.dsl
-index 8c3eae7..054b035 100644
---- a/hw/i386/q35-acpi-dsdt.dsl
-+++ b/hw/i386/q35-acpi-dsdt.dsl
-@@ -410,7 +410,7 @@ DefinitionBlock (
- /****************************************************************
- * General purpose events
- ****************************************************************/
-- External(\_SB.PCI0.MEMORY_HOPTLUG_DEVICE.MEMORY_SLOT_SCAN_METHOD, MethodObj)
-+ External(\_SB.PCI0.MEMORY_HOTPLUG_DEVICE.MEMORY_SLOT_SCAN_METHOD, MethodObj)
-
- Scope(\_GPE) {
- Name(_HID, "ACPI0006")
-@@ -425,7 +425,7 @@ DefinitionBlock (
- }
- Method(_E03) {
- // Memory hotplug event
-- \_SB.PCI0.MEMORY_HOPTLUG_DEVICE.MEMORY_SLOT_SCAN_METHOD()
-+ \_SB.PCI0.MEMORY_HOTPLUG_DEVICE.MEMORY_SLOT_SCAN_METHOD()
- }
- Method(_L04) {
- }
-diff --git a/hw/i386/ssdt-mem.dsl b/hw/i386/ssdt-mem.dsl
-index 8e17bd1..22ff5dd 100644
---- a/hw/i386/ssdt-mem.dsl
-+++ b/hw/i386/ssdt-mem.dsl
-@@ -39,10 +39,10 @@ ACPI_EXTRACT_ALL_CODE ssdm_mem_aml
- DefinitionBlock ("ssdt-mem.aml", "SSDT", 0x02, "BXPC", "CSSDT", 0x1)
- {
-
-- External(\_SB.PCI0.MEMORY_HOPTLUG_DEVICE.MEMORY_SLOT_CRS_METHOD, MethodObj)
-- External(\_SB.PCI0.MEMORY_HOPTLUG_DEVICE.MEMORY_SLOT_STATUS_METHOD, MethodObj)
-- External(\_SB.PCI0.MEMORY_HOPTLUG_DEVICE.MEMORY_SLOT_OST_METHOD, MethodObj)
-- External(\_SB.PCI0.MEMORY_HOPTLUG_DEVICE.MEMORY_SLOT_PROXIMITY_METHOD, MethodObj)
-+ External(\_SB.PCI0.MEMORY_HOTPLUG_DEVICE.MEMORY_SLOT_CRS_METHOD, MethodObj)
-+ External(\_SB.PCI0.MEMORY_HOTPLUG_DEVICE.MEMORY_SLOT_STATUS_METHOD, MethodObj)
-+ External(\_SB.PCI0.MEMORY_HOTPLUG_DEVICE.MEMORY_SLOT_OST_METHOD, MethodObj)
-+ External(\_SB.PCI0.MEMORY_HOTPLUG_DEVICE.MEMORY_SLOT_PROXIMITY_METHOD, MethodObj)
-
- Scope(\_SB) {
- /* v------------------ DO NOT EDIT ------------------v */
-@@ -58,19 +58,19 @@ DefinitionBlock ("ssdt-mem.aml", "SSDT", 0x02, "BXPC", "CSSDT", 0x1)
- Name(_HID, EISAID("PNP0C80"))
-
- Method(_CRS, 0) {
-- Return(\_SB.PCI0.MEMORY_HOPTLUG_DEVICE.MEMORY_SLOT_CRS_METHOD(_UID))
-+ Return(\_SB.PCI0.MEMORY_HOTPLUG_DEVICE.MEMORY_SLOT_CRS_METHOD(_UID))
- }
-
- Method(_STA, 0) {
-- Return(\_SB.PCI0.MEMORY_HOPTLUG_DEVICE.MEMORY_SLOT_STATUS_METHOD(_UID))
-+ Return(\_SB.PCI0.MEMORY_HOTPLUG_DEVICE.MEMORY_SLOT_STATUS_METHOD(_UID))
- }
-
- Method(_PXM, 0) {
-- Return(\_SB.PCI0.MEMORY_HOPTLUG_DEVICE.MEMORY_SLOT_PROXIMITY_METHOD(_UID))
-+ Return(\_SB.PCI0.MEMORY_HOTPLUG_DEVICE.MEMORY_SLOT_PROXIMITY_METHOD(_UID))
- }
-
- Method(_OST, 3) {
-- \_SB.PCI0.MEMORY_HOPTLUG_DEVICE.MEMORY_SLOT_OST_METHOD(_UID, Arg0, Arg1, Arg2)
-+ \_SB.PCI0.MEMORY_HOTPLUG_DEVICE.MEMORY_SLOT_OST_METHOD(_UID, Arg0, Arg1, Arg2)
- }
- }
- }
-diff --git a/hw/i386/ssdt-misc.dsl b/hw/i386/ssdt-misc.dsl
-index d329b8b..0fd4480 100644
---- a/hw/i386/ssdt-misc.dsl
-+++ b/hw/i386/ssdt-misc.dsl
-@@ -120,7 +120,7 @@ DefinitionBlock ("ssdt-misc.aml", "SSDT", 0x01, "BXPC", "BXSSDTSUSP", 0x1)
-
- External(MEMORY_SLOT_NOTIFY_METHOD, MethodObj)
- Scope(\_SB.PCI0) {
-- Device(MEMORY_HOPTLUG_DEVICE) {
-+ Device(MEMORY_HOTPLUG_DEVICE) {
- Name(_HID, "PNP0A06")
- Name(_UID, "Memory hotplug resources")
-
-diff --git a/hw/ide/core.c b/hw/ide/core.c
-index db191a6..7256592 100644
---- a/hw/ide/core.c
-+++ b/hw/ide/core.c
-@@ -688,7 +688,8 @@ void ide_dma_cb(void *opaque, int ret)
- sector_num, n, s->dma_cmd);
- #endif
-
-- if (!ide_sect_range_ok(s, sector_num, n)) {
-+ if ((s->dma_cmd == IDE_DMA_READ || s->dma_cmd == IDE_DMA_WRITE) &&
-+ !ide_sect_range_ok(s, sector_num, n)) {
- dma_buf_commit(s);
- ide_dma_error(s);
- return;
-diff --git a/hw/mem/pc-dimm.c b/hw/mem/pc-dimm.c
-index 08f49ed..5bfc5b7 100644
---- a/hw/mem/pc-dimm.c
-+++ b/hw/mem/pc-dimm.c
-@@ -252,6 +252,12 @@ static void pc_dimm_realize(DeviceState *dev, Error **errp)
- error_setg(errp, "'" PC_DIMM_MEMDEV_PROP "' property is not set");
- return;
- }
-+ if (dimm->node >= nb_numa_nodes) {
-+ error_setg(errp, "'DIMM property " PC_DIMM_NODE_PROP " has value %"
-+ PRIu32 "' which exceeds the number of numa nodes: %d",
-+ dimm->node, nb_numa_nodes);
-+ return;
-+ }
- }
-
- static MemoryRegion *pc_dimm_get_memory_region(PCDIMMDevice *dimm)
-diff --git a/hw/misc/vfio.c b/hw/misc/vfio.c
-index 0b9eba0..e88b610 100644
---- a/hw/misc/vfio.c
-+++ b/hw/misc/vfio.c
-@@ -120,11 +120,20 @@ typedef struct VFIOINTx {
- } VFIOINTx;
-
- typedef struct VFIOMSIVector {
-- EventNotifier interrupt; /* eventfd triggered on interrupt */
-- EventNotifier kvm_interrupt; /* eventfd triggered for KVM irqfd bypass */
-+ /*
-+ * Two interrupt paths are configured per vector. The first, is only used
-+ * for interrupts injected via QEMU. This is typically the non-accel path,
-+ * but may also be used when we want QEMU to handle masking and pending
-+ * bits. The KVM path bypasses QEMU and is therefore higher performance,
-+ * but requires masking at the device. virq is used to track the MSI route
-+ * through KVM, thus kvm_interrupt is only available when virq is set to a
-+ * valid (>= 0) value.
-+ */
-+ EventNotifier interrupt;
-+ EventNotifier kvm_interrupt;
- struct VFIODevice *vdev; /* back pointer to device */
- MSIMessage msg; /* cache the MSI message so we know when it changes */
-- int virq; /* KVM irqchip route for QEMU bypass */
-+ int virq;
- bool use;
- } VFIOMSIVector;
-
-@@ -681,13 +690,24 @@ static int vfio_enable_vectors(VFIODevice *vdev, bool msix)
- fds = (int32_t *)&irq_set->data;
-
- for (i = 0; i < vdev->nr_vectors; i++) {
-- if (!vdev->msi_vectors[i].use) {
-- fds[i] = -1;
-- } else if (vdev->msi_vectors[i].virq >= 0) {
-- fds[i] = event_notifier_get_fd(&vdev->msi_vectors[i].kvm_interrupt);
-- } else {
-- fds[i] = event_notifier_get_fd(&vdev->msi_vectors[i].interrupt);
-+ int fd = -1;
-+
-+ /*
-+ * MSI vs MSI-X - The guest has direct access to MSI mask and pending
-+ * bits, therefore we always use the KVM signaling path when setup.
-+ * MSI-X mask and pending bits are emulated, so we want to use the
-+ * KVM signaling path only when configured and unmasked.
-+ */
-+ if (vdev->msi_vectors[i].use) {
-+ if (vdev->msi_vectors[i].virq < 0 ||
-+ (msix && msix_is_masked(&vdev->pdev, i))) {
-+ fd = event_notifier_get_fd(&vdev->msi_vectors[i].interrupt);
-+ } else {
-+ fd = event_notifier_get_fd(&vdev->msi_vectors[i].kvm_interrupt);
-+ }
- }
-+
-+ fds[i] = fd;
- }
-
- ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set);
-diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
-index f87c798..b37438b 100644
---- a/hw/net/vhost_net.c
-+++ b/hw/net/vhost_net.c
-@@ -115,6 +115,7 @@ unsigned vhost_net_get_features(struct vhost_net *net, unsigned features)
-
- void vhost_net_ack_features(struct vhost_net *net, unsigned features)
- {
-+ net->dev.acked_features = net->dev.backend_features;
- vhost_ack_features(&net->dev, vhost_net_get_feature_bits(net), features);
- }
-
-@@ -188,9 +189,13 @@ bool vhost_net_query(VHostNetState *net, VirtIODevice *dev)
- return vhost_dev_query(&net->dev, dev);
- }
-
-+static void vhost_net_set_vq_index(struct vhost_net *net, int vq_index)
-+{
-+ net->dev.vq_index = vq_index;
-+}
-+
- static int vhost_net_start_one(struct vhost_net *net,
-- VirtIODevice *dev,
-- int vq_index)
-+ VirtIODevice *dev)
- {
- struct vhost_vring_file file = { };
- int r;
-@@ -201,7 +206,6 @@ static int vhost_net_start_one(struct vhost_net *net,
-
- net->dev.nvqs = 2;
- net->dev.vqs = net->vqs;
-- net->dev.vq_index = vq_index;
-
- r = vhost_dev_enable_notifiers(&net->dev, dev);
- if (r < 0) {
-@@ -294,7 +298,7 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs,
- BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(dev)));
- VirtioBusState *vbus = VIRTIO_BUS(qbus);
- VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus);
-- int r, i = 0;
-+ int r, e, i;
-
- if (!vhost_net_device_endian_ok(dev)) {
- error_report("vhost-net does not support cross-endian");
-@@ -309,11 +313,7 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs,
- }
-
- for (i = 0; i < total_queues; i++) {
-- r = vhost_net_start_one(get_vhost_net(ncs[i].peer), dev, i * 2);
--
-- if (r < 0) {
-- goto err;
-- }
-+ vhost_net_set_vq_index(get_vhost_net(ncs[i].peer), i * 2);
- }
-
- r = k->set_guest_notifiers(qbus->parent, total_queues * 2, true);
-@@ -322,12 +322,26 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs,
- goto err;
- }
-
-+ for (i = 0; i < total_queues; i++) {
-+ r = vhost_net_start_one(get_vhost_net(ncs[i].peer), dev);
-+
-+ if (r < 0) {
-+ goto err_start;
-+ }
-+ }
-+
- return 0;
-
--err:
-+err_start:
- while (--i >= 0) {
- vhost_net_stop_one(get_vhost_net(ncs[i].peer), dev);
- }
-+ e = k->set_guest_notifiers(qbus->parent, total_queues * 2, false);
-+ if (e < 0) {
-+ fprintf(stderr, "vhost guest notifier cleanup failed: %d\n", e);
-+ fflush(stderr);
-+ }
-+err:
- return r;
- }
-
-@@ -339,16 +353,16 @@ void vhost_net_stop(VirtIODevice *dev, NetClientState *ncs,
- VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus);
- int i, r;
-
-+ for (i = 0; i < total_queues; i++) {
-+ vhost_net_stop_one(get_vhost_net(ncs[i].peer), dev);
-+ }
-+
- r = k->set_guest_notifiers(qbus->parent, total_queues * 2, false);
- if (r < 0) {
- fprintf(stderr, "vhost guest notifier cleanup failed: %d\n", r);
- fflush(stderr);
- }
- assert(r >= 0);
--
-- for (i = 0; i < total_queues; i++) {
-- vhost_net_stop_one(get_vhost_net(ncs[i].peer), dev);
-- }
- }
-
- void vhost_net_cleanup(struct vhost_net *net)
-diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
-index 268eff9..2040eac 100644
---- a/hw/net/virtio-net.c
-+++ b/hw/net/virtio-net.c
-@@ -125,10 +125,23 @@ static void virtio_net_vhost_status(VirtIONet *n, uint8_t status)
- return;
- }
- if (!n->vhost_started) {
-- int r;
-+ int r, i;
-+
- if (!vhost_net_query(get_vhost_net(nc->peer), vdev)) {
- return;
- }
-+
-+ /* Any packets outstanding? Purge them to avoid touching rings
-+ * when vhost is running.
-+ */
-+ for (i = 0; i < queues; i++) {
-+ NetClientState *qnc = qemu_get_subqueue(n->nic, i);
-+
-+ /* Purge both directions: TX and RX. */
-+ qemu_net_queue_purge(qnc->peer->incoming_queue, qnc);
-+ qemu_net_queue_purge(qnc->incoming_queue, qnc->peer);
-+ }
-+
- n->vhost_started = 1;
- r = vhost_net_start(vdev, n->nic->ncs, queues);
- if (r < 0) {
-@@ -1112,8 +1125,6 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q)
- return num_packets;
- }
-
-- assert(vdev->vm_running);
--
- if (q->async_tx.elem.out_num) {
- virtio_queue_set_notification(q->tx_vq, 0);
- return num_packets;
-@@ -1224,7 +1235,12 @@ static void virtio_net_tx_timer(void *opaque)
- VirtIONetQueue *q = opaque;
- VirtIONet *n = q->n;
- VirtIODevice *vdev = VIRTIO_DEVICE(n);
-- assert(vdev->vm_running);
-+ /* This happens when device was stopped but BH wasn't. */
-+ if (!vdev->vm_running) {
-+ /* Make sure tx waiting is set, so we'll run when restarted. */
-+ assert(q->tx_waiting);
-+ return;
-+ }
-
- q->tx_waiting = 0;
-
-@@ -1244,7 +1260,12 @@ static void virtio_net_tx_bh(void *opaque)
- VirtIODevice *vdev = VIRTIO_DEVICE(n);
- int32_t ret;
-
-- assert(vdev->vm_running);
-+ /* This happens when device was stopped but BH wasn't. */
-+ if (!vdev->vm_running) {
-+ /* Make sure tx waiting is set, so we'll run when restarted. */
-+ assert(q->tx_waiting);
-+ return;
-+ }
-
- q->tx_waiting = 0;
-
-diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c
-index 77bea6f..ae3e50f 100644
---- a/hw/net/vmxnet3.c
-+++ b/hw/net/vmxnet3.c
-@@ -34,6 +34,7 @@
-
- #define PCI_DEVICE_ID_VMWARE_VMXNET3_REVISION 0x1
- #define VMXNET3_MSIX_BAR_SIZE 0x2000
-+#define MIN_BUF_SIZE 60
-
- #define VMXNET3_BAR0_IDX (0)
- #define VMXNET3_BAR1_IDX (1)
-@@ -1871,12 +1872,21 @@ vmxnet3_receive(NetClientState *nc, const uint8_t *buf, size_t size)
- {
- VMXNET3State *s = qemu_get_nic_opaque(nc);
- size_t bytes_indicated;
-+ uint8_t min_buf[MIN_BUF_SIZE];
-
- if (!vmxnet3_can_receive(nc)) {
- VMW_PKPRN("Cannot receive now");
- return -1;
- }
-
-+ /* Pad to minimum Ethernet frame length */
-+ if (size < sizeof(min_buf)) {
-+ memcpy(min_buf, buf, size);
-+ memset(&min_buf[size], 0, sizeof(min_buf) - size);
-+ buf = min_buf;
-+ size = sizeof(min_buf);
-+ }
-+
- if (s->peer_has_vhdr) {
- vmxnet_rx_pkt_set_vhdr(s->rx_pkt, (struct virtio_net_hdr *)buf);
- buf += sizeof(struct virtio_net_hdr);
-diff --git a/hw/pci/pci.c b/hw/pci/pci.c
-index 351d320..42995e6 100644
---- a/hw/pci/pci.c
-+++ b/hw/pci/pci.c
-@@ -1147,9 +1147,10 @@ uint32_t pci_default_read_config(PCIDevice *d,
- return le32_to_cpu(val);
- }
-
--void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l)
-+void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val_in, int l)
- {
- int i, was_irq_disabled = pci_irq_disabled(d);
-+ uint32_t val = val_in;
-
- for (i = 0; i < l; val >>= 8, ++i) {
- uint8_t wmask = d->wmask[addr + i];
-@@ -1171,8 +1172,8 @@ void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l)
- & PCI_COMMAND_MASTER);
- }
-
-- msi_write_config(d, addr, val, l);
-- msix_write_config(d, addr, val, l);
-+ msi_write_config(d, addr, val_in, l);
-+ msix_write_config(d, addr, val_in, l);
- }
-
- /***********************************************************/
-diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c
-index ddfe76a..7146e0e 100644
---- a/hw/scsi/vhost-scsi.c
-+++ b/hw/scsi/vhost-scsi.c
-@@ -238,6 +238,7 @@ static void vhost_scsi_realize(DeviceState *dev, Error **errp)
- s->dev.nvqs = VHOST_SCSI_VQ_NUM_FIXED + vs->conf.num_queues;
- s->dev.vqs = g_new(struct vhost_virtqueue, s->dev.nvqs);
- s->dev.vq_index = 0;
-+ s->dev.backend_features = 0;
-
- ret = vhost_dev_init(&s->dev, (void *)(uintptr_t)vhostfd,
- VHOST_BACKEND_TYPE_KERNEL, true);
-@@ -246,7 +247,6 @@ static void vhost_scsi_realize(DeviceState *dev, Error **errp)
- strerror(-ret));
- return;
- }
-- s->dev.backend_features = 0;
-
- error_setg(&s->migration_blocker,
- "vhost-scsi does not support migration");
-diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
-index e55fe1c..5d7c40a 100644
---- a/hw/virtio/vhost.c
-+++ b/hw/virtio/vhost.c
-@@ -976,7 +976,6 @@ void vhost_dev_disable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev)
- bool vhost_virtqueue_pending(struct vhost_dev *hdev, int n)
- {
- struct vhost_virtqueue *vq = hdev->vqs + n - hdev->vq_index;
-- assert(hdev->started);
- assert(n >= hdev->vq_index && n < hdev->vq_index + hdev->nvqs);
- return event_notifier_test_and_clear(&vq->masked_notifier);
- }
-@@ -988,7 +987,6 @@ void vhost_virtqueue_mask(struct vhost_dev *hdev, VirtIODevice *vdev, int n,
- struct VirtQueue *vvq = virtio_get_queue(vdev, n);
- int r, index = n - hdev->vq_index;
-
-- assert(hdev->started);
- assert(n >= hdev->vq_index && n < hdev->vq_index + hdev->nvqs);
-
- struct vhost_vring_file file = {
-diff --git a/include/hw/acpi/pc-hotplug.h b/include/hw/acpi/pc-hotplug.h
-index bf5157d..b9db295 100644
---- a/include/hw/acpi/pc-hotplug.h
-+++ b/include/hw/acpi/pc-hotplug.h
-@@ -32,7 +32,7 @@
- #define ACPI_MEMORY_HOTPLUG_IO_LEN 24
- #define ACPI_MEMORY_HOTPLUG_BASE 0x0a00
-
--#define MEMORY_HOPTLUG_DEVICE MHPD
-+#define MEMORY_HOTPLUG_DEVICE MHPD
- #define MEMORY_SLOTS_NUMBER MDNR
- #define MEMORY_HOTPLUG_IO_REGION HPMR
- #define MEMORY_SLOT_ADDR_LOW MRBL
-diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
-index f4b9b2b..5f0a265 100644
---- a/include/hw/i386/pc.h
-+++ b/include/hw/i386/pc.h
-@@ -177,6 +177,8 @@ void pc_acpi_init(const char *default_dsdt);
- PcGuestInfo *pc_guest_info_init(ram_addr_t below_4g_mem_size,
- ram_addr_t above_4g_mem_size);
-
-+void pc_set_legacy_acpi_data_size(void);
-+
- #define PCI_HOST_PROP_PCI_HOLE_START "pci-hole-start"
- #define PCI_HOST_PROP_PCI_HOLE_END "pci-hole-end"
- #define PCI_HOST_PROP_PCI_HOLE64_START "pci-hole64-start"
-diff --git a/net/net.c b/net/net.c
-index 6d930ea..7acc162 100644
---- a/net/net.c
-+++ b/net/net.c
-@@ -41,12 +41,14 @@
- #include "qapi-visit.h"
- #include "qapi/opts-visitor.h"
- #include "qapi/dealloc-visitor.h"
-+#include "sysemu/sysemu.h"
-
- /* Net bridge is currently not supported for W32. */
- #if !defined(_WIN32)
- # define CONFIG_NET_BRIDGE
- #endif
-
-+static VMChangeStateEntry *net_change_state_entry;
- static QTAILQ_HEAD(, NetClientState) net_clients;
-
- const char *host_net_devices[] = {
-@@ -452,6 +454,12 @@ void qemu_set_vnet_hdr_len(NetClientState *nc, int len)
-
- int qemu_can_send_packet(NetClientState *sender)
- {
-+ int vm_running = runstate_is_running();
-+
-+ if (!vm_running) {
-+ return 0;
-+ }
-+
- if (!sender->peer) {
- return 1;
- }
-@@ -504,7 +512,8 @@ void qemu_purge_queued_packets(NetClientState *nc)
- qemu_net_queue_purge(nc->peer->incoming_queue, nc);
- }
-
--void qemu_flush_queued_packets(NetClientState *nc)
-+static
-+void qemu_flush_or_purge_queued_packets(NetClientState *nc, bool purge)
- {
- nc->receive_disabled = 0;
-
-@@ -518,9 +527,17 @@ void qemu_flush_queued_packets(NetClientState *nc)
- * the file descriptor (for tap, for example).
- */
- qemu_notify_event();
-+ } else if (purge) {
-+ /* Unable to empty the queue, purge remaining packets */
-+ qemu_net_queue_purge(nc->incoming_queue, nc);
- }
- }
-
-+void qemu_flush_queued_packets(NetClientState *nc)
-+{
-+ qemu_flush_or_purge_queued_packets(nc, false);
-+}
-+
- static ssize_t qemu_send_packet_async_with_flags(NetClientState *sender,
- unsigned flags,
- const uint8_t *buf, int size,
-@@ -1168,6 +1185,22 @@ void qmp_set_link(const char *name, bool up, Error **errp)
- }
- }
-
-+static void net_vm_change_state_handler(void *opaque, int running,
-+ RunState state)
-+{
-+ /* Complete all queued packets, to guarantee we don't modify
-+ * state later when VM is not running.
-+ */
-+ if (!running) {
-+ NetClientState *nc;
-+ NetClientState *tmp;
-+
-+ QTAILQ_FOREACH_SAFE(nc, &net_clients, next, tmp) {
-+ qemu_flush_or_purge_queued_packets(nc, true);
-+ }
-+ }
-+}
-+
- void net_cleanup(void)
- {
- NetClientState *nc;
-@@ -1183,6 +1216,8 @@ void net_cleanup(void)
- qemu_del_net_client(nc);
- }
- }
-+
-+ qemu_del_vm_change_state_handler(net_change_state_entry);
- }
-
- void net_check_clients(void)
-@@ -1268,6 +1303,9 @@ int net_init_clients(void)
- #endif
- }
-
-+ net_change_state_entry =
-+ qemu_add_vm_change_state_handler(net_vm_change_state_handler, NULL);
-+
- QTAILQ_INIT(&net_clients);
-
- if (qemu_opts_foreach(qemu_find_opts("netdev"), net_init_netdev, NULL, 1) == -1)
-diff --git a/net/queue.c b/net/queue.c
-index 859d02a..f948318 100644
---- a/net/queue.c
-+++ b/net/queue.c
-@@ -233,6 +233,9 @@ void qemu_net_queue_purge(NetQueue *queue, NetClientState *from)
- if (packet->sender == from) {
- QTAILQ_REMOVE(&queue->packets, packet, entry);
- queue->nq_count--;
-+ if (packet->sent_cb) {
-+ packet->sent_cb(packet->sender, 0);
-+ }
- g_free(packet);
- }
- }
-diff --git a/numa.c b/numa.c
-index 7bf7834..c78cec9 100644
---- a/numa.c
-+++ b/numa.c
-@@ -210,8 +210,8 @@ void set_numa_nodes(void)
- numa_total += numa_info[i].node_mem;
- }
- if (numa_total != ram_size) {
-- error_report("total memory for NUMA nodes (%" PRIu64 ")"
-- " should equal RAM size (" RAM_ADDR_FMT ")",
-+ error_report("total memory for NUMA nodes (0x%" PRIx64 ")"
-+ " should equal RAM size (0x" RAM_ADDR_FMT ")",
- numa_total, ram_size);
- exit(1);
- }
-diff --git a/qdev-monitor.c b/qdev-monitor.c
-index f87f3d8..5fe5e75 100644
---- a/qdev-monitor.c
-+++ b/qdev-monitor.c
-@@ -182,9 +182,10 @@ static const char *find_typename_by_alias(const char *alias)
-
- int qdev_device_help(QemuOpts *opts)
- {
-+ Error *local_err = NULL;
- const char *driver;
-- Property *prop;
-- ObjectClass *klass;
-+ DevicePropertyInfoList *prop_list;
-+ DevicePropertyInfoList *prop;
-
- driver = qemu_opt_get(opts, "driver");
- if (driver && is_help_option(driver)) {
-@@ -196,35 +197,28 @@ int qdev_device_help(QemuOpts *opts)
- return 0;
- }
-
-- klass = object_class_by_name(driver);
-- if (!klass) {
-+ if (!object_class_by_name(driver)) {
- const char *typename = find_typename_by_alias(driver);
-
- if (typename) {
- driver = typename;
-- klass = object_class_by_name(driver);
- }
- }
-
-- if (!object_class_dynamic_cast(klass, TYPE_DEVICE)) {
-- return 0;
-+ prop_list = qmp_device_list_properties(driver, &local_err);
-+ if (!prop_list) {
-+ error_printf("%s\n", error_get_pretty(local_err));
-+ error_free(local_err);
-+ return 1;
- }
-- do {
-- for (prop = DEVICE_CLASS(klass)->props; prop && prop->name; prop++) {
-- /*
-- * TODO Properties without a parser are just for dirty hacks.
-- * qdev_prop_ptr is the only such PropertyInfo. It's marked
-- * for removal. This conditional should be removed along with
-- * it.
-- */
-- if (!prop->info->set) {
-- continue; /* no way to set it, don't show */
-- }
-- error_printf("%s.%s=%s\n", driver, prop->name,
-- prop->info->legacy_name ?: prop->info->name);
-- }
-- klass = object_class_get_parent(klass);
-- } while (klass != object_class_by_name(TYPE_DEVICE));
-+
-+ for (prop = prop_list; prop; prop = prop->next) {
-+ error_printf("%s.%s=%s\n", driver,
-+ prop->value->name,
-+ prop->value->type);
-+ }
-+
-+ qapi_free_DevicePropertyInfoList(prop_list);
- return 1;
- }
-
-diff --git a/qemu-char.c b/qemu-char.c
-index 956be49..2abb330 100644
---- a/qemu-char.c
-+++ b/qemu-char.c
-@@ -1160,7 +1160,9 @@ static int pty_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
- if (!s->connected) {
- /* guest sends data, check for (re-)connect */
- pty_chr_update_read_handler_locked(chr);
-- return 0;
-+ if (!s->connected) {
-+ return 0;
-+ }
- }
- return io_channel_send(s->fd, buf, len);
- }
-diff --git a/qmp.c b/qmp.c
-index 0d2553a..c6767c4 100644
---- a/qmp.c
-+++ b/qmp.c
-@@ -509,6 +509,7 @@ DevicePropertyInfoList *qmp_device_list_properties(const char *typename,
- if (strcmp(prop->name, "type") == 0 ||
- strcmp(prop->name, "realized") == 0 ||
- strcmp(prop->name, "hotpluggable") == 0 ||
-+ strcmp(prop->name, "hotplugged") == 0 ||
- strcmp(prop->name, "parent_bus") == 0) {
- continue;
- }
-diff --git a/slirp/udp.c b/slirp/udp.c
-index 8cc6cb6..f77e00f 100644
---- a/slirp/udp.c
-+++ b/slirp/udp.c
-@@ -152,7 +152,7 @@ udp_input(register struct mbuf *m, int iphlen)
- * Locate pcb for datagram.
- */
- so = slirp->udp_last_so;
-- if (so->so_lport != uh->uh_sport ||
-+ if (so == &slirp->udb || so->so_lport != uh->uh_sport ||
- so->so_laddr.s_addr != ip->ip_src.s_addr) {
- struct socket *tmp;
-
-diff --git a/target-arm/cpu.h b/target-arm/cpu.h
-index 369d472..f101880 100644
---- a/target-arm/cpu.h
-+++ b/target-arm/cpu.h
-@@ -1170,7 +1170,14 @@ static inline int cpu_mmu_index (CPUARMState *env)
- static inline void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
- target_ulong *cs_base, int *flags)
- {
-- int fpen = extract32(env->cp15.c1_coproc, 20, 2);
-+ int fpen;
-+
-+ if (arm_feature(env, ARM_FEATURE_V6)) {
-+ fpen = extract32(env->cp15.c1_coproc, 20, 2);
-+ } else {
-+ /* CPACR doesn't exist before v6, so VFP is always accessible */
-+ fpen = 3;
-+ }
-
- if (is_a64(env)) {
- *pc = env->pc;
-diff --git a/target-arm/cpu64.c b/target-arm/cpu64.c
-index 8b2081c..b2ed01f 100644
---- a/target-arm/cpu64.c
-+++ b/target-arm/cpu64.c
-@@ -123,9 +123,10 @@ static void aarch64_a57_initfn(Object *obj)
- cpu->id_isar2 = 0x21232042;
- cpu->id_isar3 = 0x01112131;
- cpu->id_isar4 = 0x00011142;
-+ cpu->id_isar5 = 0x00011121;
- cpu->id_aa64pfr0 = 0x00002222;
- cpu->id_aa64dfr0 = 0x10305106;
-- cpu->id_aa64isar0 = 0x00010000;
-+ cpu->id_aa64isar0 = 0x00011120;
- cpu->id_aa64mmfr0 = 0x00001124;
- cpu->clidr = 0x0a200023;
- cpu->ccsidr[0] = 0x701fe00a; /* 32KB L1 dcache */
-diff --git a/target-arm/kvm-consts.h b/target-arm/kvm-consts.h
-index 6009a33..091c126 100644
---- a/target-arm/kvm-consts.h
-+++ b/target-arm/kvm-consts.h
-@@ -17,6 +17,7 @@
- #ifdef CONFIG_KVM
- #include "qemu/compiler.h"
- #include <linux/kvm.h>
-+#include <linux/psci.h>
-
- #define MISMATCH_CHECK(X, Y) QEMU_BUILD_BUG_ON(X != Y)
-
-@@ -38,17 +39,43 @@ MISMATCH_CHECK(CP_REG_SIZE_U64, KVM_REG_SIZE_U64)
- MISMATCH_CHECK(CP_REG_ARM, KVM_REG_ARM)
- MISMATCH_CHECK(CP_REG_ARCH_MASK, KVM_REG_ARCH_MASK)
-
--#define PSCI_FN_BASE 0x95c1ba5e
--#define PSCI_FN(n) (PSCI_FN_BASE + (n))
--#define PSCI_FN_CPU_SUSPEND PSCI_FN(0)
--#define PSCI_FN_CPU_OFF PSCI_FN(1)
--#define PSCI_FN_CPU_ON PSCI_FN(2)
--#define PSCI_FN_MIGRATE PSCI_FN(3)
--
--MISMATCH_CHECK(PSCI_FN_CPU_SUSPEND, KVM_PSCI_FN_CPU_SUSPEND)
--MISMATCH_CHECK(PSCI_FN_CPU_OFF, KVM_PSCI_FN_CPU_OFF)
--MISMATCH_CHECK(PSCI_FN_CPU_ON, KVM_PSCI_FN_CPU_ON)
--MISMATCH_CHECK(PSCI_FN_MIGRATE, KVM_PSCI_FN_MIGRATE)
-+#define QEMU_PSCI_0_1_FN_BASE 0x95c1ba5e
-+#define QEMU_PSCI_0_1_FN(n) (QEMU_PSCI_0_1_FN_BASE + (n))
-+#define QEMU_PSCI_0_1_FN_CPU_SUSPEND QEMU_PSCI_0_1_FN(0)
-+#define QEMU_PSCI_0_1_FN_CPU_OFF QEMU_PSCI_0_1_FN(1)
-+#define QEMU_PSCI_0_1_FN_CPU_ON QEMU_PSCI_0_1_FN(2)
-+#define QEMU_PSCI_0_1_FN_MIGRATE QEMU_PSCI_0_1_FN(3)
-+
-+MISMATCH_CHECK(QEMU_PSCI_0_1_FN_CPU_SUSPEND, KVM_PSCI_FN_CPU_SUSPEND)
-+MISMATCH_CHECK(QEMU_PSCI_0_1_FN_CPU_OFF, KVM_PSCI_FN_CPU_OFF)
-+MISMATCH_CHECK(QEMU_PSCI_0_1_FN_CPU_ON, KVM_PSCI_FN_CPU_ON)
-+MISMATCH_CHECK(QEMU_PSCI_0_1_FN_MIGRATE, KVM_PSCI_FN_MIGRATE)
-+
-+#define QEMU_PSCI_0_2_FN_BASE 0x84000000
-+#define QEMU_PSCI_0_2_FN(n) (QEMU_PSCI_0_2_FN_BASE + (n))
-+
-+#define QEMU_PSCI_0_2_64BIT 0x40000000
-+#define QEMU_PSCI_0_2_FN64_BASE \
-+ (QEMU_PSCI_0_2_FN_BASE + QEMU_PSCI_0_2_64BIT)
-+#define QEMU_PSCI_0_2_FN64(n) (QEMU_PSCI_0_2_FN64_BASE + (n))
-+
-+#define QEMU_PSCI_0_2_FN_CPU_SUSPEND QEMU_PSCI_0_2_FN(1)
-+#define QEMU_PSCI_0_2_FN_CPU_OFF QEMU_PSCI_0_2_FN(2)
-+#define QEMU_PSCI_0_2_FN_CPU_ON QEMU_PSCI_0_2_FN(3)
-+#define QEMU_PSCI_0_2_FN_MIGRATE QEMU_PSCI_0_2_FN(5)
-+
-+#define QEMU_PSCI_0_2_FN64_CPU_SUSPEND QEMU_PSCI_0_2_FN64(1)
-+#define QEMU_PSCI_0_2_FN64_CPU_OFF QEMU_PSCI_0_2_FN64(2)
-+#define QEMU_PSCI_0_2_FN64_CPU_ON QEMU_PSCI_0_2_FN64(3)
-+#define QEMU_PSCI_0_2_FN64_MIGRATE QEMU_PSCI_0_2_FN64(5)
-+
-+MISMATCH_CHECK(QEMU_PSCI_0_2_FN_CPU_SUSPEND, PSCI_0_2_FN_CPU_SUSPEND)
-+MISMATCH_CHECK(QEMU_PSCI_0_2_FN_CPU_OFF, PSCI_0_2_FN_CPU_OFF)
-+MISMATCH_CHECK(QEMU_PSCI_0_2_FN_CPU_ON, PSCI_0_2_FN_CPU_ON)
-+MISMATCH_CHECK(QEMU_PSCI_0_2_FN_MIGRATE, PSCI_0_2_FN_MIGRATE)
-+MISMATCH_CHECK(QEMU_PSCI_0_2_FN64_CPU_SUSPEND, PSCI_0_2_FN64_CPU_SUSPEND)
-+MISMATCH_CHECK(QEMU_PSCI_0_2_FN64_CPU_ON, PSCI_0_2_FN64_CPU_ON)
-+MISMATCH_CHECK(QEMU_PSCI_0_2_FN64_MIGRATE, PSCI_0_2_FN64_MIGRATE)
-
- /* Note that KVM uses overlapping values for AArch32 and AArch64
- * target CPU numbers. AArch32 targets:
-diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
-index 33b5025..fc319d5 100644
---- a/target-arm/translate-a64.c
-+++ b/target-arm/translate-a64.c
-@@ -1454,7 +1454,7 @@ static void disas_exc(DisasContext *s, uint32_t insn)
- break;
- }
- /* BRK */
-- gen_exception_insn(s, 0, EXCP_BKPT, syn_aa64_bkpt(imm16));
-+ gen_exception_insn(s, 4, EXCP_BKPT, syn_aa64_bkpt(imm16));
- break;
- case 2:
- if (op2_ll != 0) {
-diff --git a/target-i386/cpu-qom.h b/target-i386/cpu-qom.h
-index 71a1b97..7755466 100644
---- a/target-i386/cpu-qom.h
-+++ b/target-i386/cpu-qom.h
-@@ -92,6 +92,7 @@ typedef struct X86CPU {
- bool enforce_cpuid;
- bool expose_kvm;
- bool migratable;
-+ bool host_features;
-
- /* if true the CPUID code directly forward host cache leaves to the guest */
- bool cache_info_passthrough;
-diff --git a/target-i386/cpu.c b/target-i386/cpu.c
-index 6d008ab..f9fcbca 100644
---- a/target-i386/cpu.c
-+++ b/target-i386/cpu.c
-@@ -1254,6 +1254,9 @@ void x86_cpu_compat_set_features(const char *cpu_model, FeatureWord w,
- }
- }
-
-+static uint32_t x86_cpu_get_supported_feature_word(FeatureWord w,
-+ bool migratable_only);
-+
- #ifdef CONFIG_KVM
-
- static int cpu_x86_fill_model_id(char *str)
-@@ -1310,26 +1313,23 @@ static void host_x86_cpu_class_init(ObjectClass *oc, void *data)
- dc->props = host_x86_cpu_properties;
- }
-
--static uint32_t x86_cpu_get_supported_feature_word(FeatureWord w,
-- bool migratable_only);
--
- static void host_x86_cpu_initfn(Object *obj)
- {
- X86CPU *cpu = X86_CPU(obj);
- CPUX86State *env = &cpu->env;
- KVMState *s = kvm_state;
-- FeatureWord w;
-
- assert(kvm_enabled());
-
-+ /* We can't fill the features array here because we don't know yet if
-+ * "migratable" is true or false.
-+ */
-+ cpu->host_features = true;
-+
- env->cpuid_level = kvm_arch_get_supported_cpuid(s, 0x0, 0, R_EAX);
- env->cpuid_xlevel = kvm_arch_get_supported_cpuid(s, 0x80000000, 0, R_EAX);
- env->cpuid_xlevel2 = kvm_arch_get_supported_cpuid(s, 0xC0000000, 0, R_EAX);
-
-- for (w = 0; w < FEATURE_WORDS; w++) {
-- env->features[w] =
-- x86_cpu_get_supported_feature_word(w, cpu->migratable);
-- }
- object_property_set_bool(OBJECT(cpu), true, "pmu", &error_abort);
- }
-
-@@ -1828,6 +1828,13 @@ static void x86_cpu_parse_featurestr(CPUState *cs, char *features,
- featurestr = strtok(NULL, ",");
- }
-
-+ if (cpu->host_features) {
-+ for (w = 0; w < FEATURE_WORDS; w++) {
-+ env->features[w] =
-+ x86_cpu_get_supported_feature_word(w, cpu->migratable);
-+ }
-+ }
-+
- for (w = 0; w < FEATURE_WORDS; w++) {
- env->features[w] |= plus_features[w];
- env->features[w] &= ~minus_features[w];
-@@ -2588,6 +2595,16 @@ static void x86_cpu_reset(CPUState *s)
-
- env->xcr0 = 1;
-
-+ /*
-+ * SDM 11.11.5 requires:
-+ * - IA32_MTRR_DEF_TYPE MSR.E = 0
-+ * - IA32_MTRR_PHYSMASKn.V = 0
-+ * All other bits are undefined. For simplification, zero it all.
-+ */
-+ env->mtrr_deftype = 0;
-+ memset(env->mtrr_var, 0, sizeof(env->mtrr_var));
-+ memset(env->mtrr_fixed, 0, sizeof(env->mtrr_fixed));
-+
- #if !defined(CONFIG_USER_ONLY)
- /* We hard-wire the BSP to the first CPU. */
- if (s->cpu_index == 0) {
-diff --git a/target-i386/cpu.h b/target-i386/cpu.h
-index e634d83..3460b12 100644
---- a/target-i386/cpu.h
-+++ b/target-i386/cpu.h
-@@ -337,6 +337,8 @@
- #define MSR_MTRRphysBase(reg) (0x200 + 2 * (reg))
- #define MSR_MTRRphysMask(reg) (0x200 + 2 * (reg) + 1)
-
-+#define MSR_MTRRphysIndex(addr) ((((addr) & ~1u) - 0x200) / 2)
-+
- #define MSR_MTRRfix64K_00000 0x250
- #define MSR_MTRRfix16K_80000 0x258
- #define MSR_MTRRfix16K_A0000 0x259
-@@ -930,7 +932,7 @@ typedef struct CPUX86State {
- /* MTRRs */
- uint64_t mtrr_fixed[11];
- uint64_t mtrr_deftype;
-- MTRRVar mtrr_var[8];
-+ MTRRVar mtrr_var[MSR_MTRRcap_VCNT];
-
- /* For KVM */
- uint32_t mp_state;
-diff --git a/target-i386/helper.c b/target-i386/helper.c
-index 47b982b..30cb0d0 100644
---- a/target-i386/helper.c
-+++ b/target-i386/helper.c
-@@ -615,8 +615,8 @@ int x86_cpu_handle_mmu_fault(CPUState *cs, vaddr addr,
- if (!(pdpe & PG_PRESENT_MASK)) {
- goto do_fault;
- }
-- rsvd_mask |= PG_HI_USER_MASK | PG_NX_MASK;
-- if (pdpe & rsvd_mask) {
-+ rsvd_mask |= PG_HI_USER_MASK;
-+ if (pdpe & (rsvd_mask | PG_NX_MASK)) {
- goto do_fault_rsvd;
- }
- ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK;
-diff --git a/target-i386/kvm.c b/target-i386/kvm.c
-index 097fe11..ddedc73 100644
---- a/target-i386/kvm.c
-+++ b/target-i386/kvm.c
-@@ -79,6 +79,7 @@ static int lm_capable_kernel;
- static bool has_msr_hv_hypercall;
- static bool has_msr_hv_vapic;
- static bool has_msr_hv_tsc;
-+static bool has_msr_mtrr;
-
- static bool has_msr_architectural_pmu;
- static uint32_t num_architectural_pmu_counters;
-@@ -739,6 +740,10 @@ int kvm_arch_init_vcpu(CPUState *cs)
- env->kvm_xsave_buf = qemu_memalign(4096, sizeof(struct kvm_xsave));
- }
-
-+ if (env->features[FEAT_1_EDX] & CPUID_MTRR) {
-+ has_msr_mtrr = true;
-+ }
-+
- return 0;
- }
-
-@@ -1183,7 +1188,7 @@ static int kvm_put_msrs(X86CPU *cpu, int level)
- CPUX86State *env = &cpu->env;
- struct {
- struct kvm_msrs info;
-- struct kvm_msr_entry entries[100];
-+ struct kvm_msr_entry entries[150];
- } msr_data;
- struct kvm_msr_entry *msrs = msr_data.entries;
- int n = 0, i;
-@@ -1278,6 +1283,37 @@ static int kvm_put_msrs(X86CPU *cpu, int level)
- kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_REFERENCE_TSC,
- env->msr_hv_tsc);
- }
-+ if (has_msr_mtrr) {
-+ kvm_msr_entry_set(&msrs[n++], MSR_MTRRdefType, env->mtrr_deftype);
-+ kvm_msr_entry_set(&msrs[n++],
-+ MSR_MTRRfix64K_00000, env->mtrr_fixed[0]);
-+ kvm_msr_entry_set(&msrs[n++],
-+ MSR_MTRRfix16K_80000, env->mtrr_fixed[1]);
-+ kvm_msr_entry_set(&msrs[n++],
-+ MSR_MTRRfix16K_A0000, env->mtrr_fixed[2]);
-+ kvm_msr_entry_set(&msrs[n++],
-+ MSR_MTRRfix4K_C0000, env->mtrr_fixed[3]);
-+ kvm_msr_entry_set(&msrs[n++],
-+ MSR_MTRRfix4K_C8000, env->mtrr_fixed[4]);
-+ kvm_msr_entry_set(&msrs[n++],
-+ MSR_MTRRfix4K_D0000, env->mtrr_fixed[5]);
-+ kvm_msr_entry_set(&msrs[n++],
-+ MSR_MTRRfix4K_D8000, env->mtrr_fixed[6]);
-+ kvm_msr_entry_set(&msrs[n++],
-+ MSR_MTRRfix4K_E0000, env->mtrr_fixed[7]);
-+ kvm_msr_entry_set(&msrs[n++],
-+ MSR_MTRRfix4K_E8000, env->mtrr_fixed[8]);
-+ kvm_msr_entry_set(&msrs[n++],
-+ MSR_MTRRfix4K_F0000, env->mtrr_fixed[9]);
-+ kvm_msr_entry_set(&msrs[n++],
-+ MSR_MTRRfix4K_F8000, env->mtrr_fixed[10]);
-+ for (i = 0; i < MSR_MTRRcap_VCNT; i++) {
-+ kvm_msr_entry_set(&msrs[n++],
-+ MSR_MTRRphysBase(i), env->mtrr_var[i].base);
-+ kvm_msr_entry_set(&msrs[n++],
-+ MSR_MTRRphysMask(i), env->mtrr_var[i].mask);
-+ }
-+ }
-
- /* Note: MSR_IA32_FEATURE_CONTROL is written separately, see
- * kvm_put_msr_feature_control. */
-@@ -1484,7 +1520,7 @@ static int kvm_get_msrs(X86CPU *cpu)
- CPUX86State *env = &cpu->env;
- struct {
- struct kvm_msrs info;
-- struct kvm_msr_entry entries[100];
-+ struct kvm_msr_entry entries[150];
- } msr_data;
- struct kvm_msr_entry *msrs = msr_data.entries;
- int ret, i, n;
-@@ -1572,6 +1608,24 @@ static int kvm_get_msrs(X86CPU *cpu)
- if (has_msr_hv_tsc) {
- msrs[n++].index = HV_X64_MSR_REFERENCE_TSC;
- }
-+ if (has_msr_mtrr) {
-+ msrs[n++].index = MSR_MTRRdefType;
-+ msrs[n++].index = MSR_MTRRfix64K_00000;
-+ msrs[n++].index = MSR_MTRRfix16K_80000;
-+ msrs[n++].index = MSR_MTRRfix16K_A0000;
-+ msrs[n++].index = MSR_MTRRfix4K_C0000;
-+ msrs[n++].index = MSR_MTRRfix4K_C8000;
-+ msrs[n++].index = MSR_MTRRfix4K_D0000;
-+ msrs[n++].index = MSR_MTRRfix4K_D8000;
-+ msrs[n++].index = MSR_MTRRfix4K_E0000;
-+ msrs[n++].index = MSR_MTRRfix4K_E8000;
-+ msrs[n++].index = MSR_MTRRfix4K_F0000;
-+ msrs[n++].index = MSR_MTRRfix4K_F8000;
-+ for (i = 0; i < MSR_MTRRcap_VCNT; i++) {
-+ msrs[n++].index = MSR_MTRRphysBase(i);
-+ msrs[n++].index = MSR_MTRRphysMask(i);
-+ }
-+ }
-
- msr_data.info.nmsrs = n;
- ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_MSRS, &msr_data);
-@@ -1692,6 +1746,49 @@ static int kvm_get_msrs(X86CPU *cpu)
- case HV_X64_MSR_REFERENCE_TSC:
- env->msr_hv_tsc = msrs[i].data;
- break;
-+ case MSR_MTRRdefType:
-+ env->mtrr_deftype = msrs[i].data;
-+ break;
-+ case MSR_MTRRfix64K_00000:
-+ env->mtrr_fixed[0] = msrs[i].data;
-+ break;
-+ case MSR_MTRRfix16K_80000:
-+ env->mtrr_fixed[1] = msrs[i].data;
-+ break;
-+ case MSR_MTRRfix16K_A0000:
-+ env->mtrr_fixed[2] = msrs[i].data;
-+ break;
-+ case MSR_MTRRfix4K_C0000:
-+ env->mtrr_fixed[3] = msrs[i].data;
-+ break;
-+ case MSR_MTRRfix4K_C8000:
-+ env->mtrr_fixed[4] = msrs[i].data;
-+ break;
-+ case MSR_MTRRfix4K_D0000:
-+ env->mtrr_fixed[5] = msrs[i].data;
-+ break;
-+ case MSR_MTRRfix4K_D8000:
-+ env->mtrr_fixed[6] = msrs[i].data;
-+ break;
-+ case MSR_MTRRfix4K_E0000:
-+ env->mtrr_fixed[7] = msrs[i].data;
-+ break;
-+ case MSR_MTRRfix4K_E8000:
-+ env->mtrr_fixed[8] = msrs[i].data;
-+ break;
-+ case MSR_MTRRfix4K_F0000:
-+ env->mtrr_fixed[9] = msrs[i].data;
-+ break;
-+ case MSR_MTRRfix4K_F8000:
-+ env->mtrr_fixed[10] = msrs[i].data;
-+ break;
-+ case MSR_MTRRphysBase(0) ... MSR_MTRRphysMask(MSR_MTRRcap_VCNT - 1):
-+ if (index & 1) {
-+ env->mtrr_var[MSR_MTRRphysIndex(index)].mask = msrs[i].data;
-+ } else {
-+ env->mtrr_var[MSR_MTRRphysIndex(index)].base = msrs[i].data;
-+ }
-+ break;
- }
- }
-
-diff --git a/target-i386/machine.c b/target-i386/machine.c
-index 16d2f6a..fb89065 100644
---- a/target-i386/machine.c
-+++ b/target-i386/machine.c
-@@ -677,7 +677,7 @@ VMStateDescription vmstate_x86_cpu = {
- /* MTRRs */
- VMSTATE_UINT64_ARRAY_V(env.mtrr_fixed, X86CPU, 11, 8),
- VMSTATE_UINT64_V(env.mtrr_deftype, X86CPU, 8),
-- VMSTATE_MTRR_VARS(env.mtrr_var, X86CPU, 8, 8),
-+ VMSTATE_MTRR_VARS(env.mtrr_var, X86CPU, MSR_MTRRcap_VCNT, 8),
- /* KVM-related states */
- VMSTATE_INT32_V(env.interrupt_injected, X86CPU, 9),
- VMSTATE_UINT32_V(env.mp_state, X86CPU, 9),
-diff --git a/tests/qemu-iotests/101 b/tests/qemu-iotests/101
-new file mode 100755
-index 0000000..70fbf25
---- /dev/null
-+++ b/tests/qemu-iotests/101
-@@ -0,0 +1,58 @@
-+#!/bin/bash
-+#
-+# Test short file I/O
-+#
-+# Copyright (C) 2014 Red Hat, Inc.
-+#
-+# This program is free software; you can redistribute it and/or modify
-+# it under the terms of the GNU General Public License as published by
-+# the Free Software Foundation; either version 2 of the License, or
-+# (at your option) any later version.
-+#
-+# This program is distributed in the hope that it will be useful,
-+# but WITHOUT ANY WARRANTY; without even the implied warranty of
-+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+# GNU General Public License for more details.
-+#
-+# You should have received a copy of the GNU General Public License
-+# along with this program. If not, see <http://www.gnu.org/licenses/>.
-+#
-+
-+# creator
-+owner=stefanha@redhat.com
-+
-+seq=`basename $0`
-+echo "QA output created by $seq"
-+
-+here=`pwd`
-+tmp=/tmp/$$
-+status=1 # failure is the default!
-+
-+_cleanup()
-+{
-+ _cleanup_test_img
-+}
-+trap "_cleanup; exit \$status" 0 1 2 3 15
-+
-+# get standard environment, filters and checks
-+. ./common.rc
-+. ./common.filter
-+
-+_supported_fmt raw
-+_supported_proto file
-+_supported_os Linux
-+
-+
-+echo
-+echo "== creating short image file =="
-+dd if=/dev/zero of="$TEST_IMG" bs=1 count=320
-+
-+echo
-+echo "== reading bytes beyond EOF gives zeroes =="
-+$QEMU_IO -c "read -P 0 0 512" "$TEST_IMG" | _filter_qemu_io
-+
-+
-+# success, all done
-+echo "*** done"
-+rm -f $seq.full
-+status=0
-diff --git a/tests/qemu-iotests/101.out b/tests/qemu-iotests/101.out
-new file mode 100644
-index 0000000..9a996e8
---- /dev/null
-+++ b/tests/qemu-iotests/101.out
-@@ -0,0 +1,10 @@
-+QA output created by 101
-+
-+== creating short image file ==
-+320+0 records in
-+320+0 records out
-+
-+== reading bytes beyond EOF gives zeroes ==
-+read 512/512 bytes at offset 0
-+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-+*** done
-diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
-index 6e67f61..e25e992 100644
---- a/tests/qemu-iotests/group
-+++ b/tests/qemu-iotests/group
-@@ -100,3 +100,4 @@
- 091 rw auto quick
- 092 rw auto quick
- 095 rw auto quick
-+101 rw auto quick
-diff --git a/thread-pool.c b/thread-pool.c
-index dfb699d..23888dc 100644
---- a/thread-pool.c
-+++ b/thread-pool.c
-@@ -21,7 +21,6 @@
- #include "block/coroutine.h"
- #include "trace.h"
- #include "block/block_int.h"
--#include "qemu/event_notifier.h"
- #include "block/thread-pool.h"
- #include "qemu/main-loop.h"
-
-@@ -57,8 +56,8 @@ struct ThreadPoolElement {
- };
-
- struct ThreadPool {
-- EventNotifier notifier;
- AioContext *ctx;
-+ QEMUBH *completion_bh;
- QemuMutex lock;
- QemuCond check_cancel;
- QemuCond worker_stopped;
-@@ -119,7 +118,7 @@ static void *worker_thread(void *opaque)
- qemu_cond_broadcast(&pool->check_cancel);
- }
-
-- event_notifier_set(&pool->notifier);
-+ qemu_bh_schedule(pool->completion_bh);
- }
-
- pool->cur_threads--;
-@@ -168,12 +167,11 @@ static void spawn_thread(ThreadPool *pool)
- }
- }
-
--static void event_notifier_ready(EventNotifier *notifier)
-+static void thread_pool_completion_bh(void *opaque)
- {
-- ThreadPool *pool = container_of(notifier, ThreadPool, notifier);
-+ ThreadPool *pool = opaque;
- ThreadPoolElement *elem, *next;
-
-- event_notifier_test_and_clear(notifier);
- restart:
- QLIST_FOREACH_SAFE(elem, &pool->head, all, next) {
- if (elem->state != THREAD_CANCELED && elem->state != THREAD_DONE) {
-@@ -187,6 +185,12 @@ restart:
- QLIST_REMOVE(elem, all);
- /* Read state before ret. */
- smp_rmb();
-+
-+ /* Schedule ourselves in case elem->common.cb() calls aio_poll() to
-+ * wait for another request that completed at the same time.
-+ */
-+ qemu_bh_schedule(pool->completion_bh);
-+
- elem->common.cb(elem->common.opaque, elem->ret);
- qemu_aio_release(elem);
- goto restart;
-@@ -215,7 +219,7 @@ static void thread_pool_cancel(BlockDriverAIOCB *acb)
- qemu_sem_timedwait(&pool->sem, 0) == 0) {
- QTAILQ_REMOVE(&pool->request_list, elem, reqs);
- elem->state = THREAD_CANCELED;
-- event_notifier_set(&pool->notifier);
-+ qemu_bh_schedule(pool->completion_bh);
- } else {
- pool->pending_cancellations++;
- while (elem->state != THREAD_CANCELED && elem->state != THREAD_DONE) {
-@@ -224,7 +228,7 @@ static void thread_pool_cancel(BlockDriverAIOCB *acb)
- pool->pending_cancellations--;
- }
- qemu_mutex_unlock(&pool->lock);
-- event_notifier_ready(&pool->notifier);
-+ thread_pool_completion_bh(pool);
- }
-
- static const AIOCBInfo thread_pool_aiocb_info = {
-@@ -293,8 +297,8 @@ static void thread_pool_init_one(ThreadPool *pool, AioContext *ctx)
- }
-
- memset(pool, 0, sizeof(*pool));
-- event_notifier_init(&pool->notifier, false);
- pool->ctx = ctx;
-+ pool->completion_bh = aio_bh_new(ctx, thread_pool_completion_bh, pool);
- qemu_mutex_init(&pool->lock);
- qemu_cond_init(&pool->check_cancel);
- qemu_cond_init(&pool->worker_stopped);
-@@ -304,8 +308,6 @@ static void thread_pool_init_one(ThreadPool *pool, AioContext *ctx)
-
- QLIST_INIT(&pool->head);
- QTAILQ_INIT(&pool->request_list);
--
-- aio_set_event_notifier(ctx, &pool->notifier, event_notifier_ready);
- }
-
- ThreadPool *thread_pool_new(AioContext *ctx)
-@@ -339,11 +341,10 @@ void thread_pool_free(ThreadPool *pool)
-
- qemu_mutex_unlock(&pool->lock);
-
-- aio_set_event_notifier(pool->ctx, &pool->notifier, NULL);
-+ qemu_bh_delete(pool->completion_bh);
- qemu_sem_destroy(&pool->sem);
- qemu_cond_destroy(&pool->check_cancel);
- qemu_cond_destroy(&pool->worker_stopped);
- qemu_mutex_destroy(&pool->lock);
-- event_notifier_cleanup(&pool->notifier);
- g_free(pool);
- }
-diff --git a/ui/spice-display.c b/ui/spice-display.c
-index 66e2578..def7b52 100644
---- a/ui/spice-display.c
-+++ b/ui/spice-display.c
-@@ -334,11 +334,23 @@ void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd)
- void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd)
- {
- QXLDevSurfaceCreate surface;
-+ uint64_t surface_size;
-
- memset(&surface, 0, sizeof(surface));
-
-- dprint(1, "%s/%d: %dx%d\n", __func__, ssd->qxl.id,
-- surface_width(ssd->ds), surface_height(ssd->ds));
-+ surface_size = (uint64_t) surface_width(ssd->ds) *
-+ surface_height(ssd->ds) * 4;
-+ assert(surface_size > 0);
-+ assert(surface_size < INT_MAX);
-+ if (ssd->bufsize < surface_size) {
-+ ssd->bufsize = surface_size;
-+ g_free(ssd->buf);
-+ ssd->buf = g_malloc(ssd->bufsize);
-+ }
-+
-+ dprint(1, "%s/%d: %ux%u (size %" PRIu64 "/%d)\n", __func__, ssd->qxl.id,
-+ surface_width(ssd->ds), surface_height(ssd->ds),
-+ surface_size, ssd->bufsize);
-
- surface.format = SPICE_SURFACE_FMT_32_xRGB;
- surface.width = surface_width(ssd->ds);
-@@ -369,8 +381,6 @@ void qemu_spice_display_init_common(SimpleSpiceDisplay *ssd)
- if (ssd->num_surfaces == 0) {
- ssd->num_surfaces = 1024;
- }
-- ssd->bufsize = (16 * 1024 * 1024);
-- ssd->buf = g_malloc(ssd->bufsize);
- }
-
- /* display listener callbacks */
-@@ -495,7 +505,7 @@ static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info)
- info->num_memslots = NUM_MEMSLOTS;
- info->num_memslots_groups = NUM_MEMSLOTS_GROUPS;
- info->internal_groupslot_id = 0;
-- info->qxl_ram_size = ssd->bufsize;
-+ info->qxl_ram_size = 16 * 1024 * 1024;
- info->n_surfaces = ssd->num_surfaces;
- }
-
-diff --git a/vl.c b/vl.c
-index fe451aa..7f8bd39 100644
---- a/vl.c
-+++ b/vl.c
-@@ -4009,11 +4009,6 @@ int main(int argc, char **argv, char **envp)
- qemu_set_version(machine_class->hw_version);
- }
-
-- if (qemu_opts_foreach(qemu_find_opts("object"),
-- object_create, NULL, 0) != 0) {
-- exit(1);
-- }
--
- /* Init CPU def lists, based on config
- * - Must be called after all the qemu_read_config_file() calls
- * - Must be called before list_cpus()
-@@ -4225,6 +4220,11 @@ int main(int argc, char **argv, char **envp)
- exit(0);
- }
-
-+ if (qemu_opts_foreach(qemu_find_opts("object"),
-+ object_create, NULL, 0) != 0) {
-+ exit(1);
-+ }
-+
- machine_opts = qemu_get_machine_opts();
- if (qemu_opt_foreach(machine_opts, object_set_property, current_machine,
- 1) < 0) {
diff -Nru qemu-2.1+dfsg/debian/patches/v2.1.3.diff qemu-2.1+dfsg/debian/patches/v2.1.3.diff
--- qemu-2.1+dfsg/debian/patches/v2.1.3.diff 1970-01-01 03:00:00.000000000 +0300
+++ qemu-2.1+dfsg/debian/patches/v2.1.3.diff 2015-09-14 17:40:58.000000000 +0300
@@ -0,0 +1,5900 @@
+diff --git a/VERSION b/VERSION
+index 7ec1d6d..ac2cdeb 100644
+--- a/VERSION
++++ b/VERSION
+@@ -1 +1 @@
+-2.1.0
++2.1.3
+diff --git a/audio/audio_template.h b/audio/audio_template.h
+index 8173188..584e536 100644
+--- a/audio/audio_template.h
++++ b/audio/audio_template.h
+@@ -191,9 +191,9 @@ static void glue (audio_pcm_hw_gc_, TYPE) (HW **hwp)
+ audio_detach_capture (hw);
+ #endif
+ QLIST_REMOVE (hw, entries);
++ glue (hw->pcm_ops->fini_, TYPE) (hw);
+ glue (s->nb_hw_voices_, TYPE) += 1;
+ glue (audio_pcm_hw_free_resources_ ,TYPE) (hw);
+- glue (hw->pcm_ops->fini_, TYPE) (hw);
+ g_free (hw);
+ *hwp = NULL;
+ }
+diff --git a/backends/hostmem.c b/backends/hostmem.c
+index ca10c51..a9905c0 100644
+--- a/backends/hostmem.c
++++ b/backends/hostmem.c
+@@ -304,7 +304,7 @@ host_memory_backend_memory_complete(UserCreatable *uc, Error **errp)
+ /* ensure policy won't be ignored in case memory is preallocated
+ * before mbind(). note: MPOL_MF_STRICT is ignored on hugepages so
+ * this doesn't catch hugepage case. */
+- unsigned flags = MPOL_MF_STRICT;
++ unsigned flags = MPOL_MF_STRICT | MPOL_MF_MOVE;
+
+ /* check for invalid host-nodes and policies and give more verbose
+ * error messages than mbind(). */
+diff --git a/backends/rng-egd.c b/backends/rng-egd.c
+index 25bb3b4..2962795 100644
+--- a/backends/rng-egd.c
++++ b/backends/rng-egd.c
+@@ -169,6 +169,7 @@ static void rng_egd_set_chardev(Object *obj, const char *value, Error **errp)
+ if (b->opened) {
+ error_set(errp, QERR_PERMISSION_DENIED);
+ } else {
++ g_free(s->chr_name);
+ s->chr_name = g_strdup(value);
+ }
+ }
+diff --git a/block-migration.c b/block-migration.c
+index 73cdd07..36403ee 100644
+--- a/block-migration.c
++++ b/block-migration.c
+@@ -652,6 +652,7 @@ static int block_save_iterate(QEMUFile *f, void *opaque)
+ {
+ int ret;
+ int64_t last_ftell = qemu_ftell(f);
++ int64_t delta_ftell;
+
+ DPRINTF("Enter save live iterate submitted %d transferred %d\n",
+ block_mig_state.submitted, block_mig_state.transferred);
+@@ -701,7 +702,14 @@ static int block_save_iterate(QEMUFile *f, void *opaque)
+ }
+
+ qemu_put_be64(f, BLK_MIG_FLAG_EOS);
+- return qemu_ftell(f) - last_ftell;
++ delta_ftell = qemu_ftell(f) - last_ftell;
++ if (delta_ftell > 0) {
++ return 1;
++ } else if (delta_ftell < 0) {
++ return -1;
++ } else {
++ return 0;
++ }
+ }
+
+ /* Called with iothread lock taken. */
+@@ -756,8 +764,8 @@ static uint64_t block_save_pending(QEMUFile *f, void *opaque, uint64_t max_size)
+ block_mig_state.read_done * BLOCK_SIZE;
+
+ /* Report at least one block pending during bulk phase */
+- if (pending == 0 && !block_mig_state.bulk_completed) {
+- pending = BLOCK_SIZE;
++ if (pending <= max_size && !block_mig_state.bulk_completed) {
++ pending = max_size + BLOCK_SIZE;
+ }
+ blk_mig_unlock();
+ qemu_mutex_unlock_iothread();
+diff --git a/block.c b/block.c
+index 8cf519b..ed87b7e 100644
+--- a/block.c
++++ b/block.c
+@@ -633,7 +633,7 @@ BlockDriver *bdrv_find_protocol(const char *filename,
+ }
+
+ if (!path_has_protocol(filename) || !allow_protocol_prefix) {
+- return bdrv_find_format("file");
++ return &bdrv_file;
+ }
+
+ p = strchr(filename, ':');
+@@ -662,12 +662,7 @@ static int find_image_format(BlockDriverState *bs, const char *filename,
+
+ /* Return the raw BlockDriver * to scsi-generic devices or empty drives */
+ if (bs->sg || !bdrv_is_inserted(bs) || bdrv_getlength(bs) == 0) {
+- drv = bdrv_find_format("raw");
+- if (!drv) {
+- error_setg(errp, "Could not find raw image format");
+- ret = -ENOENT;
+- }
+- *pdrv = drv;
++ *pdrv = &bdrv_raw;
+ return ret;
+ }
+
+@@ -1182,7 +1177,6 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
+ {
+ char *backing_filename = g_malloc0(PATH_MAX);
+ int ret = 0;
+- BlockDriver *back_drv = NULL;
+ BlockDriverState *backing_hd;
+ Error *local_err = NULL;
+
+@@ -1215,14 +1209,14 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
+
+ backing_hd = bdrv_new("", errp);
+
+- if (bs->backing_format[0] != '\0') {
+- back_drv = bdrv_find_format(bs->backing_format);
++ if (bs->backing_format[0] != '\0' && !qdict_haskey(options, "driver")) {
++ qdict_put(options, "driver", qstring_from_str(bs->backing_format));
+ }
+
+ assert(bs->backing_hd == NULL);
+ ret = bdrv_open(&backing_hd,
+ *backing_filename ? backing_filename : NULL, NULL, options,
+- bdrv_backing_flags(bs->open_flags), back_drv, &local_err);
++ bdrv_backing_flags(bs->open_flags), NULL, &local_err);
+ if (ret < 0) {
+ bdrv_unref(backing_hd);
+ backing_hd = NULL;
+@@ -1296,7 +1290,6 @@ int bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp)
+ /* TODO: extra byte is a hack to ensure MAX_PATH space on Windows. */
+ char *tmp_filename = g_malloc0(PATH_MAX + 1);
+ int64_t total_size;
+- BlockDriver *bdrv_qcow2;
+ QemuOpts *opts = NULL;
+ QDict *snapshot_options;
+ BlockDriverState *bs_snapshot;
+@@ -1322,11 +1315,10 @@ int bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp)
+ goto out;
+ }
+
+- bdrv_qcow2 = bdrv_find_format("qcow2");
+- opts = qemu_opts_create(bdrv_qcow2->create_opts, NULL, 0,
++ opts = qemu_opts_create(bdrv_qcow2.create_opts, NULL, 0,
+ &error_abort);
+ qemu_opt_set_number(opts, BLOCK_OPT_SIZE, total_size);
+- ret = bdrv_create(bdrv_qcow2, tmp_filename, opts, &local_err);
++ ret = bdrv_create(&bdrv_qcow2, tmp_filename, opts, &local_err);
+ qemu_opts_del(opts);
+ if (ret < 0) {
+ error_setg_errno(errp, -ret, "Could not create temporary overlay "
+@@ -1346,7 +1338,7 @@ int bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp)
+ bs_snapshot = bdrv_new("", &error_abort);
+
+ ret = bdrv_open(&bs_snapshot, NULL, NULL, snapshot_options,
+- flags, bdrv_qcow2, &local_err);
++ flags, &bdrv_qcow2, &local_err);
+ if (ret < 0) {
+ error_propagate(errp, local_err);
+ goto out;
+@@ -5535,6 +5527,18 @@ void bdrv_img_create(const char *filename, const char *fmt,
+ return;
+ }
+
++ if (!drv->create_opts) {
++ error_setg(errp, "Format driver '%s' does not support image creation",
++ drv->format_name);
++ return;
++ }
++
++ if (!proto_drv->create_opts) {
++ error_setg(errp, "Protocol driver '%s' does not support image creation",
++ proto_drv->format_name);
++ return;
++ }
++
+ create_opts = qemu_opts_append(create_opts, drv->create_opts);
+ create_opts = qemu_opts_append(create_opts, proto_drv->create_opts);
+
+diff --git a/block/blkdebug.c b/block/blkdebug.c
+index f51407d..dac7666 100644
+--- a/block/blkdebug.c
++++ b/block/blkdebug.c
+@@ -449,6 +449,10 @@ static void error_callback_bh(void *opaque)
+ static void blkdebug_aio_cancel(BlockDriverAIOCB *blockacb)
+ {
+ BlkdebugAIOCB *acb = container_of(blockacb, BlkdebugAIOCB, common);
++ if (acb->bh) {
++ qemu_bh_delete(acb->bh);
++ acb->bh = NULL;
++ }
+ qemu_aio_release(acb);
+ }
+
+@@ -522,6 +526,25 @@ static BlockDriverAIOCB *blkdebug_aio_writev(BlockDriverState *bs,
+ return bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
+ }
+
++static BlockDriverAIOCB *blkdebug_aio_flush(BlockDriverState *bs,
++ BlockDriverCompletionFunc *cb, void *opaque)
++{
++ BDRVBlkdebugState *s = bs->opaque;
++ BlkdebugRule *rule = NULL;
++
++ QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) {
++ if (rule->options.inject.sector == -1) {
++ break;
++ }
++ }
++
++ if (rule && rule->options.inject.error) {
++ return inject_error(bs, cb, opaque, rule);
++ }
++
++ return bdrv_aio_flush(bs->file, cb, opaque);
++}
++
+
+ static void blkdebug_close(BlockDriverState *bs)
+ {
+@@ -699,6 +722,7 @@ static BlockDriver bdrv_blkdebug = {
+
+ .bdrv_aio_readv = blkdebug_aio_readv,
+ .bdrv_aio_writev = blkdebug_aio_writev,
++ .bdrv_aio_flush = blkdebug_aio_flush,
+
+ .bdrv_debug_event = blkdebug_debug_event,
+ .bdrv_debug_breakpoint = blkdebug_debug_breakpoint,
+diff --git a/block/iscsi.c b/block/iscsi.c
+index a7bb697..ed883c3 100644
+--- a/block/iscsi.c
++++ b/block/iscsi.c
+@@ -1509,7 +1509,8 @@ static int iscsi_truncate(BlockDriverState *bs, int64_t offset)
+ if (iscsilun->allocationmap != NULL) {
+ g_free(iscsilun->allocationmap);
+ iscsilun->allocationmap =
+- bitmap_new(DIV_ROUND_UP(bs->total_sectors,
++ bitmap_new(DIV_ROUND_UP(sector_lun2qemu(iscsilun->num_blocks,
++ iscsilun),
+ iscsilun->cluster_sectors));
+ }
+
+diff --git a/block/nfs.c b/block/nfs.c
+index 8439e0d..1bb05ad 100644
+--- a/block/nfs.c
++++ b/block/nfs.c
+@@ -401,6 +401,19 @@ static int nfs_file_open(BlockDriverState *bs, QDict *options, int flags,
+ return 0;
+ }
+
++static QemuOptsList nfs_create_opts = {
++ .name = "nfs-create-opts",
++ .head = QTAILQ_HEAD_INITIALIZER(nfs_create_opts.head),
++ .desc = {
++ {
++ .name = BLOCK_OPT_SIZE,
++ .type = QEMU_OPT_SIZE,
++ .help = "Virtual disk size"
++ },
++ { /* end of list */ }
++ }
++};
++
+ static int nfs_file_create(const char *url, QemuOpts *opts, Error **errp)
+ {
+ int ret = 0;
+@@ -461,6 +474,8 @@ static BlockDriver bdrv_nfs = {
+
+ .instance_size = sizeof(NFSClient),
+ .bdrv_needs_filename = true,
++ .create_opts = &nfs_create_opts,
++
+ .bdrv_has_zero_init = nfs_has_zero_init,
+ .bdrv_get_allocated_file_size = nfs_get_allocated_file_size,
+ .bdrv_truncate = nfs_file_truncate,
+diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
+index 4208dc0..769e68d 100644
+--- a/block/qcow2-cluster.c
++++ b/block/qcow2-cluster.c
+@@ -158,12 +158,14 @@ static int l2_load(BlockDriverState *bs, uint64_t l2_offset,
+ int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index)
+ {
+ BDRVQcowState *s = bs->opaque;
+- uint64_t buf[L1_ENTRIES_PER_SECTOR];
++ uint64_t buf[L1_ENTRIES_PER_SECTOR] = { 0 };
+ int l1_start_index;
+ int i, ret;
+
+ l1_start_index = l1_index & ~(L1_ENTRIES_PER_SECTOR - 1);
+- for (i = 0; i < L1_ENTRIES_PER_SECTOR; i++) {
++ for (i = 0; i < L1_ENTRIES_PER_SECTOR && l1_start_index + i < s->l1_size;
++ i++)
++ {
+ buf[i] = cpu_to_be64(s->l1_table[l1_start_index + i]);
+ }
+
+@@ -1200,7 +1202,7 @@ int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
+
+ again:
+ start = offset;
+- remaining = *num << BDRV_SECTOR_BITS;
++ remaining = (uint64_t)*num << BDRV_SECTOR_BITS;
+ cluster_offset = 0;
+ *host_offset = 0;
+ cur_bytes = 0;
+diff --git a/block/qcow2.c b/block/qcow2.c
+index 1e3ab6b..ea6d3f2 100644
+--- a/block/qcow2.c
++++ b/block/qcow2.c
+@@ -114,7 +114,7 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
+ #ifdef DEBUG_EXT
+ printf("ext.magic = 0x%x\n", ext.magic);
+ #endif
+- if (ext.len > end_offset - offset) {
++ if (offset > end_offset || ext.len > end_offset - offset) {
+ error_setg(errp, "Header extension too large");
+ return -EINVAL;
+ }
+@@ -1275,10 +1275,23 @@ static void qcow2_close(BlockDriverState *bs)
+ s->l1_table = NULL;
+
+ if (!(bs->open_flags & BDRV_O_INCOMING)) {
+- qcow2_cache_flush(bs, s->l2_table_cache);
+- qcow2_cache_flush(bs, s->refcount_block_cache);
++ int ret1, ret2;
+
+- qcow2_mark_clean(bs);
++ ret1 = qcow2_cache_flush(bs, s->l2_table_cache);
++ ret2 = qcow2_cache_flush(bs, s->refcount_block_cache);
++
++ if (ret1) {
++ error_report("Failed to flush the L2 table cache: %s",
++ strerror(-ret1));
++ }
++ if (ret2) {
++ error_report("Failed to flush the refcount block cache: %s",
++ strerror(-ret2));
++ }
++
++ if (!ret1 && !ret2) {
++ qcow2_mark_clean(bs);
++ }
+ }
+
+ qcow2_cache_destroy(bs, s->l2_table_cache);
+@@ -1712,10 +1725,9 @@ static int qcow2_create2(const char *filename, int64_t total_size,
+ * refcount of the cluster that is occupied by the header and the refcount
+ * table)
+ */
+- BlockDriver* drv = bdrv_find_format("qcow2");
+- assert(drv != NULL);
+ ret = bdrv_open(&bs, filename, NULL, NULL,
+- BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH, drv, &local_err);
++ BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH,
++ &bdrv_qcow2, &local_err);
+ if (ret < 0) {
+ error_propagate(errp, local_err);
+ goto out;
+@@ -1767,7 +1779,7 @@ static int qcow2_create2(const char *filename, int64_t total_size,
+ /* Reopen the image without BDRV_O_NO_FLUSH to flush it before returning */
+ ret = bdrv_open(&bs, filename, NULL, NULL,
+ BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_BACKING,
+- drv, &local_err);
++ &bdrv_qcow2, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ goto out;
+@@ -1948,8 +1960,7 @@ static int qcow2_write_compressed(BlockDriverState *bs, int64_t sector_num,
+ sector based I/Os */
+ cluster_offset = bdrv_getlength(bs->file);
+ cluster_offset = (cluster_offset + 511) & ~511;
+- bdrv_truncate(bs->file, cluster_offset);
+- return 0;
++ return bdrv_truncate(bs->file, cluster_offset);
+ }
+
+ if (nb_sectors != s->cluster_sectors) {
+@@ -2404,7 +2415,7 @@ static QemuOptsList qcow2_create_opts = {
+ }
+ };
+
+-static BlockDriver bdrv_qcow2 = {
++BlockDriver bdrv_qcow2 = {
+ .format_name = "qcow2",
+ .instance_size = sizeof(BDRVQcowState),
+ .bdrv_probe = qcow2_probe,
+diff --git a/block/raw-posix.c b/block/raw-posix.c
+index 8e9758e..efa5686 100644
+--- a/block/raw-posix.c
++++ b/block/raw-posix.c
+@@ -447,6 +447,7 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
+ s->has_write_zeroes = true;
+
+ if (fstat(s->fd, &st) < 0) {
++ ret = -errno;
+ error_setg_errno(errp, errno, "Could not stat file");
+ goto fail;
+ }
+@@ -747,6 +748,15 @@ static ssize_t handle_aiocb_rw_linear(RawPosixAIOData *aiocb, char *buf)
+ }
+ if (len == -1 && errno == EINTR) {
+ continue;
++ } else if (len == -1 && errno == EINVAL &&
++ (aiocb->bs->open_flags & BDRV_O_NOCACHE) &&
++ !(aiocb->aio_type & QEMU_AIO_WRITE) &&
++ offset > 0) {
++ /* O_DIRECT pread() may fail with EINVAL when offset is unaligned
++ * after a short read. Assume that O_DIRECT short reads only occur
++ * at EOF. Therefore this is a short read, not an I/O error.
++ */
++ break;
+ } else if (len == -1) {
+ offset = -errno;
+ break;
+@@ -1576,7 +1586,7 @@ static QemuOptsList raw_create_opts = {
+ }
+ };
+
+-static BlockDriver bdrv_file = {
++BlockDriver bdrv_file = {
+ .format_name = "file",
+ .protocol_name = "file",
+ .instance_size = sizeof(BDRVRawState),
+diff --git a/block/raw-win32.c b/block/raw-win32.c
+index 902eab6..0f24dd8 100644
+--- a/block/raw-win32.c
++++ b/block/raw-win32.c
+@@ -540,7 +540,7 @@ static QemuOptsList raw_create_opts = {
+ }
+ };
+
+-static BlockDriver bdrv_file = {
++BlockDriver bdrv_file = {
+ .format_name = "file",
+ .protocol_name = "file",
+ .instance_size = sizeof(BDRVRawState),
+diff --git a/block/raw_bsd.c b/block/raw_bsd.c
+index f82f4c2..431af8f 100644
+--- a/block/raw_bsd.c
++++ b/block/raw_bsd.c
+@@ -173,7 +173,7 @@ static int raw_probe(const uint8_t *buf, int buf_size, const char *filename)
+ return 1;
+ }
+
+-static BlockDriver bdrv_raw = {
++BlockDriver bdrv_raw = {
+ .format_name = "raw",
+ .bdrv_probe = &raw_probe,
+ .bdrv_reopen_prepare = &raw_reopen_prepare,
+diff --git a/block/snapshot.c b/block/snapshot.c
+index 85c52ff..698e1a1 100644
+--- a/block/snapshot.c
++++ b/block/snapshot.c
+@@ -236,6 +236,10 @@ int bdrv_snapshot_delete(BlockDriverState *bs,
+ error_setg(errp, "snapshot_id and name are both NULL");
+ return -EINVAL;
+ }
++
++ /* drain all pending i/o before deleting snapshot */
++ bdrv_drain_all();
++
+ if (drv->bdrv_snapshot_delete) {
+ return drv->bdrv_snapshot_delete(bs, snapshot_id, name, errp);
+ }
+diff --git a/block/vvfat.c b/block/vvfat.c
+index 70176b1..1de8808 100644
+--- a/block/vvfat.c
++++ b/block/vvfat.c
+@@ -2926,6 +2926,12 @@ static int enable_write_target(BDRVVVFATState *s, Error **errp)
+ }
+
+ bdrv_qcow = bdrv_find_format("qcow");
++ if (!bdrv_qcow) {
++ error_setg(errp, "Failed to locate qcow driver");
++ ret = -ENOENT;
++ goto err;
++ }
++
+ opts = qemu_opts_create(bdrv_qcow->create_opts, NULL, 0, &error_abort);
+ qemu_opt_set_number(opts, BLOCK_OPT_SIZE, s->sector_count * 512);
+ qemu_opt_set(opts, BLOCK_OPT_BACKING_FILE, "fat:");
+diff --git a/configure b/configure
+index f7685b5..f49e618 100755
+--- a/configure
++++ b/configure
+@@ -1723,6 +1723,7 @@ fi
+
+ cat > $TMPC <<EOF
+ #include <sys/socket.h>
++#include <linux/ip.h>
+ int main(void) { return sizeof(struct mmsghdr); }
+ EOF
+ if compile_prog "" "" ; then
+diff --git a/cpus.c b/cpus.c
+index 5e7f2cf..492defe 100644
+--- a/cpus.c
++++ b/cpus.c
+@@ -523,6 +523,15 @@ void cpu_synchronize_all_post_init(void)
+ }
+ }
+
++void cpu_clean_all_dirty(void)
++{
++ CPUState *cpu;
++
++ CPU_FOREACH(cpu) {
++ cpu_clean_state(cpu);
++ }
++}
++
+ static int do_vm_stop(RunState state)
+ {
+ int ret = 0;
+diff --git a/exec.c b/exec.c
+index 765bd94..bfee04a 100644
+--- a/exec.c
++++ b/exec.c
+@@ -430,15 +430,50 @@ static int cpu_common_post_load(void *opaque, int version_id)
+ return 0;
+ }
+
++static int cpu_common_pre_load(void *opaque)
++{
++ CPUState *cpu = opaque;
++
++ cpu->exception_index = 0;
++
++ return 0;
++}
++
++static bool cpu_common_exception_index_needed(void *opaque)
++{
++ CPUState *cpu = opaque;
++
++ return cpu->exception_index != 0;
++}
++
++static const VMStateDescription vmstate_cpu_common_exception_index = {
++ .name = "cpu_common/exception_index",
++ .version_id = 1,
++ .minimum_version_id = 1,
++ .fields = (VMStateField[]) {
++ VMSTATE_INT32(exception_index, CPUState),
++ VMSTATE_END_OF_LIST()
++ }
++};
++
+ const VMStateDescription vmstate_cpu_common = {
+ .name = "cpu_common",
+ .version_id = 1,
+ .minimum_version_id = 1,
++ .pre_load = cpu_common_pre_load,
+ .post_load = cpu_common_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(halted, CPUState),
+ VMSTATE_UINT32(interrupt_request, CPUState),
+ VMSTATE_END_OF_LIST()
++ },
++ .subsections = (VMStateSubsection[]) {
++ {
++ .vmsd = &vmstate_cpu_common_exception_index,
++ .needed = cpu_common_exception_index_needed,
++ } , {
++ /* empty */
++ }
+ }
+ };
+
+@@ -1095,6 +1130,7 @@ static void *file_ram_alloc(RAMBlock *block,
+
+ error:
+ if (mem_prealloc) {
++ error_report("%s\n", error_get_pretty(*errp));
+ exit(1);
+ }
+ return NULL;
+@@ -1973,10 +2009,8 @@ int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr,
+ static void invalidate_and_set_dirty(hwaddr addr,
+ hwaddr length)
+ {
+- if (cpu_physical_memory_is_clean(addr)) {
+- /* invalidate code */
+- tb_invalidate_phys_page_range(addr, addr + length, 0);
+- /* set dirty bit */
++ if (cpu_physical_memory_range_includes_clean(addr, length)) {
++ tb_invalidate_phys_range(addr, addr + length, 0);
+ cpu_physical_memory_set_dirty_range_nocode(addr, length);
+ }
+ xen_modified_memory(addr, length);
+diff --git a/gdbstub.c b/gdbstub.c
+index 8afe0b7..71aaa23 100644
+--- a/gdbstub.c
++++ b/gdbstub.c
+@@ -1707,7 +1707,7 @@ int gdbserver_start(const char *device)
+ qemu_add_vm_change_state_handler(gdb_vm_state_change, NULL);
+
+ /* Initialize a monitor terminal for gdb */
+- mon_chr = g_malloc0(sizeof(*mon_chr));
++ mon_chr = qemu_chr_alloc();
+ mon_chr->chr_write = gdb_monitor_write;
+ monitor_init(mon_chr, 0);
+ } else {
+diff --git a/hw/acpi/pcihp.c b/hw/acpi/pcihp.c
+index fae663a..34dedf1 100644
+--- a/hw/acpi/pcihp.c
++++ b/hw/acpi/pcihp.c
+@@ -231,7 +231,7 @@ static uint64_t pci_read(void *opaque, hwaddr addr, unsigned int size)
+ uint32_t val = 0;
+ int bsel = s->hotplug_select;
+
+- if (bsel < 0 || bsel > ACPI_PCIHP_MAX_HOTPLUG_BUS) {
++ if (bsel < 0 || bsel >= ACPI_PCIHP_MAX_HOTPLUG_BUS) {
+ return 0;
+ }
+
+diff --git a/hw/arm/boot.c b/hw/arm/boot.c
+index 3d1f4a2..50b6c5c 100644
+--- a/hw/arm/boot.c
++++ b/hw/arm/boot.c
+@@ -508,7 +508,7 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
+ entry = elf_entry;
+ if (kernel_size < 0) {
+ kernel_size = load_uimage(info->kernel_filename, &entry, NULL,
+- &is_linux);
++ &is_linux, NULL, NULL);
+ }
+ if (kernel_size < 0) {
+ entry = info->loader_start + kernel_load_offset;
+diff --git a/hw/arm/virt.c b/hw/arm/virt.c
+index 89532bd..bdc1573 100644
+--- a/hw/arm/virt.c
++++ b/hw/arm/virt.c
+@@ -194,20 +194,41 @@ static void fdt_add_psci_node(const VirtBoardInfo *vbi)
+
+ /* No PSCI for TCG yet */
+ if (kvm_enabled()) {
++ uint32_t cpu_suspend_fn;
++ uint32_t cpu_off_fn;
++ uint32_t cpu_on_fn;
++ uint32_t migrate_fn;
++
+ qemu_fdt_add_subnode(fdt, "/psci");
+ if (armcpu->psci_version == 2) {
+ const char comp[] = "arm,psci-0.2\0arm,psci";
+ qemu_fdt_setprop(fdt, "/psci", "compatible", comp, sizeof(comp));
++
++ cpu_off_fn = QEMU_PSCI_0_2_FN_CPU_OFF;
++ if (arm_feature(&armcpu->env, ARM_FEATURE_AARCH64)) {
++ cpu_suspend_fn = QEMU_PSCI_0_2_FN64_CPU_SUSPEND;
++ cpu_on_fn = QEMU_PSCI_0_2_FN64_CPU_ON;
++ migrate_fn = QEMU_PSCI_0_2_FN64_MIGRATE;
++ } else {
++ cpu_suspend_fn = QEMU_PSCI_0_2_FN_CPU_SUSPEND;
++ cpu_on_fn = QEMU_PSCI_0_2_FN_CPU_ON;
++ migrate_fn = QEMU_PSCI_0_2_FN_MIGRATE;
++ }
+ } else {
+ qemu_fdt_setprop_string(fdt, "/psci", "compatible", "arm,psci");
++
++ cpu_suspend_fn = QEMU_PSCI_0_1_FN_CPU_SUSPEND;
++ cpu_off_fn = QEMU_PSCI_0_1_FN_CPU_OFF;
++ cpu_on_fn = QEMU_PSCI_0_1_FN_CPU_ON;
++ migrate_fn = QEMU_PSCI_0_1_FN_MIGRATE;
+ }
+
+ qemu_fdt_setprop_string(fdt, "/psci", "method", "hvc");
+- qemu_fdt_setprop_cell(fdt, "/psci", "cpu_suspend",
+- PSCI_FN_CPU_SUSPEND);
+- qemu_fdt_setprop_cell(fdt, "/psci", "cpu_off", PSCI_FN_CPU_OFF);
+- qemu_fdt_setprop_cell(fdt, "/psci", "cpu_on", PSCI_FN_CPU_ON);
+- qemu_fdt_setprop_cell(fdt, "/psci", "migrate", PSCI_FN_MIGRATE);
++
++ qemu_fdt_setprop_cell(fdt, "/psci", "cpu_suspend", cpu_suspend_fn);
++ qemu_fdt_setprop_cell(fdt, "/psci", "cpu_off", cpu_off_fn);
++ qemu_fdt_setprop_cell(fdt, "/psci", "cpu_on", cpu_on_fn);
++ qemu_fdt_setprop_cell(fdt, "/psci", "migrate", migrate_fn);
+ }
+ }
+
+@@ -350,7 +371,7 @@ static void create_uart(const VirtBoardInfo *vbi, qemu_irq *pic)
+ 2, base, 2, size);
+ qemu_fdt_setprop_cells(vbi->fdt, nodename, "interrupts",
+ GIC_FDT_IRQ_TYPE_SPI, irq,
+- GIC_FDT_IRQ_FLAGS_EDGE_LO_HI);
++ GIC_FDT_IRQ_FLAGS_LEVEL_HI);
+ qemu_fdt_setprop_cells(vbi->fdt, nodename, "clocks",
+ vbi->clock_phandle, vbi->clock_phandle);
+ qemu_fdt_setprop(vbi->fdt, nodename, "clock-names",
+@@ -375,7 +396,7 @@ static void create_rtc(const VirtBoardInfo *vbi, qemu_irq *pic)
+ 2, base, 2, size);
+ qemu_fdt_setprop_cells(vbi->fdt, nodename, "interrupts",
+ GIC_FDT_IRQ_TYPE_SPI, irq,
+- GIC_FDT_IRQ_FLAGS_EDGE_LO_HI);
++ GIC_FDT_IRQ_FLAGS_LEVEL_HI);
+ qemu_fdt_setprop_cell(vbi->fdt, nodename, "clocks", vbi->clock_phandle);
+ qemu_fdt_setprop_string(vbi->fdt, nodename, "clock-names", "apb_pclk");
+ g_free(nodename);
+diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
+index c241c50..0e3925b 100644
+--- a/hw/block/virtio-blk.c
++++ b/hw/block/virtio-blk.c
+@@ -469,8 +469,9 @@ static void virtio_blk_dma_restart_bh(void *opaque)
+ s->rq = NULL;
+
+ while (req) {
++ VirtIOBlockReq *next = req->next;
+ virtio_blk_handle_request(req, &mrb);
+- req = req->next;
++ req = next;
+ }
+
+ virtio_submit_multiwrite(s->bs, &mrb);
+diff --git a/hw/core/loader.c b/hw/core/loader.c
+index 2bf6b8f..8b84c12 100644
+--- a/hw/core/loader.c
++++ b/hw/core/loader.c
+@@ -456,7 +456,9 @@ static ssize_t gunzip(void *dst, size_t dstlen, uint8_t *src,
+
+ /* Load a U-Boot image. */
+ static int load_uboot_image(const char *filename, hwaddr *ep, hwaddr *loadaddr,
+- int *is_linux, uint8_t image_type)
++ int *is_linux, uint8_t image_type,
++ uint64_t (*translate_fn)(void *, uint64_t),
++ void *translate_opaque)
+ {
+ int fd;
+ int size;
+@@ -490,6 +492,9 @@ static int load_uboot_image(const char *filename, hwaddr *ep, hwaddr *loadaddr,
+ switch (hdr->ih_type) {
+ case IH_TYPE_KERNEL:
+ address = hdr->ih_load;
++ if (translate_fn) {
++ address = translate_fn(translate_opaque, address);
++ }
+ if (loadaddr) {
+ *loadaddr = hdr->ih_load;
+ }
+@@ -566,15 +571,19 @@ out:
+ }
+
+ int load_uimage(const char *filename, hwaddr *ep, hwaddr *loadaddr,
+- int *is_linux)
++ int *is_linux,
++ uint64_t (*translate_fn)(void *, uint64_t),
++ void *translate_opaque)
+ {
+- return load_uboot_image(filename, ep, loadaddr, is_linux, IH_TYPE_KERNEL);
++ return load_uboot_image(filename, ep, loadaddr, is_linux, IH_TYPE_KERNEL,
++ translate_fn, translate_opaque);
+ }
+
+ /* Load a ramdisk. */
+ int load_ramdisk(const char *filename, hwaddr addr, uint64_t max_sz)
+ {
+- return load_uboot_image(filename, NULL, &addr, NULL, IH_TYPE_RAMDISK);
++ return load_uboot_image(filename, NULL, &addr, NULL, IH_TYPE_RAMDISK,
++ NULL, NULL);
+ }
+
+ /*
+diff --git a/hw/core/machine.c b/hw/core/machine.c
+index 7a66c57..d145aca 100644
+--- a/hw/core/machine.c
++++ b/hw/core/machine.c
+@@ -24,6 +24,7 @@ static void machine_set_accel(Object *obj, const char *value, Error **errp)
+ {
+ MachineState *ms = MACHINE(obj);
+
++ g_free(ms->accel);
+ ms->accel = g_strdup(value);
+ }
+
+@@ -79,6 +80,7 @@ static void machine_set_kernel(Object *obj, const char *value, Error **errp)
+ {
+ MachineState *ms = MACHINE(obj);
+
++ g_free(ms->kernel_filename);
+ ms->kernel_filename = g_strdup(value);
+ }
+
+@@ -93,6 +95,7 @@ static void machine_set_initrd(Object *obj, const char *value, Error **errp)
+ {
+ MachineState *ms = MACHINE(obj);
+
++ g_free(ms->initrd_filename);
+ ms->initrd_filename = g_strdup(value);
+ }
+
+@@ -107,6 +110,7 @@ static void machine_set_append(Object *obj, const char *value, Error **errp)
+ {
+ MachineState *ms = MACHINE(obj);
+
++ g_free(ms->kernel_cmdline);
+ ms->kernel_cmdline = g_strdup(value);
+ }
+
+@@ -121,6 +125,7 @@ static void machine_set_dtb(Object *obj, const char *value, Error **errp)
+ {
+ MachineState *ms = MACHINE(obj);
+
++ g_free(ms->dtb);
+ ms->dtb = g_strdup(value);
+ }
+
+@@ -135,6 +140,7 @@ static void machine_set_dumpdtb(Object *obj, const char *value, Error **errp)
+ {
+ MachineState *ms = MACHINE(obj);
+
++ g_free(ms->dumpdtb);
+ ms->dumpdtb = g_strdup(value);
+ }
+
+@@ -176,6 +182,7 @@ static void machine_set_dt_compatible(Object *obj, const char *value, Error **er
+ {
+ MachineState *ms = MACHINE(obj);
+
++ g_free(ms->dt_compatible);
+ ms->dt_compatible = g_strdup(value);
+ }
+
+@@ -232,6 +239,7 @@ static void machine_set_firmware(Object *obj, const char *value, Error **errp)
+ {
+ MachineState *ms = MACHINE(obj);
+
++ g_free(ms->firmware);
+ ms->firmware = g_strdup(value);
+ }
+
+diff --git a/hw/core/qdev.c b/hw/core/qdev.c
+index da1ba48..0e21fad 100644
+--- a/hw/core/qdev.c
++++ b/hw/core/qdev.c
+@@ -834,12 +834,14 @@ static void device_set_realized(Object *obj, bool value, Error **errp)
+ dc->realize(dev, &local_err);
+ }
+
+- if (dev->parent_bus && dev->parent_bus->hotplug_handler &&
+- local_err == NULL) {
++ if (local_err != NULL) {
++ goto fail;
++ }
++
++ if (dev->parent_bus && dev->parent_bus->hotplug_handler) {
+ hotplug_handler_plug(dev->parent_bus->hotplug_handler,
+ dev, &local_err);
+- } else if (local_err == NULL &&
+- object_dynamic_cast(qdev_get_machine(), TYPE_MACHINE)) {
++ } else if (object_dynamic_cast(qdev_get_machine(), TYPE_MACHINE)) {
+ HotplugHandler *hotplug_ctrl;
+ MachineState *machine = MACHINE(qdev_get_machine());
+ MachineClass *mc = MACHINE_GET_CLASS(machine);
+@@ -852,47 +854,69 @@ static void device_set_realized(Object *obj, bool value, Error **errp)
+ }
+ }
+
+- if (qdev_get_vmsd(dev) && local_err == NULL) {
++ if (local_err != NULL) {
++ goto post_realize_fail;
++ }
++
++ if (qdev_get_vmsd(dev)) {
+ vmstate_register_with_alias_id(dev, -1, qdev_get_vmsd(dev), dev,
+ dev->instance_id_alias,
+ dev->alias_required_for_version);
+ }
+- if (local_err == NULL) {
+- QLIST_FOREACH(bus, &dev->child_bus, sibling) {
+- object_property_set_bool(OBJECT(bus), true, "realized",
++
++ QLIST_FOREACH(bus, &dev->child_bus, sibling) {
++ object_property_set_bool(OBJECT(bus), true, "realized",
+ &local_err);
+- if (local_err != NULL) {
+- break;
+- }
++ if (local_err != NULL) {
++ goto child_realize_fail;
+ }
+ }
+- if (dev->hotplugged && local_err == NULL) {
++ if (dev->hotplugged) {
+ device_reset(dev);
+ }
+ dev->pending_deleted_event = false;
+ } else if (!value && dev->realized) {
++ Error **local_errp = NULL;
+ QLIST_FOREACH(bus, &dev->child_bus, sibling) {
++ local_errp = local_err ? NULL : &local_err;
+ object_property_set_bool(OBJECT(bus), false, "realized",
+- &local_err);
+- if (local_err != NULL) {
+- break;
+- }
++ local_errp);
+ }
+- if (qdev_get_vmsd(dev) && local_err == NULL) {
++ if (qdev_get_vmsd(dev)) {
+ vmstate_unregister(dev, qdev_get_vmsd(dev), dev);
+ }
+- if (dc->unrealize && local_err == NULL) {
+- dc->unrealize(dev, &local_err);
++ if (dc->unrealize) {
++ local_errp = local_err ? NULL : &local_err;
++ dc->unrealize(dev, local_errp);
+ }
+ dev->pending_deleted_event = true;
+ }
+
+ if (local_err != NULL) {
+- error_propagate(errp, local_err);
+- return;
++ goto fail;
+ }
+
+ dev->realized = value;
++ return;
++
++child_realize_fail:
++ QLIST_FOREACH(bus, &dev->child_bus, sibling) {
++ object_property_set_bool(OBJECT(bus), false, "realized",
++ NULL);
++ }
++
++ if (qdev_get_vmsd(dev)) {
++ vmstate_unregister(dev, qdev_get_vmsd(dev), dev);
++ }
++
++post_realize_fail:
++ if (dc->unrealize) {
++ dc->unrealize(dev, NULL);
++ }
++
++fail:
++ error_propagate(errp, local_err);
++ return;
+ }
+
+ static bool device_get_hotpluggable(Object *obj, Error **errp)
+diff --git a/hw/display/qxl-render.c b/hw/display/qxl-render.c
+index cc2c2b1..bcc5c37 100644
+--- a/hw/display/qxl-render.c
++++ b/hw/display/qxl-render.c
+@@ -138,7 +138,9 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl)
+ if (qemu_spice_rect_is_empty(qxl->dirty+i)) {
+ break;
+ }
+- if (qxl->dirty[i].left > qxl->dirty[i].right ||
++ if (qxl->dirty[i].left < 0 ||
++ qxl->dirty[i].top < 0 ||
++ qxl->dirty[i].left > qxl->dirty[i].right ||
+ qxl->dirty[i].top > qxl->dirty[i].bottom ||
+ qxl->dirty[i].right > qxl->guest_primary.surface.width ||
+ qxl->dirty[i].bottom > qxl->guest_primary.surface.height) {
+diff --git a/hw/display/qxl.c b/hw/display/qxl.c
+index d43aa49..652af99 100644
+--- a/hw/display/qxl.c
++++ b/hw/display/qxl.c
+@@ -2063,6 +2063,7 @@ static int qxl_init_primary(PCIDevice *dev)
+
+ qxl->id = 0;
+ qxl_init_ramsize(qxl);
++ vga->vbe_size = qxl->vgamem_size;
+ vga->vram_size_mb = qxl->vga.vram_size >> 20;
+ vga_common_init(vga, OBJECT(dev), true);
+ vga_init(vga, OBJECT(dev),
+diff --git a/hw/display/vga.c b/hw/display/vga.c
+index 4b089a3..e82420d 100644
+--- a/hw/display/vga.c
++++ b/hw/display/vga.c
+@@ -580,6 +580,93 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+ }
+ }
+
++/*
++ * Sanity check vbe register writes.
++ *
++ * As we don't have a way to signal errors to the guest in the bochs
++ * dispi interface we'll go adjust the registers to the closest valid
++ * value.
++ */
++static void vbe_fixup_regs(VGACommonState *s)
++{
++ uint16_t *r = s->vbe_regs;
++ uint32_t bits, linelength, maxy, offset;
++
++ if (!(r[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
++ /* vbe is turned off -- nothing to do */
++ return;
++ }
++
++ /* check depth */
++ switch (r[VBE_DISPI_INDEX_BPP]) {
++ case 4:
++ case 8:
++ case 16:
++ case 24:
++ case 32:
++ bits = r[VBE_DISPI_INDEX_BPP];
++ break;
++ case 15:
++ bits = 16;
++ break;
++ default:
++ bits = r[VBE_DISPI_INDEX_BPP] = 8;
++ break;
++ }
++
++ /* check width */
++ r[VBE_DISPI_INDEX_XRES] &= ~7u;
++ if (r[VBE_DISPI_INDEX_XRES] == 0) {
++ r[VBE_DISPI_INDEX_XRES] = 8;
++ }
++ if (r[VBE_DISPI_INDEX_XRES] > VBE_DISPI_MAX_XRES) {
++ r[VBE_DISPI_INDEX_XRES] = VBE_DISPI_MAX_XRES;
++ }
++ r[VBE_DISPI_INDEX_VIRT_WIDTH] &= ~7u;
++ if (r[VBE_DISPI_INDEX_VIRT_WIDTH] > VBE_DISPI_MAX_XRES) {
++ r[VBE_DISPI_INDEX_VIRT_WIDTH] = VBE_DISPI_MAX_XRES;
++ }
++ if (r[VBE_DISPI_INDEX_VIRT_WIDTH] < r[VBE_DISPI_INDEX_XRES]) {
++ r[VBE_DISPI_INDEX_VIRT_WIDTH] = r[VBE_DISPI_INDEX_XRES];
++ }
++
++ /* check height */
++ linelength = r[VBE_DISPI_INDEX_VIRT_WIDTH] * bits / 8;
++ maxy = s->vbe_size / linelength;
++ if (r[VBE_DISPI_INDEX_YRES] == 0) {
++ r[VBE_DISPI_INDEX_YRES] = 1;
++ }
++ if (r[VBE_DISPI_INDEX_YRES] > VBE_DISPI_MAX_YRES) {
++ r[VBE_DISPI_INDEX_YRES] = VBE_DISPI_MAX_YRES;
++ }
++ if (r[VBE_DISPI_INDEX_YRES] > maxy) {
++ r[VBE_DISPI_INDEX_YRES] = maxy;
++ }
++
++ /* check offset */
++ if (r[VBE_DISPI_INDEX_X_OFFSET] > VBE_DISPI_MAX_XRES) {
++ r[VBE_DISPI_INDEX_X_OFFSET] = VBE_DISPI_MAX_XRES;
++ }
++ if (r[VBE_DISPI_INDEX_Y_OFFSET] > VBE_DISPI_MAX_YRES) {
++ r[VBE_DISPI_INDEX_Y_OFFSET] = VBE_DISPI_MAX_YRES;
++ }
++ offset = r[VBE_DISPI_INDEX_X_OFFSET] * bits / 8;
++ offset += r[VBE_DISPI_INDEX_Y_OFFSET] * linelength;
++ if (offset + r[VBE_DISPI_INDEX_YRES] * linelength > s->vbe_size) {
++ r[VBE_DISPI_INDEX_Y_OFFSET] = 0;
++ offset = r[VBE_DISPI_INDEX_X_OFFSET] * bits / 8;
++ if (offset + r[VBE_DISPI_INDEX_YRES] * linelength > s->vbe_size) {
++ r[VBE_DISPI_INDEX_X_OFFSET] = 0;
++ offset = 0;
++ }
++ }
++
++ /* update vga state */
++ r[VBE_DISPI_INDEX_VIRT_HEIGHT] = maxy;
++ s->vbe_line_offset = linelength;
++ s->vbe_start_addr = offset / 4;
++}
++
+ static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
+ {
+ VGACommonState *s = opaque;
+@@ -614,7 +701,7 @@ uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr)
+ val = s->vbe_regs[s->vbe_index];
+ }
+ } else if (s->vbe_index == VBE_DISPI_INDEX_VIDEO_MEMORY_64K) {
+- val = s->vram_size / (64 * 1024);
++ val = s->vbe_size / (64 * 1024);
+ } else {
+ val = 0;
+ }
+@@ -649,22 +736,13 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
+ }
+ break;
+ case VBE_DISPI_INDEX_XRES:
+- if ((val <= VBE_DISPI_MAX_XRES) && ((val & 7) == 0)) {
+- s->vbe_regs[s->vbe_index] = val;
+- }
+- break;
+ case VBE_DISPI_INDEX_YRES:
+- if (val <= VBE_DISPI_MAX_YRES) {
+- s->vbe_regs[s->vbe_index] = val;
+- }
+- break;
+ case VBE_DISPI_INDEX_BPP:
+- if (val == 0)
+- val = 8;
+- if (val == 4 || val == 8 || val == 15 ||
+- val == 16 || val == 24 || val == 32) {
+- s->vbe_regs[s->vbe_index] = val;
+- }
++ case VBE_DISPI_INDEX_VIRT_WIDTH:
++ case VBE_DISPI_INDEX_X_OFFSET:
++ case VBE_DISPI_INDEX_Y_OFFSET:
++ s->vbe_regs[s->vbe_index] = val;
++ vbe_fixup_regs(s);
+ break;
+ case VBE_DISPI_INDEX_BANK:
+ if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
+@@ -681,19 +759,11 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
+ !(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
+ int h, shift_control;
+
+- s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] =
+- s->vbe_regs[VBE_DISPI_INDEX_XRES];
+- s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] =
+- s->vbe_regs[VBE_DISPI_INDEX_YRES];
++ s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = 0;
+ s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
+ s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
+-
+- if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
+- s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1;
+- else
+- s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] *
+- ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
+- s->vbe_start_addr = 0;
++ s->vbe_regs[VBE_DISPI_INDEX_ENABLE] |= VBE_DISPI_ENABLED;
++ vbe_fixup_regs(s);
+
+ /* clear the screen (should be done in BIOS) */
+ if (!(val & VBE_DISPI_NOCLEARMEM)) {
+@@ -742,40 +812,6 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
+ s->vbe_regs[s->vbe_index] = val;
+ vga_update_memory_access(s);
+ break;
+- case VBE_DISPI_INDEX_VIRT_WIDTH:
+- {
+- int w, h, line_offset;
+-
+- if (val < s->vbe_regs[VBE_DISPI_INDEX_XRES])
+- return;
+- w = val;
+- if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
+- line_offset = w >> 1;
+- else
+- line_offset = w * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
+- h = s->vram_size / line_offset;
+- /* XXX: support weird bochs semantics ? */
+- if (h < s->vbe_regs[VBE_DISPI_INDEX_YRES])
+- return;
+- s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = w;
+- s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = h;
+- s->vbe_line_offset = line_offset;
+- }
+- break;
+- case VBE_DISPI_INDEX_X_OFFSET:
+- case VBE_DISPI_INDEX_Y_OFFSET:
+- {
+- int x;
+- s->vbe_regs[s->vbe_index] = val;
+- s->vbe_start_addr = s->vbe_line_offset * s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET];
+- x = s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET];
+- if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
+- s->vbe_start_addr += x >> 1;
+- else
+- s->vbe_start_addr += x * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
+- s->vbe_start_addr >>= 2;
+- }
+- break;
+ default:
+ break;
+ }
+@@ -2289,6 +2325,9 @@ void vga_common_init(VGACommonState *s, Object *obj, bool global_vmstate)
+ s->vram_size <<= 1;
+ }
+ s->vram_size_mb = s->vram_size >> 20;
++ if (!s->vbe_size) {
++ s->vbe_size = s->vram_size;
++ }
+
+ s->is_vbe_vmstate = 1;
+ memory_region_init_ram(&s->vram, obj, "vga.vram", s->vram_size);
+diff --git a/hw/display/vga_int.h b/hw/display/vga_int.h
+index 5320abd..cb6d8f6 100644
+--- a/hw/display/vga_int.h
++++ b/hw/display/vga_int.h
+@@ -93,6 +93,7 @@ typedef struct VGACommonState {
+ MemoryRegion vram_vbe;
+ uint32_t vram_size;
+ uint32_t vram_size_mb; /* property */
++ uint32_t vbe_size;
+ uint32_t latch;
+ MemoryRegion *chain4_alias;
+ uint8_t sr_index;
+diff --git a/hw/display/vmware_vga.c b/hw/display/vmware_vga.c
+index 591b645..d44e3e8 100644
+--- a/hw/display/vmware_vga.c
++++ b/hw/display/vmware_vga.c
+@@ -292,47 +292,74 @@ enum {
+ SVGA_CURSOR_ON_RESTORE_TO_FB = 3,
+ };
+
+-static inline void vmsvga_update_rect(struct vmsvga_state_s *s,
+- int x, int y, int w, int h)
++static inline bool vmsvga_verify_rect(DisplaySurface *surface,
++ const char *name,
++ int x, int y, int w, int h)
+ {
+- DisplaySurface *surface = qemu_console_surface(s->vga.con);
+- int line;
+- int bypl;
+- int width;
+- int start;
+- uint8_t *src;
+- uint8_t *dst;
+-
+ if (x < 0) {
+- fprintf(stderr, "%s: update x was < 0 (%d)\n", __func__, x);
+- w += x;
+- x = 0;
++ fprintf(stderr, "%s: x was < 0 (%d)\n", name, x);
++ return false;
++ }
++ if (x > SVGA_MAX_WIDTH) {
++ fprintf(stderr, "%s: x was > %d (%d)\n", name, SVGA_MAX_WIDTH, x);
++ return false;
+ }
+ if (w < 0) {
+- fprintf(stderr, "%s: update w was < 0 (%d)\n", __func__, w);
+- w = 0;
++ fprintf(stderr, "%s: w was < 0 (%d)\n", name, w);
++ return false;
++ }
++ if (w > SVGA_MAX_WIDTH) {
++ fprintf(stderr, "%s: w was > %d (%d)\n", name, SVGA_MAX_WIDTH, w);
++ return false;
+ }
+ if (x + w > surface_width(surface)) {
+- fprintf(stderr, "%s: update width too large x: %d, w: %d\n",
+- __func__, x, w);
+- x = MIN(x, surface_width(surface));
+- w = surface_width(surface) - x;
++ fprintf(stderr, "%s: width was > %d (x: %d, w: %d)\n",
++ name, surface_width(surface), x, w);
++ return false;
+ }
+
+ if (y < 0) {
+- fprintf(stderr, "%s: update y was < 0 (%d)\n", __func__, y);
+- h += y;
+- y = 0;
++ fprintf(stderr, "%s: y was < 0 (%d)\n", name, y);
++ return false;
++ }
++ if (y > SVGA_MAX_HEIGHT) {
++ fprintf(stderr, "%s: y was > %d (%d)\n", name, SVGA_MAX_HEIGHT, y);
++ return false;
+ }
+ if (h < 0) {
+- fprintf(stderr, "%s: update h was < 0 (%d)\n", __func__, h);
+- h = 0;
++ fprintf(stderr, "%s: h was < 0 (%d)\n", name, h);
++ return false;
++ }
++ if (h > SVGA_MAX_HEIGHT) {
++ fprintf(stderr, "%s: h was > %d (%d)\n", name, SVGA_MAX_HEIGHT, h);
++ return false;
+ }
+ if (y + h > surface_height(surface)) {
+- fprintf(stderr, "%s: update height too large y: %d, h: %d\n",
+- __func__, y, h);
+- y = MIN(y, surface_height(surface));
+- h = surface_height(surface) - y;
++ fprintf(stderr, "%s: update height > %d (y: %d, h: %d)\n",
++ name, surface_height(surface), y, h);
++ return false;
++ }
++
++ return true;
++}
++
++static inline void vmsvga_update_rect(struct vmsvga_state_s *s,
++ int x, int y, int w, int h)
++{
++ DisplaySurface *surface = qemu_console_surface(s->vga.con);
++ int line;
++ int bypl;
++ int width;
++ int start;
++ uint8_t *src;
++ uint8_t *dst;
++
++ if (!vmsvga_verify_rect(surface, __func__, x, y, w, h)) {
++ /* go for a fullscreen update as fallback */
++ x = 0;
++ y = 0;
++ w = surface_width(surface);
++ h = surface_height(surface);
+ }
+
+ bypl = surface_stride(surface);
+@@ -377,7 +404,7 @@ static inline void vmsvga_update_rect_flush(struct vmsvga_state_s *s)
+ }
+
+ #ifdef HW_RECT_ACCEL
+-static inline void vmsvga_copy_rect(struct vmsvga_state_s *s,
++static inline int vmsvga_copy_rect(struct vmsvga_state_s *s,
+ int x0, int y0, int x1, int y1, int w, int h)
+ {
+ DisplaySurface *surface = qemu_console_surface(s->vga.con);
+@@ -388,6 +415,13 @@ static inline void vmsvga_copy_rect(struct vmsvga_state_s *s,
+ int line = h;
+ uint8_t *ptr[2];
+
++ if (!vmsvga_verify_rect(surface, "vmsvga_copy_rect/src", x0, y0, w, h)) {
++ return -1;
++ }
++ if (!vmsvga_verify_rect(surface, "vmsvga_copy_rect/dst", x1, y1, w, h)) {
++ return -1;
++ }
++
+ if (y1 > y0) {
+ ptr[0] = vram + bypp * x0 + bypl * (y0 + h - 1);
+ ptr[1] = vram + bypp * x1 + bypl * (y1 + h - 1);
+@@ -403,11 +437,12 @@ static inline void vmsvga_copy_rect(struct vmsvga_state_s *s,
+ }
+
+ vmsvga_update_rect_delayed(s, x1, y1, w, h);
++ return 0;
+ }
+ #endif
+
+ #ifdef HW_FILL_ACCEL
+-static inline void vmsvga_fill_rect(struct vmsvga_state_s *s,
++static inline int vmsvga_fill_rect(struct vmsvga_state_s *s,
+ uint32_t c, int x, int y, int w, int h)
+ {
+ DisplaySurface *surface = qemu_console_surface(s->vga.con);
+@@ -420,6 +455,10 @@ static inline void vmsvga_fill_rect(struct vmsvga_state_s *s,
+ uint8_t *src;
+ uint8_t col[4];
+
++ if (!vmsvga_verify_rect(surface, __func__, x, y, w, h)) {
++ return -1;
++ }
++
+ col[0] = c;
+ col[1] = c >> 8;
+ col[2] = c >> 16;
+@@ -444,6 +483,7 @@ static inline void vmsvga_fill_rect(struct vmsvga_state_s *s,
+ }
+
+ vmsvga_update_rect_delayed(s, x, y, w, h);
++ return 0;
+ }
+ #endif
+
+@@ -576,12 +616,12 @@ static void vmsvga_fifo_run(struct vmsvga_state_s *s)
+ width = vmsvga_fifo_read(s);
+ height = vmsvga_fifo_read(s);
+ #ifdef HW_FILL_ACCEL
+- vmsvga_fill_rect(s, colour, x, y, width, height);
+- break;
+-#else
++ if (vmsvga_fill_rect(s, colour, x, y, width, height) == 0) {
++ break;
++ }
++#endif
+ args = 0;
+ goto badcmd;
+-#endif
+
+ case SVGA_CMD_RECT_COPY:
+ len -= 7;
+@@ -596,12 +636,12 @@ static void vmsvga_fifo_run(struct vmsvga_state_s *s)
+ width = vmsvga_fifo_read(s);
+ height = vmsvga_fifo_read(s);
+ #ifdef HW_RECT_ACCEL
+- vmsvga_copy_rect(s, x, y, dx, dy, width, height);
+- break;
+-#else
++ if (vmsvga_copy_rect(s, x, y, dx, dy, width, height) == 0) {
++ break;
++ }
++#endif
+ args = 0;
+ goto badcmd;
+-#endif
+
+ case SVGA_CMD_DEFINE_CURSOR:
+ len -= 8;
+diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
+index 816c6d9..5d9f654 100644
+--- a/hw/i386/acpi-build.c
++++ b/hw/i386/acpi-build.c
+@@ -546,6 +546,12 @@ static void fadt_setup(AcpiFadtDescriptorRev1 *fadt, AcpiPmInfo *pm)
+ (1 << ACPI_FADT_F_SLP_BUTTON) |
+ (1 << ACPI_FADT_F_RTC_S4));
+ fadt->flags |= cpu_to_le32(1 << ACPI_FADT_F_USE_PLATFORM_CLOCK);
++ /* APIC destination mode ("Flat Logical") has an upper limit of 8 CPUs
++ * For more than 8 CPUs, "Clustered Logical" mode has to be used
++ */
++ if (max_cpus > 8) {
++ fadt->flags |= cpu_to_le32(1 << ACPI_FADT_F_FORCE_APIC_CLUSTER_MODEL);
++ }
+ }
+
+
+@@ -1222,8 +1228,7 @@ acpi_build_srat_memory(AcpiSratMemoryAffinity *numamem, uint64_t base,
+ }
+
+ static void
+-build_srat(GArray *table_data, GArray *linker,
+- AcpiCpuInfo *cpu, PcGuestInfo *guest_info)
++build_srat(GArray *table_data, GArray *linker, PcGuestInfo *guest_info)
+ {
+ AcpiSystemResourceAffinityTable *srat;
+ AcpiSratProcessorAffinity *core;
+@@ -1253,11 +1258,7 @@ build_srat(GArray *table_data, GArray *linker,
+ core->proximity_lo = curnode;
+ memset(core->proximity_hi, 0, 3);
+ core->local_sapic_eid = 0;
+- if (test_bit(i, cpu->found_cpus)) {
+- core->flags = cpu_to_le32(1);
+- } else {
+- core->flags = cpu_to_le32(0);
+- }
++ core->flags = cpu_to_le32(1);
+ }
+
+
+@@ -1393,7 +1394,7 @@ build_rsdp(GArray *rsdp_table, GArray *linker, unsigned rsdt)
+ {
+ AcpiRsdpDescriptor *rsdp = acpi_data_push(rsdp_table, sizeof *rsdp);
+
+- bios_linker_loader_alloc(linker, ACPI_BUILD_RSDP_FILE, 1,
++ bios_linker_loader_alloc(linker, ACPI_BUILD_RSDP_FILE, 16,
+ true /* fseg memory */);
+
+ memcpy(&rsdp->signature, "RSD PTR ", 8);
+@@ -1533,7 +1534,7 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables)
+ }
+ if (guest_info->numa_nodes) {
+ acpi_add_table(table_offsets, tables->table_data);
+- build_srat(tables->table_data, tables->linker, &cpu, guest_info);
++ build_srat(tables->table_data, tables->linker, guest_info);
+ }
+ if (acpi_get_mcfg(&mcfg)) {
+ acpi_add_table(table_offsets, tables->table_data);
+diff --git a/hw/i386/acpi-dsdt.dsl b/hw/i386/acpi-dsdt.dsl
+index 6ba0170..559f4b6 100644
+--- a/hw/i386/acpi-dsdt.dsl
++++ b/hw/i386/acpi-dsdt.dsl
+@@ -302,7 +302,7 @@ DefinitionBlock (
+ /****************************************************************
+ * General purpose events
+ ****************************************************************/
+- External(\_SB.PCI0.MEMORY_HOPTLUG_DEVICE.MEMORY_SLOT_SCAN_METHOD, MethodObj)
++ External(\_SB.PCI0.MEMORY_HOTPLUG_DEVICE.MEMORY_SLOT_SCAN_METHOD, MethodObj)
+
+ Scope(\_GPE) {
+ Name(_HID, "ACPI0006")
+@@ -321,7 +321,7 @@ DefinitionBlock (
+ }
+ Method(_E03) {
+ // Memory hotplug event
+- \_SB.PCI0.MEMORY_HOPTLUG_DEVICE.MEMORY_SLOT_SCAN_METHOD()
++ \_SB.PCI0.MEMORY_HOTPLUG_DEVICE.MEMORY_SLOT_SCAN_METHOD()
+ }
+ Method(_L04) {
+ }
+diff --git a/hw/i386/acpi-dsdt.hex.generated b/hw/i386/acpi-dsdt.hex.generated
+index 6c8a1fc..a21bf41 100644
+--- a/hw/i386/acpi-dsdt.hex.generated
++++ b/hw/i386/acpi-dsdt.hex.generated
+@@ -8,7 +8,7 @@ static unsigned char AcpiDsdtAmlCode[] = {
+ 0x0,
+ 0x0,
+ 0x1,
+-0x2e,
++0x1f,
+ 0x42,
+ 0x58,
+ 0x50,
+@@ -31,9 +31,9 @@ static unsigned char AcpiDsdtAmlCode[] = {
+ 0x4e,
+ 0x54,
+ 0x4c,
+-0x13,
+-0x9,
+-0x12,
++0x28,
++0x5,
++0x10,
+ 0x20,
+ 0x10,
+ 0x49,
+diff --git a/hw/i386/kvm/clock.c b/hw/i386/kvm/clock.c
+index 07b9c0e..58be2bd 100644
+--- a/hw/i386/kvm/clock.c
++++ b/hw/i386/kvm/clock.c
+@@ -14,8 +14,10 @@
+ */
+
+ #include "qemu-common.h"
++#include "qemu/host-utils.h"
+ #include "sysemu/sysemu.h"
+ #include "sysemu/kvm.h"
++#include "sysemu/cpus.h"
+ #include "hw/sysbus.h"
+ #include "hw/kvm/clock.h"
+
+@@ -34,6 +36,48 @@ typedef struct KVMClockState {
+ bool clock_valid;
+ } KVMClockState;
+
++struct pvclock_vcpu_time_info {
++ uint32_t version;
++ uint32_t pad0;
++ uint64_t tsc_timestamp;
++ uint64_t system_time;
++ uint32_t tsc_to_system_mul;
++ int8_t tsc_shift;
++ uint8_t flags;
++ uint8_t pad[2];
++} __attribute__((__packed__)); /* 32 bytes */
++
++static uint64_t kvmclock_current_nsec(KVMClockState *s)
++{
++ CPUState *cpu = first_cpu;
++ CPUX86State *env = cpu->env_ptr;
++ hwaddr kvmclock_struct_pa = env->system_time_msr & ~1ULL;
++ uint64_t migration_tsc = env->tsc;
++ struct pvclock_vcpu_time_info time;
++ uint64_t delta;
++ uint64_t nsec_lo;
++ uint64_t nsec_hi;
++ uint64_t nsec;
++
++ if (!(env->system_time_msr & 1ULL)) {
++ /* KVM clock not active */
++ return 0;
++ }
++
++ cpu_physical_memory_read(kvmclock_struct_pa, &time, sizeof(time));
++
++ assert(time.tsc_timestamp <= migration_tsc);
++ delta = migration_tsc - time.tsc_timestamp;
++ if (time.tsc_shift < 0) {
++ delta >>= -time.tsc_shift;
++ } else {
++ delta <<= time.tsc_shift;
++ }
++
++ mulu64(&nsec_lo, &nsec_hi, delta, time.tsc_to_system_mul);
++ nsec = (nsec_lo >> 32) | (nsec_hi << 32);
++ return nsec + time.system_time;
++}
+
+ static void kvmclock_vm_state_change(void *opaque, int running,
+ RunState state)
+@@ -45,9 +89,15 @@ static void kvmclock_vm_state_change(void *opaque, int running,
+
+ if (running) {
+ struct kvm_clock_data data;
++ uint64_t time_at_migration = kvmclock_current_nsec(s);
+
+ s->clock_valid = false;
+
++ /* We can't rely on the migrated clock value, just discard it */
++ if (time_at_migration) {
++ s->clock = time_at_migration;
++ }
++
+ data.clock = s->clock;
+ data.flags = 0;
+ ret = kvm_vm_ioctl(kvm_state, KVM_SET_CLOCK, &data);
+@@ -75,6 +125,23 @@ static void kvmclock_vm_state_change(void *opaque, int running,
+ if (s->clock_valid) {
+ return;
+ }
++
++ cpu_synchronize_all_states();
++ /* In theory, the cpu_synchronize_all_states() call above wouldn't
++ * affect the rest of the code, as the VCPU state inside CPUState
++ * is supposed to always match the VCPU state on the kernel side.
++ *
++ * In practice, calling cpu_synchronize_state() too soon will load the
++ * kernel-side APIC state into X86CPU.apic_state too early, APIC state
++ * won't be reloaded later because CPUState.vcpu_dirty==true, and
++ * outdated APIC state may be migrated to another host.
++ *
++ * The real fix would be to make sure outdated APIC state is read
++ * from the kernel again when necessary. While this is not fixed, we
++ * need the cpu_clean_all_dirty() call below.
++ */
++ cpu_clean_all_dirty();
++
+ ret = kvm_vm_ioctl(kvm_state, KVM_GET_CLOCK, &data);
+ if (ret < 0) {
+ fprintf(stderr, "KVM_GET_CLOCK failed: %s\n", strerror(ret));
+diff --git a/hw/i386/pc.c b/hw/i386/pc.c
+index 2cf22b1..ef9fad8 100644
+--- a/hw/i386/pc.c
++++ b/hw/i386/pc.c
+@@ -72,8 +72,15 @@
+ #define DPRINTF(fmt, ...)
+ #endif
+
+-/* Leave a chunk of memory at the top of RAM for the BIOS ACPI tables. */
+-#define ACPI_DATA_SIZE 0x10000
++/* Leave a chunk of memory at the top of RAM for the BIOS ACPI tables
++ * (128K) and other BIOS datastructures (less than 4K reported to be used at
++ * the moment, 32K should be enough for a while). */
++unsigned acpi_data_size = 0x20000 + 0x8000;
++void pc_set_legacy_acpi_data_size(void)
++{
++ acpi_data_size = 0x10000;
++}
++
+ #define BIOS_CFG_IOPORT 0x510
+ #define FW_CFG_ACPI_TABLES (FW_CFG_ARCH_LOCAL + 0)
+ #define FW_CFG_SMBIOS_ENTRIES (FW_CFG_ARCH_LOCAL + 1)
+@@ -811,8 +818,9 @@ static void load_linux(FWCfgState *fw_cfg,
+ initrd_max = 0x37ffffff;
+ }
+
+- if (initrd_max >= max_ram_size-ACPI_DATA_SIZE)
+- initrd_max = max_ram_size-ACPI_DATA_SIZE-1;
++ if (initrd_max >= max_ram_size - acpi_data_size) {
++ initrd_max = max_ram_size - acpi_data_size - 1;
++ }
+
+ fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_ADDR, cmdline_addr);
+ fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, strlen(kernel_cmdline)+1);
+diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
+index 9694f88..96b8a18 100644
+--- a/hw/i386/pc_piix.c
++++ b/hw/i386/pc_piix.c
+@@ -318,6 +318,7 @@ static void pc_compat_2_0(MachineState *machine)
+ legacy_acpi_table_size = 6652;
+ smbios_legacy_mode = true;
+ has_reserved_memory = false;
++ pc_set_legacy_acpi_data_size();
+ }
+
+ static void pc_compat_1_7(MachineState *machine)
+@@ -645,7 +646,7 @@ static QEMUMachine pc_machine_v1_1 = {
+ .property = "class",\
+ .value = stringify(PCI_CLASS_MEMORY_RAM),\
+ },{\
+- .driver = "apic",\
++ .driver = "apic-common",\
+ .property = "vapic",\
+ .value = "off",\
+ },{\
+diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
+index c39ee98..4e2dd49 100644
+--- a/hw/i386/pc_q35.c
++++ b/hw/i386/pc_q35.c
+@@ -282,6 +282,7 @@ static void pc_compat_2_0(MachineState *machine)
+ {
+ smbios_legacy_mode = true;
+ has_reserved_memory = false;
++ pc_set_legacy_acpi_data_size();
+ }
+
+ static void pc_compat_1_7(MachineState *machine)
+diff --git a/hw/i386/q35-acpi-dsdt.dsl b/hw/i386/q35-acpi-dsdt.dsl
+index 8c3eae7..054b035 100644
+--- a/hw/i386/q35-acpi-dsdt.dsl
++++ b/hw/i386/q35-acpi-dsdt.dsl
+@@ -410,7 +410,7 @@ DefinitionBlock (
+ /****************************************************************
+ * General purpose events
+ ****************************************************************/
+- External(\_SB.PCI0.MEMORY_HOPTLUG_DEVICE.MEMORY_SLOT_SCAN_METHOD, MethodObj)
++ External(\_SB.PCI0.MEMORY_HOTPLUG_DEVICE.MEMORY_SLOT_SCAN_METHOD, MethodObj)
+
+ Scope(\_GPE) {
+ Name(_HID, "ACPI0006")
+@@ -425,7 +425,7 @@ DefinitionBlock (
+ }
+ Method(_E03) {
+ // Memory hotplug event
+- \_SB.PCI0.MEMORY_HOPTLUG_DEVICE.MEMORY_SLOT_SCAN_METHOD()
++ \_SB.PCI0.MEMORY_HOTPLUG_DEVICE.MEMORY_SLOT_SCAN_METHOD()
+ }
+ Method(_L04) {
+ }
+diff --git a/hw/i386/smbios.c b/hw/i386/smbios.c
+index e3fa1b2..0ae5960 100644
+--- a/hw/i386/smbios.c
++++ b/hw/i386/smbios.c
+@@ -821,7 +821,7 @@ void smbios_get_tables(uint8_t **tables, size_t *tables_len,
+ smbios_build_type_2_table();
+ smbios_build_type_3_table();
+
+- smbios_smp_sockets = smp_cpus / (smp_cores * smp_threads);
++ smbios_smp_sockets = DIV_ROUND_UP(smp_cpus, smp_cores * smp_threads);
+ assert(smbios_smp_sockets >= 1);
+
+ for (i = 0; i < smbios_smp_sockets; i++) {
+diff --git a/hw/i386/ssdt-mem.dsl b/hw/i386/ssdt-mem.dsl
+index 8e17bd1..22ff5dd 100644
+--- a/hw/i386/ssdt-mem.dsl
++++ b/hw/i386/ssdt-mem.dsl
+@@ -39,10 +39,10 @@ ACPI_EXTRACT_ALL_CODE ssdm_mem_aml
+ DefinitionBlock ("ssdt-mem.aml", "SSDT", 0x02, "BXPC", "CSSDT", 0x1)
+ {
+
+- External(\_SB.PCI0.MEMORY_HOPTLUG_DEVICE.MEMORY_SLOT_CRS_METHOD, MethodObj)
+- External(\_SB.PCI0.MEMORY_HOPTLUG_DEVICE.MEMORY_SLOT_STATUS_METHOD, MethodObj)
+- External(\_SB.PCI0.MEMORY_HOPTLUG_DEVICE.MEMORY_SLOT_OST_METHOD, MethodObj)
+- External(\_SB.PCI0.MEMORY_HOPTLUG_DEVICE.MEMORY_SLOT_PROXIMITY_METHOD, MethodObj)
++ External(\_SB.PCI0.MEMORY_HOTPLUG_DEVICE.MEMORY_SLOT_CRS_METHOD, MethodObj)
++ External(\_SB.PCI0.MEMORY_HOTPLUG_DEVICE.MEMORY_SLOT_STATUS_METHOD, MethodObj)
++ External(\_SB.PCI0.MEMORY_HOTPLUG_DEVICE.MEMORY_SLOT_OST_METHOD, MethodObj)
++ External(\_SB.PCI0.MEMORY_HOTPLUG_DEVICE.MEMORY_SLOT_PROXIMITY_METHOD, MethodObj)
+
+ Scope(\_SB) {
+ /* v------------------ DO NOT EDIT ------------------v */
+@@ -58,19 +58,19 @@ DefinitionBlock ("ssdt-mem.aml", "SSDT", 0x02, "BXPC", "CSSDT", 0x1)
+ Name(_HID, EISAID("PNP0C80"))
+
+ Method(_CRS, 0) {
+- Return(\_SB.PCI0.MEMORY_HOPTLUG_DEVICE.MEMORY_SLOT_CRS_METHOD(_UID))
++ Return(\_SB.PCI0.MEMORY_HOTPLUG_DEVICE.MEMORY_SLOT_CRS_METHOD(_UID))
+ }
+
+ Method(_STA, 0) {
+- Return(\_SB.PCI0.MEMORY_HOPTLUG_DEVICE.MEMORY_SLOT_STATUS_METHOD(_UID))
++ Return(\_SB.PCI0.MEMORY_HOTPLUG_DEVICE.MEMORY_SLOT_STATUS_METHOD(_UID))
+ }
+
+ Method(_PXM, 0) {
+- Return(\_SB.PCI0.MEMORY_HOPTLUG_DEVICE.MEMORY_SLOT_PROXIMITY_METHOD(_UID))
++ Return(\_SB.PCI0.MEMORY_HOTPLUG_DEVICE.MEMORY_SLOT_PROXIMITY_METHOD(_UID))
+ }
+
+ Method(_OST, 3) {
+- \_SB.PCI0.MEMORY_HOPTLUG_DEVICE.MEMORY_SLOT_OST_METHOD(_UID, Arg0, Arg1, Arg2)
++ \_SB.PCI0.MEMORY_HOTPLUG_DEVICE.MEMORY_SLOT_OST_METHOD(_UID, Arg0, Arg1, Arg2)
+ }
+ }
+ }
+diff --git a/hw/i386/ssdt-misc.dsl b/hw/i386/ssdt-misc.dsl
+index d329b8b..0fd4480 100644
+--- a/hw/i386/ssdt-misc.dsl
++++ b/hw/i386/ssdt-misc.dsl
+@@ -120,7 +120,7 @@ DefinitionBlock ("ssdt-misc.aml", "SSDT", 0x01, "BXPC", "BXSSDTSUSP", 0x1)
+
+ External(MEMORY_SLOT_NOTIFY_METHOD, MethodObj)
+ Scope(\_SB.PCI0) {
+- Device(MEMORY_HOPTLUG_DEVICE) {
++ Device(MEMORY_HOTPLUG_DEVICE) {
+ Name(_HID, "PNP0A06")
+ Name(_UID, "Memory hotplug resources")
+
+diff --git a/hw/ide/core.c b/hw/ide/core.c
+index db191a6..fa4cafa 100644
+--- a/hw/ide/core.c
++++ b/hw/ide/core.c
+@@ -688,7 +688,8 @@ void ide_dma_cb(void *opaque, int ret)
+ sector_num, n, s->dma_cmd);
+ #endif
+
+- if (!ide_sect_range_ok(s, sector_num, n)) {
++ if ((s->dma_cmd == IDE_DMA_READ || s->dma_cmd == IDE_DMA_WRITE) &&
++ !ide_sect_range_ok(s, sector_num, n)) {
+ dma_buf_commit(s);
+ ide_dma_error(s);
+ return;
+@@ -2298,7 +2299,7 @@ static int ide_drive_post_load(void *opaque, int version_id)
+ {
+ IDEState *s = opaque;
+
+- if (s->identify_set) {
++ if (s->bs && s->identify_set) {
+ bdrv_set_enable_write_cache(s->bs, !!(s->identify_data[85] & (1 << 5)));
+ }
+ return 0;
+diff --git a/hw/m68k/an5206.c b/hw/m68k/an5206.c
+index 684496a..388420e 100644
+--- a/hw/m68k/an5206.c
++++ b/hw/m68k/an5206.c
+@@ -74,7 +74,8 @@ static void an5206_init(MachineState *machine)
+ NULL, NULL, 1, ELF_MACHINE, 0);
+ entry = elf_entry;
+ if (kernel_size < 0) {
+- kernel_size = load_uimage(kernel_filename, &entry, NULL, NULL);
++ kernel_size = load_uimage(kernel_filename, &entry, NULL, NULL,
++ NULL, NULL);
+ }
+ if (kernel_size < 0) {
+ kernel_size = load_image_targphys(kernel_filename, KERNEL_LOAD_ADDR,
+diff --git a/hw/m68k/dummy_m68k.c b/hw/m68k/dummy_m68k.c
+index 6db1b71..fb9ca0e 100644
+--- a/hw/m68k/dummy_m68k.c
++++ b/hw/m68k/dummy_m68k.c
+@@ -50,7 +50,8 @@ static void dummy_m68k_init(MachineState *machine)
+ NULL, NULL, 1, ELF_MACHINE, 0);
+ entry = elf_entry;
+ if (kernel_size < 0) {
+- kernel_size = load_uimage(kernel_filename, &entry, NULL, NULL);
++ kernel_size = load_uimage(kernel_filename, &entry, NULL, NULL,
++ NULL, NULL);
+ }
+ if (kernel_size < 0) {
+ kernel_size = load_image_targphys(kernel_filename,
+diff --git a/hw/m68k/mcf5208.c b/hw/m68k/mcf5208.c
+index 2ef617f..07683db 100644
+--- a/hw/m68k/mcf5208.c
++++ b/hw/m68k/mcf5208.c
+@@ -279,7 +279,8 @@ static void mcf5208evb_init(MachineState *machine)
+ NULL, NULL, 1, ELF_MACHINE, 0);
+ entry = elf_entry;
+ if (kernel_size < 0) {
+- kernel_size = load_uimage(kernel_filename, &entry, NULL, NULL);
++ kernel_size = load_uimage(kernel_filename, &entry, NULL, NULL,
++ NULL, NULL);
+ }
+ if (kernel_size < 0) {
+ kernel_size = load_image_targphys(kernel_filename, 0x40000000,
+diff --git a/hw/mem/pc-dimm.c b/hw/mem/pc-dimm.c
+index 08f49ed..a800ea7 100644
+--- a/hw/mem/pc-dimm.c
++++ b/hw/mem/pc-dimm.c
+@@ -252,6 +252,12 @@ static void pc_dimm_realize(DeviceState *dev, Error **errp)
+ error_setg(errp, "'" PC_DIMM_MEMDEV_PROP "' property is not set");
+ return;
+ }
++ if ((nb_numa_nodes > 0) && (dimm->node >= nb_numa_nodes)) {
++ error_setg(errp, "'DIMM property " PC_DIMM_NODE_PROP " has value %"
++ PRIu32 "' which exceeds the number of numa nodes: %d",
++ dimm->node, nb_numa_nodes);
++ return;
++ }
+ }
+
+ static MemoryRegion *pc_dimm_get_memory_region(PCDIMMDevice *dimm)
+diff --git a/hw/microblaze/boot.c b/hw/microblaze/boot.c
+index 6bf36d0..a2843cd 100644
+--- a/hw/microblaze/boot.c
++++ b/hw/microblaze/boot.c
+@@ -154,7 +154,8 @@ void microblaze_load_kernel(MicroBlazeCPU *cpu, hwaddr ddr_base,
+ if (kernel_size < 0) {
+ hwaddr uentry, loadaddr;
+
+- kernel_size = load_uimage(kernel_filename, &uentry, &loadaddr, 0);
++ kernel_size = load_uimage(kernel_filename, &uentry, &loadaddr, 0,
++ NULL, NULL);
+ boot_info.bootstrap_pc = uentry;
+ high = (loadaddr + kernel_size + 3) & ~3;
+ }
+diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
+index 768e528..7252f64 100644
+--- a/hw/misc/ivshmem.c
++++ b/hw/misc/ivshmem.c
+@@ -24,10 +24,12 @@
+ #include "migration/migration.h"
+ #include "qapi/qmp/qerror.h"
+ #include "qemu/event_notifier.h"
++#include "qemu/fifo8.h"
+ #include "sysemu/char.h"
+
+ #include <sys/mman.h>
+ #include <sys/types.h>
++#include <limits.h>
+
+ #define PCI_VENDOR_ID_IVSHMEM PCI_VENDOR_ID_REDHAT_QUMRANET
+ #define PCI_DEVICE_ID_IVSHMEM 0x1110
+@@ -73,6 +75,7 @@ typedef struct IVShmemState {
+
+ CharDriverState **eventfd_chr;
+ CharDriverState *server_chr;
++ Fifo8 incoming_fifo;
+ MemoryRegion ivshmem_mmio;
+
+ /* We might need to register the BAR before we actually have the memory.
+@@ -383,6 +386,9 @@ static void close_guest_eventfds(IVShmemState *s, int posn)
+ if (!ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) {
+ return;
+ }
++ if (posn < 0 || posn >= s->nb_peers) {
++ return;
++ }
+
+ guest_curr_max = s->peers[posn].nb_eventfds;
+
+@@ -401,14 +407,24 @@ static void close_guest_eventfds(IVShmemState *s, int posn)
+
+ /* this function increase the dynamic storage need to store data about other
+ * guests */
+-static void increase_dynamic_storage(IVShmemState *s, int new_min_size) {
++static int increase_dynamic_storage(IVShmemState *s, int new_min_size)
++{
+
+ int j, old_nb_alloc;
+
++ /* check for integer overflow */
++ if (new_min_size >= INT_MAX / sizeof(Peer) - 1 || new_min_size <= 0) {
++ return -1;
++ }
++
+ old_nb_alloc = s->nb_peers;
+
+- while (new_min_size >= s->nb_peers)
+- s->nb_peers = s->nb_peers * 2;
++ if (new_min_size >= s->nb_peers) {
++ /* +1 because #new_min_size is used as last array index */
++ s->nb_peers = new_min_size + 1;
++ } else {
++ return 0;
++ }
+
+ IVSHMEM_DPRINTF("bumping storage to %d guests\n", s->nb_peers);
+ s->peers = g_realloc(s->peers, s->nb_peers * sizeof(Peer));
+@@ -418,23 +434,57 @@ static void increase_dynamic_storage(IVShmemState *s, int new_min_size) {
+ s->peers[j].eventfds = NULL;
+ s->peers[j].nb_eventfds = 0;
+ }
++
++ return 0;
+ }
+
+-static void ivshmem_read(void *opaque, const uint8_t * buf, int flags)
++static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
+ {
+ IVShmemState *s = opaque;
+ int incoming_fd, tmp_fd;
+ int guest_max_eventfd;
+ long incoming_posn;
+
+- memcpy(&incoming_posn, buf, sizeof(long));
++ if (fifo8_is_empty(&s->incoming_fifo) && size == sizeof(incoming_posn)) {
++ memcpy(&incoming_posn, buf, size);
++ } else {
++ const uint8_t *p;
++ uint32_t num;
++
++ IVSHMEM_DPRINTF("short read of %d bytes\n", size);
++ num = MAX(size, sizeof(long) - fifo8_num_used(&s->incoming_fifo));
++ fifo8_push_all(&s->incoming_fifo, buf, num);
++ if (fifo8_num_used(&s->incoming_fifo) < sizeof(incoming_posn)) {
++ return;
++ }
++ size -= num;
++ buf += num;
++ p = fifo8_pop_buf(&s->incoming_fifo, sizeof(incoming_posn), &num);
++ g_assert(num == sizeof(incoming_posn));
++ memcpy(&incoming_posn, p, sizeof(incoming_posn));
++ if (size > 0) {
++ fifo8_push_all(&s->incoming_fifo, buf, size);
++ }
++ }
++
++ if (incoming_posn < -1) {
++ IVSHMEM_DPRINTF("invalid incoming_posn %ld\n", incoming_posn);
++ return;
++ }
++
+ /* pick off s->server_chr->msgfd and store it, posn should accompany msg */
+ tmp_fd = qemu_chr_fe_get_msgfd(s->server_chr);
+ IVSHMEM_DPRINTF("posn is %ld, fd is %d\n", incoming_posn, tmp_fd);
+
+ /* make sure we have enough space for this guest */
+ if (incoming_posn >= s->nb_peers) {
+- increase_dynamic_storage(s, incoming_posn);
++ if (increase_dynamic_storage(s, incoming_posn) < 0) {
++ error_report("increase_dynamic_storage() failed");
++ if (tmp_fd != -1) {
++ close(tmp_fd);
++ }
++ return;
++ }
+ }
+
+ if (tmp_fd == -1) {
+@@ -458,6 +508,7 @@ static void ivshmem_read(void *opaque, const uint8_t * buf, int flags)
+ if (incoming_fd == -1) {
+ fprintf(stderr, "could not allocate file descriptor %s\n",
+ strerror(errno));
++ close(tmp_fd);
+ return;
+ }
+
+@@ -659,6 +710,8 @@ static int pci_ivshmem_init(PCIDevice *dev)
+ s->ivshmem_size = ivshmem_get_size(s);
+ }
+
++ fifo8_create(&s->incoming_fifo, sizeof(long));
++
+ register_savevm(DEVICE(dev), "ivshmem", 0, 0, ivshmem_save, ivshmem_load,
+ dev);
+
+@@ -795,6 +848,7 @@ static void pci_ivshmem_uninit(PCIDevice *dev)
+ memory_region_destroy(&s->ivshmem);
+ memory_region_destroy(&s->bar);
+ unregister_savevm(DEVICE(dev), "ivshmem", s);
++ fifo8_destroy(&s->incoming_fifo);
+ }
+
+ static Property ivshmem_properties[] = {
+diff --git a/hw/misc/vfio.c b/hw/misc/vfio.c
+index 0b9eba0..e88b610 100644
+--- a/hw/misc/vfio.c
++++ b/hw/misc/vfio.c
+@@ -120,11 +120,20 @@ typedef struct VFIOINTx {
+ } VFIOINTx;
+
+ typedef struct VFIOMSIVector {
+- EventNotifier interrupt; /* eventfd triggered on interrupt */
+- EventNotifier kvm_interrupt; /* eventfd triggered for KVM irqfd bypass */
++ /*
++ * Two interrupt paths are configured per vector. The first, is only used
++ * for interrupts injected via QEMU. This is typically the non-accel path,
++ * but may also be used when we want QEMU to handle masking and pending
++ * bits. The KVM path bypasses QEMU and is therefore higher performance,
++ * but requires masking at the device. virq is used to track the MSI route
++ * through KVM, thus kvm_interrupt is only available when virq is set to a
++ * valid (>= 0) value.
++ */
++ EventNotifier interrupt;
++ EventNotifier kvm_interrupt;
+ struct VFIODevice *vdev; /* back pointer to device */
+ MSIMessage msg; /* cache the MSI message so we know when it changes */
+- int virq; /* KVM irqchip route for QEMU bypass */
++ int virq;
+ bool use;
+ } VFIOMSIVector;
+
+@@ -681,13 +690,24 @@ static int vfio_enable_vectors(VFIODevice *vdev, bool msix)
+ fds = (int32_t *)&irq_set->data;
+
+ for (i = 0; i < vdev->nr_vectors; i++) {
+- if (!vdev->msi_vectors[i].use) {
+- fds[i] = -1;
+- } else if (vdev->msi_vectors[i].virq >= 0) {
+- fds[i] = event_notifier_get_fd(&vdev->msi_vectors[i].kvm_interrupt);
+- } else {
+- fds[i] = event_notifier_get_fd(&vdev->msi_vectors[i].interrupt);
++ int fd = -1;
++
++ /*
++ * MSI vs MSI-X - The guest has direct access to MSI mask and pending
++ * bits, therefore we always use the KVM signaling path when setup.
++ * MSI-X mask and pending bits are emulated, so we want to use the
++ * KVM signaling path only when configured and unmasked.
++ */
++ if (vdev->msi_vectors[i].use) {
++ if (vdev->msi_vectors[i].virq < 0 ||
++ (msix && msix_is_masked(&vdev->pdev, i))) {
++ fd = event_notifier_get_fd(&vdev->msi_vectors[i].interrupt);
++ } else {
++ fd = event_notifier_get_fd(&vdev->msi_vectors[i].kvm_interrupt);
++ }
+ }
++
++ fds[i] = fd;
+ }
+
+ ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set);
+diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
+index f87c798..7e3386d 100644
+--- a/hw/net/vhost_net.c
++++ b/hw/net/vhost_net.c
+@@ -115,6 +115,7 @@ unsigned vhost_net_get_features(struct vhost_net *net, unsigned features)
+
+ void vhost_net_ack_features(struct vhost_net *net, unsigned features)
+ {
++ net->dev.acked_features = net->dev.backend_features;
+ vhost_ack_features(&net->dev, vhost_net_get_feature_bits(net), features);
+ }
+
+@@ -162,11 +163,11 @@ struct vhost_net *vhost_net_init(VhostNetOptions *options)
+ if (r < 0) {
+ goto fail;
+ }
+- if (!qemu_has_vnet_hdr_len(options->net_backend,
+- sizeof(struct virtio_net_hdr_mrg_rxbuf))) {
+- net->dev.features &= ~(1 << VIRTIO_NET_F_MRG_RXBUF);
+- }
+ if (backend_kernel) {
++ if (!qemu_has_vnet_hdr_len(options->net_backend,
++ sizeof(struct virtio_net_hdr_mrg_rxbuf))) {
++ net->dev.features &= ~(1 << VIRTIO_NET_F_MRG_RXBUF);
++ }
+ if (~net->dev.features & net->dev.backend_features) {
+ fprintf(stderr, "vhost lacks feature mask %" PRIu64
+ " for backend\n",
+@@ -188,9 +189,13 @@ bool vhost_net_query(VHostNetState *net, VirtIODevice *dev)
+ return vhost_dev_query(&net->dev, dev);
+ }
+
++static void vhost_net_set_vq_index(struct vhost_net *net, int vq_index)
++{
++ net->dev.vq_index = vq_index;
++}
++
+ static int vhost_net_start_one(struct vhost_net *net,
+- VirtIODevice *dev,
+- int vq_index)
++ VirtIODevice *dev)
+ {
+ struct vhost_vring_file file = { };
+ int r;
+@@ -201,7 +206,6 @@ static int vhost_net_start_one(struct vhost_net *net,
+
+ net->dev.nvqs = 2;
+ net->dev.vqs = net->vqs;
+- net->dev.vq_index = vq_index;
+
+ r = vhost_dev_enable_notifiers(&net->dev, dev);
+ if (r < 0) {
+@@ -294,7 +298,7 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs,
+ BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(dev)));
+ VirtioBusState *vbus = VIRTIO_BUS(qbus);
+ VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus);
+- int r, i = 0;
++ int r, e, i;
+
+ if (!vhost_net_device_endian_ok(dev)) {
+ error_report("vhost-net does not support cross-endian");
+@@ -309,11 +313,7 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs,
+ }
+
+ for (i = 0; i < total_queues; i++) {
+- r = vhost_net_start_one(get_vhost_net(ncs[i].peer), dev, i * 2);
+-
+- if (r < 0) {
+- goto err;
+- }
++ vhost_net_set_vq_index(get_vhost_net(ncs[i].peer), i * 2);
+ }
+
+ r = k->set_guest_notifiers(qbus->parent, total_queues * 2, true);
+@@ -322,12 +322,26 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs,
+ goto err;
+ }
+
++ for (i = 0; i < total_queues; i++) {
++ r = vhost_net_start_one(get_vhost_net(ncs[i].peer), dev);
++
++ if (r < 0) {
++ goto err_start;
++ }
++ }
++
+ return 0;
+
+-err:
++err_start:
+ while (--i >= 0) {
+ vhost_net_stop_one(get_vhost_net(ncs[i].peer), dev);
+ }
++ e = k->set_guest_notifiers(qbus->parent, total_queues * 2, false);
++ if (e < 0) {
++ fprintf(stderr, "vhost guest notifier cleanup failed: %d\n", e);
++ fflush(stderr);
++ }
++err:
+ return r;
+ }
+
+@@ -339,16 +353,16 @@ void vhost_net_stop(VirtIODevice *dev, NetClientState *ncs,
+ VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus);
+ int i, r;
+
++ for (i = 0; i < total_queues; i++) {
++ vhost_net_stop_one(get_vhost_net(ncs[i].peer), dev);
++ }
++
+ r = k->set_guest_notifiers(qbus->parent, total_queues * 2, false);
+ if (r < 0) {
+ fprintf(stderr, "vhost guest notifier cleanup failed: %d\n", r);
+ fflush(stderr);
+ }
+ assert(r >= 0);
+-
+- for (i = 0; i < total_queues; i++) {
+- vhost_net_stop_one(get_vhost_net(ncs[i].peer), dev);
+- }
+ }
+
+ void vhost_net_cleanup(struct vhost_net *net)
+diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
+index 268eff9..6360374 100644
+--- a/hw/net/virtio-net.c
++++ b/hw/net/virtio-net.c
+@@ -125,10 +125,23 @@ static void virtio_net_vhost_status(VirtIONet *n, uint8_t status)
+ return;
+ }
+ if (!n->vhost_started) {
+- int r;
++ int r, i;
++
+ if (!vhost_net_query(get_vhost_net(nc->peer), vdev)) {
+ return;
+ }
++
++ /* Any packets outstanding? Purge them to avoid touching rings
++ * when vhost is running.
++ */
++ for (i = 0; i < queues; i++) {
++ NetClientState *qnc = qemu_get_subqueue(n->nic, i);
++
++ /* Purge both directions: TX and RX. */
++ qemu_net_queue_purge(qnc->peer->incoming_queue, qnc);
++ qemu_net_queue_purge(qnc->incoming_queue, qnc->peer);
++ }
++
+ n->vhost_started = 1;
+ r = vhost_net_start(vdev, n->nic->ncs, queues);
+ if (r < 0) {
+@@ -785,7 +798,7 @@ static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
+ virtio_net_ctrl_ack status = VIRTIO_NET_ERR;
+ VirtQueueElement elem;
+ size_t s;
+- struct iovec *iov;
++ struct iovec *iov, *iov2;
+ unsigned int iov_cnt;
+
+ while (virtqueue_pop(vq, &elem)) {
+@@ -795,8 +808,8 @@ static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
+ exit(1);
+ }
+
+- iov = elem.out_sg;
+ iov_cnt = elem.out_num;
++ iov2 = iov = g_memdup(elem.out_sg, sizeof(struct iovec) * elem.out_num);
+ s = iov_to_buf(iov, iov_cnt, 0, &ctrl, sizeof(ctrl));
+ iov_discard_front(&iov, &iov_cnt, sizeof(ctrl));
+ if (s != sizeof(ctrl)) {
+@@ -820,6 +833,7 @@ static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
+
+ virtqueue_push(vq, &elem, sizeof(status));
+ virtio_notify(vdev, vq);
++ g_free(iov2);
+ }
+ }
+
+@@ -1112,8 +1126,6 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q)
+ return num_packets;
+ }
+
+- assert(vdev->vm_running);
+-
+ if (q->async_tx.elem.out_num) {
+ virtio_queue_set_notification(q->tx_vq, 0);
+ return num_packets;
+@@ -1224,7 +1236,12 @@ static void virtio_net_tx_timer(void *opaque)
+ VirtIONetQueue *q = opaque;
+ VirtIONet *n = q->n;
+ VirtIODevice *vdev = VIRTIO_DEVICE(n);
+- assert(vdev->vm_running);
++ /* This happens when device was stopped but BH wasn't. */
++ if (!vdev->vm_running) {
++ /* Make sure tx waiting is set, so we'll run when restarted. */
++ assert(q->tx_waiting);
++ return;
++ }
+
+ q->tx_waiting = 0;
+
+@@ -1244,7 +1261,12 @@ static void virtio_net_tx_bh(void *opaque)
+ VirtIODevice *vdev = VIRTIO_DEVICE(n);
+ int32_t ret;
+
+- assert(vdev->vm_running);
++ /* This happens when device was stopped but BH wasn't. */
++ if (!vdev->vm_running) {
++ /* Make sure tx waiting is set, so we'll run when restarted. */
++ assert(q->tx_waiting);
++ return;
++ }
+
+ q->tx_waiting = 0;
+
+diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c
+index 77bea6f..ae3e50f 100644
+--- a/hw/net/vmxnet3.c
++++ b/hw/net/vmxnet3.c
+@@ -34,6 +34,7 @@
+
+ #define PCI_DEVICE_ID_VMWARE_VMXNET3_REVISION 0x1
+ #define VMXNET3_MSIX_BAR_SIZE 0x2000
++#define MIN_BUF_SIZE 60
+
+ #define VMXNET3_BAR0_IDX (0)
+ #define VMXNET3_BAR1_IDX (1)
+@@ -1871,12 +1872,21 @@ vmxnet3_receive(NetClientState *nc, const uint8_t *buf, size_t size)
+ {
+ VMXNET3State *s = qemu_get_nic_opaque(nc);
+ size_t bytes_indicated;
++ uint8_t min_buf[MIN_BUF_SIZE];
+
+ if (!vmxnet3_can_receive(nc)) {
+ VMW_PKPRN("Cannot receive now");
+ return -1;
+ }
+
++ /* Pad to minimum Ethernet frame length */
++ if (size < sizeof(min_buf)) {
++ memcpy(min_buf, buf, size);
++ memset(&min_buf[size], 0, sizeof(min_buf) - size);
++ buf = min_buf;
++ size = sizeof(min_buf);
++ }
++
+ if (s->peer_has_vhdr) {
+ vmxnet_rx_pkt_set_vhdr(s->rx_pkt, (struct virtio_net_hdr *)buf);
+ buf += sizeof(struct virtio_net_hdr);
+diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c
+index b2b4f9b..123cf4d 100644
+--- a/hw/openrisc/openrisc_sim.c
++++ b/hw/openrisc/openrisc_sim.c
+@@ -72,7 +72,7 @@ static void cpu_openrisc_load_kernel(ram_addr_t ram_size,
+ entry = elf_entry;
+ if (kernel_size < 0) {
+ kernel_size = load_uimage(kernel_filename,
+- &entry, NULL, NULL);
++ &entry, NULL, NULL, NULL, NULL);
+ }
+ if (kernel_size < 0) {
+ kernel_size = load_image_targphys(kernel_filename,
+diff --git a/hw/pci/msi.c b/hw/pci/msi.c
+index a4a3040..52d2313 100644
+--- a/hw/pci/msi.c
++++ b/hw/pci/msi.c
+@@ -291,7 +291,7 @@ void msi_notify(PCIDevice *dev, unsigned int vector)
+ "notify vector 0x%x"
+ " address: 0x%"PRIx64" data: 0x%"PRIx32"\n",
+ vector, msg.address, msg.data);
+- stl_le_phys(&address_space_memory, msg.address, msg.data);
++ stl_le_phys(&dev->bus_master_as, msg.address, msg.data);
+ }
+
+ /* Normally called by pci_default_write_config(). */
+diff --git a/hw/pci/msix.c b/hw/pci/msix.c
+index 5c49bfc..20ae476 100644
+--- a/hw/pci/msix.c
++++ b/hw/pci/msix.c
+@@ -439,7 +439,7 @@ void msix_notify(PCIDevice *dev, unsigned vector)
+
+ msg = msix_get_message(dev, vector);
+
+- stl_le_phys(&address_space_memory, msg.address, msg.data);
++ stl_le_phys(&dev->bus_master_as, msg.address, msg.data);
+ }
+
+ void msix_reset(PCIDevice *dev)
+diff --git a/hw/pci/pci.c b/hw/pci/pci.c
+index 351d320..42995e6 100644
+--- a/hw/pci/pci.c
++++ b/hw/pci/pci.c
+@@ -1147,9 +1147,10 @@ uint32_t pci_default_read_config(PCIDevice *d,
+ return le32_to_cpu(val);
+ }
+
+-void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l)
++void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val_in, int l)
+ {
+ int i, was_irq_disabled = pci_irq_disabled(d);
++ uint32_t val = val_in;
+
+ for (i = 0; i < l; val >>= 8, ++i) {
+ uint8_t wmask = d->wmask[addr + i];
+@@ -1171,8 +1172,8 @@ void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l)
+ & PCI_COMMAND_MASTER);
+ }
+
+- msi_write_config(d, addr, val, l);
+- msix_write_config(d, addr, val, l);
++ msi_write_config(d, addr, val_in, l);
++ msix_write_config(d, addr, val_in, l);
+ }
+
+ /***********************************************************/
+diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
+index 1a5b30d..c268b91 100644
+--- a/hw/ppc/e500.c
++++ b/hw/ppc/e500.c
+@@ -830,7 +830,8 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
+ * Hrm. No ELF image? Try a uImage, maybe someone is giving us an
+ * ePAPR compliant kernel
+ */
+- kernel_size = load_uimage(filename, &bios_entry, &loadaddr, NULL);
++ kernel_size = load_uimage(filename, &bios_entry, &loadaddr, NULL,
++ NULL, NULL);
+ if (kernel_size < 0) {
+ fprintf(stderr, "qemu: could not load firmware '%s'\n", filename);
+ exit(1);
+diff --git a/hw/ppc/ppc440_bamboo.c b/hw/ppc/ppc440_bamboo.c
+index 81a06d3..778970a 100644
+--- a/hw/ppc/ppc440_bamboo.c
++++ b/hw/ppc/ppc440_bamboo.c
+@@ -253,7 +253,8 @@ static void bamboo_init(MachineState *machine)
+
+ /* Load kernel. */
+ if (kernel_filename) {
+- success = load_uimage(kernel_filename, &entry, &loadaddr, NULL);
++ success = load_uimage(kernel_filename, &entry, &loadaddr, NULL,
++ NULL, NULL);
+ if (success < 0) {
+ success = load_elf(kernel_filename, NULL, NULL, &elf_entry,
+ &elf_lowaddr, NULL, 1, ELF_MACHINE, 0);
+diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
+index d01978f..4196a70 100644
+--- a/hw/ppc/spapr.c
++++ b/hw/ppc/spapr.c
+@@ -1377,7 +1377,6 @@ static void ppc_spapr_init(MachineState *machine)
+ spapr_create_nvram(spapr);
+
+ /* Set up PCI */
+- spapr_pci_msi_init(spapr, SPAPR_PCI_MSI_WINDOW);
+ spapr_pci_rtas_init();
+
+ phb = spapr_create_phb(spapr, 0);
+diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c
+index f6e32a4..067796d 100644
+--- a/hw/ppc/spapr_iommu.c
++++ b/hw/ppc/spapr_iommu.c
+@@ -172,9 +172,9 @@ sPAPRTCETable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn,
+ return tcet;
+ }
+
+-static void spapr_tce_table_finalize(Object *obj)
++static void spapr_tce_table_unrealize(DeviceState *dev, Error **errp)
+ {
+- sPAPRTCETable *tcet = SPAPR_TCE_TABLE(obj);
++ sPAPRTCETable *tcet = SPAPR_TCE_TABLE(dev);
+
+ QLIST_REMOVE(tcet, list);
+
+@@ -419,6 +419,7 @@ static void spapr_tce_table_class_init(ObjectClass *klass, void *data)
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ dc->init = spapr_tce_table_realize;
+ dc->reset = spapr_tce_reset;
++ dc->unrealize = spapr_tce_table_unrealize;
+
+ QLIST_INIT(&spapr_tce_tables);
+
+@@ -434,7 +435,6 @@ static TypeInfo spapr_tce_table_info = {
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(sPAPRTCETable),
+ .class_init = spapr_tce_table_class_init,
+- .instance_finalize = spapr_tce_table_finalize,
+ };
+
+ static void register_types(void)
+diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
+index 9ed39a9..7c18e68 100644
+--- a/hw/ppc/spapr_pci.c
++++ b/hw/ppc/spapr_pci.c
+@@ -341,7 +341,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPREnvironment *spapr,
+ }
+
+ /* Setup MSI/MSIX vectors in the device (via cfgspace or MSIX BAR) */
+- spapr_msi_setmsg(pdev, spapr->msi_win_addr, ret_intr_type == RTAS_TYPE_MSIX,
++ spapr_msi_setmsg(pdev, SPAPR_PCI_MSI_WINDOW, ret_intr_type == RTAS_TYPE_MSIX,
+ irq, req_num);
+
+ /* Add MSI device to cache */
+@@ -465,34 +465,6 @@ static const MemoryRegionOps spapr_msi_ops = {
+ .endianness = DEVICE_LITTLE_ENDIAN
+ };
+
+-void spapr_pci_msi_init(sPAPREnvironment *spapr, hwaddr addr)
+-{
+- uint64_t window_size = 4096;
+-
+- /*
+- * As MSI/MSIX interrupts trigger by writing at MSI/MSIX vectors,
+- * we need to allocate some memory to catch those writes coming
+- * from msi_notify()/msix_notify().
+- * As MSIMessage:addr is going to be the same and MSIMessage:data
+- * is going to be a VIRQ number, 4 bytes of the MSI MR will only
+- * be used.
+- *
+- * For KVM we want to ensure that this memory is a full page so that
+- * our memory slot is of page size granularity.
+- */
+-#ifdef CONFIG_KVM
+- if (kvm_enabled()) {
+- window_size = getpagesize();
+- }
+-#endif
+-
+- spapr->msi_win_addr = addr;
+- memory_region_init_io(&spapr->msiwindow, NULL, &spapr_msi_ops, spapr,
+- "msi", window_size);
+- memory_region_add_subregion(get_system_memory(), spapr->msi_win_addr,
+- &spapr->msiwindow);
+-}
+-
+ /*
+ * PHB PCI device
+ */
+@@ -512,6 +484,7 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
+ char *namebuf;
+ int i;
+ PCIBus *bus;
++ uint64_t msi_window_size = 4096;
+
+ if (sphb->index != -1) {
+ hwaddr windows_base;
+@@ -604,6 +577,28 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
+ address_space_init(&sphb->iommu_as, &sphb->iommu_root,
+ sphb->dtbusname);
+
++ /*
++ * As MSI/MSIX interrupts trigger by writing at MSI/MSIX vectors,
++ * we need to allocate some memory to catch those writes coming
++ * from msi_notify()/msix_notify().
++ * As MSIMessage:addr is going to be the same and MSIMessage:data
++ * is going to be a VIRQ number, 4 bytes of the MSI MR will only
++ * be used.
++ *
++ * For KVM we want to ensure that this memory is a full page so that
++ * our memory slot is of page size granularity.
++ */
++#ifdef CONFIG_KVM
++ if (kvm_enabled()) {
++ msi_window_size = getpagesize();
++ }
++#endif
++
++ memory_region_init_io(&sphb->msiwindow, NULL, &spapr_msi_ops, spapr,
++ "msi", msi_window_size);
++ memory_region_add_subregion(&sphb->iommu_root, SPAPR_PCI_MSI_WINDOW,
++ &sphb->msiwindow);
++
+ pci_setup_iommu(bus, spapr_pci_dma_iommu, sphb);
+
+ pci_bus_set_route_irq_fn(bus, spapr_route_intx_pin_to_irq);
+@@ -705,28 +700,34 @@ static const VMStateDescription vmstate_spapr_pci_msi = {
+ },
+ };
+
++static void spapr_pci_fill_msi_devs(gpointer key, gpointer value,
++ gpointer opaque)
++{
++ sPAPRPHBState *sphb = opaque;
++
++ sphb->msi_devs[sphb->msi_devs_num].key = *(uint32_t *)key;
++ sphb->msi_devs[sphb->msi_devs_num].value = *(spapr_pci_msi *)value;
++ sphb->msi_devs_num++;
++}
++
+ static void spapr_pci_pre_save(void *opaque)
+ {
+ sPAPRPHBState *sphb = opaque;
+- GHashTableIter iter;
+- gpointer key, value;
+- int i;
++ int msi_devs_num;
+
+ if (sphb->msi_devs) {
+ g_free(sphb->msi_devs);
+ sphb->msi_devs = NULL;
+ }
+- sphb->msi_devs_num = g_hash_table_size(sphb->msi);
+- if (!sphb->msi_devs_num) {
++ sphb->msi_devs_num = 0;
++ msi_devs_num = g_hash_table_size(sphb->msi);
++ if (!msi_devs_num) {
+ return;
+ }
+- sphb->msi_devs = g_malloc(sphb->msi_devs_num * sizeof(spapr_pci_msi_mig));
++ sphb->msi_devs = g_malloc(msi_devs_num * sizeof(spapr_pci_msi_mig));
+
+- g_hash_table_iter_init(&iter, sphb->msi);
+- for (i = 0; g_hash_table_iter_next(&iter, &key, &value); ++i) {
+- sphb->msi_devs[i].key = *(uint32_t *) key;
+- sphb->msi_devs[i].value = *(spapr_pci_msi *) value;
+- }
++ g_hash_table_foreach(sphb->msi, spapr_pci_fill_msi_devs, sphb);
++ assert(sphb->msi_devs_num == msi_devs_num);
+ }
+
+ static int spapr_pci_post_load(void *opaque, int version_id)
+diff --git a/hw/s390x/s390-virtio-bus.c b/hw/s390x/s390-virtio-bus.c
+index 6b6fb61..ca682bb 100644
+--- a/hw/s390x/s390-virtio-bus.c
++++ b/hw/s390x/s390-virtio-bus.c
+@@ -161,6 +161,8 @@ static void s390_virtio_net_instance_init(Object *obj)
+ VirtIONetS390 *dev = VIRTIO_NET_S390(obj);
+ object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_NET);
+ object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
++ object_unref(OBJECT(&dev->vdev));
++ qdev_alias_all_properties(DEVICE(&dev->vdev), obj);
+ }
+
+ static int s390_virtio_blk_init(VirtIOS390Device *s390_dev)
+@@ -224,6 +226,8 @@ static void s390_virtio_serial_instance_init(Object *obj)
+ VirtIOSerialS390 *dev = VIRTIO_SERIAL_S390(obj);
+ object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SERIAL);
+ object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
++ qdev_alias_all_properties(DEVICE(&dev->vdev), obj);
++ object_unref(OBJECT(&dev->vdev));
+ }
+
+ static int s390_virtio_scsi_init(VirtIOS390Device *s390_dev)
+@@ -256,6 +260,8 @@ static void s390_virtio_scsi_instance_init(Object *obj)
+ VirtIOSCSIS390 *dev = VIRTIO_SCSI_S390(obj);
+ object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SCSI);
+ object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
++ object_unref(OBJECT(&dev->vdev));
++ qdev_alias_all_properties(DEVICE(&dev->vdev), obj);
+ }
+
+ #ifdef CONFIG_VHOST_SCSI
+@@ -277,6 +283,8 @@ static void s390_vhost_scsi_instance_init(Object *obj)
+ VHostSCSIS390 *dev = VHOST_SCSI_S390(obj);
+ object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VHOST_SCSI);
+ object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
++ object_unref(OBJECT(&dev->vdev));
++ qdev_alias_all_properties(DEVICE(&dev->vdev), obj);
+ }
+ #endif
+
+@@ -303,6 +311,8 @@ static void s390_virtio_rng_instance_init(Object *obj)
+ VirtIORNGS390 *dev = VIRTIO_RNG_S390(obj);
+ object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_RNG);
+ object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
++ qdev_alias_all_properties(DEVICE(&dev->vdev), obj);
++ object_unref(OBJECT(&dev->vdev));
+ object_property_add_link(obj, "rng", TYPE_RNG_BACKEND,
+ (Object **)&dev->vdev.conf.rng,
+ qdev_prop_allow_set_link_before_realize,
+@@ -493,10 +503,8 @@ static unsigned virtio_s390_get_features(DeviceState *d)
+ /**************** S390 Virtio Bus Device Descriptions *******************/
+
+ static Property s390_virtio_net_properties[] = {
+- DEFINE_NIC_PROPERTIES(VirtIONetS390, vdev.nic_conf),
+ DEFINE_VIRTIO_COMMON_FEATURES(VirtIOS390Device, host_features),
+ DEFINE_VIRTIO_NET_FEATURES(VirtIOS390Device, host_features),
+- DEFINE_VIRTIO_NET_PROPERTIES(VirtIONetS390, vdev.net_conf),
+ DEFINE_PROP_END_OF_LIST(),
+ };
+
+@@ -533,7 +541,6 @@ static const TypeInfo s390_virtio_blk = {
+ };
+
+ static Property s390_virtio_serial_properties[] = {
+- DEFINE_VIRTIO_SERIAL_PROPERTIES(VirtIOSerialS390, vdev.serial),
+ DEFINE_PROP_END_OF_LIST(),
+ };
+
+@@ -556,7 +563,6 @@ static const TypeInfo s390_virtio_serial = {
+
+ static Property s390_virtio_rng_properties[] = {
+ DEFINE_VIRTIO_COMMON_FEATURES(VirtIOS390Device, host_features),
+- DEFINE_VIRTIO_RNG_PROPERTIES(VirtIORNGS390, vdev.conf),
+ DEFINE_PROP_END_OF_LIST(),
+ };
+
+@@ -614,7 +620,6 @@ static const TypeInfo virtio_s390_device_info = {
+ };
+
+ static Property s390_virtio_scsi_properties[] = {
+- DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOSCSIS390, vdev.parent_obj.conf),
+ DEFINE_VIRTIO_COMMON_FEATURES(VirtIOS390Device, host_features),
+ DEFINE_VIRTIO_SCSI_FEATURES(VirtIOS390Device, host_features),
+ DEFINE_PROP_END_OF_LIST(),
+@@ -640,7 +645,6 @@ static const TypeInfo s390_virtio_scsi = {
+ #ifdef CONFIG_VHOST_SCSI
+ static Property s390_vhost_scsi_properties[] = {
+ DEFINE_VIRTIO_COMMON_FEATURES(VirtIOS390Device, host_features),
+- DEFINE_VHOST_SCSI_PROPERTIES(VHostSCSIS390, vdev.parent_obj.conf),
+ DEFINE_PROP_END_OF_LIST(),
+ };
+
+diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c
+index 33a1d86..c074f64 100644
+--- a/hw/s390x/virtio-ccw.c
++++ b/hw/s390x/virtio-ccw.c
+@@ -794,6 +794,8 @@ static void virtio_ccw_net_instance_init(Object *obj)
+ VirtIONetCcw *dev = VIRTIO_NET_CCW(obj);
+ object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_NET);
+ object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
++ object_unref(OBJECT(&dev->vdev));
++ qdev_alias_all_properties(DEVICE(&dev->vdev), obj);
+ }
+
+ static int virtio_ccw_blk_init(VirtioCcwDevice *ccw_dev)
+@@ -850,6 +852,8 @@ static void virtio_ccw_serial_instance_init(Object *obj)
+ VirtioSerialCcw *dev = VIRTIO_SERIAL_CCW(obj);
+ object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SERIAL);
+ object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
++ qdev_alias_all_properties(DEVICE(&dev->vdev), obj);
++ object_unref(OBJECT(&dev->vdev));
+ }
+
+ static int virtio_ccw_balloon_init(VirtioCcwDevice *ccw_dev)
+@@ -896,7 +900,7 @@ static void virtio_ccw_balloon_instance_init(Object *obj)
+ VirtIOBalloonCcw *dev = VIRTIO_BALLOON_CCW(obj);
+ object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_BALLOON);
+ object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
+-
++ object_unref(OBJECT(&dev->vdev));
+ object_property_add(obj, "guest-stats", "guest statistics",
+ balloon_ccw_stats_get_all, NULL, NULL, dev, NULL);
+
+@@ -936,6 +940,8 @@ static void virtio_ccw_scsi_instance_init(Object *obj)
+ VirtIOSCSICcw *dev = VIRTIO_SCSI_CCW(obj);
+ object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SCSI);
+ object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
++ object_unref(OBJECT(&dev->vdev));
++ qdev_alias_all_properties(DEVICE(&dev->vdev), obj);
+ }
+
+ #ifdef CONFIG_VHOST_SCSI
+@@ -957,6 +963,8 @@ static void vhost_ccw_scsi_instance_init(Object *obj)
+ VHostSCSICcw *dev = VHOST_SCSI_CCW(obj);
+ object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VHOST_SCSI);
+ object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
++ object_unref(OBJECT(&dev->vdev));
++ qdev_alias_all_properties(DEVICE(&dev->vdev), obj);
+ }
+ #endif
+
+@@ -1374,8 +1382,6 @@ static int virtio_ccw_load_config(DeviceState *d, QEMUFile *f)
+ static Property virtio_ccw_net_properties[] = {
+ DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
+ DEFINE_VIRTIO_NET_FEATURES(VirtioCcwDevice, host_features[0]),
+- DEFINE_VIRTIO_NET_PROPERTIES(VirtIONetCcw, vdev.net_conf),
+- DEFINE_NIC_PROPERTIES(VirtIONetCcw, vdev.nic_conf),
+ DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
+ VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
+ DEFINE_PROP_END_OF_LIST(),
+@@ -1428,7 +1434,6 @@ static const TypeInfo virtio_ccw_blk = {
+
+ static Property virtio_ccw_serial_properties[] = {
+ DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
+- DEFINE_VIRTIO_SERIAL_PROPERTIES(VirtioSerialCcw, vdev.serial),
+ DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
+ VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
+ DEFINE_PROP_END_OF_LIST(),
+@@ -1481,7 +1486,6 @@ static const TypeInfo virtio_ccw_balloon = {
+
+ static Property virtio_ccw_scsi_properties[] = {
+ DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
+- DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOSCSICcw, vdev.parent_obj.conf),
+ DEFINE_VIRTIO_SCSI_FEATURES(VirtioCcwDevice, host_features[0]),
+ DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
+ VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
+@@ -1510,7 +1514,6 @@ static const TypeInfo virtio_ccw_scsi = {
+ #ifdef CONFIG_VHOST_SCSI
+ static Property vhost_ccw_scsi_properties[] = {
+ DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
+- DEFINE_VHOST_SCSI_PROPERTIES(VirtIOSCSICcw, vdev.parent_obj.conf),
+ DEFINE_PROP_END_OF_LIST(),
+ };
+
+@@ -1539,6 +1542,8 @@ static void virtio_ccw_rng_instance_init(Object *obj)
+ VirtIORNGCcw *dev = VIRTIO_RNG_CCW(obj);
+ object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_RNG);
+ object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
++ qdev_alias_all_properties(DEVICE(&dev->vdev), obj);
++ object_unref(OBJECT(&dev->vdev));
+ object_property_add_link(obj, "rng", TYPE_RNG_BACKEND,
+ (Object **)&dev->vdev.conf.rng,
+ qdev_prop_allow_set_link_before_realize,
+@@ -1547,7 +1552,6 @@ static void virtio_ccw_rng_instance_init(Object *obj)
+
+ static Property virtio_ccw_rng_properties[] = {
+ DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
+- DEFINE_VIRTIO_RNG_PROPERTIES(VirtIORNGCcw, vdev.conf),
+ DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
+ VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
+ DEFINE_PROP_END_OF_LIST(),
+diff --git a/hw/scsi/esp-pci.c b/hw/scsi/esp-pci.c
+index 9971bbf..32849bd 100644
+--- a/hw/scsi/esp-pci.c
++++ b/hw/scsi/esp-pci.c
+@@ -268,6 +268,8 @@ static void esp_pci_dma_memory_rw(PCIESPState *pci, uint8_t *buf, int len,
+ /* update status registers */
+ pci->dma_regs[DMA_WBC] -= len;
+ pci->dma_regs[DMA_WAC] += len;
++ if (pci->dma_regs[DMA_WBC] == 0)
++ pci->dma_regs[DMA_STAT] |= DMA_STAT_DONE;
+ }
+
+ static void esp_pci_dma_memory_read(void *opaque, uint8_t *buf, int len)
+diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c
+index ddfe76a..308b393 100644
+--- a/hw/scsi/vhost-scsi.c
++++ b/hw/scsi/vhost-scsi.c
+@@ -23,6 +23,7 @@
+ #include "hw/virtio/vhost.h"
+ #include "hw/virtio/virtio-scsi.h"
+ #include "hw/virtio/virtio-bus.h"
++#include "hw/virtio/virtio-access.h"
+
+ /* Features supported by host kernel. */
+ static const int kernel_feature_bits[] = {
+@@ -163,8 +164,8 @@ static void vhost_scsi_set_config(VirtIODevice *vdev,
+ VirtIOSCSIConfig *scsiconf = (VirtIOSCSIConfig *)config;
+ VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
+
+- if ((uint32_t) ldl_p(&scsiconf->sense_size) != vs->sense_size ||
+- (uint32_t) ldl_p(&scsiconf->cdb_size) != vs->cdb_size) {
++ if ((uint32_t) virtio_ldl_p(vdev, &scsiconf->sense_size) != vs->sense_size ||
++ (uint32_t) virtio_ldl_p(vdev, &scsiconf->cdb_size) != vs->cdb_size) {
+ error_report("vhost-scsi does not support changing the sense data and CDB sizes");
+ exit(1);
+ }
+@@ -238,6 +239,7 @@ static void vhost_scsi_realize(DeviceState *dev, Error **errp)
+ s->dev.nvqs = VHOST_SCSI_VQ_NUM_FIXED + vs->conf.num_queues;
+ s->dev.vqs = g_new(struct vhost_virtqueue, s->dev.nvqs);
+ s->dev.vq_index = 0;
++ s->dev.backend_features = 0;
+
+ ret = vhost_dev_init(&s->dev, (void *)(uintptr_t)vhostfd,
+ VHOST_BACKEND_TYPE_KERNEL, true);
+@@ -246,7 +248,6 @@ static void vhost_scsi_realize(DeviceState *dev, Error **errp)
+ strerror(-ret));
+ return;
+ }
+- s->dev.backend_features = 0;
+
+ error_setg(&s->migration_blocker,
+ "vhost-scsi does not support migration");
+diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
+index 0eb069a..f7e77e9 100644
+--- a/hw/scsi/virtio-scsi.c
++++ b/hw/scsi/virtio-scsi.c
+@@ -135,6 +135,7 @@ static size_t qemu_sgl_concat(VirtIOSCSIReq *req, struct iovec *iov,
+ static int virtio_scsi_parse_req(VirtIOSCSIReq *req,
+ unsigned req_size, unsigned resp_size)
+ {
++ VirtIODevice *vdev = (VirtIODevice *) req->dev;
+ size_t in_size, out_size;
+
+ if (iov_to_buf(req->elem.out_sg, req->elem.out_num, 0,
+@@ -147,8 +148,24 @@ static int virtio_scsi_parse_req(VirtIOSCSIReq *req,
+ resp_size) < resp_size) {
+ return -EINVAL;
+ }
++
+ req->resp_size = resp_size;
+
++ /* Old BIOSes left some padding by mistake after the req_size/resp_size.
++ * As a workaround, always consider the first buffer as the virtio-scsi
++ * request/response, making the payload start at the second element
++ * of the iovec.
++ *
++ * The actual length of the response header, stored in req->resp_size,
++ * does not change.
++ *
++ * TODO: always disable this workaround for virtio 1.0 devices.
++ */
++ if ((vdev->guest_features & VIRTIO_F_ANY_LAYOUT) == 0) {
++ req_size = req->elem.out_sg[0].iov_len;
++ resp_size = req->elem.in_sg[0].iov_len;
++ }
++
+ out_size = qemu_sgl_concat(req, req->elem.out_sg,
+ &req->elem.out_addr[0], req->elem.out_num,
+ req_size);
+@@ -400,7 +417,7 @@ static void virtio_scsi_command_complete(SCSIRequest *r, uint32_t status,
+ sense_len = scsi_req_get_sense(r, sense, sizeof(sense));
+ sense_len = MIN(sense_len, req->resp_iov.size - sizeof(req->resp.cmd));
+ qemu_iovec_from_buf(&req->resp_iov, sizeof(req->resp.cmd),
+- &req->resp, sense_len);
++ sense, sense_len);
+ req->resp.cmd.sense_len = virtio_tswap32(vdev, sense_len);
+ }
+ virtio_scsi_complete_cmd_req(req);
+diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
+index 58c4b11..807e1ae 100644
+--- a/hw/usb/hcd-xhci.c
++++ b/hw/usb/hcd-xhci.c
+@@ -499,6 +499,7 @@ enum xhci_flags {
+ XHCI_FLAG_USE_MSI = 1,
+ XHCI_FLAG_USE_MSI_X,
+ XHCI_FLAG_SS_FIRST,
++ XHCI_FLAG_FORCE_PCIE_ENDCAP,
+ };
+
+ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid,
+@@ -3626,7 +3627,8 @@ static int usb_xhci_initfn(struct PCIDevice *dev)
+ PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64,
+ &xhci->mem);
+
+- if (pci_bus_is_express(dev->bus)) {
++ if (pci_bus_is_express(dev->bus) ||
++ xhci_get_flag(xhci, XHCI_FLAG_FORCE_PCIE_ENDCAP)) {
+ ret = pcie_endpoint_cap_init(dev, 0xa0);
+ assert(ret >= 0);
+ }
+@@ -3818,6 +3820,8 @@ static Property xhci_properties[] = {
+ DEFINE_PROP_BIT("msix", XHCIState, flags, XHCI_FLAG_USE_MSI_X, true),
+ DEFINE_PROP_BIT("superspeed-ports-first",
+ XHCIState, flags, XHCI_FLAG_SS_FIRST, true),
++ DEFINE_PROP_BIT("force-pcie-endcap", XHCIState, flags,
++ XHCI_FLAG_FORCE_PCIE_ENDCAP, false),
+ DEFINE_PROP_UINT32("intrs", XHCIState, numintrs, MAXINTRS),
+ DEFINE_PROP_UINT32("slots", XHCIState, numslots, MAXSLOTS),
+ DEFINE_PROP_UINT32("p2", XHCIState, numports_2, 4),
+diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
+index e55fe1c..5d7c40a 100644
+--- a/hw/virtio/vhost.c
++++ b/hw/virtio/vhost.c
+@@ -976,7 +976,6 @@ void vhost_dev_disable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev)
+ bool vhost_virtqueue_pending(struct vhost_dev *hdev, int n)
+ {
+ struct vhost_virtqueue *vq = hdev->vqs + n - hdev->vq_index;
+- assert(hdev->started);
+ assert(n >= hdev->vq_index && n < hdev->vq_index + hdev->nvqs);
+ return event_notifier_test_and_clear(&vq->masked_notifier);
+ }
+@@ -988,7 +987,6 @@ void vhost_virtqueue_mask(struct vhost_dev *hdev, VirtIODevice *vdev, int n,
+ struct VirtQueue *vvq = virtio_get_queue(vdev, n);
+ int r, index = n - hdev->vq_index;
+
+- assert(hdev->started);
+ assert(n >= hdev->vq_index && n < hdev->vq_index + hdev->nvqs);
+
+ struct vhost_vring_file file = {
+diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c
+index 2c30b3d..b5cf7ca 100644
+--- a/hw/virtio/virtio-balloon.c
++++ b/hw/virtio/virtio-balloon.c
+@@ -87,7 +87,7 @@ static void balloon_stats_destroy_timer(VirtIOBalloon *s)
+ }
+ }
+
+-static void balloon_stats_change_timer(VirtIOBalloon *s, int secs)
++static void balloon_stats_change_timer(VirtIOBalloon *s, int64_t secs)
+ {
+ timer_mod(s->stats_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + secs * 1000);
+ }
+@@ -170,6 +170,11 @@ static void balloon_stats_set_poll_interval(Object *obj, struct Visitor *v,
+ return;
+ }
+
++ if (value > UINT_MAX) {
++ error_setg(errp, "timer value is too big");
++ return;
++ }
++
+ if (value == s->stats_poll_interval) {
+ return;
+ }
+diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
+index 3007319..ba675fe 100644
+--- a/hw/virtio/virtio-pci.c
++++ b/hw/virtio/virtio-pci.c
+@@ -314,6 +314,16 @@ static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+ msix_unuse_all_vectors(&proxy->pci_dev);
+ }
+
++ /* Linux before 2.6.34 drives the device without enabling
++ the PCI device bus master bit. Enable it automatically
++ for the guest. This is a PCI spec violation but so is
++ initiating DMA with bus master bit clear. */
++ if (val == (VIRTIO_CONFIG_S_ACKNOWLEDGE | VIRTIO_CONFIG_S_DRIVER)) {
++ pci_default_write_config(&proxy->pci_dev, PCI_COMMAND,
++ proxy->pci_dev.config[PCI_COMMAND] |
++ PCI_COMMAND_MASTER, 1);
++ }
++
+ /* Linux before 2.6.34 sets the device as OK without enabling
+ the PCI device bus master bit. In this case we need to disable
+ some safety checks. */
+@@ -914,7 +924,6 @@ static Property virtio_9p_pci_properties[] = {
+ DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
+ VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
+ DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
+- DEFINE_VIRTIO_9P_PROPERTIES(V9fsPCIState, vdev.fsconf),
+ DEFINE_PROP_END_OF_LIST(),
+ };
+
+@@ -938,6 +947,8 @@ static void virtio_9p_pci_instance_init(Object *obj)
+ V9fsPCIState *dev = VIRTIO_9P_PCI(obj);
+ object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_9P);
+ object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
++ qdev_alias_all_properties(DEVICE(&dev->vdev), obj);
++ object_unref(OBJECT(&dev->vdev));
+ }
+
+ static const TypeInfo virtio_9p_pci_info = {
+@@ -1127,7 +1138,6 @@ static Property virtio_scsi_pci_properties[] = {
+ DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
+ DEV_NVECTORS_UNSPECIFIED),
+ DEFINE_VIRTIO_SCSI_FEATURES(VirtIOPCIProxy, host_features),
+- DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOSCSIPCI, vdev.parent_obj.conf),
+ DEFINE_PROP_END_OF_LIST(),
+ };
+
+@@ -1179,6 +1189,8 @@ static void virtio_scsi_pci_instance_init(Object *obj)
+ VirtIOSCSIPCI *dev = VIRTIO_SCSI_PCI(obj);
+ object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SCSI);
+ object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
++ object_unref(OBJECT(&dev->vdev));
++ qdev_alias_all_properties(DEVICE(&dev->vdev), obj);
+ }
+
+ static const TypeInfo virtio_scsi_pci_info = {
+@@ -1195,7 +1207,6 @@ static const TypeInfo virtio_scsi_pci_info = {
+ static Property vhost_scsi_pci_properties[] = {
+ DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
+ DEV_NVECTORS_UNSPECIFIED),
+- DEFINE_VHOST_SCSI_PROPERTIES(VHostSCSIPCI, vdev.parent_obj.conf),
+ DEFINE_PROP_END_OF_LIST(),
+ };
+
+@@ -1235,6 +1246,8 @@ static void vhost_scsi_pci_instance_init(Object *obj)
+ VHostSCSIPCI *dev = VHOST_SCSI_PCI(obj);
+ object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VHOST_SCSI);
+ object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
++ object_unref(OBJECT(&dev->vdev));
++ qdev_alias_all_properties(DEVICE(&dev->vdev), obj);
+ }
+
+ static const TypeInfo vhost_scsi_pci_info = {
+@@ -1315,7 +1328,7 @@ static void virtio_balloon_pci_instance_init(Object *obj)
+ VirtIOBalloonPCI *dev = VIRTIO_BALLOON_PCI(obj);
+ object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_BALLOON);
+ object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
+-
++ object_unref(OBJECT(&dev->vdev));
+ object_property_add(obj, "guest-stats", "guest statistics",
+ balloon_pci_stats_get_all, NULL, NULL, dev,
+ NULL);
+@@ -1377,7 +1390,6 @@ static Property virtio_serial_pci_properties[] = {
+ VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
+ DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
+ DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0),
+- DEFINE_VIRTIO_SERIAL_PROPERTIES(VirtIOSerialPCI, vdev.serial),
+ DEFINE_PROP_END_OF_LIST(),
+ };
+
+@@ -1400,6 +1412,8 @@ static void virtio_serial_pci_instance_init(Object *obj)
+ VirtIOSerialPCI *dev = VIRTIO_SERIAL_PCI(obj);
+ object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SERIAL);
+ object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
++ qdev_alias_all_properties(DEVICE(&dev->vdev), obj);
++ object_unref(OBJECT(&dev->vdev));
+ }
+
+ static const TypeInfo virtio_serial_pci_info = {
+@@ -1417,8 +1431,6 @@ static Property virtio_net_properties[] = {
+ VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, false),
+ DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3),
+ DEFINE_VIRTIO_NET_FEATURES(VirtIOPCIProxy, host_features),
+- DEFINE_NIC_PROPERTIES(VirtIONetPCI, vdev.nic_conf),
+- DEFINE_VIRTIO_NET_PROPERTIES(VirtIONetPCI, vdev.net_conf),
+ DEFINE_PROP_END_OF_LIST(),
+ };
+
+@@ -1459,6 +1471,8 @@ static void virtio_net_pci_instance_init(Object *obj)
+ VirtIONetPCI *dev = VIRTIO_NET_PCI(obj);
+ object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_NET);
+ object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
++ object_unref(OBJECT(&dev->vdev));
++ qdev_alias_all_properties(DEVICE(&dev->vdev), obj);
+ }
+
+ static const TypeInfo virtio_net_pci_info = {
+@@ -1472,7 +1486,6 @@ static const TypeInfo virtio_net_pci_info = {
+ /* virtio-rng-pci */
+
+ static Property virtio_rng_pci_properties[] = {
+- DEFINE_VIRTIO_RNG_PROPERTIES(VirtIORngPCI, vdev.conf),
+ DEFINE_PROP_END_OF_LIST(),
+ };
+
+@@ -1514,6 +1527,8 @@ static void virtio_rng_initfn(Object *obj)
+ VirtIORngPCI *dev = VIRTIO_RNG_PCI(obj);
+ object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_RNG);
+ object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
++ qdev_alias_all_properties(DEVICE(&dev->vdev), obj);
++ object_unref(OBJECT(&dev->vdev));
+ object_property_add_link(obj, "rng", TYPE_RNG_BACKEND,
+ (Object **)&dev->vdev.conf.rng,
+ qdev_prop_allow_set_link_before_realize,
+diff --git a/hw/xtensa/xtfpga.c b/hw/xtensa/xtfpga.c
+index a2dff5a..e60ff90 100644
+--- a/hw/xtensa/xtfpga.c
++++ b/hw/xtensa/xtfpga.c
+@@ -325,7 +325,8 @@ static void lx_init(const LxBoardDesc *board, MachineState *machine)
+ } else {
+ hwaddr ep;
+ int is_linux;
+- success = load_uimage(kernel_filename, &ep, NULL, &is_linux);
++ success = load_uimage(kernel_filename, &ep, NULL, &is_linux,
++ translate_phys_addr, cpu);
+ if (success > 0 && is_linux) {
+ entry_point = ep;
+ } else {
+diff --git a/include/block/block_int.h b/include/block/block_int.h
+index 7b541a0..21b8718 100644
+--- a/include/block/block_int.h
++++ b/include/block/block_int.h
+@@ -395,6 +395,14 @@ struct BlockDriverState {
+ Error *backing_blocker;
+ };
+
++
++/* Essential block drivers which must always be statically linked into qemu, and
++ * which therefore can be accessed without using bdrv_find_format() */
++extern BlockDriver bdrv_file;
++extern BlockDriver bdrv_raw;
++extern BlockDriver bdrv_qcow2;
++
++
+ int get_tmp_filename(char *filename, int size);
+
+ void bdrv_set_io_limits(BlockDriverState *bs,
+diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h
+index 6593be1..e50e71c 100644
+--- a/include/exec/ram_addr.h
++++ b/include/exec/ram_addr.h
+@@ -49,6 +49,21 @@ static inline bool cpu_physical_memory_get_dirty(ram_addr_t start,
+ return next < end;
+ }
+
++static inline bool cpu_physical_memory_get_clean(ram_addr_t start,
++ ram_addr_t length,
++ unsigned client)
++{
++ unsigned long end, page, next;
++
++ assert(client < DIRTY_MEMORY_NUM);
++
++ end = TARGET_PAGE_ALIGN(start + length) >> TARGET_PAGE_BITS;
++ page = start >> TARGET_PAGE_BITS;
++ next = find_next_zero_bit(ram_list.dirty_memory[client], end, page);
++
++ return next < end;
++}
++
+ static inline bool cpu_physical_memory_get_dirty_flag(ram_addr_t addr,
+ unsigned client)
+ {
+@@ -64,6 +79,16 @@ static inline bool cpu_physical_memory_is_clean(ram_addr_t addr)
+ return !(vga && code && migration);
+ }
+
++static inline bool cpu_physical_memory_range_includes_clean(ram_addr_t start,
++ ram_addr_t length)
++{
++ bool vga = cpu_physical_memory_get_clean(start, length, DIRTY_MEMORY_VGA);
++ bool code = cpu_physical_memory_get_clean(start, length, DIRTY_MEMORY_CODE);
++ bool migration =
++ cpu_physical_memory_get_clean(start, length, DIRTY_MEMORY_MIGRATION);
++ return vga || code || migration;
++}
++
+ static inline void cpu_physical_memory_set_dirty_flag(ram_addr_t addr,
+ unsigned client)
+ {
+diff --git a/include/hw/acpi/pc-hotplug.h b/include/hw/acpi/pc-hotplug.h
+index bf5157d..b9db295 100644
+--- a/include/hw/acpi/pc-hotplug.h
++++ b/include/hw/acpi/pc-hotplug.h
+@@ -32,7 +32,7 @@
+ #define ACPI_MEMORY_HOTPLUG_IO_LEN 24
+ #define ACPI_MEMORY_HOTPLUG_BASE 0x0a00
+
+-#define MEMORY_HOPTLUG_DEVICE MHPD
++#define MEMORY_HOTPLUG_DEVICE MHPD
+ #define MEMORY_SLOTS_NUMBER MDNR
+ #define MEMORY_HOTPLUG_IO_REGION HPMR
+ #define MEMORY_SLOT_ADDR_LOW MRBL
+diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
+index f4b9b2b..b558875 100644
+--- a/include/hw/i386/pc.h
++++ b/include/hw/i386/pc.h
+@@ -177,6 +177,8 @@ void pc_acpi_init(const char *default_dsdt);
+ PcGuestInfo *pc_guest_info_init(ram_addr_t below_4g_mem_size,
+ ram_addr_t above_4g_mem_size);
+
++void pc_set_legacy_acpi_data_size(void);
++
+ #define PCI_HOST_PROP_PCI_HOLE_START "pci-hole-start"
+ #define PCI_HOST_PROP_PCI_HOLE_END "pci-hole-end"
+ #define PCI_HOST_PROP_PCI_HOLE64_START "pci-hole64-start"
+@@ -316,6 +318,11 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
+ .value = "off",\
+ },\
+ {\
++ .driver = "nec-usb-xhci",\
++ .property = "force-pcie-endcap",\
++ .value = "on",\
++ },\
++ {\
+ .driver = "pci-serial",\
+ .property = "prog_if",\
+ .value = stringify(0),\
+diff --git a/include/hw/loader.h b/include/hw/loader.h
+index 796cbf9..11b6b5a 100644
+--- a/include/hw/loader.h
++++ b/include/hw/loader.h
+@@ -28,7 +28,9 @@ int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t),
+ int load_aout(const char *filename, hwaddr addr, int max_sz,
+ int bswap_needed, hwaddr target_page_size);
+ int load_uimage(const char *filename, hwaddr *ep,
+- hwaddr *loadaddr, int *is_linux);
++ hwaddr *loadaddr, int *is_linux,
++ uint64_t (*translate_fn)(void *, uint64_t),
++ void *translate_opaque);
+
+ /**
+ * load_ramdisk:
+diff --git a/include/hw/pci-host/spapr.h b/include/hw/pci-host/spapr.h
+index 32f0aa7..4ea2a0d 100644
+--- a/include/hw/pci-host/spapr.h
++++ b/include/hw/pci-host/spapr.h
+@@ -70,7 +70,7 @@ struct sPAPRPHBState {
+
+ MemoryRegion memspace, iospace;
+ hwaddr mem_win_addr, mem_win_size, io_win_addr, io_win_size;
+- MemoryRegion memwindow, iowindow;
++ MemoryRegion memwindow, iowindow, msiwindow;
+
+ uint32_t dma_liobn;
+ AddressSpace iommu_as;
+diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
+index bbba51a..832ad6b 100644
+--- a/include/hw/ppc/spapr.h
++++ b/include/hw/ppc/spapr.h
+@@ -13,8 +13,6 @@ struct sPAPRNVRAM;
+ typedef struct sPAPREnvironment {
+ struct VIOsPAPRBus *vio_bus;
+ QLIST_HEAD(, sPAPRPHBState) phbs;
+- hwaddr msi_win_addr;
+- MemoryRegion msiwindow;
+ struct sPAPRNVRAM *nvram;
+ XICSState *icp;
+
+diff --git a/include/qapi/visitor-impl.h b/include/qapi/visitor-impl.h
+index ecc0183..09bb0fd 100644
+--- a/include/qapi/visitor-impl.h
++++ b/include/qapi/visitor-impl.h
+@@ -55,6 +55,8 @@ struct Visitor
+ void (*type_int64)(Visitor *v, int64_t *obj, const char *name, Error **errp);
+ /* visit_type_size() falls back to (*type_uint64)() if type_size is unset */
+ void (*type_size)(Visitor *v, uint64_t *obj, const char *name, Error **errp);
++ bool (*start_union)(Visitor *v, bool data_present, Error **errp);
++ void (*end_union)(Visitor *v, bool data_present, Error **errp);
+ };
+
+ void input_type_enum(Visitor *v, int *obj, const char *strings[],
+diff --git a/include/qapi/visitor.h b/include/qapi/visitor.h
+index 4a0178f..5934f59 100644
+--- a/include/qapi/visitor.h
++++ b/include/qapi/visitor.h
+@@ -58,5 +58,7 @@ void visit_type_size(Visitor *v, uint64_t *obj, const char *name, Error **errp);
+ void visit_type_bool(Visitor *v, bool *obj, const char *name, Error **errp);
+ void visit_type_str(Visitor *v, char **obj, const char *name, Error **errp);
+ void visit_type_number(Visitor *v, double *obj, const char *name, Error **errp);
++bool visit_start_union(Visitor *v, bool data_present, Error **errp);
++void visit_end_union(Visitor *v, bool data_present, Error **errp);
+
+ #endif
+diff --git a/include/qemu/atomic.h b/include/qemu/atomic.h
+index 492bce1..93c2ae2 100644
+--- a/include/qemu/atomic.h
++++ b/include/qemu/atomic.h
+@@ -122,11 +122,11 @@
+ #endif
+
+ #ifndef atomic_read
+-#define atomic_read(ptr) (*(__typeof__(*ptr) *volatile) (ptr))
++#define atomic_read(ptr) (*(__typeof__(*ptr) volatile*) (ptr))
+ #endif
+
+ #ifndef atomic_set
+-#define atomic_set(ptr, i) ((*(__typeof__(*ptr) *volatile) (ptr)) = (i))
++#define atomic_set(ptr, i) ((*(__typeof__(*ptr) volatile*) (ptr)) = (i))
+ #endif
+
+ /* These have the same semantics as Java volatile variables.
+diff --git a/include/sysemu/cpus.h b/include/sysemu/cpus.h
+index 4f79081..3f162a9 100644
+--- a/include/sysemu/cpus.h
++++ b/include/sysemu/cpus.h
+@@ -10,6 +10,7 @@ void cpu_stop_current(void);
+ void cpu_synchronize_all_states(void);
+ void cpu_synchronize_all_post_reset(void);
+ void cpu_synchronize_all_post_init(void);
++void cpu_clean_all_dirty(void);
+
+ void qtest_clock_warp(int64_t dest);
+
+diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h
+index 174ea36..777dc66 100644
+--- a/include/sysemu/kvm.h
++++ b/include/sysemu/kvm.h
+@@ -348,6 +348,7 @@ int kvm_physical_memory_addr_from_host(KVMState *s, void *ram_addr,
+ void kvm_cpu_synchronize_state(CPUState *cpu);
+ void kvm_cpu_synchronize_post_reset(CPUState *cpu);
+ void kvm_cpu_synchronize_post_init(CPUState *cpu);
++void kvm_cpu_clean_state(CPUState *cpu);
+
+ /* generic hooks - to be moved/refactored once there are more users */
+
+@@ -372,6 +373,13 @@ static inline void cpu_synchronize_post_init(CPUState *cpu)
+ }
+ }
+
++static inline void cpu_clean_state(CPUState *cpu)
++{
++ if (kvm_enabled()) {
++ kvm_cpu_clean_state(cpu);
++ }
++}
++
+ int kvm_irqchip_add_msi_route(KVMState *s, MSIMessage msg);
+ int kvm_irqchip_update_msi_route(KVMState *s, int virq, MSIMessage msg);
+ void kvm_irqchip_release_virq(KVMState *s, int virq);
+diff --git a/kvm-all.c b/kvm-all.c
+index 1402f4f..c8f9bca 100644
+--- a/kvm-all.c
++++ b/kvm-all.c
+@@ -617,8 +617,10 @@ static void kvm_set_phys_mem(MemoryRegionSection *section, bool add)
+ unsigned delta;
+
+ /* kvm works in page size chunks, but the function may be called
+- with sub-page size and unaligned start address. */
+- delta = TARGET_PAGE_ALIGN(size) - size;
++ with sub-page size and unaligned start address. Pad the start
++ address to next and truncate size to previous page boundary. */
++ delta = (TARGET_PAGE_SIZE - (start_addr & ~TARGET_PAGE_MASK));
++ delta &= ~TARGET_PAGE_MASK;
+ if (delta > size) {
+ return;
+ }
+@@ -1681,6 +1683,11 @@ void kvm_cpu_synchronize_post_init(CPUState *cpu)
+ cpu->kvm_vcpu_dirty = false;
+ }
+
++void kvm_cpu_clean_state(CPUState *cpu)
++{
++ cpu->kvm_vcpu_dirty = false;
++}
++
+ int kvm_cpu_exec(CPUState *cpu)
+ {
+ struct kvm_run *run = cpu->kvm_run;
+diff --git a/libcacard/cac.c b/libcacard/cac.c
+index ae8c378..f38fdce 100644
+--- a/libcacard/cac.c
++++ b/libcacard/cac.c
+@@ -115,6 +115,7 @@ cac_applet_pki_process_apdu(VCard *card, VCardAPDU *apdu,
+ VCardAppletPrivate *applet_private;
+ int size, next;
+ unsigned char *sign_buffer;
++ bool retain_sign_buffer = FALSE;
+ vcard_7816_status_t status;
+ VCardStatus ret = VCARD_FAIL;
+
+@@ -178,6 +179,7 @@ cac_applet_pki_process_apdu(VCard *card, VCardAPDU *apdu,
+ pki_applet->sign_buffer = sign_buffer;
+ pki_applet->sign_buffer_len = size;
+ *response = vcard_make_response(VCARD7816_STATUS_SUCCESS);
++ retain_sign_buffer = TRUE;
+ break;
+ case 0x00:
+ /* we now have the whole buffer, do the operation, result will be
+@@ -200,9 +202,11 @@ cac_applet_pki_process_apdu(VCard *card, VCardAPDU *apdu,
+ VCARD7816_STATUS_ERROR_P1_P2_INCORRECT);
+ break;
+ }
+- g_free(sign_buffer);
+- pki_applet->sign_buffer = NULL;
+- pki_applet->sign_buffer_len = 0;
++ if (!retain_sign_buffer) {
++ g_free(sign_buffer);
++ pki_applet->sign_buffer = NULL;
++ pki_applet->sign_buffer_len = 0;
++ }
+ ret = VCARD_DONE;
+ break;
+ case CAC_READ_BUFFER:
+diff --git a/libcacard/vscclient.c b/libcacard/vscclient.c
+index 80111df..fa6041d 100644
+--- a/libcacard/vscclient.c
++++ b/libcacard/vscclient.c
+@@ -597,7 +597,7 @@ connect_to_qemu(
+ const char *port
+ ) {
+ struct addrinfo hints;
+- struct addrinfo *server;
++ struct addrinfo *server = NULL;
+ int ret, sock;
+
+ sock = socket(AF_INET, SOCK_STREAM, 0);
+@@ -629,9 +629,14 @@ connect_to_qemu(
+ if (verbose) {
+ printf("Connected (sizeof Header=%zd)!\n", sizeof(VSCMsgHeader));
+ }
++
++ freeaddrinfo(server);
+ return sock;
+
+ cleanup_socket:
++ if (server) {
++ freeaddrinfo(server);
++ }
+ closesocket(sock);
+ return -1;
+ }
+diff --git a/monitor.c b/monitor.c
+index 5bc70a6..1ae32c0 100644
+--- a/monitor.c
++++ b/monitor.c
+@@ -5243,6 +5243,7 @@ static void monitor_event(void *opaque, int event)
+ monitor_printf(mon, "QEMU %s monitor - type 'help' for more "
+ "information\n", QEMU_VERSION);
+ if (!mon->mux_out) {
++ readline_restart(mon->rs);
+ readline_show_prompt(mon->rs);
+ }
+ mon->reset_seen = 1;
+diff --git a/net/l2tpv3.c b/net/l2tpv3.c
+index 528d95b..65db5ef 100644
+--- a/net/l2tpv3.c
++++ b/net/l2tpv3.c
+@@ -660,7 +660,6 @@ int net_init_l2tpv3(const NetClientOptions *opts,
+ if (fd == -1) {
+ fd = -errno;
+ error_report("l2tpv3_open : socket creation failed, errno = %d", -fd);
+- freeaddrinfo(result);
+ goto outerr;
+ }
+ if (bind(fd, (struct sockaddr *) result->ai_addr, result->ai_addrlen)) {
+diff --git a/net/net.c b/net/net.c
+index 6d930ea..7acc162 100644
+--- a/net/net.c
++++ b/net/net.c
+@@ -41,12 +41,14 @@
+ #include "qapi-visit.h"
+ #include "qapi/opts-visitor.h"
+ #include "qapi/dealloc-visitor.h"
++#include "sysemu/sysemu.h"
+
+ /* Net bridge is currently not supported for W32. */
+ #if !defined(_WIN32)
+ # define CONFIG_NET_BRIDGE
+ #endif
+
++static VMChangeStateEntry *net_change_state_entry;
+ static QTAILQ_HEAD(, NetClientState) net_clients;
+
+ const char *host_net_devices[] = {
+@@ -452,6 +454,12 @@ void qemu_set_vnet_hdr_len(NetClientState *nc, int len)
+
+ int qemu_can_send_packet(NetClientState *sender)
+ {
++ int vm_running = runstate_is_running();
++
++ if (!vm_running) {
++ return 0;
++ }
++
+ if (!sender->peer) {
+ return 1;
+ }
+@@ -504,7 +512,8 @@ void qemu_purge_queued_packets(NetClientState *nc)
+ qemu_net_queue_purge(nc->peer->incoming_queue, nc);
+ }
+
+-void qemu_flush_queued_packets(NetClientState *nc)
++static
++void qemu_flush_or_purge_queued_packets(NetClientState *nc, bool purge)
+ {
+ nc->receive_disabled = 0;
+
+@@ -518,9 +527,17 @@ void qemu_flush_queued_packets(NetClientState *nc)
+ * the file descriptor (for tap, for example).
+ */
+ qemu_notify_event();
++ } else if (purge) {
++ /* Unable to empty the queue, purge remaining packets */
++ qemu_net_queue_purge(nc->incoming_queue, nc);
+ }
+ }
+
++void qemu_flush_queued_packets(NetClientState *nc)
++{
++ qemu_flush_or_purge_queued_packets(nc, false);
++}
++
+ static ssize_t qemu_send_packet_async_with_flags(NetClientState *sender,
+ unsigned flags,
+ const uint8_t *buf, int size,
+@@ -1168,6 +1185,22 @@ void qmp_set_link(const char *name, bool up, Error **errp)
+ }
+ }
+
++static void net_vm_change_state_handler(void *opaque, int running,
++ RunState state)
++{
++ /* Complete all queued packets, to guarantee we don't modify
++ * state later when VM is not running.
++ */
++ if (!running) {
++ NetClientState *nc;
++ NetClientState *tmp;
++
++ QTAILQ_FOREACH_SAFE(nc, &net_clients, next, tmp) {
++ qemu_flush_or_purge_queued_packets(nc, true);
++ }
++ }
++}
++
+ void net_cleanup(void)
+ {
+ NetClientState *nc;
+@@ -1183,6 +1216,8 @@ void net_cleanup(void)
+ qemu_del_net_client(nc);
+ }
+ }
++
++ qemu_del_vm_change_state_handler(net_change_state_entry);
+ }
+
+ void net_check_clients(void)
+@@ -1268,6 +1303,9 @@ int net_init_clients(void)
+ #endif
+ }
+
++ net_change_state_entry =
++ qemu_add_vm_change_state_handler(net_vm_change_state_handler, NULL);
++
+ QTAILQ_INIT(&net_clients);
+
+ if (qemu_opts_foreach(qemu_find_opts("netdev"), net_init_netdev, NULL, 1) == -1)
+diff --git a/net/queue.c b/net/queue.c
+index 859d02a..f948318 100644
+--- a/net/queue.c
++++ b/net/queue.c
+@@ -233,6 +233,9 @@ void qemu_net_queue_purge(NetQueue *queue, NetClientState *from)
+ if (packet->sender == from) {
+ QTAILQ_REMOVE(&queue->packets, packet, entry);
+ queue->nq_count--;
++ if (packet->sent_cb) {
++ packet->sent_cb(packet->sender, 0);
++ }
+ g_free(packet);
+ }
+ }
+diff --git a/numa.c b/numa.c
+index 7bf7834..c78cec9 100644
+--- a/numa.c
++++ b/numa.c
+@@ -210,8 +210,8 @@ void set_numa_nodes(void)
+ numa_total += numa_info[i].node_mem;
+ }
+ if (numa_total != ram_size) {
+- error_report("total memory for NUMA nodes (%" PRIu64 ")"
+- " should equal RAM size (" RAM_ADDR_FMT ")",
++ error_report("total memory for NUMA nodes (0x%" PRIx64 ")"
++ " should equal RAM size (0x" RAM_ADDR_FMT ")",
+ numa_total, ram_size);
+ exit(1);
+ }
+diff --git a/pc-bios/optionrom/linuxboot.S b/pc-bios/optionrom/linuxboot.S
+index 748c831..ba821ab 100644
+--- a/pc-bios/optionrom/linuxboot.S
++++ b/pc-bios/optionrom/linuxboot.S
+@@ -76,14 +76,71 @@ boot_kernel:
+
+
+ copy_kernel:
+-
++ /* Read info block in low memory (0x10000 or 0x90000) */
++ read_fw FW_CFG_SETUP_ADDR
++ shr $4, %eax
++ mov %eax, %es
++ xor %edi, %edi
++ read_fw_blob_addr32_edi(FW_CFG_SETUP)
++
++ cmpw $0x203, %es:0x206 // if protocol >= 0x203
++ jae 1f // have initrd_max
++ movl $0x37ffffff, %es:0x22c // else assume 0x37ffffff
++1:
++
++ /* Check if using kernel-specified initrd address */
++ read_fw FW_CFG_INITRD_ADDR
++ mov %eax, %edi // (load_kernel wants it in %edi)
++ read_fw FW_CFG_INITRD_SIZE // find end of initrd
++ add %edi, %eax
++ xor %es:0x22c, %eax // if it matches es:0x22c
++ and $-4096, %eax // (apart from padding for page)
++ jz load_kernel // then initrd is not at top
++ // of memory
++
++ /* pc.c placed the initrd at end of memory. Compute a better
++ * initrd address based on e801 data.
++ */
++ mov $0xe801, %ax
++ xor %cx, %cx
++ xor %dx, %dx
++ int $0x15
++
++ /* Output could be in AX/BX or CX/DX */
++ or %cx, %cx
++ jnz 1f
++ or %dx, %dx
++ jnz 1f
++ mov %ax, %cx
++ mov %bx, %dx
++1:
++
++ or %dx, %dx
++ jnz 2f
++ addw $1024, %cx /* add 1 MB */
++ movzwl %cx, %edi
++ shll $10, %edi /* convert to bytes */
++ jmp 3f
++
++2:
++ addw $16777216 >> 16, %dx /* add 16 MB */
++ movzwl %dx, %edi
++ shll $16, %edi /* convert to bytes */
++
++3:
++ read_fw FW_CFG_INITRD_SIZE
++ subl %eax, %edi
++ andl $-4096, %edi /* EDI = start of initrd */
++ movl %edi, %es:0x218 /* put it in the header */
++
++load_kernel:
+ /* We need to load the kernel into memory we can't access in 16 bit
+ mode, so let's get into 32 bit mode, write the kernel and jump
+ back again. */
+
+ /* Reserve space on the stack for our GDT descriptor. */
+- mov %esp, %ebp
+- sub $16, %esp
++ mov %esp, %ebp
++ sub $16, %esp
+
+ /* Now create the GDT descriptor */
+ movw $((3 * 8) - 1), -16(%bp)
+@@ -108,10 +165,9 @@ copy_kernel:
+ /* We're now running in 16-bit CS, but 32-bit ES! */
+
+ /* Load kernel and initrd */
++ read_fw_blob_addr32_edi(FW_CFG_INITRD)
+ read_fw_blob_addr32(FW_CFG_KERNEL)
+- read_fw_blob_addr32(FW_CFG_INITRD)
+ read_fw_blob_addr32(FW_CFG_CMDLINE)
+- read_fw_blob_addr32(FW_CFG_SETUP)
+
+ /* And now jump into Linux! */
+ mov $0, %eax
+diff --git a/pc-bios/optionrom/optionrom.h b/pc-bios/optionrom/optionrom.h
+index ce43608..f1a9021 100644
+--- a/pc-bios/optionrom/optionrom.h
++++ b/pc-bios/optionrom/optionrom.h
+@@ -51,8 +51,6 @@
+ .endm
+
+ #define read_fw_blob_pre(var) \
+- read_fw var ## _ADDR; \
+- mov %eax, %edi; \
+ read_fw var ## _SIZE; \
+ mov %eax, %ecx; \
+ mov $var ## _DATA, %ax; \
+@@ -68,6 +66,8 @@
+ * Clobbers: %eax, %edx, %es, %ecx, %edi
+ */
+ #define read_fw_blob(var) \
++ read_fw var ## _ADDR; \
++ mov %eax, %edi; \
+ read_fw_blob_pre(var); \
+ /* old as(1) doesn't like this insn so emit the bytes instead: \
+ rep insb (%dx), %es:(%edi); \
+@@ -80,7 +80,22 @@
+ *
+ * Clobbers: %eax, %edx, %es, %ecx, %edi
+ */
+-#define read_fw_blob_addr32(var) \
++#define read_fw_blob_addr32(var) \
++ read_fw var ## _ADDR; \
++ mov %eax, %edi; \
++ read_fw_blob_pre(var); \
++ /* old as(1) doesn't like this insn so emit the bytes instead: \
++ addr32 rep insb (%dx), %es:(%edi); \
++ */ \
++ .dc.b 0x67,0xf3,0x6c
++
++/*
++ * Read a blob from the fw_cfg device in forced addr32 mode, address is in %edi.
++ * Requires _SIZE and _DATA values for the parameter.
++ *
++ * Clobbers: %eax, %edx, %edi, %es, %ecx
++ */
++#define read_fw_blob_addr32_edi(var) \
+ read_fw_blob_pre(var); \
+ /* old as(1) doesn't like this insn so emit the bytes instead: \
+ addr32 rep insb (%dx), %es:(%edi); \
+diff --git a/qapi/qapi-dealloc-visitor.c b/qapi/qapi-dealloc-visitor.c
+index dc53545..a14a1c7 100644
+--- a/qapi/qapi-dealloc-visitor.c
++++ b/qapi/qapi-dealloc-visitor.c
+@@ -162,6 +162,31 @@ static void qapi_dealloc_type_enum(Visitor *v, int *obj, const char *strings[],
+ {
+ }
+
++/* If there's no data present, the dealloc visitor has nothing to free.
++ * Thus, indicate to visitor code that the subsequent union fields can
++ * be skipped. This is not an error condition, since the cleanup of the
++ * rest of an object can continue unhindered, so leave errp unset in
++ * these cases.
++ *
++ * NOTE: In cases where we're attempting to deallocate an object that
++ * may have missing fields, the field indicating the union type may
++ * be missing. In such a case, it's possible we don't have enough
++ * information to differentiate data_present == false from a case where
++ * data *is* present but happens to be a scalar with a value of 0.
++ * This is okay, since in the case of the dealloc visitor there's no
++ * work that needs to done in either situation.
++ *
++ * The current inability in QAPI code to more thoroughly verify a union
++ * type in such cases will likely need to be addressed if we wish to
++ * implement this interface for other types of visitors in the future,
++ * however.
++ */
++static bool qapi_dealloc_start_union(Visitor *v, bool data_present,
++ Error **errp)
++{
++ return data_present;
++}
++
+ Visitor *qapi_dealloc_get_visitor(QapiDeallocVisitor *v)
+ {
+ return &v->visitor;
+@@ -191,6 +216,7 @@ QapiDeallocVisitor *qapi_dealloc_visitor_new(void)
+ v->visitor.type_str = qapi_dealloc_type_str;
+ v->visitor.type_number = qapi_dealloc_type_number;
+ v->visitor.type_size = qapi_dealloc_type_size;
++ v->visitor.start_union = qapi_dealloc_start_union;
+
+ QTAILQ_INIT(&v->stack);
+
+diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c
+index 55f8d40..b66b93a 100644
+--- a/qapi/qapi-visit-core.c
++++ b/qapi/qapi-visit-core.c
+@@ -58,6 +58,21 @@ void visit_end_list(Visitor *v, Error **errp)
+ v->end_list(v, errp);
+ }
+
++bool visit_start_union(Visitor *v, bool data_present, Error **errp)
++{
++ if (v->start_union) {
++ return v->start_union(v, data_present, errp);
++ }
++ return true;
++}
++
++void visit_end_union(Visitor *v, bool data_present, Error **errp)
++{
++ if (v->end_union) {
++ v->end_union(v, data_present, errp);
++ }
++}
++
+ void visit_optional(Visitor *v, bool *present, const char *name,
+ Error **errp)
+ {
+diff --git a/qdev-monitor.c b/qdev-monitor.c
+index f87f3d8..5fe5e75 100644
+--- a/qdev-monitor.c
++++ b/qdev-monitor.c
+@@ -182,9 +182,10 @@ static const char *find_typename_by_alias(const char *alias)
+
+ int qdev_device_help(QemuOpts *opts)
+ {
++ Error *local_err = NULL;
+ const char *driver;
+- Property *prop;
+- ObjectClass *klass;
++ DevicePropertyInfoList *prop_list;
++ DevicePropertyInfoList *prop;
+
+ driver = qemu_opt_get(opts, "driver");
+ if (driver && is_help_option(driver)) {
+@@ -196,35 +197,28 @@ int qdev_device_help(QemuOpts *opts)
+ return 0;
+ }
+
+- klass = object_class_by_name(driver);
+- if (!klass) {
++ if (!object_class_by_name(driver)) {
+ const char *typename = find_typename_by_alias(driver);
+
+ if (typename) {
+ driver = typename;
+- klass = object_class_by_name(driver);
+ }
+ }
+
+- if (!object_class_dynamic_cast(klass, TYPE_DEVICE)) {
+- return 0;
++ prop_list = qmp_device_list_properties(driver, &local_err);
++ if (!prop_list) {
++ error_printf("%s\n", error_get_pretty(local_err));
++ error_free(local_err);
++ return 1;
+ }
+- do {
+- for (prop = DEVICE_CLASS(klass)->props; prop && prop->name; prop++) {
+- /*
+- * TODO Properties without a parser are just for dirty hacks.
+- * qdev_prop_ptr is the only such PropertyInfo. It's marked
+- * for removal. This conditional should be removed along with
+- * it.
+- */
+- if (!prop->info->set) {
+- continue; /* no way to set it, don't show */
+- }
+- error_printf("%s.%s=%s\n", driver, prop->name,
+- prop->info->legacy_name ?: prop->info->name);
+- }
+- klass = object_class_get_parent(klass);
+- } while (klass != object_class_by_name(TYPE_DEVICE));
++
++ for (prop = prop_list; prop; prop = prop->next) {
++ error_printf("%s.%s=%s\n", driver,
++ prop->value->name,
++ prop->value->type);
++ }
++
++ qapi_free_DevicePropertyInfoList(prop_list);
+ return 1;
+ }
+
+diff --git a/qemu-char.c b/qemu-char.c
+index 956be49..2abb330 100644
+--- a/qemu-char.c
++++ b/qemu-char.c
+@@ -1160,7 +1160,9 @@ static int pty_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+ if (!s->connected) {
+ /* guest sends data, check for (re-)connect */
+ pty_chr_update_read_handler_locked(chr);
+- return 0;
++ if (!s->connected) {
++ return 0;
++ }
+ }
+ return io_channel_send(s->fd, buf, len);
+ }
+diff --git a/qemu-img.c b/qemu-img.c
+index d4518e7..27ac1fc 100644
+--- a/qemu-img.c
++++ b/qemu-img.c
+@@ -1378,6 +1378,20 @@ static int img_convert(int argc, char **argv)
+ goto out;
+ }
+
++ if (!drv->create_opts) {
++ error_report("Format driver '%s' does not support image creation",
++ drv->format_name);
++ ret = -1;
++ goto out;
++ }
++
++ if (!proto_drv->create_opts) {
++ error_report("Protocol driver '%s' does not support image creation",
++ proto_drv->format_name);
++ ret = -1;
++ goto out;
++ }
++
+ create_opts = qemu_opts_append(create_opts, drv->create_opts);
+ create_opts = qemu_opts_append(create_opts, proto_drv->create_opts);
+
+@@ -2761,6 +2775,13 @@ static int img_amend(int argc, char **argv)
+ goto out;
+ }
+
++ if (!bs->drv->create_opts) {
++ error_report("Format driver '%s' does not support any options to amend",
++ fmt);
++ ret = -1;
++ goto out;
++ }
++
+ create_opts = qemu_opts_append(create_opts, bs->drv->create_opts);
+ opts = qemu_opts_create(create_opts, NULL, 0, &error_abort);
+ if (options && qemu_opts_do_parse(opts, options, NULL)) {
+diff --git a/qmp.c b/qmp.c
+index 0d2553a..c6767c4 100644
+--- a/qmp.c
++++ b/qmp.c
+@@ -509,6 +509,7 @@ DevicePropertyInfoList *qmp_device_list_properties(const char *typename,
+ if (strcmp(prop->name, "type") == 0 ||
+ strcmp(prop->name, "realized") == 0 ||
+ strcmp(prop->name, "hotpluggable") == 0 ||
++ strcmp(prop->name, "hotplugged") == 0 ||
+ strcmp(prop->name, "parent_bus") == 0) {
+ continue;
+ }
+diff --git a/savevm.c b/savevm.c
+index e19ae0a..2d8eb96 100644
+--- a/savevm.c
++++ b/savevm.c
+@@ -1245,19 +1245,18 @@ int load_vmstate(const char *name)
+
+ void do_delvm(Monitor *mon, const QDict *qdict)
+ {
+- BlockDriverState *bs, *bs1;
++ BlockDriverState *bs;
+ Error *err = NULL;
+ const char *name = qdict_get_str(qdict, "name");
+
+- bs = find_vmstate_bs();
+- if (!bs) {
++ if (!find_vmstate_bs()) {
+ monitor_printf(mon, "No block device supports snapshots\n");
+ return;
+ }
+
+- bs1 = NULL;
+- while ((bs1 = bdrv_next(bs1))) {
+- if (bdrv_can_snapshot(bs1)) {
++ bs = NULL;
++ while ((bs = bdrv_next(bs))) {
++ if (bdrv_can_snapshot(bs)) {
+ bdrv_snapshot_delete_by_id_or_name(bs, name, &err);
+ if (err) {
+ monitor_printf(mon,
+diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
+index c129697..cfce31b 100644
+--- a/scripts/qapi-visit.py
++++ b/scripts/qapi-visit.py
+@@ -357,6 +357,9 @@ void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **e
+ if (err) {
+ goto out_obj;
+ }
++ if (!visit_start_union(m, !!(*obj)->data, &err) || err) {
++ goto out_obj;
++ }
+ switch ((*obj)->kind) {
+ ''',
+ disc_type = disc_type,
+@@ -385,6 +388,9 @@ void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **e
+ out_obj:
+ error_propagate(errp, err);
+ err = NULL;
++ visit_end_union(m, !!(*obj)->data, &err);
++ error_propagate(errp, err);
++ err = NULL;
+ }
+ visit_end_struct(m, &err);
+ out:
+diff --git a/slirp/udp.c b/slirp/udp.c
+index 8cc6cb6..f77e00f 100644
+--- a/slirp/udp.c
++++ b/slirp/udp.c
+@@ -152,7 +152,7 @@ udp_input(register struct mbuf *m, int iphlen)
+ * Locate pcb for datagram.
+ */
+ so = slirp->udp_last_so;
+- if (so->so_lport != uh->uh_sport ||
++ if (so == &slirp->udb || so->so_lport != uh->uh_sport ||
+ so->so_laddr.s_addr != ip->ip_src.s_addr) {
+ struct socket *tmp;
+
+diff --git a/target-arm/cpu.h b/target-arm/cpu.h
+index 369d472..f101880 100644
+--- a/target-arm/cpu.h
++++ b/target-arm/cpu.h
+@@ -1170,7 +1170,14 @@ static inline int cpu_mmu_index (CPUARMState *env)
+ static inline void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
+ target_ulong *cs_base, int *flags)
+ {
+- int fpen = extract32(env->cp15.c1_coproc, 20, 2);
++ int fpen;
++
++ if (arm_feature(env, ARM_FEATURE_V6)) {
++ fpen = extract32(env->cp15.c1_coproc, 20, 2);
++ } else {
++ /* CPACR doesn't exist before v6, so VFP is always accessible */
++ fpen = 3;
++ }
+
+ if (is_a64(env)) {
+ *pc = env->pc;
+diff --git a/target-arm/cpu64.c b/target-arm/cpu64.c
+index 8b2081c..b2ed01f 100644
+--- a/target-arm/cpu64.c
++++ b/target-arm/cpu64.c
+@@ -123,9 +123,10 @@ static void aarch64_a57_initfn(Object *obj)
+ cpu->id_isar2 = 0x21232042;
+ cpu->id_isar3 = 0x01112131;
+ cpu->id_isar4 = 0x00011142;
++ cpu->id_isar5 = 0x00011121;
+ cpu->id_aa64pfr0 = 0x00002222;
+ cpu->id_aa64dfr0 = 0x10305106;
+- cpu->id_aa64isar0 = 0x00010000;
++ cpu->id_aa64isar0 = 0x00011120;
+ cpu->id_aa64mmfr0 = 0x00001124;
+ cpu->clidr = 0x0a200023;
+ cpu->ccsidr[0] = 0x701fe00a; /* 32KB L1 dcache */
+diff --git a/target-arm/kvm-consts.h b/target-arm/kvm-consts.h
+index 6009a33..091c126 100644
+--- a/target-arm/kvm-consts.h
++++ b/target-arm/kvm-consts.h
+@@ -17,6 +17,7 @@
+ #ifdef CONFIG_KVM
+ #include "qemu/compiler.h"
+ #include <linux/kvm.h>
++#include <linux/psci.h>
+
+ #define MISMATCH_CHECK(X, Y) QEMU_BUILD_BUG_ON(X != Y)
+
+@@ -38,17 +39,43 @@ MISMATCH_CHECK(CP_REG_SIZE_U64, KVM_REG_SIZE_U64)
+ MISMATCH_CHECK(CP_REG_ARM, KVM_REG_ARM)
+ MISMATCH_CHECK(CP_REG_ARCH_MASK, KVM_REG_ARCH_MASK)
+
+-#define PSCI_FN_BASE 0x95c1ba5e
+-#define PSCI_FN(n) (PSCI_FN_BASE + (n))
+-#define PSCI_FN_CPU_SUSPEND PSCI_FN(0)
+-#define PSCI_FN_CPU_OFF PSCI_FN(1)
+-#define PSCI_FN_CPU_ON PSCI_FN(2)
+-#define PSCI_FN_MIGRATE PSCI_FN(3)
+-
+-MISMATCH_CHECK(PSCI_FN_CPU_SUSPEND, KVM_PSCI_FN_CPU_SUSPEND)
+-MISMATCH_CHECK(PSCI_FN_CPU_OFF, KVM_PSCI_FN_CPU_OFF)
+-MISMATCH_CHECK(PSCI_FN_CPU_ON, KVM_PSCI_FN_CPU_ON)
+-MISMATCH_CHECK(PSCI_FN_MIGRATE, KVM_PSCI_FN_MIGRATE)
++#define QEMU_PSCI_0_1_FN_BASE 0x95c1ba5e
++#define QEMU_PSCI_0_1_FN(n) (QEMU_PSCI_0_1_FN_BASE + (n))
++#define QEMU_PSCI_0_1_FN_CPU_SUSPEND QEMU_PSCI_0_1_FN(0)
++#define QEMU_PSCI_0_1_FN_CPU_OFF QEMU_PSCI_0_1_FN(1)
++#define QEMU_PSCI_0_1_FN_CPU_ON QEMU_PSCI_0_1_FN(2)
++#define QEMU_PSCI_0_1_FN_MIGRATE QEMU_PSCI_0_1_FN(3)
++
++MISMATCH_CHECK(QEMU_PSCI_0_1_FN_CPU_SUSPEND, KVM_PSCI_FN_CPU_SUSPEND)
++MISMATCH_CHECK(QEMU_PSCI_0_1_FN_CPU_OFF, KVM_PSCI_FN_CPU_OFF)
++MISMATCH_CHECK(QEMU_PSCI_0_1_FN_CPU_ON, KVM_PSCI_FN_CPU_ON)
++MISMATCH_CHECK(QEMU_PSCI_0_1_FN_MIGRATE, KVM_PSCI_FN_MIGRATE)
++
++#define QEMU_PSCI_0_2_FN_BASE 0x84000000
++#define QEMU_PSCI_0_2_FN(n) (QEMU_PSCI_0_2_FN_BASE + (n))
++
++#define QEMU_PSCI_0_2_64BIT 0x40000000
++#define QEMU_PSCI_0_2_FN64_BASE \
++ (QEMU_PSCI_0_2_FN_BASE + QEMU_PSCI_0_2_64BIT)
++#define QEMU_PSCI_0_2_FN64(n) (QEMU_PSCI_0_2_FN64_BASE + (n))
++
++#define QEMU_PSCI_0_2_FN_CPU_SUSPEND QEMU_PSCI_0_2_FN(1)
++#define QEMU_PSCI_0_2_FN_CPU_OFF QEMU_PSCI_0_2_FN(2)
++#define QEMU_PSCI_0_2_FN_CPU_ON QEMU_PSCI_0_2_FN(3)
++#define QEMU_PSCI_0_2_FN_MIGRATE QEMU_PSCI_0_2_FN(5)
++
++#define QEMU_PSCI_0_2_FN64_CPU_SUSPEND QEMU_PSCI_0_2_FN64(1)
++#define QEMU_PSCI_0_2_FN64_CPU_OFF QEMU_PSCI_0_2_FN64(2)
++#define QEMU_PSCI_0_2_FN64_CPU_ON QEMU_PSCI_0_2_FN64(3)
++#define QEMU_PSCI_0_2_FN64_MIGRATE QEMU_PSCI_0_2_FN64(5)
++
++MISMATCH_CHECK(QEMU_PSCI_0_2_FN_CPU_SUSPEND, PSCI_0_2_FN_CPU_SUSPEND)
++MISMATCH_CHECK(QEMU_PSCI_0_2_FN_CPU_OFF, PSCI_0_2_FN_CPU_OFF)
++MISMATCH_CHECK(QEMU_PSCI_0_2_FN_CPU_ON, PSCI_0_2_FN_CPU_ON)
++MISMATCH_CHECK(QEMU_PSCI_0_2_FN_MIGRATE, PSCI_0_2_FN_MIGRATE)
++MISMATCH_CHECK(QEMU_PSCI_0_2_FN64_CPU_SUSPEND, PSCI_0_2_FN64_CPU_SUSPEND)
++MISMATCH_CHECK(QEMU_PSCI_0_2_FN64_CPU_ON, PSCI_0_2_FN64_CPU_ON)
++MISMATCH_CHECK(QEMU_PSCI_0_2_FN64_MIGRATE, PSCI_0_2_FN64_MIGRATE)
+
+ /* Note that KVM uses overlapping values for AArch32 and AArch64
+ * target CPU numbers. AArch32 targets:
+diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
+index 33b5025..fc319d5 100644
+--- a/target-arm/translate-a64.c
++++ b/target-arm/translate-a64.c
+@@ -1454,7 +1454,7 @@ static void disas_exc(DisasContext *s, uint32_t insn)
+ break;
+ }
+ /* BRK */
+- gen_exception_insn(s, 0, EXCP_BKPT, syn_aa64_bkpt(imm16));
++ gen_exception_insn(s, 4, EXCP_BKPT, syn_aa64_bkpt(imm16));
+ break;
+ case 2:
+ if (op2_ll != 0) {
+diff --git a/target-i386/cpu-qom.h b/target-i386/cpu-qom.h
+index 71a1b97..7755466 100644
+--- a/target-i386/cpu-qom.h
++++ b/target-i386/cpu-qom.h
+@@ -92,6 +92,7 @@ typedef struct X86CPU {
+ bool enforce_cpuid;
+ bool expose_kvm;
+ bool migratable;
++ bool host_features;
+
+ /* if true the CPUID code directly forward host cache leaves to the guest */
+ bool cache_info_passthrough;
+diff --git a/target-i386/cpu.c b/target-i386/cpu.c
+index 6d008ab..f9fcbca 100644
+--- a/target-i386/cpu.c
++++ b/target-i386/cpu.c
+@@ -1254,6 +1254,9 @@ void x86_cpu_compat_set_features(const char *cpu_model, FeatureWord w,
+ }
+ }
+
++static uint32_t x86_cpu_get_supported_feature_word(FeatureWord w,
++ bool migratable_only);
++
+ #ifdef CONFIG_KVM
+
+ static int cpu_x86_fill_model_id(char *str)
+@@ -1310,26 +1313,23 @@ static void host_x86_cpu_class_init(ObjectClass *oc, void *data)
+ dc->props = host_x86_cpu_properties;
+ }
+
+-static uint32_t x86_cpu_get_supported_feature_word(FeatureWord w,
+- bool migratable_only);
+-
+ static void host_x86_cpu_initfn(Object *obj)
+ {
+ X86CPU *cpu = X86_CPU(obj);
+ CPUX86State *env = &cpu->env;
+ KVMState *s = kvm_state;
+- FeatureWord w;
+
+ assert(kvm_enabled());
+
++ /* We can't fill the features array here because we don't know yet if
++ * "migratable" is true or false.
++ */
++ cpu->host_features = true;
++
+ env->cpuid_level = kvm_arch_get_supported_cpuid(s, 0x0, 0, R_EAX);
+ env->cpuid_xlevel = kvm_arch_get_supported_cpuid(s, 0x80000000, 0, R_EAX);
+ env->cpuid_xlevel2 = kvm_arch_get_supported_cpuid(s, 0xC0000000, 0, R_EAX);
+
+- for (w = 0; w < FEATURE_WORDS; w++) {
+- env->features[w] =
+- x86_cpu_get_supported_feature_word(w, cpu->migratable);
+- }
+ object_property_set_bool(OBJECT(cpu), true, "pmu", &error_abort);
+ }
+
+@@ -1828,6 +1828,13 @@ static void x86_cpu_parse_featurestr(CPUState *cs, char *features,
+ featurestr = strtok(NULL, ",");
+ }
+
++ if (cpu->host_features) {
++ for (w = 0; w < FEATURE_WORDS; w++) {
++ env->features[w] =
++ x86_cpu_get_supported_feature_word(w, cpu->migratable);
++ }
++ }
++
+ for (w = 0; w < FEATURE_WORDS; w++) {
+ env->features[w] |= plus_features[w];
+ env->features[w] &= ~minus_features[w];
+@@ -2588,6 +2595,16 @@ static void x86_cpu_reset(CPUState *s)
+
+ env->xcr0 = 1;
+
++ /*
++ * SDM 11.11.5 requires:
++ * - IA32_MTRR_DEF_TYPE MSR.E = 0
++ * - IA32_MTRR_PHYSMASKn.V = 0
++ * All other bits are undefined. For simplification, zero it all.
++ */
++ env->mtrr_deftype = 0;
++ memset(env->mtrr_var, 0, sizeof(env->mtrr_var));
++ memset(env->mtrr_fixed, 0, sizeof(env->mtrr_fixed));
++
+ #if !defined(CONFIG_USER_ONLY)
+ /* We hard-wire the BSP to the first CPU. */
+ if (s->cpu_index == 0) {
+diff --git a/target-i386/cpu.h b/target-i386/cpu.h
+index e634d83..3460b12 100644
+--- a/target-i386/cpu.h
++++ b/target-i386/cpu.h
+@@ -337,6 +337,8 @@
+ #define MSR_MTRRphysBase(reg) (0x200 + 2 * (reg))
+ #define MSR_MTRRphysMask(reg) (0x200 + 2 * (reg) + 1)
+
++#define MSR_MTRRphysIndex(addr) ((((addr) & ~1u) - 0x200) / 2)
++
+ #define MSR_MTRRfix64K_00000 0x250
+ #define MSR_MTRRfix16K_80000 0x258
+ #define MSR_MTRRfix16K_A0000 0x259
+@@ -930,7 +932,7 @@ typedef struct CPUX86State {
+ /* MTRRs */
+ uint64_t mtrr_fixed[11];
+ uint64_t mtrr_deftype;
+- MTRRVar mtrr_var[8];
++ MTRRVar mtrr_var[MSR_MTRRcap_VCNT];
+
+ /* For KVM */
+ uint32_t mp_state;
+diff --git a/target-i386/helper.c b/target-i386/helper.c
+index 47b982b..30cb0d0 100644
+--- a/target-i386/helper.c
++++ b/target-i386/helper.c
+@@ -615,8 +615,8 @@ int x86_cpu_handle_mmu_fault(CPUState *cs, vaddr addr,
+ if (!(pdpe & PG_PRESENT_MASK)) {
+ goto do_fault;
+ }
+- rsvd_mask |= PG_HI_USER_MASK | PG_NX_MASK;
+- if (pdpe & rsvd_mask) {
++ rsvd_mask |= PG_HI_USER_MASK;
++ if (pdpe & (rsvd_mask | PG_NX_MASK)) {
+ goto do_fault_rsvd;
+ }
+ ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK;
+diff --git a/target-i386/kvm.c b/target-i386/kvm.c
+index 097fe11..ddedc73 100644
+--- a/target-i386/kvm.c
++++ b/target-i386/kvm.c
+@@ -79,6 +79,7 @@ static int lm_capable_kernel;
+ static bool has_msr_hv_hypercall;
+ static bool has_msr_hv_vapic;
+ static bool has_msr_hv_tsc;
++static bool has_msr_mtrr;
+
+ static bool has_msr_architectural_pmu;
+ static uint32_t num_architectural_pmu_counters;
+@@ -739,6 +740,10 @@ int kvm_arch_init_vcpu(CPUState *cs)
+ env->kvm_xsave_buf = qemu_memalign(4096, sizeof(struct kvm_xsave));
+ }
+
++ if (env->features[FEAT_1_EDX] & CPUID_MTRR) {
++ has_msr_mtrr = true;
++ }
++
+ return 0;
+ }
+
+@@ -1183,7 +1188,7 @@ static int kvm_put_msrs(X86CPU *cpu, int level)
+ CPUX86State *env = &cpu->env;
+ struct {
+ struct kvm_msrs info;
+- struct kvm_msr_entry entries[100];
++ struct kvm_msr_entry entries[150];
+ } msr_data;
+ struct kvm_msr_entry *msrs = msr_data.entries;
+ int n = 0, i;
+@@ -1278,6 +1283,37 @@ static int kvm_put_msrs(X86CPU *cpu, int level)
+ kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_REFERENCE_TSC,
+ env->msr_hv_tsc);
+ }
++ if (has_msr_mtrr) {
++ kvm_msr_entry_set(&msrs[n++], MSR_MTRRdefType, env->mtrr_deftype);
++ kvm_msr_entry_set(&msrs[n++],
++ MSR_MTRRfix64K_00000, env->mtrr_fixed[0]);
++ kvm_msr_entry_set(&msrs[n++],
++ MSR_MTRRfix16K_80000, env->mtrr_fixed[1]);
++ kvm_msr_entry_set(&msrs[n++],
++ MSR_MTRRfix16K_A0000, env->mtrr_fixed[2]);
++ kvm_msr_entry_set(&msrs[n++],
++ MSR_MTRRfix4K_C0000, env->mtrr_fixed[3]);
++ kvm_msr_entry_set(&msrs[n++],
++ MSR_MTRRfix4K_C8000, env->mtrr_fixed[4]);
++ kvm_msr_entry_set(&msrs[n++],
++ MSR_MTRRfix4K_D0000, env->mtrr_fixed[5]);
++ kvm_msr_entry_set(&msrs[n++],
++ MSR_MTRRfix4K_D8000, env->mtrr_fixed[6]);
++ kvm_msr_entry_set(&msrs[n++],
++ MSR_MTRRfix4K_E0000, env->mtrr_fixed[7]);
++ kvm_msr_entry_set(&msrs[n++],
++ MSR_MTRRfix4K_E8000, env->mtrr_fixed[8]);
++ kvm_msr_entry_set(&msrs[n++],
++ MSR_MTRRfix4K_F0000, env->mtrr_fixed[9]);
++ kvm_msr_entry_set(&msrs[n++],
++ MSR_MTRRfix4K_F8000, env->mtrr_fixed[10]);
++ for (i = 0; i < MSR_MTRRcap_VCNT; i++) {
++ kvm_msr_entry_set(&msrs[n++],
++ MSR_MTRRphysBase(i), env->mtrr_var[i].base);
++ kvm_msr_entry_set(&msrs[n++],
++ MSR_MTRRphysMask(i), env->mtrr_var[i].mask);
++ }
++ }
+
+ /* Note: MSR_IA32_FEATURE_CONTROL is written separately, see
+ * kvm_put_msr_feature_control. */
+@@ -1484,7 +1520,7 @@ static int kvm_get_msrs(X86CPU *cpu)
+ CPUX86State *env = &cpu->env;
+ struct {
+ struct kvm_msrs info;
+- struct kvm_msr_entry entries[100];
++ struct kvm_msr_entry entries[150];
+ } msr_data;
+ struct kvm_msr_entry *msrs = msr_data.entries;
+ int ret, i, n;
+@@ -1572,6 +1608,24 @@ static int kvm_get_msrs(X86CPU *cpu)
+ if (has_msr_hv_tsc) {
+ msrs[n++].index = HV_X64_MSR_REFERENCE_TSC;
+ }
++ if (has_msr_mtrr) {
++ msrs[n++].index = MSR_MTRRdefType;
++ msrs[n++].index = MSR_MTRRfix64K_00000;
++ msrs[n++].index = MSR_MTRRfix16K_80000;
++ msrs[n++].index = MSR_MTRRfix16K_A0000;
++ msrs[n++].index = MSR_MTRRfix4K_C0000;
++ msrs[n++].index = MSR_MTRRfix4K_C8000;
++ msrs[n++].index = MSR_MTRRfix4K_D0000;
++ msrs[n++].index = MSR_MTRRfix4K_D8000;
++ msrs[n++].index = MSR_MTRRfix4K_E0000;
++ msrs[n++].index = MSR_MTRRfix4K_E8000;
++ msrs[n++].index = MSR_MTRRfix4K_F0000;
++ msrs[n++].index = MSR_MTRRfix4K_F8000;
++ for (i = 0; i < MSR_MTRRcap_VCNT; i++) {
++ msrs[n++].index = MSR_MTRRphysBase(i);
++ msrs[n++].index = MSR_MTRRphysMask(i);
++ }
++ }
+
+ msr_data.info.nmsrs = n;
+ ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_MSRS, &msr_data);
+@@ -1692,6 +1746,49 @@ static int kvm_get_msrs(X86CPU *cpu)
+ case HV_X64_MSR_REFERENCE_TSC:
+ env->msr_hv_tsc = msrs[i].data;
+ break;
++ case MSR_MTRRdefType:
++ env->mtrr_deftype = msrs[i].data;
++ break;
++ case MSR_MTRRfix64K_00000:
++ env->mtrr_fixed[0] = msrs[i].data;
++ break;
++ case MSR_MTRRfix16K_80000:
++ env->mtrr_fixed[1] = msrs[i].data;
++ break;
++ case MSR_MTRRfix16K_A0000:
++ env->mtrr_fixed[2] = msrs[i].data;
++ break;
++ case MSR_MTRRfix4K_C0000:
++ env->mtrr_fixed[3] = msrs[i].data;
++ break;
++ case MSR_MTRRfix4K_C8000:
++ env->mtrr_fixed[4] = msrs[i].data;
++ break;
++ case MSR_MTRRfix4K_D0000:
++ env->mtrr_fixed[5] = msrs[i].data;
++ break;
++ case MSR_MTRRfix4K_D8000:
++ env->mtrr_fixed[6] = msrs[i].data;
++ break;
++ case MSR_MTRRfix4K_E0000:
++ env->mtrr_fixed[7] = msrs[i].data;
++ break;
++ case MSR_MTRRfix4K_E8000:
++ env->mtrr_fixed[8] = msrs[i].data;
++ break;
++ case MSR_MTRRfix4K_F0000:
++ env->mtrr_fixed[9] = msrs[i].data;
++ break;
++ case MSR_MTRRfix4K_F8000:
++ env->mtrr_fixed[10] = msrs[i].data;
++ break;
++ case MSR_MTRRphysBase(0) ... MSR_MTRRphysMask(MSR_MTRRcap_VCNT - 1):
++ if (index & 1) {
++ env->mtrr_var[MSR_MTRRphysIndex(index)].mask = msrs[i].data;
++ } else {
++ env->mtrr_var[MSR_MTRRphysIndex(index)].base = msrs[i].data;
++ }
++ break;
+ }
+ }
+
+diff --git a/target-i386/machine.c b/target-i386/machine.c
+index 16d2f6a..fb89065 100644
+--- a/target-i386/machine.c
++++ b/target-i386/machine.c
+@@ -677,7 +677,7 @@ VMStateDescription vmstate_x86_cpu = {
+ /* MTRRs */
+ VMSTATE_UINT64_ARRAY_V(env.mtrr_fixed, X86CPU, 11, 8),
+ VMSTATE_UINT64_V(env.mtrr_deftype, X86CPU, 8),
+- VMSTATE_MTRR_VARS(env.mtrr_var, X86CPU, 8, 8),
++ VMSTATE_MTRR_VARS(env.mtrr_var, X86CPU, MSR_MTRRcap_VCNT, 8),
+ /* KVM-related states */
+ VMSTATE_INT32_V(env.interrupt_injected, X86CPU, 9),
+ VMSTATE_UINT32_V(env.mp_state, X86CPU, 9),
+diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h
+index d797d26..6e4e2b2 100644
+--- a/target-xtensa/cpu.h
++++ b/target-xtensa/cpu.h
+@@ -471,6 +471,12 @@ static inline xtensa_tlb_entry *xtensa_tlb_get_entry(CPUXtensaState *env,
+ env->itlb[wi] + ei;
+ }
+
++static inline uint32_t xtensa_replicate_windowstart(CPUXtensaState *env)
++{
++ return env->sregs[WINDOW_START] |
++ (env->sregs[WINDOW_START] << env->config->nareg / 4);
++}
++
+ /* MMU modes definitions */
+ #define MMU_MODE0_SUFFIX _ring0
+ #define MMU_MODE1_SUFFIX _ring1
+diff --git a/target-xtensa/op_helper.c b/target-xtensa/op_helper.c
+index dae1386..872e5a8 100644
+--- a/target-xtensa/op_helper.c
++++ b/target-xtensa/op_helper.c
+@@ -235,6 +235,12 @@ void HELPER(entry)(CPUXtensaState *env, uint32_t pc, uint32_t s, uint32_t imm)
+ pc, env->sregs[PS]);
+ HELPER(exception_cause)(env, pc, ILLEGAL_INSTRUCTION_CAUSE);
+ } else {
++ uint32_t windowstart = xtensa_replicate_windowstart(env) >>
++ (env->sregs[WINDOW_BASE] + 1);
++
++ if (windowstart & ((1 << callinc) - 1)) {
++ HELPER(window_check)(env, pc, callinc);
++ }
+ env->regs[(callinc << 2) | (s & 3)] = env->regs[s] - (imm << 3);
+ rotate_window(env, callinc);
+ env->sregs[WINDOW_START] |=
+diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
+index 2f22cce..ff7eb23 100644
+--- a/target-xtensa/translate.c
++++ b/target-xtensa/translate.c
+@@ -884,6 +884,11 @@ static TCGv_i32 gen_mac16_m(TCGv_i32 v, bool hi, bool is_unsigned)
+ return m;
+ }
+
++static inline unsigned xtensa_op0_insn_len(unsigned op0)
++{
++ return op0 >= 8 ? 2 : 3;
++}
++
+ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc)
+ {
+ #define HAS_OPTION_BITS(opt) do { \
+@@ -986,6 +991,7 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc)
+ uint8_t b0 = cpu_ldub_code(env, dc->pc);
+ uint8_t b1 = cpu_ldub_code(env, dc->pc + 1);
+ uint8_t b2 = 0;
++ unsigned len = xtensa_op0_insn_len(OP0);
+
+ static const uint32_t B4CONST[] = {
+ 0xffffffff, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 16, 32, 64, 128, 256
+@@ -995,13 +1001,19 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc)
+ 32768, 65536, 2, 3, 4, 5, 6, 7, 8, 10, 12, 16, 32, 64, 128, 256
+ };
+
+- if (OP0 >= 8) {
+- dc->next_pc = dc->pc + 2;
++ switch (len) {
++ case 2:
+ HAS_OPTION(XTENSA_OPTION_CODE_DENSITY);
+- } else {
+- dc->next_pc = dc->pc + 3;
++ break;
++
++ case 3:
+ b2 = cpu_ldub_code(env, dc->pc + 2);
++ break;
++
++ default:
++ RESERVED();
+ }
++ dc->next_pc = dc->pc + len;
+
+ switch (OP0) {
+ case 0: /*QRST*/
+@@ -2946,6 +2958,12 @@ invalid_opcode:
+ #undef HAS_OPTION
+ }
+
++static inline unsigned xtensa_insn_len(CPUXtensaState *env, DisasContext *dc)
++{
++ uint8_t b0 = cpu_ldub_code(env, dc->pc);
++ return xtensa_op0_insn_len(OP0);
++}
++
+ static void check_breakpoint(CPUXtensaState *env, DisasContext *dc)
+ {
+ CPUState *cs = CPU(xtensa_env_get_cpu(env));
+@@ -3078,6 +3096,7 @@ void gen_intermediate_code_internal(XtensaCPU *cpu,
+ } while (dc.is_jmp == DISAS_NEXT &&
+ insn_count < max_insns &&
+ dc.pc < next_page_start &&
++ dc.pc + xtensa_insn_len(env, &dc) <= next_page_start &&
+ tcg_ctx.gen_opc_ptr < gen_opc_end);
+
+ reset_litbase(&dc);
+diff --git a/tcg/mips/tcg-target.c b/tcg/mips/tcg-target.c
+index 9cce356..b7f4d67 100644
+--- a/tcg/mips/tcg-target.c
++++ b/tcg/mips/tcg-target.c
+@@ -1302,7 +1302,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is_64)
+ so we can reuse that for the base. */
+ base = (TARGET_LONG_BITS == 32 ? TCG_REG_A1 : TCG_REG_A2);
+ tcg_out_tlb_load(s, base, addr_regl, addr_regh, mem_index,
+- s_bits, label_ptr, 1);
++ s_bits, label_ptr, 0);
+ tcg_out_qemu_st_direct(s, data_regl, data_regh, base, opc);
+ add_qemu_ldst_label(s, 0, opc, data_regl, data_regh, addr_regl, addr_regh,
+ mem_index, s->code_ptr, label_ptr);
+diff --git a/tests/Makefile b/tests/Makefile
+index 4b2e1bb..2ea54fc 100644
+--- a/tests/Makefile
++++ b/tests/Makefile
+@@ -187,7 +187,8 @@ check-qtest-xtensaeb-y = $(check-qtest-xtensa-y)
+
+ # qom-test works for all sysemu architectures:
+ $(foreach target,$(SYSEMU_TARGET_LIST), \
+- $(eval check-qtest-$(target)-y += tests/qom-test$(EXESUF)))
++ $(if $(findstring tests/qom-test$(EXESUF), $(check-qtest-$(target)-y)),, \
++ $(eval check-qtest-$(target)-y += tests/qom-test$(EXESUF))))
+
+ check-qapi-schema-y := $(addprefix tests/qapi-schema/, \
+ comments.json empty.json funny-char.json indented-expr.json \
+diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json
+index ab4d3d9..d43b5fd 100644
+--- a/tests/qapi-schema/qapi-schema-test.json
++++ b/tests/qapi-schema/qapi-schema-test.json
+@@ -33,6 +33,9 @@
+ { 'type': 'UserDefB',
+ 'data': { 'integer': 'int' } }
+
++{ 'type': 'UserDefC',
++ 'data': { 'string1': 'str', 'string2': 'str' } }
++
+ { 'union': 'UserDefUnion',
+ 'base': 'UserDefZero',
+ 'data': { 'a' : 'UserDefA', 'b' : 'UserDefB' } }
+@@ -47,6 +50,13 @@
+ # FIXME generated struct UserDefFlatUnion has members for direct base
+ # UserDefOne, but lacks members for indirect base UserDefZero
+
++# this variant of UserDefFlatUnion defaults to a union that uses fields with
++# allocated types to test corner cases in the cleanup/dealloc visitor
++{ 'union': 'UserDefFlatUnion2',
++ 'base': 'UserDefUnionBase',
++ 'discriminator': 'enum1',
++ 'data': { 'value1' : 'UserDefC', 'value2' : 'UserDefB', 'value3' : 'UserDefA' } }
++
+ { 'union': 'UserDefAnonUnion',
+ 'discriminator': {},
+ 'data': { 'uda': 'UserDefA', 's': 'str', 'i': 'int' } }
+diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
+index 95e9899..08d7304 100644
+--- a/tests/qapi-schema/qapi-schema-test.out
++++ b/tests/qapi-schema/qapi-schema-test.out
+@@ -6,9 +6,11 @@
+ OrderedDict([('type', 'UserDefNested'), ('data', OrderedDict([('string0', 'str'), ('dict1', OrderedDict([('string1', 'str'), ('dict2', OrderedDict([('userdef1', 'UserDefOne'), ('string2', 'str')])), ('*dict3', OrderedDict([('userdef2', 'UserDefOne'), ('string3', 'str')]))]))]))]),
+ OrderedDict([('type', 'UserDefA'), ('data', OrderedDict([('boolean', 'bool')]))]),
+ OrderedDict([('type', 'UserDefB'), ('data', OrderedDict([('integer', 'int')]))]),
++ OrderedDict([('type', 'UserDefC'), ('data', OrderedDict([('string1', 'str'), ('string2', 'str')]))]),
+ OrderedDict([('union', 'UserDefUnion'), ('base', 'UserDefZero'), ('data', OrderedDict([('a', 'UserDefA'), ('b', 'UserDefB')]))]),
+ OrderedDict([('type', 'UserDefUnionBase'), ('data', OrderedDict([('string', 'str'), ('enum1', 'EnumOne')]))]),
+ OrderedDict([('union', 'UserDefFlatUnion'), ('base', 'UserDefUnionBase'), ('discriminator', 'enum1'), ('data', OrderedDict([('value1', 'UserDefA'), ('value2', 'UserDefB'), ('value3', 'UserDefB')]))]),
++ OrderedDict([('union', 'UserDefFlatUnion2'), ('base', 'UserDefUnionBase'), ('discriminator', 'enum1'), ('data', OrderedDict([('value1', 'UserDefC'), ('value2', 'UserDefB'), ('value3', 'UserDefA')]))]),
+ OrderedDict([('union', 'UserDefAnonUnion'), ('discriminator', OrderedDict()), ('data', OrderedDict([('uda', 'UserDefA'), ('s', 'str'), ('i', 'int')]))]),
+ OrderedDict([('union', 'UserDefNativeListUnion'), ('data', OrderedDict([('integer', ['int']), ('s8', ['int8']), ('s16', ['int16']), ('s32', ['int32']), ('s64', ['int64']), ('u8', ['uint8']), ('u16', ['uint16']), ('u32', ['uint32']), ('u64', ['uint64']), ('number', ['number']), ('boolean', ['bool']), ('string', ['str'])]))]),
+ OrderedDict([('command', 'user_def_cmd'), ('data', OrderedDict())]),
+@@ -32,6 +34,7 @@
+ OrderedDict([('type', 'UserDefNested'), ('data', OrderedDict([('string0', 'str'), ('dict1', OrderedDict([('string1', 'str'), ('dict2', OrderedDict([('userdef1', 'UserDefOne'), ('string2', 'str')])), ('*dict3', OrderedDict([('userdef2', 'UserDefOne'), ('string3', 'str')]))]))]))]),
+ OrderedDict([('type', 'UserDefA'), ('data', OrderedDict([('boolean', 'bool')]))]),
+ OrderedDict([('type', 'UserDefB'), ('data', OrderedDict([('integer', 'int')]))]),
++ OrderedDict([('type', 'UserDefC'), ('data', OrderedDict([('string1', 'str'), ('string2', 'str')]))]),
+ OrderedDict([('type', 'UserDefUnionBase'), ('data', OrderedDict([('string', 'str'), ('enum1', 'EnumOne')]))]),
+ OrderedDict([('type', 'UserDefOptions'), ('data', OrderedDict([('*i64', ['int']), ('*u64', ['uint64']), ('*u16', ['uint16']), ('*i64x', 'int'), ('*u64x', 'uint64')]))]),
+ OrderedDict([('type', 'EventStructOne'), ('data', OrderedDict([('struct1', 'UserDefOne'), ('string', 'str'), ('*enum2', 'EnumOne')]))])]
+diff --git a/tests/qemu-iotests/026.out b/tests/qemu-iotests/026.out
+index f7c78e7..ad84ac2 100644
+--- a/tests/qemu-iotests/026.out
++++ b/tests/qemu-iotests/026.out
+@@ -14,6 +14,8 @@ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: l1_update; errno: 5; imm: off; once: off; write
++Failed to flush the L2 table cache: Input/output error
++Failed to flush the refcount block cache: Input/output error
+ write failed: Input/output error
+
+ 1 leaked clusters were found on the image.
+@@ -21,6 +23,8 @@ This means waste of disk space, but no harm to data.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: l1_update; errno: 5; imm: off; once: off; write -b
++Failed to flush the L2 table cache: Input/output error
++Failed to flush the refcount block cache: Input/output error
+ write failed: Input/output error
+
+ 1 leaked clusters were found on the image.
+@@ -38,6 +42,8 @@ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: l1_update; errno: 28; imm: off; once: off; write
++Failed to flush the L2 table cache: No space left on device
++Failed to flush the refcount block cache: No space left on device
+ write failed: No space left on device
+
+ 1 leaked clusters were found on the image.
+@@ -45,6 +51,8 @@ This means waste of disk space, but no harm to data.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: l1_update; errno: 28; imm: off; once: off; write -b
++Failed to flush the L2 table cache: No space left on device
++Failed to flush the refcount block cache: No space left on device
+ write failed: No space left on device
+
+ 1 leaked clusters were found on the image.
+@@ -70,7 +78,11 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+ Event: l2_load; errno: 5; imm: off; once: off; write
+ wrote 131072/131072 bytes at offset 0
+ 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
++Failed to flush the L2 table cache: Input/output error
++Failed to flush the refcount block cache: Input/output error
+ write failed: Input/output error
++Failed to flush the L2 table cache: Input/output error
++Failed to flush the refcount block cache: Input/output error
+ read failed: Input/output error
+ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+@@ -78,7 +90,11 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+ Event: l2_load; errno: 5; imm: off; once: off; write -b
+ wrote 131072/131072 bytes at offset 0
+ 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
++Failed to flush the L2 table cache: Input/output error
++Failed to flush the refcount block cache: Input/output error
+ write failed: Input/output error
++Failed to flush the L2 table cache: Input/output error
++Failed to flush the refcount block cache: Input/output error
+ read failed: Input/output error
+ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+@@ -102,7 +118,11 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+ Event: l2_load; errno: 28; imm: off; once: off; write
+ wrote 131072/131072 bytes at offset 0
+ 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
++Failed to flush the L2 table cache: No space left on device
++Failed to flush the refcount block cache: No space left on device
+ write failed: No space left on device
++Failed to flush the L2 table cache: No space left on device
++Failed to flush the refcount block cache: No space left on device
+ read failed: No space left on device
+ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+@@ -110,12 +130,17 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+ Event: l2_load; errno: 28; imm: off; once: off; write -b
+ wrote 131072/131072 bytes at offset 0
+ 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
++Failed to flush the L2 table cache: No space left on device
++Failed to flush the refcount block cache: No space left on device
+ write failed: No space left on device
++Failed to flush the L2 table cache: No space left on device
++Failed to flush the refcount block cache: No space left on device
+ read failed: No space left on device
+ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: l2_update; errno: 5; imm: off; once: on; write
++Failed to flush the L2 table cache: Input/output error
+ write failed: Input/output error
+
+ 127 leaked clusters were found on the image.
+@@ -123,6 +148,7 @@ This means waste of disk space, but no harm to data.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: l2_update; errno: 5; imm: off; once: on; write -b
++Failed to flush the L2 table cache: Input/output error
+ write failed: Input/output error
+
+ 127 leaked clusters were found on the image.
+@@ -130,6 +156,8 @@ This means waste of disk space, but no harm to data.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: l2_update; errno: 5; imm: off; once: off; write
++Failed to flush the L2 table cache: Input/output error
++Failed to flush the refcount block cache: Input/output error
+ write failed: Input/output error
+
+ 127 leaked clusters were found on the image.
+@@ -137,6 +165,8 @@ This means waste of disk space, but no harm to data.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: l2_update; errno: 5; imm: off; once: off; write -b
++Failed to flush the L2 table cache: Input/output error
++Failed to flush the refcount block cache: Input/output error
+ write failed: Input/output error
+
+ 127 leaked clusters were found on the image.
+@@ -144,6 +174,7 @@ This means waste of disk space, but no harm to data.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: l2_update; errno: 28; imm: off; once: on; write
++Failed to flush the L2 table cache: No space left on device
+ write failed: No space left on device
+
+ 127 leaked clusters were found on the image.
+@@ -151,6 +182,7 @@ This means waste of disk space, but no harm to data.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: l2_update; errno: 28; imm: off; once: on; write -b
++Failed to flush the L2 table cache: No space left on device
+ write failed: No space left on device
+
+ 127 leaked clusters were found on the image.
+@@ -158,6 +190,8 @@ This means waste of disk space, but no harm to data.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: l2_update; errno: 28; imm: off; once: off; write
++Failed to flush the L2 table cache: No space left on device
++Failed to flush the refcount block cache: No space left on device
+ write failed: No space left on device
+
+ 127 leaked clusters were found on the image.
+@@ -165,6 +199,8 @@ This means waste of disk space, but no harm to data.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: l2_update; errno: 28; imm: off; once: off; write -b
++Failed to flush the L2 table cache: No space left on device
++Failed to flush the refcount block cache: No space left on device
+ write failed: No space left on device
+
+ 127 leaked clusters were found on the image.
+@@ -182,11 +218,15 @@ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: l2_alloc.write; errno: 5; imm: off; once: off; write
++Failed to flush the L2 table cache: Input/output error
++Failed to flush the refcount block cache: Input/output error
+ write failed: Input/output error
+ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: l2_alloc.write; errno: 5; imm: off; once: off; write -b
++Failed to flush the L2 table cache: Input/output error
++Failed to flush the refcount block cache: Input/output error
+ write failed: Input/output error
+
+ 1 leaked clusters were found on the image.
+@@ -204,11 +244,15 @@ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: l2_alloc.write; errno: 28; imm: off; once: off; write
++Failed to flush the L2 table cache: No space left on device
++Failed to flush the refcount block cache: No space left on device
+ write failed: No space left on device
+ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: l2_alloc.write; errno: 28; imm: off; once: off; write -b
++Failed to flush the L2 table cache: No space left on device
++Failed to flush the refcount block cache: No space left on device
+ write failed: No space left on device
+
+ 1 leaked clusters were found on the image.
+@@ -226,11 +270,15 @@ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: write_aio; errno: 5; imm: off; once: off; write
++Failed to flush the L2 table cache: Input/output error
++Failed to flush the refcount block cache: Input/output error
+ write failed: Input/output error
+ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: write_aio; errno: 5; imm: off; once: off; write -b
++Failed to flush the L2 table cache: Input/output error
++Failed to flush the refcount block cache: Input/output error
+ write failed: Input/output error
+ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+@@ -246,11 +294,15 @@ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: write_aio; errno: 28; imm: off; once: off; write
++Failed to flush the L2 table cache: No space left on device
++Failed to flush the refcount block cache: No space left on device
+ write failed: No space left on device
+ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: write_aio; errno: 28; imm: off; once: off; write -b
++Failed to flush the L2 table cache: No space left on device
++Failed to flush the refcount block cache: No space left on device
+ write failed: No space left on device
+ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+@@ -266,11 +318,15 @@ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: refblock_load; errno: 5; imm: off; once: off; write
++Failed to flush the L2 table cache: Input/output error
++Failed to flush the refcount block cache: Input/output error
+ write failed: Input/output error
+ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: refblock_load; errno: 5; imm: off; once: off; write -b
++Failed to flush the L2 table cache: Input/output error
++Failed to flush the refcount block cache: Input/output error
+ write failed: Input/output error
+ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+@@ -286,51 +342,67 @@ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: refblock_load; errno: 28; imm: off; once: off; write
++Failed to flush the L2 table cache: No space left on device
++Failed to flush the refcount block cache: No space left on device
+ write failed: No space left on device
+ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: refblock_load; errno: 28; imm: off; once: off; write -b
++Failed to flush the L2 table cache: No space left on device
++Failed to flush the refcount block cache: No space left on device
+ write failed: No space left on device
+ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: refblock_update_part; errno: 5; imm: off; once: on; write
++Failed to flush the refcount block cache: Input/output error
+ write failed: Input/output error
+ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: refblock_update_part; errno: 5; imm: off; once: on; write -b
++Failed to flush the refcount block cache: Input/output error
+ write failed: Input/output error
+ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: refblock_update_part; errno: 5; imm: off; once: off; write
++Failed to flush the L2 table cache: Input/output error
++Failed to flush the refcount block cache: Input/output error
+ write failed: Input/output error
+ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: refblock_update_part; errno: 5; imm: off; once: off; write -b
++Failed to flush the L2 table cache: Input/output error
++Failed to flush the refcount block cache: Input/output error
+ write failed: Input/output error
+ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: refblock_update_part; errno: 28; imm: off; once: on; write
++Failed to flush the refcount block cache: No space left on device
+ write failed: No space left on device
+ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: refblock_update_part; errno: 28; imm: off; once: on; write -b
++Failed to flush the refcount block cache: No space left on device
+ write failed: No space left on device
+ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: refblock_update_part; errno: 28; imm: off; once: off; write
++Failed to flush the L2 table cache: No space left on device
++Failed to flush the refcount block cache: No space left on device
+ write failed: No space left on device
+ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: refblock_update_part; errno: 28; imm: off; once: off; write -b
++Failed to flush the L2 table cache: No space left on device
++Failed to flush the refcount block cache: No space left on device
+ write failed: No space left on device
+ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+@@ -346,11 +418,15 @@ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: refblock_alloc; errno: 5; imm: off; once: off; write
++Failed to flush the L2 table cache: Input/output error
++Failed to flush the refcount block cache: Input/output error
+ write failed: Input/output error
+ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: refblock_alloc; errno: 5; imm: off; once: off; write -b
++Failed to flush the L2 table cache: Input/output error
++Failed to flush the refcount block cache: Input/output error
+ write failed: Input/output error
+ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+@@ -366,11 +442,15 @@ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: refblock_alloc; errno: 28; imm: off; once: off; write
++Failed to flush the L2 table cache: No space left on device
++Failed to flush the refcount block cache: No space left on device
+ write failed: No space left on device
+ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: refblock_alloc; errno: 28; imm: off; once: off; write -b
++Failed to flush the L2 table cache: No space left on device
++Failed to flush the refcount block cache: No space left on device
+ write failed: No space left on device
+ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+@@ -386,11 +466,15 @@ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: cluster_alloc; errno: 5; imm: off; once: off; write
++Failed to flush the L2 table cache: Input/output error
++Failed to flush the refcount block cache: Input/output error
+ write failed: Input/output error
+ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: cluster_alloc; errno: 5; imm: off; once: off; write -b
++Failed to flush the L2 table cache: Input/output error
++Failed to flush the refcount block cache: Input/output error
+ write failed: Input/output error
+ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+@@ -406,11 +490,15 @@ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: cluster_alloc; errno: 28; imm: off; once: off; write
++Failed to flush the L2 table cache: No space left on device
++Failed to flush the refcount block cache: No space left on device
+ write failed: No space left on device
+ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: cluster_alloc; errno: 28; imm: off; once: off; write -b
++Failed to flush the L2 table cache: No space left on device
++Failed to flush the refcount block cache: No space left on device
+ write failed: No space left on device
+ No errors were found on the image.
+
+@@ -429,6 +517,8 @@ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: refblock_alloc.hookup; errno: 28; imm: off; once: off; write
++Failed to flush the L2 table cache: No space left on device
++Failed to flush the refcount block cache: No space left on device
+ write failed: No space left on device
+
+ 55 leaked clusters were found on the image.
+@@ -436,6 +526,8 @@ This means waste of disk space, but no harm to data.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: refblock_alloc.hookup; errno: 28; imm: off; once: off; write -b
++Failed to flush the L2 table cache: No space left on device
++Failed to flush the refcount block cache: No space left on device
+ write failed: No space left on device
+
+ 251 leaked clusters were found on the image.
+@@ -453,11 +545,15 @@ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: refblock_alloc.write; errno: 28; imm: off; once: off; write
++Failed to flush the L2 table cache: No space left on device
++Failed to flush the refcount block cache: No space left on device
+ write failed: No space left on device
+ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: refblock_alloc.write; errno: 28; imm: off; once: off; write -b
++Failed to flush the L2 table cache: No space left on device
++Failed to flush the refcount block cache: No space left on device
+ write failed: No space left on device
+ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+@@ -473,6 +569,8 @@ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: refblock_alloc.write_blocks; errno: 28; imm: off; once: off; write
++Failed to flush the L2 table cache: No space left on device
++Failed to flush the refcount block cache: No space left on device
+ write failed: No space left on device
+
+ 11 leaked clusters were found on the image.
+@@ -480,6 +578,8 @@ This means waste of disk space, but no harm to data.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: refblock_alloc.write_blocks; errno: 28; imm: off; once: off; write -b
++Failed to flush the L2 table cache: No space left on device
++Failed to flush the refcount block cache: No space left on device
+ write failed: No space left on device
+
+ 23 leaked clusters were found on the image.
+@@ -497,6 +597,8 @@ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: refblock_alloc.write_table; errno: 28; imm: off; once: off; write
++Failed to flush the L2 table cache: No space left on device
++Failed to flush the refcount block cache: No space left on device
+ write failed: No space left on device
+
+ 11 leaked clusters were found on the image.
+@@ -504,6 +606,8 @@ This means waste of disk space, but no harm to data.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: refblock_alloc.write_table; errno: 28; imm: off; once: off; write -b
++Failed to flush the L2 table cache: No space left on device
++Failed to flush the refcount block cache: No space left on device
+ write failed: No space left on device
+
+ 23 leaked clusters were found on the image.
+@@ -521,6 +625,8 @@ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: refblock_alloc.switch_table; errno: 28; imm: off; once: off; write
++Failed to flush the L2 table cache: No space left on device
++Failed to flush the refcount block cache: No space left on device
+ write failed: No space left on device
+
+ 11 leaked clusters were found on the image.
+@@ -528,6 +634,8 @@ This means waste of disk space, but no harm to data.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: refblock_alloc.switch_table; errno: 28; imm: off; once: off; write -b
++Failed to flush the L2 table cache: No space left on device
++Failed to flush the refcount block cache: No space left on device
+ write failed: No space left on device
+
+ 23 leaked clusters were found on the image.
+@@ -543,6 +651,8 @@ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: l1_grow.alloc_table; errno: 5; imm: off; once: off
++Failed to flush the L2 table cache: Input/output error
++Failed to flush the refcount block cache: Input/output error
+ write failed: Input/output error
+ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+@@ -553,6 +663,8 @@ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: l1_grow.alloc_table; errno: 28; imm: off; once: off
++Failed to flush the L2 table cache: No space left on device
++Failed to flush the refcount block cache: No space left on device
+ write failed: No space left on device
+ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+@@ -563,6 +675,8 @@ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: l1_grow.write_table; errno: 5; imm: off; once: off
++Failed to flush the L2 table cache: Input/output error
++Failed to flush the refcount block cache: Input/output error
+ write failed: Input/output error
+ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+@@ -573,6 +687,8 @@ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: l1_grow.write_table; errno: 28; imm: off; once: off
++Failed to flush the L2 table cache: No space left on device
++Failed to flush the refcount block cache: No space left on device
+ write failed: No space left on device
+ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+@@ -583,6 +699,8 @@ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: l1_grow.activate_table; errno: 5; imm: off; once: off
++Failed to flush the L2 table cache: Input/output error
++Failed to flush the refcount block cache: Input/output error
+ write failed: Input/output error
+
+ 96 leaked clusters were found on the image.
+@@ -595,6 +713,8 @@ No errors were found on the image.
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+
+ Event: l1_grow.activate_table; errno: 28; imm: off; once: off
++Failed to flush the L2 table cache: No space left on device
++Failed to flush the refcount block cache: No space left on device
+ write failed: No space left on device
+
+ 96 leaked clusters were found on the image.
+diff --git a/tests/qemu-iotests/071.out b/tests/qemu-iotests/071.out
+index 5f840a9..0624581 100644
+--- a/tests/qemu-iotests/071.out
++++ b/tests/qemu-iotests/071.out
+@@ -30,10 +30,14 @@ blkverify: read sector_num=0 nb_sectors=4 contents mismatch in sector 0
+
+ === Testing blkdebug through filename ===
+
++Failed to flush the L2 table cache: Input/output error
++Failed to flush the refcount block cache: Input/output error
+ read failed: Input/output error
+
+ === Testing blkdebug through file blockref ===
+
++Failed to flush the L2 table cache: Input/output error
++Failed to flush the refcount block cache: Input/output error
+ read failed: Input/output error
+
+ === Testing blkdebug on existing block device ===
+@@ -48,6 +52,8 @@ read failed: Input/output error
+ {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"}
+ {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}}
+ {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "floppy0", "tray-open": true}}
++qemu-system-x86_64: Failed to flush the L2 table cache: Input/output error
++qemu-system-x86_64: Failed to flush the refcount block cache: Input/output error
+
+
+ === Testing blkverify on existing block device ===
+@@ -86,5 +92,7 @@ read failed: Input/output error
+ {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"}
+ {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}}
+ {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "floppy0", "tray-open": true}}
++qemu-system-x86_64: Failed to flush the L2 table cache: Input/output error
++qemu-system-x86_64: Failed to flush the refcount block cache: Input/output error
+
+ *** done
+diff --git a/tests/qemu-iotests/080 b/tests/qemu-iotests/080
+index 6b3a3e7..b9f9630 100755
+--- a/tests/qemu-iotests/080
++++ b/tests/qemu-iotests/080
+@@ -78,6 +78,8 @@ poke_file "$TEST_IMG" "$offset_backing_file_offset" "\xff\xff\xff\xff\xff\xff\xf
+ poke_file "$TEST_IMG" "$offset_ext_magic" "\x12\x34\x56\x78"
+ poke_file "$TEST_IMG" "$offset_ext_size" "\x7f\xff\xff\xff"
+ { $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
++poke_file "$TEST_IMG" "$offset_backing_file_offset" "\x00\x00\x00\x00\x00\x00\x00\x$(printf %x $offset_ext_size)"
++{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
+ poke_file "$TEST_IMG" "$offset_backing_file_offset" "\x00\x00\x00\x00\x00\x00\x00\x00"
+ { $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
+
+diff --git a/tests/qemu-iotests/080.out b/tests/qemu-iotests/080.out
+index f7a943c..33d1f71 100644
+--- a/tests/qemu-iotests/080.out
++++ b/tests/qemu-iotests/080.out
+@@ -13,6 +13,8 @@ qemu-io: can't open device TEST_DIR/t.qcow2: Invalid backing file offset
+ no file open, try 'help open'
+ qemu-io: can't open device TEST_DIR/t.qcow2: Header extension too large
+ no file open, try 'help open'
++qemu-io: can't open device TEST_DIR/t.qcow2: Header extension too large
++no file open, try 'help open'
+
+ == Huge refcount table size ==
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+diff --git a/tests/qemu-iotests/087 b/tests/qemu-iotests/087
+index 82c56b1..d7454d1 100755
+--- a/tests/qemu-iotests/087
++++ b/tests/qemu-iotests/087
+@@ -218,6 +218,23 @@ run_qemu <<EOF
+ { "execute": "quit" }
+ EOF
+
++echo
++echo === Missing driver ===
++echo
++
++_make_test_img -o encryption=on $size
++run_qemu -S <<EOF
++{ "execute": "qmp_capabilities" }
++{ "execute": "blockdev-add",
++ "arguments": {
++ "options": {
++ "id": "disk"
++ }
++ }
++ }
++{ "execute": "quit" }
++EOF
++
+ # success, all done
+ echo "*** done"
+ rm -f $seq.full
+diff --git a/tests/qemu-iotests/087.out b/tests/qemu-iotests/087.out
+index 7fbee3f..f16bad0 100644
+--- a/tests/qemu-iotests/087.out
++++ b/tests/qemu-iotests/087.out
+@@ -64,4 +64,17 @@ QMP_VERSION
+ {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}}
+ {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "floppy0", "tray-open": true}}
+
++
++=== Missing driver ===
++
++Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on
++Testing: -S
++QMP_VERSION
++{"return": {}}
++{"error": {"class": "GenericError", "desc": "Invalid parameter type for 'driver', expected: string"}}
++{"return": {}}
++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"}
++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}}
++{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "floppy0", "tray-open": true}}
++
+ *** done
+diff --git a/tests/qemu-iotests/089.out b/tests/qemu-iotests/089.out
+index 4ca2f88..ab06c55 100644
+--- a/tests/qemu-iotests/089.out
++++ b/tests/qemu-iotests/089.out
+@@ -24,6 +24,8 @@ read 512/512 bytes at offset 0
+ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+ wrote 512/512 bytes at offset 229376
+ 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
++Failed to flush the L2 table cache: Input/output error
++Failed to flush the refcount block cache: Input/output error
+ read failed: Input/output error
+
+ === Testing qemu-img info output ===
+diff --git a/tests/qemu-iotests/101 b/tests/qemu-iotests/101
+new file mode 100755
+index 0000000..70fbf25
+--- /dev/null
++++ b/tests/qemu-iotests/101
+@@ -0,0 +1,58 @@
++#!/bin/bash
++#
++# Test short file I/O
++#
++# Copyright (C) 2014 Red Hat, Inc.
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program. If not, see <http://www.gnu.org/licenses/>.
++#
++
++# creator
++owner=stefanha@redhat.com
++
++seq=`basename $0`
++echo "QA output created by $seq"
++
++here=`pwd`
++tmp=/tmp/$$
++status=1 # failure is the default!
++
++_cleanup()
++{
++ _cleanup_test_img
++}
++trap "_cleanup; exit \$status" 0 1 2 3 15
++
++# get standard environment, filters and checks
++. ./common.rc
++. ./common.filter
++
++_supported_fmt raw
++_supported_proto file
++_supported_os Linux
++
++
++echo
++echo "== creating short image file =="
++dd if=/dev/zero of="$TEST_IMG" bs=1 count=320
++
++echo
++echo "== reading bytes beyond EOF gives zeroes =="
++$QEMU_IO -c "read -P 0 0 512" "$TEST_IMG" | _filter_qemu_io
++
++
++# success, all done
++echo "*** done"
++rm -f $seq.full
++status=0
+diff --git a/tests/qemu-iotests/101.out b/tests/qemu-iotests/101.out
+new file mode 100644
+index 0000000..9a996e8
+--- /dev/null
++++ b/tests/qemu-iotests/101.out
+@@ -0,0 +1,10 @@
++QA output created by 101
++
++== creating short image file ==
++320+0 records in
++320+0 records out
++
++== reading bytes beyond EOF gives zeroes ==
++read 512/512 bytes at offset 0
++512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
++*** done
+diff --git a/tests/qemu-iotests/113 b/tests/qemu-iotests/113
+new file mode 100755
+index 0000000..a2cd96b
+--- /dev/null
++++ b/tests/qemu-iotests/113
+@@ -0,0 +1,76 @@
++#!/bin/bash
++#
++# Test case for accessing creation options on image formats and
++# protocols not supporting image creation
++#
++# Copyright (C) 2014 Red Hat, Inc.
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program. If not, see <http://www.gnu.org/licenses/>.
++#
++
++# creator
++owner=mreitz@redhat.com
++
++seq="$(basename $0)"
++echo "QA output created by $seq"
++
++here="$PWD"
++tmp=/tmp/$$
++status=1 # failure is the default!
++
++_cleanup()
++{
++ _cleanup_test_img
++}
++trap "_cleanup; exit \$status" 0 1 2 3 15
++
++# get standard environment, filters and checks
++. ./common.rc
++. ./common.filter
++
++# We can only test one format here because we need its sample file
++_supported_fmt bochs
++_supported_proto nbd
++_supported_os Linux
++
++echo
++echo '=== Unsupported image creation in qemu-img create ==='
++echo
++
++$QEMU_IMG create -f $IMGFMT nbd://example.com 2>&1 64M | _filter_imgfmt
++
++echo
++echo '=== Unsupported image creation in qemu-img convert ==='
++echo
++
++# We could use any input image format here, but this is a bochs test, so just
++# use the bochs image
++_use_sample_img empty.bochs.bz2
++$QEMU_IMG convert -f $IMGFMT -O $IMGFMT "$TEST_IMG" nbd://example.com 2>&1 \
++ | _filter_imgfmt
++
++echo
++echo '=== Unsupported format in qemu-img amend ==='
++echo
++
++# The protocol does not matter here
++_use_sample_img empty.bochs.bz2
++$QEMU_IMG amend -f $IMGFMT -o foo=bar "$TEST_IMG" 2>&1 | _filter_imgfmt
++
++
++# success, all done
++echo
++echo '*** done'
++rm -f $seq.full
++status=0
+diff --git a/tests/qemu-iotests/113.out b/tests/qemu-iotests/113.out
+new file mode 100644
+index 0000000..00bdfd6
+--- /dev/null
++++ b/tests/qemu-iotests/113.out
+@@ -0,0 +1,15 @@
++QA output created by 113
++
++=== Unsupported image creation in qemu-img create ===
++
++qemu-img: nbd://example.com: Format driver 'IMGFMT' does not support image creation
++
++=== Unsupported image creation in qemu-img convert ===
++
++qemu-img: Format driver 'IMGFMT' does not support image creation
++
++=== Unsupported format in qemu-img amend ===
++
++qemu-img: Format driver 'IMGFMT' does not support any options to amend
++
++*** done
+diff --git a/tests/qemu-iotests/114 b/tests/qemu-iotests/114
+new file mode 100755
+index 0000000..d02e7ff
+--- /dev/null
++++ b/tests/qemu-iotests/114
+@@ -0,0 +1,61 @@
++#!/bin/bash
++#
++# Test invalid backing file format in qcow2 images
++#
++# Copyright (C) 2014 Red Hat, Inc.
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program. If not, see <http://www.gnu.org/licenses/>.
++#
++
++# creator
++owner=kwolf@redhat.com
++
++seq="$(basename $0)"
++echo "QA output created by $seq"
++
++here="$PWD"
++tmp=/tmp/$$
++status=1 # failure is the default!
++
++_cleanup()
++{
++ _cleanup_test_img
++}
++trap "_cleanup; exit \$status" 0 1 2 3 15
++
++# get standard environment, filters and checks
++. ./common.rc
++. ./common.filter
++
++_supported_fmt qcow2
++_supported_proto generic
++_supported_os Linux
++
++
++TEST_IMG="$TEST_IMG.base" _make_test_img 64M
++_make_test_img -b "$TEST_IMG.base" 64M
++
++# Set an invalid backing file format
++$PYTHON qcow2.py "$TEST_IMG" add-header-ext 0xE2792ACA "foo"
++_img_info
++
++# Try opening the image. Should fail (and not probe) in the first case, but
++# overriding the backing file format should be possible.
++$QEMU_IO -c "open $TEST_IMG" -c "read 0 4k" 2>&1 | _filter_qemu_io | _filter_testdir
++$QEMU_IO -c "open -o backing.driver=$IMGFMT $TEST_IMG" -c "read 0 4k" | _filter_qemu_io
++
++# success, all done
++echo '*** done'
++rm -f $seq.full
++status=0
+diff --git a/tests/qemu-iotests/114.out b/tests/qemu-iotests/114.out
+new file mode 100644
+index 0000000..6c6b210
+--- /dev/null
++++ b/tests/qemu-iotests/114.out
+@@ -0,0 +1,13 @@
++QA output created by 114
++Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864
++Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file='TEST_DIR/t.IMGFMT.base'
++image: TEST_DIR/t.IMGFMT
++file format: IMGFMT
++virtual size: 64M (67108864 bytes)
++cluster_size: 65536
++backing file: TEST_DIR/t.IMGFMT.base
++backing file format: foo
++qemu-io: can't open device TEST_DIR/t.qcow2: Could not open backing file: Unknown driver 'foo'
++read 4096/4096 bytes at offset 0
++4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
++*** done
+diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
+index e0ea7e3..e7760a2 100644
+--- a/tests/qemu-iotests/common.rc
++++ b/tests/qemu-iotests/common.rc
+@@ -189,7 +189,9 @@ _cleanup_test_img()
+ case "$IMGPROTO" in
+
+ nbd)
+- kill $QEMU_NBD_PID
++ if [ -n "$QEMU_NBD_PID" ]; then
++ kill $QEMU_NBD_PID
++ fi
+ rm -f "$TEST_IMG_FILE"
+ ;;
+ file)
+diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
+index 6e67f61..97026f3 100644
+--- a/tests/qemu-iotests/group
++++ b/tests/qemu-iotests/group
+@@ -100,3 +100,6 @@
+ 091 rw auto quick
+ 092 rw auto quick
+ 095 rw auto quick
++101 rw auto quick
++113 rw auto quick
++114 rw auto quick
+diff --git a/tests/qemu-iotests/qcow2.py b/tests/qemu-iotests/qcow2.py
+index 2058596..9cc4cf7 100755
+--- a/tests/qemu-iotests/qcow2.py
++++ b/tests/qemu-iotests/qcow2.py
+@@ -7,6 +7,10 @@ import string
+ class QcowHeaderExtension:
+
+ def __init__(self, magic, length, data):
++ if length % 8 != 0:
++ padding = 8 - (length % 8)
++ data += "\0" * padding
++
+ self.magic = magic
+ self.length = length
+ self.data = data
+diff --git a/tests/tcg/xtensa/test_mmu.S b/tests/tcg/xtensa/test_mmu.S
+index 58c5bca..a15316f 100644
+--- a/tests/tcg/xtensa/test_mmu.S
++++ b/tests/tcg/xtensa/test_mmu.S
+@@ -641,7 +641,7 @@ test cross_page_tb
+ witlb a2, a3
+ wdtlb a2, a3
+
+- movi a2, 0x00007ffd
++ movi a2, 0x00007ffc
+ movi a3, 20f
+ movi a4, 21f
+ sub a4, a4, a3
+@@ -651,7 +651,7 @@ test cross_page_tb
+ addi a2, a2, 1
+ addi a3, a3, 1
+ 1:
+- movi a2, 0x00007ffd
++ movi a2, 0x00007ffc
+ movi a3, 0x00008000
+ /* DTLB: OK, ITLB: OK */
+ jx a2
+@@ -668,10 +668,10 @@ test cross_page_tb
+ movi a3, 1
+ assert eq, a2, a3
+ rsr a2, epc1
+- movi a3, 0x8000
++ movi a3, 0x7fff
+ assert eq, a2, a3
+ rsr a2, excsave1
+- movi a3, 0x00007ffd
++ movi a3, 0x00007ffc
+ assert ne, a2, a3
+
+ reset_ps
+@@ -680,7 +680,7 @@ test cross_page_tb
+ movi a2, 0x0400000c /* PPN */
+ movi a3, 0x00008000 /* VPN */
+ wdtlb a2, a3
+- movi a2, 0x00007ffd
++ movi a2, 0x00007ffc
+ movi a3, 0x00008000
+ /* DTLB: FAIL, ITLB: OK */
+ jx a2
+@@ -689,10 +689,10 @@ test cross_page_tb
+ movi a3, 28
+ assert eq, a2, a3
+ rsr a2, epc1
+- movi a3, 0x7ffd
++ movi a3, 0x7ffc
+ assert eq, a2, a3
+ rsr a2, excsave1
+- movi a3, 0x00007ffd
++ movi a3, 0x00007ffc
+ assert eq, a2, a3
+
+ reset_ps
+@@ -703,7 +703,7 @@ test cross_page_tb
+ witlb a2, a3
+ movi a2, 0x04000003 /* PPN */
+ wdtlb a2, a3
+- movi a2, 0x00007ffd
++ movi a2, 0x00007ffc
+ movi a3, 0x00008000
+ /* DTLB: OK, ITLB: FAIL */
+ jx a2
+@@ -712,10 +712,10 @@ test cross_page_tb
+ movi a3, 20
+ assert eq, a2, a3
+ rsr a2, epc1
+- movi a3, 0x8000
++ movi a3, 0x7fff
+ assert eq, a2, a3
+ rsr a2, excsave1
+- movi a3, 0x00007ffd
++ movi a3, 0x00007ffc
+ assert ne, a2, a3
+
+ reset_ps
+@@ -724,7 +724,7 @@ test cross_page_tb
+ movi a2, 0x0400000c /* PPN */
+ movi a3, 0x00008000 /* VPN */
+ wdtlb a2, a3
+- movi a2, 0x00007ffd
++ movi a2, 0x00007ffc
+ movi a3, 0x00008000
+ /* DTLB: FAIL, ITLB: FAIL */
+ jx a2
+@@ -733,10 +733,10 @@ test cross_page_tb
+ movi a3, 28
+ assert eq, a2, a3
+ rsr a2, epc1
+- movi a3, 0x7ffd
++ movi a3, 0x7ffc
+ assert eq, a2, a3
+ rsr a2, excsave1
+- movi a3, 0x00007ffd
++ movi a3, 0x00007ffc
+ assert eq, a2, a3
+ test_end
+
+diff --git a/tests/test-qmp-input-strict.c b/tests/test-qmp-input-strict.c
+index 0f77003..d5360c6 100644
+--- a/tests/test-qmp-input-strict.c
++++ b/tests/test-qmp-input-strict.c
+@@ -260,6 +260,21 @@ static void test_validate_fail_union_flat(TestInputVisitorData *data,
+ qapi_free_UserDefFlatUnion(tmp);
+ }
+
++static void test_validate_fail_union_flat_no_discrim(TestInputVisitorData *data,
++ const void *unused)
++{
++ UserDefFlatUnion2 *tmp = NULL;
++ Error *err = NULL;
++ Visitor *v;
++
++ /* test situation where discriminator field ('enum1' here) is missing */
++ v = validate_test_init(data, "{ 'string': 'c', 'string1': 'd', 'string2': 'e' }");
++
++ visit_type_UserDefFlatUnion2(v, &tmp, NULL, &err);
++ g_assert(err);
++ qapi_free_UserDefFlatUnion2(tmp);
++}
++
+ static void test_validate_fail_union_anon(TestInputVisitorData *data,
+ const void *unused)
+ {
+@@ -310,6 +325,8 @@ int main(int argc, char **argv)
+ &testdata, test_validate_fail_union);
+ validate_test_add("/visitor/input-strict/fail/union-flat",
+ &testdata, test_validate_fail_union_flat);
++ validate_test_add("/visitor/input-strict/fail/union-flat-no-discriminator",
++ &testdata, test_validate_fail_union_flat_no_discrim);
+ validate_test_add("/visitor/input-strict/fail/union-anon",
+ &testdata, test_validate_fail_union_anon);
+
+diff --git a/thread-pool.c b/thread-pool.c
+index dfb699d..23888dc 100644
+--- a/thread-pool.c
++++ b/thread-pool.c
+@@ -21,7 +21,6 @@
+ #include "block/coroutine.h"
+ #include "trace.h"
+ #include "block/block_int.h"
+-#include "qemu/event_notifier.h"
+ #include "block/thread-pool.h"
+ #include "qemu/main-loop.h"
+
+@@ -57,8 +56,8 @@ struct ThreadPoolElement {
+ };
+
+ struct ThreadPool {
+- EventNotifier notifier;
+ AioContext *ctx;
++ QEMUBH *completion_bh;
+ QemuMutex lock;
+ QemuCond check_cancel;
+ QemuCond worker_stopped;
+@@ -119,7 +118,7 @@ static void *worker_thread(void *opaque)
+ qemu_cond_broadcast(&pool->check_cancel);
+ }
+
+- event_notifier_set(&pool->notifier);
++ qemu_bh_schedule(pool->completion_bh);
+ }
+
+ pool->cur_threads--;
+@@ -168,12 +167,11 @@ static void spawn_thread(ThreadPool *pool)
+ }
+ }
+
+-static void event_notifier_ready(EventNotifier *notifier)
++static void thread_pool_completion_bh(void *opaque)
+ {
+- ThreadPool *pool = container_of(notifier, ThreadPool, notifier);
++ ThreadPool *pool = opaque;
+ ThreadPoolElement *elem, *next;
+
+- event_notifier_test_and_clear(notifier);
+ restart:
+ QLIST_FOREACH_SAFE(elem, &pool->head, all, next) {
+ if (elem->state != THREAD_CANCELED && elem->state != THREAD_DONE) {
+@@ -187,6 +185,12 @@ restart:
+ QLIST_REMOVE(elem, all);
+ /* Read state before ret. */
+ smp_rmb();
++
++ /* Schedule ourselves in case elem->common.cb() calls aio_poll() to
++ * wait for another request that completed at the same time.
++ */
++ qemu_bh_schedule(pool->completion_bh);
++
+ elem->common.cb(elem->common.opaque, elem->ret);
+ qemu_aio_release(elem);
+ goto restart;
+@@ -215,7 +219,7 @@ static void thread_pool_cancel(BlockDriverAIOCB *acb)
+ qemu_sem_timedwait(&pool->sem, 0) == 0) {
+ QTAILQ_REMOVE(&pool->request_list, elem, reqs);
+ elem->state = THREAD_CANCELED;
+- event_notifier_set(&pool->notifier);
++ qemu_bh_schedule(pool->completion_bh);
+ } else {
+ pool->pending_cancellations++;
+ while (elem->state != THREAD_CANCELED && elem->state != THREAD_DONE) {
+@@ -224,7 +228,7 @@ static void thread_pool_cancel(BlockDriverAIOCB *acb)
+ pool->pending_cancellations--;
+ }
+ qemu_mutex_unlock(&pool->lock);
+- event_notifier_ready(&pool->notifier);
++ thread_pool_completion_bh(pool);
+ }
+
+ static const AIOCBInfo thread_pool_aiocb_info = {
+@@ -293,8 +297,8 @@ static void thread_pool_init_one(ThreadPool *pool, AioContext *ctx)
+ }
+
+ memset(pool, 0, sizeof(*pool));
+- event_notifier_init(&pool->notifier, false);
+ pool->ctx = ctx;
++ pool->completion_bh = aio_bh_new(ctx, thread_pool_completion_bh, pool);
+ qemu_mutex_init(&pool->lock);
+ qemu_cond_init(&pool->check_cancel);
+ qemu_cond_init(&pool->worker_stopped);
+@@ -304,8 +308,6 @@ static void thread_pool_init_one(ThreadPool *pool, AioContext *ctx)
+
+ QLIST_INIT(&pool->head);
+ QTAILQ_INIT(&pool->request_list);
+-
+- aio_set_event_notifier(ctx, &pool->notifier, event_notifier_ready);
+ }
+
+ ThreadPool *thread_pool_new(AioContext *ctx)
+@@ -339,11 +341,10 @@ void thread_pool_free(ThreadPool *pool)
+
+ qemu_mutex_unlock(&pool->lock);
+
+- aio_set_event_notifier(pool->ctx, &pool->notifier, NULL);
++ qemu_bh_delete(pool->completion_bh);
+ qemu_sem_destroy(&pool->sem);
+ qemu_cond_destroy(&pool->check_cancel);
+ qemu_cond_destroy(&pool->worker_stopped);
+ qemu_mutex_destroy(&pool->lock);
+- event_notifier_cleanup(&pool->notifier);
+ g_free(pool);
+ }
+diff --git a/ui/spice-display.c b/ui/spice-display.c
+index 66e2578..def7b52 100644
+--- a/ui/spice-display.c
++++ b/ui/spice-display.c
+@@ -334,11 +334,23 @@ void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd)
+ void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd)
+ {
+ QXLDevSurfaceCreate surface;
++ uint64_t surface_size;
+
+ memset(&surface, 0, sizeof(surface));
+
+- dprint(1, "%s/%d: %dx%d\n", __func__, ssd->qxl.id,
+- surface_width(ssd->ds), surface_height(ssd->ds));
++ surface_size = (uint64_t) surface_width(ssd->ds) *
++ surface_height(ssd->ds) * 4;
++ assert(surface_size > 0);
++ assert(surface_size < INT_MAX);
++ if (ssd->bufsize < surface_size) {
++ ssd->bufsize = surface_size;
++ g_free(ssd->buf);
++ ssd->buf = g_malloc(ssd->bufsize);
++ }
++
++ dprint(1, "%s/%d: %ux%u (size %" PRIu64 "/%d)\n", __func__, ssd->qxl.id,
++ surface_width(ssd->ds), surface_height(ssd->ds),
++ surface_size, ssd->bufsize);
+
+ surface.format = SPICE_SURFACE_FMT_32_xRGB;
+ surface.width = surface_width(ssd->ds);
+@@ -369,8 +381,6 @@ void qemu_spice_display_init_common(SimpleSpiceDisplay *ssd)
+ if (ssd->num_surfaces == 0) {
+ ssd->num_surfaces = 1024;
+ }
+- ssd->bufsize = (16 * 1024 * 1024);
+- ssd->buf = g_malloc(ssd->bufsize);
+ }
+
+ /* display listener callbacks */
+@@ -495,7 +505,7 @@ static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info)
+ info->num_memslots = NUM_MEMSLOTS;
+ info->num_memslots_groups = NUM_MEMSLOTS_GROUPS;
+ info->internal_groupslot_id = 0;
+- info->qxl_ram_size = ssd->bufsize;
++ info->qxl_ram_size = 16 * 1024 * 1024;
+ info->n_surfaces = ssd->num_surfaces;
+ }
+
+diff --git a/ui/vnc.c b/ui/vnc.c
+index f8d9b7d..87e34ae 100644
+--- a/ui/vnc.c
++++ b/ui/vnc.c
+@@ -2026,6 +2026,16 @@ static void set_pixel_format(VncState *vs,
+ return;
+ }
+
++ switch (bits_per_pixel) {
++ case 8:
++ case 16:
++ case 32:
++ break;
++ default:
++ vnc_client_error(vs);
++ return;
++ }
++
+ vs->client_pf.rmax = red_max;
+ vs->client_pf.rbits = hweight_long(red_max);
+ vs->client_pf.rshift = red_shift;
+diff --git a/vl.c b/vl.c
+index fe451aa..653ee2c 100644
+--- a/vl.c
++++ b/vl.c
+@@ -1745,9 +1745,7 @@ int qemu_reset_requested_get(void)
+
+ static int qemu_shutdown_requested(void)
+ {
+- int r = shutdown_requested;
+- shutdown_requested = 0;
+- return r;
++ return atomic_xchg(&shutdown_requested, 0);
+ }
+
+ static void qemu_kill_report(void)
+@@ -3054,9 +3052,6 @@ int main(int argc, char **argv, char **envp)
+ exit(1);
+ }
+ switch(popt->index) {
+- case QEMU_OPTION_M:
+- machine_class = machine_parse(optarg);
+- break;
+ case QEMU_OPTION_no_kvm_irqchip: {
+ olist = qemu_find_opts("machine");
+ qemu_opts_parse(olist, "kernel_irqchip=off", 0);
+@@ -3674,16 +3669,13 @@ int main(int argc, char **argv, char **envp)
+ olist = qemu_find_opts("machine");
+ qemu_opts_parse(olist, "accel=kvm", 0);
+ break;
++ case QEMU_OPTION_M:
+ case QEMU_OPTION_machine:
+ olist = qemu_find_opts("machine");
+ opts = qemu_opts_parse(olist, optarg, 1);
+ if (!opts) {
+ exit(1);
+ }
+- optarg = qemu_opt_get(opts, "type");
+- if (optarg) {
+- machine_class = machine_parse(optarg);
+- }
+ break;
+ case QEMU_OPTION_no_kvm:
+ olist = qemu_find_opts("machine");
+@@ -3966,6 +3958,13 @@ int main(int argc, char **argv, char **envp)
+ }
+ }
+ }
++
++ opts = qemu_get_machine_opts();
++ optarg = qemu_opt_get(opts, "type");
++ if (optarg) {
++ machine_class = machine_parse(optarg);
++ }
++
+ loc_set_none();
+
+ os_daemonize();
+@@ -4009,11 +4008,6 @@ int main(int argc, char **argv, char **envp)
+ qemu_set_version(machine_class->hw_version);
+ }
+
+- if (qemu_opts_foreach(qemu_find_opts("object"),
+- object_create, NULL, 0) != 0) {
+- exit(1);
+- }
+-
+ /* Init CPU def lists, based on config
+ * - Must be called after all the qemu_read_config_file() calls
+ * - Must be called before list_cpus()
+@@ -4225,6 +4219,11 @@ int main(int argc, char **argv, char **envp)
+ exit(0);
+ }
+
++ if (qemu_opts_foreach(qemu_find_opts("object"),
++ object_create, NULL, 0) != 0) {
++ exit(1);
++ }
++
+ machine_opts = qemu_get_machine_opts();
+ if (qemu_opt_foreach(machine_opts, object_set_property, current_machine,
+ 1) < 0) {
Reply to: