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