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