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