On 01/09/20 01:32, Sunil Muthuswamy wrote: > Can I please get some eyes on this?
Yes, sorry about the bad timing (5.1 freeze + Meson conversion + parental leave). Paolo >> -----Original Message----- >> From: Sunil Muthuswamy >> Sent: Thursday, July 30, 2020 3:11 PM >> To: Paolo Bonzini <pbonz...@redhat.com>; Richard Henderson >> <r...@twiddle.net>; Eduardo Habkost <ehabk...@redhat.com> >> Cc: qemu-devel@nongnu.org; Stefan Weil <s...@weilnetz.de> >> Subject: [PATCH] WHPX: vmware cpuid leaf for tsc and apic frequency >> >> Newer versions of WHPX provide the capability to query the tsc >> and apic frequency. Expose these through the vmware cpuid leaf. >> This patch doesnt support setting the tsc frequency; that will >> come as a separate fix. >> >> Signed-off-by: Sunil Muthuswamy <sunil...@microsoft.com> >> --- >> target/i386/whp-dispatch.h | 3 +- >> target/i386/whpx-all.c | 94 ++++++++++++++++++++++++++++++++++---- >> 2 files changed, 86 insertions(+), 11 deletions(-) >> >> diff --git a/target/i386/whp-dispatch.h b/target/i386/whp-dispatch.h >> index e4695c349f..b18aba20ed 100644 >> --- a/target/i386/whp-dispatch.h >> +++ b/target/i386/whp-dispatch.h >> @@ -2,10 +2,11 @@ >> #define WHP_DISPATCH_H >> >> #include <windows.h> >> - >> #include <WinHvPlatform.h> >> #include <WinHvEmulation.h> >> >> +#define WHV_E_UNKNOWN_CAPABILITY 0x80370300L >> + >> #define LIST_WINHVPLATFORM_FUNCTIONS(X) \ >> X(HRESULT, WHvGetCapability, (WHV_CAPABILITY_CODE CapabilityCode, VOID* >> CapabilityBuffer, UINT32 >> CapabilityBufferSizeInBytes, UINT32* WrittenSizeInBytes)) \ >> X(HRESULT, WHvCreatePartition, (WHV_PARTITION_HANDLE* Partition)) \ >> diff --git a/target/i386/whpx-all.c b/target/i386/whpx-all.c >> index c78baac6df..da4c135925 100644 >> --- a/target/i386/whpx-all.c >> +++ b/target/i386/whpx-all.c >> @@ -27,6 +27,8 @@ >> #include <WinHvPlatform.h> >> #include <WinHvEmulation.h> >> >> +#define HYPERV_APIC_BUS_FREQUENCY (200000000ULL) >> + >> struct whpx_state { >> uint64_t mem_quota; >> WHV_PARTITION_HANDLE partition; >> @@ -1061,6 +1063,18 @@ static int whpx_vcpu_run(CPUState *cpu) >> cpu_x86_cpuid(env, cpuid_fn, 0, (UINT32 *)&rax, (UINT32 *)&rbx, >> (UINT32 *)&rcx, (UINT32 *)&rdx); >> switch (cpuid_fn) { >> + case 0x40000000: >> + /* Expose the vmware cpu frequency cpuid leaf */ >> + rax = 0x40000010; >> + rbx = rcx = rdx = 0; >> + break; >> + >> + case 0x40000010: >> + rax = env->tsc_khz; >> + rbx = env->apic_bus_freq / 1000; /* Hz to KHz */ >> + rcx = rdx = 0; >> + break; >> + >> case 0x80000001: >> /* Remove any support of OSVW */ >> rcx &= ~CPUID_EXT3_OSVW; >> @@ -1193,6 +1207,10 @@ int whpx_init_vcpu(CPUState *cpu) >> struct whpx_state *whpx = &whpx_global; >> struct whpx_vcpu *vcpu; >> Error *local_error = NULL; >> + struct CPUX86State *env = (CPUArchState *)(cpu->env_ptr); >> + X86CPU *x86_cpu = X86_CPU(cpu); >> + UINT64 freq = 0; >> + int ret; >> >> /* Add migration blockers for all unsupported features of the >> * Windows Hypervisor Platform >> @@ -1207,7 +1225,8 @@ int whpx_init_vcpu(CPUState *cpu) >> error_report_err(local_error); >> migrate_del_blocker(whpx_migration_blocker); >> error_free(whpx_migration_blocker); >> - return -EINVAL; >> + ret = -EINVAL; >> + goto error; >> } >> } >> >> @@ -1215,7 +1234,8 @@ int whpx_init_vcpu(CPUState *cpu) >> >> if (!vcpu) { >> error_report("WHPX: Failed to allocte VCPU context."); >> - return -ENOMEM; >> + ret = -ENOMEM; >> + goto error; >> } >> >> hr = whp_dispatch.WHvEmulatorCreateEmulator( >> @@ -1224,8 +1244,8 @@ int whpx_init_vcpu(CPUState *cpu) >> if (FAILED(hr)) { >> error_report("WHPX: Failed to setup instruction completion support," >> " hr=%08lx", hr); >> - g_free(vcpu); >> - return -EINVAL; >> + ret = -EINVAL; >> + goto error; >> } >> >> hr = whp_dispatch.WHvCreateVirtualProcessor( >> @@ -1234,17 +1254,72 @@ int whpx_init_vcpu(CPUState *cpu) >> error_report("WHPX: Failed to create a virtual processor," >> " hr=%08lx", hr); >> whp_dispatch.WHvEmulatorDestroyEmulator(vcpu->emulator); >> - g_free(vcpu); >> - return -EINVAL; >> + ret = -EINVAL; >> + goto error; >> } >> >> - vcpu->interruptable = true; >> + /* >> + * vcpu's TSC frequency is either specified by user, or use the value >> + * provided by Hyper-V if the former is not present. In the latter >> case, we >> + * query it from Hyper-V and record in env->tsc_khz, so that vcpu's TSC >> + * frequency can be migrated later via this field. >> + */ >> + if (!env->tsc_khz) { >> + hr = whp_dispatch.WHvGetCapability( >> + WHvCapabilityCodeProcessorClockFrequency, &freq, sizeof(freq), >> + NULL); >> + if (hr != WHV_E_UNKNOWN_CAPABILITY) { >> + if (FAILED(hr)) { >> + printf("WHPX: Failed to query tsc frequency, hr=0x%08lx\n", >> hr); >> + } else { >> + env->tsc_khz = freq / 1000; /* Hz to KHz */ >> + } >> + } >> + } >> >> + env->apic_bus_freq = HYPERV_APIC_BUS_FREQUENCY; >> + hr = whp_dispatch.WHvGetCapability( >> + WHvCapabilityCodeInterruptClockFrequency, &freq, sizeof(freq), >> NULL); >> + if (hr != WHV_E_UNKNOWN_CAPABILITY) { >> + if (FAILED(hr)) { >> + printf("WHPX: Failed to query apic bus frequency hr=0x%08lx\n", >> hr); >> + } else { >> + env->apic_bus_freq = freq; >> + } >> + } >> + >> + /* >> + * If the vmware cpuid frequency leaf option is set, and we have a valid >> + * tsc value, trap the corresponding cpuid's. >> + */ >> + if (x86_cpu->vmware_cpuid_freq && env->tsc_khz) { >> + UINT32 cpuidExitList[] = {1, 0x80000001, 0x40000000, 0x40000010}; >> + >> + 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; >> + } >> + } >> + >> + vcpu->interruptable = true; >> cpu->vcpu_dirty = true; >> cpu->hax_vcpu = (struct hax_vcpu_state *)vcpu; >> qemu_add_vm_change_state_handler(whpx_cpu_update_state, cpu->env_ptr); >> >> return 0; >> + >> +error: >> + g_free(vcpu); >> + >> + return ret; >> } >> >> int whpx_vcpu_exec(CPUState *cpu) >> @@ -1493,6 +1568,7 @@ static int whpx_accel_init(MachineState *ms) >> WHV_CAPABILITY whpx_cap; >> UINT32 whpx_cap_size; >> WHV_PARTITION_PROPERTY prop; >> + UINT32 cpuidExitList[] = {1, 0x80000001}; >> >> whpx = &whpx_global; >> >> @@ -1551,7 +1627,6 @@ static int whpx_accel_init(MachineState *ms) >> goto error; >> } >> >> - UINT32 cpuidExitList[] = {1, 0x80000001}; >> hr = whp_dispatch.WHvSetPartitionProperty( >> whpx->partition, >> WHvPartitionPropertyCodeCpuidExitList, >> @@ -1579,14 +1654,13 @@ static int whpx_accel_init(MachineState *ms) >> printf("Windows Hypervisor Platform accelerator is operational\n"); >> return 0; >> >> - error: >> +error: >> >> if (NULL != whpx->partition) { >> whp_dispatch.WHvDeletePartition(whpx->partition); >> whpx->partition = NULL; >> } >> >> - >> return ret; >> } >> >> -- >> 2.25.1 >