]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Dxe/Hand/Locate.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / Hand / Locate.c
1 /** @file
2 Locate handle functions
3
4 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include "DxeMain.h"
10 #include "Handle.h"
11
12 //
13 // ProtocolRequest - Last LocateHandle request ID
14 //
15 UINTN mEfiLocateHandleRequest = 0;
16
17 //
18 // Internal prototypes
19 //
20
21 typedef struct {
22 EFI_GUID *Protocol;
23 VOID *SearchKey;
24 LIST_ENTRY *Position;
25 PROTOCOL_ENTRY *ProtEntry;
26 } LOCATE_POSITION;
27
28 typedef
29 IHANDLE *
30 (*CORE_GET_NEXT) (
31 IN OUT LOCATE_POSITION *Position,
32 OUT VOID **Interface
33 );
34
35 /**
36 Routine to get the next Handle, when you are searching for all handles.
37
38 @param Position Information about which Handle to seach for.
39 @param Interface Return the interface structure for the matching
40 protocol.
41
42 @return An pointer to IHANDLE if the next Position is not the end of the list.
43 Otherwise,NULL is returned.
44
45 **/
46 IHANDLE *
47 CoreGetNextLocateAllHandles (
48 IN OUT LOCATE_POSITION *Position,
49 OUT VOID **Interface
50 );
51
52 /**
53 Routine to get the next Handle, when you are searching for register protocol
54 notifies.
55
56 @param Position Information about which Handle to seach for.
57 @param Interface Return the interface structure for the matching
58 protocol.
59
60 @return An pointer to IHANDLE if the next Position is not the end of the list.
61 Otherwise,NULL is returned.
62
63 **/
64 IHANDLE *
65 CoreGetNextLocateByRegisterNotify (
66 IN OUT LOCATE_POSITION *Position,
67 OUT VOID **Interface
68 );
69
70 /**
71 Routine to get the next Handle, when you are searching for a given protocol.
72
73 @param Position Information about which Handle to seach for.
74 @param Interface Return the interface structure for the matching
75 protocol.
76
77 @return An pointer to IHANDLE if the next Position is not the end of the list.
78 Otherwise,NULL is returned.
79
80 **/
81 IHANDLE *
82 CoreGetNextLocateByProtocol (
83 IN OUT LOCATE_POSITION *Position,
84 OUT VOID **Interface
85 );
86
87 /**
88 Internal function for locating the requested handle(s) and returns them in Buffer.
89 The caller should already have acquired the ProtocolLock.
90
91 @param SearchType The type of search to perform to locate the
92 handles
93 @param Protocol The protocol to search for
94 @param SearchKey Dependant on SearchType
95 @param BufferSize On input the size of Buffer. On output the
96 size of data returned.
97 @param Buffer The buffer to return the results in
98
99 @retval EFI_BUFFER_TOO_SMALL Buffer too small, required buffer size is
100 returned in BufferSize.
101 @retval EFI_INVALID_PARAMETER Invalid parameter
102 @retval EFI_SUCCESS Successfully found the requested handle(s) and
103 returns them in Buffer.
104
105 **/
106 EFI_STATUS
107 InternalCoreLocateHandle (
108 IN EFI_LOCATE_SEARCH_TYPE SearchType,
109 IN EFI_GUID *Protocol OPTIONAL,
110 IN VOID *SearchKey OPTIONAL,
111 IN OUT UINTN *BufferSize,
112 OUT EFI_HANDLE *Buffer
113 )
114 {
115 EFI_STATUS Status;
116 LOCATE_POSITION Position;
117 PROTOCOL_NOTIFY *ProtNotify;
118 CORE_GET_NEXT GetNext;
119 UINTN ResultSize;
120 IHANDLE *Handle;
121 IHANDLE **ResultBuffer;
122 VOID *Interface;
123
124 if (BufferSize == NULL) {
125 return EFI_INVALID_PARAMETER;
126 }
127
128 if ((*BufferSize > 0) && (Buffer == NULL)) {
129 return EFI_INVALID_PARAMETER;
130 }
131
132 GetNext = NULL;
133
134 //
135 // Set initial position
136 //
137 Position.Protocol = Protocol;
138 Position.SearchKey = SearchKey;
139 Position.Position = &gHandleList;
140
141 ResultSize = 0;
142 ResultBuffer = (IHANDLE **)Buffer;
143 Status = EFI_SUCCESS;
144
145 //
146 // Get the search function based on type
147 //
148 switch (SearchType) {
149 case AllHandles:
150 GetNext = CoreGetNextLocateAllHandles;
151 break;
152
153 case ByRegisterNotify:
154 //
155 // Must have SearchKey for locate ByRegisterNotify
156 //
157 if (SearchKey == NULL) {
158 Status = EFI_INVALID_PARAMETER;
159 break;
160 }
161
162 GetNext = CoreGetNextLocateByRegisterNotify;
163 break;
164
165 case ByProtocol:
166 GetNext = CoreGetNextLocateByProtocol;
167 if (Protocol == NULL) {
168 Status = EFI_INVALID_PARAMETER;
169 break;
170 }
171
172 //
173 // Look up the protocol entry and set the head pointer
174 //
175 Position.ProtEntry = CoreFindProtocolEntry (Protocol, FALSE);
176 if (Position.ProtEntry == NULL) {
177 Status = EFI_NOT_FOUND;
178 break;
179 }
180
181 Position.Position = &Position.ProtEntry->Protocols;
182 break;
183
184 default:
185 Status = EFI_INVALID_PARAMETER;
186 break;
187 }
188
189 if (EFI_ERROR (Status)) {
190 return Status;
191 }
192
193 ASSERT (GetNext != NULL);
194 //
195 // Enumerate out the matching handles
196 //
197 mEfiLocateHandleRequest += 1;
198 for ( ; ;) {
199 //
200 // Get the next handle. If no more handles, stop
201 //
202 Handle = GetNext (&Position, &Interface);
203 if (NULL == Handle) {
204 break;
205 }
206
207 //
208 // Increase the resulting buffer size, and if this handle
209 // fits return it
210 //
211 ResultSize += sizeof (Handle);
212 if (ResultSize <= *BufferSize) {
213 *ResultBuffer = Handle;
214 ResultBuffer += 1;
215 }
216 }
217
218 //
219 // If the result is a zero length buffer, then there were no
220 // matching handles
221 //
222 if (ResultSize == 0) {
223 Status = EFI_NOT_FOUND;
224 } else {
225 //
226 // Return the resulting buffer size. If it's larger than what
227 // was passed, then set the error code
228 //
229 if (ResultSize > *BufferSize) {
230 Status = EFI_BUFFER_TOO_SMALL;
231 }
232
233 *BufferSize = ResultSize;
234
235 if ((SearchType == ByRegisterNotify) && !EFI_ERROR (Status)) {
236 //
237 // If this is a search by register notify and a handle was
238 // returned, update the register notification position
239 //
240 ASSERT (SearchKey != NULL);
241 ProtNotify = SearchKey;
242 ProtNotify->Position = ProtNotify->Position->ForwardLink;
243 }
244 }
245
246 return Status;
247 }
248
249 /**
250 Locates the requested handle(s) and returns them in Buffer.
251
252 @param SearchType The type of search to perform to locate the
253 handles
254 @param Protocol The protocol to search for
255 @param SearchKey Dependant on SearchType
256 @param BufferSize On input the size of Buffer. On output the
257 size of data returned.
258 @param Buffer The buffer to return the results in
259
260 @retval EFI_BUFFER_TOO_SMALL Buffer too small, required buffer size is
261 returned in BufferSize.
262 @retval EFI_INVALID_PARAMETER Invalid parameter
263 @retval EFI_SUCCESS Successfully found the requested handle(s) and
264 returns them in Buffer.
265
266 **/
267 EFI_STATUS
268 EFIAPI
269 CoreLocateHandle (
270 IN EFI_LOCATE_SEARCH_TYPE SearchType,
271 IN EFI_GUID *Protocol OPTIONAL,
272 IN VOID *SearchKey OPTIONAL,
273 IN OUT UINTN *BufferSize,
274 OUT EFI_HANDLE *Buffer
275 )
276 {
277 EFI_STATUS Status;
278
279 //
280 // Lock the protocol database
281 //
282 CoreAcquireProtocolLock ();
283 Status = InternalCoreLocateHandle (SearchType, Protocol, SearchKey, BufferSize, Buffer);
284 CoreReleaseProtocolLock ();
285 return Status;
286 }
287
288 /**
289 Routine to get the next Handle, when you are searching for all handles.
290
291 @param Position Information about which Handle to seach for.
292 @param Interface Return the interface structure for the matching
293 protocol.
294
295 @return An pointer to IHANDLE if the next Position is not the end of the list.
296 Otherwise,NULL is returned.
297
298 **/
299 IHANDLE *
300 CoreGetNextLocateAllHandles (
301 IN OUT LOCATE_POSITION *Position,
302 OUT VOID **Interface
303 )
304 {
305 IHANDLE *Handle;
306
307 //
308 // Next handle
309 //
310 Position->Position = Position->Position->ForwardLink;
311
312 //
313 // If not at the end of the list, get the handle
314 //
315 Handle = NULL;
316 *Interface = NULL;
317 if (Position->Position != &gHandleList) {
318 Handle = CR (Position->Position, IHANDLE, AllHandles, EFI_HANDLE_SIGNATURE);
319 }
320
321 return Handle;
322 }
323
324 /**
325 Routine to get the next Handle, when you are searching for register protocol
326 notifies.
327
328 @param Position Information about which Handle to seach for.
329 @param Interface Return the interface structure for the matching
330 protocol.
331
332 @return An pointer to IHANDLE if the next Position is not the end of the list.
333 Otherwise,NULL is returned.
334
335 **/
336 IHANDLE *
337 CoreGetNextLocateByRegisterNotify (
338 IN OUT LOCATE_POSITION *Position,
339 OUT VOID **Interface
340 )
341 {
342 IHANDLE *Handle;
343 PROTOCOL_NOTIFY *ProtNotify;
344 PROTOCOL_INTERFACE *Prot;
345 LIST_ENTRY *Link;
346
347 Handle = NULL;
348 *Interface = NULL;
349 ProtNotify = Position->SearchKey;
350
351 //
352 // If this is the first request, get the next handle
353 //
354 if (ProtNotify != NULL) {
355 ASSERT (ProtNotify->Signature == PROTOCOL_NOTIFY_SIGNATURE);
356 Position->SearchKey = NULL;
357
358 //
359 // If not at the end of the list, get the next handle
360 //
361 Link = ProtNotify->Position->ForwardLink;
362 if (Link != &ProtNotify->Protocol->Protocols) {
363 Prot = CR (Link, PROTOCOL_INTERFACE, ByProtocol, PROTOCOL_INTERFACE_SIGNATURE);
364 Handle = Prot->Handle;
365 *Interface = Prot->Interface;
366 }
367 }
368
369 return Handle;
370 }
371
372 /**
373 Routine to get the next Handle, when you are searching for a given protocol.
374
375 @param Position Information about which Handle to seach for.
376 @param Interface Return the interface structure for the matching
377 protocol.
378
379 @return An pointer to IHANDLE if the next Position is not the end of the list.
380 Otherwise,NULL is returned.
381
382 **/
383 IHANDLE *
384 CoreGetNextLocateByProtocol (
385 IN OUT LOCATE_POSITION *Position,
386 OUT VOID **Interface
387 )
388 {
389 IHANDLE *Handle;
390 LIST_ENTRY *Link;
391 PROTOCOL_INTERFACE *Prot;
392
393 Handle = NULL;
394 *Interface = NULL;
395 for ( ; ;) {
396 //
397 // Next entry
398 //
399 Link = Position->Position->ForwardLink;
400 Position->Position = Link;
401
402 //
403 // If not at the end, return the handle
404 //
405 if (Link == &Position->ProtEntry->Protocols) {
406 Handle = NULL;
407 break;
408 }
409
410 //
411 // Get the handle
412 //
413 Prot = CR (Link, PROTOCOL_INTERFACE, ByProtocol, PROTOCOL_INTERFACE_SIGNATURE);
414 Handle = Prot->Handle;
415 *Interface = Prot->Interface;
416
417 //
418 // If this handle has not been returned this request, then
419 // return it now
420 //
421 if (Handle->LocateRequest != mEfiLocateHandleRequest) {
422 Handle->LocateRequest = mEfiLocateHandleRequest;
423 break;
424 }
425 }
426
427 return Handle;
428 }
429
430 /**
431 Locates the handle to a device on the device path that supports the specified protocol.
432
433 @param Protocol Specifies the protocol to search for.
434 @param DevicePath On input, a pointer to a pointer to the device path. On output, the device
435 path pointer is modified to point to the remaining part of the device
436 path.
437 @param Device A pointer to the returned device handle.
438
439 @retval EFI_SUCCESS The resulting handle was returned.
440 @retval EFI_NOT_FOUND No handles match the search.
441 @retval EFI_INVALID_PARAMETER Protocol is NULL.
442 @retval EFI_INVALID_PARAMETER DevicePath is NULL.
443 @retval EFI_INVALID_PARAMETER A handle matched the search and Device is NULL.
444
445 **/
446 EFI_STATUS
447 EFIAPI
448 CoreLocateDevicePath (
449 IN EFI_GUID *Protocol,
450 IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath,
451 OUT EFI_HANDLE *Device
452 )
453 {
454 INTN SourceSize;
455 INTN Size;
456 INTN BestMatch;
457 UINTN HandleCount;
458 UINTN Index;
459 EFI_STATUS Status;
460 EFI_HANDLE *Handles;
461 EFI_HANDLE Handle;
462 EFI_HANDLE BestDevice;
463 EFI_DEVICE_PATH_PROTOCOL *SourcePath;
464 EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath;
465
466 if (Protocol == NULL) {
467 return EFI_INVALID_PARAMETER;
468 }
469
470 if ((DevicePath == NULL) || (*DevicePath == NULL)) {
471 return EFI_INVALID_PARAMETER;
472 }
473
474 Handles = NULL;
475 BestDevice = NULL;
476 SourcePath = *DevicePath;
477 TmpDevicePath = SourcePath;
478 while (!IsDevicePathEnd (TmpDevicePath)) {
479 if (IsDevicePathEndInstance (TmpDevicePath)) {
480 //
481 // If DevicePath is a multi-instance device path,
482 // the function will operate on the first instance
483 //
484 break;
485 }
486
487 TmpDevicePath = NextDevicePathNode (TmpDevicePath);
488 }
489
490 SourceSize = (UINTN)TmpDevicePath - (UINTN)SourcePath;
491
492 //
493 // Get a list of all handles that support the requested protocol
494 //
495 Status = CoreLocateHandleBuffer (ByProtocol, Protocol, NULL, &HandleCount, &Handles);
496 if (EFI_ERROR (Status) || (HandleCount == 0)) {
497 return EFI_NOT_FOUND;
498 }
499
500 BestMatch = -1;
501 for (Index = 0; Index < HandleCount; Index += 1) {
502 Handle = Handles[Index];
503 Status = CoreHandleProtocol (Handle, &gEfiDevicePathProtocolGuid, (VOID **)&TmpDevicePath);
504 if (EFI_ERROR (Status)) {
505 //
506 // If this handle doesn't support device path, then skip it
507 //
508 continue;
509 }
510
511 //
512 // Check if DevicePath is first part of SourcePath
513 //
514 Size = GetDevicePathSize (TmpDevicePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL);
515 ASSERT (Size >= 0);
516 if ((Size <= SourceSize) && (CompareMem (SourcePath, TmpDevicePath, (UINTN)Size) == 0)) {
517 //
518 // If the size is equal to the best match, then we
519 // have a duplicate device path for 2 different device
520 // handles
521 //
522 ASSERT (Size != BestMatch);
523
524 //
525 // We've got a match, see if it's the best match so far
526 //
527 if (Size > BestMatch) {
528 BestMatch = Size;
529 BestDevice = Handle;
530 }
531 }
532 }
533
534 CoreFreePool (Handles);
535
536 //
537 // If there wasn't any match, then no parts of the device path was found.
538 // Which is strange since there is likely a "root level" device path in the system.
539 //
540 if (BestMatch == -1) {
541 return EFI_NOT_FOUND;
542 }
543
544 if (Device == NULL) {
545 return EFI_INVALID_PARAMETER;
546 }
547
548 *Device = BestDevice;
549
550 //
551 // Return the remaining part of the device path
552 //
553 *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)(((UINT8 *)SourcePath) + BestMatch);
554 return EFI_SUCCESS;
555 }
556
557 /**
558 Return the first Protocol Interface that matches the Protocol GUID. If
559 Registration is passed in, return a Protocol Instance that was just add
560 to the system. If Registration is NULL return the first Protocol Interface
561 you find.
562
563 @param Protocol The protocol to search for
564 @param Registration Optional Registration Key returned from
565 RegisterProtocolNotify()
566 @param Interface Return the Protocol interface (instance).
567
568 @retval EFI_SUCCESS If a valid Interface is returned
569 @retval EFI_INVALID_PARAMETER Invalid parameter
570 @retval EFI_NOT_FOUND Protocol interface not found
571
572 **/
573 EFI_STATUS
574 EFIAPI
575 CoreLocateProtocol (
576 IN EFI_GUID *Protocol,
577 IN VOID *Registration OPTIONAL,
578 OUT VOID **Interface
579 )
580 {
581 EFI_STATUS Status;
582 LOCATE_POSITION Position;
583 PROTOCOL_NOTIFY *ProtNotify;
584 IHANDLE *Handle;
585
586 if ((Interface == NULL) || (Protocol == NULL)) {
587 return EFI_INVALID_PARAMETER;
588 }
589
590 *Interface = NULL;
591 Status = EFI_SUCCESS;
592
593 //
594 // Set initial position
595 //
596 Position.Protocol = Protocol;
597 Position.SearchKey = Registration;
598 Position.Position = &gHandleList;
599
600 //
601 // Lock the protocol database
602 //
603 Status = CoreAcquireLockOrFail (&gProtocolDatabaseLock);
604 if (EFI_ERROR (Status)) {
605 return EFI_NOT_FOUND;
606 }
607
608 mEfiLocateHandleRequest += 1;
609
610 if (Registration == NULL) {
611 //
612 // Look up the protocol entry and set the head pointer
613 //
614 Position.ProtEntry = CoreFindProtocolEntry (Protocol, FALSE);
615 if (Position.ProtEntry == NULL) {
616 Status = EFI_NOT_FOUND;
617 goto Done;
618 }
619
620 Position.Position = &Position.ProtEntry->Protocols;
621
622 Handle = CoreGetNextLocateByProtocol (&Position, Interface);
623 } else {
624 Handle = CoreGetNextLocateByRegisterNotify (&Position, Interface);
625 }
626
627 if (Handle == NULL) {
628 Status = EFI_NOT_FOUND;
629 } else if (Registration != NULL) {
630 //
631 // If this is a search by register notify and a handle was
632 // returned, update the register notification position
633 //
634 ProtNotify = Registration;
635 ProtNotify->Position = ProtNotify->Position->ForwardLink;
636 }
637
638 Done:
639 CoreReleaseProtocolLock ();
640 return Status;
641 }
642
643 /**
644 Function returns an array of handles that support the requested protocol
645 in a buffer allocated from pool. This is a version of CoreLocateHandle()
646 that allocates a buffer for the caller.
647
648 @param SearchType Specifies which handle(s) are to be returned.
649 @param Protocol Provides the protocol to search by. This
650 parameter is only valid for SearchType
651 ByProtocol.
652 @param SearchKey Supplies the search key depending on the
653 SearchType.
654 @param NumberHandles The number of handles returned in Buffer.
655 @param Buffer A pointer to the buffer to return the requested
656 array of handles that support Protocol.
657
658 @retval EFI_SUCCESS The result array of handles was returned.
659 @retval EFI_NOT_FOUND No handles match the search.
660 @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the
661 matching results.
662 @retval EFI_INVALID_PARAMETER One or more parameters are not valid.
663
664 **/
665 EFI_STATUS
666 EFIAPI
667 CoreLocateHandleBuffer (
668 IN EFI_LOCATE_SEARCH_TYPE SearchType,
669 IN EFI_GUID *Protocol OPTIONAL,
670 IN VOID *SearchKey OPTIONAL,
671 IN OUT UINTN *NumberHandles,
672 OUT EFI_HANDLE **Buffer
673 )
674 {
675 EFI_STATUS Status;
676 UINTN BufferSize;
677
678 if (NumberHandles == NULL) {
679 return EFI_INVALID_PARAMETER;
680 }
681
682 if (Buffer == NULL) {
683 return EFI_INVALID_PARAMETER;
684 }
685
686 BufferSize = 0;
687 *NumberHandles = 0;
688 *Buffer = NULL;
689
690 //
691 // Lock the protocol database
692 //
693 CoreAcquireProtocolLock ();
694 Status = InternalCoreLocateHandle (
695 SearchType,
696 Protocol,
697 SearchKey,
698 &BufferSize,
699 *Buffer
700 );
701 //
702 // LocateHandleBuffer() returns incorrect status code if SearchType is
703 // invalid.
704 //
705 // Add code to correctly handle expected errors from CoreLocateHandle().
706 //
707 if (EFI_ERROR (Status) && (Status != EFI_BUFFER_TOO_SMALL)) {
708 if (Status != EFI_INVALID_PARAMETER) {
709 Status = EFI_NOT_FOUND;
710 }
711
712 CoreReleaseProtocolLock ();
713 return Status;
714 }
715
716 *Buffer = AllocatePool (BufferSize);
717 if (*Buffer == NULL) {
718 CoreReleaseProtocolLock ();
719 return EFI_OUT_OF_RESOURCES;
720 }
721
722 Status = InternalCoreLocateHandle (
723 SearchType,
724 Protocol,
725 SearchKey,
726 &BufferSize,
727 *Buffer
728 );
729
730 *NumberHandles = BufferSize / sizeof (EFI_HANDLE);
731 if (EFI_ERROR (Status)) {
732 *NumberHandles = 0;
733 }
734
735 CoreReleaseProtocolLock ();
736 return Status;
737 }