BmBoot.c revision ebf735f11907e31e1fa80f21737d277d8a964e17
1/** @file 2 Library functions which relates with booting. 3 4Copyright (c) 2011 - 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 "InternalBm.h" 16 17#define VENDOR_IDENTIFICATION_OFFSET 3 18#define VENDOR_IDENTIFICATION_LENGTH 8 19#define PRODUCT_IDENTIFICATION_OFFSET 11 20#define PRODUCT_IDENTIFICATION_LENGTH 16 21 22CONST UINT16 mBmUsbLangId = 0x0409; // English 23CHAR16 mBmUefiPrefix[] = L"UEFI "; 24 25EFI_BOOT_MANAGER_REFRESH_LEGACY_BOOT_OPTION mBmRefreshLegacyBootOption = NULL; 26EFI_BOOT_MANAGER_LEGACY_BOOT mBmLegacyBoot = NULL; 27 28LIST_ENTRY mPlatformBootDescriptionHandlers = INITIALIZE_LIST_HEAD_VARIABLE (mPlatformBootDescriptionHandlers); 29 30/// 31/// This GUID is used for an EFI Variable that stores the front device pathes 32/// for a partial device path that starts with the HD node. 33/// 34EFI_GUID mBmHardDriveBootVariableGuid = { 0xfab7e9e1, 0x39dd, 0x4f2b, { 0x84, 0x08, 0xe2, 0x0e, 0x90, 0x6c, 0xb6, 0xde } }; 35EFI_GUID mBmAutoCreateBootOptionGuid = { 0x8108ac4e, 0x9f11, 0x4d59, { 0x85, 0x0e, 0xe2, 0x1a, 0x52, 0x2c, 0x59, 0xb2 } }; 36 37/** 38 The function registers the legacy boot support capabilities. 39 40 @param RefreshLegacyBootOption The function pointer to create all the legacy boot options. 41 @param LegacyBoot The function pointer to boot the legacy boot option. 42**/ 43VOID 44EFIAPI 45EfiBootManagerRegisterLegacyBootSupport ( 46 EFI_BOOT_MANAGER_REFRESH_LEGACY_BOOT_OPTION RefreshLegacyBootOption, 47 EFI_BOOT_MANAGER_LEGACY_BOOT LegacyBoot 48 ) 49{ 50 mBmRefreshLegacyBootOption = RefreshLegacyBootOption; 51 mBmLegacyBoot = LegacyBoot; 52} 53 54/** 55 For a bootable Device path, return its boot type. 56 57 @param DevicePath The bootable device Path to check 58 59 @retval AcpiFloppyBoot If given device path contains ACPI_DEVICE_PATH type device path node 60 which HID is floppy device. 61 @retval MessageAtapiBoot If given device path contains MESSAGING_DEVICE_PATH type device path node 62 and its last device path node's subtype is MSG_ATAPI_DP. 63 @retval MessageSataBoot If given device path contains MESSAGING_DEVICE_PATH type device path node 64 and its last device path node's subtype is MSG_SATA_DP. 65 @retval MessageScsiBoot If given device path contains MESSAGING_DEVICE_PATH type device path node 66 and its last device path node's subtype is MSG_SCSI_DP. 67 @retval MessageUsbBoot If given device path contains MESSAGING_DEVICE_PATH type device path node 68 and its last device path node's subtype is MSG_USB_DP. 69 @retval MessageNetworkBoot If given device path contains MESSAGING_DEVICE_PATH type device path node 70 and its last device path node's subtype is MSG_MAC_ADDR_DP, MSG_VLAN_DP, 71 MSG_IPv4_DP or MSG_IPv6_DP. 72 @retval MessageHttpBoot If given device path contains MESSAGING_DEVICE_PATH type device path node 73 and its last device path node's subtype is MSG_URI_DP. 74 @retval UnsupportedBoot If tiven device path doesn't match the above condition, it's not supported. 75 76**/ 77BM_BOOT_TYPE 78BmDevicePathType ( 79 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath 80 ) 81{ 82 EFI_DEVICE_PATH_PROTOCOL *Node; 83 EFI_DEVICE_PATH_PROTOCOL *NextNode; 84 85 ASSERT (DevicePath != NULL); 86 87 for (Node = DevicePath; !IsDevicePathEndType (Node); Node = NextDevicePathNode (Node)) { 88 switch (DevicePathType (Node)) { 89 90 case ACPI_DEVICE_PATH: 91 if (EISA_ID_TO_NUM (((ACPI_HID_DEVICE_PATH *) Node)->HID) == 0x0604) { 92 return BmAcpiFloppyBoot; 93 } 94 break; 95 96 case HARDWARE_DEVICE_PATH: 97 if (DevicePathSubType (Node) == HW_CONTROLLER_DP) { 98 return BmHardwareDeviceBoot; 99 } 100 break; 101 102 case MESSAGING_DEVICE_PATH: 103 // 104 // Skip LUN device node 105 // 106 NextNode = Node; 107 do { 108 NextNode = NextDevicePathNode (NextNode); 109 } while ( 110 (DevicePathType (NextNode) == MESSAGING_DEVICE_PATH) && 111 (DevicePathSubType(NextNode) == MSG_DEVICE_LOGICAL_UNIT_DP) 112 ); 113 114 // 115 // If the device path not only point to driver device, it is not a messaging device path, 116 // 117 if (!IsDevicePathEndType (NextNode)) { 118 continue; 119 } 120 121 switch (DevicePathSubType (Node)) { 122 case MSG_ATAPI_DP: 123 return BmMessageAtapiBoot; 124 break; 125 126 case MSG_SATA_DP: 127 return BmMessageSataBoot; 128 break; 129 130 case MSG_USB_DP: 131 return BmMessageUsbBoot; 132 break; 133 134 case MSG_SCSI_DP: 135 return BmMessageScsiBoot; 136 break; 137 138 case MSG_MAC_ADDR_DP: 139 case MSG_VLAN_DP: 140 case MSG_IPv4_DP: 141 case MSG_IPv6_DP: 142 return BmMessageNetworkBoot; 143 break; 144 145 case MSG_URI_DP: 146 return BmMessageHttpBoot; 147 break; 148 } 149 } 150 } 151 152 return BmMiscBoot; 153} 154 155/** 156 Find the boot option in the NV storage and return the option number. 157 158 @param OptionToFind Boot option to be checked. 159 160 @return The option number of the found boot option. 161 162**/ 163UINTN 164BmFindBootOptionInVariable ( 165 IN EFI_BOOT_MANAGER_LOAD_OPTION *OptionToFind 166 ) 167{ 168 EFI_STATUS Status; 169 EFI_BOOT_MANAGER_LOAD_OPTION BootOption; 170 UINTN OptionNumber; 171 CHAR16 OptionName[BM_OPTION_NAME_LEN]; 172 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions; 173 UINTN BootOptionCount; 174 UINTN Index; 175 176 OptionNumber = LoadOptionNumberUnassigned; 177 178 // 179 // Try to match the variable exactly if the option number is assigned 180 // 181 if (OptionToFind->OptionNumber != LoadOptionNumberUnassigned) { 182 UnicodeSPrint ( 183 OptionName, sizeof (OptionName), L"%s%04x", 184 mBmLoadOptionName[OptionToFind->OptionType], OptionToFind->OptionNumber 185 ); 186 Status = EfiBootManagerVariableToLoadOption (OptionName, &BootOption); 187 188 if (!EFI_ERROR (Status)) { 189 ASSERT (OptionToFind->OptionNumber == BootOption.OptionNumber); 190 if ((OptionToFind->Attributes == BootOption.Attributes) && 191 (StrCmp (OptionToFind->Description, BootOption.Description) == 0) && 192 (CompareMem (OptionToFind->FilePath, BootOption.FilePath, GetDevicePathSize (OptionToFind->FilePath)) == 0) && 193 (OptionToFind->OptionalDataSize == BootOption.OptionalDataSize) && 194 (CompareMem (OptionToFind->OptionalData, BootOption.OptionalData, OptionToFind->OptionalDataSize) == 0) 195 ) { 196 OptionNumber = OptionToFind->OptionNumber; 197 } 198 EfiBootManagerFreeLoadOption (&BootOption); 199 } 200 } 201 202 // 203 // The option number assigned is either incorrect or unassigned. 204 // 205 if (OptionNumber == LoadOptionNumberUnassigned) { 206 BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot); 207 208 Index = BmFindLoadOption (OptionToFind, BootOptions, BootOptionCount); 209 if (Index != -1) { 210 OptionNumber = BootOptions[Index].OptionNumber; 211 } 212 213 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount); 214 } 215 216 return OptionNumber; 217} 218 219/** 220 Get the file buffer using a Memory Mapped Device Path. 221 222 FV address may change across reboot. This routine promises the FV file device path is right. 223 224 @param DevicePath The Memory Mapped Device Path to get the file buffer. 225 @param FullPath Receive the updated FV Device Path pointint to the file. 226 @param FileSize Receive the file buffer size. 227 228 @return The file buffer. 229**/ 230VOID * 231BmGetFileBufferByMemmapFv ( 232 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, 233 OUT EFI_DEVICE_PATH_PROTOCOL **FullPath, 234 OUT UINTN *FileSize 235 ) 236{ 237 EFI_STATUS Status; 238 UINTN Index; 239 EFI_DEVICE_PATH_PROTOCOL *FvFileNode; 240 EFI_HANDLE FvHandle; 241 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; 242 UINT32 AuthenticationStatus; 243 UINTN FvHandleCount; 244 EFI_HANDLE *FvHandles; 245 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath; 246 VOID *FileBuffer; 247 248 FvFileNode = DevicePath; 249 Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &FvFileNode, &FvHandle); 250 if (!EFI_ERROR (Status)) { 251 FileBuffer = GetFileBufferByFilePath (TRUE, DevicePath, FileSize, &AuthenticationStatus); 252 if (FileBuffer != NULL) { 253 *FullPath = DuplicateDevicePath (DevicePath); 254 } 255 return FileBuffer; 256 } 257 258 FvFileNode = NextDevicePathNode (DevicePath); 259 260 // 261 // Firstly find the FV file in current FV 262 // 263 gBS->HandleProtocol ( 264 gImageHandle, 265 &gEfiLoadedImageProtocolGuid, 266 (VOID **) &LoadedImage 267 ); 268 NewDevicePath = AppendDevicePathNode (DevicePathFromHandle (LoadedImage->DeviceHandle), FvFileNode); 269 FileBuffer = BmGetFileBufferByMemmapFv (NewDevicePath, FullPath, FileSize); 270 FreePool (NewDevicePath); 271 272 if (FileBuffer != NULL) { 273 return FileBuffer; 274 } 275 276 // 277 // Secondly find the FV file in all other FVs 278 // 279 gBS->LocateHandleBuffer ( 280 ByProtocol, 281 &gEfiFirmwareVolume2ProtocolGuid, 282 NULL, 283 &FvHandleCount, 284 &FvHandles 285 ); 286 for (Index = 0; (Index < FvHandleCount) && (FileBuffer == NULL); Index++) { 287 if (FvHandles[Index] == LoadedImage->DeviceHandle) { 288 // 289 // Skip current FV 290 // 291 continue; 292 } 293 NewDevicePath = AppendDevicePathNode (DevicePathFromHandle (FvHandles[Index]), FvFileNode); 294 FileBuffer = BmGetFileBufferByMemmapFv (NewDevicePath, FullPath, FileSize); 295 FreePool (NewDevicePath); 296 } 297 298 if (FvHandles != NULL) { 299 FreePool (FvHandles); 300 } 301 return FileBuffer; 302} 303 304/** 305 Check if it's a Memory Mapped FV Device Path. 306 307 The function doesn't garentee the device path points to existing FV file. 308 309 @param DevicePath Input device path. 310 311 @retval TRUE The device path is a Memory Mapped FV Device Path. 312 @retval FALSE The device path is NOT a Memory Mapped FV Device Path. 313**/ 314BOOLEAN 315BmIsMemmapFvFilePath ( 316 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath 317 ) 318{ 319 EFI_DEVICE_PATH_PROTOCOL *FileNode; 320 321 if ((DevicePathType (DevicePath) == HARDWARE_DEVICE_PATH) && (DevicePathSubType (DevicePath) == HW_MEMMAP_DP)) { 322 FileNode = NextDevicePathNode (DevicePath); 323 if ((DevicePathType (FileNode) == MEDIA_DEVICE_PATH) && (DevicePathSubType (FileNode) == MEDIA_PIWG_FW_FILE_DP)) { 324 return IsDevicePathEnd (NextDevicePathNode (FileNode)); 325 } 326 } 327 328 return FALSE; 329} 330 331/** 332 Check whether a USB device match the specified USB Class device path. This 333 function follows "Load Option Processing" behavior in UEFI specification. 334 335 @param UsbIo USB I/O protocol associated with the USB device. 336 @param UsbClass The USB Class device path to match. 337 338 @retval TRUE The USB device match the USB Class device path. 339 @retval FALSE The USB device does not match the USB Class device path. 340 341**/ 342BOOLEAN 343BmMatchUsbClass ( 344 IN EFI_USB_IO_PROTOCOL *UsbIo, 345 IN USB_CLASS_DEVICE_PATH *UsbClass 346 ) 347{ 348 EFI_STATUS Status; 349 EFI_USB_DEVICE_DESCRIPTOR DevDesc; 350 EFI_USB_INTERFACE_DESCRIPTOR IfDesc; 351 UINT8 DeviceClass; 352 UINT8 DeviceSubClass; 353 UINT8 DeviceProtocol; 354 355 if ((DevicePathType (UsbClass) != MESSAGING_DEVICE_PATH) || 356 (DevicePathSubType (UsbClass) != MSG_USB_CLASS_DP)){ 357 return FALSE; 358 } 359 360 // 361 // Check Vendor Id and Product Id. 362 // 363 Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc); 364 if (EFI_ERROR (Status)) { 365 return FALSE; 366 } 367 368 if ((UsbClass->VendorId != 0xffff) && 369 (UsbClass->VendorId != DevDesc.IdVendor)) { 370 return FALSE; 371 } 372 373 if ((UsbClass->ProductId != 0xffff) && 374 (UsbClass->ProductId != DevDesc.IdProduct)) { 375 return FALSE; 376 } 377 378 DeviceClass = DevDesc.DeviceClass; 379 DeviceSubClass = DevDesc.DeviceSubClass; 380 DeviceProtocol = DevDesc.DeviceProtocol; 381 if (DeviceClass == 0) { 382 // 383 // If Class in Device Descriptor is set to 0, use the Class, SubClass and 384 // Protocol in Interface Descriptor instead. 385 // 386 Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &IfDesc); 387 if (EFI_ERROR (Status)) { 388 return FALSE; 389 } 390 391 DeviceClass = IfDesc.InterfaceClass; 392 DeviceSubClass = IfDesc.InterfaceSubClass; 393 DeviceProtocol = IfDesc.InterfaceProtocol; 394 } 395 396 // 397 // Check Class, SubClass and Protocol. 398 // 399 if ((UsbClass->DeviceClass != 0xff) && 400 (UsbClass->DeviceClass != DeviceClass)) { 401 return FALSE; 402 } 403 404 if ((UsbClass->DeviceSubClass != 0xff) && 405 (UsbClass->DeviceSubClass != DeviceSubClass)) { 406 return FALSE; 407 } 408 409 if ((UsbClass->DeviceProtocol != 0xff) && 410 (UsbClass->DeviceProtocol != DeviceProtocol)) { 411 return FALSE; 412 } 413 414 return TRUE; 415} 416 417/** 418 Eliminate the extra spaces in the Str to one space. 419 420 @param Str Input string info. 421**/ 422VOID 423BmEliminateExtraSpaces ( 424 IN CHAR16 *Str 425 ) 426{ 427 UINTN Index; 428 UINTN ActualIndex; 429 430 for (Index = 0, ActualIndex = 0; Str[Index] != L'\0'; Index++) { 431 if ((Str[Index] != L' ') || ((ActualIndex > 0) && (Str[ActualIndex - 1] != L' '))) { 432 Str[ActualIndex++] = Str[Index]; 433 } 434 } 435 Str[ActualIndex] = L'\0'; 436} 437 438/** 439 Try to get the controller's ATA/ATAPI description. 440 441 @param Handle Controller handle. 442 443 @return The description string. 444**/ 445CHAR16 * 446BmGetDescriptionFromDiskInfo ( 447 IN EFI_HANDLE Handle 448 ) 449{ 450 UINTN Index; 451 EFI_STATUS Status; 452 EFI_DISK_INFO_PROTOCOL *DiskInfo; 453 UINT32 BufferSize; 454 EFI_ATAPI_IDENTIFY_DATA IdentifyData; 455 EFI_SCSI_INQUIRY_DATA InquiryData; 456 CHAR16 *Description; 457 UINTN Length; 458 CONST UINTN ModelNameLength = 40; 459 CONST UINTN SerialNumberLength = 20; 460 CHAR8 *StrPtr; 461 UINT8 Temp; 462 463 Description = NULL; 464 465 Status = gBS->HandleProtocol ( 466 Handle, 467 &gEfiDiskInfoProtocolGuid, 468 (VOID **) &DiskInfo 469 ); 470 if (EFI_ERROR (Status)) { 471 return NULL; 472 } 473 474 if (CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoAhciInterfaceGuid) || 475 CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoIdeInterfaceGuid)) { 476 BufferSize = sizeof (EFI_ATAPI_IDENTIFY_DATA); 477 Status = DiskInfo->Identify ( 478 DiskInfo, 479 &IdentifyData, 480 &BufferSize 481 ); 482 if (!EFI_ERROR (Status)) { 483 Description = AllocateZeroPool ((ModelNameLength + SerialNumberLength + 2) * sizeof (CHAR16)); 484 ASSERT (Description != NULL); 485 for (Index = 0; Index + 1 < ModelNameLength; Index += 2) { 486 Description[Index] = (CHAR16) IdentifyData.ModelName[Index + 1]; 487 Description[Index + 1] = (CHAR16) IdentifyData.ModelName[Index]; 488 } 489 490 Length = Index; 491 Description[Length++] = L' '; 492 493 for (Index = 0; Index + 1 < SerialNumberLength; Index += 2) { 494 Description[Length + Index] = (CHAR16) IdentifyData.SerialNo[Index + 1]; 495 Description[Length + Index + 1] = (CHAR16) IdentifyData.SerialNo[Index]; 496 } 497 Length += Index; 498 Description[Length++] = L'\0'; 499 ASSERT (Length == ModelNameLength + SerialNumberLength + 2); 500 501 BmEliminateExtraSpaces (Description); 502 } 503 } else if (CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoScsiInterfaceGuid)) { 504 BufferSize = sizeof (EFI_SCSI_INQUIRY_DATA); 505 Status = DiskInfo->Inquiry ( 506 DiskInfo, 507 &InquiryData, 508 &BufferSize 509 ); 510 if (!EFI_ERROR (Status)) { 511 Description = AllocateZeroPool ((VENDOR_IDENTIFICATION_LENGTH + PRODUCT_IDENTIFICATION_LENGTH + 2) * sizeof (CHAR16)); 512 ASSERT (Description != NULL); 513 514 // 515 // Per SCSI spec, EFI_SCSI_INQUIRY_DATA.Reserved_5_95[3 - 10] save the Verdor identification 516 // EFI_SCSI_INQUIRY_DATA.Reserved_5_95[11 - 26] save the product identification, 517 // Here combine the vendor identification and product identification to the description. 518 // 519 StrPtr = (CHAR8 *) (&InquiryData.Reserved_5_95[VENDOR_IDENTIFICATION_OFFSET]); 520 Temp = StrPtr[VENDOR_IDENTIFICATION_LENGTH]; 521 StrPtr[VENDOR_IDENTIFICATION_LENGTH] = '\0'; 522 AsciiStrToUnicodeStr (StrPtr, Description); 523 StrPtr[VENDOR_IDENTIFICATION_LENGTH] = Temp; 524 525 // 526 // Add one space at the middle of vendor information and product information. 527 // 528 Description[VENDOR_IDENTIFICATION_LENGTH] = L' '; 529 530 StrPtr = (CHAR8 *) (&InquiryData.Reserved_5_95[PRODUCT_IDENTIFICATION_OFFSET]); 531 StrPtr[PRODUCT_IDENTIFICATION_LENGTH] = '\0'; 532 AsciiStrToUnicodeStr (StrPtr, Description + VENDOR_IDENTIFICATION_LENGTH + 1); 533 534 BmEliminateExtraSpaces (Description); 535 } 536 } 537 538 return Description; 539} 540 541/** 542 Try to get the controller's USB description. 543 544 @param Handle Controller handle. 545 546 @return The description string. 547**/ 548CHAR16 * 549BmGetUsbDescription ( 550 IN EFI_HANDLE Handle 551 ) 552{ 553 EFI_STATUS Status; 554 EFI_USB_IO_PROTOCOL *UsbIo; 555 CHAR16 NullChar; 556 CHAR16 *Manufacturer; 557 CHAR16 *Product; 558 CHAR16 *SerialNumber; 559 CHAR16 *Description; 560 EFI_USB_DEVICE_DESCRIPTOR DevDesc; 561 UINTN DescMaxSize; 562 563 Status = gBS->HandleProtocol ( 564 Handle, 565 &gEfiUsbIoProtocolGuid, 566 (VOID **) &UsbIo 567 ); 568 if (EFI_ERROR (Status)) { 569 return NULL; 570 } 571 572 NullChar = L'\0'; 573 574 Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc); 575 if (EFI_ERROR (Status)) { 576 return NULL; 577 } 578 579 Status = UsbIo->UsbGetStringDescriptor ( 580 UsbIo, 581 mBmUsbLangId, 582 DevDesc.StrManufacturer, 583 &Manufacturer 584 ); 585 if (EFI_ERROR (Status)) { 586 Manufacturer = &NullChar; 587 } 588 589 Status = UsbIo->UsbGetStringDescriptor ( 590 UsbIo, 591 mBmUsbLangId, 592 DevDesc.StrProduct, 593 &Product 594 ); 595 if (EFI_ERROR (Status)) { 596 Product = &NullChar; 597 } 598 599 Status = UsbIo->UsbGetStringDescriptor ( 600 UsbIo, 601 mBmUsbLangId, 602 DevDesc.StrSerialNumber, 603 &SerialNumber 604 ); 605 if (EFI_ERROR (Status)) { 606 SerialNumber = &NullChar; 607 } 608 609 if ((Manufacturer == &NullChar) && 610 (Product == &NullChar) && 611 (SerialNumber == &NullChar) 612 ) { 613 return NULL; 614 } 615 616 DescMaxSize = StrSize (Manufacturer) + StrSize (Product) + StrSize (SerialNumber); 617 Description = AllocateZeroPool (DescMaxSize); 618 ASSERT (Description != NULL); 619 StrCatS (Description, DescMaxSize/sizeof(CHAR16), Manufacturer); 620 StrCatS (Description, DescMaxSize/sizeof(CHAR16), L" "); 621 622 StrCatS (Description, DescMaxSize/sizeof(CHAR16), Product); 623 StrCatS (Description, DescMaxSize/sizeof(CHAR16), L" "); 624 625 StrCatS (Description, DescMaxSize/sizeof(CHAR16), SerialNumber); 626 627 if (Manufacturer != &NullChar) { 628 FreePool (Manufacturer); 629 } 630 if (Product != &NullChar) { 631 FreePool (Product); 632 } 633 if (SerialNumber != &NullChar) { 634 FreePool (SerialNumber); 635 } 636 637 BmEliminateExtraSpaces (Description); 638 639 return Description; 640} 641 642/** 643 Return the boot description for the controller based on the type. 644 645 @param Handle Controller handle. 646 647 @return The description string. 648**/ 649CHAR16 * 650BmGetMiscDescription ( 651 IN EFI_HANDLE Handle 652 ) 653{ 654 EFI_STATUS Status; 655 CHAR16 *Description; 656 EFI_BLOCK_IO_PROTOCOL *BlockIo; 657 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs; 658 659 switch (BmDevicePathType (DevicePathFromHandle (Handle))) { 660 case BmAcpiFloppyBoot: 661 Description = L"Floppy"; 662 break; 663 664 case BmMessageAtapiBoot: 665 case BmMessageSataBoot: 666 Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo); 667 ASSERT_EFI_ERROR (Status); 668 // 669 // Assume a removable SATA device should be the DVD/CD device 670 // 671 Description = BlockIo->Media->RemovableMedia ? L"DVD/CDROM" : L"Hard Drive"; 672 break; 673 674 case BmMessageUsbBoot: 675 Description = L"USB Device"; 676 break; 677 678 case BmMessageScsiBoot: 679 Description = L"SCSI Device"; 680 break; 681 682 case BmHardwareDeviceBoot: 683 Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo); 684 if (!EFI_ERROR (Status)) { 685 Description = BlockIo->Media->RemovableMedia ? L"Removable Disk" : L"Hard Drive"; 686 } else { 687 Description = L"Misc Device"; 688 } 689 break; 690 691 case BmMessageNetworkBoot: 692 Description = L"Network"; 693 break; 694 695 case BmMessageHttpBoot: 696 Description = L"Http"; 697 break; 698 699 default: 700 Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **) &Fs); 701 if (!EFI_ERROR (Status)) { 702 Description = L"Non-Block Boot Device"; 703 } else { 704 Description = L"Misc Device"; 705 } 706 break; 707 } 708 709 return AllocateCopyPool (StrSize (Description), Description); 710} 711 712/** 713 Register the platform provided boot description handler. 714 715 @param Handler The platform provided boot description handler 716 717 @retval EFI_SUCCESS The handler was registered successfully. 718 @retval EFI_ALREADY_STARTED The handler was already registered. 719 @retval EFI_OUT_OF_RESOURCES There is not enough resource to perform the registration. 720**/ 721EFI_STATUS 722EFIAPI 723EfiBootManagerRegisterBootDescriptionHandler ( 724 IN EFI_BOOT_MANAGER_BOOT_DESCRIPTION_HANDLER Handler 725 ) 726{ 727 LIST_ENTRY *Link; 728 BM_BOOT_DESCRIPTION_ENTRY *Entry; 729 730 for ( Link = GetFirstNode (&mPlatformBootDescriptionHandlers) 731 ; !IsNull (&mPlatformBootDescriptionHandlers, Link) 732 ; Link = GetNextNode (&mPlatformBootDescriptionHandlers, Link) 733 ) { 734 Entry = CR (Link, BM_BOOT_DESCRIPTION_ENTRY, Link, BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE); 735 if (Entry->Handler == Handler) { 736 return EFI_ALREADY_STARTED; 737 } 738 } 739 740 Entry = AllocatePool (sizeof (BM_BOOT_DESCRIPTION_ENTRY)); 741 if (Entry == NULL) { 742 return EFI_OUT_OF_RESOURCES; 743 } 744 745 Entry->Signature = BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE; 746 Entry->Handler = Handler; 747 InsertTailList (&mPlatformBootDescriptionHandlers, &Entry->Link); 748 return EFI_SUCCESS; 749} 750 751BM_GET_BOOT_DESCRIPTION mBmBootDescriptionHandlers[] = { 752 BmGetUsbDescription, 753 BmGetDescriptionFromDiskInfo, 754 BmGetMiscDescription 755}; 756 757/** 758 Return the boot description for the controller. 759 760 @param Handle Controller handle. 761 762 @return The description string. 763**/ 764CHAR16 * 765BmGetBootDescription ( 766 IN EFI_HANDLE Handle 767 ) 768{ 769 LIST_ENTRY *Link; 770 BM_BOOT_DESCRIPTION_ENTRY *Entry; 771 CHAR16 *Description; 772 CHAR16 *DefaultDescription; 773 CHAR16 *Temp; 774 UINTN Index; 775 776 // 777 // Firstly get the default boot description 778 // 779 DefaultDescription = NULL; 780 for (Index = 0; Index < sizeof (mBmBootDescriptionHandlers) / sizeof (mBmBootDescriptionHandlers[0]); Index++) { 781 DefaultDescription = mBmBootDescriptionHandlers[Index] (Handle); 782 if (DefaultDescription != NULL) { 783 // 784 // Avoid description confusion between UEFI & Legacy boot option by adding "UEFI " prefix 785 // ONLY for core provided boot description handler. 786 // 787 Temp = AllocatePool (StrSize (DefaultDescription) + sizeof (mBmUefiPrefix)); 788 ASSERT (Temp != NULL); 789 StrCpyS ( Temp, 790 (StrSize (DefaultDescription) + sizeof (mBmUefiPrefix))/sizeof(CHAR16), 791 mBmUefiPrefix 792 ); 793 StrCatS ( Temp, 794 (StrSize (DefaultDescription) + sizeof (mBmUefiPrefix))/sizeof(CHAR16), 795 DefaultDescription 796 ); 797 FreePool (DefaultDescription); 798 DefaultDescription = Temp; 799 break; 800 } 801 } 802 ASSERT (DefaultDescription != NULL); 803 804 // 805 // Secondly query platform for the better boot description 806 // 807 for ( Link = GetFirstNode (&mPlatformBootDescriptionHandlers) 808 ; !IsNull (&mPlatformBootDescriptionHandlers, Link) 809 ; Link = GetNextNode (&mPlatformBootDescriptionHandlers, Link) 810 ) { 811 Entry = CR (Link, BM_BOOT_DESCRIPTION_ENTRY, Link, BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE); 812 Description = Entry->Handler (Handle, DefaultDescription); 813 if (Description != NULL) { 814 FreePool (DefaultDescription); 815 return Description; 816 } 817 } 818 819 return DefaultDescription; 820} 821 822/** 823 Check whether a USB device match the specified USB WWID device path. This 824 function follows "Load Option Processing" behavior in UEFI specification. 825 826 @param UsbIo USB I/O protocol associated with the USB device. 827 @param UsbWwid The USB WWID device path to match. 828 829 @retval TRUE The USB device match the USB WWID device path. 830 @retval FALSE The USB device does not match the USB WWID device path. 831 832**/ 833BOOLEAN 834BmMatchUsbWwid ( 835 IN EFI_USB_IO_PROTOCOL *UsbIo, 836 IN USB_WWID_DEVICE_PATH *UsbWwid 837 ) 838{ 839 EFI_STATUS Status; 840 EFI_USB_DEVICE_DESCRIPTOR DevDesc; 841 EFI_USB_INTERFACE_DESCRIPTOR IfDesc; 842 UINT16 *LangIdTable; 843 UINT16 TableSize; 844 UINT16 Index; 845 CHAR16 *CompareStr; 846 UINTN CompareLen; 847 CHAR16 *SerialNumberStr; 848 UINTN Length; 849 850 if ((DevicePathType (UsbWwid) != MESSAGING_DEVICE_PATH) || 851 (DevicePathSubType (UsbWwid) != MSG_USB_WWID_DP)) { 852 return FALSE; 853 } 854 855 // 856 // Check Vendor Id and Product Id. 857 // 858 Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc); 859 if (EFI_ERROR (Status)) { 860 return FALSE; 861 } 862 if ((DevDesc.IdVendor != UsbWwid->VendorId) || 863 (DevDesc.IdProduct != UsbWwid->ProductId)) { 864 return FALSE; 865 } 866 867 // 868 // Check Interface Number. 869 // 870 Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &IfDesc); 871 if (EFI_ERROR (Status)) { 872 return FALSE; 873 } 874 if (IfDesc.InterfaceNumber != UsbWwid->InterfaceNumber) { 875 return FALSE; 876 } 877 878 // 879 // Check Serial Number. 880 // 881 if (DevDesc.StrSerialNumber == 0) { 882 return FALSE; 883 } 884 885 // 886 // Get all supported languages. 887 // 888 TableSize = 0; 889 LangIdTable = NULL; 890 Status = UsbIo->UsbGetSupportedLanguages (UsbIo, &LangIdTable, &TableSize); 891 if (EFI_ERROR (Status) || (TableSize == 0) || (LangIdTable == NULL)) { 892 return FALSE; 893 } 894 895 // 896 // Serial number in USB WWID device path is the last 64-or-less UTF-16 characters. 897 // 898 CompareStr = (CHAR16 *) (UINTN) (UsbWwid + 1); 899 CompareLen = (DevicePathNodeLength (UsbWwid) - sizeof (USB_WWID_DEVICE_PATH)) / sizeof (CHAR16); 900 if (CompareStr[CompareLen - 1] == L'\0') { 901 CompareLen--; 902 } 903 904 // 905 // Compare serial number in each supported language. 906 // 907 for (Index = 0; Index < TableSize / sizeof (UINT16); Index++) { 908 SerialNumberStr = NULL; 909 Status = UsbIo->UsbGetStringDescriptor ( 910 UsbIo, 911 LangIdTable[Index], 912 DevDesc.StrSerialNumber, 913 &SerialNumberStr 914 ); 915 if (EFI_ERROR (Status) || (SerialNumberStr == NULL)) { 916 continue; 917 } 918 919 Length = StrLen (SerialNumberStr); 920 if ((Length >= CompareLen) && 921 (CompareMem (SerialNumberStr + Length - CompareLen, CompareStr, CompareLen * sizeof (CHAR16)) == 0)) { 922 FreePool (SerialNumberStr); 923 return TRUE; 924 } 925 926 FreePool (SerialNumberStr); 927 } 928 929 return FALSE; 930} 931 932/** 933 Find a USB device which match the specified short-form device path start with 934 USB Class or USB WWID device path. If ParentDevicePath is NULL, this function 935 will search in all USB devices of the platform. If ParentDevicePath is not NULL, 936 this function will only search in its child devices. 937 938 @param DevicePath The device path that contains USB Class or USB WWID device path. 939 @param ParentDevicePathSize The length of the device path before the USB Class or 940 USB WWID device path. 941 @param UsbIoHandleCount A pointer to the count of the returned USB IO handles. 942 943 @retval NULL The matched USB IO handles cannot be found. 944 @retval other The matched USB IO handles. 945 946**/ 947EFI_HANDLE * 948BmFindUsbDevice ( 949 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, 950 IN UINTN ParentDevicePathSize, 951 OUT UINTN *UsbIoHandleCount 952 ) 953{ 954 EFI_STATUS Status; 955 EFI_HANDLE *UsbIoHandles; 956 EFI_DEVICE_PATH_PROTOCOL *UsbIoDevicePath; 957 EFI_USB_IO_PROTOCOL *UsbIo; 958 UINTN Index; 959 UINTN UsbIoDevicePathSize; 960 BOOLEAN Matched; 961 962 ASSERT (UsbIoHandleCount != NULL); 963 964 // 965 // Get all UsbIo Handles. 966 // 967 Status = gBS->LocateHandleBuffer ( 968 ByProtocol, 969 &gEfiUsbIoProtocolGuid, 970 NULL, 971 UsbIoHandleCount, 972 &UsbIoHandles 973 ); 974 if (EFI_ERROR (Status)) { 975 *UsbIoHandleCount = 0; 976 UsbIoHandles = NULL; 977 } 978 979 for (Index = 0; Index < *UsbIoHandleCount; ) { 980 // 981 // Get the Usb IO interface. 982 // 983 Status = gBS->HandleProtocol( 984 UsbIoHandles[Index], 985 &gEfiUsbIoProtocolGuid, 986 (VOID **) &UsbIo 987 ); 988 UsbIoDevicePath = DevicePathFromHandle (UsbIoHandles[Index]); 989 Matched = FALSE; 990 if (!EFI_ERROR (Status) && (UsbIoDevicePath != NULL)) { 991 UsbIoDevicePathSize = GetDevicePathSize (UsbIoDevicePath) - END_DEVICE_PATH_LENGTH; 992 993 // 994 // Compare starting part of UsbIoHandle's device path with ParentDevicePath. 995 // 996 if (CompareMem (UsbIoDevicePath, DevicePath, ParentDevicePathSize) == 0) { 997 if (BmMatchUsbClass (UsbIo, (USB_CLASS_DEVICE_PATH *) ((UINTN) DevicePath + ParentDevicePathSize)) || 998 BmMatchUsbWwid (UsbIo, (USB_WWID_DEVICE_PATH *) ((UINTN) DevicePath + ParentDevicePathSize))) { 999 Matched = TRUE; 1000 } 1001 } 1002 } 1003 1004 if (!Matched) { 1005 (*UsbIoHandleCount) --; 1006 CopyMem (&UsbIoHandles[Index], &UsbIoHandles[Index + 1], (*UsbIoHandleCount - Index) * sizeof (EFI_HANDLE)); 1007 } else { 1008 Index++; 1009 } 1010 } 1011 1012 return UsbIoHandles; 1013} 1014 1015/** 1016 Expand USB Class or USB WWID device path node to be full device path of a USB 1017 device in platform. 1018 1019 This function support following 4 cases: 1020 1) Boot Option device path starts with a USB Class or USB WWID device path, 1021 and there is no Media FilePath device path in the end. 1022 In this case, it will follow Removable Media Boot Behavior. 1023 2) Boot Option device path starts with a USB Class or USB WWID device path, 1024 and ended with Media FilePath device path. 1025 3) Boot Option device path starts with a full device path to a USB Host Controller, 1026 contains a USB Class or USB WWID device path node, while not ended with Media 1027 FilePath device path. In this case, it will follow Removable Media Boot Behavior. 1028 4) Boot Option device path starts with a full device path to a USB Host Controller, 1029 contains a USB Class or USB WWID device path node, and ended with Media 1030 FilePath device path. 1031 1032 @param FilePath The device path pointing to a load option. 1033 It could be a short-form device path. 1034 @param FullPath Return the full device path of the load option after 1035 short-form device path expanding. 1036 Caller is responsible to free it. 1037 @param FileSize Return the load option size. 1038 @param ShortformNode Pointer to the USB short-form device path node in the FilePath buffer. 1039 1040 @return The load option buffer. Caller is responsible to free the memory. 1041**/ 1042VOID * 1043BmExpandUsbDevicePath ( 1044 IN EFI_DEVICE_PATH_PROTOCOL *FilePath, 1045 OUT EFI_DEVICE_PATH_PROTOCOL **FullPath, 1046 OUT UINTN *FileSize, 1047 IN EFI_DEVICE_PATH_PROTOCOL *ShortformNode 1048 ) 1049{ 1050 UINTN ParentDevicePathSize; 1051 EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath; 1052 EFI_DEVICE_PATH_PROTOCOL *FullDevicePath; 1053 EFI_HANDLE *Handles; 1054 UINTN HandleCount; 1055 UINTN Index; 1056 VOID *FileBuffer; 1057 1058 ParentDevicePathSize = (UINTN) ShortformNode - (UINTN) FilePath; 1059 RemainingDevicePath = NextDevicePathNode (ShortformNode); 1060 FileBuffer = NULL; 1061 Handles = BmFindUsbDevice (FilePath, ParentDevicePathSize, &HandleCount); 1062 1063 for (Index = 0; (Index < HandleCount) && (FileBuffer == NULL); Index++) { 1064 FullDevicePath = AppendDevicePath (DevicePathFromHandle (Handles[Index]), RemainingDevicePath); 1065 FileBuffer = BmGetLoadOptionBuffer (FullDevicePath, FullPath, FileSize); 1066 FreePool (FullDevicePath); 1067 } 1068 1069 if (Handles != NULL) { 1070 FreePool (Handles); 1071 } 1072 1073 return FileBuffer; 1074} 1075 1076/** 1077 Save the partition DevicePath to the CachedDevicePath as the first instance. 1078 1079 @param CachedDevicePath The device path cache. 1080 @param DevicePath The partition device path to be cached. 1081**/ 1082VOID 1083BmCachePartitionDevicePath ( 1084 IN OUT EFI_DEVICE_PATH_PROTOCOL **CachedDevicePath, 1085 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath 1086 ) 1087{ 1088 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; 1089 UINTN Count; 1090 1091 if (BmMatchDevicePaths (*CachedDevicePath, DevicePath)) { 1092 TempDevicePath = *CachedDevicePath; 1093 *CachedDevicePath = BmDelPartMatchInstance (*CachedDevicePath, DevicePath); 1094 FreePool (TempDevicePath); 1095 } 1096 1097 if (*CachedDevicePath == NULL) { 1098 *CachedDevicePath = DuplicateDevicePath (DevicePath); 1099 return; 1100 } 1101 1102 TempDevicePath = *CachedDevicePath; 1103 *CachedDevicePath = AppendDevicePathInstance (DevicePath, *CachedDevicePath); 1104 if (TempDevicePath != NULL) { 1105 FreePool (TempDevicePath); 1106 } 1107 1108 // 1109 // Here limit the device path instance number to 12, which is max number for a system support 3 IDE controller 1110 // If the user try to boot many OS in different HDs or partitions, in theory, the 'HDDP' variable maybe become larger and larger. 1111 // 1112 Count = 0; 1113 TempDevicePath = *CachedDevicePath; 1114 while (!IsDevicePathEnd (TempDevicePath)) { 1115 TempDevicePath = NextDevicePathNode (TempDevicePath); 1116 // 1117 // Parse one instance 1118 // 1119 while (!IsDevicePathEndType (TempDevicePath)) { 1120 TempDevicePath = NextDevicePathNode (TempDevicePath); 1121 } 1122 Count++; 1123 // 1124 // If the CachedDevicePath variable contain too much instance, only remain 12 instances. 1125 // 1126 if (Count == 12) { 1127 SetDevicePathEndNode (TempDevicePath); 1128 break; 1129 } 1130 } 1131} 1132 1133/** 1134 Expand a device path that starts with a hard drive media device path node to be a 1135 full device path that includes the full hardware path to the device. We need 1136 to do this so it can be booted. As an optimization the front match (the part point 1137 to the partition node. E.g. ACPI() /PCI()/ATA()/Partition() ) is saved in a variable 1138 so a connect all is not required on every boot. All successful history device path 1139 which point to partition node (the front part) will be saved. 1140 1141 @param FilePath The device path pointing to a load option. 1142 It could be a short-form device path. 1143 @param FullPath Return the full device path of the load option after 1144 short-form device path expanding. 1145 Caller is responsible to free it. 1146 @param FileSize Return the load option size. 1147 1148 @return The load option buffer. Caller is responsible to free the memory. 1149**/ 1150VOID * 1151BmExpandPartitionDevicePath ( 1152 IN EFI_DEVICE_PATH_PROTOCOL *FilePath, 1153 OUT EFI_DEVICE_PATH_PROTOCOL **FullPath, 1154 OUT UINTN *FileSize 1155 ) 1156{ 1157 EFI_STATUS Status; 1158 UINTN BlockIoHandleCount; 1159 EFI_HANDLE *BlockIoBuffer; 1160 VOID *FileBuffer; 1161 EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath; 1162 UINTN Index; 1163 EFI_DEVICE_PATH_PROTOCOL *CachedDevicePath; 1164 EFI_DEVICE_PATH_PROTOCOL *TempNewDevicePath; 1165 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; 1166 UINTN CachedDevicePathSize; 1167 BOOLEAN NeedAdjust; 1168 EFI_DEVICE_PATH_PROTOCOL *Instance; 1169 UINTN Size; 1170 1171 FileBuffer = NULL; 1172 // 1173 // Check if there is prestore 'HDDP' variable. 1174 // If exist, search the front path which point to partition node in the variable instants. 1175 // If fail to find or 'HDDP' not exist, reconnect all and search in all system 1176 // 1177 GetVariable2 (L"HDDP", &mBmHardDriveBootVariableGuid, (VOID **) &CachedDevicePath, &CachedDevicePathSize); 1178 1179 // 1180 // Delete the invalid 'HDDP' variable. 1181 // 1182 if ((CachedDevicePath != NULL) && !IsDevicePathValid (CachedDevicePath, CachedDevicePathSize)) { 1183 FreePool (CachedDevicePath); 1184 CachedDevicePath = NULL; 1185 Status = gRT->SetVariable ( 1186 L"HDDP", 1187 &mBmHardDriveBootVariableGuid, 1188 0, 1189 0, 1190 NULL 1191 ); 1192 ASSERT_EFI_ERROR (Status); 1193 } 1194 1195 if (CachedDevicePath != NULL) { 1196 TempNewDevicePath = CachedDevicePath; 1197 NeedAdjust = FALSE; 1198 do { 1199 // 1200 // Check every instance of the variable 1201 // First, check whether the instance contain the partition node, which is needed for distinguishing multi 1202 // partial partition boot option. Second, check whether the instance could be connected. 1203 // 1204 Instance = GetNextDevicePathInstance (&TempNewDevicePath, &Size); 1205 if (BmMatchPartitionDevicePathNode (Instance, (HARDDRIVE_DEVICE_PATH *) FilePath)) { 1206 // 1207 // Connect the device path instance, the device path point to hard drive media device path node 1208 // e.g. ACPI() /PCI()/ATA()/Partition() 1209 // 1210 Status = EfiBootManagerConnectDevicePath (Instance, NULL); 1211 if (!EFI_ERROR (Status)) { 1212 TempDevicePath = AppendDevicePath (Instance, NextDevicePathNode (FilePath)); 1213 FileBuffer = BmGetLoadOptionBuffer (TempDevicePath, FullPath, FileSize); 1214 FreePool (TempDevicePath); 1215 1216 if (FileBuffer != NULL) { 1217 // 1218 // Adjust the 'HDDP' instances sequence if the matched one is not first one. 1219 // 1220 if (NeedAdjust) { 1221 BmCachePartitionDevicePath (&CachedDevicePath, Instance); 1222 // 1223 // Save the matching Device Path so we don't need to do a connect all next time 1224 // Failing to save only impacts performance next time expanding the short-form device path 1225 // 1226 Status = gRT->SetVariable ( 1227 L"HDDP", 1228 &mBmHardDriveBootVariableGuid, 1229 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE, 1230 GetDevicePathSize (CachedDevicePath), 1231 CachedDevicePath 1232 ); 1233 } 1234 1235 FreePool (Instance); 1236 FreePool (CachedDevicePath); 1237 return FileBuffer; 1238 } 1239 } 1240 } 1241 // 1242 // Come here means the first instance is not matched 1243 // 1244 NeedAdjust = TRUE; 1245 FreePool(Instance); 1246 } while (TempNewDevicePath != NULL); 1247 } 1248 1249 // 1250 // If we get here we fail to find or 'HDDP' not exist, and now we need 1251 // to search all devices in the system for a matched partition 1252 // 1253 EfiBootManagerConnectAll (); 1254 Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &BlockIoHandleCount, &BlockIoBuffer); 1255 if (EFI_ERROR (Status)) { 1256 BlockIoHandleCount = 0; 1257 BlockIoBuffer = NULL; 1258 } 1259 // 1260 // Loop through all the device handles that support the BLOCK_IO Protocol 1261 // 1262 for (Index = 0; Index < BlockIoHandleCount; Index++) { 1263 BlockIoDevicePath = DevicePathFromHandle (BlockIoBuffer[Index]); 1264 if (BlockIoDevicePath == NULL) { 1265 continue; 1266 } 1267 1268 if (BmMatchPartitionDevicePathNode (BlockIoDevicePath, (HARDDRIVE_DEVICE_PATH *) FilePath)) { 1269 // 1270 // Find the matched partition device path 1271 // 1272 TempDevicePath = AppendDevicePath (BlockIoDevicePath, NextDevicePathNode (FilePath)); 1273 FileBuffer = BmGetLoadOptionBuffer (TempDevicePath, FullPath, FileSize); 1274 FreePool (TempDevicePath); 1275 1276 if (FileBuffer != NULL) { 1277 BmCachePartitionDevicePath (&CachedDevicePath, BlockIoDevicePath); 1278 1279 // 1280 // Save the matching Device Path so we don't need to do a connect all next time 1281 // Failing to save only impacts performance next time expanding the short-form device path 1282 // 1283 Status = gRT->SetVariable ( 1284 L"HDDP", 1285 &mBmHardDriveBootVariableGuid, 1286 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE, 1287 GetDevicePathSize (CachedDevicePath), 1288 CachedDevicePath 1289 ); 1290 1291 break; 1292 } 1293 } 1294 } 1295 1296 if (CachedDevicePath != NULL) { 1297 FreePool (CachedDevicePath); 1298 } 1299 if (BlockIoBuffer != NULL) { 1300 FreePool (BlockIoBuffer); 1301 } 1302 return FileBuffer; 1303} 1304 1305/** 1306 Expand the media device path which points to a BlockIo or SimpleFileSystem instance 1307 by appending EFI_REMOVABLE_MEDIA_FILE_NAME. 1308 1309 @param DevicePath The media device path pointing to a BlockIo or SimpleFileSystem instance. 1310 @param FullPath Return the full device path pointing to the load option. 1311 @param FileSize Return the size of the load option. 1312 1313 @return The load option buffer. 1314**/ 1315VOID * 1316BmExpandMediaDevicePath ( 1317 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, 1318 OUT EFI_DEVICE_PATH_PROTOCOL **FullPath, 1319 OUT UINTN *FileSize 1320 ) 1321{ 1322 EFI_STATUS Status; 1323 EFI_HANDLE Handle; 1324 EFI_BLOCK_IO_PROTOCOL *BlockIo; 1325 VOID *Buffer; 1326 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; 1327 UINTN Size; 1328 UINTN TempSize; 1329 EFI_HANDLE *SimpleFileSystemHandles; 1330 UINTN NumberSimpleFileSystemHandles; 1331 UINTN Index; 1332 VOID *FileBuffer; 1333 UINT32 AuthenticationStatus; 1334 1335 // 1336 // Check whether the device is connected 1337 // 1338 TempDevicePath = DevicePath; 1339 Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &TempDevicePath, &Handle); 1340 if (!EFI_ERROR (Status)) { 1341 ASSERT (IsDevicePathEnd (TempDevicePath)); 1342 1343 TempDevicePath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME); 1344 FileBuffer = GetFileBufferByFilePath (TRUE, TempDevicePath, FileSize, &AuthenticationStatus); 1345 if (FileBuffer == NULL) { 1346 FreePool (TempDevicePath); 1347 TempDevicePath = NULL; 1348 } 1349 *FullPath = TempDevicePath; 1350 return FileBuffer; 1351 } 1352 1353 // 1354 // For device boot option only pointing to the removable device handle, 1355 // should make sure all its children handles (its child partion or media handles) are created and connected. 1356 // 1357 gBS->ConnectController (Handle, NULL, NULL, TRUE); 1358 1359 // 1360 // Issue a dummy read to the device to check for media change. 1361 // When the removable media is changed, any Block IO read/write will 1362 // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is 1363 // returned. After the Block IO protocol is reinstalled, subsequent 1364 // Block IO read/write will success. 1365 // 1366 Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, &Handle); 1367 ASSERT_EFI_ERROR (Status); 1368 Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo); 1369 ASSERT_EFI_ERROR (Status); 1370 Buffer = AllocatePool (BlockIo->Media->BlockSize); 1371 if (Buffer != NULL) { 1372 BlockIo->ReadBlocks ( 1373 BlockIo, 1374 BlockIo->Media->MediaId, 1375 0, 1376 BlockIo->Media->BlockSize, 1377 Buffer 1378 ); 1379 FreePool (Buffer); 1380 } 1381 1382 // 1383 // Detect the the default boot file from removable Media 1384 // 1385 FileBuffer = NULL; 1386 *FullPath = NULL; 1387 Size = GetDevicePathSize (DevicePath) - END_DEVICE_PATH_LENGTH; 1388 gBS->LocateHandleBuffer ( 1389 ByProtocol, 1390 &gEfiSimpleFileSystemProtocolGuid, 1391 NULL, 1392 &NumberSimpleFileSystemHandles, 1393 &SimpleFileSystemHandles 1394 ); 1395 for (Index = 0; Index < NumberSimpleFileSystemHandles; Index++) { 1396 // 1397 // Get the device path size of SimpleFileSystem handle 1398 // 1399 TempDevicePath = DevicePathFromHandle (SimpleFileSystemHandles[Index]); 1400 TempSize = GetDevicePathSize (TempDevicePath) - END_DEVICE_PATH_LENGTH; 1401 // 1402 // Check whether the device path of boot option is part of the SimpleFileSystem handle's device path 1403 // 1404 if ((Size <= TempSize) && (CompareMem (TempDevicePath, DevicePath, Size) == 0)) { 1405 TempDevicePath = FileDevicePath (SimpleFileSystemHandles[Index], EFI_REMOVABLE_MEDIA_FILE_NAME); 1406 FileBuffer = GetFileBufferByFilePath (TRUE, TempDevicePath, FileSize, &AuthenticationStatus); 1407 if (FileBuffer != NULL) { 1408 *FullPath = TempDevicePath; 1409 break; 1410 } 1411 FreePool (TempDevicePath); 1412 } 1413 } 1414 1415 if (SimpleFileSystemHandles != NULL) { 1416 FreePool (SimpleFileSystemHandles); 1417 } 1418 1419 return FileBuffer; 1420} 1421 1422/** 1423 Get the load option by its device path. 1424 1425 @param FilePath The device path pointing to a load option. 1426 It could be a short-form device path. 1427 @param FullPath Return the full device path of the load option after 1428 short-form device path expanding. 1429 Caller is responsible to free it. 1430 @param FileSize Return the load option size. 1431 1432 @return The load option buffer. Caller is responsible to free the memory. 1433**/ 1434VOID * 1435BmGetLoadOptionBuffer ( 1436 IN EFI_DEVICE_PATH_PROTOCOL *FilePath, 1437 OUT EFI_DEVICE_PATH_PROTOCOL **FullPath, 1438 OUT UINTN *FileSize 1439 ) 1440{ 1441 EFI_HANDLE Handle; 1442 VOID *FileBuffer; 1443 UINT32 AuthenticationStatus; 1444 EFI_DEVICE_PATH_PROTOCOL *Node; 1445 EFI_STATUS Status; 1446 1447 ASSERT ((FilePath != NULL) && (FullPath != NULL) && (FileSize != NULL)); 1448 1449 EfiBootManagerConnectDevicePath (FilePath, NULL); 1450 1451 *FullPath = NULL; 1452 *FileSize = 0; 1453 FileBuffer = NULL; 1454 1455 // 1456 // Boot from media device by adding a default file name \EFI\BOOT\BOOT{machine type short-name}.EFI 1457 // 1458 Node = FilePath; 1459 Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &Node, &Handle); 1460 if (EFI_ERROR (Status)) { 1461 Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &Node, &Handle); 1462 } 1463 1464 if (!EFI_ERROR (Status) && IsDevicePathEnd (Node)) { 1465 return BmExpandMediaDevicePath (FilePath, FullPath, FileSize); 1466 } 1467 1468 // 1469 // Expand the short-form device path to full device path 1470 // 1471 if ((DevicePathType (FilePath) == MEDIA_DEVICE_PATH) && 1472 (DevicePathSubType (FilePath) == MEDIA_HARDDRIVE_DP)) { 1473 // 1474 // Expand the Harddrive device path 1475 // 1476 return BmExpandPartitionDevicePath (FilePath, FullPath, FileSize); 1477 } else { 1478 for (Node = FilePath; !IsDevicePathEnd (Node); Node = NextDevicePathNode (Node)) { 1479 if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) && 1480 ((DevicePathSubType (Node) == MSG_USB_CLASS_DP) || (DevicePathSubType (Node) == MSG_USB_WWID_DP))) { 1481 break; 1482 } 1483 } 1484 1485 if (!IsDevicePathEnd (Node)) { 1486 // 1487 // Expand the USB WWID/Class device path 1488 // 1489 FileBuffer = BmExpandUsbDevicePath (FilePath, FullPath, FileSize, Node); 1490 if ((FileBuffer == NULL) && (FilePath == Node)) { 1491 // 1492 // Boot Option device path starts with USB Class or USB WWID device path. 1493 // For Boot Option device path which doesn't begin with the USB Class or 1494 // USB WWID device path, it's not needed to connect again here. 1495 // 1496 BmConnectUsbShortFormDevicePath (FilePath); 1497 FileBuffer = BmExpandUsbDevicePath (FilePath, FullPath, FileSize, Node); 1498 } 1499 return FileBuffer; 1500 } 1501 } 1502 1503 // 1504 // Fix up the boot option path if it points to a FV in memory map style of device path 1505 // 1506 if (BmIsMemmapFvFilePath (FilePath)) { 1507 return BmGetFileBufferByMemmapFv (FilePath, FullPath, FileSize); 1508 } 1509 1510 // 1511 // Directly reads the load option when it doesn't reside in simple file system instance (LoadFile/LoadFile2), 1512 // or it directly points to a file in simple file system instance. 1513 // 1514 Node = FilePath; 1515 Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &Node, &Handle); 1516 FileBuffer = GetFileBufferByFilePath (TRUE, FilePath, FileSize, &AuthenticationStatus); 1517 if (FileBuffer != NULL) { 1518 if (EFI_ERROR (Status)) { 1519 *FullPath = DuplicateDevicePath (FilePath); 1520 } else { 1521 // 1522 // LoadFile () may cause the device path of the Handle be updated. 1523 // 1524 *FullPath = AppendDevicePath (DevicePathFromHandle (Handle), Node); 1525 } 1526 } 1527 1528 return FileBuffer; 1529} 1530 1531/** 1532 Attempt to boot the EFI boot option. This routine sets L"BootCurent" and 1533 also signals the EFI ready to boot event. If the device path for the option 1534 starts with a BBS device path a legacy boot is attempted via the registered 1535 gLegacyBoot function. Short form device paths are also supported via this 1536 rountine. A device path starting with MEDIA_HARDDRIVE_DP, MSG_USB_WWID_DP, 1537 MSG_USB_CLASS_DP gets expaned out to find the first device that matches. 1538 If the BootOption Device Path fails the removable media boot algorithm 1539 is attempted (\EFI\BOOTIA32.EFI, \EFI\BOOTX64.EFI,... only one file type 1540 is tried per processor type) 1541 1542 @param BootOption Boot Option to try and boot. 1543 On return, BootOption->Status contains the boot status. 1544 EFI_SUCCESS BootOption was booted 1545 EFI_UNSUPPORTED A BBS device path was found with no valid callback 1546 registered via EfiBootManagerInitialize(). 1547 EFI_NOT_FOUND The BootOption was not found on the system 1548 !EFI_SUCCESS BootOption failed with this error status 1549 1550**/ 1551VOID 1552EFIAPI 1553EfiBootManagerBoot ( 1554 IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOption 1555 ) 1556{ 1557 EFI_STATUS Status; 1558 EFI_HANDLE ImageHandle; 1559 EFI_LOADED_IMAGE_PROTOCOL *ImageInfo; 1560 UINT16 Uint16; 1561 UINTN OptionNumber; 1562 UINTN OriginalOptionNumber; 1563 EFI_DEVICE_PATH_PROTOCOL *FilePath; 1564 EFI_DEVICE_PATH_PROTOCOL *Node; 1565 EFI_HANDLE FvHandle; 1566 VOID *FileBuffer; 1567 UINTN FileSize; 1568 EFI_BOOT_LOGO_PROTOCOL *BootLogo; 1569 EFI_EVENT LegacyBootEvent; 1570 1571 if (BootOption == NULL) { 1572 return; 1573 } 1574 1575 if (BootOption->FilePath == NULL || BootOption->OptionType != LoadOptionTypeBoot) { 1576 BootOption->Status = EFI_INVALID_PARAMETER; 1577 return; 1578 } 1579 1580 // 1581 // 1. Create Boot#### for a temporary boot if there is no match Boot#### (i.e. a boot by selected a EFI Shell using "Boot From File") 1582 // 1583 OptionNumber = BmFindBootOptionInVariable (BootOption); 1584 if (OptionNumber == LoadOptionNumberUnassigned) { 1585 Status = BmGetFreeOptionNumber (LoadOptionTypeBoot, &Uint16); 1586 if (!EFI_ERROR (Status)) { 1587 // 1588 // Save the BootOption->OptionNumber to restore later 1589 // 1590 OptionNumber = Uint16; 1591 OriginalOptionNumber = BootOption->OptionNumber; 1592 BootOption->OptionNumber = OptionNumber; 1593 Status = EfiBootManagerLoadOptionToVariable (BootOption); 1594 BootOption->OptionNumber = OriginalOptionNumber; 1595 } 1596 1597 if (EFI_ERROR (Status)) { 1598 DEBUG ((EFI_D_ERROR, "[Bds] Failed to create Boot#### for a temporary boot - %r!\n", Status)); 1599 BootOption->Status = Status; 1600 return ; 1601 } 1602 } 1603 1604 // 1605 // 2. Set BootCurrent 1606 // 1607 Uint16 = (UINT16) OptionNumber; 1608 BmSetVariableAndReportStatusCodeOnError ( 1609 L"BootCurrent", 1610 &gEfiGlobalVariableGuid, 1611 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, 1612 sizeof (UINT16), 1613 &Uint16 1614 ); 1615 1616 // 1617 // 3. Signal the EVT_SIGNAL_READY_TO_BOOT event when we are about to load and execute 1618 // the boot option. 1619 // 1620 Node = BootOption->FilePath; 1621 Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &Node, &FvHandle); 1622 if (!EFI_ERROR (Status) && CompareGuid ( 1623 EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) Node), 1624 PcdGetPtr (PcdBootManagerMenuFile) 1625 )) { 1626 DEBUG ((EFI_D_INFO, "[Bds] Booting Boot Manager Menu.\n")); 1627 BmStopHotkeyService (NULL, NULL); 1628 } else { 1629 EfiSignalEventReadyToBoot(); 1630 // 1631 // Report Status Code to indicate ReadyToBoot was signalled 1632 // 1633 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT)); 1634 // 1635 // 4. Repair system through DriverHealth protocol 1636 // 1637 BmRepairAllControllers (); 1638 } 1639 1640 PERF_START_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32) OptionNumber); 1641 1642 // 1643 // 5. Load EFI boot option to ImageHandle 1644 // 1645 ImageHandle = NULL; 1646 if (DevicePathType (BootOption->FilePath) != BBS_DEVICE_PATH) { 1647 Status = EFI_NOT_FOUND; 1648 FileBuffer = BmGetLoadOptionBuffer (BootOption->FilePath, &FilePath, &FileSize); 1649 DEBUG_CODE ( 1650 if (FileBuffer != NULL && CompareMem (BootOption->FilePath, FilePath, GetDevicePathSize (FilePath)) != 0) { 1651 DEBUG ((EFI_D_INFO, "[Bds] DevicePath expand: ")); 1652 BmPrintDp (BootOption->FilePath); 1653 DEBUG ((EFI_D_INFO, " -> ")); 1654 BmPrintDp (FilePath); 1655 DEBUG ((EFI_D_INFO, "\n")); 1656 } 1657 ); 1658 if (BmIsLoadOptionPeHeaderValid (BootOption->OptionType, FileBuffer, FileSize)) { 1659 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderLoad)); 1660 Status = gBS->LoadImage ( 1661 TRUE, 1662 gImageHandle, 1663 FilePath, 1664 FileBuffer, 1665 FileSize, 1666 &ImageHandle 1667 ); 1668 } 1669 if (FileBuffer != NULL) { 1670 FreePool (FileBuffer); 1671 } 1672 if (FilePath != NULL) { 1673 FreePool (FilePath); 1674 } 1675 1676 if (EFI_ERROR (Status)) { 1677 // 1678 // Report Status Code to indicate that the failure to load boot option 1679 // 1680 REPORT_STATUS_CODE ( 1681 EFI_ERROR_CODE | EFI_ERROR_MINOR, 1682 (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR) 1683 ); 1684 BootOption->Status = Status; 1685 return; 1686 } 1687 } 1688 1689 // 1690 // 6. Adjust the different type memory page number just before booting 1691 // and save the updated info into the variable for next boot to use 1692 // 1693 if ((BootOption->Attributes & LOAD_OPTION_CATEGORY) == LOAD_OPTION_CATEGORY_BOOT) { 1694 if (PcdGetBool (PcdResetOnMemoryTypeInformationChange)) { 1695 BmSetMemoryTypeInformationVariable (); 1696 } 1697 } 1698 1699 DEBUG_CODE_BEGIN(); 1700 if (BootOption->Description == NULL) { 1701 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "[Bds]Booting from unknown device path\n")); 1702 } else { 1703 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "[Bds]Booting %s\n", BootOption->Description)); 1704 } 1705 DEBUG_CODE_END(); 1706 1707 // 1708 // Check to see if we should legacy BOOT. If yes then do the legacy boot 1709 // Write boot to OS performance data for Legacy boot 1710 // 1711 if ((DevicePathType (BootOption->FilePath) == BBS_DEVICE_PATH) && (DevicePathSubType (BootOption->FilePath) == BBS_BBS_DP)) { 1712 if (mBmLegacyBoot != NULL) { 1713 // 1714 // Write boot to OS performance data for legacy boot. 1715 // 1716 PERF_CODE ( 1717 // 1718 // Create an event to be signalled when Legacy Boot occurs to write performance data. 1719 // 1720 Status = EfiCreateEventLegacyBootEx( 1721 TPL_NOTIFY, 1722 BmWriteBootToOsPerformanceData, 1723 NULL, 1724 &LegacyBootEvent 1725 ); 1726 ASSERT_EFI_ERROR (Status); 1727 ); 1728 1729 mBmLegacyBoot (BootOption); 1730 } else { 1731 BootOption->Status = EFI_UNSUPPORTED; 1732 } 1733 1734 PERF_END_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32) OptionNumber); 1735 return; 1736 } 1737 1738 // 1739 // Provide the image with its load options 1740 // 1741 Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo); 1742 ASSERT_EFI_ERROR (Status); 1743 1744 ImageInfo->LoadOptionsSize = BootOption->OptionalDataSize; 1745 ImageInfo->LoadOptions = BootOption->OptionalData; 1746 1747 // 1748 // Clean to NULL because the image is loaded directly from the firmwares boot manager. 1749 // 1750 ImageInfo->ParentHandle = NULL; 1751 1752 // 1753 // Before calling the image, enable the Watchdog Timer for 5 minutes period 1754 // 1755 gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL); 1756 1757 // 1758 // Write boot to OS performance data for UEFI boot 1759 // 1760 PERF_CODE ( 1761 BmWriteBootToOsPerformanceData (NULL, NULL); 1762 ); 1763 1764 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderStart)); 1765 1766 Status = gBS->StartImage (ImageHandle, &BootOption->ExitDataSize, &BootOption->ExitData); 1767 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Image Return Status = %r\n", Status)); 1768 BootOption->Status = Status; 1769 if (EFI_ERROR (Status)) { 1770 // 1771 // Report Status Code to indicate that boot failure 1772 // 1773 REPORT_STATUS_CODE ( 1774 EFI_ERROR_CODE | EFI_ERROR_MINOR, 1775 (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED) 1776 ); 1777 } 1778 PERF_END_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32) OptionNumber); 1779 1780 // 1781 // Clear the Watchdog Timer after the image returns 1782 // 1783 gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL); 1784 1785 // 1786 // Set Logo status invalid after trying one boot option 1787 // 1788 BootLogo = NULL; 1789 Status = gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo); 1790 if (!EFI_ERROR (Status) && (BootLogo != NULL)) { 1791 Status = BootLogo->SetBootLogo (BootLogo, NULL, 0, 0, 0, 0); 1792 ASSERT_EFI_ERROR (Status); 1793 } 1794 1795 // 1796 // Clear Boot Current 1797 // 1798 Status = gRT->SetVariable ( 1799 L"BootCurrent", 1800 &gEfiGlobalVariableGuid, 1801 0, 1802 0, 1803 NULL 1804 ); 1805 // 1806 // Deleting variable with current variable implementation shouldn't fail. 1807 // When BootXXXX (e.g.: BootManagerMenu) boots BootYYYY, exiting BootYYYY causes BootCurrent deleted, 1808 // exiting BootXXXX causes deleting BootCurrent returns EFI_NOT_FOUND. 1809 // 1810 ASSERT (Status == EFI_SUCCESS || Status == EFI_NOT_FOUND); 1811} 1812 1813/** 1814 Check whether there is a instance in BlockIoDevicePath, which contain multi device path 1815 instances, has the same partition node with HardDriveDevicePath device path 1816 1817 @param BlockIoDevicePath Multi device path instances which need to check 1818 @param HardDriveDevicePath A device path which starts with a hard drive media 1819 device path. 1820 1821 @retval TRUE There is a matched device path instance. 1822 @retval FALSE There is no matched device path instance. 1823 1824**/ 1825BOOLEAN 1826BmMatchPartitionDevicePathNode ( 1827 IN EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath, 1828 IN HARDDRIVE_DEVICE_PATH *HardDriveDevicePath 1829 ) 1830{ 1831 HARDDRIVE_DEVICE_PATH *Node; 1832 1833 if ((BlockIoDevicePath == NULL) || (HardDriveDevicePath == NULL)) { 1834 return FALSE; 1835 } 1836 1837 // 1838 // find the partition device path node 1839 // 1840 while (!IsDevicePathEnd (BlockIoDevicePath)) { 1841 if ((DevicePathType (BlockIoDevicePath) == MEDIA_DEVICE_PATH) && 1842 (DevicePathSubType (BlockIoDevicePath) == MEDIA_HARDDRIVE_DP) 1843 ) { 1844 break; 1845 } 1846 1847 BlockIoDevicePath = NextDevicePathNode (BlockIoDevicePath); 1848 } 1849 1850 if (IsDevicePathEnd (BlockIoDevicePath)) { 1851 return FALSE; 1852 } 1853 1854 // 1855 // See if the harddrive device path in blockio matches the orig Hard Drive Node 1856 // 1857 Node = (HARDDRIVE_DEVICE_PATH *) BlockIoDevicePath; 1858 1859 // 1860 // Match Signature and PartitionNumber. 1861 // Unused bytes in Signature are initiaized with zeros. 1862 // 1863 return (BOOLEAN) ( 1864 (Node->PartitionNumber == HardDriveDevicePath->PartitionNumber) && 1865 (Node->MBRType == HardDriveDevicePath->MBRType) && 1866 (Node->SignatureType == HardDriveDevicePath->SignatureType) && 1867 (CompareMem (Node->Signature, HardDriveDevicePath->Signature, sizeof (Node->Signature)) == 0) 1868 ); 1869} 1870 1871/** 1872 Emuerate all possible bootable medias in the following order: 1873 1. Removable BlockIo - The boot option only points to the removable media 1874 device, like USB key, DVD, Floppy etc. 1875 2. Fixed BlockIo - The boot option only points to a Fixed blockIo device, 1876 like HardDisk. 1877 3. Non-BlockIo SimpleFileSystem - The boot option points to a device supporting 1878 SimpleFileSystem Protocol, but not supporting BlockIo 1879 protocol. 1880 4. LoadFile - The boot option points to the media supporting 1881 LoadFile protocol. 1882 Reference: UEFI Spec chapter 3.3 Boot Option Variables Default Boot Behavior 1883 1884 @param BootOptionCount Return the boot option count which has been found. 1885 1886 @retval Pointer to the boot option array. 1887**/ 1888EFI_BOOT_MANAGER_LOAD_OPTION * 1889BmEnumerateBootOptions ( 1890 UINTN *BootOptionCount 1891 ) 1892{ 1893 EFI_STATUS Status; 1894 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions; 1895 UINTN HandleCount; 1896 EFI_HANDLE *Handles; 1897 EFI_BLOCK_IO_PROTOCOL *BlkIo; 1898 UINTN Removable; 1899 UINTN Index; 1900 CHAR16 *Description; 1901 1902 ASSERT (BootOptionCount != NULL); 1903 1904 *BootOptionCount = 0; 1905 BootOptions = NULL; 1906 1907 // 1908 // Parse removable block io followed by fixed block io 1909 // 1910 gBS->LocateHandleBuffer ( 1911 ByProtocol, 1912 &gEfiBlockIoProtocolGuid, 1913 NULL, 1914 &HandleCount, 1915 &Handles 1916 ); 1917 1918 for (Removable = 0; Removable < 2; Removable++) { 1919 for (Index = 0; Index < HandleCount; Index++) { 1920 Status = gBS->HandleProtocol ( 1921 Handles[Index], 1922 &gEfiBlockIoProtocolGuid, 1923 (VOID **) &BlkIo 1924 ); 1925 if (EFI_ERROR (Status)) { 1926 continue; 1927 } 1928 1929 // 1930 // Skip the logical partitions 1931 // 1932 if (BlkIo->Media->LogicalPartition) { 1933 continue; 1934 } 1935 1936 // 1937 // Skip the fixed block io then the removable block io 1938 // 1939 if (BlkIo->Media->RemovableMedia == ((Removable == 0) ? FALSE : TRUE)) { 1940 continue; 1941 } 1942 1943 Description = BmGetBootDescription (Handles[Index]); 1944 BootOptions = ReallocatePool ( 1945 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount), 1946 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1), 1947 BootOptions 1948 ); 1949 ASSERT (BootOptions != NULL); 1950 1951 Status = EfiBootManagerInitializeLoadOption ( 1952 &BootOptions[(*BootOptionCount)++], 1953 LoadOptionNumberUnassigned, 1954 LoadOptionTypeBoot, 1955 LOAD_OPTION_ACTIVE, 1956 Description, 1957 DevicePathFromHandle (Handles[Index]), 1958 NULL, 1959 0 1960 ); 1961 ASSERT_EFI_ERROR (Status); 1962 1963 FreePool (Description); 1964 } 1965 } 1966 1967 if (HandleCount != 0) { 1968 FreePool (Handles); 1969 } 1970 1971 // 1972 // Parse simple file system not based on block io 1973 // 1974 gBS->LocateHandleBuffer ( 1975 ByProtocol, 1976 &gEfiSimpleFileSystemProtocolGuid, 1977 NULL, 1978 &HandleCount, 1979 &Handles 1980 ); 1981 for (Index = 0; Index < HandleCount; Index++) { 1982 Status = gBS->HandleProtocol ( 1983 Handles[Index], 1984 &gEfiBlockIoProtocolGuid, 1985 (VOID **) &BlkIo 1986 ); 1987 if (!EFI_ERROR (Status)) { 1988 // 1989 // Skip if the file system handle supports a BlkIo protocol, which we've handled in above 1990 // 1991 continue; 1992 } 1993 Description = BmGetBootDescription (Handles[Index]); 1994 BootOptions = ReallocatePool ( 1995 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount), 1996 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1), 1997 BootOptions 1998 ); 1999 ASSERT (BootOptions != NULL); 2000 2001 Status = EfiBootManagerInitializeLoadOption ( 2002 &BootOptions[(*BootOptionCount)++], 2003 LoadOptionNumberUnassigned, 2004 LoadOptionTypeBoot, 2005 LOAD_OPTION_ACTIVE, 2006 Description, 2007 DevicePathFromHandle (Handles[Index]), 2008 NULL, 2009 0 2010 ); 2011 ASSERT_EFI_ERROR (Status); 2012 FreePool (Description); 2013 } 2014 2015 if (HandleCount != 0) { 2016 FreePool (Handles); 2017 } 2018 2019 // 2020 // Parse load file, assuming UEFI Network boot option 2021 // 2022 gBS->LocateHandleBuffer ( 2023 ByProtocol, 2024 &gEfiLoadFileProtocolGuid, 2025 NULL, 2026 &HandleCount, 2027 &Handles 2028 ); 2029 for (Index = 0; Index < HandleCount; Index++) { 2030 2031 Description = BmGetBootDescription (Handles[Index]); 2032 BootOptions = ReallocatePool ( 2033 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount), 2034 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1), 2035 BootOptions 2036 ); 2037 ASSERT (BootOptions != NULL); 2038 2039 Status = EfiBootManagerInitializeLoadOption ( 2040 &BootOptions[(*BootOptionCount)++], 2041 LoadOptionNumberUnassigned, 2042 LoadOptionTypeBoot, 2043 LOAD_OPTION_ACTIVE, 2044 Description, 2045 DevicePathFromHandle (Handles[Index]), 2046 NULL, 2047 0 2048 ); 2049 ASSERT_EFI_ERROR (Status); 2050 FreePool (Description); 2051 } 2052 2053 if (HandleCount != 0) { 2054 FreePool (Handles); 2055 } 2056 2057 return BootOptions; 2058} 2059 2060/** 2061 The function enumerates all boot options, creates them and registers them in the BootOrder variable. 2062**/ 2063VOID 2064EFIAPI 2065EfiBootManagerRefreshAllBootOption ( 2066 VOID 2067 ) 2068{ 2069 EFI_STATUS Status; 2070 EFI_BOOT_MANAGER_LOAD_OPTION *NvBootOptions; 2071 UINTN NvBootOptionCount; 2072 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions; 2073 UINTN BootOptionCount; 2074 UINTN Index; 2075 2076 // 2077 // Optionally refresh the legacy boot option 2078 // 2079 if (mBmRefreshLegacyBootOption != NULL) { 2080 mBmRefreshLegacyBootOption (); 2081 } 2082 2083 BootOptions = BmEnumerateBootOptions (&BootOptionCount); 2084 NvBootOptions = EfiBootManagerGetLoadOptions (&NvBootOptionCount, LoadOptionTypeBoot); 2085 2086 // 2087 // Mark the boot option as added by BDS by setting OptionalData to a special GUID 2088 // 2089 for (Index = 0; Index < BootOptionCount; Index++) { 2090 BootOptions[Index].OptionalData = AllocateCopyPool (sizeof (EFI_GUID), &mBmAutoCreateBootOptionGuid); 2091 BootOptions[Index].OptionalDataSize = sizeof (EFI_GUID); 2092 } 2093 2094 // 2095 // Remove invalid EFI boot options from NV 2096 // 2097 for (Index = 0; Index < NvBootOptionCount; Index++) { 2098 if (((DevicePathType (NvBootOptions[Index].FilePath) != BBS_DEVICE_PATH) || 2099 (DevicePathSubType (NvBootOptions[Index].FilePath) != BBS_BBS_DP) 2100 ) && 2101 (NvBootOptions[Index].OptionalDataSize == sizeof (EFI_GUID)) && 2102 CompareGuid ((EFI_GUID *) NvBootOptions[Index].OptionalData, &mBmAutoCreateBootOptionGuid) 2103 ) { 2104 // 2105 // Only check those added by BDS 2106 // so that the boot options added by end-user or OS installer won't be deleted 2107 // 2108 if (BmFindLoadOption (&NvBootOptions[Index], BootOptions, BootOptionCount) == (UINTN) -1) { 2109 Status = EfiBootManagerDeleteLoadOptionVariable (NvBootOptions[Index].OptionNumber, LoadOptionTypeBoot); 2110 // 2111 // Deleting variable with current variable implementation shouldn't fail. 2112 // 2113 ASSERT_EFI_ERROR (Status); 2114 } 2115 } 2116 } 2117 2118 // 2119 // Add new EFI boot options to NV 2120 // 2121 for (Index = 0; Index < BootOptionCount; Index++) { 2122 if (BmFindLoadOption (&BootOptions[Index], NvBootOptions, NvBootOptionCount) == (UINTN) -1) { 2123 EfiBootManagerAddLoadOptionVariable (&BootOptions[Index], (UINTN) -1); 2124 // 2125 // Try best to add the boot options so continue upon failure. 2126 // 2127 } 2128 } 2129 2130 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount); 2131 EfiBootManagerFreeLoadOptions (NvBootOptions, NvBootOptionCount); 2132} 2133 2134/** 2135 This function is called to create the boot option for the Boot Manager Menu. 2136 2137 The Boot Manager Menu is shown after successfully booting a boot option. 2138 Assume the BootManagerMenuFile is in the same FV as the module links to this library. 2139 2140 @param BootOption Return the boot option of the Boot Manager Menu 2141 2142 @retval EFI_SUCCESS Successfully register the Boot Manager Menu. 2143 @retval Status Return status of gRT->SetVariable (). BootOption still points 2144 to the Boot Manager Menu even the Status is not EFI_SUCCESS. 2145**/ 2146EFI_STATUS 2147BmRegisterBootManagerMenu ( 2148 OUT EFI_BOOT_MANAGER_LOAD_OPTION *BootOption 2149 ) 2150{ 2151 EFI_STATUS Status; 2152 CHAR16 *Description; 2153 UINTN DescriptionLength; 2154 EFI_DEVICE_PATH_PROTOCOL *DevicePath; 2155 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; 2156 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode; 2157 2158 Status = GetSectionFromFv ( 2159 PcdGetPtr (PcdBootManagerMenuFile), 2160 EFI_SECTION_USER_INTERFACE, 2161 0, 2162 (VOID **) &Description, 2163 &DescriptionLength 2164 ); 2165 if (EFI_ERROR (Status)) { 2166 Description = NULL; 2167 } 2168 2169 EfiInitializeFwVolDevicepathNode (&FileNode, PcdGetPtr (PcdBootManagerMenuFile)); 2170 Status = gBS->HandleProtocol ( 2171 gImageHandle, 2172 &gEfiLoadedImageProtocolGuid, 2173 (VOID **) &LoadedImage 2174 ); 2175 ASSERT_EFI_ERROR (Status); 2176 DevicePath = AppendDevicePathNode ( 2177 DevicePathFromHandle (LoadedImage->DeviceHandle), 2178 (EFI_DEVICE_PATH_PROTOCOL *) &FileNode 2179 ); 2180 ASSERT (DevicePath != NULL); 2181 2182 Status = EfiBootManagerInitializeLoadOption ( 2183 BootOption, 2184 LoadOptionNumberUnassigned, 2185 LoadOptionTypeBoot, 2186 LOAD_OPTION_CATEGORY_APP | LOAD_OPTION_ACTIVE | LOAD_OPTION_HIDDEN, 2187 (Description != NULL) ? Description : L"Boot Manager Menu", 2188 DevicePath, 2189 NULL, 2190 0 2191 ); 2192 ASSERT_EFI_ERROR (Status); 2193 FreePool (DevicePath); 2194 if (Description != NULL) { 2195 FreePool (Description); 2196 } 2197 2198 DEBUG_CODE ( 2199 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions; 2200 UINTN BootOptionCount; 2201 2202 BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot); 2203 ASSERT (BmFindLoadOption (BootOption, BootOptions, BootOptionCount) == -1); 2204 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount); 2205 ); 2206 2207 return EfiBootManagerAddLoadOptionVariable (BootOption, 0); 2208} 2209 2210/** 2211 Return the boot option corresponding to the Boot Manager Menu. 2212 It may automatically create one if the boot option hasn't been created yet. 2213 2214 @param BootOption Return the Boot Manager Menu. 2215 2216 @retval EFI_SUCCESS The Boot Manager Menu is successfully returned. 2217 @retval Status Return status of gRT->SetVariable (). BootOption still points 2218 to the Boot Manager Menu even the Status is not EFI_SUCCESS. 2219**/ 2220EFI_STATUS 2221EFIAPI 2222EfiBootManagerGetBootManagerMenu ( 2223 EFI_BOOT_MANAGER_LOAD_OPTION *BootOption 2224 ) 2225{ 2226 EFI_STATUS Status; 2227 UINTN BootOptionCount; 2228 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions; 2229 UINTN Index; 2230 EFI_DEVICE_PATH_PROTOCOL *Node; 2231 EFI_HANDLE FvHandle; 2232 2233 BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot); 2234 2235 for (Index = 0; Index < BootOptionCount; Index++) { 2236 Node = BootOptions[Index].FilePath; 2237 Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &Node, &FvHandle); 2238 if (!EFI_ERROR (Status)) { 2239 if (CompareGuid ( 2240 EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) Node), 2241 PcdGetPtr (PcdBootManagerMenuFile) 2242 ) 2243 ) { 2244 Status = EfiBootManagerInitializeLoadOption ( 2245 BootOption, 2246 BootOptions[Index].OptionNumber, 2247 BootOptions[Index].OptionType, 2248 BootOptions[Index].Attributes, 2249 BootOptions[Index].Description, 2250 BootOptions[Index].FilePath, 2251 BootOptions[Index].OptionalData, 2252 BootOptions[Index].OptionalDataSize 2253 ); 2254 ASSERT_EFI_ERROR (Status); 2255 break; 2256 } 2257 } 2258 } 2259 2260 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount); 2261 2262 // 2263 // Automatically create the Boot#### for Boot Manager Menu when not found. 2264 // 2265 if (Index == BootOptionCount) { 2266 return BmRegisterBootManagerMenu (BootOption); 2267 } else { 2268 return EFI_SUCCESS; 2269 } 2270} 2271 2272