CPU MP Initialize Library common functions.\r
\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
- http://opensource.org/licenses/bsd-license.php\r
-\r
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
- WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\r
CPUID_VERSION_INFO_EDX VersionInfoEdx;\r
IA32_TSS_DESCRIPTOR *Tss;\r
\r
- AsmWriteCr0 (VolatileRegisters->Cr0);\r
AsmWriteCr3 (VolatileRegisters->Cr3);\r
AsmWriteCr4 (VolatileRegisters->Cr4);\r
+ AsmWriteCr0 (VolatileRegisters->Cr0);\r
\r
if (IsRestoreDr) {\r
AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &VersionInfoEdx.Uint32);\r
//\r
// Load microcode on AP\r
//\r
- MicrocodeDetect (CpuMpData);\r
+ MicrocodeDetect (CpuMpData, FALSE);\r
//\r
// Sync BSP's MTRR table to AP\r
//\r
UINTN TotalProcessorNumber;\r
UINTN Index;\r
CPU_INFO_IN_HOB *CpuInfoInHob;\r
+ UINT32 CurrentApicId;\r
\r
CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob;\r
\r
TotalProcessorNumber = CpuMpData->CpuCount;\r
+ CurrentApicId = GetApicId ();\r
for (Index = 0; Index < TotalProcessorNumber; Index ++) {\r
- if (CpuInfoInHob[Index].ApicId == GetApicId ()) {\r
+ if (CpuInfoInHob[Index].ApicId == CurrentApicId) {\r
*ProcessorNumber = Index;\r
return EFI_SUCCESS;\r
}\r
}\r
+\r
return EFI_NOT_FOUND;\r
}\r
\r
//\r
CpuMpData->InitFlag = ApInitConfig;\r
CpuMpData->X2ApicEnable = FALSE;\r
- WakeUpAP (CpuMpData, TRUE, 0, NULL, NULL);\r
+ WakeUpAP (CpuMpData, TRUE, 0, NULL, NULL, TRUE);\r
CpuMpData->InitFlag = ApInitDone;\r
ASSERT (CpuMpData->CpuCount <= PcdGet32 (PcdCpuMaxLogicalProcessorNumber));\r
//\r
//\r
// Wakeup all APs to enable x2APIC mode\r
//\r
- WakeUpAP (CpuMpData, TRUE, 0, ApFuncEnableX2Apic, NULL);\r
+ WakeUpAP (CpuMpData, TRUE, 0, ApFuncEnableX2Apic, NULL, TRUE);\r
//\r
// Wait for all known APs finished\r
//\r
@param[in] ProcessorNumber The handle number of specified processor\r
@param[in] Procedure The function to be invoked by AP\r
@param[in] ProcedureArgument The argument to be passed into AP function\r
+ @param[in] WakeUpDisabledAps Whether need to wake up disabled APs in broadcast mode.\r
**/\r
VOID\r
WakeUpAP (\r
IN BOOLEAN Broadcast,\r
IN UINTN ProcessorNumber,\r
IN EFI_AP_PROCEDURE Procedure, OPTIONAL\r
- IN VOID *ProcedureArgument OPTIONAL\r
+ IN VOID *ProcedureArgument, OPTIONAL\r
+ IN BOOLEAN WakeUpDisabledAps\r
)\r
{\r
volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo;\r
CpuMpData->FinishedCount = 0;\r
ResetVectorRequired = FALSE;\r
\r
- if (CpuMpData->ApLoopMode == ApInHltLoop ||\r
+ if (CpuMpData->WakeUpByInitSipiSipi ||\r
CpuMpData->InitFlag != ApInitDone) {\r
ResetVectorRequired = TRUE;\r
AllocateResetVector (CpuMpData);\r
FillExchangeInfoData (CpuMpData);\r
SaveLocalApicTimerSetting (CpuMpData);\r
- } else if (CpuMpData->ApLoopMode == ApInMwaitLoop) {\r
+ }\r
+\r
+ if (CpuMpData->ApLoopMode == ApInMwaitLoop) {\r
//\r
// Get AP target C-state each time when waking up AP,\r
// for it maybe updated by platform again\r
for (Index = 0; Index < CpuMpData->CpuCount; Index++) {\r
if (Index != CpuMpData->BspNumber) {\r
CpuData = &CpuMpData->CpuData[Index];\r
+ //\r
+ // All AP(include disabled AP) will be woke up by INIT-SIPI-SIPI, but\r
+ // the AP procedure will be skipped for disabled AP because AP state\r
+ // is not CpuStateReady.\r
+ //\r
+ if (GetApState (CpuData) == CpuStateDisabled && !WakeUpDisabledAps) {\r
+ continue;\r
+ }\r
+\r
CpuData->ApFunction = (UINTN) Procedure;\r
CpuData->ApFunctionArgument = (UINTN) ProcedureArgument;\r
SetApState (CpuData, CpuStateReady);\r
if (ResetVectorRequired) {\r
FreeResetVector (CpuMpData);\r
}\r
+\r
+ //\r
+ // After one round of Wakeup Ap actions, need to re-sync ApLoopMode with\r
+ // WakeUpByInitSipiSipi flag. WakeUpByInitSipiSipi flag maybe changed by\r
+ // S3SmmInitDone Ppi.\r
+ //\r
+ CpuMpData->WakeUpByInitSipiSipi = (CpuMpData->ApLoopMode == ApInHltLoop);\r
}\r
\r
/**\r
CpuMpData = GetCpuMpData ();\r
\r
CpuMpData->InitFlag = ApInitReconfig;\r
- WakeUpAP (CpuMpData, FALSE, ProcessorNumber, NULL, NULL);\r
+ WakeUpAP (CpuMpData, FALSE, ProcessorNumber, NULL, NULL, TRUE);\r
while (CpuMpData->FinishedCount < 1) {\r
CpuPause ();\r
}\r
CpuData = &CpuMpData->CpuData[ProcessorNumber];\r
\r
//\r
- // Check the CPU state of AP. If it is CpuStateFinished, then the AP has finished its task.\r
+ // Check the CPU state of AP. If it is CpuStateIdle, then the AP has finished its task.\r
// Only BSP and corresponding AP access this unit of CPU Data. This means the AP will not modify the\r
- // value of state after setting the it to CpuStateFinished, so BSP can safely make use of its value.\r
+ // value of state after setting the it to CpuStateIdle, so BSP can safely make use of its value.\r
//\r
//\r
// If the AP finishes for StartupThisAP(), return EFI_SUCCESS.\r
\r
CpuData = &CpuMpData->CpuData[ProcessorNumber];\r
//\r
- // Check the CPU state of AP. If it is CpuStateFinished, then the AP has finished its task.\r
+ // Check the CPU state of AP. If it is CpuStateIdle, then the AP has finished its task.\r
// Only BSP and corresponding AP access this unit of CPU Data. This means the AP will not modify the\r
- // value of state after setting the it to CpuStateFinished, so BSP can safely make use of its value.\r
+ // value of state after setting the it to CpuStateIdle, so BSP can safely make use of its value.\r
//\r
if (GetApState(CpuData) == CpuStateFinished) {\r
- CpuMpData->RunningCount ++;\r
+ CpuMpData->RunningCount --;\r
CpuMpData->CpuData[ProcessorNumber].Waiting = FALSE;\r
SetApState(CpuData, CpuStateIdle);\r
\r
FALSE,\r
(UINT32) NextProcessorNumber,\r
CpuMpData->Procedure,\r
- CpuMpData->ProcArguments\r
+ CpuMpData->ProcArguments,\r
+ TRUE\r
);\r
}\r
}\r
//\r
// If all APs finish, return EFI_SUCCESS.\r
//\r
- if (CpuMpData->RunningCount == CpuMpData->StartCount) {\r
+ if (CpuMpData->RunningCount == 0) {\r
return EFI_SUCCESS;\r
}\r
\r
//\r
if (CpuMpData->FailedCpuList != NULL) {\r
*CpuMpData->FailedCpuList =\r
- AllocatePool ((CpuMpData->StartCount - CpuMpData->FinishedCount + 1) * sizeof (UINTN));\r
+ AllocatePool ((CpuMpData->RunningCount + 1) * sizeof (UINTN));\r
ASSERT (*CpuMpData->FailedCpuList != NULL);\r
}\r
ListIndex = 0;\r
UINTN ApResetVectorSize;\r
UINTN BackupBufferAddr;\r
UINTN ApIdtBase;\r
+ VOID *MicrocodePatchInRam;\r
\r
OldCpuMpData = GetCpuMpDataFromGuidedHob ();\r
if (OldCpuMpData == NULL) {\r
ApLoopMode = GetApLoopMode (&MonitorFilterSize);\r
\r
//\r
- // Save BSP's Control registers for APs\r
+ // Save BSP's Control registers for APs.\r
//\r
SaveVolatileRegisters (&VolatileRegisters);\r
\r
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
+ //\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
+\r
InitializeSpinLock(&CpuMpData->MpLock);\r
\r
//\r
//\r
CopyMem ((VOID *)ApIdtBase, (VOID *)VolatileRegisters.Idtr.Base, VolatileRegisters.Idtr.Limit + 1);\r
VolatileRegisters.Idtr.Base = ApIdtBase;\r
+ //\r
+ // Don't pass BSP's TR to APs to avoid AP init failure.\r
+ //\r
+ VolatileRegisters.Tr = 0;\r
CopyMem (&CpuMpData->CpuData[0].VolatileRegisters, &VolatileRegisters, sizeof (VolatileRegisters));\r
//\r
// Set BSP basic information\r
//\r
CpuMpData->ApLoopMode = ApLoopMode;\r
DEBUG ((DEBUG_INFO, "AP Loop Mode is %d\n", CpuMpData->ApLoopMode));\r
+\r
+ CpuMpData->WakeUpByInitSipiSipi = (CpuMpData->ApLoopMode == ApInHltLoop);\r
+\r
//\r
// Set up APs wakeup signal buffer\r
//\r
//\r
// Load Microcode on BSP\r
//\r
- MicrocodeDetect (CpuMpData);\r
+ MicrocodeDetect (CpuMpData, TRUE);\r
//\r
// Store BSP's MTRR setting\r
//\r
//\r
// Wakeup APs to do some AP initialize sync\r
//\r
- WakeUpAP (CpuMpData, TRUE, 0, ApInitializeSync, CpuMpData);\r
+ WakeUpAP (CpuMpData, TRUE, 0, ApInitializeSync, CpuMpData, TRUE);\r
//\r
// Wait for all APs finished initialization\r
//\r
//\r
// Need to wakeUp AP (future BSP).\r
//\r
- WakeUpAP (CpuMpData, FALSE, ProcessorNumber, FutureBSPProc, CpuMpData);\r
+ WakeUpAP (CpuMpData, FALSE, ProcessorNumber, FutureBSPProc, CpuMpData, TRUE);\r
\r
AsmExchangeRole (&CpuMpData->BSPInfo, &CpuMpData->APInfo);\r
\r
return EFI_NOT_STARTED;\r
}\r
\r
- CpuMpData->StartCount = 0;\r
+ CpuMpData->RunningCount = 0;\r
for (ProcessorNumber = 0; ProcessorNumber < ProcessorCount; ProcessorNumber++) {\r
CpuData = &CpuMpData->CpuData[ProcessorNumber];\r
CpuData->Waiting = FALSE;\r
// Mark this processor as responsible for current calling.\r
//\r
CpuData->Waiting = TRUE;\r
- CpuMpData->StartCount++;\r
+ CpuMpData->RunningCount++;\r
}\r
}\r
}\r
CpuMpData->ProcArguments = ProcedureArgument;\r
CpuMpData->SingleThread = SingleThread;\r
CpuMpData->FinishedCount = 0;\r
- CpuMpData->RunningCount = 0;\r
CpuMpData->FailedCpuList = FailedCpuList;\r
CpuMpData->ExpectedTime = CalculateTimeout (\r
TimeoutInMicroseconds,\r
CpuMpData->WaitEvent = WaitEvent;\r
\r
if (!SingleThread) {\r
- WakeUpAP (CpuMpData, TRUE, 0, Procedure, ProcedureArgument);\r
+ WakeUpAP (CpuMpData, TRUE, 0, Procedure, ProcedureArgument, FALSE);\r
} else {\r
for (ProcessorNumber = 0; ProcessorNumber < ProcessorCount; ProcessorNumber++) {\r
if (ProcessorNumber == CallerNumber) {\r
continue;\r
}\r
if (CpuMpData->CpuData[ProcessorNumber].Waiting) {\r
- WakeUpAP (CpuMpData, FALSE, ProcessorNumber, Procedure, ProcedureArgument);\r
+ WakeUpAP (CpuMpData, FALSE, ProcessorNumber, Procedure, ProcedureArgument, TRUE);\r
break;\r
}\r
}\r
CpuData->ExpectedTime = CalculateTimeout (TimeoutInMicroseconds, &CpuData->CurrentTime);\r
CpuData->TotalTime = 0;\r
\r
- WakeUpAP (CpuMpData, FALSE, ProcessorNumber, Procedure, ProcedureArgument);\r
+ WakeUpAP (CpuMpData, FALSE, ProcessorNumber, Procedure, ProcedureArgument, TRUE);\r
\r
//\r
// If WaitEvent is NULL, execute in blocking mode.\r