diff --git a/target-i386/cpu.c b/target-i386/cpu.c index f3708e6..ad77b72 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -1250,6 +1250,8 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model) hyperv_enable_relaxed_timing(true); } else if (!strcmp(featurestr, "hv_vapic")) { hyperv_enable_vapic_recommended(true); + } else if (!strcmp(featurestr, "hv_tsc")) { + hyperv_enable_tsc_recommended(true); } else { fprintf(stderr, "feature string `%s' not in format (+feature|-feature|feature=xyz)\n", featurestr); goto error; diff --git a/target-i386/hyperv.c b/target-i386/hyperv.c index f284e99..bd581a1 100644 --- a/target-i386/hyperv.c +++ b/target-i386/hyperv.c @@ -15,6 +15,12 @@ static bool hyperv_vapic; static bool hyperv_relaxed_timing; static int hyperv_spinlock_attempts = HYPERV_SPINLOCK_NEVER_RETRY; +static bool hyperv_tsc; + +void hyperv_enable_tsc_recommended(bool val) +{ + hyperv_tsc = val; +} void hyperv_enable_vapic_recommended(bool val) { @@ -42,12 +48,18 @@ bool hyperv_enabled(void) bool hyperv_hypercall_available(void) { if (hyperv_vapic || + hyperv_tsc || (hyperv_spinlock_attempts != HYPERV_SPINLOCK_NEVER_RETRY)) { return true; } return false; } +bool hyperv_tsc_recommended(void) +{ + return hyperv_tsc; +} + bool hyperv_vapic_recommended(void) { return hyperv_vapic; diff --git a/target-i386/hyperv.h b/target-i386/hyperv.h index bacb1d4..94c2d6e 100644 --- a/target-i386/hyperv.h +++ b/target-i386/hyperv.h @@ -27,10 +27,12 @@ #endif #if !defined(CONFIG_USER_ONLY) && defined(CONFIG_KVM) +void hyperv_enable_tsc_recommended(bool val); void hyperv_enable_vapic_recommended(bool val); void hyperv_enable_relaxed_timing(bool val); void hyperv_set_spinlock_retries(int val); #else +static inline void hyperv_enable_tsc_recommended(bool val) { } static inline void hyperv_enable_vapic_recommended(bool val) { } static inline void hyperv_enable_relaxed_timing(bool val) { } static inline void hyperv_set_spinlock_retries(int val) { } @@ -38,6 +40,7 @@ static inline void hyperv_set_spinlock_retries(int val) { } bool hyperv_enabled(void); bool hyperv_hypercall_available(void); +bool hyperv_tsc_recommended(void); bool hyperv_vapic_recommended(void); bool hyperv_relaxed_timing_enabled(void); int hyperv_get_spinlock_retries(void); diff --git a/target-i386/kvm.c b/target-i386/kvm.c index 5b18383..dc7f259 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -390,13 +390,17 @@ int kvm_arch_init_vcpu(CPUX86State *env) c = &cpuid_data.entries[cpuid_i++]; memset(c, 0, sizeof(*c)); c->function = KVM_CPUID_SIGNATURE; - if (!hyperv_enabled()) { - memcpy(signature, "KVMKVMKVM\0\0\0", 12); - c->eax = 0; - } else { - memcpy(signature, "Microsoft Hv", 12); + memcpy(signature, "KVMKVMKVM\0\0\0", 12); + if (hyperv_enabled()) { c->eax = HYPERV_CPUID_MIN; } +// if (!hyperv_enabled()) { +// memcpy(signature, "KVMKVMKVM\0\0\0", 12); +// c->eax = 0; +// } else { +// memcpy(signature, "Microsoft Hv", 12); +// c->eax = HYPERV_CPUID_MIN; +// } c->ebx = signature[0]; c->ecx = signature[1]; c->edx = signature[2]; @@ -427,7 +431,11 @@ int kvm_arch_init_vcpu(CPUX86State *env) c->eax |= HV_X64_MSR_HYPERCALL_AVAILABLE; c->eax |= HV_X64_MSR_APIC_ACCESS_AVAILABLE; } - + if (hyperv_tsc_recommended()) { + c->eax |= HV_X64_MSR_HYPERCALL_AVAILABLE; + c->eax |= HV_X64_MSR_TIME_REF_COUNT_AVAILABLE; + c->eax |= 0x200; + } c = &cpuid_data.entries[cpuid_i++]; memset(c, 0, sizeof(*c)); c->function = HYPERV_CPUID_ENLIGHTMENT_INFO; @@ -445,14 +453,14 @@ int kvm_arch_init_vcpu(CPUX86State *env) c->eax = 0x40; c->ebx = 0x40; - c = &cpuid_data.entries[cpuid_i++]; - memset(c, 0, sizeof(*c)); - c->function = KVM_CPUID_SIGNATURE_NEXT; - memcpy(signature, "KVMKVMKVM\0\0\0", 12); - c->eax = 0; - c->ebx = signature[0]; - c->ecx = signature[1]; - c->edx = signature[2]; +// c = &cpuid_data.entries[cpuid_i++]; +// memset(c, 0, sizeof(*c)); +// c->function = KVM_CPUID_SIGNATURE_NEXT; +// memcpy(signature, "KVMKVMKVM\0\0\0", 12); +// c->eax = 0; +// c->ebx = signature[0]; +// c->ecx = signature[1]; +// c->edx = signature[2]; } has_msr_async_pf_en = c->eax & (1 << KVM_FEATURE_ASYNC_PF);