Topics

[PATCH] UefiCpuPkg: Adding a new TSC library by using CPUID(0x15) TSC leaf

Zeng, Star
 

Some comments below.

-----Original Message-----
From: Kuo, Donald
Sent: Monday, August 12, 2019 1:57 PM
To: devel@edk2.groups.io
Cc: Ni, Ray <ray.ni@...>; Zeng, Star <star.zeng@...>; Dong, Eric
<eric.dong@...>
Subject: [PATCH] UefiCpuPkg: Adding a new TSC library by using CPUID(0x15)
TSC leaf

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=1909

Cc: Ray Ni <ray.ni@...>
Cc: Star Zeng <star.zeng@...>
Cc: Eric Dong <eric.dong@...>
Signed-off-by: Donald Kuo <donald.kuo@...>
---
.../Library/BaseCpuTimerLib/BaseCpuTimerLib.c | 40 +++
.../Library/BaseCpuTimerLib/BaseCpuTimerLib.inf | 35 +++
.../Library/BaseCpuTimerLib/BaseCpuTimerLib.uni | 17 ++
UefiCpuPkg/Library/BaseCpuTimerLib/CpuTimerLib.c | 290
+++++++++++++++++++++
UefiCpuPkg/UefiCpuPkg.dec | 8 +
UefiCpuPkg/UefiCpuPkg.dsc | 4 +-
6 files changed, 393 insertions(+), 1 deletion(-) create mode 100644
UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.c
create mode 100644
UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.inf
create mode 100644
UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.uni
create mode 100644 UefiCpuPkg/Library/BaseCpuTimerLib/CpuTimerLib.c

[Trimmed]


