)\r
{\r
UINTN Index;\r
- UINTN BspIndex;\r
\r
- BspIndex = mSmmMpSyncData->BspIndex;\r
for (Index = mMaxNumberOfCpus; Index-- > 0;) {\r
- if (Index != BspIndex && *(mSmmMpSyncData->CpuData[Index].Present)) {\r
+ if (IsPresentAp (Index)) {\r
ReleaseSemaphore (mSmmMpSyncData->CpuData[Index].Run);\r
}\r
}\r
MtrrSetAllMtrrs (&gSmiMtrrs);\r
}\r
\r
+/**\r
+ Wheck whether task has been finished by all APs.\r
+\r
+ @param BlockMode Whether did it in block mode or non-block mode.\r
+\r
+ @retval TRUE Task has been finished by all APs.\r
+ @retval FALSE Task not has been finished by all APs.\r
+\r
+**/\r
+BOOLEAN\r
+WaitForAllAPsNotBusy (\r
+ IN BOOLEAN BlockMode\r
+ )\r
+{\r
+ UINTN Index;\r
+\r
+ for (Index = mMaxNumberOfCpus; Index-- > 0;) {\r
+ //\r
+ // Ignore BSP and APs which not call in SMM.\r
+ //\r
+ if (!IsPresentAp(Index)) {\r
+ continue;\r
+ }\r
+\r
+ if (BlockMode) {\r
+ AcquireSpinLock(mSmmMpSyncData->CpuData[Index].Busy);\r
+ ReleaseSpinLock(mSmmMpSyncData->CpuData[Index].Busy);\r
+ } else {\r
+ if (AcquireSpinLockOrFail (mSmmMpSyncData->CpuData[Index].Busy)) {\r
+ ReleaseSpinLock(mSmmMpSyncData->CpuData[Index].Busy);\r
+ } else {\r
+ return FALSE;\r
+ }\r
+ }\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ Check whether it is an present AP.\r
+\r
+ @param CpuIndex The AP index which calls this function.\r
+\r
+ @retval TRUE It's a present AP.\r
+ @retval TRUE This is not an AP or it is not present.\r
+\r
+**/\r
+BOOLEAN\r
+IsPresentAp (\r
+ IN UINTN CpuIndex\r
+ )\r
+{\r
+ return ((CpuIndex != gSmmCpuPrivate->SmmCoreEntryContext.CurrentlyExecutingCpu) &&\r
+ *(mSmmMpSyncData->CpuData[CpuIndex].Present));\r
+}\r
+\r
+/**\r
+ Check whether execute in single AP or all APs.\r
+\r
+ Compare two Tokens used by different APs to know whether in StartAllAps call.\r
+\r
+ Whether is an valid AP base on AP's Present flag.\r
+\r
+ @retval TRUE IN StartAllAps call.\r
+ @retval FALSE Not in StartAllAps call.\r
+\r
+**/\r
+BOOLEAN\r
+InStartAllApsCall (\r
+ VOID\r
+ )\r
+{\r
+ UINTN ApIndex;\r
+ UINTN ApIndex2;\r
+\r
+ for (ApIndex = mMaxNumberOfCpus; ApIndex-- > 0;) {\r
+ if (IsPresentAp (ApIndex) && (mSmmMpSyncData->CpuData[ApIndex].Token != NULL)) {\r
+ for (ApIndex2 = ApIndex; ApIndex2-- > 0;) {\r
+ if (IsPresentAp (ApIndex2) && (mSmmMpSyncData->CpuData[ApIndex2].Token != NULL)) {\r
+ return mSmmMpSyncData->CpuData[ApIndex2].Token == mSmmMpSyncData->CpuData[ApIndex].Token;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+/**\r
+ Clean up the status flags used during executing the procedure.\r
+\r
+ @param CpuIndex The AP index which calls this function.\r
+\r
+**/\r
+VOID\r
+ReleaseToken (\r
+ IN UINTN CpuIndex\r
+ )\r
+{\r
+ UINTN Index;\r
+ BOOLEAN Released;\r
+\r
+ if (InStartAllApsCall ()) {\r
+ //\r
+ // In Start All APs mode, make sure all APs have finished task.\r
+ //\r
+ if (WaitForAllAPsNotBusy (FALSE)) {\r
+ //\r
+ // Clean the flags update in the function call.\r
+ //\r
+ Released = FALSE;\r
+ for (Index = mMaxNumberOfCpus; Index-- > 0;) {\r
+ //\r
+ // Only In SMM APs need to be clean up.\r
+ //\r
+ if (mSmmMpSyncData->CpuData[Index].Present && mSmmMpSyncData->CpuData[Index].Token != NULL) {\r
+ if (!Released) {\r
+ ReleaseSpinLock (mSmmMpSyncData->CpuData[Index].Token);\r
+ Released = TRUE;\r
+ }\r
+ mSmmMpSyncData->CpuData[Index].Token = NULL;\r
+ }\r
+ }\r
+ }\r
+ } else {\r
+ //\r
+ // In single AP mode.\r
+ //\r
+ if (mSmmMpSyncData->CpuData[CpuIndex].Token != NULL) {\r
+ ReleaseSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Token);\r
+ mSmmMpSyncData->CpuData[CpuIndex].Token = NULL;\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ Free the tokens in the maintained list.\r
+\r
+**/\r
+VOID\r
+FreeTokens (\r
+ VOID\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ PROCEDURE_TOKEN *ProcToken;\r
+\r
+ while (!IsListEmpty (&gSmmCpuPrivate->TokenList)) {\r
+ Link = GetFirstNode (&gSmmCpuPrivate->TokenList);\r
+ ProcToken = PROCEDURE_TOKEN_FROM_LINK (Link);\r
+\r
+ RemoveEntryList (&ProcToken->Link);\r
+\r
+ FreePool ((VOID *)ProcToken->ProcedureToken);\r
+ FreePool (ProcToken);\r
+ }\r
+}\r
+\r
/**\r
SMI handler for BSP.\r
\r
//\r
// Make sure all APs have completed their pending none-block tasks\r
//\r
- for (Index = mMaxNumberOfCpus; Index-- > 0;) {\r
- if (Index != CpuIndex && *(mSmmMpSyncData->CpuData[Index].Present)) {\r
- AcquireSpinLock (mSmmMpSyncData->CpuData[Index].Busy);\r
- ReleaseSpinLock (mSmmMpSyncData->CpuData[Index].Busy);\r
- }\r
- }\r
+ WaitForAllAPsNotBusy (TRUE);\r
\r
//\r
// Perform the remaining tasks\r
//\r
WaitForAllAPs (ApCount);\r
\r
+ //\r
+ // Clean the tokens buffer.\r
+ //\r
+ FreeTokens ();\r
+\r
//\r
// Reset BspIndex to -1, meaning BSP has not been elected.\r
//\r
UINT64 Timer;\r
UINTN BspIndex;\r
MTRR_SETTINGS Mtrrs;\r
+ EFI_STATUS ProcedureStatus;\r
\r
//\r
// Timeout BSP\r
//\r
// Invoke the scheduled procedure\r
//\r
- (*mSmmMpSyncData->CpuData[CpuIndex].Procedure) (\r
- (VOID*)mSmmMpSyncData->CpuData[CpuIndex].Parameter\r
- );\r
+ ProcedureStatus = (*mSmmMpSyncData->CpuData[CpuIndex].Procedure) (\r
+ (VOID*)mSmmMpSyncData->CpuData[CpuIndex].Parameter\r
+ );\r
+ if (mSmmMpSyncData->CpuData[CpuIndex].Status != NULL) {\r
+ *mSmmMpSyncData->CpuData[CpuIndex].Status = ProcedureStatus;\r
+ }\r
\r
//\r
// Release BUSY\r
//\r
ReleaseSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy);\r
+\r
+ ReleaseToken (CpuIndex);\r
}\r
\r
if (SmmCpuFeaturesNeedConfigureMtrrs()) {\r
return (UINT32)(UINTN)PageTable;\r
}\r
\r
+/**\r
+ Checks whether the input token is the current used token.\r
+\r
+ @param[in] Token This parameter describes the token that was passed into DispatchProcedure or\r
+ BroadcastProcedure.\r
+\r
+ @retval TRUE The input token is the current used token.\r
+ @retval FALSE The input token is not the current used token.\r
+**/\r
+BOOLEAN\r
+IsTokenInUse (\r
+ IN SPIN_LOCK *Token\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ PROCEDURE_TOKEN *ProcToken;\r
+\r
+ if (Token == NULL) {\r
+ return FALSE;\r
+ }\r
+\r
+ Link = GetFirstNode (&gSmmCpuPrivate->TokenList);\r
+ while (!IsNull (&gSmmCpuPrivate->TokenList, Link)) {\r
+ ProcToken = PROCEDURE_TOKEN_FROM_LINK (Link);\r
+\r
+ if (ProcToken->ProcedureToken == Token) {\r
+ return TRUE;\r
+ }\r
+\r
+ Link = GetNextNode (&gSmmCpuPrivate->TokenList, Link);\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+/**\r
+ create token and save it to the maintain list.\r
+\r
+ @retval return the spin lock used as token.\r
+\r
+**/\r
+SPIN_LOCK *\r
+CreateToken (\r
+ VOID\r
+ )\r
+{\r
+ PROCEDURE_TOKEN *ProcToken;\r
+ SPIN_LOCK *CpuToken;\r
+ UINTN SpinLockSize;\r
+\r
+ SpinLockSize = GetSpinLockProperties ();\r
+ CpuToken = AllocatePool (SpinLockSize);\r
+ ASSERT (CpuToken != NULL);\r
+ InitializeSpinLock (CpuToken);\r
+ AcquireSpinLock (CpuToken);\r
+\r
+ ProcToken = AllocatePool (sizeof (PROCEDURE_TOKEN));\r
+ ASSERT (ProcToken != NULL);\r
+ ProcToken->Signature = PROCEDURE_TOKEN_SIGNATURE;\r
+ ProcToken->ProcedureToken = CpuToken;\r
+\r
+ InsertTailList (&gSmmCpuPrivate->TokenList, &ProcToken->Link);\r
+\r
+ return CpuToken;\r
+}\r
+\r
+/**\r
+ Checks status of specified AP.\r
+\r
+ This function checks whether the specified AP has finished the task assigned\r
+ by StartupThisAP(), and whether timeout expires.\r
+\r
+ @param[in] Token This parameter describes the token that was passed into DispatchProcedure or\r
+ BroadcastProcedure.\r
+\r
+ @retval EFI_SUCCESS Specified AP has finished task assigned by StartupThisAPs().\r
+ @retval EFI_NOT_READY Specified AP has not finished task and timeout has not expired.\r
+**/\r
+EFI_STATUS\r
+IsApReady (\r
+ IN SPIN_LOCK *Token\r
+ )\r
+{\r
+ if (AcquireSpinLockOrFail (Token)) {\r
+ ReleaseSpinLock (Token);\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ return EFI_NOT_READY;\r
+}\r
+\r
/**\r
Schedule a procedure to run on the specified CPU.\r
\r
@param[in] Procedure The address of the procedure to run\r
@param[in] CpuIndex Target CPU Index\r
- @param[in, out] ProcArguments The parameter to pass to the procedure\r
- @param[in] BlockingMode Startup AP in blocking mode or not\r
+ @param[in,out] ProcArguments The parameter to pass to the procedure\r
+ @param[in] Token This is an optional parameter that allows the caller to execute the\r
+ procedure in a blocking or non-blocking fashion. If it is NULL the\r
+ call is blocking, and the call will not return until the AP has\r
+ completed the procedure. If the token is not NULL, the call will\r
+ return immediately. The caller can check whether the procedure has\r
+ completed with CheckOnProcedure or WaitForProcedure.\r
+ @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for the APs to finish\r
+ execution of Procedure, either for blocking or non-blocking mode.\r
+ Zero means infinity. If the timeout expires before all APs return\r
+ from Procedure, then Procedure on the failed APs is terminated. If\r
+ the timeout expires in blocking mode, the call returns EFI_TIMEOUT.\r
+ If the timeout expires in non-blocking mode, the timeout determined\r
+ can be through CheckOnProcedure or WaitForProcedure.\r
+ Note that timeout support is optional. Whether an implementation\r
+ supports this feature can be determined via the Attributes data\r
+ member.\r
+ @param[in,out] CpuStatus This optional pointer may be used to get the status code returned\r
+ by Procedure when it completes execution on the target AP, or with\r
+ EFI_TIMEOUT if the Procedure fails to complete within the optional\r
+ timeout. The implementation will update this variable with\r
+ EFI_NOT_READY prior to starting Procedure on the target AP.\r
\r
@retval EFI_INVALID_PARAMETER CpuNumber not valid\r
@retval EFI_INVALID_PARAMETER CpuNumber specifying BSP\r
**/\r
EFI_STATUS\r
InternalSmmStartupThisAp (\r
- IN EFI_AP_PROCEDURE Procedure,\r
- IN UINTN CpuIndex,\r
- IN OUT VOID *ProcArguments OPTIONAL,\r
- IN BOOLEAN BlockingMode\r
+ IN EFI_AP_PROCEDURE2 Procedure,\r
+ IN UINTN CpuIndex,\r
+ IN OUT VOID *ProcArguments OPTIONAL,\r
+ IN MM_COMPLETION *Token,\r
+ IN UINTN TimeoutInMicroseconds,\r
+ IN OUT EFI_STATUS *CpuStatus\r
)\r
{\r
if (CpuIndex >= gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus) {\r
}\r
return EFI_INVALID_PARAMETER;\r
}\r
+ if ((TimeoutInMicroseconds != 0) && ((mSmmMp.Attributes & EFI_MM_MP_TIMEOUT_SUPPORTED) == 0)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ if (Procedure == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
\r
- if (BlockingMode) {\r
+ if (Token == NULL) {\r
AcquireSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy);\r
} else {\r
if (!AcquireSpinLockOrFail (mSmmMpSyncData->CpuData[CpuIndex].Busy)) {\r
- DEBUG((DEBUG_ERROR, "mSmmMpSyncData->CpuData[%d].Busy\n", CpuIndex));\r
- return EFI_INVALID_PARAMETER;\r
+ DEBUG((DEBUG_ERROR, "Can't acquire mSmmMpSyncData->CpuData[%d].Busy\n", CpuIndex));\r
+ return EFI_NOT_READY;\r
}\r
+\r
+ *Token = (MM_COMPLETION) CreateToken ();\r
}\r
\r
mSmmMpSyncData->CpuData[CpuIndex].Procedure = Procedure;\r
mSmmMpSyncData->CpuData[CpuIndex].Parameter = ProcArguments;\r
+ if (Token != NULL) {\r
+ mSmmMpSyncData->CpuData[CpuIndex].Token = (SPIN_LOCK *)(*Token);\r
+ }\r
+ mSmmMpSyncData->CpuData[CpuIndex].Status = CpuStatus;\r
+ if (mSmmMpSyncData->CpuData[CpuIndex].Status != NULL) {\r
+ *mSmmMpSyncData->CpuData[CpuIndex].Status = EFI_NOT_READY;\r
+ }\r
+\r
ReleaseSemaphore (mSmmMpSyncData->CpuData[CpuIndex].Run);\r
\r
- if (BlockingMode) {\r
+ if (Token == NULL) {\r
AcquireSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy);\r
ReleaseSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy);\r
}\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Worker function to execute a caller provided function on all enabled APs.\r
+\r
+ @param[in] Procedure A pointer to the function to be run on\r
+ enabled APs of the system.\r
+ @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for\r
+ APs to return from Procedure, either for\r
+ blocking or non-blocking mode.\r
+ @param[in,out] ProcedureArguments The parameter passed into Procedure for\r
+ all APs.\r
+ @param[in,out] Token This is an optional parameter that allows the caller to execute the\r
+ procedure in a blocking or non-blocking fashion. If it is NULL the\r
+ call is blocking, and the call will not return until the AP has\r
+ completed the procedure. If the token is not NULL, the call will\r
+ return immediately. The caller can check whether the procedure has\r
+ completed with CheckOnProcedure or WaitForProcedure.\r
+ @param[in,out] CPUStatus This optional pointer may be used to get the status code returned\r
+ by Procedure when it completes execution on the target AP, or with\r
+ EFI_TIMEOUT if the Procedure fails to complete within the optional\r
+ timeout. The implementation will update this variable with\r
+ EFI_NOT_READY prior to starting Procedure on the target AP.\r
+\r
+\r
+ @retval EFI_SUCCESS In blocking mode, all APs have finished before\r
+ the timeout expired.\r
+ @retval EFI_SUCCESS In non-blocking mode, function has been dispatched\r
+ to all enabled APs.\r
+ @retval others Failed to Startup all APs.\r
+\r
+**/\r
+EFI_STATUS\r
+InternalSmmStartupAllAPs (\r
+ IN EFI_AP_PROCEDURE2 Procedure,\r
+ IN UINTN TimeoutInMicroseconds,\r
+ IN OUT VOID *ProcedureArguments OPTIONAL,\r
+ IN OUT MM_COMPLETION *Token,\r
+ IN OUT EFI_STATUS *CPUStatus\r
+ )\r
+{\r
+ UINTN Index;\r
+ UINTN CpuCount;\r
+\r
+ if ((TimeoutInMicroseconds != 0) && ((mSmmMp.Attributes & EFI_MM_MP_TIMEOUT_SUPPORTED) == 0)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ if (Procedure == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ CpuCount = 0;\r
+ for (Index = mMaxNumberOfCpus; Index-- > 0;) {\r
+ if (IsPresentAp (Index)) {\r
+ CpuCount ++;\r
+\r
+ if (gSmmCpuPrivate->Operation[Index] == SmmCpuRemove) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (!AcquireSpinLockOrFail(mSmmMpSyncData->CpuData[Index].Busy)) {\r
+ return EFI_NOT_READY;\r
+ }\r
+ ReleaseSpinLock (mSmmMpSyncData->CpuData[Index].Busy);\r
+ }\r
+ }\r
+ if (CpuCount == 0) {\r
+ return EFI_NOT_STARTED;\r
+ }\r
+\r
+ if (Token != NULL) {\r
+ *Token = (MM_COMPLETION) CreateToken ();\r
+ }\r
+\r
+ //\r
+ // Make sure all BUSY should be acquired.\r
+ //\r
+ // Because former code already check mSmmMpSyncData->CpuData[***].Busy for each AP.\r
+ // Here code always use AcquireSpinLock instead of AcquireSpinLockOrFail for not\r
+ // block mode.\r
+ //\r
+ for (Index = mMaxNumberOfCpus; Index-- > 0;) {\r
+ if (IsPresentAp (Index)) {\r
+ AcquireSpinLock (mSmmMpSyncData->CpuData[Index].Busy);\r
+ }\r
+ }\r
+\r
+ for (Index = mMaxNumberOfCpus; Index-- > 0;) {\r
+ if (IsPresentAp (Index)) {\r
+ mSmmMpSyncData->CpuData[Index].Procedure = (EFI_AP_PROCEDURE2) Procedure;\r
+ mSmmMpSyncData->CpuData[Index].Parameter = ProcedureArguments;\r
+ if (Token != NULL) {\r
+ mSmmMpSyncData->CpuData[Index].Token = (SPIN_LOCK *)(*Token);\r
+ }\r
+ if (CPUStatus != NULL) {\r
+ mSmmMpSyncData->CpuData[Index].Status = &CPUStatus[Index];\r
+ if (mSmmMpSyncData->CpuData[Index].Status != NULL) {\r
+ *mSmmMpSyncData->CpuData[Index].Status = EFI_NOT_READY;\r
+ }\r
+ }\r
+ } else {\r
+ //\r
+ // PI spec requirement:\r
+ // For every excluded processor, the array entry must contain a value of EFI_NOT_STARTED.\r
+ //\r
+ if (CPUStatus != NULL) {\r
+ CPUStatus[Index] = EFI_NOT_STARTED;\r
+ }\r
+ }\r
+ }\r
+\r
+ ReleaseAllAPs ();\r
+\r
+ if (Token == NULL) {\r
+ //\r
+ // Make sure all APs have completed their tasks.\r
+ //\r
+ WaitForAllAPsNotBusy (TRUE);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ ISO C99 6.5.2.2 "Function calls", paragraph 9:\r
+ If the function is defined with a type that is not compatible with\r
+ the type (of the expression) pointed to by the expression that\r
+ denotes the called function, the behavior is undefined.\r
+\r
+ So add below wrapper function to convert between EFI_AP_PROCEDURE\r
+ and EFI_AP_PROCEDURE2.\r
+\r
+ Wrapper for Procedures.\r
+\r
+ @param[in] Buffer Pointer to PROCEDURE_WRAPPER buffer.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ProcedureWrapper (\r
+ IN OUT VOID *Buffer\r
+ )\r
+{\r
+ PROCEDURE_WRAPPER *Wrapper;\r
+\r
+ Wrapper = Buffer;\r
+ Wrapper->Procedure (Wrapper->ProcedureArgument);\r
+\r
return EFI_SUCCESS;\r
}\r
\r
IN OUT VOID *ProcArguments OPTIONAL\r
)\r
{\r
- return InternalSmmStartupThisAp(Procedure, CpuIndex, ProcArguments, TRUE);\r
+ PROCEDURE_WRAPPER Wrapper;\r
+\r
+ Wrapper.Procedure = Procedure;\r
+ Wrapper.ProcedureArgument = ProcArguments;\r
+\r
+ //\r
+ // Use wrapper function to convert EFI_AP_PROCEDURE to EFI_AP_PROCEDURE2.\r
+ //\r
+ return InternalSmmStartupThisAp (ProcedureWrapper, CpuIndex, &Wrapper, NULL, 0, NULL);\r
}\r
\r
/**\r
IN OUT VOID *ProcArguments OPTIONAL\r
)\r
{\r
- return InternalSmmStartupThisAp(Procedure, CpuIndex, ProcArguments, FeaturePcdGet (PcdCpuSmmBlockStartupThisAp));\r
+ MM_COMPLETION Token;\r
+\r
+ gSmmCpuPrivate->ApWrapperFunc[CpuIndex].Procedure = Procedure;\r
+ gSmmCpuPrivate->ApWrapperFunc[CpuIndex].ProcedureArgument = ProcArguments;\r
+\r
+ //\r
+ // Use wrapper function to convert EFI_AP_PROCEDURE to EFI_AP_PROCEDURE2.\r
+ //\r
+ return InternalSmmStartupThisAp (\r
+ ProcedureWrapper,\r
+ CpuIndex,\r
+ &gSmmCpuPrivate->ApWrapperFunc[CpuIndex],\r
+ FeaturePcdGet (PcdCpuSmmBlockStartupThisAp) ? NULL : &Token,\r
+ 0,\r
+ NULL\r
+ );\r
}\r
\r
/**\r
Cr2 = 0;\r
SaveCr2 (&Cr2);\r
\r
+ //\r
+ // Call the user register Startup function first.\r
+ //\r
+ if (mSmmMpSyncData->StartupProcedure != NULL) {\r
+ mSmmMpSyncData->StartupProcedure (mSmmMpSyncData->StartupProcArgs);\r
+ }\r
+\r
//\r
// Perform CPU specific entry hooks\r
//\r
RestoreCr2 (Cr2);\r
}\r
\r
+/**\r
+ Allocate buffer for SpinLock and Wrapper function buffer.\r
+\r
+**/\r
+VOID\r
+InitializeDataForMmMp (\r
+ VOID\r
+ )\r
+{\r
+ gSmmCpuPrivate->ApWrapperFunc = AllocatePool (sizeof (PROCEDURE_WRAPPER) * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus);\r
+ ASSERT (gSmmCpuPrivate->ApWrapperFunc != NULL);\r
+\r
+ InitializeListHead (&gSmmCpuPrivate->TokenList);\r
+}\r
+\r
/**\r
Allocate buffer for all semaphores and spin locks.\r
\r
gSmmCpuPrivate->SmmCoreEntry = SmmEntryPoint;\r
return EFI_SUCCESS;\r
}\r
+\r
+/**\r
+\r
+ Register the SMM Foundation entry point.\r
+\r
+ @param[in] Procedure A pointer to the code stream to be run on the designated target AP\r
+ of the system. Type EFI_AP_PROCEDURE is defined below in Volume 2\r
+ with the related definitions of\r
+ EFI_MP_SERVICES_PROTOCOL.StartupAllAPs.\r
+ If caller may pass a value of NULL to deregister any existing\r
+ startup procedure.\r
+ @param[in] ProcedureArguments Allows the caller to pass a list of parameters to the code that is\r
+ run by the AP. It is an optional common mailbox between APs and\r
+ the caller to share information\r
+\r
+ @retval EFI_SUCCESS The Procedure has been set successfully.\r
+ @retval EFI_INVALID_PARAMETER The Procedure is NULL but ProcedureArguments not NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+RegisterStartupProcedure (\r
+ IN EFI_AP_PROCEDURE Procedure,\r
+ IN VOID *ProcedureArguments OPTIONAL\r
+ )\r
+{\r
+ if (Procedure == NULL && ProcedureArguments != NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ if (mSmmMpSyncData == NULL) {\r
+ return EFI_NOT_READY;\r
+ }\r
+\r
+ mSmmMpSyncData->StartupProcedure = Procedure;\r
+ mSmmMpSyncData->StartupProcArgs = ProcedureArguments;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
mSmmCpuPrivateData.SmmReservedSmramRegion, // SmmConfiguration.SmramReservedRegions\r
RegisterSmmEntry // SmmConfiguration.RegisterSmmEntry\r
},\r
+ NULL, // pointer to Ap Wrapper Func array\r
+ {NULL, NULL}, // List_Entry for Tokens.\r
};\r
\r
CPU_HOT_PLUG_DATA mCpuHotPlugData = {\r
);\r
ASSERT_EFI_ERROR (Status);\r
\r
+ //\r
+ // Initialize global buffer for MM MP.\r
+ //\r
+ InitializeDataForMmMp ();\r
+\r
+ //\r
+ // Install the SMM Mp Protocol into SMM protocol database\r
+ //\r
+ Status = gSmst->SmmInstallProtocolInterface (\r
+ &mSmmCpuHandle,\r
+ &gEfiMmMpProtocolGuid,\r
+ EFI_NATIVE_INTERFACE,\r
+ &mSmmMp\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
//\r
// Expose address of CPU Hot Plug Data structure if CPU hot plug is supported.\r
//\r
#include <Protocol/SmmReadyToLock.h>\r
#include <Protocol/SmmCpuService.h>\r
#include <Protocol/SmmMemoryAttribute.h>\r
+#include <Protocol/MmMp.h>\r
\r
#include <Guid/AcpiS3Context.h>\r
#include <Guid/MemoryAttributesTable.h>\r
#define ARRIVAL_EXCEPTION_DELAYED 0x2\r
#define ARRIVAL_EXCEPTION_SMI_DISABLED 0x4\r
\r
+//\r
+// Wrapper used to convert EFI_AP_PROCEDURE2 and EFI_AP_PROCEDURE.\r
+//\r
+typedef struct {\r
+ EFI_AP_PROCEDURE Procedure;\r
+ VOID *ProcedureArgument;\r
+} PROCEDURE_WRAPPER;\r
+\r
+#define PROCEDURE_TOKEN_SIGNATURE SIGNATURE_32 ('P', 'R', 'T', 'S')\r
+\r
+typedef struct {\r
+ UINTN Signature;\r
+ LIST_ENTRY Link;\r
+\r
+ SPIN_LOCK *ProcedureToken;\r
+} PROCEDURE_TOKEN;\r
+\r
+#define PROCEDURE_TOKEN_FROM_LINK(a) CR (a, PROCEDURE_TOKEN, Link, PROCEDURE_TOKEN_SIGNATURE)\r
+\r
//\r
// Private structure for the SMM CPU module that is stored in DXE Runtime memory\r
// Contains the SMM Configuration Protocols that is produced.\r
EFI_SMM_ENTRY_POINT SmmCoreEntry;\r
\r
EFI_SMM_CONFIGURATION_PROTOCOL SmmConfiguration;\r
+\r
+ PROCEDURE_WRAPPER *ApWrapperFunc;\r
+ LIST_ENTRY TokenList;\r
+\r
} SMM_CPU_PRIVATE_DATA;\r
\r
extern SMM_CPU_PRIVATE_DATA *gSmmCpuPrivate;\r
extern UINTN mMaxNumberOfCpus;\r
extern UINTN mNumberOfCpus;\r
extern EFI_SMM_CPU_PROTOCOL mSmmCpu;\r
+extern EFI_MM_MP_PROTOCOL mSmmMp;\r
\r
///\r
/// The mode of the CPU at the time an SMI occurs\r
///\r
typedef struct {\r
SPIN_LOCK *Busy;\r
- volatile EFI_AP_PROCEDURE Procedure;\r
+ volatile EFI_AP_PROCEDURE2 Procedure;\r
volatile VOID *Parameter;\r
volatile UINT32 *Run;\r
volatile BOOLEAN *Present;\r
+ SPIN_LOCK *Token;\r
+ EFI_STATUS *Status;\r
} SMM_CPU_DATA_BLOCK;\r
\r
typedef enum {\r
volatile SMM_CPU_SYNC_MODE EffectiveSyncMode;\r
volatile BOOLEAN SwitchBsp;\r
volatile BOOLEAN *CandidateBsp;\r
+ EFI_AP_PROCEDURE StartupProcedure;\r
+ VOID *StartupProcArgs;\r
} SMM_DISPATCHER_MP_SYNC_DATA;\r
\r
#define SMM_PSD_OFFSET 0xfb00\r
SPIN_LOCK *Busy;\r
volatile UINT32 *Run;\r
volatile BOOLEAN *Present;\r
+ SPIN_LOCK *Token;\r
} SMM_CPU_SEMAPHORE_CPU;\r
\r
///\r
IN UINTN Cr2\r
);\r
\r
+/**\r
+ Schedule a procedure to run on the specified CPU.\r
+\r
+ @param[in] Procedure The address of the procedure to run\r
+ @param[in] CpuIndex Target CPU Index\r
+ @param[in,out] ProcArguments The parameter to pass to the procedure\r
+ @param[in,out] Token This is an optional parameter that allows the caller to execute the\r
+ procedure in a blocking or non-blocking fashion. If it is NULL the\r
+ call is blocking, and the call will not return until the AP has\r
+ completed the procedure. If the token is not NULL, the call will\r
+ return immediately. The caller can check whether the procedure has\r
+ completed with CheckOnProcedure or WaitForProcedure.\r
+ @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for the APs to finish\r
+ execution of Procedure, either for blocking or non-blocking mode.\r
+ Zero means infinity. If the timeout expires before all APs return\r
+ from Procedure, then Procedure on the failed APs is terminated. If\r
+ the timeout expires in blocking mode, the call returns EFI_TIMEOUT.\r
+ If the timeout expires in non-blocking mode, the timeout determined\r
+ can be through CheckOnProcedure or WaitForProcedure.\r
+ Note that timeout support is optional. Whether an implementation\r
+ supports this feature can be determined via the Attributes data\r
+ member.\r
+ @param[in,out] CPUStatus This optional pointer may be used to get the status code returned\r
+ by Procedure when it completes execution on the target AP, or with\r
+ EFI_TIMEOUT if the Procedure fails to complete within the optional\r
+ timeout. The implementation will update this variable with\r
+ EFI_NOT_READY prior to starting Procedure on the target AP.\r
+\r
+ @retval EFI_INVALID_PARAMETER CpuNumber not valid\r
+ @retval EFI_INVALID_PARAMETER CpuNumber specifying BSP\r
+ @retval EFI_INVALID_PARAMETER The AP specified by CpuNumber did not enter SMM\r
+ @retval EFI_INVALID_PARAMETER The AP specified by CpuNumber is busy\r
+ @retval EFI_SUCCESS The procedure has been successfully scheduled\r
+\r
+**/\r
+EFI_STATUS\r
+InternalSmmStartupThisAp (\r
+ IN EFI_AP_PROCEDURE2 Procedure,\r
+ IN UINTN CpuIndex,\r
+ IN OUT VOID *ProcArguments OPTIONAL,\r
+ IN MM_COMPLETION *Token,\r
+ IN UINTN TimeoutInMicroseconds,\r
+ IN OUT EFI_STATUS *CpuStatus\r
+ );\r
+\r
+/**\r
+ Checks whether the input token is the current used token.\r
+\r
+ @param[in] Token This parameter describes the token that was passed into DispatchProcedure or\r
+ BroadcastProcedure.\r
+\r
+ @retval TRUE The input token is the current used token.\r
+ @retval FALSE The input token is not the current used token.\r
+**/\r
+BOOLEAN\r
+IsTokenInUse (\r
+ IN SPIN_LOCK *Token\r
+ );\r
+\r
+/**\r
+ Checks status of specified AP.\r
+\r
+ This function checks whether the specified AP has finished the task assigned\r
+ by StartupThisAP(), and whether timeout expires.\r
+\r
+ @param[in] Token This parameter describes the token that was passed into DispatchProcedure or\r
+ BroadcastProcedure.\r
+\r
+ @retval EFI_SUCCESS Specified AP has finished task assigned by StartupThisAPs().\r
+ @retval EFI_NOT_READY Specified AP has not finished task and timeout has not expired.\r
+**/\r
+EFI_STATUS\r
+IsApReady (\r
+ IN SPIN_LOCK *Token\r
+ );\r
+\r
+/**\r
+ Check whether it is an present AP.\r
+\r
+ @param CpuIndex The AP index which calls this function.\r
+\r
+ @retval TRUE It's a present AP.\r
+ @retval TRUE This is not an AP or it is not present.\r
+\r
+**/\r
+BOOLEAN\r
+IsPresentAp (\r
+ IN UINTN CpuIndex\r
+ );\r
+\r
+/**\r
+ Worker function to execute a caller provided function on all enabled APs.\r
+\r
+ @param[in] Procedure A pointer to the function to be run on\r
+ enabled APs of the system.\r
+ @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for\r
+ APs to return from Procedure, either for\r
+ blocking or non-blocking mode.\r
+ @param[in,out] ProcedureArgument The parameter passed into Procedure for\r
+ all APs.\r
+ @param[in,out] Token This is an optional parameter that allows the caller to execute the\r
+ procedure in a blocking or non-blocking fashion. If it is NULL the\r
+ call is blocking, and the call will not return until the AP has\r
+ completed the procedure. If the token is not NULL, the call will\r
+ return immediately. The caller can check whether the procedure has\r
+ completed with CheckOnProcedure or WaitForProcedure.\r
+ @param[in,out] CPUStatus This optional pointer may be used to get the status code returned\r
+ by Procedure when it completes execution on the target AP, or with\r
+ EFI_TIMEOUT if the Procedure fails to complete within the optional\r
+ timeout. The implementation will update this variable with\r
+ EFI_NOT_READY prior to starting Procedure on the target AP.\r
+\r
+ @retval EFI_SUCCESS In blocking mode, all APs have finished before\r
+ the timeout expired.\r
+ @retval EFI_SUCCESS In non-blocking mode, function has been dispatched\r
+ to all enabled APs.\r
+ @retval others Failed to Startup all APs.\r
+\r
+**/\r
+EFI_STATUS\r
+InternalSmmStartupAllAPs (\r
+ IN EFI_AP_PROCEDURE2 Procedure,\r
+ IN UINTN TimeoutInMicroseconds,\r
+ IN OUT VOID *ProcedureArguments OPTIONAL,\r
+ IN OUT MM_COMPLETION *Token,\r
+ IN OUT EFI_STATUS *CPUStatus\r
+ );\r
+\r
+/**\r
+\r
+ Register the SMM Foundation entry point.\r
+\r
+ @param[in] Procedure A pointer to the code stream to be run on the designated target AP\r
+ of the system. Type EFI_AP_PROCEDURE is defined below in Volume 2\r
+ with the related definitions of\r
+ EFI_MP_SERVICES_PROTOCOL.StartupAllAPs.\r
+ If caller may pass a value of NULL to deregister any existing\r
+ startup procedure.\r
+ @param[in,out] ProcedureArguments Allows the caller to pass a list of parameters to the code that is\r
+ run by the AP. It is an optional common mailbox between APs and\r
+ the caller to share information\r
+\r
+ @retval EFI_SUCCESS The Procedure has been set successfully.\r
+ @retval EFI_INVALID_PARAMETER The Procedure is NULL but ProcedureArguments not NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+RegisterStartupProcedure (\r
+ IN EFI_AP_PROCEDURE Procedure,\r
+ IN VOID *ProcedureArguments OPTIONAL\r
+ );\r
+\r
+/**\r
+ Allocate buffer for SpinLock and Wrapper function buffer.\r
+\r
+**/\r
+VOID\r
+InitializeDataForMmMp (\r
+ VOID\r
+ );\r
+\r
#endif\r
SmmProfileInternal.h\r
SmramSaveState.c\r
SmmCpuMemoryManagement.c\r
+ SmmMp.h\r
+ SmmMp.c\r
\r
[Sources.Ia32]\r
Ia32/Semaphore.c\r
gEfiSmmReadyToLockProtocolGuid ## NOTIFY\r
gEfiSmmCpuServiceProtocolGuid ## PRODUCES\r
gEdkiiSmmMemoryAttributeProtocolGuid ## PRODUCES\r
+ gEfiMmMpProtocolGuid ## PRODUCES\r
\r
[Guids]\r
gEfiAcpiVariableGuid ## SOMETIMES_CONSUMES ## HOB # it is used for S3 boot.\r
--- /dev/null
+/** @file\r
+SMM MP protocol implementation\r
+\r
+Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>\r
+\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#include "PiSmmCpuDxeSmm.h"\r
+#include "SmmMp.h"\r
+\r
+///\r
+/// SMM MP Protocol instance\r
+///\r
+EFI_MM_MP_PROTOCOL mSmmMp = {\r
+ EFI_MM_MP_PROTOCOL_REVISION,\r
+ 0,\r
+ SmmMpGetNumberOfProcessors,\r
+ SmmMpDispatchProcedure,\r
+ SmmMpBroadcastProcedure,\r
+ SmmMpSetStartupProcedure,\r
+ SmmMpCheckForProcedure,\r
+ SmmMpWaitForProcedure\r
+};\r
+\r
+/**\r
+ Service to retrieves the number of logical processor in the platform.\r
+\r
+ @param[in] This The EFI_MM_MP_PROTOCOL instance.\r
+ @param[out] NumberOfProcessors Pointer to the total number of logical processors in the system,\r
+ including the BSP and all APs.\r
+\r
+ @retval EFI_SUCCESS The number of processors was retrieved successfully\r
+ @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmMpGetNumberOfProcessors (\r
+ IN CONST EFI_MM_MP_PROTOCOL *This,\r
+ OUT UINTN *NumberOfProcessors\r
+ )\r
+{\r
+ if (NumberOfProcessors == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ *NumberOfProcessors = gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ This service allows the caller to invoke a procedure one of the application processors (AP). This\r
+ function uses an optional token parameter to support blocking and non-blocking modes. If the token\r
+ is passed into the call, the function will operate in a non-blocking fashion and the caller can\r
+ check for completion with CheckOnProcedure or WaitForProcedure.\r
+\r
+ @param[in] This The EFI_MM_MP_PROTOCOL instance.\r
+ @param[in] Procedure A pointer to the procedure to be run on the designated target\r
+ AP of the system. Type EFI_AP_PROCEDURE2 is defined below in\r
+ related definitions.\r
+ @param[in] CpuNumber The zero-based index of the processor number of the target\r
+ AP, on which the code stream is supposed to run. If the number\r
+ points to the calling processor then it will not run the\r
+ supplied code.\r
+ @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for this AP to\r
+ finish execution of Procedure, either for blocking or\r
+ non-blocking mode. Zero means infinity. If the timeout\r
+ expires before this AP returns from Procedure, then Procedure\r
+ on the AP is terminated. If the timeout expires in blocking\r
+ mode, the call returns EFI_TIMEOUT. If the timeout expires\r
+ in non-blocking mode, the timeout determined can be through\r
+ CheckOnProcedure or WaitForProcedure.\r
+ Note that timeout support is optional. Whether an\r
+ implementation supports this feature, can be determined via\r
+ the Attributes data member.\r
+ @param[in,out] ProcedureArguments Allows the caller to pass a list of parameters to the code\r
+ that is run by the AP. It is an optional common mailbox\r
+ between APs and the caller to share information.\r
+ @param[in,out] Token This is parameter is broken into two components:\r
+ 1.Token->Completion is an optional parameter that allows the\r
+ caller to execute the procedure in a blocking or non-blocking\r
+ fashion. If it is NULL the call is blocking, and the call will\r
+ not return until the AP has completed the procedure. If the\r
+ token is not NULL, the call will return immediately. The caller\r
+ can check whether the procedure has completed with\r
+ CheckOnProcedure or WaitForProcedure.\r
+ 2.Token->Status The implementation updates the address pointed\r
+ at by this variable with the status code returned by Procedure\r
+ when it completes execution on the target AP, or with EFI_TIMEOUT\r
+ if the Procedure fails to complete within the optional timeout.\r
+ The implementation will update this variable with EFI_NOT_READY\r
+ prior to starting Procedure on the target AP\r
+ @param[in,out] CPUStatus This optional pointer may be used to get the status code returned\r
+ by Procedure when it completes execution on the target AP, or with\r
+ EFI_TIMEOUT if the Procedure fails to complete within the optional\r
+ timeout. The implementation will update this variable with\r
+ EFI_NOT_READY prior to starting Procedure on the target AP.\r
+\r
+ @retval EFI_SUCCESS In the blocking case, this indicates that Procedure has completed\r
+ execution on the target AP.\r
+ In the non-blocking case this indicates that the procedure has\r
+ been successfully scheduled for execution on the target AP.\r
+ @retval EFI_INVALID_PARAMETER The input arguments are out of range. Either the target AP is the\r
+ caller of the function, or the Procedure or Token is NULL\r
+ @retval EFI_NOT_READY If the target AP is busy executing another procedure\r
+ @retval EFI_ALREADY_STARTED Token is already in use for another procedure\r
+ @retval EFI_TIMEOUT In blocking mode, the timeout expired before the specified AP\r
+ has finished\r
+ @retval EFI_OUT_OF_RESOURCES Could not allocate a required resource.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmMpDispatchProcedure (\r
+ IN CONST EFI_MM_MP_PROTOCOL *This,\r
+ IN EFI_AP_PROCEDURE2 Procedure,\r
+ IN UINTN CpuNumber,\r
+ IN UINTN TimeoutInMicroseconds,\r
+ IN OUT VOID *ProcedureArguments OPTIONAL,\r
+ IN OUT MM_COMPLETION *Token,\r
+ IN OUT EFI_STATUS *CPUStatus\r
+ )\r
+{\r
+ return InternalSmmStartupThisAp (\r
+ Procedure,\r
+ CpuNumber,\r
+ ProcedureArguments,\r
+ Token,\r
+ TimeoutInMicroseconds,\r
+ CPUStatus\r
+ );\r
+}\r
+\r
+/**\r
+ This service allows the caller to invoke a procedure on all running application processors (AP)\r
+ except the caller. This function uses an optional token parameter to support blocking and\r
+ nonblocking modes. If the token is passed into the call, the function will operate in a non-blocking\r
+ fashion and the caller can check for completion with CheckOnProcedure or WaitForProcedure.\r
+\r
+ It is not necessary for the implementation to run the procedure on every processor on the platform.\r
+ Processors that are powered down in such a way that they cannot respond to interrupts, may be\r
+ excluded from the broadcast.\r
+\r
+\r
+ @param[in] This The EFI_MM_MP_PROTOCOL instance.\r
+ @param[in] Procedure A pointer to the code stream to be run on the APs that have\r
+ entered MM. Type EFI_AP_PROCEDURE is defined below in related\r
+ definitions.\r
+ @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for the APs to finish\r
+ execution of Procedure, either for blocking or non-blocking mode.\r
+ Zero means infinity. If the timeout expires before all APs return\r
+ from Procedure, then Procedure on the failed APs is terminated. If\r
+ the timeout expires in blocking mode, the call returns EFI_TIMEOUT.\r
+ If the timeout expires in non-blocking mode, the timeout determined\r
+ can be through CheckOnProcedure or WaitForProcedure.\r
+ Note that timeout support is optional. Whether an implementation\r
+ supports this feature can be determined via the Attributes data\r
+ member.\r
+ @param[in,out] ProcedureArguments Allows the caller to pass a list of parameters to the code\r
+ that is run by the AP. It is an optional common mailbox\r
+ between APs and the caller to share information.\r
+ @param[in,out] Token This is parameter is broken into two components:\r
+ 1.Token->Completion is an optional parameter that allows the\r
+ caller to execute the procedure in a blocking or non-blocking\r
+ fashion. If it is NULL the call is blocking, and the call will\r
+ not return until the AP has completed the procedure. If the\r
+ token is not NULL, the call will return immediately. The caller\r
+ can check whether the procedure has completed with\r
+ CheckOnProcedure or WaitForProcedure.\r
+ 2.Token->Status The implementation updates the address pointed\r
+ at by this variable with the status code returned by Procedure\r
+ when it completes execution on the target AP, or with EFI_TIMEOUT\r
+ if the Procedure fails to complete within the optional timeout.\r
+ The implementation will update this variable with EFI_NOT_READY\r
+ prior to starting Procedure on the target AP\r
+ @param[in,out] CPUStatus This optional pointer may be used to get the individual status\r
+ returned by every AP that participated in the broadcast. This\r
+ parameter if used provides the base address of an array to hold\r
+ the EFI_STATUS value of each AP in the system. The size of the\r
+ array can be ascertained by the GetNumberOfProcessors function.\r
+ As mentioned above, the broadcast may not include every processor\r
+ in the system. Some implementations may exclude processors that\r
+ have been powered down in such a way that they are not responsive\r
+ to interrupts. Additionally the broadcast excludes the processor\r
+ which is making the BroadcastProcedure call. For every excluded\r
+ processor, the array entry must contain a value of EFI_NOT_STARTED\r
+\r
+ @retval EFI_SUCCESS In the blocking case, this indicates that Procedure has completed\r
+ execution on the APs.\r
+ In the non-blocking case this indicates that the procedure has\r
+ been successfully scheduled for execution on the APs.\r
+ @retval EFI_INVALID_PARAMETER The Procedure or Token is NULL\r
+ @retval EFI_NOT_READY If the target AP is busy executing another procedure\r
+ @retval EFI_ALREADY_STARTED Token is already in use for another procedure\r
+ @retval EFI_TIMEOUT In blocking mode, the timeout expired before the specified AP\r
+ has finished.\r
+ @retval EFI_OUT_OF_RESOURCES Could not allocate a required resource.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmMpBroadcastProcedure (\r
+ IN CONST EFI_MM_MP_PROTOCOL *This,\r
+ IN EFI_AP_PROCEDURE2 Procedure,\r
+ IN UINTN TimeoutInMicroseconds,\r
+ IN OUT VOID *ProcedureArguments OPTIONAL,\r
+ IN OUT MM_COMPLETION *Token,\r
+ IN OUT EFI_STATUS *CPUStatus\r
+ )\r
+{\r
+ return InternalSmmStartupAllAPs(\r
+ Procedure,\r
+ TimeoutInMicroseconds,\r
+ ProcedureArguments,\r
+ Token,\r
+ CPUStatus\r
+ );\r
+}\r
+\r
+/**\r
+ This service allows the caller to set a startup procedure that will be executed when an AP powers\r
+ up from a state where core configuration and context is lost. The procedure is execution has the\r
+ following properties:\r
+ 1. The procedure executes before the processor is handed over to the operating system.\r
+ 2. All processors execute the same startup procedure.\r
+ 3. The procedure may run in parallel with other procedures invoked through the functions in this\r
+ protocol, or with processors that are executing an MM handler or running in the operating system.\r
+\r
+\r
+ @param[in] This The EFI_MM_MP_PROTOCOL instance.\r
+ @param[in] Procedure A pointer to the code stream to be run on the designated target AP\r
+ of the system. Type EFI_AP_PROCEDURE is defined below in Volume 2\r
+ with the related definitions of\r
+ EFI_MP_SERVICES_PROTOCOL.StartupAllAPs.\r
+ If caller may pass a value of NULL to deregister any existing\r
+ startup procedure.\r
+ @param[in,out] ProcedureArguments Allows the caller to pass a list of parameters to the code that is\r
+ run by the AP. It is an optional common mailbox between APs and\r
+ the caller to share information\r
+\r
+ @retval EFI_SUCCESS The Procedure has been set successfully.\r
+ @retval EFI_INVALID_PARAMETER The Procedure is NULL but ProcedureArguments not NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmMpSetStartupProcedure (\r
+ IN CONST EFI_MM_MP_PROTOCOL *This,\r
+ IN EFI_AP_PROCEDURE Procedure,\r
+ IN OUT VOID *ProcedureArguments OPTIONAL\r
+ )\r
+{\r
+ return RegisterStartupProcedure (Procedure, ProcedureArguments);\r
+}\r
+\r
+/**\r
+ When non-blocking execution of a procedure on an AP is invoked with DispatchProcedure,\r
+ via the use of a token, this function can be used to check for completion of the procedure on the AP.\r
+ The function takes the token that was passed into the DispatchProcedure call. If the procedure\r
+ is complete, and therefore it is now possible to run another procedure on the same AP, this function\r
+ returns EFI_SUCESS. In this case the status returned by the procedure that executed on the AP is\r
+ returned in the token's Status field. If the procedure has not yet completed, then this function\r
+ returns EFI_NOT_READY.\r
+\r
+ When a non-blocking execution of a procedure is invoked with BroadcastProcedure, via the\r
+ use of a token, this function can be used to check for completion of the procedure on all the\r
+ broadcast APs. The function takes the token that was passed into the BroadcastProcedure\r
+ call. If the procedure is complete on all broadcast APs this function returns EFI_SUCESS. In this\r
+ case the Status field in the token passed into the function reflects the overall result of the\r
+ invocation, which may be EFI_SUCCESS, if all executions succeeded, or the first observed failure.\r
+ If the procedure has not yet completed on the broadcast APs, the function returns\r
+ EFI_NOT_READY.\r
+\r
+ @param[in] This The EFI_MM_MP_PROTOCOL instance.\r
+ @param[in] Token This parameter describes the token that was passed into\r
+ DispatchProcedure or BroadcastProcedure.\r
+\r
+ @retval EFI_SUCCESS Procedure has completed.\r
+ @retval EFI_NOT_READY The Procedure has not completed.\r
+ @retval EFI_INVALID_PARAMETER Token or Token->Completion is NULL\r
+ @retval EFI_NOT_FOUND Token is not currently in use for a non-blocking call\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmMpCheckForProcedure (\r
+ IN CONST EFI_MM_MP_PROTOCOL *This,\r
+ IN MM_COMPLETION Token\r
+ )\r
+{\r
+ if (Token == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (!IsTokenInUse ((SPIN_LOCK *)Token)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ return IsApReady ((SPIN_LOCK *)Token);\r
+}\r
+\r
+/**\r
+ When a non-blocking execution of a procedure on an AP is invoked via DispatchProcedure,\r
+ this function will block the caller until the remote procedure has completed on the designated AP.\r
+ The non-blocking procedure invocation is identified by the Token parameter, which must match the\r
+ token that used when DispatchProcedure was called. Upon completion the status returned by\r
+ the procedure that executed on the AP is used to update the token's Status field.\r
+\r
+ When a non-blocking execution of a procedure on an AP is invoked via BroadcastProcedure\r
+ this function will block the caller until the remote procedure has completed on all of the APs that\r
+ entered MM. The non-blocking procedure invocation is identified by the Token parameter, which\r
+ must match the token that used when BroadcastProcedure was called. Upon completion the\r
+ overall status returned by the procedures that executed on the broadcast AP is used to update the\r
+ token's Status field. The overall status may be EFI_SUCCESS, if all executions succeeded, or the\r
+ first observed failure.\r
+\r
+\r
+ @param[in] This The EFI_MM_MP_PROTOCOL instance.\r
+ @param[in] Token This parameter describes the token that was passed into\r
+ DispatchProcedure or BroadcastProcedure.\r
+\r
+ @retval EFI_SUCCESS Procedure has completed.\r
+ @retval EFI_INVALID_PARAMETER Token or Token->Completion is NULL\r
+ @retval EFI_NOT_FOUND Token is not currently in use for a non-blocking call\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmMpWaitForProcedure (\r
+ IN CONST EFI_MM_MP_PROTOCOL *This,\r
+ IN MM_COMPLETION Token\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ do {\r
+ Status = SmmMpCheckForProcedure (This, Token);\r
+ } while (Status == EFI_NOT_READY);\r
+\r
+ return Status;\r
+}\r
+\r
--- /dev/null
+/** @file\r
+Include file for SMM MP protocol implementation.\r
+\r
+Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>\r
+\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#ifndef _SMM_MP_PROTOCOL_H_\r
+#define _SMM_MP_PROTOCOL_H_\r
+\r
+//\r
+// SMM MP Protocol function prototypes.\r
+//\r
+\r
+/**\r
+ Service to retrieves the number of logical processor in the platform.\r
+\r
+ @param[in] This The EFI_MM_MP_PROTOCOL instance.\r
+ @param[out] NumberOfProcessors Pointer to the total number of logical processors in the system,\r
+ including the BSP and all APs.\r
+\r
+ @retval EFI_SUCCESS The number of processors was retrieved successfully\r
+ @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL\r
+**/\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+SmmMpGetNumberOfProcessors (\r
+ IN CONST EFI_MM_MP_PROTOCOL *This,\r
+ OUT UINTN *NumberOfProcessors\r
+ );\r
+\r
+\r
+/**\r
+ This service allows the caller to invoke a procedure one of the application processors (AP). This\r
+ function uses an optional token parameter to support blocking and non-blocking modes. If the token\r
+ is passed into the call, the function will operate in a non-blocking fashion and the caller can\r
+ check for completion with CheckOnProcedure or WaitForProcedure.\r
+\r
+ @param[in] This The EFI_MM_MP_PROTOCOL instance.\r
+ @param[in] Procedure A pointer to the procedure to be run on the designated target\r
+ AP of the system. Type EFI_AP_PROCEDURE2 is defined below in\r
+ related definitions.\r
+ @param[in] CpuNumber The zero-based index of the processor number of the target\r
+ AP, on which the code stream is supposed to run. If the number\r
+ points to the calling processor then it will not run the\r
+ supplied code.\r
+ @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for this AP to\r
+ finish execution of Procedure, either for blocking or\r
+ non-blocking mode. Zero means infinity. If the timeout\r
+ expires before this AP returns from Procedure, then Procedure\r
+ on the AP is terminated. If the timeout expires in blocking\r
+ mode, the call returns EFI_TIMEOUT. If the timeout expires\r
+ in non-blocking mode, the timeout determined can be through\r
+ CheckOnProcedure or WaitForProcedure.\r
+ Note that timeout support is optional. Whether an\r
+ implementation supports this feature, can be determined via\r
+ the Attributes data member.\r
+ @param[in,out] ProcedureArguments Allows the caller to pass a list of parameters to the code\r
+ that is run by the AP. It is an optional common mailbox\r
+ between APs and the caller to share information.\r
+ @param[in,out] Token This is parameter is broken into two components:\r
+ 1.Token->Completion is an optional parameter that allows the\r
+ caller to execute the procedure in a blocking or non-blocking\r
+ fashion. If it is NULL the call is blocking, and the call will\r
+ not return until the AP has completed the procedure. If the\r
+ token is not NULL, the call will return immediately. The caller\r
+ can check whether the procedure has completed with\r
+ CheckOnProcedure or WaitForProcedure.\r
+ 2.Token->Status The implementation updates the address pointed\r
+ at by this variable with the status code returned by Procedure\r
+ when it completes execution on the target AP, or with EFI_TIMEOUT\r
+ if the Procedure fails to complete within the optional timeout.\r
+ The implementation will update this variable with EFI_NOT_READY\r
+ prior to starting Procedure on the target AP\r
+ @param[in,out] CPUStatus This optional pointer may be used to get the status code returned\r
+ by Procedure when it completes execution on the target AP, or with\r
+ EFI_TIMEOUT if the Procedure fails to complete within the optional\r
+ timeout. The implementation will update this variable with\r
+ EFI_NOT_READY prior to starting Procedure on the target AP.\r
+\r
+ @retval EFI_SUCCESS In the blocking case, this indicates that Procedure has completed\r
+ execution on the target AP.\r
+ In the non-blocking case this indicates that the procedure has\r
+ been successfully scheduled for execution on the target AP.\r
+ @retval EFI_INVALID_PARAMETER The input arguments are out of range. Either the target AP is the\r
+ caller of the function, or the Procedure or Token is NULL\r
+ @retval EFI_NOT_READY If the target AP is busy executing another procedure\r
+ @retval EFI_ALREADY_STARTED Token is already in use for another procedure\r
+ @retval EFI_TIMEOUT In blocking mode, the timeout expired before the specified AP\r
+ has finished\r
+ @retval EFI_OUT_OF_RESOURCES Could not allocate a required resource.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmMpDispatchProcedure (\r
+ IN CONST EFI_MM_MP_PROTOCOL *This,\r
+ IN EFI_AP_PROCEDURE2 Procedure,\r
+ IN UINTN CpuNumber,\r
+ IN UINTN TimeoutInMicroseconds,\r
+ IN OUT VOID *ProcedureArguments OPTIONAL,\r
+ IN OUT MM_COMPLETION *Token,\r
+ IN OUT EFI_STATUS *CPUStatus\r
+ );\r
+\r
+/**\r
+ This service allows the caller to invoke a procedure on all running application processors (AP)\r
+ except the caller. This function uses an optional token parameter to support blocking and\r
+ nonblocking modes. If the token is passed into the call, the function will operate in a non-blocking\r
+ fashion and the caller can check for completion with CheckOnProcedure or WaitForProcedure.\r
+\r
+ It is not necessary for the implementation to run the procedure on every processor on the platform.\r
+ Processors that are powered down in such a way that they cannot respond to interrupts, may be\r
+ excluded from the broadcast.\r
+\r
+\r
+ @param[in] This The EFI_MM_MP_PROTOCOL instance.\r
+ @param[in] Procedure A pointer to the code stream to be run on the APs that have\r
+ entered MM. Type EFI_AP_PROCEDURE is defined below in related\r
+ definitions.\r
+ @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for the APs to finish\r
+ execution of Procedure, either for blocking or non-blocking mode.\r
+ Zero means infinity. If the timeout expires before all APs return\r
+ from Procedure, then Procedure on the failed APs is terminated. If\r
+ the timeout expires in blocking mode, the call returns EFI_TIMEOUT.\r
+ If the timeout expires in non-blocking mode, the timeout determined\r
+ can be through CheckOnProcedure or WaitForProcedure.\r
+ Note that timeout support is optional. Whether an implementation\r
+ supports this feature can be determined via the Attributes data\r
+ member.\r
+ @param[in,out] ProcedureArguments Allows the caller to pass a list of parameters to the code\r
+ that is run by the AP. It is an optional common mailbox\r
+ between APs and the caller to share information.\r
+ @param[in,out] Token This is parameter is broken into two components:\r
+ 1.Token->Completion is an optional parameter that allows the\r
+ caller to execute the procedure in a blocking or non-blocking\r
+ fashion. If it is NULL the call is blocking, and the call will\r
+ not return until the AP has completed the procedure. If the\r
+ token is not NULL, the call will return immediately. The caller\r
+ can check whether the procedure has completed with\r
+ CheckOnProcedure or WaitForProcedure.\r
+ 2.Token->Status The implementation updates the address pointed\r
+ at by this variable with the status code returned by Procedure\r
+ when it completes execution on the target AP, or with EFI_TIMEOUT\r
+ if the Procedure fails to complete within the optional timeout.\r
+ The implementation will update this variable with EFI_NOT_READY\r
+ prior to starting Procedure on the target AP\r
+ @param[in,out] CPUStatus This optional pointer may be used to get the individual status\r
+ returned by every AP that participated in the broadcast. This\r
+ parameter if used provides the base address of an array to hold\r
+ the EFI_STATUS value of each AP in the system. The size of the\r
+ array can be ascertained by the GetNumberOfProcessors function.\r
+ As mentioned above, the broadcast may not include every processor\r
+ in the system. Some implementations may exclude processors that\r
+ have been powered down in such a way that they are not responsive\r
+ to interrupts. Additionally the broadcast excludes the processor\r
+ which is making the BroadcastProcedure call. For every excluded\r
+ processor, the array entry must contain a value of EFI_NOT_STARTED\r
+\r
+ @retval EFI_SUCCESS In the blocking case, this indicates that Procedure has completed\r
+ execution on the APs.\r
+ In the non-blocking case this indicates that the procedure has\r
+ been successfully scheduled for execution on the APs.\r
+ @retval EFI_INVALID_PARAMETER The Procedure or Token is NULL\r
+ @retval EFI_NOT_READY If the target AP is busy executing another procedure\r
+ @retval EFI_ALREADY_STARTED Token is already in use for another procedure\r
+ @retval EFI_TIMEOUT In blocking mode, the timeout expired before the specified AP\r
+ has finished\r
+ @retval EFI_OUT_OF_RESOURCES Could not allocate a required resource.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmMpBroadcastProcedure (\r
+ IN CONST EFI_MM_MP_PROTOCOL *This,\r
+ IN EFI_AP_PROCEDURE2 Procedure,\r
+ IN UINTN TimeoutInMicroseconds,\r
+ IN OUT VOID *ProcedureArguments OPTIONAL,\r
+ IN OUT MM_COMPLETION *Token,\r
+ IN OUT EFI_STATUS *CPUStatus\r
+ );\r
+\r
+\r
+/**\r
+ This service allows the caller to set a startup procedure that will be executed when an AP powers\r
+ up from a state where core configuration and context is lost. The procedure is execution has the\r
+ following properties:\r
+ 1. The procedure executes before the processor is handed over to the operating system.\r
+ 2. All processors execute the same startup procedure.\r
+ 3. The procedure may run in parallel with other procedures invoked through the functions in this\r
+ protocol, or with processors that are executing an MM handler or running in the operating system.\r
+\r
+\r
+ @param[in] This The EFI_MM_MP_PROTOCOL instance.\r
+ @param[in] Procedure A pointer to the code stream to be run on the designated target AP\r
+ of the system. Type EFI_AP_PROCEDURE is defined below in Volume 2\r
+ with the related definitions of\r
+ EFI_MP_SERVICES_PROTOCOL.StartupAllAPs.\r
+ If caller may pass a value of NULL to deregister any existing\r
+ startup procedure.\r
+ @param[in,out] ProcedureArguments Allows the caller to pass a list of parameters to the code that is\r
+ run by the AP. It is an optional common mailbox between APs and\r
+ the caller to share information\r
+\r
+ @retval EFI_SUCCESS The Procedure has been set successfully.\r
+ @retval EFI_INVALID_PARAMETER The Procedure is NULL but ProcedureArguments not NULL.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmMpSetStartupProcedure (\r
+ IN CONST EFI_MM_MP_PROTOCOL *This,\r
+ IN EFI_AP_PROCEDURE Procedure,\r
+ IN OUT VOID *ProcedureArguments OPTIONAL\r
+ );\r
+\r
+/**\r
+ When non-blocking execution of a procedure on an AP is invoked with DispatchProcedure,\r
+ via the use of a token, this function can be used to check for completion of the procedure on the AP.\r
+ The function takes the token that was passed into the DispatchProcedure call. If the procedure\r
+ is complete, and therefore it is now possible to run another procedure on the same AP, this function\r
+ returns EFI_SUCESS. In this case the status returned by the procedure that executed on the AP is\r
+ returned in the token's Status field. If the procedure has not yet completed, then this function\r
+ returns EFI_NOT_READY.\r
+\r
+ When a non-blocking execution of a procedure is invoked with BroadcastProcedure, via the\r
+ use of a token, this function can be used to check for completion of the procedure on all the\r
+ broadcast APs. The function takes the token that was passed into the BroadcastProcedure\r
+ call. If the procedure is complete on all broadcast APs this function returns EFI_SUCESS. In this\r
+ case the Status field in the token passed into the function reflects the overall result of the\r
+ invocation, which may be EFI_SUCCESS, if all executions succeeded, or the first observed failure.\r
+ If the procedure has not yet completed on the broadcast APs, the function returns\r
+ EFI_NOT_READY.\r
+\r
+ @param[in] This The EFI_MM_MP_PROTOCOL instance.\r
+ @param[in] Token This parameter describes the token that was passed into\r
+ DispatchProcedure or BroadcastProcedure.\r
+\r
+ @retval EFI_SUCCESS Procedure has completed.\r
+ @retval EFI_NOT_READY The Procedure has not completed.\r
+ @retval EFI_INVALID_PARAMETER Token or Token->Completion is NULL\r
+ @retval EFI_NOT_FOUND Token is not currently in use for a non-blocking call\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmMpCheckForProcedure (\r
+ IN CONST EFI_MM_MP_PROTOCOL *This,\r
+ IN MM_COMPLETION Token\r
+ );\r
+\r
+/**\r
+ When a non-blocking execution of a procedure on an AP is invoked via DispatchProcedure,\r
+ this function will block the caller until the remote procedure has completed on the designated AP.\r
+ The non-blocking procedure invocation is identified by the Token parameter, which must match the\r
+ token that used when DispatchProcedure was called. Upon completion the status returned by\r
+ the procedure that executed on the AP is used to update the token's Status field.\r
+\r
+ When a non-blocking execution of a procedure on an AP is invoked via BroadcastProcedure\r
+ this function will block the caller until the remote procedure has completed on all of the APs that\r
+ entered MM. The non-blocking procedure invocation is identified by the Token parameter, which\r
+ must match the token that used when BroadcastProcedure was called. Upon completion the\r
+ overall status returned by the procedures that executed on the broadcast AP is used to update the\r
+ token's Status field. The overall status may be EFI_SUCCESS, if all executions succeeded, or the\r
+ first observed failure.\r
+\r
+\r
+ @param[in] This The EFI_MM_MP_PROTOCOL instance.\r
+ @param[in] Token This parameter describes the token that was passed into\r
+ DispatchProcedure or BroadcastProcedure.\r
+\r
+ @retval EFI_SUCCESS Procedure has completed.\r
+ @retval EFI_INVALID_PARAMETER Token or Token->Completion is NULL\r
+ @retval EFI_NOT_FOUND Token is not currently in use for a non-blocking call\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmMpWaitForProcedure (\r
+ IN CONST EFI_MM_MP_PROTOCOL *This,\r
+ IN MM_COMPLETION Token\r
+ );\r
+\r
+#endif\r