-/** @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
## @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
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
BaseLib\r
BaseMemoryLib\r
DebugLib\r
-\r
-\r
-/** @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
-/** @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
-/** @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
-/** @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
-/** @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
-/** @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
-/** @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
-/** @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
-/** @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
-## @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