]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/PiSmmCore/Handle.c
MdeModulePkg/Core: allow HeapGuard even before CpuArchProtocol installed
[mirror_edk2.git] / MdeModulePkg / Core / PiSmmCore / Handle.c
CommitLineData
e42e9404 1/** @file\r
2 SMM handle & protocol handling.\r
3\r
c01f13d5 4 Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.<BR>\r
e42e9404 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
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