]>
Commit | Line | Data |
---|---|---|
198fde3a FE |
1 | From 955c2b4d64593baecc87c64d1354cd5786975bd9 Mon Sep 17 00:00:00 2001 |
2 | From: Maxim Levitsky <mlevitsk@redhat.com> | |
3 | Date: Mon, 6 Jun 2022 21:11:49 +0300 | |
4 | Subject: [PATCH] KVM: SVM: fix tsc scaling cache logic | |
5 | ||
6 | SVM uses a per-cpu variable to cache the current value of the | |
7 | tsc scaling multiplier msr on each cpu. | |
8 | ||
9 | Commit 1ab9287add5e2 | |
10 | ("KVM: X86: Add vendor callbacks for writing the TSC multiplier") | |
11 | broke this caching logic. | |
12 | ||
13 | Refactor the code so that all TSC scaling multiplier writes go through | |
14 | a single function which checks and updates the cache. | |
15 | ||
16 | This fixes the following scenario: | |
17 | ||
18 | 1. A CPU runs a guest with some tsc scaling ratio. | |
19 | ||
20 | 2. New guest with different tsc scaling ratio starts on this CPU | |
21 | and terminates almost immediately. | |
22 | ||
23 | This ensures that the short running guest had set the tsc scaling ratio just | |
24 | once when it was set via KVM_SET_TSC_KHZ. Due to the bug, | |
25 | the per-cpu cache is not updated. | |
26 | ||
27 | 3. The original guest continues to run, it doesn't restore the msr | |
28 | value back to its own value, because the cache matches, | |
29 | and thus continues to run with a wrong tsc scaling ratio. | |
30 | ||
31 | Fixes: 1ab9287add5e2 ("KVM: X86: Add vendor callbacks for writing the TSC multiplier") | |
32 | Signed-off-by: Maxim Levitsky <mlevitsk@redhat.com> | |
33 | Message-Id: <20220606181149.103072-1-mlevitsk@redhat.com> | |
34 | Cc: stable@vger.kernel.org | |
35 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> | |
36 | [FE: backport, mainly dropped parts for the not yet present | |
37 | 5228eb96a487 ("KVM: x86: nSVM: implement nested TSC scaling")] | |
38 | Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | |
39 | --- | |
40 | arch/x86/kvm/svm/svm.c | 30 +++++++++++++++++++----------- | |
41 | 1 file changed, 19 insertions(+), 11 deletions(-) | |
42 | ||
43 | diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c | |
44 | index 938b9b24f0ee..ea87d06bdaba 100644 | |
45 | --- a/arch/x86/kvm/svm/svm.c | |
46 | +++ b/arch/x86/kvm/svm/svm.c | |
47 | @@ -468,11 +468,24 @@ static int has_svm(void) | |
48 | return 1; | |
49 | } | |
50 | ||
51 | +void __svm_write_tsc_multiplier(u64 multiplier) | |
52 | +{ | |
53 | + preempt_disable(); | |
54 | + | |
55 | + if (multiplier == __this_cpu_read(current_tsc_ratio)) | |
56 | + goto out; | |
57 | + | |
58 | + wrmsrl(MSR_AMD64_TSC_RATIO, multiplier); | |
59 | + __this_cpu_write(current_tsc_ratio, multiplier); | |
60 | +out: | |
61 | + preempt_enable(); | |
62 | +} | |
63 | + | |
64 | static void svm_hardware_disable(void) | |
65 | { | |
66 | /* Make sure we clean up behind us */ | |
67 | if (static_cpu_has(X86_FEATURE_TSCRATEMSR)) | |
68 | - wrmsrl(MSR_AMD64_TSC_RATIO, TSC_RATIO_DEFAULT); | |
69 | + __svm_write_tsc_multiplier(TSC_RATIO_DEFAULT); | |
70 | ||
71 | cpu_svm_disable(); | |
72 | ||
73 | @@ -514,8 +527,7 @@ static int svm_hardware_enable(void) | |
74 | wrmsrl(MSR_VM_HSAVE_PA, __sme_page_pa(sd->save_area)); | |
75 | ||
76 | if (static_cpu_has(X86_FEATURE_TSCRATEMSR)) { | |
77 | - wrmsrl(MSR_AMD64_TSC_RATIO, TSC_RATIO_DEFAULT); | |
78 | - __this_cpu_write(current_tsc_ratio, TSC_RATIO_DEFAULT); | |
79 | + __svm_write_tsc_multiplier(TSC_RATIO_DEFAULT); | |
80 | } | |
81 | ||
82 | ||
83 | @@ -1128,9 +1140,10 @@ static void svm_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset) | |
84 | ||
85 | static void svm_write_tsc_multiplier(struct kvm_vcpu *vcpu, u64 multiplier) | |
86 | { | |
87 | - wrmsrl(MSR_AMD64_TSC_RATIO, multiplier); | |
88 | + __svm_write_tsc_multiplier(multiplier); | |
89 | } | |
90 | ||
91 | + | |
92 | /* Evaluate instruction intercepts that depend on guest CPUID features. */ | |
93 | static void svm_recalc_instruction_intercepts(struct kvm_vcpu *vcpu, | |
94 | struct vcpu_svm *svm) | |
95 | @@ -1453,13 +1466,8 @@ static void svm_prepare_guest_switch(struct kvm_vcpu *vcpu) | |
96 | vmsave(__sme_page_pa(sd->save_area)); | |
97 | } | |
98 | ||
99 | - if (static_cpu_has(X86_FEATURE_TSCRATEMSR)) { | |
100 | - u64 tsc_ratio = vcpu->arch.tsc_scaling_ratio; | |
101 | - if (tsc_ratio != __this_cpu_read(current_tsc_ratio)) { | |
102 | - __this_cpu_write(current_tsc_ratio, tsc_ratio); | |
103 | - wrmsrl(MSR_AMD64_TSC_RATIO, tsc_ratio); | |
104 | - } | |
105 | - } | |
106 | + if (static_cpu_has(X86_FEATURE_TSCRATEMSR)) | |
107 | + __svm_write_tsc_multiplier(vcpu->arch.tsc_scaling_ratio); | |
108 | ||
109 | if (likely(tsc_aux_uret_slot >= 0)) | |
110 | kvm_set_user_return_msr(tsc_aux_uret_slot, svm->tsc_aux, -1ull); | |
111 | -- | |
112 | 2.30.2 | |
113 |