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@intel.com>
Cc: Star Zeng <star.zeng@intel.com>
Cc: Eric Dong <eric.dong@intel.com>
Cc: Amy Chan <amy.chan@intel.com>
Cc: Rangasai V Chaganty <rangasai.v.chaganty@intel.com>
Signed-off-by: Donald Kuo <donald.kuo@intel.com>
Reviewed-by: Eric Dong <eric.dong@intel.com>
This commit is contained in:
Donald Kuo 2019-08-12 12:34:39 +08:00 committed by Liming Gao
parent 9c90d39b60
commit 30781febe2
13 changed files with 643 additions and 0 deletions

View File

@ -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 ();
}

View File

@ -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

View File

@ -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."

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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."

View File

@ -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;
}

View File

@ -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

View File

@ -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."

View File

@ -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

View File

@ -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

View File

@ -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"