* [PATCH 00/14] Add ARM64 support for MSHV accelerator
@ 2026-03-11 15:15 Anirudh Rayabharam (Microsoft)
2026-03-11 15:15 ` [PATCH 01/14] accel/mshv: provision guests with the same features as host Anirudh Rayabharam (Microsoft)
` (15 more replies)
0 siblings, 16 replies; 38+ messages in thread
From: Anirudh Rayabharam (Microsoft) @ 2026-03-11 15:15 UTC (permalink / raw)
To: qemu-devel
Cc: Magnus Kulke, Wei Liu, Paolo Bonzini, Marc-André Lureau,
Daniel P. Berrangé, Philippe Mathieu-Daudé,
Peter Maydell, Anirudh Rayabharam, Aastha Rawat, qemu-arm
This series adds ARM64 guest support to the MSHV (Microsoft Hypervisor)
accelerator, enabling QEMU to run aarch64 VMs on Microsoft's hypervisor
using the mshv Linux kernel module.
The first few patches refactor the existing x86 MSHV code to separate
arch-specific pieces from common infrastructure: moving MSR handling to
target/i386, extracting shared register hypercall helpers, provisioning
host CPU features, and introducing arch-specific init hooks.
The remaining patches add the ARM64 backend:
- vCPU state get/set using hypervisor register hypercalls
- -cpu host support by querying ID registers from the hypervisor
- vCPU run loop with MMIO emulation via ESR_EL2 syndrome decoding
- In-kernel vGICv3 backed by HVCALL_ASSERT_VIRTUAL_INTERRUPT
- Interrupt control structure adjustments for arm64
With this series, a standard aarch64 virt machine can be launched with:
qemu-system-aarch64 -accel mshv -cpu host -M virt ...
Caveats:
- Currently only direct kernel is supported. We're still debugging edk2
firmware boot.
- Live migration is not yet supported.
---
Aastha Rawat (7):
accel/mshv: move msr.c to target/i386
accel/mshv: extract common CPU register helpers
meson, target/arm/mshv: Enable arm64 build & add initial MSHV support
target/arm/mshv: implement vcpu state operations for ARM64
target/arm/mshv: implement -cpu host for MSHV
accel/mshv: Add access_vp_regs synthetic proc features
target/arm: cpu: Mark MSHV supporting PSCI 1.3
Anirudh Rayabharam (Microsoft) (6):
accel/mshv: provision guests with the same features as host
accel/mshv: add arch-specific accelerator init hook
target/arm/mshv: add vCPU run loop
include/hw/hyperv: adjust hv_interrupt_control structure for arm64
hw/intc,target/arm/mshv: add MSHV vGICv3 implementation
MAINTAINERS: updates for MSHV arm64 code
Magnus Kulke (1):
accel/mshv: implement cpu_thread_is_idle() hook
MAINTAINERS | 8 +
accel/mshv/irq.c | 2 +
accel/mshv/meson.build | 4 +-
accel/mshv/mshv-all.c | 73 +++-
accel/mshv/mshv-cpu-common.c | 151 +++++++++
hw/arm/virt.c | 11 +-
hw/intc/arm_gicv3_common.c | 3 +
hw/intc/arm_gicv3_mshv.c | 180 ++++++++++
hw/intc/meson.build | 1 +
include/hw/hyperv/hvgdk_mini.h | 130 ++++++++
include/hw/hyperv/hvhdk.h | 97 +++++-
include/hw/hyperv/hvhdk_mini.h | 6 +
include/hw/intc/arm_gicv3_common.h | 1 +
include/system/hw_accel.h | 3 +-
include/system/mshv.h | 2 +
include/system/mshv_int.h | 5 +
meson.build | 7 +-
target/arm/cpu.c | 7 +-
target/arm/cpu64.c | 24 +-
target/arm/meson.build | 1 +
target/arm/mshv/meson.build | 7 +
target/arm/mshv/mshv-all.c | 665 +++++++++++++++++++++++++++++++++++++
target/arm/mshv_arm.h | 18 +
target/i386/mshv/meson.build | 2 +
target/i386/mshv/mshv-all.c | 85 +++++
target/i386/mshv/mshv-cpu.c | 170 +---------
{accel => target/i386}/mshv/msr.c | 0
27 files changed, 1465 insertions(+), 198 deletions(-)
---
base-commit: 1fd5ff9d76d23ab23a68419cbc76d5ee33e8b455
change-id: 20260311-mshv_accel_arm64_supp-e86b0082aee4
Best regards,
--
Anirudh Rayabharam (Microsoft) <anirudh@anirudhrb.com>
^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH 01/14] accel/mshv: provision guests with the same features as host
2026-03-11 15:15 [PATCH 00/14] Add ARM64 support for MSHV accelerator Anirudh Rayabharam (Microsoft)
@ 2026-03-11 15:15 ` Anirudh Rayabharam (Microsoft)
2026-03-11 15:50 ` Anirudh Rayabharam
2026-03-11 15:15 ` [PATCH 02/14] accel/mshv: move msr.c to target/i386 Anirudh Rayabharam
` (14 subsequent siblings)
15 siblings, 1 reply; 38+ messages in thread
From: Anirudh Rayabharam (Microsoft) @ 2026-03-11 15:15 UTC (permalink / raw)
To: qemu-devel
Cc: Magnus Kulke, Wei Liu, Paolo Bonzini, Marc-André Lureau,
Daniel P. Berrangé, Philippe Mathieu-Daudé,
Peter Maydell, Anirudh Rayabharam, Aastha Rawat, qemu-arm
Query HV_PARTITION_PROPERTY_PROCESSOR_FEATURES to obtain the feature set
supported by the host and pass on this feature set to the guest during
partition creation.
Signed-off-by: Anirudh Rayabharam (Microsoft) <anirudh@anirudhrb.com>
---
accel/mshv/mshv-all.c | 47 +++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 45 insertions(+), 2 deletions(-)
diff --git a/accel/mshv/mshv-all.c b/accel/mshv/mshv-all.c
index d4cc7f5371..3b8b9ef116 100644
--- a/accel/mshv/mshv-all.c
+++ b/accel/mshv/mshv-all.c
@@ -110,21 +110,64 @@ static int resume_vm(int vm_fd)
return 0;
}
+static int get_host_property(int mshv_fd, uint32_t prop_code, uint64_t *value)
+{
+ int ret;
+ struct hv_input_get_partition_property in = {0};
+ struct mshv_root_hvcall args = {0};
+ struct hv_output_get_partition_property out = {0};
+
+ in.property_code = prop_code;
+
+ args.code = HVCALL_GET_PARTITION_PROPERTY;
+ args.in_sz = sizeof(in);
+ args.in_ptr = (uint64_t)∈
+ args.out_sz = sizeof(out);
+ args.out_ptr = (uint64_t)&out;
+
+ ret = mshv_hvcall(mshv_fd, &args);
+ if (ret < 0) {
+ return -errno;
+ }
+
+ *value = out.property_value;
+ return 0;
+}
+
static int create_partition(int mshv_fd, int *vm_fd)
{
int ret;
- struct mshv_create_partition args = {0};
+ struct mshv_create_partition_v2 args = {0};
+ uint64_t host_proc_features0, host_proc_features1;
+
+ ret = get_host_property(mshv_fd, HV_PARTITION_PROPERTY_PROCESSOR_FEATURES0,
+ &host_proc_features0);
+ if (ret < 0) {
+ error_report("Failed to get host processor features (bank 0)");
+ return -1;
+ }
+
+ ret = get_host_property(mshv_fd, HV_PARTITION_PROPERTY_PROCESSOR_FEATURES1,
+ &host_proc_features1);
+ if (ret < 0) {
+ error_report("Failed to get host processor features (bank 1)");
+ return -1;
+ }
/* 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);
+ (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;
args.pt_flags = pt_flags;
args.pt_isolation = pt_isolation;
+ args.pt_num_cpu_fbanks = MSHV_NUM_CPU_FEATURES_BANKS;
+ args.pt_cpu_fbanks[0] = ~host_proc_features0;
+ args.pt_cpu_fbanks[1] = ~host_proc_features1;
ret = ioctl(mshv_fd, MSHV_CREATE_PARTITION, &args);
if (ret < 0) {
--
2.43.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 02/14] accel/mshv: move msr.c to target/i386
2026-03-11 15:15 [PATCH 00/14] Add ARM64 support for MSHV accelerator Anirudh Rayabharam (Microsoft)
2026-03-11 15:15 ` [PATCH 01/14] accel/mshv: provision guests with the same features as host Anirudh Rayabharam (Microsoft)
@ 2026-03-11 15:15 ` Anirudh Rayabharam
2026-03-11 15:47 ` Mohamed Mediouni
2026-03-11 17:06 ` Wei Liu
2026-03-11 15:15 ` [PATCH 03/14] accel/mshv: extract common CPU register helpers Anirudh Rayabharam
` (13 subsequent siblings)
15 siblings, 2 replies; 38+ messages in thread
From: Anirudh Rayabharam @ 2026-03-11 15:15 UTC (permalink / raw)
To: qemu-devel
Cc: Magnus Kulke, Wei Liu, Paolo Bonzini, Marc-André Lureau,
Daniel P. Berrangé, Philippe Mathieu-Daudé,
Peter Maydell, Anirudh Rayabharam, Aastha Rawat, qemu-arm
From: Aastha Rawat <aastharawat@linux.microsoft.com>
This file has x86 specific implementations. Move this file to i386
folder in preparation for ARM64 MSHV support.
Signed-off-by: Aastha Rawat <aastharawat@linux.microsoft.com>
---
accel/mshv/meson.build | 1 -
target/i386/mshv/meson.build | 1 +
{accel => target/i386}/mshv/msr.c | 0
3 files changed, 1 insertion(+), 1 deletion(-)
diff --git a/accel/mshv/meson.build b/accel/mshv/meson.build
index c1b1787c5e..e433187cde 100644
--- a/accel/mshv/meson.build
+++ b/accel/mshv/meson.build
@@ -1,6 +1,5 @@
system_ss.add(when: 'CONFIG_MSHV', if_true: files(
'irq.c',
'mem.c',
- 'msr.c',
'mshv-all.c'
))
diff --git a/target/i386/mshv/meson.build b/target/i386/mshv/meson.build
index 49f28d4a5b..6091c21887 100644
--- a/target/i386/mshv/meson.build
+++ b/target/i386/mshv/meson.build
@@ -2,6 +2,7 @@ i386_mshv_ss = ss.source_set()
i386_mshv_ss.add(files(
'mshv-cpu.c',
+ 'msr.c',
))
i386_system_ss.add_all(when: 'CONFIG_MSHV', if_true: i386_mshv_ss)
diff --git a/accel/mshv/msr.c b/target/i386/mshv/msr.c
similarity index 100%
rename from accel/mshv/msr.c
rename to target/i386/mshv/msr.c
--
2.43.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 03/14] accel/mshv: extract common CPU register helpers
2026-03-11 15:15 [PATCH 00/14] Add ARM64 support for MSHV accelerator Anirudh Rayabharam (Microsoft)
2026-03-11 15:15 ` [PATCH 01/14] accel/mshv: provision guests with the same features as host Anirudh Rayabharam (Microsoft)
2026-03-11 15:15 ` [PATCH 02/14] accel/mshv: move msr.c to target/i386 Anirudh Rayabharam
@ 2026-03-11 15:15 ` Anirudh Rayabharam
2026-03-11 15:15 ` [PATCH 04/14] meson, target/arm/mshv: Enable arm64 build & add initial MSHV support Anirudh Rayabharam
` (12 subsequent siblings)
15 siblings, 0 replies; 38+ messages in thread
From: Anirudh Rayabharam @ 2026-03-11 15:15 UTC (permalink / raw)
To: qemu-devel
Cc: Magnus Kulke, Wei Liu, Paolo Bonzini, Marc-André Lureau,
Daniel P. Berrangé, Philippe Mathieu-Daudé,
Peter Maydell, Anirudh Rayabharam, Aastha Rawat, qemu-arm
From: Aastha Rawat <aastharawat@linux.microsoft.com>
Move arch-independent MSHV CPU register handling functions into
accel/mshv/mshv-cpu-common.c. Update x86 MSHV backends to use these
shared helpers.
Prefix get_generic_regs() with mshv_ for proper namespacing since it
is now public.
Signed-off-by: Aastha Rawat <aastharawat@linux.microsoft.com>
---
accel/mshv/meson.build | 3 +-
accel/mshv/mshv-cpu-common.c | 151 +++++++++++++++++++++++++++++++++++++++++++
include/system/mshv_int.h | 3 +
target/i386/mshv/mshv-cpu.c | 130 +------------------------------------
4 files changed, 159 insertions(+), 128 deletions(-)
diff --git a/accel/mshv/meson.build b/accel/mshv/meson.build
index e433187cde..ebe32921b3 100644
--- a/accel/mshv/meson.build
+++ b/accel/mshv/meson.build
@@ -1,5 +1,6 @@
system_ss.add(when: 'CONFIG_MSHV', if_true: files(
'irq.c',
'mem.c',
- 'mshv-all.c'
+ 'mshv-all.c',
+ 'mshv-cpu-common.c'
))
diff --git a/accel/mshv/mshv-cpu-common.c b/accel/mshv/mshv-cpu-common.c
new file mode 100644
index 0000000000..b104720161
--- /dev/null
+++ b/accel/mshv/mshv-cpu-common.c
@@ -0,0 +1,151 @@
+/*
+ * QEMU MSHV common CPU register helpers
+ *
+ * Copyright Microsoft, Corp. 2026
+ *
+ * Authors: Ziqiao Zhou <ziqiaozhou@microsoft.com>
+ * Magnus Kulke <magnuskulke@microsoft.com>
+ * Jinank Jain <jinankjain@microsoft.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "qemu/memalign.h"
+
+#include "system/mshv.h"
+#include "system/mshv_int.h"
+
+#include "hw/core/cpu.h"
+#include "linux/mshv.h"
+
+#include <sys/ioctl.h>
+
+int mshv_set_generic_regs(const CPUState *cpu, const hv_register_assoc *assocs,
+ size_t n_regs)
+{
+ int cpu_fd = mshv_vcpufd(cpu);
+ int vp_index = cpu->cpu_index;
+ size_t in_sz, assocs_sz;
+ hv_input_set_vp_registers *in = cpu->accel->hvcall_args.input_page;
+ struct mshv_root_hvcall args = {0};
+ int ret;
+
+ /* find out the size of the struct w/ a flexible array at the tail */
+ assocs_sz = n_regs * sizeof(hv_register_assoc);
+ in_sz = sizeof(hv_input_set_vp_registers) + assocs_sz;
+
+ /* fill the input struct */
+ memset(in, 0, sizeof(hv_input_set_vp_registers));
+ in->vp_index = vp_index;
+ memcpy(in->elements, assocs, assocs_sz);
+
+ /* create the hvcall envelope */
+ args.code = HVCALL_SET_VP_REGISTERS;
+ args.in_sz = in_sz;
+ args.in_ptr = (uint64_t) in;
+ args.reps = (uint16_t) n_regs;
+
+ /* perform the call */
+ ret = mshv_hvcall(cpu_fd, &args);
+ if (ret < 0) {
+ error_report("Failed to set registers");
+ return -1;
+ }
+
+ /* assert we set all registers */
+ if (args.reps != n_regs) {
+ error_report("Failed to set registers: expected %zu elements"
+ ", got %u", n_regs, args.reps);
+ return -1;
+ }
+
+ return 0;
+}
+
+int mshv_get_generic_regs(CPUState *cpu, hv_register_assoc *assocs,
+ size_t n_regs)
+{
+ int cpu_fd = mshv_vcpufd(cpu);
+ int vp_index = cpu->cpu_index;
+ hv_input_get_vp_registers *in = cpu->accel->hvcall_args.input_page;
+ hv_register_value *values = cpu->accel->hvcall_args.output_page;
+ size_t in_sz, names_sz, values_sz;
+ int i, ret;
+ struct mshv_root_hvcall args = {0};
+
+ /* find out the size of the struct w/ a flexible array at the tail */
+ names_sz = n_regs * sizeof(hv_register_name);
+ in_sz = sizeof(hv_input_get_vp_registers) + names_sz;
+
+ /* fill the input struct */
+ memset(in, 0, sizeof(hv_input_get_vp_registers));
+ in->vp_index = vp_index;
+ for (i = 0; i < n_regs; i++) {
+ in->names[i] = assocs[i].name;
+ }
+
+ /* determine size of value output buffer */
+ values_sz = n_regs * sizeof(union hv_register_value);
+
+ /* create the hvcall envelope */
+ args.code = HVCALL_GET_VP_REGISTERS;
+ args.in_sz = in_sz;
+ args.in_ptr = (uint64_t) in;
+ args.out_sz = values_sz;
+ args.out_ptr = (uint64_t) values;
+ args.reps = (uint16_t) n_regs;
+
+ /* perform the call */
+ ret = mshv_hvcall(cpu_fd, &args);
+ if (ret < 0) {
+ error_report("Failed to retrieve registers");
+ return -1;
+ }
+
+ /* assert we got all registers */
+ if (args.reps != n_regs) {
+ error_report("Failed to retrieve registers: expected %zu elements"
+ ", got %u", n_regs, args.reps);
+ return -1;
+ }
+
+ /* copy values into assoc */
+ for (i = 0; i < n_regs; i++) {
+ assocs[i].value = values[i];
+ }
+
+ return 0;
+}
+
+int mshv_create_vcpu(int vm_fd, uint8_t vp_index, int *cpu_fd)
+{
+ int ret;
+ struct mshv_create_vp vp_arg = {
+ .vp_index = vp_index,
+ };
+
+ ret = ioctl(vm_fd, MSHV_CREATE_VP, &vp_arg);
+ if (ret < 0) {
+ error_report("failed to create mshv vcpu: %s", strerror(errno));
+ return -1;
+ }
+
+ *cpu_fd = ret;
+
+ return 0;
+}
+
+void mshv_remove_vcpu(int vm_fd, int cpu_fd)
+{
+ close(cpu_fd);
+}
+
+void mshv_setup_hvcall_args(AccelCPUState *state)
+{
+ void *mem = qemu_memalign(HV_HYP_PAGE_SIZE, 2 * HV_HYP_PAGE_SIZE);
+
+ state->hvcall_args.base = mem;
+ state->hvcall_args.input_page = mem;
+ state->hvcall_args.output_page = (uint8_t *)mem + HV_HYP_PAGE_SIZE;
+}
diff --git a/include/system/mshv_int.h b/include/system/mshv_int.h
index 35386c422f..ff3ab957b5 100644
--- a/include/system/mshv_int.h
+++ b/include/system/mshv_int.h
@@ -89,12 +89,15 @@ int mshv_load_regs(CPUState *cpu);
int mshv_store_regs(CPUState *cpu);
int mshv_set_generic_regs(const CPUState *cpu, const hv_register_assoc *assocs,
size_t n_regs);
+int mshv_get_generic_regs(CPUState *cpu, hv_register_assoc *assocs,
+ size_t n_regs);
int mshv_arch_put_registers(const CPUState *cpu);
void mshv_arch_init_vcpu(CPUState *cpu);
void mshv_arch_destroy_vcpu(CPUState *cpu);
void mshv_arch_amend_proc_features(
union hv_partition_synthetic_processor_features *features);
int mshv_arch_post_init_vm(int vm_fd);
+void mshv_setup_hvcall_args(AccelCPUState *state);
typedef struct mshv_root_hvcall mshv_root_hvcall;
int mshv_hvcall(int fd, const mshv_root_hvcall *args);
diff --git a/target/i386/mshv/mshv-cpu.c b/target/i386/mshv/mshv-cpu.c
index 2bc978deb2..9a80dc34d0 100644
--- a/target/i386/mshv/mshv-cpu.c
+++ b/target/i386/mshv/mshv-cpu.c
@@ -148,103 +148,6 @@ static int translate_gva(const CPUState *cpu, uint64_t gva, uint64_t *gpa,
return 0;
}
-int mshv_set_generic_regs(const CPUState *cpu, const hv_register_assoc *assocs,
- size_t n_regs)
-{
- int cpu_fd = mshv_vcpufd(cpu);
- int vp_index = cpu->cpu_index;
- size_t in_sz, assocs_sz;
- hv_input_set_vp_registers *in = cpu->accel->hvcall_args.input_page;
- struct mshv_root_hvcall args = {0};
- int ret;
-
- /* find out the size of the struct w/ a flexible array at the tail */
- assocs_sz = n_regs * sizeof(hv_register_assoc);
- in_sz = sizeof(hv_input_set_vp_registers) + assocs_sz;
-
- /* fill the input struct */
- memset(in, 0, sizeof(hv_input_set_vp_registers));
- in->vp_index = vp_index;
- memcpy(in->elements, assocs, assocs_sz);
-
- /* create the hvcall envelope */
- args.code = HVCALL_SET_VP_REGISTERS;
- args.in_sz = in_sz;
- args.in_ptr = (uint64_t) in;
- args.reps = (uint16_t) n_regs;
-
- /* perform the call */
- ret = mshv_hvcall(cpu_fd, &args);
- if (ret < 0) {
- error_report("Failed to set registers");
- return -1;
- }
-
- /* assert we set all registers */
- if (args.reps != n_regs) {
- error_report("Failed to set registers: expected %zu elements"
- ", got %u", n_regs, args.reps);
- return -1;
- }
-
- return 0;
-}
-
-static int get_generic_regs(CPUState *cpu, hv_register_assoc *assocs,
- size_t n_regs)
-{
- int cpu_fd = mshv_vcpufd(cpu);
- int vp_index = cpu->cpu_index;
- hv_input_get_vp_registers *in = cpu->accel->hvcall_args.input_page;
- hv_register_value *values = cpu->accel->hvcall_args.output_page;
- size_t in_sz, names_sz, values_sz;
- int i, ret;
- struct mshv_root_hvcall args = {0};
-
- /* find out the size of the struct w/ a flexible array at the tail */
- names_sz = n_regs * sizeof(hv_register_name);
- in_sz = sizeof(hv_input_get_vp_registers) + names_sz;
-
- /* fill the input struct */
- memset(in, 0, sizeof(hv_input_get_vp_registers));
- in->vp_index = vp_index;
- for (i = 0; i < n_regs; i++) {
- in->names[i] = assocs[i].name;
- }
-
- /* determine size of value output buffer */
- values_sz = n_regs * sizeof(union hv_register_value);
-
- /* create the hvcall envelope */
- args.code = HVCALL_GET_VP_REGISTERS;
- args.in_sz = in_sz;
- args.in_ptr = (uint64_t) in;
- args.out_sz = values_sz;
- args.out_ptr = (uint64_t) values;
- args.reps = (uint16_t) n_regs;
-
- /* perform the call */
- ret = mshv_hvcall(cpu_fd, &args);
- if (ret < 0) {
- error_report("Failed to retrieve registers");
- return -1;
- }
-
- /* assert we got all registers */
- if (args.reps != n_regs) {
- error_report("Failed to retrieve registers: expected %zu elements"
- ", got %u", n_regs, args.reps);
- return -1;
- }
-
- /* copy values into assoc */
- for (i = 0; i < n_regs; i++) {
- assocs[i].value = values[i];
- }
-
- return 0;
-}
-
static int set_standard_regs(const CPUState *cpu)
{
X86CPU *x86cpu = X86_CPU(cpu);
@@ -334,7 +237,7 @@ int mshv_get_standard_regs(CPUState *cpu)
for (size_t i = 0; i < n_regs; i++) {
assocs[i].name = STANDARD_REGISTER_NAMES[i];
}
- ret = get_generic_regs(cpu, assocs, n_regs);
+ ret = mshv_get_generic_regs(cpu, assocs, n_regs);
if (ret < 0) {
error_report("failed to get standard registers");
return -1;
@@ -412,7 +315,7 @@ int mshv_get_special_regs(CPUState *cpu)
for (size_t i = 0; i < n_regs; i++) {
assocs[i].name = SPECIAL_REGISTER_NAMES[i];
}
- ret = get_generic_regs(cpu, assocs, n_regs);
+ ret = mshv_get_generic_regs(cpu, assocs, n_regs);
if (ret < 0) {
error_report("failed to get special registers");
return -errno;
@@ -1525,29 +1428,6 @@ int mshv_run_vcpu(int vm_fd, CPUState *cpu, hv_message *msg, MshvVmExit *exit)
return 0;
}
-void mshv_remove_vcpu(int vm_fd, int cpu_fd)
-{
- close(cpu_fd);
-}
-
-
-int mshv_create_vcpu(int vm_fd, uint8_t vp_index, int *cpu_fd)
-{
- int ret;
- struct mshv_create_vp vp_arg = {
- .vp_index = vp_index,
- };
- ret = ioctl(vm_fd, MSHV_CREATE_VP, &vp_arg);
- if (ret < 0) {
- error_report("failed to create mshv vcpu: %s", strerror(errno));
- return -1;
- }
-
- *cpu_fd = ret;
-
- return 0;
-}
-
static void read_segment_descriptor(CPUState *cpu,
struct x86_segment_descriptor *desc,
enum X86Seg seg_idx)
@@ -1580,8 +1460,6 @@ void mshv_arch_init_vcpu(CPUState *cpu)
X86CPU *x86_cpu = X86_CPU(cpu);
CPUX86State *env = &x86_cpu->env;
AccelCPUState *state = cpu->accel;
- size_t page = HV_HYP_PAGE_SIZE;
- void *mem = qemu_memalign(page, 2 * page);
/* sanity check, to make sure we don't overflow the page */
QEMU_BUILD_BUG_ON((MAX_REGISTER_COUNT
@@ -1589,9 +1467,7 @@ void mshv_arch_init_vcpu(CPUState *cpu)
+ sizeof(hv_input_get_vp_registers)
> HV_HYP_PAGE_SIZE));
- state->hvcall_args.base = mem;
- state->hvcall_args.input_page = mem;
- state->hvcall_args.output_page = (uint8_t *)mem + page;
+ mshv_setup_hvcall_args(state);
env->emu_mmio_buf = g_new(char, 4096);
}
--
2.43.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 04/14] meson, target/arm/mshv: Enable arm64 build & add initial MSHV support
2026-03-11 15:15 [PATCH 00/14] Add ARM64 support for MSHV accelerator Anirudh Rayabharam (Microsoft)
` (2 preceding siblings ...)
2026-03-11 15:15 ` [PATCH 03/14] accel/mshv: extract common CPU register helpers Anirudh Rayabharam
@ 2026-03-11 15:15 ` Anirudh Rayabharam
2026-03-11 15:15 ` [PATCH 05/14] target/arm/mshv: implement vcpu state operations for ARM64 Anirudh Rayabharam
` (11 subsequent siblings)
15 siblings, 0 replies; 38+ messages in thread
From: Anirudh Rayabharam @ 2026-03-11 15:15 UTC (permalink / raw)
To: qemu-devel
Cc: Magnus Kulke, Wei Liu, Paolo Bonzini, Marc-André Lureau,
Daniel P. Berrangé, Philippe Mathieu-Daudé,
Peter Maydell, Anirudh Rayabharam, Aastha Rawat, qemu-arm
From: Aastha Rawat <aastharawat@linux.microsoft.com>
Enable the build of the MSHV accelerator for arm64 in the Meson build
system. Introduce initial files and stub implementations to support MSHV
for the ARM target.
Signed-off-by: Aastha Rawat <aastharawat@linux.microsoft.com>
---
meson.build | 7 +++---
target/arm/meson.build | 1 +
target/arm/mshv/meson.build | 7 ++++++
target/arm/mshv/mshv-all.c | 54 +++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 66 insertions(+), 3 deletions(-)
diff --git a/meson.build b/meson.build
index ed82247111..bf12fda40f 100644
--- a/meson.build
+++ b/meson.build
@@ -303,7 +303,8 @@ if cpu == 'aarch64'
accelerator_targets += {
'CONFIG_HVF': ['aarch64-softmmu'],
'CONFIG_NITRO': ['aarch64-softmmu'],
- 'CONFIG_WHPX': ['aarch64-softmmu']
+ 'CONFIG_WHPX': ['aarch64-softmmu'],
+ 'CONFIG_MSHV': ['aarch64-softmmu'],
}
elif cpu == 'x86_64'
accelerator_targets += {
@@ -855,8 +856,8 @@ if get_option('kvm').allowed() and host_os == 'linux'
endif
if get_option('mshv').allowed() and host_os == 'linux'
- if get_option('mshv').enabled() and host_machine.cpu() != 'x86_64'
- error('mshv accelerator requires x64_64 host')
+ if get_option('mshv').enabled() and not (host_machine.cpu() in [ 'x86_64', 'aarch64' ])
+ error('The mshv accelerator requires an x86_64 or aarch64 host')
endif
accelerators += 'CONFIG_MSHV'
endif
diff --git a/target/arm/meson.build b/target/arm/meson.build
index 6e0e504a40..8aa8cac137 100644
--- a/target/arm/meson.build
+++ b/target/arm/meson.build
@@ -59,6 +59,7 @@ arm_common_system_ss.add(files(
subdir('hvf')
subdir('whpx')
+subdir('mshv')
if 'CONFIG_TCG' in config_all_accel
subdir('tcg')
diff --git a/target/arm/mshv/meson.build b/target/arm/mshv/meson.build
new file mode 100644
index 0000000000..169643691e
--- /dev/null
+++ b/target/arm/mshv/meson.build
@@ -0,0 +1,7 @@
+arm_mshv_ss = ss.source_set()
+
+arm_mshv_ss.add(files(
+ 'mshv-all.c',
+))
+
+arm_system_ss.add_all(when: 'CONFIG_MSHV', if_true: arm_mshv_ss)
diff --git a/target/arm/mshv/mshv-all.c b/target/arm/mshv/mshv-all.c
new file mode 100644
index 0000000000..1c82e2c593
--- /dev/null
+++ b/target/arm/mshv/mshv-all.c
@@ -0,0 +1,54 @@
+/*
+ * QEMU MSHV support
+ *
+ * Copyright Microsoft, Corp. 2026
+ *
+ * Authors: Aastha Rawat <aastharawat@linux.microsoft.com>
+ * Anirudh Rayabharam <anirudh@anirudhrb.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "system/mshv.h"
+#include "system/mshv_int.h"
+
+int mshv_load_regs(CPUState *cpu)
+{
+ return 0;
+}
+
+int mshv_arch_put_registers(const CPUState *cpu)
+{
+ return 0;
+}
+
+int mshv_run_vcpu(int vm_fd, CPUState *cpu, hv_message *msg, MshvVmExit *exit)
+{
+ return 0;
+}
+
+void mshv_arch_init_vcpu(CPUState *cpu)
+{
+
+}
+
+void mshv_arch_destroy_vcpu(CPUState *cpu)
+{
+
+}
+
+void mshv_init_mmio_emu(void)
+{
+
+}
+
+void mshv_arch_amend_proc_features(
+ union hv_partition_synthetic_processor_features *features)
+{
+
+}
+
+int mshv_arch_post_init_vm(int vm_fd)
+{
+ return 0;
+}
--
2.43.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 05/14] target/arm/mshv: implement vcpu state operations for ARM64
2026-03-11 15:15 [PATCH 00/14] Add ARM64 support for MSHV accelerator Anirudh Rayabharam (Microsoft)
` (3 preceding siblings ...)
2026-03-11 15:15 ` [PATCH 04/14] meson, target/arm/mshv: Enable arm64 build & add initial MSHV support Anirudh Rayabharam
@ 2026-03-11 15:15 ` Anirudh Rayabharam
2026-03-11 15:15 ` [PATCH 06/14] target/arm/mshv: implement -cpu host for MSHV Anirudh Rayabharam
` (10 subsequent siblings)
15 siblings, 0 replies; 38+ messages in thread
From: Anirudh Rayabharam @ 2026-03-11 15:15 UTC (permalink / raw)
To: qemu-devel
Cc: Magnus Kulke, Wei Liu, Paolo Bonzini, Marc-André Lureau,
Daniel P. Berrangé, Philippe Mathieu-Daudé,
Peter Maydell, Anirudh Rayabharam, Aastha Rawat, qemu-arm
From: Aastha Rawat <aastharawat@linux.microsoft.com>
Add support for reading and writing ARM64 CPU registers in the MSHV
accelerator. This includes functions to set and get registers,
initialize and destroy VCPU state, and manage register state
synchronization between QEMU and hypervisor.
Signed-off-by: Aastha Rawat <aastharawat@linux.microsoft.com>
---
include/hw/hyperv/hvgdk_mini.h | 42 +++++++++++++
target/arm/mshv/mshv-all.c | 138 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 180 insertions(+)
diff --git a/include/hw/hyperv/hvgdk_mini.h b/include/hw/hyperv/hvgdk_mini.h
index cb52cc9de2..dfe94050f4 100644
--- a/include/hw/hyperv/hvgdk_mini.h
+++ b/include/hw/hyperv/hvgdk_mini.h
@@ -13,6 +13,46 @@ typedef enum hv_register_name {
/* Pending Interruption Register */
HV_REGISTER_PENDING_INTERRUPTION = 0x00010002,
+#if defined(__aarch64__)
+ HV_ARM64_REGISTER_XZR = 0x0002FFFE,
+ HV_ARM64_REGISTER_X0 = 0x00020000,
+ HV_ARM64_REGISTER_X1 = 0x00020001,
+ HV_ARM64_REGISTER_X2 = 0x00020002,
+ HV_ARM64_REGISTER_X3 = 0x00020003,
+ HV_ARM64_REGISTER_X4 = 0x00020004,
+ HV_ARM64_REGISTER_X5 = 0x00020005,
+ HV_ARM64_REGISTER_X6 = 0x00020006,
+ HV_ARM64_REGISTER_X7 = 0x00020007,
+ HV_ARM64_REGISTER_X8 = 0x00020008,
+ HV_ARM64_REGISTER_X9 = 0x00020009,
+ HV_ARM64_REGISTER_X10 = 0x0002000A,
+ HV_ARM64_REGISTER_X11 = 0x0002000B,
+ HV_ARM64_REGISTER_X12 = 0x0002000C,
+ HV_ARM64_REGISTER_X13 = 0x0002000D,
+ HV_ARM64_REGISTER_X14 = 0x0002000E,
+ HV_ARM64_REGISTER_X15 = 0x0002000F,
+ HV_ARM64_REGISTER_X16 = 0x00020010,
+ HV_ARM64_REGISTER_X17 = 0x00020011,
+ HV_ARM64_REGISTER_X18 = 0x00020012,
+ HV_ARM64_REGISTER_X19 = 0x00020013,
+ HV_ARM64_REGISTER_X20 = 0x00020014,
+ HV_ARM64_REGISTER_X21 = 0x00020015,
+ HV_ARM64_REGISTER_X22 = 0x00020016,
+ HV_ARM64_REGISTER_X23 = 0x00020017,
+ HV_ARM64_REGISTER_X24 = 0x00020018,
+ HV_ARM64_REGISTER_X25 = 0x00020019,
+ HV_ARM64_REGISTER_X26 = 0x0002001A,
+ HV_ARM64_REGISTER_X27 = 0x0002001B,
+ HV_ARM64_REGISTER_X28 = 0x0002001C,
+ HV_ARM64_REGISTER_FP = 0x0002001D,
+ HV_ARM64_REGISTER_LR = 0x0002001E,
+ HV_ARM64_REGISTER_PC = 0x00020022,
+
+ /* AArch64 System Register Descriptions: General system control registers */
+ HV_ARM64_REGISTER_MIDR_EL1 = 0x00040051,
+ HV_ARM64_REGISTER_MPIDR_EL1 = 0x00040001,
+
+#elif defined(__x86_64__)
/* X64 User-Mode Registers */
HV_X64_REGISTER_RAX = 0x00020000,
HV_X64_REGISTER_RCX = 0x00020001,
@@ -157,6 +197,8 @@ typedef enum hv_register_name {
/* Other MSRs */
HV_X64_REGISTER_MSR_IA32_MISC_ENABLE = 0x000800A0,
+#endif
+
/* Misc */
HV_REGISTER_GUEST_OS_ID = 0x00090002,
HV_REGISTER_REFERENCE_TSC = 0x00090017,
diff --git a/target/arm/mshv/mshv-all.c b/target/arm/mshv/mshv-all.c
index 1c82e2c593..ad9cb267a8 100644
--- a/target/arm/mshv/mshv-all.c
+++ b/target/arm/mshv/mshv-all.c
@@ -9,16 +9,146 @@
* SPDX-License-Identifier: GPL-2.0-or-later
*/
+
+#include "qemu/osdep.h"
+#include <sys/ioctl.h>
+
+#include "qemu/error-report.h"
+#include "qemu/memalign.h"
+
+#include "system/cpus.h"
+#include "target/arm/cpu.h"
+
#include "system/mshv.h"
#include "system/mshv_int.h"
+#include "hw/hyperv/hvgdk_mini.h"
+
+static enum hv_register_name STANDARD_REGISTER_NAMES[32] = {
+ HV_ARM64_REGISTER_X0,
+ HV_ARM64_REGISTER_X1,
+ HV_ARM64_REGISTER_X2,
+ HV_ARM64_REGISTER_X3,
+ HV_ARM64_REGISTER_X4,
+ HV_ARM64_REGISTER_X5,
+ HV_ARM64_REGISTER_X6,
+ HV_ARM64_REGISTER_X7,
+ HV_ARM64_REGISTER_X8,
+ HV_ARM64_REGISTER_X9,
+ HV_ARM64_REGISTER_X10,
+ HV_ARM64_REGISTER_X11,
+ HV_ARM64_REGISTER_X12,
+ HV_ARM64_REGISTER_X13,
+ HV_ARM64_REGISTER_X14,
+ HV_ARM64_REGISTER_X15,
+ HV_ARM64_REGISTER_X16,
+ HV_ARM64_REGISTER_X17,
+ HV_ARM64_REGISTER_X18,
+ HV_ARM64_REGISTER_X19,
+ HV_ARM64_REGISTER_X20,
+ HV_ARM64_REGISTER_X21,
+ HV_ARM64_REGISTER_X22,
+ HV_ARM64_REGISTER_X23,
+ HV_ARM64_REGISTER_X24,
+ HV_ARM64_REGISTER_X25,
+ HV_ARM64_REGISTER_X26,
+ HV_ARM64_REGISTER_X27,
+ HV_ARM64_REGISTER_X28,
+ HV_ARM64_REGISTER_FP,
+ HV_ARM64_REGISTER_LR,
+ HV_ARM64_REGISTER_PC,
+};
+
+static int set_standard_regs(const CPUState *cpu)
+{
+ size_t n_regs = ARRAY_SIZE(STANDARD_REGISTER_NAMES);
+ struct hv_register_assoc *assocs;
+ int ret;
+ ARMCPU *arm_cpu = ARM_CPU(cpu);
+ CPUARMState *env = &arm_cpu->env;
+
+ assocs = g_new0(hv_register_assoc, n_regs);
+
+ for (size_t i = 0; i < n_regs - 1; i++) {
+ assocs[i].name = STANDARD_REGISTER_NAMES[i];
+ assocs[i].value.reg64 = env->xregs[i];
+ }
+
+ /* Last register is the program counter */
+ assocs[n_regs - 1].name = STANDARD_REGISTER_NAMES[n_regs - 1];
+ assocs[n_regs - 1].value.reg64 = env->pc;
+
+ ret = mshv_set_generic_regs(cpu, assocs, n_regs);
+ if (ret < 0) {
+ error_report("failed to set standard registers");
+ g_free(assocs);
+ return -1;
+ }
+
+ g_free(assocs);
+
+ return 0;
+}
+
+static void populate_standard_regs(const hv_register_assoc *assocs,
+ CPUARMState *env)
+{
+ size_t n_regs = ARRAY_SIZE(STANDARD_REGISTER_NAMES);
+
+ for (size_t i = 0; i < n_regs - 1; i++) {
+ env->xregs[i] = assocs[i].value.reg64;
+ }
+
+ /* Last register is the program counter */
+ env->pc = assocs[n_regs - 1].value.reg64;
+}
int mshv_load_regs(CPUState *cpu)
{
+ int ret;
+
+ ret = mshv_get_standard_regs(cpu);
+ if (ret < 0) {
+ error_report("Failed to load standard registers");
+ return -1;
+ }
+
+ return 0;
+}
+
+int mshv_get_standard_regs(CPUState *cpu)
+{
+ size_t n_regs = ARRAY_SIZE(STANDARD_REGISTER_NAMES);
+ struct hv_register_assoc *assocs;
+ int ret;
+ ARMCPU *arm_cpu = ARM_CPU(cpu);
+ CPUARMState *env = &arm_cpu->env;
+
+ assocs = g_new0(hv_register_assoc, n_regs);
+ for (size_t i = 0; i < n_regs; i++) {
+ assocs[i].name = STANDARD_REGISTER_NAMES[i];
+ }
+ ret = mshv_get_generic_regs(cpu, assocs, n_regs);
+ if (ret < 0) {
+ error_report("failed to get standard registers");
+ g_free(assocs);
+ return -1;
+ }
+
+ populate_standard_regs(assocs, env);
+
+ g_free(assocs);
return 0;
}
int mshv_arch_put_registers(const CPUState *cpu)
{
+ int ret;
+
+ ret = set_standard_regs(cpu);
+ if (ret < 0) {
+ return ret;
+ }
+
return 0;
}
@@ -29,12 +159,20 @@ int mshv_run_vcpu(int vm_fd, CPUState *cpu, hv_message *msg, MshvVmExit *exit)
void mshv_arch_init_vcpu(CPUState *cpu)
{
+ AccelCPUState *state = cpu->accel;
+ mshv_setup_hvcall_args(state);
}
void mshv_arch_destroy_vcpu(CPUState *cpu)
{
+ AccelCPUState *state = cpu->accel;
+
+ if (state->hvcall_args.base) {
+ qemu_vfree(state->hvcall_args.base);
+ }
+ state->hvcall_args = (MshvHvCallArgs){0};
}
void mshv_init_mmio_emu(void)
--
2.43.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 06/14] target/arm/mshv: implement -cpu host for MSHV
2026-03-11 15:15 [PATCH 00/14] Add ARM64 support for MSHV accelerator Anirudh Rayabharam (Microsoft)
` (4 preceding siblings ...)
2026-03-11 15:15 ` [PATCH 05/14] target/arm/mshv: implement vcpu state operations for ARM64 Anirudh Rayabharam
@ 2026-03-11 15:15 ` Anirudh Rayabharam
2026-03-11 15:15 ` [PATCH 07/14] accel/mshv: add arch-specific accelerator init hook Anirudh Rayabharam (Microsoft)
` (9 subsequent siblings)
15 siblings, 0 replies; 38+ messages in thread
From: Anirudh Rayabharam @ 2026-03-11 15:15 UTC (permalink / raw)
To: qemu-devel
Cc: Magnus Kulke, Wei Liu, Paolo Bonzini, Marc-André Lureau,
Daniel P. Berrangé, Philippe Mathieu-Daudé,
Peter Maydell, Anirudh Rayabharam, Aastha Rawat, qemu-arm
From: Aastha Rawat <aastharawat@linux.microsoft.com>
This commit enables support for the `-cpu host` option with MSHV
accelerator on ARM64. The implementation queries the partition's CPU's
ID registers and features via hypervisor interface, allowing to pass all
CPU capabilities for the host CPU to the guest.
Replace preprocessor config checks with runtime calls to mshv_enabled(),
kvm_enabled(), etc. This ensures that the correct accelerator is
selected at runtime when both MSHV and KVM are enabled.
Signed-off-by: Aastha Rawat <aastharawat@linux.microsoft.com>
---
accel/mshv/mshv-all.c | 3 +-
hw/arm/virt.c | 3 +-
include/hw/hyperv/hvgdk_mini.h | 17 ++++
include/hw/hyperv/hvhdk.h | 10 +++
include/system/hw_accel.h | 3 +-
target/arm/cpu.c | 5 +-
target/arm/cpu64.c | 24 ++---
target/arm/mshv/mshv-all.c | 200 +++++++++++++++++++++++++++++++++++++++++
target/arm/mshv_arm.h | 18 ++++
9 files changed, 268 insertions(+), 15 deletions(-)
diff --git a/accel/mshv/mshv-all.c b/accel/mshv/mshv-all.c
index 3b8b9ef116..c6dad18d2f 100644
--- a/accel/mshv/mshv-all.c
+++ b/accel/mshv/mshv-all.c
@@ -443,13 +443,14 @@ 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;
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 7456614d05..34eb5248a9 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -50,6 +50,7 @@
#include "system/kvm.h"
#include "system/hvf.h"
#include "system/whpx.h"
+#include "system/mshv.h"
#include "system/qtest.h"
#include "system/system.h"
#include "hw/core/loader.h"
@@ -3450,7 +3451,7 @@ static GPtrArray *virt_get_valid_cpu_types(const MachineState *ms)
if (target_aarch64()) {
g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("cortex-a53")));
g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("cortex-a57")));
- if (kvm_enabled() || hvf_enabled()) {
+ if (kvm_enabled() || hvf_enabled() || mshv_enabled()) {
g_ptr_array_add(vct, g_strdup(ARM_CPU_TYPE_NAME("host")));
}
}
diff --git a/include/hw/hyperv/hvgdk_mini.h b/include/hw/hyperv/hvgdk_mini.h
index dfe94050f4..d56be0d70f 100644
--- a/include/hw/hyperv/hvgdk_mini.h
+++ b/include/hw/hyperv/hvgdk_mini.h
@@ -48,6 +48,20 @@ typedef enum hv_register_name {
HV_ARM64_REGISTER_LR = 0x0002001E,
HV_ARM64_REGISTER_PC = 0x00020022,
+ /* AArch64 System Register Descriptions: ID Registers */
+ HV_ARM64_REGISTER_ID_MIDR_EL1 = 0x00022000,
+ HV_ARM64_REGISTER_ID_MPIDR_EL1 = 0x00022005,
+ HV_ARM64_REGISTER_ID_AA64_PFR0_EL1 = 0x00022020,
+ HV_ARM64_REGISTER_ID_AA64_PFR1_EL1 = 0x00022021,
+ HV_ARM64_REGISTER_ID_AA64_ISAR0_EL1 = 0x00022030,
+ HV_ARM64_REGISTER_ID_AA64_ISAR1_EL1 = 0x00022031,
+ HV_ARM64_REGISTER_ID_AA64_ISAR2_EL1 = 0x00022032,
+ HV_ARM64_REGISTER_ID_AA64_MMFR0_EL1 = 0x00022038,
+ HV_ARM64_REGISTER_ID_AA64_MMFR1_EL1 = 0x00022039,
+ HV_ARM64_REGISTER_ID_AA64_MMFR2_EL1 = 0x0002203a,
+ HV_ARM64_REGISTER_ID_AA64_DFR0_EL1 = 0x00022028,
+ HV_ARM64_REGISTER_ID_AA64_DFR1_EL1 = 0x00022029,
+
/* AArch64 System Register Descriptions: General system control registers */
HV_ARM64_REGISTER_MIDR_EL1 = 0x00040051,
HV_ARM64_REGISTER_MPIDR_EL1 = 0x00040001,
@@ -841,6 +855,9 @@ struct hv_cpuid {
#define HV_HYP_PAGE_SIZE BIT(HV_HYP_PAGE_SHIFT)
#define HV_HYP_PAGE_MASK (~(HV_HYP_PAGE_SIZE - 1))
+#define HV_ANY_VP ((uint32_t)-1)
+#define HV_VTL_ALL 0xF
+
#define HVCALL_GET_PARTITION_PROPERTY 0x0044
#define HVCALL_SET_PARTITION_PROPERTY 0x0045
#define HVCALL_GET_VP_REGISTERS 0x0050
diff --git a/include/hw/hyperv/hvhdk.h b/include/hw/hyperv/hvhdk.h
index 866c8211bf..2e1ef80972 100644
--- a/include/hw/hyperv/hvhdk.h
+++ b/include/hw/hyperv/hvhdk.h
@@ -18,6 +18,16 @@ struct hv_input_set_partition_property {
uint64_t property_value;
};
+struct hv_input_get_partition_property {
+ uint64_t partition_id;
+ uint32_t property_code; /* enum hv_partition_property_code */
+ uint32_t padding;
+};
+
+struct hv_output_get_partition_property {
+ uint64_t property_value;
+};
+
union hv_partition_synthetic_processor_features {
uint64_t as_uint64[HV_PARTITION_SYNTHETIC_PROCESSOR_FEATURES_BANKS];
diff --git a/include/system/hw_accel.h b/include/system/hw_accel.h
index f0c10b6d80..614ea60be3 100644
--- a/include/system/hw_accel.h
+++ b/include/system/hw_accel.h
@@ -51,7 +51,8 @@ static inline bool hwaccel_enabled(void)
return hvf_enabled()
|| kvm_enabled()
|| nvmm_enabled()
- || whpx_enabled();
+ || whpx_enabled()
+ || mshv_enabled();
}
#endif /* QEMU_HW_ACCEL_H */
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 7e3e84b4bb..4b1e9750e6 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -46,6 +46,7 @@
#include "system/tcg.h"
#include "system/qtest.h"
#include "system/hw_accel.h"
+#include "system/mshv.h"
#include "kvm_arm.h"
#include "disas/capstone.h"
#include "fpu/softfloat.h"
@@ -1629,8 +1630,8 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
* this is the first point where we can report it.
*/
if (cpu->host_cpu_probe_failed) {
- if (!kvm_enabled() && !hvf_enabled()) {
- error_setg(errp, "The 'host' CPU type can only be used with KVM or HVF");
+ if (!kvm_enabled() && !hvf_enabled() && !mshv_enabled()) {
+ error_setg(errp, "The 'host' CPU type can only be used with KVM, HVF, or MSHV");
} else {
error_setg(errp, "Failed to retrieve host CPU features");
}
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index d6feba220e..59cb23dd99 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -26,12 +26,14 @@
#include "qemu/units.h"
#include "system/kvm.h"
#include "system/hvf.h"
+#include "system/mshv.h"
#include "system/whpx.h"
#include "system/hw_accel.h"
#include "system/qtest.h"
#include "system/tcg.h"
#include "kvm_arm.h"
#include "hvf_arm.h"
+#include "mshv_arm.h"
#include "whpx_arm.h"
#include "qapi/visitor.h"
#include "hw/core/qdev-properties.h"
@@ -821,16 +823,18 @@ static void aarch64_host_initfn(Object *obj)
}
#endif
-#if defined(CONFIG_KVM)
- kvm_arm_set_cpu_features_from_host(cpu);
- aarch64_add_sve_properties(obj);
-#elif defined(CONFIG_HVF)
- hvf_arm_set_cpu_features_from_host(cpu);
-#elif defined(CONFIG_WHPX)
- whpx_arm_set_cpu_features_from_host(cpu);
-#else
- g_assert_not_reached();
-#endif
+ if (mshv_enabled()) {
+ mshv_arm_set_cpu_features_from_host(cpu);
+ } else if (kvm_enabled()) {
+ kvm_arm_set_cpu_features_from_host(cpu);
+ aarch64_add_sve_properties(obj);
+ } else if (hvf_enabled()) {
+ hvf_arm_set_cpu_features_from_host(cpu);
+ } else if (whpx_enabled()) {
+ whpx_arm_set_cpu_features_from_host(cpu);
+ } else {
+ g_assert_not_reached();
+ }
if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
aarch64_add_pauth_properties(obj);
}
diff --git a/target/arm/mshv/mshv-all.c b/target/arm/mshv/mshv-all.c
index ad9cb267a8..0102297305 100644
--- a/target/arm/mshv/mshv-all.c
+++ b/target/arm/mshv/mshv-all.c
@@ -18,10 +18,23 @@
#include "system/cpus.h"
#include "target/arm/cpu.h"
+#include "target/arm/internals.h"
+#include "target/arm/mshv_arm.h"
#include "system/mshv.h"
#include "system/mshv_int.h"
#include "hw/hyperv/hvgdk_mini.h"
+#include "hw/hyperv/hvhdk_mini.h"
+
+typedef struct ARMHostCPUFeatures {
+ ARMISARegisters isar;
+ uint64_t features;
+ uint64_t midr;
+ uint32_t reset_sctlr;
+ const char *dtb_compatible;
+} ARMHostCPUFeatures;
+
+static ARMHostCPUFeatures arm_host_cpu_features;
static enum hv_register_name STANDARD_REGISTER_NAMES[32] = {
HV_ARM64_REGISTER_X0,
@@ -190,3 +203,190 @@ int mshv_arch_post_init_vm(int vm_fd)
{
return 0;
}
+
+static uint32_t mshv_arm_get_ipa_bit_size(int mshv_fd)
+{
+ 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 = HV_PARTITION_PROPERTY_PHYSICAL_ADDRESS_WIDTH;
+
+ args.code = HVCALL_GET_PARTITION_PROPERTY;
+ args.in_sz = sizeof(in);
+ args.in_ptr = (uint64_t)∈
+ args.out_sz = sizeof(out);
+ args.out_ptr = (uint64_t)&out;
+
+ ret = mshv_hvcall(mshv_fd, &args);
+
+ if (ret < 0) {
+ error_report("Failed to get IPA size");
+ exit(1);
+ }
+
+ return out.property_value;
+}
+
+static void clamp_id_aa64mmfr0_parange_to_ipa_size(int mshv_fd, ARMISARegisters *isar)
+{
+ uint32_t ipa_size = mshv_arm_get_ipa_bit_size(mshv_fd);
+ uint64_t id_aa64mmfr0;
+
+ /* Clamp down the PARange to the IPA size the kernel supports. */
+ uint8_t index = round_down_to_parange_index(ipa_size);
+ id_aa64mmfr0 = GET_IDREG(isar, ID_AA64MMFR0);
+ id_aa64mmfr0 = (id_aa64mmfr0 & ~R_ID_AA64MMFR0_PARANGE_MASK) | index;
+ SET_IDREG(isar, ID_AA64MMFR0, id_aa64mmfr0);
+}
+
+static int mshv_get_partition_regs(int vm_fd, hv_register_name *names,
+ hv_register_value *values, size_t n_regs)
+{
+ int ret = 0;
+ size_t in_sz, names_sz, values_sz;
+ void *in_buffer = qemu_memalign(HV_HYP_PAGE_SIZE, HV_HYP_PAGE_SIZE);
+ void *out_buffer = qemu_memalign(HV_HYP_PAGE_SIZE, HV_HYP_PAGE_SIZE);
+ hv_input_get_vp_registers *in = in_buffer;
+
+ struct mshv_root_hvcall args = {0};
+
+ names_sz = n_regs * sizeof(hv_register_name);
+ in_sz = sizeof(hv_input_get_vp_registers) + names_sz;
+
+ memset(in, 0, HV_HYP_PAGE_SIZE);
+
+ in->vp_index = HV_ANY_VP;
+ in->input_vtl.target_vtl = HV_VTL_ALL;
+ in->input_vtl.use_target_vtl = 1;
+
+ for (int i = 0; i < n_regs; i++) {
+ in->names[i] = names[i];
+ }
+
+ values_sz = n_regs * sizeof(hv_register_value);
+
+ args.code = HVCALL_GET_VP_REGISTERS;
+ args.in_sz = in_sz;
+ args.in_ptr = (uintptr_t)(in_buffer);
+ args.out_sz = values_sz;
+ args.out_ptr = (uintptr_t)(out_buffer);
+ args.reps = (uint16_t) n_regs;
+
+ ret = mshv_hvcall(vm_fd, &args);
+
+ if (ret == 0) {
+ memcpy(values, out_buffer, values_sz);
+ }
+
+ qemu_vfree(in_buffer);
+ qemu_vfree(out_buffer);
+
+ return ret;
+}
+
+static bool mshv_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
+{
+ int mshv_fd = mshv_state->fd;
+ int vm_fd = mshv_state->vm;
+ int i, ret;
+ bool success = true;
+ uint64_t pfr0, pfr1;
+ gchar *contents = NULL;
+
+ const struct {
+ hv_register_name name;
+ int isar_idx;
+ } regs[] = {
+ { HV_ARM64_REGISTER_ID_AA64_PFR0_EL1, ID_AA64PFR0_EL1_IDX },
+ { HV_ARM64_REGISTER_ID_AA64_PFR1_EL1, ID_AA64PFR1_EL1_IDX },
+ { HV_ARM64_REGISTER_ID_AA64_ISAR0_EL1, ID_AA64ISAR0_EL1_IDX },
+ { HV_ARM64_REGISTER_ID_AA64_ISAR1_EL1, ID_AA64ISAR1_EL1_IDX },
+ { HV_ARM64_REGISTER_ID_AA64_ISAR2_EL1, ID_AA64ISAR2_EL1_IDX },
+ { HV_ARM64_REGISTER_ID_AA64_MMFR0_EL1, ID_AA64MMFR0_EL1_IDX },
+ { HV_ARM64_REGISTER_ID_AA64_MMFR1_EL1, ID_AA64MMFR1_EL1_IDX },
+ { HV_ARM64_REGISTER_ID_AA64_MMFR2_EL1, ID_AA64MMFR2_EL1_IDX },
+ { HV_ARM64_REGISTER_ID_AA64_DFR0_EL1, ID_AA64DFR0_EL1_IDX },
+ { HV_ARM64_REGISTER_ID_AA64_DFR1_EL1, ID_AA64DFR1_EL1_IDX },
+ };
+
+ size_t n_regs = ARRAY_SIZE(regs);
+ hv_register_name *reg_names = g_new(hv_register_name, n_regs);
+ hv_register_value *reg_values = g_new(hv_register_value, n_regs);
+
+ for (i = 0; i < n_regs; i++) {
+ reg_names[i] = regs[i].name;
+ }
+
+ ret = mshv_get_partition_regs(vm_fd, reg_names, reg_values, n_regs);
+
+ if (ret < 0) {
+ error_report("Failed to get host ID registers");
+ success = false;
+ goto out;
+ }
+
+ for (i = 0; i < n_regs; i++) {
+ ahcf->isar.idregs[regs[i].isar_idx] = reg_values[i].reg64;
+ }
+
+ /* Read MIDR_EL1 from sysfs */
+ if (g_file_get_contents("/sys/devices/system/cpu/cpu0/regs/identification/midr_el1",
+ &contents, NULL, NULL)) {
+ ahcf->midr = g_ascii_strtoull(contents, NULL, 0);
+ } else {
+ error_report("Failed to read MIDR_EL1 from sysfs");
+ success = false;
+ goto out;
+ }
+
+ ahcf->dtb_compatible = "arm,armv8";
+ ahcf->features = (1ULL << ARM_FEATURE_V8) |
+ (1ULL << ARM_FEATURE_AARCH64) |
+ (1ULL << ARM_FEATURE_PMU) |
+ (1ULL << ARM_FEATURE_GENERIC_TIMER) |
+ (1ULL << ARM_FEATURE_NEON);
+
+ clamp_id_aa64mmfr0_parange_to_ipa_size(mshv_fd, &ahcf->isar);
+
+ /* SVE (Scalable Vector Extension) and SME (Scalable Matrix Extension)
+ * require specific context switch logic in the accelerator.
+ * Mask them out for now to ensure stability.
+ */
+ /* Mask SVE in PFR0 */
+ pfr0 = GET_IDREG(&ahcf->isar, ID_AA64PFR0);
+ pfr0 &= ~R_ID_AA64PFR0_SVE_MASK;
+ SET_IDREG(&ahcf->isar, ID_AA64PFR0, pfr0);
+
+ /* Mask SME in PFR1 */
+ pfr1 = GET_IDREG(&ahcf->isar, ID_AA64PFR1);
+ pfr1 &= ~R_ID_AA64PFR1_SME_MASK;
+ SET_IDREG(&ahcf->isar, ID_AA64PFR1, pfr1);
+
+out:
+ g_free(contents);
+ g_free(reg_names);
+ g_free(reg_values);
+ return success;
+}
+
+void mshv_arm_set_cpu_features_from_host(ARMCPU *cpu)
+{
+ if (!arm_host_cpu_features.dtb_compatible) {
+ if (!mshv_enabled() ||
+ !mshv_arm_get_host_cpu_features(&arm_host_cpu_features)) {
+ /* We can't report this error yet, so flag that we need to
+ * in arm_cpu_realizefn().
+ */
+ cpu->host_cpu_probe_failed = true;
+ return;
+ }
+ }
+
+ cpu->dtb_compatible = arm_host_cpu_features.dtb_compatible;
+ cpu->isar = arm_host_cpu_features.isar;
+ cpu->env.features = arm_host_cpu_features.features;
+ cpu->midr = arm_host_cpu_features.midr;
+ cpu->reset_sctlr = arm_host_cpu_features.reset_sctlr;
+}
diff --git a/target/arm/mshv_arm.h b/target/arm/mshv_arm.h
new file mode 100644
index 0000000000..a03f9a4405
--- /dev/null
+++ b/target/arm/mshv_arm.h
@@ -0,0 +1,18 @@
+/*
+ * QEMU MSHV support
+ *
+ * Copyright Microsoft, Corp. 2026
+ *
+ * Authors: Aastha Rawat <aastharawat@linux.microsoft.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef QEMU_MSHV_ARM_H
+#define QEMU_MSHV_ARM_H
+
+#include "target/arm/cpu.h"
+
+void mshv_arm_set_cpu_features_from_host(ARMCPU *cpu);
+
+#endif
--
2.43.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 07/14] accel/mshv: add arch-specific accelerator init hook
2026-03-11 15:15 [PATCH 00/14] Add ARM64 support for MSHV accelerator Anirudh Rayabharam (Microsoft)
` (5 preceding siblings ...)
2026-03-11 15:15 ` [PATCH 06/14] target/arm/mshv: implement -cpu host for MSHV Anirudh Rayabharam
@ 2026-03-11 15:15 ` Anirudh Rayabharam (Microsoft)
2026-03-11 15:15 ` [PATCH 08/14] accel/mshv: Add access_vp_regs synthetic proc features Anirudh Rayabharam
` (8 subsequent siblings)
15 siblings, 0 replies; 38+ messages in thread
From: Anirudh Rayabharam (Microsoft) @ 2026-03-11 15:15 UTC (permalink / raw)
To: qemu-devel
Cc: Magnus Kulke, Wei Liu, Paolo Bonzini, Marc-André Lureau,
Daniel P. Berrangé, Philippe Mathieu-Daudé,
Peter Maydell, Anirudh Rayabharam, Aastha Rawat, qemu-arm
Introduce mshv_arch_accel_init() as an arch-specific hook called early
in mshv_init(), before VM creation. This allows each architecture to
perform platform-specific initialization at accelerator init time.
For arm64, the hook queries the hypervisor for the supported IPA bit
size and validates it against the guest memory map via the machine's
get_physical_address_range callback, following the same pattern used by
HVF and WHPX. This also populates the memory map which comes in handy
later when retreiving the vGIC layout.
For x86, the hook calls mshv_init_mmio_emu() which was previously called
directly from the common init path. Also move set_unimplemented_msr_action()
and mshv_arch_post_init_vm() from mshv-cpu.c to the new mshv-all.c, as
they are not vCPU-specific.
Signed-off-by: Anirudh Rayabharam (Microsoft) <anirudh@anirudhrb.com>
---
accel/mshv/mshv-all.c | 5 ++-
include/system/mshv_int.h | 1 +
target/arm/mshv/mshv-all.c | 25 ++++++++++----
target/i386/mshv/meson.build | 1 +
target/i386/mshv/mshv-all.c | 80 ++++++++++++++++++++++++++++++++++++++++++++
target/i386/mshv/mshv-cpu.c | 40 ----------------------
6 files changed, 105 insertions(+), 47 deletions(-)
diff --git a/accel/mshv/mshv-all.c b/accel/mshv/mshv-all.c
index c6dad18d2f..d63b3a53bf 100644
--- a/accel/mshv/mshv-all.c
+++ b/accel/mshv/mshv-all.c
@@ -477,7 +477,10 @@ static int mshv_init(AccelState *as, MachineState *ms)
return -1;
}
- mshv_init_mmio_emu();
+ ret = mshv_arch_accel_init(as, ms, mshv_fd);
+ if (ret < 0) {
+ return -1;
+ }
mshv_init_msicontrol();
diff --git a/include/system/mshv_int.h b/include/system/mshv_int.h
index ff3ab957b5..c72c91cd23 100644
--- a/include/system/mshv_int.h
+++ b/include/system/mshv_int.h
@@ -96,6 +96,7 @@ void mshv_arch_init_vcpu(CPUState *cpu);
void mshv_arch_destroy_vcpu(CPUState *cpu);
void mshv_arch_amend_proc_features(
union hv_partition_synthetic_processor_features *features);
+int mshv_arch_accel_init(AccelState *as, MachineState *ms, int mshv_fd);
int mshv_arch_post_init_vm(int vm_fd);
void mshv_setup_hvcall_args(AccelCPUState *state);
diff --git a/target/arm/mshv/mshv-all.c b/target/arm/mshv/mshv-all.c
index 0102297305..2b983845d3 100644
--- a/target/arm/mshv/mshv-all.c
+++ b/target/arm/mshv/mshv-all.c
@@ -9,12 +9,13 @@
* SPDX-License-Identifier: GPL-2.0-or-later
*/
-
#include "qemu/osdep.h"
#include <sys/ioctl.h>
#include "qemu/error-report.h"
#include "qemu/memalign.h"
+#include "hw/arm/bsa.h"
+#include "hw/arm/virt.h"
#include "system/cpus.h"
#include "target/arm/cpu.h"
@@ -188,11 +189,6 @@ void mshv_arch_destroy_vcpu(CPUState *cpu)
state->hvcall_args = (MshvHvCallArgs){0};
}
-void mshv_init_mmio_emu(void)
-{
-
-}
-
void mshv_arch_amend_proc_features(
union hv_partition_synthetic_processor_features *features)
{
@@ -390,3 +386,20 @@ void mshv_arm_set_cpu_features_from_host(ARMCPU *cpu)
cpu->midr = arm_host_cpu_features.midr;
cpu->reset_sctlr = arm_host_cpu_features.reset_sctlr;
}
+
+int mshv_arch_accel_init(AccelState *as, MachineState *ms, int mshv_fd)
+{
+ MachineClass *mc = MACHINE_GET_CLASS(ms);
+ int pa_range;
+ uint32_t ipa_size;
+
+ if (mc->get_physical_address_range) {
+ ipa_size = mshv_arm_get_ipa_bit_size(mshv_fd);
+ pa_range = mc->get_physical_address_range(ms, ipa_size, ipa_size);
+ if (pa_range < 0) {
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
diff --git a/target/i386/mshv/meson.build b/target/i386/mshv/meson.build
index 6091c21887..ce54e134cb 100644
--- a/target/i386/mshv/meson.build
+++ b/target/i386/mshv/meson.build
@@ -1,6 +1,7 @@
i386_mshv_ss = ss.source_set()
i386_mshv_ss.add(files(
+ 'mshv-all.c',
'mshv-cpu.c',
'msr.c',
))
diff --git a/target/i386/mshv/mshv-all.c b/target/i386/mshv/mshv-all.c
new file mode 100644
index 0000000000..f0b43aa86f
--- /dev/null
+++ b/target/i386/mshv/mshv-all.c
@@ -0,0 +1,80 @@
+/*
+ * QEMU MSHV support
+ *
+ * Copyright Microsoft, Corp. 2026
+ *
+ * Authors: Ziqiao Zhou <ziqiaozhou@microsoft.com>
+ * Magnus Kulke <magnuskulke@microsoft.com>
+ * Jinank Jain <jinankjain@microsoft.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "qemu/memalign.h"
+
+#include "system/mshv.h"
+#include "system/mshv_int.h"
+#include "system/address-spaces.h"
+#include "linux/mshv.h"
+#include "hw/hyperv/hvgdk.h"
+#include "hw/hyperv/hvgdk_mini.h"
+#include "hw/hyperv/hvhdk_mini.h"
+#include "hw/i386/apic_internal.h"
+
+#include "cpu.h"
+#include "emulate/x86_decode.h"
+#include "emulate/x86_emu.h"
+#include "emulate/x86_flags.h"
+
+#include "trace-accel_mshv.h"
+#include "trace.h"
+
+#include <sys/ioctl.h>
+
+int mshv_arch_accel_init(AccelState *as, MachineState *ms, int mshv_fd)
+{
+ mshv_init_mmio_emu();
+ return 0;
+}
+
+/*
+ * Default Microsoft Hypervisor behavior for unimplemented MSR is to send a
+ * fault to the guest if it tries to access it. It is possible to override
+ * this behavior with a more suitable option i.e., ignore writes from the guest
+ * and return zero in attempt to read unimplemented.
+ */
+static int set_unimplemented_msr_action(int vm_fd)
+{
+ struct hv_input_set_partition_property in = {0};
+ struct mshv_root_hvcall args = {0};
+
+ in.property_code = HV_PARTITION_PROPERTY_UNIMPLEMENTED_MSR_ACTION;
+ in.property_value = HV_UNIMPLEMENTED_MSR_ACTION_IGNORE_WRITE_READ_ZERO;
+
+ args.code = HVCALL_SET_PARTITION_PROPERTY;
+ args.in_sz = sizeof(in);
+ args.in_ptr = (uint64_t)∈
+
+ trace_mshv_hvcall_args("unimplemented_msr_action", args.code, args.in_sz);
+
+ int ret = mshv_hvcall(vm_fd, &args);
+ if (ret < 0) {
+ error_report("Failed to set unimplemented MSR action");
+ return -1;
+ }
+ return 0;
+}
+
+int mshv_arch_post_init_vm(int vm_fd)
+{
+ int ret;
+
+ ret = set_unimplemented_msr_action(vm_fd);
+ if (ret < 0) {
+ error_report("Failed to set unimplemented MSR action");
+ }
+
+ return ret;
+}
diff --git a/target/i386/mshv/mshv-cpu.c b/target/i386/mshv/mshv-cpu.c
index 9a80dc34d0..8325ac74a3 100644
--- a/target/i386/mshv/mshv-cpu.c
+++ b/target/i386/mshv/mshv-cpu.c
@@ -1482,43 +1482,3 @@ void mshv_arch_destroy_vcpu(CPUState *cpu)
state->hvcall_args = (MshvHvCallArgs){0};
g_clear_pointer(&env->emu_mmio_buf, g_free);
}
-
-/*
- * Default Microsoft Hypervisor behavior for unimplemented MSR is to send a
- * fault to the guest if it tries to access it. It is possible to override
- * this behavior with a more suitable option i.e., ignore writes from the guest
- * and return zero in attempt to read unimplemented.
- */
-static int set_unimplemented_msr_action(int vm_fd)
-{
- struct hv_input_set_partition_property in = {0};
- struct mshv_root_hvcall args = {0};
-
- in.property_code = HV_PARTITION_PROPERTY_UNIMPLEMENTED_MSR_ACTION;
- in.property_value = HV_UNIMPLEMENTED_MSR_ACTION_IGNORE_WRITE_READ_ZERO;
-
- args.code = HVCALL_SET_PARTITION_PROPERTY;
- args.in_sz = sizeof(in);
- args.in_ptr = (uint64_t)∈
-
- trace_mshv_hvcall_args("unimplemented_msr_action", args.code, args.in_sz);
-
- int ret = mshv_hvcall(vm_fd, &args);
- if (ret < 0) {
- error_report("Failed to set unimplemented MSR action");
- return -1;
- }
- return 0;
-}
-
-int mshv_arch_post_init_vm(int vm_fd)
-{
- int ret;
-
- ret = set_unimplemented_msr_action(vm_fd);
- if (ret < 0) {
- error_report("Failed to set unimplemented MSR action");
- }
-
- return ret;
-}
--
2.43.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 08/14] accel/mshv: Add access_vp_regs synthetic proc features
2026-03-11 15:15 [PATCH 00/14] Add ARM64 support for MSHV accelerator Anirudh Rayabharam (Microsoft)
` (6 preceding siblings ...)
2026-03-11 15:15 ` [PATCH 07/14] accel/mshv: add arch-specific accelerator init hook Anirudh Rayabharam (Microsoft)
@ 2026-03-11 15:15 ` Anirudh Rayabharam
2026-03-11 15:35 ` Mohamed Mediouni
2026-03-11 20:51 ` Wei Liu
2026-03-11 15:15 ` [PATCH 09/14] target/arm: cpu: Mark MSHV supporting PSCI 1.3 Anirudh Rayabharam
` (7 subsequent siblings)
15 siblings, 2 replies; 38+ messages in thread
From: Anirudh Rayabharam @ 2026-03-11 15:15 UTC (permalink / raw)
To: qemu-devel
Cc: Magnus Kulke, Wei Liu, Paolo Bonzini, Marc-André Lureau,
Daniel P. Berrangé, Philippe Mathieu-Daudé,
Peter Maydell, Anirudh Rayabharam, Aastha Rawat, qemu-arm
From: Aastha Rawat <aastharawat@linux.microsoft.com>
Enable access_vp_regs feature for regs. In arm64, this feature bit
allows the guest to set VP registers using hypercall. This wasn't
required for x86 because such registers are set using wrmsr instead of
hypercall.
Signed-off-by: Aastha Rawat <aastharawat@linux.microsoft.com>
---
accel/mshv/mshv-all.c | 1 +
include/hw/hyperv/hvhdk.h | 87 +++++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 85 insertions(+), 3 deletions(-)
diff --git a/accel/mshv/mshv-all.c b/accel/mshv/mshv-all.c
index d63b3a53bf..563599ef6a 100644
--- a/accel/mshv/mshv-all.c
+++ b/accel/mshv/mshv-all.c
@@ -199,6 +199,7 @@ static int set_synthetic_proc_features(int vm_fd)
features.tb_flush_hypercalls = 1;
features.synthetic_cluster_ipi = 1;
features.direct_synthetic_timers = 1;
+ features.access_vp_regs = 1;
mshv_arch_amend_proc_features(&features);
diff --git a/include/hw/hyperv/hvhdk.h b/include/hw/hyperv/hvhdk.h
index 2e1ef80972..38af01f8ea 100644
--- a/include/hw/hyperv/hvhdk.h
+++ b/include/hw/hyperv/hvhdk.h
@@ -94,11 +94,15 @@ union hv_partition_synthetic_processor_features {
*/
uint64_t access_partition_reference_tsc:1;
- /*
- * Partition has access to the guest idle reg. Corresponds to
+#if defined(__x86_64__)
+
+ /* Partition has access to the guest idle reg. Corresponds to
* access_guest_idle_reg privilege.
*/
uint64_t access_guest_idle_reg:1;
+#else
+ uint64_t reserved_z10:1;
+#endif
/*
* Partition has access to frequency regs. corresponds to
@@ -110,11 +114,16 @@ union hv_partition_synthetic_processor_features {
uint64_t reserved_z13:1; /* Reserved for access_root_scheduler_reg */
uint64_t reserved_z14:1; /* Reserved for access_tsc_invariant_controls */
+#if defined(__x86_64__)
+
/*
* Extended GVA ranges for HvCallFlushVirtualAddressList hypercall.
* Corresponds to privilege.
*/
uint64_t enable_extended_gva_ranges_for_flush_virtual_address_list:1;
+#else
+ uint64_t reserved_z15:1;
+#endif
uint64_t reserved_z16:1; /* Reserved for access_vsm. */
uint64_t reserved_z17:1; /* Reserved for access_vp_registers. */
@@ -161,13 +170,85 @@ union hv_partition_synthetic_processor_features {
/* HvCallRetargetDeviceInterrupt is supported. */
uint64_t retarget_device_interrupt:1;
+#if defined(__x86_64__)
/* HvCallRestorePartitionTime is supported. */
uint64_t restore_time:1;
/* EnlightenedVmcs nested enlightenment is supported. */
uint64_t enlightened_vmcs:1;
- uint64_t reserved:30;
+ uint64_t nested_debug_ctl:1;
+ uint64_t synthetic_time_unhalted_timer:1;
+ uint64_t idle_spec_ctrl:1;
+
+#else
+ uint64_t reserved_z31:1;
+ uint64_t reserved_z32:1;
+ uint64_t reserved_z33:1;
+ uint64_t reserved_z34:1;
+ uint64_t reserved_z35:1;
+#endif
+
+#if defined(__aarch64__)
+ /* Register intercepts supported in V1. As more registers are supported in future
+ * releases, new bits will be added here to prevent migration between incompatible hosts.
+ *
+ * List of registers supported in V1:
+ * 1. TPIDRRO_EL0
+ * 2. TPIDR_EL1
+ * 3. SCTLR_EL1 - Supports write intercept mask.
+ * 4. VBAR_EL1
+ * 5. TCR_EL1 - Supports write intercept mask.
+ * 6. MAIR_EL1 - Supports write intercept mask.
+ * 7. CPACR_EL1 - Supports write intercept mask.
+ * 8. CONTEXTIDR_EL1
+ * 9. PAuth keys (total 10 registers)
+ * 10. HvArm64RegisterSyntheticException
+ */
+ uint64_t register_intercepts_v1:1;
+#else
+ uint64_t reserved_z36:1;
+#endif
+
+ /* HvCallWakeVps is supported */
+ uint64_t wake_vps:1;
+
+ /* HvCallGet/SetVpRegisters is supported.
+ * Corresponds to AccessVpRegisters privilege.
+ * This feature only affects exo partitions.
+ */
+ uint64_t access_vp_regs:1;
+
+#if defined(__aarch64__)
+ /* HvCallSyncContext/Ex is supported. */
+ uint64_t sync_context:1;
+#else
+ uint64_t reserved_z39:1;
+#endif /* __aarch64__ */
+
+ /* Management VTL synic support is allowed.
+ * Corresponds to the ManagementVtlSynicSupport privilege.
+ */
+ uint64_t management_vtl_synic_support:1;
+
+#if defined(__x86_64__)
+ /* Hypervisor supports guest mechanism to signal pending interrupts to paravisor. */
+ uint64_t proxy_interrupt_doorbell_support:1;
+#else
+ uint64_t reserved_z41:1;
+#endif
+
+#if defined(__aarch64__)
+ /* InterceptSystemResetAvailable is exposed. */
+ uint64_t intercept_system_reset:1;
+#else
+ uint64_t reserved_z42:1;
+#endif
+
+ /* Hypercalls for host MMIO operations are available. */
+ uint64_t mmio_hypercalls:1;
+
+ uint64_t reserved:20;
};
};
--
2.43.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 09/14] target/arm: cpu: Mark MSHV supporting PSCI 1.3
2026-03-11 15:15 [PATCH 00/14] Add ARM64 support for MSHV accelerator Anirudh Rayabharam (Microsoft)
` (7 preceding siblings ...)
2026-03-11 15:15 ` [PATCH 08/14] accel/mshv: Add access_vp_regs synthetic proc features Anirudh Rayabharam
@ 2026-03-11 15:15 ` Anirudh Rayabharam
2026-03-11 15:48 ` Mohamed Mediouni
2026-03-11 15:15 ` [PATCH 10/14] accel/mshv: implement cpu_thread_is_idle() hook Anirudh Rayabharam
` (6 subsequent siblings)
15 siblings, 1 reply; 38+ messages in thread
From: Anirudh Rayabharam @ 2026-03-11 15:15 UTC (permalink / raw)
To: qemu-devel
Cc: Magnus Kulke, Wei Liu, Paolo Bonzini, Marc-André Lureau,
Daniel P. Berrangé, Philippe Mathieu-Daudé,
Peter Maydell, Anirudh Rayabharam, Aastha Rawat, qemu-arm
From: Aastha Rawat <aastharawat@linux.microsoft.com>
MSHV supports PSCI 1.3. Expose this version to guests.
Signed-off-by: Aastha Rawat <aastharawat@linux.microsoft.com>
---
target/arm/cpu.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 4b1e9750e6..a0a018a8cd 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -1157,7 +1157,7 @@ static void arm_cpu_initfn(Object *obj)
if (tcg_enabled() || hvf_enabled()) {
/* TCG and HVF implement PSCI 1.1 */
cpu->psci_version = QEMU_PSCI_VERSION_1_1;
- } else if (whpx_enabled()) {
+ } else if (whpx_enabled() || mshv_enabled()) {
cpu->psci_version = QEMU_PSCI_VERSION_1_3;
}
}
--
2.43.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 10/14] accel/mshv: implement cpu_thread_is_idle() hook
2026-03-11 15:15 [PATCH 00/14] Add ARM64 support for MSHV accelerator Anirudh Rayabharam (Microsoft)
` (8 preceding siblings ...)
2026-03-11 15:15 ` [PATCH 09/14] target/arm: cpu: Mark MSHV supporting PSCI 1.3 Anirudh Rayabharam
@ 2026-03-11 15:15 ` Anirudh Rayabharam
2026-03-11 15:47 ` Mohamed Mediouni
2026-03-11 15:15 ` [PATCH 11/14] target/arm/mshv: add vCPU run loop Anirudh Rayabharam (Microsoft)
` (5 subsequent siblings)
15 siblings, 1 reply; 38+ messages in thread
From: Anirudh Rayabharam @ 2026-03-11 15:15 UTC (permalink / raw)
To: qemu-devel
Cc: Magnus Kulke, Wei Liu, Paolo Bonzini, Marc-André Lureau,
Daniel P. Berrangé, Philippe Mathieu-Daudé,
Peter Maydell, Anirudh Rayabharam, Aastha Rawat, qemu-arm
From: Magnus Kulke <magnuskulke@linux.microsoft.com>
In MSHV the hypervisor APIC is always used, so we to implement this hook
to make sure the AP's vcpu thread is not blocked waiting for an INIT SIPI
by the BSP. Without this change soft reboots with -smp cpus>=2 will
hang.
Signed-off-by: Magnus Kulke <magnuskulke@linux.microsoft.com>
---
accel/mshv/mshv-all.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/accel/mshv/mshv-all.c b/accel/mshv/mshv-all.c
index 563599ef6a..9a101d51ff 100644
--- a/accel/mshv/mshv-all.c
+++ b/accel/mshv/mshv-all.c
@@ -747,11 +747,23 @@ static const TypeInfo mshv_accel_type = {
.instance_size = sizeof(MshvState),
};
+/*
+ * MSHV manages the LAPIC in the hypervisor. SIPI for APs are handled
+ * internally. Halted vCPUs must still enter mshv_cpu_exec() so that
+ * MSHV_RUN_VP is called and the hypervisor will deliver SIPI to wake APs.
+ */
+
+static bool mshv_vcpu_thread_is_idle(CPUState *cpu)
+{
+ return false;
+}
+
static void mshv_accel_ops_class_init(ObjectClass *oc, const void *data)
{
AccelOpsClass *ops = ACCEL_OPS_CLASS(oc);
ops->create_vcpu_thread = mshv_start_vcpu_thread;
+ ops->cpu_thread_is_idle = mshv_vcpu_thread_is_idle;
ops->synchronize_post_init = mshv_cpu_synchronize_post_init;
ops->synchronize_post_reset = mshv_cpu_synchronize_post_reset;
ops->synchronize_state = mshv_cpu_synchronize;
--
2.43.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 11/14] target/arm/mshv: add vCPU run loop
2026-03-11 15:15 [PATCH 00/14] Add ARM64 support for MSHV accelerator Anirudh Rayabharam (Microsoft)
` (9 preceding siblings ...)
2026-03-11 15:15 ` [PATCH 10/14] accel/mshv: implement cpu_thread_is_idle() hook Anirudh Rayabharam
@ 2026-03-11 15:15 ` Anirudh Rayabharam (Microsoft)
2026-03-11 15:58 ` Mohamed Mediouni
2026-03-11 15:15 ` [PATCH 12/14] include/hw/hyperv: adjust hv_interrupt_control structure for arm64 Anirudh Rayabharam (Microsoft)
` (4 subsequent siblings)
15 siblings, 1 reply; 38+ messages in thread
From: Anirudh Rayabharam (Microsoft) @ 2026-03-11 15:15 UTC (permalink / raw)
To: qemu-devel
Cc: Magnus Kulke, Wei Liu, Paolo Bonzini, Marc-André Lureau,
Daniel P. Berrangé, Philippe Mathieu-Daudé,
Peter Maydell, Anirudh Rayabharam, Aastha Rawat, qemu-arm
Add the main vCPU run loop for MSHV using the MSHV_RUN_VP_IOCTL.
Handle MMIO exits by emulating the instruction using the syndrome
information from ESR_EL2.
Signed-off-by: Anirudh Rayabharam (Microsoft) <anirudh@anirudhrb.com>
---
include/hw/hyperv/hvgdk_mini.h | 44 +++++++++
target/arm/mshv/mshv-all.c | 198 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 242 insertions(+)
diff --git a/include/hw/hyperv/hvgdk_mini.h b/include/hw/hyperv/hvgdk_mini.h
index d56be0d70f..84b3c6af5f 100644
--- a/include/hw/hyperv/hvgdk_mini.h
+++ b/include/hw/hyperv/hvgdk_mini.h
@@ -750,6 +750,50 @@ struct hv_x64_memory_intercept_message {
uint8_t instruction_bytes[16];
};
+union hv_arm64_vp_execution_state {
+ uint16_t as_uint16;
+ struct {
+ uint16_t cpl:2;
+ uint16_t debug_active:1;
+ uint16_t interruption_pending:1;
+ uint16_t vtl:4;
+ uint16_t virtualization_fault_active:1;
+ uint16_t reserved:7;
+ };
+};
+
+struct hv_arm64_intercept_message_header {
+ uint32_t vp_index;
+ uint8_t instruction_length;
+ uint8_t intercept_access_type;
+ union hv_arm64_vp_execution_state execution_state;
+ uint64_t pc;
+ uint64_t cpsr;
+};
+
+union hv_arm64_memory_access_info {
+ uint8_t as_uint8;
+ struct {
+ uint8_t gva_valid:1;
+ uint8_t gva_gpa_valid:1;
+ uint8_t hypercall_output_pending:1;
+ uint8_t reserved:5;
+ };
+};
+
+struct hv_arm64_memory_intercept_message {
+ struct hv_arm64_intercept_message_header header;
+ uint32_t cache_type; /* enum hv_cache_type */
+ uint8_t instruction_byte_count;
+ union hv_arm64_memory_access_info memory_access_info;
+ uint16_t reserved1;
+ uint8_t instruction_bytes[4];
+ uint32_t reserved2;
+ uint64_t guest_virtual_address;
+ uint64_t guest_physical_address;
+ uint64_t syndrome;
+};
+
union hv_message_flags {
uint8_t asu8;
struct {
diff --git a/target/arm/mshv/mshv-all.c b/target/arm/mshv/mshv-all.c
index 2b983845d3..b0649ba10b 100644
--- a/target/arm/mshv/mshv-all.c
+++ b/target/arm/mshv/mshv-all.c
@@ -166,8 +166,206 @@ int mshv_arch_put_registers(const CPUState *cpu)
return 0;
}
+static int set_memory_info(const struct hyperv_message *msg,
+ struct hv_arm64_memory_intercept_message *info)
+{
+ if (msg->header.message_type != HVMSG_GPA_INTERCEPT
+ && msg->header.message_type != HVMSG_UNMAPPED_GPA
+ && msg->header.message_type != HVMSG_UNACCEPTED_GPA) {
+ error_report("invalid message type");
+ return -1;
+ }
+ memcpy(info, msg->payload, sizeof(*info));
+
+ return 0;
+}
+
+typedef union {
+ uint64_t raw;
+ struct {
+ uint32_t iss:25;
+ uint32_t il:1;
+ uint32_t ec:6;
+ uint32_t iss2:5;
+ uint32_t _rsvd:27;
+ } QEMU_PACKED;
+} EsrEl2;
+
+typedef union {
+ uint32_t raw;
+ struct {
+ uint32_t dfsc:6;
+ uint32_t wnr:1;
+ uint32_t s1ptw:1;
+ uint32_t cm:1;
+ uint32_t ea:1;
+ uint32_t fnv:1;
+ uint32_t set:2;
+ uint32_t vncr:1;
+ uint32_t ar:1;
+ uint32_t sf:1;
+ uint32_t srt:5;
+ uint32_t sse:1;
+ uint32_t sas:2;
+ uint32_t isv:1;
+ uint32_t _unused:7;
+ } QEMU_PACKED;
+} IssDataAbort;
+
+typedef enum {
+ data_abort_lower = 36,
+ data_abort = 37,
+} ExceptionClass;
+
+int mshv_store_regs(CPUState *cpu)
+{
+ int ret;
+
+ ret = set_standard_regs(cpu);
+ if (ret < 0) {
+ error_report("Failed to store standard registers");
+ return -1;
+ }
+
+ /* TODO: should store special registers? the equivalent hvf code doesn't */
+
+ return 0;
+}
+
+static int emulate_with_syndrome(CPUState *cpu,
+ struct hv_arm64_memory_intercept_message *info)
+{
+ ARMCPU *arm_cpu = ARM_CPU(cpu);
+ CPUARMState *env = &arm_cpu->env;
+ int ret;
+ EsrEl2 syndrome = { 0 };
+ IssDataAbort iss = { 0 };
+ uint64_t gpa = info->guest_physical_address;
+ uint64_t len, reg_index;
+ bool sign_extend;
+
+ syndrome.raw = info->syndrome;
+
+ if (!(syndrome.ec == data_abort_lower || syndrome.ec == data_abort)) {
+ error_report("Unknown exception class 0x%x", syndrome.ec);
+ return -1;
+ }
+
+ iss.raw = syndrome.iss;
+ if (!iss.isv) {
+ error_report("Invalid ESR EL2 ISV field");
+ return -1;
+ }
+
+ len = 1ULL << iss.sas;
+ sign_extend = iss.sse;
+ reg_index = iss.srt;
+
+ ret = mshv_load_regs(cpu);
+ if (ret < 0) {
+ error_report("Failed to load registers");
+ return -1;
+ }
+
+ if (iss.wnr) {
+ uint8_t data[8];
+ uint64_t val = reg_index < 31 ? env->xregs[reg_index] : 0ULL;
+
+ val = cpu_to_le64(val);
+
+ memcpy(data, &val, sizeof(val));
+ ret = mshv_guest_mem_write(gpa, data, len, false);
+ if (ret < 0) {
+ error_report("Failed to write guest memory");
+ return -1;
+ }
+ } else {
+ uint8_t data[8] = { 0 };
+
+ ret = mshv_guest_mem_read(gpa, data, len, false, false);
+ if (ret < 0) {
+ error_report("Failed to read guest memory");
+ return -1;
+ }
+
+ uint64_t val;
+ memcpy(&val, data, sizeof(val));
+
+ val = le64_to_cpu(val);
+
+ if (sign_extend) {
+ uint64_t shift = 64 - (len * 8);
+ val = (((int64_t)val << shift) >> shift);
+ if (!iss.sf) {
+ val &= 0xffffffff;
+ }
+ }
+
+ env->xregs[reg_index] = val;
+ }
+
+ env->pc += (syndrome.il == 1) ? 4 : 2;
+
+ ret = mshv_store_regs(cpu);
+ if (ret < 0) {
+ error_report("failed to store registers");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int handle_unmapped_mem(int vm_fd, CPUState *cpu,
+ const struct hyperv_message *msg,
+ MshvVmExit *exit_reason)
+{
+ struct hv_arm64_memory_intercept_message info = { 0 };
+ int ret;
+
+ ret = set_memory_info(msg, &info);
+ if (ret < 0) {
+ error_report("failed to convert message to memory info");
+ return -1;
+ }
+
+ ret = emulate_with_syndrome(cpu, &info);
+ if (ret < 0) {
+ error_report("Failed to emulate with syndrome");
+ return -1;
+ }
+
+ *exit_reason = MshvVmExitIgnore;
+
+ return 0;
+}
+
int mshv_run_vcpu(int vm_fd, CPUState *cpu, hv_message *msg, MshvVmExit *exit)
{
+ int ret;
+ int cpu_fd = mshv_vcpufd(cpu);
+
+ ret = ioctl(cpu_fd, MSHV_RUN_VP, msg);
+ if (ret < 0) {
+ *exit = MshvVmExitShutdown;
+ return ret;
+ }
+
+ switch (msg->header.message_type) {
+ case HVMSG_UNRECOVERABLE_EXCEPTION:
+ *exit = MshvVmExitShutdown;
+ break;
+ case HVMSG_UNMAPPED_GPA:
+ ret = handle_unmapped_mem(vm_fd, cpu, msg, exit);
+ if (ret < 0) {
+ error_report("failed to handle mmio");
+ return -1;
+ }
+ break;
+ default:
+ error_report("Unhandled message type: 0x%x", msg->header.message_type);
+ return -1;
+ }
+
return 0;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 12/14] include/hw/hyperv: adjust hv_interrupt_control structure for arm64
2026-03-11 15:15 [PATCH 00/14] Add ARM64 support for MSHV accelerator Anirudh Rayabharam (Microsoft)
` (10 preceding siblings ...)
2026-03-11 15:15 ` [PATCH 11/14] target/arm/mshv: add vCPU run loop Anirudh Rayabharam (Microsoft)
@ 2026-03-11 15:15 ` Anirudh Rayabharam (Microsoft)
2026-03-11 15:15 ` [PATCH 13/14] hw/intc,target/arm/mshv: add MSHV vGICv3 implementation Anirudh Rayabharam (Microsoft)
` (3 subsequent siblings)
15 siblings, 0 replies; 38+ messages in thread
From: Anirudh Rayabharam (Microsoft) @ 2026-03-11 15:15 UTC (permalink / raw)
To: qemu-devel
Cc: Magnus Kulke, Wei Liu, Paolo Bonzini, Marc-André Lureau,
Daniel P. Berrangé, Philippe Mathieu-Daudé,
Peter Maydell, Anirudh Rayabharam, Aastha Rawat, qemu-arm
Add the arm64 specific fields to the hv_interrupt_control struct and
adjust the existing usage accordingly. mshv_request_interrupt is only
needed only for x86 so compile it out entirely for arm64.
Signed-off-by: Anirudh Rayabharam (Microsoft) <anirudh@anirudhrb.com>
---
accel/mshv/irq.c | 2 ++
include/hw/hyperv/hvgdk_mini.h | 25 +++++++++++++++++++++++++
include/system/mshv.h | 2 ++
3 files changed, 29 insertions(+)
diff --git a/accel/mshv/irq.c b/accel/mshv/irq.c
index 3c238c33c3..a391d7db86 100644
--- a/accel/mshv/irq.c
+++ b/accel/mshv/irq.c
@@ -310,6 +310,7 @@ int mshv_irqchip_update_msi_route(int virq, MSIMessage msg, PCIDevice *dev)
return 0;
}
+#if defined(__x86_64__)
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)
@@ -346,6 +347,7 @@ int mshv_request_interrupt(MshvState *mshv_state, uint32_t interrupt_type, uint3
}
return 0;
}
+#endif
void mshv_irqchip_commit_routes(void)
{
diff --git a/include/hw/hyperv/hvgdk_mini.h b/include/hw/hyperv/hvgdk_mini.h
index 84b3c6af5f..eb766734d6 100644
--- a/include/hw/hyperv/hvgdk_mini.h
+++ b/include/hw/hyperv/hvgdk_mini.h
@@ -506,13 +506,38 @@ typedef struct hv_input_set_vp_registers {
struct hv_register_assoc elements[];
} hv_input_set_vp_registers;
+enum hv_interrupt_type {
+#if defined(__x86_64__)
+ HV_X64_INTERRUPT_TYPE_FIXED = 0x0000,
+ HV_X64_INTERRUPT_TYPE_LOWESTPRIORITY = 0x0001,
+ HV_X64_INTERRUPT_TYPE_SMI = 0x0002,
+ HV_X64_INTERRUPT_TYPE_REMOTEREAD = 0x0003,
+ HV_X64_INTERRUPT_TYPE_NMI = 0x0004,
+ HV_X64_INTERRUPT_TYPE_INIT = 0x0005,
+ HV_X64_INTERRUPT_TYPE_SIPI = 0x0006,
+ HV_X64_INTERRUPT_TYPE_EXTINT = 0x0007,
+ HV_X64_INTERRUPT_TYPE_LOCALINT0 = 0x0008,
+ HV_X64_INTERRUPT_TYPE_LOCALINT1 = 0x0009,
+ HV_X64_INTERRUPT_TYPE_MAXIMUM = 0x000A,
+#elif defined(__aarch64__)
+ HV_ARM64_INTERRUPT_TYPE_FIXED = 0x0000,
+ HV_ARM64_INTERRUPT_TYPE_MAXIMUM = 0x0008,
+#endif
+};
+
union hv_interrupt_control {
uint64_t as_uint64;
struct {
uint32_t interrupt_type; /* enum hv_interrupt type */
+#if defined(__x86_64__)
uint32_t level_triggered:1;
uint32_t logical_dest_mode:1;
uint32_t rsvd:30;
+#elif defined(__aarch64__)
+ uint32_t rsvd1:2;
+ uint32_t asserted:1;
+ uint32_t rsvd2:29;
+#endif
};
};
diff --git a/include/system/mshv.h b/include/system/mshv.h
index 75286baf16..0db18fcee9 100644
--- a/include/system/mshv.h
+++ b/include/system/mshv.h
@@ -47,10 +47,12 @@ extern bool mshv_allowed;
typedef struct MshvState MshvState;
extern MshvState *mshv_state;
+#if defined(__x86_64__)
/* interrupt */
int mshv_request_interrupt(MshvState *mshv_state, uint32_t interrupt_type, uint32_t vector,
uint32_t vp_index, bool logical_destination_mode,
bool level_triggered);
+#endif
int mshv_irqchip_add_msi_route(int vector, PCIDevice *dev);
int mshv_irqchip_update_msi_route(int virq, MSIMessage msg, PCIDevice *dev);
--
2.43.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 13/14] hw/intc,target/arm/mshv: add MSHV vGICv3 implementation
2026-03-11 15:15 [PATCH 00/14] Add ARM64 support for MSHV accelerator Anirudh Rayabharam (Microsoft)
` (11 preceding siblings ...)
2026-03-11 15:15 ` [PATCH 12/14] include/hw/hyperv: adjust hv_interrupt_control structure for arm64 Anirudh Rayabharam (Microsoft)
@ 2026-03-11 15:15 ` Anirudh Rayabharam (Microsoft)
2026-03-11 15:15 ` [PATCH 14/14] MAINTAINERS: updates for MSHV arm64 code Anirudh Rayabharam (Microsoft)
` (2 subsequent siblings)
15 siblings, 0 replies; 38+ messages in thread
From: Anirudh Rayabharam (Microsoft) @ 2026-03-11 15:15 UTC (permalink / raw)
To: qemu-devel
Cc: Magnus Kulke, Wei Liu, Paolo Bonzini, Marc-André Lureau,
Daniel P. Berrangé, Philippe Mathieu-Daudé,
Peter Maydell, Anirudh Rayabharam, Aastha Rawat, qemu-arm
Add in-kernel GICv3 support for the MSHV accelerator, following the
same approach as the KVM and WHPX vGIC backends. The implementation
handles IRQ injection via the HVCALL_ASSERT_VIRTUAL_INTERRUPT hypercall.
Introduce mshv_arch_pre_init_vm(), an arch-specific hook called after
VM creation but before VM initialization, used on arm64 to configure
GIC partition properties (GICD base, ITS translater base, timer and PMU
PPI numbers). The x86 side provides a no-op stub.
Update the virt machine to treat MSHV like WHPX for GIC version
selection (GICv3 only) and MSI controller finalization (no ITS support).
Signed-off-by: Anirudh Rayabharam (Microsoft) <anirudh@anirudhrb.com>
---
accel/mshv/mshv-all.c | 5 ++
hw/arm/virt.c | 8 +-
hw/intc/arm_gicv3_common.c | 3 +
hw/intc/arm_gicv3_mshv.c | 180 +++++++++++++++++++++++++++++++++++++
hw/intc/meson.build | 1 +
include/hw/hyperv/hvgdk_mini.h | 2 +
include/hw/hyperv/hvhdk_mini.h | 6 ++
include/hw/intc/arm_gicv3_common.h | 1 +
include/system/mshv_int.h | 1 +
target/arm/mshv/mshv-all.c | 62 +++++++++++++
target/i386/mshv/mshv-all.c | 5 ++
11 files changed, 270 insertions(+), 4 deletions(-)
diff --git a/accel/mshv/mshv-all.c b/accel/mshv/mshv-all.c
index 9a101d51ff..d139f46916 100644
--- a/accel/mshv/mshv-all.c
+++ b/accel/mshv/mshv-all.c
@@ -243,6 +243,11 @@ static int create_vm(int mshv_fd, int *vm_fd)
return -1;
}
+ ret = mshv_arch_pre_init_vm(*vm_fd);
+ if (ret < 0) {
+ return -1;
+ }
+
ret = initialize_vm(*vm_fd);
if (ret < 0) {
return -1;
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 34eb5248a9..5f922ece9c 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -2117,7 +2117,7 @@ static void finalize_gic_version(VirtMachineState *vms)
/* KVM w/o kernel irqchip can only deal with GICv2 */
gics_supported |= VIRT_GIC_VERSION_2_MASK;
accel_name = "KVM with kernel-irqchip=off";
- } else if (whpx_enabled()) {
+ } else if (whpx_enabled() || mshv_enabled()) {
gics_supported |= VIRT_GIC_VERSION_3_MASK;
} else if (tcg_enabled() || hvf_enabled() || qtest_enabled()) {
gics_supported |= VIRT_GIC_VERSION_2_MASK;
@@ -2159,7 +2159,7 @@ static void finalize_msi_controller(VirtMachineState *vms)
if (vms->msi_controller == VIRT_MSI_CTRL_AUTO) {
if (vms->gic_version == VIRT_GIC_VERSION_2) {
vms->msi_controller = VIRT_MSI_CTRL_GICV2M;
- } else if (whpx_enabled()) {
+ } else if (whpx_enabled() || mshv_enabled()) {
vms->msi_controller = VIRT_MSI_CTRL_GICV2M;
} else {
vms->msi_controller = VIRT_MSI_CTRL_ITS;
@@ -2176,8 +2176,8 @@ static void finalize_msi_controller(VirtMachineState *vms)
error_report("GICv2 + ITS is an invalid configuration.");
exit(1);
}
- if (whpx_enabled()) {
- error_report("ITS not supported on WHPX.");
+ if (whpx_enabled() || mshv_enabled()) {
+ error_report("ITS not supported on WHPX and MSHV.");
exit(1);
}
}
diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c
index 9200671c7a..239c645ab9 100644
--- a/hw/intc/arm_gicv3_common.c
+++ b/hw/intc/arm_gicv3_common.c
@@ -33,6 +33,7 @@
#include "hw/arm/linux-boot-if.h"
#include "system/kvm.h"
#include "system/whpx.h"
+#include "system/mshv.h"
static void gicv3_gicd_no_migration_shift_bug_post_load(GICv3State *cs)
@@ -658,6 +659,8 @@ const char *gicv3_class_name(void)
return "kvm-arm-gicv3";
} else if (whpx_enabled()) {
return TYPE_WHPX_GICV3;
+ } else if (mshv_enabled()) {
+ return TYPE_MSHV_GICV3;
} else {
if (kvm_enabled()) {
error_report("Userspace GICv3 is not supported with KVM");
diff --git a/hw/intc/arm_gicv3_mshv.c b/hw/intc/arm_gicv3_mshv.c
new file mode 100644
index 0000000000..2d0b4cbf5e
--- /dev/null
+++ b/hw/intc/arm_gicv3_mshv.c
@@ -0,0 +1,180 @@
+/*
+ * ARM Generic Interrupt Controller using MSHV in-kernel support
+ *
+ * Copyright Microsoft, Corp. 2026
+ * Based on vGICv3 KVM code by Pavel Fedin
+ *
+ * Authors:
+ * Aastha Rawat <aastharawat@microsoft.com>
+ * Anirudh Rayabharam (Microsoft) <anirudh@anirudhrb.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qemu/error-report.h"
+#include "hw/intc/arm_gicv3_common.h"
+#include "migration/blocker.h"
+#include "target/arm/cpregs.h"
+#include "hw/hyperv/hvgdk_mini.h"
+#include "system/mshv.h"
+#include "system/mshv_int.h"
+
+struct MSHVARMGICv3Class {
+ ARMGICv3CommonClass parent_class;
+ DeviceRealize parent_realize;
+ ResettablePhases parent_phases;
+};
+
+OBJECT_DECLARE_TYPE(GICv3State, MSHVARMGICv3Class, MSHV_GICV3)
+
+static void mshv_gicv3_get(GICv3State *s)
+{
+}
+
+static void mshv_gicv3_put(GICv3State *s)
+{
+}
+
+static void mshv_gicv3_reset_hold(Object *obj, ResetType type)
+{
+ GICv3State *s = ARM_GICV3_COMMON(obj);
+ MSHVARMGICv3Class *mgc = MSHV_GICV3_GET_CLASS(s);
+
+ if (mgc->parent_phases.hold) {
+ mgc->parent_phases.hold(obj, type);
+ }
+
+ mshv_gicv3_put(s);
+}
+
+static void mshv_gicv3_set_irq(void *opaque, int irq, int level)
+{
+ int ret;
+ GICv3State *s = (GICv3State *)opaque;
+ int vm_fd = mshv_state->vm;
+ struct hv_input_assert_virtual_interrupt arg = {0};
+ struct mshv_root_hvcall args = {0};
+ union hv_interrupt_control control = {
+ .interrupt_type = HV_ARM64_INTERRUPT_TYPE_FIXED,
+ .rsvd1 = 0,
+ .asserted = level,
+ .rsvd2 = 0
+ };
+
+ if (irq >= s->num_irq) {
+ return;
+ }
+
+ arg.control = control;
+ arg.vector = GIC_INTERNAL + irq;
+
+ 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 set GICv3 IRQ %d to level %d", irq, level);
+ }
+}
+
+static void mshv_gicv3_realize(DeviceState *dev, Error **errp)
+{
+ ERRP_GUARD();
+ GICv3State *s = MSHV_GICV3(dev);
+ MSHVARMGICv3Class *mgc = MSHV_GICV3_GET_CLASS(s);
+ int i, ret;
+
+ mgc->parent_realize(dev, errp);
+ if (*errp) {
+ return;
+ }
+
+ if (s->revision != 3) {
+ error_setg(errp, "unsupported GIC revision %d for platform GIC",
+ s->revision);
+ return;
+ }
+
+ if (s->security_extn) {
+ error_setg(errp, "the platform vGICv3 does not implement the "
+ "security extensions");
+ return;
+ }
+
+ if (s->nmi_support) {
+ error_setg(errp, "NMI is not supported with the platform GIC");
+ return;
+ }
+
+ if (s->nb_redist_regions > 1) {
+ error_setg(errp, "Multiple VGICv3 redistributor regions are not "
+ "supported by MSHV");
+ error_append_hint(errp, "A maximum of %d VCPUs can be used",
+ s->redist_region_count[0]);
+ return;
+ }
+
+ gicv3_init_irqs_and_mmio(s, mshv_gicv3_set_irq, NULL);
+
+ for (i = 0; i < s->num_cpu; i++) {
+ CPUState *cpu_state = qemu_get_cpu(i);
+
+ hv_register_assoc gicr_base = {
+ .name = HV_ARM64_REGISTER_GICR_BASE_GPA,
+ .value = {
+ .reg64 = 0x080A0000 + (GICV3_REDIST_SIZE * i)
+ }
+ };
+
+ ret = mshv_set_generic_regs(cpu_state, &gicr_base, 1);
+ if (ret < 0) {
+ error_setg(errp, "Failed to set GICR base for CPU %d", i);
+ return;
+ }
+ }
+
+ if (s->maint_irq) {
+ error_setg(errp, "Nested virtualisation not currently supported by MSHV");
+ return;
+ }
+
+ error_setg(&s->migration_blocker,
+ "Live migration disabled because GIC state save/restore not supported on MSHV");
+ if (migrate_add_blocker(&s->migration_blocker, errp) < 0) {
+ error_report_err(*errp);
+ }
+}
+
+static void mshv_gicv3_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+ ARMGICv3CommonClass *agcc = ARM_GICV3_COMMON_CLASS(klass);
+ MSHVARMGICv3Class *mgc = MSHV_GICV3_CLASS(klass);
+
+ agcc->pre_save = mshv_gicv3_get;
+ agcc->post_load = mshv_gicv3_put;
+
+ device_class_set_parent_realize(dc, mshv_gicv3_realize,
+ &mgc->parent_realize);
+ resettable_class_set_parent_phases(rc, NULL, mshv_gicv3_reset_hold, NULL,
+ &mgc->parent_phases);
+}
+
+static const TypeInfo mshv_arm_gicv3_info = {
+ .name = TYPE_MSHV_GICV3,
+ .parent = TYPE_ARM_GICV3_COMMON,
+ .instance_size = sizeof(GICv3State),
+ .class_init = mshv_gicv3_class_init,
+ .class_size = sizeof(MSHVARMGICv3Class),
+};
+
+static void mshv_gicv3_register_types(void)
+{
+ type_register_static(&mshv_arm_gicv3_info);
+}
+
+type_init(mshv_gicv3_register_types)
diff --git a/hw/intc/meson.build b/hw/intc/meson.build
index 96742df090..9d824db582 100644
--- a/hw/intc/meson.build
+++ b/hw/intc/meson.build
@@ -43,6 +43,7 @@ arm_common_ss.add(when: 'CONFIG_ARM_GICV3', if_true: files('arm_gicv3_cpuif.c'))
specific_ss.add(when: 'CONFIG_ARM_GIC_KVM', if_true: files('arm_gic_kvm.c'))
specific_ss.add(when: ['CONFIG_WHPX', 'TARGET_AARCH64'], if_true: files('arm_gicv3_whpx.c'))
specific_ss.add(when: ['CONFIG_ARM_GIC_KVM', 'TARGET_AARCH64'], if_true: files('arm_gicv3_kvm.c', 'arm_gicv3_its_kvm.c'))
+specific_ss.add(when: ['CONFIG_MSHV', 'TARGET_AARCH64'], if_true: files('arm_gicv3_mshv.c'))
arm_common_ss.add(when: 'CONFIG_ARM_V7M', if_true: files('armv7m_nvic.c'))
specific_ss.add(when: 'CONFIG_GRLIB', if_true: files('grlib_irqmp.c'))
specific_ss.add(when: 'CONFIG_IOAPIC', if_true: files('ioapic.c'))
diff --git a/include/hw/hyperv/hvgdk_mini.h b/include/hw/hyperv/hvgdk_mini.h
index eb766734d6..b50a65a0d4 100644
--- a/include/hw/hyperv/hvgdk_mini.h
+++ b/include/hw/hyperv/hvgdk_mini.h
@@ -66,6 +66,8 @@ typedef enum hv_register_name {
HV_ARM64_REGISTER_MIDR_EL1 = 0x00040051,
HV_ARM64_REGISTER_MPIDR_EL1 = 0x00040001,
+ HV_ARM64_REGISTER_GICR_BASE_GPA = 0x00063000,
+
#elif defined(__x86_64__)
/* X64 User-Mode Registers */
HV_X64_REGISTER_RAX = 0x00020000,
diff --git a/include/hw/hyperv/hvhdk_mini.h b/include/hw/hyperv/hvhdk_mini.h
index 9c2f3cf5ae..4d78fa0677 100644
--- a/include/hw/hyperv/hvhdk_mini.h
+++ b/include/hw/hyperv/hvhdk_mini.h
@@ -62,6 +62,12 @@ enum hv_partition_property_code {
HV_PARTITION_PROPERTY_ISOLATION_POLICY = 0x00050014,
HV_PARTITION_PROPERTY_UNIMPLEMENTED_MSR_ACTION = 0x00050017,
HV_PARTITION_PROPERTY_SEV_VMGEXIT_OFFLOADS = 0x00050022,
+ HV_PARTITION_PROPERTY_GICD_BASE_ADDRESS = 0x00050028,
+ HV_PARTITION_PROPERTY_GITS_TRANSLATER_BASE_ADDRESS = 0x00050029,
+ HV_PARTITION_PROPERTY_GIC_LPI_INT_ID_BITS = 0x0005002A,
+ HV_PARTITION_PROPERTY_GIC_PPI_OVERFLOW_INTERRUPT_FROM_CNTV = 0x0005002B,
+ HV_PARTITION_PROPERTY_GIC_PPI_OVERFLOW_INTERRUPT_FROM_CNTP = 0x0005002C,
+ HV_PARTITION_PROPERTY_GIC_PPI_PERFORMANCE_MONITORS_INTERRUPT = 0x0005002D,
/* Compatibility properties */
HV_PARTITION_PROPERTY_PROCESSOR_VENDOR = 0x00060000,
diff --git a/include/hw/intc/arm_gicv3_common.h b/include/hw/intc/arm_gicv3_common.h
index c55cf18120..3baac1a35c 100644
--- a/include/hw/intc/arm_gicv3_common.h
+++ b/include/hw/intc/arm_gicv3_common.h
@@ -315,6 +315,7 @@ DECLARE_OBJ_CHECKERS(GICv3State, ARMGICv3CommonClass,
/* Types for GICv3 kernel-irqchip */
#define TYPE_WHPX_GICV3 "whpx-arm-gicv3"
+#define TYPE_MSHV_GICV3 "mshv-arm-gicv3"
struct ARMGICv3CommonClass {
/*< private >*/
diff --git a/include/system/mshv_int.h b/include/system/mshv_int.h
index c72c91cd23..0ef98abedf 100644
--- a/include/system/mshv_int.h
+++ b/include/system/mshv_int.h
@@ -97,6 +97,7 @@ void mshv_arch_destroy_vcpu(CPUState *cpu);
void mshv_arch_amend_proc_features(
union hv_partition_synthetic_processor_features *features);
int mshv_arch_accel_init(AccelState *as, MachineState *ms, int mshv_fd);
+int mshv_arch_pre_init_vm(int vm_fd);
int mshv_arch_post_init_vm(int vm_fd);
void mshv_setup_hvcall_args(AccelCPUState *state);
diff --git a/target/arm/mshv/mshv-all.c b/target/arm/mshv/mshv-all.c
index b0649ba10b..4323399455 100644
--- a/target/arm/mshv/mshv-all.c
+++ b/target/arm/mshv/mshv-all.c
@@ -393,6 +393,68 @@ void mshv_arch_amend_proc_features(
}
+static int set_partition_prop(int vm_fd, uint32_t prop_code,
+ uint64_t prop_value)
+{
+ int ret;
+ struct hv_input_set_partition_property in = {0};
+ in.property_code = prop_code;
+ in.property_value = prop_value;
+
+ struct mshv_root_hvcall args = {0};
+ args.code = HVCALL_SET_PARTITION_PROPERTY;
+ args.in_sz = sizeof(in);
+ args.in_ptr = (uint64_t)∈
+
+ ret = mshv_hvcall(vm_fd, &args);
+ if (ret < 0) {
+ error_report("Failed to set partition property code %u", prop_code);
+ return -1;
+ }
+
+ return 0;
+}
+
+int mshv_arch_pre_init_vm(int vm_fd)
+{
+ int ret;
+ VirtMachineState *vms = VIRT_MACHINE(qdev_get_machine());
+
+ ret = set_partition_prop(vm_fd,
+ HV_PARTITION_PROPERTY_GICD_BASE_ADDRESS,
+ vms->memmap[VIRT_GIC_DIST].base);
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = set_partition_prop(vm_fd,
+ HV_PARTITION_PROPERTY_GITS_TRANSLATER_BASE_ADDRESS,
+ vms->memmap[VIRT_GIC_ITS].base);
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = set_partition_prop(vm_fd,
+ HV_PARTITION_PROPERTY_GIC_LPI_INT_ID_BITS,
+ 0);
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = set_partition_prop(vm_fd,
+ HV_PARTITION_PROPERTY_GIC_PPI_OVERFLOW_INTERRUPT_FROM_CNTV,
+ ARCH_TIMER_VIRT_IRQ);
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = set_partition_prop(vm_fd,
+ HV_PARTITION_PROPERTY_GIC_PPI_PERFORMANCE_MONITORS_INTERRUPT,
+ VIRTUAL_PMU_IRQ);
+
+ return ret;
+}
+
int mshv_arch_post_init_vm(int vm_fd)
{
return 0;
diff --git a/target/i386/mshv/mshv-all.c b/target/i386/mshv/mshv-all.c
index f0b43aa86f..ce8b426ea4 100644
--- a/target/i386/mshv/mshv-all.c
+++ b/target/i386/mshv/mshv-all.c
@@ -39,6 +39,11 @@ int mshv_arch_accel_init(AccelState *as, MachineState *ms, int mshv_fd)
return 0;
}
+int mshv_arch_pre_init_vm(int vm_fd)
+{
+ return 0;
+}
+
/*
* Default Microsoft Hypervisor behavior for unimplemented MSR is to send a
* fault to the guest if it tries to access it. It is possible to override
--
2.43.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 14/14] MAINTAINERS: updates for MSHV arm64 code
2026-03-11 15:15 [PATCH 00/14] Add ARM64 support for MSHV accelerator Anirudh Rayabharam (Microsoft)
` (12 preceding siblings ...)
2026-03-11 15:15 ` [PATCH 13/14] hw/intc,target/arm/mshv: add MSHV vGICv3 implementation Anirudh Rayabharam (Microsoft)
@ 2026-03-11 15:15 ` Anirudh Rayabharam (Microsoft)
2026-03-11 16:54 ` [PATCH 00/14] Add ARM64 support for MSHV accelerator Alex Bennée
2026-03-11 22:29 ` [PATCH 00/14] Add ARM64 support for MSHV accelerator Pierrick Bouvier
15 siblings, 0 replies; 38+ messages in thread
From: Anirudh Rayabharam (Microsoft) @ 2026-03-11 15:15 UTC (permalink / raw)
To: qemu-devel
Cc: Magnus Kulke, Wei Liu, Paolo Bonzini, Marc-André Lureau,
Daniel P. Berrangé, Philippe Mathieu-Daudé,
Peter Maydell, Anirudh Rayabharam, Aastha Rawat, qemu-arm
Add myself and Aastha Rawat as maintainers.
Add Magnus Kulke as reviewer.
Signed-off-by: Anirudh Rayabharam (Microsoft) <anirudh@anirudhrb.com>
---
MAINTAINERS | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 9d1614fd7e..e36b10a8dc 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -606,6 +606,14 @@ R: Wei Liu <wei.liu@kernel.org>
S: Supported
F: target/i386/mshv/
+ARM64 MSHV CPUs
+M: Anirudh Rayabharam <anirudh@anirudhrb.com>
+M: Aastha Rawat <aastharawat@linux.microsoft.com>
+R: Magnus Kulke <magnus.kulke@linux.microsoft.com>
+S: Supported
+F: target/arm/mshv/
+F: hw/intc/arm_gicv3_mshv.c
+
X86 Instruction Emulator
M: Cameron Esfahani <dirty@apple.com>
M: Roman Bolshakov <rbolshakov@ddn.com>
--
2.43.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* Re: [PATCH 08/14] accel/mshv: Add access_vp_regs synthetic proc features
2026-03-11 15:15 ` [PATCH 08/14] accel/mshv: Add access_vp_regs synthetic proc features Anirudh Rayabharam
@ 2026-03-11 15:35 ` Mohamed Mediouni
2026-03-11 20:51 ` Wei Liu
1 sibling, 0 replies; 38+ messages in thread
From: Mohamed Mediouni @ 2026-03-11 15:35 UTC (permalink / raw)
To: Anirudh Rayabharam
Cc: qemu-devel, Magnus Kulke, Wei Liu, Paolo Bonzini,
Marc-André Lureau, "Daniel P. Berrangé",
Philippe Mathieu-Daudé, Peter Maydell, Aastha Rawat,
qemu-arm
> On 11. Mar 2026, at 16:15, Anirudh Rayabharam <anirudh@anirudhrb.com> wrote:
>
> From: Aastha Rawat <aastharawat@linux.microsoft.com>
>
> Enable access_vp_regs feature for regs. In arm64, this feature bit
> allows the guest to set VP registers using hypercall. This wasn't
> required for x86 because such registers are set using wrmsr instead of
> hypercall.
>
Hello,
Could you split this into two patches? With the hvhdk.h changes in another patch.
> Signed-off-by: Aastha Rawat <aastharawat@linux.microsoft.com>
> ---
> accel/mshv/mshv-all.c | 1 +
> include/hw/hyperv/hvhdk.h | 87 +++++++++++++++++++++++++++++++++++++++++++++--
> 2 files changed, 85 insertions(+), 3 deletions(-)
>
> diff --git a/accel/mshv/mshv-all.c b/accel/mshv/mshv-all.c
> index d63b3a53bf..563599ef6a 100644
> --- a/accel/mshv/mshv-all.c
> +++ b/accel/mshv/mshv-all.c
> @@ -199,6 +199,7 @@ static int set_synthetic_proc_features(int vm_fd)
> features.tb_flush_hypercalls = 1;
> features.synthetic_cluster_ipi = 1;
> features.direct_synthetic_timers = 1;
> + features.access_vp_regs = 1;
>
> mshv_arch_amend_proc_features(&features);
>
> diff --git a/include/hw/hyperv/hvhdk.h b/include/hw/hyperv/hvhdk.h
> index 2e1ef80972..38af01f8ea 100644
> --- a/include/hw/hyperv/hvhdk.h
> +++ b/include/hw/hyperv/hvhdk.h
> @@ -94,11 +94,15 @@ union hv_partition_synthetic_processor_features {
> */
> uint64_t access_partition_reference_tsc:1;
>
> - /*
> - * Partition has access to the guest idle reg. Corresponds to
> +#if defined(__x86_64__)
> +
> + /* Partition has access to the guest idle reg. Corresponds to
> * access_guest_idle_reg privilege.
> */
> uint64_t access_guest_idle_reg:1;
> +#else
> + uint64_t reserved_z10:1;
> +#endif
>
> /*
> * Partition has access to frequency regs. corresponds to
> @@ -110,11 +114,16 @@ union hv_partition_synthetic_processor_features {
> uint64_t reserved_z13:1; /* Reserved for access_root_scheduler_reg */
> uint64_t reserved_z14:1; /* Reserved for access_tsc_invariant_controls */
>
> +#if defined(__x86_64__)
> +
> /*
> * Extended GVA ranges for HvCallFlushVirtualAddressList hypercall.
> * Corresponds to privilege.
> */
> uint64_t enable_extended_gva_ranges_for_flush_virtual_address_list:1;
> +#else
> + uint64_t reserved_z15:1;
> +#endif
>
> uint64_t reserved_z16:1; /* Reserved for access_vsm. */
> uint64_t reserved_z17:1; /* Reserved for access_vp_registers. */
> @@ -161,13 +170,85 @@ union hv_partition_synthetic_processor_features {
> /* HvCallRetargetDeviceInterrupt is supported. */
> uint64_t retarget_device_interrupt:1;
>
> +#if defined(__x86_64__)
> /* HvCallRestorePartitionTime is supported. */
> uint64_t restore_time:1;
>
> /* EnlightenedVmcs nested enlightenment is supported. */
> uint64_t enlightened_vmcs:1;
>
> - uint64_t reserved:30;
> + uint64_t nested_debug_ctl:1;
> + uint64_t synthetic_time_unhalted_timer:1;
> + uint64_t idle_spec_ctrl:1;
> +
> +#else
> + uint64_t reserved_z31:1;
> + uint64_t reserved_z32:1;
> + uint64_t reserved_z33:1;
> + uint64_t reserved_z34:1;
> + uint64_t reserved_z35:1;
> +#endif
> +
> +#if defined(__aarch64__)
> + /* Register intercepts supported in V1. As more registers are supported in future
> + * releases, new bits will be added here to prevent migration between incompatible hosts.
> + *
> + * List of registers supported in V1:
> + * 1. TPIDRRO_EL0
> + * 2. TPIDR_EL1
> + * 3. SCTLR_EL1 - Supports write intercept mask.
> + * 4. VBAR_EL1
> + * 5. TCR_EL1 - Supports write intercept mask.
> + * 6. MAIR_EL1 - Supports write intercept mask.
> + * 7. CPACR_EL1 - Supports write intercept mask.
> + * 8. CONTEXTIDR_EL1
> + * 9. PAuth keys (total 10 registers)
> + * 10. HvArm64RegisterSyntheticException
> + */
> + uint64_t register_intercepts_v1:1;
> +#else
> + uint64_t reserved_z36:1;
> +#endif
> +
> + /* HvCallWakeVps is supported */
> + uint64_t wake_vps:1;
> +
> + /* HvCallGet/SetVpRegisters is supported.
> + * Corresponds to AccessVpRegisters privilege.
> + * This feature only affects exo partitions.
> + */
> + uint64_t access_vp_regs:1;
> +
> +#if defined(__aarch64__)
> + /* HvCallSyncContext/Ex is supported. */
> + uint64_t sync_context:1;
> +#else
> + uint64_t reserved_z39:1;
> +#endif /* __aarch64__ */
> +
> + /* Management VTL synic support is allowed.
> + * Corresponds to the ManagementVtlSynicSupport privilege.
> + */
> + uint64_t management_vtl_synic_support:1;
> +
> +#if defined(__x86_64__)
> + /* Hypervisor supports guest mechanism to signal pending interrupts to paravisor. */
> + uint64_t proxy_interrupt_doorbell_support:1;
> +#else
> + uint64_t reserved_z41:1;
> +#endif
> +
> +#if defined(__aarch64__)
> + /* InterceptSystemResetAvailable is exposed. */
> + uint64_t intercept_system_reset:1;
> +#else
> + uint64_t reserved_z42:1;
> +#endif
> +
> + /* Hypercalls for host MMIO operations are available. */
> + uint64_t mmio_hypercalls:1;
> +
> + uint64_t reserved:20;
> };
> };
>
>
> --
> 2.43.0
>
>
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 10/14] accel/mshv: implement cpu_thread_is_idle() hook
2026-03-11 15:15 ` [PATCH 10/14] accel/mshv: implement cpu_thread_is_idle() hook Anirudh Rayabharam
@ 2026-03-11 15:47 ` Mohamed Mediouni
0 siblings, 0 replies; 38+ messages in thread
From: Mohamed Mediouni @ 2026-03-11 15:47 UTC (permalink / raw)
To: Anirudh Rayabharam
Cc: qemu-devel, Magnus Kulke, Wei Liu, Paolo Bonzini,
Marc-André Lureau, "Daniel P. Berrangé",
Philippe Mathieu-Daudé, Peter Maydell, Aastha Rawat,
qemu-arm
> On 11. Mar 2026, at 16:15, Anirudh Rayabharam <anirudh@anirudhrb.com> wrote:
>
> From: Magnus Kulke <magnuskulke@linux.microsoft.com>
>
> In MSHV the hypervisor APIC is always used, so we to implement this hook
> to make sure the AP's vcpu thread is not blocked waiting for an INIT SIPI
> by the BSP. Without this change soft reboots with -smp cpus>=2 will
> hang.
>
> Signed-off-by: Magnus Kulke <magnuskulke@linux.microsoft.com>
Reviewed-by: Mohamed Mediouni <mohamed@unpredictable.fr>
> ---
> accel/mshv/mshv-all.c | 12 ++++++++++++
> 1 file changed, 12 insertions(+)
>
> diff --git a/accel/mshv/mshv-all.c b/accel/mshv/mshv-all.c
> index 563599ef6a..9a101d51ff 100644
> --- a/accel/mshv/mshv-all.c
> +++ b/accel/mshv/mshv-all.c
> @@ -747,11 +747,23 @@ static const TypeInfo mshv_accel_type = {
> .instance_size = sizeof(MshvState),
> };
>
> +/*
> + * MSHV manages the LAPIC in the hypervisor. SIPI for APs are handled
> + * internally. Halted vCPUs must still enter mshv_cpu_exec() so that
> + * MSHV_RUN_VP is called and the hypervisor will deliver SIPI to wake APs.
> + */
> +
> +static bool mshv_vcpu_thread_is_idle(CPUState *cpu)
> +{
> + return false;
> +}
> +
> static void mshv_accel_ops_class_init(ObjectClass *oc, const void *data)
> {
> AccelOpsClass *ops = ACCEL_OPS_CLASS(oc);
>
> ops->create_vcpu_thread = mshv_start_vcpu_thread;
> + ops->cpu_thread_is_idle = mshv_vcpu_thread_is_idle;
> ops->synchronize_post_init = mshv_cpu_synchronize_post_init;
> ops->synchronize_post_reset = mshv_cpu_synchronize_post_reset;
> ops->synchronize_state = mshv_cpu_synchronize;
>
> --
> 2.43.0
>
>
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 02/14] accel/mshv: move msr.c to target/i386
2026-03-11 15:15 ` [PATCH 02/14] accel/mshv: move msr.c to target/i386 Anirudh Rayabharam
@ 2026-03-11 15:47 ` Mohamed Mediouni
2026-03-11 17:06 ` Wei Liu
1 sibling, 0 replies; 38+ messages in thread
From: Mohamed Mediouni @ 2026-03-11 15:47 UTC (permalink / raw)
To: Anirudh Rayabharam
Cc: qemu-devel, Magnus Kulke, Wei Liu, Paolo Bonzini,
Marc-André Lureau, "Daniel P. Berrangé",
Philippe Mathieu-Daudé, Peter Maydell, Aastha Rawat,
qemu-arm
> On 11. Mar 2026, at 16:15, Anirudh Rayabharam <anirudh@anirudhrb.com> wrote:
>
> From: Aastha Rawat <aastharawat@linux.microsoft.com>
>
> This file has x86 specific implementations. Move this file to i386
> folder in preparation for ARM64 MSHV support.
>
> Signed-off-by: Aastha Rawat <aastharawat@linux.microsoft.com>
Reviewed-by: Mohamed Mediouni <mohamed@unpredictable.fr>
>
> ---
> accel/mshv/meson.build | 1 -
> target/i386/mshv/meson.build | 1 +
> {accel => target/i386}/mshv/msr.c | 0
> 3 files changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/accel/mshv/meson.build b/accel/mshv/meson.build
> index c1b1787c5e..e433187cde 100644
> --- a/accel/mshv/meson.build
> +++ b/accel/mshv/meson.build
> @@ -1,6 +1,5 @@
> system_ss.add(when: 'CONFIG_MSHV', if_true: files(
> 'irq.c',
> 'mem.c',
> - 'msr.c',
> 'mshv-all.c'
> ))
> diff --git a/target/i386/mshv/meson.build b/target/i386/mshv/meson.build
> index 49f28d4a5b..6091c21887 100644
> --- a/target/i386/mshv/meson.build
> +++ b/target/i386/mshv/meson.build
> @@ -2,6 +2,7 @@ i386_mshv_ss = ss.source_set()
>
> i386_mshv_ss.add(files(
> 'mshv-cpu.c',
> + 'msr.c',
> ))
>
> i386_system_ss.add_all(when: 'CONFIG_MSHV', if_true: i386_mshv_ss)
> diff --git a/accel/mshv/msr.c b/target/i386/mshv/msr.c
> similarity index 100%
> rename from accel/mshv/msr.c
> rename to target/i386/mshv/msr.c
>
> --
> 2.43.0
>
>
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 09/14] target/arm: cpu: Mark MSHV supporting PSCI 1.3
2026-03-11 15:15 ` [PATCH 09/14] target/arm: cpu: Mark MSHV supporting PSCI 1.3 Anirudh Rayabharam
@ 2026-03-11 15:48 ` Mohamed Mediouni
0 siblings, 0 replies; 38+ messages in thread
From: Mohamed Mediouni @ 2026-03-11 15:48 UTC (permalink / raw)
To: Anirudh Rayabharam
Cc: qemu-devel, Magnus Kulke, Wei Liu, Paolo Bonzini,
Marc-André Lureau, "Daniel P. Berrangé",
Philippe Mathieu-Daudé, Peter Maydell, Aastha Rawat,
qemu-arm
> On 11. Mar 2026, at 16:15, Anirudh Rayabharam <anirudh@anirudhrb.com> wrote:
>
> From: Aastha Rawat <aastharawat@linux.microsoft.com>
>
> MSHV supports PSCI 1.3. Expose this version to guests.
>
> Signed-off-by: Aastha Rawat <aastharawat@linux.microsoft.com>
Reviewed-by: Mohamed Mediouni <mohamed@unpredictable.fr>
> ---
> target/arm/cpu.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/target/arm/cpu.c b/target/arm/cpu.c
> index 4b1e9750e6..a0a018a8cd 100644
> --- a/target/arm/cpu.c
> +++ b/target/arm/cpu.c
> @@ -1157,7 +1157,7 @@ static void arm_cpu_initfn(Object *obj)
> if (tcg_enabled() || hvf_enabled()) {
> /* TCG and HVF implement PSCI 1.1 */
> cpu->psci_version = QEMU_PSCI_VERSION_1_1;
> - } else if (whpx_enabled()) {
> + } else if (whpx_enabled() || mshv_enabled()) {
> cpu->psci_version = QEMU_PSCI_VERSION_1_3;
> }
> }
>
> --
> 2.43.0
>
>
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 01/14] accel/mshv: provision guests with the same features as host
2026-03-11 15:15 ` [PATCH 01/14] accel/mshv: provision guests with the same features as host Anirudh Rayabharam (Microsoft)
@ 2026-03-11 15:50 ` Anirudh Rayabharam
0 siblings, 0 replies; 38+ messages in thread
From: Anirudh Rayabharam @ 2026-03-11 15:50 UTC (permalink / raw)
To: qemu-devel
Cc: Magnus Kulke, Wei Liu, Paolo Bonzini, Marc-André Lureau,
Daniel P. Berrangé, Philippe Mathieu-Daudé,
Peter Maydell, Aastha Rawat, qemu-arm
On Wed, Mar 11, 2026 at 03:15:28PM +0000, Anirudh Rayabharam (Microsoft) wrote:
> Query HV_PARTITION_PROPERTY_PROCESSOR_FEATURES to obtain the feature set
> supported by the host and pass on this feature set to the guest during
> partition creation.
>
> Signed-off-by: Anirudh Rayabharam (Microsoft) <anirudh@anirudhrb.com>
I'll drop this patch in v2 in favor of Magnus' patch here:
https://lore.kernel.org/qemu-devel/20260311113505.1177878-2-magnuskulke@linux.microsoft.com/#t
Anirudh.
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 11/14] target/arm/mshv: add vCPU run loop
2026-03-11 15:15 ` [PATCH 11/14] target/arm/mshv: add vCPU run loop Anirudh Rayabharam (Microsoft)
@ 2026-03-11 15:58 ` Mohamed Mediouni
2026-03-17 7:28 ` Anirudh Rayabharam
0 siblings, 1 reply; 38+ messages in thread
From: Mohamed Mediouni @ 2026-03-11 15:58 UTC (permalink / raw)
To: Anirudh Rayabharam (Microsoft)
Cc: qemu-devel, Magnus Kulke, Wei Liu, Paolo Bonzini,
Marc-André Lureau, "Daniel P. Berrangé",
Philippe Mathieu-Daudé, Peter Maydell, Aastha Rawat,
qemu-arm
> On 11. Mar 2026, at 16:15, Anirudh Rayabharam (Microsoft) <anirudh@anirudhrb.com> wrote:
>
> Add the main vCPU run loop for MSHV using the MSHV_RUN_VP_IOCTL.
>
> Handle MMIO exits by emulating the instruction using the syndrome
> information from ESR_EL2.
>
> Signed-off-by: Anirudh Rayabharam (Microsoft) <anirudh@anirudhrb.com>
> ---
> include/hw/hyperv/hvgdk_mini.h | 44 +++++++++
> target/arm/mshv/mshv-all.c | 198 +++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 242 insertions(+)
>
Hello,
GDK updates in separate patches from the rest please. Maybe even combine them together.
And more comments below...
> diff --git a/include/hw/hyperv/hvgdk_mini.h b/include/hw/hyperv/hvgdk_mini.h
> index d56be0d70f..84b3c6af5f 100644
> --- a/include/hw/hyperv/hvgdk_mini.h
> +++ b/include/hw/hyperv/hvgdk_mini.h
> @@ -750,6 +750,50 @@ struct hv_x64_memory_intercept_message {
> uint8_t instruction_bytes[16];
> };
>
> +union hv_arm64_vp_execution_state {
> + uint16_t as_uint16;
> + struct {
> + uint16_t cpl:2;
> + uint16_t debug_active:1;
> + uint16_t interruption_pending:1;
> + uint16_t vtl:4;
> + uint16_t virtualization_fault_active:1;
> + uint16_t reserved:7;
> + };
> +};
> +
> +struct hv_arm64_intercept_message_header {
> + uint32_t vp_index;
> + uint8_t instruction_length;
> + uint8_t intercept_access_type;
> + union hv_arm64_vp_execution_state execution_state;
> + uint64_t pc;
> + uint64_t cpsr;
> +};
> +
> +union hv_arm64_memory_access_info {
> + uint8_t as_uint8;
> + struct {
> + uint8_t gva_valid:1;
> + uint8_t gva_gpa_valid:1;
> + uint8_t hypercall_output_pending:1;
> + uint8_t reserved:5;
> + };
> +};
> +
> +struct hv_arm64_memory_intercept_message {
> + struct hv_arm64_intercept_message_header header;
> + uint32_t cache_type; /* enum hv_cache_type */
> + uint8_t instruction_byte_count;
> + union hv_arm64_memory_access_info memory_access_info;
> + uint16_t reserved1;
> + uint8_t instruction_bytes[4];
> + uint32_t reserved2;
> + uint64_t guest_virtual_address;
> + uint64_t guest_physical_address;
> + uint64_t syndrome;
> +};
> +
> union hv_message_flags {
> uint8_t asu8;
> struct {
> diff --git a/target/arm/mshv/mshv-all.c b/target/arm/mshv/mshv-all.c
> index 2b983845d3..b0649ba10b 100644
> --- a/target/arm/mshv/mshv-all.c
> +++ b/target/arm/mshv/mshv-all.c
> @@ -166,8 +166,206 @@ int mshv_arch_put_registers(const CPUState *cpu)
> return 0;
> }
>
> +static int set_memory_info(const struct hyperv_message *msg,
> + struct hv_arm64_memory_intercept_message *info)
> +{
> + if (msg->header.message_type != HVMSG_GPA_INTERCEPT
> + && msg->header.message_type != HVMSG_UNMAPPED_GPA
> + && msg->header.message_type != HVMSG_UNACCEPTED_GPA) {
> + error_report("invalid message type");
> + return -1;
> + }
> + memcpy(info, msg->payload, sizeof(*info));
> +
> + return 0;
> +}
> +
> +typedef union {
> + uint64_t raw;
> + struct {
> + uint32_t iss:25;
> + uint32_t il:1;
> + uint32_t ec:6;
> + uint32_t iss2:5;
> + uint32_t _rsvd:27;
> + } QEMU_PACKED;
> +} EsrEl2;
> +
> +typedef union {
> + uint32_t raw;
> + struct {
> + uint32_t dfsc:6;
> + uint32_t wnr:1;
> + uint32_t s1ptw:1;
> + uint32_t cm:1;
> + uint32_t ea:1;
> + uint32_t fnv:1;
> + uint32_t set:2;
> + uint32_t vncr:1;
> + uint32_t ar:1;
> + uint32_t sf:1;
> + uint32_t srt:5;
> + uint32_t sse:1;
> + uint32_t sas:2;
> + uint32_t isv:1;
> + uint32_t _unused:7;
> + } QEMU_PACKED;
> +} IssDataAbort;
Think this is better suited for common code somewhere...
> +
> +typedef enum {
> + data_abort_lower = 36,
> + data_abort = 37,
> +} ExceptionClass;
> +
> +int mshv_store_regs(CPUState *cpu)
> +{
> + int ret;
> +
> + ret = set_standard_regs(cpu);
> + if (ret < 0) {
> + error_report("Failed to store standard registers");
> + return -1;
> + }
> +
> + /* TODO: should store special registers? the equivalent hvf code doesn't */
WHPX does handle this via state levels, but what HVF does via a separate function is also workable.
> + return 0;
> +}
> +
> +static int emulate_with_syndrome(CPUState *cpu,
> + struct hv_arm64_memory_intercept_message *info)
> +{
> + ARMCPU *arm_cpu = ARM_CPU(cpu);
> + CPUARMState *env = &arm_cpu->env;
> + int ret;
> + EsrEl2 syndrome = { 0 };
> + IssDataAbort iss = { 0 };
> + uint64_t gpa = info->guest_physical_address;
> + uint64_t len, reg_index;
> + bool sign_extend;
> +
> + syndrome.raw = info->syndrome;
> +
> + if (!(syndrome.ec == data_abort_lower || syndrome.ec == data_abort)) {
> + error_report("Unknown exception class 0x%x", syndrome.ec);
> + return -1;
> + }
> +
> + iss.raw = syndrome.iss;
> + if (!iss.isv) {
> + error_report("Invalid ESR EL2 ISV field");
> + return -1;
> + }
> +
> + len = 1ULL << iss.sas;
> + sign_extend = iss.sse;
> + reg_index = iss.srt;
> +
> + ret = mshv_load_regs(cpu);
> + if (ret < 0) {
> + error_report("Failed to load registers");
> + return -1;
> + }
> +
> + if (iss.wnr) {
> + uint8_t data[8];
> + uint64_t val = reg_index < 31 ? env->xregs[reg_index] : 0ULL;
> +
> + val = cpu_to_le64(val);
> +
> + memcpy(data, &val, sizeof(val));
> + ret = mshv_guest_mem_write(gpa, data, len, false);
> + if (ret < 0) {
> + error_report("Failed to write guest memory");
> + return -1;
> + }
> + } else {
> + uint8_t data[8] = { 0 };
> +
> + ret = mshv_guest_mem_read(gpa, data, len, false, false);
> + if (ret < 0) {
> + error_report("Failed to read guest memory");
> + return -1;
> + }
> +
> + uint64_t val;
> + memcpy(&val, data, sizeof(val));
> +
> + val = le64_to_cpu(val);
> +
> + if (sign_extend) {
> + uint64_t shift = 64 - (len * 8);
> + val = (((int64_t)val << shift) >> shift);
> + if (!iss.sf) {
> + val &= 0xffffffff;
> + }
> + }
> +
> + env->xregs[reg_index] = val;
> + }
> +
> + env->pc += (syndrome.il == 1) ? 4 : 2;
> +
> + ret = mshv_store_regs(cpu);
> + if (ret < 0) {
> + error_report("failed to store registers");
> + return -1;
> + }
> +
> + return 0;
> +}
I think this deserves to go to common code somewhere at this point :)
> +
> +static int handle_unmapped_mem(int vm_fd, CPUState *cpu,
> + const struct hyperv_message *msg,
> + MshvVmExit *exit_reason)
> +{
> + struct hv_arm64_memory_intercept_message info = { 0 };
> + int ret;
> +
> + ret = set_memory_info(msg, &info);
> + if (ret < 0) {
> + error_report("failed to convert message to memory info");
> + return -1;
> + }
> +
> + ret = emulate_with_syndrome(cpu, &info);
> + if (ret < 0) {
> + error_report("Failed to emulate with syndrome");
> + return -1;
> + }
> +
> + *exit_reason = MshvVmExitIgnore;
> +
> + return 0;
> +}
> +
> int mshv_run_vcpu(int vm_fd, CPUState *cpu, hv_message *msg, MshvVmExit *exit)
> {
> + int ret;
> + int cpu_fd = mshv_vcpufd(cpu);
> +
> + ret = ioctl(cpu_fd, MSHV_RUN_VP, msg);
> + if (ret < 0) {
> + *exit = MshvVmExitShutdown;
> + return ret;
> + }
> +
> + switch (msg->header.message_type) {
> + case HVMSG_UNRECOVERABLE_EXCEPTION:
> + *exit = MshvVmExitShutdown;
> + break;
> + case HVMSG_UNMAPPED_GPA:
At least as observed on WHPX you also need to handle GpaIntercept the same way
for EDK2 to be happy
>
>
> + ret = handle_unmapped_mem(vm_fd, cpu, msg, exit);
> + if (ret < 0) {
> + error_report("failed to handle mmio");
> + return -1;
> + }
> + break;
> + default:
> + error_report("Unhandled message type: 0x%x", msg->header.message_type);
> + return -1;
> + }
> +
> return 0;
> }
>
>
> --
> 2.43.0
>
>
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 00/14] Add ARM64 support for MSHV accelerator
2026-03-11 15:15 [PATCH 00/14] Add ARM64 support for MSHV accelerator Anirudh Rayabharam (Microsoft)
` (13 preceding siblings ...)
2026-03-11 15:15 ` [PATCH 14/14] MAINTAINERS: updates for MSHV arm64 code Anirudh Rayabharam (Microsoft)
@ 2026-03-11 16:54 ` Alex Bennée
2026-03-11 17:02 ` Mohamed Mediouni
2026-03-12 10:23 ` Anirudh Rayabharam
2026-03-11 22:29 ` [PATCH 00/14] Add ARM64 support for MSHV accelerator Pierrick Bouvier
15 siblings, 2 replies; 38+ messages in thread
From: Alex Bennée @ 2026-03-11 16:54 UTC (permalink / raw)
To: Anirudh Rayabharam (Microsoft)
Cc: qemu-devel, Magnus Kulke, Wei Liu, Paolo Bonzini,
Marc-André Lureau, Daniel P. Berrangé,
Philippe Mathieu-Daudé, Peter Maydell, Aastha Rawat,
qemu-arm
"Anirudh Rayabharam (Microsoft)" <anirudh@anirudhrb.com> writes:
> This series adds ARM64 guest support to the MSHV (Microsoft Hypervisor)
> accelerator, enabling QEMU to run aarch64 VMs on Microsoft's hypervisor
> using the mshv Linux kernel module.
Does GitLab (or anything we plug into it) support runners on Arm64 with
HyperV and a Linux Dom0?
I looks like we would need a dedicated runner to defend the
functionality on CI.
>
> The first few patches refactor the existing x86 MSHV code to separate
> arch-specific pieces from common infrastructure: moving MSR handling to
> target/i386, extracting shared register hypercall helpers, provisioning
> host CPU features, and introducing arch-specific init hooks.
>
> The remaining patches add the ARM64 backend:
> - vCPU state get/set using hypervisor register hypercalls
> - -cpu host support by querying ID registers from the hypervisor
> - vCPU run loop with MMIO emulation via ESR_EL2 syndrome decoding
> - In-kernel vGICv3 backed by HVCALL_ASSERT_VIRTUAL_INTERRUPT
> - Interrupt control structure adjustments for arm64
>
> With this series, a standard aarch64 virt machine can be launched with:
> qemu-system-aarch64 -accel mshv -cpu host -M virt ...
>
> Caveats:
> - Currently only direct kernel is supported. We're still debugging edk2
> firmware boot.
> - Live migration is not yet supported.
>
> ---
> Aastha Rawat (7):
> accel/mshv: move msr.c to target/i386
> accel/mshv: extract common CPU register helpers
> meson, target/arm/mshv: Enable arm64 build & add initial MSHV support
> target/arm/mshv: implement vcpu state operations for ARM64
> target/arm/mshv: implement -cpu host for MSHV
> accel/mshv: Add access_vp_regs synthetic proc features
> target/arm: cpu: Mark MSHV supporting PSCI 1.3
>
> Anirudh Rayabharam (Microsoft) (6):
> accel/mshv: provision guests with the same features as host
> accel/mshv: add arch-specific accelerator init hook
> target/arm/mshv: add vCPU run loop
> include/hw/hyperv: adjust hv_interrupt_control structure for arm64
> hw/intc,target/arm/mshv: add MSHV vGICv3 implementation
> MAINTAINERS: updates for MSHV arm64 code
>
> Magnus Kulke (1):
> accel/mshv: implement cpu_thread_is_idle() hook
>
> MAINTAINERS | 8 +
> accel/mshv/irq.c | 2 +
> accel/mshv/meson.build | 4 +-
> accel/mshv/mshv-all.c | 73 +++-
> accel/mshv/mshv-cpu-common.c | 151 +++++++++
> hw/arm/virt.c | 11 +-
> hw/intc/arm_gicv3_common.c | 3 +
> hw/intc/arm_gicv3_mshv.c | 180 ++++++++++
> hw/intc/meson.build | 1 +
> include/hw/hyperv/hvgdk_mini.h | 130 ++++++++
> include/hw/hyperv/hvhdk.h | 97 +++++-
> include/hw/hyperv/hvhdk_mini.h | 6 +
> include/hw/intc/arm_gicv3_common.h | 1 +
> include/system/hw_accel.h | 3 +-
> include/system/mshv.h | 2 +
> include/system/mshv_int.h | 5 +
> meson.build | 7 +-
> target/arm/cpu.c | 7 +-
> target/arm/cpu64.c | 24 +-
> target/arm/meson.build | 1 +
> target/arm/mshv/meson.build | 7 +
> target/arm/mshv/mshv-all.c | 665 +++++++++++++++++++++++++++++++++++++
> target/arm/mshv_arm.h | 18 +
> target/i386/mshv/meson.build | 2 +
> target/i386/mshv/mshv-all.c | 85 +++++
> target/i386/mshv/mshv-cpu.c | 170 +---------
> {accel => target/i386}/mshv/msr.c | 0
> 27 files changed, 1465 insertions(+), 198 deletions(-)
> ---
> base-commit: 1fd5ff9d76d23ab23a68419cbc76d5ee33e8b455
> change-id: 20260311-mshv_accel_arm64_supp-e86b0082aee4
>
> Best regards,
--
Alex Bennée
Virtualisation Tech Lead @ Linaro
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 00/14] Add ARM64 support for MSHV accelerator
2026-03-11 16:54 ` [PATCH 00/14] Add ARM64 support for MSHV accelerator Alex Bennée
@ 2026-03-11 17:02 ` Mohamed Mediouni
2026-03-11 17:12 ` Wei Liu
2026-03-12 10:23 ` Anirudh Rayabharam
1 sibling, 1 reply; 38+ messages in thread
From: Mohamed Mediouni @ 2026-03-11 17:02 UTC (permalink / raw)
To: Alex Bennée
Cc: Anirudh Rayabharam (Microsoft), qemu-devel, Magnus Kulke, Wei Liu,
Paolo Bonzini, Marc-André Lureau,
"Daniel P. Berrangé", Philippe Mathieu-Daudé,
Peter Maydell, Aastha Rawat, qemu-arm
> On 11. Mar 2026, at 17:54, Alex Bennée <alex.bennee@linaro.org> wrote:
>
> "Anirudh Rayabharam (Microsoft)" <anirudh@anirudhrb.com> writes:
>
>> This series adds ARM64 guest support to the MSHV (Microsoft Hypervisor)
>> accelerator, enabling QEMU to run aarch64 VMs on Microsoft's hypervisor
>> using the mshv Linux kernel module.
>
> Does GitLab (or anything we plug into it) support runners on Arm64 with
> HyperV and a Linux Dom0?
>
> I looks like we would need a dedicated runner to defend the
> functionality on CI.
The MSHV license doesn’t allow for any use outside of Azure Kubernetes Service,
despite MSHV (for x86) being public.
And Dom0 is technically not required as there’s L1VH, but that’s even less documented to
the outside and not set up for more local use - but hopefully will make its way to Windows
client at some point :/
>>
>> The first few patches refactor the existing x86 MSHV code to separate
>> arch-specific pieces from common infrastructure: moving MSR handling to
>> target/i386, extracting shared register hypercall helpers, provisioning
>> host CPU features, and introducing arch-specific init hooks.
>>
>> The remaining patches add the ARM64 backend:
>> - vCPU state get/set using hypervisor register hypercalls
>> - -cpu host support by querying ID registers from the hypervisor
>> - vCPU run loop with MMIO emulation via ESR_EL2 syndrome decoding
>> - In-kernel vGICv3 backed by HVCALL_ASSERT_VIRTUAL_INTERRUPT
>> - Interrupt control structure adjustments for arm64
>>
>> With this series, a standard aarch64 virt machine can be launched with:
>> qemu-system-aarch64 -accel mshv -cpu host -M virt ...
>>
>> Caveats:
>> - Currently only direct kernel is supported. We're still debugging edk2
>> firmware boot.
>> - Live migration is not yet supported.
>>
>> ---
>> Aastha Rawat (7):
>> accel/mshv: move msr.c to target/i386
>> accel/mshv: extract common CPU register helpers
>> meson, target/arm/mshv: Enable arm64 build & add initial MSHV support
>> target/arm/mshv: implement vcpu state operations for ARM64
>> target/arm/mshv: implement -cpu host for MSHV
>> accel/mshv: Add access_vp_regs synthetic proc features
>> target/arm: cpu: Mark MSHV supporting PSCI 1.3
>>
>> Anirudh Rayabharam (Microsoft) (6):
>> accel/mshv: provision guests with the same features as host
>> accel/mshv: add arch-specific accelerator init hook
>> target/arm/mshv: add vCPU run loop
>> include/hw/hyperv: adjust hv_interrupt_control structure for arm64
>> hw/intc,target/arm/mshv: add MSHV vGICv3 implementation
>> MAINTAINERS: updates for MSHV arm64 code
>>
>> Magnus Kulke (1):
>> accel/mshv: implement cpu_thread_is_idle() hook
>>
>> MAINTAINERS | 8 +
>> accel/mshv/irq.c | 2 +
>> accel/mshv/meson.build | 4 +-
>> accel/mshv/mshv-all.c | 73 +++-
>> accel/mshv/mshv-cpu-common.c | 151 +++++++++
>> hw/arm/virt.c | 11 +-
>> hw/intc/arm_gicv3_common.c | 3 +
>> hw/intc/arm_gicv3_mshv.c | 180 ++++++++++
>> hw/intc/meson.build | 1 +
>> include/hw/hyperv/hvgdk_mini.h | 130 ++++++++
>> include/hw/hyperv/hvhdk.h | 97 +++++-
>> include/hw/hyperv/hvhdk_mini.h | 6 +
>> include/hw/intc/arm_gicv3_common.h | 1 +
>> include/system/hw_accel.h | 3 +-
>> include/system/mshv.h | 2 +
>> include/system/mshv_int.h | 5 +
>> meson.build | 7 +-
>> target/arm/cpu.c | 7 +-
>> target/arm/cpu64.c | 24 +-
>> target/arm/meson.build | 1 +
>> target/arm/mshv/meson.build | 7 +
>> target/arm/mshv/mshv-all.c | 665 +++++++++++++++++++++++++++++++++++++
>> target/arm/mshv_arm.h | 18 +
>> target/i386/mshv/meson.build | 2 +
>> target/i386/mshv/mshv-all.c | 85 +++++
>> target/i386/mshv/mshv-cpu.c | 170 +---------
>> {accel => target/i386}/mshv/msr.c | 0
>> 27 files changed, 1465 insertions(+), 198 deletions(-)
>> ---
>> base-commit: 1fd5ff9d76d23ab23a68419cbc76d5ee33e8b455
>> change-id: 20260311-mshv_accel_arm64_supp-e86b0082aee4
>>
>> Best regards,
>
> --
> Alex Bennée
> Virtualisation Tech Lead @ Linaro
>
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 02/14] accel/mshv: move msr.c to target/i386
2026-03-11 15:15 ` [PATCH 02/14] accel/mshv: move msr.c to target/i386 Anirudh Rayabharam
2026-03-11 15:47 ` Mohamed Mediouni
@ 2026-03-11 17:06 ` Wei Liu
1 sibling, 0 replies; 38+ messages in thread
From: Wei Liu @ 2026-03-11 17:06 UTC (permalink / raw)
To: Anirudh Rayabharam
Cc: qemu-devel, Magnus Kulke, Wei Liu, Paolo Bonzini,
Marc-André Lureau, Daniel P. Berrangé,
Philippe Mathieu-Daudé, Peter Maydell, Aastha Rawat,
qemu-arm
On Wed, Mar 11, 2026 at 03:15:29PM +0000, Anirudh Rayabharam wrote:
> From: Aastha Rawat <aastharawat@linux.microsoft.com>
>
> This file has x86 specific implementations. Move this file to i386
> folder in preparation for ARM64 MSHV support.
>
> Signed-off-by: Aastha Rawat <aastharawat@linux.microsoft.com>
Acked-by: Wei Liu <wei.liu@kernel.org>
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 00/14] Add ARM64 support for MSHV accelerator
2026-03-11 17:02 ` Mohamed Mediouni
@ 2026-03-11 17:12 ` Wei Liu
2026-03-12 5:20 ` Mohamed Mediouni
0 siblings, 1 reply; 38+ messages in thread
From: Wei Liu @ 2026-03-11 17:12 UTC (permalink / raw)
To: Mohamed Mediouni
Cc: Alex Bennée, Anirudh Rayabharam (Microsoft), qemu-devel,
Magnus Kulke, Wei Liu, Paolo Bonzini, Marc-André Lureau,
"Daniel P. Berrangé", Philippe Mathieu-Daudé,
Peter Maydell, Aastha Rawat, qemu-arm
On Wed, Mar 11, 2026 at 06:02:26PM +0100, Mohamed Mediouni wrote:
>
>
> > On 11. Mar 2026, at 17:54, Alex Bennée <alex.bennee@linaro.org> wrote:
> >
> > "Anirudh Rayabharam (Microsoft)" <anirudh@anirudhrb.com> writes:
> >
> >> This series adds ARM64 guest support to the MSHV (Microsoft Hypervisor)
> >> accelerator, enabling QEMU to run aarch64 VMs on Microsoft's hypervisor
> >> using the mshv Linux kernel module.
> >
> > Does GitLab (or anything we plug into it) support runners on Arm64 with
> > HyperV and a Linux Dom0?
> >
> > I looks like we would need a dedicated runner to defend the
> > functionality on CI.
>
>
> The MSHV license doesn’t allow for any use outside of Azure Kubernetes Service,
> despite MSHV (for x86) being public.
>
> And Dom0 is technically not required as there’s L1VH, but that’s even less documented to
> the outside and not set up for more local use - but hopefully will make its way to Windows
> client at some point :/
Direct Virtualization (the marketing name for L1VH) will become
generally available on Azure at some point (hopefully within this
calendar year). I am not sure about Windows client though.
Thanks,
Wei
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 08/14] accel/mshv: Add access_vp_regs synthetic proc features
2026-03-11 15:15 ` [PATCH 08/14] accel/mshv: Add access_vp_regs synthetic proc features Anirudh Rayabharam
2026-03-11 15:35 ` Mohamed Mediouni
@ 2026-03-11 20:51 ` Wei Liu
2026-03-20 6:46 ` Aastha Rawat
1 sibling, 1 reply; 38+ messages in thread
From: Wei Liu @ 2026-03-11 20:51 UTC (permalink / raw)
To: Anirudh Rayabharam
Cc: qemu-devel, Magnus Kulke, Wei Liu, Paolo Bonzini,
Marc-André Lureau, Daniel P. Berrangé,
Philippe Mathieu-Daudé, Peter Maydell, Aastha Rawat,
qemu-arm
On Wed, Mar 11, 2026 at 03:15:35PM +0000, Anirudh Rayabharam wrote:
> From: Aastha Rawat <aastharawat@linux.microsoft.com>
>
> Enable access_vp_regs feature for regs. In arm64, this feature bit
> allows the guest to set VP registers using hypercall. This wasn't
> required for x86 because such registers are set using wrmsr instead of
> hypercall.
>
> Signed-off-by: Aastha Rawat <aastharawat@linux.microsoft.com>
> ---
> accel/mshv/mshv-all.c | 1 +
> include/hw/hyperv/hvhdk.h | 87 +++++++++++++++++++++++++++++++++++++++++++++--
> 2 files changed, 85 insertions(+), 3 deletions(-)
>
> diff --git a/accel/mshv/mshv-all.c b/accel/mshv/mshv-all.c
> index d63b3a53bf..563599ef6a 100644
> --- a/accel/mshv/mshv-all.c
> +++ b/accel/mshv/mshv-all.c
> @@ -199,6 +199,7 @@ static int set_synthetic_proc_features(int vm_fd)
> features.tb_flush_hypercalls = 1;
> features.synthetic_cluster_ipi = 1;
> features.direct_synthetic_timers = 1;
> + features.access_vp_regs = 1;
What's the side effect for enabling this for x86?
Wei
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 00/14] Add ARM64 support for MSHV accelerator
2026-03-11 15:15 [PATCH 00/14] Add ARM64 support for MSHV accelerator Anirudh Rayabharam (Microsoft)
` (14 preceding siblings ...)
2026-03-11 16:54 ` [PATCH 00/14] Add ARM64 support for MSHV accelerator Alex Bennée
@ 2026-03-11 22:29 ` Pierrick Bouvier
15 siblings, 0 replies; 38+ messages in thread
From: Pierrick Bouvier @ 2026-03-11 22:29 UTC (permalink / raw)
To: Anirudh Rayabharam (Microsoft), qemu-devel
Cc: Magnus Kulke, Wei Liu, Paolo Bonzini, Marc-André Lureau,
Daniel P. Berrangé, Philippe Mathieu-Daudé,
Peter Maydell, Aastha Rawat, qemu-arm
Hi Anirudh,
On 3/11/26 8:15 AM, Anirudh Rayabharam (Microsoft) wrote:
> This series adds ARM64 guest support to the MSHV (Microsoft Hypervisor)
> accelerator, enabling QEMU to run aarch64 VMs on Microsoft's hypervisor
> using the mshv Linux kernel module.
>
> The first few patches refactor the existing x86 MSHV code to separate
> arch-specific pieces from common infrastructure: moving MSR handling to
> target/i386, extracting shared register hypercall helpers, provisioning
> host CPU features, and introducing arch-specific init hooks.
>
> The remaining patches add the ARM64 backend:
> - vCPU state get/set using hypervisor register hypercalls
> - -cpu host support by querying ID registers from the hypervisor
> - vCPU run loop with MMIO emulation via ESR_EL2 syndrome decoding
> - In-kernel vGICv3 backed by HVCALL_ASSERT_VIRTUAL_INTERRUPT
> - Interrupt control structure adjustments for arm64
>
> With this series, a standard aarch64 virt machine can be launched with:
> qemu-system-aarch64 -accel mshv -cpu host -M virt ...
>
> Caveats:
> - Currently only direct kernel is supported. We're still debugging edk2
> firmware boot.
> - Live migration is not yet supported.
>
> ---
> Aastha Rawat (7):
> accel/mshv: move msr.c to target/i386
> accel/mshv: extract common CPU register helpers
> meson, target/arm/mshv: Enable arm64 build & add initial MSHV support
> target/arm/mshv: implement vcpu state operations for ARM64
> target/arm/mshv: implement -cpu host for MSHV
> accel/mshv: Add access_vp_regs synthetic proc features
> target/arm: cpu: Mark MSHV supporting PSCI 1.3
>
> Anirudh Rayabharam (Microsoft) (6):
> accel/mshv: provision guests with the same features as host
> accel/mshv: add arch-specific accelerator init hook
> target/arm/mshv: add vCPU run loop
> include/hw/hyperv: adjust hv_interrupt_control structure for arm64
> hw/intc,target/arm/mshv: add MSHV vGICv3 implementation
> MAINTAINERS: updates for MSHV arm64 code
>
> Magnus Kulke (1):
> accel/mshv: implement cpu_thread_is_idle() hook
>
> MAINTAINERS | 8 +
> accel/mshv/irq.c | 2 +
> accel/mshv/meson.build | 4 +-
> accel/mshv/mshv-all.c | 73 +++-
> accel/mshv/mshv-cpu-common.c | 151 +++++++++
> hw/arm/virt.c | 11 +-
> hw/intc/arm_gicv3_common.c | 3 +
> hw/intc/arm_gicv3_mshv.c | 180 ++++++++++
> hw/intc/meson.build | 1 +
> include/hw/hyperv/hvgdk_mini.h | 130 ++++++++
> include/hw/hyperv/hvhdk.h | 97 +++++-
> include/hw/hyperv/hvhdk_mini.h | 6 +
> include/hw/intc/arm_gicv3_common.h | 1 +
> include/system/hw_accel.h | 3 +-
> include/system/mshv.h | 2 +
> include/system/mshv_int.h | 5 +
> meson.build | 7 +-
> target/arm/cpu.c | 7 +-
> target/arm/cpu64.c | 24 +-
> target/arm/meson.build | 1 +
> target/arm/mshv/meson.build | 7 +
> target/arm/mshv/mshv-all.c | 665 +++++++++++++++++++++++++++++++++++++
> target/arm/mshv_arm.h | 18 +
> target/i386/mshv/meson.build | 2 +
> target/i386/mshv/mshv-all.c | 85 +++++
> target/i386/mshv/mshv-cpu.c | 170 +---------
> {accel => target/i386}/mshv/msr.c | 0
> 27 files changed, 1465 insertions(+), 198 deletions(-)
> ---
> base-commit: 1fd5ff9d76d23ab23a68419cbc76d5ee33e8b455
> change-id: 20260311-mshv_accel_arm64_supp-e86b0082aee4
>
> Best regards,
I have a question about MSHV itself.
Is it possible to get access to it through a Windows install, or a
custom binary or disk image, or is it not redistributed and available
only through Azure instances?
Regards,
Pierrick
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 00/14] Add ARM64 support for MSHV accelerator
2026-03-11 17:12 ` Wei Liu
@ 2026-03-12 5:20 ` Mohamed Mediouni
2026-03-12 20:22 ` Wei Liu
0 siblings, 1 reply; 38+ messages in thread
From: Mohamed Mediouni @ 2026-03-12 5:20 UTC (permalink / raw)
To: Wei Liu
Cc: Alex Bennée, Anirudh Rayabharam (Microsoft), qemu-devel,
Magnus Kulke, Paolo Bonzini, Marc-André Lureau,
"Daniel P. Berrangé", Philippe Mathieu-Daudé,
Peter Maydell, Aastha Rawat, qemu-arm
> On 11. Mar 2026, at 18:12, Wei Liu <wei.liu@kernel.org> wrote:
>
> On Wed, Mar 11, 2026 at 06:02:26PM +0100, Mohamed Mediouni wrote:
>>
>>
>>> On 11. Mar 2026, at 17:54, Alex Bennée <alex.bennee@linaro.org> wrote:
>>>
>>> "Anirudh Rayabharam (Microsoft)" <anirudh@anirudhrb.com> writes:
>>>
>>>> This series adds ARM64 guest support to the MSHV (Microsoft Hypervisor)
>>>> accelerator, enabling QEMU to run aarch64 VMs on Microsoft's hypervisor
>>>> using the mshv Linux kernel module.
>>>
>>> Does GitLab (or anything we plug into it) support runners on Arm64 with
>>> HyperV and a Linux Dom0?
>>>
>>> I looks like we would need a dedicated runner to defend the
>>> functionality on CI.
>>
>>
>> The MSHV license doesn’t allow for any use outside of Azure Kubernetes Service,
>> despite MSHV (for x86) being public.
>>
>> And Dom0 is technically not required as there’s L1VH, but that’s even less documented to
>> the outside and not set up for more local use - but hopefully will make its way to Windows
>> client at some point :/
>
> Direct Virtualization (the marketing name for L1VH) will become
> generally available on Azure at some point (hopefully within this
> calendar year). I am not sure about Windows client though.
Hi,
Could you ask if it’d be possible to have Windows client as an L1VH host, if even just Insider builds?
Either as a Windows Hypervisor Platform privilege (even no save/restore is okay, just being able
to enable the privilege is good enough for testing), or through HCS for WSL2 (or just Hyper-V VMs)?
Because at this point that’d solve the testability issue…
Thank you,
-Mohamed
>
> Thanks,
> Wei
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 00/14] Add ARM64 support for MSHV accelerator
2026-03-11 16:54 ` [PATCH 00/14] Add ARM64 support for MSHV accelerator Alex Bennée
2026-03-11 17:02 ` Mohamed Mediouni
@ 2026-03-12 10:23 ` Anirudh Rayabharam
2026-03-12 10:28 ` Anirudh Rayabharam
` (2 more replies)
1 sibling, 3 replies; 38+ messages in thread
From: Anirudh Rayabharam @ 2026-03-12 10:23 UTC (permalink / raw)
To: Alex Bennée
Cc: qemu-devel, Magnus Kulke, Wei Liu, Paolo Bonzini,
Marc-André Lureau, Daniel P. Berrangé,
Philippe Mathieu-Daudé, Peter Maydell, Aastha Rawat,
qemu-arm
On Wed, Mar 11, 2026 at 04:54:45PM +0000, Alex Bennée wrote:
> "Anirudh Rayabharam (Microsoft)" <anirudh@anirudhrb.com> writes:
>
> > This series adds ARM64 guest support to the MSHV (Microsoft Hypervisor)
> > accelerator, enabling QEMU to run aarch64 VMs on Microsoft's hypervisor
> > using the mshv Linux kernel module.
>
> Does GitLab (or anything we plug into it) support runners on Arm64 with
> HyperV and a Linux Dom0?
>
> I looks like we would need a dedicated runner to defend the
> functionality on CI.
Right. I think we would need to onboard a custom self-hosted runner for this.
That's what we did on GitHub for the Cloud Hypervisor project.
Thanks,
Anirudh.
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 00/14] Add ARM64 support for MSHV accelerator
2026-03-12 10:23 ` Anirudh Rayabharam
@ 2026-03-12 10:28 ` Anirudh Rayabharam
2026-03-12 10:32 ` [PATCH 08/14] accel/mshv: Add access_vp_regs synthetic proc features Anirudh Rayabharam
2026-03-12 10:45 ` Mohamed Mediouni
2 siblings, 0 replies; 38+ messages in thread
From: Anirudh Rayabharam @ 2026-03-12 10:28 UTC (permalink / raw)
To: Pierrick Bouvier
Cc: qemu-devel, Magnus Kulke, Wei Liu, Paolo Bonzini,
Marc-André Lureau, Daniel P. Berrangé,
Philippe Mathieu-Daudé, Peter Maydell, Aastha Rawat,
qemu-arm
On Wed, Mar 11, 2026 at 03:29:09PM -0700, Pierrick Bouvier wrote:
> Hi Anirudh,
>
> On 3/11/26 8:15 AM, Anirudh Rayabharam (Microsoft) wrote:
> > This series adds ARM64 guest support to the MSHV (Microsoft Hypervisor)
> > accelerator, enabling QEMU to run aarch64 VMs on Microsoft's hypervisor
> > using the mshv Linux kernel module.
> >
> > The first few patches refactor the existing x86 MSHV code to separate
> > arch-specific pieces from common infrastructure: moving MSR handling to
> > target/i386, extracting shared register hypercall helpers, provisioning
> > host CPU features, and introducing arch-specific init hooks.
> >
> > The remaining patches add the ARM64 backend:
> > - vCPU state get/set using hypervisor register hypercalls
> > - -cpu host support by querying ID registers from the hypervisor
> > - vCPU run loop with MMIO emulation via ESR_EL2 syndrome decoding
> > - In-kernel vGICv3 backed by HVCALL_ASSERT_VIRTUAL_INTERRUPT
> > - Interrupt control structure adjustments for arm64
> >
> > With this series, a standard aarch64 virt machine can be launched with:
> > qemu-system-aarch64 -accel mshv -cpu host -M virt ...
> >
> > Caveats:
> > - Currently only direct kernel is supported. We're still debugging edk2
> > firmware boot.
> > - Live migration is not yet supported.
> >
> > ---
> > Aastha Rawat (7):
> > accel/mshv: move msr.c to target/i386
> > accel/mshv: extract common CPU register helpers
> > meson, target/arm/mshv: Enable arm64 build & add initial MSHV support
> > target/arm/mshv: implement vcpu state operations for ARM64
> > target/arm/mshv: implement -cpu host for MSHV
> > accel/mshv: Add access_vp_regs synthetic proc features
> > target/arm: cpu: Mark MSHV supporting PSCI 1.3
> >
> > Anirudh Rayabharam (Microsoft) (6):
> > accel/mshv: provision guests with the same features as host
> > accel/mshv: add arch-specific accelerator init hook
> > target/arm/mshv: add vCPU run loop
> > include/hw/hyperv: adjust hv_interrupt_control structure for arm64
> > hw/intc,target/arm/mshv: add MSHV vGICv3 implementation
> > MAINTAINERS: updates for MSHV arm64 code
> >
> > Magnus Kulke (1):
> > accel/mshv: implement cpu_thread_is_idle() hook
> >
> > MAINTAINERS | 8 +
> > accel/mshv/irq.c | 2 +
> > accel/mshv/meson.build | 4 +-
> > accel/mshv/mshv-all.c | 73 +++-
> > accel/mshv/mshv-cpu-common.c | 151 +++++++++
> > hw/arm/virt.c | 11 +-
> > hw/intc/arm_gicv3_common.c | 3 +
> > hw/intc/arm_gicv3_mshv.c | 180 ++++++++++
> > hw/intc/meson.build | 1 +
> > include/hw/hyperv/hvgdk_mini.h | 130 ++++++++
> > include/hw/hyperv/hvhdk.h | 97 +++++-
> > include/hw/hyperv/hvhdk_mini.h | 6 +
> > include/hw/intc/arm_gicv3_common.h | 1 +
> > include/system/hw_accel.h | 3 +-
> > include/system/mshv.h | 2 +
> > include/system/mshv_int.h | 5 +
> > meson.build | 7 +-
> > target/arm/cpu.c | 7 +-
> > target/arm/cpu64.c | 24 +-
> > target/arm/meson.build | 1 +
> > target/arm/mshv/meson.build | 7 +
> > target/arm/mshv/mshv-all.c | 665 +++++++++++++++++++++++++++++++++++++
> > target/arm/mshv_arm.h | 18 +
> > target/i386/mshv/meson.build | 2 +
> > target/i386/mshv/mshv-all.c | 85 +++++
> > target/i386/mshv/mshv-cpu.c | 170 +---------
> > {accel => target/i386}/mshv/msr.c | 0
> > 27 files changed, 1465 insertions(+), 198 deletions(-)
> > ---
> > base-commit: 1fd5ff9d76d23ab23a68419cbc76d5ee33e8b455
> > change-id: 20260311-mshv_accel_arm64_supp-e86b0082aee4
> >
> > Best regards,
>
> I have a question about MSHV itself.
>
> Is it possible to get access to it through a Windows install, or a custom
> binary or disk image, or is it not redistributed and available only through
> Azure instances?
Hi Pierrick,
Based on the information we currently have the direct virtualization
feature will be publicly available on Azure soon. While Windows installs
on client machines do have the hypervisor available, it is not known
whether those builds will have direct virtualization support in the
future.
Thanks,
Anirudh.
>
> Regards,
> Pierrick
>
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 08/14] accel/mshv: Add access_vp_regs synthetic proc features
2026-03-12 10:23 ` Anirudh Rayabharam
2026-03-12 10:28 ` Anirudh Rayabharam
@ 2026-03-12 10:32 ` Anirudh Rayabharam
2026-03-12 10:45 ` Mohamed Mediouni
2 siblings, 0 replies; 38+ messages in thread
From: Anirudh Rayabharam @ 2026-03-12 10:32 UTC (permalink / raw)
To: Mohamed Mediouni
Cc: qemu-devel, Magnus Kulke, Wei Liu, Paolo Bonzini,
Marc-André Lureau, "Daniel P. Berrangé",
Philippe Mathieu-Daudé, Peter Maydell, Aastha Rawat,
qemu-arm
On Wed, Mar 11, 2026 at 04:35:31PM +0100, Mohamed Mediouni wrote:
>
>
> > On 11. Mar 2026, at 16:15, Anirudh Rayabharam <anirudh@anirudhrb.com> wrote:
> >
> > From: Aastha Rawat <aastharawat@linux.microsoft.com>
> >
> > Enable access_vp_regs feature for regs. In arm64, this feature bit
> > allows the guest to set VP registers using hypercall. This wasn't
> > required for x86 because such registers are set using wrmsr instead of
> > hypercall.
> >
> Hello,
>
> Could you split this into two patches? With the hvhdk.h changes in another patch.
Any reason why?
Throughout this series we're introducing hv*dk changes along with the
code using them. Isn't that a good idea?
Thanks,
Anirudh.
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 08/14] accel/mshv: Add access_vp_regs synthetic proc features
2026-03-12 10:23 ` Anirudh Rayabharam
2026-03-12 10:28 ` Anirudh Rayabharam
2026-03-12 10:32 ` [PATCH 08/14] accel/mshv: Add access_vp_regs synthetic proc features Anirudh Rayabharam
@ 2026-03-12 10:45 ` Mohamed Mediouni
2026-03-13 9:01 ` Anirudh Rayabharam
2 siblings, 1 reply; 38+ messages in thread
From: Mohamed Mediouni @ 2026-03-12 10:45 UTC (permalink / raw)
To: Anirudh Rayabharam
Cc: qemu-devel, Magnus Kulke, Wei Liu, Paolo Bonzini,
Marc-André Lureau, "Daniel P. Berrangé",
Philippe Mathieu-Daudé, Peter Maydell, Aastha Rawat,
qemu-arm
> On 12. Mar 2026, at 11:32, Anirudh Rayabharam <anirudh@anirudhrb.com> wrote:
>
> On Wed, Mar 11, 2026 at 04:35:31PM +0100, Mohamed Mediouni wrote:
>>
>>
>>> On 11. Mar 2026, at 16:15, Anirudh Rayabharam <anirudh@anirudhrb.com> wrote:
>>>
>>> From: Aastha Rawat <aastharawat@linux.microsoft.com>
>>>
>>> Enable access_vp_regs feature for regs. In arm64, this feature bit
>>> allows the guest to set VP registers using hypercall. This wasn't
>>> required for x86 because such registers are set using wrmsr instead of
>>> hypercall.
>>>
>> Hello,
>>
>> Could you split this into two patches? With the hvhdk.h changes in another patch.
>
> Any reason why?
>
> Throughout this series we're introducing hv*dk changes along with the
> code using them. Isn't that a good idea?
>
Hello,
I think that because of some of the content of header updates aren’t immediately related to the commits at hand, it’d be better to
just have a single big commit at the beginning of the series for any GDK/HDK updates.
Oh also, preemptively adding some header definitions before they’re immediately needed could be simpler for everyone
- especially given that WHP exists and is overlapping a lot.
Also makes me think of whether it could be better to share some code between WHPX and MSHV, but that’s a separate
story…
Thanks,
-Mohamed
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 00/14] Add ARM64 support for MSHV accelerator
2026-03-12 5:20 ` Mohamed Mediouni
@ 2026-03-12 20:22 ` Wei Liu
0 siblings, 0 replies; 38+ messages in thread
From: Wei Liu @ 2026-03-12 20:22 UTC (permalink / raw)
To: Mohamed Mediouni
Cc: Wei Liu, Alex Bennée, Anirudh Rayabharam (Microsoft),
qemu-devel, Magnus Kulke, Paolo Bonzini, Marc-André Lureau,
"Daniel P. Berrangé", Philippe Mathieu-Daudé,
Peter Maydell, Aastha Rawat, qemu-arm
On Thu, Mar 12, 2026 at 06:20:10AM +0100, Mohamed Mediouni wrote:
>
>
> > On 11. Mar 2026, at 18:12, Wei Liu <wei.liu@kernel.org> wrote:
> >
> > On Wed, Mar 11, 2026 at 06:02:26PM +0100, Mohamed Mediouni wrote:
> >>
> >>
> >>> On 11. Mar 2026, at 17:54, Alex Bennée <alex.bennee@linaro.org> wrote:
> >>>
> >>> "Anirudh Rayabharam (Microsoft)" <anirudh@anirudhrb.com> writes:
> >>>
> >>>> This series adds ARM64 guest support to the MSHV (Microsoft Hypervisor)
> >>>> accelerator, enabling QEMU to run aarch64 VMs on Microsoft's hypervisor
> >>>> using the mshv Linux kernel module.
> >>>
> >>> Does GitLab (or anything we plug into it) support runners on Arm64 with
> >>> HyperV and a Linux Dom0?
> >>>
> >>> I looks like we would need a dedicated runner to defend the
> >>> functionality on CI.
> >>
> >>
> >> The MSHV license doesn’t allow for any use outside of Azure Kubernetes Service,
> >> despite MSHV (for x86) being public.
> >>
> >> And Dom0 is technically not required as there’s L1VH, but that’s even less documented to
> >> the outside and not set up for more local use - but hopefully will make its way to Windows
> >> client at some point :/
> >
> > Direct Virtualization (the marketing name for L1VH) will become
> > generally available on Azure at some point (hopefully within this
> > calendar year). I am not sure about Windows client though.
>
> Hi,
>
> Could you ask if it’d be possible to have Windows client as an L1VH host, if even just Insider builds?
>
> Either as a Windows Hypervisor Platform privilege (even no save/restore is okay, just being able
> to enable the privilege is good enough for testing), or through HCS for WSL2 (or just Hyper-V VMs)?
>
I can pass on the question. Don't hold your breath though -- it is not
something engineers decide.
> Because at this point that’d solve the testability issue…
I agree. The more accessible this technology is, the better.
Wei
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 08/14] accel/mshv: Add access_vp_regs synthetic proc features
2026-03-12 10:45 ` Mohamed Mediouni
@ 2026-03-13 9:01 ` Anirudh Rayabharam
2026-03-13 11:29 ` Mohamed Mediouni
0 siblings, 1 reply; 38+ messages in thread
From: Anirudh Rayabharam @ 2026-03-13 9:01 UTC (permalink / raw)
To: Mohamed Mediouni
Cc: qemu-devel, Magnus Kulke, Wei Liu, Paolo Bonzini,
Marc-André Lureau, "Daniel P. Berrangé",
Philippe Mathieu-Daudé, Peter Maydell, Aastha Rawat,
qemu-arm
On Thu, Mar 12, 2026 at 11:45:48AM +0100, Mohamed Mediouni wrote:
>
>
> > On 12. Mar 2026, at 11:32, Anirudh Rayabharam <anirudh@anirudhrb.com> wrote:
> >
> > On Wed, Mar 11, 2026 at 04:35:31PM +0100, Mohamed Mediouni wrote:
> >>
> >>
> >>> On 11. Mar 2026, at 16:15, Anirudh Rayabharam <anirudh@anirudhrb.com> wrote:
> >>>
> >>> From: Aastha Rawat <aastharawat@linux.microsoft.com>
> >>>
> >>> Enable access_vp_regs feature for regs. In arm64, this feature bit
> >>> allows the guest to set VP registers using hypercall. This wasn't
> >>> required for x86 because such registers are set using wrmsr instead of
> >>> hypercall.
> >>>
> >> Hello,
> >>
> >> Could you split this into two patches? With the hvhdk.h changes in another patch.
> >
> > Any reason why?
> >
> > Throughout this series we're introducing hv*dk changes along with the
> > code using them. Isn't that a good idea?
> >
> Hello,
>
> I think that because of some of the content of header updates aren’t immediately related to the commits at hand, it’d be better to
> just have a single big commit at the beginning of the series for any GDK/HDK updates.
I think that in this series all the header updates are closely related
to the commits they're made in. Do you see a discrepancy?
>
> Oh also, preemptively adding some header definitions before they’re immediately needed could be simpler for everyone
> - especially given that WHP exists and is overlapping a lot.
Could you please elaborate? How would it be simpler? Do you mean simpler
for reviewing?
Thanks,
Anirudh.
>
> Also makes me think of whether it could be better to share some code between WHPX and MSHV, but that’s a separate
> story…
>
> Thanks,
> -Mohamed
>
>
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 08/14] accel/mshv: Add access_vp_regs synthetic proc features
2026-03-13 9:01 ` Anirudh Rayabharam
@ 2026-03-13 11:29 ` Mohamed Mediouni
2026-03-17 3:17 ` Anirudh Rayabharam
0 siblings, 1 reply; 38+ messages in thread
From: Mohamed Mediouni @ 2026-03-13 11:29 UTC (permalink / raw)
To: Anirudh Rayabharam
Cc: qemu-devel, Magnus Kulke, Wei Liu, Paolo Bonzini,
Marc-André Lureau, "Daniel P. Berrangé",
Philippe Mathieu-Daudé, Peter Maydell, Aastha Rawat,
qemu-arm
> On 13. Mar 2026, at 10:01, Anirudh Rayabharam <anirudh@anirudhrb.com> wrote:
>
> On Thu, Mar 12, 2026 at 11:45:48AM +0100, Mohamed Mediouni wrote:
>>
>>
>>> On 12. Mar 2026, at 11:32, Anirudh Rayabharam <anirudh@anirudhrb.com> wrote:
>>>
>>> On Wed, Mar 11, 2026 at 04:35:31PM +0100, Mohamed Mediouni wrote:
>>>>
>>>>
>>>>> On 11. Mar 2026, at 16:15, Anirudh Rayabharam <anirudh@anirudhrb.com> wrote:
>>>>>
>>>>> From: Aastha Rawat <aastharawat@linux.microsoft.com>
>>>>>
>>>>> Enable access_vp_regs feature for regs. In arm64, this feature bit
>>>>> allows the guest to set VP registers using hypercall. This wasn't
>>>>> required for x86 because such registers are set using wrmsr instead of
>>>>> hypercall.
>>>>>
>>>> Hello,
>>>>
>>>> Could you split this into two patches? With the hvhdk.h changes in another patch.
>>>
>>> Any reason why?
>>>
>>> Throughout this series we're introducing hv*dk changes along with the
>>> code using them. Isn't that a good idea?
>>>
>> Hello,
>>
>> I think that because of some of the content of header updates aren’t immediately related to the commits at hand, it’d be better to
>> just have a single big commit at the beginning of the series for any GDK/HDK updates.
>
> I think that in this series all the header updates are closely related
> to the commits they're made in. Do you see a discrepancy?
>
Hello,
As a random example https://lore.kernel.org/qemu-devel/20260312202209.GA124403@liuwe-devbox-debian-v2.local/T/#madb0f563a418a8fa1ebe35edd782aa4414893e5c ("accel/mshv: Add access_vp_regs synthetic proc features”) adds a bunch of other bits that aren’t that directly related to it.
It doesn’t mean that this info is not useful to have upstream - that’s great to have - but I think that a separate commit for the header updates at the beginning (combining them all) is best.
>>
>>
>> Oh also, preemptively adding some header definitions before they’re immediately needed could be simpler for everyone
>> - especially given that WHP exists and is overlapping a lot.
>
> Could you please elaborate? How would it be simpler? Do you mean simpler
> for reviewing?
>
Yes.
Thank you,
-Mohamed
> Thanks,
> Anirudh.
>
>>
>> Also makes me think of whether it could be better to share some code between WHPX and MSHV, but that’s a separate
>> story…
>>
>> Thanks,
>> -Mohamed
>>
>>
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 08/14] accel/mshv: Add access_vp_regs synthetic proc features
2026-03-13 11:29 ` Mohamed Mediouni
@ 2026-03-17 3:17 ` Anirudh Rayabharam
0 siblings, 0 replies; 38+ messages in thread
From: Anirudh Rayabharam @ 2026-03-17 3:17 UTC (permalink / raw)
To: Mohamed Mediouni
Cc: qemu-devel, Magnus Kulke, Wei Liu, Paolo Bonzini,
Marc-André Lureau, "Daniel P. Berrangé",
Philippe Mathieu-Daudé, Peter Maydell, Aastha Rawat,
qemu-arm
On Fri, Mar 13, 2026 at 12:29:32PM +0100, Mohamed Mediouni wrote:
>
>
> > On 13. Mar 2026, at 10:01, Anirudh Rayabharam <anirudh@anirudhrb.com> wrote:
> >
> > On Thu, Mar 12, 2026 at 11:45:48AM +0100, Mohamed Mediouni wrote:
> >>
> >>
> >>> On 12. Mar 2026, at 11:32, Anirudh Rayabharam <anirudh@anirudhrb.com> wrote:
> >>>
> >>> On Wed, Mar 11, 2026 at 04:35:31PM +0100, Mohamed Mediouni wrote:
> >>>>
> >>>>
> >>>>> On 11. Mar 2026, at 16:15, Anirudh Rayabharam <anirudh@anirudhrb.com> wrote:
> >>>>>
> >>>>> From: Aastha Rawat <aastharawat@linux.microsoft.com>
> >>>>>
> >>>>> Enable access_vp_regs feature for regs. In arm64, this feature bit
> >>>>> allows the guest to set VP registers using hypercall. This wasn't
> >>>>> required for x86 because such registers are set using wrmsr instead of
> >>>>> hypercall.
> >>>>>
> >>>> Hello,
> >>>>
> >>>> Could you split this into two patches? With the hvhdk.h changes in another patch.
> >>>
> >>> Any reason why?
> >>>
> >>> Throughout this series we're introducing hv*dk changes along with the
> >>> code using them. Isn't that a good idea?
> >>>
> >> Hello,
> >>
> >> I think that because of some of the content of header updates aren’t immediately related to the commits at hand, it’d be better to
> >> just have a single big commit at the beginning of the series for any GDK/HDK updates.
> >
> > I think that in this series all the header updates are closely related
> > to the commits they're made in. Do you see a discrepancy?
> >
> Hello,
>
> As a random example https://lore.kernel.org/qemu-devel/20260312202209.GA124403@liuwe-devbox-debian-v2.local/T/#madb0f563a418a8fa1ebe35edd782aa4414893e5c ("accel/mshv: Add access_vp_regs synthetic proc features”) adds a bunch of other bits that aren’t that directly related to it.
Sure, there are some additional fields but they must be added along with
the commit to preserve the correct layout of the struct. So, I would
argue that in spite of the additional fields this header update belongs
in this commit.
In general, I do agree that if the header updates are completely
unrelated or if they're massive they should be in a commit of their own.
But IMO the updates in this patch series don't fall into either category
Thanks,
Anirudh.
>
> It doesn’t mean that this info is not useful to have upstream - that’s great to have - but I think that a separate commit for the header updates at the beginning (combining them all) is best.
>
> >>
> >>
> >> Oh also, preemptively adding some header definitions before they’re immediately needed could be simpler for everyone
> >> - especially given that WHP exists and is overlapping a lot.
> >
> > Could you please elaborate? How would it be simpler? Do you mean simpler
> > for reviewing?
> >
> Yes.
>
> Thank you,
> -Mohamed
> > Thanks,
> > Anirudh.
> >
> >>
> >> Also makes me think of whether it could be better to share some code between WHPX and MSHV, but that’s a separate
> >> story…
> >>
> >> Thanks,
> >> -Mohamed
> >>
> >>
>
>
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 11/14] target/arm/mshv: add vCPU run loop
2026-03-11 15:58 ` Mohamed Mediouni
@ 2026-03-17 7:28 ` Anirudh Rayabharam
0 siblings, 0 replies; 38+ messages in thread
From: Anirudh Rayabharam @ 2026-03-17 7:28 UTC (permalink / raw)
To: Mohamed Mediouni
Cc: qemu-devel, Magnus Kulke, Wei Liu, Paolo Bonzini,
Marc-André Lureau, "Daniel P. Berrangé",
Philippe Mathieu-Daudé, Peter Maydell, Aastha Rawat,
qemu-arm
On Wed, Mar 11, 2026 at 04:58:28PM +0100, Mohamed Mediouni wrote:
>
>
> > On 11. Mar 2026, at 16:15, Anirudh Rayabharam (Microsoft) <anirudh@anirudhrb.com> wrote:
> >
> > Add the main vCPU run loop for MSHV using the MSHV_RUN_VP_IOCTL.
> >
> > Handle MMIO exits by emulating the instruction using the syndrome
> > information from ESR_EL2.
> >
> > Signed-off-by: Anirudh Rayabharam (Microsoft) <anirudh@anirudhrb.com>
> > ---
> > include/hw/hyperv/hvgdk_mini.h | 44 +++++++++
> > target/arm/mshv/mshv-all.c | 198 +++++++++++++++++++++++++++++++++++++++++
> > 2 files changed, 242 insertions(+)
> >
> Hello,
>
> GDK updates in separate patches from the rest please. Maybe even combine them together.
The header updates are closely related to what this patch is doing.
>
> And more comments below...
>
> > diff --git a/include/hw/hyperv/hvgdk_mini.h b/include/hw/hyperv/hvgdk_mini.h
> > index d56be0d70f..84b3c6af5f 100644
> > --- a/include/hw/hyperv/hvgdk_mini.h
> > +++ b/include/hw/hyperv/hvgdk_mini.h
> > @@ -750,6 +750,50 @@ struct hv_x64_memory_intercept_message {
> > uint8_t instruction_bytes[16];
> > };
> >
> > +union hv_arm64_vp_execution_state {
> > + uint16_t as_uint16;
> > + struct {
> > + uint16_t cpl:2;
> > + uint16_t debug_active:1;
> > + uint16_t interruption_pending:1;
> > + uint16_t vtl:4;
> > + uint16_t virtualization_fault_active:1;
> > + uint16_t reserved:7;
> > + };
> > +};
> > +
> > +struct hv_arm64_intercept_message_header {
> > + uint32_t vp_index;
> > + uint8_t instruction_length;
> > + uint8_t intercept_access_type;
> > + union hv_arm64_vp_execution_state execution_state;
> > + uint64_t pc;
> > + uint64_t cpsr;
> > +};
> > +
> > +union hv_arm64_memory_access_info {
> > + uint8_t as_uint8;
> > + struct {
> > + uint8_t gva_valid:1;
> > + uint8_t gva_gpa_valid:1;
> > + uint8_t hypercall_output_pending:1;
> > + uint8_t reserved:5;
> > + };
> > +};
> > +
> > +struct hv_arm64_memory_intercept_message {
> > + struct hv_arm64_intercept_message_header header;
> > + uint32_t cache_type; /* enum hv_cache_type */
> > + uint8_t instruction_byte_count;
> > + union hv_arm64_memory_access_info memory_access_info;
> > + uint16_t reserved1;
> > + uint8_t instruction_bytes[4];
> > + uint32_t reserved2;
> > + uint64_t guest_virtual_address;
> > + uint64_t guest_physical_address;
> > + uint64_t syndrome;
> > +};
> > +
> > union hv_message_flags {
> > uint8_t asu8;
> > struct {
> > diff --git a/target/arm/mshv/mshv-all.c b/target/arm/mshv/mshv-all.c
> > index 2b983845d3..b0649ba10b 100644
> > --- a/target/arm/mshv/mshv-all.c
> > +++ b/target/arm/mshv/mshv-all.c
> > @@ -166,8 +166,206 @@ int mshv_arch_put_registers(const CPUState *cpu)
> > return 0;
> > }
> >
> > +static int set_memory_info(const struct hyperv_message *msg,
> > + struct hv_arm64_memory_intercept_message *info)
> > +{
> > + if (msg->header.message_type != HVMSG_GPA_INTERCEPT
> > + && msg->header.message_type != HVMSG_UNMAPPED_GPA
> > + && msg->header.message_type != HVMSG_UNACCEPTED_GPA) {
> > + error_report("invalid message type");
> > + return -1;
> > + }
> > + memcpy(info, msg->payload, sizeof(*info));
> > +
> > + return 0;
> > +}
> > +
> > +typedef union {
> > + uint64_t raw;
> > + struct {
> > + uint32_t iss:25;
> > + uint32_t il:1;
> > + uint32_t ec:6;
> > + uint32_t iss2:5;
> > + uint32_t _rsvd:27;
> > + } QEMU_PACKED;
> > +} EsrEl2;
> > +
> > +typedef union {
> > + uint32_t raw;
> > + struct {
> > + uint32_t dfsc:6;
> > + uint32_t wnr:1;
> > + uint32_t s1ptw:1;
> > + uint32_t cm:1;
> > + uint32_t ea:1;
> > + uint32_t fnv:1;
> > + uint32_t set:2;
> > + uint32_t vncr:1;
> > + uint32_t ar:1;
> > + uint32_t sf:1;
> > + uint32_t srt:5;
> > + uint32_t sse:1;
> > + uint32_t sas:2;
> > + uint32_t isv:1;
> > + uint32_t _unused:7;
> > + } QEMU_PACKED;
> > +} IssDataAbort;
> Think this is better suited for common code somewhere...
> > +
> > +typedef enum {
> > + data_abort_lower = 36,
> > + data_abort = 37,
> > +} ExceptionClass;
> > +
> > +int mshv_store_regs(CPUState *cpu)
> > +{
> > + int ret;
> > +
> > + ret = set_standard_regs(cpu);
> > + if (ret < 0) {
> > + error_report("Failed to store standard registers");
> > + return -1;
> > + }
> > +
> > + /* TODO: should store special registers? the equivalent hvf code doesn't */
> WHPX does handle this via state levels, but what HVF does via a separate function is also workable.
Yeah, we'll add more registers in a later series. I think I'll get rid of
this TODO.
>
> > + return 0;
> > +}
> > +
> > +static int emulate_with_syndrome(CPUState *cpu,
> > + struct hv_arm64_memory_intercept_message *info)
> > +{
> > + ARMCPU *arm_cpu = ARM_CPU(cpu);
> > + CPUARMState *env = &arm_cpu->env;
> > + int ret;
> > + EsrEl2 syndrome = { 0 };
> > + IssDataAbort iss = { 0 };
> > + uint64_t gpa = info->guest_physical_address;
> > + uint64_t len, reg_index;
> > + bool sign_extend;
> > +
> > + syndrome.raw = info->syndrome;
> > +
> > + if (!(syndrome.ec == data_abort_lower || syndrome.ec == data_abort)) {
> > + error_report("Unknown exception class 0x%x", syndrome.ec);
> > + return -1;
> > + }
> > +
> > + iss.raw = syndrome.iss;
> > + if (!iss.isv) {
> > + error_report("Invalid ESR EL2 ISV field");
> > + return -1;
> > + }
> > +
> > + len = 1ULL << iss.sas;
> > + sign_extend = iss.sse;
> > + reg_index = iss.srt;
> > +
> > + ret = mshv_load_regs(cpu);
> > + if (ret < 0) {
> > + error_report("Failed to load registers");
> > + return -1;
> > + }
> > +
> > + if (iss.wnr) {
> > + uint8_t data[8];
> > + uint64_t val = reg_index < 31 ? env->xregs[reg_index] : 0ULL;
> > +
> > + val = cpu_to_le64(val);
> > +
> > + memcpy(data, &val, sizeof(val));
> > + ret = mshv_guest_mem_write(gpa, data, len, false);
> > + if (ret < 0) {
> > + error_report("Failed to write guest memory");
> > + return -1;
> > + }
> > + } else {
> > + uint8_t data[8] = { 0 };
> > +
> > + ret = mshv_guest_mem_read(gpa, data, len, false, false);
> > + if (ret < 0) {
> > + error_report("Failed to read guest memory");
> > + return -1;
> > + }
> > +
> > + uint64_t val;
> > + memcpy(&val, data, sizeof(val));
> > +
> > + val = le64_to_cpu(val);
> > +
> > + if (sign_extend) {
> > + uint64_t shift = 64 - (len * 8);
> > + val = (((int64_t)val << shift) >> shift);
> > + if (!iss.sf) {
> > + val &= 0xffffffff;
> > + }
> > + }
> > +
> > + env->xregs[reg_index] = val;
> > + }
> > +
> > + env->pc += (syndrome.il == 1) ? 4 : 2;
> > +
> > + ret = mshv_store_regs(cpu);
> > + if (ret < 0) {
> > + error_report("failed to store registers");
> > + return -1;
> > + }
> > +
> > + return 0;
> > +}
>
> I think this deserves to go to common code somewhere at this point :)
Do you have any ideas as to where this code can go?
>
> > +
> > +static int handle_unmapped_mem(int vm_fd, CPUState *cpu,
> > + const struct hyperv_message *msg,
> > + MshvVmExit *exit_reason)
> > +{
> > + struct hv_arm64_memory_intercept_message info = { 0 };
> > + int ret;
> > +
> > + ret = set_memory_info(msg, &info);
> > + if (ret < 0) {
> > + error_report("failed to convert message to memory info");
> > + return -1;
> > + }
> > +
> > + ret = emulate_with_syndrome(cpu, &info);
> > + if (ret < 0) {
> > + error_report("Failed to emulate with syndrome");
> > + return -1;
> > + }
> > +
> > + *exit_reason = MshvVmExitIgnore;
> > +
> > + return 0;
> > +}
> > +
> > int mshv_run_vcpu(int vm_fd, CPUState *cpu, hv_message *msg, MshvVmExit *exit)
> > {
> > + int ret;
> > + int cpu_fd = mshv_vcpufd(cpu);
> > +
> > + ret = ioctl(cpu_fd, MSHV_RUN_VP, msg);
> > + if (ret < 0) {
> > + *exit = MshvVmExitShutdown;
> > + return ret;
> > + }
> > +
> > + switch (msg->header.message_type) {
> > + case HVMSG_UNRECOVERABLE_EXCEPTION:
> > + *exit = MshvVmExitShutdown;
> > + break;
> > + case HVMSG_UNMAPPED_GPA:
> At least as observed on WHPX you also need to handle GpaIntercept the same way
> for EDK2 to be happy
Interesting, because Cloud Hypervisor doesn't handle GPA_INTERCEPT at
all for arm64 and still works fine with EDK2.
Anyway, I tried adding it but EDK2 still isn't happy. There seems to be
some other issue potentially related to the mshv driver in the kernel.
Thanks,
Anirudh.
> >
> >
> > + ret = handle_unmapped_mem(vm_fd, cpu, msg, exit);
> > + if (ret < 0) {
> > + error_report("failed to handle mmio");
> > + return -1;
> > + }
> > + break;
> > + default:
> > + error_report("Unhandled message type: 0x%x", msg->header.message_type);
> > + return -1;
> > + }
> > +
> > return 0;
> > }
> >
> >
> > --
> > 2.43.0
> >
> >
>
>
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 08/14] accel/mshv: Add access_vp_regs synthetic proc features
2026-03-11 20:51 ` Wei Liu
@ 2026-03-20 6:46 ` Aastha Rawat
0 siblings, 0 replies; 38+ messages in thread
From: Aastha Rawat @ 2026-03-20 6:46 UTC (permalink / raw)
To: Wei Liu
Cc: Anirudh Rayabharam, qemu-devel, Magnus Kulke, Paolo Bonzini,
Marc-André Lureau, Daniel P. Berrangé,
Philippe Mathieu-Daudé, Peter Maydell, qemu-arm
On Wed, Mar 11, 2026 at 08:51:42PM +0000, Wei Liu wrote:
> > + features.access_vp_regs = 1;
>
> What's the side effect for enabling this for x86?
>
> Wei
Enabling this bit is primarily a permission granting flag, it doesn't
have any functional side effects. X86 guests will continue to use wrmsr
rather than hypercalls to manage their state. This is similar to what we
have implemented in cloud-hypervisor for ARM64.
Thanks,
Aastha
^ permalink raw reply [flat|nested] 38+ messages in thread
end of thread, other threads:[~2026-03-20 12:44 UTC | newest]
Thread overview: 38+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-11 15:15 [PATCH 00/14] Add ARM64 support for MSHV accelerator Anirudh Rayabharam (Microsoft)
2026-03-11 15:15 ` [PATCH 01/14] accel/mshv: provision guests with the same features as host Anirudh Rayabharam (Microsoft)
2026-03-11 15:50 ` Anirudh Rayabharam
2026-03-11 15:15 ` [PATCH 02/14] accel/mshv: move msr.c to target/i386 Anirudh Rayabharam
2026-03-11 15:47 ` Mohamed Mediouni
2026-03-11 17:06 ` Wei Liu
2026-03-11 15:15 ` [PATCH 03/14] accel/mshv: extract common CPU register helpers Anirudh Rayabharam
2026-03-11 15:15 ` [PATCH 04/14] meson, target/arm/mshv: Enable arm64 build & add initial MSHV support Anirudh Rayabharam
2026-03-11 15:15 ` [PATCH 05/14] target/arm/mshv: implement vcpu state operations for ARM64 Anirudh Rayabharam
2026-03-11 15:15 ` [PATCH 06/14] target/arm/mshv: implement -cpu host for MSHV Anirudh Rayabharam
2026-03-11 15:15 ` [PATCH 07/14] accel/mshv: add arch-specific accelerator init hook Anirudh Rayabharam (Microsoft)
2026-03-11 15:15 ` [PATCH 08/14] accel/mshv: Add access_vp_regs synthetic proc features Anirudh Rayabharam
2026-03-11 15:35 ` Mohamed Mediouni
2026-03-11 20:51 ` Wei Liu
2026-03-20 6:46 ` Aastha Rawat
2026-03-11 15:15 ` [PATCH 09/14] target/arm: cpu: Mark MSHV supporting PSCI 1.3 Anirudh Rayabharam
2026-03-11 15:48 ` Mohamed Mediouni
2026-03-11 15:15 ` [PATCH 10/14] accel/mshv: implement cpu_thread_is_idle() hook Anirudh Rayabharam
2026-03-11 15:47 ` Mohamed Mediouni
2026-03-11 15:15 ` [PATCH 11/14] target/arm/mshv: add vCPU run loop Anirudh Rayabharam (Microsoft)
2026-03-11 15:58 ` Mohamed Mediouni
2026-03-17 7:28 ` Anirudh Rayabharam
2026-03-11 15:15 ` [PATCH 12/14] include/hw/hyperv: adjust hv_interrupt_control structure for arm64 Anirudh Rayabharam (Microsoft)
2026-03-11 15:15 ` [PATCH 13/14] hw/intc,target/arm/mshv: add MSHV vGICv3 implementation Anirudh Rayabharam (Microsoft)
2026-03-11 15:15 ` [PATCH 14/14] MAINTAINERS: updates for MSHV arm64 code Anirudh Rayabharam (Microsoft)
2026-03-11 16:54 ` [PATCH 00/14] Add ARM64 support for MSHV accelerator Alex Bennée
2026-03-11 17:02 ` Mohamed Mediouni
2026-03-11 17:12 ` Wei Liu
2026-03-12 5:20 ` Mohamed Mediouni
2026-03-12 20:22 ` Wei Liu
2026-03-12 10:23 ` Anirudh Rayabharam
2026-03-12 10:28 ` Anirudh Rayabharam
2026-03-12 10:32 ` [PATCH 08/14] accel/mshv: Add access_vp_regs synthetic proc features Anirudh Rayabharam
2026-03-12 10:45 ` Mohamed Mediouni
2026-03-13 9:01 ` Anirudh Rayabharam
2026-03-13 11:29 ` Mohamed Mediouni
2026-03-17 3:17 ` Anirudh Rayabharam
2026-03-11 22:29 ` [PATCH 00/14] Add ARM64 support for MSHV accelerator Pierrick Bouvier
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox