return ApLoopMode;\r
}\r
\r
+/**\r
+ Sort the APIC ID of all processors.\r
+\r
+ This function sorts the APIC ID of all processors so that processor number is\r
+ assigned in the ascending order of APIC ID which eases MP debugging.\r
+\r
+ @param[in] CpuMpData Pointer to PEI CPU MP Data\r
+**/\r
+VOID\r
+SortApicId (\r
+ IN CPU_MP_DATA *CpuMpData\r
+ )\r
+{\r
+ UINTN Index1;\r
+ UINTN Index2;\r
+ UINTN Index3;\r
+ UINT32 ApicId;\r
+ CPU_AP_DATA CpuData;\r
+ UINT32 ApCount;\r
+ CPU_INFO_IN_HOB *CpuInfoInHob;\r
+\r
+ ApCount = CpuMpData->CpuCount - 1;\r
+\r
+ if (ApCount != 0) {\r
+ for (Index1 = 0; Index1 < ApCount; Index1++) {\r
+ Index3 = Index1;\r
+ //\r
+ // Sort key is the hardware default APIC ID\r
+ //\r
+ ApicId = CpuMpData->CpuData[Index1].ApicId;\r
+ for (Index2 = Index1 + 1; Index2 <= ApCount; Index2++) {\r
+ if (ApicId > CpuMpData->CpuData[Index2].ApicId) {\r
+ Index3 = Index2;\r
+ ApicId = CpuMpData->CpuData[Index2].ApicId;\r
+ }\r
+ }\r
+ if (Index3 != Index1) {\r
+ CopyMem (&CpuData, &CpuMpData->CpuData[Index3], sizeof (CPU_AP_DATA));\r
+ CopyMem (\r
+ &CpuMpData->CpuData[Index3],\r
+ &CpuMpData->CpuData[Index1],\r
+ sizeof (CPU_AP_DATA)\r
+ );\r
+ CopyMem (&CpuMpData->CpuData[Index1], &CpuData, sizeof (CPU_AP_DATA));\r
+ }\r
+ }\r
+\r
+ //\r
+ // Get the processor number for the BSP\r
+ //\r
+ ApicId = GetInitialApicId ();\r
+ for (Index1 = 0; Index1 < CpuMpData->CpuCount; Index1++) {\r
+ if (CpuMpData->CpuData[Index1].ApicId == ApicId) {\r
+ CpuMpData->BspNumber = (UINT32) Index1;\r
+ break;\r
+ }\r
+ }\r
+\r
+ CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob;\r
+ for (Index1 = 0; Index1 < CpuMpData->CpuCount; Index1++) {\r
+ CpuInfoInHob[Index1].InitialApicId = CpuMpData->CpuData[Index1].InitialApicId;\r
+ CpuInfoInHob[Index1].ApicId = CpuMpData->CpuData[Index1].ApicId;\r
+ CpuInfoInHob[Index1].Health = CpuMpData->CpuData[Index1].Health;\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ Enable x2APIC mode on APs.\r
+\r
+ @param[in, out] Buffer Pointer to private data buffer.\r
+**/\r
+VOID\r
+EFIAPI\r
+ApFuncEnableX2Apic (\r
+ IN OUT VOID *Buffer\r
+ )\r
+{\r
+ SetApicMode (LOCAL_APIC_MODE_X2APIC);\r
+}\r
+\r
/**\r
Do sync on APs.\r
\r
return EFI_NOT_FOUND;\r
}\r
\r
+/**\r
+ This function will get CPU count in the system.\r
+\r
+ @param[in] CpuMpData Pointer to PEI CPU MP Data\r
+\r
+ @return CPU count detected\r
+**/\r
+UINTN\r
+CollectProcessorCount (\r
+ IN CPU_MP_DATA *CpuMpData\r
+ )\r
+{\r
+ //\r
+ // Send 1st broadcast IPI to APs to wakeup APs\r
+ //\r
+ CpuMpData->InitFlag = ApInitConfig;\r
+ CpuMpData->X2ApicEnable = FALSE;\r
+ WakeUpAP (CpuMpData, TRUE, 0, NULL, NULL);\r
+ //\r
+ // Wait for AP task to complete and then exit.\r
+ //\r
+ MicroSecondDelay (PcdGet32(PcdCpuApInitTimeOutInMicroSeconds));\r
+ CpuMpData->InitFlag = ApInitDone;\r
+ ASSERT (CpuMpData->CpuCount <= PcdGet32 (PcdCpuMaxLogicalProcessorNumber));\r
+ //\r
+ // Wait for all APs finished the initialization\r
+ //\r
+ while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) {\r
+ CpuPause ();\r
+ }\r
+\r
+ if (CpuMpData->X2ApicEnable) {\r
+ DEBUG ((DEBUG_INFO, "Force x2APIC mode!\n"));\r
+ //\r
+ // Wakeup all APs to enable x2APIC mode\r
+ //\r
+ WakeUpAP (CpuMpData, TRUE, 0, ApFuncEnableX2Apic, NULL);\r
+ //\r
+ // Wait for all known APs finished\r
+ //\r
+ while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) {\r
+ CpuPause ();\r
+ }\r
+ //\r
+ // Enable x2APIC on BSP\r
+ //\r
+ SetApicMode (LOCAL_APIC_MODE_X2APIC);\r
+ }\r
+ DEBUG ((DEBUG_INFO, "APIC MODE is %d\n", GetApicMode ()));\r
+ //\r
+ // Sort BSP/Aps by CPU APIC ID in ascending order\r
+ //\r
+ SortApicId (CpuMpData);\r
+\r
+ DEBUG ((DEBUG_INFO, "MpInitLib: Find %d processors in system.\n", CpuMpData->CpuCount));\r
+\r
+ return CpuMpData->CpuCount;\r
+}\r
+\r
/*\r
Initialize CPU AP Data when AP is wakeup at the first time.\r
\r
VOID\r
)\r
{\r
+ CPU_MP_DATA *OldCpuMpData;\r
+ CPU_INFO_IN_HOB *CpuInfoInHob;\r
UINT32 MaxLogicalProcessorNumber;\r
UINT32 ApStackSize;\r
MP_ASSEMBLY_ADDRESS_MAP AddressMap;\r
UINTN Index;\r
UINTN ApResetVectorSize;\r
UINTN BackupBufferAddr;\r
- MaxLogicalProcessorNumber = PcdGet32(PcdCpuMaxLogicalProcessorNumber);\r
+\r
+ OldCpuMpData = GetCpuMpDataFromGuidedHob ();\r
+ if (OldCpuMpData == NULL) {\r
+ MaxLogicalProcessorNumber = PcdGet32(PcdCpuMaxLogicalProcessorNumber);\r
+ } else {\r
+ MaxLogicalProcessorNumber = OldCpuMpData->CpuCount;\r
+ }\r
\r
AsmGetAddressMap (&AddressMap);\r
ApResetVectorSize = AddressMap.RendezvousFunnelSize + sizeof (MP_CPU_EXCHANGE_INFO);\r
//\r
MtrrGetAllMtrrs (&CpuMpData->MtrrTable);\r
\r
+ if (OldCpuMpData == NULL) {\r
+ //\r
+ // Wakeup all APs and calculate the processor count in system\r
+ //\r
+ CollectProcessorCount (CpuMpData);\r
+ } else {\r
+ //\r
+ // APs have been wakeup before, just get the CPU Information\r
+ // from HOB\r
+ //\r
+ CpuMpData->CpuCount = OldCpuMpData->CpuCount;\r
+ CpuMpData->BspNumber = OldCpuMpData->BspNumber;\r
+ CpuMpData->InitFlag = ApInitReconfig;\r
+ CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) OldCpuMpData->CpuInfoInHob;\r
+ for (Index = 0; Index < CpuMpData->CpuCount; Index++) {\r
+ InitializeSpinLock(&CpuMpData->CpuData[Index].ApLock);\r
+ CpuMpData->CpuData[Index].ApicId = CpuInfoInHob[Index].ApicId;\r
+ CpuMpData->CpuData[Index].InitialApicId = CpuInfoInHob[Index].InitialApicId;\r
+ if (CpuMpData->CpuData[Index].InitialApicId >= 255) {\r
+ CpuMpData->X2ApicEnable = TRUE;\r
+ }\r
+ CpuMpData->CpuData[Index].Health = CpuInfoInHob[Index].Health;\r
+ CpuMpData->CpuData[Index].CpuHealthy = (CpuMpData->CpuData[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
+ }\r
+ //\r
+ // Wakeup APs to do some AP initialize sync\r
+ //\r
+ WakeUpAP (CpuMpData, TRUE, 0, ApInitializeSync, CpuMpData);\r
+ //\r
+ // Wait for all APs finished initialization\r
+ //\r
+ while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) {\r
+ CpuPause ();\r
+ }\r
+ CpuMpData->InitFlag = ApInitDone;\r
+ for (Index = 0; Index < CpuMpData->CpuCount; Index++) {\r
+ SetApState (&CpuMpData->CpuData[Index], CpuStateIdle);\r
+ }\r
+ }\r
\r
//\r
// Initialize global data for MP support\r
{\r
return EFI_UNSUPPORTED;\r
}\r
+\r
/**\r
Retrieves the number of logical processor in the platform and the number of\r
those logical processors that are enabled on this boot. This service may only\r
OUT UINTN *NumberOfEnabledProcessors OPTIONAL\r
)\r
{\r
- return EFI_UNSUPPORTED;\r
+ CPU_MP_DATA *CpuMpData;\r
+ UINTN CallerNumber;\r
+ UINTN ProcessorNumber;\r
+ UINTN EnabledProcessorNumber;\r
+ UINTN Index;\r
+\r
+ CpuMpData = GetCpuMpData ();\r
+\r
+ if ((NumberOfProcessors == NULL) && (NumberOfEnabledProcessors == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Check whether caller processor is BSP\r
+ //\r
+ MpInitLibWhoAmI (&CallerNumber);\r
+ if (CallerNumber != CpuMpData->BspNumber) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ ProcessorNumber = CpuMpData->CpuCount;\r
+ EnabledProcessorNumber = 0;\r
+ for (Index = 0; Index < ProcessorNumber; Index++) {\r
+ if (GetApState (&CpuMpData->CpuData[Index]) != CpuStateDisabled) {\r
+ EnabledProcessorNumber ++;\r
+ }\r
+ }\r
+\r
+ if (NumberOfProcessors != NULL) {\r
+ *NumberOfProcessors = ProcessorNumber;\r
+ }\r
+ if (NumberOfEnabledProcessors != NULL) {\r
+ *NumberOfEnabledProcessors = EnabledProcessorNumber;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
}\r
+\r
+\r
/**\r
Get pointer to CPU MP Data structure from GUIDed HOB.\r
\r