| /** @file | |
| SMM handle & protocol handling. | |
| Copyright (c) 2009 - 2010, 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" | |
| // | |
| // mProtocolDatabase - A list of all protocols in the system. (simple list for now) | |
| // gHandleList - A list of all the handles in the system | |
| // | |
| LIST_ENTRY mProtocolDatabase = INITIALIZE_LIST_HEAD_VARIABLE (mProtocolDatabase); | |
| LIST_ENTRY gHandleList = INITIALIZE_LIST_HEAD_VARIABLE (gHandleList); | |
| /** | |
| Check whether a handle is a valid EFI_HANDLE | |
| @param UserHandle The handle to check | |
| @retval EFI_INVALID_PARAMETER The handle is NULL or not a valid EFI_HANDLE. | |
| @retval EFI_SUCCESS The handle is valid EFI_HANDLE. | |
| **/ | |
| EFI_STATUS | |
| SmmValidateHandle ( | |
| IN EFI_HANDLE UserHandle | |
| ) | |
| { | |
| IHANDLE *Handle; | |
| Handle = (IHANDLE *)UserHandle; | |
| if (Handle == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if (Handle->Signature != EFI_HANDLE_SIGNATURE) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Finds the protocol entry for the requested protocol. | |
| @param Protocol The ID of the protocol | |
| @param Create Create a new entry if not found | |
| @return Protocol entry | |
| **/ | |
| PROTOCOL_ENTRY * | |
| SmmFindProtocolEntry ( | |
| IN EFI_GUID *Protocol, | |
| IN BOOLEAN Create | |
| ) | |
| { | |
| LIST_ENTRY *Link; | |
| PROTOCOL_ENTRY *Item; | |
| PROTOCOL_ENTRY *ProtEntry; | |
| // | |
| // Search the database for the matching GUID | |
| // | |
| ProtEntry = NULL; | |
| for (Link = mProtocolDatabase.ForwardLink; | |
| Link != &mProtocolDatabase; | |
| Link = Link->ForwardLink) { | |
| Item = CR(Link, PROTOCOL_ENTRY, AllEntries, PROTOCOL_ENTRY_SIGNATURE); | |
| if (CompareGuid (&Item->ProtocolID, Protocol)) { | |
| // | |
| // This is the protocol entry | |
| // | |
| ProtEntry = Item; | |
| break; | |
| } | |
| } | |
| // | |
| // If the protocol entry was not found and Create is TRUE, then | |
| // allocate a new entry | |
| // | |
| if ((ProtEntry == NULL) && Create) { | |
| ProtEntry = AllocatePool (sizeof(PROTOCOL_ENTRY)); | |
| if (ProtEntry != NULL) { | |
| // | |
| // Initialize new protocol entry structure | |
| // | |
| ProtEntry->Signature = PROTOCOL_ENTRY_SIGNATURE; | |
| CopyGuid ((VOID *)&ProtEntry->ProtocolID, Protocol); | |
| InitializeListHead (&ProtEntry->Protocols); | |
| InitializeListHead (&ProtEntry->Notify); | |
| // | |
| // Add it to protocol database | |
| // | |
| InsertTailList (&mProtocolDatabase, &ProtEntry->AllEntries); | |
| } | |
| } | |
| return ProtEntry; | |
| } | |
| /** | |
| Finds the protocol instance for the requested handle and protocol. | |
| Note: This function doesn't do parameters checking, it's caller's responsibility | |
| to pass in valid parameters. | |
| @param Handle The handle to search the protocol on | |
| @param Protocol GUID of the protocol | |
| @param Interface The interface for the protocol being searched | |
| @return Protocol instance (NULL: Not found) | |
| **/ | |
| PROTOCOL_INTERFACE * | |
| SmmFindProtocolInterface ( | |
| IN IHANDLE *Handle, | |
| IN EFI_GUID *Protocol, | |
| IN VOID *Interface | |
| ) | |
| { | |
| PROTOCOL_INTERFACE *Prot; | |
| PROTOCOL_ENTRY *ProtEntry; | |
| LIST_ENTRY *Link; | |
| Prot = NULL; | |
| // | |
| // Lookup the protocol entry for this protocol ID | |
| // | |
| ProtEntry = SmmFindProtocolEntry (Protocol, FALSE); | |
| if (ProtEntry != NULL) { | |
| // | |
| // Look at each protocol interface for any matches | |
| // | |
| for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link=Link->ForwardLink) { | |
| // | |
| // If this protocol interface matches, remove it | |
| // | |
| Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE); | |
| if (Prot->Interface == Interface && Prot->Protocol == ProtEntry) { | |
| break; | |
| } | |
| Prot = NULL; | |
| } | |
| } | |
| return Prot; | |
| } | |
| /** | |
| Wrapper function to SmmInstallProtocolInterfaceNotify. This is the public API which | |
| Calls the private one which contains a BOOLEAN parameter for notifications | |
| @param UserHandle The handle to install the protocol handler on, | |
| or NULL if a new handle is to be allocated | |
| @param Protocol The protocol to add to the handle | |
| @param InterfaceType Indicates whether Interface is supplied in | |
| native form. | |
| @param Interface The interface for the protocol being added | |
| @return Status code | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| SmmInstallProtocolInterface ( | |
| IN OUT EFI_HANDLE *UserHandle, | |
| IN EFI_GUID *Protocol, | |
| IN EFI_INTERFACE_TYPE InterfaceType, | |
| IN VOID *Interface | |
| ) | |
| { | |
| return SmmInstallProtocolInterfaceNotify ( | |
| UserHandle, | |
| Protocol, | |
| InterfaceType, | |
| Interface, | |
| TRUE | |
| ); | |
| } | |
| /** | |
| Installs a protocol interface into the boot services environment. | |
| @param UserHandle The handle to install the protocol handler on, | |
| or NULL if a new handle is to be allocated | |
| @param Protocol The protocol to add to the handle | |
| @param InterfaceType Indicates whether Interface is supplied in | |
| native form. | |
| @param Interface The interface for the protocol being added | |
| @param Notify indicates whether notify the notification list | |
| for this protocol | |
| @retval EFI_INVALID_PARAMETER Invalid parameter | |
| @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate | |
| @retval EFI_SUCCESS Protocol interface successfully installed | |
| **/ | |
| EFI_STATUS | |
| SmmInstallProtocolInterfaceNotify ( | |
| IN OUT EFI_HANDLE *UserHandle, | |
| IN EFI_GUID *Protocol, | |
| IN EFI_INTERFACE_TYPE InterfaceType, | |
| IN VOID *Interface, | |
| IN BOOLEAN Notify | |
| ) | |
| { | |
| PROTOCOL_INTERFACE *Prot; | |
| PROTOCOL_ENTRY *ProtEntry; | |
| IHANDLE *Handle; | |
| EFI_STATUS Status; | |
| VOID *ExistingInterface; | |
| // | |
| // returns EFI_INVALID_PARAMETER if InterfaceType is invalid. | |
| // Also added check for invalid UserHandle and Protocol pointers. | |
| // | |
| if (UserHandle == NULL || Protocol == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if (InterfaceType != EFI_NATIVE_INTERFACE) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // Print debug message | |
| // | |
| DEBUG((DEBUG_LOAD | DEBUG_INFO, "SmmInstallProtocolInterface: %g %p\n", Protocol, Interface)); | |
| Status = EFI_OUT_OF_RESOURCES; | |
| Prot = NULL; | |
| Handle = NULL; | |
| if (*UserHandle != NULL) { | |
| Status = SmmHandleProtocol (*UserHandle, Protocol, (VOID **)&ExistingInterface); | |
| if (!EFI_ERROR (Status)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| } | |
| // | |
| // Lookup the Protocol Entry for the requested protocol | |
| // | |
| ProtEntry = SmmFindProtocolEntry (Protocol, TRUE); | |
| if (ProtEntry == NULL) { | |
| goto Done; | |
| } | |
| // | |
| // Allocate a new protocol interface structure | |
| // | |
| Prot = AllocateZeroPool (sizeof(PROTOCOL_INTERFACE)); | |
| if (Prot == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto Done; | |
| } | |
| // | |
| // If caller didn't supply a handle, allocate a new one | |
| // | |
| Handle = (IHANDLE *)*UserHandle; | |
| if (Handle == NULL) { | |
| Handle = AllocateZeroPool (sizeof(IHANDLE)); | |
| if (Handle == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto Done; | |
| } | |
| // | |
| // Initialize new handler structure | |
| // | |
| Handle->Signature = EFI_HANDLE_SIGNATURE; | |
| InitializeListHead (&Handle->Protocols); | |
| // | |
| // Add this handle to the list global list of all handles | |
| // in the system | |
| // | |
| InsertTailList (&gHandleList, &Handle->AllHandles); | |
| } | |
| Status = SmmValidateHandle (Handle); | |
| if (EFI_ERROR (Status)) { | |
| goto Done; | |
| } | |
| // | |
| // Each interface that is added must be unique | |
| // | |
| ASSERT (SmmFindProtocolInterface (Handle, Protocol, Interface) == NULL); | |
| // | |
| // Initialize the protocol interface structure | |
| // | |
| Prot->Signature = PROTOCOL_INTERFACE_SIGNATURE; | |
| Prot->Handle = Handle; | |
| Prot->Protocol = ProtEntry; | |
| Prot->Interface = Interface; | |
| // | |
| // Add this protocol interface to the head of the supported | |
| // protocol list for this handle | |
| // | |
| InsertHeadList (&Handle->Protocols, &Prot->Link); | |
| // | |
| // Add this protocol interface to the tail of the | |
| // protocol entry | |
| // | |
| InsertTailList (&ProtEntry->Protocols, &Prot->ByProtocol); | |
| // | |
| // Notify the notification list for this protocol | |
| // | |
| if (Notify) { | |
| SmmNotifyProtocol (Prot); | |
| } | |
| Status = EFI_SUCCESS; | |
| Done: | |
| if (!EFI_ERROR (Status)) { | |
| // | |
| // Return the new handle back to the caller | |
| // | |
| *UserHandle = Handle; | |
| } else { | |
| // | |
| // There was an error, clean up | |
| // | |
| if (Prot != NULL) { | |
| FreePool (Prot); | |
| } | |
| } | |
| return Status; | |
| } | |
| /** | |
| Uninstalls all instances of a protocol:interfacer from a handle. | |
| If the last protocol interface is remove from the handle, the | |
| handle is freed. | |
| @param UserHandle The handle to remove the protocol handler from | |
| @param Protocol The protocol, of protocol:interface, to remove | |
| @param Interface The interface, of protocol:interface, to remove | |
| @retval EFI_INVALID_PARAMETER Protocol is NULL. | |
| @retval EFI_SUCCESS Protocol interface successfully uninstalled. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| SmmUninstallProtocolInterface ( | |
| IN EFI_HANDLE UserHandle, | |
| IN EFI_GUID *Protocol, | |
| IN VOID *Interface | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| IHANDLE *Handle; | |
| PROTOCOL_INTERFACE *Prot; | |
| // | |
| // Check that Protocol is valid | |
| // | |
| if (Protocol == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // Check that UserHandle is a valid handle | |
| // | |
| Status = SmmValidateHandle (UserHandle); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| // | |
| // Check that Protocol exists on UserHandle, and Interface matches the interface in the database | |
| // | |
| Prot = SmmFindProtocolInterface (UserHandle, Protocol, Interface); | |
| if (Prot == NULL) { | |
| return EFI_NOT_FOUND; | |
| } | |
| // | |
| // Remove the protocol interface from the protocol | |
| // | |
| Status = EFI_NOT_FOUND; | |
| Handle = (IHANDLE *)UserHandle; | |
| Prot = SmmRemoveInterfaceFromProtocol (Handle, Protocol, Interface); | |
| if (Prot != NULL) { | |
| // | |
| // Remove the protocol interface from the handle | |
| // | |
| RemoveEntryList (&Prot->Link); | |
| // | |
| // Free the memory | |
| // | |
| Prot->Signature = 0; | |
| FreePool (Prot); | |
| Status = EFI_SUCCESS; | |
| } | |
| // | |
| // If there are no more handlers for the handle, free the handle | |
| // | |
| if (IsListEmpty (&Handle->Protocols)) { | |
| Handle->Signature = 0; | |
| RemoveEntryList (&Handle->AllHandles); | |
| FreePool (Handle); | |
| } | |
| return Status; | |
| } | |
| /** | |
| Locate a certain GUID protocol interface in a Handle's protocols. | |
| @param UserHandle The handle to obtain the protocol interface on | |
| @param Protocol The GUID of the protocol | |
| @return The requested protocol interface for the handle | |
| **/ | |
| PROTOCOL_INTERFACE * | |
| SmmGetProtocolInterface ( | |
| IN EFI_HANDLE UserHandle, | |
| IN EFI_GUID *Protocol | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| PROTOCOL_ENTRY *ProtEntry; | |
| PROTOCOL_INTERFACE *Prot; | |
| IHANDLE *Handle; | |
| LIST_ENTRY *Link; | |
| Status = SmmValidateHandle (UserHandle); | |
| if (EFI_ERROR (Status)) { | |
| return NULL; | |
| } | |
| Handle = (IHANDLE *)UserHandle; | |
| // | |
| // Look at each protocol interface for a match | |
| // | |
| for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) { | |
| Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE); | |
| ProtEntry = Prot->Protocol; | |
| if (CompareGuid (&ProtEntry->ProtocolID, Protocol)) { | |
| return Prot; | |
| } | |
| } | |
| return NULL; | |
| } | |
| /** | |
| Queries a handle to determine if it supports a specified protocol. | |
| @param UserHandle The handle being queried. | |
| @param Protocol The published unique identifier of the protocol. | |
| @param Interface Supplies the address where a pointer to the | |
| corresponding Protocol Interface is returned. | |
| @retval EFI_SUCCESS The interface information for the specified protocol was returned. | |
| @retval EFI_UNSUPPORTED The device does not support the specified protocol. | |
| @retval EFI_INVALID_PARAMETER Handle is not a valid EFI_HANDLE.. | |
| @retval EFI_INVALID_PARAMETER Protocol is NULL. | |
| @retval EFI_INVALID_PARAMETER Interface is NULL. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| SmmHandleProtocol ( | |
| IN EFI_HANDLE UserHandle, | |
| IN EFI_GUID *Protocol, | |
| OUT VOID **Interface | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| PROTOCOL_INTERFACE *Prot; | |
| // | |
| // Check for invalid Protocol | |
| // | |
| if (Protocol == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // Check for invalid Interface | |
| // | |
| if (Interface == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } else { | |
| *Interface = NULL; | |
| } | |
| // | |
| // Check for invalid UserHandle | |
| // | |
| Status = SmmValidateHandle (UserHandle); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| // | |
| // Look at each protocol interface for a match | |
| // | |
| Prot = SmmGetProtocolInterface (UserHandle, Protocol); | |
| if (Prot == NULL) { | |
| return EFI_UNSUPPORTED; | |
| } | |
| // | |
| // This is the protocol interface entry for this protocol | |
| // | |
| *Interface = Prot->Interface; | |
| return EFI_SUCCESS; | |
| } |