UefiCpuPkg/PiSmmCpuDxeSmm: Remove dependence between APs

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2268

In current implementation, when check whether APs called by StartUpAllAPs
or StartUpThisAp, it checks the Tokens value used by other APs. Also the AP
will update the Token value for itself if its task finished. In this
case, the potential race condition  issues happens for the tokens.
Because of this, system may trig ASSERT during cycling test.

This change enhance the code logic, add new attributes for the token to
remove the reference for the tokens belongs to other APs.

Reviewed-by: Ray Ni <ray.ni@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Eric Dong <eric.dong@intel.com>
This commit is contained in:
Eric Dong 2019-12-23 14:15:04 +08:00 committed by mergify[bot]
parent caa917491a
commit a457823f27
2 changed files with 45 additions and 85 deletions

View File

@ -402,38 +402,6 @@ IsPresentAp (
*(mSmmMpSyncData->CpuData[CpuIndex].Present)); *(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. Clean up the status flags used during executing the procedure.
@ -445,41 +413,16 @@ ReleaseToken (
IN UINTN CpuIndex IN UINTN CpuIndex
) )
{ {
UINTN Index; PROCEDURE_TOKEN *Token;
BOOLEAN Released;
if (InStartAllApsCall ()) { Token = mSmmMpSyncData->CpuData[CpuIndex].Token;
//
// In Start All APs mode, make sure all APs have finished task. if (InterlockedDecrement (&Token->RunningApCount) == 0) {
// ReleaseSpinLock (Token->SpinLock);
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; mSmmMpSyncData->CpuData[CpuIndex].Token = NULL;
} }
}
}
/** /**
Free the tokens in the maintained list. Free the tokens in the maintained list.
@ -912,12 +855,14 @@ APHandler (
*mSmmMpSyncData->CpuData[CpuIndex].Status = ProcedureStatus; *mSmmMpSyncData->CpuData[CpuIndex].Status = ProcedureStatus;
} }
if (mSmmMpSyncData->CpuData[CpuIndex].Token != NULL) {
ReleaseToken (CpuIndex);
}
// //
// Release BUSY // Release BUSY
// //
ReleaseSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy); ReleaseSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy);
ReleaseToken (CpuIndex);
} }
if (SmmCpuFeaturesNeedConfigureMtrrs()) { if (SmmCpuFeaturesNeedConfigureMtrrs()) {
@ -1111,7 +1056,7 @@ IsTokenInUse (
while (!IsNull (&gSmmCpuPrivate->TokenList, Link)) { while (!IsNull (&gSmmCpuPrivate->TokenList, Link)) {
ProcToken = PROCEDURE_TOKEN_FROM_LINK (Link); ProcToken = PROCEDURE_TOKEN_FROM_LINK (Link);
if (ProcToken->ProcedureToken == Token) { if (ProcToken->SpinLock == Token) {
return TRUE; return TRUE;
} }
@ -1124,16 +1069,18 @@ IsTokenInUse (
/** /**
create token and save it to the maintain list. create token and save it to the maintain list.
@param RunningApCount Input running AP count.
@retval return the spin lock used as token. @retval return the spin lock used as token.
**/ **/
SPIN_LOCK * PROCEDURE_TOKEN *
CreateToken ( CreateToken (
VOID IN UINT32 RunningApCount
) )
{ {
PROCEDURE_TOKEN *ProcToken; PROCEDURE_TOKEN *ProcToken;
SPIN_LOCK *CpuToken; SPIN_LOCK *SpinLock;
UINTN SpinLockSize; UINTN SpinLockSize;
TOKEN_BUFFER *TokenBuf; TOKEN_BUFFER *TokenBuf;
UINT32 TokenCountPerChunk; UINT32 TokenCountPerChunk;
@ -1160,20 +1107,21 @@ CreateToken (
gSmmCpuPrivate->UsedTokenNum = 0; gSmmCpuPrivate->UsedTokenNum = 0;
} }
CpuToken = (SPIN_LOCK *)(gSmmCpuPrivate->CurrentTokenBuf + SpinLockSize * gSmmCpuPrivate->UsedTokenNum); SpinLock = (SPIN_LOCK *)(gSmmCpuPrivate->CurrentTokenBuf + SpinLockSize * gSmmCpuPrivate->UsedTokenNum);
gSmmCpuPrivate->UsedTokenNum++; gSmmCpuPrivate->UsedTokenNum++;
InitializeSpinLock (CpuToken); InitializeSpinLock (SpinLock);
AcquireSpinLock (CpuToken); AcquireSpinLock (SpinLock);
ProcToken = AllocatePool (sizeof (PROCEDURE_TOKEN)); ProcToken = AllocatePool (sizeof (PROCEDURE_TOKEN));
ASSERT (ProcToken != NULL); ASSERT (ProcToken != NULL);
ProcToken->Signature = PROCEDURE_TOKEN_SIGNATURE; ProcToken->Signature = PROCEDURE_TOKEN_SIGNATURE;
ProcToken->ProcedureToken = CpuToken; ProcToken->SpinLock = SpinLock;
ProcToken->RunningApCount = RunningApCount;
InsertTailList (&gSmmCpuPrivate->TokenList, &ProcToken->Link); InsertTailList (&gSmmCpuPrivate->TokenList, &ProcToken->Link);
return CpuToken; return ProcToken;
} }
/** /**
@ -1246,6 +1194,8 @@ InternalSmmStartupThisAp (
IN OUT EFI_STATUS *CpuStatus IN OUT EFI_STATUS *CpuStatus
) )
{ {
PROCEDURE_TOKEN *ProcToken;
if (CpuIndex >= gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus) { if (CpuIndex >= gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus) {
DEBUG((DEBUG_ERROR, "CpuIndex(%d) >= gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus(%d)\n", CpuIndex, gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus)); DEBUG((DEBUG_ERROR, "CpuIndex(%d) >= gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus(%d)\n", CpuIndex, gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus));
return EFI_INVALID_PARAMETER; return EFI_INVALID_PARAMETER;
@ -1278,14 +1228,12 @@ InternalSmmStartupThisAp (
AcquireSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy); AcquireSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy);
if (Token != NULL) {
*Token = (MM_COMPLETION) CreateToken ();
}
mSmmMpSyncData->CpuData[CpuIndex].Procedure = Procedure; mSmmMpSyncData->CpuData[CpuIndex].Procedure = Procedure;
mSmmMpSyncData->CpuData[CpuIndex].Parameter = ProcArguments; mSmmMpSyncData->CpuData[CpuIndex].Parameter = ProcArguments;
if (Token != NULL) { if (Token != NULL) {
mSmmMpSyncData->CpuData[CpuIndex].Token = (SPIN_LOCK *)(*Token); ProcToken= CreateToken (1);
mSmmMpSyncData->CpuData[CpuIndex].Token = ProcToken;
*Token = (MM_COMPLETION)ProcToken->SpinLock;
} }
mSmmMpSyncData->CpuData[CpuIndex].Status = CpuStatus; mSmmMpSyncData->CpuData[CpuIndex].Status = CpuStatus;
if (mSmmMpSyncData->CpuData[CpuIndex].Status != NULL) { if (mSmmMpSyncData->CpuData[CpuIndex].Status != NULL) {
@ -1343,6 +1291,7 @@ InternalSmmStartupAllAPs (
{ {
UINTN Index; UINTN Index;
UINTN CpuCount; UINTN CpuCount;
PROCEDURE_TOKEN *ProcToken;
if ((TimeoutInMicroseconds != 0) && ((mSmmMp.Attributes & EFI_MM_MP_TIMEOUT_SUPPORTED) == 0)) { if ((TimeoutInMicroseconds != 0) && ((mSmmMp.Attributes & EFI_MM_MP_TIMEOUT_SUPPORTED) == 0)) {
return EFI_INVALID_PARAMETER; return EFI_INVALID_PARAMETER;
@ -1371,7 +1320,10 @@ InternalSmmStartupAllAPs (
} }
if (Token != NULL) { if (Token != NULL) {
*Token = (MM_COMPLETION) CreateToken (); ProcToken = CreateToken ((UINT32)mMaxNumberOfCpus);
*Token = (MM_COMPLETION)ProcToken->SpinLock;
} else {
ProcToken = NULL;
} }
// //
@ -1391,8 +1343,8 @@ InternalSmmStartupAllAPs (
if (IsPresentAp (Index)) { if (IsPresentAp (Index)) {
mSmmMpSyncData->CpuData[Index].Procedure = (EFI_AP_PROCEDURE2) Procedure; mSmmMpSyncData->CpuData[Index].Procedure = (EFI_AP_PROCEDURE2) Procedure;
mSmmMpSyncData->CpuData[Index].Parameter = ProcedureArguments; mSmmMpSyncData->CpuData[Index].Parameter = ProcedureArguments;
if (Token != NULL) { if (ProcToken != NULL) {
mSmmMpSyncData->CpuData[Index].Token = (SPIN_LOCK *)(*Token); mSmmMpSyncData->CpuData[Index].Token = ProcToken;
} }
if (CPUStatus != NULL) { if (CPUStatus != NULL) {
mSmmMpSyncData->CpuData[Index].Status = &CPUStatus[Index]; mSmmMpSyncData->CpuData[Index].Status = &CPUStatus[Index];
@ -1408,6 +1360,13 @@ InternalSmmStartupAllAPs (
if (CPUStatus != NULL) { if (CPUStatus != NULL) {
CPUStatus[Index] = EFI_NOT_STARTED; CPUStatus[Index] = EFI_NOT_STARTED;
} }
//
// Decrease the count to mark this processor(AP or BSP) as finished.
//
if (ProcToken != NULL) {
WaitForSemaphore (&ProcToken->RunningApCount);
}
} }
} }

View File

@ -212,7 +212,8 @@ typedef struct {
UINTN Signature; UINTN Signature;
LIST_ENTRY Link; LIST_ENTRY Link;
SPIN_LOCK *ProcedureToken; SPIN_LOCK *SpinLock;
volatile UINT32 RunningApCount;
} PROCEDURE_TOKEN; } PROCEDURE_TOKEN;
#define PROCEDURE_TOKEN_FROM_LINK(a) CR (a, PROCEDURE_TOKEN, Link, PROCEDURE_TOKEN_SIGNATURE) #define PROCEDURE_TOKEN_FROM_LINK(a) CR (a, PROCEDURE_TOKEN, Link, PROCEDURE_TOKEN_SIGNATURE)
@ -407,7 +408,7 @@ typedef struct {
volatile VOID *Parameter; volatile VOID *Parameter;
volatile UINT32 *Run; volatile UINT32 *Run;
volatile BOOLEAN *Present; volatile BOOLEAN *Present;
SPIN_LOCK *Token; PROCEDURE_TOKEN *Token;
EFI_STATUS *Status; EFI_STATUS *Status;
} SMM_CPU_DATA_BLOCK; } SMM_CPU_DATA_BLOCK;