Home | History | Annotate | Download | only in PiSmmCore
      1 /** @file
      2   Locate handle functions
      3 
      4   Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
      5   This program and the accompanying materials are licensed and made available
      6   under the terms and conditions of the BSD License which accompanies this
      7   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 "PiSmmCore.h"
     16 
     17 //
     18 // ProtocolRequest - Last LocateHandle request ID
     19 //
     20 UINTN mEfiLocateHandleRequest = 0;
     21 
     22 //
     23 // Internal prototypes
     24 //
     25 
     26 typedef struct {
     27   EFI_GUID        *Protocol;
     28   VOID            *SearchKey;
     29   LIST_ENTRY      *Position;
     30   PROTOCOL_ENTRY  *ProtEntry;
     31 } LOCATE_POSITION;
     32 
     33 typedef
     34 IHANDLE *
     35 (* CORE_GET_NEXT) (
     36   IN OUT LOCATE_POSITION    *Position,
     37   OUT VOID                  **Interface
     38   );
     39 
     40 /**
     41   Routine to get the next Handle, when you are searching for all handles.
     42 
     43   @param  Position               Information about which Handle to seach for.
     44   @param  Interface              Return the interface structure for the matching
     45                                  protocol.
     46 
     47   @return An pointer to IHANDLE if the next Position is not the end of the list.
     48           Otherwise,NULL is returned.
     49 
     50 **/
     51 IHANDLE *
     52 SmmGetNextLocateAllHandles (
     53   IN OUT LOCATE_POSITION  *Position,
     54   OUT    VOID             **Interface
     55   )
     56 {
     57   IHANDLE     *Handle;
     58 
     59   //
     60   // Next handle
     61   //
     62   Position->Position = Position->Position->ForwardLink;
     63 
     64   //
     65   // If not at the end of the list, get the handle
     66   //
     67   Handle      = NULL;
     68   *Interface  = NULL;
     69   if (Position->Position != &gHandleList) {
     70     Handle = CR (Position->Position, IHANDLE, AllHandles, EFI_HANDLE_SIGNATURE);
     71   }
     72   return Handle;
     73 }
     74 
     75 /**
     76   Routine to get the next Handle, when you are searching for register protocol
     77   notifies.
     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 SmmGetNextLocateByRegisterNotify (
     89   IN OUT LOCATE_POSITION  *Position,
     90   OUT    VOID             **Interface
     91   )
     92 {
     93   IHANDLE             *Handle;
     94   PROTOCOL_NOTIFY     *ProtNotify;
     95   PROTOCOL_INTERFACE  *Prot;
     96   LIST_ENTRY          *Link;
     97 
     98   Handle      = NULL;
     99   *Interface  = NULL;
    100   ProtNotify = Position->SearchKey;
    101 
    102   //
    103   // If this is the first request, get the next handle
    104   //
    105   if (ProtNotify != NULL) {
    106     ASSERT(ProtNotify->Signature == PROTOCOL_NOTIFY_SIGNATURE);
    107     Position->SearchKey = NULL;
    108 
    109     //
    110     // If not at the end of the list, get the next handle
    111     //
    112     Link = ProtNotify->Position->ForwardLink;
    113     if (Link != &ProtNotify->Protocol->Protocols) {
    114       Prot = CR (Link, PROTOCOL_INTERFACE, ByProtocol, PROTOCOL_INTERFACE_SIGNATURE);
    115       Handle = Prot->Handle;
    116       *Interface = Prot->Interface;
    117     }
    118   }
    119   return Handle;
    120 }
    121 
    122 /**
    123   Routine to get the next Handle, when you are searching for a given protocol.
    124 
    125   @param  Position               Information about which Handle to seach for.
    126   @param  Interface              Return the interface structure for the matching
    127                                  protocol.
    128 
    129   @return An pointer to IHANDLE if the next Position is not the end of the list.
    130           Otherwise,NULL is returned.
    131 
    132 **/
    133 IHANDLE *
    134 SmmGetNextLocateByProtocol (
    135   IN OUT LOCATE_POSITION  *Position,
    136   OUT    VOID             **Interface
    137   )
    138 {
    139   IHANDLE             *Handle;
    140   LIST_ENTRY          *Link;
    141   PROTOCOL_INTERFACE  *Prot;
    142 
    143   Handle      = NULL;
    144   *Interface  = NULL;
    145   for (; ;) {
    146     //
    147     // Next entry
    148     //
    149     Link = Position->Position->ForwardLink;
    150     Position->Position = Link;
    151 
    152     //
    153     // If not at the end, return the handle
    154     //
    155     if (Link == &Position->ProtEntry->Protocols) {
    156       Handle = NULL;
    157       break;
    158     }
    159 
    160     //
    161     // Get the handle
    162     //
    163     Prot = CR(Link, PROTOCOL_INTERFACE, ByProtocol, PROTOCOL_INTERFACE_SIGNATURE);
    164     Handle = Prot->Handle;
    165     *Interface = Prot->Interface;
    166 
    167     //
    168     // If this handle has not been returned this request, then
    169     // return it now
    170     //
    171     if (Handle->LocateRequest != mEfiLocateHandleRequest) {
    172       Handle->LocateRequest = mEfiLocateHandleRequest;
    173       break;
    174     }
    175   }
    176   return Handle;
    177 }
    178 
    179 /**
    180   Return the first Protocol Interface that matches the Protocol GUID. If
    181   Registration is pasased in return a Protocol Instance that was just add
    182   to the system. If Retistration is NULL return the first Protocol Interface
    183   you find.
    184 
    185   @param  Protocol               The protocol to search for
    186   @param  Registration           Optional Registration Key returned from
    187                                  RegisterProtocolNotify()
    188   @param  Interface              Return the Protocol interface (instance).
    189 
    190   @retval EFI_SUCCESS            If a valid Interface is returned
    191   @retval EFI_INVALID_PARAMETER  Invalid parameter
    192   @retval EFI_NOT_FOUND          Protocol interface not found
    193 
    194 **/
    195 EFI_STATUS
    196 EFIAPI
    197 SmmLocateProtocol (
    198   IN  EFI_GUID  *Protocol,
    199   IN  VOID      *Registration OPTIONAL,
    200   OUT VOID      **Interface
    201   )
    202 {
    203   EFI_STATUS              Status;
    204   LOCATE_POSITION         Position;
    205   PROTOCOL_NOTIFY         *ProtNotify;
    206   IHANDLE                 *Handle;
    207 
    208   if (Interface == NULL) {
    209     return EFI_INVALID_PARAMETER;
    210   }
    211 
    212   if (Protocol == NULL) {
    213     return EFI_NOT_FOUND;
    214   }
    215 
    216   *Interface = NULL;
    217   Status = EFI_SUCCESS;
    218 
    219   //
    220   // Set initial position
    221   //
    222   Position.Protocol  = Protocol;
    223   Position.SearchKey = Registration;
    224   Position.Position  = &gHandleList;
    225 
    226   mEfiLocateHandleRequest += 1;
    227 
    228   if (Registration == NULL) {
    229     //
    230     // Look up the protocol entry and set the head pointer
    231     //
    232     Position.ProtEntry = SmmFindProtocolEntry (Protocol, FALSE);
    233     if (Position.ProtEntry == NULL) {
    234       return EFI_NOT_FOUND;
    235     }
    236     Position.Position = &Position.ProtEntry->Protocols;
    237 
    238     Handle = SmmGetNextLocateByProtocol (&Position, Interface);
    239   } else {
    240     Handle = SmmGetNextLocateByRegisterNotify (&Position, Interface);
    241   }
    242 
    243   if (Handle == NULL) {
    244     Status = EFI_NOT_FOUND;
    245   } else if (Registration != NULL) {
    246     //
    247     // If this is a search by register notify and a handle was
    248     // returned, update the register notification position
    249     //
    250     ProtNotify = Registration;
    251     ProtNotify->Position = ProtNotify->Position->ForwardLink;
    252   }
    253 
    254   return Status;
    255 }
    256 
    257 /**
    258   Locates the requested handle(s) and returns them in Buffer.
    259 
    260   @param  SearchType             The type of search to perform to locate the
    261                                  handles
    262   @param  Protocol               The protocol to search for
    263   @param  SearchKey              Dependant on SearchType
    264   @param  BufferSize             On input the size of Buffer.  On output the
    265                                  size of data returned.
    266   @param  Buffer                 The buffer to return the results in
    267 
    268   @retval EFI_BUFFER_TOO_SMALL   Buffer too small, required buffer size is
    269                                  returned in BufferSize.
    270   @retval EFI_INVALID_PARAMETER  Invalid parameter
    271   @retval EFI_SUCCESS            Successfully found the requested handle(s) and
    272                                  returns them in Buffer.
    273 
    274 **/
    275 EFI_STATUS
    276 EFIAPI
    277 SmmLocateHandle (
    278   IN     EFI_LOCATE_SEARCH_TYPE  SearchType,
    279   IN     EFI_GUID                *Protocol   OPTIONAL,
    280   IN     VOID                    *SearchKey  OPTIONAL,
    281   IN OUT UINTN                   *BufferSize,
    282   OUT    EFI_HANDLE              *Buffer
    283   )
    284 {
    285   EFI_STATUS       Status;
    286   LOCATE_POSITION  Position;
    287   PROTOCOL_NOTIFY  *ProtNotify;
    288   CORE_GET_NEXT    GetNext;
    289   UINTN            ResultSize;
    290   IHANDLE          *Handle;
    291   IHANDLE          **ResultBuffer;
    292   VOID             *Interface;
    293 
    294   if (BufferSize == NULL) {
    295     return EFI_INVALID_PARAMETER;
    296   }
    297 
    298   if ((*BufferSize > 0) && (Buffer == NULL)) {
    299     return EFI_INVALID_PARAMETER;
    300   }
    301 
    302   GetNext = NULL;
    303 
    304   //
    305   // Set initial position
    306   //
    307   Position.Protocol  = Protocol;
    308   Position.SearchKey = SearchKey;
    309   Position.Position  = &gHandleList;
    310 
    311   ResultSize = 0;
    312   ResultBuffer = (IHANDLE **) Buffer;
    313   Status = EFI_SUCCESS;
    314 
    315   //
    316   // Get the search function based on type
    317   //
    318   switch (SearchType) {
    319   case AllHandles:
    320     GetNext = SmmGetNextLocateAllHandles;
    321     break;
    322 
    323   case ByRegisterNotify:
    324     GetNext = SmmGetNextLocateByRegisterNotify;
    325     //
    326     // Must have SearchKey for locate ByRegisterNotify
    327     //
    328     if (SearchKey == NULL) {
    329       Status = EFI_INVALID_PARAMETER;
    330     }
    331     break;
    332 
    333   case ByProtocol:
    334     GetNext = SmmGetNextLocateByProtocol;
    335     if (Protocol == NULL) {
    336       Status = EFI_INVALID_PARAMETER;
    337       break;
    338     }
    339     //
    340     // Look up the protocol entry and set the head pointer
    341     //
    342     Position.ProtEntry = SmmFindProtocolEntry (Protocol, FALSE);
    343     if (Position.ProtEntry == NULL) {
    344       Status = EFI_NOT_FOUND;
    345       break;
    346     }
    347     Position.Position = &Position.ProtEntry->Protocols;
    348     break;
    349 
    350   default:
    351     Status = EFI_INVALID_PARAMETER;
    352     break;
    353   }
    354 
    355   if (EFI_ERROR(Status)) {
    356     return Status;
    357   }
    358 
    359   //
    360   // Enumerate out the matching handles
    361   //
    362   mEfiLocateHandleRequest += 1;
    363   for (; ;) {
    364     //
    365     // Get the next handle.  If no more handles, stop
    366     //
    367     Handle = GetNext (&Position, &Interface);
    368     if (NULL == Handle) {
    369       break;
    370     }
    371 
    372     //
    373     // Increase the resulting buffer size, and if this handle
    374     // fits return it
    375     //
    376     ResultSize += sizeof(Handle);
    377     if (ResultSize <= *BufferSize) {
    378         *ResultBuffer = Handle;
    379         ResultBuffer += 1;
    380     }
    381   }
    382 
    383   //
    384   // If the result is a zero length buffer, then there were no
    385   // matching handles
    386   //
    387   if (ResultSize == 0) {
    388     Status = EFI_NOT_FOUND;
    389   } else {
    390     //
    391     // Return the resulting buffer size.  If it's larger than what
    392     // was passed, then set the error code
    393     //
    394     if (ResultSize > *BufferSize) {
    395       Status = EFI_BUFFER_TOO_SMALL;
    396     }
    397 
    398     *BufferSize = ResultSize;
    399 
    400     if (SearchType == ByRegisterNotify && !EFI_ERROR(Status)) {
    401       ASSERT (SearchKey != NULL);
    402       //
    403       // If this is a search by register notify and a handle was
    404       // returned, update the register notification position
    405       //
    406       ProtNotify = SearchKey;
    407       ProtNotify->Position = ProtNotify->Position->ForwardLink;
    408     }
    409   }
    410 
    411   return Status;
    412 }
    413 
    414 /**
    415   Function returns an array of handles that support the requested protocol
    416   in a buffer allocated from pool. This is a version of SmmLocateHandle()
    417   that allocates a buffer for the caller.
    418 
    419   @param  SearchType             Specifies which handle(s) are to be returned.
    420   @param  Protocol               Provides the protocol to search by.    This
    421                                  parameter is only valid for SearchType
    422                                  ByProtocol.
    423   @param  SearchKey              Supplies the search key depending on the
    424                                  SearchType.
    425   @param  NumberHandles          The number of handles returned in Buffer.
    426   @param  Buffer                 A pointer to the buffer to return the requested
    427                                  array of  handles that support Protocol.
    428 
    429   @retval EFI_SUCCESS            The result array of handles was returned.
    430   @retval EFI_NOT_FOUND          No handles match the search.
    431   @retval EFI_OUT_OF_RESOURCES   There is not enough pool memory to store the
    432                                  matching results.
    433   @retval EFI_INVALID_PARAMETER  One or more parameters are not valid.
    434 
    435 **/
    436 EFI_STATUS
    437 EFIAPI
    438 SmmLocateHandleBuffer (
    439   IN     EFI_LOCATE_SEARCH_TYPE  SearchType,
    440   IN     EFI_GUID                *Protocol OPTIONAL,
    441   IN     VOID                    *SearchKey OPTIONAL,
    442   IN OUT UINTN                   *NumberHandles,
    443   OUT    EFI_HANDLE              **Buffer
    444   )
    445 {
    446   EFI_STATUS  Status;
    447   UINTN       BufferSize;
    448 
    449   if (NumberHandles == NULL) {
    450     return EFI_INVALID_PARAMETER;
    451   }
    452 
    453   if (Buffer == NULL) {
    454     return EFI_INVALID_PARAMETER;
    455   }
    456 
    457   BufferSize = 0;
    458   *NumberHandles = 0;
    459   *Buffer = NULL;
    460   Status = SmmLocateHandle (
    461              SearchType,
    462              Protocol,
    463              SearchKey,
    464              &BufferSize,
    465              *Buffer
    466              );
    467   //
    468   // LocateHandleBuffer() returns incorrect status code if SearchType is
    469   // invalid.
    470   //
    471   // Add code to correctly handle expected errors from SmmLocateHandle().
    472   //
    473   if (EFI_ERROR(Status) && Status != EFI_BUFFER_TOO_SMALL) {
    474     if (Status != EFI_INVALID_PARAMETER) {
    475       Status = EFI_NOT_FOUND;
    476     }
    477     return Status;
    478   }
    479 
    480   *Buffer = AllocatePool (BufferSize);
    481   if (*Buffer == NULL) {
    482     return EFI_OUT_OF_RESOURCES;
    483   }
    484 
    485   Status = SmmLocateHandle (
    486              SearchType,
    487              Protocol,
    488              SearchKey,
    489              &BufferSize,
    490              *Buffer
    491              );
    492 
    493   *NumberHandles = BufferSize / sizeof(EFI_HANDLE);
    494   if (EFI_ERROR(Status)) {
    495     *NumberHandles = 0;
    496   }
    497 
    498   return Status;
    499 }
    500