]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiCpuPkg/Library/MpInitLib/MpLib.c
UefiCpuPkg/MpInitLib: Remove redundant CpuStateFinished State.
[mirror_edk2.git] / UefiCpuPkg / Library / MpInitLib / MpLib.c
index f8ab5f115dc4938b870e2727a91722e2b4bdb134..ff09a0e9e7e843f2332a0d78fb7b24a138414ee5 100644 (file)
@@ -410,7 +410,7 @@ ApInitializeSync (
   //\r
   // Load microcode on AP\r
   //\r
-  MicrocodeDetect (CpuMpData);\r
+  MicrocodeDetect (CpuMpData, FALSE);\r
   //\r
   // Sync BSP's MTRR table to AP\r
   //\r
@@ -435,16 +435,19 @@ GetProcessorNumber (
   UINTN                   TotalProcessorNumber;\r
   UINTN                   Index;\r
   CPU_INFO_IN_HOB         *CpuInfoInHob;\r
+  UINT32                  CurrentApicId;\r
 \r
   CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob;\r
 \r
   TotalProcessorNumber = CpuMpData->CpuCount;\r
+  CurrentApicId = GetApicId ();\r
   for (Index = 0; Index < TotalProcessorNumber; Index ++) {\r
-    if (CpuInfoInHob[Index].ApicId == GetApicId ()) {\r
+    if (CpuInfoInHob[Index].ApicId == CurrentApicId) {\r
       *ProcessorNumber = Index;\r
       return EFI_SUCCESS;\r
     }\r
   }\r
+\r
   return EFI_NOT_FOUND;\r
 }\r
 \r
@@ -615,7 +618,9 @@ ApWakeupFunction (
       //\r
       ApInitializeSync (CpuMpData);\r
       //\r
-      // Sync BSP's Control registers to APs\r
+      // CpuMpData->CpuData[0].VolatileRegisters is initialized based on BSP environment,\r
+      //   to initialize AP in InitConfig path.\r
+      // NOTE: IDTR.BASE stored in CpuMpData->CpuData[0].VolatileRegisters points to a different IDT shared by all APs.\r
       //\r
       RestoreVolatileRegisters (&CpuMpData->CpuData[0].VolatileRegisters, FALSE);\r
       InitializeApData (CpuMpData, ProcessorNumber, BistData, ApTopOfStack);\r
@@ -639,6 +644,13 @@ ApWakeupFunction (
         // Restore AP's volatile registers saved\r
         //\r
         RestoreVolatileRegisters (&CpuMpData->CpuData[ProcessorNumber].VolatileRegisters, TRUE);\r
+      } else {\r
+        //\r
+        // The CPU driver might not flush TLB for APs on spot after updating\r
+        // page attributes. AP in mwait loop mode needs to take care of it when\r
+        // woken up.\r
+        //\r
+        CpuFlushTlb ();\r
       }\r
 \r
       if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) == CpuStateReady) {\r
@@ -648,7 +660,7 @@ ApWakeupFunction (
           SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateBusy);\r
           //\r
           // Enable source debugging on AP function\r
-          //         \r
+          //\r
           EnableDebugAgent ();\r
           //\r
           // Invoke AP function here\r
@@ -684,7 +696,7 @@ ApWakeupFunction (
             }\r
           }\r
         }\r
-        SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateFinished);\r
+        SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateIdle);\r
       }\r
     }\r
 \r
