Home | History | Annotate | Download | only in BaseXApicLib
      1 /** @file
      2   Local APIC Library.
      3 
      4   This local APIC library instance supports xAPIC mode only.
      5 
      6   Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved.<BR>
      7   This program and the accompanying materials
      8   are licensed and made available under the terms and conditions of the BSD License
      9   which accompanies this distribution.  The full text of the license may be found at
     10   http://opensource.org/licenses/bsd-license.php
     11 
     12   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     13   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     14 
     15 **/
     16 
     17 #include <Register/Cpuid.h>
     18 #include <Register/Msr.h>
     19 #include <Register/LocalApic.h>
     20 
     21 #include <Library/BaseLib.h>
     22 #include <Library/DebugLib.h>
     23 #include <Library/LocalApicLib.h>
     24 #include <Library/IoLib.h>
     25 #include <Library/TimerLib.h>
     26 #include <Library/PcdLib.h>
     27 
     28 //
     29 // Library internal functions
     30 //
     31 
     32 /**
     33   Determine if the CPU supports the Local APIC Base Address MSR.
     34 
     35   @retval TRUE  The CPU supports the Local APIC Base Address MSR.
     36   @retval FALSE The CPU does not support the Local APIC Base Address MSR.
     37 
     38 **/
     39 BOOLEAN
     40 LocalApicBaseAddressMsrSupported (
     41   VOID
     42   )
     43 {
     44   UINT32  RegEax;
     45   UINTN   FamilyId;
     46 
     47   AsmCpuid (1, &RegEax, NULL, NULL, NULL);
     48   FamilyId = BitFieldRead32 (RegEax, 8, 11);
     49   if (FamilyId == 0x04 || FamilyId == 0x05) {
     50     //
     51     // CPUs with a FamilyId of 0x04 or 0x05 do not support the
     52     // Local APIC Base Address MSR
     53     //
     54     return FALSE;
     55   }
     56   return TRUE;
     57 }
     58 
     59 /**
     60   Retrieve the base address of local APIC.
     61 
     62   @return The base address of local APIC.
     63 
     64 **/
     65 UINTN
     66 EFIAPI
     67 GetLocalApicBaseAddress (
     68   VOID
     69   )
     70 {
     71   MSR_IA32_APIC_BASE_REGISTER  ApicBaseMsr;
     72 
     73   if (!LocalApicBaseAddressMsrSupported ()) {
     74     //
     75     // If CPU does not support Local APIC Base Address MSR, then retrieve
     76     // Local APIC Base Address from PCD
     77     //
     78     return PcdGet32 (PcdCpuLocalApicBaseAddress);
     79   }
     80 
     81   ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
     82 
     83   return (UINTN)(LShiftU64 ((UINT64) ApicBaseMsr.Bits.ApicBaseHi, 32)) +
     84            (((UINTN)ApicBaseMsr.Bits.ApicBase) << 12);
     85 }
     86 
     87 /**
     88   Set the base address of local APIC.
     89 
     90   If BaseAddress is not aligned on a 4KB boundary, then ASSERT().
     91 
     92   @param[in] BaseAddress   Local APIC base address to be set.
     93 
     94 **/
     95 VOID
     96 EFIAPI
     97 SetLocalApicBaseAddress (
     98   IN UINTN                BaseAddress
     99   )
    100 {
    101   MSR_IA32_APIC_BASE_REGISTER  ApicBaseMsr;
    102 
    103   ASSERT ((BaseAddress & (SIZE_4KB - 1)) == 0);
    104 
    105   if (!LocalApicBaseAddressMsrSupported ()) {
    106     //
    107     // Ignore set request if the CPU does not support APIC Base Address MSR
    108     //
    109     return;
    110   }
    111 
    112   ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
    113 
    114   ApicBaseMsr.Bits.ApicBase   = (UINT32) (BaseAddress >> 12);
    115   ApicBaseMsr.Bits.ApicBaseHi = (UINT32) (RShiftU64((UINT64) BaseAddress, 32));
    116 
    117   AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);
    118 }
    119 
    120 /**
    121   Read from a local APIC register.
    122 
    123   This function reads from a local APIC register either in xAPIC or x2APIC mode.
    124   It is required that in xAPIC mode wider registers (64-bit or 256-bit) must be
    125   accessed using multiple 32-bit loads or stores, so this function only performs
    126   32-bit read.
    127 
    128   @param  MmioOffset  The MMIO offset of the local APIC register in xAPIC mode.
    129                       It must be 16-byte aligned.
    130 
    131   @return 32-bit      Value read from the register.
    132 **/
    133 UINT32
    134 EFIAPI
    135 ReadLocalApicReg (
    136   IN UINTN  MmioOffset
    137   )
    138 {
    139   ASSERT ((MmioOffset & 0xf) == 0);
    140   ASSERT (GetApicMode () == LOCAL_APIC_MODE_XAPIC);
    141 
    142   return MmioRead32 (GetLocalApicBaseAddress() + MmioOffset);
    143 }
    144 
    145 /**
    146   Write to a local APIC register.
    147 
    148   This function writes to a local APIC register either in xAPIC or x2APIC mode.
    149   It is required that in xAPIC mode wider registers (64-bit or 256-bit) must be
    150   accessed using multiple 32-bit loads or stores, so this function only performs
    151   32-bit write.
    152 
    153   if the register index is invalid or unsupported in current APIC mode, then ASSERT.
    154 
    155   @param  MmioOffset  The MMIO offset of the local APIC register in xAPIC mode.
    156                       It must be 16-byte aligned.
    157   @param  Value       Value to be written to the register.
    158 **/
    159 VOID
    160 EFIAPI
    161 WriteLocalApicReg (
    162   IN UINTN  MmioOffset,
    163   IN UINT32 Value
    164   )
    165 {
    166   ASSERT ((MmioOffset & 0xf) == 0);
    167   ASSERT (GetApicMode () == LOCAL_APIC_MODE_XAPIC);
    168 
    169   MmioWrite32 (GetLocalApicBaseAddress() + MmioOffset, Value);
    170 }
    171 
    172 /**
    173   Send an IPI by writing to ICR.
    174 
    175   This function returns after the IPI has been accepted by the target processor.
    176 
    177   @param  IcrLow 32-bit value to be written to the low half of ICR.
    178   @param  ApicId APIC ID of the target processor if this IPI is targeted for a specific processor.
    179 **/
    180 VOID
    181 SendIpi (
    182   IN UINT32          IcrLow,
    183   IN UINT32          ApicId
    184   )
    185 {
    186   LOCAL_APIC_ICR_LOW IcrLowReg;
    187   UINT32             IcrHigh;
    188   BOOLEAN            InterruptState;
    189 
    190   ASSERT (GetApicMode () == LOCAL_APIC_MODE_XAPIC);
    191   ASSERT (ApicId <= 0xff);
    192 
    193   InterruptState = SaveAndDisableInterrupts ();
    194 
    195   //
    196   // Save existing contents of ICR high 32 bits
    197   //
    198   IcrHigh = ReadLocalApicReg (XAPIC_ICR_HIGH_OFFSET);
    199 
    200   //
    201   // Wait for DeliveryStatus clear in case a previous IPI
    202   //  is still being sent
    203   //
    204   do {
    205     IcrLowReg.Uint32 = ReadLocalApicReg (XAPIC_ICR_LOW_OFFSET);
    206   } while (IcrLowReg.Bits.DeliveryStatus != 0);
    207 
    208   //
    209   // For xAPIC, the act of writing to the low doubleword of the ICR causes the IPI to be sent.
    210   //
    211   WriteLocalApicReg (XAPIC_ICR_HIGH_OFFSET, ApicId << 24);
    212   WriteLocalApicReg (XAPIC_ICR_LOW_OFFSET, IcrLow);
    213 
    214   //
    215   // Wait for DeliveryStatus clear again
    216   //
    217   do {
    218     IcrLowReg.Uint32 = ReadLocalApicReg (XAPIC_ICR_LOW_OFFSET);
    219   } while (IcrLowReg.Bits.DeliveryStatus != 0);
    220 
    221   //
    222   // And restore old contents of ICR high
    223   //
    224   WriteLocalApicReg (XAPIC_ICR_HIGH_OFFSET, IcrHigh);
    225 
    226   SetInterruptState (InterruptState);
    227 
    228 }
    229 
    230 //
    231 // Library API implementation functions
    232 //
    233 
    234 /**
    235   Get the current local APIC mode.
    236 
    237   If local APIC is disabled, then ASSERT.
    238 
    239   @retval LOCAL_APIC_MODE_XAPIC  current APIC mode is xAPIC.
    240   @retval LOCAL_APIC_MODE_X2APIC current APIC mode is x2APIC.
    241 **/
    242 UINTN
    243 EFIAPI
    244 GetApicMode (
    245   VOID
    246   )
    247 {
    248   DEBUG_CODE (
    249     {
    250       MSR_IA32_APIC_BASE_REGISTER  ApicBaseMsr;
    251 
    252       //
    253       // Check to see if the CPU supports the APIC Base Address MSR
    254       //
    255       if (LocalApicBaseAddressMsrSupported ()) {
    256         ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
    257         //
    258         // Local APIC should have been enabled
    259         //
    260         ASSERT (ApicBaseMsr.Bits.EN != 0);
    261         ASSERT (ApicBaseMsr.Bits.EXTD == 0);
    262       }
    263     }
    264   );
    265   return LOCAL_APIC_MODE_XAPIC;
    266 }
    267 
    268 /**
    269   Set the current local APIC mode.
    270 
    271   If the specified local APIC mode is not valid, then ASSERT.
    272   If the specified local APIC mode can't be set as current, then ASSERT.
    273 
    274   @param ApicMode APIC mode to be set.
    275 
    276   @note  This API must not be called from an interrupt handler or SMI handler.
    277          It may result in unpredictable behavior.
    278 **/
    279 VOID
    280 EFIAPI
    281 SetApicMode (
    282   IN UINTN  ApicMode
    283   )
    284 {
    285   ASSERT (ApicMode == LOCAL_APIC_MODE_XAPIC);
    286   ASSERT (GetApicMode () == LOCAL_APIC_MODE_XAPIC);
    287 }
    288 
    289 /**
    290   Get the initial local APIC ID of the executing processor assigned by hardware upon power on or reset.
    291 
    292   In xAPIC mode, the initial local APIC ID may be different from current APIC ID.
    293   In x2APIC mode, the local APIC ID can't be changed and there is no concept of initial APIC ID. In this case,
    294   the 32-bit local APIC ID is returned as initial APIC ID.
    295 
    296   @return  32-bit initial local APIC ID of the executing processor.
    297 **/
    298 UINT32
    299 EFIAPI
    300 GetInitialApicId (
    301   VOID
    302   )
    303 {
    304   UINT32 ApicId;
    305   UINT32 MaxCpuIdIndex;
    306   UINT32 RegEbx;
    307 
    308   ASSERT (GetApicMode () == LOCAL_APIC_MODE_XAPIC);
    309 
    310   //
    311   // Get the max index of basic CPUID
    312   //
    313   AsmCpuid (CPUID_SIGNATURE, &MaxCpuIdIndex, NULL, NULL, NULL);
    314 
    315   //
    316   // If CPUID Leaf B is supported,
    317   // And CPUID.0BH:EBX[15:0] reports a non-zero value,
    318   // Then the initial 32-bit APIC ID = CPUID.0BH:EDX
    319   // Else the initial 8-bit APIC ID = CPUID.1:EBX[31:24]
    320   //
    321   if (MaxCpuIdIndex >= CPUID_EXTENDED_TOPOLOGY) {
    322     AsmCpuidEx (CPUID_EXTENDED_TOPOLOGY, 0, NULL, &RegEbx, NULL, &ApicId);
    323     if ((RegEbx & (BIT16 - 1)) != 0) {
    324       return ApicId;
    325     }
    326   }
    327 
    328   AsmCpuid (CPUID_VERSION_INFO, NULL, &RegEbx, NULL, NULL);
    329   return RegEbx >> 24;
    330 }
    331 
    332 /**
    333   Get the local APIC ID of the executing processor.
    334 
    335   @return  32-bit local APIC ID of the executing processor.
    336 **/
    337 UINT32
    338 EFIAPI
    339 GetApicId (
    340   VOID
    341   )
    342 {
    343   UINT32 ApicId;
    344 
    345   ASSERT (GetApicMode () == LOCAL_APIC_MODE_XAPIC);
    346 
    347   if ((ApicId = GetInitialApicId ()) < 0x100) {
    348     //
    349     // If the initial local APIC ID is less 0x100, read APIC ID from
    350     // XAPIC_ID_OFFSET, otherwise return the initial local APIC ID.
    351     //
    352     ApicId = ReadLocalApicReg (XAPIC_ID_OFFSET);
    353     ApicId >>= 24;
    354   }
    355   return ApicId;
    356 }
    357 
    358 /**
    359   Get the value of the local APIC version register.
    360 
    361   @return  the value of the local APIC version register.
    362 **/
    363 UINT32
    364 EFIAPI
    365 GetApicVersion (
    366   VOID
    367   )
    368 {
    369   return ReadLocalApicReg (XAPIC_VERSION_OFFSET);
    370 }
    371 
    372 /**
    373   Send a Fixed IPI to a specified target processor.
    374 
    375   This function returns after the IPI has been accepted by the target processor.
    376 
    377   @param  ApicId   The local APIC ID of the target processor.
    378   @param  Vector   The vector number of the interrupt being sent.
    379 **/
    380 VOID
    381 EFIAPI
    382 SendFixedIpi (
    383   IN UINT32          ApicId,
    384   IN UINT8           Vector
    385   )
    386 {
    387   LOCAL_APIC_ICR_LOW IcrLow;
    388 
    389   IcrLow.Uint32 = 0;
    390   IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_FIXED;
    391   IcrLow.Bits.Level = 1;
    392   IcrLow.Bits.Vector = Vector;
    393   SendIpi (IcrLow.Uint32, ApicId);
    394 }
    395 
    396 /**
    397   Send a Fixed IPI to all processors excluding self.
    398 
    399   This function returns after the IPI has been accepted by the target processors.
    400 
    401   @param  Vector   The vector number of the interrupt being sent.
    402 **/
    403 VOID
    404 EFIAPI
    405 SendFixedIpiAllExcludingSelf (
    406   IN UINT8           Vector
    407   )
    408 {
    409   LOCAL_APIC_ICR_LOW IcrLow;
    410 
    411   IcrLow.Uint32 = 0;
    412   IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_FIXED;
    413   IcrLow.Bits.Level = 1;
    414   IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;
    415   IcrLow.Bits.Vector = Vector;
    416   SendIpi (IcrLow.Uint32, 0);
    417 }
    418 
    419 /**
    420   Send a SMI IPI to a specified target processor.
    421 
    422   This function returns after the IPI has been accepted by the target processor.
    423 
    424   @param  ApicId   Specify the local APIC ID of the target processor.
    425 **/
    426 VOID
    427 EFIAPI
    428 SendSmiIpi (
    429   IN UINT32          ApicId
    430   )
    431 {
    432   LOCAL_APIC_ICR_LOW IcrLow;
    433 
    434   IcrLow.Uint32 = 0;
    435   IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_SMI;
    436   IcrLow.Bits.Level = 1;
    437   SendIpi (IcrLow.Uint32, ApicId);
    438 }
    439 
    440 /**
    441   Send a SMI IPI to all processors excluding self.
    442 
    443   This function returns after the IPI has been accepted by the target processors.
    444 **/
    445 VOID
    446 EFIAPI
    447 SendSmiIpiAllExcludingSelf (
    448   VOID
    449   )
    450 {
    451   LOCAL_APIC_ICR_LOW IcrLow;
    452 
    453   IcrLow.Uint32 = 0;
    454   IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_SMI;
    455   IcrLow.Bits.Level = 1;
    456   IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;
    457   SendIpi (IcrLow.Uint32, 0);
    458 }
    459 
    460 /**
    461   Send an INIT IPI to a specified target processor.
    462 
    463   This function returns after the IPI has been accepted by the target processor.
    464 
    465   @param  ApicId   Specify the local APIC ID of the target processor.
    466 **/
    467 VOID
    468 EFIAPI
    469 SendInitIpi (
    470   IN UINT32          ApicId
    471   )
    472 {
    473   LOCAL_APIC_ICR_LOW IcrLow;
    474 
    475   IcrLow.Uint32 = 0;
    476   IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_INIT;
    477   IcrLow.Bits.Level = 1;
    478   SendIpi (IcrLow.Uint32, ApicId);
    479 }
    480 
    481 /**
    482   Send an INIT IPI to all processors excluding self.
    483 
    484   This function returns after the IPI has been accepted by the target processors.
    485 **/
    486 VOID
    487 EFIAPI
    488 SendInitIpiAllExcludingSelf (
    489   VOID
    490   )
    491 {
    492   LOCAL_APIC_ICR_LOW IcrLow;
    493 
    494   IcrLow.Uint32 = 0;
    495   IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_INIT;
    496   IcrLow.Bits.Level = 1;
    497   IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;
    498   SendIpi (IcrLow.Uint32, 0);
    499 }
    500 
    501 /**
    502   Send an INIT-Start-up-Start-up IPI sequence to a specified target processor.
    503 
    504   This function returns after the IPI has been accepted by the target processor.
    505 
    506   if StartupRoutine >= 1M, then ASSERT.
    507   if StartupRoutine is not multiple of 4K, then ASSERT.
    508 
    509   @param  ApicId          Specify the local APIC ID of the target processor.
    510   @param  StartupRoutine  Points to a start-up routine which is below 1M physical
    511                           address and 4K aligned.
    512 **/
    513 VOID
    514 EFIAPI
    515 SendInitSipiSipi (
    516   IN UINT32          ApicId,
    517   IN UINT32          StartupRoutine
    518   )
    519 {
    520   LOCAL_APIC_ICR_LOW IcrLow;
    521 
    522   ASSERT (StartupRoutine < 0x100000);
    523   ASSERT ((StartupRoutine & 0xfff) == 0);
    524 
    525   SendInitIpi (ApicId);
    526   MicroSecondDelay (PcdGet32(PcdCpuInitIpiDelayInMicroSeconds));
    527   IcrLow.Uint32 = 0;
    528   IcrLow.Bits.Vector = (StartupRoutine >> 12);
    529   IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_STARTUP;
    530   IcrLow.Bits.Level = 1;
    531   SendIpi (IcrLow.Uint32, ApicId);
    532   MicroSecondDelay (200);
    533   SendIpi (IcrLow.Uint32, ApicId);
    534 }
    535 
    536 /**
    537   Send an INIT-Start-up-Start-up IPI sequence to all processors excluding self.
    538 
    539   This function returns after the IPI has been accepted by the target processors.
    540 
    541   if StartupRoutine >= 1M, then ASSERT.
    542   if StartupRoutine is not multiple of 4K, then ASSERT.
    543 
    544   @param  StartupRoutine    Points to a start-up routine which is below 1M physical
    545                             address and 4K aligned.
    546 **/
    547 VOID
    548 EFIAPI
    549 SendInitSipiSipiAllExcludingSelf (
    550   IN UINT32          StartupRoutine
    551   )
    552 {
    553   LOCAL_APIC_ICR_LOW IcrLow;
    554 
    555   ASSERT (StartupRoutine < 0x100000);
    556   ASSERT ((StartupRoutine & 0xfff) == 0);
    557 
    558   SendInitIpiAllExcludingSelf ();
    559   MicroSecondDelay (PcdGet32(PcdCpuInitIpiDelayInMicroSeconds));
    560   IcrLow.Uint32 = 0;
    561   IcrLow.Bits.Vector = (StartupRoutine >> 12);
    562   IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_STARTUP;
    563   IcrLow.Bits.Level = 1;
    564   IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;
    565   SendIpi (IcrLow.Uint32, 0);
    566   MicroSecondDelay (200);
    567   SendIpi (IcrLow.Uint32, 0);
    568 }
    569 
    570 /**
    571   Initialize the state of the SoftwareEnable bit in the Local APIC
    572   Spurious Interrupt Vector register.
    573 
    574   @param  Enable  If TRUE, then set SoftwareEnable to 1
    575                   If FALSE, then set SoftwareEnable to 0.
    576 
    577 **/
    578 VOID
    579 EFIAPI
    580 InitializeLocalApicSoftwareEnable (
    581   IN BOOLEAN  Enable
    582   )
    583 {
    584   LOCAL_APIC_SVR  Svr;
    585 
    586   //
    587   // Set local APIC software-enabled bit.
    588   //
    589   Svr.Uint32 = ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET);
    590   if (Enable) {
    591     if (Svr.Bits.SoftwareEnable == 0) {
    592       Svr.Bits.SoftwareEnable = 1;
    593       WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32);
    594     }
    595   } else {
    596     if (Svr.Bits.SoftwareEnable == 1) {
    597       Svr.Bits.SoftwareEnable = 0;
    598       WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32);
    599     }
    600   }
    601 }
    602 
    603 /**
    604   Programming Virtual Wire Mode.
    605 
    606   This function programs the local APIC for virtual wire mode following
    607   the example described in chapter A.3 of the MP 1.4 spec.
    608 
    609   IOxAPIC is not involved in this type of virtual wire mode.
    610 **/
    611 VOID
    612 EFIAPI
    613 ProgramVirtualWireMode (
    614   VOID
    615   )
    616 {
    617   LOCAL_APIC_SVR      Svr;
    618   LOCAL_APIC_LVT_LINT Lint;
    619 
    620   //
    621   // Enable the APIC via SVR and set the spurious interrupt to use Int 00F.
    622   //
    623   Svr.Uint32 = ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET);
    624   Svr.Bits.SpuriousVector = 0xf;
    625   Svr.Bits.SoftwareEnable = 1;
    626   WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32);
    627 
    628   //
    629   // Program the LINT0 vector entry as ExtInt. Not masked, edge, active high.
    630   //
    631   Lint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT0_OFFSET);
    632   Lint.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_EXTINT;
    633   Lint.Bits.InputPinPolarity = 0;
    634   Lint.Bits.TriggerMode = 0;
    635   Lint.Bits.Mask = 0;
    636   WriteLocalApicReg (XAPIC_LVT_LINT0_OFFSET, Lint.Uint32);
    637 
    638   //
    639   // Program the LINT0 vector entry as NMI. Not masked, edge, active high.
    640   //
    641   Lint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT1_OFFSET);
    642   Lint.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_NMI;
    643   Lint.Bits.InputPinPolarity = 0;
    644   Lint.Bits.TriggerMode = 0;
    645   Lint.Bits.Mask = 0;
    646   WriteLocalApicReg (XAPIC_LVT_LINT1_OFFSET, Lint.Uint32);
    647 }
    648 
    649 /**
    650   Disable LINT0 & LINT1 interrupts.
    651 
    652   This function sets the mask flag in the LVT LINT0 & LINT1 registers.
    653 **/
    654 VOID
    655 EFIAPI
    656 DisableLvtInterrupts (
    657   VOID
    658   )
    659 {
    660   LOCAL_APIC_LVT_LINT LvtLint;
    661 
    662   LvtLint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT0_OFFSET);
    663   LvtLint.Bits.Mask = 1;
    664   WriteLocalApicReg (XAPIC_LVT_LINT0_OFFSET, LvtLint.Uint32);
    665 
    666   LvtLint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT1_OFFSET);
    667   LvtLint.Bits.Mask = 1;
    668   WriteLocalApicReg (XAPIC_LVT_LINT1_OFFSET, LvtLint.Uint32);
    669 }
    670 
    671 /**
    672   Read the initial count value from the init-count register.
    673 
    674   @return The initial count value read from the init-count register.
    675 **/
    676 UINT32
    677 EFIAPI
    678 GetApicTimerInitCount (
    679   VOID
    680   )
    681 {
    682   return ReadLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET);
    683 }
    684 
    685 /**
    686   Read the current count value from the current-count register.
    687 
    688   @return The current count value read from the current-count register.
    689 **/
    690 UINT32
    691 EFIAPI
    692 GetApicTimerCurrentCount (
    693   VOID
    694   )
    695 {
    696   return ReadLocalApicReg (XAPIC_TIMER_CURRENT_COUNT_OFFSET);
    697 }
    698 
    699 /**
    700   Initialize the local APIC timer.
    701 
    702   The local APIC timer is initialized and enabled.
    703 
    704   @param DivideValue   The divide value for the DCR. It is one of 1,2,4,8,16,32,64,128.
    705                        If it is 0, then use the current divide value in the DCR.
    706   @param InitCount     The initial count value.
    707   @param PeriodicMode  If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot.
    708   @param Vector        The timer interrupt vector number.
    709 **/
    710 VOID
    711 EFIAPI
    712 InitializeApicTimer (
    713   IN UINTN   DivideValue,
    714   IN UINT32  InitCount,
    715   IN BOOLEAN PeriodicMode,
    716   IN UINT8   Vector
    717   )
    718 {
    719   LOCAL_APIC_DCR       Dcr;
    720   LOCAL_APIC_LVT_TIMER LvtTimer;
    721   UINT32               Divisor;
    722 
    723   //
    724   // Ensure local APIC is in software-enabled state.
    725   //
    726   InitializeLocalApicSoftwareEnable (TRUE);
    727 
    728   //
    729   // Program init-count register.
    730   //
    731   WriteLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET, InitCount);
    732 
    733   if (DivideValue != 0) {
    734     ASSERT (DivideValue <= 128);
    735     ASSERT (DivideValue == GetPowerOfTwo32((UINT32)DivideValue));
    736     Divisor = (UINT32)((HighBitSet32 ((UINT32)DivideValue) - 1) & 0x7);
    737 
    738     Dcr.Uint32 = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET);
    739     Dcr.Bits.DivideValue1 = (Divisor & 0x3);
    740     Dcr.Bits.DivideValue2 = (Divisor >> 2);
    741     WriteLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET, Dcr.Uint32);
    742   }
    743 
    744   //
    745   // Enable APIC timer interrupt with specified timer mode.
    746   //
    747   LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
    748   if (PeriodicMode) {
    749     LvtTimer.Bits.TimerMode = 1;
    750   } else {
    751     LvtTimer.Bits.TimerMode = 0;
    752   }
    753   LvtTimer.Bits.Mask = 0;
    754   LvtTimer.Bits.Vector = Vector;
    755   WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);
    756 }
    757 
    758 /**
    759   Get the state of the local APIC timer.
    760 
    761   This function will ASSERT if the local APIC is not software enabled.
    762 
    763   @param DivideValue   Return the divide value for the DCR. It is one of 1,2,4,8,16,32,64,128.
    764   @param PeriodicMode  Return the timer mode. If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot.
    765   @param Vector        Return the timer interrupt vector number.
    766 **/
    767 VOID
    768 EFIAPI
    769 GetApicTimerState (
    770   OUT UINTN    *DivideValue  OPTIONAL,
    771   OUT BOOLEAN  *PeriodicMode  OPTIONAL,
    772   OUT UINT8    *Vector  OPTIONAL
    773   )
    774 {
    775   UINT32 Divisor;
    776   LOCAL_APIC_DCR Dcr;
    777   LOCAL_APIC_LVT_TIMER LvtTimer;
    778 
    779   //
    780   // Check the APIC Software Enable/Disable bit (bit 8) in Spurious-Interrupt
    781   // Vector Register.
    782   // This bit will be 1, if local APIC is software enabled.
    783   //
    784   ASSERT ((ReadLocalApicReg(XAPIC_SPURIOUS_VECTOR_OFFSET) & BIT8) != 0);
    785 
    786   if (DivideValue != NULL) {
    787     Dcr.Uint32 = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET);
    788     Divisor = Dcr.Bits.DivideValue1 | (Dcr.Bits.DivideValue2 << 2);
    789     Divisor = (Divisor + 1) & 0x7;
    790     *DivideValue = ((UINTN)1) << Divisor;
    791   }
    792 
    793   if (PeriodicMode != NULL || Vector != NULL) {
    794     LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
    795     if (PeriodicMode != NULL) {
    796       if (LvtTimer.Bits.TimerMode == 1) {
    797         *PeriodicMode = TRUE;
    798       } else {
    799         *PeriodicMode = FALSE;
    800       }
    801     }
    802     if (Vector != NULL) {
    803       *Vector = (UINT8) LvtTimer.Bits.Vector;
    804     }
    805   }
    806 }
    807 
    808 /**
    809   Enable the local APIC timer interrupt.
    810 **/
    811 VOID
    812 EFIAPI
    813 EnableApicTimerInterrupt (
    814   VOID
    815   )
    816 {
    817   LOCAL_APIC_LVT_TIMER LvtTimer;
    818 
    819   LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
    820   LvtTimer.Bits.Mask = 0;
    821   WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);
    822 }
    823 
    824 /**
    825   Disable the local APIC timer interrupt.
    826 **/
    827 VOID
    828 EFIAPI
    829 DisableApicTimerInterrupt (
    830   VOID
    831   )
    832 {
    833   LOCAL_APIC_LVT_TIMER LvtTimer;
    834 
    835   LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
    836   LvtTimer.Bits.Mask = 1;
    837   WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);
    838 }
    839 
    840 /**
    841   Get the local APIC timer interrupt state.
    842 
    843   @retval TRUE  The local APIC timer interrupt is enabled.
    844   @retval FALSE The local APIC timer interrupt is disabled.
    845 **/
    846 BOOLEAN
    847 EFIAPI
    848 GetApicTimerInterruptState (
    849   VOID
    850   )
    851 {
    852   LOCAL_APIC_LVT_TIMER LvtTimer;
    853 
    854   LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
    855   return (BOOLEAN)(LvtTimer.Bits.Mask == 0);
    856 }
    857 
    858 /**
    859   Send EOI to the local APIC.
    860 **/
    861 VOID
    862 EFIAPI
    863 SendApicEoi (
    864   VOID
    865   )
    866 {
    867   WriteLocalApicReg (XAPIC_EOI_OFFSET, 0);
    868 }
    869 
    870 /**
    871   Get the 32-bit address that a device should use to send a Message Signaled
    872   Interrupt (MSI) to the Local APIC of the currently executing processor.
    873 
    874   @return 32-bit address used to send an MSI to the Local APIC.
    875 **/
    876 UINT32
    877 EFIAPI
    878 GetApicMsiAddress (
    879   VOID
    880   )
    881 {
    882   LOCAL_APIC_MSI_ADDRESS  MsiAddress;
    883 
    884   //
    885   // Return address for an MSI interrupt to be delivered only to the APIC ID
    886   // of the currently executing processor.
    887   //
    888   MsiAddress.Uint32             = 0;
    889   MsiAddress.Bits.BaseAddress   = 0xFEE;
    890   MsiAddress.Bits.DestinationId = GetApicId ();
    891   return MsiAddress.Uint32;
    892 }
    893 
    894 /**
    895   Get the 64-bit data value that a device should use to send a Message Signaled
    896   Interrupt (MSI) to the Local APIC of the currently executing processor.
    897 
    898   If Vector is not in range 0x10..0xFE, then ASSERT().
    899   If DeliveryMode is not supported, then ASSERT().
    900 
    901   @param  Vector          The 8-bit interrupt vector associated with the MSI.
    902                           Must be in the range 0x10..0xFE
    903   @param  DeliveryMode    A 3-bit value that specifies how the recept of the MSI
    904                           is handled.  The only supported values are:
    905                             0: LOCAL_APIC_DELIVERY_MODE_FIXED
    906                             1: LOCAL_APIC_DELIVERY_MODE_LOWEST_PRIORITY
    907                             2: LOCAL_APIC_DELIVERY_MODE_SMI
    908                             4: LOCAL_APIC_DELIVERY_MODE_NMI
    909                             5: LOCAL_APIC_DELIVERY_MODE_INIT
    910                             7: LOCAL_APIC_DELIVERY_MODE_EXTINT
    911 
    912   @param  LevelTriggered  TRUE specifies a level triggered interrupt.
    913                           FALSE specifies an edge triggered interrupt.
    914   @param  AssertionLevel  Ignored if LevelTriggered is FALSE.
    915                           TRUE specifies a level triggered interrupt that active
    916                           when the interrupt line is asserted.
    917                           FALSE specifies a level triggered interrupt that active
    918                           when the interrupt line is deasserted.
    919 
    920   @return 64-bit data value used to send an MSI to the Local APIC.
    921 **/
    922 UINT64
    923 EFIAPI
    924 GetApicMsiValue (
    925   IN UINT8    Vector,
    926   IN UINTN    DeliveryMode,
    927   IN BOOLEAN  LevelTriggered,
    928   IN BOOLEAN  AssertionLevel
    929   )
    930 {
    931   LOCAL_APIC_MSI_DATA  MsiData;
    932 
    933   ASSERT (Vector >= 0x10 && Vector <= 0xFE);
    934   ASSERT (DeliveryMode < 8 && DeliveryMode != 6 && DeliveryMode != 3);
    935 
    936   MsiData.Uint64            = 0;
    937   MsiData.Bits.Vector       = Vector;
    938   MsiData.Bits.DeliveryMode = (UINT32)DeliveryMode;
    939   if (LevelTriggered) {
    940     MsiData.Bits.TriggerMode = 1;
    941     if (AssertionLevel) {
    942       MsiData.Bits.Level = 1;
    943     }
    944   }
    945   return MsiData.Uint64;
    946 }
    947 
    948 /**
    949   Get Package ID/Core ID/Thread ID of a processor.
    950 
    951   The algorithm assumes the target system has symmetry across physical
    952   package  boundaries with respect to the number of logical processors
    953   per package,  number of cores per package.
    954 
    955   @param[in]  InitialApicId  Initial APIC ID of the target logical processor.
    956   @param[out]  Package       Returns the processor package ID.
    957   @param[out]  Core          Returns the processor core ID.
    958   @param[out]  Thread        Returns the processor thread ID.
    959 **/
    960 VOID
    961 EFIAPI
    962 GetProcessorLocationByApicId (
    963   IN  UINT32  InitialApicId,
    964   OUT UINT32  *Package  OPTIONAL,
    965   OUT UINT32  *Core    OPTIONAL,
    966   OUT UINT32  *Thread  OPTIONAL
    967   )
    968 {
    969   BOOLEAN                       TopologyLeafSupported;
    970   UINTN                         ThreadBits;
    971   UINTN                         CoreBits;
    972   CPUID_VERSION_INFO_EBX        VersionInfoEbx;
    973   CPUID_VERSION_INFO_EDX        VersionInfoEdx;
    974   CPUID_CACHE_PARAMS_EAX        CacheParamsEax;
    975   CPUID_EXTENDED_TOPOLOGY_EAX   ExtendedTopologyEax;
    976   CPUID_EXTENDED_TOPOLOGY_EBX   ExtendedTopologyEbx;
    977   CPUID_EXTENDED_TOPOLOGY_ECX   ExtendedTopologyEcx;
    978   UINT32                        MaxCpuIdIndex;
    979   UINT32                        SubIndex;
    980   UINTN                         LevelType;
    981   UINT32                        MaxLogicProcessorsPerPackage;
    982   UINT32                        MaxCoresPerPackage;
    983 
    984   //
    985   // Check if the processor is capable of supporting more than one logical processor.
    986   //
    987   AsmCpuid(CPUID_VERSION_INFO, NULL, NULL, NULL, &VersionInfoEdx.Uint32);
    988   if (VersionInfoEdx.Bits.HTT == 0) {
    989     if (Thread != NULL) {
    990       *Thread  = 0;
    991     }
    992     if (Core != NULL) {
    993       *Core    = 0;
    994     }
    995     if (Package != NULL) {
    996       *Package = 0;
    997     }
    998     return;
    999   }
   1000 
   1001   ThreadBits = 0;
   1002   CoreBits = 0;
   1003 
   1004   //
   1005   // Assume three-level mapping of APIC ID: Package:Core:SMT.
   1006   //
   1007   TopologyLeafSupported = FALSE;
   1008 
   1009   //
   1010   // Get the max index of basic CPUID
   1011   //
   1012   AsmCpuid(CPUID_SIGNATURE, &MaxCpuIdIndex, NULL, NULL, NULL);
   1013 
   1014   //
   1015   // If the extended topology enumeration leaf is available, it
   1016   // is the preferred mechanism for enumerating topology.
   1017   //
   1018   if (MaxCpuIdIndex >= CPUID_EXTENDED_TOPOLOGY) {
   1019     AsmCpuidEx(
   1020       CPUID_EXTENDED_TOPOLOGY,
   1021       0,
   1022       &ExtendedTopologyEax.Uint32,
   1023       &ExtendedTopologyEbx.Uint32,
   1024       &ExtendedTopologyEcx.Uint32,
   1025       NULL
   1026       );
   1027     //
   1028     // If CPUID.(EAX=0BH, ECX=0H):EBX returns zero and maximum input value for
   1029     // basic CPUID information is greater than 0BH, then CPUID.0BH leaf is not
   1030     // supported on that processor.
   1031     //
   1032     if (ExtendedTopologyEbx.Uint32 != 0) {
   1033       TopologyLeafSupported = TRUE;
   1034 
   1035       //
   1036       // Sub-leaf index 0 (ECX= 0 as input) provides enumeration parameters to extract
   1037       // the SMT sub-field of x2APIC ID.
   1038       //
   1039       LevelType = ExtendedTopologyEcx.Bits.LevelType;
   1040       ASSERT(LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT);
   1041       ThreadBits = ExtendedTopologyEax.Bits.ApicIdShift;
   1042 
   1043       //
   1044       // Software must not assume any "level type" encoding
   1045       // value to be related to any sub-leaf index, except sub-leaf 0.
   1046       //
   1047       SubIndex = 1;
   1048       do {
   1049         AsmCpuidEx(
   1050           CPUID_EXTENDED_TOPOLOGY,
   1051           SubIndex,
   1052           &ExtendedTopologyEax.Uint32,
   1053           NULL,
   1054           &ExtendedTopologyEcx.Uint32,
   1055           NULL
   1056           );
   1057         LevelType = ExtendedTopologyEcx.Bits.LevelType;
   1058         if (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_CORE) {
   1059           CoreBits = ExtendedTopologyEax.Bits.ApicIdShift - ThreadBits;
   1060           break;
   1061         }
   1062         SubIndex++;
   1063       } while (LevelType != CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_INVALID);
   1064     }
   1065   }
   1066 
   1067   if (!TopologyLeafSupported) {
   1068     AsmCpuid(CPUID_VERSION_INFO, NULL, &VersionInfoEbx.Uint32, NULL, NULL);
   1069     MaxLogicProcessorsPerPackage = VersionInfoEbx.Bits.MaximumAddressableIdsForLogicalProcessors;
   1070     if (MaxCpuIdIndex >= CPUID_CACHE_PARAMS) {
   1071       AsmCpuidEx(CPUID_CACHE_PARAMS, 0, &CacheParamsEax.Uint32, NULL, NULL, NULL);
   1072       MaxCoresPerPackage = CacheParamsEax.Bits.MaximumAddressableIdsForLogicalProcessors + 1;
   1073     }
   1074     else {
   1075       //
   1076       // Must be a single-core processor.
   1077       //
   1078       MaxCoresPerPackage = 1;
   1079     }
   1080 
   1081     ThreadBits = (UINTN)(HighBitSet32(MaxLogicProcessorsPerPackage / MaxCoresPerPackage - 1) + 1);
   1082     CoreBits = (UINTN)(HighBitSet32(MaxCoresPerPackage - 1) + 1);  }
   1083 
   1084   if (Thread != NULL) {
   1085     *Thread  = InitialApicId & ((1 << ThreadBits) - 1);
   1086   }
   1087   if (Core != NULL) {
   1088     *Core    = (InitialApicId >> ThreadBits) & ((1 << CoreBits) - 1);
   1089   }
   1090   if (Package != NULL) {
   1091     *Package = (InitialApicId >> (ThreadBits + CoreBits));
   1092   }
   1093 }
   1094