]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Dxe/Hand/Locate.c
Remove NULL_HANDLE. NULL_HANDLE should be replaced with NULL as consistency. For...
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / Hand / Locate.c
1 /** @file
2 Locate handle functions
3
4 Copyright (c) 2006 - 2008, Intel Corporation. <BR>
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this 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 "DxeMain.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 CoreGetNextLocateAllHandles (
53 IN OUT LOCATE_POSITION *Position,
54 OUT VOID **Interface
55 );
56
57 /**
58 Routine to get the next Handle, when you are searching for register protocol
59 notifies.
60
61 @param Position Information about which Handle to seach for.
62 @param Interface Return the interface structure for the matching
63 protocol.
64
65 @return An pointer to IHANDLE if the next Position is not the end of the list.
66 Otherwise,NULL is returned.
67
68 **/
69 IHANDLE *
70 CoreGetNextLocateByRegisterNotify (
71 IN OUT LOCATE_POSITION *Position,
72 OUT VOID **Interface
73 );
74
75 /**
76 Routine to get the next Handle, when you are searching for a given protocol.
77
78 @param Position Information about which Handle to seach for.
79 @param Interface Return the interface structure for the matching
80 protocol.
81
82 @return An pointer to IHANDLE if the next Position is not the end of the list.
83 Otherwise,NULL is returned.
84
85 **/
86 IHANDLE *
87 CoreGetNextLocateByProtocol (
88 IN OUT LOCATE_POSITION *Position,
89 OUT VOID **Interface
90 );
91
92
93 /**
94 Locates the requested handle(s) and returns them in Buffer.
95
96 @param SearchType The type of search to perform to locate the
97 handles
98 @param Protocol The protocol to search for
99 @param SearchKey Dependant on SearchType
100 @param BufferSize On input the size of Buffer. On output the
101 size of data returned.
102 @param Buffer The buffer to return the results in
103
104 @retval EFI_BUFFER_TOO_SMALL Buffer too small, required buffer size is
105 returned in BufferSize.
106 @retval EFI_INVALID_PARAMETER Invalid parameter
107 @retval EFI_SUCCESS Successfully found the requested handle(s) and
108 returns them in Buffer.
109
110 **/
111 EFI_STATUS
112 EFIAPI
113 CoreLocateHandle (
114 IN EFI_LOCATE_SEARCH_TYPE SearchType,
115 IN EFI_GUID *Protocol OPTIONAL,
116 IN VOID *SearchKey OPTIONAL,
117 IN OUT UINTN *BufferSize,
118 OUT EFI_HANDLE *Buffer
119 )
120 {
121 EFI_STATUS Status;
122 LOCATE_POSITION Position;
123 PROTOCOL_NOTIFY *ProtNotify;
124 CORE_GET_NEXT GetNext;
125 UINTN ResultSize;
126 IHANDLE *Handle;
127 IHANDLE **ResultBuffer;
128 VOID *Interface;
129
130 if (BufferSize == NULL) {
131 Status = EFI_INVALID_PARAMETER;
132 }
133
134 if ((*BufferSize > 0) && (Buffer == NULL)) {
135 return EFI_INVALID_PARAMETER;
136 }
137
138 GetNext = NULL;
139
140 //
141 // Set initial position
142 //
143 Position.Protocol = Protocol;
144 Position.SearchKey = SearchKey;
145 Position.Position = &gHandleList;
146
147 ResultSize = 0;
148 ResultBuffer = (IHANDLE **) Buffer;
149 Status = EFI_SUCCESS;
150
151 //
152 // Lock the protocol database
153 //
154 CoreAcquireProtocolLock ();
155
156 //
157 // Get the search function based on type
158 //
159 switch (SearchType) {
160 case AllHandles:
161 GetNext = CoreGetNextLocateAllHandles;
162 break;
163
164 case ByRegisterNotify:
165 //
166 // Must have SearchKey for locate ByRegisterNotify
167 //
168 if (SearchKey == NULL) {
169 Status = EFI_INVALID_PARAMETER;
170 break;
171 }
172 GetNext = CoreGetNextLocateByRegisterNotify;
173 break;
174
175 case ByProtocol:
176 GetNext = CoreGetNextLocateByProtocol;
177 if (Protocol == NULL) {
178 Status = EFI_INVALID_PARAMETER;
179 break;
180 }
181 //
182 // Look up the protocol entry and set the head pointer
183 //
184 Position.ProtEntry = CoreFindProtocolEntry (Protocol, FALSE);
185 if (Position.ProtEntry == NULL) {
186 Status = EFI_NOT_FOUND;
187 break;
188 }
189 Position.Position = &Position.ProtEntry->Protocols;
190 break;
191
192 default:
193 Status = EFI_INVALID_PARAMETER;
194 break;
195 }
196
197 if (EFI_ERROR(Status)) {
198 CoreReleaseProtocolLock ();
199 return Status;
200 }
201
202 //
203 // Enumerate out the matching handles
204 //
205 mEfiLocateHandleRequest += 1;
206 for (; ;) {
207 //
208 // Get the next handle. If no more handles, stop
209 //
210 Handle = GetNext (&Position, &Interface);
211 if (NULL == Handle) {
212 break;
213 }
214
215 //
216 // Increase the resulting buffer size, and if this handle
217 // fits return it
218 //
219 ResultSize += sizeof(Handle);
220 if (ResultSize <= *BufferSize) {
221 *ResultBuffer = Handle;
222 ResultBuffer += 1;
223 }
224 }
225
226 //
227 // If the result is a zero length buffer, then there were no
228 // matching handles
229 //
230 if (ResultSize == 0) {
231 Status = EFI_NOT_FOUND;
232 } else {
233 //
234 // Return the resulting buffer size. If it's larger than what
235 // was passed, then set the error code
236 //
237 if (ResultSize > *BufferSize) {
238 Status = EFI_BUFFER_TOO_SMALL;
239 }
240
241 *BufferSize = ResultSize;
242
243 if (SearchType == ByRegisterNotify && !EFI_ERROR(Status)) {
244 //
245 // If this is a search by register notify and a handle was
246 // returned, update the register notification position
247 //
248 ProtNotify = SearchKey;
249 ProtNotify->Position = ProtNotify->Position->ForwardLink;
250 }
251 }
252
253 CoreReleaseProtocolLock ();
254 return Status;
255 }
256
257
258
259 /**
260 Routine to get the next Handle, when you are searching for all handles.
261
262 @param Position Information about which Handle to seach for.
263 @param Interface Return the interface structure for the matching
264 protocol.
265
266 @return An pointer to IHANDLE if the next Position is not the end of the list.
267 Otherwise,NULL is returned.
268
269 **/
270 IHANDLE *
271 CoreGetNextLocateAllHandles (
272 IN OUT LOCATE_POSITION *Position,
273 OUT VOID **Interface
274 )
275 {
276 IHANDLE *Handle;
277
278 //
279 // Next handle
280 //
281 Position->Position = Position->Position->ForwardLink;
282
283 //
284 // If not at the end of the list, get the handle
285 //
286 Handle = NULL;
287 *Interface = NULL;
288 if (Position->Position != &gHandleList) {
289 Handle = CR (Position->Position, IHANDLE, AllHandles, EFI_HANDLE_SIGNATURE);
290 }
291
292 return Handle;
293 }
294
295
296
297 /**
298 Routine to get the next Handle, when you are searching for register protocol
299 notifies.
300
301 @param Position Information about which Handle to seach for.
302 @param Interface Return the interface structure for the matching
303 protocol.
304
305 @return An pointer to IHANDLE if the next Position is not the end of the list.
306 Otherwise,NULL is returned.
307
308 **/
309 IHANDLE *
310 CoreGetNextLocateByRegisterNotify (
311 IN OUT LOCATE_POSITION *Position,
312 OUT VOID **Interface
313 )
314 {
315 IHANDLE *Handle;
316 PROTOCOL_NOTIFY *ProtNotify;
317 PROTOCOL_INTERFACE *Prot;
318 LIST_ENTRY *Link;
319
320 Handle = NULL;
321 *Interface = NULL;
322 ProtNotify = Position->SearchKey;
323
324 //
325 // If this is the first request, get the next handle
326 //
327 if (ProtNotify != NULL) {
328 ASSERT(ProtNotify->Signature == PROTOCOL_NOTIFY_SIGNATURE);
329 Position->SearchKey = NULL;
330
331 //
332 // If not at the end of the list, get the next handle
333 //
334 Link = ProtNotify->Position->ForwardLink;
335 if (Link != &ProtNotify->Protocol->Protocols) {
336 Prot = CR (Link, PROTOCOL_INTERFACE, ByProtocol, PROTOCOL_INTERFACE_SIGNATURE);
337 Handle = (IHANDLE *) Prot->Handle;
338 *Interface = Prot->Interface;
339 }
340 }
341
342 return Handle;
343 }
344
345
346 /**
347 Routine to get the next Handle, when you are searching for a given protocol.
348
349 @param Position Information about which Handle to seach for.
350 @param Interface Return the interface structure for the matching
351 protocol.
352
353 @return An pointer to IHANDLE if the next Position is not the end of the list.
354 Otherwise,NULL is returned.
355
356 **/
357 IHANDLE *
358 CoreGetNextLocateByProtocol (
359 IN OUT LOCATE_POSITION *Position,
360 OUT VOID **Interface
361 )
362 {
363 IHANDLE *Handle;
364 LIST_ENTRY *Link;
365 PROTOCOL_INTERFACE *Prot;
366
367 Handle = NULL;
368 *Interface = NULL;
369 for (; ;) {
370 //
371 // Next entry
372 //
373 Link = Position->Position->ForwardLink;
374 Position->Position = Link;
375
376 //
377 // If not at the end, return the handle
378 //
379 if (Link == &Position->ProtEntry->Protocols) {
380 Handle = NULL;
381 break;
382 }
383
384 //
385 // Get the handle
386 //
387 Prot = CR(Link, PROTOCOL_INTERFACE, ByProtocol, PROTOCOL_INTERFACE_SIGNATURE);
388 Handle = (IHANDLE *) Prot->Handle;
389 *Interface = Prot->Interface;
390
391 //
392 // If this handle has not been returned this request, then
393 // return it now
394 //
395 if (Handle->LocateRequest != mEfiLocateHandleRequest) {
396 Handle->LocateRequest = mEfiLocateHandleRequest;
397 break;
398 }
399 }
400
401 return Handle;
402 }
403
404
405 /**
406 Locates the handle to a device on the device path that best matches the specified protocol.
407
408 @param Protocol The protocol to search for.
409 @param DevicePath On input, a pointer to a pointer to the device
410 path. On output, the device path pointer is
411 modified to point to the remaining part of the
412 devicepath.
413 @param Device A pointer to the returned device handle.
414
415 @retval EFI_SUCCESS The resulting handle was returned.
416 @retval EFI_NOT_FOUND No handles matched the search.
417 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
418
419 **/
420 EFI_STATUS
421 EFIAPI
422 CoreLocateDevicePath (
423 IN EFI_GUID *Protocol,
424 IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath,
425 OUT EFI_HANDLE *Device
426 )
427 {
428 INTN SourceSize;
429 INTN Size;
430 INTN BestMatch;
431 UINTN HandleCount;
432 UINTN Index;
433 EFI_STATUS Status;
434 EFI_HANDLE *Handles;
435 EFI_HANDLE Handle;
436 EFI_DEVICE_PATH_PROTOCOL *SourcePath;
437 EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath;
438
439 if (Protocol == NULL) {
440 return EFI_INVALID_PARAMETER;
441 }
442
443 if ((DevicePath == NULL) || (*DevicePath == NULL)) {
444 return EFI_INVALID_PARAMETER;
445 }
446
447 if (Device == NULL) {
448 return EFI_INVALID_PARAMETER;
449 }
450
451 *Device = NULL;
452 SourcePath = *DevicePath;
453 SourceSize = GetDevicePathSize (SourcePath) - sizeof(EFI_DEVICE_PATH_PROTOCOL);
454
455 //
456 // The source path can only have 1 instance
457 //
458 if (IsDevicePathMultiInstance (SourcePath)) {
459 DEBUG((DEBUG_ERROR, "LocateDevicePath: Device path has too many instances\n"));
460 return EFI_INVALID_PARAMETER;
461 }
462
463 //
464 // Get a list of all handles that support the requested protocol
465 //
466 Status = CoreLocateHandleBuffer (ByProtocol, Protocol, NULL, &HandleCount, &Handles);
467 if (EFI_ERROR (Status) || HandleCount == 0) {
468 return EFI_NOT_FOUND;
469 }
470
471 BestMatch = -1;
472 for(Index = 0; Index < HandleCount; Index += 1) {
473 Handle = Handles[Index];
474 Status = CoreHandleProtocol (Handle, &gEfiDevicePathProtocolGuid, (VOID **)&TmpDevicePath);
475 if (EFI_ERROR (Status)) {
476 //
477 // If this handle doesn't support device path, then skip it
478 //
479 continue;
480 }
481
482 //
483 // Check if DevicePath is first part of SourcePath
484 //
485 Size = GetDevicePathSize (TmpDevicePath) - sizeof(EFI_DEVICE_PATH_PROTOCOL);
486 if ((Size <= SourceSize) && CompareMem (SourcePath, TmpDevicePath, Size) == 0) {
487 //
488 // If the size is equal to the best match, then we
489 // have a duplice device path for 2 different device
490 // handles
491 //
492 ASSERT (Size != BestMatch);
493
494 //
495 // We've got a match, see if it's the best match so far
496 //
497 if (Size > BestMatch) {
498 BestMatch = Size;
499 *Device = Handle;
500 }
501 }
502 }
503
504 CoreFreePool (Handles);
505
506 //
507 // If there wasn't any match, then no parts of the device path was found.
508 // Which is strange since there is likely a "root level" device path in the system.
509 //
510 if (BestMatch == -1) {
511 return EFI_NOT_FOUND;
512 }
513
514 //
515 // Return the remaining part of the device path
516 //
517 *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) (((UINT8 *) SourcePath) + BestMatch);
518 return EFI_SUCCESS;
519 }
520
521
522 /**
523 Return the first Protocol Interface that matches the Protocol GUID. If
524 Registration is pasased in return a Protocol Instance that was just add
525 to the system. If Retistration is NULL return the first Protocol Interface
526 you find.
527
528 @param Protocol The protocol to search for
529 @param Registration Optional Registration Key returned from
530 RegisterProtocolNotify()
531 @param Interface Return the Protocol interface (instance).
532
533 @retval EFI_SUCCESS If a valid Interface is returned
534 @retval EFI_INVALID_PARAMETER Invalid parameter
535 @retval EFI_NOT_FOUND Protocol interface not found
536
537 **/
538 EFI_STATUS
539 EFIAPI
540 CoreLocateProtocol (
541 IN EFI_GUID *Protocol,
542 IN VOID *Registration OPTIONAL,
543 OUT VOID **Interface
544 )
545 {
546 EFI_STATUS Status;
547 LOCATE_POSITION Position;
548 PROTOCOL_NOTIFY *ProtNotify;
549 IHANDLE *Handle;
550
551 if (Interface == NULL) {
552 return EFI_INVALID_PARAMETER;
553 }
554
555 if (Protocol == NULL) {
556 return EFI_NOT_FOUND;
557 }
558
559 *Interface = NULL;
560 Status = EFI_SUCCESS;
561
562 //
563 // Set initial position
564 //
565 Position.Protocol = Protocol;
566 Position.SearchKey = Registration;
567 Position.Position = &gHandleList;
568
569 //
570 // Lock the protocol database
571 //
572 CoreAcquireProtocolLock ();
573
574 mEfiLocateHandleRequest += 1;
575
576 if (Registration == NULL) {
577 //
578 // Look up the protocol entry and set the head pointer
579 //
580 Position.ProtEntry = CoreFindProtocolEntry (Protocol, FALSE);
581 if (Position.ProtEntry == NULL) {
582 Status = EFI_NOT_FOUND;
583 goto Done;
584 }
585 Position.Position = &Position.ProtEntry->Protocols;
586
587 Handle = CoreGetNextLocateByProtocol (&Position, Interface);
588 } else {
589 Handle = CoreGetNextLocateByRegisterNotify (&Position, Interface);
590 }
591
592 if (Handle == NULL) {
593 Status = EFI_NOT_FOUND;
594 } else if (Registration != NULL) {
595 //
596 // If this is a search by register notify and a handle was
597 // returned, update the register notification position
598 //
599 ProtNotify = Registration;
600 ProtNotify->Position = ProtNotify->Position->ForwardLink;
601 }
602
603 Done:
604 CoreReleaseProtocolLock ();
605 return Status;
606 }
607
608
609 /**
610 Function returns an array of handles that support the requested protocol
611 in a buffer allocated from pool. This is a version of CoreLocateHandle()
612 that allocates a buffer for the caller.
613
614 @param SearchType Specifies which handle(s) are to be returned.
615 @param Protocol Provides the protocol to search by. This
616 parameter is only valid for SearchType
617 ByProtocol.
618 @param SearchKey Supplies the search key depending on the
619 SearchType.
620 @param NumberHandles The number of handles returned in Buffer.
621 @param Buffer A pointer to the buffer to return the requested
622 array of handles that support Protocol.
623
624 @retval EFI_SUCCESS The result array of handles was returned.
625 @retval EFI_NOT_FOUND No handles match the search.
626 @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the
627 matching results.
628 @retval EFI_INVALID_PARAMETER One or more paramters are not valid.
629
630 **/
631 EFI_STATUS
632 EFIAPI
633 CoreLocateHandleBuffer (
634 IN EFI_LOCATE_SEARCH_TYPE SearchType,
635 IN EFI_GUID *Protocol OPTIONAL,
636 IN VOID *SearchKey OPTIONAL,
637 IN OUT UINTN *NumberHandles,
638 OUT EFI_HANDLE **Buffer
639 )
640 {
641 EFI_STATUS Status;
642 UINTN BufferSize;
643
644 if (NumberHandles == NULL) {
645 return EFI_INVALID_PARAMETER;
646 }
647
648 if (Buffer == NULL) {
649 return EFI_INVALID_PARAMETER;
650 }
651
652 BufferSize = 0;
653 *NumberHandles = 0;
654 *Buffer = NULL;
655 Status = CoreLocateHandle (
656 SearchType,
657 Protocol,
658 SearchKey,
659 &BufferSize,
660 *Buffer
661 );
662 //
663 // LocateHandleBuffer() returns incorrect status code if SearchType is
664 // invalid.
665 //
666 // Add code to correctly handle expected errors from CoreLocateHandle().
667 //
668 if (EFI_ERROR(Status) && Status != EFI_BUFFER_TOO_SMALL) {
669 if (Status != EFI_INVALID_PARAMETER) {
670 Status = EFI_NOT_FOUND;
671 }
672 return Status;
673 }
674
675 *Buffer = AllocatePool (BufferSize);
676 if (*Buffer == NULL) {
677 return EFI_OUT_OF_RESOURCES;
678 }
679
680 Status = CoreLocateHandle (
681 SearchType,
682 Protocol,
683 SearchKey,
684 &BufferSize,
685 *Buffer
686 );
687
688 *NumberHandles = BufferSize / sizeof(EFI_HANDLE);
689 if (EFI_ERROR(Status)) {
690 *NumberHandles = 0;
691 }
692
693 return Status;
694 }
695
696
697