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