2015-05-06 06:48:56 +02:00
/** @file
This module produce main entry for BDS phase - BdsEntry .
When this module was dispatched by DxeCore , gEfiBdsArchProtocolGuid will be installed
which contains interface of BdsEntry .
After DxeCore finish DXE phase , gEfiBdsArchProtocolGuid - > BdsEntry will be invoked
to enter BDS phase .
2015-08-28 07:41:06 +02:00
( C ) Copyright 2015 Hewlett - Packard Development Company , L . P . < BR >
2015-05-06 06:48:56 +02:00
Copyright ( c ) 2004 - 2015 , Intel Corporation . All rights reserved . < BR >
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution . The full text of the license may be found at
http : //opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN " AS IS " BASIS ,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND , EITHER EXPRESS OR IMPLIED .
* */
# include "Bds.h"
# include "Language.h"
# include "HwErrRecSupport.h"
# define SET_BOOT_OPTION_SUPPORT_KEY_COUNT(a, c) { \
( a ) = ( ( a ) & ~ EFI_BOOT_OPTION_SUPPORT_COUNT ) | ( ( ( c ) < < LowBitSet32 ( EFI_BOOT_OPTION_SUPPORT_COUNT ) ) & EFI_BOOT_OPTION_SUPPORT_COUNT ) ; \
}
///
/// BDS arch protocol instance initial value.
///
EFI_BDS_ARCH_PROTOCOL gBds = {
BdsEntry
} ;
//
// gConnectConInEvent - Event which is signaled when ConIn connection is required
//
EFI_EVENT gConnectConInEvent = NULL ;
///
/// The read-only variables defined in UEFI Spec.
///
CHAR16 * mReadOnlyVariables [ ] = {
EFI_PLATFORM_LANG_CODES_VARIABLE_NAME ,
EFI_LANG_CODES_VARIABLE_NAME ,
EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME ,
EFI_HW_ERR_REC_SUPPORT_VARIABLE_NAME ,
EFI_OS_INDICATIONS_SUPPORT_VARIABLE_NAME
} ;
2015-05-11 08:33:45 +02:00
CHAR16 * mBdsLoadOptionName [ ] = {
L " Driver " ,
L " SysPrep " ,
2015-11-17 11:15:09 +01:00
L " Boot " ,
L " PlatformRecovery "
2015-05-11 08:33:45 +02:00
} ;
2015-05-06 06:48:56 +02:00
/**
Event to Connect ConIn .
@ param Event Event whose notification function is being invoked .
@ param Context Pointer to the notification function ' s context ,
which is implementation - dependent .
* */
VOID
EFIAPI
BdsDxeOnConnectConInCallBack (
IN EFI_EVENT Event ,
IN VOID * Context
)
{
EFI_STATUS Status ;
//
// When Osloader call ReadKeyStroke to signal this event
// no driver dependency is assumed existing. So use a non-dispatch version
//
Status = EfiBootManagerConnectConsoleVariable ( ConIn ) ;
if ( EFI_ERROR ( Status ) ) {
//
// Should not enter this case, if enter, the keyboard will not work.
// May need platfrom policy to connect keyboard.
//
2015-05-11 08:33:45 +02:00
DEBUG ( ( EFI_D_WARN , " [Bds] Connect ConIn failed - %r!!! \n " , Status ) ) ;
2015-05-06 06:48:56 +02:00
}
}
/**
Install Boot Device Selection Protocol
@ param ImageHandle The image handle .
@ param SystemTable The system table .
@ retval EFI_SUCEESS BDS has finished initializing .
Return the dispatcher and recall BDS . Entry
@ retval Other Return status from AllocatePool ( ) or gBS - > InstallProtocolInterface
* */
EFI_STATUS
EFIAPI
BdsInitialize (
IN EFI_HANDLE ImageHandle ,
IN EFI_SYSTEM_TABLE * SystemTable
)
{
EFI_STATUS Status ;
EFI_HANDLE Handle ;
//
// Install protocol interface
//
Handle = NULL ;
Status = gBS - > InstallMultipleProtocolInterfaces (
& Handle ,
& gEfiBdsArchProtocolGuid , & gBds ,
NULL
) ;
ASSERT_EFI_ERROR ( Status ) ;
return Status ;
}
/**
Function waits for a given event to fire , or for an optional timeout to expire .
@ param Event The event to wait for
@ param Timeout An optional timeout value in 100 ns units .
@ retval EFI_SUCCESS Event fired before Timeout expired .
@ retval EFI_TIME_OUT Timout expired before Event fired . .
* */
EFI_STATUS
BdsWaitForSingleEvent (
IN EFI_EVENT Event ,
IN UINT64 Timeout OPTIONAL
)
{
UINTN Index ;
EFI_STATUS Status ;
EFI_EVENT TimerEvent ;
EFI_EVENT WaitList [ 2 ] ;
if ( Timeout ! = 0 ) {
//
// Create a timer event
//
Status = gBS - > CreateEvent ( EVT_TIMER , 0 , NULL , NULL , & TimerEvent ) ;
if ( ! EFI_ERROR ( Status ) ) {
//
// Set the timer event
//
gBS - > SetTimer (
TimerEvent ,
TimerRelative ,
Timeout
) ;
//
// Wait for the original event or the timer
//
WaitList [ 0 ] = Event ;
WaitList [ 1 ] = TimerEvent ;
Status = gBS - > WaitForEvent ( 2 , WaitList , & Index ) ;
ASSERT_EFI_ERROR ( Status ) ;
gBS - > CloseEvent ( TimerEvent ) ;
//
// If the timer expired, change the return to timed out
//
if ( Index = = 1 ) {
Status = EFI_TIMEOUT ;
}
}
} else {
//
// No timeout... just wait on the event
//
Status = gBS - > WaitForEvent ( 1 , & Event , & Index ) ;
ASSERT ( ! EFI_ERROR ( Status ) ) ;
ASSERT ( Index = = 0 ) ;
}
return Status ;
}
/**
The function reads user inputs .
* */
VOID
BdsReadKeys (
VOID
)
{
EFI_STATUS Status ;
EFI_INPUT_KEY Key ;
if ( PcdGetBool ( PcdConInConnectOnDemand ) ) {
return ;
}
while ( gST - > ConIn ! = NULL ) {
Status = gST - > ConIn - > ReadKeyStroke ( gST - > ConIn , & Key ) ;
if ( EFI_ERROR ( Status ) ) {
//
// No more keys.
//
break ;
}
}
}
/**
The function waits for the boot manager timeout expires or hotkey is pressed .
It calls PlatformBootManagerWaitCallback each second .
@ param HotkeyTriggered Input hotkey event .
* */
VOID
BdsWait (
IN EFI_EVENT HotkeyTriggered
)
{
EFI_STATUS Status ;
UINT16 TimeoutRemain ;
DEBUG ( ( EFI_D_INFO , " [Bds]BdsWait ...Zzzzzzzzzzzz... \n " ) ) ;
TimeoutRemain = PcdGet16 ( PcdPlatformBootTimeOut ) ;
while ( TimeoutRemain ! = 0 ) {
DEBUG ( ( EFI_D_INFO , " [Bds]BdsWait(%d)..Zzzz... \n " , ( UINTN ) TimeoutRemain ) ) ;
PlatformBootManagerWaitCallback ( TimeoutRemain ) ;
BdsReadKeys ( ) ; // BUGBUG: Only reading can signal HotkeyTriggered
// Can be removed after all keyboard drivers invoke callback in timer callback.
if ( HotkeyTriggered ! = NULL ) {
Status = BdsWaitForSingleEvent ( HotkeyTriggered , EFI_TIMER_PERIOD_SECONDS ( 1 ) ) ;
if ( ! EFI_ERROR ( Status ) ) {
break ;
}
} else {
gBS - > Stall ( 1000000 ) ;
}
//
// 0xffff means waiting forever
// BDS with no hotkey provided and 0xffff as timeout will "hang" in the loop
//
if ( TimeoutRemain ! = 0xffff ) {
TimeoutRemain - - ;
}
}
DEBUG ( ( EFI_D_INFO , " [Bds]Exit the waiting! \n " ) ) ;
}
/**
Attempt to boot each boot option in the BootOptions array .
@ param BootOptions Input boot option array .
@ param BootOptionCount Input boot option count .
2015-11-17 11:15:09 +01:00
@ param BootManagerMenu Input boot manager menu .
2015-05-06 06:48:56 +02:00
@ retval TRUE Successfully boot one of the boot options .
@ retval FALSE Failed boot any of the boot options .
* */
BOOLEAN
2015-11-17 11:15:09 +01:00
BootBootOptions (
2015-05-06 06:48:56 +02:00
IN EFI_BOOT_MANAGER_LOAD_OPTION * BootOptions ,
2015-11-17 11:15:09 +01:00
IN UINTN BootOptionCount ,
IN EFI_BOOT_MANAGER_LOAD_OPTION * BootManagerMenu
2015-05-06 06:48:56 +02:00
)
{
UINTN Index ;
//
// Attempt boot each boot option
//
for ( Index = 0 ; Index < BootOptionCount ; Index + + ) {
//
// According to EFI Specification, if a load option is not marked
// as LOAD_OPTION_ACTIVE, the boot manager will not automatically
// load the option.
//
if ( ( BootOptions [ Index ] . Attributes & LOAD_OPTION_ACTIVE ) = = 0 ) {
continue ;
}
//
// Boot#### load options with LOAD_OPTION_CATEGORY_APP are executables which are not
// part of the normal boot processing. Boot options with reserved category values will be
// ignored by the boot manager.
//
if ( ( BootOptions [ Index ] . Attributes & LOAD_OPTION_CATEGORY ) ! = LOAD_OPTION_CATEGORY_BOOT ) {
continue ;
}
//
// All the driver options should have been processed since
// now boot will be performed.
//
EfiBootManagerBoot ( & BootOptions [ Index ] ) ;
//
2015-11-17 11:15:09 +01:00
// If the boot via Boot#### returns with a status of EFI_SUCCESS, platform firmware
// supports boot manager menu, and if firmware is configured to boot in an
// interactive mode, the boot manager will stop processing the BootOrder variable and
// present a boot manager menu to the user.
2015-05-06 06:48:56 +02:00
//
if ( BootOptions [ Index ] . Status = = EFI_SUCCESS ) {
2015-11-17 11:15:09 +01:00
EfiBootManagerBoot ( BootManagerMenu ) ;
2015-05-06 06:48:56 +02:00
break ;
}
}
return ( BOOLEAN ) ( Index < BootOptionCount ) ;
}
/**
2015-11-17 11:15:09 +01:00
The function will load and start every Driver # # # # , SysPrep # # # # or PlatformRecovery # # # # .
2015-05-06 06:48:56 +02:00
2015-05-11 08:33:45 +02:00
@ param LoadOptions Load option array .
@ param LoadOptionCount Load option count .
2015-05-06 06:48:56 +02:00
* */
VOID
2015-05-11 08:33:45 +02:00
ProcessLoadOptions (
IN EFI_BOOT_MANAGER_LOAD_OPTION * LoadOptions ,
IN UINTN LoadOptionCount
2015-05-06 06:48:56 +02:00
)
{
2015-05-11 08:33:45 +02:00
EFI_STATUS Status ;
UINTN Index ;
BOOLEAN ReconnectAll ;
EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType ;
2015-05-06 06:48:56 +02:00
2015-11-17 11:15:09 +01:00
ReconnectAll = FALSE ;
2015-05-11 08:33:45 +02:00
LoadOptionType = LoadOptionTypeMax ;
2015-05-06 06:48:56 +02:00
//
// Process the driver option
//
2015-05-11 08:33:45 +02:00
for ( Index = 0 ; Index < LoadOptionCount ; Index + + ) {
2015-05-06 06:48:56 +02:00
//
2015-05-11 08:33:45 +02:00
// All the load options in the array should be of the same type.
2015-05-06 06:48:56 +02:00
//
2015-11-17 11:15:09 +01:00
if ( Index = = 0 ) {
2015-05-11 08:33:45 +02:00
LoadOptionType = LoadOptions [ Index ] . OptionType ;
2015-05-06 06:48:56 +02:00
}
2015-05-11 08:33:45 +02:00
ASSERT ( LoadOptionType = = LoadOptions [ Index ] . OptionType ) ;
2015-05-06 06:48:56 +02:00
2015-05-11 08:33:45 +02:00
Status = EfiBootManagerProcessLoadOption ( & LoadOptions [ Index ] ) ;
2015-05-06 06:48:56 +02:00
2015-11-17 11:15:09 +01:00
if ( ! EFI_ERROR ( Status ) ) {
if ( LoadOptionType = = LoadOptionTypePlatformRecovery ) {
//
// Stop processing if any entry is successful
//
break ;
}
if ( ( LoadOptions [ Index ] . Attributes & LOAD_OPTION_FORCE_RECONNECT ) ! = 0 ) {
ReconnectAll = TRUE ;
}
2015-05-06 06:48:56 +02:00
}
}
2015-05-11 08:33:45 +02:00
2015-05-06 06:48:56 +02:00
//
2015-05-11 08:33:45 +02:00
// If a driver load option is marked as LOAD_OPTION_FORCE_RECONNECT,
// then all of the EFI drivers in the system will be disconnected and
// reconnected after the last driver load option is processed.
2015-05-06 06:48:56 +02:00
//
2015-05-11 08:33:45 +02:00
if ( ReconnectAll & & LoadOptionType = = LoadOptionTypeDriver ) {
2015-05-06 06:48:56 +02:00
EfiBootManagerDisconnectAll ( ) ;
EfiBootManagerConnectAll ( ) ;
}
}
/**
Validate input console variable data .
If found the device path is not a valid device path , remove the variable .
@ param VariableName Input console variable name .
* */
VOID
BdsFormalizeConsoleVariable (
IN CHAR16 * VariableName
)
{
EFI_DEVICE_PATH_PROTOCOL * DevicePath ;
UINTN VariableSize ;
EFI_STATUS Status ;
GetEfiGlobalVariable2 ( VariableName , ( VOID * * ) & DevicePath , & VariableSize ) ;
if ( ( DevicePath ! = NULL ) & & ! IsDevicePathValid ( DevicePath , VariableSize ) ) {
Status = gRT - > SetVariable (
VariableName ,
& gEfiGlobalVariableGuid ,
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE ,
0 ,
NULL
) ;
//
// Deleting variable with current variable implementation shouldn't fail.
//
ASSERT_EFI_ERROR ( Status ) ;
}
if ( DevicePath ! = NULL ) {
FreePool ( DevicePath ) ;
}
}
/**
Formalize OsIndication related variables .
For OsIndicationsSupported , Create a BS / RT / UINT64 variable to report caps
Delete OsIndications variable if it is not NV / BS / RT UINT64 .
Item 3 is used to solve case when OS corrupts OsIndications . Here simply delete this NV variable .
* */
VOID
BdsFormalizeOSIndicationVariable (
VOID
)
{
EFI_STATUS Status ;
UINT64 OsIndicationSupport ;
UINT64 OsIndication ;
UINTN DataSize ;
UINT32 Attributes ;
//
// OS indicater support variable
//
2015-11-17 11:15:09 +01:00
OsIndicationSupport = EFI_OS_INDICATIONS_BOOT_TO_FW_UI | EFI_OS_INDICATIONS_START_PLATFORM_RECOVERY ;
2015-05-06 06:48:56 +02:00
Status = gRT - > SetVariable (
2015-11-17 11:13:21 +01:00
EFI_OS_INDICATIONS_SUPPORT_VARIABLE_NAME ,
2015-05-06 06:48:56 +02:00
& gEfiGlobalVariableGuid ,
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS ,
sizeof ( UINT64 ) ,
& OsIndicationSupport
) ;
//
// Platform needs to make sure setting volatile variable before calling 3rd party code shouldn't fail.
//
ASSERT_EFI_ERROR ( Status ) ;
//
// If OsIndications is invalid, remove it.
// Invalid case
// 1. Data size != UINT64
// 2. OsIndication value inconsistence
// 3. OsIndication attribute inconsistence
//
OsIndication = 0 ;
Attributes = 0 ;
DataSize = sizeof ( UINT64 ) ;
Status = gRT - > GetVariable (
2015-11-17 11:13:21 +01:00
EFI_OS_INDICATIONS_VARIABLE_NAME ,
2015-05-06 06:48:56 +02:00
& gEfiGlobalVariableGuid ,
& Attributes ,
& DataSize ,
& OsIndication
) ;
if ( Status = = EFI_NOT_FOUND ) {
return ;
}
if ( ( DataSize ! = sizeof ( OsIndication ) ) | |
( ( OsIndication & ~ OsIndicationSupport ) ! = 0 ) | |
( Attributes ! = ( EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE ) )
) {
DEBUG ( ( EFI_D_ERROR , " [Bds] Unformalized OsIndications variable exists. Delete it \n " ) ) ;
Status = gRT - > SetVariable (
2015-11-17 11:13:21 +01:00
EFI_OS_INDICATIONS_VARIABLE_NAME ,
2015-05-06 06:48:56 +02:00
& gEfiGlobalVariableGuid ,
0 ,
0 ,
NULL
) ;
//
// Deleting variable with current variable implementation shouldn't fail.
//
ASSERT_EFI_ERROR ( Status ) ;
}
}
/**
Validate variables .
* */
VOID
BdsFormalizeEfiGlobalVariable (
VOID
)
{
//
// Validate Console variable.
//
2015-11-17 11:13:21 +01:00
BdsFormalizeConsoleVariable ( EFI_CON_IN_VARIABLE_NAME ) ;
BdsFormalizeConsoleVariable ( EFI_CON_OUT_VARIABLE_NAME ) ;
BdsFormalizeConsoleVariable ( EFI_ERR_OUT_VARIABLE_NAME ) ;
2015-05-06 06:48:56 +02:00
//
// Validate OSIndication related variable.
//
BdsFormalizeOSIndicationVariable ( ) ;
}
/**
Allocate a block of memory that will contain performance data to OS .
* */
VOID
BdsAllocateMemoryForPerformanceData (
VOID
)
{
EFI_STATUS Status ;
EFI_PHYSICAL_ADDRESS AcpiLowMemoryBase ;
EDKII_VARIABLE_LOCK_PROTOCOL * VariableLock ;
AcpiLowMemoryBase = 0x0FFFFFFFFULL ;
//
// Allocate a block of memory that will contain performance data to OS.
//
Status = gBS - > AllocatePages (
AllocateMaxAddress ,
EfiReservedMemoryType ,
EFI_SIZE_TO_PAGES ( PERF_DATA_MAX_LENGTH ) ,
& AcpiLowMemoryBase
) ;
if ( ! EFI_ERROR ( Status ) ) {
//
// Save the pointer to variable for use in S3 resume.
//
Status = BdsDxeSetVariableAndReportStatusCodeOnError (
L " PerfDataMemAddr " ,
& gPerformanceProtocolGuid ,
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS ,
sizeof ( EFI_PHYSICAL_ADDRESS ) ,
& AcpiLowMemoryBase
) ;
if ( EFI_ERROR ( Status ) ) {
DEBUG ( ( EFI_D_ERROR , " [Bds] PerfDataMemAddr (%08x) cannot be saved to NV storage. \n " , AcpiLowMemoryBase ) ) ;
}
//
// Mark L"PerfDataMemAddr" variable to read-only if the Variable Lock protocol exists
// Still lock it even the variable cannot be saved to prevent it's set by 3rd party code.
//
Status = gBS - > LocateProtocol ( & gEdkiiVariableLockProtocolGuid , NULL , ( VOID * * ) & VariableLock ) ;
if ( ! EFI_ERROR ( Status ) ) {
Status = VariableLock - > RequestToLock ( VariableLock , L " PerfDataMemAddr " , & gPerformanceProtocolGuid ) ;
ASSERT_EFI_ERROR ( Status ) ;
}
}
}
/**
Service routine for BdsInstance - > Entry ( ) . Devices are connected , the
consoles are initialized , and the boot options are tried .
@ param This Protocol Instance structure .
* */
VOID
EFIAPI
BdsEntry (
IN EFI_BDS_ARCH_PROTOCOL * This
)
{
2015-05-11 08:33:45 +02:00
EFI_BOOT_MANAGER_LOAD_OPTION * LoadOptions ;
UINTN LoadOptionCount ;
2015-05-06 06:48:56 +02:00
CHAR16 * FirmwareVendor ;
EFI_EVENT HotkeyTriggered ;
UINT64 OsIndication ;
UINTN DataSize ;
EFI_STATUS Status ;
UINT32 BootOptionSupport ;
UINT16 BootTimeOut ;
EDKII_VARIABLE_LOCK_PROTOCOL * VariableLock ;
UINTN Index ;
2015-11-17 11:14:13 +01:00
EFI_BOOT_MANAGER_LOAD_OPTION LoadOption ;
2015-05-06 06:48:56 +02:00
UINT16 * BootNext ;
CHAR16 BootNextVariableName [ sizeof ( " Boot#### " ) ] ;
2015-05-11 08:33:45 +02:00
EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu ;
BOOLEAN BootFwUi ;
2015-11-17 11:15:09 +01:00
BOOLEAN PlatformRecovery ;
BOOLEAN BootSuccess ;
2015-11-17 11:14:13 +01:00
EFI_DEVICE_PATH_PROTOCOL * FilePath ;
2015-05-06 06:48:56 +02:00
HotkeyTriggered = NULL ;
Status = EFI_SUCCESS ;
2015-11-17 11:15:09 +01:00
BootSuccess = FALSE ;
2015-05-06 06:48:56 +02:00
//
// Insert the performance probe
//
PERF_END ( NULL , " DXE " , NULL , 0 ) ;
PERF_START ( NULL , " BDS " , NULL , 0 ) ;
DEBUG ( ( EFI_D_INFO , " [Bds] Entry... \n " ) ) ;
PERF_CODE (
BdsAllocateMemoryForPerformanceData ( ) ;
) ;
//
// Fill in FirmwareVendor and FirmwareRevision from PCDs
//
FirmwareVendor = ( CHAR16 * ) PcdGetPtr ( PcdFirmwareVendor ) ;
gST - > FirmwareVendor = AllocateRuntimeCopyPool ( StrSize ( FirmwareVendor ) , FirmwareVendor ) ;
ASSERT ( gST - > FirmwareVendor ! = NULL ) ;
gST - > FirmwareRevision = PcdGet32 ( PcdFirmwareRevision ) ;
//
// Fixup Tasble CRC after we updated Firmware Vendor and Revision
//
gST - > Hdr . CRC32 = 0 ;
gBS - > CalculateCrc32 ( ( VOID * ) gST , sizeof ( EFI_SYSTEM_TABLE ) , & gST - > Hdr . CRC32 ) ;
//
// Validate Variable.
//
BdsFormalizeEfiGlobalVariable ( ) ;
//
// Mark the read-only variables if the Variable Lock protocol exists
//
Status = gBS - > LocateProtocol ( & gEdkiiVariableLockProtocolGuid , NULL , ( VOID * * ) & VariableLock ) ;
DEBUG ( ( EFI_D_INFO , " [BdsDxe] Locate Variable Lock protocol - %r \n " , Status ) ) ;
if ( ! EFI_ERROR ( Status ) ) {
for ( Index = 0 ; Index < sizeof ( mReadOnlyVariables ) / sizeof ( mReadOnlyVariables [ 0 ] ) ; Index + + ) {
Status = VariableLock - > RequestToLock ( VariableLock , mReadOnlyVariables [ Index ] , & gEfiGlobalVariableGuid ) ;
ASSERT_EFI_ERROR ( Status ) ;
}
}
InitializeHwErrRecSupport ( ) ;
//
// Initialize L"Timeout" EFI global variable.
//
BootTimeOut = PcdGet16 ( PcdPlatformBootTimeOut ) ;
if ( BootTimeOut ! = 0xFFFF ) {
//
// If time out value equal 0xFFFF, no need set to 0xFFFF to variable area because UEFI specification
// define same behavior between no value or 0xFFFF value for L"Timeout".
//
BdsDxeSetVariableAndReportStatusCodeOnError (
EFI_TIME_OUT_VARIABLE_NAME ,
& gEfiGlobalVariableGuid ,
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE ,
sizeof ( UINT16 ) ,
& BootTimeOut
) ;
}
//
// Initialize L"BootOptionSupport" EFI global variable.
// Lazy-ConIn implictly disables BDS hotkey.
//
2015-05-11 08:33:45 +02:00
BootOptionSupport = EFI_BOOT_OPTION_SUPPORT_APP | EFI_BOOT_OPTION_SUPPORT_SYSPREP ;
2015-05-06 06:48:56 +02:00
if ( ! PcdGetBool ( PcdConInConnectOnDemand ) ) {
BootOptionSupport | = EFI_BOOT_OPTION_SUPPORT_KEY ;
SET_BOOT_OPTION_SUPPORT_KEY_COUNT ( BootOptionSupport , 3 ) ;
}
Status = gRT - > SetVariable (
EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME ,
& gEfiGlobalVariableGuid ,
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS ,
sizeof ( BootOptionSupport ) ,
& BootOptionSupport
) ;
//
// Platform needs to make sure setting volatile variable before calling 3rd party code shouldn't fail.
//
ASSERT_EFI_ERROR ( Status ) ;
//
// Cache and remove the "BootNext" NV variable.
//
GetEfiGlobalVariable2 ( EFI_BOOT_NEXT_VARIABLE_NAME , ( VOID * * ) & BootNext , & DataSize ) ;
if ( DataSize ! = sizeof ( UINT16 ) ) {
if ( BootNext ! = NULL ) {
FreePool ( BootNext ) ;
}
BootNext = NULL ;
}
Status = gRT - > SetVariable (
EFI_BOOT_NEXT_VARIABLE_NAME ,
& gEfiGlobalVariableGuid ,
0 ,
0 ,
NULL
) ;
//
// Deleting NV variable shouldn't fail unless it doesn't exist.
//
ASSERT ( Status = = EFI_SUCCESS | | Status = = EFI_NOT_FOUND ) ;
//
// Initialize the platform language variables
//
InitializeLanguage ( TRUE ) ;
2015-11-17 11:14:13 +01:00
//
// System firmware must include a PlatformRecovery#### variable specifying
// a short-form File Path Media Device Path containing the platform default
// file path for removable media
//
FilePath = FileDevicePath ( NULL , EFI_REMOVABLE_MEDIA_FILE_NAME ) ;
Status = EfiBootManagerInitializeLoadOption (
& LoadOption ,
0 ,
LoadOptionTypePlatformRecovery ,
LOAD_OPTION_ACTIVE ,
L " Default PlatformRecovery " ,
FilePath ,
NULL ,
0
) ;
ASSERT_EFI_ERROR ( Status ) ;
EfiBootManagerLoadOptionToVariable ( & LoadOption ) ;
EfiBootManagerFreeLoadOption ( & LoadOption ) ;
FreePool ( FilePath ) ;
2015-05-06 06:48:56 +02:00
//
// Report Status Code to indicate connecting drivers will happen
//
REPORT_STATUS_CODE (
EFI_PROGRESS_CODE ,
( EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_BEGIN_CONNECTING_DRIVERS )
) ;
//
// Do the platform init, can be customized by OEM/IBV
// Possible things that can be done in PlatformBootManagerBeforeConsole:
// > Update console variable: 1. include hot-plug devices; 2. Clear ConIn and add SOL for AMT
// > Register new Driver#### or Boot####
// > Register new Key####: e.g.: F12
// > Signal ReadyToLock event
// > Authentication action: 1. connect Auth devices; 2. Identify auto logon user.
//
PERF_START ( NULL , " PlatformBootManagerBeforeConsole " , " BDS " , 0 ) ;
PlatformBootManagerBeforeConsole ( ) ;
PERF_END ( NULL , " PlatformBootManagerBeforeConsole " , " BDS " , 0 ) ;
//
// Initialize hotkey service
//
EfiBootManagerStartHotkeyService ( & HotkeyTriggered ) ;
//
2015-05-11 08:33:45 +02:00
// Execute Driver Options
2015-05-06 06:48:56 +02:00
//
2015-05-11 08:33:45 +02:00
LoadOptions = EfiBootManagerGetLoadOptions ( & LoadOptionCount , LoadOptionTypeDriver ) ;
ProcessLoadOptions ( LoadOptions , LoadOptionCount ) ;
EfiBootManagerFreeLoadOptions ( LoadOptions , LoadOptionCount ) ;
2015-05-06 06:48:56 +02:00
//
// Connect consoles
//
PERF_START ( NULL , " EfiBootManagerConnectAllDefaultConsoles " , " BDS " , 0 ) ;
if ( PcdGetBool ( PcdConInConnectOnDemand ) ) {
EfiBootManagerConnectConsoleVariable ( ConOut ) ;
EfiBootManagerConnectConsoleVariable ( ErrOut ) ;
//
// Initialize ConnectConIn event
//
Status = gBS - > CreateEventEx (
EVT_NOTIFY_SIGNAL ,
TPL_CALLBACK ,
BdsDxeOnConnectConInCallBack ,
NULL ,
& gConnectConInEventGuid ,
& gConnectConInEvent
) ;
if ( EFI_ERROR ( Status ) ) {
gConnectConInEvent = NULL ;
}
} else {
EfiBootManagerConnectAllDefaultConsoles ( ) ;
}
PERF_END ( NULL , " EfiBootManagerConnectAllDefaultConsoles " , " BDS " , 0 ) ;
//
// Do the platform specific action after the console is ready
// Possible things that can be done in PlatformBootManagerAfterConsole:
// > Console post action:
// > Dynamically switch output mode from 100x31 to 80x25 for certain senarino
// > Signal console ready platform customized event
// > Run diagnostics like memory testing
// > Connect certain devices
// > Dispatch aditional option roms
// > Special boot: e.g.: USB boot, enter UI
//
PERF_START ( NULL , " PlatformBootManagerAfterConsole " , " BDS " , 0 ) ;
PlatformBootManagerAfterConsole ( ) ;
PERF_END ( NULL , " PlatformBootManagerAfterConsole " , " BDS " , 0 ) ;
2015-11-17 11:15:09 +01:00
//
// Boot to Boot Manager Menu when EFI_OS_INDICATIONS_BOOT_TO_FW_UI is set. Skip HotkeyBoot
//
DataSize = sizeof ( UINT64 ) ;
Status = gRT - > GetVariable (
EFI_OS_INDICATIONS_VARIABLE_NAME ,
& gEfiGlobalVariableGuid ,
NULL ,
& DataSize ,
& OsIndication
) ;
if ( EFI_ERROR ( Status ) ) {
OsIndication = 0 ;
}
2015-05-06 06:48:56 +02:00
DEBUG_CODE (
2015-05-11 08:33:45 +02:00
EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType ;
2015-11-17 11:15:09 +01:00
DEBUG ( ( EFI_D_INFO , " [Bds]OsIndication: %016x \n " , OsIndication ) ) ;
2015-05-11 08:33:45 +02:00
DEBUG ( ( EFI_D_INFO , " [Bds]=============Begin Load Options Dumping ...============= \n " ) ) ;
for ( LoadOptionType = 0 ; LoadOptionType < LoadOptionTypeMax ; LoadOptionType + + ) {
2015-05-06 06:48:56 +02:00
DEBUG ( (
2015-05-11 08:33:45 +02:00
EFI_D_INFO , " %s Options: \n " ,
mBdsLoadOptionName [ LoadOptionType ]
2015-05-06 06:48:56 +02:00
) ) ;
2015-05-11 08:33:45 +02:00
LoadOptions = EfiBootManagerGetLoadOptions ( & LoadOptionCount , LoadOptionType ) ;
for ( Index = 0 ; Index < LoadOptionCount ; Index + + ) {
DEBUG ( (
EFI_D_INFO , " %s%04x: %s \t \t 0x%04x \n " ,
mBdsLoadOptionName [ LoadOptionType ] ,
LoadOptions [ Index ] . OptionNumber ,
LoadOptions [ Index ] . Description ,
LoadOptions [ Index ] . Attributes
) ) ;
}
EfiBootManagerFreeLoadOptions ( LoadOptions , LoadOptionCount ) ;
2015-05-06 06:48:56 +02:00
}
2015-05-11 08:33:45 +02:00
DEBUG ( ( EFI_D_INFO , " [Bds]=============End Load Options Dumping============= \n " ) ) ;
) ;
2015-05-06 06:48:56 +02:00
//
2015-11-17 11:15:09 +01:00
// BootManagerMenu always contains the correct information even call fails.
2015-05-06 06:48:56 +02:00
//
2015-11-17 11:15:09 +01:00
EfiBootManagerGetBootManagerMenu ( & BootManagerMenu ) ;
2015-05-11 08:33:45 +02:00
2015-11-17 11:15:09 +01:00
BootFwUi = ( BOOLEAN ) ( ( OsIndication & EFI_OS_INDICATIONS_BOOT_TO_FW_UI ) ! = 0 ) ;
PlatformRecovery = ( BOOLEAN ) ( ( OsIndication & EFI_OS_INDICATIONS_START_PLATFORM_RECOVERY ) ! = 0 ) ;
2015-05-11 08:33:45 +02:00
//
// Clear EFI_OS_INDICATIONS_BOOT_TO_FW_UI to acknowledge OS
//
2015-11-17 11:15:09 +01:00
if ( BootFwUi | | PlatformRecovery ) {
OsIndication & = ~ ( ( UINT64 ) ( EFI_OS_INDICATIONS_BOOT_TO_FW_UI | EFI_OS_INDICATIONS_START_PLATFORM_RECOVERY ) ) ;
2015-05-06 06:48:56 +02:00
Status = gRT - > SetVariable (
2015-11-17 11:13:21 +01:00
EFI_OS_INDICATIONS_VARIABLE_NAME ,
2015-05-06 06:48:56 +02:00
& gEfiGlobalVariableGuid ,
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE ,
sizeof ( UINT64 ) ,
& OsIndication
) ;
//
// Changing the content without increasing its size with current variable implementation shouldn't fail.
//
ASSERT_EFI_ERROR ( Status ) ;
2015-05-11 08:33:45 +02:00
}
2015-05-06 06:48:56 +02:00
2015-05-11 08:33:45 +02:00
//
// Launch Boot Manager Menu directly when EFI_OS_INDICATIONS_BOOT_TO_FW_UI is set. Skip HotkeyBoot
//
if ( BootFwUi ) {
2015-05-06 06:48:56 +02:00
//
// Follow generic rule, Call BdsDxeOnConnectConInCallBack to connect ConIn before enter UI
//
if ( PcdGetBool ( PcdConInConnectOnDemand ) ) {
BdsDxeOnConnectConInCallBack ( NULL , NULL ) ;
}
//
2015-05-11 08:33:45 +02:00
// Directly enter the setup page.
2015-05-06 06:48:56 +02:00
//
2015-05-11 08:33:45 +02:00
EfiBootManagerBoot ( & BootManagerMenu ) ;
2015-05-06 06:48:56 +02:00
}
2015-11-17 11:15:09 +01:00
if ( ! PlatformRecovery ) {
//
// Execute SysPrep####
//
LoadOptions = EfiBootManagerGetLoadOptions ( & LoadOptionCount , LoadOptionTypeSysPrep ) ;
ProcessLoadOptions ( LoadOptions , LoadOptionCount ) ;
EfiBootManagerFreeLoadOptions ( LoadOptions , LoadOptionCount ) ;
2015-05-11 08:33:45 +02:00
2015-11-17 11:15:09 +01:00
//
// Execute Key####
//
PERF_START ( NULL , " BdsWait " , " BDS " , 0 ) ;
BdsWait ( HotkeyTriggered ) ;
PERF_END ( NULL , " BdsWait " , " BDS " , 0 ) ;
2015-05-11 08:33:45 +02:00
2015-11-17 11:15:09 +01:00
//
// BdsReadKeys() can be removed after all keyboard drivers invoke callback in timer callback.
//
BdsReadKeys ( ) ;
2015-05-11 08:33:45 +02:00
2015-11-17 11:15:09 +01:00
EfiBootManagerHotkeyBoot ( ) ;
2015-05-11 08:33:45 +02:00
2015-11-17 11:15:09 +01:00
//
// Boot to "BootNext"
//
if ( BootNext ! = NULL ) {
UnicodeSPrint ( BootNextVariableName , sizeof ( BootNextVariableName ) , L " Boot%04x " , * BootNext ) ;
Status = EfiBootManagerVariableToLoadOption ( BootNextVariableName , & LoadOption ) ;
if ( ! EFI_ERROR ( Status ) ) {
2015-11-17 11:14:13 +01:00
EfiBootManagerBoot ( & LoadOption ) ;
EfiBootManagerFreeLoadOption ( & LoadOption ) ;
2015-11-17 11:15:09 +01:00
if ( LoadOption . Status = = EFI_SUCCESS ) {
//
// Boot to Boot Manager Menu upon EFI_SUCCESS
//
EfiBootManagerBoot ( & BootManagerMenu ) ;
}
2015-05-06 06:48:56 +02:00
}
}
2015-11-17 11:15:09 +01:00
do {
//
// Retry to boot if any of the boot succeeds
//
LoadOptions = EfiBootManagerGetLoadOptions ( & LoadOptionCount , LoadOptionTypeBoot ) ;
BootSuccess = BootBootOptions ( LoadOptions , LoadOptionCount , & BootManagerMenu ) ;
EfiBootManagerFreeLoadOptions ( LoadOptions , LoadOptionCount ) ;
} while ( BootSuccess ) ;
2015-05-06 06:48:56 +02:00
}
2015-11-17 11:15:09 +01:00
EfiBootManagerFreeLoadOption ( & BootManagerMenu ) ;
if ( ! BootSuccess ) {
LoadOptions = EfiBootManagerGetLoadOptions ( & LoadOptionCount , LoadOptionTypePlatformRecovery ) ;
ProcessLoadOptions ( LoadOptions , LoadOptionCount ) ;
EfiBootManagerFreeLoadOptions ( LoadOptions , LoadOptionCount ) ;
2015-05-06 06:48:56 +02:00
}
2015-11-17 11:15:09 +01:00
DEBUG ( ( EFI_D_ERROR , " [Bds] Unable to boot! \n " ) ) ;
CpuDeadLoop ( ) ;
2015-05-06 06:48:56 +02:00
}
/**
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
BdsDxeSetVariableAndReportStatusCodeOnError (
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 ;
}