From nobody Mon Aug 24 09:10:08 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) client-ip=192.237.175.120; envelope-from=xen-devel-bounces@lists.xenproject.org; helo=lists.xenproject.org; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=pass(p=none dis=none) header.from=infradead.org ARC-Seal: i=1; a=rsa-sha256; t=1783113837; cv=none; d=zohomail.com; s=zohoarc; b=Y/WXrJNDaoV5lyzy4jMdYJroMVRWduGgMl5ufSifTwP17w9cH+kAbTtL83KZU89tSeXx4VMWJ93le52eX9PZ+toYKQ0lYHe3xS/zGcFT9GD6P4aYd8z1K6ERJ7vQ9sETnpJSrY5Csc4ynZ6mtSpupWFl3PzbZUnnnpNa424c/ZA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1783113837; h=Content-Transfer-Encoding:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To:Cc; bh=GJgji+5kC3YzYVHStlFYRgwhsr0ZfLQx7Fpf6sFlDAA=; b=HJ/A976sCzcfLrq+s78dDNrL2Q8NEvuKZlBSqPvi5ftcX6PWvcfMUyyTJpyv7J3+vVkMdfznH72CSXXQtCYQAPYMDZL+UKA3QUgKy89WzxI9OCwa7D/51cmWE7ZHGKzP2Bk/SkeAveWci+XsTEFZHEKEU6KZRWkSO4HKiLFEw90= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1783113836975536.2886301519399; Fri, 3 Jul 2026 14:23:56 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.1353882.1609627 (Exim 4.92) (envelope-from ) id 1wflMM-0005h2-Lm; Fri, 03 Jul 2026 21:23:42 +0000 Received: by outflank-mailman (output) from mailman id 1353882.1609627; Fri, 03 Jul 2026 21:23:42 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflMM-0005gl-IC; Fri, 03 Jul 2026 21:23:42 +0000 Received: by outflank-mailman (input) for mailman id 1353882; Fri, 03 Jul 2026 21:23:41 +0000 Received: from mx.expurgate.net ([195.190.135.10]) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflML-0005et-F3 for xen-devel@lists.xenproject.org; Fri, 03 Jul 2026 21:23:41 +0000 Received: from mx.expurgate.net (helo=localhost) by mx.expurgate.net with esmtp id 1wflMK-001XO6-S9; Fri, 03 Jul 2026 23:23:40 +0200 Received: from [10.42.69.10] (helo=localhost) by localhost with ESMTP (eXpurgate MTA 0.9.1) (envelope-from ) id 6a48282a-5cb7-0a2a0a5109dd-0a2a450aa8e8-22 for ; Fri, 03 Jul 2026 23:23:40 +0200 Received: from [90.155.92.199] (helo=desiato.infradead.org) by tlsNG-4011c0.mxtls.expurgate.net with ESMTPS (eXpurgate 4.57.1) (envelope-from ) id 6a48285c-e40e-0a2a450a0019-5a9b5cc7db7c-3 for ; Fri, 03 Jul 2026 23:23:40 +0200 Received: from [2001:8b0:10b:1::425] (helo=i7.infradead.org) by desiato.infradead.org with esmtpsa (Exim 4.99.2 #2 (Red Hat Linux)) id 1wflKd-000000059O1-3OLf; Fri, 03 Jul 2026 21:23:26 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.99.2 #2 (Red Hat Linux)) id 1wflKW-00000001ROd-1uel; Fri, 03 Jul 2026 22:21:48 +0100 X-Outflank-Mailman: Message body and most headers restored to incoming version X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Authentication-Results: eu.smtp.expurgate.cloud; dkim=pass header.s=desiato.20200630 header.d=infradead.org header.i="@infradead.org" header.h="Sender:Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:To:From" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=desiato.20200630; h=Sender:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:To:From:Reply-To: Cc:Content-Type:Content-ID:Content-Description; bh=GJgji+5kC3YzYVHStlFYRgwhsr0ZfLQx7Fpf6sFlDAA=; b=aNaMFKhduCWNdatfzzJJHFUyeo Rv0SPwZDALsXDKwMgu8TapnCKqex3QPVj6TX+zcg6JTU+v1auSQB/Dm++Fne6Kd6/Xsd1WpTAh66p +Jw+sbONjIBR0Ucx+tpPYaoTJ+irYWQyCueZjPBZL8ujVdf7l3w9ZfCHuqaOz3JKseBAeiAyDV+7D ZHZ8RHyxNJF0eyEn2u16sn8ppCB0vLGNANDCMEtR4E8moNuG3lTnO3T0FdJSxQh+iIg5dUgiofp4Q WdYXyTAa47+JwSUPFmx+SeUirPzgv2aPbC8gxMNw396yX7a6sSd6/7iF/f4W8/EB9/3wPty5xPA5/ oJ+JIJWg==; From: David Woodhouse To: Paolo Bonzini , Jonathan Corbet , Shuah Khan , Sean Christopherson , Thomas Gleixner , Ingo Molnar , Borislav Petkov , Dave Hansen , x86@kernel.org, "H. Peter Anvin" , Vitaly Kuznetsov , Juergen Gross , Boris Ostrovsky , David Woodhouse , Paul Durrant , Jonathan Cameron , Sascha Bischoff , Marc Zyngier , Joey Gouly , Jack Allister , Dongli Zhang , joe.jin@oracle.com, kvm@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, xen-devel@lists.xenproject.org, linux-kselftest@vger.kernel.org Subject: [PATCH v6 13/36] KVM: x86: Fix KVM clock precision in get_kvmclock() with TSC scaling Date: Fri, 3 Jul 2026 22:17:52 +0100 Message-ID: <20260703212145.343527-14-dwmw2@infradead.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260703212145.343527-1-dwmw2@infradead.org> References: <20260703212145.343527-1-dwmw2@infradead.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: David Woodhouse X-SRS-Rewrite: SMTP reverse-path rewritten from by desiato.infradead.org. See http://www.infradead.org/rpr.html X-purgate-ID: tlsNG-4011c0/1783113820-3D275DDE-6998DC17/0/0 X-purgate-type: clean X-purgate-size: 4620 X-ZohoMail-DKIM: pass (identity @infradead.org) X-ZM-MESSAGEID: 1783113838994158500 Content-Type: text/plain; charset="utf-8" From: David Woodhouse When in master clock mode, the KVM clock is defined in terms of the guest TSC. But get_kvmclock() was computing it from the host TSC without applying TSC scaling, leading to a systemic drift from the values the guest computes from its own TSC. Store the VM's TSC scaling ratio in kvm_arch and precompute the guest-TSC-based mul/shift in pvclock_update_vm_gtod_copy(). Use these in get_kvmclock() to scale the host TSC delta to guest TSC before converting to nanoseconds. This avoids "definition C" of the KVM clock described in the earlier commit "KVM: x86/xen: Do not corrupt KVM clock in kvm_xen_shared_info_init()". Signed-off-by: David Woodhouse --- arch/x86/include/asm/kvm_host.h | 4 +++ arch/x86/kvm/x86.c | 52 +++++++++++++++++++++++++++++---- 2 files changed, 51 insertions(+), 5 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_hos= t.h index b2446c04a076..87435ddecde1 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1490,6 +1490,7 @@ struct kvm_arch { u64 last_tsc_write; u32 last_tsc_khz; u64 last_tsc_offset; + u64 last_tsc_scaling_ratio; u64 cur_tsc_nsec; u64 cur_tsc_write; u64 cur_tsc_offset; @@ -1505,6 +1506,9 @@ struct kvm_arch { u64 master_kernel_ns; u64 master_cycle_now; struct ratelimit_state kvmclock_update_rs; + u64 master_tsc_scaling_ratio; + s8 master_tsc_shift; + u32 master_tsc_mul; =20 #ifdef CONFIG_KVM_HYPERV struct kvm_hv hyperv; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 37b1f8192842..65aa0fb0b5e1 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2781,6 +2781,7 @@ static void __kvm_synchronize_tsc(struct kvm_vcpu *vc= pu, u64 offset, u64 tsc, kvm->arch.last_tsc_write =3D tsc; kvm->arch.last_tsc_khz =3D vcpu->arch.virtual_tsc_khz; kvm->arch.last_tsc_offset =3D offset; + kvm->arch.last_tsc_scaling_ratio =3D vcpu->arch.l1_tsc_scaling_ratio; =20 vcpu->arch.last_guest_tsc =3D tsc; =20 @@ -3109,6 +3110,8 @@ static bool kvm_get_walltime_and_clockread(struct tim= espec64 *ts, * */ =20 +static unsigned long get_cpu_tsc_khz(void); + static void pvclock_update_vm_gtod_copy(struct kvm *kvm) { #ifdef CONFIG_X86_64 @@ -3132,9 +3135,30 @@ static void pvclock_update_vm_gtod_copy(struct kvm *= kvm) && !ka->backwards_tsc_observed && !ka->boot_vcpu_runs_old_kvmclock; =20 - if (ka->use_master_clock) + if (ka->use_master_clock) { + u64 tsc_hz; + atomic_set(&kvm_guest_has_master_clock, 1); =20 + /* + * Copy the scaling ratio and precompute the mul/shift for + * converting guest TSC to nanoseconds. These are used by + * get_kvmclock() to compute kvmclock from the host TSC + * without needing a vCPU reference. + */ + ka->master_tsc_scaling_ratio =3D ka->last_tsc_scaling_ratio; + tsc_hz =3D (u64)get_cpu_tsc_khz() * 1000; + if (tsc_hz && kvm_caps.has_tsc_control) + tsc_hz =3D kvm_scale_tsc(tsc_hz, + ka->master_tsc_scaling_ratio); + if (tsc_hz) + kvm_get_time_scale(NSEC_PER_SEC, tsc_hz, + &ka->master_tsc_shift, + &ka->master_tsc_mul); + else + ka->use_master_clock =3D false; + } + vclock_mode =3D pvclock_gtod_data.clock.vclock_mode; trace_kvm_update_master_clock(ka->use_master_clock, vclock_mode, vcpus_matched); @@ -3220,10 +3244,28 @@ static void get_kvmclock(struct kvm *kvm, struct kv= m_clock_data *data) =20 hv_clock.tsc_timestamp =3D ka->master_cycle_now; hv_clock.system_time =3D ka->master_kernel_ns + ka->kvmclock_offset; - kvm_get_time_scale(NSEC_PER_SEC, get_cpu_tsc_khz() * 1000LL, - &hv_clock.tsc_shift, - &hv_clock.tsc_to_system_mul); - data->clock =3D __pvclock_read_cycles(&hv_clock, data->host_tsc); + + /* + * Use the precomputed guest-TSC-based mul/shift + * so that the kvmclock value matches what the + * guest computes from its own TSC. + */ + hv_clock.tsc_shift =3D ka->master_tsc_shift; + hv_clock.tsc_to_system_mul =3D ka->master_tsc_mul; + + if (kvm_caps.has_tsc_control) { + u64 tsc_delta =3D data->host_tsc - ka->master_cycle_now; + + tsc_delta =3D kvm_scale_tsc(tsc_delta, + ka->master_tsc_scaling_ratio); + data->clock =3D hv_clock.system_time + + pvclock_scale_delta(tsc_delta, + hv_clock.tsc_to_system_mul, + hv_clock.tsc_shift); + } else { + data->clock =3D __pvclock_read_cycles(&hv_clock, + data->host_tsc); + } continue; } =20 --=20 2.54.0