diff options
-rw-r--r-- | MdePkg/Include/Library/TimerLib.h | 4 | ||||
-rw-r--r-- | MdePkg/Library/BaseTimerLibLocalApic/Ipf/IpfTimerLib.c | 106 | ||||
-rw-r--r-- | MdePkg/Library/BaseTimerLibLocalApic/Ipf/ReadItc.s | 11 | ||||
-rw-r--r-- | MdePkg/Library/BaseTimerLibLocalApic/x86TimerLib.c | 185 |
4 files changed, 229 insertions, 77 deletions
diff --git a/MdePkg/Include/Library/TimerLib.h b/MdePkg/Include/Library/TimerLib.h index 4b12152..8523bd0 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 3814534..800b525 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,
@@ -40,13 +50,57 @@ PalCallStatic ( );
/**
+ 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.
Stalls the CPU for the number of microseconds specified by MicroSeconds.
@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 383bb24..ea94b67 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 9c69cdf..e3af546 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);
}
|