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