+
diff --git a/UefiCpuPkg/Library/BaseCpuTimerLib/CpuTimerLib.c
b/UefiCpuPkg/Library/BaseCpuTimerLib/CpuTimerLib.c
new file mode 100644
index 0000000000..5ed01146cf
--- /dev/null
+++ b/UefiCpuPkg/Library/BaseCpuTimerLib/CpuTimerLib.c
@@ -0,0 +1,290 @@
+/** @file
+ CPUID Leaf 0x15 for Core Crystal Clock frequency instance of Timer Library.
+
+ Copyright (c) 2019 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DebugLib.h>
+#include <Register/Cpuid.h>
+
+/**
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+InternalGetPerformanceCounterFrequency (
+ VOID
+ );
+
+/**
+ CPUID Leaf 0x15 for Core Crystal Clock Frequency.
+
+ The TSC counting frequency is determined by using CPUID leaf 0x15.
Frequency in MHz = Core XTAL frequency * EBX/EAX.
+ In newer flavors of the CPU, core xtal frequency is returned in ECX or 0 if
not supported.
+ @return The number of TSC counts per second.
+
+**/
+UINT64
+CpuidCoreClockCalculateTscFrequency (
+ VOID
+ )
+{
+ CPUID_VERSION_INFO_EAX Eax;
+ UINT64 TscFrequency;
+ UINT64 CoreXtalFrequency;
+ UINT32 RegEax;
+ UINT32 RegEbx;
+ UINT32 RegEcx;
+
+ //
+ // Display CPU FAMILY / MODEL / STEPPING ID Info // AsmCpuid
+ (CPUID_VERSION_INFO, &Eax.Uint32, NULL, NULL, NULL); DEBUG
+ ((DEBUG_INFO, "CPUID = %X\n", (Eax.Uint32 & 0x0FFF0FFF)));
Suggest removing this debugging code block.

+
+ //
+ // Use CPUID leaf 0x15 Time Stamp Counter and Nominal Core Crystal
+ Clock Information // EBX returns 0 if not supported. ECX, if non zero,
provides Core Xtal Frequency in hertz.
+ // TSC frequency = (ECX, Core Xtal Frequency) * EBX/EAX.
+ //
+ AsmCpuid (CPUID_TIME_STAMP_COUNTER, &RegEax, &RegEbx, &RegEcx,
NULL);
+ DEBUG ((DEBUG_INFO, "Denominator of the TSC ratio = %d\n", RegEax));
+ DEBUG ((DEBUG_INFO, "Numerator of the TSC ratio = %d\n", RegEbx));
+ DEBUG ((DEBUG_INFO, "Nominal frequency (hertz) = %d\n", RegEcx));
Suggest removing this debug message codes as the timerlib may be used by AP.

+
+ //
+ // If EBX returns 0, the XTAL ratio is not enumerated.
+ //
+ if (RegEbx == 0) {
+ DEBUG ((DEBUG_ERROR, "The CPU is not capble for Core Crystal Clock
Frequency !!\n"));
Suggest removing this debug message codes as the timerlib may be used by AP.
Then the if condition can be also removed.

+ ASSERT (RegEbx != 0);
+ }
+ //
+ // If ECX returns 0, the XTAL frequency is not enumerated.
+ //
+ if (RegEcx == 0) {
+ DEBUG ((DEBUG_ERROR, "The CPU is not capble for Core Crystal Clock
Frequency !!\n"));
Suggest removing this debug message codes as the timerlib may be used by AP.

+ CoreXtalFrequency = PcdGet64 (PcdCpuCoreCrystalClockFrequency);
+ DEBUG ((DEBUG_INFO, "CoreXtalFrequency (hertz) from PCD = %d\n",
CoreXtalFrequency));
Suggest removing this debug message codes as the timerlib may be used by AP.

+ //ASSERT (RegEcx != 0);
Suggest removing this line

+ } else {
+ CoreXtalFrequency = (UINT64) RegEcx; }
+
+ //
+ // Calculate TSC frequency = (ECX, Core Xtal Frequency) * EBX/EAX //
+ TscFrequency = DivU64x32 (MultU64x32 (CoreXtalFrequency, RegEbx) +
+ (UINT64)(RegEax >> 1), RegEax);
+
+ return TscFrequency;
+}
+
[Trimmed]

--- a/UefiCpuPkg/UefiCpuPkg.dsc
+++ b/UefiCpuPkg/UefiCpuPkg.dsc
@@ -42,7 +42,7 @@
PeimEntryPoint|MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf
PeiServicesLib|MdePkg/Library/PeiServicesLib/PeiServicesLib.inf

PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanc
eLibNull.inf
-
TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTem
plate.inf
+#
+TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTe
mpla
+te.inf
Suggest removing this line.

Thanks,
Star


DebugAgentLib|MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLi
bNull.inf

LocalApicLib|UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.in
f

ReportStatusCodeLib|MdePkg/Library/BaseReportStatusCodeLibNull/BaseR
eportStatusCodeLibNull.inf
@@ -56,6 +56,7 @@

PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/Base
PeCoffGetEntryPointLib.inf

PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BaseP
eCoffExtraActionLibNull.inf

TpmMeasurementLib|MdeModulePkg/Library/TpmMeasurementLibNull/Tp
mMeasurementLibNull.inf
+ TimerLib|UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.inf

[LibraryClasses.common.SEC]

PlatformSecLib|UefiCpuPkg/Library/PlatformSecLibNull/PlatformSecLibNull.i
nf
@@ -143,6 +144,7 @@

SmmCpuFeaturesLib|UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFea
turesLibStm.inf
}
UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume2Pei.inf
+ UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.inf

[BuildOptions]
*_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES
--
2.14.2.windows.3

Donald Kuo
 

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=1909

Cc: Ray Ni <ray.ni@...>
Cc: Star Zeng <star.zeng@...>
Cc: Eric Dong <eric.dong@...>
Cc: Amy Chan <amy.chan@...>
Cc: Rangasai V Chaganty <rangasai.v.chaganty@...>
Signed-off-by: Donald Kuo <donald.kuo@...>
---
.../Library/BaseCpuTimerLib/BaseCpuTimerLib.c | 40 +++
.../Library/BaseCpuTimerLib/BaseCpuTimerLib.inf | 35 +++
.../Library/BaseCpuTimerLib/BaseCpuTimerLib.uni | 16 ++
UefiCpuPkg/Library/BaseCpuTimerLib/CpuTimerLib.c | 274 +++++++++++++++++++++
UefiCpuPkg/UefiCpuPkg.dec | 8 +
UefiCpuPkg/UefiCpuPkg.dsc | 1 +
6 files changed, 374 insertions(+)
create mode 100644 UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.c
create mode 100644 UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.inf
create mode 100644 UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.uni
create mode 100644 UefiCpuPkg/Library/BaseCpuTimerLib/CpuTimerLib.c

diff --git a/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.c b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.c
new file mode 100644
index 0000000000..ccb92a95d3
--- /dev/null
+++ b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.c
@@ -0,0 +1,40 @@
+/** @file
+ CPUID Leaf 0x15 for Core Crystal Clock frequency instance of Timer Library.
+
+ Copyright (c) 2019 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+
+/**
+ CPUID Leaf 0x15 for Core Crystal Clock Frequency.
+
+ The TSC counting frequency is determined by using CPUID leaf 0x15. Frequency in MHz = Core XTAL frequency * EBX/EAX.
+ In newer flavors of the CPU, core xtal frequency is returned in ECX or 0 if not supported.
+ @return The number of TSC counts per second.
+
+**/
+UINT64
+CpuidCoreClockCalculateTscFrequency (
+ VOID
+ );
+
+/**
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+InternalGetPerformanceCounterFrequency (
+ VOID
+ )
+{
+ return CpuidCoreClockCalculateTscFrequency ();
+}
diff --git a/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.inf b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.inf
new file mode 100644
index 0000000000..7e27a55c90
--- /dev/null
+++ b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.inf
@@ -0,0 +1,35 @@
+## @file
+# Base CPU Timer Library
+#
+# Provides basic timer support using CPUID Leaf 0x15 XTAL frequency. The performance
+# counter features are provided by the processors time stamp counter.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = BaseCpuTimerLib
+ FILE_GUID = F10B5B91-D15A-496C-B044-B5235721AA08
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = TimerLib
+ MODULE_UNI_FILE = BaseCpuTimerLib.uni
+
+[Sources]
+ CpuTimerLib.c
+ BaseCpuTimerLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ PcdLib
+ DebugLib
+
+[Pcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuCoreCrystalClockFrequency ## CONSUMES
diff --git a/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.uni b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.uni
new file mode 100644
index 0000000000..6e5c3ef70e
--- /dev/null
+++ b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.uni
@@ -0,0 +1,16 @@
+// /** @file
+// Base CPU Timer Library
+//
+// Provides basic timer support using CPUID Leaf 0x15 XTAL frequency. The performance
+// counter features are provided by the processors time stamp counter.
+//
+// Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "CPU Timer Library"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Provides basic timer support using CPUID Leaf 0x15 XTAL frequency."
diff --git a/UefiCpuPkg/Library/BaseCpuTimerLib/CpuTimerLib.c b/UefiCpuPkg/Library/BaseCpuTimerLib/CpuTimerLib.c
new file mode 100644
index 0000000000..965e206d7d
--- /dev/null
+++ b/UefiCpuPkg/Library/BaseCpuTimerLib/CpuTimerLib.c
@@ -0,0 +1,274 @@
+/** @file
+ CPUID Leaf 0x15 for Core Crystal Clock frequency instance of Timer Library.
+
+ Copyright (c) 2019 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DebugLib.h>
+#include <Register/Cpuid.h>
+
+/**
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+InternalGetPerformanceCounterFrequency (
+ VOID
+ );
+
+/**
+ CPUID Leaf 0x15 for Core Crystal Clock Frequency.
+
+ The TSC counting frequency is determined by using CPUID leaf 0x15. Frequency in MHz = Core XTAL frequency * EBX/EAX.
+ In newer flavors of the CPU, core xtal frequency is returned in ECX or 0 if not supported.
+ @return The number of TSC counts per second.
+
+**/
+UINT64
+CpuidCoreClockCalculateTscFrequency (
+ VOID
+ )
+{
+ CPUID_VERSION_INFO_EAX Eax;
+ UINT64 TscFrequency;
+ UINT64 CoreXtalFrequency;
+ UINT32 RegEax;
+ UINT32 RegEbx;
+ UINT32 RegEcx;
+
+ //
+ // Use CPUID leaf 0x15 Time Stamp Counter and Nominal Core Crystal Clock Information
+ // EBX returns 0 if not supported. ECX, if non zero, provides Core Xtal Frequency in hertz.
+ // TSC frequency = (ECX, Core Xtal Frequency) * EBX/EAX.
+ //
+ AsmCpuid (CPUID_TIME_STAMP_COUNTER, &RegEax, &RegEbx, &RegEcx, NULL);
+
+ //
+ // If EBX returns 0, the XTAL ratio is not enumerated.
+ //
+ if (RegEbx == 0) {
+ ASSERT (RegEbx != 0);
+ }
+ //
+ // If ECX returns 0, the XTAL frequency is not enumerated.
+ //
+ if (RegEcx == 0) {
+ CoreXtalFrequency = PcdGet64 (PcdCpuCoreCrystalClockFrequency);
+ } else {
+ CoreXtalFrequency = (UINT64) RegEcx;
+ }
+
+ //
+ // Calculate TSC frequency = (ECX, Core Xtal Frequency) * EBX/EAX
+ //
+ TscFrequency = DivU64x32 (MultU64x32 (CoreXtalFrequency, RegEbx) + (UINT64)(RegEax >> 1), RegEax);
+
+ return TscFrequency;
+}
+
+/**
+ Stalls the CPU for at least the given number of ticks.
+
+ Stalls the CPU for at least the given number of ticks. It's invoked by
+ MicroSecondDelay() and NanoSecondDelay().
+
+ @param Delay A period of time to delay in ticks.
+
+**/
+VOID
+InternalCpuDelay (
+ IN UINT64 Delay
+ )
+{
+ UINT64 Ticks;
+
+ //
+ // The target timer count is calculated here
+ //
+ Ticks = AsmReadTsc() + Delay;
+
+ //
+ // Wait until time out
+ // Timer wrap-arounds are NOT handled correctly by this function.
+ // Thus, this function must be called within 10 years of reset since
+ // Intel guarantees a minimum of 10 years before the TSC wraps.
+ //
+ while (AsmReadTsc() <= Ticks) {
+ CpuPause();
+ }
+}
+
+/**
+ Stalls the CPU for at least the given number of microseconds.
+
+ Stalls the CPU for the number of microseconds specified by MicroSeconds.
+
+ @param[in] MicroSeconds The minimum number of microseconds to delay.
+
+ @return MicroSeconds
+
+**/
+UINTN
+EFIAPI
+MicroSecondDelay (
+ IN UINTN MicroSeconds
+ )
+{
+
+ InternalCpuDelay (
+ DivU64x32 (
+ MultU64x64 (
+ MicroSeconds,
+ CpuidCoreClockCalculateTscFrequency ()
+ ),
+ 1000000u
+ )
+ );
+
+ return MicroSeconds;
+}
+
+/**
+ Stalls the CPU for at least the given number of nanoseconds.
+
+ Stalls the CPU for the number of nanoseconds specified by NanoSeconds.
+
+ @param NanoSeconds The minimum number of nanoseconds to delay.
+
+ @return NanoSeconds
+
+**/
+UINTN
+EFIAPI
+NanoSecondDelay (
+ IN UINTN NanoSeconds
+ )
+{
+
+ InternalCpuDelay (
+ DivU64x32 (
+ MultU64x64 (
+ NanoSeconds,
+ CpuidCoreClockCalculateTscFrequency ()
+ ),
+ 1000000000u
+ )
+ );
+
+ return NanoSeconds;
+}
+
+/**
+ Retrieves the current value of a 64-bit free running performance counter.
+
+ Retrieves the current value of a 64-bit free running performance counter. The
+ counter can either count up by 1 or count down by 1. If the physical
+ performance counter counts by a larger increment, then the counter values
+ must be translated. The properties of the counter can be retrieved from
+ GetPerformanceCounterProperties().
+
+ @return The current value of the free running performance counter.
+
+**/
+UINT64
+EFIAPI
+GetPerformanceCounter (
+ VOID
+ )
+{
+ return AsmReadTsc ();
+}
+
+/**
+ Retrieves the 64-bit frequency in Hz and the range of performance counter
+ values.
+
+ If StartValue is not NULL, then the value that the performance counter starts
+ with immediately after is it rolls over is returned in StartValue. If
+ EndValue is not NULL, then the value that the performance counter end with
+ immediately before it rolls over is returned in EndValue. The 64-bit
+ frequency of the performance counter in Hz is always returned. If StartValue
+ is less than EndValue, then the performance counter counts up. If StartValue
+ is greater than EndValue, then the performance counter counts down. For
+ example, a 64-bit free running counter that counts up would have a StartValue
+ of 0 and an EndValue of 0xFFFFFFFFFFFFFFFF. A 24-bit free running counter
+ that counts down would have a StartValue of 0xFFFFFF and an EndValue of 0.
+
+ @param StartValue The value the performance counter starts with when it
+ rolls over.
+ @param EndValue The value that the performance counter ends with before
+ it rolls over.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+EFIAPI
+GetPerformanceCounterProperties (
+ OUT UINT64 *StartValue, OPTIONAL
+ OUT UINT64 *EndValue OPTIONAL
+ )
+{
+ if (StartValue != NULL) {
+ *StartValue = 0;
+ }
+
+ if (EndValue != NULL) {
+ *EndValue = 0xffffffffffffffffULL;
+ }
+ return InternalGetPerformanceCounterFrequency ();
+}
+
+/**
+ Converts elapsed ticks of performance counter to time in nanoseconds.
+
+ This function converts the elapsed ticks of running performance counter to
+ time value in unit of nanoseconds.
+
+ @param Ticks The number of elapsed ticks of running performance counter.
+
+ @return The elapsed time in nanoseconds.
+
+**/
+UINT64
+EFIAPI
+GetTimeInNanoSecond (
+ IN UINT64 Ticks
+ )
+{
+ UINT64 Frequency;
+ UINT64 NanoSeconds;
+ UINT64 Remainder;
+ INTN Shift;
+
+ Frequency = GetPerformanceCounterProperties (NULL, NULL);
+
+ //
+ // Ticks
+ // Time = --------- x 1,000,000,000
+ // Frequency
+ //
+ NanoSeconds = MultU64x32 (DivU64x64Remainder (Ticks, Frequency, &Remainder), 1000000000u);
+
+ //
+ // Ensure (Remainder * 1,000,000,000) will not overflow 64-bit.
+ // Since 2^29 < 1,000,000,000 = 0x3B9ACA00 < 2^30, Remainder should < 2^(64-30) = 2^34,
+ // i.e. highest bit set in Remainder should <= 33.
+ //
+ Shift = MAX (0, HighBitSet64 (Remainder) - 33);
+ Remainder = RShiftU64 (Remainder, (UINTN) Shift);
+ Frequency = RShiftU64 (Frequency, (UINTN) Shift);
+ NanoSeconds += DivU64x64Remainder (MultU64x32 (Remainder, 1000000000u), Frequency, NULL);
+
+ return NanoSeconds;
+}
diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec
index 14ddaa8633..a94bd2ea30 100644
--- a/UefiCpuPkg/UefiCpuPkg.dec
+++ b/UefiCpuPkg/UefiCpuPkg.dec
@@ -211,6 +211,14 @@
# @Prompt If CPU features will be initialized during S3 resume.
gUefiCpuPkgTokenSpaceGuid.PcdCpuFeaturesInitOnS3Resume|FALSE|BOOLEAN|0x0000001D

+ ## Specifies CPUID Leaf 0x15 Time Stamp Counter and Nominal Core Crystal Clock Frequency.
+ # TSC Frequency = ECX (core crystal clock frequency) * EBX/EAX.
+ # Intel Xeon Processor Scalable Family with CPUID signature 06_55H = 25000000 (25MHz)
+ # 6th and 7th generation Intel Core processors and Intel Xeon W Processor Family = 24000000 (24MHz)
+ # Intel Atom processors based on Goldmont Microarchitecture with CPUID signature 06_5CH = 19200000 (19.2MHz)
+ # @Prompt Core Crystal Clock Frequency is for CPUID Leaf 0x15.ECX
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuCoreCrystalClockFrequency|24000000|UINT64|0x32132113
+
[PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
## Specifies max supported number of Logical Processors.
# @Prompt Configure max supported number of Logical Processors
diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc
index bf690d3978..e1337c741b 100644
--- a/UefiCpuPkg/UefiCpuPkg.dsc
+++ b/UefiCpuPkg/UefiCpuPkg.dsc
@@ -143,6 +143,7 @@
SmmCpuFeaturesLib|UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLibStm.inf
}
UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume2Pei.inf
+ UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.inf

[BuildOptions]
*_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES
--
2.14.2.windows.3

Donald Kuo
 

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=1909

Cc: Ray Ni <ray.ni@...>
Cc: Star Zeng <star.zeng@...>
Cc: Eric Dong <eric.dong@...>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Donald Kuo <donald.kuo@...>
---
.../Library/BaseCpuTimerLib/BaseCpuTimerLib.c | 40 +++
.../Library/BaseCpuTimerLib/BaseCpuTimerLib.inf | 35 +++
.../Library/BaseCpuTimerLib/BaseCpuTimerLib.uni | 17 ++
UefiCpuPkg/Library/BaseCpuTimerLib/CpuTimerLib.c | 290 +++++++++++++++++++++
UefiCpuPkg/UefiCpuPkg.dec | 8 +
UefiCpuPkg/UefiCpuPkg.dsc | 4 +-
6 files changed, 393 insertions(+), 1 deletion(-)
create mode 100644 UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.c
create mode 100644 UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.inf
create mode 100644 UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.uni
create mode 100644 UefiCpuPkg/Library/BaseCpuTimerLib/CpuTimerLib.c

diff --git a/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.c b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.c
new file mode 100644
index 0000000000..ccb92a95d3
--- /dev/null
+++ b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.c
@@ -0,0 +1,40 @@
+/** @file
+ CPUID Leaf 0x15 for Core Crystal Clock frequency instance of Timer Library.
+
+ Copyright (c) 2019 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+
+/**
+ CPUID Leaf 0x15 for Core Crystal Clock Frequency.
+
+ The TSC counting frequency is determined by using CPUID leaf 0x15. Frequency in MHz = Core XTAL frequency * EBX/EAX.
+ In newer flavors of the CPU, core xtal frequency is returned in ECX or 0 if not supported.
+ @return The number of TSC counts per second.
+
+**/
+UINT64
+CpuidCoreClockCalculateTscFrequency (
+ VOID
+ );
+
+/**
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+InternalGetPerformanceCounterFrequency (
+ VOID
+ )
+{
+ return CpuidCoreClockCalculateTscFrequency ();
+}
diff --git a/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.inf b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.inf
new file mode 100644
index 0000000000..c31dacd57a
--- /dev/null
+++ b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.inf
@@ -0,0 +1,35 @@
+## @file
+# Base CPU Timer Library
+#
+# Provides basic timer support using CPUID Leaf 0x15 XTAL frequency. The performance
+# counter features are provided by the processors time stamp counter.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = BaseCpuTimerLib
+ FILE_GUID = F10B5B91-D15A-496C-B044-B5235721AA08
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = TimerLib
+ MODULE_UNI_FILE = BaseCpuTimerLib.uni
+
+[Sources]
+ CpuTimerLib.c
+ BaseCpuTimerLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ PcdLib
+ DebugLib
+
+[Pcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuCoreCrystalClockFrequency ## CONSUMES
\ No newline at end of file
diff --git a/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.uni b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.uni
new file mode 100644
index 0000000000..fcf2b0fbcb
--- /dev/null
+++ b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.uni
@@ -0,0 +1,17 @@
+// /** @file
+// Base CPU Timer Library
+//
+// Provides basic timer support using CPUID Leaf 0x15 XTAL frequency. The performance
+// counter features are provided by the processors time stamp counter.
+//
+// Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "CPU Timer Library"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Provides basic timer support using CPUID Leaf 0x15 XTAL frequency."
+
diff --git a/UefiCpuPkg/Library/BaseCpuTimerLib/CpuTimerLib.c b/UefiCpuPkg/Library/BaseCpuTimerLib/CpuTimerLib.c
new file mode 100644
index 0000000000..5ed01146cf
--- /dev/null
+++ b/UefiCpuPkg/Library/BaseCpuTimerLib/CpuTimerLib.c
@@ -0,0 +1,290 @@
+/** @file
+ CPUID Leaf 0x15 for Core Crystal Clock frequency instance of Timer Library.
+
+ Copyright (c) 2019 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DebugLib.h>
+#include <Register/Cpuid.h>
+
+/**
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+InternalGetPerformanceCounterFrequency (
+ VOID
+ );
+
+/**
+ CPUID Leaf 0x15 for Core Crystal Clock Frequency.
+
+ The TSC counting frequency is determined by using CPUID leaf 0x15. Frequency in MHz = Core XTAL frequency * EBX/EAX.
+ In newer flavors of the CPU, core xtal frequency is returned in ECX or 0 if not supported.
+ @return The number of TSC counts per second.
+
+**/
+UINT64
+CpuidCoreClockCalculateTscFrequency (
+ VOID
+ )
+{
+ CPUID_VERSION_INFO_EAX Eax;
+ UINT64 TscFrequency;
+ UINT64 CoreXtalFrequency;
+ UINT32 RegEax;
+ UINT32 RegEbx;
+ UINT32 RegEcx;
+
+ //
+ // Display CPU FAMILY / MODEL / STEPPING ID Info
+ //
+ AsmCpuid (CPUID_VERSION_INFO, &Eax.Uint32, NULL, NULL, NULL);
+ DEBUG ((DEBUG_INFO, "CPUID = %X\n", (Eax.Uint32 & 0x0FFF0FFF)));
+
+ //
+ // Use CPUID leaf 0x15 Time Stamp Counter and Nominal Core Crystal Clock Information
+ // EBX returns 0 if not supported. ECX, if non zero, provides Core Xtal Frequency in hertz.
+ // TSC frequency = (ECX, Core Xtal Frequency) * EBX/EAX.
+ //
+ AsmCpuid (CPUID_TIME_STAMP_COUNTER, &RegEax, &RegEbx, &RegEcx, NULL);
+ DEBUG ((DEBUG_INFO, "Denominator of the TSC ratio = %d\n", RegEax));
+ DEBUG ((DEBUG_INFO, "Numerator of the TSC ratio = %d\n", RegEbx));
+ DEBUG ((DEBUG_INFO, "Nominal frequency (hertz) = %d\n", RegEcx));
+
+ //
+ // If EBX returns 0, the XTAL ratio is not enumerated.
+ //
+ if (RegEbx == 0) {
+ DEBUG ((DEBUG_ERROR, "The CPU is not capble for Core Crystal Clock Frequency !!\n"));
+ ASSERT (RegEbx != 0);
+ }
+ //
+ // If ECX returns 0, the XTAL frequency is not enumerated.
+ //
+ if (RegEcx == 0) {
+ DEBUG ((DEBUG_ERROR, "The CPU is not capble for Core Crystal Clock Frequency !!\n"));
+ CoreXtalFrequency = PcdGet64 (PcdCpuCoreCrystalClockFrequency);
+ DEBUG ((DEBUG_INFO, "CoreXtalFrequency (hertz) from PCD = %d\n", CoreXtalFrequency));
+ //ASSERT (RegEcx != 0);
+ } else {
+ CoreXtalFrequency = (UINT64) RegEcx;
+ }
+
+ //
+ // Calculate TSC frequency = (ECX, Core Xtal Frequency) * EBX/EAX
+ //
+ TscFrequency = DivU64x32 (MultU64x32 (CoreXtalFrequency, RegEbx) + (UINT64)(RegEax >> 1), RegEax);
+
+ return TscFrequency;
+}
+
+/**
+ Stalls the CPU for at least the given number of ticks.
+
+ Stalls the CPU for at least the given number of ticks. It's invoked by
+ MicroSecondDelay() and NanoSecondDelay().
+
+ @param Delay A period of time to delay in ticks.
+
+**/
+VOID
+InternalCpuDelay (
+ IN UINT64 Delay
+ )
+{
+ UINT64 Ticks;
+
+ //
+ // The target timer count is calculated here
+ //
+ Ticks = AsmReadTsc() + Delay;
+
+ //
+ // Wait until time out
+ // Timer wrap-arounds are NOT handled correctly by this function.
+ // Thus, this function must be called within 10 years of reset since
+ // Intel guarantees a minimum of 10 years before the TSC wraps.
+ //
+ while (AsmReadTsc() <= Ticks) {
+ CpuPause();
+ }
+}
+
+/**
+ Stalls the CPU for at least the given number of microseconds.
+
+ Stalls the CPU for the number of microseconds specified by MicroSeconds.
+
+ @param[in] MicroSeconds The minimum number of microseconds to delay.
+
+ @return MicroSeconds
+
+**/
+UINTN
+EFIAPI
+MicroSecondDelay (
+ IN UINTN MicroSeconds
+ )
+{
+ DEBUG ((DEBUG_INFO, "MicroSecDelay = %d\n", MicroSeconds));
+
+ InternalCpuDelay (
+ DivU64x32 (
+ MultU64x64 (
+ MicroSeconds,
+ CpuidCoreClockCalculateTscFrequency ()
+ ),
+ 1000000u
+ )
+ );
+
+ return MicroSeconds;
+}
+
+/**
+ Stalls the CPU for at least the given number of nanoseconds.
+
+ Stalls the CPU for the number of nanoseconds specified by NanoSeconds.
+
+ @param NanoSeconds The minimum number of nanoseconds to delay.
+
+ @return NanoSeconds
+
+**/
+UINTN
+EFIAPI
+NanoSecondDelay (
+ IN UINTN NanoSeconds
+ )
+{
+ DEBUG ((DEBUG_INFO, "NanoSecDelay = %d\n", NanoSeconds));
+
+ InternalCpuDelay (
+ DivU64x32 (
+ MultU64x64 (
+ NanoSeconds,
+ CpuidCoreClockCalculateTscFrequency ()
+ ),
+ 1000000000u
+ )
+ );
+
+ return NanoSeconds;
+}
+
+/**
+ Retrieves the current value of a 64-bit free running performance counter.
+
+ Retrieves the current value of a 64-bit free running performance counter. The
+ counter can either count up by 1 or count down by 1. If the physical
+ performance counter counts by a larger increment, then the counter values
+ must be translated. The properties of the counter can be retrieved from
+ GetPerformanceCounterProperties().
+
+ @return The current value of the free running performance counter.
+
+**/
+UINT64
+EFIAPI
+GetPerformanceCounter (
+ VOID
+ )
+{
+ return AsmReadTsc ();
+}
+
+/**
+ Retrieves the 64-bit frequency in Hz and the range of performance counter
+ values.
+
+ If StartValue is not NULL, then the value that the performance counter starts
+ with immediately after is it rolls over is returned in StartValue. If
+ EndValue is not NULL, then the value that the performance counter end with
+ immediately before it rolls over is returned in EndValue. The 64-bit
+ frequency of the performance counter in Hz is always returned. If StartValue
+ is less than EndValue, then the performance counter counts up. If StartValue
+ is greater than EndValue, then the performance counter counts down. For
+ example, a 64-bit free running counter that counts up would have a StartValue
+ of 0 and an EndValue of 0xFFFFFFFFFFFFFFFF. A 24-bit free running counter
+ that counts down would have a StartValue of 0xFFFFFF and an EndValue of 0.
+
+ @param StartValue The value the performance counter starts with when it
+ rolls over.
+ @param EndValue The value that the performance counter ends with before
+ it rolls over.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+EFIAPI
+GetPerformanceCounterProperties (
+ OUT UINT64 *StartValue, OPTIONAL
+ OUT UINT64 *EndValue OPTIONAL
+ )
+{
+ if (StartValue != NULL) {
+ *StartValue = 0;
+ }
+
+ if (EndValue != NULL) {
+ *EndValue = 0xffffffffffffffffULL;
+ }
+ return InternalGetPerformanceCounterFrequency ();
+}
+
+/**
+ Converts elapsed ticks of performance counter to time in nanoseconds.
+
+ This function converts the elapsed ticks of running performance counter to
+ time value in unit of nanoseconds.
+
+ @param Ticks The number of elapsed ticks of running performance counter.
+
+ @return The elapsed time in nanoseconds.
+
+**/
+UINT64
+EFIAPI
+GetTimeInNanoSecond (
+ IN UINT64 Ticks
+ )
+{
+ UINT64 Frequency;
+ UINT64 NanoSeconds;
+ UINT64 Remainder;
+ INTN Shift;
+
+ Frequency = GetPerformanceCounterProperties (NULL, NULL);
+
+ //
+ // Ticks
+ // Time = --------- x 1,000,000,000
+ // Frequency
+ //
+ NanoSeconds = MultU64x32 (DivU64x64Remainder (Ticks, Frequency, &Remainder), 1000000000u);
+
+ //
+ // Ensure (Remainder * 1,000,000,000) will not overflow 64-bit.
+ // Since 2^29 < 1,000,000,000 = 0x3B9ACA00 < 2^30, Remainder should < 2^(64-30) = 2^34,
+ // i.e. highest bit set in Remainder should <= 33.
+ //
+ Shift = MAX (0, HighBitSet64 (Remainder) - 33);
+ Remainder = RShiftU64 (Remainder, (UINTN) Shift);
+ Frequency = RShiftU64 (Frequency, (UINTN) Shift);
+ NanoSeconds += DivU64x64Remainder (MultU64x32 (Remainder, 1000000000u), Frequency, NULL);
+
+ return NanoSeconds;
+}
+
diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec
index 14ddaa8633..a94bd2ea30 100644
--- a/UefiCpuPkg/UefiCpuPkg.dec
+++ b/UefiCpuPkg/UefiCpuPkg.dec
@@ -211,6 +211,14 @@
# @Prompt If CPU features will be initialized during S3 resume.
gUefiCpuPkgTokenSpaceGuid.PcdCpuFeaturesInitOnS3Resume|FALSE|BOOLEAN|0x0000001D

+ ## Specifies CPUID Leaf 0x15 Time Stamp Counter and Nominal Core Crystal Clock Frequency.
+ # TSC Frequency = ECX (core crystal clock frequency) * EBX/EAX.
+ # Intel Xeon Processor Scalable Family with CPUID signature 06_55H = 25000000 (25MHz)
+ # 6th and 7th generation Intel Core processors and Intel Xeon W Processor Family = 24000000 (24MHz)
+ # Intel Atom processors based on Goldmont Microarchitecture with CPUID signature 06_5CH = 19200000 (19.2MHz)
+ # @Prompt Core Crystal Clock Frequency is for CPUID Leaf 0x15.ECX
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuCoreCrystalClockFrequency|24000000|UINT64|0x32132113
+
[PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
## Specifies max supported number of Logical Processors.
# @Prompt Configure max supported number of Logical Processors
diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc
index bf690d3978..2d4eb931e1 100644
--- a/UefiCpuPkg/UefiCpuPkg.dsc
+++ b/UefiCpuPkg/UefiCpuPkg.dsc
@@ -42,7 +42,7 @@
PeimEntryPoint|MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf
PeiServicesLib|MdePkg/Library/PeiServicesLib/PeiServicesLib.inf
PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf
- TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf
+# TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf
DebugAgentLib|MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf
LocalApicLib|UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.inf
ReportStatusCodeLib|MdePkg/Library/BaseReportStatusCodeLibNull/BaseReportStatusCodeLibNull.inf
@@ -56,6 +56,7 @@
PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf
PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf
TpmMeasurementLib|MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf
+ TimerLib|UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.inf

[LibraryClasses.common.SEC]
PlatformSecLib|UefiCpuPkg/Library/PlatformSecLibNull/PlatformSecLibNull.inf
@@ -143,6 +144,7 @@
SmmCpuFeaturesLib|UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLibStm.inf
}
UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume2Pei.inf
+ UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.inf

[BuildOptions]
*_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES
--
2.14.2.windows.3

Donald Kuo
 

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=1909

Cc: Ray Ni <ray.ni@...>
Cc: Star Zeng <star.zeng@...>
Cc: Eric Dong <eric.dong@...>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Donald Kuo <donald.kuo@...>
---
.../Library/BaseCpuTimerLib/BaseCpuTimerLib.c | 40 +++
.../Library/BaseCpuTimerLib/BaseCpuTimerLib.inf | 35 +++
.../Library/BaseCpuTimerLib/BaseCpuTimerLib.uni | 17 ++
UefiCpuPkg/Library/BaseCpuTimerLib/CpuTimerLib.c | 290 +++++++++++++++++++++
UefiCpuPkg/UefiCpuPkg.dec | 8 +
UefiCpuPkg/UefiCpuPkg.dsc | 4 +-
6 files changed, 393 insertions(+), 1 deletion(-)
create mode 100644 UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.c
create mode 100644 UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.inf
create mode 100644 UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.uni
create mode 100644 UefiCpuPkg/Library/BaseCpuTimerLib/CpuTimerLib.c

diff --git a/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.c b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.c
new file mode 100644
index 0000000000..ccb92a95d3
--- /dev/null
+++ b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.c
@@ -0,0 +1,40 @@
+/** @file
+ CPUID Leaf 0x15 for Core Crystal Clock frequency instance of Timer Library.
+
+ Copyright (c) 2019 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+
+/**
+ CPUID Leaf 0x15 for Core Crystal Clock Frequency.
+
+ The TSC counting frequency is determined by using CPUID leaf 0x15. Frequency in MHz = Core XTAL frequency * EBX/EAX.
+ In newer flavors of the CPU, core xtal frequency is returned in ECX or 0 if not supported.
+ @return The number of TSC counts per second.
+
+**/
+UINT64
+CpuidCoreClockCalculateTscFrequency (
+ VOID
+ );
+
+/**
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+InternalGetPerformanceCounterFrequency (
+ VOID
+ )
+{
+ return CpuidCoreClockCalculateTscFrequency ();
+}
diff --git a/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.inf b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.inf
new file mode 100644
index 0000000000..c31dacd57a
--- /dev/null
+++ b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.inf
@@ -0,0 +1,35 @@
+## @file
+# Base CPU Timer Library
+#
+# Provides basic timer support using CPUID Leaf 0x15 XTAL frequency. The performance
+# counter features are provided by the processors time stamp counter.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = BaseCpuTimerLib
+ FILE_GUID = F10B5B91-D15A-496C-B044-B5235721AA08
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = TimerLib
+ MODULE_UNI_FILE = BaseCpuTimerLib.uni
+
+[Sources]
+ CpuTimerLib.c
+ BaseCpuTimerLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ PcdLib
+ DebugLib
+
+[Pcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuCoreCrystalClockFrequency ## CONSUMES
\ No newline at end of file
diff --git a/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.uni b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.uni
new file mode 100644
index 0000000000..fcf2b0fbcb
--- /dev/null
+++ b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.uni
@@ -0,0 +1,17 @@
+// /** @file
+// Base CPU Timer Library
+//
+// Provides basic timer support using CPUID Leaf 0x15 XTAL frequency. The performance
+// counter features are provided by the processors time stamp counter.
+//
+// Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "CPU Timer Library"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Provides basic timer support using CPUID Leaf 0x15 XTAL frequency."
+
diff --git a/UefiCpuPkg/Library/BaseCpuTimerLib/CpuTimerLib.c b/UefiCpuPkg/Library/BaseCpuTimerLib/CpuTimerLib.c
new file mode 100644
index 0000000000..5ed01146cf
--- /dev/null
+++ b/UefiCpuPkg/Library/BaseCpuTimerLib/CpuTimerLib.c
@@ -0,0 +1,290 @@
+/** @file
+ CPUID Leaf 0x15 for Core Crystal Clock frequency instance of Timer Library.
+
+ Copyright (c) 2019 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DebugLib.h>
+#include <Register/Cpuid.h>
+
+/**
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+InternalGetPerformanceCounterFrequency (
+ VOID
+ );
+
+/**
+ CPUID Leaf 0x15 for Core Crystal Clock Frequency.
+
+ The TSC counting frequency is determined by using CPUID leaf 0x15. Frequency in MHz = Core XTAL frequency * EBX/EAX.
+ In newer flavors of the CPU, core xtal frequency is returned in ECX or 0 if not supported.
+ @return The number of TSC counts per second.
+
+**/
+UINT64
+CpuidCoreClockCalculateTscFrequency (
+ VOID
+ )
+{
+ CPUID_VERSION_INFO_EAX Eax;
+ UINT64 TscFrequency;
+ UINT64 CoreXtalFrequency;
+ UINT32 RegEax;
+ UINT32 RegEbx;
+ UINT32 RegEcx;
+
+ //
+ // Display CPU FAMILY / MODEL / STEPPING ID Info
+ //
+ AsmCpuid (CPUID_VERSION_INFO, &Eax.Uint32, NULL, NULL, NULL);
+ DEBUG ((DEBUG_INFO, "CPUID = %X\n", (Eax.Uint32 & 0x0FFF0FFF)));
+
+ //
+ // Use CPUID leaf 0x15 Time Stamp Counter and Nominal Core Crystal Clock Information
+ // EBX returns 0 if not supported. ECX, if non zero, provides Core Xtal Frequency in hertz.
+ // TSC frequency = (ECX, Core Xtal Frequency) * EBX/EAX.
+ //
+ AsmCpuid (CPUID_TIME_STAMP_COUNTER, &RegEax, &RegEbx, &RegEcx, NULL);
+ DEBUG ((DEBUG_INFO, "Denominator of the TSC ratio = %d\n", RegEax));
+ DEBUG ((DEBUG_INFO, "Numerator of the TSC ratio = %d\n", RegEbx));
+ DEBUG ((DEBUG_INFO, "Nominal frequency (hertz) = %d\n", RegEcx));
+
+ //
+ // If EBX returns 0, the XTAL ratio is not enumerated.
+ //
+ if (RegEbx == 0) {
+ DEBUG ((DEBUG_ERROR, "The CPU is not capble for Core Crystal Clock Frequency !!\n"));
+ ASSERT (RegEbx != 0);
+ }
+ //
+ // If ECX returns 0, the XTAL frequency is not enumerated.
+ //
+ if (RegEcx == 0) {
+ DEBUG ((DEBUG_ERROR, "The CPU is not capble for Core Crystal Clock Frequency !!\n"));
+ CoreXtalFrequency = PcdGet64 (PcdCpuCoreCrystalClockFrequency);
+ DEBUG ((DEBUG_INFO, "CoreXtalFrequency (hertz) from PCD = %d\n", CoreXtalFrequency));
+ //ASSERT (RegEcx != 0);
+ } else {
+ CoreXtalFrequency = (UINT64) RegEcx;
+ }
+
+ //
+ // Calculate TSC frequency = (ECX, Core Xtal Frequency) * EBX/EAX
+ //
+ TscFrequency = DivU64x32 (MultU64x32 (CoreXtalFrequency, RegEbx) + (UINT64)(RegEax >> 1), RegEax);
+
+ return TscFrequency;
+}
+
+/**
+ Stalls the CPU for at least the given number of ticks.
+
+ Stalls the CPU for at least the given number of ticks. It's invoked by
+ MicroSecondDelay() and NanoSecondDelay().
+
+ @param Delay A period of time to delay in ticks.
+
+**/
+VOID
+InternalCpuDelay (
+ IN UINT64 Delay
+ )
+{
+ UINT64 Ticks;
+
+ //
+ // The target timer count is calculated here
+ //
+ Ticks = AsmReadTsc() + Delay;
+
+ //
+ // Wait until time out
+ // Timer wrap-arounds are NOT handled correctly by this function.
+ // Thus, this function must be called within 10 years of reset since
+ // Intel guarantees a minimum of 10 years before the TSC wraps.
+ //
+ while (AsmReadTsc() <= Ticks) {
+ CpuPause();
+ }
+}
+
+/**
+ Stalls the CPU for at least the given number of microseconds.
+
+ Stalls the CPU for the number of microseconds specified by MicroSeconds.
+
+ @param[in] MicroSeconds The minimum number of microseconds to delay.
+
+ @return MicroSeconds
+
+**/
+UINTN
+EFIAPI
+MicroSecondDelay (
+ IN UINTN MicroSeconds
+ )
+{
+ DEBUG ((DEBUG_INFO, "MicroSecDelay = %d\n", MicroSeconds));
+
+ InternalCpuDelay (
+ DivU64x32 (
+ MultU64x64 (
+ MicroSeconds,
+ CpuidCoreClockCalculateTscFrequency ()
+ ),
+ 1000000u
+ )
+ );
+
+ return MicroSeconds;
+}
+
+/**
+ Stalls the CPU for at least the given number of nanoseconds.
+
+ Stalls the CPU for the number of nanoseconds specified by NanoSeconds.
+
+ @param NanoSeconds The minimum number of nanoseconds to delay.
+
+ @return NanoSeconds
+
+**/
+UINTN
+EFIAPI
+NanoSecondDelay (
+ IN UINTN NanoSeconds
+ )
+{
+ DEBUG ((DEBUG_INFO, "NanoSecDelay = %d\n", NanoSeconds));
+
+ InternalCpuDelay (
+ DivU64x32 (
+ MultU64x64 (
+ NanoSeconds,
+ CpuidCoreClockCalculateTscFrequency ()
+ ),
+ 1000000000u
+ )
+ );
+
+ return NanoSeconds;
+}
+
+/**
+ Retrieves the current value of a 64-bit free running performance counter.
+
+ Retrieves the current value of a 64-bit free running performance counter. The
+ counter can either count up by 1 or count down by 1. If the physical
+ performance counter counts by a larger increment, then the counter values
+ must be translated. The properties of the counter can be retrieved from
+ GetPerformanceCounterProperties().
+
+ @return The current value of the free running performance counter.
+
+**/
+UINT64
+EFIAPI
+GetPerformanceCounter (
+ VOID
+ )
+{
+ return AsmReadTsc ();
+}
+
+/**
+ Retrieves the 64-bit frequency in Hz and the range of performance counter
+ values.
+
+ If StartValue is not NULL, then the value that the performance counter starts
+ with immediately after is it rolls over is returned in StartValue. If
+ EndValue is not NULL, then the value that the performance counter end with
+ immediately before it rolls over is returned in EndValue. The 64-bit
+ frequency of the performance counter in Hz is always returned. If StartValue
+ is less than EndValue, then the performance counter counts up. If StartValue
+ is greater than EndValue, then the performance counter counts down. For
+ example, a 64-bit free running counter that counts up would have a StartValue
+ of 0 and an EndValue of 0xFFFFFFFFFFFFFFFF. A 24-bit free running counter
+ that counts down would have a StartValue of 0xFFFFFF and an EndValue of 0.
+
+ @param StartValue The value the performance counter starts with when it
+ rolls over.
+ @param EndValue The value that the performance counter ends with before
+ it rolls over.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+EFIAPI
+GetPerformanceCounterProperties (
+ OUT UINT64 *StartValue, OPTIONAL
+ OUT UINT64 *EndValue OPTIONAL
+ )
+{
+ if (StartValue != NULL) {
+ *StartValue = 0;
+ }
+
+ if (EndValue != NULL) {
+ *EndValue = 0xffffffffffffffffULL;
+ }
+ return InternalGetPerformanceCounterFrequency ();
+}
+
+/**
+ Converts elapsed ticks of performance counter to time in nanoseconds.
+
+ This function converts the elapsed ticks of running performance counter to
+ time value in unit of nanoseconds.
+
+ @param Ticks The number of elapsed ticks of running performance counter.
+
+ @return The elapsed time in nanoseconds.
+
+**/
+UINT64
+EFIAPI
+GetTimeInNanoSecond (
+ IN UINT64 Ticks
+ )
+{
+ UINT64 Frequency;
+ UINT64 NanoSeconds;
+ UINT64 Remainder;
+ INTN Shift;
+
+ Frequency = GetPerformanceCounterProperties (NULL, NULL);
+
+ //
+ // Ticks
+ // Time = --------- x 1,000,000,000
+ // Frequency
+ //
+ NanoSeconds = MultU64x32 (DivU64x64Remainder (Ticks, Frequency, &Remainder), 1000000000u);
+
+ //
+ // Ensure (Remainder * 1,000,000,000) will not overflow 64-bit.
+ // Since 2^29 < 1,000,000,000 = 0x3B9ACA00 < 2^30, Remainder should < 2^(64-30) = 2^34,
+ // i.e. highest bit set in Remainder should <= 33.
+ //
+ Shift = MAX (0, HighBitSet64 (Remainder) - 33);
+ Remainder = RShiftU64 (Remainder, (UINTN) Shift);
+ Frequency = RShiftU64 (Frequency, (UINTN) Shift);
+ NanoSeconds += DivU64x64Remainder (MultU64x32 (Remainder, 1000000000u), Frequency, NULL);
+
+ return NanoSeconds;
+}
+
diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec
index 14ddaa8633..a94bd2ea30 100644
--- a/UefiCpuPkg/UefiCpuPkg.dec
+++ b/UefiCpuPkg/UefiCpuPkg.dec
@@ -211,6 +211,14 @@
# @Prompt If CPU features will be initialized during S3 resume.
gUefiCpuPkgTokenSpaceGuid.PcdCpuFeaturesInitOnS3Resume|FALSE|BOOLEAN|0x0000001D

+ ## Specifies CPUID Leaf 0x15 Time Stamp Counter and Nominal Core Crystal Clock Frequency.
+ # TSC Frequency = ECX (core crystal clock frequency) * EBX/EAX.
+ # Intel Xeon Processor Scalable Family with CPUID signature 06_55H = 25000000 (25MHz)
+ # 6th and 7th generation Intel Core processors and Intel Xeon W Processor Family = 24000000 (24MHz)
+ # Intel Atom processors based on Goldmont Microarchitecture with CPUID signature 06_5CH = 19200000 (19.2MHz)
+ # @Prompt Core Crystal Clock Frequency is for CPUID Leaf 0x15.ECX
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuCoreCrystalClockFrequency|24000000|UINT64|0x32132113
+
[PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
## Specifies max supported number of Logical Processors.
# @Prompt Configure max supported number of Logical Processors
diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc
index bf690d3978..2d4eb931e1 100644
--- a/UefiCpuPkg/UefiCpuPkg.dsc
+++ b/UefiCpuPkg/UefiCpuPkg.dsc
@@ -42,7 +42,7 @@
PeimEntryPoint|MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf
PeiServicesLib|MdePkg/Library/PeiServicesLib/PeiServicesLib.inf
PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf
- TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf
+# TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf
DebugAgentLib|MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf
LocalApicLib|UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.inf
ReportStatusCodeLib|MdePkg/Library/BaseReportStatusCodeLibNull/BaseReportStatusCodeLibNull.inf
@@ -56,6 +56,7 @@
PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf
PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf
TpmMeasurementLib|MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf
+ TimerLib|UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.inf

[LibraryClasses.common.SEC]
PlatformSecLib|UefiCpuPkg/Library/PlatformSecLibNull/PlatformSecLibNull.inf
@@ -143,6 +144,7 @@
SmmCpuFeaturesLib|UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLibStm.inf
}
UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume2Pei.inf
+ UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.inf

[BuildOptions]
*_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES
--
2.14.2.windows.3

Donald Kuo
 

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=1909

Cc: Ray Ni <ray.ni@...>
Cc: Star Zeng <star.zeng@...>
Cc: Eric Dong <eric.dong@...>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Donald Kuo <donald.kuo@...>
---
.../Library/BaseCpuTimerLib/BaseCpuTimerLib.c | 40 +++
.../Library/BaseCpuTimerLib/BaseCpuTimerLib.inf | 35 +++
.../Library/BaseCpuTimerLib/BaseCpuTimerLib.uni | 17 ++
UefiCpuPkg/Library/BaseCpuTimerLib/CpuTimerLib.c | 290 +++++++++++++++++++++
UefiCpuPkg/UefiCpuPkg.dec | 8 +
UefiCpuPkg/UefiCpuPkg.dsc | 4 +-
6 files changed, 393 insertions(+), 1 deletion(-)
create mode 100644 UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.c
create mode 100644 UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.inf
create mode 100644 UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.uni
create mode 100644 UefiCpuPkg/Library/BaseCpuTimerLib/CpuTimerLib.c

diff --git a/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.c b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.c
new file mode 100644
index 0000000000..ccb92a95d3
--- /dev/null
+++ b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.c
@@ -0,0 +1,40 @@
+/** @file
+ CPUID Leaf 0x15 for Core Crystal Clock frequency instance of Timer Library.
+
+ Copyright (c) 2019 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+
+/**
+ CPUID Leaf 0x15 for Core Crystal Clock Frequency.
+
+ The TSC counting frequency is determined by using CPUID leaf 0x15. Frequency in MHz = Core XTAL frequency * EBX/EAX.
+ In newer flavors of the CPU, core xtal frequency is returned in ECX or 0 if not supported.
+ @return The number of TSC counts per second.
+
+**/
+UINT64
+CpuidCoreClockCalculateTscFrequency (
+ VOID
+ );
+
+/**
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+InternalGetPerformanceCounterFrequency (
+ VOID
+ )
+{
+ return CpuidCoreClockCalculateTscFrequency ();
+}
diff --git a/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.inf b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.inf
new file mode 100644
index 0000000000..c31dacd57a
--- /dev/null
+++ b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.inf
@@ -0,0 +1,35 @@
+## @file
+# Base CPU Timer Library
+#
+# Provides basic timer support using CPUID Leaf 0x15 XTAL frequency. The performance
+# counter features are provided by the processors time stamp counter.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = BaseCpuTimerLib
+ FILE_GUID = F10B5B91-D15A-496C-B044-B5235721AA08
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = TimerLib
+ MODULE_UNI_FILE = BaseCpuTimerLib.uni
+
+[Sources]
+ CpuTimerLib.c
+ BaseCpuTimerLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ PcdLib
+ DebugLib
+
+[Pcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuCoreCrystalClockFrequency ## CONSUMES
\ No newline at end of file
diff --git a/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.uni b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.uni
new file mode 100644
index 0000000000..fcf2b0fbcb
--- /dev/null
+++ b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.uni
@@ -0,0 +1,17 @@
+// /** @file
+// Base CPU Timer Library
+//
+// Provides basic timer support using CPUID Leaf 0x15 XTAL frequency. The performance
+// counter features are provided by the processors time stamp counter.
+//
+// Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "CPU Timer Library"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Provides basic timer support using CPUID Leaf 0x15 XTAL frequency."
+
diff --git a/UefiCpuPkg/Library/BaseCpuTimerLib/CpuTimerLib.c b/UefiCpuPkg/Library/BaseCpuTimerLib/CpuTimerLib.c
new file mode 100644
index 0000000000..5ed01146cf
--- /dev/null
+++ b/UefiCpuPkg/Library/BaseCpuTimerLib/CpuTimerLib.c
@@ -0,0 +1,290 @@
+/** @file
+ CPUID Leaf 0x15 for Core Crystal Clock frequency instance of Timer Library.
+
+ Copyright (c) 2019 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DebugLib.h>
+#include <Register/Cpuid.h>
+
+/**
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+InternalGetPerformanceCounterFrequency (
+ VOID
+ );
+
+/**
+ CPUID Leaf 0x15 for Core Crystal Clock Frequency.
+
+ The TSC counting frequency is determined by using CPUID leaf 0x15. Frequency in MHz = Core XTAL frequency * EBX/EAX.
+ In newer flavors of the CPU, core xtal frequency is returned in ECX or 0 if not supported.
+ @return The number of TSC counts per second.
+
+**/
+UINT64
+CpuidCoreClockCalculateTscFrequency (
+ VOID
+ )
+{
+ CPUID_VERSION_INFO_EAX Eax;
+ UINT64 TscFrequency;
+ UINT64 CoreXtalFrequency;
+ UINT32 RegEax;
+ UINT32 RegEbx;
+ UINT32 RegEcx;
+
+ //
+ // Display CPU FAMILY / MODEL / STEPPING ID Info
+ //
+ AsmCpuid (CPUID_VERSION_INFO, &Eax.Uint32, NULL, NULL, NULL);
+ DEBUG ((DEBUG_INFO, "CPUID = %X\n", (Eax.Uint32 & 0x0FFF0FFF)));
+
+ //
+ // Use CPUID leaf 0x15 Time Stamp Counter and Nominal Core Crystal Clock Information
+ // EBX returns 0 if not supported. ECX, if non zero, provides Core Xtal Frequency in hertz.
+ // TSC frequency = (ECX, Core Xtal Frequency) * EBX/EAX.
+ //
+ AsmCpuid (CPUID_TIME_STAMP_COUNTER, &RegEax, &RegEbx, &RegEcx, NULL);
+ DEBUG ((DEBUG_INFO, "Denominator of the TSC ratio = %d\n", RegEax));
+ DEBUG ((DEBUG_INFO, "Numerator of the TSC ratio = %d\n", RegEbx));
+ DEBUG ((DEBUG_INFO, "Nominal frequency (hertz) = %d\n", RegEcx));
+
+ //
+ // If EBX returns 0, the XTAL ratio is not enumerated.
+ //
+ if (RegEbx == 0) {
+ DEBUG ((DEBUG_ERROR, "The CPU is not capble for Core Crystal Clock Frequency !!\n"));
+ ASSERT (RegEbx != 0);
+ }
+ //
+ // If ECX returns 0, the XTAL frequency is not enumerated.
+ //
+ if (RegEcx == 0) {
+ DEBUG ((DEBUG_ERROR, "The CPU is not capble for Core Crystal Clock Frequency !!\n"));
+ CoreXtalFrequency = PcdGet64 (PcdCpuCoreCrystalClockFrequency);
+ DEBUG ((DEBUG_INFO, "CoreXtalFrequency (hertz) from PCD = %d\n", CoreXtalFrequency));
+ //ASSERT (RegEcx != 0);
+ } else {
+ CoreXtalFrequency = (UINT64) RegEcx;
+ }
+
+ //
+ // Calculate TSC frequency = (ECX, Core Xtal Frequency) * EBX/EAX
+ //
+ TscFrequency = DivU64x32 (MultU64x32 (CoreXtalFrequency, RegEbx) + (UINT64)(RegEax >> 1), RegEax);
+
+ return TscFrequency;
+}
+
+/**
+ Stalls the CPU for at least the given number of ticks.
+
+ Stalls the CPU for at least the given number of ticks. It's invoked by
+ MicroSecondDelay() and NanoSecondDelay().
+
+ @param Delay A period of time to delay in ticks.
+
+**/
+VOID
+InternalCpuDelay (
+ IN UINT64 Delay
+ )
+{
+ UINT64 Ticks;
+
+ //
+ // The target timer count is calculated here
+ //
+ Ticks = AsmReadTsc() + Delay;
+
+ //
+ // Wait until time out
+ // Timer wrap-arounds are NOT handled correctly by this function.
+ // Thus, this function must be called within 10 years of reset since
+ // Intel guarantees a minimum of 10 years before the TSC wraps.
+ //
+ while (AsmReadTsc() <= Ticks) {
+ CpuPause();
+ }
+}
+
+/**
+ Stalls the CPU for at least the given number of microseconds.
+
+ Stalls the CPU for the number of microseconds specified by MicroSeconds.
+
+ @param[in] MicroSeconds The minimum number of microseconds to delay.
+
+ @return MicroSeconds
+
+**/
+UINTN
+EFIAPI
+MicroSecondDelay (
+ IN UINTN MicroSeconds
+ )
+{
+ DEBUG ((DEBUG_INFO, "MicroSecDelay = %d\n", MicroSeconds));
+
+ InternalCpuDelay (
+ DivU64x32 (
+ MultU64x64 (
+ MicroSeconds,
+ CpuidCoreClockCalculateTscFrequency ()
+ ),
+ 1000000u
+ )
+ );
+
+ return MicroSeconds;
+}
+
+/**
+ Stalls the CPU for at least the given number of nanoseconds.
+
+ Stalls the CPU for the number of nanoseconds specified by NanoSeconds.
+
+ @param NanoSeconds The minimum number of nanoseconds to delay.
+
+ @return NanoSeconds
+
+**/
+UINTN
+EFIAPI
+NanoSecondDelay (
+ IN UINTN NanoSeconds
+ )
+{
+ DEBUG ((DEBUG_INFO, "NanoSecDelay = %d\n", NanoSeconds));
+
+ InternalCpuDelay (
+ DivU64x32 (
+ MultU64x64 (
+ NanoSeconds,
+ CpuidCoreClockCalculateTscFrequency ()
+ ),
+ 1000000000u
+ )
+ );
+
+ return NanoSeconds;
+}
+
+/**
+ Retrieves the current value of a 64-bit free running performance counter.
+
+ Retrieves the current value of a 64-bit free running performance counter. The
+ counter can either count up by 1 or count down by 1. If the physical
+ performance counter counts by a larger increment, then the counter values
+ must be translated. The properties of the counter can be retrieved from
+ GetPerformanceCounterProperties().
+
+ @return The current value of the free running performance counter.
+
+**/
+UINT64
+EFIAPI
+GetPerformanceCounter (
+ VOID
+ )
+{
+ return AsmReadTsc ();
+}
+
+/**
+ Retrieves the 64-bit frequency in Hz and the range of performance counter
+ values.
+
+ If StartValue is not NULL, then the value that the performance counter starts
+ with immediately after is it rolls over is returned in StartValue. If
+ EndValue is not NULL, then the value that the performance counter end with
+ immediately before it rolls over is returned in EndValue. The 64-bit
+ frequency of the performance counter in Hz is always returned. If StartValue
+ is less than EndValue, then the performance counter counts up. If StartValue
+ is greater than EndValue, then the performance counter counts down. For
+ example, a 64-bit free running counter that counts up would have a StartValue
+ of 0 and an EndValue of 0xFFFFFFFFFFFFFFFF. A 24-bit free running counter
+ that counts down would have a StartValue of 0xFFFFFF and an EndValue of 0.
+
+ @param StartValue The value the performance counter starts with when it
+ rolls over.
+ @param EndValue The value that the performance counter ends with before
+ it rolls over.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+EFIAPI
+GetPerformanceCounterProperties (
+ OUT UINT64 *StartValue, OPTIONAL
+ OUT UINT64 *EndValue OPTIONAL
+ )
+{
+ if (StartValue != NULL) {
+ *StartValue = 0;
+ }
+
+ if (EndValue != NULL) {
+ *EndValue = 0xffffffffffffffffULL;
+ }
+ return InternalGetPerformanceCounterFrequency ();
+}
+
+/**
+ Converts elapsed ticks of performance counter to time in nanoseconds.
+
+ This function converts the elapsed ticks of running performance counter to
+ time value in unit of nanoseconds.
+
+ @param Ticks The number of elapsed ticks of running performance counter.
+
+ @return The elapsed time in nanoseconds.
+
+**/
+UINT64
+EFIAPI
+GetTimeInNanoSecond (
+ IN UINT64 Ticks
+ )
+{
+ UINT64 Frequency;
+ UINT64 NanoSeconds;
+ UINT64 Remainder;
+ INTN Shift;
+
+ Frequency = GetPerformanceCounterProperties (NULL, NULL);
+
+ //
+ // Ticks
+ // Time = --------- x 1,000,000,000
+ // Frequency
+ //
+ NanoSeconds = MultU64x32 (DivU64x64Remainder (Ticks, Frequency, &Remainder), 1000000000u);
+
+ //
+ // Ensure (Remainder * 1,000,000,000) will not overflow 64-bit.
+ // Since 2^29 < 1,000,000,000 = 0x3B9ACA00 < 2^30, Remainder should < 2^(64-30) = 2^34,
+ // i.e. highest bit set in Remainder should <= 33.
+ //
+ Shift = MAX (0, HighBitSet64 (Remainder) - 33);
+ Remainder = RShiftU64 (Remainder, (UINTN) Shift);
+ Frequency = RShiftU64 (Frequency, (UINTN) Shift);
+ NanoSeconds += DivU64x64Remainder (MultU64x32 (Remainder, 1000000000u), Frequency, NULL);
+
+ return NanoSeconds;
+}
+
diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec
index 14ddaa8633..a94bd2ea30 100644
--- a/UefiCpuPkg/UefiCpuPkg.dec
+++ b/UefiCpuPkg/UefiCpuPkg.dec
@@ -211,6 +211,14 @@
# @Prompt If CPU features will be initialized during S3 resume.
gUefiCpuPkgTokenSpaceGuid.PcdCpuFeaturesInitOnS3Resume|FALSE|BOOLEAN|0x0000001D

+ ## Specifies CPUID Leaf 0x15 Time Stamp Counter and Nominal Core Crystal Clock Frequency.
+ # TSC Frequency = ECX (core crystal clock frequency) * EBX/EAX.
+ # Intel Xeon Processor Scalable Family with CPUID signature 06_55H = 25000000 (25MHz)
+ # 6th and 7th generation Intel Core processors and Intel Xeon W Processor Family = 24000000 (24MHz)
+ # Intel Atom processors based on Goldmont Microarchitecture with CPUID signature 06_5CH = 19200000 (19.2MHz)
+ # @Prompt Core Crystal Clock Frequency is for CPUID Leaf 0x15.ECX
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuCoreCrystalClockFrequency|24000000|UINT64|0x32132113
+
[PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
## Specifies max supported number of Logical Processors.
# @Prompt Configure max supported number of Logical Processors
diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc
index bf690d3978..2d4eb931e1 100644
--- a/UefiCpuPkg/UefiCpuPkg.dsc
+++ b/UefiCpuPkg/UefiCpuPkg.dsc
@@ -42,7 +42,7 @@
PeimEntryPoint|MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf
PeiServicesLib|MdePkg/Library/PeiServicesLib/PeiServicesLib.inf
PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf
- TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf
+# TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf
DebugAgentLib|MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf
LocalApicLib|UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.inf
ReportStatusCodeLib|MdePkg/Library/BaseReportStatusCodeLibNull/BaseReportStatusCodeLibNull.inf
@@ -56,6 +56,7 @@
PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf
PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf
TpmMeasurementLib|MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf
+ TimerLib|UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.inf

[LibraryClasses.common.SEC]
PlatformSecLib|UefiCpuPkg/Library/PlatformSecLibNull/PlatformSecLibNull.inf
@@ -143,6 +144,7 @@
SmmCpuFeaturesLib|UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLibStm.inf
}
UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume2Pei.inf
+ UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.inf

[BuildOptions]
*_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES
--
2.14.2.windows.3

Donald Kuo
 

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=1909

Cc: Ray Ni <ray.ni@...>
Cc: Star Zeng <star.zeng@...>
Cc: Eric Dong <eric.dong@...>
Signed-off-by: Donald Kuo <donald.kuo@...>
---
.../Library/BaseCpuTimerLib/BaseCpuTimerLib.c | 40 +++
.../Library/BaseCpuTimerLib/BaseCpuTimerLib.inf | 35 +++
.../Library/BaseCpuTimerLib/BaseCpuTimerLib.uni | 17 ++
UefiCpuPkg/Library/BaseCpuTimerLib/CpuTimerLib.c | 290 +++++++++++++++++++++
UefiCpuPkg/UefiCpuPkg.dec | 8 +
UefiCpuPkg/UefiCpuPkg.dsc | 4 +-
6 files changed, 393 insertions(+), 1 deletion(-)
create mode 100644 UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.c
create mode 100644 UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.inf
create mode 100644 UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.uni
create mode 100644 UefiCpuPkg/Library/BaseCpuTimerLib/CpuTimerLib.c

diff --git a/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.c b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.c
new file mode 100644
index 0000000000..ccb92a95d3
--- /dev/null
+++ b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.c
@@ -0,0 +1,40 @@
+/** @file
+ CPUID Leaf 0x15 for Core Crystal Clock frequency instance of Timer Library.
+
+ Copyright (c) 2019 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+
+/**
+ CPUID Leaf 0x15 for Core Crystal Clock Frequency.
+
+ The TSC counting frequency is determined by using CPUID leaf 0x15. Frequency in MHz = Core XTAL frequency * EBX/EAX.
+ In newer flavors of the CPU, core xtal frequency is returned in ECX or 0 if not supported.
+ @return The number of TSC counts per second.
+
+**/
+UINT64
+CpuidCoreClockCalculateTscFrequency (
+ VOID
+ );
+
+/**
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+InternalGetPerformanceCounterFrequency (
+ VOID
+ )
+{
+ return CpuidCoreClockCalculateTscFrequency ();
+}
diff --git a/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.inf b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.inf
new file mode 100644
index 0000000000..c31dacd57a
--- /dev/null
+++ b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.inf
@@ -0,0 +1,35 @@
+## @file
+# Base CPU Timer Library
+#
+# Provides basic timer support using CPUID Leaf 0x15 XTAL frequency. The performance
+# counter features are provided by the processors time stamp counter.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = BaseCpuTimerLib
+ FILE_GUID = F10B5B91-D15A-496C-B044-B5235721AA08
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = TimerLib
+ MODULE_UNI_FILE = BaseCpuTimerLib.uni
+
+[Sources]
+ CpuTimerLib.c
+ BaseCpuTimerLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ PcdLib
+ DebugLib
+
+[Pcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuCoreCrystalClockFrequency ## CONSUMES
\ No newline at end of file
diff --git a/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.uni b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.uni
new file mode 100644
index 0000000000..fcf2b0fbcb
--- /dev/null
+++ b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.uni
@@ -0,0 +1,17 @@
+// /** @file
+// Base CPU Timer Library
+//
+// Provides basic timer support using CPUID Leaf 0x15 XTAL frequency. The performance
+// counter features are provided by the processors time stamp counter.
+//
+// Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "CPU Timer Library"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Provides basic timer support using CPUID Leaf 0x15 XTAL frequency."
+
diff --git a/UefiCpuPkg/Library/BaseCpuTimerLib/CpuTimerLib.c b/UefiCpuPkg/Library/BaseCpuTimerLib/CpuTimerLib.c
new file mode 100644
index 0000000000..5ed01146cf
--- /dev/null
+++ b/UefiCpuPkg/Library/BaseCpuTimerLib/CpuTimerLib.c
@@ -0,0 +1,290 @@
+/** @file
+ CPUID Leaf 0x15 for Core Crystal Clock frequency instance of Timer Library.
+
+ Copyright (c) 2019 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DebugLib.h>
+#include <Register/Cpuid.h>
+
+/**
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+InternalGetPerformanceCounterFrequency (
+ VOID
+ );
+
+/**
+ CPUID Leaf 0x15 for Core Crystal Clock Frequency.
+
+ The TSC counting frequency is determined by using CPUID leaf 0x15. Frequency in MHz = Core XTAL frequency * EBX/EAX.
+ In newer flavors of the CPU, core xtal frequency is returned in ECX or 0 if not supported.
+ @return The number of TSC counts per second.
+
+**/
+UINT64
+CpuidCoreClockCalculateTscFrequency (
+ VOID
+ )
+{
+ CPUID_VERSION_INFO_EAX Eax;
+ UINT64 TscFrequency;
+ UINT64 CoreXtalFrequency;
+ UINT32 RegEax;
+ UINT32 RegEbx;
+ UINT32 RegEcx;
+
+ //
+ // Display CPU FAMILY / MODEL / STEPPING ID Info
+ //
+ AsmCpuid (CPUID_VERSION_INFO, &Eax.Uint32, NULL, NULL, NULL);
+ DEBUG ((DEBUG_INFO, "CPUID = %X\n", (Eax.Uint32 & 0x0FFF0FFF)));
+
+ //
+ // Use CPUID leaf 0x15 Time Stamp Counter and Nominal Core Crystal Clock Information
+ // EBX returns 0 if not supported. ECX, if non zero, provides Core Xtal Frequency in hertz.
+ // TSC frequency = (ECX, Core Xtal Frequency) * EBX/EAX.
+ //
+ AsmCpuid (CPUID_TIME_STAMP_COUNTER, &RegEax, &RegEbx, &RegEcx, NULL);
+ DEBUG ((DEBUG_INFO, "Denominator of the TSC ratio = %d\n", RegEax));
+ DEBUG ((DEBUG_INFO, "Numerator of the TSC ratio = %d\n", RegEbx));
+ DEBUG ((DEBUG_INFO, "Nominal frequency (hertz) = %d\n", RegEcx));
+
+ //
+ // If EBX returns 0, the XTAL ratio is not enumerated.
+ //
+ if (RegEbx == 0) {
+ DEBUG ((DEBUG_ERROR, "The CPU is not capble for Core Crystal Clock Frequency !!\n"));
+ ASSERT (RegEbx != 0);
+ }
+ //
+ // If ECX returns 0, the XTAL frequency is not enumerated.
+ //
+ if (RegEcx == 0) {
+ DEBUG ((DEBUG_ERROR, "The CPU is not capble for Core Crystal Clock Frequency !!\n"));
+ CoreXtalFrequency = PcdGet64 (PcdCpuCoreCrystalClockFrequency);
+ DEBUG ((DEBUG_INFO, "CoreXtalFrequency (hertz) from PCD = %d\n", CoreXtalFrequency));
+ //ASSERT (RegEcx != 0);
+ } else {
+ CoreXtalFrequency = (UINT64) RegEcx;
+ }
+
+ //
+ // Calculate TSC frequency = (ECX, Core Xtal Frequency) * EBX/EAX
+ //
+ TscFrequency = DivU64x32 (MultU64x32 (CoreXtalFrequency, RegEbx) + (UINT64)(RegEax >> 1), RegEax);
+
+ return TscFrequency;
+}
+
+/**
+ Stalls the CPU for at least the given number of ticks.
+
+ Stalls the CPU for at least the given number of ticks. It's invoked by
+ MicroSecondDelay() and NanoSecondDelay().
+
+ @param Delay A period of time to delay in ticks.
+
+**/
+VOID
+InternalCpuDelay (
+ IN UINT64 Delay
+ )
+{
+ UINT64 Ticks;
+
+ //
+ // The target timer count is calculated here
+ //
+ Ticks = AsmReadTsc() + Delay;
+
+ //
+ // Wait until time out
+ // Timer wrap-arounds are NOT handled correctly by this function.
+ // Thus, this function must be called within 10 years of reset since
+ // Intel guarantees a minimum of 10 years before the TSC wraps.
+ //
+ while (AsmReadTsc() <= Ticks) {
+ CpuPause();
+ }
+}
+
+/**
+ Stalls the CPU for at least the given number of microseconds.
+
+ Stalls the CPU for the number of microseconds specified by MicroSeconds.
+
+ @param[in] MicroSeconds The minimum number of microseconds to delay.
+
+ @return MicroSeconds
+
+**/
+UINTN
+EFIAPI
+MicroSecondDelay (
+ IN UINTN MicroSeconds
+ )
+{
+ DEBUG ((DEBUG_INFO, "MicroSecDelay = %d\n", MicroSeconds));
+
+ InternalCpuDelay (
+ DivU64x32 (
+ MultU64x64 (
+ MicroSeconds,
+ CpuidCoreClockCalculateTscFrequency ()
+ ),
+ 1000000u
+ )
+ );
+
+ return MicroSeconds;
+}
+
+/**
+ Stalls the CPU for at least the given number of nanoseconds.
+
+ Stalls the CPU for the number of nanoseconds specified by NanoSeconds.
+
+ @param NanoSeconds The minimum number of nanoseconds to delay.
+
+ @return NanoSeconds
+
+**/
+UINTN
+EFIAPI
+NanoSecondDelay (
+ IN UINTN NanoSeconds
+ )
+{
+ DEBUG ((DEBUG_INFO, "NanoSecDelay = %d\n", NanoSeconds));
+
+ InternalCpuDelay (
+ DivU64x32 (
+ MultU64x64 (
+ NanoSeconds,
+ CpuidCoreClockCalculateTscFrequency ()
+ ),
+ 1000000000u
+ )
+ );
+
+ return NanoSeconds;
+}
+
+/**
+ Retrieves the current value of a 64-bit free running performance counter.
+
+ Retrieves the current value of a 64-bit free running performance counter. The
+ counter can either count up by 1 or count down by 1. If the physical
+ performance counter counts by a larger increment, then the counter values
+ must be translated. The properties of the counter can be retrieved from
+ GetPerformanceCounterProperties().
+
+ @return The current value of the free running performance counter.
+
+**/
+UINT64
+EFIAPI
+GetPerformanceCounter (
+ VOID
+ )
+{
+ return AsmReadTsc ();
+}
+
+/**
+ Retrieves the 64-bit frequency in Hz and the range of performance counter
+ values.
+
+ If StartValue is not NULL, then the value that the performance counter starts
+ with immediately after is it rolls over is returned in StartValue. If
+ EndValue is not NULL, then the value that the performance counter end with
+ immediately before it rolls over is returned in EndValue. The 64-bit
+ frequency of the performance counter in Hz is always returned. If StartValue
+ is less than EndValue, then the performance counter counts up. If StartValue
+ is greater than EndValue, then the performance counter counts down. For
+ example, a 64-bit free running counter that counts up would have a StartValue
+ of 0 and an EndValue of 0xFFFFFFFFFFFFFFFF. A 24-bit free running counter
+ that counts down would have a StartValue of 0xFFFFFF and an EndValue of 0.
+
+ @param StartValue The value the performance counter starts with when it
+ rolls over.
+ @param EndValue The value that the performance counter ends with before
+ it rolls over.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+EFIAPI
+GetPerformanceCounterProperties (
+ OUT UINT64 *StartValue, OPTIONAL
+ OUT UINT64 *EndValue OPTIONAL
+ )
+{
+ if (StartValue != NULL) {
+ *StartValue = 0;
+ }
+
+ if (EndValue != NULL) {
+ *EndValue = 0xffffffffffffffffULL;
+ }
+ return InternalGetPerformanceCounterFrequency ();
+}
+
+/**
+ Converts elapsed ticks of performance counter to time in nanoseconds.
+
+ This function converts the elapsed ticks of running performance counter to
+ time value in unit of nanoseconds.
+
+ @param Ticks The number of elapsed ticks of running performance counter.
+
+ @return The elapsed time in nanoseconds.
+
+**/
+UINT64
+EFIAPI
+GetTimeInNanoSecond (
+ IN UINT64 Ticks
+ )
+{
+ UINT64 Frequency;
+ UINT64 NanoSeconds;
+ UINT64 Remainder;
+ INTN Shift;
+
+ Frequency = GetPerformanceCounterProperties (NULL, NULL);
+
+ //
+ // Ticks
+ // Time = --------- x 1,000,000,000
+ // Frequency
+ //
+ NanoSeconds = MultU64x32 (DivU64x64Remainder (Ticks, Frequency, &Remainder), 1000000000u);
+
+ //
+ // Ensure (Remainder * 1,000,000,000) will not overflow 64-bit.
+ // Since 2^29 < 1,000,000,000 = 0x3B9ACA00 < 2^30, Remainder should < 2^(64-30) = 2^34,
+ // i.e. highest bit set in Remainder should <= 33.
+ //
+ Shift = MAX (0, HighBitSet64 (Remainder) - 33);
+ Remainder = RShiftU64 (Remainder, (UINTN) Shift);
+ Frequency = RShiftU64 (Frequency, (UINTN) Shift);
+ NanoSeconds += DivU64x64Remainder (MultU64x32 (Remainder, 1000000000u), Frequency, NULL);
+
+ return NanoSeconds;
+}
+
diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec
index 14ddaa8633..a94bd2ea30 100644
--- a/UefiCpuPkg/UefiCpuPkg.dec
+++ b/UefiCpuPkg/UefiCpuPkg.dec
@@ -211,6 +211,14 @@
# @Prompt If CPU features will be initialized during S3 resume.
gUefiCpuPkgTokenSpaceGuid.PcdCpuFeaturesInitOnS3Resume|FALSE|BOOLEAN|0x0000001D

+ ## Specifies CPUID Leaf 0x15 Time Stamp Counter and Nominal Core Crystal Clock Frequency.
+ # TSC Frequency = ECX (core crystal clock frequency) * EBX/EAX.
+ # Intel Xeon Processor Scalable Family with CPUID signature 06_55H = 25000000 (25MHz)
+ # 6th and 7th generation Intel Core processors and Intel Xeon W Processor Family = 24000000 (24MHz)
+ # Intel Atom processors based on Goldmont Microarchitecture with CPUID signature 06_5CH = 19200000 (19.2MHz)
+ # @Prompt Core Crystal Clock Frequency is for CPUID Leaf 0x15.ECX
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuCoreCrystalClockFrequency|24000000|UINT64|0x32132113
+
[PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
## Specifies max supported number of Logical Processors.
# @Prompt Configure max supported number of Logical Processors
diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc
index bf690d3978..2d4eb931e1 100644
--- a/UefiCpuPkg/UefiCpuPkg.dsc
+++ b/UefiCpuPkg/UefiCpuPkg.dsc
@@ -42,7 +42,7 @@
PeimEntryPoint|MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf
PeiServicesLib|MdePkg/Library/PeiServicesLib/PeiServicesLib.inf
PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf
- TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf
+# TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf
DebugAgentLib|MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf
LocalApicLib|UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.inf
ReportStatusCodeLib|MdePkg/Library/BaseReportStatusCodeLibNull/BaseReportStatusCodeLibNull.inf
@@ -56,6 +56,7 @@
PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf
PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf
TpmMeasurementLib|MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf
+ TimerLib|UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.inf

[LibraryClasses.common.SEC]
PlatformSecLib|UefiCpuPkg/Library/PlatformSecLibNull/PlatformSecLibNull.inf
@@ -143,6 +144,7 @@
SmmCpuFeaturesLib|UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLibStm.inf
}
UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume2Pei.inf
+ UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.inf

[BuildOptions]
*_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES
--
2.14.2.windows.3

Donald Kuo
 

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=1909

Cc: Ray Ni <ray.ni@...>
Cc: Star Zeng <star.zeng@...>
Cc: Eric Dong <eric.dong@...>
Cc: Amy Chan <amy.chan@...>
Cc: Rangasai V Chaganty <rangasai.v.chaganty@...>
Signed-off-by: Donald Kuo <donald.kuo@...>
---
.../Library/BaseCpuTimerLib/BaseCpuTimerLib.c | 40 +++
.../Library/BaseCpuTimerLib/BaseCpuTimerLib.inf | 35 +++
.../Library/BaseCpuTimerLib/BaseCpuTimerLib.uni | 16 ++
UefiCpuPkg/Library/BaseCpuTimerLib/CpuTimerLib.c | 272 +++++++++++++++++++++
UefiCpuPkg/UefiCpuPkg.dec | 8 +
UefiCpuPkg/UefiCpuPkg.dsc | 1 +
6 files changed, 372 insertions(+)
create mode 100644 UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.c
create mode 100644 UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.inf
create mode 100644 UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.uni
create mode 100644 UefiCpuPkg/Library/BaseCpuTimerLib/CpuTimerLib.c

diff --git a/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.c b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.c
new file mode 100644
index 0000000000..ccb92a95d3
--- /dev/null
+++ b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.c
@@ -0,0 +1,40 @@
+/** @file
+ CPUID Leaf 0x15 for Core Crystal Clock frequency instance of Timer Library.
+
+ Copyright (c) 2019 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+
+/**
+ CPUID Leaf 0x15 for Core Crystal Clock Frequency.
+
+ The TSC counting frequency is determined by using CPUID leaf 0x15. Frequency in MHz = Core XTAL frequency * EBX/EAX.
+ In newer flavors of the CPU, core xtal frequency is returned in ECX or 0 if not supported.
+ @return The number of TSC counts per second.
+
+**/
+UINT64
+CpuidCoreClockCalculateTscFrequency (
+ VOID
+ );
+
+/**
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+InternalGetPerformanceCounterFrequency (
+ VOID
+ )
+{
+ return CpuidCoreClockCalculateTscFrequency ();
+}
diff --git a/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.inf b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.inf
new file mode 100644
index 0000000000..7e27a55c90
--- /dev/null
+++ b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.inf
@@ -0,0 +1,35 @@
+## @file
+# Base CPU Timer Library
+#
+# Provides basic timer support using CPUID Leaf 0x15 XTAL frequency. The performance
+# counter features are provided by the processors time stamp counter.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = BaseCpuTimerLib
+ FILE_GUID = F10B5B91-D15A-496C-B044-B5235721AA08
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = TimerLib
+ MODULE_UNI_FILE = BaseCpuTimerLib.uni
+
+[Sources]
+ CpuTimerLib.c
+ BaseCpuTimerLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ PcdLib
+ DebugLib
+
+[Pcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuCoreCrystalClockFrequency ## CONSUMES
diff --git a/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.uni b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.uni
new file mode 100644
index 0000000000..6e5c3ef70e
--- /dev/null
+++ b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.uni
@@ -0,0 +1,16 @@
+// /** @file
+// Base CPU Timer Library
+//
+// Provides basic timer support using CPUID Leaf 0x15 XTAL frequency. The performance
+// counter features are provided by the processors time stamp counter.
+//
+// Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "CPU Timer Library"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Provides basic timer support using CPUID Leaf 0x15 XTAL frequency."
diff --git a/UefiCpuPkg/Library/BaseCpuTimerLib/CpuTimerLib.c b/UefiCpuPkg/Library/BaseCpuTimerLib/CpuTimerLib.c
new file mode 100644
index 0000000000..39492acd8e
--- /dev/null
+++ b/UefiCpuPkg/Library/BaseCpuTimerLib/CpuTimerLib.c
@@ -0,0 +1,272 @@
+/** @file
+ CPUID Leaf 0x15 for Core Crystal Clock frequency instance of Timer Library.
+
+ Copyright (c) 2019 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DebugLib.h>
+#include <Register/Cpuid.h>
+
+/**
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+InternalGetPerformanceCounterFrequency (
+ VOID
+ );
+
+/**
+ CPUID Leaf 0x15 for Core Crystal Clock Frequency.
+
+ The TSC counting frequency is determined by using CPUID leaf 0x15. Frequency in MHz = Core XTAL frequency * EBX/EAX.
+ In newer flavors of the CPU, core xtal frequency is returned in ECX or 0 if not supported.
+ @return The number of TSC counts per second.
+
+**/
+UINT64
+CpuidCoreClockCalculateTscFrequency (
+ VOID
+ )
+{
+ CPUID_VERSION_INFO_EAX Eax;
+ UINT64 TscFrequency;
+ UINT64 CoreXtalFrequency;
+ UINT32 RegEax;
+ UINT32 RegEbx;
+ UINT32 RegEcx;
+
+ //
+ // Use CPUID leaf 0x15 Time Stamp Counter and Nominal Core Crystal Clock Information
+ // EBX returns 0 if not supported. ECX, if non zero, provides Core Xtal Frequency in hertz.
+ // TSC frequency = (ECX, Core Xtal Frequency) * EBX/EAX.
+ //
+ AsmCpuid (CPUID_TIME_STAMP_COUNTER, &RegEax, &RegEbx, &RegEcx, NULL);
+
+ //
+ // If EBX returns 0, the XTAL ratio is not enumerated.
+ //
+ ASSERT (RegEbx != 0);
+ //
+ // If ECX returns 0, the XTAL frequency is not enumerated.
+ //
+ if (RegEcx == 0) {
+ CoreXtalFrequency = PcdGet64 (PcdCpuCoreCrystalClockFrequency);
+ } else {
+ CoreXtalFrequency = (UINT64) RegEcx;
+ }
+
+ //
+ // Calculate TSC frequency = (ECX, Core Xtal Frequency) * EBX/EAX
+ //
+ TscFrequency = DivU64x32 (MultU64x32 (CoreXtalFrequency, RegEbx) + (UINT64)(RegEax >> 1), RegEax);
+
+ return TscFrequency;
+}
+
+/**
+ Stalls the CPU for at least the given number of ticks.
+
+ Stalls the CPU for at least the given number of ticks. It's invoked by
+ MicroSecondDelay() and NanoSecondDelay().
+
+ @param Delay A period of time to delay in ticks.
+
+**/
+VOID
+InternalCpuDelay (
+ IN UINT64 Delay
+ )
+{
+ UINT64 Ticks;
+
+ //
+ // The target timer count is calculated here
+ //
+ Ticks = AsmReadTsc() + Delay;
+
+ //
+ // Wait until time out
+ // Timer wrap-arounds are NOT handled correctly by this function.
+ // Thus, this function must be called within 10 years of reset since
+ // Intel guarantees a minimum of 10 years before the TSC wraps.
+ //
+ while (AsmReadTsc() <= Ticks) {
+ CpuPause();
+ }
+}
+
+/**
+ Stalls the CPU for at least the given number of microseconds.
+
+ Stalls the CPU for the number of microseconds specified by MicroSeconds.
+
+ @param[in] MicroSeconds The minimum number of microseconds to delay.
+
+ @return MicroSeconds
+
+**/
+UINTN
+EFIAPI
+MicroSecondDelay (
+ IN UINTN MicroSeconds
+ )
+{
+
+ InternalCpuDelay (
+ DivU64x32 (
+ MultU64x64 (
+ MicroSeconds,
+ CpuidCoreClockCalculateTscFrequency ()
+ ),
+ 1000000u
+ )
+ );
+
+ return MicroSeconds;
+}
+
+/**
+ Stalls the CPU for at least the given number of nanoseconds.
+
+ Stalls the CPU for the number of nanoseconds specified by NanoSeconds.
+
+ @param NanoSeconds The minimum number of nanoseconds to delay.
+
+ @return NanoSeconds
+
+**/
+UINTN
+EFIAPI
+NanoSecondDelay (
+ IN UINTN NanoSeconds
+ )
+{
+
+ InternalCpuDelay (
+ DivU64x32 (
+ MultU64x64 (
+ NanoSeconds,
+ CpuidCoreClockCalculateTscFrequency ()
+ ),
+ 1000000000u
+ )
+ );
+
+ return NanoSeconds;
+}
+
+/**
+ Retrieves the current value of a 64-bit free running performance counter.
+
+ Retrieves the current value of a 64-bit free running performance counter. The
+ counter can either count up by 1 or count down by 1. If the physical
+ performance counter counts by a larger increment, then the counter values
+ must be translated. The properties of the counter can be retrieved from
+ GetPerformanceCounterProperties().
+
+ @return The current value of the free running performance counter.
+
+**/
+UINT64
+EFIAPI
+GetPerformanceCounter (
+ VOID
+ )
+{
+ return AsmReadTsc ();
+}
+
+/**
+ Retrieves the 64-bit frequency in Hz and the range of performance counter
+ values.
+
+ If StartValue is not NULL, then the value that the performance counter starts
+ with immediately after is it rolls over is returned in StartValue. If
+ EndValue is not NULL, then the value that the performance counter end with
+ immediately before it rolls over is returned in EndValue. The 64-bit
+ frequency of the performance counter in Hz is always returned. If StartValue
+ is less than EndValue, then the performance counter counts up. If StartValue
+ is greater than EndValue, then the performance counter counts down. For
+ example, a 64-bit free running counter that counts up would have a StartValue
+ of 0 and an EndValue of 0xFFFFFFFFFFFFFFFF. A 24-bit free running counter
+ that counts down would have a StartValue of 0xFFFFFF and an EndValue of 0.
+
+ @param StartValue The value the performance counter starts with when it
+ rolls over.
+ @param EndValue The value that the performance counter ends with before
+ it rolls over.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+EFIAPI
+GetPerformanceCounterProperties (
+ OUT UINT64 *StartValue, OPTIONAL
+ OUT UINT64 *EndValue OPTIONAL
+ )
+{
+ if (StartValue != NULL) {
+ *StartValue = 0;
+ }
+
+ if (EndValue != NULL) {
+ *EndValue = 0xffffffffffffffffULL;
+ }
+ return InternalGetPerformanceCounterFrequency ();
+}
+
+/**
+ Converts elapsed ticks of performance counter to time in nanoseconds.
+
+ This function converts the elapsed ticks of running performance counter to
+ time value in unit of nanoseconds.
+
+ @param Ticks The number of elapsed ticks of running performance counter.
+
+ @return The elapsed time in nanoseconds.
+
+**/
+UINT64
+EFIAPI
+GetTimeInNanoSecond (
+ IN UINT64 Ticks
+ )
+{
+ UINT64 Frequency;
+ UINT64 NanoSeconds;
+ UINT64 Remainder;
+ INTN Shift;
+
+ Frequency = GetPerformanceCounterProperties (NULL, NULL);
+
+ //
+ // Ticks
+ // Time = --------- x 1,000,000,000
+ // Frequency
+ //
+ NanoSeconds = MultU64x32 (DivU64x64Remainder (Ticks, Frequency, &Remainder), 1000000000u);
+
+ //
+ // Ensure (Remainder * 1,000,000,000) will not overflow 64-bit.
+ // Since 2^29 < 1,000,000,000 = 0x3B9ACA00 < 2^30, Remainder should < 2^(64-30) = 2^34,
+ // i.e. highest bit set in Remainder should <= 33.
+ //
+ Shift = MAX (0, HighBitSet64 (Remainder) - 33);
+ Remainder = RShiftU64 (Remainder, (UINTN) Shift);
+ Frequency = RShiftU64 (Frequency, (UINTN) Shift);
+ NanoSeconds += DivU64x64Remainder (MultU64x32 (Remainder, 1000000000u), Frequency, NULL);
+
+ return NanoSeconds;
+}
diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec
index 14ddaa8633..a94bd2ea30 100644
--- a/UefiCpuPkg/UefiCpuPkg.dec
+++ b/UefiCpuPkg/UefiCpuPkg.dec
@@ -211,6 +211,14 @@
# @Prompt If CPU features will be initialized during S3 resume.
gUefiCpuPkgTokenSpaceGuid.PcdCpuFeaturesInitOnS3Resume|FALSE|BOOLEAN|0x0000001D

+ ## Specifies CPUID Leaf 0x15 Time Stamp Counter and Nominal Core Crystal Clock Frequency.
+ # TSC Frequency = ECX (core crystal clock frequency) * EBX/EAX.
+ # Intel Xeon Processor Scalable Family with CPUID signature 06_55H = 25000000 (25MHz)
+ # 6th and 7th generation Intel Core processors and Intel Xeon W Processor Family = 24000000 (24MHz)
+ # Intel Atom processors based on Goldmont Microarchitecture with CPUID signature 06_5CH = 19200000 (19.2MHz)
+ # @Prompt Core Crystal Clock Frequency is for CPUID Leaf 0x15.ECX
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuCoreCrystalClockFrequency|24000000|UINT64|0x32132113
+
[PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
## Specifies max supported number of Logical Processors.
# @Prompt Configure max supported number of Logical Processors
diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc
index bf690d3978..e1337c741b 100644
--- a/UefiCpuPkg/UefiCpuPkg.dsc
+++ b/UefiCpuPkg/UefiCpuPkg.dsc
@@ -143,6 +143,7 @@
SmmCpuFeaturesLib|UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLibStm.inf
}
UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume2Pei.inf
+ UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.inf

[BuildOptions]
*_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES
--
2.14.2.windows.3

Dong, Eric
 

Hi Donald,

Do you think it's necessary to check the TIME_STAMP_COUNTER capability before using it? I see SDM has CPUID(0x01) which return the capability of TIME_STAMP_COUNTER.

Thanks,
Eric

-----Original Message-----
From: Kuo, Donald
Sent: Monday, August 12, 2019 7:23 PM
To: devel@edk2.groups.io
Cc: Ni, Ray <ray.ni@...>; Zeng, Star <star.zeng@...>; Dong, Eric
<eric.dong@...>; Chan, Amy <amy.chan@...>; Chaganty,
Rangasai V <rangasai.v.chaganty@...>
Subject: [PATCH] UefiCpuPkg: Adding a new TSC library by using CPUID(0x15)
TSC leaf

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=1909

Cc: Ray Ni <ray.ni@...>
Cc: Star Zeng <star.zeng@...>
Cc: Eric Dong <eric.dong@...>
Cc: Amy Chan <amy.chan@...>
Cc: Rangasai V Chaganty <rangasai.v.chaganty@...>
Signed-off-by: Donald Kuo <donald.kuo@...>
---
.../Library/BaseCpuTimerLib/BaseCpuTimerLib.c | 40 +++
.../Library/BaseCpuTimerLib/BaseCpuTimerLib.inf | 35 +++
.../Library/BaseCpuTimerLib/BaseCpuTimerLib.uni | 16 ++
UefiCpuPkg/Library/BaseCpuTimerLib/CpuTimerLib.c | 272
+++++++++++++++++++++
UefiCpuPkg/UefiCpuPkg.dec | 8 +
UefiCpuPkg/UefiCpuPkg.dsc | 1 +
6 files changed, 372 insertions(+)
create mode 100644
UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.c
create mode 100644
UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.inf
create mode 100644
UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.uni
create mode 100644 UefiCpuPkg/Library/BaseCpuTimerLib/CpuTimerLib.c

diff --git a/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.c
b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.c
new file mode 100644
index 0000000000..ccb92a95d3
--- /dev/null
+++ b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.c
@@ -0,0 +1,40 @@
+/** @file
+ CPUID Leaf 0x15 for Core Crystal Clock frequency instance of Timer Library.
+
+ Copyright (c) 2019 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+
+/**
+ CPUID Leaf 0x15 for Core Crystal Clock Frequency.
+
+ The TSC counting frequency is determined by using CPUID leaf 0x15.
Frequency in MHz = Core XTAL frequency * EBX/EAX.
+ In newer flavors of the CPU, core xtal frequency is returned in ECX or 0 if
not supported.
+ @return The number of TSC counts per second.
+
+**/
+UINT64
+CpuidCoreClockCalculateTscFrequency (
+ VOID
+ );
+
+/**
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+InternalGetPerformanceCounterFrequency (
+ VOID
+ )
+{
+ return CpuidCoreClockCalculateTscFrequency (); }
diff --git a/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.inf
b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.inf
new file mode 100644
index 0000000000..7e27a55c90
--- /dev/null
+++ b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.inf
@@ -0,0 +1,35 @@
+## @file
+# Base CPU Timer Library
+#
+# Provides basic timer support using CPUID Leaf 0x15 XTAL frequency.
+The performance # counter features are provided by the processors time
stamp counter.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR> #
+SPDX-License-Identifier: BSD-2-Clause-Patent # ##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = BaseCpuTimerLib
+ FILE_GUID = F10B5B91-D15A-496C-B044-B5235721AA08
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = TimerLib
+ MODULE_UNI_FILE = BaseCpuTimerLib.uni
+
+[Sources]
+ CpuTimerLib.c
+ BaseCpuTimerLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ PcdLib
+ DebugLib
+
+[Pcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuCoreCrystalClockFrequency ##
+CONSUMES
diff --git a/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.uni
b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.uni
new file mode 100644
index 0000000000..6e5c3ef70e
--- /dev/null
+++ b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.uni
@@ -0,0 +1,16 @@
+// /** @file
+// Base CPU Timer Library
+//
+// Provides basic timer support using CPUID Leaf 0x15 XTAL frequency.
+The performance // counter features are provided by the processors time
stamp counter.
+//
+// Copyright (c) 2019, Intel Corporation. All rights reserved.<BR> //
+// SPDX-License-Identifier: BSD-2-Clause-Patent // // **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "CPU Timer
Library"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Provides basic
timer support using CPUID Leaf 0x15 XTAL frequency."
diff --git a/UefiCpuPkg/Library/BaseCpuTimerLib/CpuTimerLib.c
b/UefiCpuPkg/Library/BaseCpuTimerLib/CpuTimerLib.c
new file mode 100644
index 0000000000..39492acd8e
--- /dev/null
+++ b/UefiCpuPkg/Library/BaseCpuTimerLib/CpuTimerLib.c
@@ -0,0 +1,272 @@
+/** @file
+ CPUID Leaf 0x15 for Core Crystal Clock frequency instance of Timer Library.
+
+ Copyright (c) 2019 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DebugLib.h>
+#include <Register/Cpuid.h>
+
+/**
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+InternalGetPerformanceCounterFrequency (
+ VOID
+ );
+
+/**
+ CPUID Leaf 0x15 for Core Crystal Clock Frequency.
+
+ The TSC counting frequency is determined by using CPUID leaf 0x15.
Frequency in MHz = Core XTAL frequency * EBX/EAX.
+ In newer flavors of the CPU, core xtal frequency is returned in ECX or 0 if
not supported.
+ @return The number of TSC counts per second.
+
+**/
+UINT64
+CpuidCoreClockCalculateTscFrequency (
+ VOID
+ )
+{
+ CPUID_VERSION_INFO_EAX Eax;
+ UINT64 TscFrequency;
+ UINT64 CoreXtalFrequency;
+ UINT32 RegEax;
+ UINT32 RegEbx;
+ UINT32 RegEcx;
+
+ //
+ // Use CPUID leaf 0x15 Time Stamp Counter and Nominal Core Crystal
+ Clock Information // EBX returns 0 if not supported. ECX, if non zero,
provides Core Xtal Frequency in hertz.
+ // TSC frequency = (ECX, Core Xtal Frequency) * EBX/EAX.
+ //
+ AsmCpuid (CPUID_TIME_STAMP_COUNTER, &RegEax, &RegEbx, &RegEcx,
NULL);
+
+ //
+ // If EBX returns 0, the XTAL ratio is not enumerated.
+ //
+ ASSERT (RegEbx != 0);
+ //
+ // If ECX returns 0, the XTAL frequency is not enumerated.
+ //
+ if (RegEcx == 0) {
+ CoreXtalFrequency = PcdGet64 (PcdCpuCoreCrystalClockFrequency);
+ } else {
+ CoreXtalFrequency = (UINT64) RegEcx; }
+
+ //
+ // Calculate TSC frequency = (ECX, Core Xtal Frequency) * EBX/EAX //
+ TscFrequency = DivU64x32 (MultU64x32 (CoreXtalFrequency, RegEbx) +
+ (UINT64)(RegEax >> 1), RegEax);
+
+ return TscFrequency;
+}
+
+/**
+ Stalls the CPU for at least the given number of ticks.
+
+ Stalls the CPU for at least the given number of ticks. It's invoked
+ by
+ MicroSecondDelay() and NanoSecondDelay().
+
+ @param Delay A period of time to delay in ticks.
+
+**/
+VOID
+InternalCpuDelay (
+ IN UINT64 Delay
+ )
+{
+ UINT64 Ticks;
+
+ //
+ // The target timer count is calculated here // Ticks =
+ AsmReadTsc() + Delay;
+
+ //
+ // Wait until time out
+ // Timer wrap-arounds are NOT handled correctly by this function.
+ // Thus, this function must be called within 10 years of reset since
+ // Intel guarantees a minimum of 10 years before the TSC wraps.
+ //
+ while (AsmReadTsc() <= Ticks) {
+ CpuPause();
+ }
+}
+
+/**
+ Stalls the CPU for at least the given number of microseconds.
+
+ Stalls the CPU for the number of microseconds specified by MicroSeconds.
+
+ @param[in] MicroSeconds The minimum number of microseconds to
delay.
+
+ @return MicroSeconds
+
+**/
+UINTN
+EFIAPI
+MicroSecondDelay (
+ IN UINTN MicroSeconds
+ )
+{
+
+ InternalCpuDelay (
+ DivU64x32 (
+ MultU64x64 (
+ MicroSeconds,
+ CpuidCoreClockCalculateTscFrequency ()
+ ),
+ 1000000u
+ )
+ );
+
+ return MicroSeconds;
+}
+
+/**
+ Stalls the CPU for at least the given number of nanoseconds.
+
+ Stalls the CPU for the number of nanoseconds specified by NanoSeconds.
+
+ @param NanoSeconds The minimum number of nanoseconds to delay.
+
+ @return NanoSeconds
+
+**/
+UINTN
+EFIAPI
+NanoSecondDelay (
+ IN UINTN NanoSeconds
+ )
+{
+
+ InternalCpuDelay (
+ DivU64x32 (
+ MultU64x64 (
+ NanoSeconds,
+ CpuidCoreClockCalculateTscFrequency ()
+ ),
+ 1000000000u
+ )
+ );
+
+ return NanoSeconds;
+}
+
+/**
+ Retrieves the current value of a 64-bit free running performance counter.
+
+ Retrieves the current value of a 64-bit free running performance
+ counter. The counter can either count up by 1 or count down by 1. If
+ the physical performance counter counts by a larger increment, then
+ the counter values must be translated. The properties of the counter
+ can be retrieved from GetPerformanceCounterProperties().
+
+ @return The current value of the free running performance counter.
+
+**/
+UINT64
+EFIAPI
+GetPerformanceCounter (
+ VOID
+ )
+{
+ return AsmReadTsc ();
+}
+
+/**
+ Retrieves the 64-bit frequency in Hz and the range of performance
+counter
+ values.
+
+ If StartValue is not NULL, then the value that the performance
+ counter starts with immediately after is it rolls over is returned in
+ StartValue. If EndValue is not NULL, then the value that the
+ performance counter end with immediately before it rolls over is
+ returned in EndValue. The 64-bit frequency of the performance counter
+ in Hz is always returned. If StartValue is less than EndValue, then
+ the performance counter counts up. If StartValue is greater than
+ EndValue, then the performance counter counts down. For example, a
+ 64-bit free running counter that counts up would have a StartValue of
+ 0 and an EndValue of 0xFFFFFFFFFFFFFFFF. A 24-bit free running counter
that counts down would have a StartValue of 0xFFFFFF and an EndValue of 0.
+
+ @param StartValue The value the performance counter starts with when
it
+ rolls over.
+ @param EndValue The value that the performance counter ends with
before
+ it rolls over.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+EFIAPI
+GetPerformanceCounterProperties (
+ OUT UINT64 *StartValue, OPTIONAL
+ OUT UINT64 *EndValue OPTIONAL
+ )
+{
+ if (StartValue != NULL) {
+ *StartValue = 0;
+ }
+
+ if (EndValue != NULL) {
+ *EndValue = 0xffffffffffffffffULL;
+ }
+ return InternalGetPerformanceCounterFrequency (); }
+
+/**
+ Converts elapsed ticks of performance counter to time in nanoseconds.
+
+ This function converts the elapsed ticks of running performance
+ counter to time value in unit of nanoseconds.
+
+ @param Ticks The number of elapsed ticks of running performance
counter.
+
+ @return The elapsed time in nanoseconds.
+
+**/
+UINT64
+EFIAPI
+GetTimeInNanoSecond (
+ IN UINT64 Ticks
+ )
+{
+ UINT64 Frequency;
+ UINT64 NanoSeconds;
+ UINT64 Remainder;
+ INTN Shift;
+
+ Frequency = GetPerformanceCounterProperties (NULL, NULL);
+
+ //
+ // Ticks
+ // Time = --------- x 1,000,000,000
+ // Frequency
+ //
+ NanoSeconds = MultU64x32 (DivU64x64Remainder (Ticks, Frequency,
+ &Remainder), 1000000000u);
+
+ //
+ // Ensure (Remainder * 1,000,000,000) will not overflow 64-bit.
+ // Since 2^29 < 1,000,000,000 = 0x3B9ACA00 < 2^30, Remainder should <
+ 2^(64-30) = 2^34, // i.e. highest bit set in Remainder should <= 33.
+ //
+ Shift = MAX (0, HighBitSet64 (Remainder) - 33); Remainder =
+ RShiftU64 (Remainder, (UINTN) Shift); Frequency = RShiftU64
+ (Frequency, (UINTN) Shift); NanoSeconds += DivU64x64Remainder
+ (MultU64x32 (Remainder, 1000000000u), Frequency, NULL);
+
+ return NanoSeconds;
+}
diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec
index 14ddaa8633..a94bd2ea30 100644
--- a/UefiCpuPkg/UefiCpuPkg.dec
+++ b/UefiCpuPkg/UefiCpuPkg.dec
@@ -211,6 +211,14 @@
# @Prompt If CPU features will be initialized during S3 resume.

gUefiCpuPkgTokenSpaceGuid.PcdCpuFeaturesInitOnS3Resume|FALSE|BOO
LEAN|0x0000001D

+ ## Specifies CPUID Leaf 0x15 Time Stamp Counter and Nominal Core
Crystal Clock Frequency.
+ # TSC Frequency = ECX (core crystal clock frequency) * EBX/EAX.
+ # Intel Xeon Processor Scalable Family with CPUID signature 06_55H =
25000000 (25MHz)
+ # 6th and 7th generation Intel Core processors and Intel Xeon W
Processor Family = 24000000 (24MHz)
+ # Intel Atom processors based on Goldmont Microarchitecture with
CPUID signature 06_5CH = 19200000 (19.2MHz)
+ # @Prompt Core Crystal Clock Frequency is for CPUID Leaf 0x15.ECX
+
+
gUefiCpuPkgTokenSpaceGuid.PcdCpuCoreCrystalClockFrequency|24000000|
UIN
+ T64|0x32132113
+
[PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
## Specifies max supported number of Logical Processors.
# @Prompt Configure max supported number of Logical Processors diff --git
a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc index
bf690d3978..e1337c741b 100644
--- a/UefiCpuPkg/UefiCpuPkg.dsc
+++ b/UefiCpuPkg/UefiCpuPkg.dsc
@@ -143,6 +143,7 @@

SmmCpuFeaturesLib|UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFea
turesLibStm.inf
}
UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume2Pei.inf
+ UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.inf

[BuildOptions]
*_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES
--
2.14.2.windows.3

Donald Kuo
 

Hi Eric,

The CPUID Leaf 0x1:EDX.TSC[bit 4] is to check capability for IA32_TIME_STAMP_COUNTER MSR and RDTSC instruction which defined in IA32 SDM chapter 17.17

And what we implement is based on IA32 SDM Chapter 18.7 for CPU core XTAL clock frequency which is from CPUID Leaf 0x15 and new TSC frequency = (ECX, Core XTAL Frequency) * EBX/EAX

So no need to check CPUID(0x01).

Thanks,
Donald

-----Original Message-----
From: Dong, Eric
Sent: Tuesday, August 13, 2019 10:27 AM
To: Kuo, Donald <donald.kuo@...>; devel@edk2.groups.io
Cc: Ni, Ray <ray.ni@...>; Zeng, Star <star.zeng@...>; Chan,
Amy <amy.chan@...>; Chaganty, Rangasai V
<rangasai.v.chaganty@...>
Subject: RE: [PATCH] UefiCpuPkg: Adding a new TSC library by using
CPUID(0x15) TSC leaf

Hi Donald,

Do you think it's necessary to check the TIME_STAMP_COUNTER capability
before using it? I see SDM has CPUID(0x01) which return the capability of
TIME_STAMP_COUNTER.

Thanks,
Eric

-----Original Message-----
From: Kuo, Donald
Sent: Monday, August 12, 2019 7:23 PM
To: devel@edk2.groups.io
Cc: Ni, Ray <ray.ni@...>; Zeng, Star <star.zeng@...>;
Dong, Eric <eric.dong@...>; Chan, Amy <amy.chan@...>;
Chaganty, Rangasai V <rangasai.v.chaganty@...>
Subject: [PATCH] UefiCpuPkg: Adding a new TSC library by using
CPUID(0x15) TSC leaf

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=1909

Cc: Ray Ni <ray.ni@...>
Cc: Star Zeng <star.zeng@...>
Cc: Eric Dong <eric.dong@...>
Cc: Amy Chan <amy.chan@...>
Cc: Rangasai V Chaganty <rangasai.v.chaganty@...>
Signed-off-by: Donald Kuo <donald.kuo@...>
---
.../Library/BaseCpuTimerLib/BaseCpuTimerLib.c | 40 +++
.../Library/BaseCpuTimerLib/BaseCpuTimerLib.inf | 35 +++
.../Library/BaseCpuTimerLib/BaseCpuTimerLib.uni | 16 ++
UefiCpuPkg/Library/BaseCpuTimerLib/CpuTimerLib.c | 272
+++++++++++++++++++++
UefiCpuPkg/UefiCpuPkg.dec | 8 +
UefiCpuPkg/UefiCpuPkg.dsc | 1 +
6 files changed, 372 insertions(+)
create mode 100644
UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.c
create mode 100644
UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.inf
create mode 100644
UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.uni
create mode 100644 UefiCpuPkg/Library/BaseCpuTimerLib/CpuTimerLib.c

diff --git a/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.c
b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.c
new file mode 100644
index 0000000000..ccb92a95d3
--- /dev/null
+++ b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.c
@@ -0,0 +1,40 @@
+/** @file
+ CPUID Leaf 0x15 for Core Crystal Clock frequency instance of Timer
Library.
+
+ Copyright (c) 2019 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+
+/**
+ CPUID Leaf 0x15 for Core Crystal Clock Frequency.
+
+ The TSC counting frequency is determined by using CPUID leaf 0x15.
Frequency in MHz = Core XTAL frequency * EBX/EAX.
+ In newer flavors of the CPU, core xtal frequency is returned in ECX
+ or 0 if
not supported.
+ @return The number of TSC counts per second.
+
+**/
+UINT64
+CpuidCoreClockCalculateTscFrequency (
+ VOID
+ );
+
+/**
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+InternalGetPerformanceCounterFrequency (
+ VOID
+ )
+{
+ return CpuidCoreClockCalculateTscFrequency (); }
diff --git a/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.inf
b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.inf
new file mode 100644
index 0000000000..7e27a55c90
--- /dev/null
+++ b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.inf
@@ -0,0 +1,35 @@
+## @file
+# Base CPU Timer Library
+#
+# Provides basic timer support using CPUID Leaf 0x15 XTAL frequency.
+The performance # counter features are provided by the processors
+time
stamp counter.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR> #
+SPDX-License-Identifier: BSD-2-Clause-Patent # ##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = BaseCpuTimerLib
+ FILE_GUID = F10B5B91-D15A-496C-B044-B5235721AA08
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = TimerLib
+ MODULE_UNI_FILE = BaseCpuTimerLib.uni
+
+[Sources]
+ CpuTimerLib.c
+ BaseCpuTimerLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ PcdLib
+ DebugLib
+
+[Pcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuCoreCrystalClockFrequency ##
+CONSUMES
diff --git a/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.uni
b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.uni
new file mode 100644
index 0000000000..6e5c3ef70e
--- /dev/null
+++ b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.uni
@@ -0,0 +1,16 @@
+// /** @file
+// Base CPU Timer Library
+//
+// Provides basic timer support using CPUID Leaf 0x15 XTAL frequency.
+The performance // counter features are provided by the processors
+time
stamp counter.
+//
+// Copyright (c) 2019, Intel Corporation. All rights reserved.<BR> //
+// SPDX-License-Identifier: BSD-2-Clause-Patent // // **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "CPU Timer
Library"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Provides
basic
timer support using CPUID Leaf 0x15 XTAL frequency."
diff --git a/UefiCpuPkg/Library/BaseCpuTimerLib/CpuTimerLib.c
b/UefiCpuPkg/Library/BaseCpuTimerLib/CpuTimerLib.c
new file mode 100644
index 0000000000..39492acd8e
--- /dev/null
+++ b/UefiCpuPkg/Library/BaseCpuTimerLib/CpuTimerLib.c
@@ -0,0 +1,272 @@
+/** @file
+ CPUID Leaf 0x15 for Core Crystal Clock frequency instance of Timer
Library.
+
+ Copyright (c) 2019 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DebugLib.h>
+#include <Register/Cpuid.h>
+
+/**
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+InternalGetPerformanceCounterFrequency (
+ VOID
+ );
+
+/**
+ CPUID Leaf 0x15 for Core Crystal Clock Frequency.
+
+ The TSC counting frequency is determined by using CPUID leaf 0x15.
Frequency in MHz = Core XTAL frequency * EBX/EAX.
+ In newer flavors of the CPU, core xtal frequency is returned in ECX
+ or 0 if
not supported.
+ @return The number of TSC counts per second.
+
+**/
+UINT64
+CpuidCoreClockCalculateTscFrequency (
+ VOID
+ )
+{
+ CPUID_VERSION_INFO_EAX Eax;
+ UINT64 TscFrequency;
+ UINT64 CoreXtalFrequency;
+ UINT32 RegEax;
+ UINT32 RegEbx;
+ UINT32 RegEcx;
+
+ //
+ // Use CPUID leaf 0x15 Time Stamp Counter and Nominal Core Crystal
+ Clock Information // EBX returns 0 if not supported. ECX, if non
+ zero,
provides Core Xtal Frequency in hertz.
+ // TSC frequency = (ECX, Core Xtal Frequency) * EBX/EAX.
+ //
+ AsmCpuid (CPUID_TIME_STAMP_COUNTER, &RegEax, &RegEbx,
&RegEcx,
NULL);
+
+ //
+ // If EBX returns 0, the XTAL ratio is not enumerated.
+ //
+ ASSERT (RegEbx != 0);
+ //
+ // If ECX returns 0, the XTAL frequency is not enumerated.
+ //
+ if (RegEcx == 0) {
+ CoreXtalFrequency = PcdGet64 (PcdCpuCoreCrystalClockFrequency);
+ } else {
+ CoreXtalFrequency = (UINT64) RegEcx; }
+
+ //
+ // Calculate TSC frequency = (ECX, Core Xtal Frequency) * EBX/EAX
+ // TscFrequency = DivU64x32 (MultU64x32 (CoreXtalFrequency, RegEbx)
+ + (UINT64)(RegEax >> 1), RegEax);
+
+ return TscFrequency;
+}
+
+/**
+ Stalls the CPU for at least the given number of ticks.
+
+ Stalls the CPU for at least the given number of ticks. It's invoked
+ by
+ MicroSecondDelay() and NanoSecondDelay().
+
+ @param Delay A period of time to delay in ticks.
+
+**/
+VOID
+InternalCpuDelay (
+ IN UINT64 Delay
+ )
+{
+ UINT64 Ticks;
+
+ //
+ // The target timer count is calculated here // Ticks =
+ AsmReadTsc() + Delay;
+
+ //
+ // Wait until time out
+ // Timer wrap-arounds are NOT handled correctly by this function.
+ // Thus, this function must be called within 10 years of reset
+since
+ // Intel guarantees a minimum of 10 years before the TSC wraps.
+ //
+ while (AsmReadTsc() <= Ticks) {
+ CpuPause();
+ }
+}
+
+/**
+ Stalls the CPU for at least the given number of microseconds.
+
+ Stalls the CPU for the number of microseconds specified by
MicroSeconds.
+
+ @param[in] MicroSeconds The minimum number of microseconds to
delay.
+
+ @return MicroSeconds
+
+**/
+UINTN
+EFIAPI
+MicroSecondDelay (
+ IN UINTN MicroSeconds
+ )
+{
+
+ InternalCpuDelay (
+ DivU64x32 (
+ MultU64x64 (
+ MicroSeconds,
+ CpuidCoreClockCalculateTscFrequency ()
+ ),
+ 1000000u
+ )
+ );
+
+ return MicroSeconds;
+}
+
+/**
+ Stalls the CPU for at least the given number of nanoseconds.
+
+ Stalls the CPU for the number of nanoseconds specified by NanoSeconds.
+
+ @param NanoSeconds The minimum number of nanoseconds to delay.
+
+ @return NanoSeconds
+
+**/
+UINTN
+EFIAPI
+NanoSecondDelay (
+ IN UINTN NanoSeconds
+ )
+{
+
+ InternalCpuDelay (
+ DivU64x32 (
+ MultU64x64 (
+ NanoSeconds,
+ CpuidCoreClockCalculateTscFrequency ()
+ ),
+ 1000000000u
+ )
+ );
+
+ return NanoSeconds;
+}
+
+/**
+ Retrieves the current value of a 64-bit free running performance counter.
+
+ Retrieves the current value of a 64-bit free running performance
+ counter. The counter can either count up by 1 or count down by 1.
+ If the physical performance counter counts by a larger increment,
+ then the counter values must be translated. The properties of the
+ counter can be retrieved from GetPerformanceCounterProperties().
+
+ @return The current value of the free running performance counter.
+
+**/
+UINT64
+EFIAPI
+GetPerformanceCounter (
+ VOID
+ )
+{
+ return AsmReadTsc ();
+}
+
+/**
+ Retrieves the 64-bit frequency in Hz and the range of performance
+counter
+ values.
+
+ If StartValue is not NULL, then the value that the performance
+ counter starts with immediately after is it rolls over is returned
+ in StartValue. If EndValue is not NULL, then the value that the
+ performance counter end with immediately before it rolls over is
+ returned in EndValue. The 64-bit frequency of the performance
+ counter in Hz is always returned. If StartValue is less than
+ EndValue, then the performance counter counts up. If StartValue is
+ greater than EndValue, then the performance counter counts down. For
+ example, a 64-bit free running counter that counts up would have a
+ StartValue of
+ 0 and an EndValue of 0xFFFFFFFFFFFFFFFF. A 24-bit free running
+ counter
that counts down would have a StartValue of 0xFFFFFF and an EndValue of
0.
+
+ @param StartValue The value the performance counter starts with
+ when
it
+ rolls over.
+ @param EndValue The value that the performance counter ends with
before
+ it rolls over.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+EFIAPI
+GetPerformanceCounterProperties (
+ OUT UINT64 *StartValue, OPTIONAL
+ OUT UINT64 *EndValue OPTIONAL
+ )
+{
+ if (StartValue != NULL) {
+ *StartValue = 0;
+ }
+
+ if (EndValue != NULL) {
+ *EndValue = 0xffffffffffffffffULL; } return
+ InternalGetPerformanceCounterFrequency (); }
+
+/**
+ Converts elapsed ticks of performance counter to time in nanoseconds.
+
+ This function converts the elapsed ticks of running performance
+ counter to time value in unit of nanoseconds.
+
+ @param Ticks The number of elapsed ticks of running performance
counter.
+
+ @return The elapsed time in nanoseconds.
+
+**/
+UINT64
+EFIAPI
+GetTimeInNanoSecond (
+ IN UINT64 Ticks
+ )
+{
+ UINT64 Frequency;
+ UINT64 NanoSeconds;
+ UINT64 Remainder;
+ INTN Shift;
+
+ Frequency = GetPerformanceCounterProperties (NULL, NULL);
+
+ //
+ // Ticks
+ // Time = --------- x 1,000,000,000
+ // Frequency
+ //
+ NanoSeconds = MultU64x32 (DivU64x64Remainder (Ticks, Frequency,
+ &Remainder), 1000000000u);
+
+ //
+ // Ensure (Remainder * 1,000,000,000) will not overflow 64-bit.
+ // Since 2^29 < 1,000,000,000 = 0x3B9ACA00 < 2^30, Remainder should
+ <
+ 2^(64-30) = 2^34, // i.e. highest bit set in Remainder should <= 33.
+ //
+ Shift = MAX (0, HighBitSet64 (Remainder) - 33); Remainder =
+ RShiftU64 (Remainder, (UINTN) Shift); Frequency = RShiftU64
+ (Frequency, (UINTN) Shift); NanoSeconds += DivU64x64Remainder
+ (MultU64x32 (Remainder, 1000000000u), Frequency, NULL);
+
+ return NanoSeconds;
+}
diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec
index 14ddaa8633..a94bd2ea30 100644
--- a/UefiCpuPkg/UefiCpuPkg.dec
+++ b/UefiCpuPkg/UefiCpuPkg.dec
@@ -211,6 +211,14 @@
# @Prompt If CPU features will be initialized during S3 resume.

gUefiCpuPkgTokenSpaceGuid.PcdCpuFeaturesInitOnS3Resume|FALSE|BOO
LEAN|0x0000001D

+ ## Specifies CPUID Leaf 0x15 Time Stamp Counter and Nominal Core
Crystal Clock Frequency.
+ # TSC Frequency = ECX (core crystal clock frequency) * EBX/EAX.
+ # Intel Xeon Processor Scalable Family with CPUID signature 06_55H =
25000000 (25MHz)
+ # 6th and 7th generation Intel Core processors and Intel Xeon W
Processor Family = 24000000 (24MHz)
+ # Intel Atom processors based on Goldmont Microarchitecture with
CPUID signature 06_5CH = 19200000 (19.2MHz)
+ # @Prompt Core Crystal Clock Frequency is for CPUID Leaf 0x15.ECX
+
+
gUefiCpuPkgTokenSpaceGuid.PcdCpuCoreCrystalClockFrequency|24000000|
UIN
+ T64|0x32132113
+
[PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
## Specifies max supported number of Logical Processors.
# @Prompt Configure max supported number of Logical Processors diff
--git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc index
bf690d3978..e1337c741b 100644
--- a/UefiCpuPkg/UefiCpuPkg.dsc
+++ b/UefiCpuPkg/UefiCpuPkg.dsc
@@ -143,6 +143,7 @@

SmmCpuFeaturesLib|UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFea
turesLibStm.inf
}
UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume2Pei.inf
+ UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.inf

[BuildOptions]
*_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES
--
2.14.2.windows.3

Dong, Eric
 

Hi Donald,

Thanks for your explanation. In this case, Reviewed-by: Eric Dong <eric.dong@...>

Thanks,
Eric

-----Original Message-----
From: Kuo, Donald
Sent: Tuesday, August 13, 2019 11:26 AM
To: Dong, Eric <eric.dong@...>; devel@edk2.groups.io
Cc: Ni, Ray <ray.ni@...>; Zeng, Star <star.zeng@...>; Chan,
Amy <amy.chan@...>; Chaganty, Rangasai V
<rangasai.v.chaganty@...>
Subject: RE: [PATCH] UefiCpuPkg: Adding a new TSC library by using
CPUID(0x15) TSC leaf

Hi Eric,

The CPUID Leaf 0x1:EDX.TSC[bit 4] is to check capability for
IA32_TIME_STAMP_COUNTER MSR and RDTSC instruction which defined in
IA32 SDM chapter 17.17

And what we implement is based on IA32 SDM Chapter 18.7 for CPU core
XTAL clock frequency which is from CPUID Leaf 0x15 and new TSC frequency
= (ECX, Core XTAL Frequency) * EBX/EAX

So no need to check CPUID(0x01).

Thanks,
Donald

-----Original Message-----
From: Dong, Eric
Sent: Tuesday, August 13, 2019 10:27 AM
To: Kuo, Donald <donald.kuo@...>; devel@edk2.groups.io
Cc: Ni, Ray <ray.ni@...>; Zeng, Star <star.zeng@...>;
Chan, Amy <amy.chan@...>; Chaganty, Rangasai V
<rangasai.v.chaganty@...>
Subject: RE: [PATCH] UefiCpuPkg: Adding a new TSC library by using
CPUID(0x15) TSC leaf

Hi Donald,

Do you think it's necessary to check the TIME_STAMP_COUNTER capability
before using it? I see SDM has CPUID(0x01) which return the capability
of TIME_STAMP_COUNTER.

Thanks,
Eric

-----Original Message-----
From: Kuo, Donald
Sent: Monday, August 12, 2019 7:23 PM
To: devel@edk2.groups.io
Cc: Ni, Ray <ray.ni@...>; Zeng, Star <star.zeng@...>;
Dong, Eric <eric.dong@...>; Chan, Amy <amy.chan@...>;
Chaganty, Rangasai V <rangasai.v.chaganty@...>
Subject: [PATCH] UefiCpuPkg: Adding a new TSC library by using
CPUID(0x15) TSC leaf

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=1909

Cc: Ray Ni <ray.ni@...>
Cc: Star Zeng <star.zeng@...>
Cc: Eric Dong <eric.dong@...>
Cc: Amy Chan <amy.chan@...>
Cc: Rangasai V Chaganty <rangasai.v.chaganty@...>
Signed-off-by: Donald Kuo <donald.kuo@...>
---
.../Library/BaseCpuTimerLib/BaseCpuTimerLib.c | 40 +++
.../Library/BaseCpuTimerLib/BaseCpuTimerLib.inf | 35 +++
.../Library/BaseCpuTimerLib/BaseCpuTimerLib.uni | 16 ++
UefiCpuPkg/Library/BaseCpuTimerLib/CpuTimerLib.c | 272
+++++++++++++++++++++
UefiCpuPkg/UefiCpuPkg.dec | 8 +
UefiCpuPkg/UefiCpuPkg.dsc | 1 +
6 files changed, 372 insertions(+)
create mode 100644
UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.c
create mode 100644
UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.inf
create mode 100644
UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.uni
create mode 100644
UefiCpuPkg/Library/BaseCpuTimerLib/CpuTimerLib.c

diff --git a/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.c
b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.c
new file mode 100644
index 0000000000..ccb92a95d3
--- /dev/null
+++ b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.c
@@ -0,0 +1,40 @@
+/** @file
+ CPUID Leaf 0x15 for Core Crystal Clock frequency instance of
+Timer
Library.
+
+ Copyright (c) 2019 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+
+/**
+ CPUID Leaf 0x15 for Core Crystal Clock Frequency.
+
+ The TSC counting frequency is determined by using CPUID leaf 0x15.
Frequency in MHz = Core XTAL frequency * EBX/EAX.
+ In newer flavors of the CPU, core xtal frequency is returned in
+ ECX or 0 if
not supported.
+ @return The number of TSC counts per second.
+
+**/
+UINT64
+CpuidCoreClockCalculateTscFrequency (
+ VOID
+ );
+
+/**
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+InternalGetPerformanceCounterFrequency (
+ VOID
+ )
+{
+ return CpuidCoreClockCalculateTscFrequency (); }
diff --git a/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.inf
b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.inf
new file mode 100644
index 0000000000..7e27a55c90
--- /dev/null
+++ b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.inf
@@ -0,0 +1,35 @@
+## @file
+# Base CPU Timer Library
+#
+# Provides basic timer support using CPUID Leaf 0x15 XTAL frequency.
+The performance # counter features are provided by the processors
+time
stamp counter.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+#
+SPDX-License-Identifier: BSD-2-Clause-Patent # ##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = BaseCpuTimerLib
+ FILE_GUID = F10B5B91-D15A-496C-B044-B5235721AA08
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = TimerLib
+ MODULE_UNI_FILE = BaseCpuTimerLib.uni
+
+[Sources]
+ CpuTimerLib.c
+ BaseCpuTimerLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ PcdLib
+ DebugLib
+
+[Pcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuCoreCrystalClockFrequency ##
+CONSUMES
diff --git a/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.uni
b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.uni
new file mode 100644
index 0000000000..6e5c3ef70e
--- /dev/null
+++ b/UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.uni
@@ -0,0 +1,16 @@
+// /** @file
+// Base CPU Timer Library
+//
+// Provides basic timer support using CPUID Leaf 0x15 XTAL frequency.
+The performance // counter features are provided by the processors
+time
stamp counter.
+//
+// Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+// // SPDX-License-Identifier: BSD-2-Clause-Patent // // **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "CPU Timer
Library"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Provides
basic
timer support using CPUID Leaf 0x15 XTAL frequency."
diff --git a/UefiCpuPkg/Library/BaseCpuTimerLib/CpuTimerLib.c
b/UefiCpuPkg/Library/BaseCpuTimerLib/CpuTimerLib.c
new file mode 100644
index 0000000000..39492acd8e
--- /dev/null
+++ b/UefiCpuPkg/Library/BaseCpuTimerLib/CpuTimerLib.c
@@ -0,0 +1,272 @@
+/** @file
+ CPUID Leaf 0x15 for Core Crystal Clock frequency instance of
+Timer
Library.
+
+ Copyright (c) 2019 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DebugLib.h>
+#include <Register/Cpuid.h>
+
+/**
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+InternalGetPerformanceCounterFrequency (
+ VOID
+ );
+
+/**
+ CPUID Leaf 0x15 for Core Crystal Clock Frequency.
+
+ The TSC counting frequency is determined by using CPUID leaf 0x15.
Frequency in MHz = Core XTAL frequency * EBX/EAX.
+ In newer flavors of the CPU, core xtal frequency is returned in
+ ECX or 0 if
not supported.
+ @return The number of TSC counts per second.
+
+**/
+UINT64
+CpuidCoreClockCalculateTscFrequency (
+ VOID
+ )
+{
+ CPUID_VERSION_INFO_EAX Eax;
+ UINT64 TscFrequency;
+ UINT64 CoreXtalFrequency;
+ UINT32 RegEax;
+ UINT32 RegEbx;
+ UINT32 RegEcx;
+
+ //
+ // Use CPUID leaf 0x15 Time Stamp Counter and Nominal Core
+ Crystal Clock Information // EBX returns 0 if not supported. ECX,
+ if non zero,
provides Core Xtal Frequency in hertz.
+ // TSC frequency = (ECX, Core Xtal Frequency) * EBX/EAX.
+ //
+ AsmCpuid (CPUID_TIME_STAMP_COUNTER, &RegEax, &RegEbx,
&RegEcx,
NULL);
+
+ //
+ // If EBX returns 0, the XTAL ratio is not enumerated.
+ //
+ ASSERT (RegEbx != 0);
+ //
+ // If ECX returns 0, the XTAL frequency is not enumerated.
+ //
+ if (RegEcx == 0) {
+ CoreXtalFrequency = PcdGet64 (PcdCpuCoreCrystalClockFrequency);
+ } else {
+ CoreXtalFrequency = (UINT64) RegEcx; }
+
+ //
+ // Calculate TSC frequency = (ECX, Core Xtal Frequency) * EBX/EAX
+ // TscFrequency = DivU64x32 (MultU64x32 (CoreXtalFrequency,
+ RegEbx)
+ + (UINT64)(RegEax >> 1), RegEax);
+
+ return TscFrequency;
+}
+
+/**
+ Stalls the CPU for at least the given number of ticks.
+
+ Stalls the CPU for at least the given number of ticks. It's
+ invoked by
+ MicroSecondDelay() and NanoSecondDelay().
+
+ @param Delay A period of time to delay in ticks.
+
+**/
+VOID
+InternalCpuDelay (
+ IN UINT64 Delay
+ )
+{
+ UINT64 Ticks;
+
+ //
+ // The target timer count is calculated here // Ticks =
+ AsmReadTsc() + Delay;
+
+ //
+ // Wait until time out
+ // Timer wrap-arounds are NOT handled correctly by this function.
+ // Thus, this function must be called within 10 years of reset
+since
+ // Intel guarantees a minimum of 10 years before the TSC wraps.
+ //
+ while (AsmReadTsc() <= Ticks) {
+ CpuPause();
+ }
+}
+
+/**
+ Stalls the CPU for at least the given number of microseconds.
+
+ Stalls the CPU for the number of microseconds specified by
MicroSeconds.
+
+ @param[in] MicroSeconds The minimum number of microseconds to
delay.
+
+ @return MicroSeconds
+
+**/
+UINTN
+EFIAPI
+MicroSecondDelay (
+ IN UINTN MicroSeconds
+ )
+{
+
+ InternalCpuDelay (
+ DivU64x32 (
+ MultU64x64 (
+ MicroSeconds,
+ CpuidCoreClockCalculateTscFrequency ()
+ ),
+ 1000000u
+ )
+ );
+
+ return MicroSeconds;
+}
+
+/**
+ Stalls the CPU for at least the given number of nanoseconds.
+
+ Stalls the CPU for the number of nanoseconds specified by
NanoSeconds.
+
+ @param NanoSeconds The minimum number of nanoseconds to delay.
+
+ @return NanoSeconds
+
+**/
+UINTN
+EFIAPI
+NanoSecondDelay (
+ IN UINTN NanoSeconds
+ )
+{
+
+ InternalCpuDelay (
+ DivU64x32 (
+ MultU64x64 (
+ NanoSeconds,
+ CpuidCoreClockCalculateTscFrequency ()
+ ),
+ 1000000000u
+ )
+ );
+
+ return NanoSeconds;
+}
+
+/**
+ Retrieves the current value of a 64-bit free running performance
counter.
+
+ Retrieves the current value of a 64-bit free running performance
+ counter. The counter can either count up by 1 or count down by 1.
+ If the physical performance counter counts by a larger increment,
+ then the counter values must be translated. The properties of the
+ counter can be retrieved from GetPerformanceCounterProperties().
+
+ @return The current value of the free running performance counter.
+
+**/
+UINT64
+EFIAPI
+GetPerformanceCounter (
+ VOID
+ )
+{
+ return AsmReadTsc ();
+}
+
+/**
+ Retrieves the 64-bit frequency in Hz and the range of performance
+counter
+ values.
+
+ If StartValue is not NULL, then the value that the performance
+ counter starts with immediately after is it rolls over is
+ returned in StartValue. If EndValue is not NULL, then the value
+ that the performance counter end with immediately before it rolls
+ over is returned in EndValue. The 64-bit frequency of the
+ performance counter in Hz is always returned. If StartValue is
+ less than EndValue, then the performance counter counts up. If
+ StartValue is greater than EndValue, then the performance counter
+ counts down. For example, a 64-bit free running counter that
+ counts up would have a StartValue of
+ 0 and an EndValue of 0xFFFFFFFFFFFFFFFF. A 24-bit free running
+ counter
that counts down would have a StartValue of 0xFFFFFF and an EndValue
of
0.
+
+ @param StartValue The value the performance counter starts with
+ when
it
+ rolls over.
+ @param EndValue The value that the performance counter ends
with
before
+ it rolls over.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+EFIAPI
+GetPerformanceCounterProperties (
+ OUT UINT64 *StartValue, OPTIONAL
+ OUT UINT64 *EndValue OPTIONAL
+ )
+{
+ if (StartValue != NULL) {
+ *StartValue = 0;
+ }
+
+ if (EndValue != NULL) {
+ *EndValue = 0xffffffffffffffffULL; } return
+ InternalGetPerformanceCounterFrequency (); }
+
+/**
+ Converts elapsed ticks of performance counter to time in nanoseconds.
+
+ This function converts the elapsed ticks of running performance
+ counter to time value in unit of nanoseconds.
+
+ @param Ticks The number of elapsed ticks of running performance
counter.
+
+ @return The elapsed time in nanoseconds.
+
+**/
+UINT64
+EFIAPI
+GetTimeInNanoSecond (
+ IN UINT64 Ticks
+ )
+{
+ UINT64 Frequency;
+ UINT64 NanoSeconds;
+ UINT64 Remainder;
+ INTN Shift;
+
+ Frequency = GetPerformanceCounterProperties (NULL, NULL);
+
+ //
+ // Ticks
+ // Time = --------- x 1,000,000,000
+ // Frequency
+ //
+ NanoSeconds = MultU64x32 (DivU64x64Remainder (Ticks, Frequency,
+ &Remainder), 1000000000u);
+
+ //
+ // Ensure (Remainder * 1,000,000,000) will not overflow 64-bit.
+ // Since 2^29 < 1,000,000,000 = 0x3B9ACA00 < 2^30, Remainder
+ should <
+ 2^(64-30) = 2^34, // i.e. highest bit set in Remainder should <= 33.
+ //
+ Shift = MAX (0, HighBitSet64 (Remainder) - 33); Remainder =
+ RShiftU64 (Remainder, (UINTN) Shift); Frequency = RShiftU64
+ (Frequency, (UINTN) Shift); NanoSeconds += DivU64x64Remainder
+ (MultU64x32 (Remainder, 1000000000u), Frequency, NULL);
+
+ return NanoSeconds;
+}
diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec
index 14ddaa8633..a94bd2ea30 100644
--- a/UefiCpuPkg/UefiCpuPkg.dec
+++ b/UefiCpuPkg/UefiCpuPkg.dec
@@ -211,6 +211,14 @@
# @Prompt If CPU features will be initialized during S3 resume.

