| /** @file | |
| Support functions for UEFI protocol notification infrastructure. | |
| Copyright (c) 2009 - 2013, 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" | |
| /** | |
| Signal event for every protocol in protocol entry. | |
| @param Prot Protocol interface | |
| **/ | |
| VOID | |
| SmmNotifyProtocol ( | |
| IN PROTOCOL_INTERFACE *Prot | |
| ) | |
| { | |
| PROTOCOL_ENTRY *ProtEntry; | |
| PROTOCOL_NOTIFY *ProtNotify; | |
| LIST_ENTRY *Link; | |
| ProtEntry = Prot->Protocol; | |
| for (Link=ProtEntry->Notify.ForwardLink; Link != &ProtEntry->Notify; Link=Link->ForwardLink) { | |
| ProtNotify = CR(Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE); | |
| ProtNotify->Function (&ProtEntry->ProtocolID, Prot->Interface, Prot->Handle); | |
| } | |
| } | |
| /** | |
| 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 * | |
| SmmRemoveInterfaceFromProtocol ( | |
| IN IHANDLE *Handle, | |
| IN EFI_GUID *Protocol, | |
| IN VOID *Interface | |
| ) | |
| { | |
| PROTOCOL_INTERFACE *Prot; | |
| PROTOCOL_NOTIFY *ProtNotify; | |
| PROTOCOL_ENTRY *ProtEntry; | |
| LIST_ENTRY *Link; | |
| Prot = SmmFindProtocolInterface (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 Function Points to the notification function | |
| @param Registration Returns the registration record | |
| @retval EFI_INVALID_PARAMETER Invalid parameter | |
| @retval EFI_SUCCESS Successfully returned the registration record | |
| that has been added | |
| @retval EFI_OUT_OF_RESOURCES Not enough memory resource to finish the request | |
| @retval EFI_NOT_FOUND If the registration is not found when Function == NULL | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| SmmRegisterProtocolNotify ( | |
| IN CONST EFI_GUID *Protocol, | |
| IN EFI_SMM_NOTIFY_FN Function, | |
| OUT VOID **Registration | |
| ) | |
| { | |
| PROTOCOL_ENTRY *ProtEntry; | |
| PROTOCOL_NOTIFY *ProtNotify; | |
| LIST_ENTRY *Link; | |
| EFI_STATUS Status; | |
| if (Protocol == NULL || Registration == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if (Function == NULL) { | |
| // | |
| // Get the protocol entry per Protocol | |
| // | |
| ProtEntry = SmmFindProtocolEntry ((EFI_GUID *) Protocol, FALSE); | |
| if (ProtEntry != NULL) { | |
| ProtNotify = (PROTOCOL_NOTIFY * )*Registration; | |
| for (Link = ProtEntry->Notify.ForwardLink; | |
| Link != &ProtEntry->Notify; | |
| Link = Link->ForwardLink) { | |
| // | |
| // Compare the notification record | |
| // | |
| if (ProtNotify == (CR(Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE))){ | |
| // | |
| // If Registration is an existing registration, then unhook it | |
| // | |
| ProtNotify->Signature = 0; | |
| RemoveEntryList (&ProtNotify->Link); | |
| FreePool (ProtNotify); | |
| return EFI_SUCCESS; | |
| } | |
| } | |
| } | |
| // | |
| // If the registration is not found | |
| // | |
| return EFI_NOT_FOUND; | |
| } | |
| ProtNotify = NULL; | |
| // | |
| // Get the protocol entry to add the notification too | |
| // | |
| ProtEntry = SmmFindProtocolEntry ((EFI_GUID *) Protocol, TRUE); | |
| if (ProtEntry != NULL) { | |
| // | |
| // Find whether notification already exist | |
| // | |
| for (Link = ProtEntry->Notify.ForwardLink; | |
| Link != &ProtEntry->Notify; | |
| Link = Link->ForwardLink) { | |
| ProtNotify = CR(Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE); | |
| if (CompareGuid (&ProtNotify->Protocol->ProtocolID, Protocol) && | |
| (ProtNotify->Function == Function)) { | |
| // | |
| // Notification already exist | |
| // | |
| *Registration = ProtNotify; | |
| return EFI_SUCCESS; | |
| } | |
| } | |
| // | |
| // Allocate a new notification record | |
| // | |
| ProtNotify = AllocatePool (sizeof(PROTOCOL_NOTIFY)); | |
| if (ProtNotify != NULL) { | |
| ProtNotify->Signature = PROTOCOL_NOTIFY_SIGNATURE; | |
| ProtNotify->Protocol = ProtEntry; | |
| ProtNotify->Function = Function; | |
| // | |
| // Start at the ending | |
| // | |
| ProtNotify->Position = ProtEntry->Protocols.BackLink; | |
| InsertTailList (&ProtEntry->Notify, &ProtNotify->Link); | |
| } | |
| } | |
| // | |
| // 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; | |
| } |