Merge tag 'for-upstream' of https://gitlab.com/bonzini/qemu into staging

* i386: fix migration issues in 10.1
* target/i386/mshv: new accelerator
* rust: use glib-sys-rs
* rust: fixes for docker tests

# -----BEGIN PGP SIGNATURE-----
#
# iQFIBAABCgAyFiEE8TM4V0tmI4mGbHaCv/vSX3jHroMFAmjnaOwUHHBib256aW5p
# QHJlZGhhdC5jb20ACgkQv/vSX3jHroNsFQf/WXKxZLLnItHwDz3UdwjzewPWpz5N
# fpS0E4C03J8pACDgyfl7PQl47P7NlJ08Ig2Lc5l3Z9KiAKgh0orR7Cqd0BY5f9lo
# uk4FgXfXpQyApywAlctadrTfcH8sRv2tMaP6EJ9coLtJtHW9RUGFPaZeMsqrjpAl
# TpwAXPYNDDvvy1ih1LPh5DzOPDXE4pin2tDa94gJei56gY95auK4zppoNYLdB3kR
# GOyR4QK43/yhuxPHOmQCZOE3HK2XrKgMZHWIjAovjZjZFiJs49FaHBOpRfFpsUlG
# PB3UbIMtu69VY20LqbbyInPnyATRQzqIGnDGTErP6lfCGTKTy2ulQYWvHA==
# =KM5O
# -----END PGP SIGNATURE-----
# gpg: Signature made Thu 09 Oct 2025 12:49:00 AM PDT
# gpg:                using RSA key F13338574B662389866C7682BFFBD25F78C7AE83
# gpg:                issuer "pbonzini@redhat.com"
# gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" [unknown]
# gpg:                 aka "Paolo Bonzini <pbonzini@redhat.com>" [unknown]
# gpg: WARNING: The key's User ID is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: 46F5 9FBD 57D6 12E7 BFD4  E2F7 7E15 100C CD36 69B1
#      Subkey fingerprint: F133 3857 4B66 2389 866C  7682 BFFB D25F 78C7 AE83

