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