X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=MdePkg%2FLibrary%2FBaseTimerLibLocalApic%2Fx86TimerLib.c;h=e3af546367e10a4b68e53d621c0d2e71723f04d6;hp=9c69cdfb92f27dfcebd64535e3875a2cbb8687d6;hb=ed384ef31cff0681d724847c684476aed214917c;hpb=26015d229452d2916521506cad5cd3647474cf8d diff --git a/MdePkg/Library/BaseTimerLibLocalApic/x86TimerLib.c b/MdePkg/Library/BaseTimerLibLocalApic/x86TimerLib.c index 9c69cdfb92..e3af546367 100644 --- a/MdePkg/Library/BaseTimerLibLocalApic/x86TimerLib.c +++ b/MdePkg/Library/BaseTimerLibLocalApic/x86TimerLib.c @@ -18,25 +18,116 @@ **/ -static +// +// The following 2 arrays are used in calculating the frequency of local APIC +// timer. Refer to IA-32 developers' manual for more details. +// + +GLOBAL_REMOVE_IF_UNREFERENCED +CONST UINT32 mTimerLibLocalApicFrequencies[] = { + 100000000, + 133000000, + 200000000, + 166000000 +}; + +GLOBAL_REMOVE_IF_UNREFERENCED +CONST UINT8 mTimerLibLocalApicDivisor[] = { + 0x02, 0x04, 0x08, 0x10, + 0x02, 0x04, 0x08, 0x10, + 0x20, 0x40, 0x80, 0x01, + 0x20, 0x40, 0x80, 0x01 +}; + +/** + Internal function to retrieve the base address of local APIC. + + Internal function to retrieve the base address of local APIC. + + @return The base address of local APIC + +**/ +STATIC UINTN -EFIAPI -DelayWorker ( - IN UINT64 NDelay +InternalX86GetApicBase ( + VOID + ) +{ + return (UINTN)AsmMsrBitFieldRead64 (27, 12, 35) << 12; +} + +/** + Internal function to return the frequency of the local APIC timer. + + Internal function to return the frequency of the local APIC timer. + + @param ApicBase The base address of memory mapped registers of local APIC. + + @return The frequency of the timer in Hz. + +**/ +STATIC +UINT32 +InternalX86GetTimerFrequency ( + IN UINTN ApicBase + ) +{ + return + mTimerLibLocalApicFrequencies[AsmMsrBitFieldRead32 (44, 16, 18)] / + mTimerLibLocalApicDivisor[MmioBitFieldRead32 (ApicBase + 0x3e0, 0, 3)]; +} + +/** + Internal function to read the current tick counter of local APIC. + + Internal function to read the current tick counter of local APIC. + + @param ApicBase The base address of memory mapped registers of local APIC. + + @return The tick counter read. + +**/ +STATIC +INT32 +InternalX86GetTimerTick ( + IN UINTN ApicBase ) { - UINT64 Ticks; - - Ticks = GetPerformanceCounter (); - Ticks -= DivU64x32 ( - MultU64x64 ( - GetPerformanceCounterProperties (NULL, NULL), - NDelay - ), - 1000000000u - ); - while (Ticks <= GetPerformanceCounter ()); - return (UINTN)Ticks; + return MmioRead32 (ApicBase + 0x390); +} + +/** + 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 ApicBase The base address of memory mapped registers of local APIC. + @param Delay A period of time to delay in ticks. + +**/ +STATIC +VOID +InternalX86Delay ( + IN UINTN ApicBase, + IN UINT32 Delay + ) +{ + INT32 Ticks; + + ApicBase = InternalX86GetApicBase (); + + // + // The target timer count is calculated here + // + Ticks = InternalX86GetTimerTick (ApicBase) - Delay; + + // + // Wait until time out + // Delay > 2^31 could not be handled by this function + // Timer wrap-arounds are handled correctly by this function + // + while (InternalX86GetTimerTick (ApicBase) - Ticks >= 0); } /** @@ -46,7 +137,7 @@ DelayWorker ( @param MicroSeconds The minimum number of microseconds to delay. - @return Return value depends on implementation. + @return MicroSeconds **/ UINTN @@ -55,7 +146,20 @@ MicroSecondDelay ( IN UINTN MicroSeconds ) { - return DelayWorker (MicroSeconds * 1000ull); + UINTN ApicBase; + + ApicBase = InternalX86GetApicBase (); + InternalX86Delay ( + ApicBase, + (UINT32)DivU64x32 ( + MultU64x64 ( + InternalX86GetTimerFrequency (ApicBase), + MicroSeconds + ), + 1000000u + ) + ); + return MicroSeconds; } /** @@ -65,7 +169,7 @@ MicroSecondDelay ( @param NanoSeconds The minimum number of nanoseconds to delay. - @return Return value depends on implementation. + @return NanoSeconds **/ UINTN @@ -74,17 +178,20 @@ NanoSecondDelay ( IN UINTN NanoSeconds ) { - return DelayWorker (NanoSeconds); -} + UINTN ApicBase; -static -UINTN -EFIAPI -GetApicBase ( - VOID - ) -{ - return (UINTN)AsmMsrBitFieldRead64 (27, 12, 35) << 12; + ApicBase = InternalX86GetApicBase (); + InternalX86Delay ( + ApicBase, + (UINT32)DivU64x32 ( + MultU64x64 ( + InternalX86GetTimerFrequency (ApicBase), + NanoSeconds + ), + 1000000000u + ) + ); + return NanoSeconds; } /** @@ -105,7 +212,7 @@ GetPerformanceCounter ( VOID ) { - return MmioRead32 (GetApicBase () + 0x390); + return InternalX86GetTimerTick (InternalX86GetApicBase ()); } /** @@ -138,22 +245,9 @@ GetPerformanceCounterProperties ( IN UINT64 *EndValue ) { - static const UINT32 mFrequencies[] = { - 100000000, - 133000000, - 200000000, - 166000000 - }; - static const UINT8 mDivisor[] = { - 0x02, 0x04, 0x08, 0x10, - 0x02, 0x04, 0x08, 0x10, - 0x20, 0x40, 0x80, 0x01, - 0x20, 0x40, 0x80, 0x01 - }; - UINTN ApicBase; - ApicBase = GetApicBase (); + ApicBase = InternalX86GetApicBase (); if (StartValue != NULL) { *StartValue = MmioRead32 (ApicBase + 0x380); @@ -163,6 +257,5 @@ GetPerformanceCounterProperties ( *EndValue = 0; } - return mFrequencies[AsmMsrBitFieldRead32 (44, 16, 18)] / - mDivisor[MmioBitFieldRead32 (ApicBase + 0x3e0, 0, 3)]; + return InternalX86GetTimerFrequency (ApicBase); }