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.
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 | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index fc9366b83912..8aae22401046 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2588,11 +2588,21 @@ static int kvm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz) static u64 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.54.0

