UINTN gPollInterval = 100; // 100 microseconds\r
\r
MP_SYSTEM_DATA mMpSystemData;\r
+EFI_HANDLE mMpServiceHandle = NULL;\r
+EFI_EVENT mExitBootServicesEvent = (EFI_EVENT)NULL;\r
\r
VOID *mCommonStack = 0;\r
VOID *mTopOfApCommonStack = 0;\r
VOID *mApStackStart = 0;\r
\r
+volatile BOOLEAN mAPsAlreadyInitFinished = FALSE;\r
+volatile BOOLEAN mStopCheckAllAPsStatus = TRUE;\r
+\r
EFI_MP_SERVICES_PROTOCOL mMpServicesTemplate = {\r
GetNumberOfProcessors,\r
GetProcessorInfo,\r
StartupAllAPs,\r
StartupThisAP,\r
- NULL, // SwitchBSP,\r
+ SwitchBSP,\r
EnableDisableAP,\r
WhoAmI\r
};\r
\r
+/**\r
+ Get Mp Service Lock.\r
+\r
+ @param CpuData the pointer to CPU_DATA_BLOCK of specified processor\r
+\r
+**/\r
+VOID\r
+GetMpSpinLock (\r
+ IN CPU_DATA_BLOCK *CpuData\r
+ )\r
+{\r
+ while (!AcquireSpinLockOrFail (&CpuData->CpuDataLock)) {\r
+ CpuPause ();\r
+ }\r
+ CpuData->LockSelf = GetApicId ();\r
+}\r
+\r
+/**\r
+ Release Mp Service Lock.\r
+\r
+ @param CpuData the pointer to CPU_DATA_BLOCK of specified processor\r
+\r
+**/\r
+VOID\r
+ReleaseMpSpinLock (\r
+ IN CPU_DATA_BLOCK *CpuData\r
+ )\r
+{\r
+ ReleaseSpinLock (&CpuData->CpuDataLock);\r
+}\r
+\r
/**\r
Check whether caller processor is BSP.\r
\r
{\r
CPU_STATE State;\r
\r
- while (!AcquireSpinLockOrFail (&CpuData->CpuDataLock)) {\r
- CpuPause ();\r
- }\r
-\r
+ GetMpSpinLock (CpuData);\r
State = CpuData->State;\r
- ReleaseSpinLock (&CpuData->CpuDataLock);\r
+ ReleaseMpSpinLock (CpuData);\r
\r
return State;\r
}\r
IN CPU_STATE State\r
)\r
{\r
- while (!AcquireSpinLockOrFail (&CpuData->CpuDataLock)) {\r
- CpuPause ();\r
- }\r
-\r
+ GetMpSpinLock (CpuData);\r
CpuData->State = State;\r
- ReleaseSpinLock (&CpuData->CpuDataLock);\r
+ ReleaseMpSpinLock (CpuData);\r
}\r
\r
/**\r
IN VOID *ProcedureArgument\r
)\r
{\r
- while (!AcquireSpinLockOrFail (&CpuData->CpuDataLock)) {\r
- CpuPause ();\r
- }\r
-\r
+ GetMpSpinLock (CpuData);\r
CpuData->Parameter = ProcedureArgument;\r
CpuData->Procedure = Procedure;\r
- ReleaseSpinLock (&CpuData->CpuDataLock);\r
+ ReleaseMpSpinLock (CpuData);\r
}\r
\r
/**\r
{\r
UINT32 Ret;\r
\r
- while (!AcquireSpinLockOrFail (&CpuData->CpuDataLock)) {\r
- CpuPause ();\r
- }\r
-\r
+ GetMpSpinLock (CpuData);\r
Ret = CpuData->Info.StatusFlag & Flags;\r
- ReleaseSpinLock (&CpuData->CpuDataLock);\r
+ ReleaseMpSpinLock (CpuData);\r
\r
return !!(Ret);\r
}\r
IN UINT32 Flags\r
)\r
{\r
- while (!AcquireSpinLockOrFail (&CpuData->CpuDataLock)) {\r
- CpuPause ();\r
- }\r
-\r
+ GetMpSpinLock (CpuData);\r
CpuData->Info.StatusFlag |= Flags;\r
- ReleaseSpinLock (&CpuData->CpuDataLock);\r
+ ReleaseMpSpinLock (CpuData);\r
}\r
\r
/**\r
IN UINT32 Flags\r
)\r
{\r
- while (!AcquireSpinLockOrFail (&CpuData->CpuDataLock)) {\r
- CpuPause ();\r
- }\r
-\r
+ GetMpSpinLock (CpuData);\r
CpuData->Info.StatusFlag &= ~Flags;\r
- ReleaseSpinLock (&CpuData->CpuDataLock);\r
+ ReleaseMpSpinLock (CpuData);\r
}\r
\r
/**\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
+ //\r
+ // temporarily stop checkAllAPsStatus for avoid resource dead-lock.\r
+ //\r
+ mStopCheckAllAPsStatus = TRUE;\r
+\r
for (Number = 0; Number < mMpSystemData.NumberOfProcessors; Number++) {\r
CpuData = &mMpSystemData.CpuDatas[Number];\r
if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT)) {\r
}\r
}\r
\r
+ mStopCheckAllAPsStatus = FALSE;\r
+\r
if (WaitEvent != NULL) {\r
- Status = gBS->SetTimer (\r
- mMpSystemData.CheckAllAPsEvent,\r
- TimerPeriodic,\r
- EFI_TIMER_PERIOD_MICROSECONDS (100)\r
- );\r
- return Status;\r
+ //\r
+ // non blocking\r
+ //\r
+ return EFI_SUCCESS;\r
}\r
\r
+ //\r
+ // Blocking temporarily stop CheckAllAPsStatus()\r
+ //\r
+ mStopCheckAllAPsStatus = TRUE;\r
+\r
while (TRUE) {\r
CheckAndUpdateAllAPsToIdleState ();\r
if (mMpSystemData.FinishCount == mMpSystemData.StartCount) {\r
)\r
{\r
CPU_DATA_BLOCK *CpuData;\r
- EFI_STATUS Status;\r
\r
CpuData = NULL;\r
\r
return EFI_NOT_FOUND;\r
}\r
\r
+ //\r
+ // temporarily stop checkAllAPsStatus for avoid resource dead-lock.\r
+ //\r
+ mStopCheckAllAPsStatus = TRUE;\r
+\r
CpuData = &mMpSystemData.CpuDatas[ProcessorNumber];\r
if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT) ||\r
!TestCpuStatusFlag (CpuData, PROCESSOR_ENABLED_BIT)) {\r
CpuData->TimeoutActive = !!(TimeoutInMicroseconds);\r
CpuData->Finished = Finished;\r
\r
+ mStopCheckAllAPsStatus = FALSE;\r
+\r
if (WaitEvent != NULL) {\r
//\r
// Non Blocking\r
//\r
- Status = gBS->SetTimer (\r
- CpuData->CheckThisAPEvent,\r
- TimerPeriodic,\r
- EFI_TIMER_PERIOD_MICROSECONDS (100)\r
- );\r
- return Status;\r
+ return EFI_SUCCESS;\r
}\r
\r
//\r
return EFI_SUCCESS;\r
}\r
\r
+/**\r
+ This service switches the requested AP to be the BSP from that point onward.\r
+ This service changes the BSP for all purposes. This call can only be performed\r
+ by the current BSP.\r
+\r
+ This service switches the requested AP to be the BSP from that point onward.\r
+ This service changes the BSP for all purposes. The new BSP can take over the\r
+ execution of the old BSP and continue seamlessly from where the old one left\r
+ off. This service may not be supported after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT\r
+ is signaled.\r
+\r
+ If the BSP cannot be switched prior to the return from this service, then\r
+ EFI_UNSUPPORTED must be returned.\r
+\r
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.\r
+ @param[in] ProcessorNumber The handle number of AP that is to become the new\r
+ BSP. The range is from 0 to the total number of\r
+ logical processors minus 1. The total number of\r
+ logical processors can be retrieved by\r
+ EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().\r
+ @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an\r
+ enabled AP. Otherwise, it will be disabled.\r
+\r
+ @retval EFI_SUCCESS BSP successfully switched.\r
+ @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to\r
+ this service returning.\r
+ @retval EFI_UNSUPPORTED Switching the BSP is not supported.\r
+ @retval EFI_SUCCESS The calling processor is an AP.\r
+ @retval EFI_NOT_FOUND The processor with the handle specified by\r
+ ProcessorNumber does not exist.\r
+ @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or\r
+ a disabled AP.\r
+ @retval EFI_NOT_READY The specified AP is busy.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SwitchBSP (\r
+ IN EFI_MP_SERVICES_PROTOCOL *This,\r
+ IN UINTN ProcessorNumber,\r
+ IN BOOLEAN EnableOldBSP\r
+ )\r
+{\r
+ //\r
+ // Current always return unsupported.\r
+ //\r
+ return EFI_UNSUPPORTED;\r
+}\r
+\r
/**\r
This service lets the caller enable or disable an AP from this point onward.\r
This service may only be called from the BSP.\r
)\r
{\r
CPU_DATA_BLOCK *CpuData;\r
+ BOOLEAN TempStopCheckState;\r
+\r
+ CpuData = NULL;\r
+ TempStopCheckState = FALSE;\r
\r
if (!IsBSP ()) {\r
return EFI_DEVICE_ERROR;\r
return EFI_NOT_FOUND;\r
}\r
\r
+ //\r
+ // temporarily stop checkAllAPsStatus for initialize parameters.\r
+ //\r
+ if (!mStopCheckAllAPsStatus) {\r
+ mStopCheckAllAPsStatus = TRUE;\r
+ TempStopCheckState = TRUE;\r
+ }\r
+\r
CpuData = &mMpSystemData.CpuDatas[ProcessorNumber];\r
if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT)) {\r
return EFI_INVALID_PARAMETER;\r
CpuStatusFlagOr (CpuData, (*HealthFlag & PROCESSOR_HEALTH_STATUS_BIT));\r
}\r
\r
+ if (TempStopCheckState) {\r
+ mStopCheckAllAPsStatus = FALSE;\r
+ }\r
+\r
return EFI_SUCCESS;\r
}\r
\r
IN CPU_DATA_BLOCK *CpuData\r
)\r
{\r
+ ResetApStackless ((UINT32)CpuData->Info.ProcessorId);\r
}\r
\r
/**\r
IN VOID *Context2 OPTIONAL\r
)\r
{\r
- DEBUG ((DEBUG_INFO, "Ap apicid is %d\n", GetApicId ()));\r
+ UINTN ProcessorNumber;\r
+ CPU_DATA_BLOCK *CpuData;\r
+ EFI_AP_PROCEDURE Procedure;\r
+ VOID *ProcedureArgument;\r
\r
AsmApDoneWithCommonStack ();\r
\r
+ while (!mAPsAlreadyInitFinished) {\r
+ CpuPause ();\r
+ }\r
+\r
+ WhoAmI (&mMpServicesTemplate, &ProcessorNumber);\r
+ CpuData = &mMpSystemData.CpuDatas[ProcessorNumber];\r
+\r
+ //\r
+ // Avoid forcibly reset AP caused the AP got lock not release.\r
+ //\r
+ if (CpuData->LockSelf == (INTN) GetApicId ()) {\r
+ ReleaseSpinLock (&CpuData->CpuDataLock);\r
+ }\r
+\r
+ //\r
+ // Avoid forcibly reset AP caused the AP State is not updated.\r
+ //\r
+ GetMpSpinLock (CpuData);\r
+ CpuData->State = CpuStateIdle;\r
+ CpuData->Procedure = NULL;\r
+ ReleaseMpSpinLock (CpuData);\r
+\r
+ while (TRUE) {\r
+ GetMpSpinLock (CpuData);\r
+ ProcedureArgument = CpuData->Parameter;\r
+ Procedure = CpuData->Procedure;\r
+ ReleaseMpSpinLock (CpuData);\r
+\r
+ if (Procedure != NULL) {\r
+ Procedure (ProcedureArgument);\r
+\r
+ GetMpSpinLock (CpuData);\r
+ CpuData->Procedure = NULL;\r
+ CpuData->State = CpuStateFinished;\r
+ ReleaseMpSpinLock (CpuData);\r
+ }\r
+\r
+ CpuPause ();\r
+ }\r
+\r
CpuSleep ();\r
CpuDeadLoop ();\r
}\r
return;\r
\r
out:\r
- gBS->SetTimer (CpuData->CheckThisAPEvent, TimerCancel, 0);\r
- if (CpuData->WaitEvent) {\r
- gBS->SignalEvent (CpuData->WaitEvent);\r
- CpuData->WaitEvent = NULL;\r
- }\r
+ CpuData->TimeoutActive = FALSE;\r
+ gBS->SignalEvent (CpuData->WaitEvent);\r
+ CpuData->WaitEvent = NULL;\r
}\r
\r
/**\r
IN VOID *Context\r
)\r
{\r
+ CPU_DATA_BLOCK *CpuData;\r
+ UINTN Number;\r
+ EFI_STATUS Status;\r
+\r
if (mMpSystemData.TimeoutActive) {\r
mMpSystemData.Timeout -= gPollInterval;\r
}\r
\r
- CheckAndUpdateAllAPsToIdleState ();\r
+ if (mStopCheckAllAPsStatus) {\r
+ return;\r
+ }\r
\r
//\r
- // task timeout\r
+ // avoid next timer enter.\r
//\r
- if (mMpSystemData.TimeoutActive && mMpSystemData.Timeout < 0) {\r
- ResetAllFailedAPs();\r
+ Status = gBS->SetTimer (\r
+ mMpSystemData.CheckAllAPsEvent,\r
+ TimerCancel,\r
+ 0\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ if (mMpSystemData.WaitEvent != NULL) {\r
+ CheckAndUpdateAllAPsToIdleState ();\r
//\r
- // force exit\r
+ // task timeout\r
//\r
- mMpSystemData.FinishCount = mMpSystemData.StartCount;\r
- }\r
-\r
- if (mMpSystemData.FinishCount != mMpSystemData.StartCount) {\r
- return;\r
- }\r
+ if (mMpSystemData.TimeoutActive && mMpSystemData.Timeout < 0) {\r
+ ResetAllFailedAPs();\r
+ //\r
+ // force exit\r
+ //\r
+ mMpSystemData.FinishCount = mMpSystemData.StartCount;\r
+ }\r
\r
- gBS->SetTimer (\r
- mMpSystemData.CheckAllAPsEvent,\r
- TimerCancel,\r
- 0\r
- );\r
+ if (mMpSystemData.FinishCount != mMpSystemData.StartCount) {\r
+ goto EXIT;\r
+ }\r
\r
- if (mMpSystemData.WaitEvent) {\r
+ mMpSystemData.TimeoutActive = FALSE;\r
gBS->SignalEvent (mMpSystemData.WaitEvent);\r
mMpSystemData.WaitEvent = NULL;\r
+ mStopCheckAllAPsStatus = TRUE;\r
+\r
+ goto EXIT;\r
}\r
+\r
+ //\r
+ // check each AP status for StartupThisAP\r
+ //\r
+ for (Number = 0; Number < mMpSystemData.NumberOfProcessors; Number++) {\r
+ CpuData = &mMpSystemData.CpuDatas[Number];\r
+ if (CpuData->WaitEvent) {\r
+ CheckThisAPStatus (NULL, (VOID *)CpuData);\r
+ }\r
+ }\r
+\r
+EXIT:\r
+ Status = gBS->SetTimer (\r
+ mMpSystemData.CheckAllAPsEvent,\r
+ TimerPeriodic,\r
+ EFI_TIMER_PERIOD_MICROSECONDS (100)\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
}\r
\r
/**\r
VOID\r
)\r
{\r
- VOID* TopOfApStack;\r
+ VOID* TopOfApStack;\r
+ UINTN ProcessorNumber;\r
\r
- FillInProcessorInformation (FALSE, mMpSystemData.NumberOfProcessors);\r
- TopOfApStack = (UINT8*)mApStackStart + gApStackSize;\r
- mApStackStart = TopOfApStack;\r
+ if (!mAPsAlreadyInitFinished) {\r
+ FillInProcessorInformation (FALSE, mMpSystemData.NumberOfProcessors);\r
+ TopOfApStack = (UINT8*)mApStackStart + gApStackSize;\r
+ mApStackStart = TopOfApStack;\r
\r
- mMpSystemData.NumberOfProcessors++;\r
+ //\r
+ // Store the Stack address, when reset the AP, We can found the original address.\r
+ //\r
+ mMpSystemData.CpuDatas[mMpSystemData.NumberOfProcessors].TopOfStack = TopOfApStack;\r
+ mMpSystemData.NumberOfProcessors++;\r
+ mMpSystemData.NumberOfEnabledProcessors++;\r
+ } else {\r
+ WhoAmI (&mMpServicesTemplate, &ProcessorNumber);\r
+ //\r
+ // Get the original stack address.\r
+ //\r
+ TopOfApStack = mMpSystemData.CpuDatas[ProcessorNumber].TopOfStack;\r
+ }\r
\r
SwitchStack (\r
(SWITCH_STACK_ENTRY_POINT)(UINTN)ProcessorToIdleState,\r
CpuData->Procedure = NULL;\r
CpuData->Parameter = NULL;\r
InitializeSpinLock (&CpuData->CpuDataLock);\r
+ CpuData->LockSelf = -1;\r
\r
return EFI_SUCCESS;\r
}\r
VOID\r
)\r
{\r
- UINTN ProcessorNumber;\r
- CPU_DATA_BLOCK *CpuData;\r
EFI_STATUS Status;\r
\r
ZeroMem (&mMpSystemData, sizeof (MP_SYSTEM_DATA));\r
);\r
ASSERT_EFI_ERROR (Status);\r
\r
- for (ProcessorNumber = 0; ProcessorNumber < gMaxLogicalProcessorNumber; ProcessorNumber++) {\r
- CpuData = &mMpSystemData.CpuDatas[ProcessorNumber];\r
- Status = gBS->CreateEvent (\r
- EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
- TPL_CALLBACK,\r
- CheckThisAPStatus,\r
- (VOID *) CpuData,\r
- &CpuData->CheckThisAPEvent\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
- }\r
+ //\r
+ // Set timer to check all APs status.\r
+ //\r
+ Status = gBS->SetTimer (\r
+ mMpSystemData.CheckAllAPsEvent,\r
+ TimerPeriodic,\r
+ EFI_TIMER_PERIOD_MICROSECONDS (100)\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
\r
//\r
// BSP\r
return EFI_SUCCESS;\r
}\r
\r
+/**\r
+ Callback function for ExitBootServices.\r
+\r
+ @param Event Event whose notification function is being invoked.\r
+ @param Context The pointer to the notification function's context,\r
+ which is implementation-dependent.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+ExitBootServicesCallback (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ //\r
+ // Avoid APs access invalid buff datas which allocated by BootServices,\r
+ // so we send INIT IPI to APs to let them wait for SIPI state.\r
+ //\r
+ SendInitIpiAllExcludingSelf ();\r
+}\r
+\r
/**\r
Initialize Multi-processor support.\r
\r
VOID\r
)\r
{\r
+ EFI_STATUS Status;\r
+\r
gMaxLogicalProcessorNumber = (UINTN) PcdGet32 (PcdCpuMaxLogicalProcessorNumber);\r
if (gMaxLogicalProcessorNumber < 1) {\r
DEBUG ((DEBUG_ERROR, "Setting PcdCpuMaxLogicalProcessorNumber should be more than zero.\n"));\r
\r
InitMpSystemData ();\r
\r
+ PrepareAPStartupCode ();\r
+\r
+ StartApsStackless ();\r
+\r
+ DEBUG ((DEBUG_INFO, "Detect CPU count: %d\n", mMpSystemData.NumberOfProcessors));\r
if (mMpSystemData.NumberOfProcessors == 1) {\r
+ FreeApStartupCode ();\r
FreePages (mCommonStack, EFI_SIZE_TO_PAGES (gMaxLogicalProcessorNumber * gApStackSize));\r
return;\r
}\r
\r
+ mMpSystemData.CpuDatas = ReallocatePool (\r
+ sizeof (CPU_DATA_BLOCK) * gMaxLogicalProcessorNumber,\r
+ sizeof (CPU_DATA_BLOCK) * mMpSystemData.NumberOfProcessors,\r
+ mMpSystemData.CpuDatas);\r
+\r
+ mAPsAlreadyInitFinished = TRUE;\r
+\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &mMpServiceHandle,\r
+ &gEfiMpServiceProtocolGuid, &mMpServicesTemplate,\r
+ NULL\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
if (mMpSystemData.NumberOfProcessors < gMaxLogicalProcessorNumber) {\r
FreePages (mApStackStart, EFI_SIZE_TO_PAGES (\r
(gMaxLogicalProcessorNumber - mMpSystemData.NumberOfProcessors) *\r
gApStackSize));\r
}\r
+\r
+ Status = gBS->CreateEvent (\r
+ EVT_SIGNAL_EXIT_BOOT_SERVICES,\r
+ TPL_CALLBACK,\r
+ ExitBootServicesCallback,\r
+ NULL,\r
+ &mExitBootServicesEvent\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
}\r