- kvm-block-backend-Fix-race-when-resuming-queued-requests.patch [RHEL-129540] - kvm-file-posix-Handle-suspended-dm-multipath-better-for-.patch [RHEL-121543] - kvm-accel-Add-Meson-and-config-support-for-MSHV-accelera.patch [RHEL-134212] - kvm-target-i386-emulate-Allow-instruction-decoding-from-.patch [RHEL-134212] - kvm-target-i386-mshv-Add-x86-decoder-emu-implementation.patch [RHEL-134212] - kvm-hw-intc-Generalize-APIC-helper-names-from-kvm_-to-ac.patch [RHEL-134212] - kvm-include-hw-hyperv-Add-MSHV-ABI-header-definitions.patch [RHEL-134212] - kvm-linux-headers-linux-Add-mshv.h-headers.patch [RHEL-134212] - kvm-accel-mshv-Add-accelerator-skeleton.patch [RHEL-134212] - kvm-accel-mshv-Register-memory-region-listeners.patch [RHEL-134212] - kvm-accel-mshv-Initialize-VM-partition.patch [RHEL-134212] - kvm-treewide-rename-qemu_wait_io_event-qemu_wait_io_even.patch [RHEL-134212] - kvm-accel-mshv-Add-vCPU-creation-and-execution-loop.patch [RHEL-134212] - kvm-accel-mshv-Add-vCPU-signal-handling.patch [RHEL-134212] - kvm-target-i386-mshv-Add-CPU-create-and-remove-logic.patch [RHEL-134212] - kvm-target-i386-mshv-Implement-mshv_store_regs.patch [RHEL-134212] - kvm-target-i386-mshv-Implement-mshv_get_standard_regs.patch [RHEL-134212] - kvm-target-i386-mshv-Implement-mshv_get_special_regs.patch [RHEL-134212] - kvm-target-i386-mshv-Implement-mshv_arch_put_registers.patch [RHEL-134212] - kvm-target-i386-mshv-Set-local-interrupt-controller-stat.patch [RHEL-134212] - kvm-target-i386-mshv-Register-CPUID-entries-with-MSHV.patch [RHEL-134212] - kvm-target-i386-mshv-Register-MSRs-with-MSHV.patch [RHEL-134212] - kvm-target-i386-mshv-Integrate-x86-instruction-decoder-e.patch [RHEL-134212] - kvm-target-i386-mshv-Write-MSRs-to-the-hypervisor.patch [RHEL-134212] - kvm-target-i386-mshv-Implement-mshv_vcpu_run.patch [RHEL-134212] - kvm-accel-mshv-Handle-overlapping-mem-mappings.patch [RHEL-134212] - kvm-qapi-accel-Allow-to-query-mshv-capabilities.patch [RHEL-134212] - kvm-target-i386-mshv-Use-preallocated-page-for-hvcall.patch [RHEL-134212] - kvm-docs-Add-mshv-to-documentation.patch [RHEL-134212] - kvm-MAINTAINERS-Add-maintainers-for-mshv-accelerator.patch [RHEL-134212] - kvm-accel-mshv-initialize-thread-name.patch [RHEL-134212] - kvm-accel-mshv-use-return-value-of-handle_pio_str_read.patch [RHEL-134212] - Resolves: RHEL-129540 (Assertion failure on drain with iothread and I/O load) - Resolves: RHEL-121543 (The VM hit io error when do S3-PR integration on the pass-through failover multipath device) - Resolves: RHEL-134212 ([RHEL10.2] L1VH qemu downstream initial merge RHEL10.2)
418 lines
11 KiB
Diff
418 lines
11 KiB
Diff
From da65137c39b3662f0288b5149b14c82d2cfa4000 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 13/32] accel/mshv: Add vCPU creation and execution loop
|
|
|
|
RH-Author: Igor Mammedov <imammedo@redhat.com>
|
|
RH-MergeRequest: 437: el10: x86: enablement for Azure L1VH OCP readiness
|
|
RH-Jira: RHEL-134212
|
|
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
|
|
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
|
RH-Commit: [11/30] e235ebda329666192a3bf95fb4fee018f5f5f10e
|
|
|
|
Create MSHV vCPUs using MSHV_CREATE_VP and initialize their state.
|
|
Register the MSHV CPU execution loop loop with the QEMU accelerator
|
|
framework to enable guest code execution.
|
|
|
|
The target/i386 functionality is still mostly stubbed out and will be
|
|
populated in a later commit in this series.
|
|
|
|
Signed-off-by: Magnus Kulke <magnuskulke@linux.microsoft.com>
|
|
Link: https://lore.kernel.org/r/20250916164847.77883-11-magnuskulke@linux.microsoft.com
|
|
[Fix g_free/g_clear_pointer confusion; rename qemu_wait_io_event;
|
|
mshv.h/mshv_int.h split. - Paolo]
|
|
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
|
|
(cherry picked from commit 4dc5d4257259764b6fcd035870517fc4140d8962)
|
|
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
|
|
---
|
|
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.47.3
|
|
|