/** @file | |
Support functions for UEFI protocol notification infrastructure. | |
Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR> | |
Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#include "StandaloneMmCore.h" | |
/** | |
Signal event for every protocol in protocol entry. | |
@param Prot Protocol interface | |
**/ | |
VOID | |
MmNotifyProtocol ( | |
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 * | |
MmRemoveInterfaceFromProtocol ( | |
IN IHANDLE *Handle, | |
IN EFI_GUID *Protocol, | |
IN VOID *Interface | |
) | |
{ | |
PROTOCOL_INTERFACE *Prot; | |
PROTOCOL_NOTIFY *ProtNotify; | |
PROTOCOL_ENTRY *ProtEntry; | |
LIST_ENTRY *Link; | |
Prot = MmFindProtocolInterface (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_SUCCESS Successfully returned the registration record | |
that has been added or unhooked | |
@retval EFI_INVALID_PARAMETER Protocol is NULL or Registration is NULL | |
@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 | |
MmRegisterProtocolNotify ( | |
IN CONST EFI_GUID *Protocol, | |
IN EFI_MM_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 = MmFindProtocolEntry ((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 = MmFindProtocolEntry ((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; | |
} |