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