mirror of
https://github.com/CloverHackyColor/CloverBootloader.git
synced 2024-11-30 12:43:41 +01:00
833 lines
27 KiB
C
833 lines
27 KiB
C
|
/** @file
|
||
|
EFI PEI Core PPI services
|
||
|
|
||
|
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
|
||
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||
|
|
||
|
**/
|
||
|
|
||
|
#include "PeiMain.h"
|
||
|
|
||
|
/**
|
||
|
|
||
|
Migrate Pointer from the temporary memory to PEI installed memory.
|
||
|
|
||
|
@param Pointer Pointer to the Pointer needs to be converted.
|
||
|
@param TempBottom Base of old temporary memory
|
||
|
@param TempTop Top of old temporary memory
|
||
|
@param Offset Offset of new memory to old temporary memory.
|
||
|
@param OffsetPositive Positive flag of Offset value.
|
||
|
|
||
|
**/
|
||
|
VOID
|
||
|
ConvertPointer (
|
||
|
IN OUT VOID **Pointer,
|
||
|
IN UINTN TempBottom,
|
||
|
IN UINTN TempTop,
|
||
|
IN UINTN Offset,
|
||
|
IN BOOLEAN OffsetPositive
|
||
|
)
|
||
|
{
|
||
|
if (((UINTN) *Pointer < TempTop) &&
|
||
|
((UINTN) *Pointer >= TempBottom)) {
|
||
|
if (OffsetPositive) {
|
||
|
*Pointer = (VOID *) ((UINTN) *Pointer + Offset);
|
||
|
} else {
|
||
|
*Pointer = (VOID *) ((UINTN) *Pointer - Offset);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
|
||
|
Migrate Pointer in ranges of the temporary memory to PEI installed memory.
|
||
|
|
||
|
@param SecCoreData Points to a data structure containing SEC to PEI handoff data, such as the size
|
||
|
and location of temporary RAM, the stack location and the BFV location.
|
||
|
@param PrivateData Pointer to PeiCore's private data structure.
|
||
|
@param Pointer Pointer to the Pointer needs to be converted.
|
||
|
|
||
|
**/
|
||
|
VOID
|
||
|
ConvertPointerInRanges (
|
||
|
IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData,
|
||
|
IN PEI_CORE_INSTANCE *PrivateData,
|
||
|
IN OUT VOID **Pointer
|
||
|
)
|
||
|
{
|
||
|
UINT8 IndexHole;
|
||
|
|
||
|
if (PrivateData->MemoryPages.Size != 0) {
|
||
|
//
|
||
|
// Convert PPI pointer in old memory pages
|
||
|
// It needs to be done before Convert PPI pointer in old Heap
|
||
|
//
|
||
|
ConvertPointer (
|
||
|
Pointer,
|
||
|
(UINTN)PrivateData->MemoryPages.Base,
|
||
|
(UINTN)PrivateData->MemoryPages.Base + PrivateData->MemoryPages.Size,
|
||
|
PrivateData->MemoryPages.Offset,
|
||
|
PrivateData->MemoryPages.OffsetPositive
|
||
|
);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Convert PPI pointer in old Heap
|
||
|
//
|
||
|
ConvertPointer (
|
||
|
Pointer,
|
||
|
(UINTN)SecCoreData->PeiTemporaryRamBase,
|
||
|
(UINTN)SecCoreData->PeiTemporaryRamBase + SecCoreData->PeiTemporaryRamSize,
|
||
|
PrivateData->HeapOffset,
|
||
|
PrivateData->HeapOffsetPositive
|
||
|
);
|
||
|
|
||
|
//
|
||
|
// Convert PPI pointer in old Stack
|
||
|
//
|
||
|
ConvertPointer (
|
||
|
Pointer,
|
||
|
(UINTN)SecCoreData->StackBase,
|
||
|
(UINTN)SecCoreData->StackBase + SecCoreData->StackSize,
|
||
|
PrivateData->StackOffset,
|
||
|
PrivateData->StackOffsetPositive
|
||
|
);
|
||
|
|
||
|
//
|
||
|
// Convert PPI pointer in old TempRam Hole
|
||
|
//
|
||
|
for (IndexHole = 0; IndexHole < HOLE_MAX_NUMBER; IndexHole ++) {
|
||
|
if (PrivateData->HoleData[IndexHole].Size == 0) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
ConvertPointer (
|
||
|
Pointer,
|
||
|
(UINTN)PrivateData->HoleData[IndexHole].Base,
|
||
|
(UINTN)PrivateData->HoleData[IndexHole].Base + PrivateData->HoleData[IndexHole].Size,
|
||
|
PrivateData->HoleData[IndexHole].Offset,
|
||
|
PrivateData->HoleData[IndexHole].OffsetPositive
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
|
||
|
Migrate Single PPI Pointer from the temporary memory to PEI installed memory.
|
||
|
|
||
|
@param SecCoreData Points to a data structure containing SEC to PEI handoff data, such as the size
|
||
|
and location of temporary RAM, the stack location and the BFV location.
|
||
|
@param PrivateData Pointer to PeiCore's private data structure.
|
||
|
@param PpiPointer Pointer to Ppi
|
||
|
|
||
|
**/
|
||
|
VOID
|
||
|
ConvertSinglePpiPointer (
|
||
|
IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData,
|
||
|
IN PEI_CORE_INSTANCE *PrivateData,
|
||
|
IN PEI_PPI_LIST_POINTERS *PpiPointer
|
||
|
)
|
||
|
{
|
||
|
//
|
||
|
// 1. Convert the pointer to the PPI descriptor from the old TempRam
|
||
|
// to the relocated physical memory.
|
||
|
// It (for the pointer to the PPI descriptor) needs to be done before 2 (for
|
||
|
// the pointer to the GUID) and 3 (for the pointer to the PPI interface structure).
|
||
|
//
|
||
|
ConvertPointerInRanges (SecCoreData, PrivateData, &PpiPointer->Raw);
|
||
|
//
|
||
|
// 2. Convert the pointer to the GUID in the PPI or NOTIFY descriptor
|
||
|
// from the old TempRam to the relocated physical memory.
|
||
|
//
|
||
|
ConvertPointerInRanges (SecCoreData, PrivateData, (VOID **) &PpiPointer->Ppi->Guid);
|
||
|
//
|
||
|
// 3. Convert the pointer to the PPI interface structure in the PPI descriptor
|
||
|
// from the old TempRam to the relocated physical memory.
|
||
|
//
|
||
|
ConvertPointerInRanges (SecCoreData, PrivateData, (VOID **) &PpiPointer->Ppi->Ppi);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
|
||
|
Migrate PPI Pointers from the temporary memory to PEI installed memory.
|
||
|
|
||
|
@param SecCoreData Points to a data structure containing SEC to PEI handoff data, such as the size
|
||
|
and location of temporary RAM, the stack location and the BFV location.
|
||
|
@param PrivateData Pointer to PeiCore's private data structure.
|
||
|
|
||
|
**/
|
||
|
VOID
|
||
|
ConvertPpiPointers (
|
||
|
IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData,
|
||
|
IN PEI_CORE_INSTANCE *PrivateData
|
||
|
)
|
||
|
{
|
||
|
UINT8 Index;
|
||
|
|
||
|
//
|
||
|
// Convert normal PPIs.
|
||
|
//
|
||
|
for (Index = 0; Index < PrivateData->PpiData.PpiList.CurrentCount; Index++) {
|
||
|
ConvertSinglePpiPointer (
|
||
|
SecCoreData,
|
||
|
PrivateData,
|
||
|
&PrivateData->PpiData.PpiList.PpiPtrs[Index]
|
||
|
);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Convert Callback Notification PPIs.
|
||
|
//
|
||
|
for (Index = 0; Index < PrivateData->PpiData.CallbackNotifyList.CurrentCount; Index++) {
|
||
|
ConvertSinglePpiPointer (
|
||
|
SecCoreData,
|
||
|
PrivateData,
|
||
|
&PrivateData->PpiData.CallbackNotifyList.NotifyPtrs[Index]
|
||
|
);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Convert Dispatch Notification PPIs.
|
||
|
//
|
||
|
for (Index = 0; Index < PrivateData->PpiData.DispatchNotifyList.CurrentCount; Index++) {
|
||
|
ConvertSinglePpiPointer (
|
||
|
SecCoreData,
|
||
|
PrivateData,
|
||
|
&PrivateData->PpiData.DispatchNotifyList.NotifyPtrs[Index]
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
|
||
|
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;
|
||
|
VOID *TempPtr;
|
||
|
|
||
|
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((EFI_D_ERROR, "ERROR -> InstallPpi: %g %p\n", PpiList->Guid, PpiList->Ppi));
|
||
|
return EFI_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
if (Index >= PpiListPointer->MaxCount) {
|
||
|
//
|
||
|
// Run out of room, grow the buffer.
|
||
|
//
|
||
|
TempPtr = AllocateZeroPool (
|
||
|
sizeof (PEI_PPI_LIST_POINTERS) * (PpiListPointer->MaxCount + PPI_GROWTH_STEP)
|
||
|
);
|
||
|
ASSERT (TempPtr != NULL);
|
||
|
CopyMem (
|
||
|
TempPtr,
|
||
|
PpiListPointer->PpiPtrs,
|
||
|
sizeof (PEI_PPI_LIST_POINTERS) * PpiListPointer->MaxCount
|
||
|
);
|
||
|
PpiListPointer->PpiPtrs = TempPtr;
|
||
|
PpiListPointer->MaxCount = PpiListPointer->MaxCount + PPI_GROWTH_STEP;
|
||
|
}
|
||
|
|
||
|
DEBUG((EFI_D_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
|
||
|
PeiInstallPpi (
|
||
|
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
|
||
|
PeiReInstallPpi (
|
||
|
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((EFI_D_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
|
||
|
PeiLocatePpi (
|
||
|
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;
|
||
|
VOID *TempPtr;
|
||
|
|
||
|
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, grow the buffer.
|
||
|
//
|
||
|
TempPtr = AllocateZeroPool (
|
||
|
sizeof (PEI_PPI_LIST_POINTERS) * (CallbackNotifyListPointer->MaxCount + CALLBACK_NOTIFY_GROWTH_STEP)
|
||
|
);
|
||
|
ASSERT (TempPtr != NULL);
|
||
|
CopyMem (
|
||
|
TempPtr,
|
||
|
CallbackNotifyListPointer->NotifyPtrs,
|
||
|
sizeof (PEI_PPI_LIST_POINTERS) * CallbackNotifyListPointer->MaxCount
|
||
|
);
|
||
|
CallbackNotifyListPointer->NotifyPtrs = TempPtr;
|
||
|
CallbackNotifyListPointer->MaxCount = CallbackNotifyListPointer->MaxCount + CALLBACK_NOTIFY_GROWTH_STEP;
|
||
|
}
|
||
|
CallbackNotifyListPointer->NotifyPtrs[CallbackNotifyIndex].Notify = (EFI_PEI_NOTIFY_DESCRIPTOR *) NotifyList;
|
||
|
CallbackNotifyIndex++;
|
||
|
CallbackNotifyListPointer->CurrentCount++;
|
||
|
} else {
|
||
|
if (DispatchNotifyIndex >= DispatchNotifyListPointer->MaxCount) {
|
||
|
//
|
||
|
// Run out of room, grow the buffer.
|
||
|
//
|
||
|
TempPtr = AllocateZeroPool (
|
||
|
sizeof (PEI_PPI_LIST_POINTERS) * (DispatchNotifyListPointer->MaxCount + DISPATCH_NOTIFY_GROWTH_STEP)
|
||
|
);
|
||
|
ASSERT (TempPtr != NULL);
|
||
|
CopyMem (
|
||
|
TempPtr,
|
||
|
DispatchNotifyListPointer->NotifyPtrs,
|
||
|
sizeof (PEI_PPI_LIST_POINTERS) * DispatchNotifyListPointer->MaxCount
|
||
|
);
|
||
|
DispatchNotifyListPointer->NotifyPtrs = TempPtr;
|
||
|
DispatchNotifyListPointer->MaxCount = DispatchNotifyListPointer->MaxCount + DISPATCH_NOTIFY_GROWTH_STEP;
|
||
|
}
|
||
|
DispatchNotifyListPointer->NotifyPtrs[DispatchNotifyIndex].Notify = (EFI_PEI_NOTIFY_DESCRIPTOR *) NotifyList;
|
||
|
DispatchNotifyIndex++;
|
||
|
DispatchNotifyListPointer->CurrentCount++;
|
||
|
}
|
||
|
|
||
|
DEBUG((EFI_D_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
|
||
|
PeiNotifyPpi (
|
||
|
IN CONST EFI_PEI_SERVICES **PeiServices,
|
||
|
IN CONST EFI_PEI_NOTIFY_DESCRIPTOR *NotifyList
|
||
|
)
|
||
|
{
|
||
|
return InternalPeiNotifyPpi (PeiServices, NotifyList, FALSE);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
|
||
|
Process the Notify List at dispatch level.
|
||
|
|
||
|
@param PrivateData PeiCore's private data structure.
|
||
|
|
||
|
**/
|
||
|
VOID
|
||
|
ProcessDispatchNotifyList (
|
||
|
IN PEI_CORE_INSTANCE *PrivateData
|
||
|
)
|
||
|
{
|
||
|
UINTN TempValue;
|
||
|
|
||
|
while (TRUE) {
|
||
|
//
|
||
|
// Check if the PEIM that was just dispatched resulted in any
|
||
|
// Notifies getting installed. If so, go process any dispatch
|
||
|
// level Notifies that match the previouly installed PPIs.
|
||
|
// Use "while" instead of "if" since ProcessNotify can modify
|
||
|
// DispatchNotifyList.CurrentCount (with NotifyPpi) so we have
|
||
|
// to iterate until the same.
|
||
|
//
|
||
|
while (PrivateData->PpiData.DispatchNotifyList.LastDispatchedCount != PrivateData->PpiData.DispatchNotifyList.CurrentCount) {
|
||
|
TempValue = PrivateData->PpiData.DispatchNotifyList.CurrentCount;
|
||
|
ProcessNotify (
|
||
|
PrivateData,
|
||
|
EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH,
|
||
|
0,
|
||
|
PrivateData->PpiData.PpiList.LastDispatchedCount,
|
||
|
PrivateData->PpiData.DispatchNotifyList.LastDispatchedCount,
|
||
|
PrivateData->PpiData.DispatchNotifyList.CurrentCount
|
||
|
);
|
||
|
PrivateData->PpiData.DispatchNotifyList.LastDispatchedCount = TempValue;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Check if the PEIM that was just dispatched resulted in any
|
||
|
// PPIs getting installed. If so, go process any dispatch
|
||
|
// level Notifies that match the installed PPIs.
|
||
|
// Use "while" instead of "if" since ProcessNotify can modify
|
||
|
// PpiList.CurrentCount (with InstallPpi) so we have to iterate
|
||
|
// until the same.
|
||
|
//
|
||
|
while (PrivateData->PpiData.PpiList.LastDispatchedCount != PrivateData->PpiData.PpiList.CurrentCount) {
|
||
|
TempValue = PrivateData->PpiData.PpiList.CurrentCount;
|
||
|
ProcessNotify (
|
||
|
PrivateData,
|
||
|
EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH,
|
||
|
PrivateData->PpiData.PpiList.LastDispatchedCount,
|
||
|
PrivateData->PpiData.PpiList.CurrentCount,
|
||
|
0,
|
||
|
PrivateData->PpiData.DispatchNotifyList.LastDispatchedCount
|
||
|
);
|
||
|
PrivateData->PpiData.PpiList.LastDispatchedCount = TempValue;
|
||
|
}
|
||
|
|
||
|
if (PrivateData->PpiData.DispatchNotifyList.LastDispatchedCount == PrivateData->PpiData.DispatchNotifyList.CurrentCount) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
|
||
|
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 ((EFI_D_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
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Process PpiList from SEC phase.
|
||
|
|
||
|
@param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
|
||
|
@param PpiList Points to a list of one or more PPI descriptors to be installed initially by the PEI core.
|
||
|
These PPI's will be installed and/or immediately signaled if they are notification type.
|
||
|
|
||
|
**/
|
||
|
VOID
|
||
|
ProcessPpiListFromSec (
|
||
|
IN CONST EFI_PEI_SERVICES **PeiServices,
|
||
|
IN CONST EFI_PEI_PPI_DESCRIPTOR *PpiList
|
||
|
)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
EFI_SEC_HOB_DATA_PPI *SecHobDataPpi;
|
||
|
EFI_HOB_GENERIC_HEADER *SecHobList;
|
||
|
|
||
|
for (;;) {
|
||
|
if ((PpiList->Flags & EFI_PEI_PPI_DESCRIPTOR_NOTIFY_TYPES) != 0) {
|
||
|
//
|
||
|
// It is a notification PPI.
|
||
|
//
|
||
|
Status = InternalPeiNotifyPpi (PeiServices, (CONST EFI_PEI_NOTIFY_DESCRIPTOR *) PpiList, TRUE);
|
||
|
ASSERT_EFI_ERROR (Status);
|
||
|
} else {
|
||
|
//
|
||
|
// It is a normal PPI.
|
||
|
//
|
||
|
Status = InternalPeiInstallPpi (PeiServices, PpiList, TRUE);
|
||
|
ASSERT_EFI_ERROR (Status);
|
||
|
}
|
||
|
|
||
|
if ((PpiList->Flags & EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) == EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) {
|
||
|
//
|
||
|
// Continue until the end of the PPI List.
|
||
|
//
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
PpiList++;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If the EFI_SEC_HOB_DATA_PPI is in the list of PPIs passed to the PEI entry point,
|
||
|
// the PEI Foundation will call the GetHobs() member function and install all HOBs
|
||
|
// returned into the HOB list. It does this after installing all PPIs passed from SEC
|
||
|
// into the PPI database and before dispatching any PEIMs.
|
||
|
//
|
||
|
Status = PeiLocatePpi (PeiServices, &gEfiSecHobDataPpiGuid, 0, NULL, (VOID **) &SecHobDataPpi);
|
||
|
if (!EFI_ERROR (Status)) {
|
||
|
Status = SecHobDataPpi->GetHobs (SecHobDataPpi, &SecHobList);
|
||
|
if (!EFI_ERROR (Status)) {
|
||
|
Status = PeiInstallSecHobData (PeiServices, SecHobList);
|
||
|
ASSERT_EFI_ERROR (Status);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|