+/** @file\r
+ A non-functional instance of the Timer Library.\r
+\r
+ Copyright (c) 2007 - 2010, 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/BaseLib.h>\r
+#include <Library/TimerLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/EmuThunkLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiLib.h>\r
+\r
+#include <Protocol/Timer.h>\r
+\r
+\r
+STATIC UINT64 gTimerPeriod = 0;\r
+STATIC EFI_TIMER_ARCH_PROTOCOL *gTimerAp = NULL;\r
+STATIC EFI_EVENT gTimerEvent = NULL;\r
+STATIC VOID *gRegistration = NULL;\r
+\r
+VOID\r
+EFIAPI\r
+RegisterTimerArchProtocol (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ \r
+ Status = gBS->LocateProtocol (&gEfiTimerArchProtocolGuid, NULL, (VOID **)&gTimerAp);\r
+ if (!EFI_ERROR (Status)) { \r
+ Status = gTimerAp->GetTimerPeriod (gTimerAp, &gTimerPeriod);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ // Convert to Nanoseconds.\r
+ gTimerPeriod = MultU64x32 (gTimerPeriod, 100);\r
+ \r
+ if (gTimerEvent == NULL) {\r
+ Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, (VOID **)&gTimerEvent);\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+ }\r
+}\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 MicroSeconds The minimum number of microseconds to delay.\r
+\r
+ @return The value of MicroSeconds inputted.\r
+\r
+**/\r
+UINTN\r
+EFIAPI\r
+MicroSecondDelay (\r
+ IN UINTN MicroSeconds\r
+ )\r
+{\r
+ return NanoSecondDelay (MicroSeconds * 1000);\r
+}\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 The value of NanoSeconds inputted.\r
+\r
+**/\r
+UINTN\r
+EFIAPI\r
+NanoSecondDelay (\r
+ IN UINTN NanoSeconds\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT64 HundredNanoseconds;\r
+ UINTN Index;\r
+ \r
+ if ((gTimerPeriod != 0) && \r
+ ((UINT64)NanoSeconds > gTimerPeriod) && \r
+ (EfiGetCurrentTpl () == TPL_APPLICATION)) {\r
+ //\r
+ // This stall is long, so use gBS->WaitForEvent () to yield CPU to DXE Core\r
+ //\r
+ \r
+ HundredNanoseconds = DivU64x32 (NanoSeconds, 100);\r
+ Status = gBS->SetTimer (gTimerEvent, TimerRelative, HundredNanoseconds);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ Status = gBS->WaitForEvent (sizeof (gTimerEvent)/sizeof (EFI_EVENT), &gTimerEvent, &Index);\r
+ ASSERT_EFI_ERROR (Status);\r
+ \r
+ } else {\r
+ gEmuThunk->Sleep (NanoSeconds);\r
+ }\r
+ return NanoSeconds;\r
+}\r
+\r
+\r
+/**\r
+ Retrieves the current value of a 64-bit free running performance counter.\r
+\r
+ The 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 gEmuThunk->QueryPerformanceCounter ();\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
+\r
+ if (StartValue != NULL) {\r
+ *StartValue = 0ULL;\r
+ }\r
+ if (EndValue != NULL) {\r
+ *EndValue = (UINT64)-1LL;\r
+ }\r
+ \r
+ return gEmuThunk->QueryPerformanceFrequency ();\r
+}\r
+\r
+\r
+/**\r
+ Register for the Timer AP protocol.\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
+DxeTimerLibConstructor (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EfiCreateProtocolNotifyEvent (\r
+ &gEfiTimerArchProtocolGuid,\r
+ TPL_CALLBACK,\r
+ RegisterTimerArchProtocol,\r
+ NULL,\r
+ &gRegistration\r
+ );\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r