From 045bc2ba9d908702c4aa039fc465f01b31fdd404 Mon Sep 17 00:00:00 2001 From: Thomas Lamprecht Date: Thu, 13 Jun 2019 20:54:14 +0200 Subject: [PATCH] backport: KVM: x86: Emulate MSR_IA32_ARCH_CAPABILITIES on AMD hosts backport this and supporting patches to ensure Ryzen/Epyc CPUs work with QEMU and it's new MDS mitigation helpers, which also base on MSRs Signed-off-by: Thomas Lamprecht --- ...VM-Take-vcpu-mutex-outside-vcpu_load.patch | 180 ++++++++++++++++++ ...dify-MSR_PLATFORM_INFO-on-vCPU-reset.patch | 40 ++++ ...MSR_IA32_ARCH_CAPABILITIES-on-AMD-ho.patch | 133 +++++++++++++ 3 files changed, 353 insertions(+) create mode 100644 patches/kernel/0010-KVM-Take-vcpu-mutex-outside-vcpu_load.patch create mode 100644 patches/kernel/0011-kvm-x86-Don-t-modify-MSR_PLATFORM_INFO-on-vCPU-reset.patch create mode 100644 patches/kernel/0012-KVM-x86-Emulate-MSR_IA32_ARCH_CAPABILITIES-on-AMD-ho.patch diff --git a/patches/kernel/0010-KVM-Take-vcpu-mutex-outside-vcpu_load.patch b/patches/kernel/0010-KVM-Take-vcpu-mutex-outside-vcpu_load.patch new file mode 100644 index 0000000..caf7c56 --- /dev/null +++ b/patches/kernel/0010-KVM-Take-vcpu-mutex-outside-vcpu_load.patch @@ -0,0 +1,180 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Christoffer Dall +Date: Mon, 4 Dec 2017 21:35:23 +0100 +Subject: [PATCH] KVM: Take vcpu->mutex outside vcpu_load + +As we're about to call vcpu_load() from architecture-specific +implementations of the KVM vcpu ioctls, but yet we access data +structures protected by the vcpu->mutex in the generic code, factor +this logic out from vcpu_load(). + +x86 is the only architecture which calls vcpu_load() outside of the main +vcpu ioctl function, and these calls will no longer take the vcpu mutex +following this patch. However, with the exception of +kvm_arch_vcpu_postcreate (see below), the callers are either in the +creation or destruction path of the VCPU, which means there cannot be +any concurrent access to the data structure, because the file descriptor +is not yet accessible, or is already gone. + +kvm_arch_vcpu_postcreate makes the newly created vcpu potentially +accessible by other in-kernel threads through the kvm->vcpus array, and +we therefore take the vcpu mutex in this case directly. + +Signed-off-by: Christoffer Dall +Reviewed-by: Cornelia Huck +Signed-off-by: Paolo Bonzini +(cherry picked from commit ec7660ccdd2b71d8c7f0243f8590253713e9b75d) +Signed-off-by: Thomas Lamprecht +--- + arch/x86/kvm/vmx.c | 4 +--- + arch/x86/kvm/x86.c | 20 +++++++------------- + include/linux/kvm_host.h | 2 +- + virt/kvm/kvm_main.c | 17 ++++++----------- + 4 files changed, 15 insertions(+), 28 deletions(-) + +diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c +index bf348fee4bd5..38e50b40db5a 100644 +--- a/arch/x86/kvm/vmx.c ++++ b/arch/x86/kvm/vmx.c +@@ -9959,10 +9959,8 @@ static void vmx_switch_vmcs(struct kvm_vcpu *vcpu, struct loaded_vmcs *vmcs) + static void vmx_free_vcpu_nested(struct kvm_vcpu *vcpu) + { + struct vcpu_vmx *vmx = to_vmx(vcpu); +- int r; + +- r = vcpu_load(vcpu); +- BUG_ON(r); ++ vcpu_load(vcpu); + vmx_switch_vmcs(vcpu, &vmx->vmcs01); + free_nested(vmx); + vcpu_put(vcpu); +diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c +index ac17f53812af..c578a90f1128 100644 +--- a/arch/x86/kvm/x86.c ++++ b/arch/x86/kvm/x86.c +@@ -7949,16 +7949,12 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, + + int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu) + { +- int r; +- + kvm_vcpu_mtrr_init(vcpu); +- r = vcpu_load(vcpu); +- if (r) +- return r; ++ vcpu_load(vcpu); + kvm_vcpu_reset(vcpu, false); + kvm_mmu_setup(vcpu); + vcpu_put(vcpu); +- return r; ++ return 0; + } + + void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu) +@@ -7968,13 +7964,15 @@ void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu) + + kvm_hv_vcpu_postcreate(vcpu); + +- if (vcpu_load(vcpu)) ++ if (mutex_lock_killable(&vcpu->mutex)) + return; ++ vcpu_load(vcpu); + msr.data = 0x0; + msr.index = MSR_IA32_TSC; + msr.host_initiated = true; + kvm_write_tsc(vcpu, &msr); + vcpu_put(vcpu); ++ mutex_unlock(&vcpu->mutex); + + if (!kvmclock_periodic_sync) + return; +@@ -7985,11 +7983,9 @@ void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu) + + void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu) + { +- int r; + vcpu->arch.apf.msr_val = 0; + +- r = vcpu_load(vcpu); +- BUG_ON(r); ++ vcpu_load(vcpu); + kvm_mmu_unload(vcpu); + vcpu_put(vcpu); + +@@ -8363,9 +8359,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) + + static void kvm_unload_vcpu_mmu(struct kvm_vcpu *vcpu) + { +- int r; +- r = vcpu_load(vcpu); +- BUG_ON(r); ++ vcpu_load(vcpu); + kvm_mmu_unload(vcpu); + vcpu_put(vcpu); + } +diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h +index c807eab9c1d3..6684da3f197f 100644 +--- a/include/linux/kvm_host.h ++++ b/include/linux/kvm_host.h +@@ -533,7 +533,7 @@ static inline int kvm_vcpu_get_idx(struct kvm_vcpu *vcpu) + int kvm_vcpu_init(struct kvm_vcpu *vcpu, struct kvm *kvm, unsigned id); + void kvm_vcpu_uninit(struct kvm_vcpu *vcpu); + +-int __must_check vcpu_load(struct kvm_vcpu *vcpu); ++void vcpu_load(struct kvm_vcpu *vcpu); + void vcpu_put(struct kvm_vcpu *vcpu); + + #ifdef __KVM_HAVE_IOAPIC +diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c +index 238ddbc127e1..0d2eddfdf785 100644 +--- a/virt/kvm/kvm_main.c ++++ b/virt/kvm/kvm_main.c +@@ -151,17 +151,12 @@ bool kvm_is_reserved_pfn(kvm_pfn_t pfn) + /* + * Switches to specified vcpu, until a matching vcpu_put() + */ +-int vcpu_load(struct kvm_vcpu *vcpu) ++void vcpu_load(struct kvm_vcpu *vcpu) + { +- int cpu; +- +- if (mutex_lock_killable(&vcpu->mutex)) +- return -EINTR; +- cpu = get_cpu(); ++ int cpu = get_cpu(); + preempt_notifier_register(&vcpu->preempt_notifier); + kvm_arch_vcpu_load(vcpu, cpu); + put_cpu(); +- return 0; + } + EXPORT_SYMBOL_GPL(vcpu_load); + +@@ -171,7 +166,6 @@ void vcpu_put(struct kvm_vcpu *vcpu) + kvm_arch_vcpu_put(vcpu); + preempt_notifier_unregister(&vcpu->preempt_notifier); + preempt_enable(); +- mutex_unlock(&vcpu->mutex); + } + EXPORT_SYMBOL_GPL(vcpu_put); + +@@ -2562,9 +2556,9 @@ static long kvm_vcpu_ioctl(struct file *filp, + #endif + + +- r = vcpu_load(vcpu); +- if (r) +- return r; ++ if (mutex_lock_killable(&vcpu->mutex)) ++ return -EINTR; ++ vcpu_load(vcpu); + switch (ioctl) { + case KVM_RUN: { + struct pid *oldpid; +@@ -2737,6 +2731,7 @@ static long kvm_vcpu_ioctl(struct file *filp, + } + out: + vcpu_put(vcpu); ++ mutex_unlock(&vcpu->mutex); + kfree(fpu); + kfree(kvm_sregs); + return r; diff --git a/patches/kernel/0011-kvm-x86-Don-t-modify-MSR_PLATFORM_INFO-on-vCPU-reset.patch b/patches/kernel/0011-kvm-x86-Don-t-modify-MSR_PLATFORM_INFO-on-vCPU-reset.patch new file mode 100644 index 0000000..d57a726 --- /dev/null +++ b/patches/kernel/0011-kvm-x86-Don-t-modify-MSR_PLATFORM_INFO-on-vCPU-reset.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jim Mattson +Date: Tue, 30 Oct 2018 12:20:21 -0700 +Subject: [PATCH] kvm: x86: Don't modify MSR_PLATFORM_INFO on vCPU reset + +If userspace has provided a different value for this MSR (e.g with the +turbo bits set), the userspace-provided value should survive a vCPU +reset. For backwards compatibility, MSR_PLATFORM_INFO is initialized +in kvm_arch_vcpu_setup. + +Signed-off-by: Jim Mattson +Reviewed-by: Drew Schmitt +Cc: Abhiroop Dabral +Signed-off-by: Paolo Bonzini +(cherry picked from commit e53d88af63ab4104e1226b8f9959f1e9903da10b) +Signed-off-by: Thomas Lamprecht +--- + arch/x86/kvm/x86.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c +index c578a90f1128..e1f16d02e44f 100644 +--- a/arch/x86/kvm/x86.c ++++ b/arch/x86/kvm/x86.c +@@ -7949,6 +7949,7 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, + + int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu) + { ++ vcpu->arch.msr_platform_info = MSR_PLATFORM_INFO_CPUID_FAULT; + kvm_vcpu_mtrr_init(vcpu); + vcpu_load(vcpu); + kvm_vcpu_reset(vcpu, false); +@@ -8050,7 +8051,6 @@ void kvm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event) + kvm_pmu_reset(vcpu); + vcpu->arch.smbase = 0x30000; + +- vcpu->arch.msr_platform_info = MSR_PLATFORM_INFO_CPUID_FAULT; + vcpu->arch.msr_misc_features_enables = 0; + + vcpu->arch.xcr0 = XFEATURE_MASK_FP; diff --git a/patches/kernel/0012-KVM-x86-Emulate-MSR_IA32_ARCH_CAPABILITIES-on-AMD-ho.patch b/patches/kernel/0012-KVM-x86-Emulate-MSR_IA32_ARCH_CAPABILITIES-on-AMD-ho.patch new file mode 100644 index 0000000..a5bdeac --- /dev/null +++ b/patches/kernel/0012-KVM-x86-Emulate-MSR_IA32_ARCH_CAPABILITIES-on-AMD-ho.patch @@ -0,0 +1,133 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Sean Christopherson +Date: Thu, 7 Mar 2019 15:43:02 -0800 +Subject: [PATCH] KVM: x86: Emulate MSR_IA32_ARCH_CAPABILITIES on AMD hosts + +BugLink: https://bugs.launchpad.net/bugs/1823060 + +commit 0cf9135b773bf32fba9dd8e6699c1b331ee4b749 upstream. + +The CPUID flag ARCH_CAPABILITIES is unconditioinally exposed to host +userspace for all x86 hosts, i.e. KVM advertises ARCH_CAPABILITIES +regardless of hardware support under the pretense that KVM fully +emulates MSR_IA32_ARCH_CAPABILITIES. Unfortunately, only VMX hosts +handle accesses to MSR_IA32_ARCH_CAPABILITIES (despite KVM_GET_MSRS +also reporting MSR_IA32_ARCH_CAPABILITIES for all hosts). + +Move the MSR_IA32_ARCH_CAPABILITIES handling to common x86 code so +that it's emulated on AMD hosts. + +Fixes: 1eaafe91a0df4 ("kvm: x86: IA32_ARCH_CAPABILITIES is always supported") +Cc: stable@vger.kernel.org +Reported-by: Xiaoyao Li +Cc: Jim Mattson +Signed-off-by: Sean Christopherson +Signed-off-by: Paolo Bonzini +Signed-off-by: Greg Kroah-Hartman + +Signed-off-by: Seth Forshee + +(back ported from commit 0cf9135b773bf32fba9dd8e6699c1b331ee4b749) +Backported-by: Thomas Lamprecht +Signed-off-by: Thomas Lamprecht +--- + arch/x86/include/asm/kvm_host.h | 1 + + arch/x86/kvm/vmx.c | 14 -------------- + arch/x86/kvm/x86.c | 12 ++++++++++++ + 3 files changed, 13 insertions(+), 14 deletions(-) + +diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h +index e76012ca0ddc..fa57f78dff2d 100644 +--- a/arch/x86/include/asm/kvm_host.h ++++ b/arch/x86/include/asm/kvm_host.h +@@ -508,6 +508,7 @@ struct kvm_vcpu_arch { + bool tpr_access_reporting; + u64 ia32_xss; + u64 microcode_version; ++ u64 arch_capabilities; + + /* + * Paging state of the vcpu +diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c +index 38e50b40db5a..1911ec5e26c1 100644 +--- a/arch/x86/kvm/vmx.c ++++ b/arch/x86/kvm/vmx.c +@@ -750,7 +750,6 @@ struct vcpu_vmx { + u64 msr_guest_kernel_gs_base; + #endif + +- u64 arch_capabilities; + u64 spec_ctrl; + + u32 vm_entry_controls_shadow; +@@ -3477,12 +3476,6 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) + + msr_info->data = to_vmx(vcpu)->spec_ctrl; + break; +- case MSR_IA32_ARCH_CAPABILITIES: +- if (!msr_info->host_initiated && +- !guest_cpuid_has(vcpu, X86_FEATURE_ARCH_CAPABILITIES)) +- return 1; +- msr_info->data = to_vmx(vcpu)->arch_capabilities; +- break; + case MSR_IA32_SYSENTER_CS: + msr_info->data = vmcs_read32(GUEST_SYSENTER_CS); + break; +@@ -3644,11 +3637,6 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) + vmx_disable_intercept_for_msr(vmx->vmcs01.msr_bitmap, MSR_IA32_PRED_CMD, + MSR_TYPE_W); + break; +- case MSR_IA32_ARCH_CAPABILITIES: +- if (!msr_info->host_initiated) +- return 1; +- vmx->arch_capabilities = data; +- break; + case MSR_IA32_CR_PAT: + if (vmcs_config.vmentry_ctrl & VM_ENTRY_LOAD_IA32_PAT) { + if (!kvm_mtrr_valid(vcpu, MSR_IA32_CR_PAT, data)) +@@ -5906,8 +5894,6 @@ static void vmx_vcpu_setup(struct vcpu_vmx *vmx) + ++vmx->nmsrs; + } + +- vmx->arch_capabilities = kvm_get_arch_capabilities(); +- + vm_exit_controls_init(vmx, vmcs_config.vmexit_ctrl); + + /* 22.2.1, 20.8.1 */ +diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c +index e1f16d02e44f..bf76e7cd9837 100644 +--- a/arch/x86/kvm/x86.c ++++ b/arch/x86/kvm/x86.c +@@ -2246,6 +2246,11 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) + if (msr_info->host_initiated) + vcpu->arch.microcode_version = data; + break; ++ case MSR_IA32_ARCH_CAPABILITIES: ++ if (!msr_info->host_initiated) ++ return 1; ++ vcpu->arch.arch_capabilities = data; ++ break; + case MSR_EFER: + return set_efer(vcpu, data); + case MSR_K7_HWCR: +@@ -2541,6 +2546,12 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) + case MSR_IA32_UCODE_REV: + msr_info->data = vcpu->arch.microcode_version; + break; ++ case MSR_IA32_ARCH_CAPABILITIES: ++ if (!msr_info->host_initiated && ++ !guest_cpuid_has(vcpu, X86_FEATURE_ARCH_CAPABILITIES)) ++ return 1; ++ msr_info->data = vcpu->arch.arch_capabilities; ++ break; + case MSR_IA32_TSC: + msr_info->data = kvm_scale_tsc(vcpu, rdtsc()) + vcpu->arch.tsc_offset; + break; +@@ -7949,6 +7960,7 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, + + int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu) + { ++ vcpu->arch.arch_capabilities = kvm_get_arch_capabilities(); + vcpu->arch.msr_platform_info = MSR_PLATFORM_INFO_CPUID_FAULT; + kvm_vcpu_mtrr_init(vcpu); + vcpu_load(vcpu);