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