From: Yuanhao If PEI and DXE stages are in the same bit mode, Mp initialization is removed in DXE phase. Signed-off-by: Yuanhao Xie Cc: Eric Dong Cc: Rahul Kumar Cc: Ray Ni --- UefiCpuPkg/Library/MpInitLib/MpLib.c | 128 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------------------- UefiCpuPkg/Library/MpInitLib/MpLib.h | 1 + 2 files changed, 90 insertions(+), 39 deletions(-) diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.c b/UefiCpuPkg/Library/MpInitLib/MpLib.c index 5430688946..c7d1e58909 100644 --- a/UefiCpuPkg/Library/MpInitLib/MpLib.c +++ b/UefiCpuPkg/Library/MpInitLib/MpLib.c @@ -1842,12 +1842,36 @@ MpInitLibInitialize ( UINTN ApResetVectorSizeAbove1Mb; UINTN BackupBufferAddr; UINTN ApIdtBase; + BOOLEAN FirstTimeMpInitializing; - OldCpuMpData = GetCpuMpDataFromGuidedHob (); - if (OldCpuMpData == NULL) { + OldCpuMpData = GetCpuMpDataFromGuidedHob (); + FirstTimeMpInitializing = (BOOLEAN)(OldCpuMpData == NULL); + + if (FirstTimeMpInitializing) { MaxLogicalProcessorNumber = PcdGet32 (PcdCpuMaxLogicalProcessorNumber); + // + // The first time Mp is initialized, or the saved CpuMpData is lost, the + // complete process including preparing the buffer, filling the CpuMpData, + // loading the microcode, and waking up the Aps needs to be performed. + // } else { MaxLogicalProcessorNumber = OldCpuMpData->CpuCount; + // + // If both PEI and DXE phases are 64-bit, CpuMpdata collected in PEI stage + // can be reused in DXE stage, thus no need to redo the initialization. + // For the case where DXE is 64-bit and PEI is 32-bit, a partial + // initialization of Mp is required. + // + if (OldCpuMpData->SizeOfUINTN == sizeof (UINTN)) { + DEBUG ((DEBUG_INFO, "OldCpuMpData->SizeOfUINTN: %04d, sizeof (UINTN): %04d\n", OldCpuMpData->SizeOfUINTN, sizeof (UINTN))); + + OldCpuMpData->NewCpuMpData = OldCpuMpData; + // + // Initialize global data for MP support + // + InitMpGlobalData (OldCpuMpData); + return EFI_SUCCESS; + } } ASSERT (MaxLogicalProcessorNumber != 0); @@ -1991,7 +2015,7 @@ MpInitLibInitialize ( // ProgramVirtualWireMode (); - if (OldCpuMpData == NULL) { + if (FirstTimeMpInitializing) { if (MaxLogicalProcessorNumber > 1) { // // Wakeup all APs and calculate the processor count in system @@ -2015,58 +2039,84 @@ MpInitLibInitialize ( // Detect and apply Microcode on BSP // MicrocodeDetect (CpuMpData, CpuMpData->BspNumber); + + // + // CpuMpData->CpuCount was updated in CollectProcessorCount() + // during the first time Mp Initialization. + // + if (CpuMpData->CpuCount > 1) { + WakeUpAP (CpuMpData, TRUE, 0, ApInitializeSync, CpuMpData, TRUE); + // + // Wait for all APs to complete initialization. + // + while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) { + CpuPause (); + } + } + // + // After Mp is initialized, sizeof(UINTN) is saved and will be transferred to DXE. + // It is used to decide whether Mp initialization needs to be done again. + // SizeOfUINTN and other fields (CpuInfoInHob, CpuCount, BspNumber) declared at the top of + // the CPU_MP_DATA structure are independent of the bit mode( 32 or 64). + // + CpuMpData->SizeOfUINTN = sizeof (UINTN); } else { // - // APs have been wakeup before, just get the CPU Information - // from HOB + // For the else case where DXE is 64-bit and PEI is 32-bit, a partial + // initialization of Mp is required. // + OldCpuMpData->NewCpuMpData = CpuMpData; - CpuMpData->CpuCount = OldCpuMpData->CpuCount; - CpuMpData->BspNumber = OldCpuMpData->BspNumber; - CpuMpData->CpuInfoInHob = OldCpuMpData->CpuInfoInHob; - CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob; + // + // CpuCount, BspNumber, CpuInfoInHob as well as SizeOfUINTN are collected during PEI, + // and need to be saved in HOB for DXE. The rest fields of _CPU_MP_DATA is more like the temporary field. + // They will be updated during DXE if the DXE mode is different from PEI. + // + CpuMpData->CpuCount = OldCpuMpData->CpuCount; + CpuMpData->BspNumber = OldCpuMpData->BspNumber; + CpuMpData->CpuInfoInHob = OldCpuMpData->CpuInfoInHob; + CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob; for (Index = 0; Index < CpuMpData->CpuCount; Index++) { + // + // In PEI phase, or for first time initialization, initializeSpinLock is + // performed during CollectProcessorCount(). In DXE phase, it is done during traversal here. + // InitializeSpinLock (&CpuMpData->CpuData[Index].ApLock); CpuMpData->CpuData[Index].CpuHealthy = (CpuInfoInHob[Index].Health == 0) ? TRUE : FALSE; CpuMpData->CpuData[Index].ApFunction = 0; } - } - // - // Store BSP's MTRR setting - // - MtrrGetAllMtrrs (&CpuMpData->MtrrTable); - - // - // Wakeup APs to do some AP initialize sync (Microcode & MTRR) - // - if (CpuMpData->CpuCount > 1) { - if (OldCpuMpData != NULL) { - // - // Only needs to use this flag for DXE phase to update the wake up - // buffer. Wakeup buffer allocated in PEI phase is no longer valid - // in DXE. - // - CpuMpData->InitFlag = ApInitReconfig; - WakeUpAP (CpuMpData, TRUE, 0, ApMtrrSync, CpuMpData, TRUE); - } else { - WakeUpAP (CpuMpData, TRUE, 0, ApInitializeSync, CpuMpData, TRUE); - } + // + // Store BSP's MTRR setting + // + MtrrGetAllMtrrs (&CpuMpData->MtrrTable); // - // Wait for all APs finished initialization + // Wakeup APs to do some AP initialize sync (Microcode & MTRR) // - while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) { - CpuPause (); - } + if (CpuMpData->CpuCount > 1) { + if (OldCpuMpData != NULL) { + // + // Only needs to use this flag for DXE phase to update the wake up + // buffer. Wakeup buffer allocated in PEI phase is no longer valid + // in DXE. + // + CpuMpData->InitFlag = ApInitReconfig; + WakeUpAP (CpuMpData, TRUE, 0, ApMtrrSync, CpuMpData, TRUE); + // + // Wait for all APs to complete initialization. + // + while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) { + CpuPause (); + } - if (OldCpuMpData != NULL) { - CpuMpData->InitFlag = ApInitDone; + CpuMpData->InitFlag = ApInitDone; + } } + } - for (Index = 0; Index < CpuMpData->CpuCount; Index++) { - SetApState (&CpuMpData->CpuData[Index], CpuStateIdle); - } + for (Index = 0; Index < CpuMpData->CpuCount; Index++) { + SetApState (&CpuMpData->CpuData[Index], CpuStateIdle); } // diff --git a/UefiCpuPkg/Library/MpInitLib/MpLib.h b/UefiCpuPkg/Library/MpInitLib/MpLib.h index f5086e497e..d6a416b943 100644 --- a/UefiCpuPkg/Library/MpInitLib/MpLib.h +++ b/UefiCpuPkg/Library/MpInitLib/MpLib.h @@ -235,6 +235,7 @@ struct _CPU_MP_DATA { UINT64 CpuInfoInHob; UINT32 CpuCount; UINT32 BspNumber; + UINT32 SizeOfUINTN; // // The above fields data will be passed from PEI to DXE // Please make sure the fields offset same in the different -- 2.36.1.windows.1