mirror of https://github.com/acidanthera/audk.git
UefiCpuPkg/PiSmmCpuDxeSmm: Enable MM MP Protocol
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> Reviewed-by: Ray Ni <ray.ni@intel.com> Regression-tested-by: Laszlo Ersek <lersek@redhat.com>
This commit is contained in:
parent
18f169a95c
commit
51dd408ae1
|
@ -136,11 +136,9 @@ ReleaseAllAPs (
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
UINTN Index;
|
UINTN Index;
|
||||||
UINTN BspIndex;
|
|
||||||
|
|
||||||
BspIndex = mSmmMpSyncData->BspIndex;
|
|
||||||
for (Index = mMaxNumberOfCpus; Index-- > 0;) {
|
for (Index = mMaxNumberOfCpus; Index-- > 0;) {
|
||||||
if (Index != BspIndex && *(mSmmMpSyncData->CpuData[Index].Present)) {
|
if (IsPresentAp (Index)) {
|
||||||
ReleaseSemaphore (mSmmMpSyncData->CpuData[Index].Run);
|
ReleaseSemaphore (mSmmMpSyncData->CpuData[Index].Run);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -347,6 +345,165 @@ ReplaceOSMtrrs (
|
||||||
MtrrSetAllMtrrs (&gSmiMtrrs);
|
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.
|
SMI handler for BSP.
|
||||||
|
|
||||||
|
@ -476,12 +633,7 @@ BSPHandler (
|
||||||
//
|
//
|
||||||
// Make sure all APs have completed their pending none-block tasks
|
// Make sure all APs have completed their pending none-block tasks
|
||||||
//
|
//
|
||||||
for (Index = mMaxNumberOfCpus; Index-- > 0;) {
|
WaitForAllAPsNotBusy (TRUE);
|
||||||
if (Index != CpuIndex && *(mSmmMpSyncData->CpuData[Index].Present)) {
|
|
||||||
AcquireSpinLock (mSmmMpSyncData->CpuData[Index].Busy);
|
|
||||||
ReleaseSpinLock (mSmmMpSyncData->CpuData[Index].Busy);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Perform the remaining tasks
|
// Perform the remaining tasks
|
||||||
|
@ -572,6 +724,11 @@ BSPHandler (
|
||||||
//
|
//
|
||||||
WaitForAllAPs (ApCount);
|
WaitForAllAPs (ApCount);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Clean the tokens buffer.
|
||||||
|
//
|
||||||
|
FreeTokens ();
|
||||||
|
|
||||||
//
|
//
|
||||||
// Reset BspIndex to -1, meaning BSP has not been elected.
|
// Reset BspIndex to -1, meaning BSP has not been elected.
|
||||||
//
|
//
|
||||||
|
@ -604,6 +761,7 @@ APHandler (
|
||||||
UINT64 Timer;
|
UINT64 Timer;
|
||||||
UINTN BspIndex;
|
UINTN BspIndex;
|
||||||
MTRR_SETTINGS Mtrrs;
|
MTRR_SETTINGS Mtrrs;
|
||||||
|
EFI_STATUS ProcedureStatus;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Timeout BSP
|
// Timeout BSP
|
||||||
|
@ -730,14 +888,19 @@ APHandler (
|
||||||
//
|
//
|
||||||
// Invoke the scheduled procedure
|
// Invoke the scheduled procedure
|
||||||
//
|
//
|
||||||
(*mSmmMpSyncData->CpuData[CpuIndex].Procedure) (
|
ProcedureStatus = (*mSmmMpSyncData->CpuData[CpuIndex].Procedure) (
|
||||||
(VOID*)mSmmMpSyncData->CpuData[CpuIndex].Parameter
|
(VOID*)mSmmMpSyncData->CpuData[CpuIndex].Parameter
|
||||||
);
|
);
|
||||||
|
if (mSmmMpSyncData->CpuData[CpuIndex].Status != NULL) {
|
||||||
|
*mSmmMpSyncData->CpuData[CpuIndex].Status = ProcedureStatus;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Release BUSY
|
// Release BUSY
|
||||||
//
|
//
|
||||||
ReleaseSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy);
|
ReleaseSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy);
|
||||||
|
|
||||||
|
ReleaseToken (CpuIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SmmCpuFeaturesNeedConfigureMtrrs()) {
|
if (SmmCpuFeaturesNeedConfigureMtrrs()) {
|
||||||
|
@ -906,13 +1069,124 @@ Gen4GPageTable (
|
||||||
return (UINT32)(UINTN)PageTable;
|
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.
|
Schedule a procedure to run on the specified CPU.
|
||||||
|
|
||||||
@param[in] Procedure The address of the procedure to run
|
@param[in] Procedure The address of the procedure to run
|
||||||
@param[in] CpuIndex Target CPU Index
|
@param[in] CpuIndex Target CPU Index
|
||||||
@param[in, out] ProcArguments The parameter to pass to the procedure
|
@param[in,out] ProcArguments The parameter to pass to the procedure
|
||||||
@param[in] BlockingMode Startup AP in blocking mode or not
|
@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 not valid
|
||||||
@retval EFI_INVALID_PARAMETER CpuNumber specifying BSP
|
@retval EFI_INVALID_PARAMETER CpuNumber specifying BSP
|
||||||
|
@ -923,10 +1197,12 @@ Gen4GPageTable (
|
||||||
**/
|
**/
|
||||||
EFI_STATUS
|
EFI_STATUS
|
||||||
InternalSmmStartupThisAp (
|
InternalSmmStartupThisAp (
|
||||||
IN EFI_AP_PROCEDURE Procedure,
|
IN EFI_AP_PROCEDURE2 Procedure,
|
||||||
IN UINTN CpuIndex,
|
IN UINTN CpuIndex,
|
||||||
IN OUT VOID *ProcArguments OPTIONAL,
|
IN OUT VOID *ProcArguments OPTIONAL,
|
||||||
IN BOOLEAN BlockingMode
|
IN MM_COMPLETION *Token,
|
||||||
|
IN UINTN TimeoutInMicroseconds,
|
||||||
|
IN OUT EFI_STATUS *CpuStatus
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (CpuIndex >= gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus) {
|
if (CpuIndex >= gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus) {
|
||||||
|
@ -952,24 +1228,190 @@ InternalSmmStartupThisAp (
|
||||||
}
|
}
|
||||||
return EFI_INVALID_PARAMETER;
|
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);
|
AcquireSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy);
|
||||||
} else {
|
} else {
|
||||||
if (!AcquireSpinLockOrFail (mSmmMpSyncData->CpuData[CpuIndex].Busy)) {
|
if (!AcquireSpinLockOrFail (mSmmMpSyncData->CpuData[CpuIndex].Busy)) {
|
||||||
DEBUG((DEBUG_ERROR, "mSmmMpSyncData->CpuData[%d].Busy\n", CpuIndex));
|
DEBUG((DEBUG_ERROR, "Can't acquire mSmmMpSyncData->CpuData[%d].Busy\n", CpuIndex));
|
||||||
return EFI_INVALID_PARAMETER;
|
return EFI_NOT_READY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*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) {
|
||||||
|
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);
|
ReleaseSemaphore (mSmmMpSyncData->CpuData[CpuIndex].Run);
|
||||||
|
|
||||||
if (BlockingMode) {
|
if (Token == NULL) {
|
||||||
AcquireSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy);
|
AcquireSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy);
|
||||||
ReleaseSpinLock (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;
|
return EFI_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -995,7 +1437,15 @@ SmmBlockingStartupThisAp (
|
||||||
IN OUT VOID *ProcArguments OPTIONAL
|
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 +1470,22 @@ SmmStartupThisAp (
|
||||||
IN OUT VOID *ProcArguments OPTIONAL
|
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 +1577,13 @@ SmiRendezvous (
|
||||||
Cr2 = 0;
|
Cr2 = 0;
|
||||||
SaveCr2 (&Cr2);
|
SaveCr2 (&Cr2);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Call the user register Startup function first.
|
||||||
|
//
|
||||||
|
if (mSmmMpSyncData->StartupProcedure != NULL) {
|
||||||
|
mSmmMpSyncData->StartupProcedure (mSmmMpSyncData->StartupProcArgs);
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Perform CPU specific entry hooks
|
// Perform CPU specific entry hooks
|
||||||
//
|
//
|
||||||
|
@ -1256,6 +1728,21 @@ Exit:
|
||||||
RestoreCr2 (Cr2);
|
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.
|
Allocate buffer for all semaphores and spin locks.
|
||||||
|
|
||||||
|
@ -1469,3 +1956,40 @@ RegisterSmmEntry (
|
||||||
gSmmCpuPrivate->SmmCoreEntry = SmmEntryPoint;
|
gSmmCpuPrivate->SmmCoreEntry = SmmEntryPoint;
|
||||||
return EFI_SUCCESS;
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -34,6 +34,8 @@ SMM_CPU_PRIVATE_DATA mSmmCpuPrivateData = {
|
||||||
mSmmCpuPrivateData.SmmReservedSmramRegion, // SmmConfiguration.SmramReservedRegions
|
mSmmCpuPrivateData.SmmReservedSmramRegion, // SmmConfiguration.SmramReservedRegions
|
||||||
RegisterSmmEntry // SmmConfiguration.RegisterSmmEntry
|
RegisterSmmEntry // SmmConfiguration.RegisterSmmEntry
|
||||||
},
|
},
|
||||||
|
NULL, // pointer to Ap Wrapper Func array
|
||||||
|
{NULL, NULL}, // List_Entry for Tokens.
|
||||||
};
|
};
|
||||||
|
|
||||||
CPU_HOT_PLUG_DATA mCpuHotPlugData = {
|
CPU_HOT_PLUG_DATA mCpuHotPlugData = {
|
||||||
|
@ -996,6 +998,22 @@ PiCpuSmmEntry (
|
||||||
);
|
);
|
||||||
ASSERT_EFI_ERROR (Status);
|
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.
|
// Expose address of CPU Hot Plug Data structure if CPU hot plug is supported.
|
||||||
//
|
//
|
||||||
|
|
|
@ -20,6 +20,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||||
#include <Protocol/SmmReadyToLock.h>
|
#include <Protocol/SmmReadyToLock.h>
|
||||||
#include <Protocol/SmmCpuService.h>
|
#include <Protocol/SmmCpuService.h>
|
||||||
#include <Protocol/SmmMemoryAttribute.h>
|
#include <Protocol/SmmMemoryAttribute.h>
|
||||||
|
#include <Protocol/MmMp.h>
|
||||||
|
|
||||||
#include <Guid/AcpiS3Context.h>
|
#include <Guid/AcpiS3Context.h>
|
||||||
#include <Guid/MemoryAttributesTable.h>
|
#include <Guid/MemoryAttributesTable.h>
|
||||||
|
@ -197,6 +198,25 @@ typedef UINT32 SMM_CPU_ARRIVAL_EXCEPTIONS;
|
||||||
#define ARRIVAL_EXCEPTION_DELAYED 0x2
|
#define ARRIVAL_EXCEPTION_DELAYED 0x2
|
||||||
#define ARRIVAL_EXCEPTION_SMI_DISABLED 0x4
|
#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
|
// Private structure for the SMM CPU module that is stored in DXE Runtime memory
|
||||||
// Contains the SMM Configuration Protocols that is produced.
|
// Contains the SMM Configuration Protocols that is produced.
|
||||||
|
@ -219,6 +239,10 @@ typedef struct {
|
||||||
EFI_SMM_ENTRY_POINT SmmCoreEntry;
|
EFI_SMM_ENTRY_POINT SmmCoreEntry;
|
||||||
|
|
||||||
EFI_SMM_CONFIGURATION_PROTOCOL SmmConfiguration;
|
EFI_SMM_CONFIGURATION_PROTOCOL SmmConfiguration;
|
||||||
|
|
||||||
|
PROCEDURE_WRAPPER *ApWrapperFunc;
|
||||||
|
LIST_ENTRY TokenList;
|
||||||
|
|
||||||
} SMM_CPU_PRIVATE_DATA;
|
} SMM_CPU_PRIVATE_DATA;
|
||||||
|
|
||||||
extern SMM_CPU_PRIVATE_DATA *gSmmCpuPrivate;
|
extern SMM_CPU_PRIVATE_DATA *gSmmCpuPrivate;
|
||||||
|
@ -226,6 +250,7 @@ extern CPU_HOT_PLUG_DATA mCpuHotPlugData;
|
||||||
extern UINTN mMaxNumberOfCpus;
|
extern UINTN mMaxNumberOfCpus;
|
||||||
extern UINTN mNumberOfCpus;
|
extern UINTN mNumberOfCpus;
|
||||||
extern EFI_SMM_CPU_PROTOCOL mSmmCpu;
|
extern EFI_SMM_CPU_PROTOCOL mSmmCpu;
|
||||||
|
extern EFI_MM_MP_PROTOCOL mSmmMp;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// The mode of the CPU at the time an SMI occurs
|
/// The mode of the CPU at the time an SMI occurs
|
||||||
|
@ -363,10 +388,12 @@ SmmRelocationSemaphoreComplete (
|
||||||
///
|
///
|
||||||
typedef struct {
|
typedef struct {
|
||||||
SPIN_LOCK *Busy;
|
SPIN_LOCK *Busy;
|
||||||
volatile EFI_AP_PROCEDURE Procedure;
|
volatile EFI_AP_PROCEDURE2 Procedure;
|
||||||
volatile VOID *Parameter;
|
volatile VOID *Parameter;
|
||||||
volatile UINT32 *Run;
|
volatile UINT32 *Run;
|
||||||
volatile BOOLEAN *Present;
|
volatile BOOLEAN *Present;
|
||||||
|
SPIN_LOCK *Token;
|
||||||
|
EFI_STATUS *Status;
|
||||||
} SMM_CPU_DATA_BLOCK;
|
} SMM_CPU_DATA_BLOCK;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
@ -388,6 +415,8 @@ typedef struct {
|
||||||
volatile SMM_CPU_SYNC_MODE EffectiveSyncMode;
|
volatile SMM_CPU_SYNC_MODE EffectiveSyncMode;
|
||||||
volatile BOOLEAN SwitchBsp;
|
volatile BOOLEAN SwitchBsp;
|
||||||
volatile BOOLEAN *CandidateBsp;
|
volatile BOOLEAN *CandidateBsp;
|
||||||
|
EFI_AP_PROCEDURE StartupProcedure;
|
||||||
|
VOID *StartupProcArgs;
|
||||||
} SMM_DISPATCHER_MP_SYNC_DATA;
|
} SMM_DISPATCHER_MP_SYNC_DATA;
|
||||||
|
|
||||||
#define SMM_PSD_OFFSET 0xfb00
|
#define SMM_PSD_OFFSET 0xfb00
|
||||||
|
@ -410,6 +439,7 @@ typedef struct {
|
||||||
SPIN_LOCK *Busy;
|
SPIN_LOCK *Busy;
|
||||||
volatile UINT32 *Run;
|
volatile UINT32 *Run;
|
||||||
volatile BOOLEAN *Present;
|
volatile BOOLEAN *Present;
|
||||||
|
SPIN_LOCK *Token;
|
||||||
} SMM_CPU_SEMAPHORE_CPU;
|
} SMM_CPU_SEMAPHORE_CPU;
|
||||||
|
|
||||||
///
|
///
|
||||||
|
@ -1259,4 +1289,165 @@ RestoreCr2 (
|
||||||
IN UINTN Cr2
|
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
|
#endif
|
||||||
|
|
|
@ -40,6 +40,8 @@
|
||||||
SmmProfileInternal.h
|
SmmProfileInternal.h
|
||||||
SmramSaveState.c
|
SmramSaveState.c
|
||||||
SmmCpuMemoryManagement.c
|
SmmCpuMemoryManagement.c
|
||||||
|
SmmMp.h
|
||||||
|
SmmMp.c
|
||||||
|
|
||||||
[Sources.Ia32]
|
[Sources.Ia32]
|
||||||
Ia32/Semaphore.c
|
Ia32/Semaphore.c
|
||||||
|
@ -105,6 +107,7 @@
|
||||||
gEfiSmmReadyToLockProtocolGuid ## NOTIFY
|
gEfiSmmReadyToLockProtocolGuid ## NOTIFY
|
||||||
gEfiSmmCpuServiceProtocolGuid ## PRODUCES
|
gEfiSmmCpuServiceProtocolGuid ## PRODUCES
|
||||||
gEdkiiSmmMemoryAttributeProtocolGuid ## PRODUCES
|
gEdkiiSmmMemoryAttributeProtocolGuid ## PRODUCES
|
||||||
|
gEfiMmMpProtocolGuid ## PRODUCES
|
||||||
|
|
||||||
[Guids]
|
[Guids]
|
||||||
gEfiAcpiVariableGuid ## SOMETIMES_CONSUMES ## HOB # it is used for S3 boot.
|
gEfiAcpiVariableGuid ## SOMETIMES_CONSUMES ## HOB # it is used for S3 boot.
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
Loading…
Reference in New Issue