]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Dxe/Hand/Locate.c
Use TmpStr as a backup, as StrCpy in BaseLib does not handle copy of two strings
[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 @retval IHANDLE An IHANDLE is returned if the next Position is
48 not the end of the list. A NULL_HANDLE is
49 returned if it's the end of the list.
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 @retval IHANDLE An IHANDLE is returned if the next Position is
67 not the end of the list. A NULL_HANDLE is
68 returned if it's the end of the list.
69
70 **/
71 IHANDLE *
72 CoreGetNextLocateByRegisterNotify (
73 IN OUT LOCATE_POSITION *Position,
74 OUT VOID **Interface
75 );
76
77 /**
78 Routine to get the next Handle, when you are searching for a given protocol.
79
80 @param Position Information about which Handle to seach for.
81 @param Interface Return the interface structure for the matching
82 protocol.
83
84 @retval IHANDLE An IHANDLE is returned if the next Position is
85 not the end of the list. A NULL_HANDLE is
86 returned if it's the end of the list.
87
88 **/
89 IHANDLE *
90 CoreGetNextLocateByProtocol (
91 IN OUT LOCATE_POSITION *Position,
92 OUT VOID **Interface
93 );
94
95
96 /**
97 Locates the requested handle(s) and returns them in Buffer.
98
99 @param SearchType The type of search to perform to locate the
100 handles
101 @param Protocol The protocol to search for
102 @param SearchKey Dependant on SearchType
103 @param BufferSize On input the size of Buffer. On output the
104 size of data returned.
105 @param Buffer The buffer to return the results in
106
107 @retval EFI_BUFFER_TOO_SMALL Buffer too small, required buffer size is
108 returned in BufferSize.
109 @retval EFI_INVALID_PARAMETER Invalid parameter
110 @retval EFI_SUCCESS Successfully found the requested handle(s) and
111 returns them in Buffer.
112
113 **/
114 EFI_STATUS
115 EFIAPI
116 CoreLocateHandle (
117 IN EFI_LOCATE_SEARCH_TYPE SearchType,
118 IN EFI_GUID *Protocol OPTIONAL,
119 IN VOID *SearchKey OPTIONAL,
120 IN OUT UINTN *BufferSize,
121 OUT EFI_HANDLE *Buffer
122 )
123 {
124 EFI_STATUS Status;
125 LOCATE_POSITION Position;
126 PROTOCOL_NOTIFY *ProtNotify;
127 CORE_GET_NEXT GetNext;
128 UINTN ResultSize;
129 IHANDLE *Handle;
130 IHANDLE **ResultBuffer;
131 VOID *Interface;
132
133 if (BufferSize == NULL) {
134 Status = EFI_INVALID_PARAMETER;
135 }
136
137 if ((*BufferSize > 0) && (Buffer == NULL)) {
138 return EFI_INVALID_PARAMETER;
139 }
140
141 GetNext = NULL;
142
143 //
144 // Set initial position
145 //
146 Position.Protocol = Protocol;
147 Position.SearchKey = SearchKey;
148 Position.Position = &gHandleList;
149
150 ResultSize = 0;
151 ResultBuffer = (IHANDLE **) Buffer;
152 Status = EFI_SUCCESS;
153
154 //
155 // Lock the protocol database
156 //
157 CoreAcquireProtocolLock ();
158
159 //
160 // Get the search function based on type
161 //
162 switch (SearchType) {
163 case AllHandles:
164 GetNext = CoreGetNextLocateAllHandles;
165 break;
166
167 case ByRegisterNotify:
168 //
169 // Must have SearchKey for locate ByRegisterNotify
170 //
171 if (SearchKey == NULL) {
172 Status = EFI_INVALID_PARAMETER;
173 break;
174 }
175 GetNext = CoreGetNextLocateByRegisterNotify;
176 break;
177
178 case ByProtocol:
179 GetNext = CoreGetNextLocateByProtocol;
180 if (Protocol == NULL) {
181 Status = EFI_INVALID_PARAMETER;
182 break;
183 }
184 //
185 // Look up the protocol entry and set the head pointer
186 //
187 Position.ProtEntry = CoreFindProtocolEntry (Protocol, FALSE);
188 if (Position.ProtEntry == NULL) {
189 Status = EFI_NOT_FOUND;
190 break;
191 }
192 Position.Position = &Position.ProtEntry->Protocols;
193 break;
194
195 default:
196 Status = EFI_INVALID_PARAMETER;
197 break;
198 }
199
200 if (EFI_ERROR(Status)) {
201 CoreReleaseProtocolLock ();
202 return Status;
203 }
204
205 //
206 // Enumerate out the matching handles
207 //
208 mEfiLocateHandleRequest += 1;
209 for (; ;) {
210 //
211 // Get the next handle. If no more handles, stop
212 //
213 Handle = GetNext (&Position, &Interface);
214 if (NULL == Handle) {
215 break;
216 }
217
218 //
219 // Increase the resulting buffer size, and if this handle
220 // fits return it
221 //
222 ResultSize += sizeof(Handle);
223 if (ResultSize <= *BufferSize) {
224 *ResultBuffer = Handle;
225 ResultBuffer += 1;
226 }
227 }
228
229 //
230 // If the result is a zero length buffer, then there were no
231 // matching handles
232 //
233 if (ResultSize == 0) {
234 Status = EFI_NOT_FOUND;
235 } else {
236 //
237 // Return the resulting buffer size. If it's larger than what
238 // was passed, then set the error code
239 //
240 if (ResultSize > *BufferSize) {
241 Status = EFI_BUFFER_TOO_SMALL;
242 }
243
244 *BufferSize = ResultSize;
245
246 if (SearchType == ByRegisterNotify && !EFI_ERROR(Status)) {
247 //
248 // If this is a search by register notify and a handle was
249 // returned, update the register notification position
250 //
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_HANDLE 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_HANDLE;
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_HANDLE 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_HANDLE;
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 = (IHANDLE *) 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_HANDLE 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_HANDLE;
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_HANDLE;
384 break;
385 }
386
387 //
388 // Get the handle
389 //
390 Prot = CR(Link, PROTOCOL_INTERFACE, ByProtocol, PROTOCOL_INTERFACE_SIGNATURE);
391 Handle = (IHANDLE *) 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 best matches the specified protocol.
410
411 @param Protocol The protocol to search for.
412 @param DevicePath On input, a pointer to a pointer to the device
413 path. On output, the device path pointer is
414 modified to point to the remaining part of the
415 devicepath.
416 @param Device A pointer to the returned device handle.
417
418 @retval EFI_SUCCESS The resulting handle was returned.
419 @retval EFI_NOT_FOUND No handles matched the search.
420 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
421
422 **/
423 EFI_STATUS
424 EFIAPI
425 CoreLocateDevicePath (
426 IN EFI_GUID *Protocol,
427 IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath,
428 OUT EFI_HANDLE *Device
429 )
430 {
431 INTN SourceSize;
432 INTN Size;
433 INTN BestMatch;
434 UINTN HandleCount;
435 UINTN Index;
436 EFI_STATUS Status;
437 EFI_HANDLE *Handles;
438 EFI_HANDLE Handle;
439 EFI_DEVICE_PATH_PROTOCOL *SourcePath;
440 EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath;
441
442 if (Protocol == NULL) {
443 return EFI_INVALID_PARAMETER;
444 }
445
446 if ((DevicePath == NULL) || (*DevicePath == NULL)) {
447 return EFI_INVALID_PARAMETER;
448 }
449
450 if (Device == NULL) {
451 return EFI_INVALID_PARAMETER;
452 }
453
454 *Device = NULL_HANDLE;
455 SourcePath = *DevicePath;
456 SourceSize = CoreDevicePathSize (SourcePath) - sizeof(EFI_DEVICE_PATH_PROTOCOL);
457
458 //
459 // The source path can only have 1 instance
460 //
461 if (CoreIsDevicePathMultiInstance (SourcePath)) {
462 DEBUG((DEBUG_ERROR, "LocateDevicePath: Device path has too many instances\n"));
463 return EFI_INVALID_PARAMETER;
464 }
465
466 //
467 // Get a list of all handles that support the requested protocol
468 //
469 Status = CoreLocateHandleBuffer (ByProtocol, Protocol, NULL, &HandleCount, &Handles);
470 if (EFI_ERROR (Status) || HandleCount == 0) {
471 return EFI_NOT_FOUND;
472 }
473
474 BestMatch = -1;
475 for(Index = 0; Index < HandleCount; Index += 1) {
476 Handle = Handles[Index];
477 Status = CoreHandleProtocol (Handle, &gEfiDevicePathProtocolGuid, (VOID **)&TmpDevicePath);
478 if (EFI_ERROR (Status)) {
479 //
480 // If this handle doesn't support device path, then skip it
481 //
482 continue;
483 }
484
485 //
486 // Check if DevicePath is first part of SourcePath
487 //
488 Size = CoreDevicePathSize (TmpDevicePath) - sizeof(EFI_DEVICE_PATH_PROTOCOL);
489 if ((Size <= SourceSize) && CompareMem (SourcePath, TmpDevicePath, Size) == 0) {
490 //
491 // If the size is equal to the best match, then we
492 // have a duplice device path for 2 different device
493 // handles
494 //
495 ASSERT (Size != BestMatch);
496
497 //
498 // We've got a match, see if it's the best match so far
499 //
500 if (Size > BestMatch) {
501 BestMatch = Size;
502 *Device = Handle;
503 }
504 }
505 }
506
507 CoreFreePool (Handles);
508
509 //
510 // If there wasn't any match, then no parts of the device path was found.
511 // Which is strange since there is likely a "root level" device path in the system.
512 //
513 if (BestMatch == -1) {
514 return EFI_NOT_FOUND;
515 }
516
517 //
518 // Return the remaining part of the device path
519 //
520 *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) (((UINT8 *) SourcePath) + BestMatch);
521 return EFI_SUCCESS;
522 }
523
524
525 /**
526 Return the first Protocol Interface that matches the Protocol GUID. If
527 Registration is pasased in return a Protocol Instance that was just add
528 to the system. If Retistration is NULL return the first Protocol Interface
529 you find.
530
531 @param Protocol The protocol to search for
532 @param Registration Optional Registration Key returned from
533 RegisterProtocolNotify()
534 @param Interface Return the Protocol interface (instance).
535
536 @retval EFI_SUCCESS If a valid Interface is returned
537 @retval EFI_INVALID_PARAMETER Invalid parameter
538 @retval EFI_NOT_FOUND Protocol interface not found
539
540 **/
541 EFI_STATUS
542 EFIAPI
543 CoreLocateProtocol (
544 IN EFI_GUID *Protocol,
545 IN VOID *Registration OPTIONAL,
546 OUT VOID **Interface
547 )
548 {
549 EFI_STATUS Status;
550 LOCATE_POSITION Position;
551 PROTOCOL_NOTIFY *ProtNotify;
552 IHANDLE *Handle;
553
554 if (Interface == NULL) {
555 return EFI_INVALID_PARAMETER;
556 }
557
558 if (Protocol == NULL) {
559 return EFI_NOT_FOUND;
560 }
561
562 *Interface = NULL;
563 Status = EFI_SUCCESS;
564
565 //
566 // Set initial position
567 //
568 Position.Protocol = Protocol;
569 Position.SearchKey = Registration;
570 Position.Position = &gHandleList;
571
572 //
573 // Lock the protocol database
574 //
575 CoreAcquireProtocolLock ();
576
577 mEfiLocateHandleRequest += 1;
578
579 if (Registration == NULL) {
580 //
581 // Look up the protocol entry and set the head pointer
582 //
583 Position.ProtEntry = CoreFindProtocolEntry (Protocol, FALSE);
584 if (Position.ProtEntry == NULL) {
585 Status = EFI_NOT_FOUND;
586 goto Done;
587 }
588 Position.Position = &Position.ProtEntry->Protocols;
589
590 Handle = CoreGetNextLocateByProtocol (&Position, Interface);
591 } else {
592 Handle = CoreGetNextLocateByRegisterNotify (&Position, Interface);
593 }
594
595 if (Handle == NULL) {
596 Status = EFI_NOT_FOUND;
597 } else if (Registration != NULL) {
598 //
599 // If this is a search by register notify and a handle was
600 // returned, update the register notification position
601 //
602 ProtNotify = Registration;
603 ProtNotify->Position = ProtNotify->Position->ForwardLink;
604 }
605
606 Done:
607 CoreReleaseProtocolLock ();
608 return Status;
609 }
610
611
612 /**
613 Function returns an array of handles that support the requested protocol
614 in a buffer allocated from pool. This is a version of CoreLocateHandle()
615 that allocates a buffer for the caller.
616
617 @param SearchType Specifies which handle(s) are to be returned.
618 @param Protocol Provides the protocol to search by. This
619 parameter is only valid for SearchType
620 ByProtocol.
621 @param SearchKey Supplies the search key depending on the
622 SearchType.
623 @param NumberHandles The number of handles returned in Buffer.
624 @param Buffer A pointer to the buffer to return the requested
625 array of handles that support Protocol.
626
627 @retval EFI_SUCCESS The result array of handles was returned.
628 @retval EFI_NOT_FOUND No handles match the search.
629 @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the
630 matching results.
631 @retval EFI_INVALID_PARAMETER One or more paramters are not valid.
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 EFI_STATUS Status;
645 UINTN BufferSize;
646
647 if (NumberHandles == NULL) {
648 return EFI_INVALID_PARAMETER;
649 }
650
651 if (Buffer == NULL) {
652 return EFI_INVALID_PARAMETER;
653 }
654
655 BufferSize = 0;
656 *NumberHandles = 0;
657 *Buffer = NULL;
658 Status = CoreLocateHandle (
659 SearchType,
660 Protocol,
661 SearchKey,
662 &BufferSize,
663 *Buffer
664 );
665 //
666 // LocateHandleBuffer() returns incorrect status code if SearchType is
667 // invalid.
668 //
669 // Add code to correctly handle expected errors from CoreLocateHandle().
670 //
671 if (EFI_ERROR(Status) && Status != EFI_BUFFER_TOO_SMALL) {
672 if (Status != EFI_INVALID_PARAMETER) {
673 Status = EFI_NOT_FOUND;
674 }
675 return Status;
676 }
677
678 *Buffer = CoreAllocateBootServicesPool (BufferSize);
679 if (*Buffer == NULL) {
680 return EFI_OUT_OF_RESOURCES;
681 }
682
683 Status = CoreLocateHandle (
684 SearchType,
685 Protocol,
686 SearchKey,
687 &BufferSize,
688 *Buffer
689 );
690
691 *NumberHandles = BufferSize / sizeof(EFI_HANDLE);
692 if (EFI_ERROR(Status)) {
693 *NumberHandles = 0;
694 }
695
696 return Status;
697 }
698
699
700