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
while (!AcquireSpinLockOrFail (&CpuData->CpuDataLock)) {\r
CpuPause ();\r
}\r
+ CpuData->LockSelf = GetApicId ();\r
}\r
\r
/**\r
Ret = CpuData->Info.StatusFlag & Flags;\r
ReleaseMpSpinLock (CpuData);\r
\r
- return !!(Ret);\r
+ return (BOOLEAN) (Ret != 0);\r
}\r
\r
/**\r
SetApProcedure (&mMpSystemData.CpuDatas[NextNumber],\r
mMpSystemData.Procedure,\r
mMpSystemData.ProcedureArgument);\r
+ //\r
+ // If this AP previous state is blocked, we should\r
+ // wake up this AP by sent a SIPI. and avoid\r
+ // re-involve the sleeping state. we must call\r
+ // SetApProcedure() first.\r
+ //\r
+ ResetProcessorToIdleState (&mMpSystemData.CpuDatas[NextNumber]);\r
}\r
}\r
-\r
SetApState (CpuData, CpuStateIdle);\r
}\r
}\r
}\r
\r
CpuState = GetApState (CpuData);\r
- if (CpuState != CpuStateIdle) {\r
+ if (CpuState != CpuStateIdle &&\r
+ CpuState != CpuStateSleeping) {\r
if (mMpSystemData.FailedList != NULL) {\r
(*mMpSystemData.FailedList)[mMpSystemData.FailedListIndex++] = Number;\r
}\r
CPU_DATA_BLOCK *CpuData;\r
UINTN Number;\r
CPU_STATE APInitialState;\r
+ CPU_STATE CpuState;\r
\r
CpuData = NULL;\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
continue;\r
}\r
\r
- if (GetApState (CpuData) != CpuStateIdle) {\r
+ CpuState = GetApState (CpuData);\r
+ if (CpuState != CpuStateIdle &&\r
+ CpuState != CpuStateSleeping) {\r
return EFI_NOT_READY;\r
}\r
}\r
\r
- //\r
- // temporarily stop checkAllAPsStatus for initialize parameters.\r
- //\r
- mStopCheckAllAPsStatus = TRUE;\r
-\r
mMpSystemData.Procedure = Procedure;\r
mMpSystemData.ProcedureArgument = ProcedureArgument;\r
mMpSystemData.WaitEvent = WaitEvent;\r
mMpSystemData.Timeout = TimeoutInMicroseconds;\r
- mMpSystemData.TimeoutActive = !!(TimeoutInMicroseconds);\r
+ mMpSystemData.TimeoutActive = (BOOLEAN) (TimeoutInMicroseconds != 0);\r
mMpSystemData.FinishCount = 0;\r
mMpSystemData.StartCount = 0;\r
mMpSystemData.SingleThread = SingleThread;\r
// state 1 by 1, until the previous 1 finished its task\r
// if not "SingleThread", all APs are put to ready state from the beginning\r
//\r
- if (GetApState (CpuData) == CpuStateIdle) {\r
+ CpuState = GetApState (CpuData);\r
+ if (CpuState == CpuStateIdle ||\r
+ CpuState == CpuStateSleeping) {\r
mMpSystemData.StartCount++;\r
\r
SetApState (CpuData, APInitialState);\r
\r
if (APInitialState == CpuStateReady) {\r
SetApProcedure (CpuData, Procedure, ProcedureArgument);\r
+ //\r
+ // If this AP previous state is Sleeping, we should\r
+ // wake up this AP by sent a SIPI. and avoid\r
+ // re-involve the sleeping state. we must call\r
+ // SetApProcedure() first.\r
+ //\r
+ if (CpuState == CpuStateSleeping) {\r
+ ResetProcessorToIdleState (CpuData);\r
+ }\r
}\r
\r
if (SingleThread) {\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
+ CPU_STATE CpuState;\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
return EFI_INVALID_PARAMETER;\r
}\r
\r
- if (GetApState (CpuData) != CpuStateIdle) {\r
+ CpuState = GetApState (CpuData);\r
+ if (CpuState != CpuStateIdle &&\r
+ CpuState != CpuStateSleeping) {\r
return EFI_NOT_READY;\r
}\r
\r
- //\r
- // temporarily stop checkAllAPsStatus for initialize parameters.\r
- //\r
- mStopCheckAllAPsStatus = TRUE;\r
-\r
SetApState (CpuData, CpuStateReady);\r
\r
SetApProcedure (CpuData, Procedure, ProcedureArgument);\r
+ //\r
+ // If this AP previous state is Sleeping, we should\r
+ // wake up this AP by sent a SIPI. and avoid\r
+ // re-involve the sleeping state. we must call\r
+ // SetApProcedure() first.\r
+ //\r
+ if (CpuState == CpuStateSleeping) {\r
+ ResetProcessorToIdleState (CpuData);\r
+ }\r
\r
CpuData->Timeout = TimeoutInMicroseconds;\r
CpuData->WaitEvent = WaitEvent;\r
- CpuData->TimeoutActive = !!(TimeoutInMicroseconds);\r
+ CpuData->TimeoutActive = (BOOLEAN) (TimeoutInMicroseconds != 0);\r
CpuData->Finished = Finished;\r
\r
mStopCheckAllAPsStatus = FALSE;\r
)\r
{\r
CPU_DATA_BLOCK *CpuData;\r
+ BOOLEAN TempStopCheckState;\r
+ CPU_STATE CpuState;\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
}\r
\r
- if (GetApState (CpuData) != CpuStateIdle) {\r
+ CpuState = GetApState (CpuData);\r
+ if (CpuState != CpuStateIdle &&\r
+ CpuState != CpuStateSleeping) {\r
return EFI_UNSUPPORTED;\r
}\r
\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
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
- AsmApDoneWithCommonStack ();\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 timeout AP State is not\r
+ // updated.\r
+ //\r
+ GetMpSpinLock (CpuData);\r
+ if (CpuData->State == CpuStateBusy) {\r
+ CpuData->Procedure = NULL;\r
+ }\r
+ CpuData->State = CpuStateIdle;\r
+ ReleaseMpSpinLock (CpuData);\r
\r
while (TRUE) {\r
GetMpSpinLock (CpuData);\r
ReleaseMpSpinLock (CpuData);\r
\r
if (Procedure != NULL) {\r
+ SetApState (CpuData, CpuStateBusy);\r
+\r
Procedure (ProcedureArgument);\r
\r
GetMpSpinLock (CpuData);\r
CpuData->Procedure = NULL;\r
CpuData->State = CpuStateFinished;\r
ReleaseMpSpinLock (CpuData);\r
+ } else {\r
+ //\r
+ // if no procedure to execution, we simply put AP\r
+ // into sleeping state, and waiting BSP sent SIPI.\r
+ //\r
+ GetMpSpinLock (CpuData);\r
+ if (CpuData->State == CpuStateIdle) {\r
+ CpuData->State = CpuStateSleeping;\r
+ }\r
+ ReleaseMpSpinLock (CpuData);\r
+ }\r
+\r
+ if (GetApState (CpuData) == CpuStateSleeping) {\r
+ CpuSleep ();\r
}\r
\r
CpuPause ();\r
//\r
for (Number = 0; Number < mMpSystemData.NumberOfProcessors; Number++) {\r
CpuData = &mMpSystemData.CpuDatas[Number];\r
- if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT)) {\r
- //\r
- // Skip BSP\r
- //\r
- continue;\r
- }\r
-\r
- if (!TestCpuStatusFlag (CpuData, PROCESSOR_ENABLED_BIT)) {\r
- //\r
- // Skip Disabled processors\r
- //\r
- continue;\r
- }\r
-\r
if (CpuData->WaitEvent) {\r
CheckThisAPStatus (NULL, (VOID *)CpuData);\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->Info.Location.Package = ProcessorId;\r
CpuData->Info.Location.Core = 0;\r
CpuData->Info.Location.Thread = 0;\r
- CpuData->State = Bsp ? CpuStateBuzy : CpuStateIdle;\r
+ CpuData->State = Bsp ? CpuStateBusy : CpuStateIdle;\r
\r
CpuData->Procedure = NULL;\r
CpuData->Parameter = NULL;\r
InitializeSpinLock (&CpuData->CpuDataLock);\r
+ CpuData->LockSelf = -1;\r
\r
return EFI_SUCCESS;\r
}\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
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