mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
target/i386/mshv: Implement mshv_store_regs()
Add support for writing general-purpose registers to MSHV vCPUs during initialization or migration using the MSHV register interface. A generic set_register call is introduced to abstract the HV call over the various register types. Signed-off-by: Magnus Kulke <magnuskulke@linux.microsoft.com> Link: https://lore.kernel.org/r/20250916164847.77883-14-magnuskulke@linux.microsoft.com [mshv.h/mshv_int.h split. - Paolo] Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
committed by
Paolo Bonzini
parent
4ed605c06e
commit
2bd7a6aa47
@@ -18,6 +18,7 @@
|
||||
#include "qemu/accel.h"
|
||||
#include "hw/hyperv/hyperv-proto.h"
|
||||
#include "hw/hyperv/hvhdk.h"
|
||||
#include "hw/hyperv/hvgdk_mini.h"
|
||||
#include "qapi/qapi-types-common.h"
|
||||
#include "system/memory.h"
|
||||
#include "accel/accel-ops.h"
|
||||
|
||||
@@ -61,6 +61,8 @@ void mshv_remove_vcpu(int vm_fd, int cpu_fd);
|
||||
int mshv_run_vcpu(int vm_fd, CPUState *cpu, hv_message *msg, MshvVmExit *exit);
|
||||
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_arch_put_registers(const CPUState *cpu);
|
||||
void mshv_arch_init_vcpu(CPUState *cpu);
|
||||
void mshv_arch_destroy_vcpu(CPUState *cpu);
|
||||
|
||||
+114
-2
@@ -32,12 +32,124 @@
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
static enum hv_register_name STANDARD_REGISTER_NAMES[18] = {
|
||||
HV_X64_REGISTER_RAX,
|
||||
HV_X64_REGISTER_RBX,
|
||||
HV_X64_REGISTER_RCX,
|
||||
HV_X64_REGISTER_RDX,
|
||||
HV_X64_REGISTER_RSI,
|
||||
HV_X64_REGISTER_RDI,
|
||||
HV_X64_REGISTER_RSP,
|
||||
HV_X64_REGISTER_RBP,
|
||||
HV_X64_REGISTER_R8,
|
||||
HV_X64_REGISTER_R9,
|
||||
HV_X64_REGISTER_R10,
|
||||
HV_X64_REGISTER_R11,
|
||||
HV_X64_REGISTER_R12,
|
||||
HV_X64_REGISTER_R13,
|
||||
HV_X64_REGISTER_R14,
|
||||
HV_X64_REGISTER_R15,
|
||||
HV_X64_REGISTER_RIP,
|
||||
HV_X64_REGISTER_RFLAGS,
|
||||
};
|
||||
|
||||
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;
|
||||
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 */
|
||||
in = g_malloc0(in_sz);
|
||||
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);
|
||||
g_free(in);
|
||||
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 set_standard_regs(const CPUState *cpu)
|
||||
{
|
||||
X86CPU *x86cpu = X86_CPU(cpu);
|
||||
CPUX86State *env = &x86cpu->env;
|
||||
hv_register_assoc assocs[ARRAY_SIZE(STANDARD_REGISTER_NAMES)];
|
||||
int ret;
|
||||
size_t n_regs = ARRAY_SIZE(STANDARD_REGISTER_NAMES);
|
||||
|
||||
/* set names */
|
||||
for (size_t i = 0; i < ARRAY_SIZE(STANDARD_REGISTER_NAMES); i++) {
|
||||
assocs[i].name = STANDARD_REGISTER_NAMES[i];
|
||||
}
|
||||
assocs[0].value.reg64 = env->regs[R_EAX];
|
||||
assocs[1].value.reg64 = env->regs[R_EBX];
|
||||
assocs[2].value.reg64 = env->regs[R_ECX];
|
||||
assocs[3].value.reg64 = env->regs[R_EDX];
|
||||
assocs[4].value.reg64 = env->regs[R_ESI];
|
||||
assocs[5].value.reg64 = env->regs[R_EDI];
|
||||
assocs[6].value.reg64 = env->regs[R_ESP];
|
||||
assocs[7].value.reg64 = env->regs[R_EBP];
|
||||
assocs[8].value.reg64 = env->regs[R_R8];
|
||||
assocs[9].value.reg64 = env->regs[R_R9];
|
||||
assocs[10].value.reg64 = env->regs[R_R10];
|
||||
assocs[11].value.reg64 = env->regs[R_R11];
|
||||
assocs[12].value.reg64 = env->regs[R_R12];
|
||||
assocs[13].value.reg64 = env->regs[R_R13];
|
||||
assocs[14].value.reg64 = env->regs[R_R14];
|
||||
assocs[15].value.reg64 = env->regs[R_R15];
|
||||
assocs[16].value.reg64 = env->eip;
|
||||
lflags_to_rflags(env);
|
||||
assocs[17].value.reg64 = env->eflags;
|
||||
|
||||
ret = mshv_set_generic_regs(cpu, assocs, n_regs);
|
||||
if (ret < 0) {
|
||||
error_report("failed to set standard registers");
|
||||
return -errno;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mshv_store_regs(CPUState *cpu)
|
||||
{
|
||||
error_report("unimplemented");
|
||||
abort();
|
||||
int ret;
|
||||
|
||||
ret = set_standard_regs(cpu);
|
||||
if (ret < 0) {
|
||||
error_report("Failed to store standard registers");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int mshv_load_regs(CPUState *cpu)
|
||||
{
|
||||
error_report("unimplemented");
|
||||
|
||||
Reference in New Issue
Block a user