mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
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:
+15
@@ -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>
|
||||
|
||||
@@ -13,6 +13,9 @@ config TCG
|
||||
config KVM
|
||||
bool
|
||||
|
||||
config MSHV
|
||||
bool
|
||||
|
||||
config XEN
|
||||
bool
|
||||
select FSDEV_9P if VIRTFS
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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"
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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:
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 = "",
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user