Was removed in 2c08624 but it's still useful for
Windows 10 so reintroduce it there.
And this time, actually make it work by reporting
the hypervisor bit in CPUID.
Also pretend to be KVM, with the only capability
reported being X2APIC support.
Although looks like Linux doesn't use that vmware leaf...
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
---
accel/whpx/whpx-common.c | 2 +
include/system/whpx-internal.h | 1 +
target/arm/whpx/whpx-all.c | 1 +
target/i386/whpx/whpx-all.c | 68 ++++++++++++++++++++++++++++++----
4 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/accel/whpx/whpx-common.c b/accel/whpx/whpx-common.c
index b813a5d9d2..59be996aef 100644
--- a/accel/whpx/whpx-common.c
+++ b/accel/whpx/whpx-common.c
@@ -550,6 +550,8 @@ static void whpx_accel_instance_init(Object *obj)
whpx->hyperv_enlightenments_allowed = true;
whpx->hyperv_enlightenments_required = false;
+ /* Value determined at whpx_accel_init */
+ whpx->hyperv_enlightenments_enabled = false;
}
static const TypeInfo whpx_accel_type = {
diff --git a/include/system/whpx-internal.h b/include/system/whpx-internal.h
index 480d05fdca..576587ec3b 100644
--- a/include/system/whpx-internal.h
+++ b/include/system/whpx-internal.h
@@ -45,6 +45,7 @@ struct whpx_state {
bool hyperv_enlightenments_allowed;
bool hyperv_enlightenments_required;
+ bool hyperv_enlightenments_enabled;
};
diff --git a/target/arm/whpx/whpx-all.c b/target/arm/whpx/whpx-all.c
index bbf0f6be96..4019a513aa 100644
--- a/target/arm/whpx/whpx-all.c
+++ b/target/arm/whpx/whpx-all.c
@@ -968,6 +968,7 @@ int whpx_accel_init(AccelState *as, MachineState *ms)
* as they're not needed for performance.
*/
if (whpx->hyperv_enlightenments_required) {
+ whpx->hyperv_enlightenments_enabled = true;
hr = whp_dispatch.WHvSetPartitionProperty(
whpx->partition,
WHvPartitionPropertyCodeSyntheticProcessorFeaturesBanks,
diff --git a/target/i386/whpx/whpx-all.c b/target/i386/whpx/whpx-all.c
index b8f53ca532..b62377cb41 100644
--- a/target/i386/whpx/whpx-all.c
+++ b/target/i386/whpx/whpx-all.c
@@ -2077,14 +2077,47 @@ int whpx_vcpu_run(CPUState *cpu)
vcpu->exit_ctx.VpContext.Rip +
vcpu->exit_ctx.VpContext.InstructionLength;
- reg_values[1].Reg64 = vcpu->exit_ctx.CpuidAccess.DefaultResultRax;
- reg_values[2].Reg64 = vcpu->exit_ctx.CpuidAccess.DefaultResultRcx;
- reg_values[3].Reg64 = vcpu->exit_ctx.CpuidAccess.DefaultResultRdx;
- reg_values[4].Reg64 = vcpu->exit_ctx.CpuidAccess.DefaultResultRbx;
-
- if (vcpu->exit_ctx.CpuidAccess.Rax == 1) {
- if (cpu_has_x2apic_feature(env)) {
- reg_values[2].Reg64 |= CPUID_EXT_X2APIC;
+ if (whpx_is_legacy_os()) {
+ reg_values[1].Reg64 = vcpu->exit_ctx.CpuidAccess.DefaultResultRax;
+ reg_values[2].Reg64 = vcpu->exit_ctx.CpuidAccess.DefaultResultRcx;
+ reg_values[3].Reg64 = vcpu->exit_ctx.CpuidAccess.DefaultResultRdx;
+ reg_values[4].Reg64 = vcpu->exit_ctx.CpuidAccess.DefaultResultRbx;
+ } else {
+ cpu_x86_cpuid(env, vcpu->exit_ctx.CpuidAccess.Rax, 0,
+ (UINT32 *)®_values[1].Reg32,
+ (UINT32 *)®_values[4].Reg32, (UINT32 *)®_values[2].Reg32,
+ (UINT32 *)®_values[3].Reg32);
+ }
+
+ if (!whpx->hyperv_enlightenments_enabled) {
+ switch (vcpu->exit_ctx.CpuidAccess.Rax) {
+ case 1:
+ if (cpu_has_x2apic_feature(env)) {
+ reg_values[2].Reg64 |= CPUID_EXT_X2APIC;
+ }
+ reg_values[2].Reg64 |= CPUID_EXT_HYPERVISOR;
+ break;
+ case 0x40000000:
+ /* report KVM */
+ if (x86_cpu->vmware_cpuid_freq) {
+ reg_values[1].Reg64 = 0x40000010;
+ } else {
+ reg_values[1].Reg64 = 0x40000001;
+ }
+ reg_values[4].Reg64 = 0x4b4d564b;
+ reg_values[2].Reg64 = 0x564b4d56;
+ reg_values[3].Reg64 = 0x4d;
+ break;
+ case 0x40000001:
+ /* report X2APIC */
+ reg_values[1].Reg64 = reg_values[4].Reg64 = reg_values[2].Reg64 = 1 << 15;
+ break;
+ case 0x40000010:
+ if (x86_cpu->vmware_cpuid_freq) {
+ reg_values[1].Reg64 = env->tsc_khz;
+ reg_values[4].Reg64 = env->apic_bus_freq / 1000; /* Hz to KHz */
+ }
+ break;
}
}
@@ -2259,6 +2292,24 @@ int whpx_init_vcpu(CPUState *cpu)
env->apic_bus_freq = 1000000000;
}
+ /* When Hyper-V enlightenments are not active, fall back to the KVM ones */
+ if (!whpx->hyperv_enlightenments_enabled) {
+ UINT32 cpuidExitList[] = {1, 0x40000000, 0x40000001, 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->accel = vcpu;
@@ -2507,6 +2558,7 @@ int whpx_accel_init(AccelState *as, MachineState *ms)
}
if (!is_legacy_os && whpx->hyperv_enlightenments_allowed) {
+ whpx->hyperv_enlightenments_enabled = true;
hr = whp_dispatch.WHvSetPartitionProperty(
whpx->partition,
WHvPartitionPropertyCodeSyntheticProcessorFeaturesBanks,
--
2.50.1 (Apple Git-155)