From nobody Fri Jul 10 17:09:10 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=1783113851; cv=none; d=zohomail.com; s=zohoarc; b=fYp3WTOueYEu9O4oyO35QI5RZTa90W02xlt0ZgknNwJcSQYXfoo9X4GanzkFLMGsZGjmy7hMjgQ+prkPB7ZtVLnTjV+FVTC2teCt12xMBh5m00/r/kIp4TQDFjwMMIbkynqypN0a0OfuDYQsmHtkg+kWL7aqe4dU0a6HtZquQlU= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1783113851; h=Content-Type: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=SebBoBga7+8xvSm9Qg2DITvEgd/PpKvvHuYtx20We+A=; b=VCBkN3tfTCulDFtLf0HzuZbVDsp+NNdin+y9uoxvHlfIOOSInpCEmnLYTfvr4TwurzYfNwHsI00Teo5bfxzaBxHzXpPyc/s4YY1z4PsIkoKB1dkMATqbQpG+ySPldxf2+uxQPOW8j7Ks4Z+xCv+0Nli1BgHB0ucxv0z+BkzfXok= 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 17831138513861019.4907194999595; Fri, 3 Jul 2026 14:24:11 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.1353901.1609669 (Exim 4.92) (envelope-from ) id 1wflMZ-0007KA-2c; Fri, 03 Jul 2026 21:23:55 +0000 Received: by outflank-mailman (output) from mailman id 1353901.1609669; Fri, 03 Jul 2026 21:23:54 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflMY-0007IX-QX; Fri, 03 Jul 2026 21:23:54 +0000 Received: by outflank-mailman (input) for mailman id 1353901; Fri, 03 Jul 2026 21:23:52 +0000 Received: from mx.expurgate.net ([195.190.135.10]) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflMW-0006v8-Lb for xen-devel@lists.xenproject.org; Fri, 03 Jul 2026 21:23:52 +0000 Received: from mx.expurgate.net (helo=localhost) by mx.expurgate.net with esmtp id 1wflMW-001XO6-2V; Fri, 03 Jul 2026 23:23:52 +0200 Received: from [10.42.69.5] (helo=localhost) by localhost with ESMTP (eXpurgate MTA 0.9.1) (envelope-from ) id 6a4827d9-5cb7-0a2a0a5109dd-0a2a4505dcf2-42 for ; Fri, 03 Jul 2026 23:23:52 +0200 Received: from [90.155.92.199] (helo=desiato.infradead.org) by tlsNG-c201ff.mxtls.expurgate.net with ESMTPS (eXpurgate 4.57.1) (envelope-from ) id 6a482867-3cb2-0a2a45050019-5a9b5cc781b6-3 for ; Fri, 03 Jul 2026 23:23:51 +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-000000059Nu-3OYm; Fri, 03 Jul 2026 21:23:38 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.99.2 #2 (Red Hat Linux)) id 1wflKV-00000001RNp-3OFP; Fri, 03 Jul 2026 22:21:47 +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:Content-Type: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: Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:To: From:Reply-To:Cc:Content-ID:Content-Description; bh=SebBoBga7+8xvSm9Qg2DITvEgd/PpKvvHuYtx20We+A=; b=MrJT44uEu/ZgsbRjkneqpYQb+I C9bwJVuCznY58yJD8EdJi8FQdNVEgxGcL50Ro9AZYdMNScp+g1s1h2IFLUn2lIqqc9EYs8NUR3RGy 6qxE3E1hl0ywiGSZI+jKomQ4xMQr+7uKuHnk/5q0xaHqpxokRZIG6n6fJrVvB2w20H2Y8vq7G+Kz/ ypBryhHJBUZNe7TIsGAxVDdtKuU2mjrLVIBo3VZJ4w8SDZ7LzobdRT/yT+cdPuckXVbOn/8HEOmTl 5FiE48zNpNUBhA5POfG4WA4DzdJ+VDeI0VUe2SBZrA7WCF/2WPhGmEyI6XoaCQ7zDs39P9Nk5648O 5UZK0HgA==; 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 01/36] KVM: x86/xen: Do not corrupt KVM clock in kvm_xen_shared_info_init() Date: Fri, 3 Jul 2026 22:17:40 +0100 Message-ID: <20260703212145.343527-2-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-Type: text/plain; charset="utf-8" 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-c201ff/1783113832-179182B8-3037DC53/0/0 X-purgate-type: clean X-purgate-size: 4490 X-ZohoMail-DKIM: pass (identity @infradead.org) X-ZM-MESSAGEID: 1783113852961158500 From: David Woodhouse The KVM clock is an interesting thing. It is defined as "nanoseconds since the guest was created", but in practice it runs at two *different* rates =E2=80=94 or three different rates, if you count implementation bugs. Definition A is that it runs synchronously with the CLOCK_MONOTONIC_RAW of the host, with a delta of kvm->arch.kvmclock_offset. But that version doesn't actually get used in the common case, where the host has a reliable TSC and the guest TSCs are all running at the same rate and in sync with each other, and kvm->arch.use_master_clock is set. In that common case, definition B is used: There is a reference point in time at kvm->arch.master_kernel_ns (again a CLOCK_MONOTONIC_RAW time), and a corresponding host TSC value kvm->arch.master_cycle_now. This fixed point in time is converted to guest units (the time offset by kvmclock_offset and the TSC Value scaled and offset to be a guest TSC value) and advertised to the guest in the pvclock structure. While in this 'use_master_clock' mode, the fixed point in time never needs to be changed, and the clock runs precisely in time with the guest TSC, at the rate advertised in the pvclock structure. The third definition C is implemented in kvm_get_wall_clock_epoch() and __get_kvmclock(), using the master_cycle_now and master_kernel_ns fields but converting the *host* TSC cycles directly to a value in nanoseconds instead of scaling via the guest TSC. One might na=C3=AFvely think that all three definitions are identical, since CLOCK_MONOTONIC_RAW is not skewed by NTP frequency corrections; all three are just the result of counting the host TSC at a known frequency, or the scaled guest TSC at a known precise fraction of the host's frequency. The problem is with arithmetic precision, and the way that frequency scaling is done in a division-free way by multiplying by a scale factor, then shifting right. In practice, all three ways of calculating the KVM clock will suffer a systemic drift from each other. Eventually, definition C should just be eliminated. Commit 451a707813ae ("KVM: x86/xen: improve accuracy of Xen timers") worked around it for the specific case of Xen timers, which are defined in terms of the KVM clock and suffered from a continually increasing error in timer expiry times. That commit notes that get_kvmclock_ns() is non-trivial to fix and says "I'll come back to that", which remains true. Definitions A and B do need to coexist, the former to handle the case where the host or guest TSC is suboptimally configured. But KVM should be more careful about switching between them, and the discontinuity in guest time which could result. In particular, KVM_REQ_MASTERCLOCK_UPDATE will take a new snapshot of time as the reference in master_kernel_ns and master_cycle_now, yanking the guest's clock back to match definition A at that moment. When invoked from in 'use_master_clock' mode, kvm_update_masterclock() should probably *adjust* kvm->arch.kvmclock_offset to account for the drift, instead of yanking the clock back to definition A. But in the meantime there are a bunch of places where it just doesn't need to be invoked at all. To start with: there is no need to do such an update when a Xen guest populates the shared_info page. This seems to have been a hangover from the very first implementation of shared_info which automatically populated the vcpu_info structures at their default locations, but even then it should just have raised KVM_REQ_CLOCK_UPDATE on each vCPU instead of using KVM_REQ_MASTERCLOCK_UPDATE. And now that userspace is expected to explicitly set the vcpu_info even in its default locations, there's not even any need for that either. Fixes: 629b5348841a ("KVM: x86/xen: update wallclock region") Reviewed-by: Paul Durrant Signed-off-by: David Woodhouse --- arch/x86/kvm/xen.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c index 91fd3673c09a..82e34edbfdbd 100644 --- a/arch/x86/kvm/xen.c +++ b/arch/x86/kvm/xen.c @@ -98,8 +98,6 @@ static int kvm_xen_shared_info_init(struct kvm *kvm) wc->version =3D wc_version + 1; read_unlock_irq(&gpc->lock); =20 - kvm_make_all_cpus_request(kvm, KVM_REQ_MASTERCLOCK_UPDATE); - out: srcu_read_unlock(&kvm->srcu, idx); return ret; base-commit: 2d6d57f889f3a5e7d19009c560ea2002cdde9fb8 --=20 2.54.0 From nobody Fri Jul 10 17:09:10 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=1783113872; cv=none; d=zohomail.com; s=zohoarc; b=ZSGiG/zDvwC33valiEPL1lxN8F4pUX4YUDxPrZlu/Xw+J4Y76F+yODhz/otaTfGdfJG64gZWif8VXKWiua24lwftjh1YDPoYtHV6FF7FgPlHfUI1GwV+mn+vfM46ciC6c/Rk0IXWmRkXdsaCULLPintikQZ9HrKYG9+zrfSK5dg= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1783113872; 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=flkC/OcSCGAXpnaP19vXBE2hMaRp11igqBu5RS6r3dg=; b=j5t+P+g73am8BmB537WMnmCTjVFlB6PucP5rSmXuJdZHu2/mDDEh/axDVxJvTYTiNtABKp4crt7xyZMsgJWydBGHWPHS+5uDzq2ygbFi1S2xpW/ZOZp9j5MgPNX/Qgui6CUlfY1DeqDrLz9v5EGwEXD8/I8et2ehZ9944+a00QQ= 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 1783113872033612.0328567775164; Fri, 3 Jul 2026 14:24:32 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.1353906.1609691 (Exim 4.92) (envelope-from ) id 1wflMb-0007xy-Oj; Fri, 03 Jul 2026 21:23:57 +0000 Received: by outflank-mailman (output) from mailman id 1353906.1609691; Fri, 03 Jul 2026 21:23:57 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflMb-0007w8-79; Fri, 03 Jul 2026 21:23:57 +0000 Received: by outflank-mailman (input) for mailman id 1353906; Fri, 03 Jul 2026 21:23:54 +0000 Received: from mx.expurgate.net ([194.145.224.10]) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflMY-0007Bo-8r for xen-devel@lists.xenproject.org; Fri, 03 Jul 2026 21:23:54 +0000 Received: from mx.expurgate.net (helo=localhost) by mx.expurgate.net with esmtp id 1wflMX-00CejO-Lw; Fri, 03 Jul 2026 23:23:53 +0200 Received: from [10.42.69.7] (helo=localhost) by localhost with ESMTP (eXpurgate MTA 0.9.1) (envelope-from ) id 6a48281d-bab6-0a2a0a5309dd-0a2a4507d556-20 for ; Fri, 03 Jul 2026 23:23:53 +0200 Received: from [90.155.92.199] (helo=desiato.infradead.org) by tlsNG-ef75cf.mxtls.expurgate.net with ESMTPS (eXpurgate 4.57.1) (envelope-from ) id 6a482869-9c8e-0a2a45070019-5a9b5cc7914a-3 for ; Fri, 03 Jul 2026 23:23:53 +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 1wflKc-000000059Nv-34Xj; Fri, 03 Jul 2026 21:23:38 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.99.2 #2 (Red Hat Linux)) id 1wflKV-00000001RNt-3e6d; Fri, 03 Jul 2026 22:21:47 +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=flkC/OcSCGAXpnaP19vXBE2hMaRp11igqBu5RS6r3dg=; b=Tbbp2+TwxLpc+G6p3RBqRTKHVF F4m+83xyTjWYceXJyh2USsFVoW6+F+mtSXFFxfE40w5kBpDY7LtCXofCcMc5DNYajLyDOqwL8awjr D8NjUmK74H6WSJ4msHlpTTp23TRYPcLxDbu5yf3S4NBseUm1GXoEO6eGOWBjZbhbqtgNYV3EslBHl sdjDwDOi/MgPFJ/us5LXXWA4S16xfC6rAOzt5Ui6F0K99DIcw/7CW4aX8nJ96jKVAAqZ7lQKV3S/e wuu9Y93KEfLorCJOM0DRw0AlgEomw2lcT+tPvveFIhQ0M5LxwRmzGgsezMN8iEKUMRI6h7CJsDgke xHD9FbXQ==; 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 02/36] KVM: x86: Improve accuracy of KVM clock when TSC scaling is in force Date: Fri, 3 Jul 2026 22:17:41 +0100 Message-ID: <20260703212145.343527-3-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-ef75cf/1783113833-FEB3B25E-425DE96E/0/0 X-purgate-type: clean X-purgate-size: 4085 X-ZohoMail-DKIM: pass (identity @infradead.org) X-ZM-MESSAGEID: 1783113873017158500 Content-Type: text/plain; charset="utf-8" From: David Woodhouse The kvm_guest_time_update() function scales the host TSC frequency to the guest's using kvm_scale_tsc() and the v->arch.l1_tsc_scaling_ratio scaling ratio previously calculated for that vCPU. Then calculates the scaling factors for the KVM clock itself based on that guest TSC frequency. However, it uses kHz as the unit when scaling, and then multiplies by 1000 only at the end. With a host TSC frequency of 3000MHz and a guest set to 2500MHz, the result of kvm_scale_tsc() will actually come out at 2,499,999kHz. So the KVM clock advertised to the guest is based on a frequency of 2,499,999,000 Hz. By using Hz as the unit from the beginning, the KVM clock would be based on a more accurate frequency of 2,499,999,999 Hz in this example. Use u64 for the hw_tsc_hz field since an unsigned int would overflow for TSC frequencies above 4GHz. Use div_u64() for the Xen CPUID leaf to play nice with 32-bit kernels. Fixes: 78db6a503796 ("KVM: x86: rewrite handling of scaled TSC for kvmclock= ") Reviewed-by: Paul Durrant Signed-off-by: David Woodhouse Tested-by: Dongli Zhang --- arch/x86/include/asm/kvm_host.h | 2 +- arch/x86/kvm/cpuid.c | 2 +- arch/x86/kvm/x86.c | 17 +++++++++-------- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_hos= t.h index f14009f25a3b..b2446c04a076 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -950,7 +950,7 @@ struct kvm_vcpu_arch { gpa_t time; s8 pvclock_tsc_shift; u32 pvclock_tsc_mul; - unsigned int hw_tsc_khz; + u64 hw_tsc_hz; struct gfn_to_pfn_cache pv_time; /* set guest stopped flag in pvclock flags field */ bool pvclock_set_guest_stopped_request; diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index e69156b54cff..621d950ec692 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -2131,7 +2131,7 @@ bool kvm_cpuid(struct kvm_vcpu *vcpu, u32 *eax, u32 *= ebx, *ecx =3D vcpu->arch.pvclock_tsc_mul; *edx =3D vcpu->arch.pvclock_tsc_shift; } else if (index =3D=3D 2) { - *eax =3D vcpu->arch.hw_tsc_khz; + *eax =3D div_u64(vcpu->arch.hw_tsc_hz, 1000); } } } else { diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 0550359ed798..dbcff49cd561 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -3314,7 +3314,8 @@ static void kvm_setup_guest_pvclock(struct pvclock_vc= pu_time_info *ref_hv_clock, int kvm_guest_time_update(struct kvm_vcpu *v) { struct pvclock_vcpu_time_info hv_clock =3D {}; - unsigned long flags, tgt_tsc_khz; + unsigned long flags; + u64 tgt_tsc_hz; unsigned seq; struct kvm_vcpu_arch *vcpu =3D &v->arch; struct kvm_arch *ka =3D &v->kvm->arch; @@ -3340,8 +3341,8 @@ int kvm_guest_time_update(struct kvm_vcpu *v) =20 /* Keep irq disabled to prevent changes to the clock */ local_irq_save(flags); - tgt_tsc_khz =3D get_cpu_tsc_khz(); - if (unlikely(tgt_tsc_khz =3D=3D 0)) { + tgt_tsc_hz =3D (u64)get_cpu_tsc_khz() * 1000; + if (unlikely(tgt_tsc_hz =3D=3D 0)) { local_irq_restore(flags); kvm_make_request(KVM_REQ_CLOCK_UPDATE, v); return 1; @@ -3376,16 +3377,16 @@ int kvm_guest_time_update(struct kvm_vcpu *v) /* With all the info we got, fill in the values */ =20 if (kvm_caps.has_tsc_control) { - tgt_tsc_khz =3D kvm_scale_tsc(tgt_tsc_khz, + tgt_tsc_hz =3D kvm_scale_tsc(tgt_tsc_hz, v->arch.l1_tsc_scaling_ratio); - tgt_tsc_khz =3D tgt_tsc_khz ? : 1; + tgt_tsc_hz =3D tgt_tsc_hz ? : 1; } =20 - if (unlikely(vcpu->hw_tsc_khz !=3D tgt_tsc_khz)) { - kvm_get_time_scale(NSEC_PER_SEC, tgt_tsc_khz * 1000LL, + if (unlikely(vcpu->hw_tsc_hz !=3D tgt_tsc_hz)) { + kvm_get_time_scale(NSEC_PER_SEC, tgt_tsc_hz, &vcpu->pvclock_tsc_shift, &vcpu->pvclock_tsc_mul); - vcpu->hw_tsc_khz =3D tgt_tsc_khz; + vcpu->hw_tsc_hz =3D tgt_tsc_hz; } =20 hv_clock.tsc_shift =3D vcpu->pvclock_tsc_shift; --=20 2.54.0 From nobody Fri Jul 10 17:09:10 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=1783113767; cv=none; d=zohomail.com; s=zohoarc; b=jNOPbX2vZBes+ZTNDR8+GY33La8xMWzf1BlfHCXdokozDiEkb7s4nMBjdGC/wuWdUljPSsFgfORIA3x5f3F8nYY95y//vx3+Hj89YRcY4P1QxiqLdYNjtRLffJ5WcxFxS9zuWSyZB8AYCNvRCYvSxDT35xbVnInE+oKQB9iyjXU= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1783113767; 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=JGip5OQmCNyYBe2RKNqtANSbVWKYmHi+8pzbH2BRHSA=; b=K9At2qdmIVdPtjXGK3TGcKX4wfa1CRgg7DrFpgVIhJ8GmSrrl+dCPzCq/0rUu1tshCkX7PYJ86IZTcDiC/Dmt8j75iStYqDi1QvGI18Q3dKUot2YETG2q1ROtkJzZZIKa45nKh1fmGmAtiUKTEPEFH3J6zY379jqATpjPI0DL08= 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 1783113767619897.6997149564402; Fri, 3 Jul 2026 14:22:47 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.1353756.1609501 (Exim 4.92) (envelope-from ) id 1wflKq-0006Is-JK; Fri, 03 Jul 2026 21:22:08 +0000 Received: by outflank-mailman (output) from mailman id 1353756.1609501; Fri, 03 Jul 2026 21:22:08 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflKq-0006H8-7Z; Fri, 03 Jul 2026 21:22:08 +0000 Received: by outflank-mailman (input) for mailman id 1353756; Fri, 03 Jul 2026 21:22:06 +0000 Received: from mx.expurgate.net ([195.190.135.10]) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflKo-0005Xr-HM for xen-devel@lists.xenproject.org; Fri, 03 Jul 2026 21:22:06 +0000 Received: from mx.expurgate.net (helo=localhost) by mx.expurgate.net with esmtp id 1wflKn-00BEX7-GE; Fri, 03 Jul 2026 23:22:05 +0200 Received: from [10.42.69.11] (helo=localhost) by localhost with ESMTP (eXpurgate MTA 0.9.1) (envelope-from ) id 6a4827be-5cb7-0a2a0a5109dd-0a2a450bcf44-20 for ; Fri, 03 Jul 2026 23:22:05 +0200 Received: from [90.155.50.34] (helo=casper.infradead.org) by tlsNG-42698a.mxtls.expurgate.net with ESMTPS (eXpurgate 4.57.1) (envelope-from ) id 6a4827f8-ac48-0a2a450b0019-5a9b3222e674-3 for ; Fri, 03 Jul 2026 23:22:00 +0200 Received: from [2001:8b0:10b:1::425] (helo=i7.infradead.org) by casper.infradead.org with esmtpsa (Exim 4.99.1 #2 (Red Hat Linux)) id 1wflKW-0000000AsXx-09Ii; Fri, 03 Jul 2026 21:21:48 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.99.2 #2 (Red Hat Linux)) id 1wflKV-00000001RNx-3z0C; Fri, 03 Jul 2026 22:21:47 +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=casper.20170209 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=casper.20170209; 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=JGip5OQmCNyYBe2RKNqtANSbVWKYmHi+8pzbH2BRHSA=; b=K/OjjdcT6O/cygwEuqkom8qloZ C+OSPUx10ymjhW/V1tZF78Q5nJxxW2QjPYLriE1GdGwSREYz44Tw3TsyTe82NSqCWM4lhGivf38wg 9D4xJ62zrzNbRoTxpSRpCCvI1dys9Fy/vhBI//h1vnhNBgX8NhQ4YfneO8qb7VoE7Wc2qbmTreVVa GCneIJ/+04IgHesf0fEdF7QfFZ4qvRcVRcQeGwt1frRTnHVzA3JdKed2mpPaZI/LW7m4axN8dohsQ eqIh5yx6j6F7xOtPZxM5z3JlqseV4oJ+7+jG5Og0yXJOI4I7gubsrk0nQ/3NxYg95+n+OLVBYJeVh wxION8tA==; 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 03/36] UAPI: x86: Move pvclock-abi to UAPI for x86 platforms Date: Fri, 3 Jul 2026 22:17:42 +0100 Message-ID: <20260703212145.343527-4-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 casper.infradead.org. See http://www.infradead.org/rpr.html X-purgate-ID: tlsNG-42698a/1783113725-A5B20220-C70E66EA/0/0 X-purgate-type: clean X-purgate-size: 3570 X-ZohoMail-DKIM: pass (identity @infradead.org) X-ZM-MESSAGEID: 1783113768541158500 Content-Type: text/plain; charset="utf-8" From: Jack Allister A subsequent commit will provide a new KVM interface for performing a fixup/correction of the KVM clock against the reference TSC. The KVM_[GS]ET_CLOCK_GUEST API requires a pvclock_vcpu_time_info, as such the caller must know about this definition. Move the definition to the UAPI folder so that it is exported to usermode and also change the type definitions to use the standard for UAPI exports. Signed-off-by: Jack Allister Signed-off-by: David Woodhouse Reviewed-by: Paul Durrant Tested-by: Dongli Zhang --- MAINTAINERS | 4 +-- arch/x86/include/{ =3D> uapi}/asm/pvclock-abi.h | 27 ++++++++++--------- scripts/xen-hypercalls.sh | 2 +- 3 files changed, 18 insertions(+), 15 deletions(-) rename arch/x86/include/{ =3D> uapi}/asm/pvclock-abi.h (82%) diff --git a/MAINTAINERS b/MAINTAINERS index 905c29fe4996..057ccef8d1fa 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14420,7 +14420,7 @@ S: Supported T: git git://git.kernel.org/pub/scm/virt/kvm/kvm.git F: arch/um/include/asm/kvm_para.h F: arch/x86/include/asm/kvm_para.h -F: arch/x86/include/asm/pvclock-abi.h +F: arch/x86/include/uapi/asm/pvclock-abi.h F: arch/x86/include/uapi/asm/kvm_para.h F: arch/x86/kernel/kvm.c F: arch/x86/kernel/kvmclock.c @@ -29105,7 +29105,7 @@ R: Boris Ostrovsky L: xen-devel@lists.xenproject.org (moderated for non-subscribers) S: Supported F: arch/x86/configs/xen.config -F: arch/x86/include/asm/pvclock-abi.h +F: arch/x86/include/uapi/asm/pvclock-abi.h F: arch/x86/include/asm/xen/ F: arch/x86/platform/pvh/ F: arch/x86/xen/ diff --git a/arch/x86/include/asm/pvclock-abi.h b/arch/x86/include/uapi/asm= /pvclock-abi.h similarity index 82% rename from arch/x86/include/asm/pvclock-abi.h rename to arch/x86/include/uapi/asm/pvclock-abi.h index b9fece5fc96d..6d70cf640362 100644 --- a/arch/x86/include/asm/pvclock-abi.h +++ b/arch/x86/include/uapi/asm/pvclock-abi.h @@ -1,6 +1,9 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ #ifndef _ASM_X86_PVCLOCK_ABI_H #define _ASM_X86_PVCLOCK_ABI_H + +#include + #ifndef __ASSEMBLER__ =20 /* @@ -24,20 +27,20 @@ */ =20 struct pvclock_vcpu_time_info { - u32 version; - u32 pad0; - u64 tsc_timestamp; - u64 system_time; - u32 tsc_to_system_mul; - s8 tsc_shift; - u8 flags; - u8 pad[2]; + __u32 version; + __u32 pad0; + __u64 tsc_timestamp; + __u64 system_time; + __u32 tsc_to_system_mul; + __s8 tsc_shift; + __u8 flags; + __u8 pad[2]; } __attribute__((__packed__)); /* 32 bytes */ =20 struct pvclock_wall_clock { - u32 version; - u32 sec; - u32 nsec; + __u32 version; + __u32 sec; + __u32 nsec; } __attribute__((__packed__)); =20 #define PVCLOCK_TSC_STABLE_BIT (1 << 0) diff --git a/scripts/xen-hypercalls.sh b/scripts/xen-hypercalls.sh index f18b00843df3..51a722198997 100755 --- a/scripts/xen-hypercalls.sh +++ b/scripts/xen-hypercalls.sh @@ -5,7 +5,7 @@ shift in=3D"$@" =20 for i in $in; do - eval $CPP $LINUXINCLUDE -dD -imacros "$i" -x c /dev/null + eval $CPP -D__KERNEL__ $LINUXINCLUDE -dD -imacros "$i" -x c /dev/null done | \ awk '$1 =3D=3D "#define" && $2 ~ /__HYPERVISOR_[a-z][a-z_0-9]*/ { v[$3] = =3D $2 } END { print "/* auto-generated by scripts/xen-hypercall.sh */" --=20 2.54.0 From nobody Fri Jul 10 17:09:10 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=1783113852; cv=none; d=zohomail.com; s=zohoarc; b=TTg//iI5XJrgTB4gGOYFLufAayqzRXZ/01lsbgNfl0z2IrlfrXUi0yYxLTj5t42kILQBEGvRnr+Ec47HJ2z8brDvJto8ajykiHpEzAot5SLhTkX7w5jW0vO5uy4a/z34glHOoj1HOva57eM3QmkhM9DRGP0nk3xaXuaj65AUi4M= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1783113852; 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=hH+knYn8nTd+TnpfZC0k8V0fYdXUF8AZtKckehaVSow=; b=hv9+2/wRKAA1fg+Z9CVFNxoWkqV52BUm2Mjs9FapsoJGjmOXKnLPOUJrGq8ekyYg/ju0ewk8QcCX6XH8AdcbaJXBIfPwqrK03BdXsnUXFAlBRadSGienWPbIl8AReHcIVKzeS/zCvYayiacBgYZ2LyHUjssN3JnUV6GziFThWv0= 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 1783113852719423.1413947773872; Fri, 3 Jul 2026 14:24:12 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.1353895.1609655 (Exim 4.92) (envelope-from ) id 1wflMX-00073z-K0; Fri, 03 Jul 2026 21:23:53 +0000 Received: by outflank-mailman (output) from mailman id 1353895.1609655; Fri, 03 Jul 2026 21:23:53 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflMX-00073O-C9; Fri, 03 Jul 2026 21:23:53 +0000 Received: by outflank-mailman (input) for mailman id 1353895; Fri, 03 Jul 2026 21:23:52 +0000 Received: from mx.expurgate.net ([195.190.135.10]) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflMW-0006u2-4y for xen-devel@lists.xenproject.org; Fri, 03 Jul 2026 21:23:52 +0000 Received: from mx.expurgate.net (helo=localhost) by mx.expurgate.net with esmtp id 1wflMV-001XO6-Gs; Fri, 03 Jul 2026 23:23:51 +0200 Received: from [10.42.69.1] (helo=localhost) by localhost with ESMTP (eXpurgate MTA 0.9.1) (envelope-from ) id 6a482856-5cb7-0a2a0a5109dd-0a2a4501b470-6 for ; Fri, 03 Jul 2026 23:23:51 +0200 Received: from [90.155.92.199] (helo=desiato.infradead.org) by tlsNG-d62444.mxtls.expurgate.net with ESMTPS (eXpurgate 4.57.1) (envelope-from ) id 6a482866-400f-0a2a45010019-5a9b5cc79db4-3 for ; Fri, 03 Jul 2026 23:23:51 +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 1wflKc-000000059Nw-41Pc; Fri, 03 Jul 2026 21:23:11 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.99.2 #2 (Red Hat Linux)) id 1wflKV-00000001RO1-49DP; Fri, 03 Jul 2026 22:21:47 +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=hH+knYn8nTd+TnpfZC0k8V0fYdXUF8AZtKckehaVSow=; b=ag/RZYPYcN4fVre9EsOS+cOhgG SwK+HBXd1dgEt76oRFLUyPps4X6KBXzSXwZeG8u4bPBlS1lY6kQQvAcw3N7JBu/jgw5Oe4TmfsCbY cGsWk+shyieTGRcnmmdvQW3sYKZmi87gbtyJxTa9TzZQfKD6AJliCrRLqmacRh4oYvoPEd9VQZYHP +EBg6NrRc7a+h2xbCvCY2ik3TtHc7gqWcC1e6ZFSOkCHviU9BxUopFV+Av+rB7l/zJUI5VuUCrOlH sKBpN9uwsn5Q2ooxq1gQ5H+fO3FvAsMOJ+0Fskg5ceKnccVTWZJB6lTZZtjdD9iLxY8ozyYLaNuNg BCA7oq3A==; 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 04/36] KVM: selftests: Use UAPI pvclock-abi.h in xen_shinfo_test Date: Fri, 3 Jul 2026 22:17:43 +0100 Message-ID: <20260703212145.343527-5-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-d62444/1783113831-83AC91E0-5144876C/0/0 X-purgate-type: clean X-purgate-size: 1138 X-ZohoMail-DKIM: pass (identity @infradead.org) X-ZM-MESSAGEID: 1783113852892158500 Content-Type: text/plain; charset="utf-8" From: David Woodhouse Now that pvclock-abi.h is a UAPI header, use it in xen_shinfo_test.c instead of locally duplicating the struct definitions. Signed-off-by: David Woodhouse --- .../testing/selftests/kvm/x86/xen_shinfo_test.c | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/tools/testing/selftests/kvm/x86/xen_shinfo_test.c b/tools/test= ing/selftests/kvm/x86/xen_shinfo_test.c index 5076f6a75455..2f241ca4f096 100644 --- a/tools/testing/selftests/kvm/x86/xen_shinfo_test.c +++ b/tools/testing/selftests/kvm/x86/xen_shinfo_test.c @@ -98,22 +98,7 @@ struct sched_poll { u64 timeout; }; =20 -struct pvclock_vcpu_time_info { - u32 version; - u32 pad0; - u64 tsc_timestamp; - u64 system_time; - u32 tsc_to_system_mul; - s8 tsc_shift; - u8 flags; - u8 pad[2]; -} __attribute__((__packed__)); /* 32 bytes */ - -struct pvclock_wall_clock { - u32 version; - u32 sec; - u32 nsec; -} __attribute__((__packed__)); +#include =20 struct vcpu_runstate_info { u32 state; --=20 2.54.0 From nobody Fri Jul 10 17:09:10 2026 Received: from casper.infradead.org (casper.infradead.org [90.155.50.34]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E4B6B34389C; Fri, 3 Jul 2026 21:22:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=90.155.50.34 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783113727; cv=none; b=SozR6LRxSTRYVMWCA4uUXKfu/M6iSjN/YtAlMoimuxTLKYNm4sBNxFSdM8cx+8G+MS4iLRvbleqetWez70Oakt0W3Nc6qHNysPWG+YDUR/iAEmnXpBK9cKU6IEzr/FrD8LNp4VfOj69UWyqcnaISC4WUIyMyudb133IyWAQzRpU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783113727; c=relaxed/simple; bh=ssGAy1eqskg00/8V9G9Tq3S1z9/N2P1magYefq3oLu8=; h=From:To:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ULEDT+aikZstzqI7Zg7TumYG8w7thoqNK/ra9aM7tnAztxsRECeMbaeu7xujz9WM/ZlA7/ZG7l2o1XSG+sl+Or2Tn4Sbn9N1MJRMXv0HsdDG2+axm2Hthrf/kFVnwM6wTiOtKZDg/h17vp7Y72uNDKJAyhosJoLW1+Mlb+v/njM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=infradead.org; spf=none smtp.mailfrom=casper.srs.infradead.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b=S3vRHxeL; arc=none smtp.client-ip=90.155.50.34 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=infradead.org Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=casper.srs.infradead.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b="S3vRHxeL" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=casper.20170209; 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=0/Ko95h1bBGKJF1vvgeKDeWdrJpZvK3VkW99NKrhR+Q=; b=S3vRHxeLB0ApTOC406bbIRimZD LC6e7diwcttbDgjqEu6A71ZDwAAcje0fFBxS68GU3Rfpt7DbqJ9S/Kc6YHHHgvP/ABwSAHYC9PBFL ExKQNj0bFNhPncvKdMD4ZLP4CgQKvO9Xa4jNtOj9quyXzxQqCYv77ZbzSeLPna3xQqFpaUM7C8hpL w1ToHaEd0myJRhspO9phRm30ftZIbMOSVix/C2jEv5SWWjcilsUMd/+SAOStTEb/ZP8M6rNDJN6oU 9W7Wj/lhjERIlMWnMxL286yDCeSUwlLCNPdfZi9mNLMZt6wx3/JQQHG1MfOiAlxHMdyGK8Yfr6PoF Wq7/22PQ==; Received: from [2001:8b0:10b:1::425] (helo=i7.infradead.org) by casper.infradead.org with esmtpsa (Exim 4.99.1 #2 (Red Hat Linux)) id 1wflKW-0000000AsXz-0V43; Fri, 03 Jul 2026 21:21:48 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.99.2 #2 (Red Hat Linux)) id 1wflKW-00000001RO5-085M; Fri, 03 Jul 2026 22:21:48 +0100 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 05/36] KVM: x86: Add KVM_[GS]ET_CLOCK_GUEST for accurate KVM clock migration Date: Fri, 3 Jul 2026 22:17:44 +0100 Message-ID: <20260703212145.343527-6-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> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: David Woodhouse X-SRS-Rewrite: SMTP reverse-path rewritten from by casper.infradead.org. See http://www.infradead.org/rpr.html Content-Type: text/plain; charset="utf-8" From: Jack Allister In the common case (where kvm->arch.use_master_clock is true), the KVM clock is defined as a simple arithmetic function of the guest TSC, based on a reference point stored in kvm->arch.master_kernel_ns and kvm->arch.master_cycle_now. The existing KVM_[GS]ET_CLOCK functionality does not allow for this relationship to be precisely saved and restored by userspace. All it can currently do is set the KVM clock at a given UTC reference time, which is necessarily imprecise. So on live update, the guest TSC can remain cycle accurate at precisely the same offset from the host TSC, but there is no way for userspace to restore the KVM clock accurately. Even on live migration to a new host, where the accuracy of the guest time-keeping is fundamentally limited by the accuracy of wallclock synchronization between the source and destination hosts, the clock jump experienced by the guest's TSC and its KVM clock should at least be *consistent*. Even when the guest TSC suffers a discontinuity, its KVM clock should still remain the *same* arithmetic function of the guest TSC, and not suffer an *additional* discontinuity. To allow for accurate migration of the KVM clock, add per-vCPU ioctls which save and restore the actual PV clock info in pvclock_vcpu_time_info. The restoration in KVM_SET_CLOCK_GUEST works by creating a new reference point in time just as kvm_update_masterclock() does, and calculating the corresponding guest TSC value. This guest TSC value is then passed through the user-provided pvclock structure to generate the *intended* KVM clock value at that point in time, and through the *actual* KVM clock calculation. Then kvm->arch.kvmclock_offset is adjusted to eliminate the difference. Where kvm->arch.use_master_clock is false (because the host TSC is unreliable, or the guest TSCs are configured strangely), the KVM clock is *not* defined as a function of the guest TSC so KVM_GET_CLOCK_GUEST returns an error. In this case, as documented, userspace shall use the legacy KVM_GET_CLOCK ioctl. The loss of precision is acceptable in this case since the clocks are imprecise in this mode anyway. On *restoration*, if kvm->arch.use_master_clock is false, an error is returned for similar reasons and userspace shall fall back to using KVM_SET_CLOCK. This does mean that, as documented, userspace needs to use *both* KVM_GET_CLOCK_GUEST and KVM_GET_CLOCK and send both results with the migration data (unless the intent is to refuse to resume on a host with bad TSC). Co-developed-by: David Woodhouse Signed-off-by: David Woodhouse Signed-off-by: Jack Allister Reviewed-by: Paul Durrant Cc: Dongli Zhang Tested-by: Dongli Zhang --- Documentation/virt/kvm/api.rst | 37 +++++++ arch/x86/include/uapi/asm/kvm.h | 1 + arch/x86/kvm/x86.c | 171 ++++++++++++++++++++++++++++++++ include/uapi/linux/kvm.h | 3 + 4 files changed, 212 insertions(+) diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index 52bbbb553ce1..2268b4442df6 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -6553,6 +6553,43 @@ KVM_S390_KEYOP_SSKE Sets the storage key for the guest address ``guest_addr`` to the key specified in ``key``, returning the previous value in ``key``. =20 +4.145 KVM_GET_CLOCK_GUEST +---------------------------- + +:Capability: none +:Architectures: x86_64 +:Type: vcpu ioctl +:Parameters: struct pvclock_vcpu_time_info (out) +:Returns: 0 on success, <0 on error + +Retrieves the current time information structure used for KVM/PV clocks, +in precisely the form advertised to the guest vCPU, which gives parameters +for a direct conversion from a guest TSC value to nanoseconds. + +When the KVM clock is not in "master clock" mode, for example because the +host TSC is unreliable or the guest TSCs are oddly configured, the KVM clo= ck +is actually defined by the host CLOCK_MONOTONIC_RAW instead of the guest T= SC. +In this case, the KVM_GET_CLOCK_GUEST ioctl returns -EINVAL. + +4.146 KVM_SET_CLOCK_GUEST +---------------------------- + +:Capability: none +:Architectures: x86_64 +:Type: vcpu ioctl +:Parameters: struct pvclock_vcpu_time_info (in) +:Returns: 0 on success, <0 on error + +Sets the KVM clock (for the whole VM) in terms of the vCPU TSC, using the +pvclock structure as returned by KVM_GET_CLOCK_GUEST. This allows the prec= ise +arithmetic relationship between guest TSC and KVM clock to be preserved by +userspace across migration. + +When the KVM clock is not in "master clock" mode, and the KVM clock is act= ually +defined by the host CLOCK_MONOTONIC_RAW, this ioctl returns -EINVAL. Users= pace +may choose to set the clock using the less precise KVM_SET_CLOCK ioctl, or= may +choose to fail, denying migration to a host whose TSC is misbehaving. + .. _kvm_run: =20 5. The kvm_run structure diff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kv= m.h index 5f2b30d0405c..5f4a66b1662a 100644 --- a/arch/x86/include/uapi/asm/kvm.h +++ b/arch/x86/include/uapi/asm/kvm.h @@ -12,6 +12,7 @@ #include #include #include +#include =20 #define KVM_PIO_PAGE_OFFSET 1 #define KVM_COALESCED_MMIO_PAGE_OFFSET 2 diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index dbcff49cd561..ff45577ed90c 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -6210,6 +6210,169 @@ static int kvm_get_reg_list(struct kvm_vcpu *vcpu, return 0; } =20 +#ifdef CONFIG_X86_64 +static int kvm_vcpu_ioctl_get_clock_guest(struct kvm_vcpu *v, void __user = *argp) +{ + struct pvclock_vcpu_time_info hv_clock =3D {}; + struct kvm_vcpu_arch *vcpu =3D &v->arch; + struct kvm_arch *ka =3D &v->kvm->arch; + unsigned int seq; + + /* + * If KVM_REQ_CLOCK_UPDATE is already pending, or if the pvclock + * has never been generated at all, call kvm_guest_time_update(). + */ + if (kvm_check_request(KVM_REQ_CLOCK_UPDATE, v) || !vcpu->hw_tsc_hz) { + int idx =3D srcu_read_lock(&v->kvm->srcu); + int ret =3D kvm_guest_time_update(v); + + srcu_read_unlock(&v->kvm->srcu, idx); + if (ret) + return -EINVAL; + } + + /* + * Reconstruct the pvclock from the master clock state, matching + * exactly what kvm_guest_time_update() writes to the guest. + */ + do { + seq =3D read_seqcount_begin(&ka->pvclock_sc); + + if (!ka->use_master_clock) + return -EINVAL; + + hv_clock.tsc_timestamp =3D kvm_read_l1_tsc(v, ka->master_cycle_now); + hv_clock.system_time =3D ka->master_kernel_ns + ka->kvmclock_offset; + } while (read_seqcount_retry(&ka->pvclock_sc, seq)); + + hv_clock.tsc_shift =3D vcpu->pvclock_tsc_shift; + hv_clock.tsc_to_system_mul =3D vcpu->pvclock_tsc_mul; + hv_clock.flags =3D PVCLOCK_TSC_STABLE_BIT; + + if (copy_to_user(argp, &hv_clock, sizeof(hv_clock))) + return -EFAULT; + + return 0; +} + +/* + * Reverse the calculation in the hv_clock definition. + * + * time_ns =3D ( (cycles << shift) * mul ) >> 32; + * (although shift can be negative, so that's bad C) + * + * So for a single second, + * NSEC_PER_SEC =3D ( ( FREQ_HZ << shift) * mul ) >> 32 + * NSEC_PER_SEC << 32 =3D ( FREQ_HZ << shift ) * mul + * ( NSEC_PER_SEC << 32 ) / mul =3D FREQ_HZ << shift + * ( NSEC_PER_SEC << 32 ) / mul ) >> shift =3D FREQ_HZ + */ +static u64 hvclock_to_hz(u32 mul, s8 shift) +{ + u64 tm =3D NSEC_PER_SEC << 32; + + /* Maximise precision. Shift right until the top bit is set */ + tm <<=3D 2; + shift +=3D 2; + + /* While 'mul' is even, increase the shift *after* the division */ + while (!(mul & 1)) { + shift++; + mul >>=3D 1; + } + + tm /=3D mul; + + if (shift >=3D 64) + return 0; + if (shift > 0) + return tm >> shift; + if (shift <=3D -64) + return 0; + return tm << -shift; +} + +static int kvm_vcpu_ioctl_set_clock_guest(struct kvm_vcpu *v, void __user = *argp) +{ + struct pvclock_vcpu_time_info user_hv_clock; + struct kvm *kvm =3D v->kvm; + struct kvm_arch *ka =3D &kvm->arch; + u64 curr_tsc_hz, user_tsc_hz; + u64 user_clk_ns; + u64 guest_tsc; + int rc =3D 0; + + if (copy_from_user(&user_hv_clock, argp, sizeof(user_hv_clock))) + return -EFAULT; + + if (user_hv_clock.pad0 || user_hv_clock.pad[0] || user_hv_clock.pad[1]) + return -EINVAL; + + if (!user_hv_clock.tsc_to_system_mul) + return -EINVAL; + + if (user_hv_clock.tsc_shift < -31 || user_hv_clock.tsc_shift > 31) + return -EINVAL; + + user_tsc_hz =3D hvclock_to_hz(user_hv_clock.tsc_to_system_mul, + user_hv_clock.tsc_shift); + + kvm_hv_request_tsc_page_update(kvm); + + /* + * kvm_start_pvclock_update() takes tsc_write_lock and opens + * the pvclock seqcount; kvm_end_pvclock_update() closes both. + * All clock state modifications between them are atomic with + * respect to readers in kvm_guest_time_update(). + */ + kvm_start_pvclock_update(kvm); + pvclock_update_vm_gtod_copy(kvm); + + if (!ka->use_master_clock) { + rc =3D -EINVAL; + goto out; + } + + curr_tsc_hz =3D (u64)get_cpu_tsc_khz() * 1000; + if (unlikely(curr_tsc_hz =3D=3D 0)) { + rc =3D -EINVAL; + goto out; + } + + if (kvm_caps.has_tsc_control) + curr_tsc_hz =3D kvm_scale_tsc(curr_tsc_hz, + v->arch.l1_tsc_scaling_ratio); + + /* + * Allow for a discrepancy of 1 kHz either way between the TSC + * frequency used to generate the user's pvclock and the current + * host's measured frequency, since they may not precisely match. + */ + if (user_tsc_hz < curr_tsc_hz - 1000 || + user_tsc_hz > curr_tsc_hz + 1000) { + rc =3D -ERANGE; + goto out; + } + + /* + * Calculate the guest TSC at the new reference point, and the + * corresponding KVM clock value according to user_hv_clock. + * Adjust kvmclock_offset so both definitions agree. + */ + guest_tsc =3D kvm_read_l1_tsc(v, ka->master_cycle_now); + if (guest_tsc < user_hv_clock.tsc_timestamp) { + rc =3D -EINVAL; + goto out; + } + user_clk_ns =3D __pvclock_read_cycles(&user_hv_clock, guest_tsc); + ka->kvmclock_offset =3D user_clk_ns - ka->master_kernel_ns; + +out: + kvm_end_pvclock_update(kvm); + return rc; +} +#endif + long kvm_arch_vcpu_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { @@ -6610,6 +6773,14 @@ long kvm_arch_vcpu_ioctl(struct file *filp, srcu_read_unlock(&vcpu->kvm->srcu, idx); break; } +#ifdef CONFIG_X86_64 + case KVM_SET_CLOCK_GUEST: + r =3D kvm_vcpu_ioctl_set_clock_guest(vcpu, argp); + break; + case KVM_GET_CLOCK_GUEST: + r =3D kvm_vcpu_ioctl_get_clock_guest(vcpu, argp); + break; +#endif #ifdef CONFIG_KVM_HYPERV case KVM_GET_SUPPORTED_HV_CPUID: r =3D kvm_ioctl_get_supported_hv_cpuid(vcpu, argp); diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 6c8afa2047bf..9b50191b859c 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -1669,4 +1669,7 @@ struct kvm_pre_fault_memory { __u64 padding[5]; }; =20 +#define KVM_SET_CLOCK_GUEST _IOW(KVMIO, 0xd6, struct pvclock_vcpu_time_inf= o) +#define KVM_GET_CLOCK_GUEST _IOR(KVMIO, 0xd7, struct pvclock_vcpu_time_inf= o) + #endif /* __LINUX_KVM_H */ --=20 2.54.0 From nobody Fri Jul 10 17:09:10 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=1783113769; cv=none; d=zohomail.com; s=zohoarc; b=Cov/EUtm1+t+WdP2qqdhdqLXHJ7d8ZJ7wU+5xacgaih2ZCxG9jC2YOBigC/NbZvdAtdbaGD58SKN2KTwnHduuLp6bxw4nCqd4F9LFLul6jXq/iRkaHNZvmcOgK7rej7vLNCe6/odHUdNwPgNykWg08ERbny/5QgUmvJuVCnd6H8= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1783113769; h=Content-Type: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=/GVIzOguJ6FEtu0Xi+CX41sxIMFfZk32Sup1CQOK2cA=; b=AR4QCr5+WpiY9gcoEhcdkYIIqoQaGYQQj+fYwtfT+4Hi7lbzIHW/jj636MgnUNrBdmSh3wJmJv/vsXpnuBWMuUpJhZ71s9w+c7MenlLaUqXNZFqAyFlFOxLgbHUvqGibcZ4iBL41IC2ODUum09M0myw6u9obBP/mjLbjFg0AHKo= 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 1783113769407220.28829288680095; Fri, 3 Jul 2026 14:22:49 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.1353760.1609526 (Exim 4.92) (envelope-from ) id 1wflKs-0006w3-Et; Fri, 03 Jul 2026 21:22:10 +0000 Received: by outflank-mailman (output) from mailman id 1353760.1609526; Fri, 03 Jul 2026 21:22:10 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflKs-0006sg-3X; Fri, 03 Jul 2026 21:22:10 +0000 Received: by outflank-mailman (input) for mailman id 1353760; Fri, 03 Jul 2026 21:22:07 +0000 Received: from mx.expurgate.net ([194.145.224.20]) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflKo-0005mx-QX for xen-devel@lists.xenproject.org; Fri, 03 Jul 2026 21:22:07 +0000 Received: from mx.expurgate.net (helo=localhost) by mx.expurgate.net with esmtp id 1wflKo-00BXCb-7G; Fri, 03 Jul 2026 23:22:06 +0200 Received: from [10.42.69.1] (helo=localhost) by localhost with ESMTP (eXpurgate MTA 0.9.1) (envelope-from ) id 6a48279b-2eae-0a2a0a5409dd-0a2a45019e62-26 for ; Fri, 03 Jul 2026 23:22:06 +0200 Received: from [90.155.50.34] (helo=casper.infradead.org) by tlsNG-d62444.mxtls.expurgate.net with ESMTPS (eXpurgate 4.57.1) (envelope-from ) id 6a4827f9-400f-0a2a45010019-5a9b3222b94c-3 for ; Fri, 03 Jul 2026 23:22:01 +0200 Received: from [2001:8b0:10b:1::425] (helo=i7.infradead.org) by casper.infradead.org with esmtpsa (Exim 4.99.1 #2 (Red Hat Linux)) id 1wflKW-0000000AsY0-0gKK; Fri, 03 Jul 2026 21:21:48 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.99.2 #2 (Red Hat Linux)) id 1wflKW-00000001RO9-0J5N; 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=casper.20170209 header.d=infradead.org header.i="@infradead.org" header.h="Sender:Content-Transfer-Encoding:Content-Type: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=casper.20170209; h=Sender:Content-Transfer-Encoding: Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:To: From:Reply-To:Cc:Content-ID:Content-Description; bh=/GVIzOguJ6FEtu0Xi+CX41sxIMFfZk32Sup1CQOK2cA=; b=BaLfOYts8sUMPmGLNaou7hmwDv ZEfJ2OXH77XM1HGv9Qct/70aBrcfJbrFrtbzbbsDoOpGsFipDwRaLmNxMu2mtVcacWgZcyXNPob4E g7uxUNPd+zDqY6qBjNJ+x9SpZ1a0eWx9S8whOdlJn11Sdea2BzLYhL6nLX7Nria99A57xj169SUeP IB8A6a3ZpKbJ6hmsFt+zSw0qlRITMmBDgjsOQounx182YctWVblQukg2QqcyGsPz/AVV8mZRN0Xn0 G7G6WOhJrirf5aATGmlwhdiPBxIdukuDn/grl0vpdDfgN1+/dlXxuqFgaxEG4ywrZfLj+AV07Ve/h tySrJOhA==; 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 06/36] KVM: selftests: Add KVM/PV clock selftest to prove timer correction Date: Fri, 3 Jul 2026 22:17:45 +0100 Message-ID: <20260703212145.343527-7-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-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Sender: David Woodhouse X-SRS-Rewrite: SMTP reverse-path rewritten from by casper.infradead.org. See http://www.infradead.org/rpr.html X-purgate-ID: tlsNG-d62444/1783113721-FFCCE1E0-C9E5487E/0/0 X-purgate-type: clean X-purgate-size: 16061 X-ZohoMail-DKIM: pass (identity @infradead.org) X-ZM-MESSAGEID: 1783113770658158500 From: Jack Allister A VM's KVM/PV clock has an inherent relationship to its TSC. When either the host system live-updates or the VM is live-migrated this pairing of the two clock sources should stay the same. In reality this is not the case without some correction taking place. The KVM_GET_CLOCK_GUEST/KVM_SET_CLOCK_GUEST ioctls can be used to perform a correction on the PVTI (PV time information) structure held by KVM to effectively fix up the kvmclock_offset prior to the guest VM resuming in either a live-update/migration scenario. This test proves that without the necessary fixup there is a perceived change in the guest TSC and KVM/PV clock relationship before and after a simulated LU/LM takes place, and that the correction eliminates it. The test: 1. Snapshots the PVTI at boot (PVTI0). 2. Induces a change in PVTI data (KVM_REQ_MASTERCLOCK_UPDATE). 3. Snapshots the PVTI after the change (PVTI1). 4. Requests correction via KVM_SET_CLOCK_GUEST using PVTI0. 5. Snapshots the PVTI after correction (PVTI2). Then samples the TSC at a single point in time and calculates the KVM clock using each PVTI snapshot. The corrected clock should match the boot clock to within =C2=B11ns. The test enumerates multiple TSC frequencies from 1GHz to 5GHz at 500MHz steps, crossing the 32-bit boundary, to exercise the scaling path at various ratios. The sleep duration between snapshots is configurable via the -s/--sleep command line option. Co-developed-by: David Woodhouse Signed-off-by: David Woodhouse Signed-off-by: Jack Allister Reviewed-by: Paul Durrant Cc: Dongli Zhang --- tools/testing/selftests/kvm/Makefile.kvm | 1 + .../testing/selftests/kvm/x86/pvclock_test.c | 443 ++++++++++++++++++ 2 files changed, 444 insertions(+) create mode 100644 tools/testing/selftests/kvm/x86/pvclock_test.c diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selft= ests/kvm/Makefile.kvm index 9118a5a51b89..fb935ae3bf38 100644 --- a/tools/testing/selftests/kvm/Makefile.kvm +++ b/tools/testing/selftests/kvm/Makefile.kvm @@ -105,6 +105,7 @@ TEST_GEN_PROGS_x86 +=3D x86/pmu_counters_test TEST_GEN_PROGS_x86 +=3D x86/pmu_event_filter_test TEST_GEN_PROGS_x86 +=3D x86/private_mem_conversions_test TEST_GEN_PROGS_x86 +=3D x86/private_mem_kvm_exits_test +TEST_GEN_PROGS_x86 +=3D x86/pvclock_test TEST_GEN_PROGS_x86 +=3D x86/set_boot_cpu_id TEST_GEN_PROGS_x86 +=3D x86/set_sregs_test TEST_GEN_PROGS_x86 +=3D x86/smaller_maxphyaddr_emulation_test diff --git a/tools/testing/selftests/kvm/x86/pvclock_test.c b/tools/testing= /selftests/kvm/x86/pvclock_test.c new file mode 100644 index 000000000000..f2b917ed5dea --- /dev/null +++ b/tools/testing/selftests/kvm/x86/pvclock_test.c @@ -0,0 +1,443 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright =C2=A9 Amazon.com, Inc. or its affiliates. + * + * Tests for pvclock API + * KVM_SET_CLOCK_GUEST/KVM_GET_CLOCK_GUEST + */ +#include +#include +#include +#include +#include + +#include "test_util.h" +#include "kvm_util.h" +#include "processor.h" + +#include + +/* + * Reproduce the pvclock calculation the guest uses to convert TSC to + * nanoseconds. This must match the kernel's __pvclock_read_cycles(). + */ +static inline uint64_t pvclock_scale_delta(uint64_t delta, uint32_t mul, + int8_t shift) +{ + if (shift < 0) + delta >>=3D -shift; + else + delta <<=3D shift; + return ((__uint128_t)delta * mul) >> 32; +} + +static inline uint64_t pvclock_read_cycles(struct pvclock_vcpu_time_info *= src, + uint64_t tsc) +{ + uint64_t delta =3D tsc - src->tsc_timestamp; + + return src->system_time + pvclock_scale_delta(delta, + src->tsc_to_system_mul, + src->tsc_shift); +} + +static inline void pvti_snapshot(struct pvclock_vcpu_time_info *dst, + volatile struct pvclock_vcpu_time_info *src) +{ + uint32_t version; + + do { + version =3D src->version; + __asm__ __volatile__("" ::: "memory"); + *dst =3D *src; + __asm__ __volatile__("" ::: "memory"); + } while ((src->version & 1) || src->version !=3D version); +} + +enum { + STAGE_FIRST_BOOT, + STAGE_UNCORRECTED, + STAGE_CORRECTED +}; + +#define KVMCLOCK_GPA 0xc0000000ull +#define KVMCLOCK_SIZE sizeof(struct pvclock_vcpu_time_info) + +static void trigger_pvti_update(void) +{ + /* + * Toggle between KVM's old and new system time methods to coerce KVM + * into updating the fields in the PV time info struct. + */ + wrmsr(MSR_KVM_SYSTEM_TIME, KVMCLOCK_GPA | KVM_MSR_ENABLED); + wrmsr(MSR_KVM_SYSTEM_TIME_NEW, KVMCLOCK_GPA | KVM_MSR_ENABLED); +} + +static void guest_code(void) +{ + struct pvclock_vcpu_time_info *pvti =3D + (void *)(unsigned long)KVMCLOCK_GPA; + struct pvclock_vcpu_time_info pvti_boot; + struct pvclock_vcpu_time_info pvti_uncorrected; + struct pvclock_vcpu_time_info pvti_corrected; + uint64_t tsc_guest; + uint64_t clk_boot, clk_uncorrected, clk_corrected; + int64_t delta_corrected; + + /* Set up kvmclock and snapshot the initial pvclock parameters. */ + wrmsr(MSR_KVM_SYSTEM_TIME_NEW, KVMCLOCK_GPA | KVM_MSR_ENABLED); + pvti_snapshot(&pvti_boot, pvti); + GUEST_SYNC(STAGE_FIRST_BOOT); + + /* + * Trigger an update of the PVTI. Calculating the KVM clock using this + * updated structure will show a delta from the original. + */ + trigger_pvti_update(); + pvti_snapshot(&pvti_uncorrected, pvti); + GUEST_SYNC(STAGE_UNCORRECTED); + + /* + * Snapshot the corrected time (the host does KVM_SET_CLOCK_GUEST when + * handling STAGE_UNCORRECTED). + */ + pvti_snapshot(&pvti_corrected, pvti); + + /* + * Sample the TSC at a single point in time, then calculate the + * effective KVM clock using the PVTI from each stage. Verify that the + * corrected clock matches the boot clock to within =C2=B12ns. + */ + tsc_guest =3D rdtsc(); + + clk_boot =3D pvclock_read_cycles(&pvti_boot, tsc_guest); + clk_uncorrected =3D pvclock_read_cycles(&pvti_uncorrected, tsc_guest); + clk_corrected =3D pvclock_read_cycles(&pvti_corrected, tsc_guest); + + delta_corrected =3D clk_boot - clk_corrected; + + __GUEST_ASSERT(delta_corrected >=3D -2 && delta_corrected <=3D 2, + "corrected delta %ld out of range (boot=3D%lu uncorrected=3D%lu c= orrected=3D%lu)", + delta_corrected, clk_boot, clk_uncorrected, clk_corrected); + + GUEST_SYNC(STAGE_CORRECTED); +} + +static void run_test(struct kvm_vm *vm, struct kvm_vcpu *vcpu, + unsigned int sleep_sec) +{ + struct pvclock_vcpu_time_info pvti_before; + struct ucall uc; + + for (;;) { + vcpu_run(vcpu); + TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO); + + switch (get_ucall(vcpu, &uc)) { + case UCALL_ABORT: + REPORT_GUEST_ASSERT(uc); + break; + case UCALL_SYNC: + break; + default: + TEST_FAIL("Unexpected ucall"); + } + + switch (uc.args[1]) { + case STAGE_FIRST_BOOT: + /* Save the pvclock parameters before the update. */ + vcpu_ioctl(vcpu, KVM_GET_CLOCK_GUEST, &pvti_before); + + /* Sleep to let the clocks diverge. */ + sleep(sleep_sec); + break; + + case STAGE_UNCORRECTED: + /* Restore the original pvclock parameters. */ + vcpu_ioctl(vcpu, KVM_SET_CLOCK_GUEST, &pvti_before); + break; + + case STAGE_CORRECTED: + /* Guest verified the delta in-guest. */ + return; + + default: + TEST_FAIL("Unknown stage %lu", uc.args[1]); + } + } +} + +static void configure_pvclock(struct kvm_vm *vm) +{ + unsigned int nr_pages; + + nr_pages =3D vm_calc_num_guest_pages(VM_MODE_DEFAULT, getpagesize()); + vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, + KVMCLOCK_GPA, 1, nr_pages, 0); + virt_map(vm, KVMCLOCK_GPA, KVMCLOCK_GPA, nr_pages); +} + +static void run_at_frequency(uint64_t tsc_khz, unsigned int sleep_sec) +{ + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + + pr_info("Testing at TSC frequency %lu kHz\n", tsc_khz); + vm =3D vm_create_with_one_vcpu(&vcpu, guest_code); + configure_pvclock(vm); + vcpu_ioctl(vcpu, KVM_SET_TSC_KHZ, (void *)tsc_khz); + run_test(vm, vcpu, sleep_sec); + kvm_vm_free(vm); +} + +static void test_tsc_stable_bit(void); +static void test_clock_guest_with_offsets(void); + +static void usage(const char *name) +{ + printf("Usage: %s [options]\n" + " -s, --sleep SEC sleep duration between snapshots (default: = 2)\n" + " -h, --help show this help\n", name); +} + +int main(int argc, char *argv[]) +{ + static const struct option long_opts[] =3D { + { "sleep", required_argument, NULL, 's' }, + { "help", no_argument, NULL, 'h' }, + { NULL, 0, NULL, 0 }, + }; + unsigned int sleep_sec =3D 2; + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + uint64_t host_khz; + uint64_t freq; + int opt; + + while ((opt =3D getopt_long(argc, argv, "s:h", long_opts, NULL)) !=3D -1)= { + switch (opt) { + case 's': + sleep_sec =3D atoi(optarg); + break; + case 'h': + default: + usage(argv[0]); + return opt =3D=3D 'h' ? 0 : 1; + } + } + + TEST_REQUIRE(sys_clocksource_is_based_on_tsc()); + TEST_REQUIRE(kvm_has_cap(KVM_CAP_TSC_CONTROL)); + + vm =3D vm_create_with_one_vcpu(&vcpu, guest_code); + configure_pvclock(vm); + + /* Check KVM_GET_CLOCK_GUEST is supported */ + { + struct pvclock_vcpu_time_info tmp; + int ret =3D __vcpu_ioctl(vcpu, KVM_GET_CLOCK_GUEST, &tmp); + TEST_REQUIRE(ret =3D=3D 0); + } + + /* First run at native frequency (no scaling). */ + run_test(vm, vcpu, sleep_sec); + + /* + * Then enumerate a range of TSC frequencies crossing the 32-bit + * boundary, to exercise the scaling path at various ratios. + */ + host_khz =3D __vcpu_ioctl(vcpu, KVM_GET_TSC_KHZ, NULL); + kvm_vm_free(vm); + + for (freq =3D 1000000; freq <=3D 5000000; freq +=3D 500000) { + if (freq =3D=3D host_khz) + continue; + run_at_frequency(freq, sleep_sec); + } + + test_tsc_stable_bit(); + test_clock_guest_with_offsets(); + + return 0; +} + +static volatile uint32_t vcpu_counter; +static void guest_code_stable_bit(void) +{ + uint32_t idx =3D __atomic_fetch_add(&vcpu_counter, 1, __ATOMIC_SEQ_CST); + uint64_t gpa =3D KVMCLOCK_GPA + idx * sizeof(struct pvclock_vcpu_time_inf= o); + + wrmsr(MSR_KVM_SYSTEM_TIME_NEW, gpa | KVM_MSR_ENABLED); + GUEST_SYNC(0); + GUEST_SYNC(0); + GUEST_SYNC(0); +} + +static void set_tsc_offset(struct kvm_vcpu *vcpu, uint64_t offset) +{ + struct kvm_device_attr attr =3D { + .group =3D KVM_VCPU_TSC_CTRL, + .attr =3D KVM_VCPU_TSC_OFFSET, + .addr =3D (__u64)(uintptr_t)&offset, + }; + + TEST_REQUIRE(__vcpu_has_device_attr(vcpu, KVM_VCPU_TSC_CTRL, + KVM_VCPU_TSC_OFFSET) =3D=3D 0); + vcpu_ioctl(vcpu, KVM_SET_DEVICE_ATTR, &attr); +} + +static void run_vcpu_once(struct kvm_vcpu *vcpu) +{ + struct ucall uc; + + vcpu_run(vcpu); + TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO); + switch (get_ucall(vcpu, &uc)) { + case UCALL_ABORT: + REPORT_GUEST_ASSERT(uc); + break; + case UCALL_SYNC: + break; + default: + TEST_FAIL("Unexpected ucall"); + } +} + +static void test_tsc_stable_bit(void) +{ + struct pvclock_vcpu_time_info pvti; + struct kvm_vcpu *vcpus[2]; + struct kvm_vm *vm; + int ret; + + pr_info("Testing PVCLOCK_TSC_STABLE_BIT with matched/unmatched TSCs\n"); + + vm =3D vm_create_with_vcpus(2, guest_code_stable_bit, vcpus); + configure_pvclock(vm); + + /* + * Case 1: All TSCs matched (same frequency and offset). + * Master clock should be active, PVCLOCK_TSC_STABLE_BIT set. + */ + run_vcpu_once(vcpus[0]); + + ret =3D __vcpu_ioctl(vcpus[0], KVM_GET_CLOCK_GUEST, &pvti); + TEST_ASSERT(!ret, "GET_CLOCK_GUEST should succeed with matched TSCs"); + TEST_ASSERT(pvti.flags & PVCLOCK_TSC_STABLE_BIT, + "PVCLOCK_TSC_STABLE_BIT should be set with matched TSCs"); + + /* + * Case 2: Different TSC offset, same frequency. + * Master clock should still be active (frequency matches), but + * PVCLOCK_TSC_STABLE_BIT should be cleared (offsets differ). + */ + set_tsc_offset(vcpus[1], 12345678); + run_vcpu_once(vcpus[1]); + run_vcpu_once(vcpus[0]); + + ret =3D __vcpu_ioctl(vcpus[0], KVM_GET_CLOCK_GUEST, &pvti); + if (ret) { + /* Master clock disabled by offset mismatch =E2=80=94 old kernel */ + pr_info(" Skipping offset tests (master clock requires matched offsets)= \n"); + goto out_stable; + } + TEST_ASSERT(!(pvti.flags & PVCLOCK_TSC_STABLE_BIT), + "PVCLOCK_TSC_STABLE_BIT should be clear with offset-mismatched TSCs"= ); + + /* + * Case 3: Different TSC frequency. + * Master clock should be disabled entirely. + */ + vcpu_ioctl(vcpus[1], KVM_SET_TSC_KHZ, + (void *)(unsigned long)(__vcpu_ioctl(vcpus[1], KVM_GET_TSC_KHZ, NULL)= / 2)); + /* Write TSC to trigger kvm_synchronize_tsc / kvm_track_tsc_matching */ + vcpu_set_msr(vcpus[1], MSR_IA32_TSC, 0); + run_vcpu_once(vcpus[1]); + + ret =3D __vcpu_ioctl(vcpus[0], KVM_GET_CLOCK_GUEST, &pvti); + TEST_ASSERT(ret && errno =3D=3D EINVAL, + "GET_CLOCK_GUEST should fail with frequency-mismatched TSCs, got %d = (errno %d)", + ret, errno); + +out_stable: + kvm_vm_free(vm); +} + +static void test_clock_guest_with_offsets(void) +{ + struct pvclock_vcpu_time_info pvti0, pvti1, pvti1_after; + struct kvm_vcpu *vcpus[2]; + struct kvm_vm *vm; + int64_t delta; + int ret; + + pr_info("Testing KVM_[GS]ET_CLOCK_GUEST with different TSC offsets\n"); + + vm =3D vm_create_with_vcpus(2, guest_code_stable_bit, vcpus); + configure_pvclock(vm); + + /* Set different TSC offsets on the two vCPUs */ + set_tsc_offset(vcpus[0], 0); + set_tsc_offset(vcpus[1], 1000000000ull); + + /* Run both to establish kvmclock */ + run_vcpu_once(vcpus[0]); + run_vcpu_once(vcpus[1]); + + /* GET_CLOCK_GUEST on both =E2=80=94 should succeed (master clock active)= */ + ret =3D __vcpu_ioctl(vcpus[0], KVM_GET_CLOCK_GUEST, &pvti0); + if (ret) { + pr_info(" Skipping (master clock requires matched offsets on this kerne= l)\n"); + kvm_vm_free(vm); + return; + } + ret =3D __vcpu_ioctl(vcpus[1], KVM_GET_CLOCK_GUEST, &pvti1); + TEST_ASSERT(!ret, "GET_CLOCK_GUEST on vcpu1 failed"); + + /* The tsc_timestamps should differ (different offsets) */ + TEST_ASSERT(pvti0.tsc_timestamp !=3D pvti1.tsc_timestamp, + "tsc_timestamps should differ with different offsets"); + + /* Sleep to let time elapse, then restore vcpu0's clock */ + sleep(1); + vcpu_ioctl(vcpus[0], KVM_SET_CLOCK_GUEST, &pvti0); + + /* Run vcpu0 to process the clock update */ + run_vcpu_once(vcpus[0]); + + /* GET_CLOCK_GUEST on vcpu1 =E2=80=94 should reflect the correction */ + ret =3D __vcpu_ioctl(vcpus[1], KVM_GET_CLOCK_GUEST, &pvti1_after); + TEST_ASSERT(!ret, "GET_CLOCK_GUEST on vcpu1 after SET failed"); + + /* + * After SET on vcpu0, verify the correction worked by getting + * the clock on vcpu0 again. The mul/shift should be the same, + * and computing kvmclock at the same TSC should give the same + * result as the original (within =C2=B12ns). + */ + { + struct pvclock_vcpu_time_info pvti0_after; + uint64_t tsc_now, clk_from_old, clk_from_new; + + ret =3D __vcpu_ioctl(vcpus[0], KVM_GET_CLOCK_GUEST, &pvti0_after); + TEST_ASSERT(!ret, "GET_CLOCK_GUEST on vcpu0 after SET failed"); + + tsc_now =3D pvti0_after.tsc_timestamp; + clk_from_old =3D pvclock_read_cycles(&pvti0, tsc_now); + clk_from_new =3D pvclock_read_cycles(&pvti0_after, tsc_now); + + delta =3D (int64_t)clk_from_new - (int64_t)clk_from_old; + TEST_ASSERT(delta >=3D -2 && delta <=3D 2, + "clock correction delta should be <=3D2ns, got %ld ns", + delta); + } + + /* + * Also verify that vcpu1's clock is still accessible (master + * clock still active with different offsets). + */ + ret =3D __vcpu_ioctl(vcpus[1], KVM_GET_CLOCK_GUEST, &pvti1_after); + TEST_ASSERT(!ret, "GET_CLOCK_GUEST on vcpu1 after SET failed"); + + kvm_vm_free(vm); +} --=20 2.54.0 From nobody Fri Jul 10 17:09:10 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=1783113859; cv=none; d=zohomail.com; s=zohoarc; b=jOGTTwALHCgIgv95g0E1a8y6Y4mxr9BAOfZEK+e6hVRnwTGnM4mLFqHSxgqTl/OIqJzo9P42jc9S2Zm2TgFtEmWfoMD8zrB2XWcq6i4XIbXjzAopMkBvNgASMuJXfnaEvcC4t4z6xn09GcsR3vidGWpIeD7TWC6W0q28Th9LluA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1783113859; 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=XAeJCQ+9v+mDSYHMRAWw2uzIOBs6a2aQ/+qu99zPeWk=; b=G0hRpasBHqWQfwUsynN43kPoNZr4ep1jK8OkmJTAUXxXh7smHWK+QBbr7Gi9SYDnT1MDcx+XA62/LgNjH4AwGSc7vizQ82WaxIVtzQSYOg4bGjefAbK/k8wDw8wYpiU8PgodUCb5j/HFfSWNTwFUtgzex+8sdgUoJ0QYrx+jHLQ= 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 1783113859428136.15969753145487; Fri, 3 Jul 2026 14:24:19 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.1353903.1609678 (Exim 4.92) (envelope-from ) id 1wflMa-0007WJ-1L; Fri, 03 Jul 2026 21:23:56 +0000 Received: by outflank-mailman (output) from mailman id 1353903.1609678; Fri, 03 Jul 2026 21:23:55 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflMZ-0007SR-H5; Fri, 03 Jul 2026 21:23:55 +0000 Received: by outflank-mailman (input) for mailman id 1353903; Fri, 03 Jul 2026 21:23:53 +0000 Received: from mx.expurgate.net ([195.190.135.10]) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflMW-0006zB-Vi for xen-devel@lists.xenproject.org; Fri, 03 Jul 2026 21:23:52 +0000 Received: from mx.expurgate.net (helo=localhost) by mx.expurgate.net with esmtp id 1wflMW-001XO6-CA; Fri, 03 Jul 2026 23:23:52 +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-34 for ; Fri, 03 Jul 2026 23:23:52 +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 6a482867-e40e-0a2a450a0019-5a9b5cc7ba58-3 for ; Fri, 03 Jul 2026 23:23:52 +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-000000059Nx-0xnf; Fri, 03 Jul 2026 21:23:38 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.99.2 #2 (Red Hat Linux)) id 1wflKW-00000001ROD-0TOT; 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=XAeJCQ+9v+mDSYHMRAWw2uzIOBs6a2aQ/+qu99zPeWk=; b=L06h6XB7ChTw5JFuRa1oGPYKJD pa/C7Tzgjlg4/j8Xcz0xLWravurCFkrPEx8W3oxblz5pXyRuuOucw0AfVSQ49G8Z2gokwtlVqRpUZ 76hF5gEabMj2GhEiYzS+cxTluSHaQJf3VqmfsdAaBGUby6HcIzGDTJx1nTtkYwrlAiBOzKKn/OJLk NsB+IqXwT26+U20Jo6IPUmvncGBzgomgyfc+lfqu+HJCe1B3oMqqyDWXnWGzjpdTw3Yw4pvvAdIDe NWCOKCuauAg+5mLGmvv2MuV/AJ4pY0kVq9SZWRoaSGeGhhLb4lcny8uw6kw5j20BInWSG2/SHbvPx 3UEsgyoQ==; 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 07/36] KVM: x86: Explicitly disable TSC scaling without CONSTANT_TSC Date: Fri, 3 Jul 2026 22:17:46 +0100 Message-ID: <20260703212145.343527-8-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/1783113832-D4B2CDDE-DEF88D8C/0/0 X-purgate-type: clean X-purgate-size: 2365 X-ZohoMail-DKIM: pass (identity @infradead.org) X-ZM-MESSAGEID: 1783113860934158500 Content-Type: text/plain; charset="utf-8" From: David Woodhouse KVM does make an attempt to cope with non-constant TSC, and has notifiers to handle host TSC frequency changes. However, it *only* adjusts the KVM clock, and doesn't adjust TSC frequency scaling when the host changes. This is presumably because non-constant TSCs were fixed in hardware long before TSC scaling was implemented, so there should never be real CPUs which have TSC scaling but *not* CONSTANT_TSC. Such a combination could potentially happen in some odd L1 nesting environment, but it isn't worth trying to support it. Just make the dependency explicit. Signed-off-by: David Woodhouse Reviewed-by: Paul Durrant --- arch/x86/kvm/svm/svm.c | 3 ++- arch/x86/kvm/vmx/vmx.c | 10 ++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index e02a38da5296..c46a34aeb3df 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -5557,7 +5557,8 @@ static __init int svm_hardware_setup(void) XFEATURE_MASK_BNDCSR); =20 if (tsc_scaling) { - if (!boot_cpu_has(X86_FEATURE_TSCRATEMSR)) { + if (!boot_cpu_has(X86_FEATURE_TSCRATEMSR) || + !boot_cpu_has(X86_FEATURE_CONSTANT_TSC)) { tsc_scaling =3D false; } else { pr_info("TSC scaling supported\n"); diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index b9103de01428..54e92d94155e 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -2792,6 +2792,16 @@ static int setup_vmcs_config(struct vmcs_config *vmc= s_conf, if (!cpu_has_sgx()) _cpu_based_2nd_exec_control &=3D ~SECONDARY_EXEC_ENCLS_EXITING; =20 + /* + * KVM doesn't re-derive the TSC scaling ratio when the host TSC + * frequency changes, so TSC scaling is only usable with a constant + * TSC. Clear the control here rather than in vmx_hardware_setup() so + * that the per-CPU configs recomputed by vmx_check_processor_compat() + * stay consistent with the golden vmcs_config. + */ + if (!boot_cpu_has(X86_FEATURE_CONSTANT_TSC)) + _cpu_based_2nd_exec_control &=3D ~SECONDARY_EXEC_TSC_SCALING; + if (_cpu_based_exec_control & CPU_BASED_ACTIVATE_TERTIARY_CONTROLS) _cpu_based_3rd_exec_control =3D adjust_vmx_controls64(KVM_OPTIONAL_VMX_TERTIARY_VM_EXEC_CONTROL, --=20 2.54.0 From nobody Fri Jul 10 17:09:10 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=1783113849; cv=none; d=zohomail.com; s=zohoarc; b=iB+6t8cgPXrt2/ctHsMWKxJxx+dkvkFOK2k0i5/Xu2pOvB+uerchBoPz1Z+JizSFl2+Q48RPph5KjNFWKYnt4N1GUhq2y1oW2+UpCVKYajycDwa16JqVuHe6RCgyDUiDlsTM7CQnLaXoIJ3SqxUSAu83hFdX0DfRrJ//2mfWV+M= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1783113849; 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=v5twNDtsGAUIy7fgp54AfjET8D0248IAEiPECDLBGtY=; b=DoPL2KJs7Rdd5jHLb4YtfeZ5MQV0tstqgivZf6dPRITb02pK46ylF5WYJyRNlEMl+zoGNgn5lXFEJtlXuC55wD0czI0uSDBtdc7t/M5E/GeSC2/BR3aW/y3B0jh1jY9wD1nFyNGLiMUI9loOVYsIHR6IwoX3pnB4MI/ziSffLO0= 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 1783113849863631.8812525679514; Fri, 3 Jul 2026 14:24:09 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.1353896.1609659 (Exim 4.92) (envelope-from ) id 1wflMY-0007At-4J; Fri, 03 Jul 2026 21:23:54 +0000 Received: by outflank-mailman (output) from mailman id 1353896.1609659; Fri, 03 Jul 2026 21:23:54 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflMX-00079A-Ue; Fri, 03 Jul 2026 21:23:53 +0000 Received: by outflank-mailman (input) for mailman id 1353896; Fri, 03 Jul 2026 21:23:52 +0000 Received: from mx.expurgate.net ([194.145.224.20]) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflMW-0006v5-KE for xen-devel@lists.xenproject.org; Fri, 03 Jul 2026 21:23:52 +0000 Received: from mx.expurgate.net (helo=localhost) by mx.expurgate.net with esmtp id 1wflMW-000kw0-1F; Fri, 03 Jul 2026 23:23:52 +0200 Received: from [10.42.69.11] (helo=localhost) by localhost with ESMTP (eXpurgate MTA 0.9.1) (envelope-from ) id 6a482832-2eae-0a2a0a5409dd-0a2a450b92fe-38 for ; Fri, 03 Jul 2026 23:23:52 +0200 Received: from [90.155.92.199] (helo=desiato.infradead.org) by tlsNG-42698a.mxtls.expurgate.net with ESMTPS (eXpurgate 4.57.1) (envelope-from ) id 6a482867-ac48-0a2a450b0019-5a9b5cc7a076-3 for ; Fri, 03 Jul 2026 23:23:51 +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 1wflKc-000000059Ny-3C3B; Fri, 03 Jul 2026 21:23:38 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.99.2 #2 (Red Hat Linux)) id 1wflKW-00000001ROH-0fUc; 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=v5twNDtsGAUIy7fgp54AfjET8D0248IAEiPECDLBGtY=; b=D3raY3MtOWfOex9Yyi+xdwR0oR uH968+lTAMciyl5YT2WpYYHWkV4kZsN8/ZHM2GRGrwrBj9ui5GYmD9fG5F2abnWtV4WzOKBvaPhA2 Q0QkFD8RDTCmadp3BR9IBi8DDKktdVZV77/JpgdmtpX0sSXUozU4PcguLEOrURgnnk/FD1DDwvg11 GhxzUTCQtWepYdtdsACcCD7qQa4cSuaOUyBMo3ystxYHRyA1I0arDUTqQRtVZrp2cyUSbbXeGS0Ie iCh4Z9aESsuLp+Ly/0B9HNI3BAqiQTUd6lP1/mWLYFZqczT8/eBEz4K0SdSrfmyS9ogn3nh0vMR4J oqQGhlcA==; 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 08/36] KVM: x86: Activate master clock immediately on vCPU creation Date: Fri, 3 Jul 2026 22:17:47 +0100 Message-ID: <20260703212145.343527-9-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-42698a/1783113832-A7B30220-98314000/0/0 X-purgate-type: clean X-purgate-size: 1254 X-ZohoMail-DKIM: pass (identity @infradead.org) X-ZM-MESSAGEID: 1783113850882158500 Content-Type: text/plain; charset="utf-8" From: David Woodhouse Previously, the master clock was only activated when the first vCPU processed KVM_REQ_MASTERCLOCK_UPDATE during KVM_RUN. This meant that KVM_GET_CLOCK could not return the host_tsc field until after the first KVM_RUN, making it impossible for userspace to follow the documented TSC migration procedure without a dummy vCPU run. Fix this by calling kvm_update_masterclock() directly from kvm_arch_vcpu_postcreate(), after kvm_synchronize_tsc() has already set all_vcpus_matched_freq. This ensures the master clock is active immediately, and KVM_GET_CLOCK returns a valid {host_tsc, realtime} pair as soon as a vCPU exists. Signed-off-by: David Woodhouse --- arch/x86/kvm/x86.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index ff45577ed90c..2039bd8518fb 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -13110,6 +13110,8 @@ void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu) return; vcpu_load(vcpu); kvm_synchronize_tsc(vcpu, NULL); + if (!vcpu->kvm->arch.use_master_clock) + kvm_update_masterclock(vcpu->kvm); vcpu_put(vcpu); =20 /* poll control enabled by default */ --=20 2.54.0 From nobody Fri Jul 10 17:09:10 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=1783113856; cv=none; d=zohomail.com; s=zohoarc; b=SCgDcy3TML6Ug/aHeqGI/M4Cnem/XSXsx2XWpVu4U02dY4Xw6CKDyA5MredeXjk8SrNcJLAC7tvG+HZ7sx3QVNACp1hGfNSr5dDGUYk1Zp18/NzBrR2do2AmeuGh1jgeklTqww2z8uoBUT48m1a5NwVqKdvPfLQBgvjXIMYcYiQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1783113856; h=Content-Type: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=3lUib/EIrL1+94Hfr3HOPm3NJZGT4m6/AxpXp3yQAbg=; b=ktGIPPnfU/BjL6VYCoDvbV1JROBpIrRii8nWrNtXn7fabaLAUqSoiJTPLGOuPHNFKlGquOm0ZBI7RH8iBuKw6++548LQy6wBwSLFR+R133r9okCH4GzqX67S5fb65KNS0HA2ybdFs5cvnOYTOj5MlHWWb3uxryV9d4FqoKRJjP0= 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 1783113856897411.2717232853123; Fri, 3 Jul 2026 14:24:16 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.1353907.1609697 (Exim 4.92) (envelope-from ) id 1wflMc-00082Y-4f; Fri, 03 Jul 2026 21:23:58 +0000 Received: by outflank-mailman (output) from mailman id 1353907.1609697; Fri, 03 Jul 2026 21:23:58 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflMb-00080t-Ke; Fri, 03 Jul 2026 21:23:57 +0000 Received: by outflank-mailman (input) for mailman id 1353907; Fri, 03 Jul 2026 21:23:54 +0000 Received: from mx.expurgate.net ([195.190.135.20]) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflMY-00078a-3q for xen-devel@lists.xenproject.org; Fri, 03 Jul 2026 21:23:54 +0000 Received: from mx.expurgate.net (helo=localhost) by mx.expurgate.net with esmtp id 1wflMX-00A83n-GB; Fri, 03 Jul 2026 23:23:53 +0200 Received: from [10.42.69.2] (helo=localhost) by localhost with ESMTP (eXpurgate MTA 0.9.1) (envelope-from ) id 6a482855-e002-0a2a0a5209dd-0a2a450295e8-10 for ; Fri, 03 Jul 2026 23:23:53 +0200 Received: from [90.155.92.199] (helo=desiato.infradead.org) by tlsNG-720697.mxtls.expurgate.net with ESMTPS (eXpurgate 4.57.1) (envelope-from ) id 6a482868-5a27-0a2a45020019-5a9b5cc7c8dc-3 for ; Fri, 03 Jul 2026 23:23:52 +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-000000059Nz-0yD3; Fri, 03 Jul 2026 21:23:31 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.99.2 #2 (Red Hat Linux)) id 1wflKW-00000001ROL-0svz; 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:Content-Type: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: Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:To: From:Reply-To:Cc:Content-ID:Content-Description; bh=3lUib/EIrL1+94Hfr3HOPm3NJZGT4m6/AxpXp3yQAbg=; b=Z7Au5hbqzBkr89WU5YG+ZPC5S9 ySbJNMLzah02oxol8S6rfewycGcma4xQAxc/yMNJ1UwcfKW0RZDK3N+ZfzpwnX0cDbzjv5IEtb3XP BqmZyXcEoEi6mGeg4G6eowbPuwlNfZdOQ3/Bi5QFoSwkKPyjSnPkAGntNnwvwwDGqmSGfM+0tOfqP H7LdsJn0nbVCjmbDvgIm50n7FXL+ms0X6P1pPKn8r3p7vR1RPFZ7mfnTwaazlLdhUz077TRnX5ZbP eSFnpVBx/QIZTGoz7Uf4ekeKzPD87F7ACQm+Sjaqai+PI1jV9VHGP1Dq2P8ygLT7zgjTP15zci0gv RqcBJSrQ==; 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 09/36] KVM: x86: Add KVM_VCPU_TSC_SCALE and fix the documentation on TSC migration Date: Fri, 3 Jul 2026 22:17:48 +0100 Message-ID: <20260703212145.343527-10-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-Type: text/plain; charset="utf-8" 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-720697/1783113833-4E10A7C5-2A36E47B/0/0 X-purgate-type: clean X-purgate-size: 24002 X-ZohoMail-DKIM: pass (identity @infradead.org) X-ZM-MESSAGEID: 1783113859010158500 From: David Woodhouse The documentation on TSC migration using KVM_VCPU_TSC_OFFSET is woefully inadequate. It ignores TSC scaling, and ignores the fact that the host TSC may differ from one host to the next (and in fact because of the way the kernel calibrates it, it generally differs from one boot to the next even on the same hardware). Add KVM_VCPU_TSC_SCALE to extract the actual scale ratio and frac_bits, and attempt to document the process that userspace needs to follow to preserve the TSC across migration. Add a self test to function as an exemplar. Only enumerate KVM_VCPU_TSC_SCALE when kvm_caps.has_tsc_control is true, since the scaling ratio is only meaningful when hardware TSC scaling is supported. Signed-off-by: David Woodhouse Reviewed-by: Paul Durrant --- Documentation/virt/kvm/devices/vcpu.rst | 120 ++++-- arch/x86/include/uapi/asm/kvm.h | 6 + arch/x86/kvm/x86.c | 21 + tools/testing/selftests/kvm/Makefile.kvm | 1 + .../kvm/x86/pvclock_migration_test.c | 383 ++++++++++++++++++ 5 files changed, 501 insertions(+), 30 deletions(-) create mode 100644 tools/testing/selftests/kvm/x86/pvclock_migration_test.c diff --git a/Documentation/virt/kvm/devices/vcpu.rst b/Documentation/virt/k= vm/devices/vcpu.rst index 5e3805820010..de9f58f75eb9 100644 --- a/Documentation/virt/kvm/devices/vcpu.rst +++ b/Documentation/virt/kvm/devices/vcpu.rst @@ -229,6 +229,7 @@ including the layout of the stolen time structure. :Architectures: x86 =20 4.1 ATTRIBUTE: KVM_VCPU_TSC_OFFSET +---------------------------------- =20 :Parameters: 64-bit unsigned TSC offset =20 @@ -243,7 +244,10 @@ Returns: Specifies the guest's TSC offset relative to the host's TSC. The guest's TSC is then derived by the following equation: =20 - guest_tsc =3D host_tsc + KVM_VCPU_TSC_OFFSET + guest_tsc =3D ((host_tsc * tsc_ratio) >> tsc_frac_bits) + KVM_VCPU_TSC_O= FFSET + +The values of tsc_ratio and tsc_frac_bits can be obtained using +the KVM_VCPU_TSC_SCALE attribute. =20 This attribute is useful to adjust the guest's TSC on live migration, so that the TSC counts the time during which the VM was paused. The @@ -251,44 +255,100 @@ following describes a possible algorithm to use for = this purpose. =20 From the source VMM process: =20 -1. Invoke the KVM_GET_CLOCK ioctl to record the host TSC (tsc_src), +1. Invoke the KVM_GET_CLOCK ioctl to record the host TSC (host_tsc_src), kvmclock nanoseconds (guest_src), and host CLOCK_REALTIME nanoseconds - (host_src). + (time_src) at a given moment (Tsrc). + +2. For each vCPU[i]: + + a. Read the KVM_VCPU_TSC_OFFSET attribute to record the guest TSC offset + (ofs_src[i]). =20 -2. Read the KVM_VCPU_TSC_OFFSET attribute for every vCPU to record the - guest TSC offset (ofs_src[i]). + b. Read the KVM_VCPU_TSC_SCALE attribute to record the guest TSC scaling + ratio (ratio_src[i], frac_bits_src[i]). =20 -3. Invoke the KVM_GET_TSC_KHZ ioctl to record the frequency of the - guest's TSC (freq). + c. Use host_tsc_src and the scaling/offset factors to calculate this + vCPU's TSC at time Tsrc: + + tsc_src[i] =3D ((host_tsc_src * ratio_src[i]) >> frac_bits_src[i]) += ofs_src[i] + +3. Invoke the KVM_GET_CLOCK_GUEST ioctl on the boot vCPU to return the KVM + clock as a function of the guest TSC (pvti_src). (This ioctl may not + succeed if the host and guest TSCs are not consistent and well-behaved.) =20 From the destination VMM process: =20 -4. Invoke the KVM_SET_CLOCK ioctl, providing the source nanoseconds from - kvmclock (guest_src) and CLOCK_REALTIME (host_src) in their respective - fields. Ensure that the KVM_CLOCK_REALTIME flag is set in the provided - structure. +4. Before creating the vCPUs, invoke the KVM_SET_TSC_KHZ ioctl on the VM, = to + set the scaled frequency of the guest's TSC (freq). + +5. Invoke the KVM_GET_CLOCK ioctl to record the host TSC (host_tsc_dst) and + host CLOCK_REALTIME nanoseconds (time_dst) at a given moment (Tdst). + +6. Calculate the number of nanoseconds elapsed between Tsrc and Tdst: + + =CE=94T =3D time_dst - time_src + +7. As each vCPU[i] is created: + + a. Read the KVM_VCPU_TSC_SCALE attribute to record the guest TSC scaling + ratio (ratio_dst[i], frac_bits_dst[i]). + + b. Calculate the intended guest TSC value at time Tdst: + + tsc_dst[i] =3D tsc_src[i] + (=CE=94T * freq[i]) =20 - KVM will advance the VM's kvmclock to account for elapsed time since - recording the clock values. Note that this will cause problems in - the guest (e.g., timeouts) unless CLOCK_REALTIME is synchronized - between the source and destination, and a reasonably short time passes - between the source pausing the VMs and the destination executing - steps 4-7. + c. Use host_tsc_dst and the scaling factors to calculate this vCPU's + raw scaled TSC at time Tdst without offsetting: + + raw_dst[i] =3D ((host_tsc_dst * ratio_dst[i]) >> frac_bits_dst[i]) + + d. Calculate ofs_dst[i] =3D tsc_dst[i] - raw_dst[i] and set the resulti= ng + offset using the KVM_VCPU_TSC_OFFSET attribute. + +8. If pvti_src was provided, invoke the KVM_SET_CLOCK_GUEST ioctl on the b= oot + vCPU to restore the KVM clock as a precise function of the guest TSC. + +9. If KVM_SET_CLOCK_GUEST was not available or failed (e.g. because the + master clock is not active), fall back to the KVM_SET_CLOCK ioctl, + providing the source nanoseconds from kvmclock (guest_src) and + CLOCK_REALTIME (time_src) in their respective fields. Ensure that the + KVM_CLOCK_REALTIME flag is set in the provided structure. + + KVM will restore the VM's kvmclock, accounting for elapsed time since + the clock values were recorded. Note that this will cause problems in + the guest (e.g., timeouts) unless CLOCK_REALTIME is synchronized between + the source and destination, and a reasonably short time passes between + the source pausing the VMs and the destination resuming them. + Due to the KVM_[SG]ET_CLOCK API using CLOCK_REALTIME instead of + CLOCK_TAI, leap seconds during the migration may also introduce errors. + +4.2 ATTRIBUTE: KVM_VCPU_TSC_SCALE +--------------------------------- + +:Parameters: struct kvm_vcpu_tsc_scale + +Returns: + + =3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + -EFAULT Error reading the provided parameter + address. + -ENXIO Attribute not supported (no TSC scaling) + -EINVAL Invalid request to write the attribute + =3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =20 -5. Invoke the KVM_GET_CLOCK ioctl to record the host TSC (tsc_dest) and - kvmclock nanoseconds (guest_dest). +This read-only attribute reports the guest's TSC scaling factor, in the fo= rm +of a fixed-point number represented by the following structure:: =20 -6. Adjust the guest TSC offsets for every vCPU to account for (1) time - elapsed since recording state and (2) difference in TSCs between the - source and destination machine: + struct kvm_vcpu_tsc_scale { + __u64 tsc_ratio; + __u64 tsc_frac_bits; + }; =20 - ofs_dst[i] =3D ofs_src[i] - - (guest_src - guest_dest) * freq + - (tsc_src - tsc_dest) +The tsc_frac_bits field indicates the location of the fixed point, such th= at +host TSC values are converted to guest TSC using the formula: =20 - ("ofs[i] + tsc - guest * freq" is the guest TSC value corresponding to - a time of 0 in kvmclock. The above formula ensures that it is the - same on the destination as it was on the source). + guest_tsc =3D ((host_tsc * tsc_ratio) >> tsc_frac_bits) + offset =20 -7. Write the KVM_VCPU_TSC_OFFSET attribute for every vCPU with the - respective value derived in the previous step. +Userspace can use this to precisely calculate the guest TSC from the host +TSC at any given moment. This is needed for accurate migration of guests, +as described in the documentation for the KVM_VCPU_TSC_OFFSET attribute. diff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kv= m.h index 5f4a66b1662a..fb38486ff742 100644 --- a/arch/x86/include/uapi/asm/kvm.h +++ b/arch/x86/include/uapi/asm/kvm.h @@ -962,6 +962,12 @@ struct kvm_hyperv_eventfd { /* for KVM_{GET,SET,HAS}_DEVICE_ATTR */ #define KVM_VCPU_TSC_CTRL 0 /* control group for the timestamp counter (TS= C) */ #define KVM_VCPU_TSC_OFFSET 0 /* attribute for the TSC offset */ +#define KVM_VCPU_TSC_SCALE 1 /* attribute for TSC scaling factor */ + +struct kvm_vcpu_tsc_scale { + __u64 tsc_ratio; + __u64 tsc_frac_bits; +}; =20 /* x86-specific KVM_EXIT_HYPERCALL flags. */ #define KVM_EXIT_HYPERCALL_LONG_MODE _BITULL(0) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 2039bd8518fb..26b4649dfb94 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -5935,6 +5935,9 @@ static int kvm_arch_tsc_has_attr(struct kvm_vcpu *vcp= u, case KVM_VCPU_TSC_OFFSET: r =3D 0; break; + case KVM_VCPU_TSC_SCALE: + r =3D kvm_caps.has_tsc_control ? 0 : -ENXIO; + break; default: r =3D -ENXIO; } @@ -5955,6 +5958,21 @@ static int kvm_arch_tsc_get_attr(struct kvm_vcpu *vc= pu, break; r =3D 0; break; + case KVM_VCPU_TSC_SCALE: { + struct kvm_vcpu_tsc_scale scale; + + r =3D -ENXIO; + if (!kvm_caps.has_tsc_control) + break; + + scale.tsc_ratio =3D vcpu->arch.l1_tsc_scaling_ratio; + scale.tsc_frac_bits =3D kvm_caps.tsc_scaling_ratio_frac_bits; + r =3D -EFAULT; + if (copy_to_user(uaddr, &scale, sizeof(scale))) + break; + r =3D 0; + break; + } default: r =3D -ENXIO; } @@ -5994,6 +6012,9 @@ static int kvm_arch_tsc_set_attr(struct kvm_vcpu *vcp= u, r =3D 0; break; } + case KVM_VCPU_TSC_SCALE: + r =3D kvm_caps.has_tsc_control ? -EINVAL : -ENXIO; + break; default: r =3D -ENXIO; } diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selft= ests/kvm/Makefile.kvm index fb935ae3bf38..90568ab631d7 100644 --- a/tools/testing/selftests/kvm/Makefile.kvm +++ b/tools/testing/selftests/kvm/Makefile.kvm @@ -106,6 +106,7 @@ TEST_GEN_PROGS_x86 +=3D x86/pmu_event_filter_test TEST_GEN_PROGS_x86 +=3D x86/private_mem_conversions_test TEST_GEN_PROGS_x86 +=3D x86/private_mem_kvm_exits_test TEST_GEN_PROGS_x86 +=3D x86/pvclock_test +TEST_GEN_PROGS_x86 +=3D x86/pvclock_migration_test TEST_GEN_PROGS_x86 +=3D x86/set_boot_cpu_id TEST_GEN_PROGS_x86 +=3D x86/set_sregs_test TEST_GEN_PROGS_x86 +=3D x86/smaller_maxphyaddr_emulation_test diff --git a/tools/testing/selftests/kvm/x86/pvclock_migration_test.c b/too= ls/testing/selftests/kvm/x86/pvclock_migration_test.c new file mode 100644 index 000000000000..3b675827aec3 --- /dev/null +++ b/tools/testing/selftests/kvm/x86/pvclock_migration_test.c @@ -0,0 +1,383 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Test KVM clock precision across simulated live migration. + * + * Verifies that the documented TSC migration procedure (using + * KVM_VCPU_TSC_OFFSET, KVM_VCPU_TSC_SCALE, KVM_GET_CLOCK, and + * KVM_SET_CLOCK_GUEST) preserves the kvmclock's relationship to + * CLOCK_MONOTONIC_RAW. + * + * The test: + * 1. Creates a VM, runs the guest to enable kvmclock + * 2. Does a PTP-like ABA measurement of kvmclock vs CLOCK_MONOTONIC_RAW + * 3. Follows the documented migration procedure (same host, 1s pause) + * 4. Does the same ABA measurement on the destination VM + * 5. Verifies the kvmclock-vs-monotonic delta is preserved + */ +#include +#include +#include +#include +#include +#include + +#include "test_util.h" +#include "kvm_util.h" +#include "processor.h" + +#include + +#define KVMCLOCK_GPA 0xc0000000ULL + +static void guest_code(void) +{ + wrmsr(MSR_KVM_SYSTEM_TIME_NEW, KVMCLOCK_GPA | 1); + GUEST_SYNC(0); + GUEST_SYNC(1); +} + +static uint64_t read_kvmclock_ns(struct kvm_vm *vm) +{ + struct kvm_clock_data data =3D {}; + + vm_ioctl(vm, KVM_GET_CLOCK, &data); + return data.clock; +} + +static uint64_t pvclock_read_cycles(struct pvclock_vcpu_time_info *src, + uint64_t tsc) +{ + uint64_t delta =3D tsc - src->tsc_timestamp; + uint64_t ns; + + if (src->tsc_shift >=3D 0) + delta <<=3D src->tsc_shift; + else + delta >>=3D -(int32_t)src->tsc_shift; + + ns =3D (unsigned __int128)delta * src->tsc_to_system_mul >> 32; + return src->system_time + ns; +} + +/* + * ABA measurement: read CLOCK_MONOTONIC_RAW, kvmclock, CLOCK_MONOTONIC_RA= W. + * Repeat 3 times, keep the reading with the smallest spread. + */ +static void aba_reading(struct kvm_vm *vm, uint64_t *lo, uint64_t *kvm_ns, + uint64_t *hi) +{ + uint64_t best_spread =3D UINT64_MAX; + int i; + + for (i =3D 0; i < 3; i++) { + struct timespec ts1, ts2; + uint64_t m1, m2, clk; + + clock_gettime(CLOCK_MONOTONIC_RAW, &ts1); + clk =3D read_kvmclock_ns(vm); + clock_gettime(CLOCK_MONOTONIC_RAW, &ts2); + + m1 =3D ts1.tv_sec * 1000000000ULL + ts1.tv_nsec; + m2 =3D ts2.tv_sec * 1000000000ULL + ts2.tv_nsec; + + if (m2 - m1 < best_spread) { + best_spread =3D m2 - m1; + *lo =3D m1; + *kvm_ns =3D clk; + *hi =3D m2; + } + } +} + +static struct kvm_vm *create_vm(struct kvm_vcpu **vcpu) +{ + struct kvm_vm *vm =3D vm_create_with_one_vcpu(vcpu, guest_code); + + vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, + KVMCLOCK_GPA, 1, 1, 0); + virt_map(vm, KVMCLOCK_GPA, KVMCLOCK_GPA, 1); + return vm; +} + +int main(void) +{ + struct pvclock_vcpu_time_info pvti_src; + struct kvm_clock_data clock_src, clock_dst; + struct kvm_vcpu_tsc_scale scale_src, scale_dst; + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + struct ucall uc; + uint64_t mono_before, kvm_before, kvm_after; + int64_t delta_before; + uint64_t ofs_src, tsc_src, tsc_dst, raw_dst, ofs_dst; + uint64_t host_tsc_src, host_tsc_dst; + uint64_t time_src, time_dst; + int64_t delta_t; + uint32_t freq_khz =3D 1500000; /* 1.5 GHz =E2=80=94 forces TSC scaling */ + int ret; + + TEST_REQUIRE(sys_clocksource_is_based_on_tsc()); + TEST_REQUIRE(kvm_has_cap(KVM_CAP_TSC_CONTROL)); + + /* =3D=3D=3D SOURCE SIDE =3D=3D=3D */ + pr_info("=3D=3D=3D Source VM =3D=3D=3D\n"); + vm =3D create_vm(&vcpu); + + /* Set guest TSC frequency (may trigger scaling) */ + vcpu_ioctl(vcpu, KVM_SET_TSC_KHZ, (void *)(unsigned long)freq_khz); + + /* Run guest to enable kvmclock */ + vcpu_run(vcpu); + TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO); + TEST_ASSERT_EQ(get_ucall(vcpu, &uc), UCALL_SYNC); + + /* ABA measurement: kvmclock vs CLOCK_MONOTONIC_RAW */ + uint64_t src_mono_lo, src_mono_hi; + aba_reading(vm, &src_mono_lo, &kvm_before, &src_mono_hi); + mono_before =3D (src_mono_lo + src_mono_hi) / 2; + delta_before =3D (int64_t)(kvm_before - mono_before); + pr_info(" kvmclock - MONOTONIC_RAW =3D %" PRId64 " ns (=C2=B1%" PRIu64 "= ns)\n", + delta_before, (src_mono_hi - src_mono_lo) / 2); + + /* Step 1: KVM_GET_CLOCK for atomic {host_tsc, realtime} */ + memset(&clock_src, 0, sizeof(clock_src)); + clock_src.flags =3D KVM_CLOCK_REALTIME; + vm_ioctl(vm, KVM_GET_CLOCK, &clock_src); + host_tsc_src =3D clock_src.host_tsc; + time_src =3D clock_src.realtime; + + /* Step 2: Save TSC offset and scale */ + { + struct kvm_device_attr attr =3D { + .group =3D KVM_VCPU_TSC_CTRL, + .attr =3D KVM_VCPU_TSC_OFFSET, + .addr =3D (uint64_t)(uintptr_t)&ofs_src, + }; + vcpu_ioctl(vcpu, KVM_GET_DEVICE_ATTR, &attr); + } + { + struct kvm_device_attr attr =3D { + .group =3D KVM_VCPU_TSC_CTRL, + .attr =3D KVM_VCPU_TSC_SCALE, + .addr =3D (uint64_t)(uintptr_t)&scale_src, + }; + memset(&scale_src, 0, sizeof(scale_src)); + __vcpu_ioctl(vcpu, KVM_GET_DEVICE_ATTR, &attr); + } + + /* Compute guest TSC at Tsrc */ + if (scale_src.tsc_frac_bits) + tsc_src =3D ((unsigned __int128)host_tsc_src * scale_src.tsc_ratio + >> scale_src.tsc_frac_bits) + ofs_src; + else + tsc_src =3D host_tsc_src + ofs_src; + + /* Step 3: KVM_GET_CLOCK_GUEST */ + ret =3D __vcpu_ioctl(vcpu, KVM_GET_CLOCK_GUEST, &pvti_src); + TEST_ASSERT(!ret, "KVM_GET_CLOCK_GUEST failed"); + + pr_info(" TSC freq=3D%u kHz, offset=3D%" PRId64 "\n", freq_khz, (int64_t= )ofs_src); + + kvm_vm_release(vm); + + /* =3D=3D=3D PAUSE (simulate migration) =3D=3D=3D */ + pr_info("=3D=3D=3D Pausing 1 second =3D=3D=3D\n"); + sleep(1); + + /* =3D=3D=3D DESTINATION SIDE =3D=3D=3D */ + pr_info("=3D=3D=3D Destination VM =3D=3D=3D\n"); + vm =3D create_vm(&vcpu); + + /* Step 4: KVM_SET_TSC_KHZ */ + vcpu_ioctl(vcpu, KVM_SET_TSC_KHZ, (void *)(unsigned long)freq_khz); + + /* Step 5: KVM_GET_CLOCK for atomic {host_tsc, realtime} pair. + * Master clock is active from vCPU creation. + */ + memset(&clock_dst, 0, sizeof(clock_dst)); + vm_ioctl(vm, KVM_GET_CLOCK, &clock_dst); + host_tsc_dst =3D clock_dst.host_tsc; + time_dst =3D clock_dst.realtime; + + /* Step 6: =CE=94T */ + delta_t =3D (int64_t)(time_dst - time_src); + + /* Step 7: Compute destination offset */ + { + struct kvm_device_attr attr =3D { + .group =3D KVM_VCPU_TSC_CTRL, + .attr =3D KVM_VCPU_TSC_SCALE, + .addr =3D (uint64_t)(uintptr_t)&scale_dst, + }; + memset(&scale_dst, 0, sizeof(scale_dst)); + __vcpu_ioctl(vcpu, KVM_GET_DEVICE_ATTR, &attr); + } + + tsc_dst =3D tsc_src + (uint64_t)((int64_t)freq_khz * delta_t / 1000000LL); + + if (scale_dst.tsc_frac_bits) + raw_dst =3D (unsigned __int128)host_tsc_dst * scale_dst.tsc_ratio + >> scale_dst.tsc_frac_bits; + else + raw_dst =3D host_tsc_dst; + + ofs_dst =3D tsc_dst - raw_dst; + + /* + * The TSC offset delta introduced by using CLOCK_REALTIME to + * estimate elapsed time. On same host, the correct offset is + * ofs_src; the difference is the CLOCK_REALTIME-vs-TSC error. + */ + int64_t tsc_ofs_delta =3D (int64_t)(ofs_dst - ofs_src); + int64_t tsc_ofs_delta_ns =3D tsc_ofs_delta * 1000000LL / freq_khz; + pr_info(" Destination TSC offset=3D%" PRId64 + ", imprecision from CLOCK_REALTIME: %" PRId64 " cycles =3D %" + PRId64 " ns\n", (int64_t)ofs_dst, tsc_ofs_delta, tsc_ofs_delta_ns); + + /* Set TSC offset */ + { + struct kvm_device_attr attr =3D { + .group =3D KVM_VCPU_TSC_CTRL, + .attr =3D KVM_VCPU_TSC_OFFSET, + .addr =3D (uint64_t)(uintptr_t)&ofs_dst, + }; + vcpu_ioctl(vcpu, KVM_SET_DEVICE_ATTR, &attr); + } + + /* Step 8: KVM_SET_CLOCK_GUEST */ + ret =3D __vcpu_ioctl(vcpu, KVM_SET_CLOCK_GUEST, &pvti_src); + TEST_ASSERT(!ret, "KVM_SET_CLOCK_GUEST failed: errno %d", errno); + + /* Run guest to update pvclock page on destination */ + vcpu_run(vcpu); + TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO); + TEST_ASSERT_EQ(get_ucall(vcpu, &uc), UCALL_SYNC); + + /* ABA measurement on destination */ + uint64_t mono_lo, mono_hi; + aba_reading(vm, &mono_lo, &kvm_after, &mono_hi); + + /* + * The kvmclock is tied to the guest TSC via SET_CLOCK_GUEST. + * The guest TSC is offset from the correct value by tsc_ofs_delta_ns + * (due to CLOCK_REALTIME imprecision). So the kvmclock should be + * offset from CLOCK_MONOTONIC_RAW by exactly: + * (original delta) + tsc_ofs_delta_ns + * + * The "original delta" has uncertainty from the source ABA spread, + * and the measurement has uncertainty from the destination ABA spread. + * Verify the expected value falls within the combined bounds. + */ + int64_t delta_before_lo =3D (int64_t)(kvm_before - src_mono_hi); + int64_t delta_before_hi =3D (int64_t)(kvm_before - src_mono_lo); + int64_t expected_lo =3D delta_before_lo + tsc_ofs_delta_ns; + int64_t expected_hi =3D delta_before_hi + tsc_ofs_delta_ns; + int64_t actual_lo =3D (int64_t)(kvm_after - mono_hi); + int64_t actual_hi =3D (int64_t)(kvm_after - mono_lo); + + /* Show the shift relative to the source measurement */ + int64_t expected_mid =3D tsc_ofs_delta_ns; + int64_t expected_err =3D (int64_t)(src_mono_hi - src_mono_lo) / 2; + int64_t actual_mid =3D ((actual_lo + actual_hi) / 2) - delta_before; + int64_t actual_err =3D (int64_t)(mono_hi - mono_lo) / 2; + pr_info(" kvmclock-mono shift: expected %" PRId64 " ns (=C2=B1%" PRId64 + "), measured %" PRId64 " ns (=C2=B1%" PRId64 ")\n", + expected_mid, expected_err, actual_mid, actual_err); + + /* The ranges must overlap */ + TEST_ASSERT(expected_hi >=3D actual_lo && expected_lo <=3D actual_hi, + "Ranges don't overlap: expected [%" PRId64 ", %" PRId64 + "] measured [%" PRId64 ", %" PRId64 "]", + expected_lo, expected_hi, actual_lo, actual_hi); + + /* + * Direct pvclock verification: read the destination pvclock page + * and verify that computing kvmclock from pvti_src and pvti_dst + * at the same guest TSC gives the same result. + * + * Get an atomic {host_tsc, kvmclock} pair, scale host_tsc to + * guest TSC using KVM_VCPU_TSC_SCALE, then compute kvmclock + * from both pvclock structs. + */ + struct kvm_clock_data clock_now =3D {}; + vm_ioctl(vm, KVM_GET_CLOCK, &clock_now); + + struct pvclock_vcpu_time_info *pvti_dst =3D addr_gpa2hva(vm, KVMCLOCK_GPA= ); + uint64_t host_tsc_now =3D clock_now.host_tsc; + uint64_t guest_tsc_now; + + if (scale_dst.tsc_frac_bits) + guest_tsc_now =3D ((unsigned __int128)host_tsc_now * + scale_dst.tsc_ratio >> scale_dst.tsc_frac_bits) + + ofs_dst; + else + guest_tsc_now =3D host_tsc_now + ofs_dst; + + uint64_t clk_from_src =3D pvclock_read_cycles(&pvti_src, guest_tsc_now); + uint64_t clk_from_dst =3D pvclock_read_cycles(pvti_dst, guest_tsc_now); + int64_t pvclock_delta =3D (int64_t)(clk_from_src - clk_from_dst); + + pr_info(" Pvclock direct: src=3D%" PRIu64 " dst=3D%" PRIu64 + " delta=3D%" PRId64 " ns\n", clk_from_src, clk_from_dst, pvclock_delta); + pr_info(" KVM_GET_CLOCK: %" PRIu64 " ns\n", (uint64_t)clock_now.clock); + + TEST_ASSERT(pvclock_delta >=3D -2 && pvclock_delta <=3D 2, + "pvclock src vs dst disagree by %" PRId64 " ns", pvclock_delta); + + /* + * Tight ABA: compare pvclock_read() directly (no ioctl) against + * CLOCK_MONOTONIC_RAW. The spread should be much smaller since + * there's no syscall between the two clock_gettime calls =E2=80=94 just + * rdtsc + userspace mul/shift. + */ + uint64_t tight_mono_lo =3D 0, tight_mono_hi =3D 0, tight_kvm =3D 0; + uint64_t tight_best_spread =3D UINT64_MAX; + for (int i =3D 0; i < 3; i++) { + struct timespec ts1, ts2; + uint64_t m1, m2, tsc, clk; + + clock_gettime(CLOCK_MONOTONIC_RAW, &ts1); + tsc =3D rdtsc(); + clock_gettime(CLOCK_MONOTONIC_RAW, &ts2); + + m1 =3D ts1.tv_sec * 1000000000ULL + ts1.tv_nsec; + m2 =3D ts2.tv_sec * 1000000000ULL + ts2.tv_nsec; + + /* Scale host TSC to guest TSC */ + if (scale_dst.tsc_frac_bits) + tsc =3D ((unsigned __int128)tsc * scale_dst.tsc_ratio + >> scale_dst.tsc_frac_bits) + ofs_dst; + else + tsc +=3D ofs_dst; + + clk =3D pvclock_read_cycles(pvti_dst, tsc); + + if (m2 - m1 < tight_best_spread) { + tight_best_spread =3D m2 - m1; + tight_mono_lo =3D m1; + tight_mono_hi =3D m2; + tight_kvm =3D clk; + } + } + pr_info(" Tight ABA spread: %" PRIu64 " ns (best of 3)\n", tight_best_sp= read); + + int64_t tight_expected_lo =3D delta_before_lo + tsc_ofs_delta_ns; + int64_t tight_expected_hi =3D delta_before_hi + tsc_ofs_delta_ns; + int64_t tight_actual_lo =3D (int64_t)(tight_kvm - tight_mono_hi); + int64_t tight_actual_hi =3D (int64_t)(tight_kvm - tight_mono_lo); + int64_t tight_actual_mid =3D ((tight_actual_lo + tight_actual_hi) / 2) - = delta_before; + int64_t tight_actual_err =3D (int64_t)(tight_mono_hi - tight_mono_lo) / 2; + + pr_info(" Tight kvmclock-mono shift: expected %" PRId64 + " ns (=C2=B1%" PRId64 "), measured %" PRId64 " ns (=C2=B1%" PRId64 ")\n", + expected_mid, expected_err, tight_actual_mid, tight_actual_err); + + TEST_ASSERT(tight_expected_hi >=3D tight_actual_lo && + tight_expected_lo <=3D tight_actual_hi, + "Tight ABA ranges don't overlap"); + + kvm_vm_release(vm); + pr_info("PASS: kvmclock offset matches TSC delta from CLOCK_REALTIME" + " (%" PRId64 " ns) within ABA bounds\n", tsc_ofs_delta_ns); + return 0; +} --=20 2.54.0 From nobody Fri Jul 10 17:09:10 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=1783113768; cv=none; d=zohomail.com; s=zohoarc; b=TNT4f39reYgEF7Xu9o10K4qvwlC8AjE71BKNnEOBN9r7enriOILuzLacewq/GiZuqCISLtMEQCep0Eag2/oo2ZbWHjgSr/ftctnlW3xXDbdtDGaag0tMv9J/aE/NLjxcsNECTovZbUl/yvDzrrGge2mgYrDmNpDkacqcw3LuVbY= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1783113768; 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=s+7qUlbLcb8dcHIU9yxWWuYHzICS9PPJgOOAoGyBp5o=; b=IQ9P/D8mxtJ3u94g7rrH+FhnJprioJTAprxkq9gIvD8PfH7UKOaShycg+GCZLmnAHfOXg0tII9RwG4Ubmk5qVBVXj01rDdhAsQ2tFsZOPsAH6GDoPtyxJkMaT1OlqjgK3XaXKuVjHBeMjcPuBEoDVN0YOSXLZVrWgFDD5NeG+VM= 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 1783113768059698.4635720053033; Fri, 3 Jul 2026 14:22:48 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.1353766.1609565 (Exim 4.92) (envelope-from ) id 1wflKz-0008Pk-M8; Fri, 03 Jul 2026 21:22:17 +0000 Received: by outflank-mailman (output) from mailman id 1353766.1609565; Fri, 03 Jul 2026 21:22:17 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflKz-0008M4-8j; Fri, 03 Jul 2026 21:22:17 +0000 Received: by outflank-mailman (input) for mailman id 1353766; Fri, 03 Jul 2026 21:22:15 +0000 Received: from mx.expurgate.net ([195.190.135.20]) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflKx-000876-Gu for xen-devel@lists.xenproject.org; Fri, 03 Jul 2026 21:22:15 +0000 Received: from mx.expurgate.net (helo=localhost) by mx.expurgate.net with esmtp id 1wflKw-00A7vt-U1; Fri, 03 Jul 2026 23:22:14 +0200 Received: from [10.42.69.6] (helo=localhost) by localhost with ESMTP (eXpurgate MTA 0.9.1) (envelope-from ) id 6a482804-e002-0a2a0a5209dd-0a2a4506d606-2 for ; Fri, 03 Jul 2026 23:22:14 +0200 Received: from [90.155.50.34] (helo=casper.infradead.org) by tlsNG-16d1c6.mxtls.expurgate.net with ESMTPS (eXpurgate 4.57.1) (envelope-from ) id 6a482806-08de-0a2a45060019-5a9b3222ce6e-3 for ; Fri, 03 Jul 2026 23:22:14 +0200 Received: from [2001:8b0:10b:1::425] (helo=i7.infradead.org) by casper.infradead.org with esmtpsa (Exim 4.99.1 #2 (Red Hat Linux)) id 1wflKW-0000000AsY2-1TLA; Fri, 03 Jul 2026 21:21:48 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.99.2 #2 (Red Hat Linux)) id 1wflKW-00000001ROP-12v9; 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=casper.20170209 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=casper.20170209; 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=s+7qUlbLcb8dcHIU9yxWWuYHzICS9PPJgOOAoGyBp5o=; b=HPj7neF/edX8jbo/JX8quja682 cEZuozcFmVKIQrBdJlzohG2fuYYQuNFcycqs5FWy96RgLuuCtsgPNENsXWM1BtzCtDYj1EbxULEiz FLnDUQn4MBs3GFp1PKN0NeVRrmqEWCnvYXdjIEPT0PPSKKwX+xlLnZfg37I9KK8Dp8hRsppgYkT8k sJz+4rBN3tgwri8rHwondVAyaMDPbqxGfNKNT1Mf5ShXTpgoE/LlIqlFF0q2ledbnIuzB0Z2Y/oK4 bMTCbCB/sTsOzQyuyvF7zwSQ3/zygcdDmM/tQILbMrqw5OpyejMR+PvuyewpDD3JmZASo2/07mat4 e/rL9FOw==; 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 10/36] KVM: x86: Avoid NTP frequency skew for KVM clock on 32-bit host Date: Fri, 3 Jul 2026 22:17:49 +0100 Message-ID: <20260703212145.343527-11-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 casper.infradead.org. See http://www.infradead.org/rpr.html X-purgate-ID: tlsNG-16d1c6/1783113734-4292368D-96F22E46/0/0 X-purgate-type: clean X-purgate-size: 3670 X-ZohoMail-DKIM: pass (identity @infradead.org) X-ZM-MESSAGEID: 1783113768541158501 Content-Type: text/plain; charset="utf-8" From: David Woodhouse Commit 53fafdbb8b21 ("KVM: x86: switch KVMCLOCK base to monotonic raw clock") did so only for 64-bit hosts, by capturing the boot offset from within the existing clocksource notifier update_pvclock_gtod(). That notifier was added in commit 16e8d74d2da9 ("KVM: x86: notifier for clocksource changes") but only on x86_64, because its original purpose was just to disable the "master clock" mode which is only supported on x86_64. Now that the notifier is used for more than disabling master clock mode, enable it for the 32-bit build too so that get_kvmclock_base_ns() can be unaffected by NTP sync on 32-bit too. Signed-off-by: David Woodhouse Reviewed-by: Paul Durrant --- arch/x86/kvm/x86.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 26b4649dfb94..21603feb44c5 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2342,7 +2342,6 @@ static int do_set_msr(struct kvm_vcpu *vcpu, unsigned= index, u64 *data) return kvm_set_msr_ignored_check(vcpu, index, *data, true); } =20 -#ifdef CONFIG_X86_64 struct pvclock_clock { int vclock_mode; u64 cycle_last; @@ -2400,13 +2399,6 @@ static s64 get_kvmclock_base_ns(void) /* Count up from boot time, but with the frequency of the raw clock. */ return ktime_to_ns(ktime_add(ktime_get_raw(), pvclock_gtod_data.offs_boot= )); } -#else -static s64 get_kvmclock_base_ns(void) -{ - /* Master clock not used, so we can just use CLOCK_BOOTTIME. */ - return ktime_get_boottime_ns(); -} -#endif =20 static void kvm_write_wall_clock(struct kvm *kvm, gpa_t wall_clock, int se= c_hi_ofs) { @@ -10184,6 +10176,7 @@ static void pvclock_irq_work_fn(struct irq_work *w) } =20 static DEFINE_IRQ_WORK(pvclock_irq_work, pvclock_irq_work_fn); +#endif =20 /* * Notification about pvclock gtod data update. @@ -10191,26 +10184,26 @@ static DEFINE_IRQ_WORK(pvclock_irq_work, pvclock_= irq_work_fn); static int pvclock_gtod_notify(struct notifier_block *nb, unsigned long un= used, void *priv) { - struct pvclock_gtod_data *gtod =3D &pvclock_gtod_data; struct timekeeper *tk =3D priv; =20 update_pvclock_gtod(tk); =20 +#ifdef CONFIG_X86_64 /* * Disable master clock if host does not trust, or does not use, * TSC based clocksource. Delegate queue_work() to irq_work as * this is invoked with tk_core.seq write held. */ - if (!gtod_is_based_on_tsc(gtod->clock.vclock_mode) && + if (!gtod_is_based_on_tsc(pvclock_gtod_data.clock.vclock_mode) && atomic_read(&kvm_guest_has_master_clock) !=3D 0) irq_work_queue(&pvclock_irq_work); +#endif return 0; } =20 static struct notifier_block pvclock_gtod_notifier =3D { .notifier_call =3D pvclock_gtod_notify, }; -#endif =20 void kvm_setup_xss_caps(void) { @@ -10399,9 +10392,9 @@ int kvm_x86_vendor_init(struct kvm_x86_init_ops *op= s) =20 if (pi_inject_timer =3D=3D -1) pi_inject_timer =3D housekeeping_enabled(HK_TYPE_TIMER); -#ifdef CONFIG_X86_64 pvclock_gtod_register_notifier(&pvclock_gtod_notifier); =20 +#ifdef CONFIG_X86_64 if (hypervisor_is_type(X86_HYPER_MS_HYPERV)) set_hv_tscchange_cb(kvm_hyperv_tsc_notifier); #endif @@ -10458,8 +10451,8 @@ void kvm_x86_vendor_exit(void) CPUFREQ_TRANSITION_NOTIFIER); cpuhp_remove_state_nocalls(CPUHP_AP_X86_KVM_CLK_ONLINE); } -#ifdef CONFIG_X86_64 pvclock_gtod_unregister_notifier(&pvclock_gtod_notifier); +#ifdef CONFIG_X86_64 irq_work_sync(&pvclock_irq_work); cancel_work_sync(&pvclock_gtod_work); #endif --=20 2.54.0 From nobody Fri Jul 10 17:09:10 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=1783113765; cv=none; d=zohomail.com; s=zohoarc; b=cPq0PAWhL5HC23282VWkL7TgERdU4OIeSO0aPYrwxbGCPEAqStawcQmSTqVWD6MwVo4VC9u6/QPDo5PZ6GYF/ewAc+/XqH+P7TvKorOqmzUBvIydlQFh3AGbR9afMJszCSkwAL5mvLwb17gAtdSV1oEQwFVoL+LCkFOR3vywsT0= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1783113765; 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=5esTOgHqgTZQG0bhg0+NN2EeUiyx8in1MUEgOdbTb68=; b=QXUhC8rf7MjkjypCb5Cf0pyibeqlKrrCDtSUzlUBEUBk0nctrPurIDlY6Mvq/Mywq+WnufLNaYjgW8y11NDolqm1bR5UbMekkc00acvHDgAo/8VHfvfZ55QAgiBQQC41dhw8pO96fb0K0NsFK3ZYUOEzpvA6HVVexVQk5P5CLSA= 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 1783113765578425.9782081318249; Fri, 3 Jul 2026 14:22:45 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.1353764.1609559 (Exim 4.92) (envelope-from ) id 1wflKz-0008GA-1Y; Fri, 03 Jul 2026 21:22:17 +0000 Received: by outflank-mailman (output) from mailman id 1353764.1609559; Fri, 03 Jul 2026 21:22:16 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflKy-0008EG-Mg; Fri, 03 Jul 2026 21:22:16 +0000 Received: by outflank-mailman (input) for mailman id 1353764; Fri, 03 Jul 2026 21:22:14 +0000 Received: from mx.expurgate.net ([194.145.224.10]) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflKw-00082A-Ce for xen-devel@lists.xenproject.org; Fri, 03 Jul 2026 21:22:14 +0000 Received: from mx.expurgate.net (helo=localhost) by mx.expurgate.net with esmtp id 1wflKv-00CeeP-PD; Fri, 03 Jul 2026 23:22:13 +0200 Received: from [10.42.69.3] (helo=localhost) by localhost with ESMTP (eXpurgate MTA 0.9.1) (envelope-from ) id 6a4827ca-bab6-0a2a0a5309dd-0a2a4503bf3c-26 for ; Fri, 03 Jul 2026 23:22:13 +0200 Received: from [90.155.50.34] (helo=casper.infradead.org) by tlsNG-33051d.mxtls.expurgate.net with ESMTPS (eXpurgate 4.57.1) (envelope-from ) id 6a482805-ec1a-0a2a45030019-5a9b3222d6fa-3 for ; Fri, 03 Jul 2026 23:22:13 +0200 Received: from [2001:8b0:10b:1::425] (helo=i7.infradead.org) by casper.infradead.org with esmtpsa (Exim 4.99.1 #2 (Red Hat Linux)) id 1wflKW-0000000AsY5-1o7d; Fri, 03 Jul 2026 21:21:48 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.99.2 #2 (Red Hat Linux)) id 1wflKW-00000001ROT-1D1r; 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=casper.20170209 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=casper.20170209; 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=5esTOgHqgTZQG0bhg0+NN2EeUiyx8in1MUEgOdbTb68=; b=i2Ub5UzQieNGYKh00g6PXh3mlj M6QMKQ7kfa6KmzGRvyGWn+y6cTd5d12wteB+OfmlUg/ChloyUDVPBsk+4pnifDfVTcFbQg8XPC6Wx 9w7ufgolgi/BG63pmuYQdHTWGhN65P30JJe53ZSKtWpbYn92SfYCQPWnJpgO1TxJrQffhrc+nwhfT Hf+GYVvn5FM5FeI/rUSwlUKt+kTEK/s1DWnwBVHw4/d0ffwmTdNa7342xixebxJ+gyh5rnT0fAaFH X9l96ijMza3ZqOhdx51JKTtN5H+fAKNBFRSq11Ker17Mu5sqoVCHIho+ILVaPiuiyXPfDunwp82m5 B97pDgTg==; 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 11/36] KVM: x86: Fold __get_kvmclock() into get_kvmclock() Date: Fri, 3 Jul 2026 22:17:50 +0100 Message-ID: <20260703212145.343527-12-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 casper.infradead.org. See http://www.infradead.org/rpr.html X-purgate-ID: tlsNG-33051d/1783113733-061315D1-03F432AA/0/0 X-purgate-type: clean X-purgate-size: 3279 X-ZohoMail-DKIM: pass (identity @infradead.org) X-ZM-MESSAGEID: 1783113766526158500 Content-Type: text/plain; charset="utf-8" From: David Woodhouse There is no need for the separate __get_kvmclock() helper; just inline its body into get_kvmclock() within the seqcount retry loop. No functional change. Signed-off-by: David Woodhouse --- arch/x86/kvm/x86.c | 63 +++++++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 35 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 21603feb44c5..50f088570dab 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -3200,50 +3200,43 @@ static unsigned long get_cpu_tsc_khz(void) return __this_cpu_read(cpu_tsc_khz); } =20 -/* Called within read_seqcount_begin/retry for kvm->pvclock_sc. */ -static void __get_kvmclock(struct kvm *kvm, struct kvm_clock_data *data) +static void get_kvmclock(struct kvm *kvm, struct kvm_clock_data *data) { struct kvm_arch *ka =3D &kvm->arch; struct pvclock_vcpu_time_info hv_clock; + unsigned int seq; =20 - /* both __this_cpu_read() and rdtsc() should be on the same cpu */ - get_cpu(); + do { + seq =3D read_seqcount_begin(&ka->pvclock_sc); =20 - data->flags =3D 0; - if (ka->use_master_clock && - (static_cpu_has(X86_FEATURE_CONSTANT_TSC) || __this_cpu_read(cpu_tsc_= khz))) { + /* both __this_cpu_read() and rdtsc() should be on the same cpu */ + get_cpu(); + + data->flags =3D 0; + if (ka->use_master_clock && + (static_cpu_has(X86_FEATURE_CONSTANT_TSC) || __this_cpu_read(cpu_tsc= _khz))) { #ifdef CONFIG_X86_64 - struct timespec64 ts; + struct timespec64 ts; =20 - if (kvm_get_walltime_and_clockread(&ts, &data->host_tsc)) { - data->realtime =3D ts.tv_nsec + NSEC_PER_SEC * ts.tv_sec; - data->flags |=3D KVM_CLOCK_REALTIME | KVM_CLOCK_HOST_TSC; - } else + if (kvm_get_walltime_and_clockread(&ts, &data->host_tsc)) { + data->realtime =3D ts.tv_nsec + NSEC_PER_SEC * ts.tv_sec; + data->flags |=3D KVM_CLOCK_REALTIME | KVM_CLOCK_HOST_TSC; + } else #endif - data->host_tsc =3D rdtsc(); - - data->flags |=3D KVM_CLOCK_TSC_STABLE; - 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); - } else { - data->clock =3D get_kvmclock_base_ns() + ka->kvmclock_offset; - } - - put_cpu(); -} - -static void get_kvmclock(struct kvm *kvm, struct kvm_clock_data *data) -{ - struct kvm_arch *ka =3D &kvm->arch; - unsigned seq; + data->host_tsc =3D rdtsc(); + + data->flags |=3D KVM_CLOCK_TSC_STABLE; + 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); + } else { + data->clock =3D get_kvmclock_base_ns() + ka->kvmclock_offset; + } =20 - do { - seq =3D read_seqcount_begin(&ka->pvclock_sc); - __get_kvmclock(kvm, data); + put_cpu(); } while (read_seqcount_retry(&ka->pvclock_sc, seq)); } =20 --=20 2.54.0 From nobody Fri Jul 10 17:09:10 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=1783113832; cv=none; d=zohomail.com; s=zohoarc; b=U2OejGyR/hnJ77F2lIrkPCCPv6VbT9wdqq/SD6XPXmE76pAWrJF2YjIvuUQ9qdeBMKAE3EadSBMrHYOqZJ4aLRmPx/7WK+kOpUx/nBxcMQIB7NPsI0Gcq9nDj1Lh0kGhGkcqEgZwNGbuWHHOy7KgQB/dDQDobqVY/rjhLAzJYmw= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1783113832; 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=tXL7aPo/yAWhlGILCeEnNw76Lh3seTcvuCYSfmK7zhI=; b=lCgz/7FhVILC36Gh+oVchlbOjuZzFte23iJBCkB0p4HPYWNqmjfXMNkocVVQFQiaFWa+N+q8yaR9JqIpJNm+l4G/PT6dOptUreHBg52AZqL6LUn28EPeFwHnpQenULSCz54ylvGBDXBpIQwWbeb9fsopVKn17bUlW5k5wpvd2UA= 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 1783113832037904.8809591789488; Fri, 3 Jul 2026 14:23:52 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.1353877.1609609 (Exim 4.92) (envelope-from ) id 1wflMA-0004wX-VH; Fri, 03 Jul 2026 21:23:30 +0000 Received: by outflank-mailman (output) from mailman id 1353877.1609609; Fri, 03 Jul 2026 21:23:30 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflMA-0004wM-Rv; Fri, 03 Jul 2026 21:23:30 +0000 Received: by outflank-mailman (input) for mailman id 1353877; Fri, 03 Jul 2026 21:23:29 +0000 Received: from mx.expurgate.net ([194.145.224.20]) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflM9-0004uV-E8 for xen-devel@lists.xenproject.org; Fri, 03 Jul 2026 21:23:29 +0000 Received: from mx.expurgate.net (helo=localhost) by mx.expurgate.net with esmtp id 1wflM8-00BXKf-RK; Fri, 03 Jul 2026 23:23:28 +0200 Received: from [10.42.69.11] (helo=localhost) by localhost with ESMTP (eXpurgate MTA 0.9.1) (envelope-from ) id 6a482832-2eae-0a2a0a5409dd-0a2a450b92fe-22 for ; Fri, 03 Jul 2026 23:23:28 +0200 Received: from [90.155.92.199] (helo=desiato.infradead.org) by tlsNG-42698a.mxtls.expurgate.net with ESMTPS (eXpurgate 4.57.1) (envelope-from ) id 6a482850-ac48-0a2a450b0019-5a9b5cc7b0d2-3 for ; Fri, 03 Jul 2026 23:23:28 +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 1wflKY-000000059O0-1xLJ; Fri, 03 Jul 2026 21:22:53 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.99.2 #2 (Red Hat Linux)) id 1wflKW-00000001ROY-1YDI; 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=tXL7aPo/yAWhlGILCeEnNw76Lh3seTcvuCYSfmK7zhI=; b=LK2l6nQjgd7DLaXcp7LIMUlNxA epcMuonePcQII23FEgetXgqFD+AaZXALFS9ajZIDA0hOhsfpISgZHAO8WzmAlWco0rLd/8BVw/en/ jU+YYEMLC4dz5fOSsczVKgQ5CxhKFAMTcfj/NRJEX6CND9xVsdtvLUQfOoACz0uz+cc3LS3pPW2In TTff6EzdA3x8+ljSoDSNP7+bzp9Xyl6SHQtIw/3pX7snHqV6H52FeGGVgfEkScDfUMCZeqkL+myG/ 88kadjllLlyrTpys0ZML5ORFoQ4EuiwHCVQpvfEWOALEIblsTSGQ1eFvv0cZpOrGRfIFSE/87cT82 lURSRZaA==; 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 12/36] KVM: x86: Restructure get_kvmclock() Date: Fri, 3 Jul 2026 22:17:51 +0100 Message-ID: <20260703212145.343527-13-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-42698a/1783113808-3AB38220-0F7362C9/0/0 X-purgate-type: clean X-purgate-size: 3563 X-ZohoMail-DKIM: pass (identity @infradead.org) X-ZM-MESSAGEID: 1783113832888158500 Content-Type: text/plain; charset="utf-8" From: David Woodhouse Simplify the use_master_clock condition: the open-coded CONSTANT_TSC || cpu_tsc_khz check is unnecessary since use_master_clock can only be true when the host clocksource is TSC based, which in turn requires a stable, constant and synchronised TSC across all CPUs. Given that, the get_cpu()/put_cpu() pinning is not needed either: both the TSC read and get_cpu_tsc_khz() are CPU-independent when the master clock is in use, so drop them. Wrap the entire use_master_clock block in #ifdef CONFIG_X86_64, since use_master_clock is never true on 32-bit (host_tsc_clocksource is only set under CONFIG_X86_64), and declare hv_clock inside the block so it is not left as an unused variable on 32-bit. Use 'continue' on the master-clock success path so the non-master-clock computation becomes the common tail, avoiding a goto and label. When the clock read fails (e.g. clocksource transitioning away from TSC), fall back to that path rather than proceeding with uninitialised data or spinning in the seqcount loop. Signed-off-by: David Woodhouse --- arch/x86/kvm/x86.c | 42 ++++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 50f088570dab..37b1f8192842 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -3203,40 +3203,38 @@ static unsigned long get_cpu_tsc_khz(void) static void get_kvmclock(struct kvm *kvm, struct kvm_clock_data *data) { struct kvm_arch *ka =3D &kvm->arch; - struct pvclock_vcpu_time_info hv_clock; unsigned int seq; =20 do { seq =3D read_seqcount_begin(&ka->pvclock_sc); =20 - /* both __this_cpu_read() and rdtsc() should be on the same cpu */ - get_cpu(); - data->flags =3D 0; - if (ka->use_master_clock && - (static_cpu_has(X86_FEATURE_CONSTANT_TSC) || __this_cpu_read(cpu_tsc= _khz))) { #ifdef CONFIG_X86_64 + if (ka->use_master_clock) { + struct pvclock_vcpu_time_info hv_clock; struct timespec64 ts; =20 if (kvm_get_walltime_and_clockread(&ts, &data->host_tsc)) { data->realtime =3D ts.tv_nsec + NSEC_PER_SEC * ts.tv_sec; - data->flags |=3D KVM_CLOCK_REALTIME | KVM_CLOCK_HOST_TSC; - } else -#endif - data->host_tsc =3D rdtsc(); - - data->flags |=3D KVM_CLOCK_TSC_STABLE; - 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); - } else { - data->clock =3D get_kvmclock_base_ns() + ka->kvmclock_offset; - } + data->flags |=3D KVM_CLOCK_REALTIME | KVM_CLOCK_HOST_TSC | KVM_CLOCK_T= SC_STABLE; + + 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); + continue; + } =20 - put_cpu(); + /* + * Clock read failed (e.g. clocksource is transitioning + * away from TSC). Fall back to the non-master-clock path + * rather than spinning. + */ + } +#endif + data->clock =3D get_kvmclock_base_ns() + ka->kvmclock_offset; } while (read_seqcount_retry(&ka->pvclock_sc, seq)); } =20 --=20 2.54.0 From nobody Fri Jul 10 17:09:11 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 From nobody Fri Jul 10 17:09:11 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=1783113847; cv=none; d=zohomail.com; s=zohoarc; b=OvgCso3G7yynCP4WTdBDDX/mVKYtJqQfkbekhHu6xHzoDbr2dd5SEyzjmnSr+yE6B8Wcu36d936uNP+6wcvLKP8kR1c56w/qE5KWIP45iQromn2lJK/2v2e/jlARzVNTYs+aMnVC6cIvNRXqn+pSDgeqj5+WHGGopd55cSx9gtk= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1783113847; 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=B9z9WHPmvLHevYFOtmsj0qG2r63h9YkhzzxvRZTeAmQ=; b=LvYC9pUpNg+p6LutyU6HiHv9QC9mwZb5hf85ap9RXGEbXNwExsB4YEHGRKvSfVqIqAqs9ejiQ1iS0au2+aQFGOaOzkm42jGgrohVctFR4EtQ+/6y5c2Ywui1z9ulWuNpPVZfG/UCtUExeO5RSHa2BEHp2lo4glZAt/+bGDpdM3o= 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 1783113847667758.3790450654755; Fri, 3 Jul 2026 14:24:07 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.1353883.1609632 (Exim 4.92) (envelope-from ) id 1wflMM-0005kO-Un; Fri, 03 Jul 2026 21:23:42 +0000 Received: by outflank-mailman (output) from mailman id 1353883.1609632; 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-0005jN-PI; Fri, 03 Jul 2026 21:23:42 +0000 Received: by outflank-mailman (input) for mailman id 1353883; Fri, 03 Jul 2026 21:23:42 +0000 Received: from mx.expurgate.net ([195.190.135.20]) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflMM-0005fl-0s for xen-devel@lists.xenproject.org; Fri, 03 Jul 2026 21:23:42 +0000 Received: from mx.expurgate.net (helo=localhost) by mx.expurgate.net with esmtp id 1wflML-00A83n-Dv; Fri, 03 Jul 2026 23:23:41 +0200 Received: from [10.42.69.2] (helo=localhost) by localhost with ESMTP (eXpurgate MTA 0.9.1) (envelope-from ) id 6a482855-e002-0a2a0a5209dd-0a2a450295e8-8 for ; Fri, 03 Jul 2026 23:23:41 +0200 Received: from [90.155.92.199] (helo=desiato.infradead.org) by tlsNG-720697.mxtls.expurgate.net with ESMTPS (eXpurgate 4.57.1) (envelope-from ) id 6a48285c-5a27-0a2a45020019-5a9b5cc7c936-3 for ; Fri, 03 Jul 2026 23:23:41 +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 1wflKc-000000059O2-31Bq; Fri, 03 Jul 2026 21:23:04 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.99.2 #2 (Red Hat Linux)) id 1wflKW-00000001ROh-26Xn; 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=B9z9WHPmvLHevYFOtmsj0qG2r63h9YkhzzxvRZTeAmQ=; b=onaWDNN2jSP0Q3PZPJs7nogpsV djN5zQDEAAEwp07PHEgjWunIEq3y03q0c8S7zV2OcMlYhl/J34JEKZ7hDMXXyEtTrI/81rwJ8Q8gM QFTPzOTXCK8UXssjTS9zoGTX9rQa4JMpnl9rJ36ID3INFYr2lBLrrofRd04iiPjaseA5YUq4XVSN+ P9NXmp10mCYVX7lINntbmHveElZKC1lFoVpWLbMkv65zJAIwkRzxBWGO+p0yyYJDfQF/6Kweqcw6j YMLtCZsL3NEMhJ26U9Dc5d2d7RIA/mGXd6lQ4sqAxNmH6Bvcz9akyjmHc63sIuT7ieyCDZ6azwkhU pCaM9FxA==; 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 14/36] KVM: x86: Use get_kvmclock() in kvm_get_wall_clock_epoch() Date: Fri, 3 Jul 2026 22:17:53 +0100 Message-ID: <20260703212145.343527-15-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-720697/1783113821-7751C7C5-1868F5BF/0/0 X-purgate-type: clean X-purgate-size: 3112 X-ZohoMail-DKIM: pass (identity @infradead.org) X-ZM-MESSAGEID: 1783113848897158500 Content-Type: text/plain; charset="utf-8" From: David Woodhouse Now that get_kvmclock() correctly handles TSC scaling and captures both wallclock and kvmclock from the same TSC reading, kvm_get_wall_clock_epoch() can simply call it instead of duplicating the pvclock computation. This eliminates the last instance of the "definition C" kvmclock calculation that computed nanoseconds directly from the host TSC without accounting for guest TSC scaling. Signed-off-by: David Woodhouse --- arch/x86/kvm/x86.c | 59 +++++++--------------------------------------- 1 file changed, 9 insertions(+), 50 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 65aa0fb0b5e1..376b8dc2ade9 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -3480,63 +3480,22 @@ int kvm_guest_time_update(struct kvm_vcpu *v) * wallclock and kvmclock times, and subtracting one from the other. * * Fall back to using their values at slightly different moments by - * calling ktime_get_real_ns() and get_kvmclock_ns() separately. + * calling ktime_get_real_ns() and get_kvmclock() separately. */ uint64_t kvm_get_wall_clock_epoch(struct kvm *kvm) { -#ifdef CONFIG_X86_64 - struct pvclock_vcpu_time_info hv_clock; - struct kvm_arch *ka =3D &kvm->arch; - unsigned long seq, local_tsc_khz; - struct timespec64 ts; - uint64_t host_tsc; - - do { - seq =3D read_seqcount_begin(&ka->pvclock_sc); - - local_tsc_khz =3D 0; - if (!ka->use_master_clock) - break; - - /* - * The TSC read and the call to get_cpu_tsc_khz() must happen - * on the same CPU. - */ - get_cpu(); - - local_tsc_khz =3D get_cpu_tsc_khz(); - - if (local_tsc_khz && - !kvm_get_walltime_and_clockread(&ts, &host_tsc)) - local_tsc_khz =3D 0; /* Fall back to old method */ - - put_cpu(); - - /* - * These values must be snapshotted within the seqcount loop. - * After that, it's just mathematics which can happen on any - * CPU at any time. - */ - hv_clock.tsc_timestamp =3D ka->master_cycle_now; - hv_clock.system_time =3D ka->master_kernel_ns + ka->kvmclock_offset; + struct kvm_clock_data data; =20 - } while (read_seqcount_retry(&ka->pvclock_sc, seq)); + get_kvmclock(kvm, &data); =20 /* - * If the conditions were right, and obtaining the wallclock+TSC was - * successful, calculate the KVM clock at the corresponding time and - * subtract one from the other to get the guest's epoch in nanoseconds - * since 1970-01-01. + * If get_kvmclock() captured both wallclock and kvmclock from the + * same TSC reading, use them for a precise epoch calculation. */ - if (local_tsc_khz) { - kvm_get_time_scale(NSEC_PER_SEC, local_tsc_khz * NSEC_PER_USEC, - &hv_clock.tsc_shift, - &hv_clock.tsc_to_system_mul); - return ts.tv_nsec + NSEC_PER_SEC * ts.tv_sec - - __pvclock_read_cycles(&hv_clock, host_tsc); - } -#endif - return ktime_get_real_ns() - get_kvmclock_ns(kvm); + if (data.flags & KVM_CLOCK_REALTIME) + return data.realtime - data.clock; + + return ktime_get_real_ns() - data.clock; } =20 /* --=20 2.54.0 From nobody Fri Jul 10 17:09:11 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=1783113856; cv=none; d=zohomail.com; s=zohoarc; b=CoWwuJaj8t81xQr+bIbN5YVpbL1pQa0lP7nkiZNhnFhDpDM8l4p7UlHRMTFB+etgsZRkOllcEm1FuaM8IbQjFNZr1TosxGjjamA7JN6Cjs/qp1LWqiugZ0Z/rlakZjQr9jsRnNQ35QQgBSBL8+TVE6o9JOfUxNypRCJJGogO0+o= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1783113856; 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=pFpNlCE+MJW0eKcLFgCCZwMvqjxRJ/tMcKVjrR0U73Q=; b=nKVidma8USBNfAzfgPuTeP4b7cdlI+BRIi8c0cN0G2sgICpWQHsnNLkKI8okb6MZ8609AjoC/Q/R8Zkuu+htA+isKXGIzZ1gSGX+U9QaU4mphqMGI8JqphGuQ0nV3UDOvt0f8+ecem/oUBYoYe2gKpCctpRpZ9ClKpdrnQfC2fA= 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 1783113856271984.3436430613805; Fri, 3 Jul 2026 14:24:16 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.1353900.1609665 (Exim 4.92) (envelope-from ) id 1wflMY-0007Fw-Rg; Fri, 03 Jul 2026 21:23:54 +0000 Received: by outflank-mailman (output) from mailman id 1353900.1609665; Fri, 03 Jul 2026 21:23:54 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflMY-0007FO-CF; Fri, 03 Jul 2026 21:23:54 +0000 Received: by outflank-mailman (input) for mailman id 1353900; Fri, 03 Jul 2026 21:23:52 +0000 Received: from mx.expurgate.net ([194.145.224.10]) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflMW-0006v9-Mq for xen-devel@lists.xenproject.org; Fri, 03 Jul 2026 21:23:52 +0000 Received: from mx.expurgate.net (helo=localhost) by mx.expurgate.net with esmtp id 1wflMW-00CejO-2E; Fri, 03 Jul 2026 23:23:52 +0200 Received: from [10.42.69.12] (helo=localhost) by localhost with ESMTP (eXpurgate MTA 0.9.1) (envelope-from ) id 6a48275c-bab6-0a2a0a5309dd-0a2a450c84ae-48 for ; Fri, 03 Jul 2026 23:23:52 +0200 Received: from [90.155.92.199] (helo=desiato.infradead.org) by tlsNG-d25034.mxtls.expurgate.net with ESMTPS (eXpurgate 4.57.1) (envelope-from ) id 6a482867-f399-0a2a450c0019-5a9b5cc7bdf0-3 for ; Fri, 03 Jul 2026 23:23:51 +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-000000059O3-3Oad; Fri, 03 Jul 2026 21:23:38 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.99.2 #2 (Red Hat Linux)) id 1wflKW-00000001ROl-2MEe; 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=pFpNlCE+MJW0eKcLFgCCZwMvqjxRJ/tMcKVjrR0U73Q=; b=qTsfnPqYdMDx4eUygFXJFljz/J HPP9ML6utEPbyFF37E1VztfM6jgMhMBh95PQ1lNByOYWgIaCp6JWwXn4CRiSdDQFDIubsZaIb1glB Pu8lGpAoP1cmJkXCbNxwxUkWPL34CuBc3XRH6b6uwshPpJHdqsbbOUZ4TmvT2K+ejBCcOwlpZY1Jb GjvaQoRWKExUh3UM+KhXoM+5PJv34XQ5X20qE921jQFhjoHQPWuJAMkL9/oLGBiIyvViWkFfekSOH a1X/CfCJ/Z+HF+xC8jpSbTeTXXtYydVpu1qQp7aurcyiShWJWGhkMCvXINe0EysHUaf8mOrj5+V/i 2xt5dohQ==; 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 15/36] KVM: x86: Fix compute_guest_tsc() to handle negative time deltas Date: Fri, 3 Jul 2026 22:17:54 +0100 Message-ID: <20260703212145.343527-16-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-d25034/1783113832-92F3BD51-96E90A37/0/0 X-purgate-type: clean X-purgate-size: 1721 X-ZohoMail-DKIM: pass (identity @infradead.org) X-ZM-MESSAGEID: 1783113856907158500 Content-Type: text/plain; charset="utf-8" From: David Woodhouse 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 --- 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, u= 32 user_tsc_khz) =20 static u64 compute_guest_tsc(struct kvm_vcpu *vcpu, s64 kernel_ns) { - u64 tsc =3D pvclock_scale_delta(kernel_ns-vcpu->arch.this_tsc_nsec, - vcpu->arch.virtual_tsc_mult, - vcpu->arch.virtual_tsc_shift); - tsc +=3D vcpu->arch.this_tsc_write; - return tsc; + s64 delta_ns =3D kernel_ns - vcpu->arch.this_tsc_nsec; + u64 tsc; + + /* Handle negative deltas gracefully (master clock ref may be earlier) */ + if (delta_ns < 0) { + tsc =3D pvclock_scale_delta(-delta_ns, + vcpu->arch.virtual_tsc_mult, + vcpu->arch.virtual_tsc_shift); + return vcpu->arch.this_tsc_write - tsc; + } + + tsc =3D pvclock_scale_delta(delta_ns, + vcpu->arch.virtual_tsc_mult, + vcpu->arch.virtual_tsc_shift); + return vcpu->arch.this_tsc_write + tsc; } =20 #ifdef CONFIG_X86_64 --=20 2.54.0 From nobody Fri Jul 10 17:09:11 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=1783113860; cv=none; d=zohomail.com; s=zohoarc; b=CkTniZcumVKG9ukdDjBqVOV15fr9JGyzviUJzEVOyPv0QHGaCT/E2VbyJGVzfJ+Fmn//CMgnh8ex7e1z03lyIiXfRLoa9r3O0tSDSyqbHGWyG+9n2MdZabLQTghPaJgPDHRMP/0D6mgemCwcK5tsWxHhq+eIjrl7bt4iCsH3KfQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1783113860; 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=mU5wFjlLT83r2DMLYPo2Un7WZ36IERFw89f8aTvqSMA=; b=KIMhBc3LIQ+7/vuVbTk0hCrHFSxwcCuMXIyZFTCIWiWQhF3X/HCkv844Tu4Br7ZxCBTslLtimasOb6vgv9LLeZacI0bUvzGF0Nzz7iFja/ARyLRriPo4Q9altfbGS5A6sVcG91gqlJgPZ88AxJDovJm4vB2TQVQJsFami/penpg= 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 1783113860492111.79092481891496; Fri, 3 Jul 2026 14:24:20 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.1353915.1609731 (Exim 4.92) (envelope-from ) id 1wflMi-0000rX-13; Fri, 03 Jul 2026 21:24:04 +0000 Received: by outflank-mailman (output) from mailman id 1353915.1609731; Fri, 03 Jul 2026 21:24:03 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflMg-0000mz-Ut; Fri, 03 Jul 2026 21:24:02 +0000 Received: by outflank-mailman (input) for mailman id 1353915; Fri, 03 Jul 2026 21:23:58 +0000 Received: from mx.expurgate.net ([194.145.224.10]) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflMb-0007x2-Fl for xen-devel@lists.xenproject.org; Fri, 03 Jul 2026 21:23:57 +0000 Received: from mx.expurgate.net (helo=localhost) by mx.expurgate.net with esmtp id 1wflMa-00CejO-SH; Fri, 03 Jul 2026 23:23:56 +0200 Received: from [10.42.69.3] (helo=localhost) by localhost with ESMTP (eXpurgate MTA 0.9.1) (envelope-from ) id 6a482835-bab6-0a2a0a5309dd-0a2a45038b46-28 for ; Fri, 03 Jul 2026 23:23:56 +0200 Received: from [90.155.92.199] (helo=desiato.infradead.org) by tlsNG-33051d.mxtls.expurgate.net with ESMTPS (eXpurgate 4.57.1) (envelope-from ) id 6a48286c-ec1a-0a2a45030019-5a9b5cc7915c-3 for ; Fri, 03 Jul 2026 23:23:56 +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-000000059O5-3OG6; Fri, 03 Jul 2026 21:23:38 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.99.2 #2 (Red Hat Linux)) id 1wflKW-00000001ROq-2d0k; 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=mU5wFjlLT83r2DMLYPo2Un7WZ36IERFw89f8aTvqSMA=; b=pLhCX7LKJ9jL0Egq3v1CQ2lbNB 6geYPA9+pnJQWRXzcRMfmIi6LmGdMv7pThTm9NBNqZ3oV/CLIRofkA9ghaM+kloYstTg6rGJ/uqbr GnQswAHHEQt//Hy0gqdhdsn2erC1pWE0fd77SkDgRHk6MqST5sk0bwspbMRnNR5szbd7Ymj8VJCst YU9p6hcjeyn6NnLTlQsfhXC1nz4OCMMSxlp07pY7lLsSATOEAODpqxY33VaH+awEptGUnxzsC6wQA YeA0u9LEqIHNkVIvkPfmzrOZ2vz+0FVTFKbgwlsKGY+yYpSVLKz1UcRj/XZobe/0Q+GwKKYcpYyCW 9ykmkL4g==; 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 16/36] KVM: x86: Restructure kvm_guest_time_update() for TSC upscaling Date: Fri, 3 Jul 2026 22:17:55 +0100 Message-ID: <20260703212145.343527-17-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-33051d/1783113836-BD1BE5D1-951A7974/0/0 X-purgate-type: clean X-purgate-size: 4893 X-ZohoMail-DKIM: pass (identity @infradead.org) X-ZM-MESSAGEID: 1783113860964158500 Content-Type: text/plain; charset="utf-8" From: David Woodhouse Restructure kvm_guest_time_update() so that kernel_ns/host_tsc are always "now" when doing TSC catchup, then swap in the master clock reference values afterward for the hv_clock. This makes the TSC upscaling code considerably simpler: the catchup adjustment is computed as the delta between what the guest TSC *should* be at "now" and what it actually is, rather than mixing "now" and "master clock reference" timestamps. The seqcount loop now also contains the kvm_get_time_and_clockread() call (matching get_kvmclock's pattern). Based on a suggestion by Sean Christopherson. Signed-off-by: David Woodhouse --- arch/x86/kvm/x86.c | 78 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 54 insertions(+), 24 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 55fb19fb7a88..9dc4213f0fa5 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -3349,45 +3349,60 @@ static void kvm_setup_guest_pvclock(struct pvclock_= vcpu_time_info *ref_hv_clock, int kvm_guest_time_update(struct kvm_vcpu *v) { struct pvclock_vcpu_time_info hv_clock =3D {}; - unsigned long flags; u64 tgt_tsc_hz; unsigned seq; struct kvm_vcpu_arch *vcpu =3D &v->arch; struct kvm_arch *ka =3D &v->kvm->arch; s64 kernel_ns; u64 tsc_timestamp, host_tsc; + u64 master_host_tsc =3D 0; + s64 master_kernel_ns =3D 0; + s64 kvmclock_offset =3D 0; bool use_master_clock; =20 - kernel_ns =3D 0; - host_tsc =3D 0; - /* * If the host uses TSC clock, then passthrough TSC as stable * to the guest. */ do { seq =3D read_seqcount_begin(&ka->pvclock_sc); + use_master_clock =3D ka->use_master_clock; + + /* + * The TSC read and the call to get_cpu_tsc_khz() must happen + * on the same CPU. + */ + get_cpu(); + + tgt_tsc_hz =3D (u64)get_cpu_tsc_khz() * 1000; + +#ifdef CONFIG_X86_64 + if (use_master_clock && + !kvm_get_time_and_clockread(&kernel_ns, &host_tsc) && + !read_seqcount_retry(&ka->pvclock_sc, seq)) + use_master_clock =3D false; +#endif + + put_cpu(); + if (use_master_clock) { - host_tsc =3D ka->master_cycle_now; - kernel_ns =3D ka->master_kernel_ns; + master_host_tsc =3D ka->master_cycle_now; + master_kernel_ns =3D ka->master_kernel_ns; + } else { + local_irq_disable(); + host_tsc =3D rdtsc(); + kernel_ns =3D get_kvmclock_base_ns(); + local_irq_enable(); } + + kvmclock_offset =3D ka->kvmclock_offset; } while (read_seqcount_retry(&ka->pvclock_sc, seq)); =20 - /* Keep irq disabled to prevent changes to the clock */ - local_irq_save(flags); - tgt_tsc_hz =3D (u64)get_cpu_tsc_khz() * 1000; if (unlikely(tgt_tsc_hz =3D=3D 0)) { - local_irq_restore(flags); kvm_make_request(KVM_REQ_CLOCK_UPDATE, v); return 1; } - if (!use_master_clock) { - host_tsc =3D rdtsc(); - kernel_ns =3D get_kvmclock_base_ns(); - } - - tsc_timestamp =3D kvm_read_l1_tsc(v, host_tsc); =20 /* * We may have to catch up the TSC to match elapsed wall clock @@ -3397,17 +3412,32 @@ int kvm_guest_time_update(struct kvm_vcpu *v) * entry to avoid unknown leaps of TSC even when running * again on the same CPU. This may cause apparent elapsed * time to disappear, and the guest to stand still or run - * very slowly. + * very slowly. */ if (vcpu->tsc_catchup) { - u64 tsc =3D compute_guest_tsc(v, kernel_ns); - if (tsc > tsc_timestamp) { - adjust_tsc_offset_guest(v, tsc - tsc_timestamp); - tsc_timestamp =3D tsc; - } + s64 adjustment; + + /* + * Calculate the delta between what the guest TSC *should* be + * and what it actually is according to kvm_read_l1_tsc(). + */ + adjustment =3D compute_guest_tsc(v, kernel_ns) - + kvm_read_l1_tsc(v, host_tsc); + if (adjustment > 0) + adjust_tsc_offset_guest(v, adjustment); } =20 - local_irq_restore(flags); + /* + * Now that TSC upscaling is out of the way, the remaining calculations + * are all relative to the reference time that's placed in hv_clock. + * If the master clock is NOT in use, the reference time is "now". If + * master clock is in use, the reference time comes from there. + */ + if (use_master_clock) { + host_tsc =3D master_host_tsc; + kernel_ns =3D master_kernel_ns; + } + tsc_timestamp =3D kvm_read_l1_tsc(v, host_tsc); =20 /* With all the info we got, fill in the values */ =20 @@ -3427,7 +3457,7 @@ int kvm_guest_time_update(struct kvm_vcpu *v) hv_clock.tsc_shift =3D vcpu->pvclock_tsc_shift; hv_clock.tsc_to_system_mul =3D vcpu->pvclock_tsc_mul; hv_clock.tsc_timestamp =3D tsc_timestamp; - hv_clock.system_time =3D kernel_ns + v->kvm->arch.kvmclock_offset; + hv_clock.system_time =3D kernel_ns + kvmclock_offset; vcpu->last_guest_tsc =3D tsc_timestamp; =20 /* If the host uses TSC clocksource, then it is stable */ --=20 2.54.0 From nobody Fri Jul 10 17:09:11 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=1783113827; cv=none; d=zohomail.com; s=zohoarc; b=QLIaAbRc78aP4tWjRYsBC2oGTg4+bSlUAkiqM2qmDwDbdduxGb23aJP0ejctYEGLiFq4U70jiC2c8BlRYfAmdI54ybB5qFLM8FvlDsGbtqU9n8lseDEPCa0M7WXk3dvNAPB1OIjdnlyXwPp2lv/zXUP6YSOCHPqjSEi+PCZpuhE= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1783113827; h=Content-Type: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=ydNYanTzV+rXuDAMNzpsQ17TnZayvJkNqhFCKKMsQXQ=; b=NiyG3UBQ3TJ/a+2jvxj+yQDAIWbSVU/CmYNfYWJE5rw1qs0ocMT2Tugfg6r7YCrxxaGRwV62q+kSdopsRy+nkX3VzCImsF6Arb2qLBe7gy3XJphSOJuPrQbrz5N783e2HTf8I07azf9dNW9GYswMN63DUPsAoCvEhYVNZlNaQ58= 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 1783113827820579.3319682032237; Fri, 3 Jul 2026 14:23:47 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.1353875.1609590 (Exim 4.92) (envelope-from ) id 1wflM6-0004RW-Er; Fri, 03 Jul 2026 21:23:26 +0000 Received: by outflank-mailman (output) from mailman id 1353875.1609590; Fri, 03 Jul 2026 21:23:26 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflM6-0004RP-Bk; Fri, 03 Jul 2026 21:23:26 +0000 Received: by outflank-mailman (input) for mailman id 1353875; Fri, 03 Jul 2026 21:23:25 +0000 Received: from mx.expurgate.net ([194.145.224.10]) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflM4-0004QN-ON for xen-devel@lists.xenproject.org; Fri, 03 Jul 2026 21:23:25 +0000 Received: from mx.expurgate.net (helo=localhost) by mx.expurgate.net with esmtp id 1wflM4-00CejO-5F; Fri, 03 Jul 2026 23:23:24 +0200 Received: from [10.42.69.3] (helo=localhost) by localhost with ESMTP (eXpurgate MTA 0.9.1) (envelope-from ) id 6a482835-bab6-0a2a0a5309dd-0a2a45038b46-12 for ; Fri, 03 Jul 2026 23:23:23 +0200 Received: from [90.155.92.199] (helo=desiato.infradead.org) by tlsNG-33051d.mxtls.expurgate.net with ESMTPS (eXpurgate 4.57.1) (envelope-from ) id 6a48284a-ec1a-0a2a45030019-5a9b5cc7ce42-3 for ; Fri, 03 Jul 2026 23:23:23 +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 1wflKY-000000059O6-1xMF; Fri, 03 Jul 2026 21:23:04 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.99.2 #2 (Red Hat Linux)) id 1wflKW-00000001ROv-2yUi; 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:Content-Type: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: Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:To: From:Reply-To:Cc:Content-ID:Content-Description; bh=ydNYanTzV+rXuDAMNzpsQ17TnZayvJkNqhFCKKMsQXQ=; b=oMsIAx+viNMO768Fm1dQ1GGaQK HXvg0RdzbGgsuyU4XEvhoMXSxjNjkwu5TbIxHkRRwfGkDZDe1Z4U8tJ6GLT0QO2ULe44BAftyOTbv aaFsMl9pLEPIW5nhCurlLhDQSFXMAlkIcVYGkGjlWSmASd1UGSg+vCw8weRL+ou3XrY8d/8LuRSbC 8/jZsf0YPkPlj4c1U57Nd8tJI6vJbUxLgJg9kHdwnvj/OHA4wyNNua2tIyY/ICjN9qfYH4GiS+luu QIUIDYxtlqNIQmClLOA15ZhWTJa5IvVzPxSBFxY7cLYtioKEIJgJcJE9Uoy0dATamc19dnoF+0clO wIaVaSdg==; 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 17/36] KVM: x86: Simplify and comment kvm_get_time_scale() Date: Fri, 3 Jul 2026 22:17:56 +0100 Message-ID: <20260703212145.343527-18-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-Type: text/plain; charset="utf-8" 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-33051d/1783113803-0652F5D1-4893E3B8/0/0 X-purgate-type: clean X-purgate-size: 3197 X-ZohoMail-DKIM: pass (identity @infradead.org) X-ZM-MESSAGEID: 1783113829095158500 From: David Woodhouse The kvm_get_time_scale() function was entirely opaque. Add comments explaining what it does: compute a fixed-point multiplier and shift for converting TSC ticks to nanoseconds via pvclock_scale_delta(). Rename the local variables from the cryptic tps64/tps32/scaled64 to base_hz_u64/base32/scaled_hz_u64 to make the code self-documenting. The "tps32" name stood for "Ticks Per Second" but was misleading since it held the shifted base frequency, not a tick count. No functional change. Signed-off-by: David Woodhouse Reviewed-by: Paul Durrant --- arch/x86/kvm/x86.c | 55 +++++++++++++++++++++++++++++++++------------- 1 file changed, 40 insertions(+), 15 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 9dc4213f0fa5..0087ddd08e83 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2472,32 +2472,57 @@ static uint32_t div_frac(uint32_t dividend, uint32_= t divisor) return dividend; } =20 -static void kvm_get_time_scale(uint64_t scaled_hz, uint64_t base_hz, +static void kvm_get_time_scale(u64 scaled_hz, u64 base_hz, s8 *pshift, u32 *pmultiplier) { - uint64_t scaled64; - int32_t shift =3D 0; - uint64_t tps64; - uint32_t tps32; + u64 scaled_hz_u64 =3D scaled_hz; + s32 shift =3D 0; + u64 base_hz_u64; + u32 base32; =20 - tps64 =3D base_hz; - scaled64 =3D scaled_hz; - while (tps64 > scaled64*2 || tps64 & 0xffffffff00000000ULL) { - tps64 >>=3D 1; + /* + * This function calculates a fixed-point multiplier and shift such + * that: + * time_ns =3D (tsc_cycles << shift) * multiplier >> 32 + * + * Where tsc_cycles tick at base_hz, and time_ns should count at + * scaled_hz (typically NSEC_PER_SEC for a TSC=E2=86=92nanoseconds conver= sion). + * + * The multiplier is: (scaled_hz << 32) / base_hz, adjusted by shift + * to keep everything in range. + */ + + base_hz_u64 =3D base_hz; + + /* + * Start by shifting base_hz right until it fits in 32 bits, and + * is lower than double the target rate. This introduces a negative + * shift value which would result in pvclock_scale_delta() shifting + * the actual tick count right before performing the multiplication. + */ + while (base_hz_u64 > scaled_hz_u64 * 2 || base_hz_u64 >> 32) { + base_hz_u64 >>=3D 1; shift--; } =20 - tps32 =3D (uint32_t)tps64; - while (tps32 <=3D scaled64 || scaled64 & 0xffffffff00000000ULL) { - if (scaled64 & 0xffffffff00000000ULL || tps32 & 0x80000000) - scaled64 >>=3D 1; + /* Now the shifted base_hz fits in 32 bits. */ + base32 =3D (u32)base_hz_u64; + + /* + * Next, shift scaled_hz right until it fits in 32 bits, and ensure + * that the shifted base_hz is strictly larger (so that the result of the + * final division also fits in 32 bits). + */ + while (base32 <=3D scaled_hz_u64 || scaled_hz_u64 >> 32) { + if (scaled_hz_u64 >> 32 || base32 & BIT(31)) + scaled_hz_u64 >>=3D 1; else - tps32 <<=3D 1; + base32 <<=3D 1; shift++; } =20 *pshift =3D shift; - *pmultiplier =3D div_frac(scaled64, tps32); + *pmultiplier =3D div_frac(scaled_hz_u64, base32); } =20 #ifdef CONFIG_X86_64 --=20 2.54.0 From nobody Fri Jul 10 17:09:11 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=1783113854; cv=none; d=zohomail.com; s=zohoarc; b=Zuhf//aVzrIZ48Gj2inkWRfMfAdskyC3zqeqZRKB1QNVo0HnmBnzBSHRhg+z6MiBYgyTVLEPydQpbzLvi+//CEdNqaYOAEvUtxwIKfJbsCvGvcolOuwM2rgaZ8eiO0kgEICpGy8lmO368LDucrgvmGLOs8ZvtbJQ6xBzDOa9kIA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1783113854; 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=shVwq4KBAoPWsH6/R3iiBMGtywtPoLEemfeJh0CtfZs=; b=eLonBWjTHZyKdpqQZ7mHAUFXVheJBak8bxBHri2Qg/qZ8CRihw1YFyzs7JKjacJl7yybBMg/Lw8Aj5tjvL637xrTFmtOwO5+CoZNia1c6E8QEFE4+Fk68Kbudje04LCsnwAa7L98RnN2u3zRpVstfXqzAk0V1SPmOprv9rCGRKs= 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 178311385451449.61320665770825; Fri, 3 Jul 2026 14:24:14 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.1353913.1609716 (Exim 4.92) (envelope-from ) id 1wflMf-0000EB-4H; Fri, 03 Jul 2026 21:24:01 +0000 Received: by outflank-mailman (output) from mailman id 1353913.1609716; Fri, 03 Jul 2026 21:24:00 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflMe-0000Au-72; Fri, 03 Jul 2026 21:24:00 +0000 Received: by outflank-mailman (input) for mailman id 1353913; Fri, 03 Jul 2026 21:23:56 +0000 Received: from mx.expurgate.net ([194.145.224.20]) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflMa-0007jg-H7 for xen-devel@lists.xenproject.org; Fri, 03 Jul 2026 21:23:56 +0000 Received: from mx.expurgate.net (helo=localhost) by mx.expurgate.net with esmtp id 1wflMZ-000kw0-TV; Fri, 03 Jul 2026 23:23:55 +0200 Received: from [10.42.69.12] (helo=localhost) by localhost with ESMTP (eXpurgate MTA 0.9.1) (envelope-from ) id 6a48286a-2eae-0a2a0a5409dd-0a2a450c8f72-2 for ; Fri, 03 Jul 2026 23:23:55 +0200 Received: from [90.155.92.199] (helo=desiato.infradead.org) by tlsNG-d25034.mxtls.expurgate.net with ESMTPS (eXpurgate 4.57.1) (envelope-from ) id 6a48286b-f399-0a2a450c0019-5a9b5cc7a078-3 for ; Fri, 03 Jul 2026 23:23:55 +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-000000059O7-0xa8; Fri, 03 Jul 2026 21:23:38 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.99.2 #2 (Red Hat Linux)) id 1wflKW-00000001RP0-3AEv; 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=shVwq4KBAoPWsH6/R3iiBMGtywtPoLEemfeJh0CtfZs=; b=SkZEUnibqnamMNvwwjyJzispV2 1MAtJAGPw1iTZJIRDZxFsdCIlehr1AJH72HcFSyB3jKCKJfw0Fd90BGAlMMMQdhA236xcz+KnrZt5 J6i/f9vm7aYd6lYLWiOLY+LqdIMG1Ummf9nhQjx/g01cPSSLh5/CKmfSk5kPOmdKGFOhCTL26KmEI ziGIU04PWq+VUBYLPAmIU9CwFFR6ay7jQAr64KUXu8sagOP2LGtLZxu7PLuu1f+oiXbDPU+92cEal OqD64ZglNnmvPA+hnXOyUgFGpeEPFJtjTQHmX1QHmakytiLhcqBRD3DUGTLbIfb+3qld2oG2YjZa1 kKLVzvmg==; 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 18/36] KVM: x86: Remove implicit rdtsc() from kvm_compute_l1_tsc_offset() Date: Fri, 3 Jul 2026 22:17:57 +0100 Message-ID: <20260703212145.343527-19-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-d25034/1783113835-0D526D51-A8B0B7BB/0/0 X-purgate-type: clean X-purgate-size: 2890 X-ZohoMail-DKIM: pass (identity @infradead.org) X-ZM-MESSAGEID: 1783113854924158500 Content-Type: text/plain; charset="utf-8" From: David Woodhouse Let the callers pass the host TSC value in as an explicit parameter. This leaves some fairly obviously stupid code, which is using this function to compare the guest TSC at some *other* time, with the newly-minted TSC value from rdtsc(). Unless it's being used to measure *elapsed* time, that isn't very sensible. In this case, "obviously stupid" is an improvement over being non-obviously so. No functional change intended. Signed-off-by: David Woodhouse Reviewed-by: Paul Durrant --- arch/x86/kvm/x86.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 0087ddd08e83..0fa2050f4bd4 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2693,11 +2693,12 @@ u64 kvm_scale_tsc(u64 tsc, u64 ratio) return _tsc; } =20 -static u64 kvm_compute_l1_tsc_offset(struct kvm_vcpu *vcpu, u64 target_tsc) +static u64 kvm_compute_l1_tsc_offset(struct kvm_vcpu *vcpu, u64 host_tsc, + u64 target_tsc) { u64 tsc; =20 - tsc =3D kvm_scale_tsc(rdtsc(), vcpu->arch.l1_tsc_scaling_ratio); + tsc =3D kvm_scale_tsc(host_tsc, vcpu->arch.l1_tsc_scaling_ratio); =20 return target_tsc - tsc; } @@ -2859,7 +2860,7 @@ static void kvm_synchronize_tsc(struct kvm_vcpu *vcpu= , u64 *user_value) bool synchronizing =3D false; =20 raw_spin_lock_irqsave(&kvm->arch.tsc_write_lock, flags); - offset =3D kvm_compute_l1_tsc_offset(vcpu, data); + offset =3D kvm_compute_l1_tsc_offset(vcpu, rdtsc(), data); ns =3D get_kvmclock_base_ns(); elapsed =3D ns - kvm->arch.last_tsc_nsec; =20 @@ -2908,7 +2909,7 @@ static void kvm_synchronize_tsc(struct kvm_vcpu *vcpu= , u64 *user_value) } else { u64 delta =3D nsec_to_cycles(vcpu, elapsed); data +=3D delta; - offset =3D kvm_compute_l1_tsc_offset(vcpu, data); + offset =3D kvm_compute_l1_tsc_offset(vcpu, rdtsc(), data); } matched =3D true; } @@ -4139,7 +4140,8 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct = msr_data *msr_info) if (msr_info->host_initiated) { kvm_synchronize_tsc(vcpu, &data); } else if (!vcpu->arch.guest_tsc_protected) { - u64 adj =3D kvm_compute_l1_tsc_offset(vcpu, data) - vcpu->arch.l1_tsc_o= ffset; + u64 adj =3D kvm_compute_l1_tsc_offset(vcpu, rdtsc(), data) - + vcpu->arch.l1_tsc_offset; adjust_tsc_offset_guest(vcpu, adj); vcpu->arch.ia32_tsc_adjust_msr +=3D adj; } @@ -5263,7 +5265,7 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cp= u) mark_tsc_unstable("KVM discovered backwards TSC"); =20 if (kvm_check_tsc_unstable()) { - u64 offset =3D kvm_compute_l1_tsc_offset(vcpu, + u64 offset =3D kvm_compute_l1_tsc_offset(vcpu, rdtsc(), vcpu->arch.last_guest_tsc); kvm_vcpu_write_tsc_offset(vcpu, offset); if (!vcpu->arch.guest_tsc_protected) --=20 2.54.0 From nobody Fri Jul 10 17:09:11 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=1783113764; cv=none; d=zohomail.com; s=zohoarc; b=LRC3DmxIcQwUhuc1LD304U5m8KJ8xH359l3hDh6HoR8KfDV8bhy82IS78mTvQmP79m/zxZZuH+iOfmC5vdbdLFShD2j6NL+HuN+1o/PKAuIERG6eoy4G915ROAhv/j+SDbCorZ6DHfH18vB/UJuPL7th/OkBR2prsGFQJamjJYI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1783113764; 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=aJbyYvbMlra4ob/lrPKW+13k0D2GomXNtoUlefAARyI=; b=bRY00brpw3iXz98ejBhBXWTQtoNapz8tic8GIMvleQF9laC03rQe6ith02+x9L2CmANhu496cSAdDx1AAfS8ftcP6SFFhfZa6jeq1tP4Y3HiaOSEvz+y5o/oKhPRQfXtJm+Z4cTDmDxwIuD9if4U1w/NcLQdefr7FA1bB57SjQk= 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 1783113764528105.40865435763897; Fri, 3 Jul 2026 14:22:44 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.1353759.1609520 (Exim 4.92) (envelope-from ) id 1wflKs-0006jt-2G; Fri, 03 Jul 2026 21:22:10 +0000 Received: by outflank-mailman (output) from mailman id 1353759.1609520; Fri, 03 Jul 2026 21:22:09 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflKr-0006gm-MO; Fri, 03 Jul 2026 21:22:09 +0000 Received: by outflank-mailman (input) for mailman id 1353759; Fri, 03 Jul 2026 21:22:07 +0000 Received: from mx.expurgate.net ([194.145.224.20]) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflKo-0005nZ-RA for xen-devel@lists.xenproject.org; Fri, 03 Jul 2026 21:22:06 +0000 Received: from mx.expurgate.net (helo=localhost) by mx.expurgate.net with esmtp id 1wflKo-00BXCb-80; Fri, 03 Jul 2026 23:22:06 +0200 Received: from [10.42.69.4] (helo=localhost) by localhost with ESMTP (eXpurgate MTA 0.9.1) (envelope-from ) id 6a4827c7-2eae-0a2a0a5409dd-0a2a4504c5b0-30 for ; Fri, 03 Jul 2026 23:22:06 +0200 Received: from [90.155.50.34] (helo=casper.infradead.org) by tlsNG-ebf023.mxtls.expurgate.net with ESMTPS (eXpurgate 4.57.1) (envelope-from ) id 6a4827f8-a01d-0a2a45040019-5a9b322291dc-3 for ; Fri, 03 Jul 2026 23:22:00 +0200 Received: from [2001:8b0:10b:1::425] (helo=i7.infradead.org) by casper.infradead.org with esmtpsa (Exim 4.99.1 #2 (Red Hat Linux)) id 1wflKW-0000000AsYA-412E; Fri, 03 Jul 2026 21:21:49 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.99.2 #2 (Red Hat Linux)) id 1wflKW-00000001RP5-3Puq; 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=casper.20170209 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=casper.20170209; 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=aJbyYvbMlra4ob/lrPKW+13k0D2GomXNtoUlefAARyI=; b=RUX0gU2BmZAS8Mc7MvtqcjpKaA 4X2GDo7Scxh/FJ1zfZj/ZZUyMDJLZdQtdY/yzpdVZO3bM/BQQLjwYOuR7nQJiiOLfJN8o9bXd0KEm l746azezEjoQE2RTg+hpkWKNpt6Vb5ogWz+nAFg5mQQ0InOMCWqd7vLGDc76I66RSvfzFQY+yfOne tJbmYqYf4y8NcSnh+ymr0gQ0qUnSjLlbP7a9/JcR68N/4qX/IVF7uUKlxqNM4lp3vkFKExekknJt9 4Ipax9FNfOZuryGMT0mvzgT9ncQ6Of+VmYZ1R2nRjr/PYhl4mTt99MskS2b0Erewa9tJ3yQ+Kw6dt ciUtLalA==; 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 19/36] KVM: x86: Improve synchronization in kvm_synchronize_tsc() Date: Fri, 3 Jul 2026 22:17:58 +0100 Message-ID: <20260703212145.343527-20-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 casper.infradead.org. See http://www.infradead.org/rpr.html X-purgate-ID: tlsNG-ebf023/1783113720-ACB3B1CC-02C39D49/0/0 X-purgate-type: clean X-purgate-size: 3475 X-ZohoMail-DKIM: pass (identity @infradead.org) X-ZM-MESSAGEID: 1783113766529158500 Content-Type: text/plain; charset="utf-8" From: David Woodhouse When synchronizing to an existing TSC (either by explicitly writing zero, or the legacy hack where the TSC is written within one second's worth of the previously written TSC), the last_tsc_write and last_tsc_nsec values were being misrecorded by __kvm_synchronize_tsc(). The *unsynchronized* value of the TSC (perhaps even zero) was being recorded, along with the current time at which kvm_synchronize_tsc() was called. This could cause *subsequent* writes to fail to synchronize correctly. Fix that by resetting {data, ns} to the previous values before passing them to __kvm_synchronize_tsc() when synchronization is detected. Except in the case where the TSC is unstable and *has* to be synthesised from the host clock, in which case attempt to create a nsec/tsc pair which is on the correct line. Furthermore, there were *three* different TSC reads used for calculating the "current" time, all slightly different from each other. Fix that by using kvm_get_time_and_clockread() where possible and using the same host_tsc value in all cases. Signed-off-by: David Woodhouse Reviewed-by: Paul Durrant --- arch/x86/kvm/x86.c | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 0fa2050f4bd4..ffe5f98a5688 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -203,6 +203,9 @@ module_param(mitigate_smt_rsb, bool, 0444); * usermode, e.g. SYSCALL MSRs and TSC_AUX, can be deferred until the CPU * returns to userspace, i.e. the kernel can run with the guest's value. */ +#ifdef CONFIG_X86_64 +static bool kvm_get_time_and_clockread(s64 *kernel_ns, u64 *tsc_timestamp); +#endif #define KVM_MAX_NR_USER_RETURN_MSRS 16 =20 struct kvm_user_return_msrs { @@ -2854,14 +2857,23 @@ static void kvm_synchronize_tsc(struct kvm_vcpu *vc= pu, u64 *user_value) { u64 data =3D user_value ? *user_value : 0; struct kvm *kvm =3D vcpu->kvm; - u64 offset, ns, elapsed; + u64 offset, host_tsc, elapsed; + s64 ns; unsigned long flags; bool matched =3D false; bool synchronizing =3D false; =20 raw_spin_lock_irqsave(&kvm->arch.tsc_write_lock, flags); - offset =3D kvm_compute_l1_tsc_offset(vcpu, rdtsc(), data); - ns =3D get_kvmclock_base_ns(); + +#ifdef CONFIG_X86_64 + if (!kvm_get_time_and_clockread(&ns, &host_tsc)) +#endif + { + host_tsc =3D rdtsc(); + ns =3D get_kvmclock_base_ns(); + } + + offset =3D kvm_compute_l1_tsc_offset(vcpu, host_tsc, data); elapsed =3D ns - kvm->arch.last_tsc_nsec; =20 if (vcpu->arch.virtual_tsc_khz) { @@ -2904,13 +2916,18 @@ static void kvm_synchronize_tsc(struct kvm_vcpu *vc= pu, u64 *user_value) */ if (synchronizing && vcpu->arch.virtual_tsc_khz =3D=3D kvm->arch.last_tsc_khz) { - if (!kvm_check_tsc_unstable()) { + /* + * If synchronizing, advance the reference point to "now" + * so the matching window slides forward with each vCPU. + */ + u64 delta =3D nsec_to_cycles(vcpu, elapsed); + + data =3D kvm->arch.cur_tsc_write + delta; + + if (!kvm_check_tsc_unstable()) offset =3D kvm->arch.cur_tsc_offset; - } else { - u64 delta =3D nsec_to_cycles(vcpu, elapsed); - data +=3D delta; - offset =3D kvm_compute_l1_tsc_offset(vcpu, rdtsc(), data); - } + else + offset =3D kvm_compute_l1_tsc_offset(vcpu, host_tsc, data); matched =3D true; } =20 --=20 2.54.0 From nobody Fri Jul 10 17:09:11 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=1783113761; cv=none; d=zohomail.com; s=zohoarc; b=B+GX72itEQ6K9kb4WYTMSdIIXtZf+2xwdr1yjctOJmW7T/msxTQ8F5Ei3LPvLOstwDWWO2eKe3qsk+p65UlTVUDrpPzZKOdWRRzPUzGq2AnVTLNQkZNXlWpSU7GX0Y19j+iKHR2yWZ/F9R8ysEQSvP7+0IPu+0B2ksWWk7t25iQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1783113761; 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=EXbsKVccUqJVUsNQz6ddm7iFrU6RHTQ7Y+Y2aEq7ws8=; b=k2zJ7OwLx57slYy6VVgjiOIjps0V6oYrJ2XtHifojQnZ2POeefxsgHLiK5mU7cXb+fJmyqrxhEeWzA2Ji1oGAbWAdYkoB8hKkNvv9TJJtBzX0LxdQv3q8XsINpo1keEeQ9hihCOycJp2j/TVjsgqEDVgbHvmQJSXmRpRHF37f5Q= 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 1783113761385483.1049666266482; Fri, 3 Jul 2026 14:22:41 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.1353753.1609467 (Exim 4.92) (envelope-from ) id 1wflKo-0005Z7-26; Fri, 03 Jul 2026 21:22:06 +0000 Received: by outflank-mailman (output) from mailman id 1353753.1609467; Fri, 03 Jul 2026 21:22:06 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflKn-0005Xe-TV; Fri, 03 Jul 2026 21:22:05 +0000 Received: by outflank-mailman (input) for mailman id 1353753; Fri, 03 Jul 2026 21:22:04 +0000 Received: from mx.expurgate.net ([194.145.224.10]) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflKm-00051o-8x for xen-devel@lists.xenproject.org; Fri, 03 Jul 2026 21:22:04 +0000 Received: from mx.expurgate.net (helo=localhost) by mx.expurgate.net with esmtp id 1wflKl-00CeeP-Lo; Fri, 03 Jul 2026 23:22:03 +0200 Received: from [10.42.69.10] (helo=localhost) by localhost with ESMTP (eXpurgate MTA 0.9.1) (envelope-from ) id 6a4827de-bab6-0a2a0a5309dd-0a2a450adcec-14 for ; Fri, 03 Jul 2026 23:22:02 +0200 Received: from [90.155.50.34] (helo=casper.infradead.org) by tlsNG-4011c0.mxtls.expurgate.net with ESMTPS (eXpurgate 4.57.1) (envelope-from ) id 6a4827fa-e40e-0a2a450a0019-5a9b3222c012-3 for ; Fri, 03 Jul 2026 23:22:02 +0200 Received: from [2001:8b0:10b:1::425] (helo=i7.infradead.org) by casper.infradead.org with esmtpsa (Exim 4.99.1 #2 (Red Hat Linux)) id 1wflKX-0000000AsYB-09Vp; Fri, 03 Jul 2026 21:21:49 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.99.2 #2 (Red Hat Linux)) id 1wflKW-00000001RP9-3lTW; 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=casper.20170209 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=casper.20170209; 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=EXbsKVccUqJVUsNQz6ddm7iFrU6RHTQ7Y+Y2aEq7ws8=; b=bmWLHuUVFitSUFZOTx9OuvAnfd xPH4uTWi9QwLkGQZiHcolsh2xvG2w+yaFIm6i3YV1ye8RBp7cKq+mwvTGGF+JhdBEMUE5bBTAdMKk 0IYlkrAN/MRrqOBcpHFfI+dzK6kbqckneRzOhdzUIj7qH+AWGPVy7JUQLJYgjbTPxlhB4eB5SwXmA uI1j/2xzbfvh6RW09eoS99Y3PPw//1OiHHNoYebGJIdwL13NuGPRTZD4QY77tAFfJcdzkJgJ6DjLo 8KHrwUNDMmWRZUUINWybBd1Ov9lHW3YVD/FKf6ETSPYBgbG7dkcdaqqxnn57QUV+cq3wubXh174y0 gUWoax4g==; 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 20/36] KVM: x86: Kill last_tsc_{nsec,write,offset} fields Date: Fri, 3 Jul 2026 22:17:59 +0100 Message-ID: <20260703212145.343527-21-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 casper.infradead.org. See http://www.infradead.org/rpr.html X-purgate-ID: tlsNG-4011c0/1783113722-CED3BDDE-051B5C97/0/0 X-purgate-type: clean X-purgate-size: 6394 X-ZohoMail-DKIM: pass (identity @infradead.org) X-ZM-MESSAGEID: 1783113763016158500 Content-Type: text/plain; charset="utf-8" From: David Woodhouse These pointlessly duplicate the cur_tsc_{nsec,write,offset} values. The only place they were used was where the TSC is stable and a new vCPU is being synchronized to the previous setting, in which case the cur_tsc_* value is definitely identical. Rename last_tsc_khz and last_tsc_scaling_ratio to cur_tsc_khz and cur_tsc_scaling_ratio respectively, since they are properties of the current TSC generation. Since cur_tsc_offset now serves as the single source of truth for the TSC generation's offset, the backwards-TSC adjustment (used during S4 resume when the host TSC resets) must also update cur_tsc_offset by the same delta applied to all vCPUs. Without this, subsequent vCPUs that synchronize after the adjustment would get the stale pre-S4 offset. Signed-off-by: David Woodhouse Reviewed-by: Paul Durrant --- arch/x86/include/asm/kvm_host.h | 7 ++--- arch/x86/kvm/x86.c | 45 +++++++++++++++++---------------- 2 files changed, 25 insertions(+), 27 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_hos= t.h index 87435ddecde1..e752b13c0809 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1486,11 +1486,8 @@ struct kvm_arch { * preemption-disabled region, so it must be a raw spinlock. */ raw_spinlock_t tsc_write_lock; - u64 last_tsc_nsec; - u64 last_tsc_write; - u32 last_tsc_khz; - u64 last_tsc_offset; - u64 last_tsc_scaling_ratio; + u32 cur_tsc_khz; + u64 cur_tsc_scaling_ratio; u64 cur_tsc_nsec; u64 cur_tsc_write; u64 cur_tsc_offset; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index ffe5f98a5688..478147aff56a 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2813,14 +2813,12 @@ static void __kvm_synchronize_tsc(struct kvm_vcpu *= vcpu, u64 offset, u64 tsc, vcpu->kvm->arch.user_set_tsc =3D true; =20 /* - * We also track th most recent recorded KHZ, write and time to - * allow the matching interval to be extended at each write. + * Track the TSC frequency, scaling ratio, and offset for the current + * generation. These are used to detect matching TSC writes and to + * compute the guest TSC from the host clock. */ - kvm->arch.last_tsc_nsec =3D ns; - 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; + kvm->arch.cur_tsc_khz =3D vcpu->arch.virtual_tsc_khz; + kvm->arch.cur_tsc_scaling_ratio =3D vcpu->arch.l1_tsc_scaling_ratio; =20 vcpu->arch.last_guest_tsc =3D tsc; =20 @@ -2833,8 +2831,6 @@ static void __kvm_synchronize_tsc(struct kvm_vcpu *vc= pu, u64 offset, u64 tsc, * nanosecond time, offset, and write, so if TSCs are in * sync, we can match exact offset, and if not, we can match * exact software computation in compute_guest_tsc() - * - * These values are tracked in kvm->arch.cur_xxx variables. */ kvm->arch.cur_tsc_generation++; kvm->arch.cur_tsc_nsec =3D ns; @@ -2874,7 +2870,7 @@ static void kvm_synchronize_tsc(struct kvm_vcpu *vcpu= , u64 *user_value) } =20 offset =3D kvm_compute_l1_tsc_offset(vcpu, host_tsc, data); - elapsed =3D ns - kvm->arch.last_tsc_nsec; + elapsed =3D ns - kvm->arch.cur_tsc_nsec; =20 if (vcpu->arch.virtual_tsc_khz) { if (data =3D=3D 0) { @@ -2884,7 +2880,7 @@ static void kvm_synchronize_tsc(struct kvm_vcpu *vcpu= , u64 *user_value) */ synchronizing =3D true; } else if (kvm->arch.user_set_tsc) { - u64 tsc_exp =3D kvm->arch.last_tsc_write + + u64 tsc_exp =3D kvm->arch.cur_tsc_write + nsec_to_cycles(vcpu, elapsed); u64 tsc_hz =3D vcpu->arch.virtual_tsc_khz * 1000LL; /* @@ -2915,7 +2911,7 @@ static void kvm_synchronize_tsc(struct kvm_vcpu *vcpu= , u64 *user_value) * it's better to try to match offsets from the beginning. */ if (synchronizing && - vcpu->arch.virtual_tsc_khz =3D=3D kvm->arch.last_tsc_khz) { + vcpu->arch.virtual_tsc_khz =3D=3D kvm->arch.cur_tsc_khz) { /* * If synchronizing, advance the reference point to "now" * so the matching window slides forward with each vCPU. @@ -3199,7 +3195,7 @@ static void pvclock_update_vm_gtod_copy(struct kvm *k= vm) * 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; + ka->master_tsc_scaling_ratio =3D ka->cur_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, @@ -6068,8 +6064,8 @@ static int kvm_arch_tsc_set_attr(struct kvm_vcpu *vcp= u, raw_spin_lock_irqsave(&kvm->arch.tsc_write_lock, flags); =20 matched =3D (vcpu->arch.virtual_tsc_khz && - kvm->arch.last_tsc_khz =3D=3D vcpu->arch.virtual_tsc_khz && - kvm->arch.last_tsc_offset =3D=3D offset); + kvm->arch.cur_tsc_khz =3D=3D vcpu->arch.virtual_tsc_khz && + kvm->arch.cur_tsc_offset =3D=3D offset); =20 tsc =3D kvm_scale_tsc(rdtsc(), vcpu->arch.l1_tsc_scaling_ratio) + offset; ns =3D get_kvmclock_base_ns(); @@ -13451,7 +13447,7 @@ int kvm_arch_enable_virtualization_cpu(void) { struct kvm *kvm; struct kvm_vcpu *vcpu; - unsigned long i; + unsigned long i, flags; int ret; u64 local_tsc; u64 max_tsc =3D 0; @@ -13530,13 +13526,18 @@ int kvm_arch_enable_virtualization_cpu(void) } =20 /* - * We have to disable TSC offset matching.. if you were - * booting a VM while issuing an S4 host suspend.... - * you may have some problem. Solving this issue is - * left as an exercise to the reader. + * Adjust the TSC matching reference by the same + * delta applied to each vCPU's offset, so that + * future KVM_SET_TSC / vCPU creation still matches + * correctly against the adjusted TSC timeline. + * Scale from host to guest TSC rate. */ - kvm->arch.last_tsc_nsec =3D 0; - kvm->arch.last_tsc_write =3D 0; + raw_spin_lock_irqsave(&kvm->arch.tsc_write_lock, flags); + kvm->arch.cur_tsc_write -=3D + kvm_scale_tsc(delta_cyc, + kvm->arch.cur_tsc_scaling_ratio); + kvm->arch.cur_tsc_offset +=3D delta_cyc; + raw_spin_unlock_irqrestore(&kvm->arch.tsc_write_lock, flags); } =20 } --=20 2.54.0 From nobody Fri Jul 10 17:09:11 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=1783113766; cv=none; d=zohomail.com; s=zohoarc; b=ZKCYlhmiDE8kgLyH/oUHl2ifNpxWowoIxbCVLti+ZF+10keyA3lnI1TZqe9B0cDhZzK+dBPuzpzZU2lrk7GKSEo8C2MIZOdFCG4qJQWJ8guMBiwIlkIXiibaQKCvVRBDucuXPNDh5UwdNBbF52pYjRBh32yRRd3hS76L2NQ1q+g= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1783113766; 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=sAJ+w5HRGJ1JE3H1Wx/huE4jGAY90IdO6mwCHpL6bJA=; b=PgIjYEb7wyYyqtlUeghZ0Qoth9wdMod37ZU2WpENIggPqWW9TurwOtVP+NJH3CKo4lEBIR6QCTJNbBOrkHHcft1S/EhkMLtBJcy/GDOtGbiLruuycjdJ7n+XIALyNRXx00jX4zkjI6TU/YzbSrdKD+GpPlHyCnp3t+nrMQ7RKSE= 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 1783113765930549.5241687945248; Fri, 3 Jul 2026 14:22:45 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.1353757.1609514 (Exim 4.92) (envelope-from ) id 1wflKr-0006dH-GM; Fri, 03 Jul 2026 21:22:09 +0000 Received: by outflank-mailman (output) from mailman id 1353757.1609514; Fri, 03 Jul 2026 21:22:09 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflKr-0006aR-6H; Fri, 03 Jul 2026 21:22:09 +0000 Received: by outflank-mailman (input) for mailman id 1353757; Fri, 03 Jul 2026 21:22:06 +0000 Received: from mx.expurgate.net ([194.145.224.20]) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflKo-0005h7-Ju for xen-devel@lists.xenproject.org; Fri, 03 Jul 2026 21:22:06 +0000 Received: from mx.expurgate.net (helo=localhost) by mx.expurgate.net with esmtp id 1wflKj-00BXCb-0b; Fri, 03 Jul 2026 23:22:06 +0200 Received: from [10.42.69.4] (helo=localhost) by localhost with ESMTP (eXpurgate MTA 0.9.1) (envelope-from ) id 6a4827c7-2eae-0a2a0a5409dd-0a2a4504c5b0-26 for ; Fri, 03 Jul 2026 23:22:00 +0200 Received: from [90.155.50.34] (helo=casper.infradead.org) by tlsNG-ebf023.mxtls.expurgate.net with ESMTPS (eXpurgate 4.57.1) (envelope-from ) id 6a4827f7-a01d-0a2a45040019-5a9b3222e448-3 for ; Fri, 03 Jul 2026 23:22:00 +0200 Received: from [2001:8b0:10b:1::425] (helo=i7.infradead.org) by casper.infradead.org with esmtpsa (Exim 4.99.1 #2 (Red Hat Linux)) id 1wflKX-0000000AsYC-0U5S; Fri, 03 Jul 2026 21:21:49 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.99.2 #2 (Red Hat Linux)) id 1wflKW-00000001RPD-46vV; Fri, 03 Jul 2026 22:21:49 +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=casper.20170209 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=casper.20170209; 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=sAJ+w5HRGJ1JE3H1Wx/huE4jGAY90IdO6mwCHpL6bJA=; b=fPnUdJ68VFN82oFjJj/i57tghy 0ZFD0hlumo0Eo/gYwzBln/e4uVYPLsis5GydyD/+Vy4w0rNcBsFWA+dW+Ch1zFGpDHSdlShsvrN6H 2XPhUzEfjC6LB0Tg162oU459VFP6GwWorQp5lrMES88+J5LfEdmILh5zqQipXPKBFQL+QF6Pjkixl 636TJb/z0HGrnDJ1GFdnnpOTdabYuoPygi84otBK2A9xaA55UpAOVjtSsMueaNRJPCWb+Nf+bWhfL UHPuZPEewOXB2c2BM4PG3/hV3K+2lePVnxjsArjeyD/3F2zSR5t6Hi71bD2Gy6MSpkMgA9oCaaUzU Dg0T/Ycw==; 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 21/36] KVM: x86: Replace nr_vcpus_matched_tsc count with all_vcpus_matched_tsc bool Date: Fri, 3 Jul 2026 22:18:00 +0100 Message-ID: <20260703212145.343527-22-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 casper.infradead.org. See http://www.infradead.org/rpr.html X-purgate-ID: tlsNG-ebf023/1783113720-AFD241CC-35407CC4/0/0 X-purgate-type: clean X-purgate-size: 2850 X-ZohoMail-DKIM: pass (identity @infradead.org) X-ZM-MESSAGEID: 1783113766521158500 Content-Type: text/plain; charset="utf-8" From: David Woodhouse Using a count and comparing with kvm->online_vcpus was always racy because a new vCPU could be created while kvm_track_tsc_matching() was running and comparing with kvm->online_vcpus. That variable is only atomic with respect to itself; kvm_arch_vcpu_create() runs before kvm->online_vcpus is incremented for the new vCPU. Replace the count with a boolean that is set in kvm_track_tsc_matching() after comparing the count, and cleared when a new TSC generation starts. The boolean is consumed by pvclock_update_vm_gtod_copy() under the tsc_write_lock, which serializes against __kvm_synchronize_tsc(). Keep the count for now as it's still used in the trace event. Signed-off-by: David Woodhouse --- arch/x86/include/asm/kvm_host.h | 1 + arch/x86/kvm/x86.c | 10 ++++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_hos= t.h index e752b13c0809..51d8bcbc2d1d 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1492,6 +1492,7 @@ struct kvm_arch { u64 cur_tsc_write; u64 cur_tsc_offset; u64 cur_tsc_generation; + bool all_vcpus_matched_tsc; int nr_vcpus_matched_tsc; =20 u32 default_tsc_khz; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 478147aff56a..83c47fe5c9b8 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2651,8 +2651,10 @@ static void kvm_track_tsc_matching(struct kvm_vcpu *= vcpu, bool new_generation) * and all vCPUs must have matching TSCs. Note, the count for matching * vCPUs doesn't include the reference vCPU, hence "+1". */ - bool use_master_clock =3D (ka->nr_vcpus_matched_tsc + 1 =3D=3D - atomic_read(&vcpu->kvm->online_vcpus)) && + ka->all_vcpus_matched_tsc =3D (ka->nr_vcpus_matched_tsc + 1 =3D=3D + atomic_read(&vcpu->kvm->online_vcpus)); + + bool use_master_clock =3D ka->all_vcpus_matched_tsc && gtod_is_based_on_tsc(gtod->clock.vclock_mode); =20 /* @@ -2837,6 +2839,7 @@ static void __kvm_synchronize_tsc(struct kvm_vcpu *vc= pu, u64 offset, u64 tsc, kvm->arch.cur_tsc_write =3D tsc; kvm->arch.cur_tsc_offset =3D offset; kvm->arch.nr_vcpus_matched_tsc =3D 0; + kvm->arch.all_vcpus_matched_tsc =3D false; } else if (vcpu->arch.this_tsc_generation !=3D kvm->arch.cur_tsc_generati= on) { kvm->arch.nr_vcpus_matched_tsc++; } @@ -3169,8 +3172,7 @@ static void pvclock_update_vm_gtod_copy(struct kvm *k= vm) bool host_tsc_clocksource, vcpus_matched; =20 lockdep_assert_held(&kvm->arch.tsc_write_lock); - vcpus_matched =3D (ka->nr_vcpus_matched_tsc + 1 =3D=3D - atomic_read(&kvm->online_vcpus)); + vcpus_matched =3D ka->all_vcpus_matched_tsc; =20 /* * If the host uses TSC clock, then passthrough TSC as stable --=20 2.54.0 From nobody Fri Jul 10 17:09:11 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=1783113870; cv=none; d=zohomail.com; s=zohoarc; b=ayvPcBAX+BOJFznVdR0bdjhW162DAFSppnzAfNBM+z+KTTRiU/9pmtzqjdfKo/Rfd8pZLqDLK/RvC9OWtKiJW9xd0iyk2F2cmiIaqiP32Rjafjw04QuxRBTkDvgmVSICP5Su6xS4q6xip/aEE0u6MqQHroGUU1olUbeje7x1hRk= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1783113870; h=Content-Type: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=R3kolXIrB5v3kRPh3GGJc2upCU64dX2iOOV3hTZ0WFA=; b=XFPHdwlyvzT2L5T2Uw28k7xlcvTHrESD6iXiLUlLdc2GhnqdmqxRyZHD5cHDHwHYy+NytfrA1kA9wxEhvi+tNAEWxAdTO5jx4GrOr5aXR9Fo96iqFOESfepJ0Go7sV1PTPQqxOdOGvdz0ciGSDv50q29Cqxe4Yh3m0Akuq/TcyE= 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 1783113870583214.22659399211943; Fri, 3 Jul 2026 14:24:30 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.1353914.1609724 (Exim 4.92) (envelope-from ) id 1wflMg-0000XB-D0; Fri, 03 Jul 2026 21:24:02 +0000 Received: by outflank-mailman (output) from mailman id 1353914.1609724; Fri, 03 Jul 2026 21:24:02 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflMf-0000Q5-CR; Fri, 03 Jul 2026 21:24:01 +0000 Received: by outflank-mailman (input) for mailman id 1353914; Fri, 03 Jul 2026 21:23:57 +0000 Received: from mx.expurgate.net ([194.145.224.20]) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflMa-0007jy-HN for xen-devel@lists.xenproject.org; Fri, 03 Jul 2026 21:23:56 +0000 Received: from mx.expurgate.net (helo=localhost) by mx.expurgate.net with esmtp id 1wflMZ-000kw0-U9; Fri, 03 Jul 2026 23:23:55 +0200 Received: from [10.42.69.9] (helo=localhost) by localhost with ESMTP (eXpurgate MTA 0.9.1) (envelope-from ) id 6a4827dc-2eae-0a2a0a5409dd-0a2a4509cd18-48 for ; Fri, 03 Jul 2026 23:23:55 +0200 Received: from [90.155.92.199] (helo=desiato.infradead.org) by tlsNG-bad1c0.mxtls.expurgate.net with ESMTPS (eXpurgate 4.57.1) (envelope-from ) id 6a48286b-97e6-0a2a45090019-5a9b5cc79a66-3 for ; Fri, 03 Jul 2026 23:23:55 +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-000000059O9-0xpH; Fri, 03 Jul 2026 21:23:38 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.99.2 #2 (Red Hat Linux)) id 1wflKX-00000001RPH-0GfY; Fri, 03 Jul 2026 22:21:49 +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:Content-Type: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: Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:To: From:Reply-To:Cc:Content-ID:Content-Description; bh=R3kolXIrB5v3kRPh3GGJc2upCU64dX2iOOV3hTZ0WFA=; b=EhYBXertXP5my1I9h4kbmXaNIu mnQI9h3PNrFrUq2Sp0GS+koN6FeHP7pXuM9lNKoJUfWQRMl+2GsyT2xxuCu2Lv8UecBHDmVRYOwHJ k5fDVDoCYaKlIgi0r3xyoTp3+mjuIVt1scTHSifB7mML8tKJWZL/ST5mZ4jBe6LgzbTcM+f7wY4nB S313GWO2jTa+j2fze8yAeMLDkAg6rsMu+k7lGr4284yb14qj98f9Tj5J3Lkx7EdZFjrddByve2YLp Gps6d02Cw5BQReD2TWZ0Bvd8I9bhzX3+lsqZcAU35+OtFaq9kj4c0fqgIKv4zHEv9edwvdqAhWX4z IQ7I+QVQ==; 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 22/36] KVM: x86: Allow KVM master clock mode when TSCs are offset from each other Date: Fri, 3 Jul 2026 22:18:01 +0100 Message-ID: <20260703212145.343527-23-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-Type: text/plain; charset="utf-8" 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-bad1c0/1783113835-45721986-A5634E7E/0/0 X-purgate-type: clean X-purgate-size: 9939 X-ZohoMail-DKIM: pass (identity @infradead.org) X-ZM-MESSAGEID: 1783113871075158500 From: David Woodhouse Previously, a guest writing different TSC values on different vCPUs could force KVM out of master clock mode. With this change, only a frequency mismatch disables master clock. The only ways for non-master-clock mode to happen now are archaic hardware without a TSC-based clocksource, a VMM that sets different TSC frequencies across vCPUs, or a guest using the legacy MSR_KVM_SYSTEM_TIME (which could be addressed in future by simply updating tsc_timestamp more frequently rather than falling out of master clock mode entirely). Running at a different frequency would lead to a systemic skew between the clock(s) as observed by different vCPUs due to arithmetic precision in the scaling. So that should indeed force the clock to be based on the host's CLOCK_MONOTONIC_RAW instead of being in masterclock mode where it is defined by the guest TSC. But when the vCPUs merely have a different TSC *offset*, that's not a problem. The offset is applied to that vCPU's kvmclock->tsc_timestamp field, and it all comes out in the wash. Track frequency matching separately from offset matching using a dedicated freq generation counter (cur_tsc_freq_generation) that only bumps on actual frequency changes. Each vCPU is counted exactly once per freq generation via a per-vCPU this_tsc_freq_generation field, preventing repeated syncs of the same vCPU from falsely re-enabling master clock. Note that the generation-based counting has a known limitation: if all vCPUs are in sync and one changes away and then back again, the other vCPUs are still at the old generation and won't be counted until they sync again (which may never happen). This was always the case for the offset tracking and isn't expected VMM behaviour =E2=80=94 although it is t= he scenario that the VM-wide KVM_SET_TSC_KHZ ioctl was introduced to handle cleanly. While at it, restructure the existing TSC offset generation tracking to use the same pattern: reset counter to zero on new generation, then unconditionally count vCPUs that haven't been seen in this generation. Both counters now use a consistent >=3D online_vcpus threshold (1-based counting where the reference vCPU is included in the count). Use frequency match for master clock eligibility, and full TSC match (including offset) only for PVCLOCK_TSC_STABLE_BIT, which tells the guest it is safe to skip cross-vCPU monotonicity enforcement. Signed-off-by: David Woodhouse --- arch/x86/include/asm/kvm_host.h | 4 ++ arch/x86/kvm/x86.c | 82 +++++++++++++++++++++++++-------- 2 files changed, 66 insertions(+), 20 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_hos= t.h index 51d8bcbc2d1d..da9141ea7d7b 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -970,6 +970,7 @@ struct kvm_vcpu_arch { u64 this_tsc_nsec; u64 this_tsc_write; u64 this_tsc_generation; + u64 this_tsc_freq_generation; bool tsc_catchup; bool tsc_always_catchup; s8 virtual_tsc_shift; @@ -1493,6 +1494,9 @@ struct kvm_arch { u64 cur_tsc_offset; u64 cur_tsc_generation; bool all_vcpus_matched_tsc; + bool all_vcpus_matched_freq; + int nr_vcpus_matched_freq; + u64 cur_tsc_freq_generation; int nr_vcpus_matched_tsc; =20 u32 default_tsc_khz; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 83c47fe5c9b8..3a651f5ce2d2 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2640,30 +2640,55 @@ static inline bool gtod_is_based_on_tsc(int mode) } #endif =20 -static void kvm_track_tsc_matching(struct kvm_vcpu *vcpu, bool new_generat= ion) +static void kvm_track_tsc_matching(struct kvm_vcpu *vcpu, bool update_mclo= ck) { #ifdef CONFIG_X86_64 struct kvm_arch *ka =3D &vcpu->kvm->arch; struct pvclock_gtod_data *gtod =3D &pvclock_gtod_data; + bool prev_matched_tsc =3D ka->all_vcpus_matched_tsc; =20 /* - * To use the masterclock, the host clocksource must be based on TSC - * and all vCPUs must have matching TSCs. Note, the count for matching - * vCPUs doesn't include the reference vCPU, hence "+1". + * Track whether all vCPUs have matching TSC offsets (for + * PVCLOCK_TSC_STABLE_BIT) and matching frequencies (for + * master clock eligibility). + */ + + /* + * A new vCPU might already have incremented ->online_vcpus + * and cause a temporary false negative here. But will then + * call kvm_synchronize_tsc() from kvm_arch_vcpu_postcreate() + * and finish the job. */ - ka->all_vcpus_matched_tsc =3D (ka->nr_vcpus_matched_tsc + 1 =3D=3D - atomic_read(&vcpu->kvm->online_vcpus)); + int online =3D atomic_read(&vcpu->kvm->online_vcpus); + ka->all_vcpus_matched_tsc =3D (ka->nr_vcpus_matched_tsc >=3D online); + + update_mclock |=3D (prev_matched_tsc !=3D ka->all_vcpus_matched_tsc); =20 - bool use_master_clock =3D ka->all_vcpus_matched_tsc && + /* + * all_vcpus_matched_freq starts true and is cleared when + * __kvm_synchronize_tsc() detects a frequency mismatch. + * Re-enable when all vCPUs have synced with matching frequency. + * If all offsets also match, that implies frequencies match too. + */ + if (ka->all_vcpus_matched_tsc || + ka->nr_vcpus_matched_freq >=3D online) + ka->all_vcpus_matched_freq =3D true; + + /* + * To use the masterclock, the host clocksource must be based on TSC + * and all vCPUs must have matching TSC *frequency*. Different offsets + * are fine =E2=80=94 each vCPU's pvclock has its own tsc_timestamp that + * accounts for its offset. + */ + bool use_master_clock =3D ka->all_vcpus_matched_freq && gtod_is_based_on_tsc(gtod->clock.vclock_mode); =20 /* - * Request a masterclock update if the masterclock needs to be toggled - * on/off, or when starting a new generation and the masterclock is - * enabled (compute_guest_tsc() requires the masterclock snapshot to be - * taken _after_ the new generation is created). + * Request a masterclock update if needed: toggling master clock, + * new generation requiring a fresh snapshot, or a change in + * all_vcpus_matched_tsc (to broadcast PVCLOCK_TSC_STABLE_BIT). */ - if ((ka->use_master_clock && new_generation) || + if ((ka->use_master_clock && update_mclock) || (ka->use_master_clock !=3D use_master_clock)) kvm_make_request(KVM_REQ_MASTERCLOCK_UPDATE, vcpu); =20 @@ -2818,7 +2843,22 @@ static void __kvm_synchronize_tsc(struct kvm_vcpu *v= cpu, u64 offset, u64 tsc, * Track the TSC frequency, scaling ratio, and offset for the current * generation. These are used to detect matching TSC writes and to * compute the guest TSC from the host clock. + * + * If the frequency changed, master clock mode can no longer be used + * since the kvmclock scaling factors differ between vCPUs. */ + if (vcpu->arch.virtual_tsc_khz !=3D kvm->arch.cur_tsc_khz) { + kvm->arch.cur_tsc_freq_generation++; + kvm->arch.all_vcpus_matched_freq =3D false; + kvm->arch.nr_vcpus_matched_freq =3D 0; + } + + /* Count each vCPU once per freq generation */ + if (vcpu->arch.this_tsc_freq_generation !=3D kvm->arch.cur_tsc_freq_gener= ation) { + vcpu->arch.this_tsc_freq_generation =3D kvm->arch.cur_tsc_freq_generatio= n; + kvm->arch.nr_vcpus_matched_freq++; + } + kvm->arch.cur_tsc_khz =3D vcpu->arch.virtual_tsc_khz; kvm->arch.cur_tsc_scaling_ratio =3D vcpu->arch.l1_tsc_scaling_ratio; =20 @@ -2835,17 +2875,18 @@ static void __kvm_synchronize_tsc(struct kvm_vcpu *= vcpu, u64 offset, u64 tsc, * exact software computation in compute_guest_tsc() */ kvm->arch.cur_tsc_generation++; + kvm->arch.all_vcpus_matched_tsc =3D false; + kvm->arch.nr_vcpus_matched_tsc =3D 0; kvm->arch.cur_tsc_nsec =3D ns; kvm->arch.cur_tsc_write =3D tsc; kvm->arch.cur_tsc_offset =3D offset; - kvm->arch.nr_vcpus_matched_tsc =3D 0; - kvm->arch.all_vcpus_matched_tsc =3D false; - } else if (vcpu->arch.this_tsc_generation !=3D kvm->arch.cur_tsc_generati= on) { + } + + if (vcpu->arch.this_tsc_generation !=3D kvm->arch.cur_tsc_generation) { + vcpu->arch.this_tsc_generation =3D kvm->arch.cur_tsc_generation; kvm->arch.nr_vcpus_matched_tsc++; } =20 - /* Keep track of which generation this VCPU has synchronized to */ - vcpu->arch.this_tsc_generation =3D kvm->arch.cur_tsc_generation; vcpu->arch.this_tsc_nsec =3D kvm->arch.cur_tsc_nsec; vcpu->arch.this_tsc_write =3D kvm->arch.cur_tsc_write; =20 @@ -3172,7 +3213,7 @@ static void pvclock_update_vm_gtod_copy(struct kvm *k= vm) bool host_tsc_clocksource, vcpus_matched; =20 lockdep_assert_held(&kvm->arch.tsc_write_lock); - vcpus_matched =3D ka->all_vcpus_matched_tsc; + vcpus_matched =3D ka->all_vcpus_matched_freq; =20 /* * If the host uses TSC clock, then passthrough TSC as stable @@ -3503,7 +3544,7 @@ int kvm_guest_time_update(struct kvm_vcpu *v) =20 /* If the host uses TSC clocksource, then it is stable */ hv_clock.flags =3D 0; - if (use_master_clock) + if (use_master_clock && ka->all_vcpus_matched_tsc) hv_clock.flags |=3D PVCLOCK_TSC_STABLE_BIT; =20 if (vcpu->pv_time.active) { @@ -6334,7 +6375,7 @@ static int kvm_vcpu_ioctl_get_clock_guest(struct kvm_= vcpu *v, void __user *argp) =20 hv_clock.tsc_shift =3D vcpu->pvclock_tsc_shift; hv_clock.tsc_to_system_mul =3D vcpu->pvclock_tsc_mul; - hv_clock.flags =3D PVCLOCK_TSC_STABLE_BIT; + hv_clock.flags =3D ka->all_vcpus_matched_tsc ? PVCLOCK_TSC_STABLE_BIT : 0; =20 if (copy_to_user(argp, &hv_clock, sizeof(hv_clock))) return -EFAULT; @@ -13641,6 +13682,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long= type) ratelimit_state_init(&kvm->arch.kvmclock_update_rs, HZ, 10); ratelimit_set_flags(&kvm->arch.kvmclock_update_rs, RATELIMIT_MSG_ON_RELEA= SE); kvm->arch.kvmclock_offset =3D -get_kvmclock_base_ns(); + kvm->arch.all_vcpus_matched_freq =3D true; =20 raw_spin_lock_irqsave(&kvm->arch.tsc_write_lock, flags); pvclock_update_vm_gtod_copy(kvm); --=20 2.54.0 From nobody Fri Jul 10 17:09:11 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=1783113866; cv=none; d=zohomail.com; s=zohoarc; b=NG23NWrZWNCjCn9T+THGjO8By02ZDYqZma0ia272YHcVMQqvrxt4cNuI1p/F77SVNcXZbwURDZYWtf9esffwez8caOT6rHIZ6ee887WRd7GpoOs6h5e+CT5Z7QvHi5LsCstKPR+C5H8nkkyS9UGd5nC1V25tXiCg8ssmb/vPPVw= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1783113866; h=Content-Type: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=wRdzvKD2bSU5nsIEUajIFrEJsqOT3VIHViFgVZVhuqk=; b=R+owTb6Df80W/gvX4cRrzvRfVMkYBmDGX5SsFaXrkrlCB5/lY7F1DbY2JC4ltA5mv7TsqP6/YnFSZdl81Xe9RBpGASgjtJiu76nd3IWjQzPexPG0mgU+nX5tvRt0gK+NZAZcCeGZwEcjoytPS+gljj0FAc4PYC+O5Lpb/J92j8Y= 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 1783113866400241.41556134000416; Fri, 3 Jul 2026 14:24:26 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.1353908.1609705 (Exim 4.92) (envelope-from ) id 1wflMd-0008E9-3e; Fri, 03 Jul 2026 21:23:59 +0000 Received: by outflank-mailman (output) from mailman id 1353908.1609705; Fri, 03 Jul 2026 21:23:59 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflMc-0008A0-EG; Fri, 03 Jul 2026 21:23:58 +0000 Received: by outflank-mailman (input) for mailman id 1353908; Fri, 03 Jul 2026 21:23:54 +0000 Received: from mx.expurgate.net ([195.190.135.10]) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflMY-0007C5-A7 for xen-devel@lists.xenproject.org; Fri, 03 Jul 2026 21:23:54 +0000 Received: from mx.expurgate.net (helo=localhost) by mx.expurgate.net with esmtp id 1wflMX-001XO6-N0; Fri, 03 Jul 2026 23:23:53 +0200 Received: from [10.42.69.5] (helo=localhost) by localhost with ESMTP (eXpurgate MTA 0.9.1) (envelope-from ) id 6a4827d9-5cb7-0a2a0a5109dd-0a2a4505dcf2-44 for ; Fri, 03 Jul 2026 23:23:53 +0200 Received: from [90.155.92.199] (helo=desiato.infradead.org) by tlsNG-c201ff.mxtls.expurgate.net with ESMTPS (eXpurgate 4.57.1) (envelope-from ) id 6a482869-3cb2-0a2a45050019-5a9b5cc79154-3 for ; Fri, 03 Jul 2026 23:23:53 +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 1wflKc-000000059OA-40uX; Fri, 03 Jul 2026 21:23:38 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.99.2 #2 (Red Hat Linux)) id 1wflKX-00000001RPL-0RPj; Fri, 03 Jul 2026 22:21:49 +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:Content-Type: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: Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:To: From:Reply-To:Cc:Content-ID:Content-Description; bh=wRdzvKD2bSU5nsIEUajIFrEJsqOT3VIHViFgVZVhuqk=; b=i2HbQgc8AAYdlD8WujdrvoPn1U qoodV8ewcMdiGBQg69o486bMpQqj3pTV6LFQ+p4lqOS+REgBO5BemjRGoJIYKDskYoX3dzxU/dlWs fn2vzHq+FScArRGbLA7uB4jy7vpg8ka9zk3nmtu49+oDQijwv+s28SVc4L6+1aNJSTs0xpcGVGk+4 PUaalf6n5Bs4BQ+P+PIB8knTn4QDDa19PFHuBjY+s0Xdh5h6LrgJk/Hs3e1pM9yixhVu0mhnBsWjJ q2hW1MEceXMx6MN7p1chCFiOsbQ0DLRYilZs1FhSzRg3dTm8+BBZ+L5AdoSzqbp/un2xzu5DlNmAh h7pBrsWw==; 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 23/36] KVM: selftests: Add master clock offset test Date: Fri, 3 Jul 2026 22:18:02 +0100 Message-ID: <20260703212145.343527-24-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-Type: text/plain; charset="utf-8" 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-c201ff/1783113833-151042B8-9021AFCA/0/0 X-purgate-type: clean X-purgate-size: 8060 X-ZohoMail-DKIM: pass (identity @infradead.org) X-ZM-MESSAGEID: 1783113867064158500 From: David Woodhouse Verify that KVM master clock mode remains active when vCPUs have different TSC offsets but the same frequency. Creates three vCPUs, sets one to a different TSC value, and confirms: - KVM_CLOCK_HOST_TSC is set (master clock active) - KVM_CLOCK_TSC_STABLE IS set (master clock =E2=87=92 stable flag) - PVCLOCK_TSC_STABLE_BIT is NOT set (offsets differ) Signed-off-by: David Woodhouse Assisted-by: Kiro (claude-opus-4.6-1m) --- tools/testing/selftests/kvm/Makefile.kvm | 1 + .../kvm/x86/masterclock_offset_test.c | 180 ++++++++++++++++++ 2 files changed, 181 insertions(+) create mode 100644 tools/testing/selftests/kvm/x86/masterclock_offset_test= .c diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selft= ests/kvm/Makefile.kvm index 90568ab631d7..7ecaaf82056e 100644 --- a/tools/testing/selftests/kvm/Makefile.kvm +++ b/tools/testing/selftests/kvm/Makefile.kvm @@ -106,6 +106,7 @@ TEST_GEN_PROGS_x86 +=3D x86/pmu_event_filter_test TEST_GEN_PROGS_x86 +=3D x86/private_mem_conversions_test TEST_GEN_PROGS_x86 +=3D x86/private_mem_kvm_exits_test TEST_GEN_PROGS_x86 +=3D x86/pvclock_test +TEST_GEN_PROGS_x86 +=3D x86/masterclock_offset_test TEST_GEN_PROGS_x86 +=3D x86/pvclock_migration_test TEST_GEN_PROGS_x86 +=3D x86/set_boot_cpu_id TEST_GEN_PROGS_x86 +=3D x86/set_sregs_test diff --git a/tools/testing/selftests/kvm/x86/masterclock_offset_test.c b/to= ols/testing/selftests/kvm/x86/masterclock_offset_test.c new file mode 100644 index 000000000000..88e2bd2edab5 --- /dev/null +++ b/tools/testing/selftests/kvm/x86/masterclock_offset_test.c @@ -0,0 +1,180 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Test that KVM master clock mode works with different TSC offsets + * as long as all vCPUs have the same TSC frequency. + */ +#include +#include + +#include "test_util.h" +#include "kvm_util.h" +#include "processor.h" + +#include + +#define KVMCLOCK_GPA 0xc0000000ull +#define TSC_OFFSET (1000000000ULL) + +static uint64_t pvclock_calc(struct pvclock_vcpu_time_info *pvti, uint64_t= guest_tsc) +{ + uint64_t delta =3D guest_tsc - pvti->tsc_timestamp; + + if (pvti->tsc_shift >=3D 0) + delta <<=3D pvti->tsc_shift; + else + delta >>=3D -(int)pvti->tsc_shift; + + return pvti->system_time + ((__uint128_t)delta * pvti->tsc_to_system_mul = >> 32); +} + +static void guest_code(void) +{ + wrmsr(MSR_KVM_SYSTEM_TIME_NEW, KVMCLOCK_GPA | KVM_MSR_ENABLED); + for (;;) + GUEST_SYNC(0); +} + +int main(void) +{ + struct kvm_vcpu *vcpus[3]; + struct kvm_clock_data clock; + struct pvclock_vcpu_time_info pvti[3]; + struct kvm_vm *vm; + uint64_t offset0, host_tsc, clk0, clk2; + int i; + + TEST_REQUIRE(sys_clocksource_is_based_on_tsc()); + + vm =3D vm_create_with_vcpus(3, guest_code, vcpus); + + TEST_REQUIRE(!__vcpu_has_device_attr(vcpus[0], KVM_VCPU_TSC_CTRL, + KVM_VCPU_TSC_OFFSET)); + + vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, + KVMCLOCK_GPA, 1, + vm_calc_num_guest_pages(VM_MODE_DEFAULT, + getpagesize()), 0); + virt_map(vm, KVMCLOCK_GPA, KVMCLOCK_GPA, + vm_calc_num_guest_pages(VM_MODE_DEFAULT, getpagesize())); + + /* Get vCPU 0's default offset and set vCPU 2's offset higher */ + vcpu_device_attr_get(vcpus[0], KVM_VCPU_TSC_CTRL, + KVM_VCPU_TSC_OFFSET, &offset0); + uint64_t offset2 =3D offset0 + TSC_OFFSET; + vcpu_device_attr_set(vcpus[2], KVM_VCPU_TSC_CTRL, + KVM_VCPU_TSC_OFFSET, &offset2); + + /* Run each vCPU to enable kvmclock (with offset already set) */ + for (i =3D 0; i < 3; i++) { + vcpu_run(vcpus[i]); + TEST_ASSERT_KVM_EXIT_REASON(vcpus[i], KVM_EXIT_IO); + } + + /* Check master clock is active */ + memset(&clock, 0, sizeof(clock)); + vm_ioctl(vm, KVM_GET_CLOCK, &clock); + pr_info("KVM_GET_CLOCK flags: 0x%x\n", clock.flags); + TEST_ASSERT(clock.flags & KVM_CLOCK_HOST_TSC, + "Master clock should be active, flags=3D0x%x", clock.flags); + TEST_ASSERT(clock.flags & KVM_CLOCK_TSC_STABLE, + "KVM_CLOCK_TSC_STABLE should be set, flags=3D0x%x", clock.flags); + + /* Get per-vCPU pvclock in order 0, 2, 1 */ + int order[] =3D {0, 2, 1}; + for (i =3D 0; i < 3; i++) { + int idx =3D order[i]; + __vcpu_ioctl(vcpus[idx], KVM_GET_CLOCK_GUEST, &pvti[idx]); + pr_info("vCPU %d: tsc_timestamp=3D%lu system_time=3D%lu " + "mul=3D%u shift=3D%d flags=3D0x%x\n", + idx, (unsigned long)pvti[idx].tsc_timestamp, + (unsigned long)pvti[idx].system_time, + pvti[idx].tsc_to_system_mul, pvti[idx].tsc_shift, + pvti[idx].flags); + } + + /* Read guest TSCs: should see (0+OFF) < 2 < (1+OFF) */ + uint64_t gtsc0 =3D vcpu_get_msr(vcpus[0], MSR_IA32_TSC); + uint64_t gtsc2 =3D vcpu_get_msr(vcpus[2], MSR_IA32_TSC); + uint64_t gtsc1 =3D vcpu_get_msr(vcpus[1], MSR_IA32_TSC); + pr_info("Guest TSCs: vcpu0=3D%lu vcpu2=3D%lu vcpu1=3D%lu\n", + (unsigned long)gtsc0, (unsigned long)gtsc2, (unsigned long)gtsc1); + pr_info("vcpu0+OFF=3D%lu vcpu1+OFF=3D%lu\n", + (unsigned long)(gtsc0 + TSC_OFFSET), + (unsigned long)(gtsc1 + TSC_OFFSET)); + TEST_ASSERT(gtsc0 + TSC_OFFSET < gtsc2 && gtsc2 < gtsc1 + TSC_OFFSET, + "Expected (vcpu0+OFF) < vcpu2 < (vcpu1+OFF)"); + + /* PVCLOCK_TSC_STABLE_BIT should NOT be set (offsets differ) */ + TEST_ASSERT(!(pvti[2].flags & PVCLOCK_TSC_STABLE_BIT), + "PVCLOCK_TSC_STABLE_BIT should NOT be set, flags=3D0x%x", + pvti[2].flags); + + /* Same mul/shift */ + TEST_ASSERT(pvti[0].tsc_to_system_mul =3D=3D pvti[2].tsc_to_system_mul && + pvti[0].tsc_shift =3D=3D pvti[2].tsc_shift, + "All vCPUs should have same mul/shift"); + + /* + * Read host TSC once. At this instant: + * vCPU 0 guest TSC =3D host_tsc + offset0 + * vCPU 2 guest TSC =3D host_tsc + offset0 + TSC_OFFSET + * Feed each through its pvclock. Expect the same kvmclock. + */ + host_tsc =3D rdtsc(); + clk0 =3D pvclock_calc(&pvti[0], host_tsc + offset0); + clk2 =3D pvclock_calc(&pvti[2], host_tsc + offset0 + TSC_OFFSET); + + pr_info("kvmclock via vCPU 0: %lu ns\n", (unsigned long)clk0); + pr_info("kvmclock via vCPU 2: %lu ns\n", (unsigned long)clk2); + TEST_ASSERT(clk0 =3D=3D clk2, + "kvmclock from offset vCPUs should match exactly, " + "diff=3D%ld ns", (long)(clk2 - clk0)); + + pr_info("PASSED: pvclock consistent across offset vCPUs\n"); + + /* + * Now add an hour to the VM kvmclock via KVM_SET_CLOCK, run each + * vCPU to pick up the update, and check they're still in sync. + */ + { +#define ONE_HOUR_NS (3600ULL * NSEC_PER_SEC) + struct kvm_clock_data setclk =3D { .clock =3D clock.clock + ONE_HOUR_NS = }; + + vm_ioctl(vm, KVM_SET_CLOCK, &setclk); + } + + /* Guest code does GUEST_SYNC then exits =E2=80=94 run each to see update= */ + for (i =3D 0; i < 3; i++) { + vcpu_run(vcpus[order[i]]); + TEST_ASSERT_KVM_EXIT_REASON(vcpus[order[i]], KVM_EXIT_IO); + } + + /* Re-read pvclocks */ + for (i =3D 0; i < 3; i++) + __vcpu_ioctl(vcpus[order[i]], KVM_GET_CLOCK_GUEST, &pvti[order[i]]); + + pr_info("After +1h: vCPU 0 system_time=3D%lu, vCPU 2 system_time=3D%lu\n", + (unsigned long)pvti[0].system_time, + (unsigned long)pvti[2].system_time); + TEST_ASSERT(pvti[0].system_time =3D=3D pvti[2].system_time, + "system_time should still match after KVM_SET_CLOCK"); + + host_tsc =3D rdtsc(); + clk0 =3D pvclock_calc(&pvti[0], host_tsc + offset0); + clk2 =3D pvclock_calc(&pvti[2], host_tsc + offset0 + TSC_OFFSET); + + pr_info("After +1h: kvmclock via vCPU 0: %lu ns\n", (unsigned long)clk0); + pr_info("After +1h: kvmclock via vCPU 2: %lu ns\n", (unsigned long)clk2); + TEST_ASSERT(clk0 =3D=3D clk2, + "After +1h: kvmclock should still match, diff=3D%ld ns", + (long)(clk2 - clk0)); + + /* Verify the clock actually moved by ~1 hour */ + TEST_ASSERT(clk0 > ONE_HOUR_NS, + "Clock should be > 1 hour after set, got %lu ns", + (unsigned long)clk0); + + pr_info("PASSED: pvclock still consistent after KVM_SET_CLOCK +1h\n"); + kvm_vm_free(vm); + return 0; +} --=20 2.54.0 From nobody Fri Jul 10 17:09:11 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=1783113762; cv=none; d=zohomail.com; s=zohoarc; b=mgB1lx6kwdAYph3i9XnadaFJBhKkCXca84XJA34B20NWka7AiL+KLO69eTm5jGcK1H+r8WDyWjYYMrl99Vugn2g8dRPt+fFOT9ozq+2WmUAX1FOlE3WQwilZuOqmhBh+zfDnBsxEeQ3v2s1RZU0gAtCeVVxQKS3x+/KEiMtioM8= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1783113762; h=Content-Type: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=LCPHKocQxei12eLOnimwDSC7Gdxv3emgr2rZMstPsfQ=; b=bRKnYgFHE+LjNrdQrIKs00tlpEBWVrfzuDznqB4kn7oxTnDOkT8te8mywTiGQA77w1bfHrWuN5NxnXHhW54IRLFL7XXC/ZO3uDDzdO6SCs2JAsIuOyg+T6UuABEOq77bsZN0RkSRTBvCpOHpnF3DxViwM8w/Ci/MnhjbZ+UWUmY= 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 1783113762127425.0007100073825; Fri, 3 Jul 2026 14:22:42 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.1353763.1609555 (Exim 4.92) (envelope-from ) id 1wflKy-0008BG-9m; Fri, 03 Jul 2026 21:22:16 +0000 Received: by outflank-mailman (output) from mailman id 1353763.1609555; Fri, 03 Jul 2026 21:22:16 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflKy-0008B2-6D; Fri, 03 Jul 2026 21:22:16 +0000 Received: by outflank-mailman (input) for mailman id 1353763; Fri, 03 Jul 2026 21:22:14 +0000 Received: from mx.expurgate.net ([194.145.224.10]) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflKw-00081M-88 for xen-devel@lists.xenproject.org; Fri, 03 Jul 2026 21:22:14 +0000 Received: from mx.expurgate.net (helo=localhost) by mx.expurgate.net with esmtp id 1wflKv-00CeeP-LH; Fri, 03 Jul 2026 23:22:13 +0200 Received: from [10.42.69.10] (helo=localhost) by localhost with ESMTP (eXpurgate MTA 0.9.1) (envelope-from ) id 6a4827de-bab6-0a2a0a5309dd-0a2a450adcec-24 for ; Fri, 03 Jul 2026 23:22:13 +0200 Received: from [90.155.50.34] (helo=casper.infradead.org) by tlsNG-4011c0.mxtls.expurgate.net with ESMTPS (eXpurgate 4.57.1) (envelope-from ) id 6a482805-e40e-0a2a450a0019-5a9b3222ce60-3 for ; Fri, 03 Jul 2026 23:22:13 +0200 Received: from [2001:8b0:10b:1::425] (helo=i7.infradead.org) by casper.infradead.org with esmtpsa (Exim 4.99.1 #2 (Red Hat Linux)) id 1wflKX-0000000AsYD-0x2z; Fri, 03 Jul 2026 21:21:49 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.99.2 #2 (Red Hat Linux)) id 1wflKX-00000001RPP-0bzt; Fri, 03 Jul 2026 22:21:49 +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=casper.20170209 header.d=infradead.org header.i="@infradead.org" header.h="Sender:Content-Transfer-Encoding:Content-Type: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=casper.20170209; h=Sender:Content-Transfer-Encoding: Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:To: From:Reply-To:Cc:Content-ID:Content-Description; bh=LCPHKocQxei12eLOnimwDSC7Gdxv3emgr2rZMstPsfQ=; b=D+gxe+zOcTheHMuzWnvdCppNWA 57JVykAHl5rRTwt63XLCRD1vkYCu3NQBErzPcDEbuP+MaahyYUw5hq3EwgT7E4w2h7Gg0Ma1b5I9c y+FhSO1tI4GXlHfRW+zlB1kpu6M0vVZhLe9024hdHZX3BeH+AbDSkFNkPcop8uZEzpFkwZZTViDED XNcIi+iHLsu+wlkRd+qUOzLAXeurJLINvTyk2DBnlnB/8mRDQeMAjew2fmG/MNXpKG+17Z+JFWmfB M+I6BAQ6bxpzkaSzDdefvG7Z1bLT2dKVd2DTwpsBwrI0PN2j3OaH1YdS6A6i80wBBLY9y/hrMp1mS kde8DTaQ==; 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 24/36] KVM: x86: Factor out kvm_use_master_clock() Date: Fri, 3 Jul 2026 22:18:03 +0100 Message-ID: <20260703212145.343527-25-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-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Sender: David Woodhouse X-SRS-Rewrite: SMTP reverse-path rewritten from by casper.infradead.org. See http://www.infradead.org/rpr.html X-purgate-ID: tlsNG-4011c0/1783113733-D6B3CDDE-1712DCFB/0/0 X-purgate-type: clean X-purgate-size: 4292 X-ZohoMail-DKIM: pass (identity @infradead.org) X-ZM-MESSAGEID: 1783113764544158500 From: David Woodhouse Both kvm_track_tsc_matching() and pvclock_update_vm_gtod_copy() make a decision about whether the KVM clock should be in master clock mode. They used *different* criteria for the decision though. This isn't really a problem; it only has the potential to cause unnecessary invocations of KVM_REQ_MASTERCLOCK_UPDATE if the masterclock was disabled due to TSC going backwards, or the guest using the old MSR. But it isn't pretty. Factor the decision out to a single function. And document the historical reason why it's disabled for guests that use the old MSR_KVM_SYSTEM_TIME. Signed-off-by: David Woodhouse Reviewed-by: Paul Durrant --- arch/x86/kvm/x86.c | 40 ++++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 3a651f5ce2d2..f8883c3b8ed2 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2638,11 +2638,30 @@ static inline bool gtod_is_based_on_tsc(int mode) { return mode =3D=3D VDSO_CLOCKMODE_TSC || mode =3D=3D VDSO_CLOCKMODE_HVCLO= CK; } -#endif + +static bool kvm_use_master_clock(struct kvm *kvm) +{ + struct kvm_arch *ka =3D &kvm->arch; + + /* + * The 'old kvmclock' check is a workaround (from 2015) for a + * SUSE 2.6.16 kernel that didn't boot if the system_time in + * its kvmclock was too far behind the current time. So the + * mode of just setting the reference point and allowing time + * to proceed linearly from there makes it fail to boot. + * Despite that being kind of the *point* of the way the clock + * is exposed to the guest. By coincidence, the offending + * kernels used the old MSR_KVM_SYSTEM_TIME, which was moved + * only because it resided in the wrong number range. So the + * workaround is activated for *all* guests using the old MSR. + */ + return ka->all_vcpus_matched_freq && + !ka->backwards_tsc_observed && + !ka->boot_vcpu_runs_old_kvmclock; +} =20 static void kvm_track_tsc_matching(struct kvm_vcpu *vcpu, bool update_mclo= ck) { -#ifdef CONFIG_X86_64 struct kvm_arch *ka =3D &vcpu->kvm->arch; struct pvclock_gtod_data *gtod =3D &pvclock_gtod_data; bool prev_matched_tsc =3D ka->all_vcpus_matched_tsc; @@ -2680,7 +2699,7 @@ static void kvm_track_tsc_matching(struct kvm_vcpu *v= cpu, bool update_mclock) * are fine =E2=80=94 each vCPU's pvclock has its own tsc_timestamp that * accounts for its offset. */ - bool use_master_clock =3D ka->all_vcpus_matched_freq && + bool use_master_clock =3D kvm_use_master_clock(vcpu->kvm) && gtod_is_based_on_tsc(gtod->clock.vclock_mode); =20 /* @@ -2695,8 +2714,11 @@ static void kvm_track_tsc_matching(struct kvm_vcpu *= vcpu, bool update_mclock) trace_kvm_track_tsc(vcpu->vcpu_id, ka->nr_vcpus_matched_tsc, atomic_read(&vcpu->kvm->online_vcpus), ka->use_master_clock, gtod->clock.vclock_mode); -#endif } +#else +static inline void kvm_track_tsc_matching(struct kvm_vcpu *vcpu, + bool new_generation) {} +#endif =20 /* * Multiply tsc by a fixed point number represented by ratio. @@ -3210,10 +3232,9 @@ static void pvclock_update_vm_gtod_copy(struct kvm *= kvm) #ifdef CONFIG_X86_64 struct kvm_arch *ka =3D &kvm->arch; int vclock_mode; - bool host_tsc_clocksource, vcpus_matched; + bool host_tsc_clocksource; =20 lockdep_assert_held(&kvm->arch.tsc_write_lock); - vcpus_matched =3D ka->all_vcpus_matched_freq; =20 /* * If the host uses TSC clock, then passthrough TSC as stable @@ -3223,9 +3244,8 @@ static void pvclock_update_vm_gtod_copy(struct kvm *k= vm) &ka->master_kernel_ns, &ka->master_cycle_now); =20 - ka->use_master_clock =3D host_tsc_clocksource && vcpus_matched - && !ka->backwards_tsc_observed - && !ka->boot_vcpu_runs_old_kvmclock; + ka->use_master_clock =3D host_tsc_clocksource && + kvm_use_master_clock(kvm); =20 if (ka->use_master_clock) { u64 tsc_hz; @@ -3253,7 +3273,7 @@ static void pvclock_update_vm_gtod_copy(struct kvm *k= vm) =20 vclock_mode =3D pvclock_gtod_data.clock.vclock_mode; trace_kvm_update_master_clock(ka->use_master_clock, vclock_mode, - vcpus_matched); + ka->all_vcpus_matched_freq); #endif } =20 --=20 2.54.0 From nobody Fri Jul 10 17:09:11 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=1783113765; cv=none; d=zohomail.com; s=zohoarc; b=XmI0ab8YcSC8dyxMRrK4kS+LezcKaEuAedGALQPj3qvNSeAmdTia8rs3VyN3W5mzMkAqCF1NFuu2Tyy3+uojcdyy1JVhEg0npMGN1AMc6wYdfsnXdlcQFMRX1AOdkXV5MzJn4oZPAp6R5L0kaSkOOpl8TsHTT8HJRowCCGlACz4= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1783113765; 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=Uf6PMMgja7l0D+gznz6ziYSzcjhgw4gAMyV+QMwIS4w=; b=n5LJoiq+KULt+sPkkFvvQYtLTMPnUAhPZtx+YwEqJWeESWkakzxb9hPcJmteChLZEGGgoA3sRe8YDvijIwEIm8bB4D4/ErsTOsrO2MJQeaq5vCn+4yprtPUxy+ZUw1SiJ2JG9QPYG+G+0x5DQlcvY3FzUnxG7l6hdzYeRuTSEx4= 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 1783113765725597.7036216627645; Fri, 3 Jul 2026 14:22:45 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.1353754.1609489 (Exim 4.92) (envelope-from ) id 1wflKp-00067k-QD; Fri, 03 Jul 2026 21:22:07 +0000 Received: by outflank-mailman (output) from mailman id 1353754.1609489; Fri, 03 Jul 2026 21:22:07 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflKp-00065J-Ii; Fri, 03 Jul 2026 21:22:07 +0000 Received: by outflank-mailman (input) for mailman id 1353754; Fri, 03 Jul 2026 21:22:06 +0000 Received: from mx.expurgate.net ([195.190.135.20]) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflKn-0005Py-Su for xen-devel@lists.xenproject.org; Fri, 03 Jul 2026 21:22:05 +0000 Received: from mx.expurgate.net (helo=localhost) by mx.expurgate.net with esmtp id 1wflKn-00A7vt-9e; Fri, 03 Jul 2026 23:22:05 +0200 Received: from [10.42.69.7] (helo=localhost) by localhost with ESMTP (eXpurgate MTA 0.9.1) (envelope-from ) id 6a4827a3-e002-0a2a0a5209dd-0a2a4507d220-28 for ; Fri, 03 Jul 2026 23:22:05 +0200 Received: from [90.155.50.34] (helo=casper.infradead.org) by tlsNG-ef75cf.mxtls.expurgate.net with ESMTPS (eXpurgate 4.57.1) (envelope-from ) id 6a4827fc-9c8e-0a2a45070019-5a9b322282c8-3 for ; Fri, 03 Jul 2026 23:22:05 +0200 Received: from [2001:8b0:10b:1::425] (helo=i7.infradead.org) by casper.infradead.org with esmtpsa (Exim 4.99.1 #2 (Red Hat Linux)) id 1wflKX-0000000AsYE-1AzU; Fri, 03 Jul 2026 21:21:49 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.99.2 #2 (Red Hat Linux)) id 1wflKX-00000001RPT-0m6V; Fri, 03 Jul 2026 22:21:49 +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=casper.20170209 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=casper.20170209; 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=Uf6PMMgja7l0D+gznz6ziYSzcjhgw4gAMyV+QMwIS4w=; b=hb/nvHEGmIkkWSIO9fLFyYkl6P lhXj0DAUVaYTNlSjh9Ss2Uc7JqT+E0mDSgQF6HZZfS6Uhrl3pFZMXnt57qYqdw8l/FXZns/+M5YY/ kKM4u3aIR9pCz2XESpfpAi5/Bi1spkdEUwrRa0uWaWvhfktAKSlCmqIgUEiL+l3J8ZMFmlO8ZLLj5 rdW5ORlo4NyoFiq4LVYWiKqBt5CXZNjaAWZ5DKCm0b5O9mq3eWA3bDwiSAPZNZ/Abx6a7eMs3duc3 /POuQuY/i9iQJJ3zU2Q5BVdFKXYQi8EURSyU73jVB+7z0aOV1hkkdmaUMI8Kzbxa0vw9EnSuOEcRF Rl2ZUp/w==; 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 25/36] KVM: x86: Avoid gratuitous global clock updates Date: Fri, 3 Jul 2026 22:18:04 +0100 Message-ID: <20260703212145.343527-26-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 casper.infradead.org. See http://www.infradead.org/rpr.html X-purgate-ID: tlsNG-ef75cf/1783113725-FD12E25E-AC831E57/0/0 X-purgate-type: clean X-purgate-size: 2448 X-ZohoMail-DKIM: pass (identity @infradead.org) X-ZM-MESSAGEID: 1783113766510158500 Content-Type: text/plain; charset="utf-8" From: David Woodhouse Eliminate two sources of unnecessary KVM_REQ_GLOBAL_CLOCK_UPDATE: 1. kvm_write_system_time(): The global clock update was a workaround for ever-drifting clocks based on the host's CLOCK_MONOTONIC subject to NTP skew. Now that the KVM clock uses CLOCK_MONOTONIC_RAW, the clock does not drift with NTP corrections and there is no need to synchronize all vCPUs on boot or resume. Use KVM_REQ_CLOCK_UPDATE on the vCPU itself, and only when the clock is being enabled, not disabled. 2. kvm_arch_vcpu_load(): In master clock mode, migration between pCPUs does not require any clock update since the master clock reference is shared. Only request a local KVM_REQ_CLOCK_UPDATE for the vCPU's first-ever load (vcpu->cpu =3D=3D -1) to generate initial pvclock params. In non-master-clock mode, keep the global update to synchronize all vCPUs. Signed-off-by: David Woodhouse --- arch/x86/kvm/x86.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index f8883c3b8ed2..2a1e1a1ab6ee 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2457,13 +2457,13 @@ static void kvm_write_system_time(struct kvm_vcpu *= vcpu, gpa_t system_time, } =20 vcpu->arch.time =3D system_time; - kvm_make_request(KVM_REQ_GLOBAL_CLOCK_UPDATE, vcpu); =20 /* we verify if the enable bit is set... */ - if (system_time & 1) + if (system_time & 1) { kvm_gpc_activate(&vcpu->arch.pv_time, system_time & ~1ULL, sizeof(struct pvclock_vcpu_time_info)); - else + kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu); + } else kvm_gpc_deactivate(&vcpu->arch.pv_time); =20 return; @@ -5355,13 +5355,13 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int = cpu) * On a host with synchronized TSC, there is no need to update * kvmclock on vcpu->cpu migration */ - if (!vcpu->kvm->arch.use_master_clock || vcpu->cpu =3D=3D -1) { + if (!vcpu->kvm->arch.use_master_clock) { if (__ratelimit(&vcpu->kvm->arch.kvmclock_update_rs)) kvm_make_request(KVM_REQ_GLOBAL_CLOCK_UPDATE, vcpu); else kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu); - } - + } else if (vcpu->cpu =3D=3D -1) + kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu); if (vcpu->cpu !=3D cpu) kvm_make_request(KVM_REQ_MIGRATE_TIMER, vcpu); vcpu->cpu =3D cpu; --=20 2.54.0 From nobody Fri Jul 10 17:09:11 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=1783113763; cv=none; d=zohomail.com; s=zohoarc; b=I5cp4BZWI1Y3fP8H23AgwK3qBPVGJNqIwsFWt7eB1kIsRDji/6kZkbl1PiRyVBs761oNdibnT1FXhsyLokZS6dY8DnfD5zUZfWrDdfixo7pzaYfxcUI5xEuJoWFyQ5YYNgt5BT5KgEetmOeSw2SOQsAH57Z7sHD0nTsG+fVHS3c= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1783113763; 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=V5hQ2fJb27QK5yOdBL7f7A818+T1JNBNilH2QwnYDyE=; b=iaL/Z/QTBudpAruOrkwhRfGUgKCUMGjyq+7qUkzTJE/cPG70fM02GYRv1lkMjEzebj1RUuPTQogzO7nFQWvjhYP+yoM04vp1rxSVDrPMNQsnfxnxQsf9gv2uPrhojrB2eQs1HSkjmvVfantP5LNzx5OwTVzD+HpvH9kBcWasmKU= 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 1783113763526707.0178202169732; Fri, 3 Jul 2026 14:22:43 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.1353750.1609444 (Exim 4.92) (envelope-from ) id 1wflKm-00053h-Qm; Fri, 03 Jul 2026 21:22:04 +0000 Received: by outflank-mailman (output) from mailman id 1353750.1609444; Fri, 03 Jul 2026 21:22:04 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflKm-00053F-Js; Fri, 03 Jul 2026 21:22:04 +0000 Received: by outflank-mailman (input) for mailman id 1353750; Fri, 03 Jul 2026 21:22:03 +0000 Received: from mx.expurgate.net ([194.145.224.10]) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflKl-00051Q-Fi for xen-devel@lists.xenproject.org; Fri, 03 Jul 2026 21:22:03 +0000 Received: from mx.expurgate.net (helo=localhost) by mx.expurgate.net with esmtp id 1wflKk-001t36-Sc; Fri, 03 Jul 2026 23:22:02 +0200 Received: from [10.42.69.3] (helo=localhost) by localhost with ESMTP (eXpurgate MTA 0.9.1) (envelope-from ) id 6a4827ca-bab6-0a2a0a5309dd-0a2a4503bf3c-18 for ; Fri, 03 Jul 2026 23:22:02 +0200 Received: from [90.155.50.34] (helo=casper.infradead.org) by tlsNG-33051d.mxtls.expurgate.net with ESMTPS (eXpurgate 4.57.1) (envelope-from ) id 6a4827fa-ec1a-0a2a45030019-5a9b3222b952-3 for ; Fri, 03 Jul 2026 23:22:02 +0200 Received: from [2001:8b0:10b:1::425] (helo=i7.infradead.org) by casper.infradead.org with esmtpsa (Exim 4.99.1 #2 (Red Hat Linux)) id 1wflKX-0000000AsYF-1TB1; Fri, 03 Jul 2026 21:21:49 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.99.2 #2 (Red Hat Linux)) id 1wflKX-00000001RPX-0w0H; Fri, 03 Jul 2026 22:21:49 +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=casper.20170209 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=casper.20170209; 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=V5hQ2fJb27QK5yOdBL7f7A818+T1JNBNilH2QwnYDyE=; b=UEnwhLQsS2wkPtr1Pd+i9zzOxH sP8ejEvNPTu+HXmRA1IRK2tldo2/gJzqZvVFkblE3k6NJg2illNeTq4r1tIkNMYNlkdWFonJNHdMK mhSmA+bD14VOI9+r+ngRb7JB7fqCDAalnTCht1e3MXaFddIt8qbgkhuau0zS6oAateAvgrEcabeSd 8ssD8QbBlyyz0HmKWi8dhUlItveVTjZXTUCDUvvZgduEIsDDko+7didrcRF7/U9ZjOHxshnYVg5m8 dzZupkJUGPLn1s+4YQMYQSdzXtYuOWrxtKD6MQ0XG4ZFW1ckoKyrimh4GbzgzAMJIyiUdwJSkSu0l 7JBF15DA==; 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 26/36] KVM: x86/xen: Prevent runstate times from becoming negative Date: Fri, 3 Jul 2026 22:18:05 +0100 Message-ID: <20260703212145.343527-27-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 casper.infradead.org. See http://www.infradead.org/rpr.html X-purgate-ID: tlsNG-33051d/1783113722-B59BA5D1-E40BB414/0/0 X-purgate-type: clean X-purgate-size: 3262 X-ZohoMail-DKIM: pass (identity @infradead.org) X-ZM-MESSAGEID: 1783113764532158500 Content-Type: text/plain; charset="utf-8" From: David Woodhouse When kvm_xen_update_runstate() is invoked to set a vCPU's runstate, the time spent in the previous runstate is accounted. This is based on the delta between the current KVM clock time, and the previous value stored in vcpu->arch.xen.runstate_entry_time. If the KVM clock goes backwards, that delta will be negative. Or, since it's an unsigned 64-bit integer, very *large*. Linux guests deal with that particularly badly, reporting 100% steal time for ever more (well, for *centuries* at least, until the delta has been consumed). So when a negative delta is detected, just refrain from updating the runstate times until the KVM clock catches up with runstate_entry_time again. Also clamp steal_ns to delta_ns to prevent steal time from exceeding the total elapsed time, and handle negative steal_ns (which can happen if run_delay goes backwards across a scheduler update). The userspace APIs for setting the runstate times do not allow them to be set past the current KVM clock, but userspace can still adjust the KVM clock *after* setting the runstate times, which would cause this situation to occur. Signed-off-by: David Woodhouse Reviewed-by: Paul Durrant --- arch/x86/kvm/xen.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c index 82e34edbfdbd..b1d67ece5db3 100644 --- a/arch/x86/kvm/xen.c +++ b/arch/x86/kvm/xen.c @@ -586,29 +586,45 @@ void kvm_xen_update_runstate(struct kvm_vcpu *v, int = state) { struct kvm_vcpu_xen *vx =3D &v->arch.xen; u64 now =3D get_kvmclock_ns(v->kvm); - u64 delta_ns =3D now - vx->runstate_entry_time; u64 run_delay =3D current->sched_info.run_delay; + s64 delta_ns =3D now - vx->runstate_entry_time; + s64 steal_ns =3D run_delay - vx->last_steal; =20 + /* + * If the vCPU was never run before, its prior state should + * be considered RUNSTATE_offline. + */ if (unlikely(!vx->runstate_entry_time)) vx->current_runstate =3D RUNSTATE_offline; =20 + /* + * If KVM clock went backwards, just update the current runstate + * but don't account any time. Leave entry_time unchanged so the + * next positive delta covers the full period once the clock + * catches up. Update last_steal every time so stolen time only + * reflects the interval since the most recent call. + */ + if (delta_ns < 0) + goto update_guest; + /* * Time waiting for the scheduler isn't "stolen" if the * vCPU wasn't running anyway. */ - if (vx->current_runstate =3D=3D RUNSTATE_running) { - u64 steal_ns =3D run_delay - vx->last_steal; + if (vx->current_runstate =3D=3D RUNSTATE_running && steal_ns > 0) { + if (steal_ns > delta_ns) + steal_ns =3D delta_ns; =20 delta_ns -=3D steal_ns; - vx->runstate_times[RUNSTATE_runnable] +=3D steal_ns; } - vx->last_steal =3D run_delay; =20 vx->runstate_times[vx->current_runstate] +=3D delta_ns; - vx->current_runstate =3D state; vx->runstate_entry_time =3D now; =20 + update_guest: + vx->current_runstate =3D state; + vx->last_steal =3D run_delay; if (vx->runstate_cache.active) kvm_xen_update_runstate_guest(v, state =3D=3D RUNSTATE_runnable); } --=20 2.54.0 From nobody Fri Jul 10 17:09:11 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=1783113764; cv=none; d=zohomail.com; s=zohoarc; b=m2qEDLPy7fYh5bx1vz5nUnC3JZ/CrGGi9vakgTkWauuHTYTXLvdiPzInpx/rXVzTR5t0DCt0m+Td7DdqIMBx4Dk0Ycb0KVUKde4+6pjLDTojJm3Sf5lcxDOU9BoiUHAWHAzjRKzNZI6Fq8Z1To++MDMLtqSAE/ioSxiH/qKttxM= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1783113764; 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=CzWz4Us7r/rEWP66HSxuHNlM7/EVQzg+tC4fjHgL8hU=; b=D5d5BCeE/sxfQwPZsUH5N9/Mhl94pqyM9dhOqONePZTHxNh3Qzkk8yOu+IvIGdgtpTHu6oqO9jJEz0iUEaNg2pCrbDcDUvV3ZDAUnnflqLrdaz54PH68gsgOtLpqGHKpgDGvIp7cEg4SidPAkpAKQZqTI3b9qj/3DzeBWFyV8NE= 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 1783113764437203.12266108284382; Fri, 3 Jul 2026 14:22:44 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.1353751.1609454 (Exim 4.92) (envelope-from ) id 1wflKn-0005Fb-BS; Fri, 03 Jul 2026 21:22:05 +0000 Received: by outflank-mailman (output) from mailman id 1353751.1609454; Fri, 03 Jul 2026 21:22:05 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflKn-0005Eh-60; Fri, 03 Jul 2026 21:22:05 +0000 Received: by outflank-mailman (input) for mailman id 1353751; Fri, 03 Jul 2026 21:22:03 +0000 Received: from mx.expurgate.net ([194.145.224.10]) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflKk-00051P-Kz for xen-devel@lists.xenproject.org; Fri, 03 Jul 2026 21:22:03 +0000 Received: from mx.expurgate.net (helo=localhost) by mx.expurgate.net with esmtp id 1wflKk-001t36-1i; Fri, 03 Jul 2026 23:22:02 +0200 Received: from [10.42.69.3] (helo=localhost) by localhost with ESMTP (eXpurgate MTA 0.9.1) (envelope-from ) id 6a4827ca-bab6-0a2a0a5309dd-0a2a4503bf3c-16 for ; Fri, 03 Jul 2026 23:22:01 +0200 Received: from [90.155.50.34] (helo=casper.infradead.org) by tlsNG-33051d.mxtls.expurgate.net with ESMTPS (eXpurgate 4.57.1) (envelope-from ) id 6a4827f9-ec1a-0a2a45030019-5a9b3222c562-3 for ; Fri, 03 Jul 2026 23:22:01 +0200 Received: from [2001:8b0:10b:1::425] (helo=i7.infradead.org) by casper.infradead.org with esmtpsa (Exim 4.99.1 #2 (Red Hat Linux)) id 1wflKX-0000000AsYG-1i3E; Fri, 03 Jul 2026 21:21:49 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.99.2 #2 (Red Hat Linux)) id 1wflKX-00000001RPb-1H0I; Fri, 03 Jul 2026 22:21:49 +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=casper.20170209 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=casper.20170209; 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=CzWz4Us7r/rEWP66HSxuHNlM7/EVQzg+tC4fjHgL8hU=; b=mTF1YHeydnaypEa+INXWx9qXoR M0PqgmKfFa4z677E1dsW1eEvyWkF6xUV1PdB8gg/x+CCYBbTc8AfTSe7OkZPaq2U5ubShAbVjKgct kCMUrQtwKWJRjjP9W7glXLslomFXL1Uab3oPmtTv/VeXByun+aTfqAFILzp5HUTkuKh4m1NdyROs6 HNxK1P0nee9tkb0MG2OqepLt57YqRuJjvJlfa11a8OWJs2g1z30A2IGWV3whrfTOf0xpAlQC1+teG DfqFxOoVBfqyecjXVw+McN+dGdz8Nmn7AjS0GmGwMHLWHq8299lfwPp8dMCfRogqtIfbHaA41RpTZ GQMkyl5A==; 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 27/36] KVM: x86: Avoid redundant masterclock updates from multiple vCPUs Date: Fri, 3 Jul 2026 22:18:06 +0100 Message-ID: <20260703212145.343527-28-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 casper.infradead.org. See http://www.infradead.org/rpr.html X-purgate-ID: tlsNG-33051d/1783113721-B63305D1-3A59CD18/0/0 X-purgate-type: clean X-purgate-size: 5183 X-ZohoMail-DKIM: pass (identity @infradead.org) X-ZM-MESSAGEID: 1783113766549158500 Content-Type: text/plain; charset="utf-8" From: David Woodhouse When a masterclock update is triggered (e.g. by the clocksource change notifier), KVM_REQ_MASTERCLOCK_UPDATE is set on all vCPUs. Without this fix, each vCPU independently processes the request and redundantly re-executes the entire pvclock_update_vm_gtod_copy() sequence, serialized only by tsc_write_lock. Each redundant re-snapshot of the master clock reference point introduces potential clock drift. Fix this by having __kvm_start_pvclock_update() check, after acquiring the lock, whether the requesting vCPU's KVM_REQ_MASTERCLOCK_UPDATE is still set. If another vCPU already did the update and cleared it, bail out. Otherwise, clear the request on all other vCPUs before proceeding. The caller in vcpu_enter_guest() now uses kvm_test_request() (non-clearing) since the clearing is done inside __kvm_start_pvclock_update() under the lock. Suggested-by: Dongli Zhang Signed-off-by: David Woodhouse Tested-by: Dongli Zhang --- arch/x86/kvm/x86.c | 60 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 46 insertions(+), 14 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 2a1e1a1ab6ee..80fe69974ded 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -3282,10 +3282,39 @@ static void kvm_make_mclock_inprogress_request(stru= ct kvm *kvm) kvm_make_all_cpus_request(kvm, KVM_REQ_MCLOCK_INPROGRESS); } =20 -static void __kvm_start_pvclock_update(struct kvm *kvm) +static void kvm_clear_mclock_inprogress_request(struct kvm *kvm) { + struct kvm_vcpu *vcpu; + unsigned long i; + + kvm_for_each_vcpu(i, vcpu, kvm) + kvm_clear_request(KVM_REQ_MCLOCK_INPROGRESS, vcpu); +} + +static bool __kvm_start_pvclock_update(struct kvm *kvm, struct kvm_vcpu *r= equesting_vcpu) +{ + struct kvm_vcpu *vcpu; + unsigned long i; + raw_spin_lock_irq(&kvm->arch.tsc_write_lock); + + /* + * If another vCPU already did the update while we were waiting + * for the lock, our request will have been cleared. Bail out. + */ + if (requesting_vcpu && + !kvm_test_request(KVM_REQ_MASTERCLOCK_UPDATE, requesting_vcpu)) { + kvm_clear_mclock_inprogress_request(kvm); + raw_spin_unlock_irq(&kvm->arch.tsc_write_lock); + return false; + } + + /* The update is VM-wide; prevent other vCPUs from redoing it. */ + kvm_for_each_vcpu(i, vcpu, kvm) + kvm_clear_request(KVM_REQ_MASTERCLOCK_UPDATE, vcpu); + write_seqcount_begin(&kvm->arch.pvclock_sc); + return true; } =20 static void kvm_start_pvclock_update(struct kvm *kvm) @@ -3293,7 +3322,7 @@ static void kvm_start_pvclock_update(struct kvm *kvm) kvm_make_mclock_inprogress_request(kvm); =20 /* no guest entries from this point */ - __kvm_start_pvclock_update(kvm); + __kvm_start_pvclock_update(kvm, NULL); } =20 static void kvm_end_pvclock_update(struct kvm *kvm) @@ -3302,22 +3331,25 @@ static void kvm_end_pvclock_update(struct kvm *kvm) struct kvm_vcpu *vcpu; unsigned long i; =20 - write_seqcount_end(&ka->pvclock_sc); - raw_spin_unlock_irq(&ka->tsc_write_lock); kvm_for_each_vcpu(i, vcpu, kvm) kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu); =20 /* guest entries allowed */ - kvm_for_each_vcpu(i, vcpu, kvm) - kvm_clear_request(KVM_REQ_MCLOCK_INPROGRESS, vcpu); + kvm_clear_mclock_inprogress_request(kvm); + + write_seqcount_end(&ka->pvclock_sc); + raw_spin_unlock_irq(&ka->tsc_write_lock); } =20 -static void kvm_update_masterclock(struct kvm *kvm) +static void kvm_update_masterclock(struct kvm *kvm, struct kvm_vcpu *vcpu) { kvm_hv_request_tsc_page_update(kvm); - kvm_start_pvclock_update(kvm); - pvclock_update_vm_gtod_copy(kvm); - kvm_end_pvclock_update(kvm); + kvm_make_mclock_inprogress_request(kvm); + + if (__kvm_start_pvclock_update(kvm, vcpu)) { + pvclock_update_vm_gtod_copy(kvm); + kvm_end_pvclock_update(kvm); + } } =20 /* @@ -10144,7 +10176,7 @@ static void kvm_hyperv_tsc_notifier(void) kvm_caps.max_guest_tsc_khz =3D tsc_khz; =20 list_for_each_entry(kvm, &vm_list, vm_list) { - __kvm_start_pvclock_update(kvm); + __kvm_start_pvclock_update(kvm, NULL); pvclock_update_vm_gtod_copy(kvm); kvm_end_pvclock_update(kvm); } @@ -11522,8 +11554,8 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) kvm_mmu_free_obsolete_roots(vcpu); if (kvm_check_request(KVM_REQ_MIGRATE_TIMER, vcpu)) __kvm_migrate_timers(vcpu); - if (kvm_check_request(KVM_REQ_MASTERCLOCK_UPDATE, vcpu)) - kvm_update_masterclock(vcpu->kvm); + if (kvm_test_request(KVM_REQ_MASTERCLOCK_UPDATE, vcpu)) + kvm_update_masterclock(vcpu->kvm, vcpu); if (kvm_check_request(KVM_REQ_GLOBAL_CLOCK_UPDATE, vcpu)) kvm_gen_kvmclock_update(vcpu); if (kvm_check_request(KVM_REQ_CLOCK_UPDATE, vcpu)) { @@ -13260,7 +13292,7 @@ void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu) vcpu_load(vcpu); kvm_synchronize_tsc(vcpu, NULL); if (!vcpu->kvm->arch.use_master_clock) - kvm_update_masterclock(vcpu->kvm); + kvm_update_masterclock(vcpu->kvm, NULL); vcpu_put(vcpu); =20 /* poll control enabled by default */ --=20 2.54.0 From nobody Fri Jul 10 17:09:11 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=1783113850; cv=none; d=zohomail.com; s=zohoarc; b=SMmDXuCLE8f1m8S3+HX+Zp+WJ5f+ApCdVH5mqoofc3q2CqIkijvpPdZHmv4ZI0sYu3eszHGa0efXc+dK2GPd39ZfPn4N/RotGrATMxKsc179RQEdAwhkM8XnmpjwSnW8rPMxUOJJ2MRL2+2RU58ojtClLC+e52ff+XoqdslLv14= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1783113850; 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=mAoCrW41i2oubtWoRcSbcZKOTJ7hLP/U/r8vkThOrIU=; b=Pg99GczoQy/bHdnxtAsUHMg/F7RUY2WV+U+jneYRnPcd9xC3Q+5THDFDrWH84UNbLX68382QK8Qrm6Lmwjc2HsfWOwEhdFq81FhYfD+zOrrl/xBxBVl8NO5qwBlLnB1HbxqJpfA1kqVrthD4PO9NQdMDTnP9jDUXisw4h/uK560= 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 1783113850986873.3983172724951; Fri, 3 Jul 2026 14:24:10 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.1353904.1609680 (Exim 4.92) (envelope-from ) id 1wflMa-0007iL-Am; Fri, 03 Jul 2026 21:23:56 +0000 Received: by outflank-mailman (output) from mailman id 1353904.1609680; Fri, 03 Jul 2026 21:23:56 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflMa-0007h5-4w; Fri, 03 Jul 2026 21:23:56 +0000 Received: by outflank-mailman (input) for mailman id 1353904; Fri, 03 Jul 2026 21:23:53 +0000 Received: from mx.expurgate.net ([194.145.224.10]) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflMX-00071A-7M for xen-devel@lists.xenproject.org; Fri, 03 Jul 2026 21:23:53 +0000 Received: from mx.expurgate.net (helo=localhost) by mx.expurgate.net with esmtp id 1wflMW-00CejO-KM; Fri, 03 Jul 2026 23:23:52 +0200 Received: from [10.42.69.3] (helo=localhost) by localhost with ESMTP (eXpurgate MTA 0.9.1) (envelope-from ) id 6a482835-bab6-0a2a0a5309dd-0a2a45038b46-26 for ; Fri, 03 Jul 2026 23:23:52 +0200 Received: from [90.155.92.199] (helo=desiato.infradead.org) by tlsNG-33051d.mxtls.expurgate.net with ESMTPS (eXpurgate 4.57.1) (envelope-from ) id 6a482868-ec1a-0a2a45030019-5a9b5cc7ba66-3 for ; Fri, 03 Jul 2026 23:23:52 +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-000000059OB-3OKN; Fri, 03 Jul 2026 21:23:31 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.99.2 #2 (Red Hat Linux)) id 1wflKX-00000001RPf-1VR4; Fri, 03 Jul 2026 22:21:49 +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=mAoCrW41i2oubtWoRcSbcZKOTJ7hLP/U/r8vkThOrIU=; b=SCbksCL3C6lCq63v2liwrhb2lA xAbzjM0Ap/EFmihcazXJMLsPc0Gy/LZbYMpy3KNL9NaNPZ08PMTpDHyMT9z4L9DQzWXqndhnhJVT/ KaO3tzV57y2ygHn+F/s78qY2H4870En1P/JMMQzNiMI3AcHjVzKmP29ZJ27qVm3fVpi0kgOi3ocQC Ldb5j68wLws0DZDKidaCijCDu71rnX34BxkzVhC35mPOUB55mdo0urZogZbzzyX9H1Btken59i/zq quARfNTDShyil/B7FPKU929VA3Q43dAMg5lcGHrX+ePGE7kLAD/aHCLdFkn9CykhB+0xJ6rmrTdEl TdTctQvw==; 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 28/36] KVM: x86: Remove runtime Xen TSC frequency CPUID update Date: Fri, 3 Jul 2026 22:18:07 +0100 Message-ID: <20260703212145.343527-29-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-33051d/1783113832-07B245D1-AD583B97/0/0 X-purgate-type: clean X-purgate-size: 3099 X-ZohoMail-DKIM: pass (identity @infradead.org) X-ZM-MESSAGEID: 1783113852932158500 Content-Type: text/plain; charset="utf-8" From: David Woodhouse Remove the code in kvm_cpuid() that dynamically updates the Xen TSC info CPUID leaf at runtime. This code was updating the wrong sub-leaf anyway (0x40000x03/2 EAX is the *host* TSC frequency per the Xen ABI, not the guest frequency which belongs in 0x40000x03/0 ECX). Userspace now has all the information it needs to populate the Xen TSC info leaves (and the generic 0x40000010 timing leaf) at vCPU setup time: - KVM_GET_CLOCK_GUEST returns the pvclock_vcpu_time_info structure containing tsc_to_system_mul and tsc_shift (Xen leaf index 1) - KVM_VCPU_TSC_SCALE returns the effective TSC and bus frequencies in kHz (Xen leaf index 2, and 0x40000010) - KVM_VCPU_TSC_SCALE returns the raw hardware scaling ratio for precise arithmetic (VMClock) This eliminates the last instance of KVM modifying guest CPUID entries at runtime for timing information. Signed-off-by: David Woodhouse --- arch/x86/kvm/cpuid.c | 16 ---------------- arch/x86/kvm/xen.h | 13 ------------- 2 files changed, 29 deletions(-) diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index 621d950ec692..826637a0b72d 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -2117,22 +2117,6 @@ bool kvm_cpuid(struct kvm_vcpu *vcpu, u32 *eax, u32 = *ebx, } else if (function =3D=3D 0x80000007) { if (kvm_hv_invtsc_suppressed(vcpu)) *edx &=3D ~feature_bit(CONSTANT_TSC); - } else if (IS_ENABLED(CONFIG_KVM_XEN) && - kvm_xen_is_tsc_leaf(vcpu, function)) { - /* - * Update guest TSC frequency information if necessary. - * Ignore failures, there is no sane value that can be - * provided if KVM can't get the TSC frequency. - */ - if (kvm_check_request(KVM_REQ_CLOCK_UPDATE, vcpu)) - kvm_guest_time_update(vcpu); - - if (index =3D=3D 1) { - *ecx =3D vcpu->arch.pvclock_tsc_mul; - *edx =3D vcpu->arch.pvclock_tsc_shift; - } else if (index =3D=3D 2) { - *eax =3D div_u64(vcpu->arch.hw_tsc_hz, 1000); - } } } else { *eax =3D *ebx =3D *ecx =3D *edx =3D 0; diff --git a/arch/x86/kvm/xen.h b/arch/x86/kvm/xen.h index 59e6128a7bd3..f372855857a8 100644 --- a/arch/x86/kvm/xen.h +++ b/arch/x86/kvm/xen.h @@ -50,14 +50,6 @@ static inline void kvm_xen_sw_enable_lapic(struct kvm_vc= pu *vcpu) kvm_xen_inject_vcpu_vector(vcpu); } =20 -static inline bool kvm_xen_is_tsc_leaf(struct kvm_vcpu *vcpu, u32 function) -{ - return static_branch_unlikely(&kvm_xen_enabled.key) && - vcpu->arch.xen.cpuid.base && - function <=3D vcpu->arch.xen.cpuid.limit && - function =3D=3D (vcpu->arch.xen.cpuid.base | XEN_CPUID_LEAF(3)); -} - static inline bool kvm_xen_msr_enabled(struct kvm *kvm) { return static_branch_unlikely(&kvm_xen_enabled.key) && @@ -177,11 +169,6 @@ static inline bool kvm_xen_timer_enabled(struct kvm_vc= pu *vcpu) { return false; } - -static inline bool kvm_xen_is_tsc_leaf(struct kvm_vcpu *vcpu, u32 function) -{ - return false; -} #endif =20 int kvm_xen_hypercall(struct kvm_vcpu *vcpu); --=20 2.54.0 From nobody Fri Jul 10 17:09:11 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=1783113773; cv=none; d=zohomail.com; s=zohoarc; b=CjGb6RbJw2ovpVvxfp1ARB/M0O/muJxdpl04j+M1VEQMm0YzHfONNwsNU0LnZPjAMUFVIk7g16Sc7moUeaF6CvaR4fEU6u2Rc3q4yUqmJ8JUAqVmN0H1QqH+LnAtYohPuhEcuhERn5tOfI1d03/cr8lngN85+YFvLgIeMcojdfo= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1783113773; h=Content-Type: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=dcChYx15IhyePM7jxxFL8xpvT1sezeCblvUhAhYmoTc=; b=V24+oFlGAHGN40cZBsjRd5GsNoXkyAEYEeQsYaoH/PP0MylfBblaVahx2T021keU65O8wU/Pp+VRghQSNdo7tu4xvBsO2U9ZbB0bYd7MkVfDATLiq29QKRRFFT4t49YbXcKn0fPpct3qux7x1ed7JLP59DfYFJrQNBI6nFtvocM= 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 178311377386065.43620269120879; Fri, 3 Jul 2026 14:22:53 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.1353752.1609462 (Exim 4.92) (envelope-from ) id 1wflKn-0005OF-MH; Fri, 03 Jul 2026 21:22:05 +0000 Received: by outflank-mailman (output) from mailman id 1353752.1609462; Fri, 03 Jul 2026 21:22:05 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflKn-0005Me-Er; Fri, 03 Jul 2026 21:22:05 +0000 Received: by outflank-mailman (input) for mailman id 1353752; Fri, 03 Jul 2026 21:22:03 +0000 Received: from mx.expurgate.net ([195.190.135.20]) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflKl-00051M-OQ for xen-devel@lists.xenproject.org; Fri, 03 Jul 2026 21:22:03 +0000 Received: from mx.expurgate.net (helo=localhost) by mx.expurgate.net with esmtp id 1wflKj-00A7vt-4i; Fri, 03 Jul 2026 23:22:01 +0200 Received: from [10.42.69.7] (helo=localhost) by localhost with ESMTP (eXpurgate MTA 0.9.1) (envelope-from ) id 6a4827a3-e002-0a2a0a5209dd-0a2a4507d220-22 for ; Fri, 03 Jul 2026 23:22:01 +0200 Received: from [90.155.50.34] (helo=casper.infradead.org) by tlsNG-ef75cf.mxtls.expurgate.net with ESMTPS (eXpurgate 4.57.1) (envelope-from ) id 6a4827f7-9c8e-0a2a45070019-5a9b3222db84-3 for ; Fri, 03 Jul 2026 23:22:00 +0200 Received: from [2001:8b0:10b:1::425] (helo=i7.infradead.org) by casper.infradead.org with esmtpsa (Exim 4.99.1 #2 (Red Hat Linux)) id 1wflKX-0000000AsYJ-27pF; Fri, 03 Jul 2026 21:21:49 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.99.2 #2 (Red Hat Linux)) id 1wflKX-00000001RPj-1hBl; Fri, 03 Jul 2026 22:21:49 +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=casper.20170209 header.d=infradead.org header.i="@infradead.org" header.h="Sender:Content-Transfer-Encoding:Content-Type: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=casper.20170209; h=Sender:Content-Transfer-Encoding: Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:To: From:Reply-To:Cc:Content-ID:Content-Description; bh=dcChYx15IhyePM7jxxFL8xpvT1sezeCblvUhAhYmoTc=; b=PpxWMrvMWWKNxttwja7nHYJHNJ Tdw+PzgGZjwODRY98hW5BR+tAtE89GRECyXkUmSTeJX1rBty2kcY8W+58CRVlWYk4Bz4l41ihaFha g01FYDjNMOh8OKhpw6xaihQ43pPDg704uo3EVd3bW5xMlHRGXnL0d+Hffs2+SQF+WpgWeEp7CgGs1 Qbg3PriQlFgedyBXaFLnwXicyc7Ph84YMeMxmkCegXoq2LTS4hfbXFUPjEA8KQWIbUH+wERqoWG49 xsrw3fT911L0O1Vdx4DtSCpxTgfx6KSV+Kg3+Gl0SH6biyYxrIIAOSM8tCTHByHs82tPXLS5Knk8Y 1/TJPGTg==; 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 29/36] KVM: selftests: Add Xen/generic CPUID timing leaf test Date: Fri, 3 Jul 2026 22:18:08 +0100 Message-ID: <20260703212145.343527-30-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-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Sender: David Woodhouse X-SRS-Rewrite: SMTP reverse-path rewritten from by casper.infradead.org. See http://www.infradead.org/rpr.html X-purgate-ID: tlsNG-ef75cf/1783113721-FD52025E-D8802687/0/0 X-purgate-type: clean X-purgate-size: 8822 X-ZohoMail-DKIM: pass (identity @infradead.org) X-ZM-MESSAGEID: 1783113774813158500 From: David Woodhouse Verify that userspace can correctly populate Xen and generic CPUID timing leaves using the KVM_VCPU_TSC_SCALE and KVM_VCPU_TSC_SCALE attributes. This validates that the removal of KVM's runtime Xen CPUID modification doesn't break guests: userspace queries the effective TSC and bus frequencies, computes the pvclock mul/shift, populates the CPUID leaves, and the guest verifies the values match. The test exercises: - KVM_VCPU_TSC_SCALE at native and scaled frequencies - KVM_VCPU_TSC_SCALE ratio verification against effective frequency - Generic timing leaf 0x40000010 (EAX=3Dtsc_khz, EBX=3Dbus_khz) - Xen leaf 3 sub-leaf 0 (ECX=3Dguest TSC kHz) - Xen leaf 3 sub-leaf 1 (ECX=3Dmul, EDX=3Dshift) Gracefully skips TSC scaling tests on hardware without support. Signed-off-by: David Woodhouse --- tools/testing/selftests/kvm/Makefile.kvm | 1 + .../selftests/kvm/x86/xen_cpuid_timing_test.c | 230 ++++++++++++++++++ 2 files changed, 231 insertions(+) create mode 100644 tools/testing/selftests/kvm/x86/xen_cpuid_timing_test.c diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selft= ests/kvm/Makefile.kvm index 7ecaaf82056e..58aac2980cdf 100644 --- a/tools/testing/selftests/kvm/Makefile.kvm +++ b/tools/testing/selftests/kvm/Makefile.kvm @@ -141,6 +141,7 @@ TEST_GEN_PROGS_x86 +=3D x86/xss_msr_test TEST_GEN_PROGS_x86 +=3D x86/debug_regs TEST_GEN_PROGS_x86 +=3D x86/tsc_msrs_test TEST_GEN_PROGS_x86 +=3D x86/vmx_pmu_caps_test +TEST_GEN_PROGS_x86 +=3D x86/xen_cpuid_timing_test TEST_GEN_PROGS_x86 +=3D x86/xen_shinfo_test TEST_GEN_PROGS_x86 +=3D x86/xen_vmcall_test TEST_GEN_PROGS_x86 +=3D x86/sev_init2_tests diff --git a/tools/testing/selftests/kvm/x86/xen_cpuid_timing_test.c b/tool= s/testing/selftests/kvm/x86/xen_cpuid_timing_test.c new file mode 100644 index 000000000000..2098cb511ef0 --- /dev/null +++ b/tools/testing/selftests/kvm/x86/xen_cpuid_timing_test.c @@ -0,0 +1,230 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Test that userspace can correctly populate Xen and generic CPUID + * timing leaves using KVM_GET_TSC_KHZ and KVM_VCPU_TSC_SCALE. + * + * This validates that the removal of KVM's runtime Xen CPUID modification + * doesn't break guests, because userspace has all the information needed. + */ +#include +#include +#include + +#include "test_util.h" +#include "kvm_util.h" +#include "processor.h" + +#include + +#define XEN_CPUID_BASE 0x40000100 +#define XEN_CPUID_LEAF(n) (XEN_CPUID_BASE + (n)) +#define GENERIC_TIMING_LEAF 0x40000010 + +/* Values set by host, verified by guest */ +static uint32_t expected_tsc_khz; +static uint32_t expected_bus_khz; +static uint32_t expected_tsc_mul; +static int8_t expected_tsc_shift; +static uint64_t host_khz; + +static void guest_code(void) +{ + uint32_t eax, ebx, ecx, edx; + + /* Check generic timing leaf 0x40000010 */ + __cpuid(GENERIC_TIMING_LEAF, 0, &eax, &ebx, &ecx, &edx); + GUEST_ASSERT_EQ(eax, expected_tsc_khz); + GUEST_ASSERT_EQ(ebx, expected_bus_khz); + + /* Check Xen leaf 3, sub-leaf 0: ECX =3D guest TSC frequency */ + __cpuid(XEN_CPUID_LEAF(3), 0, &eax, &ebx, &ecx, &edx); + GUEST_ASSERT_EQ(ecx, expected_tsc_khz); + + /* Check Xen leaf 3, sub-leaf 1: ECX =3D mul, EDX =3D shift */ + __cpuid(XEN_CPUID_LEAF(3), 1, &eax, &ebx, &ecx, &edx); + GUEST_ASSERT_EQ(ecx, expected_tsc_mul); + GUEST_ASSERT_EQ((int8_t)edx, expected_tsc_shift); + + GUEST_SYNC(0); +} + +static void add_cpuid_entry(struct kvm_vcpu *vcpu, uint32_t function, + uint32_t index, uint32_t eax, uint32_t ebx, + uint32_t ecx, uint32_t edx) +{ + struct kvm_cpuid2 *cpuid =3D vcpu->cpuid; + struct kvm_cpuid_entry2 *entry; + int n =3D cpuid->nent; + + vcpu->cpuid =3D realloc(vcpu->cpuid, + sizeof(*cpuid) + (n + 1) * sizeof(*entry)); + cpuid =3D vcpu->cpuid; + cpuid->nent =3D n + 1; + + entry =3D &cpuid->entries[n]; + memset(entry, 0, sizeof(*entry)); + entry->function =3D function; + entry->index =3D index; + entry->flags =3D KVM_CPUID_FLAG_SIGNIFCANT_INDEX; + entry->eax =3D eax; + entry->ebx =3D ebx; + entry->ecx =3D ecx; + entry->edx =3D edx; +} + +/* + * Compute pvclock mul/shift from frequency, matching kvm_get_time_scale(). + */ +static void compute_tsc_mul_shift(uint64_t tsc_hz, uint32_t *mul, int8_t *= shift) +{ + uint64_t scaled =3D 1000000000ULL; + uint64_t base =3D tsc_hz; + int32_t s =3D 0; + uint32_t base32; + + while (base > scaled * 2 || base >> 32) { + base >>=3D 1; + s--; + } + base32 =3D (uint32_t)base; + while (base32 <=3D scaled || scaled >> 32) { + if (scaled >> 32 || base32 & (1U << 31)) + scaled >>=3D 1; + else + base32 <<=3D 1; + s++; + } + *mul =3D (uint32_t)((scaled << 32) / base32); + *shift =3D (int8_t)s; +} + +static void run_test(uint64_t tsc_khz) +{ + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + struct ucall uc; + uint32_t effective_tsc_khz, effective_bus_khz; + int bus_cycle_ns; + + vm =3D vm_create_with_one_vcpu(&vcpu, guest_code); + + if (tsc_khz) { + pr_info("Testing at TSC frequency %lu kHz\n", tsc_khz); + vcpu_ioctl(vcpu, KVM_SET_TSC_KHZ, (void *)(unsigned long)tsc_khz); + } else { + pr_info("Testing at native TSC frequency\n"); + } + + effective_tsc_khz =3D __vcpu_ioctl(vcpu, KVM_GET_TSC_KHZ, NULL); + bus_cycle_ns =3D vm_check_cap(vm, KVM_CAP_X86_APIC_BUS_CYCLES_NS); + effective_bus_khz =3D bus_cycle_ns > 0 ? 1000000 / bus_cycle_ns : 1000000; + + /* If scaling wasn't applied, skip this frequency */ + if (tsc_khz && effective_tsc_khz =3D=3D host_khz) { + pr_info(" TSC scaling not available, skipping\n"); + kvm_vm_free(vm); + return; + } + + pr_info(" Effective TSC: %u kHz, Bus: %u kHz\n", effective_tsc_khz, effe= ctive_bus_khz); + + /* Also exercise KVM_VCPU_TSC_SCALE if available */ + { + struct { uint64_t ratio; uint64_t frac_bits; } scale; + struct kvm_device_attr scale_attr =3D { + .group =3D KVM_VCPU_TSC_CTRL, + .attr =3D KVM_VCPU_TSC_SCALE, + .addr =3D (uint64_t)(uintptr_t)&scale, + }; + + if (!__vcpu_ioctl(vcpu, KVM_HAS_DEVICE_ATTR, &scale_attr)) { + vcpu_ioctl(vcpu, KVM_GET_DEVICE_ATTR, &scale_attr); + pr_info(" TSC scale: ratio=3D%lu frac_bits=3D%lu\n", + scale.ratio, scale.frac_bits); + + /* + * Verify: applying the ratio to the host TSC frequency + * should give approximately the effective frequency. + */ + if (tsc_khz) { + uint64_t computed =3D ((__uint128_t)host_khz * scale.ratio) >> scale.f= rac_bits; + int64_t diff =3D (int64_t)computed - (int64_t)effective_tsc_khz; + + TEST_ASSERT(diff >=3D -1 && diff <=3D 1, + "TSC_SCALE ratio mismatch: computed %lu vs effective %u (diff %ld= )", + computed, effective_tsc_khz, diff); + } + } + } + + compute_tsc_mul_shift((uint64_t)effective_tsc_khz * 1000, + &expected_tsc_mul, &expected_tsc_shift); + + expected_tsc_khz =3D effective_tsc_khz; + expected_bus_khz =3D effective_bus_khz; + + sync_global_to_guest(vm, expected_tsc_khz); + sync_global_to_guest(vm, expected_bus_khz); + sync_global_to_guest(vm, expected_tsc_mul); + sync_global_to_guest(vm, expected_tsc_shift); + + /* Populate CPUID leaves as a VMM would */ + add_cpuid_entry(vcpu, GENERIC_TIMING_LEAF, 0, + effective_tsc_khz, effective_bus_khz, 0, 0); + add_cpuid_entry(vcpu, XEN_CPUID_LEAF(3), 0, + 0, 0, effective_tsc_khz, 0); + add_cpuid_entry(vcpu, XEN_CPUID_LEAF(3), 1, + 0, 0, expected_tsc_mul, + (uint32_t)(uint8_t)expected_tsc_shift); + + vcpu_set_cpuid(vcpu); + + pr_info(" pvclock mul=3D%u shift=3D%d\n", expected_tsc_mul, expected_tsc= _shift); + + vcpu_run(vcpu); + TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO); + + switch (get_ucall(vcpu, &uc)) { + case UCALL_ABORT: + REPORT_GUEST_ASSERT(uc); + break; + case UCALL_SYNC: + break; + default: + TEST_FAIL("Unexpected ucall"); + } + + kvm_vm_free(vm); +} + +int main(void) +{ + uint64_t freq; + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + struct kvm_device_attr attr =3D { + .group =3D KVM_VCPU_TSC_CTRL, + .attr =3D KVM_VCPU_TSC_SCALE, + }; + + TEST_REQUIRE(sys_clocksource_is_based_on_tsc()); + + /* Check KVM_VCPU_TSC_SCALE is supported (implies TSC scaling) */ + vm =3D vm_create_with_one_vcpu(&vcpu, guest_code); + TEST_REQUIRE(!__vcpu_ioctl(vcpu, KVM_HAS_DEVICE_ATTR, &attr)); + host_khz =3D __vcpu_ioctl(vcpu, KVM_GET_TSC_KHZ, NULL); + kvm_vm_free(vm); + + /* Native frequency */ + run_test(0); + + /* Scaled frequencies =E2=80=94 skip if TSC scaling not available */ + for (freq =3D 1000000; freq <=3D 4000000; freq +=3D 1000000) { + if (freq =3D=3D host_khz) + continue; + run_test(freq); + } + + pr_info("PASS: All CPUID timing leaf tests passed\n"); + return 0; +} --=20 2.54.0 From nobody Fri Jul 10 17:09:11 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=1783113878; cv=none; d=zohomail.com; s=zohoarc; b=k8WxyBJ8yIzguyREnmdFxjP7fG5pLTfTR3RvYhn1nnN3dB8M6Cf9M9ot8mfnqkbWrLM+9uN6d8XhCvYFu3IrnX6NKnQO8wBKMiO5fqsrNh1QAPeZaYRrWvII/KIj5rsDb3SgjDEkPFJZpm3xoUyEH42agNsHdv2JBvqKDA7kU6Y= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1783113878; 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=cd7ADB+seora88pbKs2aD/tIbj9VePpwMwSL1OtTGjc=; b=PDiVMEn2xdf9xlLulmm4Fu1N/maUbSN7UWg60KFEYzo7Wl5Z9J064elR/ujE25wrOlIxTqowYfH2/Ks7W0/0gwLsoigmZNICtDw05qHu0K2dtY0m2DQA93UCLgyul8xYg2600rXytgCGEIhQNqW8k3pAMadthuK02Tbi6MyHAr0= 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 1783113878833162.08109619888808; Fri, 3 Jul 2026 14:24:38 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.1353952.1609763 (Exim 4.92) (envelope-from ) id 1wflMr-0002vx-QG; Fri, 03 Jul 2026 21:24:13 +0000 Received: by outflank-mailman (output) from mailman id 1353952.1609763; Fri, 03 Jul 2026 21:24:13 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflMr-0002uz-GE; Fri, 03 Jul 2026 21:24:13 +0000 Received: by outflank-mailman (input) for mailman id 1353952; Fri, 03 Jul 2026 21:24:12 +0000 Received: from mx.expurgate.net ([195.190.135.20]) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflMp-0002lY-W8 for xen-devel@lists.xenproject.org; Fri, 03 Jul 2026 21:24:11 +0000 Received: from mx.expurgate.net (helo=localhost) by mx.expurgate.net with esmtp id 1wflMp-00A8LG-Cn; Fri, 03 Jul 2026 23:24:11 +0200 Received: from [10.42.69.7] (helo=localhost) by localhost with ESMTP (eXpurgate MTA 0.9.1) (envelope-from ) id 6a48281d-bab6-0a2a0a5309dd-0a2a4507d556-28 for ; Fri, 03 Jul 2026 23:24:10 +0200 Received: from [90.155.92.199] (helo=desiato.infradead.org) by tlsNG-ef75cf.mxtls.expurgate.net with ESMTPS (eXpurgate 4.57.1) (envelope-from ) id 6a48287a-9c8e-0a2a45070019-5a9b5cc78b72-3 for ; Fri, 03 Jul 2026 23:24:10 +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 1wflKe-000000059OC-0v73; Fri, 03 Jul 2026 21:23:05 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.99.2 #2 (Red Hat Linux)) id 1wflKX-00000001RPn-1wE5; Fri, 03 Jul 2026 22:21:49 +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=cd7ADB+seora88pbKs2aD/tIbj9VePpwMwSL1OtTGjc=; b=apbGiZMkUWlTVRA2dMsajeQnJ0 RhOJ6E89Pg9nZWfqc1RytnC60PxmSbLIc70g2wiX9+ooo+ZTGG+wuRG28iqP40gybMT4pWEYVKG45 IVR/hQwGVcaV0h45HGBgtN2qd4s+8dCM8XetiqvJ905knza/omAjyD5QDeKL2kLEu5tSs9t9rUG0C pUge3V166Jv7ecOVz6xHEpZMkC/QA8i04z7CCvmXPW7GybxZC1kDSoXQr3x1//zaHva65YLoum3ha jySMWli1TzgZTW4U5jDjlS4f0GHvt/pA6S68YpOLver+gZSd/WhlFkM4AA9b5RT7qhPBtTqlM1su1 y/Xr5sFQ==; 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 30/36] KVM: x86: Re-synchronize TSC after KVM_SET_TSC_KHZ Date: Fri, 3 Jul 2026 22:18:09 +0100 Message-ID: <20260703212145.343527-31-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-ef75cf/1783113850-145FC25E-F64A76C9/0/0 X-purgate-type: clean X-purgate-size: 2200 X-ZohoMail-DKIM: pass (identity @infradead.org) X-ZM-MESSAGEID: 1783113879080158500 Content-Type: text/plain; charset="utf-8" From: David Woodhouse KVM_SET_TSC_KHZ changes the vCPU's TSC scaling ratio but does not update the VM-wide cur_tsc_scaling_ratio used by get_kvmclock(). This causes get_kvmclock() to use a stale (default 1:1) ratio when computing the KVM clock, leading to drift between the host-side kvmclock and what the guest observes. Fix this by calling kvm_synchronize_tsc() after changing the TSC frequency. This: - Updates cur_tsc_scaling_ratio (consumed by pvclock_update_vm_gtod_copy) - Ensures the TSC value is continuous across the frequency change - Triggers kvm_track_tsc_matching() for proper masterclock handling - Allows subsequent vCPUs to synchronize via the 1-second slop hack Signed-off-by: David Woodhouse --- arch/x86/kvm/x86.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 80fe69974ded..37a768b2fe16 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -206,6 +206,7 @@ module_param(mitigate_smt_rsb, bool, 0444); #ifdef CONFIG_X86_64 static bool kvm_get_time_and_clockread(s64 *kernel_ns, u64 *tsc_timestamp); #endif +static void kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 *user_value); #define KVM_MAX_NR_USER_RETURN_MSRS 16 =20 struct kvm_user_return_msrs { @@ -2584,6 +2585,7 @@ static int kvm_set_tsc_khz(struct kvm_vcpu *vcpu, u32= user_tsc_khz) { u32 thresh_lo, thresh_hi; int use_scaling =3D 0; + u64 tsc; =20 /* tsc_khz can be zero if TSC calibration fails */ if (user_tsc_khz =3D=3D 0) { @@ -2611,7 +2613,17 @@ static int kvm_set_tsc_khz(struct kvm_vcpu *vcpu, u3= 2 user_tsc_khz) user_tsc_khz, thresh_lo, thresh_hi); use_scaling =3D 1; } - return set_tsc_khz(vcpu, user_tsc_khz, use_scaling); + /* + * Read the guest TSC before changing the ratio, so we can + * re-synchronize to preserve continuity across the change. + */ + tsc =3D kvm_read_l1_tsc(vcpu, rdtsc()); + + if (set_tsc_khz(vcpu, user_tsc_khz, use_scaling)) + return -1; + + kvm_synchronize_tsc(vcpu, &tsc); + return 0; } =20 static u64 compute_guest_tsc(struct kvm_vcpu *vcpu, s64 kernel_ns) --=20 2.54.0 From nobody Fri Jul 10 17:09:11 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=1783113831; cv=none; d=zohomail.com; s=zohoarc; b=EDcYyhEEuant4fT0wIH2Uekj4RvO8sgaHKjlFxwVUb1yqpmjIMwexLCJ8nVUgFQOIlE401YBoYBbF0aQ2RM3F4Fv0TP2be3VWpvO7EYJeuc7yTJc/VL2o7tkqnmE2130mWTV9nDLIUD3acDpEFph1k6LmugSNAUWxjnlGi14h1c= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1783113831; h=Content-Type: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=MSS/L0DlzIiHi7Bw2B047mUTxdF1yD6n9Esd4lrjANw=; b=ls7mveoHc7+ICOEhpT+an6KJSDCfWF+tHNpBCTd4gp7zUTYsd/+NeFbAWDGfWfvY6X9klYDcdUVr4pQaxPQhgYgSNPQyHgydN52U5QbldYImJn4w9y7U6xsWk39aEm7uC39FoO08dotr6/nf9YrLSmfueTdyY1wVyqRC0n0Dl64= 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 178311383177689.28777516888238; Fri, 3 Jul 2026 14:23:51 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.1353876.1609596 (Exim 4.92) (envelope-from ) id 1wflM6-0004Ul-Py; Fri, 03 Jul 2026 21:23:26 +0000 Received: by outflank-mailman (output) from mailman id 1353876.1609596; Fri, 03 Jul 2026 21:23:26 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflM6-0004UL-K2; Fri, 03 Jul 2026 21:23:26 +0000 Received: by outflank-mailman (input) for mailman id 1353876; Fri, 03 Jul 2026 21:23:25 +0000 Received: from mx.expurgate.net ([194.145.224.20]) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflM4-0004QI-El for xen-devel@lists.xenproject.org; Fri, 03 Jul 2026 21:23:25 +0000 Received: from mx.expurgate.net (helo=localhost) by mx.expurgate.net with esmtp id 1wflM3-00BXKf-Rt; Fri, 03 Jul 2026 23:23:23 +0200 Received: from [10.42.69.9] (helo=localhost) by localhost with ESMTP (eXpurgate MTA 0.9.1) (envelope-from ) id 6a4827dc-2eae-0a2a0a5409dd-0a2a4509cd18-38 for ; Fri, 03 Jul 2026 23:23:23 +0200 Received: from [90.155.92.199] (helo=desiato.infradead.org) by tlsNG-bad1c0.mxtls.expurgate.net with ESMTPS (eXpurgate 4.57.1) (envelope-from ) id 6a48284a-97e6-0a2a45090019-5a9b5cc7a69c-3 for ; Fri, 03 Jul 2026 23:23:23 +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 1wflKe-000000059OD-0yjS; Fri, 03 Jul 2026 21:22:53 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.99.2 #2 (Red Hat Linux)) id 1wflKX-00000001RPs-2B0E; Fri, 03 Jul 2026 22:21:49 +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:Content-Type: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: Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:To: From:Reply-To:Cc:Content-ID:Content-Description; bh=MSS/L0DlzIiHi7Bw2B047mUTxdF1yD6n9Esd4lrjANw=; b=iU6SK+6HlatYeQ2gl9tGwyLkqi sAlSNaCj1PI5JPhBJmRbg/ZFhceYepOCKk0FhLL4jYcu0Ca1VR2EtHfZyR4QbM6Nkewx7oXq5ElzM SEIB8TwnLNxYKX69h8tecrdlNIfS4rDY4Bwhm5882oYca8mbjNYb3jUkg7/HSWCpmyYBUBFyQOOi3 tcR/CDUHlwPBWqbHVVgaWWgQRlA6+jwPo9gNJ9sC8Gj+x8HkO25EeY7RimOfYveAQMCdQmD5iWBYI UP7CHZJJi5EKQaHg39iDBGsOfy3hGBLeHuhNl9ZJkgXvFeo9mpsYJEgU9DxfO7FEEbwn5yRsKKDgf yzRGECYw==; 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 31/36] KVM: selftests: Add Xen runstate migration test Date: Fri, 3 Jul 2026 22:18:10 +0100 Message-ID: <20260703212145.343527-32-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-Type: text/plain; charset="utf-8" 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-bad1c0/1783113803-47731986-BAA3D1A4/0/0 X-purgate-type: clean X-purgate-size: 8510 X-ZohoMail-DKIM: pass (identity @infradead.org) X-ZM-MESSAGEID: 1783113832968158500 From: David Woodhouse Test that Xen runstate (steal time) is correctly accounted across a simulated live migration using KVM_XEN_VCPU_ATTR and KVM_[GS]ET_CLOCK_GUEST. The test simulates what a real VMM does during migration: 1. Creates a VM with Xen HVM config and runstate tracking 2. Runs the guest to accumulate some kvmclock time 3. Saves clock (KVM_GET_CLOCK_GUEST), TSC offset, and runstate 4. Marks the saved state as RUNSTATE_runnable (vCPU not running) 5. Destroys the source VM 6. Sleeps 10ms (simulating migration network transfer time) 7. Creates a new VM and restores all state precisely as saved 8. Runs the guest and verifies the migration gap appears as steal The kernel accounts the gap because: on vcpu_load, it transitions from RUNSTATE_runnable to RUNSTATE_running, computing delta =3D kvmclock_now - state_entry_time. Since kvmclock has advanced past the saved entry time (real time elapsed during migration), the delta is added to time_runnable. Signed-off-by: David Woodhouse --- tools/testing/selftests/kvm/Makefile.kvm | 1 + .../selftests/kvm/x86/xen_migration_test.c | 194 ++++++++++++++++++ 2 files changed, 195 insertions(+) create mode 100644 tools/testing/selftests/kvm/x86/xen_migration_test.c diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selft= ests/kvm/Makefile.kvm index 58aac2980cdf..f155683bd7f8 100644 --- a/tools/testing/selftests/kvm/Makefile.kvm +++ b/tools/testing/selftests/kvm/Makefile.kvm @@ -142,6 +142,7 @@ TEST_GEN_PROGS_x86 +=3D x86/debug_regs TEST_GEN_PROGS_x86 +=3D x86/tsc_msrs_test TEST_GEN_PROGS_x86 +=3D x86/vmx_pmu_caps_test TEST_GEN_PROGS_x86 +=3D x86/xen_cpuid_timing_test +TEST_GEN_PROGS_x86 +=3D x86/xen_migration_test TEST_GEN_PROGS_x86 +=3D x86/xen_shinfo_test TEST_GEN_PROGS_x86 +=3D x86/xen_vmcall_test TEST_GEN_PROGS_x86 +=3D x86/sev_init2_tests diff --git a/tools/testing/selftests/kvm/x86/xen_migration_test.c b/tools/t= esting/selftests/kvm/x86/xen_migration_test.c new file mode 100644 index 000000000000..4a041d36f1b9 --- /dev/null +++ b/tools/testing/selftests/kvm/x86/xen_migration_test.c @@ -0,0 +1,194 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Test Xen runstate (steal time) preservation across simulated migration. + * + * Verifies that the kernel correctly accounts the migration gap as + * steal time (runnable) when runstate data is saved and restored + * precisely, but real time elapses during the migration. + * + * The key insight: userspace saves the runstate with state=3DRUNSTATE_run= nable + * (the vCPU is not running during migration). On restore, the kernel sees + * that kvmclock has advanced past state_entry_time, and accounts the + * difference as time spent in the runnable state. + */ +#include +#include +#include +#include +#include + +#include "test_util.h" +#include "kvm_util.h" +#include "processor.h" + +#include + +#define SHINFO_GPA 0xc0000000ULL +#define RUNSTATE_GPA (SHINFO_GPA + 0x1000) + +#define RUNSTATE_running 0 +#define RUNSTATE_runnable 1 +#define RUNSTATE_blocked 2 +#define RUNSTATE_offline 3 + +struct vcpu_runstate_info { + uint32_t state; + uint64_t state_entry_time; + uint64_t time[4]; +} __attribute__((packed)); + +static void guest_code(void) +{ + volatile struct vcpu_runstate_info *rs =3D + (void *)(unsigned long)RUNSTATE_GPA; + + /* Report runstate times =E2=80=94 no need to enable kvmclock MSR, + * the kernel writes runstate using its internal kvmclock. */ + GUEST_SYNC_ARGS(0, rs->time[RUNSTATE_runnable], + rs->time[RUNSTATE_running], 0, 0); +} + +static struct kvm_vm *create_xen_vm(struct kvm_vcpu **vcpu) +{ + struct kvm_vm *vm; + int xen_caps; + + vm =3D vm_create_with_one_vcpu(vcpu, guest_code); + + xen_caps =3D kvm_check_cap(KVM_CAP_XEN_HVM); + TEST_REQUIRE(xen_caps & KVM_XEN_HVM_CONFIG_SHARED_INFO); + TEST_REQUIRE(xen_caps & KVM_XEN_HVM_CONFIG_RUNSTATE); + + /* Map pages */ + vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, + SHINFO_GPA, 1, 2, 0); + virt_map(vm, SHINFO_GPA, SHINFO_GPA, 2); + + /* Enable Xen HVM with MSR interception (enables runstate tracking) */ + struct kvm_xen_hvm_config cfg =3D { + .flags =3D KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL, + .msr =3D 0x40000000, + }; + vm_ioctl(vm, KVM_XEN_HVM_CONFIG, &cfg); + + /* Set shared_info */ + struct kvm_xen_hvm_attr ha =3D { + .type =3D KVM_XEN_ATTR_TYPE_SHARED_INFO, + .u.shared_info.gfn =3D SHINFO_GPA >> 12, + }; + vm_ioctl(vm, KVM_XEN_HVM_SET_ATTR, &ha); + + /* Set runstate address */ + struct kvm_xen_vcpu_attr rs_addr =3D { + .type =3D KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADDR, + .u.gpa =3D RUNSTATE_GPA, + }; + vcpu_ioctl(*vcpu, KVM_XEN_VCPU_SET_ATTR, &rs_addr); + + return vm; +} + +int main(void) +{ + struct pvclock_vcpu_time_info pvti; + struct kvm_xen_vcpu_attr runstate_save; + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + struct ucall uc; + uint64_t tsc_offset; + int ret; + + /* =3D=3D=3D SOURCE SIDE =3D=3D=3D */ + pr_info("=3D=3D=3D Source: create VM and run guest =3D=3D=3D\n"); + vm =3D create_xen_vm(&vcpu); + + /* Run guest once to accumulate some runstate time */ + vcpu_run(vcpu); + TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO); + TEST_ASSERT_EQ(get_ucall(vcpu, &uc), UCALL_SYNC); + + pr_info(" Guest sees: runnable=3D%" PRIu64 " running=3D%" PRIu64 "\n", + uc.args[2], uc.args[3]); + + /* Save clock state */ + ret =3D __vcpu_ioctl(vcpu, KVM_GET_CLOCK_GUEST, &pvti); + TEST_ASSERT(!ret, "KVM_GET_CLOCK_GUEST failed"); + + /* Save TSC offset */ + tsc_offset =3D vcpu_get_msr(vcpu, MSR_IA32_TSC_ADJUST); + + /* Save runstate =E2=80=94 the vCPU is now "runnable" (not running) */ + runstate_save.type =3D KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_DATA; + vcpu_ioctl(vcpu, KVM_XEN_VCPU_GET_ATTR, &runstate_save); + + /* + * Transition to runnable state before saving =E2=80=94 the vCPU is + * not running during migration. + */ + runstate_save.u.runstate.state =3D RUNSTATE_runnable; + + pr_info(" Saved runstate: running=3D%" PRIu64 " runnable=3D%" PRIu64 + " entry=3D%" PRIu64 "\n", + (uint64_t)runstate_save.u.runstate.time_running, + (uint64_t)runstate_save.u.runstate.time_runnable, + (uint64_t)runstate_save.u.runstate.state_entry_time); + + uint64_t saved_runnable =3D runstate_save.u.runstate.time_runnable; + + kvm_vm_free(vm); + + /* =3D=3D=3D MIGRATION GAP =3D=3D=3D */ + pr_info("=3D=3D=3D Simulating migration (sleeping 10ms) =3D=3D=3D\n"); + usleep(10000); + + /* =3D=3D=3D DESTINATION SIDE =3D=3D=3D */ + pr_info("=3D=3D=3D Destination: create new VM and restore =3D=3D=3D\n"); + vm =3D create_xen_vm(&vcpu); + + /* Restore TSC offset */ + vcpu_set_msr(vcpu, MSR_IA32_TSC_ADJUST, tsc_offset); + + /* Restore clock =E2=80=94 kvmclock will now be ~10ms ahead of the snapsh= ot */ + vcpu_ioctl(vcpu, KVM_SET_CLOCK_GUEST, &pvti); + + /* Restore runstate exactly as saved (state=3Drunnable) */ + runstate_save.type =3D KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_DATA; + ret =3D __vcpu_ioctl(vcpu, KVM_XEN_VCPU_SET_ATTR, &runstate_save); + TEST_ASSERT(!ret, "Restore runstate failed: errno %d", errno); + + /* + * Run the guest. When the vCPU enters vcpu_run, the kernel + * transitions from RUNSTATE_runnable to RUNSTATE_running. + * It computes: delta =3D kvmclock_now - state_entry_time + * This delta (which includes the migration gap) is added to + * time_runnable (steal time). + */ + vcpu_run(vcpu); + TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO); + TEST_ASSERT_EQ(get_ucall(vcpu, &uc), UCALL_SYNC); + + uint64_t guest_runnable =3D uc.args[2]; + uint64_t guest_running =3D uc.args[3]; + + pr_info(" Guest sees: runnable=3D%" PRIu64 " running=3D%" PRIu64 "\n", + guest_runnable, guest_running); + + uint64_t steal_increase =3D guest_runnable - saved_runnable; + pr_info(" Steal time increase: %" PRIu64 " ns (migration gap)\n", + steal_increase); + + /* + * The steal time increase should be at least 10ms (the sleep) + * but not more than 5s (allowing for VM creation overhead). + * The actual gap is from the source's state_entry_time to the + * destination's kvmclock "now" at vcpu_load time. + */ + TEST_ASSERT(steal_increase >=3D 10000000ULL && + steal_increase < 5000000000ULL, + "Steal time increase %" PRIu64 " ns not in expected range " + "[10ms, 5s]", steal_increase); + + kvm_vm_free(vm); + pr_info("PASS: Migration gap correctly accounted as steal time\n"); + return 0; +} --=20 2.54.0 From nobody Fri Jul 10 17:09:11 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=1783113838; cv=none; d=zohomail.com; s=zohoarc; b=czouLIJIkzfMvwr0J7eE+hwfkX7jmaAadlfAI4uPkcNTlFaRng98+7gu40cggj2wuJiUTQhujPnkpfV/pN+PI5u+dhz+VXcl85BM5jOlXNY1onL2WmDhJDyL957gQOqUvyruo1bIU6Np7EXTTMQc4WNxtiD6yWwR17pfhssmPDQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1783113838; 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=1OUv5CdFlAHAtCyTuuEwus8cGCX4Zb6KK8eBdOb5xl8=; b=ZxuODSdL8HI4sr0MxuGKsmR1aE1nM0/H+JQ0iFMqGnaS9lXOioJM2SpEG6Zj1Z4bWO2GZ1U1DAikjftIH8NZdq/9G8ei9eKEzND19Y+F0GNBH1PryuR2LF2xUjZXwVNLrmJ59R8YxusM0YhD2vGwU7JoMp4kRY8i0Z1LHZK5CE4= 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 1783113838436188.77296280045846; Fri, 3 Jul 2026 14:23:58 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.1353878.1609618 (Exim 4.92) (envelope-from ) id 1wflMD-0005DE-6U; Fri, 03 Jul 2026 21:23:33 +0000 Received: by outflank-mailman (output) from mailman id 1353878.1609618; Fri, 03 Jul 2026 21:23:33 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflMD-0005D0-2w; Fri, 03 Jul 2026 21:23:33 +0000 Received: by outflank-mailman (input) for mailman id 1353878; Fri, 03 Jul 2026 21:23:31 +0000 Received: from mx.expurgate.net ([195.190.135.10]) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflMB-00052w-Ee for xen-devel@lists.xenproject.org; Fri, 03 Jul 2026 21:23:31 +0000 Received: from mx.expurgate.net (helo=localhost) by mx.expurgate.net with esmtp id 1wflMA-00BElj-Rp; Fri, 03 Jul 2026 23:23:30 +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-10 for ; Fri, 03 Jul 2026 23:23:30 +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 6a48284f-e40e-0a2a450a0019-5a9b5cc7a18a-3 for ; Fri, 03 Jul 2026 23:23:27 +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 1wflKe-000000059OE-0v6i; Fri, 03 Jul 2026 21:22:53 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.99.2 #2 (Red Hat Linux)) id 1wflKX-00000001RPx-2LRG; Fri, 03 Jul 2026 22:21:49 +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=1OUv5CdFlAHAtCyTuuEwus8cGCX4Zb6KK8eBdOb5xl8=; b=iAY6MPfXrlFmZymwYSi+vVUVlO Foj75r55Pg0RY2rE1G43N+8fD9XfvQ9wvrkZ6IQFehekLM47aqnS2WyUEiaEq45e/K3+QqpL883g2 oxc0gIJzsIQslagkNwURfAqdrJBtEiZF1ADO/kBfNTsCiCu2whVOx6OV+YtpWXnWiJjHf/km1xwi8 BjZeLG8R28itKIdJU2ORDJdGL/twrFkXyZF4cfcv/Ls01m6xV3PS2mcL+rBFHVol6Gi9uDe/rCWHY weB/t2G31ola0QBkAmIxp7fDT6IzQ5OkKGjhGdZVLn5cAiSUfsWQGKBUU3K3pD2jWVTS4EmGKfQAR jmWut/Bw==; 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 32/36] KVM: x86: Use ktime_get_snapshot_id() for master clock Date: Fri, 3 Jul 2026 22:18:11 +0100 Message-ID: <20260703212145.343527-33-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/1783113807-CF537DDE-DC71D870/0/0 X-purgate-type: clean X-purgate-size: 3954 X-ZohoMail-DKIM: pass (identity @infradead.org) X-ZM-MESSAGEID: 1783113838999158500 Content-Type: text/plain; charset="utf-8" From: David Woodhouse Replace the KVM-private vgettsc()/do_kvmclock_base()/do_monotonic()/ do_realtime() timekeeping reimplementation with calls to the generic ktime_get_snapshot_id() interface. The snapshot provides both the system time and the raw_cycles (TSC) atomically paired. When raw_cycles is zero, the clocksource could not provide a raw hardware counter value, which is equivalent to the previous vgettsc() returning VDSO_CLOCKMODE_NONE. For kvm_get_time_and_clockread(), the kvmclock base time is CLOCK_MONOTONIC_RAW + offs_boot. The snapshot provides the raw time atomically paired with the TSC; offs_boot is added separately as it only changes at suspend/resume boundaries. This is a step towards eliminating the pvclock_gtod_data private copy of timekeeping state and the associated notifier callback. Signed-off-by: David Woodhouse Assisted-by: Kiro:claude-opus-4.6-1m --- arch/x86/kvm/x86.c | 53 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 42 insertions(+), 11 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 37a768b2fe16..56afd5e66c06 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -35,6 +35,7 @@ #include "smm.h" =20 #include +#include #include #include #include @@ -3154,14 +3155,39 @@ static int do_realtime(struct timespec64 *ts, u64 *= tsc_timestamp) * reports the TSC value from which it do so. Returns true if host is * using TSC based clocksource. */ +static bool kvm_snapshot_has_tsc(struct system_time_snapshot *snap, + u64 *tsc_timestamp) +{ + /* + * ktime_get_snapshot_id() cannot fail for standard clock IDs + * (only for invalid/aux clocks or during suspend, with a WARN). + */ + if (!snap->valid) + return false; + + if (snap->cs_id =3D=3D CSID_X86_TSC) { + *tsc_timestamp =3D snap->cycles; + return true; + } + + if (snap->hw_csid =3D=3D CSID_X86_TSC && snap->hw_cycles) { + *tsc_timestamp =3D snap->hw_cycles; + return true; + } + + return false; +} + static bool kvm_get_time_and_clockread(s64 *kernel_ns, u64 *tsc_timestamp) { - /* checked again under seqlock below */ - if (!gtod_is_based_on_tsc(pvclock_gtod_data.clock.vclock_mode)) + struct system_time_snapshot snap =3D {}; + + ktime_get_snapshot_id(CLOCK_MONOTONIC_RAW, &snap); + if (!kvm_snapshot_has_tsc(&snap, tsc_timestamp)) return false; =20 - return gtod_is_based_on_tsc(do_kvmclock_base(kernel_ns, - tsc_timestamp)); + *kernel_ns =3D ktime_to_ns(ktime_mono_to_any(snap.systime, TK_OFFS_BOOT)); + return true; } =20 /* @@ -3170,12 +3196,14 @@ static bool kvm_get_time_and_clockread(s64 *kernel_= ns, u64 *tsc_timestamp) */ bool kvm_get_monotonic_and_clockread(s64 *kernel_ns, u64 *tsc_timestamp) { - /* checked again under seqlock below */ - if (!gtod_is_based_on_tsc(pvclock_gtod_data.clock.vclock_mode)) + struct system_time_snapshot snap =3D {}; + + ktime_get_snapshot_id(CLOCK_MONOTONIC, &snap); + if (!kvm_snapshot_has_tsc(&snap, tsc_timestamp)) return false; =20 - return gtod_is_based_on_tsc(do_monotonic(kernel_ns, - tsc_timestamp)); + *kernel_ns =3D ktime_to_ns(snap.systime); + return true; } =20 /* @@ -3188,11 +3216,14 @@ bool kvm_get_monotonic_and_clockread(s64 *kernel_ns= , u64 *tsc_timestamp) static bool kvm_get_walltime_and_clockread(struct timespec64 *ts, u64 *tsc_timestamp) { - /* checked again under seqlock below */ - if (!gtod_is_based_on_tsc(pvclock_gtod_data.clock.vclock_mode)) + struct system_time_snapshot snap =3D {}; + + ktime_get_snapshot_id(CLOCK_REALTIME, &snap); + if (!kvm_snapshot_has_tsc(&snap, tsc_timestamp)) return false; =20 - return gtod_is_based_on_tsc(do_realtime(ts, tsc_timestamp)); + *ts =3D ktime_to_timespec64(snap.systime); + return true; } #endif =20 --=20 2.54.0 From nobody Fri Jul 10 17:09:11 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=1783113770; cv=none; d=zohomail.com; s=zohoarc; b=BN7WUpHZa/A93R1BAhAnVWOzFb1hIhErtus9lgAU2K0SPMtyPeLTJH9CM85dMkDmclQdQp8n4CJIc9GaXPZTBVfVQBhz90aFUilh91yoe+1Wm0zm4gZRbN9jkdfkRzgEwzyAFLC+wGECCazqetjuS2ELDbOA4KRCk8D6E8VyM0I= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1783113770; 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=O/oUbS7kYPJiTQjk6lyYh7lx0CQJ2SSehd3aLwyJ2+s=; b=CJbHu3wGnor7VyHq9iuvSktiPPZ7r5Nac79KRm/FOSdbejZweKHwrme7dXvvMgXR1lTkJ26urynrZwuCkK+RoI5tfsy0or5caM83yppuLjFJPCrOREokOIYPV3haF5JXD3sLtcV118wb44A/HY2r//Hmdaxnr6tnp1uZQuh0AKE= 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 1783113770831585.891094712796; Fri, 3 Jul 2026 14:22:50 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.1353776.1609582 (Exim 4.92) (envelope-from ) id 1wflL6-00013V-0G; Fri, 03 Jul 2026 21:22:24 +0000 Received: by outflank-mailman (output) from mailman id 1353776.1609582; Fri, 03 Jul 2026 21:22:23 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflL5-00012A-QH; Fri, 03 Jul 2026 21:22:23 +0000 Received: by outflank-mailman (input) for mailman id 1353776; Fri, 03 Jul 2026 21:22:22 +0000 Received: from mx.expurgate.net ([194.145.224.20]) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflL4-0000qR-B0 for xen-devel@lists.xenproject.org; Fri, 03 Jul 2026 21:22:22 +0000 Received: from mx.expurgate.net (helo=localhost) by mx.expurgate.net with esmtp id 1wflL3-00BXCb-O9; Fri, 03 Jul 2026 23:22:21 +0200 Received: from [10.42.69.1] (helo=localhost) by localhost with ESMTP (eXpurgate MTA 0.9.1) (envelope-from ) id 6a48279b-2eae-0a2a0a5409dd-0a2a45019e62-30 for ; Fri, 03 Jul 2026 23:22:21 +0200 Received: from [90.155.50.34] (helo=casper.infradead.org) by tlsNG-d62444.mxtls.expurgate.net with ESMTPS (eXpurgate 4.57.1) (envelope-from ) id 6a48280d-400f-0a2a45010019-5a9b3222d726-3 for ; Fri, 03 Jul 2026 23:22:21 +0200 Received: from [2001:8b0:10b:1::425] (helo=i7.infradead.org) by casper.infradead.org with esmtpsa (Exim 4.99.1 #2 (Red Hat Linux)) id 1wflKX-0000000AsYP-3AaT; Fri, 03 Jul 2026 21:21:49 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.99.2 #2 (Red Hat Linux)) id 1wflKX-00000001RQ2-2bjR; Fri, 03 Jul 2026 22:21:49 +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=casper.20170209 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=casper.20170209; 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=O/oUbS7kYPJiTQjk6lyYh7lx0CQJ2SSehd3aLwyJ2+s=; b=aeZWxhF7AsGk3HBJM42jxJ3/G5 41bAnL10ZxObpBizC6FNpkO2Xhx7SLTdkscJ8MKF5yDV47DW5K+0Rw52xwDwbc1v5Xr6MFbnNaTIv fMmGadiIUz9/bFMDHwx0xHflvuT1vZtuOSFpAKCF3QT2vzA8bXyzcVb4uDPgzNPhaOjGPB/vOO/IA loTUM/AxnKgV+4Vvn7XmBqxGyMwOCoM+b1mH5d8sGRjOgY1ASOuzE7uJuQuuP+lcgT+aChKij4fAP gHIMwiL9H7nnCcslwip0AW7fSsC5uwRS4Eu3HetQtUtYTjnz0/Qt9luFtpmls6AGa86HRk5vBEFwt e062+P2A==; 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 33/36] KVM: x86: Compute kvmclock base without pvclock_gtod_data Date: Fri, 3 Jul 2026 22:18:12 +0100 Message-ID: <20260703212145.343527-34-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 casper.infradead.org. See http://www.infradead.org/rpr.html X-purgate-ID: tlsNG-d62444/1783113741-80AD11E0-32343D7B/0/0 X-purgate-type: clean X-purgate-size: 1092 X-ZohoMail-DKIM: pass (identity @infradead.org) X-ZM-MESSAGEID: 1783113772522158500 Content-Type: text/plain; charset="utf-8" From: David Woodhouse get_kvmclock_base_ns() needs CLOCK_MONOTONIC_RAW + offs_boot. Compute this directly rather than reading offs_boot from the pvclock_gtod_data private copy. offs_boot only changes at suspend/resume so does not need to be atomically paired with the raw clock read. Signed-off-by: David Woodhouse Assisted-by: Kiro:claude-opus-4.6-1m --- arch/x86/kvm/x86.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 56afd5e66c06..8d520bfae089 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2402,7 +2402,7 @@ static void update_pvclock_gtod(struct timekeeper *tk) static s64 get_kvmclock_base_ns(void) { /* Count up from boot time, but with the frequency of the raw clock. */ - return ktime_to_ns(ktime_add(ktime_get_raw(), pvclock_gtod_data.offs_boot= )); + return ktime_to_ns(ktime_mono_to_any(ktime_get_raw(), TK_OFFS_BOOT)); } =20 static void kvm_write_wall_clock(struct kvm *kvm, gpa_t wall_clock, int se= c_hi_ofs) --=20 2.54.0 From nobody Fri Jul 10 17:09:11 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=1783113762; cv=none; d=zohomail.com; s=zohoarc; b=Bcdh6mMjYHUIvue6v9rBgKjnSzFJMOdntyuc3Sr7pwhd9CHnSDQxSBzJAd1TiOjVfdNcG7gGhuERMWDER3YeOO2dcNSRUpaBRq22xE5ZSN63kg6Nx6W/TafLobUSyAKUUIjT+i224qO2EHuSKjwOpzIrC1/IzRHiDZoooPdLNGg= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1783113762; h=Content-Type: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=EpzXffKcCC8OCVBj38i2t8eVI2Er97bsxo1QNBYCK8E=; b=h+8dtf5mW+xbbFBWPOCwhPSALV0ss+hvZ0gcCksSQlqdRkC/NGD8i/y8DXVVQBco3Npbx/7mx/jyxcyDmjU8ojOxKf1Xc7Zlj//yVxdh+JLQfMFixclP5L2FvhVKFHTfuNZ95rskUTj1h/JW7ly1PbXgmt2Q1pEp0FRxp5iCCzI= 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 1783113762716198.25361059553506; Fri, 3 Jul 2026 14:22:42 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.1353748.1609438 (Exim 4.92) (envelope-from ) id 1wflKm-000522-Fe; Fri, 03 Jul 2026 21:22:04 +0000 Received: by outflank-mailman (output) from mailman id 1353748.1609438; Fri, 03 Jul 2026 21:22:04 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflKm-00051r-CB; Fri, 03 Jul 2026 21:22:04 +0000 Received: by outflank-mailman (input) for mailman id 1353748; Fri, 03 Jul 2026 21:22:03 +0000 Received: from mx.expurgate.net ([194.145.224.10]) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflKk-00051O-DP for xen-devel@lists.xenproject.org; Fri, 03 Jul 2026 21:22:03 +0000 Received: from mx.expurgate.net (helo=localhost) by mx.expurgate.net with esmtp id 1wflKj-001t36-Bn; Fri, 03 Jul 2026 23:22:01 +0200 Received: from [10.42.69.3] (helo=localhost) by localhost with ESMTP (eXpurgate MTA 0.9.1) (envelope-from ) id 6a4827ca-bab6-0a2a0a5309dd-0a2a4503bf3c-14 for ; Fri, 03 Jul 2026 23:22:01 +0200 Received: from [90.155.50.34] (helo=casper.infradead.org) by tlsNG-33051d.mxtls.expurgate.net with ESMTPS (eXpurgate 4.57.1) (envelope-from ) id 6a4827f8-ec1a-0a2a45030019-5a9b322284a8-3 for ; Fri, 03 Jul 2026 23:22:01 +0200 Received: from [2001:8b0:10b:1::425] (helo=i7.infradead.org) by casper.infradead.org with esmtpsa (Exim 4.99.1 #2 (Red Hat Linux)) id 1wflKX-0000000AsYQ-3NCh; Fri, 03 Jul 2026 21:21:50 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.99.2 #2 (Red Hat Linux)) id 1wflKX-00000001RQ7-2xkg; Fri, 03 Jul 2026 22:21:49 +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=casper.20170209 header.d=infradead.org header.i="@infradead.org" header.h="Sender:Content-Transfer-Encoding:Content-Type: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=casper.20170209; h=Sender:Content-Transfer-Encoding: Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:To: From:Reply-To:Cc:Content-ID:Content-Description; bh=EpzXffKcCC8OCVBj38i2t8eVI2Er97bsxo1QNBYCK8E=; b=jIerjpGT+yTwXfADnzFS9Ehvw1 qj5/hvk/X0LarGRgEVv+dsiKFbGxRWGknJH57gqRXscS5FUYAhSqnvtRBTN2Z6vn9teqs3fY7T27K jW8kTa1Wn2iOLEOqSbhIdiHt8Zmudzhq+tZg56Q8n6poP0Su9bZXGRUplcGieKFs0iNapavWjR6fc hzkoY/l9qx1zH8w8EdFXPjFM5inA9cmW6nJSdRy1/qSf00oSXhQLvq8P2NHcd9wzCsCydXn58F6FC AElEi2x7GlGagDUvtuQfZMQtQYs0miIjMnEqFVh2YzqPw/nArOHgfhgvtrehoSUcccIphTfkzHx4t XG8AdZ9w==; 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 34/36] KVM: x86: Cache host vclock_mode for masterclock eligibility checks Date: Fri, 3 Jul 2026 22:18:13 +0100 Message-ID: <20260703212145.343527-35-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-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Sender: David Woodhouse X-SRS-Rewrite: SMTP reverse-path rewritten from by casper.infradead.org. See http://www.infradead.org/rpr.html X-purgate-ID: tlsNG-33051d/1783113721-B4F835D1-4427BB93/0/0 X-purgate-type: clean X-purgate-size: 4113 X-ZohoMail-DKIM: pass (identity @infradead.org) X-ZM-MESSAGEID: 1783113764547158500 From: David Woodhouse The remaining users of pvclock_gtod_data only need to know whether the host clocksource is TSC-based. Cache the vclock_mode value in a simple kvm_host_vclock_mode variable, updated by the pvclock_gtod_notify callback, and use gtod_is_based_on_tsc() for eligibility checks. This is inherently racy (as it always was =E2=80=94 kvm_track_tsc_matching never held the gtod seqcount), relying on eventual consistency: the notifier fires on every timekeeping update and will correct any transient inconsistency within one tick. Signed-off-by: David Woodhouse Assisted-by: Kiro (claude-opus-4.6-1m) --- arch/x86/kvm/x86.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 8d520bfae089..c67655f8e078 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2647,6 +2647,8 @@ static u64 compute_guest_tsc(struct kvm_vcpu *vcpu, s= 64 kernel_ns) } =20 #ifdef CONFIG_X86_64 +static int kvm_host_vclock_mode; + static inline bool gtod_is_based_on_tsc(int mode) { return mode =3D=3D VDSO_CLOCKMODE_TSC || mode =3D=3D VDSO_CLOCKMODE_HVCLO= CK; @@ -2676,7 +2678,6 @@ static bool kvm_use_master_clock(struct kvm *kvm) static void kvm_track_tsc_matching(struct kvm_vcpu *vcpu, bool update_mclo= ck) { struct kvm_arch *ka =3D &vcpu->kvm->arch; - struct pvclock_gtod_data *gtod =3D &pvclock_gtod_data; bool prev_matched_tsc =3D ka->all_vcpus_matched_tsc; =20 /* @@ -2713,7 +2714,7 @@ static void kvm_track_tsc_matching(struct kvm_vcpu *v= cpu, bool update_mclock) * accounts for its offset. */ bool use_master_clock =3D kvm_use_master_clock(vcpu->kvm) && - gtod_is_based_on_tsc(gtod->clock.vclock_mode); + gtod_is_based_on_tsc(kvm_host_vclock_mode); =20 /* * Request a masterclock update if needed: toggling master clock, @@ -2726,11 +2727,11 @@ static void kvm_track_tsc_matching(struct kvm_vcpu = *vcpu, bool update_mclock) =20 trace_kvm_track_tsc(vcpu->vcpu_id, ka->nr_vcpus_matched_tsc, atomic_read(&vcpu->kvm->online_vcpus), - ka->use_master_clock, gtod->clock.vclock_mode); + ka->use_master_clock, kvm_host_vclock_mode); } #else static inline void kvm_track_tsc_matching(struct kvm_vcpu *vcpu, - bool new_generation) {} + bool update_mclock) {} #endif =20 /* @@ -2850,7 +2851,7 @@ static inline bool kvm_check_tsc_unstable(void) * TSC is marked unstable when we're running on Hyper-V, * 'TSC page' clocksource is good. */ - if (pvclock_gtod_data.clock.vclock_mode =3D=3D VDSO_CLOCKMODE_HVCLOCK) + if (kvm_host_vclock_mode =3D=3D VDSO_CLOCKMODE_HVCLOCK) return false; #endif return check_tsc_unstable(); @@ -3274,7 +3275,6 @@ static void pvclock_update_vm_gtod_copy(struct kvm *k= vm) { #ifdef CONFIG_X86_64 struct kvm_arch *ka =3D &kvm->arch; - int vclock_mode; bool host_tsc_clocksource; =20 lockdep_assert_held(&kvm->arch.tsc_write_lock); @@ -3314,9 +3314,9 @@ static void pvclock_update_vm_gtod_copy(struct kvm *k= vm) ka->use_master_clock =3D false; } =20 - vclock_mode =3D pvclock_gtod_data.clock.vclock_mode; - trace_kvm_update_master_clock(ka->use_master_clock, vclock_mode, - ka->all_vcpus_matched_freq); + trace_kvm_update_master_clock(ka->use_master_clock, + kvm_host_vclock_mode, + ka->all_vcpus_matched_freq); #endif } =20 @@ -10399,12 +10399,15 @@ static int pvclock_gtod_notify(struct notifier_bl= ock *nb, unsigned long unused, update_pvclock_gtod(tk); =20 #ifdef CONFIG_X86_64 + kvm_host_vclock_mode =3D + tk->tkr_mono.clock->vdso_clock_mode; + /* * Disable master clock if host does not trust, or does not use, * TSC based clocksource. Delegate queue_work() to irq_work as * this is invoked with tk_core.seq write held. */ - if (!gtod_is_based_on_tsc(pvclock_gtod_data.clock.vclock_mode) && + if (!gtod_is_based_on_tsc(kvm_host_vclock_mode) && atomic_read(&kvm_guest_has_master_clock) !=3D 0) irq_work_queue(&pvclock_irq_work); #endif --=20 2.54.0 From nobody Fri Jul 10 17:09:11 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=1783113841; cv=none; d=zohomail.com; s=zohoarc; b=Ly0WlC9GafAOwAh1CYwjgH6T9b6THjm6m9gRBGu53NDaC6+3dRyG8t015jNT4sDHLCZGYiAO54vNC4zqRdXKBcSk/8QPyR6HcVjgggtAqda9dP2L/GYO6iL/53PGhK6xrwsz3b49nsJEBfjzY+0a9AE+hrMM82GDbrj3H3hlPuY= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1783113841; 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=Ort/pZQb4ierCrxm1j8Wvj2iLn37EL9Xs8ile8CK+5w=; b=JIB8zHSgT9PCrYqAaywpaT1PkFvN/qPkMINFf3uWcyw3Y9idAGP8f5ER2f9ZsOcNQhkvDQHd8CWZXDyjFFGMci82nWkJojKh1EPxq8oynrpamlcheQOLxSBf2Lqxbl+pavrd+m0dCAnOQOj+A90qrAtQu8SCEaOdvMllZ1tu/jE= 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 1783113841670300.47522228924095; Fri, 3 Jul 2026 14:24:01 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.1353884.1609645 (Exim 4.92) (envelope-from ) id 1wflMP-0006D2-8H; Fri, 03 Jul 2026 21:23:45 +0000 Received: by outflank-mailman (output) from mailman id 1353884.1609645; Fri, 03 Jul 2026 21:23:45 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflMP-0006Cs-2Y; Fri, 03 Jul 2026 21:23:45 +0000 Received: by outflank-mailman (input) for mailman id 1353884; Fri, 03 Jul 2026 21:23:43 +0000 Received: from mx.expurgate.net ([194.145.224.20]) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflMN-0005qG-BT for xen-devel@lists.xenproject.org; Fri, 03 Jul 2026 21:23:43 +0000 Received: from mx.expurgate.net (helo=localhost) by mx.expurgate.net with esmtp id 1wflMM-000kw0-O4; Fri, 03 Jul 2026 23:23:42 +0200 Received: from [10.42.69.4] (helo=localhost) by localhost with ESMTP (eXpurgate MTA 0.9.1) (envelope-from ) id 6a48281c-2eae-0a2a0a5409dd-0a2a4504979a-10 for ; Fri, 03 Jul 2026 23:23:42 +0200 Received: from [90.155.92.199] (helo=desiato.infradead.org) by tlsNG-ebf023.mxtls.expurgate.net with ESMTPS (eXpurgate 4.57.1) (envelope-from ) id 6a48285d-a01d-0a2a45040019-5a9b5cc78d46-3 for ; Fri, 03 Jul 2026 23:23:42 +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 1wflKe-000000059OF-0vI4; Fri, 03 Jul 2026 21:23:11 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.99.2 #2 (Red Hat Linux)) id 1wflKX-00000001RQD-3BKG; Fri, 03 Jul 2026 22:21:49 +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=Ort/pZQb4ierCrxm1j8Wvj2iLn37EL9Xs8ile8CK+5w=; b=iGUqq6bke/f9INoPyifWfn6tMr Dxx9c7T5UqI5UMg8YjyLmZpMVseB7N8tyabz9obX/dC+ngIU3yv1JHY3JTAWY6WngiA570Ryh4IOF b01mRW0I0bfTI3wDMXY7Yqmz4AqjFrVwhNTMruP7kS6z7gO1y/WKqWK9lLjnLOsgL2ks7g7OnG9iK 1C80or7kq0ERNDnGtFaUh3xmfdkYHkkAWlJ+T0ZNUpaqHxFoQDCFHBGH5vce0dCBsk83GzuL97PPe r2wTSTLoYRY1lpzZtdTadwaq2mg2QrWDju/Gu1EeSlgsy4TO/ncXhKlwClbwNm7lOreXmIVUpUc0Y cP23OeUg==; 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 35/36] KVM: x86: Remove pvclock_gtod_data and private timekeeping code Date: Fri, 3 Jul 2026 22:18:14 +0100 Message-ID: <20260703212145.343527-36-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-ebf023/1783113822-AFD241CC-A09A4783/0/0 X-purgate-type: clean X-purgate-size: 6507 X-ZohoMail-DKIM: pass (identity @infradead.org) X-ZM-MESSAGEID: 1783113842985158500 Content-Type: text/plain; charset="utf-8" From: David Woodhouse Remove the now-unused KVM-private timekeeping infrastructure: - struct pvclock_clock and struct pvclock_gtod_data - update_pvclock_gtod() and its seqcount-protected state copy - read_tsc() (KVM's private TSC reader with cycle_last clamping) - vgettsc() (KVM's private clocksource interpolation) - do_kvmclock_base(), do_monotonic(), do_realtime() Signed-off-by: David Woodhouse Assisted-by: Kiro:claude-opus-4.6-1m --- arch/x86/kvm/x86.c | 178 +-------------------------------------------- 1 file changed, 1 insertion(+), 177 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index c67655f8e078..58016af64932 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2347,58 +2347,6 @@ static int do_set_msr(struct kvm_vcpu *vcpu, unsigne= d index, u64 *data) return kvm_set_msr_ignored_check(vcpu, index, *data, true); } =20 -struct pvclock_clock { - int vclock_mode; - u64 cycle_last; - u64 mask; - u32 mult; - u32 shift; - u64 base_cycles; - u64 offset; -}; - -struct pvclock_gtod_data { - seqcount_t seq; - - struct pvclock_clock clock; /* extract of a clocksource struct */ - struct pvclock_clock raw_clock; /* extract of a clocksource struct */ - - ktime_t offs_boot; - u64 wall_time_sec; -}; - -static struct pvclock_gtod_data pvclock_gtod_data; - -static void update_pvclock_gtod(struct timekeeper *tk) -{ - struct pvclock_gtod_data *vdata =3D &pvclock_gtod_data; - - write_seqcount_begin(&vdata->seq); - - /* copy pvclock gtod data */ - vdata->clock.vclock_mode =3D tk->tkr_mono.clock->vdso_clock_mode; - vdata->clock.cycle_last =3D tk->tkr_mono.cycle_last; - vdata->clock.mask =3D tk->tkr_mono.mask; - vdata->clock.mult =3D tk->tkr_mono.mult; - vdata->clock.shift =3D tk->tkr_mono.shift; - vdata->clock.base_cycles =3D tk->tkr_mono.xtime_nsec; - vdata->clock.offset =3D tk->tkr_mono.base; - - vdata->raw_clock.vclock_mode =3D tk->tkr_raw.clock->vdso_clock_mode; - vdata->raw_clock.cycle_last =3D tk->tkr_raw.cycle_last; - vdata->raw_clock.mask =3D tk->tkr_raw.mask; - vdata->raw_clock.mult =3D tk->tkr_raw.mult; - vdata->raw_clock.shift =3D tk->tkr_raw.shift; - vdata->raw_clock.base_cycles =3D tk->tkr_raw.xtime_nsec; - vdata->raw_clock.offset =3D tk->tkr_raw.base; - - vdata->wall_time_sec =3D tk->xtime_sec; - - vdata->offs_boot =3D tk->offs_boot; - - write_seqcount_end(&vdata->seq); -} - static s64 get_kvmclock_base_ns(void) { /* Count up from boot time, but with the frequency of the raw clock. */ @@ -3029,128 +2977,6 @@ static inline void adjust_tsc_offset_host(struct kv= m_vcpu *vcpu, s64 adjustment) =20 #ifdef CONFIG_X86_64 =20 -static u64 read_tsc(void) -{ - u64 ret =3D (u64)rdtsc_ordered(); - u64 last =3D pvclock_gtod_data.clock.cycle_last; - - if (likely(ret >=3D last)) - return ret; - - /* - * GCC likes to generate cmov here, but this branch is extremely - * predictable (it's just a function of time and the likely is - * very likely) and there's a data dependence, so force GCC - * to generate a branch instead. I don't barrier() because - * we don't actually need a barrier, and if this function - * ever gets inlined it will generate worse code. - */ - asm volatile (""); - return last; -} - -static inline u64 vgettsc(struct pvclock_clock *clock, u64 *tsc_timestamp, - int *mode) -{ - u64 tsc_pg_val; - long v; - - switch (clock->vclock_mode) { - case VDSO_CLOCKMODE_HVCLOCK: - if (hv_read_tsc_page_tsc(hv_get_tsc_page(), - tsc_timestamp, &tsc_pg_val)) { - /* TSC page valid */ - *mode =3D VDSO_CLOCKMODE_HVCLOCK; - v =3D (tsc_pg_val - clock->cycle_last) & - clock->mask; - } else { - /* TSC page invalid */ - *mode =3D VDSO_CLOCKMODE_NONE; - } - break; - case VDSO_CLOCKMODE_TSC: - *mode =3D VDSO_CLOCKMODE_TSC; - *tsc_timestamp =3D read_tsc(); - v =3D (*tsc_timestamp - clock->cycle_last) & - clock->mask; - break; - default: - *mode =3D VDSO_CLOCKMODE_NONE; - } - - if (*mode =3D=3D VDSO_CLOCKMODE_NONE) - *tsc_timestamp =3D v =3D 0; - - return v * clock->mult; -} - -/* - * As with get_kvmclock_base_ns(), this counts from boot time, at the - * frequency of CLOCK_MONOTONIC_RAW (hence adding gtos->offs_boot). - */ -static int do_kvmclock_base(s64 *t, u64 *tsc_timestamp) -{ - struct pvclock_gtod_data *gtod =3D &pvclock_gtod_data; - unsigned long seq; - int mode; - u64 ns; - - do { - seq =3D read_seqcount_begin(>od->seq); - ns =3D gtod->raw_clock.base_cycles; - ns +=3D vgettsc(>od->raw_clock, tsc_timestamp, &mode); - ns >>=3D gtod->raw_clock.shift; - ns +=3D ktime_to_ns(ktime_add(gtod->raw_clock.offset, gtod->offs_boot)); - } while (unlikely(read_seqcount_retry(>od->seq, seq))); - *t =3D ns; - - return mode; -} - -/* - * This calculates CLOCK_MONOTONIC at the time of the TSC snapshot, with - * no boot time offset. - */ -static int do_monotonic(s64 *t, u64 *tsc_timestamp) -{ - struct pvclock_gtod_data *gtod =3D &pvclock_gtod_data; - unsigned long seq; - int mode; - u64 ns; - - do { - seq =3D read_seqcount_begin(>od->seq); - ns =3D gtod->clock.base_cycles; - ns +=3D vgettsc(>od->clock, tsc_timestamp, &mode); - ns >>=3D gtod->clock.shift; - ns +=3D ktime_to_ns(gtod->clock.offset); - } while (unlikely(read_seqcount_retry(>od->seq, seq))); - *t =3D ns; - - return mode; -} - -static int do_realtime(struct timespec64 *ts, u64 *tsc_timestamp) -{ - struct pvclock_gtod_data *gtod =3D &pvclock_gtod_data; - unsigned long seq; - int mode; - u64 ns; - - do { - seq =3D read_seqcount_begin(>od->seq); - ts->tv_sec =3D gtod->wall_time_sec; - ns =3D gtod->clock.base_cycles; - ns +=3D vgettsc(>od->clock, tsc_timestamp, &mode); - ns >>=3D gtod->clock.shift; - } while (unlikely(read_seqcount_retry(>od->seq, seq))); - - ts->tv_sec +=3D __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns); - ts->tv_nsec =3D ns; - - return mode; -} - /* * Calculates the kvmclock_base_ns (CLOCK_MONOTONIC_RAW + boot time) and * reports the TSC value from which it do so. Returns true if host is @@ -10394,11 +10220,9 @@ static DEFINE_IRQ_WORK(pvclock_irq_work, pvclock_i= rq_work_fn); static int pvclock_gtod_notify(struct notifier_block *nb, unsigned long un= used, void *priv) { +#ifdef CONFIG_X86_64 struct timekeeper *tk =3D priv; =20 - update_pvclock_gtod(tk); - -#ifdef CONFIG_X86_64 kvm_host_vclock_mode =3D tk->tkr_mono.clock->vdso_clock_mode; =20 --=20 2.54.0 From nobody Fri Jul 10 17:09:11 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=1783113762; cv=none; d=zohomail.com; s=zohoarc; b=DQJ68FjYtxRDMpMsof2CLwz8py5LQzKaHzvW7NcN24+kw9piKImWGkFscaOFmq2y0IZjAFOcrwyvk+i5PyFGMXI0ZhgzQN38kDm4O9iCI3WFaQoy/Ks6y0eqNpndFFCtCVYoODFcDd3TSGObcUzzIIPNDH8BxeG+Yk4xlarAhhg= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1783113762; h=Content-Type: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=9YLu6jUxizeyw6FPvXNgLWAHtpjzd7Ja/IQI9k+fk+s=; b=RclrD3tZZdfyfiWXXpjj6BQMtLB3NJ+4c2gqCgCEylduzNtvxtnOOS1mwebiloU8xEma9nerksxL9Wyhv8FX/l+7mdkxdIoXl/2dPHvXmONBFZZDpC4zdNEcxh0G/6C49Lr6eeGBRV02bKtCj5MDFVriMG70bQHTJ3pueAoSY+A= 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 1783113762261380.85631766456004; Fri, 3 Jul 2026 14:22:42 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.1353758.1609507 (Exim 4.92) (envelope-from ) id 1wflKr-0006Wb-43; Fri, 03 Jul 2026 21:22:09 +0000 Received: by outflank-mailman (output) from mailman id 1353758.1609507; Fri, 03 Jul 2026 21:22:09 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflKq-0006Td-QL; Fri, 03 Jul 2026 21:22:08 +0000 Received: by outflank-mailman (input) for mailman id 1353758; Fri, 03 Jul 2026 21:22:06 +0000 Received: from mx.expurgate.net ([194.145.224.20]) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflKo-0005hr-LN for xen-devel@lists.xenproject.org; Fri, 03 Jul 2026 21:22:06 +0000 Received: from mx.expurgate.net (helo=localhost) by mx.expurgate.net with esmtp id 1wflKo-00BXCb-1w; Fri, 03 Jul 2026 23:22:06 +0200 Received: from [10.42.69.1] (helo=localhost) by localhost with ESMTP (eXpurgate MTA 0.9.1) (envelope-from ) id 6a48279b-2eae-0a2a0a5409dd-0a2a45019e62-24 for ; Fri, 03 Jul 2026 23:22:01 +0200 Received: from [90.155.50.34] (helo=casper.infradead.org) by tlsNG-d62444.mxtls.expurgate.net with ESMTPS (eXpurgate 4.57.1) (envelope-from ) id 6a4827f8-400f-0a2a45010019-5a9b3222a836-3 for ; Fri, 03 Jul 2026 23:22:01 +0200 Received: from [2001:8b0:10b:1::425] (helo=i7.infradead.org) by casper.infradead.org with esmtpsa (Exim 4.99.1 #2 (Red Hat Linux)) id 1wflKX-0000000AsYS-3lGH; Fri, 03 Jul 2026 21:21:50 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.99.2 #2 (Red Hat Linux)) id 1wflKX-00000001RQI-3LPT; Fri, 03 Jul 2026 22:21:49 +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=casper.20170209 header.d=infradead.org header.i="@infradead.org" header.h="Sender:Content-Transfer-Encoding:Content-Type: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=casper.20170209; h=Sender:Content-Transfer-Encoding: Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:To: From:Reply-To:Cc:Content-ID:Content-Description; bh=9YLu6jUxizeyw6FPvXNgLWAHtpjzd7Ja/IQI9k+fk+s=; b=fcUVvHAIPPdYkE7/dYS8PsNO0M 0l7rKpCfaWyv7qnO627IUm/45JZzCNXpKFxdSx3aOe4X/asoyK1w+W3ZNk66BM8q3BbjYRzGNQLNV FIOdbKNq2+NaKcooJ/SV2aSPahIzidPDXtyB92+iE1701oAJYZIobMAgIC8rg0p2P6qLAa9eY/PVl /pGKXDoXfX1z+5rZmDtJJ9Wv34vMFTG3iFXgK7vu2PgYTbtbFTcJhelUV/ioie3vUIgVLGidMeVnR PeaxJ2Y8zB3aSgCvh1ZPeMDKjka+OYRslMm979N9HKfPZmmsO4HL0U8OnTYlA/VVYGrcVlh/JcdzD AnicB8aQ==; 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 36/36] KVM: x86: Activate master clock from kvm_arch_init_vm() Date: Fri, 3 Jul 2026 22:18:15 +0100 Message-ID: <20260703212145.343527-37-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-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Sender: David Woodhouse X-SRS-Rewrite: SMTP reverse-path rewritten from by casper.infradead.org. See http://www.infradead.org/rpr.html X-purgate-ID: tlsNG-d62444/1783113721-D18C31E0-8D48DA2E/0/0 X-purgate-type: clean X-purgate-size: 4143 X-ZohoMail-DKIM: pass (identity @infradead.org) X-ZM-MESSAGEID: 1783113764544158501 From: David Woodhouse Initialize the TSC generation and master clock state at VM creation time, rather than relying on kvm_update_masterclock() from kvm_arch_vcpu_postcreate(). Set cur_tsc_generation=3D1, cur_tsc_khz, cur_tsc_scaling_ratio, cur_tsc_offset, cur_tsc_nsec and kvmclock_offset from an atomic ktime/TSC snapshot. This establishes a coherent epoch so that: - The first vCPU synchronizes to the existing generation (getting the pre-computed TSC offset) rather than computing its own. - pvclock_update_vm_gtod_copy() succeeds immediately (no zero tsc_hz from uninitialized cur_tsc_scaling_ratio). - KVM_GET_CLOCK returns valid {host_tsc, realtime} fields as soon as any vCPU exists. - KVM_[GS]ET_CLOCK_GUEST works without a prior KVM_RUN. - No O(N) iteration of all vCPUs on each vCPU creation. This replaces the kvm_update_masterclock() call that was added to kvm_arch_vcpu_postcreate() to work around the missing initialization. Signed-off-by: David Woodhouse Assisted-by: Kiro (claude-opus-4.6-1m) --- arch/x86/kvm/x86.c | 45 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 37 insertions(+), 8 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 58016af64932..d35f2ac3ef49 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -13161,8 +13161,6 @@ void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu) return; vcpu_load(vcpu); kvm_synchronize_tsc(vcpu, NULL); - if (!vcpu->kvm->arch.use_master_clock) - kvm_update_masterclock(vcpu->kvm, NULL); vcpu_put(vcpu); =20 /* poll control enabled by default */ @@ -13572,6 +13570,8 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long= type) { int ret; unsigned long flags; + u64 kvmclock_host_tsc; + s64 kvmclock_ns; =20 if (!kvm_is_vm_type_supported(type)) return -EINVAL; @@ -13603,18 +13603,47 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned lo= ng type) seqcount_raw_spinlock_init(&kvm->arch.pvclock_sc, &kvm->arch.tsc_write_lo= ck); ratelimit_state_init(&kvm->arch.kvmclock_update_rs, HZ, 10); ratelimit_set_flags(&kvm->arch.kvmclock_update_rs, RATELIMIT_MSG_ON_RELEA= SE); - kvm->arch.kvmclock_offset =3D -get_kvmclock_base_ns(); - kvm->arch.all_vcpus_matched_freq =3D true; - - raw_spin_lock_irqsave(&kvm->arch.tsc_write_lock, flags); - pvclock_update_vm_gtod_copy(kvm); - raw_spin_unlock_irqrestore(&kvm->arch.tsc_write_lock, flags); =20 kvm->arch.default_tsc_khz =3D max_tsc_khz ? : tsc_khz; kvm->arch.apic_bus_cycle_ns =3D APIC_BUS_CYCLE_NS_DEFAULT; kvm->arch.guest_can_read_msr_platform_info =3D true; kvm->arch.enable_pmu =3D enable_pmu; =20 + kvm->arch.all_vcpus_matched_freq =3D true; + kvm->arch.all_vcpus_matched_tsc =3D true; + kvm->arch.cur_tsc_scaling_ratio =3D kvm_caps.default_tsc_scaling_ratio; + kvm->arch.cur_tsc_khz =3D kvm->arch.default_tsc_khz; + + raw_spin_lock_irqsave(&kvm->arch.tsc_write_lock, flags); + + /* + * Establish the initial TSC generation for synchronization logic. + * The first vCPU will sync to this, starting its guest TSC at the + * number of cycles elapsed since VM creation rather than at zero. + * This ensures coherence with the kvmclock epoch (also set here) + * and means the master clock snapshot taken below is immediately + * valid =E2=80=94 no need to redo it at first vCPU creation. + */ +#ifdef CONFIG_X86_64 + if (!kvm_get_time_and_clockread(&kvmclock_ns, &kvmclock_host_tsc)) +#endif + { + /* + * If not simultaneous, we want the TSC to be zero slightly + * *after* the kvmclock is zero. + */ + kvmclock_ns =3D get_kvmclock_base_ns(); + kvmclock_host_tsc =3D rdtsc(); + } + kvm->arch.cur_tsc_write =3D 0; + kvm->arch.cur_tsc_offset =3D -(s64)kvmclock_host_tsc; + kvm->arch.cur_tsc_nsec =3D kvmclock_ns; + kvm->arch.cur_tsc_generation =3D 1; + kvm->arch.kvmclock_offset =3D -kvmclock_ns; + + pvclock_update_vm_gtod_copy(kvm); + raw_spin_unlock_irqrestore(&kvm->arch.tsc_write_lock, flags); + #if IS_ENABLED(CONFIG_HYPERV) spin_lock_init(&kvm->arch.hv_root_tdp_lock); kvm->arch.hv_root_tdp =3D INVALID_PAGE; --=20 2.54.0