Patchwork [RFC,v1,2/2] hyper-v: initialize Hyper-V CPUID leafs.

login
register
mail settings
Submitter Vadim Rozenfeld
Date Oct. 17, 2011, 9:17 a.m.
Message ID <1318843022-20344-3-git-send-email-vrozenfe@redhat.com>
Download mbox | patch
Permalink /patch/120115/
State New
Headers show

Comments

Vadim Rozenfeld - Oct. 17, 2011, 9:17 a.m.
---
 target-i386/kvm.c |   64 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 62 insertions(+), 2 deletions(-)
Paolo Bonzini - Oct. 17, 2011, 9:40 a.m.
On 10/17/2011 11:17 AM, Vadim Rozenfeld wrote:
> @@ -379,11 +380,16 @@ int kvm_arch_init_vcpu(CPUState *env)
>       cpuid_i = 0;
>
>       /* Paravirtualization CPUIDs */
> -    memcpy(signature, "KVMKVMKVM\0\0\0", 12);
>       c =&cpuid_data.entries[cpuid_i++];
>       memset(c, 0, sizeof(*c));
>       c->function = KVM_CPUID_SIGNATURE;
> -    c->eax = 0;
> +    if (!hyperv_enabled()) {
> +        memcpy(signature, "KVMKVMKVM\0\0\0", 12);
> +        c->eax = 0;
> +    } else {
> +        memcpy(signature, "Microsoft Hv", 12);
> +        c->eax = HYPERV_CPUID_MIN;
> +    }

Even not counting that hyper-v support should IMHO not be in 
KVM-specific code, I still think this shouldn't remove KVM leaves 
completely but rather move them to 0x40000100.  The KVM 
paravirtualization code then can similarly probe with 0x100 stride up to 
0x40001000.  This is what was done for Xen, and it allows to enable 
enlightenments independent of whether the guest is Linux or Windows.

However, let's get a third opinion---Avi, what do you think?

Paolo
Avi Kivity - Oct. 17, 2011, 10:41 a.m.
On 10/17/2011 11:40 AM, Paolo Bonzini wrote:
> On 10/17/2011 11:17 AM, Vadim Rozenfeld wrote:
>> @@ -379,11 +380,16 @@ int kvm_arch_init_vcpu(CPUState *env)
>>       cpuid_i = 0;
>>
>>       /* Paravirtualization CPUIDs */
>> -    memcpy(signature, "KVMKVMKVM\0\0\0", 12);
>>       c =&cpuid_data.entries[cpuid_i++];
>>       memset(c, 0, sizeof(*c));
>>       c->function = KVM_CPUID_SIGNATURE;
>> -    c->eax = 0;
>> +    if (!hyperv_enabled()) {
>> +        memcpy(signature, "KVMKVMKVM\0\0\0", 12);
>> +        c->eax = 0;
>> +    } else {
>> +        memcpy(signature, "Microsoft Hv", 12);
>> +        c->eax = HYPERV_CPUID_MIN;
>> +    }
>
> Even not counting that hyper-v support should IMHO not be in
> KVM-specific code, I still think this shouldn't remove KVM leaves
> completely but rather move them to 0x40000100.  The KVM
> paravirtualization code then can similarly probe with 0x100 stride up
> to 0x40001000.  This is what was done for Xen, and it allows to enable
> enlightenments independent of whether the guest is Linux or Windows.
>
> However, let's get a third opinion---Avi, what do you think?

I agree with you, especially as this already works for Xen.

Note it doesn't completely solve the issue (so we have two interfaces,
which is the preferred one?), but it's better than nothing.
Paolo Bonzini - Oct. 17, 2011, 10:42 a.m.
On 10/17/2011 12:41 PM, Avi Kivity wrote:
> >  Even not counting that hyper-v support should IMHO not be in
> >  KVM-specific code, I still think this shouldn't remove KVM leaves
> >  completely but rather move them to 0x40000100.  The KVM
> >  paravirtualization code then can similarly probe with 0x100 stride up
> >  to 0x40001000.  This is what was done for Xen, and it allows to enable
> >  enlightenments independent of whether the guest is Linux or Windows.
> >
> >  However, let's get a third opinion---Avi, what do you think?
>
> I agree with you, especially as this already works for Xen.
>
> Note it doesn't completely solve the issue (so we have two interfaces,
> which is the preferred one?), but it's better than nothing.

Windows doesn't look beyond 0x40000000, so Hyper-V stays there and KVM 
has to shift.  So MS solved that part for us. :)

Paolo
Avi Kivity - Oct. 17, 2011, 1:57 p.m.
On 10/17/2011 12:42 PM, Paolo Bonzini wrote:
> On 10/17/2011 12:41 PM, Avi Kivity wrote:
>> >  Even not counting that hyper-v support should IMHO not be in
>> >  KVM-specific code, I still think this shouldn't remove KVM leaves
>> >  completely but rather move them to 0x40000100.  The KVM
>> >  paravirtualization code then can similarly probe with 0x100 stride up
>> >  to 0x40001000.  This is what was done for Xen, and it allows to
>> enable
>> >  enlightenments independent of whether the guest is Linux or Windows.
>> >
>> >  However, let's get a third opinion---Avi, what do you think?
>>
>> I agree with you, especially as this already works for Xen.
>>
>> Note it doesn't completely solve the issue (so we have two interfaces,
>> which is the preferred one?), but it's better than nothing.
>
> Windows doesn't look beyond 0x40000000, so Hyper-V stays there and KVM
> has to shift.  So MS solved that part for us. :)

