From 361f29fe1bc6c847b108442d573fcd2690d6db4b Mon Sep 17 00:00:00 2001 From: Christian Schoenebeck Date: Fri, 6 Dec 2024 12:20:29 +0100 Subject: [PATCH 01/58] 9pfs: fix regression regarding CVE-2023-2861 The released fix for this CVE: f6b0de53fb8 ("9pfs: prevent opening special files (CVE-2023-2861)") caused a regression with security_model=passthrough. When handling a 'Tmknod' request there was a side effect that 'Tmknod' request could fail as 9p server was trying to adjust permissions: #6 close_if_special_file (fd=30) at ../hw/9pfs/9p-util.h:140 #7 openat_file (mode=, flags=2228224, name=, dirfd=) at ../hw/9pfs/9p-util.h:181 #8 fchmodat_nofollow (dirfd=dirfd@entry=31, name=name@entry=0x5555577ea6e0 "mysocket", mode=493) at ../hw/9pfs/9p-local.c:360 #9 local_set_cred_passthrough (credp=0x7ffbbc4ace10, name=0x5555577ea6e0 "mysocket", dirfd=31, fs_ctx=0x55555811f528) at ../hw/9pfs/9p-local.c:457 #10 local_mknod (fs_ctx=0x55555811f528, dir_path=, name=0x5555577ea6e0 "mysocket", credp=0x7ffbbc4ace10) at ../hw/9pfs/9p-local.c:702 #11 v9fs_co_mknod (pdu=pdu@entry=0x555558121140, fidp=fidp@entry=0x5555574c46c0, name=name@entry=0x7ffbbc4aced0, uid=1000, gid=1000, dev=, mode=49645, stbuf=0x7ffbbc4acef0) at ../hw/9pfs/cofs.c:205 #12 v9fs_mknod (opaque=0x555558121140) at ../hw/9pfs/9p.c:3711 That's because server was opening the special file to adjust permissions, however it was using O_PATH and it would have not returned the file descriptor to guest. So the call to close_if_special_file() on that branch was incorrect. Let's lift the restriction introduced by f6b0de53fb8 such that it would allow to open special files on host if O_PATH flag is supplied, not only for 9p server's own operations as described above, but also for any client 'Topen' request. It is safe to allow opening special files with O_PATH on host, because O_PATH only allows path based operations on the resulting file descriptor and prevents I/O such as read() and write() on that file descriptor. Fixes: f6b0de53fb8 ("9pfs: prevent opening special files (CVE-2023-2861)") Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2337 Reported-by: Dirk Herrendorfer Signed-off-by: Christian Schoenebeck Reviewed-by: Greg Kurz Tested-by: Dirk Herrendorfer Message-Id: (cherry picked from commit d06a9d843fb65351e0e4dc42ba0c404f01ea92b3) Signed-off-by: Michael Tokarev --- hw/9pfs/9p-util.h | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/hw/9pfs/9p-util.h b/hw/9pfs/9p-util.h index 51c94b0116..95ee4da9bd 100644 --- a/hw/9pfs/9p-util.h +++ b/hw/9pfs/9p-util.h @@ -177,20 +177,27 @@ 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() - * ignored it anyway. - */ + /* Only if O_PATH is not set ... */ if (!(flags & O_PATH_9P_UTIL)) { + /* + * Prevent I/O on special files (device files, etc.) on host side, + * however it is safe and required to allow opening them with O_PATH, + * as this is limited to (required) path based operations only. + */ + 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() ignored it anyway. + */ ret = fcntl(fd, F_SETFL, flags); assert(!ret); + errno = serrno; } - errno = serrno; return fd; } From f838a7e3659b1066e5b39be09b499d637d084758 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 7 Dec 2024 18:14:45 +0000 Subject: [PATCH 02/58] tcg: Reset free_temps before tcg_optimize MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When allocating new temps during tcg_optmize, do not re-use any EBB temps that were used within the TB. We do not have any idea what span of the TB in which the temp was live. Introduce tcg_temp_ebb_reset_freed and use before tcg_optimize, as well as replacing the equivalent in plugin_gen_inject and tcg_func_start. Cc: qemu-stable@nongnu.org Fixes: fb04ab7ddd8 ("tcg/optimize: Lower TCG_COND_TST{EQ,NE} if unsupported") Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2711 Reported-by: wannacu Signed-off-by: Richard Henderson Reviewed-by: Pierrick Bouvier Reviewed-by: Philippe Mathieu-Daudé (cherry picked from commit 04e006ab36a8565b92d4e21dd346367fbade7d74) Signed-off-by: Michael Tokarev --- accel/tcg/plugin-gen.c | 2 +- include/tcg/tcg-temp-internal.h | 6 ++++++ tcg/tcg.c | 5 ++++- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/accel/tcg/plugin-gen.c b/accel/tcg/plugin-gen.c index 0f47bfbb48..1ef075552c 100644 --- a/accel/tcg/plugin-gen.c +++ b/accel/tcg/plugin-gen.c @@ -275,7 +275,7 @@ static void plugin_gen_inject(struct qemu_plugin_tb *plugin_tb) * that might be live within the existing opcode stream. * The simplest solution is to release them all and create new. */ - memset(tcg_ctx->free_temps, 0, sizeof(tcg_ctx->free_temps)); + tcg_temp_ebb_reset_freed(tcg_ctx); QTAILQ_FOREACH_SAFE(op, &tcg_ctx->ops, link, next) { switch (op->opc) { diff --git a/include/tcg/tcg-temp-internal.h b/include/tcg/tcg-temp-internal.h index 44192c55a9..98f91e68b7 100644 --- a/include/tcg/tcg-temp-internal.h +++ b/include/tcg/tcg-temp-internal.h @@ -42,4 +42,10 @@ TCGv_i64 tcg_temp_ebb_new_i64(void); TCGv_ptr tcg_temp_ebb_new_ptr(void); TCGv_i128 tcg_temp_ebb_new_i128(void); +/* Forget all freed EBB temps, so that new allocations produce new temps. */ +static inline void tcg_temp_ebb_reset_freed(TCGContext *s) +{ + memset(s->free_temps, 0, sizeof(s->free_temps)); +} + #endif /* TCG_TEMP_FREE_H */ diff --git a/tcg/tcg.c b/tcg/tcg.c index 0babae1b88..4578b185be 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1489,7 +1489,7 @@ void tcg_func_start(TCGContext *s) s->nb_temps = s->nb_globals; /* No temps have been previously allocated for size or locality. */ - memset(s->free_temps, 0, sizeof(s->free_temps)); + tcg_temp_ebb_reset_freed(s); /* No constant temps have been previously allocated. */ for (int i = 0; i < TCG_TYPE_COUNT; ++i) { @@ -6120,6 +6120,9 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb, uint64_t pc_start) } #endif + /* Do not reuse any EBB that may be allocated within the TB. */ + tcg_temp_ebb_reset_freed(s); + tcg_optimize(s); reachable_code_pass(s); From 242376e87245daf9e8811c8a161549c019f5933c Mon Sep 17 00:00:00 2001 From: Roman Artemev Date: Wed, 11 Dec 2024 07:40:04 +0000 Subject: [PATCH 03/58] tcg/riscv: Fix StoreStore barrier generation On RISC-V to StoreStore barrier corresponds `fence w, w` not `fence r, r` Cc: qemu-stable@nongnu.org Fixes: efbea94c76b ("tcg/riscv: Add slowpath load and store instructions") Reviewed-by: Richard Henderson Signed-off-by: Denis Tomashev Signed-off-by: Roman Artemev Message-ID: Signed-off-by: Richard Henderson (cherry picked from commit b438362a142527b97b638b7f0f35ebe11911a8d5) Signed-off-by: Michael Tokarev --- tcg/riscv/tcg-target.c.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index f8331e4688..96f9a7e348 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -1624,7 +1624,7 @@ static void tcg_out_mb(TCGContext *s, TCGArg a0) insn |= 0x02100000; } if (a0 & TCG_MO_ST_ST) { - insn |= 0x02200000; + insn |= 0x01100000; } tcg_out32(s, insn); } From 05e984c200a21a9f63d6c4f88b197d5d80b0a8fb Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 5 Sep 2024 16:12:07 +0200 Subject: [PATCH 04/58] x86/loader: only patch linux kernels If the binary loaded via -kernel is *not* a linux kernel (in which case protocol == 0), do not patch the linux kernel header fields. It's (a) pointless and (b) might break binaries by random patching and (c) changes the binary hash which in turn breaks secure boot verification. Background: OVMF happily loads and runs not only linux kernels but any efi binary via direct kernel boot. Note: Breaking the secure boot verification is a problem for linux kernels too, but fixed that is left for another day ... Signed-off-by: Gerd Hoffmann Message-ID: <20240905141211.1253307-3-kraxel@redhat.com> (cherry picked from commit 57e2cc9abf5da38f600354fe920ff20e719607b4) Signed-off-by: Michael Tokarev --- hw/i386/x86-common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/i386/x86-common.c b/hw/i386/x86-common.c index dc031af662..dadc9d99e7 100644 --- a/hw/i386/x86-common.c +++ b/hw/i386/x86-common.c @@ -945,7 +945,7 @@ void x86_load_linux(X86MachineState *x86ms, * kernel on the other side of the fw_cfg interface matches the hash of the * file the user passed in. */ - if (!sev_enabled()) { + if (!sev_enabled() && protocol > 0) { memcpy(setup, header, MIN(sizeof(header), setup_size)); } From 83daae51ee6afbd2b0d79ae5e6924d6c7a840eb4 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 12 Dec 2024 09:44:07 +0100 Subject: [PATCH 05/58] roms: re-add edk2-basetools target Needed to build ipxe nic roms. Reported-by: Liu Jaloo Fixes: 22e11539e167 ("edk2: replace build scripts") Signed-off-by: Gerd Hoffmann Message-ID: <20241212084408.1390728-1-kraxel@redhat.com> (cherry picked from commit 0f5715e4b5706b31b3550d8e6b88871e029c7823) Signed-off-by: Michael Tokarev --- roms/Makefile | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/roms/Makefile b/roms/Makefile index dfed2b216a..31e4b97c98 100644 --- a/roms/Makefile +++ b/roms/Makefile @@ -157,6 +157,11 @@ edk2-version: edk2 touch $@; \ fi +edk2-basetools: edk2-version + $(PYTHON) edk2-build.py --config edk2-build.config \ + --silent --no-logs \ + --match none # build only basetools + efi: edk2-version $(PYTHON) edk2-build.py --config edk2-build.config \ --version-override "$(EDK2_STABLE)$(FIRMWARE_EXTRAVERSION)" \ From fa232044a5b21da5721dd89c1d60509f7c9b109a Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 12 Dec 2024 10:00:59 +0100 Subject: [PATCH 06/58] pc-bios: add missing riscv64 descriptor Without descriptor libvirt cannot discover the EDK II binaries via the qemu:///system connection. Signed-off-by: Heinrich Schuchardt Message-ID: <20241212090059.94167-1-heinrich.schuchardt@canonical.com> Signed-off-by: Gerd Hoffmann (cherry picked from commit 74dc38d0c6c15fd57a5dee94125d13ac5b00491d) Signed-off-by: Michael Tokarev --- pc-bios/descriptors/60-edk2-riscv64.json | 31 ++++++++++++++++++++++++ pc-bios/descriptors/meson.build | 3 ++- 2 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 pc-bios/descriptors/60-edk2-riscv64.json diff --git a/pc-bios/descriptors/60-edk2-riscv64.json b/pc-bios/descriptors/60-edk2-riscv64.json new file mode 100644 index 0000000000..14811ca307 --- /dev/null +++ b/pc-bios/descriptors/60-edk2-riscv64.json @@ -0,0 +1,31 @@ +{ + "description": "UEFI firmware for riscv64", + "interface-types": [ + "uefi" + ], + "mapping": { + "device": "flash", + "executable": { + "filename": "@DATADIR@/edk2-riscv-code.fd", + "format": "raw" + }, + "nvram-template": { + "filename": "@DATADIR@/edk2-riscv-vars.fd", + "format": "raw" + } + }, + "targets": [ + { + "architecture": "riscv64", + "machines": [ + "virt*" + ] + } + ], + "features": [ + + ], + "tags": [ + + ] +} diff --git a/pc-bios/descriptors/meson.build b/pc-bios/descriptors/meson.build index afb5a959cc..cdd0be01a3 100644 --- a/pc-bios/descriptors/meson.build +++ b/pc-bios/descriptors/meson.build @@ -6,7 +6,8 @@ if unpack_edk2_blobs and get_option('install_blobs') '60-edk2-arm.json', '60-edk2-i386.json', '60-edk2-x86_64.json', - '60-edk2-loongarch64.json' + '60-edk2-loongarch64.json', + '60-edk2-riscv64.json' ] configure_file(input: files(f), output: f, From ad06bb324d3a87582e8d5a6b1cd420714cf6c681 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 13 Dec 2024 18:23:37 +0000 Subject: [PATCH 07/58] hw/intc/arm_gicv3_its: Zero initialize local DTEntry etc structs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the GICv3 ITS model, we have a common coding pattern which has a local C struct like "DTEntry dte", which is a C representation of an in-guest-memory data structure, and we call a function such as get_dte() to read guest memory and fill in the C struct. These functions to read in the struct sometimes have cases where they will leave early and not fill in the whole struct (for instance get_dte() will set "dte->valid = false" and nothing else for the case where it is passed an entry_addr implying that there is no L2 table entry for the DTE). This then causes potential use of uninitialized memory later, for instance when we call a trace event which prints all the fields of the struct. Sufficiently advanced compilers may produce -Wmaybe-uninitialized warnings about this, especially if LTO is enabled. Rather than trying to carefully separate out these trace events into "only the 'valid' field is initialized" and "all fields can be printed", zero-init all the structs when we define them. None of these structs are large (the biggest is 24 bytes) and having consistent behaviour is less likely to be buggy. Cc: qemu-stable@nongnu.org Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2718 Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-id: 20241213182337.3343068-1-peter.maydell@linaro.org (cherry picked from commit 9678b9c505725732353baefedb88b53c2eb8a184) Signed-off-by: Michael Tokarev --- hw/intc/arm_gicv3_its.c | 44 ++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c index bf31158470..752322a3e7 100644 --- a/hw/intc/arm_gicv3_its.c +++ b/hw/intc/arm_gicv3_its.c @@ -465,7 +465,7 @@ static ItsCmdResult lookup_vte(GICv3ITSState *s, const char *who, static ItsCmdResult process_its_cmd_phys(GICv3ITSState *s, const ITEntry *ite, int irqlevel) { - CTEntry cte; + CTEntry cte = {}; ItsCmdResult cmdres; cmdres = lookup_cte(s, __func__, ite->icid, &cte); @@ -479,7 +479,7 @@ static ItsCmdResult process_its_cmd_phys(GICv3ITSState *s, const ITEntry *ite, static ItsCmdResult process_its_cmd_virt(GICv3ITSState *s, const ITEntry *ite, int irqlevel) { - VTEntry vte; + VTEntry vte = {}; ItsCmdResult cmdres; cmdres = lookup_vte(s, __func__, ite->vpeid, &vte); @@ -514,8 +514,8 @@ static ItsCmdResult process_its_cmd_virt(GICv3ITSState *s, const ITEntry *ite, static ItsCmdResult do_process_its_cmd(GICv3ITSState *s, uint32_t devid, uint32_t eventid, ItsCmdType cmd) { - DTEntry dte; - ITEntry ite; + DTEntry dte = {}; + ITEntry ite = {}; ItsCmdResult cmdres; int irqlevel; @@ -583,8 +583,8 @@ static ItsCmdResult process_mapti(GICv3ITSState *s, const uint64_t *cmdpkt, uint32_t pIntid = 0; uint64_t num_eventids; uint16_t icid = 0; - DTEntry dte; - ITEntry ite; + DTEntry dte = {}; + ITEntry ite = {}; devid = (cmdpkt[0] & DEVID_MASK) >> DEVID_SHIFT; eventid = cmdpkt[1] & EVENTID_MASK; @@ -651,8 +651,8 @@ static ItsCmdResult process_vmapti(GICv3ITSState *s, const uint64_t *cmdpkt, { uint32_t devid, eventid, vintid, doorbell, vpeid; uint32_t num_eventids; - DTEntry dte; - ITEntry ite; + DTEntry dte = {}; + ITEntry ite = {}; if (!its_feature_virtual(s)) { return CMD_CONTINUE; @@ -761,7 +761,7 @@ static bool update_cte(GICv3ITSState *s, uint16_t icid, const CTEntry *cte) static ItsCmdResult process_mapc(GICv3ITSState *s, const uint64_t *cmdpkt) { uint16_t icid; - CTEntry cte; + CTEntry cte = {}; icid = cmdpkt[2] & ICID_MASK; cte.valid = cmdpkt[2] & CMD_FIELD_VALID_MASK; @@ -822,7 +822,7 @@ static bool update_dte(GICv3ITSState *s, uint32_t devid, const DTEntry *dte) static ItsCmdResult process_mapd(GICv3ITSState *s, const uint64_t *cmdpkt) { uint32_t devid; - DTEntry dte; + DTEntry dte = {}; devid = (cmdpkt[0] & DEVID_MASK) >> DEVID_SHIFT; dte.size = cmdpkt[1] & SIZE_MASK; @@ -886,9 +886,9 @@ static ItsCmdResult process_movi(GICv3ITSState *s, const uint64_t *cmdpkt) { uint32_t devid, eventid; uint16_t new_icid; - DTEntry dte; - CTEntry old_cte, new_cte; - ITEntry old_ite; + DTEntry dte = {}; + CTEntry old_cte = {}, new_cte = {}; + ITEntry old_ite = {}; ItsCmdResult cmdres; devid = FIELD_EX64(cmdpkt[0], MOVI_0, DEVICEID); @@ -965,7 +965,7 @@ static bool update_vte(GICv3ITSState *s, uint32_t vpeid, const VTEntry *vte) static ItsCmdResult process_vmapp(GICv3ITSState *s, const uint64_t *cmdpkt) { - VTEntry vte; + VTEntry vte = {}; uint32_t vpeid; if (!its_feature_virtual(s)) { @@ -1030,7 +1030,7 @@ static void vmovp_callback(gpointer data, gpointer opaque) */ GICv3ITSState *s = data; VmovpCallbackData *cbdata = opaque; - VTEntry vte; + VTEntry vte = {}; ItsCmdResult cmdres; cmdres = lookup_vte(s, __func__, cbdata->vpeid, &vte); @@ -1085,9 +1085,9 @@ static ItsCmdResult process_vmovi(GICv3ITSState *s, const uint64_t *cmdpkt) { uint32_t devid, eventid, vpeid, doorbell; bool doorbell_valid; - DTEntry dte; - ITEntry ite; - VTEntry old_vte, new_vte; + DTEntry dte = {}; + ITEntry ite = {}; + VTEntry old_vte = {}, new_vte = {}; ItsCmdResult cmdres; if (!its_feature_virtual(s)) { @@ -1186,10 +1186,10 @@ static ItsCmdResult process_vinvall(GICv3ITSState *s, const uint64_t *cmdpkt) static ItsCmdResult process_inv(GICv3ITSState *s, const uint64_t *cmdpkt) { uint32_t devid, eventid; - ITEntry ite; - DTEntry dte; - CTEntry cte; - VTEntry vte; + ITEntry ite = {}; + DTEntry dte = {}; + CTEntry cte = {}; + VTEntry vte = {}; ItsCmdResult cmdres; devid = FIELD_EX64(cmdpkt[0], INV_0, DEVICEID); From 42490ac98088a744113589aa75400d9db714776d Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 18 Dec 2024 07:21:59 +0100 Subject: [PATCH 08/58] meson.build: Disallow libnfs v6 to fix the broken macOS build MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The macOS builds in our CI (and possibly other very recent distros) are currently broken since the update to libnfs version 6 there. That version apparently comes with a big API breakage. v5.0.3 was the final release of the old API (see the libnfs commit here: https://github.com/sahlberg/libnfs/commit/4379837 ). Disallow version 6.x for now to get the broken CI job working again. Once somebody had enough time to adapt our code in block/nfs.c, we can revert this change again. Message-ID: <20241218065157.209020-1-thuth@redhat.com> Reviewed-by: Daniel P. Berrangé Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Huth (cherry picked from commit e2d98f257138b83b6a492d1da5847a7fe0930d10) Signed-off-by: Michael Tokarev --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 147097c652..7a3faca61d 100644 --- a/meson.build +++ b/meson.build @@ -1122,7 +1122,7 @@ endif libnfs = not_found if not get_option('libnfs').auto() or have_block - libnfs = dependency('libnfs', version: '>=1.9.3', + libnfs = dependency('libnfs', version: ['>=1.9.3', '<6.0.0'], required: get_option('libnfs'), method: 'pkg-config') endif From 2dc652961d6a9508d5db140765a0b22238165d88 Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Thu, 12 Dec 2024 15:51:15 +0100 Subject: [PATCH 09/58] target/i386: Reset TSCs of parked vCPUs too on VM reset Since commit 5286c3662294 ("target/i386: properly reset TSC on reset") QEMU writes the special value of "1" to each online vCPU TSC on VM reset to reset it. However parked vCPUs don't get that handling and due to that their TSCs get desynchronized when the VM gets reset. This in turn causes KVM to turn off PVCLOCK_TSC_STABLE_BIT in its exported PV clock. Note that KVM has no understanding of vCPU being currently parked. Without PVCLOCK_TSC_STABLE_BIT the sched clock is marked unstable in the guest's kvm_sched_clock_init(). This causes a performance regressions to show in some tests. Fix this issue by writing the special value of "1" also to TSCs of parked vCPUs on VM reset. Reproducing the issue: 1) Boot a VM with "-smp 2,maxcpus=3" or similar 2) device_add host-x86_64-cpu,id=vcpu,node-id=0,socket-id=0,core-id=2,thread-id=0 3) Wait a few seconds 4) device_del vcpu 5) Inside the VM run: # echo "t" >/proc/sysrq-trigger; dmesg | grep sched_clock_stable Observe the sched_clock_stable() value is 1. 6) Reboot the VM 7) Once the VM boots once again run inside it: # echo "t" >/proc/sysrq-trigger; dmesg | grep sched_clock_stable Observe the sched_clock_stable() value is now 0. Fixes: 5286c3662294 ("target/i386: properly reset TSC on reset") Signed-off-by: Maciej S. Szmigiero Link: https://lore.kernel.org/r/5a605a88e9a231386dc803c60f5fed9b48108139.1734014926.git.maciej.szmigiero@oracle.com Signed-off-by: Paolo Bonzini (cherry picked from commit 3f2a05b31ee9ce2ddb6c75a9bc3f5e7f7af9a76f) Signed-off-by: Michael Tokarev --- accel/kvm/kvm-all.c | 11 +++++++++++ configs/targets/i386-softmmu.mak | 1 + configs/targets/x86_64-softmmu.mak | 1 + include/sysemu/kvm.h | 8 ++++++++ target/i386/kvm/kvm.c | 15 +++++++++++++++ 5 files changed, 36 insertions(+) diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index 801cff16a5..dec1d1c16a 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -437,6 +437,16 @@ int kvm_unpark_vcpu(KVMState *s, unsigned long vcpu_id) return kvm_fd; } +static void kvm_reset_parked_vcpus(void *param) +{ + KVMState *s = param; + struct KVMParkedVcpu *cpu; + + QLIST_FOREACH(cpu, &s->kvm_parked_vcpus, node) { + kvm_arch_reset_parked_vcpu(cpu->vcpu_id, cpu->kvm_fd); + } +} + int kvm_create_vcpu(CPUState *cpu) { unsigned long vcpu_id = kvm_arch_vcpu_id(cpu); @@ -2728,6 +2738,7 @@ static int kvm_init(MachineState *ms) } qemu_register_reset(kvm_unpoison_all, NULL); + qemu_register_reset(kvm_reset_parked_vcpus, s); if (s->kernel_irqchip_allowed) { kvm_irqchip_create(s); diff --git a/configs/targets/i386-softmmu.mak b/configs/targets/i386-softmmu.mak index 2ac69d5ba3..2eb0e86250 100644 --- a/configs/targets/i386-softmmu.mak +++ b/configs/targets/i386-softmmu.mak @@ -1,4 +1,5 @@ TARGET_ARCH=i386 TARGET_SUPPORTS_MTTCG=y TARGET_KVM_HAVE_GUEST_DEBUG=y +TARGET_KVM_HAVE_RESET_PARKED_VCPU=y TARGET_XML_FILES= gdb-xml/i386-32bit.xml diff --git a/configs/targets/x86_64-softmmu.mak b/configs/targets/x86_64-softmmu.mak index e12ac3dc59..920e9a4200 100644 --- a/configs/targets/x86_64-softmmu.mak +++ b/configs/targets/x86_64-softmmu.mak @@ -2,4 +2,5 @@ TARGET_ARCH=x86_64 TARGET_BASE_ARCH=i386 TARGET_SUPPORTS_MTTCG=y TARGET_KVM_HAVE_GUEST_DEBUG=y +TARGET_KVM_HAVE_RESET_PARKED_VCPU=y TARGET_XML_FILES= gdb-xml/i386-64bit.xml diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h index c3a60b2890..ab17c09a55 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -377,6 +377,14 @@ int kvm_arch_init(MachineState *ms, KVMState *s); int kvm_arch_init_vcpu(CPUState *cpu); int kvm_arch_destroy_vcpu(CPUState *cpu); +#ifdef TARGET_KVM_HAVE_RESET_PARKED_VCPU +void kvm_arch_reset_parked_vcpu(unsigned long vcpu_id, int kvm_fd); +#else +static inline void kvm_arch_reset_parked_vcpu(unsigned long vcpu_id, int kvm_fd) +{ +} +#endif + bool kvm_vcpu_id_is_valid(int vcpu_id); /* Returns VCPU ID to be used on KVM_CREATE_VCPU ioctl() */ diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index 8e17942c3b..2ff618fbf1 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -2415,6 +2415,21 @@ void kvm_arch_after_reset_vcpu(X86CPU *cpu) } } +void kvm_arch_reset_parked_vcpu(unsigned long vcpu_id, int kvm_fd) +{ + g_autofree struct kvm_msrs *msrs = NULL; + + msrs = g_malloc0(sizeof(*msrs) + sizeof(msrs->entries[0])); + msrs->entries[0].index = MSR_IA32_TSC; + msrs->entries[0].data = 1; /* match the value in x86_cpu_reset() */ + msrs->nmsrs++; + + if (ioctl(kvm_fd, KVM_SET_MSRS, msrs) != 1) { + warn_report("parked vCPU %lu TSC reset failed: %d", + vcpu_id, errno); + } +} + void kvm_arch_do_init_vcpu(X86CPU *cpu) { CPUX86State *env = &cpu->env; From 19484ed99afb6f475000a4d54b9a7aa8c45778d7 Mon Sep 17 00:00:00 2001 From: Yong-Xuan Wang Date: Tue, 29 Oct 2024 16:53:47 +0800 Subject: [PATCH 10/58] hw/intc/riscv_aplic: Fix APLIC in_clrip and clripnum write emulation In the section "4.7 Precise effects on interrupt-pending bits" of the RISC-V AIA specification defines that: "If the source mode is Level1 or Level0 and the interrupt domain is configured in MSI delivery mode (domaincfg.DM = 1): The pending bit is cleared whenever the rectified input value is low, when the interrupt is forwarded by MSI, or by a relevant write to an in_clrip register or to clripnum." Update the riscv_aplic_set_pending() to match the spec. Fixes: bf31cf06eb ("hw/intc/riscv_aplic: Fix setipnum_le write emulation for APLIC MSI-mode") Signed-off-by: Yong-Xuan Wang Acked-by: Alistair Francis Message-ID: <20241029085349.30412-1-yongxuan.wang@sifive.com> Signed-off-by: Alistair Francis (cherry picked from commit 0d0141fadc9063e527865ee420b2baf34e306093) Signed-off-by: Michael Tokarev --- hw/intc/riscv_aplic.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/hw/intc/riscv_aplic.c b/hw/intc/riscv_aplic.c index 4a262c82f0..74c82a8411 100644 --- a/hw/intc/riscv_aplic.c +++ b/hw/intc/riscv_aplic.c @@ -248,9 +248,12 @@ static void riscv_aplic_set_pending(RISCVAPLICState *aplic, if ((sm == APLIC_SOURCECFG_SM_LEVEL_HIGH) || (sm == APLIC_SOURCECFG_SM_LEVEL_LOW)) { - if (!aplic->msimode || (aplic->msimode && !pending)) { + if (!aplic->msimode) { return; } + if (aplic->msimode && !pending) { + goto noskip_write_pending; + } if ((aplic->state[irq] & APLIC_ISTATE_INPUT) && (sm == APLIC_SOURCECFG_SM_LEVEL_LOW)) { return; @@ -261,6 +264,7 @@ static void riscv_aplic_set_pending(RISCVAPLICState *aplic, } } +noskip_write_pending: riscv_aplic_set_pending_raw(aplic, irq, pending); } From 9d913e012b4328dab3c6b4e07907f3b87675fede Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Thu, 19 Dec 2024 15:41:02 +0100 Subject: [PATCH 11/58] s390x/s390-virtio-ccw: don't crash on weird RAM sizes KVM is not happy when starting a VM with weird RAM sizes: # qemu-system-s390x --enable-kvm --nographic -m 1234K qemu-system-s390x: kvm_set_user_memory_region: KVM_SET_USER_MEMORY_REGION failed, slot=0, start=0x0, size=0x244000: Invalid argument kvm_set_phys_mem: error registering slot: Invalid argument Aborted (core dumped) Let's handle that in a better way by rejecting such weird RAM sizes right from the start: # qemu-system-s390x --enable-kvm --nographic -m 1234K qemu-system-s390x: ram size must be multiples of 1 MiB Message-ID: <20241219144115.2820241-2-david@redhat.com> Acked-by: Michael S. Tsirkin Reviewed-by: Eric Farman Reviewed-by: Thomas Huth Acked-by: Janosch Frank Signed-off-by: David Hildenbrand (cherry picked from commit 14e568ab4836347481af2e334009c385f456a734) Signed-off-by: Michael Tokarev --- hw/s390x/s390-virtio-ccw.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index fe03f716f3..53c62fb77c 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -180,6 +180,17 @@ static void s390_memory_init(MemoryRegion *ram) { MemoryRegion *sysmem = get_system_memory(); + if (!QEMU_IS_ALIGNED(memory_region_size(ram), 1 * MiB)) { + /* + * SCLP cannot possibly expose smaller granularity right now and KVM + * cannot handle smaller granularity. As we don't support NUMA, the + * region size directly corresponds to machine->ram_size, and the region + * is a single RAM memory region. + */ + error_report("ram size must be multiples of 1 MiB"); + exit(EXIT_FAILURE); + } + /* allocate RAM for core */ memory_region_add_subregion(sysmem, 0, ram); From 15eedfd2ff08e34fe19d86dd41d0ee646fa7774d Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Thu, 12 Dec 2024 16:22:34 +0800 Subject: [PATCH 12/58] target/loongarch: Use actual operand size with vbsrl check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hardcoded 32 bytes is used for vbsrl emulation check, there is problem when options lsx=on,lasx=off is used for vbsrl.v instruction in TCG mode. It injects LASX exception rather LSX exception. Here actual operand size is used. Cc: qemu-stable@nongnu.org Fixes: df97f338076 ("target/loongarch: Implement xvreplve xvinsve0 xvpickve") Signed-off-by: Bibo Mao Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé (cherry picked from commit d41989e7548397b469ec9c7be4cee699321a317e) Signed-off-by: Michael Tokarev --- target/loongarch/tcg/insn_trans/trans_vec.c.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/loongarch/tcg/insn_trans/trans_vec.c.inc b/target/loongarch/tcg/insn_trans/trans_vec.c.inc index 92b1d22e28..ba5ca98a33 100644 --- a/target/loongarch/tcg/insn_trans/trans_vec.c.inc +++ b/target/loongarch/tcg/insn_trans/trans_vec.c.inc @@ -5126,7 +5126,7 @@ static bool do_vbsrl_v(DisasContext *ctx, arg_vv_i *a, uint32_t oprsz) { int i, ofs; - if (!check_vec(ctx, 32)) { + if (!check_vec(ctx, oprsz)) { return true; } From ad09b3df7e885428ba1d814dae7d2e3fcfac2c39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 19 Dec 2024 16:02:01 +0100 Subject: [PATCH 13/58] docs: Correct '-runas' and '-fsdev/-virtfs proxy' indentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the same style for deprecated / removed commands. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alex Bennée Reviewed-by: Michael Tokarev Signed-off-by: Michael Tokarev (cherry picked from commit 916f50172baa91ddf0e669a9d6d2747055c0e610) Signed-off-by: Michael Tokarev --- docs/about/deprecated.rst | 2 +- docs/about/removed-features.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index d8dc29d0a4..b1f4a51325 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -75,7 +75,7 @@ marked deprecated since 9.0, users have to ensure that all the topology members described with -smp are supported by the target machine. ``-runas`` (since 9.1) ----------------------- +'''''''''''''''''''''' Use ``-run-with user=..`` instead. diff --git a/docs/about/removed-features.rst b/docs/about/removed-features.rst index ee6455aeee..563a614738 100644 --- a/docs/about/removed-features.rst +++ b/docs/about/removed-features.rst @@ -518,7 +518,7 @@ and later do not support it because the virtio-scsi device was introduced for full SCSI support. Use virtio-scsi instead when SCSI passthrough is required. ``-fsdev proxy`` and ``-virtfs proxy`` (since 9.2) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +'''''''''''''''''''''''''''''''''''''''''''''''''' The 9p ``proxy`` filesystem backend driver was originally developed to enhance security by dispatching low level filesystem operations from 9p From 64092b346494bae2c366de15d32f83b4fae0594d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 19 Dec 2024 16:02:02 +0100 Subject: [PATCH 14/58] docs: Correct release of TCG trace-events removal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TCG trace-events were deprecated before the v6.2 release, and removed for v7.0. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alex Bennée Reviewed-by: Michael Tokarev Signed-off-by: Michael Tokarev (cherry picked from commit b4859e8f33a7d9c793a60395f792c10190cb4f78) Signed-off-by: Michael Tokarev --- docs/about/removed-features.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/about/removed-features.rst b/docs/about/removed-features.rst index 563a614738..93086f9cd5 100644 --- a/docs/about/removed-features.rst +++ b/docs/about/removed-features.rst @@ -1077,8 +1077,8 @@ processor IP (see `Intel discontinuance notification`_). TCG introspection features -------------------------- -TCG trace-events (since 6.2) -'''''''''''''''''''''''''''' +TCG trace-events (removed in 7.0) +''''''''''''''''''''''''''''''''' The ability to add new TCG trace points had bit rotted and as the feature can be replicated with TCG plugins it was removed. If From 9bbaadbf9cfb5ae60e3ecff00ef56283e21fbfb7 Mon Sep 17 00:00:00 2001 From: Han Han Date: Thu, 19 Dec 2024 16:51:38 +0800 Subject: [PATCH 15/58] target/i386/cpu: Fix notes for CPU models Fixes: 644e3c5d812 ("missing vmx features for Skylake-Server and Cascadelake-Server") Signed-off-by: Han Han Reviewed-by: Chenyi Qiang Reviewed-by: Michael Tokarev Signed-off-by: Michael Tokarev (cherry picked from commit 93dcc9390e5ad0696ae7e9b7b3a5b08c2d1b6de6) Signed-off-by: Michael Tokarev --- target/i386/cpu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 3725dbbc4b..aff5e917db 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -3691,6 +3691,7 @@ static const X86CPUDefinition builtin_x86_defs[] = { }, { .version = 4, + .note = "IBRS, EPT switching, no TSX", .props = (PropValue[]) { { "vmx-eptp-switching", "on" }, { /* end of list */ } @@ -3825,7 +3826,7 @@ static const X86CPUDefinition builtin_x86_defs[] = { }, }, { .version = 4, - .note = "ARCH_CAPABILITIES, no TSX", + .note = "ARCH_CAPABILITIES, EPT switching, no TSX", .props = (PropValue[]) { { "vmx-eptp-switching", "on" }, { /* end of list */ } From f5827eb0ac3af024918fb702690188210c31202c Mon Sep 17 00:00:00 2001 From: Shameer Kolothum Date: Tue, 3 Dec 2024 12:49:43 +0000 Subject: [PATCH 16/58] migration/multifd: Fix compile error caused by page_size usage >From Commit 90fa121c6c07 ("migration/multifd: Inline page_size and page_count") onwards page_size is not part of MutiFD*Params but uses an inline constant instead. However, it missed updating an old usage, causing a compile error. Fixes: 90fa121c6c07 ("migration/multifd: Inline page_size and page_count") Signed-off-by: Shameer Kolothum Reviewed-by: Fabiano Rosas Message-Id: <20241203124943.52572-1-shameerali.kolothum.thodi@huawei.com> Signed-off-by: Fabiano Rosas (cherry picked from commit d127294f265e6a17f8d614f2bef7df8455e81f56) Signed-off-by: Michael Tokarev --- migration/multifd-uadk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/migration/multifd-uadk.c b/migration/multifd-uadk.c index 6e6a290ae9..6895c1f65a 100644 --- a/migration/multifd-uadk.c +++ b/migration/multifd-uadk.c @@ -169,7 +169,7 @@ static int multifd_uadk_send_prepare(MultiFDSendParams *p, Error **errp) .src_len = page_size, .dst = buf, /* Set dst_len to double the src in case compressed out >= page_size */ - .dst_len = p->page_size * 2, + .dst_len = page_size * 2, }; if (uadk_data->handle) { From 7e4480dde246982f18b51d8f316a95a7dba2b825 Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Fri, 13 Dec 2024 13:01:19 -0300 Subject: [PATCH 17/58] migration/multifd: Fix compat with QEMU < 9.0 Commit f5f48a7891 ("migration/multifd: Separate SYNC request with normal jobs") changed the multifd source side to stop sending data along with the MULTIFD_FLAG_SYNC, effectively introducing the concept of a SYNC-only packet. Relying on that, commit d7e58f412c ("migration/multifd: Don't send ram data during SYNC") later came along and skipped reading data from SYNC packets. In a versions timeline like this: 8.2 f5f48a7 9.0 9.1 d7e58f41 9.2 The issue arises that QEMUs < 9.0 still send data along with SYNC, but QEMUs > 9.1 don't gather that data anymore. This leads to various kinds of migration failures due to desync/missing data. Stop checking for a SYNC packet on the destination and unconditionally unfill the packet. >From now on: old -> new: the source sends data + sync, destination reads normally new -> new: source sends only sync, destination reads zeros new -> old: source sends only sync, destination reads zeros CC: qemu-stable@nongnu.org Fixes: d7e58f412c ("migration/multifd: Don't send ram data during SYNC") Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2720 Reviewed-by: Peter Xu Signed-off-by: Fabiano Rosas Message-Id: <20241213160120.23880-2-farosas@suse.de> Signed-off-by: Fabiano Rosas (cherry picked from commit b93d897ea2f0abbe7fc341a9ac176b5ecd0f3c93) Signed-off-by: Michael Tokarev --- migration/multifd.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/migration/multifd.c b/migration/multifd.c index 498e71fd10..8d0a763a72 100644 --- a/migration/multifd.c +++ b/migration/multifd.c @@ -252,9 +252,8 @@ static int multifd_recv_unfill_packet(MultiFDRecvParams *p, Error **errp) p->packet_num = be64_to_cpu(packet->packet_num); p->packets_recved++; - if (!(p->flags & MULTIFD_FLAG_SYNC)) { - ret = multifd_ram_unfill_packet(p, errp); - } + /* Always unfill, old QEMUs (<9.0) send data along with SYNC */ + ret = multifd_ram_unfill_packet(p, errp); trace_multifd_recv_unfill(p->id, p->packet_num, p->flags, p->next_packet_size); @@ -1151,9 +1150,13 @@ static void *multifd_recv_thread(void *opaque) flags = p->flags; /* recv methods don't know how to handle the SYNC flag */ p->flags &= ~MULTIFD_FLAG_SYNC; - if (!(flags & MULTIFD_FLAG_SYNC)) { - has_data = p->normal_num || p->zero_num; - } + + /* + * Even if it's a SYNC packet, this needs to be set + * because older QEMUs (<9.0) still send data along with + * the SYNC packet. + */ + has_data = p->normal_num || p->zero_num; qemu_mutex_unlock(&p->mutex); } else { /* From ea3b821595fa474366743a293c19fa20ceb8506f Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Thu, 9 Jan 2025 15:52:43 -0300 Subject: [PATCH 18/58] migration: Add more error handling to analyze-migration.py The analyze-migration script was seen failing in s390x in misterious ways. It seems we're reaching the VMSDFieldStruct constructor without any fields, which would indicate an empty .subsection entry, a VMSTATE_STRUCT with no fields or a vmsd with no fields. We don't have any of those, at least not without the unmigratable flag set, so this should never happen. Add some debug statements so that we can see what's going on the next time the issue happens. Reviewed-by: Peter Xu Message-Id: <20250109185249.23952-2-farosas@suse.de> Signed-off-by: Fabiano Rosas (cherry picked from commit 86bee9e0c761a3d0e67c43b44001fd752f894cb0) Signed-off-by: Michael Tokarev --- scripts/analyze-migration.py | 75 +++++++++++++++++++++--------------- 1 file changed, 45 insertions(+), 30 deletions(-) diff --git a/scripts/analyze-migration.py b/scripts/analyze-migration.py index 8a254a5b6a..f2457b1dde 100755 --- a/scripts/analyze-migration.py +++ b/scripts/analyze-migration.py @@ -429,6 +429,9 @@ class VMSDFieldStruct(VMSDFieldGeneric): super(VMSDFieldStruct, self).__init__(desc, file) self.data = collections.OrderedDict() + if 'fields' not in self.desc['struct']: + raise Exception("No fields in struct. VMSD:\n%s" % self.desc) + # When we see compressed array elements, unfold them here new_fields = [] for field in self.desc['struct']['fields']: @@ -477,6 +480,10 @@ class VMSDFieldStruct(VMSDFieldGeneric): raise Exception("Subsection %s not found at offset %x" % ( subsection['vmsd_name'], self.file.tell())) name = self.file.readstr() version_id = self.file.read32() + + if not subsection: + raise Exception("Empty description for subsection: %s" % name) + self.data[name] = VMSDSection(self.file, version_id, subsection, (name, 0)) self.data[name].read() @@ -574,10 +581,13 @@ class MigrationDump(object): } self.filename = filename self.vmsd_desc = None + self.vmsd_json = "" - def read(self, desc_only = False, dump_memory = False, write_memory = False): + def read(self, desc_only = False, dump_memory = False, + write_memory = False): # Read in the whole file file = MigrationFile(self.filename) + self.vmsd_json = file.read_migration_debug_json() # File magic data = file.read32() @@ -635,9 +645,11 @@ class MigrationDump(object): file.close() def load_vmsd_json(self, file): - vmsd_json = file.read_migration_debug_json() - self.vmsd_desc = json.loads(vmsd_json, object_pairs_hook=collections.OrderedDict) + self.vmsd_desc = json.loads(self.vmsd_json, + object_pairs_hook=collections.OrderedDict) for device in self.vmsd_desc['devices']: + if 'fields' not in device: + raise Exception("vmstate for device %s has no fields" % device['name']) key = (device['name'], device['instance_id']) value = ( VMSDSection, device ) self.section_classes[key] = value @@ -666,31 +678,34 @@ args = parser.parse_args() jsonenc = JSONEncoder(indent=4, separators=(',', ': ')) -if args.extract: - dump = MigrationDump(args.file) - - dump.read(desc_only = True) - print("desc.json") - f = open("desc.json", "w") - f.truncate() - f.write(jsonenc.encode(dump.vmsd_desc)) - f.close() - - dump.read(write_memory = True) - dict = dump.getDict() - print("state.json") - f = open("state.json", "w") - f.truncate() - f.write(jsonenc.encode(dict)) - f.close() -elif args.dump == "state": - dump = MigrationDump(args.file) - dump.read(dump_memory = args.memory) - dict = dump.getDict() - print(jsonenc.encode(dict)) -elif args.dump == "desc": - dump = MigrationDump(args.file) - dump.read(desc_only = True) - print(jsonenc.encode(dump.vmsd_desc)) -else: +if not any([args.extract, args.dump == "state", args.dump == "desc"]): raise Exception("Please specify either -x, -d state or -d desc") + +try: + dump = MigrationDump(args.file) + + if args.extract: + dump.read(desc_only = True) + + print("desc.json") + f = open("desc.json", "w") + f.truncate() + f.write(jsonenc.encode(dump.vmsd_desc)) + f.close() + + dump.read(write_memory = True) + dict = dump.getDict() + print("state.json") + f = open("state.json", "w") + f.truncate() + f.write(jsonenc.encode(dict)) + f.close() + elif args.dump == "state": + dump.read(dump_memory = args.memory) + dict = dump.getDict() + print(jsonenc.encode(dict)) + elif args.dump == "desc": + dump.read(desc_only = True) + print(jsonenc.encode(dump.vmsd_desc)) +except Exception: + raise Exception("Full JSON dump:\n%s", dump.vmsd_json) From abb738ad333a8f5efe2cb7a76166a4375a782253 Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Thu, 9 Jan 2025 15:52:44 -0300 Subject: [PATCH 19/58] migration: Remove unused argument in vmsd_desc_field_end Reviewed-by: Peter Xu Message-Id: <20250109185249.23952-3-farosas@suse.de> Signed-off-by: Fabiano Rosas (cherry picked from commit 2aead53d39b828f8d9d0769ffa3579dadd64d846) Signed-off-by: Michael Tokarev --- migration/vmstate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/migration/vmstate.c b/migration/vmstate.c index fa002b24e8..aa2821dec6 100644 --- a/migration/vmstate.c +++ b/migration/vmstate.c @@ -311,7 +311,7 @@ static void vmsd_desc_field_start(const VMStateDescription *vmsd, static void vmsd_desc_field_end(const VMStateDescription *vmsd, JSONWriter *vmdesc, - const VMStateField *field, size_t size, int i) + const VMStateField *field, size_t size) { if (!vmdesc) { return; @@ -420,7 +420,7 @@ int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd, } written_bytes = qemu_file_transferred(f) - old_offset; - vmsd_desc_field_end(vmsd, vmdesc_loop, field, written_bytes, i); + vmsd_desc_field_end(vmsd, vmdesc_loop, field, written_bytes); /* Compressed arrays only care about the first element */ if (vmdesc_loop && vmsd_can_compress(field)) { From e3839b0c19280be945a2af42b66483c09732bc5f Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Thu, 9 Jan 2025 15:52:45 -0300 Subject: [PATCH 20/58] migration: Fix parsing of s390 stream The parsing for the S390StorageAttributes section is currently leaving an unconsumed token that is later interpreted by the generic code as QEMU_VM_EOF, cutting the parsing short. The migration will issue a STATTR_FLAG_DONE between iterations, which the script consumes correctly, but there's a final STATTR_FLAG_EOS at .save_complete that the script is ignoring. Since the EOS flag is a u64 0x1ULL and the stream is big endian, on little endian hosts a byte read from it will be 0x0, the same as QEMU_VM_EOF. Fixes: 81c2c9dd5d ("tests/qtest/migration-test: Fix analyze-migration.py for s390x") Reviewed-by: Peter Xu Message-Id: <20250109185249.23952-4-farosas@suse.de> Signed-off-by: Fabiano Rosas (cherry picked from commit 69d1f784569fdb950f2923c3b6d00d7c1b71acc1) Signed-off-by: Michael Tokarev --- scripts/analyze-migration.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/scripts/analyze-migration.py b/scripts/analyze-migration.py index f2457b1dde..fcda11f31d 100755 --- a/scripts/analyze-migration.py +++ b/scripts/analyze-migration.py @@ -65,6 +65,9 @@ class MigrationFile(object): def tell(self): return self.file.tell() + def seek(self, a, b): + return self.file.seek(a, b) + # The VMSD description is at the end of the file, after EOF. Look for # the last NULL byte, then for the beginning brace of JSON. def read_migration_debug_json(self): @@ -272,11 +275,24 @@ class S390StorageAttributes(object): self.section_key = section_key def read(self): + pos = 0 while True: addr_flags = self.file.read64() flags = addr_flags & 0xfff - if (flags & (self.STATTR_FLAG_DONE | self.STATTR_FLAG_EOS)): + + if flags & self.STATTR_FLAG_DONE: + pos = self.file.tell() + continue + elif flags & self.STATTR_FLAG_EOS: return + else: + # No EOS came after DONE, that's OK, but rewind the + # stream because this is not our data. + if pos: + self.file.seek(pos, os.SEEK_SET) + return + raise Exception("Unknown flags %x", flags) + if (flags & self.STATTR_FLAG_ERROR): raise Exception("Error in migration stream") count = self.file.read64() From e7a9d9342865e5f7dcd836afa77990e1980b1986 Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Thu, 9 Jan 2025 15:52:49 -0300 Subject: [PATCH 21/58] s390x: Fix CSS migration Commit a55ae46683 ("s390: move css_migration_enabled from machine to css.c") disabled CSS migration globally instead of doing it per-instance. CC: Paolo Bonzini CC: qemu-stable@nongnu.org #9.1 Fixes: a55ae46683 ("s390: move css_migration_enabled from machine to css.c") Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2704 Reviewed-by: Thomas Huth Message-Id: <20250109185249.23952-8-farosas@suse.de> Signed-off-by: Fabiano Rosas (cherry picked from commit c76ee1f6255c3988a9447d363bb17072f1ec84e1) Signed-off-by: Michael Tokarev --- hw/s390x/s390-virtio-ccw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 53c62fb77c..54f09cf096 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -1200,6 +1200,7 @@ static void ccw_machine_2_9_instance_options(MachineState *machine) s390_cpudef_featoff_greater(12, 1, S390_FEAT_ZPCI); s390_cpudef_featoff_greater(12, 1, S390_FEAT_ADAPTER_INT_SUPPRESSION); s390_cpudef_featoff_greater(12, 1, S390_FEAT_ADAPTER_EVENT_NOTIFICATION); + css_migration_enabled = false; } static void ccw_machine_2_9_class_options(MachineClass *mc) @@ -1212,7 +1213,6 @@ static void ccw_machine_2_9_class_options(MachineClass *mc) ccw_machine_2_10_class_options(mc); compat_props_add(mc->compat_props, hw_compat_2_9, hw_compat_2_9_len); compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat)); - css_migration_enabled = false; } DEFINE_CCW_MACHINE(2, 9); From 3ba6e1164a45f3345816921fec76d7bd12ed215a Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Thu, 9 Jan 2025 15:52:46 -0300 Subject: [PATCH 22/58] migration: Rename vmstate_info_nullptr Rename vmstate_info_nullptr from "uint64_t" to "nullptr". This vmstate actually reads and writes just a byte, so the proper name would be uint8. However, since this is a marker for a NULL pointer, it's convenient to have a more explicit name that can be identified by the consumers of the JSON part of the stream. Change the name to "nullptr" and add support for it in the analyze-migration.py script. Arbitrarily use the name of the type as the value of the field to avoid the script showing 0x30 or '0', which could be confusing for readers. Reviewed-by: Peter Xu Message-Id: <20250109185249.23952-5-farosas@suse.de> Signed-off-by: Fabiano Rosas (cherry picked from commit f52965bf0eeee28e89933264f1a9dbdcdaa76a7e) Signed-off-by: Michael Tokarev --- migration/vmstate-types.c | 2 +- scripts/analyze-migration.py | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/migration/vmstate-types.c b/migration/vmstate-types.c index e83bfccb9e..d70d573dbd 100644 --- a/migration/vmstate-types.c +++ b/migration/vmstate-types.c @@ -338,7 +338,7 @@ static int put_nullptr(QEMUFile *f, void *pv, size_t size, } const VMStateInfo vmstate_info_nullptr = { - .name = "uint64", + .name = "nullptr", .get = get_nullptr, .put = put_nullptr, }; diff --git a/scripts/analyze-migration.py b/scripts/analyze-migration.py index fcda11f31d..923f174f1b 100755 --- a/scripts/analyze-migration.py +++ b/scripts/analyze-migration.py @@ -417,6 +417,28 @@ class VMSDFieldIntLE(VMSDFieldInt): super(VMSDFieldIntLE, self).__init__(desc, file) self.dtype = ' Date: Thu, 9 Jan 2025 15:52:47 -0300 Subject: [PATCH 23/58] migration: Dump correct JSON format for nullptr replacement QEMU plays a trick with null pointers inside an array of pointers in a VMSD field. See 07d4e69147 ("migration/vmstate: fix array of ptr with nullptrs") for more details on why. The idea makes sense in general, but it may overlooked the JSON writer where it could write nothing in a "struct" in the JSON hints section. We hit some analyze-migration.py issues on s390 recently, showing that some of the struct field contains nothing, like: {"name": "css", "array_len": 256, "type": "struct", "struct": {}, "size": 1} As described in details by Fabiano: https://lore.kernel.org/r/87pll37cin.fsf@suse.de It could be that we hit some null pointers there, and JSON was gone when they're null pointers. To fix it, instead of hacking around only at VMStateInfo level, do that from VMStateField level, so that JSON writer can also be involved. In this case, JSON writer will replace the pointer array (which used to be a "struct") to be the real representation of the nullptr field. Signed-off-by: Peter Xu Message-Id: <20250109185249.23952-6-farosas@suse.de> Signed-off-by: Fabiano Rosas (cherry picked from commit 9867c3a7ced12dd7519155c047eb2c0098a11c5f) Signed-off-by: Michael Tokarev --- migration/vmstate.c | 118 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 91 insertions(+), 27 deletions(-) diff --git a/migration/vmstate.c b/migration/vmstate.c index aa2821dec6..52704c822c 100644 --- a/migration/vmstate.c +++ b/migration/vmstate.c @@ -51,6 +51,36 @@ vmstate_field_exists(const VMStateDescription *vmsd, const VMStateField *field, return result; } +/* + * Create a fake nullptr field when there's a NULL pointer detected in the + * array of a VMS_ARRAY_OF_POINTER VMSD field. It's needed because we + * can't dereference the NULL pointer. + */ +static const VMStateField * +vmsd_create_fake_nullptr_field(const VMStateField *field) +{ + VMStateField *fake = g_new0(VMStateField, 1); + + /* It can only happen on an array of pointers! */ + assert(field->flags & VMS_ARRAY_OF_POINTER); + + /* Some of fake's properties should match the original's */ + fake->name = field->name; + fake->version_id = field->version_id; + + /* Do not need "field_exists" check as it always exists (which is null) */ + fake->field_exists = NULL; + + /* See vmstate_info_nullptr - use 1 byte to represent nullptr */ + fake->size = 1; + fake->info = &vmstate_info_nullptr; + fake->flags = VMS_SINGLE; + + /* All the rest fields shouldn't matter.. */ + + return (const VMStateField *)fake; +} + static int vmstate_n_elems(void *opaque, const VMStateField *field) { int n_elems = 1; @@ -143,23 +173,39 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd, } for (i = 0; i < n_elems; i++) { void *curr_elem = first_elem + size * i; + const VMStateField *inner_field; if (field->flags & VMS_ARRAY_OF_POINTER) { curr_elem = *(void **)curr_elem; } + if (!curr_elem && size) { - /* if null pointer check placeholder and do not follow */ - assert(field->flags & VMS_ARRAY_OF_POINTER); - ret = vmstate_info_nullptr.get(f, curr_elem, size, NULL); - } else if (field->flags & VMS_STRUCT) { - ret = vmstate_load_state(f, field->vmsd, curr_elem, - field->vmsd->version_id); - } else if (field->flags & VMS_VSTRUCT) { - ret = vmstate_load_state(f, field->vmsd, curr_elem, - field->struct_version_id); + /* + * If null pointer found (which should only happen in + * an array of pointers), use null placeholder and do + * not follow. + */ + inner_field = vmsd_create_fake_nullptr_field(field); } else { - ret = field->info->get(f, curr_elem, size, field); + inner_field = field; } + + if (inner_field->flags & VMS_STRUCT) { + ret = vmstate_load_state(f, inner_field->vmsd, curr_elem, + inner_field->vmsd->version_id); + } else if (inner_field->flags & VMS_VSTRUCT) { + ret = vmstate_load_state(f, inner_field->vmsd, curr_elem, + inner_field->struct_version_id); + } else { + ret = inner_field->info->get(f, curr_elem, size, + inner_field); + } + + /* If we used a fake temp field.. free it now */ + if (inner_field != field) { + g_clear_pointer((gpointer *)&inner_field, g_free); + } + if (ret >= 0) { ret = qemu_file_get_error(f); } @@ -387,29 +433,50 @@ int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd, } for (i = 0; i < n_elems; i++) { void *curr_elem = first_elem + size * i; + const VMStateField *inner_field; - vmsd_desc_field_start(vmsd, vmdesc_loop, field, i, n_elems); old_offset = qemu_file_transferred(f); if (field->flags & VMS_ARRAY_OF_POINTER) { assert(curr_elem); curr_elem = *(void **)curr_elem; } + if (!curr_elem && size) { - /* if null pointer write placeholder and do not follow */ - assert(field->flags & VMS_ARRAY_OF_POINTER); - ret = vmstate_info_nullptr.put(f, curr_elem, size, NULL, - NULL); - } else if (field->flags & VMS_STRUCT) { - ret = vmstate_save_state(f, field->vmsd, curr_elem, - vmdesc_loop); - } else if (field->flags & VMS_VSTRUCT) { - ret = vmstate_save_state_v(f, field->vmsd, curr_elem, - vmdesc_loop, - field->struct_version_id, errp); + /* + * If null pointer found (which should only happen in + * an array of pointers), use null placeholder and do + * not follow. + */ + inner_field = vmsd_create_fake_nullptr_field(field); } else { - ret = field->info->put(f, curr_elem, size, field, - vmdesc_loop); + inner_field = field; } + + vmsd_desc_field_start(vmsd, vmdesc_loop, inner_field, + i, n_elems); + + if (inner_field->flags & VMS_STRUCT) { + ret = vmstate_save_state(f, inner_field->vmsd, + curr_elem, vmdesc_loop); + } else if (inner_field->flags & VMS_VSTRUCT) { + ret = vmstate_save_state_v(f, inner_field->vmsd, + curr_elem, vmdesc_loop, + inner_field->struct_version_id, + errp); + } else { + ret = inner_field->info->put(f, curr_elem, size, + inner_field, vmdesc_loop); + } + + written_bytes = qemu_file_transferred(f) - old_offset; + vmsd_desc_field_end(vmsd, vmdesc_loop, inner_field, + written_bytes); + + /* If we used a fake temp field.. free it now */ + if (inner_field != field) { + g_clear_pointer((gpointer *)&inner_field, g_free); + } + if (ret) { error_setg(errp, "Save of field %s/%s failed", vmsd->name, field->name); @@ -419,9 +486,6 @@ int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd, return ret; } - written_bytes = qemu_file_transferred(f) - old_offset; - vmsd_desc_field_end(vmsd, vmdesc_loop, field, written_bytes); - /* Compressed arrays only care about the first element */ if (vmdesc_loop && vmsd_can_compress(field)) { vmdesc_loop = NULL; From 82565fb6b36cd37a37ff0b3380cbd58f76449957 Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Thu, 9 Jan 2025 15:52:48 -0300 Subject: [PATCH 24/58] migration: Fix arrays of pointers in JSON writer Currently, if an array of pointers contains a NULL pointer, that pointer will be encoded as '0' in the stream. Since the JSON writer doesn't define a "pointer" type, that '0' will now be an uint8, which is different from the original type being pointed to, e.g. struct. (we're further calling uint8 "nullptr", but that's irrelevant to the issue) That mixed-type array shouldn't be compressed, otherwise data is lost as the code currently makes the whole array have the type of the first element: css = {NULL, NULL, ..., 0x5555568a7940, NULL}; {"name": "s390_css", "instance_id": 0, "vmsd_name": "s390_css", "version": 1, "fields": [ ..., {"name": "css", "array_len": 256, "type": "nullptr", "size": 1}, ..., ]} In the above, the valid pointer at position 254 got lost among the compressed array of nullptr. While we could disable the array compression when a NULL pointer is found, the JSON part of the stream still makes part of downtime, so we should avoid writing unecessary bytes to it. Keep the array compression in place, but if NULL and non-NULL pointers are mixed break the array into several type-contiguous pieces : css = {NULL, NULL, ..., 0x5555568a7940, NULL}; {"name": "s390_css", "instance_id": 0, "vmsd_name": "s390_css", "version": 1, "fields": [ ..., {"name": "css", "array_len": 254, "type": "nullptr", "size": 1}, {"name": "css", "type": "struct", "struct": {"vmsd_name": "s390_css_img", ... }, "size": 768}, {"name": "css", "type": "nullptr", "size": 1}, ..., ]} Now each type-discontiguous region will become a new JSON entry. The reader should interpret this as a concatenation of values, all part of the same field. Parsing the JSON with analyze-script.py now shows the proper data being pointed to at the places where the pointer is valid and "nullptr" where there's NULL: "s390_css (14)": { ... "css": [ "nullptr", "nullptr", ... "nullptr", { "chpids": [ { "in_use": "0x00", "type": "0x00", "is_virtual": "0x00" }, ... ] }, "nullptr", } Reviewed-by: Peter Xu Message-Id: <20250109185249.23952-7-farosas@suse.de> Signed-off-by: Fabiano Rosas (cherry picked from commit 35049eb0d2fc72bb8c563196ec75b4d6c13fce02) Signed-off-by: Michael Tokarev --- migration/vmstate.c | 33 ++++++++++++++++++++++++++++++++- scripts/analyze-migration.py | 26 ++++++++++++++++++-------- 2 files changed, 50 insertions(+), 9 deletions(-) diff --git a/migration/vmstate.c b/migration/vmstate.c index 52704c822c..82bd005a83 100644 --- a/migration/vmstate.c +++ b/migration/vmstate.c @@ -425,15 +425,19 @@ int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd, int size = vmstate_size(opaque, field); uint64_t old_offset, written_bytes; JSONWriter *vmdesc_loop = vmdesc; + bool is_prev_null = false; trace_vmstate_save_state_loop(vmsd->name, field->name, n_elems); if (field->flags & VMS_POINTER) { first_elem = *(void **)first_elem; assert(first_elem || !n_elems || !size); } + for (i = 0; i < n_elems; i++) { void *curr_elem = first_elem + size * i; const VMStateField *inner_field; + bool is_null; + int max_elems = n_elems - i; old_offset = qemu_file_transferred(f); if (field->flags & VMS_ARRAY_OF_POINTER) { @@ -448,12 +452,39 @@ int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd, * not follow. */ inner_field = vmsd_create_fake_nullptr_field(field); + is_null = true; } else { inner_field = field; + is_null = false; + } + + /* + * Due to the fake nullptr handling above, if there's mixed + * null/non-null data, it doesn't make sense to emit a + * compressed array representation spanning the entire array + * because the field types will be different (e.g. struct + * vs. nullptr). Search ahead for the next null/non-null element + * and start a new compressed array if found. + */ + if (field->flags & VMS_ARRAY_OF_POINTER && + is_null != is_prev_null) { + + is_prev_null = is_null; + vmdesc_loop = vmdesc; + + for (int j = i + 1; j < n_elems; j++) { + void *elem = *(void **)(first_elem + size * j); + bool elem_is_null = !elem && size; + + if (is_null != elem_is_null) { + max_elems = j - i; + break; + } + } } vmsd_desc_field_start(vmsd, vmdesc_loop, inner_field, - i, n_elems); + i, max_elems); if (inner_field->flags & VMS_STRUCT) { ret = vmstate_save_state(f, inner_field->vmsd, diff --git a/scripts/analyze-migration.py b/scripts/analyze-migration.py index 923f174f1b..8e1fbf4c9d 100755 --- a/scripts/analyze-migration.py +++ b/scripts/analyze-migration.py @@ -502,15 +502,25 @@ class VMSDFieldStruct(VMSDFieldGeneric): field['data'] = reader(field, self.file) field['data'].read() - if 'index' in field: - if field['name'] not in self.data: - self.data[field['name']] = [] - a = self.data[field['name']] - if len(a) != int(field['index']): - raise Exception("internal index of data field unmatched (%d/%d)" % (len(a), int(field['index']))) - a.append(field['data']) + fname = field['name'] + fdata = field['data'] + + # The field could be: + # i) a single data entry, e.g. uint64 + # ii) an array, indicated by it containing the 'index' key + # + # However, the overall data after parsing the whole + # stream, could be a mix of arrays and single data fields, + # all sharing the same field name due to how QEMU breaks + # up arrays with NULL pointers into multiple compressed + # array segments. + if fname not in self.data: + self.data[fname] = fdata + elif type(self.data[fname]) == list: + self.data[fname].append(fdata) else: - self.data[field['name']] = field['data'] + tmp = self.data[fname] + self.data[fname] = [tmp, fdata] if 'subsections' in self.desc['struct']: for subsection in self.desc['struct']['subsections']: From 7fb9ce40e75e06fe6d25c835830832e7c3940d03 Mon Sep 17 00:00:00 2001 From: Yuan Liu Date: Wed, 18 Dec 2024 17:14:11 +0800 Subject: [PATCH 25/58] multifd: bugfix for migration using compression methods When compression is enabled on the migration channel and the pages processed are all zero pages, these pages will not be sent and updated on the target side, resulting in incorrect memory data on the source and target sides. The root cause is that all compression methods call multifd_send_prepare_common to determine whether to compress dirty pages, but multifd_send_prepare_common does not update the IOV of MultiFDPacket_t when all dirty pages are zero pages. The solution is to always update the IOV of MultiFDPacket_t regardless of whether the dirty pages are all zero pages. Fixes: 303e6f54f9 ("migration/multifd: Implement zero page transmission on the multifd thread.") Cc: qemu-stable@nongnu.org #9.0+ Signed-off-by: Yuan Liu Reviewed-by: Jason Zeng Reviewed-by: Peter Xu Message-Id: <20241218091413.140396-2-yuan1.liu@intel.com> Signed-off-by: Fabiano Rosas (cherry picked from commit cdc3970f8597ebdc1a4c2090cfb4d11e297329ed) Signed-off-by: Michael Tokarev --- migration/multifd-nocomp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/migration/multifd-nocomp.c b/migration/multifd-nocomp.c index 55191152f9..2e4aaac285 100644 --- a/migration/multifd-nocomp.c +++ b/migration/multifd-nocomp.c @@ -362,6 +362,7 @@ int multifd_ram_flush_and_sync(void) bool multifd_send_prepare_common(MultiFDSendParams *p) { MultiFDPages_t *pages = &p->data->u.ram; + multifd_send_prepare_header(p); multifd_send_zero_page_detect(p); if (!pages->normal_num) { @@ -369,8 +370,6 @@ bool multifd_send_prepare_common(MultiFDSendParams *p) return false; } - multifd_send_prepare_header(p); - return true; } From fcd5a157e6b21412bafb146027eb74057e053271 Mon Sep 17 00:00:00 2001 From: Yuan Liu Date: Wed, 18 Dec 2024 17:14:12 +0800 Subject: [PATCH 26/58] multifd: bugfix for incorrect migration data with QPL compression When QPL compression is enabled on the migration channel and the same dirty page changes from a normal page to a zero page in the iterative memory copy, the dirty page will not be updated to a zero page again on the target side, resulting in incorrect memory data on the source and target sides. The root cause is that the target side does not record the normal pages to the receivedmap. The solution is to add ramblock_recv_bitmap_set_offset in target side to record the normal pages. Signed-off-by: Yuan Liu Reviewed-by: Jason Zeng Reviewed-by: Peter Xu Message-Id: <20241218091413.140396-3-yuan1.liu@intel.com> Signed-off-by: Fabiano Rosas (cherry picked from commit 2588a5f99b0c3493b4690e3ff01ed36f80e830cc) Signed-off-by: Michael Tokarev --- migration/multifd-qpl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/migration/multifd-qpl.c b/migration/multifd-qpl.c index bbe466617f..88e2344af2 100644 --- a/migration/multifd-qpl.c +++ b/migration/multifd-qpl.c @@ -679,6 +679,7 @@ static int multifd_qpl_recv(MultiFDRecvParams *p, Error **errp) qpl->zlen[i] = be32_to_cpu(qpl->zlen[i]); assert(qpl->zlen[i] <= multifd_ram_page_size()); zbuf_len += qpl->zlen[i]; + ramblock_recv_bitmap_set_offset(p->block, p->normal[i]); } /* read compressed pages */ From 9a17a650667bee2249310744b4508e9647b9a5bf Mon Sep 17 00:00:00 2001 From: Yuan Liu Date: Wed, 18 Dec 2024 17:14:13 +0800 Subject: [PATCH 27/58] multifd: bugfix for incorrect migration data with qatzip compression When QPL compression is enabled on the migration channel and the same dirty page changes from a normal page to a zero page in the iterative memory copy, the dirty page will not be updated to a zero page again on the target side, resulting in incorrect memory data on the source and target sides. The root cause is that the target side does not record the normal pages to the receivedmap. The solution is to add ramblock_recv_bitmap_set_offset in target side to record the normal pages. Signed-off-by: Yuan Liu Reviewed-by: Jason Zeng Reviewed-by: Peter Xu Message-Id: <20241218091413.140396-4-yuan1.liu@intel.com> Signed-off-by: Fabiano Rosas (cherry picked from commit a523bc52166c80d8a04d46584f9f3868bd53ef69) Signed-off-by: Michael Tokarev --- migration/multifd-qatzip.c | 1 + 1 file changed, 1 insertion(+) diff --git a/migration/multifd-qatzip.c b/migration/multifd-qatzip.c index 7b68397625..6a0e989fae 100644 --- a/migration/multifd-qatzip.c +++ b/migration/multifd-qatzip.c @@ -373,6 +373,7 @@ static int qatzip_recv(MultiFDRecvParams *p, Error **errp) /* Copy each page to its appropriate location. */ for (int i = 0; i < p->normal_num; i++) { memcpy(p->host + p->normal[i], q->out_buf + page_size * i, page_size); + ramblock_recv_bitmap_set_offset(p->block, p->normal[i]); } return 0; } From bb6940dbad20a90515fd53f901b370251e7a25df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 29 Dec 2024 09:34:19 +0100 Subject: [PATCH 28/58] tests/functional/test_rx_gdbsim: Use stable URL for test_linux_sash MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Yoshinori said [*] URL references on OSDN were stable, but they appear not to be. Mirror the artifacts on GitHub to avoid failures while testing on CI. [*] https://www.mail-archive.com/qemu-devel@nongnu.org/msg686487.html Cc: Yoshinori Sato Reported-by: Alex Bennée Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20200630202631.7345-1-f4bug@amsat.org> [huth: Adapt the patch to the new version in the functional framework] Message-ID: <20241229083419.180423-1-huth@tuxfamily.org> Signed-off-by: Thomas Huth (cherry picked from commit ec2dfb7c389b94d71ee825caa20b709d5df6c166) Signed-off-by: Michael Tokarev (Mjt: fixup for missing v9.2.0-421-g65d35a4e27a8 "tests/functional: convert tests to new uncompress helper") --- tests/functional/test_rx_gdbsim.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/tests/functional/test_rx_gdbsim.py b/tests/functional/test_rx_gdbsim.py index 5687f756bb..7daf1571c4 100755 --- a/tests/functional/test_rx_gdbsim.py +++ b/tests/functional/test_rx_gdbsim.py @@ -25,13 +25,16 @@ class RxGdbSimMachine(QemuSystemTest): KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 ' ASSET_UBOOT = Asset( - 'https://acc.dl.osdn.jp/users/23/23888/u-boot.bin.gz', - '7146567d669e91dbac166384b29aeba1715beb844c8551e904b86831bfd9d046') + ('https://github.com/philmd/qemu-testing-blob/raw/rx-gdbsim/rx/gdbsim/' + 'u-boot.bin'), + 'dd7dd4220cccf7aeb32227b26233bf39600db05c3f8e26005bcc2bf6c927207d') ASSET_DTB = Asset( - 'https://acc.dl.osdn.jp/users/23/23887/rx-virt.dtb', + ('https://github.com/philmd/qemu-testing-blob/raw/rx-gdbsim/rx/gdbsim/' + 'rx-gdbsim.dtb'), 'aa278d9c1907a4501741d7ee57e7f65c02dd1b3e0323b33c6d4247f1b32cf29a') ASSET_KERNEL = Asset( - 'http://acc.dl.osdn.jp/users/23/23845/zImage', + ('https://github.com/philmd/qemu-testing-blob/raw/rx-gdbsim/rx/gdbsim/' + 'zImage'), 'baa43205e74a7220ed8482188c5e9ce497226712abb7f4e7e4f825ce19ff9656') def test_uboot(self): @@ -40,9 +43,7 @@ class RxGdbSimMachine(QemuSystemTest): """ self.set_machine('gdbsim-r5f562n8') - uboot_path_gz = self.ASSET_UBOOT.fetch() - uboot_path = os.path.join(self.workdir, 'u-boot.bin') - gzip_uncompress(uboot_path_gz, uboot_path) + uboot_path = self.ASSET_UBOOT.fetch() self.vm.set_console() self.vm.add_args('-bios', uboot_path, From 48876bfc471ec02e5edcc935ba93e14426d891ab Mon Sep 17 00:00:00 2001 From: Keoseong Park Date: Tue, 7 Jan 2025 17:43:56 +0900 Subject: [PATCH 29/58] hw/ufs: Adjust value to match CPU's endian format MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In ufs_write_attr_value(), the value parameter is handled in the CPU's endian format but provided in big-endian format by the caller. Thus, it is converted to the CPU's endian format. The related test code is also fixed to reflect this change. Fixes: 7c85332a2b3e ("hw/ufs: minor bug fixes related to ufs-test") Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Keoseong Park Reviewed-by: Jeuk Kim Message-ID: <20250107084356epcms2p2af4d86432174d76ea57336933e46b4c3@epcms2p2> Signed-off-by: Philippe Mathieu-Daudé (cherry picked from commit 4572dacc33e232a7c951ba7ba7a20887fad29e71) Signed-off-by: Michael Tokarev --- hw/ufs/ufs.c | 2 +- tests/qtest/ufs-test.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/ufs/ufs.c b/hw/ufs/ufs.c index 79f786ed4e..7862bba908 100644 --- a/hw/ufs/ufs.c +++ b/hw/ufs/ufs.c @@ -1164,7 +1164,7 @@ static QueryRespCode ufs_exec_query_attr(UfsRequest *req, int op) value = ufs_read_attr_value(u, idn); ret = UFS_QUERY_RESULT_SUCCESS; } else { - value = req->req_upiu.qr.value; + value = be32_to_cpu(req->req_upiu.qr.value); ret = ufs_write_attr_value(u, idn, value); } req->rsp_upiu.qr.value = cpu_to_be32(value); diff --git a/tests/qtest/ufs-test.c b/tests/qtest/ufs-test.c index 60199abbee..1f860b41c0 100644 --- a/tests/qtest/ufs-test.c +++ b/tests/qtest/ufs-test.c @@ -145,7 +145,7 @@ static void ufs_send_query(QUfs *ufs, uint8_t slot, uint8_t query_function, req_upiu.qr.idn = idn; req_upiu.qr.index = index; req_upiu.qr.selector = selector; - req_upiu.qr.value = attr_value; + req_upiu.qr.value = cpu_to_be32(attr_value); req_upiu.qr.length = UFS_QUERY_DESC_MAX_SIZE; qtest_memwrite(ufs->dev.bus->qts, req_upiu_addr, &req_upiu, sizeof(req_upiu)); From 3b9b5cbe0ae0aa0e2fb166611d0d407df4a307e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 2 Jan 2025 10:59:31 +0100 Subject: [PATCH 30/58] tests/qtest/boot-serial-test: Correct HPPA machine name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 7df6f751176 ("hw/hppa: Split out machine creation") renamed the 'hppa' machine as 'B160L', but forgot to update the boot serial test, which ended being skipped. Cc: qemu-stable@nongnu.org Fixes: 7df6f751176 ("hw/hppa: Split out machine creation") Reported-by: Thomas Huth Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Reviewed-by: Thomas Huth Message-Id: <20250102100340.43014-2-philmd@linaro.org> (cherry picked from commit a87077316ed2f1c1c8ba8faf05feed9dbf0f2fee) Signed-off-by: Michael Tokarev --- tests/qtest/boot-serial-test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/qtest/boot-serial-test.c b/tests/qtest/boot-serial-test.c index 3b92fa5d50..7759e8c970 100644 --- a/tests/qtest/boot-serial-test.c +++ b/tests/qtest/boot-serial-test.c @@ -185,7 +185,7 @@ static const testdef_t tests[] = { sizeof(kernel_plml605), kernel_plml605 }, { "arm", "raspi2b", "", "TT", sizeof(bios_raspi2), 0, bios_raspi2 }, /* For hppa, force bios to output to serial by disabling graphics. */ - { "hppa", "hppa", "-vga none", "SeaBIOS wants SYSTEM HALT" }, + { "hppa", "B160L", "-vga none", "SeaBIOS wants SYSTEM HALT" }, { "aarch64", "virt", "-cpu max", "TT", sizeof(kernel_aarch64), kernel_aarch64 }, { "arm", "microbit", "", "T", sizeof(kernel_nrf51), kernel_nrf51 }, From 69e29c484f68e0c754a5da6772ebd769de1c7fbf Mon Sep 17 00:00:00 2001 From: Gabriel Barrantes Date: Sat, 28 Dec 2024 01:16:57 +0000 Subject: [PATCH 31/58] backends/cryptodev-vhost-user: Fix local_error leaks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Do not propagate error to the upper, directly output the error to avoid leaks. Fixes: 2fda101de07 ("virtio-crypto: Support asynchronous mode") Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2714 Signed-off-by: Gabriel Barrantes Reviewed-by: zhenwei pi Message-Id: Signed-off-by: Philippe Mathieu-Daudé (cherry picked from commit 78b0c15a563ac4be5afb0375602ca0a3adc6c442) Signed-off-by: Michael Tokarev --- backends/cryptodev-vhost-user.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/backends/cryptodev-vhost-user.c b/backends/cryptodev-vhost-user.c index e33fb78521..bb8b2c29b9 100644 --- a/backends/cryptodev-vhost-user.c +++ b/backends/cryptodev-vhost-user.c @@ -281,8 +281,7 @@ static int cryptodev_vhost_user_create_session( break; default: - error_setg(&local_error, "Unsupported opcode :%" PRIu32 "", - sess_info->op_code); + error_report("Unsupported opcode :%" PRIu32 "", sess_info->op_code); return -VIRTIO_CRYPTO_NOTSUPP; } From 4a3538e6f287b383daa82410769cec1b79e6df02 Mon Sep 17 00:00:00 2001 From: Phil Dennis-Jordan Date: Fri, 13 Dec 2024 17:06:14 +0100 Subject: [PATCH 32/58] hw/usb/hcd-xhci-pci: Use modulo to select MSI vector as per spec MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QEMU would crash with a failed assertion if the XHCI controller attempted to raise the interrupt on an interrupter corresponding to a MSI vector with a higher index than the highest configured for the device by the guest driver. This behaviour is correct on the MSI/PCI side: per PCI 3.0 spec, devices must ensure they do not send MSI notifications for vectors beyond the range of those allocated by the system/driver software. Unlike MSI-X, there is no generic way for handling aliasing in the case of fewer allocated vectors than requested, so the specifics are up to device implementors. (Section 6.8.3.4. "Sending Messages") It turns out the XHCI spec (Implementation Note in section 4.17, "Interrupters") requires that the host controller signal the MSI vector with the number computed by taking the interrupter number modulo the number of enabled MSI vectors. This change introduces that modulo calculation, fixing the failed assertion. This makes the device work correctly in MSI mode with macOS's XHCI driver, which only allocates a single vector. Signed-off-by: Phil Dennis-Jordan Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20250112210056.16658-2-phil@philjordan.eu> Signed-off-by: Philippe Mathieu-Daudé (cherry picked from commit bb5b7fced6b5d3334ab20702fc846e47bb1fb731) Signed-off-by: Michael Tokarev --- hw/usb/hcd-xhci-pci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/usb/hcd-xhci-pci.c b/hw/usb/hcd-xhci-pci.c index a039f5778a..516e6909d2 100644 --- a/hw/usb/hcd-xhci-pci.c +++ b/hw/usb/hcd-xhci-pci.c @@ -74,6 +74,7 @@ static bool xhci_pci_intr_raise(XHCIState *xhci, int n, bool level) } if (msi_enabled(pci_dev) && level) { + n %= msi_nr_vectors_allocated(pci_dev); msi_notify(pci_dev, n); return true; } From 91b2cb9a78ae3b0487497e004c660016bc7b7b44 Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Tue, 3 Dec 2024 13:19:28 +0100 Subject: [PATCH 33/58] pci: ensure valid link status bits for downstream ports PCI hotplug for downstream endpoints on arm fails because Linux' PCIe hotplug driver doesn't like the QEMU provided LNKSTA: pcieport 0000:08:01.0: pciehp: Slot(2): Card present pcieport 0000:08:01.0: pciehp: Slot(2): Link Up pcieport 0000:08:01.0: pciehp: Slot(2): Cannot train link: status 0x2000 There's 2 cases where LNKSTA isn't setup properly: * the downstream device has no express capability * max link width of the bridge is 0 Move the sanity checks added via 88c869198aa63 ("pci: Sanity test minimum downstream LNKSTA") outside of the branch to make sure downstream ports always have a valid LNKSTA. Signed-off-by: Sebastian Ott Tested-by: Zhenyu Zhang Message-Id: <20241203121928.14861-1-sebott@redhat.com> Reviewed-by: Alex Williamson Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin (cherry picked from commit 694632fd44987cc4618612a38ad151047524a590) Signed-off-by: Michael Tokarev --- hw/pci/pcie.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c index 0b455c8654..1b12db6fa2 100644 --- a/hw/pci/pcie.c +++ b/hw/pci/pcie.c @@ -1113,18 +1113,22 @@ void pcie_sync_bridge_lnk(PCIDevice *bridge_dev) if ((lnksta & PCI_EXP_LNKSTA_NLW) > (lnkcap & PCI_EXP_LNKCAP_MLW)) { lnksta &= ~PCI_EXP_LNKSTA_NLW; lnksta |= lnkcap & PCI_EXP_LNKCAP_MLW; - } else if (!(lnksta & PCI_EXP_LNKSTA_NLW)) { - lnksta |= QEMU_PCI_EXP_LNKSTA_NLW(QEMU_PCI_EXP_LNK_X1); } if ((lnksta & PCI_EXP_LNKSTA_CLS) > (lnkcap & PCI_EXP_LNKCAP_SLS)) { lnksta &= ~PCI_EXP_LNKSTA_CLS; lnksta |= lnkcap & PCI_EXP_LNKCAP_SLS; - } else if (!(lnksta & PCI_EXP_LNKSTA_CLS)) { - lnksta |= QEMU_PCI_EXP_LNKSTA_CLS(QEMU_PCI_EXP_LNK_2_5GT); } } + if (!(lnksta & PCI_EXP_LNKSTA_NLW)) { + lnksta |= QEMU_PCI_EXP_LNKSTA_NLW(QEMU_PCI_EXP_LNK_X1); + } + + if (!(lnksta & PCI_EXP_LNKSTA_CLS)) { + lnksta |= QEMU_PCI_EXP_LNKSTA_CLS(QEMU_PCI_EXP_LNK_2_5GT); + } + pci_word_test_and_clear_mask(exp_cap + PCI_EXP_LNKSTA, PCI_EXP_LNKSTA_CLS | PCI_EXP_LNKSTA_NLW); pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA, lnksta & From c8fb662a5817ee3267430ffdc711c6ec7a4cb11e Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Thu, 12 Dec 2024 22:04:02 +1000 Subject: [PATCH 34/58] pci/msix: Fix msix pba read vector poll end calculation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The end vector calculation has a bug that results in polling fewer than required vectors when reading at a non-zero offset in PBA memory. Fixes: bbef882cc193 ("msi: add API to get notified about pending bit poll") Signed-off-by: Nicholas Piggin Message-Id: <20241212120402.1475053-1-npiggin@gmail.com> Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin (cherry picked from commit 42e2a7a0ab23784e44fcb18369e06067abc89305) Signed-off-by: Michael Tokarev --- hw/pci/msix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/pci/msix.c b/hw/pci/msix.c index 487e49834e..cc6e79ec67 100644 --- a/hw/pci/msix.c +++ b/hw/pci/msix.c @@ -250,7 +250,7 @@ static uint64_t msix_pba_mmio_read(void *opaque, hwaddr addr, PCIDevice *dev = opaque; if (dev->msix_vector_poll_notifier) { unsigned vector_start = addr * 8; - unsigned vector_end = MIN(addr + size * 8, dev->msix_entries_nr); + unsigned vector_end = MIN((addr + size) * 8, dev->msix_entries_nr); dev->msix_vector_poll_notifier(dev, vector_start, vector_end); } From b107128ea6b3755e7ab5f9392ddffe8910caa9d0 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Wed, 15 Jan 2025 13:53:40 +0100 Subject: [PATCH 35/58] tests: acpi: whitelist expected blobs Signed-off-by: Igor Mammedov Message-Id: <20250115125342.3883374-2-imammedo@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin (cherry picked from commit 1ad32644fe4c9fb25086be15a66dde1d55d3410f) Signed-off-by: Michael Tokarev --- tests/qtest/bios-tables-test-allowed-diff.h | 40 +++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h index dfb8523c8b..085dfa9ff4 100644 --- a/tests/qtest/bios-tables-test-allowed-diff.h +++ b/tests/qtest/bios-tables-test-allowed-diff.h @@ -1 +1,41 @@ /* List of comma-separated changed AML files to ignore */ +"tests/data/acpi/x86/pc/DSDT", +"tests/data/acpi/x86/pc/DSDT.acpierst", +"tests/data/acpi/x86/pc/DSDT.acpihmat", +"tests/data/acpi/x86/pc/DSDT.bridge", +"tests/data/acpi/x86/pc/DSDT.cphp", +"tests/data/acpi/x86/pc/DSDT.dimmpxm", +"tests/data/acpi/x86/pc/DSDT.hpbridge", +"tests/data/acpi/x86/pc/DSDT.ipmikcs", +"tests/data/acpi/x86/pc/DSDT.memhp", +"tests/data/acpi/x86/pc/DSDT.nohpet", +"tests/data/acpi/x86/pc/DSDT.numamem", +"tests/data/acpi/x86/pc/DSDT.roothp", +"tests/data/acpi/x86/q35/DSDT", +"tests/data/acpi/x86/q35/DSDT.acpierst", +"tests/data/acpi/x86/q35/DSDT.acpihmat", +"tests/data/acpi/x86/q35/DSDT.acpihmat-generic-x", +"tests/data/acpi/x86/q35/DSDT.acpihmat-noinitiator", +"tests/data/acpi/x86/q35/DSDT.applesmc", +"tests/data/acpi/x86/q35/DSDT.bridge", +"tests/data/acpi/x86/q35/DSDT.core-count", +"tests/data/acpi/x86/q35/DSDT.core-count2", +"tests/data/acpi/x86/q35/DSDT.cphp", +"tests/data/acpi/x86/q35/DSDT.cxl", +"tests/data/acpi/x86/q35/DSDT.dimmpxm", +"tests/data/acpi/x86/q35/DSDT.ipmibt", +"tests/data/acpi/x86/q35/DSDT.ipmismbus", +"tests/data/acpi/x86/q35/DSDT.ivrs", +"tests/data/acpi/x86/q35/DSDT.memhp", +"tests/data/acpi/x86/q35/DSDT.mmio64", +"tests/data/acpi/x86/q35/DSDT.multi-bridge", +"tests/data/acpi/x86/q35/DSDT.nohpet", +"tests/data/acpi/x86/q35/DSDT.numamem", +"tests/data/acpi/x86/q35/DSDT.pvpanic-isa", +"tests/data/acpi/x86/q35/DSDT.thread-count", +"tests/data/acpi/x86/q35/DSDT.thread-count2", +"tests/data/acpi/x86/q35/DSDT.tis.tpm12", +"tests/data/acpi/x86/q35/DSDT.tis.tpm2", +"tests/data/acpi/x86/q35/DSDT.type4-count", +"tests/data/acpi/x86/q35/DSDT.viot", +"tests/data/acpi/x86/q35/DSDT.xapic", From 7170aa66aaf794c972c31d126235716b28f00cdd Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Wed, 15 Jan 2025 13:53:41 +0100 Subject: [PATCH 36/58] pci: acpi: Windows 'PCI Label Id' bug workaround Current versions of Windows call _DSM(func=7) regardless of whether it is supported or not. It leads to NICs having bogus 'PCI Label Id = 0', where none should be set at all. Also presence of 'PCI Label Id' triggers another Windows bug on localized versions that leads to hangs. The later bug is fixed in latest updates for 'Windows Server' but not in consumer versions of Windows (and there is no plans to fix it as far as I'm aware). Given it's easy, implement Microsoft suggested workaround (return invalid Package) so that affected Windows versions could boot on QEMU. This would effectvely remove bogus 'PCI Label Id's on NICs, but MS teem confirmed that flipping 'PCI Label Id' should not change 'Network Connection' ennumeration, so it should be safe for QEMU to change _DSM without any compat code. Smoke tested with WinXP and WS2022 Resolves: https://gitlab.com/qemu-project/qemu/-/issues/774 Signed-off-by: Igor Mammedov Message-Id: <20250115125342.3883374-3-imammedo@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin (cherry picked from commit 0b053391985abcc40b16ac8fc4a7f6588d1d95c1) Signed-off-by: Michael Tokarev --- hw/i386/acpi-build.c | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 9fcc2897b8..f7b961e04c 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -654,6 +654,7 @@ static Aml *aml_pci_pdsm(void) Aml *acpi_index = aml_local(2); Aml *zero = aml_int(0); Aml *one = aml_int(1); + Aml *not_supp = aml_int(0xFFFFFFFF); Aml *func = aml_arg(2); Aml *params = aml_arg(4); Aml *bnum = aml_derefof(aml_index(params, aml_int(0))); @@ -678,7 +679,7 @@ static Aml *aml_pci_pdsm(void) */ ifctx1 = aml_if(aml_lnot( aml_or(aml_equal(acpi_index, zero), - aml_equal(acpi_index, aml_int(0xFFFFFFFF)), NULL) + aml_equal(acpi_index, not_supp), NULL) )); { /* have supported functions */ @@ -704,18 +705,30 @@ static Aml *aml_pci_pdsm(void) { Aml *pkg = aml_package(2); - aml_append(pkg, zero); - /* - * optional, if not impl. should return null string - */ - aml_append(pkg, aml_string("%s", "")); - aml_append(ifctx, aml_store(pkg, ret)); - aml_append(ifctx, aml_store(aml_call2("AIDX", bnum, sunum), acpi_index)); + aml_append(ifctx, aml_store(pkg, ret)); /* - * update acpi-index to actual value + * Windows calls func=7 without checking if it's available, + * as workaround Microsoft has suggested to return invalid for func7 + * Package, so return 2 elements package but only initialize elements + * when acpi_index is supported and leave them uninitialized, which + * leads elements to being Uninitialized ObjectType and should trip + * Windows into discarding result as an unexpected and prevent setting + * bogus 'PCI Label' on the device. */ - aml_append(ifctx, aml_store(acpi_index, aml_index(ret, zero))); + ifctx1 = aml_if(aml_lnot(aml_lor( + aml_equal(acpi_index, zero), aml_equal(acpi_index, not_supp) + ))); + { + aml_append(ifctx1, aml_store(acpi_index, aml_index(ret, zero))); + /* + * optional, if not impl. should return null string + */ + aml_append(ifctx1, aml_store(aml_string("%s", ""), + aml_index(ret, one))); + } + aml_append(ifctx, ifctx1); + aml_append(ifctx, aml_return(ret)); } From 73ca3ba37d6c20174bc649663c8fc359e6fecda9 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Wed, 15 Jan 2025 13:53:42 +0100 Subject: [PATCH 37/58] tests: acpi: update expected blobs _DSM function 7 AML should have followig change: If ((Arg2 == 0x07)) { - Local0 = Package (0x02) - { - Zero, - "" - } Local2 = AIDX (DerefOf (Arg4 [Zero]), DerefOf (Arg4 [One] )) - Local0 [Zero] = Local2 + Local0 = Package (0x02) {} + If (!((Local2 == Zero) || (Local2 == 0xFFFFFFFF))) + { + Local0 [Zero] = Local2 + Local0 [One] = "" + } + Return (Local0) } } Signed-off-by: Igor Mammedov Message-Id: <20250115125342.3883374-4-imammedo@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin (cherry picked from commit 9fb1c9a1bb26e111ee5fa5538070cd684de14c08) Signed-off-by: Michael Tokarev (Mjt: regenerate acpi tables for 9.2) --- tests/data/acpi/x86/pc/DSDT | Bin 8526 -> 8544 bytes tests/data/acpi/x86/pc/DSDT.acpierst | Bin 8437 -> 8455 bytes tests/data/acpi/x86/pc/DSDT.acpihmat | Bin 9851 -> 9869 bytes tests/data/acpi/x86/pc/DSDT.bridge | Bin 15397 -> 15415 bytes tests/data/acpi/x86/pc/DSDT.cphp | Bin 8990 -> 9008 bytes tests/data/acpi/x86/pc/DSDT.dimmpxm | Bin 10180 -> 10198 bytes tests/data/acpi/x86/pc/DSDT.hpbridge | Bin 8477 -> 8495 bytes tests/data/acpi/x86/pc/DSDT.ipmikcs | Bin 8598 -> 8616 bytes tests/data/acpi/x86/pc/DSDT.memhp | Bin 9885 -> 9903 bytes tests/data/acpi/x86/pc/DSDT.nohpet | Bin 8384 -> 8402 bytes tests/data/acpi/x86/pc/DSDT.numamem | Bin 8532 -> 8550 bytes tests/data/acpi/x86/pc/DSDT.roothp | Bin 12319 -> 12337 bytes tests/data/acpi/x86/q35/DSDT | Bin 8355 -> 8373 bytes tests/data/acpi/x86/q35/DSDT.acpierst | Bin 8372 -> 8390 bytes tests/data/acpi/x86/q35/DSDT.acpihmat | Bin 9680 -> 9698 bytes .../data/acpi/x86/q35/DSDT.acpihmat-generic-x | Bin 12565 -> 12583 bytes .../acpi/x86/q35/DSDT.acpihmat-noinitiator | Bin 8634 -> 8652 bytes tests/data/acpi/x86/q35/DSDT.applesmc | Bin 8401 -> 8419 bytes tests/data/acpi/x86/q35/DSDT.bridge | Bin 11968 -> 11986 bytes tests/data/acpi/x86/q35/DSDT.core-count | Bin 12913 -> 12931 bytes tests/data/acpi/x86/q35/DSDT.core-count2 | Bin 33770 -> 33788 bytes tests/data/acpi/x86/q35/DSDT.cphp | Bin 8819 -> 8837 bytes tests/data/acpi/x86/q35/DSDT.cxl | Bin 13146 -> 13164 bytes tests/data/acpi/x86/q35/DSDT.dimmpxm | Bin 10009 -> 10027 bytes tests/data/acpi/x86/q35/DSDT.ipmibt | Bin 8430 -> 8448 bytes tests/data/acpi/x86/q35/DSDT.ipmismbus | Bin 8443 -> 8461 bytes tests/data/acpi/x86/q35/DSDT.ivrs | Bin 8372 -> 8390 bytes tests/data/acpi/x86/q35/DSDT.memhp | Bin 9714 -> 9732 bytes tests/data/acpi/x86/q35/DSDT.mmio64 | Bin 9485 -> 9503 bytes tests/data/acpi/x86/q35/DSDT.multi-bridge | Bin 13208 -> 13226 bytes tests/data/acpi/x86/q35/DSDT.nohpet | Bin 8213 -> 8231 bytes tests/data/acpi/x86/q35/DSDT.numamem | Bin 8361 -> 8379 bytes tests/data/acpi/x86/q35/DSDT.pvpanic-isa | Bin 8456 -> 8474 bytes tests/data/acpi/x86/q35/DSDT.thread-count | Bin 12913 -> 12931 bytes tests/data/acpi/x86/q35/DSDT.thread-count2 | Bin 33770 -> 33788 bytes tests/data/acpi/x86/q35/DSDT.tis.tpm12 | Bin 8961 -> 8979 bytes tests/data/acpi/x86/q35/DSDT.tis.tpm2 | Bin 8987 -> 9005 bytes tests/data/acpi/x86/q35/DSDT.type4-count | Bin 18589 -> 18607 bytes tests/data/acpi/x86/q35/DSDT.viot | Bin 14612 -> 14630 bytes tests/data/acpi/x86/q35/DSDT.xapic | Bin 35718 -> 35736 bytes tests/qtest/bios-tables-test-allowed-diff.h | 40 ------------------ 41 files changed, 40 deletions(-) diff --git a/tests/data/acpi/x86/pc/DSDT b/tests/data/acpi/x86/pc/DSDT index 8b8235fe79e2fa08a6f840c8479edb75f5a047b9..7fcbecc7991c9230cf2ab2ad7e33e2285655e2a1 100644 GIT binary patch delta 89 zcmX@-^uUSBCDk-)%Ez{}8)z_{6%Nm?EN8897b delta 71 zcmaFhbk2#(CD@l<112AliEnl=IdM*2#+a?7IysAry+DYSiGi0Pp}^78 aC8D__hk*e|Fft?+By}V(Y<6XmmInX<(-dg{ diff --git a/tests/data/acpi/x86/pc/DSDT.acpierst b/tests/data/acpi/x86/pc/DSDT.acpierst index 06829b9c6c6d726d955dc7c99bc9f42448e22aeb..5fb2b6376fdef3e9a8ce8861f8b333de01c154a8 100644 GIT binary patch delta 89 zcmezB*zUyT66_MfuE@Z^m^6{=0h6ET#5X&bT(~ALW6U-&pPa?TUf}5I64Bg|!@vL} r7#WfZgqWBT7D!E+I5~-7auUyfASg)cNMK+n;AQAYVBBoXbVv>W0=*r} delta 71 zcmZp7`s&E#66_N4Re^zlannSu2TVR96W{D$a^jr4j4@kDb#fLLdw~!u69X?pLV=^F aOGI-=4g&*_U}Q)tNa{#n*zC%5NDcrkCKby7 diff --git a/tests/data/acpi/x86/pc/DSDT.acpihmat b/tests/data/acpi/x86/pc/DSDT.acpihmat index 2fe355ebdbb858fa9247d09112e21712e3eddc45..51c70746c6c8ae33c48bf46e49a6f4ec2278feb4 100644 GIT binary patch delta 89 zcmezE)9cIS66_MvtH!{k-)%Ez{}8)z_{6%$wLJITN@sE delta 71 zcmeD6{q4i$66_LEt;WE>s5X)70h5oX&boH!>hW6V}kot(wRULeHE#K6mtP~hn4 a64Bg|!@vL}7#WfZk~$I?HoG!;r~m-^6%=^@ diff --git a/tests/data/acpi/x86/pc/DSDT.bridge b/tests/data/acpi/x86/pc/DSDT.bridge index 4d4067c182a6625db1e877408eb7436113884b50..ec920896faf05c5415ef4e485696a26a10d06d80 100644 GIT binary patch delta 89 zcmZ2lvAu%JCDk-)%Ez{}8)z_{6%>60Y@BO4xc delta 71 zcmdm9v9yBACDJ@YV diff --git a/tests/data/acpi/x86/pc/DSDT.cphp b/tests/data/acpi/x86/pc/DSDT.cphp index 045a52e75b7fcd4e5f840a758c548231498b96e4..b4d0f151ce4c21d7dd93d02aad29643d3cf3aea5 100644 GIT binary patch delta 89 zcmbQ|w!w|dCDk-)%Ez{}8)z_{6%>9qm?3v(VA delta 71 zcmdnsHqVXACDf|gg_5vYRCI()HgaSuT amx$($90mp;!N`zQkkpaDu-TPqqACC_0Tq`3 diff --git a/tests/data/acpi/x86/pc/DSDT.hpbridge b/tests/data/acpi/x86/pc/DSDT.hpbridge index 8fa8b519ec65bd5099c45f4e1c85b11b47a23845..8a410533d48ec34b174dcfe487b1fcb33cbc27b3 100644 GIT binary patch delta 89 zcmbR1wBCu!CDk-)%Ez{}8)z_{6%>6IJ+`1&2# delta 71 zcmZ4QG}npCCDf|gg_5vYRCI()HgaSuT amx$($90mp;!N`zQkkpaDu-TO2TVR96W{D$a^jr4j4@kDb#fLLdw~!u69X?pLV=^F aOGI-=4g&*_U}Q)tNa{#n*zC%br2+u{z7)3r diff --git a/tests/data/acpi/x86/pc/DSDT.nohpet b/tests/data/acpi/x86/pc/DSDT.nohpet index b081030f0ed171e52b13e28cfdc8770a04c2806e..c1aa156a877f171b072aba51e82d38d11ad20f2f 100644 GIT binary patch delta 89 zcmX@$c*&8=CDu1FqxnXzg^Wx-B9qrL?qG7_oSe>-t)x0Ri;KNLh?R+fmm#6R c(bFZOxg&>x0Z1@1Bo!oeBrt4dV_q){0OOhy?*IS* diff --git a/tests/data/acpi/x86/q35/DSDT.acpierst b/tests/data/acpi/x86/q35/DSDT.acpierst index 46fd25400b7c00ee9149ddb64cb5d5bd73f6a82b..88dd156d9532100d2f9003c06077cc399a84d5f0 100644 GIT binary patch delta 91 zcmdnuc+8Q@CDW5-6Wg^WyoqLbG$?qG7^nw-v*ZDKw-i;KO$(bFZOxg&>x t0Z1@1BozoTF(oXJnly2862s&qp8r5lkkpaDz)--;(2>Bn`3utlSpYG(9?}2+ delta 73 zcmX@+xW$pnCD3mKXGL?^Fh+`;6+H94Ir+r)fw78iSgqo+$mb4LyX t1CU^3NGcFwVoF#bHEH7HB!FW=;;#C+>yh; t03;Y0k_v>Fm=YF9O`144iD7aQ&wn5&Na{#nU?|{a=tyAP{DnzT4*>P09f|+| delta 73 zcmZ3UG&PCKCD-t)x0Ri;KNLh?R+fmm#6R c(bFZOxg&>x0Z1@1Bo!oeBrt4dV^-7y0Ox!YivR!s diff --git a/tests/data/acpi/x86/q35/DSDT.acpihmat-noinitiator b/tests/data/acpi/x86/q35/DSDT.acpihmat-noinitiator index 3aaa2bbdf54a0d0cade14421e84c6ec5a42f96fa..a9a7cec8d7e2830275bfc1b69fb4fa116ecc884b 100644 GIT binary patch delta 91 zcmdnxe8!o}CDx t0Z1@1BozoTF(oXJnly2862s&qp8r5lkkpaDz)--;(2>Bn`3uuAIRG)t9@YQ= delta 73 zcmX@(yvv!(CDu1F?B delta 73 zcmaFtc+ru|CD-t)x0Ri;KNLh?R+fmm#6R c(bFZOxg&>x0Z1@1Bo!oeBrt4dW4QdnuO7CDx t0Z1@1BozoTF(oXJnly2862s&qp8r5lkkpaDz)--;(2>Bn`3ut-Z2&G<9?}2+ delta 73 zcmcZ-t)x0Ri;KNLh?R+fmm#6R c(bFZOxg&>x0Z1@1Bo!oeBrt4dV?Lt|02J>O(*OVf diff --git a/tests/data/acpi/x86/q35/DSDT.core-count b/tests/data/acpi/x86/q35/DSDT.core-count index a24b04cbdbf09383b933a42a2a15182545543a87..d893781416b83305c3b0becc553f54fb04672fda 100644 GIT binary patch delta 91 zcmeyE(wxfW66_MvY{bC8n6Qy+AtRHY=;XDGJD6O!CZ{uHo0w0|;$kmw^mK`6?#N+a t01}K0Nd-boObH95CQY22#4tID=RXh>By}V(Fck1IbR;lt{=!tN4*)ER9*F<| delta 73 zcmZop{g}e#66_LEXvDz4xPBwoLPjPZk;!WrcQ83|PEKdaR#Kgu#l>DA#LC3L%aBmu c=;;#C+>yh;03;Y0k_wVK5*RkKG1uw?01^KbiU0rr diff --git a/tests/data/acpi/x86/q35/DSDT.core-count2 b/tests/data/acpi/x86/q35/DSDT.core-count2 index 3a0cb8c581c8cc630a2ec21712b7f8b75fcad1c8..ac87bc5db07e46285f4e42ca1d884905c8050cf6 100644 GIT binary patch delta 93 zcmaFW&h)39iOVI}CFD;t0|Voxja&;Enfyd2uVvi9Hy+=(CY)AtRHY=;XDGJD6O!CZ{uHo0w0|;$kmw^mK`6?#N+a t01}K0Nd-boObH95CQY22#4tID=RXh>By}V(Fck1IbR;lt{=!r*4*(4|9vuJx delta 73 zcmZp5{p`Z!66_LEti-^;IC~@4LPjPZk;!WrcQ83|PEKdaR#Kgu#l>DA#LC3L%aBmu c=;;#C+>yh;03;Y0k_wVK5*RkKG1toj0Qoo+9smFU diff --git a/tests/data/acpi/x86/q35/DSDT.cxl b/tests/data/acpi/x86/q35/DSDT.cxl index 3c34d4dcab16783abe65f6fa5e64eb69d40795fb..6d71a26fab6cc0b55675b65835232a562c5ee32d 100644 GIT binary patch delta 91 zcmcbW_9l(XCDFW=;;#C+>yh; t03;Y0k_v>Fm=YF9O`144iD7aQ&wn5&Na{#nU?|{a=tyAP{Dmpa001sL9&P{t delta 73 zcmaEpb}Nm`CDDA#LC3L%aBmu c=;;#C+>yh;03;Y0k_wVK5*RkKF{c>-02K)oZvX%Q diff --git a/tests/data/acpi/x86/q35/DSDT.dimmpxm b/tests/data/acpi/x86/q35/DSDT.dimmpxm index 228374b55bd544116e359f659e546fc66cf8a895..5a0ff97b9e1a680ab0bcde0cce4272b15cb6c214 100644 GIT binary patch delta 91 zcmbQ~x7v@(CDFW=;;#C+>yh; t03;Y0k_v>Fm=YF9O`144iD7aQ&wn5&Na{#nU?|{a=tyAP{DnzX1pw6?9UTAw delta 73 zcmZ4OH`9;HCDNE)LPjPZk;!WrcQ83|PEKdaR#Kgu#l>DA#LC3L%aBmu c=;;#C+>yh;03;Y0k_wVK5*RkKF{`Qo0M0QJ9smFU diff --git a/tests/data/acpi/x86/q35/DSDT.ipmibt b/tests/data/acpi/x86/q35/DSDT.ipmibt index 45f911ada5645f158f3d6c0c430ec1d52cadc5d8..a7e79e498335f3ffa1eb63c56b4a3bd9bcd5eed4 100644 GIT binary patch delta 91 zcmaFo*xBy}V(Fck1IbR;lt{=)Q2768uK9nSy& delta 73 zcmZp0dgsXH66_N4PJw}eF?%D|LPjPZk;!WrcQ83|PEKdaR#Kgu#l>DA#LC3L%aBmu c=;;#C+>yh;03;Y0k_wVK5*RkKG5?YU00{FG&;S4c diff --git a/tests/data/acpi/x86/q35/DSDT.ipmismbus b/tests/data/acpi/x86/q35/DSDT.ipmismbus index e5d6811bee1233d74236453c49060390d74d4416..075ac613d2ba1348775c2ac6c38c5e85221b577b 100644 GIT binary patch delta 91 zcmezE*z3gQ66_MftH{8>*t3yqAtRHY=;XDGJD6O!CZ{uHo0w0|;$kmw^mK`6?#N+a t01}K0Nd-boObH95CQY22#4tID=RXh>By}V(Fck1IbR;lt{=&pA2LSv(9d!Tz delta 73 zcmeBm`t8W&66_N4TY-Ur@y-t)x0Ri;KNLh?R+fmm#6R c(bFZOxg&>x0Z1@1Bo!oeBrt4dV`i5F04u2!b^rhX diff --git a/tests/data/acpi/x86/q35/DSDT.ivrs b/tests/data/acpi/x86/q35/DSDT.ivrs index 46fd25400b7c00ee9149ddb64cb5d5bd73f6a82b..88dd156d9532100d2f9003c06077cc399a84d5f0 100644 GIT binary patch delta 91 zcmdnuc+8Q@CDW5-6Wg^WyoqLbG$?qG7^nw-v*ZDKw-i;KO$(bFZOxg&>x t0Z1@1BozoTF(oXJnly2862s&qp8r5lkkpaDz)--;(2>Bn`3utlSpYG(9?}2+ delta 73 zcmX@+xW$pnCDFW=;;#C+>yh; t03;Y0k_v>Fm=YF9O`144iD7aQ&wn5&Na{#nU?|{a=tyAP{DtYC5&#su9=iYl delta 73 zcmZqi`Q**z66_N4NtJDA#LC3L%aBmu c=;;#C+>yh;03;Y0k_wVK5*RkKG5=En00Yq!yZ`_I diff --git a/tests/data/acpi/x86/q35/DSDT.mmio64 b/tests/data/acpi/x86/q35/DSDT.mmio64 index bdf36c4d575bfc4eb2eac3f00c9b7b4270f88677..3d5131761ced4fdb018671a363fd805a10251e8e 100644 GIT binary patch delta 91 zcmeD6n(xKs66_Kpugbu{IBO%FW=;;#C+>yh; t03;Y0k_v>Fm=YF9O`144iD7aQ&wn5&Na{#nU?|{a=tyAP{DnzU2>|T39b^Ci delta 73 zcmbR5)$7IO66_MftIEK@_;MrHLPjPZk;!WrcQ83|PEKdaR#Kgu#l>DA#LC3L%aBmu c=;;#C+>yh;03;Y0k_wVK5*RkKF-s}|0N>IRWdHyG diff --git a/tests/data/acpi/x86/q35/DSDT.multi-bridge b/tests/data/acpi/x86/q35/DSDT.multi-bridge index 1db43a69e4c2affd8bd678bbef4d3c228380288e..a98567b923e88bdd400ac1acd32fdb169e7e77ca 100644 GIT binary patch delta 91 zcmbP{zABx|CD-t)x0Ri;KNLh?R+fmm#6R c(bFZOxg&>x0Z1@1Bo!oeBrt4dV_sqa0Qo-@N&o-= diff --git a/tests/data/acpi/x86/q35/DSDT.nohpet b/tests/data/acpi/x86/q35/DSDT.nohpet index c13e45e3612646cc2e30f00b3b7e53335da816ea..a550cf23c0de681b6afdd7998872d9165b1c5dee 100644 GIT binary patch delta 91 zcmbR0u-t*mCDx t0Z1@1BozoTF(oXJnly2862s&qp8r5lkkpaDz)--;(2>Bn`3sYxECBOV9en@* delta 73 zcmZ4PFx7#}CDDA#LC3L%aBmu c=;;#C+>yh;03;Y0k_wVK5*RkKF)PXf0IA~=egFUf diff --git a/tests/data/acpi/x86/q35/DSDT.numamem b/tests/data/acpi/x86/q35/DSDT.numamem index ba6669437e65952f24516ded954b33fe54bdedfb..22b2a21705762f7afab457e7dd2d5fd06f8d7c84 100644 GIT binary patch delta 91 zcmZ4KxZ9D-CDb%7 diff --git a/tests/data/acpi/x86/q35/DSDT.pvpanic-isa b/tests/data/acpi/x86/q35/DSDT.pvpanic-isa index 6ad42873e91c80cef5a42224cb4d31936dad59b4..c26f9b1ba6f0c949e509c0028c7888ca6e4a768a 100644 GIT binary patch delta 91 zcmeBhn&rgh66_KprO3d*IBO%FW=;;#C+>yh; t03;Y0k_v>Fm=YF9O`144iD7aQ&wn5&Na{#nU?|{a=tyAP{DnzG4glb{9XJ30 delta 73 zcmbQ`)ZxVC66_Mfp~%3%_;MrHLPjPZk;!WrcQ83|PEKdaR#Kgu#l>DA#LC3L%aBmu c=;;#C+>yh;03;Y0k_wVK5*RkKF^k9n0MBy}V(Fck1IbR;lt{=!tN4*)ER9*F<| delta 73 zcmZop{g}e#66_LEXvDz4xPBwoLPjPZk;!WrcQ83|PEKdaR#Kgu#l>DA#LC3L%aBmu c=;;#C+>yh;03;Y0k_wVK5*RkKG1uw?01^KbiU0rr diff --git a/tests/data/acpi/x86/q35/DSDT.thread-count2 b/tests/data/acpi/x86/q35/DSDT.thread-count2 index 3a0cb8c581c8cc630a2ec21712b7f8b75fcad1c8..ac87bc5db07e46285f4e42ca1d884905c8050cf6 100644 GIT binary patch delta 93 zcmaFW&h)39iOVI}CFD;t0|Voxja&;Enfyd2uVvi9By}V(Fck1IbR;lt{=&qo006bo9HsyO delta 73 zcmbR2*67CN66_MfsLa5?n7)x~AtRHI$mF$*JD8j}C#N%IE2&P-;$kllVr63BWk@J+ b^mK`6?#N+a01}K0Nd-wA2@IRrn0XZdwM-JH diff --git a/tests/data/acpi/x86/q35/DSDT.tis.tpm2 b/tests/data/acpi/x86/q35/DSDT.tis.tpm2 index a09253042ce4a715922027245de8a2ab7449c5b7..b9c83bea1fb891eea31ab63f175a8898408ef596 100644 GIT binary patch delta 91 zcmbR3w$_cyCDx t0Z1@1BozoTF(oXJnly2862s&qp8r5lkkpaDz)--;(2>Bn`3sY}0ssi29moIx delta 73 zcmZ4MHrtKMCDDA#LC3L%aBmu c=;;#C+>yh;03;Y0k_wVK5*RkKF{>*80J?q>$p8QV diff --git a/tests/data/acpi/x86/q35/DSDT.type4-count b/tests/data/acpi/x86/q35/DSDT.type4-count index edc23198cdb47a981bcbc82bc8e392b815abb554..16b46775879d9a28090220e2ecd93fcba20a9c1b 100644 GIT binary patch delta 93 zcmbO`k#YS*MlP3Nmyq=y3=E7t8@U!TGWm&4Udy;*!sObomX e2?dUxE)mTgISdRyf{`JqAgLpPVKW=^N>>0sC>3o0 diff --git a/tests/data/acpi/x86/q35/DSDT.viot b/tests/data/acpi/x86/q35/DSDT.viot index 4c93dfd5c4b362714d3f9aa606a838d4625b3369..7cdde13b45d322855cfbb3894165d5c60dd20fa7 100644 GIT binary patch delta 91 zcmbPIw5*8BCDx t0Z1@1BozoTF(oXJnly2862s&qp8r5lkkpaDz)--;(2>Bn`3sYR82}&F9vA=s delta 73 zcmZ2hG^L2kCDDA#LC3L%aBmu c=;;#C+>yh;03;Y0k_wVK5*RkKF)Nq>0L>s182|tP diff --git a/tests/data/acpi/x86/q35/DSDT.xapic b/tests/data/acpi/x86/q35/DSDT.xapic index d4acd851c62c956436a436f9fa6d08fc5f370fa7..5a6310f45371c734fb03ac27bb864457eaeee7ad 100644 GIT binary patch delta 93 zcmZph&NO2>6PHV{OUR6F1_s7?8@U!TGWm&4Udy Date: Wed, 15 Jan 2025 15:58:34 +0800 Subject: [PATCH 38/58] hw/cxl: Fix msix_notify: Assertion `vector < dev->msix_entries_nr` This assertion always happens when we sanitize the CXL memory device. $ echo 1 > /sys/bus/cxl/devices/mem0/security/sanitize It is incorrect to register an MSIX number beyond the device's capability. Increase the device's MSIX number to cover the mailbox msix number(9). Fixes: 43efb0bfad2b ("hw/cxl/mbox: Wire up interrupts for background completion") Signed-off-by: Li Zhijian Message-Id: <20250115075834.167504-1-lizhijian@fujitsu.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin (cherry picked from commit 1ce979e7269a34d19ea1a65808df014d8b2acbf6) Signed-off-by: Michael Tokarev --- hw/mem/cxl_type3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/mem/cxl_type3.c b/hw/mem/cxl_type3.c index 5cf754b38f..7cf820e179 100644 --- a/hw/mem/cxl_type3.c +++ b/hw/mem/cxl_type3.c @@ -843,7 +843,7 @@ static void ct3_realize(PCIDevice *pci_dev, Error **errp) ComponentRegisters *regs = &cxl_cstate->crb; MemoryRegion *mr = ®s->component_registers; uint8_t *pci_conf = pci_dev->config; - unsigned short msix_num = 6; + unsigned short msix_num = 10; int i, rc; uint16_t count; From 1032dccadb647cf517c9ee57ffd7acca2f88df5d Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 19 Dec 2024 11:24:13 +0100 Subject: [PATCH 39/58] make-release: only leave tarball of wrap-file subprojects The QEMU source archive is including the sources downloaded from crates.io in both tarball form (in subprojects/packagecache) and expanded/patched form (in the subprojects directory). The former is the more authoritative form, as it has a hash that can be verified in the wrap file and checked against the download URL, so keep that one only. This works also with --disable-download; when building QEMU for the first time from the tarball, Meson will print something like Using proc-macro2-1-rs source from cache. for each subproject, and then go on to extract the tarball and apply the overlay or the patches in subprojects/packagefiles. Reported-by: Michael Tokarev Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2719 Signed-off-by: Paolo Bonzini (cherry picked from commit be27b5149c86f81531f8fc609baf3480fc4d9ca0) Signed-off-by: Michael Tokarev --- scripts/make-release | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/scripts/make-release b/scripts/make-release index 8dc939124c..2885e87210 100755 --- a/scripts/make-release +++ b/scripts/make-release @@ -10,6 +10,27 @@ # This work is licensed under the terms of the GNU GPLv2 or later. # See the COPYING file in the top-level directory. +function subproject_dir() { + if test ! -f "subprojects/$1.wrap"; then + error "scripts/archive-source.sh should only process wrap subprojects" + fi + + # Print the directory key of the wrap file, defaulting to the + # subproject name. The wrap file is in ini format and should + # have a single section only. There should be only one section + # named "[wrap-*]", which helps keeping the script simple. + local dir + dir=$(sed -n \ + -e '/^\[wrap-[a-z][a-z]*\]$/,/^\[/{' \ + -e '/^directory *= */!b' \ + -e 's///p' \ + -e 'q' \ + -e '}' \ + "subprojects/$1.wrap") + + echo "${dir:-$1}" +} + if [ $# -ne 2 ]; then echo "Usage:" echo " $0 gitrepo version" @@ -51,5 +72,13 @@ meson subprojects download $SUBPROJECTS CryptoPkg/Library/OpensslLib/openssl \ MdeModulePkg/Library/BrotliCustomDecompressLib/brotli) popd -tar --exclude=.git -cJf ${destination}.tar.xz ${destination} + +exclude=(--exclude=.git) +# include the tarballs in subprojects/packagecache but not their expansion +for sp in $SUBPROJECTS; do + if grep -xqF "[wrap-file]" subprojects/$sp.wrap; then + exclude+=(--exclude=subprojects/"$(subproject_dir $sp)") + fi +done +tar "${exclude[@]}" -cJf ${destination}.tar.xz ${destination} rm -rf ${destination} From 2f5f6cb90ab3b854044db773e418ef9867d9c9ff Mon Sep 17 00:00:00 2001 From: Zhao Liu Date: Wed, 6 Nov 2024 11:07:18 +0800 Subject: [PATCH 40/58] i386/cpu: Mark avx10_version filtered when prefix is NULL In x86_cpu_filter_features(), if host doesn't support AVX10, the configured avx10_version should be marked as filtered regardless of whether prefix is NULL or not. Check prefix before warn_report() instead of checking for have_filtered_features. Cc: qemu-stable@nongnu.org Fixes: commit bccfb846fd52 ("target/i386: add AVX10 feature and AVX10 version property") Signed-off-by: Zhao Liu Reviewed-by: Tao Su Link: https://lore.kernel.org/r/20241106030728.553238-2-zhao1.liu@intel.com Signed-off-by: Paolo Bonzini (cherry picked from commit cf4c263551886964c5d58bd7b675b13fd497b402) Signed-off-by: Michael Tokarev --- target/i386/cpu.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index aff5e917db..348771bd74 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -7719,8 +7719,10 @@ static bool x86_cpu_filter_features(X86CPU *cpu, bool verbose) env->avx10_version = version; have_filtered_features = true; } - } else if (env->avx10_version && prefix) { - warn_report("%s: avx10.%d.", prefix, env->avx10_version); + } else if (env->avx10_version) { + if (prefix) { + warn_report("%s: avx10.%d.", prefix, env->avx10_version); + } have_filtered_features = true; } From dcb80cd90832b11133f3c73706c63698f3b6e714 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Thu, 9 Jan 2025 09:37:46 +0000 Subject: [PATCH 41/58] crypto: fix bogus error benchmarking pbkdf on fast machines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We're seeing periodic reports of errors like: $ qemu-img create -f luks --object secret,data=123456,id=sec0 \ -o key-secret=sec0 luks-info.img 1M Formatting 'luks-info.img', fmt=luks size=1048576 key-secret=sec0 qemu-img: luks-info.img: Unable to get accurate CPU usage This error message comes from a recent attempt to workaround a kernel bug with measuring rusage in long running processes: commit c72cab5ad9f849bbcfcf4be7952b8b8946cc626e Author: Tiago Pasqualini Date: Wed Sep 4 20:52:30 2024 -0300 crypto: run qcrypto_pbkdf2_count_iters in a new thread Unfortunately this has a subtle bug on machines which are very fast. On the first time around the loop, the 'iterations' value is quite small (1 << 15), and so will run quite fast. Testing has shown that some machines can complete this benchmarking task in as little as 7 milliseconds. Unfortunately the 'getrusage' data is not updated at the time of the 'getrusage' call, it is done asynchronously by the scheduler. The 7 millisecond completion time for the benchmark is short enough that 'getrusage' sometimes reports 0 accumulated execution time. As a result the 'delay_ms == 0' sanity check in the above commit is triggering non-deterministically on such machines. The benchmarking loop intended to run multiple times, increasing the 'iterations' value until the benchmark ran for > 500 ms, but the sanity check doesn't allow this to happen. To fix it, we keep a loop counter and only run the sanity check after we've been around the loop more than 5 times. At that point the 'iterations' value is high enough that even with infrequent updates of 'getrusage' accounting data on fast machines, we should see a non-zero value. Fixes: https://lore.kernel.org/qemu-devel/ffe542bb-310c-4616-b0ca-13182f849fd1@redhat.com/ Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=2336437 Reported-by: Thomas Huth Reported-by: Richard W.M. Jones Tested-by: Thomas Huth Signed-off-by: Daniel P. Berrangé Message-ID: <20250109093746.1216300-1-berrange@redhat.com> Signed-off-by: Thomas Huth (cherry picked from commit 145f12ea885c8fcfbe2d0ac5230630f071b5a9fb) Signed-off-by: Michael Tokarev --- crypto/pbkdf.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/crypto/pbkdf.c b/crypto/pbkdf.c index 0dd7c3aeaa..2989fc0a40 100644 --- a/crypto/pbkdf.c +++ b/crypto/pbkdf.c @@ -107,7 +107,7 @@ static void *threaded_qcrypto_pbkdf2_count_iters(void *data) size_t nsalt = iters_data->nsalt; size_t nout = iters_data->nout; Error **errp = iters_data->errp; - + size_t scaled = 0; uint64_t ret = -1; g_autofree uint8_t *out = g_new(uint8_t, nout); uint64_t iterations = (1 << 15); @@ -131,7 +131,17 @@ static void *threaded_qcrypto_pbkdf2_count_iters(void *data) delta_ms = end_ms - start_ms; - if (delta_ms == 0) { /* sanity check */ + /* + * For very small 'iterations' values, CPU (or crypto + * accelerator) might be fast enough that the scheduler + * hasn't incremented getrusage() data, or incremented + * it by a very small amount, resulting in delta_ms == 0. + * Once we've scaled 'iterations' x10, 5 times, we really + * should be seeing delta_ms != 0, so sanity check at + * that point. + */ + if (scaled > 5 && + delta_ms == 0) { /* sanity check */ error_setg(errp, "Unable to get accurate CPU usage"); goto cleanup; } else if (delta_ms > 500) { @@ -141,6 +151,7 @@ static void *threaded_qcrypto_pbkdf2_count_iters(void *data) } else { iterations = (iterations * 1000 / delta_ms); } + scaled++; } iterations = iterations * 1000 / delta_ms; From c597e6f26d41cf17e3ecfaa12dccb5c85949eaaf Mon Sep 17 00:00:00 2001 From: Zhao Liu Date: Tue, 21 Jan 2025 23:43:18 +0800 Subject: [PATCH 42/58] stub: Fix build failure with --enable-user --disable-system --enable-tools Configuring "--enable-user --disable-system --enable-tools" causes the build failure with the following information: /usr/bin/ld: libhwcore.a.p/hw_core_qdev.c.o: in function `device_finalize': /qemu/build/../hw/core/qdev.c:688: undefined reference to `qapi_event_send_device_deleted' collect2: error: ld returned 1 exit status To fix the above issue, add qdev.c stub when build with `have_tools`. With this fix, QEMU could be successfully built in the following cases: --enable-user --disable-system --enable-tools --enable-user --disable-system --disable-tools --enable-user --disable-system Cc: qemu-stable@nongnu.org Fixes: 388b849fb6c3 ("stubs: avoid duplicate symbols in libqemuutil.a") Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2766 Signed-off-by: Zhao Liu Link: https://lore.kernel.org/r/20250121154318.214680-1-zhao1.liu@intel.com Signed-off-by: Paolo Bonzini (cherry picked from commit 8113dbbcdaee05f319a7e48272416d918cb2b04a) Signed-off-by: Michael Tokarev --- stubs/meson.build | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stubs/meson.build b/stubs/meson.build index e91614a874..a8b3aeb564 100644 --- a/stubs/meson.build +++ b/stubs/meson.build @@ -57,8 +57,8 @@ if have_user stub_ss.add(files('cpu-synchronize-state.c')) # Stubs for QAPI events. Those can always be included in the build, but - # they are not built at all for --disable-system --disable-tools builds. - if not (have_system or have_tools) + # they are not built at all for --disable-system builds. + if not have_system stub_ss.add(files('qdev.c')) endif endif From c806bbe8c161d0524648fc6fe024ceefbb833071 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 24 Jan 2025 16:27:23 +0000 Subject: [PATCH 43/58] target/arm: arm_reset_sve_state() should set FPSR, not FPCR The pseudocode ResetSVEState() does: FPSR = ZeroExtend(0x0800009f<31:0>, 64); but QEMU's arm_reset_sve_state() called vfp_set_fpcr() by accident. Before the advent of FEAT_AFP, this was only setting a collection of RES0 bits, which vfp_set_fpsr() would then ignore, so the only effect was that we didn't actually set the FPSR the way we are supposed to do. Once FEAT_AFP is implemented, setting the bottom bits of FPSR will change the floating point behaviour. Call vfp_set_fpsr(), as we ought to. (Note for stable backports: commit 7f2a01e7368f9 moved this function from sme_helper.c to helper.c, but it had the same bug before the move too.) Cc: qemu-stable@nongnu.org Fixes: f84734b87461 ("target/arm: Implement SMSTART, SMSTOP") Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20250124162836.2332150-4-peter.maydell@linaro.org (cherry picked from commit 1edc3d43f20df0d04f8d00b906ba19fed37512a5) Signed-off-by: Michael Tokarev --- target/arm/helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index f38eb054c0..fcb13fe87e 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -7362,7 +7362,7 @@ static void arm_reset_sve_state(CPUARMState *env) memset(env->vfp.zregs, 0, sizeof(env->vfp.zregs)); /* Recall that FFR is stored as pregs[16]. */ memset(env->vfp.pregs, 0, sizeof(env->vfp.pregs)); - vfp_set_fpcr(env, 0x0800009f); + vfp_set_fpsr(env, 0x0800009f); } void aarch64_set_svcr(CPUARMState *env, uint64_t new, uint64_t mask) From e82fbf01b61fef16fe0bd354198aeb42f920a4ba Mon Sep 17 00:00:00 2001 From: Hongren Zheng Date: Mon, 13 Jan 2025 17:38:56 +0800 Subject: [PATCH 44/58] hw/usb/canokey: Fix buffer overflow for OUT packet When USBPacket in OUT direction has larger payload than the ep_out_buffer (of size 512), a buffer overflow would occur. It could be fixed by limiting the size of usb_packet_copy to be at most buffer size. Further optimization gets rid of the ep_out_buffer and directly uses ep_out as the target buffer. This is reported by a security researcher who artificially constructed an OUT packet of size 2047. The report has gone through the QEMU security process, and as this device is for testing purpose and no deployment of it in virtualization environment is observed, it is triaged not to be a security bug. Cc: qemu-stable@nongnu.org Fixes: d7d34918551dc48 ("hw/usb: Add CanoKey Implementation") Reported-by: Juan Jose Lopez Jaimez Signed-off-by: Hongren Zheng Message-id: Z4TfMOrZz6IQYl_h@Sun Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell (cherry picked from commit 664280abddcb3cacc9c6204706bb739fcc1316f7) Signed-off-by: Michael Tokarev --- hw/usb/canokey.c | 6 +++--- hw/usb/canokey.h | 4 ---- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/hw/usb/canokey.c b/hw/usb/canokey.c index b306eeb20e..9af9d4da6e 100644 --- a/hw/usb/canokey.c +++ b/hw/usb/canokey.c @@ -197,8 +197,8 @@ static void canokey_handle_data(USBDevice *dev, USBPacket *p) switch (p->pid) { case USB_TOKEN_OUT: trace_canokey_handle_data_out(ep_out, p->iov.size); - usb_packet_copy(p, key->ep_out_buffer[ep_out], p->iov.size); out_pos = 0; + /* segment packet into (possibly multiple) ep_out */ while (out_pos != p->iov.size) { /* * key->ep_out[ep_out] set by prepare_receive @@ -207,8 +207,8 @@ static void canokey_handle_data(USBDevice *dev, USBPacket *p) * to be the buffer length */ out_len = MIN(p->iov.size - out_pos, key->ep_out_size[ep_out]); - memcpy(key->ep_out[ep_out], - key->ep_out_buffer[ep_out] + out_pos, out_len); + /* usb_packet_copy would update the pos offset internally */ + usb_packet_copy(p, key->ep_out[ep_out], out_len); out_pos += out_len; /* update ep_out_size to actual len */ key->ep_out_size[ep_out] = out_len; diff --git a/hw/usb/canokey.h b/hw/usb/canokey.h index e528889d33..1b60d73485 100644 --- a/hw/usb/canokey.h +++ b/hw/usb/canokey.h @@ -24,8 +24,6 @@ #define CANOKEY_EP_NUM 3 /* BULK/INTR IN can be up to 1352 bytes, e.g. get key info */ #define CANOKEY_EP_IN_BUFFER_SIZE 2048 -/* BULK OUT can be up to 270 bytes, e.g. PIV import cert */ -#define CANOKEY_EP_OUT_BUFFER_SIZE 512 typedef enum { CANOKEY_EP_IN_WAIT, @@ -59,8 +57,6 @@ typedef struct CanoKeyState { /* OUT pointer to canokey recv buffer */ uint8_t *ep_out[CANOKEY_EP_NUM]; uint32_t ep_out_size[CANOKEY_EP_NUM]; - /* For large BULK OUT, multiple write to ep_out is needed */ - uint8_t ep_out_buffer[CANOKEY_EP_NUM][CANOKEY_EP_OUT_BUFFER_SIZE]; /* Properties */ char *file; /* canokey-file */ From 7fd0224457aadf94176e4d94008db94cbdc8004a Mon Sep 17 00:00:00 2001 From: Steve Sistare Date: Wed, 15 Jan 2025 11:00:28 -0800 Subject: [PATCH 45/58] physmem: fix qemu_ram_alloc_from_fd size calculation qemu_ram_alloc_from_fd allocates space if file_size == 0. If non-zero, it uses the existing space and verifies it is large enough, but the verification was broken when the offset parameter was introduced. As a result, a file smaller than offset passes the verification and causes errors later. Fix that, and update the error message to include offset. Peter provides this concise reproducer: $ touch ramfile $ truncate -s 64M ramfile $ ./qemu-system-x86_64 -object memory-backend-file,mem-path=./ramfile,offset=128M,size=128M,id=mem1,prealloc=on qemu-system-x86_64: qemu_prealloc_mem: preallocating memory failed: Bad address With the fix, the error message is: qemu-system-x86_64: mem1 backing store size 0x4000000 is too small for 'size' option 0x8000000 plus 'offset' option 0x8000000 Cc: qemu-stable@nongnu.org Fixes: 4b870dc4d0c0 ("hostmem-file: add offset option") Signed-off-by: Steve Sistare Reviewed-by: Peter Xu Acked-by: David Hildenbrand Link: https://lore.kernel.org/r/1736967650-129648-3-git-send-email-steven.sistare@oracle.com Signed-off-by: Fabiano Rosas (cherry picked from commit 719168fba7c3215cc996dcfd32a6e5e9c7b8eee0) Signed-off-by: Michael Tokarev --- system/physmem.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/system/physmem.c b/system/physmem.c index dc1db3a384..75389064a8 100644 --- a/system/physmem.c +++ b/system/physmem.c @@ -1970,10 +1970,12 @@ RAMBlock *qemu_ram_alloc_from_fd(ram_addr_t size, MemoryRegion *mr, size = REAL_HOST_PAGE_ALIGN(size); file_size = get_file_size(fd); - if (file_size > offset && file_size < (offset + size)) { - error_setg(errp, "backing store size 0x%" PRIx64 - " does not match 'size' option 0x" RAM_ADDR_FMT, - file_size, size); + if (file_size && file_size < offset + size) { + error_setg(errp, "%s backing store size 0x%" PRIx64 + " is too small for 'size' option 0x" RAM_ADDR_FMT + " plus 'offset' option 0x%" PRIx64, + memory_region_name(mr), file_size, size, + (uint64_t)offset); return NULL; } From 066b9de4b3010c5071775d986487127772963664 Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich Date: Tue, 28 Jan 2025 01:12:42 +0100 Subject: [PATCH 46/58] target/s390x: Fix MVC not always invalidating translation blocks Node.js crashes in qemu-system-s390x with random SIGSEGVs / SIGILLs. The v8 JIT used by Node.js can garbage collect and overwrite unused code. Overwriting is performed by WritableJitAllocation::CopyCode(), which ultimately calls memcpy(). For certain sizes, memcpy() uses the MVC instruction. QEMU implements MVC and other similar instructions using helpers. While TCG store ops invalidate affected translation blocks automatically, helpers must do this manually by calling probe_access_flags(). The MVC helper does this using the access_prepare() -> access_prepare_nf() -> s390_probe_access() -> probe_access_flags() call chain. At the last step of this chain, the store size is replaced with 0. This causes the probe_access_flags() -> notdirty_write() -> tb_invalidate_phys_range_fast() chain to miss some translation blocks. When this happens, QEMU executes a mix of old and new code. This quickly leads to either a SIGSEGV or a SIGILL in case the old code ends in the middle of a new instruction. Fix by passing the true size. Reported-by: Berthold Gunreben Cc: Sarah Kriesch Cc: qemu-stable@nongnu.org Closes: https://bugzilla.opensuse.org/show_bug.cgi?id=1235709 Signed-off-by: Ilya Leoshkevich Reviewed-by: Richard Henderson Reviewed-by: David Hildenbrand Fixes: e2faabee78ff ("accel/tcg: Forward probe size on to notdirty_write") Message-ID: <20250128001338.11474-1-iii@linux.ibm.com> Signed-off-by: Thomas Huth (cherry picked from commit e43ced8be18dda77c229ab09f85136a4d600d40d) Signed-off-by: Michael Tokarev --- target/s390x/tcg/mem_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/s390x/tcg/mem_helper.c b/target/s390x/tcg/mem_helper.c index 0e12dae2aa..29ee5a8a07 100644 --- a/target/s390x/tcg/mem_helper.c +++ b/target/s390x/tcg/mem_helper.c @@ -146,7 +146,7 @@ static inline int s390_probe_access(CPUArchState *env, target_ulong addr, int mmu_idx, bool nonfault, void **phost, uintptr_t ra) { - int flags = probe_access_flags(env, addr, 0, access_type, mmu_idx, + int flags = probe_access_flags(env, addr, size, access_type, mmu_idx, nonfault, phost, ra); if (unlikely(flags & TLB_INVALID_MASK)) { From eec417351f6a2ff01aa077bda505783b2ae9dfc8 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Fri, 17 Jan 2025 12:17:08 +0100 Subject: [PATCH 47/58] net: Fix announce_self b9ad513e1876 ("net: Remove receive_raw()") adds an iovec entry in qemu_deliver_packet_iov() to add the virtio-net header in the data when QEMU_NET_PACKET_FLAG_RAW is set but forgets to increase the number of iovec entries in the array, so receive_iov() will only send the first entry (the virtio-net entry, full of 0) and no data. The packet will be discarded. The only user of QEMU_NET_PACKET_FLAG_RAW is announce_self. We can see the problem with tcpdump: - QEMU parameters: .. -monitor stdio \ -netdev bridge,id=netdev0,br=virbr0 \ -device virtio-net,mac=9a:2b:2c:2d:2e:2f,netdev=netdev0 \ - HMP command: (qemu) announce_self - TCP dump: $ sudo tcpdump -nxi virbr0 without the fix: with the fix: ARP, Reverse Request who-is 9a:2b:2c:2d:2e:2f tell 9a:2b:2c:2d:2e:2f, length 46 0x0000: 0001 0800 0604 0003 9a2b 2c2d 2e2f 0000 0x0010: 0000 9a2b 2c2d 2e2f 0000 0000 0000 0000 0x0020: 0000 0000 0000 0000 0000 0000 0000 Reported-by: Xiaohui Li Bug: https://issues.redhat.com/browse/RHEL-73891 Fixes: b9ad513e1876 ("net: Remove receive_raw()") Cc: akihiko.odaki@daynix.com Signed-off-by: Laurent Vivier Reviewed-by: Akihiko Odaki Reviewed-by: Michael Tokarev Signed-off-by: Michael Tokarev (cherry picked from commit 84dfdcbff33fff185528501be408c25c44499f32) Signed-off-by: Michael Tokarev --- net/net.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/net.c b/net/net.c index 7ef6885876..fefa701bb2 100644 --- a/net/net.c +++ b/net/net.c @@ -822,6 +822,7 @@ static ssize_t qemu_deliver_packet_iov(NetClientState *sender, iov_copy[0].iov_len = nc->vnet_hdr_len; memcpy(&iov_copy[1], iov, iovcnt * sizeof(*iov)); iov = iov_copy; + iovcnt++; } if (nc->info->receive_iov) { From 7dc66ede715410ef9f0e0e09d54c28b36da4dd95 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Fri, 17 Jan 2025 12:17:09 +0100 Subject: [PATCH 48/58] net/dump: Correctly compute Ethernet packet offset When a packet is sent with QEMU_NET_PACKET_FLAG_RAW by QEMU it never includes virtio-net header even if qemu_get_vnet_hdr_len() is not 0, and filter-dump is not managing this case. The only user of QEMU_NET_PACKET_FLAG_RAW is announce_self, we can show the problem using it and tcpddump: - QEMU parameters: .. -monitor stdio \ -netdev bridge,id=netdev0,br=virbr0 \ -device virtio-net,mac=9a:2b:2c:2d:2e:2f,netdev=netdev0 \ -object filter-dump,netdev=netdev0,file=log.pcap,id=pcap0 - HMP command: (qemu) announce_self - TCP dump: $ tcpdump -nxr log.pcap without the fix: 08:00:06:04:00:03 > 2e:2f:80:35:00:01, ethertype Unknown (0x9a2b), length 50: 0x0000: 2c2d 2e2f 0000 0000 9a2b 2c2d 2e2f 0000 0x0010: 0000 0000 0000 0000 0000 0000 0000 0000 0x0020: 0000 0000 with the fix: ARP, Reverse Request who-is 9a:2b:2c:2d:2e:2f tell 9a:2b:2c:2d:2e:2f, length 46 0x0000: 0001 0800 0604 0003 9a2b 2c2d 2e2f 0000 0x0010: 0000 9a2b 2c2d 2e2f 0000 0000 0000 0000 0x0020: 0000 0000 0000 0000 0000 0000 0000 Fixes: 481c52320a26 ("net: Strip virtio-net header when dumping") Cc: akihiko.odaki@daynix.com Signed-off-by: Laurent Vivier Reviewed-by: Akihiko Odaki Reviewed-by: Michael Tokarev Signed-off-by: Michael Tokarev (cherry picked from commit c6a1b591a68b4d7230d6c3f56965e18080d737e5) Signed-off-by: Michael Tokarev --- net/dump.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/dump.c b/net/dump.c index 956e34a123..42ab8d7716 100644 --- a/net/dump.c +++ b/net/dump.c @@ -155,7 +155,8 @@ static ssize_t filter_dump_receive_iov(NetFilterState *nf, NetClientState *sndr, { NetFilterDumpState *nfds = FILTER_DUMP(nf); - dump_receive_iov(&nfds->ds, iov, iovcnt, qemu_get_vnet_hdr_len(nf->netdev)); + dump_receive_iov(&nfds->ds, iov, iovcnt, flags & QEMU_NET_PACKET_FLAG_RAW ? + 0 : qemu_get_vnet_hdr_len(nf->netdev)); return 0; } From 4404720764db6e352cefe344be361308584d05d1 Mon Sep 17 00:00:00 2001 From: Dominik 'Disconnect3d' Czarnota Date: Mon, 20 Jan 2025 23:28:58 +0100 Subject: [PATCH 49/58] gdbstub/user-target: fix gdbserver int format (%d -> %x) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit fixes an incorrect format string for formatting integers provided to GDB when debugging a target run in QEMU user mode. The correct format is hexadecimal for both success and errno values, some of which can be seen here [0]. [0] https://github.com/bminor/binutils-gdb/blob/e65a355022d0dc6b5707310876a72b5693ec0aa5/gdbserver/hostio.cc#L196-L213 Signed-off-by: Dominik 'Disconnect3d' Czarnota Reviewed-by: Alex Bennée Fixes: e282010b2e1e ("gdbstub: Add support for info proc mappings") Cc: qemu-stable@nongnu.org Reviewed-by: Ilya Leoshkevich Reviewed-by: Michael Tokarev Signed-off-by: Michael Tokarev (cherry picked from commit 8b647bd352505234cab2acd2422aba183a1aa1fd) Signed-off-by: Michael Tokarev --- gdbstub/user-target.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/gdbstub/user-target.c b/gdbstub/user-target.c index 22bf4008c0..4bfcf78aaa 100644 --- a/gdbstub/user-target.c +++ b/gdbstub/user-target.c @@ -317,9 +317,9 @@ void gdb_handle_v_file_open(GArray *params, void *user_ctx) int fd = open(filename, flags, mode); #endif if (fd < 0) { - g_string_printf(gdbserver_state.str_buf, "F-1,%d", errno); + g_string_printf(gdbserver_state.str_buf, "F-1,%x", errno); } else { - g_string_printf(gdbserver_state.str_buf, "F%d", fd); + g_string_printf(gdbserver_state.str_buf, "F%x", fd); } gdb_put_strbuf(); } @@ -329,7 +329,7 @@ void gdb_handle_v_file_close(GArray *params, void *user_ctx) int fd = gdb_get_cmd_param(params, 0)->val_ul; if (close(fd) == -1) { - g_string_printf(gdbserver_state.str_buf, "F-1,%d", errno); + g_string_printf(gdbserver_state.str_buf, "F-1,%x", errno); gdb_put_strbuf(); return; } @@ -352,7 +352,7 @@ void gdb_handle_v_file_pread(GArray *params, void *user_ctx) ssize_t n = pread(fd, buf, bufsiz, offset); if (n < 0) { - g_string_printf(gdbserver_state.str_buf, "F-1,%d", errno); + g_string_printf(gdbserver_state.str_buf, "F-1,%x", errno); gdb_put_strbuf(); return; } @@ -375,7 +375,7 @@ void gdb_handle_v_file_readlink(GArray *params, void *user_ctx) ssize_t n = readlink(filename, buf, BUFSIZ); #endif if (n < 0) { - g_string_printf(gdbserver_state.str_buf, "F-1,%d", errno); + g_string_printf(gdbserver_state.str_buf, "F-1,%x", errno); gdb_put_strbuf(); return; } From a730f078e5799fad9027d9cf560bcf28ddeb1e73 Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Tue, 4 Feb 2025 16:12:52 -0700 Subject: [PATCH 50/58] ci: Fix Windows ccache key --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1f4d3f4a30..c73780fec8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -93,8 +93,8 @@ jobs: uses: actions/cache@v4 with: path: /tmp/xemu-ccache - key: cache-wincross-${{ runner.os }}-${{ matrix.configuration }}-${{ github.sha }} - restore-keys: cache-wincross-${{ runner.os }}-${{ matrix.configuration }}- + key: cache-wincross-${{ runner.os }}-${{ matrix.arch }}-${{ matrix.configuration }}-${{ github.sha }} + restore-keys: cache-wincross-${{ runner.os }}-${{ matrix.arch }}-${{ matrix.configuration }}- - name: Pull Docker image run: docker pull $DOCKER_IMAGE_NAME - name: Compile From 9f97cdc0270862a35e345e52952302da97980cae Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Tue, 4 Feb 2025 15:32:55 -0700 Subject: [PATCH 51/58] ci: Build AppImage for aarch64 --- .github/workflows/build.yml | 48 +++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c73780fec8..df98c4a121 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -163,28 +163,44 @@ jobs: path: dist Ubuntu: - name: Build for Ubuntu (${{ matrix.configuration }}) - runs-on: ubuntu-latest + name: Build for Ubuntu (${{matrix.arch}}, ${{ matrix.configuration }}) + runs-on: ${{ matrix.runs-on }} needs: Init strategy: matrix: include: - - configuration: Debug + - arch: x86_64 + configuration: Debug build_param: --debug - artifact_name: xemu-ubuntu-debug - artifact_filename: xemu-ubuntu-debug.tgz - - configuration: Release + artifact_name: xemu-ubuntu-x86_64-debug + artifact_filename: xemu-ubuntu-x86_64-debug.tgz + runs-on: ubuntu-24.04 + - arch: x86_64 + configuration: Release build_param: - artifact_name: xemu-ubuntu-release - artifact_filename: xemu-ubuntu-release.tgz + artifact_name: xemu-ubuntu-x86_64-release + artifact_filename: xemu-ubuntu-x86_64-release.tgz + runs-on: ubuntu-22.04 + - arch: aarch64 + configuration: Debug + build_param: --debug + artifact_name: xemu-ubuntu-aarch64-debug + artifact_filename: xemu-ubuntu-aarch64-debug.tgz + runs-on: ubuntu-24.04-arm + - arch: aarch64 + configuration: Release + build_param: + artifact_name: xemu-ubuntu-aarch64-release + artifact_filename: xemu-ubuntu-aarch64-release.tgz + runs-on: ubuntu-24.04-arm steps: - name: Initialize compiler cache id: cache uses: actions/cache@v4 with: path: /tmp/xemu-ccache - key: cache-${{ runner.os }}-${{ matrix.configuration }}-${{ github.sha }} - restore-keys: cache-${{ runner.os }}-${{ matrix.configuration }}- + key: cache-${{ runner.os }}-${{ matrix.arch }}-${{ matrix.configuration }}-${{ github.sha }} + restore-keys: cache-${{ runner.os }}-${{ matrix.arch }}-${{ matrix.configuration }}- - name: Download source package uses: actions/download-artifact@v4 with: @@ -231,8 +247,8 @@ jobs: ccache -s - name: Generate AppImage run: | - wget --no-verbose https://github.com/linuxdeploy/linuxdeploy/releases/latest/download/linuxdeploy-x86_64.AppImage - chmod +x linuxdeploy-x86_64.AppImage + wget --no-verbose https://github.com/linuxdeploy/linuxdeploy/releases/latest/download/linuxdeploy-${{ matrix.arch }}.AppImage + chmod +x linuxdeploy-${{ matrix.arch }}.AppImage ar x dist/*.deb mkdir appimage @@ -244,7 +260,7 @@ jobs: export VERSION=$VERSION-dbg fi - ./linuxdeploy-x86_64.AppImage --output appimage --appdir appimage + ./linuxdeploy-${{ matrix.arch }}.AppImage --output appimage --appdir appimage mv xemu-*.AppImage dist - name: Bundle artifacts run: | @@ -419,8 +435,10 @@ jobs: dist/xemu-win-x86_64-release-pdb/xemu-win-release.zip dist/xemu-macos-universal-release/xemu-macos-universal-release.zip dist/xemu-macos-universal-debug/xemu-macos-universal-debug.zip - dist/xemu-ubuntu-release/xemu/xemu-v${{ env.XEMU_VERSION }}-x86_64.AppImage - dist/xemu-ubuntu-debug/xemu/xemu-v${{ env.XEMU_VERSION }}-dbg-x86_64.AppImage + dist/xemu-ubuntu-x86_64-debug/xemu/xemu-v${{ env.XEMU_VERSION }}-dbg-x86_64.AppImage + dist/xemu-ubuntu-x86_64-release/xemu/xemu-v${{ env.XEMU_VERSION }}-x86_64.AppImage + dist/xemu-ubuntu-aarch64-debug/xemu/xemu-v${{ env.XEMU_VERSION }}-dbg-aarch64.AppImage + dist/xemu-ubuntu-aarch64-release/xemu/xemu-v${{ env.XEMU_VERSION }}-aarch64.AppImage - name: Trigger website update uses: benc-uk/workflow-dispatch@v1.2.2 with: From ac781ea8d1dcd7e67de62ea7ecaca60566e5e138 Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Tue, 4 Feb 2025 17:55:19 -0700 Subject: [PATCH 52/58] ci: Fix ubuntu artifact unpack --- .github/workflows/build.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index df98c4a121..4397db92b3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -404,13 +404,13 @@ jobs: echo "XEMU_VERSION=$(cat XEMU_VERSION)" >> $GITHUB_ENV - name: Extract Ubuntu artifacts run: | - pushd dist/xemu-ubuntu-release - tar xvf xemu-ubuntu-release.tgz - popd - - pushd dist/xemu-ubuntu-debug - tar xvf xemu-ubuntu-debug.tgz - popd + for arch in x86_64 aarch64; do + for config in release debug; do + pushd dist/xemu-ubuntu-$arch-$config + tar xvf xemu-ubuntu-$arch-$config.tgz + popd + done + done # Architecture tags were recently added to the Windows release path. Provide an alias with the former name for a while. - name: Add transitionary package alias run: | From cac3fb4414778eab741a5e58ca0a30f1edc9528a Mon Sep 17 00:00:00 2001 From: Michael Tokarev Date: Sat, 8 Feb 2025 14:26:21 +0300 Subject: [PATCH 53/58] Update version for 9.2.1 release Signed-off-by: Michael Tokarev --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index deeb3d66ef..45acc9e667 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -9.2.0 +9.2.1 From 0427ae8cfcf4d6b49aff3abf47dc7f6fe659880b Mon Sep 17 00:00:00 2001 From: coldhex Date: Sat, 15 Feb 2025 12:23:36 +0200 Subject: [PATCH 54/58] mcpx: Implement APU multipass voice processing Voice Processor (VP) multipass feature allows configuring lists of voices that are first mixed (in order) into a designated mixbin which is then used as a sample source when processing voices with multipass flag set to true in NV_PAVS_VOICE_CFG_FMT. Setting correct voice order in lists is the responsibility of the game/application and in practice is handled by the DirectSound library. The multipass mixbin is hardcoded to 31 in DirectSound, but hardware would allow other bins. This implementation also adds additional info to audio debug UI to see what the source and destination voices involved are. The info is only shown when DSP processing is off, i.e. "VP Only" (MON_VP) is selected. This is because storing the voice numbers requires additional digging which is required for MON_VP anyway and therefore is free. The multipass feature itself works fine with DSP (i.e. GP and EP) enabled, only the additional debug info is not shown. --- hw/xbox/mcpx/apu.c | 174 ++++++++++++++++++++++++++++++++++----- hw/xbox/mcpx/apu_debug.h | 2 + ui/xui/debug.cc | 40 ++++++++- 3 files changed, 193 insertions(+), 23 deletions(-) diff --git a/hw/xbox/mcpx/apu.c b/hw/xbox/mcpx/apu.c index 1b2b918323..ecace96ce3 100644 --- a/hw/xbox/mcpx/apu.c +++ b/hw/xbox/mcpx/apu.c @@ -218,7 +218,7 @@ static int voice_resample(MCPXAPUState *d, uint16_t v, float samples[][2], static void voice_reset_filters(MCPXAPUState *d, uint16_t v); static void voice_process(MCPXAPUState *d, float mixbins[NUM_MIXBINS][NUM_SAMPLES_PER_FRAME], - uint16_t v); + uint16_t v, int voice_list); static int voice_get_samples(MCPXAPUState *d, uint32_t v, float samples[][2], int num_samples_requested); static void se_frame(MCPXAPUState *d); @@ -245,6 +245,7 @@ static void mcpx_debug_begin_frame(void) { for (int i = 0; i < MCPX_HW_MAX_VOICES; i++) { g_dbg.vp.v[i].active = false; + g_dbg.vp.v[i].multipass_dst_voice = 0xFFFF; } } @@ -286,6 +287,19 @@ void mcpx_apu_debug_clear_isolations(void) static bool voice_should_mute(uint16_t v) { bool m = (g_dbg_voice_monitor >= 0) && (v != g_dbg_voice_monitor); + + if (m && g_dbg_cache.vp.v[g_dbg_voice_monitor].multipass) { + uint8_t mp_bin = g_dbg_cache.vp.v[g_dbg_voice_monitor].multipass_bin; + struct McpxApuDebugVoice *d = &g_dbg_cache.vp.v[v]; + + for (int i = 0; i < sizeof(d->bin) / sizeof(d->bin[0]); i++) { + if (d->bin[i] == mp_bin) { + m = false; + break; + } + } + } + return m || mcpx_apu_debug_is_muted(v); } @@ -1590,9 +1604,101 @@ static void voice_reset_filters(MCPXAPUState *d, uint16_t v) } } +static int peek_ahead_multipass_bin(MCPXAPUState *d, uint16_t v, + uint16_t *dst_voice) +{ + bool first = true; + + while (v != 0xFFFF) { + bool multipass = voice_get_mask(d, v, NV_PAVS_VOICE_CFG_FMT, + NV_PAVS_VOICE_CFG_FMT_MULTIPASS); + if (multipass) { + if (first) { + break; + } + + *dst_voice = v; + int mp_bin = voice_get_mask(d, v, NV_PAVS_VOICE_CFG_FMT, + NV_PAVS_VOICE_CFG_FMT_MULTIPASS_BIN); + return mp_bin; + } + + v = voice_get_mask(d, v, NV_PAVS_VOICE_TAR_PITCH_LINK, + NV_PAVS_VOICE_TAR_PITCH_LINK_NEXT_VOICE_HANDLE); + first = false; + } + + *dst_voice = 0xFFFF; + return -1; +} + +static void dump_multipass_unused_debug_info(MCPXAPUState *d, uint16_t v) +{ + unsigned int sample_size = voice_get_mask( + d, v, NV_PAVS_VOICE_CFG_FMT, NV_PAVS_VOICE_CFG_FMT_SAMPLE_SIZE); + unsigned int container_size_index = voice_get_mask( + d, v, NV_PAVS_VOICE_CFG_FMT, NV_PAVS_VOICE_CFG_FMT_CONTAINER_SIZE); + bool stream = voice_get_mask(d, v, NV_PAVS_VOICE_CFG_FMT, + NV_PAVS_VOICE_CFG_FMT_DATA_TYPE); + bool loop = + voice_get_mask(d, v, NV_PAVS_VOICE_CFG_FMT, NV_PAVS_VOICE_CFG_FMT_LOOP); + uint32_t ebo = voice_get_mask(d, v, NV_PAVS_VOICE_PAR_NEXT, + NV_PAVS_VOICE_PAR_NEXT_EBO); + uint32_t cbo = voice_get_mask(d, v, NV_PAVS_VOICE_PAR_OFFSET, + NV_PAVS_VOICE_PAR_OFFSET_CBO); + uint32_t lbo = voice_get_mask(d, v, NV_PAVS_VOICE_CUR_PSH_SAMPLE, + NV_PAVS_VOICE_CUR_PSH_SAMPLE_LBO); + uint32_t ba = voice_get_mask(d, v, NV_PAVS_VOICE_CUR_PSL_START, + NV_PAVS_VOICE_CUR_PSL_START_BA); + bool persist = voice_get_mask(d, v, NV_PAVS_VOICE_CFG_FMT, + NV_PAVS_VOICE_CFG_FMT_PERSIST); + bool linked = voice_get_mask(d, v, NV_PAVS_VOICE_CFG_FMT, + NV_PAVS_VOICE_CFG_FMT_LINKED); + + struct McpxApuDebugVoice *dbg = &g_dbg.vp.v[v]; + dbg->container_size = container_size_index; + dbg->sample_size = sample_size; + dbg->stream = stream; + dbg->loop = loop; + dbg->ebo = ebo; + dbg->cbo = cbo; + dbg->lbo = lbo; + dbg->ba = ba; + dbg->samples_per_block = 0; // Value overloaded with multipass bin + dbg->persist = persist; + dbg->linked = linked; +} + +static void get_multipass_samples(MCPXAPUState *d, + float mixbins[][NUM_SAMPLES_PER_FRAME], + uint16_t v, float samples[][2]) +{ + struct McpxApuDebugVoice *dbg = &g_dbg.vp.v[v]; + + // DirectSound sets bin to 31, but hardware would allow other bins + int mp_bin = voice_get_mask(d, v, NV_PAVS_VOICE_CFG_FMT, + NV_PAVS_VOICE_CFG_FMT_MULTIPASS_BIN); + dbg->multipass_bin = mp_bin; + + for (int i = 0; i < NUM_SAMPLES_PER_FRAME; i++) { + samples[i][0] = mixbins[mp_bin][i]; + samples[i][1] = mixbins[mp_bin][i]; + } + + // DirectSound sets clear mix to true + bool clear_mix = voice_get_mask(d, v, NV_PAVS_VOICE_CFG_FMT, + NV_PAVS_VOICE_CFG_FMT_CLEAR_MIX); + if (clear_mix) { + memset(&mixbins[mp_bin][0], 0, sizeof(mixbins[0])); + } + + // Dump irrelevant data for audio debug UI to avoid showing stale info + dump_multipass_unused_debug_info(d, v); +} + static void voice_process(MCPXAPUState *d, float mixbins[NUM_MIXBINS][NUM_SAMPLES_PER_FRAME], - uint16_t v) + uint16_t v, int voice_list) { assert(v < MCPX_HW_MAX_VOICES); bool stereo = voice_get_mask(d, v, NV_PAVS_VOICE_CFG_FMT, @@ -1633,18 +1739,28 @@ static void voice_process(MCPXAPUState *d, assert(ea_value <= 1.0f); float samples[NUM_SAMPLES_PER_FRAME][2] = { 0 }; - for (int sample_count = 0; sample_count < NUM_SAMPLES_PER_FRAME;) { - int active = voice_get_mask(d, v, NV_PAVS_VOICE_PAR_STATE, - NV_PAVS_VOICE_PAR_STATE_ACTIVE_VOICE); - if (!active) { - return; + + bool multipass = voice_get_mask(d, v, NV_PAVS_VOICE_CFG_FMT, + NV_PAVS_VOICE_CFG_FMT_MULTIPASS); + dbg->multipass = multipass; + + if (multipass) { + get_multipass_samples(d, mixbins, v, samples); + } else { + for (int sample_count = 0; sample_count < NUM_SAMPLES_PER_FRAME;) { + int active = voice_get_mask(d, v, NV_PAVS_VOICE_PAR_STATE, + NV_PAVS_VOICE_PAR_STATE_ACTIVE_VOICE); + if (!active) { + return; + } + int count = + voice_resample(d, v, &samples[sample_count], + NUM_SAMPLES_PER_FRAME - sample_count, rate); + if (count < 0) { + break; + } + sample_count += count; } - int count = voice_resample(d, v, &samples[sample_count], - NUM_SAMPLES_PER_FRAME - sample_count, rate); - if (count < 0) { - break; - } - sample_count += count; } int active = voice_get_mask(d, v, NV_PAVS_VOICE_PAR_STATE, @@ -1771,9 +1887,32 @@ static void voice_process(MCPXAPUState *d, /* For VP mon, simply mix all voices together here, selecting the * maximal volume used for any given mixbin as the overall volume for * this voice. + * + * If the current voice belongs to a multipass sub-voice group we must + * skip it here to avoid mixing it in twice because the sub-voices are + * mixed into the multipass bin and that sub-mix will be mixed in here + * later when the destination (i.e. second pass) voice is processed. + * TODO: Are the 2D, 3D and MP voice lists merely a DirectSound + * convention? Perhaps hardware doesn't care if e.g. a multipass + * voice is in the 2D or 3D list. On the other hand, MON_VP is + * not how the hardware works anyway so not much point worrying + * about precise emulation here. DirectSound compatibility is + * enough. */ + int mp_bin = -1; + uint16_t mp_dst_voice = 0xFFFF; + if (voice_list == NV1BA0_PIO_SET_ANTECEDENT_VOICE_LIST_MP_TOP - 1) { + mp_bin = peek_ahead_multipass_bin(d, v, &mp_dst_voice); + } + dbg->multipass_dst_voice = mp_dst_voice; + + bool debug_isolation = + g_dbg_voice_monitor >= 0 && g_dbg_voice_monitor == v; float g = 0.0f; for (int b = 0; b < 8; b++) { + if (bin[b] == mp_bin && !debug_isolation) { + continue; + } float hr = 1 << d->vp.submix_headroom[bin[b]]; g = fmax(g, attenuate(vol[b]) / hr); } @@ -1822,6 +1961,8 @@ static int voice_get_samples(MCPXAPUState *d, uint32_t v, float samples[][2], bool linked = voice_get_mask(d, v, NV_PAVS_VOICE_CFG_FMT, NV_PAVS_VOICE_CFG_FMT_LINKED); /* FIXME? */ + assert(!multipass); // Multipass is handled before this + int ssl_index = 0; int ssl_seg = 0; int page = 0; @@ -1954,11 +2095,6 @@ static int voice_get_samples(MCPXAPUState *d, uint32_t v, float samples[][2], DPRINTF("CBO=%d EBO=%d\n", cbo, ebo); - if (multipass) { - // FIXME - samples_per_block = 1; - } - block_size *= samples_per_block; // FIXME: Restructure this loop @@ -2147,7 +2283,7 @@ static void se_frame(MCPXAPUState *d) qemu_cond_wait(&d->cond, &d->lock); qemu_spin_lock(&d->vp.voice_spinlocks[v]); } - voice_process(d, mixbins, v); + voice_process(d, mixbins, v, list); qemu_spin_unlock(&d->vp.voice_spinlocks[v]); } d->regs[current] = d->regs[next]; diff --git a/hw/xbox/mcpx/apu_debug.h b/hw/xbox/mcpx/apu_debug.h index 8c99718d62..b67c258731 100644 --- a/hw/xbox/mcpx/apu_debug.h +++ b/hw/xbox/mcpx/apu_debug.h @@ -44,6 +44,8 @@ struct McpxApuDebugVoice bool persist; bool multipass; bool linked; + uint8_t multipass_bin; + uint16_t multipass_dst_voice; int container_size, sample_size; unsigned int samples_per_block; uint32_t ebo, cbo, lbo, ba; diff --git a/ui/xui/debug.cc b/ui/xui/debug.cc index 2d11eea2ed..fcc7a99cff 100644 --- a/ui/xui/debug.cc +++ b/ui/xui/debug.cc @@ -22,6 +22,8 @@ #include "font-manager.hh" #include "viewport-manager.hh" +#define MAX_VOICES 256 + DebugApuWindow::DebugApuWindow() : m_is_open(false) { } @@ -60,8 +62,7 @@ void DebugApuWindow::Draw() ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 0); ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2*g_viewport_mgr.m_scale, 2*g_viewport_mgr.m_scale)); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4*g_viewport_mgr.m_scale, 4*g_viewport_mgr.m_scale)); - for (int i = 0; i < 256; i++) - { + for (int i = 0; i < MAX_VOICES; i++) { if (i % 16) { ImGui::SameLine(); } @@ -132,8 +133,15 @@ void DebugApuWindow::Draw() assert(voice->container_size < 4); assert(voice->sample_size < 4); - ImGui::Text("Container Size: %s, Sample Size: %s, Samples per Block: %d", - cs[voice->container_size], ss[voice->sample_size], voice->samples_per_block); + const char *spb_or_bin_label = "Samples per Block"; + unsigned int spb_or_bin = voice->samples_per_block; + if (voice->multipass) { + spb_or_bin_label = "Multipass Bin"; + spb_or_bin = voice->multipass_bin; + } + ImGui::Text("Container Size: %s, Sample Size: %s, %s: %d", + cs[voice->container_size], ss[voice->sample_size], + spb_or_bin_label, spb_or_bin); ImGui::Text("Rate: %f (%d Hz)", voice->rate, (int)(48000.0/voice->rate)); ImGui::Text("EBO=%d CBO=%d LBO=%d BA=%x", voice->ebo, voice->cbo, voice->lbo, voice->ba); @@ -153,6 +161,30 @@ void DebugApuWindow::Draw() } ImGui::Text("%-17s", buf); } + + int mon = mcpx_apu_debug_get_monitor(); + if (mon == MCPX_APU_DEBUG_MON_VP) { + if (voice->multipass_dst_voice != 0xFFFF) { + ImGui::Text("Multipass Dest Voice: 0x%02x", + voice->multipass_dst_voice); + } + if (voice->multipass) { + ImGui::Text("Multipass Src Voices:"); + int n = 0; + + for (int i = 0; i < MAX_VOICES; i++) { + if (dbg->vp.v[i].multipass_dst_voice == voice_info) { + if (n > 0 && ((n & 7) == 0)) { + ImGui::Text(" "); + } + ImGui::SameLine(); + ImGui::Text("0x%02x", i); + n++; + } + } + } + } + ImGui::PopFont(); ImGui::EndTooltip(); } From 33046acd82c862ccd498eec2daf458edc85ba519 Mon Sep 17 00:00:00 2001 From: Daniel Cook <87423173+DCFUKSURMOM@users.noreply.github.com> Date: Sat, 15 Feb 2025 17:17:58 -0600 Subject: [PATCH 55/58] ui: Add 720x480 resolution to Window size options --- config_spec.yml | 2 +- ui/xemu.c | 1 + ui/xui/main-menu.cc | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/config_spec.yml b/config_spec.yml index 9d96b1f48f..d013c806ac 100644 --- a/config_spec.yml +++ b/config_spec.yml @@ -151,7 +151,7 @@ display: fullscreen_exclusive: bool startup_size: type: enum - values: [last_used, 640x480, 1280x720, 1280x800, 1280x960, 1920x1080, 2560x1440, 2560x1600, 2560x1920, 3840x2160] + values: [last_used, 640x480, 720x480, 1280x720, 1280x800, 1280x960, 1920x1080, 2560x1440, 2560x1600, 2560x1920, 3840x2160] default: 1280x960 last_width: type: integer diff --git a/ui/xemu.c b/ui/xemu.c index 645081d7e8..b602d25c09 100644 --- a/ui/xemu.c +++ b/ui/xemu.c @@ -731,6 +731,7 @@ static void sdl2_display_very_early_init(DisplayOptions *o) const int res_table[][2] = { {640, 480}, + {720, 480}, {1280, 720}, {1280, 800}, {1280, 960}, diff --git a/ui/xui/main-menu.cc b/ui/xui/main-menu.cc index d34c08b00e..d68138dceb 100644 --- a/ui/xui/main-menu.cc +++ b/ui/xui/main-menu.cc @@ -525,6 +525,7 @@ void MainMenuDisplayView::Draw() if (ChevronCombo("Window size", &g_config.display.window.startup_size, "Last Used\0" "640x480\0" + "720x480\0" "1280x720\0" "1280x800\0" "1280x960\0" From 65844f02e3f4d4c8bf19bcf30911c848bb0f9c7d Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Sat, 15 Feb 2025 16:23:37 -0700 Subject: [PATCH 56/58] meson: Update VulkanMemoryAllocator wrap --- subprojects/VulkanMemoryAllocator.wrap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subprojects/VulkanMemoryAllocator.wrap b/subprojects/VulkanMemoryAllocator.wrap index 26f6a0c8cd..b5f1c7f217 100644 --- a/subprojects/VulkanMemoryAllocator.wrap +++ b/subprojects/VulkanMemoryAllocator.wrap @@ -1,4 +1,4 @@ [wrap-git] url=https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator -revision=v3.2.0 +revision=v3.2.1 depth=1 From 906d085d665b527dc9f3870cd2c010c74a3701c2 Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Sat, 15 Feb 2025 16:30:36 -0700 Subject: [PATCH 57/58] meson: Update xxHash wrap --- subprojects/xxhash.wrap | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/subprojects/xxhash.wrap b/subprojects/xxhash.wrap index e4d612565f..77d05f6a96 100644 --- a/subprojects/xxhash.wrap +++ b/subprojects/xxhash.wrap @@ -1,13 +1,13 @@ [wrap-file] -directory = xxHash-0.8.2 -source_url = https://github.com/Cyan4973/xxHash/archive/v0.8.2.tar.gz -source_filename = xxHash-0.8.2.tar.gz -source_hash = baee0c6afd4f03165de7a4e67988d16f0f2b257b51d0e3cb91909302a26a79c4 -patch_filename = xxhash_0.8.2-1_patch.zip -patch_url = https://wrapdb.mesonbuild.com/v2/xxhash_0.8.2-1/get_patch -patch_hash = e721ef7a4c4ee0ade8b8440f6f7cb9f935b68e825249d74cb1c2503c53e68d25 -source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/xxhash_0.8.2-1/xxHash-0.8.2.tar.gz -wrapdb_version = 0.8.2-1 +directory = xxHash-0.8.3 +source_url = https://github.com/Cyan4973/xxHash/archive/v0.8.3.tar.gz +source_filename = xxHash-0.8.3.tar.gz +source_hash = aae608dfe8213dfd05d909a57718ef82f30722c392344583d3f39050c7f29a80 +patch_filename = xxhash_0.8.3-1_patch.zip +patch_url = https://wrapdb.mesonbuild.com/v2/xxhash_0.8.3-1/get_patch +patch_hash = 39c2418defa1d34cfe079c477b314b0a7a1bca657d91cdff4a05b8a7ed78aceb +source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/xxhash_0.8.3-1/xxHash-0.8.3.tar.gz +wrapdb_version = 0.8.3-1 [provide] libxxhash = xxhash_dep From 3bdb9e7fd4d6c9f5adec0543f1679d2943a0d092 Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Sat, 15 Feb 2025 16:33:54 -0700 Subject: [PATCH 58/58] ubuntu-win64-cross: Bump mxe/build-win64-mxe --- ubuntu-win64-cross/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ubuntu-win64-cross/Dockerfile b/ubuntu-win64-cross/Dockerfile index dfad7f7ff4..8741b629de 100644 --- a/ubuntu-win64-cross/Dockerfile +++ b/ubuntu-win64-cross/Dockerfile @@ -6,10 +6,10 @@ FROM ubuntu:24.04 ENV MXE_PATH=/opt/mxe ENV MXE_REPO=https://github.com/mxe/mxe.git -ENV MXE_VERSION=7f054f14930d109412d2d61d019c12fa80816b8c +ENV MXE_VERSION=866492387740cc6580ef516c8a746402be645453 ENV MXE_LLVM_MINGW_REPO=https://github.com/libvips/build-win64-mxe -ENV MXE_LLVM_MINGW_VERSION=8a4e0ab8a3b574287378459356f6bdaecc727de2 +ENV MXE_LLVM_MINGW_VERSION=32a2d0ecdfd3ea16bb4a99e333a8d5a3d63be491 ENV MXE_LLVM_MINGW_PATH=/opt/build-win64-mxe ARG PLUGIN_DIRS="${MXE_LLVM_MINGW_PATH} ${MXE_LLVM_MINGW_PATH}/build/plugins/llvm-mingw"