]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Library/UefiBootManagerLib/BmLoadOption.c
MdeModulePkg/UefiBootManagerLib: Refine the debug message
[mirror_edk2.git] / MdeModulePkg / Library / UefiBootManagerLib / BmLoadOption.c
index fc3e29a62ed171829b8a5a8c2f87e8f28cdb7f71..6f705bd4673f12a74919248cc5a229ace880e4d5 100644 (file)
-/** @file
-  Load option library functions which relate with creating and processing load options.
-
-Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
-This program and the accompanying materials
-are licensed and made available under the terms and conditions of the BSD License
-which accompanies this distribution.  The full text of the license may be found at
-http://opensource.org/licenses/bsd-license.php
-
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
-
-**/
-
-#include "InternalBm.h"
-
-/**
-  Get the Option Number that wasn't used.
-
-  @param  OrderVariableName   Could be L"BootOrder" or L"DriverOrder".
-  @param  FreeOptionNumber    To receive the minimal free option number.
-
-  @retval EFI_SUCCESS           The option number is found
-  @retval EFI_OUT_OF_RESOURCES  There is no free option number that can be used.
-  @retval EFI_INVALID_PARAMETER FreeOptionNumber is NULL
-
-**/
-EFI_STATUS
-BmGetFreeOptionNumber (
-  IN  CHAR16    *OrderVariableName,
-  OUT UINT16    *FreeOptionNumber
-  )
-{
-  
-  UINTN         OptionNumber;
-  UINTN         Index;
-  UINT16        *OptionOrder;
-  UINTN         OptionOrderSize;
-  UINT16        *BootNext;
-
-  if (FreeOptionNumber == NULL) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  GetEfiGlobalVariable2 (OrderVariableName, (VOID **) &OptionOrder, &OptionOrderSize);
-  BootNext = NULL;
-  if (*OrderVariableName == L'B') {
-    GetEfiGlobalVariable2 (L"BootNext", (VOID**) &BootNext, NULL);
-  }
-
-  for (OptionNumber = 0; 
-       OptionNumber < OptionOrderSize / sizeof (UINT16)
-                    + ((BootNext != NULL) ? 1 : 0); 
-       OptionNumber++
-       ) {
-    //
-    // Search in OptionOrder whether the OptionNumber exists
-    //
-    for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) {
-      if (OptionNumber == OptionOrder[Index]) {
-        break;
-      }
-    }
-
-    //
-    // We didn't find it in the ****Order array and it doesn't equal to BootNext 
-    // Otherwise, OptionNumber equals to OptionOrderSize / sizeof (UINT16) + 1
-    //
-    if ((Index == OptionOrderSize / sizeof (UINT16)) && 
-        ((BootNext == NULL) || (OptionNumber != *BootNext))
-        ) {
-      break;
-    }
-  }
-  if (OptionOrder != NULL) {
-    FreePool (OptionOrder);
-  }
-
-  if (BootNext != NULL) {
-    FreePool (BootNext);
-  }
-
-  //
-  // When BootOrder & BootNext conver all numbers in the range [0 ... 0xffff],
-  //   OptionNumber equals to 0x10000 which is not valid.
-  //
-  ASSERT (OptionNumber <= 0x10000);
-  if (OptionNumber == 0x10000) {
-    return EFI_OUT_OF_RESOURCES;
-  } else {
-    *FreeOptionNumber = (UINT16) OptionNumber;
-    return EFI_SUCCESS;
-  }
-}
-
-/**
-  Update order variable .
-
-  @param  OptionOrderName     Order variable name which need to be updated.
-  @param  OptionNumber        Option number for the new option.
-  @param  Position            Position of the new load option to put in the ****Order variable.
-
-  @retval EFI_SUCCESS           The boot#### or driver#### have been successfully registered.
-  @retval EFI_ALREADY_STARTED   The option number of Option is being used already.
-  @retval EFI_STATUS            Return the status of gRT->SetVariable ().
-
-**/
-EFI_STATUS
-BmAddOptionNumberToOrderVariable (
-  IN CHAR16               *OptionOrderName,
-  IN UINT16               OptionNumber,
-  IN UINTN                Position
-  )
-{
-  EFI_STATUS              Status;
-  UINTN                   Index;
-  UINT16                  *OptionOrder;
-  UINT16                  *NewOptionOrder;
-  UINTN                   OptionOrderSize;
-  //
-  // Update the option order variable
-  //
-  GetEfiGlobalVariable2 (OptionOrderName, (VOID **) &OptionOrder, &OptionOrderSize);
-
-  Status = EFI_SUCCESS;
-  for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) {
-    if (OptionOrder[Index] == OptionNumber) {
-      Status = EFI_ALREADY_STARTED;
-      break;
-    }
-  }
-
-  if (!EFI_ERROR (Status)) {
-    Position       = MIN (Position, OptionOrderSize / sizeof (UINT16));
-
-    NewOptionOrder = AllocatePool (OptionOrderSize + sizeof (UINT16));
-    ASSERT (NewOptionOrder != NULL);
-    if (OptionOrderSize != 0) {
-      CopyMem (NewOptionOrder, OptionOrder, Position * sizeof (UINT16));
-      CopyMem (&NewOptionOrder[Position + 1], &OptionOrder[Position], OptionOrderSize - Position * sizeof (UINT16));
-    }
-    NewOptionOrder[Position] = OptionNumber;
-
-    Status = gRT->SetVariable (
-                    OptionOrderName,
-                    &gEfiGlobalVariableGuid,
-                    EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
-                    OptionOrderSize + sizeof (UINT16),
-                    NewOptionOrder
-                    );
-    FreePool (NewOptionOrder);
-  }
-
-  if (OptionOrder != NULL) {
-    FreePool (OptionOrder);
-  }
-
-  return Status;
-}
-
-/**
-  Create the Boot#### or Driver#### variable from the load option.
-  
-  @param  LoadOption      Pointer to the load option.
-
-  @retval EFI_SUCCESS     The variable was created.
-  @retval Others          Error status returned by RT->SetVariable.
-**/
-EFI_STATUS
-EFIAPI
-EfiBootManagerLoadOptionToVariable (
-  IN CONST EFI_BOOT_MANAGER_LOAD_OPTION     *Option
-  )
-{
-  UINTN                            VariableSize;
-  UINT8                            *Variable;
-  UINT8                            *Ptr;
-  CHAR16                           OptionName[sizeof ("Driver####")];
-  CHAR16                           *Description;
-  CHAR16                           NullChar;
-
-  if ((Option->OptionNumber == LoadOptionNumberUnassigned) ||
-      (Option->FilePath == NULL) ||
-      (Option->OptionType >= LoadOptionTypeMax)
-     ) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  //
-  // Convert NULL description to empty description
-  //
-  NullChar    = L'\0';
-  Description = Option->Description;
-  if (Description == NULL) {
-    Description = &NullChar;
-  }
-
-  /*
-  UINT32                      Attributes;
-  UINT16                      FilePathListLength;
-  CHAR16                      Description[];
-  EFI_DEVICE_PATH_PROTOCOL    FilePathList[];
-  UINT8                       OptionalData[];
-TODO: FilePathList[] IS:
-A packed array of UEFI device paths.  The first element of the 
-array is a device path that describes the device and location of the 
-Image for this load option.  The FilePathList[0] is specific 
-to the device type.  Other device paths may optionally exist in the 
-FilePathList, but their usage is OSV specific. Each element 
-in the array is variable length, and ends at the device path end 
-structure.
-  */
-  VariableSize = sizeof (Option->Attributes)
-               + sizeof (UINT16)
-               + StrSize (Description)
-               + GetDevicePathSize (Option->FilePath)
-               + Option->OptionalDataSize;
-
-  Variable     = AllocatePool (VariableSize);
-  ASSERT (Variable != NULL);
-  
-  Ptr             = Variable;
-  *(UINT32 *) Ptr = Option->Attributes;
-  Ptr            += sizeof (Option->Attributes);
-  *(UINT16 *) Ptr = (UINT16) GetDevicePathSize (Option->FilePath);
-  Ptr            += sizeof (UINT16);
-  CopyMem (Ptr, Description, StrSize (Description));
-  Ptr            += StrSize (Description);
-  CopyMem (Ptr, Option->FilePath, GetDevicePathSize (Option->FilePath));
-  Ptr            += GetDevicePathSize (Option->FilePath);
-  CopyMem (Ptr, Option->OptionalData, Option->OptionalDataSize);
-
-  UnicodeSPrint (
-    OptionName,
-    sizeof (OptionName),
-    (Option->OptionType == LoadOptionTypeBoot) ? L"Boot%04x" : L"Driver%04x",
-    Option->OptionNumber
-    );
-
-  return gRT->SetVariable (
-                OptionName,
-                &gEfiGlobalVariableGuid,
-                EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
-                VariableSize,
-                Variable
-                );
-}
-
-/**
-  This function will register the new boot#### or driver#### option.
-  After the boot#### or driver#### updated, the BootOrder or DriverOrder will also be updated.
-
-  @param  Option            Pointer to load option to add.
-  @param  Position          Position of the new load option to put in the ****Order variable.
-
-  @retval EFI_SUCCESS           The boot#### or driver#### have been successfully registered.
-  @retval EFI_INVALID_PARAMETER The option number exceeds 0xFFFF.
-  @retval EFI_ALREADY_STARTED   The option number of Option is being used already.
-                                Note: this API only adds new load option, no replacement support.
-  @retval EFI_OUT_OF_RESOURCES  There is no free option number that can be used when the
-                                option number specified in the Option is LoadOptionNumberUnassigned.
-  @retval EFI_STATUS            Return the status of gRT->SetVariable ().
-
-**/
-EFI_STATUS
-EFIAPI
-EfiBootManagerAddLoadOptionVariable (
-  IN EFI_BOOT_MANAGER_LOAD_OPTION *Option,
-  IN UINTN                        Position
-  )
-{
-  EFI_STATUS                      Status;
-  UINT16                          OptionNumber;
-
-  if (Option == NULL) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  //
-  // Get the free option number if the option number is unassigned
-  //
-  if (Option->OptionNumber == LoadOptionNumberUnassigned) {
-    Status = BmGetFreeOptionNumber (
-               Option->OptionType == LoadOptionTypeBoot ? L"BootOrder" : L"DriverOrder",
-               &OptionNumber
-               );
-    if (EFI_ERROR (Status)) {
-      return Status;
-    }
-    Option->OptionNumber = OptionNumber;
-  }
-
-  if (Option->OptionNumber >= LoadOptionNumberMax) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  Status = BmAddOptionNumberToOrderVariable (
-             Option->OptionType == LoadOptionTypeBoot ? L"BootOrder" : L"DriverOrder",
-             (UINT16) Option->OptionNumber,
-             Position
-             );
-  if (!EFI_ERROR (Status)) {
-    //
-    // Save the Boot#### or Driver#### variable
-    //
-    Status = EfiBootManagerLoadOptionToVariable (Option);
-    if (EFI_ERROR (Status)) {
-      //
-      // Remove the #### from *Order variable when the Boot####/Driver#### cannot be saved.
-      //
-      EfiBootManagerDeleteLoadOptionVariable (Option->OptionNumber, Option->OptionType);
-    }
-  }
-
-  return Status;
-}
-
-/**
-  Sort the load option. The DriverOrder or BootOrder will be re-created to 
-  reflect the new order.
-
-  @param OptionType             Load option type
-  @param CompareFunction        The comparator
-**/
-VOID
-EFIAPI
-EfiBootManagerSortLoadOptionVariable (
-  EFI_BOOT_MANAGER_LOAD_OPTION_TYPE        OptionType,
-  SORT_COMPARE                             CompareFunction
-  )
-{
-  EFI_STATUS                     Status;
-  EFI_BOOT_MANAGER_LOAD_OPTION   *LoadOption;
-  UINTN                          LoadOptionCount;
-  UINTN                          Index;
-  UINT16                         *OptionOrder;
-
-  LoadOption = EfiBootManagerGetLoadOptions (&LoadOptionCount, OptionType);
-
-  //
-  // Insertion sort algorithm
-  //
-  PerformQuickSort (
-    LoadOption,
-    LoadOptionCount,
-    sizeof (EFI_BOOT_MANAGER_LOAD_OPTION),
-    CompareFunction
-    );
-
-  //
-  // Create new ****Order variable
-  //
-  OptionOrder = AllocatePool (LoadOptionCount * sizeof (UINT16));
-  ASSERT (OptionOrder != NULL);
-  for (Index = 0; Index < LoadOptionCount; Index++) {
-    OptionOrder[Index] = (UINT16) LoadOption[Index].OptionNumber;
-  }
-
-  Status = gRT->SetVariable (
-                  OptionType == LoadOptionTypeBoot ? L"BootOrder" : L"DriverOrder",
-                  &gEfiGlobalVariableGuid,
-                  EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
-                  LoadOptionCount * sizeof (UINT16),
-                  OptionOrder
-                  );
-  //
-  // Changing the *Order content without increasing its size with current variable implementation shouldn't fail.
-  //
-  ASSERT_EFI_ERROR (Status);
-
-  FreePool (OptionOrder);
-  EfiBootManagerFreeLoadOptions (LoadOption, LoadOptionCount);
-}
-
-/**
-  Initialize a load option.
-
-  @param Option           Pointer to the load option to be initialized.
-  @param OptionNumber     Option number of the load option.
-  @param OptionType       Type of the load option.
-  @param Attributes       Attributes of the load option.
-  @param Description      Description of the load option.
-  @param FilePath         Device path of the load option.
-  @param OptionalData     Optional data of the load option.
-  @param OptionalDataSize Size of the optional data of the load option.
-
-  @retval EFI_SUCCESS           The load option was initialized successfully.
-  @retval EFI_INVALID_PARAMETER Option, Description or FilePath is NULL.
-**/
-EFI_STATUS
-EFIAPI
-EfiBootManagerInitializeLoadOption (
-  IN OUT EFI_BOOT_MANAGER_LOAD_OPTION   *Option,
-  IN  UINTN                             OptionNumber,
-  IN  EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType,
-  IN  UINT32                            Attributes,
-  IN  CHAR16                            *Description,
-  IN  EFI_DEVICE_PATH_PROTOCOL          *FilePath,
-  IN  UINT8                             *OptionalData,   OPTIONAL
-  IN  UINT32                            OptionalDataSize
-  )
-{
-  if ((Option == NULL) || (Description == NULL) || (FilePath == NULL)) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  if (((OptionalData != NULL) && (OptionalDataSize == 0)) ||
-      ((OptionalData == NULL) && (OptionalDataSize != 0))) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  ZeroMem (Option, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
-  Option->OptionNumber       = OptionNumber;
-  Option->OptionType         = OptionType;
-  Option->Attributes         = Attributes;
-  Option->Description        = AllocateCopyPool (StrSize (Description), Description);
-  Option->FilePath           = DuplicateDevicePath (FilePath);
-  if (OptionalData != NULL) {
-    Option->OptionalData     = AllocateCopyPool (OptionalDataSize, OptionalData);
-    Option->OptionalDataSize = OptionalDataSize;
-  }
-
-  return EFI_SUCCESS;
-}
-
-
-/**
-  Return the index of the load option in the load option array.
-
-  The function consider two load options are equal when the 
-  OptionType, Attributes, Description, FilePath and OptionalData are equal.
-
-  @param Key    Pointer to the load option to be found.
-  @param Array  Pointer to the array of load options to be found.
-  @param Count  Number of entries in the Array.
-
-  @retval -1          Key wasn't found in the Array.
-  @retval 0 ~ Count-1 The index of the Key in the Array.
-**/
-INTN
-BmFindLoadOption (
-  IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Key,
-  IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Array,
-  IN UINTN                              Count
-  )
-{
-  UINTN                             Index;
-
-  for (Index = 0; Index < Count; Index++) {
-    if ((Key->OptionType == Array[Index].OptionType) &&
-        (Key->Attributes == Array[Index].Attributes) &&
-        (StrCmp (Key->Description, Array[Index].Description) == 0) &&
-        (CompareMem (Key->FilePath, Array[Index].FilePath, GetDevicePathSize (Key->FilePath)) == 0) &&
-        (Key->OptionalDataSize == Array[Index].OptionalDataSize) &&
-        (CompareMem (Key->OptionalData, Array[Index].OptionalData, Key->OptionalDataSize) == 0)) {
-      return (INTN) Index;
-    }
-  }
-
-  return -1;
-}
-
-/**
-  Update the BootOrder or DriverOrder to delete OptionNumber .
-
-  @param  OptionOrderVariable  Order variable name which need to be updated.
-  @param  OptionNumber         Indicate the option number of load option
-
-  @retval EFI_NOT_FOUND         The load option cannot be found
-  @retval EFI_SUCCESS           The load option was deleted
-  @retval others                Status of RT->SetVariable()
-**/
-EFI_STATUS
-BmDeleteOptionVariable (
-  IN CHAR16                            *OptionOrderVariable,
-  IN UINT16                            OptionNumber
-  )
-{
-  UINT16           *OptionOrder;
-  UINTN            OptionOrderSize;
-  EFI_STATUS       Status;
-  UINTN            Index;
-
-  Status      = EFI_NOT_FOUND;
-  GetEfiGlobalVariable2 (OptionOrderVariable, (VOID **) &OptionOrder, &OptionOrderSize);
-  for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) {
-    if (OptionOrder[Index] == OptionNumber) {
-      OptionOrderSize -= sizeof (UINT16);
-      CopyMem (&OptionOrder[Index], &OptionOrder[Index + 1], OptionOrderSize - Index * sizeof (UINT16));
-      Status = gRT->SetVariable (
-                      OptionOrderVariable,
-                      &gEfiGlobalVariableGuid,
-                      EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
-                      OptionOrderSize,
-                      OptionOrder
-                      );
-      break;
-    }
-  }
-  if (OptionOrder != NULL) {
-    FreePool (OptionOrder);
-  }
-
-  return Status;
-}
-
-/**
-  Update the BootOrder or DriverOrder according to the OptionType to delete OptionNumber .
-  
-  @param  OptionNumber        Indicate the option number of load option
-  @param  OptionType          Indicate the type of load option
-
-  @retval EFI_INVALID_PARAMETER OptionType or OptionNumber is invalid.
-  @retval EFI_NOT_FOUND         The load option cannot be found
-  @retval EFI_SUCCESS           The load option was deleted
-**/
-EFI_STATUS
-EFIAPI
-EfiBootManagerDeleteLoadOptionVariable (
-  IN UINTN                              OptionNumber,
-  IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE  OptionType
-  )
-{
-  if ((OptionType >= LoadOptionTypeMax) || (OptionNumber >= LoadOptionNumberMax)) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  return BmDeleteOptionVariable (
-           OptionType == LoadOptionTypeBoot ? L"BootOrder" : L"DriverOrder",
-           (UINT16) OptionNumber
-           );
-}
-
-/**
-  Convert a single character to number.
-  It assumes the input Char is in the scope of L'0' ~ L'9' and L'A' ~ L'F'
-
-  @param    Char   The input char which need to convert to int.
-**/
-UINTN
-BmCharToUint (
-  IN CHAR16                           Char
-  )
-{
-  if ((Char >= L'0') && (Char <= L'9')) {
-    return (UINTN) (Char - L'0');
-  }
-
-  if ((Char >= L'A') && (Char <= L'F')) {
-    return (UINTN) (Char - L'A' + 0xA);
-  }
-
-  ASSERT (FALSE);
-  return 0;
-}
-
-/**
-  Returns the size of a device path in bytes.
-
-  This function returns the size, in bytes, of the device path data structure 
-  specified by DevicePath including the end of device path node. If DevicePath 
-  is NULL, then 0 is returned. If the length of the device path is bigger than
-  MaxSize, also return 0 to indicate this is an invalidate device path.
-
-  @param  DevicePath         A pointer to a device path data structure.
-  @param  MaxSize            Max valid device path size. If big than this size, 
-                             return error.
-  
-  @retval 0                  An invalid device path.
-  @retval Others             The size of a device path in bytes.
-
-**/
-UINTN
-BmGetDevicePathSizeEx (
-  IN CONST EFI_DEVICE_PATH_PROTOCOL  *DevicePath,
-  IN UINTN                           MaxSize
-  )
-{
-  UINTN  Size;
-  UINTN  NodeSize;
-
-  if (DevicePath == NULL) {
-    return 0;
-  }
-
-  //
-  // Search for the end of the device path structure
-  //
-  Size = 0;
-  while (!IsDevicePathEnd (DevicePath)) {
-    NodeSize = DevicePathNodeLength (DevicePath);
-    if (NodeSize == 0) {
-      return 0;
-    }
-    Size += NodeSize;
-    if (Size > MaxSize) {
-      return 0;
-    }
-    DevicePath = NextDevicePathNode (DevicePath);
-  }
-  Size += DevicePathNodeLength (DevicePath);
-  if (Size > MaxSize) {
-    return 0;
-  }
-
-  return Size;
-}
-
-/**
-  Returns the length of a Null-terminated Unicode string. If the length is 
-  bigger than MaxStringLen, return length 0 to indicate that this is an 
-  invalidate string.
-
-  This function returns the number of Unicode characters in the Null-terminated
-  Unicode string specified by String. 
-
-  If String is NULL, then ASSERT().
-  If String is not aligned on a 16-bit boundary, then ASSERT().
-
-  @param  String           A pointer to a Null-terminated Unicode string.
-  @param  MaxStringLen     Max string len in this string.
-
-  @retval 0                An invalid string.
-  @retval Others           The length of String.
-
-**/
-UINTN
-BmStrSizeEx (
-  IN      CONST CHAR16              *String,
-  IN      UINTN                     MaxStringLen
-  )
-{
-  UINTN                             Length;
-
-  ASSERT (String != NULL && MaxStringLen != 0);
-  ASSERT (((UINTN) String & BIT0) == 0);
-
-  for (Length = 0; *String != L'\0' && MaxStringLen != Length; String++, Length+=2);
-
-  if (*String != L'\0' && MaxStringLen == Length) {
-    return 0;
-  }
-
-  return Length + 2;
-}
-
-/**
-  Validate the EFI Boot#### variable (VendorGuid/Name)
-
-  @param  Variable              Boot#### variable data.
-  @param  VariableSize          Returns the size of the EFI variable that was read
-
-  @retval TRUE                  The variable data is correct.
-  @retval FALSE                 The variable data is corrupted.
-
-**/
-BOOLEAN 
-BmValidateOption (
-  UINT8                     *Variable,
-  UINTN                     VariableSize
-  )
-{
-  UINT16                    FilePathSize;
-  UINT8                     *TempPtr;
-  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
-  UINTN                     TempSize;
-
-  if (VariableSize <= sizeof (UINT16) + sizeof (UINT32)) {
-    return FALSE;
-  }
-
-  //
-  // Skip the option attribute
-  //
-  TempPtr    = Variable;
-  TempPtr   += sizeof (UINT32);
-
-  //
-  // Get the option's device path size
-  //
-  FilePathSize  = *(UINT16 *) TempPtr;
-  TempPtr      += sizeof (UINT16);
-
-  //
-  // Get the option's description string size
-  //
-  TempSize = BmStrSizeEx ((CHAR16 *) TempPtr, VariableSize - sizeof (UINT16) - sizeof (UINT32));
-  TempPtr += TempSize;
-
-  //
-  // Get the option's device path
-  //
-  DevicePath =  (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
-  TempPtr   += FilePathSize;
-
-  //
-  // Validation boot option variable.
-  //
-  if ((FilePathSize == 0) || (TempSize == 0)) {
-    return FALSE;
-  }
-
-  if (TempSize + FilePathSize + sizeof (UINT16) + sizeof (UINT32) > VariableSize) {
-    return FALSE;
-  }
-
-  return (BOOLEAN) (BmGetDevicePathSizeEx (DevicePath, FilePathSize) != 0);
-}
-
-/**
-  Build the Boot#### or Driver#### option from the VariableName.
-
-  @param  VariableName          EFI Variable name indicate if it is Boot#### or
-                                Driver####
-  @param  Option                Return the Boot#### or Driver#### option.
-
-  @retval EFI_SUCCESS     Get the option just been created
-  @retval EFI_NOT_FOUND   Failed to get the new option
-
-**/
-EFI_STATUS
-EFIAPI
-EfiBootManagerVariableToLoadOption (
-  IN  CHAR16                          *VariableName,
-  IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *Option
-  )
-{
-  EFI_STATUS                         Status;
-  UINT32                             Attribute;
-  UINT16                             FilePathSize;
-  UINT8                              *Variable;
-  UINT8                              *TempPtr;
-  UINTN                              VariableSize;
-  EFI_DEVICE_PATH_PROTOCOL           *FilePath;
-  UINT8                              *OptionalData;
-  UINT32                             OptionalDataSize;
-  CHAR16                             *Description;
-  UINT8                              NumOff;
-  EFI_BOOT_MANAGER_LOAD_OPTION_TYPE  OptionType;
-  UINT16                             OptionNumber;
-
-  if ((VariableName == NULL) || (Option == NULL)) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  //
-  // Read the variable
-  //
-  GetEfiGlobalVariable2 (VariableName, (VOID **) &Variable, &VariableSize);
-  if (Variable == NULL) {
-    return EFI_NOT_FOUND;
-  }
-
-  //
-  // Validate Boot#### variable data.
-  //
-  if (!BmValidateOption(Variable, VariableSize)) {
-    FreePool (Variable);
-    return EFI_INVALID_PARAMETER;
-  }
-
-  //
-  // Notes: careful defined the variable of Boot#### or
-  // Driver####, consider use some macro to abstract the code
-  //
-  //
-  // Get the option attribute
-  //
-  TempPtr   =  Variable;
-  Attribute =  *(UINT32 *) Variable;
-  TempPtr   += sizeof (UINT32);
-
-  //
-  // Get the option's device path size
-  //
-  FilePathSize =  *(UINT16 *) TempPtr;
-  TempPtr     += sizeof (UINT16);
-
-  //
-  // Get the option's description string
-  //
-  Description  = (CHAR16 *) TempPtr;
-
-  //
-  // Get the option's description string size
-  //
-  TempPtr     += StrSize ((CHAR16 *) TempPtr);
-
-  //
-  // Get the option's device path
-  //
-  FilePath     =  (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
-  TempPtr     += FilePathSize;
-
-  OptionalDataSize = (UINT32) (VariableSize - (UINTN) (TempPtr - Variable));
-  if (OptionalDataSize == 0) {
-    OptionalData = NULL;
-  } else {
-    OptionalData = TempPtr;
-  }
-
-  if (*VariableName == L'B') {
-    OptionType = LoadOptionTypeBoot;
-    NumOff = (UINT8) (sizeof (L"Boot") / sizeof (CHAR16) - 1);
-  } else {
-    OptionType = LoadOptionTypeDriver;
-    NumOff = (UINT8) (sizeof (L"Driver") / sizeof (CHAR16) - 1);
-  }
-  
-  //
-  // Get the value from VariableName Unicode string
-  // since the ISO standard assumes ASCII equivalent abbreviations, we can be safe in converting this
-  // Unicode stream to ASCII without any loss in meaning.
-  //  
-  OptionNumber = (UINT16) (BmCharToUint (VariableName[NumOff+0]) * 0x1000) 
-               + (UINT16) (BmCharToUint (VariableName[NumOff+1]) * 0x100)
-               + (UINT16) (BmCharToUint (VariableName[NumOff+2]) * 0x10)
-               + (UINT16) (BmCharToUint (VariableName[NumOff+3]) * 0x1);
-
-  Status = EfiBootManagerInitializeLoadOption (
-             Option,
-             OptionNumber,
-             OptionType,
-             Attribute,
-             Description,
-             FilePath,
-             OptionalData,
-             OptionalDataSize
-             );
-  ASSERT_EFI_ERROR (Status);
-  
-  FreePool (Variable);
-  return Status;
-}
-
-/**
-  Returns an array of load options based on the EFI variable
-  L"BootOrder"/L"DriverOrder" and the L"Boot####"/L"Driver####" variables impled by it.
-  #### is the hex value of the UINT16 in each BootOrder/DriverOrder entry. 
-
-  @param  LoadOptionCount   Returns number of entries in the array.
-  @param  LoadOptionType    The type of the load option.
-
-  @retval NULL  No load options exist.
-  @retval !NULL Array of load option entries.
-
-**/
-EFI_BOOT_MANAGER_LOAD_OPTION *
-EFIAPI
-EfiBootManagerGetLoadOptions (
-  OUT UINTN                             *OptionCount,
-  IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE  LoadOptionType
-  )
-{
-  EFI_STATUS                   Status;
-  UINT16                       *OptionOrder;
-  UINTN                        OptionOrderSize;
-  UINTN                        Index;
-  UINTN                        OptionIndex;
-  EFI_BOOT_MANAGER_LOAD_OPTION *Option;
-  CHAR16                       OptionName[sizeof ("Driver####")];
-  UINT16                       OptionNumber;
-
-  *OptionCount = 0;
-
-  //
-  // Read the BootOrder, or DriverOrder variable.
-  //
-  GetEfiGlobalVariable2 (
-    (LoadOptionType == LoadOptionTypeBoot) ? L"BootOrder" : L"DriverOrder",
-    (VOID **) &OptionOrder,
-    &OptionOrderSize
-    );
-  if (OptionOrder == NULL) {
-    return NULL;
-  }
-
-  *OptionCount = OptionOrderSize / sizeof (UINT16);
-
-  Option = AllocatePool (*OptionCount * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
-  ASSERT (Option != NULL);
-
-  OptionIndex = 0;
-  for (Index = 0; Index < *OptionCount; Index++) {
-    OptionNumber = OptionOrder[Index];
-    if (LoadOptionType == LoadOptionTypeBoot) {
-      UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", OptionNumber);
-    } else {
-      UnicodeSPrint (OptionName, sizeof (OptionName), L"Driver%04x", OptionNumber);
-    }
-
-    Status = EfiBootManagerVariableToLoadOption (OptionName, &Option[OptionIndex]);
-    if (EFI_ERROR (Status)) {
-      DEBUG ((EFI_D_INFO, "[Bds] %s doesn't exist - Update ****Order variable to remove the reference!!", OptionName));
-      EfiBootManagerDeleteLoadOptionVariable (OptionNumber, LoadOptionTypeBoot);
-    } else {
-      ASSERT (Option[OptionIndex].OptionNumber == OptionNumber);
-      OptionIndex++;
-    }
-  }
-
-  if (OptionOrder != NULL) {
-    FreePool (OptionOrder);
-  }
-
-  if (OptionIndex < *OptionCount) {
-    Option = ReallocatePool (
-               *OptionCount * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION),
-               OptionIndex * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION),
-               Option
-               );
-    ASSERT (Option != NULL);
-    *OptionCount = OptionIndex;
-  }
-
-  return Option;
-}
-
-/**
-  Free an EFI_BOOT_MANGER_LOAD_OPTION entry that was allocate by the library.
-
-  @param  LoadOption   Pointer to boot option to Free.
-
-  @return EFI_SUCCESS   BootOption was freed 
-  @return EFI_NOT_FOUND BootOption == NULL 
-
-**/
-EFI_STATUS
-EFIAPI
-EfiBootManagerFreeLoadOption (
-  IN  EFI_BOOT_MANAGER_LOAD_OPTION  *LoadOption
-  )
-{
-  if (LoadOption == NULL) {
-    return EFI_NOT_FOUND;
-  }
-
-  if (LoadOption->Description != NULL) {
-    FreePool (LoadOption->Description);
-  }
-  if (LoadOption->FilePath != NULL) {
-    FreePool (LoadOption->FilePath);
-  }
-  if (LoadOption->OptionalData != NULL) {
-    FreePool (LoadOption->OptionalData);
-  }
-
-  return EFI_SUCCESS;
-}
-
-/**
-  Free an EFI_BOOT_MANGER_LOAD_OPTION array that was allocated by 
-  EfiBootManagerGetLoadOptions().
-
-  @param  Option       Pointer to boot option array to free.
-  @param  OptionCount  Number of array entries in BootOption
-
-  @return EFI_SUCCESS   BootOption was freed 
-  @return EFI_NOT_FOUND BootOption == NULL 
-
-**/
-EFI_STATUS
-EFIAPI
-EfiBootManagerFreeLoadOptions (
-  IN  EFI_BOOT_MANAGER_LOAD_OPTION  *Option,
-  IN  UINTN                         OptionCount
-  )
-{
-  UINTN   Index;
-
-  if (Option == NULL) {
-    return EFI_NOT_FOUND;
-  }
-
-  for (Index = 0;Index < OptionCount; Index++) {
-    EfiBootManagerFreeLoadOption (&Option[Index]);
-  }
-
-  FreePool (Option);
-
-  return EFI_SUCCESS;
-}
+/** @file\r
+  Load option library functions which relate with creating and processing load options.\r
+\r
+Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.<BR>\r
+(C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "InternalBm.h"\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED\r
+  CHAR16 *mBmLoadOptionName[] = {\r
+    L"Driver",\r
+    L"SysPrep",\r
+    L"Boot",\r
+    L"PlatformRecovery"\r
+  };\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED\r
+  CHAR16 *mBmLoadOptionOrderName[] = {\r
+    EFI_DRIVER_ORDER_VARIABLE_NAME,\r
+    EFI_SYS_PREP_ORDER_VARIABLE_NAME,\r
+    EFI_BOOT_ORDER_VARIABLE_NAME,\r
+    NULL  // PlatformRecovery#### doesn't have associated *Order variable\r
+  };\r
+\r
+/**\r
+  Call Visitor function for each variable in variable storage.\r
+\r
+  @param Visitor  Visitor function.\r
+  @param Context  The context passed to Visitor function.\r
+**/\r
+VOID\r
+BmForEachVariable (\r
+  BM_VARIABLE_VISITOR         Visitor,\r
+  VOID                        *Context\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  CHAR16                      *Name;\r
+  EFI_GUID                    Guid;\r
+  UINTN                       NameSize;\r
+  UINTN                       NewNameSize;\r
+\r
+  NameSize = sizeof (CHAR16);\r
+  Name = AllocateZeroPool (NameSize);\r
+  ASSERT (Name != NULL);\r
+  while (TRUE) {\r
+    NewNameSize = NameSize;\r
+    Status = gRT->GetNextVariableName (&NewNameSize, Name, &Guid);\r
+    if (Status == EFI_BUFFER_TOO_SMALL) {\r
+      Name = ReallocatePool (NameSize, NewNameSize, Name);\r
+      ASSERT (Name != NULL);\r
+      Status = gRT->GetNextVariableName (&NewNameSize, Name, &Guid);\r
+      NameSize = NewNameSize;\r
+    }\r
+\r
+    if (Status == EFI_NOT_FOUND) {\r
+      break;\r
+    }\r
+    ASSERT_EFI_ERROR (Status);\r
+\r
+    Visitor (Name, &Guid, Context);\r
+  }\r
+\r
+  FreePool (Name);\r
+}\r
+\r
+/**\r
+  Get the Option Number that wasn't used.\r
+\r
+  @param  LoadOptionType      The load option type.\r
+  @param  FreeOptionNumber    Return the minimal free option number.\r
+\r
+  @retval EFI_SUCCESS           The option number is found and will be returned.\r
+  @retval EFI_OUT_OF_RESOURCES  There is no free option number that can be used.\r
+  @retval EFI_INVALID_PARAMETER FreeOptionNumber is NULL\r
+\r
+**/\r
+EFI_STATUS\r
+BmGetFreeOptionNumber (\r
+  IN  EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType,\r
+  OUT UINT16                            *FreeOptionNumber\r
+  )\r
+{\r
+  \r
+  UINTN         OptionNumber;\r
+  UINTN         Index;\r
+  UINT16        *OptionOrder;\r
+  UINTN         OptionOrderSize;\r
+  UINT16        *BootNext;\r
+\r
+  ASSERT (FreeOptionNumber != NULL);\r
+  ASSERT (LoadOptionType == LoadOptionTypeDriver || \r
+          LoadOptionType == LoadOptionTypeBoot ||\r
+          LoadOptionType == LoadOptionTypeSysPrep);\r
+\r
+  GetEfiGlobalVariable2 (mBmLoadOptionOrderName[LoadOptionType], (VOID **) &OptionOrder, &OptionOrderSize);\r
+  ASSERT ((OptionOrder != NULL && OptionOrderSize != 0) || (OptionOrder == NULL && OptionOrderSize == 0));\r
+\r
+  BootNext = NULL;\r
+  if (LoadOptionType == LoadOptionTypeBoot) {\r
+    GetEfiGlobalVariable2 (L"BootNext", (VOID**) &BootNext, NULL);\r
+  }\r
+\r
+  for (OptionNumber = 0; \r
+       OptionNumber < OptionOrderSize / sizeof (UINT16)\r
+                    + ((BootNext != NULL) ? 1 : 0); \r
+       OptionNumber++\r
+       ) {\r
+    //\r
+    // Search in OptionOrder whether the OptionNumber exists\r
+    //\r
+    for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) {\r
+      if (OptionNumber == OptionOrder[Index]) {\r
+        break;\r
+      }\r
+    }\r
+\r
+    //\r
+    // We didn't find it in the ****Order array and it doesn't equal to BootNext \r
+    // Otherwise, OptionNumber equals to OptionOrderSize / sizeof (UINT16) + 1\r
+    //\r
+    if ((Index == OptionOrderSize / sizeof (UINT16)) && \r
+        ((BootNext == NULL) || (OptionNumber != *BootNext))\r
+        ) {\r
+      break;\r
+    }\r
+  }\r
+  if (OptionOrder != NULL) {\r
+    FreePool (OptionOrder);\r
+  }\r
+\r
+  if (BootNext != NULL) {\r
+    FreePool (BootNext);\r
+  }\r
+\r
+  //\r
+  // When BootOrder & BootNext conver all numbers in the range [0 ... 0xffff],\r
+  //   OptionNumber equals to 0x10000 which is not valid.\r
+  //\r
+  ASSERT (OptionNumber <= 0x10000);\r
+  if (OptionNumber == 0x10000) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  } else {\r
+    *FreeOptionNumber = (UINT16) OptionNumber;\r
+    return EFI_SUCCESS;\r
+  }\r
+}\r
+\r
+/**\r
+  Create the Boot####, Driver####, SysPrep####, PlatformRecovery#### variable\r
+  from the load option.\r
+\r
+  @param  LoadOption      Pointer to the load option.\r
+\r
+  @retval EFI_SUCCESS     The variable was created.\r
+  @retval Others          Error status returned by RT->SetVariable.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiBootManagerLoadOptionToVariable (\r
+  IN CONST EFI_BOOT_MANAGER_LOAD_OPTION     *Option\r
+  )\r
+{\r
+  EFI_STATUS                       Status;\r
+  UINTN                            VariableSize;\r
+  UINT8                            *Variable;\r
+  UINT8                            *Ptr;\r
+  CHAR16                           OptionName[BM_OPTION_NAME_LEN];\r
+  CHAR16                           *Description;\r
+  CHAR16                           NullChar;\r
+  EDKII_VARIABLE_LOCK_PROTOCOL     *VariableLock;\r
+  UINT32                           VariableAttributes;\r
+\r
+  if ((Option->OptionNumber == LoadOptionNumberUnassigned) ||\r
+      (Option->FilePath == NULL) ||\r
+      ((UINT32) Option->OptionType >= LoadOptionTypeMax)\r
+     ) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Convert NULL description to empty description\r
+  //\r
+  NullChar    = L'\0';\r
+  Description = Option->Description;\r
+  if (Description == NULL) {\r
+    Description = &NullChar;\r
+  }\r
+\r
+  /*\r
+  UINT32                      Attributes;\r
+  UINT16                      FilePathListLength;\r
+  CHAR16                      Description[];\r
+  EFI_DEVICE_PATH_PROTOCOL    FilePathList[];\r
+  UINT8                       OptionalData[];\r
+TODO: FilePathList[] IS:\r
+A packed array of UEFI device paths.  The first element of the \r
+array is a device path that describes the device and location of the \r
+Image for this load option.  The FilePathList[0] is specific \r
+to the device type.  Other device paths may optionally exist in the \r
+FilePathList, but their usage is OSV specific. Each element \r
+in the array is variable length, and ends at the device path end \r
+structure.\r
+  */\r
+  VariableSize = sizeof (Option->Attributes)\r
+               + sizeof (UINT16)\r
+               + StrSize (Description)\r
+               + GetDevicePathSize (Option->FilePath)\r
+               + Option->OptionalDataSize;\r
+\r
+  Variable     = AllocatePool (VariableSize);\r
+  ASSERT (Variable != NULL);\r
+\r
+  Ptr             = Variable;\r
+  WriteUnaligned32 ((UINT32 *) Ptr, Option->Attributes);\r
+  Ptr            += sizeof (Option->Attributes);\r
+\r
+  WriteUnaligned16 ((UINT16 *) Ptr, (UINT16) GetDevicePathSize (Option->FilePath));\r
+  Ptr            += sizeof (UINT16);\r
+\r
+  CopyMem (Ptr, Description, StrSize (Description));\r
+  Ptr            += StrSize (Description);\r
+\r
+  CopyMem (Ptr, Option->FilePath, GetDevicePathSize (Option->FilePath));\r
+  Ptr            += GetDevicePathSize (Option->FilePath);\r
+\r
+  CopyMem (Ptr, Option->OptionalData, Option->OptionalDataSize);\r
+\r
+  UnicodeSPrint (OptionName, sizeof (OptionName), L"%s%04x", mBmLoadOptionName[Option->OptionType], Option->OptionNumber);\r
+\r
+  VariableAttributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE;\r
+  if (Option->OptionType == LoadOptionTypePlatformRecovery) {\r
+    //\r
+    // Lock the PlatformRecovery####\r
+    //\r
+    Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock);\r
+    if (!EFI_ERROR (Status)) {\r
+      Status = VariableLock->RequestToLock (VariableLock, OptionName, &gEfiGlobalVariableGuid);\r
+      ASSERT_EFI_ERROR (Status);\r
+    }\r
+    VariableAttributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;\r
+  }\r
+\r
+  return gRT->SetVariable (\r
+                OptionName,\r
+                &gEfiGlobalVariableGuid,\r
+                VariableAttributes,\r
+                VariableSize,\r
+                Variable\r
+                );\r
+}\r
+\r
+/**\r
+  Update order variable .\r
+\r
+  @param  OptionOrderName     Order variable name which need to be updated.\r
+  @param  OptionNumber        Option number for the new option.\r
+  @param  Position            Position of the new load option to put in the ****Order variable.\r
+\r
+  @retval EFI_SUCCESS           The boot#### or driver#### have been successfully registered.\r
+  @retval EFI_ALREADY_STARTED   The option number of Option is being used already.\r
+  @retval EFI_STATUS            Return the status of gRT->SetVariable ().\r
+\r
+**/\r
+EFI_STATUS\r
+BmAddOptionNumberToOrderVariable (\r
+  IN CHAR16               *OptionOrderName,\r
+  IN UINT16               OptionNumber,\r
+  IN UINTN                Position\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  UINTN                   Index;\r
+  UINT16                  *OptionOrder;\r
+  UINT16                  *NewOptionOrder;\r
+  UINTN                   OptionOrderSize;\r
+  //\r
+  // Update the option order variable\r
+  //\r
+  GetEfiGlobalVariable2 (OptionOrderName, (VOID **) &OptionOrder, &OptionOrderSize);\r
+  ASSERT ((OptionOrder != NULL && OptionOrderSize != 0) || (OptionOrder == NULL && OptionOrderSize == 0));\r
+\r
+  Status = EFI_SUCCESS;\r
+  for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) {\r
+    if (OptionOrder[Index] == OptionNumber) {\r
+      Status = EFI_ALREADY_STARTED;\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    Position       = MIN (Position, OptionOrderSize / sizeof (UINT16));\r
+\r
+    NewOptionOrder = AllocatePool (OptionOrderSize + sizeof (UINT16));\r
+    ASSERT (NewOptionOrder != NULL);\r
+    if (OptionOrderSize != 0) {\r
+      CopyMem (NewOptionOrder, OptionOrder, Position * sizeof (UINT16));\r
+      CopyMem (&NewOptionOrder[Position + 1], &OptionOrder[Position], OptionOrderSize - Position * sizeof (UINT16));\r
+    }\r
+    NewOptionOrder[Position] = OptionNumber;\r
+\r
+    Status = gRT->SetVariable (\r
+                    OptionOrderName,\r
+                    &gEfiGlobalVariableGuid,\r
+                    EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
+                    OptionOrderSize + sizeof (UINT16),\r
+                    NewOptionOrder\r
+                    );\r
+    FreePool (NewOptionOrder);\r
+  }\r
+\r
+  if (OptionOrder != NULL) {\r
+    FreePool (OptionOrder);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  This function will register the new Boot####, Driver#### or SysPrep#### option.\r
+  After the *#### is updated, the *Order will also be updated.\r
+\r
+  @param  Option            Pointer to load option to add.\r
+  @param  Position          Position of the new load option to put in the ****Order variable.\r
+\r
+  @retval EFI_SUCCESS           The *#### have been successfully registered.\r
+  @retval EFI_INVALID_PARAMETER The option number exceeds 0xFFFF.\r
+  @retval EFI_ALREADY_STARTED   The option number of Option is being used already.\r
+                                Note: this API only adds new load option, no replacement support.\r
+  @retval EFI_OUT_OF_RESOURCES  There is no free option number that can be used when the\r
+                                option number specified in the Option is LoadOptionNumberUnassigned.\r
+  @retval EFI_STATUS            Return the status of gRT->SetVariable ().\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiBootManagerAddLoadOptionVariable (\r
+  IN EFI_BOOT_MANAGER_LOAD_OPTION *Option,\r
+  IN UINTN                        Position\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  UINT16                          OptionNumber;\r
+\r
+  if (Option == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (Option->OptionType != LoadOptionTypeDriver && \r
+      Option->OptionType != LoadOptionTypeSysPrep &&\r
+      Option->OptionType != LoadOptionTypeBoot\r
+      ) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Get the free option number if the option number is unassigned\r
+  //\r
+  if (Option->OptionNumber == LoadOptionNumberUnassigned) {\r
+    Status = BmGetFreeOptionNumber (Option->OptionType, &OptionNumber);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    Option->OptionNumber = OptionNumber;\r
+  }\r
+\r
+  if (Option->OptionNumber >= LoadOptionNumberMax) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status = BmAddOptionNumberToOrderVariable (mBmLoadOptionOrderName[Option->OptionType], (UINT16) Option->OptionNumber, Position);\r
+  if (!EFI_ERROR (Status)) {\r
+    //\r
+    // Save the Boot#### or Driver#### variable\r
+    //\r
+    Status = EfiBootManagerLoadOptionToVariable (Option);\r
+    if (EFI_ERROR (Status)) {\r
+      //\r
+      // Remove the #### from *Order variable when the Driver####/SysPrep####/Boot#### cannot be saved.\r
+      //\r
+      EfiBootManagerDeleteLoadOptionVariable (Option->OptionNumber, Option->OptionType);\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Sort the load option. The DriverOrder or BootOrder will be re-created to \r
+  reflect the new order.\r
+\r
+  @param OptionType             Load option type\r
+  @param CompareFunction        The comparator\r
+**/\r
+VOID\r
+EFIAPI\r
+EfiBootManagerSortLoadOptionVariable (\r
+  EFI_BOOT_MANAGER_LOAD_OPTION_TYPE        OptionType,\r
+  SORT_COMPARE                             CompareFunction\r
+  )\r
+{\r
+  EFI_STATUS                     Status;\r
+  EFI_BOOT_MANAGER_LOAD_OPTION   *LoadOption;\r
+  UINTN                          LoadOptionCount;\r
+  UINTN                          Index;\r
+  UINT16                         *OptionOrder;\r
+\r
+  LoadOption = EfiBootManagerGetLoadOptions (&LoadOptionCount, OptionType);\r
+\r
+  //\r
+  // Insertion sort algorithm\r
+  //\r
+  PerformQuickSort (\r
+    LoadOption,\r
+    LoadOptionCount,\r
+    sizeof (EFI_BOOT_MANAGER_LOAD_OPTION),\r
+    CompareFunction\r
+    );\r
+\r
+  //\r
+  // Create new ****Order variable\r
+  //\r
+  OptionOrder = AllocatePool (LoadOptionCount * sizeof (UINT16));\r
+  ASSERT (OptionOrder != NULL);\r
+  for (Index = 0; Index < LoadOptionCount; Index++) {\r
+    OptionOrder[Index] = (UINT16) LoadOption[Index].OptionNumber;\r
+  }\r
+\r
+  Status = gRT->SetVariable (\r
+                  mBmLoadOptionOrderName[OptionType],\r
+                  &gEfiGlobalVariableGuid,\r
+                  EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
+                  LoadOptionCount * sizeof (UINT16),\r
+                  OptionOrder\r
+                  );\r
+  //\r
+  // Changing the *Order content without increasing its size with current variable implementation shouldn't fail.\r
+  //\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  FreePool (OptionOrder);\r
+  EfiBootManagerFreeLoadOptions (LoadOption, LoadOptionCount);\r
+}\r
+\r
+/**\r
+  Initialize a load option.\r
+\r
+  @param Option           Pointer to the load option to be initialized.\r
+  @param OptionNumber     Option number of the load option.\r
+  @param OptionType       Type of the load option.\r
+  @param Attributes       Attributes of the load option.\r
+  @param Description      Description of the load option.\r
+  @param FilePath         Device path of the load option.\r
+  @param OptionalData     Optional data of the load option.\r
+  @param OptionalDataSize Size of the optional data of the load option.\r
+\r
+  @retval EFI_SUCCESS           The load option was initialized successfully.\r
+  @retval EFI_INVALID_PARAMETER Option, Description or FilePath is NULL.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiBootManagerInitializeLoadOption (\r
+  IN OUT EFI_BOOT_MANAGER_LOAD_OPTION   *Option,\r
+  IN  UINTN                             OptionNumber,\r
+  IN  EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType,\r
+  IN  UINT32                            Attributes,\r
+  IN  CHAR16                            *Description,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL          *FilePath,\r
+  IN  UINT8                             *OptionalData,   OPTIONAL\r
+  IN  UINT32                            OptionalDataSize\r
+  )\r
+{\r
+  if ((Option == NULL) || (Description == NULL) || (FilePath == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (((OptionalData != NULL) && (OptionalDataSize == 0)) ||\r
+      ((OptionalData == NULL) && (OptionalDataSize != 0))) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((UINT32) OptionType >= LoadOptionTypeMax) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  ZeroMem (Option, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));\r
+  Option->OptionNumber       = OptionNumber;\r
+  Option->OptionType         = OptionType;\r
+  Option->Attributes         = Attributes;\r
+  Option->Description        = AllocateCopyPool (StrSize (Description), Description);\r
+  Option->FilePath           = DuplicateDevicePath (FilePath);\r
+  if (OptionalData != NULL) {\r
+    Option->OptionalData     = AllocateCopyPool (OptionalDataSize, OptionalData);\r
+    Option->OptionalDataSize = OptionalDataSize;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Return the index of the load option in the load option array.\r
+\r
+  The function consider two load options are equal when the \r
+  OptionType, Attributes, Description, FilePath and OptionalData are equal.\r
+\r
+  @param Key    Pointer to the load option to be found.\r
+  @param Array  Pointer to the array of load options to be found.\r
+  @param Count  Number of entries in the Array.\r
+\r
+  @retval -1          Key wasn't found in the Array.\r
+  @retval 0 ~ Count-1 The index of the Key in the Array.\r
+**/\r
+INTN\r
+EFIAPI\r
+EfiBootManagerFindLoadOption (\r
+  IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Key,\r
+  IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Array,\r
+  IN UINTN                              Count\r
+  )\r
+{\r
+  UINTN                             Index;\r
+\r
+  for (Index = 0; Index < Count; Index++) {\r
+    if ((Key->OptionType == Array[Index].OptionType) &&\r
+        (Key->Attributes == Array[Index].Attributes) &&\r
+        (StrCmp (Key->Description, Array[Index].Description) == 0) &&\r
+        (CompareMem (Key->FilePath, Array[Index].FilePath, GetDevicePathSize (Key->FilePath)) == 0) &&\r
+        (Key->OptionalDataSize == Array[Index].OptionalDataSize) &&\r
+        (CompareMem (Key->OptionalData, Array[Index].OptionalData, Key->OptionalDataSize) == 0)) {\r
+      return (INTN) Index;\r
+    }\r
+  }\r
+\r
+  return -1;\r
+}\r
+\r
+/**\r
+  Delete the load option.\r
+\r
+  @param  OptionNumber        Indicate the option number of load option\r
+  @param  OptionType          Indicate the type of load option\r
+\r
+  @retval EFI_INVALID_PARAMETER OptionType or OptionNumber is invalid.\r
+  @retval EFI_NOT_FOUND         The load option cannot be found\r
+  @retval EFI_SUCCESS           The load option was deleted\r
+  @retval others                Status of RT->SetVariable()\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiBootManagerDeleteLoadOptionVariable (\r
+  IN UINTN                              OptionNumber,\r
+  IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE  OptionType\r
+  )\r
+{\r
+  UINT16                            *OptionOrder;\r
+  UINTN                             OptionOrderSize;\r
+  UINTN                             Index;\r
+  CHAR16                            OptionName[BM_OPTION_NAME_LEN];\r
+\r
+  if (((UINT32) OptionType >= LoadOptionTypeMax) || (OptionNumber >= LoadOptionNumberMax)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (OptionType == LoadOptionTypeDriver || OptionType == LoadOptionTypeSysPrep || OptionType == LoadOptionTypeBoot) {\r
+    //\r
+    // If the associated *Order exists, firstly remove the reference in *Order for\r
+    //  Driver####, SysPrep#### and Boot####.\r
+    //\r
+    GetEfiGlobalVariable2 (mBmLoadOptionOrderName[OptionType], (VOID **) &OptionOrder, &OptionOrderSize);\r
+    ASSERT ((OptionOrder != NULL && OptionOrderSize != 0) || (OptionOrder == NULL && OptionOrderSize == 0));\r
+\r
+    for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) {\r
+      if (OptionOrder[Index] == OptionNumber) {\r
+        OptionOrderSize -= sizeof (UINT16);\r
+        CopyMem (&OptionOrder[Index], &OptionOrder[Index + 1], OptionOrderSize - Index * sizeof (UINT16));\r
+        gRT->SetVariable (\r
+               mBmLoadOptionOrderName[OptionType],\r
+               &gEfiGlobalVariableGuid,\r
+               EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
+               OptionOrderSize,\r
+               OptionOrder\r
+               );\r
+        break;\r
+      }\r
+    }\r
+    if (OptionOrder != NULL) {\r
+      FreePool (OptionOrder);\r
+    }\r
+  }\r
+\r
+  //\r
+  // Remove the Driver####, SysPrep####, Boot#### or PlatformRecovery#### itself.\r
+  //\r
+  UnicodeSPrint (OptionName, sizeof (OptionName), L"%s%04x", mBmLoadOptionName[OptionType], OptionNumber);\r
+  return gRT->SetVariable (\r
+                OptionName,\r
+                &gEfiGlobalVariableGuid,\r
+                0,\r
+                0,\r
+                NULL\r
+                );\r
+}\r
+\r
+/**\r
+  Returns the size of a device path in bytes.\r
+\r
+  This function returns the size, in bytes, of the device path data structure \r
+  specified by DevicePath including the end of device path node. If DevicePath \r
+  is NULL, then 0 is returned. If the length of the device path is bigger than\r
+  MaxSize, also return 0 to indicate this is an invalidate device path.\r
+\r
+  @param  DevicePath         A pointer to a device path data structure.\r
+  @param  MaxSize            Max valid device path size. If big than this size, \r
+                             return error.\r
+  \r
+  @retval 0                  An invalid device path.\r
+  @retval Others             The size of a device path in bytes.\r
+\r
+**/\r
+UINTN\r
+BmGetDevicePathSizeEx (\r
+  IN CONST EFI_DEVICE_PATH_PROTOCOL  *DevicePath,\r
+  IN UINTN                           MaxSize\r
+  )\r
+{\r
+  UINTN  Size;\r
+  UINTN  NodeSize;\r
+\r
+  if (DevicePath == NULL) {\r
+    return 0;\r
+  }\r
+\r
+  //\r
+  // Search for the end of the device path structure\r
+  //\r
+  Size = 0;\r
+  while (!IsDevicePathEnd (DevicePath)) {\r
+    NodeSize = DevicePathNodeLength (DevicePath);\r
+    if (NodeSize == 0) {\r
+      return 0;\r
+    }\r
+    Size += NodeSize;\r
+    if (Size > MaxSize) {\r
+      return 0;\r
+    }\r
+    DevicePath = NextDevicePathNode (DevicePath);\r
+  }\r
+  Size += DevicePathNodeLength (DevicePath);\r
+  if (Size > MaxSize) {\r
+    return 0;\r
+  }\r
+\r
+  return Size;\r
+}\r
+\r
+/**\r
+  Returns the length of a Null-terminated Unicode string. If the length is \r
+  bigger than MaxStringLen, return length 0 to indicate that this is an \r
+  invalidate string.\r
+\r
+  This function returns the number of Unicode characters in the Null-terminated\r
+  Unicode string specified by String. \r
+\r
+  If String is NULL, then ASSERT().\r
+  If String is not aligned on a 16-bit boundary, then ASSERT().\r
+\r
+  @param  String           A pointer to a Null-terminated Unicode string.\r
+  @param  MaxStringLen     Max string len in this string.\r
+\r
+  @retval 0                An invalid string.\r
+  @retval Others           The length of String.\r
+\r
+**/\r
+UINTN\r
+BmStrSizeEx (\r
+  IN      CONST CHAR16              *String,\r
+  IN      UINTN                     MaxStringLen\r
+  )\r
+{\r
+  UINTN                             Length;\r
+\r
+  ASSERT (String != NULL && MaxStringLen != 0);\r
+  ASSERT (((UINTN) String & BIT0) == 0);\r
+\r
+  for (Length = 0; *String != L'\0' && MaxStringLen != Length; String++, Length+=2);\r
+\r
+  if (*String != L'\0' && MaxStringLen == Length) {\r
+    return 0;\r
+  }\r
+\r
+  return Length + 2;\r
+}\r
+\r
+/**\r
+  Validate the Boot####, Driver####, SysPrep#### and PlatformRecovery####\r
+  variable (VendorGuid/Name)\r
+\r
+  @param  Variable              The variable data.\r
+  @param  VariableSize          The variable size.\r
+\r
+  @retval TRUE                  The variable data is correct.\r
+  @retval FALSE                 The variable data is corrupted.\r
+\r
+**/\r
+BOOLEAN \r
+BmValidateOption (\r
+  UINT8                     *Variable,\r
+  UINTN                     VariableSize\r
+  )\r
+{\r
+  UINT16                    FilePathSize;\r
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
+  UINTN                     DescriptionSize;\r
+\r
+  if (VariableSize <= sizeof (UINT16) + sizeof (UINT32)) {\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // Skip the option attribute\r
+  //\r
+  Variable += sizeof (UINT32);\r
+\r
+  //\r
+  // Get the option's device path size\r
+  //\r
+  FilePathSize = ReadUnaligned16 ((UINT16 *) Variable);\r
+  Variable += sizeof (UINT16);\r
+\r
+  //\r
+  // Get the option's description string size\r
+  //\r
+  DescriptionSize = BmStrSizeEx ((CHAR16 *) Variable, VariableSize - sizeof (UINT16) - sizeof (UINT32));\r
+  Variable += DescriptionSize;\r
+\r
+  //\r
+  // Get the option's device path\r
+  //\r
+  DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Variable;\r
+\r
+  //\r
+  // Validation boot option variable.\r
+  //\r
+  if ((FilePathSize == 0) || (DescriptionSize == 0)) {\r
+    return FALSE;\r
+  }\r
+\r
+  if (sizeof (UINT32) + sizeof (UINT16) + DescriptionSize + FilePathSize > VariableSize) {\r
+    return FALSE;\r
+  }\r
+\r
+  return (BOOLEAN) (BmGetDevicePathSizeEx (DevicePath, FilePathSize) != 0);\r
+}\r
+\r
+/**\r
+  Check whether the VariableName is a valid load option variable name\r
+  and return the load option type and option number.\r
+\r
+  @param VariableName The name of the load option variable.\r
+  @param OptionType   Return the load option type.\r
+  @param OptionNumber Return the load option number.\r
+\r
+  @retval TRUE  The variable name is valid; The load option type and\r
+                load option number is returned.\r
+  @retval FALSE The variable name is NOT valid.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+EfiBootManagerIsValidLoadOptionVariableName (\r
+  IN CHAR16                             *VariableName,\r
+  OUT EFI_BOOT_MANAGER_LOAD_OPTION_TYPE *OptionType   OPTIONAL,\r
+  OUT UINT16                            *OptionNumber OPTIONAL\r
+  )\r
+{\r
+  UINTN                             VariableNameLen;\r
+  UINTN                             Index;\r
+  UINTN                             Uint;\r
+\r
+  if (VariableName == NULL) {\r
+    return FALSE;\r
+  }\r
+\r
+  VariableNameLen = StrLen (VariableName);\r
+\r
+  if (VariableNameLen <= 4) {\r
+    return FALSE;\r
+  }\r
+\r
+  for (Index = 0; Index < ARRAY_SIZE (mBmLoadOptionName); Index++) {\r
+    if ((VariableNameLen - 4 == StrLen (mBmLoadOptionName[Index])) &&\r
+        (StrnCmp (VariableName, mBmLoadOptionName[Index], VariableNameLen - 4) == 0)\r
+        ) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (Index == ARRAY_SIZE (mBmLoadOptionName)) {\r
+    return FALSE;\r
+  }\r
+\r
+  if (OptionType != NULL) {\r
+    *OptionType = (EFI_BOOT_MANAGER_LOAD_OPTION_TYPE) Index;\r
+  }\r
+\r
+  if (OptionNumber != NULL) {\r
+    *OptionNumber = 0;\r
+    for (Index = VariableNameLen - 4; Index < VariableNameLen; Index++) {\r
+      Uint = BmCharToUint (VariableName[Index]);\r
+      if (Uint == -1) {\r
+        break;\r
+      } else {\r
+        *OptionNumber = (UINT16) Uint + *OptionNumber * 0x10;\r
+      }\r
+    }\r
+  }\r
+\r
+  return (BOOLEAN) (Index == VariableNameLen);\r
+}\r
+\r
+/**\r
+  Build the Boot#### or Driver#### option from the VariableName.\r
+\r
+  @param  VariableName          Variable name of the load option\r
+  @param  VendorGuid            Variable GUID of the load option\r
+  @param  Option                Return the load option.\r
+\r
+  @retval EFI_SUCCESS     Get the option just been created\r
+  @retval EFI_NOT_FOUND   Failed to get the new option\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiBootManagerVariableToLoadOptionEx (\r
+  IN CHAR16                           *VariableName,\r
+  IN EFI_GUID                         *VendorGuid,\r
+  IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *Option  \r
+  )\r
+{\r
+  EFI_STATUS                         Status;\r
+  UINT32                             Attribute;\r
+  UINT16                             FilePathSize;\r
+  UINT8                              *Variable;\r
+  UINT8                              *VariablePtr;\r
+  UINTN                              VariableSize;\r
+  EFI_DEVICE_PATH_PROTOCOL           *FilePath;\r
+  UINT8                              *OptionalData;\r
+  UINT32                             OptionalDataSize;\r
+  CHAR16                             *Description;\r
+  EFI_BOOT_MANAGER_LOAD_OPTION_TYPE  OptionType;\r
+  UINT16                             OptionNumber;\r
+\r
+  if ((VariableName == NULL) || (Option == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (!EfiBootManagerIsValidLoadOptionVariableName (VariableName, &OptionType, &OptionNumber)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Read the variable\r
+  //\r
+  GetVariable2 (VariableName, VendorGuid, (VOID **) &Variable, &VariableSize);\r
+  if (Variable == NULL) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  //\r
+  // Validate *#### variable data.\r
+  //\r
+  if (!BmValidateOption(Variable, VariableSize)) {\r
+    FreePool (Variable);\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Get the option attribute\r
+  //\r
+  VariablePtr = Variable;\r
+  Attribute = ReadUnaligned32 ((UINT32 *) VariablePtr);\r
+  VariablePtr += sizeof (UINT32);\r
+\r
+  //\r
+  // Get the option's device path size\r
+  //\r
+  FilePathSize = ReadUnaligned16 ((UINT16 *) VariablePtr);\r
+  VariablePtr += sizeof (UINT16);\r
+\r
+  //\r
+  // Get the option's description string\r
+  //\r
+  Description = (CHAR16 *) VariablePtr;\r
+\r
+  //\r
+  // Get the option's description string size\r
+  //\r
+  VariablePtr += StrSize ((CHAR16 *) VariablePtr);\r
+\r
+  //\r
+  // Get the option's device path\r
+  //\r
+  FilePath = (EFI_DEVICE_PATH_PROTOCOL *) VariablePtr;\r
+  VariablePtr += FilePathSize;\r
+\r
+  OptionalDataSize = (UINT32) (VariableSize - (UINTN) (VariablePtr - Variable));\r
+  if (OptionalDataSize == 0) {\r
+    OptionalData = NULL;\r
+  } else {\r
+    OptionalData = VariablePtr;\r
+  }\r
+\r
+  Status = EfiBootManagerInitializeLoadOption (\r
+             Option,\r
+             OptionNumber,\r
+             OptionType,\r
+             Attribute,\r
+             Description,\r
+             FilePath,\r
+             OptionalData,\r
+             OptionalDataSize\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  CopyGuid (&Option->VendorGuid, VendorGuid);\r
+\r
+  FreePool (Variable);\r
+  return Status;\r
+}\r
+\r
+/**\r
+Build the Boot#### or Driver#### option from the VariableName.\r
+\r
+@param  VariableName          EFI Variable name indicate if it is Boot#### or Driver####\r
+@param  Option                Return the Boot#### or Driver#### option.\r
+\r
+@retval EFI_SUCCESS     Get the option just been created\r
+@retval EFI_NOT_FOUND   Failed to get the new option\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiBootManagerVariableToLoadOption (\r
+  IN  CHAR16                          *VariableName,\r
+  IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *Option\r
+  )\r
+{\r
+  return EfiBootManagerVariableToLoadOptionEx (VariableName, &gEfiGlobalVariableGuid, Option);\r
+}\r
+\r
+typedef struct {\r
+  EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType;\r
+  EFI_GUID                          *Guid;\r
+  EFI_BOOT_MANAGER_LOAD_OPTION      *Options;\r
+  UINTN                             OptionCount;\r
+} BM_COLLECT_LOAD_OPTIONS_PARAM;\r
+\r
+/**\r
+  Visitor function to collect the Platform Recovery load options or OS Recovery\r
+  load options from NV storage.\r
+\r
+  @param Name    Variable name.\r
+  @param Guid    Variable GUID.\r
+  @param Context The same context passed to BmForEachVariable.\r
+**/\r
+VOID\r
+BmCollectLoadOptions (\r
+  IN CHAR16               *Name,\r
+  IN EFI_GUID             *Guid,\r
+  IN VOID                 *Context\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType;\r
+  UINT16                            OptionNumber;\r
+  EFI_BOOT_MANAGER_LOAD_OPTION      Option;\r
+  UINTN                             Index;\r
+  BM_COLLECT_LOAD_OPTIONS_PARAM     *Param;\r
+\r
+  Param = (BM_COLLECT_LOAD_OPTIONS_PARAM *) Context;\r
+\r
+  if (CompareGuid (Guid, Param->Guid) && (\r
+      Param->OptionType == LoadOptionTypePlatformRecovery &&\r
+      EfiBootManagerIsValidLoadOptionVariableName (Name, &OptionType, &OptionNumber) &&\r
+      OptionType == LoadOptionTypePlatformRecovery\r
+     )) {\r
+    Status = EfiBootManagerVariableToLoadOptionEx (Name, Guid, &Option);\r
+    if (!EFI_ERROR (Status)) {\r
+      for (Index = 0; Index < Param->OptionCount; Index++) {\r
+        if (Param->Options[Index].OptionNumber > Option.OptionNumber) {\r
+          break;\r
+        }\r
+      }\r
+      Param->Options = ReallocatePool (\r
+                         Param->OptionCount * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION),\r
+                         (Param->OptionCount + 1) * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION),\r
+                         Param->Options\r
+                         );\r
+      ASSERT (Param->Options != NULL);\r
+      CopyMem (&Param->Options[Index + 1], &Param->Options[Index], (Param->OptionCount - Index) * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));\r
+      CopyMem (&Param->Options[Index], &Option, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));\r
+      Param->OptionCount++;\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  Returns an array of load options based on the EFI variable\r
+  L"BootOrder"/L"DriverOrder" and the L"Boot####"/L"Driver####" variables impled by it.\r
+  #### is the hex value of the UINT16 in each BootOrder/DriverOrder entry. \r
+\r
+  @param  LoadOptionCount   Returns number of entries in the array.\r
+  @param  LoadOptionType    The type of the load option.\r
+\r
+  @retval NULL  No load options exist.\r
+  @retval !NULL Array of load option entries.\r
+\r
+**/\r
+EFI_BOOT_MANAGER_LOAD_OPTION *\r
+EFIAPI\r
+EfiBootManagerGetLoadOptions (\r
+  OUT UINTN                             *OptionCount,\r
+  IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE  LoadOptionType\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  UINT16                        *OptionOrder;\r
+  UINTN                         OptionOrderSize;\r
+  UINTN                         Index;\r
+  UINTN                         OptionIndex;\r
+  EFI_BOOT_MANAGER_LOAD_OPTION  *Options;\r
+  CHAR16                        OptionName[BM_OPTION_NAME_LEN];\r
+  UINT16                        OptionNumber;\r
+  BM_COLLECT_LOAD_OPTIONS_PARAM Param;\r
+\r
+  *OptionCount = 0;\r
+  Options      = NULL;\r
+\r
+  if (LoadOptionType == LoadOptionTypeDriver || LoadOptionType == LoadOptionTypeSysPrep || LoadOptionType == LoadOptionTypeBoot) {\r
+    //\r
+    // Read the BootOrder, or DriverOrder variable.\r
+    //\r
+    GetEfiGlobalVariable2 (mBmLoadOptionOrderName[LoadOptionType], (VOID **) &OptionOrder, &OptionOrderSize);\r
+    if (OptionOrder == NULL) {\r
+      return NULL;\r
+    }\r
+\r
+    *OptionCount = OptionOrderSize / sizeof (UINT16);\r
+\r
+    Options = AllocatePool (*OptionCount * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));\r
+    ASSERT (Options != NULL);\r
+\r
+    OptionIndex = 0;\r
+    for (Index = 0; Index < *OptionCount; Index++) {\r
+      OptionNumber = OptionOrder[Index];\r
+      UnicodeSPrint (OptionName, sizeof (OptionName), L"%s%04x", mBmLoadOptionName[LoadOptionType], OptionNumber);\r
+\r
+      Status = EfiBootManagerVariableToLoadOption (OptionName, &Options[OptionIndex]);\r
+      if (EFI_ERROR (Status)) {\r
+        DEBUG ((EFI_D_INFO, "[Bds] %s doesn't exist - Update ****Order variable to remove the reference!!", OptionName));\r
+        EfiBootManagerDeleteLoadOptionVariable (OptionNumber, LoadOptionType);\r
+      } else {\r
+        ASSERT (Options[OptionIndex].OptionNumber == OptionNumber);\r
+        OptionIndex++;\r
+      }\r
+    }\r
+\r
+    if (OptionOrder != NULL) {\r
+      FreePool (OptionOrder);\r
+    }\r
+\r
+    if (OptionIndex < *OptionCount) {\r
+      Options = ReallocatePool (*OptionCount * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION), OptionIndex * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION), Options);\r
+      ASSERT (Options != NULL);\r
+      *OptionCount = OptionIndex;\r
+    }\r
+\r
+  } else if (LoadOptionType == LoadOptionTypePlatformRecovery) {\r
+    Param.OptionType = LoadOptionTypePlatformRecovery;\r
+    Param.Options = NULL;\r
+    Param.OptionCount = 0;\r
+    Param.Guid = &gEfiGlobalVariableGuid;\r
+\r
+    BmForEachVariable (BmCollectLoadOptions, (VOID *) &Param);\r
+\r
+    *OptionCount = Param.OptionCount;\r
+    Options = Param.Options;\r
+  }\r
+\r
+  return Options;\r
+}\r
+\r
+/**\r
+  Free an EFI_BOOT_MANGER_LOAD_OPTION entry that was allocate by the library.\r
+\r
+  @param  LoadOption   Pointer to boot option to Free.\r
+\r
+  @return EFI_SUCCESS   BootOption was freed \r
+  @return EFI_NOT_FOUND BootOption == NULL \r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiBootManagerFreeLoadOption (\r
+  IN  EFI_BOOT_MANAGER_LOAD_OPTION  *LoadOption\r
+  )\r
+{\r
+  if (LoadOption == NULL) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  if (LoadOption->Description != NULL) {\r
+    FreePool (LoadOption->Description);\r
+  }\r
+  if (LoadOption->FilePath != NULL) {\r
+    FreePool (LoadOption->FilePath);\r
+  }\r
+  if (LoadOption->OptionalData != NULL) {\r
+    FreePool (LoadOption->OptionalData);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Free an EFI_BOOT_MANGER_LOAD_OPTION array that was allocated by \r
+  EfiBootManagerGetLoadOptions().\r
+\r
+  @param  Option       Pointer to boot option array to free.\r
+  @param  OptionCount  Number of array entries in BootOption\r
+\r
+  @return EFI_SUCCESS   BootOption was freed \r
+  @return EFI_NOT_FOUND BootOption == NULL \r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiBootManagerFreeLoadOptions (\r
+  IN  EFI_BOOT_MANAGER_LOAD_OPTION  *Option,\r
+  IN  UINTN                         OptionCount\r
+  )\r
+{\r
+  UINTN   Index;\r
+\r
+  if (Option == NULL) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  for (Index = 0;Index < OptionCount; Index++) {\r
+    EfiBootManagerFreeLoadOption (&Option[Index]);\r
+  }\r
+\r
+  FreePool (Option);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Return whether the PE header of the load option is valid or not.\r
+\r
+  @param[in] Type       The load option type.\r
+  @param[in] FileBuffer The PE file buffer of the load option.\r
+  @param[in] FileSize   The size of the load option file.\r
+\r
+  @retval TRUE  The PE header of the load option is valid.\r
+  @retval FALSE The PE header of the load option is not valid.\r
+**/\r
+BOOLEAN\r
+BmIsLoadOptionPeHeaderValid (\r
+  IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE Type,\r
+  IN VOID                              *FileBuffer,\r
+  IN UINTN                             FileSize\r
+  )\r
+{\r
+  EFI_IMAGE_DOS_HEADER              *DosHeader;\r
+  EFI_IMAGE_OPTIONAL_HEADER_UNION   *PeHeader;\r
+  EFI_IMAGE_OPTIONAL_HEADER32       *OptionalHeader;\r
+  UINT16                            Subsystem;\r
+\r
+  if (FileBuffer == NULL || FileSize == 0) {\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // Read dos header\r
+  //\r
+  DosHeader = (EFI_IMAGE_DOS_HEADER *) FileBuffer;\r
+  if (FileSize >= sizeof (EFI_IMAGE_DOS_HEADER) &&\r
+      FileSize > DosHeader->e_lfanew && DosHeader->e_magic == EFI_IMAGE_DOS_SIGNATURE\r
+      ) {\r
+    //\r
+    // Read and check PE signature\r
+    //\r
+    PeHeader = (EFI_IMAGE_OPTIONAL_HEADER_UNION *) ((UINT8 *) FileBuffer + DosHeader->e_lfanew);\r
+    if (FileSize >= DosHeader->e_lfanew + sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION) &&\r
+        PeHeader->Pe32.Signature == EFI_IMAGE_NT_SIGNATURE\r
+        ) {\r
+      //\r
+      // Check PE32 or PE32+ magic, and machine type\r
+      //\r
+      OptionalHeader = (EFI_IMAGE_OPTIONAL_HEADER32 *) &PeHeader->Pe32.OptionalHeader;\r
+      if ((OptionalHeader->Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC || \r
+           OptionalHeader->Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) &&\r
+          EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeHeader->Pe32.FileHeader.Machine)\r
+          ) {\r
+        //\r
+        // Check the Subsystem:\r
+        //   Driver#### must be of type BootServiceDriver or RuntimeDriver\r
+        //   SysPrep####, Boot####, OsRecovery####, PlatformRecovery#### must be of type Application\r
+        //\r
+        Subsystem = OptionalHeader->Subsystem;\r
+        if ((Type == LoadOptionTypeDriver && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) ||\r
+            (Type == LoadOptionTypeDriver && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) ||\r
+            (Type == LoadOptionTypeSysPrep && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) ||\r
+            (Type == LoadOptionTypeBoot && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) ||\r
+            (Type == LoadOptionTypePlatformRecovery && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION)\r
+            ) {\r
+          return TRUE;\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  Process (load and execute) the load option.\r
+\r
+  @param LoadOption  Pointer to the load option.\r
+\r
+  @retval EFI_INVALID_PARAMETER  The load option type is invalid, \r
+                                 or the load option file path doesn't point to a valid file.\r
+  @retval EFI_UNSUPPORTED        The load option type is of LoadOptionTypeBoot.\r
+  @retval EFI_SUCCESS            The load option is inactive, or successfully loaded and executed.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiBootManagerProcessLoadOption (\r
+  IN EFI_BOOT_MANAGER_LOAD_OPTION       *LoadOption\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  EFI_DEVICE_PATH_PROTOCOL          *FilePath;\r
+  EFI_HANDLE                        ImageHandle;\r
+  EFI_LOADED_IMAGE_PROTOCOL         *ImageInfo;\r
+  VOID                              *FileBuffer;\r
+  UINTN                             FileSize;\r
+\r
+  if ((UINT32) LoadOption->OptionType >= LoadOptionTypeMax) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (LoadOption->OptionType == LoadOptionTypeBoot) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // If a load option is not marked as LOAD_OPTION_ACTIVE,\r
+  // the boot manager will not automatically load the option.\r
+  //\r
+  if ((LoadOption->Attributes & LOAD_OPTION_ACTIVE) == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  Status = EFI_INVALID_PARAMETER;\r
+\r
+  //\r
+  // Load and start the load option.\r
+  //\r
+  DEBUG ((\r
+    DEBUG_INFO | DEBUG_LOAD, "Process %s%04x (%s) ...\n",\r
+    mBmLoadOptionName[LoadOption->OptionType], LoadOption->OptionNumber,\r
+    LoadOption->Description\r
+    ));\r
+  ImageHandle = NULL;\r
+  FileBuffer = EfiBootManagerGetLoadOptionBuffer (LoadOption->FilePath, &FilePath, &FileSize);\r
+  DEBUG_CODE (\r
+    if (FileBuffer != NULL && CompareMem (LoadOption->FilePath, FilePath, GetDevicePathSize (FilePath)) != 0) {\r
+      DEBUG ((EFI_D_INFO, "[Bds] DevicePath expand: "));\r
+      BmPrintDp (LoadOption->FilePath);\r
+      DEBUG ((EFI_D_INFO, " -> "));\r
+      BmPrintDp (FilePath);\r
+      DEBUG ((EFI_D_INFO, "\n"));\r
+    }\r
+  );\r
+  if (BmIsLoadOptionPeHeaderValid (LoadOption->OptionType, FileBuffer, FileSize)) {\r
+    Status = gBS->LoadImage (\r
+                    FALSE,\r
+                    gImageHandle,\r
+                    FilePath,\r
+                    FileBuffer,\r
+                    FileSize,\r
+                    &ImageHandle\r
+                    );\r
+  }\r
+  if (FilePath != NULL) {\r
+    FreePool (FilePath);\r
+  }\r
+  if (FileBuffer != NULL) {\r
+    FreePool (FileBuffer);\r
+  }\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);\r
+    ASSERT_EFI_ERROR (Status);\r
+\r
+    ImageInfo->LoadOptionsSize = LoadOption->OptionalDataSize;\r
+    ImageInfo->LoadOptions = LoadOption->OptionalData;\r
+    //\r
+    // Before calling the image, enable the Watchdog Timer for the 5-minute period\r
+    //\r
+    gBS->SetWatchdogTimer (5 * 60, 0, 0, NULL);\r
+\r
+    LoadOption->Status = gBS->StartImage (ImageHandle, &LoadOption->ExitDataSize, &LoadOption->ExitData);\r
+    DEBUG ((\r
+      DEBUG_INFO | DEBUG_LOAD, "%s%04x Return Status = %r\n",\r
+      mBmLoadOptionName[LoadOption->OptionType], LoadOption->OptionNumber, LoadOption->Status\r
+      ));\r
+\r
+    //\r
+    // Clear the Watchdog Timer after the image returns\r
+    //\r
+    gBS->SetWatchdogTimer (0, 0, 0, NULL);\r
+  }\r
+\r
+  return Status;\r
+}\r