1/** @file 2 BDS Lib functions which relate with create or process the boot option. 3 4Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR> 5This program and the accompanying materials 6are licensed and made available under the terms and conditions of the BSD License 7which accompanies this distribution. The full text of the license may be found at 8http://opensource.org/licenses/bsd-license.php 9 10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 12 13**/ 14 15#include "InternalBdsLib.h" 16#include "String.h" 17#include <Library/NetLib.h> 18#include "Library/DebugLib.h" 19 20BOOLEAN mEnumBootDevice = FALSE; 21EFI_HII_HANDLE gBdsLibStringPackHandle = NULL; 22 23/** 24 The constructor function register UNI strings into imageHandle. 25 26 It will ASSERT() if that operation fails and it will always return EFI_SUCCESS. 27 28 @param ImageHandle The firmware allocated handle for the EFI image. 29 @param SystemTable A pointer to the EFI System Table. 30 31 @retval EFI_SUCCESS The constructor successfully added string package. 32 @retval Other value The constructor can't add string package. 33 34**/ 35EFI_STATUS 36EFIAPI 37GenericBdsLibConstructor ( 38 IN EFI_HANDLE ImageHandle, 39 IN EFI_SYSTEM_TABLE *SystemTable 40 ) 41{ 42 43 gBdsLibStringPackHandle = HiiAddPackages ( 44 &gBdsLibStringPackageGuid, 45 ImageHandle, 46 GenericBdsLibStrings, 47 NULL 48 ); 49 50 ASSERT (gBdsLibStringPackHandle != NULL); 51 52 return EFI_SUCCESS; 53} 54 55/** 56 Deletete the Boot Option from EFI Variable. The Boot Order Arrray 57 is also updated. 58 59 @param OptionNumber The number of Boot option want to be deleted. 60 @param BootOrder The Boot Order array. 61 @param BootOrderSize The size of the Boot Order Array. 62 63 @retval EFI_SUCCESS The Boot Option Variable was found and removed 64 @retval EFI_UNSUPPORTED The Boot Option Variable store was inaccessible 65 @retval EFI_NOT_FOUND The Boot Option Variable was not found 66**/ 67EFI_STATUS 68EFIAPI 69BdsDeleteBootOption ( 70 IN UINTN OptionNumber, 71 IN OUT UINT16 *BootOrder, 72 IN OUT UINTN *BootOrderSize 73 ) 74{ 75 CHAR16 BootOption[9]; 76 UINTN Index; 77 EFI_STATUS Status; 78 79 UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", OptionNumber); 80 Status = gRT->SetVariable ( 81 BootOption, 82 &gEfiGlobalVariableGuid, 83 0, 84 0, 85 NULL 86 ); 87 // 88 // Deleting variable with existing variable implementation shouldn't fail. 89 // 90 ASSERT_EFI_ERROR (Status); 91 92 // 93 // adjust boot order array 94 // 95 for (Index = 0; Index < *BootOrderSize / sizeof (UINT16); Index++) { 96 if (BootOrder[Index] == OptionNumber) { 97 CopyMem (&BootOrder[Index], &BootOrder[Index+1], *BootOrderSize - (Index+1) * sizeof (UINT16)); 98 *BootOrderSize -= sizeof (UINT16); 99 break; 100 } 101 } 102 103 return Status; 104} 105/** 106 107 Translate the first n characters of an Ascii string to 108 Unicode characters. The count n is indicated by parameter 109 Size. If Size is greater than the length of string, then 110 the entire string is translated. 111 112 113 @param AStr Pointer to input Ascii string. 114 @param Size The number of characters to translate. 115 @param UStr Pointer to output Unicode string buffer. 116 117**/ 118VOID 119AsciiToUnicodeSize ( 120 IN UINT8 *AStr, 121 IN UINTN Size, 122 OUT UINT16 *UStr 123 ) 124{ 125 UINTN Idx; 126 127 Idx = 0; 128 while (AStr[Idx] != 0) { 129 UStr[Idx] = (CHAR16) AStr[Idx]; 130 if (Idx == Size) { 131 break; 132 } 133 134 Idx++; 135 } 136 UStr[Idx] = 0; 137} 138 139/** 140 Build Legacy Device Name String according. 141 142 @param CurBBSEntry BBS Table. 143 @param Index Index. 144 @param BufSize The buffer size. 145 @param BootString The output string. 146 147**/ 148VOID 149BdsBuildLegacyDevNameString ( 150 IN BBS_TABLE *CurBBSEntry, 151 IN UINTN Index, 152 IN UINTN BufSize, 153 OUT CHAR16 *BootString 154 ) 155{ 156 CHAR16 *Fmt; 157 CHAR16 *Type; 158 UINT8 *StringDesc; 159 CHAR16 Temp[80]; 160 161 switch (Index) { 162 // 163 // Primary Master 164 // 165 case 1: 166 Fmt = L"Primary Master %s"; 167 break; 168 169 // 170 // Primary Slave 171 // 172 case 2: 173 Fmt = L"Primary Slave %s"; 174 break; 175 176 // 177 // Secondary Master 178 // 179 case 3: 180 Fmt = L"Secondary Master %s"; 181 break; 182 183 // 184 // Secondary Slave 185 // 186 case 4: 187 Fmt = L"Secondary Slave %s"; 188 break; 189 190 default: 191 Fmt = L"%s"; 192 break; 193 } 194 195 switch (CurBBSEntry->DeviceType) { 196 case BBS_FLOPPY: 197 Type = L"Floppy"; 198 break; 199 200 case BBS_HARDDISK: 201 Type = L"Harddisk"; 202 break; 203 204 case BBS_CDROM: 205 Type = L"CDROM"; 206 break; 207 208 case BBS_PCMCIA: 209 Type = L"PCMCIAe"; 210 break; 211 212 case BBS_USB: 213 Type = L"USB"; 214 break; 215 216 case BBS_EMBED_NETWORK: 217 Type = L"Network"; 218 break; 219 220 case BBS_BEV_DEVICE: 221 Type = L"BEVe"; 222 break; 223 224 case BBS_UNKNOWN: 225 default: 226 Type = L"Unknown"; 227 break; 228 } 229 // 230 // If current BBS entry has its description then use it. 231 // 232 StringDesc = (UINT8 *) (UINTN) ((CurBBSEntry->DescStringSegment << 4) + CurBBSEntry->DescStringOffset); 233 if (NULL != StringDesc) { 234 // 235 // Only get fisrt 32 characters, this is suggested by BBS spec 236 // 237 AsciiToUnicodeSize (StringDesc, 32, Temp); 238 Fmt = L"%s"; 239 Type = Temp; 240 } 241 242 // 243 // BbsTable 16 entries are for onboard IDE. 244 // Set description string for SATA harddisks, Harddisk 0 ~ Harddisk 11 245 // 246 if (Index >= 5 && Index <= 16 && (CurBBSEntry->DeviceType == BBS_HARDDISK || CurBBSEntry->DeviceType == BBS_CDROM)) { 247 Fmt = L"%s %d"; 248 UnicodeSPrint (BootString, BufSize, Fmt, Type, Index - 5); 249 } else { 250 UnicodeSPrint (BootString, BufSize, Fmt, Type); 251 } 252} 253 254/** 255 256 Create a legacy boot option for the specified entry of 257 BBS table, save it as variable, and append it to the boot 258 order list. 259 260 261 @param CurrentBbsEntry Pointer to current BBS table. 262 @param CurrentBbsDevPath Pointer to the Device Path Protocol instance of BBS 263 @param Index Index of the specified entry in BBS table. 264 @param BootOrderList On input, the original boot order list. 265 On output, the new boot order list attached with the 266 created node. 267 @param BootOrderListSize On input, the original size of boot order list. 268 On output, the size of new boot order list. 269 270 @retval EFI_SUCCESS Boot Option successfully created. 271 @retval EFI_OUT_OF_RESOURCES Fail to allocate necessary memory. 272 @retval Other Error occurs while setting variable. 273 274**/ 275EFI_STATUS 276BdsCreateLegacyBootOption ( 277 IN BBS_TABLE *CurrentBbsEntry, 278 IN EFI_DEVICE_PATH_PROTOCOL *CurrentBbsDevPath, 279 IN UINTN Index, 280 IN OUT UINT16 **BootOrderList, 281 IN OUT UINTN *BootOrderListSize 282 ) 283{ 284 EFI_STATUS Status; 285 UINT16 CurrentBootOptionNo; 286 UINT16 BootString[10]; 287 CHAR16 BootDesc[100]; 288 CHAR8 HelpString[100]; 289 UINT16 *NewBootOrderList; 290 UINTN BufferSize; 291 UINTN StringLen; 292 VOID *Buffer; 293 UINT8 *Ptr; 294 UINT16 CurrentBbsDevPathSize; 295 UINTN BootOrderIndex; 296 UINTN BootOrderLastIndex; 297 UINTN ArrayIndex; 298 BOOLEAN IndexNotFound; 299 BBS_BBS_DEVICE_PATH *NewBbsDevPathNode; 300 301 if ((*BootOrderList) == NULL) { 302 CurrentBootOptionNo = 0; 303 } else { 304 for (ArrayIndex = 0; ArrayIndex < (UINTN) (*BootOrderListSize / sizeof (UINT16)); ArrayIndex++) { 305 IndexNotFound = TRUE; 306 for (BootOrderIndex = 0; BootOrderIndex < (UINTN) (*BootOrderListSize / sizeof (UINT16)); BootOrderIndex++) { 307 if ((*BootOrderList)[BootOrderIndex] == ArrayIndex) { 308 IndexNotFound = FALSE; 309 break; 310 } 311 } 312 313 if (!IndexNotFound) { 314 continue; 315 } else { 316 break; 317 } 318 } 319 320 CurrentBootOptionNo = (UINT16) ArrayIndex; 321 } 322 323 UnicodeSPrint ( 324 BootString, 325 sizeof (BootString), 326 L"Boot%04x", 327 CurrentBootOptionNo 328 ); 329 330 BdsBuildLegacyDevNameString (CurrentBbsEntry, Index, sizeof (BootDesc), BootDesc); 331 332 // 333 // Create new BBS device path node with description string 334 // 335 UnicodeStrToAsciiStr (BootDesc, HelpString); 336 337 StringLen = AsciiStrLen (HelpString); 338 NewBbsDevPathNode = AllocateZeroPool (sizeof (BBS_BBS_DEVICE_PATH) + StringLen); 339 if (NewBbsDevPathNode == NULL) { 340 return EFI_OUT_OF_RESOURCES; 341 } 342 CopyMem (NewBbsDevPathNode, CurrentBbsDevPath, sizeof (BBS_BBS_DEVICE_PATH)); 343 CopyMem (NewBbsDevPathNode->String, HelpString, StringLen + 1); 344 SetDevicePathNodeLength (&(NewBbsDevPathNode->Header), sizeof (BBS_BBS_DEVICE_PATH) + StringLen); 345 346 // 347 // Create entire new CurrentBbsDevPath with end node 348 // 349 CurrentBbsDevPath = AppendDevicePathNode ( 350 NULL, 351 (EFI_DEVICE_PATH_PROTOCOL *) NewBbsDevPathNode 352 ); 353 if (CurrentBbsDevPath == NULL) { 354 FreePool (NewBbsDevPathNode); 355 return EFI_OUT_OF_RESOURCES; 356 } 357 358 CurrentBbsDevPathSize = (UINT16) (GetDevicePathSize (CurrentBbsDevPath)); 359 360 BufferSize = sizeof (UINT32) + 361 sizeof (UINT16) + 362 StrSize (BootDesc) + 363 CurrentBbsDevPathSize + 364 sizeof (BBS_TABLE) + 365 sizeof (UINT16); 366 367 Buffer = AllocateZeroPool (BufferSize); 368 if (Buffer == NULL) { 369 FreePool (NewBbsDevPathNode); 370 FreePool (CurrentBbsDevPath); 371 return EFI_OUT_OF_RESOURCES; 372 } 373 374 Ptr = (UINT8 *) Buffer; 375 376 *((UINT32 *) Ptr) = LOAD_OPTION_ACTIVE; 377 Ptr += sizeof (UINT32); 378 379 *((UINT16 *) Ptr) = CurrentBbsDevPathSize; 380 Ptr += sizeof (UINT16); 381 382 CopyMem ( 383 Ptr, 384 BootDesc, 385 StrSize (BootDesc) 386 ); 387 Ptr += StrSize (BootDesc); 388 389 CopyMem ( 390 Ptr, 391 CurrentBbsDevPath, 392 CurrentBbsDevPathSize 393 ); 394 Ptr += CurrentBbsDevPathSize; 395 396 CopyMem ( 397 Ptr, 398 CurrentBbsEntry, 399 sizeof (BBS_TABLE) 400 ); 401 402 Ptr += sizeof (BBS_TABLE); 403 *((UINT16 *) Ptr) = (UINT16) Index; 404 405 Status = gRT->SetVariable ( 406 BootString, 407 &gEfiGlobalVariableGuid, 408 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, 409 BufferSize, 410 Buffer 411 ); 412 413 FreePool (Buffer); 414 415 Buffer = NULL; 416 417 NewBootOrderList = AllocateZeroPool (*BootOrderListSize + sizeof (UINT16)); 418 if (NULL == NewBootOrderList) { 419 FreePool (NewBbsDevPathNode); 420 FreePool (CurrentBbsDevPath); 421 return EFI_OUT_OF_RESOURCES; 422 } 423 424 if (*BootOrderList != NULL) { 425 CopyMem (NewBootOrderList, *BootOrderList, *BootOrderListSize); 426 FreePool (*BootOrderList); 427 } 428 429 BootOrderLastIndex = (UINTN) (*BootOrderListSize / sizeof (UINT16)); 430 NewBootOrderList[BootOrderLastIndex] = CurrentBootOptionNo; 431 *BootOrderListSize += sizeof (UINT16); 432 *BootOrderList = NewBootOrderList; 433 434 FreePool (NewBbsDevPathNode); 435 FreePool (CurrentBbsDevPath); 436 return Status; 437} 438 439/** 440 Check if the boot option is a legacy one. 441 442 @param BootOptionVar The boot option data payload. 443 @param BbsEntry The BBS Table. 444 @param BbsIndex The table index. 445 446 @retval TRUE It is a legacy boot option. 447 @retval FALSE It is not a legacy boot option. 448 449**/ 450BOOLEAN 451BdsIsLegacyBootOption ( 452 IN UINT8 *BootOptionVar, 453 OUT BBS_TABLE **BbsEntry, 454 OUT UINT16 *BbsIndex 455 ) 456{ 457 UINT8 *Ptr; 458 EFI_DEVICE_PATH_PROTOCOL *DevicePath; 459 BOOLEAN Ret; 460 UINT16 DevPathLen; 461 462 Ptr = BootOptionVar; 463 Ptr += sizeof (UINT32); 464 DevPathLen = *(UINT16 *) Ptr; 465 Ptr += sizeof (UINT16); 466 Ptr += StrSize ((UINT16 *) Ptr); 467 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr; 468 if ((BBS_DEVICE_PATH == DevicePath->Type) && (BBS_BBS_DP == DevicePath->SubType)) { 469 Ptr += DevPathLen; 470 *BbsEntry = (BBS_TABLE *) Ptr; 471 Ptr += sizeof (BBS_TABLE); 472 *BbsIndex = *(UINT16 *) Ptr; 473 Ret = TRUE; 474 } else { 475 *BbsEntry = NULL; 476 Ret = FALSE; 477 } 478 479 return Ret; 480} 481 482/** 483 Delete all the invalid legacy boot options. 484 485 @retval EFI_SUCCESS All invalide legacy boot options are deleted. 486 @retval EFI_OUT_OF_RESOURCES Fail to allocate necessary memory. 487 @retval EFI_NOT_FOUND Fail to retrive variable of boot order. 488**/ 489EFI_STATUS 490EFIAPI 491BdsDeleteAllInvalidLegacyBootOptions ( 492 VOID 493 ) 494{ 495 UINT16 *BootOrder; 496 UINT8 *BootOptionVar; 497 UINTN BootOrderSize; 498 UINTN BootOptionSize; 499 EFI_STATUS Status; 500 UINT16 HddCount; 501 UINT16 BbsCount; 502 HDD_INFO *LocalHddInfo; 503 BBS_TABLE *LocalBbsTable; 504 BBS_TABLE *BbsEntry; 505 UINT16 BbsIndex; 506 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; 507 UINTN Index; 508 UINT16 BootOption[10]; 509 UINT16 BootDesc[100]; 510 BOOLEAN DescStringMatch; 511 512 Status = EFI_SUCCESS; 513 BootOrder = NULL; 514 BootOrderSize = 0; 515 HddCount = 0; 516 BbsCount = 0; 517 LocalHddInfo = NULL; 518 LocalBbsTable = NULL; 519 BbsEntry = NULL; 520 521 Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios); 522 if (EFI_ERROR (Status)) { 523 return Status; 524 } 525 526 BootOrder = BdsLibGetVariableAndSize ( 527 L"BootOrder", 528 &gEfiGlobalVariableGuid, 529 &BootOrderSize 530 ); 531 if (BootOrder == NULL) { 532 return EFI_NOT_FOUND; 533 } 534 535 LegacyBios->GetBbsInfo ( 536 LegacyBios, 537 &HddCount, 538 &LocalHddInfo, 539 &BbsCount, 540 &LocalBbsTable 541 ); 542 543 Index = 0; 544 while (Index < BootOrderSize / sizeof (UINT16)) { 545 UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]); 546 BootOptionVar = BdsLibGetVariableAndSize ( 547 BootOption, 548 &gEfiGlobalVariableGuid, 549 &BootOptionSize 550 ); 551 if (NULL == BootOptionVar) { 552 BootOptionSize = 0; 553 Status = gRT->GetVariable ( 554 BootOption, 555 &gEfiGlobalVariableGuid, 556 NULL, 557 &BootOptionSize, 558 BootOptionVar 559 ); 560 if (Status == EFI_NOT_FOUND) { 561 // 562 // Update BootOrder 563 // 564 BdsDeleteBootOption ( 565 BootOrder[Index], 566 BootOrder, 567 &BootOrderSize 568 ); 569 continue; 570 } else { 571 FreePool (BootOrder); 572 return EFI_OUT_OF_RESOURCES; 573 } 574 } 575 576 // 577 // Skip Non-Legacy boot option 578 // 579 if (!BdsIsLegacyBootOption (BootOptionVar, &BbsEntry, &BbsIndex)) { 580 if (BootOptionVar!= NULL) { 581 FreePool (BootOptionVar); 582 } 583 Index++; 584 continue; 585 } 586 587 if (BbsIndex < BbsCount) { 588 // 589 // Check if BBS Description String is changed 590 // 591 DescStringMatch = FALSE; 592 BdsBuildLegacyDevNameString ( 593 &LocalBbsTable[BbsIndex], 594 BbsIndex, 595 sizeof (BootDesc), 596 BootDesc 597 ); 598 599 if (StrCmp (BootDesc, (UINT16*)(BootOptionVar + sizeof (UINT32) + sizeof (UINT16))) == 0) { 600 DescStringMatch = TRUE; 601 } 602 603 if (!((LocalBbsTable[BbsIndex].BootPriority == BBS_IGNORE_ENTRY) || 604 (LocalBbsTable[BbsIndex].BootPriority == BBS_DO_NOT_BOOT_FROM)) && 605 (LocalBbsTable[BbsIndex].DeviceType == BbsEntry->DeviceType) && 606 DescStringMatch) { 607 Index++; 608 continue; 609 } 610 } 611 612 if (BootOptionVar != NULL) { 613 FreePool (BootOptionVar); 614 } 615 // 616 // should delete 617 // 618 BdsDeleteBootOption ( 619 BootOrder[Index], 620 BootOrder, 621 &BootOrderSize 622 ); 623 } 624 625 // 626 // Adjust the number of boot options. 627 // 628 Status = gRT->SetVariable ( 629 L"BootOrder", 630 &gEfiGlobalVariableGuid, 631 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, 632 BootOrderSize, 633 BootOrder 634 ); 635 // 636 // Shrinking variable with existing variable implementation shouldn't fail. 637 // 638 ASSERT_EFI_ERROR (Status); 639 FreePool (BootOrder); 640 641 return Status; 642} 643 644/** 645 Find all legacy boot option by device type. 646 647 @param BootOrder The boot order array. 648 @param BootOptionNum The number of boot option. 649 @param DevType Device type. 650 @param DevName Device name. 651 @param Attribute The boot option attribute. 652 @param BbsIndex The BBS table index. 653 @param OptionNumber The boot option index. 654 655 @retval TRUE The Legacy boot option is found. 656 @retval FALSE The legacy boot option is not found. 657 658**/ 659BOOLEAN 660BdsFindLegacyBootOptionByDevTypeAndName ( 661 IN UINT16 *BootOrder, 662 IN UINTN BootOptionNum, 663 IN UINT16 DevType, 664 IN CHAR16 *DevName, 665 OUT UINT32 *Attribute, 666 OUT UINT16 *BbsIndex, 667 OUT UINT16 *OptionNumber 668 ) 669{ 670 UINTN Index; 671 CHAR16 BootOption[9]; 672 UINTN BootOptionSize; 673 UINT8 *BootOptionVar; 674 BBS_TABLE *BbsEntry; 675 BOOLEAN Found; 676 677 BbsEntry = NULL; 678 Found = FALSE; 679 680 if (NULL == BootOrder) { 681 return Found; 682 } 683 684 // 685 // Loop all boot option from variable 686 // 687 for (Index = 0; Index < BootOptionNum; Index++) { 688 UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", (UINTN) BootOrder[Index]); 689 BootOptionVar = BdsLibGetVariableAndSize ( 690 BootOption, 691 &gEfiGlobalVariableGuid, 692 &BootOptionSize 693 ); 694 if (NULL == BootOptionVar) { 695 continue; 696 } 697 698 // 699 // Skip Non-legacy boot option 700 // 701 if (!BdsIsLegacyBootOption (BootOptionVar, &BbsEntry, BbsIndex)) { 702 FreePool (BootOptionVar); 703 continue; 704 } 705 706 if ( 707 (BbsEntry->DeviceType != DevType) || 708 (StrCmp (DevName, (CHAR16*)(BootOptionVar + sizeof (UINT32) + sizeof (UINT16))) != 0) 709 ) { 710 FreePool (BootOptionVar); 711 continue; 712 } 713 714 *Attribute = *(UINT32 *) BootOptionVar; 715 *OptionNumber = BootOrder[Index]; 716 Found = TRUE; 717 FreePool (BootOptionVar); 718 break; 719 } 720 721 return Found; 722} 723 724/** 725 Create a legacy boot option. 726 727 @param BbsItem The BBS Table entry. 728 @param Index Index of the specified entry in BBS table. 729 @param BootOrderList The boot order list. 730 @param BootOrderListSize The size of boot order list. 731 732 @retval EFI_OUT_OF_RESOURCE No enough memory. 733 @retval EFI_SUCCESS The function complete successfully. 734 @return Other value if the legacy boot option is not created. 735 736**/ 737EFI_STATUS 738BdsCreateOneLegacyBootOption ( 739 IN BBS_TABLE *BbsItem, 740 IN UINTN Index, 741 IN OUT UINT16 **BootOrderList, 742 IN OUT UINTN *BootOrderListSize 743 ) 744{ 745 BBS_BBS_DEVICE_PATH BbsDevPathNode; 746 EFI_STATUS Status; 747 EFI_DEVICE_PATH_PROTOCOL *DevPath; 748 749 DevPath = NULL; 750 751 // 752 // Create device path node. 753 // 754 BbsDevPathNode.Header.Type = BBS_DEVICE_PATH; 755 BbsDevPathNode.Header.SubType = BBS_BBS_DP; 756 SetDevicePathNodeLength (&BbsDevPathNode.Header, sizeof (BBS_BBS_DEVICE_PATH)); 757 BbsDevPathNode.DeviceType = BbsItem->DeviceType; 758 CopyMem (&BbsDevPathNode.StatusFlag, &BbsItem->StatusFlags, sizeof (UINT16)); 759 760 DevPath = AppendDevicePathNode ( 761 NULL, 762 (EFI_DEVICE_PATH_PROTOCOL *) &BbsDevPathNode 763 ); 764 if (NULL == DevPath) { 765 return EFI_OUT_OF_RESOURCES; 766 } 767 768 Status = BdsCreateLegacyBootOption ( 769 BbsItem, 770 DevPath, 771 Index, 772 BootOrderList, 773 BootOrderListSize 774 ); 775 BbsItem->BootPriority = 0x00; 776 777 FreePool (DevPath); 778 779 return Status; 780} 781 782/** 783 Add the legacy boot options from BBS table if they do not exist. 784 785 @retval EFI_SUCCESS The boot options are added successfully 786 or they are already in boot options. 787 @retval EFI_NOT_FOUND No legacy boot options is found. 788 @retval EFI_OUT_OF_RESOURCE No enough memory. 789 @return Other value LegacyBoot options are not added. 790**/ 791EFI_STATUS 792EFIAPI 793BdsAddNonExistingLegacyBootOptions ( 794 VOID 795 ) 796{ 797 UINT16 *BootOrder; 798 UINTN BootOrderSize; 799 EFI_STATUS Status; 800 CHAR16 Desc[100]; 801 UINT16 HddCount; 802 UINT16 BbsCount; 803 HDD_INFO *LocalHddInfo; 804 BBS_TABLE *LocalBbsTable; 805 UINT16 BbsIndex; 806 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; 807 UINT16 Index; 808 UINT32 Attribute; 809 UINT16 OptionNumber; 810 BOOLEAN Exist; 811 812 HddCount = 0; 813 BbsCount = 0; 814 LocalHddInfo = NULL; 815 LocalBbsTable = NULL; 816 817 Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios); 818 if (EFI_ERROR (Status)) { 819 return Status; 820 } 821 822 LegacyBios->GetBbsInfo ( 823 LegacyBios, 824 &HddCount, 825 &LocalHddInfo, 826 &BbsCount, 827 &LocalBbsTable 828 ); 829 830 BootOrder = BdsLibGetVariableAndSize ( 831 L"BootOrder", 832 &gEfiGlobalVariableGuid, 833 &BootOrderSize 834 ); 835 if (BootOrder == NULL) { 836 BootOrderSize = 0; 837 } 838 839 for (Index = 0; Index < BbsCount; Index++) { 840 if ((LocalBbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) || 841 (LocalBbsTable[Index].BootPriority == BBS_DO_NOT_BOOT_FROM) 842 ) { 843 continue; 844 } 845 846 BdsBuildLegacyDevNameString (&LocalBbsTable[Index], Index, sizeof (Desc), Desc); 847 848 Exist = BdsFindLegacyBootOptionByDevTypeAndName ( 849 BootOrder, 850 BootOrderSize / sizeof (UINT16), 851 LocalBbsTable[Index].DeviceType, 852 Desc, 853 &Attribute, 854 &BbsIndex, 855 &OptionNumber 856 ); 857 if (!Exist) { 858 // 859 // Not found such type of legacy device in boot options or we found but it's disabled 860 // so we have to create one and put it to the tail of boot order list 861 // 862 Status = BdsCreateOneLegacyBootOption ( 863 &LocalBbsTable[Index], 864 Index, 865 &BootOrder, 866 &BootOrderSize 867 ); 868 if (!EFI_ERROR (Status)) { 869 ASSERT (BootOrder != NULL); 870 BbsIndex = Index; 871 OptionNumber = BootOrder[BootOrderSize / sizeof (UINT16) - 1]; 872 } 873 } 874 875 ASSERT (BbsIndex == Index); 876 } 877 878 Status = gRT->SetVariable ( 879 L"BootOrder", 880 &gEfiGlobalVariableGuid, 881 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, 882 BootOrderSize, 883 BootOrder 884 ); 885 if (BootOrder != NULL) { 886 FreePool (BootOrder); 887 } 888 889 return Status; 890} 891 892/** 893 Fill the device order buffer. 894 895 @param BbsTable The BBS table. 896 @param BbsType The BBS Type. 897 @param BbsCount The BBS Count. 898 @param Buf device order buffer. 899 900 @return The device order buffer. 901 902**/ 903UINT16 * 904BdsFillDevOrderBuf ( 905 IN BBS_TABLE *BbsTable, 906 IN BBS_TYPE BbsType, 907 IN UINTN BbsCount, 908 OUT UINT16 *Buf 909 ) 910{ 911 UINTN Index; 912 913 for (Index = 0; Index < BbsCount; Index++) { 914 if (BbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) { 915 continue; 916 } 917 918 if (BbsTable[Index].DeviceType != BbsType) { 919 continue; 920 } 921 922 *Buf = (UINT16) (Index & 0xFF); 923 Buf++; 924 } 925 926 return Buf; 927} 928 929/** 930 Create the device order buffer. 931 932 @param BbsTable The BBS table. 933 @param BbsCount The BBS Count. 934 935 @retval EFI_SUCCES The buffer is created and the EFI variable named 936 VAR_LEGACY_DEV_ORDER and gEfiLegacyDevOrderVariableGuid is 937 set correctly. 938 @retval EFI_OUT_OF_RESOURCES Memmory or storage is not enough. 939 @retval EFI_DEVICE_ERROR Fail to add the device order into EFI variable fail 940 because of hardware error. 941**/ 942EFI_STATUS 943BdsCreateDevOrder ( 944 IN BBS_TABLE *BbsTable, 945 IN UINT16 BbsCount 946 ) 947{ 948 UINTN Index; 949 UINTN FDCount; 950 UINTN HDCount; 951 UINTN CDCount; 952 UINTN NETCount; 953 UINTN BEVCount; 954 UINTN TotalSize; 955 UINTN HeaderSize; 956 LEGACY_DEV_ORDER_ENTRY *DevOrder; 957 LEGACY_DEV_ORDER_ENTRY *DevOrderPtr; 958 EFI_STATUS Status; 959 960 FDCount = 0; 961 HDCount = 0; 962 CDCount = 0; 963 NETCount = 0; 964 BEVCount = 0; 965 TotalSize = 0; 966 HeaderSize = sizeof (BBS_TYPE) + sizeof (UINT16); 967 DevOrder = NULL; 968 Status = EFI_SUCCESS; 969 970 // 971 // Count all boot devices 972 // 973 for (Index = 0; Index < BbsCount; Index++) { 974 if (BbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) { 975 continue; 976 } 977 978 switch (BbsTable[Index].DeviceType) { 979 case BBS_FLOPPY: 980 FDCount++; 981 break; 982 983 case BBS_HARDDISK: 984 HDCount++; 985 break; 986 987 case BBS_CDROM: 988 CDCount++; 989 break; 990 991 case BBS_EMBED_NETWORK: 992 NETCount++; 993 break; 994 995 case BBS_BEV_DEVICE: 996 BEVCount++; 997 break; 998 999 default: 1000 break; 1001 } 1002 } 1003 1004 TotalSize += (HeaderSize + sizeof (UINT16) * FDCount); 1005 TotalSize += (HeaderSize + sizeof (UINT16) * HDCount); 1006 TotalSize += (HeaderSize + sizeof (UINT16) * CDCount); 1007 TotalSize += (HeaderSize + sizeof (UINT16) * NETCount); 1008 TotalSize += (HeaderSize + sizeof (UINT16) * BEVCount); 1009 1010 // 1011 // Create buffer to hold all boot device order 1012 // 1013 DevOrder = AllocateZeroPool (TotalSize); 1014 if (NULL == DevOrder) { 1015 return EFI_OUT_OF_RESOURCES; 1016 } 1017 DevOrderPtr = DevOrder; 1018 1019 DevOrderPtr->BbsType = BBS_FLOPPY; 1020 DevOrderPtr->Length = (UINT16) (sizeof (DevOrderPtr->Length) + FDCount * sizeof (UINT16)); 1021 DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) BdsFillDevOrderBuf (BbsTable, BBS_FLOPPY, BbsCount, DevOrderPtr->Data); 1022 1023 DevOrderPtr->BbsType = BBS_HARDDISK; 1024 DevOrderPtr->Length = (UINT16) (sizeof (UINT16) + HDCount * sizeof (UINT16)); 1025 DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) BdsFillDevOrderBuf (BbsTable, BBS_HARDDISK, BbsCount, DevOrderPtr->Data); 1026 1027 DevOrderPtr->BbsType = BBS_CDROM; 1028 DevOrderPtr->Length = (UINT16) (sizeof (UINT16) + CDCount * sizeof (UINT16)); 1029 DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) BdsFillDevOrderBuf (BbsTable, BBS_CDROM, BbsCount, DevOrderPtr->Data); 1030 1031 DevOrderPtr->BbsType = BBS_EMBED_NETWORK; 1032 DevOrderPtr->Length = (UINT16) (sizeof (UINT16) + NETCount * sizeof (UINT16)); 1033 DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) BdsFillDevOrderBuf (BbsTable, BBS_EMBED_NETWORK, BbsCount, DevOrderPtr->Data); 1034 1035 DevOrderPtr->BbsType = BBS_BEV_DEVICE; 1036 DevOrderPtr->Length = (UINT16) (sizeof (UINT16) + BEVCount * sizeof (UINT16)); 1037 DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) BdsFillDevOrderBuf (BbsTable, BBS_BEV_DEVICE, BbsCount, DevOrderPtr->Data); 1038 1039 ASSERT (TotalSize == (UINTN) ((UINT8 *) DevOrderPtr - (UINT8 *) DevOrder)); 1040 1041 // 1042 // Save device order for legacy boot device to variable. 1043 // 1044 Status = gRT->SetVariable ( 1045 VAR_LEGACY_DEV_ORDER, 1046 &gEfiLegacyDevOrderVariableGuid, 1047 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE, 1048 TotalSize, 1049 DevOrder 1050 ); 1051 FreePool (DevOrder); 1052 1053 return Status; 1054} 1055 1056/** 1057 Add the legacy boot devices from BBS table into 1058 the legacy device boot order. 1059 1060 @retval EFI_SUCCESS The boot devices are added successfully. 1061 @retval EFI_NOT_FOUND The legacy boot devices are not found. 1062 @retval EFI_OUT_OF_RESOURCES Memmory or storage is not enough. 1063 @retval EFI_DEVICE_ERROR Fail to add the legacy device boot order into EFI variable 1064 because of hardware error. 1065**/ 1066EFI_STATUS 1067EFIAPI 1068BdsUpdateLegacyDevOrder ( 1069 VOID 1070 ) 1071{ 1072 LEGACY_DEV_ORDER_ENTRY *DevOrder; 1073 LEGACY_DEV_ORDER_ENTRY *NewDevOrder; 1074 LEGACY_DEV_ORDER_ENTRY *Ptr; 1075 LEGACY_DEV_ORDER_ENTRY *NewPtr; 1076 UINTN DevOrderSize; 1077 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; 1078 EFI_STATUS Status; 1079 UINT16 HddCount; 1080 UINT16 BbsCount; 1081 HDD_INFO *LocalHddInfo; 1082 BBS_TABLE *LocalBbsTable; 1083 UINTN Index; 1084 UINTN Index2; 1085 UINTN *Idx; 1086 UINTN FDCount; 1087 UINTN HDCount; 1088 UINTN CDCount; 1089 UINTN NETCount; 1090 UINTN BEVCount; 1091 UINTN TotalSize; 1092 UINTN HeaderSize; 1093 UINT16 *NewFDPtr; 1094 UINT16 *NewHDPtr; 1095 UINT16 *NewCDPtr; 1096 UINT16 *NewNETPtr; 1097 UINT16 *NewBEVPtr; 1098 UINT16 *NewDevPtr; 1099 UINTN FDIndex; 1100 UINTN HDIndex; 1101 UINTN CDIndex; 1102 UINTN NETIndex; 1103 UINTN BEVIndex; 1104 1105 Idx = NULL; 1106 FDCount = 0; 1107 HDCount = 0; 1108 CDCount = 0; 1109 NETCount = 0; 1110 BEVCount = 0; 1111 TotalSize = 0; 1112 HeaderSize = sizeof (BBS_TYPE) + sizeof (UINT16); 1113 FDIndex = 0; 1114 HDIndex = 0; 1115 CDIndex = 0; 1116 NETIndex = 0; 1117 BEVIndex = 0; 1118 NewDevPtr = NULL; 1119 1120 Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios); 1121 if (EFI_ERROR (Status)) { 1122 return Status; 1123 } 1124 1125 Status = LegacyBios->GetBbsInfo ( 1126 LegacyBios, 1127 &HddCount, 1128 &LocalHddInfo, 1129 &BbsCount, 1130 &LocalBbsTable 1131 ); 1132 if (EFI_ERROR (Status)) { 1133 return Status; 1134 } 1135 1136 DevOrder = BdsLibGetVariableAndSize ( 1137 VAR_LEGACY_DEV_ORDER, 1138 &gEfiLegacyDevOrderVariableGuid, 1139 &DevOrderSize 1140 ); 1141 if (NULL == DevOrder) { 1142 return BdsCreateDevOrder (LocalBbsTable, BbsCount); 1143 } 1144 // 1145 // First we figure out how many boot devices with same device type respectively 1146 // 1147 for (Index = 0; Index < BbsCount; Index++) { 1148 if ((LocalBbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) || 1149 (LocalBbsTable[Index].BootPriority == BBS_DO_NOT_BOOT_FROM) 1150 ) { 1151 continue; 1152 } 1153 1154 switch (LocalBbsTable[Index].DeviceType) { 1155 case BBS_FLOPPY: 1156 FDCount++; 1157 break; 1158 1159 case BBS_HARDDISK: 1160 HDCount++; 1161 break; 1162 1163 case BBS_CDROM: 1164 CDCount++; 1165 break; 1166 1167 case BBS_EMBED_NETWORK: 1168 NETCount++; 1169 break; 1170 1171 case BBS_BEV_DEVICE: 1172 BEVCount++; 1173 break; 1174 1175 default: 1176 break; 1177 } 1178 } 1179 1180 TotalSize += (HeaderSize + FDCount * sizeof (UINT16)); 1181 TotalSize += (HeaderSize + HDCount * sizeof (UINT16)); 1182 TotalSize += (HeaderSize + CDCount * sizeof (UINT16)); 1183 TotalSize += (HeaderSize + NETCount * sizeof (UINT16)); 1184 TotalSize += (HeaderSize + BEVCount * sizeof (UINT16)); 1185 1186 NewDevOrder = AllocateZeroPool (TotalSize); 1187 if (NULL == NewDevOrder) { 1188 return EFI_OUT_OF_RESOURCES; 1189 } 1190 1191 1192 1193 // 1194 // copy FD 1195 // 1196 Ptr = DevOrder; 1197 NewPtr = NewDevOrder; 1198 NewPtr->BbsType = Ptr->BbsType; 1199 NewPtr->Length = (UINT16) (sizeof (UINT16) + FDCount * sizeof (UINT16)); 1200 for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) { 1201 if (LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_IGNORE_ENTRY || 1202 LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_DO_NOT_BOOT_FROM || 1203 LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_FLOPPY 1204 ) { 1205 continue; 1206 } 1207 1208 NewPtr->Data[FDIndex] = Ptr->Data[Index]; 1209 FDIndex++; 1210 } 1211 NewFDPtr = NewPtr->Data; 1212 1213 // 1214 // copy HD 1215 // 1216 Ptr = (LEGACY_DEV_ORDER_ENTRY *) (&Ptr->Data[Ptr->Length / sizeof (UINT16) - 1]); 1217 NewPtr = (LEGACY_DEV_ORDER_ENTRY *) (&NewPtr->Data[NewPtr->Length / sizeof (UINT16) -1]); 1218 NewPtr->BbsType = Ptr->BbsType; 1219 NewPtr->Length = (UINT16) (sizeof (UINT16) + HDCount * sizeof (UINT16)); 1220 for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) { 1221 if (LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_IGNORE_ENTRY || 1222 LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_DO_NOT_BOOT_FROM || 1223 LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_LOWEST_PRIORITY || 1224 LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_HARDDISK 1225 ) { 1226 continue; 1227 } 1228 1229 NewPtr->Data[HDIndex] = Ptr->Data[Index]; 1230 HDIndex++; 1231 } 1232 NewHDPtr = NewPtr->Data; 1233 1234 // 1235 // copy CD 1236 // 1237 Ptr = (LEGACY_DEV_ORDER_ENTRY *) (&Ptr->Data[Ptr->Length / sizeof (UINT16) - 1]); 1238 NewPtr = (LEGACY_DEV_ORDER_ENTRY *) (&NewPtr->Data[NewPtr->Length / sizeof (UINT16) -1]); 1239 NewPtr->BbsType = Ptr->BbsType; 1240 NewPtr->Length = (UINT16) (sizeof (UINT16) + CDCount * sizeof (UINT16)); 1241 for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) { 1242 if (LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_IGNORE_ENTRY || 1243 LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_DO_NOT_BOOT_FROM || 1244 LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_LOWEST_PRIORITY || 1245 LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_CDROM 1246 ) { 1247 continue; 1248 } 1249 1250 NewPtr->Data[CDIndex] = Ptr->Data[Index]; 1251 CDIndex++; 1252 } 1253 NewCDPtr = NewPtr->Data; 1254 1255 // 1256 // copy NET 1257 // 1258 Ptr = (LEGACY_DEV_ORDER_ENTRY *) (&Ptr->Data[Ptr->Length / sizeof (UINT16) - 1]); 1259 NewPtr = (LEGACY_DEV_ORDER_ENTRY *) (&NewPtr->Data[NewPtr->Length / sizeof (UINT16) -1]); 1260 NewPtr->BbsType = Ptr->BbsType; 1261 NewPtr->Length = (UINT16) (sizeof (UINT16) + NETCount * sizeof (UINT16)); 1262 for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) { 1263 if (LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_IGNORE_ENTRY || 1264 LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_DO_NOT_BOOT_FROM || 1265 LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_LOWEST_PRIORITY || 1266 LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_EMBED_NETWORK 1267 ) { 1268 continue; 1269 } 1270 1271 NewPtr->Data[NETIndex] = Ptr->Data[Index]; 1272 NETIndex++; 1273 } 1274 NewNETPtr = NewPtr->Data; 1275 1276 // 1277 // copy BEV 1278 // 1279 Ptr = (LEGACY_DEV_ORDER_ENTRY *) (&Ptr->Data[Ptr->Length / sizeof (UINT16) - 1]); 1280 NewPtr = (LEGACY_DEV_ORDER_ENTRY *) (&NewPtr->Data[NewPtr->Length / sizeof (UINT16) -1]); 1281 NewPtr->BbsType = Ptr->BbsType; 1282 NewPtr->Length = (UINT16) (sizeof (UINT16) + BEVCount * sizeof (UINT16)); 1283 for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) { 1284 if (LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_IGNORE_ENTRY || 1285 LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_DO_NOT_BOOT_FROM || 1286 LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_LOWEST_PRIORITY || 1287 LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_BEV_DEVICE 1288 ) { 1289 continue; 1290 } 1291 1292 NewPtr->Data[BEVIndex] = Ptr->Data[Index]; 1293 BEVIndex++; 1294 } 1295 NewBEVPtr = NewPtr->Data; 1296 1297 for (Index = 0; Index < BbsCount; Index++) { 1298 if ((LocalBbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) || 1299 (LocalBbsTable[Index].BootPriority == BBS_DO_NOT_BOOT_FROM) 1300 ) { 1301 continue; 1302 } 1303 1304 switch (LocalBbsTable[Index].DeviceType) { 1305 case BBS_FLOPPY: 1306 Idx = &FDIndex; 1307 NewDevPtr = NewFDPtr; 1308 break; 1309 1310 case BBS_HARDDISK: 1311 Idx = &HDIndex; 1312 NewDevPtr = NewHDPtr; 1313 break; 1314 1315 case BBS_CDROM: 1316 Idx = &CDIndex; 1317 NewDevPtr = NewCDPtr; 1318 break; 1319 1320 case BBS_EMBED_NETWORK: 1321 Idx = &NETIndex; 1322 NewDevPtr = NewNETPtr; 1323 break; 1324 1325 case BBS_BEV_DEVICE: 1326 Idx = &BEVIndex; 1327 NewDevPtr = NewBEVPtr; 1328 break; 1329 1330 default: 1331 Idx = NULL; 1332 break; 1333 } 1334 // 1335 // at this point we have copied those valid indexes to new buffer 1336 // and we should check if there is any new appeared boot device 1337 // 1338 if (Idx != NULL) { 1339 for (Index2 = 0; Index2 < *Idx; Index2++) { 1340 if ((NewDevPtr[Index2] & 0xFF) == (UINT16) Index) { 1341 break; 1342 } 1343 } 1344 1345 if (Index2 == *Idx) { 1346 // 1347 // Index2 == *Idx means we didn't find Index 1348 // so Index is a new appeared device's index in BBS table 1349 // insert it before disabled indexes. 1350 // 1351 for (Index2 = 0; Index2 < *Idx; Index2++) { 1352 if ((NewDevPtr[Index2] & 0xFF00) == 0xFF00) { 1353 break; 1354 } 1355 } 1356 CopyMem (&NewDevPtr[Index2 + 1], &NewDevPtr[Index2], (*Idx - Index2) * sizeof (UINT16)); 1357 NewDevPtr[Index2] = (UINT16) (Index & 0xFF); 1358 (*Idx)++; 1359 } 1360 } 1361 } 1362 1363 FreePool (DevOrder); 1364 1365 Status = gRT->SetVariable ( 1366 VAR_LEGACY_DEV_ORDER, 1367 &gEfiLegacyDevOrderVariableGuid, 1368 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE, 1369 TotalSize, 1370 NewDevOrder 1371 ); 1372 FreePool (NewDevOrder); 1373 1374 return Status; 1375} 1376 1377/** 1378 Set Boot Priority for specified device type. 1379 1380 @param DeviceType The device type. 1381 @param BbsIndex The BBS index to set the highest priority. Ignore when -1. 1382 @param LocalBbsTable The BBS table. 1383 @param Priority The prority table. 1384 1385 @retval EFI_SUCCESS The function completes successfully. 1386 @retval EFI_NOT_FOUND Failed to find device. 1387 @retval EFI_OUT_OF_RESOURCES Failed to get the efi variable of device order. 1388 1389**/ 1390EFI_STATUS 1391BdsSetBootPriority4SameTypeDev ( 1392 IN UINT16 DeviceType, 1393 IN UINTN BbsIndex, 1394 IN OUT BBS_TABLE *LocalBbsTable, 1395 IN OUT UINT16 *Priority 1396 ) 1397{ 1398 LEGACY_DEV_ORDER_ENTRY *DevOrder; 1399 LEGACY_DEV_ORDER_ENTRY *DevOrderPtr; 1400 UINTN DevOrderSize; 1401 UINTN Index; 1402 1403 DevOrder = BdsLibGetVariableAndSize ( 1404 VAR_LEGACY_DEV_ORDER, 1405 &gEfiLegacyDevOrderVariableGuid, 1406 &DevOrderSize 1407 ); 1408 if (NULL == DevOrder) { 1409 return EFI_OUT_OF_RESOURCES; 1410 } 1411 1412 DevOrderPtr = DevOrder; 1413 while ((UINT8 *) DevOrderPtr < (UINT8 *) DevOrder + DevOrderSize) { 1414 if (DevOrderPtr->BbsType == DeviceType) { 1415 break; 1416 } 1417 1418 DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) ((UINTN) DevOrderPtr + sizeof (BBS_TYPE) + DevOrderPtr->Length); 1419 } 1420 1421 if ((UINT8 *) DevOrderPtr >= (UINT8 *) DevOrder + DevOrderSize) { 1422 FreePool (DevOrder); 1423 return EFI_NOT_FOUND; 1424 } 1425 1426 if (BbsIndex != (UINTN) -1) { 1427 LocalBbsTable[BbsIndex].BootPriority = *Priority; 1428 (*Priority)++; 1429 } 1430 // 1431 // If the high byte of the DevIndex is 0xFF, it indicates that this device has been disabled. 1432 // 1433 for (Index = 0; Index < DevOrderPtr->Length / sizeof (UINT16) - 1; Index++) { 1434 if ((DevOrderPtr->Data[Index] & 0xFF00) == 0xFF00) { 1435 // 1436 // LocalBbsTable[DevIndex[Index] & 0xFF].BootPriority = BBS_DISABLED_ENTRY; 1437 // 1438 } else if (DevOrderPtr->Data[Index] != BbsIndex) { 1439 LocalBbsTable[DevOrderPtr->Data[Index]].BootPriority = *Priority; 1440 (*Priority)++; 1441 } 1442 } 1443 1444 FreePool (DevOrder); 1445 return EFI_SUCCESS; 1446} 1447 1448/** 1449 Print the BBS Table. 1450 1451 @param LocalBbsTable The BBS table. 1452 @param BbsCount The count of entry in BBS table. 1453**/ 1454VOID 1455PrintBbsTable ( 1456 IN BBS_TABLE *LocalBbsTable, 1457 IN UINT16 BbsCount 1458 ) 1459{ 1460 UINT16 Idx; 1461 1462 DEBUG ((DEBUG_ERROR, "\n")); 1463 DEBUG ((DEBUG_ERROR, " NO Prio bb/dd/ff cl/sc Type Stat segm:offs\n")); 1464 DEBUG ((DEBUG_ERROR, "=============================================\n")); 1465 for (Idx = 0; Idx < BbsCount; Idx++) { 1466 if ((LocalBbsTable[Idx].BootPriority == BBS_IGNORE_ENTRY) || 1467 (LocalBbsTable[Idx].BootPriority == BBS_DO_NOT_BOOT_FROM) || 1468 (LocalBbsTable[Idx].BootPriority == BBS_LOWEST_PRIORITY) 1469 ) { 1470 continue; 1471 } 1472 1473 DEBUG ( 1474 (DEBUG_ERROR, 1475 " %02x: %04x %02x/%02x/%02x %02x/%02x %04x %04x %04x:%04x\n", 1476 (UINTN) Idx, 1477 (UINTN) LocalBbsTable[Idx].BootPriority, 1478 (UINTN) LocalBbsTable[Idx].Bus, 1479 (UINTN) LocalBbsTable[Idx].Device, 1480 (UINTN) LocalBbsTable[Idx].Function, 1481 (UINTN) LocalBbsTable[Idx].Class, 1482 (UINTN) LocalBbsTable[Idx].SubClass, 1483 (UINTN) LocalBbsTable[Idx].DeviceType, 1484 (UINTN) * (UINT16 *) &LocalBbsTable[Idx].StatusFlags, 1485 (UINTN) LocalBbsTable[Idx].BootHandlerSegment, 1486 (UINTN) LocalBbsTable[Idx].BootHandlerOffset, 1487 (UINTN) ((LocalBbsTable[Idx].MfgStringSegment << 4) + LocalBbsTable[Idx].MfgStringOffset), 1488 (UINTN) ((LocalBbsTable[Idx].DescStringSegment << 4) + LocalBbsTable[Idx].DescStringOffset)) 1489 ); 1490 } 1491 1492 DEBUG ((DEBUG_ERROR, "\n")); 1493} 1494 1495/** 1496 Set the boot priority for BBS entries based on boot option entry and boot order. 1497 1498 @param Entry The boot option is to be checked for refresh BBS table. 1499 1500 @retval EFI_SUCCESS The boot priority for BBS entries is refreshed successfully. 1501 @retval EFI_NOT_FOUND BBS entries can't be found. 1502 @retval EFI_OUT_OF_RESOURCES Failed to get the legacy device boot order. 1503**/ 1504EFI_STATUS 1505EFIAPI 1506BdsRefreshBbsTableForBoot ( 1507 IN BDS_COMMON_OPTION *Entry 1508 ) 1509{ 1510 EFI_STATUS Status; 1511 UINT16 BbsIndex; 1512 UINT16 HddCount; 1513 UINT16 BbsCount; 1514 HDD_INFO *LocalHddInfo; 1515 BBS_TABLE *LocalBbsTable; 1516 UINT16 DevType; 1517 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; 1518 UINTN Index; 1519 UINT16 Priority; 1520 UINT16 *BootOrder; 1521 UINTN BootOrderSize; 1522 UINT8 *BootOptionVar; 1523 UINTN BootOptionSize; 1524 CHAR16 BootOption[9]; 1525 UINT8 *Ptr; 1526 UINT16 DevPathLen; 1527 EFI_DEVICE_PATH_PROTOCOL *DevPath; 1528 UINT16 *DeviceType; 1529 UINTN DeviceTypeCount; 1530 UINTN DeviceTypeIndex; 1531 1532 HddCount = 0; 1533 BbsCount = 0; 1534 LocalHddInfo = NULL; 1535 LocalBbsTable = NULL; 1536 DevType = BBS_UNKNOWN; 1537 1538 Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios); 1539 if (EFI_ERROR (Status)) { 1540 return Status; 1541 } 1542 1543 LegacyBios->GetBbsInfo ( 1544 LegacyBios, 1545 &HddCount, 1546 &LocalHddInfo, 1547 &BbsCount, 1548 &LocalBbsTable 1549 ); 1550 // 1551 // First, set all the present devices' boot priority to BBS_UNPRIORITIZED_ENTRY 1552 // We will set them according to the settings setup by user 1553 // 1554 for (Index = 0; Index < BbsCount; Index++) { 1555 if (!((BBS_IGNORE_ENTRY == LocalBbsTable[Index].BootPriority) || 1556 (BBS_DO_NOT_BOOT_FROM == LocalBbsTable[Index].BootPriority) || 1557 (BBS_LOWEST_PRIORITY == LocalBbsTable[Index].BootPriority))) { 1558 LocalBbsTable[Index].BootPriority = BBS_UNPRIORITIZED_ENTRY; 1559 } 1560 } 1561 // 1562 // boot priority always starts at 0 1563 // 1564 Priority = 0; 1565 if (Entry->LoadOptionsSize == sizeof (BBS_TABLE) + sizeof (UINT16)) { 1566 // 1567 // If Entry stands for a legacy boot option, we prioritize the devices with the same type first. 1568 // 1569 DevType = ((BBS_TABLE *) Entry->LoadOptions)->DeviceType; 1570 BbsIndex = *(UINT16 *) ((BBS_TABLE *) Entry->LoadOptions + 1); 1571 Status = BdsSetBootPriority4SameTypeDev ( 1572 DevType, 1573 BbsIndex, 1574 LocalBbsTable, 1575 &Priority 1576 ); 1577 if (EFI_ERROR (Status)) { 1578 return Status; 1579 } 1580 } 1581 // 1582 // we have to set the boot priority for other BBS entries with different device types 1583 // 1584 BootOrder = BdsLibGetVariableAndSize ( 1585 L"BootOrder", 1586 &gEfiGlobalVariableGuid, 1587 &BootOrderSize 1588 ); 1589 DeviceType = AllocatePool (BootOrderSize + sizeof (UINT16)); 1590 ASSERT (DeviceType != NULL); 1591 1592 DeviceType[0] = DevType; 1593 DeviceTypeCount = 1; 1594 for (Index = 0; ((BootOrder != NULL) && (Index < BootOrderSize / sizeof (UINT16))); Index++) { 1595 UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]); 1596 BootOptionVar = BdsLibGetVariableAndSize ( 1597 BootOption, 1598 &gEfiGlobalVariableGuid, 1599 &BootOptionSize 1600 ); 1601 if (NULL == BootOptionVar) { 1602 continue; 1603 } 1604 1605 Ptr = BootOptionVar; 1606 1607 Ptr += sizeof (UINT32); 1608 DevPathLen = *(UINT16 *) Ptr; 1609 Ptr += sizeof (UINT16); 1610 Ptr += StrSize ((UINT16 *) Ptr); 1611 DevPath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr; 1612 if (BBS_DEVICE_PATH != DevPath->Type || BBS_BBS_DP != DevPath->SubType) { 1613 FreePool (BootOptionVar); 1614 continue; 1615 } 1616 1617 Ptr += DevPathLen; 1618 DevType = ((BBS_TABLE *) Ptr)->DeviceType; 1619 for (DeviceTypeIndex = 0; DeviceTypeIndex < DeviceTypeCount; DeviceTypeIndex++) { 1620 if (DeviceType[DeviceTypeIndex] == DevType) { 1621 break; 1622 } 1623 } 1624 if (DeviceTypeIndex < DeviceTypeCount) { 1625 // 1626 // We don't want to process twice for a device type 1627 // 1628 FreePool (BootOptionVar); 1629 continue; 1630 } 1631 1632 DeviceType[DeviceTypeCount] = DevType; 1633 DeviceTypeCount++; 1634 1635 Status = BdsSetBootPriority4SameTypeDev ( 1636 DevType, 1637 (UINTN) -1, 1638 LocalBbsTable, 1639 &Priority 1640 ); 1641 FreePool (BootOptionVar); 1642 if (EFI_ERROR (Status)) { 1643 break; 1644 } 1645 } 1646 1647 FreePool (DeviceType); 1648 1649 if (BootOrder != NULL) { 1650 FreePool (BootOrder); 1651 } 1652 1653 DEBUG_CODE_BEGIN(); 1654 PrintBbsTable (LocalBbsTable, BbsCount); 1655 DEBUG_CODE_END(); 1656 1657 return Status; 1658} 1659 1660/** 1661 Boot the legacy system with the boot option 1662 1663 @param Option The legacy boot option which have BBS device path 1664 1665 @retval EFI_UNSUPPORTED There is no legacybios protocol, do not support 1666 legacy boot. 1667 @retval EFI_STATUS Return the status of LegacyBios->LegacyBoot (). 1668 1669**/ 1670EFI_STATUS 1671BdsLibDoLegacyBoot ( 1672 IN BDS_COMMON_OPTION *Option 1673 ) 1674{ 1675 EFI_STATUS Status; 1676 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; 1677 EFI_EVENT LegacyBootEvent; 1678 1679 Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios); 1680 if (EFI_ERROR (Status)) { 1681 // 1682 // If no LegacyBios protocol we do not support legacy boot 1683 // 1684 return EFI_UNSUPPORTED; 1685 } 1686 // 1687 // Notes: if we separate the int 19, then we don't need to refresh BBS 1688 // 1689 BdsRefreshBbsTableForBoot (Option); 1690 1691 // 1692 // Write boot to OS performance data for legacy boot. 1693 // 1694 PERF_CODE ( 1695 // 1696 // Create an event to be signalled when Legacy Boot occurs to write performance data. 1697 // 1698 Status = EfiCreateEventLegacyBootEx( 1699 TPL_NOTIFY, 1700 WriteBootToOsPerformanceData, 1701 NULL, 1702 &LegacyBootEvent 1703 ); 1704 ASSERT_EFI_ERROR (Status); 1705 ); 1706 1707 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Legacy Boot: %S\n", Option->Description)); 1708 return LegacyBios->LegacyBoot ( 1709 LegacyBios, 1710 (BBS_BBS_DEVICE_PATH *) Option->DevicePath, 1711 Option->LoadOptionsSize, 1712 Option->LoadOptions 1713 ); 1714} 1715 1716/** 1717 Internal function to check if the input boot option is a valid EFI NV Boot####. 1718 1719 @param OptionToCheck Boot option to be checked. 1720 1721 @retval TRUE This boot option matches a valid EFI NV Boot####. 1722 @retval FALSE If not. 1723 1724**/ 1725BOOLEAN 1726IsBootOptionValidNVVarialbe ( 1727 IN BDS_COMMON_OPTION *OptionToCheck 1728 ) 1729{ 1730 LIST_ENTRY TempList; 1731 BDS_COMMON_OPTION *BootOption; 1732 BOOLEAN Valid; 1733 CHAR16 OptionName[20]; 1734 1735 Valid = FALSE; 1736 1737 InitializeListHead (&TempList); 1738 UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", OptionToCheck->BootCurrent); 1739 1740 BootOption = BdsLibVariableToOption (&TempList, OptionName); 1741 if (BootOption == NULL) { 1742 return FALSE; 1743 } 1744 1745 // 1746 // If the Boot Option Number and Device Path matches, OptionToCheck matches a 1747 // valid EFI NV Boot####. 1748 // 1749 if ((OptionToCheck->BootCurrent == BootOption->BootCurrent) && 1750 (CompareMem (OptionToCheck->DevicePath, BootOption->DevicePath, GetDevicePathSize (OptionToCheck->DevicePath)) == 0)) 1751 { 1752 Valid = TRUE; 1753 } 1754 1755 FreePool (BootOption); 1756 1757 return Valid; 1758} 1759 1760/** 1761 Check whether a USB device match the specified USB Class device path. This 1762 function follows "Load Option Processing" behavior in UEFI specification. 1763 1764 @param UsbIo USB I/O protocol associated with the USB device. 1765 @param UsbClass The USB Class device path to match. 1766 1767 @retval TRUE The USB device match the USB Class device path. 1768 @retval FALSE The USB device does not match the USB Class device path. 1769 1770**/ 1771BOOLEAN 1772BdsMatchUsbClass ( 1773 IN EFI_USB_IO_PROTOCOL *UsbIo, 1774 IN USB_CLASS_DEVICE_PATH *UsbClass 1775 ) 1776{ 1777 EFI_STATUS Status; 1778 EFI_USB_DEVICE_DESCRIPTOR DevDesc; 1779 EFI_USB_INTERFACE_DESCRIPTOR IfDesc; 1780 UINT8 DeviceClass; 1781 UINT8 DeviceSubClass; 1782 UINT8 DeviceProtocol; 1783 1784 if ((DevicePathType (UsbClass) != MESSAGING_DEVICE_PATH) || 1785 (DevicePathSubType (UsbClass) != MSG_USB_CLASS_DP)){ 1786 return FALSE; 1787 } 1788 1789 // 1790 // Check Vendor Id and Product Id. 1791 // 1792 Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc); 1793 if (EFI_ERROR (Status)) { 1794 return FALSE; 1795 } 1796 1797 if ((UsbClass->VendorId != 0xffff) && 1798 (UsbClass->VendorId != DevDesc.IdVendor)) { 1799 return FALSE; 1800 } 1801 1802 if ((UsbClass->ProductId != 0xffff) && 1803 (UsbClass->ProductId != DevDesc.IdProduct)) { 1804 return FALSE; 1805 } 1806 1807 DeviceClass = DevDesc.DeviceClass; 1808 DeviceSubClass = DevDesc.DeviceSubClass; 1809 DeviceProtocol = DevDesc.DeviceProtocol; 1810 if (DeviceClass == 0) { 1811 // 1812 // If Class in Device Descriptor is set to 0, use the Class, SubClass and 1813 // Protocol in Interface Descriptor instead. 1814 // 1815 Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &IfDesc); 1816 if (EFI_ERROR (Status)) { 1817 return FALSE; 1818 } 1819 1820 DeviceClass = IfDesc.InterfaceClass; 1821 DeviceSubClass = IfDesc.InterfaceSubClass; 1822 DeviceProtocol = IfDesc.InterfaceProtocol; 1823 } 1824 1825 // 1826 // Check Class, SubClass and Protocol. 1827 // 1828 if ((UsbClass->DeviceClass != 0xff) && 1829 (UsbClass->DeviceClass != DeviceClass)) { 1830 return FALSE; 1831 } 1832 1833 if ((UsbClass->DeviceSubClass != 0xff) && 1834 (UsbClass->DeviceSubClass != DeviceSubClass)) { 1835 return FALSE; 1836 } 1837 1838 if ((UsbClass->DeviceProtocol != 0xff) && 1839 (UsbClass->DeviceProtocol != DeviceProtocol)) { 1840 return FALSE; 1841 } 1842 1843 return TRUE; 1844} 1845 1846/** 1847 Check whether a USB device match the specified USB WWID device path. This 1848 function follows "Load Option Processing" behavior in UEFI specification. 1849 1850 @param UsbIo USB I/O protocol associated with the USB device. 1851 @param UsbWwid The USB WWID device path to match. 1852 1853 @retval TRUE The USB device match the USB WWID device path. 1854 @retval FALSE The USB device does not match the USB WWID device path. 1855 1856**/ 1857BOOLEAN 1858BdsMatchUsbWwid ( 1859 IN EFI_USB_IO_PROTOCOL *UsbIo, 1860 IN USB_WWID_DEVICE_PATH *UsbWwid 1861 ) 1862{ 1863 EFI_STATUS Status; 1864 EFI_USB_DEVICE_DESCRIPTOR DevDesc; 1865 EFI_USB_INTERFACE_DESCRIPTOR IfDesc; 1866 UINT16 *LangIdTable; 1867 UINT16 TableSize; 1868 UINT16 Index; 1869 CHAR16 *CompareStr; 1870 UINTN CompareLen; 1871 CHAR16 *SerialNumberStr; 1872 UINTN Length; 1873 1874 if ((DevicePathType (UsbWwid) != MESSAGING_DEVICE_PATH) || 1875 (DevicePathSubType (UsbWwid) != MSG_USB_WWID_DP )){ 1876 return FALSE; 1877 } 1878 1879 // 1880 // Check Vendor Id and Product Id. 1881 // 1882 Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc); 1883 if (EFI_ERROR (Status)) { 1884 return FALSE; 1885 } 1886 if ((DevDesc.IdVendor != UsbWwid->VendorId) || 1887 (DevDesc.IdProduct != UsbWwid->ProductId)) { 1888 return FALSE; 1889 } 1890 1891 // 1892 // Check Interface Number. 1893 // 1894 Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &IfDesc); 1895 if (EFI_ERROR (Status)) { 1896 return FALSE; 1897 } 1898 if (IfDesc.InterfaceNumber != UsbWwid->InterfaceNumber) { 1899 return FALSE; 1900 } 1901 1902 // 1903 // Check Serial Number. 1904 // 1905 if (DevDesc.StrSerialNumber == 0) { 1906 return FALSE; 1907 } 1908 1909 // 1910 // Get all supported languages. 1911 // 1912 TableSize = 0; 1913 LangIdTable = NULL; 1914 Status = UsbIo->UsbGetSupportedLanguages (UsbIo, &LangIdTable, &TableSize); 1915 if (EFI_ERROR (Status) || (TableSize == 0) || (LangIdTable == NULL)) { 1916 return FALSE; 1917 } 1918 1919 // 1920 // Serial number in USB WWID device path is the last 64-or-less UTF-16 characters. 1921 // 1922 CompareStr = (CHAR16 *) (UINTN) (UsbWwid + 1); 1923 CompareLen = (DevicePathNodeLength (UsbWwid) - sizeof (USB_WWID_DEVICE_PATH)) / sizeof (CHAR16); 1924 if (CompareStr[CompareLen - 1] == L'\0') { 1925 CompareLen--; 1926 } 1927 1928 // 1929 // Compare serial number in each supported language. 1930 // 1931 for (Index = 0; Index < TableSize / sizeof (UINT16); Index++) { 1932 SerialNumberStr = NULL; 1933 Status = UsbIo->UsbGetStringDescriptor ( 1934 UsbIo, 1935 LangIdTable[Index], 1936 DevDesc.StrSerialNumber, 1937 &SerialNumberStr 1938 ); 1939 if (EFI_ERROR (Status) || (SerialNumberStr == NULL)) { 1940 continue; 1941 } 1942 1943 Length = StrLen (SerialNumberStr); 1944 if ((Length >= CompareLen) && 1945 (CompareMem (SerialNumberStr + Length - CompareLen, CompareStr, CompareLen * sizeof (CHAR16)) == 0)) { 1946 FreePool (SerialNumberStr); 1947 return TRUE; 1948 } 1949 1950 FreePool (SerialNumberStr); 1951 } 1952 1953 return FALSE; 1954} 1955 1956/** 1957 Find a USB device path which match the specified short-form device path start 1958 with USB Class or USB WWID device path and load the boot file then return the 1959 image handle. If ParentDevicePath is NULL, this function will search in all USB 1960 devices of the platform. If ParentDevicePath is not NULL,this function will only 1961 search in its child devices. 1962 1963 @param ParentDevicePath The device path of the parent. 1964 @param ShortFormDevicePath The USB Class or USB WWID device path to match. 1965 1966 @return The image Handle if find load file from specified short-form device path 1967 or NULL if not found. 1968 1969**/ 1970EFI_HANDLE * 1971BdsFindUsbDevice ( 1972 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath, 1973 IN EFI_DEVICE_PATH_PROTOCOL *ShortFormDevicePath 1974 ) 1975{ 1976 EFI_STATUS Status; 1977 UINTN UsbIoHandleCount; 1978 EFI_HANDLE *UsbIoHandleBuffer; 1979 EFI_DEVICE_PATH_PROTOCOL *UsbIoDevicePath; 1980 EFI_USB_IO_PROTOCOL *UsbIo; 1981 UINTN Index; 1982 UINTN ParentSize; 1983 UINTN Size; 1984 EFI_HANDLE ImageHandle; 1985 EFI_HANDLE Handle; 1986 EFI_DEVICE_PATH_PROTOCOL *FullDevicePath; 1987 EFI_DEVICE_PATH_PROTOCOL *NextDevicePath; 1988 1989 FullDevicePath = NULL; 1990 ImageHandle = NULL; 1991 1992 // 1993 // Get all UsbIo Handles. 1994 // 1995 UsbIoHandleCount = 0; 1996 UsbIoHandleBuffer = NULL; 1997 Status = gBS->LocateHandleBuffer ( 1998 ByProtocol, 1999 &gEfiUsbIoProtocolGuid, 2000 NULL, 2001 &UsbIoHandleCount, 2002 &UsbIoHandleBuffer 2003 ); 2004 if (EFI_ERROR (Status) || (UsbIoHandleCount == 0) || (UsbIoHandleBuffer == NULL)) { 2005 return NULL; 2006 } 2007 2008 ParentSize = (ParentDevicePath == NULL) ? 0 : GetDevicePathSize (ParentDevicePath); 2009 for (Index = 0; Index < UsbIoHandleCount; Index++) { 2010 // 2011 // Get the Usb IO interface. 2012 // 2013 Status = gBS->HandleProtocol( 2014 UsbIoHandleBuffer[Index], 2015 &gEfiUsbIoProtocolGuid, 2016 (VOID **) &UsbIo 2017 ); 2018 if (EFI_ERROR (Status)) { 2019 continue; 2020 } 2021 2022 UsbIoDevicePath = DevicePathFromHandle (UsbIoHandleBuffer[Index]); 2023 if (UsbIoDevicePath == NULL) { 2024 continue; 2025 } 2026 2027 if (ParentDevicePath != NULL) { 2028 // 2029 // Compare starting part of UsbIoHandle's device path with ParentDevicePath. 2030 // 2031 Size = GetDevicePathSize (UsbIoDevicePath); 2032 if ((Size < ParentSize) || 2033 (CompareMem (UsbIoDevicePath, ParentDevicePath, ParentSize - END_DEVICE_PATH_LENGTH) != 0)) { 2034 continue; 2035 } 2036 } 2037 2038 if (BdsMatchUsbClass (UsbIo, (USB_CLASS_DEVICE_PATH *) ShortFormDevicePath) || 2039 BdsMatchUsbWwid (UsbIo, (USB_WWID_DEVICE_PATH *) ShortFormDevicePath)) { 2040 // 2041 // Try to find if there is the boot file in this DevicePath 2042 // 2043 NextDevicePath = NextDevicePathNode (ShortFormDevicePath); 2044 if (!IsDevicePathEnd (NextDevicePath)) { 2045 FullDevicePath = AppendDevicePath (UsbIoDevicePath, NextDevicePath); 2046 // 2047 // Connect the full device path, so that Simple File System protocol 2048 // could be installed for this USB device. 2049 // 2050 BdsLibConnectDevicePath (FullDevicePath); 2051 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderLoad)); 2052 Status = gBS->LoadImage ( 2053 TRUE, 2054 gImageHandle, 2055 FullDevicePath, 2056 NULL, 2057 0, 2058 &ImageHandle 2059 ); 2060 FreePool (FullDevicePath); 2061 } else { 2062 FullDevicePath = UsbIoDevicePath; 2063 Status = EFI_NOT_FOUND; 2064 } 2065 2066 // 2067 // If we didn't find an image directly, we need to try as if it is a removable device boot option 2068 // and load the image according to the default boot behavior for removable device. 2069 // 2070 if (EFI_ERROR (Status)) { 2071 // 2072 // check if there is a bootable removable media could be found in this device path , 2073 // and get the bootable media handle 2074 // 2075 Handle = BdsLibGetBootableHandle(UsbIoDevicePath); 2076 if (Handle == NULL) { 2077 continue; 2078 } 2079 // 2080 // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from removable Media 2081 // machinename is ia32, ia64, x64, ... 2082 // 2083 FullDevicePath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME); 2084 if (FullDevicePath != NULL) { 2085 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderLoad)); 2086 Status = gBS->LoadImage ( 2087 TRUE, 2088 gImageHandle, 2089 FullDevicePath, 2090 NULL, 2091 0, 2092 &ImageHandle 2093 ); 2094 if (EFI_ERROR (Status)) { 2095 // 2096 // The DevicePath failed, and it's not a valid 2097 // removable media device. 2098 // 2099 continue; 2100 } 2101 } else { 2102 continue; 2103 } 2104 } 2105 break; 2106 } 2107 } 2108 2109 FreePool (UsbIoHandleBuffer); 2110 return ImageHandle; 2111} 2112 2113/** 2114 Expand USB Class or USB WWID device path node to be full device path of a USB 2115 device in platform then load the boot file on this full device path and return the 2116 image handle. 2117 2118 This function support following 4 cases: 2119 1) Boot Option device path starts with a USB Class or USB WWID device path, 2120 and there is no Media FilePath device path in the end. 2121 In this case, it will follow Removable Media Boot Behavior. 2122 2) Boot Option device path starts with a USB Class or USB WWID device path, 2123 and ended with Media FilePath device path. 2124 3) Boot Option device path starts with a full device path to a USB Host Controller, 2125 contains a USB Class or USB WWID device path node, while not ended with Media 2126 FilePath device path. In this case, it will follow Removable Media Boot Behavior. 2127 4) Boot Option device path starts with a full device path to a USB Host Controller, 2128 contains a USB Class or USB WWID device path node, and ended with Media 2129 FilePath device path. 2130 2131 @param DevicePath The Boot Option device path. 2132 2133 @return The image handle of boot file, or NULL if there is no boot file found in 2134 the specified USB Class or USB WWID device path. 2135 2136**/ 2137EFI_HANDLE * 2138BdsExpandUsbShortFormDevicePath ( 2139 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath 2140 ) 2141{ 2142 EFI_HANDLE *ImageHandle; 2143 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; 2144 EFI_DEVICE_PATH_PROTOCOL *ShortFormDevicePath; 2145 2146 // 2147 // Search for USB Class or USB WWID device path node. 2148 // 2149 ShortFormDevicePath = NULL; 2150 ImageHandle = NULL; 2151 TempDevicePath = DevicePath; 2152 while (!IsDevicePathEnd (TempDevicePath)) { 2153 if ((DevicePathType (TempDevicePath) == MESSAGING_DEVICE_PATH) && 2154 ((DevicePathSubType (TempDevicePath) == MSG_USB_CLASS_DP) || 2155 (DevicePathSubType (TempDevicePath) == MSG_USB_WWID_DP))) { 2156 ShortFormDevicePath = TempDevicePath; 2157 break; 2158 } 2159 TempDevicePath = NextDevicePathNode (TempDevicePath); 2160 } 2161 2162 if (ShortFormDevicePath == NULL) { 2163 // 2164 // No USB Class or USB WWID device path node found, do nothing. 2165 // 2166 return NULL; 2167 } 2168 2169 if (ShortFormDevicePath == DevicePath) { 2170 // 2171 // Boot Option device path starts with USB Class or USB WWID device path. 2172 // 2173 ImageHandle = BdsFindUsbDevice (NULL, ShortFormDevicePath); 2174 if (ImageHandle == NULL) { 2175 // 2176 // Failed to find a match in existing devices, connect the short form USB 2177 // device path and try again. 2178 // 2179 BdsLibConnectUsbDevByShortFormDP (0xff, ShortFormDevicePath); 2180 ImageHandle = BdsFindUsbDevice (NULL, ShortFormDevicePath); 2181 } 2182 } else { 2183 // 2184 // Boot Option device path contains USB Class or USB WWID device path node. 2185 // 2186 2187 // 2188 // Prepare the parent device path for search. 2189 // 2190 TempDevicePath = DuplicateDevicePath (DevicePath); 2191 ASSERT (TempDevicePath != NULL); 2192 SetDevicePathEndNode (((UINT8 *) TempDevicePath) + ((UINTN) ShortFormDevicePath - (UINTN) DevicePath)); 2193 2194 // 2195 // The USB Host Controller device path is already in Boot Option device path 2196 // and USB Bus driver already support RemainingDevicePath starts with USB 2197 // Class or USB WWID device path, so just search in existing USB devices and 2198 // doesn't perform ConnectController here. 2199 // 2200 ImageHandle = BdsFindUsbDevice (TempDevicePath, ShortFormDevicePath); 2201 FreePool (TempDevicePath); 2202 } 2203 2204 return ImageHandle; 2205} 2206 2207/** 2208 Process the boot option follow the UEFI specification and 2209 special treat the legacy boot option with BBS_DEVICE_PATH. 2210 2211 @param Option The boot option need to be processed 2212 @param DevicePath The device path which describe where to load the 2213 boot image or the legacy BBS device path to boot 2214 the legacy OS 2215 @param ExitDataSize The size of exit data. 2216 @param ExitData Data returned when Boot image failed. 2217 2218 @retval EFI_SUCCESS Boot from the input boot option successfully. 2219 @retval EFI_NOT_FOUND If the Device Path is not found in the system 2220 2221**/ 2222EFI_STATUS 2223EFIAPI 2224BdsLibBootViaBootOption ( 2225 IN BDS_COMMON_OPTION *Option, 2226 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, 2227 OUT UINTN *ExitDataSize, 2228 OUT CHAR16 **ExitData OPTIONAL 2229 ) 2230{ 2231 EFI_STATUS Status; 2232 EFI_STATUS StatusLogo; 2233 EFI_HANDLE Handle; 2234 EFI_HANDLE ImageHandle; 2235 EFI_DEVICE_PATH_PROTOCOL *FilePath; 2236 EFI_LOADED_IMAGE_PROTOCOL *ImageInfo; 2237 EFI_DEVICE_PATH_PROTOCOL *WorkingDevicePath; 2238 EFI_ACPI_S3_SAVE_PROTOCOL *AcpiS3Save; 2239 LIST_ENTRY TempBootLists; 2240 EFI_BOOT_LOGO_PROTOCOL *BootLogo; 2241 2242 *ExitDataSize = 0; 2243 *ExitData = NULL; 2244 2245 // 2246 // Notes: this code can be remove after the s3 script table 2247 // hook on the event EVT_SIGNAL_READY_TO_BOOT or 2248 // EVT_SIGNAL_LEGACY_BOOT 2249 // 2250 Status = gBS->LocateProtocol (&gEfiAcpiS3SaveProtocolGuid, NULL, (VOID **) &AcpiS3Save); 2251 if (!EFI_ERROR (Status)) { 2252 AcpiS3Save->S3Save (AcpiS3Save, NULL); 2253 } 2254 // 2255 // If it's Device Path that starts with a hard drive path, append it with the front part to compose a 2256 // full device path 2257 // 2258 WorkingDevicePath = NULL; 2259 if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) && 2260 (DevicePathSubType (DevicePath) == MEDIA_HARDDRIVE_DP)) { 2261 WorkingDevicePath = BdsExpandPartitionPartialDevicePathToFull ( 2262 (HARDDRIVE_DEVICE_PATH *)DevicePath 2263 ); 2264 if (WorkingDevicePath != NULL) { 2265 DevicePath = WorkingDevicePath; 2266 } 2267 } 2268 2269 // 2270 // Set Boot Current 2271 // 2272 if (IsBootOptionValidNVVarialbe (Option)) { 2273 // 2274 // For a temporary boot (i.e. a boot by selected a EFI Shell using "Boot From File"), Boot Current is actually not valid. 2275 // In this case, "BootCurrent" is not created. 2276 // Only create the BootCurrent variable when it points to a valid Boot#### variable. 2277 // 2278 SetVariableAndReportStatusCodeOnError ( 2279 L"BootCurrent", 2280 &gEfiGlobalVariableGuid, 2281 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, 2282 sizeof (UINT16), 2283 &Option->BootCurrent 2284 ); 2285 } 2286 2287 // 2288 // Report Status Code to indicate ReadyToBoot event will be signalled 2289 // 2290 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT)); 2291 2292 // 2293 // Signal the EVT_SIGNAL_READY_TO_BOOT event 2294 // 2295 EfiSignalEventReadyToBoot(); 2296 2297 // 2298 // Expand USB Class or USB WWID device path node to be full device path of a USB 2299 // device in platform then load the boot file on this full device path and get the 2300 // image handle. 2301 // 2302 ImageHandle = BdsExpandUsbShortFormDevicePath (DevicePath); 2303 2304 // 2305 // Adjust the different type memory page number just before booting 2306 // and save the updated info into the variable for next boot to use 2307 // 2308 BdsSetMemoryTypeInformationVariable (); 2309 2310 // 2311 // By expanding the USB Class or WWID device path, the ImageHandle has returnned. 2312 // Here get the ImageHandle for the non USB class or WWID device path. 2313 // 2314 if (ImageHandle == NULL) { 2315 ASSERT (Option->DevicePath != NULL); 2316 if ((DevicePathType (Option->DevicePath) == BBS_DEVICE_PATH) && 2317 (DevicePathSubType (Option->DevicePath) == BBS_BBS_DP) 2318 ) { 2319 // 2320 // Check to see if we should legacy BOOT. If yes then do the legacy boot 2321 // 2322 return BdsLibDoLegacyBoot (Option); 2323 } 2324 2325 // 2326 // If the boot option point to Internal FV shell, make sure it is valid 2327 // 2328 Status = BdsLibUpdateFvFileDevicePath (&DevicePath, PcdGetPtr(PcdShellFile)); 2329 if (!EFI_ERROR(Status)) { 2330 if (Option->DevicePath != NULL) { 2331 FreePool(Option->DevicePath); 2332 } 2333 Option->DevicePath = AllocateZeroPool (GetDevicePathSize (DevicePath)); 2334 ASSERT(Option->DevicePath != NULL); 2335 CopyMem (Option->DevicePath, DevicePath, GetDevicePathSize (DevicePath)); 2336 // 2337 // Update the shell boot option 2338 // 2339 InitializeListHead (&TempBootLists); 2340 BdsLibRegisterNewOption (&TempBootLists, DevicePath, L"EFI Internal Shell", L"BootOrder"); 2341 2342 // 2343 // free the temporary device path created by BdsLibUpdateFvFileDevicePath() 2344 // 2345 FreePool (DevicePath); 2346 DevicePath = Option->DevicePath; 2347 } 2348 2349 DEBUG_CODE_BEGIN(); 2350 2351 if (Option->Description == NULL) { 2352 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Booting from unknown device path\n")); 2353 } else { 2354 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Booting %S\n", Option->Description)); 2355 } 2356 2357 DEBUG_CODE_END(); 2358 2359 // 2360 // Report status code for OS Loader LoadImage. 2361 // 2362 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderLoad)); 2363 Status = gBS->LoadImage ( 2364 TRUE, 2365 gImageHandle, 2366 DevicePath, 2367 NULL, 2368 0, 2369 &ImageHandle 2370 ); 2371 2372 // 2373 // If we didn't find an image directly, we need to try as if it is a removable device boot option 2374 // and load the image according to the default boot behavior for removable device. 2375 // 2376 if (EFI_ERROR (Status)) { 2377 // 2378 // check if there is a bootable removable media could be found in this device path , 2379 // and get the bootable media handle 2380 // 2381 Handle = BdsLibGetBootableHandle(DevicePath); 2382 if (Handle != NULL) { 2383 // 2384 // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from removable Media 2385 // machinename is ia32, ia64, x64, ... 2386 // 2387 FilePath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME); 2388 if (FilePath != NULL) { 2389 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderLoad)); 2390 Status = gBS->LoadImage ( 2391 TRUE, 2392 gImageHandle, 2393 FilePath, 2394 NULL, 2395 0, 2396 &ImageHandle 2397 ); 2398 } 2399 } 2400 } 2401 } 2402 // 2403 // Provide the image with it's load options 2404 // 2405 if ((ImageHandle == NULL) || (EFI_ERROR(Status))) { 2406 // 2407 // Report Status Code to indicate that the failure to load boot option 2408 // 2409 REPORT_STATUS_CODE ( 2410 EFI_ERROR_CODE | EFI_ERROR_MINOR, 2411 (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR) 2412 ); 2413 goto Done; 2414 } 2415 2416 Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo); 2417 ASSERT_EFI_ERROR (Status); 2418 2419 if (Option->LoadOptionsSize != 0) { 2420 ImageInfo->LoadOptionsSize = Option->LoadOptionsSize; 2421 ImageInfo->LoadOptions = Option->LoadOptions; 2422 } 2423 2424 // 2425 // Clean to NULL because the image is loaded directly from the firmwares boot manager. 2426 // 2427 ImageInfo->ParentHandle = NULL; 2428 2429 // 2430 // Before calling the image, enable the Watchdog Timer for 2431 // the 5 Minute period 2432 // 2433 gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL); 2434 2435 // 2436 // Write boot to OS performance data for UEFI boot 2437 // 2438 PERF_CODE ( 2439 WriteBootToOsPerformanceData (NULL, NULL); 2440 ); 2441 2442 // 2443 // Report status code for OS Loader StartImage. 2444 // 2445 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderStart)); 2446 2447 Status = gBS->StartImage (ImageHandle, ExitDataSize, ExitData); 2448 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Image Return Status = %r\n", Status)); 2449 if (EFI_ERROR (Status)) { 2450 // 2451 // Report Status Code to indicate that boot failure 2452 // 2453 REPORT_STATUS_CODE ( 2454 EFI_ERROR_CODE | EFI_ERROR_MINOR, 2455 (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED) 2456 ); 2457 } 2458 2459 // 2460 // Clear the Watchdog Timer after the image returns 2461 // 2462 gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL); 2463 2464Done: 2465 // 2466 // Set Logo status invalid after trying one boot option 2467 // 2468 BootLogo = NULL; 2469 StatusLogo = gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo); 2470 if (!EFI_ERROR (StatusLogo) && (BootLogo != NULL)) { 2471 BootLogo->SetBootLogo (BootLogo, NULL, 0, 0, 0, 0); 2472 } 2473 2474 // 2475 // Clear Boot Current 2476 // Deleting variable with current implementation shouldn't fail. 2477 // 2478 gRT->SetVariable ( 2479 L"BootCurrent", 2480 &gEfiGlobalVariableGuid, 2481 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, 2482 0, 2483 NULL 2484 ); 2485 2486 return Status; 2487} 2488 2489 2490/** 2491 Expand a device path that starts with a hard drive media device path node to be a 2492 full device path that includes the full hardware path to the device. We need 2493 to do this so it can be booted. As an optimization the front match (the part point 2494 to the partition node. E.g. ACPI() /PCI()/ATA()/Partition() ) is saved in a variable 2495 so a connect all is not required on every boot. All successful history device path 2496 which point to partition node (the front part) will be saved. 2497 2498 @param HardDriveDevicePath EFI Device Path to boot, if it starts with a hard 2499 drive media device path. 2500 @return A Pointer to the full device path or NULL if a valid Hard Drive devic path 2501 cannot be found. 2502 2503**/ 2504EFI_DEVICE_PATH_PROTOCOL * 2505EFIAPI 2506BdsExpandPartitionPartialDevicePathToFull ( 2507 IN HARDDRIVE_DEVICE_PATH *HardDriveDevicePath 2508 ) 2509{ 2510 EFI_STATUS Status; 2511 UINTN BlockIoHandleCount; 2512 EFI_HANDLE *BlockIoBuffer; 2513 EFI_DEVICE_PATH_PROTOCOL *FullDevicePath; 2514 EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath; 2515 EFI_DEVICE_PATH_PROTOCOL *DevicePath; 2516 UINTN Index; 2517 UINTN InstanceNum; 2518 EFI_DEVICE_PATH_PROTOCOL *CachedDevicePath; 2519 EFI_DEVICE_PATH_PROTOCOL *TempNewDevicePath; 2520 UINTN CachedDevicePathSize; 2521 BOOLEAN DeviceExist; 2522 BOOLEAN NeedAdjust; 2523 EFI_DEVICE_PATH_PROTOCOL *Instance; 2524 UINTN Size; 2525 2526 FullDevicePath = NULL; 2527 // 2528 // Check if there is prestore HD_BOOT_DEVICE_PATH_VARIABLE_NAME variable. 2529 // If exist, search the front path which point to partition node in the variable instants. 2530 // If fail to find or HD_BOOT_DEVICE_PATH_VARIABLE_NAME not exist, reconnect all and search in all system 2531 // 2532 GetVariable2 ( 2533 HD_BOOT_DEVICE_PATH_VARIABLE_NAME, 2534 &gHdBootDevicePathVariablGuid, 2535 (VOID **) &CachedDevicePath, 2536 &CachedDevicePathSize 2537 ); 2538 2539 // 2540 // Delete the invalid HD_BOOT_DEVICE_PATH_VARIABLE_NAME variable. 2541 // 2542 if ((CachedDevicePath != NULL) && !IsDevicePathValid (CachedDevicePath, CachedDevicePathSize)) { 2543 FreePool (CachedDevicePath); 2544 CachedDevicePath = NULL; 2545 Status = gRT->SetVariable ( 2546 HD_BOOT_DEVICE_PATH_VARIABLE_NAME, 2547 &gHdBootDevicePathVariablGuid, 2548 0, 2549 0, 2550 NULL 2551 ); 2552 ASSERT_EFI_ERROR (Status); 2553 } 2554 2555 if (CachedDevicePath != NULL) { 2556 TempNewDevicePath = CachedDevicePath; 2557 DeviceExist = FALSE; 2558 NeedAdjust = FALSE; 2559 do { 2560 // 2561 // Check every instance of the variable 2562 // First, check whether the instance contain the partition node, which is needed for distinguishing multi 2563 // partial partition boot option. Second, check whether the instance could be connected. 2564 // 2565 Instance = GetNextDevicePathInstance (&TempNewDevicePath, &Size); 2566 if (MatchPartitionDevicePathNode (Instance, HardDriveDevicePath)) { 2567 // 2568 // Connect the device path instance, the device path point to hard drive media device path node 2569 // e.g. ACPI() /PCI()/ATA()/Partition() 2570 // 2571 Status = BdsLibConnectDevicePath (Instance); 2572 if (!EFI_ERROR (Status)) { 2573 DeviceExist = TRUE; 2574 break; 2575 } 2576 } 2577 // 2578 // Come here means the first instance is not matched 2579 // 2580 NeedAdjust = TRUE; 2581 FreePool(Instance); 2582 } while (TempNewDevicePath != NULL); 2583 2584 if (DeviceExist) { 2585 // 2586 // Find the matched device path. 2587 // Append the file path information from the boot option and return the fully expanded device path. 2588 // 2589 DevicePath = NextDevicePathNode ((EFI_DEVICE_PATH_PROTOCOL *) HardDriveDevicePath); 2590 FullDevicePath = AppendDevicePath (Instance, DevicePath); 2591 2592 // 2593 // Adjust the HD_BOOT_DEVICE_PATH_VARIABLE_NAME instances sequence if the matched one is not first one. 2594 // 2595 if (NeedAdjust) { 2596 // 2597 // First delete the matched instance. 2598 // 2599 TempNewDevicePath = CachedDevicePath; 2600 CachedDevicePath = BdsLibDelPartMatchInstance (CachedDevicePath, Instance ); 2601 FreePool (TempNewDevicePath); 2602 2603 // 2604 // Second, append the remaining path after the matched instance 2605 // 2606 TempNewDevicePath = CachedDevicePath; 2607 CachedDevicePath = AppendDevicePathInstance (Instance, CachedDevicePath ); 2608 FreePool (TempNewDevicePath); 2609 // 2610 // Save the matching Device Path so we don't need to do a connect all next time 2611 // Failure to set the variable only impacts the performance when next time expanding the short-form device path. 2612 // 2613 Status = gRT->SetVariable ( 2614 HD_BOOT_DEVICE_PATH_VARIABLE_NAME, 2615 &gHdBootDevicePathVariablGuid, 2616 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE, 2617 GetDevicePathSize (CachedDevicePath), 2618 CachedDevicePath 2619 ); 2620 } 2621 2622 FreePool (Instance); 2623 FreePool (CachedDevicePath); 2624 return FullDevicePath; 2625 } 2626 } 2627 2628 // 2629 // If we get here we fail to find or HD_BOOT_DEVICE_PATH_VARIABLE_NAME not exist, and now we need 2630 // to search all devices in the system for a matched partition 2631 // 2632 BdsLibConnectAllDriversToAllControllers (); 2633 Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &BlockIoHandleCount, &BlockIoBuffer); 2634 if (EFI_ERROR (Status) || BlockIoHandleCount == 0 || BlockIoBuffer == NULL) { 2635 // 2636 // If there was an error or there are no device handles that support 2637 // the BLOCK_IO Protocol, then return. 2638 // 2639 return NULL; 2640 } 2641 // 2642 // Loop through all the device handles that support the BLOCK_IO Protocol 2643 // 2644 for (Index = 0; Index < BlockIoHandleCount; Index++) { 2645 2646 Status = gBS->HandleProtocol (BlockIoBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID *) &BlockIoDevicePath); 2647 if (EFI_ERROR (Status) || BlockIoDevicePath == NULL) { 2648 continue; 2649 } 2650 2651 if (MatchPartitionDevicePathNode (BlockIoDevicePath, HardDriveDevicePath)) { 2652 // 2653 // Find the matched partition device path 2654 // 2655 DevicePath = NextDevicePathNode ((EFI_DEVICE_PATH_PROTOCOL *) HardDriveDevicePath); 2656 FullDevicePath = AppendDevicePath (BlockIoDevicePath, DevicePath); 2657 2658 // 2659 // Save the matched partition device path in HD_BOOT_DEVICE_PATH_VARIABLE_NAME variable 2660 // 2661 if (CachedDevicePath != NULL) { 2662 // 2663 // Save the matched partition device path as first instance of HD_BOOT_DEVICE_PATH_VARIABLE_NAME variable 2664 // 2665 if (BdsLibMatchDevicePaths (CachedDevicePath, BlockIoDevicePath)) { 2666 TempNewDevicePath = CachedDevicePath; 2667 CachedDevicePath = BdsLibDelPartMatchInstance (CachedDevicePath, BlockIoDevicePath); 2668 FreePool(TempNewDevicePath); 2669 } 2670 2671 if (CachedDevicePath != NULL) { 2672 TempNewDevicePath = CachedDevicePath; 2673 CachedDevicePath = AppendDevicePathInstance (BlockIoDevicePath, CachedDevicePath); 2674 FreePool(TempNewDevicePath); 2675 } else { 2676 CachedDevicePath = DuplicateDevicePath (BlockIoDevicePath); 2677 } 2678 2679 // 2680 // Here limit the device path instance number to 12, which is max number for a system support 3 IDE controller 2681 // If the user try to boot many OS in different HDs or partitions, in theory, 2682 // the HD_BOOT_DEVICE_PATH_VARIABLE_NAME variable maybe become larger and larger. 2683 // 2684 InstanceNum = 0; 2685 ASSERT (CachedDevicePath != NULL); 2686 TempNewDevicePath = CachedDevicePath; 2687 while (!IsDevicePathEnd (TempNewDevicePath)) { 2688 TempNewDevicePath = NextDevicePathNode (TempNewDevicePath); 2689 // 2690 // Parse one instance 2691 // 2692 while (!IsDevicePathEndType (TempNewDevicePath)) { 2693 TempNewDevicePath = NextDevicePathNode (TempNewDevicePath); 2694 } 2695 InstanceNum++; 2696 // 2697 // If the CachedDevicePath variable contain too much instance, only remain 12 instances. 2698 // 2699 if (InstanceNum >= 12) { 2700 SetDevicePathEndNode (TempNewDevicePath); 2701 break; 2702 } 2703 } 2704 } else { 2705 CachedDevicePath = DuplicateDevicePath (BlockIoDevicePath); 2706 } 2707 2708 // 2709 // Save the matching Device Path so we don't need to do a connect all next time 2710 // Failure to set the variable only impacts the performance when next time expanding the short-form device path. 2711 // 2712 Status = gRT->SetVariable ( 2713 HD_BOOT_DEVICE_PATH_VARIABLE_NAME, 2714 &gHdBootDevicePathVariablGuid, 2715 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE, 2716 GetDevicePathSize (CachedDevicePath), 2717 CachedDevicePath 2718 ); 2719 2720 break; 2721 } 2722 } 2723 2724 if (CachedDevicePath != NULL) { 2725 FreePool (CachedDevicePath); 2726 } 2727 if (BlockIoBuffer != NULL) { 2728 FreePool (BlockIoBuffer); 2729 } 2730 return FullDevicePath; 2731} 2732 2733/** 2734 Check whether there is a instance in BlockIoDevicePath, which contain multi device path 2735 instances, has the same partition node with HardDriveDevicePath device path 2736 2737 @param BlockIoDevicePath Multi device path instances which need to check 2738 @param HardDriveDevicePath A device path which starts with a hard drive media 2739 device path. 2740 2741 @retval TRUE There is a matched device path instance. 2742 @retval FALSE There is no matched device path instance. 2743 2744**/ 2745BOOLEAN 2746EFIAPI 2747MatchPartitionDevicePathNode ( 2748 IN EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath, 2749 IN HARDDRIVE_DEVICE_PATH *HardDriveDevicePath 2750 ) 2751{ 2752 HARDDRIVE_DEVICE_PATH *TmpHdPath; 2753 EFI_DEVICE_PATH_PROTOCOL *DevicePath; 2754 BOOLEAN Match; 2755 EFI_DEVICE_PATH_PROTOCOL *BlockIoHdDevicePathNode; 2756 2757 if ((BlockIoDevicePath == NULL) || (HardDriveDevicePath == NULL)) { 2758 return FALSE; 2759 } 2760 2761 // 2762 // Make PreviousDevicePath == the device path node before the end node 2763 // 2764 DevicePath = BlockIoDevicePath; 2765 BlockIoHdDevicePathNode = NULL; 2766 2767 // 2768 // find the partition device path node 2769 // 2770 while (!IsDevicePathEnd (DevicePath)) { 2771 if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) && 2772 (DevicePathSubType (DevicePath) == MEDIA_HARDDRIVE_DP) 2773 ) { 2774 BlockIoHdDevicePathNode = DevicePath; 2775 break; 2776 } 2777 2778 DevicePath = NextDevicePathNode (DevicePath); 2779 } 2780 2781 if (BlockIoHdDevicePathNode == NULL) { 2782 return FALSE; 2783 } 2784 // 2785 // See if the harddrive device path in blockio matches the orig Hard Drive Node 2786 // 2787 TmpHdPath = (HARDDRIVE_DEVICE_PATH *) BlockIoHdDevicePathNode; 2788 Match = FALSE; 2789 2790 // 2791 // Check for the match 2792 // 2793 if ((TmpHdPath->MBRType == HardDriveDevicePath->MBRType) && 2794 (TmpHdPath->SignatureType == HardDriveDevicePath->SignatureType)) { 2795 switch (TmpHdPath->SignatureType) { 2796 case SIGNATURE_TYPE_GUID: 2797 Match = CompareGuid ((EFI_GUID *)TmpHdPath->Signature, (EFI_GUID *)HardDriveDevicePath->Signature); 2798 break; 2799 case SIGNATURE_TYPE_MBR: 2800 Match = (BOOLEAN)(*((UINT32 *)(&(TmpHdPath->Signature[0]))) == ReadUnaligned32((UINT32 *)(&(HardDriveDevicePath->Signature[0])))); 2801 break; 2802 default: 2803 Match = FALSE; 2804 break; 2805 } 2806 } 2807 2808 return Match; 2809} 2810 2811/** 2812 Delete the boot option associated with the handle passed in. 2813 2814 @param Handle The handle which present the device path to create 2815 boot option 2816 2817 @retval EFI_SUCCESS Delete the boot option success 2818 @retval EFI_NOT_FOUND If the Device Path is not found in the system 2819 @retval EFI_OUT_OF_RESOURCES Lack of memory resource 2820 @retval Other Error return value from SetVariable() 2821 2822**/ 2823EFI_STATUS 2824BdsLibDeleteOptionFromHandle ( 2825 IN EFI_HANDLE Handle 2826 ) 2827{ 2828 UINT16 *BootOrder; 2829 UINT8 *BootOptionVar; 2830 UINTN BootOrderSize; 2831 UINTN BootOptionSize; 2832 EFI_STATUS Status; 2833 UINTN Index; 2834 UINT16 BootOption[BOOT_OPTION_MAX_CHAR]; 2835 UINTN DevicePathSize; 2836 UINTN OptionDevicePathSize; 2837 EFI_DEVICE_PATH_PROTOCOL *DevicePath; 2838 EFI_DEVICE_PATH_PROTOCOL *OptionDevicePath; 2839 UINT8 *TempPtr; 2840 2841 Status = EFI_SUCCESS; 2842 BootOrder = NULL; 2843 BootOrderSize = 0; 2844 2845 // 2846 // Check "BootOrder" variable, if no, means there is no any boot order. 2847 // 2848 BootOrder = BdsLibGetVariableAndSize ( 2849 L"BootOrder", 2850 &gEfiGlobalVariableGuid, 2851 &BootOrderSize 2852 ); 2853 if (BootOrder == NULL) { 2854 return EFI_NOT_FOUND; 2855 } 2856 2857 // 2858 // Convert device handle to device path protocol instance 2859 // 2860 DevicePath = DevicePathFromHandle (Handle); 2861 if (DevicePath == NULL) { 2862 return EFI_NOT_FOUND; 2863 } 2864 DevicePathSize = GetDevicePathSize (DevicePath); 2865 2866 // 2867 // Loop all boot order variable and find the matching device path 2868 // 2869 Index = 0; 2870 while (Index < BootOrderSize / sizeof (UINT16)) { 2871 UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]); 2872 BootOptionVar = BdsLibGetVariableAndSize ( 2873 BootOption, 2874 &gEfiGlobalVariableGuid, 2875 &BootOptionSize 2876 ); 2877 2878 if (BootOptionVar == NULL) { 2879 FreePool (BootOrder); 2880 return EFI_OUT_OF_RESOURCES; 2881 } 2882 2883 if (!ValidateOption(BootOptionVar, BootOptionSize)) { 2884 BdsDeleteBootOption (BootOrder[Index], BootOrder, &BootOrderSize); 2885 FreePool (BootOptionVar); 2886 Index++; 2887 continue; 2888 } 2889 2890 TempPtr = BootOptionVar; 2891 TempPtr += sizeof (UINT32) + sizeof (UINT16); 2892 TempPtr += StrSize ((CHAR16 *) TempPtr); 2893 OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr; 2894 OptionDevicePathSize = GetDevicePathSize (OptionDevicePath); 2895 2896 // 2897 // Check whether the device path match 2898 // 2899 if ((OptionDevicePathSize == DevicePathSize) && 2900 (CompareMem (DevicePath, OptionDevicePath, DevicePathSize) == 0)) { 2901 BdsDeleteBootOption (BootOrder[Index], BootOrder, &BootOrderSize); 2902 FreePool (BootOptionVar); 2903 break; 2904 } 2905 2906 FreePool (BootOptionVar); 2907 Index++; 2908 } 2909 2910 // 2911 // Adjust number of boot option for "BootOrder" variable. 2912 // 2913 Status = gRT->SetVariable ( 2914 L"BootOrder", 2915 &gEfiGlobalVariableGuid, 2916 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, 2917 BootOrderSize, 2918 BootOrder 2919 ); 2920 // 2921 // Shrinking variable with existing variable implementation shouldn't fail. 2922 // 2923 ASSERT_EFI_ERROR (Status); 2924 2925 FreePool (BootOrder); 2926 2927 return Status; 2928} 2929 2930 2931/** 2932 Delete all invalid EFI boot options. 2933 2934 @retval EFI_SUCCESS Delete all invalid boot option success 2935 @retval EFI_NOT_FOUND Variable "BootOrder" is not found 2936 @retval EFI_OUT_OF_RESOURCES Lack of memory resource 2937 @retval Other Error return value from SetVariable() 2938 2939**/ 2940EFI_STATUS 2941BdsDeleteAllInvalidEfiBootOption ( 2942 VOID 2943 ) 2944{ 2945 UINT16 *BootOrder; 2946 UINT8 *BootOptionVar; 2947 UINTN BootOrderSize; 2948 UINTN BootOptionSize; 2949 EFI_STATUS Status; 2950 UINTN Index; 2951 UINTN Index2; 2952 UINT16 BootOption[BOOT_OPTION_MAX_CHAR]; 2953 EFI_DEVICE_PATH_PROTOCOL *OptionDevicePath; 2954 UINT8 *TempPtr; 2955 CHAR16 *Description; 2956 BOOLEAN Corrupted; 2957 2958 Status = EFI_SUCCESS; 2959 BootOrder = NULL; 2960 Description = NULL; 2961 OptionDevicePath = NULL; 2962 BootOrderSize = 0; 2963 Corrupted = FALSE; 2964 2965 // 2966 // Check "BootOrder" variable firstly, this variable hold the number of boot options 2967 // 2968 BootOrder = BdsLibGetVariableAndSize ( 2969 L"BootOrder", 2970 &gEfiGlobalVariableGuid, 2971 &BootOrderSize 2972 ); 2973 if (NULL == BootOrder) { 2974 return EFI_NOT_FOUND; 2975 } 2976 2977 Index = 0; 2978 while (Index < BootOrderSize / sizeof (UINT16)) { 2979 UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]); 2980 BootOptionVar = BdsLibGetVariableAndSize ( 2981 BootOption, 2982 &gEfiGlobalVariableGuid, 2983 &BootOptionSize 2984 ); 2985 if (NULL == BootOptionVar) { 2986 FreePool (BootOrder); 2987 return EFI_OUT_OF_RESOURCES; 2988 } 2989 2990 if (!ValidateOption(BootOptionVar, BootOptionSize)) { 2991 Corrupted = TRUE; 2992 } else { 2993 TempPtr = BootOptionVar; 2994 TempPtr += sizeof (UINT32) + sizeof (UINT16); 2995 Description = (CHAR16 *) TempPtr; 2996 TempPtr += StrSize ((CHAR16 *) TempPtr); 2997 OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr; 2998 2999 // 3000 // Skip legacy boot option (BBS boot device) 3001 // 3002 if ((DevicePathType (OptionDevicePath) == BBS_DEVICE_PATH) && 3003 (DevicePathSubType (OptionDevicePath) == BBS_BBS_DP)) { 3004 FreePool (BootOptionVar); 3005 Index++; 3006 continue; 3007 } 3008 } 3009 3010 if (Corrupted || !BdsLibIsValidEFIBootOptDevicePathExt (OptionDevicePath, FALSE, Description)) { 3011 // 3012 // Delete this invalid boot option "Boot####" 3013 // 3014 Status = gRT->SetVariable ( 3015 BootOption, 3016 &gEfiGlobalVariableGuid, 3017 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, 3018 0, 3019 NULL 3020 ); 3021 // 3022 // Deleting variable with current variable implementation shouldn't fail. 3023 // 3024 ASSERT_EFI_ERROR (Status); 3025 // 3026 // Mark this boot option in boot order as deleted 3027 // 3028 BootOrder[Index] = 0xffff; 3029 Corrupted = FALSE; 3030 } 3031 3032 FreePool (BootOptionVar); 3033 Index++; 3034 } 3035 3036 // 3037 // Adjust boot order array 3038 // 3039 Index2 = 0; 3040 for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) { 3041 if (BootOrder[Index] != 0xffff) { 3042 BootOrder[Index2] = BootOrder[Index]; 3043 Index2 ++; 3044 } 3045 } 3046 Status = gRT->SetVariable ( 3047 L"BootOrder", 3048 &gEfiGlobalVariableGuid, 3049 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, 3050 Index2 * sizeof (UINT16), 3051 BootOrder 3052 ); 3053 // 3054 // Shrinking variable with current variable implementation shouldn't fail. 3055 // 3056 ASSERT_EFI_ERROR (Status); 3057 3058 FreePool (BootOrder); 3059 3060 return Status; 3061} 3062 3063 3064/** 3065 For EFI boot option, BDS separate them as six types: 3066 1. Network - The boot option points to the SimpleNetworkProtocol device. 3067 Bds will try to automatically create this type boot option when enumerate. 3068 2. Shell - The boot option points to internal flash shell. 3069 Bds will try to automatically create this type boot option when enumerate. 3070 3. Removable BlockIo - The boot option only points to the removable media 3071 device, like USB flash disk, DVD, Floppy etc. 3072 These device should contain a *removable* blockIo 3073 protocol in their device handle. 3074 Bds will try to automatically create this type boot option 3075 when enumerate. 3076 4. Fixed BlockIo - The boot option only points to a Fixed blockIo device, 3077 like HardDisk. 3078 These device should contain a *fixed* blockIo 3079 protocol in their device handle. 3080 BDS will skip fixed blockIo devices, and NOT 3081 automatically create boot option for them. But BDS 3082 will help to delete those fixed blockIo boot option, 3083 whose description rule conflict with other auto-created 3084 boot options. 3085 5. Non-BlockIo Simplefile - The boot option points to a device whose handle 3086 has SimpleFileSystem Protocol, but has no blockio 3087 protocol. These devices do not offer blockIo 3088 protocol, but BDS still can get the 3089 \EFI\BOOT\boot{machinename}.EFI by SimpleFileSystem 3090 Protocol. 3091 6. File - The boot option points to a file. These boot options are usually 3092 created by user manually or OS loader. BDS will not delete or modify 3093 these boot options. 3094 3095 This function will enumerate all possible boot device in the system, and 3096 automatically create boot options for Network, Shell, Removable BlockIo, 3097 and Non-BlockIo Simplefile devices. 3098 It will only execute once of every boot. 3099 3100 @param BdsBootOptionList The header of the link list which indexed all 3101 current boot options 3102 3103 @retval EFI_SUCCESS Finished all the boot device enumerate and create 3104 the boot option base on that boot device 3105 3106 @retval EFI_OUT_OF_RESOURCES Failed to enumerate the boot device and create the boot option list 3107**/ 3108EFI_STATUS 3109EFIAPI 3110BdsLibEnumerateAllBootOption ( 3111 IN OUT LIST_ENTRY *BdsBootOptionList 3112 ) 3113{ 3114 EFI_STATUS Status; 3115 UINT16 FloppyNumber; 3116 UINT16 HarddriveNumber; 3117 UINT16 CdromNumber; 3118 UINT16 UsbNumber; 3119 UINT16 MiscNumber; 3120 UINT16 ScsiNumber; 3121 UINT16 NonBlockNumber; 3122 UINTN NumberBlockIoHandles; 3123 EFI_HANDLE *BlockIoHandles; 3124 EFI_BLOCK_IO_PROTOCOL *BlkIo; 3125 BOOLEAN Removable[2]; 3126 UINTN RemovableIndex; 3127 UINTN Index; 3128 UINTN NumOfLoadFileHandles; 3129 EFI_HANDLE *LoadFileHandles; 3130 UINTN FvHandleCount; 3131 EFI_HANDLE *FvHandleBuffer; 3132 EFI_FV_FILETYPE Type; 3133 UINTN Size; 3134 EFI_FV_FILE_ATTRIBUTES Attributes; 3135 UINT32 AuthenticationStatus; 3136 EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv; 3137 EFI_DEVICE_PATH_PROTOCOL *DevicePath; 3138 UINTN DevicePathType; 3139 CHAR16 Buffer[40]; 3140 EFI_HANDLE *FileSystemHandles; 3141 UINTN NumberFileSystemHandles; 3142 BOOLEAN NeedDelete; 3143 EFI_IMAGE_DOS_HEADER DosHeader; 3144 CHAR8 *PlatLang; 3145 CHAR8 *LastLang; 3146 EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData; 3147 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr; 3148 CHAR16 *MacStr; 3149 CHAR16 *IPverStr; 3150 EFI_HANDLE *NetworkHandles; 3151 UINTN BufferSize; 3152 3153 FloppyNumber = 0; 3154 HarddriveNumber = 0; 3155 CdromNumber = 0; 3156 UsbNumber = 0; 3157 MiscNumber = 0; 3158 ScsiNumber = 0; 3159 PlatLang = NULL; 3160 LastLang = NULL; 3161 ZeroMem (Buffer, sizeof (Buffer)); 3162 3163 // 3164 // If the boot device enumerate happened, just get the boot 3165 // device from the boot order variable 3166 // 3167 if (mEnumBootDevice) { 3168 GetVariable2 (LAST_ENUM_LANGUAGE_VARIABLE_NAME, &gLastEnumLangGuid, (VOID**)&LastLang, NULL); 3169 GetEfiGlobalVariable2 (L"PlatformLang", (VOID**)&PlatLang, NULL); 3170 ASSERT (PlatLang != NULL); 3171 if ((LastLang != NULL) && (AsciiStrCmp (LastLang, PlatLang) == 0)) { 3172 Status = BdsLibBuildOptionFromVar (BdsBootOptionList, L"BootOrder"); 3173 FreePool (LastLang); 3174 FreePool (PlatLang); 3175 return Status; 3176 } else { 3177 Status = gRT->SetVariable ( 3178 LAST_ENUM_LANGUAGE_VARIABLE_NAME, 3179 &gLastEnumLangGuid, 3180 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE, 3181 AsciiStrSize (PlatLang), 3182 PlatLang 3183 ); 3184 // 3185 // Failure to set the variable only impacts the performance next time enumerating the boot options. 3186 // 3187 3188 if (LastLang != NULL) { 3189 FreePool (LastLang); 3190 } 3191 FreePool (PlatLang); 3192 } 3193 } 3194 3195 // 3196 // Notes: this dirty code is to get the legacy boot option from the 3197 // BBS table and create to variable as the EFI boot option, it should 3198 // be removed after the CSM can provide legacy boot option directly 3199 // 3200 REFRESH_LEGACY_BOOT_OPTIONS; 3201 3202 // 3203 // Delete invalid boot option 3204 // 3205 BdsDeleteAllInvalidEfiBootOption (); 3206 3207 // 3208 // Parse removable media followed by fixed media. 3209 // The Removable[] array is used by the for-loop below to create removable media boot options 3210 // at first, and then to create fixed media boot options. 3211 // 3212 Removable[0] = FALSE; 3213 Removable[1] = TRUE; 3214 3215 gBS->LocateHandleBuffer ( 3216 ByProtocol, 3217 &gEfiBlockIoProtocolGuid, 3218 NULL, 3219 &NumberBlockIoHandles, 3220 &BlockIoHandles 3221 ); 3222 3223 for (RemovableIndex = 0; RemovableIndex < 2; RemovableIndex++) { 3224 for (Index = 0; Index < NumberBlockIoHandles; Index++) { 3225 Status = gBS->HandleProtocol ( 3226 BlockIoHandles[Index], 3227 &gEfiBlockIoProtocolGuid, 3228 (VOID **) &BlkIo 3229 ); 3230 // 3231 // skip the logical partition 3232 // 3233 if (EFI_ERROR (Status) || BlkIo->Media->LogicalPartition) { 3234 continue; 3235 } 3236 3237 // 3238 // firstly fixed block io then the removable block io 3239 // 3240 if (BlkIo->Media->RemovableMedia == Removable[RemovableIndex]) { 3241 continue; 3242 } 3243 DevicePath = DevicePathFromHandle (BlockIoHandles[Index]); 3244 DevicePathType = BdsGetBootTypeFromDevicePath (DevicePath); 3245 3246 switch (DevicePathType) { 3247 case BDS_EFI_ACPI_FLOPPY_BOOT: 3248 if (FloppyNumber != 0) { 3249 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_FLOPPY)), FloppyNumber); 3250 } else { 3251 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_FLOPPY))); 3252 } 3253 BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer); 3254 FloppyNumber++; 3255 break; 3256 3257 // 3258 // Assume a removable SATA device should be the DVD/CD device, a fixed SATA device should be the Hard Drive device. 3259 // 3260 case BDS_EFI_MESSAGE_ATAPI_BOOT: 3261 case BDS_EFI_MESSAGE_SATA_BOOT: 3262 if (BlkIo->Media->RemovableMedia) { 3263 if (CdromNumber != 0) { 3264 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_CD_DVD)), CdromNumber); 3265 } else { 3266 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_CD_DVD))); 3267 } 3268 CdromNumber++; 3269 } else { 3270 if (HarddriveNumber != 0) { 3271 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_HARDDRIVE)), HarddriveNumber); 3272 } else { 3273 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_HARDDRIVE))); 3274 } 3275 HarddriveNumber++; 3276 } 3277 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Buffer: %S\n", Buffer)); 3278 BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer); 3279 break; 3280 3281 case BDS_EFI_MESSAGE_USB_DEVICE_BOOT: 3282 if (UsbNumber != 0) { 3283 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_USB)), UsbNumber); 3284 } else { 3285 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_USB))); 3286 } 3287 BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer); 3288 UsbNumber++; 3289 break; 3290 3291 case BDS_EFI_MESSAGE_SCSI_BOOT: 3292 if (ScsiNumber != 0) { 3293 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_SCSI)), ScsiNumber); 3294 } else { 3295 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_SCSI))); 3296 } 3297 BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer); 3298 ScsiNumber++; 3299 break; 3300 3301 case BDS_EFI_MESSAGE_MISC_BOOT: 3302 default: 3303 if (MiscNumber != 0) { 3304 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_MISC)), MiscNumber); 3305 } else { 3306 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_MISC))); 3307 } 3308 BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer); 3309 MiscNumber++; 3310 break; 3311 } 3312 } 3313 } 3314 3315 if (NumberBlockIoHandles != 0) { 3316 FreePool (BlockIoHandles); 3317 } 3318 3319 // 3320 // If there is simple file protocol which does not consume block Io protocol, create a boot option for it here. 3321 // 3322 NonBlockNumber = 0; 3323 gBS->LocateHandleBuffer ( 3324 ByProtocol, 3325 &gEfiSimpleFileSystemProtocolGuid, 3326 NULL, 3327 &NumberFileSystemHandles, 3328 &FileSystemHandles 3329 ); 3330 for (Index = 0; Index < NumberFileSystemHandles; Index++) { 3331 Status = gBS->HandleProtocol ( 3332 FileSystemHandles[Index], 3333 &gEfiBlockIoProtocolGuid, 3334 (VOID **) &BlkIo 3335 ); 3336 if (!EFI_ERROR (Status)) { 3337 // 3338 // Skip if the file system handle supports a BlkIo protocol, 3339 // 3340 continue; 3341 } 3342 3343 // 3344 // Do the removable Media thing. \EFI\BOOT\boot{machinename}.EFI 3345 // machinename is ia32, ia64, x64, ... 3346 // 3347 Hdr.Union = &HdrData; 3348 NeedDelete = TRUE; 3349 Status = BdsLibGetImageHeader ( 3350 FileSystemHandles[Index], 3351 EFI_REMOVABLE_MEDIA_FILE_NAME, 3352 &DosHeader, 3353 Hdr 3354 ); 3355 if (!EFI_ERROR (Status) && 3356 EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Hdr.Pe32->FileHeader.Machine) && 3357 Hdr.Pe32->OptionalHeader.Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) { 3358 NeedDelete = FALSE; 3359 } 3360 3361 if (NeedDelete) { 3362 // 3363 // No such file or the file is not a EFI application, delete this boot option 3364 // 3365 BdsLibDeleteOptionFromHandle (FileSystemHandles[Index]); 3366 } else { 3367 if (NonBlockNumber != 0) { 3368 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_NON_BLOCK)), NonBlockNumber); 3369 } else { 3370 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_NON_BLOCK))); 3371 } 3372 BdsLibBuildOptionFromHandle (FileSystemHandles[Index], BdsBootOptionList, Buffer); 3373 NonBlockNumber++; 3374 } 3375 } 3376 3377 if (NumberFileSystemHandles != 0) { 3378 FreePool (FileSystemHandles); 3379 } 3380 3381 // 3382 // Parse Network Boot Device 3383 // 3384 NumOfLoadFileHandles = 0; 3385 // 3386 // Search Load File protocol for PXE boot option. 3387 // 3388 gBS->LocateHandleBuffer ( 3389 ByProtocol, 3390 &gEfiLoadFileProtocolGuid, 3391 NULL, 3392 &NumOfLoadFileHandles, 3393 &LoadFileHandles 3394 ); 3395 3396 for (Index = 0; Index < NumOfLoadFileHandles; Index++) { 3397 3398// 3399//Locate EFI_DEVICE_PATH_PROTOCOL to dynamically get IPv4/IPv6 protocol information. 3400// 3401 3402 Status = gBS->HandleProtocol ( 3403 LoadFileHandles[Index], 3404 &gEfiDevicePathProtocolGuid, 3405 (VOID **) &DevicePath 3406 ); 3407 3408 ASSERT_EFI_ERROR (Status); 3409 3410 while (!IsDevicePathEnd (DevicePath)) { 3411 if ((DevicePath->Type == MESSAGING_DEVICE_PATH) && 3412 (DevicePath->SubType == MSG_IPv4_DP)) { 3413 3414 // 3415 //Get handle infomation 3416 // 3417 BufferSize = 0; 3418 NetworkHandles = NULL; 3419 Status = gBS->LocateHandle ( 3420 ByProtocol, 3421 &gEfiSimpleNetworkProtocolGuid, 3422 NULL, 3423 &BufferSize, 3424 NetworkHandles 3425 ); 3426 3427 if (Status == EFI_BUFFER_TOO_SMALL) { 3428 NetworkHandles = AllocateZeroPool(BufferSize); 3429 if (NetworkHandles == NULL) { 3430 return (EFI_OUT_OF_RESOURCES); 3431 } 3432 Status = gBS->LocateHandle( 3433 ByProtocol, 3434 &gEfiSimpleNetworkProtocolGuid, 3435 NULL, 3436 &BufferSize, 3437 NetworkHandles 3438 ); 3439 } 3440 3441 // 3442 //Get the MAC string 3443 // 3444 Status = NetLibGetMacString ( 3445 *NetworkHandles, 3446 NULL, 3447 &MacStr 3448 ); 3449 if (EFI_ERROR (Status)) { 3450 return Status; 3451 } 3452 IPverStr = L" IPv4"; 3453 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s%s%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_NETWORK)),MacStr,IPverStr); 3454 break; 3455 } 3456 if((DevicePath->Type == MESSAGING_DEVICE_PATH) && 3457 (DevicePath->SubType == MSG_IPv6_DP)) { 3458 3459 // 3460 //Get handle infomation 3461 // 3462 BufferSize = 0; 3463 NetworkHandles = NULL; 3464 Status = gBS->LocateHandle ( 3465 ByProtocol, 3466 &gEfiSimpleNetworkProtocolGuid, 3467 NULL, 3468 &BufferSize, 3469 NetworkHandles 3470 ); 3471 3472 if (Status == EFI_BUFFER_TOO_SMALL) { 3473 NetworkHandles = AllocateZeroPool(BufferSize); 3474 if (NetworkHandles == NULL) { 3475 return (EFI_OUT_OF_RESOURCES); 3476 } 3477 Status = gBS->LocateHandle( 3478 ByProtocol, 3479 &gEfiSimpleNetworkProtocolGuid, 3480 NULL, 3481 &BufferSize, 3482 NetworkHandles 3483 ); 3484 } 3485 3486 // 3487 //Get the MAC string 3488 // 3489 Status = NetLibGetMacString ( 3490 *NetworkHandles, 3491 NULL, 3492 &MacStr 3493 ); 3494 if (EFI_ERROR (Status)) { 3495 return Status; 3496 } 3497 IPverStr = L" IPv6"; 3498 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s%s%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_NETWORK)),MacStr,IPverStr); 3499 break; 3500 } 3501 DevicePath = NextDevicePathNode (DevicePath); 3502 } 3503 3504 BdsLibBuildOptionFromHandle (LoadFileHandles[Index], BdsBootOptionList, Buffer); 3505 } 3506 3507 if (NumOfLoadFileHandles != 0) { 3508 FreePool (LoadFileHandles); 3509 } 3510 3511 // 3512 // Check if we have on flash shell 3513 // 3514 gBS->LocateHandleBuffer ( 3515 ByProtocol, 3516 &gEfiFirmwareVolume2ProtocolGuid, 3517 NULL, 3518 &FvHandleCount, 3519 &FvHandleBuffer 3520 ); 3521 for (Index = 0; Index < FvHandleCount; Index++) { 3522 gBS->HandleProtocol ( 3523 FvHandleBuffer[Index], 3524 &gEfiFirmwareVolume2ProtocolGuid, 3525 (VOID **) &Fv 3526 ); 3527 3528 Status = Fv->ReadFile ( 3529 Fv, 3530 PcdGetPtr(PcdShellFile), 3531 NULL, 3532 &Size, 3533 &Type, 3534 &Attributes, 3535 &AuthenticationStatus 3536 ); 3537 if (EFI_ERROR (Status)) { 3538 // 3539 // Skip if no shell file in the FV 3540 // 3541 continue; 3542 } 3543 // 3544 // Build the shell boot option 3545 // 3546 BdsLibBuildOptionFromShell (FvHandleBuffer[Index], BdsBootOptionList); 3547 } 3548 3549 if (FvHandleCount != 0) { 3550 FreePool (FvHandleBuffer); 3551 } 3552 // 3553 // Make sure every boot only have one time 3554 // boot device enumerate 3555 // 3556 Status = BdsLibBuildOptionFromVar (BdsBootOptionList, L"BootOrder"); 3557 mEnumBootDevice = TRUE; 3558 3559 return Status; 3560} 3561 3562/** 3563 Build the boot option with the handle parsed in 3564 3565 @param Handle The handle which present the device path to create 3566 boot option 3567 @param BdsBootOptionList The header of the link list which indexed all 3568 current boot options 3569 @param String The description of the boot option. 3570 3571**/ 3572VOID 3573EFIAPI 3574BdsLibBuildOptionFromHandle ( 3575 IN EFI_HANDLE Handle, 3576 IN LIST_ENTRY *BdsBootOptionList, 3577 IN CHAR16 *String 3578 ) 3579{ 3580 EFI_DEVICE_PATH_PROTOCOL *DevicePath; 3581 3582 DevicePath = DevicePathFromHandle (Handle); 3583 3584 // 3585 // Create and register new boot option 3586 // 3587 BdsLibRegisterNewOption (BdsBootOptionList, DevicePath, String, L"BootOrder"); 3588} 3589 3590 3591/** 3592 Build the on flash shell boot option with the handle parsed in. 3593 3594 @param Handle The handle which present the device path to create 3595 on flash shell boot option 3596 @param BdsBootOptionList The header of the link list which indexed all 3597 current boot options 3598 3599**/ 3600VOID 3601EFIAPI 3602BdsLibBuildOptionFromShell ( 3603 IN EFI_HANDLE Handle, 3604 IN OUT LIST_ENTRY *BdsBootOptionList 3605 ) 3606{ 3607 EFI_DEVICE_PATH_PROTOCOL *DevicePath; 3608 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH ShellNode; 3609 3610 DevicePath = DevicePathFromHandle (Handle); 3611 3612 // 3613 // Build the shell device path 3614 // 3615 EfiInitializeFwVolDevicepathNode (&ShellNode, PcdGetPtr(PcdShellFile)); 3616 3617 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &ShellNode); 3618 3619 // 3620 // Create and register the shell boot option 3621 // 3622 BdsLibRegisterNewOption (BdsBootOptionList, DevicePath, L"EFI Internal Shell", L"BootOrder"); 3623 3624} 3625 3626/** 3627 Boot from the UEFI spec defined "BootNext" variable. 3628 3629**/ 3630VOID 3631EFIAPI 3632BdsLibBootNext ( 3633 VOID 3634 ) 3635{ 3636 EFI_STATUS Status; 3637 UINT16 *BootNext; 3638 UINTN BootNextSize; 3639 CHAR16 Buffer[20]; 3640 BDS_COMMON_OPTION *BootOption; 3641 LIST_ENTRY TempList; 3642 UINTN ExitDataSize; 3643 CHAR16 *ExitData; 3644 3645 // 3646 // Init the boot option name buffer and temp link list 3647 // 3648 InitializeListHead (&TempList); 3649 ZeroMem (Buffer, sizeof (Buffer)); 3650 3651 BootNext = BdsLibGetVariableAndSize ( 3652 L"BootNext", 3653 &gEfiGlobalVariableGuid, 3654 &BootNextSize 3655 ); 3656 3657 // 3658 // Clear the boot next variable first 3659 // 3660 if (BootNext != NULL) { 3661 Status = gRT->SetVariable ( 3662 L"BootNext", 3663 &gEfiGlobalVariableGuid, 3664 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, 3665 0, 3666 NULL 3667 ); 3668 // 3669 // Deleting variable with current variable implementation shouldn't fail. 3670 // 3671 ASSERT_EFI_ERROR (Status); 3672 3673 // 3674 // Start to build the boot option and try to boot 3675 // 3676 UnicodeSPrint (Buffer, sizeof (Buffer), L"Boot%04x", *BootNext); 3677 BootOption = BdsLibVariableToOption (&TempList, Buffer); 3678 ASSERT (BootOption != NULL); 3679 BdsLibConnectDevicePath (BootOption->DevicePath); 3680 BdsLibBootViaBootOption (BootOption, BootOption->DevicePath, &ExitDataSize, &ExitData); 3681 FreePool(BootOption); 3682 FreePool(BootNext); 3683 } 3684 3685} 3686 3687/** 3688 Return the bootable media handle. 3689 First, check the device is connected 3690 Second, check whether the device path point to a device which support SimpleFileSystemProtocol, 3691 Third, detect the the default boot file in the Media, and return the removable Media handle. 3692 3693 @param DevicePath Device Path to a bootable device 3694 3695 @return The bootable media handle. If the media on the DevicePath is not bootable, NULL will return. 3696 3697**/ 3698EFI_HANDLE 3699EFIAPI 3700BdsLibGetBootableHandle ( 3701 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath 3702 ) 3703{ 3704 EFI_STATUS Status; 3705 EFI_TPL OldTpl; 3706 EFI_DEVICE_PATH_PROTOCOL *UpdatedDevicePath; 3707 EFI_DEVICE_PATH_PROTOCOL *DupDevicePath; 3708 EFI_HANDLE Handle; 3709 EFI_BLOCK_IO_PROTOCOL *BlockIo; 3710 VOID *Buffer; 3711 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; 3712 UINTN Size; 3713 UINTN TempSize; 3714 EFI_HANDLE ReturnHandle; 3715 EFI_HANDLE *SimpleFileSystemHandles; 3716 3717 UINTN NumberSimpleFileSystemHandles; 3718 UINTN Index; 3719 EFI_IMAGE_DOS_HEADER DosHeader; 3720 EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData; 3721 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr; 3722 3723 UpdatedDevicePath = DevicePath; 3724 3725 // 3726 // Enter to critical section to protect the acquired BlockIo instance 3727 // from getting released due to the USB mass storage hotplug event 3728 // 3729 OldTpl = gBS->RaiseTPL (TPL_CALLBACK); 3730 3731 // 3732 // Check whether the device is connected 3733 // 3734 Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &UpdatedDevicePath, &Handle); 3735 if (EFI_ERROR (Status)) { 3736 // 3737 // Skip the case that the boot option point to a simple file protocol which does not consume block Io protocol, 3738 // 3739 Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &UpdatedDevicePath, &Handle); 3740 if (EFI_ERROR (Status)) { 3741 // 3742 // Fail to find the proper BlockIo and simple file protocol, maybe because device not present, we need to connect it firstly 3743 // 3744 UpdatedDevicePath = DevicePath; 3745 Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &UpdatedDevicePath, &Handle); 3746 gBS->ConnectController (Handle, NULL, NULL, TRUE); 3747 } 3748 } else { 3749 // 3750 // For removable device boot option, its contained device path only point to the removable device handle, 3751 // should make sure all its children handles (its child partion or media handles) are created and connected. 3752 // 3753 gBS->ConnectController (Handle, NULL, NULL, TRUE); 3754 // 3755 // Get BlockIo protocol and check removable attribute 3756 // 3757 Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo); 3758 ASSERT_EFI_ERROR (Status); 3759 3760 // 3761 // Issue a dummy read to the device to check for media change. 3762 // When the removable media is changed, any Block IO read/write will 3763 // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is 3764 // returned. After the Block IO protocol is reinstalled, subsequent 3765 // Block IO read/write will success. 3766 // 3767 Buffer = AllocatePool (BlockIo->Media->BlockSize); 3768 if (Buffer != NULL) { 3769 BlockIo->ReadBlocks ( 3770 BlockIo, 3771 BlockIo->Media->MediaId, 3772 0, 3773 BlockIo->Media->BlockSize, 3774 Buffer 3775 ); 3776 FreePool(Buffer); 3777 } 3778 } 3779 3780 // 3781 // Detect the the default boot file from removable Media 3782 // 3783 3784 // 3785 // If fail to get bootable handle specified by a USB boot option, the BDS should try to find other bootable device in the same USB bus 3786 // Try to locate the USB node device path first, if fail then use its previous PCI node to search 3787 // 3788 DupDevicePath = DuplicateDevicePath (DevicePath); 3789 ASSERT (DupDevicePath != NULL); 3790 3791 UpdatedDevicePath = DupDevicePath; 3792 Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &UpdatedDevicePath, &Handle); 3793 // 3794 // if the resulting device path point to a usb node, and the usb node is a dummy node, should only let device path only point to the previous Pci node 3795 // Acpi()/Pci()/Usb() --> Acpi()/Pci() 3796 // 3797 if ((DevicePathType (UpdatedDevicePath) == MESSAGING_DEVICE_PATH) && 3798 (DevicePathSubType (UpdatedDevicePath) == MSG_USB_DP)) { 3799 // 3800 // Remove the usb node, let the device path only point to PCI node 3801 // 3802 SetDevicePathEndNode (UpdatedDevicePath); 3803 UpdatedDevicePath = DupDevicePath; 3804 } else { 3805 UpdatedDevicePath = DevicePath; 3806 } 3807 3808 // 3809 // Get the device path size of boot option 3810 // 3811 Size = GetDevicePathSize(UpdatedDevicePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL); // minus the end node 3812 ReturnHandle = NULL; 3813 gBS->LocateHandleBuffer ( 3814 ByProtocol, 3815 &gEfiSimpleFileSystemProtocolGuid, 3816 NULL, 3817 &NumberSimpleFileSystemHandles, 3818 &SimpleFileSystemHandles 3819 ); 3820 for (Index = 0; Index < NumberSimpleFileSystemHandles; Index++) { 3821 // 3822 // Get the device path size of SimpleFileSystem handle 3823 // 3824 TempDevicePath = DevicePathFromHandle (SimpleFileSystemHandles[Index]); 3825 TempSize = GetDevicePathSize (TempDevicePath)- sizeof (EFI_DEVICE_PATH_PROTOCOL); // minus the end node 3826 // 3827 // Check whether the device path of boot option is part of the SimpleFileSystem handle's device path 3828 // 3829 if (Size <= TempSize && CompareMem (TempDevicePath, UpdatedDevicePath, Size)==0) { 3830 // 3831 // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from removable Media 3832 // machinename is ia32, ia64, x64, ... 3833 // 3834 Hdr.Union = &HdrData; 3835 Status = BdsLibGetImageHeader ( 3836 SimpleFileSystemHandles[Index], 3837 EFI_REMOVABLE_MEDIA_FILE_NAME, 3838 &DosHeader, 3839 Hdr 3840 ); 3841 if (!EFI_ERROR (Status) && 3842 EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Hdr.Pe32->FileHeader.Machine) && 3843 Hdr.Pe32->OptionalHeader.Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) { 3844 ReturnHandle = SimpleFileSystemHandles[Index]; 3845 break; 3846 } 3847 } 3848 } 3849 3850 FreePool(DupDevicePath); 3851 3852 if (SimpleFileSystemHandles != NULL) { 3853 FreePool(SimpleFileSystemHandles); 3854 } 3855 3856 gBS->RestoreTPL (OldTpl); 3857 3858 return ReturnHandle; 3859} 3860 3861/** 3862 Check to see if the network cable is plugged in. If the DevicePath is not 3863 connected it will be connected. 3864 3865 @param DevicePath Device Path to check 3866 3867 @retval TRUE DevicePath points to an Network that is connected 3868 @retval FALSE DevicePath does not point to a bootable network 3869 3870**/ 3871BOOLEAN 3872BdsLibNetworkBootWithMediaPresent ( 3873 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath 3874 ) 3875{ 3876 EFI_STATUS Status; 3877 EFI_DEVICE_PATH_PROTOCOL *UpdatedDevicePath; 3878 EFI_HANDLE Handle; 3879 EFI_SIMPLE_NETWORK_PROTOCOL *Snp; 3880 BOOLEAN MediaPresent; 3881 UINT32 InterruptStatus; 3882 3883 MediaPresent = FALSE; 3884 3885 UpdatedDevicePath = DevicePath; 3886 // 3887 // Locate Load File Protocol for PXE boot option first 3888 // 3889 Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &UpdatedDevicePath, &Handle); 3890 if (EFI_ERROR (Status)) { 3891 // 3892 // Device not present so see if we need to connect it 3893 // 3894 Status = BdsLibConnectDevicePath (DevicePath); 3895 if (!EFI_ERROR (Status)) { 3896 // 3897 // This one should work after we did the connect 3898 // 3899 Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &UpdatedDevicePath, &Handle); 3900 } 3901 } 3902 3903 if (!EFI_ERROR (Status)) { 3904 Status = gBS->HandleProtocol (Handle, &gEfiSimpleNetworkProtocolGuid, (VOID **)&Snp); 3905 if (EFI_ERROR (Status)) { 3906 // 3907 // Failed to open SNP from this handle, try to get SNP from parent handle 3908 // 3909 UpdatedDevicePath = DevicePathFromHandle (Handle); 3910 if (UpdatedDevicePath != NULL) { 3911 Status = gBS->LocateDevicePath (&gEfiSimpleNetworkProtocolGuid, &UpdatedDevicePath, &Handle); 3912 if (!EFI_ERROR (Status)) { 3913 // 3914 // SNP handle found, get SNP from it 3915 // 3916 Status = gBS->HandleProtocol (Handle, &gEfiSimpleNetworkProtocolGuid, (VOID **) &Snp); 3917 } 3918 } 3919 } 3920 3921 if (!EFI_ERROR (Status)) { 3922 if (Snp->Mode->MediaPresentSupported) { 3923 if (Snp->Mode->State == EfiSimpleNetworkInitialized) { 3924 // 3925 // Invoke Snp->GetStatus() to refresh the media status 3926 // 3927 Snp->GetStatus (Snp, &InterruptStatus, NULL); 3928 3929 // 3930 // In case some one else is using the SNP check to see if it's connected 3931 // 3932 MediaPresent = Snp->Mode->MediaPresent; 3933 } else { 3934 // 3935 // No one is using SNP so we need to Start and Initialize so 3936 // MediaPresent will be valid. 3937 // 3938 Status = Snp->Start (Snp); 3939 if (!EFI_ERROR (Status)) { 3940 Status = Snp->Initialize (Snp, 0, 0); 3941 if (!EFI_ERROR (Status)) { 3942 MediaPresent = Snp->Mode->MediaPresent; 3943 Snp->Shutdown (Snp); 3944 } 3945 Snp->Stop (Snp); 3946 } 3947 } 3948 } else { 3949 MediaPresent = TRUE; 3950 } 3951 } 3952 } 3953 3954 return MediaPresent; 3955} 3956 3957/** 3958 For a bootable Device path, return its boot type. 3959 3960 @param DevicePath The bootable device Path to check 3961 3962 @retval BDS_EFI_MEDIA_HD_BOOT If given device path contains MEDIA_DEVICE_PATH type device path node 3963 which subtype is MEDIA_HARDDRIVE_DP 3964 @retval BDS_EFI_MEDIA_CDROM_BOOT If given device path contains MEDIA_DEVICE_PATH type device path node 3965 which subtype is MEDIA_CDROM_DP 3966 @retval BDS_EFI_ACPI_FLOPPY_BOOT If given device path contains ACPI_DEVICE_PATH type device path node 3967 which HID is floppy device. 3968 @retval BDS_EFI_MESSAGE_ATAPI_BOOT If given device path contains MESSAGING_DEVICE_PATH type device path node 3969 and its last device path node's subtype is MSG_ATAPI_DP. 3970 @retval BDS_EFI_MESSAGE_SCSI_BOOT If given device path contains MESSAGING_DEVICE_PATH type device path node 3971 and its last device path node's subtype is MSG_SCSI_DP. 3972 @retval BDS_EFI_MESSAGE_USB_DEVICE_BOOT If given device path contains MESSAGING_DEVICE_PATH type device path node 3973 and its last device path node's subtype is MSG_USB_DP. 3974 @retval BDS_EFI_MESSAGE_MISC_BOOT If the device path not contains any media device path node, and 3975 its last device path node point to a message device path node. 3976 @retval BDS_LEGACY_BBS_BOOT If given device path contains BBS_DEVICE_PATH type device path node. 3977 @retval BDS_EFI_UNSUPPORT An EFI Removable BlockIO device path not point to a media and message device, 3978 3979**/ 3980UINT32 3981EFIAPI 3982BdsGetBootTypeFromDevicePath ( 3983 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath 3984 ) 3985{ 3986 ACPI_HID_DEVICE_PATH *Acpi; 3987 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; 3988 EFI_DEVICE_PATH_PROTOCOL *LastDeviceNode; 3989 UINT32 BootType; 3990 3991 if (NULL == DevicePath) { 3992 return BDS_EFI_UNSUPPORT; 3993 } 3994 3995 TempDevicePath = DevicePath; 3996 3997 while (!IsDevicePathEndType (TempDevicePath)) { 3998 switch (DevicePathType (TempDevicePath)) { 3999 case BBS_DEVICE_PATH: 4000 return BDS_LEGACY_BBS_BOOT; 4001 case MEDIA_DEVICE_PATH: 4002 if (DevicePathSubType (TempDevicePath) == MEDIA_HARDDRIVE_DP) { 4003 return BDS_EFI_MEDIA_HD_BOOT; 4004 } else if (DevicePathSubType (TempDevicePath) == MEDIA_CDROM_DP) { 4005 return BDS_EFI_MEDIA_CDROM_BOOT; 4006 } 4007 break; 4008 case ACPI_DEVICE_PATH: 4009 Acpi = (ACPI_HID_DEVICE_PATH *) TempDevicePath; 4010 if (EISA_ID_TO_NUM (Acpi->HID) == 0x0604) { 4011 return BDS_EFI_ACPI_FLOPPY_BOOT; 4012 } 4013 break; 4014 case MESSAGING_DEVICE_PATH: 4015 // 4016 // Get the last device path node 4017 // 4018 LastDeviceNode = NextDevicePathNode (TempDevicePath); 4019 if (DevicePathSubType(LastDeviceNode) == MSG_DEVICE_LOGICAL_UNIT_DP) { 4020 // 4021 // if the next node type is Device Logical Unit, which specify the Logical Unit Number (LUN), 4022 // skip it 4023 // 4024 LastDeviceNode = NextDevicePathNode (LastDeviceNode); 4025 } 4026 // 4027 // if the device path not only point to driver device, it is not a messaging device path, 4028 // 4029 if (!IsDevicePathEndType (LastDeviceNode)) { 4030 break; 4031 } 4032 4033 switch (DevicePathSubType (TempDevicePath)) { 4034 case MSG_ATAPI_DP: 4035 BootType = BDS_EFI_MESSAGE_ATAPI_BOOT; 4036 break; 4037 4038 case MSG_USB_DP: 4039 BootType = BDS_EFI_MESSAGE_USB_DEVICE_BOOT; 4040 break; 4041 4042 case MSG_SCSI_DP: 4043 BootType = BDS_EFI_MESSAGE_SCSI_BOOT; 4044 break; 4045 4046 case MSG_SATA_DP: 4047 BootType = BDS_EFI_MESSAGE_SATA_BOOT; 4048 break; 4049 4050 case MSG_MAC_ADDR_DP: 4051 case MSG_VLAN_DP: 4052 case MSG_IPv4_DP: 4053 case MSG_IPv6_DP: 4054 BootType = BDS_EFI_MESSAGE_MAC_BOOT; 4055 break; 4056 4057 default: 4058 BootType = BDS_EFI_MESSAGE_MISC_BOOT; 4059 break; 4060 } 4061 return BootType; 4062 4063 default: 4064 break; 4065 } 4066 TempDevicePath = NextDevicePathNode (TempDevicePath); 4067 } 4068 4069 return BDS_EFI_UNSUPPORT; 4070} 4071 4072/** 4073 Check whether the Device path in a boot option point to a valid bootable device, 4074 And if CheckMedia is true, check the device is ready to boot now. 4075 4076 @param DevPath the Device path in a boot option 4077 @param CheckMedia if true, check the device is ready to boot now. 4078 4079 @retval TRUE the Device path is valid 4080 @retval FALSE the Device path is invalid . 4081 4082**/ 4083BOOLEAN 4084EFIAPI 4085BdsLibIsValidEFIBootOptDevicePath ( 4086 IN EFI_DEVICE_PATH_PROTOCOL *DevPath, 4087 IN BOOLEAN CheckMedia 4088 ) 4089{ 4090 return BdsLibIsValidEFIBootOptDevicePathExt (DevPath, CheckMedia, NULL); 4091} 4092 4093/** 4094 Check whether the Device path in a boot option point to a valid bootable device, 4095 And if CheckMedia is true, check the device is ready to boot now. 4096 If Description is not NULL and the device path point to a fixed BlockIo 4097 device, check the description whether conflict with other auto-created 4098 boot options. 4099 4100 @param DevPath the Device path in a boot option 4101 @param CheckMedia if true, check the device is ready to boot now. 4102 @param Description the description in a boot option 4103 4104 @retval TRUE the Device path is valid 4105 @retval FALSE the Device path is invalid . 4106 4107**/ 4108BOOLEAN 4109EFIAPI 4110BdsLibIsValidEFIBootOptDevicePathExt ( 4111 IN EFI_DEVICE_PATH_PROTOCOL *DevPath, 4112 IN BOOLEAN CheckMedia, 4113 IN CHAR16 *Description 4114 ) 4115{ 4116 EFI_STATUS Status; 4117 EFI_HANDLE Handle; 4118 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; 4119 EFI_DEVICE_PATH_PROTOCOL *LastDeviceNode; 4120 EFI_BLOCK_IO_PROTOCOL *BlockIo; 4121 4122 TempDevicePath = DevPath; 4123 LastDeviceNode = DevPath; 4124 4125 // 4126 // Check if it's a valid boot option for network boot device. 4127 // Check if there is EfiLoadFileProtocol installed. 4128 // If yes, that means there is a boot option for network. 4129 // 4130 Status = gBS->LocateDevicePath ( 4131 &gEfiLoadFileProtocolGuid, 4132 &TempDevicePath, 4133 &Handle 4134 ); 4135 if (EFI_ERROR (Status)) { 4136 // 4137 // Device not present so see if we need to connect it 4138 // 4139 TempDevicePath = DevPath; 4140 BdsLibConnectDevicePath (TempDevicePath); 4141 Status = gBS->LocateDevicePath ( 4142 &gEfiLoadFileProtocolGuid, 4143 &TempDevicePath, 4144 &Handle 4145 ); 4146 } 4147 4148 if (!EFI_ERROR (Status)) { 4149 if (!IsDevicePathEnd (TempDevicePath)) { 4150 // 4151 // LoadFile protocol is not installed on handle with exactly the same DevPath 4152 // 4153 return FALSE; 4154 } 4155 4156 if (CheckMedia) { 4157 // 4158 // Test if it is ready to boot now 4159 // 4160 if (BdsLibNetworkBootWithMediaPresent(DevPath)) { 4161 return TRUE; 4162 } 4163 } else { 4164 return TRUE; 4165 } 4166 } 4167 4168 // 4169 // If the boot option point to a file, it is a valid EFI boot option, 4170 // and assume it is ready to boot now 4171 // 4172 while (!IsDevicePathEnd (TempDevicePath)) { 4173 // 4174 // If there is USB Class or USB WWID device path node, treat it as valid EFI 4175 // Boot Option. BdsExpandUsbShortFormDevicePath () will be used to expand it 4176 // to full device path. 4177 // 4178 if ((DevicePathType (TempDevicePath) == MESSAGING_DEVICE_PATH) && 4179 ((DevicePathSubType (TempDevicePath) == MSG_USB_CLASS_DP) || 4180 (DevicePathSubType (TempDevicePath) == MSG_USB_WWID_DP))) { 4181 return TRUE; 4182 } 4183 4184 LastDeviceNode = TempDevicePath; 4185 TempDevicePath = NextDevicePathNode (TempDevicePath); 4186 } 4187 if ((DevicePathType (LastDeviceNode) == MEDIA_DEVICE_PATH) && 4188 (DevicePathSubType (LastDeviceNode) == MEDIA_FILEPATH_DP)) { 4189 return TRUE; 4190 } 4191 4192 // 4193 // Check if it's a valid boot option for internal FV application 4194 // 4195 if (EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LastDeviceNode) != NULL) { 4196 // 4197 // If the boot option point to internal FV application, make sure it is valid 4198 // 4199 TempDevicePath = DevPath; 4200 Status = BdsLibUpdateFvFileDevicePath ( 4201 &TempDevicePath, 4202 EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LastDeviceNode) 4203 ); 4204 if (Status == EFI_ALREADY_STARTED) { 4205 return TRUE; 4206 } else { 4207 if (Status == EFI_SUCCESS) { 4208 FreePool (TempDevicePath); 4209 } 4210 return FALSE; 4211 } 4212 } 4213 4214 // 4215 // If the boot option point to a blockIO device: 4216 // if it is a removable blockIo device, it is valid. 4217 // if it is a fixed blockIo device, check its description confliction. 4218 // 4219 TempDevicePath = DevPath; 4220 Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, &Handle); 4221 if (EFI_ERROR (Status)) { 4222 // 4223 // Device not present so see if we need to connect it 4224 // 4225 Status = BdsLibConnectDevicePath (DevPath); 4226 if (!EFI_ERROR (Status)) { 4227 // 4228 // Try again to get the Block Io protocol after we did the connect 4229 // 4230 TempDevicePath = DevPath; 4231 Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, &Handle); 4232 } 4233 } 4234 4235 if (!EFI_ERROR (Status)) { 4236 Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo); 4237 if (!EFI_ERROR (Status)) { 4238 if (CheckMedia) { 4239 // 4240 // Test if it is ready to boot now 4241 // 4242 if (BdsLibGetBootableHandle (DevPath) != NULL) { 4243 return TRUE; 4244 } 4245 } else { 4246 return TRUE; 4247 } 4248 } 4249 } else { 4250 // 4251 // if the boot option point to a simple file protocol which does not consume block Io protocol, it is also a valid EFI boot option, 4252 // 4253 Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &TempDevicePath, &Handle); 4254 if (!EFI_ERROR (Status)) { 4255 if (CheckMedia) { 4256 // 4257 // Test if it is ready to boot now 4258 // 4259 if (BdsLibGetBootableHandle (DevPath) != NULL) { 4260 return TRUE; 4261 } 4262 } else { 4263 return TRUE; 4264 } 4265 } 4266 } 4267 4268 return FALSE; 4269} 4270 4271 4272/** 4273 According to a file guild, check a Fv file device path is valid. If it is invalid, 4274 try to return the valid device path. 4275 FV address maybe changes for memory layout adjust from time to time, use this function 4276 could promise the Fv file device path is right. 4277 4278 @param DevicePath on input, the Fv file device path need to check on 4279 output, the updated valid Fv file device path 4280 @param FileGuid the Fv file guild 4281 4282 @retval EFI_INVALID_PARAMETER the input DevicePath or FileGuid is invalid 4283 parameter 4284 @retval EFI_UNSUPPORTED the input DevicePath does not contain Fv file 4285 guild at all 4286 @retval EFI_ALREADY_STARTED the input DevicePath has pointed to Fv file, it is 4287 valid 4288 @retval EFI_SUCCESS has successfully updated the invalid DevicePath, 4289 and return the updated device path in DevicePath 4290 4291**/ 4292EFI_STATUS 4293EFIAPI 4294BdsLibUpdateFvFileDevicePath ( 4295 IN OUT EFI_DEVICE_PATH_PROTOCOL ** DevicePath, 4296 IN EFI_GUID *FileGuid 4297 ) 4298{ 4299 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; 4300 EFI_DEVICE_PATH_PROTOCOL *LastDeviceNode; 4301 EFI_STATUS Status; 4302 EFI_GUID *GuidPoint; 4303 UINTN Index; 4304 UINTN FvHandleCount; 4305 EFI_HANDLE *FvHandleBuffer; 4306 EFI_FV_FILETYPE Type; 4307 UINTN Size; 4308 EFI_FV_FILE_ATTRIBUTES Attributes; 4309 UINT32 AuthenticationStatus; 4310 BOOLEAN FindFvFile; 4311 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; 4312 EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv; 4313 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FvFileNode; 4314 EFI_HANDLE FoundFvHandle; 4315 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath; 4316 4317 if ((DevicePath == NULL) || (*DevicePath == NULL)) { 4318 return EFI_INVALID_PARAMETER; 4319 } 4320 if (FileGuid == NULL) { 4321 return EFI_INVALID_PARAMETER; 4322 } 4323 4324 // 4325 // Check whether the device path point to the default the input Fv file 4326 // 4327 TempDevicePath = *DevicePath; 4328 LastDeviceNode = TempDevicePath; 4329 while (!IsDevicePathEnd (TempDevicePath)) { 4330 LastDeviceNode = TempDevicePath; 4331 TempDevicePath = NextDevicePathNode (TempDevicePath); 4332 } 4333 GuidPoint = EfiGetNameGuidFromFwVolDevicePathNode ( 4334 (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LastDeviceNode 4335 ); 4336 if (GuidPoint == NULL) { 4337 // 4338 // if this option does not points to a Fv file, just return EFI_UNSUPPORTED 4339 // 4340 return EFI_UNSUPPORTED; 4341 } 4342 if (!CompareGuid (GuidPoint, FileGuid)) { 4343 // 4344 // If the Fv file is not the input file guid, just return EFI_UNSUPPORTED 4345 // 4346 return EFI_UNSUPPORTED; 4347 } 4348 4349 // 4350 // Check whether the input Fv file device path is valid 4351 // 4352 TempDevicePath = *DevicePath; 4353 FoundFvHandle = NULL; 4354 Status = gBS->LocateDevicePath ( 4355 &gEfiFirmwareVolume2ProtocolGuid, 4356 &TempDevicePath, 4357 &FoundFvHandle 4358 ); 4359 if (!EFI_ERROR (Status)) { 4360 Status = gBS->HandleProtocol ( 4361 FoundFvHandle, 4362 &gEfiFirmwareVolume2ProtocolGuid, 4363 (VOID **) &Fv 4364 ); 4365 if (!EFI_ERROR (Status)) { 4366 // 4367 // Set FV ReadFile Buffer as NULL, only need to check whether input Fv file exist there 4368 // 4369 Status = Fv->ReadFile ( 4370 Fv, 4371 FileGuid, 4372 NULL, 4373 &Size, 4374 &Type, 4375 &Attributes, 4376 &AuthenticationStatus 4377 ); 4378 if (!EFI_ERROR (Status)) { 4379 return EFI_ALREADY_STARTED; 4380 } 4381 } 4382 } 4383 4384 // 4385 // Look for the input wanted FV file in current FV 4386 // First, try to look for in Bds own FV. Bds and input wanted FV file usually are in the same FV 4387 // 4388 FindFvFile = FALSE; 4389 FoundFvHandle = NULL; 4390 Status = gBS->HandleProtocol ( 4391 gImageHandle, 4392 &gEfiLoadedImageProtocolGuid, 4393 (VOID **) &LoadedImage 4394 ); 4395 if (!EFI_ERROR (Status)) { 4396 Status = gBS->HandleProtocol ( 4397 LoadedImage->DeviceHandle, 4398 &gEfiFirmwareVolume2ProtocolGuid, 4399 (VOID **) &Fv 4400 ); 4401 if (!EFI_ERROR (Status)) { 4402 Status = Fv->ReadFile ( 4403 Fv, 4404 FileGuid, 4405 NULL, 4406 &Size, 4407 &Type, 4408 &Attributes, 4409 &AuthenticationStatus 4410 ); 4411 if (!EFI_ERROR (Status)) { 4412 FindFvFile = TRUE; 4413 FoundFvHandle = LoadedImage->DeviceHandle; 4414 } 4415 } 4416 } 4417 // 4418 // Second, if fail to find, try to enumerate all FV 4419 // 4420 if (!FindFvFile) { 4421 FvHandleBuffer = NULL; 4422 gBS->LocateHandleBuffer ( 4423 ByProtocol, 4424 &gEfiFirmwareVolume2ProtocolGuid, 4425 NULL, 4426 &FvHandleCount, 4427 &FvHandleBuffer 4428 ); 4429 for (Index = 0; Index < FvHandleCount; Index++) { 4430 gBS->HandleProtocol ( 4431 FvHandleBuffer[Index], 4432 &gEfiFirmwareVolume2ProtocolGuid, 4433 (VOID **) &Fv 4434 ); 4435 4436 Status = Fv->ReadFile ( 4437 Fv, 4438 FileGuid, 4439 NULL, 4440 &Size, 4441 &Type, 4442 &Attributes, 4443 &AuthenticationStatus 4444 ); 4445 if (EFI_ERROR (Status)) { 4446 // 4447 // Skip if input Fv file not in the FV 4448 // 4449 continue; 4450 } 4451 FindFvFile = TRUE; 4452 FoundFvHandle = FvHandleBuffer[Index]; 4453 break; 4454 } 4455 4456 if (FvHandleBuffer != NULL) { 4457 FreePool (FvHandleBuffer); 4458 } 4459 } 4460 4461 if (FindFvFile) { 4462 // 4463 // Build the shell device path 4464 // 4465 NewDevicePath = DevicePathFromHandle (FoundFvHandle); 4466 EfiInitializeFwVolDevicepathNode (&FvFileNode, FileGuid); 4467 NewDevicePath = AppendDevicePathNode (NewDevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &FvFileNode); 4468 ASSERT (NewDevicePath != NULL); 4469 *DevicePath = NewDevicePath; 4470 return EFI_SUCCESS; 4471 } 4472 return EFI_NOT_FOUND; 4473} 4474