summaryrefslogtreecommitdiff
path: root/EDK/Foundation/Core/Pei/Ppi/Ppi.c
diff options
context:
space:
mode:
Diffstat (limited to 'EDK/Foundation/Core/Pei/Ppi/Ppi.c')
-rw-r--r--EDK/Foundation/Core/Pei/Ppi/Ppi.c667
1 files changed, 667 insertions, 0 deletions
diff --git a/EDK/Foundation/Core/Pei/Ppi/Ppi.c b/EDK/Foundation/Core/Pei/Ppi/Ppi.c
new file mode 100644
index 0000000..ceb2ab2
--- /dev/null
+++ b/EDK/Foundation/Core/Pei/Ppi/Ppi.c
@@ -0,0 +1,667 @@
+/*++
+
+Copyright (c) 2004 - 2005, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+ Ppi.c
+
+Abstract:
+
+ EFI PEI Core PPI services
+
+Revision History
+
+--*/
+
+#include "Tiano.h"
+#include "PeiCore.h"
+#include "PeiLib.h"
+
+VOID
+InitializePpiServices (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN PEI_CORE_INSTANCE *OldCoreData
+ )
+/*++
+
+Routine Description:
+
+ Initialize PPI services.
+
+Arguments:
+
+ PeiServices - The PEI core services table.
+ OldCoreData - Pointer to the PEI Core data.
+ NULL if being run in non-permament memory mode.
+
+Returns:
+ Nothing
+
+--*/
+{
+ PEI_CORE_INSTANCE *PrivateData;
+
+ if (OldCoreData == NULL) {
+ PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS(PeiServices);
+
+ PrivateData->PpiData.NotifyListEnd = MAX_PPI_DESCRIPTORS-1;
+ PrivateData->PpiData.DispatchListEnd = MAX_PPI_DESCRIPTORS-1;
+ PrivateData->PpiData.LastDispatchedNotify = MAX_PPI_DESCRIPTORS-1;
+ }
+
+ return;
+}
+
+VOID
+ConvertPpiPointers (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_HOB_HANDOFF_INFO_TABLE *OldHandOffHob,
+ IN EFI_HOB_HANDOFF_INFO_TABLE *NewHandOffHob
+ )
+/*++
+
+Routine Description:
+
+ Convert PPI pointers after the Hob list was migrated from the CAR stack
+ to PEI installed memory.
+
+Arguments:
+
+ PeiServices - The PEI core services table.
+ OldHandOffHob - The old handoff HOB list.
+ NewHandOffHob - The new handoff HOB list.
+
+Returns:
+
+ None.
+
+--*/
+{
+ PEI_CORE_INSTANCE *PrivateData;
+ UINT8 Index;
+ PEI_PPI_LIST_POINTERS *PpiPointer;
+ UINTN Fixup;
+
+ PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS(PeiServices);
+
+ Fixup = (UINTN)NewHandOffHob - (UINTN)OldHandOffHob;
+
+ for (Index = 0; Index < MAX_PPI_DESCRIPTORS; Index++) {
+ if (Index < PrivateData->PpiData.PpiListEnd ||
+ Index > PrivateData->PpiData.NotifyListEnd) {
+ PpiPointer = &PrivateData->PpiData.PpiListPtrs[Index];
+
+ if (((UINTN)PpiPointer->Raw < (UINTN)OldHandOffHob->EfiFreeMemoryBottom) &&
+ ((UINTN)PpiPointer->Raw >= (UINTN)OldHandOffHob)) {
+ //
+ // Convert the pointer to the PEIM descriptor from the old HOB heap
+ // to the relocated HOB heap.
+ //
+ PpiPointer->Raw = (VOID *) ((UINTN)PpiPointer->Raw + Fixup);
+
+ //
+ // Only when the PEIM descriptor is in the old HOB should it be necessary
+ // to try to convert the pointers in the PEIM descriptor
+ //
+
+ if (((UINTN)PpiPointer->Ppi->Guid < (UINTN)OldHandOffHob->EfiFreeMemoryBottom) &&
+ ((UINTN)PpiPointer->Ppi->Guid >= (UINTN)OldHandOffHob)) {
+ //
+ // Convert the pointer to the GUID in the PPI or NOTIFY descriptor
+ // from the old HOB heap to the relocated HOB heap.
+ //
+ PpiPointer->Ppi->Guid = (VOID *) ((UINTN)PpiPointer->Ppi->Guid + Fixup);
+ }
+
+ //
+ // Assume that no code is located in the temporary memory, so the pointer to
+ // the notification function in the NOTIFY descriptor needs not be converted.
+ //
+ if (Index < PrivateData->PpiData.PpiListEnd &&
+ (UINTN)PpiPointer->Ppi->Ppi < (UINTN)OldHandOffHob->EfiFreeMemoryBottom &&
+ (UINTN)PpiPointer->Ppi->Ppi >= (UINTN)OldHandOffHob) {
+ //
+ // Convert the pointer to the PPI interface structure in the PPI descriptor
+ // from the old HOB heap to the relocated HOB heap.
+ //
+ PpiPointer->Ppi->Ppi = (VOID *) ((UINTN)PpiPointer->Ppi->Ppi+ Fixup);
+ }
+ }
+ }
+ }
+}
+
+
+EFI_STATUS
+EFIAPI
+PeiInstallPpi (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_PPI_DESCRIPTOR *PpiList
+ )
+/*++
+
+Routine Description:
+
+ Install PPI services.
+
+Arguments:
+
+ PeiServices - Pointer to the PEI Service Table
+ PpiList - Pointer to a list of PEI PPI Descriptors.
+
+Returns:
+
+ EFI_SUCCESS - if all PPIs in PpiList are successfully installed.
+ EFI_INVALID_PARAMETER - if PpiList is NULL pointer
+ EFI_INVALID_PARAMETER - if any PPI in PpiList is not valid
+ EFI_OUT_OF_RESOURCES - if there is no more memory resource to install PPI
+
+--*/
+{
+ PEI_CORE_INSTANCE *PrivateData;
+ INTN Index;
+ INTN LastCallbackInstall;
+
+
+ if (PpiList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS(PeiServices);
+
+ Index = PrivateData->PpiData.PpiListEnd;
+ LastCallbackInstall = 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 (;;) {
+ //
+ // Since PpiData is used for NotifyList and InstallList, max resource
+ // is reached if the Install reaches the NotifyList
+ //
+ if (Index == PrivateData->PpiData.NotifyListEnd + 1) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // 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) {
+ PrivateData->PpiData.PpiListEnd = LastCallbackInstall;
+ PEI_DEBUG((PeiServices, EFI_D_INFO, "ERROR -> InstallPpi: %g %x\n", PpiList->Guid, PpiList->Ppi));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PEI_DEBUG((PeiServices, EFI_D_INFO, "Install PPI: %g\n", PpiList->Guid));
+ PrivateData->PpiData.PpiListPtrs[Index].Ppi = PpiList;
+ PrivateData->PpiData.PpiListEnd++;
+
+ //
+ // Continue until the end of the PPI List.
+ //
+ if ((PpiList->Flags & EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) ==
+ EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) {
+ break;
+ }
+ PpiList++;
+ Index++;
+ }
+
+ //
+ // Dispatch any callback level notifies for newly installed PPIs.
+ //
+ DispatchNotify (
+ PeiServices,
+ EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
+ LastCallbackInstall,
+ PrivateData->PpiData.PpiListEnd,
+ PrivateData->PpiData.DispatchListEnd,
+ PrivateData->PpiData.NotifyListEnd
+ );
+
+
+ return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+EFIAPI
+PeiReInstallPpi (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_PPI_DESCRIPTOR *OldPpi,
+ IN EFI_PEI_PPI_DESCRIPTOR *NewPpi
+ )
+/*++
+
+Routine Description:
+
+ Re-Install PPI services.
+
+Arguments:
+
+ PeiServices - Pointer to the PEI Service Table
+ OldPpi - Pointer to the old PEI PPI Descriptors.
+ NewPpi - Pointer to the new PEI PPI Descriptors.
+
+Returns:
+
+ EFI_SUCCESS - if the operation was successful
+ EFI_INVALID_PARAMETER - if OldPpi or NewPpi is NULL
+ EFI_INVALID_PARAMETER - if NewPpi is not valid
+ EFI_NOT_FOUND - if the PPI was not in the database
+
+--*/
+{
+ PEI_CORE_INSTANCE *PrivateData;
+ INTN 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.PpiListEnd; Index++) {
+ if (OldPpi == PrivateData->PpiData.PpiListPtrs[Index].Ppi) {
+ break;
+ }
+ }
+ if (Index == PrivateData->PpiData.PpiListEnd) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Remove the old PPI from the database, add the new one.
+ //
+ PEI_DEBUG((PeiServices, EFI_D_INFO, "Reinstall PPI: %g\n", NewPpi->Guid));
+ PrivateData->PpiData.PpiListPtrs[Index].Ppi = NewPpi;
+
+ //
+ // Dispatch any callback level notifies for the newly installed PPI.
+ //
+ DispatchNotify (
+ PeiServices,
+ EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
+ Index,
+ Index+1,
+ PrivateData->PpiData.DispatchListEnd,
+ PrivateData->PpiData.NotifyListEnd
+ );
+
+
+ return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+EFIAPI
+PeiLocatePpi (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_GUID *Guid,
+ IN UINTN Instance,
+ IN OUT EFI_PEI_PPI_DESCRIPTOR **PpiDescriptor,
+ IN OUT VOID **Ppi
+ )
+/*++
+
+Routine Description:
+
+ Locate a given named PPI.
+
+Arguments:
+
+ PeiServices - Pointer to the PEI Service Table
+ Guid - Pointer to GUID of the PPI.
+ Instance - Instance Number to discover.
+ PpiDescriptor - Pointer to reference the found descriptor. If not NULL,
+ returns a pointer to the descriptor (includes flags, etc)
+ Ppi - Pointer to reference the found PPI
+
+Returns:
+
+ Status - EFI_SUCCESS if the PPI is in the database
+ EFI_NOT_FOUND if the PPI is not in the database
+--*/
+{
+ PEI_CORE_INSTANCE *PrivateData;
+ INTN 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.PpiListEnd; Index++) {
+ TempPtr = PrivateData->PpiData.PpiListPtrs[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;
+}
+
+
+EFI_STATUS
+EFIAPI
+PeiNotifyPpi (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyList
+ )
+/*++
+
+Routine Description:
+
+ Install a notification for a given PPI.
+
+Arguments:
+
+ PeiServices - Pointer to the PEI Service Table
+ NotifyList - Pointer to list of Descriptors to notify upon.
+
+Returns:
+
+ Status - EFI_SUCCESS if successful
+ EFI_OUT_OF_RESOURCES if no space in the database
+ EFI_INVALID_PARAMETER if not a good decriptor
+
+--*/
+{
+ PEI_CORE_INSTANCE *PrivateData;
+ INTN Index;
+ INTN NotifyIndex;
+ INTN LastCallbackNotify;
+ EFI_PEI_NOTIFY_DESCRIPTOR *NotifyPtr;
+ UINTN NotifyDispatchCount;
+
+
+ NotifyDispatchCount = 0;
+
+ if (NotifyList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS(PeiServices);
+
+ Index = PrivateData->PpiData.NotifyListEnd;
+ LastCallbackNotify = Index;
+
+ //
+ // 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 (;;) {
+ //
+ // Since PpiData is used for NotifyList and InstallList, max resource
+ // is reached if the Install reaches the PpiList
+ //
+ if (Index == PrivateData->PpiData.PpiListEnd - 1) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // If some of the PPI data is invalid restore original Notify PPI database value
+ //
+ if ((NotifyList->Flags & EFI_PEI_PPI_DESCRIPTOR_NOTIFY_TYPES) == 0) {
+ PrivateData->PpiData.NotifyListEnd = LastCallbackNotify;
+ PEI_DEBUG((PeiServices, EFI_D_INFO, "ERROR -> InstallNotify: %g %x\n", NotifyList->Guid, NotifyList->Notify));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((NotifyList->Flags & EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH) != 0) {
+ NotifyDispatchCount ++;
+ }
+
+ PrivateData->PpiData.PpiListPtrs[Index].Notify = NotifyList;
+
+ PrivateData->PpiData.NotifyListEnd--;
+ PEI_DEBUG((PeiServices, EFI_D_INFO, "Register PPI Notify: %g\n", NotifyList->Guid));
+ if ((NotifyList->Flags & EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) ==
+ EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) {
+ break;
+ }
+ //
+ // Go the next descriptor. Remember the NotifyList moves down.
+ //
+ NotifyList++;
+ Index--;
+ }
+
+ //
+ // If there is Dispatch Notify PPI installed put them on the bottom
+ //
+ if (NotifyDispatchCount > 0) {
+ for (NotifyIndex = LastCallbackNotify; NotifyIndex > PrivateData->PpiData.NotifyListEnd; NotifyIndex--) {
+ if ((PrivateData->PpiData.PpiListPtrs[NotifyIndex].Notify->Flags & EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH) != 0) {
+ NotifyPtr = PrivateData->PpiData.PpiListPtrs[NotifyIndex].Notify;
+
+ for (Index = NotifyIndex; Index < PrivateData->PpiData.DispatchListEnd; Index++){
+ PrivateData->PpiData.PpiListPtrs[Index].Notify = PrivateData->PpiData.PpiListPtrs[Index + 1].Notify;
+ }
+ PrivateData->PpiData.PpiListPtrs[Index].Notify = NotifyPtr;
+ PrivateData->PpiData.DispatchListEnd--;
+ }
+ }
+
+ LastCallbackNotify -= NotifyDispatchCount;
+ }
+
+ //
+ // Dispatch any callback level notifies for all previously installed PPIs.
+ //
+ DispatchNotify (
+ PeiServices,
+ EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
+ 0,
+ PrivateData->PpiData.PpiListEnd,
+ LastCallbackNotify,
+ PrivateData->PpiData.NotifyListEnd
+ );
+
+
+ return EFI_SUCCESS;
+}
+
+
+VOID
+ProcessNotifyList (
+ IN EFI_PEI_SERVICES **PeiServices
+ )
+/*++
+
+Routine Description:
+
+ Process the Notify List at dispatch level.
+
+Arguments:
+
+ PeiServices - Pointer to the PEI Service Table
+
+Returns:
+
+--*/
+
+{
+ PEI_CORE_INSTANCE *PrivateData;
+ INTN TempValue;
+
+ PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS(PeiServices);
+
+
+ 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 DispatchNotify can modify
+ // DispatchListEnd (with NotifyPpi) so we have to iterate until the same.
+ //
+ while (PrivateData->PpiData.LastDispatchedNotify != PrivateData->PpiData.DispatchListEnd) {
+ TempValue = PrivateData->PpiData.DispatchListEnd;
+ DispatchNotify (
+ PeiServices,
+ EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH,
+ 0,
+ PrivateData->PpiData.LastDispatchedInstall,
+ PrivateData->PpiData.LastDispatchedNotify,
+ PrivateData->PpiData.DispatchListEnd
+ );
+ PrivateData->PpiData.LastDispatchedNotify = 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 DispatchNotify can modify
+ // PpiListEnd (with InstallPpi) so we have to iterate until the same.
+ //
+ while (PrivateData->PpiData.LastDispatchedInstall != PrivateData->PpiData.PpiListEnd) {
+ TempValue = PrivateData->PpiData.PpiListEnd;
+ DispatchNotify (
+ PeiServices,
+ EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH,
+ PrivateData->PpiData.LastDispatchedInstall,
+ PrivateData->PpiData.PpiListEnd,
+ MAX_PPI_DESCRIPTORS-1,
+ PrivateData->PpiData.DispatchListEnd
+ );
+ PrivateData->PpiData.LastDispatchedInstall = TempValue;
+ }
+
+ if (PrivateData->PpiData.LastDispatchedNotify == PrivateData->PpiData.DispatchListEnd) {
+ break;
+ }
+ }
+ return;
+}
+
+VOID
+DispatchNotify (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN UINTN NotifyType,
+ IN INTN InstallStartIndex,
+ IN INTN InstallStopIndex,
+ IN INTN NotifyStartIndex,
+ IN INTN NotifyStopIndex
+ )
+/*++
+
+Routine Description:
+
+ Dispatch notifications.
+
+Arguments:
+
+ PeiServices - Pointer to the PEI Service Table
+ NotifyType - Type of notify to fire.
+ InstallStartIndex - Install Beginning index.
+ InstallStopIndex - Install Ending index.
+ NotifyStartIndex - Notify Beginning index.
+ NotifyStopIndex - Notify Ending index.
+
+Returns: None
+
+--*/
+
+{
+ PEI_CORE_INSTANCE *PrivateData;
+ INTN Index1;
+ INTN Index2;
+ EFI_GUID *SearchGuid;
+ EFI_GUID *CheckGuid;
+ EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor;
+
+ PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS(PeiServices);
+
+ //
+ // Remember that Installs moves up and Notifies moves down.
+ //
+ for (Index1 = NotifyStartIndex; Index1 > NotifyStopIndex; Index1--) {
+ NotifyDescriptor = PrivateData->PpiData.PpiListPtrs[Index1].Notify;
+
+ CheckGuid = NotifyDescriptor->Guid;
+
+ for (Index2 = InstallStartIndex; Index2 < InstallStopIndex; Index2++) {
+ SearchGuid = PrivateData->PpiData.PpiListPtrs[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])) {
+ PEI_DEBUG (
+ (
+ PeiServices,
+ EFI_D_INFO,
+ "Notify: PPI Guid: %g, Peim notify entry point: %x\n",
+ SearchGuid,
+ NotifyDescriptor->Notify
+ )
+ );
+ NotifyDescriptor->Notify (
+ PeiServices,
+ NotifyDescriptor,
+ (PrivateData->PpiData.PpiListPtrs[Index2].Ppi)->Ppi
+ );
+ }
+ }
+ }
+
+ return;
+}
+