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