]> git.proxmox.com Git - mirror_edk2.git/blob - StandaloneMmPkg/Core/Handle.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[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 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10 #include "StandaloneMmCore.h"
11
12 //
13 // mProtocolDatabase - A list of all protocols in the system. (simple list for now)
14 // gHandleList - A list of all the handles in the system
15 //
16 LIST_ENTRY mProtocolDatabase = INITIALIZE_LIST_HEAD_VARIABLE (mProtocolDatabase);
17 LIST_ENTRY gHandleList = INITIALIZE_LIST_HEAD_VARIABLE (gHandleList);
18
19 /**
20 Check whether a handle is a valid EFI_HANDLE
21
22 @param UserHandle The handle to check
23
24 @retval EFI_INVALID_PARAMETER The handle is NULL or not a valid EFI_HANDLE.
25 @retval EFI_SUCCESS The handle is valid EFI_HANDLE.
26
27 **/
28 EFI_STATUS
29 MmValidateHandle (
30 IN EFI_HANDLE UserHandle
31 )
32 {
33 IHANDLE *Handle;
34
35 Handle = (IHANDLE *)UserHandle;
36 if (Handle == NULL) {
37 return EFI_INVALID_PARAMETER;
38 }
39
40 if (Handle->Signature != EFI_HANDLE_SIGNATURE) {
41 return EFI_INVALID_PARAMETER;
42 }
43
44 return EFI_SUCCESS;
45 }
46
47 /**
48 Finds the protocol entry for the requested protocol.
49
50 @param Protocol The ID of the protocol
51 @param Create Create a new entry if not found
52
53 @return Protocol entry
54
55 **/
56 PROTOCOL_ENTRY *
57 MmFindProtocolEntry (
58 IN EFI_GUID *Protocol,
59 IN BOOLEAN Create
60 )
61 {
62 LIST_ENTRY *Link;
63 PROTOCOL_ENTRY *Item;
64 PROTOCOL_ENTRY *ProtEntry;
65
66 //
67 // Search the database for the matching GUID
68 //
69
70 ProtEntry = NULL;
71 for (Link = mProtocolDatabase.ForwardLink;
72 Link != &mProtocolDatabase;
73 Link = Link->ForwardLink)
74 {
75 Item = CR (Link, PROTOCOL_ENTRY, AllEntries, PROTOCOL_ENTRY_SIGNATURE);
76 if (CompareGuid (&Item->ProtocolID, Protocol)) {
77 //
78 // This is the protocol entry
79 //
80 ProtEntry = Item;
81 break;
82 }
83 }
84
85 //
86 // If the protocol entry was not found and Create is TRUE, then
87 // allocate a new entry
88 //
89 if ((ProtEntry == NULL) && Create) {
90 ProtEntry = AllocatePool (sizeof (PROTOCOL_ENTRY));
91 if (ProtEntry != NULL) {
92 //
93 // Initialize new protocol entry structure
94 //
95 ProtEntry->Signature = PROTOCOL_ENTRY_SIGNATURE;
96 CopyGuid ((VOID *)&ProtEntry->ProtocolID, Protocol);
97 InitializeListHead (&ProtEntry->Protocols);
98 InitializeListHead (&ProtEntry->Notify);
99
100 //
101 // Add it to protocol database
102 //
103 InsertTailList (&mProtocolDatabase, &ProtEntry->AllEntries);
104 }
105 }
106
107 return ProtEntry;
108 }
109
110 /**
111 Finds the protocol instance for the requested handle and protocol.
112 Note: This function doesn't do parameters checking, it's caller's responsibility
113 to pass in valid parameters.
114
115 @param Handle The handle to search the protocol on
116 @param Protocol GUID of the protocol
117 @param Interface The interface for the protocol being searched
118
119 @return Protocol instance (NULL: Not found)
120
121 **/
122 PROTOCOL_INTERFACE *
123 MmFindProtocolInterface (
124 IN IHANDLE *Handle,
125 IN EFI_GUID *Protocol,
126 IN VOID *Interface
127 )
128 {
129 PROTOCOL_INTERFACE *Prot;
130 PROTOCOL_ENTRY *ProtEntry;
131 LIST_ENTRY *Link;
132
133 Prot = NULL;
134
135 //
136 // Lookup the protocol entry for this protocol ID
137 //
138 ProtEntry = MmFindProtocolEntry (Protocol, FALSE);
139 if (ProtEntry != NULL) {
140 //
141 // Look at each protocol interface for any matches
142 //
143 for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) {
144 //
145 // If this protocol interface matches, remove it
146 //
147 Prot = CR (Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
148 if ((Prot->Interface == Interface) && (Prot->Protocol == ProtEntry)) {
149 break;
150 }
151
152 Prot = NULL;
153 }
154 }
155
156 return Prot;
157 }
158
159 /**
160 Wrapper function to MmInstallProtocolInterfaceNotify. 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 MmInstallProtocolInterface (
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 MmInstallProtocolInterfaceNotify (
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 MmInstallProtocolInterfaceNotify (
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, "MmInstallProtocolInterface: %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 = MmHandleProtocol (*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 = MmFindProtocolEntry (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 }
291
292 Status = MmValidateHandle (Handle);
293 if (EFI_ERROR (Status)) {
294 goto Done;
295 }
296
297 //
298 // Each interface that is added must be unique
299 //
300 ASSERT (MmFindProtocolInterface (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 MmNotifyProtocol (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
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 MmUninstallProtocolInterface (
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 = MmValidateHandle (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 = MmFindProtocolInterface (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 = MmRemoveInterfaceFromProtocol (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
427 return Status;
428 }
429
430 /**
431 Locate a certain GUID protocol interface in a Handle's protocols.
432
433 @param UserHandle The handle to obtain the protocol interface on
434 @param Protocol The GUID of the protocol
435
436 @return The requested protocol interface for the handle
437
438 **/
439 PROTOCOL_INTERFACE *
440 MmGetProtocolInterface (
441 IN EFI_HANDLE UserHandle,
442 IN EFI_GUID *Protocol
443 )
444 {
445 EFI_STATUS Status;
446 PROTOCOL_ENTRY *ProtEntry;
447 PROTOCOL_INTERFACE *Prot;
448 IHANDLE *Handle;
449 LIST_ENTRY *Link;
450
451 Status = MmValidateHandle (UserHandle);
452 if (EFI_ERROR (Status)) {
453 return NULL;
454 }
455
456 Handle = (IHANDLE *)UserHandle;
457
458 //
459 // Look at each protocol interface for a match
460 //
461 for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) {
462 Prot = CR (Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
463 ProtEntry = Prot->Protocol;
464 if (CompareGuid (&ProtEntry->ProtocolID, Protocol)) {
465 return Prot;
466 }
467 }
468
469 return NULL;
470 }
471
472 /**
473 Queries a handle to determine if it supports a specified protocol.
474
475 @param UserHandle The handle being queried.
476 @param Protocol The published unique identifier of the protocol.
477 @param Interface Supplies the address where a pointer to the
478 corresponding Protocol Interface is returned.
479
480 @retval EFI_SUCCESS The interface information for the specified protocol was returned.
481 @retval EFI_UNSUPPORTED The device does not support the specified protocol.
482 @retval EFI_INVALID_PARAMETER Handle is not a valid EFI_HANDLE..
483 @retval EFI_INVALID_PARAMETER Protocol is NULL.
484 @retval EFI_INVALID_PARAMETER Interface is NULL.
485
486 **/
487 EFI_STATUS
488 EFIAPI
489 MmHandleProtocol (
490 IN EFI_HANDLE UserHandle,
491 IN EFI_GUID *Protocol,
492 OUT VOID **Interface
493 )
494 {
495 EFI_STATUS Status;
496 PROTOCOL_INTERFACE *Prot;
497
498 //
499 // Check for invalid Protocol
500 //
501 if (Protocol == NULL) {
502 return EFI_INVALID_PARAMETER;
503 }
504
505 //
506 // Check for invalid Interface
507 //
508 if (Interface == NULL) {
509 return EFI_INVALID_PARAMETER;
510 } else {
511 *Interface = NULL;
512 }
513
514 //
515 // Check for invalid UserHandle
516 //
517 Status = MmValidateHandle (UserHandle);
518 if (EFI_ERROR (Status)) {
519 return Status;
520 }
521
522 //
523 // Look at each protocol interface for a match
524 //
525 Prot = MmGetProtocolInterface (UserHandle, Protocol);
526 if (Prot == NULL) {
527 return EFI_UNSUPPORTED;
528 }
529
530 //
531 // This is the protocol interface entry for this protocol
532 //
533 *Interface = Prot->Interface;
534
535 return EFI_SUCCESS;
536 }