2362 lines
72 KiB
C
2362 lines
72 KiB
C
/** @file
|
|
BdsDxe
|
|
|
|
;******************************************************************************
|
|
;* Copyright (c) 2012 - 2020, Insyde Software Corp. All Rights Reserved.
|
|
;*
|
|
;* You may not reproduce, distribute, publish, display, perform, modify, adapt,
|
|
;* transmit, broadcast, present, recite, release, license or otherwise exploit
|
|
;* any part of this publication in any form, by any means, without the prior
|
|
;* written permission of Insyde Software Corporation.
|
|
;*
|
|
;******************************************************************************
|
|
*/
|
|
|
|
/**
|
|
|
|
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 - 2012, 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 "String.h"
|
|
#include <Protocol/SetupUtilityApplication.h>
|
|
#include <Protocol/DevicePathToText.h>
|
|
|
|
typedef struct _LOAD_OPTION_ATTRIBUTE_STRING_INFO {
|
|
UINT32 Mask;
|
|
UINT32 Value;
|
|
CHAR16 *String;
|
|
} LOAD_OPTION_ATTRIBUTE_STRING_INFO;
|
|
LOAD_OPTION_ATTRIBUTE_STRING_INFO mLoadOptionAttrStrInfo[] = {
|
|
{LOAD_OPTION_CATEGORY , LOAD_OPTION_CATEGORY_BOOT , L"CATEGORY_BOOT"},
|
|
{LOAD_OPTION_CATEGORY , LOAD_OPTION_CATEGORY_APP , L"CATEGORY_APP"},
|
|
{LOAD_OPTION_ACTIVE , LOAD_OPTION_ACTIVE , L"ACTIVE"},
|
|
{LOAD_OPTION_FORCE_RECONNECT, LOAD_OPTION_FORCE_RECONNECT, L"FORCE_RECONNECT"},
|
|
{LOAD_OPTION_HIDDEN , LOAD_OPTION_HIDDEN , L"HIDDEN"}
|
|
};
|
|
|
|
#ifndef EFI_OS_INDICATIONS_START_OS_RECOVERY
|
|
#define EFI_OS_INDICATIONS_START_OS_RECOVERY 0x0000000000000020
|
|
#endif
|
|
#ifndef EFI_OS_INDICATIONS_START_PLATFORM_RECOVERY
|
|
#define EFI_OS_INDICATIONS_START_PLATFORM_RECOVERY 0x0000000000000040
|
|
#endif
|
|
|
|
#define NO_BOOT_DEVICE 0
|
|
#define NO_ACTIVE_BOOT_OPTION 1
|
|
|
|
|
|
//
|
|
// The data structure for performance data in ACPI memory.
|
|
//
|
|
#define PERFORMANCE_SIGNATURE SIGNATURE_32 ('P', 'e', 'r', 'f')
|
|
#define PERF_TOKEN_SIZE 28
|
|
#define PERF_TOKEN_LENGTH (PERF_TOKEN_SIZE - 1)
|
|
#define PERF_PEI_ENTRY_MAX_NUM 50
|
|
#define PERF_DATA_MAX_LENGTH 0x4000
|
|
|
|
typedef struct {
|
|
CHAR8 Token[PERF_TOKEN_SIZE];
|
|
UINT32 Duration;
|
|
} PERF_DATA;
|
|
|
|
typedef struct {
|
|
UINT64 BootToOs;
|
|
UINT64 S3Resume;
|
|
UINT32 S3EntryNum;
|
|
PERF_DATA S3Entry[PERF_PEI_ENTRY_MAX_NUM];
|
|
UINT64 CpuFreq;
|
|
UINT64 BDSRaw;
|
|
UINT32 Count;
|
|
UINT32 Signiture;
|
|
} PERF_HEADER;
|
|
|
|
///
|
|
/// BDS arch protocol instance initial value.
|
|
///
|
|
/// Note: Current BDS not directly get the BootMode, DefaultBoot,
|
|
/// TimeoutDefault, MemoryTestLevel value from the BDS arch protocol.
|
|
/// Please refer to the library useage of BdsLibGetBootMode, BdsLibGetTimeout
|
|
/// and PlatformBdsDiagnostics in BdsPlatform.c
|
|
///
|
|
|
|
EFI_HANDLE gBdsHandle = NULL;
|
|
UINT16 *mBootNext = NULL;
|
|
|
|
EFI_BDS_ARCH_PROTOCOL gBds = {
|
|
BdsEntry
|
|
};
|
|
|
|
H2O_BDS_CP_EXIT_BOOT_SERVICES_BEFORE_DATA mBdsExitBootServicesBeforeData;
|
|
EFI_EXIT_BOOT_SERVICES mOrginalExitBootServices;
|
|
STATIC BOOLEAN mExitBootServicesHasbeenCalled;
|
|
|
|
STATIC
|
|
UINTN
|
|
GetMapKey (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_MEMORY_DESCRIPTOR *EfiMemoryMap;
|
|
UINTN EfiMemoryMapSize;
|
|
UINTN EfiMapKey;
|
|
UINTN EfiDescriptorSize;
|
|
UINT32 EfiDescriptorVersion;
|
|
|
|
EfiMemoryMapSize = 0;
|
|
EfiMemoryMap = NULL;
|
|
gBS->GetMemoryMap (
|
|
&EfiMemoryMapSize,
|
|
EfiMemoryMap,
|
|
&EfiMapKey,
|
|
&EfiDescriptorSize,
|
|
&EfiDescriptorVersion
|
|
);
|
|
return EfiMapKey;
|
|
|
|
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
ExitBootServicesHookFunction (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN UINTN MapKey
|
|
)
|
|
{
|
|
UINTN CurrentMapKey;
|
|
|
|
if (mExitBootServicesHasbeenCalled) {
|
|
return mOrginalExitBootServices (ImageHandle, MapKey);
|
|
}
|
|
CurrentMapKey = GetMapKey ();
|
|
mExitBootServicesHasbeenCalled = TRUE;
|
|
mBdsExitBootServicesBeforeData.Size = sizeof (H2O_BDS_CP_EXIT_BOOT_SERVICES_BEFORE_DATA);
|
|
mBdsExitBootServicesBeforeData.Status = H2O_CP_TASK_NORMAL;
|
|
DEBUG_CP ((DEBUG_INFO, "Checkpoint Trigger: %g\n", &gH2OBdsCpExitBootServicesBeforeGuid));
|
|
H2OCpTrigger (&gH2OBdsCpExitBootServicesBeforeGuid, &mBdsExitBootServicesBeforeData);
|
|
DEBUG_CP ((DEBUG_INFO, "Checkpoint Result: %x\n", mBdsExitBootServicesBeforeData.Status));
|
|
return mOrginalExitBootServices (ImageHandle, CurrentMapKey == MapKey ? GetMapKey () : MapKey);
|
|
}
|
|
|
|
STATIC
|
|
UINT8
|
|
CalculateAddParity (
|
|
UINT8 Data
|
|
)
|
|
{
|
|
UINTN Index;
|
|
UINT8 TempData;
|
|
BOOLEAN ClearParityBit;
|
|
|
|
TempData = Data;
|
|
|
|
ClearParityBit = FALSE;
|
|
for (Index = 0; Index < 7; Index++) {
|
|
ClearParityBit = (BOOLEAN) ((TempData & 1) ^ ClearParityBit);
|
|
TempData >>= 1;
|
|
}
|
|
if (ClearParityBit) {
|
|
Data &= 0x7f;
|
|
} else {
|
|
Data |= 0x80;
|
|
}
|
|
|
|
return Data;
|
|
}
|
|
|
|
|
|
EFI_STATUS
|
|
SetSimpBootFlag (
|
|
VOID
|
|
)
|
|
{
|
|
UINT8 Data8;
|
|
UINT8 TempData8;
|
|
|
|
Data8 = ReadCmos8 (SimpleBootFlag);
|
|
//
|
|
// check BOOT bit. If BOOT bit enable, enable DIAG bit. otherwise, disable DIAG bit.
|
|
// then enable BOOT bit BOOT bit = Bit1 DIAG bit = bit2 SUPPERSSBOOTDISPLAY bit = bit3
|
|
//
|
|
TempData8 = Data8 & 0x02;
|
|
if (TempData8 == 0) {
|
|
Data8 &= 0xFB;
|
|
} else {
|
|
Data8 |= 0x04;
|
|
}
|
|
Data8 |= 0x02;
|
|
|
|
//
|
|
// disable SUPPERSSBOOTDISPLAY Flag
|
|
//
|
|
Data8 &= 0xF7;
|
|
Data8 = CalculateAddParity (Data8);
|
|
|
|
WriteCmos8 (SimpleBootFlag, Data8);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
VOID
|
|
EFIAPI
|
|
LoadDefaultCheck (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN VariableSize;
|
|
BOOLEAN LoadDefault;
|
|
|
|
LoadDefault = PcdGetBool (PcdLoadDefaultSetupMenu);
|
|
|
|
//
|
|
// OemServices
|
|
//
|
|
DEBUG_OEM_SVC ((DEBUG_INFO, "OemKernelServices Call: OemSvcLoadDefaultSetupMenu \n"));
|
|
Status = OemSvcLoadDefaultSetupMenu (&LoadDefault);
|
|
DEBUG_OEM_SVC ((DEBUG_INFO, "OemKernelServices OemSvcLoadDefaultSetupMenu Status: %r\n", Status));
|
|
|
|
if (!EFI_ERROR (Status) || (!LoadDefault)) {
|
|
return;
|
|
}
|
|
|
|
if (LoadDefault) {
|
|
DxeCsSvcLoadDefaultSetupMenu ();
|
|
//
|
|
// Is "Setup" variable existence?
|
|
//
|
|
VariableSize = 0;
|
|
Status = gRT->GetVariable (
|
|
SETUP_VARIABLE_NAME,
|
|
&gSystemConfigurationGuid,
|
|
NULL,
|
|
&VariableSize,
|
|
NULL
|
|
);
|
|
if (Status != EFI_BUFFER_TOO_SMALL) {
|
|
//
|
|
// No Setup variable found
|
|
// Setup menu is default setting.
|
|
//
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Delete "Setup" variable. It will load default in GetSystemConfigurationVar() of SetupUtility.c
|
|
//
|
|
VariableSize = 0;
|
|
Status = gRT->SetVariable (
|
|
SETUP_VARIABLE_NAME,
|
|
&gSystemConfigurationGuid,
|
|
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
|
|
VariableSize,
|
|
NULL
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return;
|
|
}
|
|
//
|
|
//Reset start system.
|
|
//
|
|
gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/**
|
|
Display TimeOut invalid message dialog.
|
|
|
|
@param[in] Timeout Current timeout variable value.
|
|
**/
|
|
STATIC
|
|
VOID
|
|
DisplayTimeOutInvalidDialog (
|
|
IN UINT16 Timeout
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
H2O_DIALOG_PROTOCOL *H2ODialog;
|
|
CHAR16 *ChangeStr;
|
|
CHAR16 *String;
|
|
UINTN StringSize;
|
|
EFI_INPUT_KEY Key;
|
|
|
|
Status = gBS->LocateProtocol (
|
|
&gH2ODialogProtocolGuid,
|
|
NULL,
|
|
(VOID **) &H2ODialog
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
if (EFI_ERROR (Status)) {
|
|
return;
|
|
}
|
|
|
|
ChangeStr = GetStringById (STRING_TOKEN (STR_TIMEOUT_CHANGE));
|
|
if (ChangeStr == NULL) {
|
|
return;
|
|
}
|
|
StringSize = 0x100 + StrSize (ChangeStr);
|
|
String = AllocateZeroPool (StringSize);
|
|
if (String == NULL) {
|
|
FreePool (ChangeStr);
|
|
return;
|
|
}
|
|
UnicodeSPrint (String, StringSize, ChangeStr, Timeout, PcdGet16 (PcdPlatformBootTimeOutMax), PcdGet16 (PcdPlatformBootTimeOut));
|
|
DisableQuietBoot ();
|
|
H2ODialog->ConfirmDialog (
|
|
DlgOk,
|
|
FALSE,
|
|
0,
|
|
NULL,
|
|
&Key,
|
|
String
|
|
);
|
|
FreePool (String);
|
|
FreePool (ChangeStr);
|
|
}
|
|
|
|
/**
|
|
Check timeout is whether larger than PcdPlatformBootTimeOutMax.
|
|
|
|
**/
|
|
STATIC
|
|
VOID
|
|
ProcessTimeoutChange (
|
|
VOID
|
|
)
|
|
{
|
|
UINT16 Timeout;
|
|
UINTN Size;
|
|
EFI_STATUS Status;
|
|
|
|
Size = sizeof (UINT16);
|
|
Status = gRT->GetVariable (
|
|
L"Timeout",
|
|
&gEfiGlobalVariableGuid,
|
|
NULL,
|
|
&Size,
|
|
&Timeout
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
if (EFI_ERROR (Status)) {
|
|
return;
|
|
}
|
|
if (Timeout <= PcdGet16 (PcdPlatformBootTimeOutMax)) {
|
|
return;
|
|
}
|
|
|
|
if (PcdGetBool(PcdPlatformBootTimeOutInvalidDialogSupported)) {
|
|
DisplayTimeOutInvalidDialog (Timeout);
|
|
}
|
|
|
|
Timeout = PcdGet16 (PcdPlatformBootTimeOut);
|
|
Status = gRT->SetVariable (
|
|
L"Timeout",
|
|
&gEfiGlobalVariableGuid,
|
|
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
|
|
sizeof (UINT16),
|
|
&Timeout
|
|
);
|
|
}
|
|
|
|
/**
|
|
Callback function to check Boot type is whether changed by other tools
|
|
|
|
@param Event Event whose notification function is being invoked.
|
|
@param Context Pointer to the notification function's context.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
ProcessChangeCallback (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
VOID *BdsDiagnostics;
|
|
|
|
Status = gBS->LocateProtocol (
|
|
&gEfiStartOfBdsDiagnosticsProtocolGuid,
|
|
NULL,
|
|
&BdsDiagnostics
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return;
|
|
}
|
|
|
|
gBS->CloseEvent (Event);
|
|
ProcessTimeoutChange ();
|
|
}
|
|
|
|
/**
|
|
Callback function to restore physical boot order and enumerate all boot options before enter SCU.
|
|
|
|
@param Event Event whose notification function is being invoked.
|
|
@param Context Pointer to the notification function's context.
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
SetupUtilityAppNotifyFn (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_SETUP_UTILITY_APPLICATION_PROTOCOL *SetupUtilityApp;
|
|
|
|
Status = gBS->LocateProtocol (
|
|
&gEfiSetupUtilityApplicationProtocolGuid,
|
|
NULL,
|
|
(VOID **) &SetupUtilityApp
|
|
);
|
|
if (!EFI_ERROR(Status) && SetupUtilityApp->VfrDriverState == InitializeSetupUtility) {
|
|
if (FeaturePcdGet (PcdAutoCreateDummyBootOption)) {
|
|
SyncBootOrder ();
|
|
BdsLibRestoreBootOrderFromPhysicalBootOrder ();
|
|
}
|
|
BdsLibEnumerateAllBootOption (FALSE, NULL);
|
|
}
|
|
}
|
|
|
|
/**
|
|
|
|
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;
|
|
VOID *Registration;
|
|
|
|
LoadDefaultCheck ();
|
|
BdsLibDeleteInvalidBootOptions ();
|
|
EfiCreateProtocolNotifyEvent (
|
|
&gEfiStartOfBdsDiagnosticsProtocolGuid,
|
|
TPL_CALLBACK,
|
|
ProcessChangeCallback,
|
|
NULL,
|
|
&Registration
|
|
);
|
|
EfiCreateProtocolNotifyEvent (
|
|
&gEfiSetupUtilityApplicationProtocolGuid,
|
|
TPL_CALLBACK,
|
|
SetupUtilityAppNotifyFn,
|
|
NULL,
|
|
&Registration
|
|
);
|
|
//
|
|
// Install protocol interface
|
|
//
|
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
|
&gBdsHandle,
|
|
&gEfiBdsArchProtocolGuid,
|
|
&gBds,
|
|
NULL
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
mBdsOrgGetMemoryMap = gBS->GetMemoryMap;
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
|
|
Popup a message for user to indicate no mapping boot option to boot.
|
|
|
|
@param OptionNum Input boot option number.
|
|
|
|
**/
|
|
VOID
|
|
CreateNoMappingBootOptionPopUp (
|
|
IN UINT16 OptionNum
|
|
)
|
|
{
|
|
H2O_DIALOG_PROTOCOL *H2ODialog;
|
|
EFI_INPUT_KEY Key;
|
|
EFI_STATUS Status;
|
|
CHAR16 *String;
|
|
|
|
if (!BdsLibIsDummyBootOption (OptionNum)) {
|
|
return;
|
|
}
|
|
|
|
Status = gBS->LocateProtocol (
|
|
&gH2ODialogProtocolGuid,
|
|
NULL,
|
|
(VOID **) &H2ODialog
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
DisableQuietBoot ();
|
|
String = NULL;
|
|
if (OptionNum == DummyUsbBootOptionNum) {
|
|
String = GetStringById (STRING_TOKEN (STR_USB_OPTION_INEXISTENCE));
|
|
} else if (OptionNum == DummyCDBootOptionNum){
|
|
String = GetStringById (STRING_TOKEN (STR_CD_OPTION_INEXISTENCE));
|
|
} else if (OptionNum == DummyNetwokrBootOptionNum){
|
|
String = GetStringById (STRING_TOKEN (STR_NETWORK_OPTION_INEXISTENCE));
|
|
}
|
|
ASSERT (String != NULL);
|
|
if (String == NULL) {
|
|
return;
|
|
}
|
|
H2ODialog->ConfirmDialog (
|
|
DlgOk,
|
|
FALSE,
|
|
0,
|
|
NULL,
|
|
&Key,
|
|
String
|
|
);
|
|
FreePool (String);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/**
|
|
|
|
Popup a option list for user to select which mapping boot option want to boot.
|
|
|
|
@param OptionNum Input boot option number.
|
|
@param OptionCount The total number of boot option in option order.
|
|
@param OptionOrder Pointer to option order.
|
|
@param SelectedOpitonNum The option number which user selected.
|
|
|
|
@retval EFI_SUCEESS User selects a specific USB boot option successful.
|
|
@retval EFI_INVALID_PARAMETER OptionCount is 0, OptionOrder is NULL, SelectedOpitonNum is NULL or OptinNum isn't
|
|
a dummy boot option.
|
|
@retval EFI_NOT_FOUND Cannot find corresponding title string for specific boot option type.
|
|
@retval EFI_ABORTED User presses ESC key to skip boot option selection menu.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
SelectMappingBootOption (
|
|
IN UINT16 OptionNum,
|
|
IN UINTN OptionCount,
|
|
IN UINT16 *OptionOrder,
|
|
OUT UINT16 *SelectedOpitonNum
|
|
)
|
|
{
|
|
H2O_DIALOG_PROTOCOL *H2ODialog;
|
|
EFI_STATUS Status;
|
|
CHAR16 **DescriptionOrder;
|
|
UINT32 Index;
|
|
CHAR16 *TitleString;
|
|
BOOLEAN BootOptionSelected;
|
|
EFI_INPUT_KEY Key;
|
|
UINTN MaxStrLen;
|
|
|
|
if (OptionCount == 0 || OptionOrder == NULL || SelectedOpitonNum == NULL || !BdsLibIsDummyBootOption (OptionNum)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Status = gBS->LocateProtocol (
|
|
&gH2ODialogProtocolGuid,
|
|
NULL,
|
|
(VOID **) &H2ODialog
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
TitleString = NULL;
|
|
if (OptionNum == DummyUsbBootOptionNum) {
|
|
TitleString = GetStringById (STRING_TOKEN (STR_SELECT_USB_OPTION));
|
|
} else if (OptionNum == DummyCDBootOptionNum) {
|
|
TitleString = GetStringById (STRING_TOKEN (STR_SELECT_CD_OPTION));
|
|
} else if (OptionNum == DummyNetwokrBootOptionNum) {
|
|
TitleString = GetStringById (STRING_TOKEN (STR_SELECT_NETWORK_OPTION));
|
|
}
|
|
if (TitleString == NULL) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
DescriptionOrder = AllocateZeroPool (OptionCount * sizeof (CHAR16 *));
|
|
if (DescriptionOrder == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
MaxStrLen = 0;
|
|
for (Index = 0; Index < OptionCount; Index++) {
|
|
DescriptionOrder[Index] = BdsLibGetDescriptionFromBootOption (OptionOrder[Index]);
|
|
MaxStrLen = StrLen (DescriptionOrder[Index]) > MaxStrLen ? StrLen (DescriptionOrder[Index]) : MaxStrLen;
|
|
}
|
|
|
|
DisableQuietBoot ();
|
|
BootOptionSelected = FALSE;
|
|
|
|
H2ODialog->OneOfOptionDialog (
|
|
(UINT32) OptionCount,
|
|
FALSE,
|
|
NULL,
|
|
&Key,
|
|
(UINT32) MaxStrLen,
|
|
TitleString,
|
|
&Index,
|
|
DescriptionOrder,
|
|
0
|
|
);
|
|
if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
|
|
BootOptionSelected = TRUE;
|
|
*SelectedOpitonNum = OptionOrder[Index];
|
|
}
|
|
|
|
FreePool (TitleString);
|
|
for (Index = 0; Index < OptionCount; Index++) {
|
|
FreePool (DescriptionOrder[Index]);
|
|
}
|
|
|
|
Status = BootOptionSelected ? EFI_SUCCESS : EFI_ABORTED;
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Check if the BDS hot key is support or not.
|
|
|
|
@retval TRUE The BDS hot key is support.
|
|
@retval FALSE The BDS hot key is not support.
|
|
**/
|
|
BOOLEAN
|
|
IsBdsHotKeySupport (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN Size;
|
|
IMAGE_INFO ImageInfo;
|
|
|
|
if (FeaturePcdGet(PcdSecureFlashSupported)) {
|
|
Size = sizeof (IMAGE_INFO);
|
|
Status = gRT->GetVariable (
|
|
L"SecureFlashInfo",
|
|
&gSecureFlashInfoGuid,
|
|
NULL,
|
|
&Size,
|
|
&ImageInfo
|
|
);
|
|
if ((Status == EFI_SUCCESS) && (ImageInfo.FlashMode)) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
According to boot option number to check this boot option is whether a Legacy boot option.
|
|
|
|
@param[in] OptionNum The boot option number.
|
|
|
|
@retval TRUE This is a Legacy boot option.
|
|
@retval FALSE This isn't a Legacy boot option.
|
|
**/
|
|
BOOLEAN
|
|
IsLegacyBootOption (
|
|
IN UINT16 OptionNum
|
|
)
|
|
{
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
|
BOOLEAN IsLegacyBoot;
|
|
UINT32 DevicePathType;
|
|
|
|
if (OptionNum == 0xFF) {
|
|
return FALSE;
|
|
}
|
|
|
|
DevicePath = BdsLibGetDevicePathFromBootOption (OptionNum);
|
|
if (DevicePath == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
IsLegacyBoot = FALSE;
|
|
DevicePathType = BdsLibGetBootTypeFromDevicePath (DevicePath);
|
|
if (DevicePathType == BDS_LEGACY_BBS_BOOT) {
|
|
IsLegacyBoot = TRUE;
|
|
}
|
|
|
|
FreePool (DevicePath);
|
|
|
|
return IsLegacyBoot;
|
|
}
|
|
|
|
/**
|
|
Internal function to initialize H2O_BDS_CP_NO_BOOT_DEVICE_DATA data and trigger
|
|
gH2OBdsCpNoBootDeviceGuid checkpoint.
|
|
|
|
@return The Status in H2O_BDS_CP_NO_BOOT_DEVICE_DATA data.
|
|
**/
|
|
STATIC
|
|
UINT32
|
|
TriggerCpNoBootDevice (
|
|
VOID
|
|
)
|
|
{
|
|
H2O_BDS_CP_NO_BOOT_DEVICE_DATA BdsNoBootDeviceData;
|
|
EFI_STATUS Status;
|
|
|
|
|
|
BdsNoBootDeviceData.Size = sizeof (H2O_BDS_CP_NO_BOOT_DEVICE_DATA);
|
|
BdsNoBootDeviceData.Status = H2O_BDS_TASK_NORMAL;
|
|
DEBUG_CP ((DEBUG_INFO, "Checkpoint Trigger: %g\n", &gH2OBdsCpNoBootDeviceGuid));
|
|
Status = H2OCpTrigger (&gH2OBdsCpNoBootDeviceGuid, &BdsNoBootDeviceData);
|
|
DEBUG_CP ((DEBUG_INFO, "Checkpoint Result: %x\n", BdsNoBootDeviceData.Status));
|
|
return BdsNoBootDeviceData.Status;
|
|
}
|
|
|
|
/**
|
|
Launch boot failed application which is defined by PcdH2OBdsBootFailApp.
|
|
|
|
@retval EFI_SUCCESS Launch boot failed application success.
|
|
@retval EFI_NOT_FOUND String pointer is NULL.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
LaunchBootFailApp (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
|
|
|
DevicePath = GetDevicePathByAsciiStr ((CHAR8 *) PcdGetPtr (PcdH2OBdsBootFailApp));
|
|
if (DevicePath == NULL) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
LaunchBootOptionByDevicePath (DevicePath);
|
|
FreePool (DevicePath);
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Show boot fail message. If auto failover is disable, it will go into firmware UI.
|
|
|
|
@param AutoFailover Auto failover polciy
|
|
@param Message Boot fail message
|
|
|
|
@retval EFI_SUCCESS Perform auto failover policy success.
|
|
@retval EFI_INVALID_PARAMETER String pointer is NULL.
|
|
@retval Other Locate protocol fail or pop message fail.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
AutoFailoverPolicyBehavior (
|
|
IN BOOLEAN AutoFailover,
|
|
IN CHAR16 *Message
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_INPUT_KEY Key;
|
|
H2O_DIALOG_PROTOCOL *H2ODialog;
|
|
|
|
if (Message == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Status = gBS->LocateProtocol (
|
|
&gH2ODialogProtocolGuid,
|
|
NULL,
|
|
(VOID **)&H2ODialog
|
|
);
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
DisableQuietBoot ();
|
|
|
|
Status = H2ODialog->ConfirmDialog (2, FALSE, 0, NULL, &Key, Message);
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
gST->ConOut->ClearScreen (gST->ConOut);
|
|
|
|
//
|
|
// If auto failover is disable, go into firmware UI.
|
|
//
|
|
if (!AutoFailover) {
|
|
BdsLibConnectAll ();
|
|
BdsLibEnumerateAllBootOption (TRUE, NULL);
|
|
LaunchBootFailApp ();
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Perform no boot device operation (show message and wait for user to restart system)
|
|
|
|
@param[in] NoBootDeviceType What kind of no boot device
|
|
**/
|
|
VOID
|
|
BdsNoBootDevice (
|
|
IN UINT8 NoBootDeviceType
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_INPUT_KEY Key;
|
|
CHAR16 *BootErrorString;
|
|
volatile UINTN Index;
|
|
//
|
|
// PostCode = 0xF9, No Boot Device
|
|
//
|
|
POST_CODE (POST_BDS_NO_BOOT_DEVICE);
|
|
if (FeaturePcdGet (PcdH2OBdsCpNoBootDeviceSupported)) {
|
|
if (TriggerCpNoBootDevice () == H2O_BDS_TASK_SKIP) {
|
|
return;
|
|
}
|
|
}
|
|
if (NoBootDeviceType == NO_BOOT_DEVICE) {
|
|
BootErrorString = GetStringById (STRING_TOKEN (STR_AUTO_FAILOVER_NO_BOOT_DEVICE));
|
|
} else {
|
|
BootErrorString = GetStringById (STRING_TOKEN (STR_AUTO_FAILOVER_NO_ACTIVE_BOOT_OPTION));
|
|
}
|
|
if (BootErrorString != NULL) {
|
|
AutoFailoverPolicyBehavior (FALSE, BootErrorString);
|
|
FreePool(BootErrorString);
|
|
}
|
|
|
|
DisableQuietBoot ();
|
|
|
|
BootErrorString = GetStringById (STRING_TOKEN (STR_BOOT_DEVICE_ERROR_MESSAGE));
|
|
if (BootErrorString == NULL || StrLen (BootErrorString) == 0) {
|
|
BootErrorString = L"No bootable device -- Please restart system\n";
|
|
}
|
|
|
|
gST->ConOut->EnableCursor (gST->ConOut, TRUE);
|
|
gST->ConOut->ClearScreen(gST->ConOut);
|
|
gST->ConOut->SetAttribute (gST->ConOut, EFI_WHITE);
|
|
Print (BootErrorString);
|
|
|
|
for (Index = 0; Index == 0;) {
|
|
Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
|
|
if (!EFI_ERROR (Status)) {
|
|
Print (BootErrorString);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
Creates a new copy of an option list.
|
|
|
|
@param[in] SrcOptionList Pointer to source option list.
|
|
|
|
@return A pointer to the duplicated option list or NULL if SrcOptionList is NULL or allocate memory failed.
|
|
**/
|
|
STATIC
|
|
LIST_ENTRY *
|
|
DuplicateOptionList (
|
|
IN CONST LIST_ENTRY *SrcOptionList
|
|
)
|
|
{
|
|
LIST_ENTRY *NewOptionList;
|
|
LIST_ENTRY *Link;
|
|
H2O_BDS_LOAD_OPTION *LoadOption;
|
|
H2O_BDS_LOAD_OPTION *NewLoadOption;
|
|
EFI_STATUS Status;
|
|
|
|
if (SrcOptionList == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
NewOptionList = AllocatePool (sizeof (LIST_ENTRY));
|
|
if (NewOptionList == NULL) {
|
|
return NULL;
|
|
}
|
|
InitializeListHead (NewOptionList);
|
|
|
|
Link = GetFirstNode (SrcOptionList);
|
|
while (!IsNull (SrcOptionList, Link)) {
|
|
LoadOption = BDS_OPTION_FROM_LINK (Link);
|
|
Link = GetNextNode (SrcOptionList, Link);
|
|
|
|
Status = gBdsServices->CreateLoadOption2 (
|
|
gBdsServices,
|
|
LoadOption->OptionType,
|
|
BDS_OPTION_HAVE_LOAD_ORDER_VAR_NAME(LoadOption) ? LoadOption->LoadOrderVarName : NULL,
|
|
BDS_OPTION_HAVE_LOAD_ORDER_VAR_NAME(LoadOption) ? &LoadOption->LoadOrderVarGuid : NULL,
|
|
LoadOption->Attributes,
|
|
LoadOption->DevicePath,
|
|
LoadOption->Description,
|
|
LoadOption->LoadOptionalData,
|
|
LoadOption->LoadOptionalDataSize,
|
|
&NewLoadOption
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
InsertTailList (NewOptionList, &NewLoadOption->Link);
|
|
}
|
|
}
|
|
|
|
return NewOptionList;
|
|
}
|
|
|
|
/**
|
|
Free each BDS option from option list.
|
|
|
|
@param[in, out] OptionsList A pointer to the BDS option list.
|
|
**/
|
|
STATIC
|
|
VOID
|
|
FreeBdsOptionList (
|
|
IN OUT LIST_ENTRY *OptionsList
|
|
)
|
|
{
|
|
LIST_ENTRY *Link;
|
|
H2O_BDS_LOAD_OPTION *Option;
|
|
|
|
if (OptionsList == NULL) {
|
|
return;
|
|
}
|
|
|
|
Link = GetFirstNode (OptionsList);
|
|
while (!IsNull (OptionsList, Link)) {
|
|
Option = BDS_OPTION_FROM_LINK (Link);
|
|
Link = GetNextNode (OptionsList, Link);
|
|
|
|
RemoveEntryList (&Option->Link);
|
|
gBdsServices->FreeLoadOption (gBdsServices, Option);
|
|
}
|
|
}
|
|
|
|
/**
|
|
Internal function to initialize boot device select checkpoint data and trigger checkpoint.
|
|
|
|
@retval EFI_SUCCESS Trigger boot device select checkpoint successfully.
|
|
@retval EFI_OUT_OF_RESOURCES Allocate memory to initialize checkpoint data failed.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
TriggerCpBootDeviceSelect (
|
|
IN LIST_ENTRY **BootLists
|
|
)
|
|
{
|
|
H2O_BDS_CP_BOOT_DEVICE_SELECT_DATA BdsBootDeviceSelectData;
|
|
EFI_STATUS Status;
|
|
|
|
BdsBootDeviceSelectData.Size = sizeof (H2O_BDS_CP_BOOT_DEVICE_SELECT_DATA);
|
|
BdsBootDeviceSelectData.Status = H2O_BDS_TASK_NORMAL;
|
|
BdsBootDeviceSelectData.BootList = BootLists;
|
|
|
|
DEBUG_CP ((DEBUG_INFO, "Checkpoint Trigger: %g\n", &gH2OBdsCpBootDeviceSelectGuid));
|
|
Status = H2OCpTrigger (&gH2OBdsCpBootDeviceSelectGuid, &BdsBootDeviceSelectData);
|
|
DEBUG_CP ((DEBUG_INFO, "Checkpoint Result: %x\n", BdsBootDeviceSelectData.Status));
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Update new option list to BDS services protocol.
|
|
|
|
@param[in] OptionType BDS load option type
|
|
@param[in] NewOptionList Pointer to new option list
|
|
|
|
@retval EFI_SUCCESS Update new option list successfully.
|
|
@retval EFI_INVALID_PARAMETER NewOptionList is NULL.
|
|
@retval EFI_UNSUPPORTED Option type is not supported.
|
|
@return Other Get original option list failed.
|
|
**/
|
|
EFI_STATUS
|
|
UpdateOptionList (
|
|
IN H2O_BDS_LOAD_OPTION_TYPE OptionType,
|
|
IN CONST LIST_ENTRY *NewOptionList
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
LIST_ENTRY *OldOptionList;
|
|
LIST_ENTRY *Link;
|
|
H2O_BDS_LOAD_OPTION *LoadOption;
|
|
H2O_BDS_LOAD_OPTION *NewLoadOption;
|
|
H2O_BDS_LOAD_OPTION *PreviousLoadOption;
|
|
CHAR16 *VariableName;
|
|
EFI_GUID VariableGuid;
|
|
|
|
if (NewOptionList == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
switch (OptionType) {
|
|
|
|
case H2O_BDS_LOAD_OPTION_TYPE_SYSPREP:
|
|
Status = gBdsServices->GetSysPrepList (gBdsServices, &OldOptionList);
|
|
break;
|
|
|
|
case H2O_BDS_LOAD_OPTION_TYPE_OS_RECOVERY:
|
|
Status = gBdsServices->GetOsRecoveryList (gBdsServices, &OldOptionList);
|
|
break;
|
|
|
|
case H2O_BDS_LOAD_OPTION_TYPE_PLATFORM_RECOVERY:
|
|
Status = gBdsServices->GetPlatformRecoveryList (gBdsServices, &OldOptionList);
|
|
break;
|
|
|
|
default:
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Remove all load options from current option list.
|
|
//
|
|
Link = GetFirstNode (OldOptionList);
|
|
while (!IsNull (OldOptionList, Link)) {
|
|
LoadOption = BDS_OPTION_FROM_LINK (Link);
|
|
Link = GetNextNode (OldOptionList, Link);
|
|
|
|
CopyGuid (&VariableGuid, &LoadOption->LoadOrderVarGuid);
|
|
gBdsServices->RemoveLoadOption2 (
|
|
gBdsServices,
|
|
LoadOption->OptionType,
|
|
LoadOption->LoadOrder,
|
|
LoadOption->OptionType == H2O_BDS_LOAD_OPTION_TYPE_OS_RECOVERY ? &VariableGuid : NULL
|
|
);
|
|
}
|
|
|
|
//
|
|
// Insert all load options from new list in sequence.
|
|
//
|
|
PreviousLoadOption = NULL;
|
|
Link = GetFirstNode (NewOptionList);
|
|
while (!IsNull (NewOptionList, Link)) {
|
|
LoadOption = BDS_OPTION_FROM_LINK (Link);
|
|
Link = GetNextNode (NewOptionList, Link);
|
|
|
|
Status = gBdsServices->CreateLoadOption2 (
|
|
gBdsServices,
|
|
LoadOption->OptionType,
|
|
BDS_OPTION_HAVE_LOAD_ORDER_VAR_NAME(LoadOption) ? LoadOption->LoadOrderVarName : NULL,
|
|
BDS_OPTION_HAVE_LOAD_ORDER_VAR_NAME(LoadOption) ? &LoadOption->LoadOrderVarGuid : NULL,
|
|
LoadOption->Attributes,
|
|
LoadOption->DevicePath,
|
|
LoadOption->Description,
|
|
LoadOption->LoadOptionalData,
|
|
LoadOption->LoadOptionalDataSize,
|
|
&NewLoadOption
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
continue;
|
|
}
|
|
|
|
Status = gBdsServices->ConvertLoadOptionToVar (
|
|
gBdsServices,
|
|
NewLoadOption,
|
|
&VariableName,
|
|
&VariableGuid
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
gBdsServices->FreeLoadOption (gBdsServices, NewLoadOption);
|
|
continue;
|
|
}
|
|
|
|
FreePool (VariableName);
|
|
gBdsServices->InsertLoadOption2 (
|
|
gBdsServices,
|
|
NewLoadOption,
|
|
PreviousLoadOption
|
|
);
|
|
PreviousLoadOption = NewLoadOption;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Perform the processing of the OS Recovery load option list.
|
|
|
|
@retval EFI_SUCCESS Perform OS recovery successfully.
|
|
@retval EFI_ABORTED Skip processing OS Recovery by checkpoint requirement.
|
|
@return Other Get OS Recovery load option list failed or there is no option which is launched successfully.
|
|
**/
|
|
EFI_STATUS
|
|
PerformOsRecovery (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
LIST_ENTRY *OsRecoveryList;
|
|
LIST_ENTRY *Link;
|
|
H2O_BDS_LOAD_OPTION *LoadOption;
|
|
UINTN ExitDataSize;
|
|
CHAR16 *ExitData;
|
|
EFI_STATUS LaunchStatus;
|
|
H2O_BDS_CP_OS_RECOVERY_DATA BdsOsRecoveryData;
|
|
|
|
if (FeaturePcdGet (PcdH2OBdsCpOsRecoverySupported)) {
|
|
Status = gBdsServices->GetOsRecoveryList (gBdsServices, &OsRecoveryList);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
BdsOsRecoveryData.Size = sizeof (H2O_BDS_CP_OS_RECOVERY_DATA);
|
|
BdsOsRecoveryData.Status = H2O_BDS_TASK_NORMAL;
|
|
BdsOsRecoveryData.OsRecoveryList = DuplicateOptionList (OsRecoveryList);
|
|
DEBUG_CP ((DEBUG_INFO, "Checkpoint Trigger: %g\n", &gH2OBdsCpOsRecoveryGuid));
|
|
H2OCpTrigger (&gH2OBdsCpOsRecoveryGuid, &BdsOsRecoveryData);
|
|
DEBUG_CP ((DEBUG_INFO, "Checkpoint Result: %x\n", BdsOsRecoveryData.Status));
|
|
|
|
switch (BdsOsRecoveryData.Status) {
|
|
|
|
case H2O_BDS_TASK_SKIP:
|
|
FreeBdsOptionList (BdsOsRecoveryData.OsRecoveryList);
|
|
return EFI_ABORTED;
|
|
|
|
case H2O_BDS_TASK_UPDATE:
|
|
UpdateOptionList (H2O_BDS_LOAD_OPTION_TYPE_OS_RECOVERY, BdsOsRecoveryData.OsRecoveryList);
|
|
break;
|
|
}
|
|
FreeBdsOptionList (BdsOsRecoveryData.OsRecoveryList);
|
|
}
|
|
|
|
POST_CODE (BDS_OS_RECOVERY);
|
|
|
|
Status = gBdsServices->GetOsRecoveryList (gBdsServices, &OsRecoveryList);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Status = EFI_NOT_FOUND;
|
|
for (Link = GetFirstNode (OsRecoveryList); !IsNull (OsRecoveryList, Link); Link = GetNextNode (OsRecoveryList, Link)) {
|
|
LoadOption = BDS_OPTION_FROM_LINK (Link);
|
|
if ((LoadOption->Attributes & LOAD_OPTION_ACTIVE) == 0) {
|
|
continue;
|
|
}
|
|
|
|
LaunchStatus = gBdsServices->LaunchLoadOption (gBdsServices, LoadOption, &ExitDataSize, &ExitData);
|
|
if (!EFI_ERROR (LaunchStatus)) {
|
|
Status = EFI_SUCCESS;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Perform the processing of the Platform Recovery load option list.
|
|
|
|
@retval EFI_SUCCESS Perform Platform recovery successfully.
|
|
@retval EFI_ABORTED Skip processing Platform Recovery by checkpoint requirement.
|
|
@return EFI_NOT_FOUND There is no option which is launched successfully.
|
|
@return Other Get Platform Recovery load option list failed.
|
|
**/
|
|
EFI_STATUS
|
|
PerformPlatformRecovery (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
LIST_ENTRY *PlatformRecoveryList;
|
|
LIST_ENTRY *Link;
|
|
H2O_BDS_LOAD_OPTION *LoadOption;
|
|
UINTN ExitDataSize;
|
|
CHAR16 *ExitData;
|
|
H2O_BDS_CP_PLATFORM_RECOVERY_DATA BdsPlatformRecoveryData;
|
|
|
|
if (FeaturePcdGet (PcdH2OBdsCpPlatformRecoverySupported)) {
|
|
Status = gBdsServices->GetPlatformRecoveryList (gBdsServices, &PlatformRecoveryList);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
BdsPlatformRecoveryData.Size = sizeof (H2O_BDS_CP_PLATFORM_RECOVERY_DATA);
|
|
BdsPlatformRecoveryData.Status = H2O_BDS_TASK_NORMAL;
|
|
BdsPlatformRecoveryData.PlatformRecoveryList = DuplicateOptionList (PlatformRecoveryList);
|
|
DEBUG_CP ((DEBUG_INFO, "Checkpoint Trigger: %g\n", &gH2OBdsCpPlatformRecoveryGuid));
|
|
H2OCpTrigger (&gH2OBdsCpPlatformRecoveryGuid, &BdsPlatformRecoveryData);
|
|
DEBUG_CP ((DEBUG_INFO, "Checkpoint Result: %x\n", BdsPlatformRecoveryData.Status));
|
|
|
|
switch (BdsPlatformRecoveryData.Status) {
|
|
|
|
case H2O_BDS_TASK_SKIP:
|
|
FreeBdsOptionList (BdsPlatformRecoveryData.PlatformRecoveryList);
|
|
return EFI_ABORTED;
|
|
|
|
case H2O_BDS_TASK_UPDATE:
|
|
UpdateOptionList (H2O_BDS_LOAD_OPTION_TYPE_PLATFORM_RECOVERY, BdsPlatformRecoveryData.PlatformRecoveryList);
|
|
break;
|
|
}
|
|
FreeBdsOptionList (BdsPlatformRecoveryData.PlatformRecoveryList);
|
|
}
|
|
|
|
POST_CODE (BDS_PLATFORM_RECOVERY);
|
|
|
|
Status = gBdsServices->GetPlatformRecoveryList (gBdsServices, &PlatformRecoveryList);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
for (Link = GetFirstNode (PlatformRecoveryList); !IsNull (PlatformRecoveryList, Link); Link = GetNextNode (PlatformRecoveryList, Link)) {
|
|
LoadOption = BDS_OPTION_FROM_LINK (Link);
|
|
if ((LoadOption->Attributes & LOAD_OPTION_ACTIVE) == 0) {
|
|
continue;
|
|
}
|
|
|
|
Status = gBdsServices->LaunchLoadOption (gBdsServices, LoadOption, &ExitDataSize, &ExitData);
|
|
if (!EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
/**
|
|
Perform the processing of the System Preparation load option list.
|
|
|
|
@retval EFI_SUCCESS Perform System Preparation successfully.
|
|
@retval EFI_ABORTED Skip processing System Preparation by checkpoint requirement.
|
|
@return Other Get System Preparation load option list failed or there is no option which is launched successfully.
|
|
**/
|
|
EFI_STATUS
|
|
PerformSysPrep (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
LIST_ENTRY *SysPrepList;
|
|
LIST_ENTRY *Link;
|
|
H2O_BDS_LOAD_OPTION *LoadOption;
|
|
UINTN ExitDataSize;
|
|
CHAR16 *ExitData;
|
|
EFI_STATUS LaunchStatus;
|
|
H2O_BDS_CP_SYSPREP_DATA BdsSysPrepData;
|
|
|
|
if (FeaturePcdGet (PcdH2OBdsCpSysPrepSupported)) {
|
|
Status = gBdsServices->GetSysPrepList (gBdsServices, &SysPrepList);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
BdsSysPrepData.Size = sizeof (H2O_BDS_CP_SYSPREP_DATA);
|
|
BdsSysPrepData.Status = H2O_BDS_TASK_NORMAL;
|
|
BdsSysPrepData.SysPrepList = DuplicateOptionList (SysPrepList);
|
|
DEBUG_CP ((DEBUG_INFO, "Checkpoint Trigger: %g\n", &gH2OBdsCpSysPrepGuid));
|
|
H2OCpTrigger (&gH2OBdsCpSysPrepGuid, &BdsSysPrepData);
|
|
DEBUG_CP ((DEBUG_INFO, "Checkpoint Result: %x\n", BdsSysPrepData.Status));
|
|
|
|
switch (BdsSysPrepData.Status) {
|
|
|
|
case H2O_BDS_TASK_SKIP:
|
|
FreeBdsOptionList (BdsSysPrepData.SysPrepList);
|
|
return EFI_ABORTED;
|
|
|
|
case H2O_BDS_TASK_UPDATE:
|
|
UpdateOptionList (H2O_BDS_LOAD_OPTION_TYPE_SYSPREP, BdsSysPrepData.SysPrepList);
|
|
break;
|
|
}
|
|
FreeBdsOptionList (BdsSysPrepData.SysPrepList);
|
|
}
|
|
|
|
POST_CODE (BDS_SYSPREP);
|
|
|
|
Status = gBdsServices->GetSysPrepList (gBdsServices, &SysPrepList);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Status = EFI_NOT_FOUND;
|
|
for (Link = GetFirstNode (SysPrepList); !IsNull (SysPrepList, Link); Link = GetNextNode (SysPrepList, Link)) {
|
|
LoadOption = BDS_OPTION_FROM_LINK (Link);
|
|
if ((LoadOption->Attributes & LOAD_OPTION_ACTIVE) == 0) {
|
|
continue;
|
|
}
|
|
|
|
LaunchStatus = gBdsServices->LaunchLoadOption (gBdsServices, LoadOption, &ExitDataSize, &ExitData);
|
|
if (!EFI_ERROR (LaunchStatus)) {
|
|
Status = EFI_SUCCESS;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Report the capability of system preparation by setting BootOptionSupport variable.
|
|
|
|
@retval EFI_SUCCESS Report the capability of system preparation successfully.
|
|
@retval Other Report the capability of system preparation failed.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
ReportSysPrepCapability (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT32 BootOptionSupport;
|
|
UINTN Size;
|
|
|
|
Size = sizeof (BootOptionSupport);
|
|
Status = gRT->GetVariable (
|
|
EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME,
|
|
&gEfiGlobalVariableGuid,
|
|
NULL,
|
|
&Size,
|
|
&BootOptionSupport
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
BootOptionSupport = 0;
|
|
}
|
|
|
|
if (FeaturePcdGet (PcdH2OBdsSysPrepSupported)) {
|
|
BootOptionSupport |= (UINT32) EFI_BOOT_OPTION_SUPPORT_SYSPREP;
|
|
} else {
|
|
BootOptionSupport &= (~(UINT32) EFI_BOOT_OPTION_SUPPORT_SYSPREP);
|
|
}
|
|
|
|
return gRT->SetVariable (
|
|
EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME,
|
|
&gEfiGlobalVariableGuid,
|
|
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
|
|
sizeof (BootOptionSupport),
|
|
&BootOptionSupport
|
|
);
|
|
}
|
|
|
|
/**
|
|
Perform boot option enumeration to refresh boot list.
|
|
|
|
@param[out] BootLists Double pointer to boot list
|
|
|
|
@retval EFI_SUCCESS Refresh boot list successfully.
|
|
@return Other Get boot option list failed.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
RefreshBootList (
|
|
OUT LIST_ENTRY **BootLists
|
|
)
|
|
{
|
|
BdsLibEnumerateAllBootOption (TRUE, NULL);
|
|
return gBdsServices->GetBootList (gBdsServices, BootLists);
|
|
}
|
|
|
|
/**
|
|
Internal function to check is whether no any active boot option.
|
|
|
|
@param[out] BootLists Pointer to boot list
|
|
|
|
@retval TRUE Doesn't have any boot option with active boot attribute.
|
|
@return FALSE Has at least one boot opton with active boot attribute.
|
|
**/
|
|
STATIC
|
|
BOOLEAN
|
|
IsNoActiveBootOption (
|
|
LIST_ENTRY *BootLists
|
|
)
|
|
{
|
|
LIST_ENTRY *Link;
|
|
H2O_BDS_LOAD_OPTION *BootOption;
|
|
|
|
if (BootLists == NULL) {
|
|
return TRUE;
|
|
}
|
|
for (Link = GetFirstNode (BootLists); Link != BootLists; Link = GetNextNode (BootLists, Link)) {
|
|
BootOption = BDS_OPTION_FROM_LINK (Link);
|
|
if (IS_LOAD_OPTION_TYPE (BootOption->Attributes, LOAD_OPTION_ACTIVE)) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
Dump boot option list.
|
|
**/
|
|
STATIC
|
|
VOID
|
|
DumpBootOptionList (
|
|
IN LIST_ENTRY *BootLists,
|
|
IN H2O_BDS_LOAD_OPTION *CurrentBootOption
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *DevPathToText;
|
|
LIST_ENTRY *Link;
|
|
H2O_BDS_LOAD_OPTION *BootOption;
|
|
H2O_BDS_LOAD_OPTION *ExpandedBootOption;
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
|
CHAR16 *DevicePathStr;
|
|
UINTN Index;
|
|
BOOLEAN AttrStrFound;
|
|
|
|
if (BootLists == NULL || CurrentBootOption == NULL) {
|
|
return;
|
|
}
|
|
|
|
Status = gBS->LocateProtocol (&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **) &DevPathToText);
|
|
if (EFI_ERROR (Status)) {
|
|
return;
|
|
}
|
|
|
|
DEBUG ((EFI_D_INFO, "-------------------------- Boot Option List --------------------------\n"));
|
|
for (Link = GetFirstNode (BootLists); !IsNull (BootLists, Link); Link = GetNextNode (BootLists, Link)) {
|
|
BootOption = BDS_OPTION_FROM_LINK (Link);
|
|
|
|
if (BootOption->Expanded && !IsListEmpty (&BootOption->ExpandedLoadOptions)) {
|
|
ExpandedBootOption = BDS_OPTION_FROM_LINK (BootOption->ExpandedLoadOptions.ForwardLink);
|
|
DevicePath = ExpandedBootOption->DevicePath;
|
|
} else {
|
|
DevicePath = BootOption->DevicePath;
|
|
}
|
|
DevicePathStr = DevPathToText->ConvertDevicePathToText (DevicePath, FALSE, FALSE);
|
|
if (DevicePathStr == NULL) {
|
|
break;
|
|
}
|
|
|
|
DEBUG (\
|
|
(EFI_D_INFO, "%s[Boot%04x] %s \"%s\" Attributes:0x%08x",\
|
|
(BootOption->LoadOrder == CurrentBootOption->LoadOrder) ? L"*" : L" ",\
|
|
BootOption->LoadOrder,\
|
|
DevicePathStr,\
|
|
BootOption->Description,\
|
|
BootOption->Attributes
|
|
));
|
|
FreePool (DevicePathStr);
|
|
|
|
AttrStrFound = FALSE;
|
|
for (Index = 0; Index < sizeof (mLoadOptionAttrStrInfo) / sizeof (LOAD_OPTION_ATTRIBUTE_STRING_INFO); Index++) {
|
|
if ((BootOption->Attributes & mLoadOptionAttrStrInfo[Index].Mask) == mLoadOptionAttrStrInfo[Index].Value) {
|
|
if (!AttrStrFound) {
|
|
AttrStrFound = TRUE;
|
|
DEBUG ((EFI_D_INFO, "("));
|
|
} else {
|
|
DEBUG ((EFI_D_INFO, "|"));
|
|
}
|
|
DEBUG ((EFI_D_INFO, "%s",mLoadOptionAttrStrInfo[Index].String));
|
|
}
|
|
}
|
|
if (AttrStrFound) {
|
|
DEBUG ((EFI_D_INFO, ")"));
|
|
}
|
|
DEBUG ((EFI_D_INFO, "\n"));
|
|
}
|
|
DEBUG ((EFI_D_INFO, "----------------------------------------------------------------------\n"));
|
|
}
|
|
|
|
/**
|
|
This function attempts to boot for the boot order specified
|
|
by platform policy.
|
|
**/
|
|
VOID
|
|
BdsBootDeviceSelect (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
LIST_ENTRY *Link;
|
|
H2O_BDS_LOAD_OPTION *BootOption;
|
|
H2O_BDS_LOAD_OPTION *BootNextOption;
|
|
UINTN ExitDataSize;
|
|
CHAR16 *ExitData;
|
|
LIST_ENTRY *BootLists;
|
|
LIST_ENTRY DefautlBootLists;
|
|
CHAR16 Buffer[20];
|
|
KERNEL_CONFIGURATION SystemConfiguration;
|
|
EFI_STATUS SystemConfigStatus;
|
|
EFI_BOOT_MODE BootMode;
|
|
UINT8 CmosData = 0;
|
|
CHAR16 *String;
|
|
BOOLEAN AlreadyConnectAll;
|
|
BOOLEAN LinkUpdated;
|
|
BOOLEAN BootFromBootNext;
|
|
UINTN MappingOpitonCount;
|
|
UINT16 *MappingOpitonOrder;
|
|
UINT16 SelectedOptionNum;
|
|
UINTN VariableSize;
|
|
VOID *VariablePtr;
|
|
H2O_BDS_LOAD_OPTION *TempBootOption;
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
|
BOOLEAN BootDefaultOption;
|
|
H2O_BDS_LOAD_OPTION *LoadOption;
|
|
UINT64 OsIndications;
|
|
UINT64 OsIndicationsSupported;
|
|
BOOLEAN RequireOsRecovery;
|
|
BOOLEAN RequirePlatformRecovery;
|
|
UINT8 RecoveryRetryTime;
|
|
BOOLEAN ShowBootResultFlag;
|
|
BOOLEAN OrgHotKeySetting;
|
|
|
|
//
|
|
// PostCode = 0x2B, Try to boot system to OS
|
|
//
|
|
POST_CODE (BDS_BOOT_DEVICE_SELECT);
|
|
|
|
OrgHotKeySetting = EnableBdsHotKey (FALSE);
|
|
BdsHotKeyBoot (TRIGGER_POINT_BEFORE_OS_INDICATIONS);
|
|
|
|
if (DoesOsIndicateBootToFwUI ()) {
|
|
POST_CODE (BDS_ENTER_FIRMWARE_UI);
|
|
ClearOsIndicationsBits ((UINT64) EFI_OS_INDICATIONS_BOOT_TO_FW_UI);
|
|
DevicePath = GetDevicePathByStr ((CHAR16 *) PcdGetPtr (PcdH2OBdsOsIndicationsFwUiApp));
|
|
if (DevicePath != NULL) {
|
|
LaunchBootOptionByDevicePath (DevicePath);
|
|
FreePool (DevicePath);
|
|
}
|
|
}
|
|
|
|
Status = gBdsServices->GetOsIndications (gBdsServices, &OsIndications, &OsIndicationsSupported);
|
|
if (Status != EFI_SUCCESS) {
|
|
OsIndications = 0;
|
|
OsIndicationsSupported = 0;
|
|
}
|
|
RequirePlatformRecovery = (BOOLEAN) ((OsIndications & OsIndicationsSupported & EFI_OS_INDICATIONS_START_PLATFORM_RECOVERY) != 0);
|
|
RequireOsRecovery = (BOOLEAN) ((OsIndications & OsIndicationsSupported & EFI_OS_INDICATIONS_START_OS_RECOVERY ) != 0);
|
|
|
|
if ((PcdGet64 (PcdOsIndicationsSupported) & EFI_OS_INDICATIONS_START_PLATFORM_RECOVERY) != 0 && RequirePlatformRecovery) {
|
|
ClearOsIndicationsBits ((UINT64) EFI_OS_INDICATIONS_START_PLATFORM_RECOVERY);
|
|
PerformPlatformRecovery ();
|
|
} else if ((PcdGet64 (PcdOsIndicationsSupported) & EFI_OS_INDICATIONS_START_OS_RECOVERY) != 0 && RequireOsRecovery) {
|
|
ClearOsIndicationsBits ((UINT64) EFI_OS_INDICATIONS_START_OS_RECOVERY);
|
|
PerformOsRecovery ();
|
|
}
|
|
EnableBdsHotKey (OrgHotKeySetting);
|
|
|
|
Status = BdsLibGetBootMode (&BootMode);
|
|
if (EFI_ERROR (Status)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Got the latest boot option
|
|
//
|
|
BootNextOption = NULL;
|
|
AlreadyConnectAll = FALSE;
|
|
|
|
//
|
|
// First check the boot next option
|
|
//
|
|
ZeroMem (Buffer, sizeof (Buffer));
|
|
|
|
if (mBootNext == NULL) {
|
|
//
|
|
// Check if we have the boot next option created during BDS
|
|
//
|
|
mBootNext = BdsLibGetVariableAndSize (
|
|
L"BootNext",
|
|
&gEfiGlobalVariableGuid,
|
|
&VariableSize
|
|
);
|
|
}
|
|
|
|
if (gBdsServices->BootNextLoadOption == NULL) {
|
|
//
|
|
// Check if we have the boot next option created during BDS
|
|
//
|
|
Status = gBdsServices->ConvertVarToLoadOption (gBdsServices, EFI_BOOT_NEXT_VARIABLE_NAME, &gEfiGlobalVariableGuid, &LoadOption);
|
|
if (Status == EFI_SUCCESS) {
|
|
gBdsServices->BootNextLoadOption = LoadOption;
|
|
}
|
|
}
|
|
|
|
OrgHotKeySetting = EnableBdsHotKey (FALSE);
|
|
BdsHotKeyBoot (TRIGGER_POINT_BEFORE_BOOT_NEXT);
|
|
|
|
if (FeaturePcdGet(PcdH2OBdsSysPrepSupported) && !RequireOsRecovery && !RequirePlatformRecovery) {
|
|
PerformSysPrep ();
|
|
}
|
|
|
|
gRT->SetVariable (
|
|
EFI_BOOT_NEXT_VARIABLE_NAME,
|
|
&gEfiGlobalVariableGuid,
|
|
0,
|
|
0,
|
|
NULL
|
|
);
|
|
if (gBdsServices->BootNextLoadOption && mBootNext != NULL) {
|
|
//
|
|
// Indicate we have the boot next variable, so this time
|
|
// boot will always have this boot option
|
|
//
|
|
if (BdsLibIsDummyBootOption (*mBootNext)) {
|
|
Status = BdsLibGetMappingBootOptions (*mBootNext, &MappingOpitonCount, &MappingOpitonOrder);
|
|
if (Status == EFI_SUCCESS) {
|
|
if (MappingOpitonCount == 0) {
|
|
//
|
|
// Show no USB boot option message for user and then go to Boot Manager menu for user to select boot option.
|
|
//
|
|
CreateNoMappingBootOptionPopUp (*mBootNext);
|
|
VariableSize = 0;
|
|
VariablePtr = NULL;
|
|
Status = gRT->GetVariable (L"BootOrder", &gEfiGlobalVariableGuid, NULL, &VariableSize, VariablePtr);
|
|
if (Status == EFI_BUFFER_TOO_SMALL) {
|
|
LaunchBootFailApp ();
|
|
}
|
|
} else if (MappingOpitonCount == 1) {
|
|
//
|
|
// System has one mapping boot option, boot this boot option direclty.
|
|
//
|
|
UnicodeSPrint (Buffer, sizeof (Buffer), L"Boot%04x", MappingOpitonOrder[0]);
|
|
gBdsServices->ConvertVarToLoadOption (gBdsServices, Buffer, &gEfiGlobalVariableGuid, &BootNextOption);
|
|
} else {
|
|
//
|
|
// If system has more than 1 mapping boot option, let user to select specific mapping boot option.
|
|
//
|
|
Status = SelectMappingBootOption (*mBootNext, MappingOpitonCount, MappingOpitonOrder, &SelectedOptionNum);
|
|
if (!EFI_ERROR (Status)) {
|
|
UnicodeSPrint (Buffer, sizeof (Buffer), L"Boot%04x", SelectedOptionNum);
|
|
gBdsServices->ConvertVarToLoadOption (gBdsServices, Buffer, &gEfiGlobalVariableGuid, &BootNextOption);
|
|
}
|
|
}
|
|
if (MappingOpitonOrder != NULL) {
|
|
FreePool (MappingOpitonOrder);
|
|
}
|
|
}
|
|
} else {
|
|
//
|
|
// Add the boot next boot option
|
|
//
|
|
UnicodeSPrint (Buffer, sizeof (Buffer), L"Boot%04x", *mBootNext);
|
|
gBdsServices->ConvertVarToLoadOption (gBdsServices, Buffer, &gEfiGlobalVariableGuid, &BootNextOption);
|
|
}
|
|
} else if (BootMode == BOOT_ON_S4_RESUME) {
|
|
CmosData = ReadCmos8 (LastBootDevice);
|
|
if (IsLegacyBootOption ((UINT16)CmosData)) {
|
|
//
|
|
// Add the boot next boot option
|
|
//
|
|
UnicodeSPrint (Buffer, sizeof (Buffer), L"Boot%04x", ReadCmos8 (LastBootDevice));
|
|
gBdsServices->ConvertVarToLoadOption (gBdsServices, Buffer, &gEfiGlobalVariableGuid, &BootNextOption);
|
|
}
|
|
}
|
|
|
|
BootDefaultOption = FALSE;
|
|
gBdsServices->GetBootList (gBdsServices, &BootLists);
|
|
|
|
if (IsListEmpty (BootLists)) {
|
|
InitializeListHead (&DefautlBootLists);
|
|
AddDefaultBootOptionsToBootList (&DefautlBootLists);
|
|
BootLists = &DefautlBootLists;
|
|
BootDefaultOption = TRUE;
|
|
}
|
|
|
|
RecoveryRetryTime = 0;
|
|
if (FeaturePcdGet (PcdH2OBdsCpBootDeviceSelectSupported)) {
|
|
TriggerCpBootDeviceSelect (&BootLists);
|
|
}
|
|
|
|
Link = GetFirstNode (BootLists);
|
|
SystemConfigStatus = GetKernelConfiguration (&SystemConfiguration);
|
|
|
|
// Here we make the boot in a loop, every boot success will
|
|
// return to the front page
|
|
//
|
|
for (;;) {
|
|
if (IsListEmpty (BootLists)) {
|
|
BdsNoBootDevice (NO_BOOT_DEVICE);
|
|
} else if (IsNoActiveBootOption (BootLists)) {
|
|
BdsNoBootDevice (NO_ACTIVE_BOOT_OPTION);
|
|
}
|
|
|
|
//
|
|
// Check the boot option list first
|
|
//
|
|
if (Link == BootLists && BootNextOption == NULL) {
|
|
//
|
|
// There are two ways to enter here:
|
|
// 1. There is no active boot option, give user chance to
|
|
// add new boot option
|
|
// 2. All the active boot option processed, and there is no
|
|
// one is success to boot, then we back here to allow user
|
|
// add new active boot option
|
|
//
|
|
if (RecoveryRetryTime == 0) {
|
|
RecoveryRetryTime++;
|
|
Status = PerformOsRecovery ();
|
|
if (!EFI_ERROR (Status)) {
|
|
RefreshBootList (&BootLists);
|
|
Link = GetFirstNode (BootLists);
|
|
continue;
|
|
}
|
|
}
|
|
if (RecoveryRetryTime == 1) {
|
|
RecoveryRetryTime++;
|
|
Status = PerformPlatformRecovery ();
|
|
if (!EFI_ERROR (Status)) {
|
|
RefreshBootList (&BootLists);
|
|
Link = GetFirstNode (BootLists);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
String = GetStringById (STRING_TOKEN (STR_AUTO_FAILOVER_NO_BOOT_DEVICE));
|
|
if (String != NULL) {
|
|
AutoFailoverPolicyBehavior (TRUE, String);
|
|
FreePool(String);
|
|
}
|
|
|
|
LaunchBootFailApp ();
|
|
|
|
gBdsServices->GetBootList (gBdsServices, &BootLists);
|
|
Link = GetFirstNode (BootLists);
|
|
continue;
|
|
}
|
|
EnableBdsHotKey (OrgHotKeySetting);
|
|
|
|
if (BootNextOption != NULL) {
|
|
//
|
|
// Need expand load option to prevent from the boot option is windows to GO, short form device path, USB
|
|
// WWID or USB class device path.
|
|
//
|
|
gBdsServices->ExpandLoadOption (gBdsServices, BootNextOption);
|
|
|
|
BootOption = BootNextOption;
|
|
BootNextOption = NULL;
|
|
BootFromBootNext = TRUE;
|
|
} else {
|
|
//
|
|
// Get the boot option from the link list
|
|
//
|
|
BootOption = BDS_OPTION_FROM_LINK (Link);
|
|
BootFromBootNext = FALSE;
|
|
}
|
|
|
|
OrgHotKeySetting = EnableBdsHotKey (FALSE);
|
|
BdsHotKeyBoot (TRIGGER_POINT_BEFORE_CHECK_EACH_BOOT_OPTION);
|
|
//
|
|
// 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 (!IS_LOAD_OPTION_TYPE (BootOption->Attributes, LOAD_OPTION_ACTIVE)) {
|
|
//
|
|
// skip the header of the link list, because it has no boot option
|
|
//
|
|
if (!BootFromBootNext) {
|
|
Link = Link->ForwardLink;
|
|
}
|
|
continue;
|
|
}
|
|
//
|
|
// Make sure the boot option device path connected,
|
|
// but ignore the BBS device path
|
|
//
|
|
if (DevicePathType (BootOption->DevicePath) != BBS_DEVICE_PATH) {
|
|
//
|
|
// Notes: the internal shell can not been connected with device path
|
|
// so we do not check the status here
|
|
//
|
|
BdsLibConnectDevicePath (BootOption->DevicePath);
|
|
}
|
|
|
|
DEBUG_CODE (DumpBootOptionList(BootLists, BootOption););
|
|
//
|
|
// All the driver options should have been processed since
|
|
// now boot will be performed.
|
|
//
|
|
|
|
Status = gBdsServices->LaunchLoadOption (gBdsServices, BootOption, &ExitDataSize, &ExitData);
|
|
if (Status != EFI_SUCCESS) {
|
|
ShowBootResultFlag = (TriggerCpBootFail (Status, ExitData, ExitDataSize) == H2O_BDS_TASK_SKIP) ? FALSE : TRUE;
|
|
} else {
|
|
ShowBootResultFlag = (TriggerCpBootSuccess () == H2O_BDS_TASK_SKIP) ? FALSE : TRUE;
|
|
}
|
|
|
|
LinkUpdated = FALSE;
|
|
if (BdsLibIsWin8FastBootActive () && !AlreadyConnectAll && !BootDefaultOption) {
|
|
//
|
|
// create new boot option to prevent original boot option is freed by calling gBdsServices->GetBootList ()
|
|
// to synchronize BootList to BootOrder variable.
|
|
//
|
|
gBdsServices->ConvertVarToLoadOption (gBdsServices, BootOption->LoadOrderVarName, &BootOption->LoadOrderVarGuid, &BootOption);
|
|
//
|
|
// For Win 8 Fast Boot, do one time ConnectAll to connect all boot devices and point Link to next boot device.
|
|
//
|
|
AlreadyConnectAll = TRUE;
|
|
BdsLibConnectUsbHID ();
|
|
BdsLibConnectAll ();
|
|
RefreshBootList (&BootLists);
|
|
//
|
|
// If last boot is fail, update Link for next boot.
|
|
//
|
|
if (EFI_ERROR (Status)) {
|
|
Link = GetFirstNode (BootLists);
|
|
if (!IsListEmpty (BootLists)) {
|
|
//
|
|
// If next boot device path is the same as previous one, skip to next.
|
|
//
|
|
DevicePath = BootOption->DevicePath;
|
|
TempBootOption = BDS_OPTION_FROM_LINK (Link);
|
|
if (CompareMem (DevicePath, TempBootOption->DevicePath, GetDevicePathSize (DevicePath)) == 0) {
|
|
Link = Link->ForwardLink;
|
|
}
|
|
}
|
|
LinkUpdated = TRUE;
|
|
}
|
|
|
|
if (EFI_ERROR (Status) && !FeaturePcdGet(PcdWin8FastBootErrorMessageSupported)) {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (Status != EFI_SUCCESS) {
|
|
//
|
|
// Call platform action to indicate the boot fail
|
|
//
|
|
// If boot default device (not including Windows To Go) fail and Auto Failover is disable, go into firmware UI.
|
|
//
|
|
if (!EFI_ERROR (SystemConfigStatus) &&
|
|
SystemConfiguration.AutoFailover == 0 &&
|
|
!((DevicePathType (BootOption->DevicePath) == MESSAGING_DEVICE_PATH) &&
|
|
(DevicePathSubType (BootOption->DevicePath) == MSG_USB_CLASS_DP))) {
|
|
String = GetStringById (STRING_TOKEN (STR_AUTO_FAILOVER_DISABLE_BOOT_FAIL));
|
|
if (String != NULL) {
|
|
AutoFailoverPolicyBehavior (FALSE, String);
|
|
FreePool(String);
|
|
}
|
|
} else {
|
|
if (!(((DevicePathType (BootOption->DevicePath) == MESSAGING_DEVICE_PATH) &&
|
|
(DevicePathSubType (BootOption->DevicePath) == MSG_USB_CLASS_DP)) &&
|
|
Status != EFI_SECURITY_VIOLATION)) {
|
|
if (ShowBootResultFlag) {
|
|
ShowBootFailInfo (BootOption, Status);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!LinkUpdated && !BootFromBootNext) {
|
|
Link = Link->ForwardLink;
|
|
}
|
|
} else {
|
|
//
|
|
// Call platform action to indicate the boot success
|
|
//
|
|
if (ShowBootResultFlag) {
|
|
ShowBootSuccessInfo (BootOption);
|
|
}
|
|
//
|
|
// Boot success, then stop process the boot order, and go to boot success application.
|
|
//
|
|
RefreshBootList (&BootLists);
|
|
|
|
DevicePath = GetDevicePathByAsciiStr ((CHAR8 *) PcdGetPtr (PcdH2OBdsBootSuccessApp));
|
|
if (DevicePath != NULL) {
|
|
LaunchBootOptionByDevicePath (DevicePath);
|
|
FreePool (DevicePath);
|
|
}
|
|
|
|
gBdsServices->GetBootList (gBdsServices, &BootLists);
|
|
Link = GetFirstNode (BootLists);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
|
|
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 = gRT->SetVariable (
|
|
L"PerfDataMemAddr",
|
|
&gEfiGenericVariableGuid,
|
|
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
|
|
sizeof (UINT32),
|
|
&AcpiLowMemoryBase
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
//
|
|
// Mark L"PerfDataMemAddr" variable to read-only if the Variable Lock protocol exists
|
|
//
|
|
Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock);
|
|
if (!EFI_ERROR (Status)) {
|
|
Status = VariableLock->RequestToLock (VariableLock, L"PerfDataMemAddr", &gEfiGenericVariableGuid);
|
|
ASSERT_EFI_ERROR (Status);
|
|
}
|
|
}
|
|
}
|
|
|
|
EFI_STATUS
|
|
LockSensitiveVariables (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;
|
|
|
|
|
|
//
|
|
// Lock setup sensitive variables
|
|
//
|
|
Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Status = VariableLock->RequestToLock (VariableLock, L"Setup", &gSystemConfigurationGuid);
|
|
Status = VariableLock->RequestToLock (VariableLock, SECURE_FLASH_INFORMATION_NAME, &gSecureFlashInfoGuid);
|
|
Status = VariableLock->RequestToLock (VariableLock, ACPI_GLOBAL_VARIABLE, &gAcpiVariableSetGuid);
|
|
Status = VariableLock->RequestToLock (VariableLock, EFI_ADMINISTER_SECURE_BOOT_NAME, &gEfiGenericVariableGuid);
|
|
Status = VariableLock->RequestToLock (VariableLock, EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME, &gEfiMemoryTypeInformationGuid);
|
|
return Status;
|
|
}
|
|
/**
|
|
|
|
Hook Boot Services ExitBootServices ().
|
|
|
|
**/
|
|
STATIC
|
|
VOID
|
|
HookExitBootServices (
|
|
VOID
|
|
)
|
|
{
|
|
UINT32 Crc;
|
|
|
|
mOrginalExitBootServices = gBS->ExitBootServices;
|
|
gBS->ExitBootServices = ExitBootServicesHookFunction;
|
|
gBS->Hdr.CRC32 = 0;
|
|
Crc = 0;
|
|
gBS->CalculateCrc32 ((VOID *) gBS, gBS->Hdr.HeaderSize, &Crc);
|
|
gBS->Hdr.CRC32 = Crc;
|
|
}
|
|
|
|
/**
|
|
|
|
Initialize firmware vendor and firmware version in system table.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
InitFirmwareInfo (
|
|
VOID
|
|
)
|
|
{
|
|
CHAR16 *FirmwareVendor;
|
|
UINT32 Crc;
|
|
//
|
|
// Fill in FirmwareVendor and FirmwareRevision from PCDs
|
|
//
|
|
FirmwareVendor = (CHAR16 *) PcdGetPtr (PcdFirmwareVendor);
|
|
gST->FirmwareVendor = AllocateRuntimeCopyPool (StrSize (FirmwareVendor), FirmwareVendor);
|
|
ASSERT (gST->FirmwareVendor != NULL);
|
|
if (gST->FirmwareVendor == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
gST->FirmwareRevision = PcdGet32 (PcdFirmwareRevision);
|
|
DEBUG ((EFI_D_ERROR, "EFI Vendor : %s\nEFI Revision : %d.%d\n", gST->FirmwareVendor, gST->FirmwareRevision >> 16, gST->FirmwareRevision & 0xFFFF));
|
|
//
|
|
// Fixup Tasble CRC after we updated Firmware Vendor and Revision
|
|
//
|
|
gST->Hdr.CRC32 = 0;
|
|
gBS->CalculateCrc32 ((VOID *)gST, gST->Hdr.HeaderSize, &Crc);
|
|
gST->Hdr.CRC32 = Crc;
|
|
|
|
if (FeaturePcdGet (PcdH2OBdsCpExitBootServicesBeforeSupported)) {
|
|
//
|
|
// Hook ExitBootServices () to trigger H2O_BDS_CP_EXIT_BOOT_SERVICES_BEFORE_DATA
|
|
// check point before entering ExitBootServices ().
|
|
//
|
|
HookExitBootServices ();
|
|
}
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Initialize the L"OsIndicationsSupported" variable.
|
|
|
|
@retval EFI_SUCCESS Initialize L"OsIndicationsSupported" variable successfully.
|
|
@retval Other Fail status returned from set variable function.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
InitOsIndicationsSupportedVariable (
|
|
VOID
|
|
)
|
|
{
|
|
UINT64 OsIndicationsSupported;
|
|
|
|
OsIndicationsSupported = PcdGet64 (PcdOsIndicationsSupported);
|
|
return gRT->SetVariable (
|
|
EFI_OS_INDICATIONS_SUPPORT_VARIABLE_NAME,
|
|
&gEfiGlobalVariableGuid,
|
|
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
|
|
sizeof (OsIndicationsSupported),
|
|
&OsIndicationsSupported
|
|
);
|
|
}
|
|
|
|
/**
|
|
An empty function to pass error checking of CreateEventEx ().
|
|
|
|
This empty function ensures that EVT_NOTIFY_SIGNAL_ALL is error
|
|
checked correctly since it is now mapped into CreateEventEx() in UEFI 2.0.
|
|
|
|
@param Event Event whose notification function is being invoked.
|
|
@param Context The pointer to the notification function's context,
|
|
which is implementation-dependent.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
EmptyFunction (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
return;
|
|
}
|
|
|
|
/**
|
|
Internal function to initialize H2O_BDS_CP_INIT_DATA data and trigger gH2OBdsCpInitGuid
|
|
checkpoint.
|
|
|
|
@retval EFI_SUCCESS Trigger gH2OBdsCpInitGuid checkpoint successfully.
|
|
@retval EFI_OUT_OF_RESOURCES Allocate memory to initialize checkpoint data failed.
|
|
@return Other Other error occurred while triggering gH2OBdsCpInitGuid
|
|
checkpoint.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
TriggerCpInit (
|
|
VOID
|
|
)
|
|
{
|
|
|
|
H2O_BDS_CP_INIT_DATA BdsInitData;
|
|
EFI_STATUS Status;
|
|
|
|
|
|
BdsInitData.Size = sizeof (H2O_BDS_CP_INIT_DATA);
|
|
BdsInitData.Status = H2O_CP_TASK_NORMAL;
|
|
DEBUG_CP ((DEBUG_INFO, "Checkpoint Trigger: %g\n", &gH2OBdsCpInitGuid));
|
|
Status = H2OCpTrigger (&gH2OBdsCpInitGuid, &BdsInitData);
|
|
DEBUG_CP ((DEBUG_INFO, "Checkpoint Result: %x\n", BdsInitData.Status));
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Internal function to initialize H2O_BDS_CP_PLATFORM_INIT_DATA data and trigger gH2OBdsCpPlatformInitGuid checkpoint.
|
|
|
|
@retval EFI_SUCCESS Trigger gH2OBdsCpPlatformInitGuid checkpoint successfully.
|
|
@return Other Other error occurred while triggering gH2OBdsCpPlatformInitGuid checkpoint.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
TriggerCpPlatformInit (
|
|
VOID
|
|
)
|
|
{
|
|
H2O_BDS_CP_PLATFORM_INIT_DATA BdsPlatformInitData;
|
|
EFI_STATUS Status;
|
|
|
|
BdsPlatformInitData.Size = sizeof (H2O_BDS_CP_PLATFORM_INIT_DATA);
|
|
BdsPlatformInitData.Status = H2O_CP_TASK_NORMAL;
|
|
DEBUG_CP ((DEBUG_INFO, "Checkpoint Trigger: %g\n", &gH2OBdsCpPlatformInitGuid));
|
|
Status = H2OCpTrigger (&gH2OBdsCpPlatformInitGuid, &BdsPlatformInitData);
|
|
DEBUG_CP ((DEBUG_INFO, "Checkpoint Result: %x\n", BdsPlatformInitData.Status));
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Internal function to initialize _H2O_BDS_CP_END_OF_DXE_BEFORE_PROTOCOL data and trigger gH2OBdsCpEndOfDxeBeforeGuid
|
|
checkpoint.
|
|
|
|
@retval EFI_SUCCESS Trigger gH2OBdsCpEndOfDxeBeforeGuid checkpoint successfully.
|
|
@retval EFI_OUT_OF_RESOURCES Allocate memory to initialize checkpoint data failed.
|
|
@return Other Other error occurred while triggering gH2OBdsCpEndOfDxeBeforeGuid
|
|
checkpoint.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
TriggerCpEndOfDxeBefore (
|
|
VOID
|
|
)
|
|
{
|
|
H2O_BDS_CP_END_OF_DXE_BEFORE_DATA BdsEndOfDxeBeforeData;
|
|
EFI_STATUS Status;
|
|
|
|
|
|
BdsEndOfDxeBeforeData.Size = sizeof (H2O_BDS_CP_END_OF_DXE_BEFORE_DATA);
|
|
BdsEndOfDxeBeforeData.Status = H2O_CP_TASK_NORMAL;
|
|
DEBUG_CP ((DEBUG_INFO, "Checkpoint Trigger: %g\n", &gH2OBdsCpEndOfDxeBeforeGuid));
|
|
Status = H2OCpTrigger (&gH2OBdsCpEndOfDxeBeforeGuid, &BdsEndOfDxeBeforeData);
|
|
DEBUG_CP ((DEBUG_INFO, "Checkpoint Result: %x\n", BdsEndOfDxeBeforeData.Status));
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Internal function to initialize H2O_BDS_CP_END_OF_DXE_AFTER_DATA data and trigger
|
|
gH2OBdsCpEndOfDxeAfterGuid checkpoint.
|
|
|
|
@retval EFI_SUCCESS Trigger gH2OBdsCpEndOfDxeAfterGuid checkpoint successfully.
|
|
@retval EFI_OUT_OF_RESOURCES Allocate memory to initialize checkpoint data failed.
|
|
@return Other Other error occurred while triggering gH2OBdsCpEndOfDxeAfterGuid
|
|
checkpoint.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
TriggerCpEndOfDxeAfter (
|
|
VOID
|
|
)
|
|
{
|
|
|
|
H2O_BDS_CP_END_OF_DXE_AFTER_DATA BdsEndOfDxeAfterData;
|
|
EFI_STATUS Status;
|
|
|
|
|
|
BdsEndOfDxeAfterData.Size = sizeof (H2O_BDS_CP_END_OF_DXE_AFTER_DATA);
|
|
BdsEndOfDxeAfterData.Status = H2O_CP_TASK_NORMAL;
|
|
DEBUG_CP ((DEBUG_INFO, "Checkpoint Trigger: %g\n", &gH2OBdsCpEndOfDxeAfterGuid));
|
|
Status = H2OCpTrigger (&gH2OBdsCpEndOfDxeAfterGuid, &BdsEndOfDxeAfterData);
|
|
DEBUG_CP ((DEBUG_INFO, "Checkpoint Result: %x\n", BdsEndOfDxeAfterData.Status));
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Internal function to initialize H2O_BDS_CP_DRIVER_CONNECT_AFTER_DATA data and trigger
|
|
gH2OBdsCpDriverConnectAfterGuid checkpoint.
|
|
|
|
@retval EFI_SUCCESS Trigger gH2OBdsCpDriverConnectAfterGuid checkpoint successfully.
|
|
@retval EFI_OUT_OF_RESOURCES Allocate memory to initialize checkpoint data failed.
|
|
@return Other Other error occurred while triggering gH2OBdsCpDriverConnectAfterGuid
|
|
checkpoint.
|
|
**/
|
|
EFI_STATUS
|
|
TriggerCpDriverConnectAfter (
|
|
VOID
|
|
)
|
|
{
|
|
H2O_BDS_CP_DRIVER_CONNECT_AFTER_DATA BdsDriverConnectAfterData;
|
|
EFI_STATUS Status;
|
|
|
|
BdsDriverConnectAfterData.Size = sizeof (H2O_BDS_CP_DRIVER_CONNECT_AFTER_DATA);
|
|
BdsDriverConnectAfterData.Status = H2O_CP_TASK_NORMAL;
|
|
DEBUG_CP ((DEBUG_INFO, "Checkpoint Trigger: %g\n", &gH2OBdsCpDriverConnectAfterGuid));
|
|
Status = H2OCpTrigger (&gH2OBdsCpDriverConnectAfterGuid, &BdsDriverConnectAfterData);
|
|
DEBUG_CP ((DEBUG_INFO, "Checkpoint Result: %x\n", BdsDriverConnectAfterData.Status));
|
|
return Status;
|
|
|
|
}
|
|
|
|
/**
|
|
Internal function to initialize H2O_BDS_CP_DRIVER_CONNECT_BEFORE_DATA data and trigger
|
|
gH2OBdsCpDriverConnectBeforeGuid checkpoint.
|
|
|
|
@retval EFI_SUCCESS Trigger gH2OBdsCpDriverConnectBeforeGuid checkpoint successfully.
|
|
@retval EFI_OUT_OF_RESOURCES Allocate memory to initialize checkpoint data failed.
|
|
@return Other Other error occurred while triggering gH2OBdsCpDriverConnectBeforeGuid
|
|
checkpoint.
|
|
**/
|
|
EFI_STATUS
|
|
TriggerCpDriverConnectBefore (
|
|
VOID
|
|
)
|
|
{
|
|
H2O_BDS_CP_DRIVER_CONNECT_BEFORE_DATA BdsDriverConnectBeforeData;
|
|
EFI_STATUS Status;
|
|
|
|
BdsDriverConnectBeforeData.Size = sizeof (H2O_BDS_CP_DRIVER_CONNECT_BEFORE_DATA);
|
|
BdsDriverConnectBeforeData.Status = H2O_CP_TASK_NORMAL;
|
|
DEBUG_CP ((DEBUG_INFO, "Checkpoint Trigger: %g\n", &gH2OBdsCpDriverConnectBeforeGuid));
|
|
Status = H2OCpTrigger (&gH2OBdsCpDriverConnectBeforeGuid, &BdsDriverConnectBeforeData);
|
|
DEBUG_CP ((DEBUG_INFO, "Checkpoint Result: %x\n", BdsDriverConnectBeforeData.Status));
|
|
return 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
|
|
)
|
|
{
|
|
UINTN Size;
|
|
EFI_STATUS Status;
|
|
UINT16 Timeout;
|
|
EFI_TIMER_ARCH_PROTOCOL *Timer;
|
|
EFI_EVENT EndOfDxeEvent;
|
|
//
|
|
// PostCode = 0x10, Enter BDS entry
|
|
//
|
|
POST_CODE (BDS_ENTER_BDS);
|
|
//
|
|
// Insert the performance probe
|
|
//
|
|
PERF_END (0, DXE_TOK, NULL, 0);
|
|
PERF_START (0, BDS_TOK, NULL, 0);
|
|
|
|
InitializeStringSupport ();
|
|
if (FeaturePcdGet (PcdH2OBdsCpInitSupported)) {
|
|
TriggerCpInit ();
|
|
}
|
|
PERF_CODE (
|
|
BdsAllocateMemoryForPerformanceData ();
|
|
);
|
|
LockSensitiveVariables ();
|
|
|
|
//
|
|
// Set the timer tick to 100hz to make whole timer interrupt handler operate in desire frequency
|
|
//
|
|
Status = gBS->LocateProtocol (&gEfiTimerArchProtocolGuid, NULL, (VOID **) &Timer);
|
|
if (!EFI_ERROR (Status)) {
|
|
Timer->SetTimerPeriod (Timer, 100000);
|
|
}
|
|
|
|
if (PcdGetBool (PcdEndOfDxeEventSupported)) {
|
|
//
|
|
// According to PI 1.2.1, signal EndOfDxe at end of DXE
|
|
//
|
|
Status = gBS->CreateEventEx (
|
|
EVT_NOTIFY_SIGNAL,
|
|
TPL_CALLBACK,
|
|
EmptyFunction,
|
|
NULL,
|
|
&gEfiEndOfDxeEventGroupGuid,
|
|
&EndOfDxeEvent
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
if (FeaturePcdGet (PcdH2OBdsCpEndOfDxeBeforeSupported)) {
|
|
TriggerCpEndOfDxeBefore ();
|
|
}
|
|
gBS->SignalEvent (EndOfDxeEvent);
|
|
if (FeaturePcdGet (PcdH2OBdsCpEndOfDxeAfterSupported)) {
|
|
TriggerCpEndOfDxeAfter ();
|
|
}
|
|
gBS->CloseEvent (EndOfDxeEvent);
|
|
DEBUG((EFI_D_INFO,"All EndOfDxe callbacks have returned successfully\n"));
|
|
}
|
|
}
|
|
//
|
|
// Do the platform init, can be customized by OEM/IBV
|
|
//
|
|
PERF_START (NULL, "PlatformBds", "BDS", 0);
|
|
InitFirmwareInfo ();
|
|
PlatformBdsInit ();
|
|
if (IsBdsHotKeySupport ()) {
|
|
BdsHotKeyInit ();
|
|
}
|
|
Status = InstallH2OBdsServicesProtocol ();
|
|
if (!EFI_ERROR (Status)) {
|
|
if (FeaturePcdGet (PcdH2OBdsCpPlatformInitSupported)) {
|
|
TriggerCpPlatformInit ();
|
|
}
|
|
}
|
|
|
|
//
|
|
// BdsLibGetTimeout() will initialize Timeout variable if variable is not exist.
|
|
//
|
|
Size = sizeof (Timeout);
|
|
Status = gRT->GetVariable (
|
|
L"Timeout",
|
|
&gEfiGlobalVariableGuid,
|
|
NULL,
|
|
&Size,
|
|
&Timeout
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
Timeout = (UINT16) PcdGet16 (PcdPlatformBootTimeOut);
|
|
Status = gRT->SetVariable (
|
|
L"Timeout",
|
|
&gEfiGlobalVariableGuid,
|
|
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
|
|
sizeof (Timeout),
|
|
&Timeout
|
|
);
|
|
}
|
|
InitOsIndicationsSupportedVariable ();
|
|
ReportSysPrepCapability ();
|
|
|
|
UpdateBootMessage ();
|
|
|
|
//
|
|
// Set up the device list based on EFI 1.1 variables
|
|
// process Driver#### and Load the driver's in the
|
|
// driver option list
|
|
//
|
|
if (FeaturePcdGet (PcdH2OBdsCpDriverConnectBeforeSupported)) {
|
|
TriggerCpDriverConnectBefore ();
|
|
}
|
|
BdsLibLaunchDrivers ();
|
|
if (FeaturePcdGet (PcdH2OBdsCpDriverConnectAfterSupported)) {
|
|
TriggerCpDriverConnectAfter ();
|
|
}
|
|
//
|
|
// Check if we have the boot next option
|
|
//
|
|
mBootNext = BdsLibGetVariableAndSize (
|
|
L"BootNext",
|
|
&gEfiGlobalVariableGuid,
|
|
&Size
|
|
);
|
|
|
|
SetSimpBootFlag ();
|
|
if (H2OGetBootType () == LEGACY_BOOT_TYPE) {
|
|
BdsLibSkipEbcDispatch ();
|
|
}
|
|
|
|
//
|
|
// Setup some platform policy here
|
|
//
|
|
PlatformBdsPolicyBehavior (NULL, NULL, BdsProcessCapsules, BdsMemoryTest);
|
|
PERF_END (NULL, "PlatformBds", "BDS", 0);
|
|
|
|
//
|
|
// BDS select the boot device to load OS
|
|
//
|
|
BdsBootDeviceSelect ();
|
|
|
|
//
|
|
// Only assert here since this is the right behavior, we should never
|
|
// return back to DxeCore.
|
|
//
|
|
ASSERT (FALSE);
|
|
|
|
return ;
|
|
}
|
|
|