1 /** @file
2   Timer Library functions built upon local APIC on IA32/x64.
3 
4   Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
5   SPDX-License-Identifier: BSD-2-Clause-Patent
6 
7 **/
8 
9 #include <Base.h>
10 #include <Library/TimerLib.h>
11 #include <Library/BaseLib.h>
12 #include <Library/IoLib.h>
13 #include <Library/PcdLib.h>
14 #include <Library/DebugLib.h>
15 
16 #define APIC_SVR        0x0f0
17 #define APIC_LVTERR     0x370
18 #define APIC_TMICT      0x380
19 #define APIC_TMCCT      0x390
20 #define APIC_TDCR       0x3e0
21 
22 //
23 // The following array is used in calculating the frequency of local APIC
24 // timer. Refer to IA-32 developers' manual for more details.
25 //
26 GLOBAL_REMOVE_IF_UNREFERENCED
27 CONST UINT8                           mTimerLibLocalApicDivisor[] = {
28   0x02, 0x04, 0x08, 0x10,
29   0x02, 0x04, 0x08, 0x10,
30   0x20, 0x40, 0x80, 0x01,
31   0x20, 0x40, 0x80, 0x01
32 };
33 
34 /**
35   Internal function to retrieve the base address of local APIC.
36 
37   This function will ASSERT if:
38   The local APIC is not globally enabled.
39   The local APIC is not working under XAPIC mode.
40   The local APIC is not software enabled.
41 
42   @return The base address of local APIC
43 
44 **/
45 UINTN
46 EFIAPI
InternalX86GetApicBase(VOID)47 InternalX86GetApicBase (
48   VOID
49   )
50 {
51   UINTN                             MsrValue;
52   UINTN                             ApicBase;
53 
54   MsrValue = (UINTN) AsmReadMsr64 (27);
55   ApicBase = MsrValue & 0xffffff000ULL;
56 
57   //
58   // Check the APIC Global Enable bit (bit 11) in IA32_APIC_BASE MSR.
59   // This bit will be 1, if local APIC is globally enabled.
60   //
61   ASSERT ((MsrValue & BIT11) != 0);
62 
63   //
64   // Check the APIC Extended Mode bit (bit 10) in IA32_APIC_BASE MSR.
65   // This bit will be 0, if local APIC is under XAPIC mode.
66   //
67   ASSERT ((MsrValue & BIT10) == 0);
68 
69   //
70   // Check the APIC Software Enable/Disable bit (bit 8) in Spurious-Interrupt
71   // Vector Register.
72   // This bit will be 1, if local APIC is software enabled.
73   //
74   ASSERT ((MmioRead32 (ApicBase + APIC_SVR) & BIT8) != 0);
75 
76   return ApicBase;
77 }
78 
79 /**
80   Internal function to return the frequency of the local APIC timer.
81 
82   @param  ApicBase  The base address of memory mapped registers of local APIC.
83 
84   @return The frequency of the timer in Hz.
85 
86 **/
87 UINT32
88 EFIAPI
InternalX86GetTimerFrequency(IN UINTN ApicBase)89 InternalX86GetTimerFrequency (
90   IN      UINTN                     ApicBase
91   )
92 {
93   return
94     PcdGet32(PcdFSBClock) /
95     mTimerLibLocalApicDivisor[MmioBitFieldRead32 (ApicBase + APIC_TDCR, 0, 3)];
96 }
97 
98 /**
99   Internal function to read the current tick counter of local APIC.
100 
101   @param  ApicBase  The base address of memory mapped registers of local APIC.
102 
103   @return The tick counter read.
104 
105 **/
106 INT32
107 EFIAPI
InternalX86GetTimerTick(IN UINTN ApicBase)108 InternalX86GetTimerTick (
109   IN      UINTN                     ApicBase
110   )
111 {
112   return MmioRead32 (ApicBase + APIC_TMCCT);
113 }
114 
115 /**
116   Internal function to read the initial timer count of local APIC.
117 
118   @param  ApicBase  The base address of memory mapped registers of local APIC.
119 
120   @return The initial timer count read.
121 
122 **/
123 UINT32
InternalX86GetInitTimerCount(IN UINTN ApicBase)124 InternalX86GetInitTimerCount (
125   IN      UINTN                     ApicBase
126   )
127 {
128   return MmioRead32 (ApicBase + APIC_TMICT);
129 }
130 
131 /**
132   Stalls the CPU for at least the given number of ticks.
133 
134   Stalls the CPU for at least the given number of ticks. It's invoked by
135   MicroSecondDelay() and NanoSecondDelay().
136 
137   This function will ASSERT if the APIC timer intial count returned from
138   InternalX86GetInitTimerCount() is zero.
139 
140   @param  ApicBase  The base address of memory mapped registers of local APIC.
141   @param  Delay     A period of time to delay in ticks.
142 
143 **/
144 VOID
145 EFIAPI
InternalX86Delay(IN UINTN ApicBase,IN UINT32 Delay)146 InternalX86Delay (
147   IN      UINTN                     ApicBase,
148   IN      UINT32                    Delay
149   )
150 {
151   INT32                             Ticks;
152   UINT32                            Times;
153   UINT32                            InitCount;
154   UINT32                            StartTick;
155 
156   //
157   // In case Delay is too larger, separate it into several small delay slot.
158   // Devided Delay by half value of Init Count is to avoid Delay close to
159   // the Init Count, timeout maybe missing if the time consuming between 2
160   // GetApicTimerCurrentCount() invoking is larger than the time gap between
161   // Delay and the Init Count.
162   //
163   InitCount = InternalX86GetInitTimerCount (ApicBase);
164   ASSERT (InitCount != 0);
165   Times     = Delay / (InitCount / 2);
166   Delay     = Delay % (InitCount / 2);
167 
168   //
169   // Get Start Tick and do delay
170   //
171   StartTick  = InternalX86GetTimerTick (ApicBase);
172   do {
173     //
174     // Wait until time out by Delay value
175     //
176     do {
177       CpuPause ();
178       //
179       // Get Ticks from Start to Current.
180       //
181       Ticks = StartTick - InternalX86GetTimerTick (ApicBase);
182       //
183       // Ticks < 0 means Timer wrap-arounds happens.
184       //
185       if (Ticks < 0) {
186         Ticks += InitCount;
187       }
188     } while ((UINT32)Ticks < Delay);
189 
190     //
191     // Update StartTick and Delay for next delay slot
192     //
193     StartTick -= (StartTick > Delay) ?  Delay : (Delay - InitCount);
194     Delay      = InitCount / 2;
195   } while (Times-- > 0);
196 }
197 
198 /**
199   Stalls the CPU for at least the given number of microseconds.
200 
201   Stalls the CPU for the number of microseconds specified by MicroSeconds.
202 
203   @param  MicroSeconds  The minimum number of microseconds to delay.
204 
205   @return The value of MicroSeconds inputted.
206 
207 **/
208 UINTN
209 EFIAPI
MicroSecondDelay(IN UINTN MicroSeconds)210 MicroSecondDelay (
211   IN      UINTN                     MicroSeconds
212   )
213 {
214   UINTN                             ApicBase;
215 
216   ApicBase = InternalX86GetApicBase ();
217   InternalX86Delay (
218     ApicBase,
219     (UINT32)DivU64x32 (
220               MultU64x64 (
221                 InternalX86GetTimerFrequency (ApicBase),
222                 MicroSeconds
223                 ),
224               1000000u
225               )
226     );
227   return MicroSeconds;
228 }
229 
230 /**
231   Stalls the CPU for at least the given number of nanoseconds.
232 
233   Stalls the CPU for the number of nanoseconds specified by NanoSeconds.
234 
235   @param  NanoSeconds The minimum number of nanoseconds to delay.
236 
237   @return The value of NanoSeconds inputted.
238 
239 **/
240 UINTN
241 EFIAPI
NanoSecondDelay(IN UINTN NanoSeconds)242 NanoSecondDelay (
243   IN      UINTN                     NanoSeconds
244   )
245 {
246   UINTN                             ApicBase;
247 
248   ApicBase = InternalX86GetApicBase ();
249   InternalX86Delay (
250     ApicBase,
251     (UINT32)DivU64x32 (
252               MultU64x64 (
253                 InternalX86GetTimerFrequency (ApicBase),
254                 NanoSeconds
255                 ),
256               1000000000u
257               )
258     );
259   return NanoSeconds;
260 }
261 
262 /**
263   Retrieves the current value of a 64-bit free running performance counter.
264 
265   The counter can either count up by 1 or count down by 1. If the physical
266   performance counter counts by a larger increment, then the counter values
267   must be translated. The properties of the counter can be retrieved from
268   GetPerformanceCounterProperties().
269 
270   @return The current value of the free running performance counter.
271 
272 **/
273 UINT64
274 EFIAPI
GetPerformanceCounter(VOID)275 GetPerformanceCounter (
276   VOID
277   )
278 {
279   return (UINT64)(UINT32)InternalX86GetTimerTick (InternalX86GetApicBase ());
280 }
281 
282 /**
283   Retrieves the 64-bit frequency in Hz and the range of performance counter
284   values.
285 
286   If StartValue is not NULL, then the value that the performance counter starts
287   with immediately after is it rolls over is returned in StartValue. If
288   EndValue is not NULL, then the value that the performance counter end with
289   immediately before it rolls over is returned in EndValue. The 64-bit
290   frequency of the performance counter in Hz is always returned. If StartValue
291   is less than EndValue, then the performance counter counts up. If StartValue
292   is greater than EndValue, then the performance counter counts down. For
293   example, a 64-bit free running counter that counts up would have a StartValue
294   of 0 and an EndValue of 0xFFFFFFFFFFFFFFFF. A 24-bit free running counter
295   that counts down would have a StartValue of 0xFFFFFF and an EndValue of 0.
296 
297   @param  StartValue  The value the performance counter starts with when it
298                       rolls over.
299   @param  EndValue    The value that the performance counter ends with before
300                       it rolls over.
301 
302   @return The frequency in Hz.
303 
304 **/
305 UINT64
306 EFIAPI
GetPerformanceCounterProperties(OUT UINT64 * StartValue,OPTIONAL OUT UINT64 * EndValue OPTIONAL)307 GetPerformanceCounterProperties (
308   OUT      UINT64                    *StartValue,  OPTIONAL
309   OUT      UINT64                    *EndValue     OPTIONAL
310   )
311 {
312   UINTN                             ApicBase;
313 
314   ApicBase = InternalX86GetApicBase ();
315 
316   if (StartValue != NULL) {
317     *StartValue = (UINT64)InternalX86GetInitTimerCount (ApicBase);
318   }
319 
320   if (EndValue != NULL) {
321     *EndValue = 0;
322   }
323 
324   return (UINT64) InternalX86GetTimerFrequency (ApicBase);
325 }
326 
327 /**
328   Converts elapsed ticks of performance counter to time in nanoseconds.
329 
330   This function converts the elapsed ticks of running performance counter to
331   time value in unit of nanoseconds.
332 
333   @param  Ticks     The number of elapsed ticks of running performance counter.
334 
335   @return The elapsed time in nanoseconds.
336 
337 **/
338 UINT64
339 EFIAPI
GetTimeInNanoSecond(IN UINT64 Ticks)340 GetTimeInNanoSecond (
341   IN      UINT64                     Ticks
342   )
343 {
344   UINT64  Frequency;
345   UINT64  NanoSeconds;
346   UINT64  Remainder;
347   INTN    Shift;
348 
349   Frequency = GetPerformanceCounterProperties (NULL, NULL);
350 
351   //
352   //          Ticks
353   // Time = --------- x 1,000,000,000
354   //        Frequency
355   //
356   NanoSeconds = MultU64x32 (DivU64x64Remainder (Ticks, Frequency, &Remainder), 1000000000u);
357 
358   //
359   // Ensure (Remainder * 1,000,000,000) will not overflow 64-bit.
360   // Since 2^29 < 1,000,000,000 = 0x3B9ACA00 < 2^30, Remainder should < 2^(64-30) = 2^34,
361   // i.e. highest bit set in Remainder should <= 33.
362   //
363   Shift = MAX (0, HighBitSet64 (Remainder) - 33);
364   Remainder = RShiftU64 (Remainder, (UINTN) Shift);
365   Frequency = RShiftU64 (Frequency, (UINTN) Shift);
366   NanoSeconds += DivU64x64Remainder (MultU64x32 (Remainder, 1000000000u), Frequency, NULL);
367 
368   return NanoSeconds;
369 }
370