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