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