]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.c
UefiCpuPkg: Add CpuLib to module INFs that depend on UefiCpuLib.
[mirror_edk2.git] / UefiCpuPkg / Library / BaseXApicLib / BaseXApicLib.c
index 77c24deed0b3096b941bea0d3c62bac96ae8d757..a944c3d01cf72640b8bd126207612c836ecbaf69 100644 (file)
@@ -3,18 +3,17 @@
 \r
   This local APIC library instance supports xAPIC mode only.\r
 \r
-  Copyright (c) 2010 - 2011, 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
 \r
 //\r
 // Library internal functions\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 = AsmReadMsr64 (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 if the CPU does not support APIC Base Address MSR\r
+    //\r
+    return;\r
+  }\r
+\r
+  ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);\r
+\r
+  ApicBaseMsr.Bits.ApicBase   = (UINT32)(BaseAddress >> 12);\r
+  ApicBaseMsr.Bits.ApicBaseHi = (UINT32)(RShiftU64 ((UINT64)BaseAddress, 32));\r
+\r
+  AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);\r
+}\r
+\r
 /**\r
   Read from a local APIC register.\r
 \r
@@ -49,7 +139,7 @@ ReadLocalApicReg (
   ASSERT ((MmioOffset & 0xf) == 0);\r
   ASSERT (GetApicMode () == LOCAL_APIC_MODE_XAPIC);\r
 \r
-  return MmioRead32 (PcdGet32 (PcdCpuLocalApicBaseAddress) + MmioOffset);\r
+  return MmioRead32 (GetLocalApicBaseAddress () + MmioOffset);\r
 }\r
 \r
 /**\r
@@ -69,43 +159,71 @@ 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
   ASSERT ((MmioOffset & 0xf) == 0);\r
   ASSERT (GetApicMode () == LOCAL_APIC_MODE_XAPIC);\r
 \r
-  MmioWrite32 (PcdGet32 (PcdCpuLocalApicBaseAddress) + MmioOffset, Value);\r
+  MmioWrite32 (GetLocalApicBaseAddress () + MmioOffset, Value);\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
-  LOCAL_APIC_ICR_LOW IcrLowReg;\r
+  LOCAL_APIC_ICR_LOW  IcrLowReg;\r
+  UINT32              IcrHigh;\r
+  BOOLEAN             InterruptState;\r
 \r
   ASSERT (GetApicMode () == LOCAL_APIC_MODE_XAPIC);\r
   ASSERT (ApicId <= 0xff);\r
 \r
+  InterruptState = SaveAndDisableInterrupts ();\r
+\r
+  //\r
+  // Save existing contents of ICR high 32 bits\r
+  //\r
+  IcrHigh = ReadLocalApicReg (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 = ReadLocalApicReg (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
   WriteLocalApicReg (XAPIC_ICR_HIGH_OFFSET, ApicId << 24);\r
   WriteLocalApicReg (XAPIC_ICR_LOW_OFFSET, IcrLow);\r
+\r
+  //\r
+  // Wait for DeliveryStatus clear again\r
+  //\r
   do {\r
     IcrLowReg.Uint32 = ReadLocalApicReg (XAPIC_ICR_LOW_OFFSET);\r
   } while (IcrLowReg.Bits.DeliveryStatus != 0);\r
+\r
+  //\r
+  // And restore old contents of ICR high\r
+  //\r
+  WriteLocalApicReg (XAPIC_ICR_HIGH_OFFSET, IcrHigh);\r
+\r
+  SetInterruptState (InterruptState);\r
 }\r
 \r
 //\r
@@ -126,18 +244,23 @@ GetApicMode (
   VOID\r
   )\r
 {\r
-  DEBUG_CODE (\r
-    {\r
-      MSR_IA32_APIC_BASE ApicBaseMsr;\r
-\r
-      ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE_ADDRESS);\r
+  DEBUG_CODE_BEGIN ();\r
+  {\r
+    MSR_IA32_APIC_BASE_REGISTER  ApicBaseMsr;\r
+\r
+    //\r
+    // Check to see if the CPU supports the APIC Base Address MSR\r
+    //\r
+    if (LocalApicBaseAddressMsrSupported ()) {\r
+      ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);\r
       //\r
       // Local APIC should have been enabled\r
       //\r
-      ASSERT (ApicBaseMsr.Bits.En != 0);\r
-      ASSERT (ApicBaseMsr.Bits.Extd == 0);\r
+      ASSERT (ApicBaseMsr.Bits.EN != 0);\r
+      ASSERT (ApicBaseMsr.Bits.EXTD == 0);\r
     }\r
-  );\r
+  }\r
+  DEBUG_CODE_END ();\r
   return LOCAL_APIC_MODE_XAPIC;\r
 }\r
 \r
@@ -148,6 +271,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
@@ -162,8 +288,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
@@ -174,10 +300,30 @@ GetInitialApicId (
   VOID\r
   )\r
 {\r
-  UINT32 RegEbx;\r
+  UINT32  ApicId;\r
+  UINT32  MaxCpuIdIndex;\r
+  UINT32  RegEbx;\r
 \r
   ASSERT (GetApicMode () == LOCAL_APIC_MODE_XAPIC);\r
 \r
+  //\r
+  // Get the max index of basic CPUID\r
+  //\r
+  AsmCpuid (CPUID_SIGNATURE, &MaxCpuIdIndex, NULL, NULL, NULL);\r
+\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
 }\r
@@ -193,12 +339,19 @@ GetApicId (
   VOID\r
   )\r
 {\r
-  UINT32 ApicId;\r
+  UINT32  ApicId;\r
 \r
   ASSERT (GetApicMode () == LOCAL_APIC_MODE_XAPIC);\r
 \r
-  ApicId = ReadLocalApicReg (XAPIC_ID_OFFSET);\r
-  ApicId >>= 24;\r
+  if ((ApicId = GetInitialApicId ()) < 0x100) {\r
+    //\r
+    // If the initial local APIC ID is less 0x100, read APIC ID from\r
+    // XAPIC_ID_OFFSET, otherwise return the initial local APIC ID.\r
+    //\r
+    ApicId   = ReadLocalApicReg (XAPIC_ID_OFFSET);\r
+    ApicId >>= 24;\r
+  }\r
+\r
   return ApicId;\r
 }\r
 \r
@@ -219,7 +372,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
@@ -227,67 +380,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
@@ -295,11 +448,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
@@ -307,28 +460,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
@@ -336,11 +489,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
@@ -348,7 +501,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
@@ -360,30 +513,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
@@ -394,24 +549,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
@@ -428,13 +618,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
@@ -442,21 +632,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
@@ -471,13 +661,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
@@ -524,23 +714,20 @@ 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
+  InitializeLocalApicSoftwareEnable (TRUE);\r
 \r
   //\r
   // Program init-count register.\r
@@ -549,13 +736,13 @@ InitializeApicTimer (
 \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
@@ -567,7 +754,8 @@ 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
@@ -575,6 +763,8 @@ InitializeApicTimer (
 /**\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
@@ -587,18 +777,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
@@ -607,8 +804,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
@@ -622,9 +820,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
@@ -638,9 +836,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
@@ -657,7 +855,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
@@ -676,13 +874,13 @@ SendApicEoi (
 }\r
 \r
 /**\r
-  Get the 32-bit address that a device should use to send a Message Signaled \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
+EFIAPI\r
 GetApicMsiAddress (\r
   VOID\r
   )\r
@@ -690,7 +888,7 @@ GetApicMsiAddress (
   LOCAL_APIC_MSI_ADDRESS  MsiAddress;\r
 \r
   //\r
-  // Return address for an MSI interrupt to be delivered only to the APIC ID \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
@@ -698,17 +896,17 @@ GetApicMsiAddress (
   MsiAddress.Bits.DestinationId = GetApicId ();\r
   return MsiAddress.Uint32;\r
 }\r
-    \r
+\r
 /**\r
-  Get the 64-bit data value that a device should use to send a Message Signaled \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
+\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
+  @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
@@ -716,19 +914,19 @@ GetApicMsiAddress (
                             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
+\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
+                          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
+                          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
+EFIAPI\r
 GetApicMsiValue (\r
   IN UINT8    Vector,\r
   IN UINTN    DeliveryMode,\r
@@ -740,7 +938,7 @@ GetApicMsiValue (
 \r
   ASSERT (Vector >= 0x10 && Vector <= 0xFE);\r
   ASSERT (DeliveryMode < 8 && DeliveryMode != 6 && DeliveryMode != 3);\r
-  \r
+\r
   MsiData.Uint64            = 0;\r
   MsiData.Bits.Vector       = Vector;\r
   MsiData.Bits.DeliveryMode = (UINT32)DeliveryMode;\r
@@ -750,5 +948,322 @@ GetApicMsiValue (
       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