]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c
UefiCpuPkg: Add CpuLib to module INFs that depend on UefiCpuLib.
[mirror_edk2.git] / UefiCpuPkg / Library / BaseXApicX2ApicLib / BaseXApicX2ApicLib.c
index 9f08f5d188c14d9ec5313275b0ce0b67aa16c9e0..1e45ffc3180e74d7aba4fbb5353835155ec77349 100644 (file)
@@ -4,18 +4,17 @@
   This local APIC library instance supports x2APIC capable processors\r
   which have xAPIC and x2APIC modes.\r
 \r
-  Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
-  This program and the accompanying materials\r
-  are licensed and made available under the terms and conditions of the BSD License\r
-  which accompanies this distribution.  The full text of the license may be found at\r
-  http://opensource.org/licenses/bsd-license.php\r
+  Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2017 - 2020, AMD Inc. All rights reserved.<BR>\r
 \r
-  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
-#include <Register/LocalApic.h>\r
+#include <Register/Intel/Cpuid.h>\r
+#include <Register/Amd/Cpuid.h>\r
+#include <Register/Intel/Msr.h>\r
+#include <Register/Intel/LocalApic.h>\r
 \r
 #include <Library/BaseLib.h>\r
 #include <Library/DebugLib.h>\r
 #include <Library/IoLib.h>\r
 #include <Library/TimerLib.h>\r
 #include <Library/PcdLib.h>\r
+#include <Library/CpuLib.h>\r
+#include <Library/UefiCpuLib.h>\r
+#include <IndustryStandard/Tdx.h>\r
 \r
 //\r
 // Library internal functions\r
 //\r
 \r
