Skip to content

Commit 11d39e8

Browse files
Maxim Levitskybonzini
authored andcommitted
KVM: SVM: fix tsc scaling cache logic
SVM uses a per-cpu variable to cache the current value of the tsc scaling multiplier msr on each cpu. Commit 1ab9287 ("KVM: X86: Add vendor callbacks for writing the TSC multiplier") broke this caching logic. Refactor the code so that all TSC scaling multiplier writes go through a single function which checks and updates the cache. This fixes the following scenario: 1. A CPU runs a guest with some tsc scaling ratio. 2. New guest with different tsc scaling ratio starts on this CPU and terminates almost immediately. This ensures that the short running guest had set the tsc scaling ratio just once when it was set via KVM_SET_TSC_KHZ. Due to the bug, the per-cpu cache is not updated. 3. The original guest continues to run, it doesn't restore the msr value back to its own value, because the cache matches, and thus continues to run with a wrong tsc scaling ratio. Fixes: 1ab9287 ("KVM: X86: Add vendor callbacks for writing the TSC multiplier") Signed-off-by: Maxim Levitsky <[email protected]> Message-Id: <[email protected]> Cc: [email protected] Signed-off-by: Paolo Bonzini <[email protected]>
1 parent eae260b commit 11d39e8

File tree

3 files changed

+23
-15
lines changed

3 files changed

+23
-15
lines changed

arch/x86/kvm/svm/nested.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -982,7 +982,7 @@ int nested_svm_vmexit(struct vcpu_svm *svm)
982982
if (svm->tsc_ratio_msr != kvm_default_tsc_scaling_ratio) {
983983
WARN_ON(!svm->tsc_scaling_enabled);
984984
vcpu->arch.tsc_scaling_ratio = vcpu->arch.l1_tsc_scaling_ratio;
985-
svm_write_tsc_multiplier(vcpu, vcpu->arch.tsc_scaling_ratio);
985+
__svm_write_tsc_multiplier(vcpu->arch.tsc_scaling_ratio);
986986
}
987987

988988
svm->nested.ctl.nested_cr3 = 0;
@@ -1387,7 +1387,7 @@ void nested_svm_update_tsc_ratio_msr(struct kvm_vcpu *vcpu)
13871387
vcpu->arch.tsc_scaling_ratio =
13881388
kvm_calc_nested_tsc_multiplier(vcpu->arch.l1_tsc_scaling_ratio,
13891389
svm->tsc_ratio_msr);
1390-
svm_write_tsc_multiplier(vcpu, vcpu->arch.tsc_scaling_ratio);
1390+
__svm_write_tsc_multiplier(vcpu->arch.tsc_scaling_ratio);
13911391
}
13921392

13931393
/* Inverse operation of nested_copy_vmcb_control_to_cache(). asid is copied too. */

arch/x86/kvm/svm/svm.c

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -465,11 +465,24 @@ static int has_svm(void)
465465
return 1;
466466
}
467467

468+
void __svm_write_tsc_multiplier(u64 multiplier)
469+
{
470+
preempt_disable();
471+
472+
if (multiplier == __this_cpu_read(current_tsc_ratio))
473+
goto out;
474+
475+
wrmsrl(MSR_AMD64_TSC_RATIO, multiplier);
476+
__this_cpu_write(current_tsc_ratio, multiplier);
477+
out:
478+
preempt_enable();
479+
}
480+
468481
static void svm_hardware_disable(void)
469482
{
470483
/* Make sure we clean up behind us */
471484
if (tsc_scaling)
472-
wrmsrl(MSR_AMD64_TSC_RATIO, SVM_TSC_RATIO_DEFAULT);
485+
__svm_write_tsc_multiplier(SVM_TSC_RATIO_DEFAULT);
473486

474487
cpu_svm_disable();
475488

@@ -515,8 +528,7 @@ static int svm_hardware_enable(void)
515528
* Set the default value, even if we don't use TSC scaling
516529
* to avoid having stale value in the msr
517530
*/
518-
wrmsrl(MSR_AMD64_TSC_RATIO, SVM_TSC_RATIO_DEFAULT);
519-
__this_cpu_write(current_tsc_ratio, SVM_TSC_RATIO_DEFAULT);
531+
__svm_write_tsc_multiplier(SVM_TSC_RATIO_DEFAULT);
520532
}
521533

522534

@@ -999,11 +1011,12 @@ static void svm_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset)
9991011
vmcb_mark_dirty(svm->vmcb, VMCB_INTERCEPTS);
10001012
}
10011013

1002-
void svm_write_tsc_multiplier(struct kvm_vcpu *vcpu, u64 multiplier)
1014+
static void svm_write_tsc_multiplier(struct kvm_vcpu *vcpu, u64 multiplier)
10031015
{
1004-
wrmsrl(MSR_AMD64_TSC_RATIO, multiplier);
1016+
__svm_write_tsc_multiplier(multiplier);
10051017
}
10061018

1019+
10071020
/* Evaluate instruction intercepts that depend on guest CPUID features. */
10081021
static void svm_recalc_instruction_intercepts(struct kvm_vcpu *vcpu,
10091022
struct vcpu_svm *svm)
@@ -1363,13 +1376,8 @@ static void svm_prepare_switch_to_guest(struct kvm_vcpu *vcpu)
13631376
sev_es_prepare_switch_to_guest(hostsa);
13641377
}
13651378

1366-
if (tsc_scaling) {
1367-
u64 tsc_ratio = vcpu->arch.tsc_scaling_ratio;
1368-
if (tsc_ratio != __this_cpu_read(current_tsc_ratio)) {
1369-
__this_cpu_write(current_tsc_ratio, tsc_ratio);
1370-
wrmsrl(MSR_AMD64_TSC_RATIO, tsc_ratio);
1371-
}
1372-
}
1379+
if (tsc_scaling)
1380+
__svm_write_tsc_multiplier(vcpu->arch.tsc_scaling_ratio);
13731381

13741382
if (likely(tsc_aux_uret_slot >= 0))
13751383
kvm_set_user_return_msr(tsc_aux_uret_slot, svm->tsc_aux, -1ull);

arch/x86/kvm/svm/svm.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -590,7 +590,7 @@ int nested_svm_check_exception(struct vcpu_svm *svm, unsigned nr,
590590
bool has_error_code, u32 error_code);
591591
int nested_svm_exit_special(struct vcpu_svm *svm);
592592
void nested_svm_update_tsc_ratio_msr(struct kvm_vcpu *vcpu);
593-
void svm_write_tsc_multiplier(struct kvm_vcpu *vcpu, u64 multiplier);
593+
void __svm_write_tsc_multiplier(u64 multiplier);
594594
void nested_copy_vmcb_control_to_cache(struct vcpu_svm *svm,
595595
struct vmcb_control_area *control);
596596
void nested_copy_vmcb_save_to_cache(struct vcpu_svm *svm,

0 commit comments

Comments
 (0)