Home | History | Annotate | Download | only in Hand
      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
    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 *
    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 *
    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 *
    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
    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
    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
    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