gUefiCpuPkgTokenSpaceGuid.PcdCpuFeaturesInitOnS3Resume|FALSE|BOO
LEAN|0x0000001D

+ ## Specifies CPUID Leaf 0x15 Time Stamp Counter and Nominal Core
Crystal Clock Frequency.
+ # TSC Frequency = ECX (core crystal clock frequency) * EBX/EAX.
+ # Intel Xeon Processor Scalable Family with CPUID signature 06_55H =
25000000 (25MHz)
+ # 6th and 7th generation Intel Core processors and Intel Xeon W
Processor Family = 24000000 (24MHz)
+ # Intel Atom processors based on Goldmont Microarchitecture with
CPUID signature 06_5CH = 19200000 (19.2MHz)
+ # @Prompt Core Crystal Clock Frequency is for CPUID Leaf 0x15.ECX
+
+
gUefiCpuPkgTokenSpaceGuid.PcdCpuCoreCrystalClockFrequency|24000000|
UIN
+ T64|0x32132113
+
[PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic,
PcdsDynamicEx]
## Specifies max supported number of Logical Processors.
# @Prompt Configure max supported number of Logical Processors
diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc
index bf690d3978..e1337c741b 100644
--- a/UefiCpuPkg/UefiCpuPkg.dsc
+++ b/UefiCpuPkg/UefiCpuPkg.dsc
@@ -143,6 +143,7 @@

