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