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