]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/PiSmmCore/Handle.c
MdeModulePkg/S3SmmInitDone.h: Fix copyright coding style error.
[mirror_edk2.git] / MdeModulePkg / Core / PiSmmCore / Handle.c
CommitLineData
e42e9404 1/** @file\r
2 SMM handle & protocol handling.\r
3\r
d1102dba
LG
4 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>\r
5 This program and the accompanying materials are licensed and made available\r
6 under the terms and conditions of the BSD License which accompanies this\r
7 distribution. The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
9\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
e42e9404 12\r
13**/\r
14\r
15#include "PiSmmCore.h"\r
16\r
17//\r
18// mProtocolDatabase - A list of all protocols in the system. (simple list for now)\r
19// gHandleList - A list of all the handles in the system\r
20//\r
21LIST_ENTRY mProtocolDatabase = INITIALIZE_LIST_HEAD_VARIABLE (mProtocolDatabase);\r
22LIST_ENTRY gHandleList = INITIALIZE_LIST_HEAD_VARIABLE (gHandleList);\r
23\r
24/**\r
25 Check whether a handle is a valid EFI_HANDLE\r
26\r
27 @param UserHandle The handle to check\r
28\r
29 @retval EFI_INVALID_PARAMETER The handle is NULL or not a valid EFI_HANDLE.\r
30 @retval EFI_SUCCESS The handle is valid EFI_HANDLE.\r
31\r
32**/\r
33EFI_STATUS\r
34SmmValidateHandle (\r
35 IN EFI_HANDLE UserHandle\r
36 )\r
37{\r
38 IHANDLE *Handle;\r
39\r
40 Handle = (IHANDLE *)UserHandle;\r
41 if (Handle == NULL) {\r
42 return EFI_INVALID_PARAMETER;\r
43 }\r
44 if (Handle->Signature != EFI_HANDLE_SIGNATURE) {\r
45 return EFI_INVALID_PARAMETER;\r
46 }\r
47 return EFI_SUCCESS;\r
48}\r
49\r
50/**\r
51 Finds the protocol entry for the requested protocol.\r
52\r
53 @param Protocol The ID of the protocol\r
54 @param Create Create a new entry if not found\r
55\r
56 @return Protocol entry\r
57\r
58**/\r
59PROTOCOL_ENTRY *\r
60SmmFindProtocolEntry (\r
61 IN EFI_GUID *Protocol,\r
62 IN BOOLEAN Create\r
63 )\r
64{\r
65 LIST_ENTRY *Link;\r
66 PROTOCOL_ENTRY *Item;\r
67 PROTOCOL_ENTRY *ProtEntry;\r
68\r
69 //\r
70 // Search the database for the matching GUID\r
71 //\r
72\r
73 ProtEntry = NULL;\r
74 for (Link = mProtocolDatabase.ForwardLink;\r
75 Link != &mProtocolDatabase;\r
76 Link = Link->ForwardLink) {\r
77\r
78 Item = CR(Link, PROTOCOL_ENTRY, AllEntries, PROTOCOL_ENTRY_SIGNATURE);\r
79 if (CompareGuid (&Item->ProtocolID, Protocol)) {\r
80 //\r
81 // This is the protocol entry\r
82 //\r
83 ProtEntry = Item;\r
84 break;\r
85 }\r
86 }\r
87\r
88 //\r
89 // If the protocol entry was not found and Create is TRUE, then\r
90 // allocate a new entry\r
91 //\r
92 if ((ProtEntry == NULL) && Create) {\r
93 ProtEntry = AllocatePool (sizeof(PROTOCOL_ENTRY));\r
94 if (ProtEntry != NULL) {\r
95 //\r
96 // Initialize new protocol entry structure\r
97 //\r
98 ProtEntry->Signature = PROTOCOL_ENTRY_SIGNATURE;\r
99 CopyGuid ((VOID *)&ProtEntry->ProtocolID, Protocol);\r
100 InitializeListHead (&ProtEntry->Protocols);\r
101 InitializeListHead (&ProtEntry->Notify);\r
102\r
103 //\r
104 // Add it to protocol database\r
105 //\r
106 InsertTailList (&mProtocolDatabase, &ProtEntry->AllEntries);\r
107 }\r
108 }\r
109 return ProtEntry;\r
110}\r
111\r
112/**\r
113 Finds the protocol instance for the requested handle and protocol.\r
114 Note: This function doesn't do parameters checking, it's caller's responsibility\r
115 to pass in valid parameters.\r
116\r
117 @param Handle The handle to search the protocol on\r
118 @param Protocol GUID of the protocol\r
119 @param Interface The interface for the protocol being searched\r
120\r
121 @return Protocol instance (NULL: Not found)\r
122\r
123**/\r
124PROTOCOL_INTERFACE *\r
125SmmFindProtocolInterface (\r
126 IN IHANDLE *Handle,\r
127 IN EFI_GUID *Protocol,\r
128 IN VOID *Interface\r
129 )\r
130{\r
131 PROTOCOL_INTERFACE *Prot;\r
132 PROTOCOL_ENTRY *ProtEntry;\r
133 LIST_ENTRY *Link;\r
134\r
135 Prot = NULL;\r
136\r
137 //\r
138 // Lookup the protocol entry for this protocol ID\r
139 //\r
140 ProtEntry = SmmFindProtocolEntry (Protocol, FALSE);\r
141 if (ProtEntry != NULL) {\r
142 //\r
143 // Look at each protocol interface for any matches\r
144 //\r
145 for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link=Link->ForwardLink) {\r
146 //\r
147 // If this protocol interface matches, remove it\r
148 //\r
149 Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);\r
150 if (Prot->Interface == Interface && Prot->Protocol == ProtEntry) {\r
151 break;\r
152 }\r
153 Prot = NULL;\r
154 }\r
155 }\r
156 return Prot;\r
157}\r
158\r
159/**\r
160 Wrapper function to SmmInstallProtocolInterfaceNotify. This is the public API which\r
161 Calls the private one which contains a BOOLEAN parameter for notifications\r
162\r
163 @param UserHandle The handle to install the protocol handler on,\r
164 or NULL if a new handle is to be allocated\r
165 @param Protocol The protocol to add to the handle\r
166 @param InterfaceType Indicates whether Interface is supplied in\r
167 native form.\r
168 @param Interface The interface for the protocol being added\r
169\r
170 @return Status code\r
171\r
172**/\r
173EFI_STATUS\r
174EFIAPI\r
175SmmInstallProtocolInterface (\r
176 IN OUT EFI_HANDLE *UserHandle,\r
177 IN EFI_GUID *Protocol,\r
178 IN EFI_INTERFACE_TYPE InterfaceType,\r
179 IN VOID *Interface\r
180 )\r
181{\r
182 return SmmInstallProtocolInterfaceNotify (\r
183 UserHandle,\r
184 Protocol,\r
185 InterfaceType,\r
186 Interface,\r
187 TRUE\r
188 );\r
189}\r
190\r
191/**\r
192 Installs a protocol interface into the boot services environment.\r
193\r
194 @param UserHandle The handle to install the protocol handler on,\r
195 or NULL if a new handle is to be allocated\r
196 @param Protocol The protocol to add to the handle\r
197 @param InterfaceType Indicates whether Interface is supplied in\r
198 native form.\r
199 @param Interface The interface for the protocol being added\r
200 @param Notify indicates whether notify the notification list\r
201 for this protocol\r
202\r
203 @retval EFI_INVALID_PARAMETER Invalid parameter\r
204 @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate\r
205 @retval EFI_SUCCESS Protocol interface successfully installed\r
206\r
207**/\r
208EFI_STATUS\r
209SmmInstallProtocolInterfaceNotify (\r
210 IN OUT EFI_HANDLE *UserHandle,\r
211 IN EFI_GUID *Protocol,\r
212 IN EFI_INTERFACE_TYPE InterfaceType,\r
213 IN VOID *Interface,\r
214 IN BOOLEAN Notify\r
215 )\r
216{\r
217 PROTOCOL_INTERFACE *Prot;\r
218 PROTOCOL_ENTRY *ProtEntry;\r
219 IHANDLE *Handle;\r
220 EFI_STATUS Status;\r
221 VOID *ExistingInterface;\r
222\r
223 //\r
224 // returns EFI_INVALID_PARAMETER if InterfaceType is invalid.\r
225 // Also added check for invalid UserHandle and Protocol pointers.\r
226 //\r
227 if (UserHandle == NULL || Protocol == NULL) {\r
228 return EFI_INVALID_PARAMETER;\r
229 }\r
230\r
231 if (InterfaceType != EFI_NATIVE_INTERFACE) {\r
232 return EFI_INVALID_PARAMETER;\r
233 }\r
234\r
235 //\r
236 // Print debug message\r
237 //\r
238 DEBUG((DEBUG_LOAD | DEBUG_INFO, "SmmInstallProtocolInterface: %g %p\n", Protocol, Interface));\r
239\r
240 Status = EFI_OUT_OF_RESOURCES;\r
241 Prot = NULL;\r
242 Handle = NULL;\r
243\r
244 if (*UserHandle != NULL) {\r
245 Status = SmmHandleProtocol (*UserHandle, Protocol, (VOID **)&ExistingInterface);\r
246 if (!EFI_ERROR (Status)) {\r
247 return EFI_INVALID_PARAMETER;\r
248 }\r
249 }\r
250\r
251 //\r
252 // Lookup the Protocol Entry for the requested protocol\r
253 //\r
254 ProtEntry = SmmFindProtocolEntry (Protocol, TRUE);\r
255 if (ProtEntry == NULL) {\r
256 goto Done;\r
257 }\r
258\r
259 //\r
260 // Allocate a new protocol interface structure\r
261 //\r
262 Prot = AllocateZeroPool (sizeof(PROTOCOL_INTERFACE));\r
263 if (Prot == NULL) {\r
264 Status = EFI_OUT_OF_RESOURCES;\r
265 goto Done;\r
266 }\r
267\r
268 //\r
269 // If caller didn't supply a handle, allocate a new one\r
270 //\r
271 Handle = (IHANDLE *)*UserHandle;\r
272 if (Handle == NULL) {\r
273 Handle = AllocateZeroPool (sizeof(IHANDLE));\r
274 if (Handle == NULL) {\r
275 Status = EFI_OUT_OF_RESOURCES;\r
276 goto Done;\r
277 }\r
278\r
279 //\r
280 // Initialize new handler structure\r
281 //\r
282 Handle->Signature = EFI_HANDLE_SIGNATURE;\r
283 InitializeListHead (&Handle->Protocols);\r
284\r
285 //\r
286 // Add this handle to the list global list of all handles\r
287 // in the system\r
288 //\r
289 InsertTailList (&gHandleList, &Handle->AllHandles);\r
c01f13d5
SZ
290 } else {\r
291 Status = SmmValidateHandle (Handle);\r
292 if (EFI_ERROR (Status)) {\r
293 DEBUG((DEBUG_ERROR, "SmmInstallProtocolInterface: input handle at 0x%x is invalid\n", Handle));\r
294 goto Done;\r
295 }\r
e42e9404 296 }\r
297\r
298 //\r
299 // Each interface that is added must be unique\r
300 //\r
301 ASSERT (SmmFindProtocolInterface (Handle, Protocol, Interface) == NULL);\r
302\r
303 //\r
304 // Initialize the protocol interface structure\r
305 //\r
306 Prot->Signature = PROTOCOL_INTERFACE_SIGNATURE;\r
307 Prot->Handle = Handle;\r
308 Prot->Protocol = ProtEntry;\r
309 Prot->Interface = Interface;\r
310\r
311 //\r
312 // Add this protocol interface to the head of the supported\r
313 // protocol list for this handle\r
314 //\r
315 InsertHeadList (&Handle->Protocols, &Prot->Link);\r
316\r
317 //\r
318 // Add this protocol interface to the tail of the\r
319 // protocol entry\r
320 //\r
321 InsertTailList (&ProtEntry->Protocols, &Prot->ByProtocol);\r
322\r
323 //\r
324 // Notify the notification list for this protocol\r
325 //\r
326 if (Notify) {\r
327 SmmNotifyProtocol (Prot);\r
328 }\r
329 Status = EFI_SUCCESS;\r
330\r
331Done:\r
332 if (!EFI_ERROR (Status)) {\r
333 //\r
334 // Return the new handle back to the caller\r
335 //\r
336 *UserHandle = Handle;\r
337 } else {\r
338 //\r
339 // There was an error, clean up\r
340 //\r
341 if (Prot != NULL) {\r
342 FreePool (Prot);\r
343 }\r
c01f13d5 344 DEBUG((DEBUG_ERROR, "SmmInstallProtocolInterface: %g %p failed with %r\n", Protocol, Interface, Status));\r
e42e9404 345 }\r
346 return Status;\r
347}\r
348\r
349/**\r
350 Uninstalls all instances of a protocol:interfacer from a handle.\r
351 If the last protocol interface is remove from the handle, the\r
352 handle is freed.\r
353\r
354 @param UserHandle The handle to remove the protocol handler from\r
355 @param Protocol The protocol, of protocol:interface, to remove\r
356 @param Interface The interface, of protocol:interface, to remove\r
357\r
358 @retval EFI_INVALID_PARAMETER Protocol is NULL.\r
359 @retval EFI_SUCCESS Protocol interface successfully uninstalled.\r
360\r
361**/\r
362EFI_STATUS\r
363EFIAPI\r
364SmmUninstallProtocolInterface (\r
365 IN EFI_HANDLE UserHandle,\r
366 IN EFI_GUID *Protocol,\r
367 IN VOID *Interface\r
368 )\r
369{\r
370 EFI_STATUS Status;\r
371 IHANDLE *Handle;\r
372 PROTOCOL_INTERFACE *Prot;\r
373\r
374 //\r
375 // Check that Protocol is valid\r
376 //\r
377 if (Protocol == NULL) {\r
378 return EFI_INVALID_PARAMETER;\r
379 }\r
380\r
381 //\r
382 // Check that UserHandle is a valid handle\r
383 //\r
384 Status = SmmValidateHandle (UserHandle);\r
385 if (EFI_ERROR (Status)) {\r
386 return Status;\r
387 }\r
388\r
389 //\r
390 // Check that Protocol exists on UserHandle, and Interface matches the interface in the database\r
391 //\r
392 Prot = SmmFindProtocolInterface (UserHandle, Protocol, Interface);\r
393 if (Prot == NULL) {\r
394 return EFI_NOT_FOUND;\r
395 }\r
396\r
397 //\r
398 // Remove the protocol interface from the protocol\r
399 //\r
400 Status = EFI_NOT_FOUND;\r
401 Handle = (IHANDLE *)UserHandle;\r
402 Prot = SmmRemoveInterfaceFromProtocol (Handle, Protocol, Interface);\r
403\r
404 if (Prot != NULL) {\r
405 //\r
406 // Remove the protocol interface from the handle\r
407 //\r
408 RemoveEntryList (&Prot->Link);\r
409\r
410 //\r
411 // Free the memory\r
412 //\r
413 Prot->Signature = 0;\r
414 FreePool (Prot);\r
415 Status = EFI_SUCCESS;\r
416 }\r
417\r
418 //\r
419 // If there are no more handlers for the handle, free the handle\r
420 //\r
421 if (IsListEmpty (&Handle->Protocols)) {\r
422 Handle->Signature = 0;\r
423 RemoveEntryList (&Handle->AllHandles);\r
424 FreePool (Handle);\r
425 }\r
426 return Status;\r
427}\r
428\r
429/**\r
430 Locate a certain GUID protocol interface in a Handle's protocols.\r
431\r
432 @param UserHandle The handle to obtain the protocol interface on\r
433 @param Protocol The GUID of the protocol\r
434\r
435 @return The requested protocol interface for the handle\r
436\r
437**/\r
438PROTOCOL_INTERFACE *\r
439SmmGetProtocolInterface (\r
440 IN EFI_HANDLE UserHandle,\r
441 IN EFI_GUID *Protocol\r
442 )\r
443{\r
444 EFI_STATUS Status;\r
445 PROTOCOL_ENTRY *ProtEntry;\r
446 PROTOCOL_INTERFACE *Prot;\r
447 IHANDLE *Handle;\r
448 LIST_ENTRY *Link;\r
449\r
450 Status = SmmValidateHandle (UserHandle);\r
451 if (EFI_ERROR (Status)) {\r
452 return NULL;\r
453 }\r
454\r
455 Handle = (IHANDLE *)UserHandle;\r
456\r
457 //\r
458 // Look at each protocol interface for a match\r
459 //\r
460 for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) {\r
461 Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);\r
462 ProtEntry = Prot->Protocol;\r
463 if (CompareGuid (&ProtEntry->ProtocolID, Protocol)) {\r
464 return Prot;\r
465 }\r
466 }\r
467 return NULL;\r
468}\r
469\r
470/**\r
471 Queries a handle to determine if it supports a specified protocol.\r
472\r
473 @param UserHandle The handle being queried.\r
474 @param Protocol The published unique identifier of the protocol.\r
475 @param Interface Supplies the address where a pointer to the\r
476 corresponding Protocol Interface is returned.\r
477\r
478 @retval EFI_SUCCESS The interface information for the specified protocol was returned.\r
479 @retval EFI_UNSUPPORTED The device does not support the specified protocol.\r
480 @retval EFI_INVALID_PARAMETER Handle is not a valid EFI_HANDLE..\r
481 @retval EFI_INVALID_PARAMETER Protocol is NULL.\r
482 @retval EFI_INVALID_PARAMETER Interface is NULL.\r
483\r
484**/\r
485EFI_STATUS\r
486EFIAPI\r
487SmmHandleProtocol (\r
488 IN EFI_HANDLE UserHandle,\r
489 IN EFI_GUID *Protocol,\r
490 OUT VOID **Interface\r
491 )\r
492{\r
493 EFI_STATUS Status;\r
494 PROTOCOL_INTERFACE *Prot;\r
495\r
496 //\r
497 // Check for invalid Protocol\r
498 //\r
499 if (Protocol == NULL) {\r
500 return EFI_INVALID_PARAMETER;\r
501 }\r
502\r
503 //\r
504 // Check for invalid Interface\r
505 //\r
506 if (Interface == NULL) {\r
507 return EFI_INVALID_PARAMETER;\r
508 } else {\r
509 *Interface = NULL;\r
510 }\r
511\r
512 //\r
513 // Check for invalid UserHandle\r
514 //\r
515 Status = SmmValidateHandle (UserHandle);\r
516 if (EFI_ERROR (Status)) {\r
517 return Status;\r
518 }\r
519\r
520 //\r
521 // Look at each protocol interface for a match\r
522 //\r
523 Prot = SmmGetProtocolInterface (UserHandle, Protocol);\r
524 if (Prot == NULL) {\r
525 return EFI_UNSUPPORTED;\r
526 }\r
527\r
528 //\r
529 // This is the protocol interface entry for this protocol\r
530 //\r
531 *Interface = Prot->Interface;\r
532\r
533 return EFI_SUCCESS;\r
534}\r