]> git.proxmox.com Git - mirror_edk2.git/commitdiff
MdeModulePkg: Fix EOL to be DOS format.
authorRuiyu Ni <ruiyu.ni@intel.com>
Wed, 13 May 2015 02:23:44 +0000 (02:23 +0000)
committerniruiyu <niruiyu@Edk2>
Wed, 13 May 2015 02:23:44 +0000 (02:23 +0000)
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Ruiyu Ni <ruiyu.ni@intel.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@17421 6f19259b-4bc3-4df7-8a09-765794883524

12 files changed:
MdeModulePkg/Include/Library/UefiBootManagerLib.h
MdeModulePkg/Library/BaseSortLib/BaseSortLib.inf
MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c
MdeModulePkg/Library/UefiBootManagerLib/BmConnect.c
MdeModulePkg/Library/UefiBootManagerLib/BmConsole.c
MdeModulePkg/Library/UefiBootManagerLib/BmDriverHealth.c
MdeModulePkg/Library/UefiBootManagerLib/BmHotkey.c
MdeModulePkg/Library/UefiBootManagerLib/BmLoadOption.c
MdeModulePkg/Library/UefiBootManagerLib/BmMisc.c
MdeModulePkg/Library/UefiBootManagerLib/BmPerformance.c
MdeModulePkg/Library/UefiBootManagerLib/InternalBm.h
MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf

index 2ec80894adc65d531ba7dd8962a73932d74a6748..886229ed9e3cea1c741f4878ee9420b0c04bbb3b 100644 (file)
-/** @file
-  Provide Boot Manager related library APIs.
-
-Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
-This program and the accompanying materials
-are licensed and made available under the terms and conditions of the BSD License
-which accompanies this distribution.  The full text of the license may be found at
-http://opensource.org/licenses/bsd-license.php
-
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
-
-**/
-
-
-#ifndef _UEFI_BOOT_MANAGER_LIB_H_
-#define _UEFI_BOOT_MANAGER_LIB_H_
-
-#include <Protocol/DriverHealth.h>
-#include <Library/SortLib.h>
-
-//
-// Boot Manager load option library functions.
-//
-
-//
-// Load Option Type
-//
-typedef enum {
-  LoadOptionTypeDriver,
-  LoadOptionTypeSysPrep,
-  LoadOptionTypeBoot,
-  LoadOptionTypeMax
-} EFI_BOOT_MANAGER_LOAD_OPTION_TYPE;
-
-typedef enum {
-  LoadOptionNumberMax = 0x10000,
-  LoadOptionNumberUnassigned = LoadOptionNumberMax
-} EFI_BOOT_MANAGER_LOAD_OPTION_NUMBER;
-
-//
-// Common structure definition for DriverOption and BootOption
-//
-typedef struct {
-  //
-  // Data read from UEFI NV variables
-  //
-  UINTN                             OptionNumber;       // #### numerical value, could be LoadOptionNumberUnassigned
-  EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType;         // LoadOptionTypeBoot or LoadOptionTypeDriver
-  UINT32                            Attributes;         // Load Option Attributes
-  CHAR16                            *Description;       // Load Option Description
-  EFI_DEVICE_PATH_PROTOCOL          *FilePath;          // Load Option Device Path
-  UINT8                             *OptionalData;      // Load Option optional data to pass into image
-  UINT32                            OptionalDataSize;   // Load Option size of OptionalData
-  EFI_GUID                          VendorGuid;
-
-  //
-  // Used at runtime
-  //
-  EFI_STATUS                        Status;             // Status returned from boot attempt gBS->StartImage ()
-  CHAR16                            *ExitData;          // Exit data returned from gBS->StartImage () 
-  UINTN                             ExitDataSize;       // Size of ExitData
-} EFI_BOOT_MANAGER_LOAD_OPTION;
-
-/**
-  Returns an array of load options based on the EFI variable
-  L"BootOrder"/L"DriverOrder" and the L"Boot####"/L"Driver####" variables impled by it.
-  #### is the hex value of the UINT16 in each BootOrder/DriverOrder entry. 
-
-  @param  LoadOptionCount   Returns number of entries in the array.
-  @param  LoadOptionType    The type of the load option.
-
-  @retval NULL  No load options exist.
-  @retval !NULL Array of load option entries.
-
-**/
-EFI_BOOT_MANAGER_LOAD_OPTION *
-EFIAPI
-EfiBootManagerGetLoadOptions (
-  OUT UINTN                            *LoadOptionCount,
-  IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType
-  );
-
-/**
-  Free an array of load options returned from EfiBootManagerGetLoadOptions().
-
-  @param  LoadOptions      Pointer to the array of load options to free.
-  @param  LoadOptionCount  Number of array entries in LoadOptions.
-
-  @return EFI_SUCCESS           LoadOptions was freed.
-  @return EFI_INVALID_PARAMETER LoadOptions is NULL.
-**/
-EFI_STATUS
-EFIAPI
-EfiBootManagerFreeLoadOptions (
-  IN  EFI_BOOT_MANAGER_LOAD_OPTION  *LoadOptions,
-  IN  UINTN                         LoadOptionCount
-  );
-
-/**
-  Initialize a load option.
-
-  @param Option           Pointer to the load option to be initialized.
-  @param OptionNumber     Option number of the load option.
-  @param OptionType       Type of the load option.
-  @param Attributes       Attributes of the load option.
-  @param Description      Description of the load option.
-  @param FilePath         Device path of the load option.
-  @param OptionalData     Optional data of the load option.
-  @param OptionalDataSize Size of the optional data of the load option.
-
-  @retval EFI_SUCCESS           The load option was initialized successfully.
-  @retval EFI_INVALID_PARAMETER Option, Description or FilePath is NULL.
-**/
-EFI_STATUS
-EFIAPI
-EfiBootManagerInitializeLoadOption (
-  IN OUT EFI_BOOT_MANAGER_LOAD_OPTION   *Option,
-  IN  UINTN                             OptionNumber,
-  IN  EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType,
-  IN  UINT32                            Attributes,
-  IN  CHAR16                            *Description,
-  IN  EFI_DEVICE_PATH_PROTOCOL          *FilePath,
-  IN  UINT8                             *OptionalData,
-  IN  UINT32                            OptionalDataSize
-  );
-
-/**
-  Free a load option created by EfiBootManagerInitializeLoadOption()
-  or EfiBootManagerVariableToLoadOption().
-
-  @param  LoadOption   Pointer to the load option to free.
-  CONCERN: Check Boot#### instead of BootOrder, optimize, spec clarify
-  @return EFI_SUCCESS           LoadOption was freed.
-  @return EFI_INVALID_PARAMETER LoadOption is NULL.
-
-**/
-EFI_STATUS
-EFIAPI
-EfiBootManagerFreeLoadOption (
-  IN  EFI_BOOT_MANAGER_LOAD_OPTION  *LoadOption
-  );
-
-/**
-  Initialize the load option from the VariableName.
-
-  @param  VariableName          EFI Variable name which could be Boot#### or
-                                Driver####
-  @param  LoadOption            Pointer to the load option to be initialized
-
-  @retval EFI_SUCCESS           The option was created
-  @retval EFI_INVALID_PARAMETER VariableName or LoadOption is NULL.
-  @retval EFI_NOT_FOUND         The variable specified by VariableName cannot be found.
-**/
-EFI_STATUS
-EFIAPI
-EfiBootManagerVariableToLoadOption (
-  IN CHAR16                           *VariableName,
-  IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *LoadOption
-  );
-
-/**
-  Create the Boot#### or Driver#### variable from the load option.
-  
-  @param  LoadOption      Pointer to the load option.
-
-  @retval EFI_SUCCESS     The variable was created.
-  @retval Others          Error status returned by RT->SetVariable.
-**/
-EFI_STATUS
-EFIAPI
-EfiBootManagerLoadOptionToVariable (
-  IN CONST EFI_BOOT_MANAGER_LOAD_OPTION     *LoadOption
-  );
-
-/**
-  This function will update the Boot####/Driver####/SysPrep#### and the 
-  BootOrder/DriverOrder/SysPrepOrder to add a new load option.
-
-  @param  Option        Pointer to load option to add.
-  @param  Position      Position of the new load option to put in the BootOrder/DriverOrder/SysPrepOrder.
-
-  @retval EFI_SUCCESS   The load option has been successfully added.
-  @retval Others        Error status returned by RT->SetVariable.
-**/
-EFI_STATUS
-EFIAPI
-EfiBootManagerAddLoadOptionVariable (
-  IN EFI_BOOT_MANAGER_LOAD_OPTION  *Option,
-  IN UINTN                         Position
-  );
-
-/**
-  Delete the load option according to the OptionNumber and OptionType.
-  
-  Only the BootOrder/DriverOrder is updated to remove the reference of the OptionNumber.
-  
-  @param  OptionNumber        Option number of the load option.
-  @param  OptionType          Type of the load option.
-
-  @retval EFI_NOT_FOUND       The load option cannot be found.
-  @retval EFI_SUCCESS         The load option was deleted.
-**/
-EFI_STATUS
-EFIAPI
-EfiBootManagerDeleteLoadOptionVariable (
-  IN UINTN                              OptionNumber,
-  IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE  OptionType
-  );
-
-/**
-  Sort the load options. The DriverOrder/BootOrder variables will be re-created to 
-  reflect the new order.
-
-  @param OptionType        The type of the load option.
-  @param Comparator        The comparator function pointer.
-**/
-VOID
-EFIAPI
-EfiBootManagerSortLoadOptionVariable (
-  IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType,
-  IN SORT_COMPARE                      CompareFunction
-  );
-
-//
-// Boot Manager hot key library functions.
-//
-
-#pragma pack(1)
-///
-/// EFI Key Option.
-///
-typedef struct {
-  ///
-  /// Specifies options about how the key will be processed.
-  ///
-  EFI_BOOT_KEY_DATA  KeyData;
-  ///
-  /// The CRC-32 which should match the CRC-32 of the entire EFI_LOAD_OPTION to
-  /// which BootOption refers. If the CRC-32s do not match this value, then this key
-  /// option is ignored.
-  ///
-  UINT32             BootOptionCrc;
-  ///
-  /// The Boot#### option which will be invoked if this key is pressed and the boot option
-  /// is active (LOAD_OPTION_ACTIVE is set).
-  ///
-  UINT16             BootOption;
-  ///
-  /// The key codes to compare against those returned by the
-  /// EFI_SIMPLE_TEXT_INPUT and EFI_SIMPLE_TEXT_INPUT_EX protocols.
-  /// The number of key codes (0-3) is specified by the EFI_KEY_CODE_COUNT field in KeyOptions.
-  ///
-  EFI_INPUT_KEY      Keys[3];
-  UINT16             OptionNumber;
-} EFI_BOOT_MANAGER_KEY_OPTION;
-#pragma pack()
-
-/**
-  Start the hot key service so that the key press can trigger the boot option.
-
-  @param HotkeyTriggered  Return the waitable event and it will be signaled 
-                          when a valid hot key is pressed.
-
-  @retval EFI_SUCCESS     The hot key service is started.
-**/
-EFI_STATUS
-EFIAPI
-EfiBootManagerStartHotkeyService (
-  IN EFI_EVENT      *HotkeyTriggered
-  );
-
-//
-// Modifier for EfiBootManagerAddKeyOptionVariable and EfiBootManagerDeleteKeyOptionVariable
-//
-#define EFI_BOOT_MANAGER_SHIFT_PRESSED    0x00000001
-#define EFI_BOOT_MANAGER_CONTROL_PRESSED  0x00000002
-#define EFI_BOOT_MANAGER_ALT_PRESSED      0x00000004
-#define EFI_BOOT_MANAGER_LOGO_PRESSED     0x00000008
-#define EFI_BOOT_MANAGER_MENU_KEY_PRESSED 0x00000010
-#define EFI_BOOT_MANAGER_SYS_REQ_PRESSED  0x00000020
-
-/**
-  Add the key option.
-  It adds the key option variable and the key option takes affect immediately.
-
-  @param AddedOption      Return the added key option.
-  @param BootOptionNumber The boot option number for the key option.
-  @param Modifier         Key shift state.
-  @param ...              Parameter list of pointer of EFI_INPUT_KEY.
-
-  @retval EFI_SUCCESS         The key option is added.
-  @retval EFI_ALREADY_STARTED The hot key is already used by certain key option.
-**/
-EFI_STATUS
-EFIAPI
-EfiBootManagerAddKeyOptionVariable (
-  OUT EFI_BOOT_MANAGER_KEY_OPTION *AddedOption,   OPTIONAL
-  IN UINT16                       BootOptionNumber,
-  IN UINT32                       Modifier,
-  ...
-  );
-
-/**
-  Delete the Key Option variable and unregister the hot key
-
-  @param DeletedOption  Return the deleted key options.
-  @param Modifier       Key shift state.
-  @param ...            Parameter list of pointer of EFI_INPUT_KEY.
-
-  @retval EFI_SUCCESS   The key option is deleted.
-  @retval EFI_NOT_FOUND The key option cannot be found.
-**/
-EFI_STATUS
-EFIAPI
-EfiBootManagerDeleteKeyOptionVariable (
-  IN EFI_BOOT_MANAGER_KEY_OPTION *DeletedOption, OPTIONAL
-  IN UINT32                      Modifier,
-  ...
-  );
-
-/**
-  Register the key option to exit the waiting of the Boot Manager timeout.
-  Platform should ensure that the continue key option isn't conflict with
-  other boot key options.
-
-  @param Modifier     Key shift state.
-  @param  ...         Parameter list of pointer of EFI_INPUT_KEY.
-
-  @retval EFI_SUCCESS         Successfully register the continue key option.
-  @retval EFI_ALREADY_STARTED The continue key option is already registered.
-**/
-EFI_STATUS
-EFIAPI
-EfiBootManagerRegisterContinueKeyOption (
-  IN UINT32           Modifier,
-  ...
-  );
-
-/**
-  Try to boot the boot option triggered by hot key.
-**/
-VOID
-EFIAPI
-EfiBootManagerHotkeyBoot (
-  VOID
-  );
-//
-// Boot Manager boot library functions.
-//
-
-/**
-  The function creates boot options for all possible bootable medias in the following order:
-  1. Removable BlockIo            - The boot option only points to the removable media
-                                    device, like USB key, DVD, Floppy etc.
-  2. Fixed BlockIo                - The boot option only points to a Fixed blockIo device,
-                                    like HardDisk.
-  3. Non-BlockIo SimpleFileSystem - The boot option points to a device supporting
-                                    SimpleFileSystem Protocol, but not supporting BlockIo
-                                    protocol.
-  4. LoadFile                     - The boot option points to the media supporting 
-                                    LoadFile protocol.
-  Reference: UEFI Spec chapter 3.3 Boot Option Variables Default Boot Behavior
-
-  The function won't delete the boot option not added by itself.
-**/
-VOID
-EFIAPI
-EfiBootManagerRefreshAllBootOption (
-  VOID
-  );
-
-/**
-  Attempt to boot the EFI boot option. This routine sets L"BootCurent" and
-  signals the EFI ready to boot event. If the device path for the option starts
-  with a BBS device path a legacy boot is attempted. Short form device paths are
-  also supported via this rountine. A device path starting with 
-  MEDIA_HARDDRIVE_DP, MSG_USB_WWID_DP, MSG_USB_CLASS_DP gets expaned out
-  to find the first device that matches. If the BootOption Device Path 
-  fails the removable media boot algorithm is attempted (\EFI\BOOTIA32.EFI,
-  \EFI\BOOTX64.EFI,... only one file type is tried per processor type)
-
-  @param  BootOption    Boot Option to try and boot.
-                        On return, BootOption->Status contains the boot status:
-                        EFI_SUCCESS     BootOption was booted
-                        EFI_UNSUPPORTED BootOption isn't supported.
-                        EFI_NOT_FOUND   The BootOption was not found on the system
-                        Others          BootOption failed with this error status
-
-**/
-VOID
-EFIAPI
-EfiBootManagerBoot (
-  IN  EFI_BOOT_MANAGER_LOAD_OPTION  *BootOption
-  );
-
-/**
-  Return the Boot Manager Menu.
-  @param BootOption    Return the Boot Manager Menu.
-
-  @retval EFI_SUCCESS   The Boot Manager Menu is successfully returned.
-  @retval EFI_NOT_FOUND The Boot Manager Menu is not found.
-**/
-EFI_STATUS
-EFIAPI
-EfiBootManagerGetBootManagerMenu (
-  EFI_BOOT_MANAGER_LOAD_OPTION *BootOption
-  );
-
-/**
-  The function enumerates all the legacy boot options, creates them and 
-  registers them in the BootOrder variable.
-**/
-typedef
-VOID
-(EFIAPI *EFI_BOOT_MANAGER_REFRESH_LEGACY_BOOT_OPTION) (
-  VOID
-  );
-
-/**
-  The function boots a legacy boot option.
-**/
-typedef
-VOID
-(EFIAPI *EFI_BOOT_MANAGER_LEGACY_BOOT) (
-  IN  EFI_BOOT_MANAGER_LOAD_OPTION  *BootOption
-  );
-
-/**
-  The function registers the legacy boot support capabilities.
-
-  @param RefreshLegacyBootOption The function pointer to create all the legacy boot options.
-  @param LegacyBoot              The function pointer to boot the legacy boot option.
-**/
-VOID
-EFIAPI
-EfiBootManagerRegisterLegacyBootSupport (
-  EFI_BOOT_MANAGER_REFRESH_LEGACY_BOOT_OPTION   RefreshLegacyBootOption,
-  EFI_BOOT_MANAGER_LEGACY_BOOT                  LegacyBoot
-  );
-
-
-//
-// Boot Manager connect and disconnect library functions
-//
-
-/**
-  This function will connect all the system driver to controller
-  first, and then special connect the default console, this make
-  sure all the system controller available and the platform default
-  console connected.
-**/
-VOID
-EFIAPI
-EfiBootManagerConnectAll (
-  VOID
-  );
-
-/**
-  This function will create all handles associate with every device
-  path node. If the handle associate with one device path node can not
-  be created successfully, then still give chance to do the dispatch,
-  which load the missing drivers if possible.
-
-  @param  DevicePathToConnect   The device path which will be connected, it can be
-                                a multi-instance device path
-  @param  MatchingHandle        Return the controller handle closest to the DevicePathToConnect
-
-  @retval EFI_SUCCESS            All handles associate with every device path node
-                                 have been created.
-  @retval EFI_OUT_OF_RESOURCES   There is no resource to create new handles.
-  @retval EFI_NOT_FOUND          Create the handle associate with one device path
-                                 node failed.
-  @retval EFI_SECURITY_VIOLATION The user has no permission to start UEFI device 
-                                 drivers on the DevicePath.
-**/
-EFI_STATUS
-EFIAPI
-EfiBootManagerConnectDevicePath (
-  IN  EFI_DEVICE_PATH_PROTOCOL  *DevicePathToConnect,
-  OUT EFI_HANDLE                *MatchingHandle          OPTIONAL
-  );
-
-/**
-  This function will disconnect all current system handles. 
-  
-  gBS->DisconnectController() is invoked for each handle exists in system handle buffer.
-  If handle is a bus type handle, all childrens also are disconnected recursively by
-  gBS->DisconnectController().
-**/
-VOID
-EFIAPI
-EfiBootManagerDisconnectAll (
-  VOID
-  );
-
-
-//
-// Boot Manager console library functions
-//
-
-typedef enum {
-  ConIn,
-  ConOut,
-  ErrOut,
-  ConInDev,
-  ConOutDev,
-  ErrOutDev,
-  ConsoleTypeMax
-} CONSOLE_TYPE;
-
-/**
-  This function will connect all the console devices base on the console
-  device variable ConIn, ConOut and ErrOut.
-
-  @retval EFI_DEVICE_ERROR         All the consoles were not connected due to an error.
-  @retval EFI_SUCCESS              Success connect any one instance of the console
-                                   device path base on the variable ConVarName.
-**/
-EFI_STATUS
-EFIAPI
-EfiBootManagerConnectAllDefaultConsoles (
-  VOID
-  );
-
-/**
-  This function updates the console variable based on ConVarName. It can
-  add or remove one specific console device path from the variable
-
-  @param  ConsoleType              ConIn, ConOut, ErrOut, ConInDev, ConOutDev or ErrOutDev.
-  @param  CustomizedConDevicePath  The console device path to be added to
-                                   the console variable. Cannot be multi-instance.
-  @param  ExclusiveDevicePath      The console device path to be removed
-                                   from the console variable. Cannot be multi-instance.
-
-  @retval EFI_UNSUPPORTED          The added device path is the same as a removed one.
-  @retval EFI_SUCCESS              Successfully added or removed the device path from the
-                                   console variable.
-
-**/
-EFI_STATUS
-EFIAPI
-EfiBootManagerUpdateConsoleVariable (
-  IN  CONSOLE_TYPE              ConsoleType,
-  IN  EFI_DEVICE_PATH_PROTOCOL  *CustomizedConDevicePath,
-  IN  EFI_DEVICE_PATH_PROTOCOL  *ExclusiveDevicePath
-  );
-
-/**
-  Connect the console device base on the variable ConVarName, if
-  device path of the ConVarName is multi-instance device path, if
-  anyone of the instances is connected success, then this function
-  will return success.
-
-  @param  ConsoleType              ConIn, ConOut or ErrOut.
-
-  @retval EFI_NOT_FOUND            There is not any console devices connected
-                                   success
-  @retval EFI_SUCCESS              Success connect any one instance of the console
-                                   device path base on the variable ConVarName.
-
-**/
-EFI_STATUS
-EFIAPI
-EfiBootManagerConnectConsoleVariable (
-  IN  CONSOLE_TYPE              ConsoleType
-  );
-
-/**
-  Query all the children of VideoController and return the device paths of all the 
-  children that support GraphicsOutput protocol.
-
-  @param VideoController       PCI handle of video controller.
-
-  @return  Device paths of all the children that support GraphicsOutput protocol.
-**/
-EFI_DEVICE_PATH_PROTOCOL *
-EFIAPI
-EfiBootManagerGetGopDevicePath (
-  IN  EFI_HANDLE               VideoController
-  );
-
-/**
-  Connect the platform active active video controller.
-
-  @param VideoController       PCI handle of video controller.
-
-  @retval EFI_NOT_FOUND There is no active video controller.
-  @retval EFI_SUCCESS   The video controller is connected.
-**/
-EFI_STATUS
-EFIAPI
-EfiBootManagerConnectVideoController (
-  EFI_HANDLE                 VideoController  OPTIONAL
-  );
-
-//
-// Boot Manager driver health library functions.
-//
-
-typedef struct {
-  EFI_DRIVER_HEALTH_PROTOCOL      *DriverHealth;
-
-  ///
-  /// Driver relative handles
-  ///
-  EFI_HANDLE                      DriverHealthHandle;
-  EFI_HANDLE                      ControllerHandle;
-  EFI_HANDLE                      ChildHandle;
-
-  ///
-  /// Driver health messages of the specify Driver 
-  ///
-  EFI_DRIVER_HEALTH_HII_MESSAGE   *MessageList;
-
-  ///
-  /// HII relative handles
-  ///
-  EFI_HII_HANDLE                  HiiHandle;
-
-  ///
-  /// Driver Health status
-  ///
-  EFI_DRIVER_HEALTH_STATUS        HealthStatus;
-} EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO;
-
-/**
-  Return all the Driver Health information.
-
-  When the cumulative health status of all the controllers managed by the
-  driver who produces the EFI_DRIVER_HEALTH_PROTOCOL is healthy, only one
-  EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO entry is created for such
-  EFI_DRIVER_HEALTH_PROTOCOL instance.
-  Otherwise, every controller creates one EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO
-  entry. Additionally every child controller creates one
-  EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO entry if the driver is a bus driver.
-
-  @param Count      Return the count of the Driver Health information.
-
-  @retval NULL      No Driver Health information is returned.
-  @retval !NULL     Pointer to the Driver Health information array.
-**/
-EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO *
-EFIAPI
-EfiBootManagerGetDriverHealthInfo (
-  UINTN    *Count
-  );
-
-/**
-  Free the Driver Health information array.
-
-  @param DriverHealthInfo       Pointer to array of the Driver Health information.
-  @param Count                  Count of the array.
-
-  @retval EFI_SUCCESS           The array is freed.
-  @retval EFI_INVALID_PARAMETER The array is NULL.
-**/
-EFI_STATUS
-EFIAPI
-EfiBootManagerFreeDriverHealthInfo (
-  EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO  *DriverHealthInfo,
-  UINTN                                Count
-  );
-
-/**
-  Process (load and execute) the load option.
-
-  @param LoadOption  Pointer to the load option.
-
-  @retval EFI_INVALID_PARAMETER  The load option type is invalid, 
-                                 or the load option file path doesn't point to a valid file.
-  @retval EFI_UNSUPPORTED        The load option type is of LoadOptionTypeBoot.
-  @retval EFI_SUCCESS            The load option is inactive, or successfully loaded and executed.
-**/
-EFI_STATUS
-EFIAPI
-EfiBootManagerProcessLoadOption (
-  EFI_BOOT_MANAGER_LOAD_OPTION       *LoadOption
-  );
-#endif
+/** @file\r
+  Provide Boot Manager related library APIs.\r
+\r
+Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+\r
+#ifndef _UEFI_BOOT_MANAGER_LIB_H_\r
+#define _UEFI_BOOT_MANAGER_LIB_H_\r
+\r
+#include <Protocol/DriverHealth.h>\r
+#include <Library/SortLib.h>\r
+\r
+//\r
+// Boot Manager load option library functions.\r
+//\r
+\r
+//\r
+// Load Option Type\r
+//\r
+typedef enum {\r
+  LoadOptionTypeDriver,\r
+  LoadOptionTypeSysPrep,\r
+  LoadOptionTypeBoot,\r
+  LoadOptionTypeMax\r
+} EFI_BOOT_MANAGER_LOAD_OPTION_TYPE;\r
+\r
+typedef enum {\r
+  LoadOptionNumberMax = 0x10000,\r
+  LoadOptionNumberUnassigned = LoadOptionNumberMax\r
+} EFI_BOOT_MANAGER_LOAD_OPTION_NUMBER;\r
+\r
+//\r
+// Common structure definition for DriverOption and BootOption\r
+//\r
+typedef struct {\r
+  //\r
+  // Data read from UEFI NV variables\r
+  //\r
+  UINTN                             OptionNumber;       // #### numerical value, could be LoadOptionNumberUnassigned\r
+  EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType;         // LoadOptionTypeBoot or LoadOptionTypeDriver\r
+  UINT32                            Attributes;         // Load Option Attributes\r
+  CHAR16                            *Description;       // Load Option Description\r
+  EFI_DEVICE_PATH_PROTOCOL          *FilePath;          // Load Option Device Path\r
+  UINT8                             *OptionalData;      // Load Option optional data to pass into image\r
+  UINT32                            OptionalDataSize;   // Load Option size of OptionalData\r
+  EFI_GUID                          VendorGuid;\r
+\r
+  //\r
+  // Used at runtime\r
+  //\r
+  EFI_STATUS                        Status;             // Status returned from boot attempt gBS->StartImage ()\r
+  CHAR16                            *ExitData;          // Exit data returned from gBS->StartImage () \r
+  UINTN                             ExitDataSize;       // Size of ExitData\r
+} EFI_BOOT_MANAGER_LOAD_OPTION;\r
+\r
+/**\r
+  Returns an array of load options based on the EFI variable\r
+  L"BootOrder"/L"DriverOrder" and the L"Boot####"/L"Driver####" variables impled by it.\r
+  #### is the hex value of the UINT16 in each BootOrder/DriverOrder entry. \r
+\r
+  @param  LoadOptionCount   Returns number of entries in the array.\r
+  @param  LoadOptionType    The type of the load option.\r
+\r
+  @retval NULL  No load options exist.\r
+  @retval !NULL Array of load option entries.\r
+\r
+**/\r
+EFI_BOOT_MANAGER_LOAD_OPTION *\r
+EFIAPI\r
+EfiBootManagerGetLoadOptions (\r
+  OUT UINTN                            *LoadOptionCount,\r
+  IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType\r
+  );\r
+\r
+/**\r
+  Free an array of load options returned from EfiBootManagerGetLoadOptions().\r
+\r
+  @param  LoadOptions      Pointer to the array of load options to free.\r
+  @param  LoadOptionCount  Number of array entries in LoadOptions.\r
+\r
+  @return EFI_SUCCESS           LoadOptions was freed.\r
+  @return EFI_INVALID_PARAMETER LoadOptions is NULL.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiBootManagerFreeLoadOptions (\r
+  IN  EFI_BOOT_MANAGER_LOAD_OPTION  *LoadOptions,\r
+  IN  UINTN                         LoadOptionCount\r
+  );\r
+\r
+/**\r
+  Initialize a load option.\r
+\r
+  @param Option           Pointer to the load option to be initialized.\r
+  @param OptionNumber     Option number of the load option.\r
+  @param OptionType       Type of the load option.\r
+  @param Attributes       Attributes of the load option.\r
+  @param Description      Description of the load option.\r
+  @param FilePath         Device path of the load option.\r
+  @param OptionalData     Optional data of the load option.\r
+  @param OptionalDataSize Size of the optional data of the load option.\r
+\r
+  @retval EFI_SUCCESS           The load option was initialized successfully.\r
+  @retval EFI_INVALID_PARAMETER Option, Description or FilePath is NULL.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiBootManagerInitializeLoadOption (\r
+  IN OUT EFI_BOOT_MANAGER_LOAD_OPTION   *Option,\r
+  IN  UINTN                             OptionNumber,\r
+  IN  EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType,\r
+  IN  UINT32                            Attributes,\r
+  IN  CHAR16                            *Description,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL          *FilePath,\r
+  IN  UINT8                             *OptionalData,\r
+  IN  UINT32                            OptionalDataSize\r
+  );\r
+\r
+/**\r
+  Free a load option created by EfiBootManagerInitializeLoadOption()\r
+  or EfiBootManagerVariableToLoadOption().\r
+\r
+  @param  LoadOption   Pointer to the load option to free.\r
+  CONCERN: Check Boot#### instead of BootOrder, optimize, spec clarify\r
+  @return EFI_SUCCESS           LoadOption was freed.\r
+  @return EFI_INVALID_PARAMETER LoadOption is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiBootManagerFreeLoadOption (\r
+  IN  EFI_BOOT_MANAGER_LOAD_OPTION  *LoadOption\r
+  );\r
+\r
+/**\r
+  Initialize the load option from the VariableName.\r
+\r
+  @param  VariableName          EFI Variable name which could be Boot#### or\r
+                                Driver####\r
+  @param  LoadOption            Pointer to the load option to be initialized\r
+\r
+  @retval EFI_SUCCESS           The option was created\r
+  @retval EFI_INVALID_PARAMETER VariableName or LoadOption is NULL.\r
+  @retval EFI_NOT_FOUND         The variable specified by VariableName cannot be found.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiBootManagerVariableToLoadOption (\r
+  IN CHAR16                           *VariableName,\r
+  IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *LoadOption\r
+  );\r
+\r
+/**\r
+  Create the Boot#### or Driver#### variable from the load option.\r
+  \r
+  @param  LoadOption      Pointer to the load option.\r
+\r
+  @retval EFI_SUCCESS     The variable was created.\r
+  @retval Others          Error status returned by RT->SetVariable.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiBootManagerLoadOptionToVariable (\r
+  IN CONST EFI_BOOT_MANAGER_LOAD_OPTION     *LoadOption\r
+  );\r
+\r
+/**\r
+  This function will update the Boot####/Driver####/SysPrep#### and the \r
+  BootOrder/DriverOrder/SysPrepOrder to add a new load option.\r
+\r
+  @param  Option        Pointer to load option to add.\r
+  @param  Position      Position of the new load option to put in the BootOrder/DriverOrder/SysPrepOrder.\r
+\r
+  @retval EFI_SUCCESS   The load option has been successfully added.\r
+  @retval Others        Error status returned by RT->SetVariable.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiBootManagerAddLoadOptionVariable (\r
+  IN EFI_BOOT_MANAGER_LOAD_OPTION  *Option,\r
+  IN UINTN                         Position\r
+  );\r
+\r
+/**\r
+  Delete the load option according to the OptionNumber and OptionType.\r
+  \r
+  Only the BootOrder/DriverOrder is updated to remove the reference of the OptionNumber.\r
+  \r
+  @param  OptionNumber        Option number of the load option.\r
+  @param  OptionType          Type of the load option.\r
+\r
+  @retval EFI_NOT_FOUND       The load option cannot be found.\r
+  @retval EFI_SUCCESS         The load option was deleted.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiBootManagerDeleteLoadOptionVariable (\r
+  IN UINTN                              OptionNumber,\r
+  IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE  OptionType\r
+  );\r
+\r
+/**\r
+  Sort the load options. The DriverOrder/BootOrder variables will be re-created to \r
+  reflect the new order.\r
+\r
+  @param OptionType        The type of the load option.\r
+  @param Comparator        The comparator function pointer.\r
+**/\r
+VOID\r
+EFIAPI\r
+EfiBootManagerSortLoadOptionVariable (\r
+  IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType,\r
+  IN SORT_COMPARE                      CompareFunction\r
+  );\r
+\r
+//\r
+// Boot Manager hot key library functions.\r
+//\r
+\r
+#pragma pack(1)\r
+///\r
+/// EFI Key Option.\r
+///\r
+typedef struct {\r
+  ///\r
+  /// Specifies options about how the key will be processed.\r
+  ///\r
+  EFI_BOOT_KEY_DATA  KeyData;\r
+  ///\r
+  /// The CRC-32 which should match the CRC-32 of the entire EFI_LOAD_OPTION to\r
+  /// which BootOption refers. If the CRC-32s do not match this value, then this key\r
+  /// option is ignored.\r
+  ///\r
+  UINT32             BootOptionCrc;\r
+  ///\r
+  /// The Boot#### option which will be invoked if this key is pressed and the boot option\r
+  /// is active (LOAD_OPTION_ACTIVE is set).\r
+  ///\r
+  UINT16             BootOption;\r
+  ///\r
+  /// The key codes to compare against those returned by the\r
+  /// EFI_SIMPLE_TEXT_INPUT and EFI_SIMPLE_TEXT_INPUT_EX protocols.\r
+  /// The number of key codes (0-3) is specified by the EFI_KEY_CODE_COUNT field in KeyOptions.\r
+  ///\r
+  EFI_INPUT_KEY      Keys[3];\r
+  UINT16             OptionNumber;\r
+} EFI_BOOT_MANAGER_KEY_OPTION;\r
+#pragma pack()\r
+\r
+/**\r
+  Start the hot key service so that the key press can trigger the boot option.\r
+\r
+  @param HotkeyTriggered  Return the waitable event and it will be signaled \r
+                          when a valid hot key is pressed.\r
+\r
+  @retval EFI_SUCCESS     The hot key service is started.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiBootManagerStartHotkeyService (\r
+  IN EFI_EVENT      *HotkeyTriggered\r
+  );\r
+\r
+//\r
+// Modifier for EfiBootManagerAddKeyOptionVariable and EfiBootManagerDeleteKeyOptionVariable\r
+//\r
+#define EFI_BOOT_MANAGER_SHIFT_PRESSED    0x00000001\r
+#define EFI_BOOT_MANAGER_CONTROL_PRESSED  0x00000002\r
+#define EFI_BOOT_MANAGER_ALT_PRESSED      0x00000004\r
+#define EFI_BOOT_MANAGER_LOGO_PRESSED     0x00000008\r
+#define EFI_BOOT_MANAGER_MENU_KEY_PRESSED 0x00000010\r
+#define EFI_BOOT_MANAGER_SYS_REQ_PRESSED  0x00000020\r
+\r
+/**\r
+  Add the key option.\r
+  It adds the key option variable and the key option takes affect immediately.\r
+\r
+  @param AddedOption      Return the added key option.\r
+  @param BootOptionNumber The boot option number for the key option.\r
+  @param Modifier         Key shift state.\r
+  @param ...              Parameter list of pointer of EFI_INPUT_KEY.\r
+\r
+  @retval EFI_SUCCESS         The key option is added.\r
+  @retval EFI_ALREADY_STARTED The hot key is already used by certain key option.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiBootManagerAddKeyOptionVariable (\r
+  OUT EFI_BOOT_MANAGER_KEY_OPTION *AddedOption,   OPTIONAL\r
+  IN UINT16                       BootOptionNumber,\r
+  IN UINT32                       Modifier,\r
+  ...\r
+  );\r
+\r
+/**\r
+  Delete the Key Option variable and unregister the hot key\r
+\r
+  @param DeletedOption  Return the deleted key options.\r
+  @param Modifier       Key shift state.\r
+  @param ...            Parameter list of pointer of EFI_INPUT_KEY.\r
+\r
+  @retval EFI_SUCCESS   The key option is deleted.\r
+  @retval EFI_NOT_FOUND The key option cannot be found.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiBootManagerDeleteKeyOptionVariable (\r
+  IN EFI_BOOT_MANAGER_KEY_OPTION *DeletedOption, OPTIONAL\r
+  IN UINT32                      Modifier,\r
+  ...\r
+  );\r
+\r
+/**\r
+  Register the key option to exit the waiting of the Boot Manager timeout.\r
+  Platform should ensure that the continue key option isn't conflict with\r
+  other boot key options.\r
+\r
+  @param Modifier     Key shift state.\r
+  @param  ...         Parameter list of pointer of EFI_INPUT_KEY.\r
+\r
+  @retval EFI_SUCCESS         Successfully register the continue key option.\r
+  @retval EFI_ALREADY_STARTED The continue key option is already registered.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiBootManagerRegisterContinueKeyOption (\r
+  IN UINT32           Modifier,\r
+  ...\r
+  );\r
+\r
+/**\r
+  Try to boot the boot option triggered by hot key.\r
+**/\r
+VOID\r
+EFIAPI\r
+EfiBootManagerHotkeyBoot (\r
+  VOID\r
+  );\r
+//\r
+// Boot Manager boot library functions.\r
+//\r
+\r
+/**\r
+  The function creates boot options for all possible bootable medias in the following order:\r
+  1. Removable BlockIo            - The boot option only points to the removable media\r
+                                    device, like USB key, DVD, Floppy etc.\r
+  2. Fixed BlockIo                - The boot option only points to a Fixed blockIo device,\r
+                                    like HardDisk.\r
+  3. Non-BlockIo SimpleFileSystem - The boot option points to a device supporting\r
+                                    SimpleFileSystem Protocol, but not supporting BlockIo\r
+                                    protocol.\r
+  4. LoadFile                     - The boot option points to the media supporting \r
+                                    LoadFile protocol.\r
+  Reference: UEFI Spec chapter 3.3 Boot Option Variables Default Boot Behavior\r
+\r
+  The function won't delete the boot option not added by itself.\r
+**/\r
+VOID\r
+EFIAPI\r
+EfiBootManagerRefreshAllBootOption (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Attempt to boot the EFI boot option. This routine sets L"BootCurent" and\r
+  signals the EFI ready to boot event. If the device path for the option starts\r
+  with a BBS device path a legacy boot is attempted. Short form device paths are\r
+  also supported via this rountine. A device path starting with \r
+  MEDIA_HARDDRIVE_DP, MSG_USB_WWID_DP, MSG_USB_CLASS_DP gets expaned out\r
+  to find the first device that matches. If the BootOption Device Path \r
+  fails the removable media boot algorithm is attempted (\EFI\BOOTIA32.EFI,\r
+  \EFI\BOOTX64.EFI,... only one file type is tried per processor type)\r
+\r
+  @param  BootOption    Boot Option to try and boot.\r
+                        On return, BootOption->Status contains the boot status:\r
+                        EFI_SUCCESS     BootOption was booted\r
+                        EFI_UNSUPPORTED BootOption isn't supported.\r
+                        EFI_NOT_FOUND   The BootOption was not found on the system\r
+                        Others          BootOption failed with this error status\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+EfiBootManagerBoot (\r
+  IN  EFI_BOOT_MANAGER_LOAD_OPTION  *BootOption\r
+  );\r
+\r
+/**\r
+  Return the Boot Manager Menu.\r
\r
+  @param BootOption    Return the Boot Manager Menu.\r
+\r
+  @retval EFI_SUCCESS   The Boot Manager Menu is successfully returned.\r
+  @retval EFI_NOT_FOUND The Boot Manager Menu is not found.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiBootManagerGetBootManagerMenu (\r
+  EFI_BOOT_MANAGER_LOAD_OPTION *BootOption\r
+  );\r
+\r
+/**\r
+  The function enumerates all the legacy boot options, creates them and \r
+  registers them in the BootOrder variable.\r
+**/\r
+typedef\r
+VOID\r
+(EFIAPI *EFI_BOOT_MANAGER_REFRESH_LEGACY_BOOT_OPTION) (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  The function boots a legacy boot option.\r
+**/\r
+typedef\r
+VOID\r
+(EFIAPI *EFI_BOOT_MANAGER_LEGACY_BOOT) (\r
+  IN  EFI_BOOT_MANAGER_LOAD_OPTION  *BootOption\r
+  );\r
+\r
+/**\r
+  The function registers the legacy boot support capabilities.\r
+\r
+  @param RefreshLegacyBootOption The function pointer to create all the legacy boot options.\r
+  @param LegacyBoot              The function pointer to boot the legacy boot option.\r
+**/\r
+VOID\r
+EFIAPI\r
+EfiBootManagerRegisterLegacyBootSupport (\r
+  EFI_BOOT_MANAGER_REFRESH_LEGACY_BOOT_OPTION   RefreshLegacyBootOption,\r
+  EFI_BOOT_MANAGER_LEGACY_BOOT                  LegacyBoot\r
+  );\r
+\r
+\r
+//\r
+// Boot Manager connect and disconnect library functions\r
+//\r
+\r
+/**\r
+  This function will connect all the system driver to controller\r
+  first, and then special connect the default console, this make\r
+  sure all the system controller available and the platform default\r
+  console connected.\r
+**/\r
+VOID\r
+EFIAPI\r
+EfiBootManagerConnectAll (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  This function will create all handles associate with every device\r
+  path node. If the handle associate with one device path node can not\r
+  be created successfully, then still give chance to do the dispatch,\r
+  which load the missing drivers if possible.\r
+\r
+  @param  DevicePathToConnect   The device path which will be connected, it can be\r
+                                a multi-instance device path\r
+  @param  MatchingHandle        Return the controller handle closest to the DevicePathToConnect\r
+\r
+  @retval EFI_SUCCESS            All handles associate with every device path node\r
+                                 have been created.\r
+  @retval EFI_OUT_OF_RESOURCES   There is no resource to create new handles.\r
+  @retval EFI_NOT_FOUND          Create the handle associate with one device path\r
+                                 node failed.\r
+  @retval EFI_SECURITY_VIOLATION The user has no permission to start UEFI device \r
+                                 drivers on the DevicePath.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiBootManagerConnectDevicePath (\r
+  IN  EFI_DEVICE_PATH_PROTOCOL  *DevicePathToConnect,\r
+  OUT EFI_HANDLE                *MatchingHandle          OPTIONAL\r
+  );\r
+\r
+/**\r
+  This function will disconnect all current system handles. \r
+  \r
+  gBS->DisconnectController() is invoked for each handle exists in system handle buffer.\r
+  If handle is a bus type handle, all childrens also are disconnected recursively by\r
+  gBS->DisconnectController().\r
+**/\r
+VOID\r
+EFIAPI\r
+EfiBootManagerDisconnectAll (\r
+  VOID\r
+  );\r
+\r
+\r
+//\r
+// Boot Manager console library functions\r
+//\r
+\r
+typedef enum {\r
+  ConIn,\r
+  ConOut,\r
+  ErrOut,\r
+  ConInDev,\r
+  ConOutDev,\r
+  ErrOutDev,\r
+  ConsoleTypeMax\r
+} CONSOLE_TYPE;\r
+\r
+/**\r
+  This function will connect all the console devices base on the console\r
+  device variable ConIn, ConOut and ErrOut.\r
+\r
+  @retval EFI_DEVICE_ERROR         All the consoles were not connected due to an error.\r
+  @retval EFI_SUCCESS              Success connect any one instance of the console\r
+                                   device path base on the variable ConVarName.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiBootManagerConnectAllDefaultConsoles (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  This function updates the console variable based on ConVarName. It can\r
+  add or remove one specific console device path from the variable\r
+\r
+  @param  ConsoleType              ConIn, ConOut, ErrOut, ConInDev, ConOutDev or ErrOutDev.\r
+  @param  CustomizedConDevicePath  The console device path to be added to\r
+                                   the console variable. Cannot be multi-instance.\r
+  @param  ExclusiveDevicePath      The console device path to be removed\r
+                                   from the console variable. Cannot be multi-instance.\r
+\r
+  @retval EFI_UNSUPPORTED          The added device path is the same as a removed one.\r
+  @retval EFI_SUCCESS              Successfully added or removed the device path from the\r
+                                   console variable.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiBootManagerUpdateConsoleVariable (\r
+  IN  CONSOLE_TYPE              ConsoleType,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL  *CustomizedConDevicePath,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL  *ExclusiveDevicePath\r
+  );\r
+\r
+/**\r
+  Connect the console device base on the variable ConVarName, if\r
+  device path of the ConVarName is multi-instance device path, if\r
+  anyone of the instances is connected success, then this function\r
+  will return success.\r
+\r
+  @param  ConsoleType              ConIn, ConOut or ErrOut.\r
+\r
+  @retval EFI_NOT_FOUND            There is not any console devices connected\r
+                                   success\r
+  @retval EFI_SUCCESS              Success connect any one instance of the console\r
+                                   device path base on the variable ConVarName.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiBootManagerConnectConsoleVariable (\r
+  IN  CONSOLE_TYPE              ConsoleType\r
+  );\r
+\r
+/**\r
+  Query all the children of VideoController and return the device paths of all the \r
+  children that support GraphicsOutput protocol.\r
+\r
+  @param VideoController       PCI handle of video controller.\r
+\r
+  @return  Device paths of all the children that support GraphicsOutput protocol.\r
+**/\r
+EFI_DEVICE_PATH_PROTOCOL *\r
+EFIAPI\r
+EfiBootManagerGetGopDevicePath (\r
+  IN  EFI_HANDLE               VideoController\r
+  );\r
+\r
+/**\r
+  Connect the platform active active video controller.\r
+\r
+  @param VideoController       PCI handle of video controller.\r
+\r
+  @retval EFI_NOT_FOUND There is no active video controller.\r
+  @retval EFI_SUCCESS   The video controller is connected.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiBootManagerConnectVideoController (\r
+  EFI_HANDLE                 VideoController  OPTIONAL\r
+  );\r
+\r
+//\r
+// Boot Manager driver health library functions.\r
+//\r
+\r
+typedef struct {\r
+  EFI_DRIVER_HEALTH_PROTOCOL      *DriverHealth;\r
+\r
+  ///\r
+  /// Driver relative handles\r
+  ///\r
+  EFI_HANDLE                      DriverHealthHandle;\r
+  EFI_HANDLE                      ControllerHandle;\r
+  EFI_HANDLE                      ChildHandle;\r
+\r
+  ///\r
+  /// Driver health messages of the specify Driver \r
+  ///\r
+  EFI_DRIVER_HEALTH_HII_MESSAGE   *MessageList;\r
+\r
+  ///\r
+  /// HII relative handles\r
+  ///\r
+  EFI_HII_HANDLE                  HiiHandle;\r
+\r
+  ///\r
+  /// Driver Health status\r
+  ///\r
+  EFI_DRIVER_HEALTH_STATUS        HealthStatus;\r
+} EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO;\r
+\r
+/**\r
+  Return all the Driver Health information.\r
+\r
+  When the cumulative health status of all the controllers managed by the\r
+  driver who produces the EFI_DRIVER_HEALTH_PROTOCOL is healthy, only one\r
+  EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO entry is created for such\r
+  EFI_DRIVER_HEALTH_PROTOCOL instance.\r
+  Otherwise, every controller creates one EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO\r
+  entry. Additionally every child controller creates one\r
+  EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO entry if the driver is a bus driver.\r
+\r
+  @param Count      Return the count of the Driver Health information.\r
+\r
+  @retval NULL      No Driver Health information is returned.\r
+  @retval !NULL     Pointer to the Driver Health information array.\r
+**/\r
+EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO *\r
+EFIAPI\r
+EfiBootManagerGetDriverHealthInfo (\r
+  UINTN    *Count\r
+  );\r
+\r
+/**\r
+  Free the Driver Health information array.\r
+\r
+  @param DriverHealthInfo       Pointer to array of the Driver Health information.\r
+  @param Count                  Count of the array.\r
+\r
+  @retval EFI_SUCCESS           The array is freed.\r
+  @retval EFI_INVALID_PARAMETER The array is NULL.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiBootManagerFreeDriverHealthInfo (\r
+  EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO  *DriverHealthInfo,\r
+  UINTN                                Count\r
+  );\r
+\r
+/**\r
+  Process (load and execute) the load option.\r
+\r
+  @param LoadOption  Pointer to the load option.\r
+\r
+  @retval EFI_INVALID_PARAMETER  The load option type is invalid, \r
+                                 or the load option file path doesn't point to a valid file.\r
+  @retval EFI_UNSUPPORTED        The load option type is of LoadOptionTypeBoot.\r
+  @retval EFI_SUCCESS            The load option is inactive, or successfully loaded and executed.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiBootManagerProcessLoadOption (\r
+  EFI_BOOT_MANAGER_LOAD_OPTION       *LoadOption\r
+  );\r
+#endif\r
index e23b4d073b6da9561cf9501e2fdb42fa61d47cd2..9d3633b9b6d6ab28b7eab4858f36ce73c4bc5d96 100644 (file)
@@ -1,7 +1,7 @@
 ##  @file\r
 #   Library used for sorting routines.\r
 #\r
-#  Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved. <BR>
+#  Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved. <BR>\r
 #\r
 #  This program and the accompanying materials\r
 #  are licensed and made available under the terms and conditions of the BSD License\r
@@ -19,7 +19,7 @@
   FILE_GUID                      = 03F3331B-F12D-494f-BF37-E55A657F2497\r
   MODULE_TYPE                    = UEFI_DRIVER\r
   VERSION_STRING                 = 1.0\r
-  LIBRARY_CLASS                  = SortLib|DXE_DRIVER DXE_RUNTIME_DRIVER UEFI_APPLICATION UEFI_DRIVER
+  LIBRARY_CLASS                  = SortLib|DXE_DRIVER DXE_RUNTIME_DRIVER UEFI_APPLICATION UEFI_DRIVER\r
 \r
 #\r
 #  VALID_ARCHITECTURES           = IA32 X64 IPF EBC\r
@@ -37,5 +37,3 @@
   BaseLib\r
   BaseMemoryLib\r
   DebugLib\r
-\r
-\r
index ede5250851b3172f2dd59121a1c21100af2734cc..efac6d5bea65fdbf2a82556ef1fc71ea39a959ba 100644 (file)
-/** @file
-  Library functions which relates with booting.
-
-Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
-This program and the accompanying materials
-are licensed and made available under the terms and conditions of the BSD License
-which accompanies this distribution.  The full text of the license may be found at
-http://opensource.org/licenses/bsd-license.php
-
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
-
-**/
-
-#include "InternalBm.h"
-
-#define VENDOR_IDENTIFICATION_OFFSET     3
-#define VENDOR_IDENTIFICATION_LENGTH     8
-#define PRODUCT_IDENTIFICATION_OFFSET    11
-#define PRODUCT_IDENTIFICATION_LENGTH    16
-
-CONST UINT16 mBmUsbLangId    = 0x0409; // English
-CHAR16       mBmUefiPrefix[] = L"UEFI ";
-
-EFI_BOOT_MANAGER_REFRESH_LEGACY_BOOT_OPTION  mBmRefreshLegacyBootOption = NULL;
-EFI_BOOT_MANAGER_LEGACY_BOOT                 mBmLegacyBoot              = NULL;
-
-///
-/// This GUID is used for an EFI Variable that stores the front device pathes
-/// for a partial device path that starts with the HD node.
-///
-EFI_GUID mBmHardDriveBootVariableGuid = { 0xfab7e9e1, 0x39dd, 0x4f2b, { 0x84, 0x08, 0xe2, 0x0e, 0x90, 0x6c, 0xb6, 0xde } };
-EFI_GUID mBmAutoCreateBootOptionGuid  = { 0x8108ac4e, 0x9f11, 0x4d59, { 0x85, 0x0e, 0xe2, 0x1a, 0x52, 0x2c, 0x59, 0xb2 } };
-
-/**
-  The function registers the legacy boot support capabilities.
-
-  @param RefreshLegacyBootOption The function pointer to create all the legacy boot options.
-  @param LegacyBoot              The function pointer to boot the legacy boot option.
-**/
-VOID
-EFIAPI
-EfiBootManagerRegisterLegacyBootSupport (
-  EFI_BOOT_MANAGER_REFRESH_LEGACY_BOOT_OPTION   RefreshLegacyBootOption,
-  EFI_BOOT_MANAGER_LEGACY_BOOT                  LegacyBoot
-  )
-{
-  mBmRefreshLegacyBootOption = RefreshLegacyBootOption;
-  mBmLegacyBoot              = LegacyBoot;
-}
-
-/**
-  For a bootable Device path, return its boot type.
-
-  @param  DevicePath                   The bootable device Path to check
-
-  @retval AcpiFloppyBoot               If given device path contains ACPI_DEVICE_PATH type device path node
-                                       which HID is floppy device.
-  @retval MessageAtapiBoot             If given device path contains MESSAGING_DEVICE_PATH type device path node
-                                       and its last device path node's subtype is MSG_ATAPI_DP.
-  @retval MessageSataBoot              If given device path contains MESSAGING_DEVICE_PATH type device path node
-                                       and its last device path node's subtype is MSG_SATA_DP.
-  @retval MessageScsiBoot              If given device path contains MESSAGING_DEVICE_PATH type device path node
-                                       and its last device path node's subtype is MSG_SCSI_DP.
-  @retval MessageUsbBoot               If given device path contains MESSAGING_DEVICE_PATH type device path node
-                                       and its last device path node's subtype is MSG_USB_DP.
-  @retval MessageNetworkBoot           If given device path contains MESSAGING_DEVICE_PATH type device path node
-                                       and its last device path node's subtype is MSG_MAC_ADDR_DP, MSG_VLAN_DP,
-                                       MSG_IPv4_DP or MSG_IPv6_DP.
-  @retval UnsupportedBoot              If tiven device path doesn't match the above condition, it's not supported.
-
-**/
-BM_BOOT_TYPE
-BmDevicePathType (
-  IN  EFI_DEVICE_PATH_PROTOCOL     *DevicePath
-  )
-{
-  EFI_DEVICE_PATH_PROTOCOL      *Node;
-  EFI_DEVICE_PATH_PROTOCOL      *NextNode;
-
-  ASSERT (DevicePath != NULL);
-
-  for (Node = DevicePath; !IsDevicePathEndType (Node); Node = NextDevicePathNode (Node)) {
-    switch (DevicePathType (Node)) {
-
-      case ACPI_DEVICE_PATH:
-        if (EISA_ID_TO_NUM (((ACPI_HID_DEVICE_PATH *) Node)->HID) == 0x0604) {
-          return BmAcpiFloppyBoot;
-        }
-        break;
-
-      case HARDWARE_DEVICE_PATH:
-        if (DevicePathSubType (Node) == HW_CONTROLLER_DP) {
-          return BmHardwareDeviceBoot;
-        }
-        break;
-
-      case MESSAGING_DEVICE_PATH:
-        //
-        // Skip LUN device node
-        //
-        NextNode = Node;
-        do {
-          NextNode = NextDevicePathNode (NextNode);
-        } while (
-            (DevicePathType (NextNode) == MESSAGING_DEVICE_PATH) &&
-            (DevicePathSubType(NextNode) == MSG_DEVICE_LOGICAL_UNIT_DP)
-            );
-
-        //
-        // If the device path not only point to driver device, it is not a messaging device path,
-        //
-        if (!IsDevicePathEndType (NextNode)) {
-          break;
-        }
-
-        switch (DevicePathSubType (Node)) {
-        case MSG_ATAPI_DP:
-          return BmMessageAtapiBoot;
-          break;
-
-        case MSG_SATA_DP:
-          return BmMessageSataBoot;
-          break;
-
-        case MSG_USB_DP:
-          return BmMessageUsbBoot;
-          break;
-
-        case MSG_SCSI_DP:
-          return BmMessageScsiBoot;
-          break;
-
-        case MSG_MAC_ADDR_DP:
-        case MSG_VLAN_DP:
-        case MSG_IPv4_DP:
-        case MSG_IPv6_DP:
-          return BmMessageNetworkBoot;
-          break;
-        }
-    }
-  }
-
-  return BmMiscBoot;
-}
-
-/**
-  Find the boot option in the NV storage and return the option number.
-
-  @param OptionToFind  Boot option to be checked.
-
-  @return   The option number of the found boot option.
-
-**/
-UINTN
-BmFindBootOptionInVariable (
-  IN  EFI_BOOT_MANAGER_LOAD_OPTION             *OptionToFind
-  )
-{
-  EFI_STATUS                   Status;
-  EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
-  UINTN                        OptionNumber;
-  CHAR16                       OptionName[BM_OPTION_NAME_LEN];
-  EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
-  UINTN                        BootOptionCount;
-  UINTN                        Index;
-  
-  OptionNumber = LoadOptionNumberUnassigned;
-
-  //
-  // Try to match the variable exactly if the option number is assigned
-  //
-  if (OptionToFind->OptionNumber != LoadOptionNumberUnassigned) {
-    UnicodeSPrint (
-      OptionName, sizeof (OptionName), L"%s%04x",
-      mBmLoadOptionName[OptionToFind->OptionType], OptionToFind->OptionNumber
-      );
-    Status = EfiBootManagerVariableToLoadOption (OptionName, &BootOption);
-
-    if (!EFI_ERROR (Status)) {
-      ASSERT (OptionToFind->OptionNumber == BootOption.OptionNumber);
-      if ((OptionToFind->Attributes == BootOption.Attributes) &&
-          (StrCmp (OptionToFind->Description, BootOption.Description) == 0) &&
-          (CompareMem (OptionToFind->FilePath, BootOption.FilePath, GetDevicePathSize (OptionToFind->FilePath)) == 0) &&
-          (OptionToFind->OptionalDataSize == BootOption.OptionalDataSize) &&
-          (CompareMem (OptionToFind->OptionalData, BootOption.OptionalData, OptionToFind->OptionalDataSize) == 0)
-         ) {
-        OptionNumber = OptionToFind->OptionNumber;
-      }
-      EfiBootManagerFreeLoadOption (&BootOption);
-    }
-  }
-
-  //
-  // The option number assigned is either incorrect or unassigned.
-  //
-  if (OptionNumber == LoadOptionNumberUnassigned) {
-    BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
-
-    Index = BmFindLoadOption (OptionToFind, BootOptions, BootOptionCount);
-    if (Index != -1) {
-      OptionNumber = BootOptions[Index].OptionNumber;
-    }
-
-    EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
-  }
-
-  return OptionNumber;
-}
-
-/**
-  Get the file buffer using a Memory Mapped Device Path.
-
-  FV address may change across reboot. This routine promises the FV file device path is right.
-
-  @param  DevicePath   The Memory Mapped Device Path to get the file buffer.
-  @param  FullPath     Receive the updated FV Device Path pointint to the file.
-  @param  FileSize     Receive the file buffer size.
-
-  @return  The file buffer.
-**/
-VOID *
-BmGetFileBufferByMemmapFv (
-  IN EFI_DEVICE_PATH_PROTOCOL      *DevicePath,
-  OUT EFI_DEVICE_PATH_PROTOCOL     **FullPath,
-  OUT UINTN                        *FileSize
-  )
-{
-  EFI_STATUS                    Status;
-  UINTN                         Index;
-  EFI_DEVICE_PATH_PROTOCOL      *FvFileNode;
-  EFI_HANDLE                    FvHandle;
-  EFI_LOADED_IMAGE_PROTOCOL     *LoadedImage;
-  UINT32                        AuthenticationStatus;
-  UINTN                         FvHandleCount;
-  EFI_HANDLE                    *FvHandles;
-  EFI_DEVICE_PATH_PROTOCOL      *NewDevicePath;
-  VOID                          *FileBuffer;
-  
-  FvFileNode = DevicePath;
-  Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &FvFileNode, &FvHandle);
-  if (!EFI_ERROR (Status)) {
-    FileBuffer = GetFileBufferByFilePath (TRUE, DevicePath, FileSize, &AuthenticationStatus);
-    if (FileBuffer != NULL) {
-      *FullPath = DuplicateDevicePath (DevicePath);
-    }
-    return FileBuffer;
-  }
-
-  FvFileNode = NextDevicePathNode (DevicePath);
-
-  //
-  // Firstly find the FV file in current FV
-  //
-  gBS->HandleProtocol (
-         gImageHandle,
-         &gEfiLoadedImageProtocolGuid,
-         (VOID **) &LoadedImage
-         );
-  NewDevicePath = AppendDevicePathNode (DevicePathFromHandle (LoadedImage->DeviceHandle), FvFileNode);
-  FileBuffer = BmGetFileBufferByMemmapFv (NewDevicePath, FullPath, FileSize);
-  FreePool (NewDevicePath);
-
-  if (FileBuffer != NULL) {
-    return FileBuffer;
-  }
-
-  //
-  // Secondly find the FV file in all other FVs
-  //
-  gBS->LocateHandleBuffer (
-         ByProtocol,
-         &gEfiFirmwareVolume2ProtocolGuid,
-         NULL,
-         &FvHandleCount,
-         &FvHandles
-         );
-  for (Index = 0; (Index < FvHandleCount) && (FileBuffer == NULL); Index++) {
-    if (FvHandles[Index] == LoadedImage->DeviceHandle) {
-      //
-      // Skip current FV
-      //
-      continue;
-    }
-    NewDevicePath = AppendDevicePathNode (DevicePathFromHandle (FvHandles[Index]), FvFileNode);
-    FileBuffer = BmGetFileBufferByMemmapFv (NewDevicePath, FullPath, FileSize);
-    FreePool (NewDevicePath);
-  }
-  
-  if (FvHandles != NULL) {
-    FreePool (FvHandles);
-  }
-  return FileBuffer;
-}
-
-/**
-  Check if it's a Memory Mapped FV Device Path.
-  
-  The function doesn't garentee the device path points to existing FV file.
-
-  @param  DevicePath     Input device path.
-
-  @retval TRUE   The device path is a Memory Mapped FV Device Path.
-  @retval FALSE  The device path is NOT a Memory Mapped FV Device Path.
-**/
-BOOLEAN
-BmIsMemmapFvFilePath (
-  IN EFI_DEVICE_PATH_PROTOCOL    *DevicePath
-  )
-{
-  EFI_DEVICE_PATH_PROTOCOL   *FileNode;
-
-  if ((DevicePathType (DevicePath) == HARDWARE_DEVICE_PATH) && (DevicePathSubType (DevicePath) == HW_MEMMAP_DP)) {
-    FileNode = NextDevicePathNode (DevicePath);
-    if ((DevicePathType (FileNode) == MEDIA_DEVICE_PATH) && (DevicePathSubType (FileNode) == MEDIA_PIWG_FW_FILE_DP)) {
-      return IsDevicePathEnd (NextDevicePathNode (FileNode));
-    }
-  }
-
-  return FALSE;
-}
-
-/**
-  Check whether a USB device match the specified USB Class device path. This
-  function follows "Load Option Processing" behavior in UEFI specification.
-
-  @param UsbIo       USB I/O protocol associated with the USB device.
-  @param UsbClass    The USB Class device path to match.
-
-  @retval TRUE       The USB device match the USB Class device path.
-  @retval FALSE      The USB device does not match the USB Class device path.
-
-**/
-BOOLEAN
-BmMatchUsbClass (
-  IN EFI_USB_IO_PROTOCOL        *UsbIo,
-  IN USB_CLASS_DEVICE_PATH      *UsbClass
-  )
-{
-  EFI_STATUS                    Status;
-  EFI_USB_DEVICE_DESCRIPTOR     DevDesc;
-  EFI_USB_INTERFACE_DESCRIPTOR  IfDesc;
-  UINT8                         DeviceClass;
-  UINT8                         DeviceSubClass;
-  UINT8                         DeviceProtocol;
-
-  if ((DevicePathType (UsbClass) != MESSAGING_DEVICE_PATH) ||
-      (DevicePathSubType (UsbClass) != MSG_USB_CLASS_DP)){
-    return FALSE;
-  }
-
-  //
-  // Check Vendor Id and Product Id.
-  //
-  Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);
-  if (EFI_ERROR (Status)) {
-    return FALSE;
-  }
-
-  if ((UsbClass->VendorId != 0xffff) &&
-      (UsbClass->VendorId != DevDesc.IdVendor)) {
-    return FALSE;
-  }
-
-  if ((UsbClass->ProductId != 0xffff) &&
-      (UsbClass->ProductId != DevDesc.IdProduct)) {
-    return FALSE;
-  }
-
-  DeviceClass    = DevDesc.DeviceClass;
-  DeviceSubClass = DevDesc.DeviceSubClass;
-  DeviceProtocol = DevDesc.DeviceProtocol;
-  if (DeviceClass == 0) {
-    //
-    // If Class in Device Descriptor is set to 0, use the Class, SubClass and
-    // Protocol in Interface Descriptor instead.
-    //
-    Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &IfDesc);
-    if (EFI_ERROR (Status)) {
-      return FALSE;
-    }
-
-    DeviceClass    = IfDesc.InterfaceClass;
-    DeviceSubClass = IfDesc.InterfaceSubClass;
-    DeviceProtocol = IfDesc.InterfaceProtocol;
-  }
-
-  //
-  // Check Class, SubClass and Protocol.
-  //
-  if ((UsbClass->DeviceClass != 0xff) &&
-      (UsbClass->DeviceClass != DeviceClass)) {
-    return FALSE;
-  }
-
-  if ((UsbClass->DeviceSubClass != 0xff) &&
-      (UsbClass->DeviceSubClass != DeviceSubClass)) {
-    return FALSE;
-  }
-
-  if ((UsbClass->DeviceProtocol != 0xff) &&
-      (UsbClass->DeviceProtocol != DeviceProtocol)) {
-    return FALSE;
-  }
-
-  return TRUE;
-}
-
-/**
-  Eliminate the extra spaces in the Str to one space.
-
-  @param    Str     Input string info.
-**/
-VOID
-BmEliminateExtraSpaces (
-  IN CHAR16                    *Str
-  )
-{
-  UINTN                        Index;
-  UINTN                        ActualIndex;
-
-  for (Index = 0, ActualIndex = 0; Str[Index] != L'\0'; Index++) {
-    if ((Str[Index] != L' ') || ((ActualIndex > 0) && (Str[ActualIndex - 1] != L' '))) {
-      Str[ActualIndex++] = Str[Index];
-    }
-  }
-  Str[ActualIndex] = L'\0';
-}
-
-/**
-  Try to get the controller's ATA/ATAPI description.
-
-  @param Handle                Controller handle.
-
-  @return  The description string.
-**/
-CHAR16 *
-BmGetDescriptionFromDiskInfo (
-  IN EFI_HANDLE                Handle
-  )
-{
-  UINTN                        Index;
-  EFI_STATUS                   Status;
-  EFI_DISK_INFO_PROTOCOL       *DiskInfo;
-  UINT32                       BufferSize;
-  EFI_ATAPI_IDENTIFY_DATA      IdentifyData;
-  EFI_SCSI_INQUIRY_DATA        InquiryData;
-  CHAR16                       *Description;
-  UINTN                        Length;
-  CONST UINTN                  ModelNameLength    = 40;
-  CONST UINTN                  SerialNumberLength = 20;
-  CHAR8                        *StrPtr;
-  UINT8                        Temp;
-
-  Description  = NULL;
-
-  Status = gBS->HandleProtocol (
-                  Handle,
-                  &gEfiDiskInfoProtocolGuid,
-                  (VOID **) &DiskInfo
-                  );
-  if (EFI_ERROR (Status)) {
-    return NULL;
-  }
-
-  if (CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoAhciInterfaceGuid) || 
-      CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoIdeInterfaceGuid)) {
-    BufferSize   = sizeof (EFI_ATAPI_IDENTIFY_DATA);
-    Status = DiskInfo->Identify (
-                         DiskInfo,
-                         &IdentifyData,
-                         &BufferSize
-                         );
-    if (!EFI_ERROR (Status)) {
-      Description = AllocateZeroPool ((ModelNameLength + SerialNumberLength + 2) * sizeof (CHAR16));
-      ASSERT (Description != NULL);
-      for (Index = 0; Index + 1 < ModelNameLength; Index += 2) {
-        Description[Index]     = (CHAR16) IdentifyData.ModelName[Index + 1];
-        Description[Index + 1] = (CHAR16) IdentifyData.ModelName[Index];
-      }
-
-      Length = Index;
-      Description[Length++] = L' ';
-
-      for (Index = 0; Index + 1 < SerialNumberLength; Index += 2) {
-        Description[Length + Index]     = (CHAR16) IdentifyData.SerialNo[Index + 1];
-        Description[Length + Index + 1] = (CHAR16) IdentifyData.SerialNo[Index];
-      }
-      Length += Index;
-      Description[Length++] = L'\0';
-      ASSERT (Length == ModelNameLength + SerialNumberLength + 2);
-
-      BmEliminateExtraSpaces (Description);
-    }
-  } else if (CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoScsiInterfaceGuid)) {
-    BufferSize   = sizeof (EFI_SCSI_INQUIRY_DATA);
-    Status = DiskInfo->Inquiry (
-                         DiskInfo,
-                         &InquiryData,
-                         &BufferSize
-                         );
-    if (!EFI_ERROR (Status)) {
-      Description = AllocateZeroPool ((VENDOR_IDENTIFICATION_LENGTH + PRODUCT_IDENTIFICATION_LENGTH + 2) * sizeof (CHAR16));
-      ASSERT (Description != NULL);
-
-      //
-      // Per SCSI spec, EFI_SCSI_INQUIRY_DATA.Reserved_5_95[3 - 10] save the Verdor identification
-      // EFI_SCSI_INQUIRY_DATA.Reserved_5_95[11 - 26] save the product identification, 
-      // Here combine the vendor identification and product identification to the description.
-      //
-      StrPtr = (CHAR8 *) (&InquiryData.Reserved_5_95[VENDOR_IDENTIFICATION_OFFSET]);
-      Temp = StrPtr[VENDOR_IDENTIFICATION_LENGTH];
-      StrPtr[VENDOR_IDENTIFICATION_LENGTH] = '\0';
-      AsciiStrToUnicodeStr (StrPtr, Description);
-      StrPtr[VENDOR_IDENTIFICATION_LENGTH] = Temp;
-
-      //
-      // Add one space at the middle of vendor information and product information.
-      //
-      Description[VENDOR_IDENTIFICATION_LENGTH] = L' ';
-
-      StrPtr = (CHAR8 *) (&InquiryData.Reserved_5_95[PRODUCT_IDENTIFICATION_OFFSET]);
-      StrPtr[PRODUCT_IDENTIFICATION_LENGTH] = '\0';
-      AsciiStrToUnicodeStr (StrPtr, Description + VENDOR_IDENTIFICATION_LENGTH + 1);
-
-      BmEliminateExtraSpaces (Description);
-    }
-  }
-
-  return Description;
-}
-
-/**
-  Try to get the controller's USB description.
-
-  @param Handle                Controller handle.
-
-  @return  The description string.
-**/
-CHAR16 *
-BmGetUsbDescription (
-  IN EFI_HANDLE                Handle
-  )
-{
-  EFI_STATUS                   Status;
-  EFI_USB_IO_PROTOCOL          *UsbIo;
-  CHAR16                       NullChar;
-  CHAR16                       *Manufacturer;
-  CHAR16                       *Product;
-  CHAR16                       *SerialNumber;
-  CHAR16                       *Description;
-  EFI_USB_DEVICE_DESCRIPTOR    DevDesc;
-
-  Status = gBS->HandleProtocol (
-                  Handle,
-                  &gEfiUsbIoProtocolGuid,
-                  (VOID **) &UsbIo
-                  );
-  if (EFI_ERROR (Status)) {
-    return NULL;
-  }
-
-  NullChar = L'\0';
-
-  Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);
-  if (EFI_ERROR (Status)) {
-    return NULL;
-  }
-
-  Status = UsbIo->UsbGetStringDescriptor (
-                    UsbIo,
-                    mBmUsbLangId,
-                    DevDesc.StrManufacturer,
-                    &Manufacturer
-                    );
-  if (EFI_ERROR (Status)) {
-    Manufacturer = &NullChar;
-  }
-  
-  Status = UsbIo->UsbGetStringDescriptor (
-                    UsbIo,
-                    mBmUsbLangId,
-                    DevDesc.StrProduct,
-                    &Product
-                    );
-  if (EFI_ERROR (Status)) {
-    Product = &NullChar;
-  }
-  
-  Status = UsbIo->UsbGetStringDescriptor (
-                    UsbIo,
-                    mBmUsbLangId,
-                    DevDesc.StrSerialNumber,
-                    &SerialNumber
-                    );
-  if (EFI_ERROR (Status)) {
-    SerialNumber = &NullChar;
-  }
-
-  if ((Manufacturer == &NullChar) &&
-      (Product == &NullChar) &&
-      (SerialNumber == &NullChar)
-      ) {
-    return NULL;
-  }
-
-  Description = AllocateZeroPool (StrSize (Manufacturer) + StrSize (Product) + StrSize (SerialNumber));
-  ASSERT (Description != NULL);
-  StrCat (Description, Manufacturer);
-  StrCat (Description, L" ");
-
-  StrCat (Description, Product);  
-  StrCat (Description, L" ");
-
-  StrCat (Description, SerialNumber);
-
-  if (Manufacturer != &NullChar) {
-    FreePool (Manufacturer);
-  }
-  if (Product != &NullChar) {
-    FreePool (Product);
-  }
-  if (SerialNumber != &NullChar) {
-    FreePool (SerialNumber);
-  }
-
-  BmEliminateExtraSpaces (Description);
-
-  return Description;
-}
-
-/**
-  Return the boot description for the controller based on the type.
-
-  @param Handle                Controller handle.
-
-  @return  The description string.
-**/
-CHAR16 *
-BmGetMiscDescription (
-  IN EFI_HANDLE                  Handle
-  )
-{
-  EFI_STATUS                     Status;
-  CHAR16                         *Description;
-  EFI_BLOCK_IO_PROTOCOL          *BlockIo;
-
-  switch (BmDevicePathType (DevicePathFromHandle (Handle))) {
-  case BmAcpiFloppyBoot:
-    Description = L"Floppy";
-    break;
-
-  case BmMessageAtapiBoot:
-  case BmMessageSataBoot:
-    Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
-    ASSERT_EFI_ERROR (Status);
-    //
-    // Assume a removable SATA device should be the DVD/CD device
-    //
-    Description = BlockIo->Media->RemovableMedia ? L"DVD/CDROM" : L"Hard Drive";
-    break;
-
-  case BmMessageUsbBoot:
-    Description = L"USB Device";
-    break;
-
-  case BmMessageScsiBoot:
-    Description = L"SCSI Device";
-    break;
-
-  case BmHardwareDeviceBoot:
-    Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
-    if (!EFI_ERROR (Status)) {
-      Description = BlockIo->Media->RemovableMedia ? L"Removable Disk" : L"Hard Drive";
-    } else {
-      Description = L"Misc Device";
-    }
-    break;
-
-  default:
-    Description = L"Misc Device";
-    break;
-  }
-
-  return AllocateCopyPool (StrSize (Description), Description);
-}
-
-BM_GET_BOOT_DESCRIPTION mBmGetBootDescription[] = {
-  BmGetUsbDescription,
-  BmGetDescriptionFromDiskInfo,
-  BmGetMiscDescription
-};
-
-/**
-  Check whether a USB device match the specified USB WWID device path. This
-  function follows "Load Option Processing" behavior in UEFI specification.
-
-  @param UsbIo       USB I/O protocol associated with the USB device.
-  @param UsbWwid     The USB WWID device path to match.
-
-  @retval TRUE       The USB device match the USB WWID device path.
-  @retval FALSE      The USB device does not match the USB WWID device path.
-
-**/
-BOOLEAN
-BmMatchUsbWwid (
-  IN EFI_USB_IO_PROTOCOL        *UsbIo,
-  IN USB_WWID_DEVICE_PATH       *UsbWwid
-  )
-{
-  EFI_STATUS                   Status;
-  EFI_USB_DEVICE_DESCRIPTOR    DevDesc;
-  EFI_USB_INTERFACE_DESCRIPTOR IfDesc;
-  UINT16                       *LangIdTable;
-  UINT16                       TableSize;
-  UINT16                       Index;
-  CHAR16                       *CompareStr;
-  UINTN                        CompareLen;
-  CHAR16                       *SerialNumberStr;
-  UINTN                        Length;
-
-  if ((DevicePathType (UsbWwid) != MESSAGING_DEVICE_PATH) ||
-      (DevicePathSubType (UsbWwid) != MSG_USB_WWID_DP)) {
-    return FALSE;
-  }
-
-  //
-  // Check Vendor Id and Product Id.
-  //
-  Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);
-  if (EFI_ERROR (Status)) {
-    return FALSE;
-  }
-  if ((DevDesc.IdVendor != UsbWwid->VendorId) ||
-      (DevDesc.IdProduct != UsbWwid->ProductId)) {
-    return FALSE;
-  }
-
-  //
-  // Check Interface Number.
-  //
-  Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &IfDesc);
-  if (EFI_ERROR (Status)) {
-    return FALSE;
-  }
-  if (IfDesc.InterfaceNumber != UsbWwid->InterfaceNumber) {
-    return FALSE;
-  }
-
-  //
-  // Check Serial Number.
-  //
-  if (DevDesc.StrSerialNumber == 0) {
-    return FALSE;
-  }
-
-  //
-  // Get all supported languages.
-  //
-  TableSize = 0;
-  LangIdTable = NULL;
-  Status = UsbIo->UsbGetSupportedLanguages (UsbIo, &LangIdTable, &TableSize);
-  if (EFI_ERROR (Status) || (TableSize == 0) || (LangIdTable == NULL)) {
-    return FALSE;
-  }
-
-  //
-  // Serial number in USB WWID device path is the last 64-or-less UTF-16 characters.
-  //
-  CompareStr = (CHAR16 *) (UINTN) (UsbWwid + 1);
-  CompareLen = (DevicePathNodeLength (UsbWwid) - sizeof (USB_WWID_DEVICE_PATH)) / sizeof (CHAR16);
-  if (CompareStr[CompareLen - 1] == L'\0') {
-    CompareLen--;
-  }
-
-  //
-  // Compare serial number in each supported language.
-  //
-  for (Index = 0; Index < TableSize / sizeof (UINT16); Index++) {
-    SerialNumberStr = NULL;
-    Status = UsbIo->UsbGetStringDescriptor (
-                      UsbIo,
-                      LangIdTable[Index],
-                      DevDesc.StrSerialNumber,
-                      &SerialNumberStr
-                      );
-    if (EFI_ERROR (Status) || (SerialNumberStr == NULL)) {
-      continue;
-    }
-
-    Length = StrLen (SerialNumberStr);
-    if ((Length >= CompareLen) &&
-        (CompareMem (SerialNumberStr + Length - CompareLen, CompareStr, CompareLen * sizeof (CHAR16)) == 0)) {
-      FreePool (SerialNumberStr);
-      return TRUE;
-    }
-
-    FreePool (SerialNumberStr);
-  }
-
-  return FALSE;
-}
-
-/**
-  Find a USB device which match the specified short-form device path start with 
-  USB Class or USB WWID device path. If ParentDevicePath is NULL, this function
-  will search in all USB devices of the platform. If ParentDevicePath is not NULL,
-  this function will only search in its child devices.
-
-  @param DevicePath           The device path that contains USB Class or USB WWID device path.
-  @param ParentDevicePathSize The length of the device path before the USB Class or 
-                              USB WWID device path.
-  @param UsbIoHandleCount     A pointer to the count of the returned USB IO handles.
-
-  @retval NULL       The matched USB IO handles cannot be found.
-  @retval other      The matched USB IO handles.
-
-**/
-EFI_HANDLE *
-BmFindUsbDevice (
-  IN  EFI_DEVICE_PATH_PROTOCOL  *DevicePath,
-  IN  UINTN                     ParentDevicePathSize,
-  OUT UINTN                     *UsbIoHandleCount
-  )
-{
-  EFI_STATUS                Status;
-  EFI_HANDLE                *UsbIoHandles;
-  EFI_DEVICE_PATH_PROTOCOL  *UsbIoDevicePath;
-  EFI_USB_IO_PROTOCOL       *UsbIo;
-  UINTN                     Index;
-  UINTN                     UsbIoDevicePathSize;
-  BOOLEAN                   Matched;
-
-  ASSERT (UsbIoHandleCount != NULL);  
-
-  //
-  // Get all UsbIo Handles.
-  //
-  Status = gBS->LocateHandleBuffer (
-                  ByProtocol,
-                  &gEfiUsbIoProtocolGuid,
-                  NULL,
-                  UsbIoHandleCount,
-                  &UsbIoHandles
-                  );
-  if (EFI_ERROR (Status)) {
-    *UsbIoHandleCount = 0;
-    UsbIoHandles      = NULL;
-  }
-
-  for (Index = 0; Index < *UsbIoHandleCount; ) {
-    //
-    // Get the Usb IO interface.
-    //
-    Status = gBS->HandleProtocol(
-                    UsbIoHandles[Index],
-                    &gEfiUsbIoProtocolGuid,
-                    (VOID **) &UsbIo
-                    );
-    UsbIoDevicePath = DevicePathFromHandle (UsbIoHandles[Index]);
-    Matched         = FALSE;
-    if (!EFI_ERROR (Status) && (UsbIoDevicePath != NULL)) {
-      UsbIoDevicePathSize = GetDevicePathSize (UsbIoDevicePath) - END_DEVICE_PATH_LENGTH;
-
-      //
-      // Compare starting part of UsbIoHandle's device path with ParentDevicePath.
-      //
-      if (CompareMem (UsbIoDevicePath, DevicePath, ParentDevicePathSize) == 0) {
-        if (BmMatchUsbClass (UsbIo, (USB_CLASS_DEVICE_PATH *) ((UINTN) DevicePath + ParentDevicePathSize)) ||
-            BmMatchUsbWwid (UsbIo, (USB_WWID_DEVICE_PATH *) ((UINTN) DevicePath + ParentDevicePathSize))) {
-          Matched = TRUE;
-        }
-      }
-    }
-
-    if (!Matched) {
-      (*UsbIoHandleCount) --;
-      CopyMem (&UsbIoHandles[Index], &UsbIoHandles[Index + 1], (*UsbIoHandleCount - Index) * sizeof (EFI_HANDLE));
-    } else {
-      Index++;
-    }
-  }
-
-  return UsbIoHandles;
-}
-
-/**
-  Expand USB Class or USB WWID device path node to be full device path of a USB
-  device in platform.
-
-  This function support following 4 cases:
-  1) Boot Option device path starts with a USB Class or USB WWID device path,
-     and there is no Media FilePath device path in the end.
-     In this case, it will follow Removable Media Boot Behavior.
-  2) Boot Option device path starts with a USB Class or USB WWID device path,
-     and ended with Media FilePath device path.
-  3) Boot Option device path starts with a full device path to a USB Host Controller,
-     contains a USB Class or USB WWID device path node, while not ended with Media
-     FilePath device path. In this case, it will follow Removable Media Boot Behavior.
-  4) Boot Option device path starts with a full device path to a USB Host Controller,
-     contains a USB Class or USB WWID device path node, and ended with Media
-     FilePath device path.
-
-  @param FilePath      The device path pointing to a load option.
-                       It could be a short-form device path.
-  @param FullPath      Return the full device path of the load option after
-                       short-form device path expanding.
-                       Caller is responsible to free it.
-  @param FileSize      Return the load option size.
-  @param ShortformNode Pointer to the USB short-form device path node in the FilePath buffer.
-
-  @return The load option buffer. Caller is responsible to free the memory.
-**/
-VOID *
-BmExpandUsbDevicePath (
-  IN  EFI_DEVICE_PATH_PROTOCOL  *FilePath,
-  OUT EFI_DEVICE_PATH_PROTOCOL  **FullPath,
-  OUT UINTN                     *FileSize,
-  IN EFI_DEVICE_PATH_PROTOCOL   *ShortformNode
-  )
-{
-  UINTN                             ParentDevicePathSize;
-  EFI_DEVICE_PATH_PROTOCOL          *RemainingDevicePath;
-  EFI_DEVICE_PATH_PROTOCOL          *FullDevicePath;
-  EFI_HANDLE                        *Handles;
-  UINTN                             HandleCount;
-  UINTN                             Index;
-  VOID                              *FileBuffer;
-
-  ParentDevicePathSize = (UINTN) ShortformNode - (UINTN) FilePath;
-  RemainingDevicePath = NextDevicePathNode (ShortformNode);
-  FileBuffer = NULL;
-  Handles = BmFindUsbDevice (FilePath, ParentDevicePathSize, &HandleCount);
-
-  for (Index = 0; (Index < HandleCount) && (FileBuffer == NULL); Index++) {
-    FullDevicePath = AppendDevicePath (DevicePathFromHandle (Handles[Index]), RemainingDevicePath);
-    FileBuffer = BmGetLoadOptionBuffer (FullDevicePath, FullPath, FileSize);
-    FreePool (FullDevicePath);
-  }
-
-  if (Handles != NULL) {
-    FreePool (Handles);
-  }
-
-  return FileBuffer;
-}
-
-/**
-  Save the partition DevicePath to the CachedDevicePath as the first instance.
-
-  @param CachedDevicePath  The device path cache.
-  @param DevicePath        The partition device path to be cached.
-**/
-VOID
-BmCachePartitionDevicePath (
-  IN OUT EFI_DEVICE_PATH_PROTOCOL **CachedDevicePath,
-  IN EFI_DEVICE_PATH_PROTOCOL     *DevicePath
-  )
-{
-  EFI_DEVICE_PATH_PROTOCOL        *TempDevicePath;
-  UINTN                           Count;
-  
-  if (BmMatchDevicePaths (*CachedDevicePath, DevicePath)) {
-    TempDevicePath = *CachedDevicePath;
-    *CachedDevicePath = BmDelPartMatchInstance (*CachedDevicePath, DevicePath);
-    FreePool (TempDevicePath);
-  }
-
-  if (*CachedDevicePath == NULL) {
-    *CachedDevicePath = DuplicateDevicePath (DevicePath);
-    return;
-  }
-
-  TempDevicePath = *CachedDevicePath;
-  *CachedDevicePath = AppendDevicePathInstance (DevicePath, *CachedDevicePath);
-  if (TempDevicePath != NULL) {
-    FreePool (TempDevicePath);
-  }
-
-  //
-  // Here limit the device path instance number to 12, which is max number for a system support 3 IDE controller
-  // If the user try to boot many OS in different HDs or partitions, in theory, the 'HDDP' variable maybe become larger and larger.
-  //
-  Count = 0;
-  TempDevicePath = *CachedDevicePath;
-  while (!IsDevicePathEnd (TempDevicePath)) {
-    TempDevicePath = NextDevicePathNode (TempDevicePath);
-    //
-    // Parse one instance
-    //
-    while (!IsDevicePathEndType (TempDevicePath)) {
-      TempDevicePath = NextDevicePathNode (TempDevicePath);
-    }
-    Count++;
-    //
-    // If the CachedDevicePath variable contain too much instance, only remain 12 instances.
-    //
-    if (Count == 12) {
-      SetDevicePathEndNode (TempDevicePath);
-      break;
-    }
-  }
-}
-
-/**
-  Expand a device path that starts with a hard drive media device path node to be a
-  full device path that includes the full hardware path to the device. We need
-  to do this so it can be booted. As an optimization the front match (the part point
-  to the partition node. E.g. ACPI() /PCI()/ATA()/Partition() ) is saved in a variable
-  so a connect all is not required on every boot. All successful history device path
-  which point to partition node (the front part) will be saved.
-
-  @param FilePath      The device path pointing to a load option.
-                       It could be a short-form device path.
-  @param FullPath      Return the full device path of the load option after
-                       short-form device path expanding.
-                       Caller is responsible to free it.
-  @param FileSize      Return the load option size.
-
-  @return The load option buffer. Caller is responsible to free the memory.
-**/
-VOID *
-BmExpandPartitionDevicePath (
-  IN  EFI_DEVICE_PATH_PROTOCOL  *FilePath,
-  OUT EFI_DEVICE_PATH_PROTOCOL  **FullPath,
-  OUT UINTN                     *FileSize
-  )
-{
-  EFI_STATUS                Status;
-  UINTN                     BlockIoHandleCount;
-  EFI_HANDLE                *BlockIoBuffer;
-  VOID                      *FileBuffer;
-  EFI_DEVICE_PATH_PROTOCOL  *BlockIoDevicePath;
-  UINTN                     Index;
-  EFI_DEVICE_PATH_PROTOCOL  *CachedDevicePath;
-  EFI_DEVICE_PATH_PROTOCOL  *TempNewDevicePath;
-  EFI_DEVICE_PATH_PROTOCOL  *TempDevicePath;
-  UINTN                     CachedDevicePathSize;
-  BOOLEAN                   NeedAdjust;
-  EFI_DEVICE_PATH_PROTOCOL  *Instance;
-  UINTN                     Size;
-
-  FileBuffer = NULL;
-  //
-  // Check if there is prestore 'HDDP' variable.
-  // If exist, search the front path which point to partition node in the variable instants.
-  // If fail to find or 'HDDP' not exist, reconnect all and search in all system
-  //
-  GetVariable2 (L"HDDP", &mBmHardDriveBootVariableGuid, (VOID **) &CachedDevicePath, &CachedDevicePathSize);
-
-  //
-  // Delete the invalid 'HDDP' variable.
-  //
-  if ((CachedDevicePath != NULL) && !IsDevicePathValid (CachedDevicePath, CachedDevicePathSize)) {
-    FreePool (CachedDevicePath);
-    CachedDevicePath = NULL;
-    Status = gRT->SetVariable (
-                    L"HDDP",
-                    &mBmHardDriveBootVariableGuid,
-                    0,
-                    0,
-                    NULL
-                    );
-    ASSERT_EFI_ERROR (Status);
-  }
-
-  if (CachedDevicePath != NULL) {
-    TempNewDevicePath = CachedDevicePath;
-    NeedAdjust = FALSE;
-    do {
-      //
-      // Check every instance of the variable
-      // First, check whether the instance contain the partition node, which is needed for distinguishing  multi
-      // partial partition boot option. Second, check whether the instance could be connected.
-      //
-      Instance  = GetNextDevicePathInstance (&TempNewDevicePath, &Size);
-      if (BmMatchPartitionDevicePathNode (Instance, (HARDDRIVE_DEVICE_PATH *) FilePath)) {
-        //
-        // Connect the device path instance, the device path point to hard drive media device path node
-        // e.g. ACPI() /PCI()/ATA()/Partition()
-        //
-        Status = EfiBootManagerConnectDevicePath (Instance, NULL);
-        if (!EFI_ERROR (Status)) {
-          TempDevicePath = AppendDevicePath (Instance, NextDevicePathNode (FilePath));
-          FileBuffer = BmGetLoadOptionBuffer (TempDevicePath, FullPath, FileSize);
-          FreePool (TempDevicePath);
-
-          if (FileBuffer != NULL) {
-            //
-            // Adjust the 'HDDP' instances sequence if the matched one is not first one.
-            //
-            if (NeedAdjust) {
-              BmCachePartitionDevicePath (&CachedDevicePath, Instance);
-              //
-              // Save the matching Device Path so we don't need to do a connect all next time
-              // Failing to save only impacts performance next time expanding the short-form device path
-              //
-              Status = gRT->SetVariable (
-                L"HDDP",
-                &mBmHardDriveBootVariableGuid,
-                EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
-                GetDevicePathSize (CachedDevicePath),
-                CachedDevicePath
-                );
-            }
-
-            FreePool (Instance);
-            FreePool (CachedDevicePath);
-            return FileBuffer;
-          }
-        }
-      }
-      //
-      // Come here means the first instance is not matched
-      //
-      NeedAdjust = TRUE;
-      FreePool(Instance);
-    } while (TempNewDevicePath != NULL);
-  }
-
-  //
-  // If we get here we fail to find or 'HDDP' not exist, and now we need
-  // to search all devices in the system for a matched partition
-  //
-  EfiBootManagerConnectAll ();
-  Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &BlockIoHandleCount, &BlockIoBuffer);
-  if (EFI_ERROR (Status)) {
-    BlockIoHandleCount = 0;
-    BlockIoBuffer      = NULL;
-  }
-  //
-  // Loop through all the device handles that support the BLOCK_IO Protocol
-  //
-  for (Index = 0; Index < BlockIoHandleCount; Index++) {
-    BlockIoDevicePath = DevicePathFromHandle (BlockIoBuffer[Index]);
-    if (BlockIoDevicePath == NULL) {
-      continue;
-    }
-
-    if (BmMatchPartitionDevicePathNode (BlockIoDevicePath, (HARDDRIVE_DEVICE_PATH *) FilePath)) {
-      //
-      // Find the matched partition device path
-      //
-      TempDevicePath = AppendDevicePath (BlockIoDevicePath, NextDevicePathNode (FilePath));
-      FileBuffer = BmGetLoadOptionBuffer (TempDevicePath, FullPath, FileSize);
-      FreePool (TempDevicePath);
-
-      if (FileBuffer != NULL) {
-        BmCachePartitionDevicePath (&CachedDevicePath, BlockIoDevicePath);
-
-        //
-        // Save the matching Device Path so we don't need to do a connect all next time
-        // Failing to save only impacts performance next time expanding the short-form device path
-        //
-        Status = gRT->SetVariable (
-                        L"HDDP",
-                        &mBmHardDriveBootVariableGuid,
-                        EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
-                        GetDevicePathSize (CachedDevicePath),
-                        CachedDevicePath
-                        );
-
-        break;
-      }
-    }
-  }
-
-  if (CachedDevicePath != NULL) {
-    FreePool (CachedDevicePath);
-  }
-  if (BlockIoBuffer != NULL) {
-    FreePool (BlockIoBuffer);
-  }
-  return FileBuffer;
-}
-
-/**
-  Expand the media device path which points to a BlockIo or SimpleFileSystem instance
-  by appending EFI_REMOVABLE_MEDIA_FILE_NAME.
-
-  @param DevicePath  The media device path pointing to a BlockIo or SimpleFileSystem instance.
-  @param FullPath    Return the full device path pointing to the load option.
-  @param FileSize    Return the size of the load option.
-
-  @return  The load option buffer.
-**/
-VOID *
-BmExpandMediaDevicePath (
-  IN  EFI_DEVICE_PATH_PROTOCOL        *DevicePath,
-  OUT EFI_DEVICE_PATH_PROTOCOL        **FullPath,
-  OUT UINTN                           *FileSize
-  )
-{
-  EFI_STATUS                          Status;
-  EFI_HANDLE                          Handle;
-  EFI_BLOCK_IO_PROTOCOL               *BlockIo;
-  VOID                                *Buffer;
-  EFI_DEVICE_PATH_PROTOCOL            *TempDevicePath;
-  UINTN                               Size;
-  UINTN                               TempSize;
-  EFI_HANDLE                          *SimpleFileSystemHandles;
-  UINTN                               NumberSimpleFileSystemHandles;
-  UINTN                               Index;
-  VOID                                *FileBuffer;
-  UINT32                              AuthenticationStatus;
-
-  //
-  // Check whether the device is connected
-  //
-  TempDevicePath = DevicePath;
-  Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &TempDevicePath, &Handle);
-  if (!EFI_ERROR (Status)) {
-    ASSERT (IsDevicePathEnd (TempDevicePath));
-
-    TempDevicePath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME);
-    FileBuffer = GetFileBufferByFilePath (TRUE, TempDevicePath, FileSize, &AuthenticationStatus);
-    if (FileBuffer == NULL) {
-      FreePool (TempDevicePath);
-      TempDevicePath = NULL;
-    }
-    *FullPath = TempDevicePath;
-    return FileBuffer;
-  }
-
-  //
-  // For device boot option only pointing to the removable device handle, 
-  // should make sure all its children handles (its child partion or media handles) are created and connected. 
-  //
-  gBS->ConnectController (Handle, NULL, NULL, TRUE);
-
-  //
-  // Issue a dummy read to the device to check for media change.
-  // When the removable media is changed, any Block IO read/write will
-  // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is
-  // returned. After the Block IO protocol is reinstalled, subsequent
-  // Block IO read/write will success.
-  //
-  Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, &Handle);
-  ASSERT_EFI_ERROR (Status);
-  Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
-  ASSERT_EFI_ERROR (Status);
-  Buffer = AllocatePool (BlockIo->Media->BlockSize);
-  if (Buffer != NULL) {
-    BlockIo->ReadBlocks (
-      BlockIo,
-      BlockIo->Media->MediaId,
-      0,
-      BlockIo->Media->BlockSize,
-      Buffer
-      );
-    FreePool (Buffer);
-  }
-
-  //
-  // Detect the the default boot file from removable Media
-  //
-  FileBuffer = NULL;
-  *FullPath = NULL;
-  Size = GetDevicePathSize (DevicePath) - END_DEVICE_PATH_LENGTH;
-  gBS->LocateHandleBuffer (
-         ByProtocol,
-         &gEfiSimpleFileSystemProtocolGuid,
-         NULL,
-         &NumberSimpleFileSystemHandles,
-         &SimpleFileSystemHandles
-         );
-  for (Index = 0; Index < NumberSimpleFileSystemHandles; Index++) {
-    //
-    // Get the device path size of SimpleFileSystem handle
-    //
-    TempDevicePath = DevicePathFromHandle (SimpleFileSystemHandles[Index]);
-    TempSize = GetDevicePathSize (TempDevicePath) - END_DEVICE_PATH_LENGTH;
-    //
-    // Check whether the device path of boot option is part of the SimpleFileSystem handle's device path
-    //
-    if ((Size <= TempSize) && (CompareMem (TempDevicePath, DevicePath, Size) == 0)) {
-      TempDevicePath = FileDevicePath (SimpleFileSystemHandles[Index], EFI_REMOVABLE_MEDIA_FILE_NAME);
-      FileBuffer = GetFileBufferByFilePath (TRUE, TempDevicePath, FileSize, &AuthenticationStatus);
-      if (FileBuffer != NULL) {
-        *FullPath = TempDevicePath;
-        break;
-      }
-      FreePool (TempDevicePath);
-    }
-  }
-
-  if (SimpleFileSystemHandles != NULL) {
-    FreePool (SimpleFileSystemHandles);
-  }
-
-  return FileBuffer;
-}
-
-/**
-  Get the load option by its device path.
-
-  @param FilePath  The device path pointing to a load option.
-                   It could be a short-form device path.
-  @param FullPath  Return the full device path of the load option after
-                   short-form device path expanding.
-                   Caller is responsible to free it.
-  @param FileSize  Return the load option size.
-
-  @return The load option buffer. Caller is responsible to free the memory.
-**/
-VOID *
-BmGetLoadOptionBuffer (
-  IN  EFI_DEVICE_PATH_PROTOCOL          *FilePath,
-  OUT EFI_DEVICE_PATH_PROTOCOL          **FullPath,
-  OUT UINTN                             *FileSize
-  )
-{
-  EFI_HANDLE                      Handle;
-  VOID                            *FileBuffer;
-  UINT32                          AuthenticationStatus;
-  EFI_DEVICE_PATH_PROTOCOL        *Node;
-  EFI_STATUS                      Status;
-
-  ASSERT ((FilePath != NULL) && (FullPath != NULL) && (FileSize != NULL));
-
-  EfiBootManagerConnectDevicePath (FilePath, NULL);
-
-  *FullPath  = NULL;
-  *FileSize  = 0;
-  FileBuffer = NULL;
-
-  //
-  // Boot from media device by adding a default file name \EFI\BOOT\BOOT{machine type short-name}.EFI
-  //
-  Node = FilePath;
-  Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &Node, &Handle);
-  if (EFI_ERROR (Status)) {
-    Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &Node, &Handle);
-  }
-
-  if (!EFI_ERROR (Status) && IsDevicePathEnd (Node)) {
-    return BmExpandMediaDevicePath (FilePath, FullPath, FileSize);
-  }
-
-  //
-  // Expand the short-form device path to full device path
-  //
-  if ((DevicePathType (FilePath) == MEDIA_DEVICE_PATH) &&
-      (DevicePathSubType (FilePath) == MEDIA_HARDDRIVE_DP)) {
-    //
-    // Expand the Harddrive device path
-    //
-    return BmExpandPartitionDevicePath (FilePath, FullPath, FileSize);
-  } else {
-    for (Node = FilePath; !IsDevicePathEnd (Node); Node = NextDevicePathNode (Node)) {
-      if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) &&
-          ((DevicePathSubType (Node) == MSG_USB_CLASS_DP) || (DevicePathSubType (Node) == MSG_USB_WWID_DP))) {
-        break;
-      }
-    }
-
-    if (!IsDevicePathEnd (Node)) {
-      //
-      // Expand the USB WWID/Class device path
-      //
-      FileBuffer = BmExpandUsbDevicePath (FilePath, FullPath, FileSize, Node);
-      if ((FileBuffer == NULL) && (FilePath == Node)) {
-        //
-        // Boot Option device path starts with USB Class or USB WWID device path.
-        // For Boot Option device path which doesn't begin with the USB Class or
-        // USB WWID device path, it's not needed to connect again here.
-        //
-        BmConnectUsbShortFormDevicePath (FilePath);
-        FileBuffer = BmExpandUsbDevicePath (FilePath, FullPath, FileSize, Node);
-      }
-      return FileBuffer;
-    }
-  }
-
-  //
-  // Fix up the boot option path if it points to a FV in memory map style of device path
-  //
-  if (BmIsMemmapFvFilePath (FilePath)) {
-    return BmGetFileBufferByMemmapFv (FilePath, FullPath, FileSize);
-  }
-
-  //
-  // Directly reads the load option when it doesn't reside in simple file system instance (LoadFile/LoadFile2),
-  //   or it directly points to a file in simple file system instance.
-  //
-  FileBuffer = GetFileBufferByFilePath (TRUE, FilePath, FileSize, &AuthenticationStatus);
-  if (FileBuffer != NULL) {
-    *FullPath = DuplicateDevicePath (FilePath);
-  }
-
-  return FileBuffer;
-}
-
-/**
-  Attempt to boot the EFI boot option. This routine sets L"BootCurent" and
-  also signals the EFI ready to boot event. If the device path for the option
-  starts with a BBS device path a legacy boot is attempted via the registered 
-  gLegacyBoot function. Short form device paths are also supported via this 
-  rountine. A device path starting with MEDIA_HARDDRIVE_DP, MSG_USB_WWID_DP,
-  MSG_USB_CLASS_DP gets expaned out to find the first device that matches.
-  If the BootOption Device Path fails the removable media boot algorithm 
-  is attempted (\EFI\BOOTIA32.EFI, \EFI\BOOTX64.EFI,... only one file type 
-  is tried per processor type)
-
-  @param  BootOption    Boot Option to try and boot.
-                        On return, BootOption->Status contains the boot status.
-                        EFI_SUCCESS     BootOption was booted
-                        EFI_UNSUPPORTED A BBS device path was found with no valid callback
-                                        registered via EfiBootManagerInitialize().
-                        EFI_NOT_FOUND   The BootOption was not found on the system
-                        !EFI_SUCCESS    BootOption failed with this error status
-
-**/
-VOID
-EFIAPI
-EfiBootManagerBoot (
-  IN  EFI_BOOT_MANAGER_LOAD_OPTION             *BootOption
-  )
-{
-  EFI_STATUS                Status;
-  EFI_HANDLE                ImageHandle;
-  EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;
-  UINT16                    Uint16;
-  UINTN                     OptionNumber;
-  UINTN                     OriginalOptionNumber;
-  EFI_DEVICE_PATH_PROTOCOL  *FilePath;
-  EFI_DEVICE_PATH_PROTOCOL  *Node;
-  EFI_HANDLE                FvHandle;
-  VOID                      *FileBuffer;
-  UINTN                     FileSize;
-  EFI_BOOT_LOGO_PROTOCOL    *BootLogo;
-  EFI_EVENT                 LegacyBootEvent;
-
-  if (BootOption == NULL) {
-    return;
-  }
-
-  if (BootOption->FilePath == NULL || BootOption->OptionType != LoadOptionTypeBoot) {
-    BootOption->Status = EFI_INVALID_PARAMETER;
-    return;
-  }
-
-  //
-  // 1. Create Boot#### for a temporary boot if there is no match Boot#### (i.e. a boot by selected a EFI Shell using "Boot From File")
-  //
-  OptionNumber = BmFindBootOptionInVariable (BootOption);
-  if (OptionNumber == LoadOptionNumberUnassigned) {
-    Status = BmGetFreeOptionNumber (LoadOptionTypeBoot, &Uint16);
-    if (!EFI_ERROR (Status)) {
-      //
-      // Save the BootOption->OptionNumber to restore later
-      //
-      OptionNumber             = Uint16;
-      OriginalOptionNumber     = BootOption->OptionNumber;
-      BootOption->OptionNumber = OptionNumber;
-      Status = EfiBootManagerLoadOptionToVariable (BootOption);
-      BootOption->OptionNumber = OriginalOptionNumber;
-    }
-
-    if (EFI_ERROR (Status)) {
-      DEBUG ((EFI_D_ERROR, "[Bds] Failed to create Boot#### for a temporary boot - %r!\n", Status));
-      BootOption->Status = Status;
-      return ;
-    }
-  }
-
-  //
-  // 2. Set BootCurrent
-  //
-  Uint16 = (UINT16) OptionNumber;
-  BmSetVariableAndReportStatusCodeOnError (
-    L"BootCurrent",
-    &gEfiGlobalVariableGuid,
-    EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
-    sizeof (UINT16),
-    &Uint16
-    );
-
-  //
-  // 3. Signal the EVT_SIGNAL_READY_TO_BOOT event when we are about to load and execute
-  //    the boot option.
-  //
-  Node   = BootOption->FilePath;
-  Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &Node, &FvHandle);
-  if (!EFI_ERROR (Status) && CompareGuid (
-        EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) Node),
-        PcdGetPtr (PcdBootManagerMenuFile)
-        )) {
-    DEBUG ((EFI_D_INFO, "[Bds] Booting Boot Manager Menu.\n"));
-    BmStopHotkeyService (NULL, NULL);
-  } else {
-    EfiSignalEventReadyToBoot();
-    //
-    // Report Status Code to indicate ReadyToBoot was signalled
-    //
-    REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT));
-    //
-    // 4. Repair system through DriverHealth protocol
-    //
-    BmRepairAllControllers ();
-  }
-
-  PERF_START_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32) OptionNumber);
-
-  //
-  // 5. Load EFI boot option to ImageHandle
-  //
-  ImageHandle = NULL;
-  if (DevicePathType (BootOption->FilePath) != BBS_DEVICE_PATH) {
-    Status     = EFI_NOT_FOUND;
-    FileBuffer = BmGetLoadOptionBuffer (BootOption->FilePath, &FilePath, &FileSize);
-    DEBUG_CODE (
-      if (FileBuffer != NULL && CompareMem (BootOption->FilePath, FilePath, GetDevicePathSize (FilePath)) != 0) {
-        DEBUG ((EFI_D_INFO, "[Bds] DevicePath expand: "));
-        BmPrintDp (BootOption->FilePath);
-        DEBUG ((EFI_D_INFO, " -> "));
-        BmPrintDp (FilePath);
-        DEBUG ((EFI_D_INFO, "\n"));
-      }
-    );
-    if (BmIsLoadOptionPeHeaderValid (BootOption->OptionType, FileBuffer, FileSize)) {
-      REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderLoad));
-      Status = gBS->LoadImage (
-                      TRUE,
-                      gImageHandle,
-                      FilePath,
-                      FileBuffer,
-                      FileSize,
-                      &ImageHandle
-                      );
-    }
-    if (FileBuffer != NULL) {
-      FreePool (FileBuffer);
-    }
-    if (FilePath != NULL) {
-      FreePool (FilePath);
-    }
-
-    if (EFI_ERROR (Status)) {
-      //
-      // Report Status Code to indicate that the failure to load boot option
-      //
-      REPORT_STATUS_CODE (
-        EFI_ERROR_CODE | EFI_ERROR_MINOR,
-        (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR)
-        );
-      BootOption->Status = Status;
-      return;
-    }
-  }
-
-  //
-  // 6. Adjust the different type memory page number just before booting
-  //    and save the updated info into the variable for next boot to use
-  //
-  if ((BootOption->Attributes & LOAD_OPTION_CATEGORY) == LOAD_OPTION_CATEGORY_BOOT) {
-    if (PcdGetBool (PcdResetOnMemoryTypeInformationChange)) {
-      BmSetMemoryTypeInformationVariable ();
-    }
-  }
-
-  DEBUG_CODE_BEGIN();
-    if (BootOption->Description == NULL) {
-      DEBUG ((DEBUG_INFO | DEBUG_LOAD, "[Bds]Booting from unknown device path\n"));
-    } else {
-      DEBUG ((DEBUG_INFO | DEBUG_LOAD, "[Bds]Booting %s\n", BootOption->Description));
-    }
-  DEBUG_CODE_END();
-
-  //
-  // Check to see if we should legacy BOOT. If yes then do the legacy boot
-  // Write boot to OS performance data for Legacy boot
-  //
-  if ((DevicePathType (BootOption->FilePath) == BBS_DEVICE_PATH) && (DevicePathSubType (BootOption->FilePath) == BBS_BBS_DP)) {
-    if (mBmLegacyBoot != NULL) {
-      //
-      // Write boot to OS performance data for legacy boot.
-      //
-      PERF_CODE (
-        //
-        // Create an event to be signalled when Legacy Boot occurs to write performance data.
-        //
-        Status = EfiCreateEventLegacyBootEx(
-                   TPL_NOTIFY,
-                   BmWriteBootToOsPerformanceData,
-                   NULL, 
-                   &LegacyBootEvent
-                   );
-        ASSERT_EFI_ERROR (Status);
-      );
-
-      mBmLegacyBoot (BootOption);
-    } else {
-      BootOption->Status = EFI_UNSUPPORTED;
-    }
-
-    PERF_END_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32) OptionNumber);
-    return;
-  }
-  //
-  // Provide the image with its load options
-  //
-  Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);
-  ASSERT_EFI_ERROR (Status);
-
-  ImageInfo->LoadOptionsSize  = BootOption->OptionalDataSize;
-  ImageInfo->LoadOptions      = BootOption->OptionalData;
-
-  //
-  // Clean to NULL because the image is loaded directly from the firmwares boot manager.
-  //
-  ImageInfo->ParentHandle = NULL;
-
-  //
-  // Before calling the image, enable the Watchdog Timer for 5 minutes period
-  //
-  gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);
-
-  //
-  // Write boot to OS performance data for UEFI boot
-  //
-  PERF_CODE (
-    BmWriteBootToOsPerformanceData (NULL, NULL);
-  );
-
-  REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderStart));
-
-  Status = gBS->StartImage (ImageHandle, &BootOption->ExitDataSize, &BootOption->ExitData);
-  DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Image Return Status = %r\n", Status));
-  BootOption->Status = Status;
-  if (EFI_ERROR (Status)) {
-    //
-    // Report Status Code to indicate that boot failure
-    //
-    REPORT_STATUS_CODE (
-      EFI_ERROR_CODE | EFI_ERROR_MINOR,
-      (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED)
-      );
-  }
-  PERF_END_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32) OptionNumber);
-
-  //
-  // Clear the Watchdog Timer after the image returns
-  //
-  gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
-
-  //
-  // Set Logo status invalid after trying one boot option
-  //
-  BootLogo = NULL;
-  Status = gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo);
-  if (!EFI_ERROR (Status) && (BootLogo != NULL)) {
-    Status = BootLogo->SetBootLogo (BootLogo, NULL, 0, 0, 0, 0);
-    ASSERT_EFI_ERROR (Status);
-  }
-
-  //
-  // Clear Boot Current
-  //
-  Status = gRT->SetVariable (
-                  L"BootCurrent",
-                  &gEfiGlobalVariableGuid,
-                  0,
-                  0,
-                  NULL
-                  );
-  //
-  // Deleting variable with current variable implementation shouldn't fail.
-  // When BootXXXX (e.g.: BootManagerMenu) boots BootYYYY, exiting BootYYYY causes BootCurrent deleted,
-  // exiting BootXXXX causes deleting BootCurrent returns EFI_NOT_FOUND.
-  //
-  ASSERT (Status == EFI_SUCCESS || Status == EFI_NOT_FOUND);
-}
-
-/**
-  Check whether there is a instance in BlockIoDevicePath, which contain multi device path
-  instances, has the same partition node with HardDriveDevicePath device path
-
-  @param  BlockIoDevicePath      Multi device path instances which need to check
-  @param  HardDriveDevicePath    A device path which starts with a hard drive media
-                                 device path.
-
-  @retval TRUE                   There is a matched device path instance.
-  @retval FALSE                  There is no matched device path instance.
-
-**/
-BOOLEAN
-BmMatchPartitionDevicePathNode (
-  IN  EFI_DEVICE_PATH_PROTOCOL   *BlockIoDevicePath,
-  IN  HARDDRIVE_DEVICE_PATH      *HardDriveDevicePath
-  )
-{
-  HARDDRIVE_DEVICE_PATH     *Node;
-
-  if ((BlockIoDevicePath == NULL) || (HardDriveDevicePath == NULL)) {
-    return FALSE;
-  }
-
-  //
-  // find the partition device path node
-  //
-  while (!IsDevicePathEnd (BlockIoDevicePath)) {
-    if ((DevicePathType (BlockIoDevicePath) == MEDIA_DEVICE_PATH) &&
-        (DevicePathSubType (BlockIoDevicePath) == MEDIA_HARDDRIVE_DP)
-        ) {
-      break;
-    }
-
-    BlockIoDevicePath = NextDevicePathNode (BlockIoDevicePath);
-  }
-
-  if (IsDevicePathEnd (BlockIoDevicePath)) {
-    return FALSE;
-  }
-
-  //
-  // See if the harddrive device path in blockio matches the orig Hard Drive Node
-  //
-  Node = (HARDDRIVE_DEVICE_PATH *) BlockIoDevicePath;
-
-  //
-  // Match Signature and PartitionNumber.
-  // Unused bytes in Signature are initiaized with zeros.
-  //
-  return (BOOLEAN) (
-    (Node->PartitionNumber == HardDriveDevicePath->PartitionNumber) &&
-    (Node->MBRType == HardDriveDevicePath->MBRType) &&
-    (Node->SignatureType == HardDriveDevicePath->SignatureType) &&
-    (CompareMem (Node->Signature, HardDriveDevicePath->Signature, sizeof (Node->Signature)) == 0)
-    );
-}
-
-/**
-  Emuerate all possible bootable medias in the following order:
-  1. Removable BlockIo            - The boot option only points to the removable media
-                                    device, like USB key, DVD, Floppy etc.
-  2. Fixed BlockIo                - The boot option only points to a Fixed blockIo device,
-                                    like HardDisk.
-  3. Non-BlockIo SimpleFileSystem - The boot option points to a device supporting
-                                    SimpleFileSystem Protocol, but not supporting BlockIo
-                                    protocol.
-  4. LoadFile                     - The boot option points to the media supporting 
-                                    LoadFile protocol.
-  Reference: UEFI Spec chapter 3.3 Boot Option Variables Default Boot Behavior
-
-  @param BootOptionCount   Return the boot option count which has been found.
-
-  @retval   Pointer to the boot option array.
-**/
-EFI_BOOT_MANAGER_LOAD_OPTION *
-BmEnumerateBootOptions (
-  UINTN                                 *BootOptionCount
-  )
-{
-  EFI_STATUS                            Status;
-  EFI_BOOT_MANAGER_LOAD_OPTION          *BootOptions;
-  UINT16                                NonBlockNumber;
-  UINTN                                 HandleCount;
-  EFI_HANDLE                            *Handles;
-  EFI_BLOCK_IO_PROTOCOL                 *BlkIo;
-  UINTN                                 Removable;
-  UINTN                                 Index;
-  UINTN                                 FunctionIndex;
-  CHAR16                                *Temp;
-  CHAR16                                *DescriptionPtr;
-  CHAR16                                Description[30];
-
-  ASSERT (BootOptionCount != NULL);
-
-  *BootOptionCount = 0;
-  BootOptions      = NULL;
-
-  //
-  // Parse removable block io followed by fixed block io
-  //
-  gBS->LocateHandleBuffer (
-         ByProtocol,
-         &gEfiBlockIoProtocolGuid,
-         NULL,
-         &HandleCount,
-         &Handles
-         );
-
-  for (Removable = 0; Removable < 2; Removable++) {
-    for (Index = 0; Index < HandleCount; Index++) {
-      Status = gBS->HandleProtocol (
-                      Handles[Index],
-                      &gEfiBlockIoProtocolGuid,
-                      (VOID **) &BlkIo
-                      );
-      if (EFI_ERROR (Status)) {
-        continue;
-      }
-
-      //
-      // Skip the logical partitions
-      //
-      if (BlkIo->Media->LogicalPartition) {
-        continue;
-      }
-
-      //
-      // Skip the fixed block io then the removable block io
-      //
-      if (BlkIo->Media->RemovableMedia == ((Removable == 0) ? FALSE : TRUE)) {
-        continue;
-      }
-
-      DescriptionPtr = NULL;
-      for (FunctionIndex = 0; FunctionIndex < sizeof (mBmGetBootDescription) / sizeof (mBmGetBootDescription[0]); FunctionIndex++) {
-        DescriptionPtr = mBmGetBootDescription[FunctionIndex] (Handles[Index]);
-        if (DescriptionPtr != NULL) {
-          break;
-        }
-      }
-
-      if (DescriptionPtr == NULL) {
-        continue;
-      }
-
-      //
-      // Avoid description confusion between UEFI & Legacy boot option by adding "UEFI " prefix
-      //
-      Temp = AllocatePool (StrSize (DescriptionPtr) + sizeof (mBmUefiPrefix)); 
-      ASSERT (Temp != NULL);
-      StrCpy (Temp, mBmUefiPrefix);
-      StrCat (Temp, DescriptionPtr);
-      FreePool (DescriptionPtr);
-      DescriptionPtr = Temp;
-
-      BootOptions = ReallocatePool (
-                      sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),
-                      sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),
-                      BootOptions
-                      );
-      ASSERT (BootOptions != NULL);
-
-      Status = EfiBootManagerInitializeLoadOption (
-                 &BootOptions[(*BootOptionCount)++],
-                 LoadOptionNumberUnassigned,
-                 LoadOptionTypeBoot,
-                 LOAD_OPTION_ACTIVE,
-                 DescriptionPtr,
-                 DevicePathFromHandle (Handles[Index]),
-                 NULL,
-                 0
-                 );
-      ASSERT_EFI_ERROR (Status);
-
-      FreePool (DescriptionPtr);
-    }
-  }
-
-  if (HandleCount != 0) {
-    FreePool (Handles);
-  }
-
-  //
-  // Parse simple file system not based on block io
-  //
-  NonBlockNumber = 0;
-  gBS->LocateHandleBuffer (
-         ByProtocol,
-         &gEfiSimpleFileSystemProtocolGuid,
-         NULL,
-         &HandleCount,
-         &Handles
-         );
-  for (Index = 0; Index < HandleCount; Index++) {
-    Status = gBS->HandleProtocol (
-                    Handles[Index],
-                    &gEfiBlockIoProtocolGuid,
-                    (VOID **) &BlkIo
-                    );
-     if (!EFI_ERROR (Status)) {
-      //
-      //  Skip if the file system handle supports a BlkIo protocol, which we've handled in above
-      //
-      continue;
-    }
-    UnicodeSPrint (Description, sizeof (Description), NonBlockNumber > 0 ? L"%s %d" : L"%s", L"UEFI Non-Block Boot Device", NonBlockNumber);
-    
-    BootOptions = ReallocatePool (
-                    sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),
-                    sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),
-                    BootOptions
-                    );
-    ASSERT (BootOptions != NULL);
-
-    Status = EfiBootManagerInitializeLoadOption (
-               &BootOptions[(*BootOptionCount)++],
-               LoadOptionNumberUnassigned,
-               LoadOptionTypeBoot,
-               LOAD_OPTION_ACTIVE,
-               Description,
-               DevicePathFromHandle (Handles[Index]),
-               NULL,
-               0
-               );
-    ASSERT_EFI_ERROR (Status);
-  }
-
-  if (HandleCount != 0) {
-    FreePool (Handles);
-  }
-
-  //
-  // Parse load file, assuming UEFI Network boot option
-  //
-  gBS->LocateHandleBuffer (
-         ByProtocol,
-         &gEfiLoadFileProtocolGuid,
-         NULL,
-         &HandleCount,
-         &Handles
-         );
-  for (Index = 0; Index < HandleCount; Index++) {
-
-    UnicodeSPrint (Description, sizeof (Description), Index > 0 ? L"%s %d" : L"%s", L"UEFI Network", Index);
-
-    BootOptions = ReallocatePool (
-                    sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),
-                    sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),
-                    BootOptions
-                    );
-    ASSERT (BootOptions != NULL);
-
-    Status = EfiBootManagerInitializeLoadOption (
-               &BootOptions[(*BootOptionCount)++],
-               LoadOptionNumberUnassigned,
-               LoadOptionTypeBoot,
-               LOAD_OPTION_ACTIVE,
-               Description,
-               DevicePathFromHandle (Handles[Index]),
-               NULL,
-               0
-               );
-    ASSERT_EFI_ERROR (Status);
-  }
-
-  if (HandleCount != 0) {
-    FreePool (Handles);
-  }
-
-  return BootOptions;
-}
-
-/**
-  The function enumerates all boot options, creates them and registers them in the BootOrder variable.
-**/
-VOID
-EFIAPI
-EfiBootManagerRefreshAllBootOption (
-  VOID
-  )
-{
-  EFI_STATUS                    Status;
-  EFI_BOOT_MANAGER_LOAD_OPTION  *NvBootOptions;
-  UINTN                         NvBootOptionCount;
-  EFI_BOOT_MANAGER_LOAD_OPTION  *BootOptions;
-  UINTN                         BootOptionCount;
-  UINTN                         Index;
-
-  //
-  // Optionally refresh the legacy boot option
-  //
-  if (mBmRefreshLegacyBootOption != NULL) {
-    mBmRefreshLegacyBootOption ();
-  }
-
-  BootOptions   = BmEnumerateBootOptions (&BootOptionCount);
-  NvBootOptions = EfiBootManagerGetLoadOptions (&NvBootOptionCount, LoadOptionTypeBoot);
-
-  //
-  // Mark the boot option as added by BDS by setting OptionalData to a special GUID
-  //
-  for (Index = 0; Index < BootOptionCount; Index++) {
-    BootOptions[Index].OptionalData     = AllocateCopyPool (sizeof (EFI_GUID), &mBmAutoCreateBootOptionGuid);
-    BootOptions[Index].OptionalDataSize = sizeof (EFI_GUID);
-  }
-
-  //
-  // Remove invalid EFI boot options from NV
-  //
-  for (Index = 0; Index < NvBootOptionCount; Index++) {
-    if (((DevicePathType (NvBootOptions[Index].FilePath) != BBS_DEVICE_PATH) || 
-         (DevicePathSubType (NvBootOptions[Index].FilePath) != BBS_BBS_DP)
-        ) &&
-        (NvBootOptions[Index].OptionalDataSize == sizeof (EFI_GUID)) &&
-        CompareGuid ((EFI_GUID *) NvBootOptions[Index].OptionalData, &mBmAutoCreateBootOptionGuid)
-       ) {
-      //
-      // Only check those added by BDS
-      // so that the boot options added by end-user or OS installer won't be deleted
-      //
-      if (BmFindLoadOption (&NvBootOptions[Index], BootOptions, BootOptionCount) == (UINTN) -1) {
-        Status = EfiBootManagerDeleteLoadOptionVariable (NvBootOptions[Index].OptionNumber, LoadOptionTypeBoot);
-        //
-        // Deleting variable with current variable implementation shouldn't fail.
-        //
-        ASSERT_EFI_ERROR (Status);
-      }
-    }
-  }
-
-  //
-  // Add new EFI boot options to NV
-  //
-  for (Index = 0; Index < BootOptionCount; Index++) {
-    if (BmFindLoadOption (&BootOptions[Index], NvBootOptions, NvBootOptionCount) == (UINTN) -1) {
-      EfiBootManagerAddLoadOptionVariable (&BootOptions[Index], (UINTN) -1);
-      //
-      // Try best to add the boot options so continue upon failure.
-      //
-    }
-  }
-
-  EfiBootManagerFreeLoadOptions (BootOptions,   BootOptionCount);
-  EfiBootManagerFreeLoadOptions (NvBootOptions, NvBootOptionCount);
-}
-
-/**
-  This function is called to create the boot option for the Boot Manager Menu.
-
-  The Boot Manager Menu is shown after successfully booting a boot option.
-  Assume the BootManagerMenuFile is in the same FV as the module links to this library.
-
-  @param  BootOption    Return the boot option of the Boot Manager Menu
-
-  @retval EFI_SUCCESS   Successfully register the Boot Manager Menu.
-  @retval Status        Return status of gRT->SetVariable (). BootOption still points
-                        to the Boot Manager Menu even the Status is not EFI_SUCCESS.
-**/
-EFI_STATUS
-BmRegisterBootManagerMenu (
-  OUT EFI_BOOT_MANAGER_LOAD_OPTION   *BootOption
-  )
-{
-  EFI_STATUS                         Status;
-  CHAR16                             *Description;
-  UINTN                              DescriptionLength;
-  EFI_DEVICE_PATH_PROTOCOL           *DevicePath;
-  EFI_LOADED_IMAGE_PROTOCOL          *LoadedImage;
-  MEDIA_FW_VOL_FILEPATH_DEVICE_PATH  FileNode;
-
-  Status = GetSectionFromFv (
-             PcdGetPtr (PcdBootManagerMenuFile),
-             EFI_SECTION_USER_INTERFACE,
-             0,
-             (VOID **) &Description,
-             &DescriptionLength
-             );
-  if (EFI_ERROR (Status)) {
-    Description = NULL;
-  }
-
-  EfiInitializeFwVolDevicepathNode (&FileNode, PcdGetPtr (PcdBootManagerMenuFile));
-  Status = gBS->HandleProtocol (
-                  gImageHandle,
-                  &gEfiLoadedImageProtocolGuid,
-                  (VOID **) &LoadedImage
-                  );
-  ASSERT_EFI_ERROR (Status);
-  DevicePath = AppendDevicePathNode (
-                 DevicePathFromHandle (LoadedImage->DeviceHandle),
-                 (EFI_DEVICE_PATH_PROTOCOL *) &FileNode
-                 );
-  ASSERT (DevicePath != NULL);
-
-  Status = EfiBootManagerInitializeLoadOption (
-             BootOption,
-             LoadOptionNumberUnassigned,
-             LoadOptionTypeBoot,
-             LOAD_OPTION_CATEGORY_APP | LOAD_OPTION_ACTIVE | LOAD_OPTION_HIDDEN,
-             (Description != NULL) ? Description : L"Boot Manager Menu",
-             DevicePath,
-             NULL,
-             0
-             );
-  ASSERT_EFI_ERROR (Status);
-  FreePool (DevicePath);
-  if (Description != NULL) {
-    FreePool (Description);
-  }
-
-  DEBUG_CODE (
-    EFI_BOOT_MANAGER_LOAD_OPTION    *BootOptions;
-    UINTN                           BootOptionCount;
-
-    BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
-    ASSERT (BmFindLoadOption (BootOption, BootOptions, BootOptionCount) == -1);
-    EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
-    );
-
-  return EfiBootManagerAddLoadOptionVariable (BootOption, 0);
-}
-
-/**
-  Return the boot option corresponding to the Boot Manager Menu.
-  It may automatically create one if the boot option hasn't been created yet.
-  
-  @param BootOption    Return the Boot Manager Menu.
-
-  @retval EFI_SUCCESS   The Boot Manager Menu is successfully returned.
-  @retval Status        Return status of gRT->SetVariable (). BootOption still points
-                        to the Boot Manager Menu even the Status is not EFI_SUCCESS.
-**/
-EFI_STATUS
-EFIAPI
-EfiBootManagerGetBootManagerMenu (
-  EFI_BOOT_MANAGER_LOAD_OPTION *BootOption
-  )
-{
-  EFI_STATUS                   Status;
-  UINTN                        BootOptionCount;
-  EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
-  UINTN                        Index;
-  EFI_DEVICE_PATH_PROTOCOL     *Node;
-  EFI_HANDLE                   FvHandle;
-  
-  BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
-
-  for (Index = 0; Index < BootOptionCount; Index++) {
-    Node   = BootOptions[Index].FilePath;
-    Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &Node, &FvHandle);
-    if (!EFI_ERROR (Status)) {
-      if (CompareGuid (
-            EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) Node),
-            PcdGetPtr (PcdBootManagerMenuFile)
-            )
-          ) {        
-        Status = EfiBootManagerInitializeLoadOption (
-                   BootOption,
-                   BootOptions[Index].OptionNumber,
-                   BootOptions[Index].OptionType,
-                   BootOptions[Index].Attributes,
-                   BootOptions[Index].Description,
-                   BootOptions[Index].FilePath,
-                   BootOptions[Index].OptionalData,
-                   BootOptions[Index].OptionalDataSize
-                   );
-        ASSERT_EFI_ERROR (Status);
-        break;
-      }
-    }
-  }
-
-  EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
-
-  //
-  // Automatically create the Boot#### for Boot Manager Menu when not found.
-  //
-  if (Index == BootOptionCount) {
-    return BmRegisterBootManagerMenu (BootOption);
-  } else {
-    return EFI_SUCCESS;
-  }
-}
-
+/** @file\r
+  Library functions which relates with booting.\r
+\r
+Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "InternalBm.h"\r
+\r
+#define VENDOR_IDENTIFICATION_OFFSET     3\r
+#define VENDOR_IDENTIFICATION_LENGTH     8\r
+#define PRODUCT_IDENTIFICATION_OFFSET    11\r
+#define PRODUCT_IDENTIFICATION_LENGTH    16\r
+\r
+CONST UINT16 mBmUsbLangId    = 0x0409; // English\r
+CHAR16       mBmUefiPrefix[] = L"UEFI ";\r
+\r
+EFI_BOOT_MANAGER_REFRESH_LEGACY_BOOT_OPTION  mBmRefreshLegacyBootOption = NULL;\r
+EFI_BOOT_MANAGER_LEGACY_BOOT                 mBmLegacyBoot              = NULL;\r
+\r
+///\r
+/// This GUID is used for an EFI Variable that stores the front device pathes\r
+/// for a partial device path that starts with the HD node.\r
+///\r
+EFI_GUID mBmHardDriveBootVariableGuid = { 0xfab7e9e1, 0x39dd, 0x4f2b, { 0x84, 0x08, 0xe2, 0x0e, 0x90, 0x6c, 0xb6, 0xde } };\r
+EFI_GUID mBmAutoCreateBootOptionGuid  = { 0x8108ac4e, 0x9f11, 0x4d59, { 0x85, 0x0e, 0xe2, 0x1a, 0x52, 0x2c, 0x59, 0xb2 } };\r
+\r
+/**\r
+  The function registers the legacy boot support capabilities.\r
+\r
+  @param RefreshLegacyBootOption The function pointer to create all the legacy boot options.\r
+  @param LegacyBoot              The function pointer to boot the legacy boot option.\r
+**/\r
+VOID\r
+EFIAPI\r
+EfiBootManagerRegisterLegacyBootSupport (\r
+  EFI_BOOT_MANAGER_REFRESH_LEGACY_BOOT_OPTION   RefreshLegacyBootOption,\r
+  EFI_BOOT_MANAGER_LEGACY_BOOT                  LegacyBoot\r
+  )\r
+{\r
+  mBmRefreshLegacyBootOption = RefreshLegacyBootOption;\r
+  mBmLegacyBoot              = LegacyBoot;\r
+}\r
+\r
+/**\r
+  For a bootable Device path, return its boot type.\r
+\r
+  @param  DevicePath                   The bootable device Path to check\r
+\r
+  @retval AcpiFloppyBoot               If given device path contains ACPI_DEVICE_PATH type device path node\r
+                                       which HID is floppy device.\r
+  @retval MessageAtapiBoot             If given device path contains MESSAGING_DEVICE_PATH type device path node\r
+                                       and its last device path node's subtype is MSG_ATAPI_DP.\r
+  @retval MessageSataBoot              If given device path contains MESSAGING_DEVICE_PATH type device path node\r
+                                       and its last device path node's subtype is MSG_SATA_DP.\r
+  @retval MessageScsiBoot              If given device path contains MESSAGING_DEVICE_PATH type device path node\r
+                                       and its last device path node's subtype is MSG_SCSI_DP.\r
+  @retval MessageUsbBoot               If given device path contains MESSAGING_DEVICE_PATH type device path node\r
+                                       and its last device path node's subtype is MSG_USB_DP.\r
+  @retval MessageNetworkBoot           If given device path contains MESSAGING_DEVICE_PATH type device path node\r
+                                       and its last device path node's subtype is MSG_MAC_ADDR_DP, MSG_VLAN_DP,\r
+                                       MSG_IPv4_DP or MSG_IPv6_DP.\r
+  @retval UnsupportedBoot              If tiven device path doesn't match the above condition, it's not supported.\r
+\r
+**/\r
+BM_BOOT_TYPE\r
+BmDevicePathType (\r
+  IN  EFI_DEVICE_PATH_PROTOCOL     *DevicePath\r
+  )\r
+{\r
+  EFI_DEVICE_PATH_PROTOCOL      *Node;\r
+  EFI_DEVICE_PATH_PROTOCOL      *NextNode;\r
+\r
+  ASSERT (DevicePath != NULL);\r
+\r
+  for (Node = DevicePath; !IsDevicePathEndType (Node); Node = NextDevicePathNode (Node)) {\r
+    switch (DevicePathType (Node)) {\r
+\r
+      case ACPI_DEVICE_PATH:\r
+        if (EISA_ID_TO_NUM (((ACPI_HID_DEVICE_PATH *) Node)->HID) == 0x0604) {\r
+          return BmAcpiFloppyBoot;\r
+        }\r
+        break;\r
+\r
+      case HARDWARE_DEVICE_PATH:\r
+        if (DevicePathSubType (Node) == HW_CONTROLLER_DP) {\r
+          return BmHardwareDeviceBoot;\r
+        }\r
+        break;\r
+\r
+      case MESSAGING_DEVICE_PATH:\r
+        //\r
+        // Skip LUN device node\r
+        //\r
+        NextNode = Node;\r
+        do {\r
+          NextNode = NextDevicePathNode (NextNode);\r
+        } while (\r
+            (DevicePathType (NextNode) == MESSAGING_DEVICE_PATH) &&\r
+            (DevicePathSubType(NextNode) == MSG_DEVICE_LOGICAL_UNIT_DP)\r
+            );\r
+\r
+        //\r
+        // If the device path not only point to driver device, it is not a messaging device path,\r
+        //\r
+        if (!IsDevicePathEndType (NextNode)) {\r
+          break;\r
+        }\r
+\r
+        switch (DevicePathSubType (Node)) {\r
+        case MSG_ATAPI_DP:\r
+          return BmMessageAtapiBoot;\r
+          break;\r
+\r
+        case MSG_SATA_DP:\r
+          return BmMessageSataBoot;\r
+          break;\r
+\r
+        case MSG_USB_DP:\r
+          return BmMessageUsbBoot;\r
+          break;\r
+\r
+        case MSG_SCSI_DP:\r
+          return BmMessageScsiBoot;\r
+          break;\r
+\r
+        case MSG_MAC_ADDR_DP:\r
+        case MSG_VLAN_DP:\r
+        case MSG_IPv4_DP:\r
+        case MSG_IPv6_DP:\r
+          return BmMessageNetworkBoot;\r
+          break;\r
+        }\r
+    }\r
+  }\r
+\r
+  return BmMiscBoot;\r
+}\r
+\r
+/**\r
+  Find the boot option in the NV storage and return the option number.\r
+\r
+  @param OptionToFind  Boot option to be checked.\r
+\r
+  @return   The option number of the found boot option.\r
+\r
+**/\r
+UINTN\r
+BmFindBootOptionInVariable (\r
+  IN  EFI_BOOT_MANAGER_LOAD_OPTION             *OptionToFind\r
+  )\r
+{\r
+  EFI_STATUS                   Status;\r
+  EFI_BOOT_MANAGER_LOAD_OPTION BootOption;\r
+  UINTN                        OptionNumber;\r
+  CHAR16                       OptionName[BM_OPTION_NAME_LEN];\r
+  EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;\r
+  UINTN                        BootOptionCount;\r
+  UINTN                        Index;\r
+  \r
+  OptionNumber = LoadOptionNumberUnassigned;\r
+\r
+  //\r
+  // Try to match the variable exactly if the option number is assigned\r
+  //\r
+  if (OptionToFind->OptionNumber != LoadOptionNumberUnassigned) {\r
+    UnicodeSPrint (\r
+      OptionName, sizeof (OptionName), L"%s%04x",\r
+      mBmLoadOptionName[OptionToFind->OptionType], OptionToFind->OptionNumber\r
+      );\r
+    Status = EfiBootManagerVariableToLoadOption (OptionName, &BootOption);\r
+\r
+    if (!EFI_ERROR (Status)) {\r
+      ASSERT (OptionToFind->OptionNumber == BootOption.OptionNumber);\r
+      if ((OptionToFind->Attributes == BootOption.Attributes) &&\r
+          (StrCmp (OptionToFind->Description, BootOption.Description) == 0) &&\r
+          (CompareMem (OptionToFind->FilePath, BootOption.FilePath, GetDevicePathSize (OptionToFind->FilePath)) == 0) &&\r
+          (OptionToFind->OptionalDataSize == BootOption.OptionalDataSize) &&\r
+          (CompareMem (OptionToFind->OptionalData, BootOption.OptionalData, OptionToFind->OptionalDataSize) == 0)\r
+         ) {\r
+        OptionNumber = OptionToFind->OptionNumber;\r
+      }\r
+      EfiBootManagerFreeLoadOption (&BootOption);\r
+    }\r
+  }\r
+\r
+  //\r
+  // The option number assigned is either incorrect or unassigned.\r
+  //\r
+  if (OptionNumber == LoadOptionNumberUnassigned) {\r
+    BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);\r
+\r
+    Index = BmFindLoadOption (OptionToFind, BootOptions, BootOptionCount);\r
+    if (Index != -1) {\r
+      OptionNumber = BootOptions[Index].OptionNumber;\r
+    }\r
+\r
+    EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);\r
+  }\r
+\r
+  return OptionNumber;\r
+}\r
+\r
+/**\r
+  Get the file buffer using a Memory Mapped Device Path.\r
+\r
+  FV address may change across reboot. This routine promises the FV file device path is right.\r
+\r
+  @param  DevicePath   The Memory Mapped Device Path to get the file buffer.\r
+  @param  FullPath     Receive the updated FV Device Path pointint to the file.\r
+  @param  FileSize     Receive the file buffer size.\r
+\r
+  @return  The file buffer.\r
+**/\r
+VOID *\r
+BmGetFileBufferByMemmapFv (\r
+  IN EFI_DEVICE_PATH_PROTOCOL      *DevicePath,\r
+  OUT EFI_DEVICE_PATH_PROTOCOL     **FullPath,\r
+  OUT UINTN                        *FileSize\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  UINTN                         Index;\r
+  EFI_DEVICE_PATH_PROTOCOL      *FvFileNode;\r
+  EFI_HANDLE                    FvHandle;\r
+  EFI_LOADED_IMAGE_PROTOCOL     *LoadedImage;\r
+  UINT32                        AuthenticationStatus;\r
+  UINTN                         FvHandleCount;\r
+  EFI_HANDLE                    *FvHandles;\r
+  EFI_DEVICE_PATH_PROTOCOL      *NewDevicePath;\r
+  VOID                          *FileBuffer;\r
+  \r
+  FvFileNode = DevicePath;\r
+  Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &FvFileNode, &FvHandle);\r
+  if (!EFI_ERROR (Status)) {\r
+    FileBuffer = GetFileBufferByFilePath (TRUE, DevicePath, FileSize, &AuthenticationStatus);\r
+    if (FileBuffer != NULL) {\r
+      *FullPath = DuplicateDevicePath (DevicePath);\r
+    }\r
+    return FileBuffer;\r
+  }\r
+\r
+  FvFileNode = NextDevicePathNode (DevicePath);\r
+\r
+  //\r
+  // Firstly find the FV file in current FV\r
+  //\r
+  gBS->HandleProtocol (\r
+         gImageHandle,\r
+         &gEfiLoadedImageProtocolGuid,\r
+         (VOID **) &LoadedImage\r
+         );\r
+  NewDevicePath = AppendDevicePathNode (DevicePathFromHandle (LoadedImage->DeviceHandle), FvFileNode);\r
+  FileBuffer = BmGetFileBufferByMemmapFv (NewDevicePath, FullPath, FileSize);\r
+  FreePool (NewDevicePath);\r
+\r
+  if (FileBuffer != NULL) {\r
+    return FileBuffer;\r
+  }\r
+\r
+  //\r
+  // Secondly find the FV file in all other FVs\r
+  //\r
+  gBS->LocateHandleBuffer (\r
+         ByProtocol,\r
+         &gEfiFirmwareVolume2ProtocolGuid,\r
+         NULL,\r
+         &FvHandleCount,\r
+         &FvHandles\r
+         );\r
+  for (Index = 0; (Index < FvHandleCount) && (FileBuffer == NULL); Index++) {\r
+    if (FvHandles[Index] == LoadedImage->DeviceHandle) {\r
+      //\r
+      // Skip current FV\r
+      //\r
+      continue;\r
+    }\r
+    NewDevicePath = AppendDevicePathNode (DevicePathFromHandle (FvHandles[Index]), FvFileNode);\r
+    FileBuffer = BmGetFileBufferByMemmapFv (NewDevicePath, FullPath, FileSize);\r
+    FreePool (NewDevicePath);\r
+  }\r
+  \r
+  if (FvHandles != NULL) {\r
+    FreePool (FvHandles);\r
+  }\r
+  return FileBuffer;\r
+}\r
+\r
+/**\r
+  Check if it's a Memory Mapped FV Device Path.\r
+  \r
+  The function doesn't garentee the device path points to existing FV file.\r
+\r
+  @param  DevicePath     Input device path.\r
+\r
+  @retval TRUE   The device path is a Memory Mapped FV Device Path.\r
+  @retval FALSE  The device path is NOT a Memory Mapped FV Device Path.\r
+**/\r
+BOOLEAN\r
+BmIsMemmapFvFilePath (\r
+  IN EFI_DEVICE_PATH_PROTOCOL    *DevicePath\r
+  )\r
+{\r
+  EFI_DEVICE_PATH_PROTOCOL   *FileNode;\r
+\r
+  if ((DevicePathType (DevicePath) == HARDWARE_DEVICE_PATH) && (DevicePathSubType (DevicePath) == HW_MEMMAP_DP)) {\r
+    FileNode = NextDevicePathNode (DevicePath);\r
+    if ((DevicePathType (FileNode) == MEDIA_DEVICE_PATH) && (DevicePathSubType (FileNode) == MEDIA_PIWG_FW_FILE_DP)) {\r
+      return IsDevicePathEnd (NextDevicePathNode (FileNode));\r
+    }\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  Check whether a USB device match the specified USB Class device path. This\r
+  function follows "Load Option Processing" behavior in UEFI specification.\r
+\r
+  @param UsbIo       USB I/O protocol associated with the USB device.\r
+  @param UsbClass    The USB Class device path to match.\r
+\r
+  @retval TRUE       The USB device match the USB Class device path.\r
+  @retval FALSE      The USB device does not match the USB Class device path.\r
+\r
+**/\r
+BOOLEAN\r
+BmMatchUsbClass (\r
+  IN EFI_USB_IO_PROTOCOL        *UsbIo,\r
+  IN USB_CLASS_DEVICE_PATH      *UsbClass\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  EFI_USB_DEVICE_DESCRIPTOR     DevDesc;\r
+  EFI_USB_INTERFACE_DESCRIPTOR  IfDesc;\r
+  UINT8                         DeviceClass;\r
+  UINT8                         DeviceSubClass;\r
+  UINT8                         DeviceProtocol;\r
+\r
+  if ((DevicePathType (UsbClass) != MESSAGING_DEVICE_PATH) ||\r
+      (DevicePathSubType (UsbClass) != MSG_USB_CLASS_DP)){\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // Check Vendor Id and Product Id.\r
+  //\r
+  Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);\r
+  if (EFI_ERROR (Status)) {\r
+    return FALSE;\r
+  }\r
+\r
+  if ((UsbClass->VendorId != 0xffff) &&\r
+      (UsbClass->VendorId != DevDesc.IdVendor)) {\r
+    return FALSE;\r
+  }\r
+\r
+  if ((UsbClass->ProductId != 0xffff) &&\r
+      (UsbClass->ProductId != DevDesc.IdProduct)) {\r
+    return FALSE;\r
+  }\r
+\r
+  DeviceClass    = DevDesc.DeviceClass;\r
+  DeviceSubClass = DevDesc.DeviceSubClass;\r
+  DeviceProtocol = DevDesc.DeviceProtocol;\r
+  if (DeviceClass == 0) {\r
+    //\r
+    // If Class in Device Descriptor is set to 0, use the Class, SubClass and\r
+    // Protocol in Interface Descriptor instead.\r
+    //\r
+    Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &IfDesc);\r
+    if (EFI_ERROR (Status)) {\r
+      return FALSE;\r
+    }\r
+\r
+    DeviceClass    = IfDesc.InterfaceClass;\r
+    DeviceSubClass = IfDesc.InterfaceSubClass;\r
+    DeviceProtocol = IfDesc.InterfaceProtocol;\r
+  }\r
+\r
+  //\r
+  // Check Class, SubClass and Protocol.\r
+  //\r
+  if ((UsbClass->DeviceClass != 0xff) &&\r
+      (UsbClass->DeviceClass != DeviceClass)) {\r
+    return FALSE;\r
+  }\r
+\r
+  if ((UsbClass->DeviceSubClass != 0xff) &&\r
+      (UsbClass->DeviceSubClass != DeviceSubClass)) {\r
+    return FALSE;\r
+  }\r
+\r
+  if ((UsbClass->DeviceProtocol != 0xff) &&\r
+      (UsbClass->DeviceProtocol != DeviceProtocol)) {\r
+    return FALSE;\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+/**\r
+  Eliminate the extra spaces in the Str to one space.\r
+\r
+  @param    Str     Input string info.\r
+**/\r
+VOID\r
+BmEliminateExtraSpaces (\r
+  IN CHAR16                    *Str\r
+  )\r
+{\r
+  UINTN                        Index;\r
+  UINTN                        ActualIndex;\r
+\r
+  for (Index = 0, ActualIndex = 0; Str[Index] != L'\0'; Index++) {\r
+    if ((Str[Index] != L' ') || ((ActualIndex > 0) && (Str[ActualIndex - 1] != L' '))) {\r
+      Str[ActualIndex++] = Str[Index];\r
+    }\r
+  }\r
+  Str[ActualIndex] = L'\0';\r
+}\r
+\r
+/**\r
+  Try to get the controller's ATA/ATAPI description.\r
+\r
+  @param Handle                Controller handle.\r
+\r
+  @return  The description string.\r
+**/\r
+CHAR16 *\r
+BmGetDescriptionFromDiskInfo (\r
+  IN EFI_HANDLE                Handle\r
+  )\r
+{\r
+  UINTN                        Index;\r
+  EFI_STATUS                   Status;\r
+  EFI_DISK_INFO_PROTOCOL       *DiskInfo;\r
+  UINT32                       BufferSize;\r
+  EFI_ATAPI_IDENTIFY_DATA      IdentifyData;\r
+  EFI_SCSI_INQUIRY_DATA        InquiryData;\r
+  CHAR16                       *Description;\r
+  UINTN                        Length;\r
+  CONST UINTN                  ModelNameLength    = 40;\r
+  CONST UINTN                  SerialNumberLength = 20;\r
+  CHAR8                        *StrPtr;\r
+  UINT8                        Temp;\r
+\r
+  Description  = NULL;\r
+\r
+  Status = gBS->HandleProtocol (\r
+                  Handle,\r
+                  &gEfiDiskInfoProtocolGuid,\r
+                  (VOID **) &DiskInfo\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return NULL;\r
+  }\r
+\r
+  if (CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoAhciInterfaceGuid) || \r
+      CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoIdeInterfaceGuid)) {\r
+    BufferSize   = sizeof (EFI_ATAPI_IDENTIFY_DATA);\r
+    Status = DiskInfo->Identify (\r
+                         DiskInfo,\r
+                         &IdentifyData,\r
+                         &BufferSize\r
+                         );\r
+    if (!EFI_ERROR (Status)) {\r
+      Description = AllocateZeroPool ((ModelNameLength + SerialNumberLength + 2) * sizeof (CHAR16));\r
+      ASSERT (Description != NULL);\r
+      for (Index = 0; Index + 1 < ModelNameLength; Index += 2) {\r
+        Description[Index]     = (CHAR16) IdentifyData.ModelName[Index + 1];\r
+        Description[Index + 1] = (CHAR16) IdentifyData.ModelName[Index];\r
+      }\r
+\r
+      Length = Index;\r
+      Description[Length++] = L' ';\r
+\r
+      for (Index = 0; Index + 1 < SerialNumberLength; Index += 2) {\r
+        Description[Length + Index]     = (CHAR16) IdentifyData.SerialNo[Index + 1];\r
+        Description[Length + Index + 1] = (CHAR16) IdentifyData.SerialNo[Index];\r
+      }\r
+      Length += Index;\r
+      Description[Length++] = L'\0';\r
+      ASSERT (Length == ModelNameLength + SerialNumberLength + 2);\r
+\r
+      BmEliminateExtraSpaces (Description);\r
+    }\r
+  } else if (CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoScsiInterfaceGuid)) {\r
+    BufferSize   = sizeof (EFI_SCSI_INQUIRY_DATA);\r
+    Status = DiskInfo->Inquiry (\r
+                         DiskInfo,\r
+                         &InquiryData,\r
+                         &BufferSize\r
+                         );\r
+    if (!EFI_ERROR (Status)) {\r
+      Description = AllocateZeroPool ((VENDOR_IDENTIFICATION_LENGTH + PRODUCT_IDENTIFICATION_LENGTH + 2) * sizeof (CHAR16));\r
+      ASSERT (Description != NULL);\r
+\r
+      //\r
+      // Per SCSI spec, EFI_SCSI_INQUIRY_DATA.Reserved_5_95[3 - 10] save the Verdor identification\r
+      // EFI_SCSI_INQUIRY_DATA.Reserved_5_95[11 - 26] save the product identification, \r
+      // Here combine the vendor identification and product identification to the description.\r
+      //\r
+      StrPtr = (CHAR8 *) (&InquiryData.Reserved_5_95[VENDOR_IDENTIFICATION_OFFSET]);\r
+      Temp = StrPtr[VENDOR_IDENTIFICATION_LENGTH];\r
+      StrPtr[VENDOR_IDENTIFICATION_LENGTH] = '\0';\r
+      AsciiStrToUnicodeStr (StrPtr, Description);\r
+      StrPtr[VENDOR_IDENTIFICATION_LENGTH] = Temp;\r
+\r
+      //\r
+      // Add one space at the middle of vendor information and product information.\r
+      //\r
+      Description[VENDOR_IDENTIFICATION_LENGTH] = L' ';\r
+\r
+      StrPtr = (CHAR8 *) (&InquiryData.Reserved_5_95[PRODUCT_IDENTIFICATION_OFFSET]);\r
+      StrPtr[PRODUCT_IDENTIFICATION_LENGTH] = '\0';\r
+      AsciiStrToUnicodeStr (StrPtr, Description + VENDOR_IDENTIFICATION_LENGTH + 1);\r
+\r
+      BmEliminateExtraSpaces (Description);\r
+    }\r
+  }\r
+\r
+  return Description;\r
+}\r
+\r
+/**\r
+  Try to get the controller's USB description.\r
+\r
+  @param Handle                Controller handle.\r
+\r
+  @return  The description string.\r
+**/\r
+CHAR16 *\r
+BmGetUsbDescription (\r
+  IN EFI_HANDLE                Handle\r
+  )\r
+{\r
+  EFI_STATUS                   Status;\r
+  EFI_USB_IO_PROTOCOL          *UsbIo;\r
+  CHAR16                       NullChar;\r
+  CHAR16                       *Manufacturer;\r
+  CHAR16                       *Product;\r
+  CHAR16                       *SerialNumber;\r
+  CHAR16                       *Description;\r
+  EFI_USB_DEVICE_DESCRIPTOR    DevDesc;\r
+\r
+  Status = gBS->HandleProtocol (\r
+                  Handle,\r
+                  &gEfiUsbIoProtocolGuid,\r
+                  (VOID **) &UsbIo\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return NULL;\r
+  }\r
+\r
+  NullChar = L'\0';\r
+\r
+  Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);\r
+  if (EFI_ERROR (Status)) {\r
+    return NULL;\r
+  }\r
+\r
+  Status = UsbIo->UsbGetStringDescriptor (\r
+                    UsbIo,\r
+                    mBmUsbLangId,\r
+                    DevDesc.StrManufacturer,\r
+                    &Manufacturer\r
+                    );\r
+  if (EFI_ERROR (Status)) {\r
+    Manufacturer = &NullChar;\r
+  }\r
+  \r
+  Status = UsbIo->UsbGetStringDescriptor (\r
+                    UsbIo,\r
+                    mBmUsbLangId,\r
+                    DevDesc.StrProduct,\r
+                    &Product\r
+                    );\r
+  if (EFI_ERROR (Status)) {\r
+    Product = &NullChar;\r
+  }\r
+  \r
+  Status = UsbIo->UsbGetStringDescriptor (\r
+                    UsbIo,\r
+                    mBmUsbLangId,\r
+                    DevDesc.StrSerialNumber,\r
+                    &SerialNumber\r
+                    );\r
+  if (EFI_ERROR (Status)) {\r
+    SerialNumber = &NullChar;\r
+  }\r
+\r
+  if ((Manufacturer == &NullChar) &&\r
+      (Product == &NullChar) &&\r
+      (SerialNumber == &NullChar)\r
+      ) {\r
+    return NULL;\r
+  }\r
+\r
+  Description = AllocateZeroPool (StrSize (Manufacturer) + StrSize (Product) + StrSize (SerialNumber));\r
+  ASSERT (Description != NULL);\r
+  StrCat (Description, Manufacturer);\r
+  StrCat (Description, L" ");\r
+\r
+  StrCat (Description, Product);  \r
+  StrCat (Description, L" ");\r
+\r
+  StrCat (Description, SerialNumber);\r
+\r
+  if (Manufacturer != &NullChar) {\r
+    FreePool (Manufacturer);\r
+  }\r
+  if (Product != &NullChar) {\r
+    FreePool (Product);\r
+  }\r
+  if (SerialNumber != &NullChar) {\r
+    FreePool (SerialNumber);\r
+  }\r
+\r
+  BmEliminateExtraSpaces (Description);\r
+\r
+  return Description;\r
+}\r
+\r
+/**\r
+  Return the boot description for the controller based on the type.\r
+\r
+  @param Handle                Controller handle.\r
+\r
+  @return  The description string.\r
+**/\r
+CHAR16 *\r
+BmGetMiscDescription (\r
+  IN EFI_HANDLE                  Handle\r
+  )\r
+{\r
+  EFI_STATUS                     Status;\r
+  CHAR16                         *Description;\r
+  EFI_BLOCK_IO_PROTOCOL          *BlockIo;\r
+\r
+  switch (BmDevicePathType (DevicePathFromHandle (Handle))) {\r
+  case BmAcpiFloppyBoot:\r
+    Description = L"Floppy";\r
+    break;\r
+\r
+  case BmMessageAtapiBoot:\r
+  case BmMessageSataBoot:\r
+    Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);\r
+    ASSERT_EFI_ERROR (Status);\r
+    //\r
+    // Assume a removable SATA device should be the DVD/CD device\r
+    //\r
+    Description = BlockIo->Media->RemovableMedia ? L"DVD/CDROM" : L"Hard Drive";\r
+    break;\r
+\r
+  case BmMessageUsbBoot:\r
+    Description = L"USB Device";\r
+    break;\r
+\r
+  case BmMessageScsiBoot:\r
+    Description = L"SCSI Device";\r
+    break;\r
+\r
+  case BmHardwareDeviceBoot:\r
+    Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);\r
+    if (!EFI_ERROR (Status)) {\r
+      Description = BlockIo->Media->RemovableMedia ? L"Removable Disk" : L"Hard Drive";\r
+    } else {\r
+      Description = L"Misc Device";\r
+    }\r
+    break;\r
+\r
+  default:\r
+    Description = L"Misc Device";\r
+    break;\r
+  }\r
+\r
+  return AllocateCopyPool (StrSize (Description), Description);\r
+}\r
+\r
+BM_GET_BOOT_DESCRIPTION mBmGetBootDescription[] = {\r
+  BmGetUsbDescription,\r
+  BmGetDescriptionFromDiskInfo,\r
+  BmGetMiscDescription\r
+};\r
+\r
+/**\r
+  Check whether a USB device match the specified USB WWID device path. This\r
+  function follows "Load Option Processing" behavior in UEFI specification.\r
+\r
+  @param UsbIo       USB I/O protocol associated with the USB device.\r
+  @param UsbWwid     The USB WWID device path to match.\r
+\r
+  @retval TRUE       The USB device match the USB WWID device path.\r
+  @retval FALSE      The USB device does not match the USB WWID device path.\r
+\r
+**/\r
+BOOLEAN\r
+BmMatchUsbWwid (\r
+  IN EFI_USB_IO_PROTOCOL        *UsbIo,\r
+  IN USB_WWID_DEVICE_PATH       *UsbWwid\r
+  )\r
+{\r
+  EFI_STATUS                   Status;\r
+  EFI_USB_DEVICE_DESCRIPTOR    DevDesc;\r
+  EFI_USB_INTERFACE_DESCRIPTOR IfDesc;\r
+  UINT16                       *LangIdTable;\r
+  UINT16                       TableSize;\r
+  UINT16                       Index;\r
+  CHAR16                       *CompareStr;\r
+  UINTN                        CompareLen;\r
+  CHAR16                       *SerialNumberStr;\r
+  UINTN                        Length;\r
+\r
+  if ((DevicePathType (UsbWwid) != MESSAGING_DEVICE_PATH) ||\r
+      (DevicePathSubType (UsbWwid) != MSG_USB_WWID_DP)) {\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // Check Vendor Id and Product Id.\r
+  //\r
+  Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);\r
+  if (EFI_ERROR (Status)) {\r
+    return FALSE;\r
+  }\r
+  if ((DevDesc.IdVendor != UsbWwid->VendorId) ||\r
+      (DevDesc.IdProduct != UsbWwid->ProductId)) {\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // Check Interface Number.\r
+  //\r
+  Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &IfDesc);\r
+  if (EFI_ERROR (Status)) {\r
+    return FALSE;\r
+  }\r
+  if (IfDesc.InterfaceNumber != UsbWwid->InterfaceNumber) {\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // Check Serial Number.\r
+  //\r
+  if (DevDesc.StrSerialNumber == 0) {\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // Get all supported languages.\r
+  //\r
+  TableSize = 0;\r
+  LangIdTable = NULL;\r
+  Status = UsbIo->UsbGetSupportedLanguages (UsbIo, &LangIdTable, &TableSize);\r
+  if (EFI_ERROR (Status) || (TableSize == 0) || (LangIdTable == NULL)) {\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // Serial number in USB WWID device path is the last 64-or-less UTF-16 characters.\r
+  //\r
+  CompareStr = (CHAR16 *) (UINTN) (UsbWwid + 1);\r
+  CompareLen = (DevicePathNodeLength (UsbWwid) - sizeof (USB_WWID_DEVICE_PATH)) / sizeof (CHAR16);\r
+  if (CompareStr[CompareLen - 1] == L'\0') {\r
+    CompareLen--;\r
+  }\r
+\r
+  //\r
+  // Compare serial number in each supported language.\r
+  //\r
+  for (Index = 0; Index < TableSize / sizeof (UINT16); Index++) {\r
+    SerialNumberStr = NULL;\r
+    Status = UsbIo->UsbGetStringDescriptor (\r
+                      UsbIo,\r
+                      LangIdTable[Index],\r
+                      DevDesc.StrSerialNumber,\r
+                      &SerialNumberStr\r
+                      );\r
+    if (EFI_ERROR (Status) || (SerialNumberStr == NULL)) {\r
+      continue;\r
+    }\r
+\r
+    Length = StrLen (SerialNumberStr);\r
+    if ((Length >= CompareLen) &&\r
+        (CompareMem (SerialNumberStr + Length - CompareLen, CompareStr, CompareLen * sizeof (CHAR16)) == 0)) {\r
+      FreePool (SerialNumberStr);\r
+      return TRUE;\r
+    }\r
+\r
+    FreePool (SerialNumberStr);\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  Find a USB device which match the specified short-form device path start with \r
+  USB Class or USB WWID device path. If ParentDevicePath is NULL, this function\r
+  will search in all USB devices of the platform. If ParentDevicePath is not NULL,\r
+  this function will only search in its child devices.\r
+\r
+  @param DevicePath           The device path that contains USB Class or USB WWID device path.\r
+  @param ParentDevicePathSize The length of the device path before the USB Class or \r
+                              USB WWID device path.\r
+  @param UsbIoHandleCount     A pointer to the count of the returned USB IO handles.\r
+\r
+  @retval NULL       The matched USB IO handles cannot be found.\r
+  @retval other      The matched USB IO handles.\r
+\r
+**/\r
+EFI_HANDLE *\r
+BmFindUsbDevice (\r
+  IN  EFI_DEVICE_PATH_PROTOCOL  *DevicePath,\r
+  IN  UINTN                     ParentDevicePathSize,\r
+  OUT UINTN                     *UsbIoHandleCount\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  EFI_HANDLE                *UsbIoHandles;\r
+  EFI_DEVICE_PATH_PROTOCOL  *UsbIoDevicePath;\r
+  EFI_USB_IO_PROTOCOL       *UsbIo;\r
+  UINTN                     Index;\r
+  UINTN                     UsbIoDevicePathSize;\r
+  BOOLEAN                   Matched;\r
+\r
+  ASSERT (UsbIoHandleCount != NULL);  \r
+\r
+  //\r
+  // Get all UsbIo Handles.\r
+  //\r
+  Status = gBS->LocateHandleBuffer (\r
+                  ByProtocol,\r
+                  &gEfiUsbIoProtocolGuid,\r
+                  NULL,\r
+                  UsbIoHandleCount,\r
+                  &UsbIoHandles\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    *UsbIoHandleCount = 0;\r
+    UsbIoHandles      = NULL;\r
+  }\r
+\r
+  for (Index = 0; Index < *UsbIoHandleCount; ) {\r
+    //\r
+    // Get the Usb IO interface.\r
+    //\r
+    Status = gBS->HandleProtocol(\r
+                    UsbIoHandles[Index],\r
+                    &gEfiUsbIoProtocolGuid,\r
+                    (VOID **) &UsbIo\r
+                    );\r
+    UsbIoDevicePath = DevicePathFromHandle (UsbIoHandles[Index]);\r
+    Matched         = FALSE;\r
+    if (!EFI_ERROR (Status) && (UsbIoDevicePath != NULL)) {\r
+      UsbIoDevicePathSize = GetDevicePathSize (UsbIoDevicePath) - END_DEVICE_PATH_LENGTH;\r
+\r
+      //\r
+      // Compare starting part of UsbIoHandle's device path with ParentDevicePath.\r
+      //\r
+      if (CompareMem (UsbIoDevicePath, DevicePath, ParentDevicePathSize) == 0) {\r
+        if (BmMatchUsbClass (UsbIo, (USB_CLASS_DEVICE_PATH *) ((UINTN) DevicePath + ParentDevicePathSize)) ||\r
+            BmMatchUsbWwid (UsbIo, (USB_WWID_DEVICE_PATH *) ((UINTN) DevicePath + ParentDevicePathSize))) {\r
+          Matched = TRUE;\r
+        }\r
+      }\r
+    }\r
+\r
+    if (!Matched) {\r
+      (*UsbIoHandleCount) --;\r
+      CopyMem (&UsbIoHandles[Index], &UsbIoHandles[Index + 1], (*UsbIoHandleCount - Index) * sizeof (EFI_HANDLE));\r
+    } else {\r
+      Index++;\r
+    }\r
+  }\r
+\r
+  return UsbIoHandles;\r
+}\r
+\r
+/**\r
+  Expand USB Class or USB WWID device path node to be full device path of a USB\r
+  device in platform.\r
+\r
+  This function support following 4 cases:\r
+  1) Boot Option device path starts with a USB Class or USB WWID device path,\r
+     and there is no Media FilePath device path in the end.\r
+     In this case, it will follow Removable Media Boot Behavior.\r
+  2) Boot Option device path starts with a USB Class or USB WWID device path,\r
+     and ended with Media FilePath device path.\r
+  3) Boot Option device path starts with a full device path to a USB Host Controller,\r
+     contains a USB Class or USB WWID device path node, while not ended with Media\r
+     FilePath device path. In this case, it will follow Removable Media Boot Behavior.\r
+  4) Boot Option device path starts with a full device path to a USB Host Controller,\r
+     contains a USB Class or USB WWID device path node, and ended with Media\r
+     FilePath device path.\r
+\r
+  @param FilePath      The device path pointing to a load option.\r
+                       It could be a short-form device path.\r
+  @param FullPath      Return the full device path of the load option after\r
+                       short-form device path expanding.\r
+                       Caller is responsible to free it.\r
+  @param FileSize      Return the load option size.\r
+  @param ShortformNode Pointer to the USB short-form device path node in the FilePath buffer.\r
+\r
+  @return The load option buffer. Caller is responsible to free the memory.\r
+**/\r
+VOID *\r
+BmExpandUsbDevicePath (\r
+  IN  EFI_DEVICE_PATH_PROTOCOL  *FilePath,\r
+  OUT EFI_DEVICE_PATH_PROTOCOL  **FullPath,\r
+  OUT UINTN                     *FileSize,\r
+  IN EFI_DEVICE_PATH_PROTOCOL   *ShortformNode\r
+  )\r
+{\r
+  UINTN                             ParentDevicePathSize;\r
+  EFI_DEVICE_PATH_PROTOCOL          *RemainingDevicePath;\r
+  EFI_DEVICE_PATH_PROTOCOL          *FullDevicePath;\r
+  EFI_HANDLE                        *Handles;\r
+  UINTN                             HandleCount;\r
+  UINTN                             Index;\r
+  VOID                              *FileBuffer;\r
+\r
+  ParentDevicePathSize = (UINTN) ShortformNode - (UINTN) FilePath;\r
+  RemainingDevicePath = NextDevicePathNode (ShortformNode);\r
+  FileBuffer = NULL;\r
+  Handles = BmFindUsbDevice (FilePath, ParentDevicePathSize, &HandleCount);\r
+\r
+  for (Index = 0; (Index < HandleCount) && (FileBuffer == NULL); Index++) {\r
+    FullDevicePath = AppendDevicePath (DevicePathFromHandle (Handles[Index]), RemainingDevicePath);\r
+    FileBuffer = BmGetLoadOptionBuffer (FullDevicePath, FullPath, FileSize);\r
+    FreePool (FullDevicePath);\r
+  }\r
+\r
+  if (Handles != NULL) {\r
+    FreePool (Handles);\r
+  }\r
+\r
+  return FileBuffer;\r
+}\r
+\r
+/**\r
+  Save the partition DevicePath to the CachedDevicePath as the first instance.\r
+\r
+  @param CachedDevicePath  The device path cache.\r
+  @param DevicePath        The partition device path to be cached.\r
+**/\r
+VOID\r
+BmCachePartitionDevicePath (\r
+  IN OUT EFI_DEVICE_PATH_PROTOCOL **CachedDevicePath,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *DevicePath\r
+  )\r
+{\r
+  EFI_DEVICE_PATH_PROTOCOL        *TempDevicePath;\r
+  UINTN                           Count;\r
+  \r
+  if (BmMatchDevicePaths (*CachedDevicePath, DevicePath)) {\r
+    TempDevicePath = *CachedDevicePath;\r
+    *CachedDevicePath = BmDelPartMatchInstance (*CachedDevicePath, DevicePath);\r
+    FreePool (TempDevicePath);\r
+  }\r
+\r
+  if (*CachedDevicePath == NULL) {\r
+    *CachedDevicePath = DuplicateDevicePath (DevicePath);\r
+    return;\r
+  }\r
+\r
+  TempDevicePath = *CachedDevicePath;\r
+  *CachedDevicePath = AppendDevicePathInstance (DevicePath, *CachedDevicePath);\r
+  if (TempDevicePath != NULL) {\r
+    FreePool (TempDevicePath);\r
+  }\r
+\r
+  //\r
+  // Here limit the device path instance number to 12, which is max number for a system support 3 IDE controller\r
+  // If the user try to boot many OS in different HDs or partitions, in theory, the 'HDDP' variable maybe become larger and larger.\r
+  //\r
+  Count = 0;\r
+  TempDevicePath = *CachedDevicePath;\r
+  while (!IsDevicePathEnd (TempDevicePath)) {\r
+    TempDevicePath = NextDevicePathNode (TempDevicePath);\r
+    //\r
+    // Parse one instance\r
+    //\r
+    while (!IsDevicePathEndType (TempDevicePath)) {\r
+      TempDevicePath = NextDevicePathNode (TempDevicePath);\r
+    }\r
+    Count++;\r
+    //\r
+    // If the CachedDevicePath variable contain too much instance, only remain 12 instances.\r
+    //\r
+    if (Count == 12) {\r
+      SetDevicePathEndNode (TempDevicePath);\r
+      break;\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  Expand a device path that starts with a hard drive media device path node to be a\r
+  full device path that includes the full hardware path to the device. We need\r
+  to do this so it can be booted. As an optimization the front match (the part point\r
+  to the partition node. E.g. ACPI() /PCI()/ATA()/Partition() ) is saved in a variable\r
+  so a connect all is not required on every boot. All successful history device path\r
+  which point to partition node (the front part) will be saved.\r
+\r
+  @param FilePath      The device path pointing to a load option.\r
+                       It could be a short-form device path.\r
+  @param FullPath      Return the full device path of the load option after\r
+                       short-form device path expanding.\r
+                       Caller is responsible to free it.\r
+  @param FileSize      Return the load option size.\r
+\r
+  @return The load option buffer. Caller is responsible to free the memory.\r
+**/\r
+VOID *\r
+BmExpandPartitionDevicePath (\r
+  IN  EFI_DEVICE_PATH_PROTOCOL  *FilePath,\r
+  OUT EFI_DEVICE_PATH_PROTOCOL  **FullPath,\r
+  OUT UINTN                     *FileSize\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  UINTN                     BlockIoHandleCount;\r
+  EFI_HANDLE                *BlockIoBuffer;\r
+  VOID                      *FileBuffer;\r
+  EFI_DEVICE_PATH_PROTOCOL  *BlockIoDevicePath;\r
+  UINTN                     Index;\r
+  EFI_DEVICE_PATH_PROTOCOL  *CachedDevicePath;\r
+  EFI_DEVICE_PATH_PROTOCOL  *TempNewDevicePath;\r
+  EFI_DEVICE_PATH_PROTOCOL  *TempDevicePath;\r
+  UINTN                     CachedDevicePathSize;\r
+  BOOLEAN                   NeedAdjust;\r
+  EFI_DEVICE_PATH_PROTOCOL  *Instance;\r
+  UINTN                     Size;\r
+\r
+  FileBuffer = NULL;\r
+  //\r
+  // Check if there is prestore 'HDDP' variable.\r
+  // If exist, search the front path which point to partition node in the variable instants.\r
+  // If fail to find or 'HDDP' not exist, reconnect all and search in all system\r
+  //\r
+  GetVariable2 (L"HDDP", &mBmHardDriveBootVariableGuid, (VOID **) &CachedDevicePath, &CachedDevicePathSize);\r
+\r
+  //\r
+  // Delete the invalid 'HDDP' variable.\r
+  //\r
+  if ((CachedDevicePath != NULL) && !IsDevicePathValid (CachedDevicePath, CachedDevicePathSize)) {\r
+    FreePool (CachedDevicePath);\r
+    CachedDevicePath = NULL;\r
+    Status = gRT->SetVariable (\r
+                    L"HDDP",\r
+                    &mBmHardDriveBootVariableGuid,\r
+                    0,\r
+                    0,\r
+                    NULL\r
+                    );\r
+    ASSERT_EFI_ERROR (Status);\r
+  }\r
+\r
+  if (CachedDevicePath != NULL) {\r
+    TempNewDevicePath = CachedDevicePath;\r
+    NeedAdjust = FALSE;\r
+    do {\r
+      //\r
+      // Check every instance of the variable\r
+      // First, check whether the instance contain the partition node, which is needed for distinguishing  multi\r
+      // partial partition boot option. Second, check whether the instance could be connected.\r
+      //\r
+      Instance  = GetNextDevicePathInstance (&TempNewDevicePath, &Size);\r
+      if (BmMatchPartitionDevicePathNode (Instance, (HARDDRIVE_DEVICE_PATH *) FilePath)) {\r
+        //\r
+        // Connect the device path instance, the device path point to hard drive media device path node\r
+        // e.g. ACPI() /PCI()/ATA()/Partition()\r
+        //\r
+        Status = EfiBootManagerConnectDevicePath (Instance, NULL);\r
+        if (!EFI_ERROR (Status)) {\r
+          TempDevicePath = AppendDevicePath (Instance, NextDevicePathNode (FilePath));\r
+          FileBuffer = BmGetLoadOptionBuffer (TempDevicePath, FullPath, FileSize);\r
+          FreePool (TempDevicePath);\r
+\r
+          if (FileBuffer != NULL) {\r
+            //\r
+            // Adjust the 'HDDP' instances sequence if the matched one is not first one.\r
+            //\r
+            if (NeedAdjust) {\r
+              BmCachePartitionDevicePath (&CachedDevicePath, Instance);\r
+              //\r
+              // Save the matching Device Path so we don't need to do a connect all next time\r
+              // Failing to save only impacts performance next time expanding the short-form device path\r
+              //\r
+              Status = gRT->SetVariable (\r
+                L"HDDP",\r
+                &mBmHardDriveBootVariableGuid,\r
+                EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
+                GetDevicePathSize (CachedDevicePath),\r
+                CachedDevicePath\r
+                );\r
+            }\r
+\r
+            FreePool (Instance);\r
+            FreePool (CachedDevicePath);\r
+            return FileBuffer;\r
+          }\r
+        }\r
+      }\r
+      //\r
+      // Come here means the first instance is not matched\r
+      //\r
+      NeedAdjust = TRUE;\r
+      FreePool(Instance);\r
+    } while (TempNewDevicePath != NULL);\r
+  }\r
+\r
+  //\r
+  // If we get here we fail to find or 'HDDP' not exist, and now we need\r
+  // to search all devices in the system for a matched partition\r
+  //\r
+  EfiBootManagerConnectAll ();\r
+  Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &BlockIoHandleCount, &BlockIoBuffer);\r
+  if (EFI_ERROR (Status)) {\r
+    BlockIoHandleCount = 0;\r
+    BlockIoBuffer      = NULL;\r
+  }\r
+  //\r
+  // Loop through all the device handles that support the BLOCK_IO Protocol\r
+  //\r
+  for (Index = 0; Index < BlockIoHandleCount; Index++) {\r
+    BlockIoDevicePath = DevicePathFromHandle (BlockIoBuffer[Index]);\r
+    if (BlockIoDevicePath == NULL) {\r
+      continue;\r
+    }\r
+\r
+    if (BmMatchPartitionDevicePathNode (BlockIoDevicePath, (HARDDRIVE_DEVICE_PATH *) FilePath)) {\r
+      //\r
+      // Find the matched partition device path\r
+      //\r
+      TempDevicePath = AppendDevicePath (BlockIoDevicePath, NextDevicePathNode (FilePath));\r
+      FileBuffer = BmGetLoadOptionBuffer (TempDevicePath, FullPath, FileSize);\r
+      FreePool (TempDevicePath);\r
+\r
+      if (FileBuffer != NULL) {\r
+        BmCachePartitionDevicePath (&CachedDevicePath, BlockIoDevicePath);\r
+\r
+        //\r
+        // Save the matching Device Path so we don't need to do a connect all next time\r
+        // Failing to save only impacts performance next time expanding the short-form device path\r
+        //\r
+        Status = gRT->SetVariable (\r
+                        L"HDDP",\r
+                        &mBmHardDriveBootVariableGuid,\r
+                        EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
+                        GetDevicePathSize (CachedDevicePath),\r
+                        CachedDevicePath\r
+                        );\r
+\r
+        break;\r
+      }\r
+    }\r
+  }\r
+\r
+  if (CachedDevicePath != NULL) {\r
+    FreePool (CachedDevicePath);\r
+  }\r
+  if (BlockIoBuffer != NULL) {\r
+    FreePool (BlockIoBuffer);\r
+  }\r
+  return FileBuffer;\r
+}\r
+\r
+/**\r
+  Expand the media device path which points to a BlockIo or SimpleFileSystem instance\r
+  by appending EFI_REMOVABLE_MEDIA_FILE_NAME.\r
+\r
+  @param DevicePath  The media device path pointing to a BlockIo or SimpleFileSystem instance.\r
+  @param FullPath    Return the full device path pointing to the load option.\r
+  @param FileSize    Return the size of the load option.\r
+\r
+  @return  The load option buffer.\r
+**/\r
+VOID *\r
+BmExpandMediaDevicePath (\r
+  IN  EFI_DEVICE_PATH_PROTOCOL        *DevicePath,\r
+  OUT EFI_DEVICE_PATH_PROTOCOL        **FullPath,\r
+  OUT UINTN                           *FileSize\r
+  )\r
+{\r
+  EFI_STATUS                          Status;\r
+  EFI_HANDLE                          Handle;\r
+  EFI_BLOCK_IO_PROTOCOL               *BlockIo;\r
+  VOID                                *Buffer;\r
+  EFI_DEVICE_PATH_PROTOCOL            *TempDevicePath;\r
+  UINTN                               Size;\r
+  UINTN                               TempSize;\r
+  EFI_HANDLE                          *SimpleFileSystemHandles;\r
+  UINTN                               NumberSimpleFileSystemHandles;\r
+  UINTN                               Index;\r
+  VOID                                *FileBuffer;\r
+  UINT32                              AuthenticationStatus;\r
+\r
+  //\r
+  // Check whether the device is connected\r
+  //\r
+  TempDevicePath = DevicePath;\r
+  Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &TempDevicePath, &Handle);\r
+  if (!EFI_ERROR (Status)) {\r
+    ASSERT (IsDevicePathEnd (TempDevicePath));\r
+\r
+    TempDevicePath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME);\r
+    FileBuffer = GetFileBufferByFilePath (TRUE, TempDevicePath, FileSize, &AuthenticationStatus);\r
+    if (FileBuffer == NULL) {\r
+      FreePool (TempDevicePath);\r
+      TempDevicePath = NULL;\r
+    }\r
+    *FullPath = TempDevicePath;\r
+    return FileBuffer;\r
+  }\r
+\r
+  //\r
+  // For device boot option only pointing to the removable device handle, \r
+  // should make sure all its children handles (its child partion or media handles) are created and connected. \r
+  //\r
+  gBS->ConnectController (Handle, NULL, NULL, TRUE);\r
+\r
+  //\r
+  // Issue a dummy read to the device to check for media change.\r
+  // When the removable media is changed, any Block IO read/write will\r
+  // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is\r
+  // returned. After the Block IO protocol is reinstalled, subsequent\r
+  // Block IO read/write will success.\r
+  //\r
+  Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, &Handle);\r
+  ASSERT_EFI_ERROR (Status);\r
+  Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);\r
+  ASSERT_EFI_ERROR (Status);\r
+  Buffer = AllocatePool (BlockIo->Media->BlockSize);\r
+  if (Buffer != NULL) {\r
+    BlockIo->ReadBlocks (\r
+      BlockIo,\r
+      BlockIo->Media->MediaId,\r
+      0,\r
+      BlockIo->Media->BlockSize,\r
+      Buffer\r
+      );\r
+    FreePool (Buffer);\r
+  }\r
+\r
+  //\r
+  // Detect the the default boot file from removable Media\r
+  //\r
+  FileBuffer = NULL;\r
+  *FullPath = NULL;\r
+  Size = GetDevicePathSize (DevicePath) - END_DEVICE_PATH_LENGTH;\r
+  gBS->LocateHandleBuffer (\r
+         ByProtocol,\r
+         &gEfiSimpleFileSystemProtocolGuid,\r
+         NULL,\r
+         &NumberSimpleFileSystemHandles,\r
+         &SimpleFileSystemHandles\r
+         );\r
+  for (Index = 0; Index < NumberSimpleFileSystemHandles; Index++) {\r
+    //\r
+    // Get the device path size of SimpleFileSystem handle\r
+    //\r
+    TempDevicePath = DevicePathFromHandle (SimpleFileSystemHandles[Index]);\r
+    TempSize = GetDevicePathSize (TempDevicePath) - END_DEVICE_PATH_LENGTH;\r
+    //\r
+    // Check whether the device path of boot option is part of the SimpleFileSystem handle's device path\r
+    //\r
+    if ((Size <= TempSize) && (CompareMem (TempDevicePath, DevicePath, Size) == 0)) {\r
+      TempDevicePath = FileDevicePath (SimpleFileSystemHandles[Index], EFI_REMOVABLE_MEDIA_FILE_NAME);\r
+      FileBuffer = GetFileBufferByFilePath (TRUE, TempDevicePath, FileSize, &AuthenticationStatus);\r
+      if (FileBuffer != NULL) {\r
+        *FullPath = TempDevicePath;\r
+        break;\r
+      }\r
+      FreePool (TempDevicePath);\r
+    }\r
+  }\r
+\r
+  if (SimpleFileSystemHandles != NULL) {\r
+    FreePool (SimpleFileSystemHandles);\r
+  }\r
+\r
+  return FileBuffer;\r
+}\r
+\r
+/**\r
+  Get the load option by its device path.\r
+\r
+  @param FilePath  The device path pointing to a load option.\r
+                   It could be a short-form device path.\r
+  @param FullPath  Return the full device path of the load option after\r
+                   short-form device path expanding.\r
+                   Caller is responsible to free it.\r
+  @param FileSize  Return the load option size.\r
+\r
+  @return The load option buffer. Caller is responsible to free the memory.\r
+**/\r
+VOID *\r
+BmGetLoadOptionBuffer (\r
+  IN  EFI_DEVICE_PATH_PROTOCOL          *FilePath,\r
+  OUT EFI_DEVICE_PATH_PROTOCOL          **FullPath,\r
+  OUT UINTN                             *FileSize\r
+  )\r
+{\r
+  EFI_HANDLE                      Handle;\r
+  VOID                            *FileBuffer;\r
+  UINT32                          AuthenticationStatus;\r
+  EFI_DEVICE_PATH_PROTOCOL        *Node;\r
+  EFI_STATUS                      Status;\r
+\r
+  ASSERT ((FilePath != NULL) && (FullPath != NULL) && (FileSize != NULL));\r
+\r
+  EfiBootManagerConnectDevicePath (FilePath, NULL);\r
+\r
+  *FullPath  = NULL;\r
+  *FileSize  = 0;\r
+  FileBuffer = NULL;\r
+\r
+  //\r
+  // Boot from media device by adding a default file name \EFI\BOOT\BOOT{machine type short-name}.EFI\r
+  //\r
+  Node = FilePath;\r
+  Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &Node, &Handle);\r
+  if (EFI_ERROR (Status)) {\r
+    Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &Node, &Handle);\r
+  }\r
+\r
+  if (!EFI_ERROR (Status) && IsDevicePathEnd (Node)) {\r
+    return BmExpandMediaDevicePath (FilePath, FullPath, FileSize);\r
+  }\r
+\r
+  //\r
+  // Expand the short-form device path to full device path\r
+  //\r
+  if ((DevicePathType (FilePath) == MEDIA_DEVICE_PATH) &&\r
+      (DevicePathSubType (FilePath) == MEDIA_HARDDRIVE_DP)) {\r
+    //\r
+    // Expand the Harddrive device path\r
+    //\r
+    return BmExpandPartitionDevicePath (FilePath, FullPath, FileSize);\r
+  } else {\r
+    for (Node = FilePath; !IsDevicePathEnd (Node); Node = NextDevicePathNode (Node)) {\r
+      if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) &&\r
+          ((DevicePathSubType (Node) == MSG_USB_CLASS_DP) || (DevicePathSubType (Node) == MSG_USB_WWID_DP))) {\r
+        break;\r
+      }\r
+    }\r
+\r
+    if (!IsDevicePathEnd (Node)) {\r
+      //\r
+      // Expand the USB WWID/Class device path\r
+      //\r
+      FileBuffer = BmExpandUsbDevicePath (FilePath, FullPath, FileSize, Node);\r
+      if ((FileBuffer == NULL) && (FilePath == Node)) {\r
+        //\r
+        // Boot Option device path starts with USB Class or USB WWID device path.\r
+        // For Boot Option device path which doesn't begin with the USB Class or\r
+        // USB WWID device path, it's not needed to connect again here.\r
+        //\r
+        BmConnectUsbShortFormDevicePath (FilePath);\r
+        FileBuffer = BmExpandUsbDevicePath (FilePath, FullPath, FileSize, Node);\r
+      }\r
+      return FileBuffer;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Fix up the boot option path if it points to a FV in memory map style of device path\r
+  //\r
+  if (BmIsMemmapFvFilePath (FilePath)) {\r
+    return BmGetFileBufferByMemmapFv (FilePath, FullPath, FileSize);\r
+  }\r
+\r
+  //\r
+  // Directly reads the load option when it doesn't reside in simple file system instance (LoadFile/LoadFile2),\r
+  //   or it directly points to a file in simple file system instance.\r
+  //\r
+  FileBuffer = GetFileBufferByFilePath (TRUE, FilePath, FileSize, &AuthenticationStatus);\r
+  if (FileBuffer != NULL) {\r
+    *FullPath = DuplicateDevicePath (FilePath);\r
+  }\r
+\r
+  return FileBuffer;\r
+}\r
+\r
+/**\r
+  Attempt to boot the EFI boot option. This routine sets L"BootCurent" and\r
+  also signals the EFI ready to boot event. If the device path for the option\r
+  starts with a BBS device path a legacy boot is attempted via the registered \r
+  gLegacyBoot function. Short form device paths are also supported via this \r
+  rountine. A device path starting with MEDIA_HARDDRIVE_DP, MSG_USB_WWID_DP,\r
+  MSG_USB_CLASS_DP gets expaned out to find the first device that matches.\r
+  If the BootOption Device Path fails the removable media boot algorithm \r
+  is attempted (\EFI\BOOTIA32.EFI, \EFI\BOOTX64.EFI,... only one file type \r
+  is tried per processor type)\r
+\r
+  @param  BootOption    Boot Option to try and boot.\r
+                        On return, BootOption->Status contains the boot status.\r
+                        EFI_SUCCESS     BootOption was booted\r
+                        EFI_UNSUPPORTED A BBS device path was found with no valid callback\r
+                                        registered via EfiBootManagerInitialize().\r
+                        EFI_NOT_FOUND   The BootOption was not found on the system\r
+                        !EFI_SUCCESS    BootOption failed with this error status\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+EfiBootManagerBoot (\r
+  IN  EFI_BOOT_MANAGER_LOAD_OPTION             *BootOption\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  EFI_HANDLE                ImageHandle;\r
+  EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;\r
+  UINT16                    Uint16;\r
+  UINTN                     OptionNumber;\r
+  UINTN                     OriginalOptionNumber;\r
+  EFI_DEVICE_PATH_PROTOCOL  *FilePath;\r
+  EFI_DEVICE_PATH_PROTOCOL  *Node;\r
+  EFI_HANDLE                FvHandle;\r
+  VOID                      *FileBuffer;\r
+  UINTN                     FileSize;\r
+  EFI_BOOT_LOGO_PROTOCOL    *BootLogo;\r
+  EFI_EVENT                 LegacyBootEvent;\r
+\r
+  if (BootOption == NULL) {\r
+    return;\r
+  }\r
+\r
+  if (BootOption->FilePath == NULL || BootOption->OptionType != LoadOptionTypeBoot) {\r
+    BootOption->Status = EFI_INVALID_PARAMETER;\r
+    return;\r
+  }\r
+\r
+  //\r
+  // 1. Create Boot#### for a temporary boot if there is no match Boot#### (i.e. a boot by selected a EFI Shell using "Boot From File")\r
+  //\r
+  OptionNumber = BmFindBootOptionInVariable (BootOption);\r
+  if (OptionNumber == LoadOptionNumberUnassigned) {\r
+    Status = BmGetFreeOptionNumber (LoadOptionTypeBoot, &Uint16);\r
+    if (!EFI_ERROR (Status)) {\r
+      //\r
+      // Save the BootOption->OptionNumber to restore later\r
+      //\r
+      OptionNumber             = Uint16;\r
+      OriginalOptionNumber     = BootOption->OptionNumber;\r
+      BootOption->OptionNumber = OptionNumber;\r
+      Status = EfiBootManagerLoadOptionToVariable (BootOption);\r
+      BootOption->OptionNumber = OriginalOptionNumber;\r
+    }\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_ERROR, "[Bds] Failed to create Boot#### for a temporary boot - %r!\n", Status));\r
+      BootOption->Status = Status;\r
+      return ;\r
+    }\r
+  }\r
+\r
+  //\r
+  // 2. Set BootCurrent\r
+  //\r
+  Uint16 = (UINT16) OptionNumber;\r
+  BmSetVariableAndReportStatusCodeOnError (\r
+    L"BootCurrent",\r
+    &gEfiGlobalVariableGuid,\r
+    EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+    sizeof (UINT16),\r
+    &Uint16\r
+    );\r
+\r
+  //\r
+  // 3. Signal the EVT_SIGNAL_READY_TO_BOOT event when we are about to load and execute\r
+  //    the boot option.\r
+  //\r
+  Node   = BootOption->FilePath;\r
+  Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &Node, &FvHandle);\r
+  if (!EFI_ERROR (Status) && CompareGuid (\r
+        EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) Node),\r
+        PcdGetPtr (PcdBootManagerMenuFile)\r
+        )) {\r
+    DEBUG ((EFI_D_INFO, "[Bds] Booting Boot Manager Menu.\n"));\r
+    BmStopHotkeyService (NULL, NULL);\r
+  } else {\r
+    EfiSignalEventReadyToBoot();\r
+    //\r
+    // Report Status Code to indicate ReadyToBoot was signalled\r
+    //\r
+    REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT));\r
+    //\r
+    // 4. Repair system through DriverHealth protocol\r
+    //\r
+    BmRepairAllControllers ();\r
+  }\r
+\r
+  PERF_START_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32) OptionNumber);\r
+\r
+  //\r
+  // 5. Load EFI boot option to ImageHandle\r
+  //\r
+  ImageHandle = NULL;\r
+  if (DevicePathType (BootOption->FilePath) != BBS_DEVICE_PATH) {\r
+    Status     = EFI_NOT_FOUND;\r
+    FileBuffer = BmGetLoadOptionBuffer (BootOption->FilePath, &FilePath, &FileSize);\r
+    DEBUG_CODE (\r
+      if (FileBuffer != NULL && CompareMem (BootOption->FilePath, FilePath, GetDevicePathSize (FilePath)) != 0) {\r
+        DEBUG ((EFI_D_INFO, "[Bds] DevicePath expand: "));\r
+        BmPrintDp (BootOption->FilePath);\r
+        DEBUG ((EFI_D_INFO, " -> "));\r
+        BmPrintDp (FilePath);\r
+        DEBUG ((EFI_D_INFO, "\n"));\r
+      }\r
+    );\r
+    if (BmIsLoadOptionPeHeaderValid (BootOption->OptionType, FileBuffer, FileSize)) {\r
+      REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderLoad));\r
+      Status = gBS->LoadImage (\r
+                      TRUE,\r
+                      gImageHandle,\r
+                      FilePath,\r
+                      FileBuffer,\r
+                      FileSize,\r
+                      &ImageHandle\r
+                      );\r
+    }\r
+    if (FileBuffer != NULL) {\r
+      FreePool (FileBuffer);\r
+    }\r
+    if (FilePath != NULL) {\r
+      FreePool (FilePath);\r
+    }\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      //\r
+      // Report Status Code to indicate that the failure to load boot option\r
+      //\r
+      REPORT_STATUS_CODE (\r
+        EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
+        (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR)\r
+        );\r
+      BootOption->Status = Status;\r
+      return;\r
+    }\r
+  }\r
+\r
+  //\r
+  // 6. Adjust the different type memory page number just before booting\r
+  //    and save the updated info into the variable for next boot to use\r
+  //\r
+  if ((BootOption->Attributes & LOAD_OPTION_CATEGORY) == LOAD_OPTION_CATEGORY_BOOT) {\r
+    if (PcdGetBool (PcdResetOnMemoryTypeInformationChange)) {\r
+      BmSetMemoryTypeInformationVariable ();\r
+    }\r
+  }\r
+\r
+  DEBUG_CODE_BEGIN();\r
+    if (BootOption->Description == NULL) {\r
+      DEBUG ((DEBUG_INFO | DEBUG_LOAD, "[Bds]Booting from unknown device path\n"));\r
+    } else {\r
+      DEBUG ((DEBUG_INFO | DEBUG_LOAD, "[Bds]Booting %s\n", BootOption->Description));\r
+    }\r
+  DEBUG_CODE_END();\r
+\r
+  //\r
+  // Check to see if we should legacy BOOT. If yes then do the legacy boot\r
+  // Write boot to OS performance data for Legacy boot\r
+  //\r
+  if ((DevicePathType (BootOption->FilePath) == BBS_DEVICE_PATH) && (DevicePathSubType (BootOption->FilePath) == BBS_BBS_DP)) {\r
+    if (mBmLegacyBoot != NULL) {\r
+      //\r
+      // Write boot to OS performance data for legacy boot.\r
+      //\r
+      PERF_CODE (\r
+        //\r
+        // Create an event to be signalled when Legacy Boot occurs to write performance data.\r
+        //\r
+        Status = EfiCreateEventLegacyBootEx(\r
+                   TPL_NOTIFY,\r
+                   BmWriteBootToOsPerformanceData,\r
+                   NULL, \r
+                   &LegacyBootEvent\r
+                   );\r
+        ASSERT_EFI_ERROR (Status);\r
+      );\r
+\r
+      mBmLegacyBoot (BootOption);\r
+    } else {\r
+      BootOption->Status = EFI_UNSUPPORTED;\r
+    }\r
+\r
+    PERF_END_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32) OptionNumber);\r
+    return;\r
+  }\r
\r
+  //\r
+  // Provide the image with its load options\r
+  //\r
+  Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  ImageInfo->LoadOptionsSize  = BootOption->OptionalDataSize;\r
+  ImageInfo->LoadOptions      = BootOption->OptionalData;\r
+\r
+  //\r
+  // Clean to NULL because the image is loaded directly from the firmwares boot manager.\r
+  //\r
+  ImageInfo->ParentHandle = NULL;\r
+\r
+  //\r
+  // Before calling the image, enable the Watchdog Timer for 5 minutes period\r
+  //\r
+  gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);\r
+\r
+  //\r
+  // Write boot to OS performance data for UEFI boot\r
+  //\r
+  PERF_CODE (\r
+    BmWriteBootToOsPerformanceData (NULL, NULL);\r
+  );\r
+\r
+  REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderStart));\r
+\r
+  Status = gBS->StartImage (ImageHandle, &BootOption->ExitDataSize, &BootOption->ExitData);\r
+  DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Image Return Status = %r\n", Status));\r
+  BootOption->Status = Status;\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // Report Status Code to indicate that boot failure\r
+    //\r
+    REPORT_STATUS_CODE (\r
+      EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
+      (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED)\r
+      );\r
+  }\r
+  PERF_END_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32) OptionNumber);\r
+\r
+  //\r
+  // Clear the Watchdog Timer after the image returns\r
+  //\r
+  gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);\r
+\r
+  //\r
+  // Set Logo status invalid after trying one boot option\r
+  //\r
+  BootLogo = NULL;\r
+  Status = gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo);\r
+  if (!EFI_ERROR (Status) && (BootLogo != NULL)) {\r
+    Status = BootLogo->SetBootLogo (BootLogo, NULL, 0, 0, 0, 0);\r
+    ASSERT_EFI_ERROR (Status);\r
+  }\r
+\r
+  //\r
+  // Clear Boot Current\r
+  //\r
+  Status = gRT->SetVariable (\r
+                  L"BootCurrent",\r
+                  &gEfiGlobalVariableGuid,\r
+                  0,\r
+                  0,\r
+                  NULL\r
+                  );\r
+  //\r
+  // Deleting variable with current variable implementation shouldn't fail.\r
+  // When BootXXXX (e.g.: BootManagerMenu) boots BootYYYY, exiting BootYYYY causes BootCurrent deleted,\r
+  // exiting BootXXXX causes deleting BootCurrent returns EFI_NOT_FOUND.\r
+  //\r
+  ASSERT (Status == EFI_SUCCESS || Status == EFI_NOT_FOUND);\r
+}\r
+\r
+/**\r
+  Check whether there is a instance in BlockIoDevicePath, which contain multi device path\r
+  instances, has the same partition node with HardDriveDevicePath device path\r
+\r
+  @param  BlockIoDevicePath      Multi device path instances which need to check\r
+  @param  HardDriveDevicePath    A device path which starts with a hard drive media\r
+                                 device path.\r
+\r
+  @retval TRUE                   There is a matched device path instance.\r
+  @retval FALSE                  There is no matched device path instance.\r
+\r
+**/\r
+BOOLEAN\r
+BmMatchPartitionDevicePathNode (\r
+  IN  EFI_DEVICE_PATH_PROTOCOL   *BlockIoDevicePath,\r
+  IN  HARDDRIVE_DEVICE_PATH      *HardDriveDevicePath\r
+  )\r
+{\r
+  HARDDRIVE_DEVICE_PATH     *Node;\r
+\r
+  if ((BlockIoDevicePath == NULL) || (HardDriveDevicePath == NULL)) {\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // find the partition device path node\r
+  //\r
+  while (!IsDevicePathEnd (BlockIoDevicePath)) {\r
+    if ((DevicePathType (BlockIoDevicePath) == MEDIA_DEVICE_PATH) &&\r
+        (DevicePathSubType (BlockIoDevicePath) == MEDIA_HARDDRIVE_DP)\r
+        ) {\r
+      break;\r
+    }\r
+\r
+    BlockIoDevicePath = NextDevicePathNode (BlockIoDevicePath);\r
+  }\r
+\r
+  if (IsDevicePathEnd (BlockIoDevicePath)) {\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // See if the harddrive device path in blockio matches the orig Hard Drive Node\r
+  //\r
+  Node = (HARDDRIVE_DEVICE_PATH *) BlockIoDevicePath;\r
+\r
+  //\r
+  // Match Signature and PartitionNumber.\r
+  // Unused bytes in Signature are initiaized with zeros.\r
+  //\r
+  return (BOOLEAN) (\r
+    (Node->PartitionNumber == HardDriveDevicePath->PartitionNumber) &&\r
+    (Node->MBRType == HardDriveDevicePath->MBRType) &&\r
+    (Node->SignatureType == HardDriveDevicePath->SignatureType) &&\r
+    (CompareMem (Node->Signature, HardDriveDevicePath->Signature, sizeof (Node->Signature)) == 0)\r
+    );\r
+}\r
+\r
+/**\r
+  Emuerate all possible bootable medias in the following order:\r
+  1. Removable BlockIo            - The boot option only points to the removable media\r
+                                    device, like USB key, DVD, Floppy etc.\r
+  2. Fixed BlockIo                - The boot option only points to a Fixed blockIo device,\r
+                                    like HardDisk.\r
+  3. Non-BlockIo SimpleFileSystem - The boot option points to a device supporting\r
+                                    SimpleFileSystem Protocol, but not supporting BlockIo\r
+                                    protocol.\r
+  4. LoadFile                     - The boot option points to the media supporting \r
+                                    LoadFile protocol.\r
+  Reference: UEFI Spec chapter 3.3 Boot Option Variables Default Boot Behavior\r
+\r
+  @param BootOptionCount   Return the boot option count which has been found.\r
+\r
+  @retval   Pointer to the boot option array.\r
+**/\r
+EFI_BOOT_MANAGER_LOAD_OPTION *\r
+BmEnumerateBootOptions (\r
+  UINTN                                 *BootOptionCount\r
+  )\r
+{\r
+  EFI_STATUS                            Status;\r
+  EFI_BOOT_MANAGER_LOAD_OPTION          *BootOptions;\r
+  UINT16                                NonBlockNumber;\r
+  UINTN                                 HandleCount;\r
+  EFI_HANDLE                            *Handles;\r
+  EFI_BLOCK_IO_PROTOCOL                 *BlkIo;\r
+  UINTN                                 Removable;\r
+  UINTN                                 Index;\r
+  UINTN                                 FunctionIndex;\r
+  CHAR16                                *Temp;\r
+  CHAR16                                *DescriptionPtr;\r
+  CHAR16                                Description[30];\r
+\r
+  ASSERT (BootOptionCount != NULL);\r
+\r
+  *BootOptionCount = 0;\r
+  BootOptions      = NULL;\r
+\r
+  //\r
+  // Parse removable block io followed by fixed block io\r
+  //\r
+  gBS->LocateHandleBuffer (\r
+         ByProtocol,\r
+         &gEfiBlockIoProtocolGuid,\r
+         NULL,\r
+         &HandleCount,\r
+         &Handles\r
+         );\r
+\r
+  for (Removable = 0; Removable < 2; Removable++) {\r
+    for (Index = 0; Index < HandleCount; Index++) {\r
+      Status = gBS->HandleProtocol (\r
+                      Handles[Index],\r
+                      &gEfiBlockIoProtocolGuid,\r
+                      (VOID **) &BlkIo\r
+                      );\r
+      if (EFI_ERROR (Status)) {\r
+        continue;\r
+      }\r
+\r
+      //\r
+      // Skip the logical partitions\r
+      //\r
+      if (BlkIo->Media->LogicalPartition) {\r
+        continue;\r
+      }\r
+\r
+      //\r
+      // Skip the fixed block io then the removable block io\r
+      //\r
+      if (BlkIo->Media->RemovableMedia == ((Removable == 0) ? FALSE : TRUE)) {\r
+        continue;\r
+      }\r
+\r
+      DescriptionPtr = NULL;\r
+      for (FunctionIndex = 0; FunctionIndex < sizeof (mBmGetBootDescription) / sizeof (mBmGetBootDescription[0]); FunctionIndex++) {\r
+        DescriptionPtr = mBmGetBootDescription[FunctionIndex] (Handles[Index]);\r
+        if (DescriptionPtr != NULL) {\r
+          break;\r
+        }\r
+      }\r
+\r
+      if (DescriptionPtr == NULL) {\r
+        continue;\r
+      }\r
+\r
+      //\r
+      // Avoid description confusion between UEFI & Legacy boot option by adding "UEFI " prefix\r
+      //\r
+      Temp = AllocatePool (StrSize (DescriptionPtr) + sizeof (mBmUefiPrefix)); \r
+      ASSERT (Temp != NULL);\r
+      StrCpy (Temp, mBmUefiPrefix);\r
+      StrCat (Temp, DescriptionPtr);\r
+      FreePool (DescriptionPtr);\r
+      DescriptionPtr = Temp;\r
+\r
+      BootOptions = ReallocatePool (\r
+                      sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),\r
+                      sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),\r
+                      BootOptions\r
+                      );\r
+      ASSERT (BootOptions != NULL);\r
+\r
+      Status = EfiBootManagerInitializeLoadOption (\r
+                 &BootOptions[(*BootOptionCount)++],\r
+                 LoadOptionNumberUnassigned,\r
+                 LoadOptionTypeBoot,\r
+                 LOAD_OPTION_ACTIVE,\r
+                 DescriptionPtr,\r
+                 DevicePathFromHandle (Handles[Index]),\r
+                 NULL,\r
+                 0\r
+                 );\r
+      ASSERT_EFI_ERROR (Status);\r
+\r
+      FreePool (DescriptionPtr);\r
+    }\r
+  }\r
+\r
+  if (HandleCount != 0) {\r
+    FreePool (Handles);\r
+  }\r
+\r
+  //\r
+  // Parse simple file system not based on block io\r
+  //\r
+  NonBlockNumber = 0;\r
+  gBS->LocateHandleBuffer (\r
+         ByProtocol,\r
+         &gEfiSimpleFileSystemProtocolGuid,\r
+         NULL,\r
+         &HandleCount,\r
+         &Handles\r
+         );\r
+  for (Index = 0; Index < HandleCount; Index++) {\r
+    Status = gBS->HandleProtocol (\r
+                    Handles[Index],\r
+                    &gEfiBlockIoProtocolGuid,\r
+                    (VOID **) &BlkIo\r
+                    );\r
+     if (!EFI_ERROR (Status)) {\r
+      //\r
+      //  Skip if the file system handle supports a BlkIo protocol, which we've handled in above\r
+      //\r
+      continue;\r
+    }\r
+    UnicodeSPrint (Description, sizeof (Description), NonBlockNumber > 0 ? L"%s %d" : L"%s", L"UEFI Non-Block Boot Device", NonBlockNumber);\r
+    \r
+    BootOptions = ReallocatePool (\r
+                    sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),\r
+                    sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),\r
+                    BootOptions\r
+                    );\r
+    ASSERT (BootOptions != NULL);\r
+\r
+    Status = EfiBootManagerInitializeLoadOption (\r
+               &BootOptions[(*BootOptionCount)++],\r
+               LoadOptionNumberUnassigned,\r
+               LoadOptionTypeBoot,\r
+               LOAD_OPTION_ACTIVE,\r
+               Description,\r
+               DevicePathFromHandle (Handles[Index]),\r
+               NULL,\r
+               0\r
+               );\r
+    ASSERT_EFI_ERROR (Status);\r
+  }\r
+\r
+  if (HandleCount != 0) {\r
+    FreePool (Handles);\r
+  }\r
+\r
+  //\r
+  // Parse load file, assuming UEFI Network boot option\r
+  //\r
+  gBS->LocateHandleBuffer (\r
+         ByProtocol,\r
+         &gEfiLoadFileProtocolGuid,\r
+         NULL,\r
+         &HandleCount,\r
+         &Handles\r
+         );\r
+  for (Index = 0; Index < HandleCount; Index++) {\r
+\r
+    UnicodeSPrint (Description, sizeof (Description), Index > 0 ? L"%s %d" : L"%s", L"UEFI Network", Index);\r
+\r
+    BootOptions = ReallocatePool (\r
+                    sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),\r
+                    sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),\r
+                    BootOptions\r
+                    );\r
+    ASSERT (BootOptions != NULL);\r
+\r
+    Status = EfiBootManagerInitializeLoadOption (\r
+               &BootOptions[(*BootOptionCount)++],\r
+               LoadOptionNumberUnassigned,\r
+               LoadOptionTypeBoot,\r
+               LOAD_OPTION_ACTIVE,\r
+               Description,\r
+               DevicePathFromHandle (Handles[Index]),\r
+               NULL,\r
+               0\r
+               );\r
+    ASSERT_EFI_ERROR (Status);\r
+  }\r
+\r
+  if (HandleCount != 0) {\r
+    FreePool (Handles);\r
+  }\r
+\r
+  return BootOptions;\r
+}\r
+\r
+/**\r
+  The function enumerates all boot options, creates them and registers them in the BootOrder variable.\r
+**/\r
+VOID\r
+EFIAPI\r
+EfiBootManagerRefreshAllBootOption (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  EFI_BOOT_MANAGER_LOAD_OPTION  *NvBootOptions;\r
+  UINTN                         NvBootOptionCount;\r
+  EFI_BOOT_MANAGER_LOAD_OPTION  *BootOptions;\r
+  UINTN                         BootOptionCount;\r
+  UINTN                         Index;\r
+\r
+  //\r
+  // Optionally refresh the legacy boot option\r
+  //\r
+  if (mBmRefreshLegacyBootOption != NULL) {\r
+    mBmRefreshLegacyBootOption ();\r
+  }\r
+\r
+  BootOptions   = BmEnumerateBootOptions (&BootOptionCount);\r
+  NvBootOptions = EfiBootManagerGetLoadOptions (&NvBootOptionCount, LoadOptionTypeBoot);\r
+\r
+  //\r
+  // Mark the boot option as added by BDS by setting OptionalData to a special GUID\r
+  //\r
+  for (Index = 0; Index < BootOptionCount; Index++) {\r
+    BootOptions[Index].OptionalData     = AllocateCopyPool (sizeof (EFI_GUID), &mBmAutoCreateBootOptionGuid);\r
+    BootOptions[Index].OptionalDataSize = sizeof (EFI_GUID);\r
+  }\r
+\r
+  //\r
+  // Remove invalid EFI boot options from NV\r
+  //\r
+  for (Index = 0; Index < NvBootOptionCount; Index++) {\r
+    if (((DevicePathType (NvBootOptions[Index].FilePath) != BBS_DEVICE_PATH) || \r
+         (DevicePathSubType (NvBootOptions[Index].FilePath) != BBS_BBS_DP)\r
+        ) &&\r
+        (NvBootOptions[Index].OptionalDataSize == sizeof (EFI_GUID)) &&\r
+        CompareGuid ((EFI_GUID *) NvBootOptions[Index].OptionalData, &mBmAutoCreateBootOptionGuid)\r
+       ) {\r
+      //\r
+      // Only check those added by BDS\r
+      // so that the boot options added by end-user or OS installer won't be deleted\r
+      //\r
+      if (BmFindLoadOption (&NvBootOptions[Index], BootOptions, BootOptionCount) == (UINTN) -1) {\r
+        Status = EfiBootManagerDeleteLoadOptionVariable (NvBootOptions[Index].OptionNumber, LoadOptionTypeBoot);\r
+        //\r
+        // Deleting variable with current variable implementation shouldn't fail.\r
+        //\r
+        ASSERT_EFI_ERROR (Status);\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // Add new EFI boot options to NV\r
+  //\r
+  for (Index = 0; Index < BootOptionCount; Index++) {\r
+    if (BmFindLoadOption (&BootOptions[Index], NvBootOptions, NvBootOptionCount) == (UINTN) -1) {\r
+      EfiBootManagerAddLoadOptionVariable (&BootOptions[Index], (UINTN) -1);\r
+      //\r
+      // Try best to add the boot options so continue upon failure.\r
+      //\r
+    }\r
+  }\r
+\r
+  EfiBootManagerFreeLoadOptions (BootOptions,   BootOptionCount);\r
+  EfiBootManagerFreeLoadOptions (NvBootOptions, NvBootOptionCount);\r
+}\r
+\r
+/**\r
+  This function is called to create the boot option for the Boot Manager Menu.\r
+\r
+  The Boot Manager Menu is shown after successfully booting a boot option.\r
+  Assume the BootManagerMenuFile is in the same FV as the module links to this library.\r
+\r
+  @param  BootOption    Return the boot option of the Boot Manager Menu\r
+\r
+  @retval EFI_SUCCESS   Successfully register the Boot Manager Menu.\r
+  @retval Status        Return status of gRT->SetVariable (). BootOption still points\r
+                        to the Boot Manager Menu even the Status is not EFI_SUCCESS.\r
+**/\r
+EFI_STATUS\r
+BmRegisterBootManagerMenu (\r
+  OUT EFI_BOOT_MANAGER_LOAD_OPTION   *BootOption\r
+  )\r
+{\r
+  EFI_STATUS                         Status;\r
+  CHAR16                             *Description;\r
+  UINTN                              DescriptionLength;\r
+  EFI_DEVICE_PATH_PROTOCOL           *DevicePath;\r
+  EFI_LOADED_IMAGE_PROTOCOL          *LoadedImage;\r
+  MEDIA_FW_VOL_FILEPATH_DEVICE_PATH  FileNode;\r
+\r
+  Status = GetSectionFromFv (\r
+             PcdGetPtr (PcdBootManagerMenuFile),\r
+             EFI_SECTION_USER_INTERFACE,\r
+             0,\r
+             (VOID **) &Description,\r
+             &DescriptionLength\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    Description = NULL;\r
+  }\r
+\r
+  EfiInitializeFwVolDevicepathNode (&FileNode, PcdGetPtr (PcdBootManagerMenuFile));\r
+  Status = gBS->HandleProtocol (\r
+                  gImageHandle,\r
+                  &gEfiLoadedImageProtocolGuid,\r
+                  (VOID **) &LoadedImage\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+  DevicePath = AppendDevicePathNode (\r
+                 DevicePathFromHandle (LoadedImage->DeviceHandle),\r
+                 (EFI_DEVICE_PATH_PROTOCOL *) &FileNode\r
+                 );\r
+  ASSERT (DevicePath != NULL);\r
+\r
+  Status = EfiBootManagerInitializeLoadOption (\r
+             BootOption,\r
+             LoadOptionNumberUnassigned,\r
+             LoadOptionTypeBoot,\r
+             LOAD_OPTION_CATEGORY_APP | LOAD_OPTION_ACTIVE | LOAD_OPTION_HIDDEN,\r
+             (Description != NULL) ? Description : L"Boot Manager Menu",\r
+             DevicePath,\r
+             NULL,\r
+             0\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+  FreePool (DevicePath);\r
+  if (Description != NULL) {\r
+    FreePool (Description);\r
+  }\r
+\r
+  DEBUG_CODE (\r
+    EFI_BOOT_MANAGER_LOAD_OPTION    *BootOptions;\r
+    UINTN                           BootOptionCount;\r
+\r
+    BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);\r
+    ASSERT (BmFindLoadOption (BootOption, BootOptions, BootOptionCount) == -1);\r
+    EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);\r
+    );\r
+\r
+  return EfiBootManagerAddLoadOptionVariable (BootOption, 0);\r
+}\r
+\r
+/**\r
+  Return the boot option corresponding to the Boot Manager Menu.\r
+  It may automatically create one if the boot option hasn't been created yet.\r
+  \r
+  @param BootOption    Return the Boot Manager Menu.\r
+\r
+  @retval EFI_SUCCESS   The Boot Manager Menu is successfully returned.\r
+  @retval Status        Return status of gRT->SetVariable (). BootOption still points\r
+                        to the Boot Manager Menu even the Status is not EFI_SUCCESS.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiBootManagerGetBootManagerMenu (\r
+  EFI_BOOT_MANAGER_LOAD_OPTION *BootOption\r
+  )\r
+{\r
+  EFI_STATUS                   Status;\r
+  UINTN                        BootOptionCount;\r
+  EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;\r
+  UINTN                        Index;\r
+  EFI_DEVICE_PATH_PROTOCOL     *Node;\r
+  EFI_HANDLE                   FvHandle;\r
+  \r
+  BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);\r
+\r
+  for (Index = 0; Index < BootOptionCount; Index++) {\r
+    Node   = BootOptions[Index].FilePath;\r
+    Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &Node, &FvHandle);\r
+    if (!EFI_ERROR (Status)) {\r
+      if (CompareGuid (\r
+            EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) Node),\r
+            PcdGetPtr (PcdBootManagerMenuFile)\r
+            )\r
+          ) {        \r
+        Status = EfiBootManagerInitializeLoadOption (\r
+                   BootOption,\r
+                   BootOptions[Index].OptionNumber,\r
+                   BootOptions[Index].OptionType,\r
+                   BootOptions[Index].Attributes,\r
+                   BootOptions[Index].Description,\r
+                   BootOptions[Index].FilePath,\r
+                   BootOptions[Index].OptionalData,\r
+                   BootOptions[Index].OptionalDataSize\r
+                   );\r
+        ASSERT_EFI_ERROR (Status);\r
+        break;\r
+      }\r
+    }\r
+  }\r
+\r
+  EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);\r
+\r
+  //\r
+  // Automatically create the Boot#### for Boot Manager Menu when not found.\r
+  //\r
+  if (Index == BootOptionCount) {\r
+    return BmRegisterBootManagerMenu (BootOption);\r
+  } else {\r
+    return EFI_SUCCESS;\r
+  }\r
+}\r
+\r
index 9e3a683e25f9a7958147df093e1b989dbd73606e..b1c94ad9d9c743cab7d230943fb6d4dceee2aaa5 100644 (file)
-/** @file
-  Library functions which relate with connecting the device.
-
-Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
-This program and the accompanying materials
-are licensed and made available under the terms and conditions of the BSD License
-which accompanies this distribution.  The full text of the license may be found at
-http://opensource.org/licenses/bsd-license.php
-
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
-
-**/
-
-#include "InternalBm.h"
-
-/**
-  Connect all the drivers to all the controllers.
-
-  This function makes sure all the current system drivers manage the correspoinding
-  controllers if have. And at the same time, makes sure all the system controllers
-  have driver to manage it if have.
-**/
-VOID
-BmConnectAllDriversToAllControllers (
-  VOID
-  )
-{
-  EFI_STATUS  Status;
-  UINTN       HandleCount;
-  EFI_HANDLE  *HandleBuffer;
-  UINTN       Index;
-
-  do {
-    //
-    // Connect All EFI 1.10 drivers following EFI 1.10 algorithm
-    //
-    gBS->LocateHandleBuffer (
-           AllHandles,
-           NULL,
-           NULL,
-           &HandleCount,
-           &HandleBuffer
-           );
-
-    for (Index = 0; Index < HandleCount; Index++) {
-      gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
-    }
-
-    if (HandleBuffer != NULL) {
-      FreePool (HandleBuffer);
-    }
-
-    //
-    // Check to see if it's possible to dispatch an more DXE drivers.
-    // The above code may have made new DXE drivers show up.
-    // If any new driver is dispatched (Status == EFI_SUCCESS) and we will try
-    // the connect again.
-    //
-    Status = gDS->Dispatch ();
-
-  } while (!EFI_ERROR (Status));
-}
-
-/**
-  This function will connect all the system driver to controller
-  first, and then special connect the default console, this make
-  sure all the system controller available and the platform default
-  console connected.
-
-**/
-VOID
-EFIAPI
-EfiBootManagerConnectAll (
-  VOID
-  )
-{
-  //
-  // Connect the platform console first
-  //
-  EfiBootManagerConnectAllDefaultConsoles ();
-
-  //
-  // Generic way to connect all the drivers
-  //
-  BmConnectAllDriversToAllControllers ();
-
-  //
-  // Here we have the assumption that we have already had
-  // platform default console
-  //
-  EfiBootManagerConnectAllDefaultConsoles ();
-}
-
-/**
-  This function will create all handles associate with every device
-  path node. If the handle associate with one device path node can not
-  be created successfully, then still give chance to do the dispatch,
-  which load the missing drivers if possible.
-
-  @param  DevicePathToConnect   The device path which will be connected, it can be
-                                a multi-instance device path
-  @param  MatchingHandle        Return the controller handle closest to the DevicePathToConnect
-
-  @retval EFI_SUCCESS            All handles associate with every device path node
-                                 have been created.
-  @retval EFI_OUT_OF_RESOURCES   There is no resource to create new handles.
-  @retval EFI_NOT_FOUND          Create the handle associate with one device path
-                                 node failed.
-  @retval EFI_SECURITY_VIOLATION The user has no permission to start UEFI device 
-                                 drivers on the DevicePath.
-**/
-EFI_STATUS
-EFIAPI
-EfiBootManagerConnectDevicePath (
-  IN  EFI_DEVICE_PATH_PROTOCOL  *DevicePathToConnect,
-  OUT EFI_HANDLE                *MatchingHandle          OPTIONAL
-  )
-{
-  EFI_STATUS                Status;
-  EFI_DEVICE_PATH_PROTOCOL  *RemainingDevicePath;
-  EFI_HANDLE                Handle;
-  EFI_HANDLE                PreviousHandle;
-  EFI_TPL                   CurrentTpl;
-
-  if (DevicePathToConnect == NULL) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  CurrentTpl = EfiGetCurrentTpl ();
-  //
-  // Start the real work of connect with RemainingDevicePath
-  //
-  PreviousHandle = NULL;
-  do {
-    //
-    // Find the handle that best matches the Device Path. If it is only a
-    // partial match the remaining part of the device path is returned in
-    // RemainingDevicePath.
-    //
-    RemainingDevicePath = DevicePathToConnect;
-    Status              = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingDevicePath, &Handle);
-    if (!EFI_ERROR (Status)) {
-      if (Handle == PreviousHandle) {
-        //
-        // If no forward progress is made try invoking the Dispatcher.
-        // A new FV may have been added to the system an new drivers
-        // may now be found.
-        // Status == EFI_SUCCESS means a driver was dispatched
-        // Status == EFI_NOT_FOUND means no new drivers were dispatched
-        //
-        if (CurrentTpl == TPL_APPLICATION) {
-          Status = gDS->Dispatch ();
-        } else {
-          //
-          // Always return EFI_NOT_FOUND here
-          // to prevent dead loop when control handle is found but connection failded case
-          //
-          Status = EFI_NOT_FOUND;
-        }
-      }
-
-
-      if (!EFI_ERROR (Status)) {
-        PreviousHandle = Handle;
-        //
-        // Connect all drivers that apply to Handle and RemainingDevicePath,
-        // the Recursive flag is FALSE so only one level will be expanded.
-        //
-        // If ConnectController fails to find a driver, then still give the chance to 
-        // do dispatch, because partial RemainingDevicePath may be in the new FV
-        //
-        // 1. If the connect fail, RemainingDevicepath and handle will not
-        //    change, so next time will do the dispatch, then dispatch's status
-        //    will take effect
-        // 2. If the connect success, the RemainingDevicepath and handle will
-        //    change, then avoid the dispatch, we have chance to continue the
-        //    next connection
-        //
-        Status = gBS->ConnectController (Handle, NULL, RemainingDevicePath, FALSE);
-        if (Status == EFI_NOT_FOUND) {
-          Status = EFI_SUCCESS;
-        }
-        if (MatchingHandle != NULL) {
-          *MatchingHandle = Handle;
-        }
-      }
-    }
-    //
-    // Loop until RemainingDevicePath is an empty device path
-    //
-  } while (!EFI_ERROR (Status) && !IsDevicePathEnd (RemainingDevicePath));
-
-  ASSERT (EFI_ERROR (Status) || IsDevicePathEnd (RemainingDevicePath));
-
-  return Status;
-}
-
-/**
-  This function will disconnect all current system handles. 
-  
-  gBS->DisconnectController() is invoked for each handle exists in system handle buffer.
-  If handle is a bus type handle, all childrens also are disconnected recursively by
-  gBS->DisconnectController().
-**/
-VOID
-EFIAPI
-EfiBootManagerDisconnectAll (
-  VOID
-  )
-{
-  UINTN       HandleCount;
-  EFI_HANDLE  *HandleBuffer;
-  UINTN       Index;
-
-  //
-  // Disconnect all
-  //
-  gBS->LocateHandleBuffer (
-         AllHandles,
-         NULL,
-         NULL,
-         &HandleCount,
-         &HandleBuffer
-         );
-  for (Index = 0; Index < HandleCount; Index++) {
-    gBS->DisconnectController (HandleBuffer[Index], NULL, NULL);
-  }
-
-  if (HandleBuffer != NULL) {
-    FreePool (HandleBuffer);
-  }
-}
-
-/**
-  Connect the specific Usb device which match the short form device path,
-  and whose bus is determined by Host Controller (Uhci or Ehci).
-
-  @param  DevicePath             A short-form device path that starts with the first
-                                 element being a USB WWID or a USB Class device
-                                 path
-
-  @return EFI_INVALID_PARAMETER  DevicePath is NULL pointer.
-                                 DevicePath is not a USB device path.
-
-  @return EFI_SUCCESS            Success to connect USB device
-  @return EFI_NOT_FOUND          Fail to find handle for USB controller to connect.
-
-**/
-EFI_STATUS
-BmConnectUsbShortFormDevicePath (
-  IN EFI_DEVICE_PATH_PROTOCOL   *DevicePath
-  )
-{
-  EFI_STATUS                            Status;
-  EFI_HANDLE                            *Handles;
-  UINTN                                 HandleCount;
-  UINTN                                 Index;
-  EFI_PCI_IO_PROTOCOL                   *PciIo;
-  UINT8                                 Class[3];
-  BOOLEAN                               AtLeastOneConnected;
-
-  //
-  // Check the passed in parameters
-  //
-  if (DevicePath == NULL) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  if ((DevicePathType (DevicePath) != MESSAGING_DEVICE_PATH) ||
-      ((DevicePathSubType (DevicePath) != MSG_USB_CLASS_DP) && (DevicePathSubType (DevicePath) != MSG_USB_WWID_DP))
-     ) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  //
-  // Find the usb host controller firstly, then connect with the remaining device path
-  //
-  AtLeastOneConnected = FALSE;
-  Status = gBS->LocateHandleBuffer (
-                  ByProtocol,
-                  &gEfiPciIoProtocolGuid,
-                  NULL,
-                  &HandleCount,
-                  &Handles
-                  );
-  if (!EFI_ERROR (Status)) {
-    for (Index = 0; Index < HandleCount; Index++) {
-      Status = gBS->HandleProtocol (
-                      Handles[Index],
-                      &gEfiPciIoProtocolGuid,
-                      (VOID **) &PciIo
-                      );
-      if (!EFI_ERROR (Status)) {
-        //
-        // Check whether the Pci device is the wanted usb host controller
-        //
-        Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x09, 3, &Class);
-        if (!EFI_ERROR (Status) &&
-            ((PCI_CLASS_SERIAL == Class[2]) && (PCI_CLASS_SERIAL_USB == Class[1]))
-           ) {
-          Status = gBS->ConnectController (
-                          Handles[Index],
-                          NULL,
-                          DevicePath,
-                          FALSE
-                          );
-          if (!EFI_ERROR(Status)) {
-            AtLeastOneConnected = TRUE;
-          }
-        }
-      }
-    }
-
-    if (Handles != NULL) {
-      FreePool (Handles);
-    }
-  }
-
-  return AtLeastOneConnected ? EFI_SUCCESS : EFI_NOT_FOUND;
-}
+/** @file\r
+  Library functions which relate with connecting the device.\r
+\r
+Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "InternalBm.h"\r
+\r
+/**\r
+  Connect all the drivers to all the controllers.\r
+\r
+  This function makes sure all the current system drivers manage the correspoinding\r
+  controllers if have. And at the same time, makes sure all the system controllers\r
+  have driver to manage it if have.\r
+**/\r
+VOID\r
+BmConnectAllDriversToAllControllers (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINTN       HandleCount;\r
+  EFI_HANDLE  *HandleBuffer;\r
+  UINTN       Index;\r
+\r
+  do {\r
+    //\r
+    // Connect All EFI 1.10 drivers following EFI 1.10 algorithm\r
+    //\r
+    gBS->LocateHandleBuffer (\r
+           AllHandles,\r
+           NULL,\r
+           NULL,\r
+           &HandleCount,\r
+           &HandleBuffer\r
+           );\r
+\r
+    for (Index = 0; Index < HandleCount; Index++) {\r
+      gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE);\r
+    }\r
+\r
+    if (HandleBuffer != NULL) {\r
+      FreePool (HandleBuffer);\r
+    }\r
+\r
+    //\r
+    // Check to see if it's possible to dispatch an more DXE drivers.\r
+    // The above code may have made new DXE drivers show up.\r
+    // If any new driver is dispatched (Status == EFI_SUCCESS) and we will try\r
+    // the connect again.\r
+    //\r
+    Status = gDS->Dispatch ();\r
+\r
+  } while (!EFI_ERROR (Status));\r
+}\r
+\r
+/**\r
+  This function will connect all the system driver to controller\r
+  first, and then special connect the default console, this make\r
+  sure all the system controller available and the platform default\r
+  console connected.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+EfiBootManagerConnectAll (\r
+  VOID\r
+  )\r
+{\r
+  //\r
+  // Connect the platform console first\r
+  //\r
+  EfiBootManagerConnectAllDefaultConsoles ();\r
+\r
+  //\r
+  // Generic way to connect all the drivers\r
+  //\r
+  BmConnectAllDriversToAllControllers ();\r
+\r
+  //\r
+  // Here we have the assumption that we have already had\r
+  // platform default console\r
+  //\r
+  EfiBootManagerConnectAllDefaultConsoles ();\r
+}\r
+\r
+/**\r
+  This function will create all handles associate with every device\r
+  path node. If the handle associate with one device path node can not\r
+  be created successfully, then still give chance to do the dispatch,\r
+  which load the missing drivers if possible.\r
+\r
+  @param  DevicePathToConnect   The device path which will be connected, it can be\r
+                                a multi-instance device path\r
+  @param  MatchingHandle        Return the controller handle closest to the DevicePathToConnect\r
+\r
+  @retval EFI_SUCCESS            All handles associate with every device path node\r
+                                 have been created.\r
+  @retval EFI_OUT_OF_RESOURCES   There is no resource to create new handles.\r
+  @retval EFI_NOT_FOUND          Create the handle associate with one device path\r
+                                 node failed.\r
+  @retval EFI_SECURITY_VIOLATION The user has no permission to start UEFI device \r
+                                 drivers on the DevicePath.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiBootManagerConnectDevicePath (\r
+  IN  EFI_DEVICE_PATH_PROTOCOL  *DevicePathToConnect,\r
+  OUT EFI_HANDLE                *MatchingHandle          OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  EFI_DEVICE_PATH_PROTOCOL  *RemainingDevicePath;\r
+  EFI_HANDLE                Handle;\r
+  EFI_HANDLE                PreviousHandle;\r
+  EFI_TPL                   CurrentTpl;\r
+\r
+  if (DevicePathToConnect == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  CurrentTpl = EfiGetCurrentTpl ();\r
+  //\r
+  // Start the real work of connect with RemainingDevicePath\r
+  //\r
+  PreviousHandle = NULL;\r
+  do {\r
+    //\r
+    // Find the handle that best matches the Device Path. If it is only a\r
+    // partial match the remaining part of the device path is returned in\r
+    // RemainingDevicePath.\r
+    //\r
+    RemainingDevicePath = DevicePathToConnect;\r
+    Status              = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingDevicePath, &Handle);\r
+    if (!EFI_ERROR (Status)) {\r
+      if (Handle == PreviousHandle) {\r
+        //\r
+        // If no forward progress is made try invoking the Dispatcher.\r
+        // A new FV may have been added to the system an new drivers\r
+        // may now be found.\r
+        // Status == EFI_SUCCESS means a driver was dispatched\r
+        // Status == EFI_NOT_FOUND means no new drivers were dispatched\r
+        //\r
+        if (CurrentTpl == TPL_APPLICATION) {\r
+          Status = gDS->Dispatch ();\r
+        } else {\r
+          //\r
+          // Always return EFI_NOT_FOUND here\r
+          // to prevent dead loop when control handle is found but connection failded case\r
+          //\r
+          Status = EFI_NOT_FOUND;\r
+        }\r
+      }\r
+\r
+\r
+      if (!EFI_ERROR (Status)) {\r
+        PreviousHandle = Handle;\r
+        //\r
+        // Connect all drivers that apply to Handle and RemainingDevicePath,\r
+        // the Recursive flag is FALSE so only one level will be expanded.\r
+        //\r
+        // If ConnectController fails to find a driver, then still give the chance to \r
+        // do dispatch, because partial RemainingDevicePath may be in the new FV\r
+        //\r
+        // 1. If the connect fail, RemainingDevicepath and handle will not\r
+        //    change, so next time will do the dispatch, then dispatch's status\r
+        //    will take effect\r
+        // 2. If the connect success, the RemainingDevicepath and handle will\r
+        //    change, then avoid the dispatch, we have chance to continue the\r
+        //    next connection\r
+        //\r
+        Status = gBS->ConnectController (Handle, NULL, RemainingDevicePath, FALSE);\r
+        if (Status == EFI_NOT_FOUND) {\r
+          Status = EFI_SUCCESS;\r
+        }\r
+        if (MatchingHandle != NULL) {\r
+          *MatchingHandle = Handle;\r
+        }\r
+      }\r
+    }\r
+    //\r
+    // Loop until RemainingDevicePath is an empty device path\r
+    //\r
+  } while (!EFI_ERROR (Status) && !IsDevicePathEnd (RemainingDevicePath));\r
+\r
+  ASSERT (EFI_ERROR (Status) || IsDevicePathEnd (RemainingDevicePath));\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  This function will disconnect all current system handles. \r
+  \r
+  gBS->DisconnectController() is invoked for each handle exists in system handle buffer.\r
+  If handle is a bus type handle, all childrens also are disconnected recursively by\r
+  gBS->DisconnectController().\r
+**/\r
+VOID\r
+EFIAPI\r
+EfiBootManagerDisconnectAll (\r
+  VOID\r
+  )\r
+{\r
+  UINTN       HandleCount;\r
+  EFI_HANDLE  *HandleBuffer;\r
+  UINTN       Index;\r
+\r
+  //\r
+  // Disconnect all\r
+  //\r
+  gBS->LocateHandleBuffer (\r
+         AllHandles,\r
+         NULL,\r
+         NULL,\r
+         &HandleCount,\r
+         &HandleBuffer\r
+         );\r
+  for (Index = 0; Index < HandleCount; Index++) {\r
+    gBS->DisconnectController (HandleBuffer[Index], NULL, NULL);\r
+  }\r
+\r
+  if (HandleBuffer != NULL) {\r
+    FreePool (HandleBuffer);\r
+  }\r
+}\r
+\r
+/**\r
+  Connect the specific Usb device which match the short form device path,\r
+  and whose bus is determined by Host Controller (Uhci or Ehci).\r
+\r
+  @param  DevicePath             A short-form device path that starts with the first\r
+                                 element being a USB WWID or a USB Class device\r
+                                 path\r
+\r
+  @return EFI_INVALID_PARAMETER  DevicePath is NULL pointer.\r
+                                 DevicePath is not a USB device path.\r
+\r
+  @return EFI_SUCCESS            Success to connect USB device\r
+  @return EFI_NOT_FOUND          Fail to find handle for USB controller to connect.\r
+\r
+**/\r
+EFI_STATUS\r
+BmConnectUsbShortFormDevicePath (\r
+  IN EFI_DEVICE_PATH_PROTOCOL   *DevicePath\r
+  )\r
+{\r
+  EFI_STATUS                            Status;\r
+  EFI_HANDLE                            *Handles;\r
+  UINTN                                 HandleCount;\r
+  UINTN                                 Index;\r
+  EFI_PCI_IO_PROTOCOL                   *PciIo;\r
+  UINT8                                 Class[3];\r
+  BOOLEAN                               AtLeastOneConnected;\r
+\r
+  //\r
+  // Check the passed in parameters\r
+  //\r
+  if (DevicePath == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((DevicePathType (DevicePath) != MESSAGING_DEVICE_PATH) ||\r
+      ((DevicePathSubType (DevicePath) != MSG_USB_CLASS_DP) && (DevicePathSubType (DevicePath) != MSG_USB_WWID_DP))\r
+     ) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Find the usb host controller firstly, then connect with the remaining device path\r
+  //\r
+  AtLeastOneConnected = FALSE;\r
+  Status = gBS->LocateHandleBuffer (\r
+                  ByProtocol,\r
+                  &gEfiPciIoProtocolGuid,\r
+                  NULL,\r
+                  &HandleCount,\r
+                  &Handles\r
+                  );\r
+  if (!EFI_ERROR (Status)) {\r
+    for (Index = 0; Index < HandleCount; Index++) {\r
+      Status = gBS->HandleProtocol (\r
+                      Handles[Index],\r
+                      &gEfiPciIoProtocolGuid,\r
+                      (VOID **) &PciIo\r
+                      );\r
+      if (!EFI_ERROR (Status)) {\r
+        //\r
+        // Check whether the Pci device is the wanted usb host controller\r
+        //\r
+        Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x09, 3, &Class);\r
+        if (!EFI_ERROR (Status) &&\r
+            ((PCI_CLASS_SERIAL == Class[2]) && (PCI_CLASS_SERIAL_USB == Class[1]))\r
+           ) {\r
+          Status = gBS->ConnectController (\r
+                          Handles[Index],\r
+                          NULL,\r
+                          DevicePath,\r
+                          FALSE\r
+                          );\r
+          if (!EFI_ERROR(Status)) {\r
+            AtLeastOneConnected = TRUE;\r
+          }\r
+        }\r
+      }\r
+    }\r
+\r
+    if (Handles != NULL) {\r
+      FreePool (Handles);\r
+    }\r
+  }\r
+\r
+  return AtLeastOneConnected ? EFI_SUCCESS : EFI_NOT_FOUND;\r
+}\r
index 4f5c8b04c2106e4bdcd5d00874e37a87bdc19595..86b4fac4241e33bf754fd42465ea7c330e2458c8 100644 (file)
-/** @file
-  Library functions which contain all the code to connect console device.
-
-Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
-This program and the accompanying materials
-are licensed and made available under the terms and conditions of the BSD License
-which accompanies this distribution.  The full text of the license may be found at
-http://opensource.org/licenses/bsd-license.php
-
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
-
-**/
-
-#include "InternalBm.h"
-
-CHAR16       *mConVarName[] = {
-  L"ConIn",
-  L"ConOut",
-  L"ErrOut",
-  L"ConInDev",
-  L"ConOutDev",
-  L"ErrOutDev"
-};
-
-/**
-  Search out the video controller.
-
-  @return  PCI device path of the video controller.
-**/
-EFI_HANDLE
-BmGetVideoController (
-  VOID
-  )
-{
-  EFI_STATUS                Status;
-  UINTN                     RootBridgeHandleCount;
-  EFI_HANDLE                *RootBridgeHandleBuffer;
-  UINTN                     HandleCount;
-  EFI_HANDLE                *HandleBuffer;
-  UINTN                     RootBridgeIndex;
-  UINTN                     Index;
-  EFI_HANDLE                VideoController;
-  EFI_PCI_IO_PROTOCOL       *PciIo;
-  PCI_TYPE00                Pci;
-
-  //
-  // Make all the PCI_IO protocols show up
-  //
-  Status = gBS->LocateHandleBuffer (
-                  ByProtocol,
-                  &gEfiPciRootBridgeIoProtocolGuid,
-                  NULL,
-                  &RootBridgeHandleCount,
-                  &RootBridgeHandleBuffer
-                  );
-  if (EFI_ERROR (Status) || (RootBridgeHandleCount == 0)) {
-    return NULL;
-  }
-
-  VideoController = NULL;
-  for (RootBridgeIndex = 0; RootBridgeIndex < RootBridgeHandleCount; RootBridgeIndex++) {
-    gBS->ConnectController (RootBridgeHandleBuffer[RootBridgeIndex], NULL, NULL, FALSE);
-
-    //
-    // Start to check all the pci io to find the first video controller
-    //
-    Status = gBS->LocateHandleBuffer (
-                    ByProtocol,
-                    &gEfiPciIoProtocolGuid,
-                    NULL,
-                    &HandleCount,
-                    &HandleBuffer
-                    );
-    if (EFI_ERROR (Status)) {
-      continue;
-    }
-
-    for (Index = 0; Index < HandleCount; Index++) {
-      Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiPciIoProtocolGuid, (VOID **) &PciIo);
-      if (!EFI_ERROR (Status)) {
-        //
-        // Check for all video controller
-        //
-        Status = PciIo->Pci.Read (
-                          PciIo,
-                          EfiPciIoWidthUint32,
-                          0,
-                          sizeof (Pci) / sizeof (UINT32),
-                          &Pci
-                          );
-        if (!EFI_ERROR (Status) && IS_PCI_VGA (&Pci)) {
-          // TODO: use IS_PCI_DISPLAY??
-          VideoController = HandleBuffer[Index];
-          break;
-        }
-      }
-    }
-    FreePool (HandleBuffer);
-
-    if (VideoController != NULL) {
-      break;
-    }
-  }
-  FreePool (RootBridgeHandleBuffer);
-  
-  return VideoController;
-}
-
-/**
-  Query all the children of VideoController and return the device paths of all the 
-  children that support GraphicsOutput protocol.
-
-  @param VideoController       PCI handle of video controller.
-
-  @return  Device paths of all the children that support GraphicsOutput protocol.
-**/
-EFI_DEVICE_PATH_PROTOCOL *
-EFIAPI
-EfiBootManagerGetGopDevicePath (
-  IN  EFI_HANDLE                       VideoController
-  )
-{
-  UINTN                                Index;
-  EFI_STATUS                           Status;
-  EFI_GUID                             **ProtocolBuffer;
-  UINTN                                ProtocolBufferCount;
-  UINTN                                ProtocolIndex;
-  EFI_OPEN_PROTOCOL_INFORMATION_ENTRY  *OpenInfoBuffer;
-  UINTN                                EntryCount;
-  EFI_DEVICE_PATH_PROTOCOL             *DevicePath;
-  EFI_DEVICE_PATH_PROTOCOL             *Next;
-  EFI_DEVICE_PATH_PROTOCOL             *Previous;
-  EFI_DEVICE_PATH_PROTOCOL             *TempDevicePath;
-  EFI_DEVICE_PATH_PROTOCOL             *GopPool;
-  EFI_DEVICE_PATH_PROTOCOL             *ReturnDevicePath;
-
-
-  Status = gBS->ProtocolsPerHandle (
-                  VideoController,
-                  &ProtocolBuffer,
-                  &ProtocolBufferCount
-                  );
-  if (EFI_ERROR (Status)) {
-    return NULL;
-  }
-
-  GopPool = NULL;
-
-  for (ProtocolIndex = 0; ProtocolIndex < ProtocolBufferCount; ProtocolIndex++) {
-    Status = gBS->OpenProtocolInformation (
-                    VideoController,
-                    ProtocolBuffer[ProtocolIndex],
-                    &OpenInfoBuffer,
-                    &EntryCount
-                    );
-    if (EFI_ERROR (Status)) {
-      continue;
-    }
-
-    for (Index = 0; Index < EntryCount; Index++) {
-      //
-      // Query all the children
-      //
-      if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
-        Status = gBS->OpenProtocol (
-                        OpenInfoBuffer[Index].ControllerHandle,
-                        &gEfiDevicePathProtocolGuid,
-                        (VOID **) &DevicePath,
-                        NULL,
-                        NULL,
-                        EFI_OPEN_PROTOCOL_GET_PROTOCOL
-                        );
-        if (EFI_ERROR (Status)) {
-          continue;
-        }
-
-        Previous = NULL;
-        for (Next = DevicePath; !IsDevicePathEnd (Next); Next = NextDevicePathNode (Next)) {
-          Previous = Next;
-        }
-        ASSERT (Previous != NULL);
-
-        if (DevicePathType (Previous) == ACPI_DEVICE_PATH && DevicePathSubType (Previous) == ACPI_ADR_DP) {
-          Status = gBS->OpenProtocol (
-                          OpenInfoBuffer[Index].ControllerHandle,
-                          &gEfiGraphicsOutputProtocolGuid,
-                          NULL,
-                          NULL,
-                          NULL,
-                          EFI_OPEN_PROTOCOL_TEST_PROTOCOL
-                          );
-          if (!EFI_ERROR (Status)) {
-            //
-            // Append the device path to GOP pool when there is GOP protocol installed.
-            //
-            TempDevicePath = GopPool;
-            GopPool = AppendDevicePathInstance (GopPool, DevicePath);
-            gBS->FreePool (TempDevicePath);
-          }
-        }
-
-        if (DevicePathType (Previous) == HARDWARE_DEVICE_PATH && DevicePathSubType (Previous) == HW_CONTROLLER_DP) {
-          //
-          // Recursively look for GOP child in this frame buffer handle
-          //
-          DEBUG ((EFI_D_INFO, "[Bds] Looking for GOP child deeper ... \n"));
-          TempDevicePath = GopPool;
-          ReturnDevicePath = EfiBootManagerGetGopDevicePath (OpenInfoBuffer[Index].ControllerHandle);
-          GopPool = AppendDevicePathInstance (GopPool, ReturnDevicePath);
-          gBS->FreePool (ReturnDevicePath);
-          gBS->FreePool (TempDevicePath);
-        }
-      }
-    }
-
-    FreePool (OpenInfoBuffer);
-  }
-
-  FreePool (ProtocolBuffer);
-
-  return GopPool;
-}
-
-/**
-  Connect the platform active active video controller.
-
-  @param VideoController       PCI handle of video controller.
-
-  @retval EFI_NOT_FOUND There is no active video controller.
-  @retval EFI_SUCCESS   The video controller is connected.
-**/
-EFI_STATUS
-EFIAPI
-EfiBootManagerConnectVideoController (
-  EFI_HANDLE                 VideoController  OPTIONAL
-  )
-{
-  EFI_DEVICE_PATH_PROTOCOL   *Gop;
-  
-  if (VideoController == NULL) {
-    //
-    // Get the platform vga device
-    //
-    VideoController = BmGetVideoController ();
-  }
-  if (VideoController == NULL) {
-    return EFI_NOT_FOUND;
-  }
-
-  //
-  // Try to connect the PCI device path, so that GOP dirver could start on this 
-  // device and create child handles with GraphicsOutput Protocol installed
-  // on them, then we get device paths of these child handles and select 
-  // them as possible console device.
-  //
-  gBS->ConnectController (VideoController, NULL, NULL, FALSE);
-
-  Gop = EfiBootManagerGetGopDevicePath (VideoController);
-  if (Gop == NULL) {
-    return EFI_NOT_FOUND;
-  }
-
-  EfiBootManagerUpdateConsoleVariable (ConOut, Gop, NULL);
-  FreePool (Gop);
-
-  //
-  // Necessary for ConPlatform and ConSplitter driver to start up again after ConOut is updated.
-  //
-  return gBS->ConnectController (VideoController, NULL, NULL, TRUE);
-}
-
-/**
-  Fill console handle in System Table if there are no valid console handle in.
-
-  Firstly, check the validation of console handle in System Table. If it is invalid,
-  update it by the first console device handle from EFI console variable. 
-
-  @param  VarName            The name of the EFI console variable.
-  @param  ConsoleGuid        Specified Console protocol GUID.
-  @param  ConsoleHandle      On IN,  console handle in System Table to be checked. 
-                             On OUT, new console handle in system table.
-  @param  ProtocolInterface  On IN,  console protocol on console handle in System Table to be checked. 
-                             On OUT, new console protocol on new console handle in system table.
-
-  @retval TRUE               System Table has been updated.
-  @retval FALSE              System Table hasn't been updated.
-
-**/
-BOOLEAN 
-BmUpdateSystemTableConsole (
-  IN     CHAR16                   *VarName,
-  IN     EFI_GUID                 *ConsoleGuid,
-  IN OUT EFI_HANDLE               *ConsoleHandle,
-  IN OUT VOID                     **ProtocolInterface
-  )
-{
-  EFI_STATUS                      Status;
-  UINTN                           DevicePathSize;
-  EFI_DEVICE_PATH_PROTOCOL        *FullDevicePath;
-  EFI_DEVICE_PATH_PROTOCOL        *VarConsole;
-  EFI_DEVICE_PATH_PROTOCOL        *Instance;
-  VOID                            *Interface;
-  EFI_HANDLE                      NewHandle;
-  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut;
-
-  ASSERT (VarName != NULL);
-  ASSERT (ConsoleHandle != NULL);
-  ASSERT (ConsoleGuid != NULL);
-  ASSERT (ProtocolInterface != NULL);
-
-  if (*ConsoleHandle != NULL) {
-    Status = gBS->HandleProtocol (
-                   *ConsoleHandle,
-                   ConsoleGuid,
-                   &Interface
-                   );
-    if (Status == EFI_SUCCESS && Interface == *ProtocolInterface) {
-      //
-      // If ConsoleHandle is valid and console protocol on this handle also
-      // also matched, just return.
-      //
-      return FALSE;
-    }
-  }
-  
-  //
-  // Get all possible consoles device path from EFI variable
-  //
-  GetEfiGlobalVariable2 (VarName, (VOID **) &VarConsole, NULL);
-  if (VarConsole == NULL) {
-    //
-    // If there is no any console device, just return.
-    //
-    return FALSE;
-  }
-
-  FullDevicePath = VarConsole;
-
-  do {
-    //
-    // Check every instance of the console variable
-    //
-    Instance  = GetNextDevicePathInstance (&VarConsole, &DevicePathSize);
-    if (Instance == NULL) {
-      DEBUG ((EFI_D_ERROR, "[Bds] No valid console instance is found for %s!\n", VarName));
-      // We should not ASSERT when all the console devices are removed.
-      // ASSERT_EFI_ERROR (EFI_NOT_FOUND);
-      FreePool (FullDevicePath);
-      return FALSE;
-    }
-    
-    //
-    // Find console device handle by device path instance
-    //
-    Status = gBS->LocateDevicePath (
-                    ConsoleGuid,
-                    &Instance,
-                    &NewHandle
-                    );
-    if (!EFI_ERROR (Status)) {
-      //
-      // Get the console protocol on this console device handle
-      //
-      Status = gBS->HandleProtocol (
-                      NewHandle,
-                      ConsoleGuid,
-                      &Interface
-                      );
-      if (!EFI_ERROR (Status)) {
-        //
-        // Update new console handle in System Table.
-        //
-        *ConsoleHandle     = NewHandle;
-        *ProtocolInterface = Interface;
-        if (CompareGuid (ConsoleGuid, &gEfiSimpleTextOutProtocolGuid)) {
-          //
-          // If it is console out device, set console mode 80x25 if current mode is invalid.
-          //
-          TextOut = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *) Interface;
-          if (TextOut->Mode->Mode == -1) {
-            TextOut->SetMode (TextOut, 0);
-          }
-        }
-        return TRUE;
-      }
-    }
-
-  } while (Instance != NULL);
-
-  //
-  // No any available console devcie found.
-  //
-  return FALSE;
-}
-
-/**
-  This function updates the console variable based on ConVarName. It can
-  add or remove one specific console device path from the variable
-
-  @param  ConsoleType              ConIn, ConOut, ErrOut, ConInDev, ConOutDev or ErrOutDev.
-  @param  CustomizedConDevicePath  The console device path to be added to
-                                   the console variable. Cannot be multi-instance.
-  @param  ExclusiveDevicePath      The console device path to be removed
-                                   from the console variable. Cannot be multi-instance.
-
-  @retval EFI_UNSUPPORTED          The added device path is the same as a removed one.
-  @retval EFI_SUCCESS              Successfully added or removed the device path from the
-                                   console variable.
-  @retval others                   Return status of RT->SetVariable().
-
-**/
-EFI_STATUS
-EFIAPI
-EfiBootManagerUpdateConsoleVariable (
-  IN  CONSOLE_TYPE              ConsoleType,
-  IN  EFI_DEVICE_PATH_PROTOCOL  *CustomizedConDevicePath,
-  IN  EFI_DEVICE_PATH_PROTOCOL  *ExclusiveDevicePath
-  )
-{
-  EFI_STATUS                Status;
-  EFI_DEVICE_PATH_PROTOCOL  *VarConsole;
-  EFI_DEVICE_PATH_PROTOCOL  *NewDevicePath;
-  EFI_DEVICE_PATH_PROTOCOL  *TempNewDevicePath;
-
-  if (ConsoleType >= sizeof (mConVarName) / sizeof (mConVarName[0])) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  //
-  // Notes: check the device path point, here should check
-  // with compare memory
-  //
-  if (CustomizedConDevicePath == ExclusiveDevicePath) {
-    return EFI_UNSUPPORTED;
-  }
-  //
-  // Delete the ExclusiveDevicePath from current default console
-  //
-  GetEfiGlobalVariable2 (mConVarName[ConsoleType], (VOID **) &VarConsole, NULL);
-  //
-  // Initialize NewDevicePath
-  //
-  NewDevicePath = VarConsole;
-
-  //
-  // If ExclusiveDevicePath is even the part of the instance in VarConsole, delete it.
-  // In the end, NewDevicePath is the final device path.
-  //
-  if (ExclusiveDevicePath != NULL && VarConsole != NULL) {
-      NewDevicePath = BmDelPartMatchInstance (VarConsole, ExclusiveDevicePath);
-  }
-  //
-  // Try to append customized device path to NewDevicePath.
-  //
-  if (CustomizedConDevicePath != NULL) {
-    if (!BmMatchDevicePaths (NewDevicePath, CustomizedConDevicePath)) {
-      //
-      // Check if there is part of CustomizedConDevicePath in NewDevicePath, delete it.
-      //
-      NewDevicePath = BmDelPartMatchInstance (NewDevicePath, CustomizedConDevicePath);
-      //
-      // In the first check, the default console variable will be _ModuleEntryPoint,
-      // just append current customized device path
-      //
-      TempNewDevicePath = NewDevicePath;
-      NewDevicePath = AppendDevicePathInstance (NewDevicePath, CustomizedConDevicePath);
-      if (TempNewDevicePath != NULL) {
-        FreePool(TempNewDevicePath);
-      }
-    }
-  }
-
-  //
-  // Finally, Update the variable of the default console by NewDevicePath
-  //
-  Status = gRT->SetVariable (
-                  mConVarName[ConsoleType],
-                  &gEfiGlobalVariableGuid,
-                  EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS
-                                                  | ((ConsoleType < ConInDev) ? EFI_VARIABLE_NON_VOLATILE : 0),
-                  GetDevicePathSize (NewDevicePath),
-                  NewDevicePath
-                  );
-
-  if (VarConsole == NewDevicePath) {
-    if (VarConsole != NULL) {
-      FreePool(VarConsole);
-    }
-  } else {
-    if (VarConsole != NULL) {
-      FreePool(VarConsole);
-    }
-    if (NewDevicePath != NULL) {
-      FreePool(NewDevicePath);
-    }
-  }
-
-  return Status;
-}
-
-
-/**
-  Connect the console device base on the variable ConsoleType.
-
-  @param  ConsoleType              ConIn, ConOut or ErrOut.
-
-  @retval EFI_NOT_FOUND            There is not any console devices connected
-                                   success
-  @retval EFI_SUCCESS              Success connect any one instance of the console
-                                   device path base on the variable ConVarName.
-
-**/
-EFI_STATUS
-EFIAPI
-EfiBootManagerConnectConsoleVariable (
-  IN  CONSOLE_TYPE              ConsoleType
-  )
-{
-  EFI_STATUS                Status;
-  EFI_DEVICE_PATH_PROTOCOL  *StartDevicePath;
-  EFI_DEVICE_PATH_PROTOCOL  *Instance;
-  EFI_DEVICE_PATH_PROTOCOL  *Next;
-  EFI_DEVICE_PATH_PROTOCOL  *CopyOfDevicePath;
-  UINTN                     Size;
-  BOOLEAN                   DeviceExist;
-  EFI_HANDLE                Handle;
-
-  if ((ConsoleType != ConIn) && (ConsoleType != ConOut) && (ConsoleType != ErrOut)) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  Status      = EFI_SUCCESS;
-  DeviceExist = FALSE;
-  Handle      = NULL;
-
-  //
-  // Check if the console variable exist
-  //
-  GetEfiGlobalVariable2 (mConVarName[ConsoleType], (VOID **) &StartDevicePath, NULL);
-  if (StartDevicePath == NULL) {
-    return EFI_UNSUPPORTED;
-  }
-
-  CopyOfDevicePath = StartDevicePath;
-  do {
-    //
-    // Check every instance of the console variable
-    //
-    Instance  = GetNextDevicePathInstance (&CopyOfDevicePath, &Size);
-    if (Instance == NULL) {
-      FreePool (StartDevicePath);
-      return EFI_UNSUPPORTED;
-    }
-    
-    Next      = Instance;
-    while (!IsDevicePathEndType (Next)) {
-      Next = NextDevicePathNode (Next);
-    }
-
-    SetDevicePathEndNode (Next);
-    //
-    // Connect the USB console
-    // USB console device path is a short-form device path that 
-    //  starts with the first element being a USB WWID
-    //  or a USB Class device path
-    //
-    if ((DevicePathType (Instance) == MESSAGING_DEVICE_PATH) &&
-        ((DevicePathSubType (Instance) == MSG_USB_CLASS_DP) || (DevicePathSubType (Instance) == MSG_USB_WWID_DP))
-       ) {
-      Status = BmConnectUsbShortFormDevicePath (Instance);
-      if (!EFI_ERROR (Status)) {
-        DeviceExist = TRUE;
-      }
-    } else {
-      for (Next = Instance; !IsDevicePathEnd (Next); Next = NextDevicePathNode (Next)) {
-        if (DevicePathType (Next) == ACPI_DEVICE_PATH && DevicePathSubType (Next) == ACPI_ADR_DP) {
-          break;
-        } else if (DevicePathType (Next) == HARDWARE_DEVICE_PATH && 
-                   DevicePathSubType (Next) == HW_CONTROLLER_DP &&
-                   DevicePathType (NextDevicePathNode (Next)) == ACPI_DEVICE_PATH &&
-                   DevicePathSubType (NextDevicePathNode (Next)) == ACPI_ADR_DP
-                   ) {
-          break;
-        }
-      }
-      if (!IsDevicePathEnd (Next)) {
-        //
-        // For GOP device path, start the video driver with NULL remaining device path
-        //
-        SetDevicePathEndNode (Next);
-        Status = EfiBootManagerConnectDevicePath (Instance, &Handle);
-        if (!EFI_ERROR (Status)) {
-          gBS->ConnectController (Handle, NULL, NULL, TRUE);
-        }
-      } else {
-        Status = EfiBootManagerConnectDevicePath (Instance, NULL);
-      }
-      if (EFI_ERROR (Status)) {
-        //
-        // Delete the instance from the console varialbe
-        //
-        EfiBootManagerUpdateConsoleVariable (ConsoleType, NULL, Instance);
-      } else {
-        DeviceExist = TRUE;
-      }
-    }
-    FreePool(Instance);
-  } while (CopyOfDevicePath != NULL);
-
-  FreePool (StartDevicePath);
-
-  if (!DeviceExist) {
-    return EFI_NOT_FOUND;
-  }
-
-  return EFI_SUCCESS;
-}
-
-
-/**
-  This function will search every input/output device in current system,
-  and make every input/output device as potential console device.
-**/
-VOID
-EFIAPI
-EfiBootManagerConnectAllConsoles (
-  VOID
-  )
-{
-  UINTN                     Index;
-  EFI_DEVICE_PATH_PROTOCOL  *ConDevicePath;
-  UINTN                     HandleCount;
-  EFI_HANDLE                *HandleBuffer;
-
-  Index         = 0;
-  HandleCount   = 0;
-  HandleBuffer  = NULL;
-  ConDevicePath = NULL;
-
-  //
-  // Update all the console variables
-  //
-  gBS->LocateHandleBuffer (
-          ByProtocol,
-          &gEfiSimpleTextInProtocolGuid,
-          NULL,
-          &HandleCount,
-          &HandleBuffer
-          );
-
-  for (Index = 0; Index < HandleCount; Index++) {
-    gBS->HandleProtocol (
-            HandleBuffer[Index],
-            &gEfiDevicePathProtocolGuid,
-            (VOID **) &ConDevicePath
-            );
-    EfiBootManagerUpdateConsoleVariable (ConIn, ConDevicePath, NULL);
-  }
-
-  if (HandleBuffer != NULL) {
-    FreePool(HandleBuffer);
-    HandleBuffer = NULL;
-  }
-
-  gBS->LocateHandleBuffer (
-          ByProtocol,
-          &gEfiSimpleTextOutProtocolGuid,
-          NULL,
-          &HandleCount,
-          &HandleBuffer
-          );
-  for (Index = 0; Index < HandleCount; Index++) {
-    gBS->HandleProtocol (
-            HandleBuffer[Index],
-            &gEfiDevicePathProtocolGuid,
-            (VOID **) &ConDevicePath
-            );
-    EfiBootManagerUpdateConsoleVariable (ConOut, ConDevicePath, NULL);
-    EfiBootManagerUpdateConsoleVariable (ErrOut, ConDevicePath, NULL);
-  }
-
-  if (HandleBuffer != NULL) {
-    FreePool(HandleBuffer);
-  }
-
-  //
-  // Connect all console variables
-  //
-  EfiBootManagerConnectAllDefaultConsoles ();
-}
-
-
-/**
-  This function will connect all the console devices base on the console
-  device variable ConIn, ConOut and ErrOut.
-
-  @retval EFI_DEVICE_ERROR         All the consoles were not connected due to an error.
-  @retval EFI_SUCCESS              Success connect any one instance of the console
-                                   device path base on the variable ConVarName.
-**/
-EFI_STATUS
-EFIAPI
-EfiBootManagerConnectAllDefaultConsoles (
-  VOID
-  )
-{
-  EFI_STATUS                Status;
-  BOOLEAN                   OneConnected;
-  BOOLEAN                   SystemTableUpdated;
-
-  OneConnected = FALSE;
-
-  Status = EfiBootManagerConnectConsoleVariable (ConOut);
-  if (!EFI_ERROR (Status)) {
-    OneConnected = TRUE;
-  }
-  PERF_START (NULL, "ConOutReady", "BDS", 1);
-  PERF_END   (NULL, "ConOutReady", "BDS", 0);
-
-  
-  Status = EfiBootManagerConnectConsoleVariable (ConIn);
-  if (!EFI_ERROR (Status)) {
-    OneConnected = TRUE;
-  }
-  PERF_START (NULL, "ConInReady", "BDS", 1);
-  PERF_END   (NULL, "ConInReady", "BDS", 0);
-
-  Status = EfiBootManagerConnectConsoleVariable (ErrOut);
-  if (!EFI_ERROR (Status)) {
-    OneConnected = TRUE;
-  }
-  PERF_START (NULL, "ErrOutReady", "BDS", 1);
-  PERF_END   (NULL, "ErrOutReady", "BDS", 0);
-
-  SystemTableUpdated = FALSE;
-  //
-  // Fill console handles in System Table if no console device assignd.
-  //
-  if (BmUpdateSystemTableConsole (L"ConIn", &gEfiSimpleTextInProtocolGuid, &gST->ConsoleInHandle, (VOID **) &gST->ConIn)) {
-    SystemTableUpdated = TRUE;
-  }
-  if (BmUpdateSystemTableConsole (L"ConOut", &gEfiSimpleTextOutProtocolGuid, &gST->ConsoleOutHandle, (VOID **) &gST->ConOut)) {
-    SystemTableUpdated = TRUE;
-  }
-  if (BmUpdateSystemTableConsole (L"ErrOut", &gEfiSimpleTextOutProtocolGuid, &gST->StandardErrorHandle, (VOID **) &gST->StdErr)) {
-    SystemTableUpdated = TRUE;
-  }
-
-  if (SystemTableUpdated) {
-    //
-    // Update the CRC32 in the EFI System Table header
-    //
-    gST->Hdr.CRC32 = 0;
-    gBS->CalculateCrc32 (
-          (UINT8 *) &gST->Hdr,
-          gST->Hdr.HeaderSize,
-          &gST->Hdr.CRC32
-          );
-  }
-
-  return OneConnected ? EFI_SUCCESS : EFI_DEVICE_ERROR;
-}
+/** @file\r
+  Library functions which contain all the code to connect console device.\r
+\r
+Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "InternalBm.h"\r
+\r
+CHAR16       *mConVarName[] = {\r
+  L"ConIn",\r
+  L"ConOut",\r
+  L"ErrOut",\r
+  L"ConInDev",\r
+  L"ConOutDev",\r
+  L"ErrOutDev"\r
+};\r
+\r
+/**\r
+  Search out the video controller.\r
+\r
+  @return  PCI device path of the video controller.\r
+**/\r
+EFI_HANDLE\r
+BmGetVideoController (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  UINTN                     RootBridgeHandleCount;\r
+  EFI_HANDLE                *RootBridgeHandleBuffer;\r
+  UINTN                     HandleCount;\r
+  EFI_HANDLE                *HandleBuffer;\r
+  UINTN                     RootBridgeIndex;\r
+  UINTN                     Index;\r
+  EFI_HANDLE                VideoController;\r
+  EFI_PCI_IO_PROTOCOL       *PciIo;\r
+  PCI_TYPE00                Pci;\r
+\r
+  //\r
+  // Make all the PCI_IO protocols show up\r
+  //\r
+  Status = gBS->LocateHandleBuffer (\r
+                  ByProtocol,\r
+                  &gEfiPciRootBridgeIoProtocolGuid,\r
+                  NULL,\r
+                  &RootBridgeHandleCount,\r
+                  &RootBridgeHandleBuffer\r
+                  );\r
+  if (EFI_ERROR (Status) || (RootBridgeHandleCount == 0)) {\r
+    return NULL;\r
+  }\r
+\r
+  VideoController = NULL;\r
+  for (RootBridgeIndex = 0; RootBridgeIndex < RootBridgeHandleCount; RootBridgeIndex++) {\r
+    gBS->ConnectController (RootBridgeHandleBuffer[RootBridgeIndex], NULL, NULL, FALSE);\r
+\r
+    //\r
+    // Start to check all the pci io to find the first video controller\r
+    //\r
+    Status = gBS->LocateHandleBuffer (\r
+                    ByProtocol,\r
+                    &gEfiPciIoProtocolGuid,\r
+                    NULL,\r
+                    &HandleCount,\r
+                    &HandleBuffer\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      continue;\r
+    }\r
+\r
+    for (Index = 0; Index < HandleCount; Index++) {\r
+      Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiPciIoProtocolGuid, (VOID **) &PciIo);\r
+      if (!EFI_ERROR (Status)) {\r
+        //\r
+        // Check for all video controller\r
+        //\r
+        Status = PciIo->Pci.Read (\r
+                          PciIo,\r
+                          EfiPciIoWidthUint32,\r
+                          0,\r
+                          sizeof (Pci) / sizeof (UINT32),\r
+                          &Pci\r
+                          );\r
+        if (!EFI_ERROR (Status) && IS_PCI_VGA (&Pci)) {\r
+          // TODO: use IS_PCI_DISPLAY??\r
+          VideoController = HandleBuffer[Index];\r
+          break;\r
+        }\r
+      }\r
+    }\r
+    FreePool (HandleBuffer);\r
+\r
+    if (VideoController != NULL) {\r
+      break;\r
+    }\r
+  }\r
+  FreePool (RootBridgeHandleBuffer);\r
+  \r
+  return VideoController;\r
+}\r
+\r
+/**\r
+  Query all the children of VideoController and return the device paths of all the \r
+  children that support GraphicsOutput protocol.\r
+\r
+  @param VideoController       PCI handle of video controller.\r
+\r
+  @return  Device paths of all the children that support GraphicsOutput protocol.\r
+**/\r
+EFI_DEVICE_PATH_PROTOCOL *\r
+EFIAPI\r
+EfiBootManagerGetGopDevicePath (\r
+  IN  EFI_HANDLE                       VideoController\r
+  )\r
+{\r
+  UINTN                                Index;\r
+  EFI_STATUS                           Status;\r
+  EFI_GUID                             **ProtocolBuffer;\r
+  UINTN                                ProtocolBufferCount;\r
+  UINTN                                ProtocolIndex;\r
+  EFI_OPEN_PROTOCOL_INFORMATION_ENTRY  *OpenInfoBuffer;\r
+  UINTN                                EntryCount;\r
+  EFI_DEVICE_PATH_PROTOCOL             *DevicePath;\r
+  EFI_DEVICE_PATH_PROTOCOL             *Next;\r
+  EFI_DEVICE_PATH_PROTOCOL             *Previous;\r
+  EFI_DEVICE_PATH_PROTOCOL             *TempDevicePath;\r
+  EFI_DEVICE_PATH_PROTOCOL             *GopPool;\r
+  EFI_DEVICE_PATH_PROTOCOL             *ReturnDevicePath;\r
+\r
+\r
+  Status = gBS->ProtocolsPerHandle (\r
+                  VideoController,\r
+                  &ProtocolBuffer,\r
+                  &ProtocolBufferCount\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return NULL;\r
+  }\r
+\r
+  GopPool = NULL;\r
+\r
+  for (ProtocolIndex = 0; ProtocolIndex < ProtocolBufferCount; ProtocolIndex++) {\r
+    Status = gBS->OpenProtocolInformation (\r
+                    VideoController,\r
+                    ProtocolBuffer[ProtocolIndex],\r
+                    &OpenInfoBuffer,\r
+                    &EntryCount\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      continue;\r
+    }\r
+\r
+    for (Index = 0; Index < EntryCount; Index++) {\r
+      //\r
+      // Query all the children\r
+      //\r
+      if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {\r
+        Status = gBS->OpenProtocol (\r
+                        OpenInfoBuffer[Index].ControllerHandle,\r
+                        &gEfiDevicePathProtocolGuid,\r
+                        (VOID **) &DevicePath,\r
+                        NULL,\r
+                        NULL,\r
+                        EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                        );\r
+        if (EFI_ERROR (Status)) {\r
+          continue;\r
+        }\r
+\r
+        Previous = NULL;\r
+        for (Next = DevicePath; !IsDevicePathEnd (Next); Next = NextDevicePathNode (Next)) {\r
+          Previous = Next;\r
+        }\r
+        ASSERT (Previous != NULL);\r
+\r
+        if (DevicePathType (Previous) == ACPI_DEVICE_PATH && DevicePathSubType (Previous) == ACPI_ADR_DP) {\r
+          Status = gBS->OpenProtocol (\r
+                          OpenInfoBuffer[Index].ControllerHandle,\r
+                          &gEfiGraphicsOutputProtocolGuid,\r
+                          NULL,\r
+                          NULL,\r
+                          NULL,\r
+                          EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+                          );\r
+          if (!EFI_ERROR (Status)) {\r
+            //\r
+            // Append the device path to GOP pool when there is GOP protocol installed.\r
+            //\r
+            TempDevicePath = GopPool;\r
+            GopPool = AppendDevicePathInstance (GopPool, DevicePath);\r
+            gBS->FreePool (TempDevicePath);\r
+          }\r
+        }\r
+\r
+        if (DevicePathType (Previous) == HARDWARE_DEVICE_PATH && DevicePathSubType (Previous) == HW_CONTROLLER_DP) {\r
+          //\r
+          // Recursively look for GOP child in this frame buffer handle\r
+          //\r
+          DEBUG ((EFI_D_INFO, "[Bds] Looking for GOP child deeper ... \n"));\r
+          TempDevicePath = GopPool;\r
+          ReturnDevicePath = EfiBootManagerGetGopDevicePath (OpenInfoBuffer[Index].ControllerHandle);\r
+          GopPool = AppendDevicePathInstance (GopPool, ReturnDevicePath);\r
+          gBS->FreePool (ReturnDevicePath);\r
+          gBS->FreePool (TempDevicePath);\r
+        }\r
+      }\r
+    }\r
+\r
+    FreePool (OpenInfoBuffer);\r
+  }\r
+\r
+  FreePool (ProtocolBuffer);\r
+\r
+  return GopPool;\r
+}\r
+\r
+/**\r
+  Connect the platform active active video controller.\r
+\r
+  @param VideoController       PCI handle of video controller.\r
+\r
+  @retval EFI_NOT_FOUND There is no active video controller.\r
+  @retval EFI_SUCCESS   The video controller is connected.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiBootManagerConnectVideoController (\r
+  EFI_HANDLE                 VideoController  OPTIONAL\r
+  )\r
+{\r
+  EFI_DEVICE_PATH_PROTOCOL   *Gop;\r
+  \r
+  if (VideoController == NULL) {\r
+    //\r
+    // Get the platform vga device\r
+    //\r
+    VideoController = BmGetVideoController ();\r
+  }\r
\r
+  if (VideoController == NULL) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  //\r
+  // Try to connect the PCI device path, so that GOP dirver could start on this \r
+  // device and create child handles with GraphicsOutput Protocol installed\r
+  // on them, then we get device paths of these child handles and select \r
+  // them as possible console device.\r
+  //\r
+  gBS->ConnectController (VideoController, NULL, NULL, FALSE);\r
+\r
+  Gop = EfiBootManagerGetGopDevicePath (VideoController);\r
+  if (Gop == NULL) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  EfiBootManagerUpdateConsoleVariable (ConOut, Gop, NULL);\r
+  FreePool (Gop);\r
+\r
+  //\r
+  // Necessary for ConPlatform and ConSplitter driver to start up again after ConOut is updated.\r
+  //\r
+  return gBS->ConnectController (VideoController, NULL, NULL, TRUE);\r
+}\r
+\r
+/**\r
+  Fill console handle in System Table if there are no valid console handle in.\r
+\r
+  Firstly, check the validation of console handle in System Table. If it is invalid,\r
+  update it by the first console device handle from EFI console variable. \r
+\r
+  @param  VarName            The name of the EFI console variable.\r
+  @param  ConsoleGuid        Specified Console protocol GUID.\r
+  @param  ConsoleHandle      On IN,  console handle in System Table to be checked. \r
+                             On OUT, new console handle in system table.\r
+  @param  ProtocolInterface  On IN,  console protocol on console handle in System Table to be checked. \r
+                             On OUT, new console protocol on new console handle in system table.\r
+\r
+  @retval TRUE               System Table has been updated.\r
+  @retval FALSE              System Table hasn't been updated.\r
+\r
+**/\r
+BOOLEAN \r
+BmUpdateSystemTableConsole (\r
+  IN     CHAR16                   *VarName,\r
+  IN     EFI_GUID                 *ConsoleGuid,\r
+  IN OUT EFI_HANDLE               *ConsoleHandle,\r
+  IN OUT VOID                     **ProtocolInterface\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  UINTN                           DevicePathSize;\r
+  EFI_DEVICE_PATH_PROTOCOL        *FullDevicePath;\r
+  EFI_DEVICE_PATH_PROTOCOL        *VarConsole;\r
+  EFI_DEVICE_PATH_PROTOCOL        *Instance;\r
+  VOID                            *Interface;\r
+  EFI_HANDLE                      NewHandle;\r
+  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut;\r
+\r
+  ASSERT (VarName != NULL);\r
+  ASSERT (ConsoleHandle != NULL);\r
+  ASSERT (ConsoleGuid != NULL);\r
+  ASSERT (ProtocolInterface != NULL);\r
+\r
+  if (*ConsoleHandle != NULL) {\r
+    Status = gBS->HandleProtocol (\r
+                   *ConsoleHandle,\r
+                   ConsoleGuid,\r
+                   &Interface\r
+                   );\r
+    if (Status == EFI_SUCCESS && Interface == *ProtocolInterface) {\r
+      //\r
+      // If ConsoleHandle is valid and console protocol on this handle also\r
+      // also matched, just return.\r
+      //\r
+      return FALSE;\r
+    }\r
+  }\r
+  \r
+  //\r
+  // Get all possible consoles device path from EFI variable\r
+  //\r
+  GetEfiGlobalVariable2 (VarName, (VOID **) &VarConsole, NULL);\r
+  if (VarConsole == NULL) {\r
+    //\r
+    // If there is no any console device, just return.\r
+    //\r
+    return FALSE;\r
+  }\r
+\r
+  FullDevicePath = VarConsole;\r
+\r
+  do {\r
+    //\r
+    // Check every instance of the console variable\r
+    //\r
+    Instance  = GetNextDevicePathInstance (&VarConsole, &DevicePathSize);\r
+    if (Instance == NULL) {\r
+      DEBUG ((EFI_D_ERROR, "[Bds] No valid console instance is found for %s!\n", VarName));\r
+      // We should not ASSERT when all the console devices are removed.\r
+      // ASSERT_EFI_ERROR (EFI_NOT_FOUND);\r
+      FreePool (FullDevicePath);\r
+      return FALSE;\r
+    }\r
+    \r
+    //\r
+    // Find console device handle by device path instance\r
+    //\r
+    Status = gBS->LocateDevicePath (\r
+                    ConsoleGuid,\r
+                    &Instance,\r
+                    &NewHandle\r
+                    );\r
+    if (!EFI_ERROR (Status)) {\r
+      //\r
+      // Get the console protocol on this console device handle\r
+      //\r
+      Status = gBS->HandleProtocol (\r
+                      NewHandle,\r
+                      ConsoleGuid,\r
+                      &Interface\r
+                      );\r
+      if (!EFI_ERROR (Status)) {\r
+        //\r
+        // Update new console handle in System Table.\r
+        //\r
+        *ConsoleHandle     = NewHandle;\r
+        *ProtocolInterface = Interface;\r
+        if (CompareGuid (ConsoleGuid, &gEfiSimpleTextOutProtocolGuid)) {\r
+          //\r
+          // If it is console out device, set console mode 80x25 if current mode is invalid.\r
+          //\r
+          TextOut = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *) Interface;\r
+          if (TextOut->Mode->Mode == -1) {\r
+            TextOut->SetMode (TextOut, 0);\r
+          }\r
+        }\r
+        return TRUE;\r
+      }\r
+    }\r
+\r
+  } while (Instance != NULL);\r
+\r
+  //\r
+  // No any available console devcie found.\r
+  //\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  This function updates the console variable based on ConVarName. It can\r
+  add or remove one specific console device path from the variable\r
+\r
+  @param  ConsoleType              ConIn, ConOut, ErrOut, ConInDev, ConOutDev or ErrOutDev.\r
+  @param  CustomizedConDevicePath  The console device path to be added to\r
+                                   the console variable. Cannot be multi-instance.\r
+  @param  ExclusiveDevicePath      The console device path to be removed\r
+                                   from the console variable. Cannot be multi-instance.\r
+\r
+  @retval EFI_UNSUPPORTED          The added device path is the same as a removed one.\r
+  @retval EFI_SUCCESS              Successfully added or removed the device path from the\r
+                                   console variable.\r
+  @retval others                   Return status of RT->SetVariable().\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiBootManagerUpdateConsoleVariable (\r
+  IN  CONSOLE_TYPE              ConsoleType,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL  *CustomizedConDevicePath,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL  *ExclusiveDevicePath\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  EFI_DEVICE_PATH_PROTOCOL  *VarConsole;\r
+  EFI_DEVICE_PATH_PROTOCOL  *NewDevicePath;\r
+  EFI_DEVICE_PATH_PROTOCOL  *TempNewDevicePath;\r
+\r
+  if (ConsoleType >= sizeof (mConVarName) / sizeof (mConVarName[0])) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Notes: check the device path point, here should check\r
+  // with compare memory\r
+  //\r
+  if (CustomizedConDevicePath == ExclusiveDevicePath) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+  //\r
+  // Delete the ExclusiveDevicePath from current default console\r
+  //\r
+  GetEfiGlobalVariable2 (mConVarName[ConsoleType], (VOID **) &VarConsole, NULL);\r
+  //\r
+  // Initialize NewDevicePath\r
+  //\r
+  NewDevicePath = VarConsole;\r
+\r
+  //\r
+  // If ExclusiveDevicePath is even the part of the instance in VarConsole, delete it.\r
+  // In the end, NewDevicePath is the final device path.\r
+  //\r
+  if (ExclusiveDevicePath != NULL && VarConsole != NULL) {\r
+      NewDevicePath = BmDelPartMatchInstance (VarConsole, ExclusiveDevicePath);\r
+  }\r
+  //\r
+  // Try to append customized device path to NewDevicePath.\r
+  //\r
+  if (CustomizedConDevicePath != NULL) {\r
+    if (!BmMatchDevicePaths (NewDevicePath, CustomizedConDevicePath)) {\r
+      //\r
+      // Check if there is part of CustomizedConDevicePath in NewDevicePath, delete it.\r
+      //\r
+      NewDevicePath = BmDelPartMatchInstance (NewDevicePath, CustomizedConDevicePath);\r
+      //\r
+      // In the first check, the default console variable will be _ModuleEntryPoint,\r
+      // just append current customized device path\r
+      //\r
+      TempNewDevicePath = NewDevicePath;\r
+      NewDevicePath = AppendDevicePathInstance (NewDevicePath, CustomizedConDevicePath);\r
+      if (TempNewDevicePath != NULL) {\r
+        FreePool(TempNewDevicePath);\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // Finally, Update the variable of the default console by NewDevicePath\r
+  //\r
+  Status = gRT->SetVariable (\r
+                  mConVarName[ConsoleType],\r
+                  &gEfiGlobalVariableGuid,\r
+                  EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS\r
+                                                  | ((ConsoleType < ConInDev) ? EFI_VARIABLE_NON_VOLATILE : 0),\r
+                  GetDevicePathSize (NewDevicePath),\r
+                  NewDevicePath\r
+                  );\r
+\r
+  if (VarConsole == NewDevicePath) {\r
+    if (VarConsole != NULL) {\r
+      FreePool(VarConsole);\r
+    }\r
+  } else {\r
+    if (VarConsole != NULL) {\r
+      FreePool(VarConsole);\r
+    }\r
+    if (NewDevicePath != NULL) {\r
+      FreePool(NewDevicePath);\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Connect the console device base on the variable ConsoleType.\r
+\r
+  @param  ConsoleType              ConIn, ConOut or ErrOut.\r
+\r
+  @retval EFI_NOT_FOUND            There is not any console devices connected\r
+                                   success\r
+  @retval EFI_SUCCESS              Success connect any one instance of the console\r
+                                   device path base on the variable ConVarName.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiBootManagerConnectConsoleVariable (\r
+  IN  CONSOLE_TYPE              ConsoleType\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  EFI_DEVICE_PATH_PROTOCOL  *StartDevicePath;\r
+  EFI_DEVICE_PATH_PROTOCOL  *Instance;\r
+  EFI_DEVICE_PATH_PROTOCOL  *Next;\r
+  EFI_DEVICE_PATH_PROTOCOL  *CopyOfDevicePath;\r
+  UINTN                     Size;\r
+  BOOLEAN                   DeviceExist;\r
+  EFI_HANDLE                Handle;\r
+\r
+  if ((ConsoleType != ConIn) && (ConsoleType != ConOut) && (ConsoleType != ErrOut)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status      = EFI_SUCCESS;\r
+  DeviceExist = FALSE;\r
+  Handle      = NULL;\r
+\r
+  //\r
+  // Check if the console variable exist\r
+  //\r
+  GetEfiGlobalVariable2 (mConVarName[ConsoleType], (VOID **) &StartDevicePath, NULL);\r
+  if (StartDevicePath == NULL) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  CopyOfDevicePath = StartDevicePath;\r
+  do {\r
+    //\r
+    // Check every instance of the console variable\r
+    //\r
+    Instance  = GetNextDevicePathInstance (&CopyOfDevicePath, &Size);\r
+    if (Instance == NULL) {\r
+      FreePool (StartDevicePath);\r
+      return EFI_UNSUPPORTED;\r
+    }\r
+    \r
+    Next      = Instance;\r
+    while (!IsDevicePathEndType (Next)) {\r
+      Next = NextDevicePathNode (Next);\r
+    }\r
+\r
+    SetDevicePathEndNode (Next);\r
+    //\r
+    // Connect the USB console\r
+    // USB console device path is a short-form device path that \r
+    //  starts with the first element being a USB WWID\r
+    //  or a USB Class device path\r
+    //\r
+    if ((DevicePathType (Instance) == MESSAGING_DEVICE_PATH) &&\r
+        ((DevicePathSubType (Instance) == MSG_USB_CLASS_DP) || (DevicePathSubType (Instance) == MSG_USB_WWID_DP))\r
+       ) {\r
+      Status = BmConnectUsbShortFormDevicePath (Instance);\r
+      if (!EFI_ERROR (Status)) {\r
+        DeviceExist = TRUE;\r
+      }\r
+    } else {\r
+      for (Next = Instance; !IsDevicePathEnd (Next); Next = NextDevicePathNode (Next)) {\r
+        if (DevicePathType (Next) == ACPI_DEVICE_PATH && DevicePathSubType (Next) == ACPI_ADR_DP) {\r
+          break;\r
+        } else if (DevicePathType (Next) == HARDWARE_DEVICE_PATH && \r
+                   DevicePathSubType (Next) == HW_CONTROLLER_DP &&\r
+                   DevicePathType (NextDevicePathNode (Next)) == ACPI_DEVICE_PATH &&\r
+                   DevicePathSubType (NextDevicePathNode (Next)) == ACPI_ADR_DP\r
+                   ) {\r
+          break;\r
+        }\r
+      }\r
+      if (!IsDevicePathEnd (Next)) {\r
+        //\r
+        // For GOP device path, start the video driver with NULL remaining device path\r
+        //\r
+        SetDevicePathEndNode (Next);\r
+        Status = EfiBootManagerConnectDevicePath (Instance, &Handle);\r
+        if (!EFI_ERROR (Status)) {\r
+          gBS->ConnectController (Handle, NULL, NULL, TRUE);\r
+        }\r
+      } else {\r
+        Status = EfiBootManagerConnectDevicePath (Instance, NULL);\r
+      }\r
+      if (EFI_ERROR (Status)) {\r
+        //\r
+        // Delete the instance from the console varialbe\r
+        //\r
+        EfiBootManagerUpdateConsoleVariable (ConsoleType, NULL, Instance);\r
+      } else {\r
+        DeviceExist = TRUE;\r
+      }\r
+    }\r
+    FreePool(Instance);\r
+  } while (CopyOfDevicePath != NULL);\r
+\r
+  FreePool (StartDevicePath);\r
+\r
+  if (!DeviceExist) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  This function will search every input/output device in current system,\r
+  and make every input/output device as potential console device.\r
+**/\r
+VOID\r
+EFIAPI\r
+EfiBootManagerConnectAllConsoles (\r
+  VOID\r
+  )\r
+{\r
+  UINTN                     Index;\r
+  EFI_DEVICE_PATH_PROTOCOL  *ConDevicePath;\r
+  UINTN                     HandleCount;\r
+  EFI_HANDLE                *HandleBuffer;\r
+\r
+  Index         = 0;\r
+  HandleCount   = 0;\r
+  HandleBuffer  = NULL;\r
+  ConDevicePath = NULL;\r
+\r
+  //\r
+  // Update all the console variables\r
+  //\r
+  gBS->LocateHandleBuffer (\r
+          ByProtocol,\r
+          &gEfiSimpleTextInProtocolGuid,\r
+          NULL,\r
+          &HandleCount,\r
+          &HandleBuffer\r
+          );\r
+\r
+  for (Index = 0; Index < HandleCount; Index++) {\r
+    gBS->HandleProtocol (\r
+            HandleBuffer[Index],\r
+            &gEfiDevicePathProtocolGuid,\r
+            (VOID **) &ConDevicePath\r
+            );\r
+    EfiBootManagerUpdateConsoleVariable (ConIn, ConDevicePath, NULL);\r
+  }\r
+\r
+  if (HandleBuffer != NULL) {\r
+    FreePool(HandleBuffer);\r
+    HandleBuffer = NULL;\r
+  }\r
+\r
+  gBS->LocateHandleBuffer (\r
+          ByProtocol,\r
+          &gEfiSimpleTextOutProtocolGuid,\r
+          NULL,\r
+          &HandleCount,\r
+          &HandleBuffer\r
+          );\r
+  for (Index = 0; Index < HandleCount; Index++) {\r
+    gBS->HandleProtocol (\r
+            HandleBuffer[Index],\r
+            &gEfiDevicePathProtocolGuid,\r
+            (VOID **) &ConDevicePath\r
+            );\r
+    EfiBootManagerUpdateConsoleVariable (ConOut, ConDevicePath, NULL);\r
+    EfiBootManagerUpdateConsoleVariable (ErrOut, ConDevicePath, NULL);\r
+  }\r
+\r
+  if (HandleBuffer != NULL) {\r
+    FreePool(HandleBuffer);\r
+  }\r
+\r
+  //\r
+  // Connect all console variables\r
+  //\r
+  EfiBootManagerConnectAllDefaultConsoles ();\r
+}\r
+\r
+\r
+/**\r
+  This function will connect all the console devices base on the console\r
+  device variable ConIn, ConOut and ErrOut.\r
+\r
+  @retval EFI_DEVICE_ERROR         All the consoles were not connected due to an error.\r
+  @retval EFI_SUCCESS              Success connect any one instance of the console\r
+                                   device path base on the variable ConVarName.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiBootManagerConnectAllDefaultConsoles (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  BOOLEAN                   OneConnected;\r
+  BOOLEAN                   SystemTableUpdated;\r
+\r
+  OneConnected = FALSE;\r
+\r
+  Status = EfiBootManagerConnectConsoleVariable (ConOut);\r
+  if (!EFI_ERROR (Status)) {\r
+    OneConnected = TRUE;\r
+  }\r
+  PERF_START (NULL, "ConOutReady", "BDS", 1);\r
+  PERF_END   (NULL, "ConOutReady", "BDS", 0);\r
+\r
+  \r
+  Status = EfiBootManagerConnectConsoleVariable (ConIn);\r
+  if (!EFI_ERROR (Status)) {\r
+    OneConnected = TRUE;\r
+  }\r
+  PERF_START (NULL, "ConInReady", "BDS", 1);\r
+  PERF_END   (NULL, "ConInReady", "BDS", 0);\r
+\r
+  Status = EfiBootManagerConnectConsoleVariable (ErrOut);\r
+  if (!EFI_ERROR (Status)) {\r
+    OneConnected = TRUE;\r
+  }\r
+  PERF_START (NULL, "ErrOutReady", "BDS", 1);\r
+  PERF_END   (NULL, "ErrOutReady", "BDS", 0);\r
+\r
+  SystemTableUpdated = FALSE;\r
+  //\r
+  // Fill console handles in System Table if no console device assignd.\r
+  //\r
+  if (BmUpdateSystemTableConsole (L"ConIn", &gEfiSimpleTextInProtocolGuid, &gST->ConsoleInHandle, (VOID **) &gST->ConIn)) {\r
+    SystemTableUpdated = TRUE;\r
+  }\r
+  if (BmUpdateSystemTableConsole (L"ConOut", &gEfiSimpleTextOutProtocolGuid, &gST->ConsoleOutHandle, (VOID **) &gST->ConOut)) {\r
+    SystemTableUpdated = TRUE;\r
+  }\r
+  if (BmUpdateSystemTableConsole (L"ErrOut", &gEfiSimpleTextOutProtocolGuid, &gST->StandardErrorHandle, (VOID **) &gST->StdErr)) {\r
+    SystemTableUpdated = TRUE;\r
+  }\r
+\r
+  if (SystemTableUpdated) {\r
+    //\r
+    // Update the CRC32 in the EFI System Table header\r
+    //\r
+    gST->Hdr.CRC32 = 0;\r
+    gBS->CalculateCrc32 (\r
+          (UINT8 *) &gST->Hdr,\r
+          gST->Hdr.HeaderSize,\r
+          &gST->Hdr.CRC32\r
+          );\r
+  }\r
+\r
+  return OneConnected ? EFI_SUCCESS : EFI_DEVICE_ERROR;\r
+}\r
index 2b5257394e21847b22028fd2801a130692e84cff..d197816fa1fa99ab6ed74c1c414cdbeedb4fb744 100644 (file)
-/** @file
-  Library functions which relates with driver health.
-
-Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
-This program and the accompanying materials
-are licensed and made available under the terms and conditions of the BSD License
-which accompanies this distribution.  The full text of the license may be found at
-http://opensource.org/licenses/bsd-license.php
-
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
-
-**/
-
-#include "InternalBm.h"
-
-GLOBAL_REMOVE_IF_UNREFERENCED
-  CHAR16 *mBmHealthStatusText[] = {
-    L"Healthy",
-    L"Repair Required",
-    L"Configuration Required",
-    L"Failed",
-    L"Reconnect Required",
-    L"Reboot Required"
-    };
-
-/**
-  Return the controller name.
-
-  @param DriverHealthHandle  The handle on which the Driver Health protocol instance is retrieved.
-  @param ControllerHandle    The handle of a controller that the driver specified by DriverBindingHandle is managing.
-                             This handle specifies the controller whose name is to be returned.
-  @param ChildHandle         The handle of the child controller to retrieve the name of. This is an
-                             optional parameter that may be NULL. It will be NULL for device drivers.
-                             It will also be NULL for bus drivers that attempt to retrieve the name
-                             of the bus controller. It will not be NULL for a bus driver that attempts
-                             to retrieve the name of a child controller.
-
-  @return A pointer to the Unicode string to return. This Unicode string is the name of the controller
-          specified by ControllerHandle and ChildHandle.
-**/
-CHAR16 *
-BmGetControllerName (
-  IN  EFI_HANDLE                   DriverHealthHandle,
-  IN  EFI_HANDLE                   ControllerHandle,
-  IN  EFI_HANDLE                   ChildHandle
-  )
-{
-  EFI_STATUS                       Status;
-  CHAR16                           *ControllerName;
-  CHAR8                            *LanguageVariable;
-  CHAR8                            *BestLanguage;
-  BOOLEAN                          Iso639Language;
-  EFI_COMPONENT_NAME_PROTOCOL      *ComponentName;
-
-  ControllerName = NULL;
-
-  //
-  // Locate Component Name (2) protocol on the driver binging handle.
-  //
-  Iso639Language = FALSE;
-  Status = gBS->HandleProtocol (
-                 DriverHealthHandle,
-                 &gEfiComponentName2ProtocolGuid,
-                 (VOID **) &ComponentName
-                 );
-  if (EFI_ERROR (Status)) {
-    Status = gBS->HandleProtocol (
-                    DriverHealthHandle,
-                    &gEfiComponentNameProtocolGuid,
-                    (VOID **) &ComponentName
-                    );
-    if (!EFI_ERROR (Status)) {
-      Iso639Language = TRUE;
-    }
-  }
-
-  if (!EFI_ERROR (Status)) {
-    LanguageVariable = GetEfiGlobalVariable (Iso639Language ? L"Lang" : L"PlatformLang");
-    BestLanguage     = GetBestLanguage(
-                         ComponentName->SupportedLanguages,
-                         Iso639Language,
-                         (LanguageVariable != NULL) ? LanguageVariable : "",
-                         Iso639Language ? "eng" : "en-US",
-                         NULL
-                         );
-    if (LanguageVariable != NULL) {
-      FreePool (LanguageVariable);
-    }
-
-    Status = ComponentName->GetControllerName (
-                              ComponentName,
-                              ControllerHandle, 
-                              ChildHandle,
-                              BestLanguage,
-                              &ControllerName
-                              );
-  }
-
-  if (!EFI_ERROR (Status)) {
-    return AllocateCopyPool (StrSize (ControllerName), ControllerName);
-  } else {
-    return ConvertDevicePathToText (
-             DevicePathFromHandle (ChildHandle != NULL ? ChildHandle : ControllerHandle),
-             FALSE,
-             FALSE
-             );
-  }
-}
-
-/**
-  Display a set of messages returned by the GetHealthStatus () service of the EFI Driver Health Protocol
-
-  @param DriverHealthInfo  Pointer to the Driver Health information entry.
-**/
-VOID
-BmDisplayMessages (
-  IN  EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO *DriverHealthInfo
-  )
-{
-  UINTN                            Index;
-  EFI_STRING                       String;
-  CHAR16                           *ControllerName;
-
-  if (DriverHealthInfo->MessageList == NULL ||
-      DriverHealthInfo->MessageList[0].HiiHandle == NULL) {
-    return;
-  }
-
-  ControllerName = BmGetControllerName (
-                     DriverHealthInfo->DriverHealthHandle,
-                     DriverHealthInfo->ControllerHandle, 
-                     DriverHealthInfo->ChildHandle
-                     );
-
-  DEBUG ((EFI_D_INFO, "Controller: %s\n", ControllerName));
-  Print (L"Controller: %s\n", ControllerName);
-  for (Index = 0; DriverHealthInfo->MessageList[Index].HiiHandle != NULL; Index++) {
-    String = HiiGetString (
-               DriverHealthInfo->MessageList[Index].HiiHandle,
-               DriverHealthInfo->MessageList[Index].StringId,
-               NULL
-               );
-    if (String != NULL) {
-      Print (L"  %s\n", String);
-      DEBUG ((EFI_D_INFO, "  %s\n", String));
-      FreePool (String);
-    }
-  }
-
-  if (ControllerName != NULL) {
-    FreePool (ControllerName);
-  }
-}
-
-/**
-  The repair notify function.
-  @param Value  A value between 0 and Limit that identifies the current progress
-                of the repair operation.
-  @param Limit  The maximum value of Value for the current repair operation.
-                If Limit is 0, then the completion progress is indeterminate.
-                For example, a driver that wants to specify progress in percent
-                would use a Limit value of 100.
-
-  @retval EFI_SUCCESS  Successfully return from the notify function.
-**/
-EFI_STATUS
-EFIAPI
-BmRepairNotify (
-  IN UINTN        Value,
-  IN UINTN        Limit
-  )
-{
-  DEBUG ((EFI_D_INFO, "[BDS]RepairNotify: %d/%d\n", Value, Limit));
-  Print (L"[BDS]RepairNotify: %d/%d\n", Value, Limit);
-
-  return EFI_SUCCESS;
-}
-
-/**
-  Collect the Driver Health status of a single controller.
-  
-  @param DriverHealthInfo        A pointer to the array containing all of the platform driver health information.
-  @param Count                   Return the updated array count.
-  @param DriverHealthHandle      The handle on which the Driver Health protocol instance is retrieved.
-  @param ControllerHandle        The handle of the controller..
-  @param ChildHandle             The handle of the child controller to retrieve the health
-                                 status on.  This is an optional parameter that may be NULL.
-
-  @retval Status                 The status returned from GetHealthStatus.
-  @retval EFI_ABORTED            The health status is healthy so no further query is needed.
-
-**/
-EFI_STATUS
-BmGetSingleControllerHealthStatus (
-  IN OUT EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO **DriverHealthInfo,
-  IN OUT UINTN                               *Count,
-  IN  EFI_HANDLE                             DriverHealthHandle,
-  IN  EFI_HANDLE                             ControllerHandle,  OPTIONAL
-  IN  EFI_HANDLE                             ChildHandle        OPTIONAL
-  )
-{
-  EFI_STATUS                     Status;
-  EFI_DRIVER_HEALTH_PROTOCOL     *DriverHealth;
-  EFI_DRIVER_HEALTH_HII_MESSAGE  *MessageList;
-  EFI_HII_HANDLE                 FormHiiHandle;
-  EFI_DRIVER_HEALTH_STATUS       HealthStatus;
-
-  ASSERT (DriverHealthHandle != NULL);
-  //
-  // Retrieve the Driver Health Protocol from DriverHandle
-  //
-  Status = gBS->HandleProtocol (
-                  DriverHealthHandle,
-                  &gEfiDriverHealthProtocolGuid,
-                  (VOID **) &DriverHealth
-                  );
-  ASSERT_EFI_ERROR (Status);
-  
-
-  if (ControllerHandle == NULL) {
-    //
-    // If ControllerHandle is NULL, the return the cumulative health status of the driver
-    //
-    Status = DriverHealth->GetHealthStatus (DriverHealth, NULL, NULL, &HealthStatus, NULL, NULL);
-    if (!EFI_ERROR (Status) && HealthStatus == EfiDriverHealthStatusHealthy) {
-      *DriverHealthInfo = ReallocatePool (
-                            (*Count)     * sizeof (EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO),
-                            (*Count + 1) * sizeof (EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO),
-                            *DriverHealthInfo
-                            );
-      ASSERT (*DriverHealthInfo != NULL);
-
-      (*DriverHealthInfo)[*Count].DriverHealthHandle = DriverHealthHandle;
-      (*DriverHealthInfo)[*Count].DriverHealth       = DriverHealth;
-      (*DriverHealthInfo)[*Count].HealthStatus       = HealthStatus;
-
-      *Count = *Count + 1;
-
-      Status = EFI_ABORTED;
-    }
-    return Status;
-  }
-
-  MessageList   = NULL;
-  FormHiiHandle = NULL;
-
-  //
-  // Collect the health status with the optional HII message list
-  //
-  Status = DriverHealth->GetHealthStatus (DriverHealth, ControllerHandle, ChildHandle, &HealthStatus, &MessageList, &FormHiiHandle);
-  if (!EFI_ERROR (Status)) {
-    *DriverHealthInfo = ReallocatePool (
-                          (*Count)     * sizeof (EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO),
-                          (*Count + 1) * sizeof (EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO),
-                          *DriverHealthInfo
-                          );
-    ASSERT (*DriverHealthInfo != NULL);
-    (*DriverHealthInfo)[*Count].DriverHealth       = DriverHealth;
-    (*DriverHealthInfo)[*Count].DriverHealthHandle = DriverHealthHandle;
-    (*DriverHealthInfo)[*Count].ControllerHandle   = ControllerHandle;
-    (*DriverHealthInfo)[*Count].ChildHandle        = ChildHandle;
-    (*DriverHealthInfo)[*Count].HiiHandle          = FormHiiHandle;
-    (*DriverHealthInfo)[*Count].MessageList        = MessageList;
-    (*DriverHealthInfo)[*Count].HealthStatus       = HealthStatus;
-
-    *Count = *Count + 1;
-  }
-
-  return Status;
-}
-
-/**
-  Return all the Driver Health information.
-
-  When the cumulative health status of all the controllers managed by the
-  driver who produces the EFI_DRIVER_HEALTH_PROTOCOL is healthy, only one
-  EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO entry is created for such
-  EFI_DRIVER_HEALTH_PROTOCOL instance.
-  Otherwise, every controller creates one EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO
-  entry. Additionally every child controller creates one
-  EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO entry if the driver is a bus driver.
-
-  @param Count      Return the count of the Driver Health information.
-
-  @retval NULL      No Driver Health information is returned.
-  @retval !NULL     Pointer to the Driver Health information array.
-**/
-EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO *
-EFIAPI
-EfiBootManagerGetDriverHealthInfo (
-  UINTN                      *Count
-  )
-{
-  EFI_STATUS                 Status;
-  UINTN                      NumHandles;
-  EFI_HANDLE                 *DriverHealthHandles;
-  EFI_DRIVER_HEALTH_STATUS   HealthStatus;
-  UINTN                      DriverHealthIndex;
-  EFI_HANDLE                 *Handles;
-  UINTN                      HandleCount;
-  UINTN                      ControllerIndex;
-  UINTN                      ChildIndex;
-  EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO  *DriverHealthInfo;
-
-  //
-  // Initialize local variables
-  //
-  *Count                  = 0;
-  DriverHealthInfo        = NULL;
-  Handles                 = NULL;
-  DriverHealthHandles     = NULL;
-  NumHandles              = 0;
-  HandleCount             = 0;
-
-  HealthStatus = EfiDriverHealthStatusHealthy;
-
-  Status = gBS->LocateHandleBuffer (
-                  ByProtocol,
-                  &gEfiDriverHealthProtocolGuid,
-                  NULL,
-                  &NumHandles,
-                  &DriverHealthHandles
-                  );
-
-  if (Status == EFI_NOT_FOUND || NumHandles == 0) {
-    //
-    // If there are no Driver Health Protocols handles, then return EFI_NOT_FOUND
-    //
-    return NULL;
-  }
-
-  ASSERT_EFI_ERROR (Status);
-  ASSERT (DriverHealthHandles != NULL);
-
-  //
-  // Check the health status of all controllers in the platform
-  // Start by looping through all the Driver Health Protocol handles in the handle database
-  //
-  for (DriverHealthIndex = 0; DriverHealthIndex < NumHandles; DriverHealthIndex++) {
-    //
-    // Get the cumulative health status of the driver
-    //
-    Status = BmGetSingleControllerHealthStatus (&DriverHealthInfo, Count, DriverHealthHandles[DriverHealthIndex], NULL, NULL);
-    if (EFI_ERROR (Status)) {
-      continue;
-    }
-
-    //
-    // See if the list of all handles in the handle database has been retrieved
-    //
-    //
-    if (Handles == NULL) {
-      //
-      // Retrieve the list of all handles from the handle database
-      //
-      Status = gBS->LocateHandleBuffer (
-        AllHandles,
-        NULL,
-        NULL,
-        &HandleCount,
-        &Handles
-        );
-      ASSERT_EFI_ERROR (Status);
-    }
-    //
-    // Loop through all the controller handles in the handle database
-    //
-    for (ControllerIndex = 0; ControllerIndex < HandleCount; ControllerIndex++) {
-      Status = BmGetSingleControllerHealthStatus (&DriverHealthInfo, Count, DriverHealthHandles[DriverHealthIndex], Handles[ControllerIndex], NULL);
-      if (EFI_ERROR (Status)) {
-        continue;
-      }
-
-      //
-      // Loop through all the child handles in the handle database
-      //
-      for (ChildIndex = 0; ChildIndex < HandleCount; ChildIndex++) {
-        Status = BmGetSingleControllerHealthStatus (&DriverHealthInfo, Count, DriverHealthHandles[DriverHealthIndex], Handles[ControllerIndex], Handles[ChildIndex]);
-        if (EFI_ERROR (Status)) {
-          continue;
-        }
-      }
-    }
-  }
-
-  Status = EFI_SUCCESS;
-
-  if (Handles != NULL) {
-    FreePool (Handles);
-  }
-  if (DriverHealthHandles != NULL) {
-    FreePool (DriverHealthHandles);
-  }
-
-  return DriverHealthInfo;
-}
-
-/**
-  Free the Driver Health information array.
-
-  @param DriverHealthInfo       Pointer to array of the Driver Health information.
-  @param Count                  Count of the array.
-
-  @retval EFI_SUCCESS           The array is freed.
-  @retval EFI_INVALID_PARAMETER The array is NULL.
-**/
-EFI_STATUS
-EFIAPI
-EfiBootManagerFreeDriverHealthInfo (
-  EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO *DriverHealthInfo,
-  UINTN                               Count
-  )
-{
-  UINTN                               Index;
-
-  for (Index = 0; Index < Count; Index++) {
-    if (DriverHealthInfo[Index].MessageList != NULL) {
-      FreePool (DriverHealthInfo[Index].MessageList);
-    }
-  }
-  return gBS->FreePool (DriverHealthInfo);
-}
-
-/**
-  Repair all the controllers according to the Driver Health status queried.
-**/
-VOID
-BmRepairAllControllers (
-  VOID
-  )
-{
-  EFI_STATUS                          Status;
-  EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO *DriverHealthInfo;
-  EFI_DRIVER_HEALTH_STATUS            HealthStatus;
-  UINTN                               Count;
-  UINTN                               Index;
-  BOOLEAN                             RepairRequired;
-  BOOLEAN                             ConfigurationRequired;
-  BOOLEAN                             ReconnectRequired;
-  BOOLEAN                             RebootRequired;
-  EFI_HII_HANDLE                      *HiiHandles;
-  EFI_FORM_BROWSER2_PROTOCOL          *FormBrowser2;
-
-  //
-  // Configure PcdDriverHealthConfigureForm to ZeroGuid to disable driver health check.
-  //
-  if (CompareGuid (PcdGetPtr (PcdDriverHealthConfigureForm), &gZeroGuid)) {
-    return;
-  }
-
-  Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &FormBrowser2);
-  ASSERT_EFI_ERROR (Status);
-
-  do {
-    RepairRequired        = FALSE;
-    ConfigurationRequired = FALSE;
-
-    //
-    // Deal with Repair Required
-    //
-    DriverHealthInfo = EfiBootManagerGetDriverHealthInfo (&Count);
-    for (Index = 0; Index < Count; Index++) {
-      if (DriverHealthInfo[Index].HealthStatus == EfiDriverHealthStatusConfigurationRequired) {
-        ConfigurationRequired = TRUE;
-      }
-      
-      if (DriverHealthInfo[Index].HealthStatus == EfiDriverHealthStatusRepairRequired) {
-        RepairRequired        = TRUE;
-
-        BmDisplayMessages (&DriverHealthInfo[Index]);
-
-        Status = DriverHealthInfo[Index].DriverHealth->Repair (
-                                                         DriverHealthInfo[Index].DriverHealth,
-                                                         DriverHealthInfo[Index].ControllerHandle,
-                                                         DriverHealthInfo[Index].ChildHandle,
-                                                         BmRepairNotify
-                                                         );
-        if (!EFI_ERROR (Status) && !ConfigurationRequired) {
-          Status = DriverHealthInfo[Index].DriverHealth->GetHealthStatus (
-                                                           DriverHealthInfo[Index].DriverHealth,
-                                                           DriverHealthInfo[Index].ControllerHandle,
-                                                           DriverHealthInfo[Index].ChildHandle,
-                                                           &HealthStatus,
-                                                           NULL,
-                                                           NULL
-                                                           );
-          if (!EFI_ERROR (Status) && (HealthStatus == EfiDriverHealthStatusConfigurationRequired)) {
-            ConfigurationRequired = TRUE;
-          }
-        }
-      }
-    }
-
-    if (ConfigurationRequired) {
-      HiiHandles = HiiGetHiiHandles (NULL);
-      if (HiiHandles != NULL) {
-        for (Index = 0; HiiHandles[Index] != NULL; Index++) {
-          Status = FormBrowser2->SendForm (
-                                   FormBrowser2,
-                                   &HiiHandles[Index],
-                                   1,
-                                   PcdGetPtr (PcdDriverHealthConfigureForm),
-                                   0,
-                                   NULL,
-                                   NULL
-                                   );
-          if (!EFI_ERROR (Status)) {
-            break;
-          }
-        }
-        FreePool (HiiHandles);
-      }
-    }
-  
-    EfiBootManagerFreeDriverHealthInfo (DriverHealthInfo, Count);
-  } while (RepairRequired || ConfigurationRequired);
-
-  RebootRequired    = FALSE;
-  ReconnectRequired = FALSE;
-  DriverHealthInfo  = EfiBootManagerGetDriverHealthInfo (&Count);
-  for (Index = 0; Index < Count; Index++) {
-
-    BmDisplayMessages (&DriverHealthInfo[Index]);
-
-    if (DriverHealthInfo[Index].HealthStatus == EfiDriverHealthStatusReconnectRequired) {
-      Status = gBS->DisconnectController (DriverHealthInfo[Index].ControllerHandle, NULL, NULL);
-      if (EFI_ERROR (Status)) {
-        //
-        // Disconnect failed. Need to promote reconnect to a reboot.
-        //
-        RebootRequired    = TRUE;
-      } else {
-        gBS->ConnectController (DriverHealthInfo[Index].ControllerHandle, NULL, NULL, TRUE);
-        ReconnectRequired = TRUE;
-      }
-    }
-
-    if (DriverHealthInfo[Index].HealthStatus == EfiDriverHealthStatusRebootRequired) {
-      RebootRequired      = TRUE;
-    }
-  }
-  EfiBootManagerFreeDriverHealthInfo (DriverHealthInfo, Count);
-
-
-  if (ReconnectRequired) {
-    BmRepairAllControllers ();
-  }
-
-  DEBUG_CODE (
-    CHAR16 *ControllerName;
-
-    DriverHealthInfo = EfiBootManagerGetDriverHealthInfo (&Count);
-    for (Index = 0; Index < Count; Index++) {
-      ControllerName = BmGetControllerName (
-                         DriverHealthInfo[Index].DriverHealthHandle,
-                         DriverHealthInfo[Index].ControllerHandle,
-                         DriverHealthInfo[Index].ChildHandle
-                         );
-      DEBUG ((
-        EFI_D_INFO,
-        "%02d: %s - %s\n",
-        Index,
-        ControllerName,
-        mBmHealthStatusText[DriverHealthInfo[Index].HealthStatus]
-        ));
-      if (ControllerName != NULL) {
-        FreePool (ControllerName);
-      }
-    }
-    EfiBootManagerFreeDriverHealthInfo (DriverHealthInfo, Count);
-    );
-
-  if (RebootRequired) {
-    DEBUG ((EFI_D_INFO, "[BDS] One of the Driver Health instances requires rebooting.\n"));
-    gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);
-  }
-}
+/** @file\r
+  Library functions which relates with driver health.\r
+\r
+Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "InternalBm.h"\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED\r
+  CHAR16 *mBmHealthStatusText[] = {\r
+    L"Healthy",\r
+    L"Repair Required",\r
+    L"Configuration Required",\r
+    L"Failed",\r
+    L"Reconnect Required",\r
+    L"Reboot Required"\r
+    };\r
+\r
+/**\r
+  Return the controller name.\r
+\r
+  @param DriverHealthHandle  The handle on which the Driver Health protocol instance is retrieved.\r
+  @param ControllerHandle    The handle of a controller that the driver specified by DriverBindingHandle is managing.\r
+                             This handle specifies the controller whose name is to be returned.\r
+  @param ChildHandle         The handle of the child controller to retrieve the name of. This is an\r
+                             optional parameter that may be NULL. It will be NULL for device drivers.\r
+                             It will also be NULL for bus drivers that attempt to retrieve the name\r
+                             of the bus controller. It will not be NULL for a bus driver that attempts\r
+                             to retrieve the name of a child controller.\r
+\r
+  @return A pointer to the Unicode string to return. This Unicode string is the name of the controller\r
+          specified by ControllerHandle and ChildHandle.\r
+**/\r
+CHAR16 *\r
+BmGetControllerName (\r
+  IN  EFI_HANDLE                   DriverHealthHandle,\r
+  IN  EFI_HANDLE                   ControllerHandle,\r
+  IN  EFI_HANDLE                   ChildHandle\r
+  )\r
+{\r
+  EFI_STATUS                       Status;\r
+  CHAR16                           *ControllerName;\r
+  CHAR8                            *LanguageVariable;\r
+  CHAR8                            *BestLanguage;\r
+  BOOLEAN                          Iso639Language;\r
+  EFI_COMPONENT_NAME_PROTOCOL      *ComponentName;\r
+\r
+  ControllerName = NULL;\r
+\r
+  //\r
+  // Locate Component Name (2) protocol on the driver binging handle.\r
+  //\r
+  Iso639Language = FALSE;\r
+  Status = gBS->HandleProtocol (\r
+                 DriverHealthHandle,\r
+                 &gEfiComponentName2ProtocolGuid,\r
+                 (VOID **) &ComponentName\r
+                 );\r
+  if (EFI_ERROR (Status)) {\r
+    Status = gBS->HandleProtocol (\r
+                    DriverHealthHandle,\r
+                    &gEfiComponentNameProtocolGuid,\r
+                    (VOID **) &ComponentName\r
+                    );\r
+    if (!EFI_ERROR (Status)) {\r
+      Iso639Language = TRUE;\r
+    }\r
+  }\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    LanguageVariable = GetEfiGlobalVariable (Iso639Language ? L"Lang" : L"PlatformLang");\r
+    BestLanguage     = GetBestLanguage(\r
+                         ComponentName->SupportedLanguages,\r
+                         Iso639Language,\r
+                         (LanguageVariable != NULL) ? LanguageVariable : "",\r
+                         Iso639Language ? "eng" : "en-US",\r
+                         NULL\r
+                         );\r
+    if (LanguageVariable != NULL) {\r
+      FreePool (LanguageVariable);\r
+    }\r
+\r
+    Status = ComponentName->GetControllerName (\r
+                              ComponentName,\r
+                              ControllerHandle, \r
+                              ChildHandle,\r
+                              BestLanguage,\r
+                              &ControllerName\r
+                              );\r
+  }\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    return AllocateCopyPool (StrSize (ControllerName), ControllerName);\r
+  } else {\r
+    return ConvertDevicePathToText (\r
+             DevicePathFromHandle (ChildHandle != NULL ? ChildHandle : ControllerHandle),\r
+             FALSE,\r
+             FALSE\r
+             );\r
+  }\r
+}\r
+\r
+/**\r
+  Display a set of messages returned by the GetHealthStatus () service of the EFI Driver Health Protocol\r
+\r
+  @param DriverHealthInfo  Pointer to the Driver Health information entry.\r
+**/\r
+VOID\r
+BmDisplayMessages (\r
+  IN  EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO *DriverHealthInfo\r
+  )\r
+{\r
+  UINTN                            Index;\r
+  EFI_STRING                       String;\r
+  CHAR16                           *ControllerName;\r
+\r
+  if (DriverHealthInfo->MessageList == NULL ||\r
+      DriverHealthInfo->MessageList[0].HiiHandle == NULL) {\r
+    return;\r
+  }\r
+\r
+  ControllerName = BmGetControllerName (\r
+                     DriverHealthInfo->DriverHealthHandle,\r
+                     DriverHealthInfo->ControllerHandle, \r
+                     DriverHealthInfo->ChildHandle\r
+                     );\r
+\r
+  DEBUG ((EFI_D_INFO, "Controller: %s\n", ControllerName));\r
+  Print (L"Controller: %s\n", ControllerName);\r
+  for (Index = 0; DriverHealthInfo->MessageList[Index].HiiHandle != NULL; Index++) {\r
+    String = HiiGetString (\r
+               DriverHealthInfo->MessageList[Index].HiiHandle,\r
+               DriverHealthInfo->MessageList[Index].StringId,\r
+               NULL\r
+               );\r
+    if (String != NULL) {\r
+      Print (L"  %s\n", String);\r
+      DEBUG ((EFI_D_INFO, "  %s\n", String));\r
+      FreePool (String);\r
+    }\r
+  }\r
+\r
+  if (ControllerName != NULL) {\r
+    FreePool (ControllerName);\r
+  }\r
+}\r
+\r
+/**\r
+  The repair notify function.\r
+  @param Value  A value between 0 and Limit that identifies the current progress\r
+                of the repair operation.\r
+  @param Limit  The maximum value of Value for the current repair operation.\r
+                If Limit is 0, then the completion progress is indeterminate.\r
+                For example, a driver that wants to specify progress in percent\r
+                would use a Limit value of 100.\r
+\r
+  @retval EFI_SUCCESS  Successfully return from the notify function.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BmRepairNotify (\r
+  IN UINTN        Value,\r
+  IN UINTN        Limit\r
+  )\r
+{\r
+  DEBUG ((EFI_D_INFO, "[BDS]RepairNotify: %d/%d\n", Value, Limit));\r
+  Print (L"[BDS]RepairNotify: %d/%d\n", Value, Limit);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Collect the Driver Health status of a single controller.\r
+  \r
+  @param DriverHealthInfo        A pointer to the array containing all of the platform driver health information.\r
+  @param Count                   Return the updated array count.\r
+  @param DriverHealthHandle      The handle on which the Driver Health protocol instance is retrieved.\r
+  @param ControllerHandle        The handle of the controller..\r
+  @param ChildHandle             The handle of the child controller to retrieve the health\r
+                                 status on.  This is an optional parameter that may be NULL.\r
+\r
+  @retval Status                 The status returned from GetHealthStatus.\r
+  @retval EFI_ABORTED            The health status is healthy so no further query is needed.\r
+\r
+**/\r
+EFI_STATUS\r
+BmGetSingleControllerHealthStatus (\r
+  IN OUT EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO **DriverHealthInfo,\r
+  IN OUT UINTN                               *Count,\r
+  IN  EFI_HANDLE                             DriverHealthHandle,\r
+  IN  EFI_HANDLE                             ControllerHandle,  OPTIONAL\r
+  IN  EFI_HANDLE                             ChildHandle        OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS                     Status;\r
+  EFI_DRIVER_HEALTH_PROTOCOL     *DriverHealth;\r
+  EFI_DRIVER_HEALTH_HII_MESSAGE  *MessageList;\r
+  EFI_HII_HANDLE                 FormHiiHandle;\r
+  EFI_DRIVER_HEALTH_STATUS       HealthStatus;\r
+\r
+  ASSERT (DriverHealthHandle != NULL);\r
+  //\r
+  // Retrieve the Driver Health Protocol from DriverHandle\r
+  //\r
+  Status = gBS->HandleProtocol (\r
+                  DriverHealthHandle,\r
+                  &gEfiDriverHealthProtocolGuid,\r
+                  (VOID **) &DriverHealth\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+  \r
+\r
+  if (ControllerHandle == NULL) {\r
+    //\r
+    // If ControllerHandle is NULL, the return the cumulative health status of the driver\r
+    //\r
+    Status = DriverHealth->GetHealthStatus (DriverHealth, NULL, NULL, &HealthStatus, NULL, NULL);\r
+    if (!EFI_ERROR (Status) && HealthStatus == EfiDriverHealthStatusHealthy) {\r
+      *DriverHealthInfo = ReallocatePool (\r
+                            (*Count)     * sizeof (EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO),\r
+                            (*Count + 1) * sizeof (EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO),\r
+                            *DriverHealthInfo\r
+                            );\r
+      ASSERT (*DriverHealthInfo != NULL);\r
+\r
+      (*DriverHealthInfo)[*Count].DriverHealthHandle = DriverHealthHandle;\r
+      (*DriverHealthInfo)[*Count].DriverHealth       = DriverHealth;\r
+      (*DriverHealthInfo)[*Count].HealthStatus       = HealthStatus;\r
+\r
+      *Count = *Count + 1;\r
+\r
+      Status = EFI_ABORTED;\r
+    }\r
+    return Status;\r
+  }\r
+\r
+  MessageList   = NULL;\r
+  FormHiiHandle = NULL;\r
+\r
+  //\r
+  // Collect the health status with the optional HII message list\r
+  //\r
+  Status = DriverHealth->GetHealthStatus (DriverHealth, ControllerHandle, ChildHandle, &HealthStatus, &MessageList, &FormHiiHandle);\r
+  if (!EFI_ERROR (Status)) {\r
+    *DriverHealthInfo = ReallocatePool (\r
+                          (*Count)     * sizeof (EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO),\r
+                          (*Count + 1) * sizeof (EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO),\r
+                          *DriverHealthInfo\r
+                          );\r
+    ASSERT (*DriverHealthInfo != NULL);\r
+    (*DriverHealthInfo)[*Count].DriverHealth       = DriverHealth;\r
+    (*DriverHealthInfo)[*Count].DriverHealthHandle = DriverHealthHandle;\r
+    (*DriverHealthInfo)[*Count].ControllerHandle   = ControllerHandle;\r
+    (*DriverHealthInfo)[*Count].ChildHandle        = ChildHandle;\r
+    (*DriverHealthInfo)[*Count].HiiHandle          = FormHiiHandle;\r
+    (*DriverHealthInfo)[*Count].MessageList        = MessageList;\r
+    (*DriverHealthInfo)[*Count].HealthStatus       = HealthStatus;\r
+\r
+    *Count = *Count + 1;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Return all the Driver Health information.\r
+\r
+  When the cumulative health status of all the controllers managed by the\r
+  driver who produces the EFI_DRIVER_HEALTH_PROTOCOL is healthy, only one\r
+  EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO entry is created for such\r
+  EFI_DRIVER_HEALTH_PROTOCOL instance.\r
+  Otherwise, every controller creates one EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO\r
+  entry. Additionally every child controller creates one\r
+  EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO entry if the driver is a bus driver.\r
+\r
+  @param Count      Return the count of the Driver Health information.\r
+\r
+  @retval NULL      No Driver Health information is returned.\r
+  @retval !NULL     Pointer to the Driver Health information array.\r
+**/\r
+EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO *\r
+EFIAPI\r
+EfiBootManagerGetDriverHealthInfo (\r
+  UINTN                      *Count\r
+  )\r
+{\r
+  EFI_STATUS                 Status;\r
+  UINTN                      NumHandles;\r
+  EFI_HANDLE                 *DriverHealthHandles;\r
+  EFI_DRIVER_HEALTH_STATUS   HealthStatus;\r
+  UINTN                      DriverHealthIndex;\r
+  EFI_HANDLE                 *Handles;\r
+  UINTN                      HandleCount;\r
+  UINTN                      ControllerIndex;\r
+  UINTN                      ChildIndex;\r
+  EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO  *DriverHealthInfo;\r
+\r
+  //\r
+  // Initialize local variables\r
+  //\r
+  *Count                  = 0;\r
+  DriverHealthInfo        = NULL;\r
+  Handles                 = NULL;\r
+  DriverHealthHandles     = NULL;\r
+  NumHandles              = 0;\r
+  HandleCount             = 0;\r
+\r
+  HealthStatus = EfiDriverHealthStatusHealthy;\r
+\r
+  Status = gBS->LocateHandleBuffer (\r
+                  ByProtocol,\r
+                  &gEfiDriverHealthProtocolGuid,\r
+                  NULL,\r
+                  &NumHandles,\r
+                  &DriverHealthHandles\r
+                  );\r
+\r
+  if (Status == EFI_NOT_FOUND || NumHandles == 0) {\r
+    //\r
+    // If there are no Driver Health Protocols handles, then return EFI_NOT_FOUND\r
+    //\r
+    return NULL;\r
+  }\r
+\r
+  ASSERT_EFI_ERROR (Status);\r
+  ASSERT (DriverHealthHandles != NULL);\r
+\r
+  //\r
+  // Check the health status of all controllers in the platform\r
+  // Start by looping through all the Driver Health Protocol handles in the handle database\r
+  //\r
+  for (DriverHealthIndex = 0; DriverHealthIndex < NumHandles; DriverHealthIndex++) {\r
+    //\r
+    // Get the cumulative health status of the driver\r
+    //\r
+    Status = BmGetSingleControllerHealthStatus (&DriverHealthInfo, Count, DriverHealthHandles[DriverHealthIndex], NULL, NULL);\r
+    if (EFI_ERROR (Status)) {\r
+      continue;\r
+    }\r
+\r
+    //\r
+    // See if the list of all handles in the handle database has been retrieved\r
+    //\r
+    //\r
+    if (Handles == NULL) {\r
+      //\r
+      // Retrieve the list of all handles from the handle database\r
+      //\r
+      Status = gBS->LocateHandleBuffer (\r
+        AllHandles,\r
+        NULL,\r
+        NULL,\r
+        &HandleCount,\r
+        &Handles\r
+        );\r
+      ASSERT_EFI_ERROR (Status);\r
+    }\r
+    //\r
+    // Loop through all the controller handles in the handle database\r
+    //\r
+    for (ControllerIndex = 0; ControllerIndex < HandleCount; ControllerIndex++) {\r
+      Status = BmGetSingleControllerHealthStatus (&DriverHealthInfo, Count, DriverHealthHandles[DriverHealthIndex], Handles[ControllerIndex], NULL);\r
+      if (EFI_ERROR (Status)) {\r
+        continue;\r
+      }\r
+\r
+      //\r
+      // Loop through all the child handles in the handle database\r
+      //\r
+      for (ChildIndex = 0; ChildIndex < HandleCount; ChildIndex++) {\r
+        Status = BmGetSingleControllerHealthStatus (&DriverHealthInfo, Count, DriverHealthHandles[DriverHealthIndex], Handles[ControllerIndex], Handles[ChildIndex]);\r
+        if (EFI_ERROR (Status)) {\r
+          continue;\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  if (Handles != NULL) {\r
+    FreePool (Handles);\r
+  }\r
+  if (DriverHealthHandles != NULL) {\r
+    FreePool (DriverHealthHandles);\r
+  }\r
+\r
+  return DriverHealthInfo;\r
+}\r
+\r
+/**\r
+  Free the Driver Health information array.\r
+\r
+  @param DriverHealthInfo       Pointer to array of the Driver Health information.\r
+  @param Count                  Count of the array.\r
+\r
+  @retval EFI_SUCCESS           The array is freed.\r
+  @retval EFI_INVALID_PARAMETER The array is NULL.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiBootManagerFreeDriverHealthInfo (\r
+  EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO *DriverHealthInfo,\r
+  UINTN                               Count\r
+  )\r
+{\r
+  UINTN                               Index;\r
+\r
+  for (Index = 0; Index < Count; Index++) {\r
+    if (DriverHealthInfo[Index].MessageList != NULL) {\r
+      FreePool (DriverHealthInfo[Index].MessageList);\r
+    }\r
+  }\r
+  return gBS->FreePool (DriverHealthInfo);\r
+}\r
+\r
+/**\r
+  Repair all the controllers according to the Driver Health status queried.\r
+**/\r
+VOID\r
+BmRepairAllControllers (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS                          Status;\r
+  EFI_BOOT_MANAGER_DRIVER_HEALTH_INFO *DriverHealthInfo;\r
+  EFI_DRIVER_HEALTH_STATUS            HealthStatus;\r
+  UINTN                               Count;\r
+  UINTN                               Index;\r
+  BOOLEAN                             RepairRequired;\r
+  BOOLEAN                             ConfigurationRequired;\r
+  BOOLEAN                             ReconnectRequired;\r
+  BOOLEAN                             RebootRequired;\r
+  EFI_HII_HANDLE                      *HiiHandles;\r
+  EFI_FORM_BROWSER2_PROTOCOL          *FormBrowser2;\r
+\r
+  //\r
+  // Configure PcdDriverHealthConfigureForm to ZeroGuid to disable driver health check.\r
+  //\r
+  if (CompareGuid (PcdGetPtr (PcdDriverHealthConfigureForm), &gZeroGuid)) {\r
+    return;\r
+  }\r
+\r
+  Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &FormBrowser2);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  do {\r
+    RepairRequired        = FALSE;\r
+    ConfigurationRequired = FALSE;\r
+\r
+    //\r
+    // Deal with Repair Required\r
+    //\r
+    DriverHealthInfo = EfiBootManagerGetDriverHealthInfo (&Count);\r
+    for (Index = 0; Index < Count; Index++) {\r
+      if (DriverHealthInfo[Index].HealthStatus == EfiDriverHealthStatusConfigurationRequired) {\r
+        ConfigurationRequired = TRUE;\r
+      }\r
+      \r
+      if (DriverHealthInfo[Index].HealthStatus == EfiDriverHealthStatusRepairRequired) {\r
+        RepairRequired        = TRUE;\r
+\r
+        BmDisplayMessages (&DriverHealthInfo[Index]);\r
+\r
+        Status = DriverHealthInfo[Index].DriverHealth->Repair (\r
+                                                         DriverHealthInfo[Index].DriverHealth,\r
+                                                         DriverHealthInfo[Index].ControllerHandle,\r
+                                                         DriverHealthInfo[Index].ChildHandle,\r
+                                                         BmRepairNotify\r
+                                                         );\r
+        if (!EFI_ERROR (Status) && !ConfigurationRequired) {\r
+          Status = DriverHealthInfo[Index].DriverHealth->GetHealthStatus (\r
+                                                           DriverHealthInfo[Index].DriverHealth,\r
+                                                           DriverHealthInfo[Index].ControllerHandle,\r
+                                                           DriverHealthInfo[Index].ChildHandle,\r
+                                                           &HealthStatus,\r
+                                                           NULL,\r
+                                                           NULL\r
+                                                           );\r
+          if (!EFI_ERROR (Status) && (HealthStatus == EfiDriverHealthStatusConfigurationRequired)) {\r
+            ConfigurationRequired = TRUE;\r
+          }\r
+        }\r
+      }\r
+    }\r
+\r
+    if (ConfigurationRequired) {\r
+      HiiHandles = HiiGetHiiHandles (NULL);\r
+      if (HiiHandles != NULL) {\r
+        for (Index = 0; HiiHandles[Index] != NULL; Index++) {\r
+          Status = FormBrowser2->SendForm (\r
+                                   FormBrowser2,\r
+                                   &HiiHandles[Index],\r
+                                   1,\r
+                                   PcdGetPtr (PcdDriverHealthConfigureForm),\r
+                                   0,\r
+                                   NULL,\r
+                                   NULL\r
+                                   );\r
+          if (!EFI_ERROR (Status)) {\r
+            break;\r
+          }\r
+        }\r
+        FreePool (HiiHandles);\r
+      }\r
+    }\r
+  \r
+    EfiBootManagerFreeDriverHealthInfo (DriverHealthInfo, Count);\r
+  } while (RepairRequired || ConfigurationRequired);\r
+\r
+  RebootRequired    = FALSE;\r
+  ReconnectRequired = FALSE;\r
+  DriverHealthInfo  = EfiBootManagerGetDriverHealthInfo (&Count);\r
+  for (Index = 0; Index < Count; Index++) {\r
+\r
+    BmDisplayMessages (&DriverHealthInfo[Index]);\r
+\r
+    if (DriverHealthInfo[Index].HealthStatus == EfiDriverHealthStatusReconnectRequired) {\r
+      Status = gBS->DisconnectController (DriverHealthInfo[Index].ControllerHandle, NULL, NULL);\r
+      if (EFI_ERROR (Status)) {\r
+        //\r
+        // Disconnect failed. Need to promote reconnect to a reboot.\r
+        //\r
+        RebootRequired    = TRUE;\r
+      } else {\r
+        gBS->ConnectController (DriverHealthInfo[Index].ControllerHandle, NULL, NULL, TRUE);\r
+        ReconnectRequired = TRUE;\r
+      }\r
+    }\r
+\r
+    if (DriverHealthInfo[Index].HealthStatus == EfiDriverHealthStatusRebootRequired) {\r
+      RebootRequired      = TRUE;\r
+    }\r
+  }\r
+  EfiBootManagerFreeDriverHealthInfo (DriverHealthInfo, Count);\r
+\r
+\r
+  if (ReconnectRequired) {\r
+    BmRepairAllControllers ();\r
+  }\r
+\r
+  DEBUG_CODE (\r
+    CHAR16 *ControllerName;\r
+\r
+    DriverHealthInfo = EfiBootManagerGetDriverHealthInfo (&Count);\r
+    for (Index = 0; Index < Count; Index++) {\r
+      ControllerName = BmGetControllerName (\r
+                         DriverHealthInfo[Index].DriverHealthHandle,\r
+                         DriverHealthInfo[Index].ControllerHandle,\r
+                         DriverHealthInfo[Index].ChildHandle\r
+                         );\r
+      DEBUG ((\r
+        EFI_D_INFO,\r
+        "%02d: %s - %s\n",\r
+        Index,\r
+        ControllerName,\r
+        mBmHealthStatusText[DriverHealthInfo[Index].HealthStatus]\r
+        ));\r
+      if (ControllerName != NULL) {\r
+        FreePool (ControllerName);\r
+      }\r
+    }\r
+    EfiBootManagerFreeDriverHealthInfo (DriverHealthInfo, Count);\r
+    );\r
+\r
+  if (RebootRequired) {\r
+    DEBUG ((EFI_D_INFO, "[BDS] One of the Driver Health instances requires rebooting.\n"));\r
+    gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);\r
+  }\r
+}\r
index 6a770f940c4b3666dc4fef9374a610301a26072a..8d398fb4c68afa895f38f1ec47c39399c6e2121b 100644 (file)
-/** @file
-  Hotkey library functions.
-
-Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
-This program and the accompanying materials
-are licensed and made available under the terms and conditions of the BSD License
-which accompanies this distribution.  The full text of the license may be found at
-http://opensource.org/licenses/bsd-license.php
-
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
-
-**/
-
-#include "InternalBm.h"
-
-//
-// Lock for linked list
-//
-EFI_LOCK                     mBmHotkeyLock            = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);
-LIST_ENTRY                   mBmHotkeyList            = INITIALIZE_LIST_HEAD_VARIABLE (mBmHotkeyList);
-EFI_EVENT                    mBmHotkeyTriggered       = NULL;
-BOOLEAN                      mBmHotkeyServiceStarted  = FALSE;
-UINTN                        mBmHotkeySupportCount    = 0;
-
-//
-// Set OptionNumber as unassigned value to indicate the option isn't initialized
-//
-EFI_BOOT_MANAGER_LOAD_OPTION mBmHotkeyBootOption      = { LoadOptionNumberUnassigned };
-
-EFI_BOOT_MANAGER_KEY_OPTION  *mBmContinueKeyOption    = NULL;
-VOID                         *mBmTxtInExRegistration  = NULL;
-
-/**
-
-  Check whether the input key option is valid.
-
-  @param   KeyOption               Input key option info.
-
-  @retval  TRUE               Input key option is valid.
-  @retval  FALSE              Input key option is not valid.
-**/
-BOOLEAN
-BmIsKeyOptionValid (
-  IN EFI_BOOT_MANAGER_KEY_OPTION     *KeyOption
-)
-{
-  UINT16   OptionName[sizeof (L"Boot####")];
-  UINT8    *BootOption;
-  UINTN    BootOptionSize;
-  UINT32   Crc;
-
-  //
-  // Check whether corresponding Boot Option exist
-  //
-  UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", KeyOption->BootOption);
-  GetEfiGlobalVariable2 (OptionName, (VOID **) &BootOption, &BootOptionSize);
-
-  if (BootOption == NULL) {
-    return FALSE;
-  }
-
-  //
-  // Check CRC for Boot Option
-  //
-  gBS->CalculateCrc32 (BootOption, BootOptionSize, &Crc);
-  FreePool (BootOption);
-
-  return (BOOLEAN) (KeyOption->BootOptionCrc == Crc);
-}
-
-/**
-
-  Check whether the input variable is an key option variable.
-
-  @param   Name               Input variable name.
-  @param   Guid               Input variable guid.
-  @param   OptionNumber       The option number of this key option variable.
-
-  @retval  TRUE               Input variable is a key option variable.
-  @retval  FALSE              Input variable is not a key option variable.
-**/
-BOOLEAN
-BmIsKeyOptionVariable (
-  CHAR16        *Name,
-  EFI_GUID      *Guid,
-  UINT16        *OptionNumber
-  )
-{
-  UINTN         Index;
-  
-  if (!CompareGuid (Guid, &gEfiGlobalVariableGuid) ||
-      (StrSize (Name) != sizeof (L"Key####")) ||
-      (StrnCmp (Name, L"Key", 3) != 0)
-     ) {
-    return FALSE;
-  }
-
-  *OptionNumber = 0;
-  for (Index = 3; Index < 7; Index++) {
-    if ((Name[Index] >= L'0') && (Name[Index] <= L'9')) {
-      *OptionNumber = *OptionNumber * 16 + Name[Index] - L'0';
-    } else if ((Name[Index] >= L'A') && (Name[Index] <= L'F')) {
-      *OptionNumber = *OptionNumber * 16 + Name[Index] - L'A' + 10;
-    } else {
-      return FALSE;
-    }
-  }
-
-  return TRUE;
-}
-
-/**
-  Return the buffer size of the EFI_BOOT_MANAGER_KEY_OPTION data.
-
-  @param   KeyOption            The input key option info.
-
-  @retval  The buffer size of the key option data.
-**/
-UINTN
-BmSizeOfKeyOption (
-  EFI_BOOT_MANAGER_KEY_OPTION  *KeyOption
-  )
-{
-  return OFFSET_OF (EFI_BOOT_MANAGER_KEY_OPTION, Keys)
-    + KeyOption->KeyData.Options.InputKeyCount * sizeof (EFI_INPUT_KEY);
-}
-
-/**
-  Return the array of key options.
-
-  @param Count  Return the number of key options.
-
-  @retval NULL  No key option.
-  @retval Other Pointer to the key options.
-**/
-EFI_BOOT_MANAGER_KEY_OPTION *
-BmGetKeyOptions (
-  OUT UINTN     *Count
-  )
-{
-  EFI_STATUS                  Status;
-  UINTN                       Index;
-  CHAR16                      *Name;
-  EFI_GUID                    Guid;
-  UINTN                       NameSize;
-  UINTN                       NewNameSize;
-  EFI_BOOT_MANAGER_KEY_OPTION *KeyOptions;
-  EFI_BOOT_MANAGER_KEY_OPTION *KeyOption;
-  UINT16                      OptionNumber;
-
-  if (Count == NULL) {
-    return NULL;
-  }
-
-  *Count     = 0;
-  KeyOptions = NULL;
-
-  NameSize = sizeof (CHAR16);
-  Name     = AllocateZeroPool (NameSize);
-  ASSERT (Name != NULL);
-  while (TRUE) {
-    NewNameSize = NameSize;
-    Status = gRT->GetNextVariableName (&NewNameSize, Name, &Guid);
-    if (Status == EFI_BUFFER_TOO_SMALL) {
-      Name = ReallocatePool (NameSize, NewNameSize, Name);
-      ASSERT (Name != NULL);
-      Status = gRT->GetNextVariableName (&NewNameSize, Name, &Guid);
-      NameSize = NewNameSize;
-    }
-
-    if (Status == EFI_NOT_FOUND) {
-      break;
-    }
-    ASSERT_EFI_ERROR (Status);
-
-    if (BmIsKeyOptionVariable (Name ,&Guid, &OptionNumber)) {
-      GetEfiGlobalVariable2 (Name, (VOID**) &KeyOption, NULL);
-      ASSERT (KeyOption != NULL);
-      if (BmIsKeyOptionValid (KeyOption)) {
-        KeyOptions = ReallocatePool (
-                       *Count * sizeof (EFI_BOOT_MANAGER_KEY_OPTION),
-                       (*Count + 1) * sizeof (EFI_BOOT_MANAGER_KEY_OPTION),
-                       KeyOptions
-                       );
-        ASSERT (KeyOptions != NULL);
-        //
-        // Insert the key option in order
-        //
-        for (Index = 0; Index < *Count; Index++) {
-          if (OptionNumber < KeyOptions[Index].OptionNumber) {
-            break;
-          }
-        }
-        CopyMem (&KeyOptions[Index + 1], &KeyOptions[Index], (*Count - Index) * sizeof (EFI_BOOT_MANAGER_KEY_OPTION));
-        CopyMem (&KeyOptions[Index], KeyOption, BmSizeOfKeyOption (KeyOption));
-        KeyOptions[Index].OptionNumber = OptionNumber;
-        (*Count)++;
-      }
-      FreePool (KeyOption);
-    }
-  }
-
-  FreePool (Name);
-
-  return KeyOptions;
-}
-
-/**
-  Callback function for event.
-  
-  @param    Event          Event for this callback function.
-  @param    Context        Context pass to this function.
-**/
-VOID
-EFIAPI
-BmEmptyFunction (
-  IN EFI_EVENT                Event,
-  IN VOID                     *Context
-  )
-{
-}
-
-/**
-  Check whether the bit is set in the value.
-
-  @param   Value            The value need to be check.
-  @param   Bit              The bit filed need to be check.
-
-  @retval  TRUE             The bit is set.
-  @retval  FALSE            The bit is not set.
-**/
-BOOLEAN
-BmBitSet (
-  IN UINT32   Value,
-  IN UINT32   Bit
-  )
-{
-  return (BOOLEAN) ((Value & Bit) != 0);
-}
-
-/**
-  Initialize the KeyData and Key[] in the EFI_BOOT_MANAGER_KEY_OPTION.
-
-  @param  Modifier   Input key info.
-  @param  Args       Va_list info.
-  @param  KeyOption  Key info which need to update.
-
-  @retval  EFI_SUCCESS             Succeed to initialize the KeyData and Key[].
-  @return  EFI_INVALID_PARAMETER   Input parameter error.
-**/
-EFI_STATUS
-BmInitializeKeyFields (
-  IN UINT32                       Modifier,
-  IN VA_LIST                      Args,
-  OUT EFI_BOOT_MANAGER_KEY_OPTION *KeyOption
-  )
-{
-  EFI_INPUT_KEY                   *Key;
-
-  if (KeyOption == NULL) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  Key = NULL;
-  while (KeyOption->KeyData.Options.InputKeyCount < sizeof (KeyOption->Keys) / sizeof (KeyOption->Keys[0])) {
-    Key = VA_ARG (Args, EFI_INPUT_KEY *);
-    if (Key == NULL) {
-      break;
-    }
-    CopyMem (
-      &KeyOption->Keys[KeyOption->KeyData.Options.InputKeyCount],
-      Key,
-      sizeof (EFI_INPUT_KEY)
-      );
-    KeyOption->KeyData.Options.InputKeyCount++;
-  }
-
-  if (Key != NULL) {
-    //
-    // Too many keys
-    //
-    return EFI_INVALID_PARAMETER;
-  }
-
-  if ((Modifier & ~(EFI_BOOT_MANAGER_SHIFT_PRESSED
-                 | EFI_BOOT_MANAGER_CONTROL_PRESSED
-                 | EFI_BOOT_MANAGER_ALT_PRESSED
-                 | EFI_BOOT_MANAGER_LOGO_PRESSED
-                 | EFI_BOOT_MANAGER_MENU_KEY_PRESSED
-                 | EFI_BOOT_MANAGER_SYS_REQ_PRESSED
-                 )) != 0) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  if (BmBitSet (Modifier, EFI_BOOT_MANAGER_SHIFT_PRESSED)) {
-    KeyOption->KeyData.Options.ShiftPressed = 1;
-  }
-  if (BmBitSet (Modifier, EFI_BOOT_MANAGER_CONTROL_PRESSED)) {
-    KeyOption->KeyData.Options.ControlPressed = 1;
-  }
-  if (BmBitSet (Modifier, EFI_BOOT_MANAGER_ALT_PRESSED)) {
-    KeyOption->KeyData.Options.AltPressed = 1;
-  }
-  if (BmBitSet (Modifier, EFI_BOOT_MANAGER_LOGO_PRESSED)) {
-    KeyOption->KeyData.Options.LogoPressed = 1;
-  }
-  if (BmBitSet (Modifier, EFI_BOOT_MANAGER_MENU_KEY_PRESSED)) {
-    KeyOption->KeyData.Options.MenuPressed = 1;
-  }
-  if (BmBitSet (Modifier, EFI_BOOT_MANAGER_SYS_REQ_PRESSED)) {
-    KeyOption->KeyData.Options.SysReqPressed = 1;
-  }
-
-  return EFI_SUCCESS;
-}
-
-/**
-  Try to boot the boot option triggered by hot key.
-**/
-VOID
-EFIAPI
-EfiBootManagerHotkeyBoot (
-  VOID
-  )
-{
-  if (mBmHotkeyBootOption.OptionNumber != LoadOptionNumberUnassigned) {
-    EfiBootManagerBoot (&mBmHotkeyBootOption);
-    EfiBootManagerFreeLoadOption (&mBmHotkeyBootOption);
-    mBmHotkeyBootOption.OptionNumber = LoadOptionNumberUnassigned;
-  }
-}
-
-/**
-  This is the common notification function for HotKeys, it will be registered
-  with SimpleTextInEx protocol interface - RegisterKeyNotify() of ConIn handle.
-
-  @param KeyData         A pointer to a buffer that is filled in with the keystroke
-                         information for the key that was pressed.
-
-  @retval  EFI_SUCCESS   KeyData is successfully processed.
-  @return  EFI_NOT_FOUND Fail to find boot option variable.
-**/
-EFI_STATUS
-EFIAPI
-BmHotkeyCallback (
-  IN EFI_KEY_DATA     *KeyData
-)
-{
-  LIST_ENTRY                    *Link;
-  BM_HOTKEY                     *Hotkey;
-  CHAR16                        OptionName[sizeof ("Boot####")];
-  EFI_STATUS                    Status;
-  EFI_KEY_DATA                  *HotkeyData;
-
-  if (mBmHotkeyBootOption.OptionNumber != LoadOptionNumberUnassigned) {
-    //
-    // Do not process sequential hotkey stroke until the current boot option returns
-    //
-    return EFI_SUCCESS;
-  }
-
-  DEBUG ((EFI_D_INFO, "[Bds]BmHotkeyCallback: %04x:%04x\n", KeyData->Key.ScanCode, KeyData->Key.UnicodeChar));
-
-  EfiAcquireLock (&mBmHotkeyLock);
-  for ( Link = GetFirstNode (&mBmHotkeyList)
-      ; !IsNull (&mBmHotkeyList, Link)
-      ; Link = GetNextNode (&mBmHotkeyList, Link)
-      ) {
-    Hotkey = BM_HOTKEY_FROM_LINK (Link);
-
-    //
-    // Is this Key Stroke we are waiting for?
-    //
-    ASSERT (Hotkey->WaitingKey < (sizeof (Hotkey->KeyData) / sizeof (Hotkey->KeyData[0])));
-    HotkeyData = &Hotkey->KeyData[Hotkey->WaitingKey];
-    if ((KeyData->Key.ScanCode == HotkeyData->Key.ScanCode) &&
-        (KeyData->Key.UnicodeChar == HotkeyData->Key.UnicodeChar) &&
-        (((KeyData->KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) != 0) ? 
-          (KeyData->KeyState.KeyShiftState == HotkeyData->KeyState.KeyShiftState) : TRUE
-        )
-       ) {
-
-      //
-      // Receive an expecting key stroke, transit to next waiting state
-      //
-      Hotkey->WaitingKey++;
-
-      if (Hotkey->WaitingKey == Hotkey->CodeCount) {
-        //
-        // Reset to initial waiting state
-        //
-        Hotkey->WaitingKey = 0;
-        //
-        // Received the whole key stroke sequence
-        //
-        Status = gBS->SignalEvent (mBmHotkeyTriggered);
-        ASSERT_EFI_ERROR (Status);
-
-        if (!Hotkey->IsContinue) {
-          //
-          // Launch its BootOption
-          //
-          UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", Hotkey->BootOption);
-          Status = EfiBootManagerVariableToLoadOption (OptionName, &mBmHotkeyBootOption);
-          DEBUG ((EFI_D_INFO, "[Bds]Hotkey for %s pressed - %r\n", OptionName, Status));
-          if (EFI_ERROR (Status)) {
-            mBmHotkeyBootOption.OptionNumber = LoadOptionNumberUnassigned;
-          }
-        } else {
-          DEBUG ((EFI_D_INFO, "[Bds]Continue key pressed!\n"));
-        }
-      }
-    } else {
-      //
-      // Receive an unexpected key stroke, reset to initial waiting state
-      //
-      Hotkey->WaitingKey = 0;
-    }
-
-  }
-  EfiReleaseLock (&mBmHotkeyLock);
-
-  return EFI_SUCCESS;
-}
-
-/**
-  Unregister hotkey notify list.
-
-  @param    Hotkey                Hotkey list.
-
-  @retval   EFI_SUCCESS           Unregister hotkey notify success.
-  @retval   Others                Unregister hotkey notify failed.
-**/
-EFI_STATUS
-BmUnregisterHotkeyNotify (
-  IN BM_HOTKEY                          *Hotkey
-  )
-{
-  EFI_STATUS                            Status;
-  UINTN                                 Index;
-  UINTN                                 KeyIndex;
-  EFI_HANDLE                            *Handles;
-  UINTN                                 HandleCount;
-  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL     *TxtInEx;
-  VOID                                  *NotifyHandle;
-
-  gBS->LocateHandleBuffer (
-          ByProtocol,
-          &gEfiSimpleTextInputExProtocolGuid,
-          NULL,
-          &HandleCount,
-          &Handles
-          );
-  for (Index = 0; Index < HandleCount; Index++) {
-    Status = gBS->HandleProtocol (Handles[Index], &gEfiSimpleTextInputExProtocolGuid, (VOID **) &TxtInEx);
-    ASSERT_EFI_ERROR (Status);
-    for (KeyIndex = 0; KeyIndex < Hotkey->CodeCount; KeyIndex++) {
-      Status = TxtInEx->RegisterKeyNotify (
-                          TxtInEx,
-                          &Hotkey->KeyData[KeyIndex],
-                          BmHotkeyCallback,
-                          &NotifyHandle
-                          );
-      if (!EFI_ERROR (Status)) {
-        Status = TxtInEx->UnregisterKeyNotify (TxtInEx, NotifyHandle);
-        DEBUG ((EFI_D_INFO, "[Bds]UnregisterKeyNotify: %04x/%04x %r\n", Hotkey->KeyData[KeyIndex].Key.ScanCode, Hotkey->KeyData[KeyIndex].Key.UnicodeChar, Status));
-      }
-    }
-  }
-
-  return EFI_SUCCESS;
-}
-
-/**
-  Register hotkey notify list.
-
-  @param    TxtInEx               Pointer to EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL protocol.
-  @param    Hotkey                Hotkey list.
-
-  @retval   EFI_SUCCESS           Register hotkey notify success.
-  @retval   Others                Register hotkey notify failed.
-**/
-EFI_STATUS
-BmRegisterHotkeyNotify (
-  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *TxtInEx,
-  IN BM_HOTKEY                          *Hotkey
-  )
-{
-  EFI_STATUS                            Status;
-  UINTN                                 Index;
-  VOID                                  *NotifyHandle;
-
-  for (Index = 0; Index < Hotkey->CodeCount; Index++) {
-    Status = TxtInEx->RegisterKeyNotify (
-                        TxtInEx,
-                        &Hotkey->KeyData[Index],
-                        BmHotkeyCallback,
-                        &NotifyHandle
-                        );
-    DEBUG ((
-      EFI_D_INFO,
-      "[Bds]RegisterKeyNotify: %04x/%04x %08x/%02x %r\n",
-      Hotkey->KeyData[Index].Key.ScanCode,
-      Hotkey->KeyData[Index].Key.UnicodeChar,
-      Hotkey->KeyData[Index].KeyState.KeyShiftState,
-      Hotkey->KeyData[Index].KeyState.KeyToggleState,
-      Status
-      ));
-    if (EFI_ERROR (Status)) {
-      //
-      // some of the hotkey registry failed
-      // do not unregister all in case we have both CTRL-ALT-P and CTRL-ALT-P-R
-      //
-      break;
-    }
-  }
-
-  return EFI_SUCCESS;
-}
-
-/**
-  Generate key shift state base on the input key option info.
-
-  @param    Depth                 Which key is checked.
-  @param    KeyOption             Input key option info.
-  @param    KeyShiftState         Input key shift state.
-  @param    KeyShiftStates        Return possible key shift state array.
-  @param    KeyShiftStateCount    Possible key shift state count.
-**/
-VOID
-BmGenerateKeyShiftState (
-  IN UINTN                             Depth,
-  IN EFI_BOOT_MANAGER_KEY_OPTION       *KeyOption,
-  IN UINT32                            KeyShiftState,
-  IN UINT32                            *KeyShiftStates,
-  IN UINTN                             *KeyShiftStateCount
-  )
-{
-  switch (Depth) {
-  case 0:
-    if (KeyOption->KeyData.Options.ShiftPressed) {
-      BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_RIGHT_SHIFT_PRESSED, KeyShiftStates, KeyShiftStateCount);
-      BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_LEFT_SHIFT_PRESSED,  KeyShiftStates, KeyShiftStateCount);
-    } else {
-      BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState, KeyShiftStates, KeyShiftStateCount);
-    }
-    break;
-
-  case 1:
-    if (KeyOption->KeyData.Options.ControlPressed) {
-      BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_RIGHT_CONTROL_PRESSED, KeyShiftStates, KeyShiftStateCount);
-      BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_LEFT_CONTROL_PRESSED,  KeyShiftStates, KeyShiftStateCount);
-    } else {
-      BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState, KeyShiftStates, KeyShiftStateCount);
-    }
-    break;
-
-  case 2:
-    if (KeyOption->KeyData.Options.AltPressed) {
-      BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_RIGHT_ALT_PRESSED, KeyShiftStates, KeyShiftStateCount);
-      BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_LEFT_ALT_PRESSED,  KeyShiftStates, KeyShiftStateCount);
-    } else {
-      BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState, KeyShiftStates, KeyShiftStateCount);
-    }
-    break;
-  case  3:
-    if (KeyOption->KeyData.Options.LogoPressed) {
-      BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_RIGHT_LOGO_PRESSED, KeyShiftStates, KeyShiftStateCount);
-      BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_LEFT_LOGO_PRESSED,  KeyShiftStates, KeyShiftStateCount);
-    } else {
-      BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState, KeyShiftStates, KeyShiftStateCount);
-    }
-    break;
-  case 4:
-    if (KeyOption->KeyData.Options.MenuPressed) {
-      KeyShiftState |= EFI_MENU_KEY_PRESSED;
-    }
-    if (KeyOption->KeyData.Options.SysReqPressed) {
-      KeyShiftState |= EFI_SYS_REQ_PRESSED;
-    }
-    KeyShiftStates[*KeyShiftStateCount] = KeyShiftState;
-    (*KeyShiftStateCount)++;
-    break;
-  }
-}
-
-/**
-  Add it to hot key database, register it to existing TxtInEx.
-  New TxtInEx will be automatically registered with all the hot key in dababase
-
-  @param    KeyOption  Input key option info.
-**/
-EFI_STATUS
-BmProcessKeyOption (
-  IN EFI_BOOT_MANAGER_KEY_OPTION       *KeyOption
-  )
-{
-  EFI_STATUS                           Status;
-  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL    *TxtInEx;
-  EFI_HANDLE                           *Handles;
-  UINTN                                HandleCount;
-  UINTN                                HandleIndex;
-  UINTN                                Index;
-  BM_HOTKEY                            *Hotkey;
-  UINTN                                KeyIndex;
-  //
-  // 16 is enough to enumerate all the possible combination of LEFT_XXX and RIGHT_XXX
-  //
-  UINT32                               KeyShiftStates[16];
-  UINTN                                KeyShiftStateCount;
-
-  if (KeyOption->KeyData.Options.InputKeyCount > mBmHotkeySupportCount) {
-    return EFI_UNSUPPORTED;
-  }
-
-  KeyShiftStateCount = 0;
-  BmGenerateKeyShiftState (0, KeyOption, EFI_SHIFT_STATE_VALID, KeyShiftStates, &KeyShiftStateCount);
-  ASSERT (KeyShiftStateCount <= sizeof (KeyShiftStates) / sizeof (KeyShiftStates[0]));
-
-  EfiAcquireLock (&mBmHotkeyLock);
-
-  for (Index = 0; Index < KeyShiftStateCount; Index++) {
-    Hotkey = AllocateZeroPool (sizeof (BM_HOTKEY));
-    ASSERT (Hotkey != NULL);
-
-    Hotkey->Signature  = BM_HOTKEY_SIGNATURE;
-    Hotkey->BootOption = KeyOption->BootOption;
-    Hotkey->IsContinue = (BOOLEAN) (KeyOption == mBmContinueKeyOption);
-    Hotkey->CodeCount  = (UINT8) KeyOption->KeyData.Options.InputKeyCount;
-
-    for (KeyIndex = 0; KeyIndex < Hotkey->CodeCount; KeyIndex++) {
-      CopyMem (&Hotkey->KeyData[KeyIndex].Key, &KeyOption->Keys[KeyIndex], sizeof (EFI_INPUT_KEY));
-      Hotkey->KeyData[KeyIndex].KeyState.KeyShiftState = KeyShiftStates[Index];
-    }
-    InsertTailList (&mBmHotkeyList, &Hotkey->Link);
-
-    gBS->LocateHandleBuffer (
-            ByProtocol,
-            &gEfiSimpleTextInputExProtocolGuid,
-            NULL,
-            &HandleCount,
-            &Handles
-            );
-    for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {
-      Status = gBS->HandleProtocol (Handles[HandleIndex], &gEfiSimpleTextInputExProtocolGuid, (VOID **) &TxtInEx);
-      ASSERT_EFI_ERROR (Status);
-      BmRegisterHotkeyNotify (TxtInEx, Hotkey);
-    }
-  }
-
-  EfiReleaseLock (&mBmHotkeyLock);
-
-  return EFI_SUCCESS;
-}
-
-/**
-  Callback function for SimpleTextInEx protocol install events
-
-  @param Event           the event that is signaled.
-  @param Context         not used here.
-
-**/
-VOID
-EFIAPI
-BmTxtInExCallback (
-  IN EFI_EVENT    Event,
-  IN VOID         *Context
-  )
-{
-  EFI_STATUS                         Status;
-  UINTN                              BufferSize;
-  EFI_HANDLE                         Handle;
-  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *TxtInEx;
-  LIST_ENTRY                         *Link;
-
-  while (TRUE) {
-    BufferSize = sizeof (EFI_HANDLE);
-    Status = gBS->LocateHandle (
-                    ByRegisterNotify,
-                    NULL,
-                    mBmTxtInExRegistration,
-                    &BufferSize,
-                    &Handle
-                    );
-    if (EFI_ERROR (Status)) {
-      //
-      // If no more notification events exist
-      //
-      return ;
-    }
-
-    Status = gBS->HandleProtocol (
-                    Handle,
-                    &gEfiSimpleTextInputExProtocolGuid,
-                    (VOID **) &TxtInEx
-                    );
-    ASSERT_EFI_ERROR (Status);
-
-    //
-    // Register the hot key notification for the existing items in the list
-    //
-    EfiAcquireLock (&mBmHotkeyLock);
-    for (Link = GetFirstNode (&mBmHotkeyList); !IsNull (&mBmHotkeyList, Link); Link = GetNextNode (&mBmHotkeyList, Link)) {
-      BmRegisterHotkeyNotify (TxtInEx, BM_HOTKEY_FROM_LINK (Link));
-    }
-    EfiReleaseLock (&mBmHotkeyLock);
-  }
-}
-
-/**
-  Free the key options returned from BmGetKeyOptions.
-
-  @param KeyOptions     Pointer to the key options.
-  @param KeyOptionCount Number of the key options.
-
-  @retval EFI_SUCCESS   The key options are freed.
-  @retval EFI_NOT_FOUND KeyOptions is NULL.
-**/
-EFI_STATUS
-BmFreeKeyOptions (
-  IN EFI_BOOT_MANAGER_KEY_OPTION    *KeyOptions,
-  IN UINTN                          KeyOptionCount
-  )
-{
-  if (KeyOptions != NULL) {
-    FreePool (KeyOptions);
-    return EFI_SUCCESS;
-  } else {
-    return EFI_NOT_FOUND;
-  }
-}
-
-/**
-  Register the key option to exit the waiting of the Boot Manager timeout.
-  Platform should ensure that the continue key option isn't conflict with
-  other boot key options.
-
-  @param Modifier     Key shift state.
-  @param  ...         Parameter list of pointer of EFI_INPUT_KEY.
-
-  @retval EFI_SUCCESS         Successfully register the continue key option.
-  @retval EFI_ALREADY_STARTED The continue key option is already registered.
-**/
-EFI_STATUS
-EFIAPI
-EfiBootManagerRegisterContinueKeyOption (
-  IN UINT32           Modifier,
-  ...
-  )
-{
-  EFI_STATUS                   Status;
-  EFI_BOOT_MANAGER_KEY_OPTION  KeyOption;
-  VA_LIST                      Args;
-  
-  if (mBmContinueKeyOption != NULL) {
-    return EFI_ALREADY_STARTED;
-  }
-
-  ZeroMem (&KeyOption, sizeof (EFI_BOOT_MANAGER_KEY_OPTION));
-  VA_START (Args, Modifier);
-  Status = BmInitializeKeyFields (Modifier, Args, &KeyOption);
-  VA_END (Args);
-
-  if (!EFI_ERROR (Status)) {
-    mBmContinueKeyOption = AllocateCopyPool (sizeof (EFI_BOOT_MANAGER_KEY_OPTION), &KeyOption);
-    ASSERT (mBmContinueKeyOption != NULL);
-    if (mBmHotkeyServiceStarted) {
-      BmProcessKeyOption (mBmContinueKeyOption);
-    }
-  }
-
-  return Status;
-}
-
-/**
-  Stop the hotkey processing.
-  
-  @param    Event          Event pointer related to hotkey service.
-  @param    Context        Context pass to this function.
-**/
-VOID
-EFIAPI
-BmStopHotkeyService (
-  IN EFI_EVENT    Event,
-  IN VOID         *Context
-  )
-{
-  LIST_ENTRY            *Link;
-  BM_HOTKEY             *Hotkey;
-
-  DEBUG ((EFI_D_INFO, "[Bds]Stop Hotkey Service!\n"));
-  gBS->CloseEvent (Event);
-
-  EfiAcquireLock (&mBmHotkeyLock);
-  for (Link = GetFirstNode (&mBmHotkeyList); !IsNull (&mBmHotkeyList, Link); ) {
-    Hotkey = BM_HOTKEY_FROM_LINK (Link);
-    BmUnregisterHotkeyNotify (Hotkey);
-    Link   = RemoveEntryList (Link);
-    FreePool (Hotkey);
-  }
-  EfiReleaseLock (&mBmHotkeyLock);
-}
-
-/**
-  Start the hot key service so that the key press can trigger the boot option.
-
-  @param HotkeyTriggered  Return the waitable event and it will be signaled 
-                          when a valid hot key is pressed.
-
-  @retval EFI_SUCCESS     The hot key service is started.
-**/
-EFI_STATUS
-EFIAPI
-EfiBootManagerStartHotkeyService (
-  IN EFI_EVENT                 *HotkeyTriggered
-  )
-{
-  EFI_STATUS                   Status;
-  EFI_BOOT_MANAGER_KEY_OPTION  *KeyOptions;
-  UINTN                        KeyOptionCount;
-  UINTN                        Index;
-  EFI_EVENT                    Event;
-  UINT32                       *BootOptionSupport;
-
-  Status = GetEfiGlobalVariable2 (EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME, (VOID **) &BootOptionSupport, NULL);
-  ASSERT (BootOptionSupport != NULL);
-
-  if ((*BootOptionSupport & EFI_BOOT_OPTION_SUPPORT_KEY)  != 0) {
-    mBmHotkeySupportCount = ((*BootOptionSupport & EFI_BOOT_OPTION_SUPPORT_COUNT) >> LowBitSet32 (EFI_BOOT_OPTION_SUPPORT_COUNT));
-  }
-  FreePool (BootOptionSupport);
-
-  if (mBmHotkeySupportCount == 0) {
-    DEBUG ((EFI_D_INFO, "Bds: BootOptionSupport NV variable forbids starting the hotkey service.\n"));
-    return EFI_UNSUPPORTED;
-  }
-
-  Status = gBS->CreateEvent (
-                  EVT_NOTIFY_WAIT,
-                  TPL_CALLBACK,
-                  BmEmptyFunction,
-                  NULL,
-                  &mBmHotkeyTriggered
-                  );
-  ASSERT_EFI_ERROR (Status);
-
-  if (HotkeyTriggered != NULL) {
-    *HotkeyTriggered = mBmHotkeyTriggered;
-  }
-
-  KeyOptions = BmGetKeyOptions (&KeyOptionCount);
-  for (Index = 0; Index < KeyOptionCount; Index ++) {
-    BmProcessKeyOption (&KeyOptions[Index]);
-  }
-  BmFreeKeyOptions (KeyOptions, KeyOptionCount);
-
-  if (mBmContinueKeyOption != NULL) {
-    BmProcessKeyOption (mBmContinueKeyOption);
-  }
-
-  EfiCreateProtocolNotifyEvent (
-    &gEfiSimpleTextInputExProtocolGuid,
-    TPL_CALLBACK,
-    BmTxtInExCallback,
-    NULL,
-    &mBmTxtInExRegistration
-    );
-
-  Status = EfiCreateEventReadyToBootEx (
-             TPL_CALLBACK,
-             BmStopHotkeyService,
-             NULL,
-             &Event
-             );
-  ASSERT_EFI_ERROR (Status);
-
-
-  mBmHotkeyServiceStarted = TRUE;
-  return Status;
-}
-
-/**
-  Add the key option.
-  It adds the key option variable and the key option takes affect immediately.
-
-  @param AddedOption      Return the added key option.
-  @param BootOptionNumber The boot option number for the key option.
-  @param Modifier         Key shift state.
-  @param ...              Parameter list of pointer of EFI_INPUT_KEY.
-
-  @retval EFI_SUCCESS         The key option is added.
-  @retval EFI_ALREADY_STARTED The hot key is already used by certain key option.
-**/
-EFI_STATUS
-EFIAPI
-EfiBootManagerAddKeyOptionVariable (
-  OUT EFI_BOOT_MANAGER_KEY_OPTION *AddedOption,   OPTIONAL
-  IN UINT16                       BootOptionNumber,
-  IN UINT32                       Modifier,
-  ...
-  )
-{
-  EFI_STATUS                     Status;
-  VA_LIST                        Args;
-  VOID                           *BootOption;
-  UINTN                          BootOptionSize;
-  CHAR16                         BootOptionName[sizeof (L"Boot####")];
-  EFI_BOOT_MANAGER_KEY_OPTION    KeyOption;
-  EFI_BOOT_MANAGER_KEY_OPTION    *KeyOptions;
-  UINTN                          KeyOptionCount;
-  UINTN                          Index;
-  UINTN                          KeyOptionNumber;
-  CHAR16                         KeyOptionName[sizeof (L"Key####")];
-
-  UnicodeSPrint (BootOptionName, sizeof (BootOptionName), L"Boot%04x", BootOptionNumber);
-  GetEfiGlobalVariable2 (BootOptionName, &BootOption, &BootOptionSize);
-
-  if (BootOption == NULL) {
-    return EFI_NOT_FOUND;
-  }
-
-  ZeroMem (&KeyOption, sizeof (EFI_BOOT_MANAGER_KEY_OPTION));
-  KeyOption.BootOption = BootOptionNumber;
-  Status = gBS->CalculateCrc32 (BootOption, BootOptionSize, &KeyOption.BootOptionCrc);
-  ASSERT_EFI_ERROR (Status);
-  FreePool (BootOption);
-
-  VA_START (Args, Modifier);
-  Status = BmInitializeKeyFields (Modifier, Args, &KeyOption);
-  VA_END (Args);
-  if (EFI_ERROR (Status)) {
-    return Status;
-  }
-
-  KeyOptionNumber = LoadOptionNumberUnassigned;
-  //
-  // Check if the hot key sequence was defined already
-  //
-  KeyOptions = BmGetKeyOptions (&KeyOptionCount);
-  for (Index = 0; Index < KeyOptionCount; Index++) {
-    if ((KeyOptions[Index].KeyData.PackedValue == KeyOption.KeyData.PackedValue) &&
-      (CompareMem (KeyOptions[Index].Keys, KeyOption.Keys, KeyOption.KeyData.Options.InputKeyCount * sizeof (EFI_INPUT_KEY)) == 0)) {
-      break;
-    }
-
-    if ((KeyOptionNumber == LoadOptionNumberUnassigned) &&
-        (KeyOptions[Index].OptionNumber > Index)
-       ){
-      KeyOptionNumber = Index;
-    }
-  }
-  BmFreeKeyOptions (KeyOptions, KeyOptionCount);
-
-  if (Index < KeyOptionCount) {
-    return EFI_ALREADY_STARTED;
-  }
-
-  if (KeyOptionNumber == LoadOptionNumberUnassigned) {
-    KeyOptionNumber = KeyOptionCount;
-  }
-
-  UnicodeSPrint (KeyOptionName, sizeof (KeyOptionName), L"Key%04x", KeyOptionNumber);
-
-  Status = gRT->SetVariable (
-                  KeyOptionName,
-                  &gEfiGlobalVariableGuid,
-                  EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
-                  BmSizeOfKeyOption (&KeyOption),
-                  &KeyOption
-                  );
-  if (!EFI_ERROR (Status)) {
-    //
-    // Return the Key Option in case needed by caller
-    //
-    if (AddedOption != NULL) {
-      CopyMem (AddedOption, &KeyOption, sizeof (EFI_BOOT_MANAGER_KEY_OPTION));
-    }
-
-    //
-    // Register the newly added hot key
-    // Calling this function before EfiBootManagerStartHotkeyService doesn't
-    // need to call BmProcessKeyOption
-    //
-    if (mBmHotkeyServiceStarted) {
-      BmProcessKeyOption (&KeyOption);
-    }
-  }
-
-  return Status;
-}
-
-/**
-  Delete the Key Option variable and unregister the hot key
-
-  @param DeletedOption  Return the deleted key options.
-  @param Modifier       Key shift state.
-  @param ...            Parameter list of pointer of EFI_INPUT_KEY.
-
-  @retval EFI_SUCCESS   The key option is deleted.
-  @retval EFI_NOT_FOUND The key option cannot be found.
-**/
-EFI_STATUS
-EFIAPI
-EfiBootManagerDeleteKeyOptionVariable (
-  IN EFI_BOOT_MANAGER_KEY_OPTION *DeletedOption, OPTIONAL
-  IN UINT32                      Modifier,
-  ...
-  )
-{
-  EFI_STATUS                     Status;
-  UINTN                          Index;
-  VA_LIST                        Args;
-  EFI_BOOT_MANAGER_KEY_OPTION    KeyOption;
-  EFI_BOOT_MANAGER_KEY_OPTION    *KeyOptions;
-  UINTN                          KeyOptionCount;
-  LIST_ENTRY                     *Link;
-  BM_HOTKEY                      *Hotkey;
-  UINT32                         ShiftState;
-  BOOLEAN                        Match;
-  CHAR16                         KeyOptionName[sizeof (L"Key####")];
-
-  ZeroMem (&KeyOption, sizeof (EFI_BOOT_MANAGER_KEY_OPTION));
-  VA_START (Args, Modifier);
-  Status = BmInitializeKeyFields (Modifier, Args, &KeyOption);
-  VA_END (Args);
-
-  if (EFI_ERROR (Status)) {
-    return Status;
-  }
-
-  EfiAcquireLock (&mBmHotkeyLock);
-  //
-  // Delete the key option from active hot key list
-  // Could have multiple entries when modifier isn't 0 because we map the ShiftPressed to RIGHT_SHIFT and RIGHT_SHIFT
-  //
-  for (Link = GetFirstNode (&mBmHotkeyList); !IsNull (&mBmHotkeyList, Link); ) {
-    Hotkey = BM_HOTKEY_FROM_LINK (Link);
-    Match  = (BOOLEAN) (Hotkey->CodeCount == KeyOption.KeyData.Options.InputKeyCount);
-
-    for (Index = 0; Match && (Index < Hotkey->CodeCount); Index++) {
-      ShiftState = Hotkey->KeyData[Index].KeyState.KeyShiftState;
-      if (
-        (BmBitSet (ShiftState, EFI_RIGHT_SHIFT_PRESSED | EFI_LEFT_SHIFT_PRESSED) != KeyOption.KeyData.Options.ShiftPressed) ||
-        (BmBitSet (ShiftState, EFI_RIGHT_CONTROL_PRESSED | EFI_LEFT_CONTROL_PRESSED) != KeyOption.KeyData.Options.ControlPressed) ||
-        (BmBitSet (ShiftState, EFI_RIGHT_ALT_PRESSED | EFI_LEFT_ALT_PRESSED) != KeyOption.KeyData.Options.AltPressed) ||
-        (BmBitSet (ShiftState, EFI_RIGHT_LOGO_PRESSED | EFI_LEFT_LOGO_PRESSED) != KeyOption.KeyData.Options.LogoPressed) ||
-        (BmBitSet (ShiftState, EFI_MENU_KEY_PRESSED) != KeyOption.KeyData.Options.MenuPressed) ||
-        (BmBitSet (ShiftState, EFI_SYS_REQ_PRESSED) != KeyOption.KeyData.Options.SysReqPressed) ||
-        (CompareMem (&Hotkey->KeyData[Index].Key, &KeyOption.Keys[Index], sizeof (EFI_INPUT_KEY)) != 0)
-        ) {
-        //
-        // Break when any field doesn't match
-        //
-        Match = FALSE;
-        break;
-      }
-    }
-
-    if (Match) {
-      Link = RemoveEntryList (Link);
-      FreePool (Hotkey);
-    } else {
-      Link = GetNextNode (&mBmHotkeyList, Link);
-    }
-  }
-
-  //
-  // Delete the key option from the variable
-  //
-  Status     = EFI_NOT_FOUND;
-  KeyOptions = BmGetKeyOptions (&KeyOptionCount);
-  for (Index = 0; Index < KeyOptionCount; Index++) {
-    if ((KeyOptions[Index].KeyData.PackedValue == KeyOption.KeyData.PackedValue) &&
-        (CompareMem (
-           KeyOptions[Index].Keys, KeyOption.Keys,
-           KeyOption.KeyData.Options.InputKeyCount * sizeof (EFI_INPUT_KEY)) == 0)
-       ) {
-      UnicodeSPrint (KeyOptionName, sizeof (KeyOptionName), L"Key%04x", KeyOptions[Index].OptionNumber);
-      Status = gRT->SetVariable (
-                 KeyOptionName,
-                 &gEfiGlobalVariableGuid,
-                 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
-                 0,
-                 NULL
-                 );
-      //
-      // Return the deleted key option in case needed by caller
-      //
-      if (DeletedOption != NULL) {
-        CopyMem (DeletedOption, &KeyOptions[Index], sizeof (EFI_BOOT_MANAGER_KEY_OPTION));
-      }
-      break;
-    }
-  }
-  BmFreeKeyOptions (KeyOptions, KeyOptionCount);
-
-  EfiReleaseLock (&mBmHotkeyLock);
-
-  return Status;
-}
+/** @file\r
+  Hotkey library functions.\r
+\r
+Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "InternalBm.h"\r
+\r
+//\r
+// Lock for linked list\r
+//\r
+EFI_LOCK                     mBmHotkeyLock            = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);\r
+LIST_ENTRY                   mBmHotkeyList            = INITIALIZE_LIST_HEAD_VARIABLE (mBmHotkeyList);\r
+EFI_EVENT                    mBmHotkeyTriggered       = NULL;\r
+BOOLEAN                      mBmHotkeyServiceStarted  = FALSE;\r
+UINTN                        mBmHotkeySupportCount    = 0;\r
+\r
+//\r
+// Set OptionNumber as unassigned value to indicate the option isn't initialized\r
+//\r
+EFI_BOOT_MANAGER_LOAD_OPTION mBmHotkeyBootOption      = { LoadOptionNumberUnassigned };\r
+\r
+EFI_BOOT_MANAGER_KEY_OPTION  *mBmContinueKeyOption    = NULL;\r
+VOID                         *mBmTxtInExRegistration  = NULL;\r
+\r
+/**\r
+\r
+  Check whether the input key option is valid.\r
+\r
+  @param   KeyOption               Input key option info.\r
+\r
+  @retval  TRUE               Input key option is valid.\r
+  @retval  FALSE              Input key option is not valid.\r
+**/\r
+BOOLEAN\r
+BmIsKeyOptionValid (\r
+  IN EFI_BOOT_MANAGER_KEY_OPTION     *KeyOption\r
+)\r
+{\r
+  UINT16   OptionName[sizeof (L"Boot####")];\r
+  UINT8    *BootOption;\r
+  UINTN    BootOptionSize;\r
+  UINT32   Crc;\r
+\r
+  //\r
+  // Check whether corresponding Boot Option exist\r
+  //\r
+  UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", KeyOption->BootOption);\r
+  GetEfiGlobalVariable2 (OptionName, (VOID **) &BootOption, &BootOptionSize);\r
+\r
+  if (BootOption == NULL) {\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // Check CRC for Boot Option\r
+  //\r
+  gBS->CalculateCrc32 (BootOption, BootOptionSize, &Crc);\r
+  FreePool (BootOption);\r
+\r
+  return (BOOLEAN) (KeyOption->BootOptionCrc == Crc);\r
+}\r
+\r
+/**\r
+\r
+  Check whether the input variable is an key option variable.\r
+\r
+  @param   Name               Input variable name.\r
+  @param   Guid               Input variable guid.\r
+  @param   OptionNumber       The option number of this key option variable.\r
+\r
+  @retval  TRUE               Input variable is a key option variable.\r
+  @retval  FALSE              Input variable is not a key option variable.\r
+**/\r
+BOOLEAN\r
+BmIsKeyOptionVariable (\r
+  CHAR16        *Name,\r
+  EFI_GUID      *Guid,\r
+  UINT16        *OptionNumber\r
+  )\r
+{\r
+  UINTN         Index;\r
+  \r
+  if (!CompareGuid (Guid, &gEfiGlobalVariableGuid) ||\r
+      (StrSize (Name) != sizeof (L"Key####")) ||\r
+      (StrnCmp (Name, L"Key", 3) != 0)\r
+     ) {\r
+    return FALSE;\r
+  }\r
+\r
+  *OptionNumber = 0;\r
+  for (Index = 3; Index < 7; Index++) {\r
+    if ((Name[Index] >= L'0') && (Name[Index] <= L'9')) {\r
+      *OptionNumber = *OptionNumber * 16 + Name[Index] - L'0';\r
+    } else if ((Name[Index] >= L'A') && (Name[Index] <= L'F')) {\r
+      *OptionNumber = *OptionNumber * 16 + Name[Index] - L'A' + 10;\r
+    } else {\r
+      return FALSE;\r
+    }\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+/**\r
+  Return the buffer size of the EFI_BOOT_MANAGER_KEY_OPTION data.\r
+\r
+  @param   KeyOption            The input key option info.\r
+\r
+  @retval  The buffer size of the key option data.\r
+**/\r
+UINTN\r
+BmSizeOfKeyOption (\r
+  EFI_BOOT_MANAGER_KEY_OPTION  *KeyOption\r
+  )\r
+{\r
+  return OFFSET_OF (EFI_BOOT_MANAGER_KEY_OPTION, Keys)\r
+    + KeyOption->KeyData.Options.InputKeyCount * sizeof (EFI_INPUT_KEY);\r
+}\r
+\r
+/**\r
+  Return the array of key options.\r
+\r
+  @param Count  Return the number of key options.\r
+\r
+  @retval NULL  No key option.\r
+  @retval Other Pointer to the key options.\r
+**/\r
+EFI_BOOT_MANAGER_KEY_OPTION *\r
+BmGetKeyOptions (\r
+  OUT UINTN     *Count\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  UINTN                       Index;\r
+  CHAR16                      *Name;\r
+  EFI_GUID                    Guid;\r
+  UINTN                       NameSize;\r
+  UINTN                       NewNameSize;\r
+  EFI_BOOT_MANAGER_KEY_OPTION *KeyOptions;\r
+  EFI_BOOT_MANAGER_KEY_OPTION *KeyOption;\r
+  UINT16                      OptionNumber;\r
+\r
+  if (Count == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  *Count     = 0;\r
+  KeyOptions = NULL;\r
+\r
+  NameSize = sizeof (CHAR16);\r
+  Name     = AllocateZeroPool (NameSize);\r
+  ASSERT (Name != NULL);\r
+  while (TRUE) {\r
+    NewNameSize = NameSize;\r
+    Status = gRT->GetNextVariableName (&NewNameSize, Name, &Guid);\r
+    if (Status == EFI_BUFFER_TOO_SMALL) {\r
+      Name = ReallocatePool (NameSize, NewNameSize, Name);\r
+      ASSERT (Name != NULL);\r
+      Status = gRT->GetNextVariableName (&NewNameSize, Name, &Guid);\r
+      NameSize = NewNameSize;\r
+    }\r
+\r
+    if (Status == EFI_NOT_FOUND) {\r
+      break;\r
+    }\r
+    ASSERT_EFI_ERROR (Status);\r
+\r
+    if (BmIsKeyOptionVariable (Name ,&Guid, &OptionNumber)) {\r
+      GetEfiGlobalVariable2 (Name, (VOID**) &KeyOption, NULL);\r
+      ASSERT (KeyOption != NULL);\r
+      if (BmIsKeyOptionValid (KeyOption)) {\r
+        KeyOptions = ReallocatePool (\r
+                       *Count * sizeof (EFI_BOOT_MANAGER_KEY_OPTION),\r
+                       (*Count + 1) * sizeof (EFI_BOOT_MANAGER_KEY_OPTION),\r
+                       KeyOptions\r
+                       );\r
+        ASSERT (KeyOptions != NULL);\r
+        //\r
+        // Insert the key option in order\r
+        //\r
+        for (Index = 0; Index < *Count; Index++) {\r
+          if (OptionNumber < KeyOptions[Index].OptionNumber) {\r
+            break;\r
+          }\r
+        }\r
+        CopyMem (&KeyOptions[Index + 1], &KeyOptions[Index], (*Count - Index) * sizeof (EFI_BOOT_MANAGER_KEY_OPTION));\r
+        CopyMem (&KeyOptions[Index], KeyOption, BmSizeOfKeyOption (KeyOption));\r
+        KeyOptions[Index].OptionNumber = OptionNumber;\r
+        (*Count)++;\r
+      }\r
+      FreePool (KeyOption);\r
+    }\r
+  }\r
+\r
+  FreePool (Name);\r
+\r
+  return KeyOptions;\r
+}\r
+\r
+/**\r
+  Callback function for event.\r
+  \r
+  @param    Event          Event for this callback function.\r
+  @param    Context        Context pass to this function.\r
+**/\r
+VOID\r
+EFIAPI\r
+BmEmptyFunction (\r
+  IN EFI_EVENT                Event,\r
+  IN VOID                     *Context\r
+  )\r
+{\r
+}\r
+\r
+/**\r
+  Check whether the bit is set in the value.\r
+\r
+  @param   Value            The value need to be check.\r
+  @param   Bit              The bit filed need to be check.\r
+\r
+  @retval  TRUE             The bit is set.\r
+  @retval  FALSE            The bit is not set.\r
+**/\r
+BOOLEAN\r
+BmBitSet (\r
+  IN UINT32   Value,\r
+  IN UINT32   Bit\r
+  )\r
+{\r
+  return (BOOLEAN) ((Value & Bit) != 0);\r
+}\r
+\r
+/**\r
+  Initialize the KeyData and Key[] in the EFI_BOOT_MANAGER_KEY_OPTION.\r
+\r
+  @param  Modifier   Input key info.\r
+  @param  Args       Va_list info.\r
+  @param  KeyOption  Key info which need to update.\r
+\r
+  @retval  EFI_SUCCESS             Succeed to initialize the KeyData and Key[].\r
+  @return  EFI_INVALID_PARAMETER   Input parameter error.\r
+**/\r
+EFI_STATUS\r
+BmInitializeKeyFields (\r
+  IN UINT32                       Modifier,\r
+  IN VA_LIST                      Args,\r
+  OUT EFI_BOOT_MANAGER_KEY_OPTION *KeyOption\r
+  )\r
+{\r
+  EFI_INPUT_KEY                   *Key;\r
+\r
+  if (KeyOption == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Key = NULL;\r
+  while (KeyOption->KeyData.Options.InputKeyCount < sizeof (KeyOption->Keys) / sizeof (KeyOption->Keys[0])) {\r
+    Key = VA_ARG (Args, EFI_INPUT_KEY *);\r
+    if (Key == NULL) {\r
+      break;\r
+    }\r
+    CopyMem (\r
+      &KeyOption->Keys[KeyOption->KeyData.Options.InputKeyCount],\r
+      Key,\r
+      sizeof (EFI_INPUT_KEY)\r
+      );\r
+    KeyOption->KeyData.Options.InputKeyCount++;\r
+  }\r
+\r
+  if (Key != NULL) {\r
+    //\r
+    // Too many keys\r
+    //\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((Modifier & ~(EFI_BOOT_MANAGER_SHIFT_PRESSED\r
+                 | EFI_BOOT_MANAGER_CONTROL_PRESSED\r
+                 | EFI_BOOT_MANAGER_ALT_PRESSED\r
+                 | EFI_BOOT_MANAGER_LOGO_PRESSED\r
+                 | EFI_BOOT_MANAGER_MENU_KEY_PRESSED\r
+                 | EFI_BOOT_MANAGER_SYS_REQ_PRESSED\r
+                 )) != 0) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (BmBitSet (Modifier, EFI_BOOT_MANAGER_SHIFT_PRESSED)) {\r
+    KeyOption->KeyData.Options.ShiftPressed = 1;\r
+  }\r
+  if (BmBitSet (Modifier, EFI_BOOT_MANAGER_CONTROL_PRESSED)) {\r
+    KeyOption->KeyData.Options.ControlPressed = 1;\r
+  }\r
+  if (BmBitSet (Modifier, EFI_BOOT_MANAGER_ALT_PRESSED)) {\r
+    KeyOption->KeyData.Options.AltPressed = 1;\r
+  }\r
+  if (BmBitSet (Modifier, EFI_BOOT_MANAGER_LOGO_PRESSED)) {\r
+    KeyOption->KeyData.Options.LogoPressed = 1;\r
+  }\r
+  if (BmBitSet (Modifier, EFI_BOOT_MANAGER_MENU_KEY_PRESSED)) {\r
+    KeyOption->KeyData.Options.MenuPressed = 1;\r
+  }\r
+  if (BmBitSet (Modifier, EFI_BOOT_MANAGER_SYS_REQ_PRESSED)) {\r
+    KeyOption->KeyData.Options.SysReqPressed = 1;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Try to boot the boot option triggered by hot key.\r
+**/\r
+VOID\r
+EFIAPI\r
+EfiBootManagerHotkeyBoot (\r
+  VOID\r
+  )\r
+{\r
+  if (mBmHotkeyBootOption.OptionNumber != LoadOptionNumberUnassigned) {\r
+    EfiBootManagerBoot (&mBmHotkeyBootOption);\r
+    EfiBootManagerFreeLoadOption (&mBmHotkeyBootOption);\r
+    mBmHotkeyBootOption.OptionNumber = LoadOptionNumberUnassigned;\r
+  }\r
+}\r
+\r
+/**\r
+  This is the common notification function for HotKeys, it will be registered\r
+  with SimpleTextInEx protocol interface - RegisterKeyNotify() of ConIn handle.\r
+\r
+  @param KeyData         A pointer to a buffer that is filled in with the keystroke\r
+                         information for the key that was pressed.\r
+\r
+  @retval  EFI_SUCCESS   KeyData is successfully processed.\r
+  @return  EFI_NOT_FOUND Fail to find boot option variable.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BmHotkeyCallback (\r
+  IN EFI_KEY_DATA     *KeyData\r
+)\r
+{\r
+  LIST_ENTRY                    *Link;\r
+  BM_HOTKEY                     *Hotkey;\r
+  CHAR16                        OptionName[sizeof ("Boot####")];\r
+  EFI_STATUS                    Status;\r
+  EFI_KEY_DATA                  *HotkeyData;\r
+\r
+  if (mBmHotkeyBootOption.OptionNumber != LoadOptionNumberUnassigned) {\r
+    //\r
+    // Do not process sequential hotkey stroke until the current boot option returns\r
+    //\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  DEBUG ((EFI_D_INFO, "[Bds]BmHotkeyCallback: %04x:%04x\n", KeyData->Key.ScanCode, KeyData->Key.UnicodeChar));\r
+\r
+  EfiAcquireLock (&mBmHotkeyLock);\r
+  for ( Link = GetFirstNode (&mBmHotkeyList)\r
+      ; !IsNull (&mBmHotkeyList, Link)\r
+      ; Link = GetNextNode (&mBmHotkeyList, Link)\r
+      ) {\r
+    Hotkey = BM_HOTKEY_FROM_LINK (Link);\r
+\r
+    //\r
+    // Is this Key Stroke we are waiting for?\r
+    //\r
+    ASSERT (Hotkey->WaitingKey < (sizeof (Hotkey->KeyData) / sizeof (Hotkey->KeyData[0])));\r
+    HotkeyData = &Hotkey->KeyData[Hotkey->WaitingKey];\r
+    if ((KeyData->Key.ScanCode == HotkeyData->Key.ScanCode) &&\r
+        (KeyData->Key.UnicodeChar == HotkeyData->Key.UnicodeChar) &&\r
+        (((KeyData->KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) != 0) ? \r
+          (KeyData->KeyState.KeyShiftState == HotkeyData->KeyState.KeyShiftState) : TRUE\r
+        )\r
+       ) {\r
+\r
+      //\r
+      // Receive an expecting key stroke, transit to next waiting state\r
+      //\r
+      Hotkey->WaitingKey++;\r
+\r
+      if (Hotkey->WaitingKey == Hotkey->CodeCount) {\r
+        //\r
+        // Reset to initial waiting state\r
+        //\r
+        Hotkey->WaitingKey = 0;\r
+        //\r
+        // Received the whole key stroke sequence\r
+        //\r
+        Status = gBS->SignalEvent (mBmHotkeyTriggered);\r
+        ASSERT_EFI_ERROR (Status);\r
+\r
+        if (!Hotkey->IsContinue) {\r
+          //\r
+          // Launch its BootOption\r
+          //\r
+          UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", Hotkey->BootOption);\r
+          Status = EfiBootManagerVariableToLoadOption (OptionName, &mBmHotkeyBootOption);\r
+          DEBUG ((EFI_D_INFO, "[Bds]Hotkey for %s pressed - %r\n", OptionName, Status));\r
+          if (EFI_ERROR (Status)) {\r
+            mBmHotkeyBootOption.OptionNumber = LoadOptionNumberUnassigned;\r
+          }\r
+        } else {\r
+          DEBUG ((EFI_D_INFO, "[Bds]Continue key pressed!\n"));\r
+        }\r
+      }\r
+    } else {\r
+      //\r
+      // Receive an unexpected key stroke, reset to initial waiting state\r
+      //\r
+      Hotkey->WaitingKey = 0;\r
+    }\r
+\r
+  }\r
+  EfiReleaseLock (&mBmHotkeyLock);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Unregister hotkey notify list.\r
+\r
+  @param    Hotkey                Hotkey list.\r
+\r
+  @retval   EFI_SUCCESS           Unregister hotkey notify success.\r
+  @retval   Others                Unregister hotkey notify failed.\r
+**/\r
+EFI_STATUS\r
+BmUnregisterHotkeyNotify (\r
+  IN BM_HOTKEY                          *Hotkey\r
+  )\r
+{\r
+  EFI_STATUS                            Status;\r
+  UINTN                                 Index;\r
+  UINTN                                 KeyIndex;\r
+  EFI_HANDLE                            *Handles;\r
+  UINTN                                 HandleCount;\r
+  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL     *TxtInEx;\r
+  VOID                                  *NotifyHandle;\r
+\r
+  gBS->LocateHandleBuffer (\r
+          ByProtocol,\r
+          &gEfiSimpleTextInputExProtocolGuid,\r
+          NULL,\r
+          &HandleCount,\r
+          &Handles\r
+          );\r
+  for (Index = 0; Index < HandleCount; Index++) {\r
+    Status = gBS->HandleProtocol (Handles[Index], &gEfiSimpleTextInputExProtocolGuid, (VOID **) &TxtInEx);\r
+    ASSERT_EFI_ERROR (Status);\r
+    for (KeyIndex = 0; KeyIndex < Hotkey->CodeCount; KeyIndex++) {\r
+      Status = TxtInEx->RegisterKeyNotify (\r
+                          TxtInEx,\r
+                          &Hotkey->KeyData[KeyIndex],\r
+                          BmHotkeyCallback,\r
+                          &NotifyHandle\r
+                          );\r
+      if (!EFI_ERROR (Status)) {\r
+        Status = TxtInEx->UnregisterKeyNotify (TxtInEx, NotifyHandle);\r
+        DEBUG ((EFI_D_INFO, "[Bds]UnregisterKeyNotify: %04x/%04x %r\n", Hotkey->KeyData[KeyIndex].Key.ScanCode, Hotkey->KeyData[KeyIndex].Key.UnicodeChar, Status));\r
+      }\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Register hotkey notify list.\r
+\r
+  @param    TxtInEx               Pointer to EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL protocol.\r
+  @param    Hotkey                Hotkey list.\r
+\r
+  @retval   EFI_SUCCESS           Register hotkey notify success.\r
+  @retval   Others                Register hotkey notify failed.\r
+**/\r
+EFI_STATUS\r
+BmRegisterHotkeyNotify (\r
+  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *TxtInEx,\r
+  IN BM_HOTKEY                          *Hotkey\r
+  )\r
+{\r
+  EFI_STATUS                            Status;\r
+  UINTN                                 Index;\r
+  VOID                                  *NotifyHandle;\r
+\r
+  for (Index = 0; Index < Hotkey->CodeCount; Index++) {\r
+    Status = TxtInEx->RegisterKeyNotify (\r
+                        TxtInEx,\r
+                        &Hotkey->KeyData[Index],\r
+                        BmHotkeyCallback,\r
+                        &NotifyHandle\r
+                        );\r
+    DEBUG ((\r
+      EFI_D_INFO,\r
+      "[Bds]RegisterKeyNotify: %04x/%04x %08x/%02x %r\n",\r
+      Hotkey->KeyData[Index].Key.ScanCode,\r
+      Hotkey->KeyData[Index].Key.UnicodeChar,\r
+      Hotkey->KeyData[Index].KeyState.KeyShiftState,\r
+      Hotkey->KeyData[Index].KeyState.KeyToggleState,\r
+      Status\r
+      ));\r
+    if (EFI_ERROR (Status)) {\r
+      //\r
+      // some of the hotkey registry failed\r
+      // do not unregister all in case we have both CTRL-ALT-P and CTRL-ALT-P-R\r
+      //\r
+      break;\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Generate key shift state base on the input key option info.\r
+\r
+  @param    Depth                 Which key is checked.\r
+  @param    KeyOption             Input key option info.\r
+  @param    KeyShiftState         Input key shift state.\r
+  @param    KeyShiftStates        Return possible key shift state array.\r
+  @param    KeyShiftStateCount    Possible key shift state count.\r
+**/\r
+VOID\r
+BmGenerateKeyShiftState (\r
+  IN UINTN                             Depth,\r
+  IN EFI_BOOT_MANAGER_KEY_OPTION       *KeyOption,\r
+  IN UINT32                            KeyShiftState,\r
+  IN UINT32                            *KeyShiftStates,\r
+  IN UINTN                             *KeyShiftStateCount\r
+  )\r
+{\r
+  switch (Depth) {\r
+  case 0:\r
+    if (KeyOption->KeyData.Options.ShiftPressed) {\r
+      BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_RIGHT_SHIFT_PRESSED, KeyShiftStates, KeyShiftStateCount);\r
+      BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_LEFT_SHIFT_PRESSED,  KeyShiftStates, KeyShiftStateCount);\r
+    } else {\r
+      BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState, KeyShiftStates, KeyShiftStateCount);\r
+    }\r
+    break;\r
+\r
+  case 1:\r
+    if (KeyOption->KeyData.Options.ControlPressed) {\r
+      BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_RIGHT_CONTROL_PRESSED, KeyShiftStates, KeyShiftStateCount);\r
+      BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_LEFT_CONTROL_PRESSED,  KeyShiftStates, KeyShiftStateCount);\r
+    } else {\r
+      BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState, KeyShiftStates, KeyShiftStateCount);\r
+    }\r
+    break;\r
+\r
+  case 2:\r
+    if (KeyOption->KeyData.Options.AltPressed) {\r
+      BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_RIGHT_ALT_PRESSED, KeyShiftStates, KeyShiftStateCount);\r
+      BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_LEFT_ALT_PRESSED,  KeyShiftStates, KeyShiftStateCount);\r
+    } else {\r
+      BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState, KeyShiftStates, KeyShiftStateCount);\r
+    }\r
+    break;\r
+  case  3:\r
+    if (KeyOption->KeyData.Options.LogoPressed) {\r
+      BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_RIGHT_LOGO_PRESSED, KeyShiftStates, KeyShiftStateCount);\r
+      BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState | EFI_LEFT_LOGO_PRESSED,  KeyShiftStates, KeyShiftStateCount);\r
+    } else {\r
+      BmGenerateKeyShiftState (Depth + 1, KeyOption, KeyShiftState, KeyShiftStates, KeyShiftStateCount);\r
+    }\r
+    break;\r
+  case 4:\r
+    if (KeyOption->KeyData.Options.MenuPressed) {\r
+      KeyShiftState |= EFI_MENU_KEY_PRESSED;\r
+    }\r
+    if (KeyOption->KeyData.Options.SysReqPressed) {\r
+      KeyShiftState |= EFI_SYS_REQ_PRESSED;\r
+    }\r
+    KeyShiftStates[*KeyShiftStateCount] = KeyShiftState;\r
+    (*KeyShiftStateCount)++;\r
+    break;\r
+  }\r
+}\r
+\r
+/**\r
+  Add it to hot key database, register it to existing TxtInEx.\r
+  New TxtInEx will be automatically registered with all the hot key in dababase\r
+\r
+  @param    KeyOption  Input key option info.\r
+**/\r
+EFI_STATUS\r
+BmProcessKeyOption (\r
+  IN EFI_BOOT_MANAGER_KEY_OPTION       *KeyOption\r
+  )\r
+{\r
+  EFI_STATUS                           Status;\r
+  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL    *TxtInEx;\r
+  EFI_HANDLE                           *Handles;\r
+  UINTN                                HandleCount;\r
+  UINTN                                HandleIndex;\r
+  UINTN                                Index;\r
+  BM_HOTKEY                            *Hotkey;\r
+  UINTN                                KeyIndex;\r
+  //\r
+  // 16 is enough to enumerate all the possible combination of LEFT_XXX and RIGHT_XXX\r
+  //\r
+  UINT32                               KeyShiftStates[16];\r
+  UINTN                                KeyShiftStateCount;\r
+\r
+  if (KeyOption->KeyData.Options.InputKeyCount > mBmHotkeySupportCount) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  KeyShiftStateCount = 0;\r
+  BmGenerateKeyShiftState (0, KeyOption, EFI_SHIFT_STATE_VALID, KeyShiftStates, &KeyShiftStateCount);\r
+  ASSERT (KeyShiftStateCount <= sizeof (KeyShiftStates) / sizeof (KeyShiftStates[0]));\r
+\r
+  EfiAcquireLock (&mBmHotkeyLock);\r
+\r
+  for (Index = 0; Index < KeyShiftStateCount; Index++) {\r
+    Hotkey = AllocateZeroPool (sizeof (BM_HOTKEY));\r
+    ASSERT (Hotkey != NULL);\r
+\r
+    Hotkey->Signature  = BM_HOTKEY_SIGNATURE;\r
+    Hotkey->BootOption = KeyOption->BootOption;\r
+    Hotkey->IsContinue = (BOOLEAN) (KeyOption == mBmContinueKeyOption);\r
+    Hotkey->CodeCount  = (UINT8) KeyOption->KeyData.Options.InputKeyCount;\r
+\r
+    for (KeyIndex = 0; KeyIndex < Hotkey->CodeCount; KeyIndex++) {\r
+      CopyMem (&Hotkey->KeyData[KeyIndex].Key, &KeyOption->Keys[KeyIndex], sizeof (EFI_INPUT_KEY));\r
+      Hotkey->KeyData[KeyIndex].KeyState.KeyShiftState = KeyShiftStates[Index];\r
+    }\r
+    InsertTailList (&mBmHotkeyList, &Hotkey->Link);\r
+\r
+    gBS->LocateHandleBuffer (\r
+            ByProtocol,\r
+            &gEfiSimpleTextInputExProtocolGuid,\r
+            NULL,\r
+            &HandleCount,\r
+            &Handles\r
+            );\r
+    for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {\r
+      Status = gBS->HandleProtocol (Handles[HandleIndex], &gEfiSimpleTextInputExProtocolGuid, (VOID **) &TxtInEx);\r
+      ASSERT_EFI_ERROR (Status);\r
+      BmRegisterHotkeyNotify (TxtInEx, Hotkey);\r
+    }\r
+  }\r
+\r
+  EfiReleaseLock (&mBmHotkeyLock);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Callback function for SimpleTextInEx protocol install events\r
+\r
+  @param Event           the event that is signaled.\r
+  @param Context         not used here.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+BmTxtInExCallback (\r
+  IN EFI_EVENT    Event,\r
+  IN VOID         *Context\r
+  )\r
+{\r
+  EFI_STATUS                         Status;\r
+  UINTN                              BufferSize;\r
+  EFI_HANDLE                         Handle;\r
+  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *TxtInEx;\r
+  LIST_ENTRY                         *Link;\r
+\r
+  while (TRUE) {\r
+    BufferSize = sizeof (EFI_HANDLE);\r
+    Status = gBS->LocateHandle (\r
+                    ByRegisterNotify,\r
+                    NULL,\r
+                    mBmTxtInExRegistration,\r
+                    &BufferSize,\r
+                    &Handle\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      //\r
+      // If no more notification events exist\r
+      //\r
+      return ;\r
+    }\r
+\r
+    Status = gBS->HandleProtocol (\r
+                    Handle,\r
+                    &gEfiSimpleTextInputExProtocolGuid,\r
+                    (VOID **) &TxtInEx\r
+                    );\r
+    ASSERT_EFI_ERROR (Status);\r
+\r
+    //\r
+    // Register the hot key notification for the existing items in the list\r
+    //\r
+    EfiAcquireLock (&mBmHotkeyLock);\r
+    for (Link = GetFirstNode (&mBmHotkeyList); !IsNull (&mBmHotkeyList, Link); Link = GetNextNode (&mBmHotkeyList, Link)) {\r
+      BmRegisterHotkeyNotify (TxtInEx, BM_HOTKEY_FROM_LINK (Link));\r
+    }\r
+    EfiReleaseLock (&mBmHotkeyLock);\r
+  }\r
+}\r
+\r
+/**\r
+  Free the key options returned from BmGetKeyOptions.\r
+\r
+  @param KeyOptions     Pointer to the key options.\r
+  @param KeyOptionCount Number of the key options.\r
+\r
+  @retval EFI_SUCCESS   The key options are freed.\r
+  @retval EFI_NOT_FOUND KeyOptions is NULL.\r
+**/\r
+EFI_STATUS\r
+BmFreeKeyOptions (\r
+  IN EFI_BOOT_MANAGER_KEY_OPTION    *KeyOptions,\r
+  IN UINTN                          KeyOptionCount\r
+  )\r
+{\r
+  if (KeyOptions != NULL) {\r
+    FreePool (KeyOptions);\r
+    return EFI_SUCCESS;\r
+  } else {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+}\r
+\r
+/**\r
+  Register the key option to exit the waiting of the Boot Manager timeout.\r
+  Platform should ensure that the continue key option isn't conflict with\r
+  other boot key options.\r
+\r
+  @param Modifier     Key shift state.\r
+  @param  ...         Parameter list of pointer of EFI_INPUT_KEY.\r
+\r
+  @retval EFI_SUCCESS         Successfully register the continue key option.\r
+  @retval EFI_ALREADY_STARTED The continue key option is already registered.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiBootManagerRegisterContinueKeyOption (\r
+  IN UINT32           Modifier,\r
+  ...\r
+  )\r
+{\r
+  EFI_STATUS                   Status;\r
+  EFI_BOOT_MANAGER_KEY_OPTION  KeyOption;\r
+  VA_LIST                      Args;\r
+  \r
+  if (mBmContinueKeyOption != NULL) {\r
+    return EFI_ALREADY_STARTED;\r
+  }\r
+\r
+  ZeroMem (&KeyOption, sizeof (EFI_BOOT_MANAGER_KEY_OPTION));\r
+  VA_START (Args, Modifier);\r
+  Status = BmInitializeKeyFields (Modifier, Args, &KeyOption);\r
+  VA_END (Args);\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    mBmContinueKeyOption = AllocateCopyPool (sizeof (EFI_BOOT_MANAGER_KEY_OPTION), &KeyOption);\r
+    ASSERT (mBmContinueKeyOption != NULL);\r
+    if (mBmHotkeyServiceStarted) {\r
+      BmProcessKeyOption (mBmContinueKeyOption);\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Stop the hotkey processing.\r
+  \r
+  @param    Event          Event pointer related to hotkey service.\r
+  @param    Context        Context pass to this function.\r
+**/\r
+VOID\r
+EFIAPI\r
+BmStopHotkeyService (\r
+  IN EFI_EVENT    Event,\r
+  IN VOID         *Context\r
+  )\r
+{\r
+  LIST_ENTRY            *Link;\r
+  BM_HOTKEY             *Hotkey;\r
+\r
+  DEBUG ((EFI_D_INFO, "[Bds]Stop Hotkey Service!\n"));\r
+  gBS->CloseEvent (Event);\r
+\r
+  EfiAcquireLock (&mBmHotkeyLock);\r
+  for (Link = GetFirstNode (&mBmHotkeyList); !IsNull (&mBmHotkeyList, Link); ) {\r
+    Hotkey = BM_HOTKEY_FROM_LINK (Link);\r
+    BmUnregisterHotkeyNotify (Hotkey);\r
+    Link   = RemoveEntryList (Link);\r
+    FreePool (Hotkey);\r
+  }\r
+  EfiReleaseLock (&mBmHotkeyLock);\r
+}\r
+\r
+/**\r
+  Start the hot key service so that the key press can trigger the boot option.\r
+\r
+  @param HotkeyTriggered  Return the waitable event and it will be signaled \r
+                          when a valid hot key is pressed.\r
+\r
+  @retval EFI_SUCCESS     The hot key service is started.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiBootManagerStartHotkeyService (\r
+  IN EFI_EVENT                 *HotkeyTriggered\r
+  )\r
+{\r
+  EFI_STATUS                   Status;\r
+  EFI_BOOT_MANAGER_KEY_OPTION  *KeyOptions;\r
+  UINTN                        KeyOptionCount;\r
+  UINTN                        Index;\r
+  EFI_EVENT                    Event;\r
+  UINT32                       *BootOptionSupport;\r
+\r
+  Status = GetEfiGlobalVariable2 (EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME, (VOID **) &BootOptionSupport, NULL);\r
+  ASSERT (BootOptionSupport != NULL);\r
+\r
+  if ((*BootOptionSupport & EFI_BOOT_OPTION_SUPPORT_KEY)  != 0) {\r
+    mBmHotkeySupportCount = ((*BootOptionSupport & EFI_BOOT_OPTION_SUPPORT_COUNT) >> LowBitSet32 (EFI_BOOT_OPTION_SUPPORT_COUNT));\r
+  }\r
+  FreePool (BootOptionSupport);\r
+\r
+  if (mBmHotkeySupportCount == 0) {\r
+    DEBUG ((EFI_D_INFO, "Bds: BootOptionSupport NV variable forbids starting the hotkey service.\n"));\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  Status = gBS->CreateEvent (\r
+                  EVT_NOTIFY_WAIT,\r
+                  TPL_CALLBACK,\r
+                  BmEmptyFunction,\r
+                  NULL,\r
+                  &mBmHotkeyTriggered\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  if (HotkeyTriggered != NULL) {\r
+    *HotkeyTriggered = mBmHotkeyTriggered;\r
+  }\r
+\r
+  KeyOptions = BmGetKeyOptions (&KeyOptionCount);\r
+  for (Index = 0; Index < KeyOptionCount; Index ++) {\r
+    BmProcessKeyOption (&KeyOptions[Index]);\r
+  }\r
+  BmFreeKeyOptions (KeyOptions, KeyOptionCount);\r
+\r
+  if (mBmContinueKeyOption != NULL) {\r
+    BmProcessKeyOption (mBmContinueKeyOption);\r
+  }\r
+\r
+  EfiCreateProtocolNotifyEvent (\r
+    &gEfiSimpleTextInputExProtocolGuid,\r
+    TPL_CALLBACK,\r
+    BmTxtInExCallback,\r
+    NULL,\r
+    &mBmTxtInExRegistration\r
+    );\r
+\r
+  Status = EfiCreateEventReadyToBootEx (\r
+             TPL_CALLBACK,\r
+             BmStopHotkeyService,\r
+             NULL,\r
+             &Event\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+\r
+  mBmHotkeyServiceStarted = TRUE;\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Add the key option.\r
+  It adds the key option variable and the key option takes affect immediately.\r
+\r
+  @param AddedOption      Return the added key option.\r
+  @param BootOptionNumber The boot option number for the key option.\r
+  @param Modifier         Key shift state.\r
+  @param ...              Parameter list of pointer of EFI_INPUT_KEY.\r
+\r
+  @retval EFI_SUCCESS         The key option is added.\r
+  @retval EFI_ALREADY_STARTED The hot key is already used by certain key option.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiBootManagerAddKeyOptionVariable (\r
+  OUT EFI_BOOT_MANAGER_KEY_OPTION *AddedOption,   OPTIONAL\r
+  IN UINT16                       BootOptionNumber,\r
+  IN UINT32                       Modifier,\r
+  ...\r
+  )\r
+{\r
+  EFI_STATUS                     Status;\r
+  VA_LIST                        Args;\r
+  VOID                           *BootOption;\r
+  UINTN                          BootOptionSize;\r
+  CHAR16                         BootOptionName[sizeof (L"Boot####")];\r
+  EFI_BOOT_MANAGER_KEY_OPTION    KeyOption;\r
+  EFI_BOOT_MANAGER_KEY_OPTION    *KeyOptions;\r
+  UINTN                          KeyOptionCount;\r
+  UINTN                          Index;\r
+  UINTN                          KeyOptionNumber;\r
+  CHAR16                         KeyOptionName[sizeof (L"Key####")];\r
+\r
+  UnicodeSPrint (BootOptionName, sizeof (BootOptionName), L"Boot%04x", BootOptionNumber);\r
+  GetEfiGlobalVariable2 (BootOptionName, &BootOption, &BootOptionSize);\r
+\r
+  if (BootOption == NULL) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  ZeroMem (&KeyOption, sizeof (EFI_BOOT_MANAGER_KEY_OPTION));\r
+  KeyOption.BootOption = BootOptionNumber;\r
+  Status = gBS->CalculateCrc32 (BootOption, BootOptionSize, &KeyOption.BootOptionCrc);\r
+  ASSERT_EFI_ERROR (Status);\r
+  FreePool (BootOption);\r
+\r
+  VA_START (Args, Modifier);\r
+  Status = BmInitializeKeyFields (Modifier, Args, &KeyOption);\r
+  VA_END (Args);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  KeyOptionNumber = LoadOptionNumberUnassigned;\r
+  //\r
+  // Check if the hot key sequence was defined already\r
+  //\r
+  KeyOptions = BmGetKeyOptions (&KeyOptionCount);\r
+  for (Index = 0; Index < KeyOptionCount; Index++) {\r
+    if ((KeyOptions[Index].KeyData.PackedValue == KeyOption.KeyData.PackedValue) &&\r
+      (CompareMem (KeyOptions[Index].Keys, KeyOption.Keys, KeyOption.KeyData.Options.InputKeyCount * sizeof (EFI_INPUT_KEY)) == 0)) {\r
+      break;\r
+    }\r
+\r
+    if ((KeyOptionNumber == LoadOptionNumberUnassigned) &&\r
+        (KeyOptions[Index].OptionNumber > Index)\r
+       ){\r
+      KeyOptionNumber = Index;\r
+    }\r
+  }\r
+  BmFreeKeyOptions (KeyOptions, KeyOptionCount);\r
+\r
+  if (Index < KeyOptionCount) {\r
+    return EFI_ALREADY_STARTED;\r
+  }\r
+\r
+  if (KeyOptionNumber == LoadOptionNumberUnassigned) {\r
+    KeyOptionNumber = KeyOptionCount;\r
+  }\r
+\r
+  UnicodeSPrint (KeyOptionName, sizeof (KeyOptionName), L"Key%04x", KeyOptionNumber);\r
+\r
+  Status = gRT->SetVariable (\r
+                  KeyOptionName,\r
+                  &gEfiGlobalVariableGuid,\r
+                  EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
+                  BmSizeOfKeyOption (&KeyOption),\r
+                  &KeyOption\r
+                  );\r
+  if (!EFI_ERROR (Status)) {\r
+    //\r
+    // Return the Key Option in case needed by caller\r
+    //\r
+    if (AddedOption != NULL) {\r
+      CopyMem (AddedOption, &KeyOption, sizeof (EFI_BOOT_MANAGER_KEY_OPTION));\r
+    }\r
+\r
+    //\r
+    // Register the newly added hot key\r
+    // Calling this function before EfiBootManagerStartHotkeyService doesn't\r
+    // need to call BmProcessKeyOption\r
+    //\r
+    if (mBmHotkeyServiceStarted) {\r
+      BmProcessKeyOption (&KeyOption);\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Delete the Key Option variable and unregister the hot key\r
+\r
+  @param DeletedOption  Return the deleted key options.\r
+  @param Modifier       Key shift state.\r
+  @param ...            Parameter list of pointer of EFI_INPUT_KEY.\r
+\r
+  @retval EFI_SUCCESS   The key option is deleted.\r
+  @retval EFI_NOT_FOUND The key option cannot be found.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiBootManagerDeleteKeyOptionVariable (\r
+  IN EFI_BOOT_MANAGER_KEY_OPTION *DeletedOption, OPTIONAL\r
+  IN UINT32                      Modifier,\r
+  ...\r
+  )\r
+{\r
+  EFI_STATUS                     Status;\r
+  UINTN                          Index;\r
+  VA_LIST                        Args;\r
+  EFI_BOOT_MANAGER_KEY_OPTION    KeyOption;\r
+  EFI_BOOT_MANAGER_KEY_OPTION    *KeyOptions;\r
+  UINTN                          KeyOptionCount;\r
+  LIST_ENTRY                     *Link;\r
+  BM_HOTKEY                      *Hotkey;\r
+  UINT32                         ShiftState;\r
+  BOOLEAN                        Match;\r
+  CHAR16                         KeyOptionName[sizeof (L"Key####")];\r
+\r
+  ZeroMem (&KeyOption, sizeof (EFI_BOOT_MANAGER_KEY_OPTION));\r
+  VA_START (Args, Modifier);\r
+  Status = BmInitializeKeyFields (Modifier, Args, &KeyOption);\r
+  VA_END (Args);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  EfiAcquireLock (&mBmHotkeyLock);\r
+  //\r
+  // Delete the key option from active hot key list\r
+  // Could have multiple entries when modifier isn't 0 because we map the ShiftPressed to RIGHT_SHIFT and RIGHT_SHIFT\r
+  //\r
+  for (Link = GetFirstNode (&mBmHotkeyList); !IsNull (&mBmHotkeyList, Link); ) {\r
+    Hotkey = BM_HOTKEY_FROM_LINK (Link);\r
+    Match  = (BOOLEAN) (Hotkey->CodeCount == KeyOption.KeyData.Options.InputKeyCount);\r
+\r
+    for (Index = 0; Match && (Index < Hotkey->CodeCount); Index++) {\r
+      ShiftState = Hotkey->KeyData[Index].KeyState.KeyShiftState;\r
+      if (\r
+        (BmBitSet (ShiftState, EFI_RIGHT_SHIFT_PRESSED | EFI_LEFT_SHIFT_PRESSED) != KeyOption.KeyData.Options.ShiftPressed) ||\r
+        (BmBitSet (ShiftState, EFI_RIGHT_CONTROL_PRESSED | EFI_LEFT_CONTROL_PRESSED) != KeyOption.KeyData.Options.ControlPressed) ||\r
+        (BmBitSet (ShiftState, EFI_RIGHT_ALT_PRESSED | EFI_LEFT_ALT_PRESSED) != KeyOption.KeyData.Options.AltPressed) ||\r
+        (BmBitSet (ShiftState, EFI_RIGHT_LOGO_PRESSED | EFI_LEFT_LOGO_PRESSED) != KeyOption.KeyData.Options.LogoPressed) ||\r
+        (BmBitSet (ShiftState, EFI_MENU_KEY_PRESSED) != KeyOption.KeyData.Options.MenuPressed) ||\r
+        (BmBitSet (ShiftState, EFI_SYS_REQ_PRESSED) != KeyOption.KeyData.Options.SysReqPressed) ||\r
+        (CompareMem (&Hotkey->KeyData[Index].Key, &KeyOption.Keys[Index], sizeof (EFI_INPUT_KEY)) != 0)\r
+        ) {\r
+        //\r
+        // Break when any field doesn't match\r
+        //\r
+        Match = FALSE;\r
+        break;\r
+      }\r
+    }\r
+\r
+    if (Match) {\r
+      Link = RemoveEntryList (Link);\r
+      FreePool (Hotkey);\r
+    } else {\r
+      Link = GetNextNode (&mBmHotkeyList, Link);\r
+    }\r
+  }\r
+\r
+  //\r
+  // Delete the key option from the variable\r
+  //\r
+  Status     = EFI_NOT_FOUND;\r
+  KeyOptions = BmGetKeyOptions (&KeyOptionCount);\r
+  for (Index = 0; Index < KeyOptionCount; Index++) {\r
+    if ((KeyOptions[Index].KeyData.PackedValue == KeyOption.KeyData.PackedValue) &&\r
+        (CompareMem (\r
+           KeyOptions[Index].Keys, KeyOption.Keys,\r
+           KeyOption.KeyData.Options.InputKeyCount * sizeof (EFI_INPUT_KEY)) == 0)\r
+       ) {\r
+      UnicodeSPrint (KeyOptionName, sizeof (KeyOptionName), L"Key%04x", KeyOptions[Index].OptionNumber);\r
+      Status = gRT->SetVariable (\r
+                 KeyOptionName,\r
+                 &gEfiGlobalVariableGuid,\r
+                 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
+                 0,\r
+                 NULL\r
+                 );\r
+      //\r
+      // Return the deleted key option in case needed by caller\r
+      //\r
+      if (DeletedOption != NULL) {\r
+        CopyMem (DeletedOption, &KeyOptions[Index], sizeof (EFI_BOOT_MANAGER_KEY_OPTION));\r
+      }\r
+      break;\r
+    }\r
+  }\r
+  BmFreeKeyOptions (KeyOptions, KeyOptionCount);\r
+\r
+  EfiReleaseLock (&mBmHotkeyLock);\r
+\r
+  return Status;\r
+}\r
index 27a8db733e5f555c19e1a77b494464bf77a120cb..630307ed031778dacd78897df4f98e358609672f 100644 (file)
-/** @file
-  Load option library functions which relate with creating and processing load options.
-
-Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
-This program and the accompanying materials
-are licensed and made available under the terms and conditions of the BSD License
-which accompanies this distribution.  The full text of the license may be found at
-http://opensource.org/licenses/bsd-license.php
-
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
-
-**/
-
-#include "InternalBm.h"
-
-GLOBAL_REMOVE_IF_UNREFERENCED
-  CHAR16 *mBmLoadOptionName[] = {
-    L"Driver",
-    L"SysPrep",
-    L"Boot"
-  };
-
-GLOBAL_REMOVE_IF_UNREFERENCED
-  CHAR16 *mBmLoadOptionOrderName[] = {
-    EFI_DRIVER_ORDER_VARIABLE_NAME,
-    EFI_SYS_PREP_ORDER_VARIABLE_NAME,
-    EFI_BOOT_ORDER_VARIABLE_NAME
-  };
-
-/**
-  Call Visitor function for each variable in variable storage.
-
-  @param Visitor  Visitor function.
-  @param Context  The context passed to Visitor function.
-**/
-VOID
-BmForEachVariable (
-  VARIABLE_VISITOR            Visitor,
-  VOID                        *Context
-  )
-{
-  EFI_STATUS                  Status;
-  CHAR16                      *Name;
-  EFI_GUID                    Guid;
-  UINTN                       NameSize;
-  UINTN                       NewNameSize;
-
-  NameSize = sizeof (CHAR16);
-  Name = AllocateZeroPool (NameSize);
-  ASSERT (Name != NULL);
-  while (TRUE) {
-    NewNameSize = NameSize;
-    Status = gRT->GetNextVariableName (&NewNameSize, Name, &Guid);
-    if (Status == EFI_BUFFER_TOO_SMALL) {
-      Name = ReallocatePool (NameSize, NewNameSize, Name);
-      ASSERT (Name != NULL);
-      Status = gRT->GetNextVariableName (&NewNameSize, Name, &Guid);
-      NameSize = NewNameSize;
-    }
-
-    if (Status == EFI_NOT_FOUND) {
-      break;
-    }
-    ASSERT_EFI_ERROR (Status);
-
-    Visitor (Name, &Guid, Context);
-  }
-
-  FreePool (Name);
-}
-
-/**
-  Get the Option Number that wasn't used.
-
-  @param  LoadOptionType      The load option type.
-  @param  FreeOptionNumber    Return the minimal free option number.
-
-  @retval EFI_SUCCESS           The option number is found and will be returned.
-  @retval EFI_OUT_OF_RESOURCES  There is no free option number that can be used.
-  @retval EFI_INVALID_PARAMETER FreeOptionNumber is NULL
-
-**/
-EFI_STATUS
-BmGetFreeOptionNumber (
-  IN  EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType,
-  OUT UINT16                            *FreeOptionNumber
-  )
-{
-  
-  UINTN         OptionNumber;
-  UINTN         Index;
-  UINT16        *OptionOrder;
-  UINTN         OptionOrderSize;
-  UINT16        *BootNext;
-
-  ASSERT (FreeOptionNumber != NULL);
-  ASSERT (LoadOptionType == LoadOptionTypeDriver || 
-          LoadOptionType == LoadOptionTypeBoot ||
-          LoadOptionType == LoadOptionTypeSysPrep);
-
-  GetEfiGlobalVariable2 (mBmLoadOptionOrderName[LoadOptionType], (VOID **) &OptionOrder, &OptionOrderSize);
-  BootNext = NULL;
-  if (LoadOptionType == LoadOptionTypeBoot) {
-    GetEfiGlobalVariable2 (L"BootNext", (VOID**) &BootNext, NULL);
-  }
-
-  for (OptionNumber = 0; 
-       OptionNumber < OptionOrderSize / sizeof (UINT16)
-                    + ((BootNext != NULL) ? 1 : 0); 
-       OptionNumber++
-       ) {
-    //
-    // Search in OptionOrder whether the OptionNumber exists
-    //
-    for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) {
-      if (OptionNumber == OptionOrder[Index]) {
-        break;
-      }
-    }
-
-    //
-    // We didn't find it in the ****Order array and it doesn't equal to BootNext 
-    // Otherwise, OptionNumber equals to OptionOrderSize / sizeof (UINT16) + 1
-    //
-    if ((Index == OptionOrderSize / sizeof (UINT16)) && 
-        ((BootNext == NULL) || (OptionNumber != *BootNext))
-        ) {
-      break;
-    }
-  }
-  if (OptionOrder != NULL) {
-    FreePool (OptionOrder);
-  }
-
-  if (BootNext != NULL) {
-    FreePool (BootNext);
-  }
-
-  //
-  // When BootOrder & BootNext conver all numbers in the range [0 ... 0xffff],
-  //   OptionNumber equals to 0x10000 which is not valid.
-  //
-  ASSERT (OptionNumber <= 0x10000);
-  if (OptionNumber == 0x10000) {
-    return EFI_OUT_OF_RESOURCES;
-  } else {
-    *FreeOptionNumber = (UINT16) OptionNumber;
-    return EFI_SUCCESS;
-  }
-}
-
-/**
-  Create the Boot####, Driver####, SysPrep####, variable from the load option.
-  
-  @param  LoadOption      Pointer to the load option.
-
-  @retval EFI_SUCCESS     The variable was created.
-  @retval Others          Error status returned by RT->SetVariable.
-**/
-EFI_STATUS
-EFIAPI
-EfiBootManagerLoadOptionToVariable (
-  IN CONST EFI_BOOT_MANAGER_LOAD_OPTION     *Option
-  )
-{
-  UINTN                            VariableSize;
-  UINT8                            *Variable;
-  UINT8                            *Ptr;
-  CHAR16                           OptionName[BM_OPTION_NAME_LEN];
-  CHAR16                           *Description;
-  CHAR16                           NullChar;
-  UINT32                           VariableAttributes;
-
-  if ((Option->OptionNumber == LoadOptionNumberUnassigned) ||
-      (Option->FilePath == NULL) ||
-      ((UINT32) Option->OptionType >= LoadOptionTypeMax)
-     ) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  //
-  // Convert NULL description to empty description
-  //
-  NullChar    = L'\0';
-  Description = Option->Description;
-  if (Description == NULL) {
-    Description = &NullChar;
-  }
-
-  /*
-  UINT32                      Attributes;
-  UINT16                      FilePathListLength;
-  CHAR16                      Description[];
-  EFI_DEVICE_PATH_PROTOCOL    FilePathList[];
-  UINT8                       OptionalData[];
-TODO: FilePathList[] IS:
-A packed array of UEFI device paths.  The first element of the 
-array is a device path that describes the device and location of the 
-Image for this load option.  The FilePathList[0] is specific 
-to the device type.  Other device paths may optionally exist in the 
-FilePathList, but their usage is OSV specific. Each element 
-in the array is variable length, and ends at the device path end 
-structure.
-  */
-  VariableSize = sizeof (Option->Attributes)
-               + sizeof (UINT16)
-               + StrSize (Description)
-               + GetDevicePathSize (Option->FilePath)
-               + Option->OptionalDataSize;
-
-  Variable     = AllocatePool (VariableSize);
-  ASSERT (Variable != NULL);
-
-  Ptr             = Variable;
-  WriteUnaligned32 ((UINT32 *) Ptr, Option->Attributes);
-  Ptr            += sizeof (Option->Attributes);
-
-  WriteUnaligned16 ((UINT16 *) Ptr, (UINT16) GetDevicePathSize (Option->FilePath));
-  Ptr            += sizeof (UINT16);
-
-  CopyMem (Ptr, Description, StrSize (Description));
-  Ptr            += StrSize (Description);
-
-  CopyMem (Ptr, Option->FilePath, GetDevicePathSize (Option->FilePath));
-  Ptr            += GetDevicePathSize (Option->FilePath);
-
-  CopyMem (Ptr, Option->OptionalData, Option->OptionalDataSize);
-
-  UnicodeSPrint (OptionName, sizeof (OptionName), L"%s%04x", mBmLoadOptionName[Option->OptionType], Option->OptionNumber);
-
-  VariableAttributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE;
-
-  return gRT->SetVariable (
-                OptionName,
-                &gEfiGlobalVariableGuid,
-                VariableAttributes,
-                VariableSize,
-                Variable
-                );
-}
-
-/**
-  Update order variable .
-
-  @param  OptionOrderName     Order variable name which need to be updated.
-  @param  OptionNumber        Option number for the new option.
-  @param  Position            Position of the new load option to put in the ****Order variable.
-
-  @retval EFI_SUCCESS           The boot#### or driver#### have been successfully registered.
-  @retval EFI_ALREADY_STARTED   The option number of Option is being used already.
-  @retval EFI_STATUS            Return the status of gRT->SetVariable ().
-
-**/
-EFI_STATUS
-BmAddOptionNumberToOrderVariable (
-  IN CHAR16               *OptionOrderName,
-  IN UINT16               OptionNumber,
-  IN UINTN                Position
-  )
-{
-  EFI_STATUS              Status;
-  UINTN                   Index;
-  UINT16                  *OptionOrder;
-  UINT16                  *NewOptionOrder;
-  UINTN                   OptionOrderSize;
-  //
-  // Update the option order variable
-  //
-  GetEfiGlobalVariable2 (OptionOrderName, (VOID **) &OptionOrder, &OptionOrderSize);
-
-  Status = EFI_SUCCESS;
-  for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) {
-    if (OptionOrder[Index] == OptionNumber) {
-      Status = EFI_ALREADY_STARTED;
-      break;
-    }
-  }
-
-  if (!EFI_ERROR (Status)) {
-    Position       = MIN (Position, OptionOrderSize / sizeof (UINT16));
-
-    NewOptionOrder = AllocatePool (OptionOrderSize + sizeof (UINT16));
-    ASSERT (NewOptionOrder != NULL);
-    if (OptionOrderSize != 0) {
-      CopyMem (NewOptionOrder, OptionOrder, Position * sizeof (UINT16));
-      CopyMem (&NewOptionOrder[Position + 1], &OptionOrder[Position], OptionOrderSize - Position * sizeof (UINT16));
-    }
-    NewOptionOrder[Position] = OptionNumber;
-
-    Status = gRT->SetVariable (
-                    OptionOrderName,
-                    &gEfiGlobalVariableGuid,
-                    EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
-                    OptionOrderSize + sizeof (UINT16),
-                    NewOptionOrder
-                    );
-    FreePool (NewOptionOrder);
-  }
-
-  if (OptionOrder != NULL) {
-    FreePool (OptionOrder);
-  }
-
-  return Status;
-}
-
-/**
-  This function will register the new Boot####, Driver#### or SysPrep#### option.
-  After the *#### is updated, the *Order will also be updated.
-
-  @param  Option            Pointer to load option to add.
-  @param  Position          Position of the new load option to put in the ****Order variable.
-
-  @retval EFI_SUCCESS           The *#### have been successfully registered.
-  @retval EFI_INVALID_PARAMETER The option number exceeds 0xFFFF.
-  @retval EFI_ALREADY_STARTED   The option number of Option is being used already.
-                                Note: this API only adds new load option, no replacement support.
-  @retval EFI_OUT_OF_RESOURCES  There is no free option number that can be used when the
-                                option number specified in the Option is LoadOptionNumberUnassigned.
-  @retval EFI_STATUS            Return the status of gRT->SetVariable ().
-
-**/
-EFI_STATUS
-EFIAPI
-EfiBootManagerAddLoadOptionVariable (
-  IN EFI_BOOT_MANAGER_LOAD_OPTION *Option,
-  IN UINTN                        Position
-  )
-{
-  EFI_STATUS                      Status;
-  UINT16                          OptionNumber;
-
-  if (Option == NULL) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  if (Option->OptionType != LoadOptionTypeDriver && 
-      Option->OptionType != LoadOptionTypeSysPrep &&
-      Option->OptionType != LoadOptionTypeBoot
-      ) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  //
-  // Get the free option number if the option number is unassigned
-  //
-  if (Option->OptionNumber == LoadOptionNumberUnassigned) {
-    Status = BmGetFreeOptionNumber (Option->OptionType, &OptionNumber);
-    if (EFI_ERROR (Status)) {
-      return Status;
-    }
-    Option->OptionNumber = OptionNumber;
-  }
-
-  if (Option->OptionNumber >= LoadOptionNumberMax) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  Status = BmAddOptionNumberToOrderVariable (mBmLoadOptionOrderName[Option->OptionType], (UINT16) Option->OptionNumber, Position);
-  if (!EFI_ERROR (Status)) {
-    //
-    // Save the Boot#### or Driver#### variable
-    //
-    Status = EfiBootManagerLoadOptionToVariable (Option);
-    if (EFI_ERROR (Status)) {
-      //
-      // Remove the #### from *Order variable when the Driver####/SysPrep####/Boot#### cannot be saved.
-      //
-      EfiBootManagerDeleteLoadOptionVariable (Option->OptionNumber, Option->OptionType);
-    }
-  }
-
-  return Status;
-}
-
-/**
-  Sort the load option. The DriverOrder or BootOrder will be re-created to 
-  reflect the new order.
-
-  @param OptionType             Load option type
-  @param CompareFunction        The comparator
-**/
-VOID
-EFIAPI
-EfiBootManagerSortLoadOptionVariable (
-  EFI_BOOT_MANAGER_LOAD_OPTION_TYPE        OptionType,
-  SORT_COMPARE                             CompareFunction
-  )
-{
-  EFI_STATUS                     Status;
-  EFI_BOOT_MANAGER_LOAD_OPTION   *LoadOption;
-  UINTN                          LoadOptionCount;
-  UINTN                          Index;
-  UINT16                         *OptionOrder;
-
-  LoadOption = EfiBootManagerGetLoadOptions (&LoadOptionCount, OptionType);
-
-  //
-  // Insertion sort algorithm
-  //
-  PerformQuickSort (
-    LoadOption,
-    LoadOptionCount,
-    sizeof (EFI_BOOT_MANAGER_LOAD_OPTION),
-    CompareFunction
-    );
-
-  //
-  // Create new ****Order variable
-  //
-  OptionOrder = AllocatePool (LoadOptionCount * sizeof (UINT16));
-  ASSERT (OptionOrder != NULL);
-  for (Index = 0; Index < LoadOptionCount; Index++) {
-    OptionOrder[Index] = (UINT16) LoadOption[Index].OptionNumber;
-  }
-
-  Status = gRT->SetVariable (
-                  mBmLoadOptionOrderName[OptionType],
-                  &gEfiGlobalVariableGuid,
-                  EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
-                  LoadOptionCount * sizeof (UINT16),
-                  OptionOrder
-                  );
-  //
-  // Changing the *Order content without increasing its size with current variable implementation shouldn't fail.
-  //
-  ASSERT_EFI_ERROR (Status);
-
-  FreePool (OptionOrder);
-  EfiBootManagerFreeLoadOptions (LoadOption, LoadOptionCount);
-}
-
-/**
-  Initialize a load option.
-
-  @param Option           Pointer to the load option to be initialized.
-  @param OptionNumber     Option number of the load option.
-  @param OptionType       Type of the load option.
-  @param Attributes       Attributes of the load option.
-  @param Description      Description of the load option.
-  @param FilePath         Device path of the load option.
-  @param OptionalData     Optional data of the load option.
-  @param OptionalDataSize Size of the optional data of the load option.
-
-  @retval EFI_SUCCESS           The load option was initialized successfully.
-  @retval EFI_INVALID_PARAMETER Option, Description or FilePath is NULL.
-**/
-EFI_STATUS
-EFIAPI
-EfiBootManagerInitializeLoadOption (
-  IN OUT EFI_BOOT_MANAGER_LOAD_OPTION   *Option,
-  IN  UINTN                             OptionNumber,
-  IN  EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType,
-  IN  UINT32                            Attributes,
-  IN  CHAR16                            *Description,
-  IN  EFI_DEVICE_PATH_PROTOCOL          *FilePath,
-  IN  UINT8                             *OptionalData,   OPTIONAL
-  IN  UINT32                            OptionalDataSize
-  )
-{
-  if ((Option == NULL) || (Description == NULL) || (FilePath == NULL)) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  if (((OptionalData != NULL) && (OptionalDataSize == 0)) ||
-      ((OptionalData == NULL) && (OptionalDataSize != 0))) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  if ((UINT32) OptionType >= LoadOptionTypeMax) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  ZeroMem (Option, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
-  Option->OptionNumber       = OptionNumber;
-  Option->OptionType         = OptionType;
-  Option->Attributes         = Attributes;
-  Option->Description        = AllocateCopyPool (StrSize (Description), Description);
-  Option->FilePath           = DuplicateDevicePath (FilePath);
-  if (OptionalData != NULL) {
-    Option->OptionalData     = AllocateCopyPool (OptionalDataSize, OptionalData);
-    Option->OptionalDataSize = OptionalDataSize;
-  }
-
-  return EFI_SUCCESS;
-}
-
-
-/**
-  Return the index of the load option in the load option array.
-
-  The function consider two load options are equal when the 
-  OptionType, Attributes, Description, FilePath and OptionalData are equal.
-
-  @param Key    Pointer to the load option to be found.
-  @param Array  Pointer to the array of load options to be found.
-  @param Count  Number of entries in the Array.
-
-  @retval -1          Key wasn't found in the Array.
-  @retval 0 ~ Count-1 The index of the Key in the Array.
-**/
-INTN
-BmFindLoadOption (
-  IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Key,
-  IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Array,
-  IN UINTN                              Count
-  )
-{
-  UINTN                             Index;
-
-  for (Index = 0; Index < Count; Index++) {
-    if ((Key->OptionType == Array[Index].OptionType) &&
-        (Key->Attributes == Array[Index].Attributes) &&
-        (StrCmp (Key->Description, Array[Index].Description) == 0) &&
-        (CompareMem (Key->FilePath, Array[Index].FilePath, GetDevicePathSize (Key->FilePath)) == 0) &&
-        (Key->OptionalDataSize == Array[Index].OptionalDataSize) &&
-        (CompareMem (Key->OptionalData, Array[Index].OptionalData, Key->OptionalDataSize) == 0)) {
-      return (INTN) Index;
-    }
-  }
-
-  return -1;
-}
-
-/**
-  Delete the load option.
-
-  @param  OptionNumber        Indicate the option number of load option
-  @param  OptionType          Indicate the type of load option
-
-  @retval EFI_INVALID_PARAMETER OptionType or OptionNumber is invalid.
-  @retval EFI_NOT_FOUND         The load option cannot be found
-  @retval EFI_SUCCESS           The load option was deleted
-  @retval others                Status of RT->SetVariable()
-**/
-EFI_STATUS
-EFIAPI
-EfiBootManagerDeleteLoadOptionVariable (
-  IN UINTN                              OptionNumber,
-  IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE  OptionType
-  )
-{
-  UINT16                            *OptionOrder;
-  UINTN                             OptionOrderSize;
-  EFI_STATUS                        Status;
-  UINTN                             Index;
-
-  if (((UINT32) OptionType >= LoadOptionTypeMax) || (OptionNumber >= LoadOptionNumberMax)) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  Status = EFI_NOT_FOUND;
-
-  if (OptionType == LoadOptionTypeDriver || OptionType == LoadOptionTypeSysPrep || OptionType == LoadOptionTypeBoot) {
-    //
-    // If the associated *Order exists, just remove the reference in *Order.
-    //
-    GetEfiGlobalVariable2 (mBmLoadOptionOrderName[OptionType], &OptionOrder, &OptionOrderSize);
-    for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) {
-      if (OptionOrder[Index] == OptionNumber) {
-        OptionOrderSize -= sizeof (UINT16);
-        CopyMem (&OptionOrder[Index], &OptionOrder[Index + 1], OptionOrderSize - Index * sizeof (UINT16));
-        Status = gRT->SetVariable (
-          mBmLoadOptionOrderName[OptionType],
-          &gEfiGlobalVariableGuid,
-          EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
-          OptionOrderSize,
-          OptionOrder
-          );
-        break;
-      }
-    }
-    if (OptionOrder != NULL) {
-      FreePool (OptionOrder);
-    }
-  }
-
-  return Status;
-}
-
-/**
-  Convert a single character to number.
-  It assumes the input Char is in the scope of L'0' ~ L'9' and L'A' ~ L'F'
-
-  @param    Char   The input char which need to convert to int.
-**/
-UINTN
-BmCharToUint (
-  IN CHAR16                           Char
-  )
-{
-  if ((Char >= L'0') && (Char <= L'9')) {
-    return (UINTN) (Char - L'0');
-  }
-
-  if ((Char >= L'A') && (Char <= L'F')) {
-    return (UINTN) (Char - L'A' + 0xA);
-  }
-
-  ASSERT (FALSE);
-  return (UINTN) -1;
-}
-
-/**
-  Returns the size of a device path in bytes.
-
-  This function returns the size, in bytes, of the device path data structure 
-  specified by DevicePath including the end of device path node. If DevicePath 
-  is NULL, then 0 is returned. If the length of the device path is bigger than
-  MaxSize, also return 0 to indicate this is an invalidate device path.
-
-  @param  DevicePath         A pointer to a device path data structure.
-  @param  MaxSize            Max valid device path size. If big than this size, 
-                             return error.
-  
-  @retval 0                  An invalid device path.
-  @retval Others             The size of a device path in bytes.
-
-**/
-UINTN
-BmGetDevicePathSizeEx (
-  IN CONST EFI_DEVICE_PATH_PROTOCOL  *DevicePath,
-  IN UINTN                           MaxSize
-  )
-{
-  UINTN  Size;
-  UINTN  NodeSize;
-
-  if (DevicePath == NULL) {
-    return 0;
-  }
-
-  //
-  // Search for the end of the device path structure
-  //
-  Size = 0;
-  while (!IsDevicePathEnd (DevicePath)) {
-    NodeSize = DevicePathNodeLength (DevicePath);
-    if (NodeSize == 0) {
-      return 0;
-    }
-    Size += NodeSize;
-    if (Size > MaxSize) {
-      return 0;
-    }
-    DevicePath = NextDevicePathNode (DevicePath);
-  }
-  Size += DevicePathNodeLength (DevicePath);
-  if (Size > MaxSize) {
-    return 0;
-  }
-
-  return Size;
-}
-
-/**
-  Returns the length of a Null-terminated Unicode string. If the length is 
-  bigger than MaxStringLen, return length 0 to indicate that this is an 
-  invalidate string.
-
-  This function returns the number of Unicode characters in the Null-terminated
-  Unicode string specified by String. 
-
-  If String is NULL, then ASSERT().
-  If String is not aligned on a 16-bit boundary, then ASSERT().
-
-  @param  String           A pointer to a Null-terminated Unicode string.
-  @param  MaxStringLen     Max string len in this string.
-
-  @retval 0                An invalid string.
-  @retval Others           The length of String.
-
-**/
-UINTN
-BmStrSizeEx (
-  IN      CONST CHAR16              *String,
-  IN      UINTN                     MaxStringLen
-  )
-{
-  UINTN                             Length;
-
-  ASSERT (String != NULL && MaxStringLen != 0);
-  ASSERT (((UINTN) String & BIT0) == 0);
-
-  for (Length = 0; *String != L'\0' && MaxStringLen != Length; String++, Length+=2);
-
-  if (*String != L'\0' && MaxStringLen == Length) {
-    return 0;
-  }
-
-  return Length + 2;
-}
-
-/**
-  Validate the Boot####, Driver####, SysPrep#### variable (VendorGuid/Name)
-
-  @param  Variable              The variable data.
-  @param  VariableSize          The variable size.
-
-  @retval TRUE                  The variable data is correct.
-  @retval FALSE                 The variable data is corrupted.
-
-**/
-BOOLEAN 
-BmValidateOption (
-  UINT8                     *Variable,
-  UINTN                     VariableSize
-  )
-{
-  UINT16                    FilePathSize;
-  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
-  UINTN                     DescriptionSize;
-
-  if (VariableSize <= sizeof (UINT16) + sizeof (UINT32)) {
-    return FALSE;
-  }
-
-  //
-  // Skip the option attribute
-  //
-  Variable += sizeof (UINT32);
-
-  //
-  // Get the option's device path size
-  //
-  FilePathSize = ReadUnaligned16 ((UINT16 *) Variable);
-  Variable += sizeof (UINT16);
-
-  //
-  // Get the option's description string size
-  //
-  DescriptionSize = BmStrSizeEx ((CHAR16 *) Variable, VariableSize - sizeof (UINT16) - sizeof (UINT32));
-  Variable += DescriptionSize;
-
-  //
-  // Get the option's device path
-  //
-  DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Variable;
-
-  //
-  // Validation boot option variable.
-  //
-  if ((FilePathSize == 0) || (DescriptionSize == 0)) {
-    return FALSE;
-  }
-
-  if (sizeof (UINT32) + sizeof (UINT16) + DescriptionSize + FilePathSize > VariableSize) {
-    return FALSE;
-  }
-
-  return (BOOLEAN) (BmGetDevicePathSizeEx (DevicePath, FilePathSize) != 0);
-}
-
-/**
-  Check whether the VariableName is a valid load option variable name
-  and return the load option type and option number.
-
-  @param VariableName The name of the load option variable.
-  @param OptionType   Return the load option type.
-  @param OptionNumber Return the load option number.
-
-  @retval TRUE  The variable name is valid; The load option type and
-                load option number is returned.
-  @retval FALSE The variable name is NOT valid.
-**/
-BOOLEAN
-BmIsValidLoadOptionVariableName (
-  IN CHAR16                             *VariableName,
-  OUT EFI_BOOT_MANAGER_LOAD_OPTION_TYPE *OptionType,
-  OUT UINT16                            *OptionNumber
-  )
-{
-  UINTN                             VariableNameLen;
-  UINTN                             Index;
-  UINTN                             Uint;
-
-  VariableNameLen = StrLen (VariableName);
-
-  if (VariableNameLen <= 4) {
-    return FALSE;
-  }
-
-  for (Index = 0; Index < sizeof (mBmLoadOptionName) / sizeof (mBmLoadOptionName[0]); Index++) {
-    if ((VariableNameLen - 4 == StrLen (mBmLoadOptionName[Index])) &&
-        (StrnCmp (VariableName, mBmLoadOptionName[Index], VariableNameLen - 4) == 0)
-        ) {
-      break;
-    }
-  }
-
-  if (Index == sizeof (mBmLoadOptionName) / sizeof (mBmLoadOptionName[0])) {
-    return FALSE;
-  }
-
-  *OptionType = (EFI_BOOT_MANAGER_LOAD_OPTION_TYPE) Index;
-  *OptionNumber = 0;
-  for (Index = VariableNameLen - 4; Index < VariableNameLen; Index++) {
-    Uint = BmCharToUint (VariableName[Index]);
-    if (Uint == -1) {
-      break;
-    } else {
-      *OptionNumber = (UINT16) Uint + *OptionNumber * 0x10;
-    }
-  }
-
-  return (BOOLEAN) (Index == VariableNameLen);
-}
-
-/**
-  Build the Boot#### or Driver#### option from the VariableName.
-
-  @param  VariableName          Variable name of the load option
-  @param  VendorGuid            Variable GUID of the load option
-  @param  Option                Return the load option.
-
-  @retval EFI_SUCCESS     Get the option just been created
-  @retval EFI_NOT_FOUND   Failed to get the new option
-
-**/
-EFI_STATUS
-EFIAPI
-EfiBootManagerVariableToLoadOptionEx (
-  IN CHAR16                           *VariableName,
-  IN EFI_GUID                         *VendorGuid,
-  IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *Option  
-  )
-{
-  EFI_STATUS                         Status;
-  UINT32                             Attribute;
-  UINT16                             FilePathSize;
-  UINT8                              *Variable;
-  UINT8                              *VariablePtr;
-  UINTN                              VariableSize;
-  EFI_DEVICE_PATH_PROTOCOL           *FilePath;
-  UINT8                              *OptionalData;
-  UINT32                             OptionalDataSize;
-  CHAR16                             *Description;
-  EFI_BOOT_MANAGER_LOAD_OPTION_TYPE  OptionType;
-  UINT16                             OptionNumber;
-
-  if ((VariableName == NULL) || (Option == NULL)) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  if (!BmIsValidLoadOptionVariableName (VariableName, &OptionType, &OptionNumber)) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  //
-  // Read the variable
-  //
-  GetVariable2 (VariableName, VendorGuid, (VOID **) &Variable, &VariableSize);
-  if (Variable == NULL) {
-    return EFI_NOT_FOUND;
-  }
-
-  //
-  // Validate *#### variable data.
-  //
-  if (!BmValidateOption(Variable, VariableSize)) {
-    FreePool (Variable);
-    return EFI_INVALID_PARAMETER;
-  }
-
-  //
-  // Get the option attribute
-  //
-  VariablePtr = Variable;
-  Attribute = ReadUnaligned32 ((UINT32 *) VariablePtr);
-  VariablePtr += sizeof (UINT32);
-
-  //
-  // Get the option's device path size
-  //
-  FilePathSize = ReadUnaligned16 ((UINT16 *) VariablePtr);
-  VariablePtr += sizeof (UINT16);
-
-  //
-  // Get the option's description string
-  //
-  Description = (CHAR16 *) VariablePtr;
-
-  //
-  // Get the option's description string size
-  //
-  VariablePtr += StrSize ((CHAR16 *) VariablePtr);
-
-  //
-  // Get the option's device path
-  //
-  FilePath = (EFI_DEVICE_PATH_PROTOCOL *) VariablePtr;
-  VariablePtr += FilePathSize;
-
-  OptionalDataSize = (UINT32) (VariableSize - (UINTN) (VariablePtr - Variable));
-  if (OptionalDataSize == 0) {
-    OptionalData = NULL;
-  } else {
-    OptionalData = VariablePtr;
-  }
-
-  Status = EfiBootManagerInitializeLoadOption (
-             Option,
-             OptionNumber,
-             OptionType,
-             Attribute,
-             Description,
-             FilePath,
-             OptionalData,
-             OptionalDataSize
-             );
-  ASSERT_EFI_ERROR (Status);
-
-  CopyGuid (&Option->VendorGuid, VendorGuid);
-
-  FreePool (Variable);
-  return Status;
-}
-
-/**
-Build the Boot#### or Driver#### option from the VariableName.
-
-@param  VariableName          EFI Variable name indicate if it is Boot#### or Driver####
-@param  Option                Return the Boot#### or Driver#### option.
-
-@retval EFI_SUCCESS     Get the option just been created
-@retval EFI_NOT_FOUND   Failed to get the new option
-**/
-EFI_STATUS
-EFIAPI
-EfiBootManagerVariableToLoadOption (
-  IN  CHAR16                          *VariableName,
-  IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *Option
-  )
-{
-  return EfiBootManagerVariableToLoadOptionEx (VariableName, &gEfiGlobalVariableGuid, Option);
-}
-
-/**
-  Returns an array of load options based on the EFI variable
-  L"BootOrder"/L"DriverOrder" and the L"Boot####"/L"Driver####" variables impled by it.
-  #### is the hex value of the UINT16 in each BootOrder/DriverOrder entry. 
-
-  @param  LoadOptionCount   Returns number of entries in the array.
-  @param  LoadOptionType    The type of the load option.
-
-  @retval NULL  No load options exist.
-  @retval !NULL Array of load option entries.
-
-**/
-EFI_BOOT_MANAGER_LOAD_OPTION *
-EFIAPI
-EfiBootManagerGetLoadOptions (
-  OUT UINTN                             *OptionCount,
-  IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE  LoadOptionType
-  )
-{
-  EFI_STATUS                   Status;
-  UINT16                       *OptionOrder;
-  UINTN                        OptionOrderSize;
-  UINTN                        Index;
-  UINTN                        OptionIndex;
-  EFI_BOOT_MANAGER_LOAD_OPTION *Options;
-  CHAR16                       OptionName[BM_OPTION_NAME_LEN];
-  UINT16                       OptionNumber;
-
-  *OptionCount = 0;
-
-  if (LoadOptionType == LoadOptionTypeDriver || LoadOptionType == LoadOptionTypeSysPrep || LoadOptionType == LoadOptionTypeBoot) {
-    //
-    // Read the BootOrder, or DriverOrder variable.
-    //
-    GetEfiGlobalVariable2 (mBmLoadOptionOrderName[LoadOptionType], (VOID **) &OptionOrder, &OptionOrderSize);
-    if (OptionOrder == NULL) {
-      return NULL;
-    }
-
-    *OptionCount = OptionOrderSize / sizeof (UINT16);
-
-    Options = AllocatePool (*OptionCount * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
-    ASSERT (Options != NULL);
-
-    OptionIndex = 0;
-    for (Index = 0; Index < *OptionCount; Index++) {
-      OptionNumber = OptionOrder[Index];
-      UnicodeSPrint (OptionName, sizeof (OptionName), L"%s%04x", mBmLoadOptionName[LoadOptionType], OptionNumber);
-
-      Status = EfiBootManagerVariableToLoadOption (OptionName, &Options[OptionIndex]);
-      if (EFI_ERROR (Status)) {
-        DEBUG ((EFI_D_INFO, "[Bds] %s doesn't exist - Update ****Order variable to remove the reference!!", OptionName));
-        EfiBootManagerDeleteLoadOptionVariable (OptionNumber, LoadOptionType);
-      } else {
-        ASSERT (Options[OptionIndex].OptionNumber == OptionNumber);
-        OptionIndex++;
-      }
-    }
-
-    if (OptionOrder != NULL) {
-      FreePool (OptionOrder);
-    }
-
-    if (OptionIndex < *OptionCount) {
-      Options = ReallocatePool (*OptionCount * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION), OptionIndex * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION), Options);
-      ASSERT (Options != NULL);
-      *OptionCount = OptionIndex;
-    }
-
-  } else {
-    return NULL;
-  }
-
-  return Options;
-}
-
-/**
-  Free an EFI_BOOT_MANGER_LOAD_OPTION entry that was allocate by the library.
-
-  @param  LoadOption   Pointer to boot option to Free.
-
-  @return EFI_SUCCESS   BootOption was freed 
-  @return EFI_NOT_FOUND BootOption == NULL 
-
-**/
-EFI_STATUS
-EFIAPI
-EfiBootManagerFreeLoadOption (
-  IN  EFI_BOOT_MANAGER_LOAD_OPTION  *LoadOption
-  )
-{
-  if (LoadOption == NULL) {
-    return EFI_NOT_FOUND;
-  }
-
-  if (LoadOption->Description != NULL) {
-    FreePool (LoadOption->Description);
-  }
-  if (LoadOption->FilePath != NULL) {
-    FreePool (LoadOption->FilePath);
-  }
-  if (LoadOption->OptionalData != NULL) {
-    FreePool (LoadOption->OptionalData);
-  }
-
-  return EFI_SUCCESS;
-}
-
-/**
-  Free an EFI_BOOT_MANGER_LOAD_OPTION array that was allocated by 
-  EfiBootManagerGetLoadOptions().
-
-  @param  Option       Pointer to boot option array to free.
-  @param  OptionCount  Number of array entries in BootOption
-
-  @return EFI_SUCCESS   BootOption was freed 
-  @return EFI_NOT_FOUND BootOption == NULL 
-
-**/
-EFI_STATUS
-EFIAPI
-EfiBootManagerFreeLoadOptions (
-  IN  EFI_BOOT_MANAGER_LOAD_OPTION  *Option,
-  IN  UINTN                         OptionCount
-  )
-{
-  UINTN   Index;
-
-  if (Option == NULL) {
-    return EFI_NOT_FOUND;
-  }
-
-  for (Index = 0;Index < OptionCount; Index++) {
-    EfiBootManagerFreeLoadOption (&Option[Index]);
-  }
-
-  FreePool (Option);
-
-  return EFI_SUCCESS;
-}
-
-/**
-  Return whether the PE header of the load option is valid or not.
-
-  @param[in] Type       The load option type.
-  @param[in] FileBuffer The PE file buffer of the load option.
-  @param[in] FileSize   The size of the load option file.
-
-  @retval TRUE  The PE header of the load option is valid.
-  @retval FALSE The PE header of the load option is not valid.
-**/
-BOOLEAN
-BmIsLoadOptionPeHeaderValid (
-  IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE Type,
-  IN VOID                              *FileBuffer,
-  IN UINTN                             FileSize
-  )
-{
-  EFI_IMAGE_DOS_HEADER              *DosHeader;
-  EFI_IMAGE_OPTIONAL_HEADER_UNION   *PeHeader;
-  EFI_IMAGE_OPTIONAL_HEADER32       *OptionalHeader;
-  UINT16                            Subsystem;
-
-  if (FileBuffer == NULL || FileSize == 0) {
-    return FALSE;
-  }
-
-  //
-  // Read dos header
-  //
-  DosHeader = (EFI_IMAGE_DOS_HEADER *) FileBuffer;
-  if (FileSize >= sizeof (EFI_IMAGE_DOS_HEADER) &&
-      FileSize > DosHeader->e_lfanew && DosHeader->e_magic == EFI_IMAGE_DOS_SIGNATURE
-      ) {
-    //
-    // Read and check PE signature
-    //
-    PeHeader = (EFI_IMAGE_OPTIONAL_HEADER_UNION *) ((UINT8 *) FileBuffer + DosHeader->e_lfanew);
-    if (FileSize >= DosHeader->e_lfanew + sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION) &&
-        PeHeader->Pe32.Signature == EFI_IMAGE_NT_SIGNATURE
-        ) {
-      //
-      // Check PE32 or PE32+ magic, and machine type
-      //
-      OptionalHeader = (EFI_IMAGE_OPTIONAL_HEADER32 *) &PeHeader->Pe32.OptionalHeader;
-      if ((OptionalHeader->Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC || 
-           OptionalHeader->Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) &&
-          EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeHeader->Pe32.FileHeader.Machine)
-          ) {
-        //
-        // Check the Subsystem:
-        //   Driver#### must be of type BootServiceDriver or RuntimeDriver
-        //   SysPrep####, Boot####, OsRecovery####, PlatformRecovery#### must be of type Application
-        //
-        Subsystem = OptionalHeader->Subsystem;
-        if ((Type == LoadOptionTypeDriver && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) ||
-            (Type == LoadOptionTypeDriver && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) ||
-            (Type == LoadOptionTypeSysPrep && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) ||
-            (Type == LoadOptionTypeBoot && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION)
-            ) {
-          return TRUE;
-        }
-      }
-    }
-  }
-
-  return FALSE;
-}
-
-/**
-  Process (load and execute) the load option.
-
-  @param LoadOption  Pointer to the load option.
-
-  @retval EFI_INVALID_PARAMETER  The load option type is invalid, 
-                                 or the load option file path doesn't point to a valid file.
-  @retval EFI_UNSUPPORTED        The load option type is of LoadOptionTypeBoot.
-  @retval EFI_SUCCESS            The load option is inactive, or successfully loaded and executed.
-**/
-EFI_STATUS
-EFIAPI
-EfiBootManagerProcessLoadOption (
-  IN EFI_BOOT_MANAGER_LOAD_OPTION       *LoadOption
-  )
-{
-  EFI_STATUS                        Status;
-  EFI_DEVICE_PATH_PROTOCOL          *FilePath;
-  EFI_HANDLE                        ImageHandle;
-  EFI_LOADED_IMAGE_PROTOCOL         *ImageInfo;
-  VOID                              *FileBuffer;
-  UINTN                             FileSize;
-
-  if ((UINT32) LoadOption->OptionType >= LoadOptionTypeMax) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  if (LoadOption->OptionType == LoadOptionTypeBoot) {
-    return EFI_UNSUPPORTED;
-  }
-
-  //
-  // If a load option is not marked as LOAD_OPTION_ACTIVE,
-  // the boot manager will not automatically load the option.
-  //
-  if ((LoadOption->Attributes & LOAD_OPTION_ACTIVE) == 0) {
-    return EFI_SUCCESS;
-  }
-
-  Status = EFI_INVALID_PARAMETER;
-
-  //
-  // Load and start the load option.
-  //
-  DEBUG ((
-    DEBUG_INFO | DEBUG_LOAD, "Process Load Option (%s%04x) ...\n",
-    mBmLoadOptionName[LoadOption->OptionType], LoadOption->OptionNumber
-    ));
-  ImageHandle = NULL;
-  FileBuffer = BmGetLoadOptionBuffer (LoadOption->FilePath, &FilePath, &FileSize);
-  DEBUG_CODE (
-    if (FileBuffer != NULL && CompareMem (LoadOption->FilePath, FilePath, GetDevicePathSize (FilePath)) != 0) {
-      DEBUG ((EFI_D_INFO, "[Bds] DevicePath expand: "));
-      BmPrintDp (LoadOption->FilePath);
-      DEBUG ((EFI_D_INFO, " -> "));
-      BmPrintDp (FilePath);
-      DEBUG ((EFI_D_INFO, "\n"));
-    }
-  );
-  if (BmIsLoadOptionPeHeaderValid (LoadOption->OptionType, FileBuffer, FileSize)) {
-    Status = gBS->LoadImage (
-                    FALSE,
-                    gImageHandle,
-                    FilePath,
-                    FileBuffer,
-                    FileSize,
-                    &ImageHandle
-                    );
-  }
-  if (FilePath != NULL) {
-    FreePool (FilePath);
-  }
-  if (FileBuffer != NULL) {
-    FreePool (FileBuffer);
-  }
-
-  if (!EFI_ERROR (Status)) {
-    Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);
-    ASSERT_EFI_ERROR (Status);
-
-    ImageInfo->LoadOptionsSize = LoadOption->OptionalDataSize;
-    ImageInfo->LoadOptions = LoadOption->OptionalData;
-    //
-    // Before calling the image, enable the Watchdog Timer for the 5-minute period
-    //
-    gBS->SetWatchdogTimer (5 * 60, 0, 0, NULL);
-
-    LoadOption->Status = gBS->StartImage (ImageHandle, &LoadOption->ExitDataSize, &LoadOption->ExitData);
-    DEBUG ((
-      DEBUG_INFO | DEBUG_LOAD, "Load Option (%s%04x) Return Status = %r\n",
-      mBmLoadOptionName[LoadOption->OptionType], LoadOption->OptionNumber, LoadOption->Status
-      ));
-
-    //
-    // Clear the Watchdog Timer after the image returns
-    //
-    gBS->SetWatchdogTimer (0, 0, 0, NULL);
-  }
-
-  return Status;
-}
+/** @file\r
+  Load option library functions which relate with creating and processing load options.\r
+\r
+Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "InternalBm.h"\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED\r
+  CHAR16 *mBmLoadOptionName[] = {\r
+    L"Driver",\r
+    L"SysPrep",\r
+    L"Boot"\r
+  };\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED\r
+  CHAR16 *mBmLoadOptionOrderName[] = {\r
+    EFI_DRIVER_ORDER_VARIABLE_NAME,\r
+    EFI_SYS_PREP_ORDER_VARIABLE_NAME,\r
+    EFI_BOOT_ORDER_VARIABLE_NAME\r
+  };\r
+\r
+/**\r
+  Call Visitor function for each variable in variable storage.\r
+\r
+  @param Visitor  Visitor function.\r
+  @param Context  The context passed to Visitor function.\r
+**/\r
+VOID\r
+BmForEachVariable (\r
+  VARIABLE_VISITOR            Visitor,\r
+  VOID                        *Context\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  CHAR16                      *Name;\r
+  EFI_GUID                    Guid;\r
+  UINTN                       NameSize;\r
+  UINTN                       NewNameSize;\r
+\r
+  NameSize = sizeof (CHAR16);\r
+  Name = AllocateZeroPool (NameSize);\r
+  ASSERT (Name != NULL);\r
+  while (TRUE) {\r
+    NewNameSize = NameSize;\r
+    Status = gRT->GetNextVariableName (&NewNameSize, Name, &Guid);\r
+    if (Status == EFI_BUFFER_TOO_SMALL) {\r
+      Name = ReallocatePool (NameSize, NewNameSize, Name);\r
+      ASSERT (Name != NULL);\r
+      Status = gRT->GetNextVariableName (&NewNameSize, Name, &Guid);\r
+      NameSize = NewNameSize;\r
+    }\r
+\r
+    if (Status == EFI_NOT_FOUND) {\r
+      break;\r
+    }\r
+    ASSERT_EFI_ERROR (Status);\r
+\r
+    Visitor (Name, &Guid, Context);\r
+  }\r
+\r
+  FreePool (Name);\r
+}\r
+\r
+/**\r
+  Get the Option Number that wasn't used.\r
+\r
+  @param  LoadOptionType      The load option type.\r
+  @param  FreeOptionNumber    Return the minimal free option number.\r
+\r
+  @retval EFI_SUCCESS           The option number is found and will be returned.\r
+  @retval EFI_OUT_OF_RESOURCES  There is no free option number that can be used.\r
+  @retval EFI_INVALID_PARAMETER FreeOptionNumber is NULL\r
+\r
+**/\r
+EFI_STATUS\r
+BmGetFreeOptionNumber (\r
+  IN  EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType,\r
+  OUT UINT16                            *FreeOptionNumber\r
+  )\r
+{\r
+  \r
+  UINTN         OptionNumber;\r
+  UINTN         Index;\r
+  UINT16        *OptionOrder;\r
+  UINTN         OptionOrderSize;\r
+  UINT16        *BootNext;\r
+\r
+  ASSERT (FreeOptionNumber != NULL);\r
+  ASSERT (LoadOptionType == LoadOptionTypeDriver || \r
+          LoadOptionType == LoadOptionTypeBoot ||\r
+          LoadOptionType == LoadOptionTypeSysPrep);\r
+\r
+  GetEfiGlobalVariable2 (mBmLoadOptionOrderName[LoadOptionType], (VOID **) &OptionOrder, &OptionOrderSize);\r
+  BootNext = NULL;\r
+  if (LoadOptionType == LoadOptionTypeBoot) {\r
+    GetEfiGlobalVariable2 (L"BootNext", (VOID**) &BootNext, NULL);\r
+  }\r
+\r
+  for (OptionNumber = 0; \r
+       OptionNumber < OptionOrderSize / sizeof (UINT16)\r
+                    + ((BootNext != NULL) ? 1 : 0); \r
+       OptionNumber++\r
+       ) {\r
+    //\r
+    // Search in OptionOrder whether the OptionNumber exists\r
+    //\r
+    for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) {\r
+      if (OptionNumber == OptionOrder[Index]) {\r
+        break;\r
+      }\r
+    }\r
+\r
+    //\r
+    // We didn't find it in the ****Order array and it doesn't equal to BootNext \r
+    // Otherwise, OptionNumber equals to OptionOrderSize / sizeof (UINT16) + 1\r
+    //\r
+    if ((Index == OptionOrderSize / sizeof (UINT16)) && \r
+        ((BootNext == NULL) || (OptionNumber != *BootNext))\r
+        ) {\r
+      break;\r
+    }\r
+  }\r
+  if (OptionOrder != NULL) {\r
+    FreePool (OptionOrder);\r
+  }\r
+\r
+  if (BootNext != NULL) {\r
+    FreePool (BootNext);\r
+  }\r
+\r
+  //\r
+  // When BootOrder & BootNext conver all numbers in the range [0 ... 0xffff],\r
+  //   OptionNumber equals to 0x10000 which is not valid.\r
+  //\r
+  ASSERT (OptionNumber <= 0x10000);\r
+  if (OptionNumber == 0x10000) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  } else {\r
+    *FreeOptionNumber = (UINT16) OptionNumber;\r
+    return EFI_SUCCESS;\r
+  }\r
+}\r
+\r
+/**\r
+  Create the Boot####, Driver####, SysPrep####, variable from the load option.\r
+  \r
+  @param  LoadOption      Pointer to the load option.\r
+\r
+  @retval EFI_SUCCESS     The variable was created.\r
+  @retval Others          Error status returned by RT->SetVariable.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiBootManagerLoadOptionToVariable (\r
+  IN CONST EFI_BOOT_MANAGER_LOAD_OPTION     *Option\r
+  )\r
+{\r
+  UINTN                            VariableSize;\r
+  UINT8                            *Variable;\r
+  UINT8                            *Ptr;\r
+  CHAR16                           OptionName[BM_OPTION_NAME_LEN];\r
+  CHAR16                           *Description;\r
+  CHAR16                           NullChar;\r
+  UINT32                           VariableAttributes;\r
+\r
+  if ((Option->OptionNumber == LoadOptionNumberUnassigned) ||\r
+      (Option->FilePath == NULL) ||\r
+      ((UINT32) Option->OptionType >= LoadOptionTypeMax)\r
+     ) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Convert NULL description to empty description\r
+  //\r
+  NullChar    = L'\0';\r
+  Description = Option->Description;\r
+  if (Description == NULL) {\r
+    Description = &NullChar;\r
+  }\r
+\r
+  /*\r
+  UINT32                      Attributes;\r
+  UINT16                      FilePathListLength;\r
+  CHAR16                      Description[];\r
+  EFI_DEVICE_PATH_PROTOCOL    FilePathList[];\r
+  UINT8                       OptionalData[];\r
+TODO: FilePathList[] IS:\r
+A packed array of UEFI device paths.  The first element of the \r
+array is a device path that describes the device and location of the \r
+Image for this load option.  The FilePathList[0] is specific \r
+to the device type.  Other device paths may optionally exist in the \r
+FilePathList, but their usage is OSV specific. Each element \r
+in the array is variable length, and ends at the device path end \r
+structure.\r
+  */\r
+  VariableSize = sizeof (Option->Attributes)\r
+               + sizeof (UINT16)\r
+               + StrSize (Description)\r
+               + GetDevicePathSize (Option->FilePath)\r
+               + Option->OptionalDataSize;\r
+\r
+  Variable     = AllocatePool (VariableSize);\r
+  ASSERT (Variable != NULL);\r
+\r
+  Ptr             = Variable;\r
+  WriteUnaligned32 ((UINT32 *) Ptr, Option->Attributes);\r
+  Ptr            += sizeof (Option->Attributes);\r
+\r
+  WriteUnaligned16 ((UINT16 *) Ptr, (UINT16) GetDevicePathSize (Option->FilePath));\r
+  Ptr            += sizeof (UINT16);\r
+\r
+  CopyMem (Ptr, Description, StrSize (Description));\r
+  Ptr            += StrSize (Description);\r
+\r
+  CopyMem (Ptr, Option->FilePath, GetDevicePathSize (Option->FilePath));\r
+  Ptr            += GetDevicePathSize (Option->FilePath);\r
+\r
+  CopyMem (Ptr, Option->OptionalData, Option->OptionalDataSize);\r
+\r
+  UnicodeSPrint (OptionName, sizeof (OptionName), L"%s%04x", mBmLoadOptionName[Option->OptionType], Option->OptionNumber);\r
+\r
+  VariableAttributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE;\r
+\r
+  return gRT->SetVariable (\r
+                OptionName,\r
+                &gEfiGlobalVariableGuid,\r
+                VariableAttributes,\r
+                VariableSize,\r
+                Variable\r
+                );\r
+}\r
+\r
+/**\r
+  Update order variable .\r
+\r
+  @param  OptionOrderName     Order variable name which need to be updated.\r
+  @param  OptionNumber        Option number for the new option.\r
+  @param  Position            Position of the new load option to put in the ****Order variable.\r
+\r
+  @retval EFI_SUCCESS           The boot#### or driver#### have been successfully registered.\r
+  @retval EFI_ALREADY_STARTED   The option number of Option is being used already.\r
+  @retval EFI_STATUS            Return the status of gRT->SetVariable ().\r
+\r
+**/\r
+EFI_STATUS\r
+BmAddOptionNumberToOrderVariable (\r
+  IN CHAR16               *OptionOrderName,\r
+  IN UINT16               OptionNumber,\r
+  IN UINTN                Position\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  UINTN                   Index;\r
+  UINT16                  *OptionOrder;\r
+  UINT16                  *NewOptionOrder;\r
+  UINTN                   OptionOrderSize;\r
+  //\r
+  // Update the option order variable\r
+  //\r
+  GetEfiGlobalVariable2 (OptionOrderName, (VOID **) &OptionOrder, &OptionOrderSize);\r
+\r
+  Status = EFI_SUCCESS;\r
+  for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) {\r
+    if (OptionOrder[Index] == OptionNumber) {\r
+      Status = EFI_ALREADY_STARTED;\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    Position       = MIN (Position, OptionOrderSize / sizeof (UINT16));\r
+\r
+    NewOptionOrder = AllocatePool (OptionOrderSize + sizeof (UINT16));\r
+    ASSERT (NewOptionOrder != NULL);\r
+    if (OptionOrderSize != 0) {\r
+      CopyMem (NewOptionOrder, OptionOrder, Position * sizeof (UINT16));\r
+      CopyMem (&NewOptionOrder[Position + 1], &OptionOrder[Position], OptionOrderSize - Position * sizeof (UINT16));\r
+    }\r
+    NewOptionOrder[Position] = OptionNumber;\r
+\r
+    Status = gRT->SetVariable (\r
+                    OptionOrderName,\r
+                    &gEfiGlobalVariableGuid,\r
+                    EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
+                    OptionOrderSize + sizeof (UINT16),\r
+                    NewOptionOrder\r
+                    );\r
+    FreePool (NewOptionOrder);\r
+  }\r
+\r
+  if (OptionOrder != NULL) {\r
+    FreePool (OptionOrder);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  This function will register the new Boot####, Driver#### or SysPrep#### option.\r
+  After the *#### is updated, the *Order will also be updated.\r
+\r
+  @param  Option            Pointer to load option to add.\r
+  @param  Position          Position of the new load option to put in the ****Order variable.\r
+\r
+  @retval EFI_SUCCESS           The *#### have been successfully registered.\r
+  @retval EFI_INVALID_PARAMETER The option number exceeds 0xFFFF.\r
+  @retval EFI_ALREADY_STARTED   The option number of Option is being used already.\r
+                                Note: this API only adds new load option, no replacement support.\r
+  @retval EFI_OUT_OF_RESOURCES  There is no free option number that can be used when the\r
+                                option number specified in the Option is LoadOptionNumberUnassigned.\r
+  @retval EFI_STATUS            Return the status of gRT->SetVariable ().\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiBootManagerAddLoadOptionVariable (\r
+  IN EFI_BOOT_MANAGER_LOAD_OPTION *Option,\r
+  IN UINTN                        Position\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  UINT16                          OptionNumber;\r
+\r
+  if (Option == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (Option->OptionType != LoadOptionTypeDriver && \r
+      Option->OptionType != LoadOptionTypeSysPrep &&\r
+      Option->OptionType != LoadOptionTypeBoot\r
+      ) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Get the free option number if the option number is unassigned\r
+  //\r
+  if (Option->OptionNumber == LoadOptionNumberUnassigned) {\r
+    Status = BmGetFreeOptionNumber (Option->OptionType, &OptionNumber);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    Option->OptionNumber = OptionNumber;\r
+  }\r
+\r
+  if (Option->OptionNumber >= LoadOptionNumberMax) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status = BmAddOptionNumberToOrderVariable (mBmLoadOptionOrderName[Option->OptionType], (UINT16) Option->OptionNumber, Position);\r
+  if (!EFI_ERROR (Status)) {\r
+    //\r
+    // Save the Boot#### or Driver#### variable\r
+    //\r
+    Status = EfiBootManagerLoadOptionToVariable (Option);\r
+    if (EFI_ERROR (Status)) {\r
+      //\r
+      // Remove the #### from *Order variable when the Driver####/SysPrep####/Boot#### cannot be saved.\r
+      //\r
+      EfiBootManagerDeleteLoadOptionVariable (Option->OptionNumber, Option->OptionType);\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Sort the load option. The DriverOrder or BootOrder will be re-created to \r
+  reflect the new order.\r
+\r
+  @param OptionType             Load option type\r
+  @param CompareFunction        The comparator\r
+**/\r
+VOID\r
+EFIAPI\r
+EfiBootManagerSortLoadOptionVariable (\r
+  EFI_BOOT_MANAGER_LOAD_OPTION_TYPE        OptionType,\r
+  SORT_COMPARE                             CompareFunction\r
+  )\r
+{\r
+  EFI_STATUS                     Status;\r
+  EFI_BOOT_MANAGER_LOAD_OPTION   *LoadOption;\r
+  UINTN                          LoadOptionCount;\r
+  UINTN                          Index;\r
+  UINT16                         *OptionOrder;\r
+\r
+  LoadOption = EfiBootManagerGetLoadOptions (&LoadOptionCount, OptionType);\r
+\r
+  //\r
+  // Insertion sort algorithm\r
+  //\r
+  PerformQuickSort (\r
+    LoadOption,\r
+    LoadOptionCount,\r
+    sizeof (EFI_BOOT_MANAGER_LOAD_OPTION),\r
+    CompareFunction\r
+    );\r
+\r
+  //\r
+  // Create new ****Order variable\r
+  //\r
+  OptionOrder = AllocatePool (LoadOptionCount * sizeof (UINT16));\r
+  ASSERT (OptionOrder != NULL);\r
+  for (Index = 0; Index < LoadOptionCount; Index++) {\r
+    OptionOrder[Index] = (UINT16) LoadOption[Index].OptionNumber;\r
+  }\r
+\r
+  Status = gRT->SetVariable (\r
+                  mBmLoadOptionOrderName[OptionType],\r
+                  &gEfiGlobalVariableGuid,\r
+                  EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
+                  LoadOptionCount * sizeof (UINT16),\r
+                  OptionOrder\r
+                  );\r
+  //\r
+  // Changing the *Order content without increasing its size with current variable implementation shouldn't fail.\r
+  //\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  FreePool (OptionOrder);\r
+  EfiBootManagerFreeLoadOptions (LoadOption, LoadOptionCount);\r
+}\r
+\r
+/**\r
+  Initialize a load option.\r
+\r
+  @param Option           Pointer to the load option to be initialized.\r
+  @param OptionNumber     Option number of the load option.\r
+  @param OptionType       Type of the load option.\r
+  @param Attributes       Attributes of the load option.\r
+  @param Description      Description of the load option.\r
+  @param FilePath         Device path of the load option.\r
+  @param OptionalData     Optional data of the load option.\r
+  @param OptionalDataSize Size of the optional data of the load option.\r
+\r
+  @retval EFI_SUCCESS           The load option was initialized successfully.\r
+  @retval EFI_INVALID_PARAMETER Option, Description or FilePath is NULL.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiBootManagerInitializeLoadOption (\r
+  IN OUT EFI_BOOT_MANAGER_LOAD_OPTION   *Option,\r
+  IN  UINTN                             OptionNumber,\r
+  IN  EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType,\r
+  IN  UINT32                            Attributes,\r
+  IN  CHAR16                            *Description,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL          *FilePath,\r
+  IN  UINT8                             *OptionalData,   OPTIONAL\r
+  IN  UINT32                            OptionalDataSize\r
+  )\r
+{\r
+  if ((Option == NULL) || (Description == NULL) || (FilePath == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (((OptionalData != NULL) && (OptionalDataSize == 0)) ||\r
+      ((OptionalData == NULL) && (OptionalDataSize != 0))) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((UINT32) OptionType >= LoadOptionTypeMax) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  ZeroMem (Option, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));\r
+  Option->OptionNumber       = OptionNumber;\r
+  Option->OptionType         = OptionType;\r
+  Option->Attributes         = Attributes;\r
+  Option->Description        = AllocateCopyPool (StrSize (Description), Description);\r
+  Option->FilePath           = DuplicateDevicePath (FilePath);\r
+  if (OptionalData != NULL) {\r
+    Option->OptionalData     = AllocateCopyPool (OptionalDataSize, OptionalData);\r
+    Option->OptionalDataSize = OptionalDataSize;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Return the index of the load option in the load option array.\r
+\r
+  The function consider two load options are equal when the \r
+  OptionType, Attributes, Description, FilePath and OptionalData are equal.\r
+\r
+  @param Key    Pointer to the load option to be found.\r
+  @param Array  Pointer to the array of load options to be found.\r
+  @param Count  Number of entries in the Array.\r
+\r
+  @retval -1          Key wasn't found in the Array.\r
+  @retval 0 ~ Count-1 The index of the Key in the Array.\r
+**/\r
+INTN\r
+BmFindLoadOption (\r
+  IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Key,\r
+  IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Array,\r
+  IN UINTN                              Count\r
+  )\r
+{\r
+  UINTN                             Index;\r
+\r
+  for (Index = 0; Index < Count; Index++) {\r
+    if ((Key->OptionType == Array[Index].OptionType) &&\r
+        (Key->Attributes == Array[Index].Attributes) &&\r
+        (StrCmp (Key->Description, Array[Index].Description) == 0) &&\r
+        (CompareMem (Key->FilePath, Array[Index].FilePath, GetDevicePathSize (Key->FilePath)) == 0) &&\r
+        (Key->OptionalDataSize == Array[Index].OptionalDataSize) &&\r
+        (CompareMem (Key->OptionalData, Array[Index].OptionalData, Key->OptionalDataSize) == 0)) {\r
+      return (INTN) Index;\r
+    }\r
+  }\r
+\r
+  return -1;\r
+}\r
+\r
+/**\r
+  Delete the load option.\r
+\r
+  @param  OptionNumber        Indicate the option number of load option\r
+  @param  OptionType          Indicate the type of load option\r
+\r
+  @retval EFI_INVALID_PARAMETER OptionType or OptionNumber is invalid.\r
+  @retval EFI_NOT_FOUND         The load option cannot be found\r
+  @retval EFI_SUCCESS           The load option was deleted\r
+  @retval others                Status of RT->SetVariable()\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiBootManagerDeleteLoadOptionVariable (\r
+  IN UINTN                              OptionNumber,\r
+  IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE  OptionType\r
+  )\r
+{\r
+  UINT16                            *OptionOrder;\r
+  UINTN                             OptionOrderSize;\r
+  EFI_STATUS                        Status;\r
+  UINTN                             Index;\r
+\r
+  if (((UINT32) OptionType >= LoadOptionTypeMax) || (OptionNumber >= LoadOptionNumberMax)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status = EFI_NOT_FOUND;\r
+\r
+  if (OptionType == LoadOptionTypeDriver || OptionType == LoadOptionTypeSysPrep || OptionType == LoadOptionTypeBoot) {\r
+    //\r
+    // If the associated *Order exists, just remove the reference in *Order.\r
+    //\r
+    GetEfiGlobalVariable2 (mBmLoadOptionOrderName[OptionType], &OptionOrder, &OptionOrderSize);\r
+    for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) {\r
+      if (OptionOrder[Index] == OptionNumber) {\r
+        OptionOrderSize -= sizeof (UINT16);\r
+        CopyMem (&OptionOrder[Index], &OptionOrder[Index + 1], OptionOrderSize - Index * sizeof (UINT16));\r
+        Status = gRT->SetVariable (\r
+          mBmLoadOptionOrderName[OptionType],\r
+          &gEfiGlobalVariableGuid,\r
+          EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
+          OptionOrderSize,\r
+          OptionOrder\r
+          );\r
+        break;\r
+      }\r
+    }\r
+    if (OptionOrder != NULL) {\r
+      FreePool (OptionOrder);\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Convert a single character to number.\r
+  It assumes the input Char is in the scope of L'0' ~ L'9' and L'A' ~ L'F'\r
+\r
+  @param    Char   The input char which need to convert to int.\r
+**/\r
+UINTN\r
+BmCharToUint (\r
+  IN CHAR16                           Char\r
+  )\r
+{\r
+  if ((Char >= L'0') && (Char <= L'9')) {\r
+    return (UINTN) (Char - L'0');\r
+  }\r
+\r
+  if ((Char >= L'A') && (Char <= L'F')) {\r
+    return (UINTN) (Char - L'A' + 0xA);\r
+  }\r
+\r
+  ASSERT (FALSE);\r
+  return (UINTN) -1;\r
+}\r
+\r
+/**\r
+  Returns the size of a device path in bytes.\r
+\r
+  This function returns the size, in bytes, of the device path data structure \r
+  specified by DevicePath including the end of device path node. If DevicePath \r
+  is NULL, then 0 is returned. If the length of the device path is bigger than\r
+  MaxSize, also return 0 to indicate this is an invalidate device path.\r
+\r
+  @param  DevicePath         A pointer to a device path data structure.\r
+  @param  MaxSize            Max valid device path size. If big than this size, \r
+                             return error.\r
+  \r
+  @retval 0                  An invalid device path.\r
+  @retval Others             The size of a device path in bytes.\r
+\r
+**/\r
+UINTN\r
+BmGetDevicePathSizeEx (\r
+  IN CONST EFI_DEVICE_PATH_PROTOCOL  *DevicePath,\r
+  IN UINTN                           MaxSize\r
+  )\r
+{\r
+  UINTN  Size;\r
+  UINTN  NodeSize;\r
+\r
+  if (DevicePath == NULL) {\r
+    return 0;\r
+  }\r
+\r
+  //\r
+  // Search for the end of the device path structure\r
+  //\r
+  Size = 0;\r
+  while (!IsDevicePathEnd (DevicePath)) {\r
+    NodeSize = DevicePathNodeLength (DevicePath);\r
+    if (NodeSize == 0) {\r
+      return 0;\r
+    }\r
+    Size += NodeSize;\r
+    if (Size > MaxSize) {\r
+      return 0;\r
+    }\r
+    DevicePath = NextDevicePathNode (DevicePath);\r
+  }\r
+  Size += DevicePathNodeLength (DevicePath);\r
+  if (Size > MaxSize) {\r
+    return 0;\r
+  }\r
+\r
+  return Size;\r
+}\r
+\r
+/**\r
+  Returns the length of a Null-terminated Unicode string. If the length is \r
+  bigger than MaxStringLen, return length 0 to indicate that this is an \r
+  invalidate string.\r
+\r
+  This function returns the number of Unicode characters in the Null-terminated\r
+  Unicode string specified by String. \r
+\r
+  If String is NULL, then ASSERT().\r
+  If String is not aligned on a 16-bit boundary, then ASSERT().\r
+\r
+  @param  String           A pointer to a Null-terminated Unicode string.\r
+  @param  MaxStringLen     Max string len in this string.\r
+\r
+  @retval 0                An invalid string.\r
+  @retval Others           The length of String.\r
+\r
+**/\r
+UINTN\r
+BmStrSizeEx (\r
+  IN      CONST CHAR16              *String,\r
+  IN      UINTN                     MaxStringLen\r
+  )\r
+{\r
+  UINTN                             Length;\r
+\r
+  ASSERT (String != NULL && MaxStringLen != 0);\r
+  ASSERT (((UINTN) String & BIT0) == 0);\r
+\r
+  for (Length = 0; *String != L'\0' && MaxStringLen != Length; String++, Length+=2);\r
+\r
+  if (*String != L'\0' && MaxStringLen == Length) {\r
+    return 0;\r
+  }\r
+\r
+  return Length + 2;\r
+}\r
+\r
+/**\r
+  Validate the Boot####, Driver####, SysPrep#### variable (VendorGuid/Name)\r
+\r
+  @param  Variable              The variable data.\r
+  @param  VariableSize          The variable size.\r
+\r
+  @retval TRUE                  The variable data is correct.\r
+  @retval FALSE                 The variable data is corrupted.\r
+\r
+**/\r
+BOOLEAN \r
+BmValidateOption (\r
+  UINT8                     *Variable,\r
+  UINTN                     VariableSize\r
+  )\r
+{\r
+  UINT16                    FilePathSize;\r
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
+  UINTN                     DescriptionSize;\r
+\r
+  if (VariableSize <= sizeof (UINT16) + sizeof (UINT32)) {\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // Skip the option attribute\r
+  //\r
+  Variable += sizeof (UINT32);\r
+\r
+  //\r
+  // Get the option's device path size\r
+  //\r
+  FilePathSize = ReadUnaligned16 ((UINT16 *) Variable);\r
+  Variable += sizeof (UINT16);\r
+\r
+  //\r
+  // Get the option's description string size\r
+  //\r
+  DescriptionSize = BmStrSizeEx ((CHAR16 *) Variable, VariableSize - sizeof (UINT16) - sizeof (UINT32));\r
+  Variable += DescriptionSize;\r
+\r
+  //\r
+  // Get the option's device path\r
+  //\r
+  DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Variable;\r
+\r
+  //\r
+  // Validation boot option variable.\r
+  //\r
+  if ((FilePathSize == 0) || (DescriptionSize == 0)) {\r
+    return FALSE;\r
+  }\r
+\r
+  if (sizeof (UINT32) + sizeof (UINT16) + DescriptionSize + FilePathSize > VariableSize) {\r
+    return FALSE;\r
+  }\r
+\r
+  return (BOOLEAN) (BmGetDevicePathSizeEx (DevicePath, FilePathSize) != 0);\r
+}\r
+\r
+/**\r
+  Check whether the VariableName is a valid load option variable name\r
+  and return the load option type and option number.\r
+\r
+  @param VariableName The name of the load option variable.\r
+  @param OptionType   Return the load option type.\r
+  @param OptionNumber Return the load option number.\r
+\r
+  @retval TRUE  The variable name is valid; The load option type and\r
+                load option number is returned.\r
+  @retval FALSE The variable name is NOT valid.\r
+**/\r
+BOOLEAN\r
+BmIsValidLoadOptionVariableName (\r
+  IN CHAR16                             *VariableName,\r
+  OUT EFI_BOOT_MANAGER_LOAD_OPTION_TYPE *OptionType,\r
+  OUT UINT16                            *OptionNumber\r
+  )\r
+{\r
+  UINTN                             VariableNameLen;\r
+  UINTN                             Index;\r
+  UINTN                             Uint;\r
+\r
+  VariableNameLen = StrLen (VariableName);\r
+\r
+  if (VariableNameLen <= 4) {\r
+    return FALSE;\r
+  }\r
+\r
+  for (Index = 0; Index < sizeof (mBmLoadOptionName) / sizeof (mBmLoadOptionName[0]); Index++) {\r
+    if ((VariableNameLen - 4 == StrLen (mBmLoadOptionName[Index])) &&\r
+        (StrnCmp (VariableName, mBmLoadOptionName[Index], VariableNameLen - 4) == 0)\r
+        ) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (Index == sizeof (mBmLoadOptionName) / sizeof (mBmLoadOptionName[0])) {\r
+    return FALSE;\r
+  }\r
+\r
+  *OptionType = (EFI_BOOT_MANAGER_LOAD_OPTION_TYPE) Index;\r
+  *OptionNumber = 0;\r
+  for (Index = VariableNameLen - 4; Index < VariableNameLen; Index++) {\r
+    Uint = BmCharToUint (VariableName[Index]);\r
+    if (Uint == -1) {\r
+      break;\r
+    } else {\r
+      *OptionNumber = (UINT16) Uint + *OptionNumber * 0x10;\r
+    }\r
+  }\r
+\r
+  return (BOOLEAN) (Index == VariableNameLen);\r
+}\r
+\r
+/**\r
+  Build the Boot#### or Driver#### option from the VariableName.\r
+\r
+  @param  VariableName          Variable name of the load option\r
+  @param  VendorGuid            Variable GUID of the load option\r
+  @param  Option                Return the load option.\r
+\r
+  @retval EFI_SUCCESS     Get the option just been created\r
+  @retval EFI_NOT_FOUND   Failed to get the new option\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiBootManagerVariableToLoadOptionEx (\r
+  IN CHAR16                           *VariableName,\r
+  IN EFI_GUID                         *VendorGuid,\r
+  IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *Option  \r
+  )\r
+{\r
+  EFI_STATUS                         Status;\r
+  UINT32                             Attribute;\r
+  UINT16                             FilePathSize;\r
+  UINT8                              *Variable;\r
+  UINT8                              *VariablePtr;\r
+  UINTN                              VariableSize;\r
+  EFI_DEVICE_PATH_PROTOCOL           *FilePath;\r
+  UINT8                              *OptionalData;\r
+  UINT32                             OptionalDataSize;\r
+  CHAR16                             *Description;\r
+  EFI_BOOT_MANAGER_LOAD_OPTION_TYPE  OptionType;\r
+  UINT16                             OptionNumber;\r
+\r
+  if ((VariableName == NULL) || (Option == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (!BmIsValidLoadOptionVariableName (VariableName, &OptionType, &OptionNumber)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Read the variable\r
+  //\r
+  GetVariable2 (VariableName, VendorGuid, (VOID **) &Variable, &VariableSize);\r
+  if (Variable == NULL) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  //\r
+  // Validate *#### variable data.\r
+  //\r
+  if (!BmValidateOption(Variable, VariableSize)) {\r
+    FreePool (Variable);\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Get the option attribute\r
+  //\r
+  VariablePtr = Variable;\r
+  Attribute = ReadUnaligned32 ((UINT32 *) VariablePtr);\r
+  VariablePtr += sizeof (UINT32);\r
+\r
+  //\r
+  // Get the option's device path size\r
+  //\r
+  FilePathSize = ReadUnaligned16 ((UINT16 *) VariablePtr);\r
+  VariablePtr += sizeof (UINT16);\r
+\r
+  //\r
+  // Get the option's description string\r
+  //\r
+  Description = (CHAR16 *) VariablePtr;\r
+\r
+  //\r
+  // Get the option's description string size\r
+  //\r
+  VariablePtr += StrSize ((CHAR16 *) VariablePtr);\r
+\r
+  //\r
+  // Get the option's device path\r
+  //\r
+  FilePath = (EFI_DEVICE_PATH_PROTOCOL *) VariablePtr;\r
+  VariablePtr += FilePathSize;\r
+\r
+  OptionalDataSize = (UINT32) (VariableSize - (UINTN) (VariablePtr - Variable));\r
+  if (OptionalDataSize == 0) {\r
+    OptionalData = NULL;\r
+  } else {\r
+    OptionalData = VariablePtr;\r
+  }\r
+\r
+  Status = EfiBootManagerInitializeLoadOption (\r
+             Option,\r
+             OptionNumber,\r
+             OptionType,\r
+             Attribute,\r
+             Description,\r
+             FilePath,\r
+             OptionalData,\r
+             OptionalDataSize\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  CopyGuid (&Option->VendorGuid, VendorGuid);\r
+\r
+  FreePool (Variable);\r
+  return Status;\r
+}\r
+\r
+/**\r
+Build the Boot#### or Driver#### option from the VariableName.\r
+\r
+@param  VariableName          EFI Variable name indicate if it is Boot#### or Driver####\r
+@param  Option                Return the Boot#### or Driver#### option.\r
+\r
+@retval EFI_SUCCESS     Get the option just been created\r
+@retval EFI_NOT_FOUND   Failed to get the new option\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiBootManagerVariableToLoadOption (\r
+  IN  CHAR16                          *VariableName,\r
+  IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *Option\r
+  )\r
+{\r
+  return EfiBootManagerVariableToLoadOptionEx (VariableName, &gEfiGlobalVariableGuid, Option);\r
+}\r
+\r
+/**\r
+  Returns an array of load options based on the EFI variable\r
+  L"BootOrder"/L"DriverOrder" and the L"Boot####"/L"Driver####" variables impled by it.\r
+  #### is the hex value of the UINT16 in each BootOrder/DriverOrder entry. \r
+\r
+  @param  LoadOptionCount   Returns number of entries in the array.\r
+  @param  LoadOptionType    The type of the load option.\r
+\r
+  @retval NULL  No load options exist.\r
+  @retval !NULL Array of load option entries.\r
+\r
+**/\r
+EFI_BOOT_MANAGER_LOAD_OPTION *\r
+EFIAPI\r
+EfiBootManagerGetLoadOptions (\r
+  OUT UINTN                             *OptionCount,\r
+  IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE  LoadOptionType\r
+  )\r
+{\r
+  EFI_STATUS                   Status;\r
+  UINT16                       *OptionOrder;\r
+  UINTN                        OptionOrderSize;\r
+  UINTN                        Index;\r
+  UINTN                        OptionIndex;\r
+  EFI_BOOT_MANAGER_LOAD_OPTION *Options;\r
+  CHAR16                       OptionName[BM_OPTION_NAME_LEN];\r
+  UINT16                       OptionNumber;\r
+\r
+  *OptionCount = 0;\r
+\r
+  if (LoadOptionType == LoadOptionTypeDriver || LoadOptionType == LoadOptionTypeSysPrep || LoadOptionType == LoadOptionTypeBoot) {\r
+    //\r
+    // Read the BootOrder, or DriverOrder variable.\r
+    //\r
+    GetEfiGlobalVariable2 (mBmLoadOptionOrderName[LoadOptionType], (VOID **) &OptionOrder, &OptionOrderSize);\r
+    if (OptionOrder == NULL) {\r
+      return NULL;\r
+    }\r
+\r
+    *OptionCount = OptionOrderSize / sizeof (UINT16);\r
+\r
+    Options = AllocatePool (*OptionCount * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));\r
+    ASSERT (Options != NULL);\r
+\r
+    OptionIndex = 0;\r
+    for (Index = 0; Index < *OptionCount; Index++) {\r
+      OptionNumber = OptionOrder[Index];\r
+      UnicodeSPrint (OptionName, sizeof (OptionName), L"%s%04x", mBmLoadOptionName[LoadOptionType], OptionNumber);\r
+\r
+      Status = EfiBootManagerVariableToLoadOption (OptionName, &Options[OptionIndex]);\r
+      if (EFI_ERROR (Status)) {\r
+        DEBUG ((EFI_D_INFO, "[Bds] %s doesn't exist - Update ****Order variable to remove the reference!!", OptionName));\r
+        EfiBootManagerDeleteLoadOptionVariable (OptionNumber, LoadOptionType);\r
+      } else {\r
+        ASSERT (Options[OptionIndex].OptionNumber == OptionNumber);\r
+        OptionIndex++;\r
+      }\r
+    }\r
+\r
+    if (OptionOrder != NULL) {\r
+      FreePool (OptionOrder);\r
+    }\r
+\r
+    if (OptionIndex < *OptionCount) {\r
+      Options = ReallocatePool (*OptionCount * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION), OptionIndex * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION), Options);\r
+      ASSERT (Options != NULL);\r
+      *OptionCount = OptionIndex;\r
+    }\r
+\r
+  } else {\r
+    return NULL;\r
+  }\r
+\r
+  return Options;\r
+}\r
+\r
+/**\r
+  Free an EFI_BOOT_MANGER_LOAD_OPTION entry that was allocate by the library.\r
+\r
+  @param  LoadOption   Pointer to boot option to Free.\r
+\r
+  @return EFI_SUCCESS   BootOption was freed \r
+  @return EFI_NOT_FOUND BootOption == NULL \r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiBootManagerFreeLoadOption (\r
+  IN  EFI_BOOT_MANAGER_LOAD_OPTION  *LoadOption\r
+  )\r
+{\r
+  if (LoadOption == NULL) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  if (LoadOption->Description != NULL) {\r
+    FreePool (LoadOption->Description);\r
+  }\r
+  if (LoadOption->FilePath != NULL) {\r
+    FreePool (LoadOption->FilePath);\r
+  }\r
+  if (LoadOption->OptionalData != NULL) {\r
+    FreePool (LoadOption->OptionalData);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Free an EFI_BOOT_MANGER_LOAD_OPTION array that was allocated by \r
+  EfiBootManagerGetLoadOptions().\r
+\r
+  @param  Option       Pointer to boot option array to free.\r
+  @param  OptionCount  Number of array entries in BootOption\r
+\r
+  @return EFI_SUCCESS   BootOption was freed \r
+  @return EFI_NOT_FOUND BootOption == NULL \r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiBootManagerFreeLoadOptions (\r
+  IN  EFI_BOOT_MANAGER_LOAD_OPTION  *Option,\r
+  IN  UINTN                         OptionCount\r
+  )\r
+{\r
+  UINTN   Index;\r
+\r
+  if (Option == NULL) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  for (Index = 0;Index < OptionCount; Index++) {\r
+    EfiBootManagerFreeLoadOption (&Option[Index]);\r
+  }\r
+\r
+  FreePool (Option);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Return whether the PE header of the load option is valid or not.\r
+\r
+  @param[in] Type       The load option type.\r
+  @param[in] FileBuffer The PE file buffer of the load option.\r
+  @param[in] FileSize   The size of the load option file.\r
+\r
+  @retval TRUE  The PE header of the load option is valid.\r
+  @retval FALSE The PE header of the load option is not valid.\r
+**/\r
+BOOLEAN\r
+BmIsLoadOptionPeHeaderValid (\r
+  IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE Type,\r
+  IN VOID                              *FileBuffer,\r
+  IN UINTN                             FileSize\r
+  )\r
+{\r
+  EFI_IMAGE_DOS_HEADER              *DosHeader;\r
+  EFI_IMAGE_OPTIONAL_HEADER_UNION   *PeHeader;\r
+  EFI_IMAGE_OPTIONAL_HEADER32       *OptionalHeader;\r
+  UINT16                            Subsystem;\r
+\r
+  if (FileBuffer == NULL || FileSize == 0) {\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // Read dos header\r
+  //\r
+  DosHeader = (EFI_IMAGE_DOS_HEADER *) FileBuffer;\r
+  if (FileSize >= sizeof (EFI_IMAGE_DOS_HEADER) &&\r
+      FileSize > DosHeader->e_lfanew && DosHeader->e_magic == EFI_IMAGE_DOS_SIGNATURE\r
+      ) {\r
+    //\r
+    // Read and check PE signature\r
+    //\r
+    PeHeader = (EFI_IMAGE_OPTIONAL_HEADER_UNION *) ((UINT8 *) FileBuffer + DosHeader->e_lfanew);\r
+    if (FileSize >= DosHeader->e_lfanew + sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION) &&\r
+        PeHeader->Pe32.Signature == EFI_IMAGE_NT_SIGNATURE\r
+        ) {\r
+      //\r
+      // Check PE32 or PE32+ magic, and machine type\r
+      //\r
+      OptionalHeader = (EFI_IMAGE_OPTIONAL_HEADER32 *) &PeHeader->Pe32.OptionalHeader;\r
+      if ((OptionalHeader->Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC || \r
+           OptionalHeader->Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) &&\r
+          EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeHeader->Pe32.FileHeader.Machine)\r
+          ) {\r
+        //\r
+        // Check the Subsystem:\r
+        //   Driver#### must be of type BootServiceDriver or RuntimeDriver\r
+        //   SysPrep####, Boot####, OsRecovery####, PlatformRecovery#### must be of type Application\r
+        //\r
+        Subsystem = OptionalHeader->Subsystem;\r
+        if ((Type == LoadOptionTypeDriver && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) ||\r
+            (Type == LoadOptionTypeDriver && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) ||\r
+            (Type == LoadOptionTypeSysPrep && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) ||\r
+            (Type == LoadOptionTypeBoot && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION)\r
+            ) {\r
+          return TRUE;\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  Process (load and execute) the load option.\r
+\r
+  @param LoadOption  Pointer to the load option.\r
+\r
+  @retval EFI_INVALID_PARAMETER  The load option type is invalid, \r
+                                 or the load option file path doesn't point to a valid file.\r
+  @retval EFI_UNSUPPORTED        The load option type is of LoadOptionTypeBoot.\r
+  @retval EFI_SUCCESS            The load option is inactive, or successfully loaded and executed.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiBootManagerProcessLoadOption (\r
+  IN EFI_BOOT_MANAGER_LOAD_OPTION       *LoadOption\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  EFI_DEVICE_PATH_PROTOCOL          *FilePath;\r
+  EFI_HANDLE                        ImageHandle;\r
+  EFI_LOADED_IMAGE_PROTOCOL         *ImageInfo;\r
+  VOID                              *FileBuffer;\r
+  UINTN                             FileSize;\r
+\r
+  if ((UINT32) LoadOption->OptionType >= LoadOptionTypeMax) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (LoadOption->OptionType == LoadOptionTypeBoot) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // If a load option is not marked as LOAD_OPTION_ACTIVE,\r
+  // the boot manager will not automatically load the option.\r
+  //\r
+  if ((LoadOption->Attributes & LOAD_OPTION_ACTIVE) == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  Status = EFI_INVALID_PARAMETER;\r
+\r
+  //\r
+  // Load and start the load option.\r
+  //\r
+  DEBUG ((\r
+    DEBUG_INFO | DEBUG_LOAD, "Process Load Option (%s%04x) ...\n",\r
+    mBmLoadOptionName[LoadOption->OptionType], LoadOption->OptionNumber\r
+    ));\r
+  ImageHandle = NULL;\r
+  FileBuffer = BmGetLoadOptionBuffer (LoadOption->FilePath, &FilePath, &FileSize);\r
+  DEBUG_CODE (\r
+    if (FileBuffer != NULL && CompareMem (LoadOption->FilePath, FilePath, GetDevicePathSize (FilePath)) != 0) {\r
+      DEBUG ((EFI_D_INFO, "[Bds] DevicePath expand: "));\r
+      BmPrintDp (LoadOption->FilePath);\r
+      DEBUG ((EFI_D_INFO, " -> "));\r
+      BmPrintDp (FilePath);\r
+      DEBUG ((EFI_D_INFO, "\n"));\r
+    }\r
+  );\r
+  if (BmIsLoadOptionPeHeaderValid (LoadOption->OptionType, FileBuffer, FileSize)) {\r
+    Status = gBS->LoadImage (\r
+                    FALSE,\r
+                    gImageHandle,\r
+                    FilePath,\r
+                    FileBuffer,\r
+                    FileSize,\r
+                    &ImageHandle\r
+                    );\r
+  }\r
+  if (FilePath != NULL) {\r
+    FreePool (FilePath);\r
+  }\r
+  if (FileBuffer != NULL) {\r
+    FreePool (FileBuffer);\r
+  }\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);\r
+    ASSERT_EFI_ERROR (Status);\r
+\r
+    ImageInfo->LoadOptionsSize = LoadOption->OptionalDataSize;\r
+    ImageInfo->LoadOptions = LoadOption->OptionalData;\r
+    //\r
+    // Before calling the image, enable the Watchdog Timer for the 5-minute period\r
+    //\r
+    gBS->SetWatchdogTimer (5 * 60, 0, 0, NULL);\r
+\r
+    LoadOption->Status = gBS->StartImage (ImageHandle, &LoadOption->ExitDataSize, &LoadOption->ExitData);\r
+    DEBUG ((\r
+      DEBUG_INFO | DEBUG_LOAD, "Load Option (%s%04x) Return Status = %r\n",\r
+      mBmLoadOptionName[LoadOption->OptionType], LoadOption->OptionNumber, LoadOption->Status\r
+      ));\r
+\r
+    //\r
+    // Clear the Watchdog Timer after the image returns\r
+    //\r
+    gBS->SetWatchdogTimer (0, 0, 0, NULL);\r
+  }\r
+\r
+  return Status;\r
+}\r
index 30d955111ec8ae3032e8327a9bb771f21f299051..97d1a48cd5a24af336c09242f0e26bcd50e21611 100644 (file)
-/** @file
-  Misc library functions.
-
-Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
-This program and the accompanying materials
-are licensed and made available under the terms and conditions of the BSD License
-which accompanies this distribution.  The full text of the license may be found at
-http://opensource.org/licenses/bsd-license.php
-
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
-
-**/
-
-#include "InternalBm.h"
-
-/**
-  Delete the instance in Multi which matches partly with Single instance
-
-  @param  Multi                 A pointer to a multi-instance device path data
-                                structure.
-  @param  Single                A pointer to a single-instance device path data
-                                structure.
-
-  @return This function will remove the device path instances in Multi which partly
-          match with the Single, and return the result device path. If there is no
-          remaining device path as a result, this function will return NULL.
-
-**/
-EFI_DEVICE_PATH_PROTOCOL *
-BmDelPartMatchInstance (
-  IN     EFI_DEVICE_PATH_PROTOCOL  *Multi,
-  IN     EFI_DEVICE_PATH_PROTOCOL  *Single
-  )
-{
-  EFI_DEVICE_PATH_PROTOCOL  *Instance;
-  EFI_DEVICE_PATH_PROTOCOL  *NewDevicePath;
-  EFI_DEVICE_PATH_PROTOCOL  *TempNewDevicePath;
-  UINTN                     InstanceSize;
-  UINTN                     SingleDpSize;
-
-  NewDevicePath     = NULL;
-  TempNewDevicePath = NULL;
-
-  if (Multi == NULL || Single == NULL) {
-    return Multi;
-  }
-
-  Instance        = GetNextDevicePathInstance (&Multi, &InstanceSize);
-  SingleDpSize    = GetDevicePathSize (Single) - END_DEVICE_PATH_LENGTH;
-  InstanceSize   -= END_DEVICE_PATH_LENGTH;
-
-  while (Instance != NULL) {
-
-    if (CompareMem (Instance, Single, MIN (SingleDpSize, InstanceSize)) != 0) {
-      //
-      // Append the device path instance which does not match with Single
-      //
-      TempNewDevicePath = NewDevicePath;
-      NewDevicePath = AppendDevicePathInstance (NewDevicePath, Instance);
-      if (TempNewDevicePath != NULL) {
-        FreePool(TempNewDevicePath);
-      }
-    }
-    FreePool(Instance);
-    Instance      = GetNextDevicePathInstance (&Multi, &InstanceSize);
-    InstanceSize -= END_DEVICE_PATH_LENGTH;
-  }
-
-  return NewDevicePath;
-}
-
-/**
-  Function compares a device path data structure to that of all the nodes of a
-  second device path instance.
-
-  @param  Multi                 A pointer to a multi-instance device path data
-                                structure.
-  @param  Single                A pointer to a single-instance device path data
-                                structure.
-
-  @retval TRUE                  If the Single device path is contained within Multi device path.
-  @retval FALSE                 The Single device path is not match within Multi device path.
-
-**/
-BOOLEAN
-BmMatchDevicePaths (
-  IN  EFI_DEVICE_PATH_PROTOCOL  *Multi,
-  IN  EFI_DEVICE_PATH_PROTOCOL  *Single
-  )
-{
-  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
-  EFI_DEVICE_PATH_PROTOCOL  *DevicePathInst;
-  UINTN                     Size;
-
-  if (Multi == NULL || Single  == NULL) {
-    return FALSE;
-  }
-
-  DevicePath     = Multi;
-  DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);
-
-  //
-  // Search for the match of 'Single' in 'Multi'
-  //
-  while (DevicePathInst != NULL) {
-    //
-    // If the single device path is found in multiple device paths,
-    // return success
-    //
-    if (CompareMem (Single, DevicePathInst, Size) == 0) {
-      FreePool (DevicePathInst);
-      return TRUE;
-    }
-
-    FreePool (DevicePathInst);
-    DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);
-  }
-
-  return FALSE;
-}
-
-/**
-  This routine adjust the memory information for different memory type and 
-  save them into the variables for next boot.
-**/
-VOID
-BmSetMemoryTypeInformationVariable (
-  VOID
-  )
-{
-  EFI_STATUS                   Status;
-  EFI_MEMORY_TYPE_INFORMATION  *PreviousMemoryTypeInformation;
-  EFI_MEMORY_TYPE_INFORMATION  *CurrentMemoryTypeInformation;
-  UINTN                        VariableSize;
-  UINTN                        Index;
-  UINTN                        Index1;
-  UINT32                       Previous;
-  UINT32                       Current;
-  UINT32                       Next;
-  EFI_HOB_GUID_TYPE            *GuidHob;
-  BOOLEAN                      MemoryTypeInformationModified;
-  BOOLEAN                      MemoryTypeInformationVariableExists;
-  EFI_BOOT_MODE                BootMode;
-
-  MemoryTypeInformationModified       = FALSE;
-  MemoryTypeInformationVariableExists = FALSE;
-
-
-  BootMode = GetBootModeHob ();
-  //
-  // In BOOT_IN_RECOVERY_MODE, Variable region is not reliable.
-  //
-  if (BootMode == BOOT_IN_RECOVERY_MODE) {
-    return;
-  }
-
-  //
-  // Only check the the Memory Type Information variable in the boot mode 
-  // other than BOOT_WITH_DEFAULT_SETTINGS because the Memory Type
-  // Information is not valid in this boot mode.
-  //
-  if (BootMode != BOOT_WITH_DEFAULT_SETTINGS) {
-    VariableSize = 0;
-    Status = gRT->GetVariable (
-                    EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME,
-                    &gEfiMemoryTypeInformationGuid,
-                    NULL, 
-                    &VariableSize, 
-                    NULL
-                    );
-    if (Status == EFI_BUFFER_TOO_SMALL) {
-      MemoryTypeInformationVariableExists = TRUE;
-    }
-  }
-
-  //
-  // Retrieve the current memory usage statistics.  If they are not found, then
-  // no adjustments can be made to the Memory Type Information variable.
-  //
-  Status = EfiGetSystemConfigurationTable (
-             &gEfiMemoryTypeInformationGuid,
-             (VOID **) &CurrentMemoryTypeInformation
-             );
-  if (EFI_ERROR (Status) || CurrentMemoryTypeInformation == NULL) {
-    return;
-  }
-
-  //
-  // Get the Memory Type Information settings from Hob if they exist,
-  // PEI is responsible for getting them from variable and build a Hob to save them.
-  // If the previous Memory Type Information is not available, then set defaults
-  //
-  GuidHob = GetFirstGuidHob (&gEfiMemoryTypeInformationGuid);
-  if (GuidHob == NULL) {
-    //
-    // If Platform has not built Memory Type Info into the Hob, just return.
-    //
-    return;
-  }
-  PreviousMemoryTypeInformation = GET_GUID_HOB_DATA (GuidHob);
-  VariableSize = GET_GUID_HOB_DATA_SIZE (GuidHob);
-
-  //
-  // Use a heuristic to adjust the Memory Type Information for the next boot
-  //
-  DEBUG ((EFI_D_INFO, "Memory  Previous  Current    Next   \n"));
-  DEBUG ((EFI_D_INFO, " Type    Pages     Pages     Pages  \n"));
-  DEBUG ((EFI_D_INFO, "======  ========  ========  ========\n"));
-
-  for (Index = 0; PreviousMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
-
-    for (Index1 = 0; CurrentMemoryTypeInformation[Index1].Type != EfiMaxMemoryType; Index1++) {
-      if (PreviousMemoryTypeInformation[Index].Type == CurrentMemoryTypeInformation[Index1].Type) {
-        break;
-      }
-    }
-    if (CurrentMemoryTypeInformation[Index1].Type == EfiMaxMemoryType) {
-      continue;
-    }
-
-    //
-    // Previous is the number of pages pre-allocated
-    // Current is the number of pages actually needed
-    //
-    Previous = PreviousMemoryTypeInformation[Index].NumberOfPages;
-    Current  = CurrentMemoryTypeInformation[Index1].NumberOfPages;
-    Next     = Previous;
-
-    //
-    // Inconsistent Memory Reserved across bootings may lead to S4 fail
-    // Write next varible to 125% * current when the pre-allocated memory is:
-    //  1. More than 150% of needed memory and boot mode is BOOT_WITH_DEFAULT_SETTING
-    //  2. Less than the needed memory
-    //
-    if ((Current + (Current >> 1)) < Previous) {
-      if (BootMode == BOOT_WITH_DEFAULT_SETTINGS) {
-        Next = Current + (Current >> 2);
-      }
-    } else if (Current > Previous) {
-      Next = Current + (Current >> 2);
-    }
-    if (Next > 0 && Next < 4) {
-      Next = 4;
-    }
-
-    if (Next != Previous) {
-      PreviousMemoryTypeInformation[Index].NumberOfPages = Next;
-      MemoryTypeInformationModified = TRUE;
-    }
-
-    DEBUG ((EFI_D_INFO, "  %02x    %08x  %08x  %08x\n", PreviousMemoryTypeInformation[Index].Type, Previous, Current, Next));
-  }
-
-  //
-  // If any changes were made to the Memory Type Information settings, then set the new variable value;
-  // Or create the variable in first boot.
-  //
-  if (MemoryTypeInformationModified || !MemoryTypeInformationVariableExists) {
-    Status = BmSetVariableAndReportStatusCodeOnError (
-               EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME,
-               &gEfiMemoryTypeInformationGuid,
-               EFI_VARIABLE_NON_VOLATILE  | EFI_VARIABLE_BOOTSERVICE_ACCESS,
-               VariableSize,
-               PreviousMemoryTypeInformation
-               );
-
-    if (!EFI_ERROR (Status)) {
-      //
-      // If the Memory Type Information settings have been modified, then reset the platform
-      // so the new Memory Type Information setting will be used to guarantee that an S4
-      // entry/resume cycle will not fail.
-      //
-      if (MemoryTypeInformationModified) {
-        DEBUG ((EFI_D_INFO, "Memory Type Information settings change. Warm Reset!!!\n"));
-        gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);
-      }
-    } else {
-      DEBUG ((EFI_D_ERROR, "Memory Type Information settings cannot be saved. OS S4 may fail!\n"));
-    }
-  }
-}
-
-/**
-  Set the variable and report the error through status code upon failure.
-
-  @param  VariableName           A Null-terminated string that is the name of the vendor's variable.
-                                 Each VariableName is unique for each VendorGuid. VariableName must
-                                 contain 1 or more characters. If VariableName is an empty string,
-                                 then EFI_INVALID_PARAMETER is returned.
-  @param  VendorGuid             A unique identifier for the vendor.
-  @param  Attributes             Attributes bitmask to set for the variable.
-  @param  DataSize               The size in bytes of the Data buffer. Unless the EFI_VARIABLE_APPEND_WRITE, 
-                                 EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, or 
-                                 EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute is set, a size of zero 
-                                 causes the variable to be deleted. When the EFI_VARIABLE_APPEND_WRITE attribute is 
-                                 set, then a SetVariable() call with a DataSize of zero will not cause any change to 
-                                 the variable value (the timestamp associated with the variable may be updated however 
-                                 even if no new data value is provided,see the description of the 
-                                 EFI_VARIABLE_AUTHENTICATION_2 descriptor below. In this case the DataSize will not 
-                                 be zero since the EFI_VARIABLE_AUTHENTICATION_2 descriptor will be populated). 
-  @param  Data                   The contents for the variable.
-
-  @retval EFI_SUCCESS            The firmware has successfully stored the variable and its data as
-                                 defined by the Attributes.
-  @retval EFI_INVALID_PARAMETER  An invalid combination of attribute bits, name, and GUID was supplied, or the
-                                 DataSize exceeds the maximum allowed.
-  @retval EFI_INVALID_PARAMETER  VariableName is an empty string.
-  @retval EFI_OUT_OF_RESOURCES   Not enough storage is available to hold the variable and its data.
-  @retval EFI_DEVICE_ERROR       The variable could not be retrieved due to a hardware error.
-  @retval EFI_WRITE_PROTECTED    The variable in question is read-only.
-  @retval EFI_WRITE_PROTECTED    The variable in question cannot be deleted.
-  @retval EFI_SECURITY_VIOLATION The variable could not be written due to EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS 
-                                 or EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACESS being set, but the AuthInfo 
-                                 does NOT pass the validation check carried out by the firmware.
-
-  @retval EFI_NOT_FOUND          The variable trying to be updated or deleted was not found.
-**/
-EFI_STATUS
-BmSetVariableAndReportStatusCodeOnError (
-  IN CHAR16     *VariableName,
-  IN EFI_GUID   *VendorGuid,
-  IN UINT32     Attributes,
-  IN UINTN      DataSize,
-  IN VOID       *Data
-  )
-{
-  EFI_STATUS                 Status;
-  EDKII_SET_VARIABLE_STATUS  *SetVariableStatus;
-  UINTN                      NameSize;
-
-  Status = gRT->SetVariable (
-                  VariableName,
-                  VendorGuid,
-                  Attributes,
-                  DataSize,
-                  Data
-                  );
-  if (EFI_ERROR (Status)) {
-    NameSize = StrSize (VariableName);
-    SetVariableStatus = AllocatePool (sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + DataSize);
-    if (SetVariableStatus != NULL) {
-      CopyGuid (&SetVariableStatus->Guid, VendorGuid);
-      SetVariableStatus->NameSize   = NameSize;
-      SetVariableStatus->DataSize   = DataSize;
-      SetVariableStatus->SetStatus  = Status;
-      SetVariableStatus->Attributes = Attributes;
-      CopyMem (SetVariableStatus + 1,                          VariableName, NameSize);
-      CopyMem (((UINT8 *) (SetVariableStatus + 1)) + NameSize, Data,         DataSize);
-
-      REPORT_STATUS_CODE_EX (
-        EFI_ERROR_CODE,
-        PcdGet32 (PcdErrorCodeSetVariable),
-        0,
-        NULL,
-        &gEdkiiStatusCodeDataTypeVariableGuid,
-        SetVariableStatus,
-        sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + DataSize
-        );
-
-      FreePool (SetVariableStatus);
-    }
-  }
-
-  return Status;
-}
-
-
-/**
-  Print the device path info.
-
-  @param DevicePath           The device path need to print.
-**/
-VOID
-BmPrintDp (
-  EFI_DEVICE_PATH_PROTOCOL            *DevicePath
-  )
-{
-  CHAR16                              *Str;
-
-  Str = ConvertDevicePathToText (DevicePath, FALSE, FALSE);
-  DEBUG ((EFI_D_INFO, "%s", Str));
-  if (Str != NULL) {
-    FreePool (Str);
-  }
-}
+/** @file\r
+  Misc library functions.\r
+\r
+Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "InternalBm.h"\r
+\r
+/**\r
+  Delete the instance in Multi which matches partly with Single instance\r
+\r
+  @param  Multi                 A pointer to a multi-instance device path data\r
+                                structure.\r
+  @param  Single                A pointer to a single-instance device path data\r
+                                structure.\r
+\r
+  @return This function will remove the device path instances in Multi which partly\r
+          match with the Single, and return the result device path. If there is no\r
+          remaining device path as a result, this function will return NULL.\r
+\r
+**/\r
+EFI_DEVICE_PATH_PROTOCOL *\r
+BmDelPartMatchInstance (\r
+  IN     EFI_DEVICE_PATH_PROTOCOL  *Multi,\r
+  IN     EFI_DEVICE_PATH_PROTOCOL  *Single\r
+  )\r
+{\r
+  EFI_DEVICE_PATH_PROTOCOL  *Instance;\r
+  EFI_DEVICE_PATH_PROTOCOL  *NewDevicePath;\r
+  EFI_DEVICE_PATH_PROTOCOL  *TempNewDevicePath;\r
+  UINTN                     InstanceSize;\r
+  UINTN                     SingleDpSize;\r
+\r
+  NewDevicePath     = NULL;\r
+  TempNewDevicePath = NULL;\r
+\r
+  if (Multi == NULL || Single == NULL) {\r
+    return Multi;\r
+  }\r
+\r
+  Instance        = GetNextDevicePathInstance (&Multi, &InstanceSize);\r
+  SingleDpSize    = GetDevicePathSize (Single) - END_DEVICE_PATH_LENGTH;\r
+  InstanceSize   -= END_DEVICE_PATH_LENGTH;\r
+\r
+  while (Instance != NULL) {\r
+\r
+    if (CompareMem (Instance, Single, MIN (SingleDpSize, InstanceSize)) != 0) {\r
+      //\r
+      // Append the device path instance which does not match with Single\r
+      //\r
+      TempNewDevicePath = NewDevicePath;\r
+      NewDevicePath = AppendDevicePathInstance (NewDevicePath, Instance);\r
+      if (TempNewDevicePath != NULL) {\r
+        FreePool(TempNewDevicePath);\r
+      }\r
+    }\r
+    FreePool(Instance);\r
+    Instance      = GetNextDevicePathInstance (&Multi, &InstanceSize);\r
+    InstanceSize -= END_DEVICE_PATH_LENGTH;\r
+  }\r
+\r
+  return NewDevicePath;\r
+}\r
+\r
+/**\r
+  Function compares a device path data structure to that of all the nodes of a\r
+  second device path instance.\r
+\r
+  @param  Multi                 A pointer to a multi-instance device path data\r
+                                structure.\r
+  @param  Single                A pointer to a single-instance device path data\r
+                                structure.\r
+\r
+  @retval TRUE                  If the Single device path is contained within Multi device path.\r
+  @retval FALSE                 The Single device path is not match within Multi device path.\r
+\r
+**/\r
+BOOLEAN\r
+BmMatchDevicePaths (\r
+  IN  EFI_DEVICE_PATH_PROTOCOL  *Multi,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL  *Single\r
+  )\r
+{\r
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePathInst;\r
+  UINTN                     Size;\r
+\r
+  if (Multi == NULL || Single  == NULL) {\r
+    return FALSE;\r
+  }\r
+\r
+  DevicePath     = Multi;\r
+  DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);\r
+\r
+  //\r
+  // Search for the match of 'Single' in 'Multi'\r
+  //\r
+  while (DevicePathInst != NULL) {\r
+    //\r
+    // If the single device path is found in multiple device paths,\r
+    // return success\r
+    //\r
+    if (CompareMem (Single, DevicePathInst, Size) == 0) {\r
+      FreePool (DevicePathInst);\r
+      return TRUE;\r
+    }\r
+\r
+    FreePool (DevicePathInst);\r
+    DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  This routine adjust the memory information for different memory type and \r
+  save them into the variables for next boot.\r
+**/\r
+VOID\r
+BmSetMemoryTypeInformationVariable (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS                   Status;\r
+  EFI_MEMORY_TYPE_INFORMATION  *PreviousMemoryTypeInformation;\r
+  EFI_MEMORY_TYPE_INFORMATION  *CurrentMemoryTypeInformation;\r
+  UINTN                        VariableSize;\r
+  UINTN                        Index;\r
+  UINTN                        Index1;\r
+  UINT32                       Previous;\r
+  UINT32                       Current;\r
+  UINT32                       Next;\r
+  EFI_HOB_GUID_TYPE            *GuidHob;\r
+  BOOLEAN                      MemoryTypeInformationModified;\r
+  BOOLEAN                      MemoryTypeInformationVariableExists;\r
+  EFI_BOOT_MODE                BootMode;\r
+\r
+  MemoryTypeInformationModified       = FALSE;\r
+  MemoryTypeInformationVariableExists = FALSE;\r
+\r
+\r
+  BootMode = GetBootModeHob ();\r
+  //\r
+  // In BOOT_IN_RECOVERY_MODE, Variable region is not reliable.\r
+  //\r
+  if (BootMode == BOOT_IN_RECOVERY_MODE) {\r
+    return;\r
+  }\r
+\r
+  //\r
+  // Only check the the Memory Type Information variable in the boot mode \r
+  // other than BOOT_WITH_DEFAULT_SETTINGS because the Memory Type\r
+  // Information is not valid in this boot mode.\r
+  //\r
+  if (BootMode != BOOT_WITH_DEFAULT_SETTINGS) {\r
+    VariableSize = 0;\r
+    Status = gRT->GetVariable (\r
+                    EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME,\r
+                    &gEfiMemoryTypeInformationGuid,\r
+                    NULL, \r
+                    &VariableSize, \r
+                    NULL\r
+                    );\r
+    if (Status == EFI_BUFFER_TOO_SMALL) {\r
+      MemoryTypeInformationVariableExists = TRUE;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Retrieve the current memory usage statistics.  If they are not found, then\r
+  // no adjustments can be made to the Memory Type Information variable.\r
+  //\r
+  Status = EfiGetSystemConfigurationTable (\r
+             &gEfiMemoryTypeInformationGuid,\r
+             (VOID **) &CurrentMemoryTypeInformation\r
+             );\r
+  if (EFI_ERROR (Status) || CurrentMemoryTypeInformation == NULL) {\r
+    return;\r
+  }\r
+\r
+  //\r
+  // Get the Memory Type Information settings from Hob if they exist,\r
+  // PEI is responsible for getting them from variable and build a Hob to save them.\r
+  // If the previous Memory Type Information is not available, then set defaults\r
+  //\r
+  GuidHob = GetFirstGuidHob (&gEfiMemoryTypeInformationGuid);\r
+  if (GuidHob == NULL) {\r
+    //\r
+    // If Platform has not built Memory Type Info into the Hob, just return.\r
+    //\r
+    return;\r
+  }\r
+  PreviousMemoryTypeInformation = GET_GUID_HOB_DATA (GuidHob);\r
+  VariableSize = GET_GUID_HOB_DATA_SIZE (GuidHob);\r
+\r
+  //\r
+  // Use a heuristic to adjust the Memory Type Information for the next boot\r
+  //\r
+  DEBUG ((EFI_D_INFO, "Memory  Previous  Current    Next   \n"));\r
+  DEBUG ((EFI_D_INFO, " Type    Pages     Pages     Pages  \n"));\r
+  DEBUG ((EFI_D_INFO, "======  ========  ========  ========\n"));\r
+\r
+  for (Index = 0; PreviousMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {\r
+\r
+    for (Index1 = 0; CurrentMemoryTypeInformation[Index1].Type != EfiMaxMemoryType; Index1++) {\r
+      if (PreviousMemoryTypeInformation[Index].Type == CurrentMemoryTypeInformation[Index1].Type) {\r
+        break;\r
+      }\r
+    }\r
+    if (CurrentMemoryTypeInformation[Index1].Type == EfiMaxMemoryType) {\r
+      continue;\r
+    }\r
+\r
+    //\r
+    // Previous is the number of pages pre-allocated\r
+    // Current is the number of pages actually needed\r
+    //\r
+    Previous = PreviousMemoryTypeInformation[Index].NumberOfPages;\r
+    Current  = CurrentMemoryTypeInformation[Index1].NumberOfPages;\r
+    Next     = Previous;\r
+\r
+    //\r
+    // Inconsistent Memory Reserved across bootings may lead to S4 fail\r
+    // Write next varible to 125% * current when the pre-allocated memory is:\r
+    //  1. More than 150% of needed memory and boot mode is BOOT_WITH_DEFAULT_SETTING\r
+    //  2. Less than the needed memory\r
+    //\r
+    if ((Current + (Current >> 1)) < Previous) {\r
+      if (BootMode == BOOT_WITH_DEFAULT_SETTINGS) {\r
+        Next = Current + (Current >> 2);\r
+      }\r
+    } else if (Current > Previous) {\r
+      Next = Current + (Current >> 2);\r
+    }\r
+    if (Next > 0 && Next < 4) {\r
+      Next = 4;\r
+    }\r
+\r
+    if (Next != Previous) {\r
+      PreviousMemoryTypeInformation[Index].NumberOfPages = Next;\r
+      MemoryTypeInformationModified = TRUE;\r
+    }\r
+\r
+    DEBUG ((EFI_D_INFO, "  %02x    %08x  %08x  %08x\n", PreviousMemoryTypeInformation[Index].Type, Previous, Current, Next));\r
+  }\r
+\r
+  //\r
+  // If any changes were made to the Memory Type Information settings, then set the new variable value;\r
+  // Or create the variable in first boot.\r
+  //\r
+  if (MemoryTypeInformationModified || !MemoryTypeInformationVariableExists) {\r
+    Status = BmSetVariableAndReportStatusCodeOnError (\r
+               EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME,\r
+               &gEfiMemoryTypeInformationGuid,\r
+               EFI_VARIABLE_NON_VOLATILE  | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
+               VariableSize,\r
+               PreviousMemoryTypeInformation\r
+               );\r
+\r
+    if (!EFI_ERROR (Status)) {\r
+      //\r
+      // If the Memory Type Information settings have been modified, then reset the platform\r
+      // so the new Memory Type Information setting will be used to guarantee that an S4\r
+      // entry/resume cycle will not fail.\r
+      //\r
+      if (MemoryTypeInformationModified) {\r
+        DEBUG ((EFI_D_INFO, "Memory Type Information settings change. Warm Reset!!!\n"));\r
+        gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);\r
+      }\r
+    } else {\r
+      DEBUG ((EFI_D_ERROR, "Memory Type Information settings cannot be saved. OS S4 may fail!\n"));\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  Set the variable and report the error through status code upon failure.\r
+\r
+  @param  VariableName           A Null-terminated string that is the name of the vendor's variable.\r
+                                 Each VariableName is unique for each VendorGuid. VariableName must\r
+                                 contain 1 or more characters. If VariableName is an empty string,\r
+                                 then EFI_INVALID_PARAMETER is returned.\r
+  @param  VendorGuid             A unique identifier for the vendor.\r
+  @param  Attributes             Attributes bitmask to set for the variable.\r
+  @param  DataSize               The size in bytes of the Data buffer. Unless the EFI_VARIABLE_APPEND_WRITE, \r
+                                 EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, or \r
+                                 EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute is set, a size of zero \r
+                                 causes the variable to be deleted. When the EFI_VARIABLE_APPEND_WRITE attribute is \r
+                                 set, then a SetVariable() call with a DataSize of zero will not cause any change to \r
+                                 the variable value (the timestamp associated with the variable may be updated however \r
+                                 even if no new data value is provided,see the description of the \r
+                                 EFI_VARIABLE_AUTHENTICATION_2 descriptor below. In this case the DataSize will not \r
+                                 be zero since the EFI_VARIABLE_AUTHENTICATION_2 descriptor will be populated). \r
+  @param  Data                   The contents for the variable.\r
+\r
+  @retval EFI_SUCCESS            The firmware has successfully stored the variable and its data as\r
+                                 defined by the Attributes.\r
+  @retval EFI_INVALID_PARAMETER  An invalid combination of attribute bits, name, and GUID was supplied, or the\r
+                                 DataSize exceeds the maximum allowed.\r
+  @retval EFI_INVALID_PARAMETER  VariableName is an empty string.\r
+  @retval EFI_OUT_OF_RESOURCES   Not enough storage is available to hold the variable and its data.\r
+  @retval EFI_DEVICE_ERROR       The variable could not be retrieved due to a hardware error.\r
+  @retval EFI_WRITE_PROTECTED    The variable in question is read-only.\r
+  @retval EFI_WRITE_PROTECTED    The variable in question cannot be deleted.\r
+  @retval EFI_SECURITY_VIOLATION The variable could not be written due to EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS \r
+                                 or EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACESS being set, but the AuthInfo \r
+                                 does NOT pass the validation check carried out by the firmware.\r
+\r
+  @retval EFI_NOT_FOUND          The variable trying to be updated or deleted was not found.\r
+**/\r
+EFI_STATUS\r
+BmSetVariableAndReportStatusCodeOnError (\r
+  IN CHAR16     *VariableName,\r
+  IN EFI_GUID   *VendorGuid,\r
+  IN UINT32     Attributes,\r
+  IN UINTN      DataSize,\r
+  IN VOID       *Data\r
+  )\r
+{\r
+  EFI_STATUS                 Status;\r
+  EDKII_SET_VARIABLE_STATUS  *SetVariableStatus;\r
+  UINTN                      NameSize;\r
+\r
+  Status = gRT->SetVariable (\r
+                  VariableName,\r
+                  VendorGuid,\r
+                  Attributes,\r
+                  DataSize,\r
+                  Data\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    NameSize = StrSize (VariableName);\r
+    SetVariableStatus = AllocatePool (sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + DataSize);\r
+    if (SetVariableStatus != NULL) {\r
+      CopyGuid (&SetVariableStatus->Guid, VendorGuid);\r
+      SetVariableStatus->NameSize   = NameSize;\r
+      SetVariableStatus->DataSize   = DataSize;\r
+      SetVariableStatus->SetStatus  = Status;\r
+      SetVariableStatus->Attributes = Attributes;\r
+      CopyMem (SetVariableStatus + 1,                          VariableName, NameSize);\r
+      CopyMem (((UINT8 *) (SetVariableStatus + 1)) + NameSize, Data,         DataSize);\r
+\r
+      REPORT_STATUS_CODE_EX (\r
+        EFI_ERROR_CODE,\r
+        PcdGet32 (PcdErrorCodeSetVariable),\r
+        0,\r
+        NULL,\r
+        &gEdkiiStatusCodeDataTypeVariableGuid,\r
+        SetVariableStatus,\r
+        sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + DataSize\r
+        );\r
+\r
+      FreePool (SetVariableStatus);\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Print the device path info.\r
+\r
+  @param DevicePath           The device path need to print.\r
+**/\r
+VOID\r
+BmPrintDp (\r
+  EFI_DEVICE_PATH_PROTOCOL            *DevicePath\r
+  )\r
+{\r
+  CHAR16                              *Str;\r
+\r
+  Str = ConvertDevicePathToText (DevicePath, FALSE, FALSE);\r
+  DEBUG ((EFI_D_INFO, "%s", Str));\r
+  if (Str != NULL) {\r
+    FreePool (Str);\r
+  }\r
+}\r
index 1fdb7f1fcb7c18f9da08eff33f9f46cc52e80ca8..32229d0b0a02ba96f6e9eee1e2b355c595167c25 100644 (file)
-/** @file
-  This file include the file which can help to get the system
-  performance, all the function will only include if the performance
-  switch is set.
-
-Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
-This program and the accompanying materials
-are licensed and made available under the terms and conditions of the BSD License
-which accompanies this distribution.  The full text of the license may be found at
-http://opensource.org/licenses/bsd-license.php
-
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
-
-**/
-
-#include "InternalBm.h"
-
-PERF_HEADER               mBmPerfHeader;
-PERF_DATA                 mBmPerfData;
-EFI_PHYSICAL_ADDRESS      mBmAcpiLowMemoryBase = 0x0FFFFFFFFULL;
-
-/**
-  Get the short verion of PDB file name to be
-  used in performance data logging.
-
-  @param PdbFileName     The long PDB file name.
-  @param GaugeString     The output string to be logged by performance logger.
-
-**/
-VOID
-BmGetShortPdbFileName (
-  IN  CONST CHAR8  *PdbFileName,
-  OUT       CHAR8  *GaugeString
-  )
-{
-  UINTN Index;
-  UINTN Index1;
-  UINTN StartIndex;
-  UINTN EndIndex;
-
-  if (PdbFileName == NULL) {
-    AsciiStrCpy (GaugeString, " ");
-  } else {
-    StartIndex = 0;
-    for (EndIndex = 0; PdbFileName[EndIndex] != 0; EndIndex++)
-      ;
-
-    for (Index = 0; PdbFileName[Index] != 0; Index++) {
-      if (PdbFileName[Index] == '\\') {
-        StartIndex = Index + 1;
-      }
-
-      if (PdbFileName[Index] == '.') {
-        EndIndex = Index;
-      }
-    }
-
-    Index1 = 0;
-    for (Index = StartIndex; Index < EndIndex; Index++) {
-      GaugeString[Index1] = PdbFileName[Index];
-      Index1++;
-      if (Index1 == PERF_TOKEN_LENGTH - 1) {
-        break;
-      }
-    }
-
-    GaugeString[Index1] = 0;
-  }
-
-  return ;
-}
-
-/**
-  Get the name from the Driver handle, which can be a handle with
-  EFI_LOADED_IMAGE_PROTOCOL or EFI_DRIVER_BINDING_PROTOCOL installed.
-  This name can be used in performance data logging.
-
-  @param Handle          Driver handle.
-  @param GaugeString     The output string to be logged by performance logger.
-
-**/
-VOID
-BmGetNameFromHandle (
-  IN  EFI_HANDLE     Handle,
-  OUT CHAR8          *GaugeString
-  )
-{
-  EFI_STATUS                  Status;
-  EFI_LOADED_IMAGE_PROTOCOL   *Image;
-  CHAR8                       *PdbFileName;
-  EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
-
-  AsciiStrCpy (GaugeString, " ");
-
-  //
-  // Get handle name from image protocol
-  //
-  Status = gBS->HandleProtocol (
-                  Handle,
-                  &gEfiLoadedImageProtocolGuid,
-                  (VOID **) &Image
-                  );
-
-  if (EFI_ERROR (Status)) {
-    Status = gBS->OpenProtocol (
-                    Handle,
-                    &gEfiDriverBindingProtocolGuid,
-                    (VOID **) &DriverBinding,
-                    NULL,
-                    NULL,
-                    EFI_OPEN_PROTOCOL_GET_PROTOCOL
-                    );
-    if (EFI_ERROR (Status)) {
-      return ;
-    }
-    //
-    // Get handle name from image protocol
-    //
-    Status = gBS->HandleProtocol (
-                    DriverBinding->ImageHandle,
-                    &gEfiLoadedImageProtocolGuid,
-                    (VOID **) &Image
-                    );
-  }
-
-  PdbFileName = PeCoffLoaderGetPdbPointer (Image->ImageBase);
-
-  if (PdbFileName != NULL) {
-    BmGetShortPdbFileName (PdbFileName, GaugeString);
-  }
-
-  return ;
-}
-
-/**
-
-  Writes performance data of booting into the allocated memory.
-  OS can process these records.
-
-  @param  Event                 The triggered event.
-  @param  Context               Context for this event.
-
-**/
-VOID
-EFIAPI
-BmWriteBootToOsPerformanceData (
-  IN EFI_EVENT  Event,
-  IN VOID       *Context
-  )
-{
-  EFI_STATUS                Status;
-  UINT32                    LimitCount;
-  EFI_HANDLE                *Handles;
-  UINTN                     NoHandles;
-  CHAR8                     GaugeString[PERF_TOKEN_LENGTH];
-  UINT8                     *Ptr;
-  UINT32                    Index;
-  UINT64                    Ticker;
-  UINT64                    Freq;
-  UINT32                    Duration;
-  UINTN                     LogEntryKey;
-  CONST VOID                *Handle;
-  CONST CHAR8               *Token;
-  CONST CHAR8               *Module;
-  UINT64                    StartTicker;
-  UINT64                    EndTicker;
-  UINT64                    StartValue;
-  UINT64                    EndValue;
-  BOOLEAN                   CountUp;
-  UINTN                     EntryIndex;
-  UINTN                     NumPerfEntries;
-  //
-  // List of flags indicating PerfEntry contains DXE handle
-  //
-  BOOLEAN                   *PerfEntriesAsDxeHandle;
-  UINTN                     VarSize;
-
-  //
-  // Record the performance data for End of BDS
-  //
-  PERF_END(NULL, "BDS", NULL, 0);
-
-  //
-  // Retrieve time stamp count as early as possible
-  //
-  Ticker  = GetPerformanceCounter ();
-
-  Freq    = GetPerformanceCounterProperties (&StartValue, &EndValue);
-  
-  Freq    = DivU64x32 (Freq, 1000);
-
-  mBmPerfHeader.CpuFreq = Freq;
-
-  //
-  // Record BDS raw performance data
-  //
-  if (EndValue >= StartValue) {
-    mBmPerfHeader.BDSRaw = Ticker - StartValue;
-    CountUp            = TRUE;
-  } else {
-    mBmPerfHeader.BDSRaw = StartValue - Ticker;
-    CountUp            = FALSE;
-  }
-
-  if (mBmAcpiLowMemoryBase == 0x0FFFFFFFF) {
-    VarSize = sizeof (EFI_PHYSICAL_ADDRESS);
-    Status = gRT->GetVariable (
-                    L"PerfDataMemAddr",
-                    &gPerformanceProtocolGuid,
-                    NULL,
-                    &VarSize,
-                    &mBmAcpiLowMemoryBase
-                    );
-    if (EFI_ERROR (Status)) {
-      //
-      // Fail to get the variable, return.
-      //
-      return;
-    }
-  }
-
-  //
-  // Put Detailed performance data into memory
-  //
-  Handles = NULL;
-  Status = gBS->LocateHandleBuffer (
-                  AllHandles,
-                  NULL,
-                  NULL,
-                  &NoHandles,
-                  &Handles
-                  );
-  if (EFI_ERROR (Status)) {
-    return ;
-  }
-
-  Ptr        = (UINT8 *) ((UINT32) mBmAcpiLowMemoryBase + sizeof (PERF_HEADER));
-  LimitCount = (UINT32) (PERF_DATA_MAX_LENGTH - sizeof (PERF_HEADER)) / sizeof (PERF_DATA);
-
-  NumPerfEntries = 0;
-  LogEntryKey    = 0;
-  while ((LogEntryKey = GetPerformanceMeasurement (
-                          LogEntryKey,
-                          &Handle,
-                          &Token,
-                          &Module,
-                          &StartTicker,
-                          &EndTicker)) != 0) {
-    NumPerfEntries++;
-  }
-  PerfEntriesAsDxeHandle = AllocateZeroPool (NumPerfEntries * sizeof (BOOLEAN));
-  ASSERT (PerfEntriesAsDxeHandle != NULL);
-  
-  //
-  // Get DXE drivers performance
-  //
-  for (Index = 0; Index < NoHandles; Index++) {
-    Ticker = 0;
-    LogEntryKey = 0;
-    EntryIndex  = 0;
-    while ((LogEntryKey = GetPerformanceMeasurement (
-                            LogEntryKey,
-                            &Handle,
-                            &Token,
-                            &Module,
-                            &StartTicker,
-                            &EndTicker)) != 0) {
-      if (Handle == Handles[Index] && !PerfEntriesAsDxeHandle[EntryIndex]) {
-        PerfEntriesAsDxeHandle[EntryIndex] = TRUE;
-      }
-      EntryIndex++;
-      if ((Handle == Handles[Index]) && (EndTicker != 0)) {
-        if (StartTicker == 1) {
-          StartTicker = StartValue;
-        }
-        if (EndTicker == 1) {
-          EndTicker = StartValue;
-        }
-        Ticker += CountUp ? (EndTicker - StartTicker) : (StartTicker - EndTicker);
-      }
-    }
-
-    Duration = (UINT32) DivU64x32 (Ticker, (UINT32) Freq);
-
-    if (Duration > 0) {
-
-      BmGetNameFromHandle (Handles[Index], GaugeString);
-
-      AsciiStrCpy (mBmPerfData.Token, GaugeString);
-      mBmPerfData.Duration = Duration;
-
-      CopyMem (Ptr, &mBmPerfData, sizeof (PERF_DATA));
-      Ptr += sizeof (PERF_DATA);
-
-      mBmPerfHeader.Count++;
-      if (mBmPerfHeader.Count == LimitCount) {
-        goto Done;
-      }
-    }
-  }
-
-  //
-  // Get inserted performance data
-  //
-  LogEntryKey = 0;
-  EntryIndex  = 0;
-  while ((LogEntryKey = GetPerformanceMeasurement (
-                          LogEntryKey,
-                          &Handle,
-                          &Token,
-                          &Module,
-                          &StartTicker,
-                          &EndTicker)) != 0) {
-    if (!PerfEntriesAsDxeHandle[EntryIndex] && EndTicker != 0) {
-
-      ZeroMem (&mBmPerfData, sizeof (PERF_DATA));
-
-      AsciiStrnCpy (mBmPerfData.Token, Token, PERF_TOKEN_LENGTH);
-      if (StartTicker == 1) {
-        StartTicker = StartValue;
-      }
-      if (EndTicker == 1) {
-        EndTicker = StartValue;
-      }
-      Ticker = CountUp ? (EndTicker - StartTicker) : (StartTicker - EndTicker);
-
-      mBmPerfData.Duration = (UINT32) DivU64x32 (Ticker, (UINT32) Freq);
-
-      CopyMem (Ptr, &mBmPerfData, sizeof (PERF_DATA));
-      Ptr += sizeof (PERF_DATA);
-
-      mBmPerfHeader.Count++;
-      if (mBmPerfHeader.Count == LimitCount) {
-        goto Done;
-      }
-    }
-    EntryIndex++;
-  }
-
-Done:
-
-  FreePool (Handles);
-  FreePool (PerfEntriesAsDxeHandle);
-
-  mBmPerfHeader.Signiture = PERFORMANCE_SIGNATURE;
-
-  //
-  // Put performance data to Reserved memory
-  //
-  CopyMem (
-    (UINTN *) (UINTN) mBmAcpiLowMemoryBase,
-    &mBmPerfHeader,
-    sizeof (PERF_HEADER)
-    );
-
-  return ;
-}
+/** @file\r
+  This file include the file which can help to get the system\r
+  performance, all the function will only include if the performance\r
+  switch is set.\r
+\r
+Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "InternalBm.h"\r
+\r
+PERF_HEADER               mBmPerfHeader;\r
+PERF_DATA                 mBmPerfData;\r
+EFI_PHYSICAL_ADDRESS      mBmAcpiLowMemoryBase = 0x0FFFFFFFFULL;\r
+\r
+/**\r
+  Get the short verion of PDB file name to be\r
+  used in performance data logging.\r
+\r
+  @param PdbFileName     The long PDB file name.\r
+  @param GaugeString     The output string to be logged by performance logger.\r
+\r
+**/\r
+VOID\r
+BmGetShortPdbFileName (\r
+  IN  CONST CHAR8  *PdbFileName,\r
+  OUT       CHAR8  *GaugeString\r
+  )\r
+{\r
+  UINTN Index;\r
+  UINTN Index1;\r
+  UINTN StartIndex;\r
+  UINTN EndIndex;\r
+\r
+  if (PdbFileName == NULL) {\r
+    AsciiStrCpy (GaugeString, " ");\r
+  } else {\r
+    StartIndex = 0;\r
+    for (EndIndex = 0; PdbFileName[EndIndex] != 0; EndIndex++)\r
+      ;\r
+\r
+    for (Index = 0; PdbFileName[Index] != 0; Index++) {\r
+      if (PdbFileName[Index] == '\\') {\r
+        StartIndex = Index + 1;\r
+      }\r
+\r
+      if (PdbFileName[Index] == '.') {\r
+        EndIndex = Index;\r
+      }\r
+    }\r
+\r
+    Index1 = 0;\r
+    for (Index = StartIndex; Index < EndIndex; Index++) {\r
+      GaugeString[Index1] = PdbFileName[Index];\r
+      Index1++;\r
+      if (Index1 == PERF_TOKEN_LENGTH - 1) {\r
+        break;\r
+      }\r
+    }\r
+\r
+    GaugeString[Index1] = 0;\r
+  }\r
+\r
+  return ;\r
+}\r
+\r
+/**\r
+  Get the name from the Driver handle, which can be a handle with\r
+  EFI_LOADED_IMAGE_PROTOCOL or EFI_DRIVER_BINDING_PROTOCOL installed.\r
+  This name can be used in performance data logging.\r
+\r
+  @param Handle          Driver handle.\r
+  @param GaugeString     The output string to be logged by performance logger.\r
+\r
+**/\r
+VOID\r
+BmGetNameFromHandle (\r
+  IN  EFI_HANDLE     Handle,\r
+  OUT CHAR8          *GaugeString\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  EFI_LOADED_IMAGE_PROTOCOL   *Image;\r
+  CHAR8                       *PdbFileName;\r
+  EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;\r
+\r
+  AsciiStrCpy (GaugeString, " ");\r
+\r
+  //\r
+  // Get handle name from image protocol\r
+  //\r
+  Status = gBS->HandleProtocol (\r
+                  Handle,\r
+                  &gEfiLoadedImageProtocolGuid,\r
+                  (VOID **) &Image\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    Status = gBS->OpenProtocol (\r
+                    Handle,\r
+                    &gEfiDriverBindingProtocolGuid,\r
+                    (VOID **) &DriverBinding,\r
+                    NULL,\r
+                    NULL,\r
+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      return ;\r
+    }\r
+    //\r
+    // Get handle name from image protocol\r
+    //\r
+    Status = gBS->HandleProtocol (\r
+                    DriverBinding->ImageHandle,\r
+                    &gEfiLoadedImageProtocolGuid,\r
+                    (VOID **) &Image\r
+                    );\r
+  }\r
+\r
+  PdbFileName = PeCoffLoaderGetPdbPointer (Image->ImageBase);\r
+\r
+  if (PdbFileName != NULL) {\r
+    BmGetShortPdbFileName (PdbFileName, GaugeString);\r
+  }\r
+\r
+  return ;\r
+}\r
+\r
+/**\r
+\r
+  Writes performance data of booting into the allocated memory.\r
+  OS can process these records.\r
+\r
+  @param  Event                 The triggered event.\r
+  @param  Context               Context for this event.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+BmWriteBootToOsPerformanceData (\r
+  IN EFI_EVENT  Event,\r
+  IN VOID       *Context\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  UINT32                    LimitCount;\r
+  EFI_HANDLE                *Handles;\r
+  UINTN                     NoHandles;\r
+  CHAR8                     GaugeString[PERF_TOKEN_LENGTH];\r
+  UINT8                     *Ptr;\r
+  UINT32                    Index;\r
+  UINT64                    Ticker;\r
+  UINT64                    Freq;\r
+  UINT32                    Duration;\r
+  UINTN                     LogEntryKey;\r
+  CONST VOID                *Handle;\r
+  CONST CHAR8               *Token;\r
+  CONST CHAR8               *Module;\r
+  UINT64                    StartTicker;\r
+  UINT64                    EndTicker;\r
+  UINT64                    StartValue;\r
+  UINT64                    EndValue;\r
+  BOOLEAN                   CountUp;\r
+  UINTN                     EntryIndex;\r
+  UINTN                     NumPerfEntries;\r
+  //\r
+  // List of flags indicating PerfEntry contains DXE handle\r
+  //\r
+  BOOLEAN                   *PerfEntriesAsDxeHandle;\r
+  UINTN                     VarSize;\r
+\r
+  //\r
+  // Record the performance data for End of BDS\r
+  //\r
+  PERF_END(NULL, "BDS", NULL, 0);\r
+\r
+  //\r
+  // Retrieve time stamp count as early as possible\r
+  //\r
+  Ticker  = GetPerformanceCounter ();\r
+\r
+  Freq    = GetPerformanceCounterProperties (&StartValue, &EndValue);\r
+  \r
+  Freq    = DivU64x32 (Freq, 1000);\r
+\r
+  mBmPerfHeader.CpuFreq = Freq;\r
+\r
+  //\r
+  // Record BDS raw performance data\r
+  //\r
+  if (EndValue >= StartValue) {\r
+    mBmPerfHeader.BDSRaw = Ticker - StartValue;\r
+    CountUp            = TRUE;\r
+  } else {\r
+    mBmPerfHeader.BDSRaw = StartValue - Ticker;\r
+    CountUp            = FALSE;\r
+  }\r
+\r
+  if (mBmAcpiLowMemoryBase == 0x0FFFFFFFF) {\r
+    VarSize = sizeof (EFI_PHYSICAL_ADDRESS);\r
+    Status = gRT->GetVariable (\r
+                    L"PerfDataMemAddr",\r
+                    &gPerformanceProtocolGuid,\r
+                    NULL,\r
+                    &VarSize,\r
+                    &mBmAcpiLowMemoryBase\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      //\r
+      // Fail to get the variable, return.\r
+      //\r
+      return;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Put Detailed performance data into memory\r
+  //\r
+  Handles = NULL;\r
+  Status = gBS->LocateHandleBuffer (\r
+                  AllHandles,\r
+                  NULL,\r
+                  NULL,\r
+                  &NoHandles,\r
+                  &Handles\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return ;\r
+  }\r
+\r
+  Ptr        = (UINT8 *) ((UINT32) mBmAcpiLowMemoryBase + sizeof (PERF_HEADER));\r
+  LimitCount = (UINT32) (PERF_DATA_MAX_LENGTH - sizeof (PERF_HEADER)) / sizeof (PERF_DATA);\r
+\r
+  NumPerfEntries = 0;\r
+  LogEntryKey    = 0;\r
+  while ((LogEntryKey = GetPerformanceMeasurement (\r
+                          LogEntryKey,\r
+                          &Handle,\r
+                          &Token,\r
+                          &Module,\r
+                          &StartTicker,\r
+                          &EndTicker)) != 0) {\r
+    NumPerfEntries++;\r
+  }\r
+  PerfEntriesAsDxeHandle = AllocateZeroPool (NumPerfEntries * sizeof (BOOLEAN));\r
+  ASSERT (PerfEntriesAsDxeHandle != NULL);\r
+  \r
+  //\r
+  // Get DXE drivers performance\r
+  //\r
+  for (Index = 0; Index < NoHandles; Index++) {\r
+    Ticker = 0;\r
+    LogEntryKey = 0;\r
+    EntryIndex  = 0;\r
+    while ((LogEntryKey = GetPerformanceMeasurement (\r
+                            LogEntryKey,\r
+                            &Handle,\r
+                            &Token,\r
+                            &Module,\r
+                            &StartTicker,\r
+                            &EndTicker)) != 0) {\r
+      if (Handle == Handles[Index] && !PerfEntriesAsDxeHandle[EntryIndex]) {\r
+        PerfEntriesAsDxeHandle[EntryIndex] = TRUE;\r
+      }\r
+      EntryIndex++;\r
+      if ((Handle == Handles[Index]) && (EndTicker != 0)) {\r
+        if (StartTicker == 1) {\r
+          StartTicker = StartValue;\r
+        }\r
+        if (EndTicker == 1) {\r
+          EndTicker = StartValue;\r
+        }\r
+        Ticker += CountUp ? (EndTicker - StartTicker) : (StartTicker - EndTicker);\r
+      }\r
+    }\r
+\r
+    Duration = (UINT32) DivU64x32 (Ticker, (UINT32) Freq);\r
+\r
+    if (Duration > 0) {\r
+\r
+      BmGetNameFromHandle (Handles[Index], GaugeString);\r
+\r
+      AsciiStrCpy (mBmPerfData.Token, GaugeString);\r
+      mBmPerfData.Duration = Duration;\r
+\r
+      CopyMem (Ptr, &mBmPerfData, sizeof (PERF_DATA));\r
+      Ptr += sizeof (PERF_DATA);\r
+\r
+      mBmPerfHeader.Count++;\r
+      if (mBmPerfHeader.Count == LimitCount) {\r
+        goto Done;\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // Get inserted performance data\r
+  //\r
+  LogEntryKey = 0;\r
+  EntryIndex  = 0;\r
+  while ((LogEntryKey = GetPerformanceMeasurement (\r
+                          LogEntryKey,\r
+                          &Handle,\r
+                          &Token,\r
+                          &Module,\r
+                          &StartTicker,\r
+                          &EndTicker)) != 0) {\r
+    if (!PerfEntriesAsDxeHandle[EntryIndex] && EndTicker != 0) {\r
+\r
+      ZeroMem (&mBmPerfData, sizeof (PERF_DATA));\r
+\r
+      AsciiStrnCpy (mBmPerfData.Token, Token, PERF_TOKEN_LENGTH);\r
+      if (StartTicker == 1) {\r
+        StartTicker = StartValue;\r
+      }\r
+      if (EndTicker == 1) {\r
+        EndTicker = StartValue;\r
+      }\r
+      Ticker = CountUp ? (EndTicker - StartTicker) : (StartTicker - EndTicker);\r
+\r
+      mBmPerfData.Duration = (UINT32) DivU64x32 (Ticker, (UINT32) Freq);\r
+\r
+      CopyMem (Ptr, &mBmPerfData, sizeof (PERF_DATA));\r
+      Ptr += sizeof (PERF_DATA);\r
+\r
+      mBmPerfHeader.Count++;\r
+      if (mBmPerfHeader.Count == LimitCount) {\r
+        goto Done;\r
+      }\r
+    }\r
+    EntryIndex++;\r
+  }\r
+\r
+Done:\r
+\r
+  FreePool (Handles);\r
+  FreePool (PerfEntriesAsDxeHandle);\r
+\r
+  mBmPerfHeader.Signiture = PERFORMANCE_SIGNATURE;\r
+\r
+  //\r
+  // Put performance data to Reserved memory\r
+  //\r
+  CopyMem (\r
+    (UINTN *) (UINTN) mBmAcpiLowMemoryBase,\r
+    &mBmPerfHeader,\r
+    sizeof (PERF_HEADER)\r
+    );\r
+\r
+  return ;\r
+}\r
index c362d8d7cc8a52a79173ff61a134cbd7ce554b98..8e8534dd4d472f075b441c687822f72e9a46b772 100644 (file)
-/** @file
-  BDS library definition, include the file and data structure
-
-Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
-This program and the accompanying materials
-are licensed and made available under the terms and conditions of the BSD License
-which accompanies this distribution.  The full text of the license may be found at
-http://opensource.org/licenses/bsd-license.php
-
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
-
-**/
-
-#ifndef _INTERNAL_BM_H_
-#define _INTERNAL_BM_H_
-
-#include <PiDxe.h>
-
-#include <IndustryStandard/Pci.h>
-#include <IndustryStandard/PeImage.h>
-#include <IndustryStandard/Atapi.h>
-#include <IndustryStandard/Scsi.h>
-
-#include <Protocol/PciRootBridgeIo.h>
-#include <Protocol/BlockIo.h>
-#include <Protocol/LoadedImage.h>
-#include <Protocol/SimpleFileSystem.h>
-#include <Protocol/LoadFile.h>
-#include <Protocol/DevicePath.h>
-#include <Protocol/SimpleTextIn.h>
-#include <Protocol/SimpleTextInEx.h>
-#include <Protocol/SimpleTextOut.h>
-#include <Protocol/SimpleNetwork.h>
-#include <Protocol/FirmwareVolume2.h>
-#include <Protocol/PciIo.h>
-#include <Protocol/GraphicsOutput.h>
-#include <Protocol/UsbIo.h>
-#include <Protocol/DiskInfo.h>
-#include <Protocol/IdeControllerInit.h>
-#include <Protocol/BootLogo.h>
-#include <Protocol/DriverHealth.h>
-#include <Protocol/FormBrowser2.h>
-
-#include <Guid/ZeroGuid.h>
-#include <Guid/MemoryTypeInformation.h>
-#include <Guid/FileInfo.h>
-#include <Guid/GlobalVariable.h>
-#include <Guid/Performance.h>
-#include <Guid/StatusCodeDataTypeVariable.h>
-
-#include <Library/PrintLib.h>
-#include <Library/DebugLib.h>
-#include <Library/BaseMemoryLib.h>
-#include <Library/UefiBootServicesTableLib.h>
-#include <Library/UefiRuntimeServicesTableLib.h>
-#include <Library/UefiLib.h>
-#include <Library/MemoryAllocationLib.h>
-#include <Library/DxeServicesTableLib.h>
-#include <Library/HobLib.h>
-#include <Library/BaseLib.h>
-#include <Library/DevicePathLib.h>
-#include <Library/PerformanceLib.h>
-#include <Library/PcdLib.h>
-#include <Library/PeCoffGetEntryPointLib.h>
-#include <Library/UefiBootManagerLib.h>
-#include <Library/TimerLib.h>
-#include <Library/DxeServicesLib.h>
-#include <Library/ReportStatusCodeLib.h>
-#include <Library/CapsuleLib.h>
-#include <Library/PerformanceLib.h>
-#include <Library/HiiLib.h>
-
-#if !defined (EFI_REMOVABLE_MEDIA_FILE_NAME)
-    #if defined (MDE_CPU_EBC)
-        //
-        // Uefi specification only defines the default boot file name for IA32, X64
-        // and IPF processor, so need define boot file name for EBC architecture here.
-        //
-        #define EFI_REMOVABLE_MEDIA_FILE_NAME L"\\EFI\\BOOT\\BOOTEBC.EFI"
-    #else
-        #error "Can not determine the default boot file name for unknown processor type!"
-    #endif
-#endif
-
-typedef enum {
-  BmAcpiFloppyBoot,
-  BmHardwareDeviceBoot,
-  BmMessageAtapiBoot,
-  BmMessageSataBoot,
-  BmMessageUsbBoot,
-  BmMessageScsiBoot,
-  BmMessageNetworkBoot,
-  BmMiscBoot
-} BM_BOOT_TYPE;
-
-typedef
-CHAR16 *
-(* BM_GET_BOOT_DESCRIPTION) (
-  IN EFI_HANDLE          Handle
-  );
-
-#define BM_OPTION_NAME_LEN                          sizeof ("SysPrep####")
-extern CHAR16  *mBmLoadOptionName[];
-
-typedef
-VOID
-(*VARIABLE_VISITOR) (
-  CHAR16                *Name,
-  EFI_GUID              *Guid,
-  VOID                  *Context
-  );
-
-/**
-  Call Visitor function for each variable in variable storage.
-
-  @param Visitor   Visitor function.
-  @param Context   The context passed to Visitor function.
-**/
-VOID
-ForEachVariable (
-  VARIABLE_VISITOR            Visitor,
-  VOID                        *Context
-  );
-
-/**
-  Repair all the controllers according to the Driver Health status queried.
-**/
-VOID
-BmRepairAllControllers (
-  VOID
-  );
-
-#define BM_HOTKEY_SIGNATURE SIGNATURE_32 ('b', 'm', 'h', 'k')
-typedef struct {
-  UINT32                    Signature;
-  LIST_ENTRY                Link;
-
-  BOOLEAN                   IsContinue;
-  UINT16                    BootOption;
-  UINT8                     CodeCount;
-  UINT8                     WaitingKey;
-  EFI_KEY_DATA              KeyData[3];
-} BM_HOTKEY;
-
-#define BM_HOTKEY_FROM_LINK(a) CR (a, BM_HOTKEY, Link, BM_HOTKEY_SIGNATURE)
-
-/**
-  Get the image file buffer data and buffer size by its device path. 
-
-  @param FilePath  On input, a pointer to an allocated buffer containing the device
-                   path of the file.
-                   On output the pointer could be NULL when the function fails to
-                   load the boot option, or could point to an allocated buffer containing
-                   the device path of the file.
-                   It could be updated by either short-form device path expanding,
-                   or default boot file path appending.
-                   Caller is responsible to free it when it's non-NULL.
-  @param FileSize  A pointer to the size of the file buffer.
-
-  @retval NULL   File is NULL, or FileSize is NULL. Or, the file can't be found.
-  @retval other  The file buffer. The caller is responsible to free the memory.
-**/
-VOID *
-BmLoadEfiBootOption (
-  IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath,
-  OUT    UINTN                    *FileSize
-  );
-
-/**
-  Get the Option Number that wasn't used.
-
-  @param  LoadOptionType      Load option type.
-  @param  FreeOptionNumber    To receive the minimal free option number.
-
-  @retval EFI_SUCCESS           The option number is found
-  @retval EFI_OUT_OF_RESOURCES  There is no free option number that can be used.
-  @retval EFI_INVALID_PARAMETER FreeOptionNumber is NULL
-
-**/
-EFI_STATUS
-BmGetFreeOptionNumber (
-  IN  EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType,
-  OUT UINT16                            *FreeOptionNumber
-  );
-
-/**
-
-  Writes performance data of booting into the allocated memory.
-  OS can process these records.
-
-  @param  Event                 The triggered event.
-  @param  Context               Context for this event.
-
-**/
-VOID
-EFIAPI
-BmWriteBootToOsPerformanceData (
-  IN EFI_EVENT  Event,
-  IN VOID       *Context
-  );
-
-
-/**
-  Get the headers (dos, image, optional header) from an image
-
-  @param  Device                SimpleFileSystem device handle
-  @param  FileName              File name for the image
-  @param  DosHeader             Pointer to dos header
-  @param  Hdr                   The buffer in which to return the PE32, PE32+, or TE header.
-
-  @retval EFI_SUCCESS           Successfully get the machine type.
-  @retval EFI_NOT_FOUND         The file is not found.
-  @retval EFI_LOAD_ERROR        File is not a valid image file.
-
-**/
-EFI_STATUS
-BmGetImageHeader (
-  IN  EFI_HANDLE                  Device,
-  IN  CHAR16                      *FileName,
-  OUT EFI_IMAGE_DOS_HEADER        *DosHeader,
-  OUT EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION   Hdr
-  );
-
-/**
-  This routine adjust the memory information for different memory type and 
-  save them into the variables for next boot.
-**/
-VOID
-BmSetMemoryTypeInformationVariable (
-  VOID
-  );
-
-/**
-  Check whether there is a instance in BlockIoDevicePath, which contain multi device path
-  instances, has the same partition node with HardDriveDevicePath device path
-
-  @param  BlockIoDevicePath      Multi device path instances which need to check
-  @param  HardDriveDevicePath    A device path which starts with a hard drive media
-                                 device path.
-
-  @retval TRUE                   There is a matched device path instance.
-  @retval FALSE                  There is no matched device path instance.
-
-**/
-BOOLEAN
-BmMatchPartitionDevicePathNode (
-  IN  EFI_DEVICE_PATH_PROTOCOL   *BlockIoDevicePath,
-  IN  HARDDRIVE_DEVICE_PATH      *HardDriveDevicePath
-  );
-
-/**
-  Connect the specific Usb device which match the short form device path.
-
-  @param  DevicePath             A short-form device path that starts with the first
-                                 element being a USB WWID or a USB Class device
-                                 path
-
-  @return EFI_INVALID_PARAMETER  DevicePath is NULL pointer.
-                                 DevicePath is not a USB device path.
-
-  @return EFI_SUCCESS            Success to connect USB device
-  @return EFI_NOT_FOUND          Fail to find handle for USB controller to connect.
-
-**/
-EFI_STATUS
-BmConnectUsbShortFormDevicePath (
-  IN EFI_DEVICE_PATH_PROTOCOL   *DevicePath
-  );
-
-/**
-  Stop the hotkey processing.
-  
-  @param    Event          Event pointer related to hotkey service. 
-  @param    Context        Context pass to this function. 
-**/
-VOID
-EFIAPI
-BmStopHotkeyService (
-  IN EFI_EVENT    Event,
-  IN VOID         *Context
-  );
-
-/**
-  Set the variable and report the error through status code upon failure.
-
-  @param  VariableName           A Null-terminated string that is the name of the vendor's variable.
-                                 Each VariableName is unique for each VendorGuid. VariableName must
-                                 contain 1 or more characters. If VariableName is an empty string,
-                                 then EFI_INVALID_PARAMETER is returned.
-  @param  VendorGuid             A unique identifier for the vendor.
-  @param  Attributes             Attributes bitmask to set for the variable.
-  @param  DataSize               The size in bytes of the Data buffer. Unless the EFI_VARIABLE_APPEND_WRITE, 
-                                 EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, or 
-                                 EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute is set, a size of zero 
-                                 causes the variable to be deleted. When the EFI_VARIABLE_APPEND_WRITE attribute is 
-                                 set, then a SetVariable() call with a DataSize of zero will not cause any change to 
-                                 the variable value (the timestamp associated with the variable may be updated however 
-                                 even if no new data value is provided,see the description of the 
-                                 EFI_VARIABLE_AUTHENTICATION_2 descriptor below. In this case the DataSize will not 
-                                 be zero since the EFI_VARIABLE_AUTHENTICATION_2 descriptor will be populated). 
-  @param  Data                   The contents for the variable.
-
-  @retval EFI_SUCCESS            The firmware has successfully stored the variable and its data as
-                                 defined by the Attributes.
-  @retval EFI_INVALID_PARAMETER  An invalid combination of attribute bits, name, and GUID was supplied, or the
-                                 DataSize exceeds the maximum allowed.
-  @retval EFI_INVALID_PARAMETER  VariableName is an empty string.
-  @retval EFI_OUT_OF_RESOURCES   Not enough storage is available to hold the variable and its data.
-  @retval EFI_DEVICE_ERROR       The variable could not be retrieved due to a hardware error.
-  @retval EFI_WRITE_PROTECTED    The variable in question is read-only.
-  @retval EFI_WRITE_PROTECTED    The variable in question cannot be deleted.
-  @retval EFI_SECURITY_VIOLATION The variable could not be written due to EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS 
-                                 or EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACESS being set, but the AuthInfo 
-                                 does NOT pass the validation check carried out by the firmware.
-
-  @retval EFI_NOT_FOUND          The variable trying to be updated or deleted was not found.
-**/
-EFI_STATUS
-BmSetVariableAndReportStatusCodeOnError (
-  IN CHAR16     *VariableName,
-  IN EFI_GUID   *VendorGuid,
-  IN UINT32     Attributes,
-  IN UINTN      DataSize,
-  IN VOID       *Data
-  );
-
-/**
-  Get the load option by its device path.
-
-  @param FilePath  The device path pointing to a load option.
-                   It could be a short-form device path.
-  @param FullPath  Return the full device path of the load option after
-                   short-form device path expanding.
-                   Caller is responsible to free it.
-  @param FileSize  Return the load option size.
-
-  @return The load option buffer. Caller is responsible to free the memory.
-**/
-VOID *
-BmGetLoadOptionBuffer (
-  IN  EFI_DEVICE_PATH_PROTOCOL          *FilePath,
-  OUT EFI_DEVICE_PATH_PROTOCOL          **FullPath,
-  OUT UINTN                             *FileSize
-  );
-
-/**
-  Return whether the PE header of the load option is valid or not.
-
-  @param[in] Type       The load option type.
-  @param[in] FileBuffer The PE file buffer of the load option.
-  @param[in] FileSize   The size of the load option file.
-
-  @retval TRUE  The PE header of the load option is valid.
-  @retval FALSE The PE header of the load option is not valid.
-**/
-BOOLEAN
-BmIsLoadOptionPeHeaderValid (
-  IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE Type,
-  IN VOID                              *FileBuffer,
-  IN UINTN                             FileSize
-  );
-
-/**
-  Function compares a device path data structure to that of all the nodes of a
-  second device path instance.
-
-  @param  Multi                 A pointer to a multi-instance device path data
-                                structure.
-  @param  Single                A pointer to a single-instance device path data
-                                structure.
-
-  @retval TRUE                  If the Single device path is contained within Multi device path.
-  @retval FALSE                 The Single device path is not match within Multi device path.
-
-**/
-BOOLEAN
-BmMatchDevicePaths (
-  IN  EFI_DEVICE_PATH_PROTOCOL  *Multi,
-  IN  EFI_DEVICE_PATH_PROTOCOL  *Single
-  );
-
-/**
-  Delete the instance in Multi which matches partly with Single instance
-
-  @param  Multi                 A pointer to a multi-instance device path data
-                                structure.
-  @param  Single                A pointer to a single-instance device path data
-                                structure.
-
-  @return This function will remove the device path instances in Multi which partly
-          match with the Single, and return the result device path. If there is no
-          remaining device path as a result, this function will return NULL.
-
-**/
-EFI_DEVICE_PATH_PROTOCOL *
-BmDelPartMatchInstance (
-  IN     EFI_DEVICE_PATH_PROTOCOL  *Multi,
-  IN     EFI_DEVICE_PATH_PROTOCOL  *Single
-  );
-
-
-/**
-  Return the index of the load option in the load option array.
-
-  The function consider two load options are equal when the 
-  OptionType, Attributes, Description, FilePath and OptionalData are equal.
-
-  @param Key    Pointer to the load option to be found.
-  @param Array  Pointer to the array of load options to be found.
-  @param Count  Number of entries in the Array.
-
-  @retval -1          Key wasn't found in the Array.
-  @retval 0 ~ Count-1 The index of the Key in the Array.
-**/
-INTN
-BmFindLoadOption (
-  IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Key,
-  IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Array,
-  IN UINTN                              Count
-  );
-
-/**
-  Repair all the controllers according to the Driver Health status queried.
-**/
-VOID
-BmRepairAllControllers (
-  VOID
-  );
-
-/**
-  Print the device path info.
-
-  @param DevicePath           The device path need to print.
-**/
-VOID
-BmPrintDp (
-  EFI_DEVICE_PATH_PROTOCOL            *DevicePath
-  );
-
-#endif // _INTERNAL_BM_H_
+/** @file\r
+  BDS library definition, include the file and data structure\r
+\r
+Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _INTERNAL_BM_H_\r
+#define _INTERNAL_BM_H_\r
+\r
+#include <PiDxe.h>\r
+\r
+#include <IndustryStandard/Pci.h>\r
+#include <IndustryStandard/PeImage.h>\r
+#include <IndustryStandard/Atapi.h>\r
+#include <IndustryStandard/Scsi.h>\r
+\r
+#include <Protocol/PciRootBridgeIo.h>\r
+#include <Protocol/BlockIo.h>\r
+#include <Protocol/LoadedImage.h>\r
+#include <Protocol/SimpleFileSystem.h>\r
+#include <Protocol/LoadFile.h>\r
+#include <Protocol/DevicePath.h>\r
+#include <Protocol/SimpleTextIn.h>\r
+#include <Protocol/SimpleTextInEx.h>\r
+#include <Protocol/SimpleTextOut.h>\r
+#include <Protocol/SimpleNetwork.h>\r
+#include <Protocol/FirmwareVolume2.h>\r
+#include <Protocol/PciIo.h>\r
+#include <Protocol/GraphicsOutput.h>\r
+#include <Protocol/UsbIo.h>\r
+#include <Protocol/DiskInfo.h>\r
+#include <Protocol/IdeControllerInit.h>\r
+#include <Protocol/BootLogo.h>\r
+#include <Protocol/DriverHealth.h>\r
+#include <Protocol/FormBrowser2.h>\r
+\r
+#include <Guid/ZeroGuid.h>\r
+#include <Guid/MemoryTypeInformation.h>\r
+#include <Guid/FileInfo.h>\r
+#include <Guid/GlobalVariable.h>\r
+#include <Guid/Performance.h>\r
+#include <Guid/StatusCodeDataTypeVariable.h>\r
+\r
+#include <Library/PrintLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/DxeServicesTableLib.h>\r
+#include <Library/HobLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/DevicePathLib.h>\r
+#include <Library/PerformanceLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/PeCoffGetEntryPointLib.h>\r
+#include <Library/UefiBootManagerLib.h>\r
+#include <Library/TimerLib.h>\r
+#include <Library/DxeServicesLib.h>\r
+#include <Library/ReportStatusCodeLib.h>\r
+#include <Library/CapsuleLib.h>\r
+#include <Library/PerformanceLib.h>\r
+#include <Library/HiiLib.h>\r
+\r
+#if !defined (EFI_REMOVABLE_MEDIA_FILE_NAME)\r
+    #if defined (MDE_CPU_EBC)\r
+        //\r
+        // Uefi specification only defines the default boot file name for IA32, X64\r
+        // and IPF processor, so need define boot file name for EBC architecture here.\r
+        //\r
+        #define EFI_REMOVABLE_MEDIA_FILE_NAME L"\\EFI\\BOOT\\BOOTEBC.EFI"\r
+    #else\r
+        #error "Can not determine the default boot file name for unknown processor type!"\r
+    #endif\r
+#endif\r
+\r
+typedef enum {\r
+  BmAcpiFloppyBoot,\r
+  BmHardwareDeviceBoot,\r
+  BmMessageAtapiBoot,\r
+  BmMessageSataBoot,\r
+  BmMessageUsbBoot,\r
+  BmMessageScsiBoot,\r
+  BmMessageNetworkBoot,\r
+  BmMiscBoot\r
+} BM_BOOT_TYPE;\r
+\r
+typedef\r
+CHAR16 *\r
+(* BM_GET_BOOT_DESCRIPTION) (\r
+  IN EFI_HANDLE          Handle\r
+  );\r
+\r
+#define BM_OPTION_NAME_LEN                          sizeof ("SysPrep####")\r
+extern CHAR16  *mBmLoadOptionName[];\r
+\r
+typedef\r
+VOID\r
+(*VARIABLE_VISITOR) (\r
+  CHAR16                *Name,\r
+  EFI_GUID              *Guid,\r
+  VOID                  *Context\r
+  );\r
+\r
+/**\r
+  Call Visitor function for each variable in variable storage.\r
+\r
+  @param Visitor   Visitor function.\r
+  @param Context   The context passed to Visitor function.\r
+**/\r
+VOID\r
+ForEachVariable (\r
+  VARIABLE_VISITOR            Visitor,\r
+  VOID                        *Context\r
+  );\r
+\r
+/**\r
+  Repair all the controllers according to the Driver Health status queried.\r
+**/\r
+VOID\r
+BmRepairAllControllers (\r
+  VOID\r
+  );\r
+\r
+#define BM_HOTKEY_SIGNATURE SIGNATURE_32 ('b', 'm', 'h', 'k')\r
+typedef struct {\r
+  UINT32                    Signature;\r
+  LIST_ENTRY                Link;\r
+\r
+  BOOLEAN                   IsContinue;\r
+  UINT16                    BootOption;\r
+  UINT8                     CodeCount;\r
+  UINT8                     WaitingKey;\r
+  EFI_KEY_DATA              KeyData[3];\r
+} BM_HOTKEY;\r
+\r
+#define BM_HOTKEY_FROM_LINK(a) CR (a, BM_HOTKEY, Link, BM_HOTKEY_SIGNATURE)\r
+\r
+/**\r
+  Get the image file buffer data and buffer size by its device path. \r
+\r
+  @param FilePath  On input, a pointer to an allocated buffer containing the device\r
+                   path of the file.\r
+                   On output the pointer could be NULL when the function fails to\r
+                   load the boot option, or could point to an allocated buffer containing\r
+                   the device path of the file.\r
+                   It could be updated by either short-form device path expanding,\r
+                   or default boot file path appending.\r
+                   Caller is responsible to free it when it's non-NULL.\r
+  @param FileSize  A pointer to the size of the file buffer.\r
+\r
+  @retval NULL   File is NULL, or FileSize is NULL. Or, the file can't be found.\r
+  @retval other  The file buffer. The caller is responsible to free the memory.\r
+**/\r
+VOID *\r
+BmLoadEfiBootOption (\r
+  IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath,\r
+  OUT    UINTN                    *FileSize\r
+  );\r
+\r
+/**\r
+  Get the Option Number that wasn't used.\r
+\r
+  @param  LoadOptionType      Load option type.\r
+  @param  FreeOptionNumber    To receive the minimal free option number.\r
+\r
+  @retval EFI_SUCCESS           The option number is found\r
+  @retval EFI_OUT_OF_RESOURCES  There is no free option number that can be used.\r
+  @retval EFI_INVALID_PARAMETER FreeOptionNumber is NULL\r
+\r
+**/\r
+EFI_STATUS\r
+BmGetFreeOptionNumber (\r
+  IN  EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType,\r
+  OUT UINT16                            *FreeOptionNumber\r
+  );\r
+\r
+/**\r
+\r
+  Writes performance data of booting into the allocated memory.\r
+  OS can process these records.\r
+\r
+  @param  Event                 The triggered event.\r
+  @param  Context               Context for this event.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+BmWriteBootToOsPerformanceData (\r
+  IN EFI_EVENT  Event,\r
+  IN VOID       *Context\r
+  );\r
+\r
+\r
+/**\r
+  Get the headers (dos, image, optional header) from an image\r
+\r
+  @param  Device                SimpleFileSystem device handle\r
+  @param  FileName              File name for the image\r
+  @param  DosHeader             Pointer to dos header\r
+  @param  Hdr                   The buffer in which to return the PE32, PE32+, or TE header.\r
+\r
+  @retval EFI_SUCCESS           Successfully get the machine type.\r
+  @retval EFI_NOT_FOUND         The file is not found.\r
+  @retval EFI_LOAD_ERROR        File is not a valid image file.\r
+\r
+**/\r
+EFI_STATUS\r
+BmGetImageHeader (\r
+  IN  EFI_HANDLE                  Device,\r
+  IN  CHAR16                      *FileName,\r
+  OUT EFI_IMAGE_DOS_HEADER        *DosHeader,\r
+  OUT EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION   Hdr\r
+  );\r
+\r
+/**\r
+  This routine adjust the memory information for different memory type and \r
+  save them into the variables for next boot.\r
+**/\r
+VOID\r
+BmSetMemoryTypeInformationVariable (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Check whether there is a instance in BlockIoDevicePath, which contain multi device path\r
+  instances, has the same partition node with HardDriveDevicePath device path\r
+\r
+  @param  BlockIoDevicePath      Multi device path instances which need to check\r
+  @param  HardDriveDevicePath    A device path which starts with a hard drive media\r
+                                 device path.\r
+\r
+  @retval TRUE                   There is a matched device path instance.\r
+  @retval FALSE                  There is no matched device path instance.\r
+\r
+**/\r
+BOOLEAN\r
+BmMatchPartitionDevicePathNode (\r
+  IN  EFI_DEVICE_PATH_PROTOCOL   *BlockIoDevicePath,\r
+  IN  HARDDRIVE_DEVICE_PATH      *HardDriveDevicePath\r
+  );\r
+\r
+/**\r
+  Connect the specific Usb device which match the short form device path.\r
+\r
+  @param  DevicePath             A short-form device path that starts with the first\r
+                                 element being a USB WWID or a USB Class device\r
+                                 path\r
+\r
+  @return EFI_INVALID_PARAMETER  DevicePath is NULL pointer.\r
+                                 DevicePath is not a USB device path.\r
+\r
+  @return EFI_SUCCESS            Success to connect USB device\r
+  @return EFI_NOT_FOUND          Fail to find handle for USB controller to connect.\r
+\r
+**/\r
+EFI_STATUS\r
+BmConnectUsbShortFormDevicePath (\r
+  IN EFI_DEVICE_PATH_PROTOCOL   *DevicePath\r
+  );\r
+\r
+/**\r
+  Stop the hotkey processing.\r
+  \r
+  @param    Event          Event pointer related to hotkey service. \r
+  @param    Context        Context pass to this function. \r
+**/\r
+VOID\r
+EFIAPI\r
+BmStopHotkeyService (\r
+  IN EFI_EVENT    Event,\r
+  IN VOID         *Context\r
+  );\r
+\r
+/**\r
+  Set the variable and report the error through status code upon failure.\r
+\r
+  @param  VariableName           A Null-terminated string that is the name of the vendor's variable.\r
+                                 Each VariableName is unique for each VendorGuid. VariableName must\r
+                                 contain 1 or more characters. If VariableName is an empty string,\r
+                                 then EFI_INVALID_PARAMETER is returned.\r
+  @param  VendorGuid             A unique identifier for the vendor.\r
+  @param  Attributes             Attributes bitmask to set for the variable.\r
+  @param  DataSize               The size in bytes of the Data buffer. Unless the EFI_VARIABLE_APPEND_WRITE, \r
+                                 EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, or \r
+                                 EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute is set, a size of zero \r
+                                 causes the variable to be deleted. When the EFI_VARIABLE_APPEND_WRITE attribute is \r
+                                 set, then a SetVariable() call with a DataSize of zero will not cause any change to \r
+                                 the variable value (the timestamp associated with the variable may be updated however \r
+                                 even if no new data value is provided,see the description of the \r
+                                 EFI_VARIABLE_AUTHENTICATION_2 descriptor below. In this case the DataSize will not \r
+                                 be zero since the EFI_VARIABLE_AUTHENTICATION_2 descriptor will be populated). \r
+  @param  Data                   The contents for the variable.\r
+\r
+  @retval EFI_SUCCESS            The firmware has successfully stored the variable and its data as\r
+                                 defined by the Attributes.\r
+  @retval EFI_INVALID_PARAMETER  An invalid combination of attribute bits, name, and GUID was supplied, or the\r
+                                 DataSize exceeds the maximum allowed.\r
+  @retval EFI_INVALID_PARAMETER  VariableName is an empty string.\r
+  @retval EFI_OUT_OF_RESOURCES   Not enough storage is available to hold the variable and its data.\r
+  @retval EFI_DEVICE_ERROR       The variable could not be retrieved due to a hardware error.\r
+  @retval EFI_WRITE_PROTECTED    The variable in question is read-only.\r
+  @retval EFI_WRITE_PROTECTED    The variable in question cannot be deleted.\r
+  @retval EFI_SECURITY_VIOLATION The variable could not be written due to EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS \r
+                                 or EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACESS being set, but the AuthInfo \r
+                                 does NOT pass the validation check carried out by the firmware.\r
+\r
+  @retval EFI_NOT_FOUND          The variable trying to be updated or deleted was not found.\r
+**/\r
+EFI_STATUS\r
+BmSetVariableAndReportStatusCodeOnError (\r
+  IN CHAR16     *VariableName,\r
+  IN EFI_GUID   *VendorGuid,\r
+  IN UINT32     Attributes,\r
+  IN UINTN      DataSize,\r
+  IN VOID       *Data\r
+  );\r
+\r
+/**\r
+  Get the load option by its device path.\r
+\r
+  @param FilePath  The device path pointing to a load option.\r
+                   It could be a short-form device path.\r
+  @param FullPath  Return the full device path of the load option after\r
+                   short-form device path expanding.\r
+                   Caller is responsible to free it.\r
+  @param FileSize  Return the load option size.\r
+\r
+  @return The load option buffer. Caller is responsible to free the memory.\r
+**/\r
+VOID *\r
+BmGetLoadOptionBuffer (\r
+  IN  EFI_DEVICE_PATH_PROTOCOL          *FilePath,\r
+  OUT EFI_DEVICE_PATH_PROTOCOL          **FullPath,\r
+  OUT UINTN                             *FileSize\r
+  );\r
+\r
+/**\r
+  Return whether the PE header of the load option is valid or not.\r
+\r
+  @param[in] Type       The load option type.\r
+  @param[in] FileBuffer The PE file buffer of the load option.\r
+  @param[in] FileSize   The size of the load option file.\r
+\r
+  @retval TRUE  The PE header of the load option is valid.\r
+  @retval FALSE The PE header of the load option is not valid.\r
+**/\r
+BOOLEAN\r
+BmIsLoadOptionPeHeaderValid (\r
+  IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE Type,\r
+  IN VOID                              *FileBuffer,\r
+  IN UINTN                             FileSize\r
+  );\r
+\r
+/**\r
+  Function compares a device path data structure to that of all the nodes of a\r
+  second device path instance.\r
+\r
+  @param  Multi                 A pointer to a multi-instance device path data\r
+                                structure.\r
+  @param  Single                A pointer to a single-instance device path data\r
+                                structure.\r
+\r
+  @retval TRUE                  If the Single device path is contained within Multi device path.\r
+  @retval FALSE                 The Single device path is not match within Multi device path.\r
+\r
+**/\r
+BOOLEAN\r
+BmMatchDevicePaths (\r
+  IN  EFI_DEVICE_PATH_PROTOCOL  *Multi,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL  *Single\r
+  );\r
+\r
+/**\r
+  Delete the instance in Multi which matches partly with Single instance\r
+\r
+  @param  Multi                 A pointer to a multi-instance device path data\r
+                                structure.\r
+  @param  Single                A pointer to a single-instance device path data\r
+                                structure.\r
+\r
+  @return This function will remove the device path instances in Multi which partly\r
+          match with the Single, and return the result device path. If there is no\r
+          remaining device path as a result, this function will return NULL.\r
+\r
+**/\r
+EFI_DEVICE_PATH_PROTOCOL *\r
+BmDelPartMatchInstance (\r
+  IN     EFI_DEVICE_PATH_PROTOCOL  *Multi,\r
+  IN     EFI_DEVICE_PATH_PROTOCOL  *Single\r
+  );\r
+\r
+\r
+/**\r
+  Return the index of the load option in the load option array.\r
+\r
+  The function consider two load options are equal when the \r
+  OptionType, Attributes, Description, FilePath and OptionalData are equal.\r
+\r
+  @param Key    Pointer to the load option to be found.\r
+  @param Array  Pointer to the array of load options to be found.\r
+  @param Count  Number of entries in the Array.\r
+\r
+  @retval -1          Key wasn't found in the Array.\r
+  @retval 0 ~ Count-1 The index of the Key in the Array.\r
+**/\r
+INTN\r
+BmFindLoadOption (\r
+  IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Key,\r
+  IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Array,\r
+  IN UINTN                              Count\r
+  );\r
+\r
+/**\r
+  Repair all the controllers according to the Driver Health status queried.\r
+**/\r
+VOID\r
+BmRepairAllControllers (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Print the device path info.\r
+\r
+  @param DevicePath           The device path need to print.\r
+**/\r
+VOID\r
+BmPrintDp (\r
+  EFI_DEVICE_PATH_PROTOCOL            *DevicePath\r
+  );\r
+\r
+#endif // _INTERNAL_BM_H_\r
index 760cf03dd464bb0a6f001e585ed2edfee5437931..0e4c3ebaf1609d9f1d25ec38eaa746212c99d6b8 100644 (file)
-## @file
-#  Define and produce general Boot Manager related interfaces.
-#  
-#  Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.<BR>
-#  are licensed and made available under the terms and conditions of the BSD License
-#  which accompanies this distribution.  The full text of the license may be found at
-#  http://opensource.org/licenses/bsd-license.php
-#  
-#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
-#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
-#  
-##
-
-[Defines]
-  INF_VERSION                    = 0x00010005
-  BASE_NAME                      = UefiBootManagerLib
-  FILE_GUID                      = 8D4752BC-595E-49a2-B4AF-F3F57B601DE9
-  MODULE_TYPE                    = DXE_DRIVER
-  VERSION_STRING                 = 1.0
-  LIBRARY_CLASS                  = UefiBootManagerLib|DXE_DRIVER DXE_RUNTIME_DRIVER UEFI_APPLICATION UEFI_DRIVER 
-
-#
-# The following information is for reference only and not required by the build tools.
-#
-#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC
-#
-
-[Sources]
-  BmPerformance.c
-  BmConnect.c
-  BmMisc.c
-  BmConsole.c
-  BmBoot.c
-  BmLoadOption.c
-  BmHotkey.c
-  BmDriverHealth.c
-  InternalBm.h
-  
-[Packages]
-  MdePkg/MdePkg.dec
-  MdeModulePkg/MdeModulePkg.dec
-
-[LibraryClasses]
-  HobLib
-  PcdLib
-  BaseLib
-  UefiLib
-  TimerLib
-  DebugLib
-  PrintLib
-  BaseMemoryLib
-  DevicePathLib
-  PerformanceLib
-  PeCoffGetEntryPointLib
-  UefiBootServicesTableLib
-  UefiRuntimeServicesTableLib
-  DxeServicesTableLib
-  MemoryAllocationLib
-  DxeServicesLib
-  ReportStatusCodeLib
-  PerformanceLib
-  HiiLib
-  SortLib
-
-[Guids]
-  gEfiMemoryTypeInformationGuid                 ## CONSUMES ## GUID (The identifier of memory type information type in system table)
-                                                ## CONSUMES ## GUID HOB (The hob holding memory type information)
-  gEfiGlobalVariableGuid                        ## SOMETIMES_PRODUCES ## Variable:L"BootCurrent" (The boot option of current boot)
-                                                ## SOMETIMES_CONSUMES ## Variable:L"BootXX" (Boot option variable)
-                                                ## CONSUMES           ## Variable:L"Timeout" (The time out value in second of showing progress bar)
-                                                ## SOMETIMES_CONSUMES ## Variable:L"BootOrder" (The boot option array)
-                                                ## SOMETIMES_CONSUMES ## Variable:L"DriverOrder" (The driver order list)
-                                                ## SOMETIMES_CONSUMES ## Variable:L"ConIn" (The device path of console in device)
-                                                ## SOMETIMES_CONSUMES ## Variable:L"ConOut" (The device path of console out device)
-                                                ## SOMETIMES_CONSUMES ## Variable:L"ErrOut" (The device path of error out device)
-  gEfiFileInfoGuid                              ## CONSUMES ## GUID
-  gPerformanceProtocolGuid                      ## SOMETIMES_PRODUCES ## Variable:L"PerfDataMemAddr" (The ACPI address of performance data)
-  gEdkiiStatusCodeDataTypeVariableGuid          ## SOMETIMES_CONSUMES ## GUID
-  gEfiDiskInfoAhciInterfaceGuid                 ## SOMETIMES_CONSUMES ## GUID
-  gEfiDiskInfoIdeInterfaceGuid                  ## SOMETIMES_CONSUMES ## GUID
-  gEfiDiskInfoScsiInterfaceGuid                 ## SOMETIMES_CONSUMES ## GUID
-  gZeroGuid                                     ## CONSUMES ## GUID
-
-[Protocols]
-  gEfiPciRootBridgeIoProtocolGuid               ## CONSUMES
-  gEfiSimpleFileSystemProtocolGuid              ## CONSUMES
-  gEfiLoadFileProtocolGuid                      ## CONSUMES
-  gEfiSimpleTextOutProtocolGuid                 ## CONSUMES
-  gEfiPciIoProtocolGuid                         ## CONSUMES
-  gEfiLoadedImageProtocolGuid                   ## CONSUMES
-  gEfiSimpleNetworkProtocolGuid                 ## CONSUMES
-  gEfiSimpleTextInProtocolGuid                  ## CONSUMES
-  gEfiBlockIoProtocolGuid                       ## CONSUMES
-  gEfiFirmwareVolume2ProtocolGuid               ## CONSUMES
-  gEfiDevicePathProtocolGuid                    ## CONSUMES
-  gEfiBootLogoProtocolGuid                      ## CONSUMES
-  gEfiSimpleTextInputExProtocolGuid             ## CONSUMES
-  gEfiGraphicsOutputProtocolGuid                ## SOMETIMES_CONSUMES
-  gEfiUsbIoProtocolGuid                         ## SOMETIMES_CONSUMES
-  gEfiDiskInfoProtocolGuid                      ## SOMETIMES_CONSUMES
-  gEfiDriverHealthProtocolGuid                  ## SOMETIMES_CONSUMES
-
-[Pcd]
-  gEfiMdeModulePkgTokenSpaceGuid.PcdResetOnMemoryTypeInformationChange      ## SOMETIMES_CONSUMES
-  gEfiMdeModulePkgTokenSpaceGuid.PcdProgressCodeOsLoaderLoad                ## SOMETIMES_CONSUMES
-  gEfiMdeModulePkgTokenSpaceGuid.PcdProgressCodeOsLoaderStart               ## SOMETIMES_CONSUMES
-  gEfiMdeModulePkgTokenSpaceGuid.PcdErrorCodeSetVariable                    ## SOMETIMES_CONSUMES
-  gEfiMdeModulePkgTokenSpaceGuid.PcdBootManagerMenuFile                     ## CONSUMES
-  gEfiMdeModulePkgTokenSpaceGuid.PcdDriverHealthConfigureForm               ## SOMETIMES_CONSUMES
-
+## @file\r
+#  Define and produce general Boot Manager related interfaces.\r
+#  \r
+#  Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.<BR>\r
+#  are licensed and made available under the terms and conditions of the BSD License\r
+#  which accompanies this distribution.  The full text of the license may be found at\r
+#  http://opensource.org/licenses/bsd-license.php\r
+#  \r
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#  \r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = UefiBootManagerLib\r
+  FILE_GUID                      = 8D4752BC-595E-49a2-B4AF-F3F57B601DE9\r
+  MODULE_TYPE                    = DXE_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+  LIBRARY_CLASS                  = UefiBootManagerLib|DXE_DRIVER DXE_RUNTIME_DRIVER UEFI_APPLICATION UEFI_DRIVER \r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources]\r
+  BmPerformance.c\r
+  BmConnect.c\r
+  BmMisc.c\r
+  BmConsole.c\r
+  BmBoot.c\r
+  BmLoadOption.c\r
+  BmHotkey.c\r
+  BmDriverHealth.c\r
+  InternalBm.h\r
+  \r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+\r
+[LibraryClasses]\r
+  HobLib\r
+  PcdLib\r
+  BaseLib\r
+  UefiLib\r
+  TimerLib\r
+  DebugLib\r
+  PrintLib\r
+  BaseMemoryLib\r
+  DevicePathLib\r
+  PerformanceLib\r
+  PeCoffGetEntryPointLib\r
+  UefiBootServicesTableLib\r
+  UefiRuntimeServicesTableLib\r
+  DxeServicesTableLib\r
+  MemoryAllocationLib\r
+  DxeServicesLib\r
+  ReportStatusCodeLib\r
+  PerformanceLib\r
+  HiiLib\r
+  SortLib\r
+\r
+[Guids]\r
+  gEfiMemoryTypeInformationGuid                 ## CONSUMES ## GUID (The identifier of memory type information type in system table)\r
+                                                ## CONSUMES ## GUID HOB (The hob holding memory type information)\r
+  gEfiGlobalVariableGuid                        ## SOMETIMES_PRODUCES ## Variable:L"BootCurrent" (The boot option of current boot)\r
+                                                ## SOMETIMES_CONSUMES ## Variable:L"BootXX" (Boot option variable)\r
+                                                ## CONSUMES           ## Variable:L"Timeout" (The time out value in second of showing progress bar)\r
+                                                ## SOMETIMES_CONSUMES ## Variable:L"BootOrder" (The boot option array)\r
+                                                ## SOMETIMES_CONSUMES ## Variable:L"DriverOrder" (The driver order list)\r
+                                                ## SOMETIMES_CONSUMES ## Variable:L"ConIn" (The device path of console in device)\r
+                                                ## SOMETIMES_CONSUMES ## Variable:L"ConOut" (The device path of console out device)\r
+                                                ## SOMETIMES_CONSUMES ## Variable:L"ErrOut" (The device path of error out device)\r
+  gEfiFileInfoGuid                              ## CONSUMES ## GUID\r
+  gPerformanceProtocolGuid                      ## SOMETIMES_PRODUCES ## Variable:L"PerfDataMemAddr" (The ACPI address of performance data)\r
+  gEdkiiStatusCodeDataTypeVariableGuid          ## SOMETIMES_CONSUMES ## GUID\r
+  gEfiDiskInfoAhciInterfaceGuid                 ## SOMETIMES_CONSUMES ## GUID\r
+  gEfiDiskInfoIdeInterfaceGuid                  ## SOMETIMES_CONSUMES ## GUID\r
+  gEfiDiskInfoScsiInterfaceGuid                 ## SOMETIMES_CONSUMES ## GUID\r
+  gZeroGuid                                     ## CONSUMES ## GUID\r
+\r
+[Protocols]\r
+  gEfiPciRootBridgeIoProtocolGuid               ## CONSUMES\r
+  gEfiSimpleFileSystemProtocolGuid              ## CONSUMES\r
+  gEfiLoadFileProtocolGuid                      ## CONSUMES\r
+  gEfiSimpleTextOutProtocolGuid                 ## CONSUMES\r
+  gEfiPciIoProtocolGuid                         ## CONSUMES\r
+  gEfiLoadedImageProtocolGuid                   ## CONSUMES\r
+  gEfiSimpleNetworkProtocolGuid                 ## CONSUMES\r
+  gEfiSimpleTextInProtocolGuid                  ## CONSUMES\r
+  gEfiBlockIoProtocolGuid                       ## CONSUMES\r
+  gEfiFirmwareVolume2ProtocolGuid               ## CONSUMES\r
+  gEfiDevicePathProtocolGuid                    ## CONSUMES\r
+  gEfiBootLogoProtocolGuid                      ## CONSUMES\r
+  gEfiSimpleTextInputExProtocolGuid             ## CONSUMES\r
+  gEfiGraphicsOutputProtocolGuid                ## SOMETIMES_CONSUMES\r
+  gEfiUsbIoProtocolGuid                         ## SOMETIMES_CONSUMES\r
+  gEfiDiskInfoProtocolGuid                      ## SOMETIMES_CONSUMES\r
+  gEfiDriverHealthProtocolGuid                  ## SOMETIMES_CONSUMES\r
+\r
+[Pcd]\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdResetOnMemoryTypeInformationChange      ## SOMETIMES_CONSUMES\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdProgressCodeOsLoaderLoad                ## SOMETIMES_CONSUMES\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdProgressCodeOsLoaderStart               ## SOMETIMES_CONSUMES\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdErrorCodeSetVariable                    ## SOMETIMES_CONSUMES\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdBootManagerMenuFile                     ## CONSUMES\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdDriverHealthConfigureForm               ## SOMETIMES_CONSUMES\r
+\r