]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - arch/x86/kvm/cpuid.c
x86/KVM/VMX: Expose SPEC_CTRL Bit(2) to the guest
[mirror_ubuntu-bionic-kernel.git] / arch / x86 / kvm / cpuid.c
index 19adbb4184439dd6c40c39cd6dec2afe5a9ae83a..daed3050e2de8e2a01b71c151a7a6b941f27a820 100644 (file)
@@ -67,9 +67,7 @@ u64 kvm_supported_xcr0(void)
 
 #define F(x) bit(X86_FEATURE_##x)
 
-/* These are scattered features in cpufeatures.h. */
-#define KVM_CPUID_BIT_AVX512_4VNNIW     2
-#define KVM_CPUID_BIT_AVX512_4FMAPS     3
+/* For scattered features from cpufeatures.h; we currently expose none */
 #define KF(x) bit(KVM_CPUID_BIT_##x)
 
 int kvm_update_cpuid(struct kvm_vcpu *vcpu)
@@ -126,16 +124,20 @@ int kvm_update_cpuid(struct kvm_vcpu *vcpu)
                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.
+        * The existing code assumes virtual address is 48-bit or 57-bit in the
+        * canonical address checks; exit if it is ever changed.
         */
        best = kvm_find_cpuid_entry(vcpu, 0x80000008, 0);
-       if (best && ((best->eax & 0xff00) >> 8) != 48 &&
-               ((best->eax & 0xff00) >> 8) != 0)
-               return -EINVAL;
+       if (best) {
+               int vaddr_bits = (best->eax & 0xff00) >> 8;
+
+               if (vaddr_bits != 48 && vaddr_bits != 57 && vaddr_bits != 0)
+                       return -EINVAL;
+       }
 
        /* Update physical-address width */
        vcpu->arch.maxphyaddr = cpuid_query_maxphyaddr(vcpu);
+       kvm_mmu_reset_context(vcpu);
 
        kvm_pmu_refresh(vcpu);
        return 0;
@@ -363,6 +365,10 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
                F(3DNOWPREFETCH) | F(OSVW) | 0 /* IBS */ | F(XOP) |
                0 /* SKINIT, WDT, LWP */ | F(FMA4) | F(TBM);
 
+       /* cpuid 0x80000008.ebx */
+       const u32 kvm_cpuid_8000_0008_ebx_x86_features =
+               F(IBPB) | F(IBRS);
+
        /* cpuid 0xC0000001.edx */
        const u32 kvm_cpuid_C000_0001_edx_x86_features =
                F(XSTORE) | F(XSTORE_EN) | F(XCRYPT) | F(XCRYPT_EN) |
@@ -383,11 +389,14 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
 
        /* cpuid 7.0.ecx*/
        const u32 kvm_cpuid_7_0_ecx_x86_features =
-               F(AVX512VBMI) | F(PKU) | 0 /*OSPKE*/ | F(AVX512_VPOPCNTDQ);
+               F(AVX512VBMI) | F(LA57) | F(PKU) | 0 /*OSPKE*/ |
+               F(AVX512_VPOPCNTDQ) | F(UMIP) | F(AVX512_VBMI2) | F(GFNI) |
+               F(VAES) | F(VPCLMULQDQ) | F(AVX512_VNNI) | F(AVX512_BITALG);
 
        /* cpuid 7.0.edx*/
        const u32 kvm_cpuid_7_0_edx_x86_features =
-               KF(AVX512_4VNNIW) | KF(AVX512_4FMAPS);
+               F(AVX512_4VNNIW) | F(AVX512_4FMAPS) | F(SPEC_CTRL) | F(RDS) |
+               F(ARCH_CAPABILITIES);
 
        /* all calls to cpuid_count() should be made on the same cpu */
        get_cpu();
@@ -472,7 +481,7 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
                        if (!tdp_enabled || !boot_cpu_has(X86_FEATURE_OSPKE))
                                entry->ecx &= ~F(PKU);
                        entry->edx &= kvm_cpuid_7_0_edx_x86_features;
