1 /** @file 2 Locate handle functions 3 4 Copyright (c) 2006 - 2014, 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 CoreAcquireProtocolLock (); 585 586 mEfiLocateHandleRequest += 1; 587 588 if (Registration == NULL) { 589 // 590 // Look up the protocol entry and set the head pointer 591 // 592 Position.ProtEntry = CoreFindProtocolEntry (Protocol, FALSE); 593 if (Position.ProtEntry == NULL) { 594 Status = EFI_NOT_FOUND; 595 goto Done; 596 } 597 Position.Position = &Position.ProtEntry->Protocols; 598 599 Handle = CoreGetNextLocateByProtocol (&Position, Interface); 600 } else { 601 Handle = CoreGetNextLocateByRegisterNotify (&Position, Interface); 602 } 603 604 if (Handle == NULL) { 605 Status = EFI_NOT_FOUND; 606 } else if (Registration != NULL) { 607 // 608 // If this is a search by register notify and a handle was 609 // returned, update the register notification position 610 // 611 ProtNotify = Registration; 612 ProtNotify->Position = ProtNotify->Position->ForwardLink; 613 } 614 615 Done: 616 CoreReleaseProtocolLock (); 617 return Status; 618 } 619 620 621 /** 622 Function returns an array of handles that support the requested protocol 623 in a buffer allocated from pool. This is a version of CoreLocateHandle() 624 that allocates a buffer for the caller. 625 626 @param SearchType Specifies which handle(s) are to be returned. 627 @param Protocol Provides the protocol to search by. This 628 parameter is only valid for SearchType 629 ByProtocol. 630 @param SearchKey Supplies the search key depending on the 631 SearchType. 632 @param NumberHandles The number of handles returned in Buffer. 633 @param Buffer A pointer to the buffer to return the requested 634 array of handles that support Protocol. 635 636 @retval EFI_SUCCESS The result array of handles was returned. 637 @retval EFI_NOT_FOUND No handles match the search. 638 @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the 639 matching results. 640 @retval EFI_INVALID_PARAMETER One or more paramters are not valid. 641 642 **/ 643 EFI_STATUS 644 EFIAPI 645 CoreLocateHandleBuffer ( 646 IN EFI_LOCATE_SEARCH_TYPE SearchType, 647 IN EFI_GUID *Protocol OPTIONAL, 648 IN VOID *SearchKey OPTIONAL, 649 IN OUT UINTN *NumberHandles, 650 OUT EFI_HANDLE **Buffer 651 ) 652 { 653 EFI_STATUS Status; 654 UINTN BufferSize; 655 656 if (NumberHandles == NULL) { 657 return EFI_INVALID_PARAMETER; 658 } 659 660 if (Buffer == NULL) { 661 return EFI_INVALID_PARAMETER; 662 } 663 664 BufferSize = 0; 665 *NumberHandles = 0; 666 *Buffer = NULL; 667 Status = CoreLocateHandle ( 668 SearchType, 669 Protocol, 670 SearchKey, 671 &BufferSize, 672 *Buffer 673 ); 674 // 675 // LocateHandleBuffer() returns incorrect status code if SearchType is 676 // invalid. 677 // 678 // Add code to correctly handle expected errors from CoreLocateHandle(). 679 // 680 if (EFI_ERROR(Status) && Status != EFI_BUFFER_TOO_SMALL) { 681 if (Status != EFI_INVALID_PARAMETER) { 682 Status = EFI_NOT_FOUND; 683 } 684 return Status; 685 } 686 687 *Buffer = AllocatePool (BufferSize); 688 if (*Buffer == NULL) { 689 return EFI_OUT_OF_RESOURCES; 690 } 691 692 Status = CoreLocateHandle ( 693 SearchType, 694 Protocol, 695 SearchKey, 696 &BufferSize, 697 *Buffer 698 ); 699 700 *NumberHandles = BufferSize / sizeof(EFI_HANDLE); 701 if (EFI_ERROR(Status)) { 702 *NumberHandles = 0; 703 } 704 705 return Status; 706 } 707 708 709 710