Revision: 17327
http://sourceforge.net/p/edk2/code/17327
Author: niruiyu
Date: 2015-05-06 04:47:02 +0000 (Wed, 06 May 2015)
Log Message:
-----------
MdeModulePkg: Add UefiBootManagerLib
UefiBootManagerLib provides:
load option library functions;
hot key library functions;
boot library functions;
connect and disconnect library functions;
driver health library functions.
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Ruiyu Ni <[email protected]>
Reviewed-by: Eric Dong <[email protected]>
Modified Paths:
--------------
trunk/edk2/MdeModulePkg/Library/BaseSortLib/BaseSortLib.inf
trunk/edk2/MdeModulePkg/MdeModulePkg.dec
trunk/edk2/MdeModulePkg/MdeModulePkg.dsc
Added Paths:
-----------
trunk/edk2/MdeModulePkg/Include/Library/UefiBootManagerLib.h
trunk/edk2/MdeModulePkg/Library/UefiBootManagerLib/
trunk/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c
trunk/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmConnect.c
trunk/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmConsole.c
trunk/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmDriverHealth.c
trunk/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmHotkey.c
trunk/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmLoadOption.c
trunk/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmMisc.c
trunk/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmPerformance.c
trunk/edk2/MdeModulePkg/Library/UefiBootManagerLib/InternalBm.h
trunk/edk2/MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf
Added: trunk/edk2/MdeModulePkg/Include/Library/UefiBootManagerLib.h
===================================================================
--- trunk/edk2/MdeModulePkg/Include/Library/UefiBootManagerLib.h
(rev 0)
+++ trunk/edk2/MdeModulePkg/Include/Library/UefiBootManagerLib.h
2015-05-06 04:47:02 UTC (rev 17327)
@@ -0,0 +1,657 @@
+/** @file
+ Provide Boot Manager related library APIs.
+
+Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD
License
+which accompanies this distribution. The full text of the license may be
found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+
+#ifndef _UEFI_BOOT_MANAGER_LIB_H_
+#define _UEFI_BOOT_MANAGER_LIB_H_
+
+#include <Protocol/DriverHealth.h>
+#include <Library/SortLib.h>
+
+//
+// Boot Manager load option library functions.
+//
+
+//
+// Load Option Type
+//
+typedef enum {
+ LoadOptionTypeBoot,
+ LoadOptionTypeDriver,
+ 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
+
+ //
+ // 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#### and the
BootOrder/DriverOrder
+ 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.
+
+ @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 one chance to do the dispatch,
+ which load the missing drivers if possible.
+
+ @param DevicePathToConnect The device path which will be connected, it
CANNOT be
+ a multi-instance device path
+ @param MatchingHandle Return the controller handle closest to the
DevicePathToConnect
+
+ @retval EFI_INVALID_PARAMETER DevicePathToConnect is NULL.
+ @retval EFI_NOT_FOUND Failed to create all handles associate with
every device path node.
+ @retval EFI_SUCCESS Successful to create all handles associate
with every device path node.
+
+**/
+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.
+**/
+VOID
+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
+ );
+
+#endif
Modified: trunk/edk2/MdeModulePkg/Library/BaseSortLib/BaseSortLib.inf
===================================================================
--- trunk/edk2/MdeModulePkg/Library/BaseSortLib/BaseSortLib.inf 2015-05-06
04:45:53 UTC (rev 17326)
+++ trunk/edk2/MdeModulePkg/Library/BaseSortLib/BaseSortLib.inf 2015-05-06
04:47:02 UTC (rev 17327)
@@ -1,7 +1,7 @@
## @file
# Library used for sorting routines.
#
-# Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved. <BR>
+# Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved. <BR>
#
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD
License
@@ -19,7 +19,7 @@
FILE_GUID = 03F3331B-F12D-494f-BF37-E55A657F2497
MODULE_TYPE = UEFI_DRIVER
VERSION_STRING = 1.0
- LIBRARY_CLASS = SortLib|UEFI_APPLICATION UEFI_DRIVER
+ LIBRARY_CLASS = SortLib|DXE_DRIVER UEFI_APPLICATION
UEFI_DRIVER
#
# VALID_ARCHITECTURES = IA32 X64 IPF EBC
Added: trunk/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c
===================================================================
--- trunk/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c
(rev 0)
+++ trunk/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c 2015-05-06
04:47:02 UTC (rev 17327)
@@ -0,0 +1,2278 @@
+/** @file
+ Library functions which relates with booting.
+
+Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD
License
+which accompanies this distribution. The full text of the license may be
found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "InternalBm.h"
+
+#define VENDOR_IDENTIFICATION_OFFSET 3
+#define VENDOR_IDENTIFICATION_LENGTH 8
+#define PRODUCT_IDENTIFICATION_OFFSET 11
+#define PRODUCT_IDENTIFICATION_LENGTH 16
+
+CONST UINT16 mBmUsbLangId = 0x0409; // English
+CHAR16 mBmUefiPrefix[] = L"UEFI ";
+
+EFI_BOOT_MANAGER_REFRESH_LEGACY_BOOT_OPTION mBmRefreshLegacyBootOption = NULL;
+EFI_BOOT_MANAGER_LEGACY_BOOT mBmLegacyBoot = NULL;
+
+///
+/// This GUID is used for an EFI Variable that stores the front device pathes
+/// for a partial device path that starts with the HD node.
+///
+EFI_GUID mBmHardDriveBootVariableGuid = { 0xfab7e9e1, 0x39dd, 0x4f2b, { 0x84,
0x08, 0xe2, 0x0e, 0x90, 0x6c, 0xb6, 0xde } };
+EFI_GUID mBmAutoCreateBootOptionGuid = { 0x8108ac4e, 0x9f11, 0x4d59, { 0x85,
0x0e, 0xe2, 0x1a, 0x52, 0x2c, 0x59, 0xb2 } };
+
+/**
+ The function registers the legacy boot support capabilities.
+
+ @param RefreshLegacyBootOption The function pointer to create all the legacy
boot options.
+ @param LegacyBoot The function pointer to boot the legacy boot
option.
+**/
+VOID
+EFIAPI
+EfiBootManagerRegisterLegacyBootSupport (
+ EFI_BOOT_MANAGER_REFRESH_LEGACY_BOOT_OPTION RefreshLegacyBootOption,
+ EFI_BOOT_MANAGER_LEGACY_BOOT LegacyBoot
+ )
+{
+ mBmRefreshLegacyBootOption = RefreshLegacyBootOption;
+ mBmLegacyBoot = LegacyBoot;
+}
+
+/**
+ For a bootable Device path, return its boot type.
+
+ @param DevicePath The bootable device Path to check
+
+ @retval AcpiFloppyBoot If given device path contains
ACPI_DEVICE_PATH type device path node
+ which HID is floppy device.
+ @retval MessageAtapiBoot If given device path contains
MESSAGING_DEVICE_PATH type device path node
+ and its last device path node's subtype
is MSG_ATAPI_DP.
+ @retval MessageSataBoot If given device path contains
MESSAGING_DEVICE_PATH type device path node
+ and its last device path node's subtype
is MSG_SATA_DP.
+ @retval MessageScsiBoot If given device path contains
MESSAGING_DEVICE_PATH type device path node
+ and its last device path node's subtype
is MSG_SCSI_DP.
+ @retval MessageUsbBoot If given device path contains
MESSAGING_DEVICE_PATH type device path node
+ and its last device path node's subtype
is MSG_USB_DP.
+ @retval MessageNetworkBoot If given device path contains
MESSAGING_DEVICE_PATH type device path node
+ and its last device path node's subtype
is MSG_MAC_ADDR_DP, MSG_VLAN_DP,
+ MSG_IPv4_DP or MSG_IPv6_DP.
+ @retval UnsupportedBoot If tiven device path doesn't match the
above condition, it's not supported.
+
+**/
+BM_BOOT_TYPE
+BmBootTypeFromDevicePath (
+ 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;
+}
+
+/**
+ Free old buffer and reuse the pointer to return new buffer.
+
+ @param Orig Pointer to the old buffer.
+ @param New Pointer to the new buffer.
+**/
+VOID
+BmFreeAndSet (
+ VOID **Orig,
+ VOID *New
+ )
+{
+ FreePool (*Orig);
+ *Orig = New;
+}
+
+/**
+ 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[sizeof ("Boot####")];
+ 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"Boot%04x",
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;
+}
+
+/**
+ According to a file guild, check a Fv file device path is valid. If it is
invalid,
+ try to return the valid device path.
+ FV address maybe changes for memory layout adjust from time to time, use
this function
+ could promise the Fv file device path is right.
+
+ @param DevicePath The Fv file device path to be fixed up.
+
+**/
+VOID
+BmFixupMemmapFvFilePath (
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ EFI_DEVICE_PATH_PROTOCOL *Node;
+ EFI_HANDLE FvHandle;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
+ UINTN Size;
+ EFI_FV_FILETYPE Type;
+ EFI_FV_FILE_ATTRIBUTES Attributes;
+ UINT32 AuthenticationStatus;
+ UINTN FvHandleCount;
+ EFI_HANDLE *FvHandleBuffer;
+ EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
+
+ Node = *DevicePath;
+ Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &Node,
&FvHandle);
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->HandleProtocol (FvHandle, &gEfiFirmwareVolume2ProtocolGuid,
(VOID **) &Fv);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = Fv->ReadFile (
+ Fv,
+ EfiGetNameGuidFromFwVolDevicePathNode ((CONST
MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) Node),
+ NULL,
+ &Size,
+ &Type,
+ &Attributes,
+ &AuthenticationStatus
+ );
+ if (EFI_ERROR (Status)) {
+ BmFreeAndSet ((VOID **) DevicePath, NULL);
+ }
+ return;
+ }
+
+
+ Node = NextDevicePathNode (DevicePath);
+
+ //
+ // Firstly find the FV file in current FV
+ //
+ gBS->HandleProtocol (
+ gImageHandle,
+ &gEfiLoadedImageProtocolGuid,
+ (VOID **) &LoadedImage
+ );
+ NewDevicePath = AppendDevicePathNode (DevicePathFromHandle
(LoadedImage->DeviceHandle), Node);
+ BmFixupMemmapFvFilePath (&NewDevicePath);
+
+ if (NewDevicePath != NULL) {
+ BmFreeAndSet ((VOID **) DevicePath, NewDevicePath);
+ return;
+ }
+
+ //
+ // Secondly find the FV file in all other FVs
+ //
+ gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ NULL,
+ &FvHandleCount,
+ &FvHandleBuffer
+ );
+ for (Index = 0; Index < FvHandleCount; Index++) {
+ if (FvHandleBuffer[Index] == LoadedImage->DeviceHandle) {
+ //
+ // Skip current FV
+ //
+ continue;
+ }
+ NewDevicePath = AppendDevicePathNode (DevicePathFromHandle
(FvHandleBuffer[Index]), Node);
+ BmFixupMemmapFvFilePath (&NewDevicePath);
+
+ if (NewDevicePath != NULL) {
+ BmFreeAndSet ((VOID **) DevicePath, NewDevicePath);
+ return;
+ }
+ }
+}
+
+/**
+ Check if it's of Fv file device path type.
+
+ The function doesn't garentee the device path points to existing Fv file.
+
+ @param DevicePath Input device path info.
+
+ @retval TRUE The device path is of Fv file device path type.
+ @retval FALSE The device path isn't of Fv file device path type.
+**/
+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 (BmBootTypeFromDevicePath (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;
+}
+
+/**
+ 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);
+ }
+}
+
+/**
+ 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 DevicePath On input, a pointer to an allocated buffer that
contains the
+ file device path.
+ On output, a pointer to an reallocated buffer that
contains
+ the expanded device path. It would point to NULL if
the file
+ cannot be read.
+
+ @param FileSize A pointer to the file size.
+
+ @retval !NULL The file buffer.
+ @retval NULL The input device path doesn't point to a valid file.
+**/
+VOID *
+BmExpandUsbShortFormDevicePath (
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath,
+ OUT UINTN *FileSize
+ )
+{
+ UINTN ParentDevicePathSize;
+ EFI_DEVICE_PATH_PROTOCOL *ShortformNode;
+ EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *FullDevicePath;
+ EFI_HANDLE *UsbIoHandles;
+ UINTN UsbIoHandleCount;
+ UINTN Index;
+ VOID *FileBuffer;
+
+ //
+ // Search for USB Class or USB WWID device path node.
+ //
+ for ( ShortformNode = *DevicePath
+ ; !IsDevicePathEnd (ShortformNode)
+ ; ShortformNode = NextDevicePathNode (ShortformNode)
+ ) {
+ if ((DevicePathType (ShortformNode) == MESSAGING_DEVICE_PATH) &&
+ ((DevicePathSubType (ShortformNode) == MSG_USB_CLASS_DP) ||
+ (DevicePathSubType (ShortformNode) == MSG_USB_WWID_DP))) {
+ break;
+ }
+ }
+ ASSERT (!IsDevicePathEnd (ShortformNode));
+
+ FullDevicePath = NULL;
+ ParentDevicePathSize = (UINTN) ShortformNode - (UINTN) *DevicePath;
+ RemainingDevicePath = NextDevicePathNode (ShortformNode);
+ FileBuffer = NULL;
+ UsbIoHandles = BmFindUsbDevice (*DevicePath, ParentDevicePathSize,
&UsbIoHandleCount);
+
+ for (Index = 0; Index < UsbIoHandleCount; Index++) {
+ FullDevicePath = AppendDevicePath (DevicePathFromHandle
(UsbIoHandles[Index]), RemainingDevicePath);
+ DEBUG ((EFI_D_INFO, "[Bds] FullDp1[%d]:", Index)); DEBUG_CODE (BmPrintDp
(FullDevicePath); ); DEBUG ((EFI_D_INFO, "\n"));
+ FileBuffer = BmLoadEfiBootOption (&FullDevicePath, FileSize);
+ if (FileBuffer != NULL) {
+ DEBUG ((EFI_D_INFO, "-->")); DEBUG_CODE (BmPrintDp (FullDevicePath); );
DEBUG ((EFI_D_INFO, FileBuffer != NULL ? " - Found\n" : "\n"));
+ break;
+ }
+ }
+
+ if (UsbIoHandles != NULL) {
+ FreePool (UsbIoHandles);
+ }
+
+ if (FileBuffer == NULL) {
+ //
+ // 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.
+ //
+ if ((DevicePathType (*DevicePath) == MESSAGING_DEVICE_PATH) &&
+ ((DevicePathSubType (*DevicePath) == MSG_USB_CLASS_DP) ||
+ (DevicePathSubType (*DevicePath) == MSG_USB_WWID_DP))) {
+ BmConnectUsbShortFormDevicePath (*DevicePath);
+
+ UsbIoHandles = BmFindUsbDevice (*DevicePath, ParentDevicePathSize,
&UsbIoHandleCount);
+ for (Index = 0; Index < UsbIoHandleCount; Index++) {
+ FullDevicePath = AppendDevicePath (DevicePathFromHandle
(UsbIoHandles[Index]), RemainingDevicePath);
+ DEBUG ((EFI_D_INFO, "[Bds] FullDp2[%d]:", Index)); DEBUG_CODE
(BmPrintDp (FullDevicePath); ); DEBUG ((EFI_D_INFO, "\n"));
+ FileBuffer = BmLoadEfiBootOption (&FullDevicePath, FileSize);
+ if (FileBuffer != NULL) {
+ DEBUG ((EFI_D_INFO, "-->")); DEBUG_CODE (BmPrintDp (FullDevicePath);
); DEBUG ((EFI_D_INFO, FileBuffer != NULL ? " - Found\n" : "\n"));
+ break;
+ }
+ }
+
+ if (UsbIoHandles != NULL) {
+ FreePool (UsbIoHandles);
+ }
+ }
+ }
+
+ BmFreeAndSet ((VOID **) DevicePath, FullDevicePath);
+ return FileBuffer;
+}
+
+/**
+ 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 DevicePath On input, a pointer to an allocated buffer that
contains the
+ file device path.
+ On output, a pointer to an reallocated buffer that
contains
+ the expanded device path. It would point to NULL if
the file
+ cannot be read.
+
+**/
+VOID
+BmExpandPartitionShortFormDevicePath (
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ )
+{
+ EFI_STATUS Status;
+ UINTN BlockIoHandleCount;
+ EFI_HANDLE *BlockIoBuffer;
+ EFI_DEVICE_PATH_PROTOCOL *FullDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath;
+ UINTN Index;
+ UINTN InstanceNum;
+ EFI_DEVICE_PATH_PROTOCOL *CachedDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *TempNewDevicePath;
+ UINTN CachedDevicePathSize;
+ BOOLEAN DeviceExist;
+ BOOLEAN NeedAdjust;
+ EFI_DEVICE_PATH_PROTOCOL *Instance;
+ UINTN Size;
+
+ FullDevicePath = 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;
+ DeviceExist = FALSE;
+ 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 *)
*DevicePath)) {
+ //
+ // 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)) {
+ DeviceExist = TRUE;
+ break;
+ }
+ }
+ //
+ // Come here means the first instance is not matched
+ //
+ NeedAdjust = TRUE;
+ FreePool(Instance);
+ } while (TempNewDevicePath != NULL);
+
+ if (DeviceExist) {
+ //
+ // Find the matched device path.
+ // Append the file path information from the boot option and return the
fully expanded device path.
+ //
+ FullDevicePath = AppendDevicePath (Instance, NextDevicePathNode
(*DevicePath));
+
+ //
+ // Adjust the 'HDDP' instances sequence if the matched one is not first
one.
+ //
+ if (NeedAdjust) {
+ //
+ // First delete the matched instance.
+ //
+ TempNewDevicePath = CachedDevicePath;
+ CachedDevicePath = BmDelPartMatchInstance (CachedDevicePath,
Instance);
+ FreePool (TempNewDevicePath);
+
+ //
+ // Second, append the remaining path after the matched instance
+ //
+ TempNewDevicePath = CachedDevicePath;
+ CachedDevicePath = AppendDevicePathInstance (Instance,
CachedDevicePath );
+ FreePool (TempNewDevicePath);
+ //
+ // 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);
+ FreePool (*DevicePath);
+ *DevicePath = FullDevicePath;
+ return;
+ }
+ }
+
+ //
+ // 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++) {
+
+ Status = gBS->HandleProtocol (BlockIoBuffer[Index],
&gEfiDevicePathProtocolGuid, (VOID *) &BlockIoDevicePath);
+ if (EFI_ERROR (Status) || BlockIoDevicePath == NULL) {
+ continue;
+ }
+
+ if (BmMatchPartitionDevicePathNode (BlockIoDevicePath,
(HARDDRIVE_DEVICE_PATH *) *DevicePath)) {
+ //
+ // Find the matched partition device path
+ //
+ FullDevicePath = AppendDevicePath (BlockIoDevicePath, NextDevicePathNode
(*DevicePath));
+
+ //
+ // Save the matched partition device path in 'HDDP' variable
+ //
+ if (CachedDevicePath != NULL) {
+ //
+ // Save the matched partition device path as first instance of 'HDDP'
variable
+ //
+ if (BmMatchDevicePaths (CachedDevicePath, BlockIoDevicePath)) {
+ TempNewDevicePath = CachedDevicePath;
+ CachedDevicePath = BmDelPartMatchInstance (CachedDevicePath,
BlockIoDevicePath);
+ FreePool(TempNewDevicePath);
+ }
+
+ if (CachedDevicePath != NULL) {
+ TempNewDevicePath = CachedDevicePath;
+ CachedDevicePath = AppendDevicePathInstance (BlockIoDevicePath,
CachedDevicePath);
+ FreePool(TempNewDevicePath);
+ } else {
+ CachedDevicePath = DuplicateDevicePath (BlockIoDevicePath);
+ }
+
+ //
+ // 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.
+ //
+ InstanceNum = 0;
+ ASSERT (CachedDevicePath != NULL);
+ TempNewDevicePath = CachedDevicePath;
+ while (!IsDevicePathEnd (TempNewDevicePath)) {
+ TempNewDevicePath = NextDevicePathNode (TempNewDevicePath);
+ //
+ // Parse one instance
+ //
+ while (!IsDevicePathEndType (TempNewDevicePath)) {
+ TempNewDevicePath = NextDevicePathNode (TempNewDevicePath);
+ }
+ InstanceNum++;
+ //
+ // If the CachedDevicePath variable contain too much instance, only
remain 12 instances.
+ //
+ if (InstanceNum >= 12) {
+ SetDevicePathEndNode (TempNewDevicePath);
+ break;
+ }
+ }
+ } else {
+ CachedDevicePath = DuplicateDevicePath (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);
+ }
+ BmFreeAndSet ((VOID **) DevicePath, FullDevicePath);
+}
+
+/**
+ Algorithm follows the UEFI Spec chapter 3.4 Boot Mechanisms.
+
+ @param DevicePath Device Path to a bootable device
+
+ @return The bootable media handle. If the media on the DevicePath is not
bootable, NULL will return.
+
+**/
+EFI_HANDLE
+BmGetBootableDeviceHandle (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *UpdatedDevicePath;
+ EFI_HANDLE Handle;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ VOID *Buffer;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+ UINTN Size;
+ UINTN TempSize;
+ EFI_HANDLE ReturnHandle;
+ EFI_HANDLE *SimpleFileSystemHandles;
+ UINTN NumberSimpleFileSystemHandles;
+ UINTN Index;
+ EFI_IMAGE_DOS_HEADER DosHeader;
+ EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData;
+ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
+
+ ReturnHandle = NULL;
+ UpdatedDevicePath = DevicePath;
+
+ //
+ // Check whether the device is connected
+ //
+ Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid,
&UpdatedDevicePath, &Handle);
+ if (EFI_ERROR (Status)) {
+ //
+ // Skip the case that the boot option point to a simple file protocol
which does not consume block Io protocol,
+ //
+ Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid,
&UpdatedDevicePath, &Handle);
+ if (EFI_ERROR (Status)) {
+ //
+ // Fail to find the proper BlockIo and simple file protocol, maybe
because device not present, we need to connect it firstly
+ //
+ UpdatedDevicePath = DevicePath;
+ Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid,
&UpdatedDevicePath, &Handle);
+ gBS->ConnectController (Handle, NULL, NULL, TRUE);
+ }
+ } else {
+ //
+ // For removable device boot option, its contained device path only point
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);
+ //
+ // Get BlockIo protocol and check removable attribute
+ //
+ Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID
**)&BlockIo);
+ //
+ // 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.
+ //
+ 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
+ //
+ 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)) {
+ //
+ // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from
removable Media
+ // machinename is ia32, ia64, x64, ...
+ //
+ Hdr.Union = &HdrData;
+ Status = BmGetImageHeader (
+ SimpleFileSystemHandles[Index],
+ EFI_REMOVABLE_MEDIA_FILE_NAME,
+ &DosHeader,
+ Hdr
+ );
+ if (!EFI_ERROR (Status) && EFI_IMAGE_MACHINE_TYPE_SUPPORTED
(Hdr.Pe32->FileHeader.Machine) &&
+ (Hdr.Pe32->OptionalHeader.Subsystem ==
EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION)
+ ) {
+ ReturnHandle = SimpleFileSystemHandles[Index];
+ break;
+ }
+ }
+ }
+
+ if (SimpleFileSystemHandles != NULL) {
+ FreePool(SimpleFileSystemHandles);
+ }
+
+ return ReturnHandle;
+}
+
+/**
+ Get the image file buffer data and buffer size by its device path.
+
+ @param FilePath On input, a pointer to an allocated buffer that contains
the
+ file device path.
+ On output the device path pointer could be modified to
point to
+ a new allocated buffer that contains the full device path.
+ It could be caused by either short-form device path
expanding,
+ or default boot file path appending.
+ @param FileSize A pointer to the size of the file buffer.
+
+ @retval NULL The file can't be found.
+ @retval other The file buffer. The caller is responsible to free memory.
+**/
+VOID *
+BmLoadEfiBootOption (
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath,
+ OUT UINTN *FileSize
+ )
+{
+ EFI_HANDLE Handle;
+ VOID *FileBuffer;
+ UINT32 AuthenticationStatus;
+ EFI_DEVICE_PATH_PROTOCOL *Node;
+
+ ASSERT ((FilePath != NULL) && (*FilePath != NULL) && (FileSize != NULL));
+
+ EfiBootManagerConnectDevicePath (*FilePath, NULL);
+
+ *FileSize = 0;
+ FileBuffer = NULL;
+ //
+ // 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
+ //
+ BmExpandPartitionShortFormDevicePath (FilePath);
+ if (*FilePath == NULL) {
+ return NULL;
+ }
+
+ } 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 = BmExpandUsbShortFormDevicePath (FilePath, FileSize);
+ if (FileBuffer == NULL) {
+ return NULL;
+ }
+ }
+ }
+
+ //
+ // Fix up the boot option path if it points to a FV in memory map style of
device path
+ //
+ if (BmIsMemmapFvFilePath (*FilePath)) {
+ BmFixupMemmapFvFilePath (FilePath);
+ if (*FilePath == NULL) {
+ return NULL;
+ }
+ }
+
+ if (FileBuffer == NULL) {
+ FileBuffer = GetFileBufferByFilePath (TRUE, *FilePath, FileSize,
&AuthenticationStatus);
+ }
+
+ //
+ // If we didn't find an image directly, we need to try as if it is a
removable device boot option
+ // and load the image according to the default boot behavior.
+ //
+ if (FileBuffer == NULL) {
+ //
+ // check if there is a bootable media could be found in this device path,
+ // and get the bootable media handle
+ //
+ Handle = BmGetBootableDeviceHandle (*FilePath);
+ if (Handle != NULL) {
+ //
+ // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from the
media
+ // machinename is ia32, ia64, x64, ...
+ //
+ BmFreeAndSet ((VOID **) FilePath, FileDevicePath (Handle,
EFI_REMOVABLE_MEDIA_FILE_NAME));
+ ASSERT (*FilePath != NULL);
+ FileBuffer = GetFileBufferByFilePath (TRUE, *FilePath, FileSize,
&AuthenticationStatus);
+ }
+ }
+
+ if (FileBuffer == NULL) {
+ BmFreeAndSet ((VOID **) FilePath, NULL);
+ }
+
+ 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->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 (L"BootOrder", &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 {
+ REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_DXE_BS_DRIVER |
EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT));
+ EfiSignalEventReadyToBoot();
+ //
+ // 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;
+ FilePath = DuplicateDevicePath (BootOption->FilePath);
+ FileBuffer = BmLoadEfiBootOption (&FilePath, &FileSize);
+ if (FileBuffer != NULL) {
+
+ REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32
(PcdProgressCodeOsLoaderLoad));
+
+ Status = gBS->LoadImage (
+ TRUE,
+ gImageHandle,
+ FilePath,
+ FileBuffer,
+ FileSize,
+ &ImageHandle
+ );
+ FreePool (FileBuffer);
+ 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 *TmpHdPath;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ BOOLEAN Match;
+ EFI_DEVICE_PATH_PROTOCOL *BlockIoHdDevicePathNode;
+
+ if ((BlockIoDevicePath == NULL) || (HardDriveDevicePath == NULL)) {
+ return FALSE;
+ }
+
+ //
+ // Make PreviousDevicePath == the device path node before the end node
+ //
+ DevicePath = BlockIoDevicePath;
+ BlockIoHdDevicePathNode = NULL;
+
+ //
+ // find the partition device path node
+ //
+ while (!IsDevicePathEnd (DevicePath)) {
+ if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) &&
+ (DevicePathSubType (DevicePath) == MEDIA_HARDDRIVE_DP)
+ ) {
+ BlockIoHdDevicePathNode = DevicePath;
+ break;
+ }
+
+ DevicePath = NextDevicePathNode (DevicePath);
+ }
+
+ if (BlockIoHdDevicePathNode == NULL) {
+ return FALSE;
+ }
+ //
+ // See if the harddrive device path in blockio matches the orig Hard Drive
Node
+ //
+ TmpHdPath = (HARDDRIVE_DEVICE_PATH *) BlockIoHdDevicePathNode;
+ Match = FALSE;
+
+ //
+ // Check for the match
+ //
+ if ((TmpHdPath->MBRType == HardDriveDevicePath->MBRType) &&
+ (TmpHdPath->SignatureType == HardDriveDevicePath->SignatureType)) {
+ switch (TmpHdPath->SignatureType) {
+ case SIGNATURE_TYPE_GUID:
+ Match = CompareGuid ((EFI_GUID *)TmpHdPath->Signature, (EFI_GUID
*)HardDriveDevicePath->Signature);
+ break;
+ case SIGNATURE_TYPE_MBR:
+ Match = (BOOLEAN) (*((UINT32 *) (&(TmpHdPath->Signature[0]))) ==
ReadUnaligned32((UINT32 *)(&(HardDriveDevicePath->Signature[0]))));
+ break;
+ default:
+ Match = FALSE;
+ break;
+ }
+ }
+
+ return Match;
+}
+
+/**
+ 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;
+ }
+}
+
Added: trunk/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmConnect.c
===================================================================
--- trunk/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmConnect.c
(rev 0)
+++ trunk/edk2/MdeModulePkg/Library/UefiBootManagerLib/BmConnect.c
2015-05-06 04:47:02 UTC (rev 17327)
@@ -0,0 +1,318 @@
+/** @file
+ Library functions which relate with connecting the device.
+
+Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD
License
+which accompanies this distribution. The full text of the license may be
found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "InternalBm.h"
+
+/**
+ Connect all the drivers to all the controllers.
+
+ This function makes sure all the current system drivers manage the
correspoinding
+ controllers if have. And at the same time, makes sure all the system
controllers
+ have driver to manage it if have.
+**/
+VOID
+BmConnectAllDriversToAllControllers (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ UINTN Index;
+
+ do {
+ //
+ // Connect All EFI 1.10 drivers following EFI 1.10 algorithm
+ //
+ gBS->LocateHandleBuffer (
+ AllHandles,
+ NULL,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+
+ for (Index = 0; Index < HandleCount; Index++) {
+ gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
+ }
+
+ if (HandleBuffer != NULL) {
+ FreePool (HandleBuffer);
+ }
+
+ //
+ // Check to see if it's possible to dispatch an more DXE drivers.
+ // The above code may have made new DXE drivers show up.
+ // If any new driver is dispatched (Status == EFI_SUCCESS) and we will try
+ // the connect again.
+ //
+ Status = gDS->Dispatch ();
+
+ } while (!EFI_ERROR (Status));
+}
+
+/**
+ This function will connect all the system driver to controller
+ first, and then special connect the default console, this make
+ sure all the system controller available and the platform default
+ console connected.
+
+**/
+VOID
+EFIAPI
+EfiBootManagerConnectAll (
+ VOID
+ )
+{
+ //
+ // Connect the platform console first
+ //
@@ Diff output truncated at 100000 characters. @@
------------------------------------------------------------------------------
One dashboard for servers and applications across Physical-Virtual-Cloud
Widest out-of-the-box monitoring support with 50+ applications
Performance metrics, stats and reports that give you Actionable Insights
Deep dive visibility with transaction tracing using APM Insight.
http://ad.doubleclick.net/ddm/clk/290420510;117567292;y
_______________________________________________
edk2-commits mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/edk2-commits