Re: [PATCH v6 15/36] KVM: x86: Fix compute_guest_tsc() to handle negative time deltas

From: Sean Christopherson

Date: Fri Jul 24 2026 - 17:27:14 EST


On Fri, Jul 03, 2026, David Woodhouse wrote:
> From: David Woodhouse <dwmw@xxxxxxxxxxxx>
>
> 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.

Does this need

Cc: stable@xxxxxxxxxxxxxxx

or is this a "technically a bug fix, but can't happen in practice" sort of thing?

>
> Signed-off-by: David Woodhouse <dwmw@xxxxxxxxxxxx>
> ---
> 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 376b8dc2ade9..55fb19fb7a88 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;

To cut down on the duplicate code, and IMO to make it easier to identify the
differences, how about this?

s64 delta_ns = kernel_ns - vcpu->arch.this_tsc_nsec;
u64 tsc;

/* Handle negative deltas gracefully (master clock ref may be earlier) */
tsc = pvclock_scale_delta(abs(-delta_ns),
vcpu->arch.virtual_tsc_mult,
vcpu->arch.virtual_tsc_shift);

return vcpu->arch.this_tsc_write + (delta_ns >= 0 ? tsc : -tsc);