\r
#include "MpLib.h"\r
\r
+EFI_GUID mCpuInitMpLibHobGuid = CPU_INIT_MP_LIB_HOB_GUID;\r
+\r
+/**\r
+ The function will check if BSP Execute Disable is enabled.\r
+ DxeIpl may have enabled Execute Disable for BSP,\r
+ APs need to get the status and sync up the settings.\r
+\r
+ @retval TRUE BSP Execute Disable is enabled.\r
+ @retval FALSE BSP Execute Disable is not enabled.\r
+**/\r
+BOOLEAN\r
+IsBspExecuteDisableEnabled (\r
+ VOID\r
+ )\r
+{\r
+ UINT32 Eax;\r
+ CPUID_EXTENDED_CPU_SIG_EDX Edx;\r
+ MSR_IA32_EFER_REGISTER EferMsr;\r
+ BOOLEAN Enabled;\r
+\r
+ Enabled = FALSE;\r
+ AsmCpuid (CPUID_EXTENDED_FUNCTION, &Eax, NULL, NULL, NULL);\r
+ if (Eax >= CPUID_EXTENDED_CPU_SIG) {\r
+ AsmCpuid (CPUID_EXTENDED_CPU_SIG, NULL, NULL, NULL, &Edx.Uint32);\r
+ //\r
+ // CPUID 0x80000001\r
+ // Bit 20: Execute Disable Bit available.\r
+ //\r
+ if (Edx.Bits.NX != 0) {\r
+ EferMsr.Uint64 = AsmReadMsr64 (MSR_IA32_EFER);\r
+ //\r
+ // MSR 0xC0000080\r
+ // Bit 11: Execute Disable Bit enable.\r
+ //\r
+ if (EferMsr.Bits.NXE != 0) {\r
+ Enabled = TRUE;\r
+ }\r
+ }\r
+ }\r
+\r
+ return Enabled;\r
+}\r
+\r
+/**\r
+ Get the Application Processors state.\r
+\r
+ @param[in] CpuData The pointer to CPU_AP_DATA of specified AP\r
+\r
+ @return The AP status\r
+**/\r
+CPU_STATE\r
+GetApState (\r
+ IN CPU_AP_DATA *CpuData\r
+ )\r
+{\r
+ return CpuData->State;\r
+}\r
+\r
+/**\r
+ Set the Application Processors state.\r
+\r
+ @param[in] CpuData The pointer to CPU_AP_DATA of specified AP\r
+ @param[in] State The AP status\r
+**/\r
+VOID\r
+SetApState (\r
+ IN CPU_AP_DATA *CpuData,\r
+ IN CPU_STATE State\r
+ )\r
+{\r
+ AcquireSpinLock (&CpuData->ApLock);\r
+ CpuData->State = State;\r
+ ReleaseSpinLock (&CpuData->ApLock);\r
+}\r
+\r
+/**\r
+ Save the volatile registers required to be restored following INIT IPI.\r
+\r
+ @param[out] VolatileRegisters Returns buffer saved the volatile resisters\r
+**/\r
+VOID\r
+SaveVolatileRegisters (\r
+ OUT CPU_VOLATILE_REGISTERS *VolatileRegisters\r
+ )\r
+{\r
+ CPUID_VERSION_INFO_EDX VersionInfoEdx;\r
+\r
+ VolatileRegisters->Cr0 = AsmReadCr0 ();\r
+ VolatileRegisters->Cr3 = AsmReadCr3 ();\r
+ VolatileRegisters->Cr4 = AsmReadCr4 ();\r
+\r
+ AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &VersionInfoEdx.Uint32);\r
+ if (VersionInfoEdx.Bits.DE != 0) {\r
+ //\r
+ // If processor supports Debugging Extensions feature\r
+ // by CPUID.[EAX=01H]:EDX.BIT2\r
+ //\r
+ VolatileRegisters->Dr0 = AsmReadDr0 ();\r
+ VolatileRegisters->Dr1 = AsmReadDr1 ();\r
+ VolatileRegisters->Dr2 = AsmReadDr2 ();\r
+ VolatileRegisters->Dr3 = AsmReadDr3 ();\r
+ VolatileRegisters->Dr6 = AsmReadDr6 ();\r
+ VolatileRegisters->Dr7 = AsmReadDr7 ();\r
+ }\r
+}\r
+\r
+/**\r
+ Restore the volatile registers following INIT IPI.\r
+\r
+ @param[in] VolatileRegisters Pointer to volatile resisters\r
+ @param[in] IsRestoreDr TRUE: Restore DRx if supported\r
+ FALSE: Do not restore DRx\r
+**/\r
+VOID\r
+RestoreVolatileRegisters (\r
+ IN CPU_VOLATILE_REGISTERS *VolatileRegisters,\r
+ IN BOOLEAN IsRestoreDr\r
+ )\r
+{\r
+ CPUID_VERSION_INFO_EDX VersionInfoEdx;\r
+\r
+ AsmWriteCr0 (VolatileRegisters->Cr0);\r
+ AsmWriteCr3 (VolatileRegisters->Cr3);\r
+ AsmWriteCr4 (VolatileRegisters->Cr4);\r
+\r
+ if (IsRestoreDr) {\r
+ AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &VersionInfoEdx.Uint32);\r
+ if (VersionInfoEdx.Bits.DE != 0) {\r
+ //\r
+ // If processor supports Debugging Extensions feature\r
+ // by CPUID.[EAX=01H]:EDX.BIT2\r
+ //\r
+ AsmWriteDr0 (VolatileRegisters->Dr0);\r
+ AsmWriteDr1 (VolatileRegisters->Dr1);\r
+ AsmWriteDr2 (VolatileRegisters->Dr2);\r
+ AsmWriteDr3 (VolatileRegisters->Dr3);\r
+ AsmWriteDr6 (VolatileRegisters->Dr6);\r
+ AsmWriteDr7 (VolatileRegisters->Dr7);\r
+ }\r
+ }\r
+}\r
\r
/**\r
Detect whether Mwait-monitor feature is supported.\r
\r
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
+ @param[in, out] Buffer Pointer to private data buffer.\r
+**/\r
+VOID\r
+EFIAPI\r
+ApInitializeSync (\r
+ IN OUT VOID *Buffer\r
+ )\r
+{\r
+ CPU_MP_DATA *CpuMpData;\r
+\r
+ CpuMpData = (CPU_MP_DATA *) Buffer;\r
+ //\r
+ // Sync BSP's MTRR table to AP\r
+ //\r
+ MtrrSetAllMtrrs (&CpuMpData->MtrrTable);\r
+ //\r
+ // Load microcode on AP\r
+ //\r
+ MicrocodeDetect (CpuMpData);\r
+}\r
+\r
+/**\r
+ Find the current Processor number by APIC ID.\r
+\r
+ @param[in] CpuMpData Pointer to PEI CPU MP Data\r
+ @param[in] ProcessorNumber Return the pocessor number found\r
+\r
+ @retval EFI_SUCCESS ProcessorNumber is found and returned.\r
+ @retval EFI_NOT_FOUND ProcessorNumber is not found.\r
+**/\r
+EFI_STATUS\r
+GetProcessorNumber (\r
+ IN CPU_MP_DATA *CpuMpData,\r
+ OUT UINTN *ProcessorNumber\r
+ )\r
+{\r
+ UINTN TotalProcessorNumber;\r
+ UINTN Index;\r
+\r
+ TotalProcessorNumber = CpuMpData->CpuCount;\r
+ for (Index = 0; Index < TotalProcessorNumber; Index ++) {\r
+ if (CpuMpData->CpuData[Index].ApicId == GetApicId ()) {\r
+ *ProcessorNumber = Index;\r
+ return EFI_SUCCESS;\r
+ }\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
+ @param[in, out] CpuMpData Pointer to PEI CPU MP Data\r
+ @param[in] ProcessorNumber The handle number of processor\r
+ @param[in] BistData Processor BIST data\r
+\r
+**/\r
+VOID\r
+InitializeApData (\r
+ IN OUT CPU_MP_DATA *CpuMpData,\r
+ IN UINTN ProcessorNumber,\r
+ IN UINT32 BistData\r
+ )\r
+{\r
+ CpuMpData->CpuData[ProcessorNumber].Waiting = FALSE;\r
+ CpuMpData->CpuData[ProcessorNumber].Health = BistData;\r
+ CpuMpData->CpuData[ProcessorNumber].CpuHealthy = (BistData == 0) ? TRUE : FALSE;\r
+ CpuMpData->CpuData[ProcessorNumber].ApicId = GetApicId ();\r
+ CpuMpData->CpuData[ProcessorNumber].InitialApicId = GetInitialApicId ();\r
+ if (CpuMpData->CpuData[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
+ InitializeSpinLock(&CpuMpData->CpuData[ProcessorNumber].ApLock);\r
+ SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateIdle);\r
+}\r
+\r
+/**\r
+ This function will be called from AP reset code if BSP uses WakeUpAP.\r
+\r
+ @param[in] ExchangeInfo Pointer to the MP exchange info buffer\r
+ @param[in] NumApsExecuting Number of current executing AP\r
+**/\r
+VOID\r
+EFIAPI\r
+ApWakeupFunction (\r
+ IN MP_CPU_EXCHANGE_INFO *ExchangeInfo,\r
+ IN UINTN NumApsExecuting\r
+ )\r
+{\r
+ CPU_MP_DATA *CpuMpData;\r
+ UINTN ProcessorNumber;\r
+ EFI_AP_PROCEDURE Procedure;\r
+ VOID *Parameter;\r
+ UINT32 BistData;\r
+ volatile UINT32 *ApStartupSignalBuffer;\r
+\r
+ //\r
+ // AP finished assembly code and begin to execute C code\r
+ //\r
+ CpuMpData = ExchangeInfo->CpuMpData;\r
+\r
+ ProgramVirtualWireMode (); \r
+\r
+ while (TRUE) {\r
+ if (CpuMpData->InitFlag == ApInitConfig) {\r
+ //\r
+ // Add CPU number\r
+ //\r
+ InterlockedIncrement ((UINT32 *) &CpuMpData->CpuCount);\r
+ ProcessorNumber = NumApsExecuting;\r
+ //\r
+ // This is first time AP wakeup, get BIST information from AP stack\r
+ //\r
+ BistData = *(UINT32 *) (CpuMpData->Buffer + ProcessorNumber * CpuMpData->CpuApStackSize - sizeof (UINTN));\r
+ //\r
+ // Do some AP initialize sync\r
+ //\r
+ ApInitializeSync (CpuMpData);\r
+ //\r
+ // Sync BSP's Control registers to APs\r
+ //\r
+ RestoreVolatileRegisters (&CpuMpData->CpuData[0].VolatileRegisters, FALSE);\r
+ InitializeApData (CpuMpData, ProcessorNumber, BistData);\r
+ ApStartupSignalBuffer = CpuMpData->CpuData[ProcessorNumber].StartupApSignal;\r
+ } else {\r
+ //\r
+ // Execute AP function if AP is ready\r
+ //\r
+ GetProcessorNumber (CpuMpData, &ProcessorNumber);\r
+ //\r
+ // Clear AP start-up signal when AP waken up\r
+ //\r
+ ApStartupSignalBuffer = CpuMpData->CpuData[ProcessorNumber].StartupApSignal;\r
+ InterlockedCompareExchange32 (\r
+ (UINT32 *) ApStartupSignalBuffer,\r
+ WAKEUP_AP_SIGNAL,\r
+ 0\r
+ );\r
+ if (CpuMpData->ApLoopMode == ApInHltLoop) {\r
+ //\r
+ // Restore AP's volatile registers saved\r
+ //\r
+ RestoreVolatileRegisters (&CpuMpData->CpuData[ProcessorNumber].VolatileRegisters, TRUE);\r
+ }\r
+\r
+ if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) == CpuStateReady) {\r
+ Procedure = (EFI_AP_PROCEDURE)CpuMpData->CpuData[ProcessorNumber].ApFunction;\r
+ Parameter = (VOID *) CpuMpData->CpuData[ProcessorNumber].ApFunctionArgument;\r
+ if (Procedure != NULL) {\r
+ SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateBusy);\r
+ //\r
+ // Invoke AP function here\r
+ //\r
+ Procedure (Parameter);\r
+ //\r
+ // Re-get the CPU APICID and Initial APICID\r
+ //\r
+ CpuMpData->CpuData[ProcessorNumber].ApicId = GetApicId ();\r
+ CpuMpData->CpuData[ProcessorNumber].InitialApicId = GetInitialApicId ();\r
+ }\r
+ SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateFinished);\r
+ }\r
+ }\r
+\r
+ //\r
+ // AP finished executing C code\r
+ //\r
+ InterlockedIncrement ((UINT32 *) &CpuMpData->FinishedCount);\r
+\r
+ //\r
+ // Place AP is specified loop mode\r
+ //\r
+ if (CpuMpData->ApLoopMode == ApInHltLoop) {\r
+ //\r
+ // Save AP volatile registers\r
+ //\r
+ SaveVolatileRegisters (&CpuMpData->CpuData[ProcessorNumber].VolatileRegisters);\r
+ //\r
+ // Place AP in HLT-loop\r
+ //\r
+ while (TRUE) {\r
+ DisableInterrupts ();\r
+ CpuSleep ();\r
+ CpuPause ();\r
+ }\r
+ }\r
+ while (TRUE) {\r
+ DisableInterrupts ();\r
+ if (CpuMpData->ApLoopMode == ApInMwaitLoop) {\r
+ //\r
+ // Place AP in MWAIT-loop\r
+ //\r
+ AsmMonitor ((UINTN) ApStartupSignalBuffer, 0, 0);\r
+ if (*ApStartupSignalBuffer != WAKEUP_AP_SIGNAL) {\r
+ //\r
+ // Check AP start-up signal again.\r
+ // If AP start-up signal is not set, place AP into\r
+ // the specified C-state\r
+ //\r
+ AsmMwait (CpuMpData->ApTargetCState << 4, 0);\r
+ }\r
+ } else if (CpuMpData->ApLoopMode == ApInRunLoop) {\r
+ //\r
+ // Place AP in Run-loop\r
+ //\r
+ CpuPause ();\r
+ } else {\r
+ ASSERT (FALSE);\r
+ }\r
+\r
+ //\r
+ // If AP start-up signal is written, AP is waken up\r
+ // otherwise place AP in loop again\r
+ //\r
+ if (*ApStartupSignalBuffer == WAKEUP_AP_SIGNAL) {\r
+ break;\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ Wait for AP wakeup and write AP start-up signal till AP is waken up.\r
+\r
+ @param[in] ApStartupSignalBuffer Pointer to AP wakeup signal\r
+**/\r
+VOID\r
+WaitApWakeup (\r
+ IN volatile UINT32 *ApStartupSignalBuffer\r
+ )\r
+{\r
+ //\r
+ // If AP is waken up, StartupApSignal should be cleared.\r
+ // Otherwise, write StartupApSignal again till AP waken up.\r
+ //\r
+ while (InterlockedCompareExchange32 (\r
+ (UINT32 *) ApStartupSignalBuffer,\r
+ WAKEUP_AP_SIGNAL,\r
+ WAKEUP_AP_SIGNAL\r
+ ) != 0) {\r
+ CpuPause ();\r
+ }\r
+}\r
+\r
+/**\r
+ This function will fill the exchange info structure.\r
+\r
+ @param[in] CpuMpData Pointer to CPU MP Data\r
+\r
+**/\r
+VOID\r
+FillExchangeInfoData (\r
+ IN CPU_MP_DATA *CpuMpData\r
+ )\r
+{\r
+ volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo;\r
+\r
+ ExchangeInfo = CpuMpData->MpCpuExchangeInfo;\r
+ ExchangeInfo->Lock = 0;\r
+ ExchangeInfo->StackStart = CpuMpData->Buffer;\r
+ ExchangeInfo->StackSize = CpuMpData->CpuApStackSize;\r
+ ExchangeInfo->BufferStart = CpuMpData->WakeupBuffer;\r
+ ExchangeInfo->ModeOffset = CpuMpData->AddressMap.ModeEntryOffset;\r
+\r
+ ExchangeInfo->CodeSegment = AsmReadCs ();\r
+ ExchangeInfo->DataSegment = AsmReadDs ();\r
+\r
+ ExchangeInfo->Cr3 = AsmReadCr3 ();\r
+\r
+ ExchangeInfo->CFunction = (UINTN) ApWakeupFunction;\r
+ ExchangeInfo->NumApsExecuting = 0;\r
+ ExchangeInfo->CpuMpData = CpuMpData;\r
+\r
+ ExchangeInfo->EnableExecuteDisable = IsBspExecuteDisableEnabled ();\r
+\r
+ //\r
+ // Get the BSP's data of GDT and IDT\r
+ //\r
+ AsmReadGdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->GdtrProfile);\r
+ AsmReadIdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->IdtrProfile);\r
+}\r
+\r
+/**\r
+ This function will be called by BSP to wakeup AP.\r
+\r
+ @param[in] CpuMpData Pointer to CPU MP Data\r
+ @param[in] Broadcast TRUE: Send broadcast IPI to all APs\r
+ FALSE: Send IPI to AP by ApicId\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
+**/\r
+VOID\r
+WakeUpAP (\r
+ IN CPU_MP_DATA *CpuMpData,\r
+ IN BOOLEAN Broadcast,\r
+ IN UINTN ProcessorNumber,\r
+ IN EFI_AP_PROCEDURE Procedure, OPTIONAL\r
+ IN VOID *ProcedureArgument OPTIONAL\r
+ )\r
+{\r
+ volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo;\r
+ UINTN Index;\r
+ CPU_AP_DATA *CpuData;\r
+ BOOLEAN ResetVectorRequired;\r
+\r
+ CpuMpData->FinishedCount = 0;\r
+ ResetVectorRequired = FALSE;\r
+\r
+ if (CpuMpData->ApLoopMode == ApInHltLoop ||\r
+ CpuMpData->InitFlag != ApInitDone) {\r
+ ResetVectorRequired = TRUE;\r
+ AllocateResetVector (CpuMpData);\r
+ FillExchangeInfoData (CpuMpData);\r
+ } else 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
+ //\r
+ CpuMpData->ApTargetCState = PcdGet8 (PcdCpuApTargetCstate);\r
+ }\r
+\r
+ ExchangeInfo = CpuMpData->MpCpuExchangeInfo;\r
+\r
+ if (Broadcast) {\r
+ for (Index = 0; Index < CpuMpData->CpuCount; Index++) {\r
+ if (Index != CpuMpData->BspNumber) {\r
+ CpuData = &CpuMpData->CpuData[Index];\r
+ CpuData->ApFunction = (UINTN) Procedure;\r
+ CpuData->ApFunctionArgument = (UINTN) ProcedureArgument;\r
+ SetApState (CpuData, CpuStateReady);\r
+ if (CpuMpData->InitFlag != ApInitConfig) {\r
+ *(UINT32 *) CpuData->StartupApSignal = WAKEUP_AP_SIGNAL;\r
+ }\r
+ }\r
+ }\r
+ if (ResetVectorRequired) {\r
+ //\r
+ // Wakeup all APs\r
+ //\r
+ SendInitSipiSipiAllExcludingSelf ((UINT32) ExchangeInfo->BufferStart);\r
+ }\r
+ if (CpuMpData->InitFlag != ApInitConfig) {\r
+ //\r
+ // Wait all APs waken up if this is not the 1st broadcast of SIPI\r
+ //\r
+ for (Index = 0; Index < CpuMpData->CpuCount; Index++) {\r
+ CpuData = &CpuMpData->CpuData[Index];\r
+ if (Index != CpuMpData->BspNumber) {\r
+ WaitApWakeup (CpuData->StartupApSignal);\r
+ }\r
+ }\r
+ }\r
+ } else {\r
+ CpuData = &CpuMpData->CpuData[ProcessorNumber];\r
+ CpuData->ApFunction = (UINTN) Procedure;\r
+ CpuData->ApFunctionArgument = (UINTN) ProcedureArgument;\r
+ SetApState (CpuData, CpuStateReady);\r
+ //\r
+ // Wakeup specified AP\r
+ //\r
+ ASSERT (CpuMpData->InitFlag != ApInitConfig);\r
+ *(UINT32 *) CpuData->StartupApSignal = WAKEUP_AP_SIGNAL;\r
+ if (ResetVectorRequired) {\r
+ SendInitSipiSipi (\r
+ CpuData->ApicId,\r
+ (UINT32) ExchangeInfo->BufferStart\r
+ );\r
+ }\r
+ //\r
+ // Wait specified AP waken up\r
+ //\r
+ WaitApWakeup (CpuData->StartupApSignal);\r
+ }\r
+\r
+ if (ResetVectorRequired) {\r
+ FreeResetVector (CpuMpData);\r
+ }\r
+}\r
+\r
/**\r
MP Initialize Library initialization.\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
CPU_MP_DATA *CpuMpData;\r
UINT8 ApLoopMode;\r
UINT8 *MonitorBuffer;\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
CpuMpData->CpuInfoInHob = (UINT64) (UINTN) (CpuMpData->CpuData + MaxLogicalProcessorNumber);\r
InitializeSpinLock(&CpuMpData->MpLock);\r
//\r
+ // Save BSP's Control registers to APs\r
+ //\r
+ SaveVolatileRegisters (&CpuMpData->CpuData[0].VolatileRegisters);\r
+ //\r
+ // Set BSP basic information\r
+ //\r
+ InitializeApData (CpuMpData, 0, 0);\r
+ //\r
// Save assembly code information\r
//\r
CopyMem (&CpuMpData->AddressMap, &AddressMap, sizeof (MP_ASSEMBLY_ADDRESS_MAP));\r
CpuMpData->ApLoopMode = ApLoopMode;\r
DEBUG ((DEBUG_INFO, "AP Loop Mode is %d\n", CpuMpData->ApLoopMode));\r
//\r
+ // Set up APs wakeup signal buffer\r
+ //\r
+ for (Index = 0; Index < MaxLogicalProcessorNumber; Index++) {\r
+ CpuMpData->CpuData[Index].StartupApSignal =\r
+ (UINT32 *)(MonitorBuffer + MonitorFilterSize * Index);\r
+ }\r
+ //\r
+ // Load Microcode on BSP\r
+ //\r
+ MicrocodeDetect (CpuMpData);\r
+ //\r
// Store BSP's MTRR setting\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
+ InitMpGlobalData (CpuMpData);\r
+\r
return EFI_SUCCESS;\r
}\r
\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
+ @return The pointer to CPU MP Data structure.\r
+**/\r
+CPU_MP_DATA *\r
+GetCpuMpDataFromGuidedHob (\r
+ VOID\r
+ )\r
+{\r
+ EFI_HOB_GUID_TYPE *GuidHob;\r
+ VOID *DataInHob;\r
+ CPU_MP_DATA *CpuMpData;\r
+\r
+ CpuMpData = NULL;\r
+ GuidHob = GetFirstGuidHob (&mCpuInitMpLibHobGuid);\r
+ if (GuidHob != NULL) {\r
+ DataInHob = GET_GUID_HOB_DATA (GuidHob);\r
+ CpuMpData = (CPU_MP_DATA *) (*(UINTN *) DataInHob);\r
+ }\r
+ return CpuMpData;\r
}\r