diff options
author | KarimAllah Ahmed <karahmed@amazon.de> | 2018-02-03 09:56:23 -0500 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2018-02-03 17:06:52 -0500 |
commit | b2ac58f90540e39324e7a29a7ad471407ae0bf48 (patch) | |
tree | b9c902f1141226f16d24c30e0fd808f2b95c698d /arch/x86 | |
parent | d28b387fb74da95d69d2615732f50cceb38e9a4d (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.c | 88 |
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 | ||
888 | static 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 | |||
885 | static void set_msr_interception(u32 *msrpm, unsigned msr, | 907 | static 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 | ||