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