]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiCpuPkg/Library/MpInitLib/MpLib.c
UefiCpuPkg: Clean up source files
[mirror_edk2.git] / UefiCpuPkg / Library / MpInitLib / MpLib.c
index df19b43bc03a0ba73dc0effc5802a2279be5bf67..eb2765910ca9fbd049c3808c8b5401e8bbf37997 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   CPU MP Initialize Library common functions.\r
 \r
-  Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2016 - 2018, 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
@@ -195,6 +195,10 @@ SaveVolatileRegisters (
     VolatileRegisters->Dr6 = AsmReadDr6 ();\r
     VolatileRegisters->Dr7 = AsmReadDr7 ();\r
   }\r
+\r
+  AsmReadGdtr (&VolatileRegisters->Gdtr);\r
+  AsmReadIdtr (&VolatileRegisters->Idtr);\r
+  VolatileRegisters->Tr = AsmReadTr ();\r
 }\r
 \r
 /**\r
@@ -211,6 +215,7 @@ RestoreVolatileRegisters (
   )\r
 {\r
   CPUID_VERSION_INFO_EDX        VersionInfoEdx;\r
+  IA32_TSS_DESCRIPTOR           *Tss;\r
 \r
   AsmWriteCr0 (VolatileRegisters->Cr0);\r
   AsmWriteCr3 (VolatileRegisters->Cr3);\r
@@ -231,6 +236,18 @@ RestoreVolatileRegisters (
       AsmWriteDr7 (VolatileRegisters->Dr7);\r
     }\r
   }\r
+\r
+  AsmWriteGdtr (&VolatileRegisters->Gdtr);\r
+  AsmWriteIdtr (&VolatileRegisters->Idtr);\r
+  if (VolatileRegisters->Tr != 0 &&\r
+      VolatileRegisters->Tr < VolatileRegisters->Gdtr.Limit) {\r
+    Tss = (IA32_TSS_DESCRIPTOR *)(VolatileRegisters->Gdtr.Base +\r
+                                  VolatileRegisters->Tr);\r
+    if (Tss->Bits.P == 1) {\r
+      Tss->Bits.Type &= 0xD;  // 1101 - Clear busy bit just in case\r
+      AsmWriteTr (VolatileRegisters->Tr);\r
+    }\r
+  }\r
 }\r
 \r
 /**\r
@@ -313,6 +330,7 @@ SortApicId (
   CPU_INFO_IN_HOB   CpuInfo;\r
   UINT32            ApCount;\r
   CPU_INFO_IN_HOB   *CpuInfoInHob;\r
+  volatile UINT32   *StartupApSignal;\r
 \r
   ApCount = CpuMpData->CpuCount - 1;\r
   CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob;\r
@@ -337,6 +355,14 @@ SortApicId (
           sizeof (CPU_INFO_IN_HOB)\r
           );\r
         CopyMem (&CpuInfoInHob[Index1], &CpuInfo, sizeof (CPU_INFO_IN_HOB));\r
+\r
+        //\r
+        // Also exchange the StartupApSignal.\r
+        //\r
+        StartupApSignal = CpuMpData->CpuData[Index3].StartupApSignal;\r
+        CpuMpData->CpuData[Index3].StartupApSignal =\r
+          CpuMpData->CpuData[Index1].StartupApSignal;\r
+        CpuMpData->CpuData[Index1].StartupApSignal = StartupApSignal;\r
       }\r
     }\r
 \r
@@ -536,13 +562,13 @@ InitializeApData (
   This function will be called from AP reset code if BSP uses WakeUpAP.\r
 \r
   @param[in] ExchangeInfo     Pointer to the MP exchange info buffer\r
-  @param[in] NumApsExecuting  Number of current executing AP\r
+  @param[in] ApIndex          Number of current executing AP\r
 **/\r
 VOID\r
 EFIAPI\r
 ApWakeupFunction (\r
   IN MP_CPU_EXCHANGE_INFO      *ExchangeInfo,\r
-  IN UINTN                     NumApsExecuting\r
+  IN UINTN                     ApIndex\r
   )\r
 {\r
   CPU_MP_DATA                *CpuMpData;\r
@@ -565,6 +591,10 @@ ApWakeupFunction (
   // We need to re-initialize them at here\r
   //\r
   ProgramVirtualWireMode ();\r
+  //\r
+  // Mask the LINT0 and LINT1 so that AP doesn't enter the system timer interrupt handler.\r
+  //\r
+  DisableLvtInterrupts ();\r
   SyncLocalApicTimerSetting (CpuMpData);\r
 \r
   CurrentApicMode = GetApicMode ();\r
@@ -574,7 +604,7 @@ ApWakeupFunction (
       // Add CPU number\r
       //\r
       InterlockedIncrement ((UINT32 *) &CpuMpData->CpuCount);\r
-      ProcessorNumber = NumApsExecuting;\r
+      ProcessorNumber = ApIndex;\r
       //\r
       // This is first time AP wakeup, get BIST information from AP stack\r
       //\r
@@ -609,6 +639,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
@@ -618,7 +655,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
@@ -662,6 +699,7 @@ ApWakeupFunction (
     // AP finished executing C code\r
     //\r
     InterlockedIncrement ((UINT32 *) &CpuMpData->FinishedCount);\r
+    InterlockedDecrement ((UINT32 *) &CpuMpData->MpCpuExchangeInfo->NumApsExecuting);\r
 \r
     //\r
     // Place AP is specified loop mode\r
@@ -750,6 +788,8 @@ FillExchangeInfoData (
   )\r
 {\r
   volatile MP_CPU_EXCHANGE_INFO    *ExchangeInfo;\r
+  UINTN                            Size;\r
+  IA32_SEGMENT_DESCRIPTOR          *Selector;\r
 \r
   ExchangeInfo                  = CpuMpData->MpCpuExchangeInfo;\r
   ExchangeInfo->Lock            = 0;\r
@@ -764,6 +804,7 @@ FillExchangeInfoData (
   ExchangeInfo->Cr3             = AsmReadCr3 ();\r
 \r
   ExchangeInfo->CFunction       = (UINTN) ApWakeupFunction;\r
+  ExchangeInfo->ApIndex         = 0;\r
   ExchangeInfo->NumApsExecuting = 0;\r
   ExchangeInfo->InitFlag        = (UINTN) CpuMpData->InitFlag;\r
   ExchangeInfo->CpuInfo         = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob;\r
@@ -778,6 +819,46 @@ FillExchangeInfoData (
   //\r
   AsmReadGdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->GdtrProfile);\r
   AsmReadIdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->IdtrProfile);\r
+\r
+  //\r
+  // Find a 32-bit code segment\r
+  //\r
+  Selector = (IA32_SEGMENT_DESCRIPTOR *)ExchangeInfo->GdtrProfile.Base;\r
+  Size = ExchangeInfo->GdtrProfile.Limit + 1;\r
+  while (Size > 0) {\r
+    if (Selector->Bits.L == 0 && Selector->Bits.Type >= 8) {\r
+      ExchangeInfo->ModeTransitionSegment =\r
+        (UINT16)((UINTN)Selector - ExchangeInfo->GdtrProfile.Base);\r
+      break;\r
+    }\r
+    Selector += 1;\r
+    Size -= sizeof (IA32_SEGMENT_DESCRIPTOR);\r
+  }\r
+\r
+  //\r
+  // Copy all 32-bit code and 64-bit code into memory with type of\r
+  // EfiBootServicesCode to avoid page fault if NX memory protection is enabled.\r
+  //\r
+  if (CpuMpData->WakeupBufferHigh != 0) {\r
+    Size = CpuMpData->AddressMap.RendezvousFunnelSize -\r
+           CpuMpData->AddressMap.ModeTransitionOffset;\r
+    CopyMem (\r
+      (VOID *)CpuMpData->WakeupBufferHigh,\r
+      CpuMpData->AddressMap.RendezvousFunnelAddress +\r
+      CpuMpData->AddressMap.ModeTransitionOffset,\r
+      Size\r
+      );\r
+\r
+    ExchangeInfo->ModeTransitionMemory = (UINT32)CpuMpData->WakeupBufferHigh;\r
+  } else {\r
+    ExchangeInfo->ModeTransitionMemory = (UINT32)\r
+      (ExchangeInfo->BufferStart + CpuMpData->AddressMap.ModeTransitionOffset);\r
+  }\r
+\r
+  ExchangeInfo->ModeHighMemory = ExchangeInfo->ModeTransitionMemory +\r
+                         (UINT32)ExchangeInfo->ModeOffset -\r
+                         (UINT32)CpuMpData->AddressMap.ModeTransitionOffset;\r
+  ExchangeInfo->ModeHighSegment = (UINT16)ExchangeInfo->CodeSegment;\r
 }\r
 \r
 /**\r
@@ -795,6 +876,85 @@ TimedWaitForApFinish (
   IN UINT32                    TimeLimit\r
   );\r
 \r
+/**\r
+  Get available system memory below 1MB by specified size.\r
+\r
+  @param[in]  CpuMpData  The pointer to CPU MP Data structure.\r
+**/\r
+VOID\r
+BackupAndPrepareWakeupBuffer(\r
+  IN CPU_MP_DATA              *CpuMpData\r
+  )\r
+{\r
+  CopyMem (\r
+    (VOID *) CpuMpData->BackupBuffer,\r
+    (VOID *) CpuMpData->WakeupBuffer,\r
+    CpuMpData->BackupBufferSize\r
+    );\r
+  CopyMem (\r
+    (VOID *) CpuMpData->WakeupBuffer,\r
+    (VOID *) CpuMpData->AddressMap.RendezvousFunnelAddress,\r
+    CpuMpData->AddressMap.RendezvousFunnelSize\r
+    );\r
+}\r
+\r
+/**\r
+  Restore wakeup buffer data.\r
+\r
+  @param[in]  CpuMpData  The pointer to CPU MP Data structure.\r
+**/\r
+VOID\r
+RestoreWakeupBuffer(\r
+  IN CPU_MP_DATA              *CpuMpData\r
+  )\r
+{\r
+  CopyMem (\r
+    (VOID *) CpuMpData->WakeupBuffer,\r
+    (VOID *) CpuMpData->BackupBuffer,\r
+    CpuMpData->BackupBufferSize\r
+    );\r
+}\r
+\r
+/**\r
+  Allocate reset vector buffer.\r
+\r
+  @param[in, out]  CpuMpData  The pointer to CPU MP Data structure.\r
+**/\r
+VOID\r
+AllocateResetVector (\r
+  IN OUT CPU_MP_DATA          *CpuMpData\r
+  )\r
+{\r
+  UINTN           ApResetVectorSize;\r
+\r
+  if (CpuMpData->WakeupBuffer == (UINTN) -1) {\r
+    ApResetVectorSize = CpuMpData->AddressMap.RendezvousFunnelSize +\r
+                          sizeof (MP_CPU_EXCHANGE_INFO);\r
+\r
+    CpuMpData->WakeupBuffer      = GetWakeupBuffer (ApResetVectorSize);\r
+    CpuMpData->MpCpuExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN)\r
+                    (CpuMpData->WakeupBuffer + CpuMpData->AddressMap.RendezvousFunnelSize);\r
+    CpuMpData->WakeupBufferHigh  = GetModeTransitionBuffer (\r
+                                    CpuMpData->AddressMap.RendezvousFunnelSize -\r
+                                    CpuMpData->AddressMap.ModeTransitionOffset\r
+                                    );\r
+  }\r
+  BackupAndPrepareWakeupBuffer (CpuMpData);\r
+}\r
+\r
+/**\r
+  Free AP reset vector buffer.\r
+\r
+  @param[in]  CpuMpData  The pointer to CPU MP Data structure.\r
+**/\r
+VOID\r
+FreeResetVector (\r
+  IN CPU_MP_DATA              *CpuMpData\r
+  )\r
+{\r
+  RestoreWakeupBuffer (CpuMpData);\r
+}\r
+\r
 /**\r
   This function will be called by BSP to wakeup AP.\r
 \r
@@ -859,13 +1019,24 @@ WakeUpAP (
     }\r
     if (CpuMpData->InitFlag == ApInitConfig) {\r
       //\r
-      // Wait for all potential APs waken up in one specified period\r
+      // Here support two methods to collect AP count through adjust\r
+      // PcdCpuApInitTimeOutInMicroSeconds values.\r
+      //\r
+      // one way is set a value to just let the first AP to start the\r
+      // initialization, then through the later while loop to wait all Aps\r
+      // finsh the initialization.\r
+      // The other way is set a value to let all APs finished the initialzation.\r
+      // In this case, the later while loop is useless.\r
       //\r
       TimedWaitForApFinish (\r
         CpuMpData,\r
         PcdGet32 (PcdCpuMaxLogicalProcessorNumber) - 1,\r
         PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds)\r
         );\r
+\r
+      while (CpuMpData->MpCpuExchangeInfo->NumApsExecuting != 0) {\r
+        CpuPause();\r
+      }\r
     } else {\r
       //\r
       // Wait all APs waken up if this is not the 1st broadcast of SIPI\r
@@ -926,6 +1097,9 @@ CalculateTimeout (
   OUT UINT64  *CurrentTime\r
   )\r
 {\r
+  UINT64 TimeoutInSeconds;\r
+  UINT64 TimestampCounterFreq;\r
+\r
   //\r
   // Read the current value of the performance counter\r
   //\r
@@ -941,16 +1115,36 @@ CalculateTimeout (
 \r
   //\r
   // GetPerformanceCounterProperties () returns the timestamp counter's frequency\r
-  // in Hz. So multiply the return value with TimeoutInMicroseconds and then divide\r
-  // it by 1,000,000, to get the number of ticks for the timeout value.\r
-  //\r
-  return DivU64x32 (\r
-           MultU64x64 (\r
-             GetPerformanceCounterProperties (NULL, NULL),\r
-             TimeoutInMicroseconds\r
-             ),\r
-           1000000\r
-           );\r
+  // in Hz.\r
+  //\r
+  TimestampCounterFreq = GetPerformanceCounterProperties (NULL, NULL);\r
+\r
+  //\r
+  // Check the potential overflow before calculate the number of ticks for the timeout value.\r
+  //\r
+  if (DivU64x64Remainder (MAX_UINT64, TimeoutInMicroseconds, NULL) < TimestampCounterFreq) {\r
+    //\r
+    // Convert microseconds into seconds if direct multiplication overflows\r
+    //\r
+    TimeoutInSeconds = DivU64x32 (TimeoutInMicroseconds, 1000000);\r
+    //\r
+    // Assertion if the final tick count exceeds MAX_UINT64\r
+    //\r
+    ASSERT (DivU64x64Remainder (MAX_UINT64, TimeoutInSeconds, NULL) >= TimestampCounterFreq);\r
+    return MultU64x64 (TimestampCounterFreq, TimeoutInSeconds);\r
+  } else {\r
+    //\r
+    // No overflow case, multiply the return value with TimeoutInMicroseconds and then divide\r
+    // it by 1,000,000, to get the number of ticks for the timeout value.\r
+    //\r
+    return DivU64x32 (\r
+             MultU64x64 (\r
+               TimestampCounterFreq,\r
+               TimeoutInMicroseconds\r
+               ),\r
+             1000000\r
+             );\r
+  }\r
 }\r
 \r
 /**\r
@@ -1353,7 +1547,6 @@ MpInitLibInitialize (
   CpuMpData->CpuApStackSize   = ApStackSize;\r
   CpuMpData->BackupBuffer     = BackupBufferAddr;\r
   CpuMpData->BackupBufferSize = ApResetVectorSize;\r
-  CpuMpData->SaveRestoreFlag  = FALSE;\r
   CpuMpData->WakeupBuffer     = (UINTN) -1;\r
   CpuMpData->CpuCount         = 1;\r
   CpuMpData->BspNumber        = 0;\r
@@ -1361,6 +1554,8 @@ 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
   InitializeSpinLock(&CpuMpData->MpLock);\r
   //\r
   // Save BSP's Control registers to APs\r
@@ -1369,7 +1564,7 @@ MpInitLibInitialize (
   //\r
   // Set BSP basic information\r
   //\r
-  InitializeApData (CpuMpData, 0, 0, CpuMpData->Buffer);\r
+  InitializeApData (CpuMpData, 0, 0, CpuMpData->Buffer + ApStackSize);\r
   //\r
   // Save assembly code information\r
   //\r
@@ -1542,7 +1737,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
@@ -1584,7 +1779,7 @@ SwitchBSPWorker (
   //\r
   MpInitLibWhoAmI (&CallerNumber);\r
   if (CallerNumber != CpuMpData->BspNumber) {\r
-    return EFI_SUCCESS;\r
+    return EFI_DEVICE_ERROR;\r
   }\r
 \r
   if (ProcessorNumber >= CpuMpData->CpuCount) {\r
@@ -1638,6 +1833,7 @@ SwitchBSPWorker (
   ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);\r
   ApicBaseMsr.Bits.BSP = 1;\r
   AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);\r
+  ProgramVirtualWireMode ();\r
 \r
   //\r
   // Wait for old BSP finished AP task\r
@@ -1717,7 +1913,7 @@ EnableDisableApWorker (
   if (!EnableAP) {\r
     SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateDisabled);\r
   } else {\r
-    SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateIdle);\r
+    ResetProcessorToIdleState (ProcessorNumber);\r
   }\r
 \r
   if (HealthFlag != NULL) {\r
@@ -2120,41 +2316,3 @@ GetCpuMpDataFromGuidedHob (
   return CpuMpData;\r
 }\r
 \r
-/**\r
-  Get available system memory below 1MB by specified size.\r
-\r
-  @param[in]  CpuMpData  The pointer to CPU MP Data structure.\r
-**/\r
-VOID\r
-BackupAndPrepareWakeupBuffer(\r
-  IN CPU_MP_DATA              *CpuMpData\r
-  )\r
-{\r
-  CopyMem (\r
-    (VOID *) CpuMpData->BackupBuffer,\r
-    (VOID *) CpuMpData->WakeupBuffer,\r
-    CpuMpData->BackupBufferSize\r
-    );\r
-  CopyMem (\r
-    (VOID *) CpuMpData->WakeupBuffer,\r
-    (VOID *) CpuMpData->AddressMap.RendezvousFunnelAddress,\r
-    CpuMpData->AddressMap.RendezvousFunnelSize\r
-    );\r
-}\r
-\r
-/**\r
-  Restore wakeup buffer data.\r
-\r
-  @param[in]  CpuMpData  The pointer to CPU MP Data structure.\r
-**/\r
-VOID\r
-RestoreWakeupBuffer(\r
-  IN CPU_MP_DATA              *CpuMpData\r
-  )\r
-{\r
-  CopyMem (\r
-    (VOID *) CpuMpData->WakeupBuffer,\r
-    (VOID *) CpuMpData->BackupBuffer,\r
-    CpuMpData->BackupBufferSize\r
-    );\r
-}\r