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