| /** @file | |
| Locate handle functions | |
| Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR> | |
| 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. | |
| **/ | |
| #include "PiSmmCore.h" | |
| // | |
| // ProtocolRequest - Last LocateHandle request ID | |
| // | |
| UINTN mEfiLocateHandleRequest = 0; | |
| // | |
| // Internal prototypes | |
| // | |
| typedef struct { | |
| EFI_GUID *Protocol; | |
| VOID *SearchKey; | |
| LIST_ENTRY *Position; | |
| PROTOCOL_ENTRY *ProtEntry; | |
| } LOCATE_POSITION; | |
| typedef | |
| IHANDLE * | |
| (* CORE_GET_NEXT) ( | |
| IN OUT LOCATE_POSITION *Position, | |
| OUT VOID **Interface | |
| ); | |
| /** | |
| Routine to get the next Handle, when you are searching for all handles. | |
| @param Position Information about which Handle to seach for. | |
| @param Interface Return the interface structure for the matching | |
| protocol. | |
| @return An pointer to IHANDLE if the next Position is not the end of the list. | |
| Otherwise,NULL is returned. | |
| **/ | |
| IHANDLE * | |
| SmmGetNextLocateAllHandles ( | |
| IN OUT LOCATE_POSITION *Position, | |
| OUT VOID **Interface | |
| ) | |
| { | |
| IHANDLE *Handle; | |
| // | |
| // Next handle | |
| // | |
| Position->Position = Position->Position->ForwardLink; | |
| // | |
| // If not at the end of the list, get the handle | |
| // | |
| Handle = NULL; | |
| *Interface = NULL; | |
| if (Position->Position != &gHandleList) { | |
| Handle = CR (Position->Position, IHANDLE, AllHandles, EFI_HANDLE_SIGNATURE); | |
| } | |
| return Handle; | |
| } | |
| /** | |
| Routine to get the next Handle, when you are searching for register protocol | |
| notifies. | |
| @param Position Information about which Handle to seach for. | |
| @param Interface Return the interface structure for the matching | |
| protocol. | |
| @return An pointer to IHANDLE if the next Position is not the end of the list. | |
| Otherwise,NULL is returned. | |
| **/ | |
| IHANDLE * | |
| SmmGetNextLocateByRegisterNotify ( | |
| IN OUT LOCATE_POSITION *Position, | |
| OUT VOID **Interface | |
| ) | |
| { | |
| IHANDLE *Handle; | |
| PROTOCOL_NOTIFY *ProtNotify; | |
| PROTOCOL_INTERFACE *Prot; | |
| LIST_ENTRY *Link; | |
| Handle = NULL; | |
| *Interface = NULL; | |
| ProtNotify = Position->SearchKey; | |
| // | |
| // If this is the first request, get the next handle | |
| // | |
| if (ProtNotify != NULL) { | |
| ASSERT(ProtNotify->Signature == PROTOCOL_NOTIFY_SIGNATURE); | |
| Position->SearchKey = NULL; | |
| // | |
| // If not at the end of the list, get the next handle | |
| // | |
| Link = ProtNotify->Position->ForwardLink; | |
| if (Link != &ProtNotify->Protocol->Protocols) { | |
| Prot = CR (Link, PROTOCOL_INTERFACE, ByProtocol, PROTOCOL_INTERFACE_SIGNATURE); | |
| Handle = Prot->Handle; | |
| *Interface = Prot->Interface; | |
| } | |
| } | |
| return Handle; | |
| } | |
| /** | |
| Routine to get the next Handle, when you are searching for a given protocol. | |
| @param Position Information about which Handle to seach for. | |
| @param Interface Return the interface structure for the matching | |
| protocol. | |
| @return An pointer to IHANDLE if the next Position is not the end of the list. | |
| Otherwise,NULL is returned. | |
| **/ | |
| IHANDLE * | |
| SmmGetNextLocateByProtocol ( | |
| IN OUT LOCATE_POSITION *Position, | |
| OUT VOID **Interface | |
| ) | |
| { | |
| IHANDLE *Handle; | |
| LIST_ENTRY *Link; | |
| PROTOCOL_INTERFACE *Prot; | |
| Handle = NULL; | |
| *Interface = NULL; | |
| for (; ;) { | |
| // | |
| // Next entry | |
| // | |
| Link = Position->Position->ForwardLink; | |
| Position->Position = Link; | |
| // | |
| // If not at the end, return the handle | |
| // | |
| if (Link == &Position->ProtEntry->Protocols) { | |
| Handle = NULL; | |
| break; | |
| } | |
| // | |
| // Get the handle | |
| // | |
| Prot = CR(Link, PROTOCOL_INTERFACE, ByProtocol, PROTOCOL_INTERFACE_SIGNATURE); | |
| Handle = Prot->Handle; | |
| *Interface = Prot->Interface; | |
| // | |
| // If this handle has not been returned this request, then | |
| // return it now | |
| // | |
| if (Handle->LocateRequest != mEfiLocateHandleRequest) { | |
| Handle->LocateRequest = mEfiLocateHandleRequest; | |
| break; | |
| } | |
| } | |
| return Handle; | |
| } | |
| /** | |
| Return the first Protocol Interface that matches the Protocol GUID. If | |
| Registration is pasased in return a Protocol Instance that was just add | |
| to the system. If Retistration is NULL return the first Protocol Interface | |
| you find. | |
| @param Protocol The protocol to search for | |
| @param Registration Optional Registration Key returned from | |
| RegisterProtocolNotify() | |
| @param Interface Return the Protocol interface (instance). | |
| @retval EFI_SUCCESS If a valid Interface is returned | |
| @retval EFI_INVALID_PARAMETER Invalid parameter | |
| @retval EFI_NOT_FOUND Protocol interface not found | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| SmmLocateProtocol ( | |
| IN EFI_GUID *Protocol, | |
| IN VOID *Registration OPTIONAL, | |
| OUT VOID **Interface | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| LOCATE_POSITION Position; | |
| PROTOCOL_NOTIFY *ProtNotify; | |
| IHANDLE *Handle; | |
| if ((Interface == NULL) || (Protocol == NULL)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| *Interface = NULL; | |
| Status = EFI_SUCCESS; | |
| // | |
| // Set initial position | |
| // | |
| Position.Protocol = Protocol; | |
| Position.SearchKey = Registration; | |
| Position.Position = &gHandleList; | |
| mEfiLocateHandleRequest += 1; | |
| if (Registration == NULL) { | |
| // | |
| // Look up the protocol entry and set the head pointer | |
| // | |
| Position.ProtEntry = SmmFindProtocolEntry (Protocol, FALSE); | |
| if (Position.ProtEntry == NULL) { | |
| return EFI_NOT_FOUND; | |
| } | |
| Position.Position = &Position.ProtEntry->Protocols; | |
| Handle = SmmGetNextLocateByProtocol (&Position, Interface); | |
| } else { | |
| Handle = SmmGetNextLocateByRegisterNotify (&Position, Interface); | |
| } | |
| if (Handle == NULL) { | |
| Status = EFI_NOT_FOUND; | |
| } else if (Registration != NULL) { | |
| // | |
| // If this is a search by register notify and a handle was | |
| // returned, update the register notification position | |
| // | |
| ProtNotify = Registration; | |
| ProtNotify->Position = ProtNotify->Position->ForwardLink; | |
| } | |
| return Status; | |
| } | |
| /** | |
| Locates the requested handle(s) and returns them in Buffer. | |
| @param SearchType The type of search to perform to locate the | |
| handles | |
| @param Protocol The protocol to search for | |
| @param SearchKey Dependant on SearchType | |
| @param BufferSize On input the size of Buffer. On output the | |
| size of data returned. | |
| @param Buffer The buffer to return the results in | |
| @retval EFI_BUFFER_TOO_SMALL Buffer too small, required buffer size is | |
| returned in BufferSize. | |
| @retval EFI_INVALID_PARAMETER Invalid parameter | |
| @retval EFI_SUCCESS Successfully found the requested handle(s) and | |
| returns them in Buffer. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| SmmLocateHandle ( | |
| IN EFI_LOCATE_SEARCH_TYPE SearchType, | |
| IN EFI_GUID *Protocol OPTIONAL, | |
| IN VOID *SearchKey OPTIONAL, | |
| IN OUT UINTN *BufferSize, | |
| OUT EFI_HANDLE *Buffer | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| LOCATE_POSITION Position; | |
| PROTOCOL_NOTIFY *ProtNotify; | |
| CORE_GET_NEXT GetNext; | |
| UINTN ResultSize; | |
| IHANDLE *Handle; | |
| IHANDLE **ResultBuffer; | |
| VOID *Interface; | |
| if (BufferSize == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if ((*BufferSize > 0) && (Buffer == NULL)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| GetNext = NULL; | |
| // | |
| // Set initial position | |
| // | |
| Position.Protocol = Protocol; | |
| Position.SearchKey = SearchKey; | |
| Position.Position = &gHandleList; | |
| ResultSize = 0; | |
| ResultBuffer = (IHANDLE **) Buffer; | |
| Status = EFI_SUCCESS; | |
| // | |
| // Get the search function based on type | |
| // | |
| switch (SearchType) { | |
| case AllHandles: | |
| GetNext = SmmGetNextLocateAllHandles; | |
| break; | |
| case ByRegisterNotify: | |
| GetNext = SmmGetNextLocateByRegisterNotify; | |
| // | |
| // Must have SearchKey for locate ByRegisterNotify | |
| // | |
| if (SearchKey == NULL) { | |
| Status = EFI_INVALID_PARAMETER; | |
| } | |
| break; | |
| case ByProtocol: | |
| GetNext = SmmGetNextLocateByProtocol; | |
| if (Protocol == NULL) { | |
| Status = EFI_INVALID_PARAMETER; | |
| break; | |
| } | |
| // | |
| // Look up the protocol entry and set the head pointer | |
| // | |
| Position.ProtEntry = SmmFindProtocolEntry (Protocol, FALSE); | |
| if (Position.ProtEntry == NULL) { | |
| Status = EFI_NOT_FOUND; | |
| break; | |
| } | |
| Position.Position = &Position.ProtEntry->Protocols; | |
| break; | |
| default: | |
| Status = EFI_INVALID_PARAMETER; | |
| break; | |
| } | |
| if (EFI_ERROR(Status)) { | |
| return Status; | |
| } | |
| // | |
| // Enumerate out the matching handles | |
| // | |
| mEfiLocateHandleRequest += 1; | |
| for (; ;) { | |
| // | |
| // Get the next handle. If no more handles, stop | |
| // | |
| Handle = GetNext (&Position, &Interface); | |
| if (NULL == Handle) { | |
| break; | |
| } | |
| // | |
| // Increase the resulting buffer size, and if this handle | |
| // fits return it | |
| // | |
| ResultSize += sizeof(Handle); | |
| if (ResultSize <= *BufferSize) { | |
| *ResultBuffer = Handle; | |
| ResultBuffer += 1; | |
| } | |
| } | |
| // | |
| // If the result is a zero length buffer, then there were no | |
| // matching handles | |
| // | |
| if (ResultSize == 0) { | |
| Status = EFI_NOT_FOUND; | |
| } else { | |
| // | |
| // Return the resulting buffer size. If it's larger than what | |
| // was passed, then set the error code | |
| // | |
| if (ResultSize > *BufferSize) { | |
| Status = EFI_BUFFER_TOO_SMALL; | |
| } | |
| *BufferSize = ResultSize; | |
| if (SearchType == ByRegisterNotify && !EFI_ERROR(Status)) { | |
| ASSERT (SearchKey != NULL); | |
| // | |
| // If this is a search by register notify and a handle was | |
| // returned, update the register notification position | |
| // | |
| ProtNotify = SearchKey; | |
| ProtNotify->Position = ProtNotify->Position->ForwardLink; | |
| } | |
| } | |
| return Status; | |
| } | |
| /** | |
| Function returns an array of handles that support the requested protocol | |
| in a buffer allocated from pool. This is a version of SmmLocateHandle() | |
| that allocates a buffer for the caller. | |
| @param SearchType Specifies which handle(s) are to be returned. | |
| @param Protocol Provides the protocol to search by. This | |
| parameter is only valid for SearchType | |
| ByProtocol. | |
| @param SearchKey Supplies the search key depending on the | |
| SearchType. | |
| @param NumberHandles The number of handles returned in Buffer. | |
| @param Buffer A pointer to the buffer to return the requested | |
| array of handles that support Protocol. | |
| @retval EFI_SUCCESS The result array of handles was returned. | |
| @retval EFI_NOT_FOUND No handles match the search. | |
| @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the | |
| matching results. | |
| @retval EFI_INVALID_PARAMETER One or more parameters are not valid. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| SmmLocateHandleBuffer ( | |
| IN EFI_LOCATE_SEARCH_TYPE SearchType, | |
| IN EFI_GUID *Protocol OPTIONAL, | |
| IN VOID *SearchKey OPTIONAL, | |
| IN OUT UINTN *NumberHandles, | |
| OUT EFI_HANDLE **Buffer | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| UINTN BufferSize; | |
| if (NumberHandles == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if (Buffer == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| BufferSize = 0; | |
| *NumberHandles = 0; | |
| *Buffer = NULL; | |
| Status = SmmLocateHandle ( | |
| SearchType, | |
| Protocol, | |
| SearchKey, | |
| &BufferSize, | |
| *Buffer | |
| ); | |
| // | |
| // LocateHandleBuffer() returns incorrect status code if SearchType is | |
| // invalid. | |
| // | |
| // Add code to correctly handle expected errors from SmmLocateHandle(). | |
| // | |
| if (EFI_ERROR(Status) && Status != EFI_BUFFER_TOO_SMALL) { | |
| if (Status != EFI_INVALID_PARAMETER) { | |
| Status = EFI_NOT_FOUND; | |
| } | |
| return Status; | |
| } | |
| *Buffer = AllocatePool (BufferSize); | |
| if (*Buffer == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| Status = SmmLocateHandle ( | |
| SearchType, | |
| Protocol, | |
| SearchKey, | |
| &BufferSize, | |
| *Buffer | |
| ); | |
| *NumberHandles = BufferSize / sizeof(EFI_HANDLE); | |
| if (EFI_ERROR(Status)) { | |
| *NumberHandles = 0; | |
| } | |
| return Status; | |
| } |