#include "qemu/osdep.h"
#include "cpu.h"
#include "exec/address-spaces.h"
-#include "exec/exec-all.h"
#include "exec/ioport.h"
#include "qemu-common.h"
-#include "strings.h"
#include "sysemu/accel.h"
#include "sysemu/whpx.h"
-#include "sysemu/sysemu.h"
#include "sysemu/cpus.h"
+#include "sysemu/runstate.h"
#include "qemu/main-loop.h"
#include "hw/boards.h"
#include "qemu/error-report.h"
-#include "qemu/queue.h"
#include "qapi/error.h"
#include "migration/blocker.h"
+#include "whp-dispatch.h"
#include <WinHvPlatform.h>
#include <WinHvEmulation.h>
bool interruptable;
uint64_t tpr;
uint64_t apic_base;
- WHV_X64_PENDING_INTERRUPTION_REGISTER interrupt_in_flight;
+ bool interruption_pending;
/* Must be the last field as it may have a tail */
WHV_RUN_VP_EXIT_CONTEXT exit_ctx;
};
static bool whpx_allowed;
+static bool whp_dispatch_initialized;
+static HMODULE hWinHvPlatform, hWinHvEmulation;
struct whpx_state whpx_global;
+struct WHPDispatch whp_dispatch;
/*
struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu);
struct CPUX86State *env = (CPUArchState *)(cpu->env_ptr);
X86CPU *x86_cpu = X86_CPU(cpu);
- struct whpx_register_set vcxt = {0};
+ struct whpx_register_set vcxt;
HRESULT hr;
- int idx = 0;
+ int idx;
+ int idx_next;
int i;
int v86, r86;
assert(cpu_is_stopped(cpu) || qemu_cpu_is_self(cpu));
+ memset(&vcxt, 0, sizeof(struct whpx_register_set));
+
v86 = (env->eflags & VM_MASK);
r86 = !(env->cr[0] & CR0_PE_MASK);
vcpu->tpr = cpu_get_apic_tpr(x86_cpu->apic_state);
vcpu->apic_base = cpu_get_apic_base(x86_cpu->apic_state);
+ idx = 0;
+
/* Indexes for first 16 registers match between HV and QEMU definitions */
- for (idx = 0; idx < CPU_NB_REGS64; idx += 1) {
- vcxt.values[idx].Reg64 = env->regs[idx];
+ idx_next = 16;
+ for (idx = 0; idx < CPU_NB_REGS; idx += 1) {
+ vcxt.values[idx].Reg64 = (uint64_t)env->regs[idx];
}
+ idx = idx_next;
/* Same goes for RIP and RFLAGS */
assert(whpx_register_names[idx] == WHvX64RegisterRip);
/* 16 XMM registers */
assert(whpx_register_names[idx] == WHvX64RegisterXmm0);
- for (i = 0; i < 16; i += 1, idx += 1) {
+ idx_next = idx + 16;
+ for (i = 0; i < sizeof(env->xmm_regs) / sizeof(ZMMReg); i += 1, idx += 1) {
vcxt.values[idx].Reg128.Low64 = env->xmm_regs[i].ZMM_Q(0);
vcxt.values[idx].Reg128.High64 = env->xmm_regs[i].ZMM_Q(1);
}
+ idx = idx_next;
/* 8 FP registers */
assert(whpx_register_names[idx] == WHvX64RegisterFpMmx0);
assert(idx == RTL_NUMBER_OF(whpx_register_names));
- hr = WHvSetVirtualProcessorRegisters(whpx->partition, cpu->cpu_index,
- whpx_register_names,
- RTL_NUMBER_OF(whpx_register_names),
- &vcxt.values[0]);
+ hr = whp_dispatch.WHvSetVirtualProcessorRegisters(
+ whpx->partition, cpu->cpu_index,
+ whpx_register_names,
+ RTL_NUMBER_OF(whpx_register_names),
+ &vcxt.values[0]);
if (FAILED(hr)) {
error_report("WHPX: Failed to set virtual processor context, hr=%08lx",
struct whpx_register_set vcxt;
uint64_t tpr, apic_base;
HRESULT hr;
- int idx = 0;
+ int idx;
+ int idx_next;
int i;
assert(cpu_is_stopped(cpu) || qemu_cpu_is_self(cpu));
- hr = WHvGetVirtualProcessorRegisters(whpx->partition, cpu->cpu_index,
- whpx_register_names,
- RTL_NUMBER_OF(whpx_register_names),
- &vcxt.values[0]);
+ hr = whp_dispatch.WHvGetVirtualProcessorRegisters(
+ whpx->partition, cpu->cpu_index,
+ whpx_register_names,
+ RTL_NUMBER_OF(whpx_register_names),
+ &vcxt.values[0]);
if (FAILED(hr)) {
error_report("WHPX: Failed to get virtual processor context, hr=%08lx",
hr);
}
+ idx = 0;
+
/* Indexes for first 16 registers match between HV and QEMU definitions */
- for (idx = 0; idx < CPU_NB_REGS64; idx += 1) {
+ idx_next = 16;
+ for (idx = 0; idx < CPU_NB_REGS; idx += 1) {
env->regs[idx] = vcxt.values[idx].Reg64;
}
+ idx = idx_next;
/* Same goes for RIP and RFLAGS */
assert(whpx_register_names[idx] == WHvX64RegisterRip);
/* 16 XMM registers */
assert(whpx_register_names[idx] == WHvX64RegisterXmm0);
- for (i = 0; i < 16; i += 1, idx += 1) {
+ idx_next = idx + 16;
+ for (i = 0; i < sizeof(env->xmm_regs) / sizeof(ZMMReg); i += 1, idx += 1) {
env->xmm_regs[i].ZMM_Q(0) = vcxt.values[idx].Reg128.Low64;
env->xmm_regs[i].ZMM_Q(1) = vcxt.values[idx].Reg128.High64;
}
+ idx = idx_next;
/* 8 FP registers */
assert(whpx_register_names[idx] == WHvX64RegisterFpMmx0);
struct whpx_state *whpx = &whpx_global;
CPUState *cpu = (CPUState *)ctx;
- hr = WHvGetVirtualProcessorRegisters(whpx->partition, cpu->cpu_index,
- RegisterNames, RegisterCount,
- RegisterValues);
+ 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);
struct whpx_state *whpx = &whpx_global;
CPUState *cpu = (CPUState *)ctx;
- hr = WHvSetVirtualProcessorRegisters(whpx->partition, cpu->cpu_index,
- RegisterNames, RegisterCount,
- RegisterValues);
+ 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);
CPUState *cpu = (CPUState *)ctx;
WHV_TRANSLATE_GVA_RESULT res;
- hr = WHvTranslateGva(whpx->partition, cpu->cpu_index,
- Gva, TranslateFlags, &res, Gpa);
+ 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 {
struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu);
WHV_EMULATOR_STATUS emu_status;
- hr = WHvEmulatorTryMmioEmulation(vcpu->emulator, cpu,
- &vcpu->exit_ctx.VpContext, ctx,
- &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;
}
if (!emu_status.EmulationSuccessful) {
- error_report("WHPX: Failed to emulate MMIO access");
+ error_report("WHPX: Failed to emulate MMIO access with"
+ " EmulatorReturnStatus: %u", emu_status.AsUINT32);
return -1;
}
struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu);
WHV_EMULATOR_STATUS emu_status;
- hr = WHvEmulatorTryIoEmulation(vcpu->emulator, cpu,
- &vcpu->exit_ctx.VpContext, ctx,
- &emu_status);
+ 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;
}
if (!emu_status.EmulationSuccessful) {
- error_report("WHPX: Failed to emulate PortMMIO access");
+ error_report("WHPX: Failed to emulate PortIO access with"
+ " EmulatorReturnStatus: %u", emu_status.AsUINT32);
return -1;
}
X86CPU *x86_cpu = X86_CPU(cpu);
int irq;
uint8_t tpr;
- WHV_X64_PENDING_INTERRUPTION_REGISTER new_int = {0};
+ WHV_X64_PENDING_INTERRUPTION_REGISTER new_int;
UINT32 reg_count = 0;
- WHV_REGISTER_VALUE reg_values[3] = {0};
+ WHV_REGISTER_VALUE reg_values[3];
WHV_REGISTER_NAME reg_names[3];
+ memset(&new_int, 0, sizeof(new_int));
+ memset(reg_values, 0, sizeof(reg_values));
+
qemu_mutex_lock_iothread();
/* Inject NMI */
- if (!vcpu->interrupt_in_flight.InterruptionPending &&
+ if (!vcpu->interruption_pending &&
cpu->interrupt_request & (CPU_INTERRUPT_NMI | CPU_INTERRUPT_SMI)) {
if (cpu->interrupt_request & CPU_INTERRUPT_NMI) {
cpu->interrupt_request &= ~CPU_INTERRUPT_NMI;
}
/* Get pending hard interruption or replay one that was overwritten */
- if (!vcpu->interrupt_in_flight.InterruptionPending &&
+ if (!vcpu->interruption_pending &&
vcpu->interruptable && (env->eflags & IF_MASK)) {
assert(!new_int.InterruptionPending);
if (cpu->interrupt_request & CPU_INTERRUPT_HARD) {
qemu_mutex_unlock_iothread();
if (reg_count) {
- hr = WHvSetVirtualProcessorRegisters(whpx->partition, cpu->cpu_index,
- reg_names, reg_count, reg_values);
+ hr = whp_dispatch.WHvSetVirtualProcessorRegisters(
+ whpx->partition, cpu->cpu_index,
+ reg_names, reg_count, reg_values);
if (FAILED(hr)) {
error_report("WHPX: Failed to set interrupt state registers,"
" hr=%08lx", hr);
static void whpx_vcpu_post_run(CPUState *cpu)
{
- HRESULT hr;
- struct whpx_state *whpx = &whpx_global;
struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu);
struct CPUX86State *env = (CPUArchState *)(cpu->env_ptr);
X86CPU *x86_cpu = X86_CPU(cpu);
- WHV_REGISTER_VALUE reg_values[4];
- const WHV_REGISTER_NAME reg_names[4] = {
- WHvX64RegisterRflags,
- WHvX64RegisterCr8,
- WHvRegisterPendingInterruption,
- WHvRegisterInterruptState,
- };
-
- hr = WHvGetVirtualProcessorRegisters(whpx->partition, cpu->cpu_index,
- reg_names, 4, reg_values);
- if (FAILED(hr)) {
- error_report("WHPX: Failed to get interrupt state regusters,"
- " hr=%08lx", hr);
- vcpu->interruptable = false;
- return;
- }
- assert(reg_names[0] == WHvX64RegisterRflags);
- env->eflags = reg_values[0].Reg64;
+ env->eflags = vcpu->exit_ctx.VpContext.Rflags;
- assert(reg_names[1] == WHvX64RegisterCr8);
- if (vcpu->tpr != reg_values[1].Reg64) {
- vcpu->tpr = reg_values[1].Reg64;
+ uint64_t tpr = vcpu->exit_ctx.VpContext.Cr8;
+ if (vcpu->tpr != tpr) {
+ vcpu->tpr = tpr;
qemu_mutex_lock_iothread();
cpu_set_apic_tpr(x86_cpu->apic_state, vcpu->tpr);
qemu_mutex_unlock_iothread();
}
- assert(reg_names[2] == WHvRegisterPendingInterruption);
- vcpu->interrupt_in_flight = reg_values[2].PendingInterruption;
+ vcpu->interruption_pending =
+ vcpu->exit_ctx.VpContext.ExecutionState.InterruptionPending;
- assert(reg_names[3] == WHvRegisterInterruptState);
- vcpu->interruptable = !reg_values[3].InterruptState.InterruptShadow;
+ vcpu->interruptable =
+ !vcpu->exit_ctx.VpContext.ExecutionState.InterruptShadow;
return;
}
whpx_vcpu_kick(cpu);
}
- hr = WHvRunVirtualProcessor(whpx->partition, cpu->cpu_index,
- &vcpu->exit_ctx, sizeof(vcpu->exit_ctx));
+ hr = whp_dispatch.WHvRunVirtualProcessor(
+ whpx->partition, cpu->cpu_index,
+ &vcpu->exit_ctx, sizeof(vcpu->exit_ctx));
if (FAILED(hr)) {
error_report("WHPX: Failed to exec a virtual processor,"
case WHvRunVpExitReasonX64InterruptWindow:
vcpu->window_registered = 0;
+ ret = 0;
break;
case WHvRunVpExitReasonX64Halt:
ret = 1;
break;
+ case WHvRunVpExitReasonX64MsrAccess: {
+ WHV_REGISTER_VALUE reg_values[3] = {0};
+ WHV_REGISTER_NAME reg_names[3];
+ UINT32 reg_count;
+
+ reg_names[0] = WHvX64RegisterRip;
+ reg_names[1] = WHvX64RegisterRax;
+ reg_names[2] = WHvX64RegisterRdx;
+
+ reg_values[0].Reg64 =
+ vcpu->exit_ctx.VpContext.Rip +
+ vcpu->exit_ctx.VpContext.InstructionLength;
+
+ /*
+ * For all unsupported MSR access we:
+ * ignore writes
+ * return 0 on read.
+ */
+ reg_count = vcpu->exit_ctx.MsrAccess.AccessInfo.IsWrite ?
+ 1 : 3;
+
+ hr = whp_dispatch.WHvSetVirtualProcessorRegisters(
+ whpx->partition,
+ cpu->cpu_index,
+ reg_names, reg_count,
+ reg_values);
+
+ if (FAILED(hr)) {
+ error_report("WHPX: Failed to set MsrAccess state "
+ " registers, hr=%08lx", hr);
+ }
+ ret = 0;
+ break;
+ }
+ case WHvRunVpExitReasonX64Cpuid: {
+ WHV_REGISTER_VALUE reg_values[5];
+ WHV_REGISTER_NAME reg_names[5];
+ UINT32 reg_count = 5;
+ UINT64 rip, rax, rcx, rdx, rbx;
+
+ memset(reg_values, 0, sizeof(reg_values));
+
+ rip = vcpu->exit_ctx.VpContext.Rip +
+ vcpu->exit_ctx.VpContext.InstructionLength;
+ switch (vcpu->exit_ctx.CpuidAccess.Rax) {
+ case 1:
+ rax = vcpu->exit_ctx.CpuidAccess.DefaultResultRax;
+ /* Advertise that we are running on a hypervisor */
+ rcx =
+ vcpu->exit_ctx.CpuidAccess.DefaultResultRcx |
+ CPUID_EXT_HYPERVISOR;
+
+ rdx = vcpu->exit_ctx.CpuidAccess.DefaultResultRdx;
+ rbx = vcpu->exit_ctx.CpuidAccess.DefaultResultRbx;
+ break;
+ case 0x80000001:
+ rax = vcpu->exit_ctx.CpuidAccess.DefaultResultRax;
+ /* Remove any support of OSVW */
+ rcx =
+ vcpu->exit_ctx.CpuidAccess.DefaultResultRcx &
+ ~CPUID_EXT3_OSVW;
+
+ rdx = vcpu->exit_ctx.CpuidAccess.DefaultResultRdx;
+ rbx = vcpu->exit_ctx.CpuidAccess.DefaultResultRbx;
+ break;
+ default:
+ rax = vcpu->exit_ctx.CpuidAccess.DefaultResultRax;
+ rcx = vcpu->exit_ctx.CpuidAccess.DefaultResultRcx;
+ rdx = vcpu->exit_ctx.CpuidAccess.DefaultResultRdx;
+ rbx = vcpu->exit_ctx.CpuidAccess.DefaultResultRbx;
+ }
+
+ reg_names[0] = WHvX64RegisterRip;
+ reg_names[1] = WHvX64RegisterRax;
+ reg_names[2] = WHvX64RegisterRcx;
+ reg_names[3] = WHvX64RegisterRdx;
+ reg_names[4] = WHvX64RegisterRbx;
+
+ reg_values[0].Reg64 = rip;
+ reg_values[1].Reg64 = rax;
+ reg_values[2].Reg64 = rcx;
+ reg_values[3].Reg64 = rdx;
+ reg_values[4].Reg64 = rbx;
+
+ hr = whp_dispatch.WHvSetVirtualProcessorRegisters(
+ whpx->partition, cpu->cpu_index,
+ reg_names,
+ reg_count,
+ reg_values);
+
+ if (FAILED(hr)) {
+ error_report("WHPX: Failed to set CpuidAccess state registers,"
+ " hr=%08lx", hr);
+ }
+ ret = 0;
+ break;
+ }
case WHvRunVpExitReasonNone:
case WHvRunVpExitReasonUnrecoverableException:
case WHvRunVpExitReasonInvalidVpRegisterValue:
case WHvRunVpExitReasonUnsupportedFeature:
- case WHvRunVpExitReasonX64MsrAccess:
- case WHvRunVpExitReasonX64Cpuid:
case WHvRunVpExitReasonException:
default:
error_report("WHPX: Unexpected VP exit code %d",
(void)migrate_add_blocker(whpx_migration_blocker, &local_error);
if (local_error) {
error_report_err(local_error);
- error_free(whpx_migration_blocker);
migrate_del_blocker(whpx_migration_blocker);
+ error_free(whpx_migration_blocker);
return -EINVAL;
}
}
return -ENOMEM;
}
- hr = WHvEmulatorCreateEmulator(&whpx_emu_callbacks, &vcpu->emulator);
+ hr = whp_dispatch.WHvEmulatorCreateEmulator(
+ &whpx_emu_callbacks,
+ &vcpu->emulator);
if (FAILED(hr)) {
error_report("WHPX: Failed to setup instruction completion support,"
" hr=%08lx", hr);
return -EINVAL;
}
- hr = WHvCreateVirtualProcessor(whpx->partition, cpu->cpu_index, 0);
+ 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);
- WHvEmulatorDestroyEmulator(vcpu->emulator);
+ whp_dispatch.WHvEmulatorDestroyEmulator(vcpu->emulator);
g_free(vcpu);
return -EINVAL;
}
struct whpx_state *whpx = &whpx_global;
struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu);
- WHvDeleteVirtualProcessor(whpx->partition, cpu->cpu_index);
- WHvEmulatorDestroyEmulator(vcpu->emulator);
+ whp_dispatch.WHvDeleteVirtualProcessor(whpx->partition, cpu->cpu_index);
+ whp_dispatch.WHvEmulatorDestroyEmulator(vcpu->emulator);
g_free(cpu->hax_vcpu);
return;
}
void whpx_vcpu_kick(CPUState *cpu)
{
struct whpx_state *whpx = &whpx_global;
- WHvCancelRunVirtualProcessor(whpx->partition, cpu->cpu_index, 0);
+ whp_dispatch.WHvCancelRunVirtualProcessor(
+ whpx->partition, cpu->cpu_index, 0);
}
/*
*/
if (add) {
- hr = WHvMapGpaRange(whpx->partition,
- host_va,
- start_pa,
- size,
- (WHvMapGpaRangeFlagRead |
- WHvMapGpaRangeFlagExecute |
- (rom ? 0 : WHvMapGpaRangeFlagWrite)));
+ hr = whp_dispatch.WHvMapGpaRange(whpx->partition,
+ host_va,
+ start_pa,
+ size,
+ (WHvMapGpaRangeFlagRead |
+ WHvMapGpaRangeFlagExecute |
+ (rom ? 0 : WHvMapGpaRangeFlagWrite)));
} else {
- hr = WHvUnmapGpaRange(whpx->partition,
- start_pa,
- size);
+ hr = whp_dispatch.WHvUnmapGpaRange(whpx->partition,
+ start_pa,
+ size);
}
if (FAILED(hr)) {
error_report("WHPX: Failed to %s GPA range '%s' PA:%p, Size:%p bytes,"
" Host:%p, hr=%08lx",
(add ? "MAP" : "UNMAP"), name,
- (void *)start_pa, (void *)size, host_va, hr);
+ (void *)(uintptr_t)start_pa, (void *)size, host_va, hr);
}
}
host_va = (uintptr_t)memory_region_get_ram_ptr(mr)
+ section->offset_within_region + delta;
- whpx_update_mapping(start_pa, size, (void *)host_va, add,
- memory_region_is_rom(mr), mr->name);
+ whpx_update_mapping(start_pa, size, (void *)(uintptr_t)host_va, add,
+ memory_region_is_rom(mr), mr->name);
}
static void whpx_region_add(MemoryListener *listener,
int ret;
HRESULT hr;
WHV_CAPABILITY whpx_cap;
+ UINT32 whpx_cap_size;
WHV_PARTITION_PROPERTY prop;
whpx = &whpx_global;
+ if (!init_whp_dispatch()) {
+ ret = -ENOSYS;
+ goto error;
+ }
+
memset(whpx, 0, sizeof(struct whpx_state));
whpx->mem_quota = ms->ram_size;
- hr = WHvGetCapability(WHvCapabilityCodeHypervisorPresent, &whpx_cap,
- sizeof(whpx_cap));
+ hr = whp_dispatch.WHvGetCapability(
+ WHvCapabilityCodeHypervisorPresent, &whpx_cap,
+ sizeof(whpx_cap), &whpx_cap_size);
if (FAILED(hr) || !whpx_cap.HypervisorPresent) {
error_report("WHPX: No accelerator found, hr=%08lx", hr);
ret = -ENOSPC;
goto error;
}
- hr = WHvCreatePartition(&whpx->partition);
+ hr = whp_dispatch.WHvCreatePartition(&whpx->partition);
if (FAILED(hr)) {
error_report("WHPX: Failed to create partition, hr=%08lx", hr);
ret = -EINVAL;
}
memset(&prop, 0, sizeof(WHV_PARTITION_PROPERTY));
- prop.PropertyCode = WHvPartitionPropertyCodeProcessorCount;
- prop.ProcessorCount = smp_cpus;
- hr = WHvSetPartitionProperty(whpx->partition,
- &prop,
- sizeof(WHV_PARTITION_PROPERTY));
+ prop.ProcessorCount = ms->smp.cpus;
+ hr = whp_dispatch.WHvSetPartitionProperty(
+ whpx->partition,
+ WHvPartitionPropertyCodeProcessorCount,
+ &prop,
+ sizeof(WHV_PARTITION_PROPERTY));
if (FAILED(hr)) {
error_report("WHPX: Failed to set partition core count to %d,"
- " hr=%08lx", smp_cores, hr);
+ " hr=%08lx", ms->smp.cores, hr);
ret = -EINVAL;
goto error;
}
- hr = WHvSetupPartition(whpx->partition);
+ memset(&prop, 0, sizeof(WHV_PARTITION_PROPERTY));
+ prop.ExtendedVmExits.X64MsrExit = 1;
+ prop.ExtendedVmExits.X64CpuidExit = 1;
+ hr = whp_dispatch.WHvSetPartitionProperty(
+ whpx->partition,
+ WHvPartitionPropertyCodeExtendedVmExits,
+ &prop,
+ sizeof(WHV_PARTITION_PROPERTY));
+
+ if (FAILED(hr)) {
+ error_report("WHPX: Failed to enable partition extended X64MsrExit and"
+ " X64CpuidExit hr=%08lx", hr);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ UINT32 cpuidExitList[] = {1, 0x80000001};
+ hr = whp_dispatch.WHvSetPartitionProperty(
+ whpx->partition,
+ WHvPartitionPropertyCodeCpuidExitList,
+ cpuidExitList,
+ RTL_NUMBER_OF(cpuidExitList) * sizeof(UINT32));
+
+ if (FAILED(hr)) {
+ error_report("WHPX: Failed to set partition CpuidExitList hr=%08lx",
+ hr);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ hr = whp_dispatch.WHvSetupPartition(whpx->partition);
if (FAILED(hr)) {
error_report("WHPX: Failed to setup partition, hr=%08lx", hr);
ret = -EINVAL;
error:
if (NULL != whpx->partition) {
- WHvDeletePartition(whpx->partition);
+ whp_dispatch.WHvDeletePartition(whpx->partition);
whpx->partition = NULL;
}
type_register_static(&whpx_accel_type);
}
+bool init_whp_dispatch(void)
+{
+ const char *lib_name;
+ HMODULE hLib;
+
+ if (whp_dispatch_initialized) {
+ return true;
+ }
+
+ #define WHP_LOAD_FIELD(return_type, function_name, signature) \
+ whp_dispatch.function_name = \
+ (function_name ## _t)GetProcAddress(hLib, #function_name); \
+ if (!whp_dispatch.function_name) { \
+ error_report("Could not load function %s from library %s.", \
+ #function_name, lib_name); \
+ goto error; \
+ } \
+
+ lib_name = "WinHvPlatform.dll";
+ hWinHvPlatform = LoadLibrary(lib_name);
+ if (!hWinHvPlatform) {
+ error_report("Could not load library %s.", lib_name);
+ goto error;
+ }
+ hLib = hWinHvPlatform;
+ LIST_WINHVPLATFORM_FUNCTIONS(WHP_LOAD_FIELD)
+
+ lib_name = "WinHvEmulation.dll";
+ hWinHvEmulation = LoadLibrary(lib_name);
+ if (!hWinHvEmulation) {
+ error_report("Could not load library %s.", lib_name);
+ goto error;
+ }
+ hLib = hWinHvEmulation;
+ LIST_WINHVEMULATION_FUNCTIONS(WHP_LOAD_FIELD)
+
+ whp_dispatch_initialized = true;
+ return true;
+
+ error:
+
+ if (hWinHvPlatform) {
+ FreeLibrary(hWinHvPlatform);
+ }
+ if (hWinHvEmulation) {
+ FreeLibrary(hWinHvEmulation);
+ }
+ return false;
+}
+
type_init(whpx_type_init);