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