]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiCpuPkg/Library/MpInitLib/MpLib.c
UefiCpuPkg/MpInitLib: fix 32-bit build error
[mirror_edk2.git] / UefiCpuPkg / Library / MpInitLib / MpLib.c
index df19b43bc03a0ba73dc0effc5802a2279be5bf67..cdc03113e5998116ad78d7d89ad088a569ca6980 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
@@ -536,13 +553,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 +582,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 +595,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
@@ -662,6 +683,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
@@ -764,6 +786,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
@@ -795,6 +818,81 @@ 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
+  }\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 +957,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 +1035,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 +1053,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 +1485,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 +1492,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 +1502,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
@@ -1584,7 +1717,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
@@ -1717,7 +1850,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 +2253,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