\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
\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
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
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