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