SmmCpuFeaturesLib|UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFea
turesLibStm.inf
}
UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume2Pei.inf
+ UefiCpuPkg/Library/BaseCpuTimerLib/BaseCpuTimerLib.inf

[BuildOptions]
*_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES
--
2.14.2.windows.3

Donald Kuo
 

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=1909

Cc: Ray Ni <ray.ni@...>
Cc: Star Zeng <star.zeng@...>
Cc: Eric Dong <eric.dong@...>
Cc: Amy Chan <amy.chan@...>
Cc: Rangasai V Chaganty <rangasai.v.chaganty@...>
Signed-off-by: Donald Kuo <donald.kuo@...>
---
UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.c | 41 +++
UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf | 35 +++
UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.uni | 17 ++
UefiCpuPkg/Library/CpuTimerLib/CpuTimerLib.c | 274 +++++++++++++++++++++
UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.c | 81 ++++++
UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.inf | 37 +++
UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.uni | 17 ++
UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.c | 58 +++++
UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.inf | 36 +++
UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.uni | 17 ++
UefiCpuPkg/UefiCpuPkg.dec | 8 +
UefiCpuPkg/UefiCpuPkg.dsc | 3 +
12 files changed, 624 insertions(+)
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.c
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.uni
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/CpuTimerLib.c
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.c
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.inf
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.uni
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.c
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.inf
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.uni

