1 /** @file
2   Support functions for UEFI protocol notification infrastructure.
3 
4   Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
5   Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR>
6   SPDX-License-Identifier: BSD-2-Clause-Patent
7 
8 **/
9 
10 #include "StandaloneMmCore.h"
11 
12 /**
13   Signal event for every protocol in protocol entry.
14 
15   @param  Prot                   Protocol interface
16 
17 **/
18 VOID
MmNotifyProtocol(IN PROTOCOL_INTERFACE * Prot)19 MmNotifyProtocol (
20   IN PROTOCOL_INTERFACE  *Prot
21   )
22 {
23   PROTOCOL_ENTRY   *ProtEntry;
24   PROTOCOL_NOTIFY  *ProtNotify;
25   LIST_ENTRY       *Link;
26 
27   ProtEntry = Prot->Protocol;
28   for (Link=ProtEntry->Notify.ForwardLink; Link != &ProtEntry->Notify; Link=Link->ForwardLink) {
29     ProtNotify = CR (Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE);
30     ProtNotify->Function (&ProtEntry->ProtocolID, Prot->Interface, Prot->Handle);
31   }
32 }
33 
34 /**
35   Removes Protocol from the protocol list (but not the handle list).
36 
37   @param  Handle                 The handle to remove protocol on.
38   @param  Protocol               GUID of the protocol to be moved
39   @param  Interface              The interface of the protocol
40 
41   @return Protocol Entry
42 
43 **/
44 PROTOCOL_INTERFACE *
MmRemoveInterfaceFromProtocol(IN IHANDLE * Handle,IN EFI_GUID * Protocol,IN VOID * Interface)45 MmRemoveInterfaceFromProtocol (
46   IN IHANDLE   *Handle,
47   IN EFI_GUID  *Protocol,
48   IN VOID      *Interface
49   )
50 {
51   PROTOCOL_INTERFACE  *Prot;
52   PROTOCOL_NOTIFY     *ProtNotify;
53   PROTOCOL_ENTRY      *ProtEntry;
54   LIST_ENTRY          *Link;
55 
56   Prot = MmFindProtocolInterface (Handle, Protocol, Interface);
57   if (Prot != NULL) {
58 
59     ProtEntry = Prot->Protocol;
60 
61     //
62     // If there's a protocol notify location pointing to this entry, back it up one
63     //
64     for (Link = ProtEntry->Notify.ForwardLink; Link != &ProtEntry->Notify; Link = Link->ForwardLink) {
65       ProtNotify = CR (Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE);
66 
67       if (ProtNotify->Position == &Prot->ByProtocol) {
68         ProtNotify->Position = Prot->ByProtocol.BackLink;
69       }
70     }
71 
72     //
73     // Remove the protocol interface entry
74     //
75     RemoveEntryList (&Prot->ByProtocol);
76   }
77 
78   return Prot;
79 }
80 
81 /**
82   Add a new protocol notification record for the request protocol.
83 
84   @param  Protocol               The requested protocol to add the notify
85                                  registration
86   @param  Function               Points to the notification function
87   @param  Registration           Returns the registration record
88 
89   @retval EFI_SUCCESS            Successfully returned the registration record
90                                  that has been added or unhooked
91   @retval EFI_INVALID_PARAMETER  Protocol is NULL or Registration is NULL
92   @retval EFI_OUT_OF_RESOURCES   Not enough memory resource to finish the request
93   @retval EFI_NOT_FOUND          If the registration is not found when Function == NULL
94 
95 **/
96 EFI_STATUS
97 EFIAPI
MmRegisterProtocolNotify(IN CONST EFI_GUID * Protocol,IN EFI_MM_NOTIFY_FN Function,OUT VOID ** Registration)98 MmRegisterProtocolNotify (
99   IN  CONST EFI_GUID     *Protocol,
100   IN  EFI_MM_NOTIFY_FN  Function,
101   OUT VOID               **Registration
102   )
103 {
104   PROTOCOL_ENTRY   *ProtEntry;
105   PROTOCOL_NOTIFY  *ProtNotify;
106   LIST_ENTRY       *Link;
107   EFI_STATUS       Status;
108 
109   if (Protocol == NULL || Registration == NULL) {
110     return EFI_INVALID_PARAMETER;
111   }
112 
113   if (Function == NULL) {
114     //
115     // Get the protocol entry per Protocol
116     //
117     ProtEntry = MmFindProtocolEntry ((EFI_GUID *) Protocol, FALSE);
118     if (ProtEntry != NULL) {
119       ProtNotify = (PROTOCOL_NOTIFY * )*Registration;
120       for (Link = ProtEntry->Notify.ForwardLink;
121            Link != &ProtEntry->Notify;
122            Link = Link->ForwardLink) {
123         //
124         // Compare the notification record
125         //
126         if (ProtNotify == (CR (Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE))) {
127           //
128           // If Registration is an existing registration, then unhook it
129           //
130           ProtNotify->Signature = 0;
131           RemoveEntryList (&ProtNotify->Link);
132           FreePool (ProtNotify);
133           return EFI_SUCCESS;
134         }
135       }
136     }
137     //
138     // If the registration is not found
139     //
140     return EFI_NOT_FOUND;
141   }
142 
143   ProtNotify = NULL;
144 
145   //
146   // Get the protocol entry to add the notification too
147   //
148   ProtEntry = MmFindProtocolEntry ((EFI_GUID *) Protocol, TRUE);
149   if (ProtEntry != NULL) {
150     //
151     // Find whether notification already exist
152     //
153     for (Link = ProtEntry->Notify.ForwardLink;
154          Link != &ProtEntry->Notify;
155          Link = Link->ForwardLink) {
156 
157       ProtNotify = CR (Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE);
158       if (CompareGuid (&ProtNotify->Protocol->ProtocolID, Protocol) &&
159           (ProtNotify->Function == Function)) {
160 
161         //
162         // Notification already exist
163         //
164         *Registration = ProtNotify;
165 
166         return EFI_SUCCESS;
167       }
168     }
169 
170     //
171     // Allocate a new notification record
172     //
173     ProtNotify = AllocatePool (sizeof (PROTOCOL_NOTIFY));
174     if (ProtNotify != NULL) {
175       ProtNotify->Signature = PROTOCOL_NOTIFY_SIGNATURE;
176       ProtNotify->Protocol = ProtEntry;
177       ProtNotify->Function = Function;
178       //
179       // Start at the ending
180       //
181       ProtNotify->Position = ProtEntry->Protocols.BackLink;
182 
183       InsertTailList (&ProtEntry->Notify, &ProtNotify->Link);
184     }
185   }
186 
187   //
188   // Done.  If we have a protocol notify entry, then return it.
189   // Otherwise, we must have run out of resources trying to add one
190   //
191   Status = EFI_OUT_OF_RESOURCES;
192   if (ProtNotify != NULL) {
193     *Registration = ProtNotify;
194     Status = EFI_SUCCESS;
195   }
196   return Status;
197 }
198