1 /** @file 2 Load option library functions which relate with creating and processing load options. 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 GLOBAL_REMOVE_IF_UNREFERENCED 19 CHAR16 *mBmLoadOptionName[] = { 20 L"Driver", 21 L"SysPrep", 22 L"Boot", 23 L"PlatformRecovery" 24 }; 25 26 GLOBAL_REMOVE_IF_UNREFERENCED 27 CHAR16 *mBmLoadOptionOrderName[] = { 28 EFI_DRIVER_ORDER_VARIABLE_NAME, 29 EFI_SYS_PREP_ORDER_VARIABLE_NAME, 30 EFI_BOOT_ORDER_VARIABLE_NAME, 31 NULL // PlatformRecovery#### doesn't have associated *Order variable 32 }; 33 34 /** 35 Call Visitor function for each variable in variable storage. 36 37 @param Visitor Visitor function. 38 @param Context The context passed to Visitor function. 39 **/ 40 VOID 41 BmForEachVariable ( 42 BM_VARIABLE_VISITOR Visitor, 43 VOID *Context 44 ) 45 { 46 EFI_STATUS Status; 47 CHAR16 *Name; 48 EFI_GUID Guid; 49 UINTN NameSize; 50 UINTN NewNameSize; 51 52 NameSize = sizeof (CHAR16); 53 Name = AllocateZeroPool (NameSize); 54 ASSERT (Name != NULL); 55 while (TRUE) { 56 NewNameSize = NameSize; 57 Status = gRT->GetNextVariableName (&NewNameSize, Name, &Guid); 58 if (Status == EFI_BUFFER_TOO_SMALL) { 59 Name = ReallocatePool (NameSize, NewNameSize, Name); 60 ASSERT (Name != NULL); 61 Status = gRT->GetNextVariableName (&NewNameSize, Name, &Guid); 62 NameSize = NewNameSize; 63 } 64 65 if (Status == EFI_NOT_FOUND) { 66 break; 67 } 68 ASSERT_EFI_ERROR (Status); 69 70 Visitor (Name, &Guid, Context); 71 } 72 73 FreePool (Name); 74 } 75 76 /** 77 Get the Option Number that wasn't used. 78 79 @param LoadOptionType The load option type. 80 @param FreeOptionNumber Return the minimal free option number. 81 82 @retval EFI_SUCCESS The option number is found and will be returned. 83 @retval EFI_OUT_OF_RESOURCES There is no free option number that can be used. 84 @retval EFI_INVALID_PARAMETER FreeOptionNumber is NULL 85 86 **/ 87 EFI_STATUS 88 BmGetFreeOptionNumber ( 89 IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType, 90 OUT UINT16 *FreeOptionNumber 91 ) 92 { 93 94 UINTN OptionNumber; 95 UINTN Index; 96 UINT16 *OptionOrder; 97 UINTN OptionOrderSize; 98 UINT16 *BootNext; 99 100 ASSERT (FreeOptionNumber != NULL); 101 ASSERT (LoadOptionType == LoadOptionTypeDriver || 102 LoadOptionType == LoadOptionTypeBoot || 103 LoadOptionType == LoadOptionTypeSysPrep); 104 105 GetEfiGlobalVariable2 (mBmLoadOptionOrderName[LoadOptionType], (VOID **) &OptionOrder, &OptionOrderSize); 106 ASSERT ((OptionOrder != NULL && OptionOrderSize != 0) || (OptionOrder == NULL && OptionOrderSize == 0)); 107 108 BootNext = NULL; 109 if (LoadOptionType == LoadOptionTypeBoot) { 110 GetEfiGlobalVariable2 (L"BootNext", (VOID**) &BootNext, NULL); 111 } 112 113 for (OptionNumber = 0; 114 OptionNumber < OptionOrderSize / sizeof (UINT16) 115 + ((BootNext != NULL) ? 1 : 0); 116 OptionNumber++ 117 ) { 118 // 119 // Search in OptionOrder whether the OptionNumber exists 120 // 121 for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) { 122 if (OptionNumber == OptionOrder[Index]) { 123 break; 124 } 125 } 126 127 // 128 // We didn't find it in the ****Order array and it doesn't equal to BootNext 129 // Otherwise, OptionNumber equals to OptionOrderSize / sizeof (UINT16) + 1 130 // 131 if ((Index == OptionOrderSize / sizeof (UINT16)) && 132 ((BootNext == NULL) || (OptionNumber != *BootNext)) 133 ) { 134 break; 135 } 136 } 137 if (OptionOrder != NULL) { 138 FreePool (OptionOrder); 139 } 140 141 if (BootNext != NULL) { 142 FreePool (BootNext); 143 } 144 145 // 146 // When BootOrder & BootNext conver all numbers in the range [0 ... 0xffff], 147 // OptionNumber equals to 0x10000 which is not valid. 148 // 149 ASSERT (OptionNumber <= 0x10000); 150 if (OptionNumber == 0x10000) { 151 return EFI_OUT_OF_RESOURCES; 152 } else { 153 *FreeOptionNumber = (UINT16) OptionNumber; 154 return EFI_SUCCESS; 155 } 156 } 157 158 /** 159 Create the Boot####, Driver####, SysPrep####, PlatformRecovery#### variable 160 from the load option. 161 162 @param LoadOption Pointer to the load option. 163 164 @retval EFI_SUCCESS The variable was created. 165 @retval Others Error status returned by RT->SetVariable. 166 **/ 167 EFI_STATUS 168 EFIAPI 169 EfiBootManagerLoadOptionToVariable ( 170 IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Option 171 ) 172 { 173 EFI_STATUS Status; 174 UINTN VariableSize; 175 UINT8 *Variable; 176 UINT8 *Ptr; 177 CHAR16 OptionName[BM_OPTION_NAME_LEN]; 178 CHAR16 *Description; 179 CHAR16 NullChar; 180 EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock; 181 UINT32 VariableAttributes; 182 183 if ((Option->OptionNumber == LoadOptionNumberUnassigned) || 184 (Option->FilePath == NULL) || 185 ((UINT32) Option->OptionType >= LoadOptionTypeMax) 186 ) { 187 return EFI_INVALID_PARAMETER; 188 } 189 190 // 191 // Convert NULL description to empty description 192 // 193 NullChar = L'\0'; 194 Description = Option->Description; 195 if (Description == NULL) { 196 Description = &NullChar; 197 } 198 199 /* 200 UINT32 Attributes; 201 UINT16 FilePathListLength; 202 CHAR16 Description[]; 203 EFI_DEVICE_PATH_PROTOCOL FilePathList[]; 204 UINT8 OptionalData[]; 205 TODO: FilePathList[] IS: 206 A packed array of UEFI device paths. The first element of the 207 array is a device path that describes the device and location of the 208 Image for this load option. The FilePathList[0] is specific 209 to the device type. Other device paths may optionally exist in the 210 FilePathList, but their usage is OSV specific. Each element 211 in the array is variable length, and ends at the device path end 212 structure. 213 */ 214 VariableSize = sizeof (Option->Attributes) 215 + sizeof (UINT16) 216 + StrSize (Description) 217 + GetDevicePathSize (Option->FilePath) 218 + Option->OptionalDataSize; 219 220 Variable = AllocatePool (VariableSize); 221 ASSERT (Variable != NULL); 222 223 Ptr = Variable; 224 WriteUnaligned32 ((UINT32 *) Ptr, Option->Attributes); 225 Ptr += sizeof (Option->Attributes); 226 227 WriteUnaligned16 ((UINT16 *) Ptr, (UINT16) GetDevicePathSize (Option->FilePath)); 228 Ptr += sizeof (UINT16); 229 230 CopyMem (Ptr, Description, StrSize (Description)); 231 Ptr += StrSize (Description); 232 233 CopyMem (Ptr, Option->FilePath, GetDevicePathSize (Option->FilePath)); 234 Ptr += GetDevicePathSize (Option->FilePath); 235 236 CopyMem (Ptr, Option->OptionalData, Option->OptionalDataSize); 237 238 UnicodeSPrint (OptionName, sizeof (OptionName), L"%s%04x", mBmLoadOptionName[Option->OptionType], Option->OptionNumber); 239 240 VariableAttributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE; 241 if (Option->OptionType == LoadOptionTypePlatformRecovery) { 242 // 243 // Lock the PlatformRecovery#### 244 // 245 Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock); 246 if (!EFI_ERROR (Status)) { 247 Status = VariableLock->RequestToLock (VariableLock, OptionName, &gEfiGlobalVariableGuid); 248 ASSERT_EFI_ERROR (Status); 249 } 250 VariableAttributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS; 251 } 252 253 return gRT->SetVariable ( 254 OptionName, 255 &gEfiGlobalVariableGuid, 256 VariableAttributes, 257 VariableSize, 258 Variable 259 ); 260 } 261 262 /** 263 Update order variable . 264 265 @param OptionOrderName Order variable name which need to be updated. 266 @param OptionNumber Option number for the new option. 267 @param Position Position of the new load option to put in the ****Order variable. 268 269 @retval EFI_SUCCESS The boot#### or driver#### have been successfully registered. 270 @retval EFI_ALREADY_STARTED The option number of Option is being used already. 271 @retval EFI_STATUS Return the status of gRT->SetVariable (). 272 273 **/ 274 EFI_STATUS 275 BmAddOptionNumberToOrderVariable ( 276 IN CHAR16 *OptionOrderName, 277 IN UINT16 OptionNumber, 278 IN UINTN Position 279 ) 280 { 281 EFI_STATUS Status; 282 UINTN Index; 283 UINT16 *OptionOrder; 284 UINT16 *NewOptionOrder; 285 UINTN OptionOrderSize; 286 // 287 // Update the option order variable 288 // 289 GetEfiGlobalVariable2 (OptionOrderName, (VOID **) &OptionOrder, &OptionOrderSize); 290 ASSERT ((OptionOrder != NULL && OptionOrderSize != 0) || (OptionOrder == NULL && OptionOrderSize == 0)); 291 292 Status = EFI_SUCCESS; 293 for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) { 294 if (OptionOrder[Index] == OptionNumber) { 295 Status = EFI_ALREADY_STARTED; 296 break; 297 } 298 } 299 300 if (!EFI_ERROR (Status)) { 301 Position = MIN (Position, OptionOrderSize / sizeof (UINT16)); 302 303 NewOptionOrder = AllocatePool (OptionOrderSize + sizeof (UINT16)); 304 ASSERT (NewOptionOrder != NULL); 305 if (OptionOrderSize != 0) { 306 CopyMem (NewOptionOrder, OptionOrder, Position * sizeof (UINT16)); 307 CopyMem (&NewOptionOrder[Position + 1], &OptionOrder[Position], OptionOrderSize - Position * sizeof (UINT16)); 308 } 309 NewOptionOrder[Position] = OptionNumber; 310 311 Status = gRT->SetVariable ( 312 OptionOrderName, 313 &gEfiGlobalVariableGuid, 314 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, 315 OptionOrderSize + sizeof (UINT16), 316 NewOptionOrder 317 ); 318 FreePool (NewOptionOrder); 319 } 320 321 if (OptionOrder != NULL) { 322 FreePool (OptionOrder); 323 } 324 325 return Status; 326 } 327 328 /** 329 This function will register the new Boot####, Driver#### or SysPrep#### option. 330 After the *#### is updated, the *Order will also be updated. 331 332 @param Option Pointer to load option to add. 333 @param Position Position of the new load option to put in the ****Order variable. 334 335 @retval EFI_SUCCESS The *#### have been successfully registered. 336 @retval EFI_INVALID_PARAMETER The option number exceeds 0xFFFF. 337 @retval EFI_ALREADY_STARTED The option number of Option is being used already. 338 Note: this API only adds new load option, no replacement support. 339 @retval EFI_OUT_OF_RESOURCES There is no free option number that can be used when the 340 option number specified in the Option is LoadOptionNumberUnassigned. 341 @retval EFI_STATUS Return the status of gRT->SetVariable (). 342 343 **/ 344 EFI_STATUS 345 EFIAPI 346 EfiBootManagerAddLoadOptionVariable ( 347 IN EFI_BOOT_MANAGER_LOAD_OPTION *Option, 348 IN UINTN Position 349 ) 350 { 351 EFI_STATUS Status; 352 UINT16 OptionNumber; 353 354 if (Option == NULL) { 355 return EFI_INVALID_PARAMETER; 356 } 357 358 if (Option->OptionType != LoadOptionTypeDriver && 359 Option->OptionType != LoadOptionTypeSysPrep && 360 Option->OptionType != LoadOptionTypeBoot 361 ) { 362 return EFI_INVALID_PARAMETER; 363 } 364 365 // 366 // Get the free option number if the option number is unassigned 367 // 368 if (Option->OptionNumber == LoadOptionNumberUnassigned) { 369 Status = BmGetFreeOptionNumber (Option->OptionType, &OptionNumber); 370 if (EFI_ERROR (Status)) { 371 return Status; 372 } 373 Option->OptionNumber = OptionNumber; 374 } 375 376 if (Option->OptionNumber >= LoadOptionNumberMax) { 377 return EFI_INVALID_PARAMETER; 378 } 379 380 Status = BmAddOptionNumberToOrderVariable (mBmLoadOptionOrderName[Option->OptionType], (UINT16) Option->OptionNumber, Position); 381 if (!EFI_ERROR (Status)) { 382 // 383 // Save the Boot#### or Driver#### variable 384 // 385 Status = EfiBootManagerLoadOptionToVariable (Option); 386 if (EFI_ERROR (Status)) { 387 // 388 // Remove the #### from *Order variable when the Driver####/SysPrep####/Boot#### cannot be saved. 389 // 390 EfiBootManagerDeleteLoadOptionVariable (Option->OptionNumber, Option->OptionType); 391 } 392 } 393 394 return Status; 395 } 396 397 /** 398 Sort the load option. The DriverOrder or BootOrder will be re-created to 399 reflect the new order. 400 401 @param OptionType Load option type 402 @param CompareFunction The comparator 403 **/ 404 VOID 405 EFIAPI 406 EfiBootManagerSortLoadOptionVariable ( 407 EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType, 408 SORT_COMPARE CompareFunction 409 ) 410 { 411 EFI_STATUS Status; 412 EFI_BOOT_MANAGER_LOAD_OPTION *LoadOption; 413 UINTN LoadOptionCount; 414 UINTN Index; 415 UINT16 *OptionOrder; 416 417 LoadOption = EfiBootManagerGetLoadOptions (&LoadOptionCount, OptionType); 418 419 // 420 // Insertion sort algorithm 421 // 422 PerformQuickSort ( 423 LoadOption, 424 LoadOptionCount, 425 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION), 426 CompareFunction 427 ); 428 429 // 430 // Create new ****Order variable 431 // 432 OptionOrder = AllocatePool (LoadOptionCount * sizeof (UINT16)); 433 ASSERT (OptionOrder != NULL); 434 for (Index = 0; Index < LoadOptionCount; Index++) { 435 OptionOrder[Index] = (UINT16) LoadOption[Index].OptionNumber; 436 } 437 438 Status = gRT->SetVariable ( 439 mBmLoadOptionOrderName[OptionType], 440 &gEfiGlobalVariableGuid, 441 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, 442 LoadOptionCount * sizeof (UINT16), 443 OptionOrder 444 ); 445 // 446 // Changing the *Order content without increasing its size with current variable implementation shouldn't fail. 447 // 448 ASSERT_EFI_ERROR (Status); 449 450 FreePool (OptionOrder); 451 EfiBootManagerFreeLoadOptions (LoadOption, LoadOptionCount); 452 } 453 454 /** 455 Initialize a load option. 456 457 @param Option Pointer to the load option to be initialized. 458 @param OptionNumber Option number of the load option. 459 @param OptionType Type of the load option. 460 @param Attributes Attributes of the load option. 461 @param Description Description of the load option. 462 @param FilePath Device path of the load option. 463 @param OptionalData Optional data of the load option. 464 @param OptionalDataSize Size of the optional data of the load option. 465 466 @retval EFI_SUCCESS The load option was initialized successfully. 467 @retval EFI_INVALID_PARAMETER Option, Description or FilePath is NULL. 468 **/ 469 EFI_STATUS 470 EFIAPI 471 EfiBootManagerInitializeLoadOption ( 472 IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *Option, 473 IN UINTN OptionNumber, 474 IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType, 475 IN UINT32 Attributes, 476 IN CHAR16 *Description, 477 IN EFI_DEVICE_PATH_PROTOCOL *FilePath, 478 IN UINT8 *OptionalData, OPTIONAL 479 IN UINT32 OptionalDataSize 480 ) 481 { 482 if ((Option == NULL) || (Description == NULL) || (FilePath == NULL)) { 483 return EFI_INVALID_PARAMETER; 484 } 485 486 if (((OptionalData != NULL) && (OptionalDataSize == 0)) || 487 ((OptionalData == NULL) && (OptionalDataSize != 0))) { 488 return EFI_INVALID_PARAMETER; 489 } 490 491 if ((UINT32) OptionType >= LoadOptionTypeMax) { 492 return EFI_INVALID_PARAMETER; 493 } 494 495 ZeroMem (Option, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION)); 496 Option->OptionNumber = OptionNumber; 497 Option->OptionType = OptionType; 498 Option->Attributes = Attributes; 499 Option->Description = AllocateCopyPool (StrSize (Description), Description); 500 Option->FilePath = DuplicateDevicePath (FilePath); 501 if (OptionalData != NULL) { 502 Option->OptionalData = AllocateCopyPool (OptionalDataSize, OptionalData); 503 Option->OptionalDataSize = OptionalDataSize; 504 } 505 506 return EFI_SUCCESS; 507 } 508 509 510 /** 511 Return the index of the load option in the load option array. 512 513 The function consider two load options are equal when the 514 OptionType, Attributes, Description, FilePath and OptionalData are equal. 515 516 @param Key Pointer to the load option to be found. 517 @param Array Pointer to the array of load options to be found. 518 @param Count Number of entries in the Array. 519 520 @retval -1 Key wasn't found in the Array. 521 @retval 0 ~ Count-1 The index of the Key in the Array. 522 **/ 523 INTN 524 EFIAPI 525 EfiBootManagerFindLoadOption ( 526 IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Key, 527 IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Array, 528 IN UINTN Count 529 ) 530 { 531 UINTN Index; 532 533 for (Index = 0; Index < Count; Index++) { 534 if ((Key->OptionType == Array[Index].OptionType) && 535 (Key->Attributes == Array[Index].Attributes) && 536 (StrCmp (Key->Description, Array[Index].Description) == 0) && 537 (CompareMem (Key->FilePath, Array[Index].FilePath, GetDevicePathSize (Key->FilePath)) == 0) && 538 (Key->OptionalDataSize == Array[Index].OptionalDataSize) && 539 (CompareMem (Key->OptionalData, Array[Index].OptionalData, Key->OptionalDataSize) == 0)) { 540 return (INTN) Index; 541 } 542 } 543 544 return -1; 545 } 546 547 /** 548 Delete the load option. 549 550 @param OptionNumber Indicate the option number of load option 551 @param OptionType Indicate the type of load option 552 553 @retval EFI_INVALID_PARAMETER OptionType or OptionNumber is invalid. 554 @retval EFI_NOT_FOUND The load option cannot be found 555 @retval EFI_SUCCESS The load option was deleted 556 @retval others Status of RT->SetVariable() 557 **/ 558 EFI_STATUS 559 EFIAPI 560 EfiBootManagerDeleteLoadOptionVariable ( 561 IN UINTN OptionNumber, 562 IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType 563 ) 564 { 565 UINT16 *OptionOrder; 566 UINTN OptionOrderSize; 567 UINTN Index; 568 CHAR16 OptionName[BM_OPTION_NAME_LEN]; 569 570 if (((UINT32) OptionType >= LoadOptionTypeMax) || (OptionNumber >= LoadOptionNumberMax)) { 571 return EFI_INVALID_PARAMETER; 572 } 573 574 if (OptionType == LoadOptionTypeDriver || OptionType == LoadOptionTypeSysPrep || OptionType == LoadOptionTypeBoot) { 575 // 576 // If the associated *Order exists, firstly remove the reference in *Order for 577 // Driver####, SysPrep#### and Boot####. 578 // 579 GetEfiGlobalVariable2 (mBmLoadOptionOrderName[OptionType], (VOID **) &OptionOrder, &OptionOrderSize); 580 ASSERT ((OptionOrder != NULL && OptionOrderSize != 0) || (OptionOrder == NULL && OptionOrderSize == 0)); 581 582 for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) { 583 if (OptionOrder[Index] == OptionNumber) { 584 OptionOrderSize -= sizeof (UINT16); 585 CopyMem (&OptionOrder[Index], &OptionOrder[Index + 1], OptionOrderSize - Index * sizeof (UINT16)); 586 gRT->SetVariable ( 587 mBmLoadOptionOrderName[OptionType], 588 &gEfiGlobalVariableGuid, 589 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, 590 OptionOrderSize, 591 OptionOrder 592 ); 593 break; 594 } 595 } 596 if (OptionOrder != NULL) { 597 FreePool (OptionOrder); 598 } 599 } 600 601 // 602 // Remove the Driver####, SysPrep####, Boot#### or PlatformRecovery#### itself. 603 // 604 UnicodeSPrint (OptionName, sizeof (OptionName), L"%s%04x", mBmLoadOptionName[OptionType], OptionNumber); 605 return gRT->SetVariable ( 606 OptionName, 607 &gEfiGlobalVariableGuid, 608 0, 609 0, 610 NULL 611 ); 612 } 613 614 /** 615 Returns the size of a device path in bytes. 616 617 This function returns the size, in bytes, of the device path data structure 618 specified by DevicePath including the end of device path node. If DevicePath 619 is NULL, then 0 is returned. If the length of the device path is bigger than 620 MaxSize, also return 0 to indicate this is an invalidate device path. 621 622 @param DevicePath A pointer to a device path data structure. 623 @param MaxSize Max valid device path size. If big than this size, 624 return error. 625 626 @retval 0 An invalid device path. 627 @retval Others The size of a device path in bytes. 628 629 **/ 630 UINTN 631 BmGetDevicePathSizeEx ( 632 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath, 633 IN UINTN MaxSize 634 ) 635 { 636 UINTN Size; 637 UINTN NodeSize; 638 639 if (DevicePath == NULL) { 640 return 0; 641 } 642 643 // 644 // Search for the end of the device path structure 645 // 646 Size = 0; 647 while (!IsDevicePathEnd (DevicePath)) { 648 NodeSize = DevicePathNodeLength (DevicePath); 649 if (NodeSize == 0) { 650 return 0; 651 } 652 Size += NodeSize; 653 if (Size > MaxSize) { 654 return 0; 655 } 656 DevicePath = NextDevicePathNode (DevicePath); 657 } 658 Size += DevicePathNodeLength (DevicePath); 659 if (Size > MaxSize) { 660 return 0; 661 } 662 663 return Size; 664 } 665 666 /** 667 Returns the length of a Null-terminated Unicode string. If the length is 668 bigger than MaxStringLen, return length 0 to indicate that this is an 669 invalidate string. 670 671 This function returns the number of Unicode characters in the Null-terminated 672 Unicode string specified by String. 673 674 If String is NULL, then ASSERT(). 675 If String is not aligned on a 16-bit boundary, then ASSERT(). 676 677 @param String A pointer to a Null-terminated Unicode string. 678 @param MaxStringLen Max string len in this string. 679 680 @retval 0 An invalid string. 681 @retval Others The length of String. 682 683 **/ 684 UINTN 685 BmStrSizeEx ( 686 IN CONST CHAR16 *String, 687 IN UINTN MaxStringLen 688 ) 689 { 690 UINTN Length; 691 692 ASSERT (String != NULL && MaxStringLen != 0); 693 ASSERT (((UINTN) String & BIT0) == 0); 694 695 for (Length = 0; *String != L'\0' && MaxStringLen != Length; String++, Length+=2); 696 697 if (*String != L'\0' && MaxStringLen == Length) { 698 return 0; 699 } 700 701 return Length + 2; 702 } 703 704 /** 705 Validate the Boot####, Driver####, SysPrep#### and PlatformRecovery#### 706 variable (VendorGuid/Name) 707 708 @param Variable The variable data. 709 @param VariableSize The variable size. 710 711 @retval TRUE The variable data is correct. 712 @retval FALSE The variable data is corrupted. 713 714 **/ 715 BOOLEAN 716 BmValidateOption ( 717 UINT8 *Variable, 718 UINTN VariableSize 719 ) 720 { 721 UINT16 FilePathSize; 722 EFI_DEVICE_PATH_PROTOCOL *DevicePath; 723 UINTN DescriptionSize; 724 725 if (VariableSize <= sizeof (UINT16) + sizeof (UINT32)) { 726 return FALSE; 727 } 728 729 // 730 // Skip the option attribute 731 // 732 Variable += sizeof (UINT32); 733 734 // 735 // Get the option's device path size 736 // 737 FilePathSize = ReadUnaligned16 ((UINT16 *) Variable); 738 Variable += sizeof (UINT16); 739 740 // 741 // Get the option's description string size 742 // 743 DescriptionSize = BmStrSizeEx ((CHAR16 *) Variable, VariableSize - sizeof (UINT16) - sizeof (UINT32)); 744 Variable += DescriptionSize; 745 746 // 747 // Get the option's device path 748 // 749 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Variable; 750 751 // 752 // Validation boot option variable. 753 // 754 if ((FilePathSize == 0) || (DescriptionSize == 0)) { 755 return FALSE; 756 } 757 758 if (sizeof (UINT32) + sizeof (UINT16) + DescriptionSize + FilePathSize > VariableSize) { 759 return FALSE; 760 } 761 762 return (BOOLEAN) (BmGetDevicePathSizeEx (DevicePath, FilePathSize) != 0); 763 } 764 765 /** 766 Check whether the VariableName is a valid load option variable name 767 and return the load option type and option number. 768 769 @param VariableName The name of the load option variable. 770 @param OptionType Return the load option type. 771 @param OptionNumber Return the load option number. 772 773 @retval TRUE The variable name is valid; The load option type and 774 load option number is returned. 775 @retval FALSE The variable name is NOT valid. 776 **/ 777 BOOLEAN 778 EFIAPI 779 EfiBootManagerIsValidLoadOptionVariableName ( 780 IN CHAR16 *VariableName, 781 OUT EFI_BOOT_MANAGER_LOAD_OPTION_TYPE *OptionType OPTIONAL, 782 OUT UINT16 *OptionNumber OPTIONAL 783 ) 784 { 785 UINTN VariableNameLen; 786 UINTN Index; 787 UINTN Uint; 788 789 if (VariableName == NULL) { 790 return FALSE; 791 } 792 793 VariableNameLen = StrLen (VariableName); 794 795 if (VariableNameLen <= 4) { 796 return FALSE; 797 } 798 799 for (Index = 0; Index < ARRAY_SIZE (mBmLoadOptionName); Index++) { 800 if ((VariableNameLen - 4 == StrLen (mBmLoadOptionName[Index])) && 801 (StrnCmp (VariableName, mBmLoadOptionName[Index], VariableNameLen - 4) == 0) 802 ) { 803 break; 804 } 805 } 806 807 if (Index == ARRAY_SIZE (mBmLoadOptionName)) { 808 return FALSE; 809 } 810 811 if (OptionType != NULL) { 812 *OptionType = (EFI_BOOT_MANAGER_LOAD_OPTION_TYPE) Index; 813 } 814 815 if (OptionNumber != NULL) { 816 *OptionNumber = 0; 817 for (Index = VariableNameLen - 4; Index < VariableNameLen; Index++) { 818 Uint = BmCharToUint (VariableName[Index]); 819 if (Uint == -1) { 820 break; 821 } else { 822 *OptionNumber = (UINT16) Uint + *OptionNumber * 0x10; 823 } 824 } 825 } 826 827 return (BOOLEAN) (Index == VariableNameLen); 828 } 829 830 /** 831 Build the Boot#### or Driver#### option from the VariableName. 832 833 @param VariableName Variable name of the load option 834 @param VendorGuid Variable GUID of the load option 835 @param Option Return the load option. 836 837 @retval EFI_SUCCESS Get the option just been created 838 @retval EFI_NOT_FOUND Failed to get the new option 839 840 **/ 841 EFI_STATUS 842 EFIAPI 843 EfiBootManagerVariableToLoadOptionEx ( 844 IN CHAR16 *VariableName, 845 IN EFI_GUID *VendorGuid, 846 IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *Option 847 ) 848 { 849 EFI_STATUS Status; 850 UINT32 Attribute; 851 UINT16 FilePathSize; 852 UINT8 *Variable; 853 UINT8 *VariablePtr; 854 UINTN VariableSize; 855 EFI_DEVICE_PATH_PROTOCOL *FilePath; 856 UINT8 *OptionalData; 857 UINT32 OptionalDataSize; 858 CHAR16 *Description; 859 EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType; 860 UINT16 OptionNumber; 861 862 if ((VariableName == NULL) || (Option == NULL)) { 863 return EFI_INVALID_PARAMETER; 864 } 865 866 if (!EfiBootManagerIsValidLoadOptionVariableName (VariableName, &OptionType, &OptionNumber)) { 867 return EFI_INVALID_PARAMETER; 868 } 869 870 // 871 // Read the variable 872 // 873 GetVariable2 (VariableName, VendorGuid, (VOID **) &Variable, &VariableSize); 874 if (Variable == NULL) { 875 return EFI_NOT_FOUND; 876 } 877 878 // 879 // Validate *#### variable data. 880 // 881 if (!BmValidateOption(Variable, VariableSize)) { 882 FreePool (Variable); 883 return EFI_INVALID_PARAMETER; 884 } 885 886 // 887 // Get the option attribute 888 // 889 VariablePtr = Variable; 890 Attribute = ReadUnaligned32 ((UINT32 *) VariablePtr); 891 VariablePtr += sizeof (UINT32); 892 893 // 894 // Get the option's device path size 895 // 896 FilePathSize = ReadUnaligned16 ((UINT16 *) VariablePtr); 897 VariablePtr += sizeof (UINT16); 898 899 // 900 // Get the option's description string 901 // 902 Description = (CHAR16 *) VariablePtr; 903 904 // 905 // Get the option's description string size 906 // 907 VariablePtr += StrSize ((CHAR16 *) VariablePtr); 908 909 // 910 // Get the option's device path 911 // 912 FilePath = (EFI_DEVICE_PATH_PROTOCOL *) VariablePtr; 913 VariablePtr += FilePathSize; 914 915 OptionalDataSize = (UINT32) (VariableSize - (UINTN) (VariablePtr - Variable)); 916 if (OptionalDataSize == 0) { 917 OptionalData = NULL; 918 } else { 919 OptionalData = VariablePtr; 920 } 921 922 Status = EfiBootManagerInitializeLoadOption ( 923 Option, 924 OptionNumber, 925 OptionType, 926 Attribute, 927 Description, 928 FilePath, 929 OptionalData, 930 OptionalDataSize 931 ); 932 ASSERT_EFI_ERROR (Status); 933 934 CopyGuid (&Option->VendorGuid, VendorGuid); 935 936 FreePool (Variable); 937 return Status; 938 } 939 940 /** 941 Build the Boot#### or Driver#### option from the VariableName. 942 943 @param VariableName EFI Variable name indicate if it is Boot#### or Driver#### 944 @param Option Return the Boot#### or Driver#### option. 945 946 @retval EFI_SUCCESS Get the option just been created 947 @retval EFI_NOT_FOUND Failed to get the new option 948 **/ 949 EFI_STATUS 950 EFIAPI 951 EfiBootManagerVariableToLoadOption ( 952 IN CHAR16 *VariableName, 953 IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *Option 954 ) 955 { 956 return EfiBootManagerVariableToLoadOptionEx (VariableName, &gEfiGlobalVariableGuid, Option); 957 } 958 959 typedef struct { 960 EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType; 961 EFI_GUID *Guid; 962 EFI_BOOT_MANAGER_LOAD_OPTION *Options; 963 UINTN OptionCount; 964 } BM_COLLECT_LOAD_OPTIONS_PARAM; 965 966 /** 967 Visitor function to collect the Platform Recovery load options or OS Recovery 968 load options from NV storage. 969 970 @param Name Variable name. 971 @param Guid Variable GUID. 972 @param Context The same context passed to BmForEachVariable. 973 **/ 974 VOID 975 BmCollectLoadOptions ( 976 IN CHAR16 *Name, 977 IN EFI_GUID *Guid, 978 IN VOID *Context 979 ) 980 { 981 EFI_STATUS Status; 982 EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType; 983 UINT16 OptionNumber; 984 EFI_BOOT_MANAGER_LOAD_OPTION Option; 985 UINTN Index; 986 BM_COLLECT_LOAD_OPTIONS_PARAM *Param; 987 988 Param = (BM_COLLECT_LOAD_OPTIONS_PARAM *) Context; 989 990 if (CompareGuid (Guid, Param->Guid) && ( 991 Param->OptionType == LoadOptionTypePlatformRecovery && 992 EfiBootManagerIsValidLoadOptionVariableName (Name, &OptionType, &OptionNumber) && 993 OptionType == LoadOptionTypePlatformRecovery 994 )) { 995 Status = EfiBootManagerVariableToLoadOptionEx (Name, Guid, &Option); 996 if (!EFI_ERROR (Status)) { 997 for (Index = 0; Index < Param->OptionCount; Index++) { 998 if (Param->Options[Index].OptionNumber > Option.OptionNumber) { 999 break; 1000 } 1001 } 1002 Param->Options = ReallocatePool ( 1003 Param->OptionCount * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION), 1004 (Param->OptionCount + 1) * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION), 1005 Param->Options 1006 ); 1007 ASSERT (Param->Options != NULL); 1008 CopyMem (&Param->Options[Index + 1], &Param->Options[Index], (Param->OptionCount - Index) * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION)); 1009 CopyMem (&Param->Options[Index], &Option, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION)); 1010 Param->OptionCount++; 1011 } 1012 } 1013 } 1014 1015 /** 1016 Returns an array of load options based on the EFI variable 1017 L"BootOrder"/L"DriverOrder" and the L"Boot####"/L"Driver####" variables impled by it. 1018 #### is the hex value of the UINT16 in each BootOrder/DriverOrder entry. 1019 1020 @param LoadOptionCount Returns number of entries in the array. 1021 @param LoadOptionType The type of the load option. 1022 1023 @retval NULL No load options exist. 1024 @retval !NULL Array of load option entries. 1025 1026 **/ 1027 EFI_BOOT_MANAGER_LOAD_OPTION * 1028 EFIAPI 1029 EfiBootManagerGetLoadOptions ( 1030 OUT UINTN *OptionCount, 1031 IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType 1032 ) 1033 { 1034 EFI_STATUS Status; 1035 UINT16 *OptionOrder; 1036 UINTN OptionOrderSize; 1037 UINTN Index; 1038 UINTN OptionIndex; 1039 EFI_BOOT_MANAGER_LOAD_OPTION *Options; 1040 CHAR16 OptionName[BM_OPTION_NAME_LEN]; 1041 UINT16 OptionNumber; 1042 BM_COLLECT_LOAD_OPTIONS_PARAM Param; 1043 1044 *OptionCount = 0; 1045 Options = NULL; 1046 1047 if (LoadOptionType == LoadOptionTypeDriver || LoadOptionType == LoadOptionTypeSysPrep || LoadOptionType == LoadOptionTypeBoot) { 1048 // 1049 // Read the BootOrder, or DriverOrder variable. 1050 // 1051 GetEfiGlobalVariable2 (mBmLoadOptionOrderName[LoadOptionType], (VOID **) &OptionOrder, &OptionOrderSize); 1052 if (OptionOrder == NULL) { 1053 return NULL; 1054 } 1055 1056 *OptionCount = OptionOrderSize / sizeof (UINT16); 1057 1058 Options = AllocatePool (*OptionCount * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION)); 1059 ASSERT (Options != NULL); 1060 1061 OptionIndex = 0; 1062 for (Index = 0; Index < *OptionCount; Index++) { 1063 OptionNumber = OptionOrder[Index]; 1064 UnicodeSPrint (OptionName, sizeof (OptionName), L"%s%04x", mBmLoadOptionName[LoadOptionType], OptionNumber); 1065 1066 Status = EfiBootManagerVariableToLoadOption (OptionName, &Options[OptionIndex]); 1067 if (EFI_ERROR (Status)) { 1068 DEBUG ((EFI_D_INFO, "[Bds] %s doesn't exist - Update ****Order variable to remove the reference!!", OptionName)); 1069 EfiBootManagerDeleteLoadOptionVariable (OptionNumber, LoadOptionType); 1070 } else { 1071 ASSERT (Options[OptionIndex].OptionNumber == OptionNumber); 1072 OptionIndex++; 1073 } 1074 } 1075 1076 if (OptionOrder != NULL) { 1077 FreePool (OptionOrder); 1078 } 1079 1080 if (OptionIndex < *OptionCount) { 1081 Options = ReallocatePool (*OptionCount * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION), OptionIndex * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION), Options); 1082 ASSERT (Options != NULL); 1083 *OptionCount = OptionIndex; 1084 } 1085 1086 } else if (LoadOptionType == LoadOptionTypePlatformRecovery) { 1087 Param.OptionType = LoadOptionTypePlatformRecovery; 1088 Param.Options = NULL; 1089 Param.OptionCount = 0; 1090 Param.Guid = &gEfiGlobalVariableGuid; 1091 1092 BmForEachVariable (BmCollectLoadOptions, (VOID *) &Param); 1093 1094 *OptionCount = Param.OptionCount; 1095 Options = Param.Options; 1096 } 1097 1098 return Options; 1099 } 1100 1101 /** 1102 Free an EFI_BOOT_MANGER_LOAD_OPTION entry that was allocate by the library. 1103 1104 @param LoadOption Pointer to boot option to Free. 1105 1106 @return EFI_SUCCESS BootOption was freed 1107 @return EFI_NOT_FOUND BootOption == NULL 1108 1109 **/ 1110 EFI_STATUS 1111 EFIAPI 1112 EfiBootManagerFreeLoadOption ( 1113 IN EFI_BOOT_MANAGER_LOAD_OPTION *LoadOption 1114 ) 1115 { 1116 if (LoadOption == NULL) { 1117 return EFI_NOT_FOUND; 1118 } 1119 1120 if (LoadOption->Description != NULL) { 1121 FreePool (LoadOption->Description); 1122 } 1123 if (LoadOption->FilePath != NULL) { 1124 FreePool (LoadOption->FilePath); 1125 } 1126 if (LoadOption->OptionalData != NULL) { 1127 FreePool (LoadOption->OptionalData); 1128 } 1129 1130 return EFI_SUCCESS; 1131 } 1132 1133 /** 1134 Free an EFI_BOOT_MANGER_LOAD_OPTION array that was allocated by 1135 EfiBootManagerGetLoadOptions(). 1136 1137 @param Option Pointer to boot option array to free. 1138 @param OptionCount Number of array entries in BootOption 1139 1140 @return EFI_SUCCESS BootOption was freed 1141 @return EFI_NOT_FOUND BootOption == NULL 1142 1143 **/ 1144 EFI_STATUS 1145 EFIAPI 1146 EfiBootManagerFreeLoadOptions ( 1147 IN EFI_BOOT_MANAGER_LOAD_OPTION *Option, 1148 IN UINTN OptionCount 1149 ) 1150 { 1151 UINTN Index; 1152 1153 if (Option == NULL) { 1154 return EFI_NOT_FOUND; 1155 } 1156 1157 for (Index = 0;Index < OptionCount; Index++) { 1158 EfiBootManagerFreeLoadOption (&Option[Index]); 1159 } 1160 1161 FreePool (Option); 1162 1163 return EFI_SUCCESS; 1164 } 1165 1166 /** 1167 Return whether the PE header of the load option is valid or not. 1168 1169 @param[in] Type The load option type. 1170 @param[in] FileBuffer The PE file buffer of the load option. 1171 @param[in] FileSize The size of the load option file. 1172 1173 @retval TRUE The PE header of the load option is valid. 1174 @retval FALSE The PE header of the load option is not valid. 1175 **/ 1176 BOOLEAN 1177 BmIsLoadOptionPeHeaderValid ( 1178 IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE Type, 1179 IN VOID *FileBuffer, 1180 IN UINTN FileSize 1181 ) 1182 { 1183 EFI_IMAGE_DOS_HEADER *DosHeader; 1184 EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHeader; 1185 EFI_IMAGE_OPTIONAL_HEADER32 *OptionalHeader; 1186 UINT16 Subsystem; 1187 1188 if (FileBuffer == NULL || FileSize == 0) { 1189 return FALSE; 1190 } 1191 1192 // 1193 // Read dos header 1194 // 1195 DosHeader = (EFI_IMAGE_DOS_HEADER *) FileBuffer; 1196 if (FileSize >= sizeof (EFI_IMAGE_DOS_HEADER) && 1197 FileSize > DosHeader->e_lfanew && DosHeader->e_magic == EFI_IMAGE_DOS_SIGNATURE 1198 ) { 1199 // 1200 // Read and check PE signature 1201 // 1202 PeHeader = (EFI_IMAGE_OPTIONAL_HEADER_UNION *) ((UINT8 *) FileBuffer + DosHeader->e_lfanew); 1203 if (FileSize >= DosHeader->e_lfanew + sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION) && 1204 PeHeader->Pe32.Signature == EFI_IMAGE_NT_SIGNATURE 1205 ) { 1206 // 1207 // Check PE32 or PE32+ magic, and machine type 1208 // 1209 OptionalHeader = (EFI_IMAGE_OPTIONAL_HEADER32 *) &PeHeader->Pe32.OptionalHeader; 1210 if ((OptionalHeader->Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC || 1211 OptionalHeader->Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) && 1212 EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeHeader->Pe32.FileHeader.Machine) 1213 ) { 1214 // 1215 // Check the Subsystem: 1216 // Driver#### must be of type BootServiceDriver or RuntimeDriver 1217 // SysPrep####, Boot####, OsRecovery####, PlatformRecovery#### must be of type Application 1218 // 1219 Subsystem = OptionalHeader->Subsystem; 1220 if ((Type == LoadOptionTypeDriver && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) || 1221 (Type == LoadOptionTypeDriver && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) || 1222 (Type == LoadOptionTypeSysPrep && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) || 1223 (Type == LoadOptionTypeBoot && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) || 1224 (Type == LoadOptionTypePlatformRecovery && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) 1225 ) { 1226 return TRUE; 1227 } 1228 } 1229 } 1230 } 1231 1232 return FALSE; 1233 } 1234 1235 /** 1236 Process (load and execute) the load option. 1237 1238 @param LoadOption Pointer to the load option. 1239 1240 @retval EFI_INVALID_PARAMETER The load option type is invalid, 1241 or the load option file path doesn't point to a valid file. 1242 @retval EFI_UNSUPPORTED The load option type is of LoadOptionTypeBoot. 1243 @retval EFI_SUCCESS The load option is inactive, or successfully loaded and executed. 1244 **/ 1245 EFI_STATUS 1246 EFIAPI 1247 EfiBootManagerProcessLoadOption ( 1248 IN EFI_BOOT_MANAGER_LOAD_OPTION *LoadOption 1249 ) 1250 { 1251 EFI_STATUS Status; 1252 EFI_DEVICE_PATH_PROTOCOL *FilePath; 1253 EFI_HANDLE ImageHandle; 1254 EFI_LOADED_IMAGE_PROTOCOL *ImageInfo; 1255 VOID *FileBuffer; 1256 UINTN FileSize; 1257 1258 if ((UINT32) LoadOption->OptionType >= LoadOptionTypeMax) { 1259 return EFI_INVALID_PARAMETER; 1260 } 1261 1262 if (LoadOption->OptionType == LoadOptionTypeBoot) { 1263 return EFI_UNSUPPORTED; 1264 } 1265 1266 // 1267 // If a load option is not marked as LOAD_OPTION_ACTIVE, 1268 // the boot manager will not automatically load the option. 1269 // 1270 if ((LoadOption->Attributes & LOAD_OPTION_ACTIVE) == 0) { 1271 return EFI_SUCCESS; 1272 } 1273 1274 Status = EFI_INVALID_PARAMETER; 1275 1276 // 1277 // Load and start the load option. 1278 // 1279 DEBUG (( 1280 DEBUG_INFO | DEBUG_LOAD, "Process %s%04x (%s) ...\n", 1281 mBmLoadOptionName[LoadOption->OptionType], LoadOption->OptionNumber, 1282 LoadOption->Description 1283 )); 1284 ImageHandle = NULL; 1285 FileBuffer = EfiBootManagerGetLoadOptionBuffer (LoadOption->FilePath, &FilePath, &FileSize); 1286 DEBUG_CODE ( 1287 if (FileBuffer != NULL && CompareMem (LoadOption->FilePath, FilePath, GetDevicePathSize (FilePath)) != 0) { 1288 DEBUG ((EFI_D_INFO, "[Bds] DevicePath expand: ")); 1289 BmPrintDp (LoadOption->FilePath); 1290 DEBUG ((EFI_D_INFO, " -> ")); 1291 BmPrintDp (FilePath); 1292 DEBUG ((EFI_D_INFO, "\n")); 1293 } 1294 ); 1295 if (BmIsLoadOptionPeHeaderValid (LoadOption->OptionType, FileBuffer, FileSize)) { 1296 Status = gBS->LoadImage ( 1297 FALSE, 1298 gImageHandle, 1299 FilePath, 1300 FileBuffer, 1301 FileSize, 1302 &ImageHandle 1303 ); 1304 } 1305 if (FilePath != NULL) { 1306 FreePool (FilePath); 1307 } 1308 if (FileBuffer != NULL) { 1309 FreePool (FileBuffer); 1310 } 1311 1312 if (!EFI_ERROR (Status)) { 1313 Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo); 1314 ASSERT_EFI_ERROR (Status); 1315 1316 ImageInfo->LoadOptionsSize = LoadOption->OptionalDataSize; 1317 ImageInfo->LoadOptions = LoadOption->OptionalData; 1318 // 1319 // Before calling the image, enable the Watchdog Timer for the 5-minute period 1320 // 1321 gBS->SetWatchdogTimer (5 * 60, 0, 0, NULL); 1322 1323 LoadOption->Status = gBS->StartImage (ImageHandle, &LoadOption->ExitDataSize, &LoadOption->ExitData); 1324 DEBUG (( 1325 DEBUG_INFO | DEBUG_LOAD, "%s%04x Return Status = %r\n", 1326 mBmLoadOptionName[LoadOption->OptionType], LoadOption->OptionNumber, LoadOption->Status 1327 )); 1328 1329 // 1330 // Clear the Watchdog Timer after the image returns 1331 // 1332 gBS->SetWatchdogTimer (0, 0, 0, NULL); 1333 } 1334 1335 return Status; 1336 } 1337