From ed384ef31cff0681d724847c684476aed214917c Mon Sep 17 00:00:00 2001 From: bxing Date: Tue, 25 Jul 2006 07:33:02 +0000 Subject: [PATCH] 1. Updated declaration of timer functions according to latest MWG. 2. Updated coding style. 3. Updated the algorithm used in delay functions to handle timer counter wrap-around. git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@1089 6f19259b-4bc3-4df7-8a09-765794883524 --- MdePkg/Include/Library/TimerLib.h | 4 +- .../BaseTimerLibLocalApic/Ipf/IpfTimerLib.c | 106 +++++++--- .../BaseTimerLibLocalApic/Ipf/ReadItc.s | 11 +- .../BaseTimerLibLocalApic/x86TimerLib.c | 183 +++++++++++++----- 4 files changed, 228 insertions(+), 76 deletions(-) diff --git a/MdePkg/Include/Library/TimerLib.h b/MdePkg/Include/Library/TimerLib.h index 4b12152e6b..8523bd0dfb 100644 --- a/MdePkg/Include/Library/TimerLib.h +++ b/MdePkg/Include/Library/TimerLib.h @@ -24,7 +24,7 @@ @param MicroSeconds The minimum number of microseconds to delay. - @return Return value depends on implementation. + @return MicroSeconds **/ UINTN @@ -40,7 +40,7 @@ MicroSecondDelay ( @param NanoSeconds The minimum number of nanoseconds to delay. - @return Return value depends on implementation. + @return NanoSeconds **/ UINTN diff --git a/MdePkg/Library/BaseTimerLibLocalApic/Ipf/IpfTimerLib.c b/MdePkg/Library/BaseTimerLibLocalApic/Ipf/IpfTimerLib.c index 3814534607..800b5258e3 100644 --- a/MdePkg/Library/BaseTimerLibLocalApic/Ipf/IpfTimerLib.c +++ b/MdePkg/Library/BaseTimerLibLocalApic/Ipf/IpfTimerLib.c @@ -18,11 +18,6 @@ **/ -UINT64 -ReadItc ( - VOID - ); - typedef struct { UINT64 Status; UINT64 r9; @@ -30,6 +25,21 @@ typedef struct { UINT64 r11; } PAL_PROC_RETURN; +/** + Performs a PAL call using static calling convention. + + An internal function to perform a PAL call using static calling convention. + + @param PalEntryPoint The entry point address of PAL. The address in ar.kr5 + would be used if this parameter were NULL on input. + @param Arg1 The first argument of a PAL call. + @param Arg1 The second argument of a PAL call. + @param Arg1 The third argument of a PAL call. + @param Arg1 The fourth argument of a PAL call. + + @return The values returned in r8, r9, r10 and r11. + +**/ PAL_PROC_RETURN PalCallStatic ( IN CONST VOID *PalEntryPoint, @@ -39,6 +49,50 @@ PalCallStatic ( IN UINT64 Arg4 ); +/** + Returns the current value of ar.itc. + + An internal function to return the current value of ar.itc, which is the + timer tick on IPF. + + @return The currect value of ar.itc + +**/ +INT64 +InternalIpfReadItc ( + VOID + ); + +/** + Performs a delay measured as number of ticks. + + An internal function to perform a delay measured as number of ticks. It's + invoked by MicroSecondDelay() and NanoSecondDelay(). + + @param Delay Number of ticks to delay. + +**/ +STATIC +VOID +InternalIpfDelay ( + IN INT64 Delay + ) +{ + INT64 Ticks; + + // + // The target timer count is calculated here + // + Ticks = InternalIpfReadItc () + Delay; + + // + // Wait until time out + // Delay > 2^63 could not be handled by this function + // Timer wrap-arounds are handled correctly by this function + // + while (Ticks - InternalIpfReadItc () >= 0); +} + /** Stalls the CPU for at least the given number of microseconds. @@ -46,7 +100,7 @@ PalCallStatic ( @param MicroSeconds The minimum number of microseconds to delay. - @return The ticks delayed actually. + @return MicroSeconds **/ UINTN @@ -55,13 +109,12 @@ MicroSecondDelay ( IN UINTN MicroSeconds ) { - UINT64 Ticks; - UINT64 Delay; - - Ticks = GetPerformanceCounter (); - Delay = GetPerformanceCounterProperties (NULL, NULL) * MicroSeconds / 1000000; - while (Ticks + Delay >= GetPerformanceCounter ()); - return (UINTN)Delay; + InternalIpfDelay ( + GetPerformanceCounterProperties (NULL, NULL) * + MicroSeconds / + 1000000 + ); + return MicroSeconds; } /** @@ -71,7 +124,7 @@ MicroSecondDelay ( @param NanoSeconds The minimum number of nanoseconds to delay. - @return The ticks delayed actually. + @return NanoSeconds **/ UINTN @@ -80,13 +133,12 @@ NanoSecondDelay ( IN UINTN NanoSeconds ) { - UINT64 Ticks; - UINT64 Delay; - - Ticks = GetPerformanceCounter (); - Delay = GetPerformanceCounterProperties (NULL, NULL) * NanoSeconds / 1000000000; - while (Ticks + Delay >= GetPerformanceCounter ()); - return (UINTN)Delay; + InternalIpfDelay ( + GetPerformanceCounterProperties (NULL, NULL) * + NanoSeconds / + 1000000000 + ); + return NanoSeconds; } /** @@ -107,7 +159,7 @@ GetPerformanceCounter ( VOID ) { - return ReadItc (); + return InternalIpfReadItc (); } /** @@ -150,7 +202,13 @@ GetPerformanceCounterProperties ( PalRet = PalCallStatic (NULL, 14, 0, 0, 0); ASSERT (PalRet.Status == 0); - *StartValue = 0; - *EndValue = (UINT64)(-1); + if (StartValue != NULL) { + *StartValue = 0; + } + + if (EndValue != NULL) { + *EndValue = (UINT64)(-1); + } + return BaseFrequence * (PalRet.r11 >> 32) / (UINT32)PalRet.r11; } diff --git a/MdePkg/Library/BaseTimerLibLocalApic/Ipf/ReadItc.s b/MdePkg/Library/BaseTimerLibLocalApic/Ipf/ReadItc.s index 383bb242ba..ea94b670e7 100644 --- a/MdePkg/Library/BaseTimerLibLocalApic/Ipf/ReadItc.s +++ b/MdePkg/Library/BaseTimerLibLocalApic/Ipf/ReadItc.s @@ -1,5 +1,6 @@ /// @file -/// Contains an implementation of ReadItc on Itanium-based architecture. +/// Contains an implementation of InternalIpfReadItc () on Itanium-based +/// architecture. /// /// Copyright (c) 2006, Intel Corporation /// All rights reserved. This program and the accompanying materials @@ -17,9 +18,9 @@ .auto .text -.proc ReadItc -.type ReadItc, @function -ReadItc:: +.proc InternalIpfReadItc +.type InternalIpfReadItc, @function +InternalIpfReadItc:: mov r8 = ar.itc br.ret.sptk.many b0 -.endp ReadItc \ No newline at end of file +.endp InternalIpfReadItc 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 ) { - UINT64 Ticks; + return (UINTN)AsmMsrBitFieldRead64 (27, 12, 35) << 12; +} - Ticks = GetPerformanceCounter (); - Ticks -= DivU64x32 ( - MultU64x64 ( - GetPerformanceCounterProperties (NULL, NULL), - NDelay - ), - 1000000000u - ); - while (Ticks <= GetPerformanceCounter ()); - return (UINTN)Ticks; +/** + 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 + ) +{ + 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); }