/** @file Copyright (c) 2006, 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 VOID InitializePpiServices ( IN PEI_CORE_INSTANCE *PrivateData, 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 --*/ { if (OldCoreData == NULL) { PrivateData->PpiData.NotifyListEnd = FixedPcdGet32 (PcdPeiCoreMaxPpiSupported)-1; PrivateData->PpiData.DispatchListEnd = FixedPcdGet32 (PcdPeiCoreMaxPpiSupported)-1; PrivateData->PpiData.LastDispatchedNotify = FixedPcdGet32 (PcdPeiCoreMaxPpiSupported)-1; } return; } VOID ConvertPpiPointers ( IN CONST EFI_PEI_SERVICES **PeiServices, IN UINTN OldCheckingBottom, IN UINTN OldCheckingTop, IN EFI_HOB_HANDOFF_INFO_TABLE *NewHandOffHob ) /*++ Routine Description: Migrate the Hob list from the CAR stack to PEI installed memory. Arguments: PeiServices - The PEI core services table. OldCheckingBottom - The old checking bottom. OldCheckingTop - The old checking top. NewHandOffHob - The new handoff HOB list. Returns: --*/ { PEI_CORE_INSTANCE *PrivateData; UINT8 Index; PEI_PPI_LIST_POINTERS *PpiPointer; UINTN Fixup; PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS(PeiServices); Fixup = (UINTN)NewHandOffHob - OldCheckingBottom; for (Index = 0; Index < FixedPcdGet32 (PcdPeiCoreMaxPpiSupported); Index++) { if (Index < PrivateData->PpiData.PpiListEnd || Index > PrivateData->PpiData.NotifyListEnd) { PpiPointer = &PrivateData->PpiData.PpiListPtrs[Index]; if (((UINTN)PpiPointer->Raw < OldCheckingTop) && ((UINTN)PpiPointer->Raw >= OldCheckingBottom)) { // // 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 < OldCheckingTop) && ((UINTN)PpiPointer->Ppi->Guid >= OldCheckingBottom)) { // // 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 < OldCheckingTop && (UINTN)PpiPointer->Ppi->Ppi >= OldCheckingBottom) { // // 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 CONST EFI_PEI_SERVICES **PeiServices, IN CONST 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; DEBUG((EFI_D_ERROR, "ERROR -> InstallPpi: %g %x\n", PpiList->Guid, PpiList->Ppi)); return EFI_INVALID_PARAMETER; } DEBUG((EFI_D_INFO, "Install PPI: %g\n", PpiList->Guid)); PrivateData->PpiData.PpiListPtrs[Index].Ppi = (EFI_PEI_PPI_DESCRIPTOR*) 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 ( PrivateData, EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK, LastCallbackInstall, PrivateData->PpiData.PpiListEnd, PrivateData->PpiData.DispatchListEnd, PrivateData->PpiData.NotifyListEnd ); return EFI_SUCCESS; } EFI_STATUS EFIAPI PeiReInstallPpi ( IN CONST EFI_PEI_SERVICES **PeiServices, IN CONST EFI_PEI_PPI_DESCRIPTOR *OldPpi, IN CONST 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. // DEBUG((EFI_D_INFO, "Reinstall PPI: %g\n", NewPpi->Guid)); PrivateData->PpiData.PpiListPtrs[Index].Ppi = (EFI_PEI_PPI_DESCRIPTOR *) NewPpi; // // Dispatch any callback level notifies for the newly installed PPI. // DispatchNotify ( PrivateData, EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK, Index, Index+1, PrivateData->PpiData.DispatchListEnd, PrivateData->PpiData.NotifyListEnd ); return EFI_SUCCESS; } 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 ) /*++ 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 CONST EFI_PEI_SERVICES **PeiServices, IN CONST 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; DEBUG((EFI_D_ERROR, "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 = (EFI_PEI_NOTIFY_DESCRIPTOR *) NotifyList; PrivateData->PpiData.NotifyListEnd--; DEBUG((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 ( PrivateData, EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK, 0, PrivateData->PpiData.PpiListEnd, LastCallbackNotify, PrivateData->PpiData.NotifyListEnd ); return EFI_SUCCESS; } VOID ProcessNotifyList ( IN PEI_CORE_INSTANCE *PrivateData ) /*++ Routine Description: Process the Notify List at dispatch level. Arguments: PeiServices - Pointer to the PEI Service Table Returns: --*/ { INTN 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 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 ( PrivateData, 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 ( PrivateData, EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH, PrivateData->PpiData.LastDispatchedInstall, PrivateData->PpiData.PpiListEnd, FixedPcdGet32 (PcdPeiCoreMaxPpiSupported)-1, PrivateData->PpiData.DispatchListEnd ); PrivateData->PpiData.LastDispatchedInstall = TempValue; } if (PrivateData->PpiData.LastDispatchedNotify == PrivateData->PpiData.DispatchListEnd) { break; } } return; } VOID DispatchNotify ( IN PEI_CORE_INSTANCE *PrivateData, 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 --*/ { INTN Index1; INTN Index2; EFI_GUID *SearchGuid; EFI_GUID *CheckGuid; EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor; // // 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])) { DEBUG ((EFI_D_INFO, "Notify: PPI Guid: %g, Peim notify entry point: %x\n", SearchGuid, NotifyDescriptor->Notify )); NotifyDescriptor->Notify ( GetPeiServicesTablePointer (), NotifyDescriptor, (PrivateData->PpiData.PpiListPtrs[Index2].Ppi)->Ppi ); } } } return; }