Message ID | 20231006011255.4163884-1-vannapurve@google.com |
---|---|
State | New |
Headers |
Return-Path: <linux-kernel-owner@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:a888:0:b0:403:3b70:6f57 with SMTP id x8csp19938vqo; Thu, 5 Oct 2023 18:13:21 -0700 (PDT) X-Google-Smtp-Source: AGHT+IFLP7HmL/SxTa1IoPBdnr7G4wUvUyh6Gti9q903odt+4KQ/ejRpyawvTEyMUI4YEwOT7Ca/ X-Received: by 2002:a17:903:234f:b0:1c3:a4f2:7c84 with SMTP id c15-20020a170903234f00b001c3a4f27c84mr7436174plh.60.1696554801680; Thu, 05 Oct 2023 18:13:21 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1696554801; cv=none; d=google.com; s=arc-20160816; b=SCz8lx2Y60dGrw0pDwZV3niMM51lOcFfo0kM5oFRMNp0X3iU/mdXQ7Sfq6vU728tPY UOYaQGjDCEGTmmTKsUUiU2OqgMmADWcVeibCLrTsOaTHIviI0IX3JrJd/Zw0Afr8TiGC J9e9W/MEK5hs7M/ILX5V7BbGdqG4s2jzzA06pwVXnpfBr46G+2M3w9xcDrBMFZ2w0/Sq 0Pm8IzPT1Z4TIHzX12e3dOlQF8Q+j6nS4Vnt1Fcvg/oRHq/hHh0nLZfFLlaVWYIi5zg3 Rt9HsEZR6q76moHXEoLGlZpFX+99rPezdh6EwXeh+MbZdCTunexNNKCOhnXFnD9dIOkx Qlfg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:message-id:mime-version:date :dkim-signature; bh=ZAek5umiw6GVVoIEUs57JBTUu1Ih3TpUkA3pAEzjKWY=; fh=9y7hVwrbhrgRRAd6HRGT17GK85vN9t96Z0AH9bu/Vgs=; b=WvxGVKmDxVw+0Lfpj75O7QlyViQkH4SqC2P+2kv1y5URDwQunTmhWfkhOBOArsJC21 XRQT3KmeEtWJDz+nBE3kH8mc9DytylqJa0ZeVb36Q5JPavYTsHHEbg2i1XmYmdrsE4mp YMzp3GLAvtlnSyxqVuxdZGSp6u8tp7vyI3OXm+0v4J6j+kzNK1jLtdwqHyi0e3kGJiQu 2+GJTrkqp8Yj6u3LhuGi+2Pejz6XqmSA7KWYo6QFtmGPzjL/a3BDthcje93IXb7KHrtq OHz/W0CfACp1zoZ3fKCxbh4mr5r/BBgUkHHZ5vWMYuwB4Fq5GnVJ9SRY/VL/8VtnSjd2 hFrA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20230601 header.b=2h2QK6gq; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.33 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from lipwig.vger.email (lipwig.vger.email. [23.128.96.33]) by mx.google.com with ESMTPS id u5-20020a17090341c500b001b9e2ce5723si2854718ple.495.2023.10.05.18.13.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 05 Oct 2023 18:13:21 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.33 as permitted sender) client-ip=23.128.96.33; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20230601 header.b=2h2QK6gq; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.33 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from out1.vger.email (depot.vger.email [IPv6:2620:137:e000::3:0]) by lipwig.vger.email (Postfix) with ESMTP id 81BF180CBF16; Thu, 5 Oct 2023 18:13:19 -0700 (PDT) X-Virus-Status: Clean X-Virus-Scanned: clamav-milter 0.103.10 at lipwig.vger.email Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229698AbjJFBNJ (ORCPT <rfc822;ezelljr.billy@gmail.com> + 18 others); Thu, 5 Oct 2023 21:13:09 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38646 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229683AbjJFBNH (ORCPT <rfc822;linux-kernel@vger.kernel.org>); Thu, 5 Oct 2023 21:13:07 -0400 Received: from mail-pj1-x1049.google.com (mail-pj1-x1049.google.com [IPv6:2607:f8b0:4864:20::1049]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 16AEAE4 for <linux-kernel@vger.kernel.org>; Thu, 5 Oct 2023 18:13:05 -0700 (PDT) Received: by mail-pj1-x1049.google.com with SMTP id 98e67ed59e1d1-27731a63481so1493647a91.2 for <linux-kernel@vger.kernel.org>; Thu, 05 Oct 2023 18:13:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1696554784; x=1697159584; darn=vger.kernel.org; h=cc:to:from:subject:message-id:mime-version:date:from:to:cc:subject :date:message-id:reply-to; bh=ZAek5umiw6GVVoIEUs57JBTUu1Ih3TpUkA3pAEzjKWY=; b=2h2QK6gqw4FLR3yx2bhHeZAYMiLEvjmruIIqwVZlSdfvvo9I7btoOjevefJHNsf+ry 8TL8XY+XQJu+p5ECY1LHz/3h6b4vuAbskcGklpEEFziskkAMJ9xXW9CoK/MDRHvxIIA5 /MyIM6zxNNpqCHDOAkOeSC/k/d2f46FxHGGVPKJFd1/Cb2k/tusV7oZiuGXt6copNNx4 bfrFfstVBM3W1I1n5vuTxaXltfENJKJiMWN1UGGj/ReJGCwzm4aX+dAF+O+Z9/hPW0MX s3y/gIDnQ74AmoQi18VuV87hN4nuob1qajHJzUhx/ryALztQzQxjaWUhqOwByAKwZ+7z Io/A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1696554784; x=1697159584; h=cc:to:from:subject:message-id:mime-version:date:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=ZAek5umiw6GVVoIEUs57JBTUu1Ih3TpUkA3pAEzjKWY=; b=btEGp7az3OqxiAVK0VY/dL+UiITWuVFPt6ykxlxCXRCrmI47mP8JFSMGlDk1sdnvtY 8PpNseleBES935Vs9UWS2vnje8e5pdQIpCJZntzT9FibfOpZwZRGq7XiaIaEJ1Qz6SCZ M4jqb5YQTBKEviaVoo8rQLTsIej+bwXHzZac07YVfCmXgpnuVi7QovfHe33JvXz/Nugg 8VvWlOOKHZQeQPMZeoxx522ZeN4GXwP8W5z41qm25cxQ5s1X3X+1ZXWEgLU0A/rGCpah KyqGFhlrvvuqWUdqwxmwpx8F71gWQ6oR91moDbu8eMBvmEcOohGheK9EHCDnV2SvYU+J N+bQ== X-Gm-Message-State: AOJu0YyumxlwUxAY6s4xk0BjtN6NVQgGp8KE8q5c6/c+YMDZx6J+9wue KEHznDqu2ogANbvH/XvrhlNoNv8onJmbgHPV X-Received: from vannapurve2.c.googlers.com ([fda3:e722:ac3:cc00:20:ed76:c0a8:43a4]) (user=vannapurve job=sendgmr) by 2002:a17:90a:ad4c:b0:276:d039:aec4 with SMTP id w12-20020a17090aad4c00b00276d039aec4mr110386pjv.6.1696554784428; Thu, 05 Oct 2023 18:13:04 -0700 (PDT) Date: Fri, 6 Oct 2023 01:12:55 +0000 Mime-Version: 1.0 X-Mailer: git-send-email 2.42.0.609.gbb76f46606-goog Message-ID: <20231006011255.4163884-1-vannapurve@google.com> Subject: [PATCH] x86/tdx: Override the tsc calibration for TDX VMs From: Vishal Annapurve <vannapurve@google.com> To: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com>, Thomas Gleixner <tglx@linutronix.de>, Ingo Molnar <mingo@redhat.com>, Borislav Petkov <bp@alien8.de>, Dave Hansen <dave.hansen@linux.intel.com>, Peter Zijlstra <peterz@infradead.org>, Jun Nakajima <jun.nakajima@intel.com>, Isaku Yamahata <isaku.yamahata@intel.com>, Erdem Aktas <erdemaktas@google.com>, Sagi Shahar <sagis@google.com> Cc: Sean Christopherson <seanjc@google.com>, Nikolay Borisov <nik.borisov@suse.com>, "Jason A. Donenfeld" <Jason@zx2c4.com>, Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>, "H. Peter Anvin" <hpa@zytor.com>, x86@kernel.org, linux-kernel@vger.kernel.org, Vishal Annapurve <vannapurve@google.com> Content-Type: text/plain; charset="UTF-8" X-Spam-Status: No, score=-8.4 required=5.0 tests=DKIMWL_WL_MED,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_IN_DEF_DKIM_WL autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lipwig.vger.email Precedence: bulk List-ID: <linux-kernel.vger.kernel.org> X-Mailing-List: linux-kernel@vger.kernel.org X-Greylist: Sender passed SPF test, not delayed by milter-greylist-4.6.4 (lipwig.vger.email [0.0.0.0]); Thu, 05 Oct 2023 18:13:19 -0700 (PDT) X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1778966647235658405 X-GMAIL-MSGID: 1778966647235658405 |
Series |
x86/tdx: Override the tsc calibration for TDX VMs
|
|
Commit Message
Vishal Annapurve
Oct. 6, 2023, 1:12 a.m. UTC
TSC calibration for native execution gets the TSC frequency from CPUID,
but also ends up setting lapic_timer_period. When using oneshot mode
with lapic timer, predefined value of lapic_timer_period causes lapic
timer calibration to be skipped with wrong multipliers set for lapic
timer.
To avoid this issue, override the TSC calibration step for TDX VMs to
just calculate the TSC frequency using cpuid values.
Signed-off-by: Vishal Annapurve <vannapurve@google.com>
---
arch/x86/coco/tdx/tdx.c | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
Comments
> > +/** > + * Determine TSC frequency via CPUID, else return 0. > + */ Nit: looks you don't need the k-doc style comment here? > +static unsigned long tdx_calibrate_tsc(void) > +{ > + unsigned int eax_denominator = 0, ebx_numerator = 0, ecx_hz = 0, edx = 0; > + unsigned int crystal_khz; > + > + /* CPUID 15H TSC/Crystal ratio, plus optionally Crystal Hz */ > + cpuid(0x15, &eax_denominator, &ebx_numerator, &ecx_hz, &edx); > + > + if (ebx_numerator == 0 || eax_denominator == 0) > + return 0; > + > + crystal_khz = ecx_hz / 1000; > + > + /* > + * TSC frequency reported directly by CPUID is a "hardware reported" > + * frequency and is the most accurate one so far we have. This > + * is considered a known frequency. > + */ > + if (crystal_khz != 0) > + setup_force_cpu_cap(X86_FEATURE_TSC_KNOWN_FREQ); > + > + return crystal_khz * ebx_numerator / eax_denominator; > +} > +
On 10/5/23 18:12, Vishal Annapurve wrote: > +/** > + * Determine TSC frequency via CPUID, else return 0. > + */ > +static unsigned long tdx_calibrate_tsc(void) > +{ > + unsigned int eax_denominator = 0, ebx_numerator = 0, ecx_hz = 0, edx = 0; > + unsigned int crystal_khz; > + > + /* CPUID 15H TSC/Crystal ratio, plus optionally Crystal Hz */ > + cpuid(0x15, &eax_denominator, &ebx_numerator, &ecx_hz, &edx); > + > + if (ebx_numerator == 0 || eax_denominator == 0) > + return 0; > + > + crystal_khz = ecx_hz / 1000; > + > + /* > + * TSC frequency reported directly by CPUID is a "hardware reported" > + * frequency and is the most accurate one so far we have. This > + * is considered a known frequency. > + */ > + if (crystal_khz != 0) > + setup_force_cpu_cap(X86_FEATURE_TSC_KNOWN_FREQ); > + > + return crystal_khz * ebx_numerator / eax_denominator; > +} > + Would it be possible to do this by refactoring the existing code and calling it directly instead of copying and pasting so much?
On Fri, Oct 6, 2023 at 7:03 AM Dave Hansen <dave.hansen@intel.com> wrote: > > On 10/5/23 18:12, Vishal Annapurve wrote: > > +/** > > + * Determine TSC frequency via CPUID, else return 0. > > + */ > > +static unsigned long tdx_calibrate_tsc(void) > > +{ > > + unsigned int eax_denominator = 0, ebx_numerator = 0, ecx_hz = 0, edx = 0; > > + unsigned int crystal_khz; > > + > > + /* CPUID 15H TSC/Crystal ratio, plus optionally Crystal Hz */ > > + cpuid(0x15, &eax_denominator, &ebx_numerator, &ecx_hz, &edx); > > + > > + if (ebx_numerator == 0 || eax_denominator == 0) > > + return 0; > > + > > + crystal_khz = ecx_hz / 1000; > > + > > + /* > > + * TSC frequency reported directly by CPUID is a "hardware reported" > > + * frequency and is the most accurate one so far we have. This > > + * is considered a known frequency. > > + */ > > + if (crystal_khz != 0) > > + setup_force_cpu_cap(X86_FEATURE_TSC_KNOWN_FREQ); > > + > > + return crystal_khz * ebx_numerator / eax_denominator; > > +} > > + > > Would it be possible to do this by refactoring the existing code and > calling it directly instead of copying and pasting so much? One option is to call native_calibrate_tsc from tdx_calibrate_tsc and undo the lapic_timer_period configuration after the call. Does that sound reasonable?
On Fri, Oct 6, 2023 at 3:43 AM Huang, Kai <kai.huang@intel.com> wrote: > > > > > > +/** > > + * Determine TSC frequency via CPUID, else return 0. > > + */ > > Nit: looks you don't need the k-doc style comment here? > Ack, will remove/update this comment in the next version.
On 10/6/23 08:27, Vishal Annapurve wrote: >> Would it be possible to do this by refactoring the existing code and >> calling it directly instead of copying and pasting so much? > One option is to call native_calibrate_tsc from tdx_calibrate_tsc and > undo the lapic_timer_period configuration after the call. Does that > sound reasonable? That sounds like a hack. Why not just refactor the code properly?
On Fri, Oct 06, 2023, Vishal Annapurve wrote: > TSC calibration for native execution gets the TSC frequency from CPUID, > but also ends up setting lapic_timer_period. When using oneshot mode > with lapic timer, predefined value of lapic_timer_period causes lapic > timer calibration to be skipped with wrong multipliers set for lapic > timer. > > To avoid this issue, override the TSC calibration step for TDX VMs to > just calculate the TSC frequency using cpuid values. This is a hack to workaround a KVM TDX bug. Per Intel's SDM: 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) divided by the value specified in the divide configuration register. TDX hardcodes the core crystal frequency to 25Mhz, whereas KVM hardcodes the APIC bus frequency to 1Ghz. Upstream KVM's *current* behavior is fine, because KVM doesn't advertise support for CPUID 0x15, i.e. doesn't announce to host userspace that it's safe to expose CPUID 0x15 to the guest. Because TDX makes exposing CPUID 0x15 mandatory, KVM needs to be taught to correctly emulate the guest's APIC bus frequency, a.k.a. the TDX guest core crystal frequency of 25Mhz. I.e. tmict_to_ns() needs to replace APIC_BUS_CYCLE_NS with some math that makes the guest's APIC timer actually run at 25Mhz given whatever the host APIC bus runs at. static inline u64 tmict_to_ns(struct kvm_lapic *apic, u32 tmict) { return (u64)tmict * APIC_BUS_CYCLE_NS * (u64)apic->divide_count; } The existing guest code "works" because the calibration code effectively discovers the host APIC bus frequency. If we really want to force calibration, then the best way to do that would be to add a command line option to do exactly that, not hack around a KVM TDX bug. diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index 15f97c0abc9d..ce1cec6b3c18 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c @@ -723,7 +723,8 @@ unsigned long native_calibrate_tsc(void) * lapic_timer_period here to avoid having to calibrate the APIC * timer later. */ - lapic_timer_period = crystal_khz * 1000 / HZ; + if (!force_lapic_timer_calibration) + lapic_timer_period = crystal_khz * 1000 / HZ; #endif return crystal_khz * ebx_numerator / eax_denominator; But I would be very leery of forcing calibration, as effectively calibrating to the *host* core crystal frequency will cause the guest APIC timer to be wrong if the VM is migrated to a host with a different core crystal frequency. Relying on CPUID 0x15, if it's available, avoids that problem because it puts the onus on the hypervisor to account for the new host's frequency when emulating the APIC timer. That mess exists today, but deliberate ignoring the mechanism that allows the host to fix the mess would be asinine IMO. Even better would be for GCE to just enumerate support for TSC deadline already, because KVM already does the right thing to convert guest TSC frequency to host TSC frequency. KVM TDX would still need to add full support for CPUID 0x15, but at least any problems with using one-shot mode will unlikely to impact real guests.
On Fri, Oct 13, 2023, Sean Christopherson wrote: > On Fri, Oct 06, 2023, Vishal Annapurve wrote: > > TSC calibration for native execution gets the TSC frequency from CPUID, > > but also ends up setting lapic_timer_period. When using oneshot mode > > with lapic timer, predefined value of lapic_timer_period causes lapic > > timer calibration to be skipped with wrong multipliers set for lapic > > timer. > > > > To avoid this issue, override the TSC calibration step for TDX VMs to > > just calculate the TSC frequency using cpuid values. > > This is a hack to workaround a KVM TDX bug. Per Intel's SDM: > > 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) divided by the value specified in the divide configuration register. > > TDX hardcodes the core crystal frequency to 25Mhz, whereas KVM hardcodes the APIC > bus frequency to 1Ghz. Upstream KVM's *current* behavior is fine, because KVM > doesn't advertise support for CPUID 0x15, i.e. doesn't announce to host userspace > that it's safe to expose CPUID 0x15 to the guest. Because TDX makes exposing > CPUID 0x15 mandatory, KVM needs to be taught to correctly emulate the guest's > APIC bus frequency, a.k.a. the TDX guest core crystal frequency of 25Mhz. > > I.e. tmict_to_ns() needs to replace APIC_BUS_CYCLE_NS with some math that makes > the guest's APIC timer actually run at 25Mhz given whatever the host APIC bus > runs at. > > static inline u64 tmict_to_ns(struct kvm_lapic *apic, u32 tmict) > { > return (u64)tmict * APIC_BUS_CYCLE_NS * (u64)apic->divide_count; > } > > The existing guest code "works" because the calibration code effectively discovers > the host APIC bus frequency. If we really want to force calibration, then the > best way to do that would be to add a command line option to do exactly that, not > hack around a KVM TDX bug. > > diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c > index 15f97c0abc9d..ce1cec6b3c18 100644 > --- a/arch/x86/kernel/tsc.c > +++ b/arch/x86/kernel/tsc.c > @@ -723,7 +723,8 @@ unsigned long native_calibrate_tsc(void) > * lapic_timer_period here to avoid having to calibrate the APIC > * timer later. > */ > - lapic_timer_period = crystal_khz * 1000 / HZ; > + if (!force_lapic_timer_calibration) > + lapic_timer_period = crystal_khz * 1000 / HZ; > #endif > > return crystal_khz * ebx_numerator / eax_denominator; > > But I would be very leery of forcing calibration, as effectively calibrating to > the *host* core crystal frequency will cause the guest APIC timer to be wrong if > the VM is migrated to a host with a different core crystal frequency. Relying > on CPUID 0x15, if it's available, avoids that problem because it puts the onus on > the hypervisor to account for the new host's frequency when emulating the APIC > timer. That mess exists today, but deliberate ignoring the mechanism that allows > the host to fix the mess would be asinine IMO. Gah, I had a brainfart. tmict_to_ns() obviously converts TMICT to nanoseconds, and then converts nanoseconds into whatever frequency the underlying host timer runs at. So it's really only TDX that is problematic, as TDX demands the APIC bus be emulated at a frequency other than 1Ghz.
On Sat, Oct 14, 2023 at 4:32 AM Sean Christopherson <seanjc@google.com> wrote: > > On Fri, Oct 13, 2023, Sean Christopherson wrote: > > On Fri, Oct 06, 2023, Vishal Annapurve wrote: > > > TSC calibration for native execution gets the TSC frequency from CPUID, > > > but also ends up setting lapic_timer_period. When using oneshot mode > > > with lapic timer, predefined value of lapic_timer_period causes lapic > > > timer calibration to be skipped with wrong multipliers set for lapic > > > timer. > > > > > > To avoid this issue, override the TSC calibration step for TDX VMs to > > > just calculate the TSC frequency using cpuid values. > > > > This is a hack to workaround a KVM TDX bug. Per Intel's SDM: > > > > 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) divided by the value specified in the divide configuration register. > > > > TDX hardcodes the core crystal frequency to 25Mhz, whereas KVM hardcodes the APIC > > bus frequency to 1Ghz. Upstream KVM's *current* behavior is fine, because KVM > > doesn't advertise support for CPUID 0x15, i.e. doesn't announce to host userspace > > that it's safe to expose CPUID 0x15 to the guest. Because TDX makes exposing > > CPUID 0x15 mandatory, KVM needs to be taught to correctly emulate the guest's > > APIC bus frequency, a.k.a. the TDX guest core crystal frequency of 25Mhz. > > Ack, makes sense to pursue this fix from the KVM TDX side instead of guest changes as per your suggestion. > > > > I.e. tmict_to_ns() needs to replace APIC_BUS_CYCLE_NS with some math that makes > > the guest's APIC timer actually run at 25Mhz given whatever the host APIC bus > > runs at. > > > > static inline u64 tmict_to_ns(struct kvm_lapic *apic, u32 tmict) > > { > > return (u64)tmict * APIC_BUS_CYCLE_NS * (u64)apic->divide_count; > > } >
diff --git a/arch/x86/coco/tdx/tdx.c b/arch/x86/coco/tdx/tdx.c index 1d6b863c42b0..6625594f8c62 100644 --- a/arch/x86/coco/tdx/tdx.c +++ b/arch/x86/coco/tdx/tdx.c @@ -757,6 +757,33 @@ static bool tdx_enc_status_change_finish(unsigned long vaddr, int numpages, return true; } +/** + * Determine TSC frequency via CPUID, else return 0. + */ +static unsigned long tdx_calibrate_tsc(void) +{ + unsigned int eax_denominator = 0, ebx_numerator = 0, ecx_hz = 0, edx = 0; + unsigned int crystal_khz; + + /* CPUID 15H TSC/Crystal ratio, plus optionally Crystal Hz */ + cpuid(0x15, &eax_denominator, &ebx_numerator, &ecx_hz, &edx); + + if (ebx_numerator == 0 || eax_denominator == 0) + return 0; + + crystal_khz = ecx_hz / 1000; + + /* + * TSC frequency reported directly by CPUID is a "hardware reported" + * frequency and is the most accurate one so far we have. This + * is considered a known frequency. + */ + if (crystal_khz != 0) + setup_force_cpu_cap(X86_FEATURE_TSC_KNOWN_FREQ); + + return crystal_khz * ebx_numerator / eax_denominator; +} + void __init tdx_early_init(void) { u64 cc_mask; @@ -808,6 +835,7 @@ void __init tdx_early_init(void) x86_platform.guest.enc_cache_flush_required = tdx_cache_flush_required; x86_platform.guest.enc_tlb_flush_required = tdx_tlb_flush_required; + x86_platform.calibrate_tsc = tdx_calibrate_tsc; /* * TDX intercepts the RDMSR to read the X2APIC ID in the parallel