+/**\r
+  Some MSRs in TDX are accessed via TdCall.\r
+  Some are directly read/write from/to CPU.\r
+\r
+  @param  MsrIndex  Index of the MSR\r
+  @retval TRUE      MSR accessed via TdCall.\r
+  @retval FALSE     MSR accessed not via TdCall.\r
+\r
+**/\r
+BOOLEAN\r
+AccessMsrTdxCall (\r
+  IN UINT32  MsrIndex\r
+  )\r
+{\r
+  if (!TdIsEnabled ()) {\r
+    return FALSE;\r
+  }\r
+\r
+  switch (MsrIndex) {\r
+    case MSR_IA32_X2APIC_TPR:\r
+    case MSR_IA32_X2APIC_PPR:\r
+    case MSR_IA32_X2APIC_EOI:\r
+    case MSR_IA32_X2APIC_ISR0:\r
+    case MSR_IA32_X2APIC_ISR1:\r
+    case MSR_IA32_X2APIC_ISR2:\r
+    case MSR_IA32_X2APIC_ISR3:\r
+    case MSR_IA32_X2APIC_ISR4:\r
+    case MSR_IA32_X2APIC_ISR5:\r
+    case MSR_IA32_X2APIC_ISR6:\r
+    case MSR_IA32_X2APIC_ISR7:\r
+    case MSR_IA32_X2APIC_TMR0:\r
+    case MSR_IA32_X2APIC_TMR1:\r
+    case MSR_IA32_X2APIC_TMR2:\r
+    case MSR_IA32_X2APIC_TMR3:\r
+    case MSR_IA32_X2APIC_TMR4:\r
+    case MSR_IA32_X2APIC_TMR5:\r
+    case MSR_IA32_X2APIC_TMR6:\r
+    case MSR_IA32_X2APIC_TMR7:\r
+    case MSR_IA32_X2APIC_IRR0:\r
+    case MSR_IA32_X2APIC_IRR1:\r
+    case MSR_IA32_X2APIC_IRR2:\r
+    case MSR_IA32_X2APIC_IRR3:\r
+    case MSR_IA32_X2APIC_IRR4:\r
+    case MSR_IA32_X2APIC_IRR5:\r
+    case MSR_IA32_X2APIC_IRR6:\r
+    case MSR_IA32_X2APIC_IRR7:\r
+      return FALSE;\r
+    default:\r
+      break;\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+/**\r
+  Read MSR value.\r
+\r
+  @param  MsrIndex  Index of the MSR to read\r
+  @retval 64-bit    Value of MSR.\r
+\r
+**/\r
+UINT64\r
+LocalApicReadMsrReg64 (\r
+  IN UINT32  MsrIndex\r
+  )\r
+{\r
+  UINT64  Val;\r
+  UINT64  Status;\r
+\r
+  if (AccessMsrTdxCall (MsrIndex)) {\r
+    Status = TdVmCall (TDVMCALL_RDMSR, (UINT64)MsrIndex, 0, 0, 0, &Val);\r
+    if (Status != 0) {\r
+      TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);\r
+    }\r
+  } else {\r
+    Val = AsmReadMsr64 (MsrIndex);\r
+  }\r
+\r
+  return Val;\r
+}\r
+\r
+/**\r
+  Write to MSR.\r
+\r
+  @param  MsrIndex  Index of the MSR to write to\r
+  @param  Value     Value to be written to the MSR\r
+\r
+  @return Value\r
+\r
+**/\r
+UINT64\r
+LocalApicWriteMsrReg64 (\r
+  IN UINT32  MsrIndex,\r
+  IN UINT64  Value\r
+  )\r
+{\r
+  UINT64  Status;\r
+\r
+  if (AccessMsrTdxCall (MsrIndex)) {\r
+    Status = TdVmCall (TDVMCALL_WRMSR, (UINT64)MsrIndex, Value, 0, 0, 0);\r
+    if (Status != 0) {\r
+      TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);\r
+    }\r
+  } else {\r
+    AsmWriteMsr64 (MsrIndex, Value);\r
+  }\r
+\r
+  return Value;\r
+}\r
+\r
+/**\r
+  Read MSR value.\r
+\r
+  @param  MsrIndex  Index of the MSR to read\r
+  @retval 32-bit    Value of MSR.\r
+\r
+**/\r
+UINT32\r
+LocalApicReadMsrReg32 (\r
+  IN UINT32  MsrIndex\r
+  )\r
+{\r
+  return (UINT32)LocalApicReadMsrReg64 (MsrIndex);\r
+}\r
+\r
+/**\r
+  Write to MSR.\r
+\r
+  @param  MsrIndex  Index of the MSR to write to\r
+  @param  Value     Value to be written to the MSR\r
+\r
+  @return Value\r
+\r
+**/\r
+UINT32\r
+LocalApicWriteMsrReg32 (\r
+  IN UINT32  MsrIndex,\r
+  IN UINT32  Value\r
+  )\r
+{\r
+  return (UINT32)LocalApicWriteMsrReg64 (MsrIndex, Value);\r
+}\r
+\r
+/**\r
+  Determine if the CPU supports the Local APIC Base Address MSR.\r
+\r
+  @retval TRUE  The CPU supports the Local APIC Base Address MSR.\r
+  @retval FALSE The CPU does not support the Local APIC Base Address MSR.\r
+\r
+**/\r
+BOOLEAN\r
+LocalApicBaseAddressMsrSupported (\r
+  VOID\r
+  )\r
+{\r
+  UINT32  RegEax;\r
+  UINTN   FamilyId;\r
+\r
+  AsmCpuid (1, &RegEax, NULL, NULL, NULL);\r
+  FamilyId = BitFieldRead32 (RegEax, 8, 11);\r
+  if ((FamilyId == 0x04) || (FamilyId == 0x05)) {\r
+    //\r
+    // CPUs with a FamilyId of 0x04 or 0x05 do not support the\r
+    // Local APIC Base Address MSR\r
+    //\r
+    return FALSE;\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+/**\r
+  Retrieve the base address of local APIC.\r
+\r
+  @return The base address of local APIC.\r
+\r
+**/\r
+UINTN\r
+EFIAPI\r
+GetLocalApicBaseAddress (\r
+  VOID\r
+  )\r
+{\r
+  MSR_IA32_APIC_BASE_REGISTER  ApicBaseMsr;\r
+\r
+  if (!LocalApicBaseAddressMsrSupported ()) {\r
+    //\r
+    // If CPU does not support Local APIC Base Address MSR, then retrieve\r
+    // Local APIC Base Address from PCD\r
+    //\r
+    return PcdGet32 (PcdCpuLocalApicBaseAddress);\r
+  }\r
+\r
+  ApicBaseMsr.Uint64 = LocalApicReadMsrReg64 (MSR_IA32_APIC_BASE);\r
+\r
+  return (UINTN)(LShiftU64 ((UINT64)ApicBaseMsr.Bits.ApicBaseHi, 32)) +\r
+         (((UINTN)ApicBaseMsr.Bits.ApicBase) << 12);\r
+}\r
+\r
+/**\r
+  Set the base address of local APIC.\r
+\r
+  If BaseAddress is not aligned on a 4KB boundary, then ASSERT().\r
+\r
+  @param[in] BaseAddress   Local APIC base address to be set.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+SetLocalApicBaseAddress (\r
+  IN UINTN  BaseAddress\r
+  )\r
+{\r
+  MSR_IA32_APIC_BASE_REGISTER  ApicBaseMsr;\r
+\r
+  ASSERT ((BaseAddress & (SIZE_4KB - 1)) == 0);\r
+\r
+  if (!LocalApicBaseAddressMsrSupported ()) {\r
+    //\r
+    // Ignore set request of the CPU does not support APIC Base Address MSR\r
+    //\r
+    return;\r
+  }\r
+\r
+  ApicBaseMsr.Uint64 = LocalApicReadMsrReg64 (MSR_IA32_APIC_BASE);\r
+\r
+  ApicBaseMsr.Bits.ApicBase   = (UINT32)(BaseAddress >> 12);\r
+  ApicBaseMsr.Bits.ApicBaseHi = (UINT32)(RShiftU64 ((UINT64)BaseAddress, 32));\r
+\r
+  LocalApicWriteMsrReg64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);\r
+}\r
+\r
 /**\r
   Read from a local APIC register.\r
 \r
@@ -47,12 +281,12 @@ ReadLocalApicReg (
   IN UINTN  MmioOffset\r
   )\r
 {\r
-  UINT32 MsrIndex;\r
+  UINT32  MsrIndex;\r
 \r
   ASSERT ((MmioOffset & 0xf) == 0);\r
 \r
   if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {\r
-    return MmioRead32 (PcdGet32 (PcdCpuLocalApicBaseAddress) + MmioOffset);\r
+    return MmioRead32 (GetLocalApicBaseAddress () + MmioOffset);\r
   } else {\r
     //\r
     // DFR is not supported in x2APIC mode.\r
@@ -65,7 +299,7 @@ ReadLocalApicReg (
     ASSERT (MmioOffset != XAPIC_ICR_HIGH_OFFSET);\r
 \r
     MsrIndex = (UINT32)(MmioOffset >> 4) + X2APIC_MSR_BASE_ADDRESS;\r
-    return AsmReadMsr32 (MsrIndex);\r
+    return LocalApicReadMsrReg32 (MsrIndex);\r
   }\r
 }\r
 \r
@@ -86,16 +320,16 @@ ReadLocalApicReg (
 VOID\r
 EFIAPI\r
 WriteLocalApicReg (\r
-  IN UINTN  MmioOffset,\r
-  IN UINT32 Value\r
+  IN UINTN   MmioOffset,\r
+  IN UINT32  Value\r
   )\r
 {\r
-  UINT32 MsrIndex;\r
+  UINT32  MsrIndex;\r
 \r
   ASSERT ((MmioOffset & 0xf) == 0);\r
 \r
   if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {\r
-    MmioWrite32 (PcdGet32 (PcdCpuLocalApicBaseAddress) + MmioOffset, Value);\r
+    MmioWrite32 (GetLocalApicBaseAddress () + MmioOffset, Value);\r
   } else {\r
     //\r
     // DFR is not supported in x2APIC mode.\r
@@ -114,44 +348,81 @@ WriteLocalApicReg (
     // Use memory fence here to force the serializing semantics to be consisent with xAPIC mode.\r
     //\r
     MemoryFence ();\r
-    AsmWriteMsr32 (MsrIndex, Value);\r
+    LocalApicWriteMsrReg32 (MsrIndex, Value);\r
   }\r
 }\r
 \r
 /**\r
   Send an IPI by writing to ICR.\r
 \r
-  This function returns after the IPI has been accepted by the target processor. \r
+  This function returns after the IPI has been accepted by the target processor.\r
 \r
   @param  IcrLow 32-bit value to be written to the low half of ICR.\r
   @param  ApicId APIC ID of the target processor if this IPI is targeted for a specific processor.\r
 **/\r
 VOID\r
 SendIpi (\r
-  IN UINT32          IcrLow,\r
-  IN UINT32          ApicId\r
+  IN UINT32  IcrLow,\r
+  IN UINT32  ApicId\r
   )\r
 {\r
-  UINT64             MsrValue;\r
-  LOCAL_APIC_ICR_LOW IcrLowReg;\r
+  UINT64              MsrValue;\r
+  LOCAL_APIC_ICR_LOW  IcrLowReg;\r
+  UINTN               LocalApciBaseAddress;\r
+  UINT32              IcrHigh;\r
+  BOOLEAN             InterruptState;\r
 \r
+  //\r
+  // Legacy APIC or X2APIC?\r
+  //\r
   if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {\r
     ASSERT (ApicId <= 0xff);\r
 \r
+    InterruptState = SaveAndDisableInterrupts ();\r
+\r
+    //\r
+    // Get base address of this LAPIC\r
+    //\r
+    LocalApciBaseAddress = GetLocalApicBaseAddress ();\r
+\r
+    //\r
+    // Save existing contents of ICR high 32 bits\r
+    //\r
+    IcrHigh = MmioRead32 (LocalApciBaseAddress + XAPIC_ICR_HIGH_OFFSET);\r
+\r
+    //\r
+    // Wait for DeliveryStatus clear in case a previous IPI\r
+    //  is still being sent\r
+    //\r
+    do {\r
+      IcrLowReg.Uint32 = MmioRead32 (LocalApciBaseAddress + XAPIC_ICR_LOW_OFFSET);\r
+    } while (IcrLowReg.Bits.DeliveryStatus != 0);\r
+\r
     //\r
     // For xAPIC, the act of writing to the low doubleword of the ICR causes the IPI to be sent.\r
     //\r
-    MmioWrite32 (PcdGet32 (PcdCpuLocalApicBaseAddress) + XAPIC_ICR_HIGH_OFFSET, ApicId << 24);\r
-    MmioWrite32 (PcdGet32 (PcdCpuLocalApicBaseAddress) + XAPIC_ICR_LOW_OFFSET, IcrLow);\r
+    MmioWrite32 (LocalApciBaseAddress + XAPIC_ICR_HIGH_OFFSET, ApicId << 24);\r
+    MmioWrite32 (LocalApciBaseAddress + XAPIC_ICR_LOW_OFFSET, IcrLow);\r
+\r
+    //\r
+    // Wait for DeliveryStatus clear again\r
+    //\r
     do {\r
-      IcrLowReg.Uint32 = MmioRead32 (PcdGet32 (PcdCpuLocalApicBaseAddress) + XAPIC_ICR_LOW_OFFSET);\r
+      IcrLowReg.Uint32 = MmioRead32 (LocalApciBaseAddress + XAPIC_ICR_LOW_OFFSET);\r
     } while (IcrLowReg.Bits.DeliveryStatus != 0);\r
+\r
+    //\r
+    // And restore old contents of ICR high\r
+    //\r
+    MmioWrite32 (LocalApciBaseAddress + XAPIC_ICR_HIGH_OFFSET, IcrHigh);\r
+\r
+    SetInterruptState (InterruptState);\r
   } else {\r
     //\r
-    // For x2APIC, A single MSR write to the Interrupt Command Register is required for dispatching an \r
+    // For x2APIC, A single MSR write to the Interrupt Command Register is required for dispatching an\r
     // interrupt in x2APIC mode.\r
     //\r
-    MsrValue = LShiftU64 ((UINT64) ApicId, 32) | IcrLow;\r
+    MsrValue = LShiftU64 ((UINT64)ApicId, 32) | IcrLow;\r
     AsmWriteMsr64 (X2APIC_MSR_ICR_ADDRESS, MsrValue);\r
   }\r
 }\r
@@ -174,14 +445,21 @@ GetApicMode (
   VOID\r
   )\r
 {\r
-  MSR_IA32_APIC_BASE ApicBaseMsr;\r
+  MSR_IA32_APIC_BASE_REGISTER  ApicBaseMsr;\r
+\r
+  if (!LocalApicBaseAddressMsrSupported ()) {\r
+    //\r
+    // If CPU does not support APIC Base Address MSR, then return XAPIC mode\r
+    //\r
+    return LOCAL_APIC_MODE_XAPIC;\r
+  }\r
 \r
-  ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE_ADDRESS);\r
+  ApicBaseMsr.Uint64 = LocalApicReadMsrReg64 (MSR_IA32_APIC_BASE);\r
   //\r
   // Local APIC should have been enabled\r
   //\r
-  ASSERT (ApicBaseMsr.Bits.En != 0);\r
-  if (ApicBaseMsr.Bits.Extd != 0) {\r
+  ASSERT (ApicBaseMsr.Bits.EN != 0);\r
+  if (ApicBaseMsr.Bits.EXTD != 0) {\r
     return LOCAL_APIC_MODE_X2APIC;\r
   } else {\r
     return LOCAL_APIC_MODE_XAPIC;\r
@@ -195,6 +473,9 @@ GetApicMode (
   If the specified local APIC mode can't be set as current, then ASSERT.\r
 \r
   @param ApicMode APIC mode to be set.\r
+\r
+  @note  This API must not be called from an interrupt handler or SMI handler.\r
+         It may result in unpredictable behavior.\r
 **/\r
 VOID\r
 EFIAPI\r
@@ -202,8 +483,15 @@ SetApicMode (
   IN UINTN  ApicMode\r
   )\r
 {\r
-  UINTN              CurrentMode;\r
-  MSR_IA32_APIC_BASE ApicBaseMsr;\r
+  UINTN                        CurrentMode;\r
+  MSR_IA32_APIC_BASE_REGISTER  ApicBaseMsr;\r
+\r
+  if (!LocalApicBaseAddressMsrSupported ()) {\r
+    //\r
+    // Ignore set request if the CPU does not support APIC Base Address MSR\r
+    //\r
+    return;\r
+  }\r
 \r
   CurrentMode = GetApicMode ();\r
   if (CurrentMode == LOCAL_APIC_MODE_XAPIC) {\r
@@ -211,9 +499,9 @@ SetApicMode (
       case LOCAL_APIC_MODE_XAPIC:\r
         break;\r
       case LOCAL_APIC_MODE_X2APIC:\r
-        ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE_ADDRESS);\r
-        ApicBaseMsr.Bits.Extd = 1;\r
-        AsmWriteMsr64 (MSR_IA32_APIC_BASE_ADDRESS, ApicBaseMsr.Uint64);\r
+        ApicBaseMsr.Uint64    = LocalApicReadMsrReg64 (MSR_IA32_APIC_BASE);\r
+        ApicBaseMsr.Bits.EXTD = 1;\r
+        LocalApicWriteMsrReg64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);\r
         break;\r
       default:\r
         ASSERT (FALSE);\r
@@ -225,12 +513,12 @@ SetApicMode (
         //  Transition from x2APIC mode to xAPIC mode is a two-step process:\r
         //    x2APIC -> Local APIC disabled -> xAPIC\r
         //\r
-        ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE_ADDRESS);\r
-        ApicBaseMsr.Bits.Extd = 0;\r
-        ApicBaseMsr.Bits.En = 0;\r
-        AsmWriteMsr64 (MSR_IA32_APIC_BASE_ADDRESS, ApicBaseMsr.Uint64);\r
-        ApicBaseMsr.Bits.En = 1;\r
-        AsmWriteMsr64 (MSR_IA32_APIC_BASE_ADDRESS, ApicBaseMsr.Uint64);\r
+        ApicBaseMsr.Uint64    = AsmReadMsr64 (MSR_IA32_APIC_BASE);\r
+        ApicBaseMsr.Bits.EXTD = 0;\r
+        ApicBaseMsr.Bits.EN   = 0;\r
+        AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);\r
+        ApicBaseMsr.Bits.EN = 1;\r
+        AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);\r
         break;\r
       case LOCAL_APIC_MODE_X2APIC:\r
         break;\r
@@ -243,8 +531,8 @@ SetApicMode (
 /**\r
   Get the initial local APIC ID of the executing processor assigned by hardware upon power on or reset.\r
 \r
-  In xAPIC mode, the initial local APIC ID is 8-bit, and may be different from current APIC ID.\r
-  In x2APIC mode, the local APIC ID can't be changed and there is no concept of initial APIC ID. In this case, \r
+  In xAPIC mode, the initial local APIC ID may be different from current APIC ID.\r
+  In x2APIC mode, the local APIC ID can't be changed and there is no concept of initial APIC ID. In this case,\r
   the 32-bit local APIC ID is returned as initial APIC ID.\r
 \r
   @return  32-bit initial local APIC ID of the executing processor.\r
@@ -255,9 +543,28 @@ GetInitialApicId (
   VOID\r
   )\r
 {\r
-  UINT32 RegEbx;\r
+  UINT32  ApicId;\r
+  UINT32  MaxCpuIdIndex;\r
+  UINT32  RegEbx;\r
 \r
   if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {\r
+    //\r
+    // Get the max index of basic CPUID\r
+    //\r
+    AsmCpuid (CPUID_SIGNATURE, &MaxCpuIdIndex, NULL, NULL, NULL);\r
+    //\r
+    // If CPUID Leaf B is supported,\r
+    // And CPUID.0BH:EBX[15:0] reports a non-zero value,\r
+    // Then the initial 32-bit APIC ID = CPUID.0BH:EDX\r
+    // Else the initial 8-bit APIC ID = CPUID.1:EBX[31:24]\r
+    //\r
+    if (MaxCpuIdIndex >= CPUID_EXTENDED_TOPOLOGY) {\r
+      AsmCpuidEx (CPUID_EXTENDED_TOPOLOGY, 0, NULL, &RegEbx, NULL, &ApicId);\r
+      if ((RegEbx & (BIT16 - 1)) != 0) {\r
+        return ApicId;\r
+      }\r
+    }\r
+\r
     AsmCpuid (CPUID_VERSION_INFO, NULL, &RegEbx, NULL, NULL);\r
     return RegEbx >> 24;\r
   } else {\r
@@ -276,12 +583,14 @@ GetApicId (
   VOID\r
   )\r
 {\r
-  UINT32 ApicId;\r
+  UINT32  ApicId;\r
+  UINT32  InitApicId;\r
 \r
   ApicId = ReadLocalApicReg (XAPIC_ID_OFFSET);\r
   if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {\r
-    ApicId >>= 24;\r
+    ApicId = ((InitApicId = GetInitialApicId ()) < 0x100) ? (ApicId >> 24) : InitApicId;\r
   }\r
+\r
   return ApicId;\r
 }\r
 \r
@@ -302,7 +611,7 @@ GetApicVersion (
 /**\r
   Send a Fixed IPI to a specified target processor.\r
 \r
-  This function returns after the IPI has been accepted by the target processor. \r
+  This function returns after the IPI has been accepted by the target processor.\r
 \r
   @param  ApicId   The local APIC ID of the target processor.\r
   @param  Vector   The vector number of the interrupt being sent.\r
@@ -310,67 +619,67 @@ GetApicVersion (
 VOID\r
 EFIAPI\r
 SendFixedIpi (\r
-  IN UINT32          ApicId,\r
-  IN UINT8           Vector\r
+  IN UINT32  ApicId,\r
+  IN UINT8   Vector\r
   )\r
 {\r
-  LOCAL_APIC_ICR_LOW IcrLow;\r
+  LOCAL_APIC_ICR_LOW  IcrLow;\r
 \r
-  IcrLow.Uint32 = 0;\r
+  IcrLow.Uint32            = 0;\r
   IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_FIXED;\r
-  IcrLow.Bits.Level = 1;\r
-  IcrLow.Bits.Vector = Vector;\r
+  IcrLow.Bits.Level        = 1;\r
+  IcrLow.Bits.Vector       = Vector;\r
   SendIpi (IcrLow.Uint32, ApicId);\r
 }\r
 \r
 /**\r
   Send a Fixed IPI to all processors excluding self.\r
 \r
-  This function returns after the IPI has been accepted by the target processors. \r
+  This function returns after the IPI has been accepted by the target processors.\r
 \r
   @param  Vector   The vector number of the interrupt being sent.\r
 **/\r
 VOID\r
 EFIAPI\r
 SendFixedIpiAllExcludingSelf (\r
-  IN UINT8           Vector\r
+  IN UINT8  Vector\r
   )\r
 {\r
-  LOCAL_APIC_ICR_LOW IcrLow;\r
+  LOCAL_APIC_ICR_LOW  IcrLow;\r
 \r
-  IcrLow.Uint32 = 0;\r
-  IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_FIXED;\r
-  IcrLow.Bits.Level = 1;\r
+  IcrLow.Uint32                    = 0;\r
+  IcrLow.Bits.DeliveryMode         = LOCAL_APIC_DELIVERY_MODE_FIXED;\r
+  IcrLow.Bits.Level                = 1;\r
   IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;\r
-  IcrLow.Bits.Vector = Vector;\r
+  IcrLow.Bits.Vector               = Vector;\r
   SendIpi (IcrLow.Uint32, 0);\r
 }\r
 \r
 /**\r
   Send a SMI IPI to a specified target processor.\r
 \r
-  This function returns after the IPI has been accepted by the target processor. \r
+  This function returns after the IPI has been accepted by the target processor.\r
 \r
   @param  ApicId   Specify the local APIC ID of the target processor.\r
 **/\r
 VOID\r
 EFIAPI\r
 SendSmiIpi (\r
-  IN UINT32          ApicId\r
+  IN UINT32  ApicId\r
   )\r
 {\r
-  LOCAL_APIC_ICR_LOW IcrLow;\r
+  LOCAL_APIC_ICR_LOW  IcrLow;\r
 \r
-  IcrLow.Uint32 = 0;\r
+  IcrLow.Uint32            = 0;\r
   IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_SMI;\r
-  IcrLow.Bits.Level = 1;\r
+  IcrLow.Bits.Level        = 1;\r
   SendIpi (IcrLow.Uint32, ApicId);\r
 }\r
 \r
 /**\r
   Send a SMI IPI to all processors excluding self.\r
 \r
-  This function returns after the IPI has been accepted by the target processors. \r
+  This function returns after the IPI has been accepted by the target processors.\r
 **/\r
 VOID\r
 EFIAPI\r
@@ -378,11 +687,11 @@ SendSmiIpiAllExcludingSelf (
   VOID\r
   )\r
 {\r
-  LOCAL_APIC_ICR_LOW IcrLow;\r
+  LOCAL_APIC_ICR_LOW  IcrLow;\r
 \r
-  IcrLow.Uint32 = 0;\r
-  IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_SMI;\r
-  IcrLow.Bits.Level = 1;\r
+  IcrLow.Uint32                    = 0;\r
+  IcrLow.Bits.DeliveryMode         = LOCAL_APIC_DELIVERY_MODE_SMI;\r
+  IcrLow.Bits.Level                = 1;\r
   IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;\r
   SendIpi (IcrLow.Uint32, 0);\r
 }\r
@@ -390,28 +699,28 @@ SendSmiIpiAllExcludingSelf (
 /**\r
   Send an INIT IPI to a specified target processor.\r
 \r
-  This function returns after the IPI has been accepted by the target processor. \r
+  This function returns after the IPI has been accepted by the target processor.\r
 \r
   @param  ApicId   Specify the local APIC ID of the target processor.\r
 **/\r
 VOID\r
 EFIAPI\r
 SendInitIpi (\r
-  IN UINT32          ApicId\r
+  IN UINT32  ApicId\r
   )\r
 {\r
-  LOCAL_APIC_ICR_LOW IcrLow;\r
+  LOCAL_APIC_ICR_LOW  IcrLow;\r
 \r
-  IcrLow.Uint32 = 0;\r
+  IcrLow.Uint32            = 0;\r
   IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_INIT;\r
-  IcrLow.Bits.Level = 1;\r
+  IcrLow.Bits.Level        = 1;\r
   SendIpi (IcrLow.Uint32, ApicId);\r
 }\r
 \r
 /**\r
   Send an INIT IPI to all processors excluding self.\r
 \r
-  This function returns after the IPI has been accepted by the target processors. \r
+  This function returns after the IPI has been accepted by the target processors.\r
 **/\r
 VOID\r
 EFIAPI\r
@@ -419,11 +728,11 @@ SendInitIpiAllExcludingSelf (
   VOID\r
   )\r
 {\r
-  LOCAL_APIC_ICR_LOW IcrLow;\r
+  LOCAL_APIC_ICR_LOW  IcrLow;\r
 \r
-  IcrLow.Uint32 = 0;\r
-  IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_INIT;\r
-  IcrLow.Bits.Level = 1;\r
+  IcrLow.Uint32                    = 0;\r
+  IcrLow.Bits.DeliveryMode         = LOCAL_APIC_DELIVERY_MODE_INIT;\r
+  IcrLow.Bits.Level                = 1;\r
   IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;\r
   SendIpi (IcrLow.Uint32, 0);\r
 }\r
@@ -431,7 +740,7 @@ SendInitIpiAllExcludingSelf (
 /**\r
   Send an INIT-Start-up-Start-up IPI sequence to a specified target processor.\r
 \r
-  This function returns after the IPI has been accepted by the target processor. \r
+  This function returns after the IPI has been accepted by the target processor.\r
 \r
   if StartupRoutine >= 1M, then ASSERT.\r
   if StartupRoutine is not multiple of 4K, then ASSERT.\r
@@ -443,30 +752,32 @@ SendInitIpiAllExcludingSelf (
 VOID\r
 EFIAPI\r
 SendInitSipiSipi (\r
-  IN UINT32          ApicId,\r
-  IN UINT32          StartupRoutine\r
+  IN UINT32  ApicId,\r
+  IN UINT32  StartupRoutine\r
   )\r
 {\r
-  LOCAL_APIC_ICR_LOW IcrLow;\r
+  LOCAL_APIC_ICR_LOW  IcrLow;\r
 \r
   ASSERT (StartupRoutine < 0x100000);\r
   ASSERT ((StartupRoutine & 0xfff) == 0);\r
 \r
   SendInitIpi (ApicId);\r
-  MicroSecondDelay (10);\r
-  IcrLow.Uint32 = 0;\r
-  IcrLow.Bits.Vector = (StartupRoutine >> 12);\r
+  MicroSecondDelay (PcdGet32 (PcdCpuInitIpiDelayInMicroSeconds));\r
+  IcrLow.Uint32            = 0;\r
+  IcrLow.Bits.Vector       = (StartupRoutine >> 12);\r
   IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_STARTUP;\r
-  IcrLow.Bits.Level = 1;\r
-  SendIpi (IcrLow.Uint32, ApicId);\r
-  MicroSecondDelay (200);\r
+  IcrLow.Bits.Level        = 1;\r
   SendIpi (IcrLow.Uint32, ApicId);\r
+  if (!StandardSignatureIsAuthenticAMD ()) {\r
+    MicroSecondDelay (200);\r
+    SendIpi (IcrLow.Uint32, ApicId);\r
+  }\r
 }\r
 \r
 /**\r
   Send an INIT-Start-up-Start-up IPI sequence to all processors excluding self.\r
 \r
-  This function returns after the IPI has been accepted by the target processors. \r
+  This function returns after the IPI has been accepted by the target processors.\r
 \r
   if StartupRoutine >= 1M, then ASSERT.\r
   if StartupRoutine is not multiple of 4K, then ASSERT.\r
@@ -477,24 +788,59 @@ SendInitSipiSipi (
 VOID\r
 EFIAPI\r
 SendInitSipiSipiAllExcludingSelf (\r
-  IN UINT32          StartupRoutine\r
+  IN UINT32  StartupRoutine\r
   )\r
 {\r
-  LOCAL_APIC_ICR_LOW IcrLow;\r
+  LOCAL_APIC_ICR_LOW  IcrLow;\r
 \r
   ASSERT (StartupRoutine < 0x100000);\r
   ASSERT ((StartupRoutine & 0xfff) == 0);\r
 \r
   SendInitIpiAllExcludingSelf ();\r
-  MicroSecondDelay (10);\r
-  IcrLow.Uint32 = 0;\r
-  IcrLow.Bits.Vector = (StartupRoutine >> 12);\r
-  IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_STARTUP;\r
-  IcrLow.Bits.Level = 1;\r
+  MicroSecondDelay (PcdGet32 (PcdCpuInitIpiDelayInMicroSeconds));\r
+  IcrLow.Uint32                    = 0;\r
+  IcrLow.Bits.Vector               = (StartupRoutine >> 12);\r
+  IcrLow.Bits.DeliveryMode         = LOCAL_APIC_DELIVERY_MODE_STARTUP;\r
+  IcrLow.Bits.Level                = 1;\r
   IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;\r
   SendIpi (IcrLow.Uint32, 0);\r
-  MicroSecondDelay (200);\r
-  SendIpi (IcrLow.Uint32, 0);\r
+  if (!StandardSignatureIsAuthenticAMD ()) {\r
+    MicroSecondDelay (200);\r
+    SendIpi (IcrLow.Uint32, 0);\r
+  }\r
+}\r
+\r
+/**\r
+  Initialize the state of the SoftwareEnable bit in the Local APIC\r
+  Spurious Interrupt Vector register.\r
+\r
+  @param  Enable  If TRUE, then set SoftwareEnable to 1\r
+                  If FALSE, then set SoftwareEnable to 0.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+InitializeLocalApicSoftwareEnable (\r
+  IN BOOLEAN  Enable\r
+  )\r
+{\r
+  LOCAL_APIC_SVR  Svr;\r
+\r
+  //\r
+  // Set local APIC software-enabled bit.\r
+  //\r
+  Svr.Uint32 = ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET);\r
+  if (Enable) {\r
+    if (Svr.Bits.SoftwareEnable == 0) {\r
+      Svr.Bits.SoftwareEnable = 1;\r
+      WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32);\r
+    }\r
+  } else {\r
+    if (Svr.Bits.SoftwareEnable == 1) {\r
+      Svr.Bits.SoftwareEnable = 0;\r
+      WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32);\r
+    }\r
+  }\r
 }\r
 \r
 /**\r
@@ -511,13 +857,13 @@ ProgramVirtualWireMode (
   VOID\r
   )\r
 {\r
-  LOCAL_APIC_SVR      Svr;\r
-  LOCAL_APIC_LVT_LINT Lint;\r
+  LOCAL_APIC_SVR       Svr;\r
+  LOCAL_APIC_LVT_LINT  Lint;\r
 \r
   //\r
   // Enable the APIC via SVR and set the spurious interrupt to use Int 00F.\r
   //\r
-  Svr.Uint32 = ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET);\r
+  Svr.Uint32              = ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET);\r
   Svr.Bits.SpuriousVector = 0xf;\r
   Svr.Bits.SoftwareEnable = 1;\r
   WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32);\r
@@ -525,21 +871,21 @@ ProgramVirtualWireMode (
   //\r
   // Program the LINT0 vector entry as ExtInt. Not masked, edge, active high.\r
   //\r
-  Lint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT0_OFFSET);\r
-  Lint.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_EXTINT;\r
+  Lint.Uint32                = ReadLocalApicReg (XAPIC_LVT_LINT0_OFFSET);\r
+  Lint.Bits.DeliveryMode     = LOCAL_APIC_DELIVERY_MODE_EXTINT;\r
   Lint.Bits.InputPinPolarity = 0;\r
-  Lint.Bits.TriggerMode = 0;\r
-  Lint.Bits.Mask = 0;\r
+  Lint.Bits.TriggerMode      = 0;\r
+  Lint.Bits.Mask             = 0;\r
   WriteLocalApicReg (XAPIC_LVT_LINT0_OFFSET, Lint.Uint32);\r
 \r
   //\r
   // Program the LINT0 vector entry as NMI. Not masked, edge, active high.\r
   //\r
-  Lint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT1_OFFSET);\r
-  Lint.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_NMI;\r
+  Lint.Uint32                = ReadLocalApicReg (XAPIC_LVT_LINT1_OFFSET);\r
+  Lint.Bits.DeliveryMode     = LOCAL_APIC_DELIVERY_MODE_NMI;\r
   Lint.Bits.InputPinPolarity = 0;\r
-  Lint.Bits.TriggerMode = 0;\r
-  Lint.Bits.Mask = 0;\r
+  Lint.Bits.TriggerMode      = 0;\r
+  Lint.Bits.Mask             = 0;\r
   WriteLocalApicReg (XAPIC_LVT_LINT1_OFFSET, Lint.Uint32);\r
 }\r
 \r
@@ -554,13 +900,13 @@ DisableLvtInterrupts (
   VOID\r
   )\r
 {\r
-  LOCAL_APIC_LVT_LINT LvtLint;\r
+  LOCAL_APIC_LVT_LINT  LvtLint;\r
 \r
-  LvtLint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT0_OFFSET);\r
+  LvtLint.Uint32    = ReadLocalApicReg (XAPIC_LVT_LINT0_OFFSET);\r
   LvtLint.Bits.Mask = 1;\r
   WriteLocalApicReg (XAPIC_LVT_LINT0_OFFSET, LvtLint.Uint32);\r
 \r
-  LvtLint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT1_OFFSET);\r
+  LvtLint.Uint32    = ReadLocalApicReg (XAPIC_LVT_LINT1_OFFSET);\r
   LvtLint.Bits.Mask = 1;\r
   WriteLocalApicReg (XAPIC_LVT_LINT1_OFFSET, LvtLint.Uint32);\r
 }\r
@@ -607,38 +953,30 @@ GetApicTimerCurrentCount (
 VOID\r
 EFIAPI\r
 InitializeApicTimer (\r
-  IN UINTN   DivideValue,\r
-  IN UINT32  InitCount,\r
-  IN BOOLEAN PeriodicMode,\r
-  IN UINT8   Vector\r
+  IN UINTN    DivideValue,\r
+  IN UINT32   InitCount,\r
+  IN BOOLEAN  PeriodicMode,\r
+  IN UINT8    Vector\r
   )\r
 {\r
-  LOCAL_APIC_SVR       Svr;\r
-  LOCAL_APIC_DCR       Dcr;\r
-  LOCAL_APIC_LVT_TIMER LvtTimer;\r
-  UINT32               Divisor;\r
+  LOCAL_APIC_DCR        Dcr;\r
+  LOCAL_APIC_LVT_TIMER  LvtTimer;\r
+  UINT32                Divisor;\r
 \r
   //\r
   // Ensure local APIC is in software-enabled state.\r
   //\r
-  Svr.Uint32 = ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET);\r
-  Svr.Bits.SoftwareEnable = 1;\r
-  WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32);\r
-\r
-  //\r
-  // Program init-count register.\r
-  //\r
-  WriteLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET, InitCount);\r
+  InitializeLocalApicSoftwareEnable (TRUE);\r
 \r
   if (DivideValue != 0) {\r
     ASSERT (DivideValue <= 128);\r
-    ASSERT (DivideValue == GetPowerOfTwo32((UINT32)DivideValue));\r
+    ASSERT (DivideValue == GetPowerOfTwo32 ((UINT32)DivideValue));\r
     Divisor = (UINT32)((HighBitSet32 ((UINT32)DivideValue) - 1) & 0x7);\r
 \r
-    Dcr.Uint32 = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET);\r
+    Dcr.Uint32            = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET);\r
     Dcr.Bits.DivideValue1 = (Divisor & 0x3);\r
     Dcr.Bits.DivideValue2 = (Divisor >> 2);\r
-    WriteLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET, Dcr.Uint32); \r
+    WriteLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET, Dcr.Uint32);\r
   }\r
 \r
   //\r
@@ -650,14 +988,22 @@ InitializeApicTimer (
   } else {\r
     LvtTimer.Bits.TimerMode = 0;\r
   }\r
-  LvtTimer.Bits.Mask = 0;\r
+\r
+  LvtTimer.Bits.Mask   = 0;\r
   LvtTimer.Bits.Vector = Vector;\r
   WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);\r
+\r
+  //\r
+  // Program init-count register.\r
+  //\r
+  WriteLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET, InitCount);\r
 }\r
 \r
 /**\r
   Get the state of the local APIC timer.\r
 \r
+  This function will ASSERT if the local APIC is not software enabled.\r
+\r
   @param DivideValue   Return the divide value for the DCR. It is one of 1,2,4,8,16,32,64,128.\r
   @param PeriodicMode  Return the timer mode. If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot.\r
   @param Vector        Return the timer interrupt vector number.\r
@@ -670,18 +1016,25 @@ GetApicTimerState (
   OUT UINT8    *Vector  OPTIONAL\r
   )\r
 {\r
-  UINT32 Divisor;\r
-  LOCAL_APIC_DCR Dcr;\r
-  LOCAL_APIC_LVT_TIMER LvtTimer;\r
+  UINT32                Divisor;\r
+  LOCAL_APIC_DCR        Dcr;\r
+  LOCAL_APIC_LVT_TIMER  LvtTimer;\r
+\r
+  //\r
+  // Check the APIC Software Enable/Disable bit (bit 8) in Spurious-Interrupt\r
+  // Vector Register.\r
+  // This bit will be 1, if local APIC is software enabled.\r
+  //\r
+  ASSERT ((ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET) & BIT8) != 0);\r
 \r
   if (DivideValue != NULL) {\r
-    Dcr.Uint32 = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET);\r
-    Divisor = Dcr.Bits.DivideValue1 | (Dcr.Bits.DivideValue2 << 2);\r
-    Divisor = (Divisor + 1) & 0x7;\r
+    Dcr.Uint32   = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET);\r
+    Divisor      = Dcr.Bits.DivideValue1 | (Dcr.Bits.DivideValue2 << 2);\r
+    Divisor      = (Divisor + 1) & 0x7;\r
     *DivideValue = ((UINTN)1) << Divisor;\r
   }\r
 \r
-  if (PeriodicMode != NULL || Vector != NULL) {\r
+  if ((PeriodicMode != NULL) || (Vector != NULL)) {\r
     LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);\r
     if (PeriodicMode != NULL) {\r
       if (LvtTimer.Bits.TimerMode == 1) {\r
@@ -690,8 +1043,9 @@ GetApicTimerState (
         *PeriodicMode = FALSE;\r
       }\r
     }\r
+\r
     if (Vector != NULL) {\r
-      *Vector = (UINT8) LvtTimer.Bits.Vector;\r
+      *Vector = (UINT8)LvtTimer.Bits.Vector;\r
     }\r
   }\r
 }\r
@@ -705,9 +1059,9 @@ EnableApicTimerInterrupt (
   VOID\r
   )\r
 {\r
-  LOCAL_APIC_LVT_TIMER LvtTimer;\r
+  LOCAL_APIC_LVT_TIMER  LvtTimer;\r
 \r
-  LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);\r
+  LvtTimer.Uint32    = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);\r
   LvtTimer.Bits.Mask = 0;\r
   WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);\r
 }\r
@@ -721,9 +1075,9 @@ DisableApicTimerInterrupt (
   VOID\r
   )\r
 {\r
-  LOCAL_APIC_LVT_TIMER LvtTimer;\r
+  LOCAL_APIC_LVT_TIMER  LvtTimer;\r
 \r
-  LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);\r
+  LvtTimer.Uint32    = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);\r
   LvtTimer.Bits.Mask = 1;\r
   WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);\r
 }\r
@@ -740,7 +1094,7 @@ GetApicTimerInterruptState (
   VOID\r
   )\r
 {\r
-  LOCAL_APIC_LVT_TIMER LvtTimer;\r
+  LOCAL_APIC_LVT_TIMER  LvtTimer;\r
 \r
   LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);\r
   return (BOOLEAN)(LvtTimer.Bits.Mask == 0);\r
@@ -758,3 +1112,397 @@ SendApicEoi (
   WriteLocalApicReg (XAPIC_EOI_OFFSET, 0);\r
 }\r
 \r
+/**\r
+  Get the 32-bit address that a device should use to send a Message Signaled\r
+  Interrupt (MSI) to the Local APIC of the currently executing processor.\r
+\r
+  @return 32-bit address used to send an MSI to the Local APIC.\r
+**/\r
+UINT32\r
+EFIAPI\r
+GetApicMsiAddress (\r
+  VOID\r
+  )\r
+{\r
+  LOCAL_APIC_MSI_ADDRESS  MsiAddress;\r
+\r
+  //\r
+  // Return address for an MSI interrupt to be delivered only to the APIC ID\r
+  // of the currently executing processor.\r
+  //\r
+  MsiAddress.Uint32             = 0;\r
+  MsiAddress.Bits.BaseAddress   = 0xFEE;\r
+  MsiAddress.Bits.DestinationId = GetApicId ();\r
+  return MsiAddress.Uint32;\r
+}\r
+\r
+/**\r
+  Get the 64-bit data value that a device should use to send a Message Signaled\r
+  Interrupt (MSI) to the Local APIC of the currently executing processor.\r
+\r
+  If Vector is not in range 0x10..0xFE, then ASSERT().\r
+  If DeliveryMode is not supported, then ASSERT().\r
+\r
+  @param  Vector          The 8-bit interrupt vector associated with the MSI.\r
+                          Must be in the range 0x10..0xFE\r
+  @param  DeliveryMode    A 3-bit value that specifies how the recept of the MSI\r
+                          is handled.  The only supported values are:\r
+                            0: LOCAL_APIC_DELIVERY_MODE_FIXED\r
+                            1: LOCAL_APIC_DELIVERY_MODE_LOWEST_PRIORITY\r
+                            2: LOCAL_APIC_DELIVERY_MODE_SMI\r
+                            4: LOCAL_APIC_DELIVERY_MODE_NMI\r
+                            5: LOCAL_APIC_DELIVERY_MODE_INIT\r
+                            7: LOCAL_APIC_DELIVERY_MODE_EXTINT\r
+\r
+  @param  LevelTriggered  TRUE specifies a level triggered interrupt.\r
+                          FALSE specifies an edge triggered interrupt.\r
+  @param  AssertionLevel  Ignored if LevelTriggered is FALSE.\r
+                          TRUE specifies a level triggered interrupt that active\r
+                          when the interrupt line is asserted.\r
+                          FALSE specifies a level triggered interrupt that active\r
+                          when the interrupt line is deasserted.\r
+\r
+  @return 64-bit data value used to send an MSI to the Local APIC.\r
+**/\r
+UINT64\r
+EFIAPI\r
+GetApicMsiValue (\r
+  IN UINT8    Vector,\r
+  IN UINTN    DeliveryMode,\r
+  IN BOOLEAN  LevelTriggered,\r
+  IN BOOLEAN  AssertionLevel\r
+  )\r
+{\r
+  LOCAL_APIC_MSI_DATA  MsiData;\r
+\r
+  ASSERT (Vector >= 0x10 && Vector <= 0xFE);\r
+  ASSERT (DeliveryMode < 8 && DeliveryMode != 6 && DeliveryMode != 3);\r
+\r
+  MsiData.Uint64            = 0;\r
+  MsiData.Bits.Vector       = Vector;\r
+  MsiData.Bits.DeliveryMode = (UINT32)DeliveryMode;\r
+  if (LevelTriggered) {\r
+    MsiData.Bits.TriggerMode = 1;\r
+    if (AssertionLevel) {\r
+      MsiData.Bits.Level = 1;\r
+    }\r
+  }\r
+\r
+  return MsiData.Uint64;\r
+}\r
+\r
+/**\r
+  Get Package ID/Core ID/Thread ID of a processor.\r
+\r
+  The algorithm assumes the target system has symmetry across physical\r
+  package  boundaries with respect to the number of logical processors\r
+  per package,  number of cores per package.\r
+\r
+  @param[in]  InitialApicId  Initial APIC ID of the target logical processor.\r
+  @param[out]  Package       Returns the processor package ID.\r
+  @param[out]  Core          Returns the processor core ID.\r
+  @param[out]  Thread        Returns the processor thread ID.\r
+**/\r
+VOID\r
+EFIAPI\r
+GetProcessorLocationByApicId (\r
+  IN  UINT32  InitialApicId,\r
+  OUT UINT32  *Package  OPTIONAL,\r
+  OUT UINT32  *Core    OPTIONAL,\r
+  OUT UINT32  *Thread  OPTIONAL\r
+  )\r
+{\r
+  BOOLEAN                             TopologyLeafSupported;\r
+  CPUID_VERSION_INFO_EBX              VersionInfoEbx;\r
+  CPUID_VERSION_INFO_EDX              VersionInfoEdx;\r
+  CPUID_CACHE_PARAMS_EAX              CacheParamsEax;\r
+  CPUID_EXTENDED_TOPOLOGY_EAX         ExtendedTopologyEax;\r
+  CPUID_EXTENDED_TOPOLOGY_EBX         ExtendedTopologyEbx;\r
+  CPUID_EXTENDED_TOPOLOGY_ECX         ExtendedTopologyEcx;\r
+  CPUID_AMD_EXTENDED_CPU_SIG_ECX      AmdExtendedCpuSigEcx;\r
+  CPUID_AMD_PROCESSOR_TOPOLOGY_EBX    AmdProcessorTopologyEbx;\r
+  CPUID_AMD_VIR_PHY_ADDRESS_SIZE_ECX  AmdVirPhyAddressSizeEcx;\r
+  UINT32                              MaxStandardCpuIdIndex;\r
+  UINT32                              MaxExtendedCpuIdIndex;\r
+  UINT32                              SubIndex;\r
+  UINTN                               LevelType;\r
+  UINT32                              MaxLogicProcessorsPerPackage;\r
+  UINT32                              MaxCoresPerPackage;\r
+  UINTN                               ThreadBits;\r
+  UINTN                               CoreBits;\r
+\r
+  //\r
+  // Check if the processor is capable of supporting more than one logical processor.\r
+  //\r
+  AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &VersionInfoEdx.Uint32);\r
+  if (VersionInfoEdx.Bits.HTT == 0) {\r
+    if (Thread != NULL) {\r
+      *Thread = 0;\r
+    }\r
+\r
+    if (Core != NULL) {\r
+      *Core = 0;\r
+    }\r
+\r
+    if (Package != NULL) {\r
+      *Package = 0;\r
+    }\r
+\r
+    return;\r
+  }\r
+\r
+  //\r
+  // Assume three-level mapping of APIC ID: Package|Core|Thread.\r
+  //\r
+  ThreadBits = 0;\r
+  CoreBits   = 0;\r
+\r
+  //\r
+  // Get max index of CPUID\r
+  //\r
+  AsmCpuid (CPUID_SIGNATURE, &MaxStandardCpuIdIndex, NULL, NULL, NULL);\r
+  AsmCpuid (CPUID_EXTENDED_FUNCTION, &MaxExtendedCpuIdIndex, NULL, NULL, NULL);\r
+\r
+  //\r
+  // If the extended topology enumeration leaf is available, it\r
+  // is the preferred mechanism for enumerating topology.\r
+  //\r
+  TopologyLeafSupported = FALSE;\r
+  if (MaxStandardCpuIdIndex >= CPUID_EXTENDED_TOPOLOGY) {\r
+    AsmCpuidEx (\r
+      CPUID_EXTENDED_TOPOLOGY,\r
+      0,\r
+      &ExtendedTopologyEax.Uint32,\r
+      &ExtendedTopologyEbx.Uint32,\r
+      &ExtendedTopologyEcx.Uint32,\r
+      NULL\r
+      );\r
+    //\r
+    // If CPUID.(EAX=0BH, ECX=0H):EBX returns zero and maximum input value for\r
+    // basic CPUID information is greater than 0BH, then CPUID.0BH leaf is not\r
+    // supported on that processor.\r
+    //\r
+    if (ExtendedTopologyEbx.Uint32 != 0) {\r
+      TopologyLeafSupported = TRUE;\r
+\r
+      //\r
+      // Sub-leaf index 0 (ECX= 0 as input) provides enumeration parameters to extract\r
+      // the SMT sub-field of x2APIC ID.\r
+      //\r
+      LevelType = ExtendedTopologyEcx.Bits.LevelType;\r
+      ASSERT (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT);\r
+      ThreadBits = ExtendedTopologyEax.Bits.ApicIdShift;\r
+\r
+      //\r
+      // Software must not assume any "level type" encoding\r
+      // value to be related to any sub-leaf index, except sub-leaf 0.\r
+      //\r
+      SubIndex = 1;\r
+      do {\r
+        AsmCpuidEx (\r
+          CPUID_EXTENDED_TOPOLOGY,\r
+          SubIndex,\r
+          &ExtendedTopologyEax.Uint32,\r
+          NULL,\r
+          &ExtendedTopologyEcx.Uint32,\r
+          NULL\r
+          );\r
+        LevelType = ExtendedTopologyEcx.Bits.LevelType;\r
+        if (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_CORE) {\r
+          CoreBits = ExtendedTopologyEax.Bits.ApicIdShift - ThreadBits;\r
+          break;\r
+        }\r
+\r
+        SubIndex++;\r
+      } while (LevelType != CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_INVALID);\r
+    }\r
+  }\r
+\r
+  if (!TopologyLeafSupported) {\r
+    //\r
+    // Get logical processor count\r
+    //\r
+    AsmCpuid (CPUID_VERSION_INFO, NULL, &VersionInfoEbx.Uint32, NULL, NULL);\r
+    MaxLogicProcessorsPerPackage = VersionInfoEbx.Bits.MaximumAddressableIdsForLogicalProcessors;\r
+\r
+    //\r
+    // Assume single-core processor\r
+    //\r
+    MaxCoresPerPackage = 1;\r
+\r
+    //\r
+    // Check for topology extensions on AMD processor\r
+    //\r
+    if (StandardSignatureIsAuthenticAMD ()) {\r
+      if (MaxExtendedCpuIdIndex >= CPUID_AMD_PROCESSOR_TOPOLOGY) {\r
+        AsmCpuid (CPUID_EXTENDED_CPU_SIG, NULL, NULL, &AmdExtendedCpuSigEcx.Uint32, NULL);\r
+        if (AmdExtendedCpuSigEcx.Bits.TopologyExtensions != 0) {\r
+          //\r
+          // Account for max possible thread count to decode ApicId\r
+          //\r
+          AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE, NULL, NULL, &AmdVirPhyAddressSizeEcx.Uint32, NULL);\r
+          MaxLogicProcessorsPerPackage = 1 << AmdVirPhyAddressSizeEcx.Bits.ApicIdCoreIdSize;\r
+\r
+          //\r
+          // Get cores per processor package\r
+          //\r
+          AsmCpuid (CPUID_AMD_PROCESSOR_TOPOLOGY, NULL, &AmdProcessorTopologyEbx.Uint32, NULL, NULL);\r
+          MaxCoresPerPackage = MaxLogicProcessorsPerPackage / (AmdProcessorTopologyEbx.Bits.ThreadsPerCore + 1);\r
+        }\r
+      }\r
+    } else {\r
+      //\r
+      // Extract core count based on CACHE information\r
+      //\r
+      if (MaxStandardCpuIdIndex >= CPUID_CACHE_PARAMS) {\r
+        AsmCpuidEx (CPUID_CACHE_PARAMS, 0, &CacheParamsEax.Uint32, NULL, NULL, NULL);\r
+        if (CacheParamsEax.Uint32 != 0) {\r
+          MaxCoresPerPackage = CacheParamsEax.Bits.MaximumAddressableIdsForLogicalProcessors + 1;\r
+        }\r
+      }\r
+    }\r
+\r
+    ThreadBits = (UINTN)(HighBitSet32 (MaxLogicProcessorsPerPackage / MaxCoresPerPackage - 1) + 1);\r
+    CoreBits   = (UINTN)(HighBitSet32 (MaxCoresPerPackage - 1) + 1);\r
+  }\r
+\r
+  if (Thread != NULL) {\r
+    *Thread = InitialApicId & ((1 << ThreadBits) - 1);\r
+  }\r
+\r
+  if (Core != NULL) {\r
+    *Core = (InitialApicId >> ThreadBits) & ((1 << CoreBits) - 1);\r
+  }\r
+\r
+  if (Package != NULL) {\r
+    *Package = (InitialApicId >> (ThreadBits + CoreBits));\r
+  }\r
+}\r
+\r
+/**\r
+  Get Package ID/Die ID/Tile ID/Module ID/Core ID/Thread ID of a processor.\r
+\r
+  The algorithm assumes the target system has symmetry across physical\r
+  package boundaries with respect to the number of threads per core, number of\r
+  cores per module, number of modules per tile, number of tiles per die, number\r
+  of dies per package.\r
+\r
+  @param[in]   InitialApicId Initial APIC ID of the target logical processor.\r
+  @param[out]  Package       Returns the processor package ID.\r
+  @param[out]  Die           Returns the processor die ID.\r
+  @param[out]  Tile          Returns the processor tile ID.\r
+  @param[out]  Module        Returns the processor module ID.\r
+  @param[out]  Core          Returns the processor core ID.\r
+  @param[out]  Thread        Returns the processor thread ID.\r
+**/\r
+VOID\r
+EFIAPI\r
+GetProcessorLocation2ByApicId (\r
+  IN  UINT32  InitialApicId,\r
+  OUT UINT32  *Package  OPTIONAL,\r
+  OUT UINT32  *Die      OPTIONAL,\r
+  OUT UINT32  *Tile     OPTIONAL,\r
+  OUT UINT32  *Module   OPTIONAL,\r
+  OUT UINT32  *Core     OPTIONAL,\r
+  OUT UINT32  *Thread   OPTIONAL\r
+  )\r
+{\r
+  CPUID_EXTENDED_TOPOLOGY_EAX  ExtendedTopologyEax;\r
+  CPUID_EXTENDED_TOPOLOGY_ECX  ExtendedTopologyEcx;\r
+  UINT32                       MaxStandardCpuIdIndex;\r
+  UINT32                       Index;\r
+  UINTN                        LevelType;\r
+  UINT32                       Bits[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE + 2];\r
+  UINT32                       *Location[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE + 2];\r
+\r
+  for (LevelType = 0; LevelType < ARRAY_SIZE (Bits); LevelType++) {\r
+    Bits[LevelType] = 0;\r
+  }\r
+\r
+  //\r
+  // Get max index of CPUID\r
+  //\r
+  AsmCpuid (CPUID_SIGNATURE, &MaxStandardCpuIdIndex, NULL, NULL, NULL);\r
+  if (MaxStandardCpuIdIndex < CPUID_V2_EXTENDED_TOPOLOGY) {\r
+    if (Die != NULL) {\r
+      *Die = 0;\r
+    }\r
+\r
+    if (Tile != NULL) {\r
+      *Tile = 0;\r
+    }\r
+\r
+    if (Module != NULL) {\r
+      *Module = 0;\r
+    }\r
+\r
+    GetProcessorLocationByApicId (InitialApicId, Package, Core, Thread);\r
+    return;\r
+  }\r
+\r
+  //\r
+  // If the V2 extended topology enumeration leaf is available, it\r
+  // is the preferred mechanism for enumerating topology.\r
+  //\r
+  for (Index = 0; ; Index++) {\r
+    AsmCpuidEx (\r
+      CPUID_V2_EXTENDED_TOPOLOGY,\r
+      Index,\r
+      &ExtendedTopologyEax.Uint32,\r
+      NULL,\r
+      &ExtendedTopologyEcx.Uint32,\r
+      NULL\r
+      );\r
+\r
+    LevelType = ExtendedTopologyEcx.Bits.LevelType;\r
+\r
+    //\r
+    // first level reported should be SMT.\r
+    //\r
+    ASSERT ((Index != 0) || (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT));\r
+    if (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_INVALID) {\r
+      break;\r
+    }\r
+\r
+    ASSERT (LevelType < ARRAY_SIZE (Bits));\r
+    Bits[LevelType] = ExtendedTopologyEax.Bits.ApicIdShift;\r
+  }\r
+\r
+  for (LevelType = CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_CORE; LevelType < ARRAY_SIZE (Bits); LevelType++) {\r
+    //\r
+    // If there are more levels between level-1 (low-level) and level-2 (high-level), the unknown levels will be ignored\r
+    // and treated as an extension of the last known level (i.e., level-1 in this case).\r
+    //\r
+    if (Bits[LevelType] == 0) {\r
+      Bits[LevelType] = Bits[LevelType - 1];\r
+    }\r
+  }\r
+\r
+  Location[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE + 1] = Package;\r
+  Location[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE]     = Die;\r
+  Location[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_TILE]    = Tile;\r
+  Location[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_MODULE]  = Module;\r
+  Location[CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_CORE]       = Core;\r
+  Location[CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT]        = Thread;\r
+\r
+  Bits[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE + 1] = 32;\r
+\r
+  for ( LevelType = CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT\r
+        ; LevelType <= CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE + 1\r
+        ; LevelType++\r
+        )\r
+  {\r
+    if (Location[LevelType] != NULL) {\r
+      //\r
+      // Bits[i] holds the number of bits to shift right on x2APIC ID to get a unique\r
+      // topology ID of the next level type.\r
+      //\r
+      *Location[LevelType] = InitialApicId >> Bits[LevelType - 1];\r
+\r
+      //\r
+      // Bits[i] - Bits[i-1] holds the number of bits for the next ONE level type.\r
+      //\r
+      *Location[LevelType] &= (1 << (Bits[LevelType] - Bits[LevelType - 1])) - 1;\r
+    }\r
+  }\r
+}\r