Home | History | Annotate | Download | only in UefiBootManagerLib
      1 /** @file
      2   Library functions which relates with booting.
      3 
      4 Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.<BR>
      5 (C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP<BR>
      6 This program and the accompanying materials
      7 are licensed and made available under the terms and conditions of the BSD License
      8 which accompanies this distribution.  The full text of the license may be found at
      9 http://opensource.org/licenses/bsd-license.php
     10 
     11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #include "InternalBm.h"
     17 
     18 EFI_RAM_DISK_PROTOCOL                        *mRamDisk                  = NULL;
     19 
     20 EFI_BOOT_MANAGER_REFRESH_LEGACY_BOOT_OPTION  mBmRefreshLegacyBootOption = NULL;
     21 EFI_BOOT_MANAGER_LEGACY_BOOT                 mBmLegacyBoot              = NULL;
     22 
     23 ///
     24 /// This GUID is used for an EFI Variable that stores the front device pathes
     25 /// for a partial device path that starts with the HD node.
     26 ///
     27 EFI_GUID mBmHardDriveBootVariableGuid = { 0xfab7e9e1, 0x39dd, 0x4f2b, { 0x84, 0x08, 0xe2, 0x0e, 0x90, 0x6c, 0xb6, 0xde } };
     28 EFI_GUID mBmAutoCreateBootOptionGuid  = { 0x8108ac4e, 0x9f11, 0x4d59, { 0x85, 0x0e, 0xe2, 0x1a, 0x52, 0x2c, 0x59, 0xb2 } };
     29 
     30 /**
     31   The function registers the legacy boot support capabilities.
     32 
     33   @param RefreshLegacyBootOption The function pointer to create all the legacy boot options.
     34   @param LegacyBoot              The function pointer to boot the legacy boot option.
     35 **/
     36 VOID
     37 EFIAPI
     38 EfiBootManagerRegisterLegacyBootSupport (
     39   EFI_BOOT_MANAGER_REFRESH_LEGACY_BOOT_OPTION   RefreshLegacyBootOption,
     40   EFI_BOOT_MANAGER_LEGACY_BOOT                  LegacyBoot
     41   )
     42 {
     43   mBmRefreshLegacyBootOption = RefreshLegacyBootOption;
     44   mBmLegacyBoot              = LegacyBoot;
     45 }
     46 
     47 /**
     48   Return TRUE when the boot option is auto-created instead of manually added.
     49 
     50   @param BootOption Pointer to the boot option to check.
     51 
     52   @retval TRUE  The boot option is auto-created.
     53   @retval FALSE The boot option is manually added.
     54 **/
     55 BOOLEAN
     56 BmIsAutoCreateBootOption (
     57   EFI_BOOT_MANAGER_LOAD_OPTION    *BootOption
     58   )
     59 {
     60   if ((BootOption->OptionalDataSize == sizeof (EFI_GUID)) &&
     61       CompareGuid ((EFI_GUID *) BootOption->OptionalData, &mBmAutoCreateBootOptionGuid)
     62       ) {
     63     return TRUE;
     64   } else {
     65     return FALSE;
     66   }
     67 }
     68 
     69 /**
     70   Find the boot option in the NV storage and return the option number.
     71 
     72   @param OptionToFind  Boot option to be checked.
     73 
     74   @return   The option number of the found boot option.
     75 
     76 **/
     77 UINTN
     78 BmFindBootOptionInVariable (
     79   IN  EFI_BOOT_MANAGER_LOAD_OPTION             *OptionToFind
     80   )
     81 {
     82   EFI_STATUS                   Status;
     83   EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
     84   UINTN                        OptionNumber;
     85   CHAR16                       OptionName[BM_OPTION_NAME_LEN];
     86   EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
     87   UINTN                        BootOptionCount;
     88   UINTN                        Index;
     89 
     90   OptionNumber = LoadOptionNumberUnassigned;
     91 
     92   //
     93   // Try to match the variable exactly if the option number is assigned
     94   //
     95   if (OptionToFind->OptionNumber != LoadOptionNumberUnassigned) {
     96     UnicodeSPrint (
     97       OptionName, sizeof (OptionName), L"%s%04x",
     98       mBmLoadOptionName[OptionToFind->OptionType], OptionToFind->OptionNumber
     99       );
    100     Status = EfiBootManagerVariableToLoadOption (OptionName, &BootOption);
    101 
    102     if (!EFI_ERROR (Status)) {
    103       ASSERT (OptionToFind->OptionNumber == BootOption.OptionNumber);
    104       if ((OptionToFind->Attributes == BootOption.Attributes) &&
    105           (StrCmp (OptionToFind->Description, BootOption.Description) == 0) &&
    106           (CompareMem (OptionToFind->FilePath, BootOption.FilePath, GetDevicePathSize (OptionToFind->FilePath)) == 0) &&
    107           (OptionToFind->OptionalDataSize == BootOption.OptionalDataSize) &&
    108           (CompareMem (OptionToFind->OptionalData, BootOption.OptionalData, OptionToFind->OptionalDataSize) == 0)
    109          ) {
    110         OptionNumber = OptionToFind->OptionNumber;
    111       }
    112       EfiBootManagerFreeLoadOption (&BootOption);
    113     }
    114   }
    115 
    116   //
    117   // The option number assigned is either incorrect or unassigned.
    118   //
    119   if (OptionNumber == LoadOptionNumberUnassigned) {
    120     BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
    121 
    122     Index = EfiBootManagerFindLoadOption (OptionToFind, BootOptions, BootOptionCount);
    123     if (Index != -1) {
    124       OptionNumber = BootOptions[Index].OptionNumber;
    125     }
    126 
    127     EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
    128   }
    129 
    130   return OptionNumber;
    131 }
    132 
    133 /**
    134   Get the file buffer using a Memory Mapped Device Path.
    135 
    136   FV address may change across reboot. This routine promises the FV file device path is right.
    137 
    138   @param  FilePath     The Memory Mapped Device Path to get the file buffer.
    139   @param  FullPath     Receive the updated FV Device Path pointint to the file.
    140   @param  FileSize     Receive the file buffer size.
    141 
    142   @return  The file buffer.
    143 **/
    144 VOID *
    145 BmGetFileBufferByFvFilePath (
    146   IN EFI_DEVICE_PATH_PROTOCOL      *FilePath,
    147   OUT EFI_DEVICE_PATH_PROTOCOL     **FullPath,
    148   OUT UINTN                        *FileSize
    149   )
    150 {
    151   EFI_STATUS                    Status;
    152   UINTN                         Index;
    153   EFI_DEVICE_PATH_PROTOCOL      *FvFileNode;
    154   EFI_HANDLE                    FvHandle;
    155   EFI_LOADED_IMAGE_PROTOCOL     *LoadedImage;
    156   UINT32                        AuthenticationStatus;
    157   UINTN                         FvHandleCount;
    158   EFI_HANDLE                    *FvHandles;
    159   EFI_DEVICE_PATH_PROTOCOL      *NewDevicePath;
    160   VOID                          *FileBuffer;
    161 
    162   //
    163   // Get the file buffer by using the exactly FilePath.
    164   //
    165   FvFileNode = FilePath;
    166   Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &FvFileNode, &FvHandle);
    167   if (!EFI_ERROR (Status)) {
    168     FileBuffer = GetFileBufferByFilePath (TRUE, FilePath, FileSize, &AuthenticationStatus);
    169     if (FileBuffer != NULL) {
    170       *FullPath = DuplicateDevicePath (FilePath);
    171     }
    172     return FileBuffer;
    173   }
    174 
    175   //
    176   // Only wide match other FVs if it's a memory mapped FV file path.
    177   //
    178   if ((DevicePathType (FilePath) != HARDWARE_DEVICE_PATH) || (DevicePathSubType (FilePath) != HW_MEMMAP_DP)) {
    179     return NULL;
    180   }
    181 
    182   FvFileNode = NextDevicePathNode (FilePath);
    183 
    184   //
    185   // Firstly find the FV file in current FV
    186   //
    187   gBS->HandleProtocol (
    188          gImageHandle,
    189          &gEfiLoadedImageProtocolGuid,
    190          (VOID **) &LoadedImage
    191          );
    192   NewDevicePath = AppendDevicePathNode (DevicePathFromHandle (LoadedImage->DeviceHandle), FvFileNode);
    193   FileBuffer = BmGetFileBufferByFvFilePath (NewDevicePath, FullPath, FileSize);
    194   FreePool (NewDevicePath);
    195 
    196   if (FileBuffer != NULL) {
    197     return FileBuffer;
    198   }
    199 
    200   //
    201   // Secondly find the FV file in all other FVs
    202   //
    203   gBS->LocateHandleBuffer (
    204          ByProtocol,
    205          &gEfiFirmwareVolume2ProtocolGuid,
    206          NULL,
    207          &FvHandleCount,
    208          &FvHandles
    209          );
    210   for (Index = 0; (Index < FvHandleCount) && (FileBuffer == NULL); Index++) {
    211     if (FvHandles[Index] == LoadedImage->DeviceHandle) {
    212       //
    213       // Skip current FV
    214       //
    215       continue;
    216     }
    217     NewDevicePath = AppendDevicePathNode (DevicePathFromHandle (FvHandles[Index]), FvFileNode);
    218     FileBuffer = BmGetFileBufferByFvFilePath (NewDevicePath, FullPath, FileSize);
    219     FreePool (NewDevicePath);
    220   }
    221 
    222   if (FvHandles != NULL) {
    223     FreePool (FvHandles);
    224   }
    225   return FileBuffer;
    226 }
    227 
    228 /**
    229   Check if it's a Device Path pointing to FV file.
    230 
    231   The function doesn't garentee the device path points to existing FV file.
    232 
    233   @param  DevicePath     Input device path.
    234 
    235   @retval TRUE   The device path is a FV File Device Path.
    236   @retval FALSE  The device path is NOT a FV File Device Path.
    237 **/
    238 BOOLEAN
    239 BmIsFvFilePath (
    240   IN EFI_DEVICE_PATH_PROTOCOL    *DevicePath
    241   )
    242 {
    243   EFI_STATUS                     Status;
    244   EFI_HANDLE                     Handle;
    245   EFI_DEVICE_PATH_PROTOCOL       *Node;
    246 
    247   Node = DevicePath;
    248   Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &Node, &Handle);
    249   if (!EFI_ERROR (Status)) {
    250     return TRUE;
    251   }
    252 
    253   if ((DevicePathType (DevicePath) == HARDWARE_DEVICE_PATH) && (DevicePathSubType (DevicePath) == HW_MEMMAP_DP)) {
    254     DevicePath = NextDevicePathNode (DevicePath);
    255     if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) && (DevicePathSubType (DevicePath) == MEDIA_PIWG_FW_FILE_DP)) {
    256       return IsDevicePathEnd (NextDevicePathNode (DevicePath));
    257     }
    258   }
    259   return FALSE;
    260 }
    261 
    262 /**
    263   Check whether a USB device match the specified USB Class device path. This
    264   function follows "Load Option Processing" behavior in UEFI specification.
    265 
    266   @param UsbIo       USB I/O protocol associated with the USB device.
    267   @param UsbClass    The USB Class device path to match.
    268 
    269   @retval TRUE       The USB device match the USB Class device path.
    270   @retval FALSE      The USB device does not match the USB Class device path.
    271 
    272 **/
    273 BOOLEAN
    274 BmMatchUsbClass (
    275   IN EFI_USB_IO_PROTOCOL        *UsbIo,
    276   IN USB_CLASS_DEVICE_PATH      *UsbClass
    277   )
    278 {
    279   EFI_STATUS                    Status;
    280   EFI_USB_DEVICE_DESCRIPTOR     DevDesc;
    281   EFI_USB_INTERFACE_DESCRIPTOR  IfDesc;
    282   UINT8                         DeviceClass;
    283   UINT8                         DeviceSubClass;
    284   UINT8                         DeviceProtocol;
    285 
    286   if ((DevicePathType (UsbClass) != MESSAGING_DEVICE_PATH) ||
    287       (DevicePathSubType (UsbClass) != MSG_USB_CLASS_DP)){
    288     return FALSE;
    289   }
    290 
    291   //
    292   // Check Vendor Id and Product Id.
    293   //
    294   Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);
    295   if (EFI_ERROR (Status)) {
    296     return FALSE;
    297   }
    298 
    299   if ((UsbClass->VendorId != 0xffff) &&
    300       (UsbClass->VendorId != DevDesc.IdVendor)) {
    301     return FALSE;
    302   }
    303 
    304   if ((UsbClass->ProductId != 0xffff) &&
    305       (UsbClass->ProductId != DevDesc.IdProduct)) {
    306     return FALSE;
    307   }
    308 
    309   DeviceClass    = DevDesc.DeviceClass;
    310   DeviceSubClass = DevDesc.DeviceSubClass;
    311   DeviceProtocol = DevDesc.DeviceProtocol;
    312   if (DeviceClass == 0) {
    313     //
    314     // If Class in Device Descriptor is set to 0, use the Class, SubClass and
    315     // Protocol in Interface Descriptor instead.
    316     //
    317     Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &IfDesc);
    318     if (EFI_ERROR (Status)) {
    319       return FALSE;
    320     }
    321 
    322     DeviceClass    = IfDesc.InterfaceClass;
    323     DeviceSubClass = IfDesc.InterfaceSubClass;
    324     DeviceProtocol = IfDesc.InterfaceProtocol;
    325   }
    326 
    327   //
    328   // Check Class, SubClass and Protocol.
    329   //
    330   if ((UsbClass->DeviceClass != 0xff) &&
    331       (UsbClass->DeviceClass != DeviceClass)) {
    332     return FALSE;
    333   }
    334 
    335   if ((UsbClass->DeviceSubClass != 0xff) &&
    336       (UsbClass->DeviceSubClass != DeviceSubClass)) {
    337     return FALSE;
    338   }
    339 
    340   if ((UsbClass->DeviceProtocol != 0xff) &&
    341       (UsbClass->DeviceProtocol != DeviceProtocol)) {
    342     return FALSE;
    343   }
    344 
    345   return TRUE;
    346 }
    347 
    348 /**
    349   Check whether a USB device match the specified USB WWID device path. This
    350   function follows "Load Option Processing" behavior in UEFI specification.
    351 
    352   @param UsbIo       USB I/O protocol associated with the USB device.
    353   @param UsbWwid     The USB WWID device path to match.
    354 
    355   @retval TRUE       The USB device match the USB WWID device path.
    356   @retval FALSE      The USB device does not match the USB WWID device path.
    357 
    358 **/
    359 BOOLEAN
    360 BmMatchUsbWwid (
    361   IN EFI_USB_IO_PROTOCOL        *UsbIo,
    362   IN USB_WWID_DEVICE_PATH       *UsbWwid
    363   )
    364 {
    365   EFI_STATUS                   Status;
    366   EFI_USB_DEVICE_DESCRIPTOR    DevDesc;
    367   EFI_USB_INTERFACE_DESCRIPTOR IfDesc;
    368   UINT16                       *LangIdTable;
    369   UINT16                       TableSize;
    370   UINT16                       Index;
    371   CHAR16                       *CompareStr;
    372   UINTN                        CompareLen;
    373   CHAR16                       *SerialNumberStr;
    374   UINTN                        Length;
    375 
    376   if ((DevicePathType (UsbWwid) != MESSAGING_DEVICE_PATH) ||
    377       (DevicePathSubType (UsbWwid) != MSG_USB_WWID_DP)) {
    378     return FALSE;
    379   }
    380 
    381   //
    382   // Check Vendor Id and Product Id.
    383   //
    384   Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);
    385   if (EFI_ERROR (Status)) {
    386     return FALSE;
    387   }
    388   if ((DevDesc.IdVendor != UsbWwid->VendorId) ||
    389       (DevDesc.IdProduct != UsbWwid->ProductId)) {
    390     return FALSE;
    391   }
    392 
    393   //
    394   // Check Interface Number.
    395   //
    396   Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &IfDesc);
    397   if (EFI_ERROR (Status)) {
    398     return FALSE;
    399   }
    400   if (IfDesc.InterfaceNumber != UsbWwid->InterfaceNumber) {
    401     return FALSE;
    402   }
    403 
    404   //
    405   // Check Serial Number.
    406   //
    407   if (DevDesc.StrSerialNumber == 0) {
    408     return FALSE;
    409   }
    410 
    411   //
    412   // Get all supported languages.
    413   //
    414   TableSize = 0;
    415   LangIdTable = NULL;
    416   Status = UsbIo->UsbGetSupportedLanguages (UsbIo, &LangIdTable, &TableSize);
    417   if (EFI_ERROR (Status) || (TableSize == 0) || (LangIdTable == NULL)) {
    418     return FALSE;
    419   }
    420 
    421   //
    422   // Serial number in USB WWID device path is the last 64-or-less UTF-16 characters.
    423   //
    424   CompareStr = (CHAR16 *) (UINTN) (UsbWwid + 1);
    425   CompareLen = (DevicePathNodeLength (UsbWwid) - sizeof (USB_WWID_DEVICE_PATH)) / sizeof (CHAR16);
    426   if (CompareStr[CompareLen - 1] == L'\0') {
    427     CompareLen--;
    428   }
    429 
    430   //
    431   // Compare serial number in each supported language.
    432   //
    433   for (Index = 0; Index < TableSize / sizeof (UINT16); Index++) {
    434     SerialNumberStr = NULL;
    435     Status = UsbIo->UsbGetStringDescriptor (
    436                       UsbIo,
    437                       LangIdTable[Index],
    438                       DevDesc.StrSerialNumber,
    439                       &SerialNumberStr
    440                       );
    441     if (EFI_ERROR (Status) || (SerialNumberStr == NULL)) {
    442       continue;
    443     }
    444 
    445     Length = StrLen (SerialNumberStr);
    446     if ((Length >= CompareLen) &&
    447         (CompareMem (SerialNumberStr + Length - CompareLen, CompareStr, CompareLen * sizeof (CHAR16)) == 0)) {
    448       FreePool (SerialNumberStr);
    449       return TRUE;
    450     }
    451 
    452     FreePool (SerialNumberStr);
    453   }
    454 
    455   return FALSE;
    456 }
    457 
    458 /**
    459   Find a USB device which match the specified short-form device path start with
    460   USB Class or USB WWID device path. If ParentDevicePath is NULL, this function
    461   will search in all USB devices of the platform. If ParentDevicePath is not NULL,
    462   this function will only search in its child devices.
    463 
    464   @param DevicePath           The device path that contains USB Class or USB WWID device path.
    465   @param ParentDevicePathSize The length of the device path before the USB Class or
    466                               USB WWID device path.
    467   @param UsbIoHandleCount     A pointer to the count of the returned USB IO handles.
    468 
    469   @retval NULL       The matched USB IO handles cannot be found.
    470   @retval other      The matched USB IO handles.
    471 
    472 **/
    473 EFI_HANDLE *
    474 BmFindUsbDevice (
    475   IN  EFI_DEVICE_PATH_PROTOCOL  *DevicePath,
    476   IN  UINTN                     ParentDevicePathSize,
    477   OUT UINTN                     *UsbIoHandleCount
    478   )
    479 {
    480   EFI_STATUS                Status;
    481   EFI_HANDLE                *UsbIoHandles;
    482   EFI_DEVICE_PATH_PROTOCOL  *UsbIoDevicePath;
    483   EFI_USB_IO_PROTOCOL       *UsbIo;
    484   UINTN                     Index;
    485   BOOLEAN                   Matched;
    486 
    487   ASSERT (UsbIoHandleCount != NULL);
    488 
    489   //
    490   // Get all UsbIo Handles.
    491   //
    492   Status = gBS->LocateHandleBuffer (
    493                   ByProtocol,
    494                   &gEfiUsbIoProtocolGuid,
    495                   NULL,
    496                   UsbIoHandleCount,
    497                   &UsbIoHandles
    498                   );
    499   if (EFI_ERROR (Status)) {
    500     *UsbIoHandleCount = 0;
    501     UsbIoHandles      = NULL;
    502   }
    503 
    504   for (Index = 0; Index < *UsbIoHandleCount; ) {
    505     //
    506     // Get the Usb IO interface.
    507     //
    508     Status = gBS->HandleProtocol(
    509                     UsbIoHandles[Index],
    510                     &gEfiUsbIoProtocolGuid,
    511                     (VOID **) &UsbIo
    512                     );
    513     UsbIoDevicePath = DevicePathFromHandle (UsbIoHandles[Index]);
    514     Matched         = FALSE;
    515     if (!EFI_ERROR (Status) && (UsbIoDevicePath != NULL)) {
    516 
    517       //
    518       // Compare starting part of UsbIoHandle's device path with ParentDevicePath.
    519       //
    520       if (CompareMem (UsbIoDevicePath, DevicePath, ParentDevicePathSize) == 0) {
    521         if (BmMatchUsbClass (UsbIo, (USB_CLASS_DEVICE_PATH *) ((UINTN) DevicePath + ParentDevicePathSize)) ||
    522             BmMatchUsbWwid (UsbIo, (USB_WWID_DEVICE_PATH *) ((UINTN) DevicePath + ParentDevicePathSize))) {
    523           Matched = TRUE;
    524         }
    525       }
    526     }
    527 
    528     if (!Matched) {
    529       (*UsbIoHandleCount) --;
    530       CopyMem (&UsbIoHandles[Index], &UsbIoHandles[Index + 1], (*UsbIoHandleCount - Index) * sizeof (EFI_HANDLE));
    531     } else {
    532       Index++;
    533     }
    534   }
    535 
    536   return UsbIoHandles;
    537 }
    538 
    539 /**
    540   Expand USB Class or USB WWID device path node to be full device path of a USB
    541   device in platform.
    542 
    543   This function support following 4 cases:
    544   1) Boot Option device path starts with a USB Class or USB WWID device path,
    545      and there is no Media FilePath device path in the end.
    546      In this case, it will follow Removable Media Boot Behavior.
    547   2) Boot Option device path starts with a USB Class or USB WWID device path,
    548      and ended with Media FilePath device path.
    549   3) Boot Option device path starts with a full device path to a USB Host Controller,
    550      contains a USB Class or USB WWID device path node, while not ended with Media
    551      FilePath device path. In this case, it will follow Removable Media Boot Behavior.
    552   4) Boot Option device path starts with a full device path to a USB Host Controller,
    553      contains a USB Class or USB WWID device path node, and ended with Media
    554      FilePath device path.
    555 
    556   @param FilePath      The device path pointing to a load option.
    557                        It could be a short-form device path.
    558   @param FullPath      Return the full device path of the load option after
    559                        short-form device path expanding.
    560                        Caller is responsible to free it.
    561   @param FileSize      Return the load option size.
    562   @param ShortformNode Pointer to the USB short-form device path node in the FilePath buffer.
    563 
    564   @return The load option buffer. Caller is responsible to free the memory.
    565 **/
    566 VOID *
    567 BmExpandUsbDevicePath (
    568   IN  EFI_DEVICE_PATH_PROTOCOL  *FilePath,
    569   OUT EFI_DEVICE_PATH_PROTOCOL  **FullPath,
    570   OUT UINTN                     *FileSize,
    571   IN EFI_DEVICE_PATH_PROTOCOL   *ShortformNode
    572   )
    573 {
    574   UINTN                             ParentDevicePathSize;
    575   EFI_DEVICE_PATH_PROTOCOL          *RemainingDevicePath;
    576   EFI_DEVICE_PATH_PROTOCOL          *FullDevicePath;
    577   EFI_HANDLE                        *Handles;
    578   UINTN                             HandleCount;
    579   UINTN                             Index;
    580   VOID                              *FileBuffer;
    581 
    582   ParentDevicePathSize = (UINTN) ShortformNode - (UINTN) FilePath;
    583   RemainingDevicePath = NextDevicePathNode (ShortformNode);
    584   FileBuffer = NULL;
    585   Handles = BmFindUsbDevice (FilePath, ParentDevicePathSize, &HandleCount);
    586 
    587   for (Index = 0; (Index < HandleCount) && (FileBuffer == NULL); Index++) {
    588     FullDevicePath = AppendDevicePath (DevicePathFromHandle (Handles[Index]), RemainingDevicePath);
    589     FileBuffer = EfiBootManagerGetLoadOptionBuffer (FullDevicePath, FullPath, FileSize);
    590     FreePool (FullDevicePath);
    591   }
    592 
    593   if (Handles != NULL) {
    594     FreePool (Handles);
    595   }
    596 
    597   return FileBuffer;
    598 }
    599 
    600 /**
    601   Expand File-path device path node to be full device path in platform.
    602 
    603   @param FilePath      The device path pointing to a load option.
    604                        It could be a short-form device path.
    605   @param FullPath      Return the full device path of the load option after
    606                        short-form device path expanding.
    607                        Caller is responsible to free it.
    608   @param FileSize      Return the load option size.
    609 
    610   @return The load option buffer. Caller is responsible to free the memory.
    611 **/
    612 VOID *
    613 BmExpandFileDevicePath (
    614   IN  EFI_DEVICE_PATH_PROTOCOL    *FilePath,
    615   OUT EFI_DEVICE_PATH_PROTOCOL    **FullPath,
    616   OUT UINTN                       *FileSize
    617   )
    618 {
    619   EFI_STATUS                      Status;
    620   UINTN                           Index;
    621   UINTN                           HandleCount;
    622   EFI_HANDLE                      *Handles;
    623   EFI_BLOCK_IO_PROTOCOL           *BlockIo;
    624   UINTN                           MediaType;
    625   EFI_DEVICE_PATH_PROTOCOL        *FullDevicePath;
    626   VOID                            *FileBuffer;
    627   UINT32                          AuthenticationStatus;
    628 
    629   EfiBootManagerConnectAll ();
    630   Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiSimpleFileSystemProtocolGuid, NULL, &HandleCount, &Handles);
    631   if (EFI_ERROR (Status)) {
    632     HandleCount = 0;
    633     Handles = NULL;
    634   }
    635 
    636   //
    637   // Enumerate all removable media devices followed by all fixed media devices,
    638   //   followed by media devices which don't layer on block io.
    639   //
    640   for (MediaType = 0; MediaType < 3; MediaType++) {
    641     for (Index = 0; Index < HandleCount; Index++) {
    642       Status = gBS->HandleProtocol (Handles[Index], &gEfiBlockIoProtocolGuid, (VOID *) &BlockIo);
    643       if (EFI_ERROR (Status)) {
    644         BlockIo = NULL;
    645       }
    646       if ((MediaType == 0 && BlockIo != NULL && BlockIo->Media->RemovableMedia) ||
    647           (MediaType == 1 && BlockIo != NULL && !BlockIo->Media->RemovableMedia) ||
    648           (MediaType == 2 && BlockIo == NULL)
    649           ) {
    650         FullDevicePath = AppendDevicePath (DevicePathFromHandle (Handles[Index]), FilePath);
    651         FileBuffer = GetFileBufferByFilePath (TRUE, FullDevicePath, FileSize, &AuthenticationStatus);
    652         if (FileBuffer != NULL) {
    653           *FullPath = FullDevicePath;
    654           FreePool (Handles);
    655           return FileBuffer;
    656         }
    657         FreePool (FullDevicePath);
    658       }
    659     }
    660   }
    661 
    662   if (Handles != NULL) {
    663     FreePool (Handles);
    664   }
    665 
    666   *FullPath = NULL;
    667   return NULL;
    668 }
    669 
    670 /**
    671   Expand URI device path node to be full device path in platform.
    672 
    673   @param FilePath      The device path pointing to a load option.
    674                        It could be a short-form device path.
    675   @param FullPath      Return the full device path of the load option after
    676                        short-form device path expanding.
    677                        Caller is responsible to free it.
    678   @param FileSize      Return the load option size.
    679 
    680   @return The load option buffer. Caller is responsible to free the memory.
    681 **/
    682 VOID *
    683 BmExpandUriDevicePath (
    684   IN  EFI_DEVICE_PATH_PROTOCOL    *FilePath,
    685   OUT EFI_DEVICE_PATH_PROTOCOL    **FullPath,
    686   OUT UINTN                       *FileSize
    687   )
    688 {
    689   EFI_STATUS                      Status;
    690   UINTN                           Index;
    691   UINTN                           HandleCount;
    692   EFI_HANDLE                      *Handles;
    693   VOID                            *FileBuffer;
    694 
    695   EfiBootManagerConnectAll ();
    696   Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiLoadFileProtocolGuid, NULL, &HandleCount, &Handles);
    697   if (EFI_ERROR (Status)) {
    698     HandleCount = 0;
    699     Handles = NULL;
    700   }
    701 
    702   FileBuffer = NULL;
    703   for (Index = 0; Index < HandleCount; Index++) {
    704     FileBuffer = BmGetFileBufferFromLoadFile (Handles[Index], FilePath, FullPath, FileSize);
    705     if (FileBuffer != NULL) {
    706       break;
    707     }
    708   }
    709 
    710   if (Handles != NULL) {
    711     FreePool (Handles);
    712   }
    713 
    714   return FileBuffer;
    715 }
    716 
    717 /**
    718   Save the partition DevicePath to the CachedDevicePath as the first instance.
    719 
    720   @param CachedDevicePath  The device path cache.
    721   @param DevicePath        The partition device path to be cached.
    722 **/
    723 VOID
    724 BmCachePartitionDevicePath (
    725   IN OUT EFI_DEVICE_PATH_PROTOCOL **CachedDevicePath,
    726   IN EFI_DEVICE_PATH_PROTOCOL     *DevicePath
    727   )
    728 {
    729   EFI_DEVICE_PATH_PROTOCOL        *TempDevicePath;
    730   UINTN                           Count;
    731 
    732   if (BmMatchDevicePaths (*CachedDevicePath, DevicePath)) {
    733     TempDevicePath = *CachedDevicePath;
    734     *CachedDevicePath = BmDelPartMatchInstance (*CachedDevicePath, DevicePath);
    735     FreePool (TempDevicePath);
    736   }
    737 
    738   if (*CachedDevicePath == NULL) {
    739     *CachedDevicePath = DuplicateDevicePath (DevicePath);
    740     return;
    741   }
    742 
    743   TempDevicePath = *CachedDevicePath;
    744   *CachedDevicePath = AppendDevicePathInstance (DevicePath, *CachedDevicePath);
    745   if (TempDevicePath != NULL) {
    746     FreePool (TempDevicePath);
    747   }
    748 
    749   //
    750   // Here limit the device path instance number to 12, which is max number for a system support 3 IDE controller
    751   // If the user try to boot many OS in different HDs or partitions, in theory, the 'HDDP' variable maybe become larger and larger.
    752   //
    753   Count = 0;
    754   TempDevicePath = *CachedDevicePath;
    755   while (!IsDevicePathEnd (TempDevicePath)) {
    756     TempDevicePath = NextDevicePathNode (TempDevicePath);
    757     //
    758     // Parse one instance
    759     //
    760     while (!IsDevicePathEndType (TempDevicePath)) {
    761       TempDevicePath = NextDevicePathNode (TempDevicePath);
    762     }
    763     Count++;
    764     //
    765     // If the CachedDevicePath variable contain too much instance, only remain 12 instances.
    766     //
    767     if (Count == 12) {
    768       SetDevicePathEndNode (TempDevicePath);
    769       break;
    770     }
    771   }
    772 }
    773 
    774 /**
    775   Expand a device path that starts with a hard drive media device path node to be a
    776   full device path that includes the full hardware path to the device. We need
    777   to do this so it can be booted. As an optimization the front match (the part point
    778   to the partition node. E.g. ACPI() /PCI()/ATA()/Partition() ) is saved in a variable
    779   so a connect all is not required on every boot. All successful history device path
    780   which point to partition node (the front part) will be saved.
    781 
    782   @param FilePath      The device path pointing to a load option.
    783                        It could be a short-form device path.
    784   @param FullPath      Return the full device path of the load option after
    785                        short-form device path expanding.
    786                        Caller is responsible to free it.
    787   @param FileSize      Return the load option size.
    788 
    789   @return The load option buffer. Caller is responsible to free the memory.
    790 **/
    791 VOID *
    792 BmExpandPartitionDevicePath (
    793   IN  EFI_DEVICE_PATH_PROTOCOL  *FilePath,
    794   OUT EFI_DEVICE_PATH_PROTOCOL  **FullPath,
    795   OUT UINTN                     *FileSize
    796   )
    797 {
    798   EFI_STATUS                Status;
    799   UINTN                     BlockIoHandleCount;
    800   EFI_HANDLE                *BlockIoBuffer;
    801   VOID                      *FileBuffer;
    802   EFI_DEVICE_PATH_PROTOCOL  *BlockIoDevicePath;
    803   UINTN                     Index;
    804   EFI_DEVICE_PATH_PROTOCOL  *CachedDevicePath;
    805   EFI_DEVICE_PATH_PROTOCOL  *TempNewDevicePath;
    806   EFI_DEVICE_PATH_PROTOCOL  *TempDevicePath;
    807   UINTN                     CachedDevicePathSize;
    808   BOOLEAN                   NeedAdjust;
    809   EFI_DEVICE_PATH_PROTOCOL  *Instance;
    810   UINTN                     Size;
    811 
    812   FileBuffer = NULL;
    813   //
    814   // Check if there is prestore 'HDDP' variable.
    815   // If exist, search the front path which point to partition node in the variable instants.
    816   // If fail to find or 'HDDP' not exist, reconnect all and search in all system
    817   //
    818   GetVariable2 (L"HDDP", &mBmHardDriveBootVariableGuid, (VOID **) &CachedDevicePath, &CachedDevicePathSize);
    819 
    820   //
    821   // Delete the invalid 'HDDP' variable.
    822   //
    823   if ((CachedDevicePath != NULL) && !IsDevicePathValid (CachedDevicePath, CachedDevicePathSize)) {
    824     FreePool (CachedDevicePath);
    825     CachedDevicePath = NULL;
    826     Status = gRT->SetVariable (
    827                     L"HDDP",
    828                     &mBmHardDriveBootVariableGuid,
    829                     0,
    830                     0,
    831                     NULL
    832                     );
    833     ASSERT_EFI_ERROR (Status);
    834   }
    835 
    836   if (CachedDevicePath != NULL) {
    837     TempNewDevicePath = CachedDevicePath;
    838     NeedAdjust = FALSE;
    839     do {
    840       //
    841       // Check every instance of the variable
    842       // First, check whether the instance contain the partition node, which is needed for distinguishing  multi
    843       // partial partition boot option. Second, check whether the instance could be connected.
    844       //
    845       Instance  = GetNextDevicePathInstance (&TempNewDevicePath, &Size);
    846       if (BmMatchPartitionDevicePathNode (Instance, (HARDDRIVE_DEVICE_PATH *) FilePath)) {
    847         //
    848         // Connect the device path instance, the device path point to hard drive media device path node
    849         // e.g. ACPI() /PCI()/ATA()/Partition()
    850         //
    851         Status = EfiBootManagerConnectDevicePath (Instance, NULL);
    852         if (!EFI_ERROR (Status)) {
    853           TempDevicePath = AppendDevicePath (Instance, NextDevicePathNode (FilePath));
    854           FileBuffer = EfiBootManagerGetLoadOptionBuffer (TempDevicePath, FullPath, FileSize);
    855           FreePool (TempDevicePath);
    856 
    857           if (FileBuffer != NULL) {
    858             //
    859             // Adjust the 'HDDP' instances sequence if the matched one is not first one.
    860             //
    861             if (NeedAdjust) {
    862               BmCachePartitionDevicePath (&CachedDevicePath, Instance);
    863               //
    864               // Save the matching Device Path so we don't need to do a connect all next time
    865               // Failing to save only impacts performance next time expanding the short-form device path
    866               //
    867               Status = gRT->SetVariable (
    868                 L"HDDP",
    869                 &mBmHardDriveBootVariableGuid,
    870                 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
    871                 GetDevicePathSize (CachedDevicePath),
    872                 CachedDevicePath
    873                 );
    874             }
    875 
    876             FreePool (Instance);
    877             FreePool (CachedDevicePath);
    878             return FileBuffer;
    879           }
    880         }
    881       }
    882       //
    883       // Come here means the first instance is not matched
    884       //
    885       NeedAdjust = TRUE;
    886       FreePool(Instance);
    887     } while (TempNewDevicePath != NULL);
    888   }
    889 
    890   //
    891   // If we get here we fail to find or 'HDDP' not exist, and now we need
    892   // to search all devices in the system for a matched partition
    893   //
    894   EfiBootManagerConnectAll ();
    895   Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &BlockIoHandleCount, &BlockIoBuffer);
    896   if (EFI_ERROR (Status)) {
    897     BlockIoHandleCount = 0;
    898     BlockIoBuffer      = NULL;
    899   }
    900   //
    901   // Loop through all the device handles that support the BLOCK_IO Protocol
    902   //
    903   for (Index = 0; Index < BlockIoHandleCount; Index++) {
    904     BlockIoDevicePath = DevicePathFromHandle (BlockIoBuffer[Index]);
    905     if (BlockIoDevicePath == NULL) {
    906       continue;
    907     }
    908 
    909     if (BmMatchPartitionDevicePathNode (BlockIoDevicePath, (HARDDRIVE_DEVICE_PATH *) FilePath)) {
    910       //
    911       // Find the matched partition device path
    912       //
    913       TempDevicePath = AppendDevicePath (BlockIoDevicePath, NextDevicePathNode (FilePath));
    914       FileBuffer = EfiBootManagerGetLoadOptionBuffer (TempDevicePath, FullPath, FileSize);
    915       FreePool (TempDevicePath);
    916 
    917       if (FileBuffer != NULL) {
    918         BmCachePartitionDevicePath (&CachedDevicePath, BlockIoDevicePath);
    919 
    920         //
    921         // Save the matching Device Path so we don't need to do a connect all next time
    922         // Failing to save only impacts performance next time expanding the short-form device path
    923         //
    924         Status = gRT->SetVariable (
    925                         L"HDDP",
    926                         &mBmHardDriveBootVariableGuid,
    927                         EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
    928                         GetDevicePathSize (CachedDevicePath),
    929                         CachedDevicePath
    930                         );
    931 
    932         break;
    933       }
    934     }
    935   }
    936 
    937   if (CachedDevicePath != NULL) {
    938     FreePool (CachedDevicePath);
    939   }
    940   if (BlockIoBuffer != NULL) {
    941     FreePool (BlockIoBuffer);
    942   }
    943   return FileBuffer;
    944 }
    945 
    946 /**
    947   Expand the media device path which points to a BlockIo or SimpleFileSystem instance
    948   by appending EFI_REMOVABLE_MEDIA_FILE_NAME.
    949 
    950   @param DevicePath  The media device path pointing to a BlockIo or SimpleFileSystem instance.
    951   @param FullPath    Return the full device path pointing to the load option.
    952   @param FileSize    Return the size of the load option.
    953 
    954   @return  The load option buffer.
    955 **/
    956 VOID *
    957 BmExpandMediaDevicePath (
    958   IN  EFI_DEVICE_PATH_PROTOCOL        *DevicePath,
    959   OUT EFI_DEVICE_PATH_PROTOCOL        **FullPath,
    960   OUT UINTN                           *FileSize
    961   )
    962 {
    963   EFI_STATUS                          Status;
    964   EFI_HANDLE                          Handle;
    965   EFI_BLOCK_IO_PROTOCOL               *BlockIo;
    966   VOID                                *Buffer;
    967   EFI_DEVICE_PATH_PROTOCOL            *TempDevicePath;
    968   UINTN                               Size;
    969   UINTN                               TempSize;
    970   EFI_HANDLE                          *SimpleFileSystemHandles;
    971   UINTN                               NumberSimpleFileSystemHandles;
    972   UINTN                               Index;
    973   VOID                                *FileBuffer;
    974   UINT32                              AuthenticationStatus;
    975 
    976   //
    977   // Check whether the device is connected
    978   //
    979   TempDevicePath = DevicePath;
    980   Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &TempDevicePath, &Handle);
    981   if (!EFI_ERROR (Status)) {
    982     ASSERT (IsDevicePathEnd (TempDevicePath));
    983 
    984     TempDevicePath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME);
    985     FileBuffer = GetFileBufferByFilePath (TRUE, TempDevicePath, FileSize, &AuthenticationStatus);
    986     if (FileBuffer == NULL) {
    987       FreePool (TempDevicePath);
    988       TempDevicePath = NULL;
    989     }
    990     *FullPath = TempDevicePath;
    991     return FileBuffer;
    992   }
    993 
    994   //
    995   // For device boot option only pointing to the removable device handle,
    996   // should make sure all its children handles (its child partion or media handles) are created and connected.
    997   //
    998   gBS->ConnectController (Handle, NULL, NULL, TRUE);
    999 
   1000   //
   1001   // Issue a dummy read to the device to check for media change.
   1002   // When the removable media is changed, any Block IO read/write will
   1003   // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is
   1004   // returned. After the Block IO protocol is reinstalled, subsequent
   1005   // Block IO read/write will success.
   1006   //
   1007   Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, &Handle);
   1008   ASSERT_EFI_ERROR (Status);
   1009   Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
   1010   ASSERT_EFI_ERROR (Status);
   1011   Buffer = AllocatePool (BlockIo->Media->BlockSize);
   1012   if (Buffer != NULL) {
   1013     BlockIo->ReadBlocks (
   1014       BlockIo,
   1015       BlockIo->Media->MediaId,
   1016       0,
   1017       BlockIo->Media->BlockSize,
   1018       Buffer
   1019       );
   1020     FreePool (Buffer);
   1021   }
   1022 
   1023   //
   1024   // Detect the the default boot file from removable Media
   1025   //
   1026   FileBuffer = NULL;
   1027   *FullPath = NULL;
   1028   Size = GetDevicePathSize (DevicePath) - END_DEVICE_PATH_LENGTH;
   1029   gBS->LocateHandleBuffer (
   1030          ByProtocol,
   1031          &gEfiSimpleFileSystemProtocolGuid,
   1032          NULL,
   1033          &NumberSimpleFileSystemHandles,
   1034          &SimpleFileSystemHandles
   1035          );
   1036   for (Index = 0; Index < NumberSimpleFileSystemHandles; Index++) {
   1037     //
   1038     // Get the device path size of SimpleFileSystem handle
   1039     //
   1040     TempDevicePath = DevicePathFromHandle (SimpleFileSystemHandles[Index]);
   1041     TempSize = GetDevicePathSize (TempDevicePath) - END_DEVICE_PATH_LENGTH;
   1042     //
   1043     // Check whether the device path of boot option is part of the SimpleFileSystem handle's device path
   1044     //
   1045     if ((Size <= TempSize) && (CompareMem (TempDevicePath, DevicePath, Size) == 0)) {
   1046       TempDevicePath = FileDevicePath (SimpleFileSystemHandles[Index], EFI_REMOVABLE_MEDIA_FILE_NAME);
   1047       FileBuffer = GetFileBufferByFilePath (TRUE, TempDevicePath, FileSize, &AuthenticationStatus);
   1048       if (FileBuffer != NULL) {
   1049         *FullPath = TempDevicePath;
   1050         break;
   1051       }
   1052       FreePool (TempDevicePath);
   1053     }
   1054   }
   1055 
   1056   if (SimpleFileSystemHandles != NULL) {
   1057     FreePool (SimpleFileSystemHandles);
   1058   }
   1059 
   1060   return FileBuffer;
   1061 }
   1062 
   1063 /**
   1064   Check whether Left and Right are the same without matching the specific
   1065   device path data in IP device path and URI device path node.
   1066 
   1067   @retval TRUE  Left and Right are the same.
   1068   @retval FALSE Left and Right are the different.
   1069 **/
   1070 BOOLEAN
   1071 BmMatchHttpBootDevicePath (
   1072   IN EFI_DEVICE_PATH_PROTOCOL *Left,
   1073   IN EFI_DEVICE_PATH_PROTOCOL *Right
   1074   )
   1075 {
   1076   for (;  !IsDevicePathEnd (Left) && !IsDevicePathEnd (Right)
   1077        ;  Left = NextDevicePathNode (Left), Right = NextDevicePathNode (Right)
   1078        ) {
   1079     if (CompareMem (Left, Right, DevicePathNodeLength (Left)) != 0) {
   1080       if ((DevicePathType (Left) != MESSAGING_DEVICE_PATH) || (DevicePathType (Right) != MESSAGING_DEVICE_PATH)) {
   1081         return FALSE;
   1082       }
   1083 
   1084       if (((DevicePathSubType (Left) != MSG_IPv4_DP) || (DevicePathSubType (Right) != MSG_IPv4_DP)) &&
   1085           ((DevicePathSubType (Left) != MSG_IPv6_DP) || (DevicePathSubType (Right) != MSG_IPv6_DP)) &&
   1086           ((DevicePathSubType (Left) != MSG_URI_DP)  || (DevicePathSubType (Right) != MSG_URI_DP))
   1087           ) {
   1088         return FALSE;
   1089       }
   1090     }
   1091   }
   1092   return (BOOLEAN) (IsDevicePathEnd (Left) && IsDevicePathEnd (Right));
   1093 }
   1094 
   1095 /**
   1096   Get the file buffer from the file system produced by Load File instance.
   1097 
   1098   @param LoadFileHandle The handle of LoadFile instance.
   1099   @param FullPath       Return the full device path pointing to the load option.
   1100   @param FileSize       Return the size of the load option.
   1101   @param RamDiskHandle  Return the RAM Disk handle.
   1102 
   1103   @return  The load option buffer.
   1104 **/
   1105 VOID *
   1106 BmGetFileBufferFromLoadFileSystem (
   1107   IN  EFI_HANDLE                      LoadFileHandle,
   1108   OUT EFI_DEVICE_PATH_PROTOCOL        **FullPath,
   1109   OUT UINTN                           *FileSize,
   1110   OUT EFI_HANDLE                      *RamDiskHandle
   1111   )
   1112 {
   1113   EFI_STATUS                      Status;
   1114   EFI_HANDLE                      Handle;
   1115   EFI_HANDLE                      *Handles;
   1116   UINTN                           HandleCount;
   1117   UINTN                           Index;
   1118   EFI_DEVICE_PATH_PROTOCOL        *Node;
   1119 
   1120   Status = gBS->LocateHandleBuffer (
   1121                   ByProtocol,
   1122                   &gEfiBlockIoProtocolGuid,
   1123                   NULL,
   1124                   &HandleCount,
   1125                   &Handles
   1126                   );
   1127   if (EFI_ERROR (Status)) {
   1128     Handles = NULL;
   1129     HandleCount = 0;
   1130   }
   1131 
   1132   Handle = NULL;
   1133   for (Index = 0; Index < HandleCount; Index++) {
   1134     Node = DevicePathFromHandle (Handles[Index]);
   1135     Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &Node, &Handle);
   1136     if (!EFI_ERROR (Status) &&
   1137         (Handle == LoadFileHandle) &&
   1138         (DevicePathType (Node) == MEDIA_DEVICE_PATH) && (DevicePathSubType (Node) == MEDIA_RAM_DISK_DP)) {
   1139       Handle = Handles[Index];
   1140       break;
   1141     }
   1142   }
   1143 
   1144   if (Handles != NULL) {
   1145     FreePool (Handles);
   1146   }
   1147 
   1148   if (Index == HandleCount) {
   1149     Handle = NULL;
   1150   }
   1151 
   1152   *RamDiskHandle = Handle;
   1153 
   1154   if (Handle != NULL) {
   1155     return BmExpandMediaDevicePath (DevicePathFromHandle (Handle), FullPath, FileSize);
   1156   } else {
   1157     return NULL;
   1158   }
   1159 }
   1160 
   1161 
   1162 /**
   1163   Return the RAM Disk device path created by LoadFile.
   1164 
   1165   @param FilePath  The source file path.
   1166 
   1167   @return Callee-to-free RAM Disk device path
   1168 **/
   1169 EFI_DEVICE_PATH_PROTOCOL *
   1170 BmGetRamDiskDevicePath (
   1171   IN EFI_DEVICE_PATH_PROTOCOL *FilePath
   1172   )
   1173 {
   1174   EFI_STATUS                  Status;
   1175   EFI_DEVICE_PATH_PROTOCOL    *RamDiskDevicePath;
   1176   EFI_DEVICE_PATH_PROTOCOL    *Node;
   1177   EFI_HANDLE                  Handle;
   1178 
   1179   Node = FilePath;
   1180   Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &Node, &Handle);
   1181   if (!EFI_ERROR (Status) &&
   1182       (DevicePathType (Node) == MEDIA_DEVICE_PATH) &&
   1183       (DevicePathSubType (Node) == MEDIA_RAM_DISK_DP)
   1184       ) {
   1185 
   1186     //
   1187     // Construct the device path pointing to RAM Disk
   1188     //
   1189     Node = NextDevicePathNode (Node);
   1190     RamDiskDevicePath = DuplicateDevicePath (FilePath);
   1191     ASSERT (RamDiskDevicePath != NULL);
   1192     SetDevicePathEndNode ((VOID *) ((UINTN) RamDiskDevicePath + ((UINTN) Node - (UINTN) FilePath)));
   1193     return RamDiskDevicePath;
   1194   }
   1195 
   1196   return NULL;
   1197 }
   1198 
   1199 /**
   1200   Return the buffer and buffer size occupied by the RAM Disk.
   1201 
   1202   @param RamDiskDevicePath  RAM Disk device path.
   1203   @param RamDiskSizeInPages Return RAM Disk size in pages.
   1204 
   1205   @retval RAM Disk buffer.
   1206 **/
   1207 VOID *
   1208 BmGetRamDiskMemoryInfo (
   1209   IN EFI_DEVICE_PATH_PROTOCOL *RamDiskDevicePath,
   1210   OUT UINTN                   *RamDiskSizeInPages
   1211   )
   1212 {
   1213 
   1214   EFI_STATUS                  Status;
   1215   EFI_HANDLE                  Handle;
   1216   UINT64                      StartingAddr;
   1217   UINT64                      EndingAddr;
   1218 
   1219   ASSERT (RamDiskDevicePath != NULL);
   1220 
   1221   *RamDiskSizeInPages = 0;
   1222 
   1223   //
   1224   // Get the buffer occupied by RAM Disk.
   1225   //
   1226   Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &RamDiskDevicePath, &Handle);
   1227   ASSERT_EFI_ERROR (Status);
   1228   ASSERT ((DevicePathType (RamDiskDevicePath) == MEDIA_DEVICE_PATH) &&
   1229           (DevicePathSubType (RamDiskDevicePath) == MEDIA_RAM_DISK_DP));
   1230   StartingAddr = ReadUnaligned64 ((UINT64 *) ((MEDIA_RAM_DISK_DEVICE_PATH *) RamDiskDevicePath)->StartingAddr);
   1231   EndingAddr   = ReadUnaligned64 ((UINT64 *) ((MEDIA_RAM_DISK_DEVICE_PATH *) RamDiskDevicePath)->EndingAddr);
   1232   *RamDiskSizeInPages = EFI_SIZE_TO_PAGES ((UINTN) (EndingAddr - StartingAddr + 1));
   1233   return (VOID *) (UINTN) StartingAddr;
   1234 }
   1235 
   1236 /**
   1237   Destroy the RAM Disk.
   1238 
   1239   The destroy operation includes to call RamDisk.Unregister to
   1240   unregister the RAM DISK from RAM DISK driver, free the memory
   1241   allocated for the RAM Disk.
   1242 
   1243   @param RamDiskDevicePath    RAM Disk device path.
   1244 **/
   1245 VOID
   1246 BmDestroyRamDisk (
   1247   IN EFI_DEVICE_PATH_PROTOCOL *RamDiskDevicePath
   1248   )
   1249 {
   1250   EFI_STATUS                  Status;
   1251   VOID                        *RamDiskBuffer;
   1252   UINTN                       RamDiskSizeInPages;
   1253 
   1254   ASSERT (RamDiskDevicePath != NULL);
   1255 
   1256   RamDiskBuffer = BmGetRamDiskMemoryInfo (RamDiskDevicePath, &RamDiskSizeInPages);
   1257 
   1258   //
   1259   // Destroy RAM Disk.
   1260   //
   1261   if (mRamDisk == NULL) {
   1262     Status = gBS->LocateProtocol (&gEfiRamDiskProtocolGuid, NULL, (VOID *) &mRamDisk);
   1263     ASSERT_EFI_ERROR (Status);
   1264   }
   1265   Status = mRamDisk->Unregister (RamDiskDevicePath);
   1266   ASSERT_EFI_ERROR (Status);
   1267   FreePages (RamDiskBuffer, RamDiskSizeInPages);
   1268 }
   1269 
   1270 /**
   1271   Get the file buffer from the specified Load File instance.
   1272 
   1273   @param LoadFileHandle The specified Load File instance.
   1274   @param FilePath       The file path which will pass to LoadFile().
   1275   @param FullPath       Return the full device path pointing to the load option.
   1276   @param FileSize       Return the size of the load option.
   1277 
   1278   @return  The load option buffer or NULL if fails.
   1279 **/
   1280 VOID *
   1281 BmGetFileBufferFromLoadFile (
   1282   IN  EFI_HANDLE                      LoadFileHandle,
   1283   IN  EFI_DEVICE_PATH_PROTOCOL        *FilePath,
   1284   OUT EFI_DEVICE_PATH_PROTOCOL        **FullPath,
   1285   OUT UINTN                           *FileSize
   1286   )
   1287 {
   1288   EFI_STATUS                          Status;
   1289   EFI_LOAD_FILE_PROTOCOL              *LoadFile;
   1290   VOID                                *FileBuffer;
   1291   BOOLEAN                             LoadFileSystem;
   1292   EFI_HANDLE                          RamDiskHandle;
   1293   UINTN                               BufferSize;
   1294 
   1295   *FileSize = 0;
   1296 
   1297   Status = gBS->OpenProtocol (
   1298                   LoadFileHandle,
   1299                   &gEfiLoadFileProtocolGuid,
   1300                   (VOID **) &LoadFile,
   1301                   gImageHandle,
   1302                   NULL,
   1303                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
   1304                   );
   1305   ASSERT_EFI_ERROR (Status);
   1306 
   1307   FileBuffer = NULL;
   1308   BufferSize = 0;
   1309   Status = LoadFile->LoadFile (LoadFile, FilePath, TRUE, &BufferSize, FileBuffer);
   1310   if ((Status != EFI_WARN_FILE_SYSTEM) && (Status != EFI_BUFFER_TOO_SMALL)) {
   1311     return NULL;
   1312   }
   1313 
   1314   LoadFileSystem = (BOOLEAN) (Status == EFI_WARN_FILE_SYSTEM);
   1315   FileBuffer = LoadFileSystem ? AllocateReservedPages (EFI_SIZE_TO_PAGES (BufferSize)) : AllocatePool (BufferSize);
   1316   if (FileBuffer == NULL) {
   1317     return NULL;
   1318   }
   1319 
   1320   Status = LoadFile->LoadFile (LoadFile, FilePath, TRUE, &BufferSize, FileBuffer);
   1321   if (EFI_ERROR (Status)) {
   1322     if (LoadFileSystem) {
   1323       FreePages (FileBuffer, EFI_SIZE_TO_PAGES (BufferSize));
   1324     } else {
   1325       FreePool (FileBuffer);
   1326     }
   1327     return NULL;
   1328   }
   1329 
   1330   if (LoadFileSystem) {
   1331     FileBuffer = BmGetFileBufferFromLoadFileSystem (LoadFileHandle, FullPath, FileSize, &RamDiskHandle);
   1332     if (FileBuffer == NULL) {
   1333       //
   1334       // If there is no bootable executable in the populated
   1335       //
   1336       BmDestroyRamDisk (DevicePathFromHandle (RamDiskHandle));
   1337     }
   1338   } else {
   1339     *FileSize = BufferSize;
   1340     *FullPath = DuplicateDevicePath (DevicePathFromHandle (LoadFileHandle));
   1341   }
   1342 
   1343   return FileBuffer;
   1344 }
   1345 
   1346 /**
   1347   Get the file buffer from all the Load File instances.
   1348 
   1349   @param FilePath    The media device path pointing to a LoadFile instance.
   1350   @param FullPath    Return the full device path pointing to the load option.
   1351   @param FileSize    Return the size of the load option.
   1352 
   1353   @return  The load option buffer.
   1354 **/
   1355 VOID *
   1356 BmGetFileBufferFromLoadFiles (
   1357   IN  EFI_DEVICE_PATH_PROTOCOL        *FilePath,
   1358   OUT EFI_DEVICE_PATH_PROTOCOL        **FullPath,
   1359   OUT UINTN                           *FileSize
   1360   )
   1361 {
   1362   EFI_STATUS                      Status;
   1363   EFI_HANDLE                      Handle;
   1364   EFI_HANDLE                      *Handles;
   1365   UINTN                           HandleCount;
   1366   UINTN                           Index;
   1367   EFI_DEVICE_PATH_PROTOCOL        *Node;
   1368 
   1369   //
   1370   // Get file buffer from load file instance.
   1371   //
   1372   Node = FilePath;
   1373   Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &Node, &Handle);
   1374   if (!EFI_ERROR (Status) && IsDevicePathEnd (Node)) {
   1375     //
   1376     // When wide match happens, pass full device path to LoadFile (),
   1377     // otherwise, pass remaining device path to LoadFile ().
   1378     //
   1379     FilePath = Node;
   1380   } else {
   1381     Handle = NULL;
   1382     //
   1383     // Use wide match algorithm to find one when
   1384     //  cannot find a LoadFile instance to exactly match the FilePath
   1385     //
   1386     Status = gBS->LocateHandleBuffer (
   1387                     ByProtocol,
   1388                     &gEfiLoadFileProtocolGuid,
   1389                     NULL,
   1390                     &HandleCount,
   1391                     &Handles
   1392                     );
   1393     if (EFI_ERROR (Status)) {
   1394       Handles = NULL;
   1395       HandleCount = 0;
   1396     }
   1397     for (Index = 0; Index < HandleCount; Index++) {
   1398       if (BmMatchHttpBootDevicePath (DevicePathFromHandle (Handles[Index]), FilePath)) {
   1399         Handle = Handles[Index];
   1400         break;
   1401       }
   1402     }
   1403     if (Handles != NULL) {
   1404       FreePool (Handles);
   1405     }
   1406   }
   1407 
   1408   if (Handle == NULL) {
   1409     return NULL;
   1410   }
   1411 
   1412   return BmGetFileBufferFromLoadFile (Handle, FilePath, FullPath, FileSize);
   1413 }
   1414 
   1415 /**
   1416   Get the load option by its device path.
   1417 
   1418   @param FilePath  The device path pointing to a load option.
   1419                    It could be a short-form device path.
   1420   @param FullPath  Return the full device path of the load option after
   1421                    short-form device path expanding.
   1422                    Caller is responsible to free it.
   1423   @param FileSize  Return the load option size.
   1424 
   1425   @return The load option buffer. Caller is responsible to free the memory.
   1426 **/
   1427 VOID *
   1428 EFIAPI
   1429 EfiBootManagerGetLoadOptionBuffer (
   1430   IN  EFI_DEVICE_PATH_PROTOCOL          *FilePath,
   1431   OUT EFI_DEVICE_PATH_PROTOCOL          **FullPath,
   1432   OUT UINTN                             *FileSize
   1433   )
   1434 {
   1435   EFI_HANDLE                      Handle;
   1436   VOID                            *FileBuffer;
   1437   UINT32                          AuthenticationStatus;
   1438   EFI_DEVICE_PATH_PROTOCOL        *Node;
   1439   EFI_STATUS                      Status;
   1440 
   1441   ASSERT ((FilePath != NULL) && (FullPath != NULL) && (FileSize != NULL));
   1442 
   1443   EfiBootManagerConnectDevicePath (FilePath, NULL);
   1444 
   1445   *FullPath  = NULL;
   1446   *FileSize  = 0;
   1447   FileBuffer = NULL;
   1448 
   1449   //
   1450   // Boot from media device by adding a default file name \EFI\BOOT\BOOT{machine type short-name}.EFI
   1451   //
   1452   Node = FilePath;
   1453   Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &Node, &Handle);
   1454   if (EFI_ERROR (Status)) {
   1455     Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &Node, &Handle);
   1456   }
   1457 
   1458   if (!EFI_ERROR (Status) && IsDevicePathEnd (Node)) {
   1459     return BmExpandMediaDevicePath (FilePath, FullPath, FileSize);
   1460   }
   1461 
   1462   //
   1463   // Expand the short-form device path to full device path
   1464   //
   1465   if ((DevicePathType (FilePath) == MEDIA_DEVICE_PATH) &&
   1466       (DevicePathSubType (FilePath) == MEDIA_HARDDRIVE_DP)) {
   1467     //
   1468     // Expand the Harddrive device path
   1469     //
   1470     return BmExpandPartitionDevicePath (FilePath, FullPath, FileSize);
   1471   } else if ((DevicePathType (FilePath) == MEDIA_DEVICE_PATH) &&
   1472              (DevicePathSubType (FilePath) == MEDIA_FILEPATH_DP)) {
   1473     //
   1474     // Expand the File-path device path
   1475     //
   1476     return BmExpandFileDevicePath (FilePath, FullPath, FileSize);
   1477   } else if ((DevicePathType (FilePath) == MESSAGING_DEVICE_PATH) &&
   1478              (DevicePathSubType (FilePath) == MSG_URI_DP)) {
   1479     //
   1480     // Expand the URI device path
   1481     //
   1482     return BmExpandUriDevicePath (FilePath, FullPath, FileSize);
   1483   } else {
   1484     for (Node = FilePath; !IsDevicePathEnd (Node); Node = NextDevicePathNode (Node)) {
   1485       if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) &&
   1486           ((DevicePathSubType (Node) == MSG_USB_CLASS_DP) || (DevicePathSubType (Node) == MSG_USB_WWID_DP))) {
   1487         break;
   1488       }
   1489     }
   1490 
   1491     if (!IsDevicePathEnd (Node)) {
   1492       //
   1493       // Expand the USB WWID/Class device path
   1494       //
   1495       FileBuffer = BmExpandUsbDevicePath (FilePath, FullPath, FileSize, Node);
   1496       if ((FileBuffer == NULL) && (FilePath == Node)) {
   1497         //
   1498         // Boot Option device path starts with USB Class or USB WWID device path.
   1499         // For Boot Option device path which doesn't begin with the USB Class or
   1500         // USB WWID device path, it's not needed to connect again here.
   1501         //
   1502         BmConnectUsbShortFormDevicePath (FilePath);
   1503         FileBuffer = BmExpandUsbDevicePath (FilePath, FullPath, FileSize, Node);
   1504       }
   1505       return FileBuffer;
   1506     }
   1507   }
   1508 
   1509   //
   1510   // Get file buffer from FV file path.
   1511   //
   1512   if (BmIsFvFilePath (FilePath)) {
   1513     return BmGetFileBufferByFvFilePath (FilePath, FullPath, FileSize);
   1514   }
   1515 
   1516   //
   1517   // Get file buffer from simple file system.
   1518   //
   1519   Node   = FilePath;
   1520   Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &Node, &Handle);
   1521   if (!EFI_ERROR (Status)) {
   1522     FileBuffer = GetFileBufferByFilePath (TRUE, FilePath, FileSize, &AuthenticationStatus);
   1523     if (FileBuffer != NULL) {
   1524       *FullPath = DuplicateDevicePath (FilePath);
   1525     }
   1526     return FileBuffer;
   1527   }
   1528 
   1529   return BmGetFileBufferFromLoadFiles (FilePath, FullPath, FileSize);
   1530 }
   1531 
   1532 /**
   1533   Check if it's a Device Path pointing to BootManagerMenu.
   1534 
   1535   @param  DevicePath     Input device path.
   1536 
   1537   @retval TRUE   The device path is BootManagerMenu File Device Path.
   1538   @retval FALSE  The device path is NOT BootManagerMenu File Device Path.
   1539 **/
   1540 BOOLEAN
   1541 BmIsBootManagerMenuFilePath (
   1542   EFI_DEVICE_PATH_PROTOCOL     *DevicePath
   1543 )
   1544 {
   1545   EFI_HANDLE                      FvHandle;
   1546   VOID                            *NameGuid;
   1547   EFI_STATUS                      Status;
   1548 
   1549   Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &DevicePath, &FvHandle);
   1550   if (!EFI_ERROR (Status)) {
   1551     NameGuid = EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) DevicePath);
   1552     if (NameGuid != NULL) {
   1553       return CompareGuid (NameGuid, PcdGetPtr (PcdBootManagerMenuFile));
   1554     }
   1555   }
   1556 
   1557   return FALSE;
   1558 }
   1559 
   1560 /**
   1561   Attempt to boot the EFI boot option. This routine sets L"BootCurent" and
   1562   also signals the EFI ready to boot event. If the device path for the option
   1563   starts with a BBS device path a legacy boot is attempted via the registered
   1564   gLegacyBoot function. Short form device paths are also supported via this
   1565   rountine. A device path starting with MEDIA_HARDDRIVE_DP, MSG_USB_WWID_DP,
   1566   MSG_USB_CLASS_DP gets expaned out to find the first device that matches.
   1567   If the BootOption Device Path fails the removable media boot algorithm
   1568   is attempted (\EFI\BOOTIA32.EFI, \EFI\BOOTX64.EFI,... only one file type
   1569   is tried per processor type)
   1570 
   1571   @param  BootOption    Boot Option to try and boot.
   1572                         On return, BootOption->Status contains the boot status.
   1573                         EFI_SUCCESS     BootOption was booted
   1574                         EFI_UNSUPPORTED A BBS device path was found with no valid callback
   1575                                         registered via EfiBootManagerInitialize().
   1576                         EFI_NOT_FOUND   The BootOption was not found on the system
   1577                         !EFI_SUCCESS    BootOption failed with this error status
   1578 
   1579 **/
   1580 VOID
   1581 EFIAPI
   1582 EfiBootManagerBoot (
   1583   IN  EFI_BOOT_MANAGER_LOAD_OPTION             *BootOption
   1584   )
   1585 {
   1586   EFI_STATUS                Status;
   1587   EFI_HANDLE                ImageHandle;
   1588   EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;
   1589   UINT16                    Uint16;
   1590   UINTN                     OptionNumber;
   1591   UINTN                     OriginalOptionNumber;
   1592   EFI_DEVICE_PATH_PROTOCOL  *FilePath;
   1593   EFI_DEVICE_PATH_PROTOCOL  *RamDiskDevicePath;
   1594   VOID                      *FileBuffer;
   1595   UINTN                     FileSize;
   1596   EFI_BOOT_LOGO_PROTOCOL    *BootLogo;
   1597   EFI_EVENT                 LegacyBootEvent;
   1598 
   1599   if (BootOption == NULL) {
   1600     return;
   1601   }
   1602 
   1603   if (BootOption->FilePath == NULL || BootOption->OptionType != LoadOptionTypeBoot) {
   1604     BootOption->Status = EFI_INVALID_PARAMETER;
   1605     return;
   1606   }
   1607 
   1608   //
   1609   // 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")
   1610   //
   1611   OptionNumber = BmFindBootOptionInVariable (BootOption);
   1612   if (OptionNumber == LoadOptionNumberUnassigned) {
   1613     Status = BmGetFreeOptionNumber (LoadOptionTypeBoot, &Uint16);
   1614     if (!EFI_ERROR (Status)) {
   1615       //
   1616       // Save the BootOption->OptionNumber to restore later
   1617       //
   1618       OptionNumber             = Uint16;
   1619       OriginalOptionNumber     = BootOption->OptionNumber;
   1620       BootOption->OptionNumber = OptionNumber;
   1621       Status = EfiBootManagerLoadOptionToVariable (BootOption);
   1622       BootOption->OptionNumber = OriginalOptionNumber;
   1623     }
   1624 
   1625     if (EFI_ERROR (Status)) {
   1626       DEBUG ((EFI_D_ERROR, "[Bds] Failed to create Boot#### for a temporary boot - %r!\n", Status));
   1627       BootOption->Status = Status;
   1628       return ;
   1629     }
   1630   }
   1631 
   1632   //
   1633   // 2. Set BootCurrent
   1634   //
   1635   Uint16 = (UINT16) OptionNumber;
   1636   BmSetVariableAndReportStatusCodeOnError (
   1637     L"BootCurrent",
   1638     &gEfiGlobalVariableGuid,
   1639     EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
   1640     sizeof (UINT16),
   1641     &Uint16
   1642     );
   1643 
   1644   //
   1645   // 3. Signal the EVT_SIGNAL_READY_TO_BOOT event when we are about to load and execute
   1646   //    the boot option.
   1647   //
   1648   if (BmIsBootManagerMenuFilePath (BootOption->FilePath)) {
   1649     DEBUG ((EFI_D_INFO, "[Bds] Booting Boot Manager Menu.\n"));
   1650     BmStopHotkeyService (NULL, NULL);
   1651   } else {
   1652     EfiSignalEventReadyToBoot();
   1653     //
   1654     // Report Status Code to indicate ReadyToBoot was signalled
   1655     //
   1656     REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT));
   1657     //
   1658     // 4. Repair system through DriverHealth protocol
   1659     //
   1660     BmRepairAllControllers ();
   1661   }
   1662 
   1663   PERF_START_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32) OptionNumber);
   1664 
   1665   //
   1666   // 5. Adjust the different type memory page number just before booting
   1667   //    and save the updated info into the variable for next boot to use
   1668   //
   1669   BmSetMemoryTypeInformationVariable (
   1670     (BOOLEAN) ((BootOption->Attributes & LOAD_OPTION_CATEGORY) == LOAD_OPTION_CATEGORY_BOOT)
   1671   );
   1672 
   1673   //
   1674   // 6. Load EFI boot option to ImageHandle
   1675   //
   1676   DEBUG_CODE_BEGIN ();
   1677   if (BootOption->Description == NULL) {
   1678     DEBUG ((DEBUG_INFO | DEBUG_LOAD, "[Bds]Booting from unknown device path\n"));
   1679   } else {
   1680     DEBUG ((DEBUG_INFO | DEBUG_LOAD, "[Bds]Booting %s\n", BootOption->Description));
   1681   }
   1682   DEBUG_CODE_END ();
   1683 
   1684   ImageHandle       = NULL;
   1685   RamDiskDevicePath = NULL;
   1686   if (DevicePathType (BootOption->FilePath) != BBS_DEVICE_PATH) {
   1687     Status     = EFI_NOT_FOUND;
   1688     FileBuffer = EfiBootManagerGetLoadOptionBuffer (BootOption->FilePath, &FilePath, &FileSize);
   1689     if (FileBuffer != NULL) {
   1690       RamDiskDevicePath = BmGetRamDiskDevicePath (FilePath);
   1691     }
   1692     DEBUG_CODE (
   1693       if (FileBuffer != NULL && CompareMem (BootOption->FilePath, FilePath, GetDevicePathSize (FilePath)) != 0) {
   1694         DEBUG ((EFI_D_INFO, "[Bds] DevicePath expand: "));
   1695         BmPrintDp (BootOption->FilePath);
   1696         DEBUG ((EFI_D_INFO, " -> "));
   1697         BmPrintDp (FilePath);
   1698         DEBUG ((EFI_D_INFO, "\n"));
   1699       }
   1700     );
   1701     if (BmIsLoadOptionPeHeaderValid (BootOption->OptionType, FileBuffer, FileSize)) {
   1702       REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderLoad));
   1703       Status = gBS->LoadImage (
   1704                       TRUE,
   1705                       gImageHandle,
   1706                       FilePath,
   1707                       FileBuffer,
   1708                       FileSize,
   1709                       &ImageHandle
   1710                       );
   1711     }
   1712     if (FileBuffer != NULL) {
   1713       FreePool (FileBuffer);
   1714     }
   1715     if (FilePath != NULL) {
   1716       FreePool (FilePath);
   1717     }
   1718 
   1719     if (EFI_ERROR (Status)) {
   1720       //
   1721       // Report Status Code to indicate that the failure to load boot option
   1722       //
   1723       REPORT_STATUS_CODE (
   1724         EFI_ERROR_CODE | EFI_ERROR_MINOR,
   1725         (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR)
   1726         );
   1727       BootOption->Status = Status;
   1728       //
   1729       // Destroy the RAM disk
   1730       //
   1731       if (RamDiskDevicePath != NULL) {
   1732         BmDestroyRamDisk (RamDiskDevicePath);
   1733         FreePool (RamDiskDevicePath);
   1734       }
   1735       return;
   1736     }
   1737   }
   1738 
   1739   //
   1740   // Check to see if we should legacy BOOT. If yes then do the legacy boot
   1741   // Write boot to OS performance data for Legacy boot
   1742   //
   1743   if ((DevicePathType (BootOption->FilePath) == BBS_DEVICE_PATH) && (DevicePathSubType (BootOption->FilePath) == BBS_BBS_DP)) {
   1744     if (mBmLegacyBoot != NULL) {
   1745       //
   1746       // Write boot to OS performance data for legacy boot.
   1747       //
   1748       PERF_CODE (
   1749         //
   1750         // Create an event to be signalled when Legacy Boot occurs to write performance data.
   1751         //
   1752         Status = EfiCreateEventLegacyBootEx(
   1753                    TPL_NOTIFY,
   1754                    BmWriteBootToOsPerformanceData,
   1755                    NULL,
   1756                    &LegacyBootEvent
   1757                    );
   1758         ASSERT_EFI_ERROR (Status);
   1759       );
   1760 
   1761       mBmLegacyBoot (BootOption);
   1762     } else {
   1763       BootOption->Status = EFI_UNSUPPORTED;
   1764     }
   1765 
   1766     PERF_END_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32) OptionNumber);
   1767     return;
   1768   }
   1769 
   1770   //
   1771   // Provide the image with its load options
   1772   //
   1773   Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);
   1774   ASSERT_EFI_ERROR (Status);
   1775 
   1776   if (!BmIsAutoCreateBootOption (BootOption)) {
   1777     ImageInfo->LoadOptionsSize = BootOption->OptionalDataSize;
   1778     ImageInfo->LoadOptions     = BootOption->OptionalData;
   1779   }
   1780 
   1781   //
   1782   // Clean to NULL because the image is loaded directly from the firmwares boot manager.
   1783   //
   1784   ImageInfo->ParentHandle = NULL;
   1785 
   1786   //
   1787   // Before calling the image, enable the Watchdog Timer for 5 minutes period
   1788   //
   1789   gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);
   1790 
   1791   //
   1792   // Write boot to OS performance data for UEFI boot
   1793   //
   1794   PERF_CODE (
   1795     BmWriteBootToOsPerformanceData (NULL, NULL);
   1796   );
   1797 
   1798   REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderStart));
   1799 
   1800   Status = gBS->StartImage (ImageHandle, &BootOption->ExitDataSize, &BootOption->ExitData);
   1801   DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Image Return Status = %r\n", Status));
   1802   BootOption->Status = Status;
   1803   if (EFI_ERROR (Status)) {
   1804     //
   1805     // Report Status Code to indicate that boot failure
   1806     //
   1807     REPORT_STATUS_CODE (
   1808       EFI_ERROR_CODE | EFI_ERROR_MINOR,
   1809       (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED)
   1810       );
   1811   }
   1812   PERF_END_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32) OptionNumber);
   1813 
   1814   //
   1815   // Destroy the RAM disk
   1816   //
   1817   if (RamDiskDevicePath != NULL) {
   1818     BmDestroyRamDisk (RamDiskDevicePath);
   1819     FreePool (RamDiskDevicePath);
   1820   }
   1821 
   1822   //
   1823   // Clear the Watchdog Timer after the image returns
   1824   //
   1825   gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
   1826 
   1827   //
   1828   // Set Logo status invalid after trying one boot option
   1829   //
   1830   BootLogo = NULL;
   1831   Status = gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo);
   1832   if (!EFI_ERROR (Status) && (BootLogo != NULL)) {
   1833     Status = BootLogo->SetBootLogo (BootLogo, NULL, 0, 0, 0, 0);
   1834     ASSERT_EFI_ERROR (Status);
   1835   }
   1836 
   1837   //
   1838   // Clear Boot Current
   1839   //
   1840   Status = gRT->SetVariable (
   1841                   L"BootCurrent",
   1842                   &gEfiGlobalVariableGuid,
   1843                   0,
   1844                   0,
   1845                   NULL
   1846                   );
   1847   //
   1848   // Deleting variable with current variable implementation shouldn't fail.
   1849   // When BootXXXX (e.g.: BootManagerMenu) boots BootYYYY, exiting BootYYYY causes BootCurrent deleted,
   1850   // exiting BootXXXX causes deleting BootCurrent returns EFI_NOT_FOUND.
   1851   //
   1852   ASSERT (Status == EFI_SUCCESS || Status == EFI_NOT_FOUND);
   1853 }
   1854 
   1855 /**
   1856   Check whether there is a instance in BlockIoDevicePath, which contain multi device path
   1857   instances, has the same partition node with HardDriveDevicePath device path
   1858 
   1859   @param  BlockIoDevicePath      Multi device path instances which need to check
   1860   @param  HardDriveDevicePath    A device path which starts with a hard drive media
   1861                                  device path.
   1862 
   1863   @retval TRUE                   There is a matched device path instance.
   1864   @retval FALSE                  There is no matched device path instance.
   1865 
   1866 **/
   1867 BOOLEAN
   1868 BmMatchPartitionDevicePathNode (
   1869   IN  EFI_DEVICE_PATH_PROTOCOL   *BlockIoDevicePath,
   1870   IN  HARDDRIVE_DEVICE_PATH      *HardDriveDevicePath
   1871   )
   1872 {
   1873   HARDDRIVE_DEVICE_PATH     *Node;
   1874 
   1875   if ((BlockIoDevicePath == NULL) || (HardDriveDevicePath == NULL)) {
   1876     return FALSE;
   1877   }
   1878 
   1879   //
   1880   // find the partition device path node
   1881   //
   1882   while (!IsDevicePathEnd (BlockIoDevicePath)) {
   1883     if ((DevicePathType (BlockIoDevicePath) == MEDIA_DEVICE_PATH) &&
   1884         (DevicePathSubType (BlockIoDevicePath) == MEDIA_HARDDRIVE_DP)
   1885         ) {
   1886       break;
   1887     }
   1888 
   1889     BlockIoDevicePath = NextDevicePathNode (BlockIoDevicePath);
   1890   }
   1891 
   1892   if (IsDevicePathEnd (BlockIoDevicePath)) {
   1893     return FALSE;
   1894   }
   1895 
   1896   //
   1897   // See if the harddrive device path in blockio matches the orig Hard Drive Node
   1898   //
   1899   Node = (HARDDRIVE_DEVICE_PATH *) BlockIoDevicePath;
   1900 
   1901   //
   1902   // Match Signature and PartitionNumber.
   1903   // Unused bytes in Signature are initiaized with zeros.
   1904   //
   1905   return (BOOLEAN) (
   1906     (Node->PartitionNumber == HardDriveDevicePath->PartitionNumber) &&
   1907     (Node->MBRType == HardDriveDevicePath->MBRType) &&
   1908     (Node->SignatureType == HardDriveDevicePath->SignatureType) &&
   1909     (CompareMem (Node->Signature, HardDriveDevicePath->Signature, sizeof (Node->Signature)) == 0)
   1910     );
   1911 }
   1912 
   1913 /**
   1914   Emuerate all possible bootable medias in the following order:
   1915   1. Removable BlockIo            - The boot option only points to the removable media
   1916                                     device, like USB key, DVD, Floppy etc.
   1917   2. Fixed BlockIo                - The boot option only points to a Fixed blockIo device,
   1918                                     like HardDisk.
   1919   3. Non-BlockIo SimpleFileSystem - The boot option points to a device supporting
   1920                                     SimpleFileSystem Protocol, but not supporting BlockIo
   1921                                     protocol.
   1922   4. LoadFile                     - The boot option points to the media supporting
   1923                                     LoadFile protocol.
   1924   Reference: UEFI Spec chapter 3.3 Boot Option Variables Default Boot Behavior
   1925 
   1926   @param BootOptionCount   Return the boot option count which has been found.
   1927 
   1928   @retval   Pointer to the boot option array.
   1929 **/
   1930 EFI_BOOT_MANAGER_LOAD_OPTION *
   1931 BmEnumerateBootOptions (
   1932   UINTN                                 *BootOptionCount
   1933   )
   1934 {
   1935   EFI_STATUS                            Status;
   1936   EFI_BOOT_MANAGER_LOAD_OPTION          *BootOptions;
   1937   UINTN                                 HandleCount;
   1938   EFI_HANDLE                            *Handles;
   1939   EFI_BLOCK_IO_PROTOCOL                 *BlkIo;
   1940   UINTN                                 Removable;
   1941   UINTN                                 Index;
   1942   CHAR16                                *Description;
   1943 
   1944   ASSERT (BootOptionCount != NULL);
   1945 
   1946   *BootOptionCount = 0;
   1947   BootOptions      = NULL;
   1948 
   1949   //
   1950   // Parse removable block io followed by fixed block io
   1951   //
   1952   gBS->LocateHandleBuffer (
   1953          ByProtocol,
   1954          &gEfiBlockIoProtocolGuid,
   1955          NULL,
   1956          &HandleCount,
   1957          &Handles
   1958          );
   1959 
   1960   for (Removable = 0; Removable < 2; Removable++) {
   1961     for (Index = 0; Index < HandleCount; Index++) {
   1962       Status = gBS->HandleProtocol (
   1963                       Handles[Index],
   1964                       &gEfiBlockIoProtocolGuid,
   1965                       (VOID **) &BlkIo
   1966                       );
   1967       if (EFI_ERROR (Status)) {
   1968         continue;
   1969       }
   1970 
   1971       //
   1972       // Skip the logical partitions
   1973       //
   1974       if (BlkIo->Media->LogicalPartition) {
   1975         continue;
   1976       }
   1977 
   1978       //
   1979       // Skip the fixed block io then the removable block io
   1980       //
   1981       if (BlkIo->Media->RemovableMedia == ((Removable == 0) ? FALSE : TRUE)) {
   1982         continue;
   1983       }
   1984 
   1985       Description = BmGetBootDescription (Handles[Index]);
   1986       BootOptions = ReallocatePool (
   1987                       sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),
   1988                       sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),
   1989                       BootOptions
   1990                       );
   1991       ASSERT (BootOptions != NULL);
   1992 
   1993       Status = EfiBootManagerInitializeLoadOption (
   1994                  &BootOptions[(*BootOptionCount)++],
   1995                  LoadOptionNumberUnassigned,
   1996                  LoadOptionTypeBoot,
   1997                  LOAD_OPTION_ACTIVE,
   1998                  Description,
   1999                  DevicePathFromHandle (Handles[Index]),
   2000                  NULL,
   2001                  0
   2002                  );
   2003       ASSERT_EFI_ERROR (Status);
   2004 
   2005       FreePool (Description);
   2006     }
   2007   }
   2008 
   2009   if (HandleCount != 0) {
   2010     FreePool (Handles);
   2011   }
   2012 
   2013   //
   2014   // Parse simple file system not based on block io
   2015   //
   2016   gBS->LocateHandleBuffer (
   2017          ByProtocol,
   2018          &gEfiSimpleFileSystemProtocolGuid,
   2019          NULL,
   2020          &HandleCount,
   2021          &Handles
   2022          );
   2023   for (Index = 0; Index < HandleCount; Index++) {
   2024     Status = gBS->HandleProtocol (
   2025                     Handles[Index],
   2026                     &gEfiBlockIoProtocolGuid,
   2027                     (VOID **) &BlkIo
   2028                     );
   2029      if (!EFI_ERROR (Status)) {
   2030       //
   2031       //  Skip if the file system handle supports a BlkIo protocol, which we've handled in above
   2032       //
   2033       continue;
   2034     }
   2035     Description = BmGetBootDescription (Handles[Index]);
   2036     BootOptions = ReallocatePool (
   2037                     sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),
   2038                     sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),
   2039                     BootOptions
   2040                     );
   2041     ASSERT (BootOptions != NULL);
   2042 
   2043     Status = EfiBootManagerInitializeLoadOption (
   2044                &BootOptions[(*BootOptionCount)++],
   2045                LoadOptionNumberUnassigned,
   2046                LoadOptionTypeBoot,
   2047                LOAD_OPTION_ACTIVE,
   2048                Description,
   2049                DevicePathFromHandle (Handles[Index]),
   2050                NULL,
   2051                0
   2052                );
   2053     ASSERT_EFI_ERROR (Status);
   2054     FreePool (Description);
   2055   }
   2056 
   2057   if (HandleCount != 0) {
   2058     FreePool (Handles);
   2059   }
   2060 
   2061   //
   2062   // Parse load file protocol
   2063   //
   2064   gBS->LocateHandleBuffer (
   2065          ByProtocol,
   2066          &gEfiLoadFileProtocolGuid,
   2067          NULL,
   2068          &HandleCount,
   2069          &Handles
   2070          );
   2071   for (Index = 0; Index < HandleCount; Index++) {
   2072     //
   2073     // Ignore BootManagerMenu. its boot option will be created by EfiBootManagerGetBootManagerMenu().
   2074     //
   2075     if (BmIsBootManagerMenuFilePath (DevicePathFromHandle (Handles[Index]))) {
   2076       continue;
   2077     }
   2078 
   2079     Description = BmGetBootDescription (Handles[Index]);
   2080     BootOptions = ReallocatePool (
   2081                     sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),
   2082                     sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),
   2083                     BootOptions
   2084                     );
   2085     ASSERT (BootOptions != NULL);
   2086 
   2087     Status = EfiBootManagerInitializeLoadOption (
   2088                &BootOptions[(*BootOptionCount)++],
   2089                LoadOptionNumberUnassigned,
   2090                LoadOptionTypeBoot,
   2091                LOAD_OPTION_ACTIVE,
   2092                Description,
   2093                DevicePathFromHandle (Handles[Index]),
   2094                NULL,
   2095                0
   2096                );
   2097     ASSERT_EFI_ERROR (Status);
   2098     FreePool (Description);
   2099   }
   2100 
   2101   if (HandleCount != 0) {
   2102     FreePool (Handles);
   2103   }
   2104 
   2105   BmMakeBootOptionDescriptionUnique (BootOptions, *BootOptionCount);
   2106   return BootOptions;
   2107 }
   2108 
   2109 /**
   2110   The function enumerates all boot options, creates them and registers them in the BootOrder variable.
   2111 **/
   2112 VOID
   2113 EFIAPI
   2114 EfiBootManagerRefreshAllBootOption (
   2115   VOID
   2116   )
   2117 {
   2118   EFI_STATUS                    Status;
   2119   EFI_BOOT_MANAGER_LOAD_OPTION  *NvBootOptions;
   2120   UINTN                         NvBootOptionCount;
   2121   EFI_BOOT_MANAGER_LOAD_OPTION  *BootOptions;
   2122   UINTN                         BootOptionCount;
   2123   UINTN                         Index;
   2124 
   2125   //
   2126   // Optionally refresh the legacy boot option
   2127   //
   2128   if (mBmRefreshLegacyBootOption != NULL) {
   2129     mBmRefreshLegacyBootOption ();
   2130   }
   2131 
   2132   BootOptions   = BmEnumerateBootOptions (&BootOptionCount);
   2133   NvBootOptions = EfiBootManagerGetLoadOptions (&NvBootOptionCount, LoadOptionTypeBoot);
   2134 
   2135   //
   2136   // Mark the boot option as added by BDS by setting OptionalData to a special GUID
   2137   //
   2138   for (Index = 0; Index < BootOptionCount; Index++) {
   2139     BootOptions[Index].OptionalData     = AllocateCopyPool (sizeof (EFI_GUID), &mBmAutoCreateBootOptionGuid);
   2140     BootOptions[Index].OptionalDataSize = sizeof (EFI_GUID);
   2141   }
   2142 
   2143   //
   2144   // Remove invalid EFI boot options from NV
   2145   //
   2146   for (Index = 0; Index < NvBootOptionCount; Index++) {
   2147     if (((DevicePathType (NvBootOptions[Index].FilePath) != BBS_DEVICE_PATH) ||
   2148          (DevicePathSubType (NvBootOptions[Index].FilePath) != BBS_BBS_DP)
   2149         ) && BmIsAutoCreateBootOption (&NvBootOptions[Index])
   2150        ) {
   2151       //
   2152       // Only check those added by BDS
   2153       // so that the boot options added by end-user or OS installer won't be deleted
   2154       //
   2155       if (EfiBootManagerFindLoadOption (&NvBootOptions[Index], BootOptions, BootOptionCount) == (UINTN) -1) {
   2156         Status = EfiBootManagerDeleteLoadOptionVariable (NvBootOptions[Index].OptionNumber, LoadOptionTypeBoot);
   2157         //
   2158         // Deleting variable with current variable implementation shouldn't fail.
   2159         //
   2160         ASSERT_EFI_ERROR (Status);
   2161       }
   2162     }
   2163   }
   2164 
   2165   //
   2166   // Add new EFI boot options to NV
   2167   //
   2168   for (Index = 0; Index < BootOptionCount; Index++) {
   2169     if (EfiBootManagerFindLoadOption (&BootOptions[Index], NvBootOptions, NvBootOptionCount) == (UINTN) -1) {
   2170       EfiBootManagerAddLoadOptionVariable (&BootOptions[Index], (UINTN) -1);
   2171       //
   2172       // Try best to add the boot options so continue upon failure.
   2173       //
   2174     }
   2175   }
   2176 
   2177   EfiBootManagerFreeLoadOptions (BootOptions,   BootOptionCount);
   2178   EfiBootManagerFreeLoadOptions (NvBootOptions, NvBootOptionCount);
   2179 }
   2180 
   2181 /**
   2182   This function is called to get or create the boot option for the Boot Manager Menu.
   2183 
   2184   The Boot Manager Menu is shown after successfully booting a boot option.
   2185   Assume the BootManagerMenuFile is in the same FV as the module links to this library.
   2186 
   2187   @param  BootOption    Return the boot option of the Boot Manager Menu
   2188 
   2189   @retval EFI_SUCCESS   Successfully register the Boot Manager Menu.
   2190   @retval EFI_NOT_FOUND The Boot Manager Menu cannot be found.
   2191   @retval others        Return status of gRT->SetVariable (). BootOption still points
   2192                         to the Boot Manager Menu even the Status is not EFI_SUCCESS
   2193                         and EFI_NOT_FOUND.
   2194 **/
   2195 EFI_STATUS
   2196 BmRegisterBootManagerMenu (
   2197   OUT EFI_BOOT_MANAGER_LOAD_OPTION   *BootOption
   2198   )
   2199 {
   2200   EFI_STATUS                         Status;
   2201   CHAR16                             *Description;
   2202   UINTN                              DescriptionLength;
   2203   EFI_DEVICE_PATH_PROTOCOL           *DevicePath;
   2204   EFI_LOADED_IMAGE_PROTOCOL          *LoadedImage;
   2205   MEDIA_FW_VOL_FILEPATH_DEVICE_PATH  FileNode;
   2206   UINTN                              HandleCount;
   2207   EFI_HANDLE                         *Handles;
   2208   UINTN                              Index;
   2209   VOID                               *Data;
   2210   UINTN                              DataSize;
   2211 
   2212   DevicePath = NULL;
   2213   Description = NULL;
   2214   //
   2215   // Try to find BootManagerMenu from LoadFile protocol
   2216   //
   2217   gBS->LocateHandleBuffer (
   2218          ByProtocol,
   2219          &gEfiLoadFileProtocolGuid,
   2220          NULL,
   2221          &HandleCount,
   2222          &Handles
   2223          );
   2224   for (Index = 0; Index < HandleCount; Index++) {
   2225     if (BmIsBootManagerMenuFilePath (DevicePathFromHandle (Handles[Index]))) {
   2226       DevicePath  = DuplicateDevicePath (DevicePathFromHandle (Handles[Index]));
   2227       Description = BmGetBootDescription (Handles[Index]);
   2228       break;
   2229     }
   2230   }
   2231   if (HandleCount != 0) {
   2232     FreePool (Handles);
   2233   }
   2234 
   2235   if (DevicePath == NULL) {
   2236     Data = NULL;
   2237     Status = GetSectionFromFv (
   2238                PcdGetPtr (PcdBootManagerMenuFile),
   2239                EFI_SECTION_PE32,
   2240                0,
   2241                (VOID **) &Data,
   2242                &DataSize
   2243                );
   2244     if (Data != NULL) {
   2245       FreePool (Data);
   2246     }
   2247     if (EFI_ERROR (Status)) {
   2248       DEBUG ((EFI_D_WARN, "[Bds]BootManagerMenu FFS section can not be found, skip its boot option registration\n"));
   2249       return EFI_NOT_FOUND;
   2250     }
   2251 
   2252     //
   2253     // Get BootManagerMenu application's description from EFI User Interface Section.
   2254     //
   2255     Status = GetSectionFromFv (
   2256                PcdGetPtr (PcdBootManagerMenuFile),
   2257                EFI_SECTION_USER_INTERFACE,
   2258                0,
   2259                (VOID **) &Description,
   2260                &DescriptionLength
   2261                );
   2262     if (EFI_ERROR (Status)) {
   2263       Description = NULL;
   2264     }
   2265 
   2266     EfiInitializeFwVolDevicepathNode (&FileNode, PcdGetPtr (PcdBootManagerMenuFile));
   2267     Status = gBS->HandleProtocol (
   2268                     gImageHandle,
   2269                     &gEfiLoadedImageProtocolGuid,
   2270                     (VOID **) &LoadedImage
   2271                     );
   2272     ASSERT_EFI_ERROR (Status);
   2273     DevicePath = AppendDevicePathNode (
   2274                    DevicePathFromHandle (LoadedImage->DeviceHandle),
   2275                    (EFI_DEVICE_PATH_PROTOCOL *) &FileNode
   2276                    );
   2277     ASSERT (DevicePath != NULL);
   2278   }
   2279 
   2280   Status = EfiBootManagerInitializeLoadOption (
   2281              BootOption,
   2282              LoadOptionNumberUnassigned,
   2283              LoadOptionTypeBoot,
   2284              LOAD_OPTION_CATEGORY_APP | LOAD_OPTION_ACTIVE | LOAD_OPTION_HIDDEN,
   2285              (Description != NULL) ? Description : L"Boot Manager Menu",
   2286              DevicePath,
   2287              NULL,
   2288              0
   2289              );
   2290   ASSERT_EFI_ERROR (Status);
   2291   FreePool (DevicePath);
   2292   if (Description != NULL) {
   2293     FreePool (Description);
   2294   }
   2295 
   2296   DEBUG_CODE (
   2297     EFI_BOOT_MANAGER_LOAD_OPTION    *BootOptions;
   2298     UINTN                           BootOptionCount;
   2299 
   2300     BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
   2301     ASSERT (EfiBootManagerFindLoadOption (BootOption, BootOptions, BootOptionCount) == -1);
   2302     EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
   2303     );
   2304 
   2305   return EfiBootManagerAddLoadOptionVariable (BootOption, 0);
   2306 }
   2307 
   2308 /**
   2309   Return the boot option corresponding to the Boot Manager Menu.
   2310   It may automatically create one if the boot option hasn't been created yet.
   2311 
   2312   @param BootOption    Return the Boot Manager Menu.
   2313 
   2314   @retval EFI_SUCCESS   The Boot Manager Menu is successfully returned.
   2315   @retval EFI_NOT_FOUND The Boot Manager Menu cannot be found.
   2316   @retval others        Return status of gRT->SetVariable (). BootOption still points
   2317                         to the Boot Manager Menu even the Status is not EFI_SUCCESS
   2318                         and EFI_NOT_FOUND.
   2319 **/
   2320 EFI_STATUS
   2321 EFIAPI
   2322 EfiBootManagerGetBootManagerMenu (
   2323   EFI_BOOT_MANAGER_LOAD_OPTION *BootOption
   2324   )
   2325 {
   2326   EFI_STATUS                   Status;
   2327   UINTN                        BootOptionCount;
   2328   EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
   2329   UINTN                        Index;
   2330 
   2331   BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
   2332 
   2333   for (Index = 0; Index < BootOptionCount; Index++) {
   2334     if (BmIsBootManagerMenuFilePath (BootOptions[Index].FilePath)) {
   2335         Status = EfiBootManagerInitializeLoadOption (
   2336                    BootOption,
   2337                    BootOptions[Index].OptionNumber,
   2338                    BootOptions[Index].OptionType,
   2339                    BootOptions[Index].Attributes,
   2340                    BootOptions[Index].Description,
   2341                    BootOptions[Index].FilePath,
   2342                    BootOptions[Index].OptionalData,
   2343                    BootOptions[Index].OptionalDataSize
   2344                    );
   2345         ASSERT_EFI_ERROR (Status);
   2346         break;
   2347     }
   2348   }
   2349 
   2350   EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
   2351 
   2352   //
   2353   // Automatically create the Boot#### for Boot Manager Menu when not found.
   2354   //
   2355   if (Index == BootOptionCount) {
   2356     return BmRegisterBootManagerMenu (BootOption);
   2357   } else {
   2358     return EFI_SUCCESS;
   2359   }
   2360 }
   2361 
   2362