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