V5 changes:
1. some small enhancement.
v4 changes:
1. Use link list to save the token info.
v3 changes:
1. Fix Token clean up too early caused CheckProcedure return error.
v2 changes:
1. Remove some duplicated global variables.
2. Enhance token design to support multiple task trig for different APs at the same time.
V1 changes:
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=1937
Add MM Mp Protocol in PiSmmCpuDxeSmm driver.
Cc: Ray Ni <ray.ni@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Eric Dong <eric.dong@intel.com>
---
UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c | 570 ++++++++++++++++++-
UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c | 18 +
UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h | 193 ++++++-
UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf | 3 +
UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.c | 344 +++++++++++
UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.h | 286 ++++++++++
6 files changed, 1391 insertions(+), 23 deletions(-)
create mode 100644 UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.c
create mode 100644 UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.h
diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c b/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c
index 64fb4d6344..f09e2738c3 100644
--- a/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c
+++ b/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c
@@ -140,7 +140,7 @@ ReleaseAllAPs (
BspIndex = mSmmMpSyncData->BspIndex;
for (Index = mMaxNumberOfCpus; Index-- > 0;) {
- if (Index != BspIndex && *(mSmmMpSyncData->CpuData[Index].Present)) {
+ if (IsPresentAp (Index)) {
ReleaseSemaphore (mSmmMpSyncData->CpuData[Index].Run);
}
}
@@ -347,6 +347,165 @@ ReplaceOSMtrrs (
MtrrSetAllMtrrs (&gSmiMtrrs);
}
+/**
+ Wheck whether task has been finished by all APs.
+
+ @param BlockMode Whether did it in block mode or non-block mode.
+
+ @retval TRUE Task has been finished by all APs.
+ @retval FALSE Task not has been finished by all APs.
+
+**/
+BOOLEAN
+WaitForAllAPsNotBusy (
+ IN BOOLEAN BlockMode
+ )
+{
+ UINTN Index;
+
+ for (Index = mMaxNumberOfCpus; Index-- > 0;) {
+ //
+ // Ignore BSP and APs which not call in SMM.
+ //
+ if (!IsPresentAp(Index)) {
+ continue;
+ }
+
+ if (BlockMode) {
+ AcquireSpinLock(mSmmMpSyncData->CpuData[Index].Busy);
+ ReleaseSpinLock(mSmmMpSyncData->CpuData[Index].Busy);
+ } else {
+ if (AcquireSpinLockOrFail (mSmmMpSyncData->CpuData[Index].Busy)) {
+ ReleaseSpinLock(mSmmMpSyncData->CpuData[Index].Busy);
+ } else {
+ return FALSE;
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+/**
+ Check whether it is an present AP.
+
+ @param CpuIndex The AP index which calls this function.
+
+ @retval TRUE It's a present AP.
+ @retval TRUE This is not an AP or it is not present.
+
+**/
+BOOLEAN
+IsPresentAp (
+ IN UINTN CpuIndex
+ )
+{
+ return ((CpuIndex != gSmmCpuPrivate->SmmCoreEntryContext.CurrentlyExecutingCpu) &&
+ *(mSmmMpSyncData->CpuData[CpuIndex].Present));
+}
+
+/**
+ Check whether execute in single AP or all APs.
+
+ Compare two Tokens used by different APs to know whether in StartAllAps call.
+
+ Whether is an valid AP base on AP's Present flag.
+
+ @retval TRUE IN StartAllAps call.
+ @retval FALSE Not in StartAllAps call.
+
+**/
+BOOLEAN
+InStartAllApsCall (
+ VOID
+ )
+{
+ UINTN ApIndex;
+ UINTN ApIndex2;
+
+ for (ApIndex = mMaxNumberOfCpus; ApIndex-- > 0;) {
+ if (IsPresentAp (ApIndex) && (mSmmMpSyncData->CpuData[ApIndex].Token != NULL)) {
+ for (ApIndex2 = ApIndex; ApIndex2-- > 0;) {
+ if (IsPresentAp (ApIndex2) && (mSmmMpSyncData->CpuData[ApIndex2].Token != NULL)) {
+ return mSmmMpSyncData->CpuData[ApIndex2].Token == mSmmMpSyncData->CpuData[ApIndex].Token;
+ }
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Clean up the status flags used during executing the procedure.
+
+ @param CpuIndex The AP index which calls this function.
+
+**/
+VOID
+ReleaseToken (
+ IN UINTN CpuIndex
+ )
+{
+ UINTN Index;
+ BOOLEAN Released;
+
+ if (InStartAllApsCall ()) {
+ //
+ // In Start All APs mode, make sure all APs have finished task.
+ //
+ if (WaitForAllAPsNotBusy (FALSE)) {
+ //
+ // Clean the flags update in the function call.
+ //
+ Released = FALSE;
+ for (Index = mMaxNumberOfCpus; Index-- > 0;) {
+ //
+ // Only In SMM APs need to be clean up.
+ //
+ if (mSmmMpSyncData->CpuData[Index].Present && mSmmMpSyncData->CpuData[Index].Token != NULL) {
+ if (!Released) {
+ ReleaseSpinLock (mSmmMpSyncData->CpuData[Index].Token);
+ Released = TRUE;
+ }
+ mSmmMpSyncData->CpuData[Index].Token = NULL;
+ }
+ }
+ }
+ } else {
+ //
+ // In single AP mode.
+ //
+ if (mSmmMpSyncData->CpuData[CpuIndex].Token != NULL) {
+ ReleaseSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Token);
+ mSmmMpSyncData->CpuData[CpuIndex].Token = NULL;
+ }
+ }
+}
+
+/**
+ Free the tokens in the maintained list.
+
+**/
+VOID
+FreeTokens (
+ VOID
+ )
+{
+ LIST_ENTRY *Link;
+ PROCEDURE_TOKEN *ProcToken;
+
+ while (!IsListEmpty (&gSmmCpuPrivate->TokenList)) {
+ Link = GetFirstNode (&gSmmCpuPrivate->TokenList);
+ ProcToken = PROCEDURE_TOKEN_FROM_LINK (Link);
+
+ RemoveEntryList (&ProcToken->Link);
+
+ FreePool ((VOID *)ProcToken->ProcedureToken);
+ FreePool (ProcToken);
+ }
+}
+
/**
SMI handler for BSP.
@@ -476,12 +635,7 @@ BSPHandler (
//
// Make sure all APs have completed their pending none-block tasks
//
- for (Index = mMaxNumberOfCpus; Index-- > 0;) {
- if (Index != CpuIndex && *(mSmmMpSyncData->CpuData[Index].Present)) {
- AcquireSpinLock (mSmmMpSyncData->CpuData[Index].Busy);
- ReleaseSpinLock (mSmmMpSyncData->CpuData[Index].Busy);
- }
- }
+ WaitForAllAPsNotBusy (TRUE);
//
// Perform the remaining tasks
@@ -572,6 +726,11 @@ BSPHandler (
//
WaitForAllAPs (ApCount);
+ //
+ // Clean the tokens buffer.
+ //
+ FreeTokens ();
+
//
// Reset BspIndex to -1, meaning BSP has not been elected.
//
@@ -604,6 +763,7 @@ APHandler (
UINT64 Timer;
UINTN BspIndex;
MTRR_SETTINGS Mtrrs;
+ EFI_STATUS ProcedureStatus;
//
// Timeout BSP
@@ -730,14 +890,19 @@ APHandler (
//
// Invoke the scheduled procedure
//
- (*mSmmMpSyncData->CpuData[CpuIndex].Procedure) (
- (VOID*)mSmmMpSyncData->CpuData[CpuIndex].Parameter
- );
+ ProcedureStatus = (*mSmmMpSyncData->CpuData[CpuIndex].Procedure) (
+ (VOID*)mSmmMpSyncData->CpuData[CpuIndex].Parameter
+ );
+ if (mSmmMpSyncData->CpuData[CpuIndex].Status != NULL) {
+ *mSmmMpSyncData->CpuData[CpuIndex].Status = ProcedureStatus;
+ }
//
// Release BUSY
//
ReleaseSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy);
+
+ ReleaseToken (CpuIndex);
}
if (SmmCpuFeaturesNeedConfigureMtrrs()) {
@@ -906,13 +1071,124 @@ Gen4GPageTable (
return (UINT32)(UINTN)PageTable;
}
+/**
+ Checks whether the input token is the current used token.
+
+ @param[in] Token This parameter describes the token that was passed into DispatchProcedure or
+ BroadcastProcedure.
+
+ @retval TRUE The input token is the current used token.
+ @retval FALSE The input token is not the current used token.
+**/
+BOOLEAN
+IsTokenInUse (
+ IN SPIN_LOCK *Token
+ )
+{
+ LIST_ENTRY *Link;
+ PROCEDURE_TOKEN *ProcToken;
+
+ if (Token == NULL) {
+ return FALSE;
+ }
+
+ Link = GetFirstNode (&gSmmCpuPrivate->TokenList);
+ while (!IsNull (&gSmmCpuPrivate->TokenList, Link)) {
+ ProcToken = PROCEDURE_TOKEN_FROM_LINK (Link);
+
+ if (ProcToken->ProcedureToken == Token) {
+ return TRUE;
+ }
+
+ Link = GetNextNode (&gSmmCpuPrivate->TokenList, Link);
+ }
+
+ return FALSE;
+}
+
+/**
+ create token and save it to the maintain list.
+
+ @retval return the spin lock used as token.
+
+**/
+SPIN_LOCK *
+CreateToken (
+ VOID
+ )
+{
+ PROCEDURE_TOKEN *ProcToken;
+ SPIN_LOCK *CpuToken;
+ UINTN SpinLockSize;
+
+ SpinLockSize = GetSpinLockProperties ();
+ CpuToken = AllocatePool (SpinLockSize);
+ ASSERT (CpuToken != NULL);
+ InitializeSpinLock (CpuToken);
+ AcquireSpinLock (CpuToken);
+
+ ProcToken = AllocatePool (sizeof (PROCEDURE_TOKEN));
+ ASSERT (ProcToken != NULL);
+ ProcToken->Signature = PROCEDURE_TOKEN_SIGNATURE;
+ ProcToken->ProcedureToken = CpuToken;
+
+ InsertTailList (&gSmmCpuPrivate->TokenList, &ProcToken->Link);
+
+ return CpuToken;
+}
+
+/**
+ Checks status of specified AP.
+
+ This function checks whether the specified AP has finished the task assigned
+ by StartupThisAP(), and whether timeout expires.
+
+ @param[in] Token This parameter describes the token that was passed into DispatchProcedure or
+ BroadcastProcedure.
+
+ @retval EFI_SUCCESS Specified AP has finished task assigned by StartupThisAPs().
+ @retval EFI_NOT_READY Specified AP has not finished task and timeout has not expired.
+**/
+EFI_STATUS
+IsApReady (
+ IN SPIN_LOCK *Token
+ )
+{
+ if (AcquireSpinLockOrFail (Token)) {
+ ReleaseSpinLock (Token);
+ return EFI_SUCCESS;
+ }
+
+ return EFI_NOT_READY;
+}
+
/**
Schedule a procedure to run on the specified CPU.
@param[in] Procedure The address of the procedure to run
@param[in] CpuIndex Target CPU Index
- @param[in, out] ProcArguments The parameter to pass to the procedure
- @param[in] BlockingMode Startup AP in blocking mode or not
+ @param[in,out] ProcArguments The parameter to pass to the procedure
+ @param[in] Token This is an optional parameter that allows the caller to execute the
+ procedure in a blocking or non-blocking fashion. If it is NULL the
+ call is blocking, and the call will not return until the AP has
+ completed the procedure. If the token is not NULL, the call will
+ return immediately. The caller can check whether the procedure has
+ completed with CheckOnProcedure or WaitForProcedure.
+ @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for the APs to finish
+ execution of Procedure, either for blocking or non-blocking mode.
+ Zero means infinity. If the timeout expires before all APs return
+ from Procedure, then Procedure on the failed APs is terminated. If
+ the timeout expires in blocking mode, the call returns EFI_TIMEOUT.
+ If the timeout expires in non-blocking mode, the timeout determined
+ can be through CheckOnProcedure or WaitForProcedure.
+ Note that timeout support is optional. Whether an implementation
+ supports this feature can be determined via the Attributes data
+ member.
+ @param[in,out] CpuStatus This optional pointer may be used to get the status code returned
+ by Procedure when it completes execution on the target AP, or with
+ EFI_TIMEOUT if the Procedure fails to complete within the optional
+ timeout. The implementation will update this variable with
+ EFI_NOT_READY prior to starting Procedure on the target AP.
@retval EFI_INVALID_PARAMETER CpuNumber not valid
@retval EFI_INVALID_PARAMETER CpuNumber specifying BSP
@@ -923,10 +1199,12 @@ Gen4GPageTable (
**/
EFI_STATUS
InternalSmmStartupThisAp (
- IN EFI_AP_PROCEDURE Procedure,
- IN UINTN CpuIndex,
- IN OUT VOID *ProcArguments OPTIONAL,
- IN BOOLEAN BlockingMode
+ IN EFI_AP_PROCEDURE2 Procedure,
+ IN UINTN CpuIndex,
+ IN OUT VOID *ProcArguments OPTIONAL,
+ IN MM_COMPLETION *Token,
+ IN UINTN TimeoutInMicroseconds,
+ IN OUT EFI_STATUS *CpuStatus
)
{
if (CpuIndex >= gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus) {
@@ -952,24 +1230,190 @@ InternalSmmStartupThisAp (
}
return EFI_INVALID_PARAMETER;
}
+ if ((TimeoutInMicroseconds != 0) && ((mSmmMp.Attributes & EFI_MM_MP_TIMEOUT_SUPPORTED) == 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (Procedure == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
- if (BlockingMode) {
+ if (Token == NULL) {
AcquireSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy);
} else {
if (!AcquireSpinLockOrFail (mSmmMpSyncData->CpuData[CpuIndex].Busy)) {
- DEBUG((DEBUG_ERROR, "mSmmMpSyncData->CpuData[%d].Busy\n", CpuIndex));
- return EFI_INVALID_PARAMETER;
+ DEBUG((DEBUG_ERROR, "Can't acquire mSmmMpSyncData->CpuData[%d].Busy\n", CpuIndex));
+ return EFI_NOT_READY;
}
+
+ *Token = (MM_COMPLETION) CreateToken ();
}
mSmmMpSyncData->CpuData[CpuIndex].Procedure = Procedure;
mSmmMpSyncData->CpuData[CpuIndex].Parameter = ProcArguments;
+ if (Token != NULL) {
+ mSmmMpSyncData->CpuData[CpuIndex].Token = (SPIN_LOCK *)(*Token);
+ }
+ mSmmMpSyncData->CpuData[CpuIndex].Status = CpuStatus;
+ if (mSmmMpSyncData->CpuData[CpuIndex].Status != NULL) {
+ *mSmmMpSyncData->CpuData[CpuIndex].Status = EFI_NOT_READY;
+ }
+
ReleaseSemaphore (mSmmMpSyncData->CpuData[CpuIndex].Run);
- if (BlockingMode) {
+ if (Token == NULL) {
AcquireSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy);
ReleaseSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy);
}
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Worker function to execute a caller provided function on all enabled APs.
+
+ @param[in] Procedure A pointer to the function to be run on
+ enabled APs of the system.
+ @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
+ APs to return from Procedure, either for
+ blocking or non-blocking mode.
+ @param[in,out] ProcedureArguments The parameter passed into Procedure for
+ all APs.
+ @param[in,out] Token This is an optional parameter that allows the caller to execute the
+ procedure in a blocking or non-blocking fashion. If it is NULL the
+ call is blocking, and the call will not return until the AP has
+ completed the procedure. If the token is not NULL, the call will
+ return immediately. The caller can check whether the procedure has
+ completed with CheckOnProcedure or WaitForProcedure.
+ @param[in,out] CPUStatus This optional pointer may be used to get the status code returned
+ by Procedure when it completes execution on the target AP, or with
+ EFI_TIMEOUT if the Procedure fails to complete within the optional
+ timeout. The implementation will update this variable with
+ EFI_NOT_READY prior to starting Procedure on the target AP.
+
+
+ @retval EFI_SUCCESS In blocking mode, all APs have finished before
+ the timeout expired.
+ @retval EFI_SUCCESS In non-blocking mode, function has been dispatched
+ to all enabled APs.
+ @retval others Failed to Startup all APs.
+
+**/
+EFI_STATUS
+InternalSmmStartupAllAPs (
+ IN EFI_AP_PROCEDURE2 Procedure,
+ IN UINTN TimeoutInMicroseconds,
+ IN OUT VOID *ProcedureArguments OPTIONAL,
+ IN OUT MM_COMPLETION *Token,
+ IN OUT EFI_STATUS *CPUStatus
+ )
+{
+ UINTN Index;
+ UINTN CpuCount;
+
+ if ((TimeoutInMicroseconds != 0) && ((mSmmMp.Attributes & EFI_MM_MP_TIMEOUT_SUPPORTED) == 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (Procedure == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CpuCount = 0;
+ for (Index = mMaxNumberOfCpus; Index-- > 0;) {
+ if (IsPresentAp (Index)) {
+ CpuCount ++;
+
+ if (gSmmCpuPrivate->Operation[Index] == SmmCpuRemove) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!AcquireSpinLockOrFail(mSmmMpSyncData->CpuData[Index].Busy)) {
+ return EFI_NOT_READY;
+ }
+ ReleaseSpinLock (mSmmMpSyncData->CpuData[Index].Busy);
+ }
+ }
+ if (CpuCount == 0) {
+ return EFI_NOT_STARTED;
+ }
+
+ if (Token != NULL) {
+ *Token = (MM_COMPLETION) CreateToken ();
+ }
+
+ //
+ // Make sure all BUSY should be acquired.
+ //
+ // Because former code already check mSmmMpSyncData->CpuData[***].Busy for each AP.
+ // Here code always use AcquireSpinLock instead of AcquireSpinLockOrFail for not
+ // block mode.
+ //
+ for (Index = mMaxNumberOfCpus; Index-- > 0;) {
+ if (IsPresentAp (Index)) {
+ AcquireSpinLock (mSmmMpSyncData->CpuData[Index].Busy);
+ }
+ }
+
+ for (Index = mMaxNumberOfCpus; Index-- > 0;) {
+ if (IsPresentAp (Index)) {
+ mSmmMpSyncData->CpuData[Index].Procedure = (EFI_AP_PROCEDURE2) Procedure;
+ mSmmMpSyncData->CpuData[Index].Parameter = ProcedureArguments;
+ if (Token != NULL) {
+ mSmmMpSyncData->CpuData[Index].Token = (SPIN_LOCK *)(*Token);
+ }
+ if (CPUStatus != NULL) {
+ mSmmMpSyncData->CpuData[Index].Status = &CPUStatus[Index];
+ if (mSmmMpSyncData->CpuData[Index].Status != NULL) {
+ *mSmmMpSyncData->CpuData[Index].Status = EFI_NOT_READY;
+ }
+ }
+ } else {
+ //
+ // PI spec requirement:
+ // For every excluded processor, the array entry must contain a value of EFI_NOT_STARTED.
+ //
+ if (CPUStatus != NULL) {
+ CPUStatus[Index] = EFI_NOT_STARTED;
+ }
+ }
+ }
+
+ ReleaseAllAPs ();
+
+ if (Token == NULL) {
+ //
+ // Make sure all APs have completed their tasks.
+ //
+ WaitForAllAPsNotBusy (TRUE);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ ISO C99 6.5.2.2 "Function calls", paragraph 9:
+ If the function is defined with a type that is not compatible with
+ the type (of the expression) pointed to by the expression that
+ denotes the called function, the behavior is undefined.
+
+ So add below wrapper function to convert between EFI_AP_PROCEDURE
+ and EFI_AP_PROCEDURE2.
+
+ Wrapper for Procedures.
+
+ @param[in] Buffer Pointer to PROCEDURE_WRAPPER buffer.
+
+**/
+EFI_STATUS
+EFIAPI
+ProcedureWrapper (
+ IN OUT VOID *Buffer
+ )
+{
+ PROCEDURE_WRAPPER *Wrapper;
+
+ Wrapper = Buffer;
+ Wrapper->Procedure (Wrapper->ProcedureArgument);
+
return EFI_SUCCESS;
}
@@ -995,7 +1439,15 @@ SmmBlockingStartupThisAp (
IN OUT VOID *ProcArguments OPTIONAL
)
{
- return InternalSmmStartupThisAp(Procedure, CpuIndex, ProcArguments, TRUE);
+ PROCEDURE_WRAPPER Wrapper;
+
+ Wrapper.Procedure = Procedure;
+ Wrapper.ProcedureArgument = ProcArguments;
+
+ //
+ // Use wrapper function to convert EFI_AP_PROCEDURE to EFI_AP_PROCEDURE2.
+ //
+ return InternalSmmStartupThisAp (ProcedureWrapper, CpuIndex, &Wrapper, NULL, 0, NULL);
}
/**
@@ -1020,7 +1472,22 @@ SmmStartupThisAp (
IN OUT VOID *ProcArguments OPTIONAL
)
{
- return InternalSmmStartupThisAp(Procedure, CpuIndex, ProcArguments, FeaturePcdGet (PcdCpuSmmBlockStartupThisAp));
+ MM_COMPLETION Token;
+
+ gSmmCpuPrivate->ApWrapperFunc[CpuIndex].Procedure = Procedure;
+ gSmmCpuPrivate->ApWrapperFunc[CpuIndex].ProcedureArgument = ProcArguments;
+
+ //
+ // Use wrapper function to convert EFI_AP_PROCEDURE to EFI_AP_PROCEDURE2.
+ //
+ return InternalSmmStartupThisAp (
+ ProcedureWrapper,
+ CpuIndex,
+ &gSmmCpuPrivate->ApWrapperFunc[CpuIndex],
+ FeaturePcdGet (PcdCpuSmmBlockStartupThisAp) ? NULL : &Token,
+ 0,
+ NULL
+ );
}
/**
@@ -1112,6 +1579,13 @@ SmiRendezvous (
Cr2 = 0;
SaveCr2 (&Cr2);
+ //
+ // Call the user register Startup function first.
+ //
+ if (mSmmMpSyncData->StartupProcedure != NULL) {
+ mSmmMpSyncData->StartupProcedure (mSmmMpSyncData->StartupProcArgs);
+ }
+
//
// Perform CPU specific entry hooks
//
@@ -1256,6 +1730,21 @@ Exit:
RestoreCr2 (Cr2);
}
+/**
+ Allocate buffer for SpinLock and Wrapper function buffer.
+
+**/
+VOID
+InitializeDataForMmMp (
+ VOID
+ )
+{
+ gSmmCpuPrivate->ApWrapperFunc = AllocatePool (sizeof (PROCEDURE_WRAPPER) * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus);
+ ASSERT (gSmmCpuPrivate->ApWrapperFunc != NULL);
+
+ InitializeListHead (&gSmmCpuPrivate->TokenList);
+}
+
/**
Allocate buffer for all semaphores and spin locks.
@@ -1469,3 +1958,40 @@ RegisterSmmEntry (
gSmmCpuPrivate->SmmCoreEntry = SmmEntryPoint;
return EFI_SUCCESS;
}
+
+/**
+
+ Register the SMM Foundation entry point.
+
+ @param[in] Procedure A pointer to the code stream to be run on the designated target AP
+ of the system. Type EFI_AP_PROCEDURE is defined below in Volume 2
+ with the related definitions of
+ EFI_MP_SERVICES_PROTOCOL.StartupAllAPs.
+ If caller may pass a value of NULL to deregister any existing
+ startup procedure.
+ @param[in] ProcedureArguments Allows the caller to pass a list of parameters to the code that is
+ run by the AP. It is an optional common mailbox between APs and
+ the caller to share information
+
+ @retval EFI_SUCCESS The Procedure has been set successfully.
+ @retval EFI_INVALID_PARAMETER The Procedure is NULL but ProcedureArguments not NULL.
+
+**/
+EFI_STATUS
+RegisterStartupProcedure (
+ IN EFI_AP_PROCEDURE Procedure,
+ IN VOID *ProcedureArguments OPTIONAL
+ )
+{
+ if (Procedure == NULL && ProcedureArguments != NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (mSmmMpSyncData == NULL) {
+ return EFI_NOT_READY;
+ }
+
+ mSmmMpSyncData->StartupProcedure = Procedure;
+ mSmmMpSyncData->StartupProcArgs = ProcedureArguments;
+
+ return EFI_SUCCESS;
+}
diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c
index 2f7d777ee7..69a04dfb23 100644
--- a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c
+++ b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c
@@ -34,6 +34,8 @@ SMM_CPU_PRIVATE_DATA mSmmCpuPrivateData = {
mSmmCpuPrivateData.SmmReservedSmramRegion, // SmmConfiguration.SmramReservedRegions
RegisterSmmEntry // SmmConfiguration.RegisterSmmEntry
},
+ NULL, // pointer to Ap Wrapper Func array
+ {NULL, NULL}, // List_Entry for Tokens.
};
CPU_HOT_PLUG_DATA mCpuHotPlugData = {
@@ -996,6 +998,22 @@ PiCpuSmmEntry (
);
ASSERT_EFI_ERROR (Status);
+ //
+ // Initialize global buffer for MM MP.
+ //
+ InitializeDataForMmMp ();
+
+ //
+ // Install the SMM Mp Protocol into SMM protocol database
+ //
+ Status = gSmst->SmmInstallProtocolInterface (
+ &mSmmCpuHandle,
+ &gEfiMmMpProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mSmmMp
+ );
+ ASSERT_EFI_ERROR (Status);
+
//
// Expose address of CPU Hot Plug Data structure if CPU hot plug is supported.
//
diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h
index 2bb35a424d..186809f431 100644
--- a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h
+++ b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h
@@ -20,6 +20,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
#include <Protocol/SmmReadyToLock.h>
#include <Protocol/SmmCpuService.h>
#include <Protocol/SmmMemoryAttribute.h>
+#include <Protocol/MmMp.h>
#include <Guid/AcpiS3Context.h>
#include <Guid/MemoryAttributesTable.h>
@@ -197,6 +198,25 @@ typedef UINT32 SMM_CPU_ARRIVAL_EXCEPTIONS;
#define ARRIVAL_EXCEPTION_DELAYED 0x2
#define ARRIVAL_EXCEPTION_SMI_DISABLED 0x4
+//
+// Wrapper used to convert EFI_AP_PROCEDURE2 and EFI_AP_PROCEDURE.
+//
+typedef struct {
+ EFI_AP_PROCEDURE Procedure;
+ VOID *ProcedureArgument;
+} PROCEDURE_WRAPPER;
+
+#define PROCEDURE_TOKEN_SIGNATURE SIGNATURE_32 ('P', 'R', 'T', 'S')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+
+ SPIN_LOCK *ProcedureToken;
+} PROCEDURE_TOKEN;
+
+#define PROCEDURE_TOKEN_FROM_LINK(a) CR (a, PROCEDURE_TOKEN, Link, PROCEDURE_TOKEN_SIGNATURE)
+
//
// Private structure for the SMM CPU module that is stored in DXE Runtime memory
// Contains the SMM Configuration Protocols that is produced.
@@ -219,6 +239,10 @@ typedef struct {
EFI_SMM_ENTRY_POINT SmmCoreEntry;
EFI_SMM_CONFIGURATION_PROTOCOL SmmConfiguration;
+
+ PROCEDURE_WRAPPER *ApWrapperFunc;
+ LIST_ENTRY TokenList;
+
} SMM_CPU_PRIVATE_DATA;
extern SMM_CPU_PRIVATE_DATA *gSmmCpuPrivate;
@@ -226,6 +250,7 @@ extern CPU_HOT_PLUG_DATA mCpuHotPlugData;
extern UINTN mMaxNumberOfCpus;
extern UINTN mNumberOfCpus;
extern EFI_SMM_CPU_PROTOCOL mSmmCpu;
+extern EFI_MM_MP_PROTOCOL mSmmMp;
///
/// The mode of the CPU at the time an SMI occurs
@@ -363,10 +388,12 @@ SmmRelocationSemaphoreComplete (
///
typedef struct {
SPIN_LOCK *Busy;
- volatile EFI_AP_PROCEDURE Procedure;
+ volatile EFI_AP_PROCEDURE2 Procedure;
volatile VOID *Parameter;
volatile UINT32 *Run;
volatile BOOLEAN *Present;
+ SPIN_LOCK *Token;
+ EFI_STATUS *Status;
} SMM_CPU_DATA_BLOCK;
typedef enum {
@@ -388,6 +415,8 @@ typedef struct {
volatile SMM_CPU_SYNC_MODE EffectiveSyncMode;
volatile BOOLEAN SwitchBsp;
volatile BOOLEAN *CandidateBsp;
+ EFI_AP_PROCEDURE StartupProcedure;
+ VOID *StartupProcArgs;
} SMM_DISPATCHER_MP_SYNC_DATA;
#define SMM_PSD_OFFSET 0xfb00
@@ -410,6 +439,7 @@ typedef struct {
SPIN_LOCK *Busy;
volatile UINT32 *Run;
volatile BOOLEAN *Present;
+ SPIN_LOCK *Token;
} SMM_CPU_SEMAPHORE_CPU;
///
@@ -1259,4 +1289,165 @@ RestoreCr2 (
IN UINTN Cr2
);
+/**
+ Schedule a procedure to run on the specified CPU.
+
+ @param[in] Procedure The address of the procedure to run
+ @param[in] CpuIndex Target CPU Index
+ @param[in,out] ProcArguments The parameter to pass to the procedure
+ @param[in,out] Token This is an optional parameter that allows the caller to execute the
+ procedure in a blocking or non-blocking fashion. If it is NULL the
+ call is blocking, and the call will not return until the AP has
+ completed the procedure. If the token is not NULL, the call will
+ return immediately. The caller can check whether the procedure has
+ completed with CheckOnProcedure or WaitForProcedure.
+ @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for the APs to finish
+ execution of Procedure, either for blocking or non-blocking mode.
+ Zero means infinity. If the timeout expires before all APs return
+ from Procedure, then Procedure on the failed APs is terminated. If
+ the timeout expires in blocking mode, the call returns EFI_TIMEOUT.
+ If the timeout expires in non-blocking mode, the timeout determined
+ can be through CheckOnProcedure or WaitForProcedure.
+ Note that timeout support is optional. Whether an implementation
+ supports this feature can be determined via the Attributes data
+ member.
+ @param[in,out] CPUStatus This optional pointer may be used to get the status code returned
+ by Procedure when it completes execution on the target AP, or with
+ EFI_TIMEOUT if the Procedure fails to complete within the optional
+ timeout. The implementation will update this variable with
+ EFI_NOT_READY prior to starting Procedure on the target AP.
+
+ @retval EFI_INVALID_PARAMETER CpuNumber not valid
+ @retval EFI_INVALID_PARAMETER CpuNumber specifying BSP
+ @retval EFI_INVALID_PARAMETER The AP specified by CpuNumber did not enter SMM
+ @retval EFI_INVALID_PARAMETER The AP specified by CpuNumber is busy
+ @retval EFI_SUCCESS The procedure has been successfully scheduled
+
+**/
+EFI_STATUS
+InternalSmmStartupThisAp (
+ IN EFI_AP_PROCEDURE2 Procedure,
+ IN UINTN CpuIndex,
+ IN OUT VOID *ProcArguments OPTIONAL,
+ IN MM_COMPLETION *Token,
+ IN UINTN TimeoutInMicroseconds,
+ IN OUT EFI_STATUS *CpuStatus
+ );
+
+/**
+ Checks whether the input token is the current used token.
+
+ @param[in] Token This parameter describes the token that was passed into DispatchProcedure or
+ BroadcastProcedure.
+
+ @retval TRUE The input token is the current used token.
+ @retval FALSE The input token is not the current used token.
+**/
+BOOLEAN
+IsTokenInUse (
+ IN SPIN_LOCK *Token
+ );
+
+/**
+ Checks status of specified AP.
+
+ This function checks whether the specified AP has finished the task assigned
+ by StartupThisAP(), and whether timeout expires.
+
+ @param[in] Token This parameter describes the token that was passed into DispatchProcedure or
+ BroadcastProcedure.
+
+ @retval EFI_SUCCESS Specified AP has finished task assigned by StartupThisAPs().
+ @retval EFI_NOT_READY Specified AP has not finished task and timeout has not expired.
+**/
+EFI_STATUS
+IsApReady (
+ IN SPIN_LOCK *Token
+ );
+
+/**
+ Check whether it is an present AP.
+
+ @param CpuIndex The AP index which calls this function.
+
+ @retval TRUE It's a present AP.
+ @retval TRUE This is not an AP or it is not present.
+
+**/
+BOOLEAN
+IsPresentAp (
+ IN UINTN CpuIndex
+ );
+
+/**
+ Worker function to execute a caller provided function on all enabled APs.
+
+ @param[in] Procedure A pointer to the function to be run on
+ enabled APs of the system.
+ @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
+ APs to return from Procedure, either for
+ blocking or non-blocking mode.
+ @param[in,out] ProcedureArgument The parameter passed into Procedure for
+ all APs.
+ @param[in,out] Token This is an optional parameter that allows the caller to execute the
+ procedure in a blocking or non-blocking fashion. If it is NULL the
+ call is blocking, and the call will not return until the AP has
+ completed the procedure. If the token is not NULL, the call will
+ return immediately. The caller can check whether the procedure has
+ completed with CheckOnProcedure or WaitForProcedure.
+ @param[in,out] CPUStatus This optional pointer may be used to get the status code returned
+ by Procedure when it completes execution on the target AP, or with
+ EFI_TIMEOUT if the Procedure fails to complete within the optional
+ timeout. The implementation will update this variable with
+ EFI_NOT_READY prior to starting Procedure on the target AP.
+
+ @retval EFI_SUCCESS In blocking mode, all APs have finished before
+ the timeout expired.
+ @retval EFI_SUCCESS In non-blocking mode, function has been dispatched
+ to all enabled APs.
+ @retval others Failed to Startup all APs.
+
+**/
+EFI_STATUS
+InternalSmmStartupAllAPs (
+ IN EFI_AP_PROCEDURE2 Procedure,
+ IN UINTN TimeoutInMicroseconds,
+ IN OUT VOID *ProcedureArguments OPTIONAL,
+ IN OUT MM_COMPLETION *Token,
+ IN OUT EFI_STATUS *CPUStatus
+ );
+
+/**
+
+ Register the SMM Foundation entry point.
+
+ @param[in] Procedure A pointer to the code stream to be run on the designated target AP
+ of the system. Type EFI_AP_PROCEDURE is defined below in Volume 2
+ with the related definitions of
+ EFI_MP_SERVICES_PROTOCOL.StartupAllAPs.
+ If caller may pass a value of NULL to deregister any existing
+ startup procedure.
+ @param[in,out] ProcedureArguments Allows the caller to pass a list of parameters to the code that is
+ run by the AP. It is an optional common mailbox between APs and
+ the caller to share information
+
+ @retval EFI_SUCCESS The Procedure has been set successfully.
+ @retval EFI_INVALID_PARAMETER The Procedure is NULL but ProcedureArguments not NULL.
+
+**/
+EFI_STATUS
+RegisterStartupProcedure (
+ IN EFI_AP_PROCEDURE Procedure,
+ IN VOID *ProcedureArguments OPTIONAL
+ );
+
+/**
+ Allocate buffer for SpinLock and Wrapper function buffer.
+
+**/
+VOID
+InitializeDataForMmMp (
+ VOID
+ );
+
#endif
diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf
index 466c568d49..da0308c47f 100644
--- a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf
+++ b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf
@@ -40,6 +40,8 @@
SmmProfileInternal.h
SmramSaveState.c
SmmCpuMemoryManagement.c
+ SmmMp.h
+ SmmMp.c
[Sources.Ia32]
Ia32/Semaphore.c
@@ -105,6 +107,7 @@
gEfiSmmReadyToLockProtocolGuid ## NOTIFY
gEfiSmmCpuServiceProtocolGuid ## PRODUCES
gEdkiiSmmMemoryAttributeProtocolGuid ## PRODUCES
+ gEfiMmMpProtocolGuid ## PRODUCES
[Guids]
gEfiAcpiVariableGuid ## SOMETIMES_CONSUMES ## HOB # it is used for S3 boot.
diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.c b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.c
new file mode 100644
index 0000000000..9b2b191e03
--- /dev/null
+++ b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.c
@@ -0,0 +1,344 @@
+/** @file
+SMM MP protocol implementation
+
+Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PiSmmCpuDxeSmm.h"
+#include "SmmMp.h"
+
+///
+/// SMM MP Protocol instance
+///
+EFI_MM_MP_PROTOCOL mSmmMp = {
+ EFI_MM_MP_PROTOCOL_REVISION,
+ 0,
+ SmmMpGetNumberOfProcessors,
+ SmmMpDispatchProcedure,
+ SmmMpBroadcastProcedure,
+ SmmMpSetStartupProcedure,
+ SmmMpCheckForProcedure,
+ SmmMpWaitForProcedure
+};
+
+/**
+ Service to retrieves the number of logical processor in the platform.
+
+ @param[in] This The EFI_MM_MP_PROTOCOL instance.
+ @param[out] NumberOfProcessors Pointer to the total number of logical processors in the system,
+ including the BSP and all APs.
+
+ @retval EFI_SUCCESS The number of processors was retrieved successfully
+ @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL
+**/
+EFI_STATUS
+EFIAPI
+SmmMpGetNumberOfProcessors (
+ IN CONST EFI_MM_MP_PROTOCOL *This,
+ OUT UINTN *NumberOfProcessors
+ )
+{
+ if (NumberOfProcessors == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *NumberOfProcessors = gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This service allows the caller to invoke a procedure one of the application processors (AP). This
+ function uses an optional token parameter to support blocking and non-blocking modes. If the token
+ is passed into the call, the function will operate in a non-blocking fashion and the caller can
+ check for completion with CheckOnProcedure or WaitForProcedure.
+
+ @param[in] This The EFI_MM_MP_PROTOCOL instance.
+ @param[in] Procedure A pointer to the procedure to be run on the designated target
+ AP of the system. Type EFI_AP_PROCEDURE2 is defined below in
+ related definitions.
+ @param[in] CpuNumber The zero-based index of the processor number of the target
+ AP, on which the code stream is supposed to run. If the number
+ points to the calling processor then it will not run the
+ supplied code.
+ @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for this AP to
+ finish execution of Procedure, either for blocking or
+ non-blocking mode. Zero means infinity. If the timeout
+ expires before this AP returns from Procedure, then Procedure
+ on the AP is terminated. If the timeout expires in blocking
+ mode, the call returns EFI_TIMEOUT. If the timeout expires
+ in non-blocking mode, the timeout determined can be through
+ CheckOnProcedure or WaitForProcedure.
+ Note that timeout support is optional. Whether an
+ implementation supports this feature, can be determined via
+ the Attributes data member.
+ @param[in,out] ProcedureArguments Allows the caller to pass a list of parameters to the code
+ that is run by the AP. It is an optional common mailbox
+ between APs and the caller to share information.
+ @param[in,out] Token This is parameter is broken into two components:
+ 1.Token->Completion is an optional parameter that allows the
+ caller to execute the procedure in a blocking or non-blocking
+ fashion. If it is NULL the call is blocking, and the call will
+ not return until the AP has completed the procedure. If the
+ token is not NULL, the call will return immediately. The caller
+ can check whether the procedure has completed with
+ CheckOnProcedure or WaitForProcedure.
+ 2.Token->Status The implementation updates the address pointed
+ at by this variable with the status code returned by Procedure
+ when it completes execution on the target AP, or with EFI_TIMEOUT
+ if the Procedure fails to complete within the optional timeout.
+ The implementation will update this variable with EFI_NOT_READY
+ prior to starting Procedure on the target AP
+ @param[in,out] CPUStatus This optional pointer may be used to get the status code returned
+ by Procedure when it completes execution on the target AP, or with
+ EFI_TIMEOUT if the Procedure fails to complete within the optional
+ timeout. The implementation will update this variable with
+ EFI_NOT_READY prior to starting Procedure on the target AP.
+
+ @retval EFI_SUCCESS In the blocking case, this indicates that Procedure has completed
+ execution on the target AP.
+ In the non-blocking case this indicates that the procedure has
+ been successfully scheduled for execution on the target AP.
+ @retval EFI_INVALID_PARAMETER The input arguments are out of range. Either the target AP is the
+ caller of the function, or the Procedure or Token is NULL
+ @retval EFI_NOT_READY If the target AP is busy executing another procedure
+ @retval EFI_ALREADY_STARTED Token is already in use for another procedure
+ @retval EFI_TIMEOUT In blocking mode, the timeout expired before the specified AP
+ has finished
+ @retval EFI_OUT_OF_RESOURCES Could not allocate a required resource.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmMpDispatchProcedure (
+ IN CONST EFI_MM_MP_PROTOCOL *This,
+ IN EFI_AP_PROCEDURE2 Procedure,
+ IN UINTN CpuNumber,
+ IN UINTN TimeoutInMicroseconds,
+ IN OUT VOID *ProcedureArguments OPTIONAL,
+ IN OUT MM_COMPLETION *Token,
+ IN OUT EFI_STATUS *CPUStatus
+ )
+{
+ return InternalSmmStartupThisAp (
+ Procedure,
+ CpuNumber,
+ ProcedureArguments,
+ Token,
+ TimeoutInMicroseconds,
+ CPUStatus
+ );
+}
+
+/**
+ This service allows the caller to invoke a procedure on all running application processors (AP)
+ except the caller. This function uses an optional token parameter to support blocking and
+ nonblocking modes. If the token is passed into the call, the function will operate in a non-blocking
+ fashion and the caller can check for completion with CheckOnProcedure or WaitForProcedure.
+
+ It is not necessary for the implementation to run the procedure on every processor on the platform.
+ Processors that are powered down in such a way that they cannot respond to interrupts, may be
+ excluded from the broadcast.
+
+
+ @param[in] This The EFI_MM_MP_PROTOCOL instance.
+ @param[in] Procedure A pointer to the code stream to be run on the APs that have
+ entered MM. Type EFI_AP_PROCEDURE is defined below in related
+ definitions.
+ @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for the APs to finish
+ execution of Procedure, either for blocking or non-blocking mode.
+ Zero means infinity. If the timeout expires before all APs return
+ from Procedure, then Procedure on the failed APs is terminated. If
+ the timeout expires in blocking mode, the call returns EFI_TIMEOUT.
+ If the timeout expires in non-blocking mode, the timeout determined
+ can be through CheckOnProcedure or WaitForProcedure.
+ Note that timeout support is optional. Whether an implementation
+ supports this feature can be determined via the Attributes data
+ member.
+ @param[in,out] ProcedureArguments Allows the caller to pass a list of parameters to the code
+ that is run by the AP. It is an optional common mailbox
+ between APs and the caller to share information.
+ @param[in,out] Token This is parameter is broken into two components:
+ 1.Token->Completion is an optional parameter that allows the
+ caller to execute the procedure in a blocking or non-blocking
+ fashion. If it is NULL the call is blocking, and the call will
+ not return until the AP has completed the procedure. If the
+ token is not NULL, the call will return immediately. The caller
+ can check whether the procedure has completed with
+ CheckOnProcedure or WaitForProcedure.
+ 2.Token->Status The implementation updates the address pointed
+ at by this variable with the status code returned by Procedure
+ when it completes execution on the target AP, or with EFI_TIMEOUT
+ if the Procedure fails to complete within the optional timeout.
+ The implementation will update this variable with EFI_NOT_READY
+ prior to starting Procedure on the target AP
+ @param[in,out] CPUStatus This optional pointer may be used to get the individual status
+ returned by every AP that participated in the broadcast. This
+ parameter if used provides the base address of an array to hold
+ the EFI_STATUS value of each AP in the system. The size of the
+ array can be ascertained by the GetNumberOfProcessors function.
+ As mentioned above, the broadcast may not include every processor
+ in the system. Some implementations may exclude processors that
+ have been powered down in such a way that they are not responsive
+ to interrupts. Additionally the broadcast excludes the processor
+ which is making the BroadcastProcedure call. For every excluded
+ processor, the array entry must contain a value of EFI_NOT_STARTED
+
+ @retval EFI_SUCCESS In the blocking case, this indicates that Procedure has completed
+ execution on the APs.
+ In the non-blocking case this indicates that the procedure has
+ been successfully scheduled for execution on the APs.
+ @retval EFI_INVALID_PARAMETER The Procedure or Token is NULL
+ @retval EFI_NOT_READY If the target AP is busy executing another procedure
+ @retval EFI_ALREADY_STARTED Token is already in use for another procedure
+ @retval EFI_TIMEOUT In blocking mode, the timeout expired before the specified AP
+ has finished.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate a required resource.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmMpBroadcastProcedure (
+ IN CONST EFI_MM_MP_PROTOCOL *This,
+ IN EFI_AP_PROCEDURE2 Procedure,
+ IN UINTN TimeoutInMicroseconds,
+ IN OUT VOID *ProcedureArguments OPTIONAL,
+ IN OUT MM_COMPLETION *Token,
+ IN OUT EFI_STATUS *CPUStatus
+ )
+{
+ return InternalSmmStartupAllAPs(
+ Procedure,
+ TimeoutInMicroseconds,
+ ProcedureArguments,
+ Token,
+ CPUStatus
+ );
+}
+
+/**
+ This service allows the caller to set a startup procedure that will be executed when an AP powers
+ up from a state where core configuration and context is lost. The procedure is execution has the
+ following properties:
+ 1. The procedure executes before the processor is handed over to the operating system.
+ 2. All processors execute the same startup procedure.
+ 3. The procedure may run in parallel with other procedures invoked through the functions in this
+ protocol, or with processors that are executing an MM handler or running in the operating system.
+
+
+ @param[in] This The EFI_MM_MP_PROTOCOL instance.
+ @param[in] Procedure A pointer to the code stream to be run on the designated target AP
+ of the system. Type EFI_AP_PROCEDURE is defined below in Volume 2
+ with the related definitions of
+ EFI_MP_SERVICES_PROTOCOL.StartupAllAPs.
+ If caller may pass a value of NULL to deregister any existing
+ startup procedure.
+ @param[in,out] ProcedureArguments Allows the caller to pass a list of parameters to the code that is
+ run by the AP. It is an optional common mailbox between APs and
+ the caller to share information
+
+ @retval EFI_SUCCESS The Procedure has been set successfully.
+ @retval EFI_INVALID_PARAMETER The Procedure is NULL but ProcedureArguments not NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmMpSetStartupProcedure (
+ IN CONST EFI_MM_MP_PROTOCOL *This,
+ IN EFI_AP_PROCEDURE Procedure,
+ IN OUT VOID *ProcedureArguments OPTIONAL
+ )
+{
+ return RegisterStartupProcedure (Procedure, ProcedureArguments);
+}
+
+/**
+ When non-blocking execution of a procedure on an AP is invoked with DispatchProcedure,
+ via the use of a token, this function can be used to check for completion of the procedure on the AP.
+ The function takes the token that was passed into the DispatchProcedure call. If the procedure
+ is complete, and therefore it is now possible to run another procedure on the same AP, this function
+ returns EFI_SUCESS. In this case the status returned by the procedure that executed on the AP is
+ returned in the token's Status field. If the procedure has not yet completed, then this function
+ returns EFI_NOT_READY.
+
+ When a non-blocking execution of a procedure is invoked with BroadcastProcedure, via the
+ use of a token, this function can be used to check for completion of the procedure on all the
+ broadcast APs. The function takes the token that was passed into the BroadcastProcedure
+ call. If the procedure is complete on all broadcast APs this function returns EFI_SUCESS. In this
+ case the Status field in the token passed into the function reflects the overall result of the
+ invocation, which may be EFI_SUCCESS, if all executions succeeded, or the first observed failure.
+ If the procedure has not yet completed on the broadcast APs, the function returns
+ EFI_NOT_READY.
+
+ @param[in] This The EFI_MM_MP_PROTOCOL instance.
+ @param[in] Token This parameter describes the token that was passed into
+ DispatchProcedure or BroadcastProcedure.
+
+ @retval EFI_SUCCESS Procedure has completed.
+ @retval EFI_NOT_READY The Procedure has not completed.
+ @retval EFI_INVALID_PARAMETER Token or Token->Completion is NULL
+ @retval EFI_NOT_FOUND Token is not currently in use for a non-blocking call
+
+**/
+EFI_STATUS
+EFIAPI
+SmmMpCheckForProcedure (
+ IN CONST EFI_MM_MP_PROTOCOL *This,
+ IN MM_COMPLETION Token
+ )
+{
+ if (Token == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!IsTokenInUse ((SPIN_LOCK *)Token)) {
+ return EFI_NOT_FOUND;
+ }
+
+ return IsApReady ((SPIN_LOCK *)Token);
+}
+
+/**
+ When a non-blocking execution of a procedure on an AP is invoked via DispatchProcedure,
+ this function will block the caller until the remote procedure has completed on the designated AP.
+ The non-blocking procedure invocation is identified by the Token parameter, which must match the
+ token that used when DispatchProcedure was called. Upon completion the status returned by
+ the procedure that executed on the AP is used to update the token's Status field.
+
+ When a non-blocking execution of a procedure on an AP is invoked via BroadcastProcedure
+ this function will block the caller until the remote procedure has completed on all of the APs that
+ entered MM. The non-blocking procedure invocation is identified by the Token parameter, which
+ must match the token that used when BroadcastProcedure was called. Upon completion the
+ overall status returned by the procedures that executed on the broadcast AP is used to update the
+ token's Status field. The overall status may be EFI_SUCCESS, if all executions succeeded, or the
+ first observed failure.
+
+
+ @param[in] This The EFI_MM_MP_PROTOCOL instance.
+ @param[in] Token This parameter describes the token that was passed into
+ DispatchProcedure or BroadcastProcedure.
+
+ @retval EFI_SUCCESS Procedure has completed.
+ @retval EFI_INVALID_PARAMETER Token or Token->Completion is NULL
+ @retval EFI_NOT_FOUND Token is not currently in use for a non-blocking call
+
+**/
+EFI_STATUS
+EFIAPI
+SmmMpWaitForProcedure (
+ IN CONST EFI_MM_MP_PROTOCOL *This,
+ IN MM_COMPLETION Token
+ )
+{
+ EFI_STATUS Status;
+
+ do {
+ Status = SmmMpCheckForProcedure (This, Token);
+ } while (Status == EFI_NOT_READY);
+
+ return Status;
+}
+
diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.h b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.h
new file mode 100644
index 0000000000..e0d823a4b1
--- /dev/null
+++ b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.h
@@ -0,0 +1,286 @@
+/** @file
+Include file for SMM MP protocol implementation.
+
+Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _SMM_MP_PROTOCOL_H_
+#define _SMM_MP_PROTOCOL_H_
+
+//
+// SMM MP Protocol function prototypes.
+//
+
+/**
+ Service to retrieves the number of logical processor in the platform.
+
+ @param[in] This The EFI_MM_MP_PROTOCOL instance.
+ @param[out] NumberOfProcessors Pointer to the total number of logical processors in the system,
+ including the BSP and all APs.
+
+ @retval EFI_SUCCESS The number of processors was retrieved successfully
+ @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL
+**/
+
+EFI_STATUS
+EFIAPI
+SmmMpGetNumberOfProcessors (
+ IN CONST EFI_MM_MP_PROTOCOL *This,
+ OUT UINTN *NumberOfProcessors
+ );
+
+
+/**
+ This service allows the caller to invoke a procedure one of the application processors (AP). This
+ function uses an optional token parameter to support blocking and non-blocking modes. If the token
+ is passed into the call, the function will operate in a non-blocking fashion and the caller can
+ check for completion with CheckOnProcedure or WaitForProcedure.
+
+ @param[in] This The EFI_MM_MP_PROTOCOL instance.
+ @param[in] Procedure A pointer to the procedure to be run on the designated target
+ AP of the system. Type EFI_AP_PROCEDURE2 is defined below in
+ related definitions.
+ @param[in] CpuNumber The zero-based index of the processor number of the target
+ AP, on which the code stream is supposed to run. If the number
+ points to the calling processor then it will not run the
+ supplied code.
+ @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for this AP to
+ finish execution of Procedure, either for blocking or
+ non-blocking mode. Zero means infinity. If the timeout
+ expires before this AP returns from Procedure, then Procedure
+ on the AP is terminated. If the timeout expires in blocking
+ mode, the call returns EFI_TIMEOUT. If the timeout expires
+ in non-blocking mode, the timeout determined can be through
+ CheckOnProcedure or WaitForProcedure.
+ Note that timeout support is optional. Whether an
+ implementation supports this feature, can be determined via
+ the Attributes data member.
+ @param[in,out] ProcedureArguments Allows the caller to pass a list of parameters to the code
+ that is run by the AP. It is an optional common mailbox
+ between APs and the caller to share information.
+ @param[in,out] Token This is parameter is broken into two components:
+ 1.Token->Completion is an optional parameter that allows the
+ caller to execute the procedure in a blocking or non-blocking
+ fashion. If it is NULL the call is blocking, and the call will
+ not return until the AP has completed the procedure. If the
+ token is not NULL, the call will return immediately. The caller
+ can check whether the procedure has completed with
+ CheckOnProcedure or WaitForProcedure.
+ 2.Token->Status The implementation updates the address pointed
+ at by this variable with the status code returned by Procedure
+ when it completes execution on the target AP, or with EFI_TIMEOUT
+ if the Procedure fails to complete within the optional timeout.
+ The implementation will update this variable with EFI_NOT_READY
+ prior to starting Procedure on the target AP
+ @param[in,out] CPUStatus This optional pointer may be used to get the status code returned
+ by Procedure when it completes execution on the target AP, or with
+ EFI_TIMEOUT if the Procedure fails to complete within the optional
+ timeout. The implementation will update this variable with
+ EFI_NOT_READY prior to starting Procedure on the target AP.
+
+ @retval EFI_SUCCESS In the blocking case, this indicates that Procedure has completed
+ execution on the target AP.
+ In the non-blocking case this indicates that the procedure has
+ been successfully scheduled for execution on the target AP.
+ @retval EFI_INVALID_PARAMETER The input arguments are out of range. Either the target AP is the
+ caller of the function, or the Procedure or Token is NULL
+ @retval EFI_NOT_READY If the target AP is busy executing another procedure
+ @retval EFI_ALREADY_STARTED Token is already in use for another procedure
+ @retval EFI_TIMEOUT In blocking mode, the timeout expired before the specified AP
+ has finished
+ @retval EFI_OUT_OF_RESOURCES Could not allocate a required resource.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmMpDispatchProcedure (
+ IN CONST EFI_MM_MP_PROTOCOL *This,
+ IN EFI_AP_PROCEDURE2 Procedure,
+ IN UINTN CpuNumber,
+ IN UINTN TimeoutInMicroseconds,
+ IN OUT VOID *ProcedureArguments OPTIONAL,
+ IN OUT MM_COMPLETION *Token,
+ IN OUT EFI_STATUS *CPUStatus
+ );
+
+/**
+ This service allows the caller to invoke a procedure on all running application processors (AP)
+ except the caller. This function uses an optional token parameter to support blocking and
+ nonblocking modes. If the token is passed into the call, the function will operate in a non-blocking
+ fashion and the caller can check for completion with CheckOnProcedure or WaitForProcedure.
+
+ It is not necessary for the implementation to run the procedure on every processor on the platform.
+ Processors that are powered down in such a way that they cannot respond to interrupts, may be
+ excluded from the broadcast.
+
+
+ @param[in] This The EFI_MM_MP_PROTOCOL instance.
+ @param[in] Procedure A pointer to the code stream to be run on the APs that have
+ entered MM. Type EFI_AP_PROCEDURE is defined below in related
+ definitions.
+ @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for the APs to finish
+ execution of Procedure, either for blocking or non-blocking mode.
+ Zero means infinity. If the timeout expires before all APs return
+ from Procedure, then Procedure on the failed APs is terminated. If
+ the timeout expires in blocking mode, the call returns EFI_TIMEOUT.
+ If the timeout expires in non-blocking mode, the timeout determined
+ can be through CheckOnProcedure or WaitForProcedure.
+ Note that timeout support is optional. Whether an implementation
+ supports this feature can be determined via the Attributes data
+ member.
+ @param[in,out] ProcedureArguments Allows the caller to pass a list of parameters to the code
+ that is run by the AP. It is an optional common mailbox
+ between APs and the caller to share information.
+ @param[in,out] Token This is parameter is broken into two components:
+ 1.Token->Completion is an optional parameter that allows the
+ caller to execute the procedure in a blocking or non-blocking
+ fashion. If it is NULL the call is blocking, and the call will
+ not return until the AP has completed the procedure. If the
+ token is not NULL, the call will return immediately. The caller
+ can check whether the procedure has completed with
+ CheckOnProcedure or WaitForProcedure.
+ 2.Token->Status The implementation updates the address pointed
+ at by this variable with the status code returned by Procedure
+ when it completes execution on the target AP, or with EFI_TIMEOUT
+ if the Procedure fails to complete within the optional timeout.
+ The implementation will update this variable with EFI_NOT_READY
+ prior to starting Procedure on the target AP
+ @param[in,out] CPUStatus This optional pointer may be used to get the individual status
+ returned by every AP that participated in the broadcast. This
+ parameter if used provides the base address of an array to hold
+ the EFI_STATUS value of each AP in the system. The size of the
+ array can be ascertained by the GetNumberOfProcessors function.
+ As mentioned above, the broadcast may not include every processor
+ in the system. Some implementations may exclude processors that
+ have been powered down in such a way that they are not responsive
+ to interrupts. Additionally the broadcast excludes the processor
+ which is making the BroadcastProcedure call. For every excluded
+ processor, the array entry must contain a value of EFI_NOT_STARTED
+
+ @retval EFI_SUCCESS In the blocking case, this indicates that Procedure has completed
+ execution on the APs.
+ In the non-blocking case this indicates that the procedure has
+ been successfully scheduled for execution on the APs.
+ @retval EFI_INVALID_PARAMETER The Procedure or Token is NULL
+ @retval EFI_NOT_READY If the target AP is busy executing another procedure
+ @retval EFI_ALREADY_STARTED Token is already in use for another procedure
+ @retval EFI_TIMEOUT In blocking mode, the timeout expired before the specified AP
+ has finished
+ @retval EFI_OUT_OF_RESOURCES Could not allocate a required resource.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmMpBroadcastProcedure (
+ IN CONST EFI_MM_MP_PROTOCOL *This,
+ IN EFI_AP_PROCEDURE2 Procedure,
+ IN UINTN TimeoutInMicroseconds,
+ IN OUT VOID *ProcedureArguments OPTIONAL,
+ IN OUT MM_COMPLETION *Token,
+ IN OUT EFI_STATUS *CPUStatus
+ );
+
+
+/**
+ This service allows the caller to set a startup procedure that will be executed when an AP powers
+ up from a state where core configuration and context is lost. The procedure is execution has the
+ following properties:
+ 1. The procedure executes before the processor is handed over to the operating system.
+ 2. All processors execute the same startup procedure.
+ 3. The procedure may run in parallel with other procedures invoked through the functions in this
+ protocol, or with processors that are executing an MM handler or running in the operating system.
+
+
+ @param[in] This The EFI_MM_MP_PROTOCOL instance.
+ @param[in] Procedure A pointer to the code stream to be run on the designated target AP
+ of the system. Type EFI_AP_PROCEDURE is defined below in Volume 2
+ with the related definitions of
+ EFI_MP_SERVICES_PROTOCOL.StartupAllAPs.
+ If caller may pass a value of NULL to deregister any existing
+ startup procedure.
+ @param[in,out] ProcedureArguments Allows the caller to pass a list of parameters to the code that is
+ run by the AP. It is an optional common mailbox between APs and
+ the caller to share information
+
+ @retval EFI_SUCCESS The Procedure has been set successfully.
+ @retval EFI_INVALID_PARAMETER The Procedure is NULL but ProcedureArguments not NULL.
+**/
+EFI_STATUS
+EFIAPI
+SmmMpSetStartupProcedure (
+ IN CONST EFI_MM_MP_PROTOCOL *This,
+ IN EFI_AP_PROCEDURE Procedure,
+ IN OUT VOID *ProcedureArguments OPTIONAL
+ );
+
+/**
+ When non-blocking execution of a procedure on an AP is invoked with DispatchProcedure,
+ via the use of a token, this function can be used to check for completion of the procedure on the AP.
+ The function takes the token that was passed into the DispatchProcedure call. If the procedure
+ is complete, and therefore it is now possible to run another procedure on the same AP, this function
+ returns EFI_SUCESS. In this case the status returned by the procedure that executed on the AP is
+ returned in the token's Status field. If the procedure has not yet completed, then this function
+ returns EFI_NOT_READY.
+
+ When a non-blocking execution of a procedure is invoked with BroadcastProcedure, via the
+ use of a token, this function can be used to check for completion of the procedure on all the
+ broadcast APs. The function takes the token that was passed into the BroadcastProcedure
+ call. If the procedure is complete on all broadcast APs this function returns EFI_SUCESS. In this
+ case the Status field in the token passed into the function reflects the overall result of the
+ invocation, which may be EFI_SUCCESS, if all executions succeeded, or the first observed failure.
+ If the procedure has not yet completed on the broadcast APs, the function returns
+ EFI_NOT_READY.
+
+ @param[in] This The EFI_MM_MP_PROTOCOL instance.
+ @param[in] Token This parameter describes the token that was passed into
+ DispatchProcedure or BroadcastProcedure.
+
+ @retval EFI_SUCCESS Procedure has completed.
+ @retval EFI_NOT_READY The Procedure has not completed.
+ @retval EFI_INVALID_PARAMETER Token or Token->Completion is NULL
+ @retval EFI_NOT_FOUND Token is not currently in use for a non-blocking call
+
+**/
+EFI_STATUS
+EFIAPI
+SmmMpCheckForProcedure (
+ IN CONST EFI_MM_MP_PROTOCOL *This,
+ IN MM_COMPLETION Token
+ );
+
+/**
+ When a non-blocking execution of a procedure on an AP is invoked via DispatchProcedure,
+ this function will block the caller until the remote procedure has completed on the designated AP.
+ The non-blocking procedure invocation is identified by the Token parameter, which must match the
+ token that used when DispatchProcedure was called. Upon completion the status returned by
+ the procedure that executed on the AP is used to update the token's Status field.
+
+ When a non-blocking execution of a procedure on an AP is invoked via BroadcastProcedure
+ this function will block the caller until the remote procedure has completed on all of the APs that
+ entered MM. The non-blocking procedure invocation is identified by the Token parameter, which
+ must match the token that used when BroadcastProcedure was called. Upon completion the
+ overall status returned by the procedures that executed on the broadcast AP is used to update the
+ token's Status field. The overall status may be EFI_SUCCESS, if all executions succeeded, or the
+ first observed failure.
+
+
+ @param[in] This The EFI_MM_MP_PROTOCOL instance.
+ @param[in] Token This parameter describes the token that was passed into
+ DispatchProcedure or BroadcastProcedure.
+
+ @retval EFI_SUCCESS Procedure has completed.
+ @retval EFI_INVALID_PARAMETER Token or Token->Completion is NULL
+ @retval EFI_NOT_FOUND Token is not currently in use for a non-blocking call
+
+**/
+EFI_STATUS
+EFIAPI
+SmmMpWaitForProcedure (
+ IN CONST EFI_MM_MP_PROTOCOL *This,
+ IN MM_COMPLETION Token
+ );
+
+#endif
--
2.21.0.windows.1
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#43463): https://edk2.groups.io/g/devel/message/43463
Mute This Topic: https://groups.io/mt/32414082/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-
Reviewed-by: Ray Ni <ray.ni@intel.com>
> -----Original Message-----
> From: Dong, Eric
> Sent: Wednesday, July 10, 2019 3:56 PM
> To: devel@edk2.groups.io
> Cc: Ni, Ray <ray.ni@intel.com>; Laszlo Ersek <lersek@redhat.com>
> Subject: [Patch v5 2/2] UefiCpuPkg/PiSmmCpuDxeSmm: Enable MM MP
> Protocol
>
> V5 changes:
> 1. some small enhancement.
>
> v4 changes:
> 1. Use link list to save the token info.
>
> v3 changes:
> 1. Fix Token clean up too early caused CheckProcedure return error.
>
> v2 changes:
> 1. Remove some duplicated global variables.
> 2. Enhance token design to support multiple task trig for different APs at the
> same time.
>
> V1 changes:
> REF: https://bugzilla.tianocore.org/show_bug.cgi?id=1937
>
> Add MM Mp Protocol in PiSmmCpuDxeSmm driver.
>
> Cc: Ray Ni <ray.ni@intel.com>
> Cc: Laszlo Ersek <lersek@redhat.com>
> Signed-off-by: Eric Dong <eric.dong@intel.com>
> ---
> UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c | 570
> ++++++++++++++++++-
> UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c | 18 +
> UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h | 193 ++++++-
> UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf | 3 +
> UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.c | 344 +++++++++++
> UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.h | 286 ++++++++++
> 6 files changed, 1391 insertions(+), 23 deletions(-)
> create mode 100644 UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.c
> create mode 100644 UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.h
>
> diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c
> b/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c
> index 64fb4d6344..f09e2738c3 100644
> --- a/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c
> +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c
> @@ -140,7 +140,7 @@ ReleaseAllAPs (
>
> BspIndex = mSmmMpSyncData->BspIndex;
> for (Index = mMaxNumberOfCpus; Index-- > 0;) {
> - if (Index != BspIndex && *(mSmmMpSyncData->CpuData[Index].Present))
> {
> + if (IsPresentAp (Index)) {
> ReleaseSemaphore (mSmmMpSyncData->CpuData[Index].Run);
> }
> }
> @@ -347,6 +347,165 @@ ReplaceOSMtrrs (
> MtrrSetAllMtrrs (&gSmiMtrrs);
> }
>
> +/**
> + Wheck whether task has been finished by all APs.
> +
> + @param BlockMode Whether did it in block mode or non-block mode.
> +
> + @retval TRUE Task has been finished by all APs.
> + @retval FALSE Task not has been finished by all APs.
> +
> +**/
> +BOOLEAN
> +WaitForAllAPsNotBusy (
> + IN BOOLEAN BlockMode
> + )
> +{
> + UINTN Index;
> +
> + for (Index = mMaxNumberOfCpus; Index-- > 0;) {
> + //
> + // Ignore BSP and APs which not call in SMM.
> + //
> + if (!IsPresentAp(Index)) {
> + continue;
> + }
> +
> + if (BlockMode) {
> + AcquireSpinLock(mSmmMpSyncData->CpuData[Index].Busy);
> + ReleaseSpinLock(mSmmMpSyncData->CpuData[Index].Busy);
> + } else {
> + if (AcquireSpinLockOrFail (mSmmMpSyncData->CpuData[Index].Busy)) {
> + ReleaseSpinLock(mSmmMpSyncData->CpuData[Index].Busy);
> + } else {
> + return FALSE;
> + }
> + }
> + }
> +
> + return TRUE;
> +}
> +
> +/**
> + Check whether it is an present AP.
> +
> + @param CpuIndex The AP index which calls this function.
> +
> + @retval TRUE It's a present AP.
> + @retval TRUE This is not an AP or it is not present.
> +
> +**/
> +BOOLEAN
> +IsPresentAp (
> + IN UINTN CpuIndex
> + )
> +{
> + return ((CpuIndex != gSmmCpuPrivate-
> >SmmCoreEntryContext.CurrentlyExecutingCpu) &&
> + *(mSmmMpSyncData->CpuData[CpuIndex].Present));
> +}
> +
> +/**
> + Check whether execute in single AP or all APs.
> +
> + Compare two Tokens used by different APs to know whether in
> StartAllAps call.
> +
> + Whether is an valid AP base on AP's Present flag.
> +
> + @retval TRUE IN StartAllAps call.
> + @retval FALSE Not in StartAllAps call.
> +
> +**/
> +BOOLEAN
> +InStartAllApsCall (
> + VOID
> + )
> +{
> + UINTN ApIndex;
> + UINTN ApIndex2;
> +
> + for (ApIndex = mMaxNumberOfCpus; ApIndex-- > 0;) {
> + if (IsPresentAp (ApIndex) && (mSmmMpSyncData-
> >CpuData[ApIndex].Token != NULL)) {
> + for (ApIndex2 = ApIndex; ApIndex2-- > 0;) {
> + if (IsPresentAp (ApIndex2) && (mSmmMpSyncData-
> >CpuData[ApIndex2].Token != NULL)) {
> + return mSmmMpSyncData->CpuData[ApIndex2].Token ==
> mSmmMpSyncData->CpuData[ApIndex].Token;
> + }
> + }
> + }
> + }
> +
> + return FALSE;
> +}
> +
> +/**
> + Clean up the status flags used during executing the procedure.
> +
> + @param CpuIndex The AP index which calls this function.
> +
> +**/
> +VOID
> +ReleaseToken (
> + IN UINTN CpuIndex
> + )
> +{
> + UINTN Index;
> + BOOLEAN Released;
> +
> + if (InStartAllApsCall ()) {
> + //
> + // In Start All APs mode, make sure all APs have finished task.
> + //
> + if (WaitForAllAPsNotBusy (FALSE)) {
> + //
> + // Clean the flags update in the function call.
> + //
> + Released = FALSE;
> + for (Index = mMaxNumberOfCpus; Index-- > 0;) {
> + //
> + // Only In SMM APs need to be clean up.
> + //
> + if (mSmmMpSyncData->CpuData[Index].Present &&
> mSmmMpSyncData->CpuData[Index].Token != NULL) {
> + if (!Released) {
> + ReleaseSpinLock (mSmmMpSyncData->CpuData[Index].Token);
> + Released = TRUE;
> + }
> + mSmmMpSyncData->CpuData[Index].Token = NULL;
> + }
> + }
> + }
> + } else {
> + //
> + // In single AP mode.
> + //
> + if (mSmmMpSyncData->CpuData[CpuIndex].Token != NULL) {
> + ReleaseSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Token);
> + mSmmMpSyncData->CpuData[CpuIndex].Token = NULL;
> + }
> + }
> +}
> +
> +/**
> + Free the tokens in the maintained list.
> +
> +**/
> +VOID
> +FreeTokens (
> + VOID
> + )
> +{
> + LIST_ENTRY *Link;
> + PROCEDURE_TOKEN *ProcToken;
> +
> + while (!IsListEmpty (&gSmmCpuPrivate->TokenList)) {
> + Link = GetFirstNode (&gSmmCpuPrivate->TokenList);
> + ProcToken = PROCEDURE_TOKEN_FROM_LINK (Link);
> +
> + RemoveEntryList (&ProcToken->Link);
> +
> + FreePool ((VOID *)ProcToken->ProcedureToken);
> + FreePool (ProcToken);
> + }
> +}
> +
> /**
> SMI handler for BSP.
>
> @@ -476,12 +635,7 @@ BSPHandler (
> //
> // Make sure all APs have completed their pending none-block tasks
> //
> - for (Index = mMaxNumberOfCpus; Index-- > 0;) {
> - if (Index != CpuIndex && *(mSmmMpSyncData-
> >CpuData[Index].Present)) {
> - AcquireSpinLock (mSmmMpSyncData->CpuData[Index].Busy);
> - ReleaseSpinLock (mSmmMpSyncData->CpuData[Index].Busy);
> - }
> - }
> + WaitForAllAPsNotBusy (TRUE);
>
> //
> // Perform the remaining tasks
> @@ -572,6 +726,11 @@ BSPHandler (
> //
> WaitForAllAPs (ApCount);
>
> + //
> + // Clean the tokens buffer.
> + //
> + FreeTokens ();
> +
> //
> // Reset BspIndex to -1, meaning BSP has not been elected.
> //
> @@ -604,6 +763,7 @@ APHandler (
> UINT64 Timer;
> UINTN BspIndex;
> MTRR_SETTINGS Mtrrs;
> + EFI_STATUS ProcedureStatus;
>
> //
> // Timeout BSP
> @@ -730,14 +890,19 @@ APHandler (
> //
> // Invoke the scheduled procedure
> //
> - (*mSmmMpSyncData->CpuData[CpuIndex].Procedure) (
> - (VOID*)mSmmMpSyncData->CpuData[CpuIndex].Parameter
> - );
> + ProcedureStatus = (*mSmmMpSyncData-
> >CpuData[CpuIndex].Procedure) (
> + (VOID*)mSmmMpSyncData->CpuData[CpuIndex].Parameter
> + );
> + if (mSmmMpSyncData->CpuData[CpuIndex].Status != NULL) {
> + *mSmmMpSyncData->CpuData[CpuIndex].Status = ProcedureStatus;
> + }
>
> //
> // Release BUSY
> //
> ReleaseSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy);
> +
> + ReleaseToken (CpuIndex);
> }
>
> if (SmmCpuFeaturesNeedConfigureMtrrs()) {
> @@ -906,13 +1071,124 @@ Gen4GPageTable (
> return (UINT32)(UINTN)PageTable;
> }
>
> +/**
> + Checks whether the input token is the current used token.
> +
> + @param[in] Token This parameter describes the token that was passed
> into DispatchProcedure or
> + BroadcastProcedure.
> +
> + @retval TRUE The input token is the current used token.
> + @retval FALSE The input token is not the current used token.
> +**/
> +BOOLEAN
> +IsTokenInUse (
> + IN SPIN_LOCK *Token
> + )
> +{
> + LIST_ENTRY *Link;
> + PROCEDURE_TOKEN *ProcToken;
> +
> + if (Token == NULL) {
> + return FALSE;
> + }
> +
> + Link = GetFirstNode (&gSmmCpuPrivate->TokenList);
> + while (!IsNull (&gSmmCpuPrivate->TokenList, Link)) {
> + ProcToken = PROCEDURE_TOKEN_FROM_LINK (Link);
> +
> + if (ProcToken->ProcedureToken == Token) {
> + return TRUE;
> + }
> +
> + Link = GetNextNode (&gSmmCpuPrivate->TokenList, Link);
> + }
> +
> + return FALSE;
> +}
> +
> +/**
> + create token and save it to the maintain list.
> +
> + @retval return the spin lock used as token.
> +
> +**/
> +SPIN_LOCK *
> +CreateToken (
> + VOID
> + )
> +{
> + PROCEDURE_TOKEN *ProcToken;
> + SPIN_LOCK *CpuToken;
> + UINTN SpinLockSize;
> +
> + SpinLockSize = GetSpinLockProperties ();
> + CpuToken = AllocatePool (SpinLockSize);
> + ASSERT (CpuToken != NULL);
> + InitializeSpinLock (CpuToken);
> + AcquireSpinLock (CpuToken);
> +
> + ProcToken = AllocatePool (sizeof (PROCEDURE_TOKEN));
> + ASSERT (ProcToken != NULL);
> + ProcToken->Signature = PROCEDURE_TOKEN_SIGNATURE;
> + ProcToken->ProcedureToken = CpuToken;
> +
> + InsertTailList (&gSmmCpuPrivate->TokenList, &ProcToken->Link);
> +
> + return CpuToken;
> +}
> +
> +/**
> + Checks status of specified AP.
> +
> + This function checks whether the specified AP has finished the task
> assigned
> + by StartupThisAP(), and whether timeout expires.
> +
> + @param[in] Token This parameter describes the token that was
> passed into DispatchProcedure or
> + BroadcastProcedure.
> +
> + @retval EFI_SUCCESS Specified AP has finished task assigned by
> StartupThisAPs().
> + @retval EFI_NOT_READY Specified AP has not finished task and
> timeout has not expired.
> +**/
> +EFI_STATUS
> +IsApReady (
> + IN SPIN_LOCK *Token
> + )
> +{
> + if (AcquireSpinLockOrFail (Token)) {
> + ReleaseSpinLock (Token);
> + return EFI_SUCCESS;
> + }
> +
> + return EFI_NOT_READY;
> +}
> +
> /**
> Schedule a procedure to run on the specified CPU.
>
> @param[in] Procedure The address of the procedure to run
> @param[in] CpuIndex Target CPU Index
> - @param[in, out] ProcArguments The parameter to pass to the
> procedure
> - @param[in] BlockingMode Startup AP in blocking mode or not
> + @param[in,out] ProcArguments The parameter to pass to the
> procedure
> + @param[in] Token This is an optional parameter that allows
> the caller to execute the
> + procedure in a blocking or non-blocking fashion. If it is
> NULL the
> + call is blocking, and the call will not return until the AP
> has
> + completed the procedure. If the token is not NULL,
> the call will
> + return immediately. The caller can check whether the
> procedure has
> + completed with CheckOnProcedure or
> WaitForProcedure.
> + @param[in] TimeoutInMicroseconds Indicates the time limit in
> microseconds for the APs to finish
> + execution of Procedure, either for blocking or non-
> blocking mode.
> + Zero means infinity. If the timeout expires before all
> APs return
> + from Procedure, then Procedure on the failed APs is
> terminated. If
> + the timeout expires in blocking mode, the call returns
> EFI_TIMEOUT.
> + If the timeout expires in non-blocking mode, the
> timeout determined
> + can be through CheckOnProcedure or
> WaitForProcedure.
> + Note that timeout support is optional. Whether an
> implementation
> + supports this feature can be determined via the
> Attributes data
> + member.
> + @param[in,out] CpuStatus This optional pointer may be used to
> get the status code returned
> + by Procedure when it completes execution on the
> target AP, or with
> + EFI_TIMEOUT if the Procedure fails to complete
> within the optional
> + timeout. The implementation will update this variable
> with
> + EFI_NOT_READY prior to starting Procedure on the
> target AP.
>
> @retval EFI_INVALID_PARAMETER CpuNumber not valid
> @retval EFI_INVALID_PARAMETER CpuNumber specifying BSP
> @@ -923,10 +1199,12 @@ Gen4GPageTable (
> **/
> EFI_STATUS
> InternalSmmStartupThisAp (
> - IN EFI_AP_PROCEDURE Procedure,
> - IN UINTN CpuIndex,
> - IN OUT VOID *ProcArguments OPTIONAL,
> - IN BOOLEAN BlockingMode
> + IN EFI_AP_PROCEDURE2 Procedure,
> + IN UINTN CpuIndex,
> + IN OUT VOID *ProcArguments OPTIONAL,
> + IN MM_COMPLETION *Token,
> + IN UINTN TimeoutInMicroseconds,
> + IN OUT EFI_STATUS *CpuStatus
> )
> {
> if (CpuIndex >= gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus)
> {
> @@ -952,24 +1230,190 @@ InternalSmmStartupThisAp (
> }
> return EFI_INVALID_PARAMETER;
> }
> + if ((TimeoutInMicroseconds != 0) && ((mSmmMp.Attributes &
> EFI_MM_MP_TIMEOUT_SUPPORTED) == 0)) {
> + return EFI_INVALID_PARAMETER;
> + }
> + if (Procedure == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
>
> - if (BlockingMode) {
> + if (Token == NULL) {
> AcquireSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy);
> } else {
> if (!AcquireSpinLockOrFail (mSmmMpSyncData-
> >CpuData[CpuIndex].Busy)) {
> - DEBUG((DEBUG_ERROR, "mSmmMpSyncData->CpuData[%d].Busy\n",
> CpuIndex));
> - return EFI_INVALID_PARAMETER;
> + DEBUG((DEBUG_ERROR, "Can't acquire mSmmMpSyncData-
> >CpuData[%d].Busy\n", CpuIndex));
> + return EFI_NOT_READY;
> }
> +
> + *Token = (MM_COMPLETION) CreateToken ();
> }
>
> mSmmMpSyncData->CpuData[CpuIndex].Procedure = Procedure;
> mSmmMpSyncData->CpuData[CpuIndex].Parameter = ProcArguments;
> + if (Token != NULL) {
> + mSmmMpSyncData->CpuData[CpuIndex].Token = (SPIN_LOCK
> *)(*Token);
> + }
> + mSmmMpSyncData->CpuData[CpuIndex].Status = CpuStatus;
> + if (mSmmMpSyncData->CpuData[CpuIndex].Status != NULL) {
> + *mSmmMpSyncData->CpuData[CpuIndex].Status = EFI_NOT_READY;
> + }
> +
> ReleaseSemaphore (mSmmMpSyncData->CpuData[CpuIndex].Run);
>
> - if (BlockingMode) {
> + if (Token == NULL) {
> AcquireSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy);
> ReleaseSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy);
> }
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Worker function to execute a caller provided function on all enabled APs.
> +
> + @param[in] Procedure A pointer to the function to be run on
> + enabled APs of the system.
> + @param[in] TimeoutInMicroseconds Indicates the time limit in
> microseconds for
> + APs to return from Procedure, either for
> + blocking or non-blocking mode.
> + @param[in,out] ProcedureArguments The parameter passed into
> Procedure for
> + all APs.
> + @param[in,out] Token This is an optional parameter that allows
> the caller to execute the
> + procedure in a blocking or non-blocking fashion. If it is
> NULL the
> + call is blocking, and the call will not return until the AP
> has
> + completed the procedure. If the token is not NULL, the
> call will
> + return immediately. The caller can check whether the
> procedure has
> + completed with CheckOnProcedure or
> WaitForProcedure.
> + @param[in,out] CPUStatus This optional pointer may be used to get
> the status code returned
> + by Procedure when it completes execution on the
> target AP, or with
> + EFI_TIMEOUT if the Procedure fails to complete within
> the optional
> + timeout. The implementation will update this variable
> with
> + EFI_NOT_READY prior to starting Procedure on the
> target AP.
> +
> +
> + @retval EFI_SUCCESS In blocking mode, all APs have finished before
> + the timeout expired.
> + @retval EFI_SUCCESS In non-blocking mode, function has been
> dispatched
> + to all enabled APs.
> + @retval others Failed to Startup all APs.
> +
> +**/
> +EFI_STATUS
> +InternalSmmStartupAllAPs (
> + IN EFI_AP_PROCEDURE2 Procedure,
> + IN UINTN TimeoutInMicroseconds,
> + IN OUT VOID *ProcedureArguments OPTIONAL,
> + IN OUT MM_COMPLETION *Token,
> + IN OUT EFI_STATUS *CPUStatus
> + )
> +{
> + UINTN Index;
> + UINTN CpuCount;
> +
> + if ((TimeoutInMicroseconds != 0) && ((mSmmMp.Attributes &
> EFI_MM_MP_TIMEOUT_SUPPORTED) == 0)) {
> + return EFI_INVALID_PARAMETER;
> + }
> + if (Procedure == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + CpuCount = 0;
> + for (Index = mMaxNumberOfCpus; Index-- > 0;) {
> + if (IsPresentAp (Index)) {
> + CpuCount ++;
> +
> + if (gSmmCpuPrivate->Operation[Index] == SmmCpuRemove) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + if (!AcquireSpinLockOrFail(mSmmMpSyncData->CpuData[Index].Busy)) {
> + return EFI_NOT_READY;
> + }
> + ReleaseSpinLock (mSmmMpSyncData->CpuData[Index].Busy);
> + }
> + }
> + if (CpuCount == 0) {
> + return EFI_NOT_STARTED;
> + }
> +
> + if (Token != NULL) {
> + *Token = (MM_COMPLETION) CreateToken ();
> + }
> +
> + //
> + // Make sure all BUSY should be acquired.
> + //
> + // Because former code already check mSmmMpSyncData-
> >CpuData[***].Busy for each AP.
> + // Here code always use AcquireSpinLock instead of AcquireSpinLockOrFail
> for not
> + // block mode.
> + //
> + for (Index = mMaxNumberOfCpus; Index-- > 0;) {
> + if (IsPresentAp (Index)) {
> + AcquireSpinLock (mSmmMpSyncData->CpuData[Index].Busy);
> + }
> + }
> +
> + for (Index = mMaxNumberOfCpus; Index-- > 0;) {
> + if (IsPresentAp (Index)) {
> + mSmmMpSyncData->CpuData[Index].Procedure =
> (EFI_AP_PROCEDURE2) Procedure;
> + mSmmMpSyncData->CpuData[Index].Parameter =
> ProcedureArguments;
> + if (Token != NULL) {
> + mSmmMpSyncData->CpuData[Index].Token = (SPIN_LOCK *)(*Token);
> + }
> + if (CPUStatus != NULL) {
> + mSmmMpSyncData->CpuData[Index].Status = &CPUStatus[Index];
> + if (mSmmMpSyncData->CpuData[Index].Status != NULL) {
> + *mSmmMpSyncData->CpuData[Index].Status = EFI_NOT_READY;
> + }
> + }
> + } else {
> + //
> + // PI spec requirement:
> + // For every excluded processor, the array entry must contain a value of
> EFI_NOT_STARTED.
> + //
> + if (CPUStatus != NULL) {
> + CPUStatus[Index] = EFI_NOT_STARTED;
> + }
> + }
> + }
> +
> + ReleaseAllAPs ();
> +
> + if (Token == NULL) {
> + //
> + // Make sure all APs have completed their tasks.
> + //
> + WaitForAllAPsNotBusy (TRUE);
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + ISO C99 6.5.2.2 "Function calls", paragraph 9:
> + If the function is defined with a type that is not compatible with
> + the type (of the expression) pointed to by the expression that
> + denotes the called function, the behavior is undefined.
> +
> + So add below wrapper function to convert between EFI_AP_PROCEDURE
> + and EFI_AP_PROCEDURE2.
> +
> + Wrapper for Procedures.
> +
> + @param[in] Buffer Pointer to PROCEDURE_WRAPPER buffer.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +ProcedureWrapper (
> + IN OUT VOID *Buffer
> + )
> +{
> + PROCEDURE_WRAPPER *Wrapper;
> +
> + Wrapper = Buffer;
> + Wrapper->Procedure (Wrapper->ProcedureArgument);
> +
> return EFI_SUCCESS;
> }
>
> @@ -995,7 +1439,15 @@ SmmBlockingStartupThisAp (
> IN OUT VOID *ProcArguments OPTIONAL
> )
> {
> - return InternalSmmStartupThisAp(Procedure, CpuIndex, ProcArguments,
> TRUE);
> + PROCEDURE_WRAPPER Wrapper;
> +
> + Wrapper.Procedure = Procedure;
> + Wrapper.ProcedureArgument = ProcArguments;
> +
> + //
> + // Use wrapper function to convert EFI_AP_PROCEDURE to
> EFI_AP_PROCEDURE2.
> + //
> + return InternalSmmStartupThisAp (ProcedureWrapper, CpuIndex,
> &Wrapper, NULL, 0, NULL);
> }
>
> /**
> @@ -1020,7 +1472,22 @@ SmmStartupThisAp (
> IN OUT VOID *ProcArguments OPTIONAL
> )
> {
> - return InternalSmmStartupThisAp(Procedure, CpuIndex, ProcArguments,
> FeaturePcdGet (PcdCpuSmmBlockStartupThisAp));
> + MM_COMPLETION Token;
> +
> + gSmmCpuPrivate->ApWrapperFunc[CpuIndex].Procedure = Procedure;
> + gSmmCpuPrivate->ApWrapperFunc[CpuIndex].ProcedureArgument =
> ProcArguments;
> +
> + //
> + // Use wrapper function to convert EFI_AP_PROCEDURE to
> EFI_AP_PROCEDURE2.
> + //
> + return InternalSmmStartupThisAp (
> + ProcedureWrapper,
> + CpuIndex,
> + &gSmmCpuPrivate->ApWrapperFunc[CpuIndex],
> + FeaturePcdGet (PcdCpuSmmBlockStartupThisAp) ? NULL : &Token,
> + 0,
> + NULL
> + );
> }
>
> /**
> @@ -1112,6 +1579,13 @@ SmiRendezvous (
> Cr2 = 0;
> SaveCr2 (&Cr2);
>
> + //
> + // Call the user register Startup function first.
> + //
> + if (mSmmMpSyncData->StartupProcedure != NULL) {
> + mSmmMpSyncData->StartupProcedure (mSmmMpSyncData-
> >StartupProcArgs);
> + }
> +
> //
> // Perform CPU specific entry hooks
> //
> @@ -1256,6 +1730,21 @@ Exit:
> RestoreCr2 (Cr2);
> }
>
> +/**
> + Allocate buffer for SpinLock and Wrapper function buffer.
> +
> +**/
> +VOID
> +InitializeDataForMmMp (
> + VOID
> + )
> +{
> + gSmmCpuPrivate->ApWrapperFunc = AllocatePool (sizeof
> (PROCEDURE_WRAPPER) * gSmmCpuPrivate-
> >SmmCoreEntryContext.NumberOfCpus);
> + ASSERT (gSmmCpuPrivate->ApWrapperFunc != NULL);
> +
> + InitializeListHead (&gSmmCpuPrivate->TokenList);
> +}
> +
> /**
> Allocate buffer for all semaphores and spin locks.
>
> @@ -1469,3 +1958,40 @@ RegisterSmmEntry (
> gSmmCpuPrivate->SmmCoreEntry = SmmEntryPoint;
> return EFI_SUCCESS;
> }
> +
> +/**
> +
> + Register the SMM Foundation entry point.
> +
> + @param[in] Procedure A pointer to the code stream to be run on
> the designated target AP
> + of the system. Type EFI_AP_PROCEDURE is defined
> below in Volume 2
> + with the related definitions of
> + EFI_MP_SERVICES_PROTOCOL.StartupAllAPs.
> + If caller may pass a value of NULL to deregister any
> existing
> + startup procedure.
> + @param[in] ProcedureArguments Allows the caller to pass a list of
> parameters to the code that is
> + run by the AP. It is an optional common mailbox
> between APs and
> + the caller to share information
> +
> + @retval EFI_SUCCESS The Procedure has been set successfully.
> + @retval EFI_INVALID_PARAMETER The Procedure is NULL but
> ProcedureArguments not NULL.
> +
> +**/
> +EFI_STATUS
> +RegisterStartupProcedure (
> + IN EFI_AP_PROCEDURE Procedure,
> + IN VOID *ProcedureArguments OPTIONAL
> + )
> +{
> + if (Procedure == NULL && ProcedureArguments != NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> + if (mSmmMpSyncData == NULL) {
> + return EFI_NOT_READY;
> + }
> +
> + mSmmMpSyncData->StartupProcedure = Procedure;
> + mSmmMpSyncData->StartupProcArgs = ProcedureArguments;
> +
> + return EFI_SUCCESS;
> +}
> diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c
> b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c
> index 2f7d777ee7..69a04dfb23 100644
> --- a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c
> +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c
> @@ -34,6 +34,8 @@ SMM_CPU_PRIVATE_DATA mSmmCpuPrivateData = {
> mSmmCpuPrivateData.SmmReservedSmramRegion, //
> SmmConfiguration.SmramReservedRegions
> RegisterSmmEntry // SmmConfiguration.RegisterSmmEntry
> },
> + NULL, // pointer to Ap Wrapper Func array
> + {NULL, NULL}, // List_Entry for Tokens.
> };
>
> CPU_HOT_PLUG_DATA mCpuHotPlugData = {
> @@ -996,6 +998,22 @@ PiCpuSmmEntry (
> );
> ASSERT_EFI_ERROR (Status);
>
> + //
> + // Initialize global buffer for MM MP.
> + //
> + InitializeDataForMmMp ();
> +
> + //
> + // Install the SMM Mp Protocol into SMM protocol database
> + //
> + Status = gSmst->SmmInstallProtocolInterface (
> + &mSmmCpuHandle,
> + &gEfiMmMpProtocolGuid,
> + EFI_NATIVE_INTERFACE,
> + &mSmmMp
> + );
> + ASSERT_EFI_ERROR (Status);
> +
> //
> // Expose address of CPU Hot Plug Data structure if CPU hot plug is
> supported.
> //
> diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h
> b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h
> index 2bb35a424d..186809f431 100644
> --- a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h
> +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h
> @@ -20,6 +20,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
> #include <Protocol/SmmReadyToLock.h>
> #include <Protocol/SmmCpuService.h>
> #include <Protocol/SmmMemoryAttribute.h>
> +#include <Protocol/MmMp.h>
>
> #include <Guid/AcpiS3Context.h>
> #include <Guid/MemoryAttributesTable.h>
> @@ -197,6 +198,25 @@ typedef UINT32
> SMM_CPU_ARRIVAL_EXCEPTIONS;
> #define ARRIVAL_EXCEPTION_DELAYED 0x2
> #define ARRIVAL_EXCEPTION_SMI_DISABLED 0x4
>
> +//
> +// Wrapper used to convert EFI_AP_PROCEDURE2 and EFI_AP_PROCEDURE.
> +//
> +typedef struct {
> + EFI_AP_PROCEDURE Procedure;
> + VOID *ProcedureArgument;
> +} PROCEDURE_WRAPPER;
> +
> +#define PROCEDURE_TOKEN_SIGNATURE SIGNATURE_32 ('P', 'R', 'T', 'S')
> +
> +typedef struct {
> + UINTN Signature;
> + LIST_ENTRY Link;
> +
> + SPIN_LOCK *ProcedureToken;
> +} PROCEDURE_TOKEN;
> +
> +#define PROCEDURE_TOKEN_FROM_LINK(a) CR (a, PROCEDURE_TOKEN,
> Link, PROCEDURE_TOKEN_SIGNATURE)
> +
> //
> // Private structure for the SMM CPU module that is stored in DXE Runtime
> memory
> // Contains the SMM Configuration Protocols that is produced.
> @@ -219,6 +239,10 @@ typedef struct {
> EFI_SMM_ENTRY_POINT SmmCoreEntry;
>
> EFI_SMM_CONFIGURATION_PROTOCOL SmmConfiguration;
> +
> + PROCEDURE_WRAPPER *ApWrapperFunc;
> + LIST_ENTRY TokenList;
> +
> } SMM_CPU_PRIVATE_DATA;
>
> extern SMM_CPU_PRIVATE_DATA *gSmmCpuPrivate;
> @@ -226,6 +250,7 @@ extern CPU_HOT_PLUG_DATA mCpuHotPlugData;
> extern UINTN mMaxNumberOfCpus;
> extern UINTN mNumberOfCpus;
> extern EFI_SMM_CPU_PROTOCOL mSmmCpu;
> +extern EFI_MM_MP_PROTOCOL mSmmMp;
>
> ///
> /// The mode of the CPU at the time an SMI occurs
> @@ -363,10 +388,12 @@ SmmRelocationSemaphoreComplete (
> ///
> typedef struct {
> SPIN_LOCK *Busy;
> - volatile EFI_AP_PROCEDURE Procedure;
> + volatile EFI_AP_PROCEDURE2 Procedure;
> volatile VOID *Parameter;
> volatile UINT32 *Run;
> volatile BOOLEAN *Present;
> + SPIN_LOCK *Token;
> + EFI_STATUS *Status;
> } SMM_CPU_DATA_BLOCK;
>
> typedef enum {
> @@ -388,6 +415,8 @@ typedef struct {
> volatile SMM_CPU_SYNC_MODE EffectiveSyncMode;
> volatile BOOLEAN SwitchBsp;
> volatile BOOLEAN *CandidateBsp;
> + EFI_AP_PROCEDURE StartupProcedure;
> + VOID *StartupProcArgs;
> } SMM_DISPATCHER_MP_SYNC_DATA;
>
> #define SMM_PSD_OFFSET 0xfb00
> @@ -410,6 +439,7 @@ typedef struct {
> SPIN_LOCK *Busy;
> volatile UINT32 *Run;
> volatile BOOLEAN *Present;
> + SPIN_LOCK *Token;
> } SMM_CPU_SEMAPHORE_CPU;
>
> ///
> @@ -1259,4 +1289,165 @@ RestoreCr2 (
> IN UINTN Cr2
> );
>
> +/**
> + Schedule a procedure to run on the specified CPU.
> +
> + @param[in] Procedure The address of the procedure to run
> + @param[in] CpuIndex Target CPU Index
> + @param[in,out] ProcArguments The parameter to pass to the
> procedure
> + @param[in,out] Token This is an optional parameter that allows
> the caller to execute the
> + procedure in a blocking or non-blocking fashion. If it is
> NULL the
> + call is blocking, and the call will not return until the AP
> has
> + completed the procedure. If the token is not NULL,
> the call will
> + return immediately. The caller can check whether the
> procedure has
> + completed with CheckOnProcedure or
> WaitForProcedure.
> + @param[in] TimeoutInMicroseconds Indicates the time limit in
> microseconds for the APs to finish
> + execution of Procedure, either for blocking or non-
> blocking mode.
> + Zero means infinity. If the timeout expires before all
> APs return
> + from Procedure, then Procedure on the failed APs is
> terminated. If
> + the timeout expires in blocking mode, the call returns
> EFI_TIMEOUT.
> + If the timeout expires in non-blocking mode, the
> timeout determined
> + can be through CheckOnProcedure or
> WaitForProcedure.
> + Note that timeout support is optional. Whether an
> implementation
> + supports this feature can be determined via the
> Attributes data
> + member.
> + @param[in,out] CPUStatus This optional pointer may be used to
> get the status code returned
> + by Procedure when it completes execution on the
> target AP, or with
> + EFI_TIMEOUT if the Procedure fails to complete
> within the optional
> + timeout. The implementation will update this variable
> with
> + EFI_NOT_READY prior to starting Procedure on the
> target AP.
> +
> + @retval EFI_INVALID_PARAMETER CpuNumber not valid
> + @retval EFI_INVALID_PARAMETER CpuNumber specifying BSP
> + @retval EFI_INVALID_PARAMETER The AP specified by CpuNumber did
> not enter SMM
> + @retval EFI_INVALID_PARAMETER The AP specified by CpuNumber is
> busy
> + @retval EFI_SUCCESS The procedure has been successfully
> scheduled
> +
> +**/
> +EFI_STATUS
> +InternalSmmStartupThisAp (
> + IN EFI_AP_PROCEDURE2 Procedure,
> + IN UINTN CpuIndex,
> + IN OUT VOID *ProcArguments OPTIONAL,
> + IN MM_COMPLETION *Token,
> + IN UINTN TimeoutInMicroseconds,
> + IN OUT EFI_STATUS *CpuStatus
> + );
> +
> +/**
> + Checks whether the input token is the current used token.
> +
> + @param[in] Token This parameter describes the token that was passed
> into DispatchProcedure or
> + BroadcastProcedure.
> +
> + @retval TRUE The input token is the current used token.
> + @retval FALSE The input token is not the current used token.
> +**/
> +BOOLEAN
> +IsTokenInUse (
> + IN SPIN_LOCK *Token
> + );
> +
> +/**
> + Checks status of specified AP.
> +
> + This function checks whether the specified AP has finished the task
> assigned
> + by StartupThisAP(), and whether timeout expires.
> +
> + @param[in] Token This parameter describes the token that was
> passed into DispatchProcedure or
> + BroadcastProcedure.
> +
> + @retval EFI_SUCCESS Specified AP has finished task assigned by
> StartupThisAPs().
> + @retval EFI_NOT_READY Specified AP has not finished task and
> timeout has not expired.
> +**/
> +EFI_STATUS
> +IsApReady (
> + IN SPIN_LOCK *Token
> + );
> +
> +/**
> + Check whether it is an present AP.
> +
> + @param CpuIndex The AP index which calls this function.
> +
> + @retval TRUE It's a present AP.
> + @retval TRUE This is not an AP or it is not present.
> +
> +**/
> +BOOLEAN
> +IsPresentAp (
> + IN UINTN CpuIndex
> + );
> +
> +/**
> + Worker function to execute a caller provided function on all enabled APs.
> +
> + @param[in] Procedure A pointer to the function to be run on
> + enabled APs of the system.
> + @param[in] TimeoutInMicroseconds Indicates the time limit in
> microseconds for
> + APs to return from Procedure, either for
> + blocking or non-blocking mode.
> + @param[in,out] ProcedureArgument The parameter passed into
> Procedure for
> + all APs.
> + @param[in,out] Token This is an optional parameter that allows
> the caller to execute the
> + procedure in a blocking or non-blocking fashion. If it is
> NULL the
> + call is blocking, and the call will not return until the AP
> has
> + completed the procedure. If the token is not NULL, the
> call will
> + return immediately. The caller can check whether the
> procedure has
> + completed with CheckOnProcedure or
> WaitForProcedure.
> + @param[in,out] CPUStatus This optional pointer may be used to get
> the status code returned
> + by Procedure when it completes execution on the
> target AP, or with
> + EFI_TIMEOUT if the Procedure fails to complete within
> the optional
> + timeout. The implementation will update this variable
> with
> + EFI_NOT_READY prior to starting Procedure on the
> target AP.
> +
> + @retval EFI_SUCCESS In blocking mode, all APs have finished before
> + the timeout expired.
> + @retval EFI_SUCCESS In non-blocking mode, function has been
> dispatched
> + to all enabled APs.
> + @retval others Failed to Startup all APs.
> +
> +**/
> +EFI_STATUS
> +InternalSmmStartupAllAPs (
> + IN EFI_AP_PROCEDURE2 Procedure,
> + IN UINTN TimeoutInMicroseconds,
> + IN OUT VOID *ProcedureArguments OPTIONAL,
> + IN OUT MM_COMPLETION *Token,
> + IN OUT EFI_STATUS *CPUStatus
> + );
> +
> +/**
> +
> + Register the SMM Foundation entry point.
> +
> + @param[in] Procedure A pointer to the code stream to be run on
> the designated target AP
> + of the system. Type EFI_AP_PROCEDURE is defined
> below in Volume 2
> + with the related definitions of
> + EFI_MP_SERVICES_PROTOCOL.StartupAllAPs.
> + If caller may pass a value of NULL to deregister any
> existing
> + startup procedure.
> + @param[in,out] ProcedureArguments Allows the caller to pass a list of
> parameters to the code that is
> + run by the AP. It is an optional common mailbox
> between APs and
> + the caller to share information
> +
> + @retval EFI_SUCCESS The Procedure has been set successfully.
> + @retval EFI_INVALID_PARAMETER The Procedure is NULL but
> ProcedureArguments not NULL.
> +
> +**/
> +EFI_STATUS
> +RegisterStartupProcedure (
> + IN EFI_AP_PROCEDURE Procedure,
> + IN VOID *ProcedureArguments OPTIONAL
> + );
> +
> +/**
> + Allocate buffer for SpinLock and Wrapper function buffer.
> +
> +**/
> +VOID
> +InitializeDataForMmMp (
> + VOID
> + );
> +
> #endif
> diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf
> b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf
> index 466c568d49..da0308c47f 100644
> --- a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf
> +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf
> @@ -40,6 +40,8 @@
> SmmProfileInternal.h
> SmramSaveState.c
> SmmCpuMemoryManagement.c
> + SmmMp.h
> + SmmMp.c
>
> [Sources.Ia32]
> Ia32/Semaphore.c
> @@ -105,6 +107,7 @@
> gEfiSmmReadyToLockProtocolGuid ## NOTIFY
> gEfiSmmCpuServiceProtocolGuid ## PRODUCES
> gEdkiiSmmMemoryAttributeProtocolGuid ## PRODUCES
> + gEfiMmMpProtocolGuid ## PRODUCES
>
> [Guids]
> gEfiAcpiVariableGuid ## SOMETIMES_CONSUMES ## HOB # it is
> used for S3 boot.
> diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.c
> b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.c
> new file mode 100644
> index 0000000000..9b2b191e03
> --- /dev/null
> +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.c
> @@ -0,0 +1,344 @@
> +/** @file
> +SMM MP protocol implementation
> +
> +Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
> +
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "PiSmmCpuDxeSmm.h"
> +#include "SmmMp.h"
> +
> +///
> +/// SMM MP Protocol instance
> +///
> +EFI_MM_MP_PROTOCOL mSmmMp = {
> + EFI_MM_MP_PROTOCOL_REVISION,
> + 0,
> + SmmMpGetNumberOfProcessors,
> + SmmMpDispatchProcedure,
> + SmmMpBroadcastProcedure,
> + SmmMpSetStartupProcedure,
> + SmmMpCheckForProcedure,
> + SmmMpWaitForProcedure
> +};
> +
> +/**
> + Service to retrieves the number of logical processor in the platform.
> +
> + @param[in] This The EFI_MM_MP_PROTOCOL instance.
> + @param[out] NumberOfProcessors Pointer to the total number of logical
> processors in the system,
> + including the BSP and all APs.
> +
> + @retval EFI_SUCCESS The number of processors was retrieved
> successfully
> + @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL
> +**/
> +EFI_STATUS
> +EFIAPI
> +SmmMpGetNumberOfProcessors (
> + IN CONST EFI_MM_MP_PROTOCOL *This,
> + OUT UINTN *NumberOfProcessors
> + )
> +{
> + if (NumberOfProcessors == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + *NumberOfProcessors = gSmmCpuPrivate-
> >SmmCoreEntryContext.NumberOfCpus;
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + This service allows the caller to invoke a procedure one of the application
> processors (AP). This
> + function uses an optional token parameter to support blocking and non-
> blocking modes. If the token
> + is passed into the call, the function will operate in a non-blocking fashion
> and the caller can
> + check for completion with CheckOnProcedure or WaitForProcedure.
> +
> + @param[in] This The EFI_MM_MP_PROTOCOL instance.
> + @param[in] Procedure A pointer to the procedure to be run on
> the designated target
> + AP of the system. Type EFI_AP_PROCEDURE2 is defined
> below in
> + related definitions.
> + @param[in] CpuNumber The zero-based index of the processor
> number of the target
> + AP, on which the code stream is supposed to run. If the
> number
> + points to the calling processor then it will not run the
> + supplied code.
> + @param[in] TimeoutInMicroseconds Indicates the time limit in
> microseconds for this AP to
> + finish execution of Procedure, either for blocking or
> + non-blocking mode. Zero means infinity. If the timeout
> + expires before this AP returns from Procedure, then
> Procedure
> + on the AP is terminated. If the timeout expires in
> blocking
> + mode, the call returns EFI_TIMEOUT. If the timeout
> expires
> + in non-blocking mode, the timeout determined can be
> through
> + CheckOnProcedure or WaitForProcedure.
> + Note that timeout support is optional. Whether an
> + implementation supports this feature, can be
> determined via
> + the Attributes data member.
> + @param[in,out] ProcedureArguments Allows the caller to pass a list of
> parameters to the code
> + that is run by the AP. It is an optional common mailbox
> + between APs and the caller to share information.
> + @param[in,out] Token This is parameter is broken into two
> components:
> + 1.Token->Completion is an optional parameter that
> allows the
> + caller to execute the procedure in a blocking or non-
> blocking
> + fashion. If it is NULL the call is blocking, and the call will
> + not return until the AP has completed the procedure. If
> the
> + token is not NULL, the call will return immediately. The
> caller
> + can check whether the procedure has completed with
> + CheckOnProcedure or WaitForProcedure.
> + 2.Token->Status The implementation updates the
> address pointed
> + at by this variable with the status code returned by
> Procedure
> + when it completes execution on the target AP, or with
> EFI_TIMEOUT
> + if the Procedure fails to complete within the optional
> timeout.
> + The implementation will update this variable with
> EFI_NOT_READY
> + prior to starting Procedure on the target AP
> + @param[in,out] CPUStatus This optional pointer may be used to get
> the status code returned
> + by Procedure when it completes execution on the
> target AP, or with
> + EFI_TIMEOUT if the Procedure fails to complete within
> the optional
> + timeout. The implementation will update this variable
> with
> + EFI_NOT_READY prior to starting Procedure on the
> target AP.
> +
> + @retval EFI_SUCCESS In the blocking case, this indicates that
> Procedure has completed
> + execution on the target AP.
> + In the non-blocking case this indicates that the
> procedure has
> + been successfully scheduled for execution on the target
> AP.
> + @retval EFI_INVALID_PARAMETER The input arguments are out of
> range. Either the target AP is the
> + caller of the function, or the Procedure or Token is NULL
> + @retval EFI_NOT_READY If the target AP is busy executing another
> procedure
> + @retval EFI_ALREADY_STARTED Token is already in use for another
> procedure
> + @retval EFI_TIMEOUT In blocking mode, the timeout expired
> before the specified AP
> + has finished
> + @retval EFI_OUT_OF_RESOURCES Could not allocate a required
> resource.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SmmMpDispatchProcedure (
> + IN CONST EFI_MM_MP_PROTOCOL *This,
> + IN EFI_AP_PROCEDURE2 Procedure,
> + IN UINTN CpuNumber,
> + IN UINTN TimeoutInMicroseconds,
> + IN OUT VOID *ProcedureArguments OPTIONAL,
> + IN OUT MM_COMPLETION *Token,
> + IN OUT EFI_STATUS *CPUStatus
> + )
> +{
> + return InternalSmmStartupThisAp (
> + Procedure,
> + CpuNumber,
> + ProcedureArguments,
> + Token,
> + TimeoutInMicroseconds,
> + CPUStatus
> + );
> +}
> +
> +/**
> + This service allows the caller to invoke a procedure on all running
> application processors (AP)
> + except the caller. This function uses an optional token parameter to
> support blocking and
> + nonblocking modes. If the token is passed into the call, the function will
> operate in a non-blocking
> + fashion and the caller can check for completion with CheckOnProcedure or
> WaitForProcedure.
> +
> + It is not necessary for the implementation to run the procedure on every
> processor on the platform.
> + Processors that are powered down in such a way that they cannot respond
> to interrupts, may be
> + excluded from the broadcast.
> +
> +
> + @param[in] This The EFI_MM_MP_PROTOCOL instance.
> + @param[in] Procedure A pointer to the code stream to be run on
> the APs that have
> + entered MM. Type EFI_AP_PROCEDURE is defined
> below in related
> + definitions.
> + @param[in] TimeoutInMicroseconds Indicates the time limit in
> microseconds for the APs to finish
> + execution of Procedure, either for blocking or non-
> blocking mode.
> + Zero means infinity. If the timeout expires before all
> APs return
> + from Procedure, then Procedure on the failed APs is
> terminated. If
> + the timeout expires in blocking mode, the call returns
> EFI_TIMEOUT.
> + If the timeout expires in non-blocking mode, the
> timeout determined
> + can be through CheckOnProcedure or
> WaitForProcedure.
> + Note that timeout support is optional. Whether an
> implementation
> + supports this feature can be determined via the
> Attributes data
> + member.
> + @param[in,out] ProcedureArguments Allows the caller to pass a list of
> parameters to the code
> + that is run by the AP. It is an optional common mailbox
> + between APs and the caller to share information.
> + @param[in,out] Token This is parameter is broken into two
> components:
> + 1.Token->Completion is an optional parameter that
> allows the
> + caller to execute the procedure in a blocking or non-
> blocking
> + fashion. If it is NULL the call is blocking, and the call will
> + not return until the AP has completed the procedure. If
> the
> + token is not NULL, the call will return immediately. The
> caller
> + can check whether the procedure has completed with
> + CheckOnProcedure or WaitForProcedure.
> + 2.Token->Status The implementation updates the
> address pointed
> + at by this variable with the status code returned by
> Procedure
> + when it completes execution on the target AP, or with
> EFI_TIMEOUT
> + if the Procedure fails to complete within the optional
> timeout.
> + The implementation will update this variable with
> EFI_NOT_READY
> + prior to starting Procedure on the target AP
> + @param[in,out] CPUStatus This optional pointer may be used to get
> the individual status
> + returned by every AP that participated in the broadcast.
> This
> + parameter if used provides the base address of an array
> to hold
> + the EFI_STATUS value of each AP in the system. The size
> of the
> + array can be ascertained by the
> GetNumberOfProcessors function.
> + As mentioned above, the broadcast may not include
> every processor
> + in the system. Some implementations may exclude
> processors that
> + have been powered down in such a way that they are
> not responsive
> + to interrupts. Additionally the broadcast excludes the
> processor
> + which is making the BroadcastProcedure call. For every
> excluded
> + processor, the array entry must contain a value of
> EFI_NOT_STARTED
> +
> + @retval EFI_SUCCESS In the blocking case, this indicates that
> Procedure has completed
> + execution on the APs.
> + In the non-blocking case this indicates that the
> procedure has
> + been successfully scheduled for execution on the APs.
> + @retval EFI_INVALID_PARAMETER The Procedure or Token is NULL
> + @retval EFI_NOT_READY If the target AP is busy executing another
> procedure
> + @retval EFI_ALREADY_STARTED Token is already in use for another
> procedure
> + @retval EFI_TIMEOUT In blocking mode, the timeout expired
> before the specified AP
> + has finished.
> + @retval EFI_OUT_OF_RESOURCES Could not allocate a required
> resource.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SmmMpBroadcastProcedure (
> + IN CONST EFI_MM_MP_PROTOCOL *This,
> + IN EFI_AP_PROCEDURE2 Procedure,
> + IN UINTN TimeoutInMicroseconds,
> + IN OUT VOID *ProcedureArguments OPTIONAL,
> + IN OUT MM_COMPLETION *Token,
> + IN OUT EFI_STATUS *CPUStatus
> + )
> +{
> + return InternalSmmStartupAllAPs(
> + Procedure,
> + TimeoutInMicroseconds,
> + ProcedureArguments,
> + Token,
> + CPUStatus
> + );
> +}
> +
> +/**
> + This service allows the caller to set a startup procedure that will be
> executed when an AP powers
> + up from a state where core configuration and context is lost. The
> procedure is execution has the
> + following properties:
> + 1. The procedure executes before the processor is handed over to the
> operating system.
> + 2. All processors execute the same startup procedure.
> + 3. The procedure may run in parallel with other procedures invoked
> through the functions in this
> + protocol, or with processors that are executing an MM handler or running
> in the operating system.
> +
> +
> + @param[in] This The EFI_MM_MP_PROTOCOL instance.
> + @param[in] Procedure A pointer to the code stream to be run on
> the designated target AP
> + of the system. Type EFI_AP_PROCEDURE is defined
> below in Volume 2
> + with the related definitions of
> + EFI_MP_SERVICES_PROTOCOL.StartupAllAPs.
> + If caller may pass a value of NULL to deregister any
> existing
> + startup procedure.
> + @param[in,out] ProcedureArguments Allows the caller to pass a list of
> parameters to the code that is
> + run by the AP. It is an optional common mailbox
> between APs and
> + the caller to share information
> +
> + @retval EFI_SUCCESS The Procedure has been set successfully.
> + @retval EFI_INVALID_PARAMETER The Procedure is NULL but
> ProcedureArguments not NULL.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SmmMpSetStartupProcedure (
> + IN CONST EFI_MM_MP_PROTOCOL *This,
> + IN EFI_AP_PROCEDURE Procedure,
> + IN OUT VOID *ProcedureArguments OPTIONAL
> + )
> +{
> + return RegisterStartupProcedure (Procedure, ProcedureArguments);
> +}
> +
> +/**
> + When non-blocking execution of a procedure on an AP is invoked with
> DispatchProcedure,
> + via the use of a token, this function can be used to check for completion of
> the procedure on the AP.
> + The function takes the token that was passed into the DispatchProcedure
> call. If the procedure
> + is complete, and therefore it is now possible to run another procedure on
> the same AP, this function
> + returns EFI_SUCESS. In this case the status returned by the procedure that
> executed on the AP is
> + returned in the token's Status field. If the procedure has not yet
> completed, then this function
> + returns EFI_NOT_READY.
> +
> + When a non-blocking execution of a procedure is invoked with
> BroadcastProcedure, via the
> + use of a token, this function can be used to check for completion of the
> procedure on all the
> + broadcast APs. The function takes the token that was passed into the
> BroadcastProcedure
> + call. If the procedure is complete on all broadcast APs this function returns
> EFI_SUCESS. In this
> + case the Status field in the token passed into the function reflects the
> overall result of the
> + invocation, which may be EFI_SUCCESS, if all executions succeeded, or the
> first observed failure.
> + If the procedure has not yet completed on the broadcast APs, the function
> returns
> + EFI_NOT_READY.
> +
> + @param[in] This The EFI_MM_MP_PROTOCOL instance.
> + @param[in] Token This parameter describes the token that was
> passed into
> + DispatchProcedure or BroadcastProcedure.
> +
> + @retval EFI_SUCCESS Procedure has completed.
> + @retval EFI_NOT_READY The Procedure has not completed.
> + @retval EFI_INVALID_PARAMETER Token or Token->Completion is
> NULL
> + @retval EFI_NOT_FOUND Token is not currently in use for a non-
> blocking call
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SmmMpCheckForProcedure (
> + IN CONST EFI_MM_MP_PROTOCOL *This,
> + IN MM_COMPLETION Token
> + )
> +{
> + if (Token == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + if (!IsTokenInUse ((SPIN_LOCK *)Token)) {
> + return EFI_NOT_FOUND;
> + }
> +
> + return IsApReady ((SPIN_LOCK *)Token);
> +}
> +
> +/**
> + When a non-blocking execution of a procedure on an AP is invoked via
> DispatchProcedure,
> + this function will block the caller until the remote procedure has completed
> on the designated AP.
> + The non-blocking procedure invocation is identified by the Token
> parameter, which must match the
> + token that used when DispatchProcedure was called. Upon completion the
> status returned by
> + the procedure that executed on the AP is used to update the token's
> Status field.
> +
> + When a non-blocking execution of a procedure on an AP is invoked via
> BroadcastProcedure
> + this function will block the caller until the remote procedure has completed
> on all of the APs that
> + entered MM. The non-blocking procedure invocation is identified by the
> Token parameter, which
> + must match the token that used when BroadcastProcedure was called.
> Upon completion the
> + overall status returned by the procedures that executed on the broadcast
> AP is used to update the
> + token's Status field. The overall status may be EFI_SUCCESS, if all
> executions succeeded, or the
> + first observed failure.
> +
> +
> + @param[in] This The EFI_MM_MP_PROTOCOL instance.
> + @param[in] Token This parameter describes the token that was
> passed into
> + DispatchProcedure or BroadcastProcedure.
> +
> + @retval EFI_SUCCESS Procedure has completed.
> + @retval EFI_INVALID_PARAMETER Token or Token->Completion is
> NULL
> + @retval EFI_NOT_FOUND Token is not currently in use for a non-
> blocking call
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SmmMpWaitForProcedure (
> + IN CONST EFI_MM_MP_PROTOCOL *This,
> + IN MM_COMPLETION Token
> + )
> +{
> + EFI_STATUS Status;
> +
> + do {
> + Status = SmmMpCheckForProcedure (This, Token);
> + } while (Status == EFI_NOT_READY);
> +
> + return Status;
> +}
> +
> diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.h
> b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.h
> new file mode 100644
> index 0000000000..e0d823a4b1
> --- /dev/null
> +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.h
> @@ -0,0 +1,286 @@
> +/** @file
> +Include file for SMM MP protocol implementation.
> +
> +Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
> +
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef _SMM_MP_PROTOCOL_H_
> +#define _SMM_MP_PROTOCOL_H_
> +
> +//
> +// SMM MP Protocol function prototypes.
> +//
> +
> +/**
> + Service to retrieves the number of logical processor in the platform.
> +
> + @param[in] This The EFI_MM_MP_PROTOCOL instance.
> + @param[out] NumberOfProcessors Pointer to the total number of logical
> processors in the system,
> + including the BSP and all APs.
> +
> + @retval EFI_SUCCESS The number of processors was retrieved
> successfully
> + @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL
> +**/
> +
> +EFI_STATUS
> +EFIAPI
> +SmmMpGetNumberOfProcessors (
> + IN CONST EFI_MM_MP_PROTOCOL *This,
> + OUT UINTN *NumberOfProcessors
> + );
> +
> +
> +/**
> + This service allows the caller to invoke a procedure one of the application
> processors (AP). This
> + function uses an optional token parameter to support blocking and non-
> blocking modes. If the token
> + is passed into the call, the function will operate in a non-blocking fashion
> and the caller can
> + check for completion with CheckOnProcedure or WaitForProcedure.
> +
> + @param[in] This The EFI_MM_MP_PROTOCOL instance.
> + @param[in] Procedure A pointer to the procedure to be run on
> the designated target
> + AP of the system. Type EFI_AP_PROCEDURE2 is defined
> below in
> + related definitions.
> + @param[in] CpuNumber The zero-based index of the processor
> number of the target
> + AP, on which the code stream is supposed to run. If the
> number
> + points to the calling processor then it will not run the
> + supplied code.
> + @param[in] TimeoutInMicroseconds Indicates the time limit in
> microseconds for this AP to
> + finish execution of Procedure, either for blocking or
> + non-blocking mode. Zero means infinity. If the timeout
> + expires before this AP returns from Procedure, then
> Procedure
> + on the AP is terminated. If the timeout expires in
> blocking
> + mode, the call returns EFI_TIMEOUT. If the timeout
> expires
> + in non-blocking mode, the timeout determined can be
> through
> + CheckOnProcedure or WaitForProcedure.
> + Note that timeout support is optional. Whether an
> + implementation supports this feature, can be
> determined via
> + the Attributes data member.
> + @param[in,out] ProcedureArguments Allows the caller to pass a list of
> parameters to the code
> + that is run by the AP. It is an optional common mailbox
> + between APs and the caller to share information.
> + @param[in,out] Token This is parameter is broken into two
> components:
> + 1.Token->Completion is an optional parameter that
> allows the
> + caller to execute the procedure in a blocking or non-
> blocking
> + fashion. If it is NULL the call is blocking, and the call will
> + not return until the AP has completed the procedure. If
> the
> + token is not NULL, the call will return immediately. The
> caller
> + can check whether the procedure has completed with
> + CheckOnProcedure or WaitForProcedure.
> + 2.Token->Status The implementation updates the
> address pointed
> + at by this variable with the status code returned by
> Procedure
> + when it completes execution on the target AP, or with
> EFI_TIMEOUT
> + if the Procedure fails to complete within the optional
> timeout.
> + The implementation will update this variable with
> EFI_NOT_READY
> + prior to starting Procedure on the target AP
> + @param[in,out] CPUStatus This optional pointer may be used to get
> the status code returned
> + by Procedure when it completes execution on the
> target AP, or with
> + EFI_TIMEOUT if the Procedure fails to complete within
> the optional
> + timeout. The implementation will update this variable
> with
> + EFI_NOT_READY prior to starting Procedure on the
> target AP.
> +
> + @retval EFI_SUCCESS In the blocking case, this indicates that
> Procedure has completed
> + execution on the target AP.
> + In the non-blocking case this indicates that the
> procedure has
> + been successfully scheduled for execution on the target
> AP.
> + @retval EFI_INVALID_PARAMETER The input arguments are out of
> range. Either the target AP is the
> + caller of the function, or the Procedure or Token is NULL
> + @retval EFI_NOT_READY If the target AP is busy executing another
> procedure
> + @retval EFI_ALREADY_STARTED Token is already in use for another
> procedure
> + @retval EFI_TIMEOUT In blocking mode, the timeout expired
> before the specified AP
> + has finished
> + @retval EFI_OUT_OF_RESOURCES Could not allocate a required
> resource.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SmmMpDispatchProcedure (
> + IN CONST EFI_MM_MP_PROTOCOL *This,
> + IN EFI_AP_PROCEDURE2 Procedure,
> + IN UINTN CpuNumber,
> + IN UINTN TimeoutInMicroseconds,
> + IN OUT VOID *ProcedureArguments OPTIONAL,
> + IN OUT MM_COMPLETION *Token,
> + IN OUT EFI_STATUS *CPUStatus
> + );
> +
> +/**
> + This service allows the caller to invoke a procedure on all running
> application processors (AP)
> + except the caller. This function uses an optional token parameter to
> support blocking and
> + nonblocking modes. If the token is passed into the call, the function will
> operate in a non-blocking
> + fashion and the caller can check for completion with CheckOnProcedure or
> WaitForProcedure.
> +
> + It is not necessary for the implementation to run the procedure on every
> processor on the platform.
> + Processors that are powered down in such a way that they cannot respond
> to interrupts, may be
> + excluded from the broadcast.
> +
> +
> + @param[in] This The EFI_MM_MP_PROTOCOL instance.
> + @param[in] Procedure A pointer to the code stream to be run on
> the APs that have
> + entered MM. Type EFI_AP_PROCEDURE is defined
> below in related
> + definitions.
> + @param[in] TimeoutInMicroseconds Indicates the time limit in
> microseconds for the APs to finish
> + execution of Procedure, either for blocking or non-
> blocking mode.
> + Zero means infinity. If the timeout expires before all
> APs return
> + from Procedure, then Procedure on the failed APs is
> terminated. If
> + the timeout expires in blocking mode, the call returns
> EFI_TIMEOUT.
> + If the timeout expires in non-blocking mode, the
> timeout determined
> + can be through CheckOnProcedure or
> WaitForProcedure.
> + Note that timeout support is optional. Whether an
> implementation
> + supports this feature can be determined via the
> Attributes data
> + member.
> + @param[in,out] ProcedureArguments Allows the caller to pass a list of
> parameters to the code
> + that is run by the AP. It is an optional common mailbox
> + between APs and the caller to share information.
> + @param[in,out] Token This is parameter is broken into two
> components:
> + 1.Token->Completion is an optional parameter that
> allows the
> + caller to execute the procedure in a blocking or non-
> blocking
> + fashion. If it is NULL the call is blocking, and the call will
> + not return until the AP has completed the procedure. If
> the
> + token is not NULL, the call will return immediately. The
> caller
> + can check whether the procedure has completed with
> + CheckOnProcedure or WaitForProcedure.
> + 2.Token->Status The implementation updates the
> address pointed
> + at by this variable with the status code returned by
> Procedure
> + when it completes execution on the target AP, or with
> EFI_TIMEOUT
> + if the Procedure fails to complete within the optional
> timeout.
> + The implementation will update this variable with
> EFI_NOT_READY
> + prior to starting Procedure on the target AP
> + @param[in,out] CPUStatus This optional pointer may be used to get
> the individual status
> + returned by every AP that participated in the broadcast.
> This
> + parameter if used provides the base address of an array
> to hold
> + the EFI_STATUS value of each AP in the system. The size
> of the
> + array can be ascertained by the
> GetNumberOfProcessors function.
> + As mentioned above, the broadcast may not include
> every processor
> + in the system. Some implementations may exclude
> processors that
> + have been powered down in such a way that they are
> not responsive
> + to interrupts. Additionally the broadcast excludes the
> processor
> + which is making the BroadcastProcedure call. For every
> excluded
> + processor, the array entry must contain a value of
> EFI_NOT_STARTED
> +
> + @retval EFI_SUCCESS In the blocking case, this indicates that
> Procedure has completed
> + execution on the APs.
> + In the non-blocking case this indicates that the
> procedure has
> + been successfully scheduled for execution on the APs.
> + @retval EFI_INVALID_PARAMETER The Procedure or Token is NULL
> + @retval EFI_NOT_READY If the target AP is busy executing another
> procedure
> + @retval EFI_ALREADY_STARTED Token is already in use for another
> procedure
> + @retval EFI_TIMEOUT In blocking mode, the timeout expired
> before the specified AP
> + has finished
> + @retval EFI_OUT_OF_RESOURCES Could not allocate a required
> resource.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SmmMpBroadcastProcedure (
> + IN CONST EFI_MM_MP_PROTOCOL *This,
> + IN EFI_AP_PROCEDURE2 Procedure,
> + IN UINTN TimeoutInMicroseconds,
> + IN OUT VOID *ProcedureArguments OPTIONAL,
> + IN OUT MM_COMPLETION *Token,
> + IN OUT EFI_STATUS *CPUStatus
> + );
> +
> +
> +/**
> + This service allows the caller to set a startup procedure that will be
> executed when an AP powers
> + up from a state where core configuration and context is lost. The
> procedure is execution has the
> + following properties:
> + 1. The procedure executes before the processor is handed over to the
> operating system.
> + 2. All processors execute the same startup procedure.
> + 3. The procedure may run in parallel with other procedures invoked
> through the functions in this
> + protocol, or with processors that are executing an MM handler or running
> in the operating system.
> +
> +
> + @param[in] This The EFI_MM_MP_PROTOCOL instance.
> + @param[in] Procedure A pointer to the code stream to be run on
> the designated target AP
> + of the system. Type EFI_AP_PROCEDURE is defined
> below in Volume 2
> + with the related definitions of
> + EFI_MP_SERVICES_PROTOCOL.StartupAllAPs.
> + If caller may pass a value of NULL to deregister any
> existing
> + startup procedure.
> + @param[in,out] ProcedureArguments Allows the caller to pass a list of
> parameters to the code that is
> + run by the AP. It is an optional common mailbox
> between APs and
> + the caller to share information
> +
> + @retval EFI_SUCCESS The Procedure has been set successfully.
> + @retval EFI_INVALID_PARAMETER The Procedure is NULL but
> ProcedureArguments not NULL.
> +**/
> +EFI_STATUS
> +EFIAPI
> +SmmMpSetStartupProcedure (
> + IN CONST EFI_MM_MP_PROTOCOL *This,
> + IN EFI_AP_PROCEDURE Procedure,
> + IN OUT VOID *ProcedureArguments OPTIONAL
> + );
> +
> +/**
> + When non-blocking execution of a procedure on an AP is invoked with
> DispatchProcedure,
> + via the use of a token, this function can be used to check for completion of
> the procedure on the AP.
> + The function takes the token that was passed into the DispatchProcedure
> call. If the procedure
> + is complete, and therefore it is now possible to run another procedure on
> the same AP, this function
> + returns EFI_SUCESS. In this case the status returned by the procedure that
> executed on the AP is
> + returned in the token's Status field. If the procedure has not yet
> completed, then this function
> + returns EFI_NOT_READY.
> +
> + When a non-blocking execution of a procedure is invoked with
> BroadcastProcedure, via the
> + use of a token, this function can be used to check for completion of the
> procedure on all the
> + broadcast APs. The function takes the token that was passed into the
> BroadcastProcedure
> + call. If the procedure is complete on all broadcast APs this function returns
> EFI_SUCESS. In this
> + case the Status field in the token passed into the function reflects the
> overall result of the
> + invocation, which may be EFI_SUCCESS, if all executions succeeded, or the
> first observed failure.
> + If the procedure has not yet completed on the broadcast APs, the function
> returns
> + EFI_NOT_READY.
> +
> + @param[in] This The EFI_MM_MP_PROTOCOL instance.
> + @param[in] Token This parameter describes the token that was
> passed into
> + DispatchProcedure or BroadcastProcedure.
> +
> + @retval EFI_SUCCESS Procedure has completed.
> + @retval EFI_NOT_READY The Procedure has not completed.
> + @retval EFI_INVALID_PARAMETER Token or Token->Completion is
> NULL
> + @retval EFI_NOT_FOUND Token is not currently in use for a non-
> blocking call
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SmmMpCheckForProcedure (
> + IN CONST EFI_MM_MP_PROTOCOL *This,
> + IN MM_COMPLETION Token
> + );
> +
> +/**
> + When a non-blocking execution of a procedure on an AP is invoked via
> DispatchProcedure,
> + this function will block the caller until the remote procedure has completed
> on the designated AP.
> + The non-blocking procedure invocation is identified by the Token
> parameter, which must match the
> + token that used when DispatchProcedure was called. Upon completion the
> status returned by
> + the procedure that executed on the AP is used to update the token's
> Status field.
> +
> + When a non-blocking execution of a procedure on an AP is invoked via
> BroadcastProcedure
> + this function will block the caller until the remote procedure has completed
> on all of the APs that
> + entered MM. The non-blocking procedure invocation is identified by the
> Token parameter, which
> + must match the token that used when BroadcastProcedure was called.
> Upon completion the
> + overall status returned by the procedures that executed on the broadcast
> AP is used to update the
> + token's Status field. The overall status may be EFI_SUCCESS, if all
> executions succeeded, or the
> + first observed failure.
> +
> +
> + @param[in] This The EFI_MM_MP_PROTOCOL instance.
> + @param[in] Token This parameter describes the token that was
> passed into
> + DispatchProcedure or BroadcastProcedure.
> +
> + @retval EFI_SUCCESS Procedure has completed.
> + @retval EFI_INVALID_PARAMETER Token or Token->Completion is
> NULL
> + @retval EFI_NOT_FOUND Token is not currently in use for a non-
> blocking call
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +SmmMpWaitForProcedure (
> + IN CONST EFI_MM_MP_PROTOCOL *This,
> + IN MM_COMPLETION Token
> + );
> +
> +#endif
> --
> 2.21.0.windows.1
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#43467): https://edk2.groups.io/g/devel/message/43467
Mute This Topic: https://groups.io/mt/32414082/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-
Hello Eric,
On 07/10/19 09:56, Dong, Eric wrote:
> V5 changes:
> 1. some small enhancement.
>
> v4 changes:
> 1. Use link list to save the token info.
>
> v3 changes:
> 1. Fix Token clean up too early caused CheckProcedure return error.
>
> v2 changes:
> 1. Remove some duplicated global variables.
> 2. Enhance token design to support multiple task trig for different APs at the same time.
>
> V1 changes:
> REF: https://bugzilla.tianocore.org/show_bug.cgi?id=1937
>
> Add MM Mp Protocol in PiSmmCpuDxeSmm driver.
>
> Cc: Ray Ni <ray.ni@intel.com>
> Cc: Laszlo Ersek <lersek@redhat.com>
> Signed-off-by: Eric Dong <eric.dong@intel.com>
> ---
> UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c | 570 ++++++++++++++++++-
> UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c | 18 +
> UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h | 193 ++++++-
> UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf | 3 +
> UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.c | 344 +++++++++++
> UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.h | 286 ++++++++++
> 6 files changed, 1391 insertions(+), 23 deletions(-)
> create mode 100644 UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.c
> create mode 100644 UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.h
>
> diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c b/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c
> index 64fb4d6344..f09e2738c3 100644
> --- a/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c
> +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c
> @@ -140,7 +140,7 @@ ReleaseAllAPs (
>
> BspIndex = mSmmMpSyncData->BspIndex;
> for (Index = mMaxNumberOfCpus; Index-- > 0;) {
> - if (Index != BspIndex && *(mSmmMpSyncData->CpuData[Index].Present)) {
> + if (IsPresentAp (Index)) {
> ReleaseSemaphore (mSmmMpSyncData->CpuData[Index].Run);
> }
> }
version 5 again fails to build for me, with the following error message:
> UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c: In function 'ReleaseAllAPs':
> UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c:139:37: error: variable 'BspIndex' set but not used [-Werror=unused-but-set-variable]
With the following incremental patch:
> diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c b/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c
> index f09e2738c30d..ef16997547b8 100644
> --- a/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c
> +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c
> @@ -136,9 +136,7 @@ ReleaseAllAPs (
> )
> {
> UINTN Index;
> - UINTN BspIndex;
>
> - BspIndex = mSmmMpSyncData->BspIndex;
> for (Index = mMaxNumberOfCpus; Index-- > 0;) {
> if (IsPresentAp (Index)) {
> ReleaseSemaphore (mSmmMpSyncData->CpuData[Index].Run);
the build completes fine (using GCC48).
If you change nothing on the series other than squashing the above fix,
you can add my:
Regression-tested-by: Laszlo Ersek <lersek@redhat.com>
to both patches in the series.
-*-
Important: please do not push the series until the 5-level paging
commits are reverted, and reapplied (with Mike's R-b on the MdePkg
patch).
Thanks!
Laszlo
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#43615): https://edk2.groups.io/g/devel/message/43615
Mute This Topic: https://groups.io/mt/32414082/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-
Hi Laszlo,
Thanks for your patch and regression test. I will include your change when I push the patches.
Thanks,
Eric
> -----Original Message-----
> From: Laszlo Ersek [mailto:lersek@redhat.com]
> Sent: Friday, July 12, 2019 1:54 AM
> To: devel@edk2.groups.io; Dong, Eric <eric.dong@intel.com>
> Cc: Ni, Ray <ray.ni@intel.com>
> Subject: Re: [edk2-devel] [Patch v5 2/2] UefiCpuPkg/PiSmmCpuDxeSmm:
> Enable MM MP Protocol
>
> Hello Eric,
>
> On 07/10/19 09:56, Dong, Eric wrote:
> > V5 changes:
> > 1. some small enhancement.
> >
> > v4 changes:
> > 1. Use link list to save the token info.
> >
> > v3 changes:
> > 1. Fix Token clean up too early caused CheckProcedure return error.
> >
> > v2 changes:
> > 1. Remove some duplicated global variables.
> > 2. Enhance token design to support multiple task trig for different APs at
> the same time.
> >
> > V1 changes:
> > REF: https://bugzilla.tianocore.org/show_bug.cgi?id=1937
> >
> > Add MM Mp Protocol in PiSmmCpuDxeSmm driver.
> >
> > Cc: Ray Ni <ray.ni@intel.com>
> > Cc: Laszlo Ersek <lersek@redhat.com>
> > Signed-off-by: Eric Dong <eric.dong@intel.com>
> > ---
> > UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c | 570
> ++++++++++++++++++-
> > UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c | 18 +
> > UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h | 193 ++++++-
> > UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf | 3 +
> > UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.c | 344 +++++++++++
> > UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.h | 286 ++++++++++
> > 6 files changed, 1391 insertions(+), 23 deletions(-) create mode
> > 100644 UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.c create mode 100644
> > UefiCpuPkg/PiSmmCpuDxeSmm/SmmMp.h
> >
> > diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c
> > b/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c
> > index 64fb4d6344..f09e2738c3 100644
> > --- a/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c
> > +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c
> > @@ -140,7 +140,7 @@ ReleaseAllAPs (
> >
> > BspIndex = mSmmMpSyncData->BspIndex;
> > for (Index = mMaxNumberOfCpus; Index-- > 0;) {
> > - if (Index != BspIndex && *(mSmmMpSyncData-
> >CpuData[Index].Present)) {
> > + if (IsPresentAp (Index)) {
> > ReleaseSemaphore (mSmmMpSyncData->CpuData[Index].Run);
> > }
> > }
>
> version 5 again fails to build for me, with the following error message:
>
> > UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c: In function 'ReleaseAllAPs':
> > UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c:139:37: error: variable
> > 'BspIndex' set but not used [-Werror=unused-but-set-variable]
>
> With the following incremental patch:
>
> > diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c
> > b/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c
> > index f09e2738c30d..ef16997547b8 100644
> > --- a/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c
> > +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c
> > @@ -136,9 +136,7 @@ ReleaseAllAPs (
> > )
> > {
> > UINTN Index;
> > - UINTN BspIndex;
> >
> > - BspIndex = mSmmMpSyncData->BspIndex;
> > for (Index = mMaxNumberOfCpus; Index-- > 0;) {
> > if (IsPresentAp (Index)) {
> > ReleaseSemaphore (mSmmMpSyncData->CpuData[Index].Run);
>
> the build completes fine (using GCC48).
>
> If you change nothing on the series other than squashing the above fix, you
> can add my:
>
> Regression-tested-by: Laszlo Ersek <lersek@redhat.com>
>
> to both patches in the series.
>
> -*-
>
> Important: please do not push the series until the 5-level paging commits are
> reverted, and reapplied (with Mike's R-b on the MdePkg patch).
>
> Thanks!
> Laszlo
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#43618): https://edk2.groups.io/g/devel/message/43618
Mute This Topic: https://groups.io/mt/32414082/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-
© 2016 - 2026 Red Hat, Inc.