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