]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Dxe/Hand/Locate.c
Roll back changes to apply GetBestLanguage() in HiiDataBase. Exact language match...
[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 #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 //
204 // Enumerate out the matching handles
205 //
206 mEfiLocateHandleRequest += 1;
207 for (; ;) {
208 //
209 // Get the next handle. If no more handles, stop
210 //
211 Handle = GetNext (&Position, &Interface);
212 if (NULL == Handle) {
213 break;
214 }
215
216 //
217 // Increase the resulting buffer size, and if this handle
218 // fits return it
219 //
220 ResultSize += sizeof(Handle);
221 if (ResultSize <= *BufferSize) {
222 *ResultBuffer = Handle;
223 ResultBuffer += 1;
224 }
225 }
226
227 //
228 // If the result is a zero length buffer, then there were no
229 // matching handles
230 //
231 if (ResultSize == 0) {
232 Status = EFI_NOT_FOUND;
233 } else {
234 //
235 // Return the resulting buffer size. If it's larger than what
236 // was passed, then set the error code
237 //
238 if (ResultSize > *BufferSize) {
239 Status = EFI_BUFFER_TOO_SMALL;
240 }
241
242 *BufferSize = ResultSize;
243
244 if (SearchType == ByRegisterNotify && !EFI_ERROR(Status)) {
245 //
246 // If this is a search by register notify and a handle was
247 // returned, update the register notification position
248 //
249 ProtNotify = SearchKey;
250 ProtNotify->Position = ProtNotify->Position->ForwardLink;
251 }
252 }
253
254 CoreReleaseProtocolLock ();
255 return Status;
256 }
257
258
259
260 /**
261 Routine to get the next Handle, when you are searching for all handles.
262
263 @param Position Information about which Handle to seach for.
264 @param Interface Return the interface structure for the matching
265 protocol.
266
267 @return An pointer to IHANDLE if the next Position is not the end of the list.
268 Otherwise,NULL is returned.
269
270 **/
271 IHANDLE *
272 CoreGetNextLocateAllHandles (
273 IN OUT LOCATE_POSITION *Position,
274 OUT VOID **Interface
275 )
276 {
277 IHANDLE *Handle;
278
279 //
280 // Next handle
281 //
282 Position->Position = Position->Position->ForwardLink;
283
284 //
285 // If not at the end of the list, get the handle
286 //
287 Handle = NULL;
288 *Interface = NULL;
289 if (Position->Position != &gHandleList) {
290 Handle = CR (Position->Position, IHANDLE, AllHandles, EFI_HANDLE_SIGNATURE);
291 }
292
293 return Handle;
294 }
295
296
297
298 /**
299 Routine to get the next Handle, when you are searching for register protocol
300 notifies.
301
302 @param Position Information about which Handle to seach for.
303 @param Interface Return the interface structure for the matching
304 protocol.
305
306 @return An pointer to IHANDLE if the next Position is not the end of the list.
307 Otherwise,NULL is returned.
308
309 **/
310 IHANDLE *
311 CoreGetNextLocateByRegisterNotify (
312 IN OUT LOCATE_POSITION *Position,
313 OUT VOID **Interface
314 )
315 {
316 IHANDLE *Handle;
317 PROTOCOL_NOTIFY *ProtNotify;
318 PROTOCOL_INTERFACE *Prot;
319 LIST_ENTRY *Link;
320
321 Handle = NULL;
322 *Interface = NULL;
323 ProtNotify = Position->SearchKey;
324
325 //
326 // If this is the first request, get the next handle
327 //
328 if (ProtNotify != NULL) {
329 ASSERT(ProtNotify->Signature == PROTOCOL_NOTIFY_SIGNATURE);
330 Position->SearchKey = NULL;
331
332 //
333 // If not at the end of the list, get the next handle
334 //
335 Link = ProtNotify->Position->ForwardLink;
336 if (Link != &ProtNotify->Protocol->Protocols) {
337 Prot = CR (Link, PROTOCOL_INTERFACE, ByProtocol, PROTOCOL_INTERFACE_SIGNATURE);
338 Handle = Prot->Handle;
339 *Interface = Prot->Interface;
340 }
341 }
342
343 return Handle;
344 }
345
346
347 /**
348 Routine to get the next Handle, when you are searching for a given protocol.
349
350 @param Position Information about which Handle to seach for.
351 @param Interface Return the interface structure for the matching
352 protocol.
353
354 @return An pointer to IHANDLE if the next Position is not the end of the list.
355 Otherwise,NULL is returned.
356
357 **/
358 IHANDLE *
359 CoreGetNextLocateByProtocol (
360 IN OUT LOCATE_POSITION *Position,
361 OUT VOID **Interface
362 )
363 {
364 IHANDLE *Handle;
365 LIST_ENTRY *Link;
366 PROTOCOL_INTERFACE *Prot;
367
368 Handle = NULL;
369 *Interface = NULL;
370 for (; ;) {
371 //
372 // Next entry
373 //
374 Link = Position->Position->ForwardLink;
375 Position->Position = Link;
376
377 //
378 // If not at the end, return the handle
379 //
380 if (Link == &Position->ProtEntry->Protocols) {
381 Handle = NULL;
382 break;
383 }
384
385 //
386 // Get the handle
387 //
388 Prot = CR(Link, PROTOCOL_INTERFACE, ByProtocol, PROTOCOL_INTERFACE_SIGNATURE);
389 Handle = Prot->Handle;
390 *Interface = Prot->Interface;
391
392 //
393 // If this handle has not been returned this request, then
394 // return it now
395 //
396 if (Handle->LocateRequest != mEfiLocateHandleRequest) {
397 Handle->LocateRequest = mEfiLocateHandleRequest;
398 break;
399 }
400 }
401
402 return Handle;
403 }
404
405
406 /**
407 Locates the handle to a device on the device path that best matches the specified protocol.
408
409 @param Protocol The protocol to search for.
410 @param DevicePath On input, a pointer to a pointer to the device
411 path. On output, the device path pointer is
412 modified to point to the remaining part of the
413 devicepath.
414 @param Device A pointer to the returned device handle.
415
416 @retval EFI_SUCCESS The resulting handle was returned.
417 @retval EFI_NOT_FOUND No handles matched the search.
418 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
419
420 **/
421 EFI_STATUS
422 EFIAPI
423 CoreLocateDevicePath (
424 IN EFI_GUID *Protocol,
425 IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath,
426 OUT EFI_HANDLE *Device
427 )
428 {
429 INTN SourceSize;
430 INTN Size;
431 INTN BestMatch;
432 UINTN HandleCount;
433 UINTN Index;
434 EFI_STATUS Status;
435 EFI_HANDLE *Handles;
436 EFI_HANDLE Handle;
437 EFI_DEVICE_PATH_PROTOCOL *SourcePath;
438 EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath;
439
440 if (Protocol == NULL) {
441 return EFI_INVALID_PARAMETER;
442 }
443
444 if ((DevicePath == NULL) || (*DevicePath == NULL)) {
445 return EFI_INVALID_PARAMETER;
446 }
447
448 if (Device == NULL) {
449 return EFI_INVALID_PARAMETER;
450 }
451
452 *Device = NULL;
453 SourcePath = *DevicePath;
454 SourceSize = GetDevicePathSize (SourcePath) - sizeof(EFI_DEVICE_PATH_PROTOCOL);
455
456 //
457 // The source path can only have 1 instance
458 //
459 if (IsDevicePathMultiInstance (SourcePath)) {
460 DEBUG((DEBUG_ERROR, "LocateDevicePath: Device path has too many instances\n"));
461 return EFI_INVALID_PARAMETER;
462 }
463
464 //
465 // Get a list of all handles that support the requested protocol
466 //
467 Status = CoreLocateHandleBuffer (ByProtocol, Protocol, NULL, &HandleCount, &Handles);
468 if (EFI_ERROR (Status) || HandleCount == 0) {
469 return EFI_NOT_FOUND;
470 }
471
472 BestMatch = -1;
473 for(Index = 0; Index < HandleCount; Index += 1) {
474 Handle = Handles[Index];
475 Status = CoreHandleProtocol (Handle, &gEfiDevicePathProtocolGuid, (VOID **)&TmpDevicePath);
476 if (EFI_ERROR (Status)) {
477 //
478 // If this handle doesn't support device path, then skip it
479 //
480 continue;
481 }
482
483 //
484 // Check if DevicePath is first part of SourcePath
485 //
486 Size = GetDevicePathSize (TmpDevicePath) - sizeof(EFI_DEVICE_PATH_PROTOCOL);
487 if ((Size <= SourceSize) && CompareMem (SourcePath, TmpDevicePath, Size) == 0) {
488 //
489 // If the size is equal to the best match, then we
490 // have a duplice device path for 2 different device
491 // handles
492 //
493 ASSERT (Size != BestMatch);
494
495 //
496 // We've got a match, see if it's the best match so far
497 //
498 if (Size > BestMatch) {
499 BestMatch = Size;
500 *Device = Handle;
501 }
502 }
503 }
504
505 CoreFreePool (Handles);
506
507 //
508 // If there wasn't any match, then no parts of the device path was found.
509 // Which is strange since there is likely a "root level" device path in the system.
510 //
511 if (BestMatch == -1) {
512 return EFI_NOT_FOUND;
513 }
514
515 //
516 // Return the remaining part of the device path
517 //
518 *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) (((UINT8 *) SourcePath) + BestMatch);
519 return EFI_SUCCESS;
520 }
521
522
523 /**
524 Return the first Protocol Interface that matches the Protocol GUID. If
525 Registration is passed in, return a Protocol Instance that was just add
526 to the system. If Registration is NULL return the first Protocol Interface
527 you find.
528
529 @param Protocol The protocol to search for
530 @param Registration Optional Registration Key returned from
531 RegisterProtocolNotify()
532 @param Interface Return the Protocol interface (instance).
533
534 @retval EFI_SUCCESS If a valid Interface is returned
535 @retval EFI_INVALID_PARAMETER Invalid parameter
536 @retval EFI_NOT_FOUND Protocol interface not found
537
538 **/
539 EFI_STATUS
540 EFIAPI
541 CoreLocateProtocol (
542 IN EFI_GUID *Protocol,
543 IN VOID *Registration OPTIONAL,
544 OUT VOID **Interface
545 )
546 {
547 EFI_STATUS Status;
548 LOCATE_POSITION Position;
549 PROTOCOL_NOTIFY *ProtNotify;
550 IHANDLE *Handle;
551
552 if (Interface == NULL) {
553 return EFI_INVALID_PARAMETER;
554 }
555
556 if (Protocol == NULL) {
557 return EFI_NOT_FOUND;
558 }
559
560 *Interface = NULL;
561 Status = EFI_SUCCESS;
562
563 //
564 // Set initial position
565 //
566 Position.Protocol = Protocol;
567 Position.SearchKey = Registration;
568 Position.Position = &gHandleList;
569
570 //
571 // Lock the protocol database
572 //
573 CoreAcquireProtocolLock ();
574
575 mEfiLocateHandleRequest += 1;
576
577 if (Registration == NULL) {
578 //
579 // Look up the protocol entry and set the head pointer
580 //
581 Position.ProtEntry = CoreFindProtocolEntry (Protocol, FALSE);
582 if (Position.ProtEntry == NULL) {
583 Status = EFI_NOT_FOUND;
584 goto Done;
585 }
586 Position.Position = &Position.ProtEntry->Protocols;
587
588 Handle = CoreGetNextLocateByProtocol (&Position, Interface);
589 } else {
590 Handle = CoreGetNextLocateByRegisterNotify (&Position, Interface);
591 }
592
593 if (Handle == NULL) {
594 Status = EFI_NOT_FOUND;
595 } else if (Registration != NULL) {
596 //
597 // If this is a search by register notify and a handle was
598 // returned, update the register notification position
599 //
600 ProtNotify = Registration;
601 ProtNotify->Position = ProtNotify->Position->ForwardLink;
602 }
603
604 Done:
605 CoreReleaseProtocolLock ();
606 return Status;
607 }
608
609
610 /**
611 Function returns an array of handles that support the requested protocol
612 in a buffer allocated from pool. This is a version of CoreLocateHandle()
613 that allocates a buffer for the caller.
614
615 @param SearchType Specifies which handle(s) are to be returned.
616 @param Protocol Provides the protocol to search by. This
617 parameter is only valid for SearchType
618 ByProtocol.
619 @param SearchKey Supplies the search key depending on the
620 SearchType.
621 @param NumberHandles The number of handles returned in Buffer.
622 @param Buffer A pointer to the buffer to return the requested
623 array of handles that support Protocol.
624
625 @retval EFI_SUCCESS The result array of handles was returned.
626 @retval EFI_NOT_FOUND No handles match the search.
627 @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the
628 matching results.
629 @retval EFI_INVALID_PARAMETER One or more paramters are not valid.
630
631 **/
632 EFI_STATUS
633 EFIAPI
634 CoreLocateHandleBuffer (
635 IN EFI_LOCATE_SEARCH_TYPE SearchType,
636 IN EFI_GUID *Protocol OPTIONAL,
637 IN VOID *SearchKey OPTIONAL,
638 IN OUT UINTN *NumberHandles,
639 OUT EFI_HANDLE **Buffer
640 )
641 {
642 EFI_STATUS Status;
643 UINTN BufferSize;
644
645 if (NumberHandles == NULL) {
646 return EFI_INVALID_PARAMETER;
647 }
648
649 if (Buffer == NULL) {
650 return EFI_INVALID_PARAMETER;
651 }
652
653 BufferSize = 0;
654 *NumberHandles = 0;
655 *Buffer = NULL;
656 Status = CoreLocateHandle (
657 SearchType,
658 Protocol,
659 SearchKey,
660 &BufferSize,
661 *Buffer
662 );
663 //
664 // LocateHandleBuffer() returns incorrect status code if SearchType is
665 // invalid.
666 //
667 // Add code to correctly handle expected errors from CoreLocateHandle().
668 //
669 if (EFI_ERROR(Status) && Status != EFI_BUFFER_TOO_SMALL) {
670 if (Status != EFI_INVALID_PARAMETER) {
671 Status = EFI_NOT_FOUND;
672 }
673 return Status;
674 }
675
676 *Buffer = AllocatePool (BufferSize);
677 if (*Buffer == NULL) {
678 return EFI_OUT_OF_RESOURCES;
679 }
680
681 Status = CoreLocateHandle (
682 SearchType,
683 Protocol,
684 SearchKey,
685 &BufferSize,
686 *Buffer
687 );
688
689 *NumberHandles = BufferSize / sizeof(EFI_HANDLE);
690 if (EFI_ERROR(Status)) {
691 *NumberHandles = 0;
692 }
693
694 return Status;
695 }
696
697
698