--- /dev/null
+/** @file\r
+ Support functions for UEFI protocol notification infrastructure.\r
+\r
+ Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>\r
+ Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR>\r
+ This program and the accompanying materials are licensed and made available\r
+ under the terms and conditions of the BSD License which accompanies this\r
+ distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "StandaloneMmCore.h"\r
+\r
+/**\r
+ Signal event for every protocol in protocol entry.\r
+\r
+ @param Prot Protocol interface\r
+\r
+**/\r
+VOID\r
+MmNotifyProtocol (\r
+ IN PROTOCOL_INTERFACE *Prot\r
+ )\r
+{\r
+ PROTOCOL_ENTRY *ProtEntry;\r
+ PROTOCOL_NOTIFY *ProtNotify;\r
+ LIST_ENTRY *Link;\r
+\r
+ ProtEntry = Prot->Protocol;\r
+ for (Link=ProtEntry->Notify.ForwardLink; Link != &ProtEntry->Notify; Link=Link->ForwardLink) {\r
+ ProtNotify = CR (Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE);\r
+ ProtNotify->Function (&ProtEntry->ProtocolID, Prot->Interface, Prot->Handle);\r
+ }\r
+}\r
+\r
+/**\r
+ Removes Protocol from the protocol list (but not the handle list).\r
+\r
+ @param Handle The handle to remove protocol on.\r
+ @param Protocol GUID of the protocol to be moved\r
+ @param Interface The interface of the protocol\r
+\r
+ @return Protocol Entry\r
+\r
+**/\r
+PROTOCOL_INTERFACE *\r
+MmRemoveInterfaceFromProtocol (\r
+ IN IHANDLE *Handle,\r
+ IN EFI_GUID *Protocol,\r
+ IN VOID *Interface\r
+ )\r
+{\r
+ PROTOCOL_INTERFACE *Prot;\r
+ PROTOCOL_NOTIFY *ProtNotify;\r
+ PROTOCOL_ENTRY *ProtEntry;\r
+ LIST_ENTRY *Link;\r
+\r
+ Prot = MmFindProtocolInterface (Handle, Protocol, Interface);\r
+ if (Prot != NULL) {\r
+\r
+ ProtEntry = Prot->Protocol;\r
+\r
+ //\r
+ // If there's a protocol notify location pointing to this entry, back it up one\r
+ //\r
+ for (Link = ProtEntry->Notify.ForwardLink; Link != &ProtEntry->Notify; Link = Link->ForwardLink) {\r
+ ProtNotify = CR (Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE);\r
+\r
+ if (ProtNotify->Position == &Prot->ByProtocol) {\r
+ ProtNotify->Position = Prot->ByProtocol.BackLink;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Remove the protocol interface entry\r
+ //\r
+ RemoveEntryList (&Prot->ByProtocol);\r
+ }\r
+\r
+ return Prot;\r
+}\r
+\r
+/**\r
+ Add a new protocol notification record for the request protocol.\r
+\r
+ @param Protocol The requested protocol to add the notify\r
+ registration\r
+ @param Function Points to the notification function\r
+ @param Registration Returns the registration record\r
+\r
+ @retval EFI_SUCCESS Successfully returned the registration record\r
+ that has been added or unhooked\r
+ @retval EFI_INVALID_PARAMETER Protocol is NULL or Registration is NULL\r
+ @retval EFI_OUT_OF_RESOURCES Not enough memory resource to finish the request\r
+ @retval EFI_NOT_FOUND If the registration is not found when Function == NULL\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MmRegisterProtocolNotify (\r
+ IN CONST EFI_GUID *Protocol,\r
+ IN EFI_MM_NOTIFY_FN Function,\r
+ OUT VOID **Registration\r
+ )\r
+{\r
+ PROTOCOL_ENTRY *ProtEntry;\r
+ PROTOCOL_NOTIFY *ProtNotify;\r
+ LIST_ENTRY *Link;\r
+ EFI_STATUS Status;\r
+\r
+ if (Protocol == NULL || Registration == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (Function == NULL) {\r
+ //\r
+ // Get the protocol entry per Protocol\r
+ //\r
+ ProtEntry = MmFindProtocolEntry ((EFI_GUID *) Protocol, FALSE);\r
+ if (ProtEntry != NULL) {\r
+ ProtNotify = (PROTOCOL_NOTIFY * )*Registration;\r
+ for (Link = ProtEntry->Notify.ForwardLink;\r
+ Link != &ProtEntry->Notify;\r
+ Link = Link->ForwardLink) {\r
+ //\r
+ // Compare the notification record\r
+ //\r
+ if (ProtNotify == (CR (Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE))) {\r
+ //\r
+ // If Registration is an existing registration, then unhook it\r
+ //\r
+ ProtNotify->Signature = 0;\r
+ RemoveEntryList (&ProtNotify->Link);\r
+ FreePool (ProtNotify);\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+ }\r
+ //\r
+ // If the registration is not found\r
+ //\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ ProtNotify = NULL;\r
+\r
+ //\r
+ // Get the protocol entry to add the notification too\r
+ //\r
+ ProtEntry = MmFindProtocolEntry ((EFI_GUID *) Protocol, TRUE);\r
+ if (ProtEntry != NULL) {\r
+ //\r
+ // Find whether notification already exist\r
+ //\r
+ for (Link = ProtEntry->Notify.ForwardLink;\r
+ Link != &ProtEntry->Notify;\r
+ Link = Link->ForwardLink) {\r
+\r
+ ProtNotify = CR (Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE);\r
+ if (CompareGuid (&ProtNotify->Protocol->ProtocolID, Protocol) &&\r
+ (ProtNotify->Function == Function)) {\r
+\r
+ //\r
+ // Notification already exist\r
+ //\r
+ *Registration = ProtNotify;\r
+\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Allocate a new notification record\r
+ //\r
+ ProtNotify = AllocatePool (sizeof (PROTOCOL_NOTIFY));\r
+ if (ProtNotify != NULL) {\r
+ ProtNotify->Signature = PROTOCOL_NOTIFY_SIGNATURE;\r
+ ProtNotify->Protocol = ProtEntry;\r
+ ProtNotify->Function = Function;\r
+ //\r
+ // Start at the ending\r
+ //\r
+ ProtNotify->Position = ProtEntry->Protocols.BackLink;\r
+\r
+ InsertTailList (&ProtEntry->Notify, &ProtNotify->Link);\r
+ }\r
+ }\r
+\r
+ //\r
+ // Done. If we have a protocol notify entry, then return it.\r
+ // Otherwise, we must have run out of resources trying to add one\r
+ //\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ if (ProtNotify != NULL) {\r
+ *Registration = ProtNotify;\r
+ Status = EFI_SUCCESS;\r
+ }\r
+ return Status;\r
+}\r