diff --git a/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.c b/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.c
new file mode 100644
index 0000000000..6ddf917bad
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.c
@@ -0,0 +1,41 @@
+/** @file
+ CPUID Leaf 0x15 for Core Crystal Clock frequency instance as Base Timer Library.
+
+ Copyright (c) 2019 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+
+/**
+ CPUID Leaf 0x15 for Core Crystal Clock Frequency.
+
+ The TSC counting frequency is determined by using CPUID leaf 0x15. Frequency in MHz = Core XTAL frequency * EBX/EAX.
+ In newer flavors of the CPU, core xtal frequency is returned in ECX or 0 if not supported.
+ @return The number of TSC counts per second.
+
+**/
+UINT64
+CpuidCoreClockCalculateTscFrequency (
+ VOID
+ );
+
+/**
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+InternalGetPerformanceCounterFrequency (
+ VOID
+ )
+{
+ return CpuidCoreClockCalculateTscFrequency ();
+}
+
diff --git a/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf b/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf
new file mode 100644
index 0000000000..fd93adc5f1
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf
@@ -0,0 +1,35 @@
+## @file
+# Base CPU Timer Library
+#
+# Provides basic timer support using CPUID Leaf 0x15 XTAL frequency. The performance
+# counter features are provided by the processors time stamp counter.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = BaseCpuTimerLib
+ FILE_GUID = F10B5B91-D15A-496C-B044-B5235721AA08
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = TimerLib|SEC PEI_CORE PEIM
+ MODULE_UNI_FILE = BaseCpuTimerLib.uni
+
+[Sources]
+ CpuTimerLib.c
+ BaseCpuTimerLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ PcdLib
+ DebugLib
+
+[Pcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuCoreCrystalClockFrequency ## CONSUMES
diff --git a/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.uni b/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.uni
new file mode 100644
index 0000000000..fcf2b0fbcb
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.uni
@@ -0,0 +1,17 @@
+// /** @file
+// Base CPU Timer Library
+//
+// Provides basic timer support using CPUID Leaf 0x15 XTAL frequency. The performance
+// counter features are provided by the processors time stamp counter.
+//
+// Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "CPU Timer Library"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Provides basic timer support using CPUID Leaf 0x15 XTAL frequency."
+
diff --git a/UefiCpuPkg/Library/CpuTimerLib/CpuTimerLib.c b/UefiCpuPkg/Library/CpuTimerLib/CpuTimerLib.c
new file mode 100644
index 0000000000..0b9e9384f5
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/CpuTimerLib.c
@@ -0,0 +1,274 @@
+/** @file
+ CPUID Leaf 0x15 for Core Crystal Clock frequency instance of Timer Library.
+
+ Copyright (c) 2019 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DebugLib.h>
+#include <Register/Cpuid.h>
+
+GUID mCpuCrystalFrequencyHobGuid = { 0xe1ec5ad0, 0x8569, 0x46bd, { 0x8d, 0xcd, 0x3b, 0x9f, 0x6f, 0x45, 0x82, 0x7a } };
+
+/**
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+InternalGetPerformanceCounterFrequency (
+ VOID
+ );
+
+/**
+ CPUID Leaf 0x15 for Core Crystal Clock Frequency.
+
+ The TSC counting frequency is determined by using CPUID leaf 0x15. Frequency in MHz = Core XTAL frequency * EBX/EAX.
+ In newer flavors of the CPU, core xtal frequency is returned in ECX or 0 if not supported.
+ @return The number of TSC counts per second.
+
+**/
+UINT64
+CpuidCoreClockCalculateTscFrequency (
+ VOID
+ )
+{
+ UINT64 TscFrequency;
+ UINT64 CoreXtalFrequency;
+ UINT32 RegEax;
+ UINT32 RegEbx;
+ UINT32 RegEcx;
+
+ //
+ // Use CPUID leaf 0x15 Time Stamp Counter and Nominal Core Crystal Clock Information
+ // EBX returns 0 if not supported. ECX, if non zero, provides Core Xtal Frequency in hertz.
+ // TSC frequency = (ECX, Core Xtal Frequency) * EBX/EAX.
+ //
+ AsmCpuid (CPUID_TIME_STAMP_COUNTER, &RegEax, &RegEbx, &RegEcx, NULL);
+
+ //
+ // If EBX returns 0, the XTAL ratio is not enumerated.
+ //
+ ASSERT (RegEbx != 0);
+ //
+ // If ECX returns 0, the XTAL frequency is not enumerated.
+ //
+ if (RegEcx == 0) {
+ CoreXtalFrequency = PcdGet64 (PcdCpuCoreCrystalClockFrequency);
+ } else {
+ CoreXtalFrequency = (UINT64) RegEcx;
+ }
+
+ //
+ // Calculate TSC frequency = (ECX, Core Xtal Frequency) * EBX/EAX
+ //
+ TscFrequency = DivU64x32 (MultU64x32 (CoreXtalFrequency, RegEbx) + (UINT64)(RegEax >> 1), RegEax);
+
+ return TscFrequency;
+}
+
+/**
+ Stalls the CPU for at least the given number of ticks.
+
+ Stalls the CPU for at least the given number of ticks. It's invoked by
+ MicroSecondDelay() and NanoSecondDelay().
+
+ @param Delay A period of time to delay in ticks.
+
+**/
+VOID
+InternalCpuDelay (
+ IN UINT64 Delay
+ )
+{
+ UINT64 Ticks;
+
+ //
+ // The target timer count is calculated here
+ //
+ Ticks = AsmReadTsc() + Delay;
+
+ //
+ // Wait until time out
+ // Timer wrap-arounds are NOT handled correctly by this function.
+ // Thus, this function must be called within 10 years of reset since
+ // Intel guarantees a minimum of 10 years before the TSC wraps.
+ //
+ while (AsmReadTsc() <= Ticks) {
+ CpuPause();
+ }
+}
+
+/**
+ Stalls the CPU for at least the given number of microseconds.
+
+ Stalls the CPU for the number of microseconds specified by MicroSeconds.
+
+ @param[in] MicroSeconds The minimum number of microseconds to delay.
+
+ @return MicroSeconds
+
+**/
+UINTN
+EFIAPI
+MicroSecondDelay (
+ IN UINTN MicroSeconds
+ )
+{
+
+ InternalCpuDelay (
+ DivU64x32 (
+ MultU64x64 (
+ MicroSeconds,
+ InternalGetPerformanceCounterFrequency ()
+ ),
+ 1000000u
+ )
+ );
+
+ return MicroSeconds;
+}
+
+/**
+ Stalls the CPU for at least the given number of nanoseconds.
+
+ Stalls the CPU for the number of nanoseconds specified by NanoSeconds.
+
+ @param NanoSeconds The minimum number of nanoseconds to delay.
+
+ @return NanoSeconds
+
+**/
+UINTN
+EFIAPI
+NanoSecondDelay (
+ IN UINTN NanoSeconds
+ )
+{
+
+ InternalCpuDelay (
+ DivU64x32 (
+ MultU64x64 (
+ NanoSeconds,
+ InternalGetPerformanceCounterFrequency ()
+ ),
+ 1000000000u
+ )
+ );
+
+ return NanoSeconds;
+}
+
+/**
+ Retrieves the current value of a 64-bit free running performance counter.
+
+ Retrieves the current value of a 64-bit free running performance counter. The
+ counter can either count up by 1 or count down by 1. If the physical
+ performance counter counts by a larger increment, then the counter values
+ must be translated. The properties of the counter can be retrieved from
+ GetPerformanceCounterProperties().
+
+ @return The current value of the free running performance counter.
+
+**/
+UINT64
+EFIAPI
+GetPerformanceCounter (
+ VOID
+ )
+{
+ return AsmReadTsc ();
+}
+
+/**
+ Retrieves the 64-bit frequency in Hz and the range of performance counter
+ values.
+
+ If StartValue is not NULL, then the value that the performance counter starts
+ with immediately after is it rolls over is returned in StartValue. If
+ EndValue is not NULL, then the value that the performance counter end with
+ immediately before it rolls over is returned in EndValue. The 64-bit
+ frequency of the performance counter in Hz is always returned. If StartValue
+ is less than EndValue, then the performance counter counts up. If StartValue
+ is greater than EndValue, then the performance counter counts down. For
+ example, a 64-bit free running counter that counts up would have a StartValue
+ of 0 and an EndValue of 0xFFFFFFFFFFFFFFFF. A 24-bit free running counter
+ that counts down would have a StartValue of 0xFFFFFF and an EndValue of 0.
+
+ @param StartValue The value the performance counter starts with when it
+ rolls over.
+ @param EndValue The value that the performance counter ends with before
+ it rolls over.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+EFIAPI
+GetPerformanceCounterProperties (
+ OUT UINT64 *StartValue, OPTIONAL
+ OUT UINT64 *EndValue OPTIONAL
+ )
+{
+ if (StartValue != NULL) {
+ *StartValue = 0;
+ }
+
+ if (EndValue != NULL) {
+ *EndValue = 0xffffffffffffffffULL;
+ }
+ return InternalGetPerformanceCounterFrequency ();
+}
+
+/**
+ Converts elapsed ticks of performance counter to time in nanoseconds.
+
+ This function converts the elapsed ticks of running performance counter to
+ time value in unit of nanoseconds.
+
+ @param Ticks The number of elapsed ticks of running performance counter.
+
+ @return The elapsed time in nanoseconds.
+
+**/
+UINT64
+EFIAPI
+GetTimeInNanoSecond (
+ IN UINT64 Ticks
+ )
+{
+ UINT64 Frequency;
+ UINT64 NanoSeconds;
+ UINT64 Remainder;
+ INTN Shift;
+
+ Frequency = GetPerformanceCounterProperties (NULL, NULL);
+
+ //
+ // Ticks
+ // Time = --------- x 1,000,000,000
+ // Frequency
+ //
+ NanoSeconds = MultU64x32 (DivU64x64Remainder (Ticks, Frequency, &Remainder), 1000000000u);
+
+ //
+ // Ensure (Remainder * 1,000,000,000) will not overflow 64-bit.
+ // Since 2^29 < 1,000,000,000 = 0x3B9ACA00 < 2^30, Remainder should < 2^(64-30) = 2^34,
+ // i.e. highest bit set in Remainder should <= 33.
+ //
+ Shift = MAX (0, HighBitSet64 (Remainder) - 33);
+ Remainder = RShiftU64 (Remainder, (UINTN) Shift);
+ Frequency = RShiftU64 (Frequency, (UINTN) Shift);
+ NanoSeconds += DivU64x64Remainder (MultU64x32 (Remainder, 1000000000u), Frequency, NULL);
+
+ return NanoSeconds;
+}
+
diff --git a/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.c b/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.c
new file mode 100644
index 0000000000..2d0ef6ab07
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.c
@@ -0,0 +1,81 @@
+/** @file
+ CPUID Leaf 0x15 for Core Crystal Clock frequency instance of Timer Library.
+
+ Copyright (c) 2019 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+#include <Library/HobLib.h>
+
+extern GUID mCpuCrystalFrequencyHobGuid;
+
+/**
+ CPUID Leaf 0x15 for Core Crystal Clock Frequency.
+
+ The TSC counting frequency is determined by using CPUID leaf 0x15. Frequency in MHz = Core XTAL frequency * EBX/EAX.
+ In newer flavors of the CPU, core xtal frequency is returned in ECX or 0 if not supported.
+ @return The number of TSC counts per second.
+
+**/
+UINT64
+CpuidCoreClockCalculateTscFrequency (
+ VOID
+ );
+
+//
+// Cached CPU Crystal counter frequency
+//
+UINT64 mCpuCrystalCounterFrequency = 0;
+
+
+/**
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+InternalGetPerformanceCounterFrequency (
+ VOID
+ )
+{
+ return mCpuCrystalCounterFrequency;
+}
+
+/**
+ The constructor function is to initialize CpuCrystalCounterFrequency.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The constructor always returns RETURN_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+DxeCpuTimerLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_HOB_GUID_TYPE *GuidHob;
+
+ //
+ // Initialize CpuCrystalCounterFrequency
+ //
+ GuidHob = GetFirstGuidHob (&mCpuCrystalFrequencyHobGuid);
+ if (GuidHob != NULL) {
+ mCpuCrystalCounterFrequency = *(UINT64*)GET_GUID_HOB_DATA (GuidHob);
+ } else {
+ mCpuCrystalCounterFrequency = CpuidCoreClockCalculateTscFrequency ();
+ }
+
+ return EFI_SUCCESS;
+}
+
diff --git a/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.inf b/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.inf
new file mode 100644
index 0000000000..6c83549c87
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.inf
@@ -0,0 +1,37 @@
+## @file
+# DXE CPU Timer Library
+#
+# Provides basic timer support using CPUID Leaf 0x15 XTAL frequency. The performance
+# counter features are provided by the processors time stamp counter.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeCpuTimerLib
+ FILE_GUID = F22CC0DA-E7DB-4E4D-ABE2-A608188233A2
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = TimerLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER SMM_CORE
+ CONSTRUCTOR = DxeCpuTimerLibConstructor
+ MODULE_UNI_FILE = DxeCpuTimerLib.uni
+
+[Sources]
+ CpuTimerLib.c
+ DxeCpuTimerLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ PcdLib
+ DebugLib
+ HobLib
+
+[Pcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuCoreCrystalClockFrequency ## CONSUMES
diff --git a/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.uni b/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.uni
new file mode 100644
index 0000000000..f55b92abac
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.uni
@@ -0,0 +1,17 @@
+// /** @file
+// DXE CPU Timer Library
+//
+// Provides basic timer support using CPUID Leaf 0x15 XTAL frequency. The performance
+// counter features are provided by the processors time stamp counter.
+//
+// Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "CPU Timer Library"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Provides basic timer support using CPUID Leaf 0x15 XTAL frequency."
+
diff --git a/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.c b/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.c
new file mode 100644
index 0000000000..91a7212056
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.c
@@ -0,0 +1,58 @@
+/** @file
+ CPUID Leaf 0x15 for Core Crystal Clock frequency instance as PEI Timer Library.
+
+ Copyright (c) 2019 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+#include <Library/HobLib.h>
+#include <Library/DebugLib.h>
+
+extern GUID mCpuCrystalFrequencyHobGuid;
+
+/**
+ CPUID Leaf 0x15 for Core Crystal Clock Frequency.
+
+ The TSC counting frequency is determined by using CPUID leaf 0x15. Frequency in MHz = Core XTAL frequency * EBX/EAX.
+ In newer flavors of the CPU, core xtal frequency is returned in ECX or 0 if not supported.
+ @return The number of TSC counts per second.
+
+**/
+UINT64
+CpuidCoreClockCalculateTscFrequency (
+ VOID
+ );
+
+/**
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+InternalGetPerformanceCounterFrequency (
+ VOID
+ )
+{
+ UINT64 *CpuCrystalCounterFrequency;
+ EFI_HOB_GUID_TYPE *GuidHob;
+
+ CpuCrystalCounterFrequency = NULL;
+ GuidHob = GetFirstGuidHob (&mCpuCrystalFrequencyHobGuid);
+ if (GuidHob == NULL) {
+ CpuCrystalCounterFrequency = (UINT64*)BuildGuidHob(&mCpuCrystalFrequencyHobGuid, sizeof (*CpuCrystalCounterFrequency));
+ ASSERT (CpuCrystalCounterFrequency != NULL);
+ *CpuCrystalCounterFrequency = CpuidCoreClockCalculateTscFrequency ();
+ } else {
+ CpuCrystalCounterFrequency = (UINT64*)GET_GUID_HOB_DATA (GuidHob);
+ }
+
+ return *CpuCrystalCounterFrequency;
+}
+
diff --git a/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.inf b/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.inf
new file mode 100644
index 0000000000..7af0fc44a6
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.inf
@@ -0,0 +1,36 @@
+## @file
+# PEI CPU Timer Library
+#
+# Provides basic timer support using CPUID Leaf 0x15 XTAL frequency. The performance
+# counter features are provided by the processors time stamp counter.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PeiCpuTimerLib
+ FILE_GUID = 2B13DE00-1A5F-4DD7-A298-01B08AF1015A
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = TimerLib|PEI_CORE PEIM
+ MODULE_UNI_FILE = PeiCpuTimerLib.uni
+
+[Sources]
+ CpuTimerLib.c
+ PeiCpuTimerLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ PcdLib
+ DebugLib
+ HobLib
+
+[Pcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuCoreCrystalClockFrequency ## CONSUMES
diff --git a/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.uni b/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.uni
new file mode 100644
index 0000000000..49beb44908
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.uni
@@ -0,0 +1,17 @@
+// /** @file
+// PEI CPU Timer Library
+//
+// Provides basic timer support using CPUID Leaf 0x15 XTAL frequency. The performance
+// counter features are provided by the processors time stamp counter.
+//
+// Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "CPU Timer Library"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Provides basic timer support using CPUID Leaf 0x15 XTAL frequency."
+
diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec
index 14ddaa8633..a94bd2ea30 100644
--- a/UefiCpuPkg/UefiCpuPkg.dec
+++ b/UefiCpuPkg/UefiCpuPkg.dec
@@ -211,6 +211,14 @@
# @Prompt If CPU features will be initialized during S3 resume.
gUefiCpuPkgTokenSpaceGuid.PcdCpuFeaturesInitOnS3Resume|FALSE|BOOLEAN|0x0000001D

+ ## Specifies CPUID Leaf 0x15 Time Stamp Counter and Nominal Core Crystal Clock Frequency.
+ # TSC Frequency = ECX (core crystal clock frequency) * EBX/EAX.
+ # Intel Xeon Processor Scalable Family with CPUID signature 06_55H = 25000000 (25MHz)
+ # 6th and 7th generation Intel Core processors and Intel Xeon W Processor Family = 24000000 (24MHz)
+ # Intel Atom processors based on Goldmont Microarchitecture with CPUID signature 06_5CH = 19200000 (19.2MHz)
+ # @Prompt Core Crystal Clock Frequency is for CPUID Leaf 0x15.ECX
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuCoreCrystalClockFrequency|24000000|UINT64|0x32132113
+
[PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
## Specifies max supported number of Logical Processors.
# @Prompt Configure max supported number of Logical Processors
diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc
index bf690d3978..e7dfe30eda 100644
--- a/UefiCpuPkg/UefiCpuPkg.dsc
+++ b/UefiCpuPkg/UefiCpuPkg.dsc
@@ -101,6 +101,9 @@
UefiCpuPkg/CpuIoPei/CpuIoPei.inf
UefiCpuPkg/Library/SecPeiDxeTimerLibUefiCpu/SecPeiDxeTimerLibUefiCpu.inf
UefiCpuPkg/Application/Cpuid/Cpuid.inf
+ UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf
+ UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.inf
+ UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.inf

[Components.IA32, Components.X64]
UefiCpuPkg/CpuDxe/CpuDxe.inf
--
2.14.2.windows.3

Dong, Eric
 

Reviewed-by: Eric Dong <eric.dong@...>

-----Original Message-----
From: devel@edk2.groups.io [mailto:devel@edk2.groups.io] On Behalf Of
Donald Kuo
Sent: Tuesday, August 13, 2019 6:53 PM
To: devel@edk2.groups.io
Cc: Ni, Ray <ray.ni@...>; Zeng, Star <star.zeng@...>; Dong, Eric
<eric.dong@...>; Chan, Amy <amy.chan@...>; Chaganty,
Rangasai V <rangasai.v.chaganty@...>
Subject: [edk2-devel] [PATCH] UefiCpuPkg: Adding a new TSC library by using
CPUID(0x15) TSC leaf

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=1909

Cc: Ray Ni <ray.ni@...>
Cc: Star Zeng <star.zeng@...>
Cc: Eric Dong <eric.dong@...>
Cc: Amy Chan <amy.chan@...>
Cc: Rangasai V Chaganty <rangasai.v.chaganty@...>
Signed-off-by: Donald Kuo <donald.kuo@...>
---
UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.c | 41 +++
UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf | 35 +++
UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.uni | 17 ++
UefiCpuPkg/Library/CpuTimerLib/CpuTimerLib.c | 274
+++++++++++++++++++++
UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.c | 81 ++++++
UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.inf | 37 +++
UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.uni | 17 ++
UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.c | 58 +++++
UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.inf | 36 +++
UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.uni | 17 ++
UefiCpuPkg/UefiCpuPkg.dec | 8 +
UefiCpuPkg/UefiCpuPkg.dsc | 3 +
12 files changed, 624 insertions(+)
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.c
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.uni
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/CpuTimerLib.c
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.c
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.inf
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.uni
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.c
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.inf
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.uni

diff --git a/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.c
b/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.c
new file mode 100644
index 0000000000..6ddf917bad
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.c
@@ -0,0 +1,41 @@
+/** @file
+ CPUID Leaf 0x15 for Core Crystal Clock frequency instance as Base Timer
Library.
+
+ Copyright (c) 2019 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+
+/**
+ CPUID Leaf 0x15 for Core Crystal Clock Frequency.
+
+ The TSC counting frequency is determined by using CPUID leaf 0x15.
Frequency in MHz = Core XTAL frequency * EBX/EAX.
+ In newer flavors of the CPU, core xtal frequency is returned in ECX or 0 if
not supported.
+ @return The number of TSC counts per second.
+
+**/
+UINT64
+CpuidCoreClockCalculateTscFrequency (
+ VOID
+ );
+
+/**
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+InternalGetPerformanceCounterFrequency (
+ VOID
+ )
+{
+ return CpuidCoreClockCalculateTscFrequency (); }
+
diff --git a/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf
b/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf
new file mode 100644
index 0000000000..fd93adc5f1
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf
@@ -0,0 +1,35 @@
+## @file
+# Base CPU Timer Library
+#
+# Provides basic timer support using CPUID Leaf 0x15 XTAL frequency.
+The performance # counter features are provided by the processors time
stamp counter.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR> #
+SPDX-License-Identifier: BSD-2-Clause-Patent # ##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = BaseCpuTimerLib
+ FILE_GUID = F10B5B91-D15A-496C-B044-B5235721AA08
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = TimerLib|SEC PEI_CORE PEIM
+ MODULE_UNI_FILE = BaseCpuTimerLib.uni
+
+[Sources]
+ CpuTimerLib.c
+ BaseCpuTimerLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ PcdLib
+ DebugLib
+
+[Pcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuCoreCrystalClockFrequency ##
+CONSUMES
diff --git a/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.uni
b/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.uni
new file mode 100644
index 0000000000..fcf2b0fbcb
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.uni
@@ -0,0 +1,17 @@
+// /** @file
+// Base CPU Timer Library
+//
+// Provides basic timer support using CPUID Leaf 0x15 XTAL frequency.
+The performance // counter features are provided by the processors time
stamp counter.
+//
+// Copyright (c) 2019, Intel Corporation. All rights reserved.<BR> //
+// SPDX-License-Identifier: BSD-2-Clause-Patent // // **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "CPU Timer
Library"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Provides basic
timer support using CPUID Leaf 0x15 XTAL frequency."
+
diff --git a/UefiCpuPkg/Library/CpuTimerLib/CpuTimerLib.c
b/UefiCpuPkg/Library/CpuTimerLib/CpuTimerLib.c
new file mode 100644
index 0000000000..0b9e9384f5
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/CpuTimerLib.c
@@ -0,0 +1,274 @@
+/** @file
+ CPUID Leaf 0x15 for Core Crystal Clock frequency instance of Timer Library.
+
+ Copyright (c) 2019 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DebugLib.h>
+#include <Register/Cpuid.h>
+
+GUID mCpuCrystalFrequencyHobGuid = { 0xe1ec5ad0, 0x8569, 0x46bd, {
+0x8d, 0xcd, 0x3b, 0x9f, 0x6f, 0x45, 0x82, 0x7a } };
+
+/**
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+InternalGetPerformanceCounterFrequency (
+ VOID
+ );
+
+/**
+ CPUID Leaf 0x15 for Core Crystal Clock Frequency.
+
+ The TSC counting frequency is determined by using CPUID leaf 0x15.
Frequency in MHz = Core XTAL frequency * EBX/EAX.
+ In newer flavors of the CPU, core xtal frequency is returned in ECX or 0 if
not supported.
+ @return The number of TSC counts per second.
+
+**/
+UINT64
+CpuidCoreClockCalculateTscFrequency (
+ VOID
+ )
+{
+ UINT64 TscFrequency;
+ UINT64 CoreXtalFrequency;
+ UINT32 RegEax;
+ UINT32 RegEbx;
+ UINT32 RegEcx;
+
+ //
+ // Use CPUID leaf 0x15 Time Stamp Counter and Nominal Core Crystal
+ Clock Information // EBX returns 0 if not supported. ECX, if non zero,
provides Core Xtal Frequency in hertz.
+ // TSC frequency = (ECX, Core Xtal Frequency) * EBX/EAX.
+ //
+ AsmCpuid (CPUID_TIME_STAMP_COUNTER, &RegEax, &RegEbx, &RegEcx,
NULL);
+
+ //
+ // If EBX returns 0, the XTAL ratio is not enumerated.
+ //
+ ASSERT (RegEbx != 0);
+ //
+ // If ECX returns 0, the XTAL frequency is not enumerated.
+ //
+ if (RegEcx == 0) {
+ CoreXtalFrequency = PcdGet64 (PcdCpuCoreCrystalClockFrequency);
+ } else {
+ CoreXtalFrequency = (UINT64) RegEcx; }
+
+ //
+ // Calculate TSC frequency = (ECX, Core Xtal Frequency) * EBX/EAX //
+ TscFrequency = DivU64x32 (MultU64x32 (CoreXtalFrequency, RegEbx) +
+ (UINT64)(RegEax >> 1), RegEax);
+
+ return TscFrequency;
+}
+
+/**
+ Stalls the CPU for at least the given number of ticks.
+
+ Stalls the CPU for at least the given number of ticks. It's invoked
+ by
+ MicroSecondDelay() and NanoSecondDelay().
+
+ @param Delay A period of time to delay in ticks.
+
+**/
+VOID
+InternalCpuDelay (
+ IN UINT64 Delay
+ )
+{
+ UINT64 Ticks;
+
+ //
+ // The target timer count is calculated here // Ticks =
+ AsmReadTsc() + Delay;
+
+ //
+ // Wait until time out
+ // Timer wrap-arounds are NOT handled correctly by this function.
+ // Thus, this function must be called within 10 years of reset since
+ // Intel guarantees a minimum of 10 years before the TSC wraps.
+ //
+ while (AsmReadTsc() <= Ticks) {
+ CpuPause();
+ }
+}
+
+/**
+ Stalls the CPU for at least the given number of microseconds.
+
+ Stalls the CPU for the number of microseconds specified by MicroSeconds.
+
+ @param[in] MicroSeconds The minimum number of microseconds to
delay.
+
+ @return MicroSeconds
+
+**/
+UINTN
+EFIAPI
+MicroSecondDelay (
+ IN UINTN MicroSeconds
+ )
+{
+
+ InternalCpuDelay (
+ DivU64x32 (
+ MultU64x64 (
+ MicroSeconds,
+ InternalGetPerformanceCounterFrequency ()
+ ),
+ 1000000u
+ )
+ );
+
+ return MicroSeconds;
+}
+
+/**
+ Stalls the CPU for at least the given number of nanoseconds.
+
+ Stalls the CPU for the number of nanoseconds specified by NanoSeconds.
+
+ @param NanoSeconds The minimum number of nanoseconds to delay.
+
+ @return NanoSeconds
+
+**/
+UINTN
+EFIAPI
+NanoSecondDelay (
+ IN UINTN NanoSeconds
+ )
+{
+
+ InternalCpuDelay (
+ DivU64x32 (
+ MultU64x64 (
+ NanoSeconds,
+ InternalGetPerformanceCounterFrequency ()
+ ),
+ 1000000000u
+ )
+ );
+
+ return NanoSeconds;
+}
+
+/**
+ Retrieves the current value of a 64-bit free running performance counter.
+
+ Retrieves the current value of a 64-bit free running performance
+ counter. The counter can either count up by 1 or count down by 1. If
+ the physical performance counter counts by a larger increment, then
+ the counter values must be translated. The properties of the counter
+ can be retrieved from GetPerformanceCounterProperties().
+
+ @return The current value of the free running performance counter.
+
+**/
+UINT64
+EFIAPI
+GetPerformanceCounter (
+ VOID
+ )
+{
+ return AsmReadTsc ();
+}
+
+/**
+ Retrieves the 64-bit frequency in Hz and the range of performance
+counter
+ values.
+
+ If StartValue is not NULL, then the value that the performance
+ counter starts with immediately after is it rolls over is returned in
+ StartValue. If EndValue is not NULL, then the value that the
+ performance counter end with immediately before it rolls over is
+ returned in EndValue. The 64-bit frequency of the performance counter
+ in Hz is always returned. If StartValue is less than EndValue, then
+ the performance counter counts up. If StartValue is greater than
+ EndValue, then the performance counter counts down. For example, a
+ 64-bit free running counter that counts up would have a StartValue of
+ 0 and an EndValue of 0xFFFFFFFFFFFFFFFF. A 24-bit free running counter
that counts down would have a StartValue of 0xFFFFFF and an EndValue of 0.
+
+ @param StartValue The value the performance counter starts with when
it
+ rolls over.
+ @param EndValue The value that the performance counter ends with
before
+ it rolls over.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+EFIAPI
+GetPerformanceCounterProperties (
+ OUT UINT64 *StartValue, OPTIONAL
+ OUT UINT64 *EndValue OPTIONAL
+ )
+{
+ if (StartValue != NULL) {
+ *StartValue = 0;
+ }
+
+ if (EndValue != NULL) {
+ *EndValue = 0xffffffffffffffffULL;
+ }
+ return InternalGetPerformanceCounterFrequency (); }
+
+/**
+ Converts elapsed ticks of performance counter to time in nanoseconds.
+
+ This function converts the elapsed ticks of running performance
+ counter to time value in unit of nanoseconds.
+
+ @param Ticks The number of elapsed ticks of running performance
counter.
+
+ @return The elapsed time in nanoseconds.
+
+**/
+UINT64
+EFIAPI
+GetTimeInNanoSecond (
+ IN UINT64 Ticks
+ )
+{
+ UINT64 Frequency;
+ UINT64 NanoSeconds;
+ UINT64 Remainder;
+ INTN Shift;
+
+ Frequency = GetPerformanceCounterProperties (NULL, NULL);
+
+ //
+ // Ticks
+ // Time = --------- x 1,000,000,000
+ // Frequency
+ //
+ NanoSeconds = MultU64x32 (DivU64x64Remainder (Ticks, Frequency,
+ &Remainder), 1000000000u);
+
+ //
+ // Ensure (Remainder * 1,000,000,000) will not overflow 64-bit.
+ // Since 2^29 < 1,000,000,000 = 0x3B9ACA00 < 2^30, Remainder should <
+ 2^(64-30) = 2^34, // i.e. highest bit set in Remainder should <= 33.
+ //
+ Shift = MAX (0, HighBitSet64 (Remainder) - 33); Remainder =
+ RShiftU64 (Remainder, (UINTN) Shift); Frequency = RShiftU64
+ (Frequency, (UINTN) Shift); NanoSeconds += DivU64x64Remainder
+ (MultU64x32 (Remainder, 1000000000u), Frequency, NULL);
+
+ return NanoSeconds;
+}
+
diff --git a/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.c
b/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.c
new file mode 100644
index 0000000000..2d0ef6ab07
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.c
@@ -0,0 +1,81 @@
+/** @file
+ CPUID Leaf 0x15 for Core Crystal Clock frequency instance of Timer Library.
+
+ Copyright (c) 2019 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+#include <Library/HobLib.h>
+
+extern GUID mCpuCrystalFrequencyHobGuid;
+
+/**
+ CPUID Leaf 0x15 for Core Crystal Clock Frequency.
+
+ The TSC counting frequency is determined by using CPUID leaf 0x15.
Frequency in MHz = Core XTAL frequency * EBX/EAX.
+ In newer flavors of the CPU, core xtal frequency is returned in ECX or 0 if
not supported.
+ @return The number of TSC counts per second.
+
+**/
+UINT64
+CpuidCoreClockCalculateTscFrequency (
+ VOID
+ );
+
+//
+// Cached CPU Crystal counter frequency //
+UINT64 mCpuCrystalCounterFrequency = 0;
+
+
+/**
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+InternalGetPerformanceCounterFrequency (
+ VOID
+ )
+{
+ return mCpuCrystalCounterFrequency;
+}
+
+/**
+ The constructor function is to initialize CpuCrystalCounterFrequency.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The constructor always returns RETURN_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+DxeCpuTimerLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_HOB_GUID_TYPE *GuidHob;
+
+ //
+ // Initialize CpuCrystalCounterFrequency // GuidHob =
+ GetFirstGuidHob (&mCpuCrystalFrequencyHobGuid); if (GuidHob != NULL)
+ {
+ mCpuCrystalCounterFrequency = *(UINT64*)GET_GUID_HOB_DATA
+ (GuidHob); } else {
+ mCpuCrystalCounterFrequency = CpuidCoreClockCalculateTscFrequency
+ (); }
+
+ return EFI_SUCCESS;
+}
+
diff --git a/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.inf
b/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.inf
new file mode 100644
index 0000000000..6c83549c87
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.inf
@@ -0,0 +1,37 @@
+## @file
+# DXE CPU Timer Library
+#
+# Provides basic timer support using CPUID Leaf 0x15 XTAL frequency.
+The performance # counter features are provided by the processors time
stamp counter.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR> #
+SPDX-License-Identifier: BSD-2-Clause-Patent # ##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeCpuTimerLib
+ FILE_GUID = F22CC0DA-E7DB-4E4D-ABE2-A608188233A2
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = TimerLib|DXE_CORE DXE_DRIVER
DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION
UEFI_DRIVER SMM_CORE
+ CONSTRUCTOR = DxeCpuTimerLibConstructor
+ MODULE_UNI_FILE = DxeCpuTimerLib.uni
+
+[Sources]
+ CpuTimerLib.c
+ DxeCpuTimerLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ PcdLib
+ DebugLib
+ HobLib
+
+[Pcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuCoreCrystalClockFrequency ##
+CONSUMES
diff --git a/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.uni
b/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.uni
new file mode 100644
index 0000000000..f55b92abac
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.uni
@@ -0,0 +1,17 @@
+// /** @file
+// DXE CPU Timer Library
+//
+// Provides basic timer support using CPUID Leaf 0x15 XTAL frequency.
+The performance // counter features are provided by the processors time
stamp counter.
+//
+// Copyright (c) 2019, Intel Corporation. All rights reserved.<BR> //
+// SPDX-License-Identifier: BSD-2-Clause-Patent // // **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "CPU Timer
Library"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Provides basic
timer support using CPUID Leaf 0x15 XTAL frequency."
+
diff --git a/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.c
b/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.c
new file mode 100644
index 0000000000..91a7212056
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.c
@@ -0,0 +1,58 @@
+/** @file
+ CPUID Leaf 0x15 for Core Crystal Clock frequency instance as PEI Timer
Library.
+
+ Copyright (c) 2019 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+#include <Library/HobLib.h>
+#include <Library/DebugLib.h>
+
+extern GUID mCpuCrystalFrequencyHobGuid;
+
+/**
+ CPUID Leaf 0x15 for Core Crystal Clock Frequency.
+
+ The TSC counting frequency is determined by using CPUID leaf 0x15.
Frequency in MHz = Core XTAL frequency * EBX/EAX.
+ In newer flavors of the CPU, core xtal frequency is returned in ECX or 0 if
not supported.
+ @return The number of TSC counts per second.
+
+**/
+UINT64
+CpuidCoreClockCalculateTscFrequency (
+ VOID
+ );
+
+/**
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+InternalGetPerformanceCounterFrequency (
+ VOID
+ )
+{
+ UINT64 *CpuCrystalCounterFrequency;
+ EFI_HOB_GUID_TYPE *GuidHob;
+
+ CpuCrystalCounterFrequency = NULL;
+ GuidHob = GetFirstGuidHob (&mCpuCrystalFrequencyHobGuid); if
+ (GuidHob == NULL) {
+ CpuCrystalCounterFrequency =
(UINT64*)BuildGuidHob(&mCpuCrystalFrequencyHobGuid, sizeof
(*CpuCrystalCounterFrequency));
+ ASSERT (CpuCrystalCounterFrequency != NULL);
+ *CpuCrystalCounterFrequency = CpuidCoreClockCalculateTscFrequency
+ (); } else {
+ CpuCrystalCounterFrequency = (UINT64*)GET_GUID_HOB_DATA
(GuidHob);
+ }
+
+ return *CpuCrystalCounterFrequency;
+}
+
diff --git a/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.inf
b/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.inf
new file mode 100644
index 0000000000..7af0fc44a6
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.inf
@@ -0,0 +1,36 @@
+## @file
+# PEI CPU Timer Library
+#
+# Provides basic timer support using CPUID Leaf 0x15 XTAL frequency.
+The performance # counter features are provided by the processors time
stamp counter.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR> #
+SPDX-License-Identifier: BSD-2-Clause-Patent # ##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PeiCpuTimerLib
+ FILE_GUID = 2B13DE00-1A5F-4DD7-A298-01B08AF1015A
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = TimerLib|PEI_CORE PEIM
+ MODULE_UNI_FILE = PeiCpuTimerLib.uni
+
+[Sources]
+ CpuTimerLib.c
+ PeiCpuTimerLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ PcdLib
+ DebugLib
+ HobLib
+
+[Pcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuCoreCrystalClockFrequency ##
+CONSUMES
diff --git a/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.uni
b/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.uni
new file mode 100644
index 0000000000..49beb44908
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.uni
@@ -0,0 +1,17 @@
+// /** @file
+// PEI CPU Timer Library
+//
+// Provides basic timer support using CPUID Leaf 0x15 XTAL frequency.
+The performance // counter features are provided by the processors time
stamp counter.
+//
+// Copyright (c) 2019, Intel Corporation. All rights reserved.<BR> //
+// SPDX-License-Identifier: BSD-2-Clause-Patent // // **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "CPU Timer
Library"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Provides basic
timer support using CPUID Leaf 0x15 XTAL frequency."
+
diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec
index 14ddaa8633..a94bd2ea30 100644
--- a/UefiCpuPkg/UefiCpuPkg.dec
+++ b/UefiCpuPkg/UefiCpuPkg.dec
@@ -211,6 +211,14 @@
# @Prompt If CPU features will be initialized during S3 resume.

gUefiCpuPkgTokenSpaceGuid.PcdCpuFeaturesInitOnS3Resume|FALSE|BOO
LEAN|0x0000001D

+ ## Specifies CPUID Leaf 0x15 Time Stamp Counter and Nominal Core
Crystal Clock Frequency.
+ # TSC Frequency = ECX (core crystal clock frequency) * EBX/EAX.
+ # Intel Xeon Processor Scalable Family with CPUID signature 06_55H =
25000000 (25MHz)
+ # 6th and 7th generation Intel Core processors and Intel Xeon W
Processor Family = 24000000 (24MHz)
+ # Intel Atom processors based on Goldmont Microarchitecture with
CPUID signature 06_5CH = 19200000 (19.2MHz)
+ # @Prompt Core Crystal Clock Frequency is for CPUID Leaf 0x15.ECX
+
+
gUefiCpuPkgTokenSpaceGuid.PcdCpuCoreCrystalClockFrequency|24000000|
UIN
+ T64|0x32132113
+
[PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
## Specifies max supported number of Logical Processors.
# @Prompt Configure max supported number of Logical Processors diff --git
a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc index
bf690d3978..e7dfe30eda 100644
--- a/UefiCpuPkg/UefiCpuPkg.dsc
+++ b/UefiCpuPkg/UefiCpuPkg.dsc
@@ -101,6 +101,9 @@
UefiCpuPkg/CpuIoPei/CpuIoPei.inf

UefiCpuPkg/Library/SecPeiDxeTimerLibUefiCpu/SecPeiDxeTimerLibUefiCpu.i
nf
UefiCpuPkg/Application/Cpuid/Cpuid.inf
+ UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf
+ UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.inf
+ UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.inf

[Components.IA32, Components.X64]
UefiCpuPkg/CpuDxe/CpuDxe.inf
--
2.14.2.windows.3


Donald Kuo
 

Hi Liming,

As we plan to add new TimerLib to use CPUID Leaf 0x15 (CPU XTAL clock frequency) to calculate TSC to resolve performance value unreliable concern.

As the code review had got approved and planning into 201908 stable tag. Please help to review whether any concern for 201908 stable tag.

Thanks,
Donald

-----Original Message-----
From: Dong, Eric
Sent: Thursday, August 15, 2019 10:46 AM
To: devel@edk2.groups.io; Kuo, Donald <donald.kuo@...>
Cc: Ni, Ray <ray.ni@...>; Zeng, Star <star.zeng@...>; Chan,
Amy <amy.chan@...>; Chaganty, Rangasai V
<rangasai.v.chaganty@...>
Subject: RE: [edk2-devel] [PATCH] UefiCpuPkg: Adding a new TSC library by
using CPUID(0x15) TSC leaf

Reviewed-by: Eric Dong <eric.dong@...>

-----Original Message-----
From: devel@edk2.groups.io [mailto:devel@edk2.groups.io] On Behalf Of
Donald Kuo
Sent: Tuesday, August 13, 2019 6:53 PM
To: devel@edk2.groups.io
Cc: Ni, Ray <ray.ni@...>; Zeng, Star <star.zeng@...>;
Dong, Eric <eric.dong@...>; Chan, Amy <amy.chan@...>;
Chaganty, Rangasai V <rangasai.v.chaganty@...>
Subject: [edk2-devel] [PATCH] UefiCpuPkg: Adding a new TSC library by
using
CPUID(0x15) TSC leaf

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=1909

Cc: Ray Ni <ray.ni@...>
Cc: Star Zeng <star.zeng@...>
Cc: Eric Dong <eric.dong@...>
Cc: Amy Chan <amy.chan@...>
Cc: Rangasai V Chaganty <rangasai.v.chaganty@...>
Signed-off-by: Donald Kuo <donald.kuo@...>
---
UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.c | 41 +++
UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf | 35 +++
UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.uni | 17 ++
UefiCpuPkg/Library/CpuTimerLib/CpuTimerLib.c | 274
+++++++++++++++++++++
UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.c | 81 ++++++
UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.inf | 37 +++
UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.uni | 17 ++
UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.c | 58 +++++
UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.inf | 36 +++
UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.uni | 17 ++
UefiCpuPkg/UefiCpuPkg.dec | 8 +
UefiCpuPkg/UefiCpuPkg.dsc | 3 +
12 files changed, 624 insertions(+)
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.c
create mode 100644
UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf
create mode 100644
UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.uni
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/CpuTimerLib.c
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.c
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.inf
create mode 100644
UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.uni
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.c
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.inf
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.uni

diff --git a/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.c
b/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.c
new file mode 100644
index 0000000000..6ddf917bad
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.c
@@ -0,0 +1,41 @@
+/** @file
+ CPUID Leaf 0x15 for Core Crystal Clock frequency instance as Base
+Timer
Library.
+
+ Copyright (c) 2019 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+
+/**
+ CPUID Leaf 0x15 for Core Crystal Clock Frequency.
+
+ The TSC counting frequency is determined by using CPUID leaf 0x15.
Frequency in MHz = Core XTAL frequency * EBX/EAX.
+ In newer flavors of the CPU, core xtal frequency is returned in ECX
+ or 0 if
not supported.
+ @return The number of TSC counts per second.
+
+**/
+UINT64
+CpuidCoreClockCalculateTscFrequency (
+ VOID
+ );
+
+/**
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+InternalGetPerformanceCounterFrequency (
+ VOID
+ )
+{
+ return CpuidCoreClockCalculateTscFrequency (); }
+
diff --git a/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf
b/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf
new file mode 100644
index 0000000000..fd93adc5f1
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf
@@ -0,0 +1,35 @@
+## @file
+# Base CPU Timer Library
+#
+# Provides basic timer support using CPUID Leaf 0x15 XTAL frequency.
+The performance # counter features are provided by the processors
+time
stamp counter.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR> #
+SPDX-License-Identifier: BSD-2-Clause-Patent # ##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = BaseCpuTimerLib
+ FILE_GUID = F10B5B91-D15A-496C-B044-B5235721AA08
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = TimerLib|SEC PEI_CORE PEIM
+ MODULE_UNI_FILE = BaseCpuTimerLib.uni
+
+[Sources]
+ CpuTimerLib.c
+ BaseCpuTimerLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ PcdLib
+ DebugLib
+
+[Pcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuCoreCrystalClockFrequency ##
+CONSUMES
diff --git a/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.uni
b/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.uni
new file mode 100644
index 0000000000..fcf2b0fbcb
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.uni
@@ -0,0 +1,17 @@
+// /** @file
+// Base CPU Timer Library
+//
+// Provides basic timer support using CPUID Leaf 0x15 XTAL frequency.
+The performance // counter features are provided by the processors
+time
stamp counter.
+//
+// Copyright (c) 2019, Intel Corporation. All rights reserved.<BR> //
+// SPDX-License-Identifier: BSD-2-Clause-Patent // // **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "CPU Timer
Library"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Provides
basic
timer support using CPUID Leaf 0x15 XTAL frequency."
+
diff --git a/UefiCpuPkg/Library/CpuTimerLib/CpuTimerLib.c
b/UefiCpuPkg/Library/CpuTimerLib/CpuTimerLib.c
new file mode 100644
index 0000000000..0b9e9384f5
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/CpuTimerLib.c
@@ -0,0 +1,274 @@
+/** @file
+ CPUID Leaf 0x15 for Core Crystal Clock frequency instance of Timer
Library.
+
+ Copyright (c) 2019 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DebugLib.h>
+#include <Register/Cpuid.h>
+
+GUID mCpuCrystalFrequencyHobGuid = { 0xe1ec5ad0, 0x8569, 0x46bd, {
+0x8d, 0xcd, 0x3b, 0x9f, 0x6f, 0x45, 0x82, 0x7a } };
+
+/**
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+InternalGetPerformanceCounterFrequency (
+ VOID
+ );
+
+/**
+ CPUID Leaf 0x15 for Core Crystal Clock Frequency.
+
+ The TSC counting frequency is determined by using CPUID leaf 0x15.
Frequency in MHz = Core XTAL frequency * EBX/EAX.
+ In newer flavors of the CPU, core xtal frequency is returned in ECX
+ or 0 if
not supported.
+ @return The number of TSC counts per second.
+
+**/
+UINT64
+CpuidCoreClockCalculateTscFrequency (
+ VOID
+ )
+{
+ UINT64 TscFrequency;
+ UINT64 CoreXtalFrequency;
+ UINT32 RegEax;
+ UINT32 RegEbx;
+ UINT32 RegEcx;
+
+ //
+ // Use CPUID leaf 0x15 Time Stamp Counter and Nominal Core Crystal
+ Clock Information // EBX returns 0 if not supported. ECX, if non
+ zero,
provides Core Xtal Frequency in hertz.
+ // TSC frequency = (ECX, Core Xtal Frequency) * EBX/EAX.
+ //
+ AsmCpuid (CPUID_TIME_STAMP_COUNTER, &RegEax, &RegEbx,
&RegEcx,
NULL);
+
+ //
+ // If EBX returns 0, the XTAL ratio is not enumerated.
+ //
+ ASSERT (RegEbx != 0);
+ //
+ // If ECX returns 0, the XTAL frequency is not enumerated.
+ //
+ if (RegEcx == 0) {
+ CoreXtalFrequency = PcdGet64 (PcdCpuCoreCrystalClockFrequency);
+ } else {
+ CoreXtalFrequency = (UINT64) RegEcx; }
+
+ //
+ // Calculate TSC frequency = (ECX, Core Xtal Frequency) * EBX/EAX
+ // TscFrequency = DivU64x32 (MultU64x32 (CoreXtalFrequency, RegEbx)
+ + (UINT64)(RegEax >> 1), RegEax);
+
+ return TscFrequency;
+}
+
+/**
+ Stalls the CPU for at least the given number of ticks.
+
+ Stalls the CPU for at least the given number of ticks. It's invoked
+ by
+ MicroSecondDelay() and NanoSecondDelay().
+
+ @param Delay A period of time to delay in ticks.
+
+**/
+VOID
+InternalCpuDelay (
+ IN UINT64 Delay
+ )
+{
+ UINT64 Ticks;
+
+ //
+ // The target timer count is calculated here // Ticks =
+ AsmReadTsc() + Delay;
+
+ //
+ // Wait until time out
+ // Timer wrap-arounds are NOT handled correctly by this function.
+ // Thus, this function must be called within 10 years of reset
+since
+ // Intel guarantees a minimum of 10 years before the TSC wraps.
+ //
+ while (AsmReadTsc() <= Ticks) {
+ CpuPause();
+ }
+}
+
+/**
+ Stalls the CPU for at least the given number of microseconds.
+
+ Stalls the CPU for the number of microseconds specified by
MicroSeconds.
+
+ @param[in] MicroSeconds The minimum number of microseconds to
delay.
+
+ @return MicroSeconds
+
+**/
+UINTN
+EFIAPI
+MicroSecondDelay (
+ IN UINTN MicroSeconds
+ )
+{
+
+ InternalCpuDelay (
+ DivU64x32 (
+ MultU64x64 (
+ MicroSeconds,
+ InternalGetPerformanceCounterFrequency ()
+ ),
+ 1000000u
+ )
+ );
+
+ return MicroSeconds;
+}
+
+/**
+ Stalls the CPU for at least the given number of nanoseconds.
+
+ Stalls the CPU for the number of nanoseconds specified by NanoSeconds.
+
+ @param NanoSeconds The minimum number of nanoseconds to delay.
+
+ @return NanoSeconds
+
+**/
+UINTN
+EFIAPI
+NanoSecondDelay (
+ IN UINTN NanoSeconds
+ )
+{
+
+ InternalCpuDelay (
+ DivU64x32 (
+ MultU64x64 (
+ NanoSeconds,
+ InternalGetPerformanceCounterFrequency ()
+ ),
+ 1000000000u
+ )
+ );
+
+ return NanoSeconds;
+}
+
+/**
+ Retrieves the current value of a 64-bit free running performance counter.
+
+ Retrieves the current value of a 64-bit free running performance
+ counter. The counter can either count up by 1 or count down by 1.
+ If the physical performance counter counts by a larger increment,
+ then the counter values must be translated. The properties of the
+ counter can be retrieved from GetPerformanceCounterProperties().
+
+ @return The current value of the free running performance counter.
+
+**/
+UINT64
+EFIAPI
+GetPerformanceCounter (
+ VOID
+ )
+{
+ return AsmReadTsc ();
+}
+
+/**
+ Retrieves the 64-bit frequency in Hz and the range of performance
+counter
+ values.
+
+ If StartValue is not NULL, then the value that the performance
+ counter starts with immediately after is it rolls over is returned
+ in StartValue. If EndValue is not NULL, then the value that the
+ performance counter end with immediately before it rolls over is
+ returned in EndValue. The 64-bit frequency of the performance
+ counter in Hz is always returned. If StartValue is less than
+ EndValue, then the performance counter counts up. If StartValue is
+ greater than EndValue, then the performance counter counts down. For
+ example, a 64-bit free running counter that counts up would have a
+ StartValue of
+ 0 and an EndValue of 0xFFFFFFFFFFFFFFFF. A 24-bit free running
+ counter
that counts down would have a StartValue of 0xFFFFFF and an EndValue of
0.
+
+ @param StartValue The value the performance counter starts with
+ when
it
+ rolls over.
+ @param EndValue The value that the performance counter ends with
before
+ it rolls over.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+EFIAPI
+GetPerformanceCounterProperties (
+ OUT UINT64 *StartValue, OPTIONAL
+ OUT UINT64 *EndValue OPTIONAL
+ )
+{
+ if (StartValue != NULL) {
+ *StartValue = 0;
+ }
+
+ if (EndValue != NULL) {
+ *EndValue = 0xffffffffffffffffULL; } return
+ InternalGetPerformanceCounterFrequency (); }
+
+/**
+ Converts elapsed ticks of performance counter to time in nanoseconds.
+
+ This function converts the elapsed ticks of running performance
+ counter to time value in unit of nanoseconds.
+
+ @param Ticks The number of elapsed ticks of running performance
counter.
+
+ @return The elapsed time in nanoseconds.
+
+**/
+UINT64
+EFIAPI
+GetTimeInNanoSecond (
+ IN UINT64 Ticks
+ )
+{
+ UINT64 Frequency;
+ UINT64 NanoSeconds;
+ UINT64 Remainder;
+ INTN Shift;
+
+ Frequency = GetPerformanceCounterProperties (NULL, NULL);
+
+ //
+ // Ticks
+ // Time = --------- x 1,000,000,000
+ // Frequency
+ //
+ NanoSeconds = MultU64x32 (DivU64x64Remainder (Ticks, Frequency,
+ &Remainder), 1000000000u);
+
+ //
+ // Ensure (Remainder * 1,000,000,000) will not overflow 64-bit.
+ // Since 2^29 < 1,000,000,000 = 0x3B9ACA00 < 2^30, Remainder should
+ <
+ 2^(64-30) = 2^34, // i.e. highest bit set in Remainder should <= 33.
+ //
+ Shift = MAX (0, HighBitSet64 (Remainder) - 33); Remainder =
+ RShiftU64 (Remainder, (UINTN) Shift); Frequency = RShiftU64
+ (Frequency, (UINTN) Shift); NanoSeconds += DivU64x64Remainder
+ (MultU64x32 (Remainder, 1000000000u), Frequency, NULL);
+
+ return NanoSeconds;
+}
+
diff --git a/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.c
b/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.c
new file mode 100644
index 0000000000..2d0ef6ab07
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.c
@@ -0,0 +1,81 @@
+/** @file
+ CPUID Leaf 0x15 for Core Crystal Clock frequency instance of Timer
Library.
+
+ Copyright (c) 2019 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+#include <Library/HobLib.h>
+
+extern GUID mCpuCrystalFrequencyHobGuid;
+
+/**
+ CPUID Leaf 0x15 for Core Crystal Clock Frequency.
+
+ The TSC counting frequency is determined by using CPUID leaf 0x15.
Frequency in MHz = Core XTAL frequency * EBX/EAX.
+ In newer flavors of the CPU, core xtal frequency is returned in ECX
+ or 0 if
not supported.
+ @return The number of TSC counts per second.
+
+**/
+UINT64
+CpuidCoreClockCalculateTscFrequency (
+ VOID
+ );
+
+//
+// Cached CPU Crystal counter frequency //
+UINT64 mCpuCrystalCounterFrequency = 0;
+
+
+/**
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+InternalGetPerformanceCounterFrequency (
+ VOID
+ )
+{
+ return mCpuCrystalCounterFrequency; }
+
+/**
+ The constructor function is to initialize CpuCrystalCounterFrequency.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The constructor always returns
RETURN_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+DxeCpuTimerLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_HOB_GUID_TYPE *GuidHob;
+
+ //
+ // Initialize CpuCrystalCounterFrequency // GuidHob =
+ GetFirstGuidHob (&mCpuCrystalFrequencyHobGuid); if (GuidHob !=
+ NULL) {
+ mCpuCrystalCounterFrequency = *(UINT64*)GET_GUID_HOB_DATA
+ (GuidHob); } else {
+ mCpuCrystalCounterFrequency =
CpuidCoreClockCalculateTscFrequency
+ (); }
+
+ return EFI_SUCCESS;
+}
+
diff --git a/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.inf
b/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.inf
new file mode 100644
index 0000000000..6c83549c87
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.inf
@@ -0,0 +1,37 @@
+## @file
+# DXE CPU Timer Library
+#
+# Provides basic timer support using CPUID Leaf 0x15 XTAL frequency.
+The performance # counter features are provided by the processors
+time
stamp counter.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR> #
+SPDX-License-Identifier: BSD-2-Clause-Patent # ##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeCpuTimerLib
+ FILE_GUID = F22CC0DA-E7DB-4E4D-ABE2-A608188233A2
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = TimerLib|DXE_CORE DXE_DRIVER
DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION
UEFI_DRIVER
SMM_CORE
+ CONSTRUCTOR = DxeCpuTimerLibConstructor
+ MODULE_UNI_FILE = DxeCpuTimerLib.uni
+
+[Sources]
+ CpuTimerLib.c
+ DxeCpuTimerLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ PcdLib
+ DebugLib
+ HobLib
+
+[Pcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuCoreCrystalClockFrequency ##
+CONSUMES
diff --git a/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.uni
b/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.uni
new file mode 100644
index 0000000000..f55b92abac
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.uni
@@ -0,0 +1,17 @@
+// /** @file
+// DXE CPU Timer Library
+//
+// Provides basic timer support using CPUID Leaf 0x15 XTAL frequency.
+The performance // counter features are provided by the processors
+time
stamp counter.
+//
+// Copyright (c) 2019, Intel Corporation. All rights reserved.<BR> //
+// SPDX-License-Identifier: BSD-2-Clause-Patent // // **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "CPU Timer
Library"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Provides
basic
timer support using CPUID Leaf 0x15 XTAL frequency."
+
diff --git a/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.c
b/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.c
new file mode 100644
index 0000000000..91a7212056
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.c
@@ -0,0 +1,58 @@
+/** @file
+ CPUID Leaf 0x15 for Core Crystal Clock frequency instance as PEI
+Timer
Library.
+
+ Copyright (c) 2019 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+#include <Library/HobLib.h>
+#include <Library/DebugLib.h>
+
+extern GUID mCpuCrystalFrequencyHobGuid;
+
+/**
+ CPUID Leaf 0x15 for Core Crystal Clock Frequency.
+
+ The TSC counting frequency is determined by using CPUID leaf 0x15.
Frequency in MHz = Core XTAL frequency * EBX/EAX.
+ In newer flavors of the CPU, core xtal frequency is returned in ECX
+ or 0 if
not supported.
+ @return The number of TSC counts per second.
+
+**/
+UINT64
+CpuidCoreClockCalculateTscFrequency (
+ VOID
+ );
+
+/**
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+InternalGetPerformanceCounterFrequency (
+ VOID
+ )
+{
+ UINT64 *CpuCrystalCounterFrequency;
+ EFI_HOB_GUID_TYPE *GuidHob;
+
+ CpuCrystalCounterFrequency = NULL;
+ GuidHob = GetFirstGuidHob (&mCpuCrystalFrequencyHobGuid); if
+ (GuidHob == NULL) {
+ CpuCrystalCounterFrequency =
(UINT64*)BuildGuidHob(&mCpuCrystalFrequencyHobGuid, sizeof
(*CpuCrystalCounterFrequency));
+ ASSERT (CpuCrystalCounterFrequency != NULL);
+ *CpuCrystalCounterFrequency = CpuidCoreClockCalculateTscFrequency
+ (); } else {
+ CpuCrystalCounterFrequency = (UINT64*)GET_GUID_HOB_DATA
(GuidHob);
+ }
+
+ return *CpuCrystalCounterFrequency; }
+
diff --git a/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.inf
b/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.inf
new file mode 100644
index 0000000000..7af0fc44a6
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.inf
@@ -0,0 +1,36 @@
+## @file
+# PEI CPU Timer Library
+#
+# Provides basic timer support using CPUID Leaf 0x15 XTAL frequency.
+The performance # counter features are provided by the processors
+time
stamp counter.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR> #
+SPDX-License-Identifier: BSD-2-Clause-Patent # ##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PeiCpuTimerLib
+ FILE_GUID = 2B13DE00-1A5F-4DD7-A298-01B08AF1015A
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = TimerLib|PEI_CORE PEIM
+ MODULE_UNI_FILE = PeiCpuTimerLib.uni
+
+[Sources]
+ CpuTimerLib.c
+ PeiCpuTimerLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ PcdLib
+ DebugLib
+ HobLib
+
+[Pcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuCoreCrystalClockFrequency ##
+CONSUMES
diff --git a/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.uni
b/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.uni
new file mode 100644
index 0000000000..49beb44908
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.uni
@@ -0,0 +1,17 @@
+// /** @file
+// PEI CPU Timer Library
+//
+// Provides basic timer support using CPUID Leaf 0x15 XTAL frequency.
+The performance // counter features are provided by the processors
+time
stamp counter.
+//
+// Copyright (c) 2019, Intel Corporation. All rights reserved.<BR> //
+// SPDX-License-Identifier: BSD-2-Clause-Patent // // **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "CPU Timer
Library"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Provides
basic
timer support using CPUID Leaf 0x15 XTAL frequency."
+
diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec
index 14ddaa8633..a94bd2ea30 100644
--- a/UefiCpuPkg/UefiCpuPkg.dec
+++ b/UefiCpuPkg/UefiCpuPkg.dec
@@ -211,6 +211,14 @@
# @Prompt If CPU features will be initialized during S3 resume.

gUefiCpuPkgTokenSpaceGuid.PcdCpuFeaturesInitOnS3Resume|FALSE|BOO
LEAN|0x0000001D

+ ## Specifies CPUID Leaf 0x15 Time Stamp Counter and Nominal Core
Crystal Clock Frequency.
+ # TSC Frequency = ECX (core crystal clock frequency) * EBX/EAX.
+ # Intel Xeon Processor Scalable Family with CPUID signature 06_55H =
25000000 (25MHz)
+ # 6th and 7th generation Intel Core processors and Intel Xeon W
Processor Family = 24000000 (24MHz)
+ # Intel Atom processors based on Goldmont Microarchitecture with
CPUID signature 06_5CH = 19200000 (19.2MHz)
+ # @Prompt Core Crystal Clock Frequency is for CPUID Leaf 0x15.ECX
+
+
gUefiCpuPkgTokenSpaceGuid.PcdCpuCoreCrystalClockFrequency|24000000|
UIN
+ T64|0x32132113
+
[PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
## Specifies max supported number of Logical Processors.
# @Prompt Configure max supported number of Logical Processors diff
--git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc index
bf690d3978..e7dfe30eda 100644
--- a/UefiCpuPkg/UefiCpuPkg.dsc
+++ b/UefiCpuPkg/UefiCpuPkg.dsc
@@ -101,6 +101,9 @@
UefiCpuPkg/CpuIoPei/CpuIoPei.inf

UefiCpuPkg/Library/SecPeiDxeTimerLibUefiCpu/SecPeiDxeTimerLibUefiCpu.i
nf
UefiCpuPkg/Application/Cpuid/Cpuid.inf
+ UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf
+ UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.inf
+ UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.inf

[Components.IA32, Components.X64]
UefiCpuPkg/CpuDxe/CpuDxe.inf
--
2.14.2.windows.3


Liming Gao
 

Donald:
This change is a new feature. Now, it is not in edk2 feature planning list. If you want to catch it into 201908 stable tag, please get approve from Stewards first. I have cc this mail to all Stewards.

For this patch, I have one minor comment. You add one PCD in UefiCpuPkg DEC. Please also add this PCD into UefiCpuPkg.uni.

Thanks
Liming

-----Original Message-----
From: Kuo, Donald
Sent: Thursday, August 15, 2019 11:02 AM
To: Dong, Eric <eric.dong@...>; devel@edk2.groups.io; Gao, Liming <liming.gao@...>
Cc: Ni, Ray <ray.ni@...>; Zeng, Star <star.zeng@...>; Chan, Amy <amy.chan@...>; Chaganty, Rangasai V
<rangasai.v.chaganty@...>; Lai, Luke <luke.lai@...>; Li, Kevin Y <kevin.y.li@...>
Subject: RE: [edk2-devel] [PATCH] UefiCpuPkg: Adding a new TSC library by using CPUID(0x15) TSC leaf

Hi Liming,

As we plan to add new TimerLib to use CPUID Leaf 0x15 (CPU XTAL clock frequency) to calculate TSC to resolve performance value
unreliable concern.

As the code review had got approved and planning into 201908 stable tag. Please help to review whether any concern for 201908 stable
tag.

Thanks,
Donald

-----Original Message-----
From: Dong, Eric
Sent: Thursday, August 15, 2019 10:46 AM
To: devel@edk2.groups.io; Kuo, Donald <donald.kuo@...>
Cc: Ni, Ray <ray.ni@...>; Zeng, Star <star.zeng@...>; Chan,
Amy <amy.chan@...>; Chaganty, Rangasai V
<rangasai.v.chaganty@...>
Subject: RE: [edk2-devel] [PATCH] UefiCpuPkg: Adding a new TSC library by
using CPUID(0x15) TSC leaf

Reviewed-by: Eric Dong <eric.dong@...>

-----Original Message-----
From: devel@edk2.groups.io [mailto:devel@edk2.groups.io] On Behalf Of
Donald Kuo
Sent: Tuesday, August 13, 2019 6:53 PM
To: devel@edk2.groups.io
Cc: Ni, Ray <ray.ni@...>; Zeng, Star <star.zeng@...>;
Dong, Eric <eric.dong@...>; Chan, Amy <amy.chan@...>;
Chaganty, Rangasai V <rangasai.v.chaganty@...>
Subject: [edk2-devel] [PATCH] UefiCpuPkg: Adding a new TSC library by
using
CPUID(0x15) TSC leaf

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=1909

Cc: Ray Ni <ray.ni@...>
Cc: Star Zeng <star.zeng@...>
Cc: Eric Dong <eric.dong@...>
Cc: Amy Chan <amy.chan@...>
Cc: Rangasai V Chaganty <rangasai.v.chaganty@...>
Signed-off-by: Donald Kuo <donald.kuo@...>
---
UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.c | 41 +++
UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf | 35 +++
UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.uni | 17 ++
UefiCpuPkg/Library/CpuTimerLib/CpuTimerLib.c | 274
+++++++++++++++++++++
UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.c | 81 ++++++
UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.inf | 37 +++
UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.uni | 17 ++
UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.c | 58 +++++
UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.inf | 36 +++
UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.uni | 17 ++
UefiCpuPkg/UefiCpuPkg.dec | 8 +
UefiCpuPkg/UefiCpuPkg.dsc | 3 +
12 files changed, 624 insertions(+)
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.c
create mode 100644
UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf
create mode 100644
UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.uni
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/CpuTimerLib.c
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.c
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.inf
create mode 100644
UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.uni
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.c
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.inf
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.uni

diff --git a/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.c
b/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.c
new file mode 100644
index 0000000000..6ddf917bad
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.c
@@ -0,0 +1,41 @@
+/** @file
+ CPUID Leaf 0x15 for Core Crystal Clock frequency instance as Base
+Timer
Library.
+
+ Copyright (c) 2019 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+
+/**
+ CPUID Leaf 0x15 for Core Crystal Clock Frequency.
+
+ The TSC counting frequency is determined by using CPUID leaf 0x15.
Frequency in MHz = Core XTAL frequency * EBX/EAX.
+ In newer flavors of the CPU, core xtal frequency is returned in ECX
+ or 0 if
not supported.
+ @return The number of TSC counts per second.
+
+**/
+UINT64
+CpuidCoreClockCalculateTscFrequency (
+ VOID
+ );
+
+/**
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+InternalGetPerformanceCounterFrequency (
+ VOID
+ )
+{
+ return CpuidCoreClockCalculateTscFrequency (); }
+
diff --git a/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf
b/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf
new file mode 100644
index 0000000000..fd93adc5f1
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf
@@ -0,0 +1,35 @@
+## @file
+# Base CPU Timer Library
+#
+# Provides basic timer support using CPUID Leaf 0x15 XTAL frequency.
+The performance # counter features are provided by the processors
+time
stamp counter.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR> #
+SPDX-License-Identifier: BSD-2-Clause-Patent # ##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = BaseCpuTimerLib
+ FILE_GUID = F10B5B91-D15A-496C-B044-B5235721AA08
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = TimerLib|SEC PEI_CORE PEIM
+ MODULE_UNI_FILE = BaseCpuTimerLib.uni
+
+[Sources]
+ CpuTimerLib.c
+ BaseCpuTimerLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ PcdLib
+ DebugLib
+
+[Pcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuCoreCrystalClockFrequency ##
+CONSUMES
diff --git a/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.uni
b/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.uni
new file mode 100644
index 0000000000..fcf2b0fbcb
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.uni
@@ -0,0 +1,17 @@
+// /** @file
+// Base CPU Timer Library
+//
+// Provides basic timer support using CPUID Leaf 0x15 XTAL frequency.
+The performance // counter features are provided by the processors
+time
stamp counter.
+//
+// Copyright (c) 2019, Intel Corporation. All rights reserved.<BR> //
+// SPDX-License-Identifier: BSD-2-Clause-Patent // // **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "CPU Timer
Library"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Provides
basic
timer support using CPUID Leaf 0x15 XTAL frequency."
+
diff --git a/UefiCpuPkg/Library/CpuTimerLib/CpuTimerLib.c
b/UefiCpuPkg/Library/CpuTimerLib/CpuTimerLib.c
new file mode 100644
index 0000000000..0b9e9384f5
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/CpuTimerLib.c
@@ -0,0 +1,274 @@
+/** @file
+ CPUID Leaf 0x15 for Core Crystal Clock frequency instance of Timer
Library.
+
+ Copyright (c) 2019 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DebugLib.h>
+#include <Register/Cpuid.h>
+
+GUID mCpuCrystalFrequencyHobGuid = { 0xe1ec5ad0, 0x8569, 0x46bd, {
+0x8d, 0xcd, 0x3b, 0x9f, 0x6f, 0x45, 0x82, 0x7a } };
+
+/**
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+InternalGetPerformanceCounterFrequency (
+ VOID
+ );
+
+/**
+ CPUID Leaf 0x15 for Core Crystal Clock Frequency.
+
+ The TSC counting frequency is determined by using CPUID leaf 0x15.
Frequency in MHz = Core XTAL frequency * EBX/EAX.
+ In newer flavors of the CPU, core xtal frequency is returned in ECX
+ or 0 if
not supported.
+ @return The number of TSC counts per second.
+
+**/
+UINT64
+CpuidCoreClockCalculateTscFrequency (
+ VOID
+ )
+{
+ UINT64 TscFrequency;
+ UINT64 CoreXtalFrequency;
+ UINT32 RegEax;
+ UINT32 RegEbx;
+ UINT32 RegEcx;
+
+ //
+ // Use CPUID leaf 0x15 Time Stamp Counter and Nominal Core Crystal
+ Clock Information // EBX returns 0 if not supported. ECX, if non
+ zero,
provides Core Xtal Frequency in hertz.
+ // TSC frequency = (ECX, Core Xtal Frequency) * EBX/EAX.
+ //
+ AsmCpuid (CPUID_TIME_STAMP_COUNTER, &RegEax, &RegEbx,
&RegEcx,
NULL);
+
+ //
+ // If EBX returns 0, the XTAL ratio is not enumerated.
+ //
+ ASSERT (RegEbx != 0);
+ //
+ // If ECX returns 0, the XTAL frequency is not enumerated.
+ //
+ if (RegEcx == 0) {
+ CoreXtalFrequency = PcdGet64 (PcdCpuCoreCrystalClockFrequency);
+ } else {
+ CoreXtalFrequency = (UINT64) RegEcx; }
+
+ //
+ // Calculate TSC frequency = (ECX, Core Xtal Frequency) * EBX/EAX
+ // TscFrequency = DivU64x32 (MultU64x32 (CoreXtalFrequency, RegEbx)
+ + (UINT64)(RegEax >> 1), RegEax);
+
+ return TscFrequency;
+}
+
+/**
+ Stalls the CPU for at least the given number of ticks.
+
+ Stalls the CPU for at least the given number of ticks. It's invoked
+ by
+ MicroSecondDelay() and NanoSecondDelay().
+
+ @param Delay A period of time to delay in ticks.
+
+**/
+VOID
+InternalCpuDelay (
+ IN UINT64 Delay
+ )
+{
+ UINT64 Ticks;
+
+ //
+ // The target timer count is calculated here // Ticks =
+ AsmReadTsc() + Delay;
+
+ //
+ // Wait until time out
+ // Timer wrap-arounds are NOT handled correctly by this function.
+ // Thus, this function must be called within 10 years of reset
+since
+ // Intel guarantees a minimum of 10 years before the TSC wraps.
+ //
+ while (AsmReadTsc() <= Ticks) {
+ CpuPause();
+ }
+}
+
+/**
+ Stalls the CPU for at least the given number of microseconds.
+
+ Stalls the CPU for the number of microseconds specified by
MicroSeconds.
+
+ @param[in] MicroSeconds The minimum number of microseconds to
delay.
+
+ @return MicroSeconds
+
+**/
+UINTN
+EFIAPI
+MicroSecondDelay (
+ IN UINTN MicroSeconds
+ )
+{
+
+ InternalCpuDelay (
+ DivU64x32 (
+ MultU64x64 (
+ MicroSeconds,
+ InternalGetPerformanceCounterFrequency ()
+ ),
+ 1000000u
+ )
+ );
+
+ return MicroSeconds;
+}
+
+/**
+ Stalls the CPU for at least the given number of nanoseconds.
+
+ Stalls the CPU for the number of nanoseconds specified by NanoSeconds.
+
+ @param NanoSeconds The minimum number of nanoseconds to delay.
+
+ @return NanoSeconds
+
+**/
+UINTN
+EFIAPI
+NanoSecondDelay (
+ IN UINTN NanoSeconds
+ )
+{
+
+ InternalCpuDelay (
+ DivU64x32 (
+ MultU64x64 (
+ NanoSeconds,
+ InternalGetPerformanceCounterFrequency ()
+ ),
+ 1000000000u
+ )
+ );
+
+ return NanoSeconds;
+}
+
+/**
+ Retrieves the current value of a 64-bit free running performance counter.
+
+ Retrieves the current value of a 64-bit free running performance
+ counter. The counter can either count up by 1 or count down by 1.
+ If the physical performance counter counts by a larger increment,
+ then the counter values must be translated. The properties of the
+ counter can be retrieved from GetPerformanceCounterProperties().
+
+ @return The current value of the free running performance counter.
+
+**/
+UINT64
+EFIAPI
+GetPerformanceCounter (
+ VOID
+ )
+{
+ return AsmReadTsc ();
+}
+
+/**
+ Retrieves the 64-bit frequency in Hz and the range of performance
+counter
+ values.
+
+ If StartValue is not NULL, then the value that the performance
+ counter starts with immediately after is it rolls over is returned
+ in StartValue. If EndValue is not NULL, then the value that the
+ performance counter end with immediately before it rolls over is
+ returned in EndValue. The 64-bit frequency of the performance
+ counter in Hz is always returned. If StartValue is less than
+ EndValue, then the performance counter counts up. If StartValue is
+ greater than EndValue, then the performance counter counts down. For
+ example, a 64-bit free running counter that counts up would have a
+ StartValue of
+ 0 and an EndValue of 0xFFFFFFFFFFFFFFFF. A 24-bit free running
+ counter
that counts down would have a StartValue of 0xFFFFFF and an EndValue of
0.
+
+ @param StartValue The value the performance counter starts with
+ when
it
+ rolls over.
+ @param EndValue The value that the performance counter ends with
before
+ it rolls over.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+EFIAPI
+GetPerformanceCounterProperties (
+ OUT UINT64 *StartValue, OPTIONAL
+ OUT UINT64 *EndValue OPTIONAL
+ )
+{
+ if (StartValue != NULL) {
+ *StartValue = 0;
+ }
+
+ if (EndValue != NULL) {
+ *EndValue = 0xffffffffffffffffULL; } return
+ InternalGetPerformanceCounterFrequency (); }
+
+/**
+ Converts elapsed ticks of performance counter to time in nanoseconds.
+
+ This function converts the elapsed ticks of running performance
+ counter to time value in unit of nanoseconds.
+
+ @param Ticks The number of elapsed ticks of running performance
counter.
+
+ @return The elapsed time in nanoseconds.
+
+**/
+UINT64
+EFIAPI
+GetTimeInNanoSecond (
+ IN UINT64 Ticks
+ )
+{
+ UINT64 Frequency;
+ UINT64 NanoSeconds;
+ UINT64 Remainder;
+ INTN Shift;
+
+ Frequency = GetPerformanceCounterProperties (NULL, NULL);
+
+ //
+ // Ticks
+ // Time = --------- x 1,000,000,000
+ // Frequency
+ //
+ NanoSeconds = MultU64x32 (DivU64x64Remainder (Ticks, Frequency,
+ &Remainder), 1000000000u);
+
+ //
+ // Ensure (Remainder * 1,000,000,000) will not overflow 64-bit.
+ // Since 2^29 < 1,000,000,000 = 0x3B9ACA00 < 2^30, Remainder should
+ <
+ 2^(64-30) = 2^34, // i.e. highest bit set in Remainder should <= 33.
+ //
+ Shift = MAX (0, HighBitSet64 (Remainder) - 33); Remainder =
+ RShiftU64 (Remainder, (UINTN) Shift); Frequency = RShiftU64
+ (Frequency, (UINTN) Shift); NanoSeconds += DivU64x64Remainder
+ (MultU64x32 (Remainder, 1000000000u), Frequency, NULL);
+
+ return NanoSeconds;
+}
+
diff --git a/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.c
b/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.c
new file mode 100644
index 0000000000..2d0ef6ab07
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.c
@@ -0,0 +1,81 @@
+/** @file
+ CPUID Leaf 0x15 for Core Crystal Clock frequency instance of Timer
Library.
+
+ Copyright (c) 2019 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+#include <Library/HobLib.h>
+
+extern GUID mCpuCrystalFrequencyHobGuid;
+
+/**
+ CPUID Leaf 0x15 for Core Crystal Clock Frequency.
+
+ The TSC counting frequency is determined by using CPUID leaf 0x15.
Frequency in MHz = Core XTAL frequency * EBX/EAX.
+ In newer flavors of the CPU, core xtal frequency is returned in ECX
+ or 0 if
not supported.
+ @return The number of TSC counts per second.
+
+**/
+UINT64
+CpuidCoreClockCalculateTscFrequency (
+ VOID
+ );
+
+//
+// Cached CPU Crystal counter frequency //
+UINT64 mCpuCrystalCounterFrequency = 0;
+
+
+/**
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+InternalGetPerformanceCounterFrequency (
+ VOID
+ )
+{
+ return mCpuCrystalCounterFrequency; }
+
+/**
+ The constructor function is to initialize CpuCrystalCounterFrequency.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The constructor always returns
RETURN_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+DxeCpuTimerLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_HOB_GUID_TYPE *GuidHob;
+
+ //
+ // Initialize CpuCrystalCounterFrequency // GuidHob =
+ GetFirstGuidHob (&mCpuCrystalFrequencyHobGuid); if (GuidHob !=
+ NULL) {
+ mCpuCrystalCounterFrequency = *(UINT64*)GET_GUID_HOB_DATA
+ (GuidHob); } else {
+ mCpuCrystalCounterFrequency =
CpuidCoreClockCalculateTscFrequency
+ (); }
+
+ return EFI_SUCCESS;
+}
+
diff --git a/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.inf
b/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.inf
new file mode 100644
index 0000000000..6c83549c87
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.inf
@@ -0,0 +1,37 @@
+## @file
+# DXE CPU Timer Library
+#
+# Provides basic timer support using CPUID Leaf 0x15 XTAL frequency.
+The performance # counter features are provided by the processors
+time
stamp counter.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR> #
+SPDX-License-Identifier: BSD-2-Clause-Patent # ##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeCpuTimerLib
+ FILE_GUID = F22CC0DA-E7DB-4E4D-ABE2-A608188233A2
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = TimerLib|DXE_CORE DXE_DRIVER
DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION
UEFI_DRIVER
SMM_CORE
+ CONSTRUCTOR = DxeCpuTimerLibConstructor
+ MODULE_UNI_FILE = DxeCpuTimerLib.uni
+
+[Sources]
+ CpuTimerLib.c
+ DxeCpuTimerLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ PcdLib
+ DebugLib
+ HobLib
+
+[Pcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuCoreCrystalClockFrequency ##
+CONSUMES
diff --git a/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.uni
b/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.uni
new file mode 100644
index 0000000000..f55b92abac
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.uni
@@ -0,0 +1,17 @@
+// /** @file
+// DXE CPU Timer Library
+//
+// Provides basic timer support using CPUID Leaf 0x15 XTAL frequency.
+The performance // counter features are provided by the processors
+time
stamp counter.
+//
+// Copyright (c) 2019, Intel Corporation. All rights reserved.<BR> //
+// SPDX-License-Identifier: BSD-2-Clause-Patent // // **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "CPU Timer
Library"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Provides
basic
timer support using CPUID Leaf 0x15 XTAL frequency."
+
diff --git a/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.c
b/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.c
new file mode 100644
index 0000000000..91a7212056
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.c
@@ -0,0 +1,58 @@
+/** @file
+ CPUID Leaf 0x15 for Core Crystal Clock frequency instance as PEI
+Timer
Library.
+
+ Copyright (c) 2019 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+#include <Library/HobLib.h>
+#include <Library/DebugLib.h>
+
+extern GUID mCpuCrystalFrequencyHobGuid;
+
+/**
+ CPUID Leaf 0x15 for Core Crystal Clock Frequency.
+
+ The TSC counting frequency is determined by using CPUID leaf 0x15.
Frequency in MHz = Core XTAL frequency * EBX/EAX.
+ In newer flavors of the CPU, core xtal frequency is returned in ECX
+ or 0 if
not supported.
+ @return The number of TSC counts per second.
+
+**/
+UINT64
+CpuidCoreClockCalculateTscFrequency (
+ VOID
+ );
+
+/**
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+InternalGetPerformanceCounterFrequency (
+ VOID
+ )
+{
+ UINT64 *CpuCrystalCounterFrequency;
+ EFI_HOB_GUID_TYPE *GuidHob;
+
+ CpuCrystalCounterFrequency = NULL;
+ GuidHob = GetFirstGuidHob (&mCpuCrystalFrequencyHobGuid); if
+ (GuidHob == NULL) {
+ CpuCrystalCounterFrequency =
(UINT64*)BuildGuidHob(&mCpuCrystalFrequencyHobGuid, sizeof
(*CpuCrystalCounterFrequency));
+ ASSERT (CpuCrystalCounterFrequency != NULL);
+ *CpuCrystalCounterFrequency = CpuidCoreClockCalculateTscFrequency
+ (); } else {
+ CpuCrystalCounterFrequency = (UINT64*)GET_GUID_HOB_DATA
(GuidHob);
+ }
+
+ return *CpuCrystalCounterFrequency; }
+
diff --git a/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.inf
b/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.inf
new file mode 100644
index 0000000000..7af0fc44a6
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.inf
@@ -0,0 +1,36 @@
+## @file
+# PEI CPU Timer Library
+#
+# Provides basic timer support using CPUID Leaf 0x15 XTAL frequency.
+The performance # counter features are provided by the processors
+time
stamp counter.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR> #
+SPDX-License-Identifier: BSD-2-Clause-Patent # ##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PeiCpuTimerLib
+ FILE_GUID = 2B13DE00-1A5F-4DD7-A298-01B08AF1015A
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = TimerLib|PEI_CORE PEIM
+ MODULE_UNI_FILE = PeiCpuTimerLib.uni
+
+[Sources]
+ CpuTimerLib.c
+ PeiCpuTimerLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ PcdLib
+ DebugLib
+ HobLib
+
+[Pcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuCoreCrystalClockFrequency ##
+CONSUMES
diff --git a/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.uni
b/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.uni
new file mode 100644
index 0000000000..49beb44908
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.uni
@@ -0,0 +1,17 @@
+// /** @file
+// PEI CPU Timer Library
+//
+// Provides basic timer support using CPUID Leaf 0x15 XTAL frequency.
+The performance // counter features are provided by the processors
+time
stamp counter.
+//
+// Copyright (c) 2019, Intel Corporation. All rights reserved.<BR> //
+// SPDX-License-Identifier: BSD-2-Clause-Patent // // **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "CPU Timer
Library"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Provides
basic
timer support using CPUID Leaf 0x15 XTAL frequency."
+
diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec
index 14ddaa8633..a94bd2ea30 100644
--- a/UefiCpuPkg/UefiCpuPkg.dec
+++ b/UefiCpuPkg/UefiCpuPkg.dec
@@ -211,6 +211,14 @@
# @Prompt If CPU features will be initialized during S3 resume.

gUefiCpuPkgTokenSpaceGuid.PcdCpuFeaturesInitOnS3Resume|FALSE|BOO
LEAN|0x0000001D

+ ## Specifies CPUID Leaf 0x15 Time Stamp Counter and Nominal Core
Crystal Clock Frequency.
+ # TSC Frequency = ECX (core crystal clock frequency) * EBX/EAX.
+ # Intel Xeon Processor Scalable Family with CPUID signature 06_55H =
25000000 (25MHz)
+ # 6th and 7th generation Intel Core processors and Intel Xeon W
Processor Family = 24000000 (24MHz)
+ # Intel Atom processors based on Goldmont Microarchitecture with
CPUID signature 06_5CH = 19200000 (19.2MHz)
+ # @Prompt Core Crystal Clock Frequency is for CPUID Leaf 0x15.ECX
+
+
gUefiCpuPkgTokenSpaceGuid.PcdCpuCoreCrystalClockFrequency|24000000|
UIN
+ T64|0x32132113
+
[PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
## Specifies max supported number of Logical Processors.
# @Prompt Configure max supported number of Logical Processors diff
--git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc index
bf690d3978..e7dfe30eda 100644
--- a/UefiCpuPkg/UefiCpuPkg.dsc
+++ b/UefiCpuPkg/UefiCpuPkg.dsc
@@ -101,6 +101,9 @@
UefiCpuPkg/CpuIoPei/CpuIoPei.inf

UefiCpuPkg/Library/SecPeiDxeTimerLibUefiCpu/SecPeiDxeTimerLibUefiCpu.i
nf
UefiCpuPkg/Application/Cpuid/Cpuid.inf
+ UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf
+ UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.inf
+ UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.inf

[Components.IA32, Components.X64]
UefiCpuPkg/CpuDxe/CpuDxe.inf
--
2.14.2.windows.3


Donald Kuo
 

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=1909

Cc: Ray Ni <ray.ni@...>
Cc: Star Zeng <star.zeng@...>
Cc: Eric Dong <eric.dong@...>
Cc: Amy Chan <amy.chan@...>
Cc: Rangasai V Chaganty <rangasai.v.chaganty@...>
Signed-off-by: Donald Kuo <donald.kuo@...>
---
UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.c | 41 +++
UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf | 35 +++
UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.uni | 17 ++
UefiCpuPkg/Library/CpuTimerLib/CpuTimerLib.c | 274 +++++++++++++++++++++
UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.c | 81 ++++++
UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.inf | 37 +++
UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.uni | 17 ++
UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.c | 58 +++++
UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.inf | 36 +++
UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.uni | 17 ++
UefiCpuPkg/UefiCpuPkg.dec | 8 +
UefiCpuPkg/UefiCpuPkg.dsc | 3 +
UefiCpuPkg/UefiCpuPkg.uni | 10 +
13 files changed, 634 insertions(+)
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.c
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.uni
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/CpuTimerLib.c
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.c
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.inf
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.uni
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.c
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.inf
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.uni

diff --git a/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.c b/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.c
new file mode 100644
index 0000000000..6ddf917bad
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.c
@@ -0,0 +1,41 @@
+/** @file
+ CPUID Leaf 0x15 for Core Crystal Clock frequency instance as Base Timer Library.
+
+ Copyright (c) 2019 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+
+/**
+ CPUID Leaf 0x15 for Core Crystal Clock Frequency.
+
+ The TSC counting frequency is determined by using CPUID leaf 0x15. Frequency in MHz = Core XTAL frequency * EBX/EAX.
+ In newer flavors of the CPU, core xtal frequency is returned in ECX or 0 if not supported.
+ @return The number of TSC counts per second.
+
+**/
+UINT64
+CpuidCoreClockCalculateTscFrequency (
+ VOID
+ );
+
+/**
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+InternalGetPerformanceCounterFrequency (
+ VOID
+ )
+{
+ return CpuidCoreClockCalculateTscFrequency ();
+}
+
diff --git a/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf b/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf
new file mode 100644
index 0000000000..fd93adc5f1
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf
@@ -0,0 +1,35 @@
+## @file
+# Base CPU Timer Library
+#
+# Provides basic timer support using CPUID Leaf 0x15 XTAL frequency. The performance
+# counter features are provided by the processors time stamp counter.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = BaseCpuTimerLib
+ FILE_GUID = F10B5B91-D15A-496C-B044-B5235721AA08
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = TimerLib|SEC PEI_CORE PEIM
+ MODULE_UNI_FILE = BaseCpuTimerLib.uni
+
+[Sources]
+ CpuTimerLib.c
+ BaseCpuTimerLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ PcdLib
+ DebugLib
+
+[Pcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuCoreCrystalClockFrequency ## CONSUMES
diff --git a/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.uni b/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.uni
new file mode 100644
index 0000000000..fcf2b0fbcb
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.uni
@@ -0,0 +1,17 @@
+// /** @file
+// Base CPU Timer Library
+//
+// Provides basic timer support using CPUID Leaf 0x15 XTAL frequency. The performance
+// counter features are provided by the processors time stamp counter.
+//
+// Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "CPU Timer Library"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Provides basic timer support using CPUID Leaf 0x15 XTAL frequency."
+
diff --git a/UefiCpuPkg/Library/CpuTimerLib/CpuTimerLib.c b/UefiCpuPkg/Library/CpuTimerLib/CpuTimerLib.c
new file mode 100644
index 0000000000..0b9e9384f5
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/CpuTimerLib.c
@@ -0,0 +1,274 @@
+/** @file
+ CPUID Leaf 0x15 for Core Crystal Clock frequency instance of Timer Library.
+
+ Copyright (c) 2019 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DebugLib.h>
+#include <Register/Cpuid.h>
+
+GUID mCpuCrystalFrequencyHobGuid = { 0xe1ec5ad0, 0x8569, 0x46bd, { 0x8d, 0xcd, 0x3b, 0x9f, 0x6f, 0x45, 0x82, 0x7a } };
+
+/**
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+InternalGetPerformanceCounterFrequency (
+ VOID
+ );
+
+/**
+ CPUID Leaf 0x15 for Core Crystal Clock Frequency.
+
+ The TSC counting frequency is determined by using CPUID leaf 0x15. Frequency in MHz = Core XTAL frequency * EBX/EAX.
+ In newer flavors of the CPU, core xtal frequency is returned in ECX or 0 if not supported.
+ @return The number of TSC counts per second.
+
+**/
+UINT64
+CpuidCoreClockCalculateTscFrequency (
+ VOID
+ )
+{
+ UINT64 TscFrequency;
+ UINT64 CoreXtalFrequency;
+ UINT32 RegEax;
+ UINT32 RegEbx;
+ UINT32 RegEcx;
+
+ //
+ // Use CPUID leaf 0x15 Time Stamp Counter and Nominal Core Crystal Clock Information
+ // EBX returns 0 if not supported. ECX, if non zero, provides Core Xtal Frequency in hertz.
+ // TSC frequency = (ECX, Core Xtal Frequency) * EBX/EAX.
+ //
+ AsmCpuid (CPUID_TIME_STAMP_COUNTER, &RegEax, &RegEbx, &RegEcx, NULL);
+
+ //
+ // If EBX returns 0, the XTAL ratio is not enumerated.
+ //
+ ASSERT (RegEbx != 0);
+ //
+ // If ECX returns 0, the XTAL frequency is not enumerated.
+ //
+ if (RegEcx == 0) {
+ CoreXtalFrequency = PcdGet64 (PcdCpuCoreCrystalClockFrequency);
+ } else {
+ CoreXtalFrequency = (UINT64) RegEcx;
+ }
+
+ //
+ // Calculate TSC frequency = (ECX, Core Xtal Frequency) * EBX/EAX
+ //
+ TscFrequency = DivU64x32 (MultU64x32 (CoreXtalFrequency, RegEbx) + (UINT64)(RegEax >> 1), RegEax);
+
+ return TscFrequency;
+}
+
+/**
+ Stalls the CPU for at least the given number of ticks.
+
+ Stalls the CPU for at least the given number of ticks. It's invoked by
+ MicroSecondDelay() and NanoSecondDelay().
+
+ @param Delay A period of time to delay in ticks.
+
+**/
+VOID
+InternalCpuDelay (
+ IN UINT64 Delay
+ )
+{
+ UINT64 Ticks;
+
+ //
+ // The target timer count is calculated here
+ //
+ Ticks = AsmReadTsc() + Delay;
+
+ //
+ // Wait until time out
+ // Timer wrap-arounds are NOT handled correctly by this function.
+ // Thus, this function must be called within 10 years of reset since
+ // Intel guarantees a minimum of 10 years before the TSC wraps.
+ //
+ while (AsmReadTsc() <= Ticks) {
+ CpuPause();
+ }
+}
+
+/**
+ Stalls the CPU for at least the given number of microseconds.
+
+ Stalls the CPU for the number of microseconds specified by MicroSeconds.
+
+ @param[in] MicroSeconds The minimum number of microseconds to delay.
+
+ @return MicroSeconds
+
+**/
+UINTN
+EFIAPI
+MicroSecondDelay (
+ IN UINTN MicroSeconds
+ )
+{
+
+ InternalCpuDelay (
+ DivU64x32 (
+ MultU64x64 (
+ MicroSeconds,
+ InternalGetPerformanceCounterFrequency ()
+ ),
+ 1000000u
+ )
+ );
+
+ return MicroSeconds;
+}
+
+/**
+ Stalls the CPU for at least the given number of nanoseconds.
+
+ Stalls the CPU for the number of nanoseconds specified by NanoSeconds.
+
+ @param NanoSeconds The minimum number of nanoseconds to delay.
+
+ @return NanoSeconds
+
+**/
+UINTN
+EFIAPI
+NanoSecondDelay (
+ IN UINTN NanoSeconds
+ )
+{
+
+ InternalCpuDelay (
+ DivU64x32 (
+ MultU64x64 (
+ NanoSeconds,
+ InternalGetPerformanceCounterFrequency ()
+ ),
+ 1000000000u
+ )
+ );
+
+ return NanoSeconds;
+}
+
+/**
+ Retrieves the current value of a 64-bit free running performance counter.
+
+ Retrieves the current value of a 64-bit free running performance counter. The
+ counter can either count up by 1 or count down by 1. If the physical
+ performance counter counts by a larger increment, then the counter values
+ must be translated. The properties of the counter can be retrieved from
+ GetPerformanceCounterProperties().
+
+ @return The current value of the free running performance counter.
+
+**/
+UINT64
+EFIAPI
+GetPerformanceCounter (
+ VOID
+ )
+{
+ return AsmReadTsc ();
+}
+
+/**
+ Retrieves the 64-bit frequency in Hz and the range of performance counter
+ values.
+
+ If StartValue is not NULL, then the value that the performance counter starts
+ with immediately after is it rolls over is returned in StartValue. If
+ EndValue is not NULL, then the value that the performance counter end with
+ immediately before it rolls over is returned in EndValue. The 64-bit
+ frequency of the performance counter in Hz is always returned. If StartValue
+ is less than EndValue, then the performance counter counts up. If StartValue
+ is greater than EndValue, then the performance counter counts down. For
+ example, a 64-bit free running counter that counts up would have a StartValue
+ of 0 and an EndValue of 0xFFFFFFFFFFFFFFFF. A 24-bit free running counter
+ that counts down would have a StartValue of 0xFFFFFF and an EndValue of 0.
+
+ @param StartValue The value the performance counter starts with when it
+ rolls over.
+ @param EndValue The value that the performance counter ends with before
+ it rolls over.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+EFIAPI
+GetPerformanceCounterProperties (
+ OUT UINT64 *StartValue, OPTIONAL
+ OUT UINT64 *EndValue OPTIONAL
+ )
+{
+ if (StartValue != NULL) {
+ *StartValue = 0;
+ }
+
+ if (EndValue != NULL) {
+ *EndValue = 0xffffffffffffffffULL;
+ }
+ return InternalGetPerformanceCounterFrequency ();
+}
+
+/**
+ Converts elapsed ticks of performance counter to time in nanoseconds.
+
+ This function converts the elapsed ticks of running performance counter to
+ time value in unit of nanoseconds.
+
+ @param Ticks The number of elapsed ticks of running performance counter.
+
+ @return The elapsed time in nanoseconds.
+
+**/
+UINT64
+EFIAPI
+GetTimeInNanoSecond (
+ IN UINT64 Ticks
+ )
+{
+ UINT64 Frequency;
+ UINT64 NanoSeconds;
+ UINT64 Remainder;
+ INTN Shift;
+
+ Frequency = GetPerformanceCounterProperties (NULL, NULL);
+
+ //
+ // Ticks
+ // Time = --------- x 1,000,000,000
+ // Frequency
+ //
+ NanoSeconds = MultU64x32 (DivU64x64Remainder (Ticks, Frequency, &Remainder), 1000000000u);
+
+ //
+ // Ensure (Remainder * 1,000,000,000) will not overflow 64-bit.
+ // Since 2^29 < 1,000,000,000 = 0x3B9ACA00 < 2^30, Remainder should < 2^(64-30) = 2^34,
+ // i.e. highest bit set in Remainder should <= 33.
+ //
+ Shift = MAX (0, HighBitSet64 (Remainder) - 33);
+ Remainder = RShiftU64 (Remainder, (UINTN) Shift);
+ Frequency = RShiftU64 (Frequency, (UINTN) Shift);
+ NanoSeconds += DivU64x64Remainder (MultU64x32 (Remainder, 1000000000u), Frequency, NULL);
+
+ return NanoSeconds;
+}
+
diff --git a/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.c b/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.c
new file mode 100644
index 0000000000..2d0ef6ab07
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.c
@@ -0,0 +1,81 @@
+/** @file
+ CPUID Leaf 0x15 for Core Crystal Clock frequency instance of Timer Library.
+
+ Copyright (c) 2019 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+#include <Library/HobLib.h>
+
+extern GUID mCpuCrystalFrequencyHobGuid;
+
+/**
+ CPUID Leaf 0x15 for Core Crystal Clock Frequency.
+
+ The TSC counting frequency is determined by using CPUID leaf 0x15. Frequency in MHz = Core XTAL frequency * EBX/EAX.
+ In newer flavors of the CPU, core xtal frequency is returned in ECX or 0 if not supported.
+ @return The number of TSC counts per second.
+
+**/
+UINT64
+CpuidCoreClockCalculateTscFrequency (
+ VOID
+ );
+
+//
+// Cached CPU Crystal counter frequency
+//
+UINT64 mCpuCrystalCounterFrequency = 0;
+
+
+/**
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+InternalGetPerformanceCounterFrequency (
+ VOID
+ )
+{
+ return mCpuCrystalCounterFrequency;
+}
+
+/**
+ The constructor function is to initialize CpuCrystalCounterFrequency.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The constructor always returns RETURN_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+DxeCpuTimerLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_HOB_GUID_TYPE *GuidHob;
+
+ //
+ // Initialize CpuCrystalCounterFrequency
+ //
+ GuidHob = GetFirstGuidHob (&mCpuCrystalFrequencyHobGuid);
+ if (GuidHob != NULL) {
+ mCpuCrystalCounterFrequency = *(UINT64*)GET_GUID_HOB_DATA (GuidHob);
+ } else {
+ mCpuCrystalCounterFrequency = CpuidCoreClockCalculateTscFrequency ();
+ }
+
+ return EFI_SUCCESS;
+}
+
diff --git a/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.inf b/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.inf
new file mode 100644
index 0000000000..6c83549c87
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.inf
@@ -0,0 +1,37 @@
+## @file
+# DXE CPU Timer Library
+#
+# Provides basic timer support using CPUID Leaf 0x15 XTAL frequency. The performance
+# counter features are provided by the processors time stamp counter.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeCpuTimerLib
+ FILE_GUID = F22CC0DA-E7DB-4E4D-ABE2-A608188233A2
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = TimerLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER SMM_CORE
+ CONSTRUCTOR = DxeCpuTimerLibConstructor
+ MODULE_UNI_FILE = DxeCpuTimerLib.uni
+
+[Sources]
+ CpuTimerLib.c
+ DxeCpuTimerLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ PcdLib
+ DebugLib
+ HobLib
+
+[Pcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuCoreCrystalClockFrequency ## CONSUMES
diff --git a/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.uni b/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.uni
new file mode 100644
index 0000000000..f55b92abac
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.uni
@@ -0,0 +1,17 @@
+// /** @file
+// DXE CPU Timer Library
+//
+// Provides basic timer support using CPUID Leaf 0x15 XTAL frequency. The performance
+// counter features are provided by the processors time stamp counter.
+//
+// Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "CPU Timer Library"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Provides basic timer support using CPUID Leaf 0x15 XTAL frequency."
+
diff --git a/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.c b/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.c
new file mode 100644
index 0000000000..91a7212056
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.c
@@ -0,0 +1,58 @@
+/** @file
+ CPUID Leaf 0x15 for Core Crystal Clock frequency instance as PEI Timer Library.
+
+ Copyright (c) 2019 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+#include <Library/HobLib.h>
+#include <Library/DebugLib.h>
+
+extern GUID mCpuCrystalFrequencyHobGuid;
+
+/**
+ CPUID Leaf 0x15 for Core Crystal Clock Frequency.
+
+ The TSC counting frequency is determined by using CPUID leaf 0x15. Frequency in MHz = Core XTAL frequency * EBX/EAX.
+ In newer flavors of the CPU, core xtal frequency is returned in ECX or 0 if not supported.
+ @return The number of TSC counts per second.
+
+**/
+UINT64
+CpuidCoreClockCalculateTscFrequency (
+ VOID
+ );
+
+/**
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+InternalGetPerformanceCounterFrequency (
+ VOID
+ )
+{
+ UINT64 *CpuCrystalCounterFrequency;
+ EFI_HOB_GUID_TYPE *GuidHob;
+
+ CpuCrystalCounterFrequency = NULL;
+ GuidHob = GetFirstGuidHob (&mCpuCrystalFrequencyHobGuid);
+ if (GuidHob == NULL) {
+ CpuCrystalCounterFrequency = (UINT64*)BuildGuidHob(&mCpuCrystalFrequencyHobGuid, sizeof (*CpuCrystalCounterFrequency));
+ ASSERT (CpuCrystalCounterFrequency != NULL);
+ *CpuCrystalCounterFrequency = CpuidCoreClockCalculateTscFrequency ();
+ } else {
+ CpuCrystalCounterFrequency = (UINT64*)GET_GUID_HOB_DATA (GuidHob);
+ }
+
+ return *CpuCrystalCounterFrequency;
+}
+
diff --git a/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.inf b/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.inf
new file mode 100644
index 0000000000..7af0fc44a6
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.inf
@@ -0,0 +1,36 @@
+## @file
+# PEI CPU Timer Library
+#
+# Provides basic timer support using CPUID Leaf 0x15 XTAL frequency. The performance
+# counter features are provided by the processors time stamp counter.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PeiCpuTimerLib
+ FILE_GUID = 2B13DE00-1A5F-4DD7-A298-01B08AF1015A
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = TimerLib|PEI_CORE PEIM
+ MODULE_UNI_FILE = PeiCpuTimerLib.uni
+
+[Sources]
+ CpuTimerLib.c
+ PeiCpuTimerLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ PcdLib
+ DebugLib
+ HobLib
+
+[Pcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuCoreCrystalClockFrequency ## CONSUMES
diff --git a/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.uni b/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.uni
new file mode 100644
index 0000000000..49beb44908
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.uni
@@ -0,0 +1,17 @@
+// /** @file
+// PEI CPU Timer Library
+//
+// Provides basic timer support using CPUID Leaf 0x15 XTAL frequency. The performance
+// counter features are provided by the processors time stamp counter.
+//
+// Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "CPU Timer Library"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Provides basic timer support using CPUID Leaf 0x15 XTAL frequency."
+
diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec
index 14ddaa8633..86ad61f64b 100644
--- a/UefiCpuPkg/UefiCpuPkg.dec
+++ b/UefiCpuPkg/UefiCpuPkg.dec
@@ -211,6 +211,14 @@
# @Prompt If CPU features will be initialized during S3 resume.
gUefiCpuPkgTokenSpaceGuid.PcdCpuFeaturesInitOnS3Resume|FALSE|BOOLEAN|0x0000001D

+ ## Specifies CPUID Leaf 0x15 Time Stamp Counter and Nominal Core Crystal Clock Frequency.
+ # TSC Frequency = ECX (core crystal clock frequency) * EBX/EAX.
+ # Intel Xeon Processor Scalable Family with CPUID signature 06_55H = 25000000 (25MHz)
+ # 6th and 7th generation Intel Core processors and Intel Xeon W Processor Family = 24000000 (24MHz)
+ # Intel Atom processors based on Goldmont Microarchitecture with CPUID signature 06_5CH = 19200000 (19.2MHz)
+ # @Prompt This PCD is the nominal frequency of the core crystal clock in Hz as is CPUID Leaf 0x15:ECX
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuCoreCrystalClockFrequency|24000000|UINT64|0x32132113
+
[PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
## Specifies max supported number of Logical Processors.
# @Prompt Configure max supported number of Logical Processors
diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc
index bf690d3978..e7dfe30eda 100644
--- a/UefiCpuPkg/UefiCpuPkg.dsc
+++ b/UefiCpuPkg/UefiCpuPkg.dsc
@@ -101,6 +101,9 @@
UefiCpuPkg/CpuIoPei/CpuIoPei.inf
UefiCpuPkg/Library/SecPeiDxeTimerLibUefiCpu/SecPeiDxeTimerLibUefiCpu.inf
UefiCpuPkg/Application/Cpuid/Cpuid.inf
+ UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf
+ UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.inf
+ UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.inf

[Components.IA32, Components.X64]
UefiCpuPkg/CpuDxe/CpuDxe.inf
diff --git a/UefiCpuPkg/UefiCpuPkg.uni b/UefiCpuPkg/UefiCpuPkg.uni
index 80af4fc1d2..fbf7680726 100644
--- a/UefiCpuPkg/UefiCpuPkg.uni
+++ b/UefiCpuPkg/UefiCpuPkg.uni
@@ -242,3 +242,13 @@
#string STR_gUefiCpuPkgTokenSpaceGuid_PcdCpuKnownGoodStackSize_HELP #language en-US "Size of good stack for an exception.\n"
"This PCD will only take into effect if PcdCpuStackGuard is enabled.\n"

+#string STR_gUefiCpuPkgTokenSpaceGuid_PcdCpuCoreCrystalClockFrequency_PROMPT #language en-US "Specifies CPUID Leaf 0x15 Time Stamp Counter and Nominal Core Crystal Clock Frequency."
+
+#string STR_gUefiCpuPkgTokenSpaceGuid_PcdCpuCoreCrystalClockFrequency_HELP #language en-US "Specifies CPUID Leaf 0x15 Time Stamp Counter and Nominal Core Crystal Clock Frequency.<BR><BR>\n"
+ "TSC Frequency = ECX (core crystal clock frequency) * EBX/EAX.<BR><BR>\n"
+ "This PCD is the nominal frequency of the core crystal clock in Hz as is CPUID Leaf 0x15:ECX.<BR><BR>\n"
+ "Default value is 24000000 for 6th and 7th generation Intel Core processors and Intel Xeon W Processor Family.<BR>\n"
+ "25000000 - Intel Xeon Processor Scalable Family with CPUID signature 06_55H(25MHz).<BR>\n"
+ "24000000 - 6th and 7th generation Intel Core processors and Intel Xeon W Processor Family(24MHz).<BR>\n"
+ "19200000 - Intel Atom processors based on Goldmont Microarchitecture with CPUID signature 06_5CH(19.2MHz).<BR>\n"
+
--
2.14.2.windows.3

Donald Kuo
 

Thanks Liming for review.

Update UefiCpuPkg.uni for review again.

Thanks,
Donald

-----Original Message-----
From: Gao, Liming
Sent: Thursday, August 15, 2019 12:03 PM
To: Kuo, Donald <donald.kuo@...>; Dong, Eric
<eric.dong@...>; devel@edk2.groups.io
Cc: Ni, Ray <ray.ni@...>; Zeng, Star <star.zeng@...>; Chan,
Amy <amy.chan@...>; Chaganty, Rangasai V
<rangasai.v.chaganty@...>; Lai, Luke <luke.lai@...>; Li, Kevin
Y <kevin.y.li@...>; Laszlo Ersek (lersek@...)
<lersek@...>; leif.lindholm@...; afish@...; Kinney,
Michael D <michael.d.kinney@...>
Subject: RE: [edk2-devel] [PATCH] UefiCpuPkg: Adding a new TSC library by
using CPUID(0x15) TSC leaf

Donald:
This change is a new feature. Now, it is not in edk2 feature planning list. If
you want to catch it into 201908 stable tag, please get approve from
Stewards first. I have cc this mail to all Stewards.

For this patch, I have one minor comment. You add one PCD in UefiCpuPkg
DEC. Please also add this PCD into UefiCpuPkg.uni.

Thanks
Liming
-----Original Message-----
From: Kuo, Donald
Sent: Thursday, August 15, 2019 11:02 AM
To: Dong, Eric <eric.dong@...>; devel@edk2.groups.io; Gao,
Liming <liming.gao@...>
Cc: Ni, Ray <ray.ni@...>; Zeng, Star <star.zeng@...>;
Chan, Amy <amy.chan@...>; Chaganty, Rangasai V
<rangasai.v.chaganty@...>; Lai, Luke <luke.lai@...>; Li,
Kevin Y <kevin.y.li@...>
Subject: RE: [edk2-devel] [PATCH] UefiCpuPkg: Adding a new TSC library
by using CPUID(0x15) TSC leaf

Hi Liming,

As we plan to add new TimerLib to use CPUID Leaf 0x15 (CPU XTAL clock
frequency) to calculate TSC to resolve performance value unreliable
concern.

As the code review had got approved and planning into 201908 stable
tag. Please help to review whether any concern for 201908 stable tag.

Thanks,
Donald

-----Original Message-----
From: Dong, Eric
Sent: Thursday, August 15, 2019 10:46 AM
To: devel@edk2.groups.io; Kuo, Donald <donald.kuo@...>
Cc: Ni, Ray <ray.ni@...>; Zeng, Star <star.zeng@...>;
Chan, Amy <amy.chan@...>; Chaganty, Rangasai V
<rangasai.v.chaganty@...>
Subject: RE: [edk2-devel] [PATCH] UefiCpuPkg: Adding a new TSC
library by using CPUID(0x15) TSC leaf

Reviewed-by: Eric Dong <eric.dong@...>

-----Original Message-----
From: devel@edk2.groups.io [mailto:devel@edk2.groups.io] On Behalf
Of Donald Kuo
Sent: Tuesday, August 13, 2019 6:53 PM
To: devel@edk2.groups.io
Cc: Ni, Ray <ray.ni@...>; Zeng, Star <star.zeng@...>;
Dong, Eric <eric.dong@...>; Chan, Amy <amy.chan@...>;
Chaganty, Rangasai V <rangasai.v.chaganty@...>
Subject: [edk2-devel] [PATCH] UefiCpuPkg: Adding a new TSC library
by using
CPUID(0x15) TSC leaf

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=1909

Cc: Ray Ni <ray.ni@...>
Cc: Star Zeng <star.zeng@...>
Cc: Eric Dong <eric.dong@...>
Cc: Amy Chan <amy.chan@...>
Cc: Rangasai V Chaganty <rangasai.v.chaganty@...>
Signed-off-by: Donald Kuo <donald.kuo@...>
---
UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.c | 41 +++
UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf | 35 +++
UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.uni | 17 ++
UefiCpuPkg/Library/CpuTimerLib/CpuTimerLib.c | 274
+++++++++++++++++++++
UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.c | 81 ++++++
UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.inf | 37 +++
UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.uni | 17 ++
UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.c | 58 +++++
UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.inf | 36 +++
UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.uni | 17 ++
UefiCpuPkg/UefiCpuPkg.dec | 8 +
UefiCpuPkg/UefiCpuPkg.dsc | 3 +
12 files changed, 624 insertions(+) create mode 100644
UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.c
create mode 100644
UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf
create mode 100644
UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.uni
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/CpuTimerLib.c
create mode 100644
UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.c
create mode 100644
UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.inf
create mode 100644
UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.uni
create mode 100644
UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.c
create mode 100644
UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.inf
create mode 100644
UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.uni

diff --git a/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.c
b/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.c
new file mode 100644
index 0000000000..6ddf917bad
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.c
@@ -0,0 +1,41 @@
+/** @file
+ CPUID Leaf 0x15 for Core Crystal Clock frequency instance as
+Base Timer
Library.
+
+ Copyright (c) 2019 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+
+/**
+ CPUID Leaf 0x15 for Core Crystal Clock Frequency.
+
+ The TSC counting frequency is determined by using CPUID leaf 0x15.
Frequency in MHz = Core XTAL frequency * EBX/EAX.
+ In newer flavors of the CPU, core xtal frequency is returned in
+ ECX or 0 if
not supported.
+ @return The number of TSC counts per second.
+
+**/
+UINT64
+CpuidCoreClockCalculateTscFrequency (
+ VOID
+ );
+
+/**
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+InternalGetPerformanceCounterFrequency (
+ VOID
+ )
+{
+ return CpuidCoreClockCalculateTscFrequency (); }
+
diff --git a/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf
b/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf
new file mode 100644
index 0000000000..fd93adc5f1
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf
@@ -0,0 +1,35 @@
+## @file
+# Base CPU Timer Library
+#
+# Provides basic timer support using CPUID Leaf 0x15 XTAL frequency.
+The performance # counter features are provided by the
+processors time
stamp counter.
+#
+# Copyright (c) 2019, Intel Corporation. All rights
+reserved.<BR> #
+SPDX-License-Identifier: BSD-2-Clause-Patent # ##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = BaseCpuTimerLib
+ FILE_GUID = F10B5B91-D15A-496C-B044-B5235721AA08
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = TimerLib|SEC PEI_CORE PEIM
+ MODULE_UNI_FILE = BaseCpuTimerLib.uni
+
+[Sources]
+ CpuTimerLib.c
+ BaseCpuTimerLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ PcdLib
+ DebugLib
+
+[Pcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuCoreCrystalClockFrequency ##
+CONSUMES
diff --git a/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.uni
b/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.uni
new file mode 100644
index 0000000000..fcf2b0fbcb
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.uni
@@ -0,0 +1,17 @@
+// /** @file
+// Base CPU Timer Library
+//
+// Provides basic timer support using CPUID Leaf 0x15 XTAL frequency.
+The performance // counter features are provided by the
+processors time
stamp counter.
+//
+// Copyright (c) 2019, Intel Corporation. All rights
+reserved.<BR> // // SPDX-License-Identifier: BSD-2-Clause-Patent
+// // **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "CPU Timer
Library"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Provides
basic
timer support using CPUID Leaf 0x15 XTAL frequency."
+
diff --git a/UefiCpuPkg/Library/CpuTimerLib/CpuTimerLib.c
b/UefiCpuPkg/Library/CpuTimerLib/CpuTimerLib.c
new file mode 100644
index 0000000000..0b9e9384f5
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/CpuTimerLib.c
@@ -0,0 +1,274 @@
+/** @file
+ CPUID Leaf 0x15 for Core Crystal Clock frequency instance of
+Timer
Library.
+
+ Copyright (c) 2019 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DebugLib.h>
+#include <Register/Cpuid.h>
+
+GUID mCpuCrystalFrequencyHobGuid = { 0xe1ec5ad0, 0x8569, 0x46bd,
+{ 0x8d, 0xcd, 0x3b, 0x9f, 0x6f, 0x45, 0x82, 0x7a } };
+
+/**
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+InternalGetPerformanceCounterFrequency (
+ VOID
+ );
+
+/**
+ CPUID Leaf 0x15 for Core Crystal Clock Frequency.
+
+ The TSC counting frequency is determined by using CPUID leaf 0x15.
Frequency in MHz = Core XTAL frequency * EBX/EAX.
+ In newer flavors of the CPU, core xtal frequency is returned in
+ ECX or 0 if
not supported.
+ @return The number of TSC counts per second.
+
+**/
+UINT64
+CpuidCoreClockCalculateTscFrequency (
+ VOID
+ )
+{
+ UINT64 TscFrequency;
+ UINT64 CoreXtalFrequency;
+ UINT32 RegEax;
+ UINT32 RegEbx;
+ UINT32 RegEcx;
+
+ //
+ // Use CPUID leaf 0x15 Time Stamp Counter and Nominal Core
+ Crystal Clock Information // EBX returns 0 if not supported.
+ ECX, if non zero,
provides Core Xtal Frequency in hertz.
+ // TSC frequency = (ECX, Core Xtal Frequency) * EBX/EAX.
+ //
+ AsmCpuid (CPUID_TIME_STAMP_COUNTER, &RegEax, &RegEbx,
&RegEcx,
NULL);
+
+ //
+ // If EBX returns 0, the XTAL ratio is not enumerated.
+ //
+ ASSERT (RegEbx != 0);
+ //
+ // If ECX returns 0, the XTAL frequency is not enumerated.
+ //
+ if (RegEcx == 0) {
+ CoreXtalFrequency = PcdGet64
+ (PcdCpuCoreCrystalClockFrequency);
+ } else {
+ CoreXtalFrequency = (UINT64) RegEcx; }
+
+ //
+ // Calculate TSC frequency = (ECX, Core Xtal Frequency) *
+ EBX/EAX // TscFrequency = DivU64x32 (MultU64x32
+ (CoreXtalFrequency, RegEbx)
+ + (UINT64)(RegEax >> 1), RegEax);
+
+ return TscFrequency;
+}
+
+/**
+ Stalls the CPU for at least the given number of ticks.
+
+ Stalls the CPU for at least the given number of ticks. It's
+ invoked by
+ MicroSecondDelay() and NanoSecondDelay().
+
+ @param Delay A period of time to delay in ticks.
+
+**/
+VOID
+InternalCpuDelay (
+ IN UINT64 Delay
+ )
+{
+ UINT64 Ticks;
+
+ //
+ // The target timer count is calculated here // Ticks =
+ AsmReadTsc() + Delay;
+
+ //
+ // Wait until time out
+ // Timer wrap-arounds are NOT handled correctly by this function.
+ // Thus, this function must be called within 10 years of reset
+since
+ // Intel guarantees a minimum of 10 years before the TSC wraps.
+ //
+ while (AsmReadTsc() <= Ticks) {
+ CpuPause();
+ }
+}
+
+/**
+ Stalls the CPU for at least the given number of microseconds.
+
+ Stalls the CPU for the number of microseconds specified by
MicroSeconds.
+
+ @param[in] MicroSeconds The minimum number of microseconds
to
delay.
+
+ @return MicroSeconds
+
+**/
+UINTN
+EFIAPI
+MicroSecondDelay (
+ IN UINTN MicroSeconds
+ )
+{
+
+ InternalCpuDelay (
+ DivU64x32 (
+ MultU64x64 (
+ MicroSeconds,
+ InternalGetPerformanceCounterFrequency ()
+ ),
+ 1000000u
+ )
+ );
+
+ return MicroSeconds;
+}
+
+/**
+ Stalls the CPU for at least the given number of nanoseconds.
+
+ Stalls the CPU for the number of nanoseconds specified by
NanoSeconds.
+
+ @param NanoSeconds The minimum number of nanoseconds to
delay.
+
+ @return NanoSeconds
+
+**/
+UINTN
+EFIAPI
+NanoSecondDelay (
+ IN UINTN NanoSeconds
+ )
+{
+
+ InternalCpuDelay (
+ DivU64x32 (
+ MultU64x64 (
+ NanoSeconds,
+ InternalGetPerformanceCounterFrequency ()
+ ),
+ 1000000000u
+ )
+ );
+
+ return NanoSeconds;
+}
+
+/**
+ Retrieves the current value of a 64-bit free running performance
counter.
+
+ Retrieves the current value of a 64-bit free running
+ performance counter. The counter can either count up by 1 or count
down by 1.
+ If the physical performance counter counts by a larger
+ increment, then the counter values must be translated. The
+ properties of the counter can be retrieved from
GetPerformanceCounterProperties().
+
+ @return The current value of the free running performance counter.
+
+**/
+UINT64
+EFIAPI
+GetPerformanceCounter (
+ VOID
+ )
+{
+ return AsmReadTsc ();
+}
+
+/**
+ Retrieves the 64-bit frequency in Hz and the range of
+performance counter
+ values.
+
+ If StartValue is not NULL, then the value that the performance
+ counter starts with immediately after is it rolls over is
+ returned in StartValue. If EndValue is not NULL, then the value
+ that the performance counter end with immediately before it
+ rolls over is returned in EndValue. The 64-bit frequency of the
+ performance counter in Hz is always returned. If StartValue is
+ less than EndValue, then the performance counter counts up. If
+ StartValue is greater than EndValue, then the performance
+ counter counts down. For example, a 64-bit free running counter
+ that counts up would have a StartValue of
+ 0 and an EndValue of 0xFFFFFFFFFFFFFFFF. A 24-bit free running
+ counter
that counts down would have a StartValue of 0xFFFFFF and an
EndValue of
0.
+
+ @param StartValue The value the performance counter starts
+ with when
it
+ rolls over.
+ @param EndValue The value that the performance counter ends
with
before
+ it rolls over.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+EFIAPI
+GetPerformanceCounterProperties (
+ OUT UINT64 *StartValue, OPTIONAL
+ OUT UINT64 *EndValue OPTIONAL
+ )
+{
+ if (StartValue != NULL) {
+ *StartValue = 0;
+ }
+
+ if (EndValue != NULL) {
+ *EndValue = 0xffffffffffffffffULL; } return
+ InternalGetPerformanceCounterFrequency (); }
+
+/**
+ Converts elapsed ticks of performance counter to time in
nanoseconds.
+
+ This function converts the elapsed ticks of running performance
+ counter to time value in unit of nanoseconds.
+
+ @param Ticks The number of elapsed ticks of running
performance
counter.
+
+ @return The elapsed time in nanoseconds.
+
+**/
+UINT64
+EFIAPI
+GetTimeInNanoSecond (
+ IN UINT64 Ticks
+ )
+{
+ UINT64 Frequency;
+ UINT64 NanoSeconds;
+ UINT64 Remainder;
+ INTN Shift;
+
+ Frequency = GetPerformanceCounterProperties (NULL, NULL);
+
+ //
+ // Ticks
+ // Time = --------- x 1,000,000,000
+ // Frequency
+ //
+ NanoSeconds = MultU64x32 (DivU64x64Remainder (Ticks, Frequency,
+ &Remainder), 1000000000u);
+
+ //
+ // Ensure (Remainder * 1,000,000,000) will not overflow 64-bit.
+ // Since 2^29 < 1,000,000,000 = 0x3B9ACA00 < 2^30, Remainder
+ should <
+ 2^(64-30) = 2^34, // i.e. highest bit set in Remainder should <= 33.
+ //
+ Shift = MAX (0, HighBitSet64 (Remainder) - 33); Remainder =
+ RShiftU64 (Remainder, (UINTN) Shift); Frequency = RShiftU64
+ (Frequency, (UINTN) Shift); NanoSeconds += DivU64x64Remainder
+ (MultU64x32 (Remainder, 1000000000u), Frequency, NULL);
+
+ return NanoSeconds;
+}
+
diff --git a/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.c
b/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.c
new file mode 100644
index 0000000000..2d0ef6ab07
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.c
@@ -0,0 +1,81 @@
+/** @file
+ CPUID Leaf 0x15 for Core Crystal Clock frequency instance of
+Timer
Library.
+
+ Copyright (c) 2019 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+#include <Library/HobLib.h>
+
+extern GUID mCpuCrystalFrequencyHobGuid;
+
+/**
+ CPUID Leaf 0x15 for Core Crystal Clock Frequency.
+
+ The TSC counting frequency is determined by using CPUID leaf 0x15.
Frequency in MHz = Core XTAL frequency * EBX/EAX.
+ In newer flavors of the CPU, core xtal frequency is returned in
+ ECX or 0 if
not supported.
+ @return The number of TSC counts per second.
+
+**/
+UINT64
+CpuidCoreClockCalculateTscFrequency (
+ VOID
+ );
+
+//
+// Cached CPU Crystal counter frequency //
+UINT64 mCpuCrystalCounterFrequency = 0;
+
+
+/**
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+InternalGetPerformanceCounterFrequency (
+ VOID
+ )
+{
+ return mCpuCrystalCounterFrequency; }
+
+/**
+ The constructor function is to initialize CpuCrystalCounterFrequency.
+
+ @param ImageHandle The firmware allocated handle for the EFI
image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The constructor always returns
RETURN_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+DxeCpuTimerLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_HOB_GUID_TYPE *GuidHob;
+
+ //
+ // Initialize CpuCrystalCounterFrequency // GuidHob =
+ GetFirstGuidHob (&mCpuCrystalFrequencyHobGuid); if (GuidHob !=
+ NULL) {
+ mCpuCrystalCounterFrequency = *(UINT64*)GET_GUID_HOB_DATA
+ (GuidHob); } else {
+ mCpuCrystalCounterFrequency =
CpuidCoreClockCalculateTscFrequency
+ (); }
+
+ return EFI_SUCCESS;
+}
+
diff --git a/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.inf
b/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.inf
new file mode 100644
index 0000000000..6c83549c87
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.inf
@@ -0,0 +1,37 @@
+## @file
+# DXE CPU Timer Library
+#
+# Provides basic timer support using CPUID Leaf 0x15 XTAL frequency.
+The performance # counter features are provided by the
+processors time
stamp counter.
+#
+# Copyright (c) 2019, Intel Corporation. All rights
+reserved.<BR> #
+SPDX-License-Identifier: BSD-2-Clause-Patent # ##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeCpuTimerLib
+ FILE_GUID = F22CC0DA-E7DB-4E4D-ABE2-A608188233A2
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = TimerLib|DXE_CORE DXE_DRIVER
DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION
UEFI_DRIVER
SMM_CORE
+ CONSTRUCTOR = DxeCpuTimerLibConstructor
+ MODULE_UNI_FILE = DxeCpuTimerLib.uni
+
+[Sources]
+ CpuTimerLib.c
+ DxeCpuTimerLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ PcdLib
+ DebugLib
+ HobLib
+
+[Pcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuCoreCrystalClockFrequency ##
+CONSUMES
diff --git a/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.uni
b/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.uni
new file mode 100644
index 0000000000..f55b92abac
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.uni
@@ -0,0 +1,17 @@
+// /** @file
+// DXE CPU Timer Library
+//
+// Provides basic timer support using CPUID Leaf 0x15 XTAL frequency.
+The performance // counter features are provided by the
+processors time
stamp counter.
+//
+// Copyright (c) 2019, Intel Corporation. All rights
+reserved.<BR> // // SPDX-License-Identifier: BSD-2-Clause-Patent
+// // **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "CPU Timer
Library"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Provides
basic
timer support using CPUID Leaf 0x15 XTAL frequency."
+
diff --git a/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.c
b/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.c
new file mode 100644
index 0000000000..91a7212056
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.c
@@ -0,0 +1,58 @@
+/** @file
+ CPUID Leaf 0x15 for Core Crystal Clock frequency instance as
+PEI Timer
Library.
+
+ Copyright (c) 2019 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+#include <Library/HobLib.h>
+#include <Library/DebugLib.h>
+
+extern GUID mCpuCrystalFrequencyHobGuid;
+
+/**
+ CPUID Leaf 0x15 for Core Crystal Clock Frequency.
+
+ The TSC counting frequency is determined by using CPUID leaf 0x15.
Frequency in MHz = Core XTAL frequency * EBX/EAX.
+ In newer flavors of the CPU, core xtal frequency is returned in
+ ECX or 0 if
not supported.
+ @return The number of TSC counts per second.
+
+**/
+UINT64
+CpuidCoreClockCalculateTscFrequency (
+ VOID
+ );
+
+/**
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+InternalGetPerformanceCounterFrequency (
+ VOID
+ )
+{
+ UINT64 *CpuCrystalCounterFrequency;
+ EFI_HOB_GUID_TYPE *GuidHob;
+
+ CpuCrystalCounterFrequency = NULL; GuidHob = GetFirstGuidHob
+ (&mCpuCrystalFrequencyHobGuid); if (GuidHob == NULL) {
+ CpuCrystalCounterFrequency =
(UINT64*)BuildGuidHob(&mCpuCrystalFrequencyHobGuid, sizeof
(*CpuCrystalCounterFrequency));
+ ASSERT (CpuCrystalCounterFrequency != NULL);
+ *CpuCrystalCounterFrequency =
+ CpuidCoreClockCalculateTscFrequency
+ (); } else {
+ CpuCrystalCounterFrequency = (UINT64*)GET_GUID_HOB_DATA
(GuidHob);
+ }
+
+ return *CpuCrystalCounterFrequency; }
+
diff --git a/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.inf
b/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.inf
new file mode 100644
index 0000000000..7af0fc44a6
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.inf
@@ -0,0 +1,36 @@
+## @file
+# PEI CPU Timer Library
+#
+# Provides basic timer support using CPUID Leaf 0x15 XTAL frequency.
+The performance # counter features are provided by the
+processors time
stamp counter.
+#
+# Copyright (c) 2019, Intel Corporation. All rights
+reserved.<BR> #
+SPDX-License-Identifier: BSD-2-Clause-Patent # ##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PeiCpuTimerLib
+ FILE_GUID = 2B13DE00-1A5F-4DD7-A298-01B08AF1015A
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = TimerLib|PEI_CORE PEIM
+ MODULE_UNI_FILE = PeiCpuTimerLib.uni
+
+[Sources]
+ CpuTimerLib.c
+ PeiCpuTimerLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ PcdLib
+ DebugLib
+ HobLib
+
+[Pcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuCoreCrystalClockFrequency ##
+CONSUMES
diff --git a/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.uni
b/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.uni
new file mode 100644
index 0000000000..49beb44908
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.uni
@@ -0,0 +1,17 @@
+// /** @file
+// PEI CPU Timer Library
+//
+// Provides basic timer support using CPUID Leaf 0x15 XTAL frequency.
+The performance // counter features are provided by the
+processors time
stamp counter.
+//
+// Copyright (c) 2019, Intel Corporation. All rights
+reserved.<BR> // // SPDX-License-Identifier: BSD-2-Clause-Patent
+// // **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "CPU Timer
Library"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Provides
basic
timer support using CPUID Leaf 0x15 XTAL frequency."
+
diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec
index 14ddaa8633..a94bd2ea30 100644
--- a/UefiCpuPkg/UefiCpuPkg.dec
+++ b/UefiCpuPkg/UefiCpuPkg.dec
@@ -211,6 +211,14 @@
# @Prompt If CPU features will be initialized during S3 resume.

gUefiCpuPkgTokenSpaceGuid.PcdCpuFeaturesInitOnS3Resume|FALSE|BOO
LEAN|0x0000001D

+ ## Specifies CPUID Leaf 0x15 Time Stamp Counter and Nominal
+ Core
Crystal Clock Frequency.
+ # TSC Frequency = ECX (core crystal clock frequency) * EBX/EAX.
+ # Intel Xeon Processor Scalable Family with CPUID signature 06_55H
=
25000000 (25MHz)
+ # 6th and 7th generation Intel Core processors and Intel Xeon W
Processor Family = 24000000 (24MHz)
+ # Intel Atom processors based on Goldmont Microarchitecture with
CPUID signature 06_5CH = 19200000 (19.2MHz)
+ # @Prompt Core Crystal Clock Frequency is for CPUID Leaf
+ 0x15.ECX
+
+
gUefiCpuPkgTokenSpaceGuid.PcdCpuCoreCrystalClockFrequency|24000000|
UIN
+ T64|0x32132113
+
[PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic,
PcdsDynamicEx]
## Specifies max supported number of Logical Processors.
# @Prompt Configure max supported number of Logical Processors
diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc
index bf690d3978..e7dfe30eda 100644
--- a/UefiCpuPkg/UefiCpuPkg.dsc
+++ b/UefiCpuPkg/UefiCpuPkg.dsc
@@ -101,6 +101,9 @@
UefiCpuPkg/CpuIoPei/CpuIoPei.inf

UefiCpuPkg/Library/SecPeiDxeTimerLibUefiCpu/SecPeiDxeTimerLibUefiCpu
.i
nf
UefiCpuPkg/Application/Cpuid/Cpuid.inf
+ UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf
+ UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.inf
+ UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.inf

[Components.IA32, Components.X64]
UefiCpuPkg/CpuDxe/CpuDxe.inf
--
2.14.2.windows.3


Vitaly Cheptsov
 

Hello,

Thank you for the patch! I reviewed the code and noticed select issues explained below.

1. The following construction:

if (RegEbx == 0) {
DEBUG ((DEBUG_ERROR, "The CPU is not capble for Core Crystal Clock Frequency !!\n"));
ASSERT (RegEbx != 0);
}

Does not look good to me, and in my opinion, should be written differently:

if (RegEbx == 0 || RegEax == 0) {
DEBUG ((DEBUG_ERROR, "The CPU is not capble for Core Crystal Clock Frequency !!\n"));
ASSERT (RegEbx != 0);
  ASSERT (RegEax != 0);
  return 0;
}

The reason for the above code being wrong is potential division by zero below, which behaviour is undefined (and in fact unknown due to unspecified interrupt table state). Even though the intent is to not permit the use of this library on an unsupported platform, runtime checks and assertions are essentially NO-OPs, should be separate and not confused. For this to work properly the call to CpuidCoreClockCalculateTscFrequency should happen in library constructor with EFI_UNSUPPORTED return on CpuidCoreClockCalculateTscFrequency returning 0.

2. The notes about crystal clock frequency for 06_55H CPU signature:
"25000000 - Intel Xeon Processor Scalable Family with CPUID signature 06_55H(25MHz).<BR>\n"
# Intel Xeon Processor Scalable Family with CPUID signature 06_55H = 25000000 (25MHz)

are misleading in both this library and Intel SDM. Intel Xeon W processors have the same CPUID signature (06_55H), they report 0 crystal clock frequency, and their crystal clock frequency is 24 MHz. This should at least be mentioned in the lower part mentioning Intel Xeon W Processor Family(24MHz).

Actually, given that many Intel guys are here, I wonder whether anybody knows if there is any better approach to distinguish Xeon Scalable CPUs and Xeon W CPUs besides using brand string or using marketing frequency from CPUID 16H to determine crystal clock frequency (this is what Linux does at the moment)?

3. Intel Atom Denverton with CPUID signature (06_5FH), also known as Goldmont X, reports 0 crystal clock frequency as well, and has 25 MHz frequency. This is missing from SDM, but once again I believe it should be included in the two places from the above to avoid confusion.

Besides these 3 points, honestly, the library itself appears to be very limited for anything but embedding it into the firmware with known hardware, which already works just fine by defining the PCD. Missing 0 crystal clock frequency handling in runtime with hardcoding the PCD value looks very bad, because the number of modern Intel CPU models reporting 0 crystal clock frequency and having non 24 MHz frequency is quite far from 0. This makes the library essentially impossible to use in any UEFI application or third-party product even when targeting Skylake+ generation. To resolute this I vote for additional detection functionality to be added to the library to obtain crystal clock frequency when the CPUID reports 0. The PCD could be the last resort when no other method works. My opinion is that this should be resolved prior to merging the patch.

Best regards,
Vitaly

Donald Kuo
 

Hi Vitaly,

 

Appreciated for reviewing very detail. And looks your captured some piece of code is older version. And should be ok, I do got your point.

 

Item #1

-          I do missed RegEax error handling in case for CpuidCoreClockCalculateTscFrequency () should return 0 and EFI_UNSUPPORTED. AR: Will update it.

 

Item #2:

-          Actually the information is from SDM Table 18-85

o   As we know CPUID signature could be hard to identify processor XTAL frequency is? So we only check CPUID Leaf 0x15

o   And the PCD will be defined depends on platform specific and during project early development. Based on SDM, Intel processor for CPUID.15h EAX and EBX is enumerated, but ECX could be possible not enumerated. So that is why we based on  SDM Table 18-85 to create PCD as below:

§  Intel Xeon Server family: 25MHz

§  Intel Core and Intel Xeon W family: 24MHz

§  Intel Atom : 19.2MHz

§  So regards the “06_55h” might cause the confused, we could review it whether remove it??

Item #3:

-          Again, the XTAL frequency is optional and should be define in early phase of new project. Default should still use AcpiTimer.

o    Platform / developer owner should well know the CPU generation XTAL frequency is? Server / Client / Atom ?

o   For those CPU not supported should still use AcpiTimerLib (default)

 

Thanks,

Donald

 

From: vit9696 via [] [mailto:vit9696=protonmail.com@[]]
Sent: Thursday, August 15, 2019 3:20 PM
To: Kuo, Donald <donald.kuo@...>; devel@edk2.groups.io
Subject: Re: [edk2-devel] [PATCH] UefiCpuPkg: Adding a new TSC library by using CPUID(0x15) TSC leaf

 

Hello,

Thank you for the patch! I reviewed the code and noticed select issues explained below.

1. The following construction:

if (RegEbx == 0) {
DEBUG ((DEBUG_ERROR, "The CPU is not capble for Core Crystal Clock Frequency !!\n"));
ASSERT (RegEbx != 0);
}

Does not look good to me, and in my opinion, should be written differently:

if (RegEbx == 0 || RegEax == 0) {
DEBUG ((DEBUG_ERROR, "The CPU is not capble for Core Crystal Clock Frequency !!\n"));
ASSERT (RegEbx != 0);
  ASSERT (RegEax != 0);
  return 0;
}

The reason for the above code being wrong is potential division by zero below, which behaviour is undefined (and in fact unknown due to unspecified interrupt table state). Even though the intent is to not permit the use of this library on an unsupported platform, runtime checks and assertions are essentially NO-OPs, should be separate and not confused. For this to work properly the call to CpuidCoreClockCalculateTscFrequency should happen in library constructor with EFI_UNSUPPORTED return on CpuidCoreClockCalculateTscFrequency returning 0.

2. The notes about crystal clock frequency for 06_55H CPU signature:
"25000000 - Intel Xeon Processor Scalable Family with CPUID signature 06_55H(25MHz).<BR>\n"
# Intel Xeon Processor Scalable Family with CPUID signature 06_55H = 25000000 (25MHz)

are misleading in both this library and Intel SDM. Intel Xeon W processors have the same CPUID signature (06_55H), they report 0 crystal clock frequency, and their crystal clock frequency is 24 MHz. This should at least be mentioned in the lower part mentioning Intel Xeon W Processor Family(24MHz).

Actually, given that many Intel guys are here, I wonder whether anybody knows if there is any better approach to distinguish Xeon Scalable CPUs and Xeon W CPUs besides using brand string or using marketing frequency from CPUID 16H to determine crystal clock frequency (this is what Linux does at the moment)?

3. Intel Atom Denverton with CPUID signature (06_5FH), also known as Goldmont X, reports 0 crystal clock frequency as well, and has 25 MHz frequency. This is missing from SDM, but once again I believe it should be included in the two places from the above to avoid confusion.

Besides these 3 points, honestly, the library itself appears to be very limited for anything but embedding it into the firmware with known hardware, which already works just fine by defining the PCD. Missing 0 crystal clock frequency handling in runtime with hardcoding the PCD value looks very bad, because the number of modern Intel CPU models reporting 0 crystal clock frequency and having non 24 MHz frequency is quite far from 0. This makes the library essentially impossible to use in any UEFI application or third-party product even when targeting Skylake+ generation. To resolute this I vote for additional detection functionality to be added to the library to obtain crystal clock frequency when the CPUID reports 0. The PCD could be the last resort when no other method works. My opinion is that this should be resolved prior to merging the patch.

Best regards,
Vitaly

Donald Kuo
 

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=1909

Cc: Ray Ni <ray.ni@...>
Cc: Star Zeng <star.zeng@...>
Cc: Eric Dong <eric.dong@...>
Cc: Amy Chan <amy.chan@...>
Cc: Rangasai V Chaganty <rangasai.v.chaganty@...>
Signed-off-by: Donald Kuo <donald.kuo@...>
---
UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.c | 41 +++
UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf | 35 +++
UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.uni | 17 ++
UefiCpuPkg/Library/CpuTimerLib/CpuTimerLib.c | 279 +++++++++++++++++++++
UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.c | 85 +++++++
UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.inf | 37 +++
UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.uni | 17 ++
UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.c | 58 +++++
UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.inf | 36 +++
UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.uni | 17 ++
UefiCpuPkg/UefiCpuPkg.dec | 8 +
UefiCpuPkg/UefiCpuPkg.dsc | 3 +
UefiCpuPkg/UefiCpuPkg.uni | 10 +
13 files changed, 643 insertions(+)
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.c
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.uni
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/CpuTimerLib.c
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.c
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.inf
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.uni
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.c
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.inf
create mode 100644 UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.uni

diff --git a/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.c b/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.c
new file mode 100644
index 0000000000..6ddf917bad
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.c
@@ -0,0 +1,41 @@
+/** @file
+ CPUID Leaf 0x15 for Core Crystal Clock frequency instance as Base Timer Library.
+
+ Copyright (c) 2019 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+
+/**
+ CPUID Leaf 0x15 for Core Crystal Clock Frequency.
+
+ The TSC counting frequency is determined by using CPUID leaf 0x15. Frequency in MHz = Core XTAL frequency * EBX/EAX.
+ In newer flavors of the CPU, core xtal frequency is returned in ECX or 0 if not supported.
+ @return The number of TSC counts per second.
+
+**/
+UINT64
+CpuidCoreClockCalculateTscFrequency (
+ VOID
+ );
+
+/**
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+InternalGetPerformanceCounterFrequency (
+ VOID
+ )
+{
+ return CpuidCoreClockCalculateTscFrequency ();
+}
+
diff --git a/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf b/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf
new file mode 100644
index 0000000000..fd93adc5f1
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf
@@ -0,0 +1,35 @@
+## @file
+# Base CPU Timer Library
+#
+# Provides basic timer support using CPUID Leaf 0x15 XTAL frequency. The performance
+# counter features are provided by the processors time stamp counter.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = BaseCpuTimerLib
+ FILE_GUID = F10B5B91-D15A-496C-B044-B5235721AA08
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = TimerLib|SEC PEI_CORE PEIM
+ MODULE_UNI_FILE = BaseCpuTimerLib.uni
+
+[Sources]
+ CpuTimerLib.c
+ BaseCpuTimerLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ PcdLib
+ DebugLib
+
+[Pcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuCoreCrystalClockFrequency ## CONSUMES
diff --git a/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.uni b/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.uni
new file mode 100644
index 0000000000..fcf2b0fbcb
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.uni
@@ -0,0 +1,17 @@
+// /** @file
+// Base CPU Timer Library
+//
+// Provides basic timer support using CPUID Leaf 0x15 XTAL frequency. The performance
+// counter features are provided by the processors time stamp counter.
+//
+// Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "CPU Timer Library"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Provides basic timer support using CPUID Leaf 0x15 XTAL frequency."
+
diff --git a/UefiCpuPkg/Library/CpuTimerLib/CpuTimerLib.c b/UefiCpuPkg/Library/CpuTimerLib/CpuTimerLib.c
new file mode 100644
index 0000000000..192a401fe6
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/CpuTimerLib.c
@@ -0,0 +1,279 @@
+/** @file
+ CPUID Leaf 0x15 for Core Crystal Clock frequency instance of Timer Library.
+
+ Copyright (c) 2019 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DebugLib.h>
+#include <Register/Cpuid.h>
+
+GUID mCpuCrystalFrequencyHobGuid = { 0xe1ec5ad0, 0x8569, 0x46bd, { 0x8d, 0xcd, 0x3b, 0x9f, 0x6f, 0x45, 0x82, 0x7a } };
+
+/**
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+InternalGetPerformanceCounterFrequency (
+ VOID
+ );
+
+/**
+ CPUID Leaf 0x15 for Core Crystal Clock Frequency.
+
+ The TSC counting frequency is determined by using CPUID leaf 0x15. Frequency in MHz = Core XTAL frequency * EBX/EAX.
+ In newer flavors of the CPU, core xtal frequency is returned in ECX or 0 if not supported.
+ @return The number of TSC counts per second.
+
+**/
+UINT64
+CpuidCoreClockCalculateTscFrequency (
+ VOID
+ )
+{
+ UINT64 TscFrequency;
+ UINT64 CoreXtalFrequency;
+ UINT32 RegEax;
+ UINT32 RegEbx;
+ UINT32 RegEcx;
+
+ //
+ // Use CPUID leaf 0x15 Time Stamp Counter and Nominal Core Crystal Clock Information
+ // EBX returns 0 if not supported. ECX, if non zero, provides Core Xtal Frequency in hertz.
+ // TSC frequency = (ECX, Core Xtal Frequency) * EBX/EAX.
+ //
+ AsmCpuid (CPUID_TIME_STAMP_COUNTER, &RegEax, &RegEbx, &RegEcx, NULL);
+
+ //
+ // If EAX or EBX returns 0, the XTAL ratio is not enumerated.
+ //
+ if (RegEax == 0 || RegEbx ==0 ) {
+ ASSERT (RegEax != 0);
+ ASSERT (RegEbx != 0);
+ return 0;
+ }
+ //
+ // If ECX returns 0, the XTAL frequency is not enumerated.
+ // And PcdCpuCoreCrystalClockFrequency defined should base on processor series.
+ //
+ if (RegEcx == 0) {
+ CoreXtalFrequency = PcdGet64 (PcdCpuCoreCrystalClockFrequency);
+ } else {
+ CoreXtalFrequency = (UINT64) RegEcx;
+ }
+
+ //
+ // Calculate TSC frequency = (ECX, Core Xtal Frequency) * EBX/EAX
+ //
+ TscFrequency = DivU64x32 (MultU64x32 (CoreXtalFrequency, RegEbx) + (UINT64)(RegEax >> 1), RegEax);
+
+ return TscFrequency;
+}
+
+/**
+ Stalls the CPU for at least the given number of ticks.
+
+ Stalls the CPU for at least the given number of ticks. It's invoked by
+ MicroSecondDelay() and NanoSecondDelay().
+
+ @param Delay A period of time to delay in ticks.
+
+**/
+VOID
+InternalCpuDelay (
+ IN UINT64 Delay
+ )
+{
+ UINT64 Ticks;
+
+ //
+ // The target timer count is calculated here
+ //
+ Ticks = AsmReadTsc() + Delay;
+
+ //
+ // Wait until time out
+ // Timer wrap-arounds are NOT handled correctly by this function.
+ // Thus, this function must be called within 10 years of reset since
+ // Intel guarantees a minimum of 10 years before the TSC wraps.
+ //
+ while (AsmReadTsc() <= Ticks) {
+ CpuPause();
+ }
+}
+
+/**
+ Stalls the CPU for at least the given number of microseconds.
+
+ Stalls the CPU for the number of microseconds specified by MicroSeconds.
+
+ @param[in] MicroSeconds The minimum number of microseconds to delay.
+
+ @return MicroSeconds
+
+**/
+UINTN
+EFIAPI
+MicroSecondDelay (
+ IN UINTN MicroSeconds
+ )
+{
+
+ InternalCpuDelay (
+ DivU64x32 (
+ MultU64x64 (
+ MicroSeconds,
+ InternalGetPerformanceCounterFrequency ()
+ ),
+ 1000000u
+ )
+ );
+
+ return MicroSeconds;
+}
+
+/**
+ Stalls the CPU for at least the given number of nanoseconds.
+
+ Stalls the CPU for the number of nanoseconds specified by NanoSeconds.
+
+ @param NanoSeconds The minimum number of nanoseconds to delay.
+
+ @return NanoSeconds
+
+**/
+UINTN
+EFIAPI
+NanoSecondDelay (
+ IN UINTN NanoSeconds
+ )
+{
+
+ InternalCpuDelay (
+ DivU64x32 (
+ MultU64x64 (
+ NanoSeconds,
+ InternalGetPerformanceCounterFrequency ()
+ ),
+ 1000000000u
+ )
+ );
+
+ return NanoSeconds;
+}
+
+/**
+ Retrieves the current value of a 64-bit free running performance counter.
+
+ Retrieves the current value of a 64-bit free running performance counter. The
+ counter can either count up by 1 or count down by 1. If the physical
+ performance counter counts by a larger increment, then the counter values
+ must be translated. The properties of the counter can be retrieved from
+ GetPerformanceCounterProperties().
+
+ @return The current value of the free running performance counter.
+
+**/
+UINT64
+EFIAPI
+GetPerformanceCounter (
+ VOID
+ )
+{
+ return AsmReadTsc ();
+}
+
+/**
+ Retrieves the 64-bit frequency in Hz and the range of performance counter
+ values.
+
+ If StartValue is not NULL, then the value that the performance counter starts
+ with immediately after is it rolls over is returned in StartValue. If
+ EndValue is not NULL, then the value that the performance counter end with
+ immediately before it rolls over is returned in EndValue. The 64-bit
+ frequency of the performance counter in Hz is always returned. If StartValue
+ is less than EndValue, then the performance counter counts up. If StartValue
+ is greater than EndValue, then the performance counter counts down. For
+ example, a 64-bit free running counter that counts up would have a StartValue
+ of 0 and an EndValue of 0xFFFFFFFFFFFFFFFF. A 24-bit free running counter
+ that counts down would have a StartValue of 0xFFFFFF and an EndValue of 0.
+
+ @param StartValue The value the performance counter starts with when it
+ rolls over.
+ @param EndValue The value that the performance counter ends with before
+ it rolls over.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+EFIAPI
+GetPerformanceCounterProperties (
+ OUT UINT64 *StartValue, OPTIONAL
+ OUT UINT64 *EndValue OPTIONAL
+ )
+{
+ if (StartValue != NULL) {
+ *StartValue = 0;
+ }
+
+ if (EndValue != NULL) {
+ *EndValue = 0xffffffffffffffffULL;
+ }
+ return InternalGetPerformanceCounterFrequency ();
+}
+
+/**
+ Converts elapsed ticks of performance counter to time in nanoseconds.
+
+ This function converts the elapsed ticks of running performance counter to
+ time value in unit of nanoseconds.
+
+ @param Ticks The number of elapsed ticks of running performance counter.
+
+ @return The elapsed time in nanoseconds.
+
+**/
+UINT64
+EFIAPI
+GetTimeInNanoSecond (
+ IN UINT64 Ticks
+ )
+{
+ UINT64 Frequency;
+ UINT64 NanoSeconds;
+ UINT64 Remainder;
+ INTN Shift;
+
+ Frequency = GetPerformanceCounterProperties (NULL, NULL);
+
+ //
+ // Ticks
+ // Time = --------- x 1,000,000,000
+ // Frequency
+ //
+ NanoSeconds = MultU64x32 (DivU64x64Remainder (Ticks, Frequency, &Remainder), 1000000000u);
+
+ //
+ // Ensure (Remainder * 1,000,000,000) will not overflow 64-bit.
+ // Since 2^29 < 1,000,000,000 = 0x3B9ACA00 < 2^30, Remainder should < 2^(64-30) = 2^34,
+ // i.e. highest bit set in Remainder should <= 33.
+ //
+ Shift = MAX (0, HighBitSet64 (Remainder) - 33);
+ Remainder = RShiftU64 (Remainder, (UINTN) Shift);
+ Frequency = RShiftU64 (Frequency, (UINTN) Shift);
+ NanoSeconds += DivU64x64Remainder (MultU64x32 (Remainder, 1000000000u), Frequency, NULL);
+
+ return NanoSeconds;
+}
+
diff --git a/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.c b/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.c
new file mode 100644
index 0000000000..269e5a3e83
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.c
@@ -0,0 +1,85 @@
+/** @file
+ CPUID Leaf 0x15 for Core Crystal Clock frequency instance of Timer Library.
+
+ Copyright (c) 2019 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+#include <Library/HobLib.h>
+
+extern GUID mCpuCrystalFrequencyHobGuid;
+
+/**
+ CPUID Leaf 0x15 for Core Crystal Clock Frequency.
+
+ The TSC counting frequency is determined by using CPUID leaf 0x15. Frequency in MHz = Core XTAL frequency * EBX/EAX.
+ In newer flavors of the CPU, core xtal frequency is returned in ECX or 0 if not supported.
+ @return The number of TSC counts per second.
+
+**/
+UINT64
+CpuidCoreClockCalculateTscFrequency (
+ VOID
+ );
+
+//
+// Cached CPU Crystal counter frequency
+//
+UINT64 mCpuCrystalCounterFrequency = 0;
+
+
+/**
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+InternalGetPerformanceCounterFrequency (
+ VOID
+ )
+{
+ return mCpuCrystalCounterFrequency;
+}
+
+/**
+ The constructor function is to initialize CpuCrystalCounterFrequency.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The constructor always returns RETURN_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+DxeCpuTimerLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_HOB_GUID_TYPE *GuidHob;
+
+ //
+ // Initialize CpuCrystalCounterFrequency
+ //
+ GuidHob = GetFirstGuidHob (&mCpuCrystalFrequencyHobGuid);
+ if (GuidHob != NULL) {
+ mCpuCrystalCounterFrequency = *(UINT64*)GET_GUID_HOB_DATA (GuidHob);
+ } else {
+ mCpuCrystalCounterFrequency = CpuidCoreClockCalculateTscFrequency ();
+ }
+
+ if (mCpuCrystalCounterFrequency == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
diff --git a/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.inf b/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.inf
new file mode 100644
index 0000000000..6c83549c87
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.inf
@@ -0,0 +1,37 @@
+## @file
+# DXE CPU Timer Library
+#
+# Provides basic timer support using CPUID Leaf 0x15 XTAL frequency. The performance
+# counter features are provided by the processors time stamp counter.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeCpuTimerLib
+ FILE_GUID = F22CC0DA-E7DB-4E4D-ABE2-A608188233A2
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = TimerLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER SMM_CORE
+ CONSTRUCTOR = DxeCpuTimerLibConstructor
+ MODULE_UNI_FILE = DxeCpuTimerLib.uni
+
+[Sources]
+ CpuTimerLib.c
+ DxeCpuTimerLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ PcdLib
+ DebugLib
+ HobLib
+
+[Pcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuCoreCrystalClockFrequency ## CONSUMES
diff --git a/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.uni b/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.uni
new file mode 100644
index 0000000000..f55b92abac
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.uni
@@ -0,0 +1,17 @@
+// /** @file
+// DXE CPU Timer Library
+//
+// Provides basic timer support using CPUID Leaf 0x15 XTAL frequency. The performance
+// counter features are provided by the processors time stamp counter.
+//
+// Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "CPU Timer Library"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Provides basic timer support using CPUID Leaf 0x15 XTAL frequency."
+
diff --git a/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.c b/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.c
new file mode 100644
index 0000000000..91a7212056
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.c
@@ -0,0 +1,58 @@
+/** @file
+ CPUID Leaf 0x15 for Core Crystal Clock frequency instance as PEI Timer Library.
+
+ Copyright (c) 2019 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+#include <Library/HobLib.h>
+#include <Library/DebugLib.h>
+
+extern GUID mCpuCrystalFrequencyHobGuid;
+
+/**
+ CPUID Leaf 0x15 for Core Crystal Clock Frequency.
+
+ The TSC counting frequency is determined by using CPUID leaf 0x15. Frequency in MHz = Core XTAL frequency * EBX/EAX.
+ In newer flavors of the CPU, core xtal frequency is returned in ECX or 0 if not supported.
+ @return The number of TSC counts per second.
+
+**/
+UINT64
+CpuidCoreClockCalculateTscFrequency (
+ VOID
+ );
+
+/**
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+InternalGetPerformanceCounterFrequency (
+ VOID
+ )
+{
+ UINT64 *CpuCrystalCounterFrequency;
+ EFI_HOB_GUID_TYPE *GuidHob;
+
+ CpuCrystalCounterFrequency = NULL;
+ GuidHob = GetFirstGuidHob (&mCpuCrystalFrequencyHobGuid);
+ if (GuidHob == NULL) {
+ CpuCrystalCounterFrequency = (UINT64*)BuildGuidHob(&mCpuCrystalFrequencyHobGuid, sizeof (*CpuCrystalCounterFrequency));
+ ASSERT (CpuCrystalCounterFrequency != NULL);
+ *CpuCrystalCounterFrequency = CpuidCoreClockCalculateTscFrequency ();
+ } else {
+ CpuCrystalCounterFrequency = (UINT64*)GET_GUID_HOB_DATA (GuidHob);
+ }
+
+ return *CpuCrystalCounterFrequency;
+}
+
diff --git a/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.inf b/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.inf
new file mode 100644
index 0000000000..7af0fc44a6
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.inf
@@ -0,0 +1,36 @@
+## @file
+# PEI CPU Timer Library
+#
+# Provides basic timer support using CPUID Leaf 0x15 XTAL frequency. The performance
+# counter features are provided by the processors time stamp counter.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PeiCpuTimerLib
+ FILE_GUID = 2B13DE00-1A5F-4DD7-A298-01B08AF1015A
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = TimerLib|PEI_CORE PEIM
+ MODULE_UNI_FILE = PeiCpuTimerLib.uni
+
+[Sources]
+ CpuTimerLib.c
+ PeiCpuTimerLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ PcdLib
+ DebugLib
+ HobLib
+
+[Pcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuCoreCrystalClockFrequency ## CONSUMES
diff --git a/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.uni b/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.uni
new file mode 100644
index 0000000000..49beb44908
--- /dev/null
+++ b/UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.uni
@@ -0,0 +1,17 @@
+// /** @file
+// PEI CPU Timer Library
+//
+// Provides basic timer support using CPUID Leaf 0x15 XTAL frequency. The performance
+// counter features are provided by the processors time stamp counter.
+//
+// Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "CPU Timer Library"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Provides basic timer support using CPUID Leaf 0x15 XTAL frequency."
+
diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec
index 14ddaa8633..86ad61f64b 100644
--- a/UefiCpuPkg/UefiCpuPkg.dec
+++ b/UefiCpuPkg/UefiCpuPkg.dec
@@ -211,6 +211,14 @@
# @Prompt If CPU features will be initialized during S3 resume.
gUefiCpuPkgTokenSpaceGuid.PcdCpuFeaturesInitOnS3Resume|FALSE|BOOLEAN|0x0000001D

+ ## Specifies CPUID Leaf 0x15 Time Stamp Counter and Nominal Core Crystal Clock Frequency.
+ # TSC Frequency = ECX (core crystal clock frequency) * EBX/EAX.
+ # Intel Xeon Processor Scalable Family with CPUID signature 06_55H = 25000000 (25MHz)
+ # 6th and 7th generation Intel Core processors and Intel Xeon W Processor Family = 24000000 (24MHz)
+ # Intel Atom processors based on Goldmont Microarchitecture with CPUID signature 06_5CH = 19200000 (19.2MHz)
+ # @Prompt This PCD is the nominal frequency of the core crystal clock in Hz as is CPUID Leaf 0x15:ECX
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuCoreCrystalClockFrequency|24000000|UINT64|0x32132113
+
[PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
## Specifies max supported number of Logical Processors.
# @Prompt Configure max supported number of Logical Processors
diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc
index bf690d3978..e7dfe30eda 100644
--- a/UefiCpuPkg/UefiCpuPkg.dsc
+++ b/UefiCpuPkg/UefiCpuPkg.dsc
@@ -101,6 +101,9 @@
UefiCpuPkg/CpuIoPei/CpuIoPei.inf
UefiCpuPkg/Library/SecPeiDxeTimerLibUefiCpu/SecPeiDxeTimerLibUefiCpu.inf
UefiCpuPkg/Application/Cpuid/Cpuid.inf
+ UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf
+ UefiCpuPkg/Library/CpuTimerLib/DxeCpuTimerLib.inf
+ UefiCpuPkg/Library/CpuTimerLib/PeiCpuTimerLib.inf

[Components.IA32, Components.X64]
UefiCpuPkg/CpuDxe/CpuDxe.inf
diff --git a/UefiCpuPkg/UefiCpuPkg.uni b/UefiCpuPkg/UefiCpuPkg.uni
index 80af4fc1d2..fbf7680726 100644
--- a/UefiCpuPkg/UefiCpuPkg.uni
+++ b/UefiCpuPkg/UefiCpuPkg.uni
@@ -242,3 +242,13 @@
#string STR_gUefiCpuPkgTokenSpaceGuid_PcdCpuKnownGoodStackSize_HELP #language en-US "Size of good stack for an exception.\n"
"This PCD will only take into effect if PcdCpuStackGuard is enabled.\n"

+#string STR_gUefiCpuPkgTokenSpaceGuid_PcdCpuCoreCrystalClockFrequency_PROMPT #language en-US "Specifies CPUID Leaf 0x15 Time Stamp Counter and Nominal Core Crystal Clock Frequency."
+
+#string STR_gUefiCpuPkgTokenSpaceGuid_PcdCpuCoreCrystalClockFrequency_HELP #language en-US "Specifies CPUID Leaf 0x15 Time Stamp Counter and Nominal Core Crystal Clock Frequency.<BR><BR>\n"
+ "TSC Frequency = ECX (core crystal clock frequency) * EBX/EAX.<BR><BR>\n"
+ "This PCD is the nominal frequency of the core crystal clock in Hz as is CPUID Leaf 0x15:ECX.<BR><BR>\n"
+ "Default value is 24000000 for 6th and 7th generation Intel Core processors and Intel Xeon W Processor Family.<BR>\n"
+ "25000000 - Intel Xeon Processor Scalable Family with CPUID signature 06_55H(25MHz).<BR>\n"
+ "24000000 - 6th and 7th generation Intel Core processors and Intel Xeon W Processor Family(24MHz).<BR>\n"
+ "19200000 - Intel Atom processors based on Goldmont Microarchitecture with CPUID signature 06_5CH(19.2MHz).<BR>\n"
+
--
2.14.2.windows.3

Vitaly Cheptsov
 

Hi Donald,

Glad to hear it helped a little, and sorry for some outdated quotes.

Your clarification regarding model range is very helpful. Xeon W being client and thus having client clock makes sense, though I must say it was quite not obvious. I was referring to the same SDM table, and it would have been great to have vertical range binding instead of the misleading CPUID.

With that, however, I still do not see a way to dynamically determine the difference between Xeon client and server.

For us it is needed as we use TimerLib differently. For you TimerLib is a part of BSP, so you face no issue statically setting the clock frequency as a PCD. For us TimerLib is used as a part of an UEFI application compatible with different hardware, and in fact not just Intel. We have such "generic TimerLib" library, and to determine CPU frequency, as a fallback to CPUID 15H, it relies on ACPI PM timer. This is not great for two reasons:
- we have to maintain it ourselves, while we would have liked that be part of EDK II with different vendors contributing to the project.
- we still cannot find an obvious way to determine crystal clock when it is not reported, in particular for Xeon W and Xeon Scalable case.

I guess this is now out of the scope of this patch and perhaps even this exact library, but it will be helpful to hear relevant technical details on the issue and opinions on such "generic TimerLib" library to later appear in EDK II.

Best regards,
Vitaly

15 авг. 2019 г., в 11:40, Kuo, Donald <donald.kuo@...> написал(а):

Hi Vitaly,
 
Appreciated for reviewing very detail. And looks your captured some piece of code is older version. And should be ok, I do got your point.
 
Item #1
-          I do missed RegEax error handling in case for CpuidCoreClockCalculateTscFrequency () should return 0 and EFI_UNSUPPORTED. AR: Will update it.
 
Item #2:
-          Actually the information is from SDM Table 18-85
o   As we know CPUID signature could be hard to identify processor XTAL frequency is? So we only check CPUID Leaf 0x15
o   And the PCD will be defined depends on platform specific and during project early development. Based on SDM, Intel processor for CPUID.15h EAX and EBX is enumerated, but ECX could be possible not enumerated. So that is why we based on  SDM Table 18-85 to create PCD as below:
§  Intel Xeon Server family: 25MHz
§  Intel Core and Intel Xeon W family: 24MHz
§  Intel Atom : 19.2MHz
§  So regards the “06_55h” might cause the confused, we could review it whether remove it??
Item #3:
-          Again, the XTAL frequency is optional and should be define in early phase of new project. Default should still use AcpiTimer.
o    Platform / developer owner should well know the CPU generation XTAL frequency is? Server / Client / Atom ?
o   For those CPU not supported should still use AcpiTimerLib (default)
 
Thanks,
Donald
 
From: vit9696 via [] [mailto:vit9696=protonmail.com@[]] 
Sent: Thursday, August 15, 2019 3:20 PM
To: Kuo, Donald <donald.kuo@...>; devel@edk2.groups.io
Subject: Re: [edk2-devel] [PATCH] UefiCpuPkg: Adding a new TSC library by using CPUID(0x15) TSC leaf
 
Hello,

Thank you for the patch! I reviewed the code and noticed select issues explained below.

1. The following construction:

if (RegEbx == 0) {
DEBUG ((DEBUG_ERROR, "The CPU is not capble for Core Crystal Clock Frequency !!\n"));
ASSERT (RegEbx != 0);
}

Does not look good to me, and in my opinion, should be written differently:

if (RegEbx == 0 || RegEax == 0) {
DEBUG ((DEBUG_ERROR, "The CPU is not capble for Core Crystal Clock Frequency !!\n"));
ASSERT (RegEbx != 0);
  ASSERT (RegEax != 0);
  return 0;
}

The reason for the above code being wrong is potential division by zero below, which behaviour is undefined (and in fact unknown due to unspecified interrupt table state). Even though the intent is to not permit the use of this library on an unsupported platform, runtime checks and assertions are essentially NO-OPs, should be separate and not confused. For this to work properly the call to CpuidCoreClockCalculateTscFrequency should happen in library constructor with EFI_UNSUPPORTED return on CpuidCoreClockCalculateTscFrequency returning 0.

2. The notes about crystal clock frequency for 06_55H CPU signature:
"25000000 - Intel Xeon Processor Scalable Family with CPUID signature 06_55H(25MHz).<BR>\n"
# Intel Xeon Processor Scalable Family with CPUID signature 06_55H = 25000000 (25MHz)

are misleading in both this library and Intel SDM. Intel Xeon W processors have the same CPUID signature (06_55H), they report 0 crystal clock frequency, and their crystal clock frequency is 24 MHz. This should at least be mentioned in the lower part mentioning Intel Xeon W Processor Family(24MHz).

Actually, given that many Intel guys are here, I wonder whether anybody knows if there is any better approach to distinguish Xeon Scalable CPUs and Xeon W CPUs besides using brand string or using marketing frequency from CPUID 16H to determine crystal clock frequency (this is what Linux does at the moment)?

3. Intel Atom Denverton with CPUID signature (06_5FH), also known as Goldmont X, reports 0 crystal clock frequency as well, and has 25 MHz frequency. This is missing from SDM, but once again I believe it should be included in the two places from the above to avoid confusion.

Besides these 3 points, honestly, the library itself appears to be very limited for anything but embedding it into the firmware with known hardware, which already works just fine by defining the PCD. Missing 0 crystal clock frequency handling in runtime with hardcoding the PCD value looks very bad, because the number of modern Intel CPU models reporting 0 crystal clock frequency and having non 24 MHz frequency is quite far from 0. This makes the library essentially impossible to use in any UEFI application or third-party product even when targeting Skylake+ generation. To resolute this I vote for additional detection functionality to be added to the library to obtain crystal clock frequency when the CPUID reports 0. The PCD could be the last resort when no other method works. My opinion is that this should be resolved prior to merging the patch.

Best regards,
Vitaly