1 /** @file
2 Support functions for UEFI protocol notification infrastructure.
3
4 Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
5 (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this 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 "DxeMain.h"
17 #include "Handle.h"
18 #include "Event.h"
19
20 /**
21 Signal event for every protocol in protocol entry.
22
23 @param ProtEntry Protocol entry
24
25 **/
26 VOID
CoreNotifyProtocolEntry(IN PROTOCOL_ENTRY * ProtEntry)27 CoreNotifyProtocolEntry (
28 IN PROTOCOL_ENTRY *ProtEntry
29 )
30 {
31 PROTOCOL_NOTIFY *ProtNotify;
32 LIST_ENTRY *Link;
33
34 ASSERT_LOCKED (&gProtocolDatabaseLock);
35
36 for (Link=ProtEntry->Notify.ForwardLink; Link != &ProtEntry->Notify; Link=Link->ForwardLink) {
37 ProtNotify = CR(Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE);
38 CoreSignalEvent (ProtNotify->Event);
39 }
40 }
41
42
43
44 /**
45 Removes Protocol from the protocol list (but not the handle list).
46
47 @param Handle The handle to remove protocol on.
48 @param Protocol GUID of the protocol to be moved
49 @param Interface The interface of the protocol
50
51 @return Protocol Entry
52
53 **/
54 PROTOCOL_INTERFACE *
CoreRemoveInterfaceFromProtocol(IN IHANDLE * Handle,IN EFI_GUID * Protocol,IN VOID * Interface)55 CoreRemoveInterfaceFromProtocol (
56 IN IHANDLE *Handle,
57 IN EFI_GUID *Protocol,
58 IN VOID *Interface
59 )
60 {
61 PROTOCOL_INTERFACE *Prot;
62 PROTOCOL_NOTIFY *ProtNotify;
63 PROTOCOL_ENTRY *ProtEntry;
64 LIST_ENTRY *Link;
65
66 ASSERT_LOCKED (&gProtocolDatabaseLock);
67
68 Prot = CoreFindProtocolInterface (Handle, Protocol, Interface);
69 if (Prot != NULL) {
70
71 ProtEntry = Prot->Protocol;
72
73 //
74 // If there's a protocol notify location pointing to this entry, back it up one
75 //
76 for(Link = ProtEntry->Notify.ForwardLink; Link != &ProtEntry->Notify; Link=Link->ForwardLink) {
77 ProtNotify = CR(Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE);
78
79 if (ProtNotify->Position == &Prot->ByProtocol) {
80 ProtNotify->Position = Prot->ByProtocol.BackLink;
81 }
82 }
83
84 //
85 // Remove the protocol interface entry
86 //
87 RemoveEntryList (&Prot->ByProtocol);
88 }
89
90 return Prot;
91 }
92
93
94 /**
95 Add a new protocol notification record for the request protocol.
96
97 @param Protocol The requested protocol to add the notify
98 registration
99 @param Event The event to signal
100 @param Registration Returns the registration record
101
102 @retval EFI_INVALID_PARAMETER Invalid parameter
103 @retval EFI_SUCCESS Successfully returned the registration record
104 that has been added
105
106 **/
107 EFI_STATUS
108 EFIAPI
CoreRegisterProtocolNotify(IN EFI_GUID * Protocol,IN EFI_EVENT Event,OUT VOID ** Registration)109 CoreRegisterProtocolNotify (
110 IN EFI_GUID *Protocol,
111 IN EFI_EVENT Event,
112 OUT VOID **Registration
113 )
114 {
115 PROTOCOL_ENTRY *ProtEntry;
116 PROTOCOL_NOTIFY *ProtNotify;
117 EFI_STATUS Status;
118
119 if ((Protocol == NULL) || (Event == NULL) || (Registration == NULL)) {
120 return EFI_INVALID_PARAMETER;
121 }
122
123 CoreAcquireProtocolLock ();
124
125 ProtNotify = NULL;
126
127 //
128 // Get the protocol entry to add the notification too
129 //
130
131 ProtEntry = CoreFindProtocolEntry (Protocol, TRUE);
132 if (ProtEntry != NULL) {
133
134 //
135 // Allocate a new notification record
136 //
137 ProtNotify = AllocatePool (sizeof(PROTOCOL_NOTIFY));
138 if (ProtNotify != NULL) {
139 ((IEVENT *)Event)->ExFlag |= EVT_EXFLAG_EVENT_PROTOCOL_NOTIFICATION;
140 ProtNotify->Signature = PROTOCOL_NOTIFY_SIGNATURE;
141 ProtNotify->Protocol = ProtEntry;
142 ProtNotify->Event = Event;
143 //
144 // start at the begining
145 //
146 ProtNotify->Position = &ProtEntry->Protocols;
147
148 InsertTailList (&ProtEntry->Notify, &ProtNotify->Link);
149 }
150 }
151
152 CoreReleaseProtocolLock ();
153
154 //
155 // Done. If we have a protocol notify entry, then return it.
156 // Otherwise, we must have run out of resources trying to add one
157 //
158
159 Status = EFI_OUT_OF_RESOURCES;
160 if (ProtNotify != NULL) {
161 *Registration = ProtNotify;
162 Status = EFI_SUCCESS;
163 }
164
165 return Status;
166 }
167
168
169 /**
170 Reinstall a protocol interface on a device handle. The OldInterface for Protocol is replaced by the NewInterface.
171
172 @param UserHandle Handle on which the interface is to be
173 reinstalled
174 @param Protocol The numeric ID of the interface
175 @param OldInterface A pointer to the old interface
176 @param NewInterface A pointer to the new interface
177
178 @retval EFI_SUCCESS The protocol interface was installed
179 @retval EFI_NOT_FOUND The OldInterface on the handle was not found
180 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value
181
182 **/
183 EFI_STATUS
184 EFIAPI
CoreReinstallProtocolInterface(IN EFI_HANDLE UserHandle,IN EFI_GUID * Protocol,IN VOID * OldInterface,IN VOID * NewInterface)185 CoreReinstallProtocolInterface (
186 IN EFI_HANDLE UserHandle,
187 IN EFI_GUID *Protocol,
188 IN VOID *OldInterface,
189 IN VOID *NewInterface
190 )
191 {
192 EFI_STATUS Status;
193 IHANDLE *Handle;
194 PROTOCOL_INTERFACE *Prot;
195 PROTOCOL_ENTRY *ProtEntry;
196
197 Status = CoreValidateHandle (UserHandle);
198 if (EFI_ERROR (Status)) {
199 return Status;
200 }
201
202 if (Protocol == NULL) {
203 return EFI_INVALID_PARAMETER;
204 }
205
206 Handle = (IHANDLE *) UserHandle;
207
208 //
209 // Lock the protocol database
210 //
211 CoreAcquireProtocolLock ();
212
213 //
214 // Check that Protocol exists on UserHandle, and Interface matches the interface in the database
215 //
216 Prot = CoreFindProtocolInterface (UserHandle, Protocol, OldInterface);
217 if (Prot == NULL) {
218 Status = EFI_NOT_FOUND;
219 goto Done;
220 }
221
222 //
223 // Attempt to disconnect all drivers that are using the protocol interface that is about to be reinstalled
224 //
225 Status = CoreDisconnectControllersUsingProtocolInterface (
226 UserHandle,
227 Prot
228 );
229 if (EFI_ERROR (Status)) {
230 //
231 // One or more drivers refused to release, so return the error
232 //
233 goto Done;
234 }
235
236 //
237 // Remove the protocol interface from the protocol
238 //
239 Prot = CoreRemoveInterfaceFromProtocol (Handle, Protocol, OldInterface);
240
241 if (Prot == NULL) {
242 Status = EFI_NOT_FOUND;
243 goto Done;
244 }
245
246 ProtEntry = Prot->Protocol;
247
248 //
249 // Update the interface on the protocol
250 //
251 Prot->Interface = NewInterface;
252
253 //
254 // Add this protocol interface to the tail of the
255 // protocol entry
256 //
257 InsertTailList (&ProtEntry->Protocols, &Prot->ByProtocol);
258
259 //
260 // Update the Key to show that the handle has been created/modified
261 //
262 gHandleDatabaseKey++;
263 Handle->Key = gHandleDatabaseKey;
264
265 //
266 // Release the lock and connect all drivers to UserHandle
267 //
268 CoreReleaseProtocolLock ();
269 //
270 // Return code is ignored on purpose.
271 //
272 CoreConnectController (
273 UserHandle,
274 NULL,
275 NULL,
276 TRUE
277 );
278 CoreAcquireProtocolLock ();
279
280 //
281 // Notify the notification list for this protocol
282 //
283 CoreNotifyProtocolEntry (ProtEntry);
284
285 Status = EFI_SUCCESS;
286
287 Done:
288 CoreReleaseProtocolLock ();
289
290 return Status;
291 }
292