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