| /** @file | |
| Support functions for UEFI protocol notification infrastructure. | |
| Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR> | |
| (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR> | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| **/ | |
| #include "DxeMain.h" | |
| #include "Handle.h" | |
| #include "Event.h" | |
| /** | |
| Signal event for every protocol in protocol entry. | |
| @param ProtEntry Protocol entry | |
| **/ | |
| VOID | |
| CoreNotifyProtocolEntry ( | |
| IN PROTOCOL_ENTRY *ProtEntry | |
| ) | |
| { | |
| PROTOCOL_NOTIFY *ProtNotify; | |
| LIST_ENTRY *Link; | |
| ASSERT_LOCKED (&gProtocolDatabaseLock); | |
| for (Link = ProtEntry->Notify.ForwardLink; Link != &ProtEntry->Notify; Link = Link->ForwardLink) { | |
| ProtNotify = CR (Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE); | |
| CoreSignalEvent (ProtNotify->Event); | |
| } | |
| } | |
| /** | |
| Removes Protocol from the protocol list (but not the handle list). | |
| @param Handle The handle to remove protocol on. | |
| @param Protocol GUID of the protocol to be moved | |
| @param Interface The interface of the protocol | |
| @return Protocol Entry | |
| **/ | |
| PROTOCOL_INTERFACE * | |
| CoreRemoveInterfaceFromProtocol ( | |
| IN IHANDLE *Handle, | |
| IN EFI_GUID *Protocol, | |
| IN VOID *Interface | |
| ) | |
| { | |
| PROTOCOL_INTERFACE *Prot; | |
| PROTOCOL_NOTIFY *ProtNotify; | |
| PROTOCOL_ENTRY *ProtEntry; | |
| LIST_ENTRY *Link; | |
| ASSERT_LOCKED (&gProtocolDatabaseLock); | |
| Prot = CoreFindProtocolInterface (Handle, Protocol, Interface); | |
| if (Prot != NULL) { | |
| ProtEntry = Prot->Protocol; | |
| // | |
| // If there's a protocol notify location pointing to this entry, back it up one | |
| // | |
| for (Link = ProtEntry->Notify.ForwardLink; Link != &ProtEntry->Notify; Link = Link->ForwardLink) { | |
| ProtNotify = CR (Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE); | |
| if (ProtNotify->Position == &Prot->ByProtocol) { | |
| ProtNotify->Position = Prot->ByProtocol.BackLink; | |
| } | |
| } | |
| // | |
| // Remove the protocol interface entry | |
| // | |
| RemoveEntryList (&Prot->ByProtocol); | |
| } | |
| return Prot; | |
| } | |
| /** | |
| Add a new protocol notification record for the request protocol. | |
| @param Protocol The requested protocol to add the notify | |
| registration | |
| @param Event The event to signal | |
| @param Registration Returns the registration record | |
| @retval EFI_INVALID_PARAMETER Invalid parameter | |
| @retval EFI_SUCCESS Successfully returned the registration record | |
| that has been added | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| CoreRegisterProtocolNotify ( | |
| IN EFI_GUID *Protocol, | |
| IN EFI_EVENT Event, | |
| OUT VOID **Registration | |
| ) | |
| { | |
| PROTOCOL_ENTRY *ProtEntry; | |
| PROTOCOL_NOTIFY *ProtNotify; | |
| EFI_STATUS Status; | |
| if ((Protocol == NULL) || (Event == NULL) || (Registration == NULL)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| CoreAcquireProtocolLock (); | |
| ProtNotify = NULL; | |
| // | |
| // Get the protocol entry to add the notification too | |
| // | |
| ProtEntry = CoreFindProtocolEntry (Protocol, TRUE); | |
| if (ProtEntry != NULL) { | |
| // | |
| // Allocate a new notification record | |
| // | |
| ProtNotify = AllocatePool (sizeof (PROTOCOL_NOTIFY)); | |
| if (ProtNotify != NULL) { | |
| ((IEVENT *)Event)->ExFlag |= EVT_EXFLAG_EVENT_PROTOCOL_NOTIFICATION; | |
| ProtNotify->Signature = PROTOCOL_NOTIFY_SIGNATURE; | |
| ProtNotify->Protocol = ProtEntry; | |
| ProtNotify->Event = Event; | |
| // | |
| // start at the begining | |
| // | |
| ProtNotify->Position = &ProtEntry->Protocols; | |
| InsertTailList (&ProtEntry->Notify, &ProtNotify->Link); | |
| } | |
| } | |
| CoreReleaseProtocolLock (); | |
| // | |
| // Done. If we have a protocol notify entry, then return it. | |
| // Otherwise, we must have run out of resources trying to add one | |
| // | |
| Status = EFI_OUT_OF_RESOURCES; | |
| if (ProtNotify != NULL) { | |
| *Registration = ProtNotify; | |
| Status = EFI_SUCCESS; | |
| } | |
| return Status; | |
| } | |
| /** | |
| Reinstall a protocol interface on a device handle. The OldInterface for Protocol is replaced by the NewInterface. | |
| @param UserHandle Handle on which the interface is to be | |
| reinstalled | |
| @param Protocol The numeric ID of the interface | |
| @param OldInterface A pointer to the old interface | |
| @param NewInterface A pointer to the new interface | |
| @retval EFI_SUCCESS The protocol interface was installed | |
| @retval EFI_NOT_FOUND The OldInterface on the handle was not found | |
| @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| CoreReinstallProtocolInterface ( | |
| IN EFI_HANDLE UserHandle, | |
| IN EFI_GUID *Protocol, | |
| IN VOID *OldInterface, | |
| IN VOID *NewInterface | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| IHANDLE *Handle; | |
| PROTOCOL_INTERFACE *Prot; | |
| PROTOCOL_ENTRY *ProtEntry; | |
| if (Protocol == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // Lock the protocol database | |
| // | |
| CoreAcquireProtocolLock (); | |
| Status = CoreValidateHandle (UserHandle); | |
| if (EFI_ERROR (Status)) { | |
| goto Done; | |
| } | |
| Handle = (IHANDLE *)UserHandle; | |
| // | |
| // Check that Protocol exists on UserHandle, and Interface matches the interface in the database | |
| // | |
| Prot = CoreFindProtocolInterface (UserHandle, Protocol, OldInterface); | |
| if (Prot == NULL) { | |
| Status = EFI_NOT_FOUND; | |
| goto Done; | |
| } | |
| // | |
| // Attempt to disconnect all drivers that are using the protocol interface that is about to be reinstalled | |
| // | |
| Status = CoreDisconnectControllersUsingProtocolInterface ( | |
| UserHandle, | |
| Prot | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| // | |
| // One or more drivers refused to release, so return the error | |
| // | |
| goto Done; | |
| } | |
| // | |
| // Remove the protocol interface from the protocol | |
| // | |
| Prot = CoreRemoveInterfaceFromProtocol (Handle, Protocol, OldInterface); | |
| if (Prot == NULL) { | |
| Status = EFI_NOT_FOUND; | |
| goto Done; | |
| } | |
| ProtEntry = Prot->Protocol; | |
| // | |
| // Update the interface on the protocol | |
| // | |
| Prot->Interface = NewInterface; | |
| // | |
| // Add this protocol interface to the tail of the | |
| // protocol entry | |
| // | |
| InsertTailList (&ProtEntry->Protocols, &Prot->ByProtocol); | |
| // | |
| // Update the Key to show that the handle has been created/modified | |
| // | |
| gHandleDatabaseKey++; | |
| Handle->Key = gHandleDatabaseKey; | |
| // | |
| // Release the lock and connect all drivers to UserHandle | |
| // | |
| CoreReleaseProtocolLock (); | |
| // | |
| // Return code is ignored on purpose. | |
| // | |
| CoreConnectController ( | |
| UserHandle, | |
| NULL, | |
| NULL, | |
| TRUE | |
| ); | |
| CoreAcquireProtocolLock (); | |
| // | |
| // Notify the notification list for this protocol | |
| // | |
| CoreNotifyProtocolEntry (ProtEntry); | |
| Status = EFI_SUCCESS; | |
| Done: | |
| CoreReleaseProtocolLock (); | |
| return Status; | |
| } |