Fetch standard register state from MSHV vCPUs to support debugging,
migration, and other introspection features in QEMU.
Fetch standard register state from a MHSV vCPU's. A generic get_regs()
function and a mapper to map the different register representations are
introduced.
Signed-off-by: Magnus Kulke <magnuskulke@linux.microsoft.com>
---
include/system/mshv.h | 1 +
target/i386/mshv/mshv-cpu.c | 69 +++++++++++++++++++++++++++++++++++--
2 files changed, 68 insertions(+), 2 deletions(-)
diff --git a/include/system/mshv.h b/include/system/mshv.h
index adce4153d9..65f7fa15a0 100644
--- a/include/system/mshv.h
+++ b/include/system/mshv.h
@@ -88,6 +88,7 @@ typedef enum MshvVmExit {
void mshv_init_cpu_logic(void);
int mshv_create_vcpu(int vm_fd, uint8_t vp_index, int *cpu_fd);
void mshv_remove_vcpu(int vm_fd, int cpu_fd);
+int mshv_get_standard_regs(CPUState *cpu);
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);
diff --git a/target/i386/mshv/mshv-cpu.c b/target/i386/mshv/mshv-cpu.c
index 4bd4e29b72..cb59d74eb4 100644
--- a/target/i386/mshv/mshv-cpu.c
+++ b/target/i386/mshv/mshv-cpu.c
@@ -61,6 +61,18 @@ int mshv_set_generic_regs(int cpu_fd, hv_register_assoc *assocs, size_t n_regs)
return ioctl(cpu_fd, MSHV_SET_VP_REGISTERS, &input);
}
+static int get_generic_regs(int cpu_fd, struct hv_register_assoc *assocs,
+ size_t n_regs)
+{
+ struct mshv_vp_registers input = {
+ .count = n_regs,
+ .regs = assocs,
+ };
+
+ return ioctl(cpu_fd, MSHV_GET_VP_REGISTERS, &input);
+}
+
+
static int set_standard_regs(const CPUState *cpu)
{
X86CPU *x86cpu = X86_CPU(cpu);
@@ -115,11 +127,64 @@ int mshv_store_regs(CPUState *cpu)
return 0;
}
+static void populate_standard_regs(const hv_register_assoc *assocs,
+ CPUX86State *env)
+{
+ env->regs[R_EAX] = assocs[0].value.reg64;
+ env->regs[R_EBX] = assocs[1].value.reg64;
+ env->regs[R_ECX] = assocs[2].value.reg64;
+ env->regs[R_EDX] = assocs[3].value.reg64;
+ env->regs[R_ESI] = assocs[4].value.reg64;
+ env->regs[R_EDI] = assocs[5].value.reg64;
+ env->regs[R_ESP] = assocs[6].value.reg64;
+ env->regs[R_EBP] = assocs[7].value.reg64;
+ env->regs[R_R8] = assocs[8].value.reg64;
+ env->regs[R_R9] = assocs[9].value.reg64;
+ env->regs[R_R10] = assocs[10].value.reg64;
+ env->regs[R_R11] = assocs[11].value.reg64;
+ env->regs[R_R12] = assocs[12].value.reg64;
+ env->regs[R_R13] = assocs[13].value.reg64;
+ env->regs[R_R14] = assocs[14].value.reg64;
+ env->regs[R_R15] = assocs[15].value.reg64;
+
+ env->eip = assocs[16].value.reg64;
+ env->eflags = assocs[17].value.reg64;
+ rflags_to_lflags(env);
+}
+
+int mshv_get_standard_regs(CPUState *cpu)
+{
+ struct hv_register_assoc assocs[ARRAY_SIZE(STANDARD_REGISTER_NAMES)];
+ int ret;
+ X86CPU *x86cpu = X86_CPU(cpu);
+ CPUX86State *env = &x86cpu->env;
+ int cpu_fd = mshv_vcpufd(cpu);
+ size_t n_regs = ARRAY_SIZE(STANDARD_REGISTER_NAMES);
+
+ for (size_t i = 0; i < n_regs; i++) {
+ assocs[i].name = STANDARD_REGISTER_NAMES[i];
+ }
+ ret = get_generic_regs(cpu_fd, assocs, n_regs);
+ if (ret < 0) {
+ error_report("failed to get standard registers");
+ return -1;
+ }
+
+ populate_standard_regs(assocs, env);
+ return 0;
+}
int mshv_load_regs(CPUState *cpu)
{
- error_report("unimplemented");
- abort();
+ int ret;
+
+ ret = mshv_get_standard_regs(cpu);
+ if (ret < 0) {
+ error_report("Failed to load standard registers");
+ return -1;
+ }
+
+ return 0;
}
int mshv_arch_put_registers(const CPUState *cpu)
--
2.34.1