]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c
MdeModulePkg/UefiBootManagerLib: Generate boot description for NVME
[mirror_edk2.git] / MdeModulePkg / Library / UefiBootManagerLib / BmBoot.c
index 8d1a8c9d2355759cb5fc868a4b949d24a2f92c93..8a3a4027eec0139d8203eee14a080eaf95cec3df 100644 (file)
-/** @file
-  Library functions which relates with booting.
-
-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"
-
-#define VENDOR_IDENTIFICATION_OFFSET     3
-#define VENDOR_IDENTIFICATION_LENGTH     8
-#define PRODUCT_IDENTIFICATION_OFFSET    11
-#define PRODUCT_IDENTIFICATION_LENGTH    16
-
-CONST UINT16 mBmUsbLangId    = 0x0409; // English
-CHAR16       mBmUefiPrefix[] = L"UEFI ";
-
-EFI_BOOT_MANAGER_REFRESH_LEGACY_BOOT_OPTION  mBmRefreshLegacyBootOption = NULL;
-EFI_BOOT_MANAGER_LEGACY_BOOT                 mBmLegacyBoot              = NULL;
-
-///
-/// This GUID is used for an EFI Variable that stores the front device pathes
-/// for a partial device path that starts with the HD node.
-///
-EFI_GUID mBmHardDriveBootVariableGuid = { 0xfab7e9e1, 0x39dd, 0x4f2b, { 0x84, 0x08, 0xe2, 0x0e, 0x90, 0x6c, 0xb6, 0xde } };
-EFI_GUID mBmAutoCreateBootOptionGuid  = { 0x8108ac4e, 0x9f11, 0x4d59, { 0x85, 0x0e, 0xe2, 0x1a, 0x52, 0x2c, 0x59, 0xb2 } };
-
-/**
-  The function registers the legacy boot support capabilities.
-
-  @param RefreshLegacyBootOption The function pointer to create all the legacy boot options.
-  @param LegacyBoot              The function pointer to boot the legacy boot option.
-**/
-VOID
-EFIAPI
-EfiBootManagerRegisterLegacyBootSupport (
-  EFI_BOOT_MANAGER_REFRESH_LEGACY_BOOT_OPTION   RefreshLegacyBootOption,
-  EFI_BOOT_MANAGER_LEGACY_BOOT                  LegacyBoot
-  )
-{
-  mBmRefreshLegacyBootOption = RefreshLegacyBootOption;
-  mBmLegacyBoot              = LegacyBoot;
-}
-
-/**
-  For a bootable Device path, return its boot type.
-
-  @param  DevicePath                   The bootable device Path to check
-
-  @retval AcpiFloppyBoot               If given device path contains ACPI_DEVICE_PATH type device path node
-                                       which HID is floppy device.
-  @retval MessageAtapiBoot             If given device path contains MESSAGING_DEVICE_PATH type device path node
-                                       and its last device path node's subtype is MSG_ATAPI_DP.
-  @retval MessageSataBoot              If given device path contains MESSAGING_DEVICE_PATH type device path node
-                                       and its last device path node's subtype is MSG_SATA_DP.
-  @retval MessageScsiBoot              If given device path contains MESSAGING_DEVICE_PATH type device path node
-                                       and its last device path node's subtype is MSG_SCSI_DP.
-  @retval MessageUsbBoot               If given device path contains MESSAGING_DEVICE_PATH type device path node
-                                       and its last device path node's subtype is MSG_USB_DP.
-  @retval MessageNetworkBoot           If given device path contains MESSAGING_DEVICE_PATH type device path node
-                                       and its last device path node's subtype is MSG_MAC_ADDR_DP, MSG_VLAN_DP,
-                                       MSG_IPv4_DP or MSG_IPv6_DP.
-  @retval UnsupportedBoot              If tiven device path doesn't match the above condition, it's not supported.
-
-**/
-BM_BOOT_TYPE
-BmDevicePathType (
-  IN  EFI_DEVICE_PATH_PROTOCOL     *DevicePath
-  )
-{
-  EFI_DEVICE_PATH_PROTOCOL      *Node;
-  EFI_DEVICE_PATH_PROTOCOL      *NextNode;
-
-  ASSERT (DevicePath != NULL);
-
-  for (Node = DevicePath; !IsDevicePathEndType (Node); Node = NextDevicePathNode (Node)) {
-    switch (DevicePathType (Node)) {
-
-      case ACPI_DEVICE_PATH:
-        if (EISA_ID_TO_NUM (((ACPI_HID_DEVICE_PATH *) Node)->HID) == 0x0604) {
-          return BmAcpiFloppyBoot;
-        }
-        break;
-
-      case HARDWARE_DEVICE_PATH:
-        if (DevicePathSubType (Node) == HW_CONTROLLER_DP) {
-          return BmHardwareDeviceBoot;
-        }
-        break;
-
-      case MESSAGING_DEVICE_PATH:
-        //
-        // Skip LUN device node
-        //
-        NextNode = Node;
-        do {
-          NextNode = NextDevicePathNode (NextNode);
-        } while (
-            (DevicePathType (NextNode) == MESSAGING_DEVICE_PATH) &&
-            (DevicePathSubType(NextNode) == MSG_DEVICE_LOGICAL_UNIT_DP)
-            );
-
-        //
-        // If the device path not only point to driver device, it is not a messaging device path,
-        //
-        if (!IsDevicePathEndType (NextNode)) {
-          break;
-        }
-
-        switch (DevicePathSubType (Node)) {
-        case MSG_ATAPI_DP:
-          return BmMessageAtapiBoot;
-          break;
-
-        case MSG_SATA_DP:
-          return BmMessageSataBoot;
-          break;
-
-        case MSG_USB_DP:
-          return BmMessageUsbBoot;
-          break;
-
-        case MSG_SCSI_DP:
-          return BmMessageScsiBoot;
-          break;
-
-        case MSG_MAC_ADDR_DP:
-        case MSG_VLAN_DP:
-        case MSG_IPv4_DP:
-        case MSG_IPv6_DP:
-          return BmMessageNetworkBoot;
-          break;
-        }
-    }
-  }
-
-  return BmMiscBoot;
-}
-
-/**
-  Find the boot option in the NV storage and return the option number.
-
-  @param OptionToFind  Boot option to be checked.
-
-  @return   The option number of the found boot option.
-
-**/
-UINTN
-BmFindBootOptionInVariable (
-  IN  EFI_BOOT_MANAGER_LOAD_OPTION             *OptionToFind
-  )
-{
-  EFI_STATUS                   Status;
-  EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
-  UINTN                        OptionNumber;
-  CHAR16                       OptionName[BM_OPTION_NAME_LEN];
-  EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
-  UINTN                        BootOptionCount;
-  UINTN                        Index;
-  
-  OptionNumber = LoadOptionNumberUnassigned;
-
-  //
-  // Try to match the variable exactly if the option number is assigned
-  //
-  if (OptionToFind->OptionNumber != LoadOptionNumberUnassigned) {
-    UnicodeSPrint (
-      OptionName, sizeof (OptionName), L"%s%04x",
-      mBmLoadOptionName[OptionToFind->OptionType], OptionToFind->OptionNumber
-      );
-    Status = EfiBootManagerVariableToLoadOption (OptionName, &BootOption);
-
-    if (!EFI_ERROR (Status)) {
-      ASSERT (OptionToFind->OptionNumber == BootOption.OptionNumber);
-      if ((OptionToFind->Attributes == BootOption.Attributes) &&
-          (StrCmp (OptionToFind->Description, BootOption.Description) == 0) &&
-          (CompareMem (OptionToFind->FilePath, BootOption.FilePath, GetDevicePathSize (OptionToFind->FilePath)) == 0) &&
-          (OptionToFind->OptionalDataSize == BootOption.OptionalDataSize) &&
-          (CompareMem (OptionToFind->OptionalData, BootOption.OptionalData, OptionToFind->OptionalDataSize) == 0)
-         ) {
-        OptionNumber = OptionToFind->OptionNumber;
-      }
-      EfiBootManagerFreeLoadOption (&BootOption);
-    }
-  }
-
-  //
-  // The option number assigned is either incorrect or unassigned.
-  //
-  if (OptionNumber == LoadOptionNumberUnassigned) {
-    BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
-
-    Index = BmFindLoadOption (OptionToFind, BootOptions, BootOptionCount);
-    if (Index != -1) {
-      OptionNumber = BootOptions[Index].OptionNumber;
-    }
-
-    EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
-  }
-
-  return OptionNumber;
-}
-
-/**
-  Get the file buffer using a Memory Mapped Device Path.
-
-  FV address may change across reboot. This routine promises the FV file device path is right.
-
-  @param  DevicePath   The Memory Mapped Device Path to get the file buffer.
-  @param  FullPath     Receive the updated FV Device Path pointint to the file.
-  @param  FileSize     Receive the file buffer size.
-
-  @return  The file buffer.
-**/
-VOID *
-BmGetFileBufferByMemmapFv (
-  IN EFI_DEVICE_PATH_PROTOCOL      *DevicePath,
-  OUT EFI_DEVICE_PATH_PROTOCOL     **FullPath,
-  OUT UINTN                        *FileSize
-  )
-{
-  EFI_STATUS                    Status;
-  UINTN                         Index;
-  EFI_DEVICE_PATH_PROTOCOL      *FvFileNode;
-  EFI_HANDLE                    FvHandle;
-  EFI_LOADED_IMAGE_PROTOCOL     *LoadedImage;
-  UINT32                        AuthenticationStatus;
-  UINTN                         FvHandleCount;
-  EFI_HANDLE                    *FvHandles;
-  EFI_DEVICE_PATH_PROTOCOL      *NewDevicePath;
-  VOID                          *FileBuffer;
-  
-  FvFileNode = DevicePath;
-  Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &FvFileNode, &FvHandle);
-  if (!EFI_ERROR (Status)) {
-    FileBuffer = GetFileBufferByFilePath (TRUE, DevicePath, FileSize, &AuthenticationStatus);
-    if (FileBuffer != NULL) {
-      *FullPath = DuplicateDevicePath (DevicePath);
-    }
-    return FileBuffer;
-  }
-
-  FvFileNode = NextDevicePathNode (DevicePath);
-
-  //
-  // Firstly find the FV file in current FV
-  //
-  gBS->HandleProtocol (
-         gImageHandle,
-         &gEfiLoadedImageProtocolGuid,
-         (VOID **) &LoadedImage
-         );
-  NewDevicePath = AppendDevicePathNode (DevicePathFromHandle (LoadedImage->DeviceHandle), FvFileNode);
-  FileBuffer = BmGetFileBufferByMemmapFv (NewDevicePath, FullPath, FileSize);
-  FreePool (NewDevicePath);
-
-  if (FileBuffer != NULL) {
-    return FileBuffer;
-  }
-
-  //
-  // Secondly find the FV file in all other FVs
-  //
-  gBS->LocateHandleBuffer (
-         ByProtocol,
-         &gEfiFirmwareVolume2ProtocolGuid,
-         NULL,
-         &FvHandleCount,
-         &FvHandles
-         );
-  for (Index = 0; (Index < FvHandleCount) && (FileBuffer == NULL); Index++) {
-    if (FvHandles[Index] == LoadedImage->DeviceHandle) {
-      //
-      // Skip current FV
-      //
-      continue;
-    }
-    NewDevicePath = AppendDevicePathNode (DevicePathFromHandle (FvHandles[Index]), FvFileNode);
-    FileBuffer = BmGetFileBufferByMemmapFv (NewDevicePath, FullPath, FileSize);
-    FreePool (NewDevicePath);
-  }
-  
-  if (FvHandles != NULL) {
-    FreePool (FvHandles);
-  }
-  return FileBuffer;
-}
-
-/**
-  Check if it's a Memory Mapped FV Device Path.
-  
-  The function doesn't garentee the device path points to existing FV file.
-
-  @param  DevicePath     Input device path.
-
-  @retval TRUE   The device path is a Memory Mapped FV Device Path.
-  @retval FALSE  The device path is NOT a Memory Mapped FV Device Path.
-**/
-BOOLEAN
-BmIsMemmapFvFilePath (
-  IN EFI_DEVICE_PATH_PROTOCOL    *DevicePath
-  )
-{
-  EFI_DEVICE_PATH_PROTOCOL   *FileNode;
-
-  if ((DevicePathType (DevicePath) == HARDWARE_DEVICE_PATH) && (DevicePathSubType (DevicePath) == HW_MEMMAP_DP)) {
-    FileNode = NextDevicePathNode (DevicePath);
-    if ((DevicePathType (FileNode) == MEDIA_DEVICE_PATH) && (DevicePathSubType (FileNode) == MEDIA_PIWG_FW_FILE_DP)) {
-      return IsDevicePathEnd (NextDevicePathNode (FileNode));
-    }
-  }
-
-  return FALSE;
-}
-
-/**
-  Check whether a USB device match the specified USB Class device path. This
-  function follows "Load Option Processing" behavior in UEFI specification.
-
-  @param UsbIo       USB I/O protocol associated with the USB device.
-  @param UsbClass    The USB Class device path to match.
-
-  @retval TRUE       The USB device match the USB Class device path.
-  @retval FALSE      The USB device does not match the USB Class device path.
-
-**/
-BOOLEAN
-BmMatchUsbClass (
-  IN EFI_USB_IO_PROTOCOL        *UsbIo,
-  IN USB_CLASS_DEVICE_PATH      *UsbClass
-  )
-{
-  EFI_STATUS                    Status;
-  EFI_USB_DEVICE_DESCRIPTOR     DevDesc;
-  EFI_USB_INTERFACE_DESCRIPTOR  IfDesc;
-  UINT8                         DeviceClass;
-  UINT8                         DeviceSubClass;
-  UINT8                         DeviceProtocol;
-
-  if ((DevicePathType (UsbClass) != MESSAGING_DEVICE_PATH) ||
-      (DevicePathSubType (UsbClass) != MSG_USB_CLASS_DP)){
-    return FALSE;
-  }
-
-  //
-  // Check Vendor Id and Product Id.
-  //
-  Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);
-  if (EFI_ERROR (Status)) {
-    return FALSE;
-  }
-
-  if ((UsbClass->VendorId != 0xffff) &&
-      (UsbClass->VendorId != DevDesc.IdVendor)) {
-    return FALSE;
-  }
-
-  if ((UsbClass->ProductId != 0xffff) &&
-      (UsbClass->ProductId != DevDesc.IdProduct)) {
-    return FALSE;
-  }
-
-  DeviceClass    = DevDesc.DeviceClass;
-  DeviceSubClass = DevDesc.DeviceSubClass;
-  DeviceProtocol = DevDesc.DeviceProtocol;
-  if (DeviceClass == 0) {
-    //
-    // If Class in Device Descriptor is set to 0, use the Class, SubClass and
-    // Protocol in Interface Descriptor instead.
-    //
-    Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &IfDesc);
-    if (EFI_ERROR (Status)) {
-      return FALSE;
-    }
-
-    DeviceClass    = IfDesc.InterfaceClass;
-    DeviceSubClass = IfDesc.InterfaceSubClass;
-    DeviceProtocol = IfDesc.InterfaceProtocol;
-  }
-
-  //
-  // Check Class, SubClass and Protocol.
-  //
-  if ((UsbClass->DeviceClass != 0xff) &&
-      (UsbClass->DeviceClass != DeviceClass)) {
-    return FALSE;
-  }
-
-  if ((UsbClass->DeviceSubClass != 0xff) &&
-      (UsbClass->DeviceSubClass != DeviceSubClass)) {
-    return FALSE;
-  }
-
-  if ((UsbClass->DeviceProtocol != 0xff) &&
-      (UsbClass->DeviceProtocol != DeviceProtocol)) {
-    return FALSE;
-  }
-
-  return TRUE;
-}
-
-/**
-  Eliminate the extra spaces in the Str to one space.
-
-  @param    Str     Input string info.
-**/
-VOID
-BmEliminateExtraSpaces (
-  IN CHAR16                    *Str
-  )
-{
-  UINTN                        Index;
-  UINTN                        ActualIndex;
-
-  for (Index = 0, ActualIndex = 0; Str[Index] != L'\0'; Index++) {
-    if ((Str[Index] != L' ') || ((ActualIndex > 0) && (Str[ActualIndex - 1] != L' '))) {
-      Str[ActualIndex++] = Str[Index];
-    }
-  }
-  Str[ActualIndex] = L'\0';
-}
-
-/**
-  Try to get the controller's ATA/ATAPI description.
-
-  @param Handle                Controller handle.
-
-  @return  The description string.
-**/
-CHAR16 *
-BmGetDescriptionFromDiskInfo (
-  IN EFI_HANDLE                Handle
-  )
-{
-  UINTN                        Index;
-  EFI_STATUS                   Status;
-  EFI_DISK_INFO_PROTOCOL       *DiskInfo;
-  UINT32                       BufferSize;
-  EFI_ATAPI_IDENTIFY_DATA      IdentifyData;
-  EFI_SCSI_INQUIRY_DATA        InquiryData;
-  CHAR16                       *Description;
-  UINTN                        Length;
-  CONST UINTN                  ModelNameLength    = 40;
-  CONST UINTN                  SerialNumberLength = 20;
-  CHAR8                        *StrPtr;
-  UINT8                        Temp;
-
-  Description  = NULL;
-
-  Status = gBS->HandleProtocol (
-                  Handle,
-                  &gEfiDiskInfoProtocolGuid,
-                  (VOID **) &DiskInfo
-                  );
-  if (EFI_ERROR (Status)) {
-    return NULL;
-  }
-
-  if (CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoAhciInterfaceGuid) || 
-      CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoIdeInterfaceGuid)) {
-    BufferSize   = sizeof (EFI_ATAPI_IDENTIFY_DATA);
-    Status = DiskInfo->Identify (
-                         DiskInfo,
-                         &IdentifyData,
-                         &BufferSize
-                         );
-    if (!EFI_ERROR (Status)) {
-      Description = AllocateZeroPool ((ModelNameLength + SerialNumberLength + 2) * sizeof (CHAR16));
-      ASSERT (Description != NULL);
-      for (Index = 0; Index + 1 < ModelNameLength; Index += 2) {
-        Description[Index]     = (CHAR16) IdentifyData.ModelName[Index + 1];
-        Description[Index + 1] = (CHAR16) IdentifyData.ModelName[Index];
-      }
-
-      Length = Index;
-      Description[Length++] = L' ';
-
-      for (Index = 0; Index + 1 < SerialNumberLength; Index += 2) {
-        Description[Length + Index]     = (CHAR16) IdentifyData.SerialNo[Index + 1];
-        Description[Length + Index + 1] = (CHAR16) IdentifyData.SerialNo[Index];
-      }
-      Length += Index;
-      Description[Length++] = L'\0';
-      ASSERT (Length == ModelNameLength + SerialNumberLength + 2);
-
-      BmEliminateExtraSpaces (Description);
-    }
-  } else if (CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoScsiInterfaceGuid)) {
-    BufferSize   = sizeof (EFI_SCSI_INQUIRY_DATA);
-    Status = DiskInfo->Inquiry (
-                         DiskInfo,
-                         &InquiryData,
-                         &BufferSize
-                         );
-    if (!EFI_ERROR (Status)) {
-      Description = AllocateZeroPool ((VENDOR_IDENTIFICATION_LENGTH + PRODUCT_IDENTIFICATION_LENGTH + 2) * sizeof (CHAR16));
-      ASSERT (Description != NULL);
-
-      //
-      // Per SCSI spec, EFI_SCSI_INQUIRY_DATA.Reserved_5_95[3 - 10] save the Verdor identification
-      // EFI_SCSI_INQUIRY_DATA.Reserved_5_95[11 - 26] save the product identification, 
-      // Here combine the vendor identification and product identification to the description.
-      //
-      StrPtr = (CHAR8 *) (&InquiryData.Reserved_5_95[VENDOR_IDENTIFICATION_OFFSET]);
-      Temp = StrPtr[VENDOR_IDENTIFICATION_LENGTH];
-      StrPtr[VENDOR_IDENTIFICATION_LENGTH] = '\0';
-      AsciiStrToUnicodeStr (StrPtr, Description);
-      StrPtr[VENDOR_IDENTIFICATION_LENGTH] = Temp;
-
-      //
-      // Add one space at the middle of vendor information and product information.
-      //
-      Description[VENDOR_IDENTIFICATION_LENGTH] = L' ';
-
-      StrPtr = (CHAR8 *) (&InquiryData.Reserved_5_95[PRODUCT_IDENTIFICATION_OFFSET]);
-      StrPtr[PRODUCT_IDENTIFICATION_LENGTH] = '\0';
-      AsciiStrToUnicodeStr (StrPtr, Description + VENDOR_IDENTIFICATION_LENGTH + 1);
-
-      BmEliminateExtraSpaces (Description);
-    }
-  }
-
-  return Description;
-}
-
-/**
-  Try to get the controller's USB description.
-
-  @param Handle                Controller handle.
-
-  @return  The description string.
-**/
-CHAR16 *
-BmGetUsbDescription (
-  IN EFI_HANDLE                Handle
-  )
-{
-  EFI_STATUS                   Status;
-  EFI_USB_IO_PROTOCOL          *UsbIo;
-  CHAR16                       NullChar;
-  CHAR16                       *Manufacturer;
-  CHAR16                       *Product;
-  CHAR16                       *SerialNumber;
-  CHAR16                       *Description;
-  EFI_USB_DEVICE_DESCRIPTOR    DevDesc;
-
-  Status = gBS->HandleProtocol (
-                  Handle,
-                  &gEfiUsbIoProtocolGuid,
-                  (VOID **) &UsbIo
-                  );
-  if (EFI_ERROR (Status)) {
-    return NULL;
-  }
-
-  NullChar = L'\0';
-
-  Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);
-  if (EFI_ERROR (Status)) {
-    return NULL;
-  }
-
-  Status = UsbIo->UsbGetStringDescriptor (
-                    UsbIo,
-                    mBmUsbLangId,
-                    DevDesc.StrManufacturer,
-                    &Manufacturer
-                    );
-  if (EFI_ERROR (Status)) {
-    Manufacturer = &NullChar;
-  }
-  
-  Status = UsbIo->UsbGetStringDescriptor (
-                    UsbIo,
-                    mBmUsbLangId,
-                    DevDesc.StrProduct,
-                    &Product
-                    );
-  if (EFI_ERROR (Status)) {
-    Product = &NullChar;
-  }
-  
-  Status = UsbIo->UsbGetStringDescriptor (
-                    UsbIo,
-                    mBmUsbLangId,
-                    DevDesc.StrSerialNumber,
-                    &SerialNumber
-                    );
-  if (EFI_ERROR (Status)) {
-    SerialNumber = &NullChar;
-  }
-
-  if ((Manufacturer == &NullChar) &&
-      (Product == &NullChar) &&
-      (SerialNumber == &NullChar)
-      ) {
-    return NULL;
-  }
-
-  Description = AllocateZeroPool (StrSize (Manufacturer) + StrSize (Product) + StrSize (SerialNumber));
-  ASSERT (Description != NULL);
-  StrCat (Description, Manufacturer);
-  StrCat (Description, L" ");
-
-  StrCat (Description, Product);  
-  StrCat (Description, L" ");
-
-  StrCat (Description, SerialNumber);
-
-  if (Manufacturer != &NullChar) {
-    FreePool (Manufacturer);
-  }
-  if (Product != &NullChar) {
-    FreePool (Product);
-  }
-  if (SerialNumber != &NullChar) {
-    FreePool (SerialNumber);
-  }
-
-  BmEliminateExtraSpaces (Description);
-
-  return Description;
-}
-
-/**
-  Return the boot description for the controller based on the type.
-
-  @param Handle                Controller handle.
-
-  @return  The description string.
-**/
-CHAR16 *
-BmGetMiscDescription (
-  IN EFI_HANDLE                  Handle
-  )
-{
-  EFI_STATUS                     Status;
-  CHAR16                         *Description;
-  EFI_BLOCK_IO_PROTOCOL          *BlockIo;
-
-  switch (BmDevicePathType (DevicePathFromHandle (Handle))) {
-  case BmAcpiFloppyBoot:
-    Description = L"Floppy";
-    break;
-
-  case BmMessageAtapiBoot:
-  case BmMessageSataBoot:
-    Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
-    ASSERT_EFI_ERROR (Status);
-    //
-    // Assume a removable SATA device should be the DVD/CD device
-    //
-    Description = BlockIo->Media->RemovableMedia ? L"DVD/CDROM" : L"Hard Drive";
-    break;
-
-  case BmMessageUsbBoot:
-    Description = L"USB Device";
-    break;
-
-  case BmMessageScsiBoot:
-    Description = L"SCSI Device";
-    break;
-
-  case BmHardwareDeviceBoot:
-    Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
-    if (!EFI_ERROR (Status)) {
-      Description = BlockIo->Media->RemovableMedia ? L"Removable Disk" : L"Hard Drive";
-    } else {
-      Description = L"Misc Device";
-    }
-    break;
-
-  default:
-    Description = L"Misc Device";
-    break;
-  }
-
-  return AllocateCopyPool (StrSize (Description), Description);
-}
-
-BM_GET_BOOT_DESCRIPTION mBmGetBootDescription[] = {
-  BmGetUsbDescription,
-  BmGetDescriptionFromDiskInfo,
-  BmGetMiscDescription
-};
-
-/**
-  Check whether a USB device match the specified USB WWID device path. This
-  function follows "Load Option Processing" behavior in UEFI specification.
-
-  @param UsbIo       USB I/O protocol associated with the USB device.
-  @param UsbWwid     The USB WWID device path to match.
-
-  @retval TRUE       The USB device match the USB WWID device path.
-  @retval FALSE      The USB device does not match the USB WWID device path.
-
-**/
-BOOLEAN
-BmMatchUsbWwid (
-  IN EFI_USB_IO_PROTOCOL        *UsbIo,
-  IN USB_WWID_DEVICE_PATH       *UsbWwid
-  )
-{
-  EFI_STATUS                   Status;
-  EFI_USB_DEVICE_DESCRIPTOR    DevDesc;
-  EFI_USB_INTERFACE_DESCRIPTOR IfDesc;
-  UINT16                       *LangIdTable;
-  UINT16                       TableSize;
-  UINT16                       Index;
-  CHAR16                       *CompareStr;
-  UINTN                        CompareLen;
-  CHAR16                       *SerialNumberStr;
-  UINTN                        Length;
-
-  if ((DevicePathType (UsbWwid) != MESSAGING_DEVICE_PATH) ||
-      (DevicePathSubType (UsbWwid) != MSG_USB_WWID_DP)) {
-    return FALSE;
-  }
-
-  //
-  // Check Vendor Id and Product Id.
-  //
-  Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);
-  if (EFI_ERROR (Status)) {
-    return FALSE;
-  }
-  if ((DevDesc.IdVendor != UsbWwid->VendorId) ||
-      (DevDesc.IdProduct != UsbWwid->ProductId)) {
-    return FALSE;
-  }
-
-  //
-  // Check Interface Number.
-  //
-  Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &IfDesc);
-  if (EFI_ERROR (Status)) {
-    return FALSE;
-  }
-  if (IfDesc.InterfaceNumber != UsbWwid->InterfaceNumber) {
-    return FALSE;
-  }
-
-  //
-  // Check Serial Number.
-  //
-  if (DevDesc.StrSerialNumber == 0) {
-    return FALSE;
-  }
-
-  //
-  // Get all supported languages.
-  //
-  TableSize = 0;
-  LangIdTable = NULL;
-  Status = UsbIo->UsbGetSupportedLanguages (UsbIo, &LangIdTable, &TableSize);
-  if (EFI_ERROR (Status) || (TableSize == 0) || (LangIdTable == NULL)) {
-    return FALSE;
-  }
-
-  //
-  // Serial number in USB WWID device path is the last 64-or-less UTF-16 characters.
-  //
-  CompareStr = (CHAR16 *) (UINTN) (UsbWwid + 1);
-  CompareLen = (DevicePathNodeLength (UsbWwid) - sizeof (USB_WWID_DEVICE_PATH)) / sizeof (CHAR16);
-  if (CompareStr[CompareLen - 1] == L'\0') {
-    CompareLen--;
-  }
-
-  //
-  // Compare serial number in each supported language.
-  //
-  for (Index = 0; Index < TableSize / sizeof (UINT16); Index++) {
-    SerialNumberStr = NULL;
-    Status = UsbIo->UsbGetStringDescriptor (
-                      UsbIo,
-                      LangIdTable[Index],
-                      DevDesc.StrSerialNumber,
-                      &SerialNumberStr
-                      );
-    if (EFI_ERROR (Status) || (SerialNumberStr == NULL)) {
-      continue;
-    }
-
-    Length = StrLen (SerialNumberStr);
-    if ((Length >= CompareLen) &&
-        (CompareMem (SerialNumberStr + Length - CompareLen, CompareStr, CompareLen * sizeof (CHAR16)) == 0)) {
-      FreePool (SerialNumberStr);
-      return TRUE;
-    }
-
-    FreePool (SerialNumberStr);
-  }
-
-  return FALSE;
-}
-
-/**
-  Find a USB device which match the specified short-form device path start with 
-  USB Class or USB WWID device path. If ParentDevicePath is NULL, this function
-  will search in all USB devices of the platform. If ParentDevicePath is not NULL,
-  this function will only search in its child devices.
-
-  @param DevicePath           The device path that contains USB Class or USB WWID device path.
-  @param ParentDevicePathSize The length of the device path before the USB Class or 
-                              USB WWID device path.
-  @param UsbIoHandleCount     A pointer to the count of the returned USB IO handles.
-
-  @retval NULL       The matched USB IO handles cannot be found.
-  @retval other      The matched USB IO handles.
-
-**/
-EFI_HANDLE *
-BmFindUsbDevice (
-  IN  EFI_DEVICE_PATH_PROTOCOL  *DevicePath,
-  IN  UINTN                     ParentDevicePathSize,
-  OUT UINTN                     *UsbIoHandleCount
-  )
-{
-  EFI_STATUS                Status;
-  EFI_HANDLE                *UsbIoHandles;
-  EFI_DEVICE_PATH_PROTOCOL  *UsbIoDevicePath;
-  EFI_USB_IO_PROTOCOL       *UsbIo;
-  UINTN                     Index;
-  UINTN                     UsbIoDevicePathSize;
-  BOOLEAN                   Matched;
-
-  ASSERT (UsbIoHandleCount != NULL);  
-
-  //
-  // Get all UsbIo Handles.
-  //
-  Status = gBS->LocateHandleBuffer (
-                  ByProtocol,
-                  &gEfiUsbIoProtocolGuid,
-                  NULL,
-                  UsbIoHandleCount,
-                  &UsbIoHandles
-                  );
-  if (EFI_ERROR (Status)) {
-    *UsbIoHandleCount = 0;
-    UsbIoHandles      = NULL;
-  }
-
-  for (Index = 0; Index < *UsbIoHandleCount; ) {
-    //
-    // Get the Usb IO interface.
-    //
-    Status = gBS->HandleProtocol(
-                    UsbIoHandles[Index],
-                    &gEfiUsbIoProtocolGuid,
-                    (VOID **) &UsbIo
-                    );
-    UsbIoDevicePath = DevicePathFromHandle (UsbIoHandles[Index]);
-    Matched         = FALSE;
-    if (!EFI_ERROR (Status) && (UsbIoDevicePath != NULL)) {
-      UsbIoDevicePathSize = GetDevicePathSize (UsbIoDevicePath) - END_DEVICE_PATH_LENGTH;
-
-      //
-      // Compare starting part of UsbIoHandle's device path with ParentDevicePath.
-      //
-      if (CompareMem (UsbIoDevicePath, DevicePath, ParentDevicePathSize) == 0) {
-        if (BmMatchUsbClass (UsbIo, (USB_CLASS_DEVICE_PATH *) ((UINTN) DevicePath + ParentDevicePathSize)) ||
-            BmMatchUsbWwid (UsbIo, (USB_WWID_DEVICE_PATH *) ((UINTN) DevicePath + ParentDevicePathSize))) {
-          Matched = TRUE;
-        }
-      }
-    }
-
-    if (!Matched) {
-      (*UsbIoHandleCount) --;
-      CopyMem (&UsbIoHandles[Index], &UsbIoHandles[Index + 1], (*UsbIoHandleCount - Index) * sizeof (EFI_HANDLE));
-    } else {
-      Index++;
-    }
-  }
-
-  return UsbIoHandles;
-}
-
-/**
-  Expand USB Class or USB WWID device path node to be full device path of a USB
-  device in platform.
-
-  This function support following 4 cases:
-  1) Boot Option device path starts with a USB Class or USB WWID device path,
-     and there is no Media FilePath device path in the end.
-     In this case, it will follow Removable Media Boot Behavior.
-  2) Boot Option device path starts with a USB Class or USB WWID device path,
-     and ended with Media FilePath device path.
-  3) Boot Option device path starts with a full device path to a USB Host Controller,
-     contains a USB Class or USB WWID device path node, while not ended with Media
-     FilePath device path. In this case, it will follow Removable Media Boot Behavior.
-  4) Boot Option device path starts with a full device path to a USB Host Controller,
-     contains a USB Class or USB WWID device path node, and ended with Media
-     FilePath device path.
-
-  @param FilePath      The device path pointing to a load option.
-                       It could be a short-form device path.
-  @param FullPath      Return the full device path of the load option after
-                       short-form device path expanding.
-                       Caller is responsible to free it.
-  @param FileSize      Return the load option size.
-  @param ShortformNode Pointer to the USB short-form device path node in the FilePath buffer.
-
-  @return The load option buffer. Caller is responsible to free the memory.
-**/
-VOID *
-BmExpandUsbDevicePath (
-  IN  EFI_DEVICE_PATH_PROTOCOL  *FilePath,
-  OUT EFI_DEVICE_PATH_PROTOCOL  **FullPath,
-  OUT UINTN                     *FileSize,
-  IN EFI_DEVICE_PATH_PROTOCOL   *ShortformNode
-  )
-{
-  UINTN                             ParentDevicePathSize;
-  EFI_DEVICE_PATH_PROTOCOL          *RemainingDevicePath;
-  EFI_DEVICE_PATH_PROTOCOL          *FullDevicePath;
-  EFI_HANDLE                        *Handles;
-  UINTN                             HandleCount;
-  UINTN                             Index;
-  VOID                              *FileBuffer;
-
-  ParentDevicePathSize = (UINTN) ShortformNode - (UINTN) FilePath;
-  RemainingDevicePath = NextDevicePathNode (ShortformNode);
-  FileBuffer = NULL;
-  Handles = BmFindUsbDevice (FilePath, ParentDevicePathSize, &HandleCount);
-
-  for (Index = 0; (Index < HandleCount) && (FileBuffer == NULL); Index++) {
-    FullDevicePath = AppendDevicePath (DevicePathFromHandle (Handles[Index]), RemainingDevicePath);
-    FileBuffer = BmGetLoadOptionBuffer (FullDevicePath, FullPath, FileSize);
-    FreePool (FullDevicePath);
-  }
-
-  if (Handles != NULL) {
-    FreePool (Handles);
-  }
-
-  return FileBuffer;
-}
-
-/**
-  Save the partition DevicePath to the CachedDevicePath as the first instance.
-
-  @param CachedDevicePath  The device path cache.
-  @param DevicePath        The partition device path to be cached.
-**/
-VOID
-BmCachePartitionDevicePath (
-  IN OUT EFI_DEVICE_PATH_PROTOCOL **CachedDevicePath,
-  IN EFI_DEVICE_PATH_PROTOCOL     *DevicePath
-  )
-{
-  EFI_DEVICE_PATH_PROTOCOL        *TempDevicePath;
-  UINTN                           Count;
-  
-  if (BmMatchDevicePaths (*CachedDevicePath, DevicePath)) {
-    TempDevicePath = *CachedDevicePath;
-    *CachedDevicePath = BmDelPartMatchInstance (*CachedDevicePath, DevicePath);
-    FreePool (TempDevicePath);
-  }
-
-  if (*CachedDevicePath == NULL) {
-    *CachedDevicePath = DuplicateDevicePath (DevicePath);
-    return;
-  }
-
-  TempDevicePath = *CachedDevicePath;
-  *CachedDevicePath = AppendDevicePathInstance (DevicePath, *CachedDevicePath);
-  if (TempDevicePath != NULL) {
-    FreePool (TempDevicePath);
-  }
-
-  //
-  // Here limit the device path instance number to 12, which is max number for a system support 3 IDE controller
-  // If the user try to boot many OS in different HDs or partitions, in theory, the 'HDDP' variable maybe become larger and larger.
-  //
-  Count = 0;
-  TempDevicePath = *CachedDevicePath;
-  while (!IsDevicePathEnd (TempDevicePath)) {
-    TempDevicePath = NextDevicePathNode (TempDevicePath);
-    //
-    // Parse one instance
-    //
-    while (!IsDevicePathEndType (TempDevicePath)) {
-      TempDevicePath = NextDevicePathNode (TempDevicePath);
-    }
-    Count++;
-    //
-    // If the CachedDevicePath variable contain too much instance, only remain 12 instances.
-    //
-    if (Count == 12) {
-      SetDevicePathEndNode (TempDevicePath);
-      break;
-    }
-  }
-}
-
-/**
-  Expand a device path that starts with a hard drive media device path node to be a
-  full device path that includes the full hardware path to the device. We need
-  to do this so it can be booted. As an optimization the front match (the part point
-  to the partition node. E.g. ACPI() /PCI()/ATA()/Partition() ) is saved in a variable
-  so a connect all is not required on every boot. All successful history device path
-  which point to partition node (the front part) will be saved.
-
-  @param FilePath      The device path pointing to a load option.
-                       It could be a short-form device path.
-  @param FullPath      Return the full device path of the load option after
-                       short-form device path expanding.
-                       Caller is responsible to free it.
-  @param FileSize      Return the load option size.
-
-  @return The load option buffer. Caller is responsible to free the memory.
-**/
-VOID *
-BmExpandPartitionDevicePath (
-  IN  EFI_DEVICE_PATH_PROTOCOL  *FilePath,
-  OUT EFI_DEVICE_PATH_PROTOCOL  **FullPath,
-  OUT UINTN                     *FileSize
-  )
-{
-  EFI_STATUS                Status;
-  UINTN                     BlockIoHandleCount;
-  EFI_HANDLE                *BlockIoBuffer;
-  VOID                      *FileBuffer;
-  EFI_DEVICE_PATH_PROTOCOL  *BlockIoDevicePath;
-  UINTN                     Index;
-  EFI_DEVICE_PATH_PROTOCOL  *CachedDevicePath;
-  EFI_DEVICE_PATH_PROTOCOL  *TempNewDevicePath;
-  EFI_DEVICE_PATH_PROTOCOL  *TempDevicePath;
-  UINTN                     CachedDevicePathSize;
-  BOOLEAN                   NeedAdjust;
-  EFI_DEVICE_PATH_PROTOCOL  *Instance;
-  UINTN                     Size;
-
-  FileBuffer = NULL;
-  //
-  // Check if there is prestore 'HDDP' variable.
-  // If exist, search the front path which point to partition node in the variable instants.
-  // If fail to find or 'HDDP' not exist, reconnect all and search in all system
-  //
-  GetVariable2 (L"HDDP", &mBmHardDriveBootVariableGuid, (VOID **) &CachedDevicePath, &CachedDevicePathSize);
-
-  //
-  // Delete the invalid 'HDDP' variable.
-  //
-  if ((CachedDevicePath != NULL) && !IsDevicePathValid (CachedDevicePath, CachedDevicePathSize)) {
-    FreePool (CachedDevicePath);
-    CachedDevicePath = NULL;
-    Status = gRT->SetVariable (
-                    L"HDDP",
-                    &mBmHardDriveBootVariableGuid,
-                    0,
-                    0,
-                    NULL
-                    );
-    ASSERT_EFI_ERROR (Status);
-  }
-
-  if (CachedDevicePath != NULL) {
-    TempNewDevicePath = CachedDevicePath;
-    NeedAdjust = FALSE;
-    do {
-      //
-      // Check every instance of the variable
-      // First, check whether the instance contain the partition node, which is needed for distinguishing  multi
-      // partial partition boot option. Second, check whether the instance could be connected.
-      //
-      Instance  = GetNextDevicePathInstance (&TempNewDevicePath, &Size);
-      if (BmMatchPartitionDevicePathNode (Instance, (HARDDRIVE_DEVICE_PATH *) FilePath)) {
-        //
-        // Connect the device path instance, the device path point to hard drive media device path node
-        // e.g. ACPI() /PCI()/ATA()/Partition()
-        //
-        Status = EfiBootManagerConnectDevicePath (Instance, NULL);
-        if (!EFI_ERROR (Status)) {
-          TempDevicePath = AppendDevicePath (Instance, NextDevicePathNode (FilePath));
-          FileBuffer = BmGetLoadOptionBuffer (TempDevicePath, FullPath, FileSize);
-          FreePool (TempDevicePath);
-
-          if (FileBuffer != NULL) {
-            //
-            // Adjust the 'HDDP' instances sequence if the matched one is not first one.
-            //
-            if (NeedAdjust) {
-              BmCachePartitionDevicePath (&CachedDevicePath, Instance);
-              //
-              // Save the matching Device Path so we don't need to do a connect all next time
-              // Failing to save only impacts performance next time expanding the short-form device path
-              //
-              Status = gRT->SetVariable (
-                L"HDDP",
-                &mBmHardDriveBootVariableGuid,
-                EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
-                GetDevicePathSize (CachedDevicePath),
-                CachedDevicePath
-                );
-            }
-
-            FreePool (Instance);
-            FreePool (CachedDevicePath);
-            return FileBuffer;
-          }
-        }
-      }
-      //
-      // Come here means the first instance is not matched
-      //
-      NeedAdjust = TRUE;
-      FreePool(Instance);
-    } while (TempNewDevicePath != NULL);
-  }
-
-  //
-  // If we get here we fail to find or 'HDDP' not exist, and now we need
-  // to search all devices in the system for a matched partition
-  //
-  EfiBootManagerConnectAll ();
-  Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &BlockIoHandleCount, &BlockIoBuffer);
-  if (EFI_ERROR (Status)) {
-    BlockIoHandleCount = 0;
-    BlockIoBuffer      = NULL;
-  }
-  //
-  // Loop through all the device handles that support the BLOCK_IO Protocol
-  //
-  for (Index = 0; Index < BlockIoHandleCount; Index++) {
-    BlockIoDevicePath = DevicePathFromHandle (BlockIoBuffer[Index]);
-    if (BlockIoDevicePath == NULL) {
-      continue;
-    }
-
-    if (BmMatchPartitionDevicePathNode (BlockIoDevicePath, (HARDDRIVE_DEVICE_PATH *) FilePath)) {
-      //
-      // Find the matched partition device path
-      //
-      TempDevicePath = AppendDevicePath (BlockIoDevicePath, NextDevicePathNode (FilePath));
-      FileBuffer = BmGetLoadOptionBuffer (TempDevicePath, FullPath, FileSize);
-      FreePool (TempDevicePath);
-
-      if (FileBuffer != NULL) {
-        BmCachePartitionDevicePath (&CachedDevicePath, BlockIoDevicePath);
-
-        //
-        // Save the matching Device Path so we don't need to do a connect all next time
-        // Failing to save only impacts performance next time expanding the short-form device path
-        //
-        Status = gRT->SetVariable (
-                        L"HDDP",
-                        &mBmHardDriveBootVariableGuid,
-                        EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
-                        GetDevicePathSize (CachedDevicePath),
-                        CachedDevicePath
-                        );
-
-        break;
-      }
-    }
-  }
-
-  if (CachedDevicePath != NULL) {
-    FreePool (CachedDevicePath);
-  }
-  if (BlockIoBuffer != NULL) {
-    FreePool (BlockIoBuffer);
-  }
-  return FileBuffer;
-}
-
-/**
-  Expand the media device path which points to a BlockIo or SimpleFileSystem instance
-  by appending EFI_REMOVABLE_MEDIA_FILE_NAME.
-
-  @param DevicePath  The media device path pointing to a BlockIo or SimpleFileSystem instance.
-  @param FullPath    Return the full device path pointing to the load option.
-  @param FileSize    Return the size of the load option.
-
-  @return  The load option buffer.
-**/
-VOID *
-BmExpandMediaDevicePath (
-  IN  EFI_DEVICE_PATH_PROTOCOL        *DevicePath,
-  OUT EFI_DEVICE_PATH_PROTOCOL        **FullPath,
-  OUT UINTN                           *FileSize
-  )
-{
-  EFI_STATUS                          Status;
-  EFI_HANDLE                          Handle;
-  EFI_BLOCK_IO_PROTOCOL               *BlockIo;
-  VOID                                *Buffer;
-  EFI_DEVICE_PATH_PROTOCOL            *TempDevicePath;
-  UINTN                               Size;
-  UINTN                               TempSize;
-  EFI_HANDLE                          *SimpleFileSystemHandles;
-  UINTN                               NumberSimpleFileSystemHandles;
-  UINTN                               Index;
-  VOID                                *FileBuffer;
-  UINT32                              AuthenticationStatus;
-
-  //
-  // Check whether the device is connected
-  //
-  TempDevicePath = DevicePath;
-  Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &TempDevicePath, &Handle);
-  if (!EFI_ERROR (Status)) {
-    ASSERT (IsDevicePathEnd (TempDevicePath));
-
-    TempDevicePath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME);
-    FileBuffer = GetFileBufferByFilePath (TRUE, TempDevicePath, FileSize, &AuthenticationStatus);
-    if (FileBuffer == NULL) {
-      FreePool (TempDevicePath);
-      TempDevicePath = NULL;
-    }
-    *FullPath = TempDevicePath;
-    return FileBuffer;
-  }
-
-  //
-  // For device boot option only pointing to the removable device handle, 
-  // should make sure all its children handles (its child partion or media handles) are created and connected. 
-  //
-  gBS->ConnectController (Handle, NULL, NULL, TRUE);
-
-  //
-  // Issue a dummy read to the device to check for media change.
-  // When the removable media is changed, any Block IO read/write will
-  // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is
-  // returned. After the Block IO protocol is reinstalled, subsequent
-  // Block IO read/write will success.
-  //
-  Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, &Handle);
-  ASSERT_EFI_ERROR (Status);
-  Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
-  ASSERT_EFI_ERROR (Status);
-  Buffer = AllocatePool (BlockIo->Media->BlockSize);
-  if (Buffer != NULL) {
-    BlockIo->ReadBlocks (
-      BlockIo,
-      BlockIo->Media->MediaId,
-      0,
-      BlockIo->Media->BlockSize,
-      Buffer
-      );
-    FreePool (Buffer);
-  }
-
-  //
-  // Detect the the default boot file from removable Media
-  //
-  FileBuffer = NULL;
-  *FullPath = NULL;
-  Size = GetDevicePathSize (DevicePath) - END_DEVICE_PATH_LENGTH;
-  gBS->LocateHandleBuffer (
-         ByProtocol,
-         &gEfiSimpleFileSystemProtocolGuid,
-         NULL,
-         &NumberSimpleFileSystemHandles,
-         &SimpleFileSystemHandles
-         );
-  for (Index = 0; Index < NumberSimpleFileSystemHandles; Index++) {
-    //
-    // Get the device path size of SimpleFileSystem handle
-    //
-    TempDevicePath = DevicePathFromHandle (SimpleFileSystemHandles[Index]);
-    TempSize = GetDevicePathSize (TempDevicePath) - END_DEVICE_PATH_LENGTH;
-    //
-    // Check whether the device path of boot option is part of the SimpleFileSystem handle's device path
-    //
-    if ((Size <= TempSize) && (CompareMem (TempDevicePath, DevicePath, Size) == 0)) {
-      TempDevicePath = FileDevicePath (SimpleFileSystemHandles[Index], EFI_REMOVABLE_MEDIA_FILE_NAME);
-      FileBuffer = GetFileBufferByFilePath (TRUE, TempDevicePath, FileSize, &AuthenticationStatus);
-      if (FileBuffer != NULL) {
-        *FullPath = TempDevicePath;
-        break;
-      }
-      FreePool (TempDevicePath);
-    }
-  }
-
-  if (SimpleFileSystemHandles != NULL) {
-    FreePool (SimpleFileSystemHandles);
-  }
-
-  return FileBuffer;
-}
-
-/**
-  Get the load option by its device path.
-
-  @param FilePath  The device path pointing to a load option.
-                   It could be a short-form device path.
-  @param FullPath  Return the full device path of the load option after
-                   short-form device path expanding.
-                   Caller is responsible to free it.
-  @param FileSize  Return the load option size.
-
-  @return The load option buffer. Caller is responsible to free the memory.
-**/
-VOID *
-BmGetLoadOptionBuffer (
-  IN  EFI_DEVICE_PATH_PROTOCOL          *FilePath,
-  OUT EFI_DEVICE_PATH_PROTOCOL          **FullPath,
-  OUT UINTN                             *FileSize
-  )
-{
-  EFI_HANDLE                      Handle;
-  VOID                            *FileBuffer;
-  UINT32                          AuthenticationStatus;
-  EFI_DEVICE_PATH_PROTOCOL        *Node;
-  EFI_STATUS                      Status;
-
-  ASSERT ((FilePath != NULL) && (FullPath != NULL) && (FileSize != NULL));
-
-  EfiBootManagerConnectDevicePath (FilePath, NULL);
-
-  *FullPath  = NULL;
-  *FileSize  = 0;
-  FileBuffer = NULL;
-
-  //
-  // Boot from media device by adding a default file name \EFI\BOOT\BOOT{machine type short-name}.EFI
-  //
-  Node = FilePath;
-  Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &Node, &Handle);
-  if (EFI_ERROR (Status)) {
-    Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &Node, &Handle);
-  }
-
-  if (!EFI_ERROR (Status) && IsDevicePathEnd (Node)) {
-    return BmExpandMediaDevicePath (FilePath, FullPath, FileSize);
-  }
-
-  //
-  // Expand the short-form device path to full device path
-  //
-  if ((DevicePathType (FilePath) == MEDIA_DEVICE_PATH) &&
-      (DevicePathSubType (FilePath) == MEDIA_HARDDRIVE_DP)) {
-    //
-    // Expand the Harddrive device path
-    //
-    return BmExpandPartitionDevicePath (FilePath, FullPath, FileSize);
-  } else {
-    for (Node = FilePath; !IsDevicePathEnd (Node); Node = NextDevicePathNode (Node)) {
-      if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) &&
-          ((DevicePathSubType (Node) == MSG_USB_CLASS_DP) || (DevicePathSubType (Node) == MSG_USB_WWID_DP))) {
-        break;
-      }
-    }
-
-    if (!IsDevicePathEnd (Node)) {
-      //
-      // Expand the USB WWID/Class device path
-      //
-      FileBuffer = BmExpandUsbDevicePath (FilePath, FullPath, FileSize, Node);
-      if ((FileBuffer == NULL) && (FilePath == Node)) {
-        //
-        // Boot Option device path starts with USB Class or USB WWID device path.
-        // For Boot Option device path which doesn't begin with the USB Class or
-        // USB WWID device path, it's not needed to connect again here.
-        //
-        BmConnectUsbShortFormDevicePath (FilePath);
-        FileBuffer = BmExpandUsbDevicePath (FilePath, FullPath, FileSize, Node);
-      }
-      return FileBuffer;
-    }
-  }
-
-  //
-  // Fix up the boot option path if it points to a FV in memory map style of device path
-  //
-  if (BmIsMemmapFvFilePath (FilePath)) {
-    return BmGetFileBufferByMemmapFv (FilePath, FullPath, FileSize);
-  }
-
-  //
-  // Directly reads the load option when it doesn't reside in simple file system instance (LoadFile/LoadFile2),
-  //   or it directly points to a file in simple file system instance.
-  //
-  FileBuffer = GetFileBufferByFilePath (TRUE, FilePath, FileSize, &AuthenticationStatus);
-  if (FileBuffer != NULL) {
-    *FullPath = DuplicateDevicePath (FilePath);
-  }
-
-  return FileBuffer;
-}
-
-/**
-  Attempt to boot the EFI boot option. This routine sets L"BootCurent" and
-  also signals the EFI ready to boot event. If the device path for the option
-  starts with a BBS device path a legacy boot is attempted via the registered 
-  gLegacyBoot function. Short form device paths are also supported via this 
-  rountine. A device path starting with MEDIA_HARDDRIVE_DP, MSG_USB_WWID_DP,
-  MSG_USB_CLASS_DP gets expaned out to find the first device that matches.
-  If the BootOption Device Path fails the removable media boot algorithm 
-  is attempted (\EFI\BOOTIA32.EFI, \EFI\BOOTX64.EFI,... only one file type 
-  is tried per processor type)
-
-  @param  BootOption    Boot Option to try and boot.
-                        On return, BootOption->Status contains the boot status.
-                        EFI_SUCCESS     BootOption was booted
-                        EFI_UNSUPPORTED A BBS device path was found with no valid callback
-                                        registered via EfiBootManagerInitialize().
-                        EFI_NOT_FOUND   The BootOption was not found on the system
-                        !EFI_SUCCESS    BootOption failed with this error status
-
-**/
-VOID
-EFIAPI
-EfiBootManagerBoot (
-  IN  EFI_BOOT_MANAGER_LOAD_OPTION             *BootOption
-  )
-{
-  EFI_STATUS                Status;
-  EFI_HANDLE                ImageHandle;
-  EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;
-  UINT16                    Uint16;
-  UINTN                     OptionNumber;
-  UINTN                     OriginalOptionNumber;
-  EFI_DEVICE_PATH_PROTOCOL  *FilePath;
-  EFI_DEVICE_PATH_PROTOCOL  *Node;
-  EFI_HANDLE                FvHandle;
-  VOID                      *FileBuffer;
-  UINTN                     FileSize;
-  EFI_BOOT_LOGO_PROTOCOL    *BootLogo;
-  EFI_EVENT                 LegacyBootEvent;
-
-  if (BootOption == NULL) {
-    return;
-  }
-
-  if (BootOption->FilePath == NULL || BootOption->OptionType != LoadOptionTypeBoot) {
-    BootOption->Status = EFI_INVALID_PARAMETER;
-    return;
-  }
-
-  //
-  // 1. Create Boot#### for a temporary boot if there is no match Boot#### (i.e. a boot by selected a EFI Shell using "Boot From File")
-  //
-  OptionNumber = BmFindBootOptionInVariable (BootOption);
-  if (OptionNumber == LoadOptionNumberUnassigned) {
-    Status = BmGetFreeOptionNumber (LoadOptionTypeBoot, &Uint16);
-    if (!EFI_ERROR (Status)) {
-      //
-      // Save the BootOption->OptionNumber to restore later
-      //
-      OptionNumber             = Uint16;
-      OriginalOptionNumber     = BootOption->OptionNumber;
-      BootOption->OptionNumber = OptionNumber;
-      Status = EfiBootManagerLoadOptionToVariable (BootOption);
-      BootOption->OptionNumber = OriginalOptionNumber;
-    }
-
-    if (EFI_ERROR (Status)) {
-      DEBUG ((EFI_D_ERROR, "[Bds] Failed to create Boot#### for a temporary boot - %r!\n", Status));
-      BootOption->Status = Status;
-      return ;
-    }
-  }
-
-  //
-  // 2. Set BootCurrent
-  //
-  Uint16 = (UINT16) OptionNumber;
-  BmSetVariableAndReportStatusCodeOnError (
-    L"BootCurrent",
-    &gEfiGlobalVariableGuid,
-    EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
-    sizeof (UINT16),
-    &Uint16
-    );
-
-  //
-  // 3. Signal the EVT_SIGNAL_READY_TO_BOOT event when we are about to load and execute
-  //    the boot option.
-  //
-  Node   = BootOption->FilePath;
-  Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &Node, &FvHandle);
-  if (!EFI_ERROR (Status) && CompareGuid (
-        EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) Node),
-        PcdGetPtr (PcdBootManagerMenuFile)
-        )) {
-    DEBUG ((EFI_D_INFO, "[Bds] Booting Boot Manager Menu.\n"));
-    BmStopHotkeyService (NULL, NULL);
-  } else {
-    EfiSignalEventReadyToBoot();
-    //
-    // Report Status Code to indicate ReadyToBoot was signalled
-    //
-    REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT));
-    //
-    // 4. Repair system through DriverHealth protocol
-    //
-    BmRepairAllControllers ();
-  }
-
-  PERF_START_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32) OptionNumber);
-
-  //
-  // 5. Load EFI boot option to ImageHandle
-  //
-  ImageHandle = NULL;
-  if (BmDevicePathType (BootOption->FilePath) != BBS_DEVICE_PATH) {
-    Status     = EFI_NOT_FOUND;
-    FileBuffer = BmGetLoadOptionBuffer (BootOption->FilePath, &FilePath, &FileSize);
-    DEBUG_CODE (
-      if (FileBuffer != NULL && CompareMem (BootOption->FilePath, FilePath, GetDevicePathSize (FilePath)) != 0) {
-        DEBUG ((EFI_D_INFO, "[Bds] DevicePath expand: "));
-        BmPrintDp (BootOption->FilePath);
-        DEBUG ((EFI_D_INFO, " -> "));
-        BmPrintDp (FilePath);
-        DEBUG ((EFI_D_INFO, "\n"));
-      }
-    );
-    if (BmIsLoadOptionPeHeaderValid (BootOption->OptionType, FileBuffer, FileSize)) {
-      REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderLoad));
-      Status = gBS->LoadImage (
-                      TRUE,
-                      gImageHandle,
-                      FilePath,
-                      FileBuffer,
-                      FileSize,
-                      &ImageHandle
-                      );
-    }
-    if (FileBuffer != NULL) {
-      FreePool (FileBuffer);
-    }
-    if (FilePath != NULL) {
-      FreePool (FilePath);
-    }
-
-    if (EFI_ERROR (Status)) {
-      //
-      // Report Status Code to indicate that the failure to load boot option
-      //
-      REPORT_STATUS_CODE (
-        EFI_ERROR_CODE | EFI_ERROR_MINOR,
-        (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR)
-        );
-      BootOption->Status = Status;
-      return;
-    }
-  }
-
-  //
-  // 6. Adjust the different type memory page number just before booting
-  //    and save the updated info into the variable for next boot to use
-  //
-  if ((BootOption->Attributes & LOAD_OPTION_CATEGORY) == LOAD_OPTION_CATEGORY_BOOT) {
-    if (PcdGetBool (PcdResetOnMemoryTypeInformationChange)) {
-      BmSetMemoryTypeInformationVariable ();
-    }
-  }
-
-  DEBUG_CODE_BEGIN();
-    if (BootOption->Description == NULL) {
-      DEBUG ((DEBUG_INFO | DEBUG_LOAD, "[Bds]Booting from unknown device path\n"));
-    } else {
-      DEBUG ((DEBUG_INFO | DEBUG_LOAD, "[Bds]Booting %s\n", BootOption->Description));
-    }
-  DEBUG_CODE_END();
-
-  //
-  // Check to see if we should legacy BOOT. If yes then do the legacy boot
-  // Write boot to OS performance data for Legacy boot
-  //
-  if ((DevicePathType (BootOption->FilePath) == BBS_DEVICE_PATH) && (DevicePathSubType (BootOption->FilePath) == BBS_BBS_DP)) {
-    if (mBmLegacyBoot != NULL) {
-      //
-      // Write boot to OS performance data for legacy boot.
-      //
-      PERF_CODE (
-        //
-        // Create an event to be signalled when Legacy Boot occurs to write performance data.
-        //
-        Status = EfiCreateEventLegacyBootEx(
-                   TPL_NOTIFY,
-                   BmWriteBootToOsPerformanceData,
-                   NULL, 
-                   &LegacyBootEvent
-                   );
-        ASSERT_EFI_ERROR (Status);
-      );
-
-      mBmLegacyBoot (BootOption);
-    } else {
-      BootOption->Status = EFI_UNSUPPORTED;
-    }
-
-    PERF_END_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32) OptionNumber);
-    return;
-  }
-  //
-  // Provide the image with its load options
-  //
-  Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);
-  ASSERT_EFI_ERROR (Status);
-
-  ImageInfo->LoadOptionsSize  = BootOption->OptionalDataSize;
-  ImageInfo->LoadOptions      = BootOption->OptionalData;
-
-  //
-  // Clean to NULL because the image is loaded directly from the firmwares boot manager.
-  //
-  ImageInfo->ParentHandle = NULL;
-
-  //
-  // Before calling the image, enable the Watchdog Timer for 5 minutes period
-  //
-  gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);
-
-  //
-  // Write boot to OS performance data for UEFI boot
-  //
-  PERF_CODE (
-    BmWriteBootToOsPerformanceData (NULL, NULL);
-  );
-
-  REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderStart));
-
-  Status = gBS->StartImage (ImageHandle, &BootOption->ExitDataSize, &BootOption->ExitData);
-  DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Image Return Status = %r\n", Status));
-  BootOption->Status = Status;
-  if (EFI_ERROR (Status)) {
-    //
-    // Report Status Code to indicate that boot failure
-    //
-    REPORT_STATUS_CODE (
-      EFI_ERROR_CODE | EFI_ERROR_MINOR,
-      (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED)
-      );
-  }
-  PERF_END_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32) OptionNumber);
-
-  //
-  // Clear the Watchdog Timer after the image returns
-  //
-  gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
-
-  //
-  // Set Logo status invalid after trying one boot option
-  //
-  BootLogo = NULL;
-  Status = gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo);
-  if (!EFI_ERROR (Status) && (BootLogo != NULL)) {
-    Status = BootLogo->SetBootLogo (BootLogo, NULL, 0, 0, 0, 0);
-    ASSERT_EFI_ERROR (Status);
-  }
-
-  //
-  // Clear Boot Current
-  //
-  Status = gRT->SetVariable (
-                  L"BootCurrent",
-                  &gEfiGlobalVariableGuid,
-                  0,
-                  0,
-                  NULL
-                  );
-  //
-  // Deleting variable with current variable implementation shouldn't fail.
-  // When BootXXXX (e.g.: BootManagerMenu) boots BootYYYY, exiting BootYYYY causes BootCurrent deleted,
-  // exiting BootXXXX causes deleting BootCurrent returns EFI_NOT_FOUND.
-  //
-  ASSERT (Status == EFI_SUCCESS || Status == EFI_NOT_FOUND);
-}
-
-/**
-  Check whether there is a instance in BlockIoDevicePath, which contain multi device path
-  instances, has the same partition node with HardDriveDevicePath device path
-
-  @param  BlockIoDevicePath      Multi device path instances which need to check
-  @param  HardDriveDevicePath    A device path which starts with a hard drive media
-                                 device path.
-
-  @retval TRUE                   There is a matched device path instance.
-  @retval FALSE                  There is no matched device path instance.
-
-**/
-BOOLEAN
-BmMatchPartitionDevicePathNode (
-  IN  EFI_DEVICE_PATH_PROTOCOL   *BlockIoDevicePath,
-  IN  HARDDRIVE_DEVICE_PATH      *HardDriveDevicePath
-  )
-{
-  HARDDRIVE_DEVICE_PATH     *Node;
-
-  if ((BlockIoDevicePath == NULL) || (HardDriveDevicePath == NULL)) {
-    return FALSE;
-  }
-
-  //
-  // find the partition device path node
-  //
-  while (!IsDevicePathEnd (BlockIoDevicePath)) {
-    if ((DevicePathType (BlockIoDevicePath) == MEDIA_DEVICE_PATH) &&
-        (DevicePathSubType (BlockIoDevicePath) == MEDIA_HARDDRIVE_DP)
-        ) {
-      break;
-    }
-
-    BlockIoDevicePath = NextDevicePathNode (BlockIoDevicePath);
-  }
-
-  if (IsDevicePathEnd (BlockIoDevicePath)) {
-    return FALSE;
-  }
-
-  //
-  // See if the harddrive device path in blockio matches the orig Hard Drive Node
-  //
-  Node = (HARDDRIVE_DEVICE_PATH *) BlockIoDevicePath;
-
-  //
-  // Match Signature and PartitionNumber.
-  // Unused bytes in Signature are initiaized with zeros.
-  //
-  return (BOOLEAN) (
-    (Node->PartitionNumber == HardDriveDevicePath->PartitionNumber) &&
-    (Node->MBRType == HardDriveDevicePath->MBRType) &&
-    (Node->SignatureType == HardDriveDevicePath->SignatureType) &&
-    (CompareMem (Node->Signature, HardDriveDevicePath->Signature, sizeof (Node->Signature)) == 0)
-    );
-}
-
-/**
-  Emuerate all possible bootable medias in the following order:
-  1. Removable BlockIo            - The boot option only points to the removable media
-                                    device, like USB key, DVD, Floppy etc.
-  2. Fixed BlockIo                - The boot option only points to a Fixed blockIo device,
-                                    like HardDisk.
-  3. Non-BlockIo SimpleFileSystem - The boot option points to a device supporting
-                                    SimpleFileSystem Protocol, but not supporting BlockIo
-                                    protocol.
-  4. LoadFile                     - The boot option points to the media supporting 
-                                    LoadFile protocol.
-  Reference: UEFI Spec chapter 3.3 Boot Option Variables Default Boot Behavior
-
-  @param BootOptionCount   Return the boot option count which has been found.
-
-  @retval   Pointer to the boot option array.
-**/
-EFI_BOOT_MANAGER_LOAD_OPTION *
-BmEnumerateBootOptions (
-  UINTN                                 *BootOptionCount
-  )
-{
-  EFI_STATUS                            Status;
-  EFI_BOOT_MANAGER_LOAD_OPTION          *BootOptions;
-  UINT16                                NonBlockNumber;
-  UINTN                                 HandleCount;
-  EFI_HANDLE                            *Handles;
-  EFI_BLOCK_IO_PROTOCOL                 *BlkIo;
-  UINTN                                 Removable;
-  UINTN                                 Index;
-  UINTN                                 FunctionIndex;
-  CHAR16                                *Temp;
-  CHAR16                                *DescriptionPtr;
-  CHAR16                                Description[30];
-
-  ASSERT (BootOptionCount != NULL);
-
-  *BootOptionCount = 0;
-  BootOptions      = NULL;
-
-  //
-  // Parse removable block io followed by fixed block io
-  //
-  gBS->LocateHandleBuffer (
-         ByProtocol,
-         &gEfiBlockIoProtocolGuid,
-         NULL,
-         &HandleCount,
-         &Handles
-         );
-
-  for (Removable = 0; Removable < 2; Removable++) {
-    for (Index = 0; Index < HandleCount; Index++) {
-      Status = gBS->HandleProtocol (
-                      Handles[Index],
-                      &gEfiBlockIoProtocolGuid,
-                      (VOID **) &BlkIo
-                      );
-      if (EFI_ERROR (Status)) {
-        continue;
-      }
-
-      //
-      // Skip the logical partitions
-      //
-      if (BlkIo->Media->LogicalPartition) {
-        continue;
-      }
-
-      //
-      // Skip the fixed block io then the removable block io
-      //
-      if (BlkIo->Media->RemovableMedia == ((Removable == 0) ? FALSE : TRUE)) {
-        continue;
-      }
-
-      DescriptionPtr = NULL;
-      for (FunctionIndex = 0; FunctionIndex < sizeof (mBmGetBootDescription) / sizeof (mBmGetBootDescription[0]); FunctionIndex++) {
-        DescriptionPtr = mBmGetBootDescription[FunctionIndex] (Handles[Index]);
-        if (DescriptionPtr != NULL) {
-          break;
-        }
-      }
-
-      if (DescriptionPtr == NULL) {
-        continue;
-      }
-
-      //
-      // Avoid description confusion between UEFI & Legacy boot option by adding "UEFI " prefix
-      //
-      Temp = AllocatePool (StrSize (DescriptionPtr) + sizeof (mBmUefiPrefix)); 
-      ASSERT (Temp != NULL);
-      StrCpy (Temp, mBmUefiPrefix);
-      StrCat (Temp, DescriptionPtr);
-      FreePool (DescriptionPtr);
-      DescriptionPtr = Temp;
-
-      BootOptions = ReallocatePool (
-                      sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),
-                      sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),
-                      BootOptions
-                      );
-      ASSERT (BootOptions != NULL);
-
-      Status = EfiBootManagerInitializeLoadOption (
-                 &BootOptions[(*BootOptionCount)++],
-                 LoadOptionNumberUnassigned,
-                 LoadOptionTypeBoot,
-                 LOAD_OPTION_ACTIVE,
-                 DescriptionPtr,
-                 DevicePathFromHandle (Handles[Index]),
-                 NULL,
-                 0
-                 );
-      ASSERT_EFI_ERROR (Status);
-
-      FreePool (DescriptionPtr);
-    }
-  }
-
-  if (HandleCount != 0) {
-    FreePool (Handles);
-  }
-
-  //
-  // Parse simple file system not based on block io
-  //
-  NonBlockNumber = 0;
-  gBS->LocateHandleBuffer (
-         ByProtocol,
-         &gEfiSimpleFileSystemProtocolGuid,
-         NULL,
-         &HandleCount,
-         &Handles
-         );
-  for (Index = 0; Index < HandleCount; Index++) {
-    Status = gBS->HandleProtocol (
-                    Handles[Index],
-                    &gEfiBlockIoProtocolGuid,
-                    (VOID **) &BlkIo
-                    );
-     if (!EFI_ERROR (Status)) {
-      //
-      //  Skip if the file system handle supports a BlkIo protocol, which we've handled in above
-      //
-      continue;
-    }
-    UnicodeSPrint (Description, sizeof (Description), NonBlockNumber > 0 ? L"%s %d" : L"%s", L"UEFI Non-Block Boot Device", NonBlockNumber);
-    
-    BootOptions = ReallocatePool (
-                    sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),
-                    sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),
-                    BootOptions
-                    );
-    ASSERT (BootOptions != NULL);
-
-    Status = EfiBootManagerInitializeLoadOption (
-               &BootOptions[(*BootOptionCount)++],
-               LoadOptionNumberUnassigned,
-               LoadOptionTypeBoot,
-               LOAD_OPTION_ACTIVE,
-               Description,
-               DevicePathFromHandle (Handles[Index]),
-               NULL,
-               0
-               );
-    ASSERT_EFI_ERROR (Status);
-  }
-
-  if (HandleCount != 0) {
-    FreePool (Handles);
-  }
-
-  //
-  // Parse load file, assuming UEFI Network boot option
-  //
-  gBS->LocateHandleBuffer (
-         ByProtocol,
-         &gEfiLoadFileProtocolGuid,
-         NULL,
-         &HandleCount,
-         &Handles
-         );
-  for (Index = 0; Index < HandleCount; Index++) {
-
-    UnicodeSPrint (Description, sizeof (Description), Index > 0 ? L"%s %d" : L"%s", L"UEFI Network", Index);
-
-    BootOptions = ReallocatePool (
-                    sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),
-                    sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),
-                    BootOptions
-                    );
-    ASSERT (BootOptions != NULL);
-
-    Status = EfiBootManagerInitializeLoadOption (
-               &BootOptions[(*BootOptionCount)++],
-               LoadOptionNumberUnassigned,
-               LoadOptionTypeBoot,
-               LOAD_OPTION_ACTIVE,
-               Description,
-               DevicePathFromHandle (Handles[Index]),
-               NULL,
-               0
-               );
-    ASSERT_EFI_ERROR (Status);
-  }
-
-  if (HandleCount != 0) {
-    FreePool (Handles);
-  }
-
-  return BootOptions;
-}
-
-/**
-  The function enumerates all boot options, creates them and registers them in the BootOrder variable.
-**/
-VOID
-EFIAPI
-EfiBootManagerRefreshAllBootOption (
-  VOID
-  )
-{
-  EFI_STATUS                    Status;
-  EFI_BOOT_MANAGER_LOAD_OPTION  *NvBootOptions;
-  UINTN                         NvBootOptionCount;
-  EFI_BOOT_MANAGER_LOAD_OPTION  *BootOptions;
-  UINTN                         BootOptionCount;
-  UINTN                         Index;
-
-  //
-  // Optionally refresh the legacy boot option
-  //
-  if (mBmRefreshLegacyBootOption != NULL) {
-    mBmRefreshLegacyBootOption ();
-  }
-
-  BootOptions   = BmEnumerateBootOptions (&BootOptionCount);
-  NvBootOptions = EfiBootManagerGetLoadOptions (&NvBootOptionCount, LoadOptionTypeBoot);
-
-  //
-  // Mark the boot option as added by BDS by setting OptionalData to a special GUID
-  //
-  for (Index = 0; Index < BootOptionCount; Index++) {
-    BootOptions[Index].OptionalData     = AllocateCopyPool (sizeof (EFI_GUID), &mBmAutoCreateBootOptionGuid);
-    BootOptions[Index].OptionalDataSize = sizeof (EFI_GUID);
-  }
-
-  //
-  // Remove invalid EFI boot options from NV
-  //
-  for (Index = 0; Index < NvBootOptionCount; Index++) {
-    if (((DevicePathType (NvBootOptions[Index].FilePath) != BBS_DEVICE_PATH) || 
-         (DevicePathSubType (NvBootOptions[Index].FilePath) != BBS_BBS_DP)
-        ) &&
-        (NvBootOptions[Index].OptionalDataSize == sizeof (EFI_GUID)) &&
-        CompareGuid ((EFI_GUID *) NvBootOptions[Index].OptionalData, &mBmAutoCreateBootOptionGuid)
-       ) {
-      //
-      // Only check those added by BDS
-      // so that the boot options added by end-user or OS installer won't be deleted
-      //
-      if (BmFindLoadOption (&NvBootOptions[Index], BootOptions, BootOptionCount) == (UINTN) -1) {
-        Status = EfiBootManagerDeleteLoadOptionVariable (NvBootOptions[Index].OptionNumber, LoadOptionTypeBoot);
-        //
-        // Deleting variable with current variable implementation shouldn't fail.
-        //
-        ASSERT_EFI_ERROR (Status);
-      }
-    }
-  }
-
-  //
-  // Add new EFI boot options to NV
-  //
-  for (Index = 0; Index < BootOptionCount; Index++) {
-    if (BmFindLoadOption (&BootOptions[Index], NvBootOptions, NvBootOptionCount) == (UINTN) -1) {
-      EfiBootManagerAddLoadOptionVariable (&BootOptions[Index], (UINTN) -1);
-      //
-      // Try best to add the boot options so continue upon failure.
-      //
-    }
-  }
-
-  EfiBootManagerFreeLoadOptions (BootOptions,   BootOptionCount);
-  EfiBootManagerFreeLoadOptions (NvBootOptions, NvBootOptionCount);
-}
-
-/**
-  This function is called to create the boot option for the Boot Manager Menu.
-
-  The Boot Manager Menu is shown after successfully booting a boot option.
-  Assume the BootManagerMenuFile is in the same FV as the module links to this library.
-
-  @param  BootOption    Return the boot option of the Boot Manager Menu
-
-  @retval EFI_SUCCESS   Successfully register the Boot Manager Menu.
-  @retval Status        Return status of gRT->SetVariable (). BootOption still points
-                        to the Boot Manager Menu even the Status is not EFI_SUCCESS.
-**/
-EFI_STATUS
-BmRegisterBootManagerMenu (
-  OUT EFI_BOOT_MANAGER_LOAD_OPTION   *BootOption
-  )
-{
-  EFI_STATUS                         Status;
-  CHAR16                             *Description;
-  UINTN                              DescriptionLength;
-  EFI_DEVICE_PATH_PROTOCOL           *DevicePath;
-  EFI_LOADED_IMAGE_PROTOCOL          *LoadedImage;
-  MEDIA_FW_VOL_FILEPATH_DEVICE_PATH  FileNode;
-
-  Status = GetSectionFromFv (
-             PcdGetPtr (PcdBootManagerMenuFile),
-             EFI_SECTION_USER_INTERFACE,
-             0,
-             (VOID **) &Description,
-             &DescriptionLength
-             );
-  if (EFI_ERROR (Status)) {
-    Description = NULL;
-  }
-
-  EfiInitializeFwVolDevicepathNode (&FileNode, PcdGetPtr (PcdBootManagerMenuFile));
-  Status = gBS->HandleProtocol (
-                  gImageHandle,
-                  &gEfiLoadedImageProtocolGuid,
-                  (VOID **) &LoadedImage
-                  );
-  ASSERT_EFI_ERROR (Status);
-  DevicePath = AppendDevicePathNode (
-                 DevicePathFromHandle (LoadedImage->DeviceHandle),
-                 (EFI_DEVICE_PATH_PROTOCOL *) &FileNode
-                 );
-  ASSERT (DevicePath != NULL);
-
-  Status = EfiBootManagerInitializeLoadOption (
-             BootOption,
-             LoadOptionNumberUnassigned,
-             LoadOptionTypeBoot,
-             LOAD_OPTION_CATEGORY_APP | LOAD_OPTION_ACTIVE | LOAD_OPTION_HIDDEN,
-             (Description != NULL) ? Description : L"Boot Manager Menu",
-             DevicePath,
-             NULL,
-             0
-             );
-  ASSERT_EFI_ERROR (Status);
-  FreePool (DevicePath);
-  if (Description != NULL) {
-    FreePool (Description);
-  }
-
-  DEBUG_CODE (
-    EFI_BOOT_MANAGER_LOAD_OPTION    *BootOptions;
-    UINTN                           BootOptionCount;
-
-    BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
-    ASSERT (BmFindLoadOption (BootOption, BootOptions, BootOptionCount) == -1);
-    EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
-    );
-
-  return EfiBootManagerAddLoadOptionVariable (BootOption, 0);
-}
-
-/**
-  Return the boot option corresponding to the Boot Manager Menu.
-  It may automatically create one if the boot option hasn't been created yet.
-  
-  @param BootOption    Return the Boot Manager Menu.
-
-  @retval EFI_SUCCESS   The Boot Manager Menu is successfully returned.
-  @retval Status        Return status of gRT->SetVariable (). BootOption still points
-                        to the Boot Manager Menu even the Status is not EFI_SUCCESS.
-**/
-EFI_STATUS
-EFIAPI
-EfiBootManagerGetBootManagerMenu (
-  EFI_BOOT_MANAGER_LOAD_OPTION *BootOption
-  )
-{
-  EFI_STATUS                   Status;
-  UINTN                        BootOptionCount;
-  EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
-  UINTN                        Index;
-  EFI_DEVICE_PATH_PROTOCOL     *Node;
-  EFI_HANDLE                   FvHandle;
-  
-  BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
-
-  for (Index = 0; Index < BootOptionCount; Index++) {
-    Node   = BootOptions[Index].FilePath;
-    Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &Node, &FvHandle);
-    if (!EFI_ERROR (Status)) {
-      if (CompareGuid (
-            EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) Node),
-            PcdGetPtr (PcdBootManagerMenuFile)
-            )
-          ) {        
-        Status = EfiBootManagerInitializeLoadOption (
-                   BootOption,
-                   BootOptions[Index].OptionNumber,
-                   BootOptions[Index].OptionType,
-                   BootOptions[Index].Attributes,
-                   BootOptions[Index].Description,
-                   BootOptions[Index].FilePath,
-                   BootOptions[Index].OptionalData,
-                   BootOptions[Index].OptionalDataSize
-                   );
-        ASSERT_EFI_ERROR (Status);
-        break;
-      }
-    }
-  }
-
-  EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
-
-  //
-  // Automatically create the Boot#### for Boot Manager Menu when not found.
-  //
-  if (Index == BootOptionCount) {
-    return BmRegisterBootManagerMenu (BootOption);
-  } else {
-    return EFI_SUCCESS;
-  }
-}
-
+/** @file\r
+  Library functions which relates with booting.\r
+\r
+Copyright (c) 2011 - 2017, 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
+EFI_RAM_DISK_PROTOCOL                        *mRamDisk                  = NULL;\r
+\r
+EFI_BOOT_MANAGER_REFRESH_LEGACY_BOOT_OPTION  mBmRefreshLegacyBootOption = NULL;\r
+EFI_BOOT_MANAGER_LEGACY_BOOT                 mBmLegacyBoot              = NULL;\r
+\r
+///\r
+/// This GUID is used for an EFI Variable that stores the front device pathes\r
+/// for a partial device path that starts with the HD node.\r
+///\r
+EFI_GUID mBmHardDriveBootVariableGuid = { 0xfab7e9e1, 0x39dd, 0x4f2b, { 0x84, 0x08, 0xe2, 0x0e, 0x90, 0x6c, 0xb6, 0xde } };\r
+EFI_GUID mBmAutoCreateBootOptionGuid  = { 0x8108ac4e, 0x9f11, 0x4d59, { 0x85, 0x0e, 0xe2, 0x1a, 0x52, 0x2c, 0x59, 0xb2 } };\r
+\r
+/**\r
+  The function registers the legacy boot support capabilities.\r
+\r
+  @param RefreshLegacyBootOption The function pointer to create all the legacy boot options.\r
+  @param LegacyBoot              The function pointer to boot the legacy boot option.\r
+**/\r
+VOID\r
+EFIAPI\r
+EfiBootManagerRegisterLegacyBootSupport (\r
+  EFI_BOOT_MANAGER_REFRESH_LEGACY_BOOT_OPTION   RefreshLegacyBootOption,\r
+  EFI_BOOT_MANAGER_LEGACY_BOOT                  LegacyBoot\r
+  )\r
+{\r
+  mBmRefreshLegacyBootOption = RefreshLegacyBootOption;\r
+  mBmLegacyBoot              = LegacyBoot;\r
+}\r
+\r
+/**\r
+  Return TRUE when the boot option is auto-created instead of manually added.\r
+\r
+  @param BootOption Pointer to the boot option to check.\r
+\r
+  @retval TRUE  The boot option is auto-created.\r
+  @retval FALSE The boot option is manually added.\r
+**/\r
+BOOLEAN\r
+BmIsAutoCreateBootOption (\r
+  EFI_BOOT_MANAGER_LOAD_OPTION    *BootOption\r
+  )\r
+{\r
+  if ((BootOption->OptionalDataSize == sizeof (EFI_GUID)) &&\r
+      CompareGuid ((EFI_GUID *) BootOption->OptionalData, &mBmAutoCreateBootOptionGuid)\r
+      ) {\r
+    return TRUE;\r
+  } else {\r
+    return FALSE;\r
+  }\r
+}\r
+\r
+/**\r
+  Find the boot option in the NV storage and return the option number.\r
+\r
+  @param OptionToFind  Boot option to be checked.\r
+\r
+  @return   The option number of the found boot option.\r
+\r
+**/\r
+UINTN\r
+BmFindBootOptionInVariable (\r
+  IN  EFI_BOOT_MANAGER_LOAD_OPTION             *OptionToFind\r
+  )\r
+{\r
+  EFI_STATUS                   Status;\r
+  EFI_BOOT_MANAGER_LOAD_OPTION BootOption;\r
+  UINTN                        OptionNumber;\r
+  CHAR16                       OptionName[BM_OPTION_NAME_LEN];\r
+  EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;\r
+  UINTN                        BootOptionCount;\r
+  UINTN                        Index;\r
+  \r
+  OptionNumber = LoadOptionNumberUnassigned;\r
+\r
+  //\r
+  // Try to match the variable exactly if the option number is assigned\r
+  //\r
+  if (OptionToFind->OptionNumber != LoadOptionNumberUnassigned) {\r
+    UnicodeSPrint (\r
+      OptionName, sizeof (OptionName), L"%s%04x",\r
+      mBmLoadOptionName[OptionToFind->OptionType], OptionToFind->OptionNumber\r
+      );\r
+    Status = EfiBootManagerVariableToLoadOption (OptionName, &BootOption);\r
+\r
+    if (!EFI_ERROR (Status)) {\r
+      ASSERT (OptionToFind->OptionNumber == BootOption.OptionNumber);\r
+      if ((OptionToFind->Attributes == BootOption.Attributes) &&\r
+          (StrCmp (OptionToFind->Description, BootOption.Description) == 0) &&\r
+          (CompareMem (OptionToFind->FilePath, BootOption.FilePath, GetDevicePathSize (OptionToFind->FilePath)) == 0) &&\r
+          (OptionToFind->OptionalDataSize == BootOption.OptionalDataSize) &&\r
+          (CompareMem (OptionToFind->OptionalData, BootOption.OptionalData, OptionToFind->OptionalDataSize) == 0)\r
+         ) {\r
+        OptionNumber = OptionToFind->OptionNumber;\r
+      }\r
+      EfiBootManagerFreeLoadOption (&BootOption);\r
+    }\r
+  }\r
+\r
+  //\r
+  // The option number assigned is either incorrect or unassigned.\r
+  //\r
+  if (OptionNumber == LoadOptionNumberUnassigned) {\r
+    BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);\r
+\r
+    Index = EfiBootManagerFindLoadOption (OptionToFind, BootOptions, BootOptionCount);\r
+    if (Index != -1) {\r
+      OptionNumber = BootOptions[Index].OptionNumber;\r
+    }\r
+\r
+    EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);\r
+  }\r
+\r
+  return OptionNumber;\r
+}\r
+\r
+/**\r
+  Get the file buffer using a Memory Mapped Device Path.\r
+\r
+  FV address may change across reboot. This routine promises the FV file device path is right.\r
+\r
+  @param  FilePath     The Memory Mapped Device Path to get the file buffer.\r
+  @param  FullPath     Receive the updated FV Device Path pointint to the file.\r
+  @param  FileSize     Receive the file buffer size.\r
+\r
+  @return  The file buffer.\r
+**/\r
+VOID *\r
+BmGetFileBufferByFvFilePath (\r
+  IN EFI_DEVICE_PATH_PROTOCOL      *FilePath,\r
+  OUT EFI_DEVICE_PATH_PROTOCOL     **FullPath,\r
+  OUT UINTN                        *FileSize\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  UINTN                         Index;\r
+  EFI_DEVICE_PATH_PROTOCOL      *FvFileNode;\r
+  EFI_HANDLE                    FvHandle;\r
+  EFI_LOADED_IMAGE_PROTOCOL     *LoadedImage;\r
+  UINT32                        AuthenticationStatus;\r
+  UINTN                         FvHandleCount;\r
+  EFI_HANDLE                    *FvHandles;\r
+  EFI_DEVICE_PATH_PROTOCOL      *NewDevicePath;\r
+  VOID                          *FileBuffer;\r
+\r
+  //\r
+  // Get the file buffer by using the exactly FilePath.\r
+  //\r
+  FvFileNode = FilePath;\r
+  Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &FvFileNode, &FvHandle);\r
+  if (!EFI_ERROR (Status)) {\r
+    FileBuffer = GetFileBufferByFilePath (TRUE, FilePath, FileSize, &AuthenticationStatus);\r
+    if (FileBuffer != NULL) {\r
+      *FullPath = DuplicateDevicePath (FilePath);\r
+    }\r
+    return FileBuffer;\r
+  }\r
+\r
+  //\r
+  // Only wide match other FVs if it's a memory mapped FV file path.\r
+  //\r
+  if ((DevicePathType (FilePath) != HARDWARE_DEVICE_PATH) || (DevicePathSubType (FilePath) != HW_MEMMAP_DP)) {\r
+    return NULL;\r
+  }\r
+\r
+  FvFileNode = NextDevicePathNode (FilePath);\r
+\r
+  //\r
+  // Firstly find the FV file in current FV\r
+  //\r
+  gBS->HandleProtocol (\r
+         gImageHandle,\r
+         &gEfiLoadedImageProtocolGuid,\r
+         (VOID **) &LoadedImage\r
+         );\r
+  NewDevicePath = AppendDevicePathNode (DevicePathFromHandle (LoadedImage->DeviceHandle), FvFileNode);\r
+  FileBuffer = BmGetFileBufferByFvFilePath (NewDevicePath, FullPath, FileSize);\r
+  FreePool (NewDevicePath);\r
+\r
+  if (FileBuffer != NULL) {\r
+    return FileBuffer;\r
+  }\r
+\r
+  //\r
+  // Secondly find the FV file in all other FVs\r
+  //\r
+  gBS->LocateHandleBuffer (\r
+         ByProtocol,\r
+         &gEfiFirmwareVolume2ProtocolGuid,\r
+         NULL,\r
+         &FvHandleCount,\r
+         &FvHandles\r
+         );\r
+  for (Index = 0; (Index < FvHandleCount) && (FileBuffer == NULL); Index++) {\r
+    if (FvHandles[Index] == LoadedImage->DeviceHandle) {\r
+      //\r
+      // Skip current FV\r
+      //\r
+      continue;\r
+    }\r
+    NewDevicePath = AppendDevicePathNode (DevicePathFromHandle (FvHandles[Index]), FvFileNode);\r
+    FileBuffer = BmGetFileBufferByFvFilePath (NewDevicePath, FullPath, FileSize);\r
+    FreePool (NewDevicePath);\r
+  }\r
+  \r
+  if (FvHandles != NULL) {\r
+    FreePool (FvHandles);\r
+  }\r
+  return FileBuffer;\r
+}\r
+\r
+/**\r
+  Check if it's a Device Path pointing to FV file.\r
+  \r
+  The function doesn't garentee the device path points to existing FV file.\r
+\r
+  @param  DevicePath     Input device path.\r
+\r
+  @retval TRUE   The device path is a FV File Device Path.\r
+  @retval FALSE  The device path is NOT a FV File Device Path.\r
+**/\r
+BOOLEAN\r
+BmIsFvFilePath (\r
+  IN EFI_DEVICE_PATH_PROTOCOL    *DevicePath\r
+  )\r
+{\r
+  EFI_STATUS                     Status;\r
+  EFI_HANDLE                     Handle;\r
+  EFI_DEVICE_PATH_PROTOCOL       *Node;\r
+\r
+  Node = DevicePath;\r
+  Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &Node, &Handle);\r
+  if (!EFI_ERROR (Status)) {\r
+    return TRUE;\r
+  }\r
+\r
+  if ((DevicePathType (DevicePath) == HARDWARE_DEVICE_PATH) && (DevicePathSubType (DevicePath) == HW_MEMMAP_DP)) {\r
+    DevicePath = NextDevicePathNode (DevicePath);\r
+    if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) && (DevicePathSubType (DevicePath) == MEDIA_PIWG_FW_FILE_DP)) {\r
+      return IsDevicePathEnd (NextDevicePathNode (DevicePath));\r
+    }\r
+  }\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  Check whether a USB device match the specified USB Class device path. This\r
+  function follows "Load Option Processing" behavior in UEFI specification.\r
+\r
+  @param UsbIo       USB I/O protocol associated with the USB device.\r
+  @param UsbClass    The USB Class device path to match.\r
+\r
+  @retval TRUE       The USB device match the USB Class device path.\r
+  @retval FALSE      The USB device does not match the USB Class device path.\r
+\r
+**/\r
+BOOLEAN\r
+BmMatchUsbClass (\r
+  IN EFI_USB_IO_PROTOCOL        *UsbIo,\r
+  IN USB_CLASS_DEVICE_PATH      *UsbClass\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  EFI_USB_DEVICE_DESCRIPTOR     DevDesc;\r
+  EFI_USB_INTERFACE_DESCRIPTOR  IfDesc;\r
+  UINT8                         DeviceClass;\r
+  UINT8                         DeviceSubClass;\r
+  UINT8                         DeviceProtocol;\r
+\r
+  if ((DevicePathType (UsbClass) != MESSAGING_DEVICE_PATH) ||\r
+      (DevicePathSubType (UsbClass) != MSG_USB_CLASS_DP)){\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // Check Vendor Id and Product Id.\r
+  //\r
+  Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);\r
+  if (EFI_ERROR (Status)) {\r
+    return FALSE;\r
+  }\r
+\r
+  if ((UsbClass->VendorId != 0xffff) &&\r
+      (UsbClass->VendorId != DevDesc.IdVendor)) {\r
+    return FALSE;\r
+  }\r
+\r
+  if ((UsbClass->ProductId != 0xffff) &&\r
+      (UsbClass->ProductId != DevDesc.IdProduct)) {\r
+    return FALSE;\r
+  }\r
+\r
+  DeviceClass    = DevDesc.DeviceClass;\r
+  DeviceSubClass = DevDesc.DeviceSubClass;\r
+  DeviceProtocol = DevDesc.DeviceProtocol;\r
+  if (DeviceClass == 0) {\r
+    //\r
+    // If Class in Device Descriptor is set to 0, use the Class, SubClass and\r
+    // Protocol in Interface Descriptor instead.\r
+    //\r
+    Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &IfDesc);\r
+    if (EFI_ERROR (Status)) {\r
+      return FALSE;\r
+    }\r
+\r
+    DeviceClass    = IfDesc.InterfaceClass;\r
+    DeviceSubClass = IfDesc.InterfaceSubClass;\r
+    DeviceProtocol = IfDesc.InterfaceProtocol;\r
+  }\r
+\r
+  //\r
+  // Check Class, SubClass and Protocol.\r
+  //\r
+  if ((UsbClass->DeviceClass != 0xff) &&\r
+      (UsbClass->DeviceClass != DeviceClass)) {\r
+    return FALSE;\r
+  }\r
+\r
+  if ((UsbClass->DeviceSubClass != 0xff) &&\r
+      (UsbClass->DeviceSubClass != DeviceSubClass)) {\r
+    return FALSE;\r
+  }\r
+\r
+  if ((UsbClass->DeviceProtocol != 0xff) &&\r
+      (UsbClass->DeviceProtocol != DeviceProtocol)) {\r
+    return FALSE;\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+/**\r
+  Check whether a USB device match the specified USB WWID device path. This\r
+  function follows "Load Option Processing" behavior in UEFI specification.\r
+\r
+  @param UsbIo       USB I/O protocol associated with the USB device.\r
+  @param UsbWwid     The USB WWID device path to match.\r
+\r
+  @retval TRUE       The USB device match the USB WWID device path.\r
+  @retval FALSE      The USB device does not match the USB WWID device path.\r
+\r
+**/\r
+BOOLEAN\r
+BmMatchUsbWwid (\r
+  IN EFI_USB_IO_PROTOCOL        *UsbIo,\r
+  IN USB_WWID_DEVICE_PATH       *UsbWwid\r
+  )\r
+{\r
+  EFI_STATUS                   Status;\r
+  EFI_USB_DEVICE_DESCRIPTOR    DevDesc;\r
+  EFI_USB_INTERFACE_DESCRIPTOR IfDesc;\r
+  UINT16                       *LangIdTable;\r
+  UINT16                       TableSize;\r
+  UINT16                       Index;\r
+  CHAR16                       *CompareStr;\r
+  UINTN                        CompareLen;\r
+  CHAR16                       *SerialNumberStr;\r
+  UINTN                        Length;\r
+\r
+  if ((DevicePathType (UsbWwid) != MESSAGING_DEVICE_PATH) ||\r
+      (DevicePathSubType (UsbWwid) != MSG_USB_WWID_DP)) {\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // Check Vendor Id and Product Id.\r
+  //\r
+  Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);\r
+  if (EFI_ERROR (Status)) {\r
+    return FALSE;\r
+  }\r
+  if ((DevDesc.IdVendor != UsbWwid->VendorId) ||\r
+      (DevDesc.IdProduct != UsbWwid->ProductId)) {\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // Check Interface Number.\r
+  //\r
+  Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &IfDesc);\r
+  if (EFI_ERROR (Status)) {\r
+    return FALSE;\r
+  }\r
+  if (IfDesc.InterfaceNumber != UsbWwid->InterfaceNumber) {\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // Check Serial Number.\r
+  //\r
+  if (DevDesc.StrSerialNumber == 0) {\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // Get all supported languages.\r
+  //\r
+  TableSize = 0;\r
+  LangIdTable = NULL;\r
+  Status = UsbIo->UsbGetSupportedLanguages (UsbIo, &LangIdTable, &TableSize);\r
+  if (EFI_ERROR (Status) || (TableSize == 0) || (LangIdTable == NULL)) {\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // Serial number in USB WWID device path is the last 64-or-less UTF-16 characters.\r
+  //\r
+  CompareStr = (CHAR16 *) (UINTN) (UsbWwid + 1);\r
+  CompareLen = (DevicePathNodeLength (UsbWwid) - sizeof (USB_WWID_DEVICE_PATH)) / sizeof (CHAR16);\r
+  if (CompareStr[CompareLen - 1] == L'\0') {\r
+    CompareLen--;\r
+  }\r
+\r
+  //\r
+  // Compare serial number in each supported language.\r
+  //\r
+  for (Index = 0; Index < TableSize / sizeof (UINT16); Index++) {\r
+    SerialNumberStr = NULL;\r
+    Status = UsbIo->UsbGetStringDescriptor (\r
+                      UsbIo,\r
+                      LangIdTable[Index],\r
+                      DevDesc.StrSerialNumber,\r
+                      &SerialNumberStr\r
+                      );\r
+    if (EFI_ERROR (Status) || (SerialNumberStr == NULL)) {\r
+      continue;\r
+    }\r
+\r
+    Length = StrLen (SerialNumberStr);\r
+    if ((Length >= CompareLen) &&\r
+        (CompareMem (SerialNumberStr + Length - CompareLen, CompareStr, CompareLen * sizeof (CHAR16)) == 0)) {\r
+      FreePool (SerialNumberStr);\r
+      return TRUE;\r
+    }\r
+\r
+    FreePool (SerialNumberStr);\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  Find a USB device which match the specified short-form device path start with \r
+  USB Class or USB WWID device path. If ParentDevicePath is NULL, this function\r
+  will search in all USB devices of the platform. If ParentDevicePath is not NULL,\r
+  this function will only search in its child devices.\r
+\r
+  @param DevicePath           The device path that contains USB Class or USB WWID device path.\r
+  @param ParentDevicePathSize The length of the device path before the USB Class or \r
+                              USB WWID device path.\r
+  @param UsbIoHandleCount     A pointer to the count of the returned USB IO handles.\r
+\r
+  @retval NULL       The matched USB IO handles cannot be found.\r
+  @retval other      The matched USB IO handles.\r
+\r
+**/\r
+EFI_HANDLE *\r
+BmFindUsbDevice (\r
+  IN  EFI_DEVICE_PATH_PROTOCOL  *DevicePath,\r
+  IN  UINTN                     ParentDevicePathSize,\r
+  OUT UINTN                     *UsbIoHandleCount\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  EFI_HANDLE                *UsbIoHandles;\r
+  EFI_DEVICE_PATH_PROTOCOL  *UsbIoDevicePath;\r
+  EFI_USB_IO_PROTOCOL       *UsbIo;\r
+  UINTN                     Index;\r
+  BOOLEAN                   Matched;\r
+\r
+  ASSERT (UsbIoHandleCount != NULL);  \r
+\r
+  //\r
+  // Get all UsbIo Handles.\r
+  //\r
+  Status = gBS->LocateHandleBuffer (\r
+                  ByProtocol,\r
+                  &gEfiUsbIoProtocolGuid,\r
+                  NULL,\r
+                  UsbIoHandleCount,\r
+                  &UsbIoHandles\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    *UsbIoHandleCount = 0;\r
+    UsbIoHandles      = NULL;\r
+  }\r
+\r
+  for (Index = 0; Index < *UsbIoHandleCount; ) {\r
+    //\r
+    // Get the Usb IO interface.\r
+    //\r
+    Status = gBS->HandleProtocol(\r
+                    UsbIoHandles[Index],\r
+                    &gEfiUsbIoProtocolGuid,\r
+                    (VOID **) &UsbIo\r
+                    );\r
+    UsbIoDevicePath = DevicePathFromHandle (UsbIoHandles[Index]);\r
+    Matched         = FALSE;\r
+    if (!EFI_ERROR (Status) && (UsbIoDevicePath != NULL)) {\r
+\r
+      //\r
+      // Compare starting part of UsbIoHandle's device path with ParentDevicePath.\r
+      //\r
+      if (CompareMem (UsbIoDevicePath, DevicePath, ParentDevicePathSize) == 0) {\r
+        if (BmMatchUsbClass (UsbIo, (USB_CLASS_DEVICE_PATH *) ((UINTN) DevicePath + ParentDevicePathSize)) ||\r
+            BmMatchUsbWwid (UsbIo, (USB_WWID_DEVICE_PATH *) ((UINTN) DevicePath + ParentDevicePathSize))) {\r
+          Matched = TRUE;\r
+        }\r
+      }\r
+    }\r
+\r
+    if (!Matched) {\r
+      (*UsbIoHandleCount) --;\r
+      CopyMem (&UsbIoHandles[Index], &UsbIoHandles[Index + 1], (*UsbIoHandleCount - Index) * sizeof (EFI_HANDLE));\r
+    } else {\r
+      Index++;\r
+    }\r
+  }\r
+\r
+  return UsbIoHandles;\r
+}\r
+\r
+/**\r
+  Expand USB Class or USB WWID device path node to be full device path of a USB\r
+  device in platform.\r
+\r
+  This function support following 4 cases:\r
+  1) Boot Option device path starts with a USB Class or USB WWID device path,\r
+     and there is no Media FilePath device path in the end.\r
+     In this case, it will follow Removable Media Boot Behavior.\r
+  2) Boot Option device path starts with a USB Class or USB WWID device path,\r
+     and ended with Media FilePath device path.\r
+  3) Boot Option device path starts with a full device path to a USB Host Controller,\r
+     contains a USB Class or USB WWID device path node, while not ended with Media\r
+     FilePath device path. In this case, it will follow Removable Media Boot Behavior.\r
+  4) Boot Option device path starts with a full device path to a USB Host Controller,\r
+     contains a USB Class or USB WWID device path node, and ended with Media\r
+     FilePath device path.\r
+\r
+  @param FilePath      The device path pointing to a load option.\r
+                       It could be a short-form device path.\r
+  @param FullPath      Return the full device path of the load option after\r
+                       short-form device path expanding.\r
+                       Caller is responsible to free it.\r
+  @param FileSize      Return the load option size.\r
+  @param ShortformNode Pointer to the USB short-form device path node in the FilePath buffer.\r
+\r
+  @return The load option buffer. Caller is responsible to free the memory.\r
+**/\r
+VOID *\r
+BmExpandUsbDevicePath (\r
+  IN  EFI_DEVICE_PATH_PROTOCOL  *FilePath,\r
+  OUT EFI_DEVICE_PATH_PROTOCOL  **FullPath,\r
+  OUT UINTN                     *FileSize,\r
+  IN EFI_DEVICE_PATH_PROTOCOL   *ShortformNode\r
+  )\r
+{\r
+  UINTN                             ParentDevicePathSize;\r
+  EFI_DEVICE_PATH_PROTOCOL          *RemainingDevicePath;\r
+  EFI_DEVICE_PATH_PROTOCOL          *FullDevicePath;\r
+  EFI_HANDLE                        *Handles;\r
+  UINTN                             HandleCount;\r
+  UINTN                             Index;\r
+  VOID                              *FileBuffer;\r
+\r
+  ParentDevicePathSize = (UINTN) ShortformNode - (UINTN) FilePath;\r
+  RemainingDevicePath = NextDevicePathNode (ShortformNode);\r
+  FileBuffer = NULL;\r
+  Handles = BmFindUsbDevice (FilePath, ParentDevicePathSize, &HandleCount);\r
+\r
+  for (Index = 0; (Index < HandleCount) && (FileBuffer == NULL); Index++) {\r
+    FullDevicePath = AppendDevicePath (DevicePathFromHandle (Handles[Index]), RemainingDevicePath);\r
+    FileBuffer = EfiBootManagerGetLoadOptionBuffer (FullDevicePath, FullPath, FileSize);\r
+    FreePool (FullDevicePath);\r
+  }\r
+\r
+  if (Handles != NULL) {\r
+    FreePool (Handles);\r
+  }\r
+\r
+  return FileBuffer;\r
+}\r
+\r
+/**\r
+  Expand File-path device path node to be full device path in platform.\r
+\r
+  @param FilePath      The device path pointing to a load option.\r
+                       It could be a short-form device path.\r
+  @param FullPath      Return the full device path of the load option after\r
+                       short-form device path expanding.\r
+                       Caller is responsible to free it.\r
+  @param FileSize      Return the load option size.\r
+\r
+  @return The load option buffer. Caller is responsible to free the memory.\r
+**/\r
+VOID *\r
+BmExpandFileDevicePath (\r
+  IN  EFI_DEVICE_PATH_PROTOCOL    *FilePath,\r
+  OUT EFI_DEVICE_PATH_PROTOCOL    **FullPath,\r
+  OUT UINTN                       *FileSize\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  UINTN                           Index;\r
+  UINTN                           HandleCount;\r
+  EFI_HANDLE                      *Handles;\r
+  EFI_BLOCK_IO_PROTOCOL           *BlockIo;\r
+  UINTN                           MediaType;\r
+  EFI_DEVICE_PATH_PROTOCOL        *FullDevicePath;\r
+  VOID                            *FileBuffer;\r
+  UINT32                          AuthenticationStatus;\r
+  \r
+  EfiBootManagerConnectAll ();\r
+  Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiSimpleFileSystemProtocolGuid, NULL, &HandleCount, &Handles);\r
+  if (EFI_ERROR (Status)) {\r
+    HandleCount = 0;\r
+    Handles = NULL;\r
+  }\r
+\r
+  //\r
+  // Enumerate all removable media devices followed by all fixed media devices,\r
+  //   followed by media devices which don't layer on block io.\r
+  //\r
+  for (MediaType = 0; MediaType < 3; MediaType++) {\r
+    for (Index = 0; Index < HandleCount; Index++) {\r
+      Status = gBS->HandleProtocol (Handles[Index], &gEfiBlockIoProtocolGuid, (VOID *) &BlockIo);\r
+      if (EFI_ERROR (Status)) {\r
+        BlockIo = NULL;\r
+      }\r
+      if ((MediaType == 0 && BlockIo != NULL && BlockIo->Media->RemovableMedia) ||\r
+          (MediaType == 1 && BlockIo != NULL && !BlockIo->Media->RemovableMedia) ||\r
+          (MediaType == 2 && BlockIo == NULL)\r
+          ) {\r
+        FullDevicePath = AppendDevicePath (DevicePathFromHandle (Handles[Index]), FilePath);\r
+        FileBuffer = GetFileBufferByFilePath (TRUE, FullDevicePath, FileSize, &AuthenticationStatus);\r
+        if (FileBuffer != NULL) {\r
+          *FullPath = FullDevicePath;\r
+          FreePool (Handles);\r
+          return FileBuffer;\r
+        }\r
+        FreePool (FullDevicePath);\r
+      }\r
+    }\r
+  }\r
+\r
+  if (Handles != NULL) {\r
+    FreePool (Handles);\r
+  }\r
+\r
+  *FullPath = NULL;\r
+  return NULL;\r
+}\r
+\r
+/**\r
+  Expand URI device path node to be full device path in platform.\r
+\r
+  @param FilePath      The device path pointing to a load option.\r
+                       It could be a short-form device path.\r
+  @param FullPath      Return the full device path of the load option after\r
+                       short-form device path expanding.\r
+                       Caller is responsible to free it.\r
+  @param FileSize      Return the load option size.\r
+\r
+  @return The load option buffer. Caller is responsible to free the memory.\r
+**/\r
+VOID *\r
+BmExpandUriDevicePath (\r
+  IN  EFI_DEVICE_PATH_PROTOCOL    *FilePath,\r
+  OUT EFI_DEVICE_PATH_PROTOCOL    **FullPath,\r
+  OUT UINTN                       *FileSize\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  UINTN                           Index;\r
+  UINTN                           HandleCount;\r
+  EFI_HANDLE                      *Handles;\r
+  VOID                            *FileBuffer;\r
+\r
+  EfiBootManagerConnectAll ();\r
+  Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiLoadFileProtocolGuid, NULL, &HandleCount, &Handles);\r
+  if (EFI_ERROR (Status)) {\r
+    HandleCount = 0;\r
+    Handles = NULL;\r
+  }\r
+\r
+  FileBuffer = NULL;\r
+  for (Index = 0; Index < HandleCount; Index++) {\r
+    FileBuffer = BmGetFileBufferFromLoadFile (Handles[Index], FilePath, FullPath, FileSize);\r
+    if (FileBuffer != NULL) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (Handles != NULL) {\r
+    FreePool (Handles);\r
+  }\r
+\r
+  return FileBuffer;\r
+}\r
+\r
+/**\r
+  Save the partition DevicePath to the CachedDevicePath as the first instance.\r
+\r
+  @param CachedDevicePath  The device path cache.\r
+  @param DevicePath        The partition device path to be cached.\r
+**/\r
+VOID\r
+BmCachePartitionDevicePath (\r
+  IN OUT EFI_DEVICE_PATH_PROTOCOL **CachedDevicePath,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *DevicePath\r
+  )\r
+{\r
+  EFI_DEVICE_PATH_PROTOCOL        *TempDevicePath;\r
+  UINTN                           Count;\r
+  \r
+  if (BmMatchDevicePaths (*CachedDevicePath, DevicePath)) {\r
+    TempDevicePath = *CachedDevicePath;\r
+    *CachedDevicePath = BmDelPartMatchInstance (*CachedDevicePath, DevicePath);\r
+    FreePool (TempDevicePath);\r
+  }\r
+\r
+  if (*CachedDevicePath == NULL) {\r
+    *CachedDevicePath = DuplicateDevicePath (DevicePath);\r
+    return;\r
+  }\r
+\r
+  TempDevicePath = *CachedDevicePath;\r
+  *CachedDevicePath = AppendDevicePathInstance (DevicePath, *CachedDevicePath);\r
+  if (TempDevicePath != NULL) {\r
+    FreePool (TempDevicePath);\r
+  }\r
+\r
+  //\r
+  // Here limit the device path instance number to 12, which is max number for a system support 3 IDE controller\r
+  // If the user try to boot many OS in different HDs or partitions, in theory, the 'HDDP' variable maybe become larger and larger.\r
+  //\r
+  Count = 0;\r
+  TempDevicePath = *CachedDevicePath;\r
+  while (!IsDevicePathEnd (TempDevicePath)) {\r
+    TempDevicePath = NextDevicePathNode (TempDevicePath);\r
+    //\r
+    // Parse one instance\r
+    //\r
+    while (!IsDevicePathEndType (TempDevicePath)) {\r
+      TempDevicePath = NextDevicePathNode (TempDevicePath);\r
+    }\r
+    Count++;\r
+    //\r
+    // If the CachedDevicePath variable contain too much instance, only remain 12 instances.\r
+    //\r
+    if (Count == 12) {\r
+      SetDevicePathEndNode (TempDevicePath);\r
+      break;\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  Expand a device path that starts with a hard drive media device path node to be a\r
+  full device path that includes the full hardware path to the device. We need\r
+  to do this so it can be booted. As an optimization the front match (the part point\r
+  to the partition node. E.g. ACPI() /PCI()/ATA()/Partition() ) is saved in a variable\r
+  so a connect all is not required on every boot. All successful history device path\r
+  which point to partition node (the front part) will be saved.\r
+\r
+  @param FilePath      The device path pointing to a load option.\r
+                       It could be a short-form device path.\r
+  @param FullPath      Return the full device path of the load option after\r
+                       short-form device path expanding.\r
+                       Caller is responsible to free it.\r
+  @param FileSize      Return the load option size.\r
+\r
+  @return The load option buffer. Caller is responsible to free the memory.\r
+**/\r
+VOID *\r
+BmExpandPartitionDevicePath (\r
+  IN  EFI_DEVICE_PATH_PROTOCOL  *FilePath,\r
+  OUT EFI_DEVICE_PATH_PROTOCOL  **FullPath,\r
+  OUT UINTN                     *FileSize\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  UINTN                     BlockIoHandleCount;\r
+  EFI_HANDLE                *BlockIoBuffer;\r
+  VOID                      *FileBuffer;\r
+  EFI_DEVICE_PATH_PROTOCOL  *BlockIoDevicePath;\r
+  UINTN                     Index;\r
+  EFI_DEVICE_PATH_PROTOCOL  *CachedDevicePath;\r
+  EFI_DEVICE_PATH_PROTOCOL  *TempNewDevicePath;\r
+  EFI_DEVICE_PATH_PROTOCOL  *TempDevicePath;\r
+  UINTN                     CachedDevicePathSize;\r
+  BOOLEAN                   NeedAdjust;\r
+  EFI_DEVICE_PATH_PROTOCOL  *Instance;\r
+  UINTN                     Size;\r
+\r
+  FileBuffer = NULL;\r
+  //\r
+  // Check if there is prestore 'HDDP' variable.\r
+  // If exist, search the front path which point to partition node in the variable instants.\r
+  // If fail to find or 'HDDP' not exist, reconnect all and search in all system\r
+  //\r
+  GetVariable2 (L"HDDP", &mBmHardDriveBootVariableGuid, (VOID **) &CachedDevicePath, &CachedDevicePathSize);\r
+\r
+  //\r
+  // Delete the invalid 'HDDP' variable.\r
+  //\r
+  if ((CachedDevicePath != NULL) && !IsDevicePathValid (CachedDevicePath, CachedDevicePathSize)) {\r
+    FreePool (CachedDevicePath);\r
+    CachedDevicePath = NULL;\r
+    Status = gRT->SetVariable (\r
+                    L"HDDP",\r
+                    &mBmHardDriveBootVariableGuid,\r
+                    0,\r
+                    0,\r
+                    NULL\r
+                    );\r
+    ASSERT_EFI_ERROR (Status);\r
+  }\r
+\r
+  if (CachedDevicePath != NULL) {\r
+    TempNewDevicePath = CachedDevicePath;\r
+    NeedAdjust = FALSE;\r
+    do {\r
+      //\r
+      // Check every instance of the variable\r
+      // First, check whether the instance contain the partition node, which is needed for distinguishing  multi\r
+      // partial partition boot option. Second, check whether the instance could be connected.\r
+      //\r
+      Instance  = GetNextDevicePathInstance (&TempNewDevicePath, &Size);\r
+      if (BmMatchPartitionDevicePathNode (Instance, (HARDDRIVE_DEVICE_PATH *) FilePath)) {\r
+        //\r
+        // Connect the device path instance, the device path point to hard drive media device path node\r
+        // e.g. ACPI() /PCI()/ATA()/Partition()\r
+        //\r
+        Status = EfiBootManagerConnectDevicePath (Instance, NULL);\r
+        if (!EFI_ERROR (Status)) {\r
+          TempDevicePath = AppendDevicePath (Instance, NextDevicePathNode (FilePath));\r
+          FileBuffer = EfiBootManagerGetLoadOptionBuffer (TempDevicePath, FullPath, FileSize);\r
+          FreePool (TempDevicePath);\r
+\r
+          if (FileBuffer != NULL) {\r
+            //\r
+            // Adjust the 'HDDP' instances sequence if the matched one is not first one.\r
+            //\r
+            if (NeedAdjust) {\r
+              BmCachePartitionDevicePath (&CachedDevicePath, Instance);\r
+              //\r
+              // Save the matching Device Path so we don't need to do a connect all next time\r
+              // Failing to save only impacts performance next time expanding the short-form device path\r
+              //\r
+              Status = gRT->SetVariable (\r
+                L"HDDP",\r
+                &mBmHardDriveBootVariableGuid,\r
+                EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
+                GetDevicePathSize (CachedDevicePath),\r
+                CachedDevicePath\r
+                );\r
+            }\r
+\r
+            FreePool (Instance);\r
+            FreePool (CachedDevicePath);\r
+            return FileBuffer;\r
+          }\r
+        }\r
+      }\r
+      //\r
+      // Come here means the first instance is not matched\r
+      //\r
+      NeedAdjust = TRUE;\r
+      FreePool(Instance);\r
+    } while (TempNewDevicePath != NULL);\r
+  }\r
+\r
+  //\r
+  // If we get here we fail to find or 'HDDP' not exist, and now we need\r
+  // to search all devices in the system for a matched partition\r
+  //\r
+  EfiBootManagerConnectAll ();\r
+  Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &BlockIoHandleCount, &BlockIoBuffer);\r
+  if (EFI_ERROR (Status)) {\r
+    BlockIoHandleCount = 0;\r
+    BlockIoBuffer      = NULL;\r
+  }\r
+  //\r
+  // Loop through all the device handles that support the BLOCK_IO Protocol\r
+  //\r
+  for (Index = 0; Index < BlockIoHandleCount; Index++) {\r
+    BlockIoDevicePath = DevicePathFromHandle (BlockIoBuffer[Index]);\r
+    if (BlockIoDevicePath == NULL) {\r
+      continue;\r
+    }\r
+\r
+    if (BmMatchPartitionDevicePathNode (BlockIoDevicePath, (HARDDRIVE_DEVICE_PATH *) FilePath)) {\r
+      //\r
+      // Find the matched partition device path\r
+      //\r
+      TempDevicePath = AppendDevicePath (BlockIoDevicePath, NextDevicePathNode (FilePath));\r
+      FileBuffer = EfiBootManagerGetLoadOptionBuffer (TempDevicePath, FullPath, FileSize);\r
+      FreePool (TempDevicePath);\r
+\r
+      if (FileBuffer != NULL) {\r
+        BmCachePartitionDevicePath (&CachedDevicePath, BlockIoDevicePath);\r
+\r
+        //\r
+        // Save the matching Device Path so we don't need to do a connect all next time\r
+        // Failing to save only impacts performance next time expanding the short-form device path\r
+        //\r
+        Status = gRT->SetVariable (\r
+                        L"HDDP",\r
+                        &mBmHardDriveBootVariableGuid,\r
+                        EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
+                        GetDevicePathSize (CachedDevicePath),\r
+                        CachedDevicePath\r
+                        );\r
+\r
+        break;\r
+      }\r
+    }\r
+  }\r
+\r
+  if (CachedDevicePath != NULL) {\r
+    FreePool (CachedDevicePath);\r
+  }\r
+  if (BlockIoBuffer != NULL) {\r
+    FreePool (BlockIoBuffer);\r
+  }\r
+  return FileBuffer;\r
+}\r
+\r
+/**\r
+  Expand the media device path which points to a BlockIo or SimpleFileSystem instance\r
+  by appending EFI_REMOVABLE_MEDIA_FILE_NAME.\r
+\r
+  @param DevicePath  The media device path pointing to a BlockIo or SimpleFileSystem instance.\r
+  @param FullPath    Return the full device path pointing to the load option.\r
+  @param FileSize    Return the size of the load option.\r
+\r
+  @return  The load option buffer.\r
+**/\r
+VOID *\r
+BmExpandMediaDevicePath (\r
+  IN  EFI_DEVICE_PATH_PROTOCOL        *DevicePath,\r
+  OUT EFI_DEVICE_PATH_PROTOCOL        **FullPath,\r
+  OUT UINTN                           *FileSize\r
+  )\r
+{\r
+  EFI_STATUS                          Status;\r
+  EFI_HANDLE                          Handle;\r
+  EFI_BLOCK_IO_PROTOCOL               *BlockIo;\r
+  VOID                                *Buffer;\r
+  EFI_DEVICE_PATH_PROTOCOL            *TempDevicePath;\r
+  UINTN                               Size;\r
+  UINTN                               TempSize;\r
+  EFI_HANDLE                          *SimpleFileSystemHandles;\r
+  UINTN                               NumberSimpleFileSystemHandles;\r
+  UINTN                               Index;\r
+  VOID                                *FileBuffer;\r
+  UINT32                              AuthenticationStatus;\r
+\r
+  //\r
+  // Check whether the device is connected\r
+  //\r
+  TempDevicePath = DevicePath;\r
+  Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &TempDevicePath, &Handle);\r
+  if (!EFI_ERROR (Status)) {\r
+    ASSERT (IsDevicePathEnd (TempDevicePath));\r
+\r
+    TempDevicePath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME);\r
+    FileBuffer = GetFileBufferByFilePath (TRUE, TempDevicePath, FileSize, &AuthenticationStatus);\r
+    if (FileBuffer == NULL) {\r
+      FreePool (TempDevicePath);\r
+      TempDevicePath = NULL;\r
+    }\r
+    *FullPath = TempDevicePath;\r
+    return FileBuffer;\r
+  }\r
+\r
+  Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, &Handle);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // For device boot option only pointing to the removable device handle,\r
+  // should make sure all its children handles (its child partion or media handles)\r
+  // are created and connected.\r
+  //\r
+  gBS->ConnectController (Handle, NULL, NULL, TRUE);\r
+\r
+  //\r
+  // Issue a dummy read to the device to check for media change.\r
+  // When the removable media is changed, any Block IO read/write will\r
+  // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is\r
+  // returned. After the Block IO protocol is reinstalled, subsequent\r
+  // Block IO read/write will success.\r
+  //\r
+  Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);\r
+  ASSERT_EFI_ERROR (Status);\r
+  Buffer = AllocatePool (BlockIo->Media->BlockSize);\r
+  if (Buffer != NULL) {\r
+    BlockIo->ReadBlocks (\r
+      BlockIo,\r
+      BlockIo->Media->MediaId,\r
+      0,\r
+      BlockIo->Media->BlockSize,\r
+      Buffer\r
+      );\r
+    FreePool (Buffer);\r
+  }\r
+\r
+  //\r
+  // Detect the the default boot file from removable Media\r
+  //\r
+  FileBuffer = NULL;\r
+  *FullPath = NULL;\r
+  Size = GetDevicePathSize (DevicePath) - END_DEVICE_PATH_LENGTH;\r
+  gBS->LocateHandleBuffer (\r
+         ByProtocol,\r
+         &gEfiSimpleFileSystemProtocolGuid,\r
+         NULL,\r
+         &NumberSimpleFileSystemHandles,\r
+         &SimpleFileSystemHandles\r
+         );\r
+  for (Index = 0; Index < NumberSimpleFileSystemHandles; Index++) {\r
+    //\r
+    // Get the device path size of SimpleFileSystem handle\r
+    //\r
+    TempDevicePath = DevicePathFromHandle (SimpleFileSystemHandles[Index]);\r
+    TempSize = GetDevicePathSize (TempDevicePath) - END_DEVICE_PATH_LENGTH;\r
+    //\r
+    // Check whether the device path of boot option is part of the SimpleFileSystem handle's device path\r
+    //\r
+    if ((Size <= TempSize) && (CompareMem (TempDevicePath, DevicePath, Size) == 0)) {\r
+      TempDevicePath = FileDevicePath (SimpleFileSystemHandles[Index], EFI_REMOVABLE_MEDIA_FILE_NAME);\r
+      FileBuffer = GetFileBufferByFilePath (TRUE, TempDevicePath, FileSize, &AuthenticationStatus);\r
+      if (FileBuffer != NULL) {\r
+        *FullPath = TempDevicePath;\r
+        break;\r
+      }\r
+      FreePool (TempDevicePath);\r
+    }\r
+  }\r
+\r
+  if (SimpleFileSystemHandles != NULL) {\r
+    FreePool (SimpleFileSystemHandles);\r
+  }\r
+\r
+  return FileBuffer;\r
+}\r
+\r
+/**\r
+  Check whether Left and Right are the same without matching the specific\r
+  device path data in IP device path and URI device path node.\r
+\r
+  @retval TRUE  Left and Right are the same.\r
+  @retval FALSE Left and Right are the different.\r
+**/\r
+BOOLEAN\r
+BmMatchHttpBootDevicePath (\r
+  IN EFI_DEVICE_PATH_PROTOCOL *Left,\r
+  IN EFI_DEVICE_PATH_PROTOCOL *Right\r
+  )\r
+{\r
+  for (;  !IsDevicePathEnd (Left) && !IsDevicePathEnd (Right)\r
+       ;  Left = NextDevicePathNode (Left), Right = NextDevicePathNode (Right)\r
+       ) {\r
+    if (CompareMem (Left, Right, DevicePathNodeLength (Left)) != 0) {\r
+      if ((DevicePathType (Left) != MESSAGING_DEVICE_PATH) || (DevicePathType (Right) != MESSAGING_DEVICE_PATH)) {\r
+        return FALSE;\r
+      }\r
+\r
+      if (((DevicePathSubType (Left) != MSG_IPv4_DP) || (DevicePathSubType (Right) != MSG_IPv4_DP)) &&\r
+          ((DevicePathSubType (Left) != MSG_IPv6_DP) || (DevicePathSubType (Right) != MSG_IPv6_DP)) &&\r
+          ((DevicePathSubType (Left) != MSG_URI_DP)  || (DevicePathSubType (Right) != MSG_URI_DP))\r
+          ) {\r
+        return FALSE;\r
+      }\r
+    }\r
+  }\r
+  return (BOOLEAN) (IsDevicePathEnd (Left) && IsDevicePathEnd (Right));\r
+}\r
+\r
+/**\r
+  Get the file buffer from the file system produced by Load File instance.\r
+\r
+  @param LoadFileHandle The handle of LoadFile instance.\r
+  @param FullPath       Return the full device path pointing to the load option.\r
+  @param FileSize       Return the size of the load option.\r
+  @param RamDiskHandle  Return the RAM Disk handle.\r
+\r
+  @return  The load option buffer.\r
+**/\r
+VOID *\r
+BmGetFileBufferFromLoadFileSystem (\r
+  IN  EFI_HANDLE                      LoadFileHandle,\r
+  OUT EFI_DEVICE_PATH_PROTOCOL        **FullPath,\r
+  OUT UINTN                           *FileSize,\r
+  OUT EFI_HANDLE                      *RamDiskHandle\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  EFI_HANDLE                      Handle;\r
+  EFI_HANDLE                      *Handles;\r
+  UINTN                           HandleCount;\r
+  UINTN                           Index;\r
+  EFI_DEVICE_PATH_PROTOCOL        *Node;\r
+\r
+  Status = gBS->LocateHandleBuffer (\r
+                  ByProtocol,\r
+                  &gEfiBlockIoProtocolGuid,\r
+                  NULL,\r
+                  &HandleCount,\r
+                  &Handles\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    Handles = NULL;\r
+    HandleCount = 0;\r
+  }\r
+\r
+  Handle = NULL;\r
+  for (Index = 0; Index < HandleCount; Index++) {\r
+    Node = DevicePathFromHandle (Handles[Index]);\r
+    Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &Node, &Handle);\r
+    if (!EFI_ERROR (Status) &&\r
+        (Handle == LoadFileHandle) &&\r
+        (DevicePathType (Node) == MEDIA_DEVICE_PATH) && (DevicePathSubType (Node) == MEDIA_RAM_DISK_DP)) {\r
+      Handle = Handles[Index];\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (Handles != NULL) {\r
+    FreePool (Handles);\r
+  }\r
+\r
+  if (Index == HandleCount) {\r
+    Handle = NULL;\r
+  }\r
+\r
+  *RamDiskHandle = Handle;\r
+\r
+  if (Handle != NULL) {\r
+    return BmExpandMediaDevicePath (DevicePathFromHandle (Handle), FullPath, FileSize);\r
+  } else {\r
+    return NULL;\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Return the RAM Disk device path created by LoadFile.\r
+\r
+  @param FilePath  The source file path.\r
+\r
+  @return Callee-to-free RAM Disk device path\r
+**/\r
+EFI_DEVICE_PATH_PROTOCOL *\r
+BmGetRamDiskDevicePath (\r
+  IN EFI_DEVICE_PATH_PROTOCOL *FilePath\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  EFI_DEVICE_PATH_PROTOCOL    *RamDiskDevicePath;\r
+  EFI_DEVICE_PATH_PROTOCOL    *Node;\r
+  EFI_HANDLE                  Handle;\r
+\r
+  Node = FilePath;\r
+  Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &Node, &Handle);\r
+  if (!EFI_ERROR (Status) &&\r
+      (DevicePathType (Node) == MEDIA_DEVICE_PATH) &&\r
+      (DevicePathSubType (Node) == MEDIA_RAM_DISK_DP)\r
+      ) {\r
+\r
+    //\r
+    // Construct the device path pointing to RAM Disk\r
+    //\r
+    Node = NextDevicePathNode (Node);\r
+    RamDiskDevicePath = DuplicateDevicePath (FilePath);\r
+    ASSERT (RamDiskDevicePath != NULL);\r
+    SetDevicePathEndNode ((VOID *) ((UINTN) RamDiskDevicePath + ((UINTN) Node - (UINTN) FilePath)));\r
+    return RamDiskDevicePath;\r
+  }\r
+\r
+  return NULL;\r
+}\r
+\r
+/**\r
+  Return the buffer and buffer size occupied by the RAM Disk.\r
+\r
+  @param RamDiskDevicePath  RAM Disk device path.\r
+  @param RamDiskSizeInPages Return RAM Disk size in pages.\r
+\r
+  @retval RAM Disk buffer.\r
+**/\r
+VOID *\r
+BmGetRamDiskMemoryInfo (\r
+  IN EFI_DEVICE_PATH_PROTOCOL *RamDiskDevicePath,\r
+  OUT UINTN                   *RamDiskSizeInPages\r
+  )\r
+{\r
+\r
+  EFI_STATUS                  Status;\r
+  EFI_HANDLE                  Handle;\r
+  UINT64                      StartingAddr;\r
+  UINT64                      EndingAddr;\r
+\r
+  ASSERT (RamDiskDevicePath != NULL);\r
+\r
+  *RamDiskSizeInPages = 0;\r
+\r
+  //\r
+  // Get the buffer occupied by RAM Disk.\r
+  //\r
+  Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &RamDiskDevicePath, &Handle);\r
+  ASSERT_EFI_ERROR (Status);\r
+  ASSERT ((DevicePathType (RamDiskDevicePath) == MEDIA_DEVICE_PATH) &&\r
+          (DevicePathSubType (RamDiskDevicePath) == MEDIA_RAM_DISK_DP));\r
+  StartingAddr = ReadUnaligned64 ((UINT64 *) ((MEDIA_RAM_DISK_DEVICE_PATH *) RamDiskDevicePath)->StartingAddr);\r
+  EndingAddr   = ReadUnaligned64 ((UINT64 *) ((MEDIA_RAM_DISK_DEVICE_PATH *) RamDiskDevicePath)->EndingAddr);\r
+  *RamDiskSizeInPages = EFI_SIZE_TO_PAGES ((UINTN) (EndingAddr - StartingAddr + 1));\r
+  return (VOID *) (UINTN) StartingAddr;\r
+}\r
+\r
+/**\r
+  Destroy the RAM Disk.\r
+\r
+  The destroy operation includes to call RamDisk.Unregister to\r
+  unregister the RAM DISK from RAM DISK driver, free the memory\r
+  allocated for the RAM Disk.\r
+\r
+  @param RamDiskDevicePath    RAM Disk device path.\r
+**/\r
+VOID\r
+BmDestroyRamDisk (\r
+  IN EFI_DEVICE_PATH_PROTOCOL *RamDiskDevicePath\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  VOID                        *RamDiskBuffer;\r
+  UINTN                       RamDiskSizeInPages;\r
+\r
+  ASSERT (RamDiskDevicePath != NULL);\r
+\r
+  RamDiskBuffer = BmGetRamDiskMemoryInfo (RamDiskDevicePath, &RamDiskSizeInPages);\r
+\r
+  //\r
+  // Destroy RAM Disk.\r
+  //\r
+  if (mRamDisk == NULL) {\r
+    Status = gBS->LocateProtocol (&gEfiRamDiskProtocolGuid, NULL, (VOID *) &mRamDisk);\r
+    ASSERT_EFI_ERROR (Status);\r
+  }\r
+  Status = mRamDisk->Unregister (RamDiskDevicePath);\r
+  ASSERT_EFI_ERROR (Status);\r
+  FreePages (RamDiskBuffer, RamDiskSizeInPages);\r
+}\r
+\r
+/**\r
+  Get the file buffer from the specified Load File instance.\r
+\r
+  @param LoadFileHandle The specified Load File instance.\r
+  @param FilePath       The file path which will pass to LoadFile().\r
+  @param FullPath       Return the full device path pointing to the load option.\r
+  @param FileSize       Return the size of the load option.\r
+\r
+  @return  The load option buffer or NULL if fails.\r
+**/\r
+VOID *\r
+BmGetFileBufferFromLoadFile (\r
+  IN  EFI_HANDLE                      LoadFileHandle,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL        *FilePath,\r
+  OUT EFI_DEVICE_PATH_PROTOCOL        **FullPath,\r
+  OUT UINTN                           *FileSize\r
+  )\r
+{\r
+  EFI_STATUS                          Status;\r
+  EFI_LOAD_FILE_PROTOCOL              *LoadFile;\r
+  VOID                                *FileBuffer;\r
+  BOOLEAN                             LoadFileSystem;\r
+  EFI_HANDLE                          RamDiskHandle;\r
+  UINTN                               BufferSize;\r
+\r
+  *FileSize = 0;\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  LoadFileHandle,\r
+                  &gEfiLoadFileProtocolGuid,\r
+                  (VOID **) &LoadFile,\r
+                  gImageHandle,\r
+                  NULL,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  FileBuffer = NULL;\r
+  BufferSize = 0;\r
+  Status = LoadFile->LoadFile (LoadFile, FilePath, TRUE, &BufferSize, FileBuffer);\r
+  if ((Status != EFI_WARN_FILE_SYSTEM) && (Status != EFI_BUFFER_TOO_SMALL)) {\r
+    return NULL;\r
+  }\r
+\r
+  LoadFileSystem = (BOOLEAN) (Status == EFI_WARN_FILE_SYSTEM);\r
+  FileBuffer = LoadFileSystem ? AllocateReservedPages (EFI_SIZE_TO_PAGES (BufferSize)) : AllocatePool (BufferSize);\r
+  if (FileBuffer == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  Status = LoadFile->LoadFile (LoadFile, FilePath, TRUE, &BufferSize, FileBuffer);\r
+  if (EFI_ERROR (Status)) {\r
+    if (LoadFileSystem) {\r
+      FreePages (FileBuffer, EFI_SIZE_TO_PAGES (BufferSize));\r
+    } else {\r
+      FreePool (FileBuffer);\r
+    }\r
+    return NULL;\r
+  }\r
+\r
+  if (LoadFileSystem) {\r
+    FileBuffer = BmGetFileBufferFromLoadFileSystem (LoadFileHandle, FullPath, FileSize, &RamDiskHandle);\r
+    if (FileBuffer == NULL) {\r
+      //\r
+      // If there is no bootable executable in the populated\r
+      //\r
+      BmDestroyRamDisk (DevicePathFromHandle (RamDiskHandle));\r
+    }\r
+  } else {\r
+    *FileSize = BufferSize;\r
+    *FullPath = DuplicateDevicePath (DevicePathFromHandle (LoadFileHandle));\r
+  }\r
+\r
+  return FileBuffer;\r
+}\r
+\r
+/**\r
+  Get the file buffer from all the Load File instances.\r
+\r
+  @param FilePath    The media device path pointing to a LoadFile instance.\r
+  @param FullPath    Return the full device path pointing to the load option.\r
+  @param FileSize    Return the size of the load option.\r
+\r
+  @return  The load option buffer.\r
+**/\r
+VOID *\r
+BmGetFileBufferFromLoadFiles (\r
+  IN  EFI_DEVICE_PATH_PROTOCOL        *FilePath,\r
+  OUT EFI_DEVICE_PATH_PROTOCOL        **FullPath,\r
+  OUT UINTN                           *FileSize\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  EFI_HANDLE                      Handle;\r
+  EFI_HANDLE                      *Handles;\r
+  UINTN                           HandleCount;\r
+  UINTN                           Index;\r
+  EFI_DEVICE_PATH_PROTOCOL        *Node;\r
+\r
+  //\r
+  // Get file buffer from load file instance.\r
+  //\r
+  Node = FilePath;\r
+  Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &Node, &Handle);\r
+  if (!EFI_ERROR (Status) && IsDevicePathEnd (Node)) {\r
+    //\r
+    // When wide match happens, pass full device path to LoadFile (),\r
+    // otherwise, pass remaining device path to LoadFile ().\r
+    //\r
+    FilePath = Node;\r
+  } else {\r
+    Handle = NULL;\r
+    //\r
+    // Use wide match algorithm to find one when\r
+    //  cannot find a LoadFile instance to exactly match the FilePath\r
+    //\r
+    Status = gBS->LocateHandleBuffer (\r
+                    ByProtocol,\r
+                    &gEfiLoadFileProtocolGuid,\r
+                    NULL,\r
+                    &HandleCount,\r
+                    &Handles\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      Handles = NULL;\r
+      HandleCount = 0;\r
+    }\r
+    for (Index = 0; Index < HandleCount; Index++) {\r
+      if (BmMatchHttpBootDevicePath (DevicePathFromHandle (Handles[Index]), FilePath)) {\r
+        Handle = Handles[Index];\r
+        break;\r
+      }\r
+    }\r
+    if (Handles != NULL) {\r
+      FreePool (Handles);\r
+    }\r
+  }\r
+\r
+  if (Handle == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  return BmGetFileBufferFromLoadFile (Handle, FilePath, FullPath, FileSize);\r
+}\r
+\r
+/**\r
+  Get the load option by its device path.\r
+\r
+  @param FilePath  The device path pointing to a load option.\r
+                   It could be a short-form device path.\r
+  @param FullPath  Return the full device path of the load option after\r
+                   short-form device path expanding.\r
+                   Caller is responsible to free it.\r
+  @param FileSize  Return the load option size.\r
+\r
+  @return The load option buffer. Caller is responsible to free the memory.\r
+**/\r
+VOID *\r
+EFIAPI\r
+EfiBootManagerGetLoadOptionBuffer (\r
+  IN  EFI_DEVICE_PATH_PROTOCOL          *FilePath,\r
+  OUT EFI_DEVICE_PATH_PROTOCOL          **FullPath,\r
+  OUT UINTN                             *FileSize\r
+  )\r
+{\r
+  EFI_HANDLE                      Handle;\r
+  VOID                            *FileBuffer;\r
+  UINT32                          AuthenticationStatus;\r
+  EFI_DEVICE_PATH_PROTOCOL        *Node;\r
+  EFI_STATUS                      Status;\r
+\r
+  ASSERT ((FilePath != NULL) && (FullPath != NULL) && (FileSize != NULL));\r
+\r
+  EfiBootManagerConnectDevicePath (FilePath, NULL);\r
+\r
+  *FullPath  = NULL;\r
+  *FileSize  = 0;\r
+  FileBuffer = NULL;\r
+\r
+  //\r
+  // Boot from media device by adding a default file name \EFI\BOOT\BOOT{machine type short-name}.EFI\r
+  //\r
+  Node = FilePath;\r
+  Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &Node, &Handle);\r
+  if (EFI_ERROR (Status)) {\r
+    Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &Node, &Handle);\r
+  }\r
+\r
+  if (!EFI_ERROR (Status) && IsDevicePathEnd (Node)) {\r
+    return BmExpandMediaDevicePath (FilePath, FullPath, FileSize);\r
+  }\r
+\r
+  //\r
+  // Expand the short-form device path to full device path\r
+  //\r
+  if ((DevicePathType (FilePath) == MEDIA_DEVICE_PATH) &&\r
+      (DevicePathSubType (FilePath) == MEDIA_HARDDRIVE_DP)) {\r
+    //\r
+    // Expand the Harddrive device path\r
+    //\r
+    return BmExpandPartitionDevicePath (FilePath, FullPath, FileSize);\r
+  } else if ((DevicePathType (FilePath) == MEDIA_DEVICE_PATH) &&\r
+             (DevicePathSubType (FilePath) == MEDIA_FILEPATH_DP)) {\r
+    //\r
+    // Expand the File-path device path\r
+    //\r
+    return BmExpandFileDevicePath (FilePath, FullPath, FileSize);\r
+  } else if ((DevicePathType (FilePath) == MESSAGING_DEVICE_PATH) &&\r
+             (DevicePathSubType (FilePath) == MSG_URI_DP)) {\r
+    //\r
+    // Expand the URI device path\r
+    //\r
+    return BmExpandUriDevicePath (FilePath, FullPath, FileSize);\r
+  } else {\r
+    for (Node = FilePath; !IsDevicePathEnd (Node); Node = NextDevicePathNode (Node)) {\r
+      if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) &&\r
+          ((DevicePathSubType (Node) == MSG_USB_CLASS_DP) || (DevicePathSubType (Node) == MSG_USB_WWID_DP))) {\r
+        break;\r
+      }\r
+    }\r
+\r
+    if (!IsDevicePathEnd (Node)) {\r
+      //\r
+      // Expand the USB WWID/Class device path\r
+      //\r
+      FileBuffer = BmExpandUsbDevicePath (FilePath, FullPath, FileSize, Node);\r
+      if ((FileBuffer == NULL) && (FilePath == Node)) {\r
+        //\r
+        // Boot Option device path starts with USB Class or USB WWID device path.\r
+        // For Boot Option device path which doesn't begin with the USB Class or\r
+        // USB WWID device path, it's not needed to connect again here.\r
+        //\r
+        BmConnectUsbShortFormDevicePath (FilePath);\r
+        FileBuffer = BmExpandUsbDevicePath (FilePath, FullPath, FileSize, Node);\r
+      }\r
+      return FileBuffer;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Get file buffer from FV file path.\r
+  //\r
+  if (BmIsFvFilePath (FilePath)) {\r
+    return BmGetFileBufferByFvFilePath (FilePath, FullPath, FileSize);\r
+  }\r
+\r
+  //\r
+  // Get file buffer from simple file system.\r
+  //\r
+  Node   = FilePath;\r
+  Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &Node, &Handle);\r
+  if (!EFI_ERROR (Status)) {\r
+    FileBuffer = GetFileBufferByFilePath (TRUE, FilePath, FileSize, &AuthenticationStatus);\r
+    if (FileBuffer != NULL) {\r
+      *FullPath = DuplicateDevicePath (FilePath);\r
+    }\r
+    return FileBuffer;\r
+  }\r
+\r
+  return BmGetFileBufferFromLoadFiles (FilePath, FullPath, FileSize);\r
+}\r
+\r
+/**\r
+  Check if it's a Device Path pointing to BootManagerMenu.\r
+\r
+  @param  DevicePath     Input device path.\r
+\r
+  @retval TRUE   The device path is BootManagerMenu File Device Path.\r
+  @retval FALSE  The device path is NOT BootManagerMenu File Device Path.\r
+**/\r
+BOOLEAN\r
+BmIsBootManagerMenuFilePath (\r
+  EFI_DEVICE_PATH_PROTOCOL     *DevicePath\r
+)\r
+{\r
+  EFI_HANDLE                      FvHandle;\r
+  VOID                            *NameGuid;\r
+  EFI_STATUS                      Status;\r
+\r
+  Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &DevicePath, &FvHandle);\r
+  if (!EFI_ERROR (Status)) {\r
+    NameGuid = EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) DevicePath);\r
+    if (NameGuid != NULL) {\r
+      return CompareGuid (NameGuid, PcdGetPtr (PcdBootManagerMenuFile));\r
+    }\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  Attempt to boot the EFI boot option. This routine sets L"BootCurent" and\r
+  also signals the EFI ready to boot event. If the device path for the option\r
+  starts with a BBS device path a legacy boot is attempted via the registered \r
+  gLegacyBoot function. Short form device paths are also supported via this \r
+  rountine. A device path starting with MEDIA_HARDDRIVE_DP, MSG_USB_WWID_DP,\r
+  MSG_USB_CLASS_DP gets expaned out to find the first device that matches.\r
+  If the BootOption Device Path fails the removable media boot algorithm \r
+  is attempted (\EFI\BOOTIA32.EFI, \EFI\BOOTX64.EFI,... only one file type \r
+  is tried per processor type)\r
+\r
+  @param  BootOption    Boot Option to try and boot.\r
+                        On return, BootOption->Status contains the boot status.\r
+                        EFI_SUCCESS     BootOption was booted\r
+                        EFI_UNSUPPORTED A BBS device path was found with no valid callback\r
+                                        registered via EfiBootManagerInitialize().\r
+                        EFI_NOT_FOUND   The BootOption was not found on the system\r
+                        !EFI_SUCCESS    BootOption failed with this error status\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+EfiBootManagerBoot (\r
+  IN  EFI_BOOT_MANAGER_LOAD_OPTION             *BootOption\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  EFI_HANDLE                ImageHandle;\r
+  EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;\r
+  UINT16                    Uint16;\r
+  UINTN                     OptionNumber;\r
+  UINTN                     OriginalOptionNumber;\r
+  EFI_DEVICE_PATH_PROTOCOL  *FilePath;\r
+  EFI_DEVICE_PATH_PROTOCOL  *RamDiskDevicePath;\r
+  VOID                      *FileBuffer;\r
+  UINTN                     FileSize;\r
+  EFI_BOOT_LOGO_PROTOCOL    *BootLogo;\r
+  EFI_EVENT                 LegacyBootEvent;\r
+\r
+  if (BootOption == NULL) {\r
+    return;\r
+  }\r
+\r
+  if (BootOption->FilePath == NULL || BootOption->OptionType != LoadOptionTypeBoot) {\r
+    BootOption->Status = EFI_INVALID_PARAMETER;\r
+    return;\r
+  }\r
+\r
+  //\r
+  // 1. Create Boot#### for a temporary boot if there is no match Boot#### (i.e. a boot by selected a EFI Shell using "Boot From File")\r
+  //\r
+  OptionNumber = BmFindBootOptionInVariable (BootOption);\r
+  if (OptionNumber == LoadOptionNumberUnassigned) {\r
+    Status = BmGetFreeOptionNumber (LoadOptionTypeBoot, &Uint16);\r
+    if (!EFI_ERROR (Status)) {\r
+      //\r
+      // Save the BootOption->OptionNumber to restore later\r
+      //\r
+      OptionNumber             = Uint16;\r
+      OriginalOptionNumber     = BootOption->OptionNumber;\r
+      BootOption->OptionNumber = OptionNumber;\r
+      Status = EfiBootManagerLoadOptionToVariable (BootOption);\r
+      BootOption->OptionNumber = OriginalOptionNumber;\r
+    }\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_ERROR, "[Bds] Failed to create Boot#### for a temporary boot - %r!\n", Status));\r
+      BootOption->Status = Status;\r
+      return ;\r
+    }\r
+  }\r
+\r
+  //\r
+  // 2. Set BootCurrent\r
+  //\r
+  Uint16 = (UINT16) OptionNumber;\r
+  BmSetVariableAndReportStatusCodeOnError (\r
+    L"BootCurrent",\r
+    &gEfiGlobalVariableGuid,\r
+    EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+    sizeof (UINT16),\r
+    &Uint16\r
+    );\r
+\r
+  //\r
+  // 3. Signal the EVT_SIGNAL_READY_TO_BOOT event when we are about to load and execute\r
+  //    the boot option.\r
+  //\r
+  if (BmIsBootManagerMenuFilePath (BootOption->FilePath)) {\r
+    DEBUG ((EFI_D_INFO, "[Bds] Booting Boot Manager Menu.\n"));\r
+    BmStopHotkeyService (NULL, NULL);\r
+  } else {\r
+    EfiSignalEventReadyToBoot();\r
+    //\r
+    // Report Status Code to indicate ReadyToBoot was signalled\r
+    //\r
+    REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT));\r
+    //\r
+    // 4. Repair system through DriverHealth protocol\r
+    //\r
+    BmRepairAllControllers ();\r
+  }\r
+\r
+  PERF_START_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32) OptionNumber);\r
+\r
+  //\r
+  // 5. Adjust the different type memory page number just before booting\r
+  //    and save the updated info into the variable for next boot to use\r
+  //\r
+  BmSetMemoryTypeInformationVariable (\r
+    (BOOLEAN) ((BootOption->Attributes & LOAD_OPTION_CATEGORY) == LOAD_OPTION_CATEGORY_BOOT)\r
+  );\r
+\r
+  //\r
+  // 6. Load EFI boot option to ImageHandle\r
+  //\r
+  DEBUG_CODE_BEGIN ();\r
+  if (BootOption->Description == NULL) {\r
+    DEBUG ((DEBUG_INFO | DEBUG_LOAD, "[Bds]Booting from unknown device path\n"));\r
+  } else {\r
+    DEBUG ((DEBUG_INFO | DEBUG_LOAD, "[Bds]Booting %s\n", BootOption->Description));\r
+  }\r
+  DEBUG_CODE_END ();\r
+\r
+  ImageHandle       = NULL;\r
+  RamDiskDevicePath = NULL;\r
+  if (DevicePathType (BootOption->FilePath) != BBS_DEVICE_PATH) {\r
+    Status     = EFI_NOT_FOUND;\r
+    FileBuffer = EfiBootManagerGetLoadOptionBuffer (BootOption->FilePath, &FilePath, &FileSize);\r
+    if (FileBuffer != NULL) {\r
+      RamDiskDevicePath = BmGetRamDiskDevicePath (FilePath);\r
+    }\r
+    DEBUG_CODE (\r
+      if (FileBuffer != NULL && CompareMem (BootOption->FilePath, FilePath, GetDevicePathSize (FilePath)) != 0) {\r
+        DEBUG ((EFI_D_INFO, "[Bds] DevicePath expand: "));\r
+        BmPrintDp (BootOption->FilePath);\r
+        DEBUG ((EFI_D_INFO, " -> "));\r
+        BmPrintDp (FilePath);\r
+        DEBUG ((EFI_D_INFO, "\n"));\r
+      }\r
+    );\r
+    if (BmIsLoadOptionPeHeaderValid (BootOption->OptionType, FileBuffer, FileSize)) {\r
+      REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderLoad));\r
+      Status = gBS->LoadImage (\r
+                      TRUE,\r
+                      gImageHandle,\r
+                      FilePath,\r
+                      FileBuffer,\r
+                      FileSize,\r
+                      &ImageHandle\r
+                      );\r
+    }\r
+    if (FileBuffer != NULL) {\r
+      FreePool (FileBuffer);\r
+    }\r
+    if (FilePath != NULL) {\r
+      FreePool (FilePath);\r
+    }\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      //\r
+      // Report Status Code to indicate that the failure to load boot option\r
+      //\r
+      REPORT_STATUS_CODE (\r
+        EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
+        (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR)\r
+        );\r
+      BootOption->Status = Status;\r
+      //\r
+      // Destroy the RAM disk\r
+      //\r
+      if (RamDiskDevicePath != NULL) {\r
+        BmDestroyRamDisk (RamDiskDevicePath);\r
+        FreePool (RamDiskDevicePath);\r
+      }\r
+      return;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Check to see if we should legacy BOOT. If yes then do the legacy boot\r
+  // Write boot to OS performance data for Legacy boot\r
+  //\r
+  if ((DevicePathType (BootOption->FilePath) == BBS_DEVICE_PATH) && (DevicePathSubType (BootOption->FilePath) == BBS_BBS_DP)) {\r
+    if (mBmLegacyBoot != NULL) {\r
+      //\r
+      // Write boot to OS performance data for legacy boot.\r
+      //\r
+      PERF_CODE (\r
+        //\r
+        // Create an event to be signalled when Legacy Boot occurs to write performance data.\r
+        //\r
+        Status = EfiCreateEventLegacyBootEx(\r
+                   TPL_NOTIFY,\r
+                   BmWriteBootToOsPerformanceData,\r
+                   NULL, \r
+                   &LegacyBootEvent\r
+                   );\r
+        ASSERT_EFI_ERROR (Status);\r
+      );\r
+\r
+      mBmLegacyBoot (BootOption);\r
+    } else {\r
+      BootOption->Status = EFI_UNSUPPORTED;\r
+    }\r
+\r
+    PERF_END_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32) OptionNumber);\r
+    return;\r
+  }\r
\r
+  //\r
+  // Provide the image with its load options\r
+  //\r
+  Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  if (!BmIsAutoCreateBootOption (BootOption)) {\r
+    ImageInfo->LoadOptionsSize = BootOption->OptionalDataSize;\r
+    ImageInfo->LoadOptions     = BootOption->OptionalData;\r
+  }\r
+\r
+  //\r
+  // Clean to NULL because the image is loaded directly from the firmwares boot manager.\r
+  //\r
+  ImageInfo->ParentHandle = NULL;\r
+\r
+  //\r
+  // Before calling the image, enable the Watchdog Timer for 5 minutes period\r
+  //\r
+  gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);\r
+\r
+  //\r
+  // Write boot to OS performance data for UEFI boot\r
+  //\r
+  PERF_CODE (\r
+    BmWriteBootToOsPerformanceData (NULL, NULL);\r
+  );\r
+\r
+  REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderStart));\r
+\r
+  Status = gBS->StartImage (ImageHandle, &BootOption->ExitDataSize, &BootOption->ExitData);\r
+  DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Image Return Status = %r\n", Status));\r
+  BootOption->Status = Status;\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // Report Status Code to indicate that boot failure\r
+    //\r
+    REPORT_STATUS_CODE (\r
+      EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
+      (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED)\r
+      );\r
+  }\r
+  PERF_END_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32) OptionNumber);\r
+\r
+  //\r
+  // Destroy the RAM disk\r
+  //\r
+  if (RamDiskDevicePath != NULL) {\r
+    BmDestroyRamDisk (RamDiskDevicePath);\r
+    FreePool (RamDiskDevicePath);\r
+  }\r
+\r
+  //\r
+  // Clear the Watchdog Timer after the image returns\r
+  //\r
+  gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);\r
+\r
+  //\r
+  // Set Logo status invalid after trying one boot option\r
+  //\r
+  BootLogo = NULL;\r
+  Status = gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo);\r
+  if (!EFI_ERROR (Status) && (BootLogo != NULL)) {\r
+    Status = BootLogo->SetBootLogo (BootLogo, NULL, 0, 0, 0, 0);\r
+    ASSERT_EFI_ERROR (Status);\r
+  }\r
+\r
+  //\r
+  // Clear Boot Current\r
+  //\r
+  Status = gRT->SetVariable (\r
+                  L"BootCurrent",\r
+                  &gEfiGlobalVariableGuid,\r
+                  0,\r
+                  0,\r
+                  NULL\r
+                  );\r
+  //\r
+  // Deleting variable with current variable implementation shouldn't fail.\r
+  // When BootXXXX (e.g.: BootManagerMenu) boots BootYYYY, exiting BootYYYY causes BootCurrent deleted,\r
+  // exiting BootXXXX causes deleting BootCurrent returns EFI_NOT_FOUND.\r
+  //\r
+  ASSERT (Status == EFI_SUCCESS || Status == EFI_NOT_FOUND);\r
+}\r
+\r
+/**\r
+  Check whether there is a instance in BlockIoDevicePath, which contain multi device path\r
+  instances, has the same partition node with HardDriveDevicePath device path\r
+\r
+  @param  BlockIoDevicePath      Multi device path instances which need to check\r
+  @param  HardDriveDevicePath    A device path which starts with a hard drive media\r
+                                 device path.\r
+\r
+  @retval TRUE                   There is a matched device path instance.\r
+  @retval FALSE                  There is no matched device path instance.\r
+\r
+**/\r
+BOOLEAN\r
+BmMatchPartitionDevicePathNode (\r
+  IN  EFI_DEVICE_PATH_PROTOCOL   *BlockIoDevicePath,\r
+  IN  HARDDRIVE_DEVICE_PATH      *HardDriveDevicePath\r
+  )\r
+{\r
+  HARDDRIVE_DEVICE_PATH     *Node;\r
+\r
+  if ((BlockIoDevicePath == NULL) || (HardDriveDevicePath == NULL)) {\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // find the partition device path node\r
+  //\r
+  while (!IsDevicePathEnd (BlockIoDevicePath)) {\r
+    if ((DevicePathType (BlockIoDevicePath) == MEDIA_DEVICE_PATH) &&\r
+        (DevicePathSubType (BlockIoDevicePath) == MEDIA_HARDDRIVE_DP)\r
+        ) {\r
+      break;\r
+    }\r
+\r
+    BlockIoDevicePath = NextDevicePathNode (BlockIoDevicePath);\r
+  }\r
+\r
+  if (IsDevicePathEnd (BlockIoDevicePath)) {\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // See if the harddrive device path in blockio matches the orig Hard Drive Node\r
+  //\r
+  Node = (HARDDRIVE_DEVICE_PATH *) BlockIoDevicePath;\r
+\r
+  //\r
+  // Match Signature and PartitionNumber.\r
+  // Unused bytes in Signature are initiaized with zeros.\r
+  //\r
+  return (BOOLEAN) (\r
+    (Node->PartitionNumber == HardDriveDevicePath->PartitionNumber) &&\r
+    (Node->MBRType == HardDriveDevicePath->MBRType) &&\r
+    (Node->SignatureType == HardDriveDevicePath->SignatureType) &&\r
+    (CompareMem (Node->Signature, HardDriveDevicePath->Signature, sizeof (Node->Signature)) == 0)\r
+    );\r
+}\r
+\r
+/**\r
+  Emuerate all possible bootable medias in the following order:\r
+  1. Removable BlockIo            - The boot option only points to the removable media\r
+                                    device, like USB key, DVD, Floppy etc.\r
+  2. Fixed BlockIo                - The boot option only points to a Fixed blockIo device,\r
+                                    like HardDisk.\r
+  3. Non-BlockIo SimpleFileSystem - The boot option points to a device supporting\r
+                                    SimpleFileSystem Protocol, but not supporting BlockIo\r
+                                    protocol.\r
+  4. LoadFile                     - The boot option points to the media supporting \r
+                                    LoadFile protocol.\r
+  Reference: UEFI Spec chapter 3.3 Boot Option Variables Default Boot Behavior\r
+\r
+  @param BootOptionCount   Return the boot option count which has been found.\r
+\r
+  @retval   Pointer to the boot option array.\r
+**/\r
+EFI_BOOT_MANAGER_LOAD_OPTION *\r
+BmEnumerateBootOptions (\r
+  UINTN                                 *BootOptionCount\r
+  )\r
+{\r
+  EFI_STATUS                            Status;\r
+  EFI_BOOT_MANAGER_LOAD_OPTION          *BootOptions;\r
+  UINTN                                 HandleCount;\r
+  EFI_HANDLE                            *Handles;\r
+  EFI_BLOCK_IO_PROTOCOL                 *BlkIo;\r
+  UINTN                                 Removable;\r
+  UINTN                                 Index;\r
+  CHAR16                                *Description;\r
+\r
+  ASSERT (BootOptionCount != NULL);\r
+\r
+  *BootOptionCount = 0;\r
+  BootOptions      = NULL;\r
+\r
+  //\r
+  // Parse removable block io followed by fixed block io\r
+  //\r
+  gBS->LocateHandleBuffer (\r
+         ByProtocol,\r
+         &gEfiBlockIoProtocolGuid,\r
+         NULL,\r
+         &HandleCount,\r
+         &Handles\r
+         );\r
+\r
+  for (Removable = 0; Removable < 2; Removable++) {\r
+    for (Index = 0; Index < HandleCount; Index++) {\r
+      Status = gBS->HandleProtocol (\r
+                      Handles[Index],\r
+                      &gEfiBlockIoProtocolGuid,\r
+                      (VOID **) &BlkIo\r
+                      );\r
+      if (EFI_ERROR (Status)) {\r
+        continue;\r
+      }\r
+\r
+      //\r
+      // Skip the logical partitions\r
+      //\r
+      if (BlkIo->Media->LogicalPartition) {\r
+        continue;\r
+      }\r
+\r
+      //\r
+      // Skip the fixed block io then the removable block io\r
+      //\r
+      if (BlkIo->Media->RemovableMedia == ((Removable == 0) ? FALSE : TRUE)) {\r
+        continue;\r
+      }\r
+\r
+      Description = BmGetBootDescription (Handles[Index]);\r
+      BootOptions = ReallocatePool (\r
+                      sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),\r
+                      sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),\r
+                      BootOptions\r
+                      );\r
+      ASSERT (BootOptions != NULL);\r
+\r
+      Status = EfiBootManagerInitializeLoadOption (\r
+                 &BootOptions[(*BootOptionCount)++],\r
+                 LoadOptionNumberUnassigned,\r
+                 LoadOptionTypeBoot,\r
+                 LOAD_OPTION_ACTIVE,\r
+                 Description,\r
+                 DevicePathFromHandle (Handles[Index]),\r
+                 NULL,\r
+                 0\r
+                 );\r
+      ASSERT_EFI_ERROR (Status);\r
+\r
+      FreePool (Description);\r
+    }\r
+  }\r
+\r
+  if (HandleCount != 0) {\r
+    FreePool (Handles);\r
+  }\r
+\r
+  //\r
+  // Parse simple file system not based on block io\r
+  //\r
+  gBS->LocateHandleBuffer (\r
+         ByProtocol,\r
+         &gEfiSimpleFileSystemProtocolGuid,\r
+         NULL,\r
+         &HandleCount,\r
+         &Handles\r
+         );\r
+  for (Index = 0; Index < HandleCount; Index++) {\r
+    Status = gBS->HandleProtocol (\r
+                    Handles[Index],\r
+                    &gEfiBlockIoProtocolGuid,\r
+                    (VOID **) &BlkIo\r
+                    );\r
+     if (!EFI_ERROR (Status)) {\r
+      //\r
+      //  Skip if the file system handle supports a BlkIo protocol, which we've handled in above\r
+      //\r
+      continue;\r
+    }\r
+    Description = BmGetBootDescription (Handles[Index]);\r
+    BootOptions = ReallocatePool (\r
+                    sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),\r
+                    sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),\r
+                    BootOptions\r
+                    );\r
+    ASSERT (BootOptions != NULL);\r
+\r
+    Status = EfiBootManagerInitializeLoadOption (\r
+               &BootOptions[(*BootOptionCount)++],\r
+               LoadOptionNumberUnassigned,\r
+               LoadOptionTypeBoot,\r
+               LOAD_OPTION_ACTIVE,\r
+               Description,\r
+               DevicePathFromHandle (Handles[Index]),\r
+               NULL,\r
+               0\r
+               );\r
+    ASSERT_EFI_ERROR (Status);\r
+    FreePool (Description);\r
+  }\r
+\r
+  if (HandleCount != 0) {\r
+    FreePool (Handles);\r
+  }\r
+\r
+  //\r
+  // Parse load file protocol\r
+  //\r
+  gBS->LocateHandleBuffer (\r
+         ByProtocol,\r
+         &gEfiLoadFileProtocolGuid,\r
+         NULL,\r
+         &HandleCount,\r
+         &Handles\r
+         );\r
+  for (Index = 0; Index < HandleCount; Index++) {\r
+    //\r
+    // Ignore BootManagerMenu. its boot option will be created by EfiBootManagerGetBootManagerMenu().\r
+    //\r
+    if (BmIsBootManagerMenuFilePath (DevicePathFromHandle (Handles[Index]))) {\r
+      continue;\r
+    }\r
+\r
+    Description = BmGetBootDescription (Handles[Index]);\r
+    BootOptions = ReallocatePool (\r
+                    sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),\r
+                    sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),\r
+                    BootOptions\r
+                    );\r
+    ASSERT (BootOptions != NULL);\r
+\r
+    Status = EfiBootManagerInitializeLoadOption (\r
+               &BootOptions[(*BootOptionCount)++],\r
+               LoadOptionNumberUnassigned,\r
+               LoadOptionTypeBoot,\r
+               LOAD_OPTION_ACTIVE,\r
+               Description,\r
+               DevicePathFromHandle (Handles[Index]),\r
+               NULL,\r
+               0\r
+               );\r
+    ASSERT_EFI_ERROR (Status);\r
+    FreePool (Description);\r
+  }\r
+\r
+  if (HandleCount != 0) {\r
+    FreePool (Handles);\r
+  }\r
+\r
+  BmMakeBootOptionDescriptionUnique (BootOptions, *BootOptionCount);\r
+  return BootOptions;\r
+}\r
+\r
+/**\r
+  The function enumerates all boot options, creates them and registers them in the BootOrder variable.\r
+**/\r
+VOID\r
+EFIAPI\r
+EfiBootManagerRefreshAllBootOption (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  EFI_BOOT_MANAGER_LOAD_OPTION  *NvBootOptions;\r
+  UINTN                         NvBootOptionCount;\r
+  EFI_BOOT_MANAGER_LOAD_OPTION  *BootOptions;\r
+  UINTN                         BootOptionCount;\r
+  UINTN                         Index;\r
+\r
+  //\r
+  // Optionally refresh the legacy boot option\r
+  //\r
+  if (mBmRefreshLegacyBootOption != NULL) {\r
+    mBmRefreshLegacyBootOption ();\r
+  }\r
+\r
+  BootOptions   = BmEnumerateBootOptions (&BootOptionCount);\r
+  NvBootOptions = EfiBootManagerGetLoadOptions (&NvBootOptionCount, LoadOptionTypeBoot);\r
+\r
+  //\r
+  // Mark the boot option as added by BDS by setting OptionalData to a special GUID\r
+  //\r
+  for (Index = 0; Index < BootOptionCount; Index++) {\r
+    BootOptions[Index].OptionalData     = AllocateCopyPool (sizeof (EFI_GUID), &mBmAutoCreateBootOptionGuid);\r
+    BootOptions[Index].OptionalDataSize = sizeof (EFI_GUID);\r
+  }\r
+\r
+  //\r
+  // Remove invalid EFI boot options from NV\r
+  //\r
+  for (Index = 0; Index < NvBootOptionCount; Index++) {\r
+    if (((DevicePathType (NvBootOptions[Index].FilePath) != BBS_DEVICE_PATH) || \r
+         (DevicePathSubType (NvBootOptions[Index].FilePath) != BBS_BBS_DP)\r
+        ) && BmIsAutoCreateBootOption (&NvBootOptions[Index])\r
+       ) {\r
+      //\r
+      // Only check those added by BDS\r
+      // so that the boot options added by end-user or OS installer won't be deleted\r
+      //\r
+      if (EfiBootManagerFindLoadOption (&NvBootOptions[Index], BootOptions, BootOptionCount) == -1) {\r
+        Status = EfiBootManagerDeleteLoadOptionVariable (NvBootOptions[Index].OptionNumber, LoadOptionTypeBoot);\r
+        //\r
+        // Deleting variable with current variable implementation shouldn't fail.\r
+        //\r
+        ASSERT_EFI_ERROR (Status);\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // Add new EFI boot options to NV\r
+  //\r
+  for (Index = 0; Index < BootOptionCount; Index++) {\r
+    if (EfiBootManagerFindLoadOption (&BootOptions[Index], NvBootOptions, NvBootOptionCount) == -1) {\r
+      EfiBootManagerAddLoadOptionVariable (&BootOptions[Index], (UINTN) -1);\r
+      //\r
+      // Try best to add the boot options so continue upon failure.\r
+      //\r
+    }\r
+  }\r
+\r
+  EfiBootManagerFreeLoadOptions (BootOptions,   BootOptionCount);\r
+  EfiBootManagerFreeLoadOptions (NvBootOptions, NvBootOptionCount);\r
+}\r
+\r
+/**\r
+  This function is called to get or create the boot option for the Boot Manager Menu.\r
+\r
+  The Boot Manager Menu is shown after successfully booting a boot option.\r
+  Assume the BootManagerMenuFile is in the same FV as the module links to this library.\r
+\r
+  @param  BootOption    Return the boot option of the Boot Manager Menu\r
+\r
+  @retval EFI_SUCCESS   Successfully register the Boot Manager Menu.\r
+  @retval EFI_NOT_FOUND The Boot Manager Menu cannot be found.\r
+  @retval others        Return status of gRT->SetVariable (). BootOption still points\r
+                        to the Boot Manager Menu even the Status is not EFI_SUCCESS\r
+                        and EFI_NOT_FOUND.\r
+**/\r
+EFI_STATUS\r
+BmRegisterBootManagerMenu (\r
+  OUT EFI_BOOT_MANAGER_LOAD_OPTION   *BootOption\r
+  )\r
+{\r
+  EFI_STATUS                         Status;\r
+  CHAR16                             *Description;\r
+  UINTN                              DescriptionLength;\r
+  EFI_DEVICE_PATH_PROTOCOL           *DevicePath;\r
+  EFI_LOADED_IMAGE_PROTOCOL          *LoadedImage;\r
+  MEDIA_FW_VOL_FILEPATH_DEVICE_PATH  FileNode;\r
+  UINTN                              HandleCount;\r
+  EFI_HANDLE                         *Handles;\r
+  UINTN                              Index;\r
+  VOID                               *Data;\r
+  UINTN                              DataSize;\r
+\r
+  DevicePath = NULL;\r
+  Description = NULL;\r
+  //\r
+  // Try to find BootManagerMenu from LoadFile protocol\r
+  //\r
+  gBS->LocateHandleBuffer (\r
+         ByProtocol,\r
+         &gEfiLoadFileProtocolGuid,\r
+         NULL,\r
+         &HandleCount,\r
+         &Handles\r
+         );\r
+  for (Index = 0; Index < HandleCount; Index++) {\r
+    if (BmIsBootManagerMenuFilePath (DevicePathFromHandle (Handles[Index]))) {\r
+      DevicePath  = DuplicateDevicePath (DevicePathFromHandle (Handles[Index]));\r
+      Description = BmGetBootDescription (Handles[Index]);\r
+      break;\r
+    }\r
+  }\r
+  if (HandleCount != 0) {\r
+    FreePool (Handles);\r
+  }\r
+\r
+  if (DevicePath == NULL) {\r
+    Data = NULL;\r
+    Status = GetSectionFromFv (\r
+               PcdGetPtr (PcdBootManagerMenuFile),\r
+               EFI_SECTION_PE32,\r
+               0,\r
+               (VOID **) &Data,\r
+               &DataSize\r
+               );\r
+    if (Data != NULL) {\r
+      FreePool (Data);\r
+    }\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_WARN, "[Bds]BootManagerMenu FFS section can not be found, skip its boot option registration\n"));\r
+      return EFI_NOT_FOUND;\r
+    }\r
+\r
+    //\r
+    // Get BootManagerMenu application's description from EFI User Interface Section.\r
+    //\r
+    Status = GetSectionFromFv (\r
+               PcdGetPtr (PcdBootManagerMenuFile),\r
+               EFI_SECTION_USER_INTERFACE,\r
+               0,\r
+               (VOID **) &Description,\r
+               &DescriptionLength\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      Description = NULL;\r
+    }\r
+\r
+    EfiInitializeFwVolDevicepathNode (&FileNode, PcdGetPtr (PcdBootManagerMenuFile));\r
+    Status = gBS->HandleProtocol (\r
+                    gImageHandle,\r
+                    &gEfiLoadedImageProtocolGuid,\r
+                    (VOID **) &LoadedImage\r
+                    );\r
+    ASSERT_EFI_ERROR (Status);\r
+    DevicePath = AppendDevicePathNode (\r
+                   DevicePathFromHandle (LoadedImage->DeviceHandle),\r
+                   (EFI_DEVICE_PATH_PROTOCOL *) &FileNode\r
+                   );\r
+    ASSERT (DevicePath != NULL);\r
+  }\r
+\r
+  Status = EfiBootManagerInitializeLoadOption (\r
+             BootOption,\r
+             LoadOptionNumberUnassigned,\r
+             LoadOptionTypeBoot,\r
+             LOAD_OPTION_CATEGORY_APP | LOAD_OPTION_ACTIVE | LOAD_OPTION_HIDDEN,\r
+             (Description != NULL) ? Description : L"Boot Manager Menu",\r
+             DevicePath,\r
+             NULL,\r
+             0\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+  FreePool (DevicePath);\r
+  if (Description != NULL) {\r
+    FreePool (Description);\r
+  }\r
+\r
+  DEBUG_CODE (\r
+    EFI_BOOT_MANAGER_LOAD_OPTION    *BootOptions;\r
+    UINTN                           BootOptionCount;\r
+\r
+    BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);\r
+    ASSERT (EfiBootManagerFindLoadOption (BootOption, BootOptions, BootOptionCount) == -1);\r
+    EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);\r
+    );\r
+\r
+  return EfiBootManagerAddLoadOptionVariable (BootOption, 0);\r
+}\r
+\r
+/**\r
+  Return the boot option corresponding to the Boot Manager Menu.\r
+  It may automatically create one if the boot option hasn't been created yet.\r
+\r
+  @param BootOption    Return the Boot Manager Menu.\r
+\r
+  @retval EFI_SUCCESS   The Boot Manager Menu is successfully returned.\r
+  @retval EFI_NOT_FOUND The Boot Manager Menu cannot be found.\r
+  @retval others        Return status of gRT->SetVariable (). BootOption still points\r
+                        to the Boot Manager Menu even the Status is not EFI_SUCCESS\r
+                        and EFI_NOT_FOUND.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiBootManagerGetBootManagerMenu (\r
+  EFI_BOOT_MANAGER_LOAD_OPTION *BootOption\r
+  )\r
+{\r
+  EFI_STATUS                   Status;\r
+  UINTN                        BootOptionCount;\r
+  EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;\r
+  UINTN                        Index;\r
+  \r
+  BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);\r
+\r
+  for (Index = 0; Index < BootOptionCount; Index++) {\r
+    if (BmIsBootManagerMenuFilePath (BootOptions[Index].FilePath)) {\r
+        Status = EfiBootManagerInitializeLoadOption (\r
+                   BootOption,\r
+                   BootOptions[Index].OptionNumber,\r
+                   BootOptions[Index].OptionType,\r
+                   BootOptions[Index].Attributes,\r
+                   BootOptions[Index].Description,\r
+                   BootOptions[Index].FilePath,\r
+                   BootOptions[Index].OptionalData,\r
+                   BootOptions[Index].OptionalDataSize\r
+                   );\r
+        ASSERT_EFI_ERROR (Status);\r
+        break;\r
+    }\r
+  }\r
+\r
+  EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);\r
+\r
+  //\r
+  // Automatically create the Boot#### for Boot Manager Menu when not found.\r
+  //\r
+  if (Index == BootOptionCount) {\r
+    return BmRegisterBootManagerMenu (BootOption);\r
+  } else {\r
+    return EFI_SUCCESS;\r
+  }\r
+}\r
+\r