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