Home | History | Annotate | Download | only in UefiBootManagerLib
      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