From: Sean Christopherson <seanjc@google.com>
To: Jonathan Corbet <corbet@lwn.net>,
Paolo Bonzini <pbonzini@redhat.com>,
Thomas Gleixner <tglx@kernel.org>,
Ingo Molnar <mingo@redhat.com>, Borislav Petkov <bp@alien8.de>,
Dave Hansen <dave.hansen@linux.intel.com>,
x86@kernel.org, Kiryl Shutsemau <kas@kernel.org>,
Rick Edgecombe <rick.p.edgecombe@intel.com>,
Sean Christopherson <seanjc@google.com>,
"K. Y. Srinivasan" <kys@microsoft.com>,
Haiyang Zhang <haiyangz@microsoft.com>,
Wei Liu <wei.liu@kernel.org>, Dexuan Cui <decui@microsoft.com>,
Long Li <longli@microsoft.com>,
Ajay Kaher <ajay.kaher@broadcom.com>,
Alexey Makhalov <alexey.makhalov@broadcom.com>,
Jan Kiszka <jan.kiszka@siemens.com>,
Andy Lutomirski <luto@kernel.org>,
Peter Zijlstra <peterz@infradead.org>,
Juergen Gross <jgross@suse.com>,
Daniel Lezcano <daniel.lezcano@kernel.org>,
John Stultz <jstultz@google.com>
Cc: Shuah Khan <skhan@linuxfoundation.org>,
"H. Peter Anvin" <hpa@zytor.com>,
Vitaly Kuznetsov <vkuznets@redhat.com>,
Broadcom internal kernel review list
<bcm-kernel-feedback-list@broadcom.com>,
Boris Ostrovsky <boris.ostrovsky@oracle.com>,
Stephen Boyd <sboyd@kernel.org>,
linux-doc@vger.kernel.org, kvm@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-coco@lists.linux.dev,
linux-hyperv@vger.kernel.org, virtualization@lists.linux.dev,
xen-devel@lists.xenproject.org,
Tom Lendacky <thomas.lendacky@amd.com>,
Nikunj A Dadhania <nikunj@amd.com>,
David Woodhouse <dwmw@amazon.co.uk>,
David Woodhouse <dwmw2@infradead.org>,
Michael Kelley <mhklinux@outlook.com>,
Thomas Gleixner <tglx@linutronix.de>
Subject: [PATCH v5 10/51] x86/tdx: Force TSC frequency with CPUID-based info provided by the TDX-Module
Date: Wed, 1 Jul 2026 12:31:31 -0700 [thread overview]
Message-ID: <20260701193212.749551-11-seanjc@google.com> (raw)
In-Reply-To: <20260701193212.749551-1-seanjc@google.com>
When running as a TDX guest, explicitly set the TSC frequency to a known
value, using CPUID-based information, instead of potentially relying on a
hypervisor-controlled PV routine. For TDX guests, CPUID.0x15 is always
emulated by the TDX-Module, i.e. the information from CPUID is more
trustworthy than the information provided by the hypervisor.
To maintain backwards compatibility with TDX guest kernels that use native
calibration, and because it's the least awful option, retain
native_calibrate_tsc()'s stuffing of the local APIC bus period using the
core crystal frequency. While it's entirely possible for the hypervisor
to emulate the APIC timer at a different frequency than the core crystal
frequency, the commonly accepted interpretation of Intel's SDM is that APIC
timer runs at the core crystal frequency when that latter is enumerated via
CPUID:
The APIC timer frequency will be the processor’s bus clock or core
crystal clock frequency (when TSC/core crystal clock ratio is enumerated
in CPUID leaf 0x15).
If the hypervisor is malicious and deliberately runs the APIC timer at the
wrong frequency, nothing would stop the hypervisor from modifying the
frequency at any time, i.e. attempting to manually calibrate the frequency
out of paranoia would be futile.
Deliberately leave CPU frequency calibration as is, since the TDX-Module
doesn't provide any guarantees with respect to CPUID.0x16.
Expose and use cpuid_get_tsc_info() instead of providing a wrapper to
get the TSC and core crystal frequency, as TDX is the only anticipated
user outside of the TSC code, i.e. adding a helper to dedup the math won't
actually dedup anything. Having TDX use "struct cpuid_tsc_info" also
avoids the temptation of declaring a local "tsc_khz" variable and thus
unintentionally creating a shadow of the global "tsc_khz".
Cc: Kiryl Shutsemau (Meta) <kas@kernel.org>
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
.../admin-guide/kernel-parameters.txt | 4 ++--
arch/x86/coco/tdx/tdx.c | 20 ++++++++++++++++---
arch/x86/include/asm/tdx.h | 2 ++
arch/x86/include/asm/tsc.h | 7 +++++++
arch/x86/kernel/tsc.c | 11 ++++------
5 files changed, 32 insertions(+), 12 deletions(-)
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 181149f633c3..490e6aa72fc2 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -7947,8 +7947,8 @@ Kernel parameters
Format: <unsigned int>
Note, tsc_early_khz is ignored if the TSC frequency is
- provided by trusted firmware when running as an SNP
- guest.
+ provided by trusted firmware when running as an SNP or
+ TDX guest.
tsx= [X86] Control Transactional Synchronization
Extensions (TSX) feature in Intel processors that
diff --git a/arch/x86/coco/tdx/tdx.c b/arch/x86/coco/tdx/tdx.c
index 29b6f1ed59ec..ae2d35f2ef33 100644
--- a/arch/x86/coco/tdx/tdx.c
+++ b/arch/x86/coco/tdx/tdx.c
@@ -8,6 +8,7 @@
#include <linux/export.h>
#include <linux/io.h>
#include <linux/kexec.h>
+#include <asm/apic.h>
#include <asm/coco.h>
#include <asm/tdx.h>
#include <asm/vmx.h>
@@ -1123,9 +1124,6 @@ void __init tdx_early_init(void)
setup_force_cpu_cap(X86_FEATURE_TDX_GUEST);
- /* TSC is the only reliable clock in TDX guest */
- setup_force_cpu_cap(X86_FEATURE_TSC_RELIABLE);
-
cc_vendor = CC_VENDOR_INTEL;
/* Configure the TD */
@@ -1195,3 +1193,19 @@ void __init tdx_early_init(void)
tdx_announce();
}
+
+unsigned int __init tdx_tsc_init(void)
+{
+ struct cpuid_tsc_info info;
+
+ if (WARN_ON_ONCE(cpuid_get_tsc_info(&info) || !info.crystal_khz))
+ return 0;
+
+ apic_set_timer_period_khz(info.crystal_khz, "TDX-Module via CPUID");
+
+ /* TSC is the only reliable clock in TDX guest */
+ setup_force_cpu_cap(X86_FEATURE_TSC_RELIABLE);
+ setup_force_cpu_cap(X86_FEATURE_TSC_KNOWN_FREQ);
+
+ return info.crystal_khz * info.numerator / info.denominator;
+}
diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h
index 89e97d5761d8..d23ff06db41a 100644
--- a/arch/x86/include/asm/tdx.h
+++ b/arch/x86/include/asm/tdx.h
@@ -68,6 +68,7 @@ struct ve_info {
#ifdef CONFIG_INTEL_TDX_GUEST
void __init tdx_early_init(void);
+unsigned int __init tdx_tsc_init(void);
void tdx_get_ve_info(struct ve_info *ve);
@@ -89,6 +90,7 @@ void __init tdx_dump_td_ctls(u64 td_ctls);
#else
static inline void tdx_early_init(void) { };
+static inline unsigned int tdx_tsc_init(void) { return 0; }
static inline void tdx_halt(void) { };
static inline bool tdx_early_handle_ve(struct pt_regs *regs) { return false; }
diff --git a/arch/x86/include/asm/tsc.h b/arch/x86/include/asm/tsc.h
index 4d2d2f21ff06..b6b86e24e1bf 100644
--- a/arch/x86/include/asm/tsc.h
+++ b/arch/x86/include/asm/tsc.h
@@ -82,6 +82,13 @@ static inline cycles_t get_cycles(void)
}
#define get_cycles get_cycles
+struct cpuid_tsc_info {
+ unsigned int denominator;
+ unsigned int numerator;
+ unsigned int crystal_khz;
+};
+extern int cpuid_get_tsc_info(struct cpuid_tsc_info *info);
+
extern void tsc_early_init(void);
extern void tsc_init(void);
extern void mark_tsc_unstable(char *reason);
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
index 12043812c8f5..86384a83a5f6 100644
--- a/arch/x86/kernel/tsc.c
+++ b/arch/x86/kernel/tsc.c
@@ -34,6 +34,7 @@
#include <asm/topology.h>
#include <asm/uv/uv.h>
#include <asm/sev.h>
+#include <asm/tdx.h>
unsigned int __read_mostly cpu_khz; /* TSC clocks / usec, not used here */
EXPORT_SYMBOL(cpu_khz);
@@ -645,13 +646,7 @@ static unsigned long quick_pit_calibrate(void)
return delta;
}
-struct cpuid_tsc_info {
- unsigned int denominator;
- unsigned int numerator;
- unsigned int crystal_khz;
-};
-
-static int cpuid_get_tsc_info(struct cpuid_tsc_info *info)
+int cpuid_get_tsc_info(struct cpuid_tsc_info *info)
{
unsigned int ecx_hz, edx;
@@ -1529,6 +1524,8 @@ void __init tsc_early_init(void)
if (cc_platform_has(CC_ATTR_GUEST_SNP_SECURE_TSC))
known_tsc_khz = snp_secure_tsc_init();
+ else if (boot_cpu_has(X86_FEATURE_TDX_GUEST))
+ known_tsc_khz = tdx_tsc_init();
/*
* Ignore the user-provided TSC frequency if the exact frequency was
--
2.55.0.rc0.799.gd6f94ed593-goog
next prev parent reply other threads:[~2026-07-01 19:32 UTC|newest]
Thread overview: 67+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-01 19:31 [PATCH v5 00/51] x86: Try to wrangle PV clocks vs. TSC Sean Christopherson
2026-07-01 19:31 ` [PATCH v5 01/51] x86/apic: Provide helpers to set local APIC timer period in hz and khz Sean Christopherson
2026-07-01 19:46 ` sashiko-bot
2026-07-01 20:05 ` Sean Christopherson
2026-07-01 19:31 ` [PATCH v5 02/51] x86/apic: Add CONFIG_X86_LOCAL_APIC=n stubs for apic_set_timer_period_{,k}hz() Sean Christopherson
2026-07-01 19:48 ` sashiko-bot
2026-07-01 19:31 ` [PATCH v5 03/51] x86/tsc: Ensure that TSC recalibration doesn't run if TSC frequency is known Sean Christopherson
2026-07-01 19:31 ` [PATCH v5 04/51] x86/tsc: Restrict recalibrate_cpu_khz() export to p4-clockmod and powernow-k7 Sean Christopherson
2026-07-01 19:31 ` [PATCH v5 05/51] x86/sev: Mark TSC as reliable when configuring Secure TSC Sean Christopherson
2026-07-01 19:56 ` sashiko-bot
2026-07-01 20:07 ` Sean Christopherson
2026-07-01 19:31 ` [PATCH v5 06/51] x86/sev: Don't override CPU frequency calibration for SNP's " Sean Christopherson
2026-07-01 19:53 ` sashiko-bot
2026-07-01 20:09 ` Sean Christopherson
2026-07-01 19:31 ` [PATCH v5 07/51] x86/sev: Move check for SNP Secure TSC support to tsc_early_init() Sean Christopherson
2026-07-01 19:31 ` [PATCH v5 08/51] x86/sev: Shove SNP's secure/trusted TSC frequency directly into "calibration" Sean Christopherson
2026-07-01 19:31 ` [PATCH v5 09/51] x86/tsc: Add a standalone helper for getting TSC info from CPUID.0x15 Sean Christopherson
2026-07-01 19:31 ` Sean Christopherson [this message]
2026-07-01 19:31 ` [PATCH v5 11/51] x86/tsc: Add dedicated hypervisor hooks for getting known TSC/CPU frequencies Sean Christopherson
2026-07-01 19:31 ` [PATCH v5 12/51] x86/acrn: Register TSC/CPU frequency callbacks iff frequency is actually in CPUID Sean Christopherson
2026-07-01 19:52 ` sashiko-bot
2026-07-01 20:10 ` Sean Christopherson
2026-07-01 19:31 ` [PATCH v5 13/51] x86/acrn: Mark TSC frequency as known when using ACRN for calibration Sean Christopherson
2026-07-01 19:31 ` [PATCH v5 14/51] x86/tsc: Consolidate forcing of X86_FEATURE_TSC_KNOWN_FREQ for PV code Sean Christopherson
2026-07-01 19:31 ` [PATCH v5 15/51] x86/tsc: Kill off x86_platform_ops.calibrate_{cpu,tsc}() hooks Sean Christopherson
2026-07-01 19:31 ` [PATCH v5 16/51] x86/tsc: Rename pit_hpet_ptimer_calibrate_cpu() => native_calibrate_cpu_late() Sean Christopherson
2026-07-01 19:31 ` [PATCH v5 17/51] x86/tsc: Fold native_calibrate_cpu() into recalibrate_cpu_khz() Sean Christopherson
2026-07-01 19:50 ` sashiko-bot
2026-07-01 19:31 ` [PATCH v5 18/51] x86/kvmclock: Rename kvm_get_tsc_khz() to kvmclock_get_tsc_khz() Sean Christopherson
2026-07-01 19:31 ` [PATCH v5 19/51] x86/kvmclock: Drop dead check on TSC being unstable during kvmclock_init() Sean Christopherson
2026-07-01 19:31 ` [PATCH v5 20/51] KVM: x86: Officially define CPUID 0x40000010 as PV Timing Info (TSC and Bus) Sean Christopherson
2026-07-01 19:31 ` [PATCH v5 21/51] x86/kvm: Obtain TSC frequency from PV CPUID if present Sean Christopherson
2026-07-01 19:31 ` [PATCH v5 22/51] x86/kvm: Mark TSC as reliable when it's constant and nonstop Sean Christopherson
2026-07-01 20:03 ` sashiko-bot
2026-07-01 20:13 ` Sean Christopherson
2026-07-01 19:31 ` [PATCH v5 23/51] x86/tsc: Add standalone helper for getting CPU frequency from CPUID Sean Christopherson
2026-07-01 19:31 ` [PATCH v5 24/51] x86/kvm: Get CPU base frequency from CPUID when it's available Sean Christopherson
2026-07-01 19:54 ` sashiko-bot
2026-07-01 19:31 ` [PATCH v5 25/51] clocksource: hyper-v: Register sched_clock save/restore iff it's necessary Sean Christopherson
2026-07-01 19:31 ` [PATCH v5 26/51] clocksource: hyper-v: Drop wrappers to sched_clock save/restore helpers Sean Christopherson
2026-07-01 19:31 ` [PATCH v5 27/51] clocksource: hyper-v: Don't save/restore TSC offset when using HV sched_clock Sean Christopherson
2026-07-01 19:31 ` [PATCH v5 28/51] x86/kvmclock: Setup kvmclock for secondary CPUs iff CONFIG_SMP=y Sean Christopherson
2026-07-01 19:31 ` [PATCH v5 29/51] x86/kvm: Don't disable kvmclock on BSP in syscore_suspend() Sean Christopherson
2026-07-01 20:03 ` sashiko-bot
2026-07-01 20:43 ` Sean Christopherson
2026-07-01 19:31 ` [PATCH v5 30/51] x86/paravirt: Remove unnecessary PARAVIRT=n stub for paravirt_set_sched_clock() Sean Christopherson
2026-07-01 19:31 ` [PATCH v5 31/51] x86/paravirt: Move handling of unstable PV clocks into paravirt_set_sched_clock() Sean Christopherson
2026-07-01 19:31 ` [PATCH v5 32/51] x86/kvmclock: Move sched_clock save/restore helpers up in kvmclock.c Sean Christopherson
2026-07-01 19:31 ` [PATCH v5 33/51] x86/xen/time: NOP-ify x86_platform's sched_clock save/restore hooks Sean Christopherson
2026-07-01 19:31 ` [PATCH v5 34/51] x86/vmware: NOP-ify save/restore hooks when using VMware's sched_clock Sean Christopherson
2026-07-01 19:31 ` [PATCH v5 35/51] x86/tsc: WARN if TSC sched_clock save/restore used with PV sched_clock Sean Christopherson
2026-07-01 19:31 ` [PATCH v5 36/51] x86/paravirt: Pass sched_clock save/restore helpers during registration Sean Christopherson
2026-07-01 19:31 ` [PATCH v5 37/51] x86/kvmclock: Move kvm_sched_clock_init() down in kvmclock.c Sean Christopherson
2026-07-01 19:31 ` [PATCH v5 38/51] x86/xen/time: Mark xen_setup_vsyscall_time_info() as __init Sean Christopherson
2026-07-01 19:32 ` [PATCH v5 39/51] x86/pvclock: Mark setup helpers and related various as __init/__ro_after_init Sean Christopherson
2026-07-01 19:32 ` [PATCH v5 40/51] x86/pvclock: WARN if pvclock's valid_flags are overwritten Sean Christopherson
2026-07-01 19:32 ` [PATCH v5 41/51] x86/kvmclock: Refactor handling of PVCLOCK_TSC_STABLE_BIT during kvmclock_init() Sean Christopherson
2026-07-01 19:32 ` [PATCH v5 42/51] timekeeping: Resume clocksources before reading persistent clock Sean Christopherson
2026-07-01 19:32 ` [PATCH v5 43/51] x86/kvmclock: Hook clocksource.suspend/resume when kvmclock isn't sched_clock Sean Christopherson
2026-07-01 19:32 ` [PATCH v5 44/51] x86/kvmclock: WARN if wall clock is read while kvmclock is suspended Sean Christopherson
2026-07-01 19:32 ` [PATCH v5 45/51] x86/paravirt: Mark __paravirt_set_sched_clock() as __init Sean Christopherson
2026-07-01 19:32 ` [PATCH v5 46/51] x86/paravirt: Plumb a return code into __paravirt_set_sched_clock() Sean Christopherson
2026-07-01 19:32 ` [PATCH v5 47/51] x86/paravirt: Don't use a PV sched_clock in CoCo guests with trusted TSC Sean Christopherson
2026-07-01 19:32 ` [PATCH v5 48/51] x86/kvmclock: Use TSC for sched_clock if it's constant and non-stop Sean Christopherson
2026-07-01 19:32 ` [PATCH v5 49/51] x86/kvmclock: Plumb in AP-online and BSP-resume to kvmlock, for documentation Sean Christopherson
2026-07-01 19:32 ` [PATCH v5 50/51] x86/paravirt: Move using_native_sched_clock() stub into timer.h Sean Christopherson
2026-07-01 19:32 ` [PATCH v5 51/51] x86/kvm: Get local APIC bus frequency from PV CPUID Timing Info Sean Christopherson
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260701193212.749551-11-seanjc@google.com \
--to=seanjc@google.com \
--cc=ajay.kaher@broadcom.com \
--cc=alexey.makhalov@broadcom.com \
--cc=bcm-kernel-feedback-list@broadcom.com \
--cc=boris.ostrovsky@oracle.com \
--cc=bp@alien8.de \
--cc=corbet@lwn.net \
--cc=daniel.lezcano@kernel.org \
--cc=dave.hansen@linux.intel.com \
--cc=decui@microsoft.com \
--cc=dwmw2@infradead.org \
--cc=dwmw@amazon.co.uk \
--cc=haiyangz@microsoft.com \
--cc=hpa@zytor.com \
--cc=jan.kiszka@siemens.com \
--cc=jgross@suse.com \
--cc=jstultz@google.com \
--cc=kas@kernel.org \
--cc=kvm@vger.kernel.org \
--cc=kys@microsoft.com \
--cc=linux-coco@lists.linux.dev \
--cc=linux-doc@vger.kernel.org \
--cc=linux-hyperv@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=longli@microsoft.com \
--cc=luto@kernel.org \
--cc=mhklinux@outlook.com \
--cc=mingo@redhat.com \
--cc=nikunj@amd.com \
--cc=pbonzini@redhat.com \
--cc=peterz@infradead.org \
--cc=rick.p.edgecombe@intel.com \
--cc=sboyd@kernel.org \
--cc=skhan@linuxfoundation.org \
--cc=tglx@kernel.org \
--cc=tglx@linutronix.de \
--cc=thomas.lendacky@amd.com \
--cc=virtualization@lists.linux.dev \
--cc=vkuznets@redhat.com \
--cc=wei.liu@kernel.org \
--cc=x86@kernel.org \
--cc=xen-devel@lists.xenproject.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox