Message ID | 20210521102449.21505-8-ilstam@amazon.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | KVM: Implement nested TSC scaling | expand |
On Fri, 2021-05-21 at 11:24 +0100, Ilias Stamatis wrote: > 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@amazon.com> > --- > arch/x86/include/asm/kvm_host.h | 2 ++ > arch/x86/kvm/x86.c | 25 +++++++++++++++++++++++++ > 2 files changed, 27 insertions(+) > > diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h > index 0f2cf5d1240c..aaf756442ed1 100644 > --- a/arch/x86/include/asm/kvm_host.h > +++ b/arch/x86/include/asm/kvm_host.h > @@ -1792,6 +1792,8 @@ static inline bool kvm_is_supported_user_return_msr(u32 msr) > > u64 kvm_scale_tsc(struct kvm_vcpu *vcpu, u64 tsc, u64 ratio); > u64 kvm_read_l1_tsc(struct kvm_vcpu *vcpu, u64 host_tsc); > +u64 kvm_calc_nested_tsc_offset(u64 l1_offset, u64 l2_offset, u64 l2_multiplier); > +u64 kvm_calc_nested_tsc_multiplier(u64 l1_multiplier, u64 l2_multiplier); > > 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 fdcb4f46a003..04abaacb9cfc 100644 > --- a/arch/x86/kvm/x86.c > +++ b/arch/x86/kvm/x86.c > @@ -2334,6 +2334,31 @@ u64 kvm_read_l1_tsc(struct kvm_vcpu *vcpu, u64 host_tsc) > } > EXPORT_SYMBOL_GPL(kvm_read_l1_tsc); > > +u64 kvm_calc_nested_tsc_offset(u64 l1_offset, u64 l2_offset, u64 l2_multiplier) > +{ > + u64 nested_offset; > + > + if (l2_multiplier == kvm_default_tsc_scaling_ratio) > + nested_offset = l1_offset; > + else > + nested_offset = mul_s64_u64_shr((s64) l1_offset, l2_multiplier, > + kvm_tsc_scaling_ratio_frac_bits); > + > + nested_offset += l2_offset; > + return nested_offset; > +} > +EXPORT_SYMBOL_GPL(kvm_calc_nested_tsc_offset); Looks OK. > + > +u64 kvm_calc_nested_tsc_multiplier(u64 l1_multiplier, u64 l2_multiplier) > +{ > + if (l2_multiplier != kvm_default_tsc_scaling_ratio) > + return mul_u64_u64_shr(l1_multiplier, l2_multiplier, > + kvm_tsc_scaling_ratio_frac_bits); > + > + return l1_multiplier; > +} > +EXPORT_SYMBOL_GPL(kvm_calc_nested_tsc_multiplier); Looks OK as well. > + > static void kvm_vcpu_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset) > { > vcpu->arch.l1_tsc_offset = offset; Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com> Best regards, Maxim Levitsky
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 0f2cf5d1240c..aaf756442ed1 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1792,6 +1792,8 @@ static inline bool kvm_is_supported_user_return_msr(u32 msr) u64 kvm_scale_tsc(struct kvm_vcpu *vcpu, u64 tsc, u64 ratio); u64 kvm_read_l1_tsc(struct kvm_vcpu *vcpu, u64 host_tsc); +u64 kvm_calc_nested_tsc_offset(u64 l1_offset, u64 l2_offset, u64 l2_multiplier); +u64 kvm_calc_nested_tsc_multiplier(u64 l1_multiplier, u64 l2_multiplier); 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 fdcb4f46a003..04abaacb9cfc 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2334,6 +2334,31 @@ u64 kvm_read_l1_tsc(struct kvm_vcpu *vcpu, u64 host_tsc) } EXPORT_SYMBOL_GPL(kvm_read_l1_tsc); +u64 kvm_calc_nested_tsc_offset(u64 l1_offset, u64 l2_offset, u64 l2_multiplier) +{ + u64 nested_offset; + + if (l2_multiplier == kvm_default_tsc_scaling_ratio) + nested_offset = l1_offset; + else + nested_offset = mul_s64_u64_shr((s64) l1_offset, l2_multiplier, + kvm_tsc_scaling_ratio_frac_bits); + + nested_offset += l2_offset; + return nested_offset; +} +EXPORT_SYMBOL_GPL(kvm_calc_nested_tsc_offset); + +u64 kvm_calc_nested_tsc_multiplier(u64 l1_multiplier, u64 l2_multiplier) +{ + if (l2_multiplier != kvm_default_tsc_scaling_ratio) + return mul_u64_u64_shr(l1_multiplier, l2_multiplier, + kvm_tsc_scaling_ratio_frac_bits); + + return l1_multiplier; +} +EXPORT_SYMBOL_GPL(kvm_calc_nested_tsc_multiplier); + static void kvm_vcpu_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset) { vcpu->arch.l1_tsc_offset = offset;
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@amazon.com> --- arch/x86/include/asm/kvm_host.h | 2 ++ arch/x86/kvm/x86.c | 25 +++++++++++++++++++++++++ 2 files changed, 27 insertions(+)