From: David Woodhouse <[email protected]> The compute_guest_tsc() function computes the guest TSC at a given kernel_ns timestamp. When the master clock reference point (master_kernel_ns) is earlier than vcpu->arch.this_tsc_nsec, the delta is negative. Since pvclock_scale_delta() takes a u64, the negative value wraps to a huge positive number, producing a wildly wrong result.
Change the return type to s64 and handle negative deltas explicitly by negating the delta, scaling it, and subtracting from this_tsc_write. Signed-off-by: David Woodhouse <[email protected]> --- arch/x86/kvm/x86.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 2bbc2c7ac449..e281c49561fa 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2586,13 +2586,23 @@ static int kvm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz) return set_tsc_khz(vcpu, user_tsc_khz, use_scaling); } -static u64 compute_guest_tsc(struct kvm_vcpu *vcpu, s64 kernel_ns) +static s64 compute_guest_tsc(struct kvm_vcpu *vcpu, s64 kernel_ns) { - u64 tsc = pvclock_scale_delta(kernel_ns-vcpu->arch.this_tsc_nsec, - vcpu->arch.virtual_tsc_mult, - vcpu->arch.virtual_tsc_shift); - tsc += vcpu->arch.this_tsc_write; - return tsc; + s64 delta_ns = kernel_ns - vcpu->arch.this_tsc_nsec; + u64 tsc; + + /* Handle negative deltas gracefully (master clock ref may be earlier) */ + if (delta_ns < 0) { + tsc = pvclock_scale_delta(-delta_ns, + vcpu->arch.virtual_tsc_mult, + vcpu->arch.virtual_tsc_shift); + return vcpu->arch.this_tsc_write - tsc; + } + + tsc = pvclock_scale_delta(delta_ns, + vcpu->arch.virtual_tsc_mult, + vcpu->arch.virtual_tsc_shift); + return vcpu->arch.this_tsc_write + tsc; } #ifdef CONFIG_X86_64 -- 2.51.0

