summaryrefslogtreecommitdiffstats
path: root/arch/x86
diff options
context:
space:
mode:
authorKarimAllah Ahmed <karahmed@amazon.de>2018-02-03 09:56:23 -0500
committerThomas Gleixner <tglx@linutronix.de>2018-02-03 17:06:52 -0500
commitb2ac58f90540e39324e7a29a7ad471407ae0bf48 (patch)
treeb9c902f1141226f16d24c30e0fd808f2b95c698d /arch/x86
parentd28b387fb74da95d69d2615732f50cceb38e9a4d (diff)
KVM/SVM: Allow direct access to MSR_IA32_SPEC_CTRL
[ Based on a patch from Paolo Bonzini <pbonzini@redhat.com> ] ... basically doing exactly what we do for VMX: - Passthrough SPEC_CTRL to guests (if enabled in guest CPUID) - Save and restore SPEC_CTRL around VMExit and VMEntry only if the guest actually used it. Signed-off-by: KarimAllah Ahmed <karahmed@amazon.de> Signed-off-by: David Woodhouse <dwmw@amazon.co.uk> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Darren Kenny <darren.kenny@oracle.com> Reviewed-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> Cc: Andrea Arcangeli <aarcange@redhat.com> Cc: Andi Kleen <ak@linux.intel.com> Cc: Jun Nakajima <jun.nakajima@intel.com> Cc: kvm@vger.kernel.org Cc: Dave Hansen <dave.hansen@intel.com> Cc: Tim Chen <tim.c.chen@linux.intel.com> Cc: Andy Lutomirski <luto@kernel.org> Cc: Asit Mallick <asit.k.mallick@intel.com> Cc: Arjan Van De Ven <arjan.van.de.ven@intel.com> Cc: Greg KH <gregkh@linuxfoundation.org> Cc: Paolo Bonzini <pbonzini@redhat.com> Cc: Dan Williams <dan.j.williams@intel.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Ashok Raj <ashok.raj@intel.com> Link: https://lkml.kernel.org/r/1517669783-20732-1-git-send-email-karahmed@amazon.de
Diffstat (limited to 'arch/x86')
-rw-r--r--arch/x86/kvm/svm.c88
1 files changed, 88 insertions, 0 deletions
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 254eefb3b57f..4e3c79530526 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -184,6 +184,8 @@ struct vcpu_svm {
184 u64 gs_base; 184 u64 gs_base;
185 } host; 185 } host;
186 186
187 u64 spec_ctrl;
188
187 u32 *msrpm; 189 u32 *msrpm;
188 190
189 ulong nmi_iret_rip; 191 ulong nmi_iret_rip;
@@ -249,6 +251,7 @@ static const struct svm_direct_access_msrs {
249 { .index = MSR_CSTAR, .always = true }, 251 { .index = MSR_CSTAR, .always = true },
250 { .index = MSR_SYSCALL_MASK, .always = true }, 252 { .index = MSR_SYSCALL_MASK, .always = true },
251#endif 253#endif
254 { .index = MSR_IA32_SPEC_CTRL, .always = false },
252 { .index = MSR_IA32_PRED_CMD, .always = false }, 255 { .index = MSR_IA32_PRED_CMD, .always = false },
253 { .index = MSR_IA32_LASTBRANCHFROMIP, .always = false }, 256 { .index = MSR_IA32_LASTBRANCHFROMIP, .always = false },
254 { .index = MSR_IA32_LASTBRANCHTOIP, .always = false }, 257 { .index = MSR_IA32_LASTBRANCHTOIP, .always = false },
@@ -882,6 +885,25 @@ static bool valid_msr_intercept(u32 index)
882 return false; 885 return false;
883} 886}
884 887
888static bool msr_write_intercepted(struct kvm_vcpu *vcpu, unsigned msr)
889{
890 u8 bit_write;
891 unsigned long tmp;
892 u32 offset;
893 u32 *msrpm;
894
895 msrpm = is_guest_mode(vcpu) ? to_svm(vcpu)->nested.msrpm:
896 to_svm(vcpu)->msrpm;
897
898 offset = svm_msrpm_offset(msr);
899 bit_write = 2 * (msr & 0x0f) + 1;
900 tmp = msrpm[offset];
901
902 BUG_ON(offset == MSR_INVALID);
903
904 return !!test_bit(bit_write, &tmp);
905}
906
885static void set_msr_interception(u32 *msrpm, unsigned msr, 907static void set_msr_interception(u32 *msrpm, unsigned msr,
886 int read, int write) 908 int read, int write)
887{ 909{
@@ -1584,6 +1606,8 @@ static void svm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
1584 u32 dummy; 1606 u32 dummy;
1585 u32 eax = 1; 1607 u32 eax = 1;
1586 1608
1609 svm->spec_ctrl = 0;
1610
1587 if (!init_event) { 1611 if (!init_event) {
1588 svm->vcpu.arch.apic_base = APIC_DEFAULT_PHYS_BASE | 1612 svm->vcpu.arch.apic_base = APIC_DEFAULT_PHYS_BASE |
1589 MSR_IA32_APICBASE_ENABLE; 1613 MSR_IA32_APICBASE_ENABLE;
@@ -3605,6 +3629,13 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
3605 case MSR_VM_CR: 3629 case MSR_VM_CR:
3606 msr_info->data = svm->nested.vm_cr_msr; 3630 msr_info->data = svm->nested.vm_cr_msr;
3607 break; 3631 break;
3632 case MSR_IA32_SPEC_CTRL:
3633 if (!msr_info->host_initiated &&
3634 !guest_cpuid_has(vcpu, X86_FEATURE_IBRS))
3635 return 1;
3636
3637 msr_info->data = svm->spec_ctrl;
3638 break;
3608 case MSR_IA32_UCODE_REV: 3639 case MSR_IA32_UCODE_REV:
3609 msr_info->data = 0x01000065; 3640 msr_info->data = 0x01000065;
3610 break; 3641 break;
@@ -3696,6 +3727,33 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr)
3696 case MSR_IA32_TSC: 3727 case MSR_IA32_TSC:
3697 kvm_write_tsc(vcpu, msr); 3728 kvm_write_tsc(vcpu, msr);
3698 break; 3729 break;
3730 case MSR_IA32_SPEC_CTRL:
3731 if (!msr->host_initiated &&
3732 !guest_cpuid_has(vcpu, X86_FEATURE_IBRS))
3733 return 1;
3734
3735 /* The STIBP bit doesn't fault even if it's not advertised */
3736 if (data & ~(SPEC_CTRL_IBRS | SPEC_CTRL_STIBP))
3737 return 1;
3738
3739 svm->spec_ctrl = data;
3740
3741 if (!data)
3742 break;
3743
3744 /*
3745 * For non-nested:
3746 * When it's written (to non-zero) for the first time, pass
3747 * it through.
3748 *
3749 * For nested:
3750 * The handling of the MSR bitmap for L2 guests is done in
3751 * nested_svm_vmrun_msrpm.
3752 * We update the L1 MSR bit as well since it will end up
3753 * touching the MSR anyway now.
3754 */
3755 set_msr_interception(svm->msrpm, MSR_IA32_SPEC_CTRL, 1, 1);
3756 break;
3699 case MSR_IA32_PRED_CMD: 3757 case MSR_IA32_PRED_CMD:
3700 if (!msr->host_initiated && 3758 if (!msr->host_initiated &&
3701 !guest_cpuid_has(vcpu, X86_FEATURE_IBPB)) 3759 !guest_cpuid_has(vcpu, X86_FEATURE_IBPB))
@@ -4964,6 +5022,15 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu)
4964 5022
4965 local_irq_enable(); 5023 local_irq_enable();
4966 5024
5025 /*
5026 * If this vCPU has touched SPEC_CTRL, restore the guest's value if
5027 * it's non-zero. Since vmentry is serialising on affected CPUs, there
5028 * is no need to worry about the conditional branch over the wrmsr
5029 * being speculatively taken.
5030 */
5031 if (svm->spec_ctrl)
5032 wrmsrl(MSR_IA32_SPEC_CTRL, svm->spec_ctrl);
5033
4967 asm volatile ( 5034 asm volatile (
4968 "push %%" _ASM_BP "; \n\t" 5035 "push %%" _ASM_BP "; \n\t"
4969 "mov %c[rbx](%[svm]), %%" _ASM_BX " \n\t" 5036 "mov %c[rbx](%[svm]), %%" _ASM_BX " \n\t"
@@ -5056,6 +5123,27 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu)
5056#endif 5123#endif
5057 ); 5124 );
5058 5125
5126 /*
5127 * We do not use IBRS in the kernel. If this vCPU has used the
5128 * SPEC_CTRL MSR it may have left it on; save the value and
5129 * turn it off. This is much more efficient than blindly adding
5130 * it to the atomic save/restore list. Especially as the former
5131 * (Saving guest MSRs on vmexit) doesn't even exist in KVM.
5132 *
5133 * For non-nested case:
5134 * If the L01 MSR bitmap does not intercept the MSR, then we need to
5135 * save it.
5136 *
5137 * For nested case:
5138 * If the L02 MSR bitmap does not intercept the MSR, then we need to
5139 * save it.
5140 */
5141 if (!msr_write_intercepted(vcpu, MSR_IA32_SPEC_CTRL))
5142 rdmsrl(MSR_IA32_SPEC_CTRL, svm->spec_ctrl);
5143
5144 if (svm->spec_ctrl)
5145 wrmsrl(MSR_IA32_SPEC_CTRL, 0);
5146
5059 /* Eliminate branch target predictions from guest mode */ 5147 /* Eliminate branch target predictions from guest mode */
5060 vmexit_fill_RSB(); 5148 vmexit_fill_RSB();
5061 5149