]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiCpuPkg/Library/MpInitLib/MpLib.c
UefiCpuPkg/MpInitLib: Add MicrocodeDetect() and load microcode on BSP
[mirror_edk2.git] / UefiCpuPkg / Library / MpInitLib / MpLib.c
index 3ac79b6a9031b9bbf8e8f7569dbc952d59fc0687..7384f5d0d2b6086528f064806286a9cc9a9de717 100644 (file)
 \r
 #include "MpLib.h"\r
 \r
+/**\r
+  Get the Application Processors state.\r
+\r
+  @param[in]  CpuData    The pointer to CPU_AP_DATA of specified AP\r
+\r
+  @return  The AP status\r
+**/\r
+CPU_STATE\r
+GetApState (\r
+  IN  CPU_AP_DATA     *CpuData\r
+  )\r
+{\r
+  return CpuData->State;\r
+}\r
+\r
+/**\r
+  Set the Application Processors state.\r
+\r
+  @param[in]   CpuData    The pointer to CPU_AP_DATA of specified AP\r
+  @param[in]   State      The AP status\r
+**/\r
+VOID\r
+SetApState (\r
+  IN  CPU_AP_DATA     *CpuData,\r
+  IN  CPU_STATE       State\r
+  )\r
+{\r
+  AcquireSpinLock (&CpuData->ApLock);\r
+  CpuData->State = State;\r
+  ReleaseSpinLock (&CpuData->ApLock);\r
+}\r
+\r
+/**\r
+  Save the volatile registers required to be restored following INIT IPI.\r
+\r
+  @param[out]  VolatileRegisters    Returns buffer saved the volatile resisters\r
+**/\r
+VOID\r
+SaveVolatileRegisters (\r
+  OUT CPU_VOLATILE_REGISTERS    *VolatileRegisters\r
+  )\r
+{\r
+  CPUID_VERSION_INFO_EDX        VersionInfoEdx;\r
+\r
+  VolatileRegisters->Cr0 = AsmReadCr0 ();\r
+  VolatileRegisters->Cr3 = AsmReadCr3 ();\r
+  VolatileRegisters->Cr4 = AsmReadCr4 ();\r
+\r
+  AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &VersionInfoEdx.Uint32);\r
+  if (VersionInfoEdx.Bits.DE != 0) {\r
+    //\r
+    // If processor supports Debugging Extensions feature\r
+    // by CPUID.[EAX=01H]:EDX.BIT2\r
+    //\r
+    VolatileRegisters->Dr0 = AsmReadDr0 ();\r
+    VolatileRegisters->Dr1 = AsmReadDr1 ();\r
+    VolatileRegisters->Dr2 = AsmReadDr2 ();\r
+    VolatileRegisters->Dr3 = AsmReadDr3 ();\r
+    VolatileRegisters->Dr6 = AsmReadDr6 ();\r
+    VolatileRegisters->Dr7 = AsmReadDr7 ();\r
+  }\r
+}\r
+\r
+/**\r
+  Restore the volatile registers following INIT IPI.\r
+\r
+  @param[in]  VolatileRegisters   Pointer to volatile resisters\r
+  @param[in]  IsRestoreDr         TRUE:  Restore DRx if supported\r
+                                  FALSE: Do not restore DRx\r
+**/\r
+VOID\r
+RestoreVolatileRegisters (\r
+  IN CPU_VOLATILE_REGISTERS    *VolatileRegisters,\r
+  IN BOOLEAN                   IsRestoreDr\r
+  )\r
+{\r
+  CPUID_VERSION_INFO_EDX        VersionInfoEdx;\r
+\r
+  AsmWriteCr0 (VolatileRegisters->Cr0);\r
+  AsmWriteCr3 (VolatileRegisters->Cr3);\r
+  AsmWriteCr4 (VolatileRegisters->Cr4);\r
+\r
+  if (IsRestoreDr) {\r
+    AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &VersionInfoEdx.Uint32);\r
+    if (VersionInfoEdx.Bits.DE != 0) {\r
+      //\r
+      // If processor supports Debugging Extensions feature\r
+      // by CPUID.[EAX=01H]:EDX.BIT2\r
+      //\r
+      AsmWriteDr0 (VolatileRegisters->Dr0);\r
+      AsmWriteDr1 (VolatileRegisters->Dr1);\r
+      AsmWriteDr2 (VolatileRegisters->Dr2);\r
+      AsmWriteDr3 (VolatileRegisters->Dr3);\r
+      AsmWriteDr6 (VolatileRegisters->Dr6);\r
+      AsmWriteDr7 (VolatileRegisters->Dr7);\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  Detect whether Mwait-monitor feature is supported.\r
+\r
+  @retval TRUE    Mwait-monitor feature is supported.\r
+  @retval FALSE   Mwait-monitor feature is not supported.\r
+**/\r
+BOOLEAN\r
+IsMwaitSupport (\r
+  VOID\r
+  )\r
+{\r
+  CPUID_VERSION_INFO_ECX        VersionInfoEcx;\r
+\r
+  AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, &VersionInfoEcx.Uint32, NULL);\r
+  return (VersionInfoEcx.Bits.MONITOR == 1) ? TRUE : FALSE;\r
+}\r
+\r
+/**\r
+  Get AP loop mode.\r
+\r
+  @param[out] MonitorFilterSize  Returns the largest monitor-line size in bytes.\r
+\r
+  @return The AP loop mode.\r
+**/\r
+UINT8\r
+GetApLoopMode (\r
+  OUT UINT32     *MonitorFilterSize\r
+  )\r
+{\r
+  UINT8                         ApLoopMode;\r
+  CPUID_MONITOR_MWAIT_EBX       MonitorMwaitEbx;\r
+\r
+  ASSERT (MonitorFilterSize != NULL);\r
+\r
+  ApLoopMode = PcdGet8 (PcdCpuApLoopMode);\r
+  ASSERT (ApLoopMode >= ApInHltLoop && ApLoopMode <= ApInRunLoop);\r
+  if (ApLoopMode == ApInMwaitLoop) {\r
+    if (!IsMwaitSupport ()) {\r
+      //\r
+      // If processor does not support MONITOR/MWAIT feature,\r
+      // force AP in Hlt-loop mode\r
+      //\r
+      ApLoopMode = ApInHltLoop;\r
+    }\r
+  }\r
+\r
+  if (ApLoopMode != ApInMwaitLoop) {\r
+    *MonitorFilterSize = sizeof (UINT32);\r
+  } else {\r
+    //\r
+    // CPUID.[EAX=05H]:EBX.BIT0-15: Largest monitor-line size in bytes\r
+    // CPUID.[EAX=05H].EDX: C-states supported using MWAIT\r
+    //\r
+    AsmCpuid (CPUID_MONITOR_MWAIT, NULL, &MonitorMwaitEbx.Uint32, NULL, NULL);\r
+    *MonitorFilterSize = MonitorMwaitEbx.Bits.LargestMonitorLineSize;\r
+  }\r
+\r
+  return ApLoopMode;\r
+}\r
+/*\r
+  Initialize CPU AP Data when AP is wakeup at the first time.\r
+\r
+  @param[in, out] CpuMpData        Pointer to PEI CPU MP Data\r
+  @param[in]      ProcessorNumber  The handle number of processor\r
+  @param[in]      BistData         Processor BIST data\r
+\r
+**/\r
+VOID\r
+InitializeApData (\r
+  IN OUT CPU_MP_DATA      *CpuMpData,\r
+  IN     UINTN            ProcessorNumber,\r
+  IN     UINT32           BistData\r
+  )\r
+{\r
+  CpuMpData->CpuData[ProcessorNumber].Waiting    = FALSE;\r
+  CpuMpData->CpuData[ProcessorNumber].Health     = BistData;\r
+  CpuMpData->CpuData[ProcessorNumber].CpuHealthy = (BistData == 0) ? TRUE : FALSE;\r
+  CpuMpData->CpuData[ProcessorNumber].ApicId     = GetApicId ();\r
+  CpuMpData->CpuData[ProcessorNumber].InitialApicId = GetInitialApicId ();\r
+  if (CpuMpData->CpuData[ProcessorNumber].InitialApicId >= 0xFF) {\r
+    //\r
+    // Set x2APIC mode if there are any logical processor reporting\r
+    // an Initial APIC ID of 255 or greater.\r
+    //\r
+    AcquireSpinLock(&CpuMpData->MpLock);\r
+    CpuMpData->X2ApicEnable = TRUE;\r
+    ReleaseSpinLock(&CpuMpData->MpLock);\r
+  }\r
+\r
+  InitializeSpinLock(&CpuMpData->CpuData[ProcessorNumber].ApLock);\r
+  SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateIdle);\r
+}\r
 \r
 /**\r
   MP Initialize Library initialization.\r
@@ -34,11 +225,84 @@ MpInitLibInitialize (
   VOID\r
   )\r
 {\r
+  UINT32                   MaxLogicalProcessorNumber;\r
+  UINT32                   ApStackSize;\r
   MP_ASSEMBLY_ADDRESS_MAP  AddressMap;\r
+  UINTN                    BufferSize;\r
+  UINT32                   MonitorFilterSize;\r
+  VOID                     *MpBuffer;\r
+  UINTN                    Buffer;\r
+  CPU_MP_DATA              *CpuMpData;\r
+  UINT8                    ApLoopMode;\r
+  UINT8                    *MonitorBuffer;\r
+  UINTN                    Index;\r
   UINTN                    ApResetVectorSize;\r
+  UINTN                    BackupBufferAddr;\r
+  MaxLogicalProcessorNumber = PcdGet32(PcdCpuMaxLogicalProcessorNumber);\r
 \r
   AsmGetAddressMap (&AddressMap);\r
   ApResetVectorSize = AddressMap.RendezvousFunnelSize + sizeof (MP_CPU_EXCHANGE_INFO);\r
+  ApStackSize = PcdGet32(PcdCpuApStackSize);\r
+  ApLoopMode  = GetApLoopMode (&MonitorFilterSize);\r
+\r
+  BufferSize  = ApStackSize * MaxLogicalProcessorNumber;\r
+  BufferSize += MonitorFilterSize * MaxLogicalProcessorNumber;\r
+  BufferSize += sizeof (CPU_MP_DATA);\r
+  BufferSize += ApResetVectorSize;\r
+  BufferSize += (sizeof (CPU_AP_DATA) + sizeof (CPU_INFO_IN_HOB))* MaxLogicalProcessorNumber;\r
+  MpBuffer    = AllocatePages (EFI_SIZE_TO_PAGES (BufferSize));\r
+  ASSERT (MpBuffer != NULL);\r
+  ZeroMem (MpBuffer, BufferSize);\r
+  Buffer = (UINTN) MpBuffer;\r
+\r
+  MonitorBuffer    = (UINT8 *) (Buffer + ApStackSize * MaxLogicalProcessorNumber);\r
+  BackupBufferAddr = (UINTN) MonitorBuffer + MonitorFilterSize * MaxLogicalProcessorNumber;\r
+  CpuMpData = (CPU_MP_DATA *) (BackupBufferAddr + ApResetVectorSize);\r
+  CpuMpData->Buffer           = Buffer;\r
+  CpuMpData->CpuApStackSize   = ApStackSize;\r
+  CpuMpData->BackupBuffer     = BackupBufferAddr;\r
+  CpuMpData->BackupBufferSize = ApResetVectorSize;\r
+  CpuMpData->EndOfPeiFlag     = FALSE;\r
+  CpuMpData->WakeupBuffer     = (UINTN) -1;\r
+  CpuMpData->CpuCount         = 1;\r
+  CpuMpData->BspNumber        = 0;\r
+  CpuMpData->WaitEvent        = NULL;\r
+  CpuMpData->CpuData          = (CPU_AP_DATA *) (CpuMpData + 1);\r
+  CpuMpData->CpuInfoInHob     = (UINT64) (UINTN) (CpuMpData->CpuData + MaxLogicalProcessorNumber);\r
+  InitializeSpinLock(&CpuMpData->MpLock);\r
+  //\r
+  // Save BSP's Control registers to APs\r
+  //\r
+  SaveVolatileRegisters (&CpuMpData->CpuData[0].VolatileRegisters);\r
+  //\r
+  // Set BSP basic information\r
+  //\r
+  InitializeApData (CpuMpData, 0, 0);\r
+  //\r
+  // Save assembly code information\r
+  //\r
+  CopyMem (&CpuMpData->AddressMap, &AddressMap, sizeof (MP_ASSEMBLY_ADDRESS_MAP));\r
+  //\r
+  // Finally set AP loop mode\r
+  //\r
+  CpuMpData->ApLoopMode = ApLoopMode;\r
+  DEBUG ((DEBUG_INFO, "AP Loop Mode is %d\n", CpuMpData->ApLoopMode));\r
+  //\r
+  // Set up APs wakeup signal buffer\r
+  //\r
+  for (Index = 0; Index < MaxLogicalProcessorNumber; Index++) {\r
+    CpuMpData->CpuData[Index].StartupApSignal =\r
+      (UINT32 *)(MonitorBuffer + MonitorFilterSize * Index);\r
+  }\r
+  //\r
+  // Load Microcode on BSP\r
+  //\r
+  MicrocodeDetect (CpuMpData);\r
+  //\r
+  // Store BSP's MTRR setting\r
+  //\r
+  MtrrGetAllMtrrs (&CpuMpData->MtrrTable);\r
+\r
   return EFI_SUCCESS;\r
 }\r
 \r