mirror of https://github.com/acidanthera/audk.git
1247 lines
40 KiB
C
1247 lines
40 KiB
C
|
/** @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.
|
||
|
|
||
|
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
|
||
|
};
|
||
|
|
||
|
CHAR16 mRecoveryBoot[] = L"Recovery Boot";
|
||
|
/**
|
||
|
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.
|
||
|
//
|
||
|
DEBUG ((EFI_D_WARN, "[Bds] ASSERT Connect ConIn failed!!!\n"));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
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 *
|
||
|
BdsEnumerateBootOptions (
|
||
|
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;
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
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,
|
||
|
mRecoveryBoot,
|
||
|
DevicePathFromHandle (Handles[Index]),
|
||
|
NULL,
|
||
|
0
|
||
|
);
|
||
|
ASSERT_EFI_ERROR (Status);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
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,
|
||
|
mRecoveryBoot,
|
||
|
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++) {
|
||
|
|
||
|
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,
|
||
|
mRecoveryBoot,
|
||
|
DevicePathFromHandle (Handles[Index]),
|
||
|
NULL,
|
||
|
0
|
||
|
);
|
||
|
ASSERT_EFI_ERROR (Status);
|
||
|
}
|
||
|
|
||
|
if (HandleCount != 0) {
|
||
|
FreePool (Handles);
|
||
|
}
|
||
|
|
||
|
return BootOptions;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
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.
|
||
|
|
||
|
@retval TRUE Successfully boot one of the boot options.
|
||
|
@retval FALSE Failed boot any of the boot options.
|
||
|
**/
|
||
|
BOOLEAN
|
||
|
BootAllBootOptions (
|
||
|
IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions,
|
||
|
IN UINTN BootOptionCount
|
||
|
)
|
||
|
{
|
||
|
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]);
|
||
|
|
||
|
//
|
||
|
// Successful boot breaks the loop, otherwise tries next boot option
|
||
|
//
|
||
|
if (BootOptions[Index].Status == EFI_SUCCESS) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return (BOOLEAN) (Index < BootOptionCount);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
This function attempts to boot per the boot order specified by platform policy.
|
||
|
|
||
|
If the boot via Boot#### returns with a status of EFI_SUCCESS the boot manager will stop
|
||
|
processing the BootOrder variable and present a boot manager menu to the user. If a boot via
|
||
|
Boot#### returns a status other than EFI_SUCCESS, the boot has failed and the next Boot####
|
||
|
in the BootOrder variable will be tried until all possibilities are exhausted.
|
||
|
-- Chapter 3.1.1 Boot Manager Programming, the 4th paragraph
|
||
|
**/
|
||
|
VOID
|
||
|
DefaultBootBehavior (
|
||
|
VOID
|
||
|
)
|
||
|
{
|
||
|
UINTN BootOptionCount;
|
||
|
EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
|
||
|
EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu;
|
||
|
|
||
|
EfiBootManagerGetBootManagerMenu (&BootManagerMenu);
|
||
|
//
|
||
|
// BootManagerMenu always contains the correct information even the above function returns failure.
|
||
|
//
|
||
|
|
||
|
BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
|
||
|
|
||
|
if (BootAllBootOptions (BootOptions, BootOptionCount)) {
|
||
|
//
|
||
|
// Follow generic rule, Call BdsDxeOnConnectConInCallBack to connect ConIn before enter UI
|
||
|
//
|
||
|
if (PcdGetBool (PcdConInConnectOnDemand)) {
|
||
|
BdsDxeOnConnectConInCallBack (NULL, NULL);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Show the Boot Manager Menu after successful boot
|
||
|
//
|
||
|
EfiBootManagerBoot (&BootManagerMenu);
|
||
|
} else {
|
||
|
EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
|
||
|
//
|
||
|
// Re-scan all EFI boot options in case all the boot#### are deleted or failed to boot
|
||
|
//
|
||
|
// If no valid boot options exist, the boot manager will enumerate all removable media
|
||
|
// devices followed by all fixed media devices. The order within each group is undefined.
|
||
|
// These new default boot options are not saved to non volatile storage.The boot manger
|
||
|
// will then attempt toboot from each boot option.
|
||
|
// -- Chapter 3.3 Boot Manager Programming, the 2nd paragraph
|
||
|
//
|
||
|
EfiBootManagerConnectAll ();
|
||
|
BootOptions = BdsEnumerateBootOptions (&BootOptionCount);
|
||
|
|
||
|
if (!BootAllBootOptions (BootOptions, BootOptionCount)) {
|
||
|
DEBUG ((EFI_D_ERROR, "[Bds]No bootable device!\n"));
|
||
|
EfiBootManagerBoot (&BootManagerMenu);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
EfiBootManagerFreeLoadOption (&BootManagerMenu);
|
||
|
EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
The function will go through the driver option link list, load and start
|
||
|
every driver the driver option device path point to.
|
||
|
|
||
|
@param DriverOption Input driver option array.
|
||
|
@param DriverOptionCount Input driver option count.
|
||
|
|
||
|
**/
|
||
|
VOID
|
||
|
LoadDrivers (
|
||
|
IN EFI_BOOT_MANAGER_LOAD_OPTION *DriverOption,
|
||
|
IN UINTN DriverOptionCount
|
||
|
)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
UINTN Index;
|
||
|
EFI_HANDLE ImageHandle;
|
||
|
EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;
|
||
|
BOOLEAN ReconnectAll;
|
||
|
|
||
|
ReconnectAll = FALSE;
|
||
|
|
||
|
//
|
||
|
// Process the driver option
|
||
|
//
|
||
|
for (Index = 0; Index < DriverOptionCount; Index++) {
|
||
|
//
|
||
|
// If a load option is not marked as LOAD_OPTION_ACTIVE,
|
||
|
// the boot manager will not automatically load the option.
|
||
|
//
|
||
|
if ((DriverOption[Index].Attributes & LOAD_OPTION_ACTIVE) == 0) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// 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.
|
||
|
//
|
||
|
if ((DriverOption[Index].Attributes & LOAD_OPTION_FORCE_RECONNECT) != 0) {
|
||
|
ReconnectAll = TRUE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Make sure the driver path is connected.
|
||
|
//
|
||
|
EfiBootManagerConnectDevicePath (DriverOption[Index].FilePath, NULL);
|
||
|
|
||
|
//
|
||
|
// Load and start the image that Driver#### describes
|
||
|
//
|
||
|
Status = gBS->LoadImage (
|
||
|
FALSE,
|
||
|
gImageHandle,
|
||
|
DriverOption[Index].FilePath,
|
||
|
NULL,
|
||
|
0,
|
||
|
&ImageHandle
|
||
|
);
|
||
|
|
||
|
if (!EFI_ERROR (Status)) {
|
||
|
gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);
|
||
|
|
||
|
//
|
||
|
// Verify whether this image is a driver, if not,
|
||
|
// exit it and continue to parse next load option
|
||
|
//
|
||
|
if (ImageInfo->ImageCodeType != EfiBootServicesCode && ImageInfo->ImageCodeType != EfiRuntimeServicesCode) {
|
||
|
gBS->Exit (ImageHandle, EFI_INVALID_PARAMETER, 0, NULL);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
ImageInfo->LoadOptionsSize = DriverOption[Index].OptionalDataSize;
|
||
|
ImageInfo->LoadOptions = DriverOption[Index].OptionalData;
|
||
|
//
|
||
|
// Before calling the image, enable the Watchdog Timer for
|
||
|
// the 5 Minute period
|
||
|
//
|
||
|
gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);
|
||
|
|
||
|
DriverOption[Index].Status = gBS->StartImage (ImageHandle, &DriverOption[Index].ExitDataSize, &DriverOption[Index].ExitData);
|
||
|
DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Driver Return Status = %r\n", DriverOption[Index].Status));
|
||
|
|
||
|
//
|
||
|
// Clear the Watchdog Timer after the image returns
|
||
|
//
|
||
|
gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Process the LOAD_OPTION_FORCE_RECONNECT driver option
|
||
|
//
|
||
|
if (ReconnectAll) {
|
||
|
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
|
||
|
//
|
||
|
OsIndicationSupport = EFI_OS_INDICATIONS_BOOT_TO_FW_UI;
|
||
|
Status = gRT->SetVariable (
|
||
|
L"OsIndicationsSupported",
|
||
|
&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 (
|
||
|
L"OsIndications",
|
||
|
&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 (
|
||
|
L"OsIndications",
|
||
|
&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.
|
||
|
//
|
||
|
BdsFormalizeConsoleVariable (L"ConIn");
|
||
|
BdsFormalizeConsoleVariable (L"ConOut");
|
||
|
BdsFormalizeConsoleVariable (L"ErrOut");
|
||
|
|
||
|
//
|
||
|
// 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
|
||
|
)
|
||
|
{
|
||
|
EFI_BOOT_MANAGER_LOAD_OPTION *DriverOption;
|
||
|
EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
|
||
|
UINTN DriverOptionCount;
|
||
|
CHAR16 *FirmwareVendor;
|
||
|
EFI_EVENT HotkeyTriggered;
|
||
|
UINT64 OsIndication;
|
||
|
UINTN DataSize;
|
||
|
EFI_STATUS Status;
|
||
|
UINT32 BootOptionSupport;
|
||
|
UINT16 BootTimeOut;
|
||
|
EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;
|
||
|
UINTN Index;
|
||
|
UINT16 *BootNext;
|
||
|
CHAR16 BootNextVariableName[sizeof ("Boot####")];
|
||
|
|
||
|
HotkeyTriggered = NULL;
|
||
|
Status = EFI_SUCCESS;
|
||
|
|
||
|
//
|
||
|
// 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.
|
||
|
//
|
||
|
BootOptionSupport = EFI_BOOT_OPTION_SUPPORT_APP;
|
||
|
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);
|
||
|
|
||
|
//
|
||
|
// 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);
|
||
|
|
||
|
//
|
||
|
// Load Driver Options
|
||
|
//
|
||
|
DriverOption = EfiBootManagerGetLoadOptions (&DriverOptionCount, LoadOptionTypeDriver);
|
||
|
LoadDrivers (DriverOption, DriverOptionCount);
|
||
|
EfiBootManagerFreeLoadOptions (DriverOption, DriverOptionCount);
|
||
|
|
||
|
//
|
||
|
// 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);
|
||
|
|
||
|
DEBUG_CODE (
|
||
|
EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
|
||
|
UINTN BootOptionCount;
|
||
|
UINTN Index;
|
||
|
|
||
|
BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
|
||
|
DEBUG ((EFI_D_INFO, "[Bds]=============Dumping Boot Options=============\n"));
|
||
|
for (Index = 0; Index < BootOptionCount; Index++) {
|
||
|
DEBUG ((
|
||
|
EFI_D_INFO, "[Bds]Boot%04x: %s \t\t 0x%04x\n",
|
||
|
BootOptions[Index].OptionNumber,
|
||
|
BootOptions[Index].Description,
|
||
|
BootOptions[Index].Attributes
|
||
|
));
|
||
|
}
|
||
|
DEBUG ((EFI_D_INFO, "[Bds]=============Dumping Boot Options Finished====\n"));
|
||
|
EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
|
||
|
);
|
||
|
|
||
|
//
|
||
|
// Boot to Boot Manager Menu when EFI_OS_INDICATIONS_BOOT_TO_FW_UI is set. Skip HotkeyBoot
|
||
|
//
|
||
|
DataSize = sizeof (UINT64);
|
||
|
Status = gRT->GetVariable (
|
||
|
L"OsIndications",
|
||
|
&gEfiGlobalVariableGuid,
|
||
|
NULL,
|
||
|
&DataSize,
|
||
|
&OsIndication
|
||
|
);
|
||
|
if (!EFI_ERROR(Status) && ((OsIndication & EFI_OS_INDICATIONS_BOOT_TO_FW_UI) != 0)) {
|
||
|
//
|
||
|
// Clear EFI_OS_INDICATIONS_BOOT_TO_FW_UI to acknowledge OS
|
||
|
//
|
||
|
OsIndication &= ~((UINT64) EFI_OS_INDICATIONS_BOOT_TO_FW_UI);
|
||
|
Status = gRT->SetVariable (
|
||
|
L"OsIndications",
|
||
|
&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);
|
||
|
|
||
|
//
|
||
|
// Follow generic rule, Call BdsDxeOnConnectConInCallBack to connect ConIn before enter UI
|
||
|
//
|
||
|
if (PcdGetBool (PcdConInConnectOnDemand)) {
|
||
|
BdsDxeOnConnectConInCallBack (NULL, NULL);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Directly boot to Boot Manager Menu.
|
||
|
//
|
||
|
EfiBootManagerGetBootManagerMenu (&BootOption);
|
||
|
EfiBootManagerBoot (&BootOption);
|
||
|
EfiBootManagerFreeLoadOption (&BootOption);
|
||
|
} else {
|
||
|
PERF_START (NULL, "BdsWait", "BDS", 0);
|
||
|
BdsWait (HotkeyTriggered);
|
||
|
PERF_END (NULL, "BdsWait", "BDS", 0);
|
||
|
|
||
|
//
|
||
|
// BdsReadKeys() be removed after all keyboard drivers invoke callback in timer callback.
|
||
|
//
|
||
|
BdsReadKeys ();
|
||
|
|
||
|
EfiBootManagerHotkeyBoot ();
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Boot to "BootNext"
|
||
|
//
|
||
|
if (BootNext != NULL) {
|
||
|
UnicodeSPrint (BootNextVariableName, sizeof (BootNextVariableName), L"Boot%04x", *BootNext);
|
||
|
Status = EfiBootManagerVariableToLoadOption (BootNextVariableName, &BootOption);
|
||
|
if (!EFI_ERROR (Status)) {
|
||
|
EfiBootManagerBoot (&BootOption);
|
||
|
EfiBootManagerFreeLoadOption (&BootOption);
|
||
|
if (BootOption.Status == EFI_SUCCESS) {
|
||
|
//
|
||
|
// Boot to Boot Manager Menu upon EFI_SUCCESS
|
||
|
//
|
||
|
EfiBootManagerGetBootManagerMenu (&BootOption);
|
||
|
EfiBootManagerBoot (&BootOption);
|
||
|
EfiBootManagerFreeLoadOption (&BootOption);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
while (TRUE) {
|
||
|
//
|
||
|
// BDS select the boot device to load OS
|
||
|
// Try next upon boot failure
|
||
|
// Show Boot Manager Menu upon boot success
|
||
|
//
|
||
|
DefaultBootBehavior ();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
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;
|
||
|
}
|