* tag 'for-upstream' of https://gitlab.com/bonzini/qemu: (35 commits)
  rust: fix path to rust_root_crate.sh
  tests/docker: make --enable-rust overridable with EXTRA_CONFIGURE_OPTS
  MAINTAINERS: Add maintainers for mshv accelerator
  docs: Add mshv to documentation
  target/i386/mshv: Use preallocated page for hvcall
  qapi/accel: Allow to query mshv capabilities
  accel/mshv: Handle overlapping mem mappings
  target/i386/mshv: Implement mshv_vcpu_run()
  target/i386/mshv: Write MSRs to the hypervisor
  target/i386/mshv: Integrate x86 instruction decoder/emulator
  target/i386/mshv: Register MSRs with MSHV
  target/i386/mshv: Register CPUID entries with MSHV
  target/i386/mshv: Set local interrupt controller state
  target/i386/mshv: Implement mshv_arch_put_registers()
  target/i386/mshv: Implement mshv_get_special_regs()
  target/i386/mshv: Implement mshv_get_standard_regs()
  target/i386/mshv: Implement mshv_store_regs()
  target/i386/mshv: Add CPU create and remove logic
  accel/mshv: Add vCPU signal handling
  accel/mshv: Add vCPU creation and execution loop
  ...

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson
2025-10-09 07:59:01 -07:00
87 changed files with 6617 additions and 79 deletions
+15
View File
@@ -551,6 +551,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>
+3
View File
@@ -13,6 +13,9 @@ config TCG
config KVM
bool
config MSHV
bool
config XEN
bool
select FSDEV_9P if VIRTFS
+106
View File
@@ -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;
}
+2 -1
View File
@@ -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')
@@ -10,6 +10,7 @@ if have_system
subdir('kvm')
subdir('xen')
subdir('stubs')
subdir('mshv')
endif
# qtest
+399
View File
@@ -0,0 +1,399 @@
/*
* QEMU MSHV support
*
* Copyright Microsoft, Corp. 2025
*
* Authors: Ziqiao Zhou <ziqiaozhou@microsoft.com>
* Magnus Kulke <magnuskulke@microsoft.com>
* Stanislav Kinsburskii <skinsburskii@microsoft.com>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "linux/mshv.h"
#include "qemu/osdep.h"
#include "qemu/error-report.h"
#include "hw/hyperv/hvhdk_mini.h"
#include "hw/hyperv/hvgdk_mini.h"
#include "hw/intc/ioapic.h"
#include "hw/pci/msi.h"
#include "system/mshv.h"
#include "system/mshv_int.h"
#include "trace.h"
#include <stdint.h>
#include <sys/ioctl.h>
#define MSHV_IRQFD_RESAMPLE_FLAG (1 << MSHV_IRQFD_BIT_RESAMPLE)
#define MSHV_IRQFD_BIT_DEASSIGN_FLAG (1 << MSHV_IRQFD_BIT_DEASSIGN)
static MshvMsiControl *msi_control;
static QemuMutex msi_control_mutex;
void mshv_init_msicontrol(void)
{
qemu_mutex_init(&msi_control_mutex);
msi_control = g_new0(MshvMsiControl, 1);
msi_control->gsi_routes = g_hash_table_new(g_direct_hash, g_direct_equal);
msi_control->updated = false;
}
static int set_msi_routing(uint32_t gsi, uint64_t addr, uint32_t data)
{
struct mshv_user_irq_entry *entry;
uint32_t high_addr = addr >> 32;
uint32_t low_addr = addr & 0xFFFFFFFF;
GHashTable *gsi_routes;
trace_mshv_set_msi_routing(gsi, addr, data);
if (gsi >= MSHV_MAX_MSI_ROUTES) {
error_report("gsi >= MSHV_MAX_MSI_ROUTES");
return -1;
}
assert(msi_control);
WITH_QEMU_LOCK_GUARD(&msi_control_mutex) {
gsi_routes = msi_control->gsi_routes;
entry = g_hash_table_lookup(gsi_routes, GINT_TO_POINTER(gsi));
if (entry
&& entry->address_hi == high_addr
&& entry->address_lo == low_addr
&& entry->data == data)
{
/* nothing to update */
return 0;
}
/* free old entry */
g_free(entry);
/* create new entry */
entry = g_new0(struct mshv_user_irq_entry, 1);
entry->gsi = gsi;
entry->address_hi = high_addr;
entry->address_lo = low_addr;
entry->data = data;
g_hash_table_insert(gsi_routes, GINT_TO_POINTER(gsi), entry);
msi_control->updated = true;
}
return 0;
}
static int add_msi_routing(uint64_t addr, uint32_t data)
{
struct mshv_user_irq_entry *route_entry;
uint32_t high_addr = addr >> 32;
uint32_t low_addr = addr & 0xFFFFFFFF;
int gsi;
GHashTable *gsi_routes;
trace_mshv_add_msi_routing(addr, data);
assert(msi_control);
WITH_QEMU_LOCK_GUARD(&msi_control_mutex) {
/* find an empty slot */
gsi = 0;
gsi_routes = msi_control->gsi_routes;
while (gsi < MSHV_MAX_MSI_ROUTES) {
route_entry = g_hash_table_lookup(gsi_routes, GINT_TO_POINTER(gsi));
if (!route_entry) {
break;
}
gsi++;
}
if (gsi >= MSHV_MAX_MSI_ROUTES) {
error_report("No empty gsi slot available");
return -1;
}
/* create new entry */
route_entry = g_new0(struct mshv_user_irq_entry, 1);
route_entry->gsi = gsi;
route_entry->address_hi = high_addr;
route_entry->address_lo = low_addr;
route_entry->data = data;
g_hash_table_insert(gsi_routes, GINT_TO_POINTER(gsi), route_entry);
msi_control->updated = true;
}
return gsi;
}
static int commit_msi_routing_table(int vm_fd)
{
guint len;
int i, ret;
size_t table_size;
struct mshv_user_irq_table *table;
GHashTableIter iter;
gpointer key, value;
assert(msi_control);
WITH_QEMU_LOCK_GUARD(&msi_control_mutex) {
if (!msi_control->updated) {
/* nothing to update */
return 0;
}
/* Calculate the size of the table */
len = g_hash_table_size(msi_control->gsi_routes);
table_size = sizeof(struct mshv_user_irq_table)
+ len * sizeof(struct mshv_user_irq_entry);
table = g_malloc0(table_size);
g_hash_table_iter_init(&iter, msi_control->gsi_routes);
i = 0;
while (g_hash_table_iter_next(&iter, &key, &value)) {
struct mshv_user_irq_entry *entry = value;
table->entries[i] = *entry;
i++;
}
table->nr = i;
trace_mshv_commit_msi_routing_table(vm_fd, len);
ret = ioctl(vm_fd, MSHV_SET_MSI_ROUTING, table);
g_free(table);
if (ret < 0) {
error_report("Failed to commit msi routing table");
return -1;
}
msi_control->updated = false;
}
return 0;
}
static int remove_msi_routing(uint32_t gsi)
{
struct mshv_user_irq_entry *route_entry;
GHashTable *gsi_routes;
trace_mshv_remove_msi_routing(gsi);
if (gsi >= MSHV_MAX_MSI_ROUTES) {
error_report("Invalid GSI: %u", gsi);
return -1;
}
assert(msi_control);
WITH_QEMU_LOCK_GUARD(&msi_control_mutex) {
gsi_routes = msi_control->gsi_routes;
route_entry = g_hash_table_lookup(gsi_routes, GINT_TO_POINTER(gsi));
if (route_entry) {
g_hash_table_remove(gsi_routes, GINT_TO_POINTER(gsi));
g_free(route_entry);
msi_control->updated = true;
}
}
return 0;
}
/* Pass an eventfd which is to be used for injecting interrupts from userland */
static int irqfd(int vm_fd, int fd, int resample_fd, uint32_t gsi,
uint32_t flags)
{
int ret;
struct mshv_user_irqfd arg = {
.fd = fd,
.resamplefd = resample_fd,
.gsi = gsi,
.flags = flags,
};
ret = ioctl(vm_fd, MSHV_IRQFD, &arg);
if (ret < 0) {
error_report("Failed to set irqfd: gsi=%u, fd=%d", gsi, fd);
return -1;
}
return ret;
}
static int register_irqfd(int vm_fd, int event_fd, uint32_t gsi)
{
int ret;
trace_mshv_register_irqfd(vm_fd, event_fd, gsi);
ret = irqfd(vm_fd, event_fd, 0, gsi, 0);
if (ret < 0) {
error_report("Failed to register irqfd: gsi=%u", gsi);
return -1;
}
return 0;
}
static int register_irqfd_with_resample(int vm_fd, int event_fd,
int resample_fd, uint32_t gsi)
{
int ret;
uint32_t flags = MSHV_IRQFD_RESAMPLE_FLAG;
ret = irqfd(vm_fd, event_fd, resample_fd, gsi, flags);
if (ret < 0) {
error_report("Failed to register irqfd with resample: gsi=%u", gsi);
return -errno;
}
return 0;
}
static int unregister_irqfd(int vm_fd, int event_fd, uint32_t gsi)
{
int ret;
uint32_t flags = MSHV_IRQFD_BIT_DEASSIGN_FLAG;
ret = irqfd(vm_fd, event_fd, 0, gsi, flags);
if (ret < 0) {
error_report("Failed to unregister irqfd: gsi=%u", gsi);
return -errno;
}
return 0;
}
static int irqchip_update_irqfd_notifier_gsi(const EventNotifier *event,
const EventNotifier *resample,
int virq, bool add)
{
int fd = event_notifier_get_fd(event);
int rfd = resample ? event_notifier_get_fd(resample) : -1;
int vm_fd = mshv_state->vm;
trace_mshv_irqchip_update_irqfd_notifier_gsi(fd, rfd, virq, add);
if (!add) {
return unregister_irqfd(vm_fd, fd, virq);
}
if (rfd > 0) {
return register_irqfd_with_resample(vm_fd, fd, rfd, virq);
}
return register_irqfd(vm_fd, fd, virq);
}
int mshv_irqchip_add_msi_route(int vector, PCIDevice *dev)
{
MSIMessage msg = { 0, 0 };
int virq = 0;
if (pci_available && dev) {
msg = pci_get_msi_message(dev, vector);
virq = add_msi_routing(msg.address, le32_to_cpu(msg.data));
}
return virq;
}
void mshv_irqchip_release_virq(int virq)
{
remove_msi_routing(virq);
}
int mshv_irqchip_update_msi_route(int virq, MSIMessage msg, PCIDevice *dev)
{
int ret;
ret = set_msi_routing(virq, msg.address, le32_to_cpu(msg.data));
if (ret < 0) {
error_report("Failed to set msi routing");
return -1;
}
return 0;
}
int mshv_request_interrupt(MshvState *mshv_state, uint32_t interrupt_type, uint32_t vector,
uint32_t vp_index, bool logical_dest_mode,
bool level_triggered)
{
int ret;
int vm_fd = mshv_state->vm;
if (vector == 0) {
warn_report("Ignoring request for interrupt vector 0");
return 0;
}
union hv_interrupt_control control = {
.interrupt_type = interrupt_type,
.level_triggered = level_triggered,
.logical_dest_mode = logical_dest_mode,
.rsvd = 0,
};
struct hv_input_assert_virtual_interrupt arg = {0};
arg.control = control;
arg.dest_addr = (uint64_t)vp_index;
arg.vector = vector;
struct mshv_root_hvcall args = {0};
args.code = HVCALL_ASSERT_VIRTUAL_INTERRUPT;
args.in_sz = sizeof(arg);
args.in_ptr = (uint64_t)&arg;
ret = mshv_hvcall(vm_fd, &args);
if (ret < 0) {
error_report("Failed to request interrupt");
return -errno;
}
return 0;
}
void mshv_irqchip_commit_routes(void)
{
int ret;
int vm_fd = mshv_state->vm;
ret = commit_msi_routing_table(vm_fd);
if (ret < 0) {
error_report("Failed to commit msi routing table");
abort();
}
}
int mshv_irqchip_add_irqfd_notifier_gsi(const EventNotifier *event,
const EventNotifier *resample,
int virq)
{
return irqchip_update_irqfd_notifier_gsi(event, resample, virq, true);
}
int mshv_irqchip_remove_irqfd_notifier_gsi(const EventNotifier *event,
int virq)
{
return irqchip_update_irqfd_notifier_gsi(event, NULL, virq, false);
}
int mshv_reserve_ioapic_msi_routes(int vm_fd)
{
int ret, gsi;
/*
* Reserve GSI 0-23 for IOAPIC pins, to avoid conflicts of legacy
* peripherals with MSI-X devices
*/
for (gsi = 0; gsi < IOAPIC_NUM_PINS; gsi++) {
ret = add_msi_routing(0, 0);
if (ret < 0) {
error_report("Failed to reserve GSI %d", gsi);
return -1;
}
}
ret = commit_msi_routing_table(vm_fd);
if (ret < 0) {
error_report("Failed to commit reserved IOAPIC MSI routes");
return -1;
}
return 0;
}
+563
View File
File diff suppressed because it is too large Load Diff
+9
View File
@@ -0,0 +1,9 @@
mshv_ss = ss.source_set()
mshv_ss.add(if_true: files(
'irq.c',
'mem.c',
'msr.c',
'mshv-all.c'
))
specific_ss.add_all(when: 'CONFIG_MSHV', if_true: mshv_ss)
File diff suppressed because it is too large Load Diff
+375
View File
@@ -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;
}
+33
View File
@@ -0,0 +1,33 @@
# Authors: Ziqiao Zhou <ziqiaozhou@microsoft.com>
# Magnus Kulke <magnuskulke@microsoft.com>
#
# 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"
mshv_hvcall_args(const char* hvcall, uint16_t code, uint16_t in_sz) "built args for '%s' code: %d in_sz: %d"
mshv_handle_interrupt(uint32_t cpu, int mask) "cpu_index=%d mask=0x%x"
mshv_set_msi_routing(uint32_t gsi, uint64_t addr, uint32_t data) "gsi=%d addr=0x%" PRIx64 " data=0x%x"
mshv_remove_msi_routing(uint32_t gsi) "gsi=%d"
mshv_add_msi_routing(uint64_t addr, uint32_t data) "addr=0x%" PRIx64 " data=0x%x"
mshv_commit_msi_routing_table(int vm_fd, int len) "vm_fd=%d table_size=%d"
mshv_register_irqfd(int vm_fd, int event_fd, uint32_t gsi) "vm_fd=%d event_fd=%d gsi=%d"
mshv_irqchip_update_irqfd_notifier_gsi(int event_fd, int resample_fd, int virq, bool add) "event_fd=%d resample_fd=%d virq=%d add=%d"
mshv_insn_fetch(uint64_t addr, size_t size) "gpa=0x%" PRIx64 " size=%zu"
mshv_mem_write(uint64_t addr, size_t size) "\tgpa=0x%" PRIx64 " size=%zu"
mshv_mem_read(uint64_t addr, size_t size) "\tgpa=0x%" PRIx64 " size=%zu"
mshv_map_memory(uint64_t userspace_addr, uint64_t gpa, uint64_t size) "\tu_a=0x%" PRIx64 " gpa=0x%010" PRIx64 " size=0x%08" PRIx64
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
+14
View File
@@ -0,0 +1,14 @@
/*
* QEMU MSHV support
*
* Copyright Microsoft, Corp. 2025
*
* Authors:
* Ziqiao Zhou <ziqiaozhou@microsoft.com>
* Magnus Kulke <magnuskulke@microsoft.com>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*
*/
#include "trace/trace-accel_mshv.h"
+1
View File
@@ -5,5 +5,6 @@ system_stubs_ss.add(when: 'CONFIG_TCG', if_false: files('tcg-stub.c'))
system_stubs_ss.add(when: 'CONFIG_HVF', if_false: files('hvf-stub.c'))
system_stubs_ss.add(when: 'CONFIG_NVMM', if_false: files('nvmm-stub.c'))
system_stubs_ss.add(when: 'CONFIG_WHPX', if_false: files('whpx-stub.c'))
system_stubs_ss.add(when: 'CONFIG_MSHV', if_false: files('mshv-stub.c'))
specific_ss.add_all(when: ['CONFIG_SYSTEM_ONLY'], if_true: system_stubs_ss)
+44
View File
@@ -0,0 +1,44 @@
/*
* QEMU MSHV stub
*
* Copyright Red Hat, Inc. 2025
*
* Author: Paolo Bonzini <pbonzini@redhat.com>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
#include "hw/pci/msi.h"
#include "system/mshv.h"
bool mshv_allowed;
int mshv_irqchip_add_msi_route(int vector, PCIDevice *dev)
{
return -ENOSYS;
}
void mshv_irqchip_release_virq(int virq)
{
}
int mshv_irqchip_update_msi_route(int virq, MSIMessage msg, PCIDevice *dev)
{
return -ENOSYS;
}
void mshv_irqchip_commit_routes(void)
{
}
int mshv_irqchip_add_irqfd_notifier_gsi(const EventNotifier *n,
const EventNotifier *rn, int virq)
{
return -ENOSYS;
}
int mshv_irqchip_remove_irqfd_notifier_gsi(const EventNotifier *n, int virq)
{
return -ENOSYS;
}
Vendored
+7 -6
View File
@@ -1216,8 +1216,9 @@ fi
if test "$rust" != disabled && test -z "$rust_target_triple"; then
# arch and os generally matches between meson and rust
rust_arch=$host_arch
# default to host vendor
rust_vendor=$(echo "$rust_host_triple" | cut -d'-' -f2)
rust_os=$host_os
rust_machine=unknown
rust_osvariant=
# tweak rust_os if needed; also, machine and variant depend on the OS
@@ -1225,7 +1226,7 @@ if test "$rust" != disabled && test -z "$rust_target_triple"; then
case "$host_os" in
darwin)
# e.g. aarch64-apple-darwin
rust_machine=apple
rust_vendor=apple
;;
linux)
@@ -1273,13 +1274,13 @@ EOF
;;
sunos)
rust_machine=pc
rust_vendor=pc
rust_os=solaris
;;
windows)
# e.g. aarch64-pc-windows-gnullvm, x86_64-pc-windows-gnu (MSVC not supported)
rust_machine=pc
rust_vendor=pc
if test "$host_arch" = aarch64; then
rust_osvariant=gnullvm
else
@@ -1310,7 +1311,7 @@ EOF
sparc64)
if test "$rust_os" = solaris; then
rust_arch=sparcv9
rust_machine=sun
rust_vendor=sun
fi
;;
@@ -1324,7 +1325,7 @@ EOF
# e.g. aarch64-linux-android
rust_target_triple=$rust_arch-$rust_os-$rust_osvariant
else
rust_target_triple=$rust_arch-$rust_machine-$rust_os${rust_osvariant:+-$rust_osvariant}
rust_target_triple=$rust_arch-$rust_vendor-$rust_os${rust_osvariant:+-$rust_osvariant}
fi
fi
+1 -1
View File
@@ -53,7 +53,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
+1 -1
View File
@@ -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>`_:
+3 -4
View File
@@ -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:
+3
View File
@@ -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)
+13
View File
@@ -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 = "",
+15
View File
@@ -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;

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