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