Using the mshv backend as a base, move away from winhvemulation to using common QEMU code used by the HVF and mshv backends.
Signed-off-by: Mohamed Mediouni <[email protected]> --- target/i386/whpx/whpx-all.c | 250 ++++++++++++++++-------------------- 1 file changed, 114 insertions(+), 136 deletions(-) diff --git a/target/i386/whpx/whpx-all.c b/target/i386/whpx/whpx-all.c index cdcaebbe16..eb6076d2f4 100644 --- a/target/i386/whpx/whpx-all.c +++ b/target/i386/whpx/whpx-all.c @@ -15,6 +15,7 @@ #include "gdbstub/helpers.h" #include "qemu/accel.h" #include "accel/accel-ops.h" +#include "system/memory.h" #include "system/whpx.h" #include "system/cpus.h" #include "system/runstate.h" @@ -36,8 +37,12 @@ #include "system/whpx-all.h" #include "system/whpx-common.h" +#include "emulate/x86_decode.h" +#include "emulate/x86_emu.h" +#include "emulate/x86_flags.h" +#include "emulate/x86_mmu.h" + #include <winhvplatform.h> -#include <winhvemulation.h> #define HYPERV_APIC_BUS_FREQUENCY (200000000ULL) @@ -756,158 +761,138 @@ void whpx_get_registers(CPUState *cpu) x86_update_hflags(env); } -static HRESULT CALLBACK whpx_emu_ioport_callback( - void *ctx, - WHV_EMULATOR_IO_ACCESS_INFO *IoAccess) +static int emulate_instruction(CPUState *cpu, const uint8_t *insn_bytes, size_t insn_len) { - MemTxAttrs attrs = { 0 }; - address_space_rw(&address_space_io, IoAccess->Port, attrs, - &IoAccess->Data, IoAccess->AccessSize, - IoAccess->Direction); - return S_OK; -} + X86CPU *x86_cpu = X86_CPU(cpu); + CPUX86State *env = &x86_cpu->env; + struct x86_decode decode = { 0 }; + x86_insn_stream stream = { .bytes = insn_bytes, .len = insn_len }; -static HRESULT CALLBACK whpx_emu_mmio_callback( - void *ctx, - WHV_EMULATOR_MEMORY_ACCESS_INFO *ma) -{ - CPUState *cs = (CPUState *)ctx; - AddressSpace *as = cpu_addressspace(cs, MEMTXATTRS_UNSPECIFIED); + whpx_get_registers(cpu); + decode_instruction_stream(env, &decode, &stream); + exec_instruction(env, &decode); + whpx_set_registers(cpu, WHPX_SET_RUNTIME_STATE); - address_space_rw(as, ma->GpaAddress, MEMTXATTRS_UNSPECIFIED, - ma->Data, ma->AccessSize, ma->Direction); - return S_OK; + return 0; } -static HRESULT CALLBACK whpx_emu_getreg_callback( - void *ctx, - const WHV_REGISTER_NAME *RegisterNames, - UINT32 RegisterCount, - WHV_REGISTER_VALUE *RegisterValues) +static int whpx_handle_mmio(CPUState *cpu, WHV_RUN_VP_EXIT_CONTEXT *exit_ctx) { - HRESULT hr; - struct whpx_state *whpx = &whpx_global; - CPUState *cpu = (CPUState *)ctx; + WHV_MEMORY_ACCESS_CONTEXT *ctx = &exit_ctx->MemoryAccess; + int ret; - hr = whp_dispatch.WHvGetVirtualProcessorRegisters( - whpx->partition, cpu->cpu_index, - RegisterNames, RegisterCount, - RegisterValues); - if (FAILED(hr)) { - error_report("WHPX: Failed to get virtual processor registers," - " hr=%08lx", hr); + ret = emulate_instruction(cpu, ctx->InstructionBytes, ctx->InstructionByteCount); + if (ret < 0) { + error_report("failed to emulate mmio"); + return -1; } - return hr; + return 0; } -static HRESULT CALLBACK whpx_emu_setreg_callback( - void *ctx, - const WHV_REGISTER_NAME *RegisterNames, - UINT32 RegisterCount, - const WHV_REGISTER_VALUE *RegisterValues) +static void handle_io(CPUState *env, uint16_t port, void *buffer, + int direction, int size, int count) { - HRESULT hr; - struct whpx_state *whpx = &whpx_global; - CPUState *cpu = (CPUState *)ctx; + int i; + uint8_t *ptr = buffer; - hr = whp_dispatch.WHvSetVirtualProcessorRegisters( - whpx->partition, cpu->cpu_index, - RegisterNames, RegisterCount, - RegisterValues); - if (FAILED(hr)) { - error_report("WHPX: Failed to set virtual processor registers," - " hr=%08lx", hr); + for (i = 0; i < count; i++) { + address_space_rw(&address_space_io, port, MEMTXATTRS_UNSPECIFIED, + ptr, size, + direction); + ptr += size; } - - /* - * The emulator just successfully wrote the register state. We clear the - * dirty state so we avoid the double write on resume of the VP. - */ - cpu->vcpu_dirty = false; - - return hr; } -static HRESULT CALLBACK whpx_emu_translate_callback( - void *ctx, - WHV_GUEST_VIRTUAL_ADDRESS Gva, - WHV_TRANSLATE_GVA_FLAGS TranslateFlags, - WHV_TRANSLATE_GVA_RESULT_CODE *TranslationResult, - WHV_GUEST_PHYSICAL_ADDRESS *Gpa) +static void whpx_bump_rip(CPUState *cpu, WHV_RUN_VP_EXIT_CONTEXT *exit_ctx) { - HRESULT hr; - struct whpx_state *whpx = &whpx_global; - CPUState *cpu = (CPUState *)ctx; - WHV_TRANSLATE_GVA_RESULT res; - - hr = whp_dispatch.WHvTranslateGva(whpx->partition, cpu->cpu_index, - Gva, TranslateFlags, &res, Gpa); - if (FAILED(hr)) { - error_report("WHPX: Failed to translate GVA, hr=%08lx", hr); - } else { - *TranslationResult = res.ResultCode; - } - - return hr; + WHV_REGISTER_VALUE reg; + whpx_get_reg(cpu, WHvX64RegisterRip, ®); + reg.Reg64 = exit_ctx->VpContext.Rip + exit_ctx->VpContext.InstructionLength; + whpx_set_reg(cpu, WHvX64RegisterRip, reg); } -static const WHV_EMULATOR_CALLBACKS whpx_emu_callbacks = { - .Size = sizeof(WHV_EMULATOR_CALLBACKS), - .WHvEmulatorIoPortCallback = whpx_emu_ioport_callback, - .WHvEmulatorMemoryCallback = whpx_emu_mmio_callback, - .WHvEmulatorGetVirtualProcessorRegisters = whpx_emu_getreg_callback, - .WHvEmulatorSetVirtualProcessorRegisters = whpx_emu_setreg_callback, - .WHvEmulatorTranslateGvaPage = whpx_emu_translate_callback, -}; - -static int whpx_handle_mmio(CPUState *cpu, WHV_MEMORY_ACCESS_CONTEXT *ctx) +static int whpx_handle_portio(CPUState *cpu, + WHV_RUN_VP_EXIT_CONTEXT *exit_ctx) { - HRESULT hr; - AccelCPUState *vcpu = cpu->accel; - WHV_EMULATOR_STATUS emu_status; - - hr = whp_dispatch.WHvEmulatorTryMmioEmulation( - vcpu->emulator, cpu, - &vcpu->exit_ctx.VpContext, ctx, - &emu_status); - if (FAILED(hr)) { - error_report("WHPX: Failed to parse MMIO access, hr=%08lx", hr); - return -1; - } + WHV_X64_IO_PORT_ACCESS_CONTEXT *ctx = &exit_ctx->IoPortAccess; + X86CPU *x86_cpu = X86_CPU(cpu); + CPUX86State *env = &x86_cpu->env; + int ret; - if (!emu_status.EmulationSuccessful) { - error_report("WHPX: Failed to emulate MMIO access with" - " EmulatorReturnStatus: %u", emu_status.AsUINT32); + if (!ctx->AccessInfo.StringOp && !ctx->AccessInfo.IsWrite) { + uint64_t val = 0; + WHV_REGISTER_VALUE reg; + + whpx_get_reg(cpu, WHvX64RegisterRax, ®); + handle_io(cpu, ctx->PortNumber, &val, 0, ctx->AccessInfo.AccessSize, 1); + if (ctx->AccessInfo.AccessSize == 1) { + reg.Reg8 = val; + } else if (ctx->AccessInfo.AccessSize == 2) { + reg.Reg16 = val; + } else if (ctx->AccessInfo.AccessSize == 4) { + reg.Reg64 = (uint32_t)val; + } else { + reg.Reg64 = (uint64_t)val; + } + whpx_bump_rip(cpu, exit_ctx); + whpx_set_reg(cpu, WHvX64RegisterRax, reg); + return 0; + } else if (!ctx->AccessInfo.StringOp && ctx->AccessInfo.IsWrite) { + RAX(env) = ctx->Rax; + handle_io(cpu, ctx->PortNumber, &RAX(env), 1, ctx->AccessInfo.AccessSize, 1); + whpx_bump_rip(cpu, exit_ctx); + return 0; + } + + ret = emulate_instruction(cpu, ctx->InstructionBytes, exit_ctx->VpContext.InstructionLength); + if (ret < 0) { + error_report("failed to emulate I/O port access"); return -1; } return 0; } -static int whpx_handle_portio(CPUState *cpu, - WHV_X64_IO_PORT_ACCESS_CONTEXT *ctx) +static void write_mem(CPUState *cpu, void *data, target_ulong addr, int bytes) { - HRESULT hr; - AccelCPUState *vcpu = cpu->accel; - WHV_EMULATOR_STATUS emu_status; + vmx_write_mem(cpu, addr, data, bytes); +} - hr = whp_dispatch.WHvEmulatorTryIoEmulation( - vcpu->emulator, cpu, - &vcpu->exit_ctx.VpContext, ctx, - &emu_status); - if (FAILED(hr)) { - error_report("WHPX: Failed to parse PortIO access, hr=%08lx", hr); - return -1; - } +static void read_mem(CPUState *cpu, void *data, target_ulong addr, int bytes) +{ + vmx_read_mem(cpu, data, addr, bytes); +} - if (!emu_status.EmulationSuccessful) { - error_report("WHPX: Failed to emulate PortIO access with" - " EmulatorReturnStatus: %u", emu_status.AsUINT32); - return -1; +static void read_segment_descriptor(CPUState *cpu, + struct x86_segment_descriptor *desc, + enum X86Seg seg_idx) +{ + bool ret; + X86CPU *x86_cpu = X86_CPU(cpu); + CPUX86State *env = &x86_cpu->env; + SegmentCache *seg = &env->segs[seg_idx]; + x86_segment_selector sel = { .sel = seg->selector & 0xFFFF }; + + ret = x86_read_segment_descriptor(cpu, desc, sel); + if (ret == false) { + error_report("failed to read segment descriptor"); + abort(); } +} - return 0; + +static const struct x86_emul_ops whpx_x86_emul_ops = { + .read_mem = read_mem, + .write_mem = write_mem, + .read_segment_descriptor = read_segment_descriptor, + .handle_io = handle_io +}; + +static void whpx_init_emu(void) +{ + init_decoder(); + init_emu(&whpx_x86_emul_ops); } /* @@ -1279,8 +1264,9 @@ bool whpx_arch_supports_guest_debug(void) void whpx_arch_destroy_vcpu(CPUState *cpu) { - AccelCPUState *vcpu = cpu->accel; - whp_dispatch.WHvEmulatorDestroyEmulator(vcpu->emulator); + X86CPU *x86cpu = X86_CPU(cpu); + CPUX86State *env = &x86cpu->env; + g_free(env->emu_mmio_buf); } /* Returns the address of the next instruction that is about to be executed. */ @@ -1639,11 +1625,11 @@ int whpx_vcpu_run(CPUState *cpu) switch (vcpu->exit_ctx.ExitReason) { case WHvRunVpExitReasonMemoryAccess: - ret = whpx_handle_mmio(cpu, &vcpu->exit_ctx.MemoryAccess); + ret = whpx_handle_mmio(cpu, &vcpu->exit_ctx); break; case WHvRunVpExitReasonX64IoPortAccess: - ret = whpx_handle_portio(cpu, &vcpu->exit_ctx.IoPortAccess); + ret = whpx_handle_portio(cpu, &vcpu->exit_ctx); break; case WHvRunVpExitReasonX64InterruptWindow: @@ -1990,22 +1976,11 @@ int whpx_init_vcpu(CPUState *cpu) vcpu = g_new0(AccelCPUState, 1); - hr = whp_dispatch.WHvEmulatorCreateEmulator( - &whpx_emu_callbacks, - &vcpu->emulator); - if (FAILED(hr)) { - error_report("WHPX: Failed to setup instruction completion support," - " hr=%08lx", hr); - ret = -EINVAL; - goto error; - } - hr = whp_dispatch.WHvCreateVirtualProcessor( whpx->partition, cpu->cpu_index, 0); if (FAILED(hr)) { error_report("WHPX: Failed to create a virtual processor," " hr=%08lx", hr); - whp_dispatch.WHvEmulatorDestroyEmulator(vcpu->emulator); ret = -EINVAL; goto error; } @@ -2067,6 +2042,8 @@ int whpx_init_vcpu(CPUState *cpu) max_vcpu_index = max(max_vcpu_index, cpu->cpu_index); qemu_add_vm_change_state_handler(whpx_cpu_update_state, env); + env->emu_mmio_buf = g_new(char, 4096); + return 0; error: @@ -2256,6 +2233,7 @@ int whpx_accel_init(AccelState *as, MachineState *ms) } whpx_memory_init(); + whpx_init_emu(); printf("Windows Hypervisor Platform accelerator is operational\n"); return 0; -- 2.50.1 (Apple Git-155)
