From 067ed98a734eabd311b8c2c8ebd48b67e0242afa Mon Sep 17 00:00:00 2001 From: Ruiyu Ni Date: Wed, 13 May 2015 02:23:44 +0000 Subject: [PATCH] MdeModulePkg: Fix EOL to be DOS format. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ruiyu Ni git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@17421 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Include/Library/UefiBootManagerLib.h | 1362 +++--- .../Library/BaseSortLib/BaseSortLib.inf | 6 +- .../Library/UefiBootManagerLib/BmBoot.c | 4320 ++++++++--------- .../Library/UefiBootManagerLib/BmConnect.c | 642 +-- .../Library/UefiBootManagerLib/BmConsole.c | 1528 +++--- .../UefiBootManagerLib/BmDriverHealth.c | 1156 ++--- .../Library/UefiBootManagerLib/BmHotkey.c | 2202 ++++----- .../Library/UefiBootManagerLib/BmLoadOption.c | 2496 +++++----- .../Library/UefiBootManagerLib/BmMisc.c | 772 +-- .../UefiBootManagerLib/BmPerformance.c | 716 +-- .../Library/UefiBootManagerLib/InternalBm.h | 882 ++-- .../UefiBootManagerLib/UefiBootManagerLib.inf | 220 +- 12 files changed, 8150 insertions(+), 8152 deletions(-) diff --git a/MdeModulePkg/Include/Library/UefiBootManagerLib.h b/MdeModulePkg/Include/Library/UefiBootManagerLib.h index 2ec80894ad..886229ed9e 100644 --- a/MdeModulePkg/Include/Library/UefiBootManagerLib.h +++ b/MdeModulePkg/Include/Library/UefiBootManagerLib.h @@ -1,681 +1,681 @@ -/** @file - Provide Boot Manager related library APIs. - -Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.
-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 -#include - -// -// 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 + Provide Boot Manager related library APIs. + +Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.
+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 +#include + +// +// 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 diff --git a/MdeModulePkg/Library/BaseSortLib/BaseSortLib.inf b/MdeModulePkg/Library/BaseSortLib/BaseSortLib.inf index e23b4d073b..9d3633b9b6 100644 --- a/MdeModulePkg/Library/BaseSortLib/BaseSortLib.inf +++ b/MdeModulePkg/Library/BaseSortLib/BaseSortLib.inf @@ -1,7 +1,7 @@ ## @file # Library used for sorting routines. # -# Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.
+# Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.
# # This program and the accompanying materials # are licensed and made available under the terms and conditions of the BSD License @@ -19,7 +19,7 @@ FILE_GUID = 03F3331B-F12D-494f-BF37-E55A657F2497 MODULE_TYPE = UEFI_DRIVER VERSION_STRING = 1.0 - LIBRARY_CLASS = SortLib|DXE_DRIVER DXE_RUNTIME_DRIVER UEFI_APPLICATION UEFI_DRIVER + LIBRARY_CLASS = SortLib|DXE_DRIVER DXE_RUNTIME_DRIVER UEFI_APPLICATION UEFI_DRIVER # # VALID_ARCHITECTURES = IA32 X64 IPF EBC @@ -37,5 +37,3 @@ BaseLib BaseMemoryLib DebugLib - - diff --git a/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c b/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c index ede5250851..efac6d5bea 100644 --- a/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c +++ b/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c @@ -1,2160 +1,2160 @@ -/** @file - Library functions which relates with booting. - -Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.
-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 + Library functions which relates with booting. + +Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.
+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; + } +} + diff --git a/MdeModulePkg/Library/UefiBootManagerLib/BmConnect.c b/MdeModulePkg/Library/UefiBootManagerLib/BmConnect.c index 9e3a683e25..b1c94ad9d9 100644 --- a/MdeModulePkg/Library/UefiBootManagerLib/BmConnect.c +++ b/MdeModulePkg/Library/UefiBootManagerLib/BmConnect.c @@ -1,321 +1,321 @@ -/** @file - Library functions which relate with connecting the device. - -Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.
-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 + Library functions which relate with connecting the device. + +Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.
+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; +} diff --git a/MdeModulePkg/Library/UefiBootManagerLib/BmConsole.c b/MdeModulePkg/Library/UefiBootManagerLib/BmConsole.c index 4f5c8b04c2..86b4fac424 100644 --- a/MdeModulePkg/Library/UefiBootManagerLib/BmConsole.c +++ b/MdeModulePkg/Library/UefiBootManagerLib/BmConsole.c @@ -1,764 +1,764 @@ -/** @file - Library functions which contain all the code to connect console device. - -Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.
-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 + Library functions which contain all the code to connect console device. + +Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.
+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; +} diff --git a/MdeModulePkg/Library/UefiBootManagerLib/BmDriverHealth.c b/MdeModulePkg/Library/UefiBootManagerLib/BmDriverHealth.c index 2b5257394e..d197816fa1 100644 --- a/MdeModulePkg/Library/UefiBootManagerLib/BmDriverHealth.c +++ b/MdeModulePkg/Library/UefiBootManagerLib/BmDriverHealth.c @@ -1,578 +1,578 @@ -/** @file - Library functions which relates with driver health. - -Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.
-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 + Library functions which relates with driver health. + +Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.
+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); + } +} diff --git a/MdeModulePkg/Library/UefiBootManagerLib/BmHotkey.c b/MdeModulePkg/Library/UefiBootManagerLib/BmHotkey.c index 6a770f940c..8d398fb4c6 100644 --- a/MdeModulePkg/Library/UefiBootManagerLib/BmHotkey.c +++ b/MdeModulePkg/Library/UefiBootManagerLib/BmHotkey.c @@ -1,1101 +1,1101 @@ -/** @file - Hotkey library functions. - -Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.
-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 + Hotkey library functions. + +Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.
+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; +} diff --git a/MdeModulePkg/Library/UefiBootManagerLib/BmLoadOption.c b/MdeModulePkg/Library/UefiBootManagerLib/BmLoadOption.c index 27a8db733e..630307ed03 100644 --- a/MdeModulePkg/Library/UefiBootManagerLib/BmLoadOption.c +++ b/MdeModulePkg/Library/UefiBootManagerLib/BmLoadOption.c @@ -1,1248 +1,1248 @@ -/** @file - Load option library functions which relate with creating and processing load options. - -Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.
-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 + Load option library functions which relate with creating and processing load options. + +Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.
+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; +} diff --git a/MdeModulePkg/Library/UefiBootManagerLib/BmMisc.c b/MdeModulePkg/Library/UefiBootManagerLib/BmMisc.c index 30d955111e..97d1a48cd5 100644 --- a/MdeModulePkg/Library/UefiBootManagerLib/BmMisc.c +++ b/MdeModulePkg/Library/UefiBootManagerLib/BmMisc.c @@ -1,386 +1,386 @@ -/** @file - Misc library functions. - -Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.
-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 + Misc library functions. + +Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.
+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); + } +} diff --git a/MdeModulePkg/Library/UefiBootManagerLib/BmPerformance.c b/MdeModulePkg/Library/UefiBootManagerLib/BmPerformance.c index 1fdb7f1fcb..32229d0b0a 100644 --- a/MdeModulePkg/Library/UefiBootManagerLib/BmPerformance.c +++ b/MdeModulePkg/Library/UefiBootManagerLib/BmPerformance.c @@ -1,358 +1,358 @@ -/** @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.
-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 + 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.
+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 ; +} diff --git a/MdeModulePkg/Library/UefiBootManagerLib/InternalBm.h b/MdeModulePkg/Library/UefiBootManagerLib/InternalBm.h index c362d8d7cc..8e8534dd4d 100644 --- a/MdeModulePkg/Library/UefiBootManagerLib/InternalBm.h +++ b/MdeModulePkg/Library/UefiBootManagerLib/InternalBm.h @@ -1,441 +1,441 @@ -/** @file - BDS library definition, include the file and data structure - -Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.
-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 - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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 + BDS library definition, include the file and data structure + +Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.
+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 + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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_ diff --git a/MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf b/MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf index 760cf03dd4..0e4c3ebaf1 100644 --- a/MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf +++ b/MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf @@ -1,110 +1,110 @@ -## @file -# Define and produce general Boot Manager related interfaces. -# -# Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.
-# 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 +# Define and produce general Boot Manager related interfaces. +# +# Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.
+# 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 + -- 2.39.2