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 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 BmIsValidLoadOptionVariableName (
    779   IN CHAR16                             *VariableName,
    780   OUT EFI_BOOT_MANAGER_LOAD_OPTION_TYPE *OptionType,
    781   OUT UINT16                            *OptionNumber
    782   )
    783 {
    784   UINTN                             VariableNameLen;
    785   UINTN                             Index;
    786   UINTN                             Uint;
    787 
    788   VariableNameLen = StrLen (VariableName);
    789 
    790   if (VariableNameLen <= 4) {
    791     return FALSE;
    792   }
    793 
    794   for (Index = 0; Index < sizeof (mBmLoadOptionName) / sizeof (mBmLoadOptionName[0]); Index++) {
    795     if ((VariableNameLen - 4 == StrLen (mBmLoadOptionName[Index])) &&
    796         (StrnCmp (VariableName, mBmLoadOptionName[Index], VariableNameLen - 4) == 0)
    797         ) {
    798       break;
    799     }
    800   }
    801 
    802   if (Index == sizeof (mBmLoadOptionName) / sizeof (mBmLoadOptionName[0])) {
    803     return FALSE;
    804   }
    805 
    806   *OptionType = (EFI_BOOT_MANAGER_LOAD_OPTION_TYPE) Index;
    807   *OptionNumber = 0;
    808   for (Index = VariableNameLen - 4; Index < VariableNameLen; Index++) {
    809     Uint = BmCharToUint (VariableName[Index]);
    810     if (Uint == -1) {
    811       break;
    812     } else {
    813       *OptionNumber = (UINT16) Uint + *OptionNumber * 0x10;
    814     }
    815   }
    816 
    817   return (BOOLEAN) (Index == VariableNameLen);
    818 }
    819 
    820 /**
    821   Build the Boot#### or Driver#### option from the VariableName.
    822 
    823   @param  VariableName          Variable name of the load option
    824   @param  VendorGuid            Variable GUID of the load option
    825   @param  Option                Return the load option.
    826 
    827   @retval EFI_SUCCESS     Get the option just been created
    828   @retval EFI_NOT_FOUND   Failed to get the new option
    829 
    830 **/
    831 EFI_STATUS
    832 EFIAPI
    833 EfiBootManagerVariableToLoadOptionEx (
    834   IN CHAR16                           *VariableName,
    835   IN EFI_GUID                         *VendorGuid,
    836   IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *Option
    837   )
    838 {
    839   EFI_STATUS                         Status;
    840   UINT32                             Attribute;
    841   UINT16                             FilePathSize;
    842   UINT8                              *Variable;
    843   UINT8                              *VariablePtr;
    844   UINTN                              VariableSize;
    845   EFI_DEVICE_PATH_PROTOCOL           *FilePath;
    846   UINT8                              *OptionalData;
    847   UINT32                             OptionalDataSize;
    848   CHAR16                             *Description;
    849   EFI_BOOT_MANAGER_LOAD_OPTION_TYPE  OptionType;
    850   UINT16                             OptionNumber;
    851 
    852   if ((VariableName == NULL) || (Option == NULL)) {
    853     return EFI_INVALID_PARAMETER;
    854   }
    855 
    856   if (!BmIsValidLoadOptionVariableName (VariableName, &OptionType, &OptionNumber)) {
    857     return EFI_INVALID_PARAMETER;
    858   }
    859 
    860   //
    861   // Read the variable
    862   //
    863   GetVariable2 (VariableName, VendorGuid, (VOID **) &Variable, &VariableSize);
    864   if (Variable == NULL) {
    865     return EFI_NOT_FOUND;
    866   }
    867 
    868   //
    869   // Validate *#### variable data.
    870   //
    871   if (!BmValidateOption(Variable, VariableSize)) {
    872     FreePool (Variable);
    873     return EFI_INVALID_PARAMETER;
    874   }
    875 
    876   //
    877   // Get the option attribute
    878   //
    879   VariablePtr = Variable;
    880   Attribute = ReadUnaligned32 ((UINT32 *) VariablePtr);
    881   VariablePtr += sizeof (UINT32);
    882 
    883   //
    884   // Get the option's device path size
    885   //
    886   FilePathSize = ReadUnaligned16 ((UINT16 *) VariablePtr);
    887   VariablePtr += sizeof (UINT16);
    888 
    889   //
    890   // Get the option's description string
    891   //
    892   Description = (CHAR16 *) VariablePtr;
    893 
    894   //
    895   // Get the option's description string size
    896   //
    897   VariablePtr += StrSize ((CHAR16 *) VariablePtr);
    898 
    899   //
    900   // Get the option's device path
    901   //
    902   FilePath = (EFI_DEVICE_PATH_PROTOCOL *) VariablePtr;
    903   VariablePtr += FilePathSize;
    904 
    905   OptionalDataSize = (UINT32) (VariableSize - (UINTN) (VariablePtr - Variable));
    906   if (OptionalDataSize == 0) {
    907     OptionalData = NULL;
    908   } else {
    909     OptionalData = VariablePtr;
    910   }
    911 
    912   Status = EfiBootManagerInitializeLoadOption (
    913              Option,
    914              OptionNumber,
    915              OptionType,
    916              Attribute,
    917              Description,
    918              FilePath,
    919              OptionalData,
    920              OptionalDataSize
    921              );
    922   ASSERT_EFI_ERROR (Status);
    923 
    924   CopyGuid (&Option->VendorGuid, VendorGuid);
    925 
    926   FreePool (Variable);
    927   return Status;
    928 }
    929 
    930 /**
    931 Build the Boot#### or Driver#### option from the VariableName.
    932 
    933 @param  VariableName          EFI Variable name indicate if it is Boot#### or Driver####
    934 @param  Option                Return the Boot#### or Driver#### option.
    935 
    936 @retval EFI_SUCCESS     Get the option just been created
    937 @retval EFI_NOT_FOUND   Failed to get the new option
    938 **/
    939 EFI_STATUS
    940 EFIAPI
    941 EfiBootManagerVariableToLoadOption (
    942   IN  CHAR16                          *VariableName,
    943   IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *Option
    944   )
    945 {
    946   return EfiBootManagerVariableToLoadOptionEx (VariableName, &gEfiGlobalVariableGuid, Option);
    947 }
    948 
    949 typedef struct {
    950   EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType;
    951   EFI_GUID                          *Guid;
    952   EFI_BOOT_MANAGER_LOAD_OPTION      *Options;
    953   UINTN                             OptionCount;
    954 } BM_COLLECT_LOAD_OPTIONS_PARAM;
    955 
    956 /**
    957   Visitor function to collect the Platform Recovery load options or OS Recovery
    958   load options from NV storage.
    959 
    960   @param Name    Variable name.
    961   @param Guid    Variable GUID.
    962   @param Context The same context passed to BmForEachVariable.
    963 **/
    964 VOID
    965 BmCollectLoadOptions (
    966   IN CHAR16               *Name,
    967   IN EFI_GUID             *Guid,
    968   IN VOID                 *Context
    969   )
    970 {
    971   EFI_STATUS                        Status;
    972   EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType;
    973   UINT16                            OptionNumber;
    974   EFI_BOOT_MANAGER_LOAD_OPTION      Option;
    975   UINTN                             Index;
    976   BM_COLLECT_LOAD_OPTIONS_PARAM     *Param;
    977 
    978   Param = (BM_COLLECT_LOAD_OPTIONS_PARAM *) Context;
    979 
    980   if (CompareGuid (Guid, Param->Guid) && (
    981       Param->OptionType == LoadOptionTypePlatformRecovery &&
    982       BmIsValidLoadOptionVariableName (Name, &OptionType, &OptionNumber) &&
    983       OptionType == LoadOptionTypePlatformRecovery
    984      )) {
    985     Status = EfiBootManagerVariableToLoadOptionEx (Name, Guid, &Option);
    986     if (!EFI_ERROR (Status)) {
    987       for (Index = 0; Index < Param->OptionCount; Index++) {
    988         if (Param->Options[Index].OptionNumber > Option.OptionNumber) {
    989           break;
    990         }
    991       }
    992       Param->Options = ReallocatePool (
    993                          Param->OptionCount * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION),
    994                          (Param->OptionCount + 1) * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION),
    995                          Param->Options
    996                          );
    997       ASSERT (Param->Options != NULL);
    998       CopyMem (&Param->Options[Index + 1], &Param->Options[Index], (Param->OptionCount - Index) * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
    999       CopyMem (&Param->Options[Index], &Option, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
   1000       Param->OptionCount++;
   1001     }
   1002   }
   1003 }
   1004 
   1005 /**
   1006   Returns an array of load options based on the EFI variable
   1007   L"BootOrder"/L"DriverOrder" and the L"Boot####"/L"Driver####" variables impled by it.
   1008   #### is the hex value of the UINT16 in each BootOrder/DriverOrder entry.
   1009 
   1010   @param  LoadOptionCount   Returns number of entries in the array.
   1011   @param  LoadOptionType    The type of the load option.
   1012 
   1013   @retval NULL  No load options exist.
   1014   @retval !NULL Array of load option entries.
   1015 
   1016 **/
   1017 EFI_BOOT_MANAGER_LOAD_OPTION *
   1018 EFIAPI
   1019 EfiBootManagerGetLoadOptions (
   1020   OUT UINTN                             *OptionCount,
   1021   IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE  LoadOptionType
   1022   )
   1023 {
   1024   EFI_STATUS                    Status;
   1025   UINT16                        *OptionOrder;
   1026   UINTN                         OptionOrderSize;
   1027   UINTN                         Index;
   1028   UINTN                         OptionIndex;
   1029   EFI_BOOT_MANAGER_LOAD_OPTION  *Options;
   1030   CHAR16                        OptionName[BM_OPTION_NAME_LEN];
   1031   UINT16                        OptionNumber;
   1032   BM_COLLECT_LOAD_OPTIONS_PARAM Param;
   1033 
   1034   *OptionCount = 0;
   1035   Options      = NULL;
   1036 
   1037   if (LoadOptionType == LoadOptionTypeDriver || LoadOptionType == LoadOptionTypeSysPrep || LoadOptionType == LoadOptionTypeBoot) {
   1038     //
   1039     // Read the BootOrder, or DriverOrder variable.
   1040     //
   1041     GetEfiGlobalVariable2 (mBmLoadOptionOrderName[LoadOptionType], (VOID **) &OptionOrder, &OptionOrderSize);
   1042     if (OptionOrder == NULL) {
   1043       return NULL;
   1044     }
   1045 
   1046     *OptionCount = OptionOrderSize / sizeof (UINT16);
   1047 
   1048     Options = AllocatePool (*OptionCount * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
   1049     ASSERT (Options != NULL);
   1050 
   1051     OptionIndex = 0;
   1052     for (Index = 0; Index < *OptionCount; Index++) {
   1053       OptionNumber = OptionOrder[Index];
   1054       UnicodeSPrint (OptionName, sizeof (OptionName), L"%s%04x", mBmLoadOptionName[LoadOptionType], OptionNumber);
   1055 
   1056       Status = EfiBootManagerVariableToLoadOption (OptionName, &Options[OptionIndex]);
   1057       if (EFI_ERROR (Status)) {
   1058         DEBUG ((EFI_D_INFO, "[Bds] %s doesn't exist - Update ****Order variable to remove the reference!!", OptionName));
   1059         EfiBootManagerDeleteLoadOptionVariable (OptionNumber, LoadOptionType);
   1060       } else {
   1061         ASSERT (Options[OptionIndex].OptionNumber == OptionNumber);
   1062         OptionIndex++;
   1063       }
   1064     }
   1065 
   1066     if (OptionOrder != NULL) {
   1067       FreePool (OptionOrder);
   1068     }
   1069 
   1070     if (OptionIndex < *OptionCount) {
   1071       Options = ReallocatePool (*OptionCount * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION), OptionIndex * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION), Options);
   1072       ASSERT (Options != NULL);
   1073       *OptionCount = OptionIndex;
   1074     }
   1075 
   1076   } else if (LoadOptionType == LoadOptionTypePlatformRecovery) {
   1077     Param.OptionType = LoadOptionTypePlatformRecovery;
   1078     Param.Options = NULL;
   1079     Param.OptionCount = 0;
   1080     Param.Guid = &gEfiGlobalVariableGuid;
   1081 
   1082     BmForEachVariable (BmCollectLoadOptions, (VOID *) &Param);
   1083 
   1084     *OptionCount = Param.OptionCount;
   1085     Options = Param.Options;
   1086   }
   1087 
   1088   return Options;
   1089 }
   1090 
   1091 /**
   1092   Free an EFI_BOOT_MANGER_LOAD_OPTION entry that was allocate by the library.
   1093 
   1094   @param  LoadOption   Pointer to boot option to Free.
   1095 
   1096   @return EFI_SUCCESS   BootOption was freed
   1097   @return EFI_NOT_FOUND BootOption == NULL
   1098 
   1099 **/
   1100 EFI_STATUS
   1101 EFIAPI
   1102 EfiBootManagerFreeLoadOption (
   1103   IN  EFI_BOOT_MANAGER_LOAD_OPTION  *LoadOption
   1104   )
   1105 {
   1106   if (LoadOption == NULL) {
   1107     return EFI_NOT_FOUND;
   1108   }
   1109 
   1110   if (LoadOption->Description != NULL) {
   1111     FreePool (LoadOption->Description);
   1112   }
   1113   if (LoadOption->FilePath != NULL) {
   1114     FreePool (LoadOption->FilePath);
   1115   }
   1116   if (LoadOption->OptionalData != NULL) {
   1117     FreePool (LoadOption->OptionalData);
   1118   }
   1119 
   1120   return EFI_SUCCESS;
   1121 }
   1122 
   1123 /**
   1124   Free an EFI_BOOT_MANGER_LOAD_OPTION array that was allocated by
   1125   EfiBootManagerGetLoadOptions().
   1126 
   1127   @param  Option       Pointer to boot option array to free.
   1128   @param  OptionCount  Number of array entries in BootOption
   1129 
   1130   @return EFI_SUCCESS   BootOption was freed
   1131   @return EFI_NOT_FOUND BootOption == NULL
   1132 
   1133 **/
   1134 EFI_STATUS
   1135 EFIAPI
   1136 EfiBootManagerFreeLoadOptions (
   1137   IN  EFI_BOOT_MANAGER_LOAD_OPTION  *Option,
   1138   IN  UINTN                         OptionCount
   1139   )
   1140 {
   1141   UINTN   Index;
   1142 
   1143   if (Option == NULL) {
   1144     return EFI_NOT_FOUND;
   1145   }
   1146 
   1147   for (Index = 0;Index < OptionCount; Index++) {
   1148     EfiBootManagerFreeLoadOption (&Option[Index]);
   1149   }
   1150 
   1151   FreePool (Option);
   1152 
   1153   return EFI_SUCCESS;
   1154 }
   1155 
   1156 /**
   1157   Return whether the PE header of the load option is valid or not.
   1158 
   1159   @param[in] Type       The load option type.
   1160   @param[in] FileBuffer The PE file buffer of the load option.
   1161   @param[in] FileSize   The size of the load option file.
   1162 
   1163   @retval TRUE  The PE header of the load option is valid.
   1164   @retval FALSE The PE header of the load option is not valid.
   1165 **/
   1166 BOOLEAN
   1167 BmIsLoadOptionPeHeaderValid (
   1168   IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE Type,
   1169   IN VOID                              *FileBuffer,
   1170   IN UINTN                             FileSize
   1171   )
   1172 {
   1173   EFI_IMAGE_DOS_HEADER              *DosHeader;
   1174   EFI_IMAGE_OPTIONAL_HEADER_UNION   *PeHeader;
   1175   EFI_IMAGE_OPTIONAL_HEADER32       *OptionalHeader;
   1176   UINT16                            Subsystem;
   1177 
   1178   if (FileBuffer == NULL || FileSize == 0) {
   1179     return FALSE;
   1180   }
   1181 
   1182   //
   1183   // Read dos header
   1184   //
   1185   DosHeader = (EFI_IMAGE_DOS_HEADER *) FileBuffer;
   1186   if (FileSize >= sizeof (EFI_IMAGE_DOS_HEADER) &&
   1187       FileSize > DosHeader->e_lfanew && DosHeader->e_magic == EFI_IMAGE_DOS_SIGNATURE
   1188       ) {
   1189     //
   1190     // Read and check PE signature
   1191     //
   1192     PeHeader = (EFI_IMAGE_OPTIONAL_HEADER_UNION *) ((UINT8 *) FileBuffer + DosHeader->e_lfanew);
   1193     if (FileSize >= DosHeader->e_lfanew + sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION) &&
   1194         PeHeader->Pe32.Signature == EFI_IMAGE_NT_SIGNATURE
   1195         ) {
   1196       //
   1197       // Check PE32 or PE32+ magic, and machine type
   1198       //
   1199       OptionalHeader = (EFI_IMAGE_OPTIONAL_HEADER32 *) &PeHeader->Pe32.OptionalHeader;
   1200       if ((OptionalHeader->Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC ||
   1201            OptionalHeader->Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) &&
   1202           EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeHeader->Pe32.FileHeader.Machine)
   1203           ) {
   1204         //
   1205         // Check the Subsystem:
   1206         //   Driver#### must be of type BootServiceDriver or RuntimeDriver
   1207         //   SysPrep####, Boot####, OsRecovery####, PlatformRecovery#### must be of type Application
   1208         //
   1209         Subsystem = OptionalHeader->Subsystem;
   1210         if ((Type == LoadOptionTypeDriver && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) ||
   1211             (Type == LoadOptionTypeDriver && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) ||
   1212             (Type == LoadOptionTypeSysPrep && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) ||
   1213             (Type == LoadOptionTypeBoot && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) ||
   1214             (Type == LoadOptionTypePlatformRecovery && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION)
   1215             ) {
   1216           return TRUE;
   1217         }
   1218       }
   1219     }
   1220   }
   1221 
   1222   return FALSE;
   1223 }
   1224 
   1225 /**
   1226   Process (load and execute) the load option.
   1227 
   1228   @param LoadOption  Pointer to the load option.
   1229 
   1230   @retval EFI_INVALID_PARAMETER  The load option type is invalid,
   1231                                  or the load option file path doesn't point to a valid file.
   1232   @retval EFI_UNSUPPORTED        The load option type is of LoadOptionTypeBoot.
   1233   @retval EFI_SUCCESS            The load option is inactive, or successfully loaded and executed.
   1234 **/
   1235 EFI_STATUS
   1236 EFIAPI
   1237 EfiBootManagerProcessLoadOption (
   1238   IN EFI_BOOT_MANAGER_LOAD_OPTION       *LoadOption
   1239   )
   1240 {
   1241   EFI_STATUS                        Status;
   1242   EFI_DEVICE_PATH_PROTOCOL          *FilePath;
   1243   EFI_HANDLE                        ImageHandle;
   1244   EFI_LOADED_IMAGE_PROTOCOL         *ImageInfo;
   1245   VOID                              *FileBuffer;
   1246   UINTN                             FileSize;
   1247 
   1248   if ((UINT32) LoadOption->OptionType >= LoadOptionTypeMax) {
   1249     return EFI_INVALID_PARAMETER;
   1250   }
   1251 
   1252   if (LoadOption->OptionType == LoadOptionTypeBoot) {
   1253     return EFI_UNSUPPORTED;
   1254   }
   1255 
   1256   //
   1257   // If a load option is not marked as LOAD_OPTION_ACTIVE,
   1258   // the boot manager will not automatically load the option.
   1259   //
   1260   if ((LoadOption->Attributes & LOAD_OPTION_ACTIVE) == 0) {
   1261     return EFI_SUCCESS;
   1262   }
   1263 
   1264   Status = EFI_INVALID_PARAMETER;
   1265 
   1266   //
   1267   // Load and start the load option.
   1268   //
   1269   DEBUG ((
   1270     DEBUG_INFO | DEBUG_LOAD, "Process Load Option (%s%04x) ...\n",
   1271     mBmLoadOptionName[LoadOption->OptionType], LoadOption->OptionNumber
   1272     ));
   1273   ImageHandle = NULL;
   1274   FileBuffer = BmGetLoadOptionBuffer (LoadOption->FilePath, &FilePath, &FileSize);
   1275   DEBUG_CODE (
   1276     if (FileBuffer != NULL && CompareMem (LoadOption->FilePath, FilePath, GetDevicePathSize (FilePath)) != 0) {
   1277       DEBUG ((EFI_D_INFO, "[Bds] DevicePath expand: "));
   1278       BmPrintDp (LoadOption->FilePath);
   1279       DEBUG ((EFI_D_INFO, " -> "));
   1280       BmPrintDp (FilePath);
   1281       DEBUG ((EFI_D_INFO, "\n"));
   1282     }
   1283   );
   1284   if (BmIsLoadOptionPeHeaderValid (LoadOption->OptionType, FileBuffer, FileSize)) {
   1285     Status = gBS->LoadImage (
   1286                     FALSE,
   1287                     gImageHandle,
   1288                     FilePath,
   1289                     FileBuffer,
   1290                     FileSize,
   1291                     &ImageHandle
   1292                     );
   1293   }
   1294   if (FilePath != NULL) {
   1295     FreePool (FilePath);
   1296   }
   1297   if (FileBuffer != NULL) {
   1298     FreePool (FileBuffer);
   1299   }
   1300 
   1301   if (!EFI_ERROR (Status)) {
   1302     Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);
   1303     ASSERT_EFI_ERROR (Status);
   1304 
   1305     ImageInfo->LoadOptionsSize = LoadOption->OptionalDataSize;
   1306     ImageInfo->LoadOptions = LoadOption->OptionalData;
   1307     //
   1308     // Before calling the image, enable the Watchdog Timer for the 5-minute period
   1309     //
   1310     gBS->SetWatchdogTimer (5 * 60, 0, 0, NULL);
   1311 
   1312     LoadOption->Status = gBS->StartImage (ImageHandle, &LoadOption->ExitDataSize, &LoadOption->ExitData);
   1313     DEBUG ((
   1314       DEBUG_INFO | DEBUG_LOAD, "Load Option (%s%04x) Return Status = %r\n",
   1315       mBmLoadOptionName[LoadOption->OptionType], LoadOption->OptionNumber, LoadOption->Status
   1316       ));
   1317 
   1318     //
   1319     // Clear the Watchdog Timer after the image returns
   1320     //
   1321     gBS->SetWatchdogTimer (0, 0, 0, NULL);
   1322   }
   1323 
   1324   return Status;
   1325 }
   1326