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