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