@@ -976,13 +988,15 @@ WakeUpAP (
   CpuMpData->FinishedCount = 0;\r
   ResetVectorRequired = FALSE;\r
 \r
-  if (CpuMpData->ApLoopMode == ApInHltLoop ||\r
+  if (CpuMpData->WakeUpByInitSipiSipi ||\r
       CpuMpData->InitFlag   != ApInitDone) {\r
     ResetVectorRequired = TRUE;\r
     AllocateResetVector (CpuMpData);\r
     FillExchangeInfoData (CpuMpData);\r
     SaveLocalApicTimerSetting (CpuMpData);\r
-  } else if (CpuMpData->ApLoopMode == ApInMwaitLoop) {\r
+  }\r
+\r
+  if (CpuMpData->ApLoopMode == ApInMwaitLoop) {\r
     //\r
     // Get AP target C-state each time when waking up AP,\r
     // for it maybe updated by platform again\r
@@ -1067,6 +1081,13 @@ WakeUpAP (
   if (ResetVectorRequired) {\r
     FreeResetVector (CpuMpData);\r
   }\r
+\r
+  //\r
+  // After one round of Wakeup Ap actions, need to re-sync ApLoopMode with\r
+  // WakeUpByInitSipiSipi flag. WakeUpByInitSipiSipi flag maybe changed by\r
+  // S3SmmInitDone Ppi.\r
+  //\r
+  CpuMpData->WakeUpByInitSipiSipi = (CpuMpData->ApLoopMode == ApInHltLoop);\r
 }\r
 \r
 /**\r
@@ -1108,7 +1129,7 @@ CalculateTimeout (
 \r
   //\r
   // GetPerformanceCounterProperties () returns the timestamp counter's frequency\r
-  // in Hz. \r
+  // in Hz.\r
   //\r
   TimestampCounterFreq = GetPerformanceCounterProperties (NULL, NULL);\r
 \r
@@ -1331,18 +1352,17 @@ CheckThisAP (
   CpuData   = &CpuMpData->CpuData[ProcessorNumber];\r
 \r
   //\r
-  //  Check the CPU state of AP. If it is CpuStateFinished, then the AP has finished its task.\r
+  //  Check the CPU state of AP. If it is CpuStateIdle, then the AP has finished its task.\r
   //  Only BSP and corresponding AP access this unit of CPU Data. This means the AP will not modify the\r
-  //  value of state after setting the it to CpuStateFinished, so BSP can safely make use of its value.\r
+  //  value of state after setting the it to CpuStateIdle, so BSP can safely make use of its value.\r
   //\r
   //\r
   // If the AP finishes for StartupThisAP(), return EFI_SUCCESS.\r
   //\r
-  if (GetApState(CpuData) == CpuStateFinished) {\r
+  if (GetApState(CpuData) == CpuStateIdle) {\r
     if (CpuData->Finished != NULL) {\r
       *(CpuData->Finished) = TRUE;\r
     }\r
-    SetApState (CpuData, CpuStateIdle);\r
     return EFI_SUCCESS;\r
   } else {\r
     //\r
@@ -1399,14 +1419,13 @@ CheckAllAPs (
 \r
     CpuData = &CpuMpData->CpuData[ProcessorNumber];\r
     //\r
-    // Check the CPU state of AP. If it is CpuStateFinished, then the AP has finished its task.\r
+    // Check the CPU state of AP. If it is CpuStateIdle, then the AP has finished its task.\r
     // Only BSP and corresponding AP access this unit of CPU Data. This means the AP will not modify the\r
-    // value of state after setting the it to CpuStateFinished, so BSP can safely make use of its value.\r
+    // value of state after setting the it to CpuStateIdle, so BSP can safely make use of its value.\r
     //\r
-    if (GetApState(CpuData) == CpuStateFinished) {\r
+    if (GetApState(CpuData) == CpuStateIdle) {\r
       CpuMpData->RunningCount ++;\r
       CpuMpData->CpuData[ProcessorNumber].Waiting = FALSE;\r
-      SetApState(CpuData, CpuStateIdle);\r
 \r
       //\r
       // If in Single Thread mode, then search for the next waiting AP for execution.\r
@@ -1499,6 +1518,7 @@ MpInitLibInitialize (
   UINT32                   MaxLogicalProcessorNumber;\r
   UINT32                   ApStackSize;\r
   MP_ASSEMBLY_ADDRESS_MAP  AddressMap;\r
+  CPU_VOLATILE_REGISTERS   VolatileRegisters;\r
   UINTN                    BufferSize;\r
   UINT32                   MonitorFilterSize;\r
   VOID                     *MpBuffer;\r
@@ -1509,6 +1529,8 @@ MpInitLibInitialize (
   UINTN                    Index;\r
   UINTN                    ApResetVectorSize;\r
   UINTN                    BackupBufferAddr;\r
+  UINTN                    ApIdtBase;\r
+  VOID                     *MicrocodePatchInRam;\r
 \r
   OldCpuMpData = GetCpuMpDataFromGuidedHob ();\r
   if (OldCpuMpData == NULL) {\r
@@ -1523,19 +1545,48 @@ MpInitLibInitialize (
   ApStackSize = PcdGet32(PcdCpuApStackSize);\r
   ApLoopMode  = GetApLoopMode (&MonitorFilterSize);\r
 \r
+  //\r
+  // Save BSP's Control registers for APs\r
+  //\r
+  SaveVolatileRegisters (&VolatileRegisters);\r
+\r
   BufferSize  = ApStackSize * MaxLogicalProcessorNumber;\r
   BufferSize += MonitorFilterSize * MaxLogicalProcessorNumber;\r
-  BufferSize += sizeof (CPU_MP_DATA);\r
   BufferSize += ApResetVectorSize;\r
+  BufferSize  = ALIGN_VALUE (BufferSize, 8);\r
+  BufferSize += VolatileRegisters.Idtr.Limit + 1;\r
+  BufferSize += sizeof (CPU_MP_DATA);\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
+  //\r
+  //  The layout of the Buffer is as below:\r
+  //\r
+  //    +--------------------+ <-- Buffer\r
+  //        AP Stacks (N)\r
+  //    +--------------------+ <-- MonitorBuffer\r
+  //    AP Monitor Filters (N)\r
+  //    +--------------------+ <-- BackupBufferAddr (CpuMpData->BackupBuffer)\r
+  //         Backup Buffer\r
+  //    +--------------------+\r
+  //           Padding\r
+  //    +--------------------+ <-- ApIdtBase (8-byte boundary)\r
+  //           AP IDT          All APs share one separate IDT. So AP can get address of CPU_MP_DATA from IDT Base.\r
+  //    +--------------------+ <-- CpuMpData\r
+  //         CPU_MP_DATA\r
+  //    +--------------------+ <-- CpuMpData->CpuData\r
+  //        CPU_AP_DATA (N)\r
+  //    +--------------------+ <-- CpuMpData->CpuInfoInHob\r
+  //      CPU_INFO_IN_HOB (N)\r
+  //    +--------------------+\r
+  //\r
   MonitorBuffer    = (UINT8 *) (Buffer + ApStackSize * MaxLogicalProcessorNumber);\r
   BackupBufferAddr = (UINTN) MonitorBuffer + MonitorFilterSize * MaxLogicalProcessorNumber;\r
-  CpuMpData = (CPU_MP_DATA *) (BackupBufferAddr + ApResetVectorSize);\r
+  ApIdtBase        = ALIGN_VALUE (BackupBufferAddr + ApResetVectorSize, 8);\r
+  CpuMpData        = (CPU_MP_DATA *) (ApIdtBase + VolatileRegisters.Idtr.Limit + 1);\r
   CpuMpData->Buffer           = Buffer;\r
   CpuMpData->CpuApStackSize   = ApStackSize;\r
   CpuMpData->BackupBuffer     = BackupBufferAddr;\r
@@ -1547,13 +1598,53 @@ MpInitLibInitialize (
   CpuMpData->SwitchBspFlag    = FALSE;\r
   CpuMpData->CpuData          = (CPU_AP_DATA *) (CpuMpData + 1);\r
   CpuMpData->CpuInfoInHob     = (UINT64) (UINTN) (CpuMpData->CpuData + MaxLogicalProcessorNumber);\r
-  CpuMpData->MicrocodePatchAddress    = PcdGet64 (PcdCpuMicrocodePatchAddress);\r
   CpuMpData->MicrocodePatchRegionSize = PcdGet64 (PcdCpuMicrocodePatchRegionSize);\r
+  //\r
+  // If platform has more than one CPU, relocate microcode to memory to reduce\r
+  // loading microcode time.\r
+  //\r
+  MicrocodePatchInRam = NULL;\r
+  if (MaxLogicalProcessorNumber > 1) {\r
+    MicrocodePatchInRam = AllocatePages (\r
+                            EFI_SIZE_TO_PAGES (\r
+                              (UINTN)CpuMpData->MicrocodePatchRegionSize\r
+                              )\r
+                            );\r
+  }\r
+  if (MicrocodePatchInRam == NULL) {\r
+    //\r
+    // there is only one processor, or no microcode patch is available, or\r
+    // memory allocation failed\r
+    //\r
+    CpuMpData->MicrocodePatchAddress = PcdGet64 (PcdCpuMicrocodePatchAddress);\r
+  } else {\r
+    //\r
+    // there are multiple processors, and a microcode patch is available, and\r
+    // memory allocation succeeded\r
+    //\r
+    CopyMem (\r
+      MicrocodePatchInRam,\r
+      (VOID *)(UINTN)PcdGet64 (PcdCpuMicrocodePatchAddress),\r
+      (UINTN)CpuMpData->MicrocodePatchRegionSize\r
+      );\r
+    CpuMpData->MicrocodePatchAddress = (UINTN)MicrocodePatchInRam;\r
+  }\r
+\r
   InitializeSpinLock(&CpuMpData->MpLock);\r
+\r
   //\r
-  // Save BSP's Control registers to APs\r
+  // Make sure no memory usage outside of the allocated buffer.\r
+  //\r
+  ASSERT ((CpuMpData->CpuInfoInHob + sizeof (CPU_INFO_IN_HOB) * MaxLogicalProcessorNumber) ==\r
+          Buffer + BufferSize);\r
+\r
   //\r
-  SaveVolatileRegisters (&CpuMpData->CpuData[0].VolatileRegisters);\r
+  // Duplicate BSP's IDT to APs.\r
+  // All APs share one separate IDT. So AP can get the address of CpuMpData by using IDTR.BASE + IDTR.LIMIT + 1\r
+  //\r
+  CopyMem ((VOID *)ApIdtBase, (VOID *)VolatileRegisters.Idtr.Base, VolatileRegisters.Idtr.Limit + 1);\r
+  VolatileRegisters.Idtr.Base = ApIdtBase;\r
+  CopyMem (&CpuMpData->CpuData[0].VolatileRegisters, &VolatileRegisters, sizeof (VolatileRegisters));\r
   //\r
   // Set BSP basic information\r
   //\r
@@ -1567,6 +1658,9 @@ MpInitLibInitialize (
   //\r
   CpuMpData->ApLoopMode = ApLoopMode;\r
   DEBUG ((DEBUG_INFO, "AP Loop Mode is %d\n", CpuMpData->ApLoopMode));\r
+\r
+  CpuMpData->WakeUpByInitSipiSipi = (CpuMpData->ApLoopMode == ApInHltLoop);\r
+\r
   //\r
   // Set up APs wakeup signal buffer\r
   //\r
@@ -1577,7 +1671,7 @@ MpInitLibInitialize (
   //\r
   // Load Microcode on BSP\r
   //\r
-  MicrocodeDetect (CpuMpData);\r
+  MicrocodeDetect (CpuMpData, TRUE);\r
   //\r
   // Store BSP's MTRR setting\r
   //\r
@@ -1611,11 +1705,7 @@ MpInitLibInitialize (
       }\r
       CpuMpData->CpuData[Index].CpuHealthy = (CpuInfoInHob[Index].Health == 0)? TRUE:FALSE;\r
       CpuMpData->CpuData[Index].ApFunction = 0;\r
-      CopyMem (\r
-        &CpuMpData->CpuData[Index].VolatileRegisters,\r
-        &CpuMpData->CpuData[0].VolatileRegisters,\r
-        sizeof (CPU_VOLATILE_REGISTERS)\r
-        );\r
+      CopyMem (&CpuMpData->CpuData[Index].VolatileRegisters, &VolatileRegisters, sizeof (CPU_VOLATILE_REGISTERS));\r
     }\r
     if (MaxLogicalProcessorNumber > 1) {\r
       //\r
@@ -1730,7 +1820,7 @@ MpInitLibGetProcessorInfo (
                                enabled AP. Otherwise, it will be disabled.\r
 \r
   @retval EFI_SUCCESS          BSP successfully switched.\r
-  @retval others               Failed to switch BSP. \r
+  @retval others               Failed to switch BSP.\r
 \r
 **/\r
 EFI_STATUS\r
@@ -1831,7 +1921,7 @@ SwitchBSPWorker (
   //\r
   // Wait for old BSP finished AP task\r
   //\r
-  while (GetApState (&CpuMpData->CpuData[CallerNumber]) != CpuStateFinished) {\r
+  while (GetApState (&CpuMpData->CpuData[CallerNumber]) != CpuStateIdle) {\r
     CpuPause ();\r
   }\r
 \r