]> git.proxmox.com Git - mirror_edk2.git/blame - DuetPkg/Library/DuetTimerLib/X86TimerLib.c
INF extension reviewed
[mirror_edk2.git] / DuetPkg / Library / DuetTimerLib / X86TimerLib.c
CommitLineData
f5752cb2 1/** @file\r
2 Timer Library functions built upon local APIC on IA32/x64.\r
3\r
4 Copyright (c) 2006 - 2007, Intel Corporation<BR>\r
5 All rights reserved. This program and the accompanying materials\r
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
8 http://opensource.org/licenses/bsd-license.php\r
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
13**/\r
14\r
15#include <Base.h>\r
16#include <Library/TimerLib.h>\r
17#include <Library/BaseLib.h>\r
18#include <Library/IoLib.h>\r
19#include <Library/DebugLib.h>\r
20#include <Library/PcdLib.h>\r
21\r
22\r
23//\r
24// The following array is used in calculating the frequency of local APIC\r
25// timer. Refer to IA-32 developers' manual for more details.\r
26//\r
27GLOBAL_REMOVE_IF_UNREFERENCED\r
28CONST UINT8 mTimerLibLocalApicDivisor[] = {\r
29 0x02, 0x04, 0x08, 0x10,\r
30 0x02, 0x04, 0x08, 0x10,\r
31 0x20, 0x40, 0x80, 0x01,\r
32 0x20, 0x40, 0x80, 0x01\r
33};\r
34\r
35/**\r
36 Internal function to retrieve the base address of local APIC.\r
37\r
38 Internal function to retrieve the base address of local APIC.\r
39\r
40 @return The base address of local APIC\r
41\r
42**/\r
f5752cb2 43UINTN\r
44InternalX86GetApicBase (\r
45 VOID\r
46 )\r
47{\r
48 return (UINTN)AsmMsrBitFieldRead64 (27, 12, 35) << 12;\r
49}\r
50\r
51/**\r
52 Internal function to return the frequency of the local APIC timer.\r
53\r
54 Internal function to return the frequency of the local APIC timer.\r
55\r
56 @param ApicBase The base address of memory mapped registers of local APIC.\r
57\r
58 @return The frequency of the timer in Hz.\r
59\r
60**/\r
f5752cb2 61UINT32\r
62InternalX86GetTimerFrequency (\r
63 IN UINTN ApicBase\r
64 )\r
65{\r
66 return\r
67 PcdGet32(PcdFSBClock) /\r
68 mTimerLibLocalApicDivisor[MmioBitFieldRead32 (ApicBase + 0x3e0, 0, 3)];\r
69}\r
70\r
71/**\r
72 Internal function to read the current tick counter of local APIC.\r
73\r
74 Internal function to read the current tick counter of local APIC.\r
75\r
76 @param ApicBase The base address of memory mapped registers of local APIC.\r
77\r
78 @return The tick counter read.\r
79\r
80**/\r
f5752cb2 81INT32\r
82InternalX86GetTimerTick (\r
83 IN UINTN ApicBase\r
84 )\r
85{\r
86 return MmioRead32 (ApicBase + 0x390);\r
87}\r
88\r
89/**\r
90 Stalls the CPU for at least the given number of ticks.\r
91\r
92 Stalls the CPU for at least the given number of ticks. It's invoked by\r
93 MicroSecondDelay() and NanoSecondDelay().\r
94\r
95 @param ApicBase The base address of memory mapped registers of local APIC.\r
96 @param Delay A period of time to delay in ticks.\r
97\r
98**/\r
f5752cb2 99VOID\r
100InternalX86Delay (\r
101 IN UINTN ApicBase,\r
102 IN UINT32 Delay\r
103 )\r
104{\r
105 INT32 Ticks;\r
106\r
107 //\r
108 // The target timer count is calculated here\r
109 //\r
110 Ticks = InternalX86GetTimerTick (ApicBase) - Delay;\r
111\r
112 //\r
113 // Wait until time out\r
114 // Delay > 2^31 could not be handled by this function\r
115 // Timer wrap-arounds are handled correctly by this function\r
116 //\r
117 while (InternalX86GetTimerTick (ApicBase) - Ticks >= 0);\r
118}\r
119\r
120/**\r
121 Stalls the CPU for at least the given number of microseconds.\r
122\r
123 Stalls the CPU for the number of microseconds specified by MicroSeconds.\r
124\r
125 @param MicroSeconds The minimum number of microseconds to delay.\r
126\r
127 @return MicroSeconds\r
128\r
129**/\r
130UINTN\r
131EFIAPI\r
132MicroSecondDelay (\r
133 IN UINTN MicroSeconds\r
134 )\r
135{\r
136 UINTN ApicBase;\r
137\r
138 ApicBase = InternalX86GetApicBase ();\r
139 InternalX86Delay (\r
140 ApicBase,\r
141 (UINT32)DivU64x32 (\r
142 MultU64x64 (\r
143 InternalX86GetTimerFrequency (ApicBase),\r
144 MicroSeconds\r
145 ),\r
146 1000000u\r
147 )\r
148 );\r
149 return MicroSeconds;\r
150}\r
151\r
152/**\r
153 Stalls the CPU for at least the given number of nanoseconds.\r
154\r
155 Stalls the CPU for the number of nanoseconds specified by NanoSeconds.\r
156\r
157 @param NanoSeconds The minimum number of nanoseconds to delay.\r
158\r
159 @return NanoSeconds\r
160\r
161**/\r
162UINTN\r
163EFIAPI\r
164NanoSecondDelay (\r
165 IN UINTN NanoSeconds\r
166 )\r
167{\r
168 UINTN ApicBase;\r
169\r
170 ApicBase = InternalX86GetApicBase ();\r
171 InternalX86Delay (\r
172 ApicBase,\r
173 (UINT32)DivU64x32 (\r
174 MultU64x64 (\r
175 InternalX86GetTimerFrequency (ApicBase),\r
176 NanoSeconds\r
177 ),\r
178 1000000000u\r
179 )\r
180 );\r
181 return NanoSeconds;\r
182}\r
183\r
184/**\r
185 Retrieves the current value of a 64-bit free running performance counter.\r
186\r
187 Retrieves the current value of a 64-bit free running performance counter. The\r
188 counter can either count up by 1 or count down by 1. If the physical\r
189 performance counter counts by a larger increment, then the counter values\r
190 must be translated. The properties of the counter can be retrieved from\r
191 GetPerformanceCounterProperties().\r
192\r
193 @return The current value of the free running performance counter.\r
194\r
195**/\r
196UINT64\r
197EFIAPI\r
198GetPerformanceCounter (\r
199 VOID\r
200 )\r
201{\r
202 return (UINT64)(UINT32)InternalX86GetTimerTick (InternalX86GetApicBase ());\r
203}\r
204\r
205/**\r
206 Retrieves the 64-bit frequency in Hz and the range of performance counter\r
207 values.\r
208\r
209 If StartValue is not NULL, then the value that the performance counter starts\r
210 with immediately after is it rolls over is returned in StartValue. If\r
211 EndValue is not NULL, then the value that the performance counter end with\r
212 immediately before it rolls over is returned in EndValue. The 64-bit\r
213 frequency of the performance counter in Hz is always returned. If StartValue\r
214 is less than EndValue, then the performance counter counts up. If StartValue\r
215 is greater than EndValue, then the performance counter counts down. For\r
216 example, a 64-bit free running counter that counts up would have a StartValue\r
217 of 0 and an EndValue of 0xFFFFFFFFFFFFFFFF. A 24-bit free running counter\r
218 that counts down would have a StartValue of 0xFFFFFF and an EndValue of 0.\r
219\r
220 @param StartValue The value the performance counter starts with when it\r
221 rolls over.\r
222 @param EndValue The value that the performance counter ends with before\r
223 it rolls over.\r
224\r
225 @return The frequency in Hz.\r
226\r
227**/\r
228UINT64\r
229EFIAPI\r
230GetPerformanceCounterProperties (\r
231 OUT UINT64 *StartValue, OPTIONAL\r
232 OUT UINT64 *EndValue OPTIONAL\r
233 )\r
234{\r
235 UINTN ApicBase;\r
236\r
237 ApicBase = InternalX86GetApicBase ();\r
238\r
239 if (StartValue != NULL) {\r
240 *StartValue = MmioRead32 (ApicBase + 0x380);\r
241 }\r
242\r
243 if (EndValue != NULL) {\r
244 *EndValue = 0;\r
245 }\r
246\r
247 return (UINT64) InternalX86GetTimerFrequency (ApicBase);;\r
248}\r