\r
**/\r
\r
-static\r
+//\r
+// The following 2 arrays are used in calculating the frequency of local APIC\r
+// timer. Refer to IA-32 developers' manual for more details.\r
+//\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED\r
+CONST UINT32 mTimerLibLocalApicFrequencies[] = {\r
+ 100000000,\r
+ 133000000,\r
+ 200000000,\r
+ 166000000\r
+};\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED\r
+CONST UINT8 mTimerLibLocalApicDivisor[] = {\r
+ 0x02, 0x04, 0x08, 0x10,\r
+ 0x02, 0x04, 0x08, 0x10,\r
+ 0x20, 0x40, 0x80, 0x01,\r
+ 0x20, 0x40, 0x80, 0x01\r
+};\r
+\r
+/**\r
+ Internal function to retrieve the base address of local APIC.\r
+\r
+ Internal function to retrieve the base address of local APIC.\r
+\r
+ @return The base address of local APIC\r
+\r
+**/\r
+STATIC\r
UINTN\r
-EFIAPI\r
-DelayWorker (\r
- IN UINT64 NDelay\r
+InternalX86GetApicBase (\r
+ VOID\r
)\r
{\r
- UINT64 Ticks;\r
-\r
- Ticks = GetPerformanceCounter ();\r
- Ticks -= DivU64x32 (\r
- MultU64x64 (\r
- GetPerformanceCounterProperties (NULL, NULL),\r
- NDelay\r
- ),\r
- 1000000000u\r
- );\r
- while (Ticks <= GetPerformanceCounter ());\r
- return (UINTN)Ticks;\r
+ return (UINTN)AsmMsrBitFieldRead64 (27, 12, 35) << 12;\r
+}\r
+\r
+/**\r
+ Internal function to return the frequency of the local APIC timer.\r
+\r
+ Internal function to return the frequency of the local APIC timer.\r
+\r
+ @param ApicBase The base address of memory mapped registers of local APIC.\r
+\r
+ @return The frequency of the timer in Hz.\r
+\r
+**/\r
+STATIC\r
+UINT32\r
+InternalX86GetTimerFrequency (\r
+ IN UINTN ApicBase\r
+ )\r
+{\r
+ return\r
+ mTimerLibLocalApicFrequencies[AsmMsrBitFieldRead32 (44, 16, 18)] /\r
+ mTimerLibLocalApicDivisor[MmioBitFieldRead32 (ApicBase + 0x3e0, 0, 3)];\r
+}\r
+\r
+/**\r
+ Internal function to read the current tick counter of local APIC.\r
+\r
+ Internal function to read the current tick counter of local APIC.\r
+\r
+ @param ApicBase The base address of memory mapped registers of local APIC.\r
+\r
+ @return The tick counter read.\r
+\r
+**/\r
+STATIC\r
+INT32\r
+InternalX86GetTimerTick (\r
+ IN UINTN ApicBase\r
+ )\r
+{\r
+ return MmioRead32 (ApicBase + 0x390);\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 ApicBase The base address of memory mapped registers of local APIC.\r
+ @param Delay A period of time to delay in ticks.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+InternalX86Delay (\r
+ IN UINTN ApicBase,\r
+ IN UINT32 Delay\r
+ )\r
+{\r
+ INT32 Ticks;\r
+\r
+ //\r
+ // The target timer count is calculated here\r
+ //\r
+ Ticks = InternalX86GetTimerTick (ApicBase) - Delay;\r
+\r
+ //\r
+ // Wait until time out\r
+ // Delay > 2^31 could not be handled by this function\r
+ // Timer wrap-arounds are handled correctly by this function\r
+ //\r
+ while (InternalX86GetTimerTick (ApicBase) - Ticks >= 0);\r
}\r
\r
/**\r
\r
@param MicroSeconds The minimum number of microseconds to delay.\r
\r
- @return Return value depends on implementation.\r
+ @return MicroSeconds\r
\r
**/\r
UINTN\r
IN UINTN MicroSeconds\r
)\r
{\r
- return DelayWorker (MicroSeconds * 1000ull);\r
+ UINTN ApicBase;\r
+\r
+ ApicBase = InternalX86GetApicBase ();\r
+ InternalX86Delay (\r
+ ApicBase,\r
+ (UINT32)DivU64x32 (\r
+ MultU64x64 (\r
+ InternalX86GetTimerFrequency (ApicBase),\r
+ MicroSeconds\r
+ ),\r
+ 1000000u\r
+ )\r
+ );\r
+ return MicroSeconds;\r
}\r
\r
/**\r
\r
@param NanoSeconds The minimum number of nanoseconds to delay.\r
\r
- @return Return value depends on implementation.\r
+ @return NanoSeconds\r
\r
**/\r
UINTN\r
IN UINTN NanoSeconds\r
)\r
{\r
- return DelayWorker (NanoSeconds);\r
-}\r
+ UINTN ApicBase;\r
\r
-static\r
-UINTN\r
-EFIAPI\r
-GetApicBase (\r
- VOID\r
- )\r
-{\r
- return (UINTN)AsmMsrBitFieldRead64 (27, 12, 35) << 12;\r
+ ApicBase = InternalX86GetApicBase ();\r
+ InternalX86Delay (\r
+ ApicBase,\r
+ (UINT32)DivU64x32 (\r
+ MultU64x64 (\r
+ InternalX86GetTimerFrequency (ApicBase),\r
+ NanoSeconds\r
+ ),\r
+ 1000000000u\r
+ )\r
+ );\r
+ return NanoSeconds;\r
}\r
\r
/**\r
VOID\r
)\r
{\r
- return MmioRead32 (GetApicBase () + 0x390);\r
+ return InternalX86GetTimerTick (InternalX86GetApicBase ());\r
}\r
\r
/**\r
IN UINT64 *EndValue\r
)\r
{\r
- static const UINT32 mFrequencies[] = {\r
- 100000000,\r
- 133000000,\r
- 200000000,\r
- 166000000\r
- };\r
- static const UINT8 mDivisor[] = {\r
- 0x02, 0x04, 0x08, 0x10,\r
- 0x02, 0x04, 0x08, 0x10,\r
- 0x20, 0x40, 0x80, 0x01,\r
- 0x20, 0x40, 0x80, 0x01\r
- };\r
-\r
UINTN ApicBase;\r
\r
- ApicBase = GetApicBase ();\r
+ ApicBase = InternalX86GetApicBase ();\r
\r
if (StartValue != NULL) {\r
*StartValue = MmioRead32 (ApicBase + 0x380);\r
*EndValue = 0;\r
}\r
\r
- return mFrequencies[AsmMsrBitFieldRead32 (44, 16, 18)] /\r
- mDivisor[MmioBitFieldRead32 (ApicBase + 0x3e0, 0, 3)];\r
+ return InternalX86GetTimerFrequency (ApicBase);\r
}\r