mirror of https://github.com/acidanthera/audk.git
486 lines
16 KiB
C
486 lines
16 KiB
C
/** @file
|
|
This file implements some PEI services about PPI.
|
|
|
|
Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
|
|
**/
|
|
|
|
#include "UnitTestPeiServicesTablePointerLib.h"
|
|
|
|
/**
|
|
|
|
This function installs an interface in the PEI PPI database by GUID.
|
|
The purpose of the service is to publish an interface that other parties
|
|
can use to call additional PEIMs.
|
|
|
|
@param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
|
|
@param PpiList Pointer to a list of PEI PPI Descriptors.
|
|
@param Single TRUE if only single entry in the PpiList.
|
|
FALSE if the PpiList is ended with an entry which has the
|
|
EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST flag set in its Flags field.
|
|
|
|
@retval EFI_SUCCESS if all PPIs in PpiList are successfully installed.
|
|
@retval EFI_INVALID_PARAMETER if PpiList is NULL pointer
|
|
if any PPI in PpiList is not valid
|
|
@retval EFI_OUT_OF_RESOURCES if there is no more memory resource to install PPI
|
|
|
|
**/
|
|
EFI_STATUS
|
|
InternalPeiInstallPpi (
|
|
IN CONST EFI_PEI_SERVICES **PeiServices,
|
|
IN CONST EFI_PEI_PPI_DESCRIPTOR *PpiList,
|
|
IN BOOLEAN Single
|
|
)
|
|
{
|
|
PEI_CORE_INSTANCE *PrivateData;
|
|
PEI_PPI_LIST *PpiListPointer;
|
|
UINTN Index;
|
|
UINTN LastCount;
|
|
|
|
if (PpiList == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
|
|
|
|
PpiListPointer = &PrivateData->PpiData.PpiList;
|
|
Index = PpiListPointer->CurrentCount;
|
|
LastCount = Index;
|
|
|
|
//
|
|
// This is loop installs all PPI descriptors in the PpiList. It is terminated
|
|
// by the EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST being set in the last
|
|
// EFI_PEI_PPI_DESCRIPTOR in the list.
|
|
//
|
|
|
|
for ( ; ;) {
|
|
//
|
|
// Check if it is a valid PPI.
|
|
// If not, rollback list to exclude all in this list.
|
|
// Try to indicate which item failed.
|
|
//
|
|
if ((PpiList->Flags & EFI_PEI_PPI_DESCRIPTOR_PPI) == 0) {
|
|
PpiListPointer->CurrentCount = LastCount;
|
|
DEBUG ((DEBUG_ERROR, "ERROR -> InstallPpi: %g %p\n", PpiList->Guid, PpiList->Ppi));
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (Index >= PpiListPointer->MaxCount) {
|
|
//
|
|
// Run out of room, assert.
|
|
//
|
|
ASSERT (Index < PpiListPointer->MaxCount);
|
|
}
|
|
|
|
DEBUG ((DEBUG_INFO, "Install PPI: %g\n", PpiList->Guid));
|
|
PpiListPointer->PpiPtrs[Index].Ppi = (EFI_PEI_PPI_DESCRIPTOR *)PpiList;
|
|
Index++;
|
|
PpiListPointer->CurrentCount++;
|
|
|
|
if (Single) {
|
|
//
|
|
// Only single entry in the PpiList.
|
|
//
|
|
break;
|
|
} else if ((PpiList->Flags & EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) ==
|
|
EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST)
|
|
{
|
|
//
|
|
// Continue until the end of the PPI List.
|
|
//
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Go to the next descriptor.
|
|
//
|
|
PpiList++;
|
|
}
|
|
|
|
//
|
|
// Process any callback level notifies for newly installed PPIs.
|
|
//
|
|
ProcessNotify (
|
|
PrivateData,
|
|
EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
|
|
LastCount,
|
|
PpiListPointer->CurrentCount,
|
|
0,
|
|
PrivateData->PpiData.CallbackNotifyList.CurrentCount
|
|
);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
|
|
This function installs an interface in the PEI PPI database by GUID.
|
|
The purpose of the service is to publish an interface that other parties
|
|
can use to call additional PEIMs.
|
|
|
|
@param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
|
|
@param PpiList Pointer to a list of PEI PPI Descriptors.
|
|
|
|
@retval EFI_SUCCESS if all PPIs in PpiList are successfully installed.
|
|
@retval EFI_INVALID_PARAMETER if PpiList is NULL pointer
|
|
if any PPI in PpiList is not valid
|
|
@retval EFI_OUT_OF_RESOURCES if there is no more memory resource to install PPI
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
UnitTestInstallPpi (
|
|
IN CONST EFI_PEI_SERVICES **PeiServices,
|
|
IN CONST EFI_PEI_PPI_DESCRIPTOR *PpiList
|
|
)
|
|
{
|
|
return InternalPeiInstallPpi (PeiServices, PpiList, FALSE);
|
|
}
|
|
|
|
/**
|
|
|
|
This function reinstalls an interface in the PEI PPI database by GUID.
|
|
The purpose of the service is to publish an interface that other parties can
|
|
use to replace an interface of the same name in the protocol database with a
|
|
different interface.
|
|
|
|
@param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
|
|
@param OldPpi Pointer to the old PEI PPI Descriptors.
|
|
@param NewPpi Pointer to the new PEI PPI Descriptors.
|
|
|
|
@retval EFI_SUCCESS if the operation was successful
|
|
@retval EFI_INVALID_PARAMETER if OldPpi or NewPpi is NULL
|
|
@retval EFI_INVALID_PARAMETER if NewPpi is not valid
|
|
@retval EFI_NOT_FOUND if the PPI was not in the database
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
UnitTestReInstallPpi (
|
|
IN CONST EFI_PEI_SERVICES **PeiServices,
|
|
IN CONST EFI_PEI_PPI_DESCRIPTOR *OldPpi,
|
|
IN CONST EFI_PEI_PPI_DESCRIPTOR *NewPpi
|
|
)
|
|
{
|
|
PEI_CORE_INSTANCE *PrivateData;
|
|
UINTN Index;
|
|
|
|
if ((OldPpi == NULL) || (NewPpi == NULL)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if ((NewPpi->Flags & EFI_PEI_PPI_DESCRIPTOR_PPI) == 0) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
|
|
|
|
//
|
|
// Find the old PPI instance in the database. If we can not find it,
|
|
// return the EFI_NOT_FOUND error.
|
|
//
|
|
for (Index = 0; Index < PrivateData->PpiData.PpiList.CurrentCount; Index++) {
|
|
if (OldPpi == PrivateData->PpiData.PpiList.PpiPtrs[Index].Ppi) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (Index == PrivateData->PpiData.PpiList.CurrentCount) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
//
|
|
// Replace the old PPI with the new one.
|
|
//
|
|
DEBUG ((DEBUG_INFO, "Reinstall PPI: %g\n", NewPpi->Guid));
|
|
PrivateData->PpiData.PpiList.PpiPtrs[Index].Ppi = (EFI_PEI_PPI_DESCRIPTOR *)NewPpi;
|
|
|
|
//
|
|
// Process any callback level notifies for the newly installed PPI.
|
|
//
|
|
ProcessNotify (
|
|
PrivateData,
|
|
EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
|
|
Index,
|
|
Index+1,
|
|
0,
|
|
PrivateData->PpiData.CallbackNotifyList.CurrentCount
|
|
);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
|
|
Locate a given named PPI.
|
|
|
|
|
|
@param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
|
|
@param Guid Pointer to GUID of the PPI.
|
|
@param Instance Instance Number to discover.
|
|
@param PpiDescriptor Pointer to reference the found descriptor. If not NULL,
|
|
returns a pointer to the descriptor (includes flags, etc)
|
|
@param Ppi Pointer to reference the found PPI
|
|
|
|
@retval EFI_SUCCESS if the PPI is in the database
|
|
@retval EFI_NOT_FOUND if the PPI is not in the database
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
UnitTestLocatePpi (
|
|
IN CONST EFI_PEI_SERVICES **PeiServices,
|
|
IN CONST EFI_GUID *Guid,
|
|
IN UINTN Instance,
|
|
IN OUT EFI_PEI_PPI_DESCRIPTOR **PpiDescriptor,
|
|
IN OUT VOID **Ppi
|
|
)
|
|
{
|
|
PEI_CORE_INSTANCE *PrivateData;
|
|
UINTN Index;
|
|
EFI_GUID *CheckGuid;
|
|
EFI_PEI_PPI_DESCRIPTOR *TempPtr;
|
|
|
|
PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
|
|
|
|
//
|
|
// Search the data base for the matching instance of the GUIDed PPI.
|
|
//
|
|
for (Index = 0; Index < PrivateData->PpiData.PpiList.CurrentCount; Index++) {
|
|
TempPtr = PrivateData->PpiData.PpiList.PpiPtrs[Index].Ppi;
|
|
CheckGuid = TempPtr->Guid;
|
|
|
|
//
|
|
// Don't use CompareGuid function here for performance reasons.
|
|
// Instead we compare the GUID as INT32 at a time and branch
|
|
// on the first failed comparison.
|
|
//
|
|
if ((((INT32 *)Guid)[0] == ((INT32 *)CheckGuid)[0]) &&
|
|
(((INT32 *)Guid)[1] == ((INT32 *)CheckGuid)[1]) &&
|
|
(((INT32 *)Guid)[2] == ((INT32 *)CheckGuid)[2]) &&
|
|
(((INT32 *)Guid)[3] == ((INT32 *)CheckGuid)[3]))
|
|
{
|
|
if (Instance == 0) {
|
|
if (PpiDescriptor != NULL) {
|
|
*PpiDescriptor = TempPtr;
|
|
}
|
|
|
|
if (Ppi != NULL) {
|
|
*Ppi = TempPtr->Ppi;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
Instance--;
|
|
}
|
|
}
|
|
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
/**
|
|
|
|
This function installs a notification service to be called back when a given
|
|
interface is installed or reinstalled. The purpose of the service is to publish
|
|
an interface that other parties can use to call additional PPIs that may materialize later.
|
|
|
|
@param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
|
|
@param NotifyList Pointer to list of Descriptors to notify upon.
|
|
@param Single TRUE if only single entry in the NotifyList.
|
|
FALSE if the NotifyList is ended with an entry which has the
|
|
EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST flag set in its Flags field.
|
|
|
|
@retval EFI_SUCCESS if successful
|
|
@retval EFI_OUT_OF_RESOURCES if no space in the database
|
|
@retval EFI_INVALID_PARAMETER if not a good descriptor
|
|
|
|
**/
|
|
EFI_STATUS
|
|
InternalPeiNotifyPpi (
|
|
IN CONST EFI_PEI_SERVICES **PeiServices,
|
|
IN CONST EFI_PEI_NOTIFY_DESCRIPTOR *NotifyList,
|
|
IN BOOLEAN Single
|
|
)
|
|
{
|
|
PEI_CORE_INSTANCE *PrivateData;
|
|
PEI_CALLBACK_NOTIFY_LIST *CallbackNotifyListPointer;
|
|
UINTN CallbackNotifyIndex;
|
|
UINTN LastCallbackNotifyCount;
|
|
PEI_DISPATCH_NOTIFY_LIST *DispatchNotifyListPointer;
|
|
UINTN DispatchNotifyIndex;
|
|
UINTN LastDispatchNotifyCount;
|
|
|
|
if (NotifyList == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
|
|
|
|
CallbackNotifyListPointer = &PrivateData->PpiData.CallbackNotifyList;
|
|
CallbackNotifyIndex = CallbackNotifyListPointer->CurrentCount;
|
|
LastCallbackNotifyCount = CallbackNotifyIndex;
|
|
|
|
DispatchNotifyListPointer = &PrivateData->PpiData.DispatchNotifyList;
|
|
DispatchNotifyIndex = DispatchNotifyListPointer->CurrentCount;
|
|
LastDispatchNotifyCount = DispatchNotifyIndex;
|
|
|
|
//
|
|
// This is loop installs all Notify descriptors in the NotifyList. It is
|
|
// terminated by the EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST being set in the last
|
|
// EFI_PEI_NOTIFY_DESCRIPTOR in the list.
|
|
//
|
|
|
|
for ( ; ;) {
|
|
//
|
|
// If some of the PPI data is invalid restore original Notify PPI database value
|
|
//
|
|
if ((NotifyList->Flags & EFI_PEI_PPI_DESCRIPTOR_NOTIFY_TYPES) == 0) {
|
|
CallbackNotifyListPointer->CurrentCount = LastCallbackNotifyCount;
|
|
DispatchNotifyListPointer->CurrentCount = LastDispatchNotifyCount;
|
|
DEBUG ((DEBUG_ERROR, "ERROR -> NotifyPpi: %g %p\n", NotifyList->Guid, NotifyList->Notify));
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if ((NotifyList->Flags & EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK) != 0) {
|
|
if (CallbackNotifyIndex >= CallbackNotifyListPointer->MaxCount) {
|
|
//
|
|
// Run out of room, assert.
|
|
//
|
|
ASSERT (CallbackNotifyIndex < CallbackNotifyListPointer->MaxCount);
|
|
}
|
|
|
|
CallbackNotifyListPointer->NotifyPtrs[CallbackNotifyIndex].Notify = (EFI_PEI_NOTIFY_DESCRIPTOR *)NotifyList;
|
|
CallbackNotifyIndex++;
|
|
CallbackNotifyListPointer->CurrentCount++;
|
|
} else {
|
|
ASSERT ((NotifyList->Flags & EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK) != 0);
|
|
}
|
|
|
|
DEBUG ((DEBUG_INFO, "Register PPI Notify: %g\n", NotifyList->Guid));
|
|
|
|
if (Single) {
|
|
//
|
|
// Only single entry in the NotifyList.
|
|
//
|
|
break;
|
|
} else if ((NotifyList->Flags & EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) ==
|
|
EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST)
|
|
{
|
|
//
|
|
// Continue until the end of the Notify List.
|
|
//
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Go to the next descriptor.
|
|
//
|
|
NotifyList++;
|
|
}
|
|
|
|
//
|
|
// Process any callback level notifies for all previously installed PPIs.
|
|
//
|
|
ProcessNotify (
|
|
PrivateData,
|
|
EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
|
|
0,
|
|
PrivateData->PpiData.PpiList.CurrentCount,
|
|
LastCallbackNotifyCount,
|
|
CallbackNotifyListPointer->CurrentCount
|
|
);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
|
|
This function installs a notification service to be called back when a given
|
|
interface is installed or reinstalled. The purpose of the service is to publish
|
|
an interface that other parties can use to call additional PPIs that may materialize later.
|
|
|
|
@param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
|
|
@param NotifyList Pointer to list of Descriptors to notify upon.
|
|
|
|
@retval EFI_SUCCESS if successful
|
|
@retval EFI_OUT_OF_RESOURCES if no space in the database
|
|
@retval EFI_INVALID_PARAMETER if not a good descriptor
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
UnitTestNotifyPpi (
|
|
IN CONST EFI_PEI_SERVICES **PeiServices,
|
|
IN CONST EFI_PEI_NOTIFY_DESCRIPTOR *NotifyList
|
|
)
|
|
{
|
|
return InternalPeiNotifyPpi (PeiServices, NotifyList, FALSE);
|
|
}
|
|
|
|
/**
|
|
|
|
Process notifications.
|
|
|
|
@param PrivateData PeiCore's private data structure
|
|
@param NotifyType Type of notify to fire.
|
|
@param InstallStartIndex Install Beginning index.
|
|
@param InstallStopIndex Install Ending index.
|
|
@param NotifyStartIndex Notify Beginning index.
|
|
@param NotifyStopIndex Notify Ending index.
|
|
|
|
**/
|
|
VOID
|
|
ProcessNotify (
|
|
IN PEI_CORE_INSTANCE *PrivateData,
|
|
IN UINTN NotifyType,
|
|
IN INTN InstallStartIndex,
|
|
IN INTN InstallStopIndex,
|
|
IN INTN NotifyStartIndex,
|
|
IN INTN NotifyStopIndex
|
|
)
|
|
{
|
|
INTN Index1;
|
|
INTN Index2;
|
|
EFI_GUID *SearchGuid;
|
|
EFI_GUID *CheckGuid;
|
|
EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor;
|
|
|
|
for (Index1 = NotifyStartIndex; Index1 < NotifyStopIndex; Index1++) {
|
|
if (NotifyType == EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK) {
|
|
NotifyDescriptor = PrivateData->PpiData.CallbackNotifyList.NotifyPtrs[Index1].Notify;
|
|
} else {
|
|
NotifyDescriptor = PrivateData->PpiData.DispatchNotifyList.NotifyPtrs[Index1].Notify;
|
|
}
|
|
|
|
CheckGuid = NotifyDescriptor->Guid;
|
|
|
|
for (Index2 = InstallStartIndex; Index2 < InstallStopIndex; Index2++) {
|
|
SearchGuid = PrivateData->PpiData.PpiList.PpiPtrs[Index2].Ppi->Guid;
|
|
//
|
|
// Don't use CompareGuid function here for performance reasons.
|
|
// Instead we compare the GUID as INT32 at a time and branch
|
|
// on the first failed comparison.
|
|
//
|
|
if ((((INT32 *)SearchGuid)[0] == ((INT32 *)CheckGuid)[0]) &&
|
|
(((INT32 *)SearchGuid)[1] == ((INT32 *)CheckGuid)[1]) &&
|
|
(((INT32 *)SearchGuid)[2] == ((INT32 *)CheckGuid)[2]) &&
|
|
(((INT32 *)SearchGuid)[3] == ((INT32 *)CheckGuid)[3]))
|
|
{
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"Notify: PPI Guid: %g, Peim notify entry point: %p\n",
|
|
SearchGuid,
|
|
NotifyDescriptor->Notify
|
|
));
|
|
NotifyDescriptor->Notify (
|
|
(EFI_PEI_SERVICES **)GetPeiServicesTablePointer (),
|
|
NotifyDescriptor,
|
|
(PrivateData->PpiData.PpiList.PpiPtrs[Index2].Ppi)->Ppi
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|