This change removes userland code that worked around a restriction
in the mshv driver in the 6.18 kernel: regions from userland
couldn't be mapped to multiple regions in the kernel. We maintained a
shadow mapping table in qemu and used a heuristic to swap in a requested
region in case of UNMAPPED_GPA exits.
However, this heuristic wasn't reliable in all cases, since HyperV
behaviour is not 100% reliable across versions. HyperV itself doesn't
prohibit to map regions at multiple places into the guest, so the
restriction has been removed in the mshv driver.
Hence we can remove the remapping code. Effectively this will mandate a
6.19 kernel, if the workload attempt to map e.g. BIOS to multiple
reagions. I still think it's the right call to remove this logic:
- The workaround only seems to work reliably with a certain revision
of HyperV as a nested hypervisor.
- We expect Direct Virtualization (L1VH) to be the main platform for
the mshv accelerator, which also requires a 6.19 kernel
This reverts commit efc4093358.
Signed-off-by: Magnus Kulke <magnuskulke@linux.microsoft.com>
Acked-by: Wei Liu (Microsoft) <wei.liu@kernel.org>
Tested-by: Mohamed Mediouni <mohamed@unpredictable.fr>
Link: https://lore.kernel.org/r/20260113153708.448968-1-magnuskulke@linux.microsoft.com
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
138 lines
3.5 KiB
C
138 lines
3.5 KiB
C
/*
|
|
* 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
|
|
|
|
#define MSHV_MSR_ENTRIES_COUNT 64
|
|
|
|
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 {
|
|
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;
|
|
int fd;
|
|
};
|
|
|
|
typedef struct MshvMsiControl {
|
|
bool updated;
|
|
GHashTable *gsi_routes;
|
|
} 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,
|
|
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_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);
|
|
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);
|
|
void mshv_arch_amend_proc_features(
|
|
union hv_partition_synthetic_processor_features *features);
|
|
int mshv_arch_post_init_vm(int vm_fd);
|
|
|
|
#if defined COMPILING_PER_TARGET && defined CONFIG_MSHV_IS_POSSIBLE
|
|
int mshv_hvcall(int fd, const struct mshv_root_hvcall *args);
|
|
#endif
|
|
|
|
/* memory */
|
|
typedef struct MshvMemoryRegion {
|
|
uint64_t guest_phys_addr;
|
|
uint64_t memory_size;
|
|
uint64_t userspace_addr;
|
|
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);
|
|
|
|
/* 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);
|
|
|
|
#endif
|