]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c
UefiCpuPkg: Check SMM Delayed/Blocked AP Count
[mirror_edk2.git] / UefiCpuPkg / PiSmmCpuDxeSmm / MpService.c
index c79da418e37c96a6d9670603c507fd53fae44151..a0967eb69c71de1c97d714e38c47b9f7ecb20106 100644 (file)
@@ -24,6 +24,11 @@ SMM_CPU_SYNC_MODE            mCpuSmmSyncMode;
 BOOLEAN                      mMachineCheckSupported = FALSE;\r
 MM_COMPLETION                mSmmStartupThisApToken;\r
 \r
+//\r
+// Processor specified by mPackageFirstThreadIndex[PackageIndex] will do the package-scope register check.\r
+//\r
+UINT32  *mPackageFirstThreadIndex = NULL;\r
+\r
 extern UINTN  mSmmShadowStackSize;\r
 \r
 /**\r
@@ -157,50 +162,125 @@ ReleaseAllAPs (
 }\r
 \r
 /**\r
-  Checks if all CPUs (with certain exceptions) have checked in for this SMI run\r
+  Check whether the index of CPU perform the package level register\r
+  programming during System Management Mode initialization.\r
 \r
-  @param   Exceptions     CPU Arrival exception flags.\r
+  The index of Processor specified by mPackageFirstThreadIndex[PackageIndex]\r
+  will do the package-scope register programming.\r
 \r
-  @retval   TRUE  if all CPUs the have checked in.\r
-  @retval   FALSE  if at least one Normal AP hasn't checked in.\r
+  @param[in] CpuIndex   Processor Index.\r
+\r
+  @retval TRUE  Perform the package level register programming.\r
+  @retval FALSE Don't perform the package level register programming.\r
 \r
 **/\r
 BOOLEAN\r
