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