We're doing a wrong shift when calculating the offset for the
interrupt-pending bits, off by one right shift order.
This went undercover for awhile because the calculation works for
interrupt entities 1 to 63. The math goes wrong when using interrupt
entities 64 or greater.
Instead of fixing the issue and running we're also adding some notes
on where this calc comes from.
Fixes: 0c54acb8243d ("hw/riscv: add RISC-V IOMMU base emulation")
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3561 Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Acked-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260626220529.3800372-1-daniel.barboza@oss.qualcomm.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
The existing nomenclature can be misleading: regs_rw can cosplay as
'read and write' mask, in particular because we have regs_ro which is a
read only mask.
regs_rw is the current reg value, and all bits that aren't on the
regs_ro mask is considered r/w bits.
Rename regs_rw to 'regs' to be on par with the nomenclature other
devices uses (e.g. cadence_gem).
Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260625210833.3294437-2-daniel.barboza@oss.qualcomm.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Consolidate the common plic FDT code between 'virt' and sifive_u boards
into a single place.
Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260616235939.1358663-6-daniel.barboza@oss.qualcomm.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
The nodename must be 'interrupt-controller@...' since the node inherits
the 'interrupt-controller' type. In fact, ever since at least the 2020
Linux kernel commit c825a081c169cc7f ("dt-bindings: riscv: convert plic
bindings to json-schema") the correct nodename has been
'interrupt-controller' for the sifive PLIC controller.
There's no deprecation needed for bug fixes so we're just fixing the
name. This was the policy we dud when fixing the aplic [1] and the
imsic [2] nodenames to 'interrupt-controller@...' as well.
The sifive_u PLIC FDT already uses the correct nodename for PLIC, so it
is safe to assume that available SW is already aware of the correct
nodename and this change won't affect well-behaved SW.
[1] commit 29390fd ("hw/riscv/virt.c: rename aplic nodename to 'interrupt-controller'")
[2] commit e8ad581 ("hw/riscv/virt.c: change imsic nodename to 'interrupt-controller'")
Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260616235939.1358663-5-daniel.barboza@oss.qualcomm.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260616235939.1358663-4-daniel.barboza@oss.qualcomm.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
hw/riscv/sifive_u.c: use intc_phandle in plic creation
The info about intc_phandles for each CPU is already stored in the
intc_phandles array. We don't need to fetch them again using
qemu_fdt_get_phandle().
Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260616235939.1358663-3-daniel.barboza@oss.qualcomm.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
What this is doing is assigning a value to plic_phandle, then use that
as phandle of "nodename", and then fetching the phandle of "nodename"
again in the same variable that already had the right phandle val.
Here's how it looks like in gdb:
Thread 1 "qemu-system-ris" hit Breakpoint 1, create_fdt
(s=0xaaaaac162a30, memmap=0xaaaaab8f70c8 <sifive_u_memmap>,
is_32_bit=false) at ../hw/riscv/sifive_u.c:199
199 plic_phandle = phandle++;
(gdb) n
200 cells = g_new0(uint32_t, ms->smp.cpus * 4 - 2);
(gdb) p plic_phandle
$3 = 12
(gdb) c
Continuing.
Thread 1 "qemu-system-ris" hit Breakpoint 2, create_fdt
(s=0xaaaaac162a30, memmap=0xaaaaab8f70c8 <sifive_u_memmap>,
is_32_bit=false) at ../hw/riscv/sifive_u.c:232
232 plic_phandle = qemu_fdt_get_phandle(fdt, nodename);
(gdb) n
233 g_free(cells);
(gdb) p plic_phandle
$4 = 12
(gdb)
Remove the extra qemu_fdt_get_phandle() call.
Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260616235939.1358663-2-daniel.barboza@oss.qualcomm.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Meng Zhuo [Mon, 18 May 2026 10:21:18 +0000 (18:21 +0800)]
target/riscv/kvm: skip FP/Vector sync on KVM_PUT_RUNTIME_STATE
During KVM exit processing (KVM_PUT_RUNTIME_STATE), QEMU never modifies
FP or Vector registers — only core GPRs/PC and CSRs are potentially
changed. Re-syncing 32 FP and 32 Vector registers on every KVM exit
wastes 36-68 individual KVM_SET_ONE_REG ioctls per vCPU exit.
Follow the s390x pattern: early return on RUNTIME after syncing core
registers and CSRs. KVM_PUT_FULL_STATE and KVM_PUT_RESET_STATE continue
to sync everything for correctness during migration and initialization.
Signed-off-by: Meng Zhuo <mengzhuo@iscas.ac.cn> Acked-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Chao Liu <chao.liu.zevorn@gmail.com>
Message-ID: <20260518102118.2768383-1-mengzhuo@iscas.ac.cn> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Qingwei Hu [Mon, 15 Jun 2026 13:19:25 +0000 (21:19 +0800)]
hw/intc: riscv_imsic: Skip reset for KVM irqchip
The emulated IMSIC state arrays are only allocated when QEMU handles
the interrupt controller state itself. With KVM AIA/APLIC-IMSIC, the
interrupt controller state is owned by the KVM in-kernel irqchip, so
these emulated state arrays are not allocated.
The IMSIC reset handler still clears those arrays unconditionally. This
makes qemu_system_reset(), which runs during machine creation,
dereference NULL pointers with -machine virt,aia=aplic-imsic and KVM.
Skip the emulated IMSIC reset path when the interrupt controller is
handled by KVM. The emulated path is unchanged for TCG and for
configurations that use QEMU emulation.
Fixes: 766391483b ("hw/intc: riscv_imsic: Add reset API to IMSIC") Reviewed-by: Nutty Liu <nutty.liu@hotmail.com> Signed-off-by: Qingwei Hu <qingwei.hu@bytedance.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260615131925.3019370-3-qingwei.hu@bytedance.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Qingwei Hu [Mon, 15 Jun 2026 13:19:24 +0000 (21:19 +0800)]
hw/intc: riscv_aplic: Skip reset for KVM irqchip
The emulated APLIC state arrays are only allocated when QEMU handles
the interrupt controller state itself. With KVM AIA/APLIC-IMSIC, the
interrupt controller state is owned by the KVM in-kernel irqchip, so
these emulated state arrays are not allocated.
The APLIC reset handler still clears those arrays unconditionally. This
makes qemu_system_reset(), which runs during machine creation,
dereference NULL pointers with -machine virt,aia=aplic-imsic and KVM.
Skip the emulated APLIC reset path when the interrupt controller is
handled by KVM. The emulated path is unchanged for TCG and for
configurations that use QEMU emulation.
Fixes: 99bfcd329a ("hw/intc: riscv_aplic: Add reset API to APLIC") Reviewed-by: Nutty Liu <nutty.liu@hotmail.com> Signed-off-by: Qingwei Hu <qingwei.hu@bytedance.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260615131925.3019370-2-qingwei.hu@bytedance.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
ZhengXiang Qin [Mon, 15 Jun 2026 13:24:33 +0000 (21:24 +0800)]
target/riscv: avoid abort when reading vtype before env->xl is set
TCG plugins may read registers from the vcpu_init_cb() callback. For
vtype, this reaches read_vtype() before env->xl has been initialized.
In that case read_vtype() currently hits g_assert_not_reached() because
env->xl is zero. Fall back to the CPU's maximum XLEN only for this
early-init case.
Fixes: 638181a180bd ("core/cpu-common: initialise plugin state before thread creation")
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/3545 Signed-off-by: ZhengXiang Qin <qinzhengxiang@foxmail.com> Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Message-ID: <tencent_FB929239B227F05F30D62745E38BA01D4307@qq.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Qingwei Hu [Thu, 4 Jun 2026 12:00:17 +0000 (20:00 +0800)]
hw/riscv/virt-acpi-build: Fix RINTC PLIC context ID for KVM
Each RISC-V MADT RINTC entry contains an External Interrupt Controller
ID field. On the virt machine without AIA, this field identifies the
S-mode PLIC context associated with the hart.
TCG virt has both M-mode and S-mode PLIC contexts, so the S-mode context
ID is odd and 2 * local_cpu_id + 1 is correct. KVM virt exposes only
S-mode PLIC contexts, and those contexts are numbered contiguously from
0. Reporting the TCG context ID for KVM makes the guest enable a
different PLIC context from the one used by QEMU.
With ACPI enabled, this can leave PCI INTx interrupts pending in QEMU
while the guest-programmed PLIC context remains disabled. A virtio-blk
root disk can then stall during boot because its first interrupt is never
delivered.
Use local_cpu_id for KVM and keep the existing odd S-mode context ID for
TCG.
Fixes: d641da6ed43 ("hw/riscv/virt-acpi-build.c: Add PLIC in MADT") Signed-off-by: Qingwei Hu <qingwei.hu@bytedance.com> Reviewed-by: Nutty Liu <nutty.liu@hotmail.com> Reviewed-by: Sunil V L <sunilvl@oss.qualcomm.com>
Message-ID: <20260604120017.398890-1-qingwei.hu@bytedance.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Seems like we forgot to add a flag to set satp-mode=bare. What we're
doing instead is to set the CPU default satp-mode to 'off' to set it to
bare ... assuming we know the default satp-mode. Otherwise one needs to
do -cpu X,sv39=off,sv48=off,sv57=off,sv64=off to get a bare-mode CPU.
Add a flag to make this process easier. The name choice is based on the
fact that I didn't find many references to 'mbare' in RISC-V docs, but
'svbare' is a flag name that toolchain uses to set satp-mode=bare.
Might as well use the same name to help with cross project compat.
Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Message-ID: <20260611162223.2361941-2-daniel.barboza@oss.qualcomm.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
All CPUs have the same amount of triggers: 2 triggers per hart, set via
RV_MAX_TRIGGERS. This is not enough anymore: we'll have at least one
future CPU that will demand more triggers per hart when implementing the
RISC-V Server Ref Platform, requiring at least 11 triggers per hart.
Parametrize the trigger amount using a new 'num_triggers' property. The
default amount is kept at 2 for backwards compatibility. The new
maximum is bumped to a generous 1024 triggers per hart, which hopefully
will be enough for the foreseeable future.
The property can be set in two ways:
- a '.num_triggers' CPU definition flag, allowing CPUs to set a custom
amount inside the CPU def in DEFINE_RISCV_CPU();
- a new 'num-triggers' user property. The user property has a higher
priority than an existing '.num_triggers' CPU def setting.
Assuming a hypothetical case where a CPU 'X' is defined with
'.num_triggers = 8':
- -cpu X,num-triggers=30 => num_triggers set to 30
- -cpu X (...) => num_triggers set to 8
For a CPU that doesn't set '.num_triggers':
- -cpu rv64,num-triggers=30 => num_triggers set to 30
- -cpu rv64 (...) => num_triggers set to 2
Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260617131710.1855353-4-daniel.barboza@oss.qualcomm.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
target/riscv: dynamic alloc of debug trigger arrays
The debug trigger facility consists of a set of arrays: tdata1-3,
cpu_breakpoint, cpu_watchpoint and itrigger_timer. All of them are
static allocated with RV_MAX_TRIGGERS (2). This means that all RISC-V
cpus will have 2 triggers per hart.
The RISC-V Server Ref demands at least 11 triggers per hart, and several
CPUs in the wild works with 4+ triggers. We need more flexibility, ergo
we need to parametrize the amount of triggers and make it configurable.
Before doing that we need to handle a situation faced in a previous
attempt [1]. We were unable to set the tdataN array length in
vmstate_debug, meaning that we would always migrate RV_MAX_TRIGGERS
regardless of the actual amount of triggers in play. To fix that we need
to change the tdata arrays from static to dynamic, allowing us to use
VMSTATE_VARRAY_UINT32(). This also means that, in contrast with [1], we
have the opportunity to turn all trigger arrays into dynamic allocation
and reduce the amount of stuff being carried by CPURISCVState, or in
other words, we can carry just what we're using instead of a static max
value.
All the forementioned trigger facility arrays are now dynamic. They are
allocated and freed during realize/unrealize, and their size is
expressed by env->num_triggers. All relevant code is changed to use
env->num_triggers instead of the RV_MAX_TRIGGERS to loop through each
array.
This will make it easier for the next patch to parametrize
env->num_triggers.
Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260617131710.1855353-3-daniel.barboza@oss.qualcomm.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Next patch is going to dynamically allocate debug trigger arrays during
realize() time. We need a way of freeing them during unrealize(), which
doesn't exist at this moment.
There's a lot going on in that patch already so we're adding the
callback infrastructure beforehand.
Suggested-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com> Signed-off-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20260617131710.1855353-2-daniel.barboza@oss.qualcomm.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Joel Stanley [Wed, 17 Jun 2026 05:39:28 +0000 (15:09 +0930)]
tests/functional/riscv64: Add virt machine AIA boot test
Add coverage of the riscv64 virt machine's Advanced Interrupt
Architecture models. With this the APLIC and IMSIC models are used by
Linux, catching regressions.
This test requires a kernel >= 6.10, as AIA drivers were added to Linux
in 6.10.
Boot time is ~5s on a laptop.
Signed-off-by: Joel Stanley <joel@jms.id.au> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Message-ID: <20260617054034.1020724-4-joel@jms.id.au> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Joel Stanley [Wed, 17 Jun 2026 05:39:27 +0000 (15:09 +0930)]
tests/functional/riscv64: Use newer kernel for tuxrun boot
The published tuxrun kernel is 6.4 which predates the introduction of
AIA support in Linux. Update it to a 6.11 kernel, the newest build
on the tuxrun site.
Boot times on a laptop are slightly longer but still reasonable:
Signed-off-by: Joel Stanley <joel@jms.id.au> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Message-ID: <20260617054034.1020724-3-joel@jms.id.au> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Joel Stanley [Wed, 17 Jun 2026 05:39:26 +0000 (15:09 +0930)]
target/riscv: Avoid NULL deref in IMSIC CSR write
rmw_xireg_aia() and rmw_xtopei() were changed to store the IMSIC
callback's value in a local before passing it back to the caller.
For write only CSR accesses that pointer is NULL, causing a crash when
guest programs write to xireg or xtopei, such as when the guest sets up
the IMSIC.
This only happens when setting aia=aplic-imsic so none of the existing
boot tests caught it.
Fix it by guarding the pointer dereference as done for other CSRs.
Fixes: 63469ad75dcc ("target/riscv: Fix arguments to board IMSIC emulation callbacks") Signed-off-by: Joel Stanley <joel@jms.id.au> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Anton Johansson <anjo@rev.ng> Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Message-ID: <20260617054034.1020724-2-joel@jms.id.au> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Jeuk Kim [Fri, 26 Jun 2026 08:04:17 +0000 (17:04 +0900)]
hw/ufs: Populate cqe.task_tag for UFSHCI 4.1 tag decoding
In UFSHCI 4.1 the MCQ completion queue entry carries the request tag in
the cqe.task_tag field (DW5), whereas 4.0 hosts derive it from the UTP
command descriptor base address. The device reports version 4.1 in the VER
register but left task_tag/lun zero in the completion path, so a
4.1-compliant host reads tag 0 for every completion and cannot match it to
the outstanding request.
Add the task_tag/lun/iid fields to UfsCqEntry per the UFSHCI 4.1 CQE
layout and populate them from the request UPIU header.
For example, the Linux ufshcd_mcq_get_tag() uses cqe.task_tag for
version >= 4.1, so without this SCSI commands hung (e.g. INQUIRY to the
device W-LUN) while device-management commands still completed.
Jeuk Kim [Fri, 26 Jun 2026 07:30:30 +0000 (16:30 +0900)]
hw/ufs: Emulate DME_GET/SET for PA layer attributes
After DME_LINK_STARTUP a UFSHCI host typically negotiates the link power
mode: it reads PA layer attributes (connected RX/TX data lanes, max RX
HS/PWM gears) via DME_GET and then issues DME_SET(PA_PWRMODE), waiting for
the UIC power-mode-change completion (IS.UPMS / HCS.UPMCRS). The device
only handled DME_LINK_STARTUP and DME_HIBER_{ENTER,EXIT} and returned
FAILURE for every other DME command, so a host that performs power-mode
change could never complete it.
Return canned PA attribute values (1 lane, HS-G4, FAST_MODE) on
DME_GET/PEER_GET and acknowledge DME_SET/PEER_SET. For DME_SET(PA_PWRMODE)
also raise IS.UPMS and set HCS.UPMCRS=PWR_LOCAL so the power-mode change
completes. The emulated link has no PHY, so no state is persisted.
For example, the Linux ufshcd driver reads these attributes during probe
and otherwise aborts with "invalid connected lanes value".
When qemu_strtou64() fails on the value after NUMBER(phys_base)= or
NUMBER(PHYS_OFFSET)=, report a parse failure and include the malformed
value. The previous message suggested the field name itself could not
be read.
Fixes: d9feb51772 ("dump: update phys_base header field based on VMCOREINFO content") Signed-off-by: yujun <yujun@kylinos.cn> Acked-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20260629114646.288664-1-yujun@kylinos.cn>
Denis V. Lunev [Fri, 19 Jun 2026 10:18:34 +0000 (12:18 +0200)]
tests/qtest/dump: cover win-dmp availability via vmcoreinfo
win-dmp becomes available only once the guest exposes a Windows dump
header through vmcoreinfo. Forge exactly such a note (an ELF note
header followed by a WinDumpHeader64 carrying the PAGE/DU64
signatures, the layout a Windows guest with the QEMU vmcoreinfo writer
produces), place it in guest RAM, point the vmcoreinfo device at it via
fw_cfg, and check that win-dmp flips from unavailable to available.
This exercises win_dump_available()'s positive path without a real
Windows guest. It only covers availability reporting; the actual
win-dmp generation (create_win_dump()) needs real Windows kernel
structures and is not exercised here.
The test is registered only on x86_64 with a vmcoreinfo device present.
Denis V. Lunev [Fri, 19 Jun 2026 10:18:33 +0000 (12:18 +0200)]
tests/qtest/dump: reject win-dmp without vmcoreinfo
Requesting the Windows crashdump format (win-dmp) on a guest that does not
expose a Windows dump header through vmcoreinfo must be rejected, not
silently turned into a bogus dump. Add a test that asks for win-dmp on a
plain VM and checks the request fails with "invalid vmcoreinfo note size"
and that the VM stays usable afterwards (a subsequent ELF dump succeeds).
The test is x86_64 only, where win_dump_available() performs this check.
Denis V. Lunev [Fri, 19 Jun 2026 10:18:32 +0000 (12:18 +0200)]
tests/qtest: add dump-guest-memory test
There is currently almost no coverage for the dump-guest-memory QMP
command beyond the test-hmp smoke test. Add a qtest that runs on a bare
machine (no guest OS) and checks:
- query-dump-guest-memory-capability always advertises 'elf';
- an ELF dump is produced and starts with the ELF magic;
- a non-raw kdump dump is emitted in makedumpfile flattened format;
- a raw kdump dump starts with the on-disk KDUMP header;
- an unknown protocol is rejected without killing the VM, and dumping
still works afterwards.
Denis V. Lunev [Fri, 19 Jun 2026 10:18:31 +0000 (12:18 +0200)]
dump: make win_dump_available() check vmcoreinfo for a Windows dump header
QMP query-dump-guest-memory-capability reports win-dmp as available for
any x86 VM, and dump-guest-memory accepts the win-dmp format
unconditionally. Both are wrong: win-dmp only works when the guest has
published a Windows dump header through vmcoreinfo.
The guest registers that note with the vmcoreinfo device (its physical
address and size), so win_dump_available() can read it back directly and
validate the note size and the Windows dump header signature. This needs
no other guest state, so it does not stop the vCPUs.
The capability query reads the note on the main thread with the BQL held
and has no migration guard of its own, so it is skipped while a migration
destination is still receiving guest RAM: there the read would deadlock
against the postcopy load (which needs the BQL) or, in precopy, see
incomplete pages.
Based on the original work of Nikolai Barybin.
Signed-off-by: Denis V. Lunev <den@openvz.org>
[ MA - changed physical_memory_read() call ] Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20260619101834.228432-5-den@openvz.org>
Denis V. Lunev [Fri, 19 Jun 2026 10:18:30 +0000 (12:18 +0200)]
system/cpus: refuse memsave/pmemsave while guest RAM is being migrated
memsave and pmemsave read guest memory and write it to a file, with no
guard at all. They run on the main thread with the BQL held, so on a
postcopy destination touching a not-yet-received page deadlocks: the
thread blocks on the userfault while the postcopy incoming path waits for
the BQL to install that page. During precopy the read returns incomplete
state instead.
Refuse both while guest RAM is still being received, using the same
migration_guest_ram_loading() check as dump-guest-memory.
Denis V. Lunev [Fri, 19 Jun 2026 10:18:29 +0000 (12:18 +0200)]
dump: refuse dump-guest-memory while guest RAM is being migrated
dump-guest-memory reads all of guest RAM. The existing guard only rejects
the dump in RUN_STATE_INMIGRATE, i.e. the precopy load phase. On a
postcopy destination the guest already runs (RUN_STATE_RUNNING) while its
pages are pulled from the source on demand.
A non-detached dump reads that RAM on the main thread with the BQL held.
Touching a not-yet-received page blocks on the userfault, and because the
postcopy incoming path itself takes the BQL to install pages, the
transfer that would satisfy the fault cannot progress: the VM deadlocks.
Use migration_guest_ram_loading(), which also covers postcopy, so the
dump is refused for the whole time the destination is still receiving
guest RAM.
Operations that read guest RAM (dump-guest-memory, memsave, pmemsave)
must refuse to run while the destination of a migration is still
receiving that RAM: during precopy it is incomplete, and during postcopy
a read faults the page in from the source. Provide a single predicate
they can share instead of open-coding the runstate and postcopy checks.
yujun [Tue, 30 Jun 2026 03:13:24 +0000 (11:13 +0800)]
migration: Fix invalid %ud format and trace arg typo
Standard printf has no %ud conversion; glibc treats it as %u followed
by a literal 'd', so postcopy userfaultfd error messages printed event
values like "5d" instead of "5". The same typo existed in two postcopy
discard trace format strings.
Also rename the misspelled ram_save_iterate_big_wait() trace argument
milliconds to milliseconds.
Stefan Hajnoczi [Mon, 29 Jun 2026 15:41:42 +0000 (17:41 +0200)]
Merge tag 'net-pull-request' of https://github.com/jasowang/qemu into staging
# -----BEGIN PGP SIGNATURE-----
#
# iQFJBAABCAAzFiEEIV1G9IJGaJ7HfzVi7wSWWzmNYhEFAmpCdSsVHGphc293YW5n
# aW9AZ21haWwuY29tAAoJEO8Ells5jWIRb+sH/2PLAv0BpViEDy5lL0b+s5yCIdbw
# 8XRwVvLk/SXavj/zn+LaWe/DQCdd4MKALvCCuG6WfqfSdF7XWnG4DhSXvnx5MRiW
# um+259bwwAsW2H++Unue6TdkCFvGQQo8TJFP3EV+gibzIaFEXwxHloMgp9y1uQah
# HhAKFr3QJL5zX7YohzuzUSkXQO2yVnEcPCsTuvdnbe9QOrIyKFNOcTQJrtKwSBpm
# YxGJfooOIpimtobecw18B9UJJ4iMN7Sgs80vAeA2PXkrie0KxTwO6FAwyIlaZlUy
# 6DSEdsozJoV6TG0dP2pj3Lt6RAbEesvxBI3zYDqgnrKZNL8Etb0gzMS6U4k=
# =3c3b
# -----END PGP SIGNATURE-----
# gpg: Signature made Mon 29 Jun 2026 15:37:47 CEST
# gpg: using RSA key 215D46F48246689EC77F3562EF04965B398D6211
# gpg: issuer "jasowangio@gmail.com"
# gpg: Good signature from "Jason Wang (Jason Wang on RedHat) <jasowang@redhat.com>" [full]
# gpg: issuer "jasowangio@gmail.com" does not match any User ID
# gpg: WARNING: The key's User ID is not certified with a trusted signature!
# gpg: There is no indication that the signature belongs to the owner.
# Primary key fingerprint: 215D 46F4 8246 689E C77F 3562 EF04 965B 398D 6211
* tag 'net-pull-request' of https://github.com/jasowang/qemu:
MAINTAINERS: update Jason Wang's email address
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
local_fid_fd() returns fs->fd for any FID type that is not P9_FID_DIR.
Since P9_FID_XATTR and P9_FID_NONE share union V9fsFidOpenState, calling
local_fid_fd() on these types misinterprets xattr state as a file
descriptor, potentially leading to undefined behaviour or information
disclosure.
Even though we are catching these FID type mismatches on protocol level
in 9p.c already, previous patches proofed this to be error prone.
So let's add another safety layer in local_fid_fd() that would return -1
if the FID type would not possess a valid file descriptor, to prevent
wrong file descriptors from reaching fs backend calls.
hw/9pfs: fix invalid union access by v9fs_co_fstat()
The individual FID types (P9_FID_NONE, P9_FID_FILE, P9_FID_DIR, P9_FID_XATTR)
share union V9fsFidOpenState with FID-type specific fields. Accessing any of
the union fields must comply with the FID-type to avoid undefined behaviour
or information disclosure.
Fix this in v9fs_lock() and v9fs_getlock() by checking if FID has a valid
file descriptor before calling v9fs_co_fstat().
hw/9pfs: fix invalid union access by v9fs_co_fsync()
The individual FID types (P9_FID_NONE, P9_FID_FILE, P9_FID_DIR, P9_FID_XATTR)
share union V9fsFidOpenState with FID-type specific fields. Accessing any of
the union fields must comply with the FID-type to avoid undefined behaviour
or information disclosure.
Fix this in v9fs_fsync() and v9fs_wstat() by checking if FID has a valid file
descriptor before calling v9fs_co_fsync().
Analogue to the previously added 3 synth tests, add (similar) 3 test
cases using the "local" fs driver to verify correct xattr FID limit
enforcement of 9pfs server with a real filesystem.
These 3 new local tests use the shared test code of the previously
added 3 synth tests. The only difference is that the local fs driver
does not expose the current internal xattr FID counter, so we can't
verify this with the local tests.
This is a slow test (may take several seconds) and therefore
registered as "slow" test and not running by default.
Add 3 test cases to verify correct xattr FID limit enforcement of
9pfs server.
- 1. test with default max_xattr=1024
- 2. test with custom max_xattr=100
- 3. test with unlimited max_xattr=0
These are tests using the synth driver. Advantage: by using the
synth driver the tests cannot only check when the xattr FID limit
kicks in (server would return an Rlerror response with ENOSPC),
but can also validate the current 9p server internal xattr FID
counter at any moment.
This is a slow test (may take several seconds) and therefore
registered as "slow" test and not running by default.
Increase the maximum 9P message size ('msize') of 9p test client from
4k to 32k to support larger messages.
This is needed for the xattr tests being added with the subsequent
patches which are going to transmit xattrs of size 8k. It would have
also been possible to send them in multiple chunks, however let's not
overcomplicate things.
This new msize is still reasonable small compared to common msize
values on production systems.
Previous patch introduced a limit of max. 1024 simultaneous xattr FIDs.
This patch introduces an option "max_attr" that allows to override this
limit, just for the case that some user might run into this limit for
some reason, even if unlikely; or for reducing the limit further down
(e.g. that default limit of 1024 would cap at max. 64 MiB host memory,
at least on Linux hosts where the limit per xattr is 64k).
This new "max_xattr" option can be specified with both -fsdev and
-virtfs command line options, with the "local" and the "synth" fs
drivers.
The previous limit of 1024 is preserved as the default value.
hw/9pfs: add xattr FID limit to prevent memory exhaustion
Add a limit on the number of simultaneously open xattr FIDs to prevent
host memory exhaustion attacks. Each xattr FID contains a buffer for the
xattr value, and without a limit, a malicious priviliged guest with
direct communication access to 9p server could create a huge number of
xattr FIDs until host memory is eventually exhausted.
Fix this by:
- add xattr_fid_limit to struct FsContext for the max. amount
- add xattr_fid_count to struct FsContext for the current amount
- init xattr_fid_limit with 1024
- init xattr_fid_count with 0
- add function xattr_fid_count_inc() to increment the count
- add function xattr_fid_count_decr() to decrement the count
- call xattr_fid_count_inc() in Txattrcreate handler
- call xattr_fid_count_inc() in Txattrwalk handler
- call xattr_fid_count_decr() when a xattr FID is freed
Additionally:
- reset the xattr FID counter in virtfs_reset()
When the limit is reached then xattr_fid_count_inc() returns -ENOSPC and
the request handler is aborted on its error path without turning the
FID into an xattr type and without allocating memory for the xattr.
The default value of 1024 was chosen, as (sane usage of) xattr requests
in the 9p protocol are usually very short-lived, and even machines with
128 cores with very high xattr activity should have plenty of head room
without ever hitting this limit.
Constrain max_count in v9fs_readdir() to transport's current, real
response buffer size before calling v9fs_do_readdir() to prevent
excessive host memory allocation for specific, crafted, huge
directories (large amount of entries) by bad clients.
Client may send a Treaddir request with a large 'count' parameter, and
while the negotiated 'msize' provides some limit, it accounts for guest
being somewhat faithful on the negotiated 'msize' value throughout the
session.
A bad guest client could have negotiated a large 'msize' but provide a
small reply buffer for Treaddir request, causing QEMU to allocate host
memory proportional to 'msize' before discovering the reply cannot fit.
Possible consequence was a potential DoS by a priviliged guest, causing
a disconnection of guest communication due to transport device being
marked as "broken", however QEMU process would have continued to run with
potentially giant host memory allocation, which might have negative
impact on other services running on host.
Add and implement the response_buffer_size callback for the Xen
transport.
Returns the size of the response buffer from the rings in_sg, as limit
for 9p server while generating a response for supplied PDU.
We use a local iovec array variable in_sg[2] instead of ring->sg, as
ring->sg is only allocated by init_in_iov_from_pdu() and
init_out_iov_from_pdu() during request / response processing.
response_buffer_size() however may be called before those allocators,
which would dereference ring->sg as NULL pointer. The local array
avoids this.
Add and implement the response_buffer_size callback for the virtio
transport.
Returns the actual current virtio response buffer size for the supplied
PDU, which will be used as safety guard for limiting the response size
when generating a 9p response.
hw/9pfs: add response_buffer_size transport callback
Add a new callback to the V9fsTransport interface that allows each transport
to provide the real size of its current response buffer.
This is needed for subsequent safety guards that will limit generated
responses appropriately before trying to allocate, generate, and send a
response to guest.
This is especially required for request handlers that need to allocate
dynamic and potentially large host memory for generating a response. These
safety guards are mandatory to counter bad clients that try to trick server
by supplying response buffers being smaller than the previously negotiated
msize value.
The 'msize' parameter negotiated during Tversion handshake can be
arbitrarily large as requested by the guest. So far 9p server accepted
any msize value suggested by guest, i.e. server did not cap it at all,
no matter how large, as in practice the upper limit of msize is a client
capability. But as subsequent's security patch shows, capping msize on
server side makes sense as additional safety-net.
Let's cap msize to transport's theoretical limit for msize, mainly to
prevent a bad client from triggering excessive host memory allocations
throughout the session.
We intentionally don't cap msize to transport's current, real response
buffer size, as the response buffer size may vary between individual
requests.
Add and implement the msize_limit callback for the Xen transport.
The limit is calculated using XEN_FLEX_RING_SIZE() based on the
negotiated ring_order. For the theoretical maximum ring_order of 9,
this results in a maximum 'msize' of 1048576 bytes (1 MiB).
The minimum limit of all rings is picked, because multiple rings
could theoretically have different ring_orders.
Add and implement the msize_limit callback for the virtio transport.
This new callback function provides the theoretical maximum 'msize'
value supported by this virtio transport.
The limit is calculated as (VIRTQUEUE_MAX_SIZE - 2) * 4096 bytes,
where 2 virtio descriptors are lost exactly for:
- 1 descriptor for the original request (typically being small)
- 1 descriptor as indirect table pointer (when used), which just
contains a pointer to the separate sglist containing the
response's actual payload data
And 4096 bytes are assumed as standard page size used by Linux 9p
client. This results in a maximum 'msize' of 4186112 bytes.
Theoretically Linux client could support a much larger size, e.g. by
using multiple consecutive pages per sg entry / descriptor. However
that's currently not the case and unlikely to change any time soon.
And due to recent security issues, let's handle this limit
conservatively until really necessary to be raised.
Add a new callback 'msize_limit' to the V9fsTransport structure.
This allows each transport implementation to provide its theoretical
maximum 'msize' value, which will be used to cap the negotiated
msize during Tversion handshake.
Implement the frame limit check for system emulation mode. When
allocframe computes a new stack pointer below FRAMELIMIT, raise a
precise exception (HEX_CAUSE_STACK_LIMIT). The check is skipped in
monitor mode.
Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com> Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>