From 034307a7ec57dd87b83b14e2c706b3e7c2d302c5 Mon Sep 17 00:00:00 2001 From: lzeng14 Date: Sun, 30 Oct 2011 13:14:44 +0000 Subject: Add BaseTscTimerLib, and then merge the three TscTimerLib to one directory. Signed-off-by: lzeng14 Reviewed-by: lgao4 git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@12604 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Library/DxeTscTimerLib/DxeTscTimerLib.c | 320 --------------------- .../Library/DxeTscTimerLib/DxeTscTimerLib.inf | 58 ---- .../Library/PeiTscTimerLib/PeiTscTimerLib.c | 309 -------------------- .../Library/PeiTscTimerLib/PeiTscTimerLib.inf | 54 ---- .../Library/TscTimerLib/BaseTscTimerLib.c | 57 ++++ .../Library/TscTimerLib/BaseTscTimerLib.inf | 54 ++++ .../Library/TscTimerLib/DxeTscTimerLib.c | 100 +++++++ .../Library/TscTimerLib/DxeTscTimerLib.inf | 59 ++++ .../Library/TscTimerLib/PeiTscTimerLib.c | 76 +++++ .../Library/TscTimerLib/PeiTscTimerLib.inf | 55 ++++ .../Library/TscTimerLib/TscTimerLibInternal.h | 55 ++++ .../Library/TscTimerLib/TscTimerLibShare.c | 275 ++++++++++++++++++ PerformancePkg/PerformancePkg.dsc | 7 +- 13 files changed, 735 insertions(+), 744 deletions(-) delete mode 100644 PerformancePkg/Library/DxeTscTimerLib/DxeTscTimerLib.c delete mode 100644 PerformancePkg/Library/DxeTscTimerLib/DxeTscTimerLib.inf delete mode 100644 PerformancePkg/Library/PeiTscTimerLib/PeiTscTimerLib.c delete mode 100644 PerformancePkg/Library/PeiTscTimerLib/PeiTscTimerLib.inf create mode 100644 PerformancePkg/Library/TscTimerLib/BaseTscTimerLib.c create mode 100644 PerformancePkg/Library/TscTimerLib/BaseTscTimerLib.inf create mode 100644 PerformancePkg/Library/TscTimerLib/DxeTscTimerLib.c create mode 100644 PerformancePkg/Library/TscTimerLib/DxeTscTimerLib.inf create mode 100644 PerformancePkg/Library/TscTimerLib/PeiTscTimerLib.c create mode 100644 PerformancePkg/Library/TscTimerLib/PeiTscTimerLib.inf create mode 100644 PerformancePkg/Library/TscTimerLib/TscTimerLibInternal.h create mode 100644 PerformancePkg/Library/TscTimerLib/TscTimerLibShare.c (limited to 'PerformancePkg') diff --git a/PerformancePkg/Library/DxeTscTimerLib/DxeTscTimerLib.c b/PerformancePkg/Library/DxeTscTimerLib/DxeTscTimerLib.c deleted file mode 100644 index b7e4d68069..0000000000 --- a/PerformancePkg/Library/DxeTscTimerLib/DxeTscTimerLib.c +++ /dev/null @@ -1,320 +0,0 @@ -/** @file - A Dxe Timer Library implementation which uses the Time Stamp Counter in the processor. - - For Pentium 4 processors, Intel Xeon processors (family [0FH], models [03H and higher]); - for Intel Core Solo and Intel Core Duo processors (family [06H], model [0EH]); - for the Intel Xeon processor 5100 series and Intel Core 2 Duo processors (family [06H], model [0FH]); - for Intel Core 2 and Intel Xeon processors (family [06H], display_model [17H]); - for Intel Atom processors (family [06H], display_model [1CH]): - the time-stamp counter increments at a constant rate. - That rate may be set by the maximum core-clock to bus-clock ratio of the processor or may be set by - the maximum resolved frequency at which the processor is booted. The maximum resolved frequency may - differ from the maximum qualified frequency of the processor. - - The specific processor configuration determines the behavior. Constant TSC behavior ensures that the - duration of each clock tick is uniform and supports the use of the TSC as a wall clock timer even if - the processor core changes frequency. This is the architectural behavior moving forward. - - A Processor's support for invariant TSC is indicated by CPUID.0x80000007.EDX[8]. - - Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
- This program and the accompanying materials - are licensed and made available under the terms and conditions of the BSD License - which accompanies this distribution. The full text of the license may be found at - http://opensource.org/licenses/bsd-license.php - - THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -UINT64 mTscFrequency; - -/** The constructor function determines the actual TSC frequency. - - First, Get TSC frequency from system configuration table with TSC frequency GUID, - if the table is not found, install it. - - The TSC counting frequency is determined by comparing how far it counts - during a 1ms period as determined by the ACPI timer. The ACPI timer is - used because it counts at a known frequency. - If ACPI I/O space not enabled, this function will enable it. Then the - TSC is sampled, followed by waiting for 3579 clocks of the ACPI timer, or 1ms. - The TSC is then sampled again. The difference multiplied by 1000 is the TSC - frequency. There will be a small error because of the overhead of reading - the ACPI timer. An attempt is made to determine and compensate for this error. - This function will always return EFI_SUCCESS. - - @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 EFI_SUCCESS. - -**/ -EFI_STATUS -EFIAPI -DxeTscTimerLibConstructor ( - IN EFI_HANDLE ImageHandle, - IN EFI_SYSTEM_TABLE *SystemTable - ) -{ - EFI_STATUS Status; - UINT64 *TscFrequency; - UINT64 StartTSC; - UINT64 EndTSC; - UINT32 TimerAddr; - UINT32 Ticks; - - // - // Get TSC frequency from system configuration table with TSC frequency GUID. - // - Status = EfiGetSystemConfigurationTable (&gEfiTscFrequencyGuid, (VOID **) &TscFrequency); - if (Status == EFI_SUCCESS) { - mTscFrequency = *TscFrequency; - return EFI_SUCCESS; - } - - // - // TSC frequency GUID system configuration table is not found, install it. - // - - // - // If ACPI I/O space is not enabled yet, program ACPI I/O base address and enable it. - // - if ((PciRead8 (PCI_ICH_LPC_ADDRESS (R_ICH_LPC_ACPI_CNT)) & B_ICH_LPC_ACPI_CNT_ACPI_EN) == 0) { - PciWrite16 (PCI_ICH_LPC_ADDRESS (R_ICH_LPC_ACPI_BASE), PcdGet16 (PcdPerfPkgAcpiIoPortBaseAddress)); - PciOr8 (PCI_ICH_LPC_ADDRESS (R_ICH_LPC_ACPI_CNT), B_ICH_LPC_ACPI_CNT_ACPI_EN); - } - - // - // ACPI I/O space should be enabled now, locate the ACPI Timer. - // ACPI I/O base address maybe have be initialized by other driver with different value, - // So get it from PCI space directly. - // - TimerAddr = ((PciRead16 (PCI_ICH_LPC_ADDRESS (R_ICH_LPC_ACPI_BASE))) & B_ICH_LPC_ACPI_BASE_BAR) + R_ACPI_PM1_TMR; - Ticks = IoRead32 (TimerAddr) + (3579); // Set Ticks to 1ms in the future - StartTSC = AsmReadTsc(); // Get base value for the TSC - // - // Wait until the ACPI timer has counted 1ms. - // Timer wrap-arounds are handled correctly by this function. - // When the current ACPI timer value is greater than 'Ticks', the while loop will exit. - // - while (((Ticks - IoRead32 (TimerAddr)) & BIT23) == 0) { - CpuPause(); - } - EndTSC = AsmReadTsc(); // TSC value 1ms later - - Status = gBS->AllocatePool (EfiBootServicesData, sizeof (UINT64), (VOID **) &TscFrequency); - ASSERT_EFI_ERROR (Status); - - *TscFrequency = MultU64x32 ( - (EndTSC - StartTSC), // Number of TSC counts in 1ms - 1000 // Number of ms in a second - ); - // - // TscFrequency now points to the number of TSC counts per second, install system configuration table for it. - // - gBS->InstallConfigurationTable (&gEfiTscFrequencyGuid, TscFrequency); - - mTscFrequency = *TscFrequency; - return EFI_SUCCESS; -} - -/** 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[in] Delay A period of time to delay in ticks. - -**/ -VOID -InternalX86Delay ( - 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 specified number of MicroSeconds. - - @param[in] MicroSeconds The minimum number of microseconds to delay. - - @return The value of MicroSeconds input. - -**/ -UINTN -EFIAPI -MicroSecondDelay ( - IN UINTN MicroSeconds - ) -{ - InternalX86Delay ( - DivU64x32 ( - MultU64x64 ( - mTscFrequency, - MicroSeconds - ), - 1000000u - ) - ); - return MicroSeconds; -} - -/** Stalls the CPU for at least the specified number of NanoSeconds. - - @param[in] NanoSeconds The minimum number of nanoseconds to delay. - - @return The value of NanoSeconds input. - -**/ -UINTN -EFIAPI -NanoSecondDelay ( - IN UINTN NanoSeconds - ) -{ - InternalX86Delay ( - DivU64x32 ( - MultU64x32 ( - mTscFrequency, - (UINT32)NanoSeconds - ), - 1000000000u - ) - ); - return NanoSeconds; -} - -/** Retrieves the current value of the 64-bit free running Time-Stamp counter. - - The time-stamp counter (as implemented in the P6 family, Pentium, Pentium M, - Pentium 4, Intel Xeon, Intel Core Solo and Intel Core Duo processors and - later processors) is a 64-bit counter that is set to 0 following a RESET of - the processor. Following a RESET, the counter increments even when the - processor is halted by the HLT instruction or the external STPCLK# pin. Note - that the assertion of the external DPSLP# pin may cause the time-stamp - counter to stop. - - The properties of the counter can be retrieved by the - GetPerformanceCounterProperties() function. - - @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, 0x0, is returned in StartValue. If EndValue is not NULL, then the value - that the performance counter end with, 0xFFFFFFFFFFFFFFFF, is returned in - EndValue. - - The 64-bit frequency of the performance counter, in Hz, is always returned. - To determine average processor clock frequency, Intel recommends the use of - EMON logic to count processor core clocks over the period of time for which - the average is required. - - - @param[out] StartValue Pointer to where the performance counter's starting value is saved, or NULL. - @param[out] EndValue Pointer to where the performance counter's ending value is saved, or NULL. - - @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 mTscFrequency; -} - -/** - 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/PerformancePkg/Library/DxeTscTimerLib/DxeTscTimerLib.inf b/PerformancePkg/Library/DxeTscTimerLib/DxeTscTimerLib.inf deleted file mode 100644 index 8d2e6cf8bb..0000000000 --- a/PerformancePkg/Library/DxeTscTimerLib/DxeTscTimerLib.inf +++ /dev/null @@ -1,58 +0,0 @@ -## @file -# Dxe Timer Library which uses the Time Stamp Counter in the processor. -# -# A version of the Timer Library using the processor's TSC. -# The time stamp counter in newer processors may support an enhancement, referred to as invariant TSC. -# The invariant TSC runs at a constant rate in all ACPI P-, C-. and T-states. -# This is the architectural behavior moving forward. -# TSC reads are much more efficient and do not incur the overhead associated with a ring transition or -# access to a platform resource. -# -# Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
-# This program and the accompanying materials -# are licensed and made available under the terms and conditions of the BSD License -# which accompanies this distribution. The full text of the license may be found at -# http://opensource.org/licenses/bsd-license.php -# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. -# -## - -[Defines] - INF_VERSION = 0x00010005 - BASE_NAME = DxeTscTimerLib - FILE_GUID = 95ab030f-b4fd-4ee4-92a5-9e04e87634d9 - 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 = DxeTscTimerLibConstructor - - -# -# VALID_ARCHITECTURES = IA32 X64 -# - -[Sources.common] - DxeTscTimerLib.c - - -[Packages] - MdePkg/MdePkg.dec - PerformancePkg/PerformancePkg.dec - - -[LibraryClasses] - UefiBootServicesTableLib - PcdLib - PciLib - IoLib - BaseLib - UefiLib - DebugLib - -[Guids] - gEfiTscFrequencyGuid ## CONSUMES ## System Configuration Table - -[Pcd.common] - gPerformancePkgTokenSpaceGuid.PcdPerfPkgAcpiIoPortBaseAddress diff --git a/PerformancePkg/Library/PeiTscTimerLib/PeiTscTimerLib.c b/PerformancePkg/Library/PeiTscTimerLib/PeiTscTimerLib.c deleted file mode 100644 index 4c37964445..0000000000 --- a/PerformancePkg/Library/PeiTscTimerLib/PeiTscTimerLib.c +++ /dev/null @@ -1,309 +0,0 @@ -/** @file - A Pei Timer Library implementation which uses the Time Stamp Counter in the processor. - - For Pentium 4 processors, Intel Xeon processors (family [0FH], models [03H and higher]); - for Intel Core Solo and Intel Core Duo processors (family [06H], model [0EH]); - for the Intel Xeon processor 5100 series and Intel Core 2 Duo processors (family [06H], model [0FH]); - for Intel Core 2 and Intel Xeon processors (family [06H], display_model [17H]); - for Intel Atom processors (family [06H], display_model [1CH]): - the time-stamp counter increments at a constant rate. - That rate may be set by the maximum core-clock to bus-clock ratio of the processor or may be set by - the maximum resolved frequency at which the processor is booted. The maximum resolved frequency may - differ from the maximum qualified frequency of the processor. - - The specific processor configuration determines the behavior. Constant TSC behavior ensures that the - duration of each clock tick is uniform and supports the use of the TSC as a wall clock timer even if - the processor core changes frequency. This is the architectural behavior moving forward. - - A Processor's support for invariant TSC is indicated by CPUID.0x80000007.EDX[8]. - - Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
- This program and the accompanying materials - are licensed and made available under the terms and conditions of the BSD License - which accompanies this distribution. The full text of the license may be found at - http://opensource.org/licenses/bsd-license.php - - THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - -#include -#include - -#include -#include -#include -#include -#include -#include - -#include - -/** Get TSC frequency from TSC frequency GUID HOB, if the HOB is not found, build it. - - The TSC counting frequency is determined by comparing how far it counts - during a 1ms period as determined by the ACPI timer. The ACPI timer is - used because it counts at a known frequency. - If ACPI I/O space not enabled, this function will enable it. Then the - TSC is sampled, followed by waiting for 3579 clocks of the ACPI timer, or 1ms. - The TSC is then sampled again. The difference multiplied by 1000 is the TSC - frequency. There will be a small error because of the overhead of reading - the ACPI timer. - - @return The number of TSC counts per second. - -**/ -UINT64 -InternalGetTscFrequency ( - VOID - ) -{ - EFI_HOB_GUID_TYPE *GuidHob; - VOID *DataInHob; - UINT64 StartTSC; - UINT64 EndTSC; - UINT32 TimerAddr; - UINT32 Ticks; - UINT64 TscFrequency; - - // - // Get TSC frequency from TSC frequency GUID HOB. - // - GuidHob = GetFirstGuidHob (&gEfiTscFrequencyGuid); - if (GuidHob != NULL) { - DataInHob = GET_GUID_HOB_DATA (GuidHob); - TscFrequency = * (UINT64 *) DataInHob; - return TscFrequency; - } - - // - // TSC frequency GUID HOB is not found, build it. - // - - // - // If ACPI I/O space is not enabled yet, program ACPI I/O base address and enable it. - // - if ((PciRead8 (PCI_ICH_LPC_ADDRESS (R_ICH_LPC_ACPI_CNT)) & B_ICH_LPC_ACPI_CNT_ACPI_EN) == 0) { - PciWrite16 (PCI_ICH_LPC_ADDRESS (R_ICH_LPC_ACPI_BASE), PcdGet16 (PcdPerfPkgAcpiIoPortBaseAddress)); - PciOr8 (PCI_ICH_LPC_ADDRESS (R_ICH_LPC_ACPI_CNT), B_ICH_LPC_ACPI_CNT_ACPI_EN); - } - - // - // ACPI I/O space should be enabled now, locate the ACPI Timer. - // ACPI I/O base address maybe have be initialized by other driver with different value, - // So get it from PCI space directly. - // - TimerAddr = ((PciRead16 (PCI_ICH_LPC_ADDRESS (R_ICH_LPC_ACPI_BASE))) & B_ICH_LPC_ACPI_BASE_BAR) + R_ACPI_PM1_TMR; - Ticks = IoRead32 (TimerAddr) + (3579); // Set Ticks to 1ms in the future - StartTSC = AsmReadTsc(); // Get base value for the TSC - // - // Wait until the ACPI timer has counted 1ms. - // Timer wrap-arounds are handled correctly by this function. - // When the current ACPI timer value is greater than 'Ticks', the while loop will exit. - // - while (((Ticks - IoRead32 (TimerAddr)) & BIT23) == 0) { - CpuPause(); - } - EndTSC = AsmReadTsc(); // TSC value 1ms later - - TscFrequency = MultU64x32 ( - (EndTSC - StartTSC), // Number of TSC counts in 1ms - 1000 // Number of ms in a second - ); - // - // TscFrequency is now equal to the number of TSC counts per second, build GUID HOB for it. - // - BuildGuidDataHob ( - &gEfiTscFrequencyGuid, - &TscFrequency, - sizeof (UINT64) - ); - - 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[in] Delay A period of time to delay in ticks. - -**/ -VOID -InternalX86Delay ( - 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 specified number of MicroSeconds. - - @param[in] MicroSeconds The minimum number of microseconds to delay. - - @return The value of MicroSeconds input. - -**/ -UINTN -EFIAPI -MicroSecondDelay ( - IN UINTN MicroSeconds - ) -{ - InternalX86Delay ( - DivU64x32 ( - MultU64x64 ( - InternalGetTscFrequency (), - MicroSeconds - ), - 1000000u - ) - ); - return MicroSeconds; -} - -/** Stalls the CPU for at least the specified number of NanoSeconds. - - @param[in] NanoSeconds The minimum number of nanoseconds to delay. - - @return The value of NanoSeconds input. - -**/ -UINTN -EFIAPI -NanoSecondDelay ( - IN UINTN NanoSeconds - ) -{ - InternalX86Delay ( - DivU64x32 ( - MultU64x32 ( - InternalGetTscFrequency (), - (UINT32)NanoSeconds - ), - 1000000000u - ) - ); - return NanoSeconds; -} - -/** Retrieves the current value of the 64-bit free running Time-Stamp counter. - - The time-stamp counter (as implemented in the P6 family, Pentium, Pentium M, - Pentium 4, Intel Xeon, Intel Core Solo and Intel Core Duo processors and - later processors) is a 64-bit counter that is set to 0 following a RESET of - the processor. Following a RESET, the counter increments even when the - processor is halted by the HLT instruction or the external STPCLK# pin. Note - that the assertion of the external DPSLP# pin may cause the time-stamp - counter to stop. - - The properties of the counter can be retrieved by the - GetPerformanceCounterProperties() function. - - @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, 0x0, is returned in StartValue. If EndValue is not NULL, then the value - that the performance counter end with, 0xFFFFFFFFFFFFFFFF, is returned in - EndValue. - - The 64-bit frequency of the performance counter, in Hz, is always returned. - To determine average processor clock frequency, Intel recommends the use of - EMON logic to count processor core clocks over the period of time for which - the average is required. - - - @param[out] StartValue Pointer to where the performance counter's starting value is saved, or NULL. - @param[out] EndValue Pointer to where the performance counter's ending value is saved, or NULL. - - @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 InternalGetTscFrequency (); -} - -/** - 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/PerformancePkg/Library/PeiTscTimerLib/PeiTscTimerLib.inf b/PerformancePkg/Library/PeiTscTimerLib/PeiTscTimerLib.inf deleted file mode 100644 index 1a4bc1981f..0000000000 --- a/PerformancePkg/Library/PeiTscTimerLib/PeiTscTimerLib.inf +++ /dev/null @@ -1,54 +0,0 @@ -## @file -# Pei Timer Library which uses the Time Stamp Counter in the processor. -# -# A version of the Timer Library using the processor's TSC. -# The time stamp counter in newer processors may support an enhancement, referred to as invariant TSC. -# The invariant TSC runs at a constant rate in all ACPI P-, C-. and T-states. -# This is the architectural behavior moving forward. -# TSC reads are much more efficient and do not incur the overhead associated with a ring transition or -# access to a platform resource. -# -# Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
-# This program and the accompanying materials -# are licensed and made available under the terms and conditions of the BSD License -# which accompanies this distribution. The full text of the license may be found at -# http://opensource.org/licenses/bsd-license.php -# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. -# -## - -[Defines] - INF_VERSION = 0x00010005 - BASE_NAME = PeiTscTimerLib - FILE_GUID = 342C36C0-15DF-43b4-9EC9-FBF748BFB3D1 - MODULE_TYPE = PEIM - VERSION_STRING = 1.0 - LIBRARY_CLASS = TimerLib|SEC PEIM PEI_CORE - - -# -# VALID_ARCHITECTURES = IA32 X64 -# - -[Sources.common] - PeiTscTimerLib.c - - -[Packages] - MdePkg/MdePkg.dec - PerformancePkg/PerformancePkg.dec - - -[LibraryClasses] - PcdLib - PciLib - IoLib - BaseLib - HobLib - -[Guids] - gEfiTscFrequencyGuid ## PRODUCES ## Hob - -[Pcd.common] - gPerformancePkgTokenSpaceGuid.PcdPerfPkgAcpiIoPortBaseAddress diff --git a/PerformancePkg/Library/TscTimerLib/BaseTscTimerLib.c b/PerformancePkg/Library/TscTimerLib/BaseTscTimerLib.c new file mode 100644 index 0000000000..77bc04e085 --- /dev/null +++ b/PerformancePkg/Library/TscTimerLib/BaseTscTimerLib.c @@ -0,0 +1,57 @@ +/** @file + A Base Timer Library implementation which uses the Time Stamp Counter in the processor. + + For Pentium 4 processors, Intel Xeon processors (family [0FH], models [03H and higher]); + for Intel Core Solo and Intel Core Duo processors (family [06H], model [0EH]); + for the Intel Xeon processor 5100 series and Intel Core 2 Duo processors (family [06H], model [0FH]); + for Intel Core 2 and Intel Xeon processors (family [06H], display_model [17H]); + for Intel Atom processors (family [06H], display_model [1CH]): + the time-stamp counter increments at a constant rate. + That rate may be set by the maximum core-clock to bus-clock ratio of the processor or may be set by + the maximum resolved frequency at which the processor is booted. The maximum resolved frequency may + differ from the maximum qualified frequency of the processor. + + The specific processor configuration determines the behavior. Constant TSC behavior ensures that the + duration of each clock tick is uniform and supports the use of the TSC as a wall clock timer even if + the processor core changes frequency. This is the architectural behavior moving forward. + + A Processor's support for invariant TSC is indicated by CPUID.0x80000007.EDX[8]. + + Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "TscTimerLibInternal.h" + +UINT64 mTscFrequency = 0; + +/** Get TSC frequency. + + @return The number of TSC counts per second. + +**/ +UINT64 +InternalGetTscFrequency ( + VOID + ) +{ + UINT64 TscFrequency; + + if (mTscFrequency != 0) { + return mTscFrequency; + } + + TscFrequency = InternalCalculateTscFrequency (); + + mTscFrequency = TscFrequency; + + return TscFrequency; +} + diff --git a/PerformancePkg/Library/TscTimerLib/BaseTscTimerLib.inf b/PerformancePkg/Library/TscTimerLib/BaseTscTimerLib.inf new file mode 100644 index 0000000000..2c33b7702e --- /dev/null +++ b/PerformancePkg/Library/TscTimerLib/BaseTscTimerLib.inf @@ -0,0 +1,54 @@ +## @file +# Base Timer Library which uses the Time Stamp Counter in the processor. +# +# Note: There will be 1ms penalty to get TSC frequency every time +# by waiting for 3579 clocks of the ACPI timer, or 1ms. +# +# A version of the Timer Library using the processor's TSC. +# The time stamp counter in newer processors may support an enhancement, referred to as invariant TSC. +# The invariant TSC runs at a constant rate in all ACPI P-, C-. and T-states. +# This is the architectural behavior moving forward. +# TSC reads are much more efficient and do not incur the overhead associated with a ring transition or +# access to a platform resource. +# +# Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = BaseTscTimerLib + FILE_GUID = D29338B9-50FE-4e4f-B7D4-A150A2C1F4FB + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = TimerLib + + +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources.common] + TscTimerLibShare.c + BaseTscTimerLib.c + + +[Packages] + MdePkg/MdePkg.dec + PerformancePkg/PerformancePkg.dec + + +[LibraryClasses] + PcdLib + PciLib + IoLib + BaseLib + +[Pcd.common] + gPerformancePkgTokenSpaceGuid.PcdPerfPkgAcpiIoPortBaseAddress diff --git a/PerformancePkg/Library/TscTimerLib/DxeTscTimerLib.c b/PerformancePkg/Library/TscTimerLib/DxeTscTimerLib.c new file mode 100644 index 0000000000..c5a789428b --- /dev/null +++ b/PerformancePkg/Library/TscTimerLib/DxeTscTimerLib.c @@ -0,0 +1,100 @@ +/** @file + A Dxe Timer Library implementation which uses the Time Stamp Counter in the processor. + + For Pentium 4 processors, Intel Xeon processors (family [0FH], models [03H and higher]); + for Intel Core Solo and Intel Core Duo processors (family [06H], model [0EH]); + for the Intel Xeon processor 5100 series and Intel Core 2 Duo processors (family [06H], model [0FH]); + for Intel Core 2 and Intel Xeon processors (family [06H], display_model [17H]); + for Intel Atom processors (family [06H], display_model [1CH]): + the time-stamp counter increments at a constant rate. + That rate may be set by the maximum core-clock to bus-clock ratio of the processor or may be set by + the maximum resolved frequency at which the processor is booted. The maximum resolved frequency may + differ from the maximum qualified frequency of the processor. + + The specific processor configuration determines the behavior. Constant TSC behavior ensures that the + duration of each clock tick is uniform and supports the use of the TSC as a wall clock timer even if + the processor core changes frequency. This is the architectural behavior moving forward. + + A Processor's support for invariant TSC is indicated by CPUID.0x80000007.EDX[8]. + + Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include +#include +#include "TscTimerLibInternal.h" + +UINT64 mTscFrequency; + +/** The constructor function determines the actual TSC frequency. + + First, Get TSC frequency from system configuration table with TSC frequency GUID, + if the table is not found, install it. + This function will always return EFI_SUCCESS. + + @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 EFI_SUCCESS. + +**/ +EFI_STATUS +EFIAPI +DxeTscTimerLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + UINT64 *TscFrequency; + + // + // Get TSC frequency from system configuration table with TSC frequency GUID. + // + Status = EfiGetSystemConfigurationTable (&gEfiTscFrequencyGuid, (VOID **) &TscFrequency); + if (Status == EFI_SUCCESS) { + mTscFrequency = *TscFrequency; + return EFI_SUCCESS; + } + + // + // TSC frequency GUID system configuration table is not found, install it. + // + + Status = gBS->AllocatePool (EfiBootServicesData, sizeof (UINT64), (VOID **) &TscFrequency); + ASSERT_EFI_ERROR (Status); + + *TscFrequency = InternalCalculateTscFrequency (); + // + // TscFrequency now points to the number of TSC counts per second, install system configuration table for it. + // + gBS->InstallConfigurationTable (&gEfiTscFrequencyGuid, TscFrequency); + + mTscFrequency = *TscFrequency; + return EFI_SUCCESS; +} + +/** Get TSC frequency. + + @return The number of TSC counts per second. + +**/ +UINT64 +InternalGetTscFrequency ( + VOID + ) +{ + return mTscFrequency; +} + diff --git a/PerformancePkg/Library/TscTimerLib/DxeTscTimerLib.inf b/PerformancePkg/Library/TscTimerLib/DxeTscTimerLib.inf new file mode 100644 index 0000000000..e0edd6f21e --- /dev/null +++ b/PerformancePkg/Library/TscTimerLib/DxeTscTimerLib.inf @@ -0,0 +1,59 @@ +## @file +# Dxe Timer Library which uses the Time Stamp Counter in the processor. +# +# A version of the Timer Library using the processor's TSC. +# The time stamp counter in newer processors may support an enhancement, referred to as invariant TSC. +# The invariant TSC runs at a constant rate in all ACPI P-, C-. and T-states. +# This is the architectural behavior moving forward. +# TSC reads are much more efficient and do not incur the overhead associated with a ring transition or +# access to a platform resource. +# +# Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = DxeTscTimerLib + FILE_GUID = 95ab030f-b4fd-4ee4-92a5-9e04e87634d9 + 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 = DxeTscTimerLibConstructor + + +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources.common] + TscTimerLibShare.c + DxeTscTimerLib.c + + +[Packages] + MdePkg/MdePkg.dec + PerformancePkg/PerformancePkg.dec + + +[LibraryClasses] + UefiBootServicesTableLib + PcdLib + PciLib + IoLib + BaseLib + UefiLib + DebugLib + +[Guids] + gEfiTscFrequencyGuid ## CONSUMES ## System Configuration Table + +[Pcd.common] + gPerformancePkgTokenSpaceGuid.PcdPerfPkgAcpiIoPortBaseAddress diff --git a/PerformancePkg/Library/TscTimerLib/PeiTscTimerLib.c b/PerformancePkg/Library/TscTimerLib/PeiTscTimerLib.c new file mode 100644 index 0000000000..af3600b007 --- /dev/null +++ b/PerformancePkg/Library/TscTimerLib/PeiTscTimerLib.c @@ -0,0 +1,76 @@ +/** @file + A Pei Timer Library implementation which uses the Time Stamp Counter in the processor. + + For Pentium 4 processors, Intel Xeon processors (family [0FH], models [03H and higher]); + for Intel Core Solo and Intel Core Duo processors (family [06H], model [0EH]); + for the Intel Xeon processor 5100 series and Intel Core 2 Duo processors (family [06H], model [0FH]); + for Intel Core 2 and Intel Xeon processors (family [06H], display_model [17H]); + for Intel Atom processors (family [06H], display_model [1CH]): + the time-stamp counter increments at a constant rate. + That rate may be set by the maximum core-clock to bus-clock ratio of the processor or may be set by + the maximum resolved frequency at which the processor is booted. The maximum resolved frequency may + differ from the maximum qualified frequency of the processor. + + The specific processor configuration determines the behavior. Constant TSC behavior ensures that the + duration of each clock tick is uniform and supports the use of the TSC as a wall clock timer even if + the processor core changes frequency. This is the architectural behavior moving forward. + + A Processor's support for invariant TSC is indicated by CPUID.0x80000007.EDX[8]. + + Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include "TscTimerLibInternal.h" + +/** Get TSC frequency from TSC frequency GUID HOB, if the HOB is not found, build it. + + @return The number of TSC counts per second. + +**/ +UINT64 +InternalGetTscFrequency ( + VOID + ) +{ + EFI_HOB_GUID_TYPE *GuidHob; + VOID *DataInHob; + UINT64 TscFrequency; + + // + // Get TSC frequency from TSC frequency GUID HOB. + // + GuidHob = GetFirstGuidHob (&gEfiTscFrequencyGuid); + if (GuidHob != NULL) { + DataInHob = GET_GUID_HOB_DATA (GuidHob); + TscFrequency = * (UINT64 *) DataInHob; + return TscFrequency; + } + + // + // TSC frequency GUID HOB is not found, build it. + // + + TscFrequency = InternalCalculateTscFrequency (); + // + // TscFrequency is now equal to the number of TSC counts per second, build GUID HOB for it. + // + BuildGuidDataHob ( + &gEfiTscFrequencyGuid, + &TscFrequency, + sizeof (UINT64) + ); + + return TscFrequency; +} + diff --git a/PerformancePkg/Library/TscTimerLib/PeiTscTimerLib.inf b/PerformancePkg/Library/TscTimerLib/PeiTscTimerLib.inf new file mode 100644 index 0000000000..177e4c3aed --- /dev/null +++ b/PerformancePkg/Library/TscTimerLib/PeiTscTimerLib.inf @@ -0,0 +1,55 @@ +## @file +# Pei Timer Library which uses the Time Stamp Counter in the processor. +# +# A version of the Timer Library using the processor's TSC. +# The time stamp counter in newer processors may support an enhancement, referred to as invariant TSC. +# The invariant TSC runs at a constant rate in all ACPI P-, C-. and T-states. +# This is the architectural behavior moving forward. +# TSC reads are much more efficient and do not incur the overhead associated with a ring transition or +# access to a platform resource. +# +# Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PeiTscTimerLib + FILE_GUID = 342C36C0-15DF-43b4-9EC9-FBF748BFB3D1 + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + LIBRARY_CLASS = TimerLib|PEIM PEI_CORE + + +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources.common] + TscTimerLibShare.c + PeiTscTimerLib.c + + +[Packages] + MdePkg/MdePkg.dec + PerformancePkg/PerformancePkg.dec + + +[LibraryClasses] + PcdLib + PciLib + IoLib + BaseLib + HobLib + +[Guids] + gEfiTscFrequencyGuid ## PRODUCES ## Hob + +[Pcd.common] + gPerformancePkgTokenSpaceGuid.PcdPerfPkgAcpiIoPortBaseAddress diff --git a/PerformancePkg/Library/TscTimerLib/TscTimerLibInternal.h b/PerformancePkg/Library/TscTimerLib/TscTimerLibInternal.h new file mode 100644 index 0000000000..a4ed0ebb31 --- /dev/null +++ b/PerformancePkg/Library/TscTimerLib/TscTimerLibInternal.h @@ -0,0 +1,55 @@ +/** @file + Internal header file for TscTimerLib instances. + + Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _TSC_TIMER_LIB_INTERNAL_H_ +#define _TSC_TIMER_LIB_INTERNAL_H_ + +#include + +#include +#include +#include +#include +#include + +/** Get TSC frequency. + + @return The number of TSC counts per second. + +**/ +UINT64 +InternalGetTscFrequency ( + VOID + ); + +/** Calculate TSC frequency. + + The TSC counting frequency is determined by comparing how far it counts + during a 1ms period as determined by the ACPI timer. The ACPI timer is + used because it counts at a known frequency. + If ACPI I/O space not enabled, this function will enable it. Then the + TSC is sampled, followed by waiting for 3579 clocks of the ACPI timer, or 1ms. + The TSC is then sampled again. The difference multiplied by 1000 is the TSC + frequency. There will be a small error because of the overhead of reading + the ACPI timer. An attempt is made to determine and compensate for this error. + + @return The number of TSC counts per second. + +**/ +UINT64 +InternalCalculateTscFrequency ( + VOID + ); + +#endif diff --git a/PerformancePkg/Library/TscTimerLib/TscTimerLibShare.c b/PerformancePkg/Library/TscTimerLib/TscTimerLibShare.c new file mode 100644 index 0000000000..161af00237 --- /dev/null +++ b/PerformancePkg/Library/TscTimerLib/TscTimerLibShare.c @@ -0,0 +1,275 @@ +/** @file + The Timer Library implementation which uses the Time Stamp Counter in the processor. + + For Pentium 4 processors, Intel Xeon processors (family [0FH], models [03H and higher]); + for Intel Core Solo and Intel Core Duo processors (family [06H], model [0EH]); + for the Intel Xeon processor 5100 series and Intel Core 2 Duo processors (family [06H], model [0FH]); + for Intel Core 2 and Intel Xeon processors (family [06H], display_model [17H]); + for Intel Atom processors (family [06H], display_model [1CH]): + the time-stamp counter increments at a constant rate. + That rate may be set by the maximum core-clock to bus-clock ratio of the processor or may be set by + the maximum resolved frequency at which the processor is booted. The maximum resolved frequency may + differ from the maximum qualified frequency of the processor. + + The specific processor configuration determines the behavior. Constant TSC behavior ensures that the + duration of each clock tick is uniform and supports the use of the TSC as a wall clock timer even if + the processor core changes frequency. This is the architectural behavior moving forward. + + A Processor's support for invariant TSC is indicated by CPUID.0x80000007.EDX[8]. + + Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "TscTimerLibInternal.h" + +/** Calculate TSC frequency. + + The TSC counting frequency is determined by comparing how far it counts + during a 1ms period as determined by the ACPI timer. The ACPI timer is + used because it counts at a known frequency. + If ACPI I/O space not enabled, this function will enable it. Then the + TSC is sampled, followed by waiting for 3579 clocks of the ACPI timer, or 1ms. + The TSC is then sampled again. The difference multiplied by 1000 is the TSC + frequency. There will be a small error because of the overhead of reading + the ACPI timer. An attempt is made to determine and compensate for this error. + + @return The number of TSC counts per second. + +**/ +UINT64 +InternalCalculateTscFrequency ( + VOID + ) +{ + UINT64 StartTSC; + UINT64 EndTSC; + UINT32 TimerAddr; + UINT32 Ticks; + UINT64 TscFrequency; + + // + // If ACPI I/O space is not enabled yet, program ACPI I/O base address and enable it. + // + if ((PciRead8 (PCI_ICH_LPC_ADDRESS (R_ICH_LPC_ACPI_CNT)) & B_ICH_LPC_ACPI_CNT_ACPI_EN) == 0) { + PciWrite16 (PCI_ICH_LPC_ADDRESS (R_ICH_LPC_ACPI_BASE), PcdGet16 (PcdPerfPkgAcpiIoPortBaseAddress)); + PciOr8 (PCI_ICH_LPC_ADDRESS (R_ICH_LPC_ACPI_CNT), B_ICH_LPC_ACPI_CNT_ACPI_EN); + } + + // + // ACPI I/O space should be enabled now, locate the ACPI Timer. + // ACPI I/O base address maybe have be initialized by other driver with different value, + // So get it from PCI space directly. + // + TimerAddr = ((PciRead16 (PCI_ICH_LPC_ADDRESS (R_ICH_LPC_ACPI_BASE))) & B_ICH_LPC_ACPI_BASE_BAR) + R_ACPI_PM1_TMR; + Ticks = IoRead32 (TimerAddr) + (3579); // Set Ticks to 1ms in the future + StartTSC = AsmReadTsc(); // Get base value for the TSC + // + // Wait until the ACPI timer has counted 1ms. + // Timer wrap-arounds are handled correctly by this function. + // When the current ACPI timer value is greater than 'Ticks', the while loop will exit. + // + while (((Ticks - IoRead32 (TimerAddr)) & BIT23) == 0) { + CpuPause(); + } + EndTSC = AsmReadTsc(); // TSC value 1ms later + + TscFrequency = MultU64x32 ( + (EndTSC - StartTSC), // Number of TSC counts in 1ms + 1000 // Number of ms in a second + ); + + 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[in] Delay A period of time to delay in ticks. + +**/ +VOID +InternalX86Delay ( + 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 specified number of MicroSeconds. + + @param[in] MicroSeconds The minimum number of microseconds to delay. + + @return The value of MicroSeconds input. + +**/ +UINTN +EFIAPI +MicroSecondDelay ( + IN UINTN MicroSeconds + ) +{ + InternalX86Delay ( + DivU64x32 ( + MultU64x64 ( + InternalGetTscFrequency (), + MicroSeconds + ), + 1000000u + ) + ); + return MicroSeconds; +} + +/** Stalls the CPU for at least the specified number of NanoSeconds. + + @param[in] NanoSeconds The minimum number of nanoseconds to delay. + + @return The value of NanoSeconds input. + +**/ +UINTN +EFIAPI +NanoSecondDelay ( + IN UINTN NanoSeconds + ) +{ + InternalX86Delay ( + DivU64x32 ( + MultU64x32 ( + InternalGetTscFrequency (), + (UINT32)NanoSeconds + ), + 1000000000u + ) + ); + return NanoSeconds; +} + +/** Retrieves the current value of the 64-bit free running Time-Stamp counter. + + The time-stamp counter (as implemented in the P6 family, Pentium, Pentium M, + Pentium 4, Intel Xeon, Intel Core Solo and Intel Core Duo processors and + later processors) is a 64-bit counter that is set to 0 following a RESET of + the processor. Following a RESET, the counter increments even when the + processor is halted by the HLT instruction or the external STPCLK# pin. Note + that the assertion of the external DPSLP# pin may cause the time-stamp + counter to stop. + + The properties of the counter can be retrieved by the + GetPerformanceCounterProperties() function. + + @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, 0x0, is returned in StartValue. If EndValue is not NULL, then the value + that the performance counter end with, 0xFFFFFFFFFFFFFFFF, is returned in + EndValue. + + The 64-bit frequency of the performance counter, in Hz, is always returned. + To determine average processor clock frequency, Intel recommends the use of + EMON logic to count processor core clocks over the period of time for which + the average is required. + + + @param[out] StartValue Pointer to where the performance counter's starting value is saved, or NULL. + @param[out] EndValue Pointer to where the performance counter's ending value is saved, or NULL. + + @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 InternalGetTscFrequency (); +} + +/** + 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/PerformancePkg/PerformancePkg.dsc b/PerformancePkg/PerformancePkg.dsc index 0717322d9f..b6b6c2df17 100644 --- a/PerformancePkg/PerformancePkg.dsc +++ b/PerformancePkg/PerformancePkg.dsc @@ -63,15 +63,16 @@ # that is different than the one below. # # TimerLib|MdePkg/Library/SecPeiDxeTimerLibCpu/SecPeiDxeTimerLibCpu.inf - TimerLib|PerformancePkg/Library/DxeTscTimerLib/DxeTscTimerLib.inf + TimerLib|PerformancePkg/Library/TscTimerLib/DxeTscTimerLib.inf [LibraryClasses.IPF] PalLib|MdePkg/Library/UefiPalLib/UefiPalLib.inf TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf [Components.IA32, Components.X64] - PerformancePkg/Library/DxeTscTimerLib/DxeTscTimerLib.inf - PerformancePkg/Library/PeiTscTimerLib/PeiTscTimerLib.inf + PerformancePkg/Library/TscTimerLib/DxeTscTimerLib.inf + PerformancePkg/Library/TscTimerLib/PeiTscTimerLib.inf + PerformancePkg/Library/TscTimerLib/BaseTscTimerLib.inf [Components] PerformancePkg/Dp_App/Dp.inf -- cgit v1.2.3