Compare commits

...

No commits in common. "c10s-aie-nv" and "c8-stream-rhel" have entirely different histories.

891 changed files with 75563 additions and 79982 deletions

43
.gitignore vendored
View File

@ -1,38 +1,5 @@
/qemu-3.1.0.tar.xz
/qemu-4.0.0.tar.xz
/qemu-4.1.0-rc4.tar.xz
/qemu-4.1.0.tar.xz
/qemu-4.2.0-rc1.tar.xz
/qemu-4.2.0-rc4.tar.xz
/qemu-4.2.0.tar.xz
/qemu-5.0.0-rc0.tar.xz
/qemu-5.0.0-rc1.tar.xz
/qemu-5.0.0-rc2.tar.xz
/qemu-5.0.0-rc3.tar.xz
/qemu-5.0.0-rc4.tar.xz
/qemu-5.0.0.tar.xz
/qemu-5.1.0.tar.xz
/qemu-5.2.0-rc1.tar.xz
/qemu-5.2.0-rc3.tar.xz
/qemu-5.2.0.tar.xz
/qemu-6.0.0.tar.xz
/qemu-kvm*.src.rpm
/patches.*
/*.orig
/qemu-6.1.0.tar.xz
/qemu-6.2.0.tar.xz
/qemu-7.0.0.tar.xz
/capstone.tar.gz
/qemu-7.1.0.tar.xz
/qemu-7.2.0.tar.xz
/qemu-8.0.0.tar.xz
/qemu-8.1.0.tar.xz
/qemu-8.2.0.tar.xz
/qemu-9.0.0.tar.xz
/qemu-9.1.0.tar.xz
/qemu-10.0.0.tar.xz
/qemu-10.1.0.tar.xz
/IORT
/IORT.its_off
/IORT.smmuv3-dev
/IORT.smmuv3-legacy
SOURCES/qemu-6.2.0.tar.xz
SOURCES/tests_data_acpi_pc_SSDT.dimmpxm
SOURCES/tests_data_acpi_q35_FACP.slic
SOURCES/tests_data_acpi_q35_SSDT.dimmpxm
SOURCES/tests_data_acpi_virt_SSDT.memhp

5
.qemu-kvm.metadata Normal file
View File

@ -0,0 +1,5 @@
68cd61a466170115b88817e2d52db2cd7a92f43a SOURCES/qemu-6.2.0.tar.xz
c4b34092bc5af1ba7febfca1477320fb024e8acd SOURCES/tests_data_acpi_pc_SSDT.dimmpxm
19349e3517143bd1af56a5444e927ba37a111f72 SOURCES/tests_data_acpi_q35_FACP.slic
4632d10ae8cedad4d5d760ed211f83f0dc81005d SOURCES/tests_data_acpi_q35_SSDT.dimmpxm
ef12eed43cc357fb134db6fa3c7ffc83e222a97d SOURCES/tests_data_acpi_virt_SSDT.memhp

View File

@ -1,123 +0,0 @@
From 67dd7ae821a4fba377f2240d4930b96df012b840 Mon Sep 17 00:00:00 2001
From: Miroslav Rezanina <mrezanin@redhat.com>
Date: Wed, 26 May 2021 10:56:02 +0200
Subject: [PATCH] Initial redhat build
This patch introduces redhat build structure in redhat subdirectory. In addition,
several issues are fixed in QEMU tree:
- Change of app name for sasl_server_init in VNC code from qemu to qemu-kvm
- As we use qemu-kvm as name in all places, this is updated to be consistent
- Man page renamed from qemu to qemu-kvm
- man page is installed using make install so we have to fix it in qemu tree
We disable make check due to issues with some of the tests.
We are rebasing from qemu-kvm-10.0.0-12.el10.
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
---
README.systemtap | 43 +++++++++++++++++++++++++
scripts/qemu-guest-agent/fsfreeze-hook | 4 +--
scripts/systemtap/conf.d/qemu_kvm.conf | 4 +++
scripts/systemtap/script.d/qemu_kvm.stp | 1 +
ui/vnc-auth-sasl.c | 2 +-
5 files changed, 51 insertions(+), 3 deletions(-)
create mode 100644 README.systemtap
create mode 100644 scripts/systemtap/conf.d/qemu_kvm.conf
create mode 100644 scripts/systemtap/script.d/qemu_kvm.stp
diff --git a/README.systemtap b/README.systemtap
new file mode 100644
index 0000000000..ad913fc990
--- /dev/null
+++ b/README.systemtap
@@ -0,0 +1,43 @@
+QEMU tracing using systemtap-initscript
+---------------------------------------
+
+You can capture QEMU trace data all the time using systemtap-initscript. This
+uses SystemTap's flight recorder mode to trace all running guests to a
+fixed-size buffer on the host. Old trace entries are overwritten by new
+entries when the buffer size wraps.
+
+1. Install the systemtap-initscript package:
+ # yum install systemtap-initscript
+
+2. Install the systemtap scripts and the conf file:
+ # cp /usr/share/qemu-kvm/systemtap/script.d/qemu_kvm.stp /etc/systemtap/script.d/
+ # cp /usr/share/qemu-kvm/systemtap/conf.d/qemu_kvm.conf /etc/systemtap/conf.d/
+
+The set of trace events to enable is given in qemu_kvm.stp. This SystemTap
+script can be customized to add or remove trace events provided in
+/usr/share/systemtap/tapset/qemu-kvm-simpletrace.stp.
+
+SystemTap customizations can be made to qemu_kvm.conf to control the flight
+recorder buffer size and whether to store traces in memory only or disk too.
+See stap(1) for option documentation.
+
+3. Start the systemtap service.
+ # service systemtap start qemu_kvm
+
+4. Make the service start at boot time.
+ # chkconfig systemtap on
+
+5. Confirm that the service works.
+ # service systemtap status qemu_kvm
+ qemu_kvm is running...
+
+When you want to inspect the trace buffer, perform the following steps:
+
+1. Dump the trace buffer.
+ # staprun -A qemu_kvm >/tmp/trace.log
+
+2. Start the systemtap service because the preceding step stops the service.
+ # service systemtap start qemu_kvm
+
+3. Translate the trace record to readable format.
+ # /usr/share/qemu-kvm/simpletrace.py --no-header /usr/share/qemu-kvm/trace-events /tmp/trace.log
diff --git a/scripts/qemu-guest-agent/fsfreeze-hook b/scripts/qemu-guest-agent/fsfreeze-hook
index c1feb6f5ce..d5d8d4daf8 100755
--- a/scripts/qemu-guest-agent/fsfreeze-hook
+++ b/scripts/qemu-guest-agent/fsfreeze-hook
@@ -7,8 +7,8 @@
# "freeze" argument before the filesystem is frozen. And for fsfreeze-thaw
# request, it is issued with "thaw" argument after filesystem is thawed.
-LOGFILE=/var/log/qga-fsfreeze-hook.log
-FSFREEZE_D=$(dirname -- "$0")/fsfreeze-hook.d
+LOGFILE=/var/log/qemu-ga/qga-fsfreeze-hook.log
+FSFREEZE_D=$(dirname -- "$(realpath $0)")/fsfreeze-hook.d
# Check whether file $1 is a backup or rpm-generated file and should be ignored
is_ignored_file() {
diff --git a/scripts/systemtap/conf.d/qemu_kvm.conf b/scripts/systemtap/conf.d/qemu_kvm.conf
new file mode 100644
index 0000000000..372d8160a4
--- /dev/null
+++ b/scripts/systemtap/conf.d/qemu_kvm.conf
@@ -0,0 +1,4 @@
+# Force load uprobes (see BZ#1118352)
+stap -e 'probe process("/usr/libexec/qemu-kvm").function("main") { printf("") }' -c true
+
+qemu_kvm_OPT="-s4" # per-CPU buffer size, in megabytes
diff --git a/scripts/systemtap/script.d/qemu_kvm.stp b/scripts/systemtap/script.d/qemu_kvm.stp
new file mode 100644
index 0000000000..c04abf9449
--- /dev/null
+++ b/scripts/systemtap/script.d/qemu_kvm.stp
@@ -0,0 +1 @@
+probe qemu.kvm.simpletrace.handle_qmp_command,qemu.kvm.simpletrace.monitor_protocol_*,qemu.kvm.simpletrace.migrate_set_state {}
diff --git a/ui/vnc-auth-sasl.c b/ui/vnc-auth-sasl.c
index 3f4cfc471d..09dafba18d 100644
--- a/ui/vnc-auth-sasl.c
+++ b/ui/vnc-auth-sasl.c
@@ -42,7 +42,7 @@
bool vnc_sasl_server_init(Error **errp)
{
- int saslErr = sasl_server_init(NULL, "qemu");
+ int saslErr = sasl_server_init(NULL, "qemu-kvm");
if (saslErr != SASL_OK) {
error_setg(errp, "Failed to initialize SASL auth: %s",

View File

@ -1,847 +0,0 @@
From f9d8a760501e0cf4147a7d9bcf59c765745fbbe3 Mon Sep 17 00:00:00 2001
From: Miroslav Rezanina <mrezanin@redhat.com>
Date: Wed, 7 Dec 2022 03:05:48 -0500
Subject: [PATCH] Enable/disable devices for RHEL
This commit adds all changes related to changes in supported devices.
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
---
.../aarch64-softmmu/aarch64-rh-devices.mak | 49 ++++++++
configs/devices/rh-virtio.mak | 10 ++
.../riscv64-softmmu/riscv64-rh-devices.mak | 39 ++++++
.../s390x-softmmu/s390x-rh-devices.mak | 20 +++
.../x86_64-softmmu/x86_64-rh-devices.mak | 118 ++++++++++++++++++
hw/arm/virt.c | 4 +
hw/cxl/meson.build | 3 +-
hw/ide/piix.c | 5 +-
hw/input/pckbd.c | 2 +
hw/net/e1000.c | 2 +
hw/net/rtl8139.c | 4 +
hw/usb/meson.build | 2 +-
hw/virtio/meson.build | 6 +-
target/arm/arm-qmp-cmds.c | 2 +
target/arm/cpu.h | 2 +
target/arm/cpu64.c | 7 +-
target/arm/tcg/cpu32.c | 2 +
target/arm/tcg/cpu64.c | 8 ++
target/arm/tcg/meson.build | 2 +-
target/i386/cpu.c | 20 +++
target/riscv/cpu.c | 6 +
target/s390x/cpu_models.c | 2 +-
tests/qtest/arm-cpu-features.c | 4 +
23 files changed, 311 insertions(+), 8 deletions(-)
create mode 100644 configs/devices/aarch64-softmmu/aarch64-rh-devices.mak
create mode 100644 configs/devices/rh-virtio.mak
create mode 100644 configs/devices/riscv64-softmmu/riscv64-rh-devices.mak
create mode 100644 configs/devices/s390x-softmmu/s390x-rh-devices.mak
create mode 100644 configs/devices/x86_64-softmmu/x86_64-rh-devices.mak
diff --git a/configs/devices/aarch64-softmmu/aarch64-rh-devices.mak b/configs/devices/aarch64-softmmu/aarch64-rh-devices.mak
new file mode 100644
index 0000000000..855278f70e
--- /dev/null
+++ b/configs/devices/aarch64-softmmu/aarch64-rh-devices.mak
@@ -0,0 +1,49 @@
+include ../rh-virtio.mak
+
+CONFIG_ARM_GIC_KVM=y
+CONFIG_ARM_GICV3=y
+CONFIG_ARM_GIC=y
+CONFIG_ARM_SMMUV3=y
+CONFIG_ARM_VIRT=y
+CONFIG_CXL=y
+CONFIG_CXL_MEM_DEVICE=y
+CONFIG_EDID=y
+CONFIG_PCI_BRIDGE=y
+CONFIG_PCIE_PORT=y
+CONFIG_PCIE_PCI_BRIDGE=y
+CONFIG_PCI_DEVICES=y
+CONFIG_PCI_TESTDEV=y
+CONFIG_PFLASH_CFI01=y
+CONFIG_SCSI=y
+CONFIG_SEMIHOSTING=y
+CONFIG_USB=y
+CONFIG_USB_XHCI=y
+CONFIG_USB_XHCI_PCI=y
+CONFIG_USB_STORAGE_CORE=y
+CONFIG_USB_STORAGE_CLASSIC=y
+CONFIG_USB_HUB=y
+CONFIG_USB_HID=y
+CONFIG_VFIO=y
+CONFIG_VFIO_PCI=y
+CONFIG_VIRTIO_MMIO=y
+CONFIG_VIRTIO_PCI=y
+CONFIG_VIRTIO_MEM=y
+CONFIG_VIRTIO_IOMMU=y
+CONFIG_XIO3130=y
+CONFIG_NVDIMM=y
+CONFIG_ACPI_APEI=y
+CONFIG_TPM=y
+CONFIG_TPM_EMULATOR=y
+CONFIG_TPM_TIS_SYSBUS=y
+CONFIG_PTIMER=y
+CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
+CONFIG_PVPANIC_PCI=y
+CONFIG_PXB=y
+CONFIG_VHOST_VSOCK=y
+CONFIG_VHOST_USER_VSOCK=y
+CONFIG_VHOST_USER_FS=y
+CONFIG_IOMMUFD=y
+CONFIG_VHOST_USER_SND=y
+CONFIG_VHOST_USER_SCMI=y
+CONFIG_VHOST_USER_GPU=y
+CONFIG_UEFI_VARS=y
diff --git a/configs/devices/rh-virtio.mak b/configs/devices/rh-virtio.mak
new file mode 100644
index 0000000000..94ede1b5f6
--- /dev/null
+++ b/configs/devices/rh-virtio.mak
@@ -0,0 +1,10 @@
+CONFIG_VIRTIO=y
+CONFIG_VIRTIO_BALLOON=y
+CONFIG_VIRTIO_BLK=y
+CONFIG_VIRTIO_GPU=y
+CONFIG_VIRTIO_INPUT=y
+CONFIG_VIRTIO_INPUT_HOST=y
+CONFIG_VIRTIO_NET=y
+CONFIG_VIRTIO_RNG=y
+CONFIG_VIRTIO_SCSI=y
+CONFIG_VIRTIO_SERIAL=y
diff --git a/configs/devices/riscv64-softmmu/riscv64-rh-devices.mak b/configs/devices/riscv64-softmmu/riscv64-rh-devices.mak
new file mode 100644
index 0000000000..b5e55de916
--- /dev/null
+++ b/configs/devices/riscv64-softmmu/riscv64-rh-devices.mak
@@ -0,0 +1,39 @@
+include ../rh-virtio.mak
+
+CONFIG_RISCV_VIRT=y
+CONFIG_CXL=y
+CONFIG_CXL_MEM_DEVICE=y
+CONFIG_EDID=y
+CONFIG_PCI_BRIDGE=y
+CONFIG_PCIE_PORT=y
+CONFIG_PCIE_PCI_BRIDGE=y
+CONFIG_PCI_DEVICES=y
+CONFIG_PCI_TESTDEV=y
+CONFIG_PFLASH_CFI01=y
+CONFIG_SCSI=y
+CONFIG_SEMIHOSTING=y
+CONFIG_USB=y
+CONFIG_USB_XHCI=y
+CONFIG_USB_XHCI_PCI=y
+CONFIG_USB_STORAGE_CORE=y
+CONFIG_USB_STORAGE_CLASSIC=y
+CONFIG_USB_HUB=y
+CONFIG_USB_HID=y
+CONFIG_VFIO=y
+CONFIG_VFIO_PCI=y
+CONFIG_VIRTIO_MMIO=y
+CONFIG_VIRTIO_PCI=y
+CONFIG_VIRTIO_IOMMU=y
+CONFIG_XIO3130=y
+CONFIG_ACPI_APEI=y
+CONFIG_TPM=y
+CONFIG_TPM_EMULATOR=y
+CONFIG_TPM_TIS_SYSBUS=y
+CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
+CONFIG_PVPANIC_PCI=y
+CONFIG_PXB=y
+CONFIG_VHOST_VSOCK=y
+CONFIG_VHOST_USER_VSOCK=y
+CONFIG_VHOST_USER_FS=y
+CONFIG_IOMMUFD=y
+CONFIG_VHOST_USER_SND=y
diff --git a/configs/devices/s390x-softmmu/s390x-rh-devices.mak b/configs/devices/s390x-softmmu/s390x-rh-devices.mak
new file mode 100644
index 0000000000..834281d872
--- /dev/null
+++ b/configs/devices/s390x-softmmu/s390x-rh-devices.mak
@@ -0,0 +1,20 @@
+include ../rh-virtio.mak
+
+CONFIG_PCI=y
+CONFIG_S390_CCW_VIRTIO=y
+CONFIG_S390_FLIC=y
+CONFIG_S390_FLIC_KVM=y
+CONFIG_SCLPCONSOLE=y
+CONFIG_SCSI=y
+CONFIG_VFIO=y
+CONFIG_VFIO_AP=y
+CONFIG_VFIO_CCW=y
+CONFIG_VFIO_PCI=y
+CONFIG_VHOST_USER=y
+CONFIG_VIRTIO_CCW=y
+CONFIG_VIRTIO_MEM=y
+CONFIG_WDT_DIAG288=y
+CONFIG_VHOST_VSOCK=y
+CONFIG_VHOST_USER_VSOCK=y
+CONFIG_VHOST_USER_FS=y
+CONFIG_IOMMUFD=y
diff --git a/configs/devices/x86_64-softmmu/x86_64-rh-devices.mak b/configs/devices/x86_64-softmmu/x86_64-rh-devices.mak
new file mode 100644
index 0000000000..828cb8aa6f
--- /dev/null
+++ b/configs/devices/x86_64-softmmu/x86_64-rh-devices.mak
@@ -0,0 +1,118 @@
+include ../rh-virtio.mak
+
+CONFIG_ACPI=y
+CONFIG_ACPI_PCI=y
+CONFIG_ACPI_CPU_HOTPLUG=y
+CONFIG_ACPI_MEMORY_HOTPLUG=y
+CONFIG_ACPI_NVDIMM=y
+CONFIG_ACPI_SMBUS=y
+CONFIG_ACPI_VMGENID=y
+CONFIG_ACPI_X86=y
+CONFIG_ACPI_ICH9=y
+CONFIG_AHCI=y
+CONFIG_APIC=y
+CONFIG_APM=y
+CONFIG_BOCHS_DISPLAY=y
+CONFIG_CXL=y
+CONFIG_CXL_MEM_DEVICE=y
+CONFIG_DIMM=y
+CONFIG_E1000E_PCI_EXPRESS=y
+CONFIG_E1000_PCI=y
+CONFIG_EDU=y
+#CONFIG_FDC=y
+#CONFIG_FDC_SYSBUS=y
+#CONFIG_FDC_ISA=y
+CONFIG_FW_CFG_DMA=y
+CONFIG_HDA=y
+CONFIG_HYPERV=y
+CONFIG_HYPERV_TESTDEV=y
+CONFIG_I2C=y
+CONFIG_I440FX=y
+CONFIG_I8254=y
+CONFIG_I8257=y
+CONFIG_I8259=y
+CONFIG_I82801B11=y
+CONFIG_IDE_CORE=y
+CONFIG_IDE_PCI=y
+CONFIG_IDE_PIIX=y
+CONFIG_IDE_DEV=y
+CONFIG_IDE_BUS=y
+CONFIG_IGB_PCI_EXPRESS=y
+CONFIG_IOAPIC=y
+CONFIG_IOH3420=y
+CONFIG_ISA_BUS=y
+CONFIG_ISA_DEBUG=y
+CONFIG_ISA_TESTDEV=y
+CONFIG_LPC_ICH9=y
+CONFIG_MC146818RTC=y
+CONFIG_MEM_DEVICE=y
+CONFIG_NVDIMM=y
+CONFIG_PAM=y
+CONFIG_PC=y
+CONFIG_PCI=y
+CONFIG_PCIE_PORT=y
+CONFIG_PCI_DEVICES=y
+CONFIG_PCI_EXPRESS=y
+CONFIG_PCI_EXPRESS_Q35=y
+CONFIG_PCI_I440FX=y
+CONFIG_PCI_TESTDEV=y
+CONFIG_PCKBD=y
+CONFIG_PCSPK=y
+CONFIG_PC_ACPI=y
+CONFIG_PC_PCI=y
+CONFIG_PCI_BRIDGE=y
+CONFIG_PCIE_PCI_BRIDGE=y
+CONFIG_PFLASH_CFI01=y
+CONFIG_PVPANIC_ISA=y
+CONFIG_PXB=y
+CONFIG_Q35=y
+CONFIG_RTL8139_PCI=y
+CONFIG_SCSI=y
+CONFIG_SERIAL=y
+CONFIG_SERIAL_ISA=y
+CONFIG_SERIAL_PCI=y
+CONFIG_SEV=y
+CONFIG_SMBIOS=y
+CONFIG_SMBUS_EEPROM=y
+CONFIG_TEST_DEVICES=y
+CONFIG_USB=y
+CONFIG_USB_EHCI=y
+CONFIG_USB_EHCI_PCI=y
+CONFIG_USB_SMARTCARD=y
+CONFIG_USB_STORAGE_CORE=y
+CONFIG_USB_STORAGE_CLASSIC=y
+CONFIG_USB_UHCI=y
+CONFIG_USB_XHCI=y
+CONFIG_USB_XHCI_NEC=y
+CONFIG_USB_XHCI_PCI=y
+CONFIG_USB_HUB=y
+CONFIG_USB_HID=y
+CONFIG_VFIO=y
+CONFIG_VFIO_PCI=y
+CONFIG_VGA=y
+CONFIG_VGA_PCI=y
+CONFIG_VHOST_USER=y
+CONFIG_VHOST_USER_BLK=y
+CONFIG_VIRTIO_MEM=y
+CONFIG_VIRTIO_PCI=y
+CONFIG_VIRTIO_VGA=y
+CONFIG_VIRTIO_IOMMU=y
+CONFIG_AMD_IOMMU=y
+CONFIG_VMMOUSE=y
+CONFIG_VMPORT=y
+CONFIG_VTD=y
+CONFIG_WDT_IB6300ESB=y
+CONFIG_WDT_IB700=y
+CONFIG_XIO3130=y
+CONFIG_TPM=y
+CONFIG_TPM_CRB=y
+CONFIG_TPM_TIS_ISA=y
+CONFIG_TPM_EMULATOR=y
+CONFIG_SGX=y
+CONFIG_VHOST_VSOCK=y
+CONFIG_VHOST_USER_VSOCK=y
+CONFIG_VHOST_USER_FS=y
+CONFIG_IOMMUFD=y
+CONFIG_VHOST_USER_SND=y
+CONFIG_VHOST_USER_GPU=y
+CONFIG_UEFI_VARS=y
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index ef6be3660f..b525e00365 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -3183,6 +3183,7 @@ static void virt_machine_class_init(ObjectClass *oc, const void *data)
MachineClass *mc = MACHINE_CLASS(oc);
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
static const char * const valid_cpu_types[] = {
+#if 0 /* Disabled for Red Hat Enterprise Linux */
#ifdef CONFIG_TCG
ARM_CPU_TYPE_NAME("cortex-a7"),
ARM_CPU_TYPE_NAME("cortex-a15"),
@@ -3198,8 +3199,11 @@ static void virt_machine_class_init(ObjectClass *oc, const void *data)
ARM_CPU_TYPE_NAME("neoverse-n2"),
#endif /* TARGET_AARCH64 */
#endif /* CONFIG_TCG */
+#endif /* disabled for RHEL */
#ifdef TARGET_AARCH64
+#if 0 /* Disabled for Red Hat Enterprise Linux */
ARM_CPU_TYPE_NAME("cortex-a53"),
+#endif /* disabled for RHEL */
ARM_CPU_TYPE_NAME("cortex-a57"),
#if defined(CONFIG_KVM) || defined(CONFIG_HVF)
ARM_CPU_TYPE_NAME("host"),
diff --git a/hw/cxl/meson.build b/hw/cxl/meson.build
index 3e375f61a9..613adb3ebb 100644
--- a/hw/cxl/meson.build
+++ b/hw/cxl/meson.build
@@ -6,7 +6,8 @@ system_ss.add(when: 'CONFIG_CXL',
'cxl-host.c',
'cxl-cdat.c',
'cxl-events.c',
- 'switch-mailbox-cci.c',
+# Disabled for 8.2.0 rebase for RHEL 9.4.0
+# 'switch-mailbox-cci.c',
),
if_false: files(
'cxl-host-stubs.c',
diff --git a/hw/ide/piix.c b/hw/ide/piix.c
index a0f2709c69..8c3962443b 100644
--- a/hw/ide/piix.c
+++ b/hw/ide/piix.c
@@ -191,7 +191,8 @@ static void piix3_ide_class_init(ObjectClass *klass, const void *data)
k->device_id = PCI_DEVICE_ID_INTEL_82371SB_1;
k->class_id = PCI_CLASS_STORAGE_IDE;
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
- dc->hotpluggable = false;
+ /* Disabled for Red Hat Enterprise Linux: */
+ dc->user_creatable = false;
}
static const TypeInfo piix3_ide_info = {
@@ -215,6 +216,8 @@ static void piix4_ide_class_init(ObjectClass *klass, const void *data)
k->class_id = PCI_CLASS_STORAGE_IDE;
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
dc->hotpluggable = false;
+ /* Disabled for Red Hat Enterprise Linux: */
+ dc->user_creatable = false;
}
static const TypeInfo piix4_ide_info = {
diff --git a/hw/input/pckbd.c b/hw/input/pckbd.c
index 71f5f976e9..794078ed84 100644
--- a/hw/input/pckbd.c
+++ b/hw/input/pckbd.c
@@ -950,6 +950,8 @@ static void i8042_class_initfn(ObjectClass *klass, const void *data)
dc->vmsd = &vmstate_kbd_isa;
adevc->build_dev_aml = i8042_build_aml;
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
+ /* Disabled for Red Hat Enterprise Linux: */
+ dc->user_creatable = false;
}
static const TypeInfo i8042_info = {
diff --git a/hw/net/e1000.c b/hw/net/e1000.c
index a80a7b0cdb..7eb5a3b19d 100644
--- a/hw/net/e1000.c
+++ b/hw/net/e1000.c
@@ -1732,6 +1732,7 @@ static const E1000Info e1000_devices[] = {
.revision = 0x03,
.phy_id2 = E1000_PHY_ID2_8254xx_DEFAULT,
},
+#if 0 /* Disabled for Red Hat Enterprise Linux 7 */
{
.name = "e1000-82544gc",
.device_id = E1000_DEV_ID_82544GC_COPPER,
@@ -1744,6 +1745,7 @@ static const E1000Info e1000_devices[] = {
.revision = 0x03,
.phy_id2 = E1000_PHY_ID2_8254xx_DEFAULT,
},
+#endif
};
static void e1000_register_types(void)
diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c
index 324fb932aa..f4dd693abb 100644
--- a/hw/net/rtl8139.c
+++ b/hw/net/rtl8139.c
@@ -57,6 +57,7 @@
#include "system/dma.h"
#include "qemu/module.h"
#include "qemu/timer.h"
+#include "qemu/error-report.h"
#include "qemu/bswap.h"
#include "net/net.h"
#include "net/eth.h"
@@ -3363,6 +3364,9 @@ static void pci_rtl8139_realize(PCIDevice *dev, Error **errp)
DeviceState *d = DEVICE(dev);
uint8_t *pci_conf;
+ warn_report("'rtl8139' is deprecated, "
+ "please use a different Network Interface Card");
+
pci_conf = dev->config;
pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin A */
/* TODO: start of capability list, but no capability
diff --git a/hw/usb/meson.build b/hw/usb/meson.build
index 17360a5b5a..3c4fdfc31d 100644
--- a/hw/usb/meson.build
+++ b/hw/usb/meson.build
@@ -53,7 +53,7 @@ system_ss.add(when: 'CONFIG_USB_SMARTCARD', if_true: files('dev-smartcard-reader
if cacard.found()
usbsmartcard_ss = ss.source_set()
usbsmartcard_ss.add(when: 'CONFIG_USB_SMARTCARD',
- if_true: [cacard, files('ccid-card-emulated.c', 'ccid-card-passthru.c')])
+ if_true: [cacard, files('ccid-card-passthru.c')])
hw_usb_modules += {'smartcard': usbsmartcard_ss}
endif
diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build
index 3ea7b3cec8..3102d68bec 100644
--- a/hw/virtio/meson.build
+++ b/hw/virtio/meson.build
@@ -22,7 +22,8 @@ if have_vhost
system_virtio_ss.add(files('vhost-user-base.c'))
# MMIO Stubs
- system_virtio_ss.add(files('vhost-user-device.c'))
+# Disabled for 8.2.0 rebase for RHEL 9.4.0
+# system_virtio_ss.add(files('vhost-user-device.c'))
system_virtio_ss.add(when: 'CONFIG_VHOST_USER_GPIO', if_true: files('vhost-user-gpio.c'))
system_virtio_ss.add(when: 'CONFIG_VHOST_USER_I2C', if_true: files('vhost-user-i2c.c'))
system_virtio_ss.add(when: 'CONFIG_VHOST_USER_RNG', if_true: files('vhost-user-rng.c'))
@@ -30,7 +31,8 @@ if have_vhost
system_virtio_ss.add(when: 'CONFIG_VHOST_USER_INPUT', if_true: files('vhost-user-input.c'))
# PCI Stubs
- system_virtio_ss.add(when: 'CONFIG_VIRTIO_PCI', if_true: files('vhost-user-device-pci.c'))
+# Disabled for 8.2.0 rebase for RHEL 9.4.0
+# system_virtio_ss.add(when: 'CONFIG_VIRTIO_PCI', if_true: files('vhost-user-device-pci.c'))
system_virtio_ss.add(when: ['CONFIG_VIRTIO_PCI', 'CONFIG_VHOST_USER_GPIO'],
if_true: files('vhost-user-gpio-pci.c'))
system_virtio_ss.add(when: ['CONFIG_VIRTIO_PCI', 'CONFIG_VHOST_USER_I2C'],
diff --git a/target/arm/arm-qmp-cmds.c b/target/arm/arm-qmp-cmds.c
index d292c974c4..9bb68866e1 100644
--- a/target/arm/arm-qmp-cmds.c
+++ b/target/arm/arm-qmp-cmds.c
@@ -225,6 +225,7 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
static void arm_cpu_add_definition(gpointer data, gpointer user_data)
{
ObjectClass *oc = data;
+ CPUClass *cc = CPU_CLASS(oc);
CpuDefinitionInfoList **cpu_list = user_data;
CpuDefinitionInfo *info;
const char *typename;
@@ -233,6 +234,7 @@ static void arm_cpu_add_definition(gpointer data, gpointer user_data)
info = g_malloc0(sizeof(*info));
info->name = cpu_model_from_type(typename);
info->q_typename = g_strdup(typename);
+ info->deprecated = !!cc->deprecation_note;
QAPI_LIST_PREPEND(*cpu_list, info);
}
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index dc9b6dce4c..dc0da8b0ae 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -34,6 +34,8 @@
#include "target/arm/gtimer.h"
#include "target/arm/cpu-sysregs.h"
+#define RHEL_CPU_DEPRECATION "use 'host' / 'max'"
+
#define EXCP_UDEF 1 /* undefined instruction */
#define EXCP_SWI 2 /* software interrupt */
#define EXCP_PREFETCH_ABORT 3
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index 26cf7e6dfa..051d5d653b 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -698,6 +698,7 @@ static void aarch64_a57_initfn(Object *obj)
define_cortex_a72_a57_a53_cp_reginfo(cpu);
}
+#if 0 /* Disabled for Red Hat Enterprise Linux */
static void aarch64_a53_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
@@ -759,6 +760,7 @@ static void aarch64_a53_initfn(Object *obj)
cpu->gic_pribits = 5;
define_cortex_a72_a57_a53_cp_reginfo(cpu);
}
+#endif
static void aarch64_host_initfn(Object *obj)
{
@@ -797,8 +799,11 @@ static void aarch64_max_initfn(Object *obj)
}
static const ARMCPUInfo aarch64_cpus[] = {
- { .name = "cortex-a57", .initfn = aarch64_a57_initfn },
+ { .name = "cortex-a57", .initfn = aarch64_a57_initfn,
+ .deprecation_note = RHEL_CPU_DEPRECATION },
+#if 0 /* Disabled for Red Hat Enterprise Linux */
{ .name = "cortex-a53", .initfn = aarch64_a53_initfn },
+#endif /* disabled for RHEL */
{ .name = "max", .initfn = aarch64_max_initfn },
#if defined(CONFIG_KVM) || defined(CONFIG_HVF)
{ .name = "host", .initfn = aarch64_host_initfn },
diff --git a/target/arm/tcg/cpu32.c b/target/arm/tcg/cpu32.c
index a2a23eae0d..c362759d65 100644
--- a/target/arm/tcg/cpu32.c
+++ b/target/arm/tcg/cpu32.c
@@ -115,6 +115,7 @@ void aa32_max_features(ARMCPU *cpu)
FIELD_DP32_IDREG(isar, ID_DFR1, HPMN0, 1); /* FEAT_HPMN0 */
}
+#if 0 /* Disabled for Red Hat Enterprise Linux */
/* CPU models. These are not needed for the AArch64 linux-user build. */
#if !defined(CONFIG_USER_ONLY) || !defined(TARGET_AARCH64)
@@ -1084,3 +1085,4 @@ static void arm_tcg_cpu_register_types(void)
type_init(arm_tcg_cpu_register_types)
#endif /* !CONFIG_USER_ONLY || !TARGET_AARCH64 */
+#endif /* disabled for RHEL */
diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c
index 35cddbafa4..c7c464a0af 100644
--- a/target/arm/tcg/cpu64.c
+++ b/target/arm/tcg/cpu64.c
@@ -29,6 +29,7 @@
#include "cpu-features.h"
#include "cpregs.h"
+#if 0 /* Disabled for Red Hat Enterprise Linux */
static void aarch64_a35_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
@@ -113,6 +114,7 @@ static void aarch64_a35_initfn(Object *obj)
/* These values are the same with A53/A57/A72. */
define_cortex_a72_a57_a53_cp_reginfo(cpu);
}
+#endif
static void cpu_max_get_sve_max_vq(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
@@ -199,6 +201,7 @@ static void cpu_max_get_l0gptsz(Object *obj, Visitor *v, const char *name,
static const Property arm_cpu_lpa2_property =
DEFINE_PROP_BOOL("lpa2", ARMCPU, prop_lpa2, true);
+#if 0 /* Disabled for Red Hat Enterprise Linux */
static void aarch64_a55_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
@@ -1080,6 +1083,7 @@ static void aarch64_neoverse_n2_initfn(Object *obj)
aarch64_add_pauth_properties(obj);
aarch64_add_sve_properties(obj);
}
+#endif
/*
* -cpu max: a CPU with as many features enabled as our emulation supports.
@@ -1310,6 +1314,7 @@ void aarch64_max_tcg_initfn(Object *obj)
qdev_property_add_static(DEVICE(obj), &arm_cpu_lpa2_property);
}
+#if 0 /* Disabled for Red Hat Enterprise Linux */
static const ARMCPUInfo aarch64_cpus[] = {
{ .name = "cortex-a35", .initfn = aarch64_a35_initfn },
{ .name = "cortex-a55", .initfn = aarch64_a55_initfn },
@@ -1321,14 +1326,17 @@ static const ARMCPUInfo aarch64_cpus[] = {
{ .name = "neoverse-v1", .initfn = aarch64_neoverse_v1_initfn },
{ .name = "neoverse-n2", .initfn = aarch64_neoverse_n2_initfn },
};
+#endif
static void aarch64_cpu_register_types(void)
{
+#if 0 /* Disabled for Red Hat Enterprise Linux */
size_t i;
for (i = 0; i < ARRAY_SIZE(aarch64_cpus); ++i) {
arm_cpu_register(&aarch64_cpus[i]);
}
+#endif
}
type_init(aarch64_cpu_register_types)
diff --git a/target/arm/tcg/meson.build b/target/arm/tcg/meson.build
index 895facdc30..f1a9e01c51 100644
--- a/target/arm/tcg/meson.build
+++ b/target/arm/tcg/meson.build
@@ -53,7 +53,7 @@ arm_system_ss.add(files(
'psci.c',
))
-arm_system_ss.add(when: 'CONFIG_ARM_V7M', if_true: files('cpu-v7m.c'))
+#arm_system_ss.add(when: 'CONFIG_ARM_V7M', if_true: files('cpu-v7m.c'))
arm_user_ss.add(when: 'TARGET_AARCH64', if_false: files('cpu-v7m.c'))
arm_common_ss.add(zlib)
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 6d85149e6e..9c756a05f2 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -3163,6 +3163,7 @@ static const CPUCaches xeon_srf_cache_info = {
},
};
+#if 0 /* Disabled for Red Hat Enterprise Linux */
static const CPUCaches yongfeng_cache_info = {
.l1d_cache = &(CPUCacheInfo) {
/* CPUID 0x4.0x0.EAX */
@@ -3261,6 +3262,7 @@ static const CPUCaches yongfeng_cache_info = {
.share_level = CPU_TOPOLOGY_LEVEL_DIE,
},
};
+#endif
/* The following VMX features are not supported by KVM and are left out in the
* CPU definitions:
@@ -3290,9 +3292,13 @@ static const CPUCaches yongfeng_cache_info = {
* PT in VMX operation
*/
+#define RHEL_CPU_DEPRECATION \
+ "use at least 'Haswell' / 'EPYC', or 'host' / 'max'"
+
static const X86CPUDefinition builtin_x86_defs[] = {
{
.name = "qemu64",
+ .deprecation_note = RHEL_CPU_DEPRECATION,
.level = 0xd,
.vendor = CPUID_VENDOR_AMD,
.family = 15,
@@ -3311,6 +3317,7 @@ static const X86CPUDefinition builtin_x86_defs[] = {
.xlevel = 0x8000000A,
.model_id = "QEMU Virtual CPU version " QEMU_HW_VERSION,
},
+#if 0 // Deprecated CPU models are removed in RHEL-10
{
.name = "phenom",
.level = 5,
@@ -3679,8 +3686,10 @@ static const X86CPUDefinition builtin_x86_defs[] = {
.xlevel = 0x80000008,
.model_id = "Intel Core 2 Duo P9xxx (Penryn Class Core 2)",
},
+#endif // Removal of deprecated CPU models in RHEL-10
{
.name = "Nehalem",
+ .deprecation_note = RHEL_CPU_DEPRECATION,
.level = 11,
.vendor = CPUID_VENDOR_INTEL,
.family = 6,
@@ -3758,6 +3767,7 @@ static const X86CPUDefinition builtin_x86_defs[] = {
},
{
.name = "Westmere",
+ .deprecation_note = RHEL_CPU_DEPRECATION,
.level = 11,
.vendor = CPUID_VENDOR_INTEL,
.family = 6,
@@ -3839,6 +3849,7 @@ static const X86CPUDefinition builtin_x86_defs[] = {
},
{
.name = "SandyBridge",
+ .deprecation_note = RHEL_CPU_DEPRECATION,
.level = 0xd,
.vendor = CPUID_VENDOR_INTEL,
.family = 6,
@@ -3925,6 +3936,7 @@ static const X86CPUDefinition builtin_x86_defs[] = {
},
{
.name = "IvyBridge",
+ .deprecation_note = RHEL_CPU_DEPRECATION,
.level = 0xd,
.vendor = CPUID_VENDOR_INTEL,
.family = 6,
@@ -5551,6 +5563,7 @@ static const X86CPUDefinition builtin_x86_defs[] = {
},
{
.name = "Denverton",
+ .deprecation_note = RHEL_CPU_DEPRECATION,
.level = 21,
.vendor = CPUID_VENDOR_INTEL,
.family = 6,
@@ -5661,6 +5674,7 @@ static const X86CPUDefinition builtin_x86_defs[] = {
},
{
.name = "Snowridge",
+ .deprecation_note = RHEL_CPU_DEPRECATION,
.level = 27,
.vendor = CPUID_VENDOR_INTEL,
.family = 6,
@@ -5842,6 +5856,7 @@ static const X86CPUDefinition builtin_x86_defs[] = {
.xlevel = 0x80000008,
.model_id = "Intel Xeon Phi Processor (Knights Mill)",
},
+#if 0 // Deprecated CPU models are removed in RHEL-10
{
.name = "Opteron_G1",
.level = 5,
@@ -5909,8 +5924,10 @@ static const X86CPUDefinition builtin_x86_defs[] = {
.xlevel = 0x80000008,
.model_id = "AMD Opteron 23xx (Gen 3 Class Opteron)",
},
+#endif
{
.name = "Opteron_G4",
+ .deprecation_note = RHEL_CPU_DEPRECATION,
.level = 0xd,
.vendor = CPUID_VENDOR_AMD,
.family = 21,
@@ -5943,6 +5960,7 @@ static const X86CPUDefinition builtin_x86_defs[] = {
},
{
.name = "Opteron_G5",
+ .deprecation_note = RHEL_CPU_DEPRECATION,
.level = 0xd,
.vendor = CPUID_VENDOR_AMD,
.family = 21,
@@ -6420,6 +6438,7 @@ static const X86CPUDefinition builtin_x86_defs[] = {
{ /* end of list */ }
}
},
+#if 0 // Disabled for Red Hat Enterprise Linux
{
.name = "YongFeng",
.level = 0x1F,
@@ -6565,6 +6584,7 @@ static const X86CPUDefinition builtin_x86_defs[] = {
{ /* end of list */ }
}
},
+#endif
{
.name = "EPYC-Turin",
.level = 0xd,
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index d055ddf462..bca50a39be 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -2035,6 +2035,7 @@ static const PropertyInfo prop_marchid = {
.set = prop_marchid_set,
};
+#if 0 /* Disabled for Red Hat Enterprise Linux */
/*
* RVA22U64 defines some 'named features' that are cache
* related: Za64rs, Zic64b, Ziccif, Ziccrse, Ziccamoa
@@ -2143,12 +2144,15 @@ static RISCVCPUProfile RVA23S64 = {
RISCV_PROFILE_EXT_LIST_END
}
};
+#endif
RISCVCPUProfile *riscv_profiles[] = {
+#if 0 /* Disabled for Red Hat Enterprise Linux */
&RVA22U64,
&RVA22S64,
&RVA23U64,
&RVA23S64,
+#endif
NULL,
};
@@ -2993,6 +2997,7 @@ static const TypeInfo riscv_cpu_type_infos[] = {
.cfg.pmp_regions = 8
),
+#if 0 /* Disabled for Red Hat Enterprise Linux */
#if defined(TARGET_RISCV32) || \
(defined(TARGET_RISCV64) && !defined(CONFIG_USER_ONLY))
DEFINE_RISCV_CPU(TYPE_RISCV_CPU_BASE32, TYPE_RISCV_DYNAMIC_CPU,
@@ -3287,6 +3292,7 @@ static const TypeInfo riscv_cpu_type_infos[] = {
DEFINE_PROFILE_CPU(TYPE_RISCV_CPU_RVA23U64, TYPE_RISCV_CPU_RV64I, RVA23U64),
DEFINE_PROFILE_CPU(TYPE_RISCV_CPU_RVA23S64, TYPE_RISCV_CPU_RV64I, RVA23S64),
#endif /* TARGET_RISCV64 */
+#endif /* disabled for RHEL */
};
DEFINE_TYPES(riscv_cpu_type_infos)
diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c
index 954a7a99a9..fe29f5c5b7 100644
--- a/target/s390x/cpu_models.c
+++ b/target/s390x/cpu_models.c
@@ -72,7 +72,6 @@ static S390CPUDef s390_cpu_defs[] = {
CPUDEF_INIT(0x2096, 9, 2, 40, 0x00000000U, "z9BC", "IBM System z9 BC GA1"),
CPUDEF_INIT(0x2094, 9, 3, 40, 0x00000000U, "z9EC.3", "IBM System z9 EC GA3"),
CPUDEF_INIT(0x2096, 9, 3, 40, 0x00000000U, "z9BC.2", "IBM System z9 BC GA2"),
-#endif
CPUDEF_INIT(0x2097, 10, 1, 43, 0x00000000U, "z10EC", "IBM System z10 EC GA1"),
CPUDEF_INIT(0x2097, 10, 2, 43, 0x00000000U, "z10EC.2", "IBM System z10 EC GA2"),
CPUDEF_INIT(0x2098, 10, 2, 43, 0x00000000U, "z10BC", "IBM System z10 BC GA1"),
@@ -81,6 +80,7 @@ static S390CPUDef s390_cpu_defs[] = {
CPUDEF_INIT(0x2817, 11, 1, 44, 0x08000000U, "z196", "IBM zEnterprise 196 GA1"),
CPUDEF_INIT(0x2817, 11, 2, 44, 0x08000000U, "z196.2", "IBM zEnterprise 196 GA2"),
CPUDEF_INIT(0x2818, 11, 2, 44, 0x08000000U, "z114", "IBM zEnterprise 114 GA1"),
+#endif
CPUDEF_INIT(0x2827, 12, 1, 44, 0x08000000U, "zEC12", "IBM zEnterprise EC12 GA1"),
CPUDEF_INIT(0x2827, 12, 2, 44, 0x08000000U, "zEC12.2", "IBM zEnterprise EC12 GA2"),
CPUDEF_INIT(0x2828, 12, 2, 44, 0x08000000U, "zBC12", "IBM zEnterprise BC12 GA1"),
diff --git a/tests/qtest/arm-cpu-features.c b/tests/qtest/arm-cpu-features.c
index eb8ddebffb..2d3304bb4a 100644
--- a/tests/qtest/arm-cpu-features.c
+++ b/tests/qtest/arm-cpu-features.c
@@ -459,8 +459,10 @@ static void test_query_cpu_model_expansion(const void *data)
assert_error(qts, "host", "The CPU type 'host' requires KVM", NULL);
/* Test expected feature presence/absence for some cpu types */
+#if 0 /* Disabled for Red Hat Enterprise Linux */
assert_has_feature_enabled(qts, "cortex-a15", "pmu");
assert_has_not_feature(qts, "cortex-a15", "aarch64");
+#endif /* disabled for RHEL */
/* Enabling and disabling pmu should always work. */
assert_has_feature_enabled(qts, "max", "pmu");
@@ -477,6 +479,7 @@ static void test_query_cpu_model_expansion(const void *data)
assert_has_feature_enabled(qts, "cortex-a57", "pmu");
assert_has_feature_enabled(qts, "cortex-a57", "aarch64");
+#if 0 /* Disabled for Red Hat Enterprise Linux */
assert_has_feature_enabled(qts, "a64fx", "pmu");
assert_has_feature_enabled(qts, "a64fx", "aarch64");
/*
@@ -489,6 +492,7 @@ static void test_query_cpu_model_expansion(const void *data)
"{ 'sve384': true }");
assert_error(qts, "a64fx", "cannot enable sve640",
"{ 'sve640': true }");
+#endif /* disabled for RHEL */
sve_tests_default(qts, "max");
pauth_tests_default(qts, "max");

View File

@ -1,530 +0,0 @@
From 2a4e74aaa600b6acbab1fa25637f1bc10ca789ed Mon Sep 17 00:00:00 2001
From: Miroslav Rezanina <mrezanin@redhat.com>
Date: Fri, 11 Jan 2019 09:54:45 +0100
Subject: [PATCH] Machine type related general changes
This patch is first part of original "Add RHEL machine types" patch we
split to allow easier review. It contains changes not related to any
architecture.
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
---
hw/acpi/piix4.c | 2 +-
hw/arm/virt.c | 2 +-
hw/core/machine.c | 145 +++++++++++++++++++++++++++++++++++
hw/i386/fw_cfg.c | 3 +-
hw/net/rtl8139.c | 4 +-
hw/riscv/virt.c | 4 +-
hw/smbios/smbios.c | 46 ++++++++++-
hw/usb/hcd-xhci-pci.c | 54 +++++++++----
hw/usb/hcd-xhci-pci.h | 1 +
hw/virtio/virtio-mem.c | 3 +-
include/hw/boards.h | 31 ++++++++
include/hw/firmware/smbios.h | 4 +-
include/hw/i386/pc.h | 3 +
13 files changed, 277 insertions(+), 25 deletions(-)
diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c
index 7a18f18dda..2b3678b8c6 100644
--- a/hw/acpi/piix4.c
+++ b/hw/acpi/piix4.c
@@ -245,7 +245,7 @@ static bool vmstate_test_migrate_acpi_index(void *opaque, int version_id)
static const VMStateDescription vmstate_acpi = {
.name = "piix4_pm",
.version_id = 3,
- .minimum_version_id = 3,
+ .minimum_version_id = 2,
.post_load = vmstate_acpi_post_load,
.fields = (const VMStateField[]) {
VMSTATE_PCI_DEVICE(parent_obj, PIIX4PMState),
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index b525e00365..1800981317 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -1755,7 +1755,7 @@ static void virt_build_smbios(VirtMachineState *vms)
product = "KVM Virtual Machine";
}
- smbios_set_defaults("QEMU", product, mc->name);
+ smbios_set_defaults("QEMU", product, mc->name, NULL, NULL);
/* build the array of physical mem area from base_memmap */
mem_array.address = vms->memmap[VIRT_MEM].base;
diff --git a/hw/core/machine.c b/hw/core/machine.c
index bd47527479..2a1a42cebc 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -288,6 +288,151 @@ GlobalProperty hw_compat_2_6[] = {
};
const size_t hw_compat_2_6_len = G_N_ELEMENTS(hw_compat_2_6);
+/*
+ * RHEL only: machine types for previous major releases are deprecated
+ */
+const char *rhel_old_machine_deprecation =
+ "machine types for previous major releases are deprecated";
+
+GlobalProperty hw_compat_rhel_10_2[] = {
+ /* hw_compat_rhel_10_2 from hw_compat_10_0 */
+ { "scsi-hd", "dpofua", "off" },
+ /* hw_compat_rhel_10_2 from hw_compat_10_0 */
+ { "vfio-pci", "x-migration-load-config-after-iter", "off" },
+ /* hw_compat_rhel_10_2 from hw_compat_10_0 */
+ { "ramfb", "use-legacy-x86-rom", "true"},
+ /* hw_compat_rhel_10_2 from hw_compat_10_0 */
+ { "vfio-pci-nohotplug", "use-legacy-x86-rom", "true" },
+};
+const size_t hw_compat_rhel_10_2_len = G_N_ELEMENTS(hw_compat_10_0);
+
+GlobalProperty hw_compat_rhel_10_1[] = {
+ /* hw_compat_rhel_10_1 from hw_compat_9_1 */
+ { TYPE_PCI_DEVICE, "x-pcie-ext-tag", "false" },
+ /* hw_compat_rhel_10_1 from hw_compat_9_2 */
+ {"arm-cpu", "backcompat-pauth-default-use-qarma5", "true"},
+ /* hw_compat_rhel_10_1 from hw_compat_9_2 */
+ { "virtio-balloon-pci", "vectors", "0" },
+ /* hw_compat_rhel_10_1 from hw_compat_9_2 */
+ { "virtio-balloon-pci-transitional", "vectors", "0" },
+ /* hw_compat_rhel_10_1 from hw_compat_9_2 */
+ { "virtio-balloon-pci-non-transitional", "vectors", "0" },
+ /* hw_compat_rhel_10_1 from hw_compat_9_2 */
+ { "virtio-mem-pci", "vectors", "0" },
+ /* hw_compat_rhel_10_1 from hw_compat_9_2 */
+ { "migration", "multifd-clean-tls-termination", "false" },
+ /* hw_compat_rhel_10_1 from hw_compat_9_2 */
+ { "migration", "send-switchover-start", "off"},
+ /* hw_compat_rhel_10_1 from hw_compat_9_2 */
+ { "vfio-pci", "x-migration-multifd-transfer", "off" },
+};
+const size_t hw_compat_rhel_10_1_len = G_N_ELEMENTS(hw_compat_rhel_10_1);
+
+
+GlobalProperty hw_compat_rhel_10_0[] = {
+ /* hw_compat_rhel_10_0 from hw_compat_9_0 */
+ {"arm-cpu", "backcompat-cntfrq", "true" },
+ /* hw_compat_rhel_10_0 from hw_compat_9_0 */
+ { "scsi-hd", "migrate-emulated-scsi-request", "false" },
+ /* hw_compat_rhel_10_0 from hw_compat_9_0 */
+ { "scsi-cd", "migrate-emulated-scsi-request", "false" },
+ /* hw_compat_rhel_10_0 from hw_compat_9_0 */
+ {"vfio-pci", "skip-vsc-check", "false" },
+ /* hw_compat_rhel_10_0 from hw_compat_9_0 */
+ { "virtio-pci", "x-pcie-pm-no-soft-reset", "off" },
+ /* hw_compat_rhel_10_0 from hw_compat_9_0 */
+ {"sd-card", "spec_version", "2" },
+};
+const size_t hw_compat_rhel_10_0_len = G_N_ELEMENTS(hw_compat_rhel_10_0);
+
+/* Apply this to all RHEL9 boards going backward and forward */
+GlobalProperty hw_compat_rhel_9[] = {
+ /* supported by userspace, but RHEL 9 *kernels* do not support USO. */
+ { TYPE_VIRTIO_NET, "host_uso", "off"},
+ { TYPE_VIRTIO_NET, "guest_uso4", "off"},
+ { TYPE_VIRTIO_NET, "guest_uso6", "off"},
+};
+const size_t hw_compat_rhel_9_len = G_N_ELEMENTS(hw_compat_rhel_9);
+
+GlobalProperty hw_compat_rhel_9_5[] = {
+ /* hw_compat_rhel_9_5 from hw_compat_8_2 */
+ { "migration", "zero-page-detection", "legacy"},
+ /* hw_compat_rhel_9_5 from hw_compat_8_2 */
+ { TYPE_VIRTIO_IOMMU_PCI, "granule", "4k" },
+ /* hw_compat_rhel_9_5 from hw_compat_8_2 */
+ { TYPE_VIRTIO_IOMMU_PCI, "aw-bits", "64" },
+ /* hw_compat_rhel_9_5 from hw_compat_8_2 */
+ { "virtio-gpu-device", "x-scanout-vmstate-version", "1" },
+};
+const size_t hw_compat_rhel_9_5_len = G_N_ELEMENTS(hw_compat_rhel_9_5);
+
+GlobalProperty hw_compat_rhel_9_4[] = {
+ /* hw_compat_rhel_9_4 from hw_compat_8_0 */
+ { TYPE_VIRTIO_NET, "host_uso", "off"},
+ /* hw_compat_rhel_9_4 from hw_compat_8_0 */
+ { TYPE_VIRTIO_NET, "guest_uso4", "off"},
+ /* hw_compat_rhel_9_4 from hw_compat_8_0 */
+ { TYPE_VIRTIO_NET, "guest_uso6", "off"},
+ /* hw_compat_rhel_9_4 from hw_compat_8_1 */
+ { TYPE_PCI_BRIDGE, "x-pci-express-writeable-slt-bug", "true" },
+ /* hw_compat_rhel_9_4 from hw_compat_8_1 */
+ { "ramfb", "x-migrate", "off" },
+ /* hw_compat_rhel_9_4 from hw_compat_8_1 */
+ { "vfio-pci-nohotplug", "x-ramfb-migrate", "off" },
+ /* hw_compat_rhel_9_4 from hw_compat_8_1 */
+ { "igb", "x-pcie-flr-init", "off" },
+ /* hw_compat_rhel_9_4 jira RHEL-24045 */
+ { "virtio-mem", "dynamic-memslots", "off" },
+};
+const size_t hw_compat_rhel_9_4_len = G_N_ELEMENTS(hw_compat_rhel_9_4);
+
+GlobalProperty hw_compat_rhel_9_3[] = {
+ /* hw_compat_rhel_9_3 from hw_compat_8_0 */
+ { "migration", "multifd-flush-after-each-section", "on"},
+ /* hw_compat_rhel_9_3 from hw_compat_8_0 */
+ { TYPE_PCI_DEVICE, "x-pcie-ari-nextfn-1", "on" },
+};
+const size_t hw_compat_rhel_9_3_len = G_N_ELEMENTS(hw_compat_rhel_9_3);
+
+GlobalProperty hw_compat_rhel_9_2[] = {
+ /* hw_compat_rhel_9_2 from hw_compat_7_2 */
+ { "e1000e", "migrate-timadj", "off" },
+ /* hw_compat_rhel_9_2 from hw_compat_7_2 */
+ { "virtio-mem", "x-early-migration", "false" },
+ /* hw_compat_rhel_9_2 from hw_compat_7_2 */
+ { "migration", "x-preempt-pre-7-2", "true" },
+ /* hw_compat_rhel_9_2 from hw_compat_7_2 */
+ { TYPE_PCI_DEVICE, "x-pcie-err-unc-mask", "off" },
+};
+const size_t hw_compat_rhel_9_2_len = G_N_ELEMENTS(hw_compat_rhel_9_2);
+
+/*
+ * Mostly the same as hw_compat_7_0
+ */
+GlobalProperty hw_compat_rhel_9_1[] = {
+ /* hw_compat_rhel_9_1 from hw_compat_7_0 */
+ { "arm-gicv3-common", "force-8-bit-prio", "on" },
+ /* hw_compat_rhel_9_1 from hw_compat_7_0 */
+ { "nvme-ns", "eui64-default", "on"},
+ /* hw_compat_rhel_9_1 from hw_compat_7_1 */
+ { "virtio-device", "queue_reset", "false" },
+ /* hw_compat_rhel_9_1 bz 2155749 */
+ { "virtio-rng-pci", "vectors", "0" },
+ /* hw_compat_rhel_9_1 bz 2162569 */
+ { "virtio-rng-pci-transitional", "vectors", "0" },
+ { "virtio-rng-pci-non-transitional", "vectors", "0" },
+};
+const size_t hw_compat_rhel_9_1_len = G_N_ELEMENTS(hw_compat_rhel_9_1);
+
+/*
+ * Mostly the same as hw_compat_6_2
+ */
+GlobalProperty hw_compat_rhel_9_0[] = {
+ /* hw_compat_rhel_9_0 from hw_compat_6_2 */
+ { "PIIX4_PM", "x-not-migrate-acpi-index", "on"},
+};
+const size_t hw_compat_rhel_9_0_len = G_N_ELEMENTS(hw_compat_rhel_9_0);
+
MachineState *current_machine;
static char *machine_get_kernel(Object *obj, Error **errp)
diff --git a/hw/i386/fw_cfg.c b/hw/i386/fw_cfg.c
index 5c0bcd5f8a..07df7281d2 100644
--- a/hw/i386/fw_cfg.c
+++ b/hw/i386/fw_cfg.c
@@ -75,7 +75,8 @@ void fw_cfg_build_smbios(PCMachineState *pcms, FWCfgState *fw_cfg,
if (pcmc->smbios_defaults) {
/* These values are guest ABI, do not change */
- smbios_set_defaults("QEMU", mc->desc, mc->name);
+ smbios_set_defaults("QEMU", mc->desc, mc->name,
+ pcmc->smbios_stream_product, pcmc->smbios_stream_version);
}
/* tell smbios about cpuid version and features */
diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c
index f4dd693abb..ac3a7376ad 100644
--- a/hw/net/rtl8139.c
+++ b/hw/net/rtl8139.c
@@ -3173,7 +3173,7 @@ static int rtl8139_pre_save(void *opaque)
static const VMStateDescription vmstate_rtl8139 = {
.name = "rtl8139",
- .version_id = 5,
+ .version_id = 4,
.minimum_version_id = 3,
.post_load = rtl8139_post_load,
.pre_save = rtl8139_pre_save,
@@ -3254,7 +3254,9 @@ static const VMStateDescription vmstate_rtl8139 = {
VMSTATE_UINT32(tally_counters.TxMCol, RTL8139State),
VMSTATE_UINT64(tally_counters.RxOkPhy, RTL8139State),
VMSTATE_UINT64(tally_counters.RxOkBrd, RTL8139State),
+#if 0 /* Disabled for Red Hat Enterprise Linux bz 1420195 */
VMSTATE_UINT32_V(tally_counters.RxOkMul, RTL8139State, 5),
+#endif
VMSTATE_UINT16(tally_counters.TxAbt, RTL8139State),
VMSTATE_UINT16(tally_counters.TxUndrn, RTL8139State),
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index 47e573f85a..ab5a9ec613 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -1402,7 +1402,7 @@ static void virt_build_smbios(RISCVVirtState *s)
product = "KVM Virtual Machine";
}
- smbios_set_defaults("QEMU", product, mc->name);
+ smbios_set_defaults("QEMU", product, mc->name, NULL, NULL);
if (riscv_is_32bit(&s->soc[0])) {
smbios_set_default_processor_family(0x200);
@@ -1920,7 +1920,7 @@ static void virt_machine_class_init(ObjectClass *oc, const void *data)
mc->desc = "RISC-V VirtIO board";
mc->init = virt_machine_init;
mc->max_cpus = VIRT_CPUS_MAX;
- mc->default_cpu_type = TYPE_RISCV_CPU_BASE;
+ mc->default_cpu_type = TYPE_RISCV_CPU_MAX;
mc->block_default_type = IF_VIRTIO;
mc->no_cdrom = 1;
mc->pci_allow_0_address = true;
diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c
index 1ac063cfb4..03f7a00ed1 100644
--- a/hw/smbios/smbios.c
+++ b/hw/smbios/smbios.c
@@ -39,6 +39,10 @@ size_t usr_blobs_len;
static unsigned usr_table_max;
static unsigned usr_table_cnt;
+/* Set to true for modern Windows 10 HardwareID-6 compat */
+static bool smbios_type2_required;
+
+
uint8_t *smbios_tables;
size_t smbios_tables_len;
unsigned smbios_table_max;
@@ -627,7 +631,7 @@ static void smbios_build_type_1_table(void)
static void smbios_build_type_2_table(void)
{
- SMBIOS_BUILD_TABLE_PRE(2, T2_BASE, false); /* optional */
+ SMBIOS_BUILD_TABLE_PRE(2, T2_BASE, smbios_type2_required);
SMBIOS_TABLE_SET_STR(2, manufacturer_str, type2.manufacturer);
SMBIOS_TABLE_SET_STR(2, product_str, type2.product);
@@ -1015,15 +1019,51 @@ void smbios_set_default_processor_family(uint16_t processor_family)
}
void smbios_set_defaults(const char *manufacturer, const char *product,
- const char *version)
+ const char *version,
+ const char *stream_product,
+ const char *stream_version)
{
smbios_have_defaults = true;
+ /*
+ * If @stream_product & @stream_version are non-NULL, then
+ * we're following rules for new Windows driver support.
+ * The data we have to report is defined in this doc:
+ *
+ * https://docs.microsoft.com/en-us/windows-hardware/drivers/install/specifying-hardware-ids-for-a-computer
+ *
+ * The Windows drivers are written to expect use of the
+ * scheme documented as "HardwareID-6" against Windows 10,
+ * which uses SMBIOS System (Type 1) and Base Board (Type 2)
+ * tables and will match on
+ *
+ * System Manufacturer = Red Hat (@manufacturer)
+ * System SKU Number = 8.2.0 (@stream_version)
+ * Baseboard Manufacturer = Red Hat (@manufacturer)
+ * Baseboard Product = RHEL-AV (@stream_product)
+ *
+ * NB, SKU must be changed with each RHEL-AV release
+ *
+ * Other fields can be freely used by applications using
+ * QEMU. For example apps can use the "System product"
+ * and "System version" to identify themselves.
+ *
+ * We get 'System Manufacturer' and 'Baseboard Manufacturer'
+ */
SMBIOS_SET_DEFAULT(smbios_type1.manufacturer, manufacturer);
SMBIOS_SET_DEFAULT(smbios_type1.product, product);
SMBIOS_SET_DEFAULT(smbios_type1.version, version);
+ SMBIOS_SET_DEFAULT(smbios_type1.family, "Red Hat Enterprise Linux");
+ if (stream_version != NULL) {
+ SMBIOS_SET_DEFAULT(smbios_type1.sku, stream_version);
+ }
SMBIOS_SET_DEFAULT(type2.manufacturer, manufacturer);
- SMBIOS_SET_DEFAULT(type2.product, product);
+ if (stream_product != NULL) {
+ SMBIOS_SET_DEFAULT(type2.product, stream_product);
+ smbios_type2_required = true;
+ } else {
+ SMBIOS_SET_DEFAULT(type2.product, product);
+ }
SMBIOS_SET_DEFAULT(type2.version, version);
SMBIOS_SET_DEFAULT(type3.manufacturer, manufacturer);
SMBIOS_SET_DEFAULT(type3.version, version);
diff --git a/hw/usb/hcd-xhci-pci.c b/hw/usb/hcd-xhci-pci.c
index b93c80b09d..f4a2f1a1de 100644
--- a/hw/usb/hcd-xhci-pci.c
+++ b/hw/usb/hcd-xhci-pci.c
@@ -120,6 +120,33 @@ static int xhci_pci_vmstate_post_load(void *opaque, int version_id)
return 0;
}
+/* RH bz 1912846 */
+static bool usb_xhci_pci_add_msi(struct PCIDevice *dev, Error **errp)
+{
+ int ret;
+ Error *err = NULL;
+ XHCIPciState *s = XHCI_PCI(dev);
+
+ ret = msi_init(dev, 0x70, s->xhci.numintrs, true, false, &err);
+ /*
+ * Any error other than -ENOTSUP(board's MSI support is broken)
+ * is a programming error
+ */
+ assert(!ret || ret == -ENOTSUP);
+ if (ret && s->msi == ON_OFF_AUTO_ON) {
+ /* Can't satisfy user's explicit msi=on request, fail */
+ error_append_hint(&err, "You have to use msi=auto (default) or "
+ "msi=off with this machine type.\n");
+ error_propagate(errp, err);
+ return true;
+ }
+ assert(!err || s->msi == ON_OFF_AUTO_AUTO);
+ /* With msi=auto, we fall back to MSI off silently */
+ error_free(err);
+
+ return false;
+}
+
static void usb_xhci_pci_realize(struct PCIDevice *dev, Error **errp)
{
int ret;
@@ -144,23 +171,12 @@ static void usb_xhci_pci_realize(struct PCIDevice *dev, Error **errp)
s->xhci.nec_quirks = true;
}
- if (s->msi != ON_OFF_AUTO_OFF) {
- ret = msi_init(dev, 0x70, s->xhci.numintrs, true, false, &err);
- /*
- * Any error other than -ENOTSUP(board's MSI support is broken)
- * is a programming error
- */
- assert(!ret || ret == -ENOTSUP);
- if (ret && s->msi == ON_OFF_AUTO_ON) {
- /* Can't satisfy user's explicit msi=on request, fail */
- error_append_hint(&err, "You have to use msi=auto (default) or "
- "msi=off with this machine type.\n");
+ if (s->msi != ON_OFF_AUTO_OFF && s->rh_late_msi_cap) {
+ /* This gives the behaviour from 5.2.0 onwards, lspci shows 90,a0,70 */
+ if (usb_xhci_pci_add_msi(dev, &err)) {
error_propagate(errp, err);
return;
}
- assert(!err || s->msi == ON_OFF_AUTO_AUTO);
- /* With msi=auto, we fall back to MSI off silently */
- error_free(err);
}
pci_register_bar(dev, 0,
PCI_BASE_ADDRESS_SPACE_MEMORY |
@@ -172,6 +188,14 @@ static void usb_xhci_pci_realize(struct PCIDevice *dev, Error **errp)
assert(ret > 0);
}
+ /* RH bz 1912846 */
+ if (s->msi != ON_OFF_AUTO_OFF && !s->rh_late_msi_cap) {
+ /* This gives the older RH machine behaviour, lspci shows 90,70,a0 */
+ if (usb_xhci_pci_add_msi(dev, &err)) {
+ error_propagate(errp, err);
+ return;
+ }
+ }
if (s->msix != ON_OFF_AUTO_OFF) {
/* TODO check for errors, and should fail when msix=on */
msix_init(dev, s->xhci.numintrs,
@@ -221,6 +245,8 @@ static const Property xhci_pci_properties[] = {
DEFINE_PROP_ON_OFF_AUTO("msix", XHCIPciState, msix, ON_OFF_AUTO_AUTO),
DEFINE_PROP_BOOL("conditional-intr-mapping", XHCIPciState,
conditional_intr_mapping, false),
+ /* RH bz 1912846 */
+ DEFINE_PROP_BOOL("x-rh-late-msi-cap", XHCIPciState, rh_late_msi_cap, true),
};
static void xhci_class_init(ObjectClass *klass, const void *data)
diff --git a/hw/usb/hcd-xhci-pci.h b/hw/usb/hcd-xhci-pci.h
index 5b61ae8455..3170db064b 100644
--- a/hw/usb/hcd-xhci-pci.h
+++ b/hw/usb/hcd-xhci-pci.h
@@ -41,6 +41,7 @@ typedef struct XHCIPciState {
OnOffAuto msi;
OnOffAuto msix;
bool conditional_intr_mapping;
+ bool rh_late_msi_cap; /* bz 1912846 */
} XHCIPciState;
#endif
diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c
index c46f6f9c3e..1805597879 100644
--- a/hw/virtio/virtio-mem.c
+++ b/hw/virtio/virtio-mem.c
@@ -1699,8 +1699,9 @@ static const Property virtio_mem_properties[] = {
#endif
DEFINE_PROP_BOOL(VIRTIO_MEM_EARLY_MIGRATION_PROP, VirtIOMEM,
early_migration, true),
+ /* RHEL: default-enable "dynamic-memslots" (jira RHEL-24045) */
DEFINE_PROP_BOOL(VIRTIO_MEM_DYNAMIC_MEMSLOTS_PROP, VirtIOMEM,
- dynamic_memslots, false),
+ dynamic_memslots, true),
};
static uint64_t virtio_mem_rdm_get_min_granularity(const RamDiscardManager *rdm,
diff --git a/include/hw/boards.h b/include/hw/boards.h
index f94713e6e2..a434b21909 100644
--- a/include/hw/boards.h
+++ b/include/hw/boards.h
@@ -863,4 +863,35 @@ extern const size_t hw_compat_2_7_len;
extern GlobalProperty hw_compat_2_6[];
extern const size_t hw_compat_2_6_len;
+extern GlobalProperty hw_compat_rhel_10_2[];
+extern const size_t hw_compat_rhel_10_2_len;
+
+extern GlobalProperty hw_compat_rhel_10_1[];
+extern const size_t hw_compat_rhel_10_1_len;
+
+extern GlobalProperty hw_compat_rhel_10_0[];
+extern const size_t hw_compat_rhel_10_0_len;
+
+extern GlobalProperty hw_compat_rhel_9[];
+extern const size_t hw_compat_rhel_9_len;
+
+extern GlobalProperty hw_compat_rhel_9_5[];
+extern const size_t hw_compat_rhel_9_5_len;
+
+extern GlobalProperty hw_compat_rhel_9_4[];
+extern const size_t hw_compat_rhel_9_4_len;
+
+extern GlobalProperty hw_compat_rhel_9_3[];
+extern const size_t hw_compat_rhel_9_3_len;
+
+extern GlobalProperty hw_compat_rhel_9_2[];
+extern const size_t hw_compat_rhel_9_2_len;
+
+extern GlobalProperty hw_compat_rhel_9_1[];
+extern const size_t hw_compat_rhel_9_1_len;
+
+extern GlobalProperty hw_compat_rhel_9_0[];
+extern const size_t hw_compat_rhel_9_0_len;
+
+extern const char *rhel_old_machine_deprecation;
#endif
diff --git a/include/hw/firmware/smbios.h b/include/hw/firmware/smbios.h
index f066ab7262..e805d25fbe 100644
--- a/include/hw/firmware/smbios.h
+++ b/include/hw/firmware/smbios.h
@@ -331,7 +331,9 @@ void smbios_add_usr_blob_size(size_t size);
void smbios_entry_add(QemuOpts *opts, Error **errp);
void smbios_set_cpuid(uint32_t version, uint32_t features);
void smbios_set_defaults(const char *manufacturer, const char *product,
- const char *version);
+ const char *version,
+ const char *stream_product,
+ const char *stream_version);
void smbios_set_default_processor_family(uint16_t processor_family);
uint8_t *smbios_get_table_legacy(size_t *length, Error **errp);
void smbios_get_tables(MachineState *ms,
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index 79b72c54dd..3b4ea24c20 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -103,6 +103,9 @@ struct PCMachineClass {
bool smbios_defaults;
bool smbios_legacy_mode;
SmbiosEntryPointType default_smbios_ep_type;
+ /* New fields needed for Windows HardwareID-6 matching */
+ const char *smbios_stream_product;
+ const char *smbios_stream_version;
/* RAM / address space compat: */
bool gigabyte_align;

View File

@ -1,33 +0,0 @@
From a55eca67d3d95bf1db0e82ba1eaca5006419a9c4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= <berrange@redhat.com>
Date: Wed, 3 Jul 2024 13:32:32 +0100
Subject: [PATCH] meson: temporarily disable -Wunused-function
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Deleting the upstream versioned machine types will leave some functions
unused until RHEL machine types are added once again. Temporarily
disable the -Wunused-function warning to preserve bisectability with
fine grained patch splits.
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
Rebase notes (9.1.0)
- New patch
---
meson.build | 1 +
1 file changed, 1 insertion(+)
diff --git a/meson.build b/meson.build
index 50c774a195..0e0120a613 100644
--- a/meson.build
+++ b/meson.build
@@ -757,6 +757,7 @@ warn_flags = [
'-Wno-string-plus-int',
'-Wno-tautological-type-limit-compare',
'-Wno-typedef-redefinition',
+ '-Wno-unused-function',
]
if host_os != 'darwin'

View File

@ -1,99 +0,0 @@
From 8bb638561d3ad36be896d7648385d4fdb7bef0df Mon Sep 17 00:00:00 2001
From: Miroslav Rezanina <mrezanin@redhat.com>
Date: Wed, 10 Jul 2024 02:25:51 -0400
Subject: [PATCH] Remove upstream machine types for aarch64, s390x and x86_64
architectures
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
We will replace upstream machine types on supported architectures with RHEL
machine types.
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
Rebase notes (9.1.0):
- Split off commits adding RHEL machine types
---
hw/arm/virt.c | 2 ++
hw/i386/pc_piix.c | 2 ++
hw/i386/pc_q35.c | 2 ++
hw/s390x/s390-virtio-ccw.c | 3 +++
4 files changed, 9 insertions(+)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 1800981317..e6e98fef1c 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -3459,6 +3459,7 @@ static void machvirt_machine_init(void)
}
type_init(machvirt_machine_init);
+#if 0 /* Disabled for Red Hat Enterprise Linux */
static void virt_machine_10_1_options(MachineClass *mc)
{
}
@@ -3634,3 +3635,4 @@ static void virt_machine_4_1_options(MachineClass *mc)
mc->auto_enable_numa_with_memhp = false;
}
DEFINE_VIRT_MACHINE(4, 1)
+#endif /* disabled for RHEL */
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index c03324281b..acf010e20f 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -475,6 +475,7 @@ static void pc_i440fx_init(MachineState *machine)
#define DEFINE_I440FX_MACHINE_AS_LATEST(major, minor) \
DEFINE_PC_VER_MACHINE(pc_i440fx, "pc-i440fx", pc_i440fx_init, true, "pc", major, minor);
+#if 0 /* Disabled for Red Hat Enterprise Linux */
static void pc_i440fx_machine_options(MachineClass *m)
{
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
@@ -802,6 +803,7 @@ static void pc_i440fx_machine_2_6_options(MachineClass *m)
}
DEFINE_I440FX_MACHINE(2, 6);
+#endif /* Disabled for Red Hat Enterprise Linux */
#ifdef CONFIG_ISAPC
static void isapc_machine_options(MachineClass *m)
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index b309b2b378..2203ffd67e 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -374,6 +374,7 @@ static void pc_q35_machine_options(MachineClass *m)
pc_q35_compat_defaults, pc_q35_compat_defaults_len);
}
+#if 0 /* Disabled for Red Hat Enterprise Linux */
static void pc_q35_machine_10_1_options(MachineClass *m)
{
pc_q35_machine_options(m);
@@ -685,3 +686,4 @@ static void pc_q35_machine_2_6_options(MachineClass *m)
}
DEFINE_Q35_MACHINE(2, 6);
+#endif /* Disabled for Red Hat Enterprise Linux */
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index a79bd13275..2fca2bcf4d 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -911,6 +911,7 @@ static const TypeInfo ccw_machine_info = {
DEFINE_CCW_MACHINE_IMPL(false, major, minor)
+#if 0 /* Disabled for Red Hat Enterprise Linux */
static void ccw_machine_10_1_instance_options(MachineState *machine)
{
}
@@ -1167,6 +1168,8 @@ static void ccw_machine_4_2_class_options(MachineClass *mc)
}
DEFINE_CCW_MACHINE(4, 2);
+#endif /* disabled for RHEL */
+
static void ccw_machine_register_types(void)
{
type_register_static(&ccw_machine_info);

View File

@ -1,185 +0,0 @@
From 840ad52f0446382a948c97456ba94db17241c2de Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= <berrange@redhat.com>
Date: Wed, 3 Jul 2024 15:27:03 +0100
Subject: [PATCH] Adapt versioned machine type macros for RHEL
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The versioned machine type macros are changed thus:
* All symbol names get 'rhel' inserted eg 'virt_rhel_macine_9_4_0_<blah>'
* All machine type names get 'rhel' inserted eg 'virt-rhel9.4.0-machine'
* Lifecycle is changed to deprecate after 1 major RHEL release,
force non-registration (effectively deletion) after 2 major releases
* Custom message to explain RHEL deprecation/deletion policy
* Remove upstream logic that temporarily disabled deletion since
the upstream constraints in this area don't apply to RHEL
* For automatic deprecation/deletion, RHEL_VERSION is defined
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
---
docs/conf.py | 4 ++--
include/hw/boards.h | 39 ++++++++++++++---------------------
meson.build | 1 +
meson_options.txt | 2 ++
scripts/meson-buildoptions.sh | 2 ++
5 files changed, 23 insertions(+), 25 deletions(-)
diff --git a/docs/conf.py b/docs/conf.py
index f892a6e1da..0b8861e4bf 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -140,8 +140,8 @@
# MACHINE_VER_DELETION_MAJOR & MACHINE_VER_DEPRECATION_MAJOR
# defined in include/hw/boards.h and the introductory text in
# docs/about/deprecated.rst
-ver_machine_deprecation_version = "%d.%d.0" % (major - 3, minor)
-ver_machine_deletion_version = "%d.%d.0" % (major - 6, minor)
+ver_machine_deprecation_version = "%d.%d.0" % (major - 1, minor)
+ver_machine_deletion_version = "%d.%d.0" % (major - 2, minor)
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
diff --git a/include/hw/boards.h b/include/hw/boards.h
index a434b21909..da2fc92ce8 100644
--- a/include/hw/boards.h
+++ b/include/hw/boards.h
@@ -577,16 +577,16 @@ struct MachineState {
* "{prefix}-{major}.{minor}.{micro}-{tag}"
*/
#define _MACHINE_VER_TYPE_NAME2(prefix, major, minor) \
- prefix "-" #major "." #minor TYPE_MACHINE_SUFFIX
+ prefix "-rhel" #major "." #minor TYPE_MACHINE_SUFFIX
#define _MACHINE_VER_TYPE_NAME3(prefix, major, minor, micro) \
- prefix "-" #major "." #minor "." #micro TYPE_MACHINE_SUFFIX
+ prefix "-rhel" #major "." #minor "." #micro TYPE_MACHINE_SUFFIX
#define _MACHINE_VER_TYPE_NAME4(prefix, major, minor, _unused_, tag) \
- prefix "-" #major "." #minor "-" #tag TYPE_MACHINE_SUFFIX
+ prefix "-rhel" #major "." #minor "-" #tag TYPE_MACHINE_SUFFIX
#define _MACHINE_VER_TYPE_NAME5(prefix, major, minor, micro, _unused_, tag) \
- prefix "-" #major "." #minor "." #micro "-" #tag TYPE_MACHINE_SUFFIX
+ prefix "-rhel" #major "." #minor "." #micro "-" #tag TYPE_MACHINE_SUFFIX
#define MACHINE_VER_TYPE_NAME(prefix, ...) \
_MACHINE_VER_PICK(__VA_ARGS__, \
@@ -614,16 +614,16 @@ struct MachineState {
* {prefix}_machine_{major}_{minor}_{micro}_{tag}_{sym}
*/
#define _MACHINE_VER_SYM2(sym, prefix, major, minor) \
- prefix ## _machine_ ## major ## _ ## minor ## _ ## sym
+ prefix ## _rhel_machine_ ## major ## _ ## minor ## _ ## sym
#define _MACHINE_VER_SYM3(sym, prefix, major, minor, micro) \
- prefix ## _machine_ ## major ## _ ## minor ## _ ## micro ## _ ## sym
+ prefix ## _rhel_machine_ ## major ## _ ## minor ## _ ## micro ## _ ## sym
#define _MACHINE_VER_SYM4(sym, prefix, major, minor, _unused_, tag) \
- prefix ## _machine_ ## major ## _ ## minor ## _ ## tag ## _ ## sym
+ prefix ## _rhel_machine_ ## major ## _ ## minor ## _ ## tag ## _ ## sym
#define _MACHINE_VER_SYM5(sym, prefix, major, minor, micro, _unused_, tag) \
- prefix ## _machine_ ## major ## _ ## minor ## _ ## micro ## _ ## tag ## _ ## sym
+ prefix ## _rhel_machine_ ## major ## _ ## minor ## _ ## micro ## _ ## tag ## _ ## sym
#define MACHINE_VER_SYM(sym, prefix, ...) \
_MACHINE_VER_PICK(__VA_ARGS__, \
@@ -642,17 +642,16 @@ struct MachineState {
* and ver_machine_deletion_version logic in docs/conf.py and
* the text in docs/about/deprecated.rst
*/
-#define MACHINE_VER_DELETION_MAJOR 6
-#define MACHINE_VER_DEPRECATION_MAJOR 3
+#define MACHINE_VER_DELETION_MAJOR 2
+#define MACHINE_VER_DEPRECATION_MAJOR 1
/*
* Expands to a static string containing a deprecation
* message for a versioned machine type
*/
#define MACHINE_VER_DEPRECATION_MSG \
- "machines more than " stringify(MACHINE_VER_DEPRECATION_MAJOR) \
- " years old are subject to deletion after " \
- stringify(MACHINE_VER_DELETION_MAJOR) " years"
+ "machines from the previous RHEL major release are " \
+ "subject to deletion in the next RHEL major release"
#define _MACHINE_VER_IS_CURRENT_EXPIRED(cutoff, major, minor) \
(((QEMU_VERSION_MAJOR - major) > cutoff) || \
@@ -683,12 +682,7 @@ struct MachineState {
* If this ever changes the logic below will need modifying....
*/
#define _MACHINE_VER_IS_EXPIRED_IMPL(cutoff, major, minor) \
- ((QEMU_VERSION_MICRO < 50 && \
- _MACHINE_VER_IS_CURRENT_EXPIRED(cutoff, major, minor)) || \
- (QEMU_VERSION_MICRO >= 50 && QEMU_VERSION_MINOR < 2 && \
- _MACHINE_VER_IS_NEXT_MINOR_EXPIRED(cutoff, major, minor)) || \
- (QEMU_VERSION_MICRO >= 50 && QEMU_VERSION_MINOR == 2 && \
- _MACHINE_VER_IS_NEXT_MAJOR_EXPIRED(cutoff, major, minor)))
+ ((RHEL_VERSION - major) >= cutoff)
#define _MACHINE_VER_IS_EXPIRED2(cutoff, major, minor) \
_MACHINE_VER_IS_EXPIRED_IMPL(cutoff, major, minor)
@@ -750,10 +744,9 @@ struct MachineState {
* This must be unconditionally used in the register
* method for all machine types which support versioning.
*
- * Inijtially it will effectively be a no-op, but after a
- * suitable period of time has passed, it will cause
- * execution of the method to return, avoiding registration
- * of the machine
+ * It will automatically avoid registration of machines
+ * that should have been deleted at the start of this
+ * RHEL release
*/
#define MACHINE_VER_DELETION(...) \
do { \
diff --git a/meson.build b/meson.build
index 0e0120a613..23494666d9 100644
--- a/meson.build
+++ b/meson.build
@@ -2636,6 +2636,7 @@ config_host_data.set('QEMU_VERSION', '"@0@"'.format(meson.project_version()))
config_host_data.set('QEMU_VERSION_MAJOR', meson.project_version().split('.')[0])
config_host_data.set('QEMU_VERSION_MINOR', meson.project_version().split('.')[1])
config_host_data.set('QEMU_VERSION_MICRO', meson.project_version().split('.')[2])
+config_host_data.set('RHEL_VERSION', get_option('rhel_version').split('.')[0])
config_host_data.set_quoted('CONFIG_HOST_DSOSUF', host_dsosuf)
config_host_data.set('HAVE_HOST_BLOCK_DEVICE', have_host_block_device)
diff --git a/meson_options.txt b/meson_options.txt
index fff1521e58..f45d7ded45 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -2,6 +2,8 @@
# on the configure script command line. If you add more, list them in
# scripts/meson-buildoptions.py's SKIP_OPTIONS constant too.
+option('rhel_version', type: 'string', value: '0.0',
+ description: 'RHEL major/minor version')
option('qemu_suffix', type : 'string', value: 'qemu',
description: 'Suffix for QEMU data/modules/config directories (can be empty)')
option('docdir', type : 'string', value : 'share/doc',
diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh
index 0ebe6bc52a..4146dbc88d 100644
--- a/scripts/meson-buildoptions.sh
+++ b/scripts/meson-buildoptions.sh
@@ -75,6 +75,7 @@ meson_options_help() {
printf "%s\n" ' [QEMU]'
printf "%s\n" ' --qemu-ga-version=VALUE version number for qemu-ga installer'
printf "%s\n" ' --rtsig-map=VALUE default value of QEMU_RTSIG_MAP [NULL]'
+ printf "%s\n" ' --rhel-version=VALUE RHEL major/minor version [0.0]'
printf "%s\n" ' --smbd=VALUE Path to smbd for slirp networking'
printf "%s\n" ' --sysconfdir=VALUE Sysconf data directory [etc]'
printf "%s\n" ' --tls-priority=VALUE Default TLS protocol/cipher priority string'
@@ -465,6 +466,7 @@ _meson_option_parse() {
--disable-relocatable) printf "%s" -Drelocatable=false ;;
--enable-replication) printf "%s" -Dreplication=enabled ;;
--disable-replication) printf "%s" -Dreplication=disabled ;;
+ --rhel-version=*) quote_sh "-Drhel_version=$2" ;;
--enable-rng-none) printf "%s" -Drng_none=true ;;
--disable-rng-none) printf "%s" -Drng_none=false ;;
--rtsig-map=*) quote_sh "-Drtsig_map=$2" ;;

View File

@ -1,34 +0,0 @@
From 3d48892605114ddc144dca5b2f34e1ea5a7f1cb1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= <berrange@redhat.com>
Date: Wed, 3 Jul 2024 18:45:58 +0100
Subject: [PATCH] Increase deletion schedule to 4 releases
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Until RHEL 10 pc machine type is introduced, we have to keep
7.6.0 machine types as a special exception to our normal rule of
deleting machine types after 2 releases due to being a default
machine type.
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
Rebase notes (9.1.0)
- New patch
---
include/hw/boards.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/hw/boards.h b/include/hw/boards.h
index da2fc92ce8..aca254ea18 100644
--- a/include/hw/boards.h
+++ b/include/hw/boards.h
@@ -642,7 +642,7 @@ struct MachineState {
* and ver_machine_deletion_version logic in docs/conf.py and
* the text in docs/about/deprecated.rst
*/
-#define MACHINE_VER_DELETION_MAJOR 2
+#define MACHINE_VER_DELETION_MAJOR 4
#define MACHINE_VER_DEPRECATION_MAJOR 1
/*

View File

@ -1,368 +0,0 @@
From 48f8e990ce9175426e1d2c33c3ef64cbb06300ed Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= <berrange@redhat.com>
Date: Wed, 3 Jul 2024 13:25:47 +0100
Subject: [PATCH] Add downstream aarch64 versioned 'virt' machine types
Adding changes to add RHEL machine types for aarch64 architecture.
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
---
hw/arm/virt.c | 154 +++++++++++++++++++++++++++++++++++++-----
include/hw/arm/virt.h | 1 +
2 files changed, 137 insertions(+), 18 deletions(-)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index e6e98fef1c..d37d1bb3cf 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -97,6 +97,32 @@ static GlobalProperty arm_virt_compat[] = {
};
static const size_t arm_virt_compat_len = G_N_ELEMENTS(arm_virt_compat);
+/*
+ * RHEL9 kernels have pauth disabled while RHEL10 has it enabled,
+ * since qemu will setup the VM with pauth when KVM supports it we
+ * have to disable it for virt-rhel9* to support upgrades / migration.
+ */
+GlobalProperty arm_rhel9_compat[] = {
+ {TYPE_ARM_CPU, "pauth", "off", .optional = true},
+};
+const size_t arm_rhel9_compat_len = G_N_ELEMENTS(arm_rhel9_compat);
+
+/*
+ * This variable is for changes to properties that are RHEL specific,
+ * different to the current upstream and to be applied to the latest
+ * machine type. They may be overriden by older machine compats.
+ *
+ * virtio-net-pci variant romfiles are not needed because edk2 does
+ * fully support the pxe boot. Besides virtio romfiles are not shipped
+ * on rhel/aarch64.
+ */
+GlobalProperty arm_rhel_compat[] = {
+ {"virtio-net-pci", "romfile", "" },
+ {"virtio-net-pci-transitional", "romfile", "" },
+ {"virtio-net-pci-non-transitional", "romfile", "" },
+};
+const size_t arm_rhel_compat_len = G_N_ELEMENTS(arm_rhel_compat);
+
/*
* This cannot be called from the virt_machine_class_init() because
* TYPE_VIRT_MACHINE is abstract and mc->compat_props g_ptr_array_new()
@@ -106,6 +132,8 @@ static void arm_virt_compat_set(MachineClass *mc)
{
compat_props_add(mc->compat_props, arm_virt_compat,
arm_virt_compat_len);
+ compat_props_add(mc->compat_props, arm_rhel_compat,
+ arm_rhel_compat_len);
}
#define DEFINE_VIRT_MACHINE_IMPL(latest, ...) \
@@ -116,10 +144,11 @@ static void arm_virt_compat_set(MachineClass *mc)
MachineClass *mc = MACHINE_CLASS(oc); \
arm_virt_compat_set(mc); \
MACHINE_VER_SYM(options, virt, __VA_ARGS__)(mc); \
- mc->desc = "QEMU " MACHINE_VER_STR(__VA_ARGS__) " ARM Virtual Machine"; \
+ mc->desc = "RHEL " MACHINE_VER_STR(__VA_ARGS__) " ARM Virtual Machine"; \
MACHINE_VER_DEPRECATION(__VA_ARGS__); \
if (latest) { \
mc->alias = "virt"; \
+ mc->is_default = 1; \
} \
} \
static const TypeInfo MACHINE_VER_SYM(info, virt, __VA_ARGS__) = \
@@ -135,10 +164,10 @@ static void arm_virt_compat_set(MachineClass *mc)
} \
type_init(MACHINE_VER_SYM(register, virt, __VA_ARGS__));
-#define DEFINE_VIRT_MACHINE_AS_LATEST(major, minor) \
- DEFINE_VIRT_MACHINE_IMPL(true, major, minor)
-#define DEFINE_VIRT_MACHINE(major, minor) \
- DEFINE_VIRT_MACHINE_IMPL(false, major, minor)
+#define DEFINE_VIRT_MACHINE_AS_LATEST(major, minor, micro) \
+ DEFINE_VIRT_MACHINE_IMPL(true, major, minor, micro)
+#define DEFINE_VIRT_MACHINE(major, minor, micro) \
+ DEFINE_VIRT_MACHINE_IMPL(false, major, minor, micro)
/* Number of external interrupt lines to configure the GIC with */
@@ -1746,16 +1775,26 @@ static void virt_build_smbios(VirtMachineState *vms)
{
MachineClass *mc = MACHINE_GET_CLASS(vms);
MachineState *ms = MACHINE(vms);
+ VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms);
uint8_t *smbios_tables, *smbios_anchor;
size_t smbios_tables_len, smbios_anchor_len;
struct smbios_phys_mem_area mem_array;
+ const char *manufacturer = "QEMU";
const char *product = "QEMU Virtual Machine";
+ const char *version = mc->name;
if (kvm_enabled()) {
product = "KVM Virtual Machine";
}
- smbios_set_defaults("QEMU", product, mc->name, NULL, NULL);
+ if (!vmc->manufacturer_product_compat) {
+ manufacturer = "Red Hat";
+ product = "KVM";
+ version = mc->desc;
+ }
+
+ smbios_set_defaults(manufacturer, product, version,
+ NULL, NULL);
/* build the array of physical mem area from base_memmap */
mem_array.address = vms->memmap[VIRT_MEM].base;
@@ -2517,6 +2556,7 @@ static void machvirt_init(MachineState *machine)
qemu_add_machine_init_done_notifier(&vms->machine_done);
}
+#if 0 /* Disabled for Red Hat Enterprise Linux */
static bool virt_get_secure(Object *obj, Error **errp)
{
VirtMachineState *vms = VIRT_MACHINE(obj);
@@ -2544,6 +2584,7 @@ static void virt_set_virt(Object *obj, bool value, Error **errp)
vms->virt = value;
}
+#endif /* disabled for RHEL */
static bool virt_get_highmem(Object *obj, Error **errp)
{
@@ -2559,6 +2600,7 @@ static void virt_set_highmem(Object *obj, bool value, Error **errp)
vms->highmem = value;
}
+#if 0 /* Disabled for Red Hat Enterprise Linux */
static bool virt_get_compact_highmem(Object *obj, Error **errp)
{
VirtMachineState *vms = VIRT_MACHINE(obj);
@@ -2572,6 +2614,7 @@ static void virt_set_compact_highmem(Object *obj, bool value, Error **errp)
vms->highmem_compact = value;
}
+#endif /* disabled for RHEL */
static bool virt_get_highmem_redists(Object *obj, Error **errp)
{
@@ -2664,6 +2707,7 @@ static void virt_set_its(Object *obj, bool value, Error **errp)
vms->its = value;
}
+#if 0 /* Disabled for Red Hat Enterprise Linux */
static bool virt_get_dtb_randomness(Object *obj, Error **errp)
{
VirtMachineState *vms = VIRT_MACHINE(obj);
@@ -2677,6 +2721,7 @@ static void virt_set_dtb_randomness(Object *obj, bool value, Error **errp)
vms->dtb_randomness = value;
}
+#endif /* disabled for RHEL */
static char *virt_get_oem_id(Object *obj, Error **errp)
{
@@ -2760,6 +2805,7 @@ static void virt_set_ras(Object *obj, bool value, Error **errp)
vms->ras = value;
}
+#if 0 /* Disabled for Red Hat Enterprise Linux */
static bool virt_get_mte(Object *obj, Error **errp)
{
VirtMachineState *vms = VIRT_MACHINE(obj);
@@ -2773,6 +2819,7 @@ static void virt_set_mte(Object *obj, bool value, Error **errp)
vms->mte = value;
}
+#endif /* disabled for RHEL */
static char *virt_get_gic_version(Object *obj, Error **errp)
{
@@ -3213,16 +3260,16 @@ static void virt_machine_class_init(ObjectClass *oc, const void *data)
NULL
};
+ mc->family = "virt-rhel-Z";
mc->init = machvirt_init;
- /* Start with max_cpus set to 512, which is the maximum supported by KVM.
- * The value may be reduced later when we have more information about the
- * configuration of the particular instance.
- */
- mc->max_cpus = 512;
+ /* Maximum supported VCPU count for all virt-rhel* machines */
+ mc->max_cpus = 384;
+#if 0 /* Disabled for Red Hat Enterprise Linux */
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_VFIO_CALXEDA_XGMAC);
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_VFIO_AMD_XGBE);
- machine_class_allow_dynamic_sysbus_dev(mc, TYPE_RAMFB_DEVICE);
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_VFIO_PLATFORM);
+#endif
+ machine_class_allow_dynamic_sysbus_dev(mc, TYPE_RAMFB_DEVICE);
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_UEFI_VARS_SYSBUS);
#ifdef CONFIG_TPM
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_TPM_TIS_SYSBUS);
@@ -3234,11 +3281,7 @@ static void virt_machine_class_init(ObjectClass *oc, const void *data)
mc->minimum_page_bits = 12;
mc->possible_cpu_arch_ids = virt_possible_cpu_arch_ids;
mc->cpu_index_to_instance_props = virt_cpu_index_to_props;
-#ifdef CONFIG_TCG
- mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a15");
-#else
- mc->default_cpu_type = ARM_CPU_TYPE_NAME("max");
-#endif
+ mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a57");
mc->valid_cpu_types = valid_cpu_types;
mc->get_default_cpu_node_id = virt_get_default_cpu_node_id;
mc->kvm_type = virt_kvm_type;
@@ -3263,6 +3306,7 @@ static void virt_machine_class_init(ObjectClass *oc, const void *data)
NULL, NULL);
object_class_property_set_description(oc, "acpi",
"Enable ACPI");
+#if 0 /* disabled for RHEL */
object_class_property_add_bool(oc, "secure", virt_get_secure,
virt_set_secure);
object_class_property_set_description(oc, "secure",
@@ -3275,6 +3319,7 @@ static void virt_machine_class_init(ObjectClass *oc, const void *data)
"Set on/off to enable/disable emulating a "
"guest CPU which implements the ARM "
"Virtualization Extensions");
+#endif /* disabled for RHEL */
object_class_property_add_bool(oc, "highmem", virt_get_highmem,
virt_set_highmem);
@@ -3282,12 +3327,14 @@ static void virt_machine_class_init(ObjectClass *oc, const void *data)
"Set on/off to enable/disable using "
"physical address space above 32 bits");
+#if 0 /* disabled for RHEL */
object_class_property_add_bool(oc, "compact-highmem",
virt_get_compact_highmem,
virt_set_compact_highmem);
object_class_property_set_description(oc, "compact-highmem",
"Set on/off to enable/disable compact "
"layout for high memory regions");
+#endif /* disabled for RHEL */
object_class_property_add_bool(oc, "highmem-redists",
virt_get_highmem_redists,
@@ -3323,7 +3370,7 @@ static void virt_machine_class_init(ObjectClass *oc, const void *data)
virt_set_gic_version);
object_class_property_set_description(oc, "gic-version",
"Set GIC version. "
- "Valid values are 2, 3, 4, host and max");
+ "Valid values are 2, 3, host and max");
object_class_property_add_str(oc, "iommu", virt_get_iommu, virt_set_iommu);
object_class_property_set_description(oc, "iommu",
@@ -3343,11 +3390,13 @@ static void virt_machine_class_init(ObjectClass *oc, const void *data)
"Set on/off to enable/disable reporting host memory errors "
"to a KVM guest using ACPI and guest external abort exceptions");
+#if 0 /* disabled for RHEL */
object_class_property_add_bool(oc, "mte", virt_get_mte, virt_set_mte);
object_class_property_set_description(oc, "mte",
"Set on/off to enable/disable emulating a "
"guest CPU which implements the ARM "
"Memory Tagging Extension");
+#endif /* disabled for RHEL */
object_class_property_add_bool(oc, "its", virt_get_its,
virt_set_its);
@@ -3355,6 +3404,7 @@ static void virt_machine_class_init(ObjectClass *oc, const void *data)
"Set on/off to enable/disable "
"ITS instantiation");
+#if 0 /* disabled for RHEL */
object_class_property_add_bool(oc, "dtb-randomness",
virt_get_dtb_randomness,
virt_set_dtb_randomness);
@@ -3367,6 +3417,7 @@ static void virt_machine_class_init(ObjectClass *oc, const void *data)
virt_set_dtb_randomness);
object_class_property_set_description(oc, "dtb-kaslr-seed",
"Deprecated synonym of dtb-randomness");
+#endif /* disabled for RHEL */
object_class_property_add_str(oc, "x-oem-id",
virt_get_oem_id,
@@ -3636,3 +3687,70 @@ static void virt_machine_4_1_options(MachineClass *mc)
}
DEFINE_VIRT_MACHINE(4, 1)
#endif /* disabled for RHEL */
+
+static void virt_rhel_machine_10_0_0_options(MachineClass *mc)
+{
+ VirtMachineClass *vmc = VIRT_MACHINE_CLASS(OBJECT_CLASS(mc));
+
+ /* QEMU 9.1 and earlier have only a stage-1 SMMU, not a nested s1+2 one */
+ vmc->no_nested_smmu = true;
+ compat_props_add(mc->compat_props, hw_compat_rhel_10_2, hw_compat_rhel_10_2_len);
+ compat_props_add(mc->compat_props, hw_compat_rhel_10_1, hw_compat_rhel_10_1_len);
+}
+DEFINE_VIRT_MACHINE_AS_LATEST(10, 0, 0)
+
+static void virt_rhel_machine_9_6_0_options(MachineClass *mc)
+{
+ virt_rhel_machine_10_0_0_options(mc);
+
+ compat_props_add(mc->compat_props, arm_rhel9_compat, arm_rhel9_compat_len);
+ /* NB: remember to move this line to the *latest* RHEL 9 machine */
+ compat_props_add(mc->compat_props, hw_compat_rhel_9, hw_compat_rhel_9_len);
+}
+DEFINE_VIRT_MACHINE(9, 6, 0)
+
+static void virt_rhel_machine_9_4_0_options(MachineClass *mc)
+{
+ VirtMachineClass *vmc = VIRT_MACHINE_CLASS(OBJECT_CLASS(mc));
+
+ virt_rhel_machine_9_6_0_options(mc);
+
+ /* From virt_machine_9_0_options() */
+ mc->smbios_memory_device_size = 16 * GiB;
+
+ compat_props_add(mc->compat_props, hw_compat_rhel_10_0, hw_compat_rhel_10_0_len);
+ compat_props_add(mc->compat_props, hw_compat_rhel_9_5, hw_compat_rhel_9_5_len);
+
+ vmc->manufacturer_product_compat = true;
+}
+DEFINE_VIRT_MACHINE(9, 4, 0)
+
+static void virt_rhel_machine_9_2_0_options(MachineClass *mc)
+{
+ virt_rhel_machine_9_4_0_options(mc);
+
+ compat_props_add(mc->compat_props, hw_compat_rhel_9_4, hw_compat_rhel_9_4_len);
+ compat_props_add(mc->compat_props, hw_compat_rhel_9_3, hw_compat_rhel_9_3_len);
+ compat_props_add(mc->compat_props, hw_compat_rhel_9_2, hw_compat_rhel_9_2_len);
+
+ /* RHEL 9.4 is the first supported release */
+ mc->deprecation_reason =
+ "machine types for versions prior to 9.4 are deprecated";
+}
+DEFINE_VIRT_MACHINE(9, 2, 0)
+
+static void virt_rhel_machine_9_0_0_options(MachineClass *mc)
+{
+ VirtMachineClass *vmc = VIRT_MACHINE_CLASS(OBJECT_CLASS(mc));
+
+ virt_rhel_machine_9_2_0_options(mc);
+
+ compat_props_add(mc->compat_props, hw_compat_rhel_9_1, hw_compat_rhel_9_1_len);
+ compat_props_add(mc->compat_props, hw_compat_rhel_9_0, hw_compat_rhel_9_0_len);
+
+ /* Disable FEAT_LPA2 since old kernels (<= v5.12) don't boot with that feature */
+ vmc->no_tcg_lpa2 = true;
+ /* Compact layout for high memory regions was introduced with 9.2.0 */
+ vmc->no_highmem_compact = true;
+}
+DEFINE_VIRT_MACHINE(9, 0, 0)
diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
index 365a28b082..94c79d6c6d 100644
--- a/include/hw/arm/virt.h
+++ b/include/hw/arm/virt.h
@@ -132,6 +132,7 @@ struct VirtMachineClass {
bool no_tcg_lpa2;
bool no_ns_el2_virt_timer_irq;
bool no_nested_smmu;
+ bool manufacturer_product_compat;
};
struct VirtMachineState {

View File

@ -1,260 +0,0 @@
From d944ff2722e07a8829b918ec1e414fd7a1421ca1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= <berrange@redhat.com>
Date: Wed, 3 Jul 2024 13:44:36 +0100
Subject: [PATCH] Add downstream s390x versioned 's390-ccw-virtio' machine
types
Adding changes to add RHEL machine types for s390x architecture.
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
--
Rebase notes(9.1.0):
- Convert to new DEFINE_CCW_MACHINE macros
Rebase notes (10.0.0):
- Use upstream compat
- Disabled relaxed-translation for older types
Rebase notes (10.1.0):
- Use rebase compat
Merged patches (9.1.0):
- 043ad5ce97 Add upstream compatibility bits (partial)
- 04596b496e s390x: remove deprecated rhel machine types
Merged patches (10.0.0 rc0):
- 03502faf70 Add upstream compatibility bits (partial)
- d27437e5ba redhat: Add QEMU 9.1 compat handling to the s390x machine types
- 926a9d0ca2 redhat: Add rhel9.6.0 and rhel10.0.0 machine types
- d93fcb3940 virtio-net: disable USO for all RHEL9 (partial)
---
hw/s390x/s390-virtio-ccw.c | 106 +++++++++++++++++++++++++++++--
target/s390x/cpu_models.c | 11 ++++
target/s390x/cpu_models.h | 2 +
target/s390x/cpu_models_system.c | 2 +
4 files changed, 116 insertions(+), 5 deletions(-)
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index 2fca2bcf4d..9be423858d 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -716,6 +716,7 @@ static void s390_nmi(NMIState *n, int cpu_index, Error **errp)
s390_cpu_restart(S390_CPU(cs));
}
+#if 0 /* Disabled for Red Hat Enterprise Linux */
static ram_addr_t s390_fixup_ram_size(ram_addr_t sz)
{
/* same logic as in sclp.c */
@@ -735,6 +736,7 @@ static ram_addr_t s390_fixup_ram_size(ram_addr_t sz)
}
return newsz;
}
+#endif /* disabled for RHEL */
static inline bool machine_get_aes_key_wrap(Object *obj, Error **errp)
{
@@ -883,7 +885,7 @@ static const TypeInfo ccw_machine_info = {
{ \
MachineClass *mc = MACHINE_CLASS(oc); \
MACHINE_VER_SYM(class_options, ccw, __VA_ARGS__)(mc); \
- mc->desc = "Virtual s390x machine (version " MACHINE_VER_STR(__VA_ARGS__) ")"; \
+ mc->desc = "Virtual s390x machine (version rhel" MACHINE_VER_STR(__VA_ARGS__) ")"; \
mc->init = MACHINE_VER_SYM(mach_init, ccw, __VA_ARGS__); \
MACHINE_VER_DEPRECATION(__VA_ARGS__); \
if (latest) { \
@@ -904,11 +906,11 @@ static const TypeInfo ccw_machine_info = {
} \
type_init(MACHINE_VER_SYM(register, ccw, __VA_ARGS__))
-#define DEFINE_CCW_MACHINE_AS_LATEST(major, minor) \
- DEFINE_CCW_MACHINE_IMPL(true, major, minor)
+#define DEFINE_CCW_MACHINE_AS_LATEST(major, minor, micro) \
+ DEFINE_CCW_MACHINE_IMPL(true, major, minor, micro)
-#define DEFINE_CCW_MACHINE(major, minor) \
- DEFINE_CCW_MACHINE_IMPL(false, major, minor)
+#define DEFINE_CCW_MACHINE(major, minor, micro) \
+ DEFINE_CCW_MACHINE_IMPL(false, major, minor, micro)
#if 0 /* Disabled for Red Hat Enterprise Linux */
@@ -1170,6 +1172,100 @@ DEFINE_CCW_MACHINE(4, 2);
#endif /* disabled for RHEL */
+static void ccw_rhel_machine_10_0_0_instance_options(MachineState *machine)
+{
+}
+
+static void ccw_rhel_machine_10_0_0_class_options(MachineClass *mc)
+{
+ S390CcwMachineClass *s390mc = S390_CCW_MACHINE_CLASS(mc);
+ static GlobalProperty compat[] = {
+ { TYPE_S390_PCI_DEVICE, "relaxed-translation", "off", },
+ };
+
+ compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
+ compat_props_add(mc->compat_props, hw_compat_rhel_10_2, hw_compat_rhel_10_2_len);
+ compat_props_add(mc->compat_props, hw_compat_rhel_10_1, hw_compat_rhel_10_1_len);
+ s390mc->use_cpi = false;
+}
+DEFINE_CCW_MACHINE_AS_LATEST(10, 0, 0);
+
+static void ccw_rhel_machine_9_6_0_instance_options(MachineState *machine)
+{
+ ccw_rhel_machine_10_0_0_instance_options(machine);
+}
+
+static void ccw_rhel_machine_9_6_0_class_options(MachineClass *mc)
+{
+ ccw_rhel_machine_10_0_0_class_options(mc);
+
+ /* NB: remember to move this line to the *latest* RHEL 9 machine */
+ compat_props_add(mc->compat_props, hw_compat_rhel_9, hw_compat_rhel_9_len);
+}
+DEFINE_CCW_MACHINE(9, 6, 0);
+
+static void ccw_rhel_machine_9_4_0_instance_options(MachineState *machine)
+{
+ ccw_rhel_machine_9_6_0_instance_options(machine);
+}
+
+static void ccw_rhel_machine_9_4_0_class_options(MachineClass *mc)
+{
+ static GlobalProperty compat[] = {
+ { TYPE_QEMU_S390_FLIC, "migrate-all-state", "off", },
+ };
+
+ ccw_rhel_machine_9_6_0_class_options(mc);
+
+ compat_props_add(mc->compat_props, hw_compat_rhel_10_0, hw_compat_rhel_10_0_len);
+ compat_props_add(mc->compat_props, hw_compat_rhel_9_5, hw_compat_rhel_9_5_len);
+ compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
+}
+DEFINE_CCW_MACHINE(9, 4, 0);
+
+static void ccw_rhel_machine_9_2_0_instance_options(MachineState *machine)
+{
+ ccw_rhel_machine_9_4_0_instance_options(machine);
+}
+
+static void ccw_rhel_machine_9_2_0_class_options(MachineClass *mc)
+{
+ ccw_rhel_machine_9_4_0_class_options(mc);
+ compat_props_add(mc->compat_props, hw_compat_rhel_9_4, hw_compat_rhel_9_4_len);
+ compat_props_add(mc->compat_props, hw_compat_rhel_9_3, hw_compat_rhel_9_3_len);
+ compat_props_add(mc->compat_props, hw_compat_rhel_9_2, hw_compat_rhel_9_2_len);
+ mc->smp_props.drawers_supported = false; /* from ccw_machine_8_1 */
+ mc->smp_props.books_supported = false; /* from ccw_machine_8_1 */
+}
+DEFINE_CCW_MACHINE(9, 2, 0);
+
+static void ccw_rhel_machine_9_0_0_instance_options(MachineState *machine)
+{
+ static const S390FeatInit qemu_cpu_feat = { S390_FEAT_LIST_QEMU_V6_2 };
+
+ ccw_rhel_machine_9_2_0_instance_options(machine);
+
+ s390_set_qemu_cpu_model(0x3906, 14, 2, qemu_cpu_feat);
+ s390_cpudef_featoff_greater(16, 1, S390_FEAT_PAIE);
+}
+
+static void ccw_rhel_machine_9_0_0_class_options(MachineClass *mc)
+{
+ S390CcwMachineClass *s390mc = S390_CCW_MACHINE_CLASS(mc);
+ static GlobalProperty compat[] = {
+ { TYPE_S390_PCI_DEVICE, "interpret", "off", },
+ { TYPE_S390_PCI_DEVICE, "forwarding-assist", "off", },
+ };
+
+ ccw_rhel_machine_9_2_0_class_options(mc);
+
+ compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
+ compat_props_add(mc->compat_props, hw_compat_rhel_9_1, hw_compat_rhel_9_1_len);
+ compat_props_add(mc->compat_props, hw_compat_rhel_9_0, hw_compat_rhel_9_0_len);
+ s390mc->max_threads = S390_MAX_CPUS;
+}
+DEFINE_CCW_MACHINE(9, 0, 0);
+
static void ccw_machine_register_types(void)
{
type_register_static(&ccw_machine_info);
diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c
index fe29f5c5b7..2a7fc949a4 100644
--- a/target/s390x/cpu_models.c
+++ b/target/s390x/cpu_models.c
@@ -47,6 +47,9 @@
* of a following release have been a superset of the previous release. With
* generation 15 one base feature and one optional feature have been deprecated.
*/
+
+#define RHEL_CPU_DEPRECATION "use at least 'z14', or 'host' / 'qemu' / 'max'"
+
static S390CPUDef s390_cpu_defs[] = {
/*
* Linux requires at least z10 nowadays, and IBM only supports recent CPUs
@@ -931,22 +934,30 @@ static void s390_host_cpu_model_class_init(ObjectClass *oc, const void *data)
static void s390_base_cpu_model_class_init(ObjectClass *oc, const void *data)
{
S390CPUClass *xcc = S390_CPU_CLASS(oc);
+ CPUClass *cc = CPU_CLASS(oc);
/* all base models are migration safe */
xcc->cpu_def = (const S390CPUDef *) data;
xcc->is_migration_safe = true;
xcc->is_static = true;
xcc->desc = xcc->cpu_def->desc;
+ if (xcc->cpu_def->gen < 14) {
+ cc->deprecation_note = RHEL_CPU_DEPRECATION;
+ }
}
static void s390_cpu_model_class_init(ObjectClass *oc, const void *data)
{
S390CPUClass *xcc = S390_CPU_CLASS(oc);
+ CPUClass *cc = CPU_CLASS(oc);
/* model that can change between QEMU versions */
xcc->cpu_def = (const S390CPUDef *) data;
xcc->is_migration_safe = true;
xcc->desc = xcc->cpu_def->desc;
+ if (xcc->cpu_def->gen < 14) {
+ cc->deprecation_note = RHEL_CPU_DEPRECATION;
+ }
}
static void s390_qemu_cpu_model_class_init(ObjectClass *oc, const void *data)
diff --git a/target/s390x/cpu_models.h b/target/s390x/cpu_models.h
index f701bc0b53..670a567c67 100644
--- a/target/s390x/cpu_models.h
+++ b/target/s390x/cpu_models.h
@@ -38,6 +38,8 @@ typedef struct S390CPUDef {
S390FeatBitmap full_feat;
/* used to init full_feat from generated data */
S390FeatInit full_init;
+ /* if deprecated, provides a suggestion */
+ const char *deprecation_note;
} S390CPUDef;
/* CPU model based on a CPU definition */
diff --git a/target/s390x/cpu_models_system.c b/target/s390x/cpu_models_system.c
index 5b84604867..d715bdc870 100644
--- a/target/s390x/cpu_models_system.c
+++ b/target/s390x/cpu_models_system.c
@@ -56,6 +56,7 @@ static void create_cpu_model_list(ObjectClass *klass, void *opaque)
CpuDefinitionInfo *info;
char *name = g_strdup(object_class_get_name(klass));
S390CPUClass *scc = S390_CPU_CLASS(klass);
+ CPUClass *cc = CPU_CLASS(klass);
/* strip off the -s390x-cpu */
g_strrstr(name, "-" TYPE_S390_CPU)[0] = 0;
@@ -65,6 +66,7 @@ static void create_cpu_model_list(ObjectClass *klass, void *opaque)
info->migration_safe = scc->is_migration_safe;
info->q_static = scc->is_static;
info->q_typename = g_strdup(object_class_get_name(klass));
+ info->deprecated = !!cc->deprecation_note;
/* check for unavailable features */
if (cpu_list_data->model) {
Object *obj;

View File

@ -1,485 +0,0 @@
From a4d11d87c642d697cdacf5eaf5cd6a6d2a0bbe0e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= <berrange@redhat.com>
Date: Wed, 3 Jul 2024 13:44:41 +0100
Subject: [PATCH] Add downstream x86_64 versioned 'pc' & 'q35' machine types
Adding changes to add RHEL machine types for x86_64 architecture.
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
---
hw/i386/fw_cfg.c | 2 +-
hw/i386/pc.c | 70 ++++++++++++++++++++-
hw/i386/pc_piix.c | 55 +++++++++++++++--
hw/i386/pc_q35.c | 123 ++++++++++++++++++++++++++++++++++---
include/hw/boards.h | 2 +
include/hw/i386/pc.h | 21 +++++++
target/i386/kvm/kvm-cpu.c | 1 +
target/i386/kvm/kvm.c | 4 ++
tests/qtest/meson.build | 2 +-
tests/qtest/pvpanic-test.c | 5 +-
10 files changed, 267 insertions(+), 18 deletions(-)
diff --git a/hw/i386/fw_cfg.c b/hw/i386/fw_cfg.c
index 07df7281d2..8009f5f31f 100644
--- a/hw/i386/fw_cfg.c
+++ b/hw/i386/fw_cfg.c
@@ -75,7 +75,7 @@ void fw_cfg_build_smbios(PCMachineState *pcms, FWCfgState *fw_cfg,
if (pcmc->smbios_defaults) {
/* These values are guest ABI, do not change */
- smbios_set_defaults("QEMU", mc->desc, mc->name,
+ smbios_set_defaults("Red Hat", "KVM", mc->desc,
pcmc->smbios_stream_product, pcmc->smbios_stream_version);
}
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 2f58e73d33..439abe8f46 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -273,6 +273,72 @@ const size_t pc_compat_2_6_len = G_N_ELEMENTS(pc_compat_2_6);
*/
#define PC_FW_DATA (0x20000 + 0x8000)
+/* This macro is for changes to properties that are RHEL specific,
+ * different to the current upstream and to be applied to the latest
+ * machine type.
+ */
+GlobalProperty pc_rhel_compat[] = {
+ /* we don't support s3/s4 suspend */
+ { "PIIX4_PM", "disable_s3", "1" },
+ { "PIIX4_PM", "disable_s4", "1" },
+ { "ICH9-LPC", "disable_s3", "1" },
+ { "ICH9-LPC", "disable_s4", "1" },
+
+ { TYPE_X86_CPU, "host-phys-bits", "on" },
+ { TYPE_X86_CPU, "host-phys-bits-limit", "48" },
+ { TYPE_X86_CPU, "vmx-entry-load-perf-global-ctrl", "off" },
+ { TYPE_X86_CPU, "vmx-exit-load-perf-global-ctrl", "off" },
+ /* bz 1508330 */
+ { "vfio-pci", "x-no-geforce-quirks", "on" },
+ /* bz 1941397 */
+ { TYPE_X86_CPU, "kvm-asyncpf-int", "on" },
+};
+const size_t pc_rhel_compat_len = G_N_ELEMENTS(pc_rhel_compat);
+
+GlobalProperty pc_rhel_10_2_compat[] = {
+ /* pc_rhel_10_2_compat from pc_compat_10_0 */
+ { TYPE_X86_CPU, "x-consistent-cache", "false" },
+ { TYPE_X86_CPU, "x-vendor-cpuid-only-v2", "false" },
+};
+const size_t pc_rhel_10_2_compat_len = G_N_ELEMENTS(pc_compat_10_0);
+
+GlobalProperty pc_rhel_10_1_compat[] = {
+ /* pc_rhel_10_1_compat from pc_compat_9_1 */
+ { "ICH9-LPC", "x-smi-swsmi-timer", "off" },
+ { "ICH9-LPC", "x-smi-periodic-timer", "off" },
+ { TYPE_INTEL_IOMMU_DEVICE, "stale-tm", "on" },
+ { TYPE_INTEL_IOMMU_DEVICE, "aw-bits", "39" },
+};
+const size_t pc_rhel_10_1_compat_len = G_N_ELEMENTS(pc_rhel_10_1_compat);
+
+GlobalProperty pc_rhel_10_0_compat[] = {
+ /* pc_rhel_10_0_compat from pc_compat_9_0 */
+ { TYPE_X86_CPU, "x-amd-topoext-features-only", "false" },
+ { TYPE_X86_CPU, "x-l1-cache-per-thread", "false" },
+ { TYPE_X86_CPU, "guest-phys-bits", "0" },
+ { "sev-guest", "legacy-vm-type", "on" },
+ { TYPE_X86_CPU, "legacy-multi-node", "on" },
+};
+const size_t pc_rhel_10_0_compat_len = G_N_ELEMENTS(pc_rhel_10_0_compat);
+
+GlobalProperty pc_rhel_9_3_compat[] = {
+ /* pc_rhel_9_3_compat from pc_compat_8_0 */
+ { "virtio-mem", "unplugged-inaccessible", "auto" },
+};
+const size_t pc_rhel_9_3_compat_len = G_N_ELEMENTS(pc_rhel_9_3_compat);
+
+GlobalProperty pc_rhel_9_2_compat[] = {
+ /* pc_rhel_9_2_compat from pc_compat_7_2 */
+ { "ICH9-LPC", "noreboot", "true" },
+};
+const size_t pc_rhel_9_2_compat_len = G_N_ELEMENTS(pc_rhel_9_2_compat);
+
+GlobalProperty pc_rhel_9_0_compat[] = {
+ /* pc_rhel_9_0_compat from pc_compat_6_2 */
+ { "virtio-mem", "unplugged-inaccessible", "off" },
+};
+const size_t pc_rhel_9_0_compat_len = G_N_ELEMENTS(pc_rhel_9_0_compat);
+
GSIState *pc_gsi_create(qemu_irq **irqs, bool pci_enabled)
{
GSIState *s;
@@ -1754,6 +1820,7 @@ static void pc_machine_class_init(ObjectClass *oc, const void *data)
pcmc->kvmclock_create_always = true;
x86mc->apic_xrupt_override = true;
assert(!mc->get_hotplug_handler);
+ mc->async_pf_vmexit_disable = false;
mc->get_hotplug_handler = pc_get_hotplug_handler;
mc->hotplug_allowed = pc_hotplug_allowed;
mc->auto_enable_numa_with_memhp = true;
@@ -1761,7 +1828,8 @@ static void pc_machine_class_init(ObjectClass *oc, const void *data)
mc->has_hotpluggable_cpus = true;
mc->default_boot_order = "cad";
mc->block_default_type = IF_IDE;
- mc->max_cpus = 255;
+ /* 240: max CPU count for RHEL */
+ mc->max_cpus = 240;
mc->reset = pc_machine_reset;
mc->wakeup = pc_machine_wakeup;
hc->pre_plug = pc_machine_device_pre_plug_cb;
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index acf010e20f..d546c4a8a9 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -53,6 +53,7 @@
#include "qapi/error.h"
#include "qemu/error-report.h"
#include "system/xen.h"
+#include "migration/migration.h"
#ifdef CONFIG_XEN
#include <xen/hvm/hvm_info_table.h>
#include "hw/xen/xen_pt.h"
@@ -469,11 +470,11 @@ static void pc_i440fx_init(MachineState *machine)
pc_init1(machine, TYPE_I440FX_PCI_DEVICE);
}
-#define DEFINE_I440FX_MACHINE(major, minor) \
- DEFINE_PC_VER_MACHINE(pc_i440fx, "pc-i440fx", pc_i440fx_init, false, NULL, major, minor);
+#define DEFINE_I440FX_MACHINE(major, minor, micro) \
+ DEFINE_PC_VER_MACHINE(pc_i440fx, "pc-i440fx", pc_i440fx_init, false, NULL, major, minor, micro);
-#define DEFINE_I440FX_MACHINE_AS_LATEST(major, minor) \
- DEFINE_PC_VER_MACHINE(pc_i440fx, "pc-i440fx", pc_i440fx_init, true, "pc", major, minor);
+#define DEFINE_I440FX_MACHINE_AS_LATEST(major, minor, micro) \
+ DEFINE_PC_VER_MACHINE(pc_i440fx, "pc-i440fx", pc_i440fx_init, true, "pc", major, minor, micro);
#if 0 /* Disabled for Red Hat Enterprise Linux */
static void pc_i440fx_machine_options(MachineClass *m)
@@ -853,3 +854,49 @@ static void xenfv_machine_3_1_options(MachineClass *m)
DEFINE_PC_MACHINE(xenfv, "xenfv-3.1", pc_xen_hvm_init,
xenfv_machine_3_1_options);
#endif
+
+/* Red Hat Enterprise Linux machine types */
+
+static void pc_machine_rhel10_options(MachineClass *m)
+{
+ PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
+ ObjectClass *oc = OBJECT_CLASS(m);
+ pcmc->default_south_bridge = TYPE_PIIX3_DEVICE;
+ pcmc->pci_root_uid = 0;
+ pcmc->default_cpu_version = 1;
+
+ m->family = "pc_piix_Y";
+ m->default_machine_opts = "firmware=bios-256k.bin";
+ m->default_display = "std";
+ m->default_nic = "e1000";
+ m->no_parallel = 1;
+ m->no_floppy = 1;
+ machine_class_allow_dynamic_sysbus_dev(m, TYPE_RAMFB_DEVICE);
+
+ object_class_property_add_enum(oc, "x-south-bridge", "PCSouthBridgeOption",
+ &PCSouthBridgeOption_lookup,
+ pc_get_south_bridge,
+ pc_set_south_bridge);
+ object_class_property_set_description(oc, "x-south-bridge",
+ "Use a different south bridge than PIIX3");
+ compat_props_add(m->compat_props,
+ pc_piix_compat_defaults, pc_piix_compat_defaults_len);
+}
+
+static void pc_i440fx_rhel_machine_10_0_0_options(MachineClass *m)
+{
+ pc_machine_rhel10_options(m);
+
+ m->desc = "RHEL 10.0.0 PC (i440FX + PIIX, 1996)";
+ m->deprecation_reason = rhel_old_machine_deprecation;
+
+ compat_props_add(m->compat_props, hw_compat_rhel_10_2,
+ hw_compat_rhel_10_2_len);
+ compat_props_add(m->compat_props, hw_compat_rhel_10_1,
+ hw_compat_rhel_10_1_len);
+ compat_props_add(m->compat_props, pc_rhel_10_2_compat,
+ pc_rhel_10_2_compat_len);
+ compat_props_add(m->compat_props, pc_rhel_10_1_compat,
+ pc_rhel_10_1_compat_len);
+}
+DEFINE_I440FX_MACHINE_AS_LATEST(10, 0, 0);
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index 2203ffd67e..e5d10c0335 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -340,11 +340,11 @@ static void pc_q35_init(MachineState *machine)
#endif
}
-#define DEFINE_Q35_MACHINE(major, minor) \
- DEFINE_PC_VER_MACHINE(pc_q35, "pc-q35", pc_q35_init, false, NULL, major, minor);
+#define DEFINE_Q35_MACHINE(major, minor, micro) \
+ DEFINE_PC_VER_MACHINE(pc_q35, "pc-q35", pc_q35_init, false, NULL, major, minor, micro);
-#define DEFINE_Q35_MACHINE_AS_LATEST(major, minor) \
- DEFINE_PC_VER_MACHINE(pc_q35, "pc-q35", pc_q35_init, false, "q35", major, minor);
+#define DEFINE_Q35_MACHINE_AS_LATEST(major, minor, micro) \
+ DEFINE_PC_VER_MACHINE(pc_q35, "pc-q35", pc_q35_init, false, "q35", major, minor, micro);
#define DEFINE_Q35_MACHINE_BUGFIX(major, minor, micro) \
DEFINE_PC_VER_MACHINE(pc_q35, "pc-q35", pc_q35_init, false, NULL, major, minor, micro);
@@ -355,21 +355,21 @@ static void pc_q35_machine_options(MachineClass *m)
pcmc->pci_root_uid = 0;
pcmc->default_cpu_version = 1;
- m->family = "pc_q35";
- m->desc = "Standard PC (Q35 + ICH9, 2009)";
+ m->family = "pc_q35_Z";
m->units_per_default_bus = 1;
- m->default_machine_opts = "firmware=bios-256k.bin";
+ m->default_machine_opts = "firmware=bios-256k.bin,hpet=off";
m->default_display = "std";
m->default_nic = "e1000e";
- m->default_kernel_irqchip_split = false;
m->no_floppy = 1;
m->max_cpus = 4096;
- m->no_parallel = !module_object_class_by_name(TYPE_ISA_PARALLEL);
+ m->no_parallel = 1;
+ m->alias = "q35";
machine_class_allow_dynamic_sysbus_dev(m, TYPE_AMD_IOMMU_DEVICE);
machine_class_allow_dynamic_sysbus_dev(m, TYPE_INTEL_IOMMU_DEVICE);
machine_class_allow_dynamic_sysbus_dev(m, TYPE_RAMFB_DEVICE);
machine_class_allow_dynamic_sysbus_dev(m, TYPE_VMBUS_BRIDGE);
machine_class_allow_dynamic_sysbus_dev(m, TYPE_UEFI_VARS_X64);
+ compat_props_add(m->compat_props, pc_rhel_compat, pc_rhel_compat_len);
compat_props_add(m->compat_props,
pc_q35_compat_defaults, pc_q35_compat_defaults_len);
}
@@ -687,3 +687,108 @@ static void pc_q35_machine_2_6_options(MachineClass *m)
DEFINE_Q35_MACHINE(2, 6);
#endif /* Disabled for Red Hat Enterprise Linux */
+
+/* Red Hat Enterprise Linux machine types */
+
+static void pc_q35_rhel_machine_10_0_0_options(MachineClass *m)
+{
+ PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
+ pc_q35_machine_options(m);
+ m->desc = "RHEL-10.0.0 PC (Q35 + ICH9, 2009)";
+ pcmc->smbios_stream_product = "RHEL";
+ pcmc->smbios_stream_version = "10.0.0";
+
+ compat_props_add(m->compat_props, hw_compat_rhel_10_2,
+ hw_compat_rhel_10_2_len);
+ compat_props_add(m->compat_props, hw_compat_rhel_10_1,
+ hw_compat_rhel_10_1_len);
+ compat_props_add(m->compat_props, pc_rhel_10_2_compat,
+ pc_rhel_10_2_compat_len);
+ compat_props_add(m->compat_props, pc_rhel_10_1_compat,
+ pc_rhel_10_1_compat_len);
+}
+DEFINE_Q35_MACHINE_AS_LATEST(10, 0, 0);
+
+static void pc_q35_rhel_machine_9_6_0_options(MachineClass *m)
+{
+ PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
+ pc_q35_rhel_machine_10_0_0_options(m);
+ m->desc = "RHEL-9.6.0 PC (Q35 + ICH9, 2009)";
+ pcmc->smbios_stream_product = "RHEL";
+ pcmc->smbios_stream_version = "9.6.0";
+
+ /* NB: remember to move this line to the *latest* RHEL 9 machine */
+ compat_props_add(m->compat_props, hw_compat_rhel_9, hw_compat_rhel_9_len);
+}
+
+DEFINE_Q35_MACHINE(9, 6, 0);
+
+static void pc_q35_rhel_machine_9_4_0_options(MachineClass *m)
+{
+ PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
+ pc_q35_rhel_machine_9_6_0_options(m);
+
+ /* older RHEL machines continue to support 710 vcpus */
+ m->max_cpus = 710;
+ m->desc = "RHEL-9.4.0 PC (Q35 + ICH9, 2009)";
+ pcmc->smbios_stream_product = "RHEL";
+ pcmc->smbios_stream_version = "9.4.0";
+
+ /* From pc_q35_machine_9_0_options() */
+ pcmc->isa_bios_alias = false;
+ m->smbios_memory_device_size = 16 * GiB;
+
+ compat_props_add(m->compat_props, hw_compat_rhel_10_0,
+ hw_compat_rhel_10_0_len);
+ compat_props_add(m->compat_props, hw_compat_rhel_9_5,
+ hw_compat_rhel_9_5_len);
+ compat_props_add(m->compat_props, pc_rhel_10_0_compat,
+ pc_rhel_10_0_compat_len);
+}
+
+DEFINE_Q35_MACHINE(9, 4, 0);
+
+static void pc_q35_rhel_machine_9_2_0_options(MachineClass *m)
+{
+ PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
+ pc_q35_rhel_machine_9_4_0_options(m);
+ m->desc = "RHEL-9.2.0 PC (Q35 + ICH9, 2009)";
+ pcmc->smbios_stream_product = "RHEL";
+ pcmc->smbios_stream_version = "9.2.0";
+
+ /* From pc_q35_8_0_machine_options() */
+ pcmc->default_smbios_ep_type = SMBIOS_ENTRY_POINT_TYPE_32;
+ /* From pc_q35_8_1_machine_options() */
+ pcmc->broken_32bit_mem_addr_check = true;
+
+ compat_props_add(m->compat_props, hw_compat_rhel_9_4,
+ hw_compat_rhel_9_4_len);
+ compat_props_add(m->compat_props, hw_compat_rhel_9_3,
+ hw_compat_rhel_9_3_len);
+ compat_props_add(m->compat_props, pc_rhel_9_3_compat,
+ pc_rhel_9_3_compat_len);
+ compat_props_add(m->compat_props, hw_compat_rhel_9_2,
+ hw_compat_rhel_9_2_len);
+ compat_props_add(m->compat_props, pc_rhel_9_2_compat,
+ pc_rhel_9_2_compat_len);
+}
+
+DEFINE_Q35_MACHINE(9, 2, 0);
+
+static void pc_q35_rhel_machine_9_0_0_options(MachineClass *m)
+{
+ PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
+ pc_q35_rhel_machine_9_2_0_options(m);
+ m->desc = "RHEL-9.0.0 PC (Q35 + ICH9, 2009)";
+ pcmc->smbios_stream_product = "RHEL";
+ pcmc->smbios_stream_version = "9.0.0";
+ pcmc->enforce_amd_1tb_hole = false;
+ compat_props_add(m->compat_props, hw_compat_rhel_9_1,
+ hw_compat_rhel_9_1_len);
+ compat_props_add(m->compat_props, hw_compat_rhel_9_0,
+ hw_compat_rhel_9_0_len);
+ compat_props_add(m->compat_props, pc_rhel_9_0_compat,
+ pc_rhel_9_0_compat_len);
+}
+
+DEFINE_Q35_MACHINE(9, 0, 0);
diff --git a/include/hw/boards.h b/include/hw/boards.h
index aca254ea18..22c3abd51e 100644
--- a/include/hw/boards.h
+++ b/include/hw/boards.h
@@ -308,6 +308,8 @@ struct MachineClass {
strList *allowed_dynamic_sysbus_devices;
bool auto_enable_numa_with_memhp;
bool auto_enable_numa_with_memdev;
+ /* RHEL only */
+ bool async_pf_vmexit_disable;
bool ignore_boot_device_suffixes;
bool smbus_no_migration_support;
bool nvdimm_supported;
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index 3b4ea24c20..633df2fcf8 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -301,6 +301,27 @@ extern const size_t pc_compat_2_7_len;
extern GlobalProperty pc_compat_2_6[];
extern const size_t pc_compat_2_6_len;
+extern GlobalProperty pc_rhel_compat[];
+extern const size_t pc_rhel_compat_len;
+
+extern GlobalProperty pc_rhel_10_2_compat[];
+extern const size_t pc_rhel_10_2_compat_len;
+
+extern GlobalProperty pc_rhel_10_1_compat[];
+extern const size_t pc_rhel_10_1_compat_len;
+
+extern GlobalProperty pc_rhel_10_0_compat[];
+extern const size_t pc_rhel_10_0_compat_len;
+
+extern GlobalProperty pc_rhel_9_3_compat[];
+extern const size_t pc_rhel_9_3_compat_len;
+
+extern GlobalProperty pc_rhel_9_2_compat[];
+extern const size_t pc_rhel_9_2_compat_len;
+
+extern GlobalProperty pc_rhel_9_0_compat[];
+extern const size_t pc_rhel_9_0_compat_len;
+
#define DEFINE_PC_MACHINE(suffix, namestr, initfn, optsfn) \
static void pc_machine_##suffix##_class_init(ObjectClass *oc, \
const void *data) \
diff --git a/target/i386/kvm/kvm-cpu.c b/target/i386/kvm/kvm-cpu.c
index 89a7953659..74c0b036e3 100644
--- a/target/i386/kvm/kvm-cpu.c
+++ b/target/i386/kvm/kvm-cpu.c
@@ -175,6 +175,7 @@ static PropValue kvm_default_props[] = {
{ "acpi", "off" },
{ "monitor", "off" },
{ "svm", "off" },
+ { "kvm-pv-unhalt", "on" },
{ NULL, NULL },
};
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index 369626f8c8..0eb39d22d6 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -4389,6 +4389,7 @@ static int kvm_get_msrs(X86CPU *cpu)
struct kvm_msr_entry *msrs = cpu->kvm_msr_buf->entries;
int ret, i;
uint64_t mtrr_top_bits;
+ MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
kvm_msr_buf_reset(cpu);
@@ -4786,6 +4787,9 @@ static int kvm_get_msrs(X86CPU *cpu)
break;
case MSR_KVM_ASYNC_PF_EN:
env->async_pf_en_msr = msrs[i].data;
+ if (mc->async_pf_vmexit_disable) {
+ env->async_pf_en_msr &= ~(1ULL << 2);
+ }
break;
case MSR_KVM_ASYNC_PF_INT:
env->async_pf_int_msr = msrs[i].data;
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index 669d07c06b..b96aa06084 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -49,6 +49,7 @@ qtests_filter = \
(get_option('default_devices') and host_os != 'windows' ? ['test-filter-mirror'] : []) + \
(get_option('default_devices') and host_os != 'windows' ? ['test-filter-redirector'] : [])
+# RHEL: Removed intel-iommu-test as it's not working with 10.0 machine type
qtests_i386 = \
(slirp.found() ? ['pxe-test'] : []) + \
qtests_filter + \
@@ -94,7 +95,6 @@ qtests_i386 = \
(config_all_devices.has_key('CONFIG_SB16') ? ['fuzz-sb16-test'] : []) + \
(config_all_devices.has_key('CONFIG_SDHCI_PCI') ? ['fuzz-sdcard-test'] : []) + \
(config_all_devices.has_key('CONFIG_ESP_PCI') ? ['am53c974-test'] : []) + \
- (config_all_devices.has_key('CONFIG_VTD') ? ['intel-iommu-test'] : []) + \
(host_os != 'windows' and \
config_all_devices.has_key('CONFIG_ACPI_ERST') ? ['erst-test'] : []) + \
(config_all_devices.has_key('CONFIG_PCIE_PORT') and \
diff --git a/tests/qtest/pvpanic-test.c b/tests/qtest/pvpanic-test.c
index 5606baf47b..094c56b0cd 100644
--- a/tests/qtest/pvpanic-test.c
+++ b/tests/qtest/pvpanic-test.c
@@ -18,7 +18,7 @@ static void test_panic_nopause(void)
QDict *response, *data;
QTestState *qts;
- qts = qtest_init("-device pvpanic -action panic=none");
+ qts = qtest_init("-M q35 -device pvpanic -action panic=none");
val = qtest_inb(qts, 0x505);
g_assert_cmpuint(val, ==, PVPANIC_EVENTS);
@@ -41,7 +41,8 @@ static void test_panic(void)
QDict *response, *data;
QTestState *qts;
- qts = qtest_init("-device pvpanic -action panic=pause");
+ /* RHEL: Use q35 */
+ qts = qtest_init("-M q35 -device pvpanic -action panic=pause");
val = qtest_inb(qts, 0x505);
g_assert_cmpuint(val, ==, PVPANIC_EVENTS);

View File

@ -1,55 +0,0 @@
From 6eb636192635d165336534dbbe312145958df5a6 Mon Sep 17 00:00:00 2001
From: Andrea Bolognani <abologna@redhat.com>
Date: Tue, 10 Jun 2025 14:27:29 +0200
Subject: [PATCH] Disable virtio-net-pci romfile loading on riscv64
RH-Author: Andrea Bolognani <None>
RH-MergeRequest: 373: Various small fixes
RH-Jira: RHEL-96057
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [4/4] b490ef3c3ab6a47f90c67016f685e19a65d97100 (abologna/centos-stream-qemu-kvm)
Same motivation for disabling it as on aarch64.
Signed-off-by: Andrea Bolognani <abologna@redhat.com>
Patch-name: kvm-Disable-virtio-net-pci-romfile-loading-on-riscv64.patch
Patch-id: 51
Patch-present-in-specfile: True
---
hw/riscv/virt.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index ab5a9ec613..3b187d6c98 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -59,6 +59,18 @@
#include "hw/virtio/virtio-iommu.h"
#include "hw/uefi/var-service-api.h"
+/*
+ * virtio-net-pci variant romfiles are not needed because edk2 does
+ * fully support the pxe boot. Besides virtio romfiles are not shipped
+ * on rhel/riscv64.
+ */
+static GlobalProperty riscv_virt_compat[] = {
+ {"virtio-net-pci", "romfile", "" },
+ {"virtio-net-pci-transitional", "romfile", "" },
+ {"virtio-net-pci-non-transitional", "romfile", "" },
+};
+const size_t riscv_virt_compat_len = G_N_ELEMENTS(riscv_virt_compat);
+
/* KVM AIA only supports APLIC MSI. APLIC Wired is always emulated by QEMU. */
static bool virt_use_kvm_aia_aplic_imsic(RISCVVirtAIAType aia_type)
{
@@ -1978,6 +1990,9 @@ static void virt_machine_class_init(ObjectClass *oc, const void *data)
NULL, NULL);
object_class_property_set_description(oc, "iommu-sys",
"Enable IOMMU platform device");
+
+ compat_props_add(mc->compat_props, riscv_virt_compat,
+ riscv_virt_compat_len);
}
static const TypeInfo virt_machine_typeinfo = {

View File

@ -1,29 +0,0 @@
From 299a99e5714de89647c0fac650026682b365c040 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= <berrange@redhat.com>
Date: Wed, 3 Jul 2024 13:47:04 +0100
Subject: [PATCH] Revert "meson: temporarily disable -Wunused-function"
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This reverts commit c682111eaa73d9b985187b8be330338f50b78a7a.
No longer needed after introduction of downstream machines.
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
---
meson.build | 1 -
1 file changed, 1 deletion(-)
diff --git a/meson.build b/meson.build
index 23494666d9..ef2e5be6e2 100644
--- a/meson.build
+++ b/meson.build
@@ -757,7 +757,6 @@ warn_flags = [
'-Wno-string-plus-int',
'-Wno-tautological-type-limit-compare',
'-Wno-typedef-redefinition',
- '-Wno-unused-function',
]
if host_os != 'darwin'

View File

@ -1,346 +0,0 @@
From 0cc1623ce4c79af21ce7a3e8c3b67315ff9e3e7b Mon Sep 17 00:00:00 2001
From: Miroslav Rezanina <mrezanin@redhat.com>
Date: Wed, 2 Sep 2020 09:39:41 +0200
Subject: [PATCH] Enable make check
Fixing tests after device disabling and machine types changes and enabling
make check run during build.
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
---
tests/functional/meson.build | 2 +-
tests/functional/test_aarch64_tcg_plugins.py | 4 +--
tests/qemu-iotests/meson.build | 34 ++++++++++----------
tests/qemu-iotests/testenv.py | 3 ++
tests/qtest/bios-tables-test.c | 10 ++++++
tests/qtest/fuzz-e1000e-test.c | 2 +-
tests/qtest/fuzz-virtio-scsi-test.c | 2 +-
tests/qtest/intel-hda-test.c | 2 +-
tests/qtest/libqos/meson.build | 2 +-
tests/qtest/lpc-ich9-test.c | 2 +-
tests/qtest/machine-none-test.c | 2 +-
tests/qtest/meson.build | 1 -
tests/qtest/pvpanic-test.c | 2 +-
tests/qtest/riscv-csr-test.c | 4 +++
tests/qtest/virtio-net-failover.c | 1 +
15 files changed, 45 insertions(+), 28 deletions(-)
diff --git a/tests/functional/meson.build b/tests/functional/meson.build
index 311c6f1806..c7f9051c90 100644
--- a/tests/functional/meson.build
+++ b/tests/functional/meson.build
@@ -319,7 +319,7 @@ tests_sparc64_system_thorough = [
tests_x86_64_system_quick = [
'cpu_queries',
- 'mem_addr_space',
+# 'mem_addr_space',
'migration',
'pc_cpu_hotplug_props',
'virtio_version',
diff --git a/tests/functional/test_aarch64_tcg_plugins.py b/tests/functional/test_aarch64_tcg_plugins.py
index cb7e9298fb..9efa826b01 100755
--- a/tests/functional/test_aarch64_tcg_plugins.py
+++ b/tests/functional/test_aarch64_tcg_plugins.py
@@ -64,7 +64,7 @@ class PluginKernelNormal(PluginKernelBase):
def test_aarch64_virt_insn(self):
self.set_machine('virt')
- self.cpu='cortex-a53'
+ self.cpu='cortex-a57'
kernel_path = self.ASSET_KERNEL.fetch()
kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
'console=ttyAMA0')
@@ -90,7 +90,7 @@ def test_aarch64_virt_insn(self):
def test_aarch64_virt_insn_icount(self):
self.set_machine('virt')
- self.cpu='cortex-a53'
+ self.cpu='cortex-a57'
kernel_path = self.ASSET_KERNEL.fetch()
kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
'console=ttyAMA0')
diff --git a/tests/qemu-iotests/meson.build b/tests/qemu-iotests/meson.build
index fad340ad59..3c0d5241f6 100644
--- a/tests/qemu-iotests/meson.build
+++ b/tests/qemu-iotests/meson.build
@@ -51,21 +51,21 @@ foreach format, speed: qemu_iotests_formats
check: true,
)
- foreach item: rc.stdout().strip().split()
- args = [qemu_iotests_check_cmd,
- '-tap', '-' + format, item,
- '--source-dir', meson.current_source_dir(),
- '--build-dir', meson.current_build_dir()]
- # Some individual tests take as long as 45 seconds
- # Bump the timeout to 3 minutes for some headroom
- # on slow machines to minimize spurious failures
- test('io-' + format + '-' + item,
- python,
- args: args,
- depends: qemu_iotests_binaries,
- env: qemu_iotests_env,
- protocol: 'tap',
- timeout: 180,
- suite: suites)
- endforeach
+# foreach item: rc.stdout().strip().split()
+# args = [qemu_iotests_check_cmd,
+# '-tap', '-' + format, item,
+# '--source-dir', meson.current_source_dir(),
+# '--build-dir', meson.current_build_dir()]
+# # Some individual tests take as long as 45 seconds
+# # Bump the timeout to 3 minutes for some headroom
+# # on slow machines to minimize spurious failures
+# test('io-' + format + '-' + item,
+# python,
+# args: args,
+# depends: qemu_iotests_binaries,
+# env: qemu_iotests_env,
+# protocol: 'tap',
+# timeout: 180,
+# suite: suites)
+# endforeach
endforeach
diff --git a/tests/qemu-iotests/testenv.py b/tests/qemu-iotests/testenv.py
index 6326e46b7b..bc849ae9cf 100644
--- a/tests/qemu-iotests/testenv.py
+++ b/tests/qemu-iotests/testenv.py
@@ -252,6 +252,9 @@ def __init__(self, source_dir: str, build_dir: str,
if self.qemu_prog.endswith(f'qemu-system-{suffix}'):
self.qemu_options += f' -machine {machine}'
+ if self.qemu_prog.endswith('qemu-system-x86_64'):
+ self.qemu_options += ' -cpu Nehalem'
+
# QEMU_DEFAULT_MACHINE
self.qemu_default_machine = get_default_machine(self.qemu_prog)
diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c
index e7e6926c81..386196edc8 100644
--- a/tests/qtest/bios-tables-test.c
+++ b/tests/qtest/bios-tables-test.c
@@ -1755,6 +1755,7 @@ static void test_acpi_microvm_ioapic2_tcg(void)
free_test_data(&data);
}
+#if 0 /* Disabled for Red Hat Enterprise Linux */
static void test_acpi_riscv64_virt_tcg_numamem(void)
{
test_data data = {
@@ -1780,6 +1781,7 @@ static void test_acpi_riscv64_virt_tcg_numamem(void)
&data);
free_test_data(&data);
}
+#endif /* disabled for RHEL */
static void test_acpi_aarch64_virt_tcg_numamem(void)
{
@@ -1856,6 +1858,7 @@ static void test_acpi_aarch64_virt_tcg_acpi_spcr(void)
free_test_data(&data);
}
+#if 0 /* Disabled for Red Hat Enterprise Linux */
static void test_acpi_riscv64_virt_tcg_acpi_spcr(void)
{
test_data data = {
@@ -1874,6 +1877,7 @@ static void test_acpi_riscv64_virt_tcg_acpi_spcr(void)
"-machine spcr=off", &data);
free_test_data(&data);
}
+#endif
static void test_acpi_tcg_acpi_hmat(const char *machine, const char *arch)
{
@@ -2171,6 +2175,7 @@ static void test_acpi_microvm_acpi_erst(void)
}
#endif /* CONFIG_POSIX */
+#if 0 /* Disabled for Red Hat Enterprise Linux */
static void test_acpi_riscv64_virt_tcg(void)
{
test_data data = {
@@ -2192,6 +2197,7 @@ static void test_acpi_riscv64_virt_tcg(void)
test_acpi_one("-cpu rva22s64 ", &data);
free_test_data(&data);
}
+#endif /* disabled for RHEL */
static void test_acpi_aarch64_virt_tcg(void)
{
@@ -2526,6 +2532,7 @@ static void test_acpi_aarch64_virt_oem_fields(void)
g_free(args);
}
+#if 0 /* Disabled for Red Hat Enterprise Linux */
#define LOONGARCH64_INIT_TEST_DATA(data) \
test_data data = { \
.machine = "virt", \
@@ -2594,6 +2601,7 @@ static void test_acpi_loongarch64_virt_oem_fields(void)
free_test_data(&data);
g_free(args);
}
+#endif
int main(int argc, char *argv[])
{
@@ -2769,6 +2777,7 @@ int main(int argc, char *argv[])
qtest_add_func("acpi/virt/viot", test_acpi_aarch64_virt_viot);
}
}
+#if 0 /* Disabled for Red Hat Enterprise Linux */
} else if (strcmp(arch, "riscv64") == 0) {
if (has_tcg && qtest_has_device("virtio-blk-pci")) {
qtest_add_func("acpi/virt", test_acpi_riscv64_virt_tcg);
@@ -2788,6 +2797,7 @@ int main(int argc, char *argv[])
qtest_add_func("acpi/virt/oem-fields",
test_acpi_loongarch64_virt_oem_fields);
}
+#endif /* disabled for RHEL */
}
ret = g_test_run();
boot_sector_cleanup(disk);
diff --git a/tests/qtest/fuzz-e1000e-test.c b/tests/qtest/fuzz-e1000e-test.c
index 5052883fb6..8242190170 100644
--- a/tests/qtest/fuzz-e1000e-test.c
+++ b/tests/qtest/fuzz-e1000e-test.c
@@ -17,7 +17,7 @@ static void test_lp1879531_eth_get_rss_ex_dst_addr(void)
{
QTestState *s;
- s = qtest_init("-nographic -monitor none -serial none -M pc-q35-5.0");
+ s = qtest_init("-nographic -monitor none -serial none -M pc-q35-rhel9.4.0");
qtest_outl(s, 0xcf8, 0x80001010);
qtest_outl(s, 0xcfc, 0xe1020000);
diff --git a/tests/qtest/fuzz-virtio-scsi-test.c b/tests/qtest/fuzz-virtio-scsi-test.c
index e37b48b2cc..9f1965b530 100644
--- a/tests/qtest/fuzz-virtio-scsi-test.c
+++ b/tests/qtest/fuzz-virtio-scsi-test.c
@@ -19,7 +19,7 @@ static void test_mmio_oob_from_memory_region_cache(void)
{
QTestState *s;
- s = qtest_init("-M pc-q35-5.2 -m 512M "
+ s = qtest_init("-M pc-q35-rhel9.4.0 -m 512M "
"-device virtio-scsi,num_queues=8,addr=03.0 ");
qtest_outl(s, 0xcf8, 0x80001811);
diff --git a/tests/qtest/intel-hda-test.c b/tests/qtest/intel-hda-test.c
index 663bb6c485..2efc43e3f7 100644
--- a/tests/qtest/intel-hda-test.c
+++ b/tests/qtest/intel-hda-test.c
@@ -42,7 +42,7 @@ static void test_issue542_ich6(void)
{
QTestState *s;
- s = qtest_init("-nographic -nodefaults -M pc-q35-6.2 "
+ s = qtest_init("-nographic -nodefaults -M pc-q35-rhel9.0.0 "
AUDIODEV
"-device intel-hda,id=" HDA_ID CODEC_DEVICES);
diff --git a/tests/qtest/libqos/meson.build b/tests/qtest/libqos/meson.build
index 1ddaf7b095..1cb403e90d 100644
--- a/tests/qtest/libqos/meson.build
+++ b/tests/qtest/libqos/meson.build
@@ -43,7 +43,7 @@ libqos_srcs = files(
'virtio-rng.c',
'virtio-scsi.c',
'virtio-serial.c',
- 'virtio-iommu.c',
+# 'virtio-iommu.c',
'virtio-gpio.c',
'virtio-scmi.c',
'generic-pcihost.c',
diff --git a/tests/qtest/lpc-ich9-test.c b/tests/qtest/lpc-ich9-test.c
index 8ac95b89f7..0e118b76eb 100644
--- a/tests/qtest/lpc-ich9-test.c
+++ b/tests/qtest/lpc-ich9-test.c
@@ -15,7 +15,7 @@ static void test_lp1878642_pci_bus_get_irq_level_assert(void)
{
QTestState *s;
- s = qtest_init("-M pc-q35-5.0 "
+ s = qtest_init("-M pc-q35-rhel9.4.0 "
"-nographic -monitor none -serial none");
qtest_outl(s, 0xcf8, 0x8000f840); /* PMBASE */
diff --git a/tests/qtest/machine-none-test.c b/tests/qtest/machine-none-test.c
index b6a87d27ed..423ba12159 100644
--- a/tests/qtest/machine-none-test.c
+++ b/tests/qtest/machine-none-test.c
@@ -49,7 +49,7 @@ static struct arch2cpu cpus_map[] = {
{ "xtensa", "dc233c" },
{ "xtensaeb", "fsf" },
{ "hppa", "hppa" },
- { "riscv64", "rv64" },
+ { "riscv64", "max" },
{ "riscv32", "rv32" },
{ "rx", "rx62n" },
{ "loongarch64", "la464"},
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index b96aa06084..ef44ffaf78 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -91,7 +91,6 @@ qtests_i386 = \
(config_all_devices.has_key('CONFIG_LSI_SCSI_PCI') ? ['fuzz-lsi53c895a-test'] : []) + \
(config_all_devices.has_key('CONFIG_VIRTIO_SCSI') ? ['fuzz-virtio-scsi-test'] : []) + \
(config_all_devices.has_key('CONFIG_VIRTIO_BALLOON') ? ['virtio-balloon-test'] : []) + \
- (config_all_devices.has_key('CONFIG_Q35') ? ['q35-test'] : []) + \
(config_all_devices.has_key('CONFIG_SB16') ? ['fuzz-sb16-test'] : []) + \
(config_all_devices.has_key('CONFIG_SDHCI_PCI') ? ['fuzz-sdcard-test'] : []) + \
(config_all_devices.has_key('CONFIG_ESP_PCI') ? ['am53c974-test'] : []) + \
diff --git a/tests/qtest/pvpanic-test.c b/tests/qtest/pvpanic-test.c
index 094c56b0cd..338f94dcd9 100644
--- a/tests/qtest/pvpanic-test.c
+++ b/tests/qtest/pvpanic-test.c
@@ -65,7 +65,7 @@ static void test_pvshutdown(void)
QDict *response, *data;
QTestState *qts;
- qts = qtest_init("-device pvpanic");
+ qts = qtest_init("-M q35 -device pvpanic");
val = qtest_inb(qts, 0x505);
g_assert_cmpuint(val, ==, PVPANIC_EVENTS);
diff --git a/tests/qtest/riscv-csr-test.c b/tests/qtest/riscv-csr-test.c
index ff5c29e6c6..cc3b08a976 100644
--- a/tests/qtest/riscv-csr-test.c
+++ b/tests/qtest/riscv-csr-test.c
@@ -20,6 +20,7 @@
#define CSR_MVENDORID 0xf11
#define CSR_MISELECT 0x350
+#if 0 /* Disabled for Red Hat Enterprise Linux */
static void run_test_csr(void)
{
uint64_t res;
@@ -45,12 +46,15 @@ static void run_test_csr(void)
qtest_quit(qts);
}
+#endif /* disabled for RHEL */
int main(int argc, char **argv)
{
g_test_init(&argc, &argv, NULL);
+#if 0 /* Disabled for Red Hat Enterprise Linux */
qtest_add_func("/cpu/csr", run_test_csr);
+#endif /* disabled for RHEL */
return g_test_run();
}
diff --git a/tests/qtest/virtio-net-failover.c b/tests/qtest/virtio-net-failover.c
index 5baf81c3e6..aa87bf5698 100644
--- a/tests/qtest/virtio-net-failover.c
+++ b/tests/qtest/virtio-net-failover.c
@@ -27,6 +27,7 @@
#define PCI_SEL_BASE 0x0010
#define BASE_MACHINE "-M q35 -nodefaults " \
+ "-global ICH9-LPC.acpi-pci-hotplug-with-bridge-support=on " \
"-device pcie-root-port,id=root0,addr=0x1,bus=pcie.0,chassis=1 " \
"-device pcie-root-port,id=root1,addr=0x2,bus=pcie.0,chassis=2 "

View File

@ -1,49 +0,0 @@
From c17ca305893c976061a94fd5058ef5a53493e41a Mon Sep 17 00:00:00 2001
From: Miroslav Rezanina <mrezanin@redhat.com>
Date: Wed, 8 Jul 2020 08:35:50 +0200
Subject: [PATCH] Use qemu-kvm in documentation instead of qemu-system-<arch>
We change the name and location of qemu-kvm binaries. Update documentation
to reflect this change. Only architectures available in RHEL are updated.
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
---
docs/defs.rst.inc | 4 ++--
qemu-options.hx | 10 +++++-----
2 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/docs/defs.rst.inc b/docs/defs.rst.inc
index 52d6454b93..d74dbdeca9 100644
--- a/docs/defs.rst.inc
+++ b/docs/defs.rst.inc
@@ -9,7 +9,7 @@
but the manpages will end up misrendered with following normal text
incorrectly in boldface.
-.. |qemu_system| replace:: qemu-system-x86_64
-.. |qemu_system_x86| replace:: qemu-system-x86_64
+.. |qemu_system| replace:: qemu-kvm
+.. |qemu_system_x86| replace:: qemu-kvm
.. |I2C| replace:: I\ :sup:`2`\ C
.. |I2S| replace:: I\ :sup:`2`\ S
diff --git a/qemu-options.hx b/qemu-options.hx
index ab23f14d21..3837456a61 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -3858,11 +3858,11 @@ SRST
::
- qemu -m 512 -object memory-backend-file,id=mem,size=512M,mem-path=/hugetlbfs,share=on \
- -numa node,memdev=mem \
- -chardev socket,id=chr0,path=/path/to/socket \
- -netdev type=vhost-user,id=net0,chardev=chr0 \
- -device virtio-net-pci,netdev=net0
+ qemu-kvm -m 512 -object memory-backend-file,id=mem,size=512M,mem-path=/hugetlbfs,share=on \
+ -numa node,memdev=mem \
+ -chardev socket,id=chr0,path=/path/to/socket \
+ -netdev type=vhost-user,id=net0,chardev=chr0 \
+ -device virtio-net-pci,netdev=net0
``-netdev vhost-vdpa[,vhostdev=/path/to/dev][,vhostfd=h]``
Establish a vhost-vdpa netdev.

View File

@ -1,55 +0,0 @@
From d4a2e3344ea9e909a3262ac569fc0e5fab49562b Mon Sep 17 00:00:00 2001
From: Kevin Wolf <kwolf@redhat.com>
Date: Fri, 20 Aug 2021 18:25:12 +0200
Subject: [PATCH] qcow2: Deprecation warning when opening v2 images rw
qcow2 v3 has been around for a long time (since QEMU 1.1/RHEL 7), so
there is no real reason any more to use it. People still using it might
do so unintentionally. Warn about it and suggest upgrading during the
RHEL 9 timeframe so that the code can possibly be disabled in RHEL 10.
The warning is restricted to read-write mode and the system emulator.
The primary motivation for not having it in qemu-img is that 'qemu-img
amend' for upgrades would warn otherwise. It also avoids having to make
too many changes to the test suite.
bdrv_uses_whitelist() is used as a proxy for deciding whether we are
running in a tool or the system emulator. This is not entirely clean,
but it's what is available and the same function qcow2_do_open() already
uses it this way for another warning.
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
block/qcow2.c | 6 ++++++
tests/qemu-iotests/common.filter | 1 +
2 files changed, 7 insertions(+)
diff --git a/block/qcow2.c b/block/qcow2.c
index 4aa9f9e068..6df65aab93 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -1358,6 +1358,12 @@ qcow2_do_open(BlockDriverState *bs, QDict *options, int flags,
ret = -ENOTSUP;
goto fail;
}
+ if (header.version < 3 && !bdrv_is_read_only(bs) && bdrv_uses_whitelist()) {
+ warn_report_once("qcow2 v2 images are deprecated and may not be "
+ "supported in future versions. Please consider "
+ "upgrading the image with 'qemu-img amend "
+ "-o compat=v3'.");
+ }
s->qcow_version = header.version;
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
index 511a55b1e8..35c0fc0d20 100644
--- a/tests/qemu-iotests/common.filter
+++ b/tests/qemu-iotests/common.filter
@@ -83,6 +83,7 @@ _filter_qemu()
{
gsed -e "s#\\(^\\|(qemu) \\)$(basename $QEMU_PROG):#\1QEMU_PROG:#" \
-e 's#^QEMU [0-9]\+\.[0-9]\+\.[0-9]\+ monitor#QEMU X.Y.Z monitor#' \
+ -e "/qcow2 v2 images are deprecated/d" \
-e $'s#\r##' # QEMU monitor uses \r\n line endings
}

View File

@ -1,43 +0,0 @@
From fa1f21136ad5acb144c56dbfd0c4fb74d1a9b3e6 Mon Sep 17 00:00:00 2001
From: Kevin Wolf <kwolf@redhat.com>
Date: Tue, 29 Apr 2025 17:05:41 +0200
Subject: [PATCH] file-posix: Define DM_MPATH_PROBE_PATHS
RH-Author: Kevin Wolf <kwolf@redhat.com>
RH-MergeRequest: 370: file-posix: Fix multipath failover with SCSI passthrough
RH-Jira: RHEL-65852
RH-Acked-by: Hanna Czenczek <hreitz@redhat.com>
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
RH-Commit: [1/2] 6680f4a3f15a768b1ca51aafea452c3d0886f12e (kmwolf/centos-qemu-kvm)
While the kernel side isn't merged yet and we're still using old kernel
headers, just define DM_MPATH_PROBE_PATHS manually.
This is a downstream-only patch that can be removed after the next minor
release.
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Patch-name: kvm-file-posix-Define-DM_MPATH_PROBE_PATHS.patch
Patch-id: 41
Patch-present-in-specfile: True
---
block/file-posix.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/block/file-posix.c b/block/file-posix.c
index 8c738674ce..cb2e94d7db 100644
--- a/block/file-posix.c
+++ b/block/file-posix.c
@@ -156,6 +156,11 @@
*/
#define SG_IO_MAX_RETRIES 8
+/* TODO Remove this when the kernel side is merged */
+#if !defined(DM_MPATH_PROBE_PATHS) && defined(DM_GET_TARGET_VERSION)
+#define DM_MPATH_PROBE_PATHS _IO(DM_IOCTL, DM_GET_TARGET_VERSION_CMD + 1)
+#endif
+
typedef struct BDRVRawState {
int fd;
bool use_lock;

View File

@ -1,70 +0,0 @@
From dedb116d88615adedd6b651e5fb22083b86857b0 Mon Sep 17 00:00:00 2001
From: Laurent Vivier <lvivier@redhat.com>
Date: Thu, 7 Aug 2025 13:08:06 +0200
Subject: [PATCH] e1000e: Prevent crash from legacy interrupt firing after
MSI-X enable
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
RH-Author: Laurent Vivier <lvivier@redhat.com>
RH-MergeRequest: 403: e1000e: Prevent crash from legacy interrupt firing after MSI-X enable
RH-Jira: RHEL-112882
RH-Acked-by: Cindy Lu <lulu@redhat.com>
RH-Acked-by: Jason Wang <jasowang@redhat.com>
RH-Commit: [1/1] 8241a58b76307f27ad3d3b3b2106e00b153b7b53 (lvivier/qemu-kvm-centos)
JIRA: https://issues.redhat.com/browse/RHEL-112882
A race condition between guest driver actions and QEMU timers can lead
to an assertion failure when the guest switches the e1000e from legacy
interrupt mode to MSI-X. If a legacy interrupt delay timer (TIDV or
RDTR) is active, but the guest enables MSI-X before the timer fires,
the pending interrupt cause can trigger an assert in
e1000e_intmgr_collect_delayed_causes().
This patch removes the assertion and executes the code that clears the
pending legacy causes. This change is safe and introduces no unintended
behavioral side effects, as it only alters a state that previously led
to termination.
- when core->delayed_causes == 0 the function was already a no-op and
remains so.
- when core->delayed_causes != 0 the function would previously
crash due to the assertion failure. The patch now defines a safe
outcome by clearing the cause and returning. Since behavior after
the assertion never existed, this simply corrects the crash.
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1863
Suggested-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>
Signed-off-by: Laurent Vivier <lvivier@redhat.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Reviewed-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>
Message-ID: <20250807110806.409065-1-lvivier@redhat.com>
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
(cherry picked from commit 8e4649cac9bcddc050d2df07908075e9e69bccc7)
Patch-name: kvm-e1000e-Prevent-crash-from-legacy-interrupt-firing-af.patch
Patch-id: 22
Patch-present-in-specfile: True
---
hw/net/e1000e_core.c | 5 -----
1 file changed, 5 deletions(-)
diff --git a/hw/net/e1000e_core.c b/hw/net/e1000e_core.c
index 2413858790..06657bb3ac 100644
--- a/hw/net/e1000e_core.c
+++ b/hw/net/e1000e_core.c
@@ -341,11 +341,6 @@ e1000e_intmgr_collect_delayed_causes(E1000ECore *core)
{
uint32_t res;
- if (msix_enabled(core->owner)) {
- assert(core->delayed_causes == 0);
- return 0;
- }
-
res = core->delayed_causes;
core->delayed_causes = 0;

View File

@ -1,155 +0,0 @@
From f98acf4248abc79bf08a72ff018a496de9389eef Mon Sep 17 00:00:00 2001
From: Cornelia Huck <cohuck@redhat.com>
Date: Thu, 11 Sep 2025 17:41:59 +0200
Subject: [PATCH] arm/kvm: report registers we failed to set
RH-Author: Eric Auger <eric.auger@redhat.com>
RH-MergeRequest: 410: arm/kvm: report registers we failed to set
RH-Jira: RHEL-119368
RH-Acked-by: Cornelia Huck <cohuck@redhat.com>
RH-Acked-by: Sebastian Ott <sebott@redhat.com>
RH-Acked-by: Gavin Shan <gshan@redhat.com>
RH-Acked-by: Donald Dutile <None>
RH-Commit: [1/1] 82b4496284ff0a4dd2dd0eae7bb1cf114dded61e (eauger1/centos-qemu-kvm)
If we fail migration because of a mismatch of some registers between
source and destination, the error message is not very informative:
qemu-system-aarch64: error while loading state for instance 0x0 ofdevice 'cpu'
qemu-system-aarch64: Failed to put registers after init: Invalid argument
At least try to give the user a hint which registers had a problem,
even if they cannot really do anything about it right now.
Sample output:
Could not set register op0:3 op1:0 crn:0 crm:0 op2:0 to c00fac31 (is 413fd0c1)
We could be even more helpful once we support writable ID registers,
at which point the user might actually be able to configure something
that is migratable.
Suggested-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Sebastian Ott <sebott@redhat.com>
Signed-off-by: Cornelia Huck <cohuck@redhat.com>
Message-id: 20250911154159.158046-1-cohuck@redhat.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
(cherry picked from commit 19f6dcfe6b8b2a3523362812fc696ab83050d316)
Signed-off-by: Eric Auger <eric.auger@redhat.com>
Patch-name: kvm-arm-kvm-report-registers-we-failed-to-set.patch
Patch-id: 23
Patch-present-in-specfile: True
---
target/arm/kvm.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 86 insertions(+)
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index 6672344855..c1ec6654ca 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -900,6 +900,58 @@ bool write_kvmstate_to_list(ARMCPU *cpu)
return ok;
}
+/* pretty-print a KVM register */
+#define CP_REG_ARM64_SYSREG_OP(_reg, _op) \
+ ((uint8_t)((_reg & CP_REG_ARM64_SYSREG_ ## _op ## _MASK) >> \
+ CP_REG_ARM64_SYSREG_ ## _op ## _SHIFT))
+
+static gchar *kvm_print_sve_register_name(uint64_t regidx)
+{
+ uint16_t sve_reg = regidx & 0x000000000000ffff;
+
+ if (regidx == KVM_REG_ARM64_SVE_VLS) {
+ return g_strdup_printf("SVE VLS");
+ }
+ /* zreg, preg, ffr */
+ switch (sve_reg & 0xfc00) {
+ case 0:
+ return g_strdup_printf("SVE zreg n:%d slice:%d",
+ (sve_reg & 0x03e0) >> 5, sve_reg & 0x001f);
+ case 0x04:
+ return g_strdup_printf("SVE preg n:%d slice:%d",
+ (sve_reg & 0x01e0) >> 5, sve_reg & 0x001f);
+ case 0x06:
+ return g_strdup_printf("SVE ffr slice:%d", sve_reg & 0x001f);
+ default:
+ return g_strdup_printf("SVE ???");
+ }
+}
+
+static gchar *kvm_print_register_name(uint64_t regidx)
+{
+ switch ((regidx & KVM_REG_ARM_COPROC_MASK)) {
+ case KVM_REG_ARM_CORE:
+ return g_strdup_printf("core reg %"PRIx64, regidx);
+ case KVM_REG_ARM_DEMUX:
+ return g_strdup_printf("demuxed reg %"PRIx64, regidx);
+ case KVM_REG_ARM64_SYSREG:
+ return g_strdup_printf("op0:%d op1:%d crn:%d crm:%d op2:%d",
+ CP_REG_ARM64_SYSREG_OP(regidx, OP0),
+ CP_REG_ARM64_SYSREG_OP(regidx, OP1),
+ CP_REG_ARM64_SYSREG_OP(regidx, CRN),
+ CP_REG_ARM64_SYSREG_OP(regidx, CRM),
+ CP_REG_ARM64_SYSREG_OP(regidx, OP2));
+ case KVM_REG_ARM_FW:
+ return g_strdup_printf("fw reg %d", (int)(regidx & 0xffff));
+ case KVM_REG_ARM64_SVE:
+ return kvm_print_sve_register_name(regidx);
+ case KVM_REG_ARM_FW_FEAT_BMAP:
+ return g_strdup_printf("fw feat reg %d", (int)(regidx & 0xffff));
+ default:
+ return g_strdup_printf("%"PRIx64, regidx);
+ }
+}
+
bool write_list_to_kvmstate(ARMCPU *cpu, int level)
{
CPUState *cs = CPU(cpu);
@@ -927,11 +979,45 @@ bool write_list_to_kvmstate(ARMCPU *cpu, int level)
g_assert_not_reached();
}
if (ret) {
+ gchar *reg_str = kvm_print_register_name(regidx);
+
/* We might fail for "unknown register" and also for
* "you tried to set a register which is constant with
* a different value from what it actually contains".
*/
ok = false;
+ switch (ret) {
+ case -ENOENT:
+ error_report("Could not set register %s: unknown to KVM",
+ reg_str);
+ break;
+ case -EINVAL:
+ if ((regidx & KVM_REG_SIZE_MASK) == KVM_REG_SIZE_U32) {
+ if (!kvm_get_one_reg(cs, regidx, &v32)) {
+ error_report("Could not set register %s to %x (is %x)",
+ reg_str, (uint32_t)cpu->cpreg_values[i],
+ v32);
+ } else {
+ error_report("Could not set register %s to %x",
+ reg_str, (uint32_t)cpu->cpreg_values[i]);
+ }
+ } else /* U64 */ {
+ uint64_t v64;
+
+ if (!kvm_get_one_reg(cs, regidx, &v64)) {
+ error_report("Could not set register %s to %"PRIx64" (is %"PRIx64")",
+ reg_str, cpu->cpreg_values[i], v64);
+ } else {
+ error_report("Could not set register %s to %"PRIx64,
+ reg_str, cpu->cpreg_values[i]);
+ }
+ }
+ break;
+ default:
+ error_report("Could not set register %s: %s",
+ reg_str, strerror(-ret));
+ }
+ g_free(reg_str);
}
}
return ok;

View File

@ -1,74 +0,0 @@
From 103e764a9c557b38b03f23928bb9f20aeaec9b52 Mon Sep 17 00:00:00 2001
From: Stefan Hajnoczi <stefanha@redhat.com>
Date: Wed, 24 Sep 2025 11:51:53 -0400
Subject: [PATCH] pcie_sriov: make pcie_sriov_pf_exit() safe on non-SR-IOV
devices
RH-Author: Stefan Hajnoczi <stefanha@redhat.com>
RH-MergeRequest: 408: pcie_sriov: make pcie_sriov_pf_exit() safe on non-SR-IOV devices
RH-Jira: RHEL-116443
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [1/1] a4fea6ad073c9fa5fdc7f20b3dfeab4e4acef73f (stefanha/centos-stream-qemu-kvm)
Commit 3f9cfaa92c96 ("virtio-pci: Implement SR-IOV PF") added an
unconditional call from virtio_pci_exit() to pcie_sriov_pf_exit().
pcie_sriov_pf_exit() reads from the SR-IOV Capability in Configuration
Space:
uint8_t *cfg = dev->config + dev->exp.sriov_cap;
...
unparent_vfs(dev, pci_get_word(cfg + PCI_SRIOV_TOTAL_VF));
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This results in undefined behavior when dev->exp.sriov_cap is 0 because
this is not an SR-IOV device. For example, unparent_vfs() segfaults when
total_vfs happens to be non-zero.
Fix this by returning early from pcie_sriov_pf_exit() when
dev->exp.sriov_cap is 0 because this is not an SR-IOV device.
Cc: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>
Cc: Michael S. Tsirkin <mst@redhat.com>
Reported-by: Qing Wang <qinwang@redhat.com>
Buglink: https://issues.redhat.com/browse/RHEL-116443
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>
Fixes: cab1398a60eb ("pcie_sriov: Reuse SR-IOV VF device instances")
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <20250924155153.579495-1-stefanha@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
(cherry picked from commit bab681f752048c3bc22d561b1d314c7ec16419c9)
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Patch-name: kvm-pcie_sriov-make-pcie_sriov_pf_exit-safe-on-non-SR-IO.patch
Patch-id: 24
Patch-present-in-specfile: True
---
hw/pci/pcie_sriov.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/hw/pci/pcie_sriov.c b/hw/pci/pcie_sriov.c
index 8a4bf0d6f7..cf1b5b5c05 100644
--- a/hw/pci/pcie_sriov.c
+++ b/hw/pci/pcie_sriov.c
@@ -195,7 +195,9 @@ bool pcie_sriov_pf_init(PCIDevice *dev, uint16_t offset,
void pcie_sriov_pf_exit(PCIDevice *dev)
{
- uint8_t *cfg = dev->config + dev->exp.sriov_cap;
+ if (dev->exp.sriov_cap == 0) {
+ return;
+ }
if (dev->exp.sriov_pf.vf_user_created) {
uint16_t ven_id = pci_get_word(dev->config + PCI_VENDOR_ID);
@@ -211,6 +213,8 @@ void pcie_sriov_pf_exit(PCIDevice *dev)
pci_config_set_device_id(dev->exp.sriov_pf.vf[i]->config, vf_dev_id);
}
} else {
+ uint8_t *cfg = dev->config + dev->exp.sriov_cap;
+
unparent_vfs(dev, pci_get_word(cfg + PCI_SRIOV_TOTAL_VF));
}
}

View File

@ -1,135 +0,0 @@
From e1328dd999ee518164a5620b23b9d4fb698a0daa Mon Sep 17 00:00:00 2001
From: Paolo Bonzini <pbonzini@redhat.com>
Date: Thu, 9 Oct 2025 16:49:59 +0200
Subject: [PATCH] target/i386: add compatibility property for arch_capabilities
RH-Author: Paolo Bonzini <pbonzini@redhat.com>
RH-MergeRequest: 411: fix x86-64 migration regression in QEMU 10.1
RH-Jira: RHEL-120253
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [1/2] 6bfa7c38398623ac7c3392c0ad17312e6f641f4d (bonzini/qemu-kvm-centos)
JIRA: https://issues.redhat.com/browse/RHEL-120253
Prior to v10.1, if requested by user, arch-capabilities is always on
despite the fact that CPUID advertises it to be off/unvailable.
This causes a migration issue for VMs that are run on a machine
without arch-capabilities and expect this feature to be present
on the destination host with QEMU 10.1.
Add a compatibility property to restore the legacy behavior for all
machines with version prior to 10.1.
To preserve the functionality (added by 10.1) of turning off
ARCH_CAPABILITIES where Windows does not like it, use directly
the guest CPU vendor: x86_cpu_get_supported_feature_word is not
KVM-specific and therefore should not necessarily use the host
CPUID.
Co-authored-by: Hector Cao <hector.cao@canonical.com>
Signed-off-by: Hector Cao <hector.cao@canonical.com>
Fixes: d3a24134e37 ("target/i386: do not expose ARCH_CAPABILITIES on AMD CPU", 2025-07-17)
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit e9efa4a77168ac2816bf9471f878252ce6224710)
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Patch-name: kvm-target-i386-add-compatibility-property-for-arch_capa.patch
Patch-id: 25
Patch-present-in-specfile: True
---
hw/i386/pc.c | 2 ++
target/i386/cpu.c | 17 +++++++++++++++++
target/i386/cpu.h | 6 ++++++
target/i386/kvm/kvm.c | 6 +-----
4 files changed, 26 insertions(+), 5 deletions(-)
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 439abe8f46..625a89d097 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -84,6 +84,7 @@
GlobalProperty pc_compat_10_0[] = {
{ TYPE_X86_CPU, "x-consistent-cache", "false" },
{ TYPE_X86_CPU, "x-vendor-cpuid-only-v2", "false" },
+ { TYPE_X86_CPU, "x-arch-cap-always-on", "true" },
};
const size_t pc_compat_10_0_len = G_N_ELEMENTS(pc_compat_10_0);
@@ -299,6 +300,7 @@ GlobalProperty pc_rhel_10_2_compat[] = {
/* pc_rhel_10_2_compat from pc_compat_10_0 */
{ TYPE_X86_CPU, "x-consistent-cache", "false" },
{ TYPE_X86_CPU, "x-vendor-cpuid-only-v2", "false" },
+ { TYPE_X86_CPU, "x-arch-cap-always-on", "true" },
};
const size_t pc_rhel_10_2_compat_len = G_N_ELEMENTS(pc_compat_10_0);
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 9c756a05f2..de288dc5ac 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -7559,6 +7559,20 @@ uint64_t x86_cpu_get_supported_feature_word(X86CPU *cpu, FeatureWord w)
#endif
break;
+ case FEAT_7_0_EDX:
+ /*
+ * Windows does not like ARCH_CAPABILITIES on AMD machines at all.
+ * Do not show the fake ARCH_CAPABILITIES MSR that KVM sets up,
+ * except if needed for migration.
+ *
+ * When arch_cap_always_on is removed, this tweak can move to
+ * kvm_arch_get_supported_cpuid.
+ */
+ if (cpu && IS_AMD_CPU(&cpu->env) && !cpu->arch_cap_always_on) {
+ unavail = CPUID_7_0_EDX_ARCH_CAPABILITIES;
+ }
+ break;
+
default:
break;
}
@@ -10024,6 +10038,9 @@ static const Property x86_cpu_properties[] = {
true),
DEFINE_PROP_BOOL("x-l1-cache-per-thread", X86CPU, l1_cache_per_core, true),
DEFINE_PROP_BOOL("x-force-cpuid-0x1f", X86CPU, force_cpuid_0x1f, false),
+
+ DEFINE_PROP_BOOL("x-arch-cap-always-on", X86CPU,
+ arch_cap_always_on, false),
};
#ifndef CONFIG_USER_ONLY
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index f977fc49a7..b966bc997c 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -2314,6 +2314,12 @@ struct ArchCPU {
/* Forcefully disable KVM PV features not exposed in guest CPUIDs */
bool kvm_pv_enforce_cpuid;
+ /*
+ * Expose arch-capabilities unconditionally even on AMD models, for backwards
+ * compatibility with QEMU <10.1.
+ */
+ bool arch_cap_always_on;
+
/* Number of physical address bits supported */
uint32_t phys_bits;
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index 0eb39d22d6..baa2f80beb 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -503,12 +503,8 @@ uint32_t kvm_arch_get_supported_cpuid(KVMState *s, uint32_t function,
* Linux v4.17-v4.20 incorrectly return ARCH_CAPABILITIES on SVM hosts.
* We can detect the bug by checking if MSR_IA32_ARCH_CAPABILITIES is
* returned by KVM_GET_MSR_INDEX_LIST.
- *
- * But also, because Windows does not like ARCH_CAPABILITIES on AMD
- * mcahines at all, do not show the fake ARCH_CAPABILITIES MSR that
- * KVM sets up.
*/
- if (!has_msr_arch_capabs || !(edx & CPUID_7_0_EDX_ARCH_CAPABILITIES)) {
+ if (!has_msr_arch_capabs) {
ret &= ~CPUID_7_0_EDX_ARCH_CAPABILITIES;
}
} else if (function == 7 && index == 1 && reg == R_EAX) {

View File

@ -1,116 +0,0 @@
From 0bf7082e44f311902726b90b0b38dd2602dcc118 Mon Sep 17 00:00:00 2001
From: Hector Cao <hector.cao@canonical.com>
Date: Tue, 23 Sep 2025 12:16:41 +0200
Subject: [PATCH] target/i386: add compatibility property for pdcm feature
RH-Author: Paolo Bonzini <pbonzini@redhat.com>
RH-MergeRequest: 411: fix x86-64 migration regression in QEMU 10.1
RH-Jira: RHEL-120253
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [2/2] 9d76b45215d7ae2bc5ea2e61fe01780059d6d44c (bonzini/qemu-kvm-centos)
JIRA: https://issues.redhat.com/browse/RHEL-120253
The pdcm feature is supposed to be disabled when PMU is not
available. Up until v10.1, pdcm feature is enabled even when PMU
is off. This behavior has been fixed but this change breaks the
migration of VMs that are run with QEMU < 10.0 and expect the pdcm
feature to be enabled on the destination host.
This commit restores the legacy behavior for machines with version
prior to 10.1 to allow the migration from older QEMU to QEMU 10.1.
Signed-off-by: Hector Cao <hector.cao@canonical.com>
Link: https://lore.kernel.org/r/20250910115733.21149-3-hector.cao@canonical.com
Fixes: e68ec298090 ("i386/cpu: Move adjustment of CPUID_EXT_PDCM before feature_dependencies[] check", 2025-06-20)
[Move property from migration object to CPU. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit 6529f31e0dccadb532c80b36e3efe7aef83f9cad)
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Patch-name: kvm-target-i386-add-compatibility-property-for-pdcm-feat.patch
Patch-id: 26
Patch-present-in-specfile: True
---
hw/i386/pc.c | 2 ++
target/i386/cpu.c | 15 ++++++++++++---
target/i386/cpu.h | 6 ++++++
3 files changed, 20 insertions(+), 3 deletions(-)
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 625a89d097..446d4a7c93 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -85,6 +85,7 @@ GlobalProperty pc_compat_10_0[] = {
{ TYPE_X86_CPU, "x-consistent-cache", "false" },
{ TYPE_X86_CPU, "x-vendor-cpuid-only-v2", "false" },
{ TYPE_X86_CPU, "x-arch-cap-always-on", "true" },
+ { TYPE_X86_CPU, "x-pdcm-on-even-without-pmu", "true" },
};
const size_t pc_compat_10_0_len = G_N_ELEMENTS(pc_compat_10_0);
@@ -301,6 +302,7 @@ GlobalProperty pc_rhel_10_2_compat[] = {
{ TYPE_X86_CPU, "x-consistent-cache", "false" },
{ TYPE_X86_CPU, "x-vendor-cpuid-only-v2", "false" },
{ TYPE_X86_CPU, "x-arch-cap-always-on", "true" },
+ { TYPE_X86_CPU, "x-pdcm-on-even-without-pmu", "true" },
};
const size_t pc_rhel_10_2_compat_len = G_N_ELEMENTS(pc_compat_10_0);
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index de288dc5ac..dfcdfd3da6 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -7928,6 +7928,11 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
/* Fixup overflow: max value for bits 23-16 is 255. */
*ebx |= MIN(num, 255) << 16;
}
+ if (cpu->pdcm_on_even_without_pmu) {
+ if (!cpu->enable_pmu) {
+ *ecx &= ~CPUID_EXT_PDCM;
+ }
+ }
break;
case 2: { /* cache info: needed for Pentium Pro compatibility */
const CPUCaches *caches;
@@ -8978,9 +8983,11 @@ void x86_cpu_expand_features(X86CPU *cpu, Error **errp)
}
}
- /* PDCM is fixed1 bit for TDX */
- if (!cpu->enable_pmu && !is_tdx_vm()) {
- env->features[FEAT_1_ECX] &= ~CPUID_EXT_PDCM;
+ if (!cpu->pdcm_on_even_without_pmu) {
+ /* PDCM is fixed1 bit for TDX */
+ if (!cpu->enable_pmu && !is_tdx_vm()) {
+ env->features[FEAT_1_ECX] &= ~CPUID_EXT_PDCM;
+ }
}
for (i = 0; i < ARRAY_SIZE(feature_dependencies); i++) {
@@ -10041,6 +10048,8 @@ static const Property x86_cpu_properties[] = {
DEFINE_PROP_BOOL("x-arch-cap-always-on", X86CPU,
arch_cap_always_on, false),
+ DEFINE_PROP_BOOL("x-pdcm-on-even-without-pmu", X86CPU,
+ pdcm_on_even_without_pmu, false),
};
#ifndef CONFIG_USER_ONLY
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index b966bc997c..2187e61654 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -2320,6 +2320,12 @@ struct ArchCPU {
*/
bool arch_cap_always_on;
+ /*
+ * Backwards compatibility with QEMU <10.1. The PDCM feature is now disabled when
+ * PMU is not available, but prior to 10.1 it was enabled even if PMU is off.
+ */
+ bool pdcm_on_even_without_pmu;
+
/* Number of physical address bits supported */
uint32_t phys_bits;

View File

@ -1,87 +0,0 @@
From f8640da2e54f79ca5966e8390c0bd3b5a40c2581 Mon Sep 17 00:00:00 2001
From: Shalini Chellathurai Saroja <shalini@linux.ibm.com>
Date: Thu, 16 Oct 2025 14:17:07 +0200
Subject: [PATCH] qapi/machine-s390x: add QAPI event SCLP_CPI_INFO_AVAILABLE
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
RH-Author: Thomas Huth <thuth@redhat.com>
RH-MergeRequest: 412: Add -rhel9.8.0 and -rhel10.2.0 s390x machine types and enable the CPI feature
RH-Jira: RHEL-104009 RHEL-105823 RHEL-73008
RH-Acked-by: Cédric Le Goater <clg@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [1/3] 24789cc7501d22168819bf459f7d880deba8b403 (thuth/qemu-kvm-cs)
JIRA: https://issues.redhat.com/browse/RHEL-73008
Add QAPI event SCLP_CPI_INFO_AVAILABLE to notify the availability
of Control-Program Identification data in QOM.
Signed-off-by: Shalini Chellathurai Saroja <shalini@linux.ibm.com>
Suggested-by: Thomas Huth <thuth@redhat.com>
Reviewed-by: Hendrik Brueckner <brueckner@linux.ibm.com>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Message-ID: <20251016121708.334133-1-shalini@linux.ibm.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
(cherry picked from commit 0ce63280dc6fe9fce1d89922f2d17dcae77827e6)
Patch-name: kvm-qapi-machine-s390x-add-QAPI-event-SCLP_CPI_INFO_AVAI.patch
Patch-id: 27
Patch-present-in-specfile: True
---
hw/s390x/sclpcpi.c | 4 ++++
qapi/machine-s390x.json | 21 +++++++++++++++++++++
2 files changed, 25 insertions(+)
diff --git a/hw/s390x/sclpcpi.c b/hw/s390x/sclpcpi.c
index 7aa039d510..68fc1b809b 100644
--- a/hw/s390x/sclpcpi.c
+++ b/hw/s390x/sclpcpi.c
@@ -54,6 +54,7 @@
#include "hw/s390x/event-facility.h"
#include "hw/s390x/ebcdic.h"
#include "qapi/qapi-visit-machine.h"
+#include "qapi/qapi-events-machine-s390x.h"
#include "migration/vmstate.h"
typedef struct Data {
@@ -106,6 +107,9 @@ static int write_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr)
e->timestamp = qemu_clock_get_ns(QEMU_CLOCK_HOST);
cpim->ebh.flags = SCLP_EVENT_BUFFER_ACCEPTED;
+
+ qapi_event_send_sclp_cpi_info_available();
+
return SCLP_RC_NORMAL_COMPLETION;
}
diff --git a/qapi/machine-s390x.json b/qapi/machine-s390x.json
index 966dbd61d2..8412668b67 100644
--- a/qapi/machine-s390x.json
+++ b/qapi/machine-s390x.json
@@ -119,3 +119,24 @@
{ 'command': 'query-s390x-cpu-polarization', 'returns': 'CpuPolarizationInfo',
'features': [ 'unstable' ]
}
+
+##
+# @SCLP_CPI_INFO_AVAILABLE:
+#
+# Emitted when the Control-Program Identification data is available
+# in the QOM tree.
+#
+# Features:
+#
+# @unstable: This event is experimental.
+#
+# Since: 10.2
+#
+# .. qmp-example::
+#
+# <- { "event": "SCLP_CPI_INFO_AVAILABLE",
+# "timestamp": { "seconds": 1401385907, "microseconds": 422329 } }
+##
+{ 'event': 'SCLP_CPI_INFO_AVAILABLE',
+ 'features': [ 'unstable' ]
+}

View File

@ -1,77 +0,0 @@
From fdb8dcb26a3840f4ddf03c37389d6ffc80c4b5ba Mon Sep 17 00:00:00 2001
From: Shalini Chellathurai Saroja <shalini@linux.ibm.com>
Date: Thu, 16 Oct 2025 14:17:08 +0200
Subject: [PATCH] tests/functional: add tests for SCLP event CPI
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
RH-Author: Thomas Huth <thuth@redhat.com>
RH-MergeRequest: 412: Add -rhel9.8.0 and -rhel10.2.0 s390x machine types and enable the CPI feature
RH-Jira: RHEL-104009 RHEL-105823 RHEL-73008
RH-Acked-by: Cédric Le Goater <clg@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [2/3] 7ff3e50bf038921d4514db88ef147ba92f960780 (thuth/qemu-kvm-cs)
JIRA: https://issues.redhat.com/browse/RHEL-73008
Add tests for SCLP event type Control-Program Identification.
Signed-off-by: Shalini Chellathurai Saroja <shalini@linux.ibm.com>
Suggested-by: Thomas Huth <thuth@redhat.com>
Reviewed-by: Hendrik Brueckner <brueckner@linux.ibm.com>
Reviewed-by Thomas Huth <thuth@redhat.com>
Message-ID: <20251016121708.334133-2-shalini@linux.ibm.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
(cherry picked from commit bc436b739c3c8683ef5e8c22391952dcaa95242e)
Patch-name: kvm-tests-functional-add-tests-for-SCLP-event-CPI.patch
Patch-id: 28
Patch-present-in-specfile: True
---
tests/functional/test_s390x_ccw_virtio.py | 26 +++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/tests/functional/test_s390x_ccw_virtio.py b/tests/functional/test_s390x_ccw_virtio.py
index 453711aa0f..0455337856 100755
--- a/tests/functional/test_s390x_ccw_virtio.py
+++ b/tests/functional/test_s390x_ccw_virtio.py
@@ -15,6 +15,7 @@
import tempfile
from qemu_test import QemuSystemTest, Asset
+from qemu_test import exec_command
from qemu_test import exec_command_and_wait_for_pattern
from qemu_test import wait_for_console_pattern
@@ -270,5 +271,30 @@ def test_s390x_fedora(self):
'while ! (dmesg -c | grep Start.virtcrypto_remove) ; do'
' sleep 1 ; done', 'Start virtcrypto_remove.')
+ # Test SCLP event Control-Program Identification (CPI)
+ cpi = '/sys/firmware/cpi/'
+ sclpcpi = '/machine/sclp/s390-sclp-event-facility/sclpcpi'
+ self.log.info("Test SCLP event CPI")
+ exec_command(self, 'echo TESTVM > ' + cpi + 'system_name')
+ exec_command(self, 'echo LINUX > ' + cpi + 'system_type')
+ exec_command(self, 'echo TESTPLEX > ' + cpi + 'sysplex_name')
+ exec_command(self, 'echo 0x001a000000060b00 > ' + cpi + 'system_level')
+ exec_command_and_wait_for_pattern(self,
+ 'echo 1 > ' + cpi + 'set', ':/#')
+ try:
+ event = self.vm.event_wait('SCLP_CPI_INFO_AVAILABLE')
+ except TimeoutError:
+ self.fail('Timed out waiting for the SCLP_CPI_INFO_AVAILABLE event')
+ ts = self.vm.cmd('qom-get', path=sclpcpi, property='timestamp')
+ self.assertNotEqual(ts, 0)
+ name = self.vm.cmd('qom-get', path=sclpcpi, property='system_name')
+ self.assertEqual(name.strip(), 'TESTVM')
+ typ = self.vm.cmd('qom-get', path=sclpcpi, property='system_type')
+ self.assertEqual(typ.strip(), 'LINUX')
+ sysplex = self.vm.cmd('qom-get', path=sclpcpi, property='sysplex_name')
+ self.assertEqual(sysplex.strip(), 'TESTPLEX')
+ level = self.vm.cmd('qom-get', path=sclpcpi, property='system_level')
+ self.assertEqual(level, 0x001a000000060b00)
+
if __name__ == '__main__':
QemuSystemTest.main()

View File

@ -1,100 +0,0 @@
From 79a55b8fb1b4dace565ceedee8f4b5dbcc5e1210 Mon Sep 17 00:00:00 2001
From: Thomas Huth <thuth@redhat.com>
Date: Thu, 18 Sep 2025 17:41:25 +0200
Subject: [PATCH] redhat: Add new -rhel9.8.0 and -rhel10.2.0 machine types on
s390x
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
RH-Author: Thomas Huth <thuth@redhat.com>
RH-MergeRequest: 412: Add -rhel9.8.0 and -rhel10.2.0 s390x machine types and enable the CPI feature
RH-Jira: RHEL-104009 RHEL-105823 RHEL-73008
RH-Acked-by: Cédric Le Goater <clg@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [3/3] e9ad89069cb4b9badb1b5f57d78a043c64411b65 (thuth/qemu-kvm-cs)
Upstream Status: RHEL only
JIRA: https://issues.redhat.com/browse/RHEL-105823
JIRA: https://issues.redhat.com/browse/RHEL-104009
Add new -rhel9.8.0 and -rhel10.2.0 machine types that enable the
CPI feature and have the "relaxed-translation" for PCI passthrough
devices enabled by default.
Signed-off-by: Thomas Huth <thuth@redhat.com>
Patch-name: kvm-redhat-Add-new-rhel9.8.0-and-rhel10.2.0-machine-type.patch
Patch-id: 29
Patch-present-in-specfile: True
---
hw/s390x/s390-virtio-ccw.c | 34 +++++++++++++++++++++++++++++++---
1 file changed, 31 insertions(+), 3 deletions(-)
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index 9be423858d..4937a0c3b8 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -1172,8 +1172,18 @@ DEFINE_CCW_MACHINE(4, 2);
#endif /* disabled for RHEL */
+static void ccw_rhel_machine_10_2_0_instance_options(MachineState *machine)
+{
+}
+
+static void ccw_rhel_machine_10_2_0_class_options(MachineClass *mc)
+{
+}
+DEFINE_CCW_MACHINE_AS_LATEST(10, 2, 0);
+
static void ccw_rhel_machine_10_0_0_instance_options(MachineState *machine)
{
+ ccw_rhel_machine_10_2_0_instance_options(machine);
}
static void ccw_rhel_machine_10_0_0_class_options(MachineClass *mc)
@@ -1183,12 +1193,28 @@ static void ccw_rhel_machine_10_0_0_class_options(MachineClass *mc)
{ TYPE_S390_PCI_DEVICE, "relaxed-translation", "off", },
};
+ ccw_rhel_machine_10_2_0_class_options(mc);
+
compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
compat_props_add(mc->compat_props, hw_compat_rhel_10_2, hw_compat_rhel_10_2_len);
compat_props_add(mc->compat_props, hw_compat_rhel_10_1, hw_compat_rhel_10_1_len);
s390mc->use_cpi = false;
}
-DEFINE_CCW_MACHINE_AS_LATEST(10, 0, 0);
+DEFINE_CCW_MACHINE(10, 0, 0);
+
+static void ccw_rhel_machine_9_8_0_instance_options(MachineState *machine)
+{
+ ccw_rhel_machine_10_2_0_instance_options(machine);
+}
+
+static void ccw_rhel_machine_9_8_0_class_options(MachineClass *mc)
+{
+ ccw_rhel_machine_10_2_0_class_options(mc);
+
+ /* NB: remember to copy this line to the *latest* RHEL 9 machine */
+ compat_props_add(mc->compat_props, hw_compat_rhel_9, hw_compat_rhel_9_len);
+}
+DEFINE_CCW_MACHINE(9, 8, 0);
static void ccw_rhel_machine_9_6_0_instance_options(MachineState *machine)
{
@@ -1197,9 +1223,11 @@ static void ccw_rhel_machine_9_6_0_instance_options(MachineState *machine)
static void ccw_rhel_machine_9_6_0_class_options(MachineClass *mc)
{
+ /*
+ * NB: -rhel9.6 was on a par with -rhel10.0, so we derive from that
+ * instead of deriving from the 9.8 machine type
+ */
ccw_rhel_machine_10_0_0_class_options(mc);
-
- /* NB: remember to move this line to the *latest* RHEL 9 machine */
compat_props_add(mc->compat_props, hw_compat_rhel_9, hw_compat_rhel_9_len);
}
DEFINE_CCW_MACHINE(9, 6, 0);

View File

@ -1,254 +0,0 @@
From 60e7ac0c41c27dfefeb68b53ce76ebd7f1a1e1be Mon Sep 17 00:00:00 2001
From: John Levon <john.levon@nutanix.com>
Date: Tue, 14 Oct 2025 17:12:26 +0200
Subject: [PATCH] vfio: rename field to "num_initial_regions"
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
RH-Author: Cédric Le Goater <clg@redhat.com>
RH-MergeRequest: 414: Fixes for vfio region cache
RH-Jira: RHEL-118810
RH-Acked-by: Eric Auger <eric.auger@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [1/2] 62524d77e79b6a57c4e61762cd61449280e4f2cd (clegoate/qemu-kvm-centos)
We set VFIODevice::num_regions at initialization time, and do not
otherwise refresh it. As it is valid in theory for a VFIO device to
later increase the number of supported regions, rename the field to
"num_initial_regions" to better reflect its semantics.
Signed-off-by: John Levon <john.levon@nutanix.com>
Reviewed-by: Cédric Le Goater <clg@redhat.com>
Reviewed-by: Alex Williamson <alex@shazbot.org>
Link: https://lore.kernel.org/qemu-devel/20251014151227.2298892-2-john.levon@nutanix.com
Signed-off-by: Cédric Le Goater <clg@redhat.com>
(cherry picked from commit aaca725884b57c9245528a0afb3f32e078543faf)
Conflicts: Modified hw/core/sysbus-fdt.c and hw/vfio/platform.c
Patch-name: kvm-vfio-rename-field-to-num_initial_regions.patch
Patch-id: 30
Patch-present-in-specfile: True
---
hw/core/sysbus-fdt.c | 14 +++++++-------
hw/vfio-user/device.c | 2 +-
hw/vfio/ccw.c | 4 ++--
hw/vfio/device.c | 12 ++++++------
hw/vfio/iommufd.c | 3 ++-
hw/vfio/pci.c | 4 ++--
hw/vfio/platform.c | 10 +++++-----
include/hw/vfio/vfio-device.h | 2 +-
8 files changed, 26 insertions(+), 25 deletions(-)
diff --git a/hw/core/sysbus-fdt.c b/hw/core/sysbus-fdt.c
index c339a27875..1e1966813f 100644
--- a/hw/core/sysbus-fdt.c
+++ b/hw/core/sysbus-fdt.c
@@ -236,15 +236,15 @@ static int add_calxeda_midway_xgmac_fdt_node(SysBusDevice *sbdev, void *opaque)
qemu_fdt_setprop(fdt, nodename, "dma-coherent", "", 0);
- reg_attr = g_new(uint32_t, vbasedev->num_regions * 2);
- for (i = 0; i < vbasedev->num_regions; i++) {
+ reg_attr = g_new(uint32_t, vbasedev->num_initial_regions * 2);
+ for (i = 0; i < vbasedev->num_initial_regions; i++) {
mmio_base = platform_bus_get_mmio_addr(pbus, sbdev, i);
reg_attr[2 * i] = cpu_to_be32(mmio_base);
reg_attr[2 * i + 1] = cpu_to_be32(
memory_region_size(vdev->regions[i]->mem));
}
qemu_fdt_setprop(fdt, nodename, "reg", reg_attr,
- vbasedev->num_regions * 2 * sizeof(uint32_t));
+ vbasedev->num_initial_regions * 2 * sizeof(uint32_t));
irq_attr = g_new(uint32_t, vbasedev->num_irqs * 3);
for (i = 0; i < vbasedev->num_irqs; i++) {
@@ -330,7 +330,7 @@ static int add_amd_xgbe_fdt_node(SysBusDevice *sbdev, void *opaque)
g_free(dt_name);
- if (vbasedev->num_regions != 5) {
+ if (vbasedev->num_initial_regions != 5) {
error_report("%s Does the host dt node combine XGBE/PHY?", __func__);
exit(1);
}
@@ -374,15 +374,15 @@ static int add_amd_xgbe_fdt_node(SysBusDevice *sbdev, void *opaque)
guest_clock_phandles[0],
guest_clock_phandles[1]);
- reg_attr = g_new(uint32_t, vbasedev->num_regions * 2);
- for (i = 0; i < vbasedev->num_regions; i++) {
+ reg_attr = g_new(uint32_t, vbasedev->num_initial_regions * 2);
+ for (i = 0; i < vbasedev->num_initial_regions; i++) {
mmio_base = platform_bus_get_mmio_addr(pbus, sbdev, i);
reg_attr[2 * i] = cpu_to_be32(mmio_base);
reg_attr[2 * i + 1] = cpu_to_be32(
memory_region_size(vdev->regions[i]->mem));
}
qemu_fdt_setprop(guest_fdt, nodename, "reg", reg_attr,
- vbasedev->num_regions * 2 * sizeof(uint32_t));
+ vbasedev->num_initial_regions * 2 * sizeof(uint32_t));
irq_attr = g_new(uint32_t, vbasedev->num_irqs * 3);
for (i = 0; i < vbasedev->num_irqs; i++) {
diff --git a/hw/vfio-user/device.c b/hw/vfio-user/device.c
index 0609a7dc25..64ef35b320 100644
--- a/hw/vfio-user/device.c
+++ b/hw/vfio-user/device.c
@@ -134,7 +134,7 @@ static int vfio_user_device_io_get_region_info(VFIODevice *vbasedev,
VFIOUserFDs fds = { 0, 1, fd};
int ret;
- if (info->index > vbasedev->num_regions) {
+ if (info->index > vbasedev->num_initial_regions) {
return -EINVAL;
}
diff --git a/hw/vfio/ccw.c b/hw/vfio/ccw.c
index 9560b8d851..4d9588e7aa 100644
--- a/hw/vfio/ccw.c
+++ b/hw/vfio/ccw.c
@@ -484,9 +484,9 @@ static bool vfio_ccw_get_region(VFIOCCWDevice *vcdev, Error **errp)
* We always expect at least the I/O region to be present. We also
* may have a variable number of regions governed by capabilities.
*/
- if (vdev->num_regions < VFIO_CCW_CONFIG_REGION_INDEX + 1) {
+ if (vdev->num_initial_regions < VFIO_CCW_CONFIG_REGION_INDEX + 1) {
error_setg(errp, "vfio: too few regions (%u), expected at least %u",
- vdev->num_regions, VFIO_CCW_CONFIG_REGION_INDEX + 1);
+ vdev->num_initial_regions, VFIO_CCW_CONFIG_REGION_INDEX + 1);
return false;
}
diff --git a/hw/vfio/device.c b/hw/vfio/device.c
index 52a1996dc4..0b459c0f7c 100644
--- a/hw/vfio/device.c
+++ b/hw/vfio/device.c
@@ -257,7 +257,7 @@ int vfio_device_get_region_info_type(VFIODevice *vbasedev, uint32_t type,
{
int i;
- for (i = 0; i < vbasedev->num_regions; i++) {
+ for (i = 0; i < vbasedev->num_initial_regions; i++) {
struct vfio_info_cap_header *hdr;
struct vfio_region_info_cap_type *cap_type;
@@ -466,7 +466,7 @@ void vfio_device_prepare(VFIODevice *vbasedev, VFIOContainerBase *bcontainer,
int i;
vbasedev->num_irqs = info->num_irqs;
- vbasedev->num_regions = info->num_regions;
+ vbasedev->num_initial_regions = info->num_regions;
vbasedev->flags = info->flags;
vbasedev->reset_works = !!(info->flags & VFIO_DEVICE_FLAGS_RESET);
@@ -476,10 +476,10 @@ void vfio_device_prepare(VFIODevice *vbasedev, VFIOContainerBase *bcontainer,
QLIST_INSERT_HEAD(&vfio_device_list, vbasedev, global_next);
vbasedev->reginfo = g_new0(struct vfio_region_info *,
- vbasedev->num_regions);
+ vbasedev->num_initial_regions);
if (vbasedev->use_region_fds) {
- vbasedev->region_fds = g_new0(int, vbasedev->num_regions);
- for (i = 0; i < vbasedev->num_regions; i++) {
+ vbasedev->region_fds = g_new0(int, vbasedev->num_initial_regions);
+ for (i = 0; i < vbasedev->num_initial_regions; i++) {
vbasedev->region_fds[i] = -1;
}
}
@@ -489,7 +489,7 @@ void vfio_device_unprepare(VFIODevice *vbasedev)
{
int i;
- for (i = 0; i < vbasedev->num_regions; i++) {
+ for (i = 0; i < vbasedev->num_initial_regions; i++) {
g_free(vbasedev->reginfo[i]);
if (vbasedev->region_fds != NULL && vbasedev->region_fds[i] != -1) {
close(vbasedev->region_fds[i]);
diff --git a/hw/vfio/iommufd.c b/hw/vfio/iommufd.c
index 48c590b6a9..dbcd861b27 100644
--- a/hw/vfio/iommufd.c
+++ b/hw/vfio/iommufd.c
@@ -668,7 +668,8 @@ found_container:
vfio_iommufd_cpr_register_device(vbasedev);
trace_iommufd_cdev_device_info(vbasedev->name, devfd, vbasedev->num_irqs,
- vbasedev->num_regions, vbasedev->flags);
+ vbasedev->num_initial_regions,
+ vbasedev->flags);
return true;
err_listener_register:
diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
index 48da233cb2..9486521a90 100644
--- a/hw/vfio/pci.c
+++ b/hw/vfio/pci.c
@@ -2933,9 +2933,9 @@ bool vfio_pci_populate_device(VFIOPCIDevice *vdev, Error **errp)
return false;
}
- if (vbasedev->num_regions < VFIO_PCI_CONFIG_REGION_INDEX + 1) {
+ if (vbasedev->num_initial_regions < VFIO_PCI_CONFIG_REGION_INDEX + 1) {
error_setg(errp, "unexpected number of io regions %u",
- vbasedev->num_regions);
+ vbasedev->num_initial_regions);
return false;
}
diff --git a/hw/vfio/platform.c b/hw/vfio/platform.c
index 5c1795a26f..c9349ba7b7 100644
--- a/hw/vfio/platform.c
+++ b/hw/vfio/platform.c
@@ -148,7 +148,7 @@ static void vfio_mmap_set_enabled(VFIOPlatformDevice *vdev, bool enabled)
{
int i;
- for (i = 0; i < vdev->vbasedev.num_regions; i++) {
+ for (i = 0; i < vdev->vbasedev.num_initial_regions; i++) {
vfio_region_mmaps_set_enabled(vdev->regions[i], enabled);
}
}
@@ -453,9 +453,9 @@ static bool vfio_populate_device(VFIODevice *vbasedev, Error **errp)
return false;
}
- vdev->regions = g_new0(VFIORegion *, vbasedev->num_regions);
+ vdev->regions = g_new0(VFIORegion *, vbasedev->num_initial_regions);
- for (i = 0; i < vbasedev->num_regions; i++) {
+ for (i = 0; i < vbasedev->num_initial_regions; i++) {
char *name = g_strdup_printf("VFIO %s region %d\n", vbasedev->name, i);
vdev->regions[i] = g_new0(VFIORegion, 1);
@@ -499,7 +499,7 @@ irq_err:
g_free(intp);
}
reg_error:
- for (i = 0; i < vbasedev->num_regions; i++) {
+ for (i = 0; i < vbasedev->num_initial_regions; i++) {
if (vdev->regions[i]) {
vfio_region_finalize(vdev->regions[i]);
}
@@ -608,7 +608,7 @@ static void vfio_platform_realize(DeviceState *dev, Error **errp)
}
}
- for (i = 0; i < vbasedev->num_regions; i++) {
+ for (i = 0; i < vbasedev->num_initial_regions; i++) {
if (vfio_region_mmap(vdev->regions[i])) {
warn_report("%s mmap unsupported, performance may be slow",
memory_region_name(vdev->regions[i]->mem));
diff --git a/include/hw/vfio/vfio-device.h b/include/hw/vfio/vfio-device.h
index 9290774299..df81d319b2 100644
--- a/include/hw/vfio/vfio-device.h
+++ b/include/hw/vfio/vfio-device.h
@@ -74,7 +74,7 @@ typedef struct VFIODevice {
VFIODeviceOps *ops;
VFIODeviceIOOps *io_ops;
unsigned int num_irqs;
- unsigned int num_regions;
+ unsigned int num_initial_regions;
unsigned int flags;
VFIOMigration *migration;
Error *migration_blocker;

View File

@ -1,84 +0,0 @@
From 2541098f271ffc71046a2bd398043691cf82b2f2 Mon Sep 17 00:00:00 2001
From: John Levon <john.levon@nutanix.com>
Date: Tue, 14 Oct 2025 17:12:27 +0200
Subject: [PATCH] vfio: only check region info cache for initial regions
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
RH-Author: Cédric Le Goater <clg@redhat.com>
RH-MergeRequest: 414: Fixes for vfio region cache
RH-Jira: RHEL-118810
RH-Acked-by: Eric Auger <eric.auger@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [2/2] 30b628642ee153e7da612e43aead3c6cd2de9769 (clegoate/qemu-kvm-centos)
It is semantically valid for a VFIO device to increase the number of
regions after initialization. In this case, we'd attempt to check for
cached region info past the size of the ->reginfo array. Check for the
region index and skip the cache in these cases.
This also works around some VGPU use cases which appear to be a bug,
where VFIO_DEVICE_QUERY_GFX_PLANE returns a region index beyond the
reported ->num_regions.
Fixes: 95cdb024 ("vfio: add region info cache")
Signed-off-by: John Levon <john.levon@nutanix.com>
Reviewed-by: Cédric Le Goater <clg@redhat.com>
Reviewed-by: Alex Williamson <alex@shazbot.org>
Link: https://lore.kernel.org/qemu-devel/20251014151227.2298892-3-john.levon@nutanix.com
Signed-off-by: Cédric Le Goater <clg@redhat.com>
(cherry picked from commit ecbe424a63c9f860a901d6a4a75724b046abd796)
Patch-name: kvm-vfio-only-check-region-info-cache-for-initial-region.patch
Patch-id: 31
Patch-present-in-specfile: True
---
hw/vfio/device.c | 27 +++++++++++++++++++--------
1 file changed, 19 insertions(+), 8 deletions(-)
diff --git a/hw/vfio/device.c b/hw/vfio/device.c
index 0b459c0f7c..7ebf41c95e 100644
--- a/hw/vfio/device.c
+++ b/hw/vfio/device.c
@@ -205,10 +205,19 @@ int vfio_device_get_region_info(VFIODevice *vbasedev, int index,
int fd = -1;
int ret;
- /* check cache */
- if (vbasedev->reginfo[index] != NULL) {
- *info = vbasedev->reginfo[index];
- return 0;
+ /*
+ * We only set up the region info cache for the initial number of regions.
+ *
+ * Since a VFIO device may later increase the number of regions then use
+ * such regions with an index past ->num_initial_regions, don't attempt to
+ * use the info cache in those cases.
+ */
+ if (index < vbasedev->num_initial_regions) {
+ /* check cache */
+ if (vbasedev->reginfo[index] != NULL) {
+ *info = vbasedev->reginfo[index];
+ return 0;
+ }
}
*info = g_malloc0(argsz);
@@ -236,10 +245,12 @@ retry:
goto retry;
}
- /* fill cache */
- vbasedev->reginfo[index] = *info;
- if (vbasedev->region_fds != NULL) {
- vbasedev->region_fds[index] = fd;
+ if (index < vbasedev->num_initial_regions) {
+ /* fill cache */
+ vbasedev->reginfo[index] = *info;
+ if (vbasedev->region_fds != NULL) {
+ vbasedev->region_fds[index] = fd;
+ }
}
return 0;

View File

@ -1,51 +0,0 @@
From a75749cb933cbb6d1b6cce5dd8b283242069215e Mon Sep 17 00:00:00 2001
From: Sebastian Ott <sebott@redhat.com>
Date: Wed, 29 Oct 2025 15:53:41 +0100
Subject: [PATCH] arm: create new rhel 10.2 specific virt machine type
RH-Author: Sebastian Ott <sebott@redhat.com>
RH-MergeRequest: 416: x86, arm: create new rhel 9.8, 10.2 specific machine types
RH-Jira: RHEL-105826 RHEL-105828
RH-Acked-by: Eric Auger <eric.auger@redhat.com>
RH-Acked-by: Gavin Shan <gshan@redhat.com>
RH-Acked-by: Cornelia Huck <cohuck@redhat.com>
RH-Commit: [1/4] 829eed93aefddcc4684ddacff3cd6ff3f991f442 (seott1/cos-qemu-kvm)
Signed-off-by: Sebastian Ott <sebott@redhat.com>
Patch-name: kvm-arm-create-new-rhel-10.2-specific-virt-machine-type.patch
Patch-id: 32
Patch-present-in-specfile: True
---
hw/arm/virt.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index d37d1bb3cf..e68979d2c5 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -3688,16 +3688,23 @@ static void virt_machine_4_1_options(MachineClass *mc)
DEFINE_VIRT_MACHINE(4, 1)
#endif /* disabled for RHEL */
+static void virt_rhel_machine_10_2_0_options(MachineClass *mc)
+{
+}
+DEFINE_VIRT_MACHINE_AS_LATEST(10, 2, 0)
+
static void virt_rhel_machine_10_0_0_options(MachineClass *mc)
{
VirtMachineClass *vmc = VIRT_MACHINE_CLASS(OBJECT_CLASS(mc));
+ virt_rhel_machine_10_2_0_options(mc);
+
/* QEMU 9.1 and earlier have only a stage-1 SMMU, not a nested s1+2 one */
vmc->no_nested_smmu = true;
compat_props_add(mc->compat_props, hw_compat_rhel_10_2, hw_compat_rhel_10_2_len);
compat_props_add(mc->compat_props, hw_compat_rhel_10_1, hw_compat_rhel_10_1_len);
}
-DEFINE_VIRT_MACHINE_AS_LATEST(10, 0, 0)
+DEFINE_VIRT_MACHINE(10, 0, 0)
static void virt_rhel_machine_9_6_0_options(MachineClass *mc)
{

View File

@ -1,50 +0,0 @@
From 5ac559365c62f3b6f38b3ebfaab4b9dbf1a0888f Mon Sep 17 00:00:00 2001
From: Sebastian Ott <sebott@redhat.com>
Date: Wed, 29 Oct 2025 16:05:12 +0100
Subject: [PATCH] arm: create new rhel 9.8 specific virt machine type
RH-Author: Sebastian Ott <sebott@redhat.com>
RH-MergeRequest: 416: x86, arm: create new rhel 9.8, 10.2 specific machine types
RH-Jira: RHEL-105826 RHEL-105828
RH-Acked-by: Eric Auger <eric.auger@redhat.com>
RH-Acked-by: Gavin Shan <gshan@redhat.com>
RH-Acked-by: Cornelia Huck <cohuck@redhat.com>
RH-Commit: [2/4] fb3fc4decafd0c6e94ef31c0120b843512089573 (seott1/cos-qemu-kvm)
Signed-off-by: Sebastian Ott <sebott@redhat.com>
Patch-name: kvm-arm-create-new-rhel-9.8-specific-virt-machine-type.patch
Patch-id: 33
Patch-present-in-specfile: True
---
hw/arm/virt.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index e68979d2c5..dcdd53043e 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -3706,14 +3706,19 @@ static void virt_rhel_machine_10_0_0_options(MachineClass *mc)
}
DEFINE_VIRT_MACHINE(10, 0, 0)
-static void virt_rhel_machine_9_6_0_options(MachineClass *mc)
+static void virt_rhel_machine_9_8_0_options(MachineClass *mc)
{
- virt_rhel_machine_10_0_0_options(mc);
-
+ /* NB: remember to move these lines to the *latest* RHEL 9 machine */
compat_props_add(mc->compat_props, arm_rhel9_compat, arm_rhel9_compat_len);
- /* NB: remember to move this line to the *latest* RHEL 9 machine */
compat_props_add(mc->compat_props, hw_compat_rhel_9, hw_compat_rhel_9_len);
}
+DEFINE_VIRT_MACHINE(9, 8, 0)
+
+static void virt_rhel_machine_9_6_0_options(MachineClass *mc)
+{
+ virt_rhel_machine_10_0_0_options(mc);
+ virt_rhel_machine_9_8_0_options(mc);
+}
DEFINE_VIRT_MACHINE(9, 6, 0)
static void virt_rhel_machine_9_4_0_options(MachineClass *mc)

View File

@ -1,57 +0,0 @@
From 298dd9449200357a9563287ac036cb53283c27ae Mon Sep 17 00:00:00 2001
From: Sebastian Ott <sebott@redhat.com>
Date: Wed, 29 Oct 2025 17:59:07 +0100
Subject: [PATCH] x86: create new rhel 10.2 specific pc-q35 machine type
RH-Author: Sebastian Ott <sebott@redhat.com>
RH-MergeRequest: 416: x86, arm: create new rhel 9.8, 10.2 specific machine types
RH-Jira: RHEL-105826 RHEL-105828
RH-Acked-by: Eric Auger <eric.auger@redhat.com>
RH-Acked-by: Gavin Shan <gshan@redhat.com>
RH-Acked-by: Cornelia Huck <cohuck@redhat.com>
RH-Commit: [3/4] 7f5a5fa45696e579cd08fb3869884ce9543badd5 (seott1/cos-qemu-kvm)
Signed-off-by: Sebastian Ott <sebott@redhat.com>
Patch-name: kvm-x86-create-new-rhel-10.2-specific-pc-q35-machine-typ.patch
Patch-id: 34
Patch-present-in-specfile: True
---
hw/i386/pc_q35.c | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index e5d10c0335..aea4735dd3 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -690,10 +690,20 @@ DEFINE_Q35_MACHINE(2, 6);
/* Red Hat Enterprise Linux machine types */
-static void pc_q35_rhel_machine_10_0_0_options(MachineClass *m)
+static void pc_q35_rhel_machine_10_2_0_options(MachineClass *m)
{
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
pc_q35_machine_options(m);
+ m->desc = "RHEL-10.2.0 PC (Q35 + ICH9, 2009)";
+ pcmc->smbios_stream_product = "RHEL";
+ pcmc->smbios_stream_version = "10.2.0";
+}
+DEFINE_Q35_MACHINE_AS_LATEST(10, 2, 0);
+
+static void pc_q35_rhel_machine_10_0_0_options(MachineClass *m)
+{
+ PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
+ pc_q35_rhel_machine_10_2_0_options(m);
m->desc = "RHEL-10.0.0 PC (Q35 + ICH9, 2009)";
pcmc->smbios_stream_product = "RHEL";
pcmc->smbios_stream_version = "10.0.0";
@@ -707,7 +717,7 @@ static void pc_q35_rhel_machine_10_0_0_options(MachineClass *m)
compat_props_add(m->compat_props, pc_rhel_10_1_compat,
pc_rhel_10_1_compat_len);
}
-DEFINE_Q35_MACHINE_AS_LATEST(10, 0, 0);
+DEFINE_Q35_MACHINE(10, 0, 0);
static void pc_q35_rhel_machine_9_6_0_options(MachineClass *m)
{

View File

@ -1,57 +0,0 @@
From 77cd3055b005a8a0e83d8684c630beea6fd0e805 Mon Sep 17 00:00:00 2001
From: Sebastian Ott <sebott@redhat.com>
Date: Wed, 29 Oct 2025 18:05:21 +0100
Subject: [PATCH] x86: create new rhel 9.8 specific pc-q35 machine type
RH-Author: Sebastian Ott <sebott@redhat.com>
RH-MergeRequest: 416: x86, arm: create new rhel 9.8, 10.2 specific machine types
RH-Jira: RHEL-105826 RHEL-105828
RH-Acked-by: Eric Auger <eric.auger@redhat.com>
RH-Acked-by: Gavin Shan <gshan@redhat.com>
RH-Acked-by: Cornelia Huck <cohuck@redhat.com>
RH-Commit: [4/4] 2bfa55e063b4551e8e3299cf4f7aa2520943076a (seott1/cos-qemu-kvm)
Signed-off-by: Sebastian Ott <sebott@redhat.com>
Patch-name: kvm-x86-create-new-rhel-9.8-specific-pc-q35-machine-type.patch
Patch-id: 35
Patch-present-in-specfile: True
---
hw/i386/pc_q35.c | 17 ++++++++++++++---
1 file changed, 14 insertions(+), 3 deletions(-)
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index aea4735dd3..efbb5695c2 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -719,16 +719,27 @@ static void pc_q35_rhel_machine_10_0_0_options(MachineClass *m)
}
DEFINE_Q35_MACHINE(10, 0, 0);
+static void pc_q35_rhel_machine_9_8_0_options(MachineClass *m)
+{
+ PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
+ pc_q35_machine_options(m);
+ m->desc = "RHEL-9.8.0 PC (Q35 + ICH9, 2009)";
+ pcmc->smbios_stream_product = "RHEL";
+ pcmc->smbios_stream_version = "9.8.0";
+
+ /* NB: remember to move this line to the *latest* RHEL 9 machine */
+ compat_props_add(m->compat_props, hw_compat_rhel_9, hw_compat_rhel_9_len);
+}
+DEFINE_Q35_MACHINE(9, 8, 0);
+
static void pc_q35_rhel_machine_9_6_0_options(MachineClass *m)
{
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
pc_q35_rhel_machine_10_0_0_options(m);
+ pc_q35_rhel_machine_9_8_0_options(m);
m->desc = "RHEL-9.6.0 PC (Q35 + ICH9, 2009)";
pcmc->smbios_stream_product = "RHEL";
pcmc->smbios_stream_version = "9.6.0";
-
- /* NB: remember to move this line to the *latest* RHEL 9 machine */
- compat_props_add(m->compat_props, hw_compat_rhel_9, hw_compat_rhel_9_len);
}
DEFINE_Q35_MACHINE(9, 6, 0);

View File

@ -1,63 +0,0 @@
From 627b1afca71a6e0a7db77c310fe0d1db53818dd2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= <marcandre.lureau@redhat.com>
Date: Mon, 3 Nov 2025 14:35:38 +0400
Subject: [PATCH] rh: enable CONFIG_USB_STORAGE_BOT
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
RH-Author: Marc-André Lureau <marcandre.lureau@redhat.com>
RH-MergeRequest: 417: rh: enable CONFIG_USB_STORAGE_BOT
RH-Jira: RHEL-101929
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [1/1] 612acd1d19c799c7441f63548648eb70b9e1dfd6 (marcandre.lureau-rh/qemu-kvm-centos)
JIRA: https://issues.redhat.com/browse/RHEL-101929
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Patch-name: kvm-rh-enable-CONFIG_USB_STORAGE_BOT.patch
Patch-id: 36
Patch-present-in-specfile: True
---
configs/devices/aarch64-softmmu/aarch64-rh-devices.mak | 1 +
configs/devices/riscv64-softmmu/riscv64-rh-devices.mak | 1 +
configs/devices/x86_64-softmmu/x86_64-rh-devices.mak | 1 +
3 files changed, 3 insertions(+)
diff --git a/configs/devices/aarch64-softmmu/aarch64-rh-devices.mak b/configs/devices/aarch64-softmmu/aarch64-rh-devices.mak
index 855278f70e..92d0b322d0 100644
--- a/configs/devices/aarch64-softmmu/aarch64-rh-devices.mak
+++ b/configs/devices/aarch64-softmmu/aarch64-rh-devices.mak
@@ -19,6 +19,7 @@ CONFIG_SEMIHOSTING=y
CONFIG_USB=y
CONFIG_USB_XHCI=y
CONFIG_USB_XHCI_PCI=y
+CONFIG_USB_STORAGE_BOT=y
CONFIG_USB_STORAGE_CORE=y
CONFIG_USB_STORAGE_CLASSIC=y
CONFIG_USB_HUB=y
diff --git a/configs/devices/riscv64-softmmu/riscv64-rh-devices.mak b/configs/devices/riscv64-softmmu/riscv64-rh-devices.mak
index b5e55de916..5ac051f90b 100644
--- a/configs/devices/riscv64-softmmu/riscv64-rh-devices.mak
+++ b/configs/devices/riscv64-softmmu/riscv64-rh-devices.mak
@@ -15,6 +15,7 @@ CONFIG_SEMIHOSTING=y
CONFIG_USB=y
CONFIG_USB_XHCI=y
CONFIG_USB_XHCI_PCI=y
+CONFIG_USB_STORAGE_BOT=y
CONFIG_USB_STORAGE_CORE=y
CONFIG_USB_STORAGE_CLASSIC=y
CONFIG_USB_HUB=y
diff --git a/configs/devices/x86_64-softmmu/x86_64-rh-devices.mak b/configs/devices/x86_64-softmmu/x86_64-rh-devices.mak
index 828cb8aa6f..1f244f766d 100644
--- a/configs/devices/x86_64-softmmu/x86_64-rh-devices.mak
+++ b/configs/devices/x86_64-softmmu/x86_64-rh-devices.mak
@@ -79,6 +79,7 @@ CONFIG_USB=y
CONFIG_USB_EHCI=y
CONFIG_USB_EHCI_PCI=y
CONFIG_USB_SMARTCARD=y
+CONFIG_USB_STORAGE_BOT=y
CONFIG_USB_STORAGE_CORE=y
CONFIG_USB_STORAGE_CLASSIC=y
CONFIG_USB_UHCI=y

View File

@ -1,48 +0,0 @@
From 5aa680dc7371173d2ac1c1fb7cdd393819f44dca Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= <clg@redhat.com>
Date: Thu, 6 Nov 2025 16:39:53 +0100
Subject: [PATCH] vfio: Disable VFIO migration with MultiFD support
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
RH-Author: Cédric Le Goater <clg@redhat.com>
RH-MergeRequest: 421: vfio: Disable VFIO migration with MultiFD support
RH-Jira: RHEL-126573
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Acked-by: Thomas Huth <thuth@redhat.com>
RH-Commit: [1/1] b3ec6731c96e5650c66ece6e3b8728a7b94353f2 (clegoate/qemu-kvm-centos)
QEMU 10.0 extends VFIO migration with MultiFD support, which can be
controlled through the 'vfio-pci' device property
'x-migration-multifd-transfer'. By default, this property is set to
'auto', meaning its activation depends on the availability of other
related features. However, it should be set to 'off' in RHEL until
more testing has been completed.
Signed-off-by: Cédric Le Goater <clg@redhat.com>
Patch-name: kvm-vfio-Disable-VFIO-migration-with-MultiFD-support.patch
Patch-id: 39
Patch-present-in-specfile: True
---
hw/vfio/pci.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
index 9486521a90..83ecffb535 100644
--- a/hw/vfio/pci.c
+++ b/hw/vfio/pci.c
@@ -3686,10 +3686,11 @@ static const Property vfio_pci_dev_properties[] = {
igd_legacy_mode, ON_OFF_AUTO_AUTO),
DEFINE_PROP_ON_OFF_AUTO("enable-migration", VFIOPCIDevice,
vbasedev.enable_migration, ON_OFF_AUTO_AUTO),
+ /* RHEL only. Disable VFIO migration with MultiFD support */
DEFINE_PROP("x-migration-multifd-transfer", VFIOPCIDevice,
vbasedev.migration_multifd_transfer,
vfio_pci_migration_multifd_transfer_prop, OnOffAuto,
- .set_default = true, .defval.i = ON_OFF_AUTO_AUTO),
+ .set_default = true, .defval.i = ON_OFF_AUTO_OFF),
DEFINE_PROP_ON_OFF_AUTO("x-migration-load-config-after-iter", VFIOPCIDevice,
vbasedev.migration_load_config_after_iter,
ON_OFF_AUTO_AUTO),

View File

@ -1,67 +0,0 @@
From 58cba97a715fa3f506234e718191fcc34286f333 Mon Sep 17 00:00:00 2001
From: Eric Auger <eric.auger@redhat.com>
Date: Fri, 7 Nov 2025 05:23:16 -0500
Subject: [PATCH] hw/arm/virt: Use ACPI PCI hotplug by default from 10.2
onwards
RH-Author: Eric Auger <eric.auger@redhat.com>
RH-MergeRequest: 422: hw/arm/virt: Use ACPI PCI hotplug by default from 10.2 onwards
RH-Jira: RHEL-67323
RH-Acked-by: Sebastian Ott <sebott@redhat.com>
RH-Acked-by: Cornelia Huck <cohuck@redhat.com>
RH-Acked-by: Gavin Shan <gshan@redhat.com>
RH-Acked-by: Igor Mammedov <imammedo@redhat.com>
RH-Commit: [1/1] 4539ba6526fef80adb9893a643eb001449397447 (eauger1/centos-qemu-kvm)
UPSTREAM: RHEL-only
Use ACPI PCI hotplug by default from 10.2 onwards. For older
rhel10 machine types and all rhel9 machine types ACPI PCI hotplug
is kept disabled.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
Patch-name: kvm-hw-arm-virt-Use-ACPI-PCI-hotplug-by-default-from-10..patch
Patch-id: 40
Patch-present-in-specfile: True
---
hw/arm/virt.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index dcdd53043e..542d702513 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -94,9 +94,15 @@
static GlobalProperty arm_virt_compat[] = {
{ TYPE_VIRTIO_IOMMU_PCI, "aw-bits", "48" },
+ { TYPE_ACPI_GED, "acpi-pci-hotplug-with-bridge-support", "on" },
};
static const size_t arm_virt_compat_len = G_N_ELEMENTS(arm_virt_compat);
+GlobalProperty arm_acpi_pci_hp_disabled_compat[] = {
+ { TYPE_ACPI_GED, "acpi-pci-hotplug-with-bridge-support", "off" },
+};
+static const size_t arm_acpi_pci_hp_disabled_compat_len = G_N_ELEMENTS(arm_virt_compat);
+
/*
* RHEL9 kernels have pauth disabled while RHEL10 has it enabled,
* since qemu will setup the VM with pauth when KVM supports it we
@@ -104,6 +110,7 @@ static const size_t arm_virt_compat_len = G_N_ELEMENTS(arm_virt_compat);
*/
GlobalProperty arm_rhel9_compat[] = {
{TYPE_ARM_CPU, "pauth", "off", .optional = true},
+ {TYPE_ACPI_GED, "acpi-pci-hotplug-with-bridge-support", "off" },
};
const size_t arm_rhel9_compat_len = G_N_ELEMENTS(arm_rhel9_compat);
@@ -3701,6 +3708,8 @@ static void virt_rhel_machine_10_0_0_options(MachineClass *mc)
/* QEMU 9.1 and earlier have only a stage-1 SMMU, not a nested s1+2 one */
vmc->no_nested_smmu = true;
+ compat_props_add(mc->compat_props, arm_acpi_pci_hp_disabled_compat,
+ arm_acpi_pci_hp_disabled_compat_len);
compat_props_add(mc->compat_props, hw_compat_rhel_10_2, hw_compat_rhel_10_2_len);
compat_props_add(mc->compat_props, hw_compat_rhel_10_1, hw_compat_rhel_10_1_len);
}

View File

@ -1,132 +0,0 @@
From b8a9e338fb98883ba262f04320502d778753d427 Mon Sep 17 00:00:00 2001
From: Shameer Kolothum <skolothumtho@nvidia.com>
Date: Fri, 29 Aug 2025 09:25:23 +0100
Subject: [PATCH] hw/arm/smmu-common: Check SMMU has PCIe Root Complex
association
RH-Author: Eric Auger <eric.auger@redhat.com>
RH-MergeRequest: 423: hw/arm/virt: Add support for user creatable SMMUv3 device
RH-Jira: RHEL-73800
RH-Acked-by: Gavin Shan <gshan@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Acked-by: Sebastian Ott <sebott@redhat.com>
RH-Acked-by: Donald Dutile <None>
RH-Commit: [1/11] 9e7a87070ebfef643848d31fe66f5b4e82bfe0cf (eauger1/centos-qemu-kvm)
We only allow default PCIe Root Complex(pcie.0) or pxb-pcie based extra
root complexes to be associated with SMMU.
Although this change does not affect functionality at present, it is
required when we add support for user-creatable SMMUv3 devices in
future patches.
Note: Added a specific check to identify pxb-pcie to avoid matching
pxb-cxl host bridges, which are also of type PCI_HOST_BRIDGE. This
restriction can be relaxed once support for CXL devices on arm/virt
is added and validated with SMMUv3.
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Tested-by: Nathan Chen <nathanc@nvidia.com>
Tested-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Nicolin Chen <nicolinc@nvidia.com>
Tested-by: Nicolin Chen <nicolinc@nvidia.com>
Signed-off-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
Signed-off-by: Shameer Kolothum <skolothumtho@nvidia.com>
Reviewed-by: Donald Dutile <ddutile@redhat.com>
Message-id: 20250829082543.7680-2-skolothumtho@nvidia.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
(cherry picked from commit d9e6b8424fd2523a0361972d5dd841471879479c)
Signed-off-by: Eric Auger <eric.auger@redhat.com>
Patch-name: kvm-hw-arm-smmu-common-Check-SMMU-has-PCIe-Root-Complex-.patch
Patch-id: 41
Patch-present-in-specfile: True
---
hw/arm/smmu-common.c | 31 ++++++++++++++++++++++++++---
hw/pci-bridge/pci_expander_bridge.c | 1 -
include/hw/pci/pci_bridge.h | 1 +
3 files changed, 29 insertions(+), 4 deletions(-)
diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
index 0dcaf2f589..7f64ea48d0 100644
--- a/hw/arm/smmu-common.c
+++ b/hw/arm/smmu-common.c
@@ -20,6 +20,7 @@
#include "trace.h"
#include "exec/target_page.h"
#include "hw/core/cpu.h"
+#include "hw/pci/pci_bridge.h"
#include "hw/qdev-properties.h"
#include "qapi/error.h"
#include "qemu/jhash.h"
@@ -925,6 +926,7 @@ static void smmu_base_realize(DeviceState *dev, Error **errp)
{
SMMUState *s = ARM_SMMU(dev);
SMMUBaseClass *sbc = ARM_SMMU_GET_CLASS(dev);
+ PCIBus *pci_bus = s->primary_bus;
Error *local_err = NULL;
sbc->parent_realize(dev, &local_err);
@@ -937,11 +939,34 @@ static void smmu_base_realize(DeviceState *dev, Error **errp)
g_free, g_free);
s->smmu_pcibus_by_busptr = g_hash_table_new(NULL, NULL);
- if (s->primary_bus) {
- pci_setup_iommu(s->primary_bus, &smmu_ops, s);
- } else {
+ if (!pci_bus) {
error_setg(errp, "SMMU is not attached to any PCI bus!");
+ return;
+ }
+
+ /*
+ * We only allow default PCIe Root Complex(pcie.0) or pxb-pcie based extra
+ * root complexes to be associated with SMMU.
+ */
+ if (pci_bus_is_express(pci_bus) && pci_bus_is_root(pci_bus) &&
+ object_dynamic_cast(OBJECT(pci_bus)->parent, TYPE_PCI_HOST_BRIDGE)) {
+ /*
+ * This condition matches either the default pcie.0, pxb-pcie, or
+ * pxb-cxl. For both pxb-pcie and pxb-cxl, parent_dev will be set.
+ * Currently, we don't allow pxb-cxl as it requires further
+ * verification. Therefore, make sure this is indeed pxb-pcie.
+ */
+ if (pci_bus->parent_dev) {
+ if (!object_dynamic_cast(OBJECT(pci_bus), TYPE_PXB_PCIE_BUS)) {
+ goto out_err;
+ }
+ }
+ pci_setup_iommu(pci_bus, &smmu_ops, s);
+ return;
}
+out_err:
+ error_setg(errp, "SMMU should be attached to a default PCIe root complex"
+ "(pcie.0) or a pxb-pcie based root complex");
}
/*
diff --git a/hw/pci-bridge/pci_expander_bridge.c b/hw/pci-bridge/pci_expander_bridge.c
index 3a29dfefc2..1bcceddbc4 100644
--- a/hw/pci-bridge/pci_expander_bridge.c
+++ b/hw/pci-bridge/pci_expander_bridge.c
@@ -34,7 +34,6 @@ typedef struct PXBBus PXBBus;
DECLARE_INSTANCE_CHECKER(PXBBus, PXB_BUS,
TYPE_PXB_BUS)
-#define TYPE_PXB_PCIE_BUS "pxb-pcie-bus"
DECLARE_INSTANCE_CHECKER(PXBBus, PXB_PCIE_BUS,
TYPE_PXB_PCIE_BUS)
diff --git a/include/hw/pci/pci_bridge.h b/include/hw/pci/pci_bridge.h
index 8cdacbc4e1..a055fd8d32 100644
--- a/include/hw/pci/pci_bridge.h
+++ b/include/hw/pci/pci_bridge.h
@@ -104,6 +104,7 @@ typedef struct PXBPCIEDev {
PXBDev parent_obj;
} PXBPCIEDev;
+#define TYPE_PXB_PCIE_BUS "pxb-pcie-bus"
#define TYPE_PXB_CXL_BUS "pxb-cxl-bus"
#define TYPE_PXB_DEV "pxb"
OBJECT_DECLARE_SIMPLE_TYPE(PXBDev, PXB_DEV)

View File

@ -1,292 +0,0 @@
From 49538761679e13a5d2c37466e06f79be153aa17f Mon Sep 17 00:00:00 2001
From: Shameer Kolothum <skolothumtho@nvidia.com>
Date: Fri, 29 Aug 2025 09:25:24 +0100
Subject: [PATCH] hw/arm/virt-acpi-build: Re-arrange SMMUv3 IORT build
RH-Author: Eric Auger <eric.auger@redhat.com>
RH-MergeRequest: 423: hw/arm/virt: Add support for user creatable SMMUv3 device
RH-Jira: RHEL-73800
RH-Acked-by: Gavin Shan <gshan@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Acked-by: Sebastian Ott <sebott@redhat.com>
RH-Acked-by: Donald Dutile <None>
RH-Commit: [2/11] 73e2dd4f48ffaf614c79241bc73cbb0457849131 (eauger1/centos-qemu-kvm)
Introduce a new struct AcpiIortSMMUv3Dev to hold all the information
required for SMMUv3 IORT node and use that for populating the node.
The current machine wide SMMUv3 is named as legacy SMMUv3 as we will
soon add support for user-creatable SMMUv3 devices. These changes will
be useful to have common code paths when we add that support.
Tested-by: Nathan Chen <nathanc@nvidia.com>
Reviewed-by: Nicolin Chen <nicolinc@nvidia.com>
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Tested-by: Eric Auger <eric.auger@redhat.com>
Tested-by: Nicolin Chen <nicolinc@nvidia.com>
Signed-off-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
Signed-off-by: Shameer Kolothum <skolothumtho@nvidia.com>
Reviewed-by: Donald Dutile <ddutile@redhat.com>
Message-id: 20250829082543.7680-3-skolothumtho@nvidia.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
(cherry picked from commit 0e6a5bfb0eb17f57fb923b7905bd1435204bdd62)
Signed-off-by: Eric Auger <eric.auger@redhat.com>
Patch-name: kvm-hw-arm-virt-acpi-build-Re-arrange-SMMUv3-IORT-build.patch
Patch-id: 42
Patch-present-in-specfile: True
---
hw/arm/virt-acpi-build.c | 137 ++++++++++++++++++++++++++-------------
hw/arm/virt.c | 1 +
include/hw/arm/virt.h | 1 +
3 files changed, 94 insertions(+), 45 deletions(-)
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index b01fc4f8ef..bef4fabe56 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -305,29 +305,65 @@ static int iort_idmap_compare(gconstpointer a, gconstpointer b)
return idmap_a->input_base - idmap_b->input_base;
}
+typedef struct AcpiIortSMMUv3Dev {
+ int irq;
+ hwaddr base;
+ GArray *rc_smmu_idmaps;
+ /* Offset of the SMMUv3 IORT Node relative to the start of the IORT */
+ size_t offset;
+} AcpiIortSMMUv3Dev;
+
+/*
+ * Populate the struct AcpiIortSMMUv3Dev for the legacy SMMUv3 and
+ * return the total number of associated idmaps.
+ */
+static int populate_smmuv3_legacy_dev(GArray *sdev_blob)
+{
+ VirtMachineState *vms = VIRT_MACHINE(qdev_get_machine());
+ AcpiIortSMMUv3Dev sdev;
+
+ sdev.rc_smmu_idmaps = g_array_new(false, true, sizeof(AcpiIortIdMapping));
+ object_child_foreach_recursive(object_get_root(), iort_host_bridges,
+ sdev.rc_smmu_idmaps);
+ /*
+ * There can be only one legacy SMMUv3("iommu=smmuv3") as it is a machine
+ * wide one. Since it may cover multiple PCIe RCs(based on "bypass_iommu"
+ * property), may have multiple SMMUv3 idmaps. Sort it by input_base.
+ */
+ g_array_sort(sdev.rc_smmu_idmaps, iort_idmap_compare);
+
+ sdev.base = vms->memmap[VIRT_SMMU].base;
+ sdev.irq = vms->irqmap[VIRT_SMMU] + ARM_SPI_BASE;
+ g_array_append_val(sdev_blob, sdev);
+ return sdev.rc_smmu_idmaps->len;
+}
+
/* Compute ID ranges (RIDs) from RC that are directed to the ITS Group node */
-static void create_rc_its_idmaps(GArray *its_idmaps, GArray *smmu_idmaps)
+static void create_rc_its_idmaps(GArray *its_idmaps, GArray *smmuv3_devs)
{
AcpiIortIdMapping *idmap;
AcpiIortIdMapping next_range = {0};
+ AcpiIortSMMUv3Dev *sdev;
- /*
- * Based on the RID ranges that are directed to the SMMU, determine the
- * bypassed RID ranges, i.e., the ones that are directed to the ITS Group
- * node and do not pass through the SMMU, by subtracting the SMMU-bound
- * ranges from the full RID range (0x00000xFFFF).
- */
- for (int i = 0; i < smmu_idmaps->len; i++) {
- idmap = &g_array_index(smmu_idmaps, AcpiIortIdMapping, i);
+ for (int i = 0; i < smmuv3_devs->len; i++) {
+ sdev = &g_array_index(smmuv3_devs, AcpiIortSMMUv3Dev, i);
+ /*
+ * Based on the RID ranges that are directed to the SMMU, determine the
+ * bypassed RID ranges, i.e., the ones that are directed to the ITS
+ * Group node and do not pass through the SMMU, by subtracting the
+ * SMMU-bound ranges from the full RID range (0x00000xFFFF).
+ */
+ for (int j = 0; j < sdev->rc_smmu_idmaps->len; j++) {
+ idmap = &g_array_index(sdev->rc_smmu_idmaps, AcpiIortIdMapping, j);
- if (next_range.input_base < idmap->input_base) {
- next_range.id_count = idmap->input_base - next_range.input_base;
- g_array_append_val(its_idmaps, next_range);
- }
+ if (next_range.input_base < idmap->input_base) {
+ next_range.id_count = idmap->input_base - next_range.input_base;
+ g_array_append_val(its_idmaps, next_range);
+ }
- next_range.input_base = idmap->input_base + idmap->id_count;
+ next_range.input_base = idmap->input_base + idmap->id_count;
+ }
}
-
/*
* Append the last RC -> ITS ID mapping.
*
@@ -341,7 +377,6 @@ static void create_rc_its_idmaps(GArray *its_idmaps, GArray *smmu_idmaps)
}
}
-
/*
* Input Output Remapping Table (IORT)
* Conforms to "IO Remapping Table System Software on ARM Platforms",
@@ -351,9 +386,12 @@ static void
build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
{
int i, nb_nodes, rc_mapping_count;
- size_t node_size, smmu_offset = 0;
+ AcpiIortSMMUv3Dev *sdev;
+ size_t node_size;
+ int num_smmus = 0;
uint32_t id = 0;
- GArray *rc_smmu_idmaps = g_array_new(false, true, sizeof(AcpiIortIdMapping));
+ int rc_smmu_idmaps_len = 0;
+ GArray *smmuv3_devs = g_array_new(false, true, sizeof(AcpiIortSMMUv3Dev));
GArray *rc_its_idmaps = g_array_new(false, true, sizeof(AcpiIortIdMapping));
AcpiTable table = { .sig = "IORT", .rev = 3, .oem_id = vms->oem_id,
@@ -361,22 +399,21 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
/* Table 2 The IORT */
acpi_table_begin(&table, table_data);
- if (vms->iommu == VIRT_IOMMU_SMMUV3) {
- object_child_foreach_recursive(object_get_root(),
- iort_host_bridges, rc_smmu_idmaps);
-
- /* Sort the smmu idmap by input_base */
- g_array_sort(rc_smmu_idmaps, iort_idmap_compare);
+ if (vms->legacy_smmuv3_present) {
+ rc_smmu_idmaps_len = populate_smmuv3_legacy_dev(smmuv3_devs);
+ }
- nb_nodes = 2; /* RC and SMMUv3 */
- rc_mapping_count = rc_smmu_idmaps->len;
+ num_smmus = smmuv3_devs->len;
+ if (num_smmus) {
+ nb_nodes = num_smmus + 1; /* RC and SMMUv3 */
+ rc_mapping_count = rc_smmu_idmaps_len;
if (vms->its) {
/*
* Knowing the ID ranges from the RC to the SMMU, it's possible to
* determine the ID ranges from RC that go directly to ITS.
*/
- create_rc_its_idmaps(rc_its_idmaps, rc_smmu_idmaps);
+ create_rc_its_idmaps(rc_its_idmaps, smmuv3_devs);
nb_nodes++; /* ITS */
rc_mapping_count += rc_its_idmaps->len;
@@ -411,9 +448,10 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
build_append_int_noprefix(table_data, 0 /* MADT translation_id */, 4);
}
- if (vms->iommu == VIRT_IOMMU_SMMUV3) {
- int irq = vms->irqmap[VIRT_SMMU] + ARM_SPI_BASE;
+ for (i = 0; i < num_smmus; i++) {
+ sdev = &g_array_index(smmuv3_devs, AcpiIortSMMUv3Dev, i);
int smmu_mapping_count, offset_to_id_array;
+ int irq = sdev->irq;
if (vms->its) {
smmu_mapping_count = 1; /* ITS Group node */
@@ -422,7 +460,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
smmu_mapping_count = 0; /* No ID mappings */
offset_to_id_array = 0; /* No ID mappings array */
}
- smmu_offset = table_data->len - table.table_offset;
+ sdev->offset = table_data->len - table.table_offset;
/* Table 9 SMMUv3 Format */
build_append_int_noprefix(table_data, 4 /* SMMUv3 */, 1); /* Type */
node_size = SMMU_V3_ENTRY_SIZE +
@@ -435,7 +473,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
/* Reference to ID Array */
build_append_int_noprefix(table_data, offset_to_id_array, 4);
/* Base address */
- build_append_int_noprefix(table_data, vms->memmap[VIRT_SMMU].base, 8);
+ build_append_int_noprefix(table_data, sdev->base, 8);
/* Flags */
build_append_int_noprefix(table_data, 1 /* COHACC Override */, 4);
build_append_int_noprefix(table_data, 0, 4); /* Reserved */
@@ -486,21 +524,26 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
build_append_int_noprefix(table_data, 0, 3); /* Reserved */
/* Output Reference */
- if (vms->iommu == VIRT_IOMMU_SMMUV3) {
+ if (num_smmus) {
AcpiIortIdMapping *range;
- /*
- * Map RIDs (input) from RC to SMMUv3 nodes: RC -> SMMUv3.
- *
- * N.B.: The mapping from SMMUv3 to ITS Group node (SMMUv3 -> ITS) is
- * defined in the SMMUv3 table, where all SMMUv3 IDs are mapped to the
- * ITS Group node, if ITS is available.
- */
- for (i = 0; i < rc_smmu_idmaps->len; i++) {
- range = &g_array_index(rc_smmu_idmaps, AcpiIortIdMapping, i);
- /* Output IORT node is the SMMUv3 node. */
- build_iort_id_mapping(table_data, range->input_base,
- range->id_count, smmu_offset);
+ for (i = 0; i < num_smmus; i++) {
+ sdev = &g_array_index(smmuv3_devs, AcpiIortSMMUv3Dev, i);
+
+ /*
+ * Map RIDs (input) from RC to SMMUv3 nodes: RC -> SMMUv3.
+ *
+ * N.B.: The mapping from SMMUv3 to ITS Group node (SMMUv3 -> ITS)
+ * is defined in the SMMUv3 table, where all SMMUv3 IDs are mapped
+ * to the ITS Group node, if ITS is available.
+ */
+ for (int j = 0; j < sdev->rc_smmu_idmaps->len; j++) {
+ range = &g_array_index(sdev->rc_smmu_idmaps,
+ AcpiIortIdMapping, j);
+ /* Output IORT node is the SMMUv3 node. */
+ build_iort_id_mapping(table_data, range->input_base,
+ range->id_count, sdev->offset);
+ }
}
if (vms->its) {
@@ -525,8 +568,12 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
}
acpi_table_end(linker, &table);
- g_array_free(rc_smmu_idmaps, true);
g_array_free(rc_its_idmaps, true);
+ for (i = 0; i < num_smmus; i++) {
+ sdev = &g_array_index(smmuv3_devs, AcpiIortSMMUv3Dev, i);
+ g_array_free(sdev->rc_smmu_idmaps, true);
+ }
+ g_array_free(smmuv3_devs, true);
}
/*
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 542d702513..0cc9e5f068 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -1686,6 +1686,7 @@ static void create_pcie(VirtMachineState *vms)
qemu_fdt_setprop_cells(ms->fdt, nodename, "iommu-map",
0x0, vms->iommu_phandle, 0x0, 0x10000);
}
+ vms->legacy_smmuv3_present = true;
break;
default:
g_assert_not_reached();
diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
index 94c79d6c6d..98b877c8b9 100644
--- a/include/hw/arm/virt.h
+++ b/include/hw/arm/virt.h
@@ -180,6 +180,7 @@ struct VirtMachineState {
char *oem_table_id;
bool ns_el2_virt_timer_irq;
CXLState cxl_devices_state;
+ bool legacy_smmuv3_present;
};
#define VIRT_ECAM_ID(high) (high ? VIRT_HIGH_PCIE_ECAM : VIRT_PCIE_ECAM)

View File

@ -1,171 +0,0 @@
From 90910403b2dc85fa6f2106a6bd75f1eee123f359 Mon Sep 17 00:00:00 2001
From: Shameer Kolothum <skolothumtho@nvidia.com>
Date: Fri, 29 Aug 2025 09:25:25 +0100
Subject: [PATCH] hw/arm/virt-acpi-build: Update IORT for multiple smmuv3
devices
RH-Author: Eric Auger <eric.auger@redhat.com>
RH-MergeRequest: 423: hw/arm/virt: Add support for user creatable SMMUv3 device
RH-Jira: RHEL-73800
RH-Acked-by: Gavin Shan <gshan@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Acked-by: Sebastian Ott <sebott@redhat.com>
RH-Acked-by: Donald Dutile <None>
RH-Commit: [3/11] 9cb15768a319676af16cd2cdef8b8fabfa7b6f13 (eauger1/centos-qemu-kvm)
With the soon to be introduced user-creatable SMMUv3 devices for
virt, it is possible to have multiple SMMUv3 devices associated
with different PCIe root complexes.
Update IORT nodes accordingly.
An example IORT Id mappings for a Qemu virt machine with two
PCIe Root Complexes each assocaited with a SMMUv3 will
be something like below,
-device arm-smmuv3,primary-bus=pcie.0,id=smmuv3.0
-device arm-smmuv3,primary-bus=pcie.1,id=smmuv3.1
...
+--------------------+ +--------------------+
| Root Complex 0 | | Root Complex 1 |
| | | |
| Requestor IDs | | Requestor IDs |
| 0x0000 - 0x00FF | | 0x0100 - 0x01FF |
+---------+----------+ +---------+----------+
| |
| |
| Stream ID Mapping |
v v
+--------------------+ +--------------------+
| SMMUv3 Node 0 | | SMMUv3 Node 1 |
| | | |
| Stream IDs 0x0000- | | Stream IDs 0x0100- |
| 0x00FF mapped from | | 0x01FF mapped from |
| RC0 Requestor IDs | | RC1 Requestor IDs |
+--------------------+ +--------------------+
| |
| |
+----------------+---------------+
|
|Device ID Mapping
v
+----------------------------+
| ITS Node 0 |
| |
| Device IDs: |
| 0x0000 - 0x00FF (from RC0) |
| 0x0100 - 0x01FF (from RC1) |
| 0x0200 - 0xFFFF (No SMMU) |
+----------------------------+
Tested-by: Nathan Chen <nathanc@nvidia.com>
Reviewed-by: Nicolin Chen <nicolinc@nvidia.com>
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Tested-by: Eric Auger <eric.auger@redhat.com>
Tested-by: Nicolin Chen <nicolinc@nvidia.com>
Signed-off-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
Signed-off-by: Shameer Kolothum <skolothumtho@nvidia.com>
Reviewed-by: Donald Dutile <ddutile@redhat.com>
Message-id: 20250829082543.7680-4-skolothumtho@nvidia.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
(cherry picked from commit 01e9a18730e6f56f713ed074603a8b0f2982ed26)
Signed-off-by: Eric Auger <eric.auger@redhat.com>
Patch-name: kvm-hw-arm-virt-acpi-build-Update-IORT-for-multiple-smmu.patch
Patch-id: 43
Patch-present-in-specfile: True
---
hw/arm/virt-acpi-build.c | 64 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 64 insertions(+)
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index bef4fabe56..96830f7c4e 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -45,6 +45,7 @@
#include "hw/acpi/generic_event_device.h"
#include "hw/acpi/tpm.h"
#include "hw/acpi/hmat.h"
+#include "hw/arm/smmuv3.h"
#include "hw/cxl/cxl.h"
#include "hw/pci/pcie_host.h"
#include "hw/pci/pci.h"
@@ -338,6 +339,67 @@ static int populate_smmuv3_legacy_dev(GArray *sdev_blob)
return sdev.rc_smmu_idmaps->len;
}
+static int smmuv3_dev_idmap_compare(gconstpointer a, gconstpointer b)
+{
+ AcpiIortSMMUv3Dev *sdev_a = (AcpiIortSMMUv3Dev *)a;
+ AcpiIortSMMUv3Dev *sdev_b = (AcpiIortSMMUv3Dev *)b;
+ AcpiIortIdMapping *map_a = &g_array_index(sdev_a->rc_smmu_idmaps,
+ AcpiIortIdMapping, 0);
+ AcpiIortIdMapping *map_b = &g_array_index(sdev_b->rc_smmu_idmaps,
+ AcpiIortIdMapping, 0);
+ return map_a->input_base - map_b->input_base;
+}
+
+static int iort_smmuv3_devices(Object *obj, void *opaque)
+{
+ VirtMachineState *vms = VIRT_MACHINE(qdev_get_machine());
+ GArray *sdev_blob = opaque;
+ AcpiIortIdMapping idmap;
+ PlatformBusDevice *pbus;
+ AcpiIortSMMUv3Dev sdev;
+ int min_bus, max_bus;
+ SysBusDevice *sbdev;
+ PCIBus *bus;
+
+ if (!object_dynamic_cast(obj, TYPE_ARM_SMMUV3)) {
+ return 0;
+ }
+
+ bus = PCI_BUS(object_property_get_link(obj, "primary-bus", &error_abort));
+ pbus = PLATFORM_BUS_DEVICE(vms->platform_bus_dev);
+ sbdev = SYS_BUS_DEVICE(obj);
+ sdev.base = platform_bus_get_mmio_addr(pbus, sbdev, 0);
+ sdev.base += vms->memmap[VIRT_PLATFORM_BUS].base;
+ sdev.irq = platform_bus_get_irqn(pbus, sbdev, 0);
+ sdev.irq += vms->irqmap[VIRT_PLATFORM_BUS];
+ sdev.irq += ARM_SPI_BASE;
+
+ pci_bus_range(bus, &min_bus, &max_bus);
+ sdev.rc_smmu_idmaps = g_array_new(false, true, sizeof(AcpiIortIdMapping));
+ idmap.input_base = min_bus << 8,
+ idmap.id_count = (max_bus - min_bus + 1) << 8,
+ g_array_append_val(sdev.rc_smmu_idmaps, idmap);
+ g_array_append_val(sdev_blob, sdev);
+ return 0;
+}
+
+/*
+ * Populate the struct AcpiIortSMMUv3Dev for all SMMUv3 devices and
+ * return the total number of idmaps.
+ */
+static int populate_smmuv3_dev(GArray *sdev_blob)
+{
+ object_child_foreach_recursive(object_get_root(),
+ iort_smmuv3_devices, sdev_blob);
+ /* Sort the smmuv3 devices(if any) by smmu idmap input_base */
+ g_array_sort(sdev_blob, smmuv3_dev_idmap_compare);
+ /*
+ * Since each SMMUv3 dev is assocaited with specific host bridge,
+ * total number of idmaps equals to total number of smmuv3 devices.
+ */
+ return sdev_blob->len;
+}
+
/* Compute ID ranges (RIDs) from RC that are directed to the ITS Group node */
static void create_rc_its_idmaps(GArray *its_idmaps, GArray *smmuv3_devs)
{
@@ -401,6 +463,8 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
if (vms->legacy_smmuv3_present) {
rc_smmu_idmaps_len = populate_smmuv3_legacy_dev(smmuv3_devs);
+ } else {
+ rc_smmu_idmaps_len = populate_smmuv3_dev(smmuv3_devs);
}
num_smmus = smmuv3_devs->len;

View File

@ -1,119 +0,0 @@
From cb1057c9f94d149a6ddc2c9310ab6bd4ec260538 Mon Sep 17 00:00:00 2001
From: Shameer Kolothum <skolothumtho@nvidia.com>
Date: Fri, 29 Aug 2025 09:25:26 +0100
Subject: [PATCH] hw/arm/virt: Factor out common SMMUV3 dt bindings code
RH-Author: Eric Auger <eric.auger@redhat.com>
RH-MergeRequest: 423: hw/arm/virt: Add support for user creatable SMMUv3 device
RH-Jira: RHEL-73800
RH-Acked-by: Gavin Shan <gshan@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Acked-by: Sebastian Ott <sebott@redhat.com>
RH-Acked-by: Donald Dutile <None>
RH-Commit: [4/11] db5d2a44f4cd1583c839b93ae551a2ddbd68b83b (eauger1/centos-qemu-kvm)
No functional changes intended. This will be useful when we
add support for user-creatable smmuv3 device.
Reviewed-by: Nicolin Chen <nicolinc@nvidia.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Tested-by: Nathan Chen <nathanc@nvidia.com>
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Tested-by: Eric Auger <eric.auger@redhat.com>
Tested-by: Nicolin Chen <nicolinc@nvidia.com>
Signed-off-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
Signed-off-by: Shameer Kolothum <skolothumtho@nvidia.com>
Reviewed-by: Donald Dutile <ddutile@redhat.com>
Message-id: 20250829082543.7680-5-skolothumtho@nvidia.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
(cherry picked from commit 7a276b7570266ec39611f9d91089741ec7e9295b)
Signed-off-by: Eric Auger <eric.auger@redhat.com>
Patch-name: kvm-hw-arm-virt-Factor-out-common-SMMUV3-dt-bindings-cod.patch
Patch-id: 44
Patch-present-in-specfile: True
---
hw/arm/virt.c | 54 +++++++++++++++++++++++++++------------------------
1 file changed, 29 insertions(+), 25 deletions(-)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 0cc9e5f068..9b95a7c9a9 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -1479,19 +1479,43 @@ static void create_pcie_irq_map(const MachineState *ms,
0x7 /* PCI irq */);
}
+static void create_smmuv3_dt_bindings(const VirtMachineState *vms, hwaddr base,
+ hwaddr size, int irq)
+{
+ char *node;
+ const char compat[] = "arm,smmu-v3";
+ const char irq_names[] = "eventq\0priq\0cmdq-sync\0gerror";
+ MachineState *ms = MACHINE(vms);
+
+ node = g_strdup_printf("/smmuv3@%" PRIx64, base);
+ qemu_fdt_add_subnode(ms->fdt, node);
+ qemu_fdt_setprop(ms->fdt, node, "compatible", compat, sizeof(compat));
+ qemu_fdt_setprop_sized_cells(ms->fdt, node, "reg", 2, base, 2, size);
+
+ qemu_fdt_setprop_cells(ms->fdt, node, "interrupts",
+ GIC_FDT_IRQ_TYPE_SPI, irq , GIC_FDT_IRQ_FLAGS_EDGE_LO_HI,
+ GIC_FDT_IRQ_TYPE_SPI, irq + 1, GIC_FDT_IRQ_FLAGS_EDGE_LO_HI,
+ GIC_FDT_IRQ_TYPE_SPI, irq + 2, GIC_FDT_IRQ_FLAGS_EDGE_LO_HI,
+ GIC_FDT_IRQ_TYPE_SPI, irq + 3, GIC_FDT_IRQ_FLAGS_EDGE_LO_HI);
+
+ qemu_fdt_setprop(ms->fdt, node, "interrupt-names", irq_names,
+ sizeof(irq_names));
+
+ qemu_fdt_setprop(ms->fdt, node, "dma-coherent", NULL, 0);
+ qemu_fdt_setprop_cell(ms->fdt, node, "#iommu-cells", 1);
+ qemu_fdt_setprop_cell(ms->fdt, node, "phandle", vms->iommu_phandle);
+ g_free(node);
+}
+
static void create_smmu(const VirtMachineState *vms,
PCIBus *bus)
{
VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms);
- char *node;
- const char compat[] = "arm,smmu-v3";
int irq = vms->irqmap[VIRT_SMMU];
int i;
hwaddr base = vms->memmap[VIRT_SMMU].base;
hwaddr size = vms->memmap[VIRT_SMMU].size;
- const char irq_names[] = "eventq\0priq\0cmdq-sync\0gerror";
DeviceState *dev;
- MachineState *ms = MACHINE(vms);
if (vms->iommu != VIRT_IOMMU_SMMUV3 || !vms->iommu_phandle) {
return;
@@ -1510,27 +1534,7 @@ static void create_smmu(const VirtMachineState *vms,
sysbus_connect_irq(SYS_BUS_DEVICE(dev), i,
qdev_get_gpio_in(vms->gic, irq + i));
}
-
- node = g_strdup_printf("/smmuv3@%" PRIx64, base);
- qemu_fdt_add_subnode(ms->fdt, node);
- qemu_fdt_setprop(ms->fdt, node, "compatible", compat, sizeof(compat));
- qemu_fdt_setprop_sized_cells(ms->fdt, node, "reg", 2, base, 2, size);
-
- qemu_fdt_setprop_cells(ms->fdt, node, "interrupts",
- GIC_FDT_IRQ_TYPE_SPI, irq , GIC_FDT_IRQ_FLAGS_EDGE_LO_HI,
- GIC_FDT_IRQ_TYPE_SPI, irq + 1, GIC_FDT_IRQ_FLAGS_EDGE_LO_HI,
- GIC_FDT_IRQ_TYPE_SPI, irq + 2, GIC_FDT_IRQ_FLAGS_EDGE_LO_HI,
- GIC_FDT_IRQ_TYPE_SPI, irq + 3, GIC_FDT_IRQ_FLAGS_EDGE_LO_HI);
-
- qemu_fdt_setprop(ms->fdt, node, "interrupt-names", irq_names,
- sizeof(irq_names));
-
- qemu_fdt_setprop(ms->fdt, node, "dma-coherent", NULL, 0);
-
- qemu_fdt_setprop_cell(ms->fdt, node, "#iommu-cells", 1);
-
- qemu_fdt_setprop_cell(ms->fdt, node, "phandle", vms->iommu_phandle);
- g_free(node);
+ create_smmuv3_dt_bindings(vms, base, size, irq);
}
static void create_virtio_iommu_dt_bindings(VirtMachineState *vms)

View File

@ -1,62 +0,0 @@
From 2a43ed7e5472ba40c08cb5784fd1aadae9774c0e Mon Sep 17 00:00:00 2001
From: Nicolin Chen <nicolinc@nvidia.com>
Date: Fri, 29 Aug 2025 09:25:27 +0100
Subject: [PATCH] hw/arm/virt: Add an SMMU_IO_LEN macro
RH-Author: Eric Auger <eric.auger@redhat.com>
RH-MergeRequest: 423: hw/arm/virt: Add support for user creatable SMMUv3 device
RH-Jira: RHEL-73800
RH-Acked-by: Gavin Shan <gshan@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Acked-by: Sebastian Ott <sebott@redhat.com>
RH-Acked-by: Donald Dutile <None>
RH-Commit: [5/11] 72c82e228bb256db07fbe28728ad47dbd8b04dc3 (eauger1/centos-qemu-kvm)
This is useful as the subsequent support for new SMMUv3 dev will also
use the same.
Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
Reviewed-by: Donald Dutile <ddutile@redhat.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Tested-by: Nathan Chen <nathanc@nvidia.com>
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Tested-by: Eric Auger <eric.auger@redhat.com>
Tested-by: Nicolin Chen <nicolinc@nvidia.com>
Signed-off-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
Signed-off-by: Shameer Kolothum <skolothumtho@nvidia.com>
Reviewed-by: Nicolin Chen <nicolinc@nvidia.com>
Message-id: 20250829082543.7680-6-skolothumtho@nvidia.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
(cherry picked from commit 466197fc7a25658f9187d538c26887f5738d1ac9)
Signed-off-by: Eric Auger <eric.auger@redhat.com>
Patch-name: kvm-hw-arm-virt-Add-an-SMMU_IO_LEN-macro.patch
Patch-id: 45
Patch-present-in-specfile: True
---
hw/arm/virt.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 9b95a7c9a9..b435efafe1 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -186,6 +186,9 @@ static void arm_virt_compat_set(MachineClass *mc)
#define LEGACY_RAMLIMIT_GB 255
#define LEGACY_RAMLIMIT_BYTES (LEGACY_RAMLIMIT_GB * GiB)
+/* MMIO region size for SMMUv3 */
+#define SMMU_IO_LEN 0x20000
+
/* Addresses and sizes of our components.
* 0..128MB is space for a flash device so we can run bootrom code such as UEFI.
* 128MB..256MB is used for miscellaneous device I/O.
@@ -217,7 +220,7 @@ static const MemMapEntry base_memmap[] = {
[VIRT_FW_CFG] = { 0x09020000, 0x00000018 },
[VIRT_GPIO] = { 0x09030000, 0x00001000 },
[VIRT_UART1] = { 0x09040000, 0x00001000 },
- [VIRT_SMMU] = { 0x09050000, 0x00020000 },
+ [VIRT_SMMU] = { 0x09050000, SMMU_IO_LEN },
[VIRT_PCDIMM_ACPI] = { 0x09070000, MEMORY_HOTPLUG_IO_LEN },
[VIRT_ACPI_GED] = { 0x09080000, ACPI_GED_EVT_SEL_LEN },
[VIRT_NVDIMM_ACPI] = { 0x09090000, NVDIMM_ACPI_IO_LEN},

View File

@ -1,151 +0,0 @@
From fc47a08ea593b2fdb1d872f40237a818dabad4fc Mon Sep 17 00:00:00 2001
From: Shameer Kolothum <skolothumtho@nvidia.com>
Date: Fri, 29 Aug 2025 09:25:28 +0100
Subject: [PATCH] hw/pci: Introduce pci_setup_iommu_per_bus() for per-bus IOMMU
ops retrieval
RH-Author: Eric Auger <eric.auger@redhat.com>
RH-MergeRequest: 423: hw/arm/virt: Add support for user creatable SMMUv3 device
RH-Jira: RHEL-73800
RH-Acked-by: Gavin Shan <gshan@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Acked-by: Sebastian Ott <sebott@redhat.com>
RH-Acked-by: Donald Dutile <None>
RH-Commit: [6/11] 0c41f77254cd66a3648c14c5d4ba2dfdbd396665 (eauger1/centos-qemu-kvm)
Currently, pci_setup_iommu() registers IOMMU ops for a given PCIBus.
However, when retrieving IOMMU ops for a device using
pci_device_get_iommu_bus_devfn(), the function checks the parent_dev
and fetches IOMMU ops from the parent device, even if the current
bus does not have any associated IOMMU ops.
This behavior works for now because QEMU's IOMMU implementations are
globally scoped, and host bridges rely on the bypass_iommu property
to skip IOMMU translation when needed.
However, this model will break with the soon to be introduced
arm-smmuv3 device, which allows users to associate the IOMMU
with a specific PCIe root complex (e.g., the default pcie.0
or a pxb-pcie root complex).
For example, consider the following setup with multiple root
complexes:
-device arm-smmuv3,primary-bus=pcie.0,id=smmuv3.0 \
...
-device pxb-pcie,id=pcie.1,bus_nr=8,bus=pcie.0 \
-device pcie-root-port,id=pcie.port1,bus=pcie.1 \
-device virtio-net-pci,bus=pcie.port1
In Qemu, pxb-pcie acts as a special root complex whose parent is
effectively the default root complex(pcie.0). Hence, though pcie.1
has no associated SMMUv3 as per above, pci_device_get_iommu_bus_devfn()
will incorrectly return the IOMMU ops from pcie.0 due to the fallback
via parent_dev.
To fix this, introduce a new helper pci_setup_iommu_per_bus() that
explicitly sets the new iommu_per_bus field in the PCIBus structure.
This helper will be used in a subsequent patch that adds support for
the new arm-smmuv3 device.
Update pci_device_get_iommu_bus_devfn() to use iommu_per_bus when
determining the correct IOMMU ops, ensuring accurate behavior for
per-bus IOMMUs.
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Tested-by: Nathan Chen <nathanc@nvidia.com>
Tested-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Nicolin Chen <nicolinc@nvidia.com>
Tested-by: Nicolin Chen <nicolinc@nvidia.com>
Signed-off-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
Signed-off-by: Shameer Kolothum <skolothumtho@nvidia.com>
Reviewed-by: Donald Dutile <ddutile@redhat.com>
Message-id: 20250829082543.7680-7-skolothumtho@nvidia.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
(cherry picked from commit 951bc76fb669eab96cc60e38a50097ad4435163e)
Signed-off-by: Eric Auger <eric.auger@redhat.com>
Patch-name: kvm-hw-pci-Introduce-pci_setup_iommu_per_bus-for-per-bus.patch
Patch-id: 46
Patch-present-in-specfile: True
---
hw/pci/pci.c | 31 +++++++++++++++++++++++++++++++
include/hw/pci/pci.h | 2 ++
include/hw/pci/pci_bus.h | 1 +
3 files changed, 34 insertions(+)
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index c70b5ceeba..0012cc12e7 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -2909,6 +2909,19 @@ static void pci_device_get_iommu_bus_devfn(PCIDevice *dev,
}
}
+ /*
+ * When multiple PCI Express Root Buses are defined using pxb-pcie,
+ * the IOMMU configuration may be specific to each root bus. However,
+ * pxb-pcie acts as a special root complex whose parent is effectively
+ * the default root complex(pcie.0). Ensure that we retrieve the
+ * correct IOMMU ops(if any) in such cases.
+ */
+ if (pci_bus_is_express(iommu_bus) && pci_bus_is_root(iommu_bus)) {
+ if (parent_bus->iommu_per_bus) {
+ break;
+ }
+ }
+
iommu_bus = parent_bus;
}
@@ -3169,6 +3182,24 @@ void pci_setup_iommu(PCIBus *bus, const PCIIOMMUOps *ops, void *opaque)
bus->iommu_opaque = opaque;
}
+/*
+ * Similar to pci_setup_iommu(), but sets iommu_per_bus to true,
+ * indicating that the IOMMU is specific to this bus. This is used by
+ * IOMMU implementations that are tied to a specific PCIe root complex.
+ *
+ * In QEMU, pxb-pcie behaves as a special root complex whose parent is
+ * effectively the default root complex (pcie.0). The iommu_per_bus
+ * is checked in pci_device_get_iommu_bus_devfn() to ensure the correct
+ * IOMMU ops are returned, avoiding the use of the parents IOMMU when
+ * it's not appropriate.
+ */
+void pci_setup_iommu_per_bus(PCIBus *bus, const PCIIOMMUOps *ops,
+ void *opaque)
+{
+ pci_setup_iommu(bus, ops, opaque);
+ bus->iommu_per_bus = true;
+}
+
static void pci_dev_get_w64(PCIBus *b, PCIDevice *dev, void *opaque)
{
Range *range = opaque;
diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h
index 6b7d3ac8a3..6bccb25ac2 100644
--- a/include/hw/pci/pci.h
+++ b/include/hw/pci/pci.h
@@ -773,6 +773,8 @@ int pci_iommu_unregister_iotlb_notifier(PCIDevice *dev, uint32_t pasid,
*/
void pci_setup_iommu(PCIBus *bus, const PCIIOMMUOps *ops, void *opaque);
+void pci_setup_iommu_per_bus(PCIBus *bus, const PCIIOMMUOps *ops, void *opaque);
+
pcibus_t pci_bar_address(PCIDevice *d,
int reg, uint8_t type, pcibus_t size);
diff --git a/include/hw/pci/pci_bus.h b/include/hw/pci/pci_bus.h
index 2261312546..c738446788 100644
--- a/include/hw/pci/pci_bus.h
+++ b/include/hw/pci/pci_bus.h
@@ -35,6 +35,7 @@ struct PCIBus {
enum PCIBusFlags flags;
const PCIIOMMUOps *iommu_ops;
void *iommu_opaque;
+ bool iommu_per_bus;
uint8_t devfn_min;
uint32_t slot_reserved_mask;
pci_set_irq_fn set_irq;

View File

@ -1,215 +0,0 @@
From fa04930d828fa4de32a5ecae907fdbf316d88509 Mon Sep 17 00:00:00 2001
From: Shameer Kolothum <skolothumtho@nvidia.com>
Date: Fri, 29 Aug 2025 09:25:29 +0100
Subject: [PATCH] hw/arm/virt: Allow user-creatable SMMUv3 dev instantiation
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
RH-Author: Eric Auger <eric.auger@redhat.com>
RH-MergeRequest: 423: hw/arm/virt: Add support for user creatable SMMUv3 device
RH-Jira: RHEL-73800
RH-Acked-by: Gavin Shan <gshan@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Acked-by: Sebastian Ott <sebott@redhat.com>
RH-Acked-by: Donald Dutile <None>
RH-Commit: [7/11] 8f4a03c34d5c699023b3916f4919caf669f7a87c (eauger1/centos-qemu-kvm)
Allow cold-plugging of an SMMUv3 device on the virt machine when no
global (legacy) SMMUv3 is present or when a virtio-iommu is specified.
This user-created SMMUv3 device is tied to a specific PCI bus provided
by the user, so ensure the IOMMU ops are configured accordingly.
Due to current limitations in QEMUs device tree support, specifically
its inability to properly present pxb-pcie based root complexes and
their devices, the device tree support for the new SMMUv3 device is
limited to cases where it is attached to the default pcie.0 root complex.
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Tested-by: Nathan Chen <nathanc@nvidia.com>
Tested-by: Eric Auger <eric.auger@redhat.com>
Tested-by: Nicolin Chen <nicolinc@nvidia.com>
Signed-off-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
Signed-off-by: Shameer Kolothum <skolothumtho@nvidia.com>
Reviewed-by: Donald Dutile <ddutile@redhat.com>
Reviewed-by: Nicolin Chen <nicolinc@nvidia.com>
Message-id: 20250829082543.7680-8-skolothumtho@nvidia.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
(cherry picked from commit 66d2f665e163cf1afccd171e3c16f8d3acb3d94a)
Signed-off-by: Eric Auger <eric.auger@redhat.com>
Patch-name: kvm-hw-arm-virt-Allow-user-creatable-SMMUv3-dev-instanti.patch
Patch-id: 47
Patch-present-in-specfile: True
---
hw/arm/smmu-common.c | 8 +++++-
hw/arm/smmuv3.c | 2 ++
hw/arm/virt.c | 51 ++++++++++++++++++++++++++++++++++++
hw/core/sysbus-fdt.c | 3 +++
include/hw/arm/smmu-common.h | 1 +
5 files changed, 64 insertions(+), 1 deletion(-)
diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
index 7f64ea48d0..62a7612184 100644
--- a/hw/arm/smmu-common.c
+++ b/hw/arm/smmu-common.c
@@ -961,7 +961,12 @@ static void smmu_base_realize(DeviceState *dev, Error **errp)
goto out_err;
}
}
- pci_setup_iommu(pci_bus, &smmu_ops, s);
+
+ if (s->smmu_per_bus) {
+ pci_setup_iommu_per_bus(pci_bus, &smmu_ops, s);
+ } else {
+ pci_setup_iommu(pci_bus, &smmu_ops, s);
+ }
return;
}
out_err:
@@ -986,6 +991,7 @@ static void smmu_base_reset_exit(Object *obj, ResetType type)
static const Property smmu_dev_properties[] = {
DEFINE_PROP_UINT8("bus_num", SMMUState, bus_num, 0),
+ DEFINE_PROP_BOOL("smmu_per_bus", SMMUState, smmu_per_bus, false),
DEFINE_PROP_LINK("primary-bus", SMMUState, primary_bus,
TYPE_PCI_BUS, PCIBus *),
};
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index ab67972353..bcf8af8dc7 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -1996,6 +1996,8 @@ static void smmuv3_class_init(ObjectClass *klass, const void *data)
device_class_set_parent_realize(dc, smmu_realize,
&c->parent_realize);
device_class_set_props(dc, smmuv3_properties);
+ dc->hotpluggable = false;
+ dc->user_creatable = true;
}
static int smmuv3_notify_flag_changed(IOMMUMemoryRegion *iommu,
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index b435efafe1..e8e64fe7fe 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -56,6 +56,7 @@
#include "qemu/cutils.h"
#include "qemu/error-report.h"
#include "qemu/module.h"
+#include "hw/pci/pci_bus.h"
#include "hw/pci-host/gpex.h"
#include "hw/pci-bridge/pci_expander_bridge.h"
#include "hw/virtio/virtio-pci.h"
@@ -1510,6 +1511,29 @@ static void create_smmuv3_dt_bindings(const VirtMachineState *vms, hwaddr base,
g_free(node);
}
+static void create_smmuv3_dev_dtb(VirtMachineState *vms,
+ DeviceState *dev, PCIBus *bus)
+{
+ PlatformBusDevice *pbus = PLATFORM_BUS_DEVICE(vms->platform_bus_dev);
+ SysBusDevice *sbdev = SYS_BUS_DEVICE(dev);
+ int irq = platform_bus_get_irqn(pbus, sbdev, 0);
+ hwaddr base = platform_bus_get_mmio_addr(pbus, sbdev, 0);
+ MachineState *ms = MACHINE(vms);
+
+ if (!(vms->bootinfo.firmware_loaded && virt_is_acpi_enabled(vms)) &&
+ strcmp("pcie.0", bus->qbus.name)) {
+ warn_report("SMMUv3 device only supported with pcie.0 for DT");
+ return;
+ }
+ base += vms->memmap[VIRT_PLATFORM_BUS].base;
+ irq += vms->irqmap[VIRT_PLATFORM_BUS];
+
+ vms->iommu_phandle = qemu_fdt_alloc_phandle(ms->fdt);
+ create_smmuv3_dt_bindings(vms, base, SMMU_IO_LEN, irq);
+ qemu_fdt_setprop_cells(ms->fdt, vms->pciehb_nodename, "iommu-map",
+ 0x0, vms->iommu_phandle, 0x0, 0x10000);
+}
+
static void create_smmu(const VirtMachineState *vms,
PCIBus *bus)
{
@@ -3057,6 +3081,16 @@ static void virt_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev,
qlist_append_str(reserved_regions, resv_prop_str);
qdev_prop_set_array(dev, "reserved-regions", reserved_regions);
g_free(resv_prop_str);
+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_ARM_SMMUV3)) {
+ if (vms->legacy_smmuv3_present || vms->iommu == VIRT_IOMMU_VIRTIO) {
+ error_setg(errp, "virt machine already has %s set. "
+ "Doesn't support incompatible iommus",
+ (vms->legacy_smmuv3_present) ?
+ "iommu=smmuv3" : "virtio-iommu");
+ } else if (vms->iommu == VIRT_IOMMU_NONE) {
+ /* The new SMMUv3 device is specific to the PCI bus */
+ object_property_set_bool(OBJECT(dev), "smmu_per_bus", true, NULL);
+ }
}
}
@@ -3080,6 +3114,22 @@ static void virt_machine_device_plug_cb(HotplugHandler *hotplug_dev,
virtio_md_pci_plug(VIRTIO_MD_PCI(dev), MACHINE(hotplug_dev), errp);
}
+ if (object_dynamic_cast(OBJECT(dev), TYPE_ARM_SMMUV3)) {
+ if (!vms->legacy_smmuv3_present && vms->platform_bus_dev) {
+ PCIBus *bus;
+
+ bus = PCI_BUS(object_property_get_link(OBJECT(dev), "primary-bus",
+ &error_abort));
+ if (pci_bus_bypass_iommu(bus)) {
+ error_setg(errp, "Bypass option cannot be set for SMMUv3 "
+ "associated PCIe RC");
+ return;
+ }
+
+ create_smmuv3_dev_dtb(vms, dev, bus);
+ }
+ }
+
if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_IOMMU_PCI)) {
PCIDevice *pdev = PCI_DEVICE(dev);
@@ -3286,6 +3336,7 @@ static void virt_machine_class_init(ObjectClass *oc, const void *data)
#endif
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_RAMFB_DEVICE);
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_UEFI_VARS_SYSBUS);
+ machine_class_allow_dynamic_sysbus_dev(mc, TYPE_ARM_SMMUV3);
#ifdef CONFIG_TPM
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_TPM_TIS_SYSBUS);
#endif
diff --git a/hw/core/sysbus-fdt.c b/hw/core/sysbus-fdt.c
index 1e1966813f..673e083d31 100644
--- a/hw/core/sysbus-fdt.c
+++ b/hw/core/sysbus-fdt.c
@@ -31,6 +31,7 @@
#include "qemu/error-report.h"
#include "system/device_tree.h"
#include "system/tpm.h"
+#include "hw/arm/smmuv3.h"
#include "hw/platform-bus.h"
#include "hw/vfio/vfio-platform.h"
#include "hw/vfio/vfio-calxeda-xgmac.h"
@@ -518,6 +519,8 @@ static const BindingEntry bindings[] = {
#ifdef CONFIG_TPM
TYPE_BINDING(TYPE_TPM_TIS_SYSBUS, add_tpm_tis_fdt_node),
#endif
+ /* No generic DT support for smmuv3 dev. Support added for arm virt only */
+ TYPE_BINDING(TYPE_ARM_SMMUV3, no_fdt_node),
TYPE_BINDING(TYPE_RAMFB_DEVICE, no_fdt_node),
TYPE_BINDING(TYPE_UEFI_VARS_SYSBUS, add_uefi_vars_node),
TYPE_BINDING("", NULL), /* last element */
diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
index e5e2d09294..80d0fecfde 100644
--- a/include/hw/arm/smmu-common.h
+++ b/include/hw/arm/smmu-common.h
@@ -161,6 +161,7 @@ struct SMMUState {
QLIST_HEAD(, SMMUDevice) devices_with_notifiers;
uint8_t bus_num;
PCIBus *primary_bus;
+ bool smmu_per_bus; /* SMMU is specific to the primary_bus */
};
struct SMMUBaseClass {

View File

@ -1,54 +0,0 @@
From b6fd153e384990dabf068c5c893140d88edcaa40 Mon Sep 17 00:00:00 2001
From: Shameer Kolothum <skolothumtho@nvidia.com>
Date: Fri, 29 Aug 2025 09:25:30 +0100
Subject: [PATCH] qemu-options.hx: Document the arm-smmuv3 device
RH-Author: Eric Auger <eric.auger@redhat.com>
RH-MergeRequest: 423: hw/arm/virt: Add support for user creatable SMMUv3 device
RH-Jira: RHEL-73800
RH-Acked-by: Gavin Shan <gshan@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Acked-by: Sebastian Ott <sebott@redhat.com>
RH-Acked-by: Donald Dutile <None>
RH-Commit: [8/11] 775310b784fd7631a58e8bab1e8fcc36973fceca (eauger1/centos-qemu-kvm)
Now that arm,virt can have user-creatable smmuv3 devices, document it.
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Tested-by: Eric Auger <eric.auger@redhat.com>
Tested-by: Nicolin Chen <nicolinc@nvidia.com>
Signed-off-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
Signed-off-by: Shameer Kolothum <skolothumtho@nvidia.com>
Reviewed-by: Donald Dutile <ddutile@redhat.com>
Reviewed-by: Nicolin Chen <nicolinc@nvidia.com>
Message-id: 20250829082543.7680-9-skolothumtho@nvidia.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
(cherry picked from commit 73d3d0187bc6b482d8b15116edce1475c7975b89)
Signed-off-by: Eric Auger <eric.auger@redhat.com>
Patch-name: kvm-qemu-options.hx-Document-the-arm-smmuv3-device.patch
Patch-id: 48
Patch-present-in-specfile: True
---
qemu-options.hx | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/qemu-options.hx b/qemu-options.hx
index 3837456a61..5f146c1860 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1231,6 +1231,13 @@ SRST
``aw-bits=val`` (val between 32 and 64, default depends on machine)
This decides the address width of the IOVA address space.
+``-device arm-smmuv3,primary-bus=id``
+ This is only supported by ``-machine virt`` (ARM).
+
+ ``primary-bus=id``
+ Accepts either the default root complex (pcie.0) or a
+ pxb-pcie based root complex.
+
ERST
DEF("name", HAS_ARG, QEMU_OPTION_name,

View File

@ -1,67 +0,0 @@
From b1a804dc528b237d127a99ca6bc25f352e542fc4 Mon Sep 17 00:00:00 2001
From: Shameer Kolothum <skolothumtho@nvidia.com>
Date: Fri, 29 Aug 2025 09:25:31 +0100
Subject: [PATCH] bios-tables-test: Allow for smmuv3 test data.
RH-Author: Eric Auger <eric.auger@redhat.com>
RH-MergeRequest: 423: hw/arm/virt: Add support for user creatable SMMUv3 device
RH-Jira: RHEL-73800
RH-Acked-by: Gavin Shan <gshan@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Acked-by: Sebastian Ott <sebott@redhat.com>
RH-Acked-by: Donald Dutile <None>
RH-Commit: [9/11] cf98e2e7589b794775c1d9c4f564e3cd536b886e (eauger1/centos-qemu-kvm)
The tests to be added exercise both legacy(iommu=smmuv3) and new
-device arm-smmuv3,.. cases.
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Tested-by: Eric Auger <eric.auger@redhat.com>
Tested-by: Nicolin Chen <nicolinc@nvidia.com>
Signed-off-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
Signed-off-by: Shameer Kolothum <skolothumtho@nvidia.com>
Reviewed-by: Donald Dutile <ddutile@redhat.com>
Reviewed-by: Nicolin Chen <nicolinc@nvidia.com>
Message-id: 20250829082543.7680-10-skolothumtho@nvidia.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
(cherry picked from commit c69520c13d6ea45a69a7a49361806fa05b19046d)
Signed-off-by: Eric Auger <eric.auger@redhat.com>
Patch-name: kvm-bios-tables-test-Allow-for-smmuv3-test-data.patch
Patch-id: 49
Patch-present-in-specfile: True
---
tests/data/acpi/aarch64/virt/DSDT.smmuv3-dev | 0
tests/data/acpi/aarch64/virt/DSDT.smmuv3-legacy | 0
tests/data/acpi/aarch64/virt/IORT.smmuv3-dev | 0
tests/data/acpi/aarch64/virt/IORT.smmuv3-legacy | 0
tests/qtest/bios-tables-test-allowed-diff.h | 4 ++++
5 files changed, 4 insertions(+)
create mode 100644 tests/data/acpi/aarch64/virt/DSDT.smmuv3-dev
create mode 100644 tests/data/acpi/aarch64/virt/DSDT.smmuv3-legacy
create mode 100644 tests/data/acpi/aarch64/virt/IORT.smmuv3-dev
create mode 100644 tests/data/acpi/aarch64/virt/IORT.smmuv3-legacy
diff --git a/tests/data/acpi/aarch64/virt/DSDT.smmuv3-dev b/tests/data/acpi/aarch64/virt/DSDT.smmuv3-dev
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/tests/data/acpi/aarch64/virt/DSDT.smmuv3-legacy b/tests/data/acpi/aarch64/virt/DSDT.smmuv3-legacy
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/tests/data/acpi/aarch64/virt/IORT.smmuv3-dev b/tests/data/acpi/aarch64/virt/IORT.smmuv3-dev
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/tests/data/acpi/aarch64/virt/IORT.smmuv3-legacy b/tests/data/acpi/aarch64/virt/IORT.smmuv3-legacy
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h
index dfb8523c8b..2e3e3ccdce 100644
--- a/tests/qtest/bios-tables-test-allowed-diff.h
+++ b/tests/qtest/bios-tables-test-allowed-diff.h
@@ -1 +1,5 @@
/* List of comma-separated changed AML files to ignore */
+"tests/data/acpi/aarch64/virt/DSDT.smmuv3-legacy",
+"tests/data/acpi/aarch64/virt/DSDT.smmuv3-dev",
+"tests/data/acpi/aarch64/virt/IORT.smmuv3-legacy",
+"tests/data/acpi/aarch64/virt/IORT.smmuv3-dev",

View File

@ -1,161 +0,0 @@
From bdd38feb47a92951cd32a33e8fcd8626aa5ff5e0 Mon Sep 17 00:00:00 2001
From: Shameer Kolothum <skolothumtho@nvidia.com>
Date: Fri, 29 Aug 2025 09:25:32 +0100
Subject: [PATCH] qtest/bios-tables-test: Add tests for legacy smmuv3 and
smmuv3 device
RH-Author: Eric Auger <eric.auger@redhat.com>
RH-MergeRequest: 423: hw/arm/virt: Add support for user creatable SMMUv3 device
RH-Jira: RHEL-73800
RH-Acked-by: Gavin Shan <gshan@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Acked-by: Sebastian Ott <sebott@redhat.com>
RH-Acked-by: Donald Dutile <None>
RH-Commit: [10/11] 101ed34313636fdc11f7fbdedbe2f91671b84c4b (eauger1/centos-qemu-kvm)
For the legacy SMMUv3 test, the setup includes three PCIe Root Complexes,
one of which has bypass_iommu enabled. The generated IORT table contains
a single SMMUv3 node, a Root Complex(RC) node and 1 ITS node.
RC node features 4 ID mappings, of which 2 points to SMMU node and the
remaining ones points to ITS.
pcie.0 -> {SMMU0} -> {ITS}
{RC} pcie.1 -> {SMMU0} -> {ITS}
pcie.2 -> {ITS}
[all other ids] -> {ITS}
For the -device arm-smmuv3,... test, the configuration also includes three
Root Complexes, with two connected to separate SMMUv3 devices.
The resulting IORT table contains 1 RC node, 2 SMMU nodes and 1 ITS node.
RC node features 4 ID mappings. 2 of them target the 2 SMMU nodes while
the others targets the ITS.
pcie.0 -> {SMMU0} -> {ITS}
{RC} pcie.1 -> {SMMU1} -> {ITS}
pcie.2 -> {ITS}
[all other ids] -> {ITS}
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Tested-by: Eric Auger <eric.auger@redhat.com>
Tested-by: Nicolin Chen <nicolinc@nvidia.com>
Signed-off-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
Signed-off-by: Shameer Kolothum <skolothumtho@nvidia.com>
Reviewed-by: Donald Dutile <ddutile@redhat.com>
Reviewed-by: Nicolin Chen <nicolinc@nvidia.com>
Message-id: 20250829082543.7680-11-skolothumtho@nvidia.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
(cherry picked from commit 3f8cd046c151c471d9a34181320f4a7d3f72b32a)
Signed-off-by: Eric Auger <eric.auger@redhat.com>
Patch-name: kvm-qtest-bios-tables-test-Add-tests-for-legacy-smmuv3-a.patch
Patch-id: 50
Patch-present-in-specfile: True
---
tests/qtest/bios-tables-test.c | 86 ++++++++++++++++++++++++++++++++++
1 file changed, 86 insertions(+)
diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c
index 386196edc8..a384aac1be 100644
--- a/tests/qtest/bios-tables-test.c
+++ b/tests/qtest/bios-tables-test.c
@@ -2343,6 +2343,86 @@ static void test_acpi_aarch64_virt_viot(void)
free_test_data(&data);
}
+static void test_acpi_aarch64_virt_smmuv3_legacy(void)
+{
+ test_data data = {
+ .machine = "virt",
+ .arch = "aarch64",
+ .tcg_only = true,
+ .uefi_fl1 = "pc-bios/edk2-aarch64-code.fd",
+ .uefi_fl2 = "pc-bios/edk2-arm-vars.fd",
+ .ram_start = 0x40000000ULL,
+ .scan_len = 128ULL * MiB,
+ };
+
+ /*
+ * cdrom is plugged into scsi controller to avoid conflict
+ * with pxb-pcie. See comments in test_acpi_aarch64_virt_tcg_pxb() for
+ * details.
+ *
+ * The setup includes three PCIe root complexes, one of which has
+ * bypass_iommu enabled. The generated IORT table contains a single
+ * SMMUv3 node and a Root Complex node with three ID mappings. Two
+ * of the ID mappings have output references pointing to the SMMUv3
+ * node and the remaining one points to ITS.
+ */
+ data.variant = ".smmuv3-legacy";
+ test_acpi_one(" -device pcie-root-port,chassis=1,id=pci.1"
+ " -device virtio-scsi-pci,id=scsi0,bus=pci.1"
+ " -drive file="
+ "tests/data/uefi-boot-images/bios-tables-test.aarch64.iso.qcow2,"
+ "if=none,media=cdrom,id=drive-scsi0-0-0-1,readonly=on"
+ " -device scsi-cd,bus=scsi0.0,scsi-id=0,"
+ "drive=drive-scsi0-0-0-1,id=scsi0-0-0-1,bootindex=1"
+ " -cpu cortex-a57"
+ " -M iommu=smmuv3"
+ " -device pxb-pcie,id=pcie.1,bus=pcie.0,bus_nr=0x10"
+ " -device pxb-pcie,id=pcie.2,bus=pcie.0,bus_nr=0x20,bypass_iommu=on",
+ &data);
+ free_test_data(&data);
+}
+
+static void test_acpi_aarch64_virt_smmuv3_dev(void)
+{
+ test_data data = {
+ .machine = "virt",
+ .arch = "aarch64",
+ .tcg_only = true,
+ .uefi_fl1 = "pc-bios/edk2-aarch64-code.fd",
+ .uefi_fl2 = "pc-bios/edk2-arm-vars.fd",
+ .ram_start = 0x40000000ULL,
+ .scan_len = 128ULL * MiB,
+ };
+
+ /*
+ * cdrom is plugged into scsi controller to avoid conflict
+ * with pxb-pcie. See comments in test_acpi_aarch64_virt_tcg_pxb()
+ * for details.
+ *
+ * The setup includes three PCie root complexes, two of which are
+ * connected to separate SMMUv3 devices. The resulting IORT table
+ * contains two SMMUv3 nodes and a Root Complex node with ID mappings
+ * of which two of the ID mappings have output references pointing
+ * to two different SMMUv3 nodes and the remaining ones pointing to
+ * ITS.
+ */
+ data.variant = ".smmuv3-dev";
+ test_acpi_one(" -device pcie-root-port,chassis=1,id=pci.1"
+ " -device virtio-scsi-pci,id=scsi0,bus=pci.1"
+ " -drive file="
+ "tests/data/uefi-boot-images/bios-tables-test.aarch64.iso.qcow2,"
+ "if=none,media=cdrom,id=drive-scsi0-0-0-1,readonly=on"
+ " -device scsi-cd,bus=scsi0.0,scsi-id=0,"
+ "drive=drive-scsi0-0-0-1,id=scsi0-0-0-1,bootindex=1"
+ " -cpu cortex-a57"
+ " -device arm-smmuv3,primary-bus=pcie.0,id=smmuv3.0"
+ " -device pxb-pcie,id=pcie.1,bus=pcie.0,bus_nr=0x10"
+ " -device arm-smmuv3,primary-bus=pcie.1,id=smmuv3.1"
+ " -device pxb-pcie,id=pcie.2,bus=pcie.0,bus_nr=0x20",
+ &data);
+ free_test_data(&data);
+}
+
#ifndef _WIN32
# define DEV_NULL "/dev/null"
#else
@@ -2776,6 +2856,12 @@ int main(int argc, char *argv[])
if (qtest_has_device("virtio-iommu-pci")) {
qtest_add_func("acpi/virt/viot", test_acpi_aarch64_virt_viot);
}
+ qtest_add_func("acpi/virt/smmuv3-legacy",
+ test_acpi_aarch64_virt_smmuv3_legacy);
+ if (qtest_has_device("arm-smmuv3")) {
+ qtest_add_func("acpi/virt/smmuv3-dev",
+ test_acpi_aarch64_virt_smmuv3_dev);
+ }
}
#if 0 /* Disabled for Red Hat Enterprise Linux */
} else if (strcmp(arch, "riscv64") == 0) {

View File

@ -1,295 +0,0 @@
From be2f82165c36208d01117404382ad0fee35e4ce0 Mon Sep 17 00:00:00 2001
From: Shameer Kolothum <skolothumtho@nvidia.com>
Date: Fri, 29 Aug 2025 09:25:33 +0100
Subject: [PATCH] qtest/bios-tables-test: Update tables for smmuv3 tests
RH-Author: Eric Auger <eric.auger@redhat.com>
RH-MergeRequest: 423: hw/arm/virt: Add support for user creatable SMMUv3 device
RH-Jira: RHEL-73800
RH-Acked-by: Gavin Shan <gshan@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Acked-by: Sebastian Ott <sebott@redhat.com>
RH-Acked-by: Donald Dutile <None>
RH-Commit: [11/11] 88cb1daec4e92b759f12a96daacd46fc4656eacd (eauger1/centos-qemu-kvm)
For the legacy smmuv3 test case, generated IORT has a single SMMUv3 node,
a Root Complex(RC) node and 1 ITS node.
RC node features 4 ID mappings, of which 2 points to SMMU node and the
remaining ones points to ITS.
pcie.0 -> {SMMU0} -> {ITS}
{RC} pcie.1 -> {SMMU0} -> {ITS}
pcie.2 -> {ITS}
[all other ids] -> {ITS}
...
[030h 0048 1] Type : 00
[031h 0049 2] Length : 0018
[033h 0051 1] Revision : 01
[034h 0052 4] Identifier : 00000000
[038h 0056 4] Mapping Count : 00000000
[03Ch 0060 4] Mapping Offset : 00000000
[040h 0064 4] ItsCount : 00000001
[044h 0068 4] Identifiers : 00000000
[048h 0072 1] Type : 04
[049h 0073 2] Length : 0058
[04Bh 0075 1] Revision : 04
[04Ch 0076 4] Identifier : 00000001
[050h 0080 4] Mapping Count : 00000001
[054h 0084 4] Mapping Offset : 00000044
[058h 0088 8] Base Address : 0000000009050000
[060h 0096 4] Flags (decoded below) : 00000001
COHACC Override : 1
HTTU Override : 0
Proximity Domain Valid : 0
[064h 0100 4] Reserved : 00000000
[068h 0104 8] VATOS Address : 0000000000000000
[070h 0112 4] Model : 00000000
[074h 0116 4] Event GSIV : 0000006A
[078h 0120 4] PRI GSIV : 0000006B
[07Ch 0124 4] GERR GSIV : 0000006D
[080h 0128 4] Sync GSIV : 0000006C
[084h 0132 4] Proximity Domain : 00000000
[088h 0136 4] Device ID Mapping Index : 00000000
[08Ch 0140 4] Input base : 00000000
[090h 0144 4] ID Count : 0000FFFF
[094h 0148 4] Output Base : 00000000
[098h 0152 4] Output Reference : 00000030
[09Ch 0156 4] Flags (decoded below) : 00000000
Single Mapping : 0
[0A0h 0160 1] Type : 02
[0A1h 0161 2] Length : 0074
[0A3h 0163 1] Revision : 03
[0A4h 0164 4] Identifier : 00000002
[0A8h 0168 4] Mapping Count : 00000004
[0ACh 0172 4] Mapping Offset : 00000024
[0B0h 0176 8] Memory Properties : [IORT Memory Access Properties]
[0B0h 0176 4] Cache Coherency : 00000001
[0B4h 0180 1] Hints (decoded below) : 00
Transient : 0
Write Allocate : 0
Read Allocate : 0
Override : 0
[0B5h 0181 2] Reserved : 0000
[0B7h 0183 1] Memory Flags (decoded below) : 03
Coherency : 1
Device Attribute : 1
[0B8h 0184 4] ATS Attribute : 00000000
[0BCh 0188 4] PCI Segment Number : 00000000
[0C0h 0192 1] Memory Size Limit : 40
[0C1h 0193 2] PASID Capabilities : 0000
[0C3h 0195 1] Reserved : 00
[0C4h 0196 4] Input base : 00000000
[0C8h 0200 4] ID Count : 000001FF
[0CCh 0204 4] Output Base : 00000000
[0D0h 0208 4] Output Reference : 00000048
[0D4h 0212 4] Flags (decoded below) : 00000000
Single Mapping : 0
[0D8h 0216 4] Input base : 00001000
[0DCh 0220 4] ID Count : 000000FF
[0E0h 0224 4] Output Base : 00001000
[0E4h 0228 4] Output Reference : 00000048
[0E8h 0232 4] Flags (decoded below) : 00000000
Single Mapping : 0
[0ECh 0236 4] Input base : 00000200
[0F0h 0240 4] ID Count : 00000DFF
[0F4h 0244 4] Output Base : 00000200
[0F8h 0248 4] Output Reference : 00000030
[0FCh 0252 4] Flags (decoded below) : 00000000
Single Mapping : 0
[100h 0256 4] Input base : 00001100
[104h 0260 4] ID Count : 0000EEFF
[108h 0264 4] Output Base : 00001100
[10Ch 0268 4] Output Reference : 00000030
[110h 0272 4] Flags (decoded below) : 00000000
Single Mapping : 0
For the smmuv3-dev test case, IORT has 2 SMMUV3 nodes,
1 RC node and 1 ITS node.
RC node features 4 ID mappings. 2 of them target the 2
SMMU nodes while the others targets the ITS.
pcie.0 -> {SMMU0} -> {ITS}
{RC} pcie.1 -> {SMMU1} -> {ITS}
pcie.2 -> {ITS}
[all other ids] -> {ITS}
...
[030h 0048 1] Type : 00
[031h 0049 2] Length : 0018
[033h 0051 1] Revision : 01
[034h 0052 4] Identifier : 00000000
[038h 0056 4] Mapping Count : 00000000
[03Ch 0060 4] Mapping Offset : 00000000
[040h 0064 4] ItsCount : 00000001
[044h 0068 4] Identifiers : 00000000
[048h 0072 1] Type : 04
[049h 0073 2] Length : 0058
[04Bh 0075 1] Revision : 04
[04Ch 0076 4] Identifier : 00000001
[050h 0080 4] Mapping Count : 00000001
[054h 0084 4] Mapping Offset : 00000044
[058h 0088 8] Base Address : 000000000C000000
[060h 0096 4] Flags (decoded below) : 00000001
COHACC Override : 1
HTTU Override : 0
Proximity Domain Valid : 0
[064h 0100 4] Reserved : 00000000
[068h 0104 8] VATOS Address : 0000000000000000
[070h 0112 4] Model : 00000000
[074h 0116 4] Event GSIV : 00000090
[078h 0120 4] PRI GSIV : 00000091
[07Ch 0124 4] GERR GSIV : 00000093
[080h 0128 4] Sync GSIV : 00000092
[084h 0132 4] Proximity Domain : 00000000
[088h 0136 4] Device ID Mapping Index : 00000000
[08Ch 0140 4] Input base : 00000000
[090h 0144 4] ID Count : 0000FFFF
[094h 0148 4] Output Base : 00000000
[098h 0152 4] Output Reference : 00000030
[09Ch 0156 4] Flags (decoded below) : 00000000
Single Mapping : 0
[0A0h 0160 1] Type : 04
[0A1h 0161 2] Length : 0058
[0A3h 0163 1] Revision : 04
[0A4h 0164 4] Identifier : 00000002
[0A8h 0168 4] Mapping Count : 00000001
[0ACh 0172 4] Mapping Offset : 00000044
[0B0h 0176 8] Base Address : 000000000C020000
[0B8h 0184 4] Flags (decoded below) : 00000001
COHACC Override : 1
HTTU Override : 0
Proximity Domain Valid : 0
[0BCh 0188 4] Reserved : 00000000
[0C0h 0192 8] VATOS Address : 0000000000000000
[0C8h 0200 4] Model : 00000000
[0CCh 0204 4] Event GSIV : 00000094
[0D0h 0208 4] PRI GSIV : 00000095
[0D4h 0212 4] GERR GSIV : 00000097
[0D8h 0216 4] Sync GSIV : 00000096
[0DCh 0220 4] Proximity Domain : 00000000
[0E0h 0224 4] Device ID Mapping Index : 00000000
[0E4h 0228 4] Input base : 00000000
[0E8h 0232 4] ID Count : 0000FFFF
[0ECh 0236 4] Output Base : 00000000
[0F0h 0240 4] Output Reference : 00000030
[0F4h 0244 4] Flags (decoded below) : 00000000
Single Mapping : 0
[0F8h 0248 1] Type : 02
[0F9h 0249 2] Length : 0074
[0FBh 0251 1] Revision : 03
[0FCh 0252 4] Identifier : 00000003
[100h 0256 4] Mapping Count : 00000004
[104h 0260 4] Mapping Offset : 00000024
[108h 0264 8] Memory Properties : [IORT Memory Access Properties]
[108h 0264 4] Cache Coherency : 00000001
[10Ch 0268 1] Hints (decoded below) : 00
Transient : 0
Write Allocate : 0
Read Allocate : 0
Override : 0
[10Dh 0269 2] Reserved : 0000
[10Fh 0271 1] Memory Flags (decoded below) : 03
Coherency : 1
Device Attribute : 1
[110h 0272 4] ATS Attribute : 00000000
[114h 0276 4] PCI Segment Number : 00000000
[118h 0280 1] Memory Size Limit : 40
[119h 0281 2] PASID Capabilities : 0000
[11Bh 0283 1] Reserved : 00
[11Ch 0284 4] Input base : 00000000
[120h 0288 4] ID Count : 000001FF
[124h 0292 4] Output Base : 00000000
[128h 0296 4] Output Reference : 00000048
[12Ch 0300 4] Flags (decoded below) : 00000000
Single Mapping : 0
[130h 0304 4] Input base : 00001000
[134h 0308 4] ID Count : 000000FF
[138h 0312 4] Output Base : 00001000
[13Ch 0316 4] Output Reference : 000000A0
[140h 0320 4] Flags (decoded below) : 00000000
Single Mapping : 0
[144h 0324 4] Input base : 00000200
[148h 0328 4] ID Count : 00000DFF
[14Ch 0332 4] Output Base : 00000200
[150h 0336 4] Output Reference : 00000030
[154h 0340 4] Flags (decoded below) : 00000000
Single Mapping : 0
[158h 0344 4] Input base : 00001100
[15Ch 0348 4] ID Count : 0000EEFF
[160h 0352 4] Output Base : 00001100
[164h 0356 4] Output Reference : 00000030
[168h 0360 4] Flags (decoded below) : 00000000
Single Mapping : 0
Note: DSDT changes are not described here as it is not impacted by the
way the SMMUv3 is instantiated.
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Tested-by: Eric Auger <eric.auger@redhat.com>
Tested-by: Nicolin Chen <nicolinc@nvidia.com>
Signed-off-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
Signed-off-by: Shameer Kolothum <skolothumtho@nvidia.com>
Reviewed-by: Donald Dutile <ddutile@redhat.com>
Reviewed-by: Nicolin Chen <nicolinc@nvidia.com>
Message-id: 20250829082543.7680-12-skolothumtho@nvidia.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
(cherry picked from commit d35146a6606cf6ebb4e24bb97dfc0330f074f6e3)
Signed-off-by: Eric Auger <eric.auger@redhat.com>
Patch-name: kvm-qtest-bios-tables-test-Update-tables-for-smmuv3-test.patch
Patch-id: 51
Patch-present-in-specfile: True
---
tests/data/acpi/aarch64/virt/DSDT.smmuv3-dev | Bin 0 -> 10230 bytes
tests/data/acpi/aarch64/virt/DSDT.smmuv3-legacy | Bin 0 -> 10230 bytes
tests/data/acpi/aarch64/virt/IORT.smmuv3-dev | Bin 0 -> 364 bytes
tests/data/acpi/aarch64/virt/IORT.smmuv3-legacy | Bin 0 -> 276 bytes
tests/qtest/bios-tables-test-allowed-diff.h | 4 ----
5 files changed, 4 deletions(-)
diff --git a/tests/data/acpi/aarch64/virt/DSDT.smmuv3-dev b/tests/data/acpi/aarch64/virt/DSDT.smmuv3-dev
index e69de29bb2..53d4c07f42 100644
Binary files a/tests/data/acpi/aarch64/virt/DSDT.smmuv3-dev and b/tests/data/acpi/aarch64/virt/DSDT.smmuv3-dev differ
diff --git a/tests/data/acpi/aarch64/virt/DSDT.smmuv3-legacy b/tests/data/acpi/aarch64/virt/DSDT.smmuv3-legacy
index e69de29bb2..53d4c07f42 100644
Binary files a/tests/data/acpi/aarch64/virt/DSDT.smmuv3-legacy and b/tests/data/acpi/aarch64/virt/DSDT.smmuv3-legacy differ
diff --git a/tests/data/acpi/aarch64/virt/IORT.smmuv3-dev b/tests/data/acpi/aarch64/virt/IORT.smmuv3-dev
index e69de29bb2..67be268f62 100644
Binary files a/tests/data/acpi/aarch64/virt/IORT.smmuv3-dev and b/tests/data/acpi/aarch64/virt/IORT.smmuv3-dev differ
diff --git a/tests/data/acpi/aarch64/virt/IORT.smmuv3-legacy b/tests/data/acpi/aarch64/virt/IORT.smmuv3-legacy
index e69de29bb2..41981a449f 100644
Binary files a/tests/data/acpi/aarch64/virt/IORT.smmuv3-legacy and b/tests/data/acpi/aarch64/virt/IORT.smmuv3-legacy differ
diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h
index 2e3e3ccdce..dfb8523c8b 100644
--- a/tests/qtest/bios-tables-test-allowed-diff.h
+++ b/tests/qtest/bios-tables-test-allowed-diff.h
@@ -1,5 +1 @@
/* List of comma-separated changed AML files to ignore */
-"tests/data/acpi/aarch64/virt/DSDT.smmuv3-legacy",
-"tests/data/acpi/aarch64/virt/DSDT.smmuv3-dev",
-"tests/data/acpi/aarch64/virt/IORT.smmuv3-legacy",
-"tests/data/acpi/aarch64/virt/IORT.smmuv3-dev",

View File

@ -1,31 +0,0 @@
From 010f0f393976a1422f16a7252d6fcd986671b8d7 Mon Sep 17 00:00:00 2001
From: Miroslav Rezanina <mrezanin@redhat.com>
Date: Fri, 14 Nov 2025 06:46:07 +0100
Subject: [PATCH] qtest: Do not run bios-tables-test on aarch64
We do several disruptive downstream only changes that make
bios-tables-test to fail. Disabling it for now.
This is done to enable fixing RHEL-126573 and RHEL-67323.
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
Patch-name: kvm-qtest-Do-not-run-bios-tables-test-on-aarch64.patch
Patch-id: 52
Patch-present-in-specfile: True
---
tests/qtest/meson.build | 1 -
1 file changed, 1 deletion(-)
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index ef44ffaf78..13b52ea41a 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -252,7 +252,6 @@ qtests_arm = \
# TODO: once aarch64 TCG is fixed on ARM 32 bit host, make bios-tables-test unconditional
qtests_aarch64 = \
- (cpu != 'arm' and unpack_edk2_blobs ? ['bios-tables-test'] : []) + \
(config_all_accel.has_key('CONFIG_TCG') and config_all_devices.has_key('CONFIG_TPM_TIS_SYSBUS') ? \
['tpm-tis-device-test', 'tpm-tis-device-swtpm-test'] : []) + \
(config_all_devices.has_key('CONFIG_XLNX_ZYNQMP_ARM') ? ['xlnx-can-test', 'fuzz-xlnx-dp-test'] : []) + \

View File

@ -1,126 +0,0 @@
From 1e83cccb197114db68fa625c40f396ee159bb3a2 Mon Sep 17 00:00:00 2001
From: Paolo Bonzini <pbonzini@redhat.com>
Date: Wed, 19 Nov 2025 12:51:32 +0100
Subject: [PATCH] ram-block-attributes: fix interaction with hugetlb memory
backends
RH-Author: Paolo Bonzini <pbonzini@redhat.com>
RH-MergeRequest: 426: Fix hugetlb memory backends in confidential VMs
RH-Jira: RHEL-126708
RH-Acked-by: Bandan Das <bdas@redhat.com>
RH-Acked-by: Eric Blake <eblake@redhat.com>
RH-Acked-by: Peter Xu <peterx@redhat.com>
RH-Commit: [1/2] 050a6c78989db4ba3111fb903647270c7ab12e53 (bonzini/qemu-kvm-centos)
JIRA: https://issues.redhat.com/browse/RHEL-126708
Currently, CoCo VMs can perform conversion at the base page granularity,
which is the granularity that has to be tracked. In relevant setups, the
target page size is assumed to be equal to the host page size, thus
fixing the block size to the host page size.
However, since private memory and shared memory have different backend
at present, users can specify shared memory with a hugetlbfs backend
while private memory with guest_memfd backend only supports 4K page
size. In this scenario, ram_block->page_size is different from the host
page size which will trigger an assertion when retrieving the block
size.
To address this, return the host page size directly to relax the
restriction. This changes fixes a regression of using hugetlbfs backend
for shared memory within CoCo VMs, with or without VFIO devices' presence.
Acked-by: David Hildenbrand <david@redhat.com>
Tested-by: Farrah Chen <farrah.chen@intel.com>
Signed-off-by: Chenyi Qiang <chenyi.qiang@intel.com>
Link: https://lore.kernel.org/r/20251023095526.48365-2-chenyi.qiang@intel.com
[peterx: fix subject, per david]
Cc: qemu-stable <qemu-stable@nongnu.org>
Signed-off-by: Peter Xu <peterx@redhat.com>
(cherry picked from commit 8922a758b29251d9009ec509e7f580b76509ab3d)
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Patch-name: kvm-ram-block-attributes-fix-interaction-with-hugetlb-me.patch
Patch-id: 53
Patch-present-in-specfile: True
---
system/ram-block-attributes.c | 18 ++++++++----------
1 file changed, 8 insertions(+), 10 deletions(-)
diff --git a/system/ram-block-attributes.c b/system/ram-block-attributes.c
index 68e8a02703..a7579de5b4 100644
--- a/system/ram-block-attributes.c
+++ b/system/ram-block-attributes.c
@@ -22,16 +22,14 @@ OBJECT_DEFINE_SIMPLE_TYPE_WITH_INTERFACES(RamBlockAttributes,
{ })
static size_t
-ram_block_attributes_get_block_size(const RamBlockAttributes *attr)
+ram_block_attributes_get_block_size(void)
{
/*
* Because page conversion could be manipulated in the size of at least 4K
* or 4K aligned, Use the host page size as the granularity to track the
* memory attribute.
*/
- g_assert(attr && attr->ram_block);
- g_assert(attr->ram_block->page_size == qemu_real_host_page_size());
- return attr->ram_block->page_size;
+ return qemu_real_host_page_size();
}
@@ -40,7 +38,7 @@ ram_block_attributes_rdm_is_populated(const RamDiscardManager *rdm,
const MemoryRegionSection *section)
{
const RamBlockAttributes *attr = RAM_BLOCK_ATTRIBUTES(rdm);
- const size_t block_size = ram_block_attributes_get_block_size(attr);
+ const size_t block_size = ram_block_attributes_get_block_size();
const uint64_t first_bit = section->offset_within_region / block_size;
const uint64_t last_bit =
first_bit + int128_get64(section->size) / block_size - 1;
@@ -81,7 +79,7 @@ ram_block_attributes_for_each_populated_section(const RamBlockAttributes *attr,
{
unsigned long first_bit, last_bit;
uint64_t offset, size;
- const size_t block_size = ram_block_attributes_get_block_size(attr);
+ const size_t block_size = ram_block_attributes_get_block_size();
int ret = 0;
first_bit = section->offset_within_region / block_size;
@@ -122,7 +120,7 @@ ram_block_attributes_for_each_discarded_section(const RamBlockAttributes *attr,
{
unsigned long first_bit, last_bit;
uint64_t offset, size;
- const size_t block_size = ram_block_attributes_get_block_size(attr);
+ const size_t block_size = ram_block_attributes_get_block_size();
int ret = 0;
first_bit = section->offset_within_region / block_size;
@@ -163,7 +161,7 @@ ram_block_attributes_rdm_get_min_granularity(const RamDiscardManager *rdm,
const RamBlockAttributes *attr = RAM_BLOCK_ATTRIBUTES(rdm);
g_assert(mr == attr->ram_block->mr);
- return ram_block_attributes_get_block_size(attr);
+ return ram_block_attributes_get_block_size();
}
static void
@@ -265,7 +263,7 @@ ram_block_attributes_is_valid_range(RamBlockAttributes *attr, uint64_t offset,
g_assert(mr);
uint64_t region_size = memory_region_size(mr);
- const size_t block_size = ram_block_attributes_get_block_size(attr);
+ const size_t block_size = ram_block_attributes_get_block_size();
if (!QEMU_IS_ALIGNED(offset, block_size) ||
!QEMU_IS_ALIGNED(size, block_size)) {
@@ -322,7 +320,7 @@ int ram_block_attributes_state_change(RamBlockAttributes *attr,
uint64_t offset, uint64_t size,
bool to_discard)
{
- const size_t block_size = ram_block_attributes_get_block_size(attr);
+ const size_t block_size = ram_block_attributes_get_block_size();
const unsigned long first_bit = offset / block_size;
const unsigned long nbits = size / block_size;
const unsigned long last_bit = first_bit + nbits - 1;

View File

@ -1,47 +0,0 @@
From 5752a9e1aeb36ba0819cce747a15ec74eb8b8d98 Mon Sep 17 00:00:00 2001
From: Paolo Bonzini <pbonzini@redhat.com>
Date: Wed, 19 Nov 2025 12:51:32 +0100
Subject: [PATCH] ram-block-attributes: Unify the retrieval of the block size
RH-Author: Paolo Bonzini <pbonzini@redhat.com>
RH-MergeRequest: 426: Fix hugetlb memory backends in confidential VMs
RH-Jira: RHEL-126708
RH-Acked-by: Bandan Das <bdas@redhat.com>
RH-Acked-by: Eric Blake <eblake@redhat.com>
RH-Acked-by: Peter Xu <peterx@redhat.com>
RH-Commit: [2/2] 0d6f2045a97f04348c4d07ef331e42f47eaba160 (bonzini/qemu-kvm-centos)
JIRA: https://issues.redhat.com/browse/RHEL-126708
There's an existing helper function designed to obtain the block size.
Modify ram_block_attribute_create() to use this function for
consistency.
Tested-by: Farrah Chen <farrah.chen@intel.com>
Signed-off-by: Chenyi Qiang <chenyi.qiang@intel.com>
Link: https://lore.kernel.org/r/20251023095526.48365-3-chenyi.qiang@intel.com
[peterx: fix double spaces, per david]
Signed-off-by: Peter Xu <peterx@redhat.com>
(cherry picked from commit b2ceb87b1a210d91a29d525590eb164d1121b8a1)
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Patch-name: kvm-ram-block-attributes-Unify-the-retrieval-of-the-bloc.patch
Patch-id: 54
Patch-present-in-specfile: True
---
system/ram-block-attributes.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/system/ram-block-attributes.c b/system/ram-block-attributes.c
index a7579de5b4..fb7c5c2746 100644
--- a/system/ram-block-attributes.c
+++ b/system/ram-block-attributes.c
@@ -390,7 +390,7 @@ int ram_block_attributes_state_change(RamBlockAttributes *attr,
RamBlockAttributes *ram_block_attributes_create(RAMBlock *ram_block)
{
- const int block_size = qemu_real_host_page_size();
+ const int block_size = ram_block_attributes_get_block_size();
RamBlockAttributes *attr;
MemoryRegion *mr = ram_block->mr;

View File

@ -1,84 +0,0 @@
From cd7ee8d8043415d89a80a6e75c2d58afae270038 Mon Sep 17 00:00:00 2001
From: Thomas Huth <thuth@redhat.com>
Date: Tue, 18 Nov 2025 18:40:47 +0100
Subject: [PATCH] hw/s390x: Fix a possible crash with passed-through virtio
devices
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
RH-Author: Thomas Huth <thuth@redhat.com>
RH-MergeRequest: 427: s390x: Fix a possible crash with passed-through virtio devices
RH-Jira: RHEL-128085
RH-Acked-by: Cornelia Huck <cohuck@redhat.com>
RH-Acked-by: Cédric Le Goater <clg@redhat.com>
RH-Commit: [1/1] a368a65a46a8d85f7ae83cfb5af23b1a341ea9d4 (thuth/qemu-kvm-cs)
JIRA: https://issues.redhat.com/browse/RHEL-128085
Consider the following nested setup: An L1 host uses some virtio device
(e.g. virtio-keyboard) for the L2 guest, and this L2 guest passes this
device through to the L3 guest. Since the L3 guest sees a virtio device,
it might send virtio notifications to the QEMU in L2 for that device.
But since the QEMU in L2 defined this device as vfio-ccw, the function
handle_virtio_ccw_notify() cannot handle this and crashes: It calls
virtio_ccw_get_vdev() that casts sch->driver_data into a VirtioCcwDevice,
but since "sch" belongs to a vfio-ccw device, that driver_data rather
points to a CcwDevice instead. So as soon as QEMU tries to use some
VirtioCcwDevice specific data from that device, we've lost.
We must not take virtio notifications for such devices. Thus fix the
issue by adding a check to the handle_virtio_ccw_notify() handler to
refuse all devices that are not our own virtio devices. Like in the
other branches that detect wrong settings, we return -EINVAL from the
function, which will later be placed in GPR2 to inform the guest about
the error.
Reviewed-by: Halil Pasic <pasic@linux.ibm.com>
Reviewed-by: Eric Farman <farman@linux.ibm.com>
Tested-by: Eric Farman <farman@linux.ibm.com>
Reviewed-by: Cornelia Huck <cohuck@redhat.com>
Acked-by: Christian Borntraeger <borntraeger@linux.ibm.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
Message-ID: <20251118174047.73103-1-thuth@redhat.com>
(cherry picked from commit e5cb62e7b6f99d45a42f0cd358d76d6ee2cef5cd)
Patch-name: kvm-hw-s390x-Fix-a-possible-crash-with-passed-through-vi.patch
Patch-id: 55
Patch-present-in-specfile: True
---
hw/s390x/s390-hypercall.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/hw/s390x/s390-hypercall.c b/hw/s390x/s390-hypercall.c
index ac1b08b2cd..508dd97ca0 100644
--- a/hw/s390x/s390-hypercall.c
+++ b/hw/s390x/s390-hypercall.c
@@ -10,6 +10,7 @@
*/
#include "qemu/osdep.h"
+#include "qemu/error-report.h"
#include "cpu.h"
#include "hw/s390x/s390-virtio-ccw.h"
#include "hw/s390x/s390-hypercall.h"
@@ -42,6 +43,19 @@ static int handle_virtio_ccw_notify(uint64_t subch_id, uint64_t data)
if (!sch || !css_subch_visible(sch)) {
return -EINVAL;
}
+ if (sch->id.cu_type != VIRTIO_CCW_CU_TYPE) {
+ /*
+ * This might happen in nested setups: If the L1 host defined the
+ * L2 guest with a virtio device (e.g. virtio-keyboard), and the
+ * L2 guest passes this device through to the L3 guest, the L3 guest
+ * might send virtio notifications to the QEMU in L2 for that device.
+ * But since the QEMU in L2 defined this device as vfio-ccw, it's not
+ * a VirtIODevice that we can handle here!
+ */
+ warn_report_once("Got virtio notification for unsupported device "
+ "on subchannel %02x.%1x.%04x!", cssid, ssid, schid);
+ return -EINVAL;
+ }
vdev = virtio_ccw_get_vdev(sch);
if (vq_idx >= VIRTIO_QUEUE_MAX || !virtio_queue_get_num(vdev, vq_idx)) {

View File

@ -1,38 +0,0 @@
From eaa84431d740547a719a11020feda8ae0ef8834a Mon Sep 17 00:00:00 2001
From: Yanghang Liu <yanghliu@redhat.com>
Date: Mon, 24 Nov 2025 23:02:37 +0800
Subject: [PATCH] Fix the typo of vfio-pci device's enable-migration option
RH-Author: YangHang Liu <None>
RH-MergeRequest: 428: RHEL10: Fix the typo of vfio-pci device's enable-migration option
RH-Jira: RHEL-130704
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [1/1] bcf8b2089f687d02b5f0a48dd1e3dfc4664946e0 (yanghliu/qemu-kvm)
Signed-off-by: Yanghang Liu <yanghliu@redhat.com>
Reported-by: Mario Casquero <mcasquer@redhat.com>
Reviewed-by: Michael Tokarev <mjt@tls.msk.ru>
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
(cherry picked from commit 5f9ac963735598c1efbdce9c4a09f0a64e13d613)
Signed-off-by: Yanghang Liu <yanghliu@redhat.com>
Patch-name: kvm-Fix-the-typo-of-vfio-pci-device-s-enable-migration-o.patch
Patch-id: 56
Patch-present-in-specfile: True
---
hw/vfio/pci.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
index 83ecffb535..7c057ee2f9 100644
--- a/hw/vfio/pci.c
+++ b/hw/vfio/pci.c
@@ -3847,7 +3847,7 @@ static void vfio_pci_dev_class_init(ObjectClass *klass, const void *data)
"(DEBUG)");
object_class_property_set_description(klass, /* 5.2, 8.0 non-experimetal */
"enable-migration",
- "Enale device migration. Also requires a host VFIO PCI "
+ "Enable device migration. Also requires a host VFIO PCI "
"variant or mdev driver with migration support enabled");
object_class_property_set_description(klass, /* 8.1 */
"vf-token",

View File

@ -1,178 +0,0 @@
From 4bf5116601e58a07863c88426ab408dcc26e0331 Mon Sep 17 00:00:00 2001
From: Damien Bergamini <damien.bergamini@eviden.com>
Date: Mon, 1 Sep 2025 15:14:23 +0000
Subject: [PATCH] pcie_sriov: Fix broken MMIO accesses from SR-IOV VFs
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
RH-Author: Laurent Vivier <lvivier@redhat.com>
RH-MergeRequest: 431: pcie_sriov: Fix broken MMIO accesses from SR-IOV VFs
RH-Jira: RHEL-120115
RH-Acked-by: Eric Auger <eric.auger@redhat.com>
RH-Acked-by: Cédric Le Goater <clg@redhat.com>
RH-Commit: [1/1] b6bb40d37376db589852cb07a915d6f0eae29f67 (lvivier/qemu-kvm-centos)
JIRA: https://issues.redhat.com/browse/RHEL-120115
Starting with commit cab1398a60eb, SR-IOV VFs are realized as soon as
pcie_sriov_pf_init() is called. Because pcie_sriov_pf_init() must be
called before pcie_sriov_pf_init_vf_bar(), the VF BARs types won't be
known when the VF realize function calls pcie_sriov_vf_register_bar().
This breaks the memory regions of the VFs (for instance with igbvf):
$ lspci
...
Region 0: Memory at 281a00000 (64-bit, prefetchable) [virtual] [size=16K]
Region 3: Memory at 281a20000 (64-bit, prefetchable) [virtual] [size=16K]
$ info mtree
...
address-space: pci_bridge_pci_mem
0000000000000000-ffffffffffffffff (prio 0, i/o): pci_bridge_pci
0000000081a00000-0000000081a03fff (prio 1, i/o): igbvf-mmio
0000000081a20000-0000000081a23fff (prio 1, i/o): igbvf-msix
and causes MMIO accesses to fail:
Invalid write at addr 0x281A01520, size 4, region '(null)', reason: rejected
Invalid read at addr 0x281A00C40, size 4, region '(null)', reason: rejected
To fix this, VF BARs are now registered with pci_register_bar() which
has a type parameter and pcie_sriov_vf_register_bar() is removed.
Fixes: cab1398a60eb ("pcie_sriov: Reuse SR-IOV VF device instances")
Signed-off-by: Damien Bergamini <damien.bergamini@eviden.com>
Signed-off-by: Clement Mathieu--Drif <clement.mathieu--drif@eviden.com>
Reviewed-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <20250901151314.1038020-1-clement.mathieu--drif@eviden.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
(cherry picked from commit 2e54e5fda779a7ba45578884276dca62462f7a06)
Signed-off-by: Laurent Vivier <lvivier@redhat.com>
Patch-name: kvm-pcie_sriov-Fix-broken-MMIO-accesses-from-SR-IOV-VFs.patch
Patch-id: 57
Patch-present-in-specfile: True
---
docs/pcie_sriov.txt | 5 ++---
hw/net/igbvf.c | 6 ++++--
hw/nvme/ctrl.c | 8 ++------
hw/pci/pci.c | 3 ---
hw/pci/pcie_sriov.c | 11 -----------
include/hw/pci/pcie_sriov.h | 4 ----
6 files changed, 8 insertions(+), 29 deletions(-)
diff --git a/docs/pcie_sriov.txt b/docs/pcie_sriov.txt
index ab2142807f..00d7bd93fd 100644
--- a/docs/pcie_sriov.txt
+++ b/docs/pcie_sriov.txt
@@ -72,8 +72,7 @@ setting up a BAR for a VF.
2) Similarly in the implementation of the virtual function, you need to
make it a PCI Express device and add a similar set of capabilities
except for the SR/IOV capability. Then you need to set up the VF BARs as
- subregions of the PFs SR/IOV VF BARs by calling
- pcie_sriov_vf_register_bar() instead of the normal pci_register_bar() call:
+ subregions of the PFs SR/IOV VF BARs by calling pci_register_bar():
pci_your_vf_dev_realize( ... )
{
@@ -83,7 +82,7 @@ setting up a BAR for a VF.
pcie_ari_init(d, 0x100);
...
memory_region_init(mr, ... )
- pcie_sriov_vf_register_bar(d, bar_nr, mr);
+ pci_register_bar(d, bar_nr, bar_type, mr);
...
}
diff --git a/hw/net/igbvf.c b/hw/net/igbvf.c
index 31d72c4977..9b0db8f841 100644
--- a/hw/net/igbvf.c
+++ b/hw/net/igbvf.c
@@ -251,10 +251,12 @@ static void igbvf_pci_realize(PCIDevice *dev, Error **errp)
memory_region_init_io(&s->mmio, OBJECT(dev), &mmio_ops, s, "igbvf-mmio",
IGBVF_MMIO_SIZE);
- pcie_sriov_vf_register_bar(dev, IGBVF_MMIO_BAR_IDX, &s->mmio);
+ pci_register_bar(dev, IGBVF_MMIO_BAR_IDX, PCI_BASE_ADDRESS_MEM_TYPE_64 |
+ PCI_BASE_ADDRESS_MEM_PREFETCH, &s->mmio);
memory_region_init(&s->msix, OBJECT(dev), "igbvf-msix", IGBVF_MSIX_SIZE);
- pcie_sriov_vf_register_bar(dev, IGBVF_MSIX_BAR_IDX, &s->msix);
+ pci_register_bar(dev, IGBVF_MSIX_BAR_IDX, PCI_BASE_ADDRESS_MEM_TYPE_64 |
+ PCI_BASE_ADDRESS_MEM_PREFETCH, &s->msix);
ret = msix_init(dev, IGBVF_MSIX_VEC_NUM, &s->msix, IGBVF_MSIX_BAR_IDX, 0,
&s->msix, IGBVF_MSIX_BAR_IDX, 0x2000, 0x70, errp);
diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c
index f5ee6bf260..cd81f73997 100644
--- a/hw/nvme/ctrl.c
+++ b/hw/nvme/ctrl.c
@@ -8708,12 +8708,8 @@ static bool nvme_init_pci(NvmeCtrl *n, PCIDevice *pci_dev, Error **errp)
msix_table_offset);
memory_region_add_subregion(&n->bar0, 0, &n->iomem);
- if (pci_is_vf(pci_dev)) {
- pcie_sriov_vf_register_bar(pci_dev, 0, &n->bar0);
- } else {
- pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY |
- PCI_BASE_ADDRESS_MEM_TYPE_64, &n->bar0);
- }
+ pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY |
+ PCI_BASE_ADDRESS_MEM_TYPE_64, &n->bar0);
ret = msix_init(pci_dev, nr_vectors,
&n->bar0, 0, msix_table_offset,
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index 0012cc12e7..d2ebb066e1 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -1490,9 +1490,6 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num,
: pci_get_bus(pci_dev)->address_space_mem;
if (pci_is_vf(pci_dev)) {
- PCIDevice *pf = pci_dev->exp.sriov_vf.pf;
- assert(!pf || type == pf->exp.sriov_pf.vf_bar_type[region_num]);
-
r->addr = pci_bar_address(pci_dev, region_num, r->type, r->size);
if (r->addr != PCI_BAR_UNMAPPED) {
memory_region_add_subregion_overlap(r->address_space,
diff --git a/hw/pci/pcie_sriov.c b/hw/pci/pcie_sriov.c
index cf1b5b5c05..c4f88f0975 100644
--- a/hw/pci/pcie_sriov.c
+++ b/hw/pci/pcie_sriov.c
@@ -246,17 +246,6 @@ void pcie_sriov_pf_init_vf_bar(PCIDevice *dev, int region_num,
dev->exp.sriov_pf.vf_bar_type[region_num] = type;
}
-void pcie_sriov_vf_register_bar(PCIDevice *dev, int region_num,
- MemoryRegion *memory)
-{
- uint8_t type;
-
- assert(dev->exp.sriov_vf.pf);
- type = dev->exp.sriov_vf.pf->exp.sriov_pf.vf_bar_type[region_num];
-
- return pci_register_bar(dev, region_num, type, memory);
-}
-
static gint compare_vf_devfns(gconstpointer a, gconstpointer b)
{
return (*(PCIDevice **)a)->devfn - (*(PCIDevice **)b)->devfn;
diff --git a/include/hw/pci/pcie_sriov.h b/include/hw/pci/pcie_sriov.h
index aeaa38cf34..b0ea6a62c7 100644
--- a/include/hw/pci/pcie_sriov.h
+++ b/include/hw/pci/pcie_sriov.h
@@ -37,10 +37,6 @@ void pcie_sriov_pf_exit(PCIDevice *dev);
void pcie_sriov_pf_init_vf_bar(PCIDevice *dev, int region_num,
uint8_t type, dma_addr_t size);
-/* Instantiate a bar for a VF */
-void pcie_sriov_vf_register_bar(PCIDevice *dev, int region_num,
- MemoryRegion *memory);
-
/**
* pcie_sriov_pf_init_from_user_created_vfs() - Initialize PF with user-created
* VFs, adding ARI to PF

View File

@ -1,45 +0,0 @@
From fa0a758781fc63888c9af9a585928217fd07c140 Mon Sep 17 00:00:00 2001
From: Sebastian Ott <sebott@redhat.com>
Date: Tue, 25 Nov 2025 09:19:30 +0100
Subject: [PATCH] arm: fix oob access in compat handling
RH-Author: Sebastian Ott <sebott@redhat.com>
RH-MergeRequest: 430: arm: fix oob access in compat handling
RH-Jira: RHEL-130478
RH-Acked-by: Cornelia Huck <cohuck@redhat.com>
RH-Acked-by: Eric Auger <eric.auger@redhat.com>
RH-Acked-by: Gavin Shan <gshan@redhat.com>
RH-Acked-by: Igor Mammedov <imammedo@redhat.com>
RH-Commit: [1/1] 5d6ab0821b0ffce732862969f275aa50f6917bf1 (seott1/cos-qemu-kvm)
Upstream: RHEL only
Fixes: 58cba97a "hw/arm/virt: Use ACPI PCI hotplug by default from 10.2 onwards"
Due to incorrect length information arm_acpi_pci_hp_disabled_compat[]
was accessed out of bounds. This led to the weird side effect that the
1st member of arm_rhel9_compat[] was applied to the virt-rhel10.0
machine type causing migration failures. Fix the length.
Signed-off-by: Sebastian Ott <sebott@redhat.com>
Patch-name: kvm-arm-fix-oob-access-in-compat-handling.patch
Patch-id: 58
Patch-present-in-specfile: True
---
hw/arm/virt.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index e8e64fe7fe..1cfb386f64 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -102,7 +102,8 @@ static const size_t arm_virt_compat_len = G_N_ELEMENTS(arm_virt_compat);
GlobalProperty arm_acpi_pci_hp_disabled_compat[] = {
{ TYPE_ACPI_GED, "acpi-pci-hotplug-with-bridge-support", "off" },
};
-static const size_t arm_acpi_pci_hp_disabled_compat_len = G_N_ELEMENTS(arm_virt_compat);
+static const size_t arm_acpi_pci_hp_disabled_compat_len =
+ G_N_ELEMENTS(arm_acpi_pci_hp_disabled_compat);
/*
* RHEL9 kernels have pauth disabled while RHEL10 has it enabled,

View File

@ -1,74 +0,0 @@
From bd02d862e6cdce44a5bf0052db5bf3e6f599934d Mon Sep 17 00:00:00 2001
From: Kevin Wolf <kwolf@redhat.com>
Date: Wed, 19 Nov 2025 18:27:20 +0100
Subject: [PATCH] block-backend: Fix race when resuming queued requests
RH-Author: Kevin Wolf <kwolf@redhat.com>
RH-MergeRequest: 432: block-backend: Fix race when resuming queued requests [c10s]
RH-Jira: RHEL-129540
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
RH-Acked-by: Hanna Czenczek <hreitz@redhat.com>
RH-Commit: [1/1] fa7ead79ae44d89054ed574deb3fbd196536fef3 (kmwolf/centos-qemu-kvm)
When new requests arrive at a BlockBackend that is currently drained,
these requests are queued until the drain section ends.
There is a race window between blk_root_drained_end() waking up a queued
request in an iothread from the main thread and blk_wait_while_drained()
actually being woken up in the iothread and calling blk_inc_in_flight().
If the BlockBackend is drained again during this window, drain won't
wait for this request and it will sneak in when the BlockBackend is
already supposed to be quiesced. This causes assertion failures in
bdrv_drain_all_begin() and can have other unintended consequences.
Fix this by increasing the in_flight counter immediately when scheduling
the request to be resumed so that the next drain will wait for it to
complete.
Cc: qemu-stable@nongnu.org
Reported-by: Andrey Drobyshev <andrey.drobyshev@virtuozzo.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Message-ID: <20251119172720.135424-1-kwolf@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Tested-by: Andrey Drobyshev <andrey.drobyshev@virtuozzo.com>
Reviewed-by: Fiona Ebner <f.ebner@proxmox.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 8eeaa706ba73251063cb80d87ae838d2d5b08e9a)
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Patch-name: kvm-block-backend-Fix-race-when-resuming-queued-requests.patch
Patch-id: 59
Patch-present-in-specfile: True
---
block/block-backend.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/block/block-backend.c b/block/block-backend.c
index f8d6ba65c1..d6df369188 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -1318,9 +1318,9 @@ static void coroutine_fn blk_wait_while_drained(BlockBackend *blk)
* section.
*/
qemu_mutex_lock(&blk->queued_requests_lock);
+ /* blk_root_drained_end() has the corresponding blk_inc_in_flight() */
blk_dec_in_flight(blk);
qemu_co_queue_wait(&blk->queued_requests, &blk->queued_requests_lock);
- blk_inc_in_flight(blk);
qemu_mutex_unlock(&blk->queued_requests_lock);
}
}
@@ -2767,9 +2767,11 @@ static void blk_root_drained_end(BdrvChild *child)
blk->dev_ops->drained_end(blk->dev_opaque);
}
qemu_mutex_lock(&blk->queued_requests_lock);
- while (qemu_co_enter_next(&blk->queued_requests,
- &blk->queued_requests_lock)) {
+ while (!qemu_co_queue_empty(&blk->queued_requests)) {
/* Resume all queued requests */
+ blk_inc_in_flight(blk);
+ qemu_co_enter_next(&blk->queued_requests,
+ &blk->queued_requests_lock);
}
qemu_mutex_unlock(&blk->queued_requests_lock);
}

View File

@ -1,123 +0,0 @@
From 0078d9aa02c830ca38a68a1e5b794227c6542c3c Mon Sep 17 00:00:00 2001
From: Kevin Wolf <kwolf@redhat.com>
Date: Fri, 28 Nov 2025 23:14:40 +0100
Subject: [PATCH] file-posix: Handle suspended dm-multipath better for SG_IO
RH-Author: Kevin Wolf <kwolf@redhat.com>
RH-MergeRequest: 436: file-posix: Handle suspended dm-multipath better for SG_IO
RH-Jira: RHEL-121543
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
RH-Acked-by: Hanna Czenczek <hreitz@redhat.com>
RH-Commit: [1/1] f90d36aba5b374dcb9d5986f968c2dbde4bdd18d (kmwolf/centos-qemu-kvm)
When introducing DM_MPATH_PROBE_PATHS, we already anticipated that
dm-multipath devices might be suspended for a short time when the DM
tables are reloaded and that they return -EAGAIN in this case. We then
wait for a millisecond and retry.
However, meanwhile it has also turned out that libmpathpersist (which is
used by qemu-pr-helper) may need to perform more complex recovery
operations to get reservations back to expected state if a path failure
happened in the middle of a PR operation. In this case, the device is
suspended for a longer time compared to the case we originally expected.
This patch changes hdev_co_ioctl() to treat -EAGAIN separately so that
it doesn't result in an immediate failure if the device is suspended for
more than 1ms, and moves to incremental backoff to cover both quick and
slow cases without excessive delays.
Buglink: https://issues.redhat.com/browse/RHEL-121543
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Message-ID: <20251128221440.89125-1-kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 2c3165a1a61c299b4a3ae30899e1cc738d20e004)
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Patch-name: kvm-file-posix-Handle-suspended-dm-multipath-better-for-.patch
Patch-id: 60
Patch-present-in-specfile: True
---
block/file-posix.c | 56 ++++++++++++++++++++++++++++------------------
1 file changed, 34 insertions(+), 22 deletions(-)
diff --git a/block/file-posix.c b/block/file-posix.c
index cb2e94d7db..ffca37130b 100644
--- a/block/file-posix.c
+++ b/block/file-posix.c
@@ -4289,25 +4289,8 @@ hdev_open_Mac_error:
static bool coroutine_fn sgio_path_error(int ret, sg_io_hdr_t *io_hdr)
{
if (ret < 0) {
- switch (ret) {
- case -ENODEV:
- return true;
- case -EAGAIN:
- /*
- * The device is probably suspended. This happens while the dm table
- * is reloaded, e.g. because a path is added or removed. This is an
- * operation that should complete within 1ms, so just wait a bit and
- * retry.
- *
- * If the device was suspended for another reason, we'll wait and
- * retry SG_IO_MAX_RETRIES times. This is a tolerable delay before
- * we return an error and potentially stop the VM.
- */
- qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, 1000000);
- return true;
- default:
- return false;
- }
+ /* Path errors sometimes result in -ENODEV */
+ return ret == -ENODEV;
}
if (io_hdr->host_status != SCSI_HOST_OK) {
@@ -4376,6 +4359,7 @@ hdev_co_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
{
BDRVRawState *s = bs->opaque;
RawPosixAIOData acb;
+ uint64_t eagain_sleep_ns = 1 * SCALE_MS;
int retries = SG_IO_MAX_RETRIES;
int ret;
@@ -4404,9 +4388,37 @@ hdev_co_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
},
};
- do {
- ret = raw_thread_pool_submit(handle_aiocb_ioctl, &acb);
- } while (req == SG_IO && retries-- && hdev_co_ioctl_sgio_retry(&acb, ret));
+retry:
+ ret = raw_thread_pool_submit(handle_aiocb_ioctl, &acb);
+ if (req == SG_IO && s->use_mpath) {
+ if (ret == -EAGAIN && eagain_sleep_ns < NANOSECONDS_PER_SECOND) {
+ /*
+ * If this is a multipath device, it is probably suspended.
+ *
+ * This can happen while the dm table is reloaded, e.g. because a
+ * path is added or removed. This is an operation that should
+ * complete within 1ms, so just wait a bit and retry.
+ *
+ * There are also some cases in which libmpathpersist must recover
+ * from path failure during its operation, which can leave the
+ * device suspended for a bit longer while the library brings back
+ * reservations into the expected state.
+ *
+ * Use increasing delays to cover both cases without waiting
+ * excessively, and stop after a bit more than a second (1023 ms).
+ * This is a tolerable delay before we return an error and
+ * potentially stop the VM.
+ */
+ qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, eagain_sleep_ns);
+ eagain_sleep_ns *= 2;
+ goto retry;
+ }
+
+ /* Even for ret == 0, the SG_IO header can contain an error */
+ if (retries-- && hdev_co_ioctl_sgio_retry(&acb, ret)) {
+ goto retry;
+ }
+ }
return ret;
}

View File

@ -1,131 +0,0 @@
From da2c7d5f43b53796bfc8e76ea3e9e63c617048ba Mon Sep 17 00:00:00 2001
From: Magnus Kulke <magnuskulke@linux.microsoft.com>
Date: Tue, 16 Sep 2025 18:48:21 +0200
Subject: [PATCH] accel: Add Meson and config support for MSHV accelerator
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
RH-Author: Igor Mammedov <imammedo@redhat.com>
RH-MergeRequest: 437: el10: x86: enablement for Azure L1VH OCP readiness
RH-Jira: RHEL-134212
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [1/30] 04ab9685b09f4d837715bf624d87566f472cb6c2
Introduce a Meson feature option and default-config entry to allow
building QEMU with MSHV (Microsoft Hypervisor) acceleration support.
This is the first step toward implementing an MSHV backend in QEMU.
Signed-off-by: Magnus Kulke <magnuskulke@linux.microsoft.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Link: https://lore.kernel.org/r/20250916164847.77883-2-magnuskulke@linux.microsoft.com
[Add error for unavailable accelerator. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit 37e12da5df8eb74042f11e9e7bec8a50b8090adb)
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Patch-name: kvm-accel-Add-Meson-and-config-support-for-MSHV-accelera.patch
Patch-id: 61
Patch-present-in-specfile: True
---
accel/Kconfig | 3 +++
meson.build | 13 +++++++++++++
meson_options.txt | 2 ++
scripts/meson-buildoptions.sh | 3 +++
4 files changed, 21 insertions(+)
diff --git a/accel/Kconfig b/accel/Kconfig
index 4263cab722..a60f114923 100644
--- a/accel/Kconfig
+++ b/accel/Kconfig
@@ -13,6 +13,9 @@ config TCG
config KVM
bool
+config MSHV
+ bool
+
config XEN
bool
select FSDEV_9P if VIRTFS
diff --git a/meson.build b/meson.build
index ef2e5be6e2..96254f8075 100644
--- a/meson.build
+++ b/meson.build
@@ -334,6 +334,7 @@ elif cpu == 'x86_64'
'CONFIG_HVF': ['x86_64-softmmu'],
'CONFIG_NVMM': ['i386-softmmu', 'x86_64-softmmu'],
'CONFIG_WHPX': ['i386-softmmu', 'x86_64-softmmu'],
+ 'CONFIG_MSHV': ['x86_64-softmmu'],
}
endif
@@ -884,6 +885,14 @@ accelerators = []
if get_option('kvm').allowed() and host_os == 'linux'
accelerators += 'CONFIG_KVM'
endif
+
+if get_option('mshv').allowed() and host_os == 'linux'
+ if get_option('mshv').enabled() and host_machine.cpu() != 'x86_64'
+ error('mshv accelerator requires x64_64 host')
+ endif
+ accelerators += 'CONFIG_MSHV'
+endif
+
if get_option('whpx').allowed() and host_os == 'windows'
if get_option('whpx').enabled() and host_machine.cpu() != 'x86_64'
error('WHPX requires 64-bit host')
@@ -953,6 +962,9 @@ endif
if 'CONFIG_WHPX' not in accelerators and get_option('whpx').enabled()
error('WHPX not available on this platform')
endif
+if 'CONFIG_MSHV' not in accelerators and get_option('mshv').enabled()
+ error('mshv not available on this platform')
+endif
xen = not_found
if get_option('xen').enabled() or (get_option('xen').auto() and have_system)
@@ -4821,6 +4833,7 @@ if have_system
summary_info += {'HVF support': config_all_accel.has_key('CONFIG_HVF')}
summary_info += {'WHPX support': config_all_accel.has_key('CONFIG_WHPX')}
summary_info += {'NVMM support': config_all_accel.has_key('CONFIG_NVMM')}
+ summary_info += {'MSHV support': config_all_accel.has_key('CONFIG_MSHV')}
summary_info += {'Xen support': xen.found()}
if xen.found()
summary_info += {'xen ctrl version': xen.version()}
diff --git a/meson_options.txt b/meson_options.txt
index f45d7ded45..2267dee8a0 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -73,6 +73,8 @@ option('malloc', type : 'combo', choices : ['system', 'tcmalloc', 'jemalloc'],
option('kvm', type: 'feature', value: 'auto',
description: 'KVM acceleration support')
+option('mshv', type: 'feature', value: 'auto',
+ description: 'MSHV acceleration support')
option('whpx', type: 'feature', value: 'auto',
description: 'WHPX acceleration support')
option('hvf', type: 'feature', value: 'auto',
diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh
index 4146dbc88d..9aff126c28 100644
--- a/scripts/meson-buildoptions.sh
+++ b/scripts/meson-buildoptions.sh
@@ -155,6 +155,7 @@ meson_options_help() {
printf "%s\n" ' membarrier membarrier system call (for Linux 4.14+ or Windows'
printf "%s\n" ' modules modules support (non Windows)'
printf "%s\n" ' mpath Multipath persistent reservation passthrough'
+ printf "%s\n" ' mshv MSHV acceleration support'
printf "%s\n" ' multiprocess Out of process device emulation support'
printf "%s\n" ' netmap netmap network backend support'
printf "%s\n" ' nettle nettle cryptography support'
@@ -409,6 +410,8 @@ _meson_option_parse() {
--disable-modules) printf "%s" -Dmodules=disabled ;;
--enable-mpath) printf "%s" -Dmpath=enabled ;;
--disable-mpath) printf "%s" -Dmpath=disabled ;;
+ --enable-mshv) printf "%s" -Dmshv=enabled ;;
+ --disable-mshv) printf "%s" -Dmshv=disabled ;;
--enable-multiprocess) printf "%s" -Dmultiprocess=enabled ;;
--disable-multiprocess) printf "%s" -Dmultiprocess=disabled ;;
--enable-netmap) printf "%s" -Dnetmap=enabled ;;

View File

@ -1,150 +0,0 @@
From b347fa5c362ac5f1fdcfa5601f4b4a36a2d3798c Mon Sep 17 00:00:00 2001
From: Magnus Kulke <magnuskulke@linux.microsoft.com>
Date: Tue, 16 Sep 2025 18:48:22 +0200
Subject: [PATCH] target/i386/emulate: Allow instruction decoding from stream
RH-Author: Igor Mammedov <imammedo@redhat.com>
RH-MergeRequest: 437: el10: x86: enablement for Azure L1VH OCP readiness
RH-Jira: RHEL-134212
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [2/30] 36aa0cc1832e8162cb7bba8001b2362245cdb80b
Introduce a new helper function to decode x86 instructions from a
raw instruction byte stream. MSHV delivers an instruction stream in a
buffer of the vm_exit message. It can be used to speed up MMIO
emulation, since instructions do not have to be fetched and translated.
Added "fetch_instruction()" op to x86_emul_ops() to improve
traceability.
Signed-off-by: Magnus Kulke <magnuskulke@linux.microsoft.com>
Link: https://lore.kernel.org/r/20250916164847.77883-3-magnuskulke@linux.microsoft.com
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit 1e25327b244a217078e3fa5df18322c70932f478)
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Patch-name: kvm-target-i386-emulate-Allow-instruction-decoding-from-.patch
Patch-id: 62
Patch-present-in-specfile: True
---
target/i386/emulate/x86_decode.c | 27 +++++++++++++++++++++++----
target/i386/emulate/x86_decode.h | 9 +++++++++
target/i386/emulate/x86_emu.c | 3 ++-
target/i386/emulate/x86_emu.h | 2 ++
4 files changed, 36 insertions(+), 5 deletions(-)
diff --git a/target/i386/emulate/x86_decode.c b/target/i386/emulate/x86_decode.c
index 2eca39802e..97bd6f1a3b 100644
--- a/target/i386/emulate/x86_decode.c
+++ b/target/i386/emulate/x86_decode.c
@@ -71,10 +71,16 @@ static inline uint64_t decode_bytes(CPUX86State *env, struct x86_decode *decode,
VM_PANIC_EX("%s invalid size %d\n", __func__, size);
break;
}
- target_ulong va = linear_rip(env_cpu(env), env->eip) + decode->len;
- emul_ops->read_mem(env_cpu(env), &val, va, size);
+
+ /* copy the bytes from the instruction stream, if available */
+ if (decode->stream && decode->len + size <= decode->stream->len) {
+ memcpy(&val, decode->stream->bytes + decode->len, size);
+ } else {
+ target_ulong va = linear_rip(env_cpu(env), env->eip) + decode->len;
+ emul_ops->fetch_instruction(env_cpu(env), &val, va, size);
+ }
decode->len += size;
-
+
return val;
}
@@ -2076,9 +2082,10 @@ static void decode_opcodes(CPUX86State *env, struct x86_decode *decode)
}
}
-uint32_t decode_instruction(CPUX86State *env, struct x86_decode *decode)
+static uint32_t decode_opcode(CPUX86State *env, struct x86_decode *decode)
{
memset(decode, 0, sizeof(*decode));
+
decode_prefix(env, decode);
set_addressing_size(env, decode);
set_operand_size(env, decode);
@@ -2088,6 +2095,18 @@ uint32_t decode_instruction(CPUX86State *env, struct x86_decode *decode)
return decode->len;
}
+uint32_t decode_instruction(CPUX86State *env, struct x86_decode *decode)
+{
+ return decode_opcode(env, decode);
+}
+
+uint32_t decode_instruction_stream(CPUX86State *env, struct x86_decode *decode,
+ struct x86_insn_stream *stream)
+{
+ decode->stream = stream;
+ return decode_opcode(env, decode);
+}
+
void init_decoder(void)
{
int i;
diff --git a/target/i386/emulate/x86_decode.h b/target/i386/emulate/x86_decode.h
index 927645af1a..1cadf3694f 100644
--- a/target/i386/emulate/x86_decode.h
+++ b/target/i386/emulate/x86_decode.h
@@ -272,6 +272,11 @@ typedef struct x86_decode_op {
};
} x86_decode_op;
+typedef struct x86_insn_stream {
+ const uint8_t *bytes;
+ size_t len;
+} x86_insn_stream;
+
typedef struct x86_decode {
int len;
uint8_t opcode[4];
@@ -298,11 +303,15 @@ typedef struct x86_decode {
struct x86_modrm modrm;
struct x86_decode_op op[4];
bool is_fpu;
+
+ x86_insn_stream *stream;
} x86_decode;
uint64_t sign(uint64_t val, int size);
uint32_t decode_instruction(CPUX86State *env, struct x86_decode *decode);
+uint32_t decode_instruction_stream(CPUX86State *env, struct x86_decode *decode,
+ struct x86_insn_stream *stream);
void *get_reg_ref(CPUX86State *env, int reg, int rex_present,
int is_extended, int size);
diff --git a/target/i386/emulate/x86_emu.c b/target/i386/emulate/x86_emu.c
index db7a7f7437..4409f7bc13 100644
--- a/target/i386/emulate/x86_emu.c
+++ b/target/i386/emulate/x86_emu.c
@@ -1246,7 +1246,8 @@ static void init_cmd_handler(void)
bool exec_instruction(CPUX86State *env, struct x86_decode *ins)
{
if (!_cmd_handler[ins->cmd].handler) {
- printf("Unimplemented handler (" TARGET_FMT_lx ") for %d (%x %x) \n", env->eip,
+ printf("Unimplemented handler (" TARGET_FMT_lx ") for %d (%x %x)\n",
+ env->eip,
ins->cmd, ins->opcode[0],
ins->opcode_len > 1 ? ins->opcode[1] : 0);
env->eip += ins->len;
diff --git a/target/i386/emulate/x86_emu.h b/target/i386/emulate/x86_emu.h
index a1a961284b..05686b162f 100644
--- a/target/i386/emulate/x86_emu.h
+++ b/target/i386/emulate/x86_emu.h
@@ -24,6 +24,8 @@
#include "cpu.h"
struct x86_emul_ops {
+ void (*fetch_instruction)(CPUState *cpu, void *data, target_ulong addr,
+ int bytes);
void (*read_mem)(CPUState *cpu, void *data, target_ulong addr, int bytes);
void (*write_mem)(CPUState *cpu, void *data, target_ulong addr, int bytes);
void (*read_segment_descriptor)(CPUState *cpu, struct x86_segment_descriptor *desc,

View File

@ -1,432 +0,0 @@
From b49240242f3d6a007abc4027aef16cd0b2f70d8b Mon Sep 17 00:00:00 2001
From: Magnus Kulke <magnuskulke@linux.microsoft.com>
Date: Tue, 16 Sep 2025 18:48:23 +0200
Subject: [PATCH] target/i386/mshv: Add x86 decoder/emu implementation
RH-Author: Igor Mammedov <imammedo@redhat.com>
RH-MergeRequest: 437: el10: x86: enablement for Azure L1VH OCP readiness
RH-Jira: RHEL-134212
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [3/30] 8fa2e2f50c18532d98ef3917f624bc3e65ad167d
The MSHV accelerator requires a x86 decoder/emulator in userland to
emulate MMIO instructions. This change contains the implementations for
the generalized i386 instruction decoder/emulator.
Signed-off-by: Magnus Kulke <magnuskulke@linux.microsoft.com>
Link: https://lore.kernel.org/r/20250916164847.77883-4-magnuskulke@linux.microsoft.com
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit 0daf817c80b57e58168309420abf0a8a3d2a60f6)
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Patch-name: kvm-target-i386-mshv-Add-x86-decoder-emu-implementation.patch
Patch-id: 63
Patch-present-in-specfile: True
---
include/system/mshv.h | 25 +++
target/i386/cpu.h | 2 +-
target/i386/emulate/meson.build | 7 +-
target/i386/meson.build | 2 +
target/i386/mshv/meson.build | 7 +
target/i386/mshv/x86.c | 297 ++++++++++++++++++++++++++++++++
6 files changed, 337 insertions(+), 3 deletions(-)
create mode 100644 include/system/mshv.h
create mode 100644 target/i386/mshv/meson.build
create mode 100644 target/i386/mshv/x86.c
diff --git a/include/system/mshv.h b/include/system/mshv.h
new file mode 100644
index 0000000000..342f1ef6a9
--- /dev/null
+++ b/include/system/mshv.h
@@ -0,0 +1,25 @@
+/*
+ * QEMU MSHV support
+ *
+ * Copyright Microsoft, Corp. 2025
+ *
+ * Authors: Ziqiao Zhou <ziqiaozhou@microsoft.com>
+ * Magnus Kulke <magnuskulke@microsoft.com>
+ * Jinank Jain <jinankjain@microsoft.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ */
+
+#ifndef QEMU_MSHV_H
+#define QEMU_MSHV_H
+
+#ifdef COMPILING_PER_TARGET
+#ifdef CONFIG_MSHV
+#define CONFIG_MSHV_IS_POSSIBLE
+#endif
+#else
+#define CONFIG_MSHV_IS_POSSIBLE
+#endif
+
+#endif
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index 2187e61654..4b7eae43e1 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -2126,7 +2126,7 @@ typedef struct CPUArchState {
QEMUTimer *xen_periodic_timer;
QemuMutex xen_timers_lock;
#endif
-#if defined(CONFIG_HVF)
+#if defined(CONFIG_HVF) || defined(CONFIG_MSHV)
void *emu_mmio_buf;
#endif
diff --git a/target/i386/emulate/meson.build b/target/i386/emulate/meson.build
index 4edd4f462f..b6dafb6a5b 100644
--- a/target/i386/emulate/meson.build
+++ b/target/i386/emulate/meson.build
@@ -1,5 +1,8 @@
-i386_system_ss.add(when: [hvf, 'CONFIG_HVF'], if_true: files(
+emulator_files = files(
'x86_decode.c',
'x86_emu.c',
'x86_flags.c',
-))
+)
+
+i386_system_ss.add(when: [hvf, 'CONFIG_HVF'], if_true: emulator_files)
+i386_system_ss.add(when: 'CONFIG_MSHV', if_true: emulator_files)
diff --git a/target/i386/meson.build b/target/i386/meson.build
index 092af34e2d..89ba4912aa 100644
--- a/target/i386/meson.build
+++ b/target/i386/meson.build
@@ -13,6 +13,7 @@ i386_ss.add(when: 'CONFIG_KVM', if_true: files('host-cpu.c'))
i386_ss.add(when: 'CONFIG_HVF', if_true: files('host-cpu.c'))
i386_ss.add(when: 'CONFIG_WHPX', if_true: files('host-cpu.c'))
i386_ss.add(when: 'CONFIG_NVMM', if_true: files('host-cpu.c'))
+i386_ss.add(when: 'CONFIG_MSHV', if_true: files('host-cpu.c'))
i386_system_ss = ss.source_set()
i386_system_ss.add(files(
@@ -34,6 +35,7 @@ subdir('nvmm')
subdir('hvf')
subdir('tcg')
subdir('emulate')
+subdir('mshv')
target_arch += {'i386': i386_ss}
target_system_arch += {'i386': i386_system_ss}
diff --git a/target/i386/mshv/meson.build b/target/i386/mshv/meson.build
new file mode 100644
index 0000000000..8ddaa7c11d
--- /dev/null
+++ b/target/i386/mshv/meson.build
@@ -0,0 +1,7 @@
+i386_mshv_ss = ss.source_set()
+
+i386_mshv_ss.add(files(
+ 'x86.c',
+))
+
+i386_system_ss.add_all(when: 'CONFIG_MSHV', if_true: i386_mshv_ss)
diff --git a/target/i386/mshv/x86.c b/target/i386/mshv/x86.c
new file mode 100644
index 0000000000..d574b3bc52
--- /dev/null
+++ b/target/i386/mshv/x86.c
@@ -0,0 +1,297 @@
+/*
+ * QEMU MSHV support
+ *
+ * Copyright Microsoft, Corp. 2025
+ *
+ * Authors: Magnus Kulke <magnuskulke@microsoft.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+
+#include "cpu.h"
+#include "emulate/x86_decode.h"
+#include "emulate/x86_emu.h"
+#include "qemu/typedefs.h"
+#include "qemu/error-report.h"
+#include "system/mshv.h"
+
+/* RW or Exec segment */
+static const uint8_t RWRX_SEGMENT_TYPE = 0x2;
+static const uint8_t CODE_SEGMENT_TYPE = 0x8;
+static const uint8_t EXPAND_DOWN_SEGMENT_TYPE = 0x4;
+
+typedef enum CpuMode {
+ REAL_MODE,
+ PROTECTED_MODE,
+ LONG_MODE,
+} CpuMode;
+
+static CpuMode cpu_mode(CPUState *cpu)
+{
+ enum CpuMode m = REAL_MODE;
+
+ if (x86_is_protected(cpu)) {
+ m = PROTECTED_MODE;
+
+ if (x86_is_long_mode(cpu)) {
+ m = LONG_MODE;
+ }
+ }
+
+ return m;
+}
+
+static bool segment_type_ro(const SegmentCache *seg)
+{
+ uint32_t type_ = (seg->flags >> DESC_TYPE_SHIFT) & 15;
+ return (type_ & (~RWRX_SEGMENT_TYPE)) == 0;
+}
+
+static bool segment_type_code(const SegmentCache *seg)
+{
+ uint32_t type_ = (seg->flags >> DESC_TYPE_SHIFT) & 15;
+ return (type_ & CODE_SEGMENT_TYPE) != 0;
+}
+
+static bool segment_expands_down(const SegmentCache *seg)
+{
+ uint32_t type_ = (seg->flags >> DESC_TYPE_SHIFT) & 15;
+
+ if (segment_type_code(seg)) {
+ return false;
+ }
+
+ return (type_ & EXPAND_DOWN_SEGMENT_TYPE) != 0;
+}
+
+static uint32_t segment_limit(const SegmentCache *seg)
+{
+ uint32_t limit = seg->limit;
+ uint32_t granularity = (seg->flags & DESC_G_MASK) != 0;
+
+ if (granularity != 0) {
+ limit = (limit << 12) | 0xFFF;
+ }
+
+ return limit;
+}
+
+static uint8_t segment_db(const SegmentCache *seg)
+{
+ return (seg->flags >> DESC_B_SHIFT) & 1;
+}
+
+static uint32_t segment_max_limit(const SegmentCache *seg)
+{
+ if (segment_db(seg) != 0) {
+ return 0xFFFFFFFF;
+ }
+ return 0xFFFF;
+}
+
+static int linearize(CPUState *cpu,
+ target_ulong logical_addr, target_ulong *linear_addr,
+ X86Seg seg_idx)
+{
+ enum CpuMode mode;
+ X86CPU *x86_cpu = X86_CPU(cpu);
+ CPUX86State *env = &x86_cpu->env;
+ SegmentCache *seg = &env->segs[seg_idx];
+ target_ulong base = seg->base;
+ target_ulong logical_addr_32b;
+ uint32_t limit;
+ /* TODO: the emulator will not pass us "write" indicator yet */
+ bool write = false;
+
+ mode = cpu_mode(cpu);
+
+ switch (mode) {
+ case LONG_MODE:
+ if (__builtin_add_overflow(logical_addr, base, linear_addr)) {
+ error_report("Address overflow");
+ return -1;
+ }
+ break;
+ case PROTECTED_MODE:
+ case REAL_MODE:
+ if (segment_type_ro(seg) && write) {
+ error_report("Cannot write to read-only segment");
+ return -1;
+ }
+
+ logical_addr_32b = logical_addr & 0xFFFFFFFF;
+ limit = segment_limit(seg);
+
+ if (segment_expands_down(seg)) {
+ if (logical_addr_32b >= limit) {
+ error_report("Address exceeds limit (expands down)");
+ return -1;
+ }
+
+ limit = segment_max_limit(seg);
+ }
+
+ if (logical_addr_32b > limit) {
+ error_report("Address exceeds limit %u", limit);
+ return -1;
+ }
+ *linear_addr = logical_addr_32b + base;
+ break;
+ default:
+ error_report("Unknown cpu mode: %d", mode);
+ return -1;
+ }
+
+ return 0;
+}
+
+bool x86_read_segment_descriptor(CPUState *cpu,
+ struct x86_segment_descriptor *desc,
+ x86_segment_selector sel)
+{
+ target_ulong base;
+ uint32_t limit;
+ X86CPU *x86_cpu = X86_CPU(cpu);
+ CPUX86State *env = &x86_cpu->env;
+ target_ulong gva;
+
+ memset(desc, 0, sizeof(*desc));
+
+ /* valid gdt descriptors start from index 1 */
+ if (!sel.index && GDT_SEL == sel.ti) {
+ return false;
+ }
+
+ if (GDT_SEL == sel.ti) {
+ base = env->gdt.base;
+ limit = env->gdt.limit;
+ } else {
+ base = env->ldt.base;
+ limit = env->ldt.limit;
+ }
+
+ if (sel.index * 8 >= limit) {
+ return false;
+ }
+
+ gva = base + sel.index * 8;
+ emul_ops->read_mem(cpu, desc, gva, sizeof(*desc));
+
+ return true;
+}
+
+bool x86_read_call_gate(CPUState *cpu, struct x86_call_gate *idt_desc,
+ int gate)
+{
+ target_ulong base;
+ uint32_t limit;
+ X86CPU *x86_cpu = X86_CPU(cpu);
+ CPUX86State *env = &x86_cpu->env;
+ target_ulong gva;
+
+ base = env->idt.base;
+ limit = env->idt.limit;
+
+ memset(idt_desc, 0, sizeof(*idt_desc));
+ if (gate * 8 >= limit) {
+ perror("call gate exceeds idt limit");
+ return false;
+ }
+
+ gva = base + gate * 8;
+ emul_ops->read_mem(cpu, idt_desc, gva, sizeof(*idt_desc));
+
+ return true;
+}
+
+bool x86_is_protected(CPUState *cpu)
+{
+ X86CPU *x86_cpu = X86_CPU(cpu);
+ CPUX86State *env = &x86_cpu->env;
+ uint64_t cr0 = env->cr[0];
+
+ return cr0 & CR0_PE_MASK;
+}
+
+bool x86_is_real(CPUState *cpu)
+{
+ return !x86_is_protected(cpu);
+}
+
+bool x86_is_v8086(CPUState *cpu)
+{
+ X86CPU *x86_cpu = X86_CPU(cpu);
+ CPUX86State *env = &x86_cpu->env;
+ return x86_is_protected(cpu) && (env->eflags & VM_MASK);
+}
+
+bool x86_is_long_mode(CPUState *cpu)
+{
+ X86CPU *x86_cpu = X86_CPU(cpu);
+ CPUX86State *env = &x86_cpu->env;
+ uint64_t efer = env->efer;
+ uint64_t lme_lma = (MSR_EFER_LME | MSR_EFER_LMA);
+
+ return ((efer & lme_lma) == lme_lma);
+}
+
+bool x86_is_long64_mode(CPUState *cpu)
+{
+ error_report("unimplemented: is_long64_mode()");
+ abort();
+}
+
+bool x86_is_paging_mode(CPUState *cpu)
+{
+ X86CPU *x86_cpu = X86_CPU(cpu);
+ CPUX86State *env = &x86_cpu->env;
+ uint64_t cr0 = env->cr[0];
+
+ return cr0 & CR0_PG_MASK;
+}
+
+bool x86_is_pae_enabled(CPUState *cpu)
+{
+ X86CPU *x86_cpu = X86_CPU(cpu);
+ CPUX86State *env = &x86_cpu->env;
+ uint64_t cr4 = env->cr[4];
+
+ return cr4 & CR4_PAE_MASK;
+}
+
+target_ulong linear_addr(CPUState *cpu, target_ulong addr, X86Seg seg)
+{
+ int ret;
+ target_ulong linear_addr;
+
+ ret = linearize(cpu, addr, &linear_addr, seg);
+ if (ret < 0) {
+ error_report("failed to linearize address");
+ abort();
+ }
+
+ return linear_addr;
+}
+
+target_ulong linear_addr_size(CPUState *cpu, target_ulong addr, int size,
+ X86Seg seg)
+{
+ switch (size) {
+ case 2:
+ addr = (uint16_t)addr;
+ break;
+ case 4:
+ addr = (uint32_t)addr;
+ break;
+ default:
+ break;
+ }
+ return linear_addr(cpu, addr, seg);
+}
+
+target_ulong linear_rip(CPUState *cpu, target_ulong rip)
+{
+ return linear_addr(cpu, rip, R_CS);
+}

View File

@ -1,386 +0,0 @@
From 2dcc4aa67b074801ed831ec53ebeed4fc232dade Mon Sep 17 00:00:00 2001
From: Magnus Kulke <magnuskulke@linux.microsoft.com>
Date: Tue, 16 Sep 2025 18:48:24 +0200
Subject: [PATCH] hw/intc: Generalize APIC helper names from kvm_* to accel_*
RH-Author: Igor Mammedov <imammedo@redhat.com>
RH-MergeRequest: 437: el10: x86: enablement for Azure L1VH OCP readiness
RH-Jira: RHEL-134212
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [4/30] 2622233d15ed5138cb143d2a5b54fb05c8574654
Rename APIC helper functions to use an accel_* prefix instead of kvm_*
to support use by accelerators other than KVM. This is a preparatory
step for integrating MSHV support with common APIC logic.
Signed-off-by: Magnus Kulke <magnuskulke@linux.microsoft.com>
Link: https://lore.kernel.org/r/20250916164847.77883-5-magnuskulke@linux.microsoft.com
[Remove dead definition of mshv_msi_via_irqfd_enabled. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit 638ac1c78457dd93ccd795b9c6c2673af8c7dd21)
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Patch-name: kvm-hw-intc-Generalize-APIC-helper-names-from-kvm_-to-ac.patch
Patch-id: 64
Patch-present-in-specfile: True
---
accel/accel-irq.c | 106 +++++++++++++++++++++++++++++++++++++
accel/meson.build | 2 +-
hw/intc/ioapic.c | 20 ++++---
hw/virtio/virtio-pci.c | 21 ++++----
include/system/accel-irq.h | 37 +++++++++++++
include/system/mshv.h | 17 ++++++
6 files changed, 185 insertions(+), 18 deletions(-)
create mode 100644 accel/accel-irq.c
create mode 100644 include/system/accel-irq.h
diff --git a/accel/accel-irq.c b/accel/accel-irq.c
new file mode 100644
index 0000000000..7f864e35c4
--- /dev/null
+++ b/accel/accel-irq.c
@@ -0,0 +1,106 @@
+/*
+ * Accelerated irqchip abstraction
+ *
+ * Copyright Microsoft, Corp. 2025
+ *
+ * Authors: Ziqiao Zhou <ziqiaozhou@microsoft.com>
+ * Magnus Kulke <magnuskulke@microsoft.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "hw/pci/msi.h"
+
+#include "system/kvm.h"
+#include "system/mshv.h"
+#include "system/accel-irq.h"
+
+int accel_irqchip_add_msi_route(KVMRouteChange *c, int vector, PCIDevice *dev)
+{
+#ifdef CONFIG_MSHV_IS_POSSIBLE
+ if (mshv_msi_via_irqfd_enabled()) {
+ return mshv_irqchip_add_msi_route(vector, dev);
+ }
+#endif
+ if (kvm_enabled()) {
+ return kvm_irqchip_add_msi_route(c, vector, dev);
+ }
+ return -ENOSYS;
+}
+
+int accel_irqchip_update_msi_route(int vector, MSIMessage msg, PCIDevice *dev)
+{
+#ifdef CONFIG_MSHV_IS_POSSIBLE
+ if (mshv_msi_via_irqfd_enabled()) {
+ return mshv_irqchip_update_msi_route(vector, msg, dev);
+ }
+#endif
+ if (kvm_enabled()) {
+ return kvm_irqchip_update_msi_route(kvm_state, vector, msg, dev);
+ }
+ return -ENOSYS;
+}
+
+void accel_irqchip_commit_route_changes(KVMRouteChange *c)
+{
+#ifdef CONFIG_MSHV_IS_POSSIBLE
+ if (mshv_msi_via_irqfd_enabled()) {
+ mshv_irqchip_commit_routes();
+ }
+#endif
+ if (kvm_enabled()) {
+ kvm_irqchip_commit_route_changes(c);
+ }
+}
+
+void accel_irqchip_commit_routes(void)
+{
+#ifdef CONFIG_MSHV_IS_POSSIBLE
+ if (mshv_msi_via_irqfd_enabled()) {
+ mshv_irqchip_commit_routes();
+ }
+#endif
+ if (kvm_enabled()) {
+ kvm_irqchip_commit_routes(kvm_state);
+ }
+}
+
+void accel_irqchip_release_virq(int virq)
+{
+#ifdef CONFIG_MSHV_IS_POSSIBLE
+ if (mshv_msi_via_irqfd_enabled()) {
+ mshv_irqchip_release_virq(virq);
+ }
+#endif
+ if (kvm_enabled()) {
+ kvm_irqchip_release_virq(kvm_state, virq);
+ }
+}
+
+int accel_irqchip_add_irqfd_notifier_gsi(EventNotifier *n, EventNotifier *rn,
+ int virq)
+{
+#ifdef CONFIG_MSHV_IS_POSSIBLE
+ if (mshv_msi_via_irqfd_enabled()) {
+ return mshv_irqchip_add_irqfd_notifier_gsi(n, rn, virq);
+ }
+#endif
+ if (kvm_enabled()) {
+ return kvm_irqchip_add_irqfd_notifier_gsi(kvm_state, n, rn, virq);
+ }
+ return -ENOSYS;
+}
+
+int accel_irqchip_remove_irqfd_notifier_gsi(EventNotifier *n, int virq)
+{
+#ifdef CONFIG_MSHV_IS_POSSIBLE
+ if (mshv_msi_via_irqfd_enabled()) {
+ return mshv_irqchip_remove_irqfd_notifier_gsi(n, virq);
+ }
+#endif
+ if (kvm_enabled()) {
+ return kvm_irqchip_remove_irqfd_notifier_gsi(kvm_state, n, virq);
+ }
+ return -ENOSYS;
+}
diff --git a/accel/meson.build b/accel/meson.build
index 25b0f100b5..6349efe682 100644
--- a/accel/meson.build
+++ b/accel/meson.build
@@ -1,6 +1,6 @@
common_ss.add(files('accel-common.c'))
specific_ss.add(files('accel-target.c'))
-system_ss.add(files('accel-system.c', 'accel-blocker.c', 'accel-qmp.c'))
+system_ss.add(files('accel-system.c', 'accel-blocker.c', 'accel-qmp.c', 'accel-irq.c'))
user_ss.add(files('accel-user.c'))
subdir('tcg')
diff --git a/hw/intc/ioapic.c b/hw/intc/ioapic.c
index 133bef852d..e431d00311 100644
--- a/hw/intc/ioapic.c
+++ b/hw/intc/ioapic.c
@@ -30,12 +30,18 @@
#include "hw/intc/ioapic_internal.h"
#include "hw/pci/msi.h"
#include "hw/qdev-properties.h"
+#include "system/accel-irq.h"
#include "system/kvm.h"
#include "system/system.h"
#include "hw/i386/apic-msidef.h"
#include "hw/i386/x86-iommu.h"
#include "trace.h"
+
+#if defined(CONFIG_KVM) || defined(CONFIG_MSHV)
+#define ACCEL_GSI_IRQFD_POSSIBLE
+#endif
+
#define APIC_DELIVERY_MODE_SHIFT 8
#define APIC_POLARITY_SHIFT 14
#define APIC_TRIG_MODE_SHIFT 15
@@ -191,10 +197,10 @@ static void ioapic_set_irq(void *opaque, int vector, int level)
static void ioapic_update_kvm_routes(IOAPICCommonState *s)
{
-#ifdef CONFIG_KVM
+#ifdef ACCEL_GSI_IRQFD_POSSIBLE
int i;
- if (kvm_irqchip_is_split()) {
+ if (accel_irqchip_is_split()) {
for (i = 0; i < IOAPIC_NUM_PINS; i++) {
MSIMessage msg;
struct ioapic_entry_info info;
@@ -202,15 +208,15 @@ static void ioapic_update_kvm_routes(IOAPICCommonState *s)
if (!info.masked) {
msg.address = info.addr;
msg.data = info.data;
- kvm_irqchip_update_msi_route(kvm_state, i, msg, NULL);
+ accel_irqchip_update_msi_route(i, msg, NULL);
}
}
- kvm_irqchip_commit_routes(kvm_state);
+ accel_irqchip_commit_routes();
}
#endif
}
-#ifdef CONFIG_KVM
+#ifdef ACCEL_KERNEL_GSI_IRQFD_POSSIBLE
static void ioapic_iec_notifier(void *private, bool global,
uint32_t index, uint32_t mask)
{
@@ -428,11 +434,11 @@ static const MemoryRegionOps ioapic_io_ops = {
static void ioapic_machine_done_notify(Notifier *notifier, void *data)
{
-#ifdef CONFIG_KVM
+#ifdef ACCEL_KERNEL_GSI_IRQFD_POSSIBLE
IOAPICCommonState *s = container_of(notifier, IOAPICCommonState,
machine_done);
- if (kvm_irqchip_is_split()) {
+ if (accel_irqchip_is_split()) {
X86IOMMUState *iommu = x86_iommu_get_default();
if (iommu) {
/* Register this IOAPIC with IOMMU IEC notifier, so that
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index 767216d795..0cdc16217f 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -34,6 +34,7 @@
#include "hw/pci/msi.h"
#include "hw/pci/msix.h"
#include "hw/loader.h"
+#include "system/accel-irq.h"
#include "system/kvm.h"
#include "hw/virtio/virtio-pci.h"
#include "qemu/range.h"
@@ -825,11 +826,11 @@ static int kvm_virtio_pci_vq_vector_use(VirtIOPCIProxy *proxy,
if (irqfd->users == 0) {
KVMRouteChange c = kvm_irqchip_begin_route_changes(kvm_state);
- ret = kvm_irqchip_add_msi_route(&c, vector, &proxy->pci_dev);
+ ret = accel_irqchip_add_msi_route(&c, vector, &proxy->pci_dev);
if (ret < 0) {
return ret;
}
- kvm_irqchip_commit_route_changes(&c);
+ accel_irqchip_commit_route_changes(&c);
irqfd->virq = ret;
}
irqfd->users++;
@@ -841,7 +842,7 @@ static void kvm_virtio_pci_vq_vector_release(VirtIOPCIProxy *proxy,
{
VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
if (--irqfd->users == 0) {
- kvm_irqchip_release_virq(kvm_state, irqfd->virq);
+ accel_irqchip_release_virq(irqfd->virq);
}
}
@@ -850,7 +851,7 @@ static int kvm_virtio_pci_irqfd_use(VirtIOPCIProxy *proxy,
unsigned int vector)
{
VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
- return kvm_irqchip_add_irqfd_notifier_gsi(kvm_state, n, NULL, irqfd->virq);
+ return accel_irqchip_add_irqfd_notifier_gsi(n, NULL, irqfd->virq);
}
static void kvm_virtio_pci_irqfd_release(VirtIOPCIProxy *proxy,
@@ -860,7 +861,7 @@ static void kvm_virtio_pci_irqfd_release(VirtIOPCIProxy *proxy,
VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
int ret;
- ret = kvm_irqchip_remove_irqfd_notifier_gsi(kvm_state, n, irqfd->virq);
+ ret = accel_irqchip_remove_irqfd_notifier_gsi(n, irqfd->virq);
assert(ret == 0);
}
static int virtio_pci_get_notifier(VirtIOPCIProxy *proxy, int queue_no,
@@ -995,12 +996,12 @@ static int virtio_pci_one_vector_unmask(VirtIOPCIProxy *proxy,
if (proxy->vector_irqfd) {
irqfd = &proxy->vector_irqfd[vector];
if (irqfd->msg.data != msg.data || irqfd->msg.address != msg.address) {
- ret = kvm_irqchip_update_msi_route(kvm_state, irqfd->virq, msg,
- &proxy->pci_dev);
+ ret = accel_irqchip_update_msi_route(irqfd->virq, msg,
+ &proxy->pci_dev);
if (ret < 0) {
return ret;
}
- kvm_irqchip_commit_routes(kvm_state);
+ accel_irqchip_commit_routes();
}
}
@@ -1229,7 +1230,7 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign)
VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
int r, n;
bool with_irqfd = msix_enabled(&proxy->pci_dev) &&
- kvm_msi_via_irqfd_enabled();
+ accel_msi_via_irqfd_enabled() ;
nvqs = MIN(nvqs, VIRTIO_QUEUE_MAX);
@@ -1433,7 +1434,7 @@ static void virtio_pci_set_vector(VirtIODevice *vdev,
uint16_t new_vector)
{
bool kvm_irqfd = (vdev->status & VIRTIO_CONFIG_S_DRIVER_OK) &&
- msix_enabled(&proxy->pci_dev) && kvm_msi_via_irqfd_enabled();
+ msix_enabled(&proxy->pci_dev) && accel_msi_via_irqfd_enabled();
if (new_vector == old_vector) {
return;
diff --git a/include/system/accel-irq.h b/include/system/accel-irq.h
new file mode 100644
index 0000000000..671fb7dfdb
--- /dev/null
+++ b/include/system/accel-irq.h
@@ -0,0 +1,37 @@
+/*
+ * Accelerated irqchip abstraction
+ *
+ * Copyright Microsoft, Corp. 2025
+ *
+ * Authors: Ziqiao Zhou <ziqiaozhou@microsoft.com>
+ * Magnus Kulke <magnuskulke@microsoft.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef SYSTEM_ACCEL_IRQ_H
+#define SYSTEM_ACCEL_IRQ_H
+#include "hw/pci/msi.h"
+#include "qemu/osdep.h"
+#include "system/kvm.h"
+#include "system/mshv.h"
+
+static inline bool accel_msi_via_irqfd_enabled(void)
+{
+ return mshv_msi_via_irqfd_enabled() || kvm_msi_via_irqfd_enabled();
+}
+
+static inline bool accel_irqchip_is_split(void)
+{
+ return mshv_msi_via_irqfd_enabled() || kvm_irqchip_is_split();
+}
+
+int accel_irqchip_add_msi_route(KVMRouteChange *c, int vector, PCIDevice *dev);
+int accel_irqchip_update_msi_route(int vector, MSIMessage msg, PCIDevice *dev);
+void accel_irqchip_commit_route_changes(KVMRouteChange *c);
+void accel_irqchip_commit_routes(void);
+void accel_irqchip_release_virq(int virq);
+int accel_irqchip_add_irqfd_notifier_gsi(EventNotifier *n, EventNotifier *rn,
+ int virq);
+int accel_irqchip_remove_irqfd_notifier_gsi(EventNotifier *n, int virq);
+#endif
diff --git a/include/system/mshv.h b/include/system/mshv.h
index 342f1ef6a9..2a504ed81f 100644
--- a/include/system/mshv.h
+++ b/include/system/mshv.h
@@ -22,4 +22,21 @@
#define CONFIG_MSHV_IS_POSSIBLE
#endif
+#ifdef CONFIG_MSHV_IS_POSSIBLE
+extern bool mshv_allowed;
+#define mshv_enabled() (mshv_allowed)
+#else /* CONFIG_MSHV_IS_POSSIBLE */
+#define mshv_enabled() false
+#endif
+#define mshv_msi_via_irqfd_enabled() false
+
+/* interrupt */
+int mshv_irqchip_add_msi_route(int vector, PCIDevice *dev);
+int mshv_irqchip_update_msi_route(int virq, MSIMessage msg, PCIDevice *dev);
+void mshv_irqchip_commit_routes(void);
+void mshv_irqchip_release_virq(int virq);
+int mshv_irqchip_add_irqfd_notifier_gsi(const EventNotifier *n,
+ const EventNotifier *rn, int virq);
+int mshv_irqchip_remove_irqfd_notifier_gsi(const EventNotifier *n, int virq);
+
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,330 +0,0 @@
From d0ad38d558917e602d8b85d0737e0dbb38c19a9c Mon Sep 17 00:00:00 2001
From: Magnus Kulke <magnuskulke@linux.microsoft.com>
Date: Tue, 16 Sep 2025 18:48:26 +0200
Subject: [PATCH] linux-headers/linux: Add mshv.h headers
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
RH-Author: Igor Mammedov <imammedo@redhat.com>
RH-MergeRequest: 437: el10: x86: enablement for Azure L1VH OCP readiness
RH-Jira: RHEL-134212
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [6/30] ef60621970d29f626815bdeb68bc8bdfe0061d0e
This file has been added to the tree by running `update-linux-header.sh`
on linux v6.16.
Signed-off-by: Magnus Kulke <magnuskulke@linux.microsoft.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Link: https://lore.kernel.org/r/20250916164847.77883-7-magnuskulke@linux.microsoft.com
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit a6d6878650a0f4982918e8cd9d7ea6c3c3c681f7)
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Patch-name: kvm-linux-headers-linux-Add-mshv.h-headers.patch
Patch-id: 66
Patch-present-in-specfile: True
---
linux-headers/linux/mshv.h | 291 +++++++++++++++++++++++++++++++++++++
1 file changed, 291 insertions(+)
create mode 100644 linux-headers/linux/mshv.h
diff --git a/linux-headers/linux/mshv.h b/linux-headers/linux/mshv.h
new file mode 100644
index 0000000000..5bc83db6a3
--- /dev/null
+++ b/linux-headers/linux/mshv.h
@@ -0,0 +1,291 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/*
+ * Userspace interfaces for /dev/mshv* devices and derived fds
+ *
+ * This file is divided into sections containing data structures and IOCTLs for
+ * a particular set of related devices or derived file descriptors.
+ *
+ * The IOCTL definitions are at the end of each section. They are grouped by
+ * device/fd, so that new IOCTLs can easily be added with a monotonically
+ * increasing number.
+ */
+#ifndef _LINUX_MSHV_H
+#define _LINUX_MSHV_H
+
+#include <linux/types.h>
+
+#define MSHV_IOCTL 0xB8
+
+/*
+ *******************************************
+ * Entry point to main VMM APIs: /dev/mshv *
+ *******************************************
+ */
+
+enum {
+ MSHV_PT_BIT_LAPIC,
+ MSHV_PT_BIT_X2APIC,
+ MSHV_PT_BIT_GPA_SUPER_PAGES,
+ MSHV_PT_BIT_COUNT,
+};
+
+#define MSHV_PT_FLAGS_MASK ((1 << MSHV_PT_BIT_COUNT) - 1)
+
+enum {
+ MSHV_PT_ISOLATION_NONE,
+ MSHV_PT_ISOLATION_COUNT,
+};
+
+/**
+ * struct mshv_create_partition - arguments for MSHV_CREATE_PARTITION
+ * @pt_flags: Bitmask of 1 << MSHV_PT_BIT_*
+ * @pt_isolation: MSHV_PT_ISOLATION_*
+ *
+ * Returns a file descriptor to act as a handle to a guest partition.
+ * At this point the partition is not yet initialized in the hypervisor.
+ * Some operations must be done with the partition in this state, e.g. setting
+ * so-called "early" partition properties. The partition can then be
+ * initialized with MSHV_INITIALIZE_PARTITION.
+ */
+struct mshv_create_partition {
+ __u64 pt_flags;
+ __u64 pt_isolation;
+};
+
+/* /dev/mshv */
+#define MSHV_CREATE_PARTITION _IOW(MSHV_IOCTL, 0x00, struct mshv_create_partition)
+
+/*
+ ************************
+ * Child partition APIs *
+ ************************
+ */
+
+struct mshv_create_vp {
+ __u32 vp_index;
+};
+
+enum {
+ MSHV_SET_MEM_BIT_WRITABLE,
+ MSHV_SET_MEM_BIT_EXECUTABLE,
+ MSHV_SET_MEM_BIT_UNMAP,
+ MSHV_SET_MEM_BIT_COUNT
+};
+
+#define MSHV_SET_MEM_FLAGS_MASK ((1 << MSHV_SET_MEM_BIT_COUNT) - 1)
+
+/* The hypervisor's "native" page size */
+#define MSHV_HV_PAGE_SIZE 0x1000
+
+/**
+ * struct mshv_user_mem_region - arguments for MSHV_SET_GUEST_MEMORY
+ * @size: Size of the memory region (bytes). Must be aligned to
+ * MSHV_HV_PAGE_SIZE
+ * @guest_pfn: Base guest page number to map
+ * @userspace_addr: Base address of userspace memory. Must be aligned to
+ * MSHV_HV_PAGE_SIZE
+ * @flags: Bitmask of 1 << MSHV_SET_MEM_BIT_*. If (1 << MSHV_SET_MEM_BIT_UNMAP)
+ * is set, ignore other bits.
+ * @rsvd: MBZ
+ *
+ * Map or unmap a region of userspace memory to Guest Physical Addresses (GPA).
+ * Mappings can't overlap in GPA space or userspace.
+ * To unmap, these fields must match an existing mapping.
+ */
+struct mshv_user_mem_region {
+ __u64 size;
+ __u64 guest_pfn;
+ __u64 userspace_addr;
+ __u8 flags;
+ __u8 rsvd[7];
+};
+
+enum {
+ MSHV_IRQFD_BIT_DEASSIGN,
+ MSHV_IRQFD_BIT_RESAMPLE,
+ MSHV_IRQFD_BIT_COUNT,
+};
+
+#define MSHV_IRQFD_FLAGS_MASK ((1 << MSHV_IRQFD_BIT_COUNT) - 1)
+
+struct mshv_user_irqfd {
+ __s32 fd;
+ __s32 resamplefd;
+ __u32 gsi;
+ __u32 flags;
+};
+
+enum {
+ MSHV_IOEVENTFD_BIT_DATAMATCH,
+ MSHV_IOEVENTFD_BIT_PIO,
+ MSHV_IOEVENTFD_BIT_DEASSIGN,
+ MSHV_IOEVENTFD_BIT_COUNT,
+};
+
+#define MSHV_IOEVENTFD_FLAGS_MASK ((1 << MSHV_IOEVENTFD_BIT_COUNT) - 1)
+
+struct mshv_user_ioeventfd {
+ __u64 datamatch;
+ __u64 addr; /* legal pio/mmio address */
+ __u32 len; /* 1, 2, 4, or 8 bytes */
+ __s32 fd;
+ __u32 flags;
+ __u8 rsvd[4];
+};
+
+struct mshv_user_irq_entry {
+ __u32 gsi;
+ __u32 address_lo;
+ __u32 address_hi;
+ __u32 data;
+};
+
+struct mshv_user_irq_table {
+ __u32 nr;
+ __u32 rsvd; /* MBZ */
+ struct mshv_user_irq_entry entries[];
+};
+
+enum {
+ MSHV_GPAP_ACCESS_TYPE_ACCESSED,
+ MSHV_GPAP_ACCESS_TYPE_DIRTY,
+ MSHV_GPAP_ACCESS_TYPE_COUNT /* Count of enum members */
+};
+
+enum {
+ MSHV_GPAP_ACCESS_OP_NOOP,
+ MSHV_GPAP_ACCESS_OP_CLEAR,
+ MSHV_GPAP_ACCESS_OP_SET,
+ MSHV_GPAP_ACCESS_OP_COUNT /* Count of enum members */
+};
+
+/**
+ * struct mshv_gpap_access_bitmap - arguments for MSHV_GET_GPAP_ACCESS_BITMAP
+ * @access_type: MSHV_GPAP_ACCESS_TYPE_* - The type of access to record in the
+ * bitmap
+ * @access_op: MSHV_GPAP_ACCESS_OP_* - Allows an optional clear or set of all
+ * the access states in the range, after retrieving the current
+ * states.
+ * @rsvd: MBZ
+ * @page_count: Number of pages
+ * @gpap_base: Base gpa page number
+ * @bitmap_ptr: Output buffer for bitmap, at least (page_count + 7) / 8 bytes
+ *
+ * Retrieve a bitmap of either ACCESSED or DIRTY bits for a given range of guest
+ * memory, and optionally clear or set the bits.
+ */
+struct mshv_gpap_access_bitmap {
+ __u8 access_type;
+ __u8 access_op;
+ __u8 rsvd[6];
+ __u64 page_count;
+ __u64 gpap_base;
+ __u64 bitmap_ptr;
+};
+
+/**
+ * struct mshv_root_hvcall - arguments for MSHV_ROOT_HVCALL
+ * @code: Hypercall code (HVCALL_*)
+ * @reps: in: Rep count ('repcount')
+ * out: Reps completed ('repcomp'). MBZ unless rep hvcall
+ * @in_sz: Size of input incl rep data. <= MSHV_HV_PAGE_SIZE
+ * @out_sz: Size of output buffer. <= MSHV_HV_PAGE_SIZE. MBZ if out_ptr is 0
+ * @status: in: MBZ
+ * out: HV_STATUS_* from hypercall
+ * @rsvd: MBZ
+ * @in_ptr: Input data buffer (struct hv_input_*). If used with partition or
+ * vp fd, partition id field is populated by kernel.
+ * @out_ptr: Output data buffer (optional)
+ */
+struct mshv_root_hvcall {
+ __u16 code;
+ __u16 reps;
+ __u16 in_sz;
+ __u16 out_sz;
+ __u16 status;
+ __u8 rsvd[6];
+ __u64 in_ptr;
+ __u64 out_ptr;
+};
+
+/* Partition fds created with MSHV_CREATE_PARTITION */
+#define MSHV_INITIALIZE_PARTITION _IO(MSHV_IOCTL, 0x00)
+#define MSHV_CREATE_VP _IOW(MSHV_IOCTL, 0x01, struct mshv_create_vp)
+#define MSHV_SET_GUEST_MEMORY _IOW(MSHV_IOCTL, 0x02, struct mshv_user_mem_region)
+#define MSHV_IRQFD _IOW(MSHV_IOCTL, 0x03, struct mshv_user_irqfd)
+#define MSHV_IOEVENTFD _IOW(MSHV_IOCTL, 0x04, struct mshv_user_ioeventfd)
+#define MSHV_SET_MSI_ROUTING _IOW(MSHV_IOCTL, 0x05, struct mshv_user_irq_table)
+#define MSHV_GET_GPAP_ACCESS_BITMAP _IOWR(MSHV_IOCTL, 0x06, struct mshv_gpap_access_bitmap)
+/* Generic hypercall */
+#define MSHV_ROOT_HVCALL _IOWR(MSHV_IOCTL, 0x07, struct mshv_root_hvcall)
+
+/*
+ ********************************
+ * VP APIs for child partitions *
+ ********************************
+ */
+
+#define MSHV_RUN_VP_BUF_SZ 256
+
+/*
+ * VP state pages may be mapped to userspace via mmap().
+ * To specify which state page, use MSHV_VP_MMAP_OFFSET_ values multiplied by
+ * the system page size.
+ * e.g.
+ * long page_size = sysconf(_SC_PAGE_SIZE);
+ * void *reg_page = mmap(NULL, MSHV_HV_PAGE_SIZE, PROT_READ|PROT_WRITE,
+ * MAP_SHARED, vp_fd,
+ * MSHV_VP_MMAP_OFFSET_REGISTERS * page_size);
+ */
+enum {
+ MSHV_VP_MMAP_OFFSET_REGISTERS,
+ MSHV_VP_MMAP_OFFSET_INTERCEPT_MESSAGE,
+ MSHV_VP_MMAP_OFFSET_GHCB,
+ MSHV_VP_MMAP_OFFSET_COUNT
+};
+
+/**
+ * struct mshv_run_vp - argument for MSHV_RUN_VP
+ * @msg_buf: On success, the intercept message is copied here. It can be
+ * interpreted using the relevant hypervisor definitions.
+ */
+struct mshv_run_vp {
+ __u8 msg_buf[MSHV_RUN_VP_BUF_SZ];
+};
+
+enum {
+ MSHV_VP_STATE_LAPIC, /* Local interrupt controller state (either arch) */
+ MSHV_VP_STATE_XSAVE, /* XSAVE data in compacted form (x86_64) */
+ MSHV_VP_STATE_SIMP,
+ MSHV_VP_STATE_SIEFP,
+ MSHV_VP_STATE_SYNTHETIC_TIMERS,
+ MSHV_VP_STATE_COUNT,
+};
+
+/**
+ * struct mshv_get_set_vp_state - arguments for MSHV_[GET,SET]_VP_STATE
+ * @type: MSHV_VP_STATE_*
+ * @rsvd: MBZ
+ * @buf_sz: in: 4k page-aligned size of buffer
+ * out: Actual size of data (on EINVAL, check this to see if buffer
+ * was too small)
+ * @buf_ptr: 4k page-aligned data buffer
+ */
+struct mshv_get_set_vp_state {
+ __u8 type;
+ __u8 rsvd[3];
+ __u32 buf_sz;
+ __u64 buf_ptr;
+};
+
+/* VP fds created with MSHV_CREATE_VP */
+#define MSHV_RUN_VP _IOR(MSHV_IOCTL, 0x00, struct mshv_run_vp)
+#define MSHV_GET_VP_STATE _IOWR(MSHV_IOCTL, 0x01, struct mshv_get_set_vp_state)
+#define MSHV_SET_VP_STATE _IOWR(MSHV_IOCTL, 0x02, struct mshv_get_set_vp_state)
+/*
+ * Generic hypercall
+ * Defined above in partition IOCTLs, avoid redefining it here
+ * #define MSHV_ROOT_HVCALL _IOWR(MSHV_IOCTL, 0x07, struct mshv_root_hvcall)
+ */
+
+#endif

View File

@ -1,292 +0,0 @@
From 22dc2eb8f036f562d7867d1827c4c66f4488a48e Mon Sep 17 00:00:00 2001
From: Magnus Kulke <magnuskulke@linux.microsoft.com>
Date: Thu, 2 Oct 2025 18:25:02 +0200
Subject: [PATCH] accel/mshv: Add accelerator skeleton
RH-Author: Igor Mammedov <imammedo@redhat.com>
RH-MergeRequest: 437: el10: x86: enablement for Azure L1VH OCP readiness
RH-Jira: RHEL-134212
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [7/30] 2bf55db3c9fbc6ce5964090f192be3699ae2ea00
Introduce the initial scaffold for the MSHV (Microsoft Hypervisor)
accelerator backend. This includes the basic directory structure and
stub implementations needed to integrate with QEMU's accelerator
framework.
Signed-off-by: Magnus Kulke <magnuskulke@linux.microsoft.com>
Link: https://lore.kernel.org/r/20250916164847.77883-8-magnuskulke@linux.microsoft.com
[Move include of linux/mshv.h in the per-target section; create
include/system/mshv_int.h. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit d0d2918f968c55628e17e2733b799fcefb50f16b)
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Patch-name: kvm-accel-mshv-Add-accelerator-skeleton.patch
Patch-id: 67
Patch-present-in-specfile: True
---
accel/meson.build | 1 +
accel/mshv/meson.build | 6 ++
accel/mshv/mshv-all.c | 144 ++++++++++++++++++++++++++++++++++++++
include/system/mshv.h | 12 ++++
include/system/mshv_int.h | 41 +++++++++++
5 files changed, 204 insertions(+)
create mode 100644 accel/mshv/meson.build
create mode 100644 accel/mshv/mshv-all.c
create mode 100644 include/system/mshv_int.h
diff --git a/accel/meson.build b/accel/meson.build
index 6349efe682..983dfd0bd5 100644
--- a/accel/meson.build
+++ b/accel/meson.build
@@ -10,6 +10,7 @@ if have_system
subdir('kvm')
subdir('xen')
subdir('stubs')
+ subdir('mshv')
endif
# qtest
diff --git a/accel/mshv/meson.build b/accel/mshv/meson.build
new file mode 100644
index 0000000000..4c03ac7921
--- /dev/null
+++ b/accel/mshv/meson.build
@@ -0,0 +1,6 @@
+mshv_ss = ss.source_set()
+mshv_ss.add(if_true: files(
+ 'mshv-all.c'
+))
+
+specific_ss.add_all(when: 'CONFIG_MSHV', if_true: mshv_ss)
diff --git a/accel/mshv/mshv-all.c b/accel/mshv/mshv-all.c
new file mode 100644
index 0000000000..ae12f0f58b
--- /dev/null
+++ b/accel/mshv/mshv-all.c
@@ -0,0 +1,144 @@
+/*
+ * QEMU MSHV support
+ *
+ * Copyright Microsoft, Corp. 2025
+ *
+ * Authors:
+ * Ziqiao Zhou <ziqiaozhou@microsoft.com>
+ * Magnus Kulke <magnuskulke@microsoft.com>
+ * Jinank Jain <jinankjain@microsoft.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qemu/error-report.h"
+#include "qemu/event_notifier.h"
+#include "qemu/module.h"
+#include "qemu/main-loop.h"
+#include "hw/boards.h"
+
+#include "hw/hyperv/hvhdk.h"
+#include "hw/hyperv/hvhdk_mini.h"
+#include "hw/hyperv/hvgdk.h"
+#include "linux/mshv.h"
+
+#include "qemu/accel.h"
+#include "qemu/guest-random.h"
+#include "accel/accel-ops.h"
+#include "accel/accel-cpu-ops.h"
+#include "system/cpus.h"
+#include "system/runstate.h"
+#include "system/accel-blocker.h"
+#include "system/address-spaces.h"
+#include "system/mshv.h"
+#include "system/mshv_int.h"
+#include "system/reset.h"
+#include "trace.h"
+#include <err.h>
+#include <stdint.h>
+#include <sys/ioctl.h>
+
+#define TYPE_MSHV_ACCEL ACCEL_CLASS_NAME("mshv")
+
+DECLARE_INSTANCE_CHECKER(MshvState, MSHV_STATE, TYPE_MSHV_ACCEL)
+
+bool mshv_allowed;
+
+MshvState *mshv_state;
+
+static int mshv_init(AccelState *as, MachineState *ms)
+{
+ error_report("unimplemented");
+ abort();
+}
+
+static void mshv_start_vcpu_thread(CPUState *cpu)
+{
+ error_report("unimplemented");
+ abort();
+}
+
+static void mshv_cpu_synchronize_post_init(CPUState *cpu)
+{
+ error_report("unimplemented");
+ abort();
+}
+
+static void mshv_cpu_synchronize_post_reset(CPUState *cpu)
+{
+ error_report("unimplemented");
+ abort();
+}
+
+static void mshv_cpu_synchronize_pre_loadvm(CPUState *cpu)
+{
+ error_report("unimplemented");
+ abort();
+}
+
+static void mshv_cpu_synchronize(CPUState *cpu)
+{
+ error_report("unimplemented");
+ abort();
+}
+
+static bool mshv_cpus_are_resettable(void)
+{
+ error_report("unimplemented");
+ abort();
+}
+
+static void mshv_accel_class_init(ObjectClass *oc, const void *data)
+{
+ AccelClass *ac = ACCEL_CLASS(oc);
+
+ ac->name = "MSHV";
+ ac->init_machine = mshv_init;
+ ac->allowed = &mshv_allowed;
+}
+
+static void mshv_accel_instance_init(Object *obj)
+{
+ MshvState *s = MSHV_STATE(obj);
+
+ s->vm = 0;
+}
+
+static const TypeInfo mshv_accel_type = {
+ .name = TYPE_MSHV_ACCEL,
+ .parent = TYPE_ACCEL,
+ .instance_init = mshv_accel_instance_init,
+ .class_init = mshv_accel_class_init,
+ .instance_size = sizeof(MshvState),
+};
+
+static void mshv_accel_ops_class_init(ObjectClass *oc, const void *data)
+{
+ AccelOpsClass *ops = ACCEL_OPS_CLASS(oc);
+
+ ops->create_vcpu_thread = mshv_start_vcpu_thread;
+ ops->synchronize_post_init = mshv_cpu_synchronize_post_init;
+ ops->synchronize_post_reset = mshv_cpu_synchronize_post_reset;
+ ops->synchronize_state = mshv_cpu_synchronize;
+ ops->synchronize_pre_loadvm = mshv_cpu_synchronize_pre_loadvm;
+ ops->cpus_are_resettable = mshv_cpus_are_resettable;
+ ops->handle_interrupt = generic_handle_interrupt;
+}
+
+static const TypeInfo mshv_accel_ops_type = {
+ .name = ACCEL_OPS_NAME("mshv"),
+ .parent = TYPE_ACCEL_OPS,
+ .class_init = mshv_accel_ops_class_init,
+ .abstract = true,
+};
+
+static void mshv_type_init(void)
+{
+ type_register_static(&mshv_accel_type);
+ type_register_static(&mshv_accel_ops_type);
+}
+
+type_init(mshv_type_init);
diff --git a/include/system/mshv.h b/include/system/mshv.h
index 2a504ed81f..434ea9682e 100644
--- a/include/system/mshv.h
+++ b/include/system/mshv.h
@@ -14,8 +14,17 @@
#ifndef QEMU_MSHV_H
#define QEMU_MSHV_H
+#include "qemu/osdep.h"
+#include "qemu/accel.h"
+#include "hw/hyperv/hyperv-proto.h"
+#include "hw/hyperv/hvhdk.h"
+#include "qapi/qapi-types-common.h"
+#include "system/memory.h"
+#include "accel/accel-ops.h"
+
#ifdef COMPILING_PER_TARGET
#ifdef CONFIG_MSHV
+#include <linux/mshv.h>
#define CONFIG_MSHV_IS_POSSIBLE
#endif
#else
@@ -30,6 +39,9 @@ extern bool mshv_allowed;
#endif
#define mshv_msi_via_irqfd_enabled() false
+typedef struct MshvState MshvState;
+extern MshvState *mshv_state;
+
/* interrupt */
int mshv_irqchip_add_msi_route(int vector, PCIDevice *dev);
int mshv_irqchip_update_msi_route(int virq, MSIMessage msg, PCIDevice *dev);
diff --git a/include/system/mshv_int.h b/include/system/mshv_int.h
new file mode 100644
index 0000000000..132491b599
--- /dev/null
+++ b/include/system/mshv_int.h
@@ -0,0 +1,41 @@
+/*
+ * QEMU MSHV support
+ *
+ * Copyright Microsoft, Corp. 2025
+ *
+ * Authors: Ziqiao Zhou <ziqiaozhou@microsoft.com>
+ * Magnus Kulke <magnuskulke@microsoft.com>
+ * Jinank Jain <jinankjain@microsoft.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ */
+
+#ifndef QEMU_MSHV_INT_H
+#define QEMU_MSHV_INT_H
+
+struct AccelCPUState {
+ int cpufd;
+ bool dirty;
+};
+
+typedef struct MshvMemoryListener {
+ MemoryListener listener;
+ int as_id;
+} MshvMemoryListener;
+
+typedef struct MshvAddressSpace {
+ MshvMemoryListener *ml;
+ AddressSpace *as;
+} MshvAddressSpace;
+
+struct MshvState {
+ AccelState parent_obj;
+ int vm;
+ MshvMemoryListener memory_listener;
+ /* number of listeners */
+ int nr_as;
+ MshvAddressSpace *as;
+};
+
+#endif

View File

@ -1,173 +0,0 @@
From 49e8b7e37e4e481be6a821ec6482c4e8b04e4573 Mon Sep 17 00:00:00 2001
From: Magnus Kulke <magnuskulke@linux.microsoft.com>
Date: Tue, 16 Sep 2025 18:48:28 +0200
Subject: [PATCH] accel/mshv: Register memory region listeners
RH-Author: Igor Mammedov <imammedo@redhat.com>
RH-MergeRequest: 437: el10: x86: enablement for Azure L1VH OCP readiness
RH-Jira: RHEL-134212
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [8/30] ecd0d05d8f04c400ad1d9c428f89b23b12889968
Add memory listener hooks for the MSHV accelerator to track guest
memory regions. This enables the backend to respond to region
additions, removals and will be used to manage guest memory mappings
inside the hypervisor.
Actually registering physical memory in the hypervisor is still stubbed
out.
Signed-off-by: Magnus Kulke <magnuskulke@linux.microsoft.com>
Link: https://lore.kernel.org/r/20250916164847.77883-9-magnuskulke@linux.microsoft.com
[mshv.h/mshv_int.h split. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit 5006ea1344d134356a9b2e1afd521cf8df0c6a85)
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Patch-name: kvm-accel-mshv-Register-memory-region-listeners.patch
Patch-id: 68
Patch-present-in-specfile: True
---
accel/mshv/mem.c | 25 +++++++++++++++
accel/mshv/meson.build | 1 +
accel/mshv/mshv-all.c | 67 +++++++++++++++++++++++++++++++++++++--
include/system/mshv_int.h | 4 +++
4 files changed, 95 insertions(+), 2 deletions(-)
create mode 100644 accel/mshv/mem.c
diff --git a/accel/mshv/mem.c b/accel/mshv/mem.c
new file mode 100644
index 0000000000..9889918c31
--- /dev/null
+++ b/accel/mshv/mem.c
@@ -0,0 +1,25 @@
+/*
+ * QEMU MSHV support
+ *
+ * Copyright Microsoft, Corp. 2025
+ *
+ * Authors:
+ * Magnus Kulke <magnuskulke@microsoft.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "system/address-spaces.h"
+#include "system/mshv.h"
+#include "system/mshv_int.h"
+
+void mshv_set_phys_mem(MshvMemoryListener *mml, MemoryRegionSection *section,
+ bool add)
+{
+ error_report("unimplemented");
+ abort();
+}
+
diff --git a/accel/mshv/meson.build b/accel/mshv/meson.build
index 4c03ac7921..8a6beb3fb1 100644
--- a/accel/mshv/meson.build
+++ b/accel/mshv/meson.build
@@ -1,5 +1,6 @@
mshv_ss = ss.source_set()
mshv_ss.add(if_true: files(
+ 'mem.c',
'mshv-all.c'
))
diff --git a/accel/mshv/mshv-all.c b/accel/mshv/mshv-all.c
index ae12f0f58b..a684a36677 100644
--- a/accel/mshv/mshv-all.c
+++ b/accel/mshv/mshv-all.c
@@ -49,10 +49,73 @@ bool mshv_allowed;
MshvState *mshv_state;
+static void mem_region_add(MemoryListener *listener,
+ MemoryRegionSection *section)
+{
+ MshvMemoryListener *mml;
+ mml = container_of(listener, MshvMemoryListener, listener);
+ memory_region_ref(section->mr);
+ mshv_set_phys_mem(mml, section, true);
+}
+
+static void mem_region_del(MemoryListener *listener,
+ MemoryRegionSection *section)
+{
+ MshvMemoryListener *mml;
+ mml = container_of(listener, MshvMemoryListener, listener);
+ mshv_set_phys_mem(mml, section, false);
+ memory_region_unref(section->mr);
+}
+
+static MemoryListener mshv_memory_listener = {
+ .name = "mshv",
+ .priority = MEMORY_LISTENER_PRIORITY_ACCEL,
+ .region_add = mem_region_add,
+ .region_del = mem_region_del,
+};
+
+static MemoryListener mshv_io_listener = {
+ .name = "mshv", .priority = MEMORY_LISTENER_PRIORITY_DEV_BACKEND,
+ /* MSHV does not support PIO eventfd */
+};
+
+static void register_mshv_memory_listener(MshvState *s, MshvMemoryListener *mml,
+ AddressSpace *as, int as_id,
+ const char *name)
+{
+ int i;
+
+ mml->listener = mshv_memory_listener;
+ mml->listener.name = name;
+ memory_listener_register(&mml->listener, as);
+ for (i = 0; i < s->nr_as; ++i) {
+ if (!s->as[i].as) {
+ s->as[i].as = as;
+ s->as[i].ml = mml;
+ break;
+ }
+ }
+}
+
static int mshv_init(AccelState *as, MachineState *ms)
{
- error_report("unimplemented");
- abort();
+ MshvState *s;
+ s = MSHV_STATE(as);
+
+ accel_blocker_init();
+
+ s->vm = 0;
+
+ s->nr_as = 1;
+ s->as = g_new0(MshvAddressSpace, s->nr_as);
+
+ mshv_state = s;
+
+ register_mshv_memory_listener(s, &s->memory_listener, &address_space_memory,
+ 0, "mshv-memory");
+ memory_listener_register(&mshv_io_listener, &address_space_io);
+
+ return 0;
}
static void mshv_start_vcpu_thread(CPUState *cpu)
diff --git a/include/system/mshv_int.h b/include/system/mshv_int.h
index 132491b599..cfa177ff72 100644
--- a/include/system/mshv_int.h
+++ b/include/system/mshv_int.h
@@ -38,4 +38,8 @@ struct MshvState {
MshvAddressSpace *as;
};
+/* memory */
+void mshv_set_phys_mem(MshvMemoryListener *mml, MemoryRegionSection *section,
+ bool add);
+
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,219 +0,0 @@
From d6f3367b197d060d35aeeb781828d0ca4e3dc584 Mon Sep 17 00:00:00 2001
From: Paolo Bonzini <pbonzini@redhat.com>
Date: Tue, 2 Sep 2025 07:17:09 +0200
Subject: [PATCH] treewide: rename qemu_wait_io_event/qemu_wait_io_event_common
RH-Author: Igor Mammedov <imammedo@redhat.com>
RH-MergeRequest: 437: el10: x86: enablement for Azure L1VH OCP readiness
RH-Jira: RHEL-134212
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [10/30] 501e99aab6fb49429b23c688cffbecdf283c89dd
Do so before extending it to the user-mode emulators, where there is no
such thing as an "I/O thread".
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit 871de7078fcaf597605576b97b32fab14722ea43)
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Conflicts: (due to missing cpu exit/interrupt_request refactoring)
cpu-common.c
include/hw/core/cpu.h
Patch-name: kvm-treewide-rename-qemu_wait_io_event-qemu_wait_io_even.patch
Patch-id: 70
Patch-present-in-specfile: True
---
accel/dummy-cpus.c | 2 +-
accel/hvf/hvf-accel-ops.c | 2 +-
accel/kvm/kvm-accel-ops.c | 2 +-
accel/tcg/tcg-accel-ops-mttcg.c | 2 +-
accel/tcg/tcg-accel-ops-rr.c | 4 ++--
cpu-common.c | 1 +
include/hw/core/cpu.h | 9 +++++++++
include/system/cpus.h | 4 ++--
system/cpus.c | 6 +++---
target/i386/nvmm/nvmm-accel-ops.c | 2 +-
target/i386/whpx/whpx-accel-ops.c | 2 +-
11 files changed, 23 insertions(+), 13 deletions(-)
diff --git a/accel/dummy-cpus.c b/accel/dummy-cpus.c
index 03cfc0fa01..225a47c31f 100644
--- a/accel/dummy-cpus.c
+++ b/accel/dummy-cpus.c
@@ -57,7 +57,7 @@ static void *dummy_cpu_thread_fn(void *arg)
qemu_sem_wait(&cpu->sem);
#endif
bql_lock();
- qemu_wait_io_event(cpu);
+ qemu_process_cpu_events(cpu);
} while (!cpu->unplug);
bql_unlock();
diff --git a/accel/hvf/hvf-accel-ops.c b/accel/hvf/hvf-accel-ops.c
index d488d6afba..7a27bdadb4 100644
--- a/accel/hvf/hvf-accel-ops.c
+++ b/accel/hvf/hvf-accel-ops.c
@@ -198,7 +198,7 @@ static void *hvf_cpu_thread_fn(void *arg)
cpu_handle_guest_debug(cpu);
}
}
- qemu_wait_io_event(cpu);
+ qemu_process_cpu_events(cpu);
} while (!cpu->unplug || cpu_can_run(cpu));
hvf_vcpu_destroy(cpu);
diff --git a/accel/kvm/kvm-accel-ops.c b/accel/kvm/kvm-accel-ops.c
index b709187c7d..65a7f76a69 100644
--- a/accel/kvm/kvm-accel-ops.c
+++ b/accel/kvm/kvm-accel-ops.c
@@ -53,7 +53,7 @@ static void *kvm_vcpu_thread_fn(void *arg)
cpu_handle_guest_debug(cpu);
}
}
- qemu_wait_io_event(cpu);
+ qemu_process_cpu_events(cpu);
} while (!cpu->unplug || cpu_can_run(cpu));
kvm_destroy_vcpu(cpu);
diff --git a/accel/tcg/tcg-accel-ops-mttcg.c b/accel/tcg/tcg-accel-ops-mttcg.c
index 337b993d3d..a3255000df 100644
--- a/accel/tcg/tcg-accel-ops-mttcg.c
+++ b/accel/tcg/tcg-accel-ops-mttcg.c
@@ -113,7 +113,7 @@ static void *mttcg_cpu_thread_fn(void *arg)
}
}
- qemu_wait_io_event(cpu);
+ qemu_process_cpu_events(cpu);
} while (!cpu->unplug || cpu_can_run(cpu));
tcg_cpu_destroy(cpu);
diff --git a/accel/tcg/tcg-accel-ops-rr.c b/accel/tcg/tcg-accel-ops-rr.c
index 6eec5c9eee..60ad1a39f0 100644
--- a/accel/tcg/tcg-accel-ops-rr.c
+++ b/accel/tcg/tcg-accel-ops-rr.c
@@ -117,7 +117,7 @@ static void rr_wait_io_event(void)
rr_start_kick_timer();
CPU_FOREACH(cpu) {
- qemu_wait_io_event_common(cpu);
+ qemu_process_cpu_events_common(cpu);
}
}
@@ -203,7 +203,7 @@ static void *rr_cpu_thread_fn(void *arg)
/* process any pending work */
CPU_FOREACH(cpu) {
current_cpu = cpu;
- qemu_wait_io_event_common(cpu);
+ qemu_process_cpu_events_common(cpu);
}
}
diff --git a/cpu-common.c b/cpu-common.c
index ef5757d23b..8e4cbac290 100644
--- a/cpu-common.c
+++ b/cpu-common.c
@@ -137,6 +137,7 @@ static void queue_work_on_cpu(CPUState *cpu, struct qemu_work_item *wi)
wi->done = false;
qemu_mutex_unlock(&cpu->work_mutex);
+ /* conflict fixup due missing exit and interrupt refactoring */
qemu_cpu_kick(cpu);
}
diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h
index 5eaf41a566..fadd6c5ac0 100644
--- a/include/hw/core/cpu.h
+++ b/include/hw/core/cpu.h
@@ -422,6 +422,15 @@ struct qemu_work_item;
* valid under cpu_list_lock.
* @created: Indicates whether the CPU thread has been successfully created.
* @halt_cond: condition variable sleeping threads can wait on.
+ * @exit_request: Another thread requests the CPU to call qemu_process_cpu_events().
+ * Should be read only by CPU thread with load-acquire, to synchronize with
+ * other threads' store-release operation.
+ *
+ * In some cases, accelerator-specific code will write exit_request from
+ * within the same thread, to "bump" the effect of qemu_cpu_kick() to
+ * the one provided by cpu_exit(), especially when processing interrupt
+ * flags. In this case, the write and read happen in the same thread
+ * and the write therefore can use qemu_atomic_set().
* @interrupt_request: Indicates a pending interrupt request.
* @halted: Nonzero if the CPU is in suspended state.
* @stop: Indicates a pending stop request.
diff --git a/include/system/cpus.h b/include/system/cpus.h
index 69be6a77a7..4aebec4870 100644
--- a/include/system/cpus.h
+++ b/include/system/cpus.h
@@ -17,8 +17,8 @@ bool cpu_work_list_empty(CPUState *cpu);
bool cpu_thread_is_idle(CPUState *cpu);
bool all_cpu_threads_idle(void);
bool cpu_can_run(CPUState *cpu);
-void qemu_wait_io_event_common(CPUState *cpu);
-void qemu_wait_io_event(CPUState *cpu);
+void qemu_process_cpu_events_common(CPUState *cpu);
+void qemu_process_cpu_events(CPUState *cpu);
void cpu_thread_signal_created(CPUState *cpu);
void cpu_thread_signal_destroyed(CPUState *cpu);
void cpu_handle_guest_debug(CPUState *cpu);
diff --git a/system/cpus.c b/system/cpus.c
index 256723558d..efffbd8df6 100644
--- a/system/cpus.c
+++ b/system/cpus.c
@@ -444,7 +444,7 @@ static void qemu_cpu_stop(CPUState *cpu, bool exit)
qemu_cond_broadcast(&qemu_pause_cond);
}
-void qemu_wait_io_event_common(CPUState *cpu)
+void qemu_process_cpu_events_common(CPUState *cpu)
{
qatomic_set_mb(&cpu->thread_kicked, false);
if (cpu->stop) {
@@ -453,7 +453,7 @@ void qemu_wait_io_event_common(CPUState *cpu)
process_queued_cpu_work(cpu);
}
-void qemu_wait_io_event(CPUState *cpu)
+void qemu_process_cpu_events(CPUState *cpu)
{
bool slept = false;
@@ -468,7 +468,7 @@ void qemu_wait_io_event(CPUState *cpu)
qemu_plugin_vcpu_resume_cb(cpu);
}
- qemu_wait_io_event_common(cpu);
+ qemu_process_cpu_events_common(cpu);
}
void cpus_kick_thread(CPUState *cpu)
diff --git a/target/i386/nvmm/nvmm-accel-ops.c b/target/i386/nvmm/nvmm-accel-ops.c
index 3799260bbd..c7b1d0f1d3 100644
--- a/target/i386/nvmm/nvmm-accel-ops.c
+++ b/target/i386/nvmm/nvmm-accel-ops.c
@@ -51,7 +51,7 @@ static void *qemu_nvmm_cpu_thread_fn(void *arg)
while (cpu_thread_is_idle(cpu)) {
qemu_cond_wait_bql(cpu->halt_cond);
}
- qemu_wait_io_event_common(cpu);
+ qemu_process_cpu_events_common(cpu);
} while (!cpu->unplug || cpu_can_run(cpu));
nvmm_destroy_vcpu(cpu);
diff --git a/target/i386/whpx/whpx-accel-ops.c b/target/i386/whpx/whpx-accel-ops.c
index da58805b1a..2ca4ee0263 100644
--- a/target/i386/whpx/whpx-accel-ops.c
+++ b/target/i386/whpx/whpx-accel-ops.c
@@ -51,7 +51,7 @@ static void *whpx_cpu_thread_fn(void *arg)
while (cpu_thread_is_idle(cpu)) {
qemu_cond_wait_bql(cpu->halt_cond);
}
- qemu_wait_io_event_common(cpu);
+ qemu_process_cpu_events_common(cpu);
} while (!cpu->unplug || cpu_can_run(cpu));
whpx_destroy_vcpu(cpu);

View File

@ -1,418 +0,0 @@
From 2d8f8fb4690faad8f1b9a93af2aad04a0502acb2 Mon Sep 17 00:00:00 2001
From: Magnus Kulke <magnuskulke@linux.microsoft.com>
Date: Tue, 16 Sep 2025 18:48:30 +0200
Subject: [PATCH] accel/mshv: Add vCPU creation and execution loop
RH-Author: Igor Mammedov <imammedo@redhat.com>
RH-MergeRequest: 437: el10: x86: enablement for Azure L1VH OCP readiness
RH-Jira: RHEL-134212
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [11/30] e235ebda329666192a3bf95fb4fee018f5f5f10e
Create MSHV vCPUs using MSHV_CREATE_VP and initialize their state.
Register the MSHV CPU execution loop loop with the QEMU accelerator
framework to enable guest code execution.
The target/i386 functionality is still mostly stubbed out and will be
populated in a later commit in this series.
Signed-off-by: Magnus Kulke <magnuskulke@linux.microsoft.com>
Link: https://lore.kernel.org/r/20250916164847.77883-11-magnuskulke@linux.microsoft.com
[Fix g_free/g_clear_pointer confusion; rename qemu_wait_io_event;
mshv.h/mshv_int.h split. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit 4dc5d4257259764b6fcd035870517fc4140d8962)
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Patch-name: kvm-accel-mshv-Add-vCPU-creation-and-execution-loop.patch
Patch-id: 71
Patch-present-in-specfile: True
---
accel/mshv/mshv-all.c | 186 +++++++++++++++++++++++++++++++++---
accel/mshv/trace-events | 2 +
include/system/mshv.h | 2 +-
include/system/mshv_int.h | 20 ++++
target/i386/mshv/mshv-cpu.c | 63 ++++++++++++
5 files changed, 260 insertions(+), 13 deletions(-)
diff --git a/accel/mshv/mshv-all.c b/accel/mshv/mshv-all.c
index 653195c57c..e02421d79d 100644
--- a/accel/mshv/mshv-all.c
+++ b/accel/mshv/mshv-all.c
@@ -393,6 +393,24 @@ int mshv_hvcall(int fd, const struct mshv_root_hvcall *args)
return ret;
}
+static int mshv_init_vcpu(CPUState *cpu)
+{
+ int vm_fd = mshv_state->vm;
+ uint8_t vp_index = cpu->cpu_index;
+ int ret;
+
+ mshv_arch_init_vcpu(cpu);
+ cpu->accel = g_new0(AccelCPUState, 1);
+
+ ret = mshv_create_vcpu(vm_fd, vp_index, &cpu->accel->cpufd);
+ if (ret < 0) {
+ return -1;
+ }
+
+ cpu->accel->dirty = true;
+
+ return 0;
+}
static int mshv_init(AccelState *as, MachineState *ms)
{
@@ -415,6 +433,8 @@ static int mshv_init(AccelState *as, MachineState *ms)
return -1;
}
+ mshv_init_mmio_emu();
+
mshv_init_msicontrol();
ret = create_vm(mshv_fd, &vm_fd);
@@ -444,40 +464,182 @@ static int mshv_init(AccelState *as, MachineState *ms)
return 0;
}
+static int mshv_destroy_vcpu(CPUState *cpu)
+{
+ int cpu_fd = mshv_vcpufd(cpu);
+ int vm_fd = mshv_state->vm;
+
+ mshv_remove_vcpu(vm_fd, cpu_fd);
+ mshv_vcpufd(cpu) = 0;
+
+ mshv_arch_destroy_vcpu(cpu);
+ g_clear_pointer(&cpu->accel, g_free);
+ return 0;
+}
+
+static int mshv_cpu_exec(CPUState *cpu)
+{
+ hv_message mshv_msg;
+ enum MshvVmExit exit_reason;
+ int ret = 0;
+
+ bql_unlock();
+ cpu_exec_start(cpu);
+
+ do {
+ if (cpu->accel->dirty) {
+ ret = mshv_arch_put_registers(cpu);
+ if (ret) {
+ error_report("Failed to put registers after init: %s",
+ strerror(-ret));
+ ret = -1;
+ break;
+ }
+ cpu->accel->dirty = false;
+ }
+
+ ret = mshv_run_vcpu(mshv_state->vm, cpu, &mshv_msg, &exit_reason);
+ if (ret < 0) {
+ error_report("Failed to run on vcpu %d", cpu->cpu_index);
+ abort();
+ }
+
+ switch (exit_reason) {
+ case MshvVmExitIgnore:
+ break;
+ default:
+ ret = EXCP_INTERRUPT;
+ break;
+ }
+ } while (ret == 0);
+
+ cpu_exec_end(cpu);
+ bql_lock();
+
+ if (ret < 0) {
+ cpu_dump_state(cpu, stderr, CPU_DUMP_CODE);
+ vm_stop(RUN_STATE_INTERNAL_ERROR);
+ }
+
+ return ret;
+}
+
+static void *mshv_vcpu_thread(void *arg)
+{
+ CPUState *cpu = arg;
+ int ret;
+
+ rcu_register_thread();
+
+ bql_lock();
+ qemu_thread_get_self(cpu->thread);
+ cpu->thread_id = qemu_get_thread_id();
+ current_cpu = cpu;
+ ret = mshv_init_vcpu(cpu);
+ if (ret < 0) {
+ error_report("Failed to init vcpu %d", cpu->cpu_index);
+ goto cleanup;
+ }
+
+ /* signal CPU creation */
+ cpu_thread_signal_created(cpu);
+ qemu_guest_random_seed_thread_part2(cpu->random_seed);
+
+ do {
+ qemu_process_cpu_events(cpu);
+ if (cpu_can_run(cpu)) {
+ mshv_cpu_exec(cpu);
+ }
+ } while (!cpu->unplug || cpu_can_run(cpu));
+
+ mshv_destroy_vcpu(cpu);
+cleanup:
+ cpu_thread_signal_destroyed(cpu);
+ bql_unlock();
+ rcu_unregister_thread();
+ return NULL;
+}
+
static void mshv_start_vcpu_thread(CPUState *cpu)
{
- error_report("unimplemented");
- abort();
+ char thread_name[VCPU_THREAD_NAME_SIZE];
+
+ cpu->thread = g_malloc0(sizeof(QemuThread));
+ cpu->halt_cond = g_malloc0(sizeof(QemuCond));
+
+ qemu_cond_init(cpu->halt_cond);
+
+ trace_mshv_start_vcpu_thread(thread_name, cpu->cpu_index);
+ qemu_thread_create(cpu->thread, thread_name, mshv_vcpu_thread, cpu,
+ QEMU_THREAD_JOINABLE);
+}
+
+static void do_mshv_cpu_synchronize_post_init(CPUState *cpu,
+ run_on_cpu_data arg)
+{
+ int ret = mshv_arch_put_registers(cpu);
+ if (ret < 0) {
+ error_report("Failed to put registers after init: %s", strerror(-ret));
+ abort();
+ }
+
+ cpu->accel->dirty = false;
}
static void mshv_cpu_synchronize_post_init(CPUState *cpu)
{
- error_report("unimplemented");
- abort();
+ run_on_cpu(cpu, do_mshv_cpu_synchronize_post_init, RUN_ON_CPU_NULL);
}
static void mshv_cpu_synchronize_post_reset(CPUState *cpu)
{
- error_report("unimplemented");
- abort();
+ int ret = mshv_arch_put_registers(cpu);
+ if (ret) {
+ error_report("Failed to put registers after reset: %s",
+ strerror(-ret));
+ cpu_dump_state(cpu, stderr, CPU_DUMP_CODE);
+ vm_stop(RUN_STATE_INTERNAL_ERROR);
+ }
+ cpu->accel->dirty = false;
+}
+
+static void do_mshv_cpu_synchronize_pre_loadvm(CPUState *cpu,
+ run_on_cpu_data arg)
+{
+ cpu->accel->dirty = true;
}
static void mshv_cpu_synchronize_pre_loadvm(CPUState *cpu)
{
- error_report("unimplemented");
- abort();
+ run_on_cpu(cpu, do_mshv_cpu_synchronize_pre_loadvm, RUN_ON_CPU_NULL);
+}
+
+static void do_mshv_cpu_synchronize(CPUState *cpu, run_on_cpu_data arg)
+{
+ if (!cpu->accel->dirty) {
+ int ret = mshv_load_regs(cpu);
+ if (ret < 0) {
+ error_report("Failed to load registers for vcpu %d",
+ cpu->cpu_index);
+
+ cpu_dump_state(cpu, stderr, CPU_DUMP_CODE);
+ vm_stop(RUN_STATE_INTERNAL_ERROR);
+ }
+
+ cpu->accel->dirty = true;
+ }
}
static void mshv_cpu_synchronize(CPUState *cpu)
{
- error_report("unimplemented");
- abort();
+ if (!cpu->accel->dirty) {
+ run_on_cpu(cpu, do_mshv_cpu_synchronize, RUN_ON_CPU_NULL);
+ }
}
static bool mshv_cpus_are_resettable(void)
{
- error_report("unimplemented");
- abort();
+ return false;
}
static void mshv_accel_class_init(ObjectClass *oc, const void *data)
diff --git a/accel/mshv/trace-events b/accel/mshv/trace-events
index 6130c4abf8..a4dffeb24a 100644
--- a/accel/mshv/trace-events
+++ b/accel/mshv/trace-events
@@ -3,6 +3,8 @@
#
# SPDX-License-Identifier: GPL-2.0-or-later
+mshv_start_vcpu_thread(const char* thread, uint32_t cpu) "thread=%s cpu_index=%d"
+
mshv_set_memory(bool add, uint64_t gpa, uint64_t size, uint64_t user_addr, bool readonly, int ret) "add=%d gpa=0x%" PRIx64 " size=0x%" PRIx64 " user=0x%" PRIx64 " readonly=%d result=%d"
mshv_mem_ioeventfd_add(uint64_t addr, uint32_t size, uint32_t data) "addr=0x%" PRIx64 " size=%d data=0x%x"
mshv_mem_ioeventfd_del(uint64_t addr, uint32_t size, uint32_t data) "addr=0x%" PRIx64 " size=%d data=0x%x"
diff --git a/include/system/mshv.h b/include/system/mshv.h
index 1011e81df4..bbc42f4dc3 100644
--- a/include/system/mshv.h
+++ b/include/system/mshv.h
@@ -41,7 +41,7 @@ extern bool mshv_allowed;
#define mshv_msi_via_irqfd_enabled() mshv_enabled()
#else /* CONFIG_MSHV_IS_POSSIBLE */
#define mshv_enabled() false
-#define mshv_msi_via_irqfd_enabled() false
+#define mshv_msi_via_irqfd_enabled() mshv_enabled()
#endif
typedef struct MshvState MshvState;
diff --git a/include/system/mshv_int.h b/include/system/mshv_int.h
index b36124a0ea..fb80f69772 100644
--- a/include/system/mshv_int.h
+++ b/include/system/mshv_int.h
@@ -14,6 +14,8 @@
#ifndef QEMU_MSHV_INT_H
#define QEMU_MSHV_INT_H
+typedef struct hyperv_message hv_message;
+
struct AccelCPUState {
int cpufd;
bool dirty;
@@ -44,6 +46,24 @@ typedef struct MshvMsiControl {
GHashTable *gsi_routes;
} MshvMsiControl;
+#define mshv_vcpufd(cpu) (cpu->accel->cpufd)
+
+/* cpu */
+typedef enum MshvVmExit {
+ MshvVmExitIgnore = 0,
+ MshvVmExitShutdown = 1,
+ MshvVmExitSpecial = 2,
+} MshvVmExit;
+
+void mshv_init_mmio_emu(void);
+int mshv_create_vcpu(int vm_fd, uint8_t vp_index, int *cpu_fd);
+void mshv_remove_vcpu(int vm_fd, int cpu_fd);
+int mshv_run_vcpu(int vm_fd, CPUState *cpu, hv_message *msg, MshvVmExit *exit);
+int mshv_load_regs(CPUState *cpu);
+int mshv_store_regs(CPUState *cpu);
+int mshv_arch_put_registers(const CPUState *cpu);
+void mshv_arch_init_vcpu(CPUState *cpu);
+void mshv_arch_destroy_vcpu(CPUState *cpu);
void mshv_arch_amend_proc_features(
union hv_partition_synthetic_processor_features *features);
int mshv_arch_post_init_vm(int vm_fd);
diff --git a/target/i386/mshv/mshv-cpu.c b/target/i386/mshv/mshv-cpu.c
index de0c26bc6c..02d71ebc14 100644
--- a/target/i386/mshv/mshv-cpu.c
+++ b/target/i386/mshv/mshv-cpu.c
@@ -22,15 +22,78 @@
#include "hw/hyperv/hvgdk_mini.h"
#include "hw/hyperv/hvhdk_mini.h"
+#include "cpu.h"
+#include "emulate/x86_decode.h"
+#include "emulate/x86_emu.h"
+#include "emulate/x86_flags.h"
+
#include "trace-accel_mshv.h"
#include "trace.h"
+int mshv_store_regs(CPUState *cpu)
+{
+ error_report("unimplemented");
+ abort();
+}
+
+int mshv_load_regs(CPUState *cpu)
+{
+ error_report("unimplemented");
+ abort();
+}
+
+int mshv_arch_put_registers(const CPUState *cpu)
+{
+ error_report("unimplemented");
+ abort();
+}
+
void mshv_arch_amend_proc_features(
union hv_partition_synthetic_processor_features *features)
{
features->access_guest_idle_reg = 1;
}
+int mshv_run_vcpu(int vm_fd, CPUState *cpu, hv_message *msg, MshvVmExit *exit)
+{
+ error_report("unimplemented");
+ abort();
+}
+
+void mshv_remove_vcpu(int vm_fd, int cpu_fd)
+{
+ error_report("unimplemented");
+ abort();
+}
+
+int mshv_create_vcpu(int vm_fd, uint8_t vp_index, int *cpu_fd)
+{
+ error_report("unimplemented");
+ abort();
+}
+
+void mshv_init_mmio_emu(void)
+{
+ error_report("unimplemented");
+ abort();
+}
+
+void mshv_arch_init_vcpu(CPUState *cpu)
+{
+ X86CPU *x86_cpu = X86_CPU(cpu);
+ CPUX86State *env = &x86_cpu->env;
+
+ env->emu_mmio_buf = g_new(char, 4096);
+}
+
+void mshv_arch_destroy_vcpu(CPUState *cpu)
+{
+ X86CPU *x86_cpu = X86_CPU(cpu);
+ CPUX86State *env = &x86_cpu->env;
+
+ g_clear_pointer(&env->emu_mmio_buf, g_free);
+}
+
/*
* Default Microsoft Hypervisor behavior for unimplemented MSR is to send a
* fault to the guest if it tries to access it. It is possible to override

View File

@ -1,76 +0,0 @@
From f291987a12ea9ff0d7c3bed02fb23faea42f5523 Mon Sep 17 00:00:00 2001
From: Magnus Kulke <magnuskulke@linux.microsoft.com>
Date: Tue, 16 Sep 2025 18:48:31 +0200
Subject: [PATCH] accel/mshv: Add vCPU signal handling
RH-Author: Igor Mammedov <imammedo@redhat.com>
RH-MergeRequest: 437: el10: x86: enablement for Azure L1VH OCP readiness
RH-Jira: RHEL-134212
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [12/30] c3c9c5d9ad4d335a12c9d54499e4a2902b523441
Implement signal handling for MSHV vCPUs to support asynchronous
interrupts from the main thread.
Signed-off-by: Magnus Kulke <magnuskulke@linux.microsoft.com>
Link: https://lore.kernel.org/r/20250916164847.77883-12-magnuskulke@linux.microsoft.com
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit 575df4df54e060661db45e6f80293b29ea8901c1)
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Patch-name: kvm-accel-mshv-Add-vCPU-signal-handling.patch
Patch-id: 72
Patch-present-in-specfile: True
---
accel/mshv/mshv-all.c | 30 ++++++++++++++++++++++++++++++
1 file changed, 30 insertions(+)
diff --git a/accel/mshv/mshv-all.c b/accel/mshv/mshv-all.c
index e02421d79d..fa1f8f35bd 100644
--- a/accel/mshv/mshv-all.c
+++ b/accel/mshv/mshv-all.c
@@ -524,6 +524,35 @@ static int mshv_cpu_exec(CPUState *cpu)
return ret;
}
+/*
+ * The signal handler is triggered when QEMU's main thread receives a SIG_IPI
+ * (SIGUSR1). This signal causes the current CPU thread to be kicked, forcing a
+ * VM exit on the CPU. The VM exit generates an exit reason that breaks the loop
+ * (see mshv_cpu_exec). If the exit is due to a Ctrl+A+x command, the system
+ * will shut down. For other cases, the system will continue running.
+ */
+static void sa_ipi_handler(int sig)
+{
+ /* TODO: call IOCTL to set_immediate_exit, once implemented. */
+
+ qemu_cpu_kick_self();
+}
+
+static void init_signal(CPUState *cpu)
+{
+ /* init cpu signals */
+ struct sigaction sigact;
+ sigset_t set;
+
+ memset(&sigact, 0, sizeof(sigact));
+ sigact.sa_handler = sa_ipi_handler;
+ sigaction(SIG_IPI, &sigact, NULL);
+
+ pthread_sigmask(SIG_BLOCK, NULL, &set);
+ sigdelset(&set, SIG_IPI);
+ pthread_sigmask(SIG_SETMASK, &set, NULL);
+}
+
static void *mshv_vcpu_thread(void *arg)
{
CPUState *cpu = arg;
@@ -540,6 +569,7 @@ static void *mshv_vcpu_thread(void *arg)
error_report("Failed to init vcpu %d", cpu->cpu_index);
goto cleanup;
}
+ init_signal(cpu);
/* signal CPU creation */
cpu_thread_signal_created(cpu);

View File

@ -1,77 +0,0 @@
From 8033e3b98bda1261f95770b68f6337cc6d66bf9d Mon Sep 17 00:00:00 2001
From: Magnus Kulke <magnuskulke@linux.microsoft.com>
Date: Tue, 16 Sep 2025 18:48:32 +0200
Subject: [PATCH] target/i386/mshv: Add CPU create and remove logic
RH-Author: Igor Mammedov <imammedo@redhat.com>
RH-MergeRequest: 437: el10: x86: enablement for Azure L1VH OCP readiness
RH-Jira: RHEL-134212
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [13/30] cdb6e3cec7a38a6328be8facbbdf19fd0fd9ec78
Implement MSHV-specific hooks for vCPU creation and teardown in the
i386 target.
Signed-off-by: Magnus Kulke <magnuskulke@linux.microsoft.com>
Link: https://lore.kernel.org/r/20250916164847.77883-13-magnuskulke@linux.microsoft.com
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit 4ed605c06e743b2ec0bfe35954d88b8c64dd3767)
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Patch-name: kvm-target-i386-mshv-Add-CPU-create-and-remove-logic.patch
Patch-id: 73
Patch-present-in-specfile: True
---
target/i386/mshv/mshv-cpu.c | 23 +++++++++++++++++------
1 file changed, 17 insertions(+), 6 deletions(-)
diff --git a/target/i386/mshv/mshv-cpu.c b/target/i386/mshv/mshv-cpu.c
index 02d71ebc14..5069ab7a22 100644
--- a/target/i386/mshv/mshv-cpu.c
+++ b/target/i386/mshv/mshv-cpu.c
@@ -30,6 +30,8 @@
#include "trace-accel_mshv.h"
#include "trace.h"
+#include <sys/ioctl.h>
+
int mshv_store_regs(CPUState *cpu)
{
error_report("unimplemented");
@@ -62,20 +64,29 @@ int mshv_run_vcpu(int vm_fd, CPUState *cpu, hv_message *msg, MshvVmExit *exit)
void mshv_remove_vcpu(int vm_fd, int cpu_fd)
{
- error_report("unimplemented");
- abort();
+ close(cpu_fd);
}
+
int mshv_create_vcpu(int vm_fd, uint8_t vp_index, int *cpu_fd)
{
- error_report("unimplemented");
- abort();
+ int ret;
+ struct mshv_create_vp vp_arg = {
+ .vp_index = vp_index,
+ };
+ ret = ioctl(vm_fd, MSHV_CREATE_VP, &vp_arg);
+ if (ret < 0) {
+ error_report("failed to create mshv vcpu: %s", strerror(errno));
+ return -1;
+ }
+
+ *cpu_fd = ret;
+
+ return 0;
}
void mshv_init_mmio_emu(void)
{
- error_report("unimplemented");
- abort();
}
void mshv_arch_init_vcpu(CPUState *cpu)

View File

@ -1,189 +0,0 @@
From 2096f4c0379df09a24a0cab1fc8902bba669b632 Mon Sep 17 00:00:00 2001
From: Magnus Kulke <magnuskulke@linux.microsoft.com>
Date: Thu, 2 Oct 2025 18:13:31 +0200
Subject: [PATCH] target/i386/mshv: Implement mshv_store_regs()
RH-Author: Igor Mammedov <imammedo@redhat.com>
RH-MergeRequest: 437: el10: x86: enablement for Azure L1VH OCP readiness
RH-Jira: RHEL-134212
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [14/30] 2f4fe2c0b042ec06d351929a7b090e554a459be1
Add support for writing general-purpose registers to MSHV vCPUs
during initialization or migration using the MSHV register interface. A
generic set_register call is introduced to abstract the HV call over
the various register types.
Signed-off-by: Magnus Kulke <magnuskulke@linux.microsoft.com>
Link: https://lore.kernel.org/r/20250916164847.77883-14-magnuskulke@linux.microsoft.com
[mshv.h/mshv_int.h split. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit 2bd7a6aa4743ee85c77c0520e8b422b3bfeab386)
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Patch-name: kvm-target-i386-mshv-Implement-mshv_store_regs.patch
Patch-id: 74
Patch-present-in-specfile: True
---
include/system/mshv.h | 1 +
include/system/mshv_int.h | 2 +
target/i386/mshv/mshv-cpu.c | 116 +++++++++++++++++++++++++++++++++++-
3 files changed, 117 insertions(+), 2 deletions(-)
diff --git a/include/system/mshv.h b/include/system/mshv.h
index bbc42f4dc3..8b1fc20c80 100644
--- a/include/system/mshv.h
+++ b/include/system/mshv.h
@@ -18,6 +18,7 @@
#include "qemu/accel.h"
#include "hw/hyperv/hyperv-proto.h"
#include "hw/hyperv/hvhdk.h"
+#include "hw/hyperv/hvgdk_mini.h"
#include "qapi/qapi-types-common.h"
#include "system/memory.h"
#include "accel/accel-ops.h"
diff --git a/include/system/mshv_int.h b/include/system/mshv_int.h
index fb80f69772..731841af92 100644
--- a/include/system/mshv_int.h
+++ b/include/system/mshv_int.h
@@ -61,6 +61,8 @@ void mshv_remove_vcpu(int vm_fd, int cpu_fd);
int mshv_run_vcpu(int vm_fd, CPUState *cpu, hv_message *msg, MshvVmExit *exit);
int mshv_load_regs(CPUState *cpu);
int mshv_store_regs(CPUState *cpu);
+int mshv_set_generic_regs(const CPUState *cpu, const hv_register_assoc *assocs,
+ size_t n_regs);
int mshv_arch_put_registers(const CPUState *cpu);
void mshv_arch_init_vcpu(CPUState *cpu);
void mshv_arch_destroy_vcpu(CPUState *cpu);
diff --git a/target/i386/mshv/mshv-cpu.c b/target/i386/mshv/mshv-cpu.c
index 5069ab7a22..9ead03ca2d 100644
--- a/target/i386/mshv/mshv-cpu.c
+++ b/target/i386/mshv/mshv-cpu.c
@@ -32,12 +32,124 @@
#include <sys/ioctl.h>
+static enum hv_register_name STANDARD_REGISTER_NAMES[18] = {
+ HV_X64_REGISTER_RAX,
+ HV_X64_REGISTER_RBX,
+ HV_X64_REGISTER_RCX,
+ HV_X64_REGISTER_RDX,
+ HV_X64_REGISTER_RSI,
+ HV_X64_REGISTER_RDI,
+ HV_X64_REGISTER_RSP,
+ HV_X64_REGISTER_RBP,
+ HV_X64_REGISTER_R8,
+ HV_X64_REGISTER_R9,
+ HV_X64_REGISTER_R10,
+ HV_X64_REGISTER_R11,
+ HV_X64_REGISTER_R12,
+ HV_X64_REGISTER_R13,
+ HV_X64_REGISTER_R14,
+ HV_X64_REGISTER_R15,
+ HV_X64_REGISTER_RIP,
+ HV_X64_REGISTER_RFLAGS,
+};
+
+int mshv_set_generic_regs(const CPUState *cpu, const hv_register_assoc *assocs,
+ size_t n_regs)
+{
+ int cpu_fd = mshv_vcpufd(cpu);
+ int vp_index = cpu->cpu_index;
+ size_t in_sz, assocs_sz;
+ hv_input_set_vp_registers *in;
+ struct mshv_root_hvcall args = {0};
+ int ret;
+
+ /* find out the size of the struct w/ a flexible array at the tail */
+ assocs_sz = n_regs * sizeof(hv_register_assoc);
+ in_sz = sizeof(hv_input_set_vp_registers) + assocs_sz;
+
+ /* fill the input struct */
+ in = g_malloc0(in_sz);
+ in->vp_index = vp_index;
+ memcpy(in->elements, assocs, assocs_sz);
+
+ /* create the hvcall envelope */
+ args.code = HVCALL_SET_VP_REGISTERS;
+ args.in_sz = in_sz;
+ args.in_ptr = (uint64_t) in;
+ args.reps = (uint16_t) n_regs;
+
+ /* perform the call */
+ ret = mshv_hvcall(cpu_fd, &args);
+ g_free(in);
+ if (ret < 0) {
+ error_report("Failed to set registers");
+ return -1;
+ }
+
+ /* assert we set all registers */
+ if (args.reps != n_regs) {
+ error_report("Failed to set registers: expected %zu elements"
+ ", got %u", n_regs, args.reps);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int set_standard_regs(const CPUState *cpu)
+{
+ X86CPU *x86cpu = X86_CPU(cpu);
+ CPUX86State *env = &x86cpu->env;
+ hv_register_assoc assocs[ARRAY_SIZE(STANDARD_REGISTER_NAMES)];
+ int ret;
+ size_t n_regs = ARRAY_SIZE(STANDARD_REGISTER_NAMES);
+
+ /* set names */
+ for (size_t i = 0; i < ARRAY_SIZE(STANDARD_REGISTER_NAMES); i++) {
+ assocs[i].name = STANDARD_REGISTER_NAMES[i];
+ }
+ assocs[0].value.reg64 = env->regs[R_EAX];
+ assocs[1].value.reg64 = env->regs[R_EBX];
+ assocs[2].value.reg64 = env->regs[R_ECX];
+ assocs[3].value.reg64 = env->regs[R_EDX];
+ assocs[4].value.reg64 = env->regs[R_ESI];
+ assocs[5].value.reg64 = env->regs[R_EDI];
+ assocs[6].value.reg64 = env->regs[R_ESP];
+ assocs[7].value.reg64 = env->regs[R_EBP];
+ assocs[8].value.reg64 = env->regs[R_R8];
+ assocs[9].value.reg64 = env->regs[R_R9];
+ assocs[10].value.reg64 = env->regs[R_R10];
+ assocs[11].value.reg64 = env->regs[R_R11];
+ assocs[12].value.reg64 = env->regs[R_R12];
+ assocs[13].value.reg64 = env->regs[R_R13];
+ assocs[14].value.reg64 = env->regs[R_R14];
+ assocs[15].value.reg64 = env->regs[R_R15];
+ assocs[16].value.reg64 = env->eip;
+ lflags_to_rflags(env);
+ assocs[17].value.reg64 = env->eflags;
+
+ ret = mshv_set_generic_regs(cpu, assocs, n_regs);
+ if (ret < 0) {
+ error_report("failed to set standard registers");
+ return -errno;
+ }
+ return 0;
+}
+
int mshv_store_regs(CPUState *cpu)
{
- error_report("unimplemented");
- abort();
+ int ret;
+
+ ret = set_standard_regs(cpu);
+ if (ret < 0) {
+ error_report("Failed to store standard registers");
+ return -1;
+ }
+
+ return 0;
}
+
int mshv_load_regs(CPUState *cpu)
{
error_report("unimplemented");

View File

@ -1,183 +0,0 @@
From a60b80bb7d9969cdb0f4281c16104bf1ddc5163d Mon Sep 17 00:00:00 2001
From: Magnus Kulke <magnuskulke@linux.microsoft.com>
Date: Tue, 16 Sep 2025 18:48:34 +0200
Subject: [PATCH] target/i386/mshv: Implement mshv_get_standard_regs()
RH-Author: Igor Mammedov <imammedo@redhat.com>
RH-MergeRequest: 437: el10: x86: enablement for Azure L1VH OCP readiness
RH-Jira: RHEL-134212
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [15/30] ccb135407183081206513dd2de2410a9c1768f15
Fetch standard register state from MSHV vCPUs to support debugging,
migration, and other introspection features in QEMU.
Fetch standard register state from a MHSV vCPU's. A generic get_regs()
function and a mapper to map the different register representations are
introduced.
Signed-off-by: Magnus Kulke <magnuskulke@linux.microsoft.com>
Link: https://lore.kernel.org/r/20250916164847.77883-15-magnuskulke@linux.microsoft.com
[mshv.h/mshv_int.h split. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit 66480a048a01fc833ba153410282609f26166141)
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Patch-name: kvm-target-i386-mshv-Implement-mshv_get_standard_regs.patch
Patch-id: 75
Patch-present-in-specfile: True
---
include/system/mshv_int.h | 1 +
target/i386/mshv/mshv-cpu.c | 116 +++++++++++++++++++++++++++++++++++-
2 files changed, 115 insertions(+), 2 deletions(-)
diff --git a/include/system/mshv_int.h b/include/system/mshv_int.h
index 731841af92..b0a79296ad 100644
--- a/include/system/mshv_int.h
+++ b/include/system/mshv_int.h
@@ -58,6 +58,7 @@ typedef enum MshvVmExit {
void mshv_init_mmio_emu(void);
int mshv_create_vcpu(int vm_fd, uint8_t vp_index, int *cpu_fd);
void mshv_remove_vcpu(int vm_fd, int cpu_fd);
+int mshv_get_standard_regs(CPUState *cpu);
int mshv_run_vcpu(int vm_fd, CPUState *cpu, hv_message *msg, MshvVmExit *exit);
int mshv_load_regs(CPUState *cpu);
int mshv_store_regs(CPUState *cpu);
diff --git a/target/i386/mshv/mshv-cpu.c b/target/i386/mshv/mshv-cpu.c
index 9ead03ca2d..4e3eee113b 100644
--- a/target/i386/mshv/mshv-cpu.c
+++ b/target/i386/mshv/mshv-cpu.c
@@ -96,6 +96,66 @@ int mshv_set_generic_regs(const CPUState *cpu, const hv_register_assoc *assocs,
return 0;
}
+static int get_generic_regs(CPUState *cpu, hv_register_assoc *assocs,
+ size_t n_regs)
+{
+ int cpu_fd = mshv_vcpufd(cpu);
+ int vp_index = cpu->cpu_index;
+ hv_input_get_vp_registers *in;
+ hv_register_value *values;
+ size_t in_sz, names_sz, values_sz;
+ int i, ret;
+ struct mshv_root_hvcall args = {0};
+
+ /* find out the size of the struct w/ a flexible array at the tail */
+ names_sz = n_regs * sizeof(hv_register_name);
+ in_sz = sizeof(hv_input_get_vp_registers) + names_sz;
+
+ /* fill the input struct */
+ in = g_malloc0(in_sz);
+ in->vp_index = vp_index;
+ for (i = 0; i < n_regs; i++) {
+ in->names[i] = assocs[i].name;
+ }
+
+ /* allocate value output buffer */
+ values_sz = n_regs * sizeof(union hv_register_value);
+ values = g_malloc0(values_sz);
+
+ /* create the hvcall envelope */
+ args.code = HVCALL_GET_VP_REGISTERS;
+ args.in_sz = in_sz;
+ args.in_ptr = (uint64_t) in;
+ args.out_sz = values_sz;
+ args.out_ptr = (uint64_t) values;
+ args.reps = (uint16_t) n_regs;
+
+ /* perform the call */
+ ret = mshv_hvcall(cpu_fd, &args);
+ g_free(in);
+ if (ret < 0) {
+ g_free(values);
+ error_report("Failed to retrieve registers");
+ return -1;
+ }
+
+ /* assert we got all registers */
+ if (args.reps != n_regs) {
+ g_free(values);
+ error_report("Failed to retrieve registers: expected %zu elements"
+ ", got %u", n_regs, args.reps);
+ return -1;
+ }
+
+ /* copy values into assoc */
+ for (i = 0; i < n_regs; i++) {
+ assocs[i].value = values[i];
+ }
+ g_free(values);
+
+ return 0;
+}
+
static int set_standard_regs(const CPUState *cpu)
{
X86CPU *x86cpu = X86_CPU(cpu);
@@ -149,11 +209,63 @@ int mshv_store_regs(CPUState *cpu)
return 0;
}
+static void populate_standard_regs(const hv_register_assoc *assocs,
+ CPUX86State *env)
+{
+ env->regs[R_EAX] = assocs[0].value.reg64;
+ env->regs[R_EBX] = assocs[1].value.reg64;
+ env->regs[R_ECX] = assocs[2].value.reg64;
+ env->regs[R_EDX] = assocs[3].value.reg64;
+ env->regs[R_ESI] = assocs[4].value.reg64;
+ env->regs[R_EDI] = assocs[5].value.reg64;
+ env->regs[R_ESP] = assocs[6].value.reg64;
+ env->regs[R_EBP] = assocs[7].value.reg64;
+ env->regs[R_R8] = assocs[8].value.reg64;
+ env->regs[R_R9] = assocs[9].value.reg64;
+ env->regs[R_R10] = assocs[10].value.reg64;
+ env->regs[R_R11] = assocs[11].value.reg64;
+ env->regs[R_R12] = assocs[12].value.reg64;
+ env->regs[R_R13] = assocs[13].value.reg64;
+ env->regs[R_R14] = assocs[14].value.reg64;
+ env->regs[R_R15] = assocs[15].value.reg64;
+
+ env->eip = assocs[16].value.reg64;
+ env->eflags = assocs[17].value.reg64;
+ rflags_to_lflags(env);
+}
+
+int mshv_get_standard_regs(CPUState *cpu)
+{
+ struct hv_register_assoc assocs[ARRAY_SIZE(STANDARD_REGISTER_NAMES)];
+ int ret;
+ X86CPU *x86cpu = X86_CPU(cpu);
+ CPUX86State *env = &x86cpu->env;
+ size_t n_regs = ARRAY_SIZE(STANDARD_REGISTER_NAMES);
+
+ for (size_t i = 0; i < n_regs; i++) {
+ assocs[i].name = STANDARD_REGISTER_NAMES[i];
+ }
+ ret = get_generic_regs(cpu, assocs, n_regs);
+ if (ret < 0) {
+ error_report("failed to get standard registers");
+ return -1;
+ }
+
+ populate_standard_regs(assocs, env);
+ return 0;
+}
int mshv_load_regs(CPUState *cpu)
{
- error_report("unimplemented");
- abort();
+ int ret;
+
+ ret = mshv_get_standard_regs(cpu);
+ if (ret < 0) {
+ error_report("Failed to load standard registers");
+ return -1;
+ }
+
+ return 0;
}
int mshv_arch_put_registers(const CPUState *cpu)

View File

@ -1,174 +0,0 @@
From f72c428f6ebc373a6cbe566a7f99db8b7d03efd0 Mon Sep 17 00:00:00 2001
From: Magnus Kulke <magnuskulke@linux.microsoft.com>
Date: Tue, 16 Sep 2025 18:48:35 +0200
Subject: [PATCH] target/i386/mshv: Implement mshv_get_special_regs()
RH-Author: Igor Mammedov <imammedo@redhat.com>
RH-MergeRequest: 437: el10: x86: enablement for Azure L1VH OCP readiness
RH-Jira: RHEL-134212
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [16/30] 429625fae745bc6c3c9e9412741c875331a92180
Retrieve special registers (e.g. segment, control, and descriptor
table registers) from MSHV vCPUs.
Various helper functions to map register state representations between
Qemu and MSHV are introduced.
Signed-off-by: Magnus Kulke <magnuskulke@linux.microsoft.com>
Link: https://lore.kernel.org/r/20250916164847.77883-16-magnuskulke@linux.microsoft.com
[mshv.h/mshv_int.h split. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit 0382c2c8544da66619d16988caaab8e3d9e881d4)
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Patch-name: kvm-target-i386-mshv-Implement-mshv_get_special_regs.patch
Patch-id: 76
Patch-present-in-specfile: True
---
include/system/mshv_int.h | 1 +
target/i386/mshv/mshv-cpu.c | 104 ++++++++++++++++++++++++++++++++++++
2 files changed, 105 insertions(+)
diff --git a/include/system/mshv_int.h b/include/system/mshv_int.h
index b0a79296ad..c6e6e8af30 100644
--- a/include/system/mshv_int.h
+++ b/include/system/mshv_int.h
@@ -59,6 +59,7 @@ void mshv_init_mmio_emu(void);
int mshv_create_vcpu(int vm_fd, uint8_t vp_index, int *cpu_fd);
void mshv_remove_vcpu(int vm_fd, int cpu_fd);
int mshv_get_standard_regs(CPUState *cpu);
+int mshv_get_special_regs(CPUState *cpu);
int mshv_run_vcpu(int vm_fd, CPUState *cpu, hv_message *msg, MshvVmExit *exit);
int mshv_load_regs(CPUState *cpu);
int mshv_store_regs(CPUState *cpu);
diff --git a/target/i386/mshv/mshv-cpu.c b/target/i386/mshv/mshv-cpu.c
index 4e3eee113b..bc75686f82 100644
--- a/target/i386/mshv/mshv-cpu.c
+++ b/target/i386/mshv/mshv-cpu.c
@@ -53,6 +53,26 @@ static enum hv_register_name STANDARD_REGISTER_NAMES[18] = {
HV_X64_REGISTER_RFLAGS,
};
+static enum hv_register_name SPECIAL_REGISTER_NAMES[17] = {
+ HV_X64_REGISTER_CS,
+ HV_X64_REGISTER_DS,
+ HV_X64_REGISTER_ES,
+ HV_X64_REGISTER_FS,
+ HV_X64_REGISTER_GS,
+ HV_X64_REGISTER_SS,
+ HV_X64_REGISTER_TR,
+ HV_X64_REGISTER_LDTR,
+ HV_X64_REGISTER_GDTR,
+ HV_X64_REGISTER_IDTR,
+ HV_X64_REGISTER_CR0,
+ HV_X64_REGISTER_CR2,
+ HV_X64_REGISTER_CR3,
+ HV_X64_REGISTER_CR4,
+ HV_X64_REGISTER_CR8,
+ HV_X64_REGISTER_EFER,
+ HV_X64_REGISTER_APIC_BASE,
+};
+
int mshv_set_generic_regs(const CPUState *cpu, const hv_register_assoc *assocs,
size_t n_regs)
{
@@ -255,6 +275,84 @@ int mshv_get_standard_regs(CPUState *cpu)
return 0;
}
+static inline void populate_segment_reg(const hv_x64_segment_register *hv_seg,
+ SegmentCache *seg)
+{
+ memset(seg, 0, sizeof(SegmentCache));
+
+ seg->base = hv_seg->base;
+ seg->limit = hv_seg->limit;
+ seg->selector = hv_seg->selector;
+
+ seg->flags = (hv_seg->segment_type << DESC_TYPE_SHIFT)
+ | (hv_seg->present * DESC_P_MASK)
+ | (hv_seg->descriptor_privilege_level << DESC_DPL_SHIFT)
+ | (hv_seg->_default << DESC_B_SHIFT)
+ | (hv_seg->non_system_segment * DESC_S_MASK)
+ | (hv_seg->_long << DESC_L_SHIFT)
+ | (hv_seg->granularity * DESC_G_MASK)
+ | (hv_seg->available * DESC_AVL_MASK);
+
+}
+
+static inline void populate_table_reg(const hv_x64_table_register *hv_seg,
+ SegmentCache *tbl)
+{
+ memset(tbl, 0, sizeof(SegmentCache));
+
+ tbl->base = hv_seg->base;
+ tbl->limit = hv_seg->limit;
+}
+
+static void populate_special_regs(const hv_register_assoc *assocs,
+ X86CPU *x86cpu)
+{
+ CPUX86State *env = &x86cpu->env;
+
+ populate_segment_reg(&assocs[0].value.segment, &env->segs[R_CS]);
+ populate_segment_reg(&assocs[1].value.segment, &env->segs[R_DS]);
+ populate_segment_reg(&assocs[2].value.segment, &env->segs[R_ES]);
+ populate_segment_reg(&assocs[3].value.segment, &env->segs[R_FS]);
+ populate_segment_reg(&assocs[4].value.segment, &env->segs[R_GS]);
+ populate_segment_reg(&assocs[5].value.segment, &env->segs[R_SS]);
+
+ populate_segment_reg(&assocs[6].value.segment, &env->tr);
+ populate_segment_reg(&assocs[7].value.segment, &env->ldt);
+
+ populate_table_reg(&assocs[8].value.table, &env->gdt);
+ populate_table_reg(&assocs[9].value.table, &env->idt);
+
+ env->cr[0] = assocs[10].value.reg64;
+ env->cr[2] = assocs[11].value.reg64;
+ env->cr[3] = assocs[12].value.reg64;
+ env->cr[4] = assocs[13].value.reg64;
+
+ cpu_set_apic_tpr(x86cpu->apic_state, assocs[14].value.reg64);
+ env->efer = assocs[15].value.reg64;
+ cpu_set_apic_base(x86cpu->apic_state, assocs[16].value.reg64);
+}
+
+
+int mshv_get_special_regs(CPUState *cpu)
+{
+ struct hv_register_assoc assocs[ARRAY_SIZE(SPECIAL_REGISTER_NAMES)];
+ int ret;
+ X86CPU *x86cpu = X86_CPU(cpu);
+ size_t n_regs = ARRAY_SIZE(SPECIAL_REGISTER_NAMES);
+
+ for (size_t i = 0; i < n_regs; i++) {
+ assocs[i].name = SPECIAL_REGISTER_NAMES[i];
+ }
+ ret = get_generic_regs(cpu, assocs, n_regs);
+ if (ret < 0) {
+ error_report("failed to get special registers");
+ return -errno;
+ }
+
+ populate_special_regs(assocs, x86cpu);
+ return 0;
+}
+
int mshv_load_regs(CPUState *cpu)
{
int ret;
@@ -265,6 +363,12 @@ int mshv_load_regs(CPUState *cpu)
return -1;
}
+ ret = mshv_get_special_regs(cpu);
+ if (ret < 0) {
+ error_report("Failed to load special registers");
+ return -1;
+ }
+
return 0;
}

View File

@ -1,320 +0,0 @@
From f3e0329c1ce6d3b147baad937f0261ecb2c9f542 Mon Sep 17 00:00:00 2001
From: Magnus Kulke <magnuskulke@linux.microsoft.com>
Date: Tue, 16 Sep 2025 18:48:36 +0200
Subject: [PATCH] target/i386/mshv: Implement mshv_arch_put_registers()
RH-Author: Igor Mammedov <imammedo@redhat.com>
RH-MergeRequest: 437: el10: x86: enablement for Azure L1VH OCP readiness
RH-Jira: RHEL-134212
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [17/30] e2648880fed0b7eb9097768c3e4cfc914baa104a
Write CPU register state to MSHV vCPUs. Various mapping functions to
prepare the payload for the HV call have been implemented.
Signed-off-by: Magnus Kulke <magnuskulke@linux.microsoft.com>
Link: https://lore.kernel.org/r/20250916164847.77883-17-magnuskulke@linux.microsoft.com
[mshv.h/mshv_int.h split. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit 25a1d871e0f19bbf8fee471af5fefec52465bb09)
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Patch-name: kvm-target-i386-mshv-Implement-mshv_arch_put_registers.patch
Patch-id: 77
Patch-present-in-specfile: True
---
include/system/mshv_int.h | 15 +++
target/i386/mshv/mshv-cpu.c | 237 ++++++++++++++++++++++++++++++++++++
2 files changed, 252 insertions(+)
diff --git a/include/system/mshv_int.h b/include/system/mshv_int.h
index c6e6e8af30..0ea8d504fa 100644
--- a/include/system/mshv_int.h
+++ b/include/system/mshv_int.h
@@ -49,6 +49,20 @@ typedef struct MshvMsiControl {
#define mshv_vcpufd(cpu) (cpu->accel->cpufd)
/* cpu */
+typedef struct MshvFPU {
+ uint8_t fpr[8][16];
+ uint16_t fcw;
+ uint16_t fsw;
+ uint8_t ftwx;
+ uint8_t pad1;
+ uint16_t last_opcode;
+ uint64_t last_ip;
+ uint64_t last_dp;
+ uint8_t xmm[16][16];
+ uint32_t mxcsr;
+ uint32_t pad2;
+} MshvFPU;
+
typedef enum MshvVmExit {
MshvVmExitIgnore = 0,
MshvVmExitShutdown = 1,
@@ -58,6 +72,7 @@ typedef enum MshvVmExit {
void mshv_init_mmio_emu(void);
int mshv_create_vcpu(int vm_fd, uint8_t vp_index, int *cpu_fd);
void mshv_remove_vcpu(int vm_fd, int cpu_fd);
+int mshv_configure_vcpu(const CPUState *cpu, const MshvFPU *fpu, uint64_t xcr0);
int mshv_get_standard_regs(CPUState *cpu);
int mshv_get_special_regs(CPUState *cpu);
int mshv_run_vcpu(int vm_fd, CPUState *cpu, hv_message *msg, MshvVmExit *exit);
diff --git a/target/i386/mshv/mshv-cpu.c b/target/i386/mshv/mshv-cpu.c
index bc75686f82..8b10c79e54 100644
--- a/target/i386/mshv/mshv-cpu.c
+++ b/target/i386/mshv/mshv-cpu.c
@@ -73,6 +73,35 @@ static enum hv_register_name SPECIAL_REGISTER_NAMES[17] = {
HV_X64_REGISTER_APIC_BASE,
};
+static enum hv_register_name FPU_REGISTER_NAMES[26] = {
+ HV_X64_REGISTER_XMM0,
+ HV_X64_REGISTER_XMM1,
+ HV_X64_REGISTER_XMM2,
+ HV_X64_REGISTER_XMM3,
+ HV_X64_REGISTER_XMM4,
+ HV_X64_REGISTER_XMM5,
+ HV_X64_REGISTER_XMM6,
+ HV_X64_REGISTER_XMM7,
+ HV_X64_REGISTER_XMM8,
+ HV_X64_REGISTER_XMM9,
+ HV_X64_REGISTER_XMM10,
+ HV_X64_REGISTER_XMM11,
+ HV_X64_REGISTER_XMM12,
+ HV_X64_REGISTER_XMM13,
+ HV_X64_REGISTER_XMM14,
+ HV_X64_REGISTER_XMM15,
+ HV_X64_REGISTER_FP_MMX0,
+ HV_X64_REGISTER_FP_MMX1,
+ HV_X64_REGISTER_FP_MMX2,
+ HV_X64_REGISTER_FP_MMX3,
+ HV_X64_REGISTER_FP_MMX4,
+ HV_X64_REGISTER_FP_MMX5,
+ HV_X64_REGISTER_FP_MMX6,
+ HV_X64_REGISTER_FP_MMX7,
+ HV_X64_REGISTER_FP_CONTROL_STATUS,
+ HV_X64_REGISTER_XMM_CONTROL_STATUS,
+};
+
int mshv_set_generic_regs(const CPUState *cpu, const hv_register_assoc *assocs,
size_t n_regs)
{
@@ -372,8 +401,216 @@ int mshv_load_regs(CPUState *cpu)
return 0;
}
+static inline void populate_hv_segment_reg(SegmentCache *seg,
+ hv_x64_segment_register *hv_reg)
+{
+ uint32_t flags = seg->flags;
+
+ hv_reg->base = seg->base;
+ hv_reg->limit = seg->limit;
+ hv_reg->selector = seg->selector;
+ hv_reg->segment_type = (flags >> DESC_TYPE_SHIFT) & 0xF;
+ hv_reg->non_system_segment = (flags & DESC_S_MASK) != 0;
+ hv_reg->descriptor_privilege_level = (flags >> DESC_DPL_SHIFT) & 0x3;
+ hv_reg->present = (flags & DESC_P_MASK) != 0;
+ hv_reg->reserved = 0;
+ hv_reg->available = (flags & DESC_AVL_MASK) != 0;
+ hv_reg->_long = (flags >> DESC_L_SHIFT) & 0x1;
+ hv_reg->_default = (flags >> DESC_B_SHIFT) & 0x1;
+ hv_reg->granularity = (flags & DESC_G_MASK) != 0;
+}
+
+static inline void populate_hv_table_reg(const struct SegmentCache *seg,
+ hv_x64_table_register *hv_reg)
+{
+ memset(hv_reg, 0, sizeof(*hv_reg));
+
+ hv_reg->base = seg->base;
+ hv_reg->limit = seg->limit;
+}
+
+static int set_special_regs(const CPUState *cpu)
+{
+ X86CPU *x86cpu = X86_CPU(cpu);
+ CPUX86State *env = &x86cpu->env;
+ struct hv_register_assoc assocs[ARRAY_SIZE(SPECIAL_REGISTER_NAMES)];
+ size_t n_regs = ARRAY_SIZE(SPECIAL_REGISTER_NAMES);
+ int ret;
+
+ /* set names */
+ for (size_t i = 0; i < n_regs; i++) {
+ assocs[i].name = SPECIAL_REGISTER_NAMES[i];
+ }
+ populate_hv_segment_reg(&env->segs[R_CS], &assocs[0].value.segment);
+ populate_hv_segment_reg(&env->segs[R_DS], &assocs[1].value.segment);
+ populate_hv_segment_reg(&env->segs[R_ES], &assocs[2].value.segment);
+ populate_hv_segment_reg(&env->segs[R_FS], &assocs[3].value.segment);
+ populate_hv_segment_reg(&env->segs[R_GS], &assocs[4].value.segment);
+ populate_hv_segment_reg(&env->segs[R_SS], &assocs[5].value.segment);
+ populate_hv_segment_reg(&env->tr, &assocs[6].value.segment);
+ populate_hv_segment_reg(&env->ldt, &assocs[7].value.segment);
+
+ populate_hv_table_reg(&env->gdt, &assocs[8].value.table);
+ populate_hv_table_reg(&env->idt, &assocs[9].value.table);
+
+ assocs[10].value.reg64 = env->cr[0];
+ assocs[11].value.reg64 = env->cr[2];
+ assocs[12].value.reg64 = env->cr[3];
+ assocs[13].value.reg64 = env->cr[4];
+ assocs[14].value.reg64 = cpu_get_apic_tpr(x86cpu->apic_state);
+ assocs[15].value.reg64 = env->efer;
+ assocs[16].value.reg64 = cpu_get_apic_base(x86cpu->apic_state);
+
+ ret = mshv_set_generic_regs(cpu, assocs, n_regs);
+ if (ret < 0) {
+ error_report("failed to set special registers");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int set_fpu(const CPUState *cpu, const struct MshvFPU *regs)
+{
+ struct hv_register_assoc assocs[ARRAY_SIZE(FPU_REGISTER_NAMES)];
+ union hv_register_value *value;
+ size_t fp_i;
+ union hv_x64_fp_control_status_register *ctrl_status;
+ union hv_x64_xmm_control_status_register *xmm_ctrl_status;
+ int ret;
+ size_t n_regs = ARRAY_SIZE(FPU_REGISTER_NAMES);
+
+ /* first 16 registers are xmm0-xmm15 */
+ for (size_t i = 0; i < 16; i++) {
+ assocs[i].name = FPU_REGISTER_NAMES[i];
+ value = &assocs[i].value;
+ memcpy(&value->reg128, &regs->xmm[i], 16);
+ }
+
+ /* next 8 registers are fp_mmx0-fp_mmx7 */
+ for (size_t i = 16; i < 24; i++) {
+ assocs[i].name = FPU_REGISTER_NAMES[i];
+ fp_i = (i - 16);
+ value = &assocs[i].value;
+ memcpy(&value->reg128, &regs->fpr[fp_i], 16);
+ }
+
+ /* last two registers are fp_control_status and xmm_control_status */
+ assocs[24].name = FPU_REGISTER_NAMES[24];
+ value = &assocs[24].value;
+ ctrl_status = &value->fp_control_status;
+ ctrl_status->fp_control = regs->fcw;
+ ctrl_status->fp_status = regs->fsw;
+ ctrl_status->fp_tag = regs->ftwx;
+ ctrl_status->reserved = 0;
+ ctrl_status->last_fp_op = regs->last_opcode;
+ ctrl_status->last_fp_rip = regs->last_ip;
+
+ assocs[25].name = FPU_REGISTER_NAMES[25];
+ value = &assocs[25].value;
+ xmm_ctrl_status = &value->xmm_control_status;
+ xmm_ctrl_status->xmm_status_control = regs->mxcsr;
+ xmm_ctrl_status->xmm_status_control_mask = 0;
+ xmm_ctrl_status->last_fp_rdp = regs->last_dp;
+
+ ret = mshv_set_generic_regs(cpu, assocs, n_regs);
+ if (ret < 0) {
+ error_report("failed to set fpu registers");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int set_xc_reg(const CPUState *cpu, uint64_t xcr0)
+{
+ int ret;
+ struct hv_register_assoc assoc = {
+ .name = HV_X64_REGISTER_XFEM,
+ .value.reg64 = xcr0,
+ };
+
+ ret = mshv_set_generic_regs(cpu, &assoc, 1);
+ if (ret < 0) {
+ error_report("failed to set xcr0");
+ return -errno;
+ }
+ return 0;
+}
+
+static int set_cpu_state(const CPUState *cpu, const MshvFPU *fpu_regs,
+ uint64_t xcr0)
+{
+ int ret;
+
+ ret = set_standard_regs(cpu);
+ if (ret < 0) {
+ return ret;
+ }
+ ret = set_special_regs(cpu);
+ if (ret < 0) {
+ return ret;
+ }
+ ret = set_fpu(cpu, fpu_regs);
+ if (ret < 0) {
+ return ret;
+ }
+ ret = set_xc_reg(cpu, xcr0);
+ if (ret < 0) {
+ return ret;
+ }
+ return 0;
+}
+
+/*
+ * TODO: populate topology info:
+ *
+ * X86CPU *x86cpu = X86_CPU(cpu);
+ * CPUX86State *env = &x86cpu->env;
+ * X86CPUTopoInfo *topo_info = &env->topo_info;
+ */
+int mshv_configure_vcpu(const CPUState *cpu, const struct MshvFPU *fpu,
+ uint64_t xcr0)
+{
+ int ret;
+
+ ret = set_cpu_state(cpu, fpu, xcr0);
+ if (ret < 0) {
+ error_report("failed to set cpu state");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int put_regs(const CPUState *cpu)
+{
+ X86CPU *x86cpu = X86_CPU(cpu);
+ CPUX86State *env = &x86cpu->env;
+ MshvFPU fpu = {0};
+ int ret;
+
+ memset(&fpu, 0, sizeof(fpu));
+
+ ret = mshv_configure_vcpu(cpu, &fpu, env->xcr0);
+ if (ret < 0) {
+ error_report("failed to configure vcpu");
+ return ret;
+ }
+
+ return 0;
+}
+
int mshv_arch_put_registers(const CPUState *cpu)
{
+ int ret;
+
+ ret = put_regs(cpu);
+ if (ret < 0) {
+ error_report("Failed to put registers");
+ return -1;
+ }
+
error_report("unimplemented");
abort();
}

View File

@ -1,184 +0,0 @@
From a03d8784b3b02cc0bd7ff04db10e4ebcece41b54 Mon Sep 17 00:00:00 2001
From: Magnus Kulke <magnuskulke@linux.microsoft.com>
Date: Tue, 16 Sep 2025 18:48:37 +0200
Subject: [PATCH] target/i386/mshv: Set local interrupt controller state
RH-Author: Igor Mammedov <imammedo@redhat.com>
RH-MergeRequest: 437: el10: x86: enablement for Azure L1VH OCP readiness
RH-Jira: RHEL-134212
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [18/30] ded044d2fd9c55a149d7e71d952c10ed6ea29505
To set the local interrupt controller state, perform hv calls retrieving
partition state from the hypervisor.
Signed-off-by: Magnus Kulke <magnuskulke@linux.microsoft.com>
Link: https://lore.kernel.org/r/20250916164847.77883-18-magnuskulke@linux.microsoft.com
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit ca20d46fa94887a6e42061646a71ee44cbc9adb0)
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Patch-name: kvm-target-i386-mshv-Set-local-interrupt-controller-stat.patch
Patch-id: 78
Patch-present-in-specfile: True
---
target/i386/mshv/mshv-cpu.c | 117 ++++++++++++++++++++++++++++++++++++
1 file changed, 117 insertions(+)
diff --git a/target/i386/mshv/mshv-cpu.c b/target/i386/mshv/mshv-cpu.c
index 8b10c79e54..0fe3cbb48d 100644
--- a/target/i386/mshv/mshv-cpu.c
+++ b/target/i386/mshv/mshv-cpu.c
@@ -12,6 +12,7 @@
#include "qemu/osdep.h"
#include "qemu/error-report.h"
+#include "qemu/memalign.h"
#include "qemu/typedefs.h"
#include "system/mshv.h"
@@ -21,6 +22,7 @@
#include "hw/hyperv/hvgdk.h"
#include "hw/hyperv/hvgdk_mini.h"
#include "hw/hyperv/hvhdk_mini.h"
+#include "hw/i386/apic_internal.h"
#include "cpu.h"
#include "emulate/x86_decode.h"
@@ -562,6 +564,114 @@ static int set_cpu_state(const CPUState *cpu, const MshvFPU *fpu_regs,
return 0;
}
+static int get_vp_state(int cpu_fd, struct mshv_get_set_vp_state *state)
+{
+ int ret;
+
+ ret = ioctl(cpu_fd, MSHV_GET_VP_STATE, state);
+ if (ret < 0) {
+ error_report("failed to get partition state: %s", strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+static int get_lapic(int cpu_fd,
+ struct hv_local_interrupt_controller_state *state)
+{
+ int ret;
+ size_t size = 4096;
+ /* buffer aligned to 4k, as *state requires that */
+ void *buffer = qemu_memalign(size, size);
+ struct mshv_get_set_vp_state mshv_state = { 0 };
+
+ mshv_state.buf_ptr = (uint64_t) buffer;
+ mshv_state.buf_sz = size;
+ mshv_state.type = MSHV_VP_STATE_LAPIC;
+
+ ret = get_vp_state(cpu_fd, &mshv_state);
+ if (ret == 0) {
+ memcpy(state, buffer, sizeof(*state));
+ }
+ qemu_vfree(buffer);
+ if (ret < 0) {
+ error_report("failed to get lapic");
+ return -1;
+ }
+
+ return 0;
+}
+
+static uint32_t set_apic_delivery_mode(uint32_t reg, uint32_t mode)
+{
+ return ((reg) & ~0x700) | ((mode) << 8);
+}
+
+static int set_vp_state(int cpu_fd, const struct mshv_get_set_vp_state *state)
+{
+ int ret;
+
+ ret = ioctl(cpu_fd, MSHV_SET_VP_STATE, state);
+ if (ret < 0) {
+ error_report("failed to set partition state: %s", strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+static int set_lapic(int cpu_fd,
+ const struct hv_local_interrupt_controller_state *state)
+{
+ int ret;
+ size_t size = 4096;
+ /* buffer aligned to 4k, as *state requires that */
+ void *buffer = qemu_memalign(size, size);
+ struct mshv_get_set_vp_state mshv_state = { 0 };
+
+ if (!state) {
+ error_report("lapic state is NULL");
+ return -1;
+ }
+ memcpy(buffer, state, sizeof(*state));
+
+ mshv_state.buf_ptr = (uint64_t) buffer;
+ mshv_state.buf_sz = size;
+ mshv_state.type = MSHV_VP_STATE_LAPIC;
+
+ ret = set_vp_state(cpu_fd, &mshv_state);
+ qemu_vfree(buffer);
+ if (ret < 0) {
+ error_report("failed to set lapic: %s", strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+static int set_lint(int cpu_fd)
+{
+ int ret;
+ uint32_t *lvt_lint0, *lvt_lint1;
+
+ struct hv_local_interrupt_controller_state lapic_state = { 0 };
+ ret = get_lapic(cpu_fd, &lapic_state);
+ if (ret < 0) {
+ return ret;
+ }
+
+ lvt_lint0 = &lapic_state.apic_lvt_lint0;
+ *lvt_lint0 = set_apic_delivery_mode(*lvt_lint0, APIC_DM_EXTINT);
+
+ lvt_lint1 = &lapic_state.apic_lvt_lint1;
+ *lvt_lint1 = set_apic_delivery_mode(*lvt_lint1, APIC_DM_NMI);
+
+ /* TODO: should we skip setting lapic if the values are the same? */
+
+ return set_lapic(cpu_fd, &lapic_state);
+}
+
/*
* TODO: populate topology info:
*
@@ -573,6 +683,7 @@ int mshv_configure_vcpu(const CPUState *cpu, const struct MshvFPU *fpu,
uint64_t xcr0)
{
int ret;
+ int cpu_fd = mshv_vcpufd(cpu);
ret = set_cpu_state(cpu, fpu, xcr0);
if (ret < 0) {
@@ -580,6 +691,12 @@ int mshv_configure_vcpu(const CPUState *cpu, const struct MshvFPU *fpu,
return -1;
}
+ ret = set_lint(cpu_fd);
+ if (ret < 0) {
+ error_report("failed to set lpic int");
+ return -1;
+ }
+
return 0;
}

View File

@ -1,253 +0,0 @@
From 9b579f8392e7c71e60e5791f3b7980774a6253e1 Mon Sep 17 00:00:00 2001
From: Magnus Kulke <magnuskulke@linux.microsoft.com>
Date: Tue, 16 Sep 2025 18:48:38 +0200
Subject: [PATCH] target/i386/mshv: Register CPUID entries with MSHV
RH-Author: Igor Mammedov <imammedo@redhat.com>
RH-MergeRequest: 437: el10: x86: enablement for Azure L1VH OCP readiness
RH-Jira: RHEL-134212
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [19/30] 4a1e70942d21acee2c90095afd82e9f376b87b56
Convert the guest CPU's CPUID model into MSHV's format and register it
with the hypervisor. This ensures that the guest observes the correct
CPU feature set during CPUID instructions.
Signed-off-by: Magnus Kulke <magnuskulke@linux.microsoft.com>
Link: https://lore.kernel.org/r/20250916164847.77883-19-magnuskulke@linux.microsoft.com
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit 4fa04dd16216e266564606b7da582e5fce07bced)
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Patch-name: kvm-target-i386-mshv-Register-CPUID-entries-with-MSHV.patch
Patch-id: 79
Patch-present-in-specfile: True
---
target/i386/mshv/mshv-cpu.c | 206 ++++++++++++++++++++++++++++++++++++
1 file changed, 206 insertions(+)
diff --git a/target/i386/mshv/mshv-cpu.c b/target/i386/mshv/mshv-cpu.c
index 0fe3cbb48d..2b7a81274b 100644
--- a/target/i386/mshv/mshv-cpu.c
+++ b/target/i386/mshv/mshv-cpu.c
@@ -403,6 +403,206 @@ int mshv_load_regs(CPUState *cpu)
return 0;
}
+static void add_cpuid_entry(GList *cpuid_entries,
+ uint32_t function, uint32_t index,
+ uint32_t eax, uint32_t ebx,
+ uint32_t ecx, uint32_t edx)
+{
+ struct hv_cpuid_entry *entry;
+
+ entry = g_malloc0(sizeof(struct hv_cpuid_entry));
+ entry->function = function;
+ entry->index = index;
+ entry->eax = eax;
+ entry->ebx = ebx;
+ entry->ecx = ecx;
+ entry->edx = edx;
+
+ cpuid_entries = g_list_append(cpuid_entries, entry);
+}
+
+static void collect_cpuid_entries(const CPUState *cpu, GList *cpuid_entries)
+{
+ X86CPU *x86_cpu = X86_CPU(cpu);
+ CPUX86State *env = &x86_cpu->env;
+ uint32_t eax, ebx, ecx, edx;
+ uint32_t leaf, subleaf;
+ size_t max_leaf = 0x1F;
+ size_t max_subleaf = 0x20;
+
+ uint32_t leaves_with_subleaves[] = {0x4, 0x7, 0xD, 0xF, 0x10};
+ int n_subleaf_leaves = ARRAY_SIZE(leaves_with_subleaves);
+
+ /* Regular leaves without subleaves */
+ for (leaf = 0; leaf <= max_leaf; leaf++) {
+ bool has_subleaves = false;
+ for (int i = 0; i < n_subleaf_leaves; i++) {
+ if (leaf == leaves_with_subleaves[i]) {
+ has_subleaves = true;
+ break;
+ }
+ }
+
+ if (!has_subleaves) {
+ cpu_x86_cpuid(env, leaf, 0, &eax, &ebx, &ecx, &edx);
+ if (eax == 0 && ebx == 0 && ecx == 0 && edx == 0) {
+ /* all zeroes indicates no more leaves */
+ continue;
+ }
+
+ add_cpuid_entry(cpuid_entries, leaf, 0, eax, ebx, ecx, edx);
+ continue;
+ }
+
+ subleaf = 0;
+ while (subleaf < max_subleaf) {
+ cpu_x86_cpuid(env, leaf, subleaf, &eax, &ebx, &ecx, &edx);
+
+ if (eax == 0 && ebx == 0 && ecx == 0 && edx == 0) {
+ /* all zeroes indicates no more leaves */
+ break;
+ }
+ add_cpuid_entry(cpuid_entries, leaf, 0, eax, ebx, ecx, edx);
+ subleaf++;
+ }
+ }
+}
+
+static int register_intercept_result_cpuid_entry(const CPUState *cpu,
+ uint8_t subleaf_specific,
+ uint8_t always_override,
+ struct hv_cpuid_entry *entry)
+{
+ int ret;
+ int vp_index = cpu->cpu_index;
+ int cpu_fd = mshv_vcpufd(cpu);
+
+ struct hv_register_x64_cpuid_result_parameters cpuid_params = {
+ .input.eax = entry->function,
+ .input.ecx = entry->index,
+ .input.subleaf_specific = subleaf_specific,
+ .input.always_override = always_override,
+ .input.padding = 0,
+ /*
+ * With regard to masks - these are to specify bits to be overwritten
+ * The current CpuidEntry structure wouldn't allow to carry the masks
+ * in addition to the actual register values. For this reason, the
+ * masks are set to the exact values of the corresponding register bits
+ * to be registered for an overwrite. To view resulting values the
+ * hypervisor would return, HvCallGetVpCpuidValues hypercall can be
+ * used.
+ */
+ .result.eax = entry->eax,
+ .result.eax_mask = entry->eax,
+ .result.ebx = entry->ebx,
+ .result.ebx_mask = entry->ebx,
+ .result.ecx = entry->ecx,
+ .result.ecx_mask = entry->ecx,
+ .result.edx = entry->edx,
+ .result.edx_mask = entry->edx,
+ };
+ union hv_register_intercept_result_parameters parameters = {
+ .cpuid = cpuid_params,
+ };
+
+ hv_input_register_intercept_result in = {0};
+ in.vp_index = vp_index;
+ in.intercept_type = HV_INTERCEPT_TYPE_X64_CPUID;
+ in.parameters = parameters;
+
+ struct mshv_root_hvcall args = {0};
+ args.code = HVCALL_REGISTER_INTERCEPT_RESULT;
+ args.in_sz = sizeof(in);
+ args.in_ptr = (uint64_t)&in;
+
+ ret = mshv_hvcall(cpu_fd, &args);
+ if (ret < 0) {
+ error_report("failed to register intercept result for cpuid");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int register_intercept_result_cpuid(const CPUState *cpu,
+ struct hv_cpuid *cpuid)
+{
+ int ret = 0, entry_ret;
+ struct hv_cpuid_entry *entry;
+ uint8_t subleaf_specific, always_override;
+
+ for (size_t i = 0; i < cpuid->nent; i++) {
+ entry = &cpuid->entries[i];
+
+ /* set defaults */
+ subleaf_specific = 0;
+ always_override = 1;
+
+ /* Intel */
+ /* 0xb - Extended Topology Enumeration Leaf */
+ /* 0x1f - V2 Extended Topology Enumeration Leaf */
+ /* AMD */
+ /* 0x8000_001e - Processor Topology Information */
+ /* 0x8000_0026 - Extended CPU Topology */
+ if (entry->function == 0xb
+ || entry->function == 0x1f
+ || entry->function == 0x8000001e
+ || entry->function == 0x80000026) {
+ subleaf_specific = 1;
+ always_override = 1;
+ } else if (entry->function == 0x00000001
+ || entry->function == 0x80000000
+ || entry->function == 0x80000001
+ || entry->function == 0x80000008) {
+ subleaf_specific = 0;
+ always_override = 1;
+ }
+
+ entry_ret = register_intercept_result_cpuid_entry(cpu, subleaf_specific,
+ always_override,
+ entry);
+ if ((entry_ret < 0) && (ret == 0)) {
+ ret = entry_ret;
+ }
+ }
+
+ return ret;
+}
+
+static int set_cpuid2(const CPUState *cpu)
+{
+ int ret;
+ size_t n_entries, cpuid_size;
+ struct hv_cpuid *cpuid;
+ struct hv_cpuid_entry *entry;
+ GList *entries = NULL;
+
+ collect_cpuid_entries(cpu, entries);
+ n_entries = g_list_length(entries);
+
+ cpuid_size = sizeof(struct hv_cpuid)
+ + n_entries * sizeof(struct hv_cpuid_entry);
+
+ cpuid = g_malloc0(cpuid_size);
+ cpuid->nent = n_entries;
+ cpuid->padding = 0;
+
+ for (size_t i = 0; i < n_entries; i++) {
+ entry = g_list_nth_data(entries, i);
+ cpuid->entries[i] = *entry;
+ g_free(entry);
+ }
+ g_list_free(entries);
+
+ ret = register_intercept_result_cpuid(cpu, cpuid);
+ g_free(cpuid);
+ if (ret < 0) {
+ return ret;
+ }
+
+ return 0;
+}
+
static inline void populate_hv_segment_reg(SegmentCache *seg,
hv_x64_segment_register *hv_reg)
{
@@ -685,6 +885,12 @@ int mshv_configure_vcpu(const CPUState *cpu, const struct MshvFPU *fpu,
int ret;
int cpu_fd = mshv_vcpufd(cpu);
+ ret = set_cpuid2(cpu);
+ if (ret < 0) {
+ error_report("failed to set cpuid");
+ return -1;
+ }
+
ret = set_cpu_state(cpu, fpu, xcr0);
if (ret < 0) {
error_report("failed to set cpu state");

View File

@ -1,529 +0,0 @@
From 100c5e414f7867193fc2973660a6cabbf75f318f Mon Sep 17 00:00:00 2001
From: Magnus Kulke <magnuskulke@linux.microsoft.com>
Date: Thu, 2 Oct 2025 18:19:22 +0200
Subject: [PATCH] target/i386/mshv: Register MSRs with MSHV
RH-Author: Igor Mammedov <imammedo@redhat.com>
RH-MergeRequest: 437: el10: x86: enablement for Azure L1VH OCP readiness
RH-Jira: RHEL-134212
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [20/30] 43ca27cba532fd1d562fa10ade6261df58af82fd
Build and register the guest vCPU's model-specific registers using
the MSHV interface.
Signed-off-by: Magnus Kulke <magnuskulke@linux.microsoft.com>
Link: https://lore.kernel.org/r/20250916164847.77883-20-magnuskulke@linux.microsoft.com
[mshv.h/mshv_int.h split. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit f38e2a63e541730e114f6ed09e5f8719e388c8db)
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Patch-name: kvm-target-i386-mshv-Register-MSRs-with-MSHV.patch
Patch-id: 80
Patch-present-in-specfile: True
---
accel/mshv/meson.build | 1 +
accel/mshv/msr.c | 375 ++++++++++++++++++++++++++++++++++++
include/system/mshv_int.h | 17 ++
target/i386/cpu.h | 2 +
target/i386/mshv/mshv-cpu.c | 33 ++++
5 files changed, 428 insertions(+)
create mode 100644 accel/mshv/msr.c
diff --git a/accel/mshv/meson.build b/accel/mshv/meson.build
index f88fc8678c..d3a2b32581 100644
--- a/accel/mshv/meson.build
+++ b/accel/mshv/meson.build
@@ -2,6 +2,7 @@ mshv_ss = ss.source_set()
mshv_ss.add(if_true: files(
'irq.c',
'mem.c',
+ 'msr.c',
'mshv-all.c'
))
diff --git a/accel/mshv/msr.c b/accel/mshv/msr.c
new file mode 100644
index 0000000000..e6e5baef50
--- /dev/null
+++ b/accel/mshv/msr.c
@@ -0,0 +1,375 @@
+/*
+ * QEMU MSHV support
+ *
+ * Copyright Microsoft, Corp. 2025
+ *
+ * Authors: Magnus Kulke <magnuskulke@microsoft.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "system/mshv.h"
+#include "system/mshv_int.h"
+#include "hw/hyperv/hvgdk_mini.h"
+#include "linux/mshv.h"
+#include "qemu/error-report.h"
+
+static uint32_t supported_msrs[64] = {
+ IA32_MSR_TSC,
+ IA32_MSR_EFER,
+ IA32_MSR_KERNEL_GS_BASE,
+ IA32_MSR_APIC_BASE,
+ IA32_MSR_PAT,
+ IA32_MSR_SYSENTER_CS,
+ IA32_MSR_SYSENTER_ESP,
+ IA32_MSR_SYSENTER_EIP,
+ IA32_MSR_STAR,
+ IA32_MSR_LSTAR,
+ IA32_MSR_CSTAR,
+ IA32_MSR_SFMASK,
+ IA32_MSR_MTRR_DEF_TYPE,
+ IA32_MSR_MTRR_PHYSBASE0,
+ IA32_MSR_MTRR_PHYSMASK0,
+ IA32_MSR_MTRR_PHYSBASE1,
+ IA32_MSR_MTRR_PHYSMASK1,
+ IA32_MSR_MTRR_PHYSBASE2,
+ IA32_MSR_MTRR_PHYSMASK2,
+ IA32_MSR_MTRR_PHYSBASE3,
+ IA32_MSR_MTRR_PHYSMASK3,
+ IA32_MSR_MTRR_PHYSBASE4,
+ IA32_MSR_MTRR_PHYSMASK4,
+ IA32_MSR_MTRR_PHYSBASE5,
+ IA32_MSR_MTRR_PHYSMASK5,
+ IA32_MSR_MTRR_PHYSBASE6,
+ IA32_MSR_MTRR_PHYSMASK6,
+ IA32_MSR_MTRR_PHYSBASE7,
+ IA32_MSR_MTRR_PHYSMASK7,
+ IA32_MSR_MTRR_FIX64K_00000,
+ IA32_MSR_MTRR_FIX16K_80000,
+ IA32_MSR_MTRR_FIX16K_A0000,
+ IA32_MSR_MTRR_FIX4K_C0000,
+ IA32_MSR_MTRR_FIX4K_C8000,
+ IA32_MSR_MTRR_FIX4K_D0000,
+ IA32_MSR_MTRR_FIX4K_D8000,
+ IA32_MSR_MTRR_FIX4K_E0000,
+ IA32_MSR_MTRR_FIX4K_E8000,
+ IA32_MSR_MTRR_FIX4K_F0000,
+ IA32_MSR_MTRR_FIX4K_F8000,
+ IA32_MSR_TSC_AUX,
+ IA32_MSR_DEBUG_CTL,
+ HV_X64_MSR_GUEST_OS_ID,
+ HV_X64_MSR_SINT0,
+ HV_X64_MSR_SINT1,
+ HV_X64_MSR_SINT2,
+ HV_X64_MSR_SINT3,
+ HV_X64_MSR_SINT4,
+ HV_X64_MSR_SINT5,
+ HV_X64_MSR_SINT6,
+ HV_X64_MSR_SINT7,
+ HV_X64_MSR_SINT8,
+ HV_X64_MSR_SINT9,
+ HV_X64_MSR_SINT10,
+ HV_X64_MSR_SINT11,
+ HV_X64_MSR_SINT12,
+ HV_X64_MSR_SINT13,
+ HV_X64_MSR_SINT14,
+ HV_X64_MSR_SINT15,
+ HV_X64_MSR_SCONTROL,
+ HV_X64_MSR_SIEFP,
+ HV_X64_MSR_SIMP,
+ HV_X64_MSR_REFERENCE_TSC,
+ HV_X64_MSR_EOM,
+};
+static const size_t msr_count = ARRAY_SIZE(supported_msrs);
+
+static int compare_msr_index(const void *a, const void *b)
+{
+ return *(uint32_t *)a - *(uint32_t *)b;
+}
+
+__attribute__((constructor))
+static void init_sorted_msr_map(void)
+{
+ qsort(supported_msrs, msr_count, sizeof(uint32_t), compare_msr_index);
+}
+
+static int mshv_is_supported_msr(uint32_t msr)
+{
+ return bsearch(&msr, supported_msrs, msr_count, sizeof(uint32_t),
+ compare_msr_index) != NULL;
+}
+
+static int mshv_msr_to_hv_reg_name(uint32_t msr, uint32_t *hv_reg)
+{
+ switch (msr) {
+ case IA32_MSR_TSC:
+ *hv_reg = HV_X64_REGISTER_TSC;
+ return 0;
+ case IA32_MSR_EFER:
+ *hv_reg = HV_X64_REGISTER_EFER;
+ return 0;
+ case IA32_MSR_KERNEL_GS_BASE:
+ *hv_reg = HV_X64_REGISTER_KERNEL_GS_BASE;
+ return 0;
+ case IA32_MSR_APIC_BASE:
+ *hv_reg = HV_X64_REGISTER_APIC_BASE;
+ return 0;
+ case IA32_MSR_PAT:
+ *hv_reg = HV_X64_REGISTER_PAT;
+ return 0;
+ case IA32_MSR_SYSENTER_CS:
+ *hv_reg = HV_X64_REGISTER_SYSENTER_CS;
+ return 0;
+ case IA32_MSR_SYSENTER_ESP:
+ *hv_reg = HV_X64_REGISTER_SYSENTER_ESP;
+ return 0;
+ case IA32_MSR_SYSENTER_EIP:
+ *hv_reg = HV_X64_REGISTER_SYSENTER_EIP;
+ return 0;
+ case IA32_MSR_STAR:
+ *hv_reg = HV_X64_REGISTER_STAR;
+ return 0;
+ case IA32_MSR_LSTAR:
+ *hv_reg = HV_X64_REGISTER_LSTAR;
+ return 0;
+ case IA32_MSR_CSTAR:
+ *hv_reg = HV_X64_REGISTER_CSTAR;
+ return 0;
+ case IA32_MSR_SFMASK:
+ *hv_reg = HV_X64_REGISTER_SFMASK;
+ return 0;
+ case IA32_MSR_MTRR_CAP:
+ *hv_reg = HV_X64_REGISTER_MSR_MTRR_CAP;
+ return 0;
+ case IA32_MSR_MTRR_DEF_TYPE:
+ *hv_reg = HV_X64_REGISTER_MSR_MTRR_DEF_TYPE;
+ return 0;
+ case IA32_MSR_MTRR_PHYSBASE0:
+ *hv_reg = HV_X64_REGISTER_MSR_MTRR_PHYS_BASE0;
+ return 0;
+ case IA32_MSR_MTRR_PHYSMASK0:
+ *hv_reg = HV_X64_REGISTER_MSR_MTRR_PHYS_MASK0;
+ return 0;
+ case IA32_MSR_MTRR_PHYSBASE1:
+ *hv_reg = HV_X64_REGISTER_MSR_MTRR_PHYS_BASE1;
+ return 0;
+ case IA32_MSR_MTRR_PHYSMASK1:
+ *hv_reg = HV_X64_REGISTER_MSR_MTRR_PHYS_MASK1;
+ return 0;
+ case IA32_MSR_MTRR_PHYSBASE2:
+ *hv_reg = HV_X64_REGISTER_MSR_MTRR_PHYS_BASE2;
+ return 0;
+ case IA32_MSR_MTRR_PHYSMASK2:
+ *hv_reg = HV_X64_REGISTER_MSR_MTRR_PHYS_MASK2;
+ return 0;
+ case IA32_MSR_MTRR_PHYSBASE3:
+ *hv_reg = HV_X64_REGISTER_MSR_MTRR_PHYS_BASE3;
+ return 0;
+ case IA32_MSR_MTRR_PHYSMASK3:
+ *hv_reg = HV_X64_REGISTER_MSR_MTRR_PHYS_MASK3;
+ return 0;
+ case IA32_MSR_MTRR_PHYSBASE4:
+ *hv_reg = HV_X64_REGISTER_MSR_MTRR_PHYS_BASE4;
+ return 0;
+ case IA32_MSR_MTRR_PHYSMASK4:
+ *hv_reg = HV_X64_REGISTER_MSR_MTRR_PHYS_MASK4;
+ return 0;
+ case IA32_MSR_MTRR_PHYSBASE5:
+ *hv_reg = HV_X64_REGISTER_MSR_MTRR_PHYS_BASE5;
+ return 0;
+ case IA32_MSR_MTRR_PHYSMASK5:
+ *hv_reg = HV_X64_REGISTER_MSR_MTRR_PHYS_MASK5;
+ return 0;
+ case IA32_MSR_MTRR_PHYSBASE6:
+ *hv_reg = HV_X64_REGISTER_MSR_MTRR_PHYS_BASE6;
+ return 0;
+ case IA32_MSR_MTRR_PHYSMASK6:
+ *hv_reg = HV_X64_REGISTER_MSR_MTRR_PHYS_MASK6;
+ return 0;
+ case IA32_MSR_MTRR_PHYSBASE7:
+ *hv_reg = HV_X64_REGISTER_MSR_MTRR_PHYS_BASE7;
+ return 0;
+ case IA32_MSR_MTRR_PHYSMASK7:
+ *hv_reg = HV_X64_REGISTER_MSR_MTRR_PHYS_MASK7;
+ return 0;
+ case IA32_MSR_MTRR_FIX64K_00000:
+ *hv_reg = HV_X64_REGISTER_MSR_MTRR_FIX64K00000;
+ return 0;
+ case IA32_MSR_MTRR_FIX16K_80000:
+ *hv_reg = HV_X64_REGISTER_MSR_MTRR_FIX16K80000;
+ return 0;
+ case IA32_MSR_MTRR_FIX16K_A0000:
+ *hv_reg = HV_X64_REGISTER_MSR_MTRR_FIX16KA0000;
+ return 0;
+ case IA32_MSR_MTRR_FIX4K_C0000:
+ *hv_reg = HV_X64_REGISTER_MSR_MTRR_FIX4KC0000;
+ return 0;
+ case IA32_MSR_MTRR_FIX4K_C8000:
+ *hv_reg = HV_X64_REGISTER_MSR_MTRR_FIX4KC8000;
+ return 0;
+ case IA32_MSR_MTRR_FIX4K_D0000:
+ *hv_reg = HV_X64_REGISTER_MSR_MTRR_FIX4KD0000;
+ return 0;
+ case IA32_MSR_MTRR_FIX4K_D8000:
+ *hv_reg = HV_X64_REGISTER_MSR_MTRR_FIX4KD8000;
+ return 0;
+ case IA32_MSR_MTRR_FIX4K_E0000:
+ *hv_reg = HV_X64_REGISTER_MSR_MTRR_FIX4KE0000;
+ return 0;
+ case IA32_MSR_MTRR_FIX4K_E8000:
+ *hv_reg = HV_X64_REGISTER_MSR_MTRR_FIX4KE8000;
+ return 0;
+ case IA32_MSR_MTRR_FIX4K_F0000:
+ *hv_reg = HV_X64_REGISTER_MSR_MTRR_FIX4KF0000;
+ return 0;
+ case IA32_MSR_MTRR_FIX4K_F8000:
+ *hv_reg = HV_X64_REGISTER_MSR_MTRR_FIX4KF8000;
+ return 0;
+ case IA32_MSR_TSC_AUX:
+ *hv_reg = HV_X64_REGISTER_TSC_AUX;
+ return 0;
+ case IA32_MSR_BNDCFGS:
+ *hv_reg = HV_X64_REGISTER_BNDCFGS;
+ return 0;
+ case IA32_MSR_DEBUG_CTL:
+ *hv_reg = HV_X64_REGISTER_DEBUG_CTL;
+ return 0;
+ case IA32_MSR_TSC_ADJUST:
+ *hv_reg = HV_X64_REGISTER_TSC_ADJUST;
+ return 0;
+ case IA32_MSR_SPEC_CTRL:
+ *hv_reg = HV_X64_REGISTER_SPEC_CTRL;
+ return 0;
+ case HV_X64_MSR_GUEST_OS_ID:
+ *hv_reg = HV_REGISTER_GUEST_OS_ID;
+ return 0;
+ case HV_X64_MSR_SINT0:
+ *hv_reg = HV_REGISTER_SINT0;
+ return 0;
+ case HV_X64_MSR_SINT1:
+ *hv_reg = HV_REGISTER_SINT1;
+ return 0;
+ case HV_X64_MSR_SINT2:
+ *hv_reg = HV_REGISTER_SINT2;
+ return 0;
+ case HV_X64_MSR_SINT3:
+ *hv_reg = HV_REGISTER_SINT3;
+ return 0;
+ case HV_X64_MSR_SINT4:
+ *hv_reg = HV_REGISTER_SINT4;
+ return 0;
+ case HV_X64_MSR_SINT5:
+ *hv_reg = HV_REGISTER_SINT5;
+ return 0;
+ case HV_X64_MSR_SINT6:
+ *hv_reg = HV_REGISTER_SINT6;
+ return 0;
+ case HV_X64_MSR_SINT7:
+ *hv_reg = HV_REGISTER_SINT7;
+ return 0;
+ case HV_X64_MSR_SINT8:
+ *hv_reg = HV_REGISTER_SINT8;
+ return 0;
+ case HV_X64_MSR_SINT9:
+ *hv_reg = HV_REGISTER_SINT9;
+ return 0;
+ case HV_X64_MSR_SINT10:
+ *hv_reg = HV_REGISTER_SINT10;
+ return 0;
+ case HV_X64_MSR_SINT11:
+ *hv_reg = HV_REGISTER_SINT11;
+ return 0;
+ case HV_X64_MSR_SINT12:
+ *hv_reg = HV_REGISTER_SINT12;
+ return 0;
+ case HV_X64_MSR_SINT13:
+ *hv_reg = HV_REGISTER_SINT13;
+ return 0;
+ case HV_X64_MSR_SINT14:
+ *hv_reg = HV_REGISTER_SINT14;
+ return 0;
+ case HV_X64_MSR_SINT15:
+ *hv_reg = HV_REGISTER_SINT15;
+ return 0;
+ case IA32_MSR_MISC_ENABLE:
+ *hv_reg = HV_X64_REGISTER_MSR_IA32_MISC_ENABLE;
+ return 0;
+ case HV_X64_MSR_SCONTROL:
+ *hv_reg = HV_REGISTER_SCONTROL;
+ return 0;
+ case HV_X64_MSR_SIEFP:
+ *hv_reg = HV_REGISTER_SIEFP;
+ return 0;
+ case HV_X64_MSR_SIMP:
+ *hv_reg = HV_REGISTER_SIMP;
+ return 0;
+ case HV_X64_MSR_REFERENCE_TSC:
+ *hv_reg = HV_REGISTER_REFERENCE_TSC;
+ return 0;
+ case HV_X64_MSR_EOM:
+ *hv_reg = HV_REGISTER_EOM;
+ return 0;
+ default:
+ error_report("failed to map MSR %u to HV register name", msr);
+ return -1;
+ }
+}
+
+static int set_msrs(const CPUState *cpu, GList *msrs)
+{
+ size_t n_msrs;
+ GList *entries;
+ MshvMsrEntry *entry;
+ enum hv_register_name name;
+ struct hv_register_assoc *assoc;
+ int ret;
+ size_t i = 0;
+
+ n_msrs = g_list_length(msrs);
+ hv_register_assoc *assocs = g_new0(hv_register_assoc, n_msrs);
+
+ entries = msrs;
+ for (const GList *elem = entries; elem != NULL; elem = elem->next) {
+ entry = elem->data;
+ ret = mshv_msr_to_hv_reg_name(entry->index, &name);
+ if (ret < 0) {
+ g_free(assocs);
+ return ret;
+ }
+ assoc = &assocs[i];
+ assoc->name = name;
+ /* the union has been initialized to 0 */
+ assoc->value.reg64 = entry->data;
+ i++;
+ }
+ ret = mshv_set_generic_regs(cpu, assocs, n_msrs);
+ g_free(assocs);
+ if (ret < 0) {
+ error_report("failed to set msrs");
+ return -1;
+ }
+ return 0;
+}
+
+
+int mshv_configure_msr(const CPUState *cpu, const MshvMsrEntry *msrs,
+ size_t n_msrs)
+{
+ GList *valid_msrs = NULL;
+ uint32_t msr_index;
+ int ret;
+
+ for (size_t i = 0; i < n_msrs; i++) {
+ msr_index = msrs[i].index;
+ /* check whether index of msrs is in SUPPORTED_MSRS */
+ if (mshv_is_supported_msr(msr_index)) {
+ valid_msrs = g_list_append(valid_msrs, (void *) &msrs[i]);
+ }
+ }
+
+ ret = set_msrs(cpu, valid_msrs);
+ g_list_free(valid_msrs);
+
+ return ret;
+}
diff --git a/include/system/mshv_int.h b/include/system/mshv_int.h
index 0ea8d504fa..6649438313 100644
--- a/include/system/mshv_int.h
+++ b/include/system/mshv_int.h
@@ -14,6 +14,8 @@
#ifndef QEMU_MSHV_INT_H
#define QEMU_MSHV_INT_H
+#define MSHV_MSR_ENTRIES_COUNT 64
+
typedef struct hyperv_message hv_message;
struct AccelCPUState {
@@ -102,6 +104,21 @@ typedef struct MshvMemoryRegion {
void mshv_set_phys_mem(MshvMemoryListener *mml, MemoryRegionSection *section,
bool add);
+/* msr */
+typedef struct MshvMsrEntry {
+ uint32_t index;
+ uint32_t reserved;
+ uint64_t data;
+} MshvMsrEntry;
+
+typedef struct MshvMsrEntries {
+ MshvMsrEntry entries[MSHV_MSR_ENTRIES_COUNT];
+ uint32_t nmsrs;
+} MshvMsrEntries;
+
+int mshv_configure_msr(const CPUState *cpu, const MshvMsrEntry *msrs,
+ size_t n_msrs);
+
/* interrupt */
void mshv_init_msicontrol(void);
int mshv_reserve_ioapic_msi_routes(int vm_fd);
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index 4b7eae43e1..8f780a3abe 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -435,9 +435,11 @@ typedef enum X86Seg {
#define MSR_SMI_COUNT 0x34
#define MSR_CORE_THREAD_COUNT 0x35
#define MSR_MTRRcap 0xfe
+#define MSR_MTRR_MEM_TYPE_WB 0x06
#define MSR_MTRRcap_VCNT 8
#define MSR_MTRRcap_FIXRANGE_SUPPORT (1 << 8)
#define MSR_MTRRcap_WC_SUPPORTED (1 << 10)
+#define MSR_MTRR_ENABLE (1 << 11)
#define MSR_IA32_SYSENTER_CS 0x174
#define MSR_IA32_SYSENTER_ESP 0x175
diff --git a/target/i386/mshv/mshv-cpu.c b/target/i386/mshv/mshv-cpu.c
index 2b7a81274b..1f43dfc58a 100644
--- a/target/i386/mshv/mshv-cpu.c
+++ b/target/i386/mshv/mshv-cpu.c
@@ -872,6 +872,33 @@ static int set_lint(int cpu_fd)
return set_lapic(cpu_fd, &lapic_state);
}
+static int setup_msrs(const CPUState *cpu)
+{
+ int ret;
+ uint64_t default_type = MSR_MTRR_ENABLE | MSR_MTRR_MEM_TYPE_WB;
+
+ /* boot msr entries */
+ MshvMsrEntry msrs[9] = {
+ { .index = IA32_MSR_SYSENTER_CS, .data = 0x0, },
+ { .index = IA32_MSR_SYSENTER_ESP, .data = 0x0, },
+ { .index = IA32_MSR_SYSENTER_EIP, .data = 0x0, },
+ { .index = IA32_MSR_STAR, .data = 0x0, },
+ { .index = IA32_MSR_CSTAR, .data = 0x0, },
+ { .index = IA32_MSR_LSTAR, .data = 0x0, },
+ { .index = IA32_MSR_KERNEL_GS_BASE, .data = 0x0, },
+ { .index = IA32_MSR_SFMASK, .data = 0x0, },
+ { .index = IA32_MSR_MTRR_DEF_TYPE, .data = default_type, },
+ };
+
+ ret = mshv_configure_msr(cpu, msrs, 9);
+ if (ret < 0) {
+ error_report("failed to setup msrs");
+ return -1;
+ }
+
+ return 0;
+}
+
/*
* TODO: populate topology info:
*
@@ -891,6 +918,12 @@ int mshv_configure_vcpu(const CPUState *cpu, const struct MshvFPU *fpu,
return -1;
}
+ ret = setup_msrs(cpu);
+ if (ret < 0) {
+ error_report("failed to setup msrs");
+ return -1;
+ }
+
ret = set_cpu_state(cpu, fpu, xcr0);
if (ret < 0) {
error_report("failed to set cpu state");

View File

@ -1,283 +0,0 @@
From 0f233bbf8c0eafdef5d1d4ceb9fcd5264dec029e Mon Sep 17 00:00:00 2001
From: Magnus Kulke <magnuskulke@linux.microsoft.com>
Date: Tue, 16 Sep 2025 18:48:40 +0200
Subject: [PATCH] target/i386/mshv: Integrate x86 instruction decoder/emulator
RH-Author: Igor Mammedov <imammedo@redhat.com>
RH-MergeRequest: 437: el10: x86: enablement for Azure L1VH OCP readiness
RH-Jira: RHEL-134212
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [21/30] c9dba7c3e0a4c896fa581b97f121a293606e074f
Connect the x86 instruction decoder and emulator to the MSHV backend
to handle intercepted instructions. This enables software emulation
of MMIO operations in MSHV guests. MSHV has a translate_gva hypercall
that is used to accessing the physical guest memory.
A guest might read from unmapped memory regions (e.g. OVMF will probe
0xfed40000 for a vTPM). In those cases 0xFF bytes is returned instead of
aborting the execution.
Signed-off-by: Magnus Kulke <magnuskulke@linux.microsoft.com>
Link: https://lore.kernel.org/r/20250916164847.77883-21-magnuskulke@linux.microsoft.com
[mshv.h/mshv_int.h split. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit 9bc6a1d29605a13c541629a651e41787af65a963)
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Patch-name: kvm-target-i386-mshv-Integrate-x86-instruction-decoder-e.patch
Patch-id: 81
Patch-present-in-specfile: True
---
accel/mshv/mem.c | 65 +++++++++++++++++
include/system/mshv_int.h | 4 ++
target/i386/mshv/mshv-cpu.c | 135 ++++++++++++++++++++++++++++++++++++
3 files changed, 204 insertions(+)
diff --git a/accel/mshv/mem.c b/accel/mshv/mem.c
index a0a40eb333..e55c38d4db 100644
--- a/accel/mshv/mem.c
+++ b/accel/mshv/mem.c
@@ -59,6 +59,71 @@ static int map_or_unmap(int vm_fd, const MshvMemoryRegion *mr, bool map)
return set_guest_memory(vm_fd, &region);
}
+static int handle_unmapped_mmio_region_read(uint64_t gpa, uint64_t size,
+ uint8_t *data)
+{
+ warn_report("read from unmapped mmio region gpa=0x%lx size=%lu", gpa, size);
+
+ if (size == 0 || size > 8) {
+ error_report("invalid size %lu for reading from unmapped mmio region",
+ size);
+ return -1;
+ }
+
+ memset(data, 0xFF, size);
+
+ return 0;
+}
+
+int mshv_guest_mem_read(uint64_t gpa, uint8_t *data, uintptr_t size,
+ bool is_secure_mode, bool instruction_fetch)
+{
+ int ret;
+ MemTxAttrs memattr = { .secure = is_secure_mode };
+
+ if (instruction_fetch) {
+ trace_mshv_insn_fetch(gpa, size);
+ } else {
+ trace_mshv_mem_read(gpa, size);
+ }
+
+ ret = address_space_rw(&address_space_memory, gpa, memattr, (void *)data,
+ size, false);
+ if (ret == MEMTX_OK) {
+ return 0;
+ }
+
+ if (ret == MEMTX_DECODE_ERROR) {
+ return handle_unmapped_mmio_region_read(gpa, size, data);
+ }
+
+ error_report("failed to read guest memory at 0x%lx", gpa);
+ return -1;
+}
+
+int mshv_guest_mem_write(uint64_t gpa, const uint8_t *data, uintptr_t size,
+ bool is_secure_mode)
+{
+ int ret;
+ MemTxAttrs memattr = { .secure = is_secure_mode };
+
+ trace_mshv_mem_write(gpa, size);
+ ret = address_space_rw(&address_space_memory, gpa, memattr, (void *)data,
+ size, true);
+ if (ret == MEMTX_OK) {
+ return 0;
+ }
+
+ if (ret == MEMTX_DECODE_ERROR) {
+ warn_report("write to unmapped mmio region gpa=0x%lx size=%lu", gpa,
+ size);
+ return 0;
+ }
+
+ error_report("Failed to write guest memory");
+ return -1;
+}
+
static int set_memory(const MshvMemoryRegion *mshv_mr, bool add)
{
int ret = 0;
diff --git a/include/system/mshv_int.h b/include/system/mshv_int.h
index 6649438313..b29d39911d 100644
--- a/include/system/mshv_int.h
+++ b/include/system/mshv_int.h
@@ -101,6 +101,10 @@ typedef struct MshvMemoryRegion {
bool readonly;
} MshvMemoryRegion;
+int mshv_guest_mem_read(uint64_t gpa, uint8_t *data, uintptr_t size,
+ bool is_secure_mode, bool instruction_fetch);
+int mshv_guest_mem_write(uint64_t gpa, const uint8_t *data, uintptr_t size,
+ bool is_secure_mode);
void mshv_set_phys_mem(MshvMemoryListener *mml, MemoryRegionSection *section,
bool add);
diff --git a/target/i386/mshv/mshv-cpu.c b/target/i386/mshv/mshv-cpu.c
index 1f43dfc58a..424ebdb122 100644
--- a/target/i386/mshv/mshv-cpu.c
+++ b/target/i386/mshv/mshv-cpu.c
@@ -104,6 +104,47 @@ static enum hv_register_name FPU_REGISTER_NAMES[26] = {
HV_X64_REGISTER_XMM_CONTROL_STATUS,
};
+static int translate_gva(const CPUState *cpu, uint64_t gva, uint64_t *gpa,
+ uint64_t flags)
+{
+ int ret;
+ int cpu_fd = mshv_vcpufd(cpu);
+ int vp_index = cpu->cpu_index;
+
+ hv_input_translate_virtual_address in = { 0 };
+ hv_output_translate_virtual_address out = { 0 };
+ struct mshv_root_hvcall args = {0};
+ uint64_t gva_page = gva >> HV_HYP_PAGE_SHIFT;
+
+ in.vp_index = vp_index;
+ in.control_flags = flags;
+ in.gva_page = gva_page;
+
+ /* create the hvcall envelope */
+ args.code = HVCALL_TRANSLATE_VIRTUAL_ADDRESS;
+ args.in_sz = sizeof(in);
+ args.in_ptr = (uint64_t) &in;
+ args.out_sz = sizeof(out);
+ args.out_ptr = (uint64_t) &out;
+
+ /* perform the call */
+ ret = mshv_hvcall(cpu_fd, &args);
+ if (ret < 0) {
+ error_report("Failed to invoke gva->gpa translation");
+ return -errno;
+ }
+
+ if (out.translation_result.result_code != HV_TRANSLATE_GVA_SUCCESS) {
+ error_report("Failed to translate gva (" TARGET_FMT_lx ") to gpa", gva);
+ return -1;
+ }
+
+ *gpa = ((out.gpa_page << HV_HYP_PAGE_SHIFT)
+ | (gva & ~(uint64_t)HV_HYP_PAGE_MASK));
+
+ return 0;
+}
+
int mshv_set_generic_regs(const CPUState *cpu, const hv_register_assoc *assocs,
size_t n_regs)
{
@@ -1006,8 +1047,102 @@ int mshv_create_vcpu(int vm_fd, uint8_t vp_index, int *cpu_fd)
return 0;
}
+static int guest_mem_read_with_gva(const CPUState *cpu, uint64_t gva,
+ uint8_t *data, uintptr_t size,
+ bool fetch_instruction)
+{
+ int ret;
+ uint64_t gpa, flags;
+
+ flags = HV_TRANSLATE_GVA_VALIDATE_READ;
+ ret = translate_gva(cpu, gva, &gpa, flags);
+ if (ret < 0) {
+ error_report("failed to translate gva to gpa");
+ return -1;
+ }
+
+ ret = mshv_guest_mem_read(gpa, data, size, false, fetch_instruction);
+ if (ret < 0) {
+ error_report("failed to read from guest memory");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int guest_mem_write_with_gva(const CPUState *cpu, uint64_t gva,
+ const uint8_t *data, uintptr_t size)
+{
+ int ret;
+ uint64_t gpa, flags;
+
+ flags = HV_TRANSLATE_GVA_VALIDATE_WRITE;
+ ret = translate_gva(cpu, gva, &gpa, flags);
+ if (ret < 0) {
+ error_report("failed to translate gva to gpa");
+ return -1;
+ }
+ ret = mshv_guest_mem_write(gpa, data, size, false);
+ if (ret < 0) {
+ error_report("failed to write to guest memory");
+ return -1;
+ }
+ return 0;
+}
+
+static void write_mem(CPUState *cpu, void *data, target_ulong addr, int bytes)
+{
+ if (guest_mem_write_with_gva(cpu, addr, data, bytes) < 0) {
+ error_report("failed to write memory");
+ abort();
+ }
+}
+
+static void fetch_instruction(CPUState *cpu, void *data,
+ target_ulong addr, int bytes)
+{
+ if (guest_mem_read_with_gva(cpu, addr, data, bytes, true) < 0) {
+ error_report("failed to fetch instruction");
+ abort();
+ }
+}
+
+static void read_mem(CPUState *cpu, void *data, target_ulong addr, int bytes)
+{
+ if (guest_mem_read_with_gva(cpu, addr, data, bytes, false) < 0) {
+ error_report("failed to read memory");
+ abort();
+ }
+}
+
+static void read_segment_descriptor(CPUState *cpu,
+ struct x86_segment_descriptor *desc,
+ enum X86Seg seg_idx)
+{
+ bool ret;
+ X86CPU *x86_cpu = X86_CPU(cpu);
+ CPUX86State *env = &x86_cpu->env;
+ SegmentCache *seg = &env->segs[seg_idx];
+ x86_segment_selector sel = { .sel = seg->selector & 0xFFFF };
+
+ ret = x86_read_segment_descriptor(cpu, desc, sel);
+ if (ret == false) {
+ error_report("failed to read segment descriptor");
+ abort();
+ }
+}
+
+static const struct x86_emul_ops mshv_x86_emul_ops = {
+ .fetch_instruction = fetch_instruction,
+ .read_mem = read_mem,
+ .write_mem = write_mem,
+ .read_segment_descriptor = read_segment_descriptor,
+};
+
void mshv_init_mmio_emu(void)
{
+ init_decoder();
+ init_emu(&mshv_x86_emul_ops);
}
void mshv_arch_init_vcpu(CPUState *cpu)

View File

@ -1,114 +0,0 @@
From 8e713b554eac614d11513364580ffc8e5723645a Mon Sep 17 00:00:00 2001
From: Magnus Kulke <magnuskulke@linux.microsoft.com>
Date: Tue, 16 Sep 2025 18:48:41 +0200
Subject: [PATCH] target/i386/mshv: Write MSRs to the hypervisor
RH-Author: Igor Mammedov <imammedo@redhat.com>
RH-MergeRequest: 437: el10: x86: enablement for Azure L1VH OCP readiness
RH-Jira: RHEL-134212
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [22/30] 8b9720dbc31e48c43e618a0650a21eb5a43b7954
Push current model-specific register (MSR) values to MSHV's vCPUs as
part of setting state to the hypervisor.
Signed-off-by: Magnus Kulke <magnuskulke@linux.microsoft.com>
Link: https://lore.kernel.org/r/20250916164847.77883-22-magnuskulke@linux.microsoft.com
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit 64118f452cbd97cd9fa790b1c15b65b435f136d2)
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Patch-name: kvm-target-i386-mshv-Write-MSRs-to-the-hypervisor.patch
Patch-id: 82
Patch-present-in-specfile: True
---
target/i386/mshv/mshv-cpu.c | 68 +++++++++++++++++++++++++++++++++++--
1 file changed, 66 insertions(+), 2 deletions(-)
diff --git a/target/i386/mshv/mshv-cpu.c b/target/i386/mshv/mshv-cpu.c
index 424ebdb122..33a3ce8b11 100644
--- a/target/i386/mshv/mshv-cpu.c
+++ b/target/i386/mshv/mshv-cpu.c
@@ -998,6 +998,65 @@ static int put_regs(const CPUState *cpu)
return 0;
}
+struct MsrPair {
+ uint32_t index;
+ uint64_t value;
+};
+
+static int put_msrs(const CPUState *cpu)
+{
+ int ret = 0;
+ X86CPU *x86cpu = X86_CPU(cpu);
+ CPUX86State *env = &x86cpu->env;
+ MshvMsrEntries *msrs = g_malloc0(sizeof(MshvMsrEntries));
+
+ struct MsrPair pairs[] = {
+ { MSR_IA32_SYSENTER_CS, env->sysenter_cs },
+ { MSR_IA32_SYSENTER_ESP, env->sysenter_esp },
+ { MSR_IA32_SYSENTER_EIP, env->sysenter_eip },
+ { MSR_EFER, env->efer },
+ { MSR_PAT, env->pat },
+ { MSR_STAR, env->star },
+ { MSR_CSTAR, env->cstar },
+ { MSR_LSTAR, env->lstar },
+ { MSR_KERNELGSBASE, env->kernelgsbase },
+ { MSR_FMASK, env->fmask },
+ { MSR_MTRRdefType, env->mtrr_deftype },
+ { MSR_VM_HSAVE_PA, env->vm_hsave },
+ { MSR_SMI_COUNT, env->msr_smi_count },
+ { MSR_IA32_PKRS, env->pkrs },
+ { MSR_IA32_BNDCFGS, env->msr_bndcfgs },
+ { MSR_IA32_XSS, env->xss },
+ { MSR_IA32_UMWAIT_CONTROL, env->umwait },
+ { MSR_IA32_TSX_CTRL, env->tsx_ctrl },
+ { MSR_AMD64_TSC_RATIO, env->amd_tsc_scale_msr },
+ { MSR_TSC_AUX, env->tsc_aux },
+ { MSR_TSC_ADJUST, env->tsc_adjust },
+ { MSR_IA32_SMBASE, env->smbase },
+ { MSR_IA32_SPEC_CTRL, env->spec_ctrl },
+ { MSR_VIRT_SSBD, env->virt_ssbd },
+ };
+
+ if (ARRAY_SIZE(pairs) > MSHV_MSR_ENTRIES_COUNT) {
+ error_report("MSR entries exceed maximum size");
+ g_free(msrs);
+ return -1;
+ }
+
+ for (size_t i = 0; i < ARRAY_SIZE(pairs); i++) {
+ MshvMsrEntry *entry = &msrs->entries[i];
+ entry->index = pairs[i].index;
+ entry->reserved = 0;
+ entry->data = pairs[i].value;
+ msrs->nmsrs++;
+ }
+
+ ret = mshv_configure_msr(cpu, &msrs->entries[0], msrs->nmsrs);
+ g_free(msrs);
+ return ret;
+}
+
+
int mshv_arch_put_registers(const CPUState *cpu)
{
int ret;
@@ -1008,8 +1067,13 @@ int mshv_arch_put_registers(const CPUState *cpu)
return -1;
}
- error_report("unimplemented");
- abort();
+ ret = put_msrs(cpu);
+ if (ret < 0) {
+ error_report("Failed to put msrs");
+ return -1;
+ }
+
+ return 0;
}
void mshv_arch_amend_proc_features(

View File

@ -1,490 +0,0 @@
From 4c7f452f08434460dd37f604d985588b248d7759 Mon Sep 17 00:00:00 2001
From: Magnus Kulke <magnuskulke@linux.microsoft.com>
Date: Tue, 16 Sep 2025 18:48:42 +0200
Subject: [PATCH] target/i386/mshv: Implement mshv_vcpu_run()
RH-Author: Igor Mammedov <imammedo@redhat.com>
RH-MergeRequest: 437: el10: x86: enablement for Azure L1VH OCP readiness
RH-Jira: RHEL-134212
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [23/30] f21e5df491be51f4256237f9497fbc73f44cc386
Add the main vCPU execution loop for MSHV using the MSHV_RUN_VP ioctl.
The execution loop handles guest entry and VM exits. There are handlers for
memory r/w, PIO and MMIO to which the exit events are dispatched.
In case of MMIO the i386 instruction decoder/emulator is invoked to
perform the operation in user space.
Signed-off-by: Magnus Kulke <magnuskulke@linux.microsoft.com>
Link: https://lore.kernel.org/r/20250916164847.77883-23-magnuskulke@linux.microsoft.com
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit 6dec60528c419781f1f79cd9837d5f26415a3fd7)
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Patch-name: kvm-target-i386-mshv-Implement-mshv_vcpu_run.patch
Patch-id: 83
Patch-present-in-specfile: True
---
target/i386/mshv/mshv-cpu.c | 444 +++++++++++++++++++++++++++++++++++-
1 file changed, 442 insertions(+), 2 deletions(-)
diff --git a/target/i386/mshv/mshv-cpu.c b/target/i386/mshv/mshv-cpu.c
index 33a3ce8b11..7edc032cea 100644
--- a/target/i386/mshv/mshv-cpu.c
+++ b/target/i386/mshv/mshv-cpu.c
@@ -1082,10 +1082,450 @@ void mshv_arch_amend_proc_features(
features->access_guest_idle_reg = 1;
}
+static int set_memory_info(const struct hyperv_message *msg,
+ struct hv_x64_memory_intercept_message *info)
+{
+ if (msg->header.message_type != HVMSG_GPA_INTERCEPT
+ && msg->header.message_type != HVMSG_UNMAPPED_GPA
+ && msg->header.message_type != HVMSG_UNACCEPTED_GPA) {
+ error_report("invalid message type");
+ return -1;
+ }
+ memcpy(info, msg->payload, sizeof(*info));
+
+ return 0;
+}
+
+static int emulate_instruction(CPUState *cpu,
+ const uint8_t *insn_bytes, size_t insn_len,
+ uint64_t gva, uint64_t gpa)
+{
+ X86CPU *x86_cpu = X86_CPU(cpu);
+ CPUX86State *env = &x86_cpu->env;
+ struct x86_decode decode = { 0 };
+ int ret;
+ x86_insn_stream stream = { .bytes = insn_bytes, .len = insn_len };
+
+ ret = mshv_load_regs(cpu);
+ if (ret < 0) {
+ error_report("failed to load registers");
+ return -1;
+ }
+
+ decode_instruction_stream(env, &decode, &stream);
+ exec_instruction(env, &decode);
+
+ ret = mshv_store_regs(cpu);
+ if (ret < 0) {
+ error_report("failed to store registers");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int handle_mmio(CPUState *cpu, const struct hyperv_message *msg,
+ MshvVmExit *exit_reason)
+{
+ struct hv_x64_memory_intercept_message info = { 0 };
+ size_t insn_len;
+ uint8_t access_type;
+ uint8_t *instruction_bytes;
+ int ret;
+
+ ret = set_memory_info(msg, &info);
+ if (ret < 0) {
+ error_report("failed to convert message to memory info");
+ return -1;
+ }
+ insn_len = info.instruction_byte_count;
+ access_type = info.header.intercept_access_type;
+
+ if (access_type == HV_X64_INTERCEPT_ACCESS_TYPE_EXECUTE) {
+ error_report("invalid intercept access type: execute");
+ return -1;
+ }
+
+ if (insn_len > 16) {
+ error_report("invalid mmio instruction length: %zu", insn_len);
+ return -1;
+ }
+
+ trace_mshv_handle_mmio(info.guest_virtual_address,
+ info.guest_physical_address,
+ info.instruction_byte_count, access_type);
+
+ instruction_bytes = info.instruction_bytes;
+
+ ret = emulate_instruction(cpu, instruction_bytes, insn_len,
+ info.guest_virtual_address,
+ info.guest_physical_address);
+ if (ret < 0) {
+ error_report("failed to emulate mmio");
+ return -1;
+ }
+
+ *exit_reason = MshvVmExitIgnore;
+
+ return 0;
+}
+
+static int set_ioport_info(const struct hyperv_message *msg,
+ hv_x64_io_port_intercept_message *info)
+{
+ if (msg->header.message_type != HVMSG_X64_IO_PORT_INTERCEPT) {
+ error_report("Invalid message type");
+ return -1;
+ }
+ memcpy(info, msg->payload, sizeof(*info));
+
+ return 0;
+}
+
+static int set_x64_registers(const CPUState *cpu, const uint32_t *names,
+ const uint64_t *values)
+{
+
+ hv_register_assoc assocs[2];
+ int ret;
+
+ for (size_t i = 0; i < ARRAY_SIZE(assocs); i++) {
+ assocs[i].name = names[i];
+ assocs[i].value.reg64 = values[i];
+ }
+
+ ret = mshv_set_generic_regs(cpu, assocs, ARRAY_SIZE(assocs));
+ if (ret < 0) {
+ error_report("failed to set x64 registers");
+ return -1;
+ }
+
+ return 0;
+}
+
+static inline MemTxAttrs get_mem_attrs(bool is_secure_mode)
+{
+ MemTxAttrs memattr = {0};
+ memattr.secure = is_secure_mode;
+ return memattr;
+}
+
+static void pio_read(uint64_t port, uint8_t *data, uintptr_t size,
+ bool is_secure_mode)
+{
+ int ret = 0;
+ MemTxAttrs memattr = get_mem_attrs(is_secure_mode);
+ ret = address_space_rw(&address_space_io, port, memattr, (void *)data, size,
+ false);
+ if (ret != MEMTX_OK) {
+ error_report("Failed to read from port %lx: %d", port, ret);
+ abort();
+ }
+}
+
+static int pio_write(uint64_t port, const uint8_t *data, uintptr_t size,
+ bool is_secure_mode)
+{
+ int ret = 0;
+ MemTxAttrs memattr = get_mem_attrs(is_secure_mode);
+ ret = address_space_rw(&address_space_io, port, memattr, (void *)data, size,
+ true);
+ return ret;
+}
+
+static int handle_pio_non_str(const CPUState *cpu,
+ hv_x64_io_port_intercept_message *info)
+{
+ size_t len = info->access_info.access_size;
+ uint8_t access_type = info->header.intercept_access_type;
+ int ret;
+ uint32_t val, eax;
+ const uint32_t eax_mask = 0xffffffffu >> (32 - len * 8);
+ size_t insn_len;
+ uint64_t rip, rax;
+ uint32_t reg_names[2];
+ uint64_t reg_values[2];
+ uint16_t port = info->port_number;
+
+ if (access_type == HV_X64_INTERCEPT_ACCESS_TYPE_WRITE) {
+ union {
+ uint32_t u32;
+ uint8_t bytes[4];
+ } conv;
+
+ /* convert the first 4 bytes of rax to bytes */
+ conv.u32 = (uint32_t)info->rax;
+ /* secure mode is set to false */
+ ret = pio_write(port, conv.bytes, len, false);
+ if (ret < 0) {
+ error_report("Failed to write to io port");
+ return -1;
+ }
+ } else {
+ uint8_t data[4] = { 0 };
+ /* secure mode is set to false */
+ pio_read(info->port_number, data, len, false);
+
+ /* Preserve high bits in EAX, but clear out high bits in RAX */
+ val = *(uint32_t *)data;
+ eax = (((uint32_t)info->rax) & ~eax_mask) | (val & eax_mask);
+ info->rax = (uint64_t)eax;
+ }
+
+ insn_len = info->header.instruction_length;
+
+ /* Advance RIP and update RAX */
+ rip = info->header.rip + insn_len;
+ rax = info->rax;
+
+ reg_names[0] = HV_X64_REGISTER_RIP;
+ reg_values[0] = rip;
+ reg_names[1] = HV_X64_REGISTER_RAX;
+ reg_values[1] = rax;
+
+ ret = set_x64_registers(cpu, reg_names, reg_values);
+ if (ret < 0) {
+ error_report("Failed to set x64 registers");
+ return -1;
+ }
+
+ cpu->accel->dirty = false;
+
+ return 0;
+}
+
+static int fetch_guest_state(CPUState *cpu)
+{
+ int ret;
+
+ ret = mshv_get_standard_regs(cpu);
+ if (ret < 0) {
+ error_report("Failed to get standard registers");
+ return -1;
+ }
+
+ ret = mshv_get_special_regs(cpu);
+ if (ret < 0) {
+ error_report("Failed to get special registers");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int read_memory(const CPUState *cpu, uint64_t initial_gva,
+ uint64_t initial_gpa, uint64_t gva, uint8_t *data,
+ size_t len)
+{
+ int ret;
+ uint64_t gpa, flags;
+
+ if (gva == initial_gva) {
+ gpa = initial_gpa;
+ } else {
+ flags = HV_TRANSLATE_GVA_VALIDATE_READ;
+ ret = translate_gva(cpu, gva, &gpa, flags);
+ if (ret < 0) {
+ return -1;
+ }
+
+ ret = mshv_guest_mem_read(gpa, data, len, false, false);
+ if (ret < 0) {
+ error_report("failed to read guest mem");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int write_memory(const CPUState *cpu, uint64_t initial_gva,
+ uint64_t initial_gpa, uint64_t gva, const uint8_t *data,
+ size_t len)
+{
+ int ret;
+ uint64_t gpa, flags;
+
+ if (gva == initial_gva) {
+ gpa = initial_gpa;
+ } else {
+ flags = HV_TRANSLATE_GVA_VALIDATE_WRITE;
+ ret = translate_gva(cpu, gva, &gpa, flags);
+ if (ret < 0) {
+ error_report("failed to translate gva to gpa");
+ return -1;
+ }
+ }
+ ret = mshv_guest_mem_write(gpa, data, len, false);
+ if (ret != MEMTX_OK) {
+ error_report("failed to write to mmio");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int handle_pio_str_write(CPUState *cpu,
+ hv_x64_io_port_intercept_message *info,
+ size_t repeat, uint16_t port,
+ bool direction_flag)
+{
+ int ret;
+ uint64_t src;
+ uint8_t data[4] = { 0 };
+ size_t len = info->access_info.access_size;
+
+ src = linear_addr(cpu, info->rsi, R_DS);
+
+ for (size_t i = 0; i < repeat; i++) {
+ ret = read_memory(cpu, 0, 0, src, data, len);
+ if (ret < 0) {
+ error_report("Failed to read memory");
+ return -1;
+ }
+ ret = pio_write(port, data, len, false);
+ if (ret < 0) {
+ error_report("Failed to write to io port");
+ return -1;
+ }
+ src += direction_flag ? -len : len;
+ info->rsi += direction_flag ? -len : len;
+ }
+
+ return 0;
+}
+
+static int handle_pio_str_read(CPUState *cpu,
+ hv_x64_io_port_intercept_message *info,
+ size_t repeat, uint16_t port,
+ bool direction_flag)
+{
+ int ret;
+ uint64_t dst;
+ size_t len = info->access_info.access_size;
+ uint8_t data[4] = { 0 };
+
+ dst = linear_addr(cpu, info->rdi, R_ES);
+
+ for (size_t i = 0; i < repeat; i++) {
+ pio_read(port, data, len, false);
+
+ ret = write_memory(cpu, 0, 0, dst, data, len);
+ if (ret < 0) {
+ error_report("Failed to write memory");
+ return -1;
+ }
+ dst += direction_flag ? -len : len;
+ info->rdi += direction_flag ? -len : len;
+ }
+
+ return 0;
+}
+
+static int handle_pio_str(CPUState *cpu, hv_x64_io_port_intercept_message *info)
+{
+ uint8_t access_type = info->header.intercept_access_type;
+ uint16_t port = info->port_number;
+ bool repop = info->access_info.rep_prefix == 1;
+ size_t repeat = repop ? info->rcx : 1;
+ size_t insn_len = info->header.instruction_length;
+ bool direction_flag;
+ uint32_t reg_names[3];
+ uint64_t reg_values[3];
+ int ret;
+ X86CPU *x86_cpu = X86_CPU(cpu);
+ CPUX86State *env = &x86_cpu->env;
+
+ ret = fetch_guest_state(cpu);
+ if (ret < 0) {
+ error_report("Failed to fetch guest state");
+ return -1;
+ }
+
+ direction_flag = (env->eflags & DESC_E_MASK) != 0;
+
+ if (access_type == HV_X64_INTERCEPT_ACCESS_TYPE_WRITE) {
+ ret = handle_pio_str_write(cpu, info, repeat, port, direction_flag);
+ if (ret < 0) {
+ error_report("Failed to handle pio str write");
+ return -1;
+ }
+ reg_names[0] = HV_X64_REGISTER_RSI;
+ reg_values[0] = info->rsi;
+ } else {
+ ret = handle_pio_str_read(cpu, info, repeat, port, direction_flag);
+ reg_names[0] = HV_X64_REGISTER_RDI;
+ reg_values[0] = info->rdi;
+ }
+
+ reg_names[1] = HV_X64_REGISTER_RIP;
+ reg_values[1] = info->header.rip + insn_len;
+ reg_names[2] = HV_X64_REGISTER_RAX;
+ reg_values[2] = info->rax;
+
+ ret = set_x64_registers(cpu, reg_names, reg_values);
+ if (ret < 0) {
+ error_report("Failed to set x64 registers");
+ return -1;
+ }
+
+ cpu->accel->dirty = false;
+
+ return 0;
+}
+
+static int handle_pio(CPUState *cpu, const struct hyperv_message *msg)
+{
+ struct hv_x64_io_port_intercept_message info = { 0 };
+ int ret;
+
+ ret = set_ioport_info(msg, &info);
+ if (ret < 0) {
+ error_report("Failed to convert message to ioport info");
+ return -1;
+ }
+
+ if (info.access_info.string_op) {
+ return handle_pio_str(cpu, &info);
+ }
+
+ return handle_pio_non_str(cpu, &info);
+}
+
int mshv_run_vcpu(int vm_fd, CPUState *cpu, hv_message *msg, MshvVmExit *exit)
{
- error_report("unimplemented");
- abort();
+ int ret;
+ enum MshvVmExit exit_reason;
+ int cpu_fd = mshv_vcpufd(cpu);
+
+ ret = ioctl(cpu_fd, MSHV_RUN_VP, msg);
+ if (ret < 0) {
+ return MshvVmExitShutdown;
+ }
+
+ switch (msg->header.message_type) {
+ case HVMSG_UNRECOVERABLE_EXCEPTION:
+ return MshvVmExitShutdown;
+ case HVMSG_UNMAPPED_GPA:
+ case HVMSG_GPA_INTERCEPT:
+ ret = handle_mmio(cpu, msg, &exit_reason);
+ if (ret < 0) {
+ error_report("failed to handle mmio");
+ return -1;
+ }
+ return exit_reason;
+ case HVMSG_X64_IO_PORT_INTERCEPT:
+ ret = handle_pio(cpu, msg);
+ if (ret < 0) {
+ return MshvVmExitSpecial;
+ }
+ return MshvVmExitIgnore;
+ default:
+ break;
+ }
+
+ *exit = MshvVmExitIgnore;
+ return 0;
}
void mshv_remove_vcpu(int vm_fd, int cpu_fd)

View File

@ -1,696 +0,0 @@
From ccc3eea713711a301281dd8ae0f5197cbcc7ac4a Mon Sep 17 00:00:00 2001
From: Magnus Kulke <magnuskulke@linux.microsoft.com>
Date: Tue, 16 Sep 2025 18:48:43 +0200
Subject: [PATCH] accel/mshv: Handle overlapping mem mappings
RH-Author: Igor Mammedov <imammedo@redhat.com>
RH-MergeRequest: 437: el10: x86: enablement for Azure L1VH OCP readiness
RH-Jira: RHEL-134212
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [24/30] abe9045eadeabccae811682dccd8679f41c32cc0
QEMU maps certain regions into the guest multiple times, as seen in the
trace below. Currently the MSHV kernel driver will reject those
mappings. To workaround this, a record is kept (a static global list of
"slots", inspired by what the HVF accelerator has implemented). An
overlapping region is not registered at the hypervisor, and marked as
mapped=false. If there is an UNMAPPED_GPA exit, we can look for a slot
that is unmapped and would cover the GPA. In this case we map out the
conflicting slot and map in the requested region.
mshv_set_phys_mem add=1 name=pc.bios
mshv_map_memory => u_a=7ffff4e00000 gpa=00fffc0000 size=00040000
mshv_set_phys_mem add=1 name=ioapic
mshv_set_phys_mem add=1 name=hpet
mshv_set_phys_mem add=0 name=pc.ram
mshv_unmap_memory u_a=7fff67e00000 gpa=0000000000 size=80000000
mshv_set_phys_mem add=1 name=pc.ram
mshv_map_memory u_a=7fff67e00000 gpa=0000000000 size=000c0000
mshv_set_phys_mem add=1 name=pc.rom
mshv_map_memory u_a=7ffff4c00000 gpa=00000c0000 size=00020000
mshv_set_phys_mem add=1 name=pc.bios
mshv_remap_attempt => u_a=7ffff4e20000 gpa=00000e0000 size=00020000
The mapping table is guarded by a mutex for concurrent modification and
RCU mechanisms for concurrent reads. Writes occur rarely, but we'll have
to verify whether an unmapped region exist for each UNMAPPED_GPA exit,
which happens frequently.
Signed-off-by: Magnus Kulke <magnuskulke@linux.microsoft.com>
Link: https://lore.kernel.org/r/20250916164847.77883-24-magnuskulke@linux.microsoft.com
[Fix format strings for trace-events; mshv.h/mshv_int.h split. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit efc4093358511a58846a409b965213aa1bb9f31a)
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Patch-name: kvm-accel-mshv-Handle-overlapping-mem-mappings.patch
Patch-id: 84
Patch-present-in-specfile: True
---
accel/mshv/mem.c | 406 +++++++++++++++++++++++++++++++++---
accel/mshv/mshv-all.c | 2 +
accel/mshv/trace-events | 5 +
include/system/mshv_int.h | 22 +-
target/i386/mshv/mshv-cpu.c | 43 ++++
5 files changed, 448 insertions(+), 30 deletions(-)
diff --git a/accel/mshv/mem.c b/accel/mshv/mem.c
index e55c38d4db..0e2164af3e 100644
--- a/accel/mshv/mem.c
+++ b/accel/mshv/mem.c
@@ -11,7 +11,9 @@
*/
#include "qemu/osdep.h"
+#include "qemu/lockable.h"
#include "qemu/error-report.h"
+#include "qemu/rcu.h"
#include "linux/mshv.h"
#include "system/address-spaces.h"
#include "system/mshv.h"
@@ -20,6 +22,137 @@
#include <sys/ioctl.h>
#include "trace.h"
+typedef struct SlotsRCUReclaim {
+ struct rcu_head rcu;
+ GList *old_head;
+ MshvMemorySlot *removed_slot;
+} SlotsRCUReclaim;
+
+static void rcu_reclaim_slotlist(struct rcu_head *rcu)
+{
+ SlotsRCUReclaim *r = container_of(rcu, SlotsRCUReclaim, rcu);
+ g_list_free(r->old_head);
+ g_free(r->removed_slot);
+ g_free(r);
+}
+
+static void publish_slots(GList *new_head, GList *old_head,
+ MshvMemorySlot *removed_slot)
+{
+ MshvMemorySlotManager *manager = &mshv_state->msm;
+
+ assert(manager);
+ qatomic_store_release(&manager->slots, new_head);
+
+ SlotsRCUReclaim *r = g_new(SlotsRCUReclaim, 1);
+ r->old_head = old_head;
+ r->removed_slot = removed_slot;
+
+ call_rcu1(&r->rcu, rcu_reclaim_slotlist);
+}
+
+/* Needs to be called with mshv_state->msm.mutex held */
+static int remove_slot(MshvMemorySlot *slot)
+{
+ GList *old_head, *new_head;
+ MshvMemorySlotManager *manager = &mshv_state->msm;
+
+ assert(manager);
+ old_head = qatomic_load_acquire(&manager->slots);
+
+ if (!g_list_find(old_head, slot)) {
+ error_report("slot requested for removal not found");
+ return -1;
+ }
+
+ new_head = g_list_copy(old_head);
+ new_head = g_list_remove(new_head, slot);
+ manager->n_slots--;
+
+ publish_slots(new_head, old_head, slot);
+
+ return 0;
+}
+
+/* Needs to be called with mshv_state->msm.mutex held */
+static MshvMemorySlot *append_slot(uint64_t gpa, uint64_t userspace_addr,
+ uint64_t size, bool readonly)
+{
+ GList *old_head, *new_head;
+ MshvMemorySlot *slot;
+ MshvMemorySlotManager *manager = &mshv_state->msm;
+
+ assert(manager);
+
+ old_head = qatomic_load_acquire(&manager->slots);
+
+ if (manager->n_slots >= MSHV_MAX_MEM_SLOTS) {
+ error_report("no free memory slots available");
+ return NULL;
+ }
+
+ slot = g_new0(MshvMemorySlot, 1);
+ slot->guest_phys_addr = gpa;
+ slot->userspace_addr = userspace_addr;
+ slot->memory_size = size;
+ slot->readonly = readonly;
+
+ new_head = g_list_copy(old_head);
+ new_head = g_list_append(new_head, slot);
+ manager->n_slots++;
+
+ publish_slots(new_head, old_head, NULL);
+
+ return slot;
+}
+
+static int slot_overlaps(const MshvMemorySlot *slot1,
+ const MshvMemorySlot *slot2)
+{
+ uint64_t start_1 = slot1->userspace_addr,
+ start_2 = slot2->userspace_addr;
+ size_t len_1 = slot1->memory_size,
+ len_2 = slot2->memory_size;
+
+ if (slot1 == slot2) {
+ return -1;
+ }
+
+ return ranges_overlap(start_1, len_1, start_2, len_2) ? 0 : -1;
+}
+
+static bool is_mapped(MshvMemorySlot *slot)
+{
+ /* Subsequent reads of mapped field see a fully-initialized slot */
+ return qatomic_load_acquire(&slot->mapped);
+}
+
+/*
+ * Find slot that is:
+ * - overlapping in userspace
+ * - currently mapped in the guest
+ *
+ * Needs to be called with mshv_state->msm.mutex or RCU read lock held.
+ */
+static MshvMemorySlot *find_overlap_mem_slot(GList *head, MshvMemorySlot *slot)
+{
+ GList *found;
+ MshvMemorySlot *overlap_slot;
+
+ found = g_list_find_custom(head, slot, (GCompareFunc) slot_overlaps);
+
+ if (!found) {
+ return NULL;
+ }
+
+ overlap_slot = found->data;
+ if (!overlap_slot || !is_mapped(overlap_slot)) {
+ return NULL;
+ }
+
+ return overlap_slot;
+}
+
static int set_guest_memory(int vm_fd,
const struct mshv_user_mem_region *region)
{
@@ -27,38 +160,169 @@ static int set_guest_memory(int vm_fd,
ret = ioctl(vm_fd, MSHV_SET_GUEST_MEMORY, region);
if (ret < 0) {
- error_report("failed to set guest memory");
- return -errno;
+ error_report("failed to set guest memory: %s", strerror(errno));
+ return -1;
}
return 0;
}
-static int map_or_unmap(int vm_fd, const MshvMemoryRegion *mr, bool map)
+static int map_or_unmap(int vm_fd, const MshvMemorySlot *slot, bool map)
{
struct mshv_user_mem_region region = {0};
- region.guest_pfn = mr->guest_phys_addr >> MSHV_PAGE_SHIFT;
- region.size = mr->memory_size;
- region.userspace_addr = mr->userspace_addr;
+ region.guest_pfn = slot->guest_phys_addr >> MSHV_PAGE_SHIFT;
+ region.size = slot->memory_size;
+ region.userspace_addr = slot->userspace_addr;
if (!map) {
region.flags |= (1 << MSHV_SET_MEM_BIT_UNMAP);
- trace_mshv_unmap_memory(mr->userspace_addr, mr->guest_phys_addr,
- mr->memory_size);
+ trace_mshv_unmap_memory(slot->userspace_addr, slot->guest_phys_addr,
+ slot->memory_size);
return set_guest_memory(vm_fd, &region);
}
region.flags = BIT(MSHV_SET_MEM_BIT_EXECUTABLE);
- if (!mr->readonly) {
+ if (!slot->readonly) {
region.flags |= BIT(MSHV_SET_MEM_BIT_WRITABLE);
}
- trace_mshv_map_memory(mr->userspace_addr, mr->guest_phys_addr,
- mr->memory_size);
+ trace_mshv_map_memory(slot->userspace_addr, slot->guest_phys_addr,
+ slot->memory_size);
return set_guest_memory(vm_fd, &region);
}
+static int slot_matches_region(const MshvMemorySlot *slot1,
+ const MshvMemorySlot *slot2)
+{
+ return (slot1->guest_phys_addr == slot2->guest_phys_addr &&
+ slot1->userspace_addr == slot2->userspace_addr &&
+ slot1->memory_size == slot2->memory_size) ? 0 : -1;
+}
+
+/* Needs to be called with mshv_state->msm.mutex held */
+static MshvMemorySlot *find_mem_slot_by_region(uint64_t gpa, uint64_t size,
+ uint64_t userspace_addr)
+{
+ MshvMemorySlot ref_slot = {
+ .guest_phys_addr = gpa,
+ .userspace_addr = userspace_addr,
+ .memory_size = size,
+ };
+ GList *found;
+ MshvMemorySlotManager *manager = &mshv_state->msm;
+
+ assert(manager);
+ found = g_list_find_custom(manager->slots, &ref_slot,
+ (GCompareFunc) slot_matches_region);
+
+ return found ? found->data : NULL;
+}
+
+static int slot_covers_gpa(const MshvMemorySlot *slot, uint64_t *gpa_p)
+{
+ uint64_t gpa_offset, gpa = *gpa_p;
+
+ gpa_offset = gpa - slot->guest_phys_addr;
+ return (slot->guest_phys_addr <= gpa && gpa_offset < slot->memory_size)
+ ? 0 : -1;
+}
+
+/* Needs to be called with mshv_state->msm.mutex or RCU read lock held */
+static MshvMemorySlot *find_mem_slot_by_gpa(GList *head, uint64_t gpa)
+{
+ GList *found;
+ MshvMemorySlot *slot;
+
+ trace_mshv_find_slot_by_gpa(gpa);
+
+ found = g_list_find_custom(head, &gpa, (GCompareFunc) slot_covers_gpa);
+ if (found) {
+ slot = found->data;
+ trace_mshv_found_slot(slot->userspace_addr, slot->guest_phys_addr,
+ slot->memory_size);
+ return slot;
+ }
+
+ return NULL;
+}
+
+/* Needs to be called with mshv_state->msm.mutex held */
+static void set_mapped(MshvMemorySlot *slot, bool mapped)
+{
+ /* prior writes to mapped field becomes visible before readers see slot */
+ qatomic_store_release(&slot->mapped, mapped);
+}
+
+MshvRemapResult mshv_remap_overlap_region(int vm_fd, uint64_t gpa)
+{
+ MshvMemorySlot *gpa_slot, *overlap_slot;
+ GList *head;
+ int ret;
+ MshvMemorySlotManager *manager = &mshv_state->msm;
+
+ /* fast path, called often by unmapped_gpa vm exit */
+ WITH_RCU_READ_LOCK_GUARD() {
+ assert(manager);
+ head = qatomic_load_acquire(&manager->slots);
+ /* return early if no slot is found */
+ gpa_slot = find_mem_slot_by_gpa(head, gpa);
+ if (gpa_slot == NULL) {
+ return MshvRemapNoMapping;
+ }
+
+ /* return early if no overlapping slot is found */
+ overlap_slot = find_overlap_mem_slot(head, gpa_slot);
+ if (overlap_slot == NULL) {
+ return MshvRemapNoOverlap;
+ }
+ }
+
+ /*
+ * We'll modify the mapping list, so we need to upgrade to mutex and
+ * recheck.
+ */
+ assert(manager);
+ QEMU_LOCK_GUARD(&manager->mutex);
+
+ /* return early if no slot is found */
+ gpa_slot = find_mem_slot_by_gpa(manager->slots, gpa);
+ if (gpa_slot == NULL) {
+ return MshvRemapNoMapping;
+ }
+
+ /* return early if no overlapping slot is found */
+ overlap_slot = find_overlap_mem_slot(manager->slots, gpa_slot);
+ if (overlap_slot == NULL) {
+ return MshvRemapNoOverlap;
+ }
+
+ /* unmap overlapping slot */
+ ret = map_or_unmap(vm_fd, overlap_slot, false);
+ if (ret < 0) {
+ error_report("failed to unmap overlap region");
+ abort();
+ }
+ set_mapped(overlap_slot, false);
+ warn_report("mapped out userspace_addr=0x%016lx gpa=0x%010lx size=0x%lx",
+ overlap_slot->userspace_addr,
+ overlap_slot->guest_phys_addr,
+ overlap_slot->memory_size);
+
+ /* map region for gpa */
+ ret = map_or_unmap(vm_fd, gpa_slot, true);
+ if (ret < 0) {
+ error_report("failed to map new region");
+ abort();
+ }
+ set_mapped(gpa_slot, true);
+ warn_report("mapped in userspace_addr=0x%016lx gpa=0x%010lx size=0x%lx",
+ gpa_slot->userspace_addr, gpa_slot->guest_phys_addr,
+ gpa_slot->memory_size);
+
+ return MshvRemapOk;
+}
+
static int handle_unmapped_mmio_region_read(uint64_t gpa, uint64_t size,
uint8_t *data)
{
@@ -124,20 +388,97 @@ int mshv_guest_mem_write(uint64_t gpa, const uint8_t *data, uintptr_t size,
return -1;
}
-static int set_memory(const MshvMemoryRegion *mshv_mr, bool add)
+static int tracked_unmap(int vm_fd, uint64_t gpa, uint64_t size,
+ uint64_t userspace_addr)
{
- int ret = 0;
+ int ret;
+ MshvMemorySlot *slot;
+ MshvMemorySlotManager *manager = &mshv_state->msm;
+
+ assert(manager);
+
+ QEMU_LOCK_GUARD(&manager->mutex);
+
+ slot = find_mem_slot_by_region(gpa, size, userspace_addr);
+ if (!slot) {
+ trace_mshv_skip_unset_mem(userspace_addr, gpa, size);
+ /* no work to do */
+ return 0;
+ }
+
+ if (!is_mapped(slot)) {
+ /* remove slot, no need to unmap */
+ return remove_slot(slot);
+ }
- if (!mshv_mr) {
- error_report("Invalid mshv_mr");
+ ret = map_or_unmap(vm_fd, slot, false);
+ if (ret < 0) {
+ error_report("failed to unmap memory region");
+ return ret;
+ }
+ return remove_slot(slot);
+}
+
+static int tracked_map(int vm_fd, uint64_t gpa, uint64_t size, bool readonly,
+ uint64_t userspace_addr)
+{
+ MshvMemorySlot *slot, *overlap_slot;
+ int ret;
+ MshvMemorySlotManager *manager = &mshv_state->msm;
+
+ assert(manager);
+
+ QEMU_LOCK_GUARD(&manager->mutex);
+
+ slot = find_mem_slot_by_region(gpa, size, userspace_addr);
+ if (slot) {
+ error_report("memory region already mapped at gpa=0x%lx, "
+ "userspace_addr=0x%lx, size=0x%lx",
+ slot->guest_phys_addr, slot->userspace_addr,
+ slot->memory_size);
return -1;
}
- trace_mshv_set_memory(add, mshv_mr->guest_phys_addr,
- mshv_mr->memory_size,
- mshv_mr->userspace_addr, mshv_mr->readonly,
- ret);
- return map_or_unmap(mshv_state->vm, mshv_mr, add);
+ slot = append_slot(gpa, userspace_addr, size, readonly);
+
+ overlap_slot = find_overlap_mem_slot(manager->slots, slot);
+ if (overlap_slot) {
+ trace_mshv_remap_attempt(slot->userspace_addr,
+ slot->guest_phys_addr,
+ slot->memory_size);
+ warn_report("attempt to map region [0x%lx-0x%lx], while "
+ "[0x%lx-0x%lx] is already mapped in the guest",
+ userspace_addr, userspace_addr + size - 1,
+ overlap_slot->userspace_addr,
+ overlap_slot->userspace_addr +
+ overlap_slot->memory_size - 1);
+
+ /* do not register mem slot in hv, but record for later swap-in */
+ set_mapped(slot, false);
+
+ return 0;
+ }
+
+ ret = map_or_unmap(vm_fd, slot, true);
+ if (ret < 0) {
+ error_report("failed to map memory region");
+ return -1;
+ }
+ set_mapped(slot, true);
+
+ return 0;
+}
+
+static int set_memory(uint64_t gpa, uint64_t size, bool readonly,
+ uint64_t userspace_addr, bool add)
+{
+ int vm_fd = mshv_state->vm;
+
+ if (add) {
+ return tracked_map(vm_fd, gpa, size, readonly, userspace_addr);
+ }
+
+ return tracked_unmap(vm_fd, gpa, size, userspace_addr);
}
/*
@@ -173,7 +514,9 @@ void mshv_set_phys_mem(MshvMemoryListener *mml, MemoryRegionSection *section,
bool writable = !area->readonly && !area->rom_device;
hwaddr start_addr, mr_offset, size;
void *ram;
- MshvMemoryRegion mshv_mr = {0};
+
+ size = align_section(section, &start_addr);
+ trace_mshv_set_phys_mem(add, section->mr->name, start_addr);
size = align_section(section, &start_addr);
trace_mshv_set_phys_mem(add, section->mr->name, start_addr);
@@ -200,14 +543,21 @@ void mshv_set_phys_mem(MshvMemoryListener *mml, MemoryRegionSection *section,
ram = memory_region_get_ram_ptr(area) + mr_offset;
- mshv_mr.guest_phys_addr = start_addr;
- mshv_mr.memory_size = size;
- mshv_mr.readonly = !writable;
- mshv_mr.userspace_addr = (uint64_t)ram;
-
- ret = set_memory(&mshv_mr, add);
+ ret = set_memory(start_addr, size, !writable, (uint64_t)ram, add);
if (ret < 0) {
- error_report("Failed to set memory region");
+ error_report("failed to set memory region");
abort();
}
}
+
+void mshv_init_memory_slot_manager(MshvState *mshv_state)
+{
+ MshvMemorySlotManager *manager;
+
+ assert(mshv_state);
+ manager = &mshv_state->msm;
+
+ manager->n_slots = 0;
+ manager->slots = NULL;
+ qemu_mutex_init(&manager->mutex);
+}
diff --git a/accel/mshv/mshv-all.c b/accel/mshv/mshv-all.c
index fa1f8f35bd..5edfcbad9d 100644
--- a/accel/mshv/mshv-all.c
+++ b/accel/mshv/mshv-all.c
@@ -437,6 +437,8 @@ static int mshv_init(AccelState *as, MachineState *ms)
mshv_init_msicontrol();
+ mshv_init_memory_slot_manager(s);
+
ret = create_vm(mshv_fd, &vm_fd);
if (ret < 0) {
close(mshv_fd);
diff --git a/accel/mshv/trace-events b/accel/mshv/trace-events
index a4dffeb24a..36f0d59b38 100644
--- a/accel/mshv/trace-events
+++ b/accel/mshv/trace-events
@@ -26,3 +26,8 @@ mshv_map_memory(uint64_t userspace_addr, uint64_t gpa, uint64_t size) "\tu_a=0x%
mshv_unmap_memory(uint64_t userspace_addr, uint64_t gpa, uint64_t size) "\tu_a=0x%" PRIx64 " gpa=0x%010" PRIx64 " size=0x%08" PRIx64
mshv_set_phys_mem(bool add, const char *name, uint64_t gpa) "\tadd=%d name=%s gpa=0x%010" PRIx64
mshv_handle_mmio(uint64_t gva, uint64_t gpa, uint64_t size, uint8_t access_type) "\tgva=0x%" PRIx64 " gpa=0x%010" PRIx64 " size=0x%" PRIx64 " access_type=%d"
+
+mshv_found_slot(uint64_t userspace_addr, uint64_t gpa, uint64_t size) "\tu_a=0x%" PRIx64 " gpa=0x%010" PRIx64 " size=0x%08" PRIx64
+mshv_skip_unset_mem(uint64_t userspace_addr, uint64_t gpa, uint64_t size) "\tu_a=0x%" PRIx64 " gpa=0x%010" PRIx64 " size=0x%08" PRIx64
+mshv_remap_attempt(uint64_t userspace_addr, uint64_t gpa, uint64_t size) "\tu_a=0x%" PRIx64 " gpa=0x%010" PRIx64 " size=0x%08" PRIx64
+mshv_find_slot_by_gpa(uint64_t gpa) "\tgpa=0x%010" PRIx64
diff --git a/include/system/mshv_int.h b/include/system/mshv_int.h
index b29d39911d..6350c69e9d 100644
--- a/include/system/mshv_int.h
+++ b/include/system/mshv_int.h
@@ -16,6 +16,8 @@
#define MSHV_MSR_ENTRIES_COUNT 64
+#define MSHV_MAX_MEM_SLOTS 32
+
typedef struct hyperv_message hv_message;
struct AccelCPUState {
@@ -33,6 +35,12 @@ typedef struct MshvAddressSpace {
AddressSpace *as;
} MshvAddressSpace;
+typedef struct MshvMemorySlotManager {
+ size_t n_slots;
+ GList *slots;
+ QemuMutex mutex;
+} MshvMemorySlotManager;
+
struct MshvState {
AccelState parent_obj;
int vm;
@@ -41,6 +49,7 @@ struct MshvState {
int nr_as;
MshvAddressSpace *as;
int fd;
+ MshvMemorySlotManager msm;
};
typedef struct MshvMsiControl {
@@ -71,6 +80,12 @@ typedef enum MshvVmExit {
MshvVmExitSpecial = 2,
} MshvVmExit;
+typedef enum MshvRemapResult {
+ MshvRemapOk = 0,
+ MshvRemapNoMapping = 1,
+ MshvRemapNoOverlap = 2,
+} MshvRemapResult;
+
void mshv_init_mmio_emu(void);
int mshv_create_vcpu(int vm_fd, uint8_t vp_index, int *cpu_fd);
void mshv_remove_vcpu(int vm_fd, int cpu_fd);
@@ -94,19 +109,22 @@ int mshv_hvcall(int fd, const struct mshv_root_hvcall *args);
#endif
/* memory */
-typedef struct MshvMemoryRegion {
+typedef struct MshvMemorySlot {
uint64_t guest_phys_addr;
uint64_t memory_size;
uint64_t userspace_addr;
bool readonly;
-} MshvMemoryRegion;
+ bool mapped;
+} MshvMemorySlot;
+MshvRemapResult mshv_remap_overlap_region(int vm_fd, uint64_t gpa);
int mshv_guest_mem_read(uint64_t gpa, uint8_t *data, uintptr_t size,
bool is_secure_mode, bool instruction_fetch);
int mshv_guest_mem_write(uint64_t gpa, const uint8_t *data, uintptr_t size,
bool is_secure_mode);
void mshv_set_phys_mem(MshvMemoryListener *mml, MemoryRegionSection *section,
bool add);
+void mshv_init_memory_slot_manager(MshvState *mshv_state);
/* msr */
typedef struct MshvMsrEntry {
diff --git a/target/i386/mshv/mshv-cpu.c b/target/i386/mshv/mshv-cpu.c
index 7edc032cea..de87142bff 100644
--- a/target/i386/mshv/mshv-cpu.c
+++ b/target/i386/mshv/mshv-cpu.c
@@ -1170,6 +1170,43 @@ static int handle_mmio(CPUState *cpu, const struct hyperv_message *msg,
return 0;
}
+static int handle_unmapped_mem(int vm_fd, CPUState *cpu,
+ const struct hyperv_message *msg,
+ MshvVmExit *exit_reason)
+{
+ struct hv_x64_memory_intercept_message info = { 0 };
+ uint64_t gpa;
+ int ret;
+ enum MshvRemapResult remap_result;
+
+ ret = set_memory_info(msg, &info);
+ if (ret < 0) {
+ error_report("failed to convert message to memory info");
+ return -1;
+ }
+
+ gpa = info.guest_physical_address;
+
+ /* attempt to remap the region, in case of overlapping userspace mappings */
+ remap_result = mshv_remap_overlap_region(vm_fd, gpa);
+ *exit_reason = MshvVmExitIgnore;
+
+ switch (remap_result) {
+ case MshvRemapNoMapping:
+ /* if we didn't find a mapping, it is probably mmio */
+ return handle_mmio(cpu, msg, exit_reason);
+ case MshvRemapOk:
+ break;
+ case MshvRemapNoOverlap:
+ /* This should not happen, but we are forgiving it */
+ warn_report("found no overlap for unmapped region");
+ *exit_reason = MshvVmExitSpecial;
+ break;
+ }
+
+ return 0;
+}
+
static int set_ioport_info(const struct hyperv_message *msg,
hv_x64_io_port_intercept_message *info)
{
@@ -1507,6 +1544,12 @@ int mshv_run_vcpu(int vm_fd, CPUState *cpu, hv_message *msg, MshvVmExit *exit)
case HVMSG_UNRECOVERABLE_EXCEPTION:
return MshvVmExitShutdown;
case HVMSG_UNMAPPED_GPA:
+ ret = handle_unmapped_mem(vm_fd, cpu, msg, &exit_reason);
+ if (ret < 0) {
+ error_report("failed to handle unmapped memory");
+ return -1;
+ }
+ return exit_reason;
case HVMSG_GPA_INTERCEPT:
ret = handle_mmio(cpu, msg, &exit_reason);
if (ret < 0) {

View File

@ -1,170 +0,0 @@
From 10f9371fe319b86ceb363b9516438c1ee9cf9656 Mon Sep 17 00:00:00 2001
From: Praveen K Paladugu <prapal@microsoft.com>
Date: Tue, 16 Sep 2025 18:48:44 +0200
Subject: [PATCH] qapi/accel: Allow to query mshv capabilities
RH-Author: Igor Mammedov <imammedo@redhat.com>
RH-MergeRequest: 437: el10: x86: enablement for Azure L1VH OCP readiness
RH-Jira: RHEL-134212
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [25/30] 50d73451b735ee139ca065c15a84e5f7e77e3904
Allow to query mshv capabilities via query-mshv QMP and info mshv HMP commands.
Signed-off-by: Magnus Kulke <magnuskulke@linux.microsoft.com>
Acked-by: Dr. David Alan Gilbert <dave@treblig.org>
Link: https://lore.kernel.org/r/20250916164847.77883-25-magnuskulke@linux.microsoft.com
[Fix "since" version. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit e7b08dfb902430b4f8226d23d7cf9b2762b6fc83)
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Patch-name: kvm-qapi-accel-Allow-to-query-mshv-capabilities.patch
Patch-id: 85
Patch-present-in-specfile: True
---
hmp-commands-info.hx | 13 +++++++++++++
hw/core/machine-hmp-cmds.c | 15 +++++++++++++++
hw/core/machine-qmp-cmds.c | 14 ++++++++++++++
include/monitor/hmp.h | 1 +
include/system/hw_accel.h | 1 +
qapi/accelerator.json | 29 +++++++++++++++++++++++++++++
6 files changed, 73 insertions(+)
diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx
index 6142f60e7b..eaaa880c1b 100644
--- a/hmp-commands-info.hx
+++ b/hmp-commands-info.hx
@@ -307,6 +307,19 @@ SRST
Show KVM information.
ERST
+ {
+ .name = "mshv",
+ .args_type = "",
+ .params = "",
+ .help = "show MSHV information",
+ .cmd = hmp_info_mshv,
+ },
+
+SRST
+ ``info mshv``
+ Show MSHV information.
+ERST
+
{
.name = "numa",
.args_type = "",
diff --git a/hw/core/machine-hmp-cmds.c b/hw/core/machine-hmp-cmds.c
index 3a612e2232..682ed9f49b 100644
--- a/hw/core/machine-hmp-cmds.c
+++ b/hw/core/machine-hmp-cmds.c
@@ -163,6 +163,21 @@ void hmp_info_kvm(Monitor *mon, const QDict *qdict)
qapi_free_KvmInfo(info);
}
+void hmp_info_mshv(Monitor *mon, const QDict *qdict)
+{
+ MshvInfo *info;
+
+ info = qmp_query_mshv(NULL);
+ monitor_printf(mon, "mshv support: ");
+ if (info->present) {
+ monitor_printf(mon, "%s\n", info->enabled ? "enabled" : "disabled");
+ } else {
+ monitor_printf(mon, "not compiled\n");
+ }
+
+ qapi_free_MshvInfo(info);
+}
+
void hmp_info_uuid(Monitor *mon, const QDict *qdict)
{
UuidInfo *info;
diff --git a/hw/core/machine-qmp-cmds.c b/hw/core/machine-qmp-cmds.c
index 6aca1a626e..e24bf0d97b 100644
--- a/hw/core/machine-qmp-cmds.c
+++ b/hw/core/machine-qmp-cmds.c
@@ -28,6 +28,20 @@
#include "system/runstate.h"
#include "system/system.h"
#include "hw/s390x/storage-keys.h"
+#include <sys/stat.h>
+
+/*
+ * QMP query for MSHV
+ */
+MshvInfo *qmp_query_mshv(Error **errp)
+{
+ MshvInfo *info = g_malloc0(sizeof(*info));
+
+ info->enabled = mshv_enabled();
+ info->present = accel_find("mshv");
+
+ return info;
+}
/*
* fast means: we NEVER interrupt vCPU threads to retrieve
diff --git a/include/monitor/hmp.h b/include/monitor/hmp.h
index ae116d9804..31bd812e5f 100644
--- a/include/monitor/hmp.h
+++ b/include/monitor/hmp.h
@@ -24,6 +24,7 @@ strList *hmp_split_at_comma(const char *str);
void hmp_info_name(Monitor *mon, const QDict *qdict);
void hmp_info_version(Monitor *mon, const QDict *qdict);
void hmp_info_kvm(Monitor *mon, const QDict *qdict);
+void hmp_info_mshv(Monitor *mon, const QDict *qdict);
void hmp_info_status(Monitor *mon, const QDict *qdict);
void hmp_info_uuid(Monitor *mon, const QDict *qdict);
void hmp_info_chardev(Monitor *mon, const QDict *qdict);
diff --git a/include/system/hw_accel.h b/include/system/hw_accel.h
index fa9228d5d2..55497edc29 100644
--- a/include/system/hw_accel.h
+++ b/include/system/hw_accel.h
@@ -14,6 +14,7 @@
#include "hw/core/cpu.h"
#include "system/kvm.h"
#include "system/hvf.h"
+#include "system/mshv.h"
#include "system/whpx.h"
#include "system/nvmm.h"
diff --git a/qapi/accelerator.json b/qapi/accelerator.json
index fb28c8d920..664e027246 100644
--- a/qapi/accelerator.json
+++ b/qapi/accelerator.json
@@ -54,3 +54,32 @@
{ 'command': 'x-accel-stats',
'returns': 'HumanReadableText',
'features': [ 'unstable' ] }
+
+##
+# @MshvInfo:
+#
+# Information about support for MSHV acceleration
+#
+# @enabled: true if MSHV acceleration is active
+#
+# @present: true if MSHV acceleration is built into this executable
+#
+# Since: 10.2.0
+##
+{ 'struct': 'MshvInfo', 'data': {'enabled': 'bool', 'present': 'bool'} }
+
+##
+# @query-mshv:
+#
+# Return information about MSHV acceleration
+#
+# Returns: @MshvInfo
+#
+# Since: 10.0.92
+#
+# .. qmp-example::
+#
+# -> { "execute": "query-mshv" }
+# <- { "return": { "enabled": true, "present": true } }
+##
+{ 'command': 'query-mshv', 'returns': 'MshvInfo' }

View File

@ -1,194 +0,0 @@
From 8cf57c4a254598ba434e1322af26e473e1382c73 Mon Sep 17 00:00:00 2001
From: Magnus Kulke <magnuskulke@linux.microsoft.com>
Date: Thu, 2 Oct 2025 09:50:12 +0200
Subject: [PATCH] target/i386/mshv: Use preallocated page for hvcall
RH-Author: Igor Mammedov <imammedo@redhat.com>
RH-MergeRequest: 437: el10: x86: enablement for Azure L1VH OCP readiness
RH-Jira: RHEL-134212
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [26/30] 338fa20beaaa44e30512d49026d2a9e9dd016b53
There are hvcalls that are invoked during MMIO exits, the payload is of
dynamic size. To avoid heap allocations we can use preallocated pages as
in/out buffer for those calls. A page is reserved per vCPU and used for
set/get register hv calls.
Signed-off-by: Magnus Kulke <magnuskulke@linux.microsoft.com>
Link: https://lore.kernel.org/r/20250916164847.77883-26-magnuskulke@linux.microsoft.com
[Use standard MAX_CONST macro; mshv.h/mshv_int.h split. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit e4a20afce59937073298d716cc829bdc026542dc)
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Patch-name: kvm-target-i386-mshv-Use-preallocated-page-for-hvcall.patch
Patch-id: 86
Patch-present-in-specfile: True
---
accel/mshv/mshv-all.c | 2 +-
include/system/mshv_int.h | 7 +++++++
target/i386/mshv/mshv-cpu.c | 38 +++++++++++++++++++++++++------------
3 files changed, 34 insertions(+), 13 deletions(-)
diff --git a/accel/mshv/mshv-all.c b/accel/mshv/mshv-all.c
index 5edfcbad9d..45174f7c4e 100644
--- a/accel/mshv/mshv-all.c
+++ b/accel/mshv/mshv-all.c
@@ -399,8 +399,8 @@ static int mshv_init_vcpu(CPUState *cpu)
uint8_t vp_index = cpu->cpu_index;
int ret;
- mshv_arch_init_vcpu(cpu);
cpu->accel = g_new0(AccelCPUState, 1);
+ mshv_arch_init_vcpu(cpu);
ret = mshv_create_vcpu(vm_fd, vp_index, &cpu->accel->cpufd);
if (ret < 0) {
diff --git a/include/system/mshv_int.h b/include/system/mshv_int.h
index 6350c69e9d..490563c1ab 100644
--- a/include/system/mshv_int.h
+++ b/include/system/mshv_int.h
@@ -20,9 +20,16 @@
typedef struct hyperv_message hv_message;
+typedef struct MshvHvCallArgs {
+ void *base;
+ void *input_page;
+ void *output_page;
+} MshvHvCallArgs;
+
struct AccelCPUState {
int cpufd;
bool dirty;
+ MshvHvCallArgs hvcall_args;
};
typedef struct MshvMemoryListener {
diff --git a/target/i386/mshv/mshv-cpu.c b/target/i386/mshv/mshv-cpu.c
index de87142bff..1f7b9cb37e 100644
--- a/target/i386/mshv/mshv-cpu.c
+++ b/target/i386/mshv/mshv-cpu.c
@@ -34,6 +34,10 @@
#include <sys/ioctl.h>
+#define MAX_REGISTER_COUNT (MAX_CONST(ARRAY_SIZE(STANDARD_REGISTER_NAMES), \
+ MAX_CONST(ARRAY_SIZE(SPECIAL_REGISTER_NAMES), \
+ ARRAY_SIZE(FPU_REGISTER_NAMES))))
+
static enum hv_register_name STANDARD_REGISTER_NAMES[18] = {
HV_X64_REGISTER_RAX,
HV_X64_REGISTER_RBX,
@@ -151,7 +155,7 @@ int mshv_set_generic_regs(const CPUState *cpu, const hv_register_assoc *assocs,
int cpu_fd = mshv_vcpufd(cpu);
int vp_index = cpu->cpu_index;
size_t in_sz, assocs_sz;
- hv_input_set_vp_registers *in;
+ hv_input_set_vp_registers *in = cpu->accel->hvcall_args.input_page;
struct mshv_root_hvcall args = {0};
int ret;
@@ -160,7 +164,7 @@ int mshv_set_generic_regs(const CPUState *cpu, const hv_register_assoc *assocs,
in_sz = sizeof(hv_input_set_vp_registers) + assocs_sz;
/* fill the input struct */
- in = g_malloc0(in_sz);
+ memset(in, 0, sizeof(hv_input_set_vp_registers));
in->vp_index = vp_index;
memcpy(in->elements, assocs, assocs_sz);
@@ -172,7 +176,6 @@ int mshv_set_generic_regs(const CPUState *cpu, const hv_register_assoc *assocs,
/* perform the call */
ret = mshv_hvcall(cpu_fd, &args);
- g_free(in);
if (ret < 0) {
error_report("Failed to set registers");
return -1;
@@ -193,8 +196,8 @@ static int get_generic_regs(CPUState *cpu, hv_register_assoc *assocs,
{
int cpu_fd = mshv_vcpufd(cpu);
int vp_index = cpu->cpu_index;
- hv_input_get_vp_registers *in;
- hv_register_value *values;
+ hv_input_get_vp_registers *in = cpu->accel->hvcall_args.input_page;
+ hv_register_value *values = cpu->accel->hvcall_args.output_page;
size_t in_sz, names_sz, values_sz;
int i, ret;
struct mshv_root_hvcall args = {0};
@@ -204,15 +207,14 @@ static int get_generic_regs(CPUState *cpu, hv_register_assoc *assocs,
in_sz = sizeof(hv_input_get_vp_registers) + names_sz;
/* fill the input struct */
- in = g_malloc0(in_sz);
+ memset(in, 0, sizeof(hv_input_get_vp_registers));
in->vp_index = vp_index;
for (i = 0; i < n_regs; i++) {
in->names[i] = assocs[i].name;
}
- /* allocate value output buffer */
+ /* determine size of value output buffer */
values_sz = n_regs * sizeof(union hv_register_value);
- values = g_malloc0(values_sz);
/* create the hvcall envelope */
args.code = HVCALL_GET_VP_REGISTERS;
@@ -224,16 +226,13 @@ static int get_generic_regs(CPUState *cpu, hv_register_assoc *assocs,
/* perform the call */
ret = mshv_hvcall(cpu_fd, &args);
- g_free(in);
if (ret < 0) {
- g_free(values);
error_report("Failed to retrieve registers");
return -1;
}
/* assert we got all registers */
if (args.reps != n_regs) {
- g_free(values);
error_report("Failed to retrieve registers: expected %zu elements"
", got %u", n_regs, args.reps);
return -1;
@@ -243,7 +242,6 @@ static int get_generic_regs(CPUState *cpu, hv_register_assoc *assocs,
for (i = 0; i < n_regs; i++) {
assocs[i].value = values[i];
}
- g_free(values);
return 0;
}
@@ -1696,6 +1694,19 @@ void mshv_arch_init_vcpu(CPUState *cpu)
{
X86CPU *x86_cpu = X86_CPU(cpu);
CPUX86State *env = &x86_cpu->env;
+ AccelCPUState *state = cpu->accel;
+ size_t page = HV_HYP_PAGE_SIZE;
+ void *mem = qemu_memalign(page, 2 * page);
+
+ /* sanity check, to make sure we don't overflow the page */
+ QEMU_BUILD_BUG_ON((MAX_REGISTER_COUNT
+ * sizeof(hv_register_assoc)
+ + sizeof(hv_input_get_vp_registers)
+ > HV_HYP_PAGE_SIZE));
+
+ state->hvcall_args.base = mem;
+ state->hvcall_args.input_page = mem;
+ state->hvcall_args.output_page = (uint8_t *)mem + page;
env->emu_mmio_buf = g_new(char, 4096);
}
@@ -1704,7 +1715,10 @@ void mshv_arch_destroy_vcpu(CPUState *cpu)
{
X86CPU *x86_cpu = X86_CPU(cpu);
CPUX86State *env = &x86_cpu->env;
+ AccelCPUState *state = cpu->accel;
+ g_free(state->hvcall_args.base);
+ state->hvcall_args = (MshvHvCallArgs){0};
g_clear_pointer(&env->emu_mmio_buf, g_free);
}

View File

@ -1,144 +0,0 @@
From 394307bb31702b6dece1df0d4dc14e8bd19b0bec Mon Sep 17 00:00:00 2001
From: Magnus Kulke <magnuskulke@linux.microsoft.com>
Date: Tue, 16 Sep 2025 18:48:46 +0200
Subject: [PATCH] docs: Add mshv to documentation
RH-Author: Igor Mammedov <imammedo@redhat.com>
RH-MergeRequest: 437: el10: x86: enablement for Azure L1VH OCP readiness
RH-Jira: RHEL-134212
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [27/30] 6450fc04dede6796c6a6383904792da34fb11de1
Added mshv to the list of accelerators in doc text.
Signed-off-by: Magnus Kulke <magnuskulke@linux.microsoft.com>
Link: https://lore.kernel.org/r/20250916164847.77883-27-magnuskulke@linux.microsoft.com
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit 3af71a1a6a7a497df7d3026239d6136b56e3d5ab)
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Patch-name: kvm-docs-Add-mshv-to-documentation.patch
Patch-id: 87
Patch-present-in-specfile: True
---
docs/about/build-platforms.rst | 2 +-
docs/devel/codebase.rst | 2 +-
docs/glossary.rst | 7 +++----
docs/system/introduction.rst | 3 +++
qemu-options.hx | 16 ++++++++--------
5 files changed, 16 insertions(+), 14 deletions(-)
diff --git a/docs/about/build-platforms.rst b/docs/about/build-platforms.rst
index 8671c3be9c..06ba0ddc9a 100644
--- a/docs/about/build-platforms.rst
+++ b/docs/about/build-platforms.rst
@@ -55,7 +55,7 @@ Those hosts are officially supported, with various accelerators:
* - SPARC
- tcg
* - x86
- - hvf (64 bit only), kvm, nvmm, tcg, whpx (64 bit only), xen
+ - hvf (64 bit only), mshv (64 bit only), kvm, nvmm, tcg, whpx (64 bit only), xen
Other host architectures are not supported. It is possible to build QEMU system
emulation on an unsupported host architecture using the configure
diff --git a/docs/devel/codebase.rst b/docs/devel/codebase.rst
index 2a3143787a..69d8827117 100644
--- a/docs/devel/codebase.rst
+++ b/docs/devel/codebase.rst
@@ -48,7 +48,7 @@ yet, so sometimes the source code is all you have.
* `accel <https://gitlab.com/qemu-project/qemu/-/tree/master/accel>`_:
Infrastructure and architecture agnostic code related to the various
`accelerators <Accelerators>` supported by QEMU
- (TCG, KVM, hvf, whpx, xen, nvmm).
+ (TCG, KVM, hvf, whpx, xen, nvmm, mshv).
Contains interfaces for operations that will be implemented per
`target <https://gitlab.com/qemu-project/qemu/-/tree/master/target>`_.
* `audio <https://gitlab.com/qemu-project/qemu/-/tree/master/audio>`_:
diff --git a/docs/glossary.rst b/docs/glossary.rst
index 4fa044bfb6..2857731bc4 100644
--- a/docs/glossary.rst
+++ b/docs/glossary.rst
@@ -12,7 +12,7 @@ Accelerator
A specific API used to accelerate execution of guest instructions. It can be
hardware-based, through a virtualization API provided by the host OS (kvm, hvf,
-whpx, ...), or software-based (tcg). See this description of `supported
+whpx, mshv, ...), or software-based (tcg). See this description of `supported
accelerators<Accelerators>`.
Board
@@ -101,9 +101,8 @@ manage a virtual machine. QEMU is a virtualizer, that interacts with various
hypervisors.
In the context of QEMU, an hypervisor is an API, provided by the Host OS,
-allowing to execute virtual machines. Linux implementation is KVM (and supports
-Xen as well). For MacOS, it's HVF. Windows defines WHPX. And NetBSD provides
-NVMM.
+allowing to execute virtual machines. Linux provides a choice of KVM, Xen
+or MSHV; MacOS provides HVF; Windows provides WHPX; NetBSD provides NVMM.
.. _machine:
diff --git a/docs/system/introduction.rst b/docs/system/introduction.rst
index 4cd46b5b8f..9c57523b6c 100644
--- a/docs/system/introduction.rst
+++ b/docs/system/introduction.rst
@@ -23,6 +23,9 @@ Tiny Code Generator (TCG) capable of emulating many CPUs.
* - Xen
- Linux (as dom0)
- Arm, x86
+ * - MSHV
+ - Linux (as dom0)
+ - x86
* - Hypervisor Framework (hvf)
- MacOS
- x86 (64 bit only), Arm (64 bit only)
diff --git a/qemu-options.hx b/qemu-options.hx
index 5f146c1860..8eca7faa94 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -28,7 +28,7 @@ DEF("machine", HAS_ARG, QEMU_OPTION_machine, \
"-machine [type=]name[,prop[=value][,...]]\n"
" selects emulated machine ('-machine help' for list)\n"
" property accel=accel1[:accel2[:...]] selects accelerator\n"
- " supported accelerators are kvm, xen, hvf, nvmm, whpx or tcg (default: tcg)\n"
+ " supported accelerators are kvm, xen, hvf, nvmm, whpx, mshv or tcg (default: tcg)\n"
" vmport=on|off|auto controls emulation of vmport (default: auto)\n"
" dump-guest-core=on|off include guest memory in a core dump (default=on)\n"
" mem-merge=on|off controls memory merge support (default: on)\n"
@@ -66,10 +66,10 @@ SRST
``accel=accels1[:accels2[:...]]``
This is used to enable an accelerator. Depending on the target
- architecture, kvm, xen, hvf, nvmm, whpx or tcg can be available.
- By default, tcg is used. If there is more than one accelerator
- specified, the next one is used if the previous one fails to
- initialize.
+ architecture, kvm, xen, hvf, nvmm, whpx, mshv or tcg can be
+ available. By default, tcg is used. If there is more than one
+ accelerator specified, the next one is used if the previous one
+ fails to initialize.
``vmport=on|off|auto``
Enables emulation of VMWare IO port, for vmmouse etc. auto says
@@ -226,7 +226,7 @@ ERST
DEF("accel", HAS_ARG, QEMU_OPTION_accel,
"-accel [accel=]accelerator[,prop[=value][,...]]\n"
- " select accelerator (kvm, xen, hvf, nvmm, whpx or tcg; use 'help' for a list)\n"
+ " select accelerator (kvm, xen, hvf, nvmm, whpx, mshv or tcg; use 'help' for a list)\n"
" igd-passthru=on|off (enable Xen integrated Intel graphics passthrough, default=off)\n"
" kernel-irqchip=on|off|split controls accelerated irqchip support (default=on)\n"
" kvm-shadow-mem=size of KVM shadow MMU in bytes\n"
@@ -241,8 +241,8 @@ DEF("accel", HAS_ARG, QEMU_OPTION_accel,
SRST
``-accel name[,prop=value[,...]]``
This is used to enable an accelerator. Depending on the target
- architecture, kvm, xen, hvf, nvmm, whpx or tcg can be available. By
- default, tcg is used. If there is more than one accelerator
+ architecture, kvm, xen, hvf, nvmm, whpx, mshv or tcg can be available.
+ By default, tcg is used. If there is more than one accelerator
specified, the next one is used if the previous one fails to
initialize.

View File

@ -1,55 +0,0 @@
From 678f73d1b85bab0d47f11d23df186a6797b2da8e Mon Sep 17 00:00:00 2001
From: Magnus Kulke <magnuskulke@linux.microsoft.com>
Date: Tue, 16 Sep 2025 18:48:47 +0200
Subject: [PATCH] MAINTAINERS: Add maintainers for mshv accelerator
RH-Author: Igor Mammedov <imammedo@redhat.com>
RH-MergeRequest: 437: el10: x86: enablement for Azure L1VH OCP readiness
RH-Jira: RHEL-134212
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [28/30] 0178a9a61285bd708b5f589888c36b74efd4a4bf
Adding Magnus Kulke and Wei Liu to the maintainers file for the
respective folders/files.
Signed-off-by: Magnus Kulke <magnuskulke@linux.microsoft.com>
Link: https://lore.kernel.org/r/20250916164847.77883-28-magnuskulke@linux.microsoft.com
[Rename "MAHV CPUs" to mention x86. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit 1872bd9f2dad5113b0c27d352ec49683e0953c7f)
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Patch-name: kvm-MAINTAINERS-Add-maintainers-for-mshv-accelerator.patch
Patch-id: 88
Patch-present-in-specfile: True
---
MAINTAINERS | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index a07086ed76..d4696f00d7 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -546,6 +546,21 @@ F: target/i386/whpx/
F: accel/stubs/whpx-stub.c
F: include/system/whpx.h
+MSHV
+M: Magnus Kulke <magnus.kulke@linux.microsoft.com>
+R: Wei Liu <wei.liu@kernel.org>
+S: Supported
+F: accel/mshv/
+F: include/system/mshv.h
+F: include/hw/hyperv/hvgdk*.h
+F: include/hw/hyperv/hvhdk*.h
+
+X86 MSHV CPUs
+M: Magnus Kulke <magnus.kulke@linux.microsoft.com>
+R: Wei Liu <wei.liu@kernel.org>
+S: Supported
+F: target/i386/mshv/
+
X86 Instruction Emulator
M: Cameron Esfahani <dirty@apple.com>
M: Roman Bolshakov <rbolshakov@ddn.com>

View File

@ -1,40 +0,0 @@
From 8b6f5eb5eee8bac91997ab49a0f07d7d23db387c Mon Sep 17 00:00:00 2001
From: Paolo Bonzini <pbonzini@redhat.com>
Date: Wed, 22 Oct 2025 14:52:48 +0200
Subject: [PATCH] accel/mshv: initialize thread name
RH-Author: Igor Mammedov <imammedo@redhat.com>
RH-MergeRequest: 437: el10: x86: enablement for Azure L1VH OCP readiness
RH-Jira: RHEL-134212
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [29/30] 3e7286070c5ce162001fd407ebb1fa3920e300fa
The initialization was dropped when the code was copied from existing
accelerators. Coverity knows (CID 1641400). Fix it.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit 2cd3c1d35a06a62b25afa80c5baf381ce4b56805)
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Patch-name: kvm-accel-mshv-initialize-thread-name.patch
Patch-id: 89
Patch-present-in-specfile: True
---
accel/mshv/mshv-all.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/accel/mshv/mshv-all.c b/accel/mshv/mshv-all.c
index 45174f7c4e..80428d130d 100644
--- a/accel/mshv/mshv-all.c
+++ b/accel/mshv/mshv-all.c
@@ -596,6 +596,9 @@ static void mshv_start_vcpu_thread(CPUState *cpu)
{
char thread_name[VCPU_THREAD_NAME_SIZE];
+ snprintf(thread_name, VCPU_THREAD_NAME_SIZE, "CPU %d/MSHV",
+ cpu->cpu_index);
+
cpu->thread = g_malloc0(sizeof(QemuThread));
cpu->halt_cond = g_malloc0(sizeof(QemuCond));

View File

@ -1,43 +0,0 @@
From 94cb07058fe3c3cfac8af7f955cf7d40a231aada Mon Sep 17 00:00:00 2001
From: Paolo Bonzini <pbonzini@redhat.com>
Date: Wed, 22 Oct 2025 14:54:30 +0200
Subject: [PATCH] accel/mshv: use return value of handle_pio_str_read
RH-Author: Igor Mammedov <imammedo@redhat.com>
RH-MergeRequest: 437: el10: x86: enablement for Azure L1VH OCP readiness
RH-Jira: RHEL-134212
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [30/30] 60404a4d9211cf711fd4581d9f586510c3897bd4
Coverity complains because we assign to ret here but
then never read it again before we overwrite it with
the call to set_x64_registers().
Analyzed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit 1557adc82698416bc68033765cfffb0a0b91c6bf)
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Patch-name: kvm-accel-mshv-use-return-value-of-handle_pio_str_read.patch
Patch-id: 90
Patch-present-in-specfile: True
---
target/i386/mshv/mshv-cpu.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/target/i386/mshv/mshv-cpu.c b/target/i386/mshv/mshv-cpu.c
index 1f7b9cb37e..1c3db02188 100644
--- a/target/i386/mshv/mshv-cpu.c
+++ b/target/i386/mshv/mshv-cpu.c
@@ -1489,6 +1489,10 @@ static int handle_pio_str(CPUState *cpu, hv_x64_io_port_intercept_message *info)
reg_values[0] = info->rsi;
} else {
ret = handle_pio_str_read(cpu, info, repeat, port, direction_flag);
+ if (ret < 0) {
+ error_report("Failed to handle pio str read");
+ return -1;
+ }
reg_names[0] = HV_X64_REGISTER_RDI;
reg_values[0] = info->rdi;
}

View File

@ -1,236 +0,0 @@
From 94b83e4df3495f451190a26d0ae481aebf38055f Mon Sep 17 00:00:00 2001
From: Paolo Bonzini <pbonzini@redhat.com>
Date: Mon, 13 Oct 2025 12:49:04 +0200
Subject: [PATCH] monitor: generalize query-mshv/"info mshv" to
query-accelerators/"info accelerators"
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
RH-Author: Igor Mammedov <imammedo@redhat.com>
RH-MergeRequest: 443: [REHL10.2] L1HV: monitor: generalize query-mshv/"info mshv" to query-accelerators/"info accelerators"
RH-Jira: RHEL-134212
RH-Acked-by: MST <mst@redhat.com>
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
RH-Commit: [1/1] af946c572c3dab34cee6399bf4438e2722dd7e44 (imammedo/qemu-kvm-cs)
The recently-introduced query-mshv command is a duplicate of query-kvm,
and neither provides a full view of which accelerators are supported
by a particular binary of QEMU and which is in use.
KVM was the first accelerator added to QEMU, predating QOM and TYPE_ACCEL,
so it got a pass. But now, instead of adding a badly designed copy, solve
the problem completely for all accelerators with a command that provides
the whole picture:
>> {"execute": "query-accelerators"}
<< {"return": {"enabled": "tcg", "present": ["kvm", "mshv", "qtest", "tcg", "xen"]}}
Cc: Praveen K Paladugu <prapal@microsoft.com>
Cc: Magnus Kulke <magnuskulke@linux.microsoft.com>
Suggested-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit 71d5babbd6fffc7def1ecbf29f9753e3a2807761)
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Patch-name: kvm-monitor-generalize-query-mshv-info-mshv-to-query-acc.patch
Patch-id: 91
Patch-present-in-specfile: True
---
hmp-commands-info.hx | 15 ++++++++----
hw/core/machine-hmp-cmds.c | 23 +++++++++++--------
hw/core/machine-qmp-cmds.c | 24 +++++++++++++------
include/monitor/hmp.h | 2 +-
qapi/accelerator.json | 47 +++++++++++++++++++++++++++++---------
5 files changed, 77 insertions(+), 34 deletions(-)
diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx
index eaaa880c1b..3ed636e4e8 100644
--- a/hmp-commands-info.hx
+++ b/hmp-commands-info.hx
@@ -308,16 +308,21 @@ SRST
ERST
{
- .name = "mshv",
+ .name = "accelerators",
.args_type = "",
.params = "",
- .help = "show MSHV information",
- .cmd = hmp_info_mshv,
+ .help = "show present and enabled information",
+ .cmd = hmp_info_accelerators,
},
SRST
- ``info mshv``
- Show MSHV information.
+ ``info accelerators``
+ Show which accelerators are compiled into a QEMU binary, and what accelerator
+ is in use. For example::
+
+ kvm qtest [tcg]
+
+ indicates that TCG in use, and that KVM and qtest are also available.
ERST
{
diff --git a/hw/core/machine-hmp-cmds.c b/hw/core/machine-hmp-cmds.c
index 682ed9f49b..74a56600be 100644
--- a/hw/core/machine-hmp-cmds.c
+++ b/hw/core/machine-hmp-cmds.c
@@ -163,19 +163,22 @@ void hmp_info_kvm(Monitor *mon, const QDict *qdict)
qapi_free_KvmInfo(info);
}
-void hmp_info_mshv(Monitor *mon, const QDict *qdict)
+void hmp_info_accelerators(Monitor *mon, const QDict *qdict)
{
- MshvInfo *info;
-
- info = qmp_query_mshv(NULL);
- monitor_printf(mon, "mshv support: ");
- if (info->present) {
- monitor_printf(mon, "%s\n", info->enabled ? "enabled" : "disabled");
- } else {
- monitor_printf(mon, "not compiled\n");
+ AcceleratorInfo *info;
+ AcceleratorList *accel;
+
+ info = qmp_query_accelerators(NULL);
+ for (accel = info->present; accel; accel = accel->next) {
+ char trail = accel->next ? ' ' : '\n';
+ if (info->enabled == accel->value) {
+ monitor_printf(mon, "[%s]%c", Accelerator_str(accel->value), trail);
+ } else {
+ monitor_printf(mon, "%s%c", Accelerator_str(accel->value), trail);
+ }
}
- qapi_free_MshvInfo(info);
+ qapi_free_AcceleratorInfo(info);
}
void hmp_info_uuid(Monitor *mon, const QDict *qdict)
diff --git a/hw/core/machine-qmp-cmds.c b/hw/core/machine-qmp-cmds.c
index e24bf0d97b..51d5c230f7 100644
--- a/hw/core/machine-qmp-cmds.c
+++ b/hw/core/machine-qmp-cmds.c
@@ -31,15 +31,25 @@
#include <sys/stat.h>
/*
- * QMP query for MSHV
+ * QMP query for enabled and present accelerators
*/
-MshvInfo *qmp_query_mshv(Error **errp)
+AcceleratorInfo *qmp_query_accelerators(Error **errp)
{
- MshvInfo *info = g_malloc0(sizeof(*info));
-
- info->enabled = mshv_enabled();
- info->present = accel_find("mshv");
-
+ AcceleratorInfo *info = g_malloc0(sizeof(*info));
+ AccelClass *current_class = ACCEL_GET_CLASS(current_accel());
+ int i;
+
+ for (i = ACCELERATOR__MAX; i-- > 0; ) {
+ const char *s = Accelerator_str(i);
+ AccelClass *this_class = accel_find(s);
+
+ if (this_class) {
+ QAPI_LIST_PREPEND(info->present, i);
+ if (this_class == current_class) {
+ info->enabled = i;
+ }
+ }
+ }
return info;
}
diff --git a/include/monitor/hmp.h b/include/monitor/hmp.h
index 31bd812e5f..897dfaa2b6 100644
--- a/include/monitor/hmp.h
+++ b/include/monitor/hmp.h
@@ -24,7 +24,7 @@ strList *hmp_split_at_comma(const char *str);
void hmp_info_name(Monitor *mon, const QDict *qdict);
void hmp_info_version(Monitor *mon, const QDict *qdict);
void hmp_info_kvm(Monitor *mon, const QDict *qdict);
-void hmp_info_mshv(Monitor *mon, const QDict *qdict);
+void hmp_info_accelerators(Monitor *mon, const QDict *qdict);
void hmp_info_status(Monitor *mon, const QDict *qdict);
void hmp_info_uuid(Monitor *mon, const QDict *qdict);
void hmp_info_chardev(Monitor *mon, const QDict *qdict);
diff --git a/qapi/accelerator.json b/qapi/accelerator.json
index 664e027246..2b92060884 100644
--- a/qapi/accelerator.json
+++ b/qapi/accelerator.json
@@ -56,30 +56,55 @@
'features': [ 'unstable' ] }
##
-# @MshvInfo:
+# @Accelerator:
#
# Information about support for MSHV acceleration
#
-# @enabled: true if MSHV acceleration is active
+# @hvf: Apple Hypervisor.framework
#
-# @present: true if MSHV acceleration is built into this executable
+# @kvm: KVM
+#
+# @mshv: Hyper-V
+#
+# @nvmm: NetBSD NVMM
+#
+# @qtest: QTest (dummy accelerator)
+#
+# @tcg: TCG (dynamic translation)
+#
+# @whpx: Windows Hypervisor Platform
+#
+# @xen: Xen
+#
+# Since: 10.2.0
+##
+{ 'enum': 'Accelerator', 'data': ['hvf', 'kvm', 'mshv', 'nvmm', 'qtest', 'tcg', 'whpx', 'xen'] }
+
+##
+# @AcceleratorInfo:
+#
+# Information about support for various accelerators
+#
+# @enabled: the accelerator that is in use
+#
+# @present: the list of accelerators that are built into this executable
#
# Since: 10.2.0
##
-{ 'struct': 'MshvInfo', 'data': {'enabled': 'bool', 'present': 'bool'} }
+{ 'struct': 'AcceleratorInfo', 'data': {'enabled': 'Accelerator', 'present': ['Accelerator']} }
##
-# @query-mshv:
+# @query-accelerators:
#
-# Return information about MSHV acceleration
+# Return information about accelerators
#
-# Returns: @MshvInfo
+# Returns: @AcceleratorInfo
#
-# Since: 10.0.92
+# Since: 10.2.0
#
# .. qmp-example::
#
-# -> { "execute": "query-mshv" }
-# <- { "return": { "enabled": true, "present": true } }
+# -> { "execute": "query-accelerators" }
+# <- { "return": { "enabled": "mshv", "present": ["kvm", "mshv", "qtest", "tcg"] } }
##
-{ 'command': 'query-mshv', 'returns': 'MshvInfo' }
+{ 'command': 'query-accelerators', 'returns': 'AcceleratorInfo' }

View File

@ -1,99 +0,0 @@
From 95cb09a4a0a6b81a5a5e52384a345a3379c8c674 Mon Sep 17 00:00:00 2001
From: Kevin Wolf <kwolf@redhat.com>
Date: Fri, 24 Oct 2025 14:30:37 +0200
Subject: [PATCH] block: Improve comments in BlockLimits
RH-Author: Kevin Wolf <kwolf@redhat.com>
RH-MergeRequest: 439: block: Expose block limits in monitor and qemu-img info
RH-Jira: RHEL-110003
RH-Acked-by: Hanna Czenczek <hreitz@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [1/4] 06c55e52ff339d2bc4559b109b0a6dd625caa7f0 (kmwolf/centos-qemu-kvm)
Patches to expose the limits in QAPI have made clear that the existing
documentation of BlockLimits could be improved: The meaning of
min_mem_alignment and opt_mem_alignment could be clearer, and talking
about better alignment values isn't helpful when we only detect these
values and never choose them.
Make the changes in the BlockLimits documentation now, so that the
patches exposing the fields in QAPI can use descriptions consistent with
it.
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Message-ID: <20251024123041.51254-2-kwolf@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 46dd683d56b1328cb2bc923914bfd7ac590064f7)
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Patch-name: kvm-block-Improve-comments-in-BlockLimits.patch
Patch-id: 92
Patch-present-in-specfile: True
---
include/block/block_int-common.h | 30 +++++++++++++++++-------------
1 file changed, 17 insertions(+), 13 deletions(-)
diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
index 034c0634c8..5206f32d53 100644
--- a/include/block/block_int-common.h
+++ b/include/block/block_int-common.h
@@ -817,10 +817,10 @@ typedef struct BlockLimits {
int64_t max_pdiscard;
/*
- * Optimal alignment for discard requests in bytes. A power of 2
- * is best but not mandatory. Must be a multiple of
- * bl.request_alignment, and must be less than max_pdiscard if
- * that is set. May be 0 if bl.request_alignment is good enough
+ * Optimal alignment for discard requests in bytes. Note that this doesn't
+ * have to be a power of two. Must be a multiple of bl.request_alignment,
+ * and must be less than max_pdiscard if that is set. May be 0 if
+ * bl.request_alignment is good enough.
*/
uint32_t pdiscard_alignment;
@@ -831,11 +831,10 @@ typedef struct BlockLimits {
int64_t max_pwrite_zeroes;
/*
- * Optimal alignment for write zeroes requests in bytes. A power
- * of 2 is best but not mandatory. Must be a multiple of
- * bl.request_alignment, and must be less than max_pwrite_zeroes
- * if that is set. May be 0 if bl.request_alignment is good
- * enough
+ * Optimal alignment for write zeroes requests in bytes. Note that this
+ * doesn't have to be a power of two. Must be a multiple of
+ * bl.request_alignment, and must be less than max_pwrite_zeroes if that is
+ * set. May be 0 if bl.request_alignment is good enough.
*/
uint32_t pwrite_zeroes_alignment;
@@ -863,18 +862,23 @@ typedef struct BlockLimits {
uint64_t max_hw_transfer;
/*
- * Maximal number of scatter/gather elements allowed by the hardware.
+ * Maximum number of scatter/gather elements allowed by the hardware.
* Applies whenever transfers to the device bypass the kernel I/O
* scheduler, for example with SG_IO. If larger than max_iov
* or if zero, blk_get_max_hw_iov will fall back to max_iov.
*/
int max_hw_iov;
-
- /* memory alignment, in bytes so that no bounce buffer is needed */
+ /*
+ * Minimal required memory alignment in bytes for zero-copy I/O to succeed.
+ * For unaligned requests, a bounce buffer will be used.
+ */
size_t min_mem_alignment;
- /* memory alignment, in bytes, for bounce buffer */
+ /*
+ * Optimal memory alignment in bytes. This is the alignment used for any
+ * buffer allocations QEMU performs internally.
+ */
size_t opt_mem_alignment;
/* maximum number of iovec elements */

View File

@ -1,256 +0,0 @@
From 2b27b1a46e5c0c2eb53bf7d9d2a9759d0ffc3f2c Mon Sep 17 00:00:00 2001
From: Kevin Wolf <kwolf@redhat.com>
Date: Fri, 24 Oct 2025 14:30:38 +0200
Subject: [PATCH] block: Expose block limits for images in QMP
RH-Author: Kevin Wolf <kwolf@redhat.com>
RH-MergeRequest: 439: block: Expose block limits in monitor and qemu-img info
RH-Jira: RHEL-110003
RH-Acked-by: Hanna Czenczek <hreitz@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [2/4] a2d45f05abd5bedbad2f10ae4dc7a5cce909a2fe (kmwolf/centos-qemu-kvm)
This information can be useful both for debugging and for management
tools trying to configure guest devices with the optimal limits
(possibly across multiple hosts). There is no reason not to make it
available, so just add it to BlockNodeInfo.
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-ID: <20251024123041.51254-3-kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit d2634e18286a5772f04cc724e64f8b16a2124587)
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Patch-name: kvm-block-Expose-block-limits-for-images-in-QMP.patch
Patch-id: 93
Patch-present-in-specfile: True
---
block/qapi.c | 34 ++++++++++++++--
qapi/block-core.json | 66 ++++++++++++++++++++++++++++++++
tests/qemu-iotests/184 | 5 ++-
tests/qemu-iotests/184.out | 8 ----
tests/qemu-iotests/common.filter | 3 +-
5 files changed, 102 insertions(+), 14 deletions(-)
diff --git a/block/qapi.c b/block/qapi.c
index 12fbf8d1b7..54521d0a68 100644
--- a/block/qapi.c
+++ b/block/qapi.c
@@ -235,7 +235,8 @@ int bdrv_query_snapshot_info_list(BlockDriverState *bs,
* in @info, setting @errp on error.
*/
static void GRAPH_RDLOCK
-bdrv_do_query_node_info(BlockDriverState *bs, BlockNodeInfo *info, Error **errp)
+bdrv_do_query_node_info(BlockDriverState *bs, BlockNodeInfo *info, bool limits,
+ Error **errp)
{
int64_t size;
const char *backing_filename;
@@ -269,6 +270,33 @@ bdrv_do_query_node_info(BlockDriverState *bs, BlockNodeInfo *info, Error **errp)
info->dirty_flag = bdi.is_dirty;
info->has_dirty_flag = true;
}
+
+ if (limits) {
+ info->limits = g_new(BlockLimitsInfo, 1);
+ *info->limits = (BlockLimitsInfo) {
+ .request_alignment = bs->bl.request_alignment,
+ .has_max_discard = bs->bl.max_pdiscard != 0,
+ .max_discard = bs->bl.max_pdiscard,
+ .has_discard_alignment = bs->bl.pdiscard_alignment != 0,
+ .discard_alignment = bs->bl.pdiscard_alignment,
+ .has_max_write_zeroes = bs->bl.max_pwrite_zeroes != 0,
+ .max_write_zeroes = bs->bl.max_pwrite_zeroes,
+ .has_write_zeroes_alignment = bs->bl.pwrite_zeroes_alignment != 0,
+ .write_zeroes_alignment = bs->bl.pwrite_zeroes_alignment,
+ .has_opt_transfer = bs->bl.opt_transfer != 0,
+ .opt_transfer = bs->bl.opt_transfer,
+ .has_max_transfer = bs->bl.max_transfer != 0,
+ .max_transfer = bs->bl.max_transfer,
+ .has_max_hw_transfer = bs->bl.max_hw_transfer != 0,
+ .max_hw_transfer = bs->bl.max_hw_transfer,
+ .max_iov = bs->bl.max_iov,
+ .has_max_hw_iov = bs->bl.max_hw_iov != 0,
+ .max_hw_iov = bs->bl.max_hw_iov,
+ .min_mem_alignment = bs->bl.min_mem_alignment,
+ .opt_mem_alignment = bs->bl.opt_mem_alignment,
+ };
+ }
+
info->format_specific = bdrv_get_specific_info(bs, &err);
if (err) {
error_propagate(errp, err);
@@ -343,7 +371,7 @@ void bdrv_query_image_info(BlockDriverState *bs,
ImageInfo *info;
info = g_new0(ImageInfo, 1);
- bdrv_do_query_node_info(bs, qapi_ImageInfo_base(info), errp);
+ bdrv_do_query_node_info(bs, qapi_ImageInfo_base(info), true, errp);
if (*errp) {
goto fail;
}
@@ -397,7 +425,7 @@ void bdrv_query_block_graph_info(BlockDriverState *bs,
BdrvChild *c;
info = g_new0(BlockGraphInfo, 1);
- bdrv_do_query_node_info(bs, qapi_BlockGraphInfo_base(info), errp);
+ bdrv_do_query_node_info(bs, qapi_BlockGraphInfo_base(info), false, errp);
if (*errp) {
goto fail;
}
diff --git a/qapi/block-core.json b/qapi/block-core.json
index dc6eb4ae23..2c037183f0 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -275,6 +275,69 @@
'file': 'ImageInfoSpecificFileWrapper'
} }
+##
+# @BlockLimitsInfo:
+#
+# @request-alignment: Alignment requirement, in bytes, for
+# offset/length of I/O requests.
+#
+# @max-discard: Maximum number of bytes that can be discarded at once.
+# If not present, there is no specific maximum.
+#
+# @discard-alignment: Optimal alignment for discard requests in bytes.
+# Note that this doesn't have to be a power of two. If not
+# present, discards don't have a alignment requirement different
+# from @request-alignment.
+#
+# @max-write-zeroes: Maximum number of bytes that can be zeroed out at
+# once. If not present, there is no specific maximum.
+#
+# @write-zeroes-alignment: Optimal alignment for write zeroes requests
+# in bytes. Note that this doesn't have to be a power of two. If
+# not present, write_zeroes doesn't have a alignment requirement
+# different from @request-alignment.
+#
+# @opt-transfer: Optimal transfer length in bytes. If not present,
+# there is no preferred size.
+#
+# @max-transfer: Maximal transfer length in bytes. If not present,
+# there is no specific maximum.
+#
+# @max-hw-transfer: Maximal hardware transfer length in bytes.
+# Applies whenever transfers to the device bypass the kernel I/O
+# scheduler, for example with SG_IO. If not present, there is no
+# specific maximum.
+#
+# @max-iov: Maximum number of scatter/gather elements
+#
+# @max-hw-iov: Maximum number of scatter/gather elements allowed by
+# the hardware. Applies whenever transfers to the device bypass
+# the kernel I/O scheduler, for example with SG_IO. If not
+# present, the hardware limits is unknown and @max-iov is always
+# used.
+#
+# @min-mem-alignment: Minimal required memory alignment in bytes for
+# zero-copy I/O to succeed. For unaligned requests, a bounce
+# buffer will be used.
+#
+# @opt-mem-alignment: Optimal memory alignment in bytes. This is the
+# alignment used for any buffer allocations QEMU performs
+# internally.
+##
+{ 'struct': 'BlockLimitsInfo',
+ 'data': { 'request-alignment': 'uint32',
+ '*max-discard': 'uint64',
+ '*discard-alignment': 'uint32',
+ '*max-write-zeroes': 'uint64',
+ '*write-zeroes-alignment': 'uint32',
+ '*opt-transfer': 'uint32',
+ '*max-transfer': 'uint32',
+ '*max-hw-transfer': 'uint32',
+ 'max-iov': 'int',
+ '*max-hw-iov': 'int',
+ 'min-mem-alignment': 'size',
+ 'opt-mem-alignment': 'size' } }
+
##
# @BlockNodeInfo:
#
@@ -304,6 +367,8 @@
#
# @snapshots: list of VM snapshots
#
+# @limits: block limits that are used for I/O on the node (Since 10.2)
+#
# @format-specific: structure supplying additional format-specific
# information (since 1.7)
#
@@ -315,6 +380,7 @@
'*cluster-size': 'int', '*encrypted': 'bool', '*compressed': 'bool',
'*backing-filename': 'str', '*full-backing-filename': 'str',
'*backing-filename-format': 'str', '*snapshots': ['SnapshotInfo'],
+ '*limits': 'BlockLimitsInfo',
'*format-specific': 'ImageInfoSpecific' } }
##
diff --git a/tests/qemu-iotests/184 b/tests/qemu-iotests/184
index e4cbcd8634..6d0afe9d38 100755
--- a/tests/qemu-iotests/184
+++ b/tests/qemu-iotests/184
@@ -45,8 +45,9 @@ do_run_qemu()
run_qemu()
{
- do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | _filter_qmp\
- | _filter_qemu_io | _filter_generated_node_ids
+ do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | _filter_qmp \
+ | _filter_qemu_io | _filter_generated_node_ids \
+ | _filter_img_info
}
test_throttle=$($QEMU_IMG --help|grep throttle)
diff --git a/tests/qemu-iotests/184.out b/tests/qemu-iotests/184.out
index ef99bb2e9a..52692b6b3b 100644
--- a/tests/qemu-iotests/184.out
+++ b/tests/qemu-iotests/184.out
@@ -41,12 +41,6 @@ Testing:
},
"iops_wr": 0,
"ro": false,
- "children": [
- {
- "node-name": "disk0",
- "child": "file"
- }
- ],
"node-name": "throttle0",
"backing_file_depth": 1,
"drv": "throttle",
@@ -75,8 +69,6 @@ Testing:
},
"iops_wr": 0,
"ro": false,
- "children": [
- ],
"node-name": "disk0",
"backing_file_depth": 0,
"drv": "null-co",
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
index 35c0fc0d20..cd8b506dba 100644
--- a/tests/qemu-iotests/common.filter
+++ b/tests/qemu-iotests/common.filter
@@ -230,6 +230,7 @@ _filter_img_info()
discard=0
regex_json_spec_start='^ *"format-specific": \{'
regex_json_child_start='^ *"children": \['
+ regex_json_limit_start='^ *"limits": \{'
gsed -e "s#$REMOTE_TEST_DIR#TEST_DIR#g" \
-e "s#$IMGPROTO:$TEST_DIR#TEST_DIR#g" \
-e "s#$TEST_DIR#TEST_DIR#g" \
@@ -262,7 +263,7 @@ _filter_img_info()
discard=1
elif [[ $line =~ "Child node '/" ]]; then
discard=1
- elif [[ $line =~ $regex_json_spec_start ]]; then
+ elif [[ $line =~ $regex_json_spec_start || $line =~ $regex_json_limit_start ]]; then
discard=2
regex_json_end="^${line%%[^ ]*}\\},? *$"
elif [[ $line =~ $regex_json_child_start ]]; then

View File

@ -1,241 +0,0 @@
From 70f342dce4cfe8b2fe3998ad06c5072e4481067f Mon Sep 17 00:00:00 2001
From: Kevin Wolf <kwolf@redhat.com>
Date: Fri, 24 Oct 2025 14:30:39 +0200
Subject: [PATCH] qemu-img info: Optionally show block limits
RH-Author: Kevin Wolf <kwolf@redhat.com>
RH-MergeRequest: 439: block: Expose block limits in monitor and qemu-img info
RH-Jira: RHEL-110003
RH-Acked-by: Hanna Czenczek <hreitz@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [3/4] 688d6d1617c4d5916b299f08fad0e928341c73f7 (kmwolf/centos-qemu-kvm)
Add a new --limits option to 'qemu-img info' that displays the block
limits for the image and all of its children, making the information
more accessible for human users than in QMP. This option is not enabled
by default because it can be a lot of output that isn't usually relevant
if you're not specifically trying to diagnose some I/O problem.
This makes the same information automatically also available in HMP
'info block -v'.
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
Message-ID: <20251024123041.51254-4-kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 5b4b3bfdfc28d2398f34194d260d6eef9a9048b4)
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Patch-name: kvm-qemu-img-info-Optionally-show-block-limits.patch
Patch-id: 94
Patch-present-in-specfile: True
---
block/qapi.c | 34 ++++++++++++++++++++++++++++++++--
docs/tools/qemu-img.rst | 6 +++++-
include/block/qapi.h | 2 +-
qemu-img-cmds.hx | 4 ++--
qemu-img.c | 15 ++++++++++++---
5 files changed, 52 insertions(+), 9 deletions(-)
diff --git a/block/qapi.c b/block/qapi.c
index 54521d0a68..9f5771e019 100644
--- a/block/qapi.c
+++ b/block/qapi.c
@@ -417,6 +417,7 @@ fail:
*/
void bdrv_query_block_graph_info(BlockDriverState *bs,
BlockGraphInfo **p_info,
+ bool limits,
Error **errp)
{
ERRP_GUARD();
@@ -425,7 +426,7 @@ void bdrv_query_block_graph_info(BlockDriverState *bs,
BdrvChild *c;
info = g_new0(BlockGraphInfo, 1);
- bdrv_do_query_node_info(bs, qapi_BlockGraphInfo_base(info), false, errp);
+ bdrv_do_query_node_info(bs, qapi_BlockGraphInfo_base(info), limits, errp);
if (*errp) {
goto fail;
}
@@ -439,7 +440,7 @@ void bdrv_query_block_graph_info(BlockDriverState *bs,
QAPI_LIST_APPEND(children_list_tail, c_info);
c_info->name = g_strdup(c->name);
- bdrv_query_block_graph_info(c->bs, &c_info->info, errp);
+ bdrv_query_block_graph_info(c->bs, &c_info->info, limits, errp);
if (*errp) {
goto fail;
}
@@ -936,6 +937,29 @@ void bdrv_image_info_specific_dump(ImageInfoSpecific *info_spec,
visit_free(v);
}
+/**
+ * Dumps the given BlockLimitsInfo object in a human-readable form,
+ * prepending an optional prefix if the dump is not empty.
+ */
+static void bdrv_image_info_limits_dump(BlockLimitsInfo *limits,
+ const char *prefix,
+ int indentation)
+{
+ QObject *obj;
+ Visitor *v = qobject_output_visitor_new(&obj);
+
+ visit_type_BlockLimitsInfo(v, NULL, &limits, &error_abort);
+ visit_complete(v, &obj);
+ if (!qobject_is_empty_dump(obj)) {
+ if (prefix) {
+ qemu_printf("%*s%s", indentation * 4, "", prefix);
+ }
+ dump_qobject(indentation + 1, obj);
+ }
+ qobject_unref(obj);
+ visit_free(v);
+}
+
/**
* Print the given @info object in human-readable form. Every field is indented
* using the given @indentation (four spaces per indentation level).
@@ -1011,6 +1035,12 @@ void bdrv_node_info_dump(BlockNodeInfo *info, int indentation, bool protocol)
}
}
+ if (info->limits) {
+ bdrv_image_info_limits_dump(info->limits,
+ "Block limits:\n",
+ indentation);
+ }
+
if (info->has_snapshots) {
SnapshotInfoList *elem;
diff --git a/docs/tools/qemu-img.rst b/docs/tools/qemu-img.rst
index 5e7b85079d..fdc9ea9cf2 100644
--- a/docs/tools/qemu-img.rst
+++ b/docs/tools/qemu-img.rst
@@ -503,7 +503,7 @@ Command description:
The size syntax is similar to :manpage:`dd(1)`'s size syntax.
-.. option:: info [--object OBJECTDEF] [--image-opts] [-f FMT] [--output=OFMT] [--backing-chain] [-U] FILENAME
+.. option:: info [--object OBJECTDEF] [--image-opts] [-f FMT] [--output=OFMT] [--backing-chain] [--limits] [-U] FILENAME
Give information about the disk image *FILENAME*. Use it in
particular to know the size reserved on disk which can be different
@@ -571,6 +571,10 @@ Command description:
``ImageInfoSpecific*`` QAPI object (e.g. ``ImageInfoSpecificQCow2``
for qcow2 images).
+ *Block limits*
+ The block limits for I/O that QEMU detected for the image.
+ This information is only shown if the ``--limits`` option was specified.
+
.. option:: map [--object OBJECTDEF] [--image-opts] [-f FMT] [--start-offset=OFFSET] [--max-length=LEN] [--output=OFMT] [-U] FILENAME
Dump the metadata of image *FILENAME* and its backing file chain.
diff --git a/include/block/qapi.h b/include/block/qapi.h
index 54c48de26a..be554e53dc 100644
--- a/include/block/qapi.h
+++ b/include/block/qapi.h
@@ -42,7 +42,7 @@ bdrv_query_image_info(BlockDriverState *bs, ImageInfo **p_info, bool flat,
bool skip_implicit_filters, Error **errp);
void GRAPH_RDLOCK
bdrv_query_block_graph_info(BlockDriverState *bs, BlockGraphInfo **p_info,
- Error **errp);
+ bool limits, Error **errp);
void bdrv_snapshot_dump(QEMUSnapshotInfo *sn);
void bdrv_image_info_specific_dump(ImageInfoSpecific *info_spec,
diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx
index 2c5a8a28f9..74b66f9d42 100644
--- a/qemu-img-cmds.hx
+++ b/qemu-img-cmds.hx
@@ -66,9 +66,9 @@ SRST
ERST
DEF("info", img_info,
- "info [--object objectdef] [--image-opts] [-f fmt] [--output=ofmt] [--backing-chain] [-U] filename")
+ "info [--object objectdef] [--image-opts] [-f fmt] [--output=ofmt] [--backing-chain] [--limits] [-U] filename")
SRST
-.. option:: info [--object OBJECTDEF] [--image-opts] [-f FMT] [--output=OFMT] [--backing-chain] [-U] FILENAME
+.. option:: info [--object OBJECTDEF] [--image-opts] [-f FMT] [--output=OFMT] [--backing-chain] [--limits] [-U] FILENAME
ERST
DEF("map", img_map,
diff --git a/qemu-img.c b/qemu-img.c
index 7a162fdc08..5cdbeda969 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -86,6 +86,7 @@ enum {
OPTION_BITMAPS = 275,
OPTION_FORCE = 276,
OPTION_SKIP_BROKEN = 277,
+ OPTION_LIMITS = 278,
};
typedef enum OutputFormat {
@@ -3002,7 +3003,8 @@ static gboolean str_equal_func(gconstpointer a, gconstpointer b)
static BlockGraphInfoList *collect_image_info_list(bool image_opts,
const char *filename,
const char *fmt,
- bool chain, bool force_share)
+ bool chain, bool limits,
+ bool force_share)
{
BlockGraphInfoList *head = NULL;
BlockGraphInfoList **tail = &head;
@@ -3039,7 +3041,7 @@ static BlockGraphInfoList *collect_image_info_list(bool image_opts,
* the chain manually here.
*/
bdrv_graph_rdlock_main_loop();
- bdrv_query_block_graph_info(bs, &info, &err);
+ bdrv_query_block_graph_info(bs, &info, limits, &err);
bdrv_graph_rdunlock_main_loop();
if (err) {
@@ -3088,6 +3090,7 @@ static int img_info(const img_cmd_t *ccmd, int argc, char **argv)
BlockGraphInfoList *list;
bool image_opts = false;
bool force_share = false;
+ bool limits = false;
fmt = NULL;
for(;;) {
@@ -3097,6 +3100,7 @@ static int img_info(const img_cmd_t *ccmd, int argc, char **argv)
{"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
{"backing-chain", no_argument, 0, OPTION_BACKING_CHAIN},
{"force-share", no_argument, 0, 'U'},
+ {"limits", no_argument, 0, OPTION_LIMITS},
{"output", required_argument, 0, OPTION_OUTPUT},
{"object", required_argument, 0, OPTION_OBJECT},
{0, 0, 0, 0}
@@ -3119,6 +3123,8 @@ static int img_info(const img_cmd_t *ccmd, int argc, char **argv)
" display information about the backing chain for copy-on-write overlays\n"
" -U, --force-share\n"
" open image in shared mode for concurrent access\n"
+" --limits\n"
+" show detected block limits (may depend on options, e.g. cache mode)\n"
" --output human|json\n"
" specify output format (default: human)\n"
" --object OBJDEF\n"
@@ -3140,6 +3146,9 @@ static int img_info(const img_cmd_t *ccmd, int argc, char **argv)
case 'U':
force_share = true;
break;
+ case OPTION_LIMITS:
+ limits = true;
+ break;
case OPTION_OUTPUT:
output_format = parse_output_format(argv[0], optarg);
break;
@@ -3156,7 +3165,7 @@ static int img_info(const img_cmd_t *ccmd, int argc, char **argv)
filename = argv[optind++];
list = collect_image_info_list(image_opts, filename, fmt, chain,
- force_share);
+ limits, force_share);
if (!list) {
return 1;
}

View File

@ -1,154 +0,0 @@
From cc4a0ad4fd6ab541216e49620cdb0e4132ea7c99 Mon Sep 17 00:00:00 2001
From: Kevin Wolf <kwolf@redhat.com>
Date: Fri, 24 Oct 2025 14:30:40 +0200
Subject: [PATCH] qemu-img info: Add cache mode option
RH-Author: Kevin Wolf <kwolf@redhat.com>
RH-MergeRequest: 439: block: Expose block limits in monitor and qemu-img info
RH-Jira: RHEL-110003
RH-Acked-by: Hanna Czenczek <hreitz@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [4/4] 1d7c278d70f37528be71b31fe121cc531a13dde5 (kmwolf/centos-qemu-kvm)
When querying block limits, different cache modes (in particular
O_DIRECT or not) can result in different limits. Add an option to
'qemu-img info' that allows the user to specify a cache mode, so that
they can get the block limits for the cache mode they intend to use with
their VM.
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Message-ID: <20251024123041.51254-5-kwolf@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 911992fd6ec7a84c7cc82831b4bcd8a2ca5ccc76)
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Patch-name: kvm-qemu-img-info-Add-cache-mode-option.patch
Patch-id: 95
Patch-present-in-specfile: True
---
docs/tools/qemu-img.rst | 2 +-
qemu-img-cmds.hx | 4 ++--
qemu-img.c | 25 +++++++++++++++++++++----
3 files changed, 24 insertions(+), 7 deletions(-)
diff --git a/docs/tools/qemu-img.rst b/docs/tools/qemu-img.rst
index fdc9ea9cf2..558b0eb84d 100644
--- a/docs/tools/qemu-img.rst
+++ b/docs/tools/qemu-img.rst
@@ -503,7 +503,7 @@ Command description:
The size syntax is similar to :manpage:`dd(1)`'s size syntax.
-.. option:: info [--object OBJECTDEF] [--image-opts] [-f FMT] [--output=OFMT] [--backing-chain] [--limits] [-U] FILENAME
+.. option:: info [--object OBJECTDEF] [--image-opts] [-f FMT] [--output=OFMT] [--backing-chain] [--limits] [-t CACHE] [-U] FILENAME
Give information about the disk image *FILENAME*. Use it in
particular to know the size reserved on disk which can be different
diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx
index 74b66f9d42..6bc8265cfb 100644
--- a/qemu-img-cmds.hx
+++ b/qemu-img-cmds.hx
@@ -66,9 +66,9 @@ SRST
ERST
DEF("info", img_info,
- "info [--object objectdef] [--image-opts] [-f fmt] [--output=ofmt] [--backing-chain] [--limits] [-U] filename")
+ "info [--object objectdef] [--image-opts] [-f fmt] [--output=ofmt] [--backing-chain] [--limits] [-t CACHE] [-U] filename")
SRST
-.. option:: info [--object OBJECTDEF] [--image-opts] [-f FMT] [--output=OFMT] [--backing-chain] [--limits] [-U] FILENAME
+.. option:: info [--object OBJECTDEF] [--image-opts] [-f FMT] [--output=OFMT] [--backing-chain] [--limits] [-t CACHE] [-U] FILENAME
ERST
DEF("map", img_map,
diff --git a/qemu-img.c b/qemu-img.c
index 5cdbeda969..a7791896c1 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -3003,6 +3003,7 @@ static gboolean str_equal_func(gconstpointer a, gconstpointer b)
static BlockGraphInfoList *collect_image_info_list(bool image_opts,
const char *filename,
const char *fmt,
+ const char *cache,
bool chain, bool limits,
bool force_share)
{
@@ -3010,6 +3011,15 @@ static BlockGraphInfoList *collect_image_info_list(bool image_opts,
BlockGraphInfoList **tail = &head;
GHashTable *filenames;
Error *err = NULL;
+ int cache_flags = 0;
+ bool writethrough = false;
+ int ret;
+
+ ret = bdrv_parse_cache_mode(cache, &cache_flags, &writethrough);
+ if (ret < 0) {
+ error_report("Invalid cache option: %s", cache);
+ return NULL;
+ }
filenames = g_hash_table_new_full(g_str_hash, str_equal_func, NULL, NULL);
@@ -3026,8 +3036,8 @@ static BlockGraphInfoList *collect_image_info_list(bool image_opts,
g_hash_table_insert(filenames, (gpointer)filename, NULL);
blk = img_open(image_opts, filename, fmt,
- BDRV_O_NO_BACKING | BDRV_O_NO_IO, false, false,
- force_share);
+ BDRV_O_NO_BACKING | BDRV_O_NO_IO | cache_flags,
+ writethrough, false, force_share);
if (!blk) {
goto err;
}
@@ -3087,6 +3097,7 @@ static int img_info(const img_cmd_t *ccmd, int argc, char **argv)
OutputFormat output_format = OFORMAT_HUMAN;
bool chain = false;
const char *filename, *fmt;
+ const char *cache = BDRV_DEFAULT_CACHE;
BlockGraphInfoList *list;
bool image_opts = false;
bool force_share = false;
@@ -3099,13 +3110,14 @@ static int img_info(const img_cmd_t *ccmd, int argc, char **argv)
{"format", required_argument, 0, 'f'},
{"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
{"backing-chain", no_argument, 0, OPTION_BACKING_CHAIN},
+ {"cache", required_argument, 0, 't'},
{"force-share", no_argument, 0, 'U'},
{"limits", no_argument, 0, OPTION_LIMITS},
{"output", required_argument, 0, OPTION_OUTPUT},
{"object", required_argument, 0, OPTION_OBJECT},
{0, 0, 0, 0}
};
- c = getopt_long(argc, argv, "hf:U", long_options, NULL);
+ c = getopt_long(argc, argv, "hf:t:U", long_options, NULL);
if (c == -1) {
break;
}
@@ -3121,6 +3133,8 @@ static int img_info(const img_cmd_t *ccmd, int argc, char **argv)
" (incompatible with -f|--format)\n"
" --backing-chain\n"
" display information about the backing chain for copy-on-write overlays\n"
+" -t, --cache CACHE\n"
+" cache mode for FILE (default: " BDRV_DEFAULT_CACHE ")\n"
" -U, --force-share\n"
" open image in shared mode for concurrent access\n"
" --limits\n"
@@ -3143,6 +3157,9 @@ static int img_info(const img_cmd_t *ccmd, int argc, char **argv)
case OPTION_BACKING_CHAIN:
chain = true;
break;
+ case 't':
+ cache = optarg;
+ break;
case 'U':
force_share = true;
break;
@@ -3164,7 +3181,7 @@ static int img_info(const img_cmd_t *ccmd, int argc, char **argv)
}
filename = argv[optind++];
- list = collect_image_info_list(image_opts, filename, fmt, chain,
+ list = collect_image_info_list(image_opts, filename, fmt, cache, chain,
limits, force_share);
if (!list) {
return 1;

View File

@ -1,38 +0,0 @@
From 1e80aae75dd950911dfa06c0ea814c751342f931 Mon Sep 17 00:00:00 2001
From: Paolo Bonzini <pbonzini@redhat.com>
Date: Fri, 12 Dec 2025 12:30:30 +0100
Subject: [PATCH] rh: configs: enable CONFIG_TDX for x86_64
RH-Author: Paolo Bonzini <pbonzini@redhat.com>
RH-MergeRequest: 445: rh: configs: enable CONFIG_TDX for x86_64
RH-Jira: RHEL-111853
RH-Acked-by: Igor Mammedov <imammedo@redhat.com>
RH-Acked-by: Stefano Garzarella <sgarzare@redhat.com>
RH-Commit: [1/1] 282972aa9e4f94097c68b046f6bb09c4b03705fc (bonzini/qemu-kvm-centos)
JIRA: https://issues.redhat.com/browse/RHEL-111853
TDX support is included in 10.1 but we still need to enable it,
because RHEL is built --without-default-devices.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Patch-name: kvm-rh-configs-enable-CONFIG_TDX-for-x86_64.patch
Patch-id: 96
Patch-present-in-specfile: True
---
configs/devices/x86_64-softmmu/x86_64-rh-devices.mak | 1 +
1 file changed, 1 insertion(+)
diff --git a/configs/devices/x86_64-softmmu/x86_64-rh-devices.mak b/configs/devices/x86_64-softmmu/x86_64-rh-devices.mak
index 1f244f766d..9063ae1b53 100644
--- a/configs/devices/x86_64-softmmu/x86_64-rh-devices.mak
+++ b/configs/devices/x86_64-softmmu/x86_64-rh-devices.mak
@@ -74,6 +74,7 @@ CONFIG_SERIAL_PCI=y
CONFIG_SEV=y
CONFIG_SMBIOS=y
CONFIG_SMBUS_EEPROM=y
+CONFIG_TDX=y
CONFIG_TEST_DEVICES=y
CONFIG_USB=y
CONFIG_USB_EHCI=y

View File

@ -1,65 +0,0 @@
From ce67b67635b76cdd7f43f21988ce2170f47425ef Mon Sep 17 00:00:00 2001
From: Kevin Wolf <kwolf@redhat.com>
Date: Mon, 15 Dec 2025 16:07:14 +0100
Subject: [PATCH] block: Fix BDS use after free during shutdown
RH-Author: Thomas Huth <thuth@redhat.com>
RH-MergeRequest: 446: Fix crash that happens when powering-off a guest during migration
RH-Jira: RHEL-108142
RH-Acked-by: Cornelia Huck <cohuck@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [1/1] af2687210d89fef5c4229a84371236c2b9bbdf5b (thuth/qemu-kvm-cs)
JIRA: https://issues.redhat.com/browse/RHEL-108142
During shutdown, blockdev_close_all_bdrv_states() drops any block node
references that are still owned by the monitor (i.e. the user). However,
in doing so, it forgot to also remove the node from monitor_bdrv_states
(which qmp_blockdev_del() correctly does), which means that later calls
of bdrv_first()/bdrv_next() will still return the (now stale) pointer to
the node.
Usually there is no such call after this point, but in some cases it can
happen. In the reported case, there was an ongoing migration, and the
migration thread wasn't shut down yet: migration_shutdown() called by
qemu_cleanup() doesn't actually wait for the migration to be shut down,
but may just move it to MIGRATION_STATUS_CANCELLING. The next time
migration_iteration_finish() runs, it sees the status and tries to
re-activate all block devices that migration may have previously
inactivated. This is where bdrv_first()/bdrv_next() get called and the
access to the already freed node happens.
It is debatable if migration_shutdown() should really return before
migration has settled, but leaving a dangling pointer in the list of
monitor-owned block nodes is clearly a bug either way and fixing it
solves the immediate problem, so fix it.
Reported-by: Thomas Huth <thuth@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Message-ID: <20251215150714.130214-1-kwolf@redhat.com>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Tested-by: Thomas Huth <thuth@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 307bc43095b8ab1765fd66c26003d5da06681c05)
Signed-off-by: Thomas Huth <thuth@redhat.com>
Patch-name: kvm-block-Fix-BDS-use-after-free-during-shutdown.patch
Patch-id: 97
Patch-present-in-specfile: True
---
blockdev.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/blockdev.c b/blockdev.c
index b451fee6e1..76c8dd0573 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -685,6 +685,7 @@ void blockdev_close_all_bdrv_states(void)
GLOBAL_STATE_CODE();
QTAILQ_FOREACH_SAFE(bs, &monitor_bdrv_states, monitor_list, next_bs) {
+ QTAILQ_REMOVE(&monitor_bdrv_states, bs, monitor_list);
bdrv_unref(bs);
}
}

View File

@ -1,37 +0,0 @@
From a04b03ae978dcec172e27cbaffaca5cfec50eb9c Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Mon, 12 Jan 2026 09:19:07 +0100
Subject: [PATCH] fix pc_rhel_10_2_compat_len
RH-Author: Gerd Hoffmann <kraxel@redhat.com>
RH-MergeRequest: 447: q35: increase default tseg size
RH-Jira: RHEL-126707
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [1/2] b9291186e031c0c018dfdc87960b04817421ecec (kraxel.rh/centos-src-qemu-kvm)
There is an (apparently) cut+paste error in the definition
pc_rhel_10_2_compat_len variable, it calculates the length
of the wrong array. Fix it.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Patch-name: kvm-fix-pc_rhel_10_2_compat_len.patch
Patch-id: 98
Patch-present-in-specfile: True
---
hw/i386/pc.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 446d4a7c93..394a84eb8a 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -304,7 +304,7 @@ GlobalProperty pc_rhel_10_2_compat[] = {
{ TYPE_X86_CPU, "x-arch-cap-always-on", "true" },
{ TYPE_X86_CPU, "x-pdcm-on-even-without-pmu", "true" },
};
-const size_t pc_rhel_10_2_compat_len = G_N_ELEMENTS(pc_compat_10_0);
+const size_t pc_rhel_10_2_compat_len = G_N_ELEMENTS(pc_rhel_10_2_compat);
GlobalProperty pc_rhel_10_1_compat[] = {
/* pc_rhel_10_1_compat from pc_compat_9_1 */

View File

@ -1,64 +0,0 @@
From 552c6b5fb530feebcfab92b18e5ccc592ae2af2e Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Thu, 6 Nov 2025 11:56:40 +0100
Subject: [PATCH] q35: increase default tseg size
RH-Author: Gerd Hoffmann <kraxel@redhat.com>
RH-MergeRequest: 447: q35: increase default tseg size
RH-Jira: RHEL-126707
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [2/2] 8cbbb7b55e2e83bb6129b2da92179ff7b969c4ed (kraxel.rh/centos-src-qemu-kvm)
With virtual machines becoming larger (more CPUs, more memory) the
memory needed by the SMM code in OVMF to manage page tables and vcpu
state grows too.
Default SMM memory (aka TSEG) size is 16 MB, and this often is not
enough. Bump it to 64 MB for new machine types.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-Id: <20251106105640.1642109-1-kraxel@redhat.com>
(cherry picked from commit fa4136387928749d5a1b4fa3606ae0ce6dce75aa)
[ RHEL: drop compat property update for upstream machine types ]
[ RHEL: add compat property for rhel 10.0 machine type ]
[ NOTE: the 10.0 compat properties are used for
rhel-9.6 + older machine types too ]
Resolves: RHEL-126707
Patch-name: kvm-q35-increase-default-tseg-size.patch
Patch-id: 99
Patch-present-in-specfile: True
---
hw/i386/pc.c | 1 +
hw/pci-host/q35.c | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 394a84eb8a..27900e071b 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -299,6 +299,7 @@ const size_t pc_rhel_compat_len = G_N_ELEMENTS(pc_rhel_compat);
GlobalProperty pc_rhel_10_2_compat[] = {
/* pc_rhel_10_2_compat from pc_compat_10_0 */
+ { "mch", "extended-tseg-mbytes", "16" },
{ TYPE_X86_CPU, "x-consistent-cache", "false" },
{ TYPE_X86_CPU, "x-vendor-cpuid-only-v2", "false" },
{ TYPE_X86_CPU, "x-arch-cap-always-on", "true" },
diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c
index 1951ae440c..a708758d36 100644
--- a/hw/pci-host/q35.c
+++ b/hw/pci-host/q35.c
@@ -663,7 +663,7 @@ static void mch_realize(PCIDevice *d, Error **errp)
static const Property mch_props[] = {
DEFINE_PROP_UINT16("extended-tseg-mbytes", MCHPCIState, ext_tseg_mbytes,
- 16),
+ 64),
DEFINE_PROP_BOOL("smbase-smram", MCHPCIState, has_smram_at_smbase, true),
};

View File

@ -1,69 +0,0 @@
From 1b13e3592cda0576d62195f63a9a692459218173 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= <clg@redhat.com>
Date: Thu, 6 Nov 2025 11:51:48 +0100
Subject: [PATCH] hw/intc/ioapic: Fix ACCEL_KERNEL_GSI_IRQFD_POSSIBLE typo
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
RH-Author: Cédric Le Goater <clg@redhat.com>
RH-MergeRequest: 449: hw/intc/ioapic: Fix ACCEL_KERNEL_GSI_IRQFD_POSSIBLE typo
RH-Jira: RHEL-139028
RH-Acked-by: Igor Mammedov <imammedo@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [1/1] 61c1a3f68e0a5403a90f1d1f2cb793cc83e0cea9 (clegoate/qemu-kvm-centos)
Commit 638ac1c78457 introduced a regression in interrupt remapping
when running a VM configured with an intel-iommu device and an
assigned PCI VF. During boot, Linux reports repeated messages :
[ 15.416794] __common_interrupt: 2.37 No irq handler for vector
[ 15.417266] __common_interrupt: 2.37 No irq handler for vector
[ 15.417733] __common_interrupt: 2.37 No irq handler for vector
[ 15.418202] __common_interrupt: 2.37 No irq handler for vector
[ 15.418670] __common_interrupt: 2.37 No irq handler for vector
and may eventually hang.
The issue is caused by the incorrect use of the macro
ACCEL_KERNEL_GSI_IRQFD_POSSIBLE, which should instead be
ACCEL_GSI_IRQFD_POSSIBLE.
Fixes: 638ac1c78457 ("hw/intc: Generalize APIC helper names from kvm_* to accel_*")
Cc: Magnus Kulke <magnuskulke@linux.microsoft.com>
Signed-off-by: Cédric Le Goater <clg@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Message-ID: <20251106105148.737093-1-clg@redhat.com>
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
(cherry picked from commit 3abfbb571143ba865488b6c11f8ad75dda97d1a3)
Signed-off-by: Cédric Le Goater <clg@redhat.com>
Patch-name: kvm-hw-intc-ioapic-Fix-ACCEL_KERNEL_GSI_IRQFD_POSSIBLE-t.patch
Patch-id: 100
Patch-present-in-specfile: True
---
hw/intc/ioapic.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/hw/intc/ioapic.c b/hw/intc/ioapic.c
index e431d00311..38e4384648 100644
--- a/hw/intc/ioapic.c
+++ b/hw/intc/ioapic.c
@@ -216,7 +216,7 @@ static void ioapic_update_kvm_routes(IOAPICCommonState *s)
#endif
}
-#ifdef ACCEL_KERNEL_GSI_IRQFD_POSSIBLE
+#ifdef ACCEL_GSI_IRQFD_POSSIBLE
static void ioapic_iec_notifier(void *private, bool global,
uint32_t index, uint32_t mask)
{
@@ -434,7 +434,7 @@ static const MemoryRegionOps ioapic_io_ops = {
static void ioapic_machine_done_notify(Notifier *notifier, void *data)
{
-#ifdef ACCEL_KERNEL_GSI_IRQFD_POSSIBLE
+#ifdef ACCEL_GSI_IRQFD_POSSIBLE
IOAPICCommonState *s = container_of(notifier, IOAPICCommonState,
machine_done);

View File

@ -1,44 +0,0 @@
From 273b5c9f7ae94d9fc31f1a72fc81062154d90f13 Mon Sep 17 00:00:00 2001
From: Paolo Bonzini <pbonzini@redhat.com>
Date: Fri, 18 Jul 2025 18:03:50 +0200
Subject: [PATCH] redhat: allow 5-level paging for TDX VMs
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
RH-Author: Paolo Bonzini <pbonzini@redhat.com>
RH-MergeRequest: 450: redhat: allow 5-level paging for TDX VMs
RH-Jira: RHEL-111853
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Acked-by: Daniel P. Berrangé <berrange@redhat.com>
RH-Commit: [1/1] d3ffac324cfbf79d99763b9d3d29797d883f4969 (bonzini/qemu-kvm-centos)
Without this patch, when booting a TDX guest, qemu outputs,
qemu-kvm: TDX requires guest CPU physical bits (48) to match host CPU physical bits (52)
This is due to different machine types in RHEL vs. upstream, and therefore
must be kept forever as a delta from upstream.
Resolves: https://issues.redhat.com/browse/RHEL-111853
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Patch-name: kvm-redhat-allow-5-level-paging-for-TDX-VMs.patch
Patch-id: 101
Patch-present-in-specfile: True
---
target/i386/kvm/tdx.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/target/i386/kvm/tdx.c b/target/i386/kvm/tdx.c
index dbf0fa2c91..91fe19b7d4 100644
--- a/target/i386/kvm/tdx.c
+++ b/target/i386/kvm/tdx.c
@@ -754,6 +754,7 @@ static void tdx_cpu_instance_init(X86ConfidentialGuest *cg, CPUState *cpu)
}
object_property_set_bool(OBJECT(cpu), "pmu", false, &error_abort);
+ object_property_set_int(OBJECT(cpu), "host-phys-bits-limit", 0, &error_abort);
/* invtsc is fixed1 for TD guest */
object_property_set_bool(OBJECT(cpu), "invtsc", true, &error_abort);

View File

@ -1,128 +0,0 @@
From a94d01d60347a517bc6433a1af95de5fa99b2f25 Mon Sep 17 00:00:00 2001
From: Hanna Czenczek <hreitz@redhat.com>
Date: Mon, 10 Nov 2025 16:48:37 +0100
Subject: [PATCH] =?UTF-8?q?rbd:=20Run=20co=20BH=20CB=20in=20the=20coroutin?=
=?UTF-8?q?e=E2=80=99s=20AioContext?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
RH-Author: Hanna Czenczek <hreitz@redhat.com>
RH-MergeRequest: 454: Multithreading fixes for rbd, curl, qcow2
RH-Jira: RHEL-79118
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [1/5] 6d858f7d65d6358bf7b8b58dc6e5a2ea9e8599fe (hreitz/qemu-kvm-c-9-s)
qemu_rbd_completion_cb() schedules the request completion code
(qemu_rbd_finish_bh()) to run in the BDSs AioContext, assuming that
this is the same thread in which qemu_rbd_start_co() runs.
To explain, this is how both latter functions interact:
In qemu_rbd_start_co():
while (!task.complete)
qemu_coroutine_yield();
In qemu_rbd_finish_bh():
task->complete = true;
aio_co_wake(task->co); // task->co is qemu_rbd_start_co()
For this interaction to work reliably, both must run in the same thread
so that qemu_rbd_finish_bh() can only run once the coroutine yields.
Otherwise, finish_bh() may run before start_co() checks task.complete,
which will result in the latter seeing .complete as true immediately and
skipping the yield altogether, even though finish_bh() still wakes it.
With multiqueue, the BDSs AioContext is not necessarily the thread
start_co() runs in, and so finish_bh() may be scheduled to run in a
different thread than start_co(). With the right timing, this will
cause the problems described above; waking a non-yielding coroutine is
not good, as can be reproduced by putting e.g. a usleep(100000) above
the while loop in start_co() (and using multiqueue), giving finish_bh()
a much better chance at exiting before start_co() can yield.
So instead of scheduling finish_bh() in the BDSs AioContext, schedule
finish_bh() in task->cos AioContext.
In addition, we can get rid of task.complete altogether because we will
get woken exactly once, when the task is indeed complete, no need to
check.
(We could go further and drop the BH, running aio_co_wake() directly in
qemu_rbd_completion_cb() because we are allowed to do that even if the
coroutine isnt yet yielding and were in a different thread but the
doc comment on qemu_rbd_completion_cb() says to be careful, so I decided
not to go so far here.)
Buglink: https://issues.redhat.com/browse/RHEL-67115
Reported-by: Junyao Zhao <junzhao@redhat.com>
Cc: qemu-stable@nongnu.org
Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
Message-ID: <20251110154854.151484-3-hreitz@redhat.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 89d22536d1a1715083ef8118fe7e6e9239f900c1)
Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
Patch-name: kvm-rbd-Run-co-BH-CB-in-the-coroutine-s-AioContext.patch
Patch-id: 102
Patch-present-in-specfile: True
---
block/rbd.c | 12 ++++--------
1 file changed, 4 insertions(+), 8 deletions(-)
diff --git a/block/rbd.c b/block/rbd.c
index 3611dc81cf..2a70b5a983 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -110,9 +110,7 @@ typedef struct BDRVRBDState {
} BDRVRBDState;
typedef struct RBDTask {
- BlockDriverState *bs;
Coroutine *co;
- bool complete;
int64_t ret;
} RBDTask;
@@ -1309,7 +1307,6 @@ static int qemu_rbd_resize(BlockDriverState *bs, uint64_t size)
static void qemu_rbd_finish_bh(void *opaque)
{
RBDTask *task = opaque;
- task->complete = true;
aio_co_wake(task->co);
}
@@ -1326,7 +1323,7 @@ static void qemu_rbd_completion_cb(rbd_completion_t c, RBDTask *task)
{
task->ret = rbd_aio_get_return_value(c);
rbd_aio_release(c);
- aio_bh_schedule_oneshot(bdrv_get_aio_context(task->bs),
+ aio_bh_schedule_oneshot(qemu_coroutine_get_aio_context(task->co),
qemu_rbd_finish_bh, task);
}
@@ -1338,7 +1335,7 @@ static int coroutine_fn qemu_rbd_start_co(BlockDriverState *bs,
RBDAIOCmd cmd)
{
BDRVRBDState *s = bs->opaque;
- RBDTask task = { .bs = bs, .co = qemu_coroutine_self() };
+ RBDTask task = { .co = qemu_coroutine_self() };
rbd_completion_t c;
int r;
@@ -1401,9 +1398,8 @@ static int coroutine_fn qemu_rbd_start_co(BlockDriverState *bs,
return r;
}
- while (!task.complete) {
- qemu_coroutine_yield();
- }
+ /* Expect exactly a single wake from qemu_rbd_finish_bh() */
+ qemu_coroutine_yield();
if (task.ret < 0) {
error_report("rbd request failed: cmd %d offset %" PRIu64 " bytes %"

View File

@ -1,173 +0,0 @@
From 79feeddb30fd8b6c80a458019d909c54d82c8140 Mon Sep 17 00:00:00 2001
From: Hanna Czenczek <hreitz@redhat.com>
Date: Mon, 10 Nov 2025 16:48:40 +0100
Subject: [PATCH] curl: Fix coroutine waking
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
RH-Author: Hanna Czenczek <hreitz@redhat.com>
RH-MergeRequest: 454: Multithreading fixes for rbd, curl, qcow2
RH-Jira: RHEL-79118
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [2/5] 20268ed1de88de45a7525d01dbb64899b8c4e443 (hreitz/qemu-kvm-c-9-s)
If we wake a coroutine from a different context, we must ensure that it
will yield exactly once (now or later), awaiting that wake.
curls current .ret == -EINPROGRESS loop may lead to the coroutine not
yielding if the request finishes before the loop gets run. To fix it,
we must drop the loop and yield exactly once, if we need to yield.
Finding out that latter part ("if we need to yield") makes it a bit
complicated: Requests may be served from a cache internal to the curl
block driver, or fail before being submitted. In these cases, we must
not yield. However, if we find a matching but still ongoing request in
the cache, we will have to await that, i.e. still yield.
To address this, move the yield inside of the respective functions:
- Inside of curl_find_buf() when awaiting ongoing concurrent requests,
- Inside of curl_setup_preadv() when having created a new request.
Rename curl_setup_preadv() to curl_do_preadv() to reflect this.
(Can be reproduced with multiqueue by adding a usleep(100000) before the
`while (acb.ret == -EINPROGRESS)` loop.)
Also, add a comment why aio_co_wake() is safe regardless of whether the
coroutine and curl_multi_check_completion() run in the same context.
Cc: qemu-stable@nongnu.org
Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
Message-ID: <20251110154854.151484-6-hreitz@redhat.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 53d5c7ffac7bd4e0d12174432ebb2b3e88614b15)
Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
Patch-name: kvm-curl-Fix-coroutine-waking.patch
Patch-id: 103
Patch-present-in-specfile: True
---
block/curl.c | 45 +++++++++++++++++++++++++++++++--------------
1 file changed, 31 insertions(+), 14 deletions(-)
diff --git a/block/curl.c b/block/curl.c
index 5467678024..d69bcdff79 100644
--- a/block/curl.c
+++ b/block/curl.c
@@ -262,8 +262,8 @@ read_end:
}
/* Called with s->mutex held. */
-static bool curl_find_buf(BDRVCURLState *s, uint64_t start, uint64_t len,
- CURLAIOCB *acb)
+static bool coroutine_fn
+curl_find_buf(BDRVCURLState *s, uint64_t start, uint64_t len, CURLAIOCB *acb)
{
int i;
uint64_t end = start + len;
@@ -311,6 +311,10 @@ static bool curl_find_buf(BDRVCURLState *s, uint64_t start, uint64_t len,
for (j=0; j<CURL_NUM_ACB; j++) {
if (!state->acb[j]) {
state->acb[j] = acb;
+ /* Await ongoing request */
+ qemu_mutex_unlock(&s->mutex);
+ qemu_coroutine_yield();
+ qemu_mutex_lock(&s->mutex);
return true;
}
}
@@ -382,6 +386,16 @@ static void curl_multi_check_completion(BDRVCURLState *s)
acb->ret = error ? -EIO : 0;
state->acb[i] = NULL;
qemu_mutex_unlock(&s->mutex);
+ /*
+ * Current AioContext is the BDS context, which may or may not
+ * be the request (coroutine) context.
+ * - If it is, the coroutine must have yielded or the FD handler
+ * (curl_multi_do()/curl_multi_timeout_do()) could not have
+ * been called and we would not be here
+ * - If it is not, it doesn't matter whether it has already
+ * yielded or not; it will be scheduled once it does yield
+ * So aio_co_wake() is safe to call.
+ */
aio_co_wake(acb->co);
qemu_mutex_lock(&s->mutex);
}
@@ -882,7 +896,7 @@ out_noclean:
return -EINVAL;
}
-static void coroutine_fn curl_setup_preadv(BlockDriverState *bs, CURLAIOCB *acb)
+static void coroutine_fn curl_do_preadv(BlockDriverState *bs, CURLAIOCB *acb)
{
CURLState *state;
int running;
@@ -894,10 +908,13 @@ static void coroutine_fn curl_setup_preadv(BlockDriverState *bs, CURLAIOCB *acb)
qemu_mutex_lock(&s->mutex);
- // In case we have the requested data already (e.g. read-ahead),
- // we can just call the callback and be done.
+ /*
+ * In case we have the requested data already (e.g. read-ahead),
+ * we can just call the callback and be done. This may have to
+ * await an ongoing request, in which case it itself will yield.
+ */
if (curl_find_buf(s, start, acb->bytes, acb)) {
- goto out;
+ goto dont_yield;
}
// No cache found, so let's start a new request
@@ -912,7 +929,7 @@ static void coroutine_fn curl_setup_preadv(BlockDriverState *bs, CURLAIOCB *acb)
if (curl_init_state(s, state) < 0) {
curl_clean_state(state);
acb->ret = -EIO;
- goto out;
+ goto dont_yield;
}
acb->start = 0;
@@ -927,7 +944,7 @@ static void coroutine_fn curl_setup_preadv(BlockDriverState *bs, CURLAIOCB *acb)
if (state->buf_len && state->orig_buf == NULL) {
curl_clean_state(state);
acb->ret = -ENOMEM;
- goto out;
+ goto dont_yield;
}
state->acb[0] = acb;
@@ -939,13 +956,16 @@ static void coroutine_fn curl_setup_preadv(BlockDriverState *bs, CURLAIOCB *acb)
acb->ret = -EIO;
curl_clean_state(state);
- goto out;
+ goto dont_yield;
}
/* Tell curl it needs to kick things off */
curl_multi_socket_action(s->multi, CURL_SOCKET_TIMEOUT, 0, &running);
+ qemu_mutex_unlock(&s->mutex);
+ qemu_coroutine_yield();
+ return;
-out:
+dont_yield:
qemu_mutex_unlock(&s->mutex);
}
@@ -961,10 +981,7 @@ static int coroutine_fn curl_co_preadv(BlockDriverState *bs,
.bytes = bytes
};
- curl_setup_preadv(bs, &acb);
- while (acb.ret == -EINPROGRESS) {
- qemu_coroutine_yield();
- }
+ curl_do_preadv(bs, &acb);
return acb.ret;
}

View File

@ -1,67 +0,0 @@
From 4c93e33fbe8a37a28f553241fd9b6555f8a8a13f Mon Sep 17 00:00:00 2001
From: Hanna Czenczek <hreitz@redhat.com>
Date: Mon, 10 Nov 2025 16:48:45 +0100
Subject: [PATCH] block/io: Take reqs_lock for tracked_requests
RH-Author: Hanna Czenczek <hreitz@redhat.com>
RH-MergeRequest: 454: Multithreading fixes for rbd, curl, qcow2
RH-Jira: RHEL-79118
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [3/5] 91512b6569546b6e82eca0034608fb5c7b426916 (hreitz/qemu-kvm-c-9-s)
bdrv_co_get_self_request() does not take a lock around iterating through
bs->tracked_requests. With multiqueue, it may thus iterate over a list
that is in the process of being modified, producing an assertion
failure:
../block/file-posix.c:3702: raw_do_pwrite_zeroes: Assertion `req' failed.
[0] abort() at /lib64/libc.so.6
[1] __assert_fail_base.cold() at /lib64/libc.so.6
[2] raw_do_pwrite_zeroes() at ../block/file-posix.c:3702
[3] bdrv_co_do_pwrite_zeroes() at ../block/io.c:1910
[4] bdrv_aligned_pwritev() at ../block/io.c:2109
[5] bdrv_co_do_zero_pwritev() at ../block/io.c:2192
[6] bdrv_co_pwritev_part() at ../block/io.c:2292
[7] bdrv_co_pwritev() at ../block/io.c:2225
[8] handle_alloc_space() at ../block/qcow2.c:2573
[9] qcow2_co_pwritev_task() at ../block/qcow2.c:2625
Fix this by taking reqs_lock.
Cc: qemu-stable@nongnu.org
Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
Message-ID: <20251110154854.151484-11-hreitz@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 9b9ee60c07f52009f9bb659f54c42afae95c1d94)
Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
Patch-name: kvm-block-io-Take-reqs_lock-for-tracked_requests.patch
Patch-id: 104
Patch-present-in-specfile: True
---
block/io.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/block/io.c b/block/io.c
index 9bd8ba8431..37df1e0253 100644
--- a/block/io.c
+++ b/block/io.c
@@ -721,11 +721,14 @@ BdrvTrackedRequest *coroutine_fn bdrv_co_get_self_request(BlockDriverState *bs)
Coroutine *self = qemu_coroutine_self();
IO_CODE();
+ qemu_mutex_lock(&bs->reqs_lock);
QLIST_FOREACH(req, &bs->tracked_requests, list) {
if (req->co == self) {
+ qemu_mutex_unlock(&bs->reqs_lock);
return req;
}
}
+ qemu_mutex_unlock(&bs->reqs_lock);
return NULL;
}

View File

@ -1,46 +0,0 @@
From d8abe96a07ad3150bf3d2e72bc5ba153f26d646b Mon Sep 17 00:00:00 2001
From: Hanna Czenczek <hreitz@redhat.com>
Date: Mon, 10 Nov 2025 16:48:46 +0100
Subject: [PATCH] qcow2: Re-initialize lock in invalidate_cache
RH-Author: Hanna Czenczek <hreitz@redhat.com>
RH-MergeRequest: 454: Multithreading fixes for rbd, curl, qcow2
RH-Jira: RHEL-79118
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
RH-Commit: [4/5] 48ead2f35d8558fda48a2098240c0203f4c547b0 (hreitz/qemu-kvm-c-9-s)
After clearing our state (memset()-ing it to 0), we should
re-initialize objects that need it. Specifically, that applies to
s->lock, which is originally initialized in qcow2_open().
Given qemu_co_mutex_init() is just a memset() to 0, this is functionally
a no-op, but still seems like the right thing to do.
Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
Message-ID: <20251110154854.151484-12-hreitz@redhat.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 90db3a1721b30daf839901813616c0854f383cc5)
Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
Patch-name: kvm-qcow2-Re-initialize-lock-in-invalidate_cache.patch
Patch-id: 105
Patch-present-in-specfile: True
---
block/qcow2.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/block/qcow2.c b/block/qcow2.c
index 6df65aab93..374ca53829 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -2879,6 +2879,8 @@ qcow2_co_invalidate_cache(BlockDriverState *bs, Error **errp)
data_file = s->data_file;
memset(s, 0, sizeof(BDRVQcow2State));
s->data_file = data_file;
+ /* Re-initialize objects initialized in qcow2_open() */
+ qemu_co_mutex_init(&s->lock);
options = qdict_clone_shallow(bs->options);

Some files were not shown because too many files have changed in this diff Show More