summaryrefslogtreecommitdiffstats
path: root/debian/patches/v7.2.4.diff
diff options
context:
space:
mode:
authorDaniel Baumann <mail@daniel-baumann.ch>2025-06-06 10:05:27 +0000
committerDaniel Baumann <mail@daniel-baumann.ch>2025-06-06 10:05:27 +0000
commit43904a02caeb311a505bbb5ffa431ea9859db5f4 (patch)
treecd841d75f639d9092243b0d02a3bb93cbdea5804 /debian/patches/v7.2.4.diff
parentAdding upstream version 1:7.2+dfsg. (diff)
downloadqemu-debian.tar.xz
qemu-debian.zip
Adding debian version 1:7.2+dfsg-7+deb12u13.debian/1%7.2+dfsg-7+deb12u13debian
Signed-off-by: Daniel Baumann <mail@daniel-baumann.ch>
Diffstat (limited to '')
-rw-r--r--debian/patches/v7.2.4.diff1420
1 files changed, 1420 insertions, 0 deletions
diff --git a/debian/patches/v7.2.4.diff b/debian/patches/v7.2.4.diff
new file mode 100644
index 00000000..e2eeed5f
--- /dev/null
+++ b/debian/patches/v7.2.4.diff
@@ -0,0 +1,1420 @@
+diff --git a/.gitlab-ci.d/buildtest.yml b/.gitlab-ci.d/buildtest.yml
+index d21b4a1fd4..10886bb414 100644
+--- a/.gitlab-ci.d/buildtest.yml
++++ b/.gitlab-ci.d/buildtest.yml
+@@ -109,8 +109,8 @@ crash-test-debian:
+ IMAGE: debian-amd64
+ script:
+ - cd build
+- - make check-venv
+- - tests/venv/bin/python3 scripts/device-crash-test -q ./qemu-system-i386
++ - make NINJA=":" check-venv
++ - tests/venv/bin/python3 scripts/device-crash-test -q --tcg-only ./qemu-system-i386
+
+ build-system-fedora:
+ extends: .native_build_job_template
+@@ -155,7 +155,7 @@ crash-test-fedora:
+ IMAGE: fedora
+ script:
+ - cd build
+- - make check-venv
++ - make NINJA=":" check-venv
+ - tests/venv/bin/python3 scripts/device-crash-test -q ./qemu-system-ppc
+ - tests/venv/bin/python3 scripts/device-crash-test -q ./qemu-system-riscv32
+
+diff --git a/VERSION b/VERSION
+index 429dc57af3..2bbaead448 100644
+--- a/VERSION
++++ b/VERSION
+@@ -1 +1 @@
+-7.2.3
++7.2.4
+diff --git a/docs/system/multi-process.rst b/docs/system/multi-process.rst
+index 210531ee17..1b8852c27c 100644
+--- a/docs/system/multi-process.rst
++++ b/docs/system/multi-process.rst
+@@ -2,7 +2,7 @@ Multi-process QEMU
+ ==================
+
+ This document describes how to configure and use multi-process qemu.
+-For the design document refer to docs/devel/qemu-multiprocess.
++For the design document refer to docs/devel/multi-process.rst.
+
+ 1) Configuration
+ ----------------
+diff --git a/fsdev/virtfs-proxy-helper.c b/fsdev/virtfs-proxy-helper.c
+index 5cafcd7703..d9511f429c 100644
+--- a/fsdev/virtfs-proxy-helper.c
++++ b/fsdev/virtfs-proxy-helper.c
+@@ -26,6 +26,7 @@
+ #include "qemu/xattr.h"
+ #include "9p-iov-marshal.h"
+ #include "hw/9pfs/9p-proxy.h"
++#include "hw/9pfs/9p-util.h"
+ #include "fsdev/9p-iov-marshal.h"
+
+ #define PROGNAME "virtfs-proxy-helper"
+@@ -338,6 +339,28 @@ static void resetugid(int suid, int sgid)
+ }
+ }
+
++/*
++ * Open regular file or directory. Attempts to open any special file are
++ * rejected.
++ *
++ * returns file descriptor or -1 on error
++ */
++static int open_regular(const char *pathname, int flags, mode_t mode)
++{
++ int fd;
++
++ fd = open(pathname, flags, mode);
++ if (fd < 0) {
++ return fd;
++ }
++
++ if (close_if_special_file(fd) < 0) {
++ return -1;
++ }
++
++ return fd;
++}
++
+ /*
+ * send response in two parts
+ * 1) ProxyHeader
+@@ -682,7 +705,7 @@ static int do_create(struct iovec *iovec)
+ if (ret < 0) {
+ goto unmarshal_err_out;
+ }
+- ret = open(path.data, flags, mode);
++ ret = open_regular(path.data, flags, mode);
+ if (ret < 0) {
+ ret = -errno;
+ }
+@@ -707,7 +730,7 @@ static int do_open(struct iovec *iovec)
+ if (ret < 0) {
+ goto err_out;
+ }
+- ret = open(path.data, flags);
++ ret = open_regular(path.data, flags, 0);
+ if (ret < 0) {
+ ret = -errno;
+ }
+diff --git a/hw/9pfs/9p-util.h b/hw/9pfs/9p-util.h
+index c3526144c9..6b44e5f7a4 100644
+--- a/hw/9pfs/9p-util.h
++++ b/hw/9pfs/9p-util.h
+@@ -13,6 +13,8 @@
+ #ifndef QEMU_9P_UTIL_H
+ #define QEMU_9P_UTIL_H
+
++#include "qemu/error-report.h"
++
+ #ifdef O_PATH
+ #define O_PATH_9P_UTIL O_PATH
+ #else
+@@ -112,6 +114,38 @@ static inline void close_preserve_errno(int fd)
+ errno = serrno;
+ }
+
++/**
++ * close_if_special_file() - Close @fd if neither regular file nor directory.
++ *
++ * @fd: file descriptor of open file
++ * Return: 0 on regular file or directory, -1 otherwise
++ *
++ * CVE-2023-2861: Prohibit opening any special file directly on host
++ * (especially device files), as a compromised client could potentially gain
++ * access outside exported tree under certain, unsafe setups. We expect
++ * client to handle I/O on special files exclusively on guest side.
++ */
++static inline int close_if_special_file(int fd)
++{
++ struct stat stbuf;
++
++ if (fstat(fd, &stbuf) < 0) {
++ close_preserve_errno(fd);
++ return -1;
++ }
++ if (!S_ISREG(stbuf.st_mode) && !S_ISDIR(stbuf.st_mode)) {
++ error_report_once(
++ "9p: broken or compromised client detected; attempt to open "
++ "special file (i.e. neither regular file, nor directory)"
++ );
++ close(fd);
++ errno = ENXIO;
++ return -1;
++ }
++
++ return 0;
++}
++
+ static inline int openat_dir(int dirfd, const char *name)
+ {
+ return openat(dirfd, name,
+@@ -146,6 +180,10 @@ again:
+ return -1;
+ }
+
++ if (close_if_special_file(fd) < 0) {
++ return -1;
++ }
++
+ serrno = errno;
+ /* O_NONBLOCK was only needed to open the file. Let's drop it. We don't
+ * do that with O_PATH since fcntl(F_SETFL) isn't supported, and openat()
+diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c
+index 335cfc417d..5905a33015 100644
+--- a/hw/arm/xlnx-zynqmp.c
++++ b/hw/arm/xlnx-zynqmp.c
+@@ -213,7 +213,7 @@ static void xlnx_zynqmp_create_rpu(MachineState *ms, XlnxZynqMPState *s,
+ const char *boot_cpu, Error **errp)
+ {
+ int i;
+- int num_rpus = MIN(ms->smp.cpus - XLNX_ZYNQMP_NUM_APU_CPUS,
++ int num_rpus = MIN((int)(ms->smp.cpus - XLNX_ZYNQMP_NUM_APU_CPUS),
+ XLNX_ZYNQMP_NUM_RPU_CPUS);
+
+ if (num_rpus <= 0) {
+diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
+index 5e15c79b94..4e2e0dd53a 100644
+--- a/hw/display/virtio-gpu.c
++++ b/hw/display/virtio-gpu.c
+@@ -498,6 +498,8 @@ static void virtio_gpu_resource_flush(VirtIOGPU *g,
+ struct virtio_gpu_resource_flush rf;
+ struct virtio_gpu_scanout *scanout;
+ pixman_region16_t flush_region;
++ bool within_bounds = false;
++ bool update_submitted = false;
+ int i;
+
+ VIRTIO_GPU_FILL_CMD(rf);
+@@ -518,13 +520,28 @@ static void virtio_gpu_resource_flush(VirtIOGPU *g,
+ rf.r.x < scanout->x + scanout->width &&
+ rf.r.x + rf.r.width >= scanout->x &&
+ rf.r.y < scanout->y + scanout->height &&
+- rf.r.y + rf.r.height >= scanout->y &&
+- console_has_gl(scanout->con)) {
+- dpy_gl_update(scanout->con, 0, 0, scanout->width,
+- scanout->height);
++ rf.r.y + rf.r.height >= scanout->y) {
++ within_bounds = true;
++
++ if (console_has_gl(scanout->con)) {
++ dpy_gl_update(scanout->con, 0, 0, scanout->width,
++ scanout->height);
++ update_submitted = true;
++ }
+ }
+ }
+- return;
++
++ if (update_submitted) {
++ return;
++ }
++ if (!within_bounds) {
++ qemu_log_mask(LOG_GUEST_ERROR, "%s: flush bounds outside scanouts"
++ " bounds for flush %d: %d %d %d %d\n",
++ __func__, rf.resource_id, rf.r.x, rf.r.y,
++ rf.r.width, rf.r.height);
++ cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
++ return;
++ }
+ }
+
+ if (!res->blob &&
+diff --git a/hw/dma/xilinx_axidma.c b/hw/dma/xilinx_axidma.c
+index cbb8f0f169..99e50f65e2 100644
+--- a/hw/dma/xilinx_axidma.c
++++ b/hw/dma/xilinx_axidma.c
+@@ -168,6 +168,11 @@ static inline int stream_idle(struct Stream *s)
+ return !!(s->regs[R_DMASR] & DMASR_IDLE);
+ }
+
++static inline int stream_halted(struct Stream *s)
++{
++ return !!(s->regs[R_DMASR] & DMASR_HALTED);
++}
++
+ static void stream_reset(struct Stream *s)
+ {
+ s->regs[R_DMASR] = DMASR_HALTED; /* starts up halted. */
+@@ -269,7 +274,7 @@ static void stream_process_mem2s(struct Stream *s, StreamSink *tx_data_dev,
+ uint64_t addr;
+ bool eop;
+
+- if (!stream_running(s) || stream_idle(s)) {
++ if (!stream_running(s) || stream_idle(s) || stream_halted(s)) {
+ return;
+ }
+
+@@ -326,7 +331,7 @@ static size_t stream_process_s2mem(struct Stream *s, unsigned char *buf,
+ unsigned int rxlen;
+ size_t pos = 0;
+
+- if (!stream_running(s) || stream_idle(s)) {
++ if (!stream_running(s) || stream_idle(s) || stream_halted(s)) {
+ return 0;
+ }
+
+@@ -407,7 +412,7 @@ xilinx_axidma_data_stream_can_push(StreamSink *obj,
+ XilinxAXIDMAStreamSink *ds = XILINX_AXI_DMA_DATA_STREAM(obj);
+ struct Stream *s = &ds->dma->streams[1];
+
+- if (!stream_running(s) || stream_idle(s)) {
++ if (!stream_running(s) || stream_idle(s) || stream_halted(s)) {
+ ds->dma->notify = notify;
+ ds->dma->notify_opaque = notify_opaque;
+ return false;
+diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c
+index de1cc7ab71..98a78b84b4 100644
+--- a/hw/hppa/machine.c
++++ b/hw/hppa/machine.c
+@@ -123,6 +123,7 @@ static FWCfgState *create_fw_cfg(MachineState *ms)
+ {
+ FWCfgState *fw_cfg;
+ uint64_t val;
++ const char qemu_version[] = QEMU_VERSION;
+
+ fw_cfg = fw_cfg_init_mem(FW_CFG_IO_BASE, FW_CFG_IO_BASE + 4);
+ fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, ms->smp.cpus);
+@@ -148,6 +149,10 @@ static FWCfgState *create_fw_cfg(MachineState *ms)
+ fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, ms->boot_config.order[0]);
+ qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
+
++ fw_cfg_add_file(fw_cfg, "/etc/qemu-version",
++ g_memdup(qemu_version, sizeof(qemu_version)),
++ sizeof(qemu_version));
++
+ return fw_cfg;
+ }
+
+@@ -418,10 +423,16 @@ static void hppa_machine_reset(MachineState *ms, ShutdownCause reason)
+
+ /* Start all CPUs at the firmware entry point.
+ * Monarch CPU will initialize firmware, secondary CPUs
+- * will enter a small idle look and wait for rendevouz. */
++ * will enter a small idle loop and wait for rendevouz. */
+ for (i = 0; i < smp_cpus; i++) {
+- cpu_set_pc(CPU(cpu[i]), firmware_entry);
++ CPUState *cs = CPU(cpu[i]);
++
++ cpu_set_pc(cs, firmware_entry);
++ cpu[i]->env.psw = PSW_Q;
+ cpu[i]->env.gr[5] = CPU_HPA + i * 0x1000;
++
++ cs->exception_index = -1;
++ cs->halted = 0;
+ }
+
+ /* already initialized by machine_hppa_init()? */
+diff --git a/hw/intc/allwinner-a10-pic.c b/hw/intc/allwinner-a10-pic.c
+index 4875e68ba6..d0bf8d545b 100644
+--- a/hw/intc/allwinner-a10-pic.c
++++ b/hw/intc/allwinner-a10-pic.c
+@@ -51,7 +51,7 @@ 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];
+
+- *pending_reg = deposit32(*pending_reg, irq % 32, 1, level);
++ *pending_reg = deposit32(*pending_reg, irq % 32, 1, !!level);
+ aw_a10_pic_update(s);
+ }
+
+diff --git a/hw/misc/aspeed_hace.c b/hw/misc/aspeed_hace.c
+index ac21be306c..69175e972d 100644
+--- a/hw/misc/aspeed_hace.c
++++ b/hw/misc/aspeed_hace.c
+@@ -189,7 +189,7 @@ static void do_hash_operation(AspeedHACEState *s, int algo, bool sg_mode,
+ bool acc_mode)
+ {
+ struct iovec iov[ASPEED_HACE_MAX_SG];
+- g_autofree uint8_t *digest_buf;
++ g_autofree uint8_t *digest_buf = NULL;
+ size_t digest_len = 0;
+ int niov = 0;
+ int i;
+diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c
+index dc86c1c7db..fbdc48911e 100644
+--- a/hw/ppc/ppc.c
++++ b/hw/ppc/ppc.c
+@@ -806,6 +806,8 @@ static void __cpu_ppc_store_decr(PowerPCCPU *cpu, uint64_t *nextp,
+ int64_t signed_decr;
+
+ /* Truncate value to decr_width and sign extend for simplicity */
++ value = extract64(value, 0, nr_bits);
++ decr = extract64(decr, 0, nr_bits);
+ signed_value = sextract64(value, 0, nr_bits);
+ signed_decr = sextract64(decr, 0, nr_bits);
+
+diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c
+index fcbe4c5837..ec8d9584fb 100644
+--- a/hw/ppc/prep.c
++++ b/hw/ppc/prep.c
+@@ -271,9 +271,11 @@ static void ibm_40p_init(MachineState *machine)
+ }
+
+ /* PCI -> ISA bridge */
+- i82378_dev = DEVICE(pci_create_simple(pci_bus, PCI_DEVFN(11, 0), "i82378"));
++ i82378_dev = DEVICE(pci_new(PCI_DEVFN(11, 0), "i82378"));
+ qdev_connect_gpio_out(i82378_dev, 0,
+ qdev_get_gpio_in(DEVICE(cpu), PPC6xx_INPUT_INT));
++ qdev_realize_and_unref(i82378_dev, BUS(pci_bus), &error_fatal);
++
+ sysbus_connect_irq(pcihost, 0, qdev_get_gpio_in(i82378_dev, 15));
+ isa_bus = ISA_BUS(qdev_get_child_bus(i82378_dev, "isa.0"));
+
+diff --git a/hw/remote/trace-events b/hw/remote/trace-events
+index c167b3c7a5..0d1b7d56a5 100644
+--- a/hw/remote/trace-events
++++ b/hw/remote/trace-events
+@@ -5,8 +5,8 @@ mpqemu_recv_io_error(int cmd, int size, int nfds) "failed to receive %d size %d,
+
+ # vfio-user-obj.c
+ vfu_prop(const char *prop, const char *val) "vfu: setting %s as %s"
+-vfu_cfg_read(uint32_t offset, uint32_t val) "vfu: cfg: 0x%u -> 0x%x"
+-vfu_cfg_write(uint32_t offset, uint32_t val) "vfu: cfg: 0x%u <- 0x%x"
++vfu_cfg_read(uint32_t offset, uint32_t val) "vfu: cfg: 0x%x -> 0x%x"
++vfu_cfg_write(uint32_t offset, uint32_t val) "vfu: cfg: 0x%x <- 0x%x"
+ vfu_dma_register(uint64_t gpa, size_t len) "vfu: registering GPA 0x%"PRIx64", %zu bytes"
+ vfu_dma_unregister(uint64_t gpa) "vfu: unregistering GPA 0x%"PRIx64""
+ vfu_bar_register(int i, uint64_t addr, uint64_t size) "vfu: BAR %d: addr 0x%"PRIx64" size 0x%"PRIx64""
+diff --git a/hw/riscv/numa.c b/hw/riscv/numa.c
+index 7fe92d402f..edf6750f54 100644
+--- a/hw/riscv/numa.c
++++ b/hw/riscv/numa.c
+@@ -207,6 +207,12 @@ int64_t riscv_numa_get_default_cpu_node_id(const MachineState *ms, int idx)
+ {
+ int64_t nidx = 0;
+
++ if (ms->numa_state->num_nodes > ms->smp.cpus) {
++ error_report("Number of NUMA nodes (%d)"
++ " cannot exceed the number of available CPUs (%d).",
++ ms->numa_state->num_nodes, ms->smp.max_cpus);
++ exit(EXIT_FAILURE);
++ }
+ if (ms->numa_state->num_nodes) {
+ nidx = idx / (ms->smp.cpus / ms->numa_state->num_nodes);
+ if (ms->numa_state->num_nodes <= nidx) {
+diff --git a/hw/timer/nrf51_timer.c b/hw/timer/nrf51_timer.c
+index 42be79c736..50c6772383 100644
+--- a/hw/timer/nrf51_timer.c
++++ b/hw/timer/nrf51_timer.c
+@@ -45,7 +45,12 @@ static uint32_t update_counter(NRF51TimerState *s, int64_t now)
+ uint32_t ticks = ns_to_ticks(s, now - s->update_counter_ns);
+
+ s->counter = (s->counter + ticks) % BIT(bitwidths[s->bitmode]);
+- s->update_counter_ns = now;
++ /*
++ * Only advance the sync time to the timestamp of the last tick,
++ * not all the way to 'now', so we don't lose time if we do
++ * multiple resyncs in a single tick.
++ */
++ s->update_counter_ns += ticks_to_ns(s, ticks);
+ return ticks;
+ }
+
+diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
+index 939dcc3d4a..92a45de4c3 100644
+--- a/hw/vfio/pci.c
++++ b/hw/vfio/pci.c
+@@ -663,6 +663,8 @@ static void vfio_msi_enable(VFIOPCIDevice *vdev)
+
+ vfio_disable_interrupts(vdev);
+
++ vdev->nr_vectors = msi_nr_vectors_allocated(&vdev->pdev);
++retry:
+ /*
+ * Setting vector notifiers needs to enable route for each vector.
+ * Deferring to commit the KVM routes once rather than per vector
+@@ -670,8 +672,6 @@ static void vfio_msi_enable(VFIOPCIDevice *vdev)
+ */
+ vfio_prepare_kvm_msi_virq_batch(vdev);
+
+- vdev->nr_vectors = msi_nr_vectors_allocated(&vdev->pdev);
+-retry:
+ vdev->msi_vectors = g_new0(VFIOMSIVector, vdev->nr_vectors);
+
+ for (i = 0; i < vdev->nr_vectors; i++) {
+@@ -3159,7 +3159,9 @@ static void vfio_realize(PCIDevice *pdev, Error **errp)
+
+ out_deregister:
+ pci_device_set_intx_routing_notifier(&vdev->pdev, NULL);
+- kvm_irqchip_remove_change_notifier(&vdev->irqchip_change_notifier);
++ if (vdev->irqchip_change_notifier.notify) {
++ kvm_irqchip_remove_change_notifier(&vdev->irqchip_change_notifier);
++ }
+ out_teardown:
+ vfio_teardown_msi(vdev);
+ vfio_bars_exit(vdev);
+diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
+index fdcd1a8fdf..f38997b3f6 100644
+--- a/hw/virtio/vhost.c
++++ b/hw/virtio/vhost.c
+@@ -1934,6 +1934,9 @@ fail_vq:
+ }
+
+ fail_mem:
++ if (vhost_dev_has_iommu(hdev)) {
++ memory_listener_unregister(&hdev->iommu_listener);
++ }
+ fail_features:
+ vdev->vhost_started = false;
+ hdev->started = false;
+diff --git a/include/qemu/compiler.h b/include/qemu/compiler.h
+index f20a76e4a2..c7ffcaba43 100644
+--- a/include/qemu/compiler.h
++++ b/include/qemu/compiler.h
+@@ -184,4 +184,17 @@
+ #define QEMU_DISABLE_CFI
+ #endif
+
++/*
++ * Apple clang version 14 has a bug in its __builtin_subcll(); define
++ * BUILTIN_SUBCLL_BROKEN for the offending versions so we can avoid it.
++ * When a version of Apple clang which has this bug fixed is released
++ * we can add an upper bound to this check.
++ * See https://gitlab.com/qemu-project/qemu/-/issues/1631
++ * and https://gitlab.com/qemu-project/qemu/-/issues/1659 for details.
++ * The bug never made it into any upstream LLVM releases, only Apple ones.
++ */
++#if defined(__apple_build_version__) && __clang_major__ >= 14
++#define BUILTIN_SUBCLL_BROKEN
++#endif
++
+ #endif /* COMPILER_H */
+diff --git a/include/qemu/host-utils.h b/include/qemu/host-utils.h
+index 88d476161c..b3434ec0bc 100644
+--- a/include/qemu/host-utils.h
++++ b/include/qemu/host-utils.h
+@@ -596,7 +596,7 @@ static inline uint64_t uadd64_carry(uint64_t x, uint64_t y, bool *pcarry)
+ */
+ static inline uint64_t usub64_borrow(uint64_t x, uint64_t y, bool *pborrow)
+ {
+-#if __has_builtin(__builtin_subcll)
++#if __has_builtin(__builtin_subcll) && !defined(BUILTIN_SUBCLL_BROKEN)
+ unsigned long long b = *pborrow;
+ x = __builtin_subcll(x, y, b, &b);
+ *pborrow = b & 1;
+diff --git a/linux-user/s390x/cpu_loop.c b/linux-user/s390x/cpu_loop.c
+index 285bc60071..8b7ac2879e 100644
+--- a/linux-user/s390x/cpu_loop.c
++++ b/linux-user/s390x/cpu_loop.c
+@@ -86,6 +86,15 @@ void cpu_loop(CPUS390XState *env)
+ } else if (ret != -QEMU_ESIGRETURN) {
+ env->regs[2] = ret;
+ }
++
++ if (unlikely(cs->singlestep_enabled)) {
++ /*
++ * cpu_tb_exec() did not raise EXCP_DEBUG, because it has seen
++ * that EXCP_SVC was already pending.
++ */
++ cs->exception_index = EXCP_DEBUG;
++ }
++
+ break;
+
+ case EXCP_DEBUG:
+diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c
+index 2b4b85d8f8..e533f8a348 100644
+--- a/net/vhost-vdpa.c
++++ b/net/vhost-vdpa.c
+@@ -49,6 +49,7 @@ const int vdpa_feature_bits[] = {
+ VIRTIO_F_VERSION_1,
+ VIRTIO_NET_F_CSUM,
+ VIRTIO_NET_F_GUEST_CSUM,
++ VIRTIO_NET_F_CTRL_GUEST_OFFLOADS,
+ VIRTIO_NET_F_GSO,
+ VIRTIO_NET_F_GUEST_TSO4,
+ VIRTIO_NET_F_GUEST_TSO6,
+@@ -160,6 +161,14 @@ static void vhost_vdpa_cleanup(NetClientState *nc)
+ VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc);
+ struct vhost_dev *dev = &s->vhost_net->dev;
+
++ /*
++ * If a peer NIC is attached, do not cleanup anything.
++ * Cleanup will happen as a part of qemu_cleanup() -> net_cleanup()
++ * when the guest is shutting down.
++ */
++ if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_NIC) {
++ return;
++ }
+ qemu_vfree(s->cvq_cmd_out_buffer);
+ qemu_vfree(s->status);
+ if (dev->vq_index + dev->nvqs == dev->vq_index_end) {
+@@ -500,7 +509,7 @@ static int vhost_vdpa_net_handle_ctrl_avail(VhostShadowVirtqueue *svq,
+ }
+
+ if (*s->status != VIRTIO_NET_OK) {
+- return VIRTIO_NET_ERR;
++ goto out;
+ }
+
+ status = VIRTIO_NET_ERR;
+diff --git a/pc-bios/keymaps/meson.build b/pc-bios/keymaps/meson.build
+index 06c75e646b..452395b962 100644
+--- a/pc-bios/keymaps/meson.build
++++ b/pc-bios/keymaps/meson.build
+@@ -1,5 +1,5 @@
+ keymaps = {
+- 'ar': '-l ar',
++ 'ar': '-l ara',
+ 'bepo': '-l fr -v dvorak',
+ 'cz': '-l cz',
+ 'da': '-l dk',
+diff --git a/qga/commands-posix.c b/qga/commands-posix.c
+index 32493d6383..182eba4a38 100644
+--- a/qga/commands-posix.c
++++ b/qga/commands-posix.c
+@@ -1925,10 +1925,10 @@ static void guest_suspend(SuspendMode mode, Error **errp)
+ if (systemd_supports_mode(mode, &local_err)) {
+ mode_supported = true;
+ systemd_suspend(mode, &local_err);
+- }
+
+- if (!local_err) {
+- return;
++ if (!local_err) {
++ return;
++ }
+ }
+
+ error_free(local_err);
+@@ -1937,10 +1937,10 @@ static void guest_suspend(SuspendMode mode, Error **errp)
+ if (pmutils_supports_mode(mode, &local_err)) {
+ mode_supported = true;
+ pmutils_suspend(mode, &local_err);
+- }
+
+- if (!local_err) {
+- return;
++ if (!local_err) {
++ return;
++ }
+ }
+
+ error_free(local_err);
+diff --git a/scripts/device-crash-test b/scripts/device-crash-test
+index 73bcb98693..b74d887331 100755
+--- a/scripts/device-crash-test
++++ b/scripts/device-crash-test
+@@ -397,7 +397,7 @@ def binariesToTest(args, testcase):
+
+
+ def accelsToTest(args, testcase):
+- if getBinaryInfo(args, testcase['binary']).kvm_available:
++ if getBinaryInfo(args, testcase['binary']).kvm_available and not args.tcg_only:
+ yield 'kvm'
+ yield 'tcg'
+
+@@ -510,6 +510,8 @@ def main():
+ help="Full mode: test cases that are expected to fail")
+ parser.add_argument('--strict', action='store_true', dest='strict',
+ help="Treat all warnings as fatal")
++ parser.add_argument('--tcg-only', action='store_true', dest='tcg_only',
++ help="Only test with TCG accelerator")
+ parser.add_argument('qemu', nargs='*', metavar='QEMU',
+ help='QEMU binary to run')
+ args = parser.parse_args()
+diff --git a/softmmu/icount.c b/softmmu/icount.c
+index 4504433e16..a5cef9c60a 100644
+--- a/softmmu/icount.c
++++ b/softmmu/icount.c
+@@ -259,11 +259,16 @@ static void icount_warp_rt(void)
+ warp_delta = clock - timers_state.vm_clock_warp_start;
+ if (icount_enabled() == 2) {
+ /*
+- * In adaptive mode, do not let QEMU_CLOCK_VIRTUAL run too
+- * far ahead of real time.
++ * In adaptive mode, do not let QEMU_CLOCK_VIRTUAL run too far
++ * ahead of real time (it might already be ahead so careful not
++ * to go backwards).
+ */
+ int64_t cur_icount = icount_get_locked();
+ int64_t delta = clock - cur_icount;
++
++ if (delta < 0) {
++ delta = 0;
++ }
+ warp_delta = MIN(warp_delta, delta);
+ }
+ qatomic_set_i64(&timers_state.qemu_icount_bias,
+diff --git a/target/arm/tlb_helper.c b/target/arm/tlb_helper.c
+index 0f4f4fc809..1384fe6f98 100644
+--- a/target/arm/tlb_helper.c
++++ b/target/arm/tlb_helper.c
+@@ -82,8 +82,17 @@ static uint32_t compute_fsr_fsc(CPUARMState *env, ARMMMUFaultInfo *fi,
+ ARMMMUIdx arm_mmu_idx = core_to_arm_mmu_idx(env, mmu_idx);
+ uint32_t fsr, fsc;
+
+- if (target_el == 2 || arm_el_is_aa64(env, target_el) ||
+- arm_s1_regime_using_lpae_format(env, arm_mmu_idx)) {
++ /*
++ * For M-profile there is no guest-facing FSR. We compute a
++ * short-form value for env->exception.fsr which we will then
++ * examine in arm_v7m_cpu_do_interrupt(). In theory we could
++ * use the LPAE format instead as long as both bits of code agree
++ * (and arm_fi_to_lfsc() handled the M-profile specific
++ * ARMFault_QEMU_NSCExec and ARMFault_QEMU_SFault cases).
++ */
++ if (!arm_feature(env, ARM_FEATURE_M) &&
++ (target_el == 2 || arm_el_is_aa64(env, target_el) ||
++ arm_s1_regime_using_lpae_format(env, arm_mmu_idx))) {
+ /*
+ * LPAE format fault status register : bottom 6 bits are
+ * status code in the same form as needed for syndrome
+diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
+index 2ee171f249..f0b8db7ce5 100644
+--- a/target/arm/translate-a64.c
++++ b/target/arm/translate-a64.c
+@@ -3536,8 +3536,22 @@ static void disas_ldst_atomic(DisasContext *s, uint32_t insn,
+ */
+ fn(tcg_rt, clean_addr, tcg_rs, get_mem_index(s), mop);
+
+- if ((mop & MO_SIGN) && size != MO_64) {
+- tcg_gen_ext32u_i64(tcg_rt, tcg_rt);
++ if (mop & MO_SIGN) {
++ switch (size) {
++ case MO_8:
++ tcg_gen_ext8u_i64(tcg_rt, tcg_rt);
++ break;
++ case MO_16:
++ tcg_gen_ext16u_i64(tcg_rt, tcg_rt);
++ break;
++ case MO_32:
++ tcg_gen_ext32u_i64(tcg_rt, tcg_rt);
++ break;
++ case MO_64:
++ break;
++ default:
++ g_assert_not_reached();
++ }
+ }
+ }
+
+@@ -4176,9 +4190,13 @@ static void disas_ldst_tag(DisasContext *s, uint32_t insn)
+ if (s->ata) {
+ gen_helper_ldg(tcg_rt, cpu_env, addr, tcg_rt);
+ } else {
++ /*
++ * Tag access disabled: we must check for aborts on the load
++ * load from [rn+offset], and then insert a 0 tag into rt.
++ */
+ clean_addr = clean_data_tbi(s, addr);
+ gen_probe_access(s, clean_addr, MMU_DATA_LOAD, MO_8);
+- gen_address_with_allocation_tag0(tcg_rt, addr);
++ gen_address_with_allocation_tag0(tcg_rt, tcg_rt);
+ }
+ } else {
+ tcg_rt = cpu_reg_sp(s, rt);
+diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
+index cbf0081374..294a18a5b7 100644
+--- a/target/ppc/cpu_init.c
++++ b/target/ppc/cpu_init.c
+@@ -7085,7 +7085,7 @@ static void ppc_cpu_reset(DeviceState *dev)
+ if (env->mmu_model != POWERPC_MMU_REAL) {
+ ppc_tlb_invalidate_all(env);
+ }
+- pmu_update_summaries(env);
++ pmu_mmcr01_updated(env);
+ }
+
+ /* clean any pending stop state */
+diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
+index 30bc2e6adf..6cf88f635a 100644
+--- a/target/ppc/excp_helper.c
++++ b/target/ppc/excp_helper.c
+@@ -1358,9 +1358,12 @@ static void powerpc_excp_books(PowerPCCPU *cpu, int excp)
+
+ /*
+ * We don't want to generate a Hypervisor Emulation Assistance
+- * Interrupt if we don't have HVB in msr_mask (PAPR mode).
++ * Interrupt if we don't have HVB in msr_mask (PAPR mode),
++ * unless running a nested-hv guest, in which case the L1
++ * kernel wants the interrupt.
+ */
+- if (excp == POWERPC_EXCP_HV_EMU && !(env->msr_mask & MSR_HVB)) {
++ if (excp == POWERPC_EXCP_HV_EMU && !(env->msr_mask & MSR_HVB) &&
++ !books_vhyp_handles_hv_excp(cpu)) {
+ excp = POWERPC_EXCP_PROGRAM;
+ }
+
+diff --git a/target/ppc/helper_regs.c b/target/ppc/helper_regs.c
+index c0aee5855b..e200091a23 100644
+--- a/target/ppc/helper_regs.c
++++ b/target/ppc/helper_regs.c
+@@ -46,6 +46,48 @@ void hreg_swap_gpr_tgpr(CPUPPCState *env)
+ env->tgpr[3] = tmp;
+ }
+
++static uint32_t hreg_compute_pmu_hflags_value(CPUPPCState *env)
++{
++ uint32_t hflags = 0;
++
++#if defined(TARGET_PPC64)
++ if (env->spr[SPR_POWER_MMCR0] & MMCR0_PMCC0) {
++ hflags |= 1 << HFLAGS_PMCC0;
++ }
++ if (env->spr[SPR_POWER_MMCR0] & MMCR0_PMCC1) {
++ hflags |= 1 << HFLAGS_PMCC1;
++ }
++ if (env->spr[SPR_POWER_MMCR0] & MMCR0_PMCjCE) {
++ hflags |= 1 << HFLAGS_PMCJCE;
++ }
++
++#ifndef CONFIG_USER_ONLY
++ if (env->pmc_ins_cnt) {
++ hflags |= 1 << HFLAGS_INSN_CNT;
++ }
++ if (env->pmc_ins_cnt & 0x1e) {
++ hflags |= 1 << HFLAGS_PMC_OTHER;
++ }
++#endif
++#endif
++
++ return hflags;
++}
++
++/* Mask of all PMU hflags */
++static uint32_t hreg_compute_pmu_hflags_mask(CPUPPCState *env)
++{
++ uint32_t hflags_mask = 0;
++#if defined(TARGET_PPC64)
++ hflags_mask |= 1 << HFLAGS_PMCC0;
++ hflags_mask |= 1 << HFLAGS_PMCC1;
++ hflags_mask |= 1 << HFLAGS_PMCJCE;
++ hflags_mask |= 1 << HFLAGS_INSN_CNT;
++ hflags_mask |= 1 << HFLAGS_PMC_OTHER;
++#endif
++ return hflags_mask;
++}
++
+ static uint32_t hreg_compute_hflags_value(CPUPPCState *env)
+ {
+ target_ulong msr = env->msr;
+@@ -103,30 +145,12 @@ static uint32_t hreg_compute_hflags_value(CPUPPCState *env)
+ if (env->spr[SPR_LPCR] & LPCR_HR) {
+ hflags |= 1 << HFLAGS_HR;
+ }
+- if (env->spr[SPR_POWER_MMCR0] & MMCR0_PMCC0) {
+- hflags |= 1 << HFLAGS_PMCC0;
+- }
+- if (env->spr[SPR_POWER_MMCR0] & MMCR0_PMCC1) {
+- hflags |= 1 << HFLAGS_PMCC1;
+- }
+- if (env->spr[SPR_POWER_MMCR0] & MMCR0_PMCjCE) {
+- hflags |= 1 << HFLAGS_PMCJCE;
+- }
+
+ #ifndef CONFIG_USER_ONLY
+ if (!env->has_hv_mode || (msr & (1ull << MSR_HV))) {
+ hflags |= 1 << HFLAGS_HV;
+ }
+
+-#if defined(TARGET_PPC64)
+- if (env->pmc_ins_cnt) {
+- hflags |= 1 << HFLAGS_INSN_CNT;
+- }
+- if (env->pmc_ins_cnt & 0x1e) {
+- hflags |= 1 << HFLAGS_PMC_OTHER;
+- }
+-#endif
+-
+ /*
+ * This is our encoding for server processors. The architecture
+ * specifies that there is no such thing as userspace with
+@@ -171,6 +195,8 @@ static uint32_t hreg_compute_hflags_value(CPUPPCState *env)
+ hflags |= dmmu_idx << HFLAGS_DMMU_IDX;
+ #endif
+
++ hflags |= hreg_compute_pmu_hflags_value(env);
++
+ return hflags | (msr & msr_mask);
+ }
+
+@@ -179,6 +205,17 @@ void hreg_compute_hflags(CPUPPCState *env)
+ env->hflags = hreg_compute_hflags_value(env);
+ }
+
++/*
++ * This can be used as a lighter-weight alternative to hreg_compute_hflags
++ * when PMU MMCR0 or pmc_ins_cnt changes. pmc_ins_cnt is changed by
++ * pmu_update_summaries.
++ */
++void hreg_update_pmu_hflags(CPUPPCState *env)
++{
++ env->hflags &= ~hreg_compute_pmu_hflags_mask(env);
++ env->hflags |= hreg_compute_pmu_hflags_value(env);
++}
++
+ #ifdef CONFIG_DEBUG_TCG
+ void cpu_get_tb_cpu_state(CPUPPCState *env, target_ulong *pc,
+ target_ulong *cs_base, uint32_t *flags)
+diff --git a/target/ppc/helper_regs.h b/target/ppc/helper_regs.h
+index 42f26870b9..8196c1346d 100644
+--- a/target/ppc/helper_regs.h
++++ b/target/ppc/helper_regs.h
+@@ -22,6 +22,7 @@
+
+ void hreg_swap_gpr_tgpr(CPUPPCState *env);
+ void hreg_compute_hflags(CPUPPCState *env);
++void hreg_update_pmu_hflags(CPUPPCState *env);
+ void cpu_interrupt_exittb(CPUState *cs);
+ int hreg_store_msr(CPUPPCState *env, target_ulong value, int alter_hv);
+
+diff --git a/target/ppc/machine.c b/target/ppc/machine.c
+index be6eb3d968..134b16c625 100644
+--- a/target/ppc/machine.c
++++ b/target/ppc/machine.c
+@@ -21,10 +21,6 @@ static void post_load_update_msr(CPUPPCState *env)
+ */
+ env->msr ^= env->msr_mask & ~((1ULL << MSR_TGPR) | MSR_HVB);
+ ppc_store_msr(env, msr);
+-
+- if (tcg_enabled()) {
+- pmu_update_summaries(env);
+- }
+ }
+
+ static int get_avr(QEMUFile *f, void *pv, size_t size,
+@@ -317,6 +313,10 @@ static int cpu_post_load(void *opaque, int version_id)
+
+ post_load_update_msr(env);
+
++ if (tcg_enabled()) {
++ pmu_mmcr01_updated(env);
++ }
++
+ return 0;
+ }
+
+diff --git a/target/ppc/power8-pmu.c b/target/ppc/power8-pmu.c
+index 1381072b9e..fccd011088 100644
+--- a/target/ppc/power8-pmu.c
++++ b/target/ppc/power8-pmu.c
+@@ -31,7 +31,11 @@ static bool pmc_has_overflow_enabled(CPUPPCState *env, int sprn)
+ return env->spr[SPR_POWER_MMCR0] & MMCR0_PMCjCE;
+ }
+
+-void pmu_update_summaries(CPUPPCState *env)
++/*
++ * Called after MMCR0 or MMCR1 changes to update pmc_ins_cnt and pmc_cyc_cnt.
++ * hflags must subsequently be updated.
++ */
++static void pmu_update_summaries(CPUPPCState *env)
+ {
+ target_ulong mmcr0 = env->spr[SPR_POWER_MMCR0];
+ target_ulong mmcr1 = env->spr[SPR_POWER_MMCR1];
+@@ -39,7 +43,7 @@ void pmu_update_summaries(CPUPPCState *env)
+ int cyc_cnt = 0;
+
+ if (mmcr0 & MMCR0_FC) {
+- goto hflags_calc;
++ goto out;
+ }
+
+ if (!(mmcr0 & MMCR0_FC14) && mmcr1 != 0) {
+@@ -73,10 +77,19 @@ void pmu_update_summaries(CPUPPCState *env)
+ ins_cnt |= !(mmcr0 & MMCR0_FC56) << 5;
+ cyc_cnt |= !(mmcr0 & MMCR0_FC56) << 6;
+
+- hflags_calc:
++ out:
+ env->pmc_ins_cnt = ins_cnt;
+ env->pmc_cyc_cnt = cyc_cnt;
+- env->hflags = deposit32(env->hflags, HFLAGS_INSN_CNT, 1, ins_cnt != 0);
++}
++
++void pmu_mmcr01_updated(CPUPPCState *env)
++{
++ pmu_update_summaries(env);
++ hreg_update_pmu_hflags(env);
++ /*
++ * Should this update overflow timers (if mmcr0 is updated) so they
++ * get set in cpu_post_load?
++ */
+ }
+
+ static bool pmu_increment_insns(CPUPPCState *env, uint32_t num_insns)
+@@ -234,18 +247,11 @@ static void pmu_delete_timers(CPUPPCState *env)
+
+ void helper_store_mmcr0(CPUPPCState *env, target_ulong value)
+ {
+- bool hflags_pmcc0 = (value & MMCR0_PMCC0) != 0;
+- bool hflags_pmcc1 = (value & MMCR0_PMCC1) != 0;
+-
+ pmu_update_cycles(env);
+
+ env->spr[SPR_POWER_MMCR0] = value;
+
+- /* MMCR0 writes can change HFLAGS_PMCC[01] and HFLAGS_INSN_CNT */
+- env->hflags = deposit32(env->hflags, HFLAGS_PMCC0, 1, hflags_pmcc0);
+- env->hflags = deposit32(env->hflags, HFLAGS_PMCC1, 1, hflags_pmcc1);
+-
+- pmu_update_summaries(env);
++ pmu_mmcr01_updated(env);
+
+ /* Update cycle overflow timers with the current MMCR0 state */
+ pmu_update_overflow_timers(env);
+@@ -257,8 +263,7 @@ void helper_store_mmcr1(CPUPPCState *env, uint64_t value)
+
+ env->spr[SPR_POWER_MMCR1] = value;
+
+- /* MMCR1 writes can change HFLAGS_INSN_CNT */
+- pmu_update_summaries(env);
++ pmu_mmcr01_updated(env);
+ }
+
+ target_ulong helper_read_pmc(CPUPPCState *env, uint32_t sprn)
+@@ -287,8 +292,8 @@ static void fire_PMC_interrupt(PowerPCCPU *cpu)
+ env->spr[SPR_POWER_MMCR0] &= ~MMCR0_FCECE;
+ env->spr[SPR_POWER_MMCR0] |= MMCR0_FC;
+
+- /* Changing MMCR0_FC requires a new HFLAGS_INSN_CNT calc */
+- pmu_update_summaries(env);
++ /* Changing MMCR0_FC requires summaries and hflags update */
++ pmu_mmcr01_updated(env);
+
+ /*
+ * Delete all pending timers if we need to freeze
+@@ -299,6 +304,7 @@ static void fire_PMC_interrupt(PowerPCCPU *cpu)
+ }
+
+ if (env->spr[SPR_POWER_MMCR0] & MMCR0_PMAE) {
++ /* These MMCR0 bits do not require summaries or hflags update. */
+ env->spr[SPR_POWER_MMCR0] &= ~MMCR0_PMAE;
+ env->spr[SPR_POWER_MMCR0] |= MMCR0_PMAO;
+ }
+diff --git a/target/ppc/power8-pmu.h b/target/ppc/power8-pmu.h
+index c0093e2219..775e640053 100644
+--- a/target/ppc/power8-pmu.h
++++ b/target/ppc/power8-pmu.h
+@@ -18,10 +18,10 @@
+ #define PMC_COUNTER_NEGATIVE_VAL 0x80000000UL
+
+ void cpu_ppc_pmu_init(CPUPPCState *env);
+-void pmu_update_summaries(CPUPPCState *env);
++void pmu_mmcr01_updated(CPUPPCState *env);
+ #else
+ static inline void cpu_ppc_pmu_init(CPUPPCState *env) { }
+-static inline void pmu_update_summaries(CPUPPCState *env) { }
++static inline void pmu_mmcr01_updated(CPUPPCState *env) { }
+ #endif
+
+ #endif
+diff --git a/target/ppc/translate.c b/target/ppc/translate.c
+index 19c1d17cb0..1de7eca9c4 100644
+--- a/target/ppc/translate.c
++++ b/target/ppc/translate.c
+@@ -3972,6 +3972,7 @@ static void gen_lqarx(DisasContext *ctx)
+ }
+ tcg_temp_free(EA);
+
++ tcg_gen_mov_tl(cpu_reserve, EA);
+ tcg_gen_st_tl(hi, cpu_env, offsetof(CPUPPCState, reserve_val));
+ tcg_gen_st_tl(lo, cpu_env, offsetof(CPUPPCState, reserve_val2));
+ }
+diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c
+index c3a4f80633..a85c56b4ee 100644
+--- a/target/s390x/cpu_models.c
++++ b/target/s390x/cpu_models.c
+@@ -604,8 +604,8 @@ void s390_realize_cpu_model(CPUState *cs, Error **errp)
+ #if !defined(CONFIG_USER_ONLY)
+ cpu->env.cpuid = s390_cpuid_from_cpu_model(cpu->model);
+ if (tcg_enabled()) {
+- /* basic mode, write the cpu address into the first 4 bit of the ID */
+- cpu->env.cpuid = deposit64(cpu->env.cpuid, 54, 4, cpu->env.core_id);
++ cpu->env.cpuid = deposit64(cpu->env.cpuid, CPU_PHYS_ADDR_SHIFT,
++ CPU_PHYS_ADDR_BITS, cpu->env.core_id);
+ }
+ #endif
+ }
+diff --git a/target/s390x/cpu_models.h b/target/s390x/cpu_models.h
+index fb1adc8b21..cc7305ec21 100644
+--- a/target/s390x/cpu_models.h
++++ b/target/s390x/cpu_models.h
+@@ -96,10 +96,18 @@ static inline bool s390_known_cpu_type(uint16_t type)
+ {
+ return s390_get_gen_for_cpu_type(type) != 0;
+ }
++#define CPU_ID_SHIFT 32
++#define CPU_ID_BITS 24
++/*
++ * When cpu_id_format is 0 (basic mode), the leftmost 4 bits of cpu_id contain
++ * the rightmost 4 bits of the physical CPU address.
++ */
++#define CPU_PHYS_ADDR_BITS 4
++#define CPU_PHYS_ADDR_SHIFT (CPU_ID_SHIFT + CPU_ID_BITS - CPU_PHYS_ADDR_BITS)
+ static inline uint64_t s390_cpuid_from_cpu_model(const S390CPUModel *model)
+ {
+ return ((uint64_t)model->cpu_ver << 56) |
+- ((uint64_t)model->cpu_id << 32) |
++ ((uint64_t)model->cpu_id << CPU_ID_SHIFT) |
+ ((uint64_t)model->def->type << 16) |
+ (model->def->gen == 7 ? 0 : (uint64_t)model->cpu_id_format << 15);
+ }
+diff --git a/target/s390x/tcg/insn-data.h.inc b/target/s390x/tcg/insn-data.h.inc
+index 13ffdda4da..4249632af3 100644
+--- a/target/s390x/tcg/insn-data.h.inc
++++ b/target/s390x/tcg/insn-data.h.inc
+@@ -486,7 +486,7 @@
+ F(0xb343, LCXBR, RRE, Z, x2h, x2l, new_P, x1, negf128, f128, IF_BFP)
+ F(0xb373, LCDFR, RRE, FPSSH, 0, f2, new, f1, negf64, 0, IF_AFP1 | IF_AFP2)
+ /* LOAD COUNT TO BLOCK BOUNDARY */
+- C(0xe727, LCBB, RXE, V, la2, 0, r1, 0, lcbb, 0)
++ C(0xe727, LCBB, RXE, V, la2, 0, new, r1_32, lcbb, 0)
+ /* LOAD HALFWORD */
+ C(0xb927, LHR, RRE, EI, 0, r2_16s, 0, r1_32, mov2, 0)
+ C(0xb907, LGHR, RRE, EI, 0, r2_16s, 0, r1, mov2, 0)
+@@ -564,7 +564,7 @@
+ C(0xec46, LOCGHI, RIE_g, LOC2, r1, i2, r1, 0, loc, 0)
+ C(0xec4e, LOCHHI, RIE_g, LOC2, r1_sr32, i2, new, r1_32h, loc, 0)
+ /* LOAD HIGH ON CONDITION */
+- C(0xb9e0, LOCFHR, RRF_c, LOC2, r1_sr32, r2, new, r1_32h, loc, 0)
++ C(0xb9e0, LOCFHR, RRF_c, LOC2, r1_sr32, r2_sr32, new, r1_32h, loc, 0)
+ C(0xebe0, LOCFH, RSY_b, LOC2, r1_sr32, m2_32u, new, r1_32h, loc, 0)
+ /* LOAD PAIR DISJOINT */
+ D(0xc804, LPD, SSF, ILA, 0, 0, new_P, r3_P32, lpd, 0, MO_TEUL)
+diff --git a/tests/tcg/s390x/Makefile.target b/tests/tcg/s390x/Makefile.target
+index 07fcc6d0ce..cb90d4183d 100644
+--- a/tests/tcg/s390x/Makefile.target
++++ b/tests/tcg/s390x/Makefile.target
+@@ -26,6 +26,8 @@ TESTS+=branch-relative-long
+ TESTS+=noexec
+
+ Z13_TESTS=vistr
++Z13_TESTS+=lcbb
++Z13_TESTS+=locfhr
+ $(Z13_TESTS): CFLAGS+=-march=z13 -O2
+ TESTS+=$(Z13_TESTS)
+
+@@ -54,7 +56,16 @@ run-gdbstub-signals-s390x: signals-s390x
+ --bin $< --test $(S390X_SRC)/gdbstub/test-signals-s390x.py, \
+ mixing signals and debugging)
+
+-EXTRA_RUNS += run-gdbstub-signals-s390x
++hello-s390x-asm: CFLAGS+=-nostdlib
++
++run-gdbstub-svc: hello-s390x-asm
++ $(call run-test, $@, $(GDB_SCRIPT) \
++ --gdb $(HAVE_GDB_BIN) \
++ --qemu $(QEMU) --qargs "$(QEMU_OPTS)" \
++ --bin $< --test $(S390X_SRC)/gdbstub/test-svc.py, \
++ single-stepping svc)
++
++EXTRA_RUNS += run-gdbstub-signals-s390x run-gdbstub-svc
+ endif
+
+ # MVX versions of sha512
+diff --git a/tests/tcg/s390x/gdbstub/test-svc.py b/tests/tcg/s390x/gdbstub/test-svc.py
+new file mode 100644
+index 0000000000..7851ca7284
+--- /dev/null
++++ b/tests/tcg/s390x/gdbstub/test-svc.py
+@@ -0,0 +1,64 @@
++"""Test single-stepping SVC.
++
++This runs as a sourced script (via -x, via run-test.py)."""
++from __future__ import print_function
++import gdb
++import sys
++
++
++n_failures = 0
++
++
++def report(cond, msg):
++ """Report success/fail of a test"""
++ if cond:
++ print("PASS: {}".format(msg))
++ else:
++ print("FAIL: {}".format(msg))
++ global n_failures
++ n_failures += 1
++
++
++def run_test():
++ """Run through the tests one by one"""
++ report("lghi\t" in gdb.execute("x/i $pc", False, True), "insn #1")
++ gdb.execute("si")
++ report("larl\t" in gdb.execute("x/i $pc", False, True), "insn #2")
++ gdb.execute("si")
++ report("lghi\t" in gdb.execute("x/i $pc", False, True), "insn #3")
++ gdb.execute("si")
++ report("svc\t" in gdb.execute("x/i $pc", False, True), "insn #4")
++ gdb.execute("si")
++ report("xgr\t" in gdb.execute("x/i $pc", False, True), "insn #5")
++ gdb.execute("si")
++ report("svc\t" in gdb.execute("x/i $pc", False, True), "insn #6")
++ gdb.execute("si")
++
++
++def main():
++ """Prepare the environment and run through the tests"""
++ try:
++ inferior = gdb.selected_inferior()
++ print("ATTACHED: {}".format(inferior.architecture().name()))
++ except (gdb.error, AttributeError):
++ print("SKIPPING (not connected)")
++ exit(0)
++
++ if gdb.parse_and_eval('$pc') == 0:
++ print("SKIP: PC not set")
++ exit(0)
++
++ try:
++ # These are not very useful in scripts
++ gdb.execute("set pagination off")
++ gdb.execute("set confirm off")
++
++ # Run the actual tests
++ run_test()
++ except gdb.error:
++ report(False, "GDB Exception: {}".format(sys.exc_info()[0]))
++ print("All tests complete: %d failures" % n_failures)
++ exit(n_failures)
++
++
++main()
+diff --git a/tests/tcg/s390x/hello-s390x-asm.S b/tests/tcg/s390x/hello-s390x-asm.S
+new file mode 100644
+index 0000000000..2e9faa1604
+--- /dev/null
++++ b/tests/tcg/s390x/hello-s390x-asm.S
+@@ -0,0 +1,20 @@
++/*
++ * Hello, World! in assembly.
++ */
++
++.globl _start
++_start:
++
++/* puts("Hello, World!"); */
++lghi %r2,1
++larl %r3,foo
++lghi %r4,foo_end-foo
++svc 4
++
++/* exit(0); */
++xgr %r2,%r2
++svc 1
++
++.align 2
++foo: .asciz "Hello, World!\n"
++foo_end:
+diff --git a/tests/tcg/s390x/lcbb.c b/tests/tcg/s390x/lcbb.c
+new file mode 100644
+index 0000000000..8d368e0998
+--- /dev/null
++++ b/tests/tcg/s390x/lcbb.c
+@@ -0,0 +1,51 @@
++/*
++ * Test the LCBB instruction.
++ *
++ * SPDX-License-Identifier: GPL-2.0-or-later
++ */
++#include <assert.h>
++#include <stdlib.h>
++
++static inline __attribute__((__always_inline__)) void
++lcbb(long *r1, void *dxb2, int m3, int *cc)
++{
++ asm("lcbb %[r1],%[dxb2],%[m3]\n"
++ "ipm %[cc]"
++ : [r1] "+r" (*r1), [cc] "=r" (*cc)
++ : [dxb2] "R" (*(char *)dxb2), [m3] "i" (m3)
++ : "cc");
++ *cc = (*cc >> 28) & 3;
++}
++
++static char buf[0x1000] __attribute__((aligned(0x1000)));
++
++static inline __attribute__((__always_inline__)) void
++test_lcbb(void *p, int m3, int exp_r1, int exp_cc)
++{
++ long r1 = 0xfedcba9876543210;
++ int cc;
++
++ lcbb(&r1, p, m3, &cc);
++ assert(r1 == (0xfedcba9800000000 | exp_r1));
++ assert(cc == exp_cc);
++}
++
++int main(void)
++{
++ test_lcbb(&buf[0], 0, 16, 0);
++ test_lcbb(&buf[63], 0, 1, 3);
++ test_lcbb(&buf[0], 1, 16, 0);
++ test_lcbb(&buf[127], 1, 1, 3);
++ test_lcbb(&buf[0], 2, 16, 0);
++ test_lcbb(&buf[255], 2, 1, 3);
++ test_lcbb(&buf[0], 3, 16, 0);
++ test_lcbb(&buf[511], 3, 1, 3);
++ test_lcbb(&buf[0], 4, 16, 0);
++ test_lcbb(&buf[1023], 4, 1, 3);
++ test_lcbb(&buf[0], 5, 16, 0);
++ test_lcbb(&buf[2047], 5, 1, 3);
++ test_lcbb(&buf[0], 6, 16, 0);
++ test_lcbb(&buf[4095], 6, 1, 3);
++
++ return EXIT_SUCCESS;
++}
+diff --git a/tests/tcg/s390x/locfhr.c b/tests/tcg/s390x/locfhr.c
+new file mode 100644
+index 0000000000..ab9ff6e449
+--- /dev/null
++++ b/tests/tcg/s390x/locfhr.c
+@@ -0,0 +1,29 @@
++/*
++ * Test the LOCFHR instruction.
++ *
++ * SPDX-License-Identifier: GPL-2.0-or-later
++ */
++#include <assert.h>
++#include <stdlib.h>
++
++static inline __attribute__((__always_inline__)) long
++locfhr(long r1, long r2, int m3, int cc)
++{
++ cc <<= 28;
++ asm("spm %[cc]\n"
++ "locfhr %[r1],%[r2],%[m3]\n"
++ : [r1] "+r" (r1)
++ : [cc] "r" (cc), [r2] "r" (r2), [m3] "i" (m3)
++ : "cc");
++ return r1;
++}
++
++int main(void)
++{
++ assert(locfhr(0x1111111122222222, 0x3333333344444444, 8, 0) ==
++ 0x3333333322222222);
++ assert(locfhr(0x5555555566666666, 0x7777777788888888, 11, 1) ==
++ 0x5555555566666666);
++
++ return EXIT_SUCCESS;
++}
+diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c
+index e84431790c..e99e3b0d8c 100644
+--- a/ui/gtk-egl.c
++++ b/ui/gtk-egl.c
+@@ -88,8 +88,8 @@ void gd_egl_draw(VirtualConsole *vc)
+ #endif
+ gd_egl_scanout_flush(&vc->gfx.dcl, 0, 0, vc->gfx.w, vc->gfx.h);
+
+- vc->gfx.scale_x = (double)ww / vc->gfx.w;
+- vc->gfx.scale_y = (double)wh / vc->gfx.h;
++ vc->gfx.scale_x = (double)ww / surface_width(vc->gfx.ds);
++ vc->gfx.scale_y = (double)wh / surface_height(vc->gfx.ds);
+
+ glFlush();
+ #ifdef CONFIG_GBM
+@@ -256,8 +256,9 @@ void gd_egl_scanout_dmabuf(DisplayChangeListener *dcl,
+ }
+
+ gd_egl_scanout_texture(dcl, dmabuf->texture,
+- false, dmabuf->width, dmabuf->height,
+- 0, 0, dmabuf->width, dmabuf->height);
++ dmabuf->y0_top, dmabuf->width, dmabuf->height,
++ dmabuf->x, dmabuf->y, dmabuf->scanout_width,
++ dmabuf->scanout_height);
+
+ if (dmabuf->allow_fences) {
+ vc->gfx.guest_fb.dmabuf = dmabuf;
+diff --git a/ui/gtk-gl-area.c b/ui/gtk-gl-area.c
+index 7696df1f6b..1605818bd1 100644
+--- a/ui/gtk-gl-area.c
++++ b/ui/gtk-gl-area.c
+@@ -298,8 +298,9 @@ void gd_gl_area_scanout_dmabuf(DisplayChangeListener *dcl,
+ }
+
+ gd_gl_area_scanout_texture(dcl, dmabuf->texture,
+- false, dmabuf->width, dmabuf->height,
+- 0, 0, dmabuf->width, dmabuf->height);
++ dmabuf->y0_top, dmabuf->width, dmabuf->height,
++ dmabuf->x, dmabuf->y, dmabuf->scanout_width,
++ dmabuf->scanout_height);
+
+ if (dmabuf->allow_fences) {
+ vc->gfx.guest_fb.dmabuf = dmabuf;
+diff --git a/ui/gtk.c b/ui/gtk.c
+index dfaf6d33c3..e681e8c319 100644
+--- a/ui/gtk.c
++++ b/ui/gtk.c
+@@ -868,7 +868,6 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion,
+ {
+ VirtualConsole *vc = opaque;
+ GtkDisplayState *s = vc->s;
+- GdkWindow *window;
+ int x, y;
+ int mx, my;
+ int fbh, fbw;
+@@ -881,10 +880,9 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion,
+ fbw = surface_width(vc->gfx.ds) * vc->gfx.scale_x;
+ fbh = surface_height(vc->gfx.ds) * vc->gfx.scale_y;
+
+- window = gtk_widget_get_window(vc->gfx.drawing_area);
+- ww = gdk_window_get_width(window);
+- wh = gdk_window_get_height(window);
+- ws = gdk_window_get_scale_factor(window);
++ ww = gtk_widget_get_allocated_width(widget);
++ wh = gtk_widget_get_allocated_height(widget);
++ ws = gtk_widget_get_scale_factor(widget);
+
+ mx = my = 0;
+ if (ww > fbw) {
+diff --git a/ui/sdl2-gl.c b/ui/sdl2-gl.c
+index 39cab8cde7..bbfa70eac3 100644
+--- a/ui/sdl2-gl.c
++++ b/ui/sdl2-gl.c
+@@ -67,6 +67,10 @@ void sdl2_gl_update(DisplayChangeListener *dcl,
+
+ assert(scon->opengl);
+
++ if (!scon->real_window) {
++ return;
++ }
++
+ SDL_GL_MakeCurrent(scon->real_window, scon->winctx);
+ surface_gl_update_texture(scon->gls, scon->surface, x, y, w, h);
+ scon->updates++;
+diff --git a/ui/sdl2.c b/ui/sdl2.c
+index 8cb77416af..d630459b78 100644
+--- a/ui/sdl2.c
++++ b/ui/sdl2.c
+@@ -849,7 +849,14 @@ static void sdl2_display_init(DisplayState *ds, DisplayOptions *o)
+ #ifdef SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR /* only available since SDL 2.0.8 */
+ SDL_SetHint(SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR, "0");
+ #endif
++#ifndef CONFIG_WIN32
++ /* QEMU uses its own low level keyboard hook procecure on Windows */
+ SDL_SetHint(SDL_HINT_GRAB_KEYBOARD, "1");
++#endif
++#ifdef SDL_HINT_ALLOW_ALT_TAB_WHILE_GRABBED
++ SDL_SetHint(SDL_HINT_ALLOW_ALT_TAB_WHILE_GRABBED, "0");
++#endif
++ SDL_SetHint(SDL_HINT_WINDOWS_NO_CLOSE_ON_ALT_F4, "1");
+ memset(&info, 0, sizeof(info));
+ SDL_VERSION(&info.version);
+
+diff --git a/ui/vnc-jobs.c b/ui/vnc-jobs.c
+index 886f9bf611..fcca7ec632 100644
+--- a/ui/vnc-jobs.c
++++ b/ui/vnc-jobs.c
+@@ -250,12 +250,13 @@ static int vnc_worker_thread_loop(VncJobQueue *queue)
+ /* Here job can only be NULL if queue->exit is true */
+ job = QTAILQ_FIRST(&queue->jobs);
+ vnc_unlock_queue(queue);
+- assert(job->vs->magic == VNC_MAGIC);
+
+ if (queue->exit) {
+ return -1;
+ }
+
++ assert(job->vs->magic == VNC_MAGIC);
++
+ vnc_lock_output(job->vs);
+ if (job->vs->ioc == NULL || job->vs->abort == true) {
+ vnc_unlock_output(job->vs);