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