+++ /dev/null
-/** @file\r
- A Dxe Timer Library implementation which uses the Time Stamp Counter in the processor.\r
-\r
- For Pentium 4 processors, Intel Xeon processors (family [0FH], models [03H and higher]);\r
- for Intel Core Solo and Intel Core Duo processors (family [06H], model [0EH]);\r
- for the Intel Xeon processor 5100 series and Intel Core 2 Duo processors (family [06H], model [0FH]);\r
- for Intel Core 2 and Intel Xeon processors (family [06H], display_model [17H]);\r
- for Intel Atom processors (family [06H], display_model [1CH]):\r
- the time-stamp counter increments at a constant rate.\r
- That rate may be set by the maximum core-clock to bus-clock ratio of the processor or may be set by\r
- the maximum resolved frequency at which the processor is booted. The maximum resolved frequency may\r
- differ from the maximum qualified frequency of the processor.\r
-\r
- The specific processor configuration determines the behavior. Constant TSC behavior ensures that the\r
- duration of each clock tick is uniform and supports the use of the TSC as a wall clock timer even if\r
- the processor core changes frequency. This is the architectural behavior moving forward.\r
-\r
- A Processor's support for invariant TSC is indicated by CPUID.0x80000007.EDX[8].\r
-\r
- Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
- This program and the accompanying materials\r
- are licensed and made available under the terms and conditions of the BSD License\r
- which accompanies this distribution. The full text of the license may be found at\r
- http://opensource.org/licenses/bsd-license.php\r
-\r
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
- WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
-\r
-**/\r
-\r
-#include <PiDxe.h>\r
-#include <Ich/GenericIch.h>\r
-\r
-#include <Library/UefiBootServicesTableLib.h>\r
-#include <Library/TimerLib.h>\r
-#include <Library/BaseLib.h>\r
-#include <Library/IoLib.h>\r
-#include <Library/PciLib.h>\r
-#include <Library/PcdLib.h>\r
-#include <Library/UefiLib.h>\r
-#include <Library/DebugLib.h>\r
-\r
-#include <Guid/TscFrequency.h>\r
-\r
-UINT64 mTscFrequency;\r
-\r
-/** The constructor function determines the actual TSC frequency.\r
-\r
- First, Get TSC frequency from system configuration table with TSC frequency GUID,\r
- if the table is not found, install it.\r
-\r
- The TSC counting frequency is determined by comparing how far it counts\r
- during a 1ms period as determined by the ACPI timer. The ACPI timer is\r
- used because it counts at a known frequency.\r
- If ACPI I/O space not enabled, this function will enable it. Then the\r
- TSC is sampled, followed by waiting for 3579 clocks of the ACPI timer, or 1ms.\r
- The TSC is then sampled again. The difference multiplied by 1000 is the TSC\r
- frequency. There will be a small error because of the overhead of reading\r
- the ACPI timer. An attempt is made to determine and compensate for this error.\r
- This function will always return EFI_SUCCESS.\r
-\r
- @param ImageHandle The firmware allocated handle for the EFI image.\r
- @param SystemTable A pointer to the EFI System Table.\r
-\r
- @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-DxeTscTimerLibConstructor (\r
- IN EFI_HANDLE ImageHandle,\r
- IN EFI_SYSTEM_TABLE *SystemTable\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINT64 *TscFrequency;\r
- UINT64 StartTSC;\r
- UINT64 EndTSC;\r
- UINT32 TimerAddr;\r
- UINT32 Ticks;\r
-\r
- //\r
- // Get TSC frequency from system configuration table with TSC frequency GUID.\r
- //\r
- Status = EfiGetSystemConfigurationTable (&gEfiTscFrequencyGuid, (VOID **) &TscFrequency);\r
- if (Status == EFI_SUCCESS) {\r
- mTscFrequency = *TscFrequency;\r
- return EFI_SUCCESS;\r
- }\r
-\r
- //\r
- // TSC frequency GUID system configuration table is not found, install it.\r
- //\r
-\r
- //\r
- // If ACPI I/O space is not enabled yet, program ACPI I/O base address and enable it.\r
- //\r
- if ((PciRead8 (PCI_ICH_LPC_ADDRESS (R_ICH_LPC_ACPI_CNT)) & B_ICH_LPC_ACPI_CNT_ACPI_EN) == 0) {\r
- PciWrite16 (PCI_ICH_LPC_ADDRESS (R_ICH_LPC_ACPI_BASE), PcdGet16 (PcdPerfPkgAcpiIoPortBaseAddress));\r
- PciOr8 (PCI_ICH_LPC_ADDRESS (R_ICH_LPC_ACPI_CNT), B_ICH_LPC_ACPI_CNT_ACPI_EN);\r
- }\r
-\r
- //\r
- // ACPI I/O space should be enabled now, locate the ACPI Timer.\r
- // ACPI I/O base address maybe have be initialized by other driver with different value,\r
- // So get it from PCI space directly.\r
- //\r
- TimerAddr = ((PciRead16 (PCI_ICH_LPC_ADDRESS (R_ICH_LPC_ACPI_BASE))) & B_ICH_LPC_ACPI_BASE_BAR) + R_ACPI_PM1_TMR;\r
- Ticks = IoRead32 (TimerAddr) + (3579); // Set Ticks to 1ms in the future\r
- StartTSC = AsmReadTsc(); // Get base value for the TSC\r
- //\r
- // Wait until the ACPI timer has counted 1ms.\r
- // Timer wrap-arounds are handled correctly by this function.\r
- // When the current ACPI timer value is greater than 'Ticks', the while loop will exit.\r
- //\r
- while (((Ticks - IoRead32 (TimerAddr)) & BIT23) == 0) {\r
- CpuPause();\r
- }\r
- EndTSC = AsmReadTsc(); // TSC value 1ms later\r
-\r
- Status = gBS->AllocatePool (EfiBootServicesData, sizeof (UINT64), (VOID **) &TscFrequency);\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- *TscFrequency = MultU64x32 (\r
- (EndTSC - StartTSC), // Number of TSC counts in 1ms\r
- 1000 // Number of ms in a second\r
- );\r
- //\r
- // TscFrequency now points to the number of TSC counts per second, install system configuration table for it.\r
- //\r
- gBS->InstallConfigurationTable (&gEfiTscFrequencyGuid, TscFrequency);\r
-\r
- mTscFrequency = *TscFrequency;\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/** Stalls the CPU for at least the given number of ticks.\r
-\r
- Stalls the CPU for at least the given number of ticks. It's invoked by\r
- MicroSecondDelay() and NanoSecondDelay().\r
-\r
- @param[in] Delay A period of time to delay in ticks.\r
-\r
-**/\r
-VOID\r
-InternalX86Delay (\r
- IN UINT64 Delay\r
- )\r
-{\r
- UINT64 Ticks;\r
-\r
- //\r
- // The target timer count is calculated here\r
- //\r
- Ticks = AsmReadTsc() + Delay;\r
-\r
- //\r
- // Wait until time out\r
- // Timer wrap-arounds are NOT handled correctly by this function.\r
- // Thus, this function must be called within 10 years of reset since\r
- // Intel guarantees a minimum of 10 years before the TSC wraps.\r
- //\r
- while (AsmReadTsc() <= Ticks) CpuPause();\r
-}\r
-\r
-/** Stalls the CPU for at least the specified number of MicroSeconds.\r
-\r
- @param[in] MicroSeconds The minimum number of microseconds to delay.\r
-\r
- @return The value of MicroSeconds input.\r
-\r
-**/\r
-UINTN\r
-EFIAPI\r
-MicroSecondDelay (\r
- IN UINTN MicroSeconds\r
- )\r
-{\r
- InternalX86Delay (\r
- DivU64x32 (\r
- MultU64x64 (\r
- mTscFrequency,\r
- MicroSeconds\r
- ),\r
- 1000000u\r
- )\r
- );\r
- return MicroSeconds;\r
-}\r
-\r
-/** Stalls the CPU for at least the specified number of NanoSeconds.\r
-\r
- @param[in] NanoSeconds The minimum number of nanoseconds to delay.\r
-\r
- @return The value of NanoSeconds input.\r
-\r
-**/\r
-UINTN\r
-EFIAPI\r
-NanoSecondDelay (\r
- IN UINTN NanoSeconds\r
- )\r
-{\r
- InternalX86Delay (\r
- DivU64x32 (\r
- MultU64x32 (\r
- mTscFrequency,\r
- (UINT32)NanoSeconds\r
- ),\r
- 1000000000u\r
- )\r
- );\r
- return NanoSeconds;\r
-}\r
-\r
-/** Retrieves the current value of the 64-bit free running Time-Stamp counter.\r
-\r
- The time-stamp counter (as implemented in the P6 family, Pentium, Pentium M,\r
- Pentium 4, Intel Xeon, Intel Core Solo and Intel Core Duo processors and\r
- later processors) is a 64-bit counter that is set to 0 following a RESET of\r
- the processor. Following a RESET, the counter increments even when the\r
- processor is halted by the HLT instruction or the external STPCLK# pin. Note\r
- that the assertion of the external DPSLP# pin may cause the time-stamp\r
- counter to stop.\r
-\r
- The properties of the counter can be retrieved by the\r
- GetPerformanceCounterProperties() function.\r
-\r
- @return The current value of the free running performance counter.\r
-\r
-**/\r
-UINT64\r
-EFIAPI\r
-GetPerformanceCounter (\r
- VOID\r
- )\r
-{\r
- return AsmReadTsc();\r
-}\r
-\r
-/** Retrieves the 64-bit frequency in Hz and the range of performance counter\r
- values.\r
-\r
- If StartValue is not NULL, then the value that the performance counter starts\r
- with, 0x0, is returned in StartValue. If EndValue is not NULL, then the value\r
- that the performance counter end with, 0xFFFFFFFFFFFFFFFF, is returned in\r
- EndValue.\r
-\r
- The 64-bit frequency of the performance counter, in Hz, is always returned.\r
- To determine average processor clock frequency, Intel recommends the use of\r
- EMON logic to count processor core clocks over the period of time for which\r
- the average is required.\r
-\r
-\r
- @param[out] StartValue Pointer to where the performance counter's starting value is saved, or NULL.\r
- @param[out] EndValue Pointer to where the performance counter's ending value is saved, or NULL.\r
-\r
- @return The frequency in Hz.\r
-\r
-**/\r
-UINT64\r
-EFIAPI\r
-GetPerformanceCounterProperties (\r
- OUT UINT64 *StartValue, OPTIONAL\r
- OUT UINT64 *EndValue OPTIONAL\r
- )\r
-{\r
- if (StartValue != NULL) {\r
- *StartValue = 0;\r
- }\r
- if (EndValue != NULL) {\r
- *EndValue = 0xFFFFFFFFFFFFFFFFull;\r
- }\r
-\r
- return mTscFrequency;\r
-}\r
-\r
-/**\r
- Converts elapsed ticks of performance counter to time in nanoseconds.\r
-\r
- This function converts the elapsed ticks of running performance counter to\r
- time value in unit of nanoseconds.\r
-\r
- @param Ticks The number of elapsed ticks of running performance counter.\r
-\r
- @return The elapsed time in nanoseconds.\r
-\r
-**/\r
-UINT64\r
-EFIAPI\r
-GetTimeInNanoSecond (\r
- IN UINT64 Ticks\r
- )\r
-{\r
- UINT64 Frequency;\r
- UINT64 NanoSeconds;\r
- UINT64 Remainder;\r
- INTN Shift;\r
-\r
- Frequency = GetPerformanceCounterProperties (NULL, NULL);\r
-\r
- //\r
- // Ticks\r
- // Time = --------- x 1,000,000,000\r
- // Frequency\r
- //\r
- NanoSeconds = MultU64x32 (DivU64x64Remainder (Ticks, Frequency, &Remainder), 1000000000u);\r
-\r
- //\r
- // Ensure (Remainder * 1,000,000,000) will not overflow 64-bit.\r
- // Since 2^29 < 1,000,000,000 = 0x3B9ACA00 < 2^30, Remainder should < 2^(64-30) = 2^34,\r
- // i.e. highest bit set in Remainder should <= 33.\r
- //\r
- Shift = MAX (0, HighBitSet64 (Remainder) - 33);\r
- Remainder = RShiftU64 (Remainder, (UINTN) Shift);\r
- Frequency = RShiftU64 (Frequency, (UINTN) Shift);\r
- NanoSeconds += DivU64x64Remainder (MultU64x32 (Remainder, 1000000000u), Frequency, NULL);\r
-\r
- return NanoSeconds;\r
-}\r
+++ /dev/null
-## @file\r
-# Dxe Timer Library which uses the Time Stamp Counter in the processor.\r
-#\r
-# A version of the Timer Library using the processor's TSC.\r
-# The time stamp counter in newer processors may support an enhancement, referred to as invariant TSC.\r
-# The invariant TSC runs at a constant rate in all ACPI P-, C-. and T-states.\r
-# This is the architectural behavior moving forward.\r
-# TSC reads are much more efficient and do not incur the overhead associated with a ring transition or\r
-# access to a platform resource.\r
-#\r
-# Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
-# This program and the accompanying materials\r
-# are licensed and made available under the terms and conditions of the BSD License\r
-# which accompanies this distribution. The full text of the license may be found at\r
-# http://opensource.org/licenses/bsd-license.php\r
-# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
-#\r
-##\r
-\r
-[Defines]\r
- INF_VERSION = 0x00010005\r
- BASE_NAME = DxeTscTimerLib\r
- FILE_GUID = 95ab030f-b4fd-4ee4-92a5-9e04e87634d9\r
- MODULE_TYPE = DXE_DRIVER\r
- VERSION_STRING = 1.0\r
- LIBRARY_CLASS = TimerLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER SMM_CORE\r
-\r
- CONSTRUCTOR = DxeTscTimerLibConstructor\r
-\r
-\r
-#\r
-# VALID_ARCHITECTURES = IA32 X64\r
-#\r
-\r
-[Sources.common]\r
- DxeTscTimerLib.c\r
-\r
-\r
-[Packages]\r
- MdePkg/MdePkg.dec\r
- PerformancePkg/PerformancePkg.dec\r
-\r
-\r
-[LibraryClasses]\r
- UefiBootServicesTableLib\r
- PcdLib\r
- PciLib\r
- IoLib\r
- BaseLib\r
- UefiLib\r
- DebugLib\r
-\r
-[Guids]\r
- gEfiTscFrequencyGuid ## CONSUMES ## System Configuration Table\r
-\r
-[Pcd.common]\r
- gPerformancePkgTokenSpaceGuid.PcdPerfPkgAcpiIoPortBaseAddress\r
+++ /dev/null
-/** @file\r
- A Pei Timer Library implementation which uses the Time Stamp Counter in the processor.\r
-\r
- For Pentium 4 processors, Intel Xeon processors (family [0FH], models [03H and higher]);\r
- for Intel Core Solo and Intel Core Duo processors (family [06H], model [0EH]);\r
- for the Intel Xeon processor 5100 series and Intel Core 2 Duo processors (family [06H], model [0FH]);\r
- for Intel Core 2 and Intel Xeon processors (family [06H], display_model [17H]);\r
- for Intel Atom processors (family [06H], display_model [1CH]):\r
- the time-stamp counter increments at a constant rate.\r
- That rate may be set by the maximum core-clock to bus-clock ratio of the processor or may be set by\r
- the maximum resolved frequency at which the processor is booted. The maximum resolved frequency may\r
- differ from the maximum qualified frequency of the processor.\r
-\r
- The specific processor configuration determines the behavior. Constant TSC behavior ensures that the\r
- duration of each clock tick is uniform and supports the use of the TSC as a wall clock timer even if\r
- the processor core changes frequency. This is the architectural behavior moving forward.\r
-\r
- A Processor's support for invariant TSC is indicated by CPUID.0x80000007.EDX[8].\r
-\r
- Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
- This program and the accompanying materials\r
- are licensed and made available under the terms and conditions of the BSD License\r
- which accompanies this distribution. The full text of the license may be found at\r
- http://opensource.org/licenses/bsd-license.php\r
-\r
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
- WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
-\r
-**/\r
-\r
-#include <PiPei.h>\r
-#include <Ich/GenericIch.h>\r
-\r
-#include <Library/TimerLib.h>\r
-#include <Library/BaseLib.h>\r
-#include <Library/IoLib.h>\r
-#include <Library/PciLib.h>\r
-#include <Library/PcdLib.h>\r
-#include <Library/HobLib.h>\r
-\r
-#include <Guid/TscFrequency.h>\r
-\r
-/** Get TSC frequency from TSC frequency GUID HOB, if the HOB is not found, build it.\r
-\r
- The TSC counting frequency is determined by comparing how far it counts\r
- during a 1ms period as determined by the ACPI timer. The ACPI timer is\r
- used because it counts at a known frequency.\r
- If ACPI I/O space not enabled, this function will enable it. Then the\r
- TSC is sampled, followed by waiting for 3579 clocks of the ACPI timer, or 1ms.\r
- The TSC is then sampled again. The difference multiplied by 1000 is the TSC\r
- frequency. There will be a small error because of the overhead of reading\r
- the ACPI timer.\r
-\r
- @return The number of TSC counts per second.\r
-\r
-**/\r
-UINT64\r
-InternalGetTscFrequency (\r
- VOID\r
- )\r
-{\r
- EFI_HOB_GUID_TYPE *GuidHob;\r
- VOID *DataInHob;\r
- UINT64 StartTSC;\r
- UINT64 EndTSC;\r
- UINT32 TimerAddr;\r
- UINT32 Ticks;\r
- UINT64 TscFrequency;\r
-\r
- //\r
- // Get TSC frequency from TSC frequency GUID HOB.\r
- //\r
- GuidHob = GetFirstGuidHob (&gEfiTscFrequencyGuid);\r
- if (GuidHob != NULL) {\r
- DataInHob = GET_GUID_HOB_DATA (GuidHob);\r
- TscFrequency = * (UINT64 *) DataInHob;\r
- return TscFrequency;\r
- }\r
-\r
- //\r
- // TSC frequency GUID HOB is not found, build it.\r
- //\r
-\r
- //\r
- // If ACPI I/O space is not enabled yet, program ACPI I/O base address and enable it.\r
- //\r
- if ((PciRead8 (PCI_ICH_LPC_ADDRESS (R_ICH_LPC_ACPI_CNT)) & B_ICH_LPC_ACPI_CNT_ACPI_EN) == 0) {\r
- PciWrite16 (PCI_ICH_LPC_ADDRESS (R_ICH_LPC_ACPI_BASE), PcdGet16 (PcdPerfPkgAcpiIoPortBaseAddress));\r
- PciOr8 (PCI_ICH_LPC_ADDRESS (R_ICH_LPC_ACPI_CNT), B_ICH_LPC_ACPI_CNT_ACPI_EN);\r
- }\r
-\r
- //\r
- // ACPI I/O space should be enabled now, locate the ACPI Timer.\r
- // ACPI I/O base address maybe have be initialized by other driver with different value,\r
- // So get it from PCI space directly.\r
- //\r
- TimerAddr = ((PciRead16 (PCI_ICH_LPC_ADDRESS (R_ICH_LPC_ACPI_BASE))) & B_ICH_LPC_ACPI_BASE_BAR) + R_ACPI_PM1_TMR;\r
- Ticks = IoRead32 (TimerAddr) + (3579); // Set Ticks to 1ms in the future\r
- StartTSC = AsmReadTsc(); // Get base value for the TSC\r
- //\r
- // Wait until the ACPI timer has counted 1ms.\r
- // Timer wrap-arounds are handled correctly by this function.\r
- // When the current ACPI timer value is greater than 'Ticks', the while loop will exit.\r
- //\r
- while (((Ticks - IoRead32 (TimerAddr)) & BIT23) == 0) {\r
- CpuPause();\r
- }\r
- EndTSC = AsmReadTsc(); // TSC value 1ms later\r
-\r
- TscFrequency = MultU64x32 (\r
- (EndTSC - StartTSC), // Number of TSC counts in 1ms\r
- 1000 // Number of ms in a second\r
- );\r
- //\r
- // TscFrequency is now equal to the number of TSC counts per second, build GUID HOB for it.\r
- //\r
- BuildGuidDataHob (\r
- &gEfiTscFrequencyGuid,\r
- &TscFrequency,\r
- sizeof (UINT64)\r
- );\r
-\r
- return TscFrequency;\r
-}\r
-\r
-/** Stalls the CPU for at least the given number of ticks.\r
-\r
- Stalls the CPU for at least the given number of ticks. It's invoked by\r
- MicroSecondDelay() and NanoSecondDelay().\r
-\r
- @param[in] Delay A period of time to delay in ticks.\r
-\r
-**/\r
-VOID\r
-InternalX86Delay (\r
- IN UINT64 Delay\r
- )\r
-{\r
- UINT64 Ticks;\r
-\r
- //\r
- // The target timer count is calculated here\r
- //\r
- Ticks = AsmReadTsc() + Delay;\r
-\r
- //\r
- // Wait until time out\r
- // Timer wrap-arounds are NOT handled correctly by this function.\r
- // Thus, this function must be called within 10 years of reset since\r
- // Intel guarantees a minimum of 10 years before the TSC wraps.\r
- //\r
- while (AsmReadTsc() <= Ticks) CpuPause();\r
-}\r
-\r
-/** Stalls the CPU for at least the specified number of MicroSeconds.\r
-\r
- @param[in] MicroSeconds The minimum number of microseconds to delay.\r
-\r
- @return The value of MicroSeconds input.\r
-\r
-**/\r
-UINTN\r
-EFIAPI\r
-MicroSecondDelay (\r
- IN UINTN MicroSeconds\r
- )\r
-{\r
- InternalX86Delay (\r
- DivU64x32 (\r
- MultU64x64 (\r
- InternalGetTscFrequency (),\r
- MicroSeconds\r
- ),\r
- 1000000u\r
- )\r
- );\r
- return MicroSeconds;\r
-}\r
-\r
-/** Stalls the CPU for at least the specified number of NanoSeconds.\r
-\r
- @param[in] NanoSeconds The minimum number of nanoseconds to delay.\r
-\r
- @return The value of NanoSeconds input.\r
-\r
-**/\r
-UINTN\r
-EFIAPI\r
-NanoSecondDelay (\r
- IN UINTN NanoSeconds\r
- )\r
-{\r
- InternalX86Delay (\r
- DivU64x32 (\r
- MultU64x32 (\r
- InternalGetTscFrequency (),\r
- (UINT32)NanoSeconds\r
- ),\r
- 1000000000u\r
- )\r
- );\r
- return NanoSeconds;\r
-}\r
-\r
-/** Retrieves the current value of the 64-bit free running Time-Stamp counter.\r
-\r
- The time-stamp counter (as implemented in the P6 family, Pentium, Pentium M,\r
- Pentium 4, Intel Xeon, Intel Core Solo and Intel Core Duo processors and\r
- later processors) is a 64-bit counter that is set to 0 following a RESET of\r
- the processor. Following a RESET, the counter increments even when the\r
- processor is halted by the HLT instruction or the external STPCLK# pin. Note\r
- that the assertion of the external DPSLP# pin may cause the time-stamp\r
- counter to stop.\r
-\r
- The properties of the counter can be retrieved by the\r
- GetPerformanceCounterProperties() function.\r
-\r
- @return The current value of the free running performance counter.\r
-\r
-**/\r
-UINT64\r
-EFIAPI\r
-GetPerformanceCounter (\r
- VOID\r
- )\r
-{\r
- return AsmReadTsc();\r
-}\r
-\r
-/** Retrieves the 64-bit frequency in Hz and the range of performance counter\r
- values.\r
-\r
- If StartValue is not NULL, then the value that the performance counter starts\r
- with, 0x0, is returned in StartValue. If EndValue is not NULL, then the value\r
- that the performance counter end with, 0xFFFFFFFFFFFFFFFF, is returned in\r
- EndValue.\r
-\r
- The 64-bit frequency of the performance counter, in Hz, is always returned.\r
- To determine average processor clock frequency, Intel recommends the use of\r
- EMON logic to count processor core clocks over the period of time for which\r
- the average is required.\r
-\r
-\r
- @param[out] StartValue Pointer to where the performance counter's starting value is saved, or NULL.\r
- @param[out] EndValue Pointer to where the performance counter's ending value is saved, or NULL.\r
-\r
- @return The frequency in Hz.\r
-\r
-**/\r
-UINT64\r
-EFIAPI\r
-GetPerformanceCounterProperties (\r
- OUT UINT64 *StartValue, OPTIONAL\r
- OUT UINT64 *EndValue OPTIONAL\r
- )\r
-{\r
- if (StartValue != NULL) {\r
- *StartValue = 0;\r
- }\r
- if (EndValue != NULL) {\r
- *EndValue = 0xFFFFFFFFFFFFFFFFull;\r
- }\r
-\r
- return InternalGetTscFrequency ();\r
-}\r
-\r
-/**\r
- Converts elapsed ticks of performance counter to time in nanoseconds.\r
-\r
- This function converts the elapsed ticks of running performance counter to\r
- time value in unit of nanoseconds.\r
-\r
- @param Ticks The number of elapsed ticks of running performance counter.\r
-\r
- @return The elapsed time in nanoseconds.\r
-\r
-**/\r
-UINT64\r
-EFIAPI\r
-GetTimeInNanoSecond (\r
- IN UINT64 Ticks\r
- )\r
-{\r
- UINT64 Frequency;\r
- UINT64 NanoSeconds;\r
- UINT64 Remainder;\r
- INTN Shift;\r
-\r
- Frequency = GetPerformanceCounterProperties (NULL, NULL);\r
-\r
- //\r
- // Ticks\r
- // Time = --------- x 1,000,000,000\r
- // Frequency\r
- //\r
- NanoSeconds = MultU64x32 (DivU64x64Remainder (Ticks, Frequency, &Remainder), 1000000000u);\r
-\r
- //\r
- // Ensure (Remainder * 1,000,000,000) will not overflow 64-bit.\r
- // Since 2^29 < 1,000,000,000 = 0x3B9ACA00 < 2^30, Remainder should < 2^(64-30) = 2^34,\r
- // i.e. highest bit set in Remainder should <= 33.\r
- //\r
- Shift = MAX (0, HighBitSet64 (Remainder) - 33);\r
- Remainder = RShiftU64 (Remainder, (UINTN) Shift);\r
- Frequency = RShiftU64 (Frequency, (UINTN) Shift);\r
- NanoSeconds += DivU64x64Remainder (MultU64x32 (Remainder, 1000000000u), Frequency, NULL);\r
-\r
- return NanoSeconds;\r
-}\r
+++ /dev/null
-## @file\r
-# Pei Timer Library which uses the Time Stamp Counter in the processor.\r
-#\r
-# A version of the Timer Library using the processor's TSC.\r
-# The time stamp counter in newer processors may support an enhancement, referred to as invariant TSC.\r
-# The invariant TSC runs at a constant rate in all ACPI P-, C-. and T-states.\r
-# This is the architectural behavior moving forward.\r
-# TSC reads are much more efficient and do not incur the overhead associated with a ring transition or\r
-# access to a platform resource.\r
-#\r
-# Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
-# This program and the accompanying materials\r
-# are licensed and made available under the terms and conditions of the BSD License\r
-# which accompanies this distribution. The full text of the license may be found at\r
-# http://opensource.org/licenses/bsd-license.php\r
-# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
-#\r
-##\r
-\r
-[Defines]\r
- INF_VERSION = 0x00010005\r
- BASE_NAME = PeiTscTimerLib\r
- FILE_GUID = 342C36C0-15DF-43b4-9EC9-FBF748BFB3D1\r
- MODULE_TYPE = PEIM\r
- VERSION_STRING = 1.0\r
- LIBRARY_CLASS = TimerLib|SEC PEIM PEI_CORE\r
-\r
-\r
-#\r
-# VALID_ARCHITECTURES = IA32 X64\r
-#\r
-\r
-[Sources.common]\r
- PeiTscTimerLib.c\r
-\r
-\r
-[Packages]\r
- MdePkg/MdePkg.dec\r
- PerformancePkg/PerformancePkg.dec\r
-\r
-\r
-[LibraryClasses]\r
- PcdLib\r
- PciLib\r
- IoLib\r
- BaseLib\r
- HobLib\r
-\r
-[Guids]\r
- gEfiTscFrequencyGuid ## PRODUCES ## Hob\r
-\r
-[Pcd.common]\r
- gPerformancePkgTokenSpaceGuid.PcdPerfPkgAcpiIoPortBaseAddress\r
--- /dev/null
+/** @file\r
+ A Base Timer Library implementation which uses the Time Stamp Counter in the processor.\r
+\r
+ For Pentium 4 processors, Intel Xeon processors (family [0FH], models [03H and higher]);\r
+ for Intel Core Solo and Intel Core Duo processors (family [06H], model [0EH]);\r
+ for the Intel Xeon processor 5100 series and Intel Core 2 Duo processors (family [06H], model [0FH]);\r
+ for Intel Core 2 and Intel Xeon processors (family [06H], display_model [17H]);\r
+ for Intel Atom processors (family [06H], display_model [1CH]):\r
+ the time-stamp counter increments at a constant rate.\r
+ That rate may be set by the maximum core-clock to bus-clock ratio of the processor or may be set by\r
+ the maximum resolved frequency at which the processor is booted. The maximum resolved frequency may\r
+ differ from the maximum qualified frequency of the processor.\r
+\r
+ The specific processor configuration determines the behavior. Constant TSC behavior ensures that the\r
+ duration of each clock tick is uniform and supports the use of the TSC as a wall clock timer even if\r
+ the processor core changes frequency. This is the architectural behavior moving forward.\r
+\r
+ A Processor's support for invariant TSC is indicated by CPUID.0x80000007.EDX[8].\r
+\r
+ Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "TscTimerLibInternal.h"\r
+\r
+UINT64 mTscFrequency = 0;\r
+\r
+/** Get TSC frequency.\r
+\r
+ @return The number of TSC counts per second.\r
+\r
+**/\r
+UINT64\r
+InternalGetTscFrequency (\r
+ VOID\r
+ )\r
+{\r
+ UINT64 TscFrequency;\r
+\r
+ if (mTscFrequency != 0) {\r
+ return mTscFrequency;\r
+ }\r
+\r
+ TscFrequency = InternalCalculateTscFrequency ();\r
+\r
+ mTscFrequency = TscFrequency;\r
+\r
+ return TscFrequency;\r
+}\r
+\r
--- /dev/null
+## @file\r
+# Base Timer Library which uses the Time Stamp Counter in the processor.\r
+#\r
+# Note: There will be 1ms penalty to get TSC frequency every time\r
+# by waiting for 3579 clocks of the ACPI timer, or 1ms.\r
+#\r
+# A version of the Timer Library using the processor's TSC.\r
+# The time stamp counter in newer processors may support an enhancement, referred to as invariant TSC.\r
+# The invariant TSC runs at a constant rate in all ACPI P-, C-. and T-states.\r
+# This is the architectural behavior moving forward.\r
+# TSC reads are much more efficient and do not incur the overhead associated with a ring transition or\r
+# access to a platform resource.\r
+#\r
+# Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = BaseTscTimerLib\r
+ FILE_GUID = D29338B9-50FE-4e4f-B7D4-A150A2C1F4FB\r
+ MODULE_TYPE = BASE\r
+ VERSION_STRING = 1.0\r
+ LIBRARY_CLASS = TimerLib\r
+\r
+\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64\r
+#\r
+\r
+[Sources.common]\r
+ TscTimerLibShare.c\r
+ BaseTscTimerLib.c\r
+\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ PerformancePkg/PerformancePkg.dec\r
+\r
+\r
+[LibraryClasses]\r
+ PcdLib\r
+ PciLib\r
+ IoLib\r
+ BaseLib\r
+\r
+[Pcd.common]\r
+ gPerformancePkgTokenSpaceGuid.PcdPerfPkgAcpiIoPortBaseAddress\r
--- /dev/null
+/** @file\r
+ A Dxe Timer Library implementation which uses the Time Stamp Counter in the processor.\r
+\r
+ For Pentium 4 processors, Intel Xeon processors (family [0FH], models [03H and higher]);\r
+ for Intel Core Solo and Intel Core Duo processors (family [06H], model [0EH]);\r
+ for the Intel Xeon processor 5100 series and Intel Core 2 Duo processors (family [06H], model [0FH]);\r
+ for Intel Core 2 and Intel Xeon processors (family [06H], display_model [17H]);\r
+ for Intel Atom processors (family [06H], display_model [1CH]):\r
+ the time-stamp counter increments at a constant rate.\r
+ That rate may be set by the maximum core-clock to bus-clock ratio of the processor or may be set by\r
+ the maximum resolved frequency at which the processor is booted. The maximum resolved frequency may\r
+ differ from the maximum qualified frequency of the processor.\r
+\r
+ The specific processor configuration determines the behavior. Constant TSC behavior ensures that the\r
+ duration of each clock tick is uniform and supports the use of the TSC as a wall clock timer even if\r
+ the processor core changes frequency. This is the architectural behavior moving forward.\r
+\r
+ A Processor's support for invariant TSC is indicated by CPUID.0x80000007.EDX[8].\r
+\r
+ Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <PiDxe.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Guid/TscFrequency.h>\r
+#include "TscTimerLibInternal.h"\r
+\r
+UINT64 mTscFrequency;\r
+\r
+/** The constructor function determines the actual TSC frequency.\r
+\r
+ First, Get TSC frequency from system configuration table with TSC frequency GUID,\r
+ if the table is not found, install it.\r
+ This function will always return EFI_SUCCESS.\r
+\r
+ @param ImageHandle The firmware allocated handle for the EFI image.\r
+ @param SystemTable A pointer to the EFI System Table.\r
+\r
+ @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DxeTscTimerLibConstructor (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT64 *TscFrequency;\r
+\r
+ //\r
+ // Get TSC frequency from system configuration table with TSC frequency GUID.\r
+ //\r
+ Status = EfiGetSystemConfigurationTable (&gEfiTscFrequencyGuid, (VOID **) &TscFrequency);\r
+ if (Status == EFI_SUCCESS) {\r
+ mTscFrequency = *TscFrequency;\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // TSC frequency GUID system configuration table is not found, install it.\r
+ //\r
+\r
+ Status = gBS->AllocatePool (EfiBootServicesData, sizeof (UINT64), (VOID **) &TscFrequency);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ *TscFrequency = InternalCalculateTscFrequency ();\r
+ //\r
+ // TscFrequency now points to the number of TSC counts per second, install system configuration table for it.\r
+ //\r
+ gBS->InstallConfigurationTable (&gEfiTscFrequencyGuid, TscFrequency);\r
+\r
+ mTscFrequency = *TscFrequency;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/** Get TSC frequency.\r
+\r
+ @return The number of TSC counts per second.\r
+\r
+**/\r
+UINT64\r
+InternalGetTscFrequency (\r
+ VOID\r
+ )\r
+{\r
+ return mTscFrequency;\r
+}\r
+\r
--- /dev/null
+## @file\r
+# Dxe Timer Library which uses the Time Stamp Counter in the processor.\r
+#\r
+# A version of the Timer Library using the processor's TSC.\r
+# The time stamp counter in newer processors may support an enhancement, referred to as invariant TSC.\r
+# The invariant TSC runs at a constant rate in all ACPI P-, C-. and T-states.\r
+# This is the architectural behavior moving forward.\r
+# TSC reads are much more efficient and do not incur the overhead associated with a ring transition or\r
+# access to a platform resource.\r
+#\r
+# Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = DxeTscTimerLib\r
+ FILE_GUID = 95ab030f-b4fd-4ee4-92a5-9e04e87634d9\r
+ MODULE_TYPE = DXE_DRIVER\r
+ VERSION_STRING = 1.0\r
+ LIBRARY_CLASS = TimerLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER SMM_CORE\r
+\r
+ CONSTRUCTOR = DxeTscTimerLibConstructor\r
+\r
+\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64\r
+#\r
+\r
+[Sources.common]\r
+ TscTimerLibShare.c\r
+ DxeTscTimerLib.c\r
+\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ PerformancePkg/PerformancePkg.dec\r
+\r
+\r
+[LibraryClasses]\r
+ UefiBootServicesTableLib\r
+ PcdLib\r
+ PciLib\r
+ IoLib\r
+ BaseLib\r
+ UefiLib\r
+ DebugLib\r
+\r
+[Guids]\r
+ gEfiTscFrequencyGuid ## CONSUMES ## System Configuration Table\r
+\r
+[Pcd.common]\r
+ gPerformancePkgTokenSpaceGuid.PcdPerfPkgAcpiIoPortBaseAddress\r
--- /dev/null
+/** @file\r
+ A Pei Timer Library implementation which uses the Time Stamp Counter in the processor.\r
+\r
+ For Pentium 4 processors, Intel Xeon processors (family [0FH], models [03H and higher]);\r
+ for Intel Core Solo and Intel Core Duo processors (family [06H], model [0EH]);\r
+ for the Intel Xeon processor 5100 series and Intel Core 2 Duo processors (family [06H], model [0FH]);\r
+ for Intel Core 2 and Intel Xeon processors (family [06H], display_model [17H]);\r
+ for Intel Atom processors (family [06H], display_model [1CH]):\r
+ the time-stamp counter increments at a constant rate.\r
+ That rate may be set by the maximum core-clock to bus-clock ratio of the processor or may be set by\r
+ the maximum resolved frequency at which the processor is booted. The maximum resolved frequency may\r
+ differ from the maximum qualified frequency of the processor.\r
+\r
+ The specific processor configuration determines the behavior. Constant TSC behavior ensures that the\r
+ duration of each clock tick is uniform and supports the use of the TSC as a wall clock timer even if\r
+ the processor core changes frequency. This is the architectural behavior moving forward.\r
+\r
+ A Processor's support for invariant TSC is indicated by CPUID.0x80000007.EDX[8].\r
+\r
+ Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <PiPei.h>\r
+#include <Library/HobLib.h>\r
+#include <Guid/TscFrequency.h>\r
+#include "TscTimerLibInternal.h"\r
+\r
+/** Get TSC frequency from TSC frequency GUID HOB, if the HOB is not found, build it.\r
+\r
+ @return The number of TSC counts per second.\r
+\r
+**/\r
+UINT64\r
+InternalGetTscFrequency (\r
+ VOID\r
+ )\r
+{\r
+ EFI_HOB_GUID_TYPE *GuidHob;\r
+ VOID *DataInHob;\r
+ UINT64 TscFrequency;\r
+\r
+ //\r
+ // Get TSC frequency from TSC frequency GUID HOB.\r
+ //\r
+ GuidHob = GetFirstGuidHob (&gEfiTscFrequencyGuid);\r
+ if (GuidHob != NULL) {\r
+ DataInHob = GET_GUID_HOB_DATA (GuidHob);\r
+ TscFrequency = * (UINT64 *) DataInHob;\r
+ return TscFrequency;\r
+ }\r
+\r
+ //\r
+ // TSC frequency GUID HOB is not found, build it.\r
+ //\r
+\r
+ TscFrequency = InternalCalculateTscFrequency ();\r
+ //\r
+ // TscFrequency is now equal to the number of TSC counts per second, build GUID HOB for it.\r
+ //\r
+ BuildGuidDataHob (\r
+ &gEfiTscFrequencyGuid,\r
+ &TscFrequency,\r
+ sizeof (UINT64)\r
+ );\r
+\r
+ return TscFrequency;\r
+}\r
+\r
--- /dev/null
+## @file\r
+# Pei Timer Library which uses the Time Stamp Counter in the processor.\r
+#\r
+# A version of the Timer Library using the processor's TSC.\r
+# The time stamp counter in newer processors may support an enhancement, referred to as invariant TSC.\r
+# The invariant TSC runs at a constant rate in all ACPI P-, C-. and T-states.\r
+# This is the architectural behavior moving forward.\r
+# TSC reads are much more efficient and do not incur the overhead associated with a ring transition or\r
+# access to a platform resource.\r
+#\r
+# Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = PeiTscTimerLib\r
+ FILE_GUID = 342C36C0-15DF-43b4-9EC9-FBF748BFB3D1\r
+ MODULE_TYPE = PEIM\r
+ VERSION_STRING = 1.0\r
+ LIBRARY_CLASS = TimerLib|PEIM PEI_CORE\r
+\r
+\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64\r
+#\r
+\r
+[Sources.common]\r
+ TscTimerLibShare.c\r
+ PeiTscTimerLib.c\r
+\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ PerformancePkg/PerformancePkg.dec\r
+\r
+\r
+[LibraryClasses]\r
+ PcdLib\r
+ PciLib\r
+ IoLib\r
+ BaseLib\r
+ HobLib\r
+\r
+[Guids]\r
+ gEfiTscFrequencyGuid ## PRODUCES ## Hob\r
+\r
+[Pcd.common]\r
+ gPerformancePkgTokenSpaceGuid.PcdPerfPkgAcpiIoPortBaseAddress\r
--- /dev/null
+/** @file\r
+ Internal header file for TscTimerLib instances.\r
+\r
+ Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _TSC_TIMER_LIB_INTERNAL_H_\r
+#define _TSC_TIMER_LIB_INTERNAL_H_\r
+\r
+#include <Ich/GenericIch.h>\r
+\r
+#include <Library/TimerLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/IoLib.h>\r
+#include <Library/PciLib.h>\r
+#include <Library/PcdLib.h>\r
+\r
+/** Get TSC frequency.\r
+\r
+ @return The number of TSC counts per second.\r
+\r
+**/\r
+UINT64\r
+InternalGetTscFrequency (\r
+ VOID\r
+ );\r
+\r
+/** Calculate TSC frequency.\r
+\r
+ The TSC counting frequency is determined by comparing how far it counts\r
+ during a 1ms period as determined by the ACPI timer. The ACPI timer is\r
+ used because it counts at a known frequency.\r
+ If ACPI I/O space not enabled, this function will enable it. Then the\r
+ TSC is sampled, followed by waiting for 3579 clocks of the ACPI timer, or 1ms.\r
+ The TSC is then sampled again. The difference multiplied by 1000 is the TSC\r
+ frequency. There will be a small error because of the overhead of reading\r
+ the ACPI timer. An attempt is made to determine and compensate for this error.\r
+\r
+ @return The number of TSC counts per second.\r
+\r
+**/\r
+UINT64\r
+InternalCalculateTscFrequency (\r
+ VOID\r
+ );\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+ The Timer Library implementation which uses the Time Stamp Counter in the processor.\r
+\r
+ For Pentium 4 processors, Intel Xeon processors (family [0FH], models [03H and higher]);\r
+ for Intel Core Solo and Intel Core Duo processors (family [06H], model [0EH]);\r
+ for the Intel Xeon processor 5100 series and Intel Core 2 Duo processors (family [06H], model [0FH]);\r
+ for Intel Core 2 and Intel Xeon processors (family [06H], display_model [17H]);\r
+ for Intel Atom processors (family [06H], display_model [1CH]):\r
+ the time-stamp counter increments at a constant rate.\r
+ That rate may be set by the maximum core-clock to bus-clock ratio of the processor or may be set by\r
+ the maximum resolved frequency at which the processor is booted. The maximum resolved frequency may\r
+ differ from the maximum qualified frequency of the processor.\r
+\r
+ The specific processor configuration determines the behavior. Constant TSC behavior ensures that the\r
+ duration of each clock tick is uniform and supports the use of the TSC as a wall clock timer even if\r
+ the processor core changes frequency. This is the architectural behavior moving forward.\r
+\r
+ A Processor's support for invariant TSC is indicated by CPUID.0x80000007.EDX[8].\r
+\r
+ Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "TscTimerLibInternal.h"\r
+\r
+/** Calculate TSC frequency.\r
+\r
+ The TSC counting frequency is determined by comparing how far it counts\r
+ during a 1ms period as determined by the ACPI timer. The ACPI timer is\r
+ used because it counts at a known frequency.\r
+ If ACPI I/O space not enabled, this function will enable it. Then the\r
+ TSC is sampled, followed by waiting for 3579 clocks of the ACPI timer, or 1ms.\r
+ The TSC is then sampled again. The difference multiplied by 1000 is the TSC\r
+ frequency. There will be a small error because of the overhead of reading\r
+ the ACPI timer. An attempt is made to determine and compensate for this error.\r
+\r
+ @return The number of TSC counts per second.\r
+\r
+**/\r
+UINT64\r
+InternalCalculateTscFrequency (\r
+ VOID\r
+ )\r
+{\r
+ UINT64 StartTSC;\r
+ UINT64 EndTSC;\r
+ UINT32 TimerAddr;\r
+ UINT32 Ticks;\r
+ UINT64 TscFrequency;\r
+\r
+ //\r
+ // If ACPI I/O space is not enabled yet, program ACPI I/O base address and enable it.\r
+ //\r
+ if ((PciRead8 (PCI_ICH_LPC_ADDRESS (R_ICH_LPC_ACPI_CNT)) & B_ICH_LPC_ACPI_CNT_ACPI_EN) == 0) {\r
+ PciWrite16 (PCI_ICH_LPC_ADDRESS (R_ICH_LPC_ACPI_BASE), PcdGet16 (PcdPerfPkgAcpiIoPortBaseAddress));\r
+ PciOr8 (PCI_ICH_LPC_ADDRESS (R_ICH_LPC_ACPI_CNT), B_ICH_LPC_ACPI_CNT_ACPI_EN);\r
+ }\r
+\r
+ //\r
+ // ACPI I/O space should be enabled now, locate the ACPI Timer.\r
+ // ACPI I/O base address maybe have be initialized by other driver with different value,\r
+ // So get it from PCI space directly.\r
+ //\r
+ TimerAddr = ((PciRead16 (PCI_ICH_LPC_ADDRESS (R_ICH_LPC_ACPI_BASE))) & B_ICH_LPC_ACPI_BASE_BAR) + R_ACPI_PM1_TMR;\r
+ Ticks = IoRead32 (TimerAddr) + (3579); // Set Ticks to 1ms in the future\r
+ StartTSC = AsmReadTsc(); // Get base value for the TSC\r
+ //\r
+ // Wait until the ACPI timer has counted 1ms.\r
+ // Timer wrap-arounds are handled correctly by this function.\r
+ // When the current ACPI timer value is greater than 'Ticks', the while loop will exit.\r
+ //\r
+ while (((Ticks - IoRead32 (TimerAddr)) & BIT23) == 0) {\r
+ CpuPause();\r
+ }\r
+ EndTSC = AsmReadTsc(); // TSC value 1ms later\r
+\r
+ TscFrequency = MultU64x32 (\r
+ (EndTSC - StartTSC), // Number of TSC counts in 1ms\r
+ 1000 // Number of ms in a second\r
+ );\r
+\r
+ return TscFrequency;\r
+}\r
+\r
+/** Stalls the CPU for at least the given number of ticks.\r
+\r
+ Stalls the CPU for at least the given number of ticks. It's invoked by\r
+ MicroSecondDelay() and NanoSecondDelay().\r
+\r
+ @param[in] Delay A period of time to delay in ticks.\r
+\r
+**/\r
+VOID\r
+InternalX86Delay (\r
+ IN UINT64 Delay\r
+ )\r
+{\r
+ UINT64 Ticks;\r
+\r
+ //\r
+ // The target timer count is calculated here\r
+ //\r
+ Ticks = AsmReadTsc() + Delay;\r
+\r
+ //\r
+ // Wait until time out\r
+ // Timer wrap-arounds are NOT handled correctly by this function.\r
+ // Thus, this function must be called within 10 years of reset since\r
+ // Intel guarantees a minimum of 10 years before the TSC wraps.\r
+ //\r
+ while (AsmReadTsc() <= Ticks) CpuPause();\r
+}\r
+\r
+/** Stalls the CPU for at least the specified number of MicroSeconds.\r
+\r
+ @param[in] MicroSeconds The minimum number of microseconds to delay.\r
+\r
+ @return The value of MicroSeconds input.\r
+\r
+**/\r
+UINTN\r
+EFIAPI\r
+MicroSecondDelay (\r
+ IN UINTN MicroSeconds\r
+ )\r
+{\r
+ InternalX86Delay (\r
+ DivU64x32 (\r
+ MultU64x64 (\r
+ InternalGetTscFrequency (),\r
+ MicroSeconds\r
+ ),\r
+ 1000000u\r
+ )\r
+ );\r
+ return MicroSeconds;\r
+}\r
+\r
+/** Stalls the CPU for at least the specified number of NanoSeconds.\r
+\r
+ @param[in] NanoSeconds The minimum number of nanoseconds to delay.\r
+\r
+ @return The value of NanoSeconds input.\r
+\r
+**/\r
+UINTN\r
+EFIAPI\r
+NanoSecondDelay (\r
+ IN UINTN NanoSeconds\r
+ )\r
+{\r
+ InternalX86Delay (\r
+ DivU64x32 (\r
+ MultU64x32 (\r
+ InternalGetTscFrequency (),\r
+ (UINT32)NanoSeconds\r
+ ),\r
+ 1000000000u\r
+ )\r
+ );\r
+ return NanoSeconds;\r
+}\r
+\r
+/** Retrieves the current value of the 64-bit free running Time-Stamp counter.\r
+\r
+ The time-stamp counter (as implemented in the P6 family, Pentium, Pentium M,\r
+ Pentium 4, Intel Xeon, Intel Core Solo and Intel Core Duo processors and\r
+ later processors) is a 64-bit counter that is set to 0 following a RESET of\r
+ the processor. Following a RESET, the counter increments even when the\r
+ processor is halted by the HLT instruction or the external STPCLK# pin. Note\r
+ that the assertion of the external DPSLP# pin may cause the time-stamp\r
+ counter to stop.\r
+\r
+ The properties of the counter can be retrieved by the\r
+ GetPerformanceCounterProperties() function.\r
+\r
+ @return The current value of the free running performance counter.\r
+\r
+**/\r
+UINT64\r
+EFIAPI\r
+GetPerformanceCounter (\r
+ VOID\r
+ )\r
+{\r
+ return AsmReadTsc();\r
+}\r
+\r
+/** Retrieves the 64-bit frequency in Hz and the range of performance counter\r
+ values.\r
+\r
+ If StartValue is not NULL, then the value that the performance counter starts\r
+ with, 0x0, is returned in StartValue. If EndValue is not NULL, then the value\r
+ that the performance counter end with, 0xFFFFFFFFFFFFFFFF, is returned in\r
+ EndValue.\r
+\r
+ The 64-bit frequency of the performance counter, in Hz, is always returned.\r
+ To determine average processor clock frequency, Intel recommends the use of\r
+ EMON logic to count processor core clocks over the period of time for which\r
+ the average is required.\r
+\r
+\r
+ @param[out] StartValue Pointer to where the performance counter's starting value is saved, or NULL.\r
+ @param[out] EndValue Pointer to where the performance counter's ending value is saved, or NULL.\r
+\r
+ @return The frequency in Hz.\r
+\r
+**/\r
+UINT64\r
+EFIAPI\r
+GetPerformanceCounterProperties (\r
+ OUT UINT64 *StartValue, OPTIONAL\r
+ OUT UINT64 *EndValue OPTIONAL\r
+ )\r
+{\r
+ if (StartValue != NULL) {\r
+ *StartValue = 0;\r
+ }\r
+ if (EndValue != NULL) {\r
+ *EndValue = 0xFFFFFFFFFFFFFFFFull;\r
+ }\r
+\r
+ return InternalGetTscFrequency ();\r
+}\r
+\r
+/**\r
+ Converts elapsed ticks of performance counter to time in nanoseconds.\r
+\r
+ This function converts the elapsed ticks of running performance counter to\r
+ time value in unit of nanoseconds.\r
+\r
+ @param Ticks The number of elapsed ticks of running performance counter.\r
+\r
+ @return The elapsed time in nanoseconds.\r
+\r
+**/\r
+UINT64\r
+EFIAPI\r
+GetTimeInNanoSecond (\r
+ IN UINT64 Ticks\r
+ )\r
+{\r
+ UINT64 Frequency;\r
+ UINT64 NanoSeconds;\r
+ UINT64 Remainder;\r
+ INTN Shift;\r
+\r
+ Frequency = GetPerformanceCounterProperties (NULL, NULL);\r
+\r
+ //\r
+ // Ticks\r
+ // Time = --------- x 1,000,000,000\r
+ // Frequency\r
+ //\r
+ NanoSeconds = MultU64x32 (DivU64x64Remainder (Ticks, Frequency, &Remainder), 1000000000u);\r
+\r
+ //\r
+ // Ensure (Remainder * 1,000,000,000) will not overflow 64-bit.\r
+ // Since 2^29 < 1,000,000,000 = 0x3B9ACA00 < 2^30, Remainder should < 2^(64-30) = 2^34,\r
+ // i.e. highest bit set in Remainder should <= 33.\r
+ //\r
+ Shift = MAX (0, HighBitSet64 (Remainder) - 33);\r
+ Remainder = RShiftU64 (Remainder, (UINTN) Shift);\r
+ Frequency = RShiftU64 (Frequency, (UINTN) Shift);\r
+ NanoSeconds += DivU64x64Remainder (MultU64x32 (Remainder, 1000000000u), Frequency, NULL);\r
+\r
+ return NanoSeconds;\r
+}\r
# that is different than the one below.\r
#\r
# TimerLib|MdePkg/Library/SecPeiDxeTimerLibCpu/SecPeiDxeTimerLibCpu.inf\r
- TimerLib|PerformancePkg/Library/DxeTscTimerLib/DxeTscTimerLib.inf\r
+ TimerLib|PerformancePkg/Library/TscTimerLib/DxeTscTimerLib.inf\r
\r
[LibraryClasses.IPF]\r
PalLib|MdePkg/Library/UefiPalLib/UefiPalLib.inf\r
TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf\r
\r
[Components.IA32, Components.X64]\r
- PerformancePkg/Library/DxeTscTimerLib/DxeTscTimerLib.inf\r
- PerformancePkg/Library/PeiTscTimerLib/PeiTscTimerLib.inf\r
+ PerformancePkg/Library/TscTimerLib/DxeTscTimerLib.inf\r
+ PerformancePkg/Library/TscTimerLib/PeiTscTimerLib.inf\r
+ PerformancePkg/Library/TscTimerLib/BaseTscTimerLib.inf\r
\r
[Components]\r
PerformancePkg/Dp_App/Dp.inf\r