Home | History | Annotate | Download | only in SecPeiDxeTimerLibCpu
      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