I mean, suppose Linux finds hyper-v at 000 and kvm at 100.  Is it kvm
impersonating hyper-v, or a future hyper-v impersonating kvm, or
something else (TAINT_CRAP?) impersonating both?

Patch

diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index 3840255..30b3e85 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -29,6 +29,7 @@ 
 #include "hw/pc.h"
 #include "hw/apic.h"
 #include "ioport.h"
+#include "hyperv.h"
 
 //#define DEBUG_KVM
 
@@ -379,11 +380,16 @@  int kvm_arch_init_vcpu(CPUState *env)
     cpuid_i = 0;
 
     /* Paravirtualization CPUIDs */
-    memcpy(signature, "KVMKVMKVM\0\0\0", 12);
     c = &cpuid_data.entries[cpuid_i++];
     memset(c, 0, sizeof(*c));
     c->function = KVM_CPUID_SIGNATURE;
-    c->eax = 0;
+    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];
@@ -394,6 +400,45 @@  int kvm_arch_init_vcpu(CPUState *env)
     c->eax = env->cpuid_kvm_features &
         kvm_arch_get_supported_cpuid(s, KVM_CPUID_FEATURES, 0, R_EAX);
 
+    if (hyperv_enabled()) {
+        memcpy(signature, "Hv#1\0\0\0\0\0\0\0\0", 12);
+        c->eax = signature[0];
+
+        c = &cpuid_data.entries[cpuid_i++];
+        memset(c, 0, sizeof(*c));
+        c->function = HYPERV_CPUID_VERSION;
+        c->eax = 0x00001bbc;
+        c->ebx = 0x00060001;
+
+        c = &cpuid_data.entries[cpuid_i++];
+        memset(c, 0, sizeof(*c));
+        c->function = HYPERV_CPUID_FEATURES;
+        if (hyperv_get_relaxed_timing()) {
+            c->eax |= HV_X64_MSR_HYPERCALL_AVAILABLE;
+        }
+        if (hyperv_get_vapic_recommended()) {
+            c->eax |= HV_X64_MSR_HYPERCALL_AVAILABLE;
+            c->eax |= HV_X64_MSR_APIC_ACCESS_AVAILABLE;
+        }
+
+        c = &cpuid_data.entries[cpuid_i++];
+        memset(c, 0, sizeof(*c));
+        c->function = HYPERV_CPUID_ENLIGHTMENT_INFO;
+        if (hyperv_get_relaxed_timing()) {
+            c->eax |= HV_X64_RELAXED_TIMING_RECOMMENDED;
+        }
+        if (hyperv_get_vapic_recommended()) {
+            c->eax |= HV_X64_APIC_ACCESS_RECOMMENDED;
+        }
+        c->ebx = hyperv_get_spinlock_retries();
+
+        c = &cpuid_data.entries[cpuid_i++];
+        memset(c, 0, sizeof(*c));
+        c->function = HYPERV_CPUID_IMPLEMENT_LIMITS;
+        c->eax = 0x40;
+        c->ebx = 0x40;
+    }
+
     has_msr_async_pf_en = c->eax & (1 << KVM_FEATURE_ASYNC_PF);
 
     cpu_x86_cpuid(env, 0, 0, &limit, &unused, &unused, &unused);
@@ -945,6 +990,13 @@  static int kvm_put_msrs(CPUState *env, int level)
             kvm_msr_entry_set(&msrs[n++], MSR_KVM_ASYNC_PF_EN,
                               env->async_pf_en_msr);
         }
+        if (hyperv_hypercall_available()) {
+            kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_GUEST_OS_ID, 0);
+            kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_HYPERCALL, 0);
+        }
+        if (hyperv_get_vapic_recommended()) {
+            kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_APIC_ASSIST_PAGE, 0);
+        }
     }
     if (env->mcg_cap) {
         int i;
@@ -1179,6 +1231,14 @@  static int kvm_get_msrs(CPUState *env)
         msrs[n++].index = MSR_KVM_ASYNC_PF_EN;
     }
 
+    if (hyperv_hypercall_available()) {
+        msrs[n++].index = HV_X64_MSR_GUEST_OS_ID;
+        msrs[n++].index = HV_X64_MSR_HYPERCALL;
+    }
+    if (hyperv_get_vapic_recommended()) {
+        msrs[n++].index = HV_X64_MSR_APIC_ASSIST_PAGE;
+    }
+
     if (env->mcg_cap) {
         msrs[n++].index = MSR_MCG_STATUS;
         msrs[n++].index = MSR_MCG_CTL;