diff --git a/target/i386/cpu.c b/target/i386/cpu.c index cff23e129d..e41375eb95 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -3658,6 +3658,7 @@ static Property x86_cpu_properties[] = { DEFINE_PROP_BOOL("cpuid-0xb", X86CPU, enable_cpuid_0xb, true), DEFINE_PROP_BOOL("lmce", X86CPU, enable_lmce, false), DEFINE_PROP_BOOL("l3-cache", X86CPU, enable_l3_cache, true), + DEFINE_PROP_BOOL("vmware-cpuid-freq", X86CPU, vmware_cpuid_freq, false), DEFINE_PROP_END_OF_LIST() }; diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 10c5a3538d..4d788d56fc 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -1214,6 +1214,10 @@ struct X86CPU { bool host_features; uint32_t apic_id; + /* Enables publishing of TSC increment and Local APIC bus frequencies to + * the guest OS in CPUID page 0x40000010, the same way that VMWare does. */ + bool vmware_cpuid_freq; + /* if true the CPUID code directly forward host cache leaves to the guest */ bool cache_info_passthrough; diff --git a/target/i386/kvm.c b/target/i386/kvm.c index 8e130ccf9c..27fd0505df 100644 --- a/target/i386/kvm.c +++ b/target/i386/kvm.c @@ -982,12 +982,6 @@ int kvm_arch_init_vcpu(CPUState *cs) } } - cpuid_data.cpuid.padding = 0; - r = kvm_vcpu_ioctl(cs, KVM_SET_CPUID2, &cpuid_data); - if (r) { - goto fail; - } - r = kvm_arch_set_tsc_khz(cs); if (r < 0) { goto fail; @@ -1007,6 +1001,36 @@ int kvm_arch_init_vcpu(CPUState *cs) } } + if (cpu->vmware_cpuid_freq + /* Guests depend on 0x40000000 to detect this feature, so only expose + * it if KVM exposes leaf 0x40000000. (Conflicts with Hyper-V) */ + && cpu->expose_kvm + && kvm_base == KVM_CPUID_SIGNATURE + /* TSC clock must be stable and known for this feature. */ + && ((env->features[FEAT_8000_0007_EDX] & CPUID_APM_INVTSC) + || env->user_tsc_khz != 0) + && env->tsc_khz != 0) { + + c = &cpuid_data.entries[cpuid_i++]; + c->function = KVM_CPUID_SIGNATURE | 0x10; + c->eax = env->tsc_khz; + /* LAPIC resolution of 1ns (freq: 1GHz) is hardcoded in KVM's + * APIC_BUS_CYCLE_NS */ + c->ebx = 1000000; + c->ecx = c->edx = 0; + + c = cpuid_find_entry(&cpuid_data.cpuid, kvm_base, 0); + c->eax = MAX(c->eax, KVM_CPUID_SIGNATURE | 0x10); + } + + cpuid_data.cpuid.nent = cpuid_i; + + cpuid_data.cpuid.padding = 0; + r = kvm_vcpu_ioctl(cs, KVM_SET_CPUID2, &cpuid_data); + if (r) { + goto fail; + } + if (has_xsave) { env->kvm_xsave_buf = qemu_memalign(4096, sizeof(struct kvm_xsave)); }