1200 lines
38 KiB
C
1200 lines
38 KiB
C
/** @file
|
|
The boot manager implementation
|
|
|
|
;******************************************************************************
|
|
;* 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.
|
|
;*
|
|
;******************************************************************************
|
|
*/
|
|
|
|
/**
|
|
The platform boot manager reference implementation
|
|
|
|
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 "BootManager.h"
|
|
|
|
STATIC EFI_FORM_BROWSER2_PROTOCOL *gBootManagerFormBrowser2;
|
|
BOOLEAN gConnectAllHappened;
|
|
|
|
STATIC BOOLEAN mBootMgrSendFormBySelf = FALSE;
|
|
STATIC EFI_EVENT mUpdateBootOptionListEvt = NULL;
|
|
STATIC LIST_ENTRY mBackupBootOptionsList = INITIALIZE_LIST_HEAD_VARIABLE (mBackupBootOptionsList);
|
|
STATIC LIST_ENTRY *mBootOptionsList;
|
|
STATIC H2O_BDS_LOAD_OPTION *gOption;
|
|
STATIC EFI_STRING_ID mDeviceTypeStrId[] = {
|
|
STRING_TOKEN (STR_DEVICE_TYPE_LEGACY_BEV),
|
|
STRING_TOKEN (STR_DEVICE_TYPE_LEGACY_FLOPPY),
|
|
STRING_TOKEN (STR_DEVICE_TYPE_LEGACY_HARD_DRIVE),
|
|
STRING_TOKEN (STR_DEVICE_TYPE_LEGACY_CDROM),
|
|
STRING_TOKEN (STR_DEVICE_TYPE_LEGACY_PCMCIA),
|
|
STRING_TOKEN (STR_DEVICE_TYPE_LEGACY_USB),
|
|
STRING_TOKEN (STR_DEVICE_TYPE_LEGACY_NETWORK),
|
|
STRING_TOKEN (STR_DEVICE_TYPE_LEGACY_UNKNOWN_DEVICE),
|
|
};
|
|
|
|
EFI_LOAD_FILE_PROTOCOL mBootManagerLoadFile = {BootManagerLoadFile};
|
|
STATIC HII_VENDOR_DEVICE_PATH mBootManagerHiiVendorDevicePath = {
|
|
{
|
|
{
|
|
HARDWARE_DEVICE_PATH,
|
|
HW_VENDOR_DP,
|
|
{
|
|
(UINT8) (sizeof (VENDOR_DEVICE_PATH)),
|
|
(UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
|
|
}
|
|
},
|
|
BOOT_MANAGER_FORMSET_GUID
|
|
},
|
|
{
|
|
END_DEVICE_PATH_TYPE,
|
|
END_ENTIRE_DEVICE_PATH_SUBTYPE,
|
|
{
|
|
(UINT8) (END_DEVICE_PATH_LENGTH),
|
|
(UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
|
|
}
|
|
}
|
|
};
|
|
|
|
STATIC BOOT_MANAGER_CALLBACK_DATA gBootManagerPrivate = {
|
|
BOOT_MANAGER_CALLBACK_DATA_SIGNATURE,
|
|
NULL,
|
|
NULL,
|
|
{
|
|
BootManagerFakeExtractConfig,
|
|
BootManagerFakeRouteConfig,
|
|
BootManagerCallback
|
|
}
|
|
};
|
|
|
|
/**
|
|
Compares two boot option.
|
|
|
|
@param[in] BootOptions1 A pointer to one boot option.
|
|
@param[in] BootOptions2 A pointer to another boot option.
|
|
|
|
@retval TRUE BootOptions1 and BootOptions2 are identical.
|
|
@retval FALSE BootOptions1 and BootOptions2 are not identical.
|
|
**/
|
|
STATIC
|
|
BOOLEAN
|
|
IsIdenticalBootOption (
|
|
IN H2O_BDS_LOAD_OPTION *Option1,
|
|
IN H2O_BDS_LOAD_OPTION *Option2
|
|
)
|
|
{
|
|
if (Option1 == NULL || Option2 == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (Option1->DevicePath == Option2->DevicePath ||
|
|
(GetDevicePathSize (Option1->DevicePath) == GetDevicePathSize (Option2->DevicePath) &&
|
|
CompareMem (Option1->DevicePath, Option2->DevicePath, GetDevicePathSize (Option1->DevicePath)) == 0)) {
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
Free each boot option from boot option list.
|
|
|
|
@param[in, out] BootOptionsList A pointer to the boot option list.
|
|
**/
|
|
STATIC
|
|
VOID
|
|
FreeBootOptionList (
|
|
IN OUT LIST_ENTRY *BootOptionsList
|
|
)
|
|
{
|
|
LIST_ENTRY *Link;
|
|
H2O_BDS_LOAD_OPTION *Option;
|
|
|
|
if (BootOptionsList == NULL) {
|
|
return;
|
|
}
|
|
|
|
Link = GetFirstNode (BootOptionsList);
|
|
while (!IsNull (BootOptionsList, Link)) {
|
|
Option = BDS_OPTION_FROM_LINK (Link);
|
|
Link = GetNextNode (BootOptionsList, Link);
|
|
|
|
RemoveEntryList (&Option->Link);
|
|
FreePool (Option);
|
|
}
|
|
}
|
|
|
|
/**
|
|
Copy the source boot option list to the destination boot option list.
|
|
|
|
@param[in, out] DstBootOptionsList A pointer to the destination boot option list.
|
|
@param[in] SrcBootOptionsList A pointer to the source boot option list.
|
|
**/
|
|
STATIC
|
|
VOID
|
|
CopyBootOptionList (
|
|
IN OUT LIST_ENTRY *DstBootOptionsList,
|
|
IN LIST_ENTRY *SrcBootOptionsList
|
|
)
|
|
{
|
|
LIST_ENTRY *SrcLink;
|
|
H2O_BDS_LOAD_OPTION *SrcOption;
|
|
H2O_BDS_LOAD_OPTION *DstOption;
|
|
|
|
if (DstBootOptionsList == NULL || SrcBootOptionsList == NULL) {
|
|
return;
|
|
}
|
|
|
|
SrcLink = GetFirstNode (SrcBootOptionsList);
|
|
while (!IsNull (SrcBootOptionsList, SrcLink)) {
|
|
SrcOption = BDS_OPTION_FROM_LINK (SrcLink);
|
|
SrcLink = GetNextNode (SrcBootOptionsList, SrcLink);
|
|
|
|
DstOption = AllocateCopyPool (sizeof (H2O_BDS_LOAD_OPTION), SrcOption);
|
|
if (DstOption != NULL) {
|
|
InsertTailList (DstBootOptionsList, &DstOption->Link);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
Compares two boot option lists.
|
|
|
|
@param[in] BootOptionsList1 A pointer to one boot option list.
|
|
@param[in] BootOptionsList2 A pointer to another boot option list.
|
|
|
|
@retval TRUE BootOptionsList1 and BootOptionsList2 are identical.
|
|
@retval FALSE BootOptionsList1 and BootOptionsList2 are not identical.
|
|
**/
|
|
STATIC
|
|
BOOLEAN
|
|
CompareBootOptionList (
|
|
IN LIST_ENTRY *BootOptionsList1,
|
|
IN LIST_ENTRY *BootOptionsList2
|
|
)
|
|
{
|
|
LIST_ENTRY *Link1;
|
|
LIST_ENTRY *Link2;
|
|
H2O_BDS_LOAD_OPTION *Option1;
|
|
H2O_BDS_LOAD_OPTION *Option2;
|
|
|
|
if (BootOptionsList1 == NULL || BootOptionsList2 == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
Link1 = GetFirstNode (BootOptionsList1);
|
|
Link2 = GetFirstNode (BootOptionsList2);
|
|
while (!IsNull (BootOptionsList1, Link1) &&
|
|
!IsNull (BootOptionsList2, Link2)) {
|
|
Option1 = BDS_OPTION_FROM_LINK (Link1);
|
|
Option2 = BDS_OPTION_FROM_LINK (Link2);
|
|
if (!IsIdenticalBootOption (Option1, Option2)) {
|
|
return FALSE;
|
|
}
|
|
|
|
Link1 = GetNextNode (BootOptionsList1, Link1);
|
|
Link2 = GetNextNode (BootOptionsList2, Link2);
|
|
}
|
|
if (IsNull (BootOptionsList1, Link1) &&
|
|
IsNull (BootOptionsList2, Link2)) {
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
Check if the boot option is a legacy boot option.
|
|
|
|
@param[in] Option A pointer to the boot option.
|
|
|
|
@retval TRUE The boot option is a legacy boot option.
|
|
@retval FALSE The boot option is not a legacy boot option.
|
|
**/
|
|
STATIC
|
|
BOOLEAN
|
|
IsLegacyBootOption (
|
|
IN H2O_BDS_LOAD_OPTION *Option
|
|
)
|
|
{
|
|
if (Option == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
return (BOOLEAN) ((DevicePathType (Option->DevicePath) == BBS_DEVICE_PATH) &&
|
|
(DevicePathSubType (Option->DevicePath) == BBS_BBS_DP));
|
|
}
|
|
|
|
/**
|
|
Send hot key notify event.
|
|
|
|
@param[in] HotKeyAction Hot key action
|
|
@param[in] OptionsList Target question ID
|
|
|
|
@retval EFI_SUCCESS Send hot key notify successfully
|
|
@retval Other H2O form browser is not found or notify function return failed.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
SendHotKeyNotify (
|
|
IN HOT_KEY_ACTION HotKeyAction,
|
|
IN UINT16 QuestionId
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
H2O_FORM_BROWSER_PROTOCOL *FBProtocol;
|
|
H2O_DISPLAY_ENGINE_EVT_HOT_KEY HotKeyNotify;
|
|
|
|
Status = gBS->LocateProtocol (&gH2OFormBrowserProtocolGuid, NULL, (VOID **) &FBProtocol);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
ZeroMem (&HotKeyNotify, sizeof (HotKeyNotify));
|
|
HotKeyNotify.Hdr.Size = sizeof (H2O_DISPLAY_ENGINE_EVT_HOT_KEY);
|
|
HotKeyNotify.Hdr.Type = H2O_DISPLAY_ENGINE_EVT_TYPE_HOT_KEY;
|
|
HotKeyNotify.Hdr.Target = H2O_DISPLAY_ENGINE_EVT_TARGET_FORM_BROWSER;
|
|
|
|
HotKeyNotify.HotKeyAction = HotKeyAction;
|
|
HotKeyNotify.HotKeyTargetQuestionId = QuestionId;
|
|
|
|
return FBProtocol->Notify (FBProtocol, &HotKeyNotify.Hdr);
|
|
}
|
|
|
|
/**
|
|
Shift boot option in list and update to BootOrder variable based on list.
|
|
|
|
@param[in] QuestionId The question ID of current boot option.
|
|
@param[in] ToHigherPriority Shift current boot option to higher (TRUE) or lower (FALSE) priority.
|
|
|
|
@retval EFI_SUCCESS Shift boot option successfully
|
|
@retval EFI_NOT_FOUND Current boot option is not found
|
|
@retval EFI_ABORTED Exchanged two boot options are not the same boot type.
|
|
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
ShiftBootOption (
|
|
IN EFI_QUESTION_ID QuestionId,
|
|
IN BOOLEAN ToHigherPriority
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
LIST_ENTRY *OptionsList;
|
|
H2O_BDS_LOAD_OPTION *CurrentOption;
|
|
H2O_BDS_LOAD_OPTION *Option;
|
|
H2O_BDS_LOAD_OPTION *PreviousOption;
|
|
EFI_QUESTION_ID PreviousQuestionId;
|
|
H2O_BDS_LOAD_OPTION *NextOption;
|
|
EFI_QUESTION_ID NextQuestionId;
|
|
LIST_ENTRY *Link;
|
|
UINT16 OptionCount;
|
|
UINT16 *BootOrderVar;
|
|
|
|
//
|
|
// Enumerate option list to get the info of previous, current and next options.
|
|
//
|
|
CurrentOption = NULL;
|
|
PreviousOption = NULL;
|
|
PreviousQuestionId = 0;
|
|
NextOption = NULL;
|
|
NextQuestionId = 0;
|
|
OptionCount = 0;
|
|
OptionsList = &mBackupBootOptionsList;
|
|
for (Link = GetFirstNode (OptionsList); !IsNull (OptionsList, Link); Link = GetNextNode (OptionsList, Link)) {
|
|
Option = BDS_OPTION_FROM_LINK (Link);
|
|
OptionCount++;
|
|
|
|
if (((Option->Attributes & LOAD_OPTION_HIDDEN) != 0) || ((Option->Attributes & LOAD_OPTION_ACTIVE) == 0)) {
|
|
continue;
|
|
}
|
|
|
|
if (CurrentOption == NULL) {
|
|
if (OptionCount == QuestionId) {
|
|
CurrentOption = Option;
|
|
continue;
|
|
}
|
|
PreviousOption = Option;
|
|
PreviousQuestionId = OptionCount;
|
|
} else {
|
|
NextOption = Option;
|
|
NextQuestionId = OptionCount;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (CurrentOption == NULL ||
|
|
(ToHigherPriority && PreviousOption == NULL) ||
|
|
(!ToHigherPriority && NextOption == NULL)) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
//
|
|
// Forbid to exchange EFI and legacy boot options because of Setup "EFI device first" policy.
|
|
//
|
|
if ((ToHigherPriority && (IsLegacyBootOption (CurrentOption) != IsLegacyBootOption (PreviousOption))) ||
|
|
(!ToHigherPriority && (IsLegacyBootOption (CurrentOption) != IsLegacyBootOption (NextOption)))) {
|
|
return EFI_ABORTED;
|
|
}
|
|
|
|
BootOrderVar = CommonGetVariableData (L"BootOrder", &gEfiGlobalVariableGuid);
|
|
if (BootOrderVar == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Shift the position of current option in the list and update BootOrder variable based on the order in the list.
|
|
//
|
|
RemoveEntryList (&CurrentOption->Link);
|
|
if (ToHigherPriority) {
|
|
InsertTailList (&PreviousOption->Link, &CurrentOption->Link);
|
|
} else {
|
|
InsertHeadList (&NextOption->Link, &CurrentOption->Link);
|
|
}
|
|
|
|
OptionCount = 0;
|
|
for (Link = GetFirstNode (OptionsList); !IsNull (OptionsList, Link); Link = GetNextNode (OptionsList, Link)) {
|
|
Option = BDS_OPTION_FROM_LINK (Link);
|
|
BootOrderVar[OptionCount++] = Option->LoadOrder;
|
|
}
|
|
|
|
if (FeaturePcdGet (PcdAutoCreateDummyBootOption)) {
|
|
SyncBootOrder ();
|
|
BdsLibRestoreBootOrderFromPhysicalBootOrder ();
|
|
}
|
|
|
|
Status = CommonSetVariable (
|
|
L"BootOrder",
|
|
&gEfiGlobalVariableGuid,
|
|
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
|
|
OptionCount * sizeof (UINT16),
|
|
BootOrderVar
|
|
);
|
|
FreePool (BootOrderVar);
|
|
|
|
//
|
|
// Update option list and HII form.
|
|
//
|
|
gBdsServices->GetBootList (gBdsServices, &mBootOptionsList);
|
|
FreeBootOptionList (&mBackupBootOptionsList);
|
|
CopyBootOptionList (&mBackupBootOptionsList, mBootOptionsList);
|
|
UpdateBootOptionListIntoHiiForm ();
|
|
|
|
SendHotKeyNotify (HotKeyGoTo, (UINT16) (ToHigherPriority ? PreviousQuestionId : NextQuestionId));
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
This function allows a caller to extract the current configuration for one
|
|
or more named elements from the target driver.
|
|
|
|
|
|
@param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
|
|
@param Request A null-terminated Unicode string in <ConfigRequest> format.
|
|
@param Progress On return, points to a character in the Request string.
|
|
Points to the string's null terminator if request was successful.
|
|
Points to the most recent '&' before the first failing name/value
|
|
pair (or the beginning of the string if the failure is in the
|
|
first name/value pair) if the request was not successful.
|
|
@param Results A null-terminated Unicode string in <ConfigAltResp> format which
|
|
has all values filled in for the names in the Request string.
|
|
String to be allocated by the called function.
|
|
|
|
@retval EFI_SUCCESS The Results is filled with the requested values.
|
|
@retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.
|
|
@retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name.
|
|
@retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
BootManagerFakeExtractConfig (
|
|
IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
|
|
IN CONST EFI_STRING Request,
|
|
OUT EFI_STRING *Progress,
|
|
OUT EFI_STRING *Results
|
|
)
|
|
{
|
|
if (Progress == NULL || Results == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
*Progress = Request;
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
/**
|
|
This function processes the results of changes in configuration.
|
|
|
|
|
|
@param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
|
|
@param Configuration A null-terminated Unicode string in <ConfigResp> format.
|
|
@param Progress A pointer to a string filled in with the offset of the most
|
|
recent '&' before the first failing name/value pair (or the
|
|
beginning of the string if the failure is in the first
|
|
name/value pair) or the terminating NULL if all was successful.
|
|
|
|
@retval EFI_SUCCESS The Results is processed successfully.
|
|
@retval EFI_INVALID_PARAMETER Configuration is NULL.
|
|
@retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
BootManagerFakeRouteConfig (
|
|
IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
|
|
IN CONST EFI_STRING Configuration,
|
|
OUT EFI_STRING *Progress
|
|
)
|
|
{
|
|
if (Configuration == NULL || Progress == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
*Progress = Configuration;
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
/**
|
|
This call back function is registered with Boot Manager formset.
|
|
When user selects a boot option, this call back function will
|
|
be triggered. The boot option is saved for later processing.
|
|
|
|
|
|
@param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
|
|
@param Action Specifies the type of action taken by the browser.
|
|
@param QuestionId A unique value which is sent to the original exporting driver
|
|
so that it can identify the type of data to expect.
|
|
@param Type The type of value for the question.
|
|
@param Value A pointer to the data being sent to the original exporting driver.
|
|
@param ActionRequest On return, points to the action requested by the callback function.
|
|
|
|
@retval EFI_SUCCESS The callback successfully handled the action.
|
|
@retval EFI_INVALID_PARAMETER The setup browser call this function with invalid parameters.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
BootManagerCallback (
|
|
IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
|
|
IN EFI_BROWSER_ACTION Action,
|
|
IN EFI_QUESTION_ID QuestionId,
|
|
IN UINT8 Type,
|
|
IN EFI_IFR_TYPE_VALUE *Value,
|
|
OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
|
|
)
|
|
{
|
|
H2O_BDS_LOAD_OPTION *Option;
|
|
LIST_ENTRY *Link;
|
|
UINT16 KeyCount;
|
|
EFI_STATUS Status;
|
|
CHAR16 *ExitData;
|
|
UINTN ExitDataSize;
|
|
|
|
if (Action == EFI_BROWSER_ACTION_CHANGED) {
|
|
if ((Value == NULL) || (ActionRequest == NULL)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Initialize the key count
|
|
//
|
|
KeyCount = 0;
|
|
gOption = NULL;
|
|
for (Link = GetFirstNode (mBootOptionsList); !IsNull (mBootOptionsList, Link); Link = GetNextNode (mBootOptionsList, Link)) {
|
|
Option = BDS_OPTION_FROM_LINK (Link);
|
|
|
|
KeyCount++;
|
|
|
|
//
|
|
// Is this device the one chosen?
|
|
//
|
|
if (KeyCount == QuestionId) {
|
|
gOption = Option;
|
|
//
|
|
// Request to exit SendForm(), so that we could boot the selected option
|
|
//
|
|
*ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
|
|
if (mUpdateBootOptionListEvt != NULL) {
|
|
gBS->CloseEvent (mUpdateBootOptionListEvt);
|
|
mUpdateBootOptionListEvt = NULL;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
} else if (Action == H2O_BROWSER_ACTION_HOT_KEY_CALLBACK) {
|
|
if (QuestionId == BOOT_MANAGER_UPDATE_BOOT_LIST_QUESTION_ID) {
|
|
return UpdateBootOptionList ();
|
|
}
|
|
|
|
if (FeaturePcdGet (PcdH2OBootMgrChangeBootOrderSupported)) {
|
|
return ShiftBootOption (QuestionId, Value->b);
|
|
}
|
|
} else if (Action == EFI_BROWSER_ACTION_FORM_OPEN) {
|
|
if (!mBootMgrSendFormBySelf && QuestionId == 0x1212) {
|
|
//
|
|
// Boot Manager is imported by other VFR driver. Here to initialize boot manager.
|
|
//
|
|
InternalCallBootManagerBefore ();
|
|
}
|
|
} else if (Action == EFI_BROWSER_ACTION_FORM_CLOSE) {
|
|
if (!mBootMgrSendFormBySelf && QuestionId == 0x1212) {
|
|
InternalCallBootManagerAfter ();
|
|
|
|
if (gOption != NULL) {
|
|
Status = gBdsServices->LaunchLoadOption (gBdsServices, gOption, &ExitDataSize, &ExitData);
|
|
if (!EFI_ERROR (Status)) {
|
|
BdsLibBootSuccess (gOption);
|
|
} else {
|
|
BdsLibBootFailed (gOption, Status, ExitData, ExitDataSize);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// All other action return unsupported.
|
|
//
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
/**
|
|
|
|
Registers HII packages for the Boot Manger to HII Database.
|
|
It also registers the browser call back function.
|
|
|
|
@retval EFI_SUCCESS HII packages for the Boot Manager were registered successfully.
|
|
@retval EFI_OUT_OF_RESOURCES HII packages for the Boot Manager failed to be registered.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
InitializeBootManager (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &gBootManagerFormBrowser2);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Install Device Path Protocol and Config Access protocol to driver handle
|
|
//
|
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
|
&gBootManagerPrivate.DriverHandle,
|
|
&gEfiDevicePathProtocolGuid,
|
|
&mBootManagerHiiVendorDevicePath,
|
|
&gEfiHiiConfigAccessProtocolGuid,
|
|
&gBootManagerPrivate.ConfigAccess,
|
|
NULL
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
//
|
|
// Publish our HII data
|
|
//
|
|
gBootManagerPrivate.HiiHandle = HiiAddPackages (
|
|
&gBootManagerFormSetGuid,
|
|
gBootManagerPrivate.DriverHandle,
|
|
BootManagerVfrBin,
|
|
BootManagerDxeStrings,
|
|
BootManagerDxeImages,
|
|
NULL
|
|
);
|
|
if (gBootManagerPrivate.HiiHandle == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
} else {
|
|
Status = EFI_SUCCESS;
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Check the specific BBS Table entry is USB device
|
|
|
|
@param[in] CurrentBbsTable Pointer to current BBS table start address
|
|
|
|
@retval TRUE It is USB device
|
|
@retval FALSE It isn't USB device
|
|
**/
|
|
STATIC
|
|
BOOLEAN
|
|
IsUsbDevice (
|
|
IN BBS_TABLE *CurrentBbsTable
|
|
)
|
|
{
|
|
if ((CurrentBbsTable->Class == PCI_CLASS_SERIAL) &&
|
|
(CurrentBbsTable->SubClass == PCI_CLASS_SERIAL_USB)) {
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
Get prompt string which is consist of the description of EFI boot option and hardware device name
|
|
|
|
@param[in] Option Pointer to boot option data
|
|
@param[in] HwBootDeviceInfo Pointer to the array of hardware device info
|
|
@param[in] HwBootDeviceCount The number of hardware device info
|
|
|
|
@return pointer to the prompt string or NULL if input parameter is invalid
|
|
**/
|
|
CHAR16 *
|
|
GetPromptString (
|
|
IN H2O_BDS_LOAD_OPTION *Option,
|
|
IN HARDWARE_BOOT_DEVICE_INFO *HwBootDeviceInfo,
|
|
IN UINTN HwBootDeviceCount
|
|
)
|
|
{
|
|
CHAR16 NoDeviceStr[] = L"No Device";
|
|
UINTN Index;
|
|
UINT8 *Ptr;
|
|
UINT8 *VarData;
|
|
UINTN DeviceCount;
|
|
UINTN Size;
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
|
CHAR16 *HwDeviceName;
|
|
CHAR16 *PromptString;
|
|
|
|
|
|
if (Option == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
if (!((DevicePathType (Option->DevicePath) == MEDIA_DEVICE_PATH &&
|
|
DevicePathSubType (Option->DevicePath) == MEDIA_HARDDRIVE_DP) ||
|
|
(DevicePathType (Option->DevicePath) == MESSAGING_DEVICE_PATH &&
|
|
DevicePathSubType (Option->DevicePath) == MSG_USB_CLASS_DP))) {
|
|
return AllocateCopyPool (StrSize (Option->Description), Option->Description);
|
|
}
|
|
|
|
VarData = NULL;
|
|
HwDeviceName = NULL;
|
|
DeviceCount = 1;
|
|
DevicePath = Option->DevicePath;
|
|
|
|
if (DevicePathType (Option->DevicePath) == MESSAGING_DEVICE_PATH &&
|
|
DevicePathSubType (Option->DevicePath) == MSG_USB_CLASS_DP) {
|
|
//
|
|
// For Windows To Go, assign no device string as device name if device number is 0.
|
|
//
|
|
VarData = BdsLibGetVariableAndSize (
|
|
L"WindowsToGo",
|
|
&gEfiGenericVariableGuid,
|
|
&Size
|
|
);
|
|
if (VarData != NULL) {
|
|
Ptr = VarData;
|
|
DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr;
|
|
Ptr += GetDevicePathSize (DevicePath);
|
|
DeviceCount = *(UINT16 *) Ptr;
|
|
} else {
|
|
DeviceCount = 0;
|
|
}
|
|
|
|
if (DeviceCount == 0) {
|
|
HwDeviceName = NoDeviceStr;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Append device name to boot option description if BlkIo device path is match.
|
|
//
|
|
if (HwDeviceName == NULL) {
|
|
for (Index = 0; Index < HwBootDeviceCount; Index++) {
|
|
if (BdsLibCompareBlockIoDevicePath (HwBootDeviceInfo[Index].BlockIoDevicePath, DevicePath)) {
|
|
HwDeviceName = HwBootDeviceInfo[Index].HwDeviceName;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (HwDeviceName != NULL) {
|
|
if (DeviceCount > 1) {
|
|
Size = StrSize (Option->Description) + StrSize (L" (") + StrSize (HwDeviceName) + StrSize (L",...") + StrSize (L")");
|
|
} else {
|
|
Size = StrSize (Option->Description) + StrSize (L" (") + StrSize (HwDeviceName) + StrSize (L")");
|
|
}
|
|
PromptString = AllocateZeroPool (Size);
|
|
if (PromptString != NULL) {
|
|
StrCatS (PromptString, Size / sizeof(CHAR16), Option->Description);
|
|
StrCatS (PromptString, Size / sizeof(CHAR16), L" (");
|
|
StrCatS (PromptString, Size / sizeof(CHAR16), HwDeviceName);
|
|
if (DeviceCount > 1) {
|
|
StrCatS (PromptString, Size / sizeof(CHAR16), L",...");
|
|
}
|
|
StrCatS (PromptString, Size / sizeof(CHAR16), L")");
|
|
}
|
|
} else {
|
|
PromptString = AllocateCopyPool (StrSize (Option->Description), Option->Description);
|
|
}
|
|
|
|
if (VarData != NULL) {
|
|
FreePool (VarData);
|
|
}
|
|
|
|
return PromptString;
|
|
}
|
|
|
|
/**
|
|
Update boot option list into HII form.
|
|
**/
|
|
VOID
|
|
UpdateBootOptionListIntoHiiForm (
|
|
VOID
|
|
)
|
|
{
|
|
H2O_BDS_LOAD_OPTION *Option;
|
|
LIST_ENTRY *Link;
|
|
EFI_STRING_ID Token;
|
|
EFI_HII_HANDLE HiiHandle;
|
|
VOID *StartOpCodeHandle;
|
|
VOID *EndOpCodeHandle;
|
|
EFI_IFR_GUID_LABEL *StartLabel;
|
|
EFI_IFR_GUID_LABEL *EndLabel;
|
|
UINT16 DeviceType;
|
|
BOOLEAN IsLegacyOption;
|
|
BOOLEAN NeedEndOp;
|
|
BOOLEAN PreviousOptionIsLegacy;
|
|
UINTN Index;
|
|
HARDWARE_BOOT_DEVICE_INFO *HwBootDeviceInfo;
|
|
UINTN HwBootDeviceCount;
|
|
CHAR16 *PromptString;
|
|
UINT16 OptionDeviceType;
|
|
UINT16 KeyInput;
|
|
UINTN StrIdIndex;
|
|
STATIC EFI_STRING_ID *StrIdRecordList = NULL;
|
|
STATIC UINTN StrIdRecordCount = 0;
|
|
|
|
DeviceType = (UINT16) -1;
|
|
OptionDeviceType = (UINT16) -1;
|
|
HiiHandle = gBootManagerPrivate.HiiHandle;
|
|
|
|
//
|
|
// Create list to record allocated string IDs and reuse these to avoid exhausting string ID.
|
|
//
|
|
for (Link = GetFirstNode (mBootOptionsList), StrIdIndex = 0; !IsNull (mBootOptionsList, Link); Link = GetNextNode (mBootOptionsList, Link), StrIdIndex++);
|
|
if (StrIdIndex > StrIdRecordCount) {
|
|
StrIdRecordList = ReallocatePool (StrIdRecordCount * sizeof(EFI_STRING_ID), StrIdIndex * sizeof(EFI_STRING_ID), StrIdRecordList);
|
|
if (StrIdRecordList == NULL) {
|
|
StrIdRecordCount = 0;
|
|
return;
|
|
}
|
|
StrIdRecordCount = StrIdIndex;
|
|
}
|
|
|
|
BdsLibGetAllHwBootDeviceInfo (&HwBootDeviceCount, &HwBootDeviceInfo);
|
|
|
|
//
|
|
// Allocate space for creation of UpdateData Buffer
|
|
//
|
|
StartOpCodeHandle = HiiAllocateOpCodeHandle ();
|
|
ASSERT (StartOpCodeHandle != NULL);
|
|
|
|
EndOpCodeHandle = HiiAllocateOpCodeHandle ();
|
|
ASSERT (EndOpCodeHandle != NULL);
|
|
|
|
//
|
|
// Create Hii Extend Label OpCode as the start opcode
|
|
//
|
|
StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
|
|
StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
|
|
StartLabel->Number = LABEL_BOOT_OPTION;
|
|
|
|
//
|
|
// Create Hii Extend Label OpCode as the end opcode
|
|
//
|
|
EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
|
|
EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
|
|
EndLabel->Number = LABEL_BOOT_OPTION_END;
|
|
|
|
KeyInput = 0;
|
|
NeedEndOp = FALSE;
|
|
PreviousOptionIsLegacy = TRUE;
|
|
for (Link = GetFirstNode (mBootOptionsList), StrIdIndex = 0; !IsNull (mBootOptionsList, Link); Link = GetNextNode (mBootOptionsList, Link), StrIdIndex++) {
|
|
Option = BDS_OPTION_FROM_LINK (Link);
|
|
//
|
|
// At this stage we are creating a menu entry, thus the Keys are reproduceable
|
|
//
|
|
KeyInput++;
|
|
|
|
//
|
|
// Don't display the hidden/inactive boot option
|
|
//
|
|
if (((Option->Attributes & LOAD_OPTION_HIDDEN) != 0) || ((Option->Attributes & LOAD_OPTION_ACTIVE) == 0)) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Group the legacy boot option in the sub title created dynamically
|
|
//
|
|
IsLegacyOption = IsLegacyBootOption (Option);
|
|
if (IsLegacyOption) {
|
|
if (Option->LoadOptionalDataSize != 0 &&
|
|
IsUsbDevice ((BBS_TABLE *) Option->LoadOptionalData)) {
|
|
OptionDeviceType = BBS_USB;
|
|
} else {
|
|
OptionDeviceType = ((BBS_BBS_DEVICE_PATH *) Option->DevicePath)->DeviceType;
|
|
}
|
|
if (NeedEndOp && (IsLegacyOption != PreviousOptionIsLegacy || DeviceType != OptionDeviceType)) {
|
|
HiiCreateEndOpCode (StartOpCodeHandle);
|
|
}
|
|
if (DeviceType != OptionDeviceType) {
|
|
DeviceType = OptionDeviceType;
|
|
Index = DeviceType & 0xF;
|
|
Token = mDeviceTypeStrId[MIN (Index, sizeof (mDeviceTypeStrId) / sizeof (mDeviceTypeStrId[0]) - 1)];
|
|
HiiCreateSubTitleOpCode (StartOpCodeHandle, Token, 0, 0, 1);
|
|
NeedEndOp = TRUE;
|
|
}
|
|
} else if (IsLegacyOption != PreviousOptionIsLegacy) {
|
|
if (NeedEndOp) {
|
|
HiiCreateEndOpCode (StartOpCodeHandle);
|
|
}
|
|
|
|
HiiCreateSubTitleOpCode (StartOpCodeHandle, STRING_TOKEN (STR_DEVICE_TYPE_EFI), 0, 0, 1);
|
|
NeedEndOp = TRUE;
|
|
}
|
|
|
|
ASSERT (Option->Description != NULL);
|
|
|
|
PromptString = GetPromptString (
|
|
Option,
|
|
HwBootDeviceInfo,
|
|
HwBootDeviceCount
|
|
);
|
|
if (PromptString != NULL) {
|
|
StrIdRecordList[StrIdIndex] = HiiSetString (HiiHandle, StrIdRecordList[StrIdIndex], PromptString, NULL);
|
|
FreePool (PromptString);
|
|
} else {
|
|
StrIdRecordList[StrIdIndex] = HiiSetString (HiiHandle, StrIdRecordList[StrIdIndex], Option->Description, NULL);
|
|
}
|
|
|
|
HiiCreateActionOpCode (
|
|
StartOpCodeHandle,
|
|
KeyInput,
|
|
StrIdRecordList[StrIdIndex],
|
|
0,
|
|
EFI_IFR_FLAG_CALLBACK,
|
|
0
|
|
);
|
|
|
|
PreviousOptionIsLegacy = IsLegacyOption;
|
|
}
|
|
|
|
if (NeedEndOp) {
|
|
HiiCreateEndOpCode (StartOpCodeHandle);
|
|
}
|
|
|
|
HiiUpdateForm (
|
|
HiiHandle,
|
|
&gBootManagerFormSetGuid,
|
|
BOOT_MANAGER_FORM_ID,
|
|
StartOpCodeHandle,
|
|
EndOpCodeHandle
|
|
);
|
|
|
|
HiiFreeOpCodeHandle (StartOpCodeHandle);
|
|
HiiFreeOpCodeHandle (EndOpCodeHandle);
|
|
|
|
if (HwBootDeviceCount != 0 && HwBootDeviceInfo != NULL) {
|
|
for (Index = 0; Index < HwBootDeviceCount; Index++) {
|
|
FreePool (HwBootDeviceInfo[Index].HwDeviceName);
|
|
}
|
|
FreePool (HwBootDeviceInfo);
|
|
}
|
|
}
|
|
|
|
/**
|
|
Update boot option list. If boot option list is changed, update HII form.
|
|
|
|
@retval EFI_SUCCESS Boot option list is changed and updated.
|
|
@retval EFI_ABORTED Boot option list is not changed.
|
|
**/
|
|
EFI_STATUS
|
|
UpdateBootOptionList (
|
|
VOID
|
|
)
|
|
{
|
|
BdsLibEnumerateAllBootOption (FALSE, NULL);
|
|
gBdsServices->GetBootList (gBdsServices, &mBootOptionsList);
|
|
|
|
if (CompareBootOptionList (&mBackupBootOptionsList, mBootOptionsList)) {
|
|
return EFI_ABORTED;
|
|
}
|
|
|
|
FreeBootOptionList (&mBackupBootOptionsList);
|
|
CopyBootOptionList (&mBackupBootOptionsList, mBootOptionsList);
|
|
|
|
UpdateBootOptionListIntoHiiForm ();
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Event function to send hot key callback notify to update boot option list.
|
|
|
|
@param[in] Event The Event this notify function registered to.
|
|
@param[in] Context Pointer to the context data registerd to the Event.
|
|
**/
|
|
STATIC
|
|
VOID
|
|
EFIAPI
|
|
UpdateBootOptionListEvtFunc (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
//
|
|
// Prevent from updating mBootOptionsList causes gOption is invalid, move update list process in callback function.
|
|
//
|
|
SendHotKeyNotify (HotKeyCallback, BOOT_MANAGER_UPDATE_BOOT_LIST_QUESTION_ID);
|
|
}
|
|
|
|
/**
|
|
Perform necessary process before call boot manager.
|
|
**/
|
|
VOID
|
|
InternalCallBootManagerBefore (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
gOption = NULL;
|
|
|
|
//
|
|
// Connect all prior to entering the platform setup menu.
|
|
//
|
|
if (!gConnectAllHappened) {
|
|
BdsLibConnectAllDriversToAllControllers ();
|
|
gConnectAllHappened = TRUE;
|
|
}
|
|
|
|
BdsLibEnumerateAllBootOption (FALSE, NULL);
|
|
Status = gBdsServices->GetBootList (gBdsServices, &mBootOptionsList);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
|
|
CopyBootOptionList (&mBackupBootOptionsList, mBootOptionsList);
|
|
UpdateBootOptionListIntoHiiForm ();
|
|
|
|
if (FeaturePcdGet (PcdH2OBootMgrAutoDetectRemovableBootDevice)) {
|
|
Status = gBS->CreateEvent (
|
|
EVT_TIMER | EVT_NOTIFY_SIGNAL,
|
|
TPL_CALLBACK,
|
|
UpdateBootOptionListEvtFunc,
|
|
NULL,
|
|
&mUpdateBootOptionListEvt
|
|
);
|
|
if (!EFI_ERROR(Status)) {
|
|
Status = gBS->SetTimer (mUpdateBootOptionListEvt, TimerPeriodic, EFI_TIMER_PERIOD_SECONDS(1));
|
|
} else {
|
|
mUpdateBootOptionListEvt = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
Perform necessary process after called boot manager.
|
|
**/
|
|
VOID
|
|
InternalCallBootManagerAfter (
|
|
VOID
|
|
)
|
|
{
|
|
if (mUpdateBootOptionListEvt != NULL) {
|
|
gBS->CloseEvent (mUpdateBootOptionListEvt);
|
|
mUpdateBootOptionListEvt = NULL;
|
|
}
|
|
FreeBootOptionList (&mBackupBootOptionsList);
|
|
}
|
|
|
|
/**
|
|
This function invokes Boot Manager. If all devices have not a chance to be connected,
|
|
the connect all will be triggered. It then enumerate all boot options. If
|
|
a boot option from the Boot Manager page is selected, Boot Manager will boot
|
|
from this boot option.
|
|
|
|
**/
|
|
VOID
|
|
InternalCallBootManager (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
CHAR16 *ExitData;
|
|
UINTN ExitDataSize;
|
|
EFI_HII_HANDLE HiiHandle;
|
|
EFI_BROWSER_ACTION_REQUEST ActionRequest;
|
|
|
|
InternalCallBootManagerBefore ();
|
|
|
|
mBootMgrSendFormBySelf = TRUE;
|
|
HiiHandle = gBootManagerPrivate.HiiHandle;
|
|
ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
|
|
Status = gBootManagerFormBrowser2->SendForm (
|
|
gBootManagerFormBrowser2,
|
|
&HiiHandle,
|
|
1,
|
|
&gBootManagerFormSetGuid,
|
|
0,
|
|
NULL,
|
|
&ActionRequest
|
|
);
|
|
if (ActionRequest == EFI_BROWSER_ACTION_REQUEST_RESET) {
|
|
EnableResetRequired ();
|
|
}
|
|
mBootMgrSendFormBySelf = FALSE;
|
|
|
|
InternalCallBootManagerAfter ();
|
|
if (gOption == NULL) {
|
|
return ;
|
|
}
|
|
|
|
//
|
|
// Will leave browser, check any reset required change is applied? if yes, reset system
|
|
//
|
|
SetupResetReminder ();
|
|
|
|
//
|
|
// Restore to original mode before launching boot option.
|
|
//
|
|
|
|
//
|
|
// parse the selected option
|
|
//
|
|
Status = gBdsServices->LaunchLoadOption (gBdsServices, gOption, &ExitDataSize, &ExitData);
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
BdsLibBootSuccess (gOption);
|
|
} else {
|
|
BdsLibBootFailed (gOption, Status, ExitData, ExitDataSize);
|
|
}
|
|
}
|
|
|
|
/**
|
|
Enter boot manager.
|
|
|
|
@param[in] This Protocol instance pointer.
|
|
@param[in] FilePath The device specific path of the file to load.
|
|
@param[in] BootPolicy If TRUE, indicates that the request originates from the boot manager is attempting to
|
|
load FilePath as a boot selection. If FALSE, then FilePath must match as exact file to be loaded.
|
|
@param[in, out] BufferSize On input the size of Buffer in bytes. On output with a return code of EFI_SUCCESS,
|
|
the amount of data transferred to Buffer. On output with a return code of EFI_BUFFER_TOO_SMALL,
|
|
the size of Buffer required to retrieve the requested file.
|
|
@param[in] Buffer The memory buffer to transfer the file to. IF Buffer is NULL, then no the size of the
|
|
requested file is returned in BufferSize.
|
|
|
|
@retval EFI_NOT_FOUND Always return not found.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
BootManagerLoadFile (
|
|
IN EFI_LOAD_FILE_PROTOCOL *This,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
|
|
IN BOOLEAN BootPolicy,
|
|
IN OUT UINTN *BufferSize,
|
|
IN VOID *Buffer OPTIONAL
|
|
)
|
|
{
|
|
if (gBootManagerPrivate.HiiHandle != NULL) {
|
|
while (TRUE) {
|
|
InternalCallBootManager ();
|
|
if (gOption == NULL) {
|
|
//
|
|
// User presses ESC key to exit boot manager.
|
|
//
|
|
break;
|
|
}
|
|
if (PcdGetBool (PcdH2OBootMgrExitAfterLaunchOption)) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
/**
|
|
Initialize HII data.
|
|
|
|
@param[in] Event A pointer to the Event that triggered the callback.
|
|
@param[in] Handle Checkpoint handle.
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
BootManagerCpInitNotifyFunc (
|
|
IN EFI_EVENT Event,
|
|
IN H2O_CP_HANDLE Handle
|
|
)
|
|
{
|
|
H2OCpUnregisterHandler (Handle);
|
|
InitializeBootManager ();
|
|
}
|
|
|
|
/**
|
|
Register H2OBdsCpInit notification to initialize HII data.
|
|
Install the instance of the EFI_LOAD_FILE_PROTOCOL and EFI_DEVICE_PATH_PROTOCOL on new handle.
|
|
|
|
@param[in] ImageHandle The firmware allocated handle for the EFI image.
|
|
@param[in] SystemTable A pointer to the EFI System Table.
|
|
|
|
@retval EFI_SUCCESS Install protocol successfully.
|
|
@retval other Fail to install protocol instance.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
BootManagerEntry (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
H2O_CP_HANDLE CpHandle;
|
|
EFI_STATUS Status;
|
|
EFI_HANDLE DriverHandle;
|
|
|
|
if (FeaturePcdGet (PcdH2OBdsCpInitSupported)) {
|
|
Status = H2OCpRegisterHandler (
|
|
&gH2OBdsCpInitGuid,
|
|
BootManagerCpInitNotifyFunc,
|
|
H2O_CP_MEDIUM,
|
|
&CpHandle
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG_CP ((DEBUG_ERROR, "Checkpoint Register Fail: %g (%r)\n", &gH2OBdsCpInitGuid, Status));
|
|
return Status;
|
|
}
|
|
DEBUG_CP ((DEBUG_INFO, "Checkpoint Registered: %g (%r)\n", &gH2OBdsCpInitGuid, Status));
|
|
}
|
|
|
|
DriverHandle = NULL;
|
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
|
&DriverHandle,
|
|
&gEfiDevicePathProtocolGuid,
|
|
&gH2OBootManagerDevicePath,
|
|
&gEfiLoadFileProtocolGuid,
|
|
&mBootManagerLoadFile,
|
|
NULL
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
return Status;
|
|
}
|