summaryrefslogtreecommitdiffstats
path: root/debian/patches/v7.2.3.diff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--debian/patches/v7.2.3.diff2258
1 files changed, 2258 insertions, 0 deletions
diff --git a/debian/patches/v7.2.3.diff b/debian/patches/v7.2.3.diff
new file mode 100644
index 00000000..d6d3da44
--- /dev/null
+++ b/debian/patches/v7.2.3.diff
@@ -0,0 +1,2258 @@
+diff --git a/VERSION b/VERSION
+index 77f5bec5b2..429dc57af3 100644
+--- a/VERSION
++++ b/VERSION
+@@ -1 +1 @@
+-7.2.2
++7.2.3
+diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c
+index 6f1c00682b..1160aec626 100644
+--- a/accel/tcg/cputlb.c
++++ b/accel/tcg/cputlb.c
+@@ -1817,7 +1817,7 @@ static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr,
+ } else /* if (prot & PAGE_READ) */ {
+ tlb_addr = tlbe->addr_read;
+ if (!tlb_hit(tlb_addr, addr)) {
+- if (!VICTIM_TLB_HIT(addr_write, addr)) {
++ if (!VICTIM_TLB_HIT(addr_read, addr)) {
+ tlb_fill(env_cpu(env), addr, size,
+ MMU_DATA_LOAD, mmu_idx, retaddr);
+ index = tlb_index(env, mmu_idx, addr);
+diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c
+index b6135e9bfe..cf21b5e40a 100644
+--- a/block/monitor/block-hmp-cmds.c
++++ b/block/monitor/block-hmp-cmds.c
+@@ -213,15 +213,17 @@ void hmp_commit(Monitor *mon, const QDict *qdict)
+ error_report("Device '%s' not found", device);
+ return;
+ }
+- if (!blk_is_available(blk)) {
+- error_report("Device '%s' has no medium", device);
+- return;
+- }
+
+ bs = bdrv_skip_implicit_filters(blk_bs(blk));
+ aio_context = bdrv_get_aio_context(bs);
+ aio_context_acquire(aio_context);
+
++ if (!blk_is_available(blk)) {
++ error_report("Device '%s' has no medium", device);
++ aio_context_release(aio_context);
++ return;
++ }
++
+ ret = bdrv_commit(bs);
+
+ aio_context_release(aio_context);
+diff --git a/blockdev.c b/blockdev.c
+index 3f1dec6242..ae27a41efa 100644
+--- a/blockdev.c
++++ b/blockdev.c
+@@ -152,12 +152,22 @@ void blockdev_mark_auto_del(BlockBackend *blk)
+
+ JOB_LOCK_GUARD();
+
+- for (job = block_job_next_locked(NULL); job;
+- job = block_job_next_locked(job)) {
+- if (block_job_has_bdrv(job, blk_bs(blk))) {
++ do {
++ job = block_job_next_locked(NULL);
++ while (job && (job->job.cancelled ||
++ job->job.deferred_to_main_loop ||
++ !block_job_has_bdrv(job, blk_bs(blk))))
++ {
++ job = block_job_next_locked(job);
++ }
++ if (job) {
++ /*
++ * This drops the job lock temporarily and polls, so we need to
++ * restart processing the list from the start after this.
++ */
+ job_cancel_locked(&job->job, false);
+ }
+- }
++ } while (job);
+
+ dinfo->auto_del = 1;
+ }
+diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst
+index 93affe3669..0b26c01da0 100644
+--- a/docs/about/deprecated.rst
++++ b/docs/about/deprecated.rst
+@@ -233,8 +233,8 @@ Use the more generic event ``DEVICE_UNPLUG_GUEST_ERROR`` instead.
+ System emulator machines
+ ------------------------
+
+-Arm ``virt`` machine ``dtb-kaslr-seed`` property
+-''''''''''''''''''''''''''''''''''''''''''''''''
++Arm ``virt`` machine ``dtb-kaslr-seed`` property (since 7.1)
++''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+
+ The ``dtb-kaslr-seed`` property on the ``virt`` board has been
+ deprecated; use the new name ``dtb-randomness`` instead. The new name
+diff --git a/fpu/softfloat.c b/fpu/softfloat.c
+index c7454c3eb1..108f9cb224 100644
+--- a/fpu/softfloat.c
++++ b/fpu/softfloat.c
+@@ -5135,7 +5135,7 @@ float32 float32_exp2(float32 a, float_status *status)
+ float64_unpack_canonical(&rp, float64_one, status);
+ for (i = 0 ; i < 15 ; i++) {
+ float64_unpack_canonical(&tp, float32_exp2_coefficients[i], status);
+- rp = *parts_muladd(&tp, &xp, &rp, 0, status);
++ rp = *parts_muladd(&tp, &xnp, &rp, 0, status);
+ xnp = *parts_mul(&xnp, &xp, status);
+ }
+
+diff --git a/hw/9pfs/trace-events b/hw/9pfs/trace-events
+index 6c77966c0b..a12e55c165 100644
+--- a/hw/9pfs/trace-events
++++ b/hw/9pfs/trace-events
+@@ -48,3 +48,9 @@ v9fs_readlink(uint16_t tag, uint8_t id, int32_t fid) "tag %d id %d fid %d"
+ v9fs_readlink_return(uint16_t tag, uint8_t id, char* target) "tag %d id %d name %s"
+ v9fs_setattr(uint16_t tag, uint8_t id, int32_t fid, int32_t valid, int32_t mode, int32_t uid, int32_t gid, int64_t size, int64_t atime_sec, int64_t mtime_sec) "tag %u id %u fid %d iattr={valid %d mode %d uid %d gid %d size %"PRId64" atime=%"PRId64" mtime=%"PRId64" }"
+ v9fs_setattr_return(uint16_t tag, uint8_t id) "tag %u id %u"
++
++# xen-9p-backend.c
++xen_9pfs_alloc(char *name) "name %s"
++xen_9pfs_connect(char *name) "name %s"
++xen_9pfs_disconnect(char *name) "name %s"
++xen_9pfs_free(char *name) "name %s"
+diff --git a/hw/9pfs/xen-9p-backend.c b/hw/9pfs/xen-9p-backend.c
+index 65c4979c3c..ab1df8dd2f 100644
+--- a/hw/9pfs/xen-9p-backend.c
++++ b/hw/9pfs/xen-9p-backend.c
+@@ -24,6 +24,8 @@
+ #include "qemu/option.h"
+ #include "fsdev/qemu-fsdev.h"
+
++#include "trace.h"
++
+ #define VERSIONS "1"
+ #define MAX_RINGS 8
+ #define MAX_RING_ORDER 9
+@@ -335,6 +337,8 @@ static void xen_9pfs_disconnect(struct XenLegacyDevice *xendev)
+ Xen9pfsDev *xen_9pdev = container_of(xendev, Xen9pfsDev, xendev);
+ int i;
+
++ trace_xen_9pfs_disconnect(xendev->name);
++
+ for (i = 0; i < xen_9pdev->num_rings; i++) {
+ if (xen_9pdev->rings[i].evtchndev != NULL) {
+ qemu_set_fd_handler(xenevtchn_fd(xen_9pdev->rings[i].evtchndev),
+@@ -343,39 +347,40 @@ static void xen_9pfs_disconnect(struct XenLegacyDevice *xendev)
+ xen_9pdev->rings[i].local_port);
+ xen_9pdev->rings[i].evtchndev = NULL;
+ }
+- }
+-}
+-
+-static int xen_9pfs_free(struct XenLegacyDevice *xendev)
+-{
+- Xen9pfsDev *xen_9pdev = container_of(xendev, Xen9pfsDev, xendev);
+- int i;
+-
+- if (xen_9pdev->rings[0].evtchndev != NULL) {
+- xen_9pfs_disconnect(xendev);
+- }
+-
+- for (i = 0; i < xen_9pdev->num_rings; i++) {
+ if (xen_9pdev->rings[i].data != NULL) {
+ xen_be_unmap_grant_refs(&xen_9pdev->xendev,
+ xen_9pdev->rings[i].data,
+ (1 << xen_9pdev->rings[i].ring_order));
++ xen_9pdev->rings[i].data = NULL;
+ }
+ if (xen_9pdev->rings[i].intf != NULL) {
+ xen_be_unmap_grant_refs(&xen_9pdev->xendev,
+ xen_9pdev->rings[i].intf,
+ 1);
++ xen_9pdev->rings[i].intf = NULL;
+ }
+ if (xen_9pdev->rings[i].bh != NULL) {
+ qemu_bh_delete(xen_9pdev->rings[i].bh);
++ xen_9pdev->rings[i].bh = NULL;
+ }
+ }
+
+ g_free(xen_9pdev->id);
++ xen_9pdev->id = NULL;
+ g_free(xen_9pdev->tag);
++ xen_9pdev->tag = NULL;
+ g_free(xen_9pdev->path);
++ xen_9pdev->path = NULL;
+ g_free(xen_9pdev->security_model);
++ xen_9pdev->security_model = NULL;
+ g_free(xen_9pdev->rings);
++ xen_9pdev->rings = NULL;
++}
++
++static int xen_9pfs_free(struct XenLegacyDevice *xendev)
++{
++ trace_xen_9pfs_free(xendev->name);
++
+ return 0;
+ }
+
+@@ -387,6 +392,8 @@ static int xen_9pfs_connect(struct XenLegacyDevice *xendev)
+ V9fsState *s = &xen_9pdev->state;
+ QemuOpts *fsdev;
+
++ trace_xen_9pfs_connect(xendev->name);
++
+ if (xenstore_read_fe_int(&xen_9pdev->xendev, "num-rings",
+ &xen_9pdev->num_rings) == -1 ||
+ xen_9pdev->num_rings > MAX_RINGS || xen_9pdev->num_rings < 1) {
+@@ -494,6 +501,8 @@ out:
+
+ static void xen_9pfs_alloc(struct XenLegacyDevice *xendev)
+ {
++ trace_xen_9pfs_alloc(xendev->name);
++
+ xenstore_write_be_str(xendev, "versions", VERSIONS);
+ xenstore_write_be_int(xendev, "max-rings", MAX_RINGS);
+ xenstore_write_be_int(xendev, "max-ring-page-order", MAX_RING_ORDER);
+diff --git a/hw/acpi/pcihp.c b/hw/acpi/pcihp.c
+index 84d75e6b84..a2a3738b46 100644
+--- a/hw/acpi/pcihp.c
++++ b/hw/acpi/pcihp.c
+@@ -429,6 +429,16 @@ void acpi_pcihp_device_unplug_request_cb(HotplugHandler *hotplug_dev,
+ * acpi_pcihp_eject_slot() when the operation is completed.
+ */
+ pdev->qdev.pending_deleted_event = true;
++ /* if unplug was requested before OSPM is initialized,
++ * linux kernel will clear GPE0.sts[] bits during boot, which effectively
++ * hides unplug event. And than followup qmp_device_del() calls remain
++ * blocked by above flag permanently.
++ * Unblock qmp_device_del() by setting expire limit, so user can
++ * repeat unplug request later when OSPM has been booted.
++ */
++ pdev->qdev.pending_deleted_expires_ms =
++ qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL); /* 1 msec */
++
+ s->acpi_pcihp_pci_status[bsel].down |= (1U << slot);
+ acpi_send_event(DEVICE(hotplug_dev), ACPI_PCI_HOTPLUG_STATUS);
+ }
+diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
+index 55f114ef72..97fb1916ec 100644
+--- a/hw/arm/aspeed.c
++++ b/hw/arm/aspeed.c
+@@ -188,33 +188,35 @@ struct AspeedMachineState {
+ static void aspeed_write_smpboot(ARMCPU *cpu,
+ const struct arm_boot_info *info)
+ {
+- static const uint32_t poll_mailbox_ready[] = {
++ AddressSpace *as = arm_boot_address_space(cpu, info);
++ static const ARMInsnFixup poll_mailbox_ready[] = {
+ /*
+ * r2 = per-cpu go sign value
+ * r1 = AST_SMP_MBOX_FIELD_ENTRY
+ * r0 = AST_SMP_MBOX_FIELD_GOSIGN
+ */
+- 0xee100fb0, /* mrc p15, 0, r0, c0, c0, 5 */
+- 0xe21000ff, /* ands r0, r0, #255 */
+- 0xe59f201c, /* ldr r2, [pc, #28] */
+- 0xe1822000, /* orr r2, r2, r0 */
+-
+- 0xe59f1018, /* ldr r1, [pc, #24] */
+- 0xe59f0018, /* ldr r0, [pc, #24] */
+-
+- 0xe320f002, /* wfe */
+- 0xe5904000, /* ldr r4, [r0] */
+- 0xe1520004, /* cmp r2, r4 */
+- 0x1afffffb, /* bne <wfe> */
+- 0xe591f000, /* ldr pc, [r1] */
+- AST_SMP_MBOX_GOSIGN,
+- AST_SMP_MBOX_FIELD_ENTRY,
+- AST_SMP_MBOX_FIELD_GOSIGN,
++ { 0xee100fb0 }, /* mrc p15, 0, r0, c0, c0, 5 */
++ { 0xe21000ff }, /* ands r0, r0, #255 */
++ { 0xe59f201c }, /* ldr r2, [pc, #28] */
++ { 0xe1822000 }, /* orr r2, r2, r0 */
++
++ { 0xe59f1018 }, /* ldr r1, [pc, #24] */
++ { 0xe59f0018 }, /* ldr r0, [pc, #24] */
++
++ { 0xe320f002 }, /* wfe */
++ { 0xe5904000 }, /* ldr r4, [r0] */
++ { 0xe1520004 }, /* cmp r2, r4 */
++ { 0x1afffffb }, /* bne <wfe> */
++ { 0xe591f000 }, /* ldr pc, [r1] */
++ { AST_SMP_MBOX_GOSIGN },
++ { AST_SMP_MBOX_FIELD_ENTRY },
++ { AST_SMP_MBOX_FIELD_GOSIGN },
++ { 0, FIXUP_TERMINATOR }
+ };
++ static const uint32_t fixupcontext[FIXUP_MAX] = { 0 };
+
+- rom_add_blob_fixed("aspeed.smpboot", poll_mailbox_ready,
+- sizeof(poll_mailbox_ready),
+- info->smp_loader_start);
++ arm_write_bootloader("aspeed.smpboot", as, info->smp_loader_start,
++ poll_mailbox_ready, fixupcontext);
+ }
+
+ static void aspeed_reset_secondary(ARMCPU *cpu,
+diff --git a/hw/arm/boot.c b/hw/arm/boot.c
+index 725bab8adc..8ff315f431 100644
+--- a/hw/arm/boot.c
++++ b/hw/arm/boot.c
+@@ -59,26 +59,6 @@ AddressSpace *arm_boot_address_space(ARMCPU *cpu,
+ return cpu_get_address_space(cs, asidx);
+ }
+
+-typedef enum {
+- FIXUP_NONE = 0, /* do nothing */
+- FIXUP_TERMINATOR, /* end of insns */
+- FIXUP_BOARDID, /* overwrite with board ID number */
+- FIXUP_BOARD_SETUP, /* overwrite with board specific setup code address */
+- FIXUP_ARGPTR_LO, /* overwrite with pointer to kernel args */
+- FIXUP_ARGPTR_HI, /* overwrite with pointer to kernel args (high half) */
+- FIXUP_ENTRYPOINT_LO, /* overwrite with kernel entry point */
+- FIXUP_ENTRYPOINT_HI, /* overwrite with kernel entry point (high half) */
+- FIXUP_GIC_CPU_IF, /* overwrite with GIC CPU interface address */
+- FIXUP_BOOTREG, /* overwrite with boot register address */
+- FIXUP_DSB, /* overwrite with correct DSB insn for cpu */
+- FIXUP_MAX,
+-} FixupType;
+-
+-typedef struct ARMInsnFixup {
+- uint32_t insn;
+- FixupType fixup;
+-} ARMInsnFixup;
+-
+ static const ARMInsnFixup bootloader_aarch64[] = {
+ { 0x580000c0 }, /* ldr x0, arg ; Load the lower 32-bits of DTB */
+ { 0xaa1f03e1 }, /* mov x1, xzr */
+@@ -149,9 +129,10 @@ static const ARMInsnFixup smpboot[] = {
+ { 0, FIXUP_TERMINATOR }
+ };
+
+-static void write_bootloader(const char *name, hwaddr addr,
+- const ARMInsnFixup *insns, uint32_t *fixupcontext,
+- AddressSpace *as)
++void arm_write_bootloader(const char *name,
++ AddressSpace *as, hwaddr addr,
++ const ARMInsnFixup *insns,
++ const uint32_t *fixupcontext)
+ {
+ /* Fix up the specified bootloader fragment and write it into
+ * guest memory using rom_add_blob_fixed(). fixupcontext is
+@@ -213,8 +194,8 @@ static void default_write_secondary(ARMCPU *cpu,
+ fixupcontext[FIXUP_DSB] = CP15_DSB_INSN;
+ }
+
+- write_bootloader("smpboot", info->smp_loader_start,
+- smpboot, fixupcontext, as);
++ arm_write_bootloader("smpboot", as, info->smp_loader_start,
++ smpboot, fixupcontext);
+ }
+
+ void arm_write_secure_board_setup_dummy_smc(ARMCPU *cpu,
+@@ -1174,8 +1155,8 @@ static void arm_setup_direct_kernel_boot(ARMCPU *cpu,
+ fixupcontext[FIXUP_ENTRYPOINT_LO] = entry;
+ fixupcontext[FIXUP_ENTRYPOINT_HI] = entry >> 32;
+
+- write_bootloader("bootloader", info->loader_start,
+- primary_loader, fixupcontext, as);
++ arm_write_bootloader("bootloader", as, info->loader_start,
++ primary_loader, fixupcontext);
+
+ if (info->write_board_setup) {
+ info->write_board_setup(cpu, info);
+diff --git a/hw/arm/raspi.c b/hw/arm/raspi.c
+index 92d068d1f9..a7d287b1a8 100644
+--- a/hw/arm/raspi.c
++++ b/hw/arm/raspi.c
+@@ -16,6 +16,7 @@
+ #include "qemu/units.h"
+ #include "qemu/cutils.h"
+ #include "qapi/error.h"
++#include "hw/arm/boot.h"
+ #include "hw/arm/bcm2836.h"
+ #include "hw/registerfields.h"
+ #include "qemu/error-report.h"
+@@ -124,20 +125,22 @@ static const char *board_type(uint32_t board_rev)
+
+ static void write_smpboot(ARMCPU *cpu, const struct arm_boot_info *info)
+ {
+- static const uint32_t smpboot[] = {
+- 0xe1a0e00f, /* mov lr, pc */
+- 0xe3a0fe00 + (BOARDSETUP_ADDR >> 4), /* mov pc, BOARDSETUP_ADDR */
+- 0xee100fb0, /* mrc p15, 0, r0, c0, c0, 5;get core ID */
+- 0xe7e10050, /* ubfx r0, r0, #0, #2 ;extract LSB */
+- 0xe59f5014, /* ldr r5, =0x400000CC ;load mbox base */
+- 0xe320f001, /* 1: yield */
+- 0xe7953200, /* ldr r3, [r5, r0, lsl #4] ;read mbox for our core*/
+- 0xe3530000, /* cmp r3, #0 ;spin while zero */
+- 0x0afffffb, /* beq 1b */
+- 0xe7853200, /* str r3, [r5, r0, lsl #4] ;clear mbox */
+- 0xe12fff13, /* bx r3 ;jump to target */
+- 0x400000cc, /* (constant: mailbox 3 read/clear base) */
++ static const ARMInsnFixup smpboot[] = {
++ { 0xe1a0e00f }, /* mov lr, pc */
++ { 0xe3a0fe00 + (BOARDSETUP_ADDR >> 4) }, /* mov pc, BOARDSETUP_ADDR */
++ { 0xee100fb0 }, /* mrc p15, 0, r0, c0, c0, 5;get core ID */
++ { 0xe7e10050 }, /* ubfx r0, r0, #0, #2 ;extract LSB */
++ { 0xe59f5014 }, /* ldr r5, =0x400000CC ;load mbox base */
++ { 0xe320f001 }, /* 1: yield */
++ { 0xe7953200 }, /* ldr r3, [r5, r0, lsl #4] ;read mbox for our core */
++ { 0xe3530000 }, /* cmp r3, #0 ;spin while zero */
++ { 0x0afffffb }, /* beq 1b */
++ { 0xe7853200 }, /* str r3, [r5, r0, lsl #4] ;clear mbox */
++ { 0xe12fff13 }, /* bx r3 ;jump to target */
++ { 0x400000cc }, /* (constant: mailbox 3 read/clear base) */
++ { 0, FIXUP_TERMINATOR }
+ };
++ static const uint32_t fixupcontext[FIXUP_MAX] = { 0 };
+
+ /* check that we don't overrun board setup vectors */
+ QEMU_BUILD_BUG_ON(SMPBOOT_ADDR + sizeof(smpboot) > MVBAR_ADDR);
+@@ -145,9 +148,8 @@ static void write_smpboot(ARMCPU *cpu, const struct arm_boot_info *info)
+ QEMU_BUILD_BUG_ON((BOARDSETUP_ADDR & 0xf) != 0
+ || (BOARDSETUP_ADDR >> 4) >= 0x100);
+
+- rom_add_blob_fixed_as("raspi_smpboot", smpboot, sizeof(smpboot),
+- info->smp_loader_start,
+- arm_boot_address_space(cpu, info));
++ arm_write_bootloader("raspi_smpboot", arm_boot_address_space(cpu, info),
++ info->smp_loader_start, smpboot, fixupcontext);
+ }
+
+ static void write_smpboot64(ARMCPU *cpu, const struct arm_boot_info *info)
+@@ -161,26 +163,28 @@ static void write_smpboot64(ARMCPU *cpu, const struct arm_boot_info *info)
+ * the primary CPU goes into the kernel. We put these variables inside
+ * a rom blob, so that the reset for ROM contents zeroes them for us.
+ */
+- static const uint32_t smpboot[] = {
+- 0xd2801b05, /* mov x5, 0xd8 */
+- 0xd53800a6, /* mrs x6, mpidr_el1 */
+- 0x924004c6, /* and x6, x6, #0x3 */
+- 0xd503205f, /* spin: wfe */
+- 0xf86678a4, /* ldr x4, [x5,x6,lsl #3] */
+- 0xb4ffffc4, /* cbz x4, spin */
+- 0xd2800000, /* mov x0, #0x0 */
+- 0xd2800001, /* mov x1, #0x0 */
+- 0xd2800002, /* mov x2, #0x0 */
+- 0xd2800003, /* mov x3, #0x0 */
+- 0xd61f0080, /* br x4 */
++ static const ARMInsnFixup smpboot[] = {
++ { 0xd2801b05 }, /* mov x5, 0xd8 */
++ { 0xd53800a6 }, /* mrs x6, mpidr_el1 */
++ { 0x924004c6 }, /* and x6, x6, #0x3 */
++ { 0xd503205f }, /* spin: wfe */
++ { 0xf86678a4 }, /* ldr x4, [x5,x6,lsl #3] */
++ { 0xb4ffffc4 }, /* cbz x4, spin */
++ { 0xd2800000 }, /* mov x0, #0x0 */
++ { 0xd2800001 }, /* mov x1, #0x0 */
++ { 0xd2800002 }, /* mov x2, #0x0 */
++ { 0xd2800003 }, /* mov x3, #0x0 */
++ { 0xd61f0080 }, /* br x4 */
++ { 0, FIXUP_TERMINATOR }
+ };
++ static const uint32_t fixupcontext[FIXUP_MAX] = { 0 };
+
+ static const uint64_t spintables[] = {
+ 0, 0, 0, 0
+ };
+
+- rom_add_blob_fixed_as("raspi_smpboot", smpboot, sizeof(smpboot),
+- info->smp_loader_start, as);
++ arm_write_bootloader("raspi_smpboot", as, info->smp_loader_start,
++ smpboot, fixupcontext);
+ rom_add_blob_fixed_as("raspi_spintables", spintables, sizeof(spintables),
+ SPINTABLE_ADDR, as);
+ }
+diff --git a/hw/core/machine.c b/hw/core/machine.c
+index 035d078a74..19f42450f5 100644
+--- a/hw/core/machine.c
++++ b/hw/core/machine.c
+@@ -1329,6 +1329,14 @@ void machine_run_board_init(MachineState *machine, const char *mem_path, Error *
+ }
+ } else if (machine_class->default_ram_id && machine->ram_size &&
+ numa_uses_legacy_mem()) {
++ if (object_property_find(object_get_objects_root(),
++ machine_class->default_ram_id)) {
++ error_setg(errp, "object name '%s' is reserved for the default"
++ " RAM backend, it can't be used for any other purposes."
++ " Change the object's 'id' to something else",
++ machine_class->default_ram_id);
++ return;
++ }
+ if (!create_default_memdev(current_machine, mem_path, errp)) {
+ return;
+ }
+diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
+index 24616bf924..04f793cca1 100644
+--- a/hw/i386/pc_piix.c
++++ b/hw/i386/pc_piix.c
+@@ -405,6 +405,7 @@ static void pc_xen_hvm_init(MachineState *machine)
+ }
+
+ pc_xen_hvm_init_pci(machine);
++ xen_igd_reserve_slot(pcms->bus);
+ pci_create_simple(pcms->bus, -1, "xen-platform");
+ }
+ #endif
+diff --git a/hw/intc/allwinner-a10-pic.c b/hw/intc/allwinner-a10-pic.c
+index 8cca124807..4875e68ba6 100644
+--- a/hw/intc/allwinner-a10-pic.c
++++ b/hw/intc/allwinner-a10-pic.c
+@@ -49,12 +49,9 @@ static void aw_a10_pic_update(AwA10PICState *s)
+ static void aw_a10_pic_set_irq(void *opaque, int irq, int level)
+ {
+ AwA10PICState *s = opaque;
++ uint32_t *pending_reg = &s->irq_pending[irq / 32];
+
+- if (level) {
+- set_bit(irq % 32, (void *)&s->irq_pending[irq / 32]);
+- } else {
+- clear_bit(irq % 32, (void *)&s->irq_pending[irq / 32]);
+- }
++ *pending_reg = deposit32(*pending_reg, irq % 32, 1, level);
+ aw_a10_pic_update(s);
+ }
+
+diff --git a/hw/net/allwinner-sun8i-emac.c b/hw/net/allwinner-sun8i-emac.c
+index ecc0245fe8..c3fed5fcbe 100644
+--- a/hw/net/allwinner-sun8i-emac.c
++++ b/hw/net/allwinner-sun8i-emac.c
+@@ -350,8 +350,13 @@ static void allwinner_sun8i_emac_get_desc(AwSun8iEmacState *s,
+ FrameDescriptor *desc,
+ uint32_t phys_addr)
+ {
+- dma_memory_read(&s->dma_as, phys_addr, desc, sizeof(*desc),
++ uint32_t desc_words[4];
++ dma_memory_read(&s->dma_as, phys_addr, &desc_words, sizeof(desc_words),
+ MEMTXATTRS_UNSPECIFIED);
++ desc->status = le32_to_cpu(desc_words[0]);
++ desc->status2 = le32_to_cpu(desc_words[1]);
++ desc->addr = le32_to_cpu(desc_words[2]);
++ desc->next = le32_to_cpu(desc_words[3]);
+ }
+
+ static uint32_t allwinner_sun8i_emac_next_desc(AwSun8iEmacState *s,
+@@ -400,10 +405,15 @@ static uint32_t allwinner_sun8i_emac_tx_desc(AwSun8iEmacState *s,
+ }
+
+ static void allwinner_sun8i_emac_flush_desc(AwSun8iEmacState *s,
+- FrameDescriptor *desc,
++ const FrameDescriptor *desc,
+ uint32_t phys_addr)
+ {
+- dma_memory_write(&s->dma_as, phys_addr, desc, sizeof(*desc),
++ uint32_t desc_words[4];
++ desc_words[0] = cpu_to_le32(desc->status);
++ desc_words[1] = cpu_to_le32(desc->status2);
++ desc_words[2] = cpu_to_le32(desc->addr);
++ desc_words[3] = cpu_to_le32(desc->next);
++ dma_memory_write(&s->dma_as, phys_addr, &desc_words, sizeof(desc_words),
+ MEMTXATTRS_UNSPECIFIED);
+ }
+
+@@ -638,8 +648,7 @@ static uint64_t allwinner_sun8i_emac_read(void *opaque, hwaddr offset,
+ break;
+ case REG_TX_CUR_BUF: /* Transmit Current Buffer */
+ if (s->tx_desc_curr != 0) {
+- dma_memory_read(&s->dma_as, s->tx_desc_curr, &desc, sizeof(desc),
+- MEMTXATTRS_UNSPECIFIED);
++ allwinner_sun8i_emac_get_desc(s, &desc, s->tx_desc_curr);
+ value = desc.addr;
+ } else {
+ value = 0;
+@@ -652,8 +661,7 @@ static uint64_t allwinner_sun8i_emac_read(void *opaque, hwaddr offset,
+ break;
+ case REG_RX_CUR_BUF: /* Receive Current Buffer */
+ if (s->rx_desc_curr != 0) {
+- dma_memory_read(&s->dma_as, s->rx_desc_curr, &desc, sizeof(desc),
+- MEMTXATTRS_UNSPECIFIED);
++ allwinner_sun8i_emac_get_desc(s, &desc, s->rx_desc_curr);
+ value = desc.addr;
+ } else {
+ value = 0;
+diff --git a/hw/net/e1000.c b/hw/net/e1000.c
+index e26e0a64c1..0dfdf47313 100644
+--- a/hw/net/e1000.c
++++ b/hw/net/e1000.c
+@@ -567,7 +567,7 @@ e1000_send_packet(E1000State *s, const uint8_t *buf, int size)
+ qemu_send_packet(nc, buf, size);
+ }
+ inc_tx_bcast_or_mcast_count(s, buf);
+- e1000x_increase_size_stats(s->mac_reg, PTCregs, size);
++ e1000x_increase_size_stats(s->mac_reg, PTCregs, size + 4);
+ }
+
+ static void
+@@ -631,10 +631,9 @@ xmit_seg(E1000State *s)
+ }
+
+ e1000x_inc_reg_if_not_full(s->mac_reg, TPT);
+- e1000x_grow_8reg_if_not_full(s->mac_reg, TOTL, s->tx.size);
+- s->mac_reg[GPTC] = s->mac_reg[TPT];
+- s->mac_reg[GOTCL] = s->mac_reg[TOTL];
+- s->mac_reg[GOTCH] = s->mac_reg[TOTH];
++ e1000x_grow_8reg_if_not_full(s->mac_reg, TOTL, s->tx.size + 4);
++ e1000x_inc_reg_if_not_full(s->mac_reg, GPTC);
++ e1000x_grow_8reg_if_not_full(s->mac_reg, GOTCL, s->tx.size + 4);
+ }
+
+ static void
+diff --git a/hw/net/e1000e_core.c b/hw/net/e1000e_core.c
+index fc9cdb4528..c71d82ce1d 100644
+--- a/hw/net/e1000e_core.c
++++ b/hw/net/e1000e_core.c
+@@ -687,9 +687,8 @@ e1000e_on_tx_done_update_stats(E1000ECore *core, struct NetTxPkt *tx_pkt)
+ g_assert_not_reached();
+ }
+
+- core->mac[GPTC] = core->mac[TPT];
+- core->mac[GOTCL] = core->mac[TOTL];
+- core->mac[GOTCH] = core->mac[TOTH];
++ e1000x_inc_reg_if_not_full(core->mac, GPTC);
++ e1000x_grow_8reg_if_not_full(core->mac, GOTCL, tot_len);
+ }
+
+ static void
+diff --git a/hw/net/e1000x_common.c b/hw/net/e1000x_common.c
+index a8d93870b5..3fdc34f753 100644
+--- a/hw/net/e1000x_common.c
++++ b/hw/net/e1000x_common.c
+@@ -217,15 +217,14 @@ e1000x_update_rx_total_stats(uint32_t *mac,
+
+ e1000x_increase_size_stats(mac, PRCregs, data_fcs_size);
+ e1000x_inc_reg_if_not_full(mac, TPR);
+- mac[GPRC] = mac[TPR];
++ e1000x_inc_reg_if_not_full(mac, GPRC);
+ /* TOR - Total Octets Received:
+ * This register includes bytes received in a packet from the <Destination
+ * Address> field through the <CRC> field, inclusively.
+ * Always include FCS length (4) in size.
+ */
+ e1000x_grow_8reg_if_not_full(mac, TORL, data_size + 4);
+- mac[GORCL] = mac[TORL];
+- mac[GORCH] = mac[TORH];
++ e1000x_grow_8reg_if_not_full(mac, GORCL, data_size + 4);
+ }
+
+ void
+diff --git a/hw/net/msf2-emac.c b/hw/net/msf2-emac.c
+index 7ccd3e5142..db3a04deb1 100644
+--- a/hw/net/msf2-emac.c
++++ b/hw/net/msf2-emac.c
+@@ -118,14 +118,18 @@ static void emac_load_desc(MSF2EmacState *s, EmacDesc *d, hwaddr desc)
+ d->next = le32_to_cpu(d->next);
+ }
+
+-static void emac_store_desc(MSF2EmacState *s, EmacDesc *d, hwaddr desc)
++static void emac_store_desc(MSF2EmacState *s, const EmacDesc *d, hwaddr desc)
+ {
+- /* Convert from host endianness into LE. */
+- d->pktaddr = cpu_to_le32(d->pktaddr);
+- d->pktsize = cpu_to_le32(d->pktsize);
+- d->next = cpu_to_le32(d->next);
+-
+- address_space_write(&s->dma_as, desc, MEMTXATTRS_UNSPECIFIED, d, sizeof *d);
++ EmacDesc outd;
++ /*
++ * Convert from host endianness into LE. We use a local struct because
++ * calling code may still want to look at the fields afterwards.
++ */
++ outd.pktaddr = cpu_to_le32(d->pktaddr);
++ outd.pktsize = cpu_to_le32(d->pktsize);
++ outd.next = cpu_to_le32(d->next);
++
++ address_space_write(&s->dma_as, desc, MEMTXATTRS_UNSPECIFIED, &outd, sizeof outd);
+ }
+
+ static void msf2_dma_tx(MSF2EmacState *s)
+diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c
+index 700b1b66b6..eb679d7c40 100644
+--- a/hw/net/rtl8139.c
++++ b/hw/net/rtl8139.c
+@@ -2154,6 +2154,9 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
+
+ int large_send_mss = (txdw0 >> CP_TC_LGSEN_MSS_SHIFT) &
+ CP_TC_LGSEN_MSS_MASK;
++ if (large_send_mss == 0) {
++ goto skip_offload;
++ }
+
+ DPRINTF("+++ C+ mode offloaded task TSO IP data %d "
+ "frame data %d specified MSS=%d\n",
+diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
+index aba12759d5..4abd49e298 100644
+--- a/hw/net/virtio-net.c
++++ b/hw/net/virtio-net.c
+@@ -802,7 +802,6 @@ static uint64_t virtio_net_get_features(VirtIODevice *vdev, uint64_t features,
+ }
+
+ if (!get_vhost_net(nc->peer)) {
+- virtio_add_feature(&features, VIRTIO_F_RING_RESET);
+ return features;
+ }
+
+diff --git a/hw/scsi/lsi53c895a.c b/hw/scsi/lsi53c895a.c
+index 50979640c3..42532c4744 100644
+--- a/hw/scsi/lsi53c895a.c
++++ b/hw/scsi/lsi53c895a.c
+@@ -1134,15 +1134,24 @@ static void lsi_execute_script(LSIState *s)
+ uint32_t addr, addr_high;
+ int opcode;
+ int insn_processed = 0;
++ static int reentrancy_level;
++
++ reentrancy_level++;
+
+ s->istat1 |= LSI_ISTAT1_SRUN;
+ again:
+- if (++insn_processed > LSI_MAX_INSN) {
+- /* Some windows drivers make the device spin waiting for a memory
+- location to change. If we have been executed a lot of code then
+- assume this is the case and force an unexpected device disconnect.
+- This is apparently sufficient to beat the drivers into submission.
+- */
++ /*
++ * Some windows drivers make the device spin waiting for a memory location
++ * to change. If we have executed more than LSI_MAX_INSN instructions then
++ * assume this is the case and force an unexpected device disconnect. This
++ * is apparently sufficient to beat the drivers into submission.
++ *
++ * Another issue (CVE-2023-0330) can occur if the script is programmed to
++ * trigger itself again and again. Avoid this problem by stopping after
++ * being called multiple times in a reentrant way (8 is an arbitrary value
++ * which should be enough for all valid use cases).
++ */
++ if (++insn_processed > LSI_MAX_INSN || reentrancy_level > 8) {
+ if (!(s->sien0 & LSI_SIST0_UDC)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "lsi_scsi: inf. loop with UDC masked");
+@@ -1596,6 +1605,8 @@ again:
+ }
+ }
+ trace_lsi_execute_script_stop();
++
++ reentrancy_level--;
+ }
+
+ static uint8_t lsi_reg_readb(LSIState *s, int offset)
+diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c
+index 92cce20a4d..d513870181 100644
+--- a/hw/scsi/scsi-generic.c
++++ b/hw/scsi/scsi-generic.c
+@@ -190,12 +190,16 @@ static int scsi_handle_inquiry_reply(SCSIGenericReq *r, SCSIDevice *s, int len)
+ if ((s->type == TYPE_DISK || s->type == TYPE_ZBC) &&
+ (r->req.cmd.buf[1] & 0x01)) {
+ page = r->req.cmd.buf[2];
+- if (page == 0xb0) {
++ if (page == 0xb0 && r->buflen >= 8) {
++ uint8_t buf[16] = {};
++ uint8_t buf_used = MIN(r->buflen, 16);
+ uint64_t max_transfer = calculate_max_transfer(s);
+- stl_be_p(&r->buf[8], max_transfer);
+- /* Also take care of the opt xfer len. */
+- stl_be_p(&r->buf[12],
+- MIN_NON_ZERO(max_transfer, ldl_be_p(&r->buf[12])));
++
++ memcpy(buf, r->buf, buf_used);
++ stl_be_p(&buf[8], max_transfer);
++ stl_be_p(&buf[12], MIN_NON_ZERO(max_transfer, ldl_be_p(&buf[12])));
++ memcpy(r->buf + 8, buf + 8, buf_used - 8);
++
+ } else if (s->needs_vpd_bl_emulation && page == 0x00 && r->buflen >= 4) {
+ /*
+ * Now we're capable of supplying the VPD Block Limits
+diff --git a/hw/sd/allwinner-sdhost.c b/hw/sd/allwinner-sdhost.c
+index 51e5e90830..92a0f42708 100644
+--- a/hw/sd/allwinner-sdhost.c
++++ b/hw/sd/allwinner-sdhost.c
+@@ -302,6 +302,30 @@ static void allwinner_sdhost_auto_stop(AwSdHostState *s)
+ }
+ }
+
++static void read_descriptor(AwSdHostState *s, hwaddr desc_addr,
++ TransferDescriptor *desc)
++{
++ uint32_t desc_words[4];
++ dma_memory_read(&s->dma_as, desc_addr, &desc_words, sizeof(desc_words),
++ MEMTXATTRS_UNSPECIFIED);
++ desc->status = le32_to_cpu(desc_words[0]);
++ desc->size = le32_to_cpu(desc_words[1]);
++ desc->addr = le32_to_cpu(desc_words[2]);
++ desc->next = le32_to_cpu(desc_words[3]);
++}
++
++static void write_descriptor(AwSdHostState *s, hwaddr desc_addr,
++ const TransferDescriptor *desc)
++{
++ uint32_t desc_words[4];
++ desc_words[0] = cpu_to_le32(desc->status);
++ desc_words[1] = cpu_to_le32(desc->size);
++ desc_words[2] = cpu_to_le32(desc->addr);
++ desc_words[3] = cpu_to_le32(desc->next);
++ dma_memory_write(&s->dma_as, desc_addr, &desc_words, sizeof(desc_words),
++ MEMTXATTRS_UNSPECIFIED);
++}
++
+ static uint32_t allwinner_sdhost_process_desc(AwSdHostState *s,
+ hwaddr desc_addr,
+ TransferDescriptor *desc,
+@@ -312,9 +336,7 @@ static uint32_t allwinner_sdhost_process_desc(AwSdHostState *s,
+ uint32_t num_bytes = max_bytes;
+ uint8_t buf[1024];
+
+- /* Read descriptor */
+- dma_memory_read(&s->dma_as, desc_addr, desc, sizeof(*desc),
+- MEMTXATTRS_UNSPECIFIED);
++ read_descriptor(s, desc_addr, desc);
+ if (desc->size == 0) {
+ desc->size = klass->max_desc_size;
+ } else if (desc->size > klass->max_desc_size) {
+@@ -356,8 +378,7 @@ static uint32_t allwinner_sdhost_process_desc(AwSdHostState *s,
+
+ /* Clear hold flag and flush descriptor */
+ desc->status &= ~DESC_STATUS_HOLD;
+- dma_memory_write(&s->dma_as, desc_addr, desc, sizeof(*desc),
+- MEMTXATTRS_UNSPECIFIED);
++ write_descriptor(s, desc_addr, desc);
+
+ return num_done;
+ }
+diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c
+index 9d68036d23..c3ab762f54 100644
+--- a/hw/usb/hcd-ohci.c
++++ b/hw/usb/hcd-ohci.c
+@@ -1210,6 +1210,8 @@ static void ohci_frame_boundary(void *opaque)
+ /* Increment frame number and take care of endianness. */
+ ohci->frame_number = (ohci->frame_number + 1) & 0xffff;
+ hcca.frame = cpu_to_le16(ohci->frame_number);
++ /* When the HC updates frame number, set pad to 0. Ref OHCI Spec 4.4.1*/
++ hcca.pad = 0;
+
+ if (ohci->done_count == 0 && !(ohci->intr_status & OHCI_INTR_WD)) {
+ if (!ohci->done)
+diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c
+index a723073747..d422418f2d 100644
+--- a/hw/virtio/vhost-shadow-virtqueue.c
++++ b/hw/virtio/vhost-shadow-virtqueue.c
+@@ -68,7 +68,7 @@ bool vhost_svq_valid_features(uint64_t features, Error **errp)
+ */
+ static uint16_t vhost_svq_available_slots(const VhostShadowVirtqueue *svq)
+ {
+- return svq->vring.num - (svq->shadow_avail_idx - svq->shadow_used_idx);
++ return svq->num_free;
+ }
+
+ /**
+@@ -263,6 +263,7 @@ int vhost_svq_add(VhostShadowVirtqueue *svq, const struct iovec *out_sg,
+ return -EINVAL;
+ }
+
++ svq->num_free -= ndescs;
+ svq->desc_state[qemu_head].elem = elem;
+ svq->desc_state[qemu_head].ndescs = ndescs;
+ vhost_svq_kick(svq);
+@@ -449,6 +450,7 @@ static VirtQueueElement *vhost_svq_get_buf(VhostShadowVirtqueue *svq,
+ last_used_chain = vhost_svq_last_desc_of_chain(svq, num, used_elem.id);
+ svq->desc_next[last_used_chain] = svq->free_head;
+ svq->free_head = used_elem.id;
++ svq->num_free += num;
+
+ *len = used_elem.len;
+ return g_steal_pointer(&svq->desc_state[used_elem.id].elem);
+@@ -656,6 +658,7 @@ void vhost_svq_start(VhostShadowVirtqueue *svq, VirtIODevice *vdev,
+ svq->vq = vq;
+
+ svq->vring.num = virtio_queue_get_num(vdev, virtio_get_queue_index(vq));
++ svq->num_free = svq->vring.num;
+ driver_size = vhost_svq_driver_area_size(svq);
+ device_size = vhost_svq_device_area_size(svq);
+ svq->vring.desc = qemu_memalign(qemu_real_host_page_size(), driver_size);
+diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h
+index d04c34a589..328a7fc075 100644
+--- a/hw/virtio/vhost-shadow-virtqueue.h
++++ b/hw/virtio/vhost-shadow-virtqueue.h
+@@ -107,6 +107,9 @@ typedef struct VhostShadowVirtqueue {
+
+ /* Next head to consume from the device */
+ uint16_t last_used_idx;
++
++ /* Size of SVQ vring free descriptors */
++ uint16_t num_free;
+ } VhostShadowVirtqueue;
+
+ bool vhost_svq_valid_features(uint64_t features, Error **errp);
+diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
+index 8f635844af..d92b026e1c 100644
+--- a/hw/virtio/vhost-user.c
++++ b/hw/virtio/vhost-user.c
+@@ -305,19 +305,8 @@ static int vhost_user_read_header(struct vhost_dev *dev, VhostUserMsg *msg)
+ return 0;
+ }
+
+-struct vhost_user_read_cb_data {
+- struct vhost_dev *dev;
+- VhostUserMsg *msg;
+- GMainLoop *loop;
+- int ret;
+-};
+-
+-static gboolean vhost_user_read_cb(void *do_not_use, GIOCondition condition,
+- gpointer opaque)
++static int vhost_user_read(struct vhost_dev *dev, VhostUserMsg *msg)
+ {
+- struct vhost_user_read_cb_data *data = opaque;
+- struct vhost_dev *dev = data->dev;
+- VhostUserMsg *msg = data->msg;
+ struct vhost_user *u = dev->opaque;
+ CharBackend *chr = u->user->chr;
+ uint8_t *p = (uint8_t *) msg;
+@@ -325,8 +314,7 @@ static gboolean vhost_user_read_cb(void *do_not_use, GIOCondition condition,
+
+ r = vhost_user_read_header(dev, msg);
+ if (r < 0) {
+- data->ret = r;
+- goto end;
++ return r;
+ }
+
+ /* validate message size is sane */
+@@ -334,8 +322,7 @@ static gboolean vhost_user_read_cb(void *do_not_use, GIOCondition condition,
+ error_report("Failed to read msg header."
+ " Size %d exceeds the maximum %zu.", msg->hdr.size,
+ VHOST_USER_PAYLOAD_SIZE);
+- data->ret = -EPROTO;
+- goto end;
++ return -EPROTO;
+ }
+
+ if (msg->hdr.size) {
+@@ -346,84 +333,11 @@ static gboolean vhost_user_read_cb(void *do_not_use, GIOCondition condition,
+ int saved_errno = errno;
+ error_report("Failed to read msg payload."
+ " Read %d instead of %d.", r, msg->hdr.size);
+- data->ret = r < 0 ? -saved_errno : -EIO;
+- goto end;
++ return r < 0 ? -saved_errno : -EIO;
+ }
+ }
+
+-end:
+- g_main_loop_quit(data->loop);
+- return G_SOURCE_REMOVE;
+-}
+-
+-static gboolean slave_read(QIOChannel *ioc, GIOCondition condition,
+- gpointer opaque);
+-
+-/*
+- * This updates the read handler to use a new event loop context.
+- * Event sources are removed from the previous context : this ensures
+- * that events detected in the previous context are purged. They will
+- * be re-detected and processed in the new context.
+- */
+-static void slave_update_read_handler(struct vhost_dev *dev,
+- GMainContext *ctxt)
+-{
+- struct vhost_user *u = dev->opaque;
+-
+- if (!u->slave_ioc) {
+- return;
+- }
+-
+- if (u->slave_src) {
+- g_source_destroy(u->slave_src);
+- g_source_unref(u->slave_src);
+- }
+-
+- u->slave_src = qio_channel_add_watch_source(u->slave_ioc,
+- G_IO_IN | G_IO_HUP,
+- slave_read, dev, NULL,
+- ctxt);
+-}
+-
+-static int vhost_user_read(struct vhost_dev *dev, VhostUserMsg *msg)
+-{
+- struct vhost_user *u = dev->opaque;
+- CharBackend *chr = u->user->chr;
+- GMainContext *prev_ctxt = chr->chr->gcontext;
+- GMainContext *ctxt = g_main_context_new();
+- GMainLoop *loop = g_main_loop_new(ctxt, FALSE);
+- struct vhost_user_read_cb_data data = {
+- .dev = dev,
+- .loop = loop,
+- .msg = msg,
+- .ret = 0
+- };
+-
+- /*
+- * We want to be able to monitor the slave channel fd while waiting
+- * for chr I/O. This requires an event loop, but we can't nest the
+- * one to which chr is currently attached : its fd handlers might not
+- * be prepared for re-entrancy. So we create a new one and switch chr
+- * to use it.
+- */
+- slave_update_read_handler(dev, ctxt);
+- qemu_chr_be_update_read_handlers(chr->chr, ctxt);
+- qemu_chr_fe_add_watch(chr, G_IO_IN | G_IO_HUP, vhost_user_read_cb, &data);
+-
+- g_main_loop_run(loop);
+-
+- /*
+- * Restore the previous event loop context. This also destroys/recreates
+- * event sources : this guarantees that all pending events in the original
+- * context that have been processed by the nested loop are purged.
+- */
+- qemu_chr_be_update_read_handlers(chr->chr, prev_ctxt);
+- slave_update_read_handler(dev, NULL);
+-
+- g_main_loop_unref(loop);
+- g_main_context_unref(ctxt);
+-
+- return data.ret;
++ return 0;
+ }
+
+ static int process_message_reply(struct vhost_dev *dev,
+@@ -1802,7 +1716,9 @@ static int vhost_setup_slave_channel(struct vhost_dev *dev)
+ return -ECONNREFUSED;
+ }
+ u->slave_ioc = ioc;
+- slave_update_read_handler(dev, NULL);
++ u->slave_src = qio_channel_add_watch_source(u->slave_ioc,
++ G_IO_IN | G_IO_HUP,
++ slave_read, dev, NULL, NULL);
+
+ if (reply_supported) {
+ msg.hdr.flags |= VHOST_USER_NEED_REPLY_MASK;
+@@ -2108,8 +2024,8 @@ static int vhost_user_backend_init(struct vhost_dev *dev, void *opaque,
+ } else {
+ if (virtio_has_feature(protocol_features,
+ VHOST_USER_PROTOCOL_F_CONFIG)) {
+- warn_reportf_err(*errp, "vhost-user backend supports "
+- "VHOST_USER_PROTOCOL_F_CONFIG but QEMU does not.");
++ warn_report("vhost-user backend supports "
++ "VHOST_USER_PROTOCOL_F_CONFIG but QEMU does not.");
+ protocol_features &= ~(1ULL << VHOST_USER_PROTOCOL_F_CONFIG);
+ }
+ }
+diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c
+index 97da74e719..a6dbdd32da 100644
+--- a/hw/virtio/virtio-crypto.c
++++ b/hw/virtio/virtio-crypto.c
+@@ -476,15 +476,17 @@ static void virtio_crypto_free_request(VirtIOCryptoReq *req)
+ size_t max_len;
+ CryptoDevBackendSymOpInfo *op_info = req->op_info.u.sym_op_info;
+
+- max_len = op_info->iv_len +
+- op_info->aad_len +
+- op_info->src_len +
+- op_info->dst_len +
+- op_info->digest_result_len;
+-
+- /* Zeroize and free request data structure */
+- memset(op_info, 0, sizeof(*op_info) + max_len);
+- g_free(op_info);
++ if (op_info) {
++ max_len = op_info->iv_len +
++ op_info->aad_len +
++ op_info->src_len +
++ op_info->dst_len +
++ op_info->digest_result_len;
++
++ /* Zeroize and free request data structure */
++ memset(op_info, 0, sizeof(*op_info) + max_len);
++ g_free(op_info);
++ }
+ } else if (req->flags == CRYPTODEV_BACKEND_ALG_ASYM) {
+ CryptoDevBackendAsymOpInfo *op_info = req->op_info.u.asym_op_info;
+ if (op_info) {
+diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
+index eb6347ab5d..384c8f0f08 100644
+--- a/hw/virtio/virtio.c
++++ b/hw/virtio/virtio.c
+@@ -1478,7 +1478,7 @@ static void virtqueue_split_get_avail_bytes(VirtQueue *vq,
+ VRingMemoryRegionCaches *caches)
+ {
+ VirtIODevice *vdev = vq->vdev;
+- unsigned int max, idx;
++ unsigned int idx;
+ unsigned int total_bufs, in_total, out_total;
+ MemoryRegionCache indirect_desc_cache = MEMORY_REGION_CACHE_INVALID;
+ int64_t len = 0;
+@@ -1487,13 +1487,12 @@ static void virtqueue_split_get_avail_bytes(VirtQueue *vq,
+ idx = vq->last_avail_idx;
+ total_bufs = in_total = out_total = 0;
+
+- max = vq->vring.num;
+-
+ while ((rc = virtqueue_num_heads(vq, idx)) > 0) {
+ MemoryRegionCache *desc_cache = &caches->desc;
+ unsigned int num_bufs;
+ VRingDesc desc;
+ unsigned int i;
++ unsigned int max = vq->vring.num;
+
+ num_bufs = total_bufs;
+
+@@ -1615,7 +1614,7 @@ static void virtqueue_packed_get_avail_bytes(VirtQueue *vq,
+ VRingMemoryRegionCaches *caches)
+ {
+ VirtIODevice *vdev = vq->vdev;
+- unsigned int max, idx;
++ unsigned int idx;
+ unsigned int total_bufs, in_total, out_total;
+ MemoryRegionCache *desc_cache;
+ MemoryRegionCache indirect_desc_cache = MEMORY_REGION_CACHE_INVALID;
+@@ -1627,14 +1626,14 @@ static void virtqueue_packed_get_avail_bytes(VirtQueue *vq,
+ wrap_counter = vq->last_avail_wrap_counter;
+ total_bufs = in_total = out_total = 0;
+
+- max = vq->vring.num;
+-
+ for (;;) {
+ unsigned int num_bufs = total_bufs;
+ unsigned int i = idx;
+ int rc;
++ unsigned int max = vq->vring.num;
+
+ desc_cache = &caches->desc;
++
+ vring_packed_desc_read(vdev, &desc, desc_cache, idx, true);
+ if (!is_desc_avail(desc.flags, wrap_counter)) {
+ break;
+diff --git a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c
+index 0ec7e52183..5dd706efbf 100644
+--- a/hw/xen/xen_pt.c
++++ b/hw/xen/xen_pt.c
+@@ -57,6 +57,7 @@
+ #include <sys/ioctl.h>
+
+ #include "hw/pci/pci.h"
++#include "hw/pci/pci_bus.h"
+ #include "hw/qdev-properties.h"
+ #include "hw/qdev-properties-system.h"
+ #include "hw/xen/xen.h"
+@@ -780,15 +781,6 @@ static void xen_pt_realize(PCIDevice *d, Error **errp)
+ s->hostaddr.bus, s->hostaddr.slot, s->hostaddr.function,
+ s->dev.devfn);
+
+- xen_host_pci_device_get(&s->real_device,
+- s->hostaddr.domain, s->hostaddr.bus,
+- s->hostaddr.slot, s->hostaddr.function,
+- errp);
+- if (*errp) {
+- error_append_hint(errp, "Failed to \"open\" the real pci device");
+- return;
+- }
+-
+ s->is_virtfn = s->real_device.is_virtfn;
+ if (s->is_virtfn) {
+ XEN_PT_LOG(d, "%04x:%02x:%02x.%d is a SR-IOV Virtual Function\n",
+@@ -803,8 +795,10 @@ static void xen_pt_realize(PCIDevice *d, Error **errp)
+ s->io_listener = xen_pt_io_listener;
+
+ /* Setup VGA bios for passthrough GFX */
+- if ((s->real_device.domain == 0) && (s->real_device.bus == 0) &&
+- (s->real_device.dev == 2) && (s->real_device.func == 0)) {
++ if ((s->real_device.domain == XEN_PCI_IGD_DOMAIN) &&
++ (s->real_device.bus == XEN_PCI_IGD_BUS) &&
++ (s->real_device.dev == XEN_PCI_IGD_DEV) &&
++ (s->real_device.func == XEN_PCI_IGD_FN)) {
+ if (!is_igd_vga_passthrough(&s->real_device)) {
+ error_setg(errp, "Need to enable igd-passthru if you're trying"
+ " to passthrough IGD GFX");
+@@ -950,11 +944,58 @@ static void xen_pci_passthrough_instance_init(Object *obj)
+ PCI_DEVICE(obj)->cap_present |= QEMU_PCI_CAP_EXPRESS;
+ }
+
++void xen_igd_reserve_slot(PCIBus *pci_bus)
++{
++ if (!xen_igd_gfx_pt_enabled()) {
++ return;
++ }
++
++ XEN_PT_LOG(0, "Reserving PCI slot 2 for IGD\n");
++ pci_bus->slot_reserved_mask |= XEN_PCI_IGD_SLOT_MASK;
++}
++
++static void xen_igd_clear_slot(DeviceState *qdev, Error **errp)
++{
++ ERRP_GUARD();
++ PCIDevice *pci_dev = (PCIDevice *)qdev;
++ XenPCIPassthroughState *s = XEN_PT_DEVICE(pci_dev);
++ XenPTDeviceClass *xpdc = XEN_PT_DEVICE_GET_CLASS(s);
++ PCIBus *pci_bus = pci_get_bus(pci_dev);
++
++ xen_host_pci_device_get(&s->real_device,
++ s->hostaddr.domain, s->hostaddr.bus,
++ s->hostaddr.slot, s->hostaddr.function,
++ errp);
++ if (*errp) {
++ error_append_hint(errp, "Failed to \"open\" the real pci device");
++ return;
++ }
++
++ if (!(pci_bus->slot_reserved_mask & XEN_PCI_IGD_SLOT_MASK)) {
++ xpdc->pci_qdev_realize(qdev, errp);
++ return;
++ }
++
++ if (is_igd_vga_passthrough(&s->real_device) &&
++ s->real_device.domain == XEN_PCI_IGD_DOMAIN &&
++ s->real_device.bus == XEN_PCI_IGD_BUS &&
++ s->real_device.dev == XEN_PCI_IGD_DEV &&
++ s->real_device.func == XEN_PCI_IGD_FN &&
++ s->real_device.vendor_id == PCI_VENDOR_ID_INTEL) {
++ pci_bus->slot_reserved_mask &= ~XEN_PCI_IGD_SLOT_MASK;
++ XEN_PT_LOG(pci_dev, "Intel IGD found, using slot 2\n");
++ }
++ xpdc->pci_qdev_realize(qdev, errp);
++}
++
+ static void xen_pci_passthrough_class_init(ObjectClass *klass, void *data)
+ {
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
++ XenPTDeviceClass *xpdc = XEN_PT_DEVICE_CLASS(klass);
++ xpdc->pci_qdev_realize = dc->realize;
++ dc->realize = xen_igd_clear_slot;
+ k->realize = xen_pt_realize;
+ k->exit = xen_pt_unregister_device;
+ k->config_read = xen_pt_pci_read_config;
+@@ -977,6 +1018,7 @@ static const TypeInfo xen_pci_passthrough_info = {
+ .instance_size = sizeof(XenPCIPassthroughState),
+ .instance_finalize = xen_pci_passthrough_finalize,
+ .class_init = xen_pci_passthrough_class_init,
++ .class_size = sizeof(XenPTDeviceClass),
+ .instance_init = xen_pci_passthrough_instance_init,
+ .interfaces = (InterfaceInfo[]) {
+ { INTERFACE_CONVENTIONAL_PCI_DEVICE },
+diff --git a/hw/xen/xen_pt.h b/hw/xen/xen_pt.h
+index e7c4316a7d..292bdf7499 100644
+--- a/hw/xen/xen_pt.h
++++ b/hw/xen/xen_pt.h
+@@ -41,7 +41,20 @@ typedef struct XenPTReg XenPTReg;
+ #define TYPE_XEN_PT_DEVICE "xen-pci-passthrough"
+ OBJECT_DECLARE_SIMPLE_TYPE(XenPCIPassthroughState, XEN_PT_DEVICE)
+
++#define XEN_PT_DEVICE_CLASS(klass) \
++ OBJECT_CLASS_CHECK(XenPTDeviceClass, klass, TYPE_XEN_PT_DEVICE)
++#define XEN_PT_DEVICE_GET_CLASS(obj) \
++ OBJECT_GET_CLASS(XenPTDeviceClass, obj, TYPE_XEN_PT_DEVICE)
++
++typedef void (*XenPTQdevRealize)(DeviceState *qdev, Error **errp);
++
++typedef struct XenPTDeviceClass {
++ PCIDeviceClass parent_class;
++ XenPTQdevRealize pci_qdev_realize;
++} XenPTDeviceClass;
++
+ uint32_t igd_read_opregion(XenPCIPassthroughState *s);
++void xen_igd_reserve_slot(PCIBus *pci_bus);
+ void igd_write_opregion(XenPCIPassthroughState *s, uint32_t val);
+ void xen_igd_passthrough_isa_bridge_create(XenPCIPassthroughState *s,
+ XenHostPCIDevice *dev);
+@@ -76,6 +89,13 @@ typedef int (*xen_pt_conf_byte_read)
+
+ #define XEN_PCI_INTEL_OPREGION 0xfc
+
++#define XEN_PCI_IGD_DOMAIN 0
++#define XEN_PCI_IGD_BUS 0
++#define XEN_PCI_IGD_DEV 2
++#define XEN_PCI_IGD_FN 0
++#define XEN_PCI_IGD_SLOT_MASK \
++ (1UL << PCI_SLOT(PCI_DEVFN(XEN_PCI_IGD_DEV, XEN_PCI_IGD_FN)))
++
+ typedef enum {
+ XEN_PT_GRP_TYPE_HARDWIRED = 0, /* 0 Hardwired reg group */
+ XEN_PT_GRP_TYPE_EMU, /* emul reg group */
+diff --git a/hw/xen/xen_pt_stub.c b/hw/xen/xen_pt_stub.c
+index 2d8cac8d54..5c108446a8 100644
+--- a/hw/xen/xen_pt_stub.c
++++ b/hw/xen/xen_pt_stub.c
+@@ -20,3 +20,7 @@ void xen_igd_gfx_pt_set(bool value, Error **errp)
+ error_setg(errp, "Xen PCI passthrough support not built in");
+ }
+ }
++
++void xen_igd_reserve_slot(PCIBus *pci_bus)
++{
++}
+diff --git a/include/hw/arm/boot.h b/include/hw/arm/boot.h
+index f18cc3064f..80c492d742 100644
+--- a/include/hw/arm/boot.h
++++ b/include/hw/arm/boot.h
+@@ -183,4 +183,53 @@ void arm_write_secure_board_setup_dummy_smc(ARMCPU *cpu,
+ const struct arm_boot_info *info,
+ hwaddr mvbar_addr);
+
++typedef enum {
++ FIXUP_NONE = 0, /* do nothing */
++ FIXUP_TERMINATOR, /* end of insns */
++ FIXUP_BOARDID, /* overwrite with board ID number */
++ FIXUP_BOARD_SETUP, /* overwrite with board specific setup code address */
++ FIXUP_ARGPTR_LO, /* overwrite with pointer to kernel args */
++ FIXUP_ARGPTR_HI, /* overwrite with pointer to kernel args (high half) */
++ FIXUP_ENTRYPOINT_LO, /* overwrite with kernel entry point */
++ FIXUP_ENTRYPOINT_HI, /* overwrite with kernel entry point (high half) */
++ FIXUP_GIC_CPU_IF, /* overwrite with GIC CPU interface address */
++ FIXUP_BOOTREG, /* overwrite with boot register address */
++ FIXUP_DSB, /* overwrite with correct DSB insn for cpu */
++ FIXUP_MAX,
++} FixupType;
++
++typedef struct ARMInsnFixup {
++ uint32_t insn;
++ FixupType fixup;
++} ARMInsnFixup;
++
++/**
++ * arm_write_bootloader - write a bootloader to guest memory
++ * @name: name of the bootloader blob
++ * @as: AddressSpace to write the bootloader
++ * @addr: guest address to write it
++ * @insns: the blob to be loaded
++ * @fixupcontext: context to be used for any fixups in @insns
++ *
++ * Write a bootloader to guest memory at address @addr in the address
++ * space @as. @name is the name to use for the resulting ROM blob, so
++ * it should be unique in the system and reasonably identifiable for debugging.
++ *
++ * @insns must be an array of ARMInsnFixup structs, each of which has
++ * one 32-bit value to be written to the guest memory, and a fixup to be
++ * applied to the value. FIXUP_NONE (do nothing) is value 0, so effectively
++ * the fixup is optional when writing a struct initializer.
++ * The final entry in the array must be { 0, FIXUP_TERMINATOR }.
++ *
++ * All other supported fixup types have the semantics "ignore insn
++ * and instead use the value from the array element @fixupcontext[fixup]".
++ * The caller should therefore provide @fixupcontext as an array of
++ * size FIXUP_MAX whose elements have been initialized for at least
++ * the entries that @insns refers to.
++ */
++void arm_write_bootloader(const char *name,
++ AddressSpace *as, hwaddr addr,
++ const ARMInsnFixup *insns,
++ const uint32_t *fixupcontext);
++
+ #endif /* HW_ARM_BOOT_H */
+diff --git a/linux-user/mips/cpu_loop.c b/linux-user/mips/cpu_loop.c
+index d5c1c7941d..8735e58bad 100644
+--- a/linux-user/mips/cpu_loop.c
++++ b/linux-user/mips/cpu_loop.c
+@@ -290,7 +290,10 @@ void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
+ env->CP0_Status |= (1 << CP0St_FR);
+ env->hflags |= MIPS_HFLAG_F64;
+ }
+- } else if (!prog_req.fre && !prog_req.frdefault &&
++ } else if (prog_req.fr1) {
++ env->CP0_Status |= (1 << CP0St_FR);
++ env->hflags |= MIPS_HFLAG_F64;
++ } else if (!prog_req.fre && !prog_req.frdefault &&
+ !prog_req.fr1 && !prog_req.single && !prog_req.soft) {
+ fprintf(stderr, "qemu: Can't find a matching FPU mode\n");
+ exit(1);
+diff --git a/linux-user/syscall.c b/linux-user/syscall.c
+index 9ca30149d4..cedf22c5b5 100644
+--- a/linux-user/syscall.c
++++ b/linux-user/syscall.c
+@@ -11438,39 +11438,58 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
+ {
+ int gidsetsize = arg1;
+ target_id *target_grouplist;
+- gid_t *grouplist;
++ g_autofree gid_t *grouplist = NULL;
+ int i;
+
+- grouplist = alloca(gidsetsize * sizeof(gid_t));
++ if (gidsetsize > NGROUPS_MAX) {
++ return -TARGET_EINVAL;
++ }
++ if (gidsetsize > 0) {
++ grouplist = g_try_new(gid_t, gidsetsize);
++ if (!grouplist) {
++ return -TARGET_ENOMEM;
++ }
++ }
+ ret = get_errno(getgroups(gidsetsize, grouplist));
+- if (gidsetsize == 0)
+- return ret;
+- if (!is_error(ret)) {
+- target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * sizeof(target_id), 0);
+- if (!target_grouplist)
++ if (!is_error(ret) && gidsetsize > 0) {
++ target_grouplist = lock_user(VERIFY_WRITE, arg2,
++ gidsetsize * sizeof(target_id), 0);
++ if (!target_grouplist) {
+ return -TARGET_EFAULT;
+- for(i = 0;i < ret; i++)
++ }
++ for (i = 0; i < ret; i++) {
+ target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
+- unlock_user(target_grouplist, arg2, gidsetsize * sizeof(target_id));
++ }
++ unlock_user(target_grouplist, arg2,
++ gidsetsize * sizeof(target_id));
+ }
++ return ret;
+ }
+- return ret;
+ case TARGET_NR_setgroups:
+ {
+ int gidsetsize = arg1;
+ target_id *target_grouplist;
+- gid_t *grouplist = NULL;
++ g_autofree gid_t *grouplist = NULL;
+ int i;
+- if (gidsetsize) {
+- grouplist = alloca(gidsetsize * sizeof(gid_t));
+- target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * sizeof(target_id), 1);
++
++ if (gidsetsize > NGROUPS_MAX || gidsetsize < 0) {
++ return -TARGET_EINVAL;
++ }
++ if (gidsetsize > 0) {
++ grouplist = g_try_new(gid_t, gidsetsize);
++ if (!grouplist) {
++ return -TARGET_ENOMEM;
++ }
++ target_grouplist = lock_user(VERIFY_READ, arg2,
++ gidsetsize * sizeof(target_id), 1);
+ if (!target_grouplist) {
+ return -TARGET_EFAULT;
+ }
+ for (i = 0; i < gidsetsize; i++) {
+ grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
+ }
+- unlock_user(target_grouplist, arg2, 0);
++ unlock_user(target_grouplist, arg2,
++ gidsetsize * sizeof(target_id));
+ }
+ return get_errno(setgroups(gidsetsize, grouplist));
+ }
+@@ -11755,41 +11774,59 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
+ {
+ int gidsetsize = arg1;
+ uint32_t *target_grouplist;
+- gid_t *grouplist;
++ g_autofree gid_t *grouplist = NULL;
+ int i;
+
+- grouplist = alloca(gidsetsize * sizeof(gid_t));
++ if (gidsetsize > NGROUPS_MAX) {
++ return -TARGET_EINVAL;
++ }
++ if (gidsetsize > 0) {
++ grouplist = g_try_new(gid_t, gidsetsize);
++ if (!grouplist) {
++ return -TARGET_ENOMEM;
++ }
++ }
+ ret = get_errno(getgroups(gidsetsize, grouplist));
+- if (gidsetsize == 0)
+- return ret;
+- if (!is_error(ret)) {
+- target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0);
++ if (!is_error(ret) && gidsetsize > 0) {
++ target_grouplist = lock_user(VERIFY_WRITE, arg2,
++ gidsetsize * 4, 0);
+ if (!target_grouplist) {
+ return -TARGET_EFAULT;
+ }
+- for(i = 0;i < ret; i++)
++ for (i = 0; i < ret; i++) {
+ target_grouplist[i] = tswap32(grouplist[i]);
++ }
+ unlock_user(target_grouplist, arg2, gidsetsize * 4);
+ }
++ return ret;
+ }
+- return ret;
+ #endif
+ #ifdef TARGET_NR_setgroups32
+ case TARGET_NR_setgroups32:
+ {
+ int gidsetsize = arg1;
+ uint32_t *target_grouplist;
+- gid_t *grouplist;
++ g_autofree gid_t *grouplist = NULL;
+ int i;
+
+- grouplist = alloca(gidsetsize * sizeof(gid_t));
+- target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1);
+- if (!target_grouplist) {
+- return -TARGET_EFAULT;
++ if (gidsetsize > NGROUPS_MAX || gidsetsize < 0) {
++ return -TARGET_EINVAL;
++ }
++ if (gidsetsize > 0) {
++ grouplist = g_try_new(gid_t, gidsetsize);
++ if (!grouplist) {
++ return -TARGET_ENOMEM;
++ }
++ target_grouplist = lock_user(VERIFY_READ, arg2,
++ gidsetsize * 4, 1);
++ if (!target_grouplist) {
++ return -TARGET_EFAULT;
++ }
++ for (i = 0; i < gidsetsize; i++) {
++ grouplist[i] = tswap32(target_grouplist[i]);
++ }
++ unlock_user(target_grouplist, arg2, 0);
+ }
+- for(i = 0;i < gidsetsize; i++)
+- grouplist[i] = tswap32(target_grouplist[i]);
+- unlock_user(target_grouplist, arg2, 0);
+ return get_errno(setgroups(gidsetsize, grouplist));
+ }
+ #endif
+diff --git a/meson.build b/meson.build
+index b88867ca9d..450c48a9f0 100644
+--- a/meson.build
++++ b/meson.build
+@@ -3164,6 +3164,10 @@ modinfo_files = []
+ block_mods = []
+ softmmu_mods = []
+ foreach d, list : modules
++ if not (d == 'block' ? have_block : have_system)
++ continue
++ endif
++
+ foreach m, module_ss : list
+ if enable_modules and targetos != 'windows'
+ module_ss = module_ss.apply(config_all, strict: false)
+diff --git a/migration/migration.c b/migration/migration.c
+index f485eea5fb..c19fb5cb3e 100644
+--- a/migration/migration.c
++++ b/migration/migration.c
+@@ -3320,7 +3320,6 @@ static void migration_completion(MigrationState *s)
+ ret = global_state_store();
+
+ if (!ret) {
+- bool inactivate = !migrate_colo_enabled();
+ ret = vm_stop_force_state(RUN_STATE_FINISH_MIGRATE);
+ trace_migration_completion_vm_stop(ret);
+ if (ret >= 0) {
+@@ -3328,12 +3327,15 @@ static void migration_completion(MigrationState *s)
+ MIGRATION_STATUS_DEVICE);
+ }
+ if (ret >= 0) {
++ /*
++ * Inactivate disks except in COLO, and track that we
++ * have done so in order to remember to reactivate
++ * them if migration fails or is cancelled.
++ */
++ s->block_inactive = !migrate_colo_enabled();
+ qemu_file_set_rate_limit(s->to_dst_file, INT64_MAX);
+ ret = qemu_savevm_state_complete_precopy(s->to_dst_file, false,
+- inactivate);
+- }
+- if (inactivate && ret >= 0) {
+- s->block_inactive = true;
++ s->block_inactive);
+ }
+ }
+ qemu_mutex_unlock_iothread();
+@@ -3370,13 +3372,13 @@ static void migration_completion(MigrationState *s)
+ rp_error = await_return_path_close_on_source(s);
+ trace_migration_return_path_end_after(rp_error);
+ if (rp_error) {
+- goto fail_invalidate;
++ goto fail;
+ }
+ }
+
+ if (qemu_file_get_error(s->to_dst_file)) {
+ trace_migration_completion_file_err();
+- goto fail_invalidate;
++ goto fail;
+ }
+
+ if (migrate_colo_enabled() && s->state == MIGRATION_STATUS_ACTIVE) {
+@@ -3390,12 +3392,13 @@ static void migration_completion(MigrationState *s)
+
+ return;
+
+-fail_invalidate:
+- /* If not doing postcopy, vm_start() will be called: let's regain
+- * control on images.
+- */
+- if (s->state == MIGRATION_STATUS_ACTIVE ||
+- s->state == MIGRATION_STATUS_DEVICE) {
++fail:
++ if (s->block_inactive && (s->state == MIGRATION_STATUS_ACTIVE ||
++ s->state == MIGRATION_STATUS_DEVICE)) {
++ /*
++ * If not doing postcopy, vm_start() will be called: let's
++ * regain control on images.
++ */
+ Error *local_err = NULL;
+
+ qemu_mutex_lock_iothread();
+@@ -3408,7 +3411,6 @@ fail_invalidate:
+ qemu_mutex_unlock_iothread();
+ }
+
+-fail:
+ migrate_set_state(&s->state, current_active_state,
+ MIGRATION_STATUS_FAILED);
+ }
+diff --git a/qemu-options.hx b/qemu-options.hx
+index 7f99d15b23..e52289479b 100644
+--- a/qemu-options.hx
++++ b/qemu-options.hx
+@@ -1140,10 +1140,22 @@ have gone through several iterations as the feature set and complexity
+ of the block layer have grown. Many online guides to QEMU often
+ reference older and deprecated options, which can lead to confusion.
+
+-The recommended modern way to describe disks is to use a combination of
++The most explicit way to describe disks is to use a combination of
+ ``-device`` to specify the hardware device and ``-blockdev`` to
+ describe the backend. The device defines what the guest sees and the
+-backend describes how QEMU handles the data.
++backend describes how QEMU handles the data. It is the only guaranteed
++stable interface for describing block devices and as such is
++recommended for management tools and scripting.
++
++The ``-drive`` option combines the device and backend into a single
++command line option which is a more human friendly. There is however no
++interface stability guarantee although some older board models still
++need updating to work with the modern blockdev forms.
++
++Older options like ``-hda`` are essentially macros which expand into
++``-drive`` options for various drive interfaces. The original forms
++bake in a lot of assumptions from the days when QEMU was emulating a
++legacy PC, they are not recommended for modern configurations.
+
+ ERST
+
+@@ -1636,6 +1648,14 @@ SRST
+ the raw disk image you use is not written back. You can however
+ force the write back by pressing C-a s (see the :ref:`disk images`
+ chapter in the System Emulation Users Guide).
++
++ .. warning::
++ snapshot is incompatible with ``-blockdev`` (instead use qemu-img
++ to manually create snapshot images to attach to your blockdev).
++ If you have mixed ``-blockdev`` and ``-drive`` declarations you
++ can use the 'snapshot' property on your drive declarations
++ instead of this global option.
++
+ ERST
+
+ DEF("fsdev", HAS_ARG, QEMU_OPTION_fsdev,
+diff --git a/target/arm/kvm.c b/target/arm/kvm.c
+index f022c644d2..84da49332c 100644
+--- a/target/arm/kvm.c
++++ b/target/arm/kvm.c
+@@ -280,6 +280,8 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
+ }
+ }
+
++ kvm_arm_init_debug(s);
++
+ return ret;
+ }
+
+diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c
+index 1197253d12..810db33ccb 100644
+--- a/target/arm/kvm64.c
++++ b/target/arm/kvm64.c
+@@ -74,24 +74,16 @@ GArray *hw_breakpoints, *hw_watchpoints;
+ #define get_hw_bp(i) (&g_array_index(hw_breakpoints, HWBreakpoint, i))
+ #define get_hw_wp(i) (&g_array_index(hw_watchpoints, HWWatchpoint, i))
+
+-/**
+- * kvm_arm_init_debug() - check for guest debug capabilities
+- * @cs: CPUState
+- *
+- * kvm_check_extension returns the number of debug registers we have
+- * or 0 if we have none.
+- *
+- */
+-static void kvm_arm_init_debug(CPUState *cs)
++void kvm_arm_init_debug(KVMState *s)
+ {
+- have_guest_debug = kvm_check_extension(cs->kvm_state,
++ have_guest_debug = kvm_check_extension(s,
+ KVM_CAP_SET_GUEST_DEBUG);
+
+- max_hw_wps = kvm_check_extension(cs->kvm_state, KVM_CAP_GUEST_DEBUG_HW_WPS);
++ max_hw_wps = kvm_check_extension(s, KVM_CAP_GUEST_DEBUG_HW_WPS);
+ hw_watchpoints = g_array_sized_new(true, true,
+ sizeof(HWWatchpoint), max_hw_wps);
+
+- max_hw_bps = kvm_check_extension(cs->kvm_state, KVM_CAP_GUEST_DEBUG_HW_BPS);
++ max_hw_bps = kvm_check_extension(s, KVM_CAP_GUEST_DEBUG_HW_BPS);
+ hw_breakpoints = g_array_sized_new(true, true,
+ sizeof(HWBreakpoint), max_hw_bps);
+ return;
+@@ -920,8 +912,6 @@ int kvm_arch_init_vcpu(CPUState *cs)
+ }
+ cpu->mp_affinity = mpidr & ARM64_AFFINITY_MASK;
+
+- kvm_arm_init_debug(cs);
+-
+ /* Check whether user space can specify guest syndrome value */
+ kvm_arm_init_serror_injection(cs);
+
+diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h
+index 99017b635c..330fbe5c72 100644
+--- a/target/arm/kvm_arm.h
++++ b/target/arm/kvm_arm.h
+@@ -18,6 +18,14 @@
+ #define KVM_ARM_VGIC_V2 (1 << 0)
+ #define KVM_ARM_VGIC_V3 (1 << 1)
+
++/**
++ * kvm_arm_init_debug() - initialize guest debug capabilities
++ * @s: KVMState
++ *
++ * Should be called only once before using guest debug capabilities.
++ */
++void kvm_arm_init_debug(KVMState *s);
++
+ /**
+ * kvm_arm_vcpu_init:
+ * @cs: CPUState
+diff --git a/target/arm/sve_helper.c b/target/arm/sve_helper.c
+index 521fc9b969..27838fb6e2 100644
+--- a/target/arm/sve_helper.c
++++ b/target/arm/sve_helper.c
+@@ -6726,6 +6726,7 @@ void sve_ldff1_z(CPUARMState *env, void *vd, uint64_t *vg, void *vm,
+ intptr_t reg_off;
+ SVEHostPage info;
+ target_ulong addr, in_page;
++ ARMVectorReg scratch;
+
+ /* Skip to the first true predicate. */
+ reg_off = find_next_active(vg, 0, reg_max, esz);
+@@ -6735,6 +6736,11 @@ void sve_ldff1_z(CPUARMState *env, void *vd, uint64_t *vg, void *vm,
+ return;
+ }
+
++ /* Protect against overlap between vd and vm. */
++ if (unlikely(vd == vm)) {
++ vm = memcpy(&scratch, vm, reg_max);
++ }
++
+ /*
+ * Probe the first element, allowing faults.
+ */
+diff --git a/target/arm/translate-a32.h b/target/arm/translate-a32.h
+index 5339c22f1e..99eea85fa8 100644
+--- a/target/arm/translate-a32.h
++++ b/target/arm/translate-a32.h
+@@ -61,6 +61,13 @@ static inline TCGv_i32 load_cpu_offset(int offset)
+
+ #define load_cpu_field(name) load_cpu_offset(offsetof(CPUARMState, name))
+
++/* Load from the low half of a 64-bit field to a TCGv_i32 */
++#define load_cpu_field_low32(name) \
++ ({ \
++ QEMU_BUILD_BUG_ON(sizeof_field(CPUARMState, name) != 8); \
++ load_cpu_offset(offsetoflow32(CPUARMState, name)); \
++ })
++
+ void store_cpu_offset(TCGv_i32 var, int offset, int size);
+
+ #define store_cpu_field(var, name) \
+diff --git a/target/arm/translate.c b/target/arm/translate.c
+index 1dcaefb8e7..a06da05640 100644
+--- a/target/arm/translate.c
++++ b/target/arm/translate.c
+@@ -2886,7 +2886,7 @@ static bool msr_banked_access_decode(DisasContext *s, int r, int sysm, int rn,
+ if (arm_dc_feature(s, ARM_FEATURE_AARCH64) &&
+ dc_isar_feature(aa64_sel2, s)) {
+ /* Target EL is EL<3 minus SCR_EL3.EEL2> */
+- tcg_el = load_cpu_field(cp15.scr_el3);
++ tcg_el = load_cpu_field_low32(cp15.scr_el3);
+ tcg_gen_sextract_i32(tcg_el, tcg_el, ctz32(SCR_EEL2), 1);
+ tcg_gen_addi_i32(tcg_el, tcg_el, 3);
+ } else {
+@@ -6558,7 +6558,7 @@ static bool trans_ERET(DisasContext *s, arg_ERET *a)
+ }
+ if (s->current_el == 2) {
+ /* ERET from Hyp uses ELR_Hyp, not LR */
+- tmp = load_cpu_field(elr_el[2]);
++ tmp = load_cpu_field_low32(elr_el[2]);
+ } else {
+ tmp = load_reg(s, 14);
+ }
+diff --git a/target/i386/cpu.c b/target/i386/cpu.c
+index 22b681ca37..0f71ff9fea 100644
+--- a/target/i386/cpu.c
++++ b/target/i386/cpu.c
+@@ -5584,8 +5584,8 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
+ } else {
+ *eax &= env->features[FEAT_SGX_12_1_EAX];
+ *ebx &= 0; /* ebx reserve */
+- *ecx &= env->features[FEAT_XSAVE_XSS_LO];
+- *edx &= env->features[FEAT_XSAVE_XSS_HI];
++ *ecx &= env->features[FEAT_XSAVE_XCR0_LO];
++ *edx &= env->features[FEAT_XSAVE_XCR0_HI];
+
+ /* FP and SSE are always allowed regardless of XSAVE/XCR0. */
+ *ecx |= XSTATE_FP_MASK | XSTATE_SSE_MASK;
+diff --git a/target/i386/ops_sse.h b/target/i386/ops_sse.h
+index 3cbc36a59d..44c1e70093 100644
+--- a/target/i386/ops_sse.h
++++ b/target/i386/ops_sse.h
+@@ -2493,6 +2493,14 @@ void helper_vpermdq_ymm(Reg *d, Reg *v, Reg *s, uint32_t order)
+ d->Q(1) = r1;
+ d->Q(2) = r2;
+ d->Q(3) = r3;
++ if (order & 0x8) {
++ d->Q(0) = 0;
++ d->Q(1) = 0;
++ }
++ if (order & 0x80) {
++ d->Q(2) = 0;
++ d->Q(3) = 0;
++ }
+ }
+
+ void helper_vpermq_ymm(Reg *d, Reg *s, uint32_t order)
+diff --git a/target/i386/tcg/decode-new.c.inc b/target/i386/tcg/decode-new.c.inc
+index 80c579164f..c2ee712561 100644
+--- a/target/i386/tcg/decode-new.c.inc
++++ b/target/i386/tcg/decode-new.c.inc
+@@ -782,6 +782,17 @@ static void decode_0F2D(DisasContext *s, CPUX86State *env, X86OpEntry *entry, ui
+ *entry = *decode_by_prefix(s, opcodes_0F2D);
+ }
+
++static void decode_VxCOMISx(DisasContext *s, CPUX86State *env, X86OpEntry *entry, uint8_t *b)
++{
++ /*
++ * VUCOMISx and VCOMISx are different and use no-prefix and 0x66 for SS and SD
++ * respectively. Scalar values usually are associated with 0xF2 and 0xF3, for
++ * which X86_VEX_REPScalar exists, but here it has to be decoded by hand.
++ */
++ entry->s1 = entry->s2 = (s->prefix & PREFIX_DATA ? X86_SIZE_sd : X86_SIZE_ss);
++ entry->gen = (*b == 0x2E ? gen_VUCOMI : gen_VCOMI);
++}
++
+ static void decode_sse_unary(DisasContext *s, CPUX86State *env, X86OpEntry *entry, uint8_t *b)
+ {
+ if (!(s->prefix & (PREFIX_REPZ | PREFIX_REPNZ))) {
+@@ -870,8 +881,8 @@ static const X86OpEntry opcodes_0F[256] = {
+ [0x2B] = X86_OP_GROUP0(0F2B),
+ [0x2C] = X86_OP_GROUP0(0F2C),
+ [0x2D] = X86_OP_GROUP0(0F2D),
+- [0x2E] = X86_OP_ENTRY3(VUCOMI, None,None, V,x, W,x, vex4 p_00_66),
+- [0x2F] = X86_OP_ENTRY3(VCOMI, None,None, V,x, W,x, vex4 p_00_66),
++ [0x2E] = X86_OP_GROUP3(VxCOMISx, None,None, V,x, W,x, vex3 p_00_66), /* VUCOMISS/SD */
++ [0x2F] = X86_OP_GROUP3(VxCOMISx, None,None, V,x, W,x, vex3 p_00_66), /* VCOMISS/SD */
+
+ [0x38] = X86_OP_GROUP0(0F38),
+ [0x3a] = X86_OP_GROUP0(0F3A),
+diff --git a/target/i386/tcg/emit.c.inc b/target/i386/tcg/emit.c.inc
+index 7296f3952c..5d31fce65d 100644
+--- a/target/i386/tcg/emit.c.inc
++++ b/target/i386/tcg/emit.c.inc
+@@ -2288,7 +2288,7 @@ static void gen_VZEROALL(DisasContext *s, CPUX86State *env, X86DecodedInsn *deco
+ {
+ TCGv_ptr ptr = tcg_temp_new_ptr();
+
+- tcg_gen_addi_ptr(ptr, cpu_env, offsetof(CPUX86State, xmm_t0));
++ tcg_gen_addi_ptr(ptr, cpu_env, offsetof(CPUX86State, xmm_regs));
+ gen_helper_memset(ptr, ptr, tcg_constant_i32(0),
+ tcg_constant_ptr(CPU_NB_REGS * sizeof(ZMMReg)));
+ tcg_temp_free_ptr(ptr);
+diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
+index 94adcb766b..30bc2e6adf 100644
+--- a/target/ppc/excp_helper.c
++++ b/target/ppc/excp_helper.c
+@@ -2631,7 +2631,7 @@ void helper_scv(CPUPPCState *env, uint32_t lev)
+ }
+ }
+
+-void helper_pminsn(CPUPPCState *env, powerpc_pm_insn_t insn)
++void helper_pminsn(CPUPPCState *env, uint32_t insn)
+ {
+ CPUState *cs;
+
+diff --git a/target/ppc/translate/vmx-impl.c.inc b/target/ppc/translate/vmx-impl.c.inc
+index 7741f2eb49..764b76dcc6 100644
+--- a/target/ppc/translate/vmx-impl.c.inc
++++ b/target/ppc/translate/vmx-impl.c.inc
+@@ -2231,7 +2231,7 @@ static bool trans_VEXPANDQM(DisasContext *ctx, arg_VX_tb *a)
+ static bool do_vextractm(DisasContext *ctx, arg_VX_tb *a, unsigned vece)
+ {
+ const uint64_t elem_width = 8 << vece, elem_count_half = 8 >> vece,
+- mask = dup_const(vece, 1 << (elem_width - 1));
++ mask = dup_const(vece, 1ULL << (elem_width - 1));
+ uint64_t i, j;
+ TCGv_i64 lo, hi, t0, t1;
+
+diff --git a/target/riscv/insn_trans/trans_privileged.c.inc b/target/riscv/insn_trans/trans_privileged.c.inc
+index 3281408a87..74e2894462 100644
+--- a/target/riscv/insn_trans/trans_privileged.c.inc
++++ b/target/riscv/insn_trans/trans_privileged.c.inc
+@@ -77,6 +77,9 @@ static bool trans_sret(DisasContext *ctx, arg_sret *a)
+ #ifndef CONFIG_USER_ONLY
+ if (has_ext(ctx, RVS)) {
+ decode_save_opc(ctx);
++ if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
++ gen_io_start();
++ }
+ gen_helper_sret(cpu_pc, cpu_env);
+ tcg_gen_exit_tb(NULL, 0); /* no chaining */
+ ctx->base.is_jmp = DISAS_NORETURN;
+@@ -93,6 +96,9 @@ static bool trans_mret(DisasContext *ctx, arg_mret *a)
+ {
+ #ifndef CONFIG_USER_ONLY
+ decode_save_opc(ctx);
++ if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
++ gen_io_start();
++ }
+ gen_helper_mret(cpu_pc, cpu_env);
+ tcg_gen_exit_tb(NULL, 0); /* no chaining */
+ ctx->base.is_jmp = DISAS_NORETURN;
+diff --git a/target/s390x/tcg/insn-data.h.inc b/target/s390x/tcg/insn-data.h.inc
+index 2a5fc99818..13ffdda4da 100644
+--- a/target/s390x/tcg/insn-data.h.inc
++++ b/target/s390x/tcg/insn-data.h.inc
+@@ -606,7 +606,7 @@
+ F(0xed04, LDEB, RXE, Z, 0, m2_32u, new, f1, ldeb, 0, IF_BFP)
+ F(0xed05, LXDB, RXE, Z, 0, m2_64, new_P, x1, lxdb, 0, IF_BFP)
+ F(0xed06, LXEB, RXE, Z, 0, m2_32u, new_P, x1, lxeb, 0, IF_BFP)
+- F(0xb324, LDER, RXE, Z, 0, e2, new, f1, lde, 0, IF_AFP1)
++ F(0xb324, LDER, RRE, Z, 0, e2, new, f1, lde, 0, IF_AFP1)
+ F(0xed24, LDE, RXE, Z, 0, m2_32u, new, f1, lde, 0, IF_AFP1)
+ /* LOAD ROUNDED */
+ F(0xb344, LEDBR, RRF_e, Z, 0, f2, new, e1, ledb, 0, IF_BFP)
+diff --git a/target/s390x/tcg/translate.c b/target/s390x/tcg/translate.c
+index e328aa5b97..0885bf2641 100644
+--- a/target/s390x/tcg/translate.c
++++ b/target/s390x/tcg/translate.c
+@@ -1585,18 +1585,51 @@ static DisasJumpType op_bal(DisasContext *s, DisasOps *o)
+ }
+ }
+
++/*
++ * Disassemble the target of a branch. The results are returned in a form
++ * suitable for passing into help_branch():
++ *
++ * - bool IS_IMM reflects whether the target is fixed or computed. Non-EXECUTEd
++ * branches, whose DisasContext *S contains the relative immediate field RI,
++ * are considered fixed. All the other branches are considered computed.
++ * - int IMM is the value of RI.
++ * - TCGv_i64 CDEST is the address of the computed target.
++ */
++#define disas_jdest(s, ri, is_imm, imm, cdest) do { \
++ if (have_field(s, ri)) { \
++ if (unlikely(s->ex_value)) { \
++ cdest = tcg_temp_new_i64(); \
++ tcg_gen_ld_i64(cdest, cpu_env, offsetof(CPUS390XState, ex_target));\
++ tcg_gen_addi_i64(cdest, cdest, (int64_t)get_field(s, ri) * 2); \
++ is_imm = false; \
++ } else { \
++ is_imm = true; \
++ } \
++ } else { \
++ is_imm = false; \
++ } \
++ imm = is_imm ? get_field(s, ri) : 0; \
++} while (false)
++
+ static DisasJumpType op_basi(DisasContext *s, DisasOps *o)
+ {
++ DisasCompare c;
++ bool is_imm;
++ int imm;
++
+ pc_to_link_info(o->out, s, s->pc_tmp);
+- return help_goto_direct(s, s->base.pc_next + (int64_t)get_field(s, i2) * 2);
++
++ disas_jdest(s, i2, is_imm, imm, o->in2);
++ disas_jcc(s, &c, 0xf);
++ return help_branch(s, &c, is_imm, imm, o->in2);
+ }
+
+ static DisasJumpType op_bc(DisasContext *s, DisasOps *o)
+ {
+ int m1 = get_field(s, m1);
+- bool is_imm = have_field(s, i2);
+- int imm = is_imm ? get_field(s, i2) : 0;
+ DisasCompare c;
++ bool is_imm;
++ int imm;
+
+ /* BCR with R2 = 0 causes no branching */
+ if (have_field(s, r2) && get_field(s, r2) == 0) {
+@@ -1613,6 +1646,7 @@ static DisasJumpType op_bc(DisasContext *s, DisasOps *o)
+ return DISAS_NEXT;
+ }
+
++ disas_jdest(s, i2, is_imm, imm, o->in2);
+ disas_jcc(s, &c, m1);
+ return help_branch(s, &c, is_imm, imm, o->in2);
+ }
+@@ -1620,10 +1654,10 @@ static DisasJumpType op_bc(DisasContext *s, DisasOps *o)
+ static DisasJumpType op_bct32(DisasContext *s, DisasOps *o)
+ {
+ int r1 = get_field(s, r1);
+- bool is_imm = have_field(s, i2);
+- int imm = is_imm ? get_field(s, i2) : 0;
+ DisasCompare c;
++ bool is_imm;
+ TCGv_i64 t;
++ int imm;
+
+ c.cond = TCG_COND_NE;
+ c.is_64 = false;
+@@ -1638,6 +1672,7 @@ static DisasJumpType op_bct32(DisasContext *s, DisasOps *o)
+ tcg_gen_extrl_i64_i32(c.u.s32.a, t);
+ tcg_temp_free_i64(t);
+
++ disas_jdest(s, i2, is_imm, imm, o->in2);
+ return help_branch(s, &c, is_imm, imm, o->in2);
+ }
+
+@@ -1668,9 +1703,9 @@ static DisasJumpType op_bcth(DisasContext *s, DisasOps *o)
+ static DisasJumpType op_bct64(DisasContext *s, DisasOps *o)
+ {
+ int r1 = get_field(s, r1);
+- bool is_imm = have_field(s, i2);
+- int imm = is_imm ? get_field(s, i2) : 0;
+ DisasCompare c;
++ bool is_imm;
++ int imm;
+
+ c.cond = TCG_COND_NE;
+ c.is_64 = true;
+@@ -1681,6 +1716,7 @@ static DisasJumpType op_bct64(DisasContext *s, DisasOps *o)
+ c.u.s64.a = regs[r1];
+ c.u.s64.b = tcg_const_i64(0);
+
++ disas_jdest(s, i2, is_imm, imm, o->in2);
+ return help_branch(s, &c, is_imm, imm, o->in2);
+ }
+
+@@ -1688,10 +1724,10 @@ static DisasJumpType op_bx32(DisasContext *s, DisasOps *o)
+ {
+ int r1 = get_field(s, r1);
+ int r3 = get_field(s, r3);
+- bool is_imm = have_field(s, i2);
+- int imm = is_imm ? get_field(s, i2) : 0;
+ DisasCompare c;
++ bool is_imm;
+ TCGv_i64 t;
++ int imm;
+
+ c.cond = (s->insn->data ? TCG_COND_LE : TCG_COND_GT);
+ c.is_64 = false;
+@@ -1707,6 +1743,7 @@ static DisasJumpType op_bx32(DisasContext *s, DisasOps *o)
+ store_reg32_i64(r1, t);
+ tcg_temp_free_i64(t);
+
++ disas_jdest(s, i2, is_imm, imm, o->in2);
+ return help_branch(s, &c, is_imm, imm, o->in2);
+ }
+
+@@ -1714,9 +1751,9 @@ static DisasJumpType op_bx64(DisasContext *s, DisasOps *o)
+ {
+ int r1 = get_field(s, r1);
+ int r3 = get_field(s, r3);
+- bool is_imm = have_field(s, i2);
+- int imm = is_imm ? get_field(s, i2) : 0;
+ DisasCompare c;
++ bool is_imm;
++ int imm;
+
+ c.cond = (s->insn->data ? TCG_COND_LE : TCG_COND_GT);
+ c.is_64 = true;
+@@ -1733,6 +1770,7 @@ static DisasJumpType op_bx64(DisasContext *s, DisasOps *o)
+ c.u.s64.a = regs[r1];
+ c.g1 = true;
+
++ disas_jdest(s, i2, is_imm, imm, o->in2);
+ return help_branch(s, &c, is_imm, imm, o->in2);
+ }
+
+@@ -1750,10 +1788,9 @@ static DisasJumpType op_cj(DisasContext *s, DisasOps *o)
+ c.u.s64.a = o->in1;
+ c.u.s64.b = o->in2;
+
+- is_imm = have_field(s, i4);
+- if (is_imm) {
+- imm = get_field(s, i4);
+- } else {
++ o->out = NULL;
++ disas_jdest(s, i4, is_imm, imm, o->out);
++ if (!is_imm && !o->out) {
+ imm = 0;
+ o->out = get_address(s, 0, get_field(s, b4),
+ get_field(s, d4));
+@@ -5964,15 +6001,13 @@ static void in2_a2(DisasContext *s, DisasOps *o)
+
+ static TCGv gen_ri2(DisasContext *s)
+ {
+- int64_t delta = (int64_t)get_field(s, i2) * 2;
+- TCGv ri2;
++ TCGv ri2 = NULL;
++ bool is_imm;
++ int imm;
+
+- if (unlikely(s->ex_value)) {
+- ri2 = tcg_temp_new_i64();
+- tcg_gen_ld_i64(ri2, cpu_env, offsetof(CPUS390XState, ex_target));
+- tcg_gen_addi_i64(ri2, ri2, delta);
+- } else {
+- ri2 = tcg_constant_i64(s->base.pc_next + delta);
++ disas_jdest(s, i2, is_imm, imm, ri2);
++ if (is_imm) {
++ ri2 = tcg_constant_i64(s->base.pc_next + imm * 2);
+ }
+
+ return ri2;
+diff --git a/tests/docker/dockerfiles/debian-xtensa-cross.docker b/tests/docker/dockerfiles/debian-xtensa-cross.docker
+index 2f11b3b7bc..aebfabdd6e 100644
+--- a/tests/docker/dockerfiles/debian-xtensa-cross.docker
++++ b/tests/docker/dockerfiles/debian-xtensa-cross.docker
+@@ -5,7 +5,7 @@
+ # using a prebuilt toolchains for Xtensa cores from:
+ # https://github.com/foss-xtensa/toolchain/releases
+ #
+-FROM docker.io/library/debian:stretch-slim
++FROM docker.io/library/debian:11-slim
+
+ RUN apt-get update && \
+ DEBIAN_FRONTEND=noninteractive apt install -yy eatmydata && \
+diff --git a/tests/qtest/fuzz-lsi53c895a-test.c b/tests/qtest/fuzz-lsi53c895a-test.c
+index 392a7ae7ed..9b007def26 100644
+--- a/tests/qtest/fuzz-lsi53c895a-test.c
++++ b/tests/qtest/fuzz-lsi53c895a-test.c
+@@ -8,6 +8,36 @@
+ #include "qemu/osdep.h"
+ #include "libqtest.h"
+
++/*
++ * This used to trigger a DMA reentrancy issue
++ * leading to memory corruption bugs like stack
++ * overflow or use-after-free
++ * https://gitlab.com/qemu-project/qemu/-/issues/1563
++ */
++static void test_lsi_dma_reentrancy(void)
++{
++ QTestState *s;
++
++ s = qtest_init("-M q35 -m 512M -nodefaults "
++ "-blockdev driver=null-co,node-name=null0 "
++ "-device lsi53c810 -device scsi-cd,drive=null0");
++
++ qtest_outl(s, 0xcf8, 0x80000804); /* PCI Command Register */
++ qtest_outw(s, 0xcfc, 0x7); /* Enables accesses */
++ qtest_outl(s, 0xcf8, 0x80000814); /* Memory Bar 1 */
++ qtest_outl(s, 0xcfc, 0xff100000); /* Set MMIO Address*/
++ qtest_outl(s, 0xcf8, 0x80000818); /* Memory Bar 2 */
++ qtest_outl(s, 0xcfc, 0xff000000); /* Set RAM Address*/
++ qtest_writel(s, 0xff000000, 0xc0000024);
++ qtest_writel(s, 0xff000114, 0x00000080);
++ qtest_writel(s, 0xff00012c, 0xff000000);
++ qtest_writel(s, 0xff000004, 0xff000114);
++ qtest_writel(s, 0xff000008, 0xff100014);
++ qtest_writel(s, 0xff10002f, 0x000000ff);
++
++ qtest_quit(s);
++}
++
+ /*
+ * This used to trigger a UAF in lsi_do_msgout()
+ * https://gitlab.com/qemu-project/qemu/-/issues/972
+@@ -120,5 +150,8 @@ int main(int argc, char **argv)
+ qtest_add_func("fuzz/lsi53c895a/lsi_do_msgout_cancel_req",
+ test_lsi_do_msgout_cancel_req);
+
++ qtest_add_func("fuzz/lsi53c895a/lsi_dma_reentrancy",
++ test_lsi_dma_reentrancy);
++
+ return g_test_run();
+ }
+diff --git a/ui/console.c b/ui/console.c
+index 3c0d9b061a..646202214a 100644
+--- a/ui/console.c
++++ b/ui/console.c
+@@ -307,7 +307,7 @@ static bool png_save(int fd, pixman_image_t *image, Error **errp)
+ png_struct *png_ptr;
+ png_info *info_ptr;
+ g_autoptr(pixman_image_t) linebuf =
+- qemu_pixman_linebuf_create(PIXMAN_a8r8g8b8, width);
++ qemu_pixman_linebuf_create(PIXMAN_BE_r8g8b8, width);
+ uint8_t *buf = (uint8_t *)pixman_image_get_data(linebuf);
+ FILE *f = fdopen(fd, "wb");
+ int y;
+@@ -337,7 +337,7 @@ static bool png_save(int fd, pixman_image_t *image, Error **errp)
+ png_init_io(png_ptr, f);
+
+ png_set_IHDR(png_ptr, info_ptr, width, height, 8,
+- PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
++ PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
+ PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
+
+ png_write_info(png_ptr, info_ptr);
+diff --git a/ui/vnc.c b/ui/vnc.c
+index 88f55cbf3c..1856d57380 100644
+--- a/ui/vnc.c
++++ b/ui/vnc.c
+@@ -3765,7 +3765,7 @@ static int vnc_display_get_address(const char *addrstr,
+
+ addr->type = SOCKET_ADDRESS_TYPE_INET;
+ inet = &addr->u.inet;
+- if (addrstr[0] == '[' && addrstr[hostlen - 1] == ']') {
++ if (hostlen && addrstr[0] == '[' && addrstr[hostlen - 1] == ']') {
+ inet->host = g_strndup(addrstr + 1, hostlen - 2);
+ } else {
+ inet->host = g_strndup(addrstr, hostlen);
+diff --git a/util/async.c b/util/async.c
+index 63434ddae4..f449c3444e 100644
+--- a/util/async.c
++++ b/util/async.c
+@@ -158,7 +158,21 @@ int aio_bh_poll(AioContext *ctx)
+ int ret = 0;
+
+ QSLIST_MOVE_ATOMIC(&slice.bh_list, &ctx->bh_list);
++
++ /*
++ * GCC13 [-Werror=dangling-pointer=] complains that the local variable
++ * 'slice' is being stored in the global 'ctx->bh_slice_list' but the
++ * list is emptied before this function returns.
++ */
++#if !defined(__clang__)
++#pragma GCC diagnostic push
++#pragma GCC diagnostic ignored "-Wpragmas"
++#pragma GCC diagnostic ignored "-Wdangling-pointer="
++#endif
+ QSIMPLEQ_INSERT_TAIL(&ctx->bh_slice_list, &slice, next);
++#if !defined(__clang__)
++#pragma GCC diagnostic pop
++#endif
+
+ while ((s = QSIMPLEQ_FIRST(&ctx->bh_slice_list))) {
+ QEMUBH *bh;
+diff --git a/util/vfio-helpers.c b/util/vfio-helpers.c
+index 0d1520caac..4670867e1f 100644
+--- a/util/vfio-helpers.c
++++ b/util/vfio-helpers.c
+@@ -106,15 +106,17 @@ struct QEMUVFIOState {
+ */
+ static char *sysfs_find_group_file(const char *device, Error **errp)
+ {
++ g_autoptr(GError) gerr = NULL;
+ char *sysfs_link;
+ char *sysfs_group;
+ char *p;
+ char *path = NULL;
+
+ sysfs_link = g_strdup_printf("/sys/bus/pci/devices/%s/iommu_group", device);
+- sysfs_group = g_malloc0(PATH_MAX);
+- if (readlink(sysfs_link, sysfs_group, PATH_MAX - 1) == -1) {
+- error_setg_errno(errp, errno, "Failed to find iommu group sysfs path");
++ sysfs_group = g_file_read_link(sysfs_link, &gerr);
++ if (gerr) {
++ error_setg(errp, "Failed to find iommu group sysfs path: %s",
++ gerr->message);
+ goto out;
+ }
+ p = strrchr(sysfs_group, '/');