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