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 <[email protected]> --- 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 <[email protected]> + * Magnus Kulke <[email protected]> + * Jinank Jain <[email protected]> + * + * 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 4ed6e7548f..e1df5e8a17 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) @@ -1605,8 +1485,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 @@ -1614,9 +1492,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.45.4
