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

* target/i386/mshv: CPU model support
* target/i386/mshv: first part of migration support
* target/i386/mshv: faster register access for MMIO exits
* target/i386/tdx: add support for AMX alias bits in CPUID and AVX10
* Deprecate memory-encryption in favor of confidential-guest-support

# -----BEGIN PGP SIGNATURE-----
#
# iQFIBAABCgAyFiEE8TM4V0tmI4mGbHaCv/vSX3jHroMFAmo9sDwUHHBib256aW5p
# QHJlZGhhdC5jb20ACgkQv/vSX3jHroOHBwf8Dx4gkbzOFxmCNX3EaW+ROYwlyAC7
# ADo9LFloDHXforRYTm4mBXNUVNF1/KFA6Tf92rzBlUZgp9KuMy/KhWZ1GbNsE+9b
# k5/1RF9/IxRHy6GL69apdHEKY2OYzXl76or2HF3wMd6Mu77qD8Onthko81VaLWox
# 5ZOBz6NaSnykzs9RimkVLtD9HswtFile2NWTPSliUV874lEJioNi9RcdhnQvJCnX
# WqGWViC0THucIGCm+NVhSEmvRnAFbPgUBPvQuy7skLu+R7Ryy7GAWmE/gFlSrYy2
# 4c4zt4SB0tFYJlT9db5ZdaUSgCs52CFawQ9uTSEjNSmEEuQFzXGo6BeY4w==
# =4V0w
# -----END PGP SIGNATURE-----
# gpg: Signature made Thu 25 Jun 2026 18:48:28 EDT
# gpg:                using RSA key F13338574B662389866C7682BFFBD25F78C7AE83
# gpg:                issuer "pbonzini@redhat.com"
# gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" [full]
# gpg:                 aka "Paolo Bonzini <pbonzini@redhat.com>" [full]
# 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: (45 commits)
  i386/tdx: Add CPUID_24_0_EBX_AVX10_VL_MASK as supported
  i386/tdx: Make AMX alias bits supported
  i386/tdx: Use .has_gpa field to check if the gpa is valid
  machine: Deprecate memory-encryption
  qemu-options: Add description of tdx-guest object
  qemu-options: Add confidential-guest-support to machine options
  qemu-options: Change memory-encryption to confidential-guest-support in the example
  i386/sev: Remove the example that references memory-encryption
  target/i386/mshv: use the register page to set registers
  target/i386/mshv: use the register page to get registers
  target/i386/mshv: hv_vp_register_page setup for the vcpu
  include/hw/hyperv: add hv_vp_register_page struct definition
  accel: remove unnecessary #ifdefs
  target/i386/mshv: migrate CET/SS MSRs
  target/i386/mshv: migrate MTRR MSRs
  target/i386/mshv: migrate MSRs
  target/i386/mshv: reconstruct hflags after load
  target/i386/mshv: migrate XSAVE state
  target/i386/mshv: migrate pending ints/excs
  target/i386/mshv: move msr code to arch
  ...

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
Stefan Hajnoczi
2026-06-27 23:06:04 -04:00
32 changed files with 2353 additions and 997 deletions

View File

