]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c
StandaloneMmPkg: Apply uncrustify changes
[mirror_edk2.git] / UefiCpuPkg / Library / BaseXApicX2ApicLib / BaseXApicX2ApicLib.c
index 62201cd2404128dab76adc968e430a3af7650617..cdcbca04619119a2b0012e347647acd1ec65f6cd 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 - 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/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
+  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 of 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
@@ -52,7 +140,7 @@ ReadLocalApicReg (
   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
@@ -95,7 +183,7 @@ WriteLocalApicReg (
   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
@@ -121,7 +209,7 @@ WriteLocalApicReg (
 /**\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
@@ -134,21 +222,59 @@ SendIpi (
 {\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
+\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
@@ -174,14 +300,21 @@ GetApicMode (
   VOID\r
   )\r
 {\r
-  MSR_IA32_APIC_BASE ApicBaseMsr;\r
+  MSR_IA32_APIC_BASE_REGISTER  ApicBaseMsr;\r
 \r
-  ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE_ADDRESS);\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);\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 +328,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 +338,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 +354,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 = AsmReadMsr64 (MSR_IA32_APIC_BASE);\r
+        ApicBaseMsr.Bits.EXTD = 1;\r
+        AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);\r
         break;\r
       default:\r
         ASSERT (FALSE);\r
@@ -225,12 +368,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 +386,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 +398,27 @@ GetInitialApicId (
   VOID\r
   )\r
 {\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
     AsmCpuid (CPUID_VERSION_INFO, NULL, &RegEbx, NULL, NULL);\r
     return RegEbx >> 24;\r
   } else {\r
@@ -277,11 +438,13 @@ GetApicId (
   )\r
 {\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 +465,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
@@ -326,7 +489,7 @@ SendFixedIpi (
 /**\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
@@ -349,7 +512,7 @@ SendFixedIpiAllExcludingSelf (
 /**\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
@@ -370,7 +533,7 @@ SendSmiIpi (
 /**\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
@@ -390,7 +553,7 @@ 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
@@ -411,7 +574,7 @@ SendInitIpi (
 /**\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
@@ -431,7 +594,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
@@ -453,20 +616,22 @@ SendInitSipiSipi (
   ASSERT ((StartupRoutine & 0xfff) == 0);\r
 \r
   SendInitIpi (ApicId);\r
-  MicroSecondDelay (10);\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
-  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
@@ -486,15 +651,50 @@ SendInitSipiSipiAllExcludingSelf (
   ASSERT ((StartupRoutine & 0xfff) == 0);\r
 \r
   SendInitIpiAllExcludingSelf ();\r
-  MicroSecondDelay (10);\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
@@ -613,7 +813,6 @@ InitializeApicTimer (
   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
@@ -621,9 +820,7 @@ InitializeApicTimer (
   //\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
@@ -638,7 +835,7 @@ InitializeApicTimer (
     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
@@ -658,6 +855,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
@@ -674,6 +873,13 @@ GetApicTimerState (
   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
@@ -759,13 +965,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
@@ -773,7 +979,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
@@ -781,17 +987,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
@@ -799,19 +1005,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
@@ -823,7 +1029,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
@@ -835,3 +1041,309 @@ GetApicMsiValue (
   }\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
+    if (Core != NULL) {\r
+      *Core = 0;\r
+    }\r
+    if (Package != NULL) {\r
+      *Package = 0;\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
+        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
+    }\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
+  if (Core != NULL) {\r
+    *Core = (InitialApicId >> ThreadBits) & ((1 << CoreBits) - 1);\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
+    if (Tile != NULL) {\r
+      *Tile = 0;\r
+    }\r
+    if (Module != NULL) {\r
+      *Module = 0;\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
+    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
+    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