)\r
{\r
CPU_MP_DATA *CpuMpData;\r
+ UINTN ProcessorNumber;\r
+ EFI_STATUS Status;\r
\r
CpuMpData = (CPU_MP_DATA *) Buffer;\r
+ Status = GetProcessorNumber (CpuMpData, &ProcessorNumber);\r
+ ASSERT_EFI_ERROR (Status);\r
//\r
// Load microcode on AP\r
//\r
- MicrocodeDetect (CpuMpData, FALSE);\r
+ MicrocodeDetect (CpuMpData, ProcessorNumber);\r
//\r
// Sync BSP's MTRR table to AP\r
//\r
)\r
{\r
UINTN Index;\r
+ CPU_INFO_IN_HOB *CpuInfoInHob;\r
+ BOOLEAN X2Apic;\r
\r
//\r
// Send 1st broadcast IPI to APs to wakeup APs\r
//\r
- CpuMpData->InitFlag = ApInitConfig;\r
- CpuMpData->X2ApicEnable = FALSE;\r
+ CpuMpData->InitFlag = ApInitConfig;\r
WakeUpAP (CpuMpData, TRUE, 0, NULL, NULL, TRUE);\r
CpuMpData->InitFlag = ApInitDone;\r
ASSERT (CpuMpData->CpuCount <= PcdGet32 (PcdCpuMaxLogicalProcessorNumber));\r
CpuPause ();\r
}\r
\r
+\r
+ //\r
+ // Enable x2APIC mode if\r
+ // 1. Number of CPU is greater than 255; or\r
+ // 2. There are any logical processors reporting an Initial APIC ID of 255 or greater.\r
+ //\r
+ X2Apic = FALSE;\r
if (CpuMpData->CpuCount > 255) {\r
//\r
// If there are more than 255 processor found, force to enable X2APIC\r
//\r
- CpuMpData->X2ApicEnable = TRUE;\r
+ X2Apic = TRUE;\r
+ } else {\r
+ CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob;\r
+ for (Index = 0; Index < CpuMpData->CpuCount; Index++) {\r
+ if (CpuInfoInHob[Index].InitialApicId >= 0xFF) {\r
+ X2Apic = TRUE;\r
+ break;\r
+ }\r
+ }\r
}\r
- if (CpuMpData->X2ApicEnable) {\r
+\r
+ if (X2Apic) {\r
DEBUG ((DEBUG_INFO, "Force x2APIC mode!\n"));\r
//\r
// Wakeup all APs to enable x2APIC mode\r
IN UINT64 ApTopOfStack\r
)\r
{\r
- CPU_INFO_IN_HOB *CpuInfoInHob;\r
+ CPU_INFO_IN_HOB *CpuInfoInHob;\r
+ MSR_IA32_PLATFORM_ID_REGISTER PlatformIdMsr;\r
\r
CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob;\r
CpuInfoInHob[ProcessorNumber].InitialApicId = GetInitialApicId ();\r
\r
CpuMpData->CpuData[ProcessorNumber].Waiting = FALSE;\r
CpuMpData->CpuData[ProcessorNumber].CpuHealthy = (BistData == 0) ? TRUE : FALSE;\r
- if (CpuInfoInHob[ProcessorNumber].InitialApicId >= 0xFF) {\r
- //\r
- // Set x2APIC mode if there are any logical processor reporting\r
- // an Initial APIC ID of 255 or greater.\r
- //\r
- AcquireSpinLock(&CpuMpData->MpLock);\r
- CpuMpData->X2ApicEnable = TRUE;\r
- ReleaseSpinLock(&CpuMpData->MpLock);\r
- }\r
+\r
+ PlatformIdMsr.Uint64 = AsmReadMsr64 (MSR_IA32_PLATFORM_ID);\r
+ CpuMpData->CpuData[ProcessorNumber].PlatformId = (UINT8) PlatformIdMsr.Bits.PlatformId;\r
+\r
+ AsmCpuid (\r
+ CPUID_VERSION_INFO,\r
+ &CpuMpData->CpuData[ProcessorNumber].ProcessorSignature,\r
+ NULL,\r
+ NULL,\r
+ NULL\r
+ );\r
\r
InitializeSpinLock(&CpuMpData->CpuData[ProcessorNumber].ApLock);\r
SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateIdle);\r
ApTopOfStack = CpuMpData->Buffer + (ProcessorNumber + 1) * CpuMpData->CpuApStackSize;\r
BistData = *(UINT32 *) ((UINTN) ApTopOfStack - sizeof (UINTN));\r
//\r
- // Do some AP initialize sync\r
- //\r
- ApInitializeSync (CpuMpData);\r
- //\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
SendInitSipiSipiAllExcludingSelf ((UINT32) ExchangeInfo->BufferStart);\r
}\r
if (CpuMpData->InitFlag == ApInitConfig) {\r
- //\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
+ if (PcdGet32 (PcdCpuBootLogicalProcessorNumber) > 0) {\r
+ //\r
+ // The AP enumeration algorithm below is suitable only when the\r
+ // platform can tell us the *exact* boot CPU count in advance.\r
+ //\r
+ // The wait below finishes only when the detected AP count reaches\r
+ // (PcdCpuBootLogicalProcessorNumber - 1), regardless of how long that\r
+ // takes. If at least one AP fails to check in (meaning a platform\r
+ // hardware bug), the detection hangs forever, by design. If the actual\r
+ // boot CPU count in the system is higher than\r
+ // PcdCpuBootLogicalProcessorNumber (meaning a platform\r
+ // misconfiguration), then some APs may complete initialization after\r
+ // the wait finishes, and cause undefined behavior.\r
+ //\r
+ TimedWaitForApFinish (\r
+ CpuMpData,\r
+ PcdGet32 (PcdCpuBootLogicalProcessorNumber) - 1,\r
+ MAX_UINT32 // approx. 71 minutes\r
+ );\r
+ } else {\r
+ //\r
+ // The AP enumeration algorithm below is suitable for two use cases.\r
+ //\r
+ // (1) The check-in time for an individual AP is bounded, and APs run\r
+ // through their initialization routines strongly concurrently. In\r
+ // particular, the number of concurrently running APs\r
+ // ("NumApsExecuting") is never expected to fall to zero\r
+ // *temporarily* -- it is expected to fall to zero only when all\r
+ // APs have checked-in.\r
+ //\r
+ // In this case, the platform is supposed to set\r
+ // PcdCpuApInitTimeOutInMicroSeconds to a low-ish value (just long\r
+ // enough for one AP to start initialization). The timeout will be\r
+ // reached soon, and remaining APs are collected by watching\r
+ // NumApsExecuting fall to zero. If NumApsExecuting falls to zero\r
+ // mid-process, while some APs have not completed initialization,\r
+ // the behavior is undefined.\r
+ //\r
+ // (2) The check-in time for an individual AP is unbounded, and/or APs\r
+ // may complete their initializations widely spread out. In\r
+ // particular, some APs may finish initialization before some APs\r
+ // even start.\r
+ //\r
+ // In this case, the platform is supposed to set\r
+ // PcdCpuApInitTimeOutInMicroSeconds to a high-ish value. The AP\r
+ // enumeration will always take that long (except when the boot CPU\r
+ // count happens to be maximal, that is,\r
+ // PcdCpuMaxLogicalProcessorNumber). All APs are expected to\r
+ // check-in before the timeout, and NumApsExecuting is assumed zero\r
+ // at timeout. APs that miss the time-out may cause undefined\r
+ // behavior.\r
+ //\r
+ TimedWaitForApFinish (\r
+ CpuMpData,\r
+ PcdGet32 (PcdCpuMaxLogicalProcessorNumber) - 1,\r
+ PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds)\r
+ );\r
\r
- while (CpuMpData->MpCpuExchangeInfo->NumApsExecuting != 0) {\r
- CpuPause();\r
+ while (CpuMpData->MpCpuExchangeInfo->NumApsExecuting != 0) {\r
+ CpuPause();\r
+ }\r
}\r
} else {\r
//\r
UINTN ApResetVectorSize;\r
UINTN BackupBufferAddr;\r
UINTN ApIdtBase;\r
- VOID *MicrocodePatchInRam;\r
\r
OldCpuMpData = GetCpuMpDataFromGuidedHob ();\r
if (OldCpuMpData == NULL) {\r
CpuMpData->SwitchBspFlag = FALSE;\r
CpuMpData->CpuData = (CPU_AP_DATA *) (CpuMpData + 1);\r
CpuMpData->CpuInfoInHob = (UINT64) (UINTN) (CpuMpData->CpuData + MaxLogicalProcessorNumber);\r
- if (OldCpuMpData == NULL) {\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
- }else {\r
+ if (OldCpuMpData != NULL) {\r
CpuMpData->MicrocodePatchRegionSize = OldCpuMpData->MicrocodePatchRegionSize;\r
CpuMpData->MicrocodePatchAddress = OldCpuMpData->MicrocodePatchAddress;\r
}\r
(UINT32 *)(MonitorBuffer + MonitorFilterSize * Index);\r
}\r
//\r
- // Load Microcode on BSP\r
- //\r
- MicrocodeDetect (CpuMpData, TRUE);\r
- //\r
- // Store BSP's MTRR setting\r
- //\r
- MtrrGetAllMtrrs (&CpuMpData->MtrrTable);\r
- //\r
// Enable the local APIC for Virtual Wire Mode.\r
//\r
ProgramVirtualWireMode ();\r
//\r
CollectProcessorCount (CpuMpData);\r
}\r
+\r
+ //\r
+ // Load required microcode patches data into memory\r
+ //\r
+ LoadMicrocodePatch (CpuMpData);\r
} else {\r
//\r
// APs have been wakeup before, just get the CPU Information\r
//\r
CpuMpData->CpuCount = OldCpuMpData->CpuCount;\r
CpuMpData->BspNumber = OldCpuMpData->BspNumber;\r
- CpuMpData->InitFlag = ApInitReconfig;\r
CpuMpData->CpuInfoInHob = OldCpuMpData->CpuInfoInHob;\r
CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob;\r
for (Index = 0; Index < CpuMpData->CpuCount; Index++) {\r
InitializeSpinLock(&CpuMpData->CpuData[Index].ApLock);\r
- if (CpuInfoInHob[Index].InitialApicId >= 255 || Index > 254) {\r
- CpuMpData->X2ApicEnable = TRUE;\r
- }\r
CpuMpData->CpuData[Index].CpuHealthy = (CpuInfoInHob[Index].Health == 0)? TRUE:FALSE;\r
CpuMpData->CpuData[Index].ApFunction = 0;\r
CopyMem (&CpuMpData->CpuData[Index].VolatileRegisters, &VolatileRegisters, sizeof (CPU_VOLATILE_REGISTERS));\r
}\r
- if (MaxLogicalProcessorNumber > 1) {\r
- //\r
- // Wakeup APs to do some AP initialize sync\r
- //\r
- WakeUpAP (CpuMpData, TRUE, 0, ApInitializeSync, CpuMpData, TRUE);\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
+ // Detect and apply Microcode on BSP\r
+ //\r
+ MicrocodeDetect (CpuMpData, CpuMpData->BspNumber);\r
+ //\r
+ // Store BSP's MTRR setting\r
+ //\r
+ MtrrGetAllMtrrs (&CpuMpData->MtrrTable);\r
+\r
+ //\r
+ // Wakeup APs to do some AP initialize sync (Microcode & MTRR)\r
+ //\r
+ if (CpuMpData->CpuCount > 1) {\r
+ WakeUpAP (CpuMpData, TRUE, 0, ApInitializeSync, CpuMpData, TRUE);\r
+ while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) {\r
+ CpuPause ();\r
+ }\r
+\r
+ for (Index = 0; Index < CpuMpData->CpuCount; Index++) {\r
+ SetApState (&CpuMpData->CpuData[Index], CpuStateIdle);\r
}\r
}\r
\r