qemu-kvm/kvm-target-i386-mshv-Integrate-x86-instruction-decoder-e.patch
Miroslav Rezanina ca65b33041 * Tue Dec 09 2025 Miroslav Rezanina <mrezanin@redhat.com> - 10.1.0-8
- 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)
2025-12-09 11:43:14 +01:00

284 lines
8.8 KiB
Diff

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