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