Merge tag 'iwlwifi-next-for-kalle-2014-12-30' of https://git.kernel.org/pub/scm/linux...
[cascardo/linux.git] / arch / x86 / kvm / cpuid.c
index 976e3a5..8a80737 100644 (file)
@@ -23,7 +23,7 @@
 #include "mmu.h"
 #include "trace.h"
 
-static u32 xstate_required_size(u64 xstate_bv)
+static u32 xstate_required_size(u64 xstate_bv, bool compacted)
 {
        int feature_bit = 0;
        u32 ret = XSAVE_HDR_SIZE + XSAVE_HDR_OFFSET;
@@ -31,9 +31,10 @@ static u32 xstate_required_size(u64 xstate_bv)
        xstate_bv &= XSTATE_EXTEND_MASK;
        while (xstate_bv) {
                if (xstate_bv & 0x1) {
-                       u32 eax, ebx, ecx, edx;
+                       u32 eax, ebx, ecx, edx, offset;
                        cpuid_count(0xD, feature_bit, &eax, &ebx, &ecx, &edx);
-                       ret = max(ret, eax + ebx);
+                       offset = compacted ? ret : ebx;
+                       ret = max(ret, offset + eax);
                }
 
                xstate_bv >>= 1;
@@ -53,6 +54,8 @@ u64 kvm_supported_xcr0(void)
        return xcr0;
 }
 
+#define F(x) bit(X86_FEATURE_##x)
+
 int kvm_update_cpuid(struct kvm_vcpu *vcpu)
 {
        struct kvm_cpuid_entry2 *best;
@@ -64,13 +67,13 @@ int kvm_update_cpuid(struct kvm_vcpu *vcpu)
 
        /* Update OSXSAVE bit */
        if (cpu_has_xsave && best->function == 0x1) {
-               best->ecx &= ~(bit(X86_FEATURE_OSXSAVE));
+               best->ecx &= ~F(OSXSAVE);
                if (kvm_read_cr4_bits(vcpu, X86_CR4_OSXSAVE))
-                       best->ecx |= bit(X86_FEATURE_OSXSAVE);
+                       best->ecx |= F(OSXSAVE);
        }
 
        if (apic) {
-               if (best->ecx & bit(X86_FEATURE_TSC_DEADLINE_TIMER))
+               if (best->ecx & F(TSC_DEADLINE_TIMER))
                        apic->lapic_timer.timer_mode_mask = 3 << 17;
                else
                        apic->lapic_timer.timer_mode_mask = 1 << 17;
@@ -85,9 +88,13 @@ int kvm_update_cpuid(struct kvm_vcpu *vcpu)
                        (best->eax | ((u64)best->edx << 32)) &
                        kvm_supported_xcr0();
                vcpu->arch.guest_xstate_size = best->ebx =
-                       xstate_required_size(vcpu->arch.xcr0);
+                       xstate_required_size(vcpu->arch.xcr0, false);
        }
 
+       best = kvm_find_cpuid_entry(vcpu, 0xD, 1);
+       if (best && (best->eax & (F(XSAVES) | F(XSAVEC))))
+               best->ebx = xstate_required_size(vcpu->arch.xcr0, true);
+
        /*
         * The existing code assumes virtual address is 48-bit in the canonical
         * address checks; exit if it is ever changed.
@@ -122,8 +129,8 @@ static void cpuid_fix_nx_cap(struct kvm_vcpu *vcpu)
                        break;
                }
        }
-       if (entry && (entry->edx & bit(X86_FEATURE_NX)) && !is_efer_nx()) {
-               entry->edx &= ~bit(X86_FEATURE_NX);
+       if (entry && (entry->edx & F(NX)) && !is_efer_nx()) {
+               entry->edx &= ~F(NX);
                printk(KERN_INFO "kvm: guest NX capability removed\n");
        }
 }
@@ -227,8 +234,6 @@ static void do_cpuid_1_ent(struct kvm_cpuid_entry2 *entry, u32 function,
        entry->flags = 0;
 }
 
-#define F(x) bit(X86_FEATURE_##x)
-
 static int __do_cpuid_ent_emulated(struct kvm_cpuid_entry2 *entry,
                                   u32 func, u32 index, int *nent, int maxnent)
 {
@@ -267,6 +272,7 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
        unsigned f_rdtscp = kvm_x86_ops->rdtscp_supported() ? F(RDTSCP) : 0;
        unsigned f_invpcid = kvm_x86_ops->invpcid_supported() ? F(INVPCID) : 0;
        unsigned f_mpx = kvm_x86_ops->mpx_supported() ? F(MPX) : 0;
+       unsigned f_xsaves = kvm_x86_ops->xsaves_supported() ? F(XSAVES) : 0;
 
        /* cpuid 1.edx */
        const u32 kvm_supported_word0_x86_features =
@@ -317,7 +323,12 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
        const u32 kvm_supported_word9_x86_features =
                F(FSGSBASE) | F(BMI1) | F(HLE) | F(AVX2) | F(SMEP) |
                F(BMI2) | F(ERMS) | f_invpcid | F(RTM) | f_mpx | F(RDSEED) |
-               F(ADX) | F(SMAP);
+               F(ADX) | F(SMAP) | F(AVX512F) | F(AVX512PF) | F(AVX512ER) |
+               F(AVX512CD);
+
+       /* cpuid 0xD.1.eax */
+       const u32 kvm_supported_word10_x86_features =
+               F(XSAVEOPT) | F(XSAVEC) | F(XGETBV1) | f_xsaves;
 
        /* all calls to cpuid_count() should be made on the same cpu */
        get_cpu();
@@ -453,16 +464,34 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
                u64 supported = kvm_supported_xcr0();
 
                entry->eax &= supported;
+               entry->ebx = xstate_required_size(supported, false);
+               entry->ecx = entry->ebx;
                entry->edx &= supported >> 32;
                entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
+               if (!supported)
+                       break;
+
                for (idx = 1, i = 1; idx < 64; ++idx) {
                        u64 mask = ((u64)1 << idx);
                        if (*nent >= maxnent)
                                goto out;
 
                        do_cpuid_1_ent(&entry[i], function, idx);
-                       if (entry[i].eax == 0 || !(supported & mask))
-                               continue;
+                       if (idx == 1) {
+                               entry[i].eax &= kvm_supported_word10_x86_features;
+                               entry[i].ebx = 0;
+                               if (entry[i].eax & (F(XSAVES)|F(XSAVEC)))
+                                       entry[i].ebx =
+                                               xstate_required_size(supported,
+                                                                    true);
+                       } else {
+                               if (entry[i].eax == 0 || !(supported & mask))
+                                       continue;
+                               if (WARN_ON_ONCE(entry[i].ecx & 1))
+                                       continue;
+                       }
+                       entry[i].ecx = 0;
+                       entry[i].edx = 0;
                        entry[i].flags |=
                               KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
                        ++*nent;