1) Remove buffer overflow when the number of Driver Binding Protocols increases in...
[people/mcb30/edk2.git] / edk2 / MdeModulePkg / Core / Dxe / Hand / Notify.c
1 /*++\r
2 \r
3 Copyright (c) 2006, Intel Corporation                                                         \r
4 All rights reserved. This program and the accompanying materials                          \r
5 are licensed and made available under the terms and conditions of the BSD License         \r
6 which accompanies this distribution.  The full text of the license may be found at        \r
7 http://opensource.org/licenses/bsd-license.php                                            \r
8                                                                                           \r
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
11 \r
12 Module Name:\r
13 \r
14   notify.c\r
15 \r
16 Abstract:\r
17 \r
18   EFI notify infrastructure\r
19 \r
20 \r
21 \r
22 Revision History\r
23 \r
24 --*/\r
25 \r
26 #include <DxeMain.h>\r
27 \r
28 VOID\r
29 CoreNotifyProtocolEntry (\r
30   IN PROTOCOL_ENTRY   *ProtEntry\r
31   )\r
32 /*++\r
33 \r
34 Routine Description:\r
35 \r
36   Signal event for every protocol in protocol entry.\r
37 \r
38 Arguments:\r
39 \r
40   ProtEntry     - Protocol entry\r
41 \r
42 Returns:\r
43 \r
44 --*/\r
45 {\r
46   PROTOCOL_NOTIFY     *ProtNotify;\r
47   LIST_ENTRY          *Link;\r
48 \r
49   ASSERT_LOCKED (&gProtocolDatabaseLock);\r
50 \r
51   for (Link=ProtEntry->Notify.ForwardLink; Link != &ProtEntry->Notify; Link=Link->ForwardLink) {\r
52     ProtNotify = CR(Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE);\r
53     CoreSignalEvent (ProtNotify->Event);\r
54   }\r
55 }\r
56 \r
57 \r
58 PROTOCOL_INTERFACE *\r
59 CoreRemoveInterfaceFromProtocol (\r
60   IN IHANDLE        *Handle,\r
61   IN EFI_GUID       *Protocol,\r
62   IN VOID           *Interface\r
63   )\r
64 /*++\r
65 \r
66 Routine Description:\r
67 \r
68   Removes Protocol from the protocol list (but not the handle list).\r
69 \r
70 Arguments:\r
71 \r
72   Handle -  The handle to remove protocol on.\r
73 \r
74   Protocol  -  GUID of the protocol to be moved\r
75 \r
76   Interface - The interface of the protocol\r
77 \r
78 Returns:\r
79 \r
80   Protocol Entry\r
81 \r
82 --*/\r
83 {\r
84   PROTOCOL_INTERFACE  *Prot;\r
85   PROTOCOL_NOTIFY     *ProtNotify;\r
86   PROTOCOL_ENTRY      *ProtEntry;\r
87   LIST_ENTRY          *Link;\r
88 \r
89   ASSERT_LOCKED (&gProtocolDatabaseLock);\r
90 \r
91   Prot = CoreFindProtocolInterface (Handle, Protocol, Interface);\r
92   if (Prot != NULL) {\r
93 \r
94     ProtEntry = Prot->Protocol;\r
95 \r
96     //\r
97     // If there's a protocol notify location pointing to this entry, back it up one\r
98     //\r
99 \r
100     for(Link = ProtEntry->Notify.ForwardLink; Link != &ProtEntry->Notify; Link=Link->ForwardLink) {\r
101       ProtNotify = CR(Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE);\r
102 \r
103       if (ProtNotify->Position == &Prot->ByProtocol) {\r
104         ProtNotify->Position = Prot->ByProtocol.BackLink;\r
105       }\r
106     }\r
107 \r
108     //\r
109     // Remove the protocol interface entry\r
110     //\r
111 \r
112     RemoveEntryList (&Prot->ByProtocol);\r
113   }\r
114 \r
115   return Prot;\r
116 }\r
117 \r
118 \r
119 \r
120 EFI_STATUS\r
121 EFIAPI\r
122 CoreRegisterProtocolNotify (\r
123   IN EFI_GUID       *Protocol,\r
124   IN EFI_EVENT      Event,\r
125   OUT  VOID           **Registration\r
126   )\r
127 /*++\r
128 \r
129 Routine Description:\r
130 \r
131   Add a new protocol notification record for the request protocol.\r
132 \r
133 Arguments:\r
134 \r
135   Protocol      - The requested protocol to add the notify registration\r
136 \r
137   Event         - The event to signal \r
138 \r
139   Registration  - Returns the registration record\r
140 \r
141 \r
142 Returns:\r
143 \r
144   EFI_INVALID_PARAMETER       - Invalid parameter\r
145 \r
146   EFI_SUCCESS                 - Successfully returned the registration record that has been added\r
147   \r
148 --*/\r
149 {\r
150   PROTOCOL_ENTRY      *ProtEntry;\r
151   PROTOCOL_NOTIFY     *ProtNotify;\r
152   EFI_STATUS        Status;\r
153   \r
154   if ((Protocol == NULL) || (Event == NULL) || (Registration == NULL))  {\r
155     return EFI_INVALID_PARAMETER;\r
156   }\r
157 \r
158   CoreAcquireProtocolLock ();\r
159 \r
160   ProtNotify = NULL;\r
161   \r
162   //\r
163   // Get the protocol entry to add the notification too\r
164   //\r
165 \r
166   ProtEntry = CoreFindProtocolEntry (Protocol, TRUE);\r
167   if (ProtEntry != NULL) {\r
168 \r
169     //\r
170     // Allocate a new notification record\r
171     //\r
172 \r
173     ProtNotify = CoreAllocateBootServicesPool (sizeof(PROTOCOL_NOTIFY));\r
174 \r
175     if (ProtNotify != NULL) {\r
176       \r
177       ProtNotify->Signature = PROTOCOL_NOTIFY_SIGNATURE;\r
178       ProtNotify->Protocol = ProtEntry;\r
179       ProtNotify->Event = Event;\r
180       //\r
181       // start at the begining\r
182       //\r
183       ProtNotify->Position = &ProtEntry->Protocols; \r
184 \r
185       InsertTailList (&ProtEntry->Notify, &ProtNotify->Link);\r
186     }\r
187   }\r
188 \r
189   CoreReleaseProtocolLock ();\r
190 \r
191   //\r
192   // Done.  If we have a protocol notify entry, then return it.\r
193   // Otherwise, we must have run out of resources trying to add one\r
194   //\r
195 \r
196   Status = EFI_OUT_OF_RESOURCES;\r
197   if (ProtNotify != NULL) {\r
198     *Registration = ProtNotify;\r
199     Status = EFI_SUCCESS;\r
200   }\r
201 \r
202   return Status;\r
203 }\r
204 \r
205 \r
206 \r
207 EFI_STATUS\r
208 EFIAPI\r
209 CoreReinstallProtocolInterface (\r
210   IN EFI_HANDLE     UserHandle,\r
211   IN EFI_GUID       *Protocol,\r
212   IN VOID           *OldInterface,\r
213   IN VOID           *NewInterface\r
214   )\r
215 /*++\r
216 \r
217 Routine Description:\r
218 \r
219   Reinstall a protocol interface on a device handle.  The OldInterface for Protocol is replaced by the NewInterface.\r
220 \r
221 Arguments:\r
222 \r
223   UserHandle    - Handle on which the interface is to be reinstalled\r
224   Protocol      - The numeric ID of the interface\r
225   OldInterface  - A pointer to the old interface\r
226   NewInterface  - A pointer to the new interface \r
227 \r
228 \r
229 Returns:\r
230 \r
231   Status code.\r
232 \r
233   On EFI_SUCCESS            The protocol interface was installed\r
234   On EFI_NOT_FOUND          The OldInterface on the handle was not found\r
235   On EFI_INVALID_PARAMETER  One of the parameters has an invalid value\r
236   \r
237 --*/\r
238 {\r
239   EFI_STATUS                Status;\r
240   IHANDLE                   *Handle;\r
241   PROTOCOL_INTERFACE        *Prot;\r
242   PROTOCOL_ENTRY            *ProtEntry;\r
243 \r
244   Status = CoreValidateHandle (UserHandle);\r
245   if (EFI_ERROR (Status)) {\r
246     return Status;\r
247   }\r
248 \r
249   if (Protocol == NULL) {\r
250     return EFI_INVALID_PARAMETER;\r
251   }\r
252 \r
253   Handle = (IHANDLE *) UserHandle;\r
254 \r
255   //\r
256   // Lock the protocol database\r
257   //\r
258   CoreAcquireProtocolLock ();\r
259 \r
260   //\r
261   // Check that Protocol exists on UserHandle, and Interface matches the interface in the database\r
262   //\r
263   Prot = CoreFindProtocolInterface (UserHandle, Protocol, OldInterface);\r
264   if (Prot == NULL) {\r
265     CoreReleaseProtocolLock ();\r
266     return EFI_NOT_FOUND;\r
267   }\r
268 \r
269   //\r
270   // Attempt to disconnect all drivers that are using the protocol interface that is about to be reinstalled\r
271   //\r
272   Status = CoreDisconnectControllersUsingProtocolInterface (\r
273              UserHandle,\r
274              Prot\r
275              );\r
276   if (EFI_ERROR (Status)) {\r
277     //\r
278     // One or more drivers refused to release, so return the error\r
279     //\r
280     CoreReleaseProtocolLock ();\r
281     return Status;\r
282   }\r
283 \r
284   //\r
285   // Remove the protocol interface from the protocol\r
286   //\r
287   Prot = CoreRemoveInterfaceFromProtocol (Handle, Protocol, OldInterface);\r
288 \r
289   if (Prot == NULL) {\r
290     CoreReleaseProtocolLock ();\r
291     return EFI_NOT_FOUND;\r
292   }\r
293 \r
294   ProtEntry = Prot->Protocol;\r
295 \r
296   //\r
297   // Update the interface on the protocol\r
298   //\r
299   Prot->Interface = NewInterface;\r
300 \r
301   //\r
302   // Add this protocol interface to the tail of the\r
303   // protocol entry\r
304   //\r
305   InsertTailList (&ProtEntry->Protocols, &Prot->ByProtocol);\r
306 \r
307   //\r
308   // Update the Key to show that the handle has been created/modified\r
309   //\r
310   gHandleDatabaseKey++;\r
311   Handle->Key = gHandleDatabaseKey;\r
312 \r
313   //\r
314   // Release the lock and connect all drivers to UserHandle\r
315   //\r
316   CoreReleaseProtocolLock ();\r
317   Status = CoreConnectController (\r
318                   UserHandle, \r
319                   NULL, \r
320                   NULL, \r
321                   TRUE\r
322                   );\r
323   CoreAcquireProtocolLock ();\r
324   \r
325   //\r
326   // Notify the notification list for this protocol\r
327   //\r
328   CoreNotifyProtocolEntry (ProtEntry);\r
329 \r
330   CoreReleaseProtocolLock ();\r
331   \r
332   return EFI_SUCCESS;\r
333 }\r