+/** @file\r
+ CPUID Leaf 0x15 for Core Crystal Clock frequency instance of Timer Library.\r
+\r
+ Copyright (c) 2019 Intel Corporation. All rights reserved.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#include <Base.h>\r
+#include <Library/TimerLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Register/Cpuid.h>\r
+\r
+GUID mCpuCrystalFrequencyHobGuid = { 0xe1ec5ad0, 0x8569, 0x46bd, { 0x8d, 0xcd, 0x3b, 0x9f, 0x6f, 0x45, 0x82, 0x7a } };\r
+\r
+/**\r
+ Internal function to retrieves the 64-bit frequency in Hz.\r
+\r
+ Internal function to retrieves the 64-bit frequency in Hz.\r
+\r
+ @return The frequency in Hz.\r
+\r
+**/\r
+UINT64\r
+InternalGetPerformanceCounterFrequency (\r
+ VOID\r
+ );\r
+\r
+/**\r
+ CPUID Leaf 0x15 for Core Crystal Clock Frequency.\r
+\r
+ The TSC counting frequency is determined by using CPUID leaf 0x15. Frequency in MHz = Core XTAL frequency * EBX/EAX.\r
+ In newer flavors of the CPU, core xtal frequency is returned in ECX or 0 if not supported.\r
+ @return The number of TSC counts per second.\r
+\r
+**/\r
+UINT64\r
+CpuidCoreClockCalculateTscFrequency (\r
+ VOID\r
+ )\r
+{\r
+ UINT64 TscFrequency;\r
+ UINT64 CoreXtalFrequency;\r
+ UINT32 RegEax;\r
+ UINT32 RegEbx;\r
+ UINT32 RegEcx;\r
+\r
+ //\r
+ // Use CPUID leaf 0x15 Time Stamp Counter and Nominal Core Crystal Clock Information\r
+ // EBX returns 0 if not supported. ECX, if non zero, provides Core Xtal Frequency in hertz.\r
+ // TSC frequency = (ECX, Core Xtal Frequency) * EBX/EAX.\r
+ //\r
+ AsmCpuid (CPUID_TIME_STAMP_COUNTER, &RegEax, &RegEbx, &RegEcx, NULL);\r
+\r
+ //\r
+ // If EAX or EBX returns 0, the XTAL ratio is not enumerated.\r
+ //\r
+ if (RegEax == 0 || RegEbx ==0 ) {\r
+ ASSERT (RegEax != 0);\r
+ ASSERT (RegEbx != 0);\r
+ return 0;\r
+ }\r
+ //\r
+ // If ECX returns 0, the XTAL frequency is not enumerated.\r
+ // And PcdCpuCoreCrystalClockFrequency defined should base on processor series.\r
+ //\r
+ if (RegEcx == 0) {\r
+ CoreXtalFrequency = PcdGet64 (PcdCpuCoreCrystalClockFrequency);\r
+ } else {\r
+ CoreXtalFrequency = (UINT64) RegEcx;\r
+ }\r
+\r
+ //\r
+ // Calculate TSC frequency = (ECX, Core Xtal Frequency) * EBX/EAX\r
+ //\r
+ TscFrequency = DivU64x32 (MultU64x32 (CoreXtalFrequency, RegEbx) + (UINT64)(RegEax >> 1), RegEax);\r
+\r
+ return TscFrequency;\r
+}\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 Delay A period of time to delay in ticks.\r
+\r
+**/\r
+VOID\r
+InternalCpuDelay (\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) {\r
+ CpuPause();\r
+ }\r
+}\r
+\r
+/**\r
+ Stalls the CPU for at least the given number of microseconds.\r
+\r
+ Stalls the CPU for the number of microseconds specified by MicroSeconds.\r
+\r
+ @param[in] MicroSeconds The minimum number of microseconds to delay.\r
+\r
+ @return MicroSeconds\r
+\r
+**/\r
+UINTN\r
+EFIAPI\r
+MicroSecondDelay (\r
+ IN UINTN MicroSeconds\r
+ )\r
+{\r
+\r
+ InternalCpuDelay (\r
+ DivU64x32 (\r
+ MultU64x64 (\r
+ MicroSeconds,\r
+ InternalGetPerformanceCounterFrequency ()\r
+ ),\r
+ 1000000u\r
+ )\r
+ );\r
+\r
+ return MicroSeconds;\r
+}\r
+\r
+/**\r
+ Stalls the CPU for at least the given number of nanoseconds.\r
+\r
+ Stalls the CPU for the number of nanoseconds specified by NanoSeconds.\r
+\r
+ @param NanoSeconds The minimum number of nanoseconds to delay.\r
+\r
+ @return NanoSeconds\r
+\r
+**/\r
+UINTN\r
+EFIAPI\r
+NanoSecondDelay (\r
+ IN UINTN NanoSeconds\r
+ )\r
+{\r
+\r
+ InternalCpuDelay (\r
+ DivU64x32 (\r
+ MultU64x64 (\r
+ NanoSeconds,\r
+ InternalGetPerformanceCounterFrequency ()\r
+ ),\r
+ 1000000000u\r
+ )\r
+ );\r
+\r
+ return NanoSeconds;\r
+}\r
+\r
+/**\r
+ Retrieves the current value of a 64-bit free running performance counter.\r
+\r
+ Retrieves the current value of a 64-bit free running performance counter. The\r
+ counter can either count up by 1 or count down by 1. If the physical\r
+ performance counter counts by a larger increment, then the counter values\r
+ must be translated. The properties of the counter can be retrieved from\r
+ GetPerformanceCounterProperties().\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
+/**\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 immediately after is it rolls over is returned in StartValue. If\r
+ EndValue is not NULL, then the value that the performance counter end with\r
+ immediately before it rolls over is returned in EndValue. The 64-bit\r
+ frequency of the performance counter in Hz is always returned. If StartValue\r
+ is less than EndValue, then the performance counter counts up. If StartValue\r
+ is greater than EndValue, then the performance counter counts down. For\r
+ example, a 64-bit free running counter that counts up would have a StartValue\r
+ of 0 and an EndValue of 0xFFFFFFFFFFFFFFFF. A 24-bit free running counter\r
+ that counts down would have a StartValue of 0xFFFFFF and an EndValue of 0.\r
+\r
+ @param StartValue The value the performance counter starts with when it\r
+ rolls over.\r
+ @param EndValue The value that the performance counter ends with before\r
+ it rolls over.\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
+\r
+ if (EndValue != NULL) {\r
+ *EndValue = 0xffffffffffffffffULL;\r
+ }\r
+ return InternalGetPerformanceCounterFrequency ();\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
+\r