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.45.4