When L2 is entered we need to "merge" the TSC multiplier and TSC offset values of 01 and 12 together. The merging is done using the following equations: offset_02 = ((offset_01 * mult_12) >> shift_bits) + offset_12 mult_02 = (mult_01 * mult_12) >> shift_bits Where shift_bits is kvm_tsc_scaling_ratio_frac_bits. Signed-off-by: Ilias Stamatis <ilstam@xxxxxxxxxx> --- arch/x86/include/asm/kvm_host.h | 2 ++ arch/x86/kvm/x86.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 4c4a3fefff57..57a25d8e8b0f 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1793,6 +1793,8 @@ static inline bool kvm_is_supported_user_return_msr(u32 msr) u64 kvm_scale_tsc(struct kvm_vcpu *vcpu, u64 tsc); u64 kvm_scale_tsc_l1(struct kvm_vcpu *vcpu, u64 tsc); u64 kvm_read_l1_tsc(struct kvm_vcpu *vcpu, u64 host_tsc); +void kvm_set_02_tsc_offset(struct kvm_vcpu *vcpu); +void kvm_set_02_tsc_multiplier(struct kvm_vcpu *vcpu); unsigned long kvm_get_linear_rip(struct kvm_vcpu *vcpu); bool kvm_is_linear_rip(struct kvm_vcpu *vcpu, unsigned long linear_rip); diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 84af1af7a2cc..1db6cfc2079f 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2346,6 +2346,35 @@ u64 kvm_read_l1_tsc(struct kvm_vcpu *vcpu, u64 host_tsc) } EXPORT_SYMBOL_GPL(kvm_read_l1_tsc); +void kvm_set_02_tsc_offset(struct kvm_vcpu *vcpu) +{ + u64 l2_offset = static_call(kvm_x86_get_l2_tsc_offset)(vcpu); + u64 l2_multiplier = static_call(kvm_x86_get_l2_tsc_multiplier)(vcpu); + + if (l2_multiplier != kvm_default_tsc_scaling_ratio) { + vcpu->arch.tsc_offset = mul_s64_u64_shr( + (s64) vcpu->arch.l1_tsc_offset, + l2_multiplier, + kvm_tsc_scaling_ratio_frac_bits); + } + + vcpu->arch.tsc_offset += l2_offset; +} +EXPORT_SYMBOL_GPL(kvm_set_02_tsc_offset); + +void kvm_set_02_tsc_multiplier(struct kvm_vcpu *vcpu) +{ + u64 l2_multiplier = static_call(kvm_x86_get_l2_tsc_multiplier)(vcpu); + + if (l2_multiplier != kvm_default_tsc_scaling_ratio) { + vcpu->arch.tsc_scaling_ratio = mul_u64_u64_shr( + vcpu->arch.l1_tsc_scaling_ratio, + l2_multiplier, + kvm_tsc_scaling_ratio_frac_bits); + } +} +EXPORT_SYMBOL_GPL(kvm_set_02_tsc_multiplier); + static void kvm_vcpu_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset) { vcpu->arch.l1_tsc_offset = offset; -- 2.17.1