From: "Anirudh Rayabharam (Microsoft)" <anirudh@anirudhrb.com>
Add the main vCPU run loop for MSHV using the MSHV_RUN_VP_IOCTL.
Handle MMIO exits by emulating the instruction using the syndrome
information from ESR_EL2.
Signed-off-by: Anirudh Rayabharam (Microsoft) <anirudh@anirudhrb.com>
---
include/hw/hyperv/hvgdk_mini.h | 44 +++++++++++++++++++
target/arm/mshv/mshv-all.c | 95 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 139 insertions(+)
diff --git a/include/hw/hyperv/hvgdk_mini.h b/include/hw/hyperv/hvgdk_mini.h
index d56be0d70f..84b3c6af5f 100644
--- a/include/hw/hyperv/hvgdk_mini.h
+++ b/include/hw/hyperv/hvgdk_mini.h
@@ -750,6 +750,50 @@ struct hv_x64_memory_intercept_message {
uint8_t instruction_bytes[16];
};
+union hv_arm64_vp_execution_state {
+ uint16_t as_uint16;
+ struct {
+ uint16_t cpl:2;
+ uint16_t debug_active:1;
+ uint16_t interruption_pending:1;
+ uint16_t vtl:4;
+ uint16_t virtualization_fault_active:1;
+ uint16_t reserved:7;
+ };
+};
+
+struct hv_arm64_intercept_message_header {
+ uint32_t vp_index;
+ uint8_t instruction_length;
+ uint8_t intercept_access_type;
+ union hv_arm64_vp_execution_state execution_state;
+ uint64_t pc;
+ uint64_t cpsr;
+};
+
+union hv_arm64_memory_access_info {
+ uint8_t as_uint8;
+ struct {
+ uint8_t gva_valid:1;
+ uint8_t gva_gpa_valid:1;
+ uint8_t hypercall_output_pending:1;
+ uint8_t reserved:5;
+ };
+};
+
+struct hv_arm64_memory_intercept_message {
+ struct hv_arm64_intercept_message_header header;
+ uint32_t cache_type; /* enum hv_cache_type */
+ uint8_t instruction_byte_count;
+ union hv_arm64_memory_access_info memory_access_info;
+ uint16_t reserved1;
+ uint8_t instruction_bytes[4];
+ uint32_t reserved2;
+ uint64_t guest_virtual_address;
+ uint64_t guest_physical_address;
+ uint64_t syndrome;
+};
+
union hv_message_flags {
uint8_t asu8;
struct {
diff --git a/target/arm/mshv/mshv-all.c b/target/arm/mshv/mshv-all.c
index 8d16971c0d..c1c0291461 100644
--- a/target/arm/mshv/mshv-all.c
+++ b/target/arm/mshv/mshv-all.c
@@ -21,6 +21,7 @@
#include "target/arm/cpu.h"
#include "target/arm/internals.h"
#include "target/arm/mshv_arm.h"
+#include "target/arm/helper.h"
#include "system/mshv.h"
#include "system/mshv_int.h"
@@ -166,8 +167,102 @@ int mshv_arch_put_registers(const CPUState *cpu)
return 0;
}
+static int set_memory_info(const struct hyperv_message *msg,
+ struct hv_arm64_memory_intercept_message *info)
+{
+ if (msg->header.message_type != HVMSG_GPA_INTERCEPT
+ && msg->header.message_type != HVMSG_UNMAPPED_GPA
+ && msg->header.message_type != HVMSG_UNACCEPTED_GPA) {
+ error_report("invalid message type");
+ return -1;
+ }
+ memcpy(info, msg->payload, sizeof(*info));
+
+ return 0;
+}
+
+int mshv_store_regs(CPUState *cpu)
+{
+ int ret;
+
+ ret = set_standard_regs(cpu);
+ if (ret < 0) {
+ error_report("Failed to store standard registers");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int handle_unmapped_mem(int vm_fd, CPUState *cpu,
+ const struct hyperv_message *msg,
+ MshvVmExit *exit_reason)
+{
+ struct hv_arm64_memory_intercept_message info = { 0 };
+ ARMCPU *arm_cpu = ARM_CPU(cpu);
+ CPUARMState *env = &arm_cpu->env;
+ int ret;
+ EsrEl2 syndrome;
+
+ ret = set_memory_info(msg, &info);
+ if (ret < 0) {
+ error_report("failed to convert message to memory info");
+ return -1;
+ }
+
+ syndrome.raw = info.syndrome;
+
+ ret = mshv_load_regs(cpu);
+ if (ret < 0) {
+ error_report("Failed to load registers");
+ return -1;
+ }
+
+ ret = arm_emulate_mmio(cpu, syndrome, info.guest_physical_address);
+ if (ret < 0) {
+ error_report("Failed to emulate with syndrome");
+ return -1;
+ }
+
+ env->pc += (syndrome.il == 1) ? 4 : 2;
+
+ ret = mshv_store_regs(cpu);
+ if (ret < 0) {
+ error_report("Failed to store registers");
+ return -1;
+ }
+ *exit_reason = MshvVmExitIgnore;
+
+ return 0;
+}
+
int mshv_run_vcpu(int vm_fd, CPUState *cpu, hv_message *msg, MshvVmExit *exit)
{
+ int ret;
+ int cpu_fd = mshv_vcpufd(cpu);
+
+ ret = ioctl(cpu_fd, MSHV_RUN_VP, msg);
+ if (ret < 0) {
+ *exit = MshvVmExitShutdown;
+ return ret;
+ }
+
+ switch (msg->header.message_type) {
+ case HVMSG_UNRECOVERABLE_EXCEPTION:
+ *exit = MshvVmExitShutdown;
+ break;
+ case HVMSG_UNMAPPED_GPA:
+ ret = handle_unmapped_mem(vm_fd, cpu, msg, exit);
+ if (ret < 0) {
+ error_report("failed to handle mmio");
+ return -1;
+ }
+ break;
+ default:
+ error_report("Unhandled message type: 0x%x", msg->header.message_type);
+ return -1;
+ }
+
return 0;
}
--
2.45.4