* Tue Dec 09 2025 Jon Maloy <jmaloy@redhat.com> - 10.1.0-9
- kvm-pcie_sriov-make-pcie_sriov_pf_exit-safe-on-non-SR-IO.patch [RHEL-131144] - kvm-accel-Add-Meson-and-config-support-for-MSHV-accelera.patch [RHEL-132193] - kvm-target-i386-emulate-Allow-instruction-decoding-from-.patch [RHEL-132193] - kvm-target-i386-mshv-Add-x86-decoder-emu-implementation.patch [RHEL-132193] - kvm-hw-intc-Generalize-APIC-helper-names-from-kvm_-to-ac.patch [RHEL-132193] - kvm-include-hw-hyperv-Add-MSHV-ABI-header-definitions.patch [RHEL-132193] - kvm-linux-headers-linux-Add-mshv.h-headers.patch [RHEL-132193] - kvm-accel-mshv-Add-accelerator-skeleton.patch [RHEL-132193] - kvm-accel-mshv-Register-memory-region-listeners.patch [RHEL-132193] - kvm-accel-mshv-Initialize-VM-partition.patch [RHEL-132193] - kvm-accel-mshv-Add-vCPU-creation-and-execution-loop.patch [RHEL-132193] - kvm-treewide-rename-qemu_wait_io_event-qemu_wait_io_even.patch [RHEL-132193] - kvm-accel-mshv-Add-vCPU-signal-handling.patch [RHEL-132193] - kvm-target-i386-mshv-Add-CPU-create-and-remove-logic.patch [RHEL-132193] - kvm-target-i386-mshv-Implement-mshv_store_regs.patch [RHEL-132193] - kvm-target-i386-mshv-Implement-mshv_get_standard_regs.patch [RHEL-132193] - kvm-target-i386-mshv-Implement-mshv_get_special_regs.patch [RHEL-132193] - kvm-target-i386-mshv-Implement-mshv_arch_put_registers.patch [RHEL-132193] - kvm-target-i386-mshv-Set-local-interrupt-controller-stat.patch [RHEL-132193] - kvm-target-i386-mshv-Register-CPUID-entries-with-MSHV.patch [RHEL-132193] - kvm-target-i386-mshv-Register-MSRs-with-MSHV.patch [RHEL-132193] - kvm-target-i386-mshv-Integrate-x86-instruction-decoder-e.patch [RHEL-132193] - kvm-target-i386-mshv-Write-MSRs-to-the-hypervisor.patch [RHEL-132193] - kvm-target-i386-mshv-Implement-mshv_vcpu_run.patch [RHEL-132193] - kvm-accel-mshv-Handle-overlapping-mem-mappings.patch [RHEL-132193] - kvm-qapi-accel-Allow-to-query-mshv-capabilities.patch [RHEL-132193] - kvm-target-i386-mshv-Use-preallocated-page-for-hvcall.patch [RHEL-132193] - kvm-docs-Add-mshv-to-documentation.patch [RHEL-132193] - kvm-MAINTAINERS-Add-maintainers-for-mshv-accelerator.patch [RHEL-132193] - kvm-accel-mshv-initialize-thread-name.patch [RHEL-132193] - kvm-accel-mshv-use-return-value-of-handle_pio_str_read.patch [RHEL-132193] - Resolves: RHEL-131144 (qemu crash after hot-unplug disk from the multifunction enabled bus [RHEL.9.8]) - Resolves: RHEL-132193 ([rhel 9.8]L1VH qemu downstream initial merge RHEL9)
This commit is contained in:
parent
4de7fac8a3
commit
4ba0b5c287
54
kvm-MAINTAINERS-Add-maintainers-for-mshv-accelerator.patch
Normal file
54
kvm-MAINTAINERS-Add-maintainers-for-mshv-accelerator.patch
Normal file
@ -0,0 +1,54 @@
|
||||
From 0fdaad5ececfa48df564eaf8ee08fdb76a08e5c5 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 29/31] MAINTAINERS: Add maintainers for mshv accelerator
|
||||
|
||||
RH-Author: Igor Mammedov <imammedo@redhat.com>
|
||||
RH-MergeRequest: 435: x86: enablement for Azure L1VH OCP readiness
|
||||
RH-Jira: RHEL-132193
|
||||
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
|
||||
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||
RH-Commit: [28/30] 8ddf4160575605b6d6e4d8490f61dffe826d5acc
|
||||
|
||||
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>
|
||||
---
|
||||
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>
|
||||
--
|
||||
2.51.1
|
||||
|
||||
131
kvm-accel-Add-Meson-and-config-support-for-MSHV-accelera.patch
Normal file
131
kvm-accel-Add-Meson-and-config-support-for-MSHV-accelera.patch
Normal file
@ -0,0 +1,131 @@
|
||||
From 566ceb746665ec2729791f979f9a4771f299c564 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 02/31] 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: 435: x86: enablement for Azure L1VH OCP readiness
|
||||
RH-Jira: RHEL-132193
|
||||
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
|
||||
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||
RH-Commit: [1/30] f47b1d42871811bead1e3430b18694284d70a534
|
||||
|
||||
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>
|
||||
---
|
||||
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 ;;
|
||||
--
|
||||
2.51.1
|
||||
|
||||
291
kvm-accel-mshv-Add-accelerator-skeleton.patch
Normal file
291
kvm-accel-mshv-Add-accelerator-skeleton.patch
Normal file
@ -0,0 +1,291 @@
|
||||
From 185d76c5267fb97eb51df160b212cded1fb72e86 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 08/31] accel/mshv: Add accelerator skeleton
|
||||
|
||||
RH-Author: Igor Mammedov <imammedo@redhat.com>
|
||||
RH-MergeRequest: 435: x86: enablement for Azure L1VH OCP readiness
|
||||
RH-Jira: RHEL-132193
|
||||
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
|
||||
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||
RH-Commit: [7/30] 3490738c5fd68ed2d66f1ab5599252cbbc76ef5f
|
||||
|
||||
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>
|
||||
---
|
||||
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
|
||||
--
|
||||
2.51.1
|
||||
|
||||
417
kvm-accel-mshv-Add-vCPU-creation-and-execution-loop.patch
Normal file
417
kvm-accel-mshv-Add-vCPU-creation-and-execution-loop.patch
Normal file
@ -0,0 +1,417 @@
|
||||
From aa8010ec2f64396baffff491b32f31a44ca1b117 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 11/31] accel/mshv: Add vCPU creation and execution loop
|
||||
|
||||
RH-Author: Igor Mammedov <imammedo@redhat.com>
|
||||
RH-MergeRequest: 435: x86: enablement for Azure L1VH OCP readiness
|
||||
RH-Jira: RHEL-132193
|
||||
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
|
||||
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||
RH-Commit: [10/30] 91f9d846d568c41fc2b03ffa2e120034b1ab1439
|
||||
|
||||
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>
|
||||
---
|
||||
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
|
||||
--
|
||||
2.51.1
|
||||
|
||||
75
kvm-accel-mshv-Add-vCPU-signal-handling.patch
Normal file
75
kvm-accel-mshv-Add-vCPU-signal-handling.patch
Normal file
@ -0,0 +1,75 @@
|
||||
From d8f03b683f887433bccf15bf012d94e130290414 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 13/31] accel/mshv: Add vCPU signal handling
|
||||
|
||||
RH-Author: Igor Mammedov <imammedo@redhat.com>
|
||||
RH-MergeRequest: 435: x86: enablement for Azure L1VH OCP readiness
|
||||
RH-Jira: RHEL-132193
|
||||
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
|
||||
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||
RH-Commit: [12/30] 87dd1e952aae5893b29c3f74b804b2935c347001
|
||||
|
||||
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>
|
||||
---
|
||||
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);
|
||||
--
|
||||
2.51.1
|
||||
|
||||
695
kvm-accel-mshv-Handle-overlapping-mem-mappings.patch
Normal file
695
kvm-accel-mshv-Handle-overlapping-mem-mappings.patch
Normal file
@ -0,0 +1,695 @@
|
||||
From 1bbcbcfd11a90719b7a7eb25e8547b9d6d35b9f3 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 25/31] accel/mshv: Handle overlapping mem mappings
|
||||
|
||||
RH-Author: Igor Mammedov <imammedo@redhat.com>
|
||||
RH-MergeRequest: 435: x86: enablement for Azure L1VH OCP readiness
|
||||
RH-Jira: RHEL-132193
|
||||
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
|
||||
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||
RH-Commit: [24/30] 957ca3735cd46783d0ca044b37ddbfa5303158f7
|
||||
|
||||
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>
|
||||
---
|
||||
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, ®ion);
|
||||
}
|
||||
|
||||
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, ®ion);
|
||||
}
|
||||
|
||||
+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) {
|
||||
--
|
||||
2.51.1
|
||||
|
||||
1302
kvm-accel-mshv-Initialize-VM-partition.patch
Normal file
1302
kvm-accel-mshv-Initialize-VM-partition.patch
Normal file
File diff suppressed because it is too large
Load Diff
172
kvm-accel-mshv-Register-memory-region-listeners.patch
Normal file
172
kvm-accel-mshv-Register-memory-region-listeners.patch
Normal file
@ -0,0 +1,172 @@
|
||||
From bbcb9aabff22f694f88e518de0261fc28d5dc2c3 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 09/31] accel/mshv: Register memory region listeners
|
||||
|
||||
RH-Author: Igor Mammedov <imammedo@redhat.com>
|
||||
RH-MergeRequest: 435: x86: enablement for Azure L1VH OCP readiness
|
||||
RH-Jira: RHEL-132193
|
||||
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
|
||||
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||
RH-Commit: [8/30] 4b7ab25a2146d964cf526067925157c706566040
|
||||
|
||||
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>
|
||||
---
|
||||
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
|
||||
--
|
||||
2.51.1
|
||||
|
||||
39
kvm-accel-mshv-initialize-thread-name.patch
Normal file
39
kvm-accel-mshv-initialize-thread-name.patch
Normal file
@ -0,0 +1,39 @@
|
||||
From 193512539736d1cf0ef4e138b7c621a2f12ac167 Mon Sep 17 00:00:00 2001
|
||||
From: Paolo Bonzini <pbonzini@redhat.com>
|
||||
Date: Wed, 22 Oct 2025 14:52:48 +0200
|
||||
Subject: [PATCH 30/31] accel/mshv: initialize thread name
|
||||
|
||||
RH-Author: Igor Mammedov <imammedo@redhat.com>
|
||||
RH-MergeRequest: 435: x86: enablement for Azure L1VH OCP readiness
|
||||
RH-Jira: RHEL-132193
|
||||
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
|
||||
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||
RH-Commit: [29/30] 88e9d5fed01c8ab1fa4433a7b84d297b0879d20d
|
||||
|
||||
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>
|
||||
---
|
||||
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));
|
||||
|
||||
--
|
||||
2.51.1
|
||||
|
||||
42
kvm-accel-mshv-use-return-value-of-handle_pio_str_read.patch
Normal file
42
kvm-accel-mshv-use-return-value-of-handle_pio_str_read.patch
Normal file
@ -0,0 +1,42 @@
|
||||
From 3234aa5a584713cc4423bfb5215ef38d8789ff73 Mon Sep 17 00:00:00 2001
|
||||
From: Paolo Bonzini <pbonzini@redhat.com>
|
||||
Date: Wed, 22 Oct 2025 14:54:30 +0200
|
||||
Subject: [PATCH 31/31] accel/mshv: use return value of handle_pio_str_read
|
||||
|
||||
RH-Author: Igor Mammedov <imammedo@redhat.com>
|
||||
RH-MergeRequest: 435: x86: enablement for Azure L1VH OCP readiness
|
||||
RH-Jira: RHEL-132193
|
||||
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
|
||||
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||
RH-Commit: [30/30] 75d6f9f124f9e967b6a605241e1f725173bd1142
|
||||
|
||||
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>
|
||||
---
|
||||
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;
|
||||
}
|
||||
--
|
||||
2.51.1
|
||||
|
||||
143
kvm-docs-Add-mshv-to-documentation.patch
Normal file
143
kvm-docs-Add-mshv-to-documentation.patch
Normal file
@ -0,0 +1,143 @@
|
||||
From 8ff12da78a42d59fd4e3525d081634804debf008 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 28/31] docs: Add mshv to documentation
|
||||
|
||||
RH-Author: Igor Mammedov <imammedo@redhat.com>
|
||||
RH-MergeRequest: 435: x86: enablement for Azure L1VH OCP readiness
|
||||
RH-Jira: RHEL-132193
|
||||
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
|
||||
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||
RH-Commit: [27/30] 2c46c1324ab9670aa133efcb9104d744746be32b
|
||||
|
||||
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>
|
||||
---
|
||||
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 3837456a61..f802f1d6d2 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.
|
||||
|
||||
--
|
||||
2.51.1
|
||||
|
||||
386
kvm-hw-intc-Generalize-APIC-helper-names-from-kvm_-to-ac.patch
Normal file
386
kvm-hw-intc-Generalize-APIC-helper-names-from-kvm_-to-ac.patch
Normal file
@ -0,0 +1,386 @@
|
||||
From f68e2f259fc589c33e2fef16e488842824125a98 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 05/31] hw/intc: Generalize APIC helper names from kvm_* to
|
||||
accel_*
|
||||
|
||||
RH-Author: Igor Mammedov <imammedo@redhat.com>
|
||||
RH-MergeRequest: 435: x86: enablement for Azure L1VH OCP readiness
|
||||
RH-Jira: RHEL-132193
|
||||
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
|
||||
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||
RH-Commit: [4/30] dd44c736f2bef167511d2b60d456c04f12019882
|
||||
|
||||
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>
|
||||
---
|
||||
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
|
||||
--
|
||||
2.51.1
|
||||
|
||||
1264
kvm-include-hw-hyperv-Add-MSHV-ABI-header-definitions.patch
Normal file
1264
kvm-include-hw-hyperv-Add-MSHV-ABI-header-definitions.patch
Normal file
File diff suppressed because it is too large
Load Diff
329
kvm-linux-headers-linux-Add-mshv.h-headers.patch
Normal file
329
kvm-linux-headers-linux-Add-mshv.h-headers.patch
Normal file
@ -0,0 +1,329 @@
|
||||
From 9515494b6a17b26bca1451976a54b53a0524d65f 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 07/31] 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: 435: x86: enablement for Azure L1VH OCP readiness
|
||||
RH-Jira: RHEL-132193
|
||||
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
|
||||
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||
RH-Commit: [6/30] 866a40c74aede97a9b1a5ac50651eb13face82bd
|
||||
|
||||
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>
|
||||
---
|
||||
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
|
||||
--
|
||||
2.51.1
|
||||
|
||||
@ -0,0 +1,74 @@
|
||||
From 12f78b7e20b751e64a3de3e594579673956d60dc Mon Sep 17 00:00:00 2001
|
||||
From: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
Date: Wed, 24 Sep 2025 11:51:53 -0400
|
||||
Subject: [PATCH 01/31] pcie_sriov: make pcie_sriov_pf_exit() safe on
|
||||
non-SR-IOV devices
|
||||
|
||||
RH-Author: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
RH-MergeRequest: 434: pcie_sriov: make pcie_sriov_pf_exit() safe on non-SR-IOV devices
|
||||
RH-Jira: RHEL-131144
|
||||
RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
|
||||
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||
RH-Commit: [1/1] 3b9b7e7385fe8e3700865955f6c3b9a350e8a545 (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>
|
||||
---
|
||||
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));
|
||||
}
|
||||
}
|
||||
--
|
||||
2.51.1
|
||||
|
||||
169
kvm-qapi-accel-Allow-to-query-mshv-capabilities.patch
Normal file
169
kvm-qapi-accel-Allow-to-query-mshv-capabilities.patch
Normal file
@ -0,0 +1,169 @@
|
||||
From 5c048c7fe16c14e864571824fefbf5749bfed34a 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 26/31] qapi/accel: Allow to query mshv capabilities
|
||||
|
||||
RH-Author: Igor Mammedov <imammedo@redhat.com>
|
||||
RH-MergeRequest: 435: x86: enablement for Azure L1VH OCP readiness
|
||||
RH-Jira: RHEL-132193
|
||||
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
|
||||
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||
RH-Commit: [25/30] 951d3f2530367f0d95b23b712227384229161cd7
|
||||
|
||||
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>
|
||||
---
|
||||
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' }
|
||||
--
|
||||
2.51.1
|
||||
|
||||
150
kvm-target-i386-emulate-Allow-instruction-decoding-from-.patch
Normal file
150
kvm-target-i386-emulate-Allow-instruction-decoding-from-.patch
Normal file
@ -0,0 +1,150 @@
|
||||
From be2a68162ad72e30332382b5d9e46458b3ac50d3 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 03/31] target/i386/emulate: Allow instruction decoding from
|
||||
stream
|
||||
|
||||
RH-Author: Igor Mammedov <imammedo@redhat.com>
|
||||
RH-MergeRequest: 435: x86: enablement for Azure L1VH OCP readiness
|
||||
RH-Jira: RHEL-132193
|
||||
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
|
||||
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||
RH-Commit: [2/30] a2c8de87daaf40fd824b5f0e1c07f435dc5085f8
|
||||
|
||||
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>
|
||||
---
|
||||
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,
|
||||
--
|
||||
2.51.1
|
||||
|
||||
76
kvm-target-i386-mshv-Add-CPU-create-and-remove-logic.patch
Normal file
76
kvm-target-i386-mshv-Add-CPU-create-and-remove-logic.patch
Normal file
@ -0,0 +1,76 @@
|
||||
From 4fe545d2156dca3a77dad94b858314f75cf6b8c9 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 14/31] target/i386/mshv: Add CPU create and remove logic
|
||||
|
||||
RH-Author: Igor Mammedov <imammedo@redhat.com>
|
||||
RH-MergeRequest: 435: x86: enablement for Azure L1VH OCP readiness
|
||||
RH-Jira: RHEL-132193
|
||||
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
|
||||
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||
RH-Commit: [13/30] 8354d97d26446ff93646331936b6adbb0f12f293
|
||||
|
||||
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>
|
||||
---
|
||||
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)
|
||||
--
|
||||
2.51.1
|
||||
|
||||
431
kvm-target-i386-mshv-Add-x86-decoder-emu-implementation.patch
Normal file
431
kvm-target-i386-mshv-Add-x86-decoder-emu-implementation.patch
Normal file
@ -0,0 +1,431 @@
|
||||
From c44215842fbec5613df55d175ce9917a5767ca60 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 04/31] target/i386/mshv: Add x86 decoder/emu implementation
|
||||
|
||||
RH-Author: Igor Mammedov <imammedo@redhat.com>
|
||||
RH-MergeRequest: 435: x86: enablement for Azure L1VH OCP readiness
|
||||
RH-Jira: RHEL-132193
|
||||
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
|
||||
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||
RH-Commit: [3/30] 927337096abcf5f1189df70e332adc25543a8729
|
||||
|
||||
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>
|
||||
---
|
||||
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);
|
||||
+}
|
||||
--
|
||||
2.51.1
|
||||
|
||||
319
kvm-target-i386-mshv-Implement-mshv_arch_put_registers.patch
Normal file
319
kvm-target-i386-mshv-Implement-mshv_arch_put_registers.patch
Normal file
@ -0,0 +1,319 @@
|
||||
From d0c6c51df07c1e0343e700e9f5a14181b3f8f692 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 18/31] target/i386/mshv: Implement mshv_arch_put_registers()
|
||||
|
||||
RH-Author: Igor Mammedov <imammedo@redhat.com>
|
||||
RH-MergeRequest: 435: x86: enablement for Azure L1VH OCP readiness
|
||||
RH-Jira: RHEL-132193
|
||||
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
|
||||
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||
RH-Commit: [17/30] d6aa93a9e455d49b8bf2fe562e84dace2a549ebb
|
||||
|
||||
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>
|
||||
---
|
||||
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, ®s->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, ®s->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();
|
||||
}
|
||||
--
|
||||
2.51.1
|
||||
|
||||
173
kvm-target-i386-mshv-Implement-mshv_get_special_regs.patch
Normal file
173
kvm-target-i386-mshv-Implement-mshv_get_special_regs.patch
Normal file
@ -0,0 +1,173 @@
|
||||
From 07254ec97137018057b6afed344cee6347761193 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 17/31] target/i386/mshv: Implement mshv_get_special_regs()
|
||||
|
||||
RH-Author: Igor Mammedov <imammedo@redhat.com>
|
||||
RH-MergeRequest: 435: x86: enablement for Azure L1VH OCP readiness
|
||||
RH-Jira: RHEL-132193
|
||||
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
|
||||
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||
RH-Commit: [16/30] 17fff3d39ea8cdd0934bd78589b828d075d0e84e
|
||||
|
||||
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>
|
||||
---
|
||||
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;
|
||||
}
|
||||
|
||||
--
|
||||
2.51.1
|
||||
|
||||
182
kvm-target-i386-mshv-Implement-mshv_get_standard_regs.patch
Normal file
182
kvm-target-i386-mshv-Implement-mshv_get_standard_regs.patch
Normal file
@ -0,0 +1,182 @@
|
||||
From abaa75c0fcb9f2caac6a75435b44f215fdfb7f20 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 16/31] target/i386/mshv: Implement mshv_get_standard_regs()
|
||||
|
||||
RH-Author: Igor Mammedov <imammedo@redhat.com>
|
||||
RH-MergeRequest: 435: x86: enablement for Azure L1VH OCP readiness
|
||||
RH-Jira: RHEL-132193
|
||||
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
|
||||
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||
RH-Commit: [15/30] 514614ac3b954e8ced754ce2e522c4d0c11e22d8
|
||||
|
||||
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>
|
||||
---
|
||||
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)
|
||||
--
|
||||
2.51.1
|
||||
|
||||
188
kvm-target-i386-mshv-Implement-mshv_store_regs.patch
Normal file
188
kvm-target-i386-mshv-Implement-mshv_store_regs.patch
Normal file
@ -0,0 +1,188 @@
|
||||
From 0e5bbb8ec6fe3f4826bb936105158066b53a4bd3 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 15/31] target/i386/mshv: Implement mshv_store_regs()
|
||||
|
||||
RH-Author: Igor Mammedov <imammedo@redhat.com>
|
||||
RH-MergeRequest: 435: x86: enablement for Azure L1VH OCP readiness
|
||||
RH-Jira: RHEL-132193
|
||||
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
|
||||
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||
RH-Commit: [14/30] 5ec94e69cd408b47bd3f52a92a0fc671946a6f1a
|
||||
|
||||
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>
|
||||
---
|
||||
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");
|
||||
--
|
||||
2.51.1
|
||||
|
||||
489
kvm-target-i386-mshv-Implement-mshv_vcpu_run.patch
Normal file
489
kvm-target-i386-mshv-Implement-mshv_vcpu_run.patch
Normal file
@ -0,0 +1,489 @@
|
||||
From 6e98581e6fda1f3624c9542940647d3d78e970c2 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 24/31] target/i386/mshv: Implement mshv_vcpu_run()
|
||||
|
||||
RH-Author: Igor Mammedov <imammedo@redhat.com>
|
||||
RH-MergeRequest: 435: x86: enablement for Azure L1VH OCP readiness
|
||||
RH-Jira: RHEL-132193
|
||||
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
|
||||
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||
RH-Commit: [23/30] 956e2a76fee028cc4d94f061327b9b60d803866e
|
||||
|
||||
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>
|
||||
---
|
||||
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)
|
||||
--
|
||||
2.51.1
|
||||
|
||||
283
kvm-target-i386-mshv-Integrate-x86-instruction-decoder-e.patch
Normal file
283
kvm-target-i386-mshv-Integrate-x86-instruction-decoder-e.patch
Normal file
@ -0,0 +1,283 @@
|
||||
From 3728bde1fc86472ed2a9a95b3393fe86f6f1f0cb 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 22/31] target/i386/mshv: Integrate x86 instruction
|
||||
decoder/emulator
|
||||
|
||||
RH-Author: Igor Mammedov <imammedo@redhat.com>
|
||||
RH-MergeRequest: 435: x86: enablement for Azure L1VH OCP readiness
|
||||
RH-Jira: RHEL-132193
|
||||
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
|
||||
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||
RH-Commit: [21/30] 72fddb8db33c05a299d78b37fc1974eab2ff1f5f
|
||||
|
||||
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>
|
||||
---
|
||||
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, ®ion);
|
||||
}
|
||||
|
||||
+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) ∈
|
||||
+ 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)
|
||||
--
|
||||
2.51.1
|
||||
|
||||
252
kvm-target-i386-mshv-Register-CPUID-entries-with-MSHV.patch
Normal file
252
kvm-target-i386-mshv-Register-CPUID-entries-with-MSHV.patch
Normal file
@ -0,0 +1,252 @@
|
||||
From 869cabe9c6bf4cc9f77362eb8bca93ed918b8399 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 20/31] target/i386/mshv: Register CPUID entries with MSHV
|
||||
|
||||
RH-Author: Igor Mammedov <imammedo@redhat.com>
|
||||
RH-MergeRequest: 435: x86: enablement for Azure L1VH OCP readiness
|
||||
RH-Jira: RHEL-132193
|
||||
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
|
||||
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||
RH-Commit: [19/30] 3f0bb94850c8f124c84a90e0b2afe2760fc38d0a
|
||||
|
||||
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>
|
||||
---
|
||||
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)∈
|
||||
+
|
||||
+ 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");
|
||||
--
|
||||
2.51.1
|
||||
|
||||
528
kvm-target-i386-mshv-Register-MSRs-with-MSHV.patch
Normal file
528
kvm-target-i386-mshv-Register-MSRs-with-MSHV.patch
Normal file
@ -0,0 +1,528 @@
|
||||
From bb8c88f7b92e99b58db1e1f4a7c59d9cd24e3d90 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 21/31] target/i386/mshv: Register MSRs with MSHV
|
||||
|
||||
RH-Author: Igor Mammedov <imammedo@redhat.com>
|
||||
RH-MergeRequest: 435: x86: enablement for Azure L1VH OCP readiness
|
||||
RH-Jira: RHEL-132193
|
||||
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
|
||||
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||
RH-Commit: [20/30] 3c6a297eff5a862bae60febd181a8f52252b37cb
|
||||
|
||||
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>
|
||||
---
|
||||
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");
|
||||
--
|
||||
2.51.1
|
||||
|
||||
183
kvm-target-i386-mshv-Set-local-interrupt-controller-stat.patch
Normal file
183
kvm-target-i386-mshv-Set-local-interrupt-controller-stat.patch
Normal file
@ -0,0 +1,183 @@
|
||||
From ea7024c1a3846c5f6a33b60b47759c1dff355564 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 19/31] target/i386/mshv: Set local interrupt controller state
|
||||
|
||||
RH-Author: Igor Mammedov <imammedo@redhat.com>
|
||||
RH-MergeRequest: 435: x86: enablement for Azure L1VH OCP readiness
|
||||
RH-Jira: RHEL-132193
|
||||
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
|
||||
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||
RH-Commit: [18/30] 290eb63d2e8f99e5a91168b4fcd416ed8ddc9ada
|
||||
|
||||
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>
|
||||
---
|
||||
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;
|
||||
}
|
||||
|
||||
--
|
||||
2.51.1
|
||||
|
||||
193
kvm-target-i386-mshv-Use-preallocated-page-for-hvcall.patch
Normal file
193
kvm-target-i386-mshv-Use-preallocated-page-for-hvcall.patch
Normal file
@ -0,0 +1,193 @@
|
||||
From 8baf8bd7e48ed651f83da39417c55f5b0ab34d08 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 27/31] target/i386/mshv: Use preallocated page for hvcall
|
||||
|
||||
RH-Author: Igor Mammedov <imammedo@redhat.com>
|
||||
RH-MergeRequest: 435: x86: enablement for Azure L1VH OCP readiness
|
||||
RH-Jira: RHEL-132193
|
||||
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
|
||||
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||
RH-Commit: [26/30] d0c3fa02d62be1a4b15d28abd4d92b4302e30ea3
|
||||
|
||||
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>
|
||||
---
|
||||
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);
|
||||
}
|
||||
|
||||
--
|
||||
2.51.1
|
||||
|
||||
113
kvm-target-i386-mshv-Write-MSRs-to-the-hypervisor.patch
Normal file
113
kvm-target-i386-mshv-Write-MSRs-to-the-hypervisor.patch
Normal file
@ -0,0 +1,113 @@
|
||||
From 392edd1e35e63e6f92d8badfb086b656ea82593a 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 23/31] target/i386/mshv: Write MSRs to the hypervisor
|
||||
|
||||
RH-Author: Igor Mammedov <imammedo@redhat.com>
|
||||
RH-MergeRequest: 435: x86: enablement for Azure L1VH OCP readiness
|
||||
RH-Jira: RHEL-132193
|
||||
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
|
||||
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||
RH-Commit: [22/30] 341bb2428b5a41d9b5d6ebc325ba384464c7542a
|
||||
|
||||
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>
|
||||
---
|
||||
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(
|
||||
--
|
||||
2.51.1
|
||||
|
||||
219
kvm-treewide-rename-qemu_wait_io_event-qemu_wait_io_even.patch
Normal file
219
kvm-treewide-rename-qemu_wait_io_event-qemu_wait_io_even.patch
Normal file
@ -0,0 +1,219 @@
|
||||
From 48b40bd483dbafcea66f84465796bdf1eb1fc962 Mon Sep 17 00:00:00 2001
|
||||
From: Paolo Bonzini <pbonzini@redhat.com>
|
||||
Date: Tue, 2 Sep 2025 07:17:09 +0200
|
||||
Subject: [PATCH 12/31] treewide: rename
|
||||
qemu_wait_io_event/qemu_wait_io_event_common
|
||||
|
||||
RH-Author: Igor Mammedov <imammedo@redhat.com>
|
||||
RH-MergeRequest: 435: x86: enablement for Azure L1VH OCP readiness
|
||||
RH-Jira: RHEL-132193
|
||||
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
|
||||
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||
RH-Commit: [11/30] cabe3f5e84e62f47c8ff23a3bc253c2f64e05804
|
||||
|
||||
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
|
||||
---
|
||||
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);
|
||||
--
|
||||
2.51.1
|
||||
|
||||
101
qemu-kvm.spec
101
qemu-kvm.spec
@ -149,7 +149,7 @@ Obsoletes: %{name}-block-ssh <= %{epoch}:%{version} \
|
||||
Summary: QEMU is a machine emulator and virtualizer
|
||||
Name: qemu-kvm
|
||||
Version: 10.1.0
|
||||
Release: 8%{?rcrel}%{?dist}%{?cc_suffix}
|
||||
Release: 9%{?rcrel}%{?dist}%{?cc_suffix}
|
||||
# Epoch because we pushed a qemu-1.0 package. AIUI this can't ever be dropped
|
||||
# Epoch 15 used for RHEL 8
|
||||
# Epoch 17 used for RHEL 9 (due to release versioning offset in RHEL 8.5)
|
||||
@ -230,6 +230,68 @@ Patch42: kvm-Fix-the-typo-of-vfio-pci-device-s-enable-migration-o.patch
|
||||
Patch43: kvm-block-backend-Fix-race-when-resuming-queued-requests.patch
|
||||
# For RHEL-133303 - The VM hit io error when do S3-PR integration on the pass-through failover multipath device [rhel-9]
|
||||
Patch44: kvm-file-posix-Handle-suspended-dm-multipath-better-for-.patch
|
||||
# For RHEL-131144 - qemu crash after hot-unplug disk from the multifunction enabled bus [RHEL.9.8]
|
||||
Patch45: kvm-pcie_sriov-make-pcie_sriov_pf_exit-safe-on-non-SR-IO.patch
|
||||
# For RHEL-132193 - [rhel 9.8]L1VH qemu downstream initial merge RHEL9
|
||||
Patch46: kvm-accel-Add-Meson-and-config-support-for-MSHV-accelera.patch
|
||||
# For RHEL-132193 - [rhel 9.8]L1VH qemu downstream initial merge RHEL9
|
||||
Patch47: kvm-target-i386-emulate-Allow-instruction-decoding-from-.patch
|
||||
# For RHEL-132193 - [rhel 9.8]L1VH qemu downstream initial merge RHEL9
|
||||
Patch48: kvm-target-i386-mshv-Add-x86-decoder-emu-implementation.patch
|
||||
# For RHEL-132193 - [rhel 9.8]L1VH qemu downstream initial merge RHEL9
|
||||
Patch49: kvm-hw-intc-Generalize-APIC-helper-names-from-kvm_-to-ac.patch
|
||||
# For RHEL-132193 - [rhel 9.8]L1VH qemu downstream initial merge RHEL9
|
||||
Patch50: kvm-include-hw-hyperv-Add-MSHV-ABI-header-definitions.patch
|
||||
# For RHEL-132193 - [rhel 9.8]L1VH qemu downstream initial merge RHEL9
|
||||
Patch51: kvm-linux-headers-linux-Add-mshv.h-headers.patch
|
||||
# For RHEL-132193 - [rhel 9.8]L1VH qemu downstream initial merge RHEL9
|
||||
Patch52: kvm-accel-mshv-Add-accelerator-skeleton.patch
|
||||
# For RHEL-132193 - [rhel 9.8]L1VH qemu downstream initial merge RHEL9
|
||||
Patch53: kvm-accel-mshv-Register-memory-region-listeners.patch
|
||||
# For RHEL-132193 - [rhel 9.8]L1VH qemu downstream initial merge RHEL9
|
||||
Patch54: kvm-accel-mshv-Initialize-VM-partition.patch
|
||||
# For RHEL-132193 - [rhel 9.8]L1VH qemu downstream initial merge RHEL9
|
||||
Patch55: kvm-accel-mshv-Add-vCPU-creation-and-execution-loop.patch
|
||||
# For RHEL-132193 - [rhel 9.8]L1VH qemu downstream initial merge RHEL9
|
||||
Patch56: kvm-treewide-rename-qemu_wait_io_event-qemu_wait_io_even.patch
|
||||
# For RHEL-132193 - [rhel 9.8]L1VH qemu downstream initial merge RHEL9
|
||||
Patch57: kvm-accel-mshv-Add-vCPU-signal-handling.patch
|
||||
# For RHEL-132193 - [rhel 9.8]L1VH qemu downstream initial merge RHEL9
|
||||
Patch58: kvm-target-i386-mshv-Add-CPU-create-and-remove-logic.patch
|
||||
# For RHEL-132193 - [rhel 9.8]L1VH qemu downstream initial merge RHEL9
|
||||
Patch59: kvm-target-i386-mshv-Implement-mshv_store_regs.patch
|
||||
# For RHEL-132193 - [rhel 9.8]L1VH qemu downstream initial merge RHEL9
|
||||
Patch60: kvm-target-i386-mshv-Implement-mshv_get_standard_regs.patch
|
||||
# For RHEL-132193 - [rhel 9.8]L1VH qemu downstream initial merge RHEL9
|
||||
Patch61: kvm-target-i386-mshv-Implement-mshv_get_special_regs.patch
|
||||
# For RHEL-132193 - [rhel 9.8]L1VH qemu downstream initial merge RHEL9
|
||||
Patch62: kvm-target-i386-mshv-Implement-mshv_arch_put_registers.patch
|
||||
# For RHEL-132193 - [rhel 9.8]L1VH qemu downstream initial merge RHEL9
|
||||
Patch63: kvm-target-i386-mshv-Set-local-interrupt-controller-stat.patch
|
||||
# For RHEL-132193 - [rhel 9.8]L1VH qemu downstream initial merge RHEL9
|
||||
Patch64: kvm-target-i386-mshv-Register-CPUID-entries-with-MSHV.patch
|
||||
# For RHEL-132193 - [rhel 9.8]L1VH qemu downstream initial merge RHEL9
|
||||
Patch65: kvm-target-i386-mshv-Register-MSRs-with-MSHV.patch
|
||||
# For RHEL-132193 - [rhel 9.8]L1VH qemu downstream initial merge RHEL9
|
||||
Patch66: kvm-target-i386-mshv-Integrate-x86-instruction-decoder-e.patch
|
||||
# For RHEL-132193 - [rhel 9.8]L1VH qemu downstream initial merge RHEL9
|
||||
Patch67: kvm-target-i386-mshv-Write-MSRs-to-the-hypervisor.patch
|
||||
# For RHEL-132193 - [rhel 9.8]L1VH qemu downstream initial merge RHEL9
|
||||
Patch68: kvm-target-i386-mshv-Implement-mshv_vcpu_run.patch
|
||||
# For RHEL-132193 - [rhel 9.8]L1VH qemu downstream initial merge RHEL9
|
||||
Patch69: kvm-accel-mshv-Handle-overlapping-mem-mappings.patch
|
||||
# For RHEL-132193 - [rhel 9.8]L1VH qemu downstream initial merge RHEL9
|
||||
Patch70: kvm-qapi-accel-Allow-to-query-mshv-capabilities.patch
|
||||
# For RHEL-132193 - [rhel 9.8]L1VH qemu downstream initial merge RHEL9
|
||||
Patch71: kvm-target-i386-mshv-Use-preallocated-page-for-hvcall.patch
|
||||
# For RHEL-132193 - [rhel 9.8]L1VH qemu downstream initial merge RHEL9
|
||||
Patch72: kvm-docs-Add-mshv-to-documentation.patch
|
||||
# For RHEL-132193 - [rhel 9.8]L1VH qemu downstream initial merge RHEL9
|
||||
Patch73: kvm-MAINTAINERS-Add-maintainers-for-mshv-accelerator.patch
|
||||
# For RHEL-132193 - [rhel 9.8]L1VH qemu downstream initial merge RHEL9
|
||||
Patch74: kvm-accel-mshv-initialize-thread-name.patch
|
||||
# For RHEL-132193 - [rhel 9.8]L1VH qemu downstream initial merge RHEL9
|
||||
Patch75: kvm-accel-mshv-use-return-value-of-handle_pio_str_read.patch
|
||||
|
||||
|
||||
# For RHEL-11424 - [IBM 9.6 FEAT] KVM: Full boot order support - qemu part
|
||||
@ -1944,6 +2006,43 @@ useradd -r -u 107 -g qemu -G kvm -d / -s /sbin/nologin \
|
||||
%endif
|
||||
|
||||
%changelog
|
||||
* Tue Dec 09 2025 Jon Maloy <jmaloy@redhat.com> - 10.1.0-9
|
||||
- kvm-pcie_sriov-make-pcie_sriov_pf_exit-safe-on-non-SR-IO.patch [RHEL-131144]
|
||||
- kvm-accel-Add-Meson-and-config-support-for-MSHV-accelera.patch [RHEL-132193]
|
||||
- kvm-target-i386-emulate-Allow-instruction-decoding-from-.patch [RHEL-132193]
|
||||
- kvm-target-i386-mshv-Add-x86-decoder-emu-implementation.patch [RHEL-132193]
|
||||
- kvm-hw-intc-Generalize-APIC-helper-names-from-kvm_-to-ac.patch [RHEL-132193]
|
||||
- kvm-include-hw-hyperv-Add-MSHV-ABI-header-definitions.patch [RHEL-132193]
|
||||
- kvm-linux-headers-linux-Add-mshv.h-headers.patch [RHEL-132193]
|
||||
- kvm-accel-mshv-Add-accelerator-skeleton.patch [RHEL-132193]
|
||||
- kvm-accel-mshv-Register-memory-region-listeners.patch [RHEL-132193]
|
||||
- kvm-accel-mshv-Initialize-VM-partition.patch [RHEL-132193]
|
||||
- kvm-accel-mshv-Add-vCPU-creation-and-execution-loop.patch [RHEL-132193]
|
||||
- kvm-treewide-rename-qemu_wait_io_event-qemu_wait_io_even.patch [RHEL-132193]
|
||||
- kvm-accel-mshv-Add-vCPU-signal-handling.patch [RHEL-132193]
|
||||
- kvm-target-i386-mshv-Add-CPU-create-and-remove-logic.patch [RHEL-132193]
|
||||
- kvm-target-i386-mshv-Implement-mshv_store_regs.patch [RHEL-132193]
|
||||
- kvm-target-i386-mshv-Implement-mshv_get_standard_regs.patch [RHEL-132193]
|
||||
- kvm-target-i386-mshv-Implement-mshv_get_special_regs.patch [RHEL-132193]
|
||||
- kvm-target-i386-mshv-Implement-mshv_arch_put_registers.patch [RHEL-132193]
|
||||
- kvm-target-i386-mshv-Set-local-interrupt-controller-stat.patch [RHEL-132193]
|
||||
- kvm-target-i386-mshv-Register-CPUID-entries-with-MSHV.patch [RHEL-132193]
|
||||
- kvm-target-i386-mshv-Register-MSRs-with-MSHV.patch [RHEL-132193]
|
||||
- kvm-target-i386-mshv-Integrate-x86-instruction-decoder-e.patch [RHEL-132193]
|
||||
- kvm-target-i386-mshv-Write-MSRs-to-the-hypervisor.patch [RHEL-132193]
|
||||
- kvm-target-i386-mshv-Implement-mshv_vcpu_run.patch [RHEL-132193]
|
||||
- kvm-accel-mshv-Handle-overlapping-mem-mappings.patch [RHEL-132193]
|
||||
- kvm-qapi-accel-Allow-to-query-mshv-capabilities.patch [RHEL-132193]
|
||||
- kvm-target-i386-mshv-Use-preallocated-page-for-hvcall.patch [RHEL-132193]
|
||||
- kvm-docs-Add-mshv-to-documentation.patch [RHEL-132193]
|
||||
- kvm-MAINTAINERS-Add-maintainers-for-mshv-accelerator.patch [RHEL-132193]
|
||||
- kvm-accel-mshv-initialize-thread-name.patch [RHEL-132193]
|
||||
- kvm-accel-mshv-use-return-value-of-handle_pio_str_read.patch [RHEL-132193]
|
||||
- Resolves: RHEL-131144
|
||||
(qemu crash after hot-unplug disk from the multifunction enabled bus [RHEL.9.8])
|
||||
- Resolves: RHEL-132193
|
||||
([rhel 9.8]L1VH qemu downstream initial merge RHEL9)
|
||||
|
||||
* Mon Dec 08 2025 Jon Maloy <jmaloy@redhat.com> - 10.1.0-8
|
||||
- kvm-file-posix-Handle-suspended-dm-multipath-better-for-.patch [RHEL-133303]
|
||||
- Resolves: RHEL-133303
|
||||
|
||||
Loading…
Reference in New Issue
Block a user