• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 *
SmmGetNextLocateAllHandles(IN OUT LOCATE_POSITION * Position,OUT VOID ** Interface)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 *
SmmGetNextLocateByRegisterNotify(IN OUT LOCATE_POSITION * Position,OUT VOID ** Interface)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 *
SmmGetNextLocateByProtocol(IN OUT LOCATE_POSITION * Position,OUT VOID ** Interface)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
SmmLocateProtocol(IN EFI_GUID * Protocol,IN VOID * Registration OPTIONAL,OUT VOID ** Interface)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
SmmLocateHandle(IN EFI_LOCATE_SEARCH_TYPE SearchType,IN EFI_GUID * Protocol OPTIONAL,IN VOID * SearchKey OPTIONAL,IN OUT UINTN * BufferSize,OUT EFI_HANDLE * Buffer)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
SmmLocateHandleBuffer(IN EFI_LOCATE_SEARCH_TYPE SearchType,IN EFI_GUID * Protocol OPTIONAL,IN VOID * SearchKey OPTIONAL,IN OUT UINTN * NumberHandles,OUT EFI_HANDLE ** Buffer)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