-AllCpusInSmmWithExceptions (\r
-  SMM_CPU_ARRIVAL_EXCEPTIONS  Exceptions\r
+IsPackageFirstThread (\r
+  IN UINTN  CpuIndex\r
   )\r
 {\r
-  UINTN                      Index;\r
-  SMM_CPU_DATA_BLOCK         *CpuData;\r
-  EFI_PROCESSOR_INFORMATION  *ProcessorInfo;\r
+  UINT32  PackageIndex;\r
 \r
-  ASSERT (*mSmmMpSyncData->Counter <= mNumberOfCpus);\r
+  PackageIndex =  gSmmCpuPrivate->ProcessorInfo[CpuIndex].Location.Package;\r
 \r
-  if (*mSmmMpSyncData->Counter == mNumberOfCpus) {\r
-    return TRUE;\r
+  ASSERT (mPackageFirstThreadIndex != NULL);\r
+\r
+  //\r
+  // Set the value of mPackageFirstThreadIndex[PackageIndex].\r
+  // The package-scope register are checked by the first processor (CpuIndex) in Package.\r
+  //\r
+  // If mPackageFirstThreadIndex[PackageIndex] equals to (UINT32)-1, then update\r
+  // to current CpuIndex. If it doesn't equal to (UINT32)-1, don't change it.\r
+  //\r
+  if (mPackageFirstThreadIndex[PackageIndex] == (UINT32)-1) {\r
+    mPackageFirstThreadIndex[PackageIndex] = (UINT32)CpuIndex;\r
   }\r
 \r
-  CpuData       = mSmmMpSyncData->CpuData;\r
-  ProcessorInfo = gSmmCpuPrivate->ProcessorInfo;\r
-  for (Index = 0; Index < mMaxNumberOfCpus; Index++) {\r
-    if (!(*(CpuData[Index].Present)) && (ProcessorInfo[Index].ProcessorId != INVALID_APIC_ID)) {\r
-      if (((Exceptions & ARRIVAL_EXCEPTION_DELAYED) != 0) && (SmmCpuFeaturesGetSmmRegister (Index, SmmRegSmmDelayed) != 0)) {\r
-        continue;\r
-      }\r
+  return (BOOLEAN)(mPackageFirstThreadIndex[PackageIndex] == CpuIndex);\r
+}\r
+\r
+/**\r
+  Returns the Number of SMM Delayed & Blocked & Disabled Thread Count.\r
+\r
+  @param[in,out] DelayedCount  The Number of SMM Delayed Thread Count.\r
+  @param[in,out] BlockedCount  The Number of SMM Blocked Thread Count.\r
+  @param[in,out] DisabledCount The Number of SMM Disabled Thread Count.\r
+\r
+**/\r
+VOID\r
+GetSmmDelayedBlockedDisabledCount (\r
+  IN OUT UINT32  *DelayedCount,\r
+  IN OUT UINT32  *BlockedCount,\r
+  IN OUT UINT32  *DisabledCount\r
+  )\r
+{\r
+  UINTN  Index;\r
 \r
-      if (((Exceptions & ARRIVAL_EXCEPTION_BLOCKED) != 0) && (SmmCpuFeaturesGetSmmRegister (Index, SmmRegSmmBlocked) != 0)) {\r
-        continue;\r
+  for (Index = 0; Index < mNumberOfCpus; Index++) {\r
+    if (IsPackageFirstThread (Index)) {\r
+      if (DelayedCount != NULL) {\r
+        *DelayedCount += (UINT32)SmmCpuFeaturesGetSmmRegister (Index, SmmRegSmmDelayed);\r
       }\r
 \r
-      if (((Exceptions & ARRIVAL_EXCEPTION_SMI_DISABLED) != 0) && (SmmCpuFeaturesGetSmmRegister (Index, SmmRegSmmEnable) != 0)) {\r
-        continue;\r
+      if (BlockedCount != NULL) {\r
+        *BlockedCount += (UINT32)SmmCpuFeaturesGetSmmRegister (Index, SmmRegSmmBlocked);\r
       }\r
 \r
-      return FALSE;\r
+      if (DisabledCount != NULL) {\r
+        *DisabledCount += (UINT32)SmmCpuFeaturesGetSmmRegister (Index, SmmRegSmmEnable);\r
+      }\r
     }\r
   }\r
+}\r
 \r
-  return TRUE;\r
+/**\r
+  Checks if all CPUs (except Blocked & Disabled) have checked in for this SMI run\r
+\r
+  @retval   TRUE  if all CPUs the have checked in.\r
+  @retval   FALSE  if at least one Normal AP hasn't checked in.\r
+\r
+**/\r
+BOOLEAN\r
+AllCpusInSmmExceptBlockedDisabled (\r
+  VOID\r
+  )\r
+{\r
+  UINT32  BlockedCount;\r
+  UINT32  DisabledCount;\r
+\r
+  BlockedCount  = 0;\r
+  DisabledCount = 0;\r
+\r
+  //\r
+  // Check to make sure mSmmMpSyncData->Counter is valid and not locked.\r
+  //\r
+  ASSERT (*mSmmMpSyncData->Counter <= mNumberOfCpus);\r
+\r
+  //\r
+  // Check whether all CPUs in SMM.\r
+  //\r
+  if (*mSmmMpSyncData->Counter == mNumberOfCpus) {\r
+    return TRUE;\r
+  }\r
+\r
+  //\r
+  // Check for the Blocked & Disabled Exceptions Case.\r
+  //\r
+  GetSmmDelayedBlockedDisabledCount (NULL, &BlockedCount, &DisabledCount);\r
+\r
+  //\r
+  // *mSmmMpSyncData->Counter might be updated by all APs concurrently. The value\r
+  // can be dynamic changed. If some Aps enter the SMI after the BlockedCount &\r
+  // DisabledCount check, then the *mSmmMpSyncData->Counter will be increased, thus\r
+  // leading the *mSmmMpSyncData->Counter + BlockedCount + DisabledCount > mNumberOfCpus.\r
+  // since the BlockedCount & DisabledCount are local variable, it's ok here only for\r
+  // the checking of all CPUs In Smm.\r
+  //\r
+  if (*mSmmMpSyncData->Counter + BlockedCount + DisabledCount >= mNumberOfCpus) {\r
+    return TRUE;\r
+  }\r
+\r
+  return FALSE;\r
 }\r
 \r
 /**\r
@@ -268,6 +348,11 @@ SmmWaitForApArrival (
   UINTN    Index;\r
   BOOLEAN  LmceEn;\r
   BOOLEAN  LmceSignal;\r
+  UINT32   DelayedCount;\r
+  UINT32   BlockedCount;\r
+\r
+  DelayedCount = 0;\r
+  BlockedCount = 0;\r
 \r
   ASSERT (*mSmmMpSyncData->Counter <= mNumberOfCpus);\r
 \r
@@ -296,7 +381,7 @@ SmmWaitForApArrival (
        !IsSyncTimerTimeout (Timer) && !(LmceEn && LmceSignal);\r
        )\r
   {\r
-    mSmmMpSyncData->AllApArrivedWithException = AllCpusInSmmWithExceptions (ARRIVAL_EXCEPTION_BLOCKED | ARRIVAL_EXCEPTION_SMI_DISABLED);\r
+    mSmmMpSyncData->AllApArrivedWithException = AllCpusInSmmExceptBlockedDisabled ();\r
     if (mSmmMpSyncData->AllApArrivedWithException) {\r
       break;\r
     }\r
@@ -337,7 +422,7 @@ SmmWaitForApArrival (
          !IsSyncTimerTimeout (Timer);\r
          )\r
     {\r
-      mSmmMpSyncData->AllApArrivedWithException = AllCpusInSmmWithExceptions (ARRIVAL_EXCEPTION_BLOCKED | ARRIVAL_EXCEPTION_SMI_DISABLED);\r
+      mSmmMpSyncData->AllApArrivedWithException = AllCpusInSmmExceptBlockedDisabled ();\r
       if (mSmmMpSyncData->AllApArrivedWithException) {\r
         break;\r
       }\r
@@ -346,6 +431,14 @@ SmmWaitForApArrival (
     }\r
   }\r
 \r
+  if (!mSmmMpSyncData->AllApArrivedWithException) {\r
+    //\r
+    // Check for the Blocked & Delayed Case.\r
+    //\r
+    GetSmmDelayedBlockedDisabledCount (&DelayedCount, &BlockedCount, NULL);\r
+    DEBUG ((DEBUG_INFO, "SmmWaitForApArrival: Delayed AP Count = %d, Blocked AP Count = %d\n", DelayedCount, BlockedCount));\r
+  }\r
+\r
   return;\r
 }\r
 \r
@@ -739,6 +832,7 @@ APHandler (
     if (mSmmMpSyncData->BspIndex != -1) {\r
       //\r
       // BSP Index is known\r
+      // Existing AP is in SMI now but BSP not in, so, try bring BSP in SMM.\r
       //\r
       BspIndex = mSmmMpSyncData->BspIndex;\r
       ASSERT (CpuIndex != BspIndex);\r
@@ -763,12 +857,15 @@ APHandler (
         //\r
         // Give up since BSP is unable to enter SMM\r
         // and signal the completion of this AP\r
+        // Reduce the mSmmMpSyncData->Counter!\r
+        //\r
         WaitForSemaphore (mSmmMpSyncData->Counter);\r
         return;\r
       }\r
     } else {\r
       //\r
       // Don't know BSP index. Give up without sending IPI to BSP.\r
+      // Reduce the mSmmMpSyncData->Counter!\r
       //\r
       WaitForSemaphore (mSmmMpSyncData->Counter);\r
       return;\r
@@ -1668,10 +1765,13 @@ SmiRendezvous (
   } else {\r
     //\r
     // Signal presence of this processor\r
+    // mSmmMpSyncData->Counter is increased here!\r
+    // "ReleaseSemaphore (mSmmMpSyncData->Counter) == 0" means BSP has already ended the synchronization.\r
     //\r
     if (ReleaseSemaphore (mSmmMpSyncData->Counter) == 0) {\r
       //\r
       // BSP has already ended the synchronization, so QUIT!!!\r
+      // Existing AP is too late now to enter SMI since BSP has already ended the synchronization!!!\r
       //\r
 \r
       //\r
@@ -1783,6 +1883,47 @@ Exit:
   RestoreCr2 (Cr2);\r
 }\r
 \r
+/**\r
+  Initialize PackageBsp Info. Processor specified by mPackageFirstThreadIndex[PackageIndex]\r
+  will do the package-scope register programming. Set default CpuIndex to (UINT32)-1, which\r
+  means not specified yet.\r
+\r
+**/\r
+VOID\r
+InitPackageFirstThreadIndexInfo (\r
+  VOID\r
+  )\r
+{\r
+  UINT32  Index;\r
+  UINT32  PackageId;\r
+  UINT32  PackageCount;\r
+\r
+  PackageId    = 0;\r
+  PackageCount = 0;\r
+\r
+  //\r
+  // Count the number of package, set to max PackageId + 1\r
+  //\r
+  for (Index = 0; Index < mNumberOfCpus; Index++) {\r
+    if (PackageId < gSmmCpuPrivate->ProcessorInfo[Index].Location.Package) {\r
+      PackageId = gSmmCpuPrivate->ProcessorInfo[Index].Location.Package;\r
+    }\r
+  }\r
+\r
+  PackageCount = PackageId + 1;\r
+\r
+  mPackageFirstThreadIndex = (UINT32 *)AllocatePool (sizeof (UINT32) * PackageCount);\r
+  ASSERT (mPackageFirstThreadIndex != NULL);\r
+  if (mPackageFirstThreadIndex == NULL) {\r
+    return;\r
+  }\r
+\r
+  //\r
+  // Set default CpuIndex to (UINT32)-1, which means not specified yet.\r
+  //\r
+  SetMem32 (mPackageFirstThreadIndex, sizeof (UINT32) * PackageCount, (UINT32)-1);\r
+}\r
+\r
 /**\r
   Allocate buffer for SpinLock and Wrapper function buffer.\r
 \r