-                       entry->edx &= get_scattered_cpuid_leaf(7, 0, CPUID_EDX);
+                       cpuid_mask(&entry->edx, CPUID_7_EDX);
                } else {
                        entry->ebx = 0;
                        entry->ecx = 0;
@@ -589,7 +598,8 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
                             (1 << KVM_FEATURE_ASYNC_PF) |
                             (1 << KVM_FEATURE_PV_EOI) |
                             (1 << KVM_FEATURE_CLOCKSOURCE_STABLE_BIT) |
-                            (1 << KVM_FEATURE_PV_UNHALT);
+                            (1 << KVM_FEATURE_PV_UNHALT) |
+                            (1 << KVM_FEATURE_ASYNC_PF_VMEXIT);
 
                if (sched_info_on())
                        entry->eax |= (1 << KVM_FEATURE_STEAL_TIME);
@@ -622,7 +632,14 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
                if (!g_phys_as)
                        g_phys_as = phys_as;
                entry->eax = g_phys_as | (virt_as << 8);
-               entry->ebx = entry->edx = 0;
+               entry->edx = 0;
+               /* IBRS and IBPB aren't necessarily present in hardware cpuid */
+               if (boot_cpu_has(X86_FEATURE_IBPB))
+                       entry->ebx |= F(IBPB);
+               if (boot_cpu_has(X86_FEATURE_IBRS))
+                       entry->ebx |= F(IBRS);
+               entry->ebx &= kvm_cpuid_8000_0008_ebx_x86_features;
+               cpuid_mask(&entry->ebx, CPUID_8000_0008_EBX);
                break;
        }
        case 0x80000019:
@@ -853,16 +870,24 @@ static struct kvm_cpuid_entry2* check_cpuid_limit(struct kvm_vcpu *vcpu,
        return kvm_find_cpuid_entry(vcpu, maxlevel->eax, index);
 }
 
-void kvm_cpuid(struct kvm_vcpu *vcpu, u32 *eax, u32 *ebx, u32 *ecx, u32 *edx)
+bool kvm_cpuid(struct kvm_vcpu *vcpu, u32 *eax, u32 *ebx,
+              u32 *ecx, u32 *edx, bool check_limit)
 {
        u32 function = *eax, index = *ecx;
        struct kvm_cpuid_entry2 *best;
+       bool entry_found = true;
 
        best = kvm_find_cpuid_entry(vcpu, function, index);
 
-       if (!best)
+       if (!best) {
+               entry_found = false;
+               if (!check_limit)
+                       goto out;
+
                best = check_cpuid_limit(vcpu, function, index);
+       }
 
+out:
        if (best) {
                *eax = best->eax;
                *ebx = best->ebx;
@@ -870,7 +895,8 @@ void kvm_cpuid(struct kvm_vcpu *vcpu, u32 *eax, u32 *ebx, u32 *ecx, u32 *edx)
                *edx = best->edx;
        } else
                *eax = *ebx = *ecx = *edx = 0;
-       trace_kvm_cpuid(function, *eax, *ebx, *ecx, *edx);
+       trace_kvm_cpuid(function, *eax, *ebx, *ecx, *edx, entry_found);
+       return entry_found;
 }
 EXPORT_SYMBOL_GPL(kvm_cpuid);
 
@@ -883,7 +909,7 @@ int kvm_emulate_cpuid(struct kvm_vcpu *vcpu)
 
        eax = kvm_register_read(vcpu, VCPU_REGS_RAX);
        ecx = kvm_register_read(vcpu, VCPU_REGS_RCX);
-       kvm_cpuid(vcpu, &eax, &ebx, &ecx, &edx);
+       kvm_cpuid(vcpu, &eax, &ebx, &ecx, &edx, true);
        kvm_register_write(vcpu, VCPU_REGS_RAX, eax);
        kvm_register_write(vcpu, VCPU_REGS_RBX, ebx);
        kvm_register_write(vcpu, VCPU_REGS_RCX, ecx);