@@ -10,19 +10,18 @@
*/
#include "qemu/osdep.h"
#include "qemu/error-report.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)
int accel_irqchip_add_msi_route(AccelRouteChange *c, int vector, PCIDevice *dev)
{
#ifdef CONFIG_MSHV_IS_POSSIBLE
if (mshv_msi_via_irqfd_enabled()) {
return mshv_irqchip_add_msi_route(vector, dev);
return mshv_irqchip_add_msi_route(c, vector, dev);
}
#endif
if (kvm_enabled()) {
return kvm_irqchip_add_msi_route(c, vector, dev);
}
@@ -31,36 +30,28 @@ int accel_irqchip_add_msi_route(KVMRouteChange *c, int vector, PCIDevice *dev)
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)
void accel_irqchip_commit_route_changes(AccelRouteChange *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);
if (c->changes) {
accel_irqchip_commit_routes();
c->changes = 0;
}
}
void accel_irqchip_commit_routes(void)
{
#ifdef CONFIG_MSHV_IS_POSSIBLE
if (mshv_msi_via_irqfd_enabled()) {
mshv_irqchip_commit_routes();
mshv_irqchip_commit_routes(mshv_state);
}
#endif
if (kvm_enabled()) {
kvm_irqchip_commit_routes(kvm_state);
}
@@ -68,11 +59,9 @@ void accel_irqchip_commit_routes(void)
void accel_irqchip_release_virq(int virq)
{
#ifdef CONFIG_MSHV_IS_POSSIBLE
if (mshv_msi_via_irqfd_enabled()) {
mshv_irqchip_release_virq(virq);
mshv_irqchip_release_virq(mshv_state, virq);
}
#endif
if (kvm_enabled()) {
kvm_irqchip_release_virq(kvm_state, virq);
}
@@ -81,11 +70,9 @@ void accel_irqchip_release_virq(int 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);
}
@@ -94,13 +81,29 @@ int accel_irqchip_add_irqfd_notifier_gsi(EventNotifier *n, EventNotifier *rn,
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;
}
inline AccelRouteChange accel_irqchip_begin_route_changes(void)
{
if (mshv_msi_via_irqfd_enabled()) {
return (AccelRouteChange) {
.accel = ACCEL(mshv_state),
.changes = 0,
};
}
if (kvm_enabled()) {
return (AccelRouteChange) {
.accel = ACCEL(kvm_state),
.changes = 0,
};
}
error_report("can't initiate route change, no accel irqchip available");
abort();
}

View File

@@ -2359,11 +2359,11 @@ int kvm_irqchip_send_msi(KVMState *s, MSIMessage msg)
return kvm_vm_ioctl(s, KVM_SIGNAL_MSI, &msi);
}
int kvm_irqchip_add_msi_route(KVMRouteChange *c, int vector, PCIDevice *dev)
int kvm_irqchip_add_msi_route(AccelRouteChange *c, int vector, PCIDevice *dev)
{
struct kvm_irq_routing_entry kroute = {};
int virq;
KVMState *s = c->s;
KVMState *s = KVM_STATE(c->accel);
MSIMessage msg = {0, 0};
if (pci_available && dev) {
@@ -2506,7 +2506,7 @@ int kvm_irqchip_send_msi(KVMState *s, MSIMessage msg)
abort();
}
int kvm_irqchip_add_msi_route(KVMRouteChange *c, int vector, PCIDevice *dev)
int kvm_irqchip_add_msi_route(AccelRouteChange *c, int vector, PCIDevice *dev)
{
return -ENOSYS;
}

View File

@@ -25,177 +25,6 @@
#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)
@@ -278,35 +107,155 @@ static int irqchip_update_irqfd_notifier_gsi(const EventNotifier *event,
return register_irqfd(vm_fd, fd, virq);
}
int mshv_irqchip_add_msi_route(int vector, PCIDevice *dev)
static int irqchip_allocate_gsi(MshvState *s, int *gsi)
{
MSIMessage msg = { 0, 0 };
int virq = 0;
int next_gsi;
if (pci_available && dev) {
msg = pci_get_msi_message(dev, vector);
virq = add_msi_routing(msg.address, le32_to_cpu(msg.data));
/* Return the lowest unused GSI in the bitmap */
next_gsi = find_first_zero_bit(s->used_gsi_bitmap, s->gsi_count);
if (next_gsi >= s->gsi_count) {
return -ENOSPC;
}
return virq;
*gsi = next_gsi;
return 0;
}
void mshv_irqchip_release_virq(int virq)
static void irqchip_release_gsi(MshvState *s, int gsi)
{
remove_msi_routing(virq);
clear_bit(gsi, s->used_gsi_bitmap);
}
static void add_routing_entry(MshvState *s, struct mshv_user_irq_entry *entry)
{
struct mshv_user_irq_entry *new;
int n, size;
if (s->irq_routes->nr == s->nr_allocated_irq_routes) {
n = s->nr_allocated_irq_routes * 2;
if (n < MSHV_MIN_ALLOCATED_MSI_ROUTES) {
n = MSHV_MIN_ALLOCATED_MSI_ROUTES;
}
size = sizeof(struct mshv_user_irq_table);
size += n * sizeof(*new);
s->irq_routes = g_realloc(s->irq_routes, size);
s->nr_allocated_irq_routes = n;
}
n = s->irq_routes->nr;
s->irq_routes->nr++;
new = &s->irq_routes->entries[n];
*new = *entry;
set_bit(entry->gsi, s->used_gsi_bitmap);
trace_mshv_add_msi_routing(entry->address_lo | entry->address_hi,
entry->data);
}
int mshv_irqchip_add_msi_route(AccelRouteChange *c, int vector, PCIDevice *dev)
{
struct mshv_user_irq_entry entry = { 0 };
MSIMessage msg = { 0 };
uint32_t data, high_addr, low_addr;
int gsi, ret;
MshvState *s = MSHV_STATE(c->accel);
if (!pci_available || !dev) {
return 0;
}
msg = pci_get_msi_message(dev, vector);
ret = irqchip_allocate_gsi(mshv_state, &gsi);
if (ret < 0) {
error_report("Could not allocate GSI for MSI route");
return -1;
}
high_addr = msg.address >> 32;
low_addr = msg.address & 0xFFFFFFFF;
data = le32_to_cpu(msg.data);
entry.gsi = gsi;
entry.address_hi = high_addr;
entry.address_lo = low_addr;
entry.data = data;
if (s->irq_routes->nr < s->gsi_count) {
add_routing_entry(s, &entry);
c->changes++;
} else {
irqchip_release_gsi(s, gsi);
return -ENOSPC;
}
return gsi;
}
void mshv_irqchip_release_virq(MshvState *s, int virq)
{
struct mshv_user_irq_entry *e;
int i;
for (i = 0; i < s->irq_routes->nr; i++) {
e = &s->irq_routes->entries[i];
if (e->gsi == virq) {
s->irq_routes->nr--;
*e = s->irq_routes->entries[s->irq_routes->nr];
}
}
irqchip_release_gsi(s, virq);
trace_mshv_remove_msi_routing(virq);
}
static int update_routing_entry(MshvState *s,
struct mshv_user_irq_entry *new_entry)
{
struct mshv_user_irq_entry *entry;
int n;
for (n = 0; n < s->irq_routes->nr; n++) {
entry = &s->irq_routes->entries[n];
if (entry->gsi != new_entry->gsi) {
continue;
}
if (!memcmp(entry, new_entry, sizeof *entry)) {
return 0;
}
*entry = *new_entry;
return 0;
}
return -ESRCH;
}
int mshv_irqchip_update_msi_route(int virq, MSIMessage msg, PCIDevice *dev)
{
uint32_t addr_hi = msg.address >> 32;
uint32_t addr_lo = msg.address & 0xFFFFFFFF;
uint32_t data = le32_to_cpu(msg.data);
struct mshv_user_irq_entry entry = {
.gsi = virq,
.address_hi = addr_hi,
.address_lo = addr_lo,
.data = data,
};
int ret;
ret = set_msi_routing(virq, msg.address, le32_to_cpu(msg.data));
ret = update_routing_entry(mshv_state, &entry);
if (ret < 0) {
error_report("Failed to set msi routing");
return -1;
error_report("Failed to set msi routing for gsi %d", virq);
abort();
}
trace_mshv_set_msi_routing(virq, msg.address, data);
return 0;
}
@@ -347,16 +296,17 @@ int mshv_request_interrupt(MshvState *mshv_state, uint32_t interrupt_type, uint3
return 0;
}
void mshv_irqchip_commit_routes(void)
void mshv_irqchip_commit_routes(MshvState *s)
{
int ret;
int vm_fd = mshv_state->vm;
int vm_fd = s->vm;
ret = commit_msi_routing_table(vm_fd);
ret = ioctl(vm_fd, MSHV_SET_MSI_ROUTING, s->irq_routes);
if (ret < 0) {
error_report("Failed to commit msi routing table");
abort();
}
trace_mshv_commit_msi_routing_table(vm_fd, s->irq_routes->nr);
}
int mshv_irqchip_add_irqfd_notifier_gsi(const EventNotifier *event,
@@ -372,27 +322,45 @@ int mshv_irqchip_remove_irqfd_notifier_gsi(const EventNotifier *event,
return irqchip_update_irqfd_notifier_gsi(event, NULL, virq, false);
}
int mshv_reserve_ioapic_msi_routes(int vm_fd)
static int mshv_reserve_ioapic_msi_routes(MshvState *s)
{
int ret, gsi;
int ret, i;
int gsi = 0;
struct mshv_user_irq_entry blank_entry = { 0 };
/*
* 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);
for (i = 0; i < IOAPIC_NUM_PINS; i++) {
/* ret = add_msi_routing(0, 0); */
ret = irqchip_allocate_gsi(s, &gsi);
if (ret < 0) {
error_report("Failed to reserve GSI %d", gsi);
error_report("Failed to reserve GSI %d: %s", gsi, strerror(-ret));
return -1;
}
blank_entry.gsi = gsi;
add_routing_entry(s, &blank_entry);
}
ret = commit_msi_routing_table(vm_fd);
if (ret < 0) {
error_report("Failed to commit reserved IOAPIC MSI routes");
return -1;
}
mshv_irqchip_commit_routes(s);
return 0;
}
void mshv_init_irq_routing(MshvState *s)
{
int ret;
int gsi_count = MSHV_MAX_MSI_ROUTES;
s->irq_routes = g_malloc0(sizeof(*s->irq_routes));
s->nr_allocated_irq_routes = 0;
s->gsi_count = gsi_count;
s->used_gsi_bitmap = bitmap_new(gsi_count);
ret = mshv_reserve_ioapic_msi_routes(s);
if (ret < 0) {
error_report("Failed to reserve IOAPIC MSI routes");
abort();
}
}

View File

@@ -12,10 +12,13 @@
#include "qemu/osdep.h"
#include "qemu/error-report.h"
#include "qapi/error.h"
#include "linux/mshv.h"
#include "system/address-spaces.h"
#include "system/mshv.h"
#include "system/mshv_int.h"
#include "hw/hyperv/hvhdk_mini.h"
#include "system/physmem.h"
#include "exec/memattrs.h"
#include <sys/ioctl.h>
#include "trace.h"
@@ -211,3 +214,211 @@ void mshv_set_phys_mem(MshvMemoryListener *mml, MemoryRegionSection *section,
abort();
}
}
static int enable_dirty_page_tracking(int vm_fd)
{
int ret;
struct hv_input_set_partition_property in = {0};
struct mshv_root_hvcall args = {0};
in.property_code = HV_PARTITION_PROPERTY_GPA_PAGE_ACCESS_TRACKING;
in.property_value = 1;
args.code = HVCALL_SET_PARTITION_PROPERTY;
args.in_sz = sizeof(in);
args.in_ptr = (uint64_t)&in;
ret = mshv_hvcall(vm_fd, &args);
if (ret < 0) {
error_report("Failed to enable dirty page tracking: %s",
strerror(errno));
return -1;
}
return 0;
}
/*
* Retrieve dirty page bitmap for a GPA range, clearing the dirty bits
* atomically. Large ranges are handled in batches.
*/
static int get_dirty_log(int vm_fd, uint64_t base_pfn, uint64_t page_count,
unsigned long *bitmap, size_t bitmap_size)
{
uint64_t batch, bitmap_offset, completed = 0;
struct mshv_gpap_access_bitmap args = {0};
int ret;
QEMU_BUILD_BUG_ON(MSHV_DIRTY_PAGES_BATCH_SIZE % BITS_PER_LONG != 0);
assert(bitmap_size >= ROUND_UP(page_count, BITS_PER_LONG) / 8);
while (completed < page_count) {
batch = MIN(MSHV_DIRTY_PAGES_BATCH_SIZE, page_count - completed);
bitmap_offset = completed / BITS_PER_LONG;
args.access_type = MSHV_GPAP_ACCESS_TYPE_DIRTY;
args.access_op = MSHV_GPAP_ACCESS_OP_CLEAR;
args.page_count = batch;
args.gpap_base = base_pfn + completed;
args.bitmap_ptr = (uint64_t)(bitmap + bitmap_offset);
ret = ioctl(vm_fd, MSHV_GET_GPAP_ACCESS_BITMAP, &args);
if (ret < 0) {
error_report("Failed to get dirty log (base_pfn=0x%" PRIx64
" batch=%" PRIu64 "): %s",
base_pfn + completed, batch, strerror(errno));
return -1;
}
completed += batch;
}
return 0;
}
bool mshv_log_global_start(MemoryListener *listener, Error **errp)
{
int ret;
ret = enable_dirty_page_tracking(mshv_state->vm);
if (ret < 0) {
error_setg_errno(errp, -ret, "Failed to enable dirty page tracking");
return false;
}
return true;
}
static int disable_dirty_page_tracking(int vm_fd)
{
int ret;
struct hv_input_set_partition_property in = {0};
struct mshv_root_hvcall args = {0};
in.property_code = HV_PARTITION_PROPERTY_GPA_PAGE_ACCESS_TRACKING;
in.property_value = 0;
args.code = HVCALL_SET_PARTITION_PROPERTY;
args.in_sz = sizeof(in);
args.in_ptr = (uint64_t)&in;
ret = mshv_hvcall(vm_fd, &args);
if (ret < 0) {
error_report("Failed to disable dirty page tracking: %s",
strerror(errno));
return -1;
}
return 0;
}
static int set_dirty_pages(int vm_fd, uint64_t base_pfn, uint64_t page_count)
{
uint64_t batch, completed = 0;
unsigned long bitmap[MSHV_DIRTY_PAGES_BATCH_SIZE / BITS_PER_LONG];
struct mshv_gpap_access_bitmap args = {0};
int ret;
while (completed < page_count) {
batch = MIN(MSHV_DIRTY_PAGES_BATCH_SIZE, page_count - completed);
args.access_type = MSHV_GPAP_ACCESS_TYPE_DIRTY;
args.access_op = MSHV_GPAP_ACCESS_OP_SET;
args.page_count = batch;
args.gpap_base = base_pfn + completed;
args.bitmap_ptr = (uint64_t)bitmap;
ret = ioctl(vm_fd, MSHV_GET_GPAP_ACCESS_BITMAP, &args);
if (ret < 0) {
error_report("Failed to set dirty pages (base_pfn=0x%" PRIx64
" batch=%" PRIu64 "): %s",
base_pfn + completed, batch, strerror(errno));
return -1;
}
completed += batch;
}
return 0;
}
static bool set_dirty_bits_cb(Int128 start, Int128 len, const MemoryRegion *mr,
hwaddr offset_in_region, void *opaque)
{
int ret, *errp = opaque;
hwaddr gpa, size;
uint64_t page_count, base_pfn;
gpa = int128_get64(start);
size = int128_get64(len);
page_count = size >> MSHV_PAGE_SHIFT;
base_pfn = gpa >> MSHV_PAGE_SHIFT;
if (!mr->ram || mr->readonly) {
return false;
}
if (page_count == 0) {
return false;
}
ret = set_dirty_pages(mshv_state->vm, base_pfn, page_count);
/* true aborts the iteration, which is what we want if there's an error */
if (ret < 0) {
*errp = ret;
return true;
}
return false;
}
void mshv_log_global_stop(MemoryListener *listener)
{
int err = 0;
/* MSHV requires all dirty bits to be set before disabling tracking. */
FlatView *fv = address_space_to_flatview(&address_space_memory);
flatview_for_each_range(fv, set_dirty_bits_cb, &err);
if (err < 0) {
error_report("Failed to set dirty bits before disabling tracking");
}
disable_dirty_page_tracking(mshv_state->vm);
}
void mshv_log_sync(MemoryListener *listener, MemoryRegionSection *section)
{
hwaddr size, start_addr, mr_offset;
uint64_t page_count, base_pfn;
size_t bitmap_size;
unsigned long *bitmap;
ram_addr_t ram_addr;
int ret;
MemoryRegion *mr = section->mr;
if (!memory_region_is_ram(mr) || memory_region_is_rom(mr)) {
return;
}
size = align_section(section, &start_addr);
if (!size) {
return;
}
page_count = size >> MSHV_PAGE_SHIFT;
base_pfn = start_addr >> MSHV_PAGE_SHIFT;
bitmap_size = ROUND_UP(page_count, BITS_PER_LONG) / 8;
bitmap = g_malloc0(bitmap_size);
ret = get_dirty_log(mshv_state->vm, base_pfn, page_count, bitmap,
bitmap_size);
if (ret < 0) {
g_free(bitmap);
return;
}
mr_offset = section->offset_within_region + start_addr -
section->offset_within_address_space;
ram_addr = memory_region_get_ram_addr(mr) + mr_offset;
physical_memory_set_dirty_lebitmap(bitmap, ram_addr, page_count);
g_free(bitmap);
}

View File

@@ -1,6 +1,5 @@
system_ss.add(when: 'CONFIG_MSHV', if_true: files(
'irq.c',
'mem.c',
'msr.c',
'mshv-all.c'
))

View File

@@ -43,10 +43,6 @@
#include <err.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;
@@ -110,21 +106,136 @@ static int resume_vm(int vm_fd)
return 0;
}
static int get_host_partition_property(int mshv_fd, uint32_t property_code,
uint64_t *value)
{
int ret;
struct hv_input_get_partition_property in = {0};
struct hv_output_get_partition_property out = {0};
struct mshv_root_hvcall args = {0};
in.property_code = property_code;
args.code = HVCALL_GET_PARTITION_PROPERTY;
args.in_sz = sizeof(in);
args.in_ptr = (uint64_t)&in;
args.out_sz = sizeof(out);
args.out_ptr = (uint64_t)&out;
ret = ioctl(mshv_fd, MSHV_ROOT_HVCALL, &args);
if (ret < 0) {
error_report("Failed to get host partition property bank: %s",
strerror(errno));
return -1;
}
*value = out.property_value;
return 0;
}
static int get_partition_property(int vm_fd, uint32_t feature_bank,
uint64_t *value)
{
struct hv_input_get_partition_property in = {0};
struct hv_output_get_partition_property out = {0};
struct mshv_root_hvcall args = {0};
int ret;
in.property_code = feature_bank;
args.code = HVCALL_GET_PARTITION_PROPERTY;
args.in_sz = sizeof(in);
args.in_ptr = (uint64_t)&in;
args.out_sz = sizeof(out);
args.out_ptr = (uint64_t)&out;
ret = ioctl(vm_fd, MSHV_ROOT_HVCALL, &args);
if (ret < 0) {
error_report("Failed to get guest partition property bank: %s",
strerror(errno));
return -1;
}
*value = out.property_value;
return 0;
}
static int get_proc_features(int vm_fd,
union hv_partition_processor_features *features)
{
int ret;
ret = get_partition_property(vm_fd,
HV_PARTITION_PROPERTY_PROCESSOR_FEATURES0,
features[0].as_uint64);
if (ret < 0) {
error_report("Failed to get processor features bank 0");
return -1;
}
ret = get_partition_property(vm_fd,
HV_PARTITION_PROPERTY_PROCESSOR_FEATURES1,
features[1].as_uint64);
if (ret < 0) {
error_report("Failed to get processor features bank 1");
return -1;
}
return 0;
}
static int create_partition(int mshv_fd, int *vm_fd)
{
int ret;
struct mshv_create_partition args = {0};
uint64_t pt_flags, host_proc_features;
union hv_partition_processor_xsave_features disabled_xsave_features;
union hv_partition_processor_features disabled_partition_features = {0};
struct mshv_create_partition_v2 args = {0};
QEMU_BUILD_BUG_ON(MSHV_NUM_CPU_FEATURES_BANKS != 2);
/* Initialize pt_flags with the desired features */
uint64_t pt_flags = (1ULL << MSHV_PT_BIT_LAPIC) |
(1ULL << MSHV_PT_BIT_X2APIC) |
(1ULL << MSHV_PT_BIT_GPA_SUPER_PAGES);
pt_flags = (1ULL << MSHV_PT_BIT_LAPIC) |
(1ULL << MSHV_PT_BIT_X2APIC) |
(1ULL << MSHV_PT_BIT_GPA_SUPER_PAGES) |
(1ULL << MSHV_PT_BIT_CPU_AND_XSAVE_FEATURES);
/* Set default isolation type */
uint64_t pt_isolation = MSHV_PT_ISOLATION_NONE;
/* enable all */
disabled_xsave_features.as_uint64 = 0;
/*
* query host for supported processor features and disable unsupported
* features: (0 means supported, 1 means disabled, hence the negation)
*/
ret = get_host_partition_property(mshv_fd,
HV_PARTITION_PROPERTY_PROCESSOR_FEATURES0,
&host_proc_features);
if (ret < 0) {
error_report("Failed to get host processor feature bank 0");
return -1;
}
args.pt_cpu_fbanks[0] = ~host_proc_features;
ret = get_host_partition_property(mshv_fd,
HV_PARTITION_PROPERTY_PROCESSOR_FEATURES1,
&host_proc_features);
if (ret < 0) {
error_report("Failed to get host processor feature bank 1");
return -1;
}
args.pt_cpu_fbanks[1] = ~host_proc_features;
/* arch-specific features we disable regardless of host support */
mshv_arch_disable_partition_proc_features(&disabled_partition_features);
args.pt_cpu_fbanks[0] |= disabled_partition_features.as_uint64[0];
args.pt_cpu_fbanks[1] |= disabled_partition_features.as_uint64[1];
/* populate args structure */
args.pt_flags = pt_flags;
args.pt_isolation = pt_isolation;
args.pt_isolation = MSHV_PT_ISOLATION_NONE;
args.pt_disabled_xsave = disabled_xsave_features.as_uint64;
args.pt_num_cpu_fbanks = MSHV_NUM_CPU_FEATURES_BANKS;
ret = ioctl(mshv_fd, MSHV_CREATE_PARTITION, &args);
if (ret < 0) {
@@ -204,11 +315,6 @@ static int create_vm(int mshv_fd, int *vm_fd)
return -1;
}
ret = mshv_reserve_ioapic_msi_routes(*vm_fd);
if (ret < 0) {
return -1;
}
ret = mshv_arch_post_init_vm(*vm_fd);
if (ret < 0) {
return -1;
@@ -371,6 +477,9 @@ static MemoryListener mshv_memory_listener = {
.region_del = mem_region_del,
.eventfd_add = mem_ioeventfd_add,
.eventfd_del = mem_ioeventfd_del,
.log_sync = mshv_log_sync,
.log_global_start = mshv_log_global_start,
.log_global_stop = mshv_log_global_stop,
};
static MemoryListener mshv_io_listener = {
@@ -415,13 +524,13 @@ static int mshv_init_vcpu(CPUState *cpu)
int ret;
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) {
return -1;
}
mshv_arch_init_vcpu(cpu);
cpu->accel->dirty = true;
return 0;
@@ -450,8 +559,6 @@ static int mshv_init(AccelState *as, MachineState *ms)
mshv_init_mmio_emu();
mshv_init_msicontrol();
ret = create_vm(mshv_fd, &vm_fd);
if (ret < 0) {
close(mshv_fd);
@@ -467,11 +574,19 @@ static int mshv_init(AccelState *as, MachineState *ms)
s->vm = vm_fd;
s->fd = mshv_fd;
ret = get_proc_features(vm_fd, &s->processor_features);
if (ret < 0) {
return -1;
}
s->nr_as = 1;
s->as = g_new0(MshvAddressSpace, s->nr_as);
mshv_state = s;
mshv_init_irq_routing(s);
register_mshv_memory_listener(s, &s->memory_listener, &address_space_memory,
0, "mshv-memory");
memory_listener_register(&mshv_io_listener, &address_space_io);
@@ -503,7 +618,7 @@ static int mshv_cpu_exec(CPUState *cpu)
do {
if (cpu->accel->dirty) {
ret = mshv_arch_put_registers(cpu);
ret = mshv_arch_store_vcpu_state(cpu);
if (ret) {
error_report("Failed to put registers after init: %s",
strerror(-ret));
@@ -625,7 +740,7 @@ static void mshv_start_vcpu_thread(CPUState *cpu)
static void do_mshv_cpu_synchronize_post_init(CPUState *cpu,
run_on_cpu_data arg)
{
int ret = mshv_arch_put_registers(cpu);
int ret = mshv_arch_store_vcpu_state(cpu);
if (ret < 0) {
error_report("Failed to put registers after init: %s", strerror(-ret));
abort();
@@ -641,7 +756,7 @@ static void mshv_cpu_synchronize_post_init(CPUState *cpu)
static void mshv_cpu_synchronize_post_reset(CPUState *cpu)
{
int ret = mshv_arch_put_registers(cpu);
int ret = mshv_arch_store_vcpu_state(cpu);
if (ret) {
error_report("Failed to put registers after reset: %s",
strerror(-ret));
@@ -665,7 +780,7 @@ static void mshv_cpu_synchronize_pre_loadvm(CPUState *cpu)
static void do_mshv_cpu_synchronize(CPUState *cpu, run_on_cpu_data arg)
{
if (!cpu->accel->dirty) {
int ret = mshv_load_regs(cpu);
int ret = mshv_arch_load_vcpu_state(cpu);
if (ret < 0) {
error_report("Failed to load registers for vcpu %d",
cpu->cpu_index);

View File

@@ -1,375 +0,0 @@
/*
* 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;
}

View File

@@ -44,7 +44,7 @@ int kvm_on_sigbus(int code, void *addr)
return 1;
}
int kvm_irqchip_add_msi_route(KVMRouteChange *c, int vector, PCIDevice *dev)
int kvm_irqchip_add_msi_route(AccelRouteChange *c, int vector, PCIDevice *dev)
{
return -ENOSYS;
}

View File

@@ -13,13 +13,14 @@
#include "system/mshv.h"
bool mshv_allowed;
MshvState *mshv_state;
int mshv_irqchip_add_msi_route(int vector, PCIDevice *dev)
int mshv_irqchip_add_msi_route(AccelRouteChange *c, int vector, PCIDevice *dev)
{
return -ENOSYS;
}
void mshv_irqchip_release_virq(int virq)
void mshv_irqchip_release_virq(MshvState *s, int virq)
{
}
@@ -28,7 +29,7 @@ int mshv_irqchip_update_msi_route(int virq, MSIMessage msg, PCIDevice *dev)
return -ENOSYS;
}
void mshv_irqchip_commit_routes(void)
void mshv_irqchip_commit_routes(MshvState *s)
{
}