4242 lines
141 KiB
C
4242 lines
141 KiB
C
/** @file
|
|
Provide H2O BDS service protocol interface
|
|
|
|
;******************************************************************************
|
|
;* Copyright (c) 2014 - 2021, 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.
|
|
;*
|
|
;******************************************************************************
|
|
*/
|
|
|
|
|
|
#include "Bds.h"
|
|
#include "String.h"
|
|
|
|
#define SHELL_ENVIRONMENT_INTERFACE_PROTOCOL \
|
|
{ 0x47c7b221, 0xc42a, 0x11d2, 0x8e, 0x57, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b }
|
|
|
|
#define OPTION_VAR_NAME_BUFFER_CHAR_COUNT 21
|
|
#define OPTION_VAR_NAME_FORMAT_STR L"%s%04x"
|
|
|
|
#define VAR_ATTR_BS_RT (EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS)
|
|
#define VAR_ATTR_BS_RT_NV (VAR_ATTR_BS_RT | EFI_VARIABLE_NON_VOLATILE)
|
|
#define VAR_ATTR_BS_RT_NV_AT (VAR_ATTR_BS_RT_NV | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)
|
|
|
|
typedef struct _H2O_BDS_OPTION_TYPE_INFO {
|
|
UINT8 OptionType;
|
|
LIST_ENTRY OptionList;
|
|
CHAR16 *OrderVarName;
|
|
CHAR16 *OptionVarPrefixName;
|
|
UINT32 VarAttribute;
|
|
} H2O_BDS_OPTION_TYPE_INFO;
|
|
|
|
H2O_BDS_OPTION_TYPE_INFO mOptionTypeInfo[] = {
|
|
{H2O_BDS_LOAD_OPTION_TYPE_DRIVER , {NULL, NULL}, EFI_DRIVER_ORDER_VARIABLE_NAME , L"Driver" , VAR_ATTR_BS_RT_NV },
|
|
{H2O_BDS_LOAD_OPTION_TYPE_BOOT , {NULL, NULL}, EFI_BOOT_ORDER_VARIABLE_NAME , L"Boot" , VAR_ATTR_BS_RT_NV },
|
|
{H2O_BDS_LOAD_OPTION_TYPE_SYSPREP , {NULL, NULL}, EFI_SYS_PREP_ORDER_VARIABLE_NAME, L"SysPrep" , VAR_ATTR_BS_RT_NV },
|
|
{H2O_BDS_LOAD_OPTION_TYPE_OS_RECOVERY , {NULL, NULL}, L"OsRecoveryOrder" , L"OsRecovery" , VAR_ATTR_BS_RT_NV_AT},
|
|
{H2O_BDS_LOAD_OPTION_TYPE_PLATFORM_RECOVERY, {NULL, NULL}, NULL , L"PlatformRecovery", VAR_ATTR_BS_RT },
|
|
};
|
|
|
|
typedef struct _H2O_BDS_ORDER_VAR_INFO {
|
|
UINT16 OptionCount;
|
|
UINT16 *OptionOrder;
|
|
EFI_GUID *OptionVarGuid;
|
|
} H2O_BDS_ORDER_VAR_INFO;
|
|
|
|
STATIC VOID *mShellEnvProtocolCallbackReg;
|
|
STATIC BOOLEAN mNeedSyncBootOrder = TRUE;
|
|
STATIC EFI_GUID mShellEnvProtocol = SHELL_ENVIRONMENT_INTERFACE_PROTOCOL;
|
|
|
|
H2O_BDS_SERVICES_PROTOCOL mH2OBdsServices = {
|
|
sizeof (H2O_BDS_SERVICES_PROTOCOL),
|
|
BdsServicesGetOsIndications,
|
|
BdsServicesGetTimeout,
|
|
BdsServicesGetBootMode,
|
|
BdsServicesGetBootType,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
BdsServicesGetBootList,
|
|
BdsServicesGetDriverList,
|
|
BdsServicesCreateLoadOption,
|
|
BdsServicesFreeLoadOption,
|
|
BdsServicesConvertVarToLoadOption,
|
|
BdsServicesConvertLoadOptionToVar,
|
|
BdsServicesInsertLoadOption,
|
|
BdsServicesRemoveLoadOption,
|
|
BdsServicesExpandLoadOption,
|
|
BdsServicesLaunchLoadOption,
|
|
BdsServicesEnableHotKeys,
|
|
BdsServicesRegisterCallbackHotKey,
|
|
BdsServicesRegisterLoadOptionHotKey,
|
|
BdsServicesUnregisterHotKey,
|
|
BdsServicesGetBootDisplayMode,
|
|
BdsServicesSetHotKeyDescText,
|
|
BdsServicesSetHotKeyDescPosn,
|
|
BdsServicesSetHotKeyDescColor,
|
|
BdsServicesSetHotKeyDescFont,
|
|
BdsServicesGetSysPrepList,
|
|
BdsServicesGetOsRecoveryList,
|
|
BdsServicesGetPlatformRecoveryList,
|
|
BdsServicesCreateLoadOption2,
|
|
BdsServicesInsertLoadOption2,
|
|
BdsServicesRemoveLoadOption2
|
|
};
|
|
|
|
/**
|
|
Frees pool.
|
|
|
|
@param Buffer The allocated pool entry to free.
|
|
**/
|
|
STATIC
|
|
VOID
|
|
InternalFreePool (
|
|
IN VOID *Buffer
|
|
)
|
|
{
|
|
if (Buffer != NULL) {
|
|
FreePool (Buffer);
|
|
}
|
|
}
|
|
|
|
/**
|
|
Internal function to free all of allocated memory in specific H2O_BDS_LOAD_OPTION.
|
|
|
|
@param[in] LoadOption The allocated load option to free.
|
|
**/
|
|
STATIC
|
|
VOID
|
|
InternalFreeBdsLoadOption (
|
|
IN H2O_BDS_LOAD_OPTION *LoadOption
|
|
)
|
|
{
|
|
if (LoadOption == NULL) {
|
|
return;
|
|
}
|
|
InternalFreePool (LoadOption->DevicePath);
|
|
InternalFreePool (LoadOption->Description);
|
|
InternalFreePool (LoadOption->LoadOptionalData);
|
|
InternalFreePool (LoadOption->StatusString);
|
|
FreePool (LoadOption);
|
|
}
|
|
|
|
/**
|
|
Internal function to check the input str is whether a correct #### format. Here the #### is replaced
|
|
by a unique option number in printable hexadecimal representation using the digits 0-9, and the upper
|
|
case versions of the characters A-F (0000-FFFF).
|
|
|
|
@param[in] Str Input #### string to be checked.
|
|
|
|
@retval TRUE The input string is correct #### format.
|
|
@retval FALSE The input string is incorrect #### format.
|
|
**/
|
|
STATIC
|
|
BOOLEAN
|
|
IsValidOptionNumber (
|
|
IN CONST CHAR16 *Str
|
|
)
|
|
{
|
|
UINTN Index;
|
|
|
|
if (Str == NULL || StrLen (Str) != 4) {
|
|
return FALSE;
|
|
}
|
|
|
|
for (Index = 0; Str[Index] != 0; Index++) {
|
|
if (!((Str[Index] >= L'0' && Str[Index] <= L'9') || (Str[Index] >= L'A' && Str[Index] <= L'F'))) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
Check if the BDS load option is a valid.
|
|
|
|
@param[in] BdsLoadOption Pointer to BDS load option.
|
|
|
|
@retval TRUE The input BDS load option is valid.
|
|
@retval FALSE The input BDS load option is not valid.
|
|
**/
|
|
STATIC
|
|
BOOLEAN
|
|
IsValidLoadOption (
|
|
IN CONST H2O_BDS_LOAD_OPTION *BdsLoadOption
|
|
)
|
|
{
|
|
if (BdsLoadOption == NULL ||
|
|
BdsLoadOption->Signature != H2O_BDS_LOAD_OPTION_SIGNATURE ||
|
|
BdsLoadOption->OptionType >= H2O_BDS_LOAD_OPTION_TYPE_MAX) {
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
Check if the input BDS load option match with input load order and variable GUID.
|
|
|
|
@param[in] LoadOption Pointer to BDS load option.
|
|
@param[in] LoadOrder Load order number.
|
|
@param[in] LoadOrderVarGuid Pointer to variable GUID.
|
|
|
|
@retval TRUE The input BDS load option match with input load order and variable GUID.
|
|
@retval FALSE The input BDS load option does not match with input load order and variable GUID or input parameter is NULL.
|
|
**/
|
|
STATIC
|
|
BOOLEAN
|
|
IsLoadOptionMatch (
|
|
IN CONST H2O_BDS_LOAD_OPTION *LoadOption,
|
|
IN UINT16 LoadOrder,
|
|
IN CONST EFI_GUID *LoadOrderVarGuid
|
|
)
|
|
{
|
|
if (LoadOption == NULL || LoadOrderVarGuid == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (LoadOption->LoadOrder == LoadOrder &&
|
|
CompareGuid (&LoadOption->LoadOrderVarGuid, LoadOrderVarGuid)) {
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
Get BDS load option type info.
|
|
|
|
@param[in] OptionType BDS load option type
|
|
|
|
@return A pointer to the BDS load option type info or NULL if not found.
|
|
**/
|
|
STATIC
|
|
H2O_BDS_OPTION_TYPE_INFO *
|
|
GetOptionTypeInfo (
|
|
IN UINT8 OptionType
|
|
)
|
|
{
|
|
UINTN Index;
|
|
|
|
for (Index = 0; Index < sizeof (mOptionTypeInfo) / sizeof (H2O_BDS_OPTION_TYPE_INFO); Index++) {
|
|
if (mOptionTypeInfo[Index].OptionType == OptionType) {
|
|
return &mOptionTypeInfo[Index];
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
Internal function to calculate UINT16 value from input #### string.
|
|
|
|
@param[in] Str Input #### string to be calculated.
|
|
|
|
@return The UINT16 value which calculate from input string.
|
|
**/
|
|
STATIC
|
|
UINT16
|
|
GetOptionNumber (
|
|
IN CONST CHAR16 *Str
|
|
)
|
|
{
|
|
UINTN Index;
|
|
UINT16 Number;
|
|
|
|
if (Str == NULL || StrLen (Str) != 4) {
|
|
return 0;
|
|
}
|
|
|
|
Number = 0;
|
|
for (Index = 0; Str[Index] != 0; Index++) {
|
|
if (Str[Index] >= L'0' && Str[Index] <= L'9') {
|
|
Number = Number * 0x10 + Str[Index] - L'0';
|
|
} else if (Str[Index] >= L'A' && Str[Index] <= L'F') {
|
|
Number = Number * 0x10 + Str[Index] - L'A' + 0x0A;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
return Number;
|
|
}
|
|
|
|
/**
|
|
Enumerate all option variable which variable name match the input option prefix name.
|
|
The output option number list is organized in order.
|
|
|
|
@param[in] OptionPrefixName A pointer to option variable prefix name.
|
|
@param[out] OptionCount A pointer to output option count.
|
|
@param[out] OptionNumList A pointer to output option number list.
|
|
@param[out] OptionGuidList A pointer to output option variable GUID list.
|
|
|
|
@retval EFI_SUCCESS Enumerate all option variable successfully.
|
|
@retval EFI_INVALID_PARAMETER Input parameter is NULL.
|
|
@retval EFI_OUT_OF_RESOURCES Allocate memory failed.
|
|
@retval EFI_NOT_FOUND There is no option variable which name match the input prefix name.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
EnumerateAllOptionVar (
|
|
IN CONST CHAR16 *OptionPrefixName,
|
|
OUT UINT16 *OptionCount,
|
|
OUT UINT16 **OptionNumList,
|
|
OUT EFI_GUID **OptionGuidList
|
|
)
|
|
{
|
|
UINTN OptionPrefixNameLen;
|
|
CHAR16 *VarName;
|
|
UINTN VarNameSize;
|
|
UINTN VarNameBufSize;
|
|
UINTN VarNameLen;
|
|
UINT16 *NumList;
|
|
EFI_GUID *GuidList;
|
|
EFI_GUID Guid;
|
|
UINT16 Count;
|
|
EFI_STATUS Status;
|
|
UINT16 OptionNum;
|
|
UINT16 Index;
|
|
|
|
|
|
if (OptionPrefixName == NULL || OptionCount == NULL || OptionNumList == NULL || OptionGuidList == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
VarNameBufSize = 50 * sizeof (CHAR16);
|
|
VarName = AllocateZeroPool (VarNameBufSize);
|
|
if (VarName == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
OptionPrefixNameLen = StrLen (OptionPrefixName);
|
|
|
|
//
|
|
// Enumerate all option variables which variable name matches the input option prefix name.
|
|
//
|
|
Count = 0;
|
|
NumList = NULL;
|
|
GuidList = NULL;
|
|
while (TRUE) {
|
|
VarNameSize = VarNameBufSize;
|
|
Status = gRT->GetNextVariableName (&VarNameSize, VarName, &Guid);
|
|
if (Status == EFI_BUFFER_TOO_SMALL) {
|
|
VarName = ReallocatePool (VarNameBufSize, VarNameSize, VarName);
|
|
if (VarName == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
VarNameBufSize = VarNameSize;
|
|
Status = gRT->GetNextVariableName (&VarNameSize, VarName, &Guid);
|
|
}
|
|
if (EFI_ERROR (Status)) {
|
|
break;
|
|
}
|
|
|
|
VarNameLen = (VarNameSize <= sizeof (CHAR16)) ? 0 : (VarNameSize / sizeof (CHAR16) - 1);
|
|
|
|
if (VarNameLen != OptionPrefixNameLen + 4 ||
|
|
StrnCmp (VarName, OptionPrefixName, OptionPrefixNameLen) != 0 ||
|
|
!IsValidOptionNumber (&VarName[OptionPrefixNameLen])) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Add option number into list in numeric order.
|
|
//
|
|
OptionNum = GetOptionNumber (&VarName[OptionPrefixNameLen]);
|
|
|
|
for (Index = 0; Index < Count; Index++) {
|
|
if (NumList[Index] > OptionNum) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
NumList = ReallocatePool (Count * sizeof (UINT16) , (Count + 1) * sizeof (UINT16) , NumList);
|
|
GuidList = ReallocatePool (Count * sizeof (EFI_GUID), (Count + 1) * sizeof (EFI_GUID), GuidList);
|
|
if (NumList == NULL || GuidList == NULL) {
|
|
FreePool (VarName);
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
CopyMem (&NumList[Index + 1] , &NumList[Index] , (Count - Index) * sizeof (UINT16));
|
|
CopyMem (&GuidList[Index + 1], &GuidList[Index], (Count - Index) * sizeof (EFI_GUID));
|
|
NumList[Index] = OptionNum;
|
|
CopyGuid (&GuidList[Index], &Guid);
|
|
Count++;
|
|
}
|
|
FreePool (VarName);
|
|
|
|
if (Count == 0) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
*OptionCount = Count;
|
|
*OptionNumList = NumList;
|
|
*OptionGuidList = GuidList;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Set OS recovery order variable.
|
|
|
|
@param[in] OrderVarInfo A pointer to order variable info.
|
|
|
|
@retval EFI_SUCCESS Set OS recovery order variable successfully.
|
|
@retval EFI_INVALID_PARAMETER OrderVarInfo is NULL.
|
|
@retval EFI_UNSUPPORTED Failed to find OS recovery info.
|
|
@retval Other Failed to set variable.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
OsRecoverySetOrderVar (
|
|
IN CONST H2O_BDS_ORDER_VAR_INFO *OrderVarInfo
|
|
)
|
|
{
|
|
H2O_BDS_OPTION_TYPE_INFO *OptionTypeInfo;
|
|
UINTN OptionIndex;
|
|
UINTN Index;
|
|
EFI_GUID *OptionVarGuid;
|
|
EFI_GUID *VendorGuidOrder;
|
|
UINTN VendorGuidOrderCount;
|
|
EFI_STATUS Status;
|
|
|
|
if (OrderVarInfo == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
OptionTypeInfo = GetOptionTypeInfo (H2O_BDS_LOAD_OPTION_TYPE_OS_RECOVERY);
|
|
if (OptionTypeInfo == NULL) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
VendorGuidOrder = OrderVarInfo->OptionCount == 0 ? NULL : AllocateZeroPool (OrderVarInfo->OptionCount * sizeof (EFI_GUID));
|
|
if (VendorGuidOrder == NULL && OrderVarInfo->OptionCount != 0) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
VendorGuidOrderCount = 0;
|
|
for (OptionIndex = 0; OptionIndex < OrderVarInfo->OptionCount; OptionIndex++) {
|
|
OptionVarGuid = &OrderVarInfo->OptionVarGuid[OptionIndex];
|
|
|
|
for (Index = 0; Index < VendorGuidOrderCount; Index++) {
|
|
if (CompareGuid (&VendorGuidOrder[Index], OptionVarGuid)) {
|
|
break;
|
|
}
|
|
}
|
|
if (Index != VendorGuidOrderCount) {
|
|
continue;
|
|
}
|
|
|
|
CopyGuid (&VendorGuidOrder[VendorGuidOrderCount], OptionVarGuid);
|
|
VendorGuidOrderCount++;
|
|
}
|
|
|
|
Status = CommonSetVariable (
|
|
OptionTypeInfo->OrderVarName,
|
|
&gEfiGlobalVariableGuid,
|
|
OptionTypeInfo->VarAttribute,
|
|
sizeof (EFI_GUID) * VendorGuidOrderCount,
|
|
VendorGuidOrder
|
|
);
|
|
|
|
InternalFreePool (VendorGuidOrder);
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Get the order variable info of OS recovery option.
|
|
|
|
@param[out] OrderVarInfo A pointer to order variable info.
|
|
|
|
@retval EFI_SUCCESS Get the order variable info of OS recovery option successfully.
|
|
@retval EFI_INVALID_PARAMETER Input parameter is NULL.
|
|
@retval EFI_OUT_OF_RESOURCES Allocate memory failed.
|
|
@retval EFI_UNSUPPORTED Fail to find OS recovery info.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
OsRecoveryGetOrderVarInfo (
|
|
OUT H2O_BDS_ORDER_VAR_INFO *OrderVarInfo
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT16 OptionCount;
|
|
UINT16 *OptionNumList;
|
|
EFI_GUID *OptionGuidList;
|
|
UINT16 Index;
|
|
UINT16 Count;
|
|
UINT16 *Order;
|
|
EFI_GUID *GuidList;
|
|
UINT16 GuidIndex;
|
|
EFI_GUID *VendorGuidOrder;
|
|
UINTN VendorGuidOrderSize;
|
|
UINTN VendorGuidCount;
|
|
H2O_BDS_OPTION_TYPE_INFO *OptionTypeInfo;
|
|
|
|
if (OrderVarInfo == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
OptionTypeInfo = GetOptionTypeInfo (H2O_BDS_LOAD_OPTION_TYPE_OS_RECOVERY);
|
|
if (OptionTypeInfo == NULL) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
Count = 0;
|
|
Order = NULL;
|
|
GuidList = NULL;
|
|
|
|
VendorGuidOrder = NULL;
|
|
Status = CommonGetVariableDataAndSize (
|
|
OptionTypeInfo->OrderVarName,
|
|
&gEfiGlobalVariableGuid,
|
|
&VendorGuidOrderSize,
|
|
(VOID **) &VendorGuidOrder
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Done;
|
|
}
|
|
|
|
Status = EnumerateAllOptionVar (
|
|
OptionTypeInfo->OptionVarPrefixName,
|
|
&OptionCount,
|
|
&OptionNumList,
|
|
&OptionGuidList
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// Sort option number by vendor GUID order
|
|
//
|
|
VendorGuidCount = VendorGuidOrderSize / sizeof (EFI_GUID);
|
|
|
|
for (GuidIndex = 0; GuidIndex < VendorGuidCount; GuidIndex++) {
|
|
for (Index = 0; Index < OptionCount; Index++) {
|
|
if (!CompareGuid (&OptionGuidList[Index], VendorGuidOrder + GuidIndex)) {
|
|
continue;
|
|
}
|
|
|
|
Order = ReallocatePool (Count * sizeof (UINT16) , (Count + 1) * sizeof (UINT16) , Order);
|
|
GuidList = ReallocatePool (Count * sizeof (EFI_GUID), (Count + 1) * sizeof (EFI_GUID), GuidList);
|
|
if (Order == NULL || GuidList == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
Order[Count] = OptionNumList[Index];
|
|
CopyGuid (&GuidList[Count], &OptionGuidList[Index]);
|
|
Count++;
|
|
}
|
|
}
|
|
InternalFreePool (OptionNumList);
|
|
InternalFreePool (OptionGuidList);
|
|
|
|
Done:
|
|
InternalFreePool (VendorGuidOrder);
|
|
|
|
OrderVarInfo->OptionCount = Count;
|
|
OrderVarInfo->OptionOrder = Order;
|
|
OrderVarInfo->OptionVarGuid = GuidList;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Get the order variable info of platform recovery option.
|
|
|
|
@param[out] OrderVarInfo A pointer to the order variable info.
|
|
|
|
@retval EFI_SUCCESS Get the order variable info of platform recovery option successfully.
|
|
@retval EFI_INVALID_PARAMETER Input parameter is NULL.
|
|
@retval EFI_UNSUPPORTED Fail to find platform recovery info.
|
|
@retval EFI_OUT_OF_RESOURCES Allocate memory failed.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
PlatformRecoveryGetOrderVarInfo (
|
|
OUT H2O_BDS_ORDER_VAR_INFO *OrderVarInfo
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT16 OptionCount;
|
|
UINT16 *OptionNumList;
|
|
EFI_GUID *OptionGuidList;
|
|
UINT16 Index;
|
|
UINT16 Count;
|
|
UINT16 *Order;
|
|
EFI_GUID *GuidList;
|
|
H2O_BDS_OPTION_TYPE_INFO *OptionTypeInfo;
|
|
|
|
if (OrderVarInfo == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
OptionTypeInfo = GetOptionTypeInfo (H2O_BDS_LOAD_OPTION_TYPE_PLATFORM_RECOVERY);
|
|
if (OptionTypeInfo == NULL) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
Count = 0;
|
|
Order = NULL;
|
|
GuidList = NULL;
|
|
|
|
Status = EnumerateAllOptionVar (
|
|
OptionTypeInfo->OptionVarPrefixName,
|
|
&OptionCount,
|
|
&OptionNumList,
|
|
&OptionGuidList
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Done;
|
|
}
|
|
|
|
for (Index = 0; Index < OptionCount; Index++) {
|
|
if (!CompareGuid (&OptionGuidList[Index], &gEfiGlobalVariableGuid)) {
|
|
continue;
|
|
}
|
|
|
|
Order = ReallocatePool (Count * sizeof (UINT16) , (Count + 1) * sizeof (UINT16) , Order);
|
|
GuidList = ReallocatePool (Count * sizeof (EFI_GUID), (Count + 1) * sizeof (EFI_GUID), GuidList);
|
|
if (Order == NULL || GuidList == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
Order[Count] = OptionNumList[Index];
|
|
CopyGuid (&GuidList[Count], &gEfiGlobalVariableGuid);
|
|
Count++;
|
|
}
|
|
InternalFreePool (OptionNumList);
|
|
InternalFreePool (OptionGuidList);
|
|
|
|
Done:
|
|
OrderVarInfo->OptionCount = Count;
|
|
OrderVarInfo->OptionOrder = Order;
|
|
OrderVarInfo->OptionVarGuid = GuidList;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Free the order variable info.
|
|
|
|
@param[in, out] OrderVarInfo A pointer to the order variable info.
|
|
**/
|
|
STATIC
|
|
VOID
|
|
FreeOrderVarInfo (
|
|
IN OUT H2O_BDS_ORDER_VAR_INFO *OrderVarInfo
|
|
)
|
|
{
|
|
if (OrderVarInfo == NULL) {
|
|
return;
|
|
}
|
|
InternalFreePool (OrderVarInfo->OptionOrder);
|
|
InternalFreePool (OrderVarInfo->OptionVarGuid);
|
|
ZeroMem (OrderVarInfo, sizeof (H2O_BDS_ORDER_VAR_INFO));
|
|
}
|
|
|
|
/**
|
|
Get the order variable info by specific option type.
|
|
|
|
@param[in] OptionType Option type value.
|
|
@param[out] OrderVarInfo A pointer to output order variable info.
|
|
|
|
@retval EFI_SUCCESS Get the order variable info successfully.
|
|
@retval EFI_INVALID_PARAMETER Input parameter is NULL.
|
|
@retval EFI_UNSUPPORTED Fail to find option type info.
|
|
@retval Other Failed to get order variable info.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
GetOrderVarInfo (
|
|
IN UINT8 OptionType,
|
|
OUT H2O_BDS_ORDER_VAR_INFO *OrderVarInfo
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN Index;
|
|
UINTN OptionOrderSize;
|
|
UINT16 *OptionOrder;
|
|
H2O_BDS_OPTION_TYPE_INFO *OptionTypeInfo;
|
|
|
|
if (OrderVarInfo == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
switch (OptionType) {
|
|
|
|
case H2O_BDS_LOAD_OPTION_TYPE_OS_RECOVERY:
|
|
Status = OsRecoveryGetOrderVarInfo (OrderVarInfo);
|
|
break;
|
|
|
|
case H2O_BDS_LOAD_OPTION_TYPE_PLATFORM_RECOVERY:
|
|
Status = PlatformRecoveryGetOrderVarInfo (OrderVarInfo);
|
|
break;
|
|
|
|
case H2O_BDS_LOAD_OPTION_TYPE_DRIVER:
|
|
case H2O_BDS_LOAD_OPTION_TYPE_BOOT:
|
|
case H2O_BDS_LOAD_OPTION_TYPE_SYSPREP:
|
|
OptionTypeInfo = GetOptionTypeInfo (OptionType);
|
|
if (OptionTypeInfo == NULL) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
Status = CommonGetVariableDataAndSize (
|
|
OptionTypeInfo->OrderVarName,
|
|
&gEfiGlobalVariableGuid,
|
|
&OptionOrderSize,
|
|
(VOID **) &OptionOrder
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
Status = EFI_SUCCESS;
|
|
OptionOrderSize = 0;
|
|
OptionOrder = NULL;
|
|
}
|
|
|
|
OrderVarInfo->OptionCount = (UINT16) (OptionOrderSize / sizeof (UINT16));
|
|
OrderVarInfo->OptionOrder = OptionOrder;
|
|
OrderVarInfo->OptionVarGuid = OrderVarInfo->OptionCount == 0 ? NULL : AllocatePool (OrderVarInfo->OptionCount * sizeof (EFI_GUID));
|
|
if (OrderVarInfo->OptionVarGuid != NULL) {
|
|
for (Index = 0; Index < OrderVarInfo->OptionCount; Index++) {
|
|
CopyGuid (&OrderVarInfo->OptionVarGuid[Index], &gEfiGlobalVariableGuid);
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Based on input order variable info, update order variable.
|
|
|
|
@param[in] OptionType Option type value.
|
|
@param[in] OrderVarInfo A pointer to order variable info.
|
|
|
|
@retval EFI_SUCCESS Update order variable successfully.
|
|
@retval EFI_INVALID_PARAMETER Input parameter is NULL.
|
|
@retval EFI_UNSUPPORTED Fail to find option type info.
|
|
@retval Other Failed to set variable.
|
|
**/
|
|
EFI_STATUS
|
|
SetOrderVar (
|
|
IN UINT8 OptionType,
|
|
IN CONST H2O_BDS_ORDER_VAR_INFO *OrderVarInfo
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
H2O_BDS_OPTION_TYPE_INFO *OptionTypeInfo;
|
|
|
|
if (OrderVarInfo == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
switch (OptionType) {
|
|
|
|
case H2O_BDS_LOAD_OPTION_TYPE_OS_RECOVERY:
|
|
Status = OsRecoverySetOrderVar (OrderVarInfo);
|
|
break;
|
|
|
|
case H2O_BDS_LOAD_OPTION_TYPE_DRIVER:
|
|
case H2O_BDS_LOAD_OPTION_TYPE_BOOT:
|
|
case H2O_BDS_LOAD_OPTION_TYPE_SYSPREP:
|
|
OptionTypeInfo = GetOptionTypeInfo (OptionType);
|
|
if (OptionTypeInfo == NULL) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
Status = CommonSetVariable (
|
|
OptionTypeInfo->OrderVarName,
|
|
&gEfiGlobalVariableGuid,
|
|
OptionTypeInfo->VarAttribute,
|
|
OrderVarInfo->OptionCount * sizeof (UINT16),
|
|
OrderVarInfo->OptionOrder
|
|
);
|
|
break;
|
|
|
|
case H2O_BDS_LOAD_OPTION_TYPE_PLATFORM_RECOVERY:
|
|
//
|
|
// There is no PlatformRecoveryOrder variable, because order is determined by #### of PlatformRecovery#### variable.
|
|
//
|
|
default:
|
|
Status = EFI_UNSUPPORTED;
|
|
break;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
According to variable name and GUID to Determine the variable is BootPerv or not.
|
|
|
|
@param[in] VariableName Name of Variable to be found.
|
|
@param[in] VendorGuid Variable vendor GUID.
|
|
|
|
@retval TRUE This is BootPerv variable.
|
|
@retval FALSE This isn't BootPerv variable.
|
|
**/
|
|
STATIC
|
|
BOOLEAN
|
|
IsBootPreviousVariable (
|
|
IN CONST CHAR16 *VariableName,
|
|
IN CONST EFI_GUID *VendorGuid
|
|
)
|
|
{
|
|
if (VariableName != NULL && VendorGuid != NULL) {
|
|
if (StrCmp (VariableName, H2O_BOOT_PREVIOUS_VARIABLE_NAME) == 0 && CompareGuid (VendorGuid, &gEfiGenericVariableGuid)) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
According to variable name and GUID to Determine the variable is BootCurrent or not.
|
|
|
|
@param[in] VariableName Name of Variable to be found.
|
|
@param[in] VendorGuid Variable vendor GUID.
|
|
|
|
@retval TRUE This is BootCurrent variable.
|
|
@retval FALSE This isn't BootCurrent variable.
|
|
**/
|
|
STATIC
|
|
BOOLEAN
|
|
IsBootCurrentVariable (
|
|
IN CONST CHAR16 *VariableName,
|
|
IN CONST EFI_GUID *VendorGuid
|
|
)
|
|
{
|
|
if (VariableName != NULL && VendorGuid != NULL) {
|
|
if (StrCmp (VariableName, EFI_BOOT_CURRENT_VARIABLE_NAME) == 0 && CompareGuid (VendorGuid, &gEfiGlobalVariableGuid)) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
According to variable name and GUID to Determine the variable is BootNext or not.
|
|
|
|
@param[in] VariableName Name of Variable to be found.
|
|
@param[in] VendorGuid Variable vendor GUID.
|
|
|
|
@retval TRUE This is BootNext variable.
|
|
@retval FALSE This isn't BootNext variable.
|
|
**/
|
|
STATIC
|
|
BOOLEAN
|
|
IsBootNextVariable (
|
|
IN CONST CHAR16 *VariableName,
|
|
IN CONST EFI_GUID *VendorGuid
|
|
)
|
|
{
|
|
if (VariableName != NULL && VendorGuid != NULL) {
|
|
if (StrCmp (VariableName, EFI_BOOT_NEXT_VARIABLE_NAME) == 0 && CompareGuid (VendorGuid, &gEfiGlobalVariableGuid)) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
Internal function to insert load option to load option list.
|
|
|
|
@param[in] BdsLoadOption Load option want to insert to load option list.
|
|
@param[in] OrderVarInfo Pointer to order variable info.
|
|
@param[in] InsertOptionIndex Order index of inserted load option.
|
|
|
|
@retval EFI_SUCCESS Insert load option to load option list successfully.
|
|
@retval EFI_INVALID_PARAMETER BdsLoadOption is NULL, OrderVarInfo is NULL.
|
|
@retval EFI_UNSUPPORTED Fail to find option type info.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
InsertLoadOptionToList (
|
|
IN H2O_BDS_LOAD_OPTION *BdsLoadOption,
|
|
IN CONST H2O_BDS_ORDER_VAR_INFO *OrderVarInfo,
|
|
IN UINTN InsertOptionIndex
|
|
)
|
|
{
|
|
LIST_ENTRY *OptionList;
|
|
LIST_ENTRY *CurrentList;
|
|
LIST_ENTRY *NextList;
|
|
UINTN Index;
|
|
H2O_BDS_LOAD_OPTION *CurrentLoadOption;
|
|
H2O_BDS_OPTION_TYPE_INFO *OptionTypeInfo;
|
|
|
|
|
|
if (BdsLoadOption == NULL || OrderVarInfo == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
OptionTypeInfo = GetOptionTypeInfo (BdsLoadOption->OptionType);
|
|
if (OptionTypeInfo == NULL) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
OptionList = &OptionTypeInfo->OptionList;
|
|
|
|
if (IsListEmpty (OptionList)) {
|
|
InsertTailList (OptionList, &BdsLoadOption->Link);
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
CurrentList = GetFirstNode (OptionList);
|
|
for (Index = 0; Index < InsertOptionIndex && Index < OrderVarInfo->OptionCount; Index++) {
|
|
if (IsNull (OptionList, CurrentList)) {
|
|
break;
|
|
}
|
|
CurrentLoadOption = BDS_OPTION_FROM_LINK (CurrentList);
|
|
if (IsLoadOptionMatch (CurrentLoadOption, OrderVarInfo->OptionOrder[Index], &OrderVarInfo->OptionVarGuid[Index])) {
|
|
CurrentList = GetNextNode (OptionList, CurrentList);
|
|
}
|
|
}
|
|
|
|
if (CurrentList != OptionList) {
|
|
CurrentLoadOption = BDS_OPTION_FROM_LINK (CurrentList);
|
|
if (IsLoadOptionMatch (CurrentLoadOption, BdsLoadOption->LoadOrder, &BdsLoadOption->LoadOrderVarGuid)) {
|
|
NextList = GetNextNode (OptionList, CurrentList);
|
|
RemoveEntryList (&CurrentLoadOption->Link);
|
|
BdsServicesFreeLoadOption (&mH2OBdsServices, CurrentLoadOption);
|
|
CurrentList = NextList;
|
|
}
|
|
}
|
|
|
|
InsertTailList (CurrentList, &BdsLoadOption->Link);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Internal function to check the input device path is whether a legacy boot option device path.
|
|
|
|
@param[in] DevicePath A pointer to a device path data structure.
|
|
|
|
@retval TRUE This is a legacy boot option.
|
|
@retval FALSE This isn't a legacy boot option.
|
|
**/
|
|
STATIC
|
|
BOOLEAN
|
|
IsLegacyBootOption (
|
|
IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath
|
|
)
|
|
{
|
|
if (DevicePath == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
if ((BBS_DEVICE_PATH == DevicePath->Type) && (BBS_BBS_DP == DevicePath->SubType)) {
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
Internal function to check the input device is whether in expanded option list.
|
|
|
|
@param[in] BdsLoadOption Load option want to insert to load option list.
|
|
@param[in] DevicePath A pointer to a device path data structure.
|
|
|
|
@retval TRUE The device path is already in expanded option list
|
|
@retval FALSE The device path isn't in expanded option list
|
|
**/
|
|
STATIC
|
|
BOOLEAN
|
|
IsInExpandedLoadOptions (
|
|
IN H2O_BDS_LOAD_OPTION *BdsLoadOption,
|
|
IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath
|
|
)
|
|
{
|
|
LIST_ENTRY *ExpandedOptions;
|
|
LIST_ENTRY *Link;
|
|
H2O_BDS_LOAD_OPTION *CurrentLoadOption;
|
|
|
|
if (BdsLoadOption == NULL || !BdsLoadOption->Expanded || DevicePath == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
ExpandedOptions = &BdsLoadOption->ExpandedLoadOptions;
|
|
for (Link = GetFirstNode (ExpandedOptions); !IsNull (ExpandedOptions, Link); Link = GetNextNode (ExpandedOptions, Link)) {
|
|
CurrentLoadOption = BDS_OPTION_FROM_LINK (Link);
|
|
if (GetDevicePathSize (DevicePath) == GetDevicePathSize (CurrentLoadOption->DevicePath) &&
|
|
CompareMem (DevicePath, CurrentLoadOption->DevicePath, GetDevicePathSize (DevicePath)) == 0) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
Internal function to add expanded load option to expand option list.
|
|
|
|
@param[in] BdsLoadOption Load option want to insert to load option list.
|
|
|
|
@retval EFI_SUCCESS Add expaanded load option to option list successfully.
|
|
@retval EFI_INVALID_PARAMETER BdsLoadOption is NULL.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
AddExpandedWindowsToGoOption (
|
|
IN OUT H2O_BDS_LOAD_OPTION *BdsLoadOption
|
|
)
|
|
{
|
|
UINTN Index;
|
|
UINTN NumberFileSystemHandles;
|
|
EFI_HANDLE *FileSystemHandles;
|
|
H2O_BDS_LOAD_OPTION *NewLoadOption;
|
|
EFI_STATUS Status;
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
|
|
|
if (BdsLoadOption == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Status = gBS->LocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiSimpleFileSystemProtocolGuid,
|
|
NULL,
|
|
&NumberFileSystemHandles,
|
|
&FileSystemHandles
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
for (Index = 0; Index < NumberFileSystemHandles; Index++) {
|
|
DevicePath = DevicePathFromHandle (FileSystemHandles[Index]);
|
|
if (IsWindowsToGo (FileSystemHandles[Index]) && !IsInExpandedLoadOptions (BdsLoadOption, DevicePath)) {
|
|
Status = BdsServicesCreateLoadOption (
|
|
&mH2OBdsServices,
|
|
BOOT_OPTION,
|
|
BDS_OPTION_HAVE_LOAD_ORDER_VAR_NAME(BdsLoadOption) ? BdsLoadOption->LoadOrderVarName : NULL,
|
|
BDS_OPTION_HAVE_LOAD_ORDER_VAR_NAME(BdsLoadOption) ? &BdsLoadOption->LoadOrderVarGuid : NULL,
|
|
LOAD_OPTION_ACTIVE,
|
|
DevicePath,
|
|
BdsLoadOption->Description,
|
|
BdsLoadOption->LoadOptionalData,
|
|
BdsLoadOption->LoadOptionalDataSize,
|
|
&NewLoadOption
|
|
);
|
|
if (Status == EFI_SUCCESS) {
|
|
InsertTailList (&BdsLoadOption->ExpandedLoadOptions, &NewLoadOption->Link);
|
|
}
|
|
}
|
|
}
|
|
InternalFreePool (FileSystemHandles);
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Internal function to check the input device is whether in input device path array.
|
|
|
|
@param[in] DevicePath A Pointer to a UEFI device path.
|
|
@param[in] DevicePaths A Pointer to a UEFI device path array.
|
|
@param[in] DevicePathCount The device path count in device path array.
|
|
|
|
@retval TRUE Device path is in device path array.
|
|
@retval FALSE Device path isn't in device path array.
|
|
**/
|
|
STATIC
|
|
BOOLEAN
|
|
IsDevicePathInArray (
|
|
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
|
|
IN EFI_DEVICE_PATH_PROTOCOL **DevicePaths,
|
|
IN UINTN DevicePathCount
|
|
)
|
|
{
|
|
UINTN Index;
|
|
|
|
if (DevicePath == NULL || DevicePaths == NULL || DevicePathCount == 0) {
|
|
return FALSE;
|
|
}
|
|
|
|
for (Index = 0; Index < DevicePathCount; Index++) {
|
|
if (GetDevicePathSize (DevicePath) == GetDevicePathSize (DevicePaths[Index]) &&
|
|
CompareMem (DevicePath, DevicePaths[Index], GetDevicePathSize (DevicePath)) == 0) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
Internal function to remove redundant boot option in expanded list.
|
|
|
|
@param[in] BdsLoadOption Load option want to insert to load option list.
|
|
|
|
@retval EFI_SUCCESS Remove redundant boot option successfully.
|
|
@retval EFI_INVALID_PARAMETER BdsLoadOption is NULL.
|
|
@retval EFI_OUT_OF_RESOURCES Unable to allocate memory to store device path.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
RemoveRedundantExpandedWindowsToGoOption (
|
|
IN OUT H2O_BDS_LOAD_OPTION *BdsLoadOption
|
|
)
|
|
{
|
|
UINTN Index;
|
|
UINTN NumberFileSystemHandles;
|
|
EFI_HANDLE *FileSystemHandles;
|
|
H2O_BDS_LOAD_OPTION *CurrentLoadOption;
|
|
EFI_STATUS Status;
|
|
EFI_DEVICE_PATH_PROTOCOL **DevicePaths;
|
|
LIST_ENTRY *ExpandedOptions;
|
|
LIST_ENTRY *Link;
|
|
LIST_ENTRY *CurrentLink;
|
|
|
|
if (BdsLoadOption == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Status = gBS->LocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiSimpleFileSystemProtocolGuid,
|
|
NULL,
|
|
&NumberFileSystemHandles,
|
|
&FileSystemHandles
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
DevicePaths = AllocateZeroPool (NumberFileSystemHandles * sizeof (EFI_DEVICE_PATH_PROTOCOL *));
|
|
if (DevicePaths == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
for (Index = 0; Index < NumberFileSystemHandles; Index++) {
|
|
DevicePaths[Index] = DevicePathFromHandle (FileSystemHandles[Index]);
|
|
}
|
|
|
|
ExpandedOptions = &BdsLoadOption->ExpandedLoadOptions;
|
|
for (Link = GetFirstNode (ExpandedOptions); !IsNull (ExpandedOptions, Link); Link = GetNextNode (ExpandedOptions, Link)) {
|
|
CurrentLoadOption = BDS_OPTION_FROM_LINK (Link);
|
|
if (!IsDevicePathInArray (CurrentLoadOption->DevicePath, DevicePaths, NumberFileSystemHandles)) {
|
|
CurrentLink = Link;
|
|
Link = CurrentLink->BackLink;
|
|
RemoveEntryList (CurrentLink);
|
|
BdsServicesFreeLoadOption (&mH2OBdsServices, CurrentLoadOption);
|
|
}
|
|
}
|
|
InternalFreePool (DevicePaths);
|
|
InternalFreePool (FileSystemHandles);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
/**
|
|
Internal function to expand windows to go boot option.
|
|
|
|
It will set Expanded member in BdsLoadOption to TRUE and insert all of expanded load options
|
|
to ExpandedLoadOptions list in BdsLoadOption if this function return EFI_SUCESS.
|
|
|
|
@param[in,out] BdsLoadOption A pointer to BDS load option.
|
|
|
|
@retval EFI_SUCCESS Expand windows to go boot option successfully.
|
|
@retval EFI_INVALID_PARAMETER BdsLoadOption is NULL.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
ExpandWinowsToGoOption (
|
|
IN OUT H2O_BDS_LOAD_OPTION *BdsLoadOption
|
|
)
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
KERNEL_CONFIGURATION SystemConfiguration;
|
|
|
|
if (BdsLoadOption == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Status = GetKernelConfiguration (&SystemConfiguration);
|
|
if (Status == EFI_SUCCESS && SystemConfiguration.UsbBoot != 0) {
|
|
BdsLoadOption->Expanded = TRUE;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
AddExpandedWindowsToGoOption (BdsLoadOption);
|
|
RemoveRedundantExpandedWindowsToGoOption (BdsLoadOption);
|
|
BdsLoadOption->Expanded = TRUE;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Internal function to expand hard drive media short-form device path to hard driver media full device
|
|
path.
|
|
|
|
It will set Expanded member in BdsLoadOption to TRUE and insert all of expanded load options
|
|
to ExpandedLoadOptions list in BdsLoadOption if this function return EFI_SUCESS.
|
|
|
|
@param[in,out] BdsLoadOption A pointer to BDS load option.
|
|
|
|
@retval EFI_SUCCESS Expand hard driver media device path successfully.
|
|
@retval EFI_INVALID_PARAMETER BdsLoadOption is NULL.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
ExpandHddOption (
|
|
IN H2O_BDS_LOAD_OPTION *BdsLoadOption
|
|
)
|
|
{
|
|
EFI_DEVICE_PATH_PROTOCOL *FullDevicePath;
|
|
EFI_STATUS Status;
|
|
H2O_BDS_LOAD_OPTION *NewLoadOption;
|
|
|
|
if (BdsLoadOption == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
FullDevicePath = BdsExpandPartitionPartialDevicePathToFull ((HARDDRIVE_DEVICE_PATH *)BdsLoadOption->DevicePath);
|
|
if (FullDevicePath != NULL && !IsInExpandedLoadOptions (BdsLoadOption, FullDevicePath)) {
|
|
Status = BdsServicesCreateLoadOption (
|
|
&mH2OBdsServices,
|
|
BOOT_OPTION,
|
|
BDS_OPTION_HAVE_LOAD_ORDER_VAR_NAME(BdsLoadOption) ? BdsLoadOption->LoadOrderVarName : NULL,
|
|
BDS_OPTION_HAVE_LOAD_ORDER_VAR_NAME(BdsLoadOption) ? &BdsLoadOption->LoadOrderVarGuid : NULL,
|
|
LOAD_OPTION_ACTIVE,
|
|
FullDevicePath,
|
|
BdsLoadOption->Description,
|
|
BdsLoadOption->LoadOptionalData,
|
|
BdsLoadOption->LoadOptionalDataSize,
|
|
&NewLoadOption
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
InsertTailList (&BdsLoadOption->ExpandedLoadOptions, &NewLoadOption->Link);
|
|
}
|
|
BdsLoadOption->Expanded = TRUE;
|
|
}
|
|
InternalFreePool (FullDevicePath);
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Internal function to expand firmware file media short-form device path to full device path.
|
|
|
|
It will set Expanded member in BdsLoadOption to TRUE and insert all of expanded load options
|
|
to ExpandedLoadOptions list in BdsLoadOption if this function return EFI_SUCESS.
|
|
|
|
@param[in,out] BdsLoadOption A pointer to BDS load option.
|
|
|
|
@retval EFI_SUCCESS Expand firmware file media device path successfully.
|
|
@retval EFI_INVALID_PARAMETER BdsLoadOption is NULL.
|
|
@retval Other There is no firmware volume on system.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
ExpandFvFileOption (
|
|
IN OUT H2O_BDS_LOAD_OPTION *BdsLoadOption
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN HandleCount;
|
|
EFI_HANDLE *HandleBuffer;
|
|
EFI_GUID *FvFileName;
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
|
UINTN Index;
|
|
EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
|
|
EFI_FV_FILETYPE Type;
|
|
UINTN Size;
|
|
EFI_FV_FILE_ATTRIBUTES Attributes;
|
|
UINT32 AuthenticationStatus;
|
|
H2O_BDS_LOAD_OPTION *NewLoadOption;
|
|
|
|
if (BdsLoadOption == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Status = gBS->LocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiFirmwareVolume2ProtocolGuid,
|
|
NULL,
|
|
&HandleCount,
|
|
&HandleBuffer
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
FvFileName = &(((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) BdsLoadOption->DevicePath)->FvFileName);
|
|
for (Index = 0; Index < HandleCount; Index++) {
|
|
Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiFirmwareVolume2ProtocolGuid, (VOID **) &Fv);
|
|
if (EFI_ERROR (Status)) {
|
|
continue;
|
|
}
|
|
|
|
Status = Fv->ReadFile (
|
|
Fv,
|
|
FvFileName,
|
|
NULL,
|
|
&Size,
|
|
&Type,
|
|
&Attributes,
|
|
&AuthenticationStatus
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
continue;
|
|
}
|
|
|
|
Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID *) &DevicePath);
|
|
if (EFI_ERROR (Status)) {
|
|
continue;
|
|
}
|
|
|
|
DevicePath = AppendDevicePath (DevicePath, BdsLoadOption->DevicePath);
|
|
if (DevicePath == NULL) {
|
|
continue;
|
|
}
|
|
|
|
if (!IsInExpandedLoadOptions (BdsLoadOption, DevicePath)) {
|
|
Status = BdsServicesCreateLoadOption (
|
|
&mH2OBdsServices,
|
|
BOOT_OPTION,
|
|
BDS_OPTION_HAVE_LOAD_ORDER_VAR_NAME(BdsLoadOption) ? BdsLoadOption->LoadOrderVarName : NULL,
|
|
BDS_OPTION_HAVE_LOAD_ORDER_VAR_NAME(BdsLoadOption) ? &BdsLoadOption->LoadOrderVarGuid : NULL,
|
|
LOAD_OPTION_ACTIVE,
|
|
DevicePath,
|
|
BdsLoadOption->Description,
|
|
BdsLoadOption->LoadOptionalData,
|
|
BdsLoadOption->LoadOptionalDataSize,
|
|
&NewLoadOption
|
|
);
|
|
if (Status == EFI_SUCCESS) {
|
|
InsertTailList (&BdsLoadOption->ExpandedLoadOptions, &NewLoadOption->Link);
|
|
BdsLoadOption->Expanded = TRUE;
|
|
}
|
|
}
|
|
FreePool (DevicePath);
|
|
}
|
|
|
|
FreePool (HandleBuffer);
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Internal function to expand H2O BDS groupt boot option.
|
|
|
|
It will set Expanded member in BdsLoadOption to TRUE and insert all of expanded load options
|
|
to ExpandedLoadOptions list in BdsLoadOption if this function return EFI_SUCESS.
|
|
|
|
@param[in,out] BdsLoadOption A pointer to BDS load option.
|
|
|
|
@retval EFI_SUCCESS Expand H2O BDS groupt boot option successfully.
|
|
@retval EFI_INVALID_PARAMETER BdsLoadOption is NULL.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
ExpandBootGroupOption (
|
|
IN H2O_BDS_LOAD_OPTION *BdsLoadOption
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN HandleCount;
|
|
EFI_HANDLE *HandleBuffer;
|
|
H2O_BDS_BOOT_GROUP_DEVICE_PATH *BootGroupDevicePath;
|
|
UINTN Index;
|
|
H2O_BDS_BOOT_GROUP_PROTOCOL *BootGroup;
|
|
UINT32 BootOptionArrayLen;
|
|
H2O_BDS_LOAD_OPTION *BootOptionArray;
|
|
UINT32 ArrayIndex;
|
|
H2O_BDS_LOAD_OPTION *NewLoadOption;
|
|
|
|
if (BdsLoadOption == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
Status = gBS->LocateHandleBuffer (
|
|
ByProtocol,
|
|
&gH2OBdsBootGroupProtocolGuid,
|
|
NULL,
|
|
&HandleCount,
|
|
&HandleBuffer
|
|
);
|
|
if (Status != EFI_SUCCESS) {
|
|
return Status;
|
|
}
|
|
|
|
BootGroupDevicePath = (H2O_BDS_BOOT_GROUP_DEVICE_PATH *) BdsLoadOption->DevicePath;
|
|
for (Index = 0; Index < HandleCount; Index++) {
|
|
Status = gBS->HandleProtocol (
|
|
HandleBuffer[Index],
|
|
&gH2OBdsBootGroupProtocolGuid,
|
|
(VOID **) &BootGroup
|
|
);
|
|
ASSERT (Status == EFI_SUCCESS);
|
|
if (CompareGuid (&BootGroup->VendorGuid, &BootGroupDevicePath->VendorGuid)) {
|
|
Status = BootGroup->GetGroupDevices (
|
|
BootGroup,
|
|
BdsLoadOption,
|
|
&BootOptionArrayLen,
|
|
&BootOptionArray
|
|
);
|
|
if (Status != EFI_SUCCESS) {
|
|
break;
|
|
}
|
|
for (ArrayIndex = 0; ArrayIndex < BootOptionArrayLen; ArrayIndex++) {
|
|
if (!IsInExpandedLoadOptions(BdsLoadOption, BootOptionArray[ArrayIndex].DevicePath)) {
|
|
Status = BdsServicesCreateLoadOption (
|
|
&mH2OBdsServices,
|
|
BootOptionArray[ArrayIndex].DriverOrBoot,
|
|
BDS_OPTION_HAVE_LOAD_ORDER_VAR_NAME(&BootOptionArray[ArrayIndex]) ? BootOptionArray[ArrayIndex].LoadOrderVarName : NULL,
|
|
BDS_OPTION_HAVE_LOAD_ORDER_VAR_NAME(&BootOptionArray[ArrayIndex]) ? &BootOptionArray[ArrayIndex].LoadOrderVarGuid : NULL,
|
|
BootOptionArray[ArrayIndex].Attributes,
|
|
BootOptionArray[ArrayIndex].DevicePath,
|
|
BootOptionArray[ArrayIndex].Description,
|
|
BootOptionArray[ArrayIndex].LoadOptionalData,
|
|
BootOptionArray[ArrayIndex].LoadOptionalDataSize,
|
|
&NewLoadOption
|
|
);
|
|
ASSERT (Status == EFI_SUCCESS);
|
|
if (!EFI_ERROR (Status)) {
|
|
InsertTailList (&BdsLoadOption->ExpandedLoadOptions, &NewLoadOption->Link);
|
|
}
|
|
}
|
|
}
|
|
FreePool (BootOptionArray);
|
|
break;
|
|
}
|
|
}
|
|
|
|
FreePool (HandleBuffer);
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Internal function to expand H2O BDS boot option with USB short-form device path.
|
|
|
|
It will set Expanded member in BdsLoadOption to TRUE and insert all of expanded load options
|
|
to ExpandedLoadOptions list in BdsLoadOption if this function return EFI_SUCESS.
|
|
|
|
@param[in,out] BdsLoadOption A pointer to BDS load option.
|
|
|
|
@retval EFI_SUCCESS Expand H2O BDS boot option with USB short-form device path successfully.
|
|
@retval EFI_INVALID_PARAMETER BdsLoadOption is NULL.
|
|
@retval EFI_NOT_FOUND Failed to expand USB short-form device path.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
ExpandUsbShortFormOption (
|
|
IN H2O_BDS_LOAD_OPTION *BdsLoadOption
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_DEVICE_PATH_PROTOCOL *FullDevicePath;
|
|
H2O_BDS_LOAD_OPTION *NewLoadOption;
|
|
|
|
if (BdsLoadOption == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
FullDevicePath = BdsLibExpandUsbShortFormDevPath (BdsLoadOption->DevicePath);
|
|
if (FullDevicePath == NULL) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
if (!IsInExpandedLoadOptions (BdsLoadOption, FullDevicePath)) {
|
|
Status = BdsServicesCreateLoadOption (
|
|
&mH2OBdsServices,
|
|
BOOT_OPTION,
|
|
BDS_OPTION_HAVE_LOAD_ORDER_VAR_NAME(BdsLoadOption) ? BdsLoadOption->LoadOrderVarName : NULL,
|
|
BDS_OPTION_HAVE_LOAD_ORDER_VAR_NAME(BdsLoadOption) ? &BdsLoadOption->LoadOrderVarGuid : NULL,
|
|
LOAD_OPTION_ACTIVE,
|
|
FullDevicePath,
|
|
BdsLoadOption->Description,
|
|
BdsLoadOption->LoadOptionalData,
|
|
BdsLoadOption->LoadOptionalDataSize,
|
|
&NewLoadOption
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
InsertTailList (&BdsLoadOption->ExpandedLoadOptions, &NewLoadOption->Link);
|
|
}
|
|
BdsLoadOption->Expanded = TRUE;
|
|
}
|
|
|
|
InternalFreePool (FullDevicePath);
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Internal function to check the load option is whether in order variable.
|
|
|
|
@param[in] LoadOption A pointer to BDS load option.
|
|
@param[in] OrderVarInfo A pointer to order variable info.
|
|
|
|
@retval TRUE Load option is in the order variable.
|
|
@retval FALSE Load option isn't in the order variable.
|
|
**/
|
|
STATIC
|
|
BOOLEAN
|
|
IsLoadOptionInOrderVar (
|
|
IN CONST H2O_BDS_LOAD_OPTION *LoadOption,
|
|
IN CONST H2O_BDS_ORDER_VAR_INFO *OrderVarInfo
|
|
)
|
|
{
|
|
UINTN Index;
|
|
|
|
if (LoadOption == NULL || OrderVarInfo == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
for (Index = 0; Index < OrderVarInfo->OptionCount; Index++) {
|
|
if (IsLoadOptionMatch (LoadOption, OrderVarInfo->OptionOrder[Index], &OrderVarInfo->OptionVarGuid[Index])) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
Internal function to check the load order number with vendor GUID is whether in option list.
|
|
|
|
@param[in] LoadOrder Unsigned integer that specifies the current option being booted.
|
|
@param[in] LoadOrderVarGuid A pointer to the vendor variable GUID.
|
|
@param[in] OptionList A list head of linked list. Each entry is a H2O_BDS_LOAD_OPTION.
|
|
|
|
@retval TRUE Load order number is in the option list.
|
|
@retval FALSE Load order number isn't in the option list.
|
|
**/
|
|
STATIC
|
|
BOOLEAN
|
|
IsOptionNumInOptionList (
|
|
IN UINT16 LoadOrder,
|
|
IN CONST EFI_GUID *LoadOrderVarGuid,
|
|
IN CONST LIST_ENTRY *OptionList
|
|
)
|
|
{
|
|
LIST_ENTRY *Link;
|
|
H2O_BDS_LOAD_OPTION *CurrentLoadOption;
|
|
|
|
if (LoadOrderVarGuid == NULL || OptionList == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
for (Link = GetFirstNode (OptionList); !IsNull (OptionList, Link); Link = GetNextNode (OptionList, Link)) {
|
|
CurrentLoadOption = BDS_OPTION_FROM_LINK (Link);
|
|
if (IsLoadOptionMatch (CurrentLoadOption, LoadOrder, LoadOrderVarGuid)) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
Get the order index in order variable for input load option.
|
|
|
|
@param[in] BdsLoadOption Pointer to load option
|
|
@param[out] OrderIndex Order index in the option order variable
|
|
|
|
@retval EFI_SUCCESS Get the order index in order variable successfully.
|
|
@retval EFI_INVALID_PARAMETER BdsLoadOption is invalid or OrderIndex is NULL.
|
|
@retval EFI_UNSUPPORTED Fail to find option type info.
|
|
@retval EFI_NOT_FOUND Order variable info is not found.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
GetOrderIndexInOrderVar (
|
|
IN CONST H2O_BDS_LOAD_OPTION *BdsLoadOption,
|
|
OUT UINTN *OrderIndex
|
|
)
|
|
{
|
|
H2O_BDS_OPTION_TYPE_INFO *OptionTypeInfo;
|
|
H2O_BDS_ORDER_VAR_INFO OrderVarInfo;
|
|
EFI_STATUS Status;
|
|
UINTN Index;
|
|
UINTN OptionCount;
|
|
UINT16 *OptionOrder;
|
|
CHAR16 OptionVarName[OPTION_VAR_NAME_BUFFER_CHAR_COUNT];
|
|
UINTN OptionVarSize;
|
|
UINT16 *OptionVar;
|
|
UINT8 *TempPtr;
|
|
EFI_DEVICE_PATH_PROTOCOL *OptionDevicePath;
|
|
UINT16 VarBbsTableIndex;
|
|
UINT16 OptionBbsTableIndex;
|
|
|
|
if (!IsValidLoadOption (BdsLoadOption) || OrderIndex == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
OptionTypeInfo = GetOptionTypeInfo (BdsLoadOption->OptionType);
|
|
if (OptionTypeInfo == NULL) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
Status = GetOrderVarInfo (BdsLoadOption->OptionType, &OrderVarInfo);
|
|
if (EFI_ERROR (Status)) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
OptionVar = NULL;
|
|
OptionCount = OrderVarInfo.OptionCount;
|
|
OptionOrder = OrderVarInfo.OptionOrder;
|
|
for (Index = 0; Index < OptionCount; Index++) {
|
|
if (BdsLoadOption->OptionType == H2O_BDS_LOAD_OPTION_TYPE_BOOT && BdsLibIsDummyBootOption (OptionOrder[Index])) {
|
|
if (BdsLoadOption->LoadOrder == OptionOrder[Index]) {
|
|
break;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
UnicodeSPrint (OptionVarName, sizeof (OptionVarName), OPTION_VAR_NAME_FORMAT_STR, OptionTypeInfo->OptionVarPrefixName, OptionOrder[Index]);
|
|
Status = CommonGetVariableDataAndSize (
|
|
OptionVarName,
|
|
&OrderVarInfo.OptionVarGuid[Index],
|
|
&OptionVarSize,
|
|
(VOID **) &OptionVar
|
|
);
|
|
if (Status != EFI_SUCCESS) {
|
|
continue;
|
|
}
|
|
|
|
TempPtr = (UINT8 *) OptionVar;
|
|
TempPtr += sizeof (UINT32) + sizeof (UINT16);
|
|
TempPtr += StrSize ((CHAR16 *) TempPtr);
|
|
OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
|
|
|
|
if (IsLegacyBootOption (OptionDevicePath)) {
|
|
if (IsLegacyBootOption (BdsLoadOption->DevicePath)) {
|
|
VarBbsTableIndex = *((UINT16 *) (TempPtr + GetDevicePathSize (OptionDevicePath) + sizeof (BBS_TABLE)));
|
|
OptionBbsTableIndex = *((UINT16 *) ((UINT8 *) BdsLoadOption->LoadOptionalData + sizeof (BBS_TABLE)));
|
|
if (VarBbsTableIndex == OptionBbsTableIndex) {
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
if ((CompareMem (BdsLoadOption->DevicePath, OptionDevicePath, GetDevicePathSize (OptionDevicePath)) == 0) ||
|
|
(MatchPartitionDevicePathNode (BdsLoadOption->DevicePath, (HARDDRIVE_DEVICE_PATH *) OptionDevicePath) &&
|
|
BdsLibMatchFilePathDevicePathNode (BdsLoadOption->DevicePath, OptionDevicePath))) {
|
|
break;
|
|
}
|
|
}
|
|
InternalFreePool (OptionVar);
|
|
OptionVar = NULL;
|
|
}
|
|
|
|
InternalFreePool (OptionVar);
|
|
FreeOrderVarInfo (&OrderVarInfo);
|
|
if (Index == OptionCount) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
*OrderIndex = Index;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Check the device path belongs to PXE boot option or not.
|
|
|
|
@param[in] DevicePath Device path
|
|
|
|
@retval TRUE The device path is for PXE boot option.
|
|
@retval FALSE The device path isn't for PXE boot option.
|
|
**/
|
|
STATIC
|
|
BOOLEAN
|
|
IsPxeBoot (
|
|
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
|
|
)
|
|
{
|
|
BOOLEAN IsPxeImage;
|
|
EFI_DEVICE_PATH_PROTOCOL *NetworkDevicePath;
|
|
|
|
IsPxeImage = FALSE;
|
|
NetworkDevicePath = DevicePath;
|
|
while (!IsDevicePathEnd (NetworkDevicePath)) {
|
|
if (NetworkDevicePath->Type == MESSAGING_DEVICE_PATH) {
|
|
if (NetworkDevicePath->SubType == MSG_MAC_ADDR_DP) {
|
|
IsPxeImage = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
NetworkDevicePath = NextDevicePathNode (NetworkDevicePath);
|
|
}
|
|
|
|
return IsPxeImage;
|
|
}
|
|
|
|
/**
|
|
Check the device path is belong to HTTP boot option or not.
|
|
|
|
@param[in] DevicePath Device path
|
|
|
|
@retval TRUE The device path is for PXE boot option.
|
|
@retval FALSE The device path isn't for PXE boot option.
|
|
**/
|
|
STATIC
|
|
BOOLEAN
|
|
IsHttpBootHandle (
|
|
IN EFI_DEVICE_PATH_PROTOCOL *BootDevicePath
|
|
)
|
|
{
|
|
BOOLEAN IsNetworkDevice;
|
|
EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath;
|
|
|
|
if (BootDevicePath == NULL) {
|
|
return FALSE;
|
|
}
|
|
//
|
|
// Find out DevicePath like .../MAC/IP/URI
|
|
//
|
|
TmpDevicePath = BootDevicePath;
|
|
|
|
IsNetworkDevice = FALSE;
|
|
while (!IsDevicePathEnd (TmpDevicePath)) {
|
|
if (TmpDevicePath->Type == MESSAGING_DEVICE_PATH) {
|
|
if (TmpDevicePath->SubType == MSG_MAC_ADDR_DP) {
|
|
IsNetworkDevice = TRUE;
|
|
} else if (IsNetworkDevice && (TmpDevicePath->SubType == MSG_URI_DP)) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
TmpDevicePath = NextDevicePathNode (TmpDevicePath);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
Return the buffer and buffer size occupied by the RAM Disk.
|
|
|
|
@param[in] RamDiskDevicePath RAM Disk device path.
|
|
@param[out] RamDiskSizeInPages Return RAM Disk size in pages.
|
|
|
|
@retval RAM Disk buffer.
|
|
**/
|
|
VOID *
|
|
GetRamDiskMemoryInfo (
|
|
IN EFI_DEVICE_PATH_PROTOCOL *RamDiskDevicePath,
|
|
OUT UINTN *RamDiskSizeInPages
|
|
)
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
EFI_HANDLE Handle;
|
|
UINT64 StartingAddr;
|
|
UINT64 EndingAddr;
|
|
|
|
if (RamDiskDevicePath == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
*RamDiskSizeInPages = 0;
|
|
Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &RamDiskDevicePath, &Handle);
|
|
if (EFI_ERROR (Status)) {
|
|
return NULL;
|
|
}
|
|
//
|
|
// Check DevicePath is MediaDevice and SubType is RamDisk.
|
|
//
|
|
if ((DevicePathType (RamDiskDevicePath) != MEDIA_DEVICE_PATH) && (DevicePathSubType (RamDiskDevicePath) != MEDIA_RAM_DISK_DP)) {
|
|
return NULL;
|
|
}
|
|
StartingAddr = ReadUnaligned64 ((UINT64 *) ((MEDIA_RAM_DISK_DEVICE_PATH *) RamDiskDevicePath)->StartingAddr);
|
|
EndingAddr = ReadUnaligned64 ((UINT64 *) ((MEDIA_RAM_DISK_DEVICE_PATH *) RamDiskDevicePath)->EndingAddr);
|
|
*RamDiskSizeInPages = EFI_SIZE_TO_PAGES ((UINTN) (EndingAddr - StartingAddr + 1));
|
|
return (VOID *) (UINTN) StartingAddr;
|
|
}
|
|
|
|
/**
|
|
Destroy the RAM Disk.
|
|
|
|
The destroy operation includes to call RamDisk.Unregister to
|
|
unregister the RAM DISK from RAM DISK driver, free the memory
|
|
allocated for the RAM Disk.
|
|
|
|
@param[in] RamDiskDevicePath RAM Disk device path.
|
|
**/
|
|
VOID
|
|
DestroyRamDisk (
|
|
IN EFI_DEVICE_PATH_PROTOCOL *RamDiskDevicePath
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
VOID *RamDiskBuffer;
|
|
UINTN RamDiskSizeInPages;
|
|
EFI_RAM_DISK_PROTOCOL *RamDisk;
|
|
|
|
if (RamDiskDevicePath == NULL) {
|
|
return;
|
|
}
|
|
|
|
RamDiskBuffer = GetRamDiskMemoryInfo (RamDiskDevicePath, &RamDiskSizeInPages);
|
|
if (RamDiskBuffer == NULL) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Destroy RAM Disk.
|
|
//
|
|
Status = gBS->LocateProtocol (&gEfiRamDiskProtocolGuid, NULL, (VOID **) &RamDisk);
|
|
if (EFI_ERROR (Status)) {
|
|
return;
|
|
}
|
|
RamDisk->Unregister (RamDiskDevicePath);
|
|
FreePages (RamDiskBuffer, RamDiskSizeInPages);
|
|
}
|
|
|
|
/**
|
|
Expand the media device path which points to a BlockIo or SimpleFileSystem instance
|
|
by appending EFI_REMOVABLE_MEDIA_FILE_NAME.
|
|
|
|
@param[in] DevicePath The media device path pointing to a BlockIo or SimpleFileSystem instance.
|
|
|
|
@return The next possible full path pointing to the load option.
|
|
Caller is responsible to free the memory.
|
|
**/
|
|
EFI_DEVICE_PATH_PROTOCOL *
|
|
ExpandMediaDevicePath (
|
|
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_HANDLE Handle;
|
|
EFI_BLOCK_IO_PROTOCOL *BlockIo;
|
|
VOID *Buffer;
|
|
EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
|
|
EFI_DEVICE_PATH_PROTOCOL *NextFullPath;
|
|
UINTN Size;
|
|
UINTN TempSize;
|
|
EFI_HANDLE *SimpleFileSystemHandles;
|
|
UINTN NumberSimpleFileSystemHandles;
|
|
UINTN Index;
|
|
|
|
//
|
|
// Check whether the device is connected
|
|
//
|
|
TempDevicePath = DevicePath;
|
|
Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &TempDevicePath, &Handle);
|
|
if (!EFI_ERROR (Status)) {
|
|
NextFullPath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME);
|
|
return NextFullPath;
|
|
}
|
|
|
|
Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, &Handle);
|
|
if (EFI_ERROR (Status)) {
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// For device boot option only pointing to the removable device handle,
|
|
// should make sure all its children handles (its child partion or media handles)
|
|
// are created and connected.
|
|
//
|
|
gBS->ConnectController (Handle, NULL, NULL, TRUE);
|
|
|
|
//
|
|
// Issue a dummy read to the device to check for media change.
|
|
// When the removable media is changed, any Block IO read/write will
|
|
// cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is
|
|
// returned. After the Block IO protocol is reinstalled, subsequent
|
|
// Block IO read/write will success.
|
|
//
|
|
Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
|
|
if (EFI_ERROR (Status)) {
|
|
return NULL;
|
|
}
|
|
Buffer = AllocatePool (BlockIo->Media->BlockSize);
|
|
if (Buffer != NULL) {
|
|
BlockIo->ReadBlocks (
|
|
BlockIo,
|
|
BlockIo->Media->MediaId,
|
|
0,
|
|
BlockIo->Media->BlockSize,
|
|
Buffer
|
|
);
|
|
FreePool (Buffer);
|
|
}
|
|
|
|
//
|
|
// Detect the the default boot file from removable Media
|
|
//
|
|
NextFullPath = NULL;
|
|
Size = GetDevicePathSize (DevicePath) - END_DEVICE_PATH_LENGTH;
|
|
gBS->LocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiSimpleFileSystemProtocolGuid,
|
|
NULL,
|
|
&NumberSimpleFileSystemHandles,
|
|
&SimpleFileSystemHandles
|
|
);
|
|
for (Index = 0; Index < NumberSimpleFileSystemHandles; Index++) {
|
|
//
|
|
// Get the device path size of SimpleFileSystem handle
|
|
//
|
|
TempDevicePath = DevicePathFromHandle (SimpleFileSystemHandles[Index]);
|
|
TempSize = GetDevicePathSize (TempDevicePath) - END_DEVICE_PATH_LENGTH;
|
|
//
|
|
// Check whether the device path of boot option is part of the SimpleFileSystem handle's device path
|
|
//
|
|
if ((Size <= TempSize) && (CompareMem (TempDevicePath, DevicePath, Size) == 0)) {
|
|
NextFullPath = FileDevicePath (SimpleFileSystemHandles[Index], EFI_REMOVABLE_MEDIA_FILE_NAME);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (SimpleFileSystemHandles != NULL) {
|
|
FreePool (SimpleFileSystemHandles);
|
|
}
|
|
|
|
return NextFullPath;
|
|
}
|
|
|
|
/**
|
|
Get the file buffer from the file system produced by Load File instance.
|
|
|
|
@param[in] LoadFileHandle The handle of LoadFile instance.
|
|
@param[out] RamDiskHandle Return the RAM Disk handle.
|
|
|
|
@return The next possible full path pointing to the load option.
|
|
Caller is responsible to free the memory.
|
|
**/
|
|
EFI_DEVICE_PATH_PROTOCOL *
|
|
ExpandNetworkFileSystem (
|
|
IN EFI_HANDLE LoadFileHandle,
|
|
OUT EFI_HANDLE *RamDiskHandle
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_HANDLE Handle;
|
|
EFI_HANDLE *Handles;
|
|
UINTN HandleCount;
|
|
UINTN Index;
|
|
EFI_DEVICE_PATH_PROTOCOL *Node;
|
|
|
|
Status = gBS->LocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiBlockIoProtocolGuid,
|
|
NULL,
|
|
&HandleCount,
|
|
&Handles
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
Handles = NULL;
|
|
HandleCount = 0;
|
|
}
|
|
|
|
Handle = NULL;
|
|
for (Index = 0; Index < HandleCount; Index++) {
|
|
Node = DevicePathFromHandle (Handles[Index]);
|
|
Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &Node, &Handle);
|
|
if (!EFI_ERROR (Status) &&
|
|
(Handle == LoadFileHandle) &&
|
|
(DevicePathType (Node) == MEDIA_DEVICE_PATH) && (DevicePathSubType (Node) == MEDIA_RAM_DISK_DP)) {
|
|
//
|
|
// Find the BlockIo instance populated from the LoadFile.
|
|
//
|
|
Handle = Handles[Index];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (Handles != NULL) {
|
|
FreePool (Handles);
|
|
}
|
|
|
|
if (Index == HandleCount) {
|
|
Handle = NULL;
|
|
}
|
|
|
|
*RamDiskHandle = Handle;
|
|
|
|
if (Handle != NULL) {
|
|
//
|
|
// Re-use ExpandMediaDevicePath() to get the full device path of load option.
|
|
// But assume only one SimpleFileSystem can be found under the BlockIo.
|
|
//
|
|
return ExpandMediaDevicePath (DevicePathFromHandle (Handle));
|
|
} else {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/**
|
|
Process HTTP boot, if HttpBootDxe driver return EFI_WARN_FILE_SYSTEM.
|
|
This function will allocate reserved memory to HttpBootDxe, it will get the ISO file and put in reverved memory.
|
|
Then it will register RamDisk and connect to BlockIo and FileSystem handle.
|
|
This function will find the expanded device handle (usually is FS) and Output in ExpandedUriDevicePath and RamDiskHandle parameters.
|
|
|
|
@param[in] LoadFileDevicePath DevicePath of HTTP boot.
|
|
@param[out] ExpandedUriDevicePath Expanded device path, include RamDisk and FileSystem.
|
|
@param[out] RamDiskHandle RamDisk handle, output this parameter to handle RamDisk if BDS need to destroy it.
|
|
|
|
@return EFI_SUCCESS Function successfully.
|
|
@return EFI_INVALID_PARAMETER Invalid parameters.
|
|
@return EFI_NOT_FOUND LoadFile is not found.
|
|
@return others Error status from called functions.
|
|
**/
|
|
EFI_STATUS
|
|
ProcessHttpUriBoot (
|
|
IN EFI_DEVICE_PATH_PROTOCOL *LoadFileDevicePath,
|
|
OUT EFI_DEVICE_PATH_PROTOCOL **ExpandedUriDevicePath,
|
|
OUT EFI_HANDLE *RamDiskHandle
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_HANDLE HttpBootHandle;
|
|
EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
|
|
EFI_DEVICE_PATH_PROTOCOL *FilePath;
|
|
EFI_DEVICE_PATH_PROTOCOL *FullPath;
|
|
EFI_LOAD_FILE_PROTOCOL *LoadFile;
|
|
UINTN BufferSize;
|
|
VOID *FileBuffer;
|
|
|
|
if ((LoadFileDevicePath == NULL) || (ExpandedUriDevicePath == NULL) || (RamDiskHandle == NULL)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
HttpBootHandle = NULL;
|
|
TempDevicePath = LoadFileDevicePath;
|
|
Status = gBS->LocateDevicePath (
|
|
&gEfiDevicePathProtocolGuid,
|
|
&TempDevicePath,
|
|
&HttpBootHandle
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto ON_EXIT;
|
|
}
|
|
|
|
//
|
|
// Find out HTTP boot entry and original DevicePath.
|
|
//
|
|
Status = gBS->HandleProtocol (HttpBootHandle, &gEfiLoadFileProtocolGuid, (VOID **) &LoadFile);
|
|
if (EFI_ERROR (Status)) {
|
|
Status = EFI_NOT_FOUND;
|
|
goto ON_EXIT;
|
|
}
|
|
Status = gBS->HandleProtocol (HttpBootHandle, &gEfiDevicePathProtocolGuid, (VOID **) &FilePath);
|
|
if (EFI_ERROR (Status)) {
|
|
Status = EFI_NOT_FOUND;
|
|
goto ON_EXIT;
|
|
}
|
|
|
|
//
|
|
// Calling HTTP boot entry
|
|
//
|
|
FileBuffer = NULL;
|
|
BufferSize = 0;
|
|
Status = LoadFile->LoadFile (LoadFile, FilePath, TRUE, &BufferSize, NULL);
|
|
if ((Status != EFI_BUFFER_TOO_SMALL) && (Status != EFI_WARN_FILE_SYSTEM)) {
|
|
goto ON_EXIT;
|
|
}
|
|
if (Status == EFI_BUFFER_TOO_SMALL) {
|
|
//
|
|
// The load option buffer is directly returned by LoadFile.
|
|
// **HttpBootDxe maybe updates the Device to append the real URL in DevicePath on HttpBootHandle.
|
|
//
|
|
goto ON_EXIT;
|
|
}
|
|
|
|
//
|
|
// The load option resides in a RAM disk.
|
|
//
|
|
FileBuffer = AllocateReservedPages (EFI_SIZE_TO_PAGES (BufferSize));
|
|
if (FileBuffer == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto ON_EXIT;
|
|
}
|
|
|
|
Status = LoadFile->LoadFile (LoadFile, FilePath, TRUE, &BufferSize, FileBuffer);
|
|
if (EFI_ERROR (Status)) {
|
|
FreePages (FileBuffer, EFI_SIZE_TO_PAGES (BufferSize));
|
|
goto ON_EXIT;
|
|
}
|
|
|
|
FullPath = ExpandNetworkFileSystem (HttpBootHandle, RamDiskHandle);
|
|
if (FullPath == NULL) {
|
|
//
|
|
// Free the memory occupied by the RAM disk if there is no BlockIo or SimpleFileSystem instance.
|
|
//
|
|
DestroyRamDisk (DevicePathFromHandle (*RamDiskHandle));
|
|
Status = EFI_UNSUPPORTED;
|
|
goto ON_EXIT;
|
|
}
|
|
|
|
*ExpandedUriDevicePath = FullPath;
|
|
return EFI_SUCCESS;
|
|
|
|
ON_EXIT:
|
|
/// This processing will resolve system hang if BootOption's DevicePath changed.
|
|
*ExpandedUriDevicePath = LoadFileDevicePath;
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Check the Device path is a file path pointer to UEFI OS boot option.
|
|
|
|
@param[in] DevicePath Device path
|
|
|
|
@retval TRUE The device path is pointer to UEFI OS boot opiton.
|
|
@retval FALSE The device path isn't pointer to UEFI OS boot opiton.
|
|
**/
|
|
STATIC
|
|
BOOLEAN
|
|
IsUefiOsFilePath (
|
|
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
|
|
)
|
|
{
|
|
EFI_DEVICE_PATH_PROTOCOL *WorkingDevicePath;
|
|
EFI_HANDLE Handle;
|
|
EFI_STATUS Status;
|
|
FILEPATH_DEVICE_PATH *FilePath;
|
|
|
|
WorkingDevicePath = DevicePath;
|
|
|
|
Status = gBS->LocateDevicePath (
|
|
&gEfiSimpleFileSystemProtocolGuid,
|
|
&WorkingDevicePath,
|
|
&Handle
|
|
);
|
|
if (!EFI_ERROR (Status) &&
|
|
DevicePathType (WorkingDevicePath) == MEDIA_DEVICE_PATH &&
|
|
DevicePathSubType (WorkingDevicePath) == MEDIA_FILEPATH_DP) {
|
|
//
|
|
// If file name isn't default removable file name, we consider this file path pointer to UEFI OS
|
|
//
|
|
FilePath = (FILEPATH_DEVICE_PATH *) WorkingDevicePath;
|
|
if ((StrLen (FilePath->PathName) != StrLen (EFI_REMOVABLE_MEDIA_FILE_NAME)) ||
|
|
(StrCmp (FilePath->PathName, EFI_REMOVABLE_MEDIA_FILE_NAME) != 0)) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
Initalize H2O_BDS_CP_BOOT_AFTER_DATA data and trigger gH2OBdsCpBootAfterGuid checkpoint.
|
|
|
|
@retval EFI_SUCCESS Trigger gH2OBdsCpBootAfterGuid checkpoint successfully.
|
|
@return Other Other error occurred while triggering gH2OBdsCpBootAfterGuid checkpoint.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
TriggerCpBootAfter (
|
|
VOID
|
|
)
|
|
{
|
|
H2O_BDS_CP_BOOT_AFTER_DATA BdsCpBootAfterData;
|
|
EFI_STATUS Status;
|
|
|
|
BdsCpBootAfterData.Size = sizeof (H2O_BDS_CP_BOOT_AFTER_DATA);
|
|
BdsCpBootAfterData.Status = H2O_BDS_TASK_NORMAL;
|
|
|
|
DEBUG_CP ((DEBUG_INFO, "Checkpoint Trigger: %g\n", &gH2OBdsCpBootAfterGuid));
|
|
Status = H2OCpTrigger (&gH2OBdsCpBootAfterGuid, &BdsCpBootAfterData);
|
|
DEBUG_CP ((DEBUG_INFO, "Checkpoint Result: %x\n", BdsCpBootAfterData.Status));
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Initalize H2O_BDS_CP_BOOT_BEFORE_DATA data and trigger gH2OBdsCpBootBeforeGuid checkpoint.
|
|
|
|
@retval EFI_SUCCESS Trigger gH2OBdsCpBootBeforeGuid checkpoint successfully.
|
|
@return Other Other error occurred while triggering gH2OBdsCpBootBeforeGuid checkpoint.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
TriggerCpBootBefore (
|
|
VOID
|
|
)
|
|
{
|
|
H2O_BDS_CP_BOOT_BEFORE_DATA BdsCpBootBeforeData;
|
|
EFI_STATUS Status;
|
|
|
|
BdsCpBootBeforeData.Size = sizeof (H2O_BDS_CP_BOOT_BEFORE_DATA);
|
|
BdsCpBootBeforeData.Status = H2O_BDS_TASK_NORMAL;
|
|
|
|
DEBUG_CP ((DEBUG_INFO, "Checkpoint Trigger: %g\n", &gH2OBdsCpBootBeforeGuid));
|
|
Status = H2OCpTrigger (&gH2OBdsCpBootBeforeGuid, &BdsCpBootBeforeData);
|
|
DEBUG_CP ((DEBUG_INFO, "Checkpoint Result: %x\n", BdsCpBootBeforeData.Status));
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Internal function to create new H2O_BDS_LOAD_OPTION by input load order.
|
|
|
|
@param[in] OptionType BDS load option type.
|
|
@param[in] LoadOrder Unsigned integer that specifies the current boot option being booted.
|
|
@param[in] LoadOrderVarGuid A pointer to the vendor variable GUID.
|
|
|
|
@return pointer to H2O_BDS_LOAD_OPTION instance or return NULL if create new boot option failed.
|
|
**/
|
|
STATIC
|
|
H2O_BDS_LOAD_OPTION *
|
|
GetNewBdsLoadOption (
|
|
IN UINT8 OptionType,
|
|
IN UINT16 LoadOrder,
|
|
IN CONST EFI_GUID *LoadOrderVarGuid
|
|
)
|
|
{
|
|
H2O_BDS_LOAD_OPTION *LoadOption;
|
|
UINT16 LoadOptionName[OPTION_VAR_NAME_BUFFER_CHAR_COUNT];
|
|
H2O_BDS_OPTION_TYPE_INFO *OptionTypeInfo;
|
|
|
|
OptionTypeInfo = GetOptionTypeInfo (OptionType);
|
|
if (OptionTypeInfo == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
LoadOption = NULL;
|
|
UnicodeSPrint (LoadOptionName, sizeof (LoadOptionName), OPTION_VAR_NAME_FORMAT_STR, OptionTypeInfo->OptionVarPrefixName, LoadOrder);
|
|
BdsServicesConvertVarToLoadOption (&mH2OBdsServices, LoadOptionName, LoadOrderVarGuid, &LoadOption);
|
|
return LoadOption;
|
|
}
|
|
|
|
/**
|
|
Internal function to check the load option list and order variable info are matched.
|
|
|
|
@param[in] OptionType BDS load option type.
|
|
@param[in] OrderVarInfo A pointer to order variable info.
|
|
|
|
@retval TRUE The load option list data is correct.
|
|
@retval FALSE The load option list data is incorrect.
|
|
**/
|
|
STATIC
|
|
BOOLEAN
|
|
IsLoadOptionListCorrect (
|
|
IN UINT8 OptionType,
|
|
IN CONST H2O_BDS_ORDER_VAR_INFO *OrderVarInfo
|
|
)
|
|
{
|
|
H2O_BDS_OPTION_TYPE_INFO *OptionTypeInfo;
|
|
LIST_ENTRY *OptionList;
|
|
LIST_ENTRY *Link;
|
|
UINTN Index;
|
|
H2O_BDS_LOAD_OPTION *CurrentLoadOption;
|
|
|
|
|
|
if (OrderVarInfo == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
OptionTypeInfo = GetOptionTypeInfo (OptionType);
|
|
if (OptionTypeInfo == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
Index = 0;
|
|
OptionList = &OptionTypeInfo->OptionList;
|
|
for (Link = GetFirstNode (OptionList); !IsNull (OptionList, Link); Link = GetNextNode (OptionList, Link)) {
|
|
if (Index >= OrderVarInfo->OptionCount) {
|
|
return FALSE;
|
|
}
|
|
CurrentLoadOption = BDS_OPTION_FROM_LINK (Link);
|
|
if (!IsLoadOptionMatch (CurrentLoadOption, OrderVarInfo->OptionOrder[Index], &OrderVarInfo->OptionVarGuid[Index])) {
|
|
return FALSE;
|
|
}
|
|
Index++;
|
|
}
|
|
|
|
return Index == OrderVarInfo->OptionCount ? TRUE : FALSE;
|
|
}
|
|
|
|
|
|
/**
|
|
Internal function to remove all of load options in load option list.
|
|
|
|
@param[in] OptionType BDS load option type.
|
|
**/
|
|
STATIC
|
|
VOID
|
|
RemoveAllLoadOptions (
|
|
IN UINT8 OptionType
|
|
)
|
|
{
|
|
H2O_BDS_OPTION_TYPE_INFO *OptionTypeInfo;
|
|
LIST_ENTRY *OptionList;
|
|
LIST_ENTRY *Link;
|
|
H2O_BDS_LOAD_OPTION *CurrentLoadOption;
|
|
|
|
OptionTypeInfo = GetOptionTypeInfo (OptionType);
|
|
if (OptionTypeInfo == NULL) {
|
|
return;
|
|
}
|
|
|
|
OptionList = &OptionTypeInfo->OptionList;
|
|
while (!IsListEmpty (OptionList)) {
|
|
Link = GetFirstNode (OptionList);
|
|
RemoveEntryList (Link);
|
|
CurrentLoadOption = BDS_OPTION_FROM_LINK (Link);
|
|
BdsServicesFreeLoadOption (&mH2OBdsServices, CurrentLoadOption);
|
|
}
|
|
}
|
|
|
|
/**
|
|
Internal function to check if BDS load option is stale data.
|
|
|
|
@param[in] LoadOption A pointer to BDS load option.
|
|
|
|
@retval TRUE The BDS load option is stale data.
|
|
@retval FALSE The BDS load option isn't stale data.
|
|
**/
|
|
STATIC
|
|
BOOLEAN
|
|
IsLoadOptionStaleData (
|
|
IN H2O_BDS_LOAD_OPTION *LoadOption
|
|
)
|
|
{
|
|
CHAR16 OptionName[OPTION_VAR_NAME_BUFFER_CHAR_COUNT];
|
|
EFI_STATUS Status;
|
|
UINT8 *EfiLoadOption;
|
|
UINTN EfiLoadOptionSize;
|
|
UINT8 *WorkingPtr;
|
|
CHAR16 *Description;
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
|
H2O_BDS_OPTION_TYPE_INFO *OptionTypeInfo;
|
|
UINT32 Attributes;
|
|
UINT16 DevicePathLength;
|
|
UINTN UsedSize;
|
|
UINT8 *OptionalData;
|
|
UINT32 OptionalDataSize;
|
|
|
|
if (LoadOption == NULL) {
|
|
return TRUE;
|
|
}
|
|
|
|
OptionTypeInfo = GetOptionTypeInfo (LoadOption->OptionType);
|
|
if (OptionTypeInfo == NULL) {
|
|
return TRUE;
|
|
}
|
|
UnicodeSPrint (OptionName, sizeof (OptionName), OPTION_VAR_NAME_FORMAT_STR, OptionTypeInfo->OptionVarPrefixName, LoadOption->LoadOrder);
|
|
|
|
Status = CommonGetVariableDataAndSize (
|
|
OptionName,
|
|
&LoadOption->LoadOrderVarGuid,
|
|
&EfiLoadOptionSize,
|
|
(VOID **) &EfiLoadOption
|
|
);
|
|
if (Status != EFI_SUCCESS) {
|
|
return TRUE;
|
|
}
|
|
|
|
WorkingPtr = (UINT8 *) EfiLoadOption;
|
|
Attributes = *((UINT32 *) WorkingPtr);
|
|
WorkingPtr += sizeof (UINT32);
|
|
DevicePathLength = *((UINT16 *) WorkingPtr);
|
|
WorkingPtr += sizeof (UINT16);
|
|
Description = (CHAR16 *) WorkingPtr;
|
|
WorkingPtr += StrSize (Description);
|
|
DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) WorkingPtr;
|
|
WorkingPtr += DevicePathLength;
|
|
UsedSize = (UINTN) (WorkingPtr - (UINT8 *) EfiLoadOption);
|
|
if (EfiLoadOptionSize > UsedSize) {
|
|
OptionalDataSize = (UINT32) (EfiLoadOptionSize - UsedSize);
|
|
OptionalData = WorkingPtr;
|
|
} else {
|
|
OptionalData = NULL;
|
|
OptionalDataSize = 0;
|
|
}
|
|
|
|
if (LoadOption->Attributes != Attributes ||
|
|
StrCmp (LoadOption->Description, Description) != 0 ||
|
|
GetDevicePathSize (LoadOption->DevicePath) != GetDevicePathSize (DevicePath) ||
|
|
CompareMem (LoadOption->DevicePath, DevicePath, GetDevicePathSize (DevicePath)) != 0 ||
|
|
LoadOption->LoadOptionalDataSize != OptionalDataSize ||
|
|
(OptionalDataSize != 0 && CompareMem (LoadOption->LoadOptionalData, OptionalData, OptionalDataSize) != 0)
|
|
) {
|
|
FreePool (EfiLoadOption);
|
|
return TRUE;
|
|
}
|
|
|
|
FreePool (EfiLoadOption);
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
Synchronize the load option list from variable.
|
|
|
|
@param[in] OptionType Option type that specifies which option list to be synchronized.
|
|
|
|
@retval EFI_SUCCESS Synchronize boot list successfully.
|
|
@retval EFI_UNSUPPORTED Fail to find option type info.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
SyncBdsLoadList (
|
|
IN UINT8 OptionType
|
|
)
|
|
{
|
|
H2O_BDS_OPTION_TYPE_INFO *OptionTypeInfo;
|
|
H2O_BDS_ORDER_VAR_INFO OrderVarInfo;
|
|
LIST_ENTRY *OptionList;
|
|
LIST_ENTRY *Link;
|
|
LIST_ENTRY *CurrentLink;
|
|
H2O_BDS_LOAD_OPTION *CurrentLoadOption;
|
|
UINTN Index;
|
|
EFI_STATUS Status;
|
|
|
|
OptionTypeInfo = GetOptionTypeInfo (OptionType);
|
|
if (OptionTypeInfo == NULL) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
Status = GetOrderVarInfo (OptionType, &OrderVarInfo);
|
|
if (EFI_ERROR (Status)) {
|
|
ZeroMem (&OrderVarInfo, sizeof (OrderVarInfo));
|
|
}
|
|
|
|
//
|
|
// Remove redundant bds load option in option list.
|
|
//
|
|
OptionList = &OptionTypeInfo->OptionList;
|
|
for (Link = GetFirstNode (OptionList); !IsNull (OptionList, Link); Link = GetNextNode (OptionList, Link)) {
|
|
CurrentLoadOption = BDS_OPTION_FROM_LINK (Link);
|
|
if (!IsLoadOptionInOrderVar (CurrentLoadOption, &OrderVarInfo) || IsLoadOptionStaleData (CurrentLoadOption)) {
|
|
CurrentLink = Link;
|
|
Link = CurrentLink->BackLink;
|
|
RemoveEntryList (&CurrentLoadOption->Link);
|
|
BdsServicesFreeLoadOption (&mH2OBdsServices, CurrentLoadOption);
|
|
}
|
|
}
|
|
//
|
|
// Add BDS load option.
|
|
//
|
|
for (Index = 0; Index < OrderVarInfo.OptionCount; Index++) {
|
|
if (!IsOptionNumInOptionList (OrderVarInfo.OptionOrder[Index], &OrderVarInfo.OptionVarGuid[Index], OptionList)) {
|
|
CurrentLoadOption = GetNewBdsLoadOption (OptionType, OrderVarInfo.OptionOrder[Index], &OrderVarInfo.OptionVarGuid[Index]);
|
|
if (CurrentLoadOption == NULL) {
|
|
continue;
|
|
}
|
|
|
|
InsertLoadOptionToList (CurrentLoadOption, &OrderVarInfo, Index);
|
|
}
|
|
}
|
|
|
|
if (!IsLoadOptionListCorrect (OptionType, &OrderVarInfo)) {
|
|
if (mNeedSyncBootOrder) {
|
|
mNeedSyncBootOrder = FALSE;
|
|
RemoveAllLoadOptions (OptionType);
|
|
SyncBdsLoadList (OptionType);
|
|
for (Link = GetFirstNode (OptionList); !IsNull (OptionList, Link); Link = GetNextNode (OptionList, Link)) {
|
|
CurrentLoadOption = BDS_OPTION_FROM_LINK (Link);
|
|
CurrentLoadOption->Connected = TRUE;
|
|
}
|
|
}
|
|
}
|
|
mNeedSyncBootOrder = TRUE;
|
|
|
|
FreeOrderVarInfo (&OrderVarInfo);
|
|
if (OptionType != H2O_BDS_LOAD_OPTION_TYPE_BOOT) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
//
|
|
// Expand all of BDS boot option
|
|
//
|
|
for (Link = GetFirstNode (OptionList); !IsNull (OptionList, Link); Link = GetNextNode (OptionList, Link)) {
|
|
CurrentLoadOption = BDS_OPTION_FROM_LINK (Link);
|
|
BdsServicesExpandLoadOption (&mH2OBdsServices, CurrentLoadOption);
|
|
}
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Return linked list of BDS load options derived from the UEFI order and option variables.
|
|
|
|
@param[in] This Option type value.
|
|
@param[in] OptionList A pointer to a pointer to the first list entry in a linked list. Each list entry
|
|
describes a single BDS load option using a "H2O_BDS_LOAD_OPTION" structure.
|
|
This structure can be retrieved from the list entry using the "BDS_OPTION_FROM_LINK()" macro.
|
|
|
|
@retval EFI_SUCCESS The function completed successfully.
|
|
@retval EFI_INVALID_PARAMETER OptionList is set to NULL.
|
|
@retval EFI_UNSUPPORTED Failed to find OS recovery info.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
GetBdsLoadList (
|
|
IN UINT8 OptionType,
|
|
OUT LIST_ENTRY **OptionList
|
|
)
|
|
{
|
|
H2O_BDS_OPTION_TYPE_INFO *OptionTypeInfo;
|
|
|
|
if (OptionList == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
OptionTypeInfo = GetOptionTypeInfo (OptionType);
|
|
if (OptionTypeInfo == NULL) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
SyncBdsLoadList (OptionType);
|
|
*OptionList = &OptionTypeInfo->OptionList;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
According to order in Boot list to update boot priority in BBS table.
|
|
|
|
@param[in] *LegacyBios A pointer to EFI_LEGACY_BIOS_PROTOCOL instance.
|
|
|
|
@retval EFI_SUCCESS Update boot priority successfully.
|
|
@retval EFI_INVALID_PARAMETER LegacyBios is NULL.
|
|
@retval EFI_UNSUPPORTED Fail to find option type info.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
UpdateBbsPriority (
|
|
IN EFI_LEGACY_BIOS_PROTOCOL *LegacyBios
|
|
)
|
|
{
|
|
BBS_TABLE *LocalBbsTable;
|
|
UINT16 BbsIndex;
|
|
UINT16 PriorityIndex;
|
|
LIST_ENTRY *OptionList;
|
|
LIST_ENTRY *Link;
|
|
H2O_BDS_LOAD_OPTION *BootOption;
|
|
BOOLEAN BootCurrentFound;
|
|
H2O_BDS_OPTION_TYPE_INFO *OptionTypeInfo;
|
|
|
|
if (LegacyBios == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
OptionTypeInfo = GetOptionTypeInfo (H2O_BDS_LOAD_OPTION_TYPE_BOOT);
|
|
if (OptionTypeInfo == NULL) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
BootCurrentFound = FALSE;
|
|
OptionList = &OptionTypeInfo->OptionList;
|
|
for (Link = GetFirstNode (OptionList), PriorityIndex = 0; !IsNull (OptionList, Link);
|
|
Link = GetNextNode (OptionList, Link)) {
|
|
BootOption = BDS_OPTION_FROM_LINK (Link);
|
|
if (!IsLegacyBootOption (BootOption->DevicePath)) {
|
|
continue;
|
|
}
|
|
BbsIndex = *((UINT16 *) ((UINT8 *) BootOption->LoadOptionalData + sizeof (BBS_TABLE)));
|
|
LegacyBios->GetBbsInfo (LegacyBios, NULL, NULL, NULL, &LocalBbsTable);
|
|
LocalBbsTable[BbsIndex].BootPriority = (UINT16) PriorityIndex;
|
|
if (!BootCurrentFound) {
|
|
if (BootOption->LoadOrder == mH2OBdsServices.BootCurrentLoadOption->LoadOrder) {
|
|
LocalBbsTable[BbsIndex].BootPriority = 0;
|
|
BootCurrentFound = TRUE;
|
|
} else {
|
|
LocalBbsTable[BbsIndex].BootPriority++;
|
|
}
|
|
}
|
|
PriorityIndex++;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Boot the legacy system with the boot option
|
|
|
|
@param Option The legacy boot option which have BBS device path
|
|
|
|
@retval EFI_SUCCESS It will never return EFI_SUCCESS. If boot success, system will enter
|
|
legacy OS directly.
|
|
@retval EFI_UNSUPPORTED There is no legacybios protocol, do not support legacy boot.
|
|
@retval Other Return the status of LegacyBios->LegacyBoot ().
|
|
**/
|
|
EFI_STATUS
|
|
LauchLegacyBootOption (
|
|
IN H2O_BDS_LOAD_OPTION *Option
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
|
|
|
|
Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
|
|
if (EFI_ERROR (Status)) {
|
|
//
|
|
// If no LegacyBios protocol we do not support legacy boot
|
|
//
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
//
|
|
// Notes: if we separate the int 19, then we don't need to refresh BBS
|
|
//
|
|
// to set BBS Table priority
|
|
//
|
|
UpdateBbsPriority (LegacyBios);
|
|
//
|
|
// Write boot to OS performance data for legacy boot.
|
|
//
|
|
WRITE_BOOT_TO_OS_PERFORMANCE_DATA;
|
|
|
|
DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Legacy Boot: %S\n", Option->Description));
|
|
return LegacyBios->LegacyBoot (
|
|
LegacyBios,
|
|
(BBS_BBS_DEVICE_PATH *) Option->DevicePath,
|
|
Option->LoadOptionalDataSize,
|
|
Option->LoadOptionalData
|
|
);
|
|
}
|
|
|
|
/**
|
|
Callback function to clear screen to prevent from screen has some garbage after
|
|
booting to shell environment.
|
|
|
|
@param[in] Event Event whose notification function is being invoked.
|
|
@param[in] Context Pointer to the notification function's context.
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
ShellEnvProtocolCallback (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
gST->ConOut->ClearScreen(gST->ConOut);
|
|
}
|
|
|
|
/**
|
|
According to device path and image handle to boot.
|
|
|
|
@param[in] ImageHandle Image handle.
|
|
@param[in] Option The boot option need to be processed.
|
|
@param[out] ExitDataSize Returned directly from gBS->StartImage ().
|
|
@param[out] ExitData Returned directly from gBS->StartImage ().
|
|
|
|
@retval EFI_SUCCESS Boot from recovery boot option successfully.
|
|
@retval Other Some errors occured during boot process.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
LaunchBootImage (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN H2O_BDS_LOAD_OPTION *Option,
|
|
OUT UINTN *ExitDataSize,
|
|
OUT CHAR16 **ExitData OPTIONAL
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;
|
|
EFI_EVENT ShellImageEvent;
|
|
|
|
|
|
Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);
|
|
ASSERT_EFI_ERROR (Status);
|
|
if (Status != EFI_SUCCESS) {
|
|
return Status;
|
|
}
|
|
|
|
if (Option->LoadOptionalDataSize != 0 &&
|
|
Option->LoadOptionalData != NULL &&
|
|
!((Option->LoadOptionalDataSize == 2 || Option->LoadOptionalDataSize == 6) &&
|
|
AsciiStrnCmp ((CHAR8 *) Option->LoadOptionalData, "RC", 2) == 0)) {
|
|
ImageInfo->LoadOptionsSize = Option->LoadOptionalDataSize;
|
|
ImageInfo->LoadOptions = Option->LoadOptionalData;
|
|
}
|
|
|
|
//
|
|
// Register Event for Shell Image
|
|
//
|
|
if (mShellEnvProtocolCallbackReg == NULL) {
|
|
Status = gBS->CreateEvent (
|
|
EVT_NOTIFY_SIGNAL,
|
|
TPL_CALLBACK,
|
|
ShellEnvProtocolCallback,
|
|
NULL,
|
|
&ShellImageEvent
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
Status = gBS->RegisterProtocolNotify (
|
|
&mShellEnvProtocol,
|
|
ShellImageEvent,
|
|
&mShellEnvProtocolCallbackReg
|
|
);
|
|
}
|
|
}
|
|
if (FeaturePcdGet (PcdH2OBdsCpBootBeforeSupported)) {
|
|
TriggerCpBootBefore ();
|
|
}
|
|
//
|
|
// Before calling the image, enable the Watchdog Timer
|
|
//
|
|
gBS->SetWatchdogTimer (PcdGet32 (PcdH2OBdsBootWatchdogTimeOut), 0x0000, 0x00, NULL);
|
|
|
|
//
|
|
// PostCode = 0xFB, UEFI Boot Start Image
|
|
//
|
|
POST_CODE (POST_BDS_START_IMAGE);
|
|
|
|
PERF_END (0, "PostBDS", NULL, 0);
|
|
WRITE_BOOT_TO_OS_PERFORMANCE_DATA;
|
|
if (FeaturePcdGet (PcdAutoCreateDummyBootOption)) {
|
|
BdsLibChangeToVirtualBootOrder ();
|
|
}
|
|
|
|
DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Image Start...\n"));
|
|
|
|
//
|
|
// Report status code for OS Loader StartImage.
|
|
//
|
|
REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderStart));
|
|
|
|
Status = gBS->StartImage (ImageHandle, ExitDataSize, ExitData);
|
|
DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Image Return Status = %r\n", Status));
|
|
|
|
//
|
|
// Clear the Watchdog Timer after the image returns
|
|
//
|
|
gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
|
|
if (FeaturePcdGet (PcdAutoCreateDummyBootOption)) {
|
|
SyncBootOrder ();
|
|
BdsLibRestoreBootOrderFromPhysicalBootOrder ();
|
|
}
|
|
if (FeaturePcdGet (PcdH2OBdsCpBootAfterSupported)) {
|
|
TriggerCpBootAfter ();
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
According to device path to boot from reocvery boot option.
|
|
|
|
@param[in] Option The boot option need to be processed.
|
|
@param[in] ExitDataSize Returned directly from gBS->StartImage ().
|
|
@param[in] ExitData Returned directly from gBS->StartImage ().
|
|
|
|
@retval EFI_SUCCESS Boot from recovery boot option successfully.
|
|
@retval Other Some errors occured during boot process.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
LaunchRecoveryOption (
|
|
IN H2O_BDS_LOAD_OPTION *Option,
|
|
OUT UINTN *ExitDataSize,
|
|
OUT CHAR16 **ExitData OPTIONAL
|
|
)
|
|
{
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
|
EFI_DEVICE_PATH_PROTOCOL *FilePath;
|
|
EFI_HANDLE Handle;
|
|
EFI_STATUS Status;
|
|
EFI_HANDLE ImageHandle;
|
|
|
|
|
|
DevicePath = Option->DevicePath;
|
|
Status = gBS->LocateDevicePath (
|
|
&gEfiSimpleFileSystemProtocolGuid,
|
|
&DevicePath,
|
|
&Handle
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
FilePath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME);
|
|
if (FilePath != NULL) {
|
|
Status = gBS->LoadImage (
|
|
TRUE,
|
|
gImageHandle,
|
|
FilePath,
|
|
NULL,
|
|
0,
|
|
&ImageHandle
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
Status = LaunchBootImage (ImageHandle, Option, ExitDataSize, ExitData);
|
|
}
|
|
|
|
FreePool (FilePath);
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Launch a BDS boot option.
|
|
|
|
@param[in] BdsLoadOption A pointer to BDS load option.
|
|
@param[out] ExitDataSize Pointer to the size, in bytes, of ExitData.
|
|
@param[out] ExitData Pointer to a pointer to a data buffer that includes a Null-terminated
|
|
string, optionally followed by additional binary data.
|
|
|
|
@retval EFI_SUCCESS Boot from the input boot option successfully.
|
|
@retval EFI_INVALID_PARAMETER BdsLoadOption is NULL.
|
|
@retval EFI_NOT_FOUND If the Device Path is not found in the system
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
LaunchBootOption (
|
|
IN OUT H2O_BDS_LOAD_OPTION *BdsLoadOption,
|
|
OUT UINTN *ExitDataSize,
|
|
OUT CHAR16 **ExitData OPTIONAL
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_STATUS RecoveryBootStatus;
|
|
EFI_HANDLE Handle;
|
|
EFI_HANDLE ImageHandle;
|
|
EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
|
|
EFI_DEVICE_PATH_PROTOCOL *RemovableMediaFilePath;
|
|
EFI_BLOCK_IO_PROTOCOL *BlkIo;
|
|
VOID *Buffer;
|
|
EFI_STATUS LocateDevicePathStatus;
|
|
H2O_BDS_LOAD_OPTION *CurrentBootOption;
|
|
LIST_ENTRY *Link;
|
|
BOOLEAN IsLegacyBoot;
|
|
|
|
EFI_DEVICE_PATH *UpdatedHttpDevicePath;
|
|
EFI_HANDLE RamDiskHandle;
|
|
EFI_DEVICE_PATH_PROTOCOL *CurrentBootDevicePath;
|
|
|
|
//
|
|
// All the driver options should have been processed since now boot will be performed.
|
|
//
|
|
PERF_END (0, BDS_TOK, NULL, 0);
|
|
|
|
PERF_START (0, "PostBDS", NULL, 0);
|
|
|
|
if (BdsLoadOption == NULL || BdsLoadOption->DevicePath == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Before boot to device, always clean BootNext variable.
|
|
//
|
|
CommonSetVariable (L"BootNext", &gEfiGlobalVariableGuid, 0, 0, NULL);
|
|
|
|
IsLegacyBoot = (BOOLEAN) ((DevicePathType (BdsLoadOption->DevicePath) == BBS_DEVICE_PATH) &&
|
|
(DevicePathSubType (BdsLoadOption->DevicePath) == BBS_BBS_DP));
|
|
if (!IsLegacyBoot) {
|
|
EnableOptimalTextMode ();
|
|
}
|
|
|
|
//
|
|
// Follow EDKII policy, Set "BootCurrent" variable before ready to boot event
|
|
//
|
|
if (BdsLoadOption->LoadOrderVarName[0] == L'B') {
|
|
//
|
|
// For a temporary boot (i.e. a boot by selected a EFI Shell using "Boot From File"),
|
|
// Boot Current is actually not valid.
|
|
// In this case, "BootCurrent" is not created.
|
|
// Only create the BootCurrent variable when it points to a valid Boot#### variable.
|
|
//
|
|
CommonSetVariable (
|
|
EFI_BOOT_CURRENT_VARIABLE_NAME,
|
|
&gEfiGlobalVariableGuid,
|
|
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
|
|
sizeof (UINT16),
|
|
&BdsLoadOption->LoadOrder
|
|
);
|
|
BdsServicesConvertVarToLoadOption (
|
|
&mH2OBdsServices,
|
|
EFI_BOOT_CURRENT_VARIABLE_NAME,
|
|
&gEfiGlobalVariableGuid,
|
|
&mH2OBdsServices.BootCurrentLoadOption
|
|
);
|
|
}
|
|
|
|
if ((BdsLoadOption->Attributes & LOAD_OPTION_CATEGORY) == LOAD_OPTION_CATEGORY_BOOT) {
|
|
if (FeaturePcdGet (PcdH2OBdsCpReadyToBootBeforeSupported)) {
|
|
TriggerCpReadyToBootBefore ();
|
|
}
|
|
//
|
|
// PostCode = 0x2E, Last Chipset initial before boot to OS
|
|
//
|
|
POST_CODE (BDS_READY_TO_BOOT_EVENT);
|
|
//
|
|
// Signal the EVT_SIGNAL_READY_TO_BOOT event
|
|
//
|
|
EfiSignalEventReadyToBoot();
|
|
if (FeaturePcdGet (PcdH2OBdsCpReadyToBootAfterSupported)) {
|
|
TriggerCpReadyToBootAfter ();
|
|
}
|
|
|
|
if (FeaturePcdGet (PcdMemoryMapConsistencyCheck)) {
|
|
CheckRtAndBsMemUsage ();
|
|
}
|
|
}
|
|
|
|
if (IsLegacyBoot) {
|
|
if (!FeaturePcdGet (PcdH2OCsmSupported)) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
//
|
|
// TODO: Many CRB doesn't support CSM, we need remove legacy related code in BDS to reduce code size in the future.
|
|
//
|
|
// Check to see if we should legacy BOOT. If yes then do the legacy boot
|
|
//
|
|
if (FeaturePcdGet (PcdAutoCreateDummyBootOption) && BdsLibIsBootOrderHookEnabled ()) {
|
|
BdsLibRestoreBootOrderFromPhysicalBootOrder ();
|
|
}
|
|
//
|
|
// PostCode = 0x2F, Start to boot Legacy OS
|
|
//
|
|
POST_CODE (BDS_GO_LEGACY_BOOT);
|
|
return LauchLegacyBootOption (BdsLoadOption);
|
|
}
|
|
//
|
|
// PostCode = 0x30, Start to boot UEFI OS
|
|
//
|
|
POST_CODE (BDS_GO_UEFI_BOOT);
|
|
|
|
#ifndef MDEPKG_NDEBUG
|
|
DumpMemoryMap();
|
|
#endif
|
|
|
|
DEBUG_CODE_BEGIN();
|
|
if (BdsLoadOption->Description == NULL) {
|
|
DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Booting from unknown device path\n"));
|
|
} else {
|
|
DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Booting %S\n", BdsLoadOption->Description));
|
|
}
|
|
DEBUG_CODE_END();
|
|
|
|
//
|
|
// Report status code for OS Loader LoadImage.
|
|
//
|
|
REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderLoad));
|
|
|
|
if (IsPxeBoot (BdsLoadOption->DevicePath)) {
|
|
DisableQuietBoot ();
|
|
}
|
|
|
|
CurrentBootOption = BdsLoadOption;
|
|
if (BdsLoadOption->Expanded) {
|
|
if (IsListEmpty (&BdsLoadOption->ExpandedLoadOptions)) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
Link = GetFirstNode (&BdsLoadOption->ExpandedLoadOptions);
|
|
CurrentBootOption = BDS_OPTION_FROM_LINK (Link);
|
|
}
|
|
|
|
Status = EFI_NOT_FOUND;
|
|
RemovableMediaFilePath = NULL;
|
|
ImageHandle = NULL;
|
|
RamDiskHandle = NULL;
|
|
while (CurrentBootOption != NULL) {
|
|
RamDiskHandle = NULL;
|
|
UpdatedHttpDevicePath = NULL;
|
|
CurrentBootDevicePath = CurrentBootOption->DevicePath;
|
|
if (IsHttpBootHandle (CurrentBootOption->DevicePath)) {
|
|
//
|
|
// If HTTP boot load the EFI file, the status will be EFI_BUFFER_TOO_SMALL.
|
|
// The CurrentBootOption->DevicePath need to update if HttpBooDxe update the DevicePath.
|
|
// GetDevicePathSize return 0, it means the DevicePath is invalid, so CurrentBootOption->DevicePath should be update.
|
|
//
|
|
Status = ProcessHttpUriBoot (CurrentBootOption->DevicePath, &UpdatedHttpDevicePath, &RamDiskHandle);
|
|
CurrentBootOption->DevicePath = UpdatedHttpDevicePath;
|
|
//
|
|
// Buffer too small means HttpBootDxe will to load PE application, not ISO file.
|
|
//
|
|
if (EFI_ERROR (Status) && (Status != EFI_BUFFER_TOO_SMALL)) {
|
|
break;
|
|
}
|
|
//
|
|
// Update boot device path to file path of RamDisk\SimpleFileSystem\efi\boot\boot$(ARCH).efi
|
|
//
|
|
CurrentBootDevicePath = UpdatedHttpDevicePath;
|
|
}
|
|
|
|
Status = gBS->LoadImage (
|
|
TRUE,
|
|
gImageHandle,
|
|
CurrentBootDevicePath,
|
|
NULL,
|
|
0,
|
|
&ImageHandle
|
|
);
|
|
//
|
|
// If we didn't find an image, we may need to load the default boot behavior for the device.
|
|
//
|
|
if (EFI_ERROR (Status)) {
|
|
//
|
|
// Find a Simple File System protocol on the device path.
|
|
// If the remaining device path is set to end then no Files are being specified, so try the removable media file name.
|
|
//
|
|
TempDevicePath = CurrentBootOption->DevicePath;
|
|
LocateDevicePathStatus = gBS->LocateDevicePath (
|
|
&gEfiSimpleFileSystemProtocolGuid,
|
|
&TempDevicePath,
|
|
&Handle
|
|
);
|
|
if (!EFI_ERROR (LocateDevicePathStatus) && IsDevicePathEnd (TempDevicePath)) {
|
|
RemovableMediaFilePath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME);
|
|
if (RemovableMediaFilePath != NULL) {
|
|
//
|
|
// Issue a dummy read to the device to check for media change.
|
|
// When the removable media is changed, any Block IO read/write will cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is returned.
|
|
// After the Block IO protocol is reinstalled, subsequent Block IO read/write will success.
|
|
//
|
|
Status = gBS->HandleProtocol (
|
|
Handle,
|
|
&gEfiBlockIoProtocolGuid,
|
|
(VOID **) &BlkIo
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
Buffer = AllocatePool (BlkIo->Media->BlockSize);
|
|
if (Buffer != NULL) {
|
|
BlkIo->ReadBlocks (
|
|
BlkIo,
|
|
BlkIo->Media->MediaId,
|
|
0,
|
|
BlkIo->Media->BlockSize,
|
|
Buffer
|
|
);
|
|
FreePool (Buffer);
|
|
}
|
|
}
|
|
|
|
Status = gBS->LoadImage (
|
|
TRUE,
|
|
gImageHandle,
|
|
RemovableMediaFilePath,
|
|
NULL,
|
|
0,
|
|
&ImageHandle
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
FreePool (RemovableMediaFilePath);
|
|
RemovableMediaFilePath = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (Status == EFI_SUCCESS || !BdsLoadOption->Expanded) {
|
|
break;
|
|
}
|
|
|
|
Link = GetNextNode (&BdsLoadOption->ExpandedLoadOptions, &CurrentBootOption->Link);
|
|
if (Link == &BdsLoadOption->ExpandedLoadOptions) {
|
|
CurrentBootOption = BDS_OPTION_FROM_LINK (BdsLoadOption->ExpandedLoadOptions.BackLink);
|
|
break;
|
|
}
|
|
|
|
CurrentBootOption = BDS_OPTION_FROM_LINK (Link);
|
|
}
|
|
|
|
if (Status == EFI_SUCCESS) {
|
|
//
|
|
// Provide the image with it's load options
|
|
//
|
|
Status = LaunchBootImage (ImageHandle, CurrentBootOption, ExitDataSize, ExitData);
|
|
|
|
//
|
|
// Destroy HTTP boot created RamDisk to avoid it was out of manage.
|
|
//
|
|
if (RamDiskHandle != NULL) {
|
|
DestroyRamDisk (DevicePathFromHandle(RamDiskHandle));
|
|
}
|
|
}
|
|
if (EFI_ERROR (Status) && RemovableMediaFilePath == NULL && CurrentBootOption != NULL && IsUefiOsFilePath (CurrentBootOption->DevicePath)) {
|
|
//
|
|
// Try to boot from recovery boot option and only update status to EFI_SUCCESS,
|
|
// if boot from this recovery file path is successful.
|
|
//
|
|
RecoveryBootStatus = LaunchRecoveryOption (CurrentBootOption, ExitDataSize, ExitData);
|
|
if (!EFI_ERROR (RecoveryBootStatus)) {
|
|
Status = EFI_SUCCESS;
|
|
}
|
|
}
|
|
if (EFI_ERROR (Status) && CurrentBootOption != NULL && IS_HW_VENDOR_DEVICE_PATH (CurrentBootOption->DevicePath)) {
|
|
//
|
|
// Always return success if launch boot option by specific vendor device path.
|
|
//
|
|
Status = EFI_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Clear BootCurrent and set BootPrev variables.
|
|
//
|
|
CommonSetVariable (EFI_BOOT_CURRENT_VARIABLE_NAME, &gEfiGlobalVariableGuid, 0, 0, NULL);
|
|
if (mH2OBdsServices.BootCurrentLoadOption != NULL) {
|
|
BdsServicesFreeLoadOption (&mH2OBdsServices, mH2OBdsServices.BootCurrentLoadOption);
|
|
mH2OBdsServices.BootCurrentLoadOption = NULL;
|
|
}
|
|
CommonSetVariable (
|
|
H2O_BOOT_PREVIOUS_VARIABLE_NAME,
|
|
&gEfiGenericVariableGuid,
|
|
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
|
|
sizeof (UINT16),
|
|
&BdsLoadOption->LoadOrder
|
|
);
|
|
if (mH2OBdsServices.BootPrevLoadOption != NULL) {
|
|
BdsServicesFreeLoadOption (&mH2OBdsServices, mH2OBdsServices.BootPrevLoadOption);
|
|
mH2OBdsServices.BootPrevLoadOption = NULL;
|
|
}
|
|
BdsServicesConvertVarToLoadOption (
|
|
&mH2OBdsServices,
|
|
H2O_BOOT_PREVIOUS_VARIABLE_NAME,
|
|
&gEfiGenericVariableGuid,
|
|
&mH2OBdsServices.BootPrevLoadOption
|
|
);
|
|
//
|
|
// Signal BIOS after the image returns
|
|
//
|
|
SignalImageReturns ();
|
|
|
|
if (RemovableMediaFilePath != NULL) {
|
|
FreePool (RemovableMediaFilePath);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Launch a BDS driver option.
|
|
|
|
@param[in] BdsLoadOption A pointer to BDS load option.
|
|
@param[out] ExitDataSize Pointer to the size, in bytes, of ExitData.
|
|
@param[out] ExitData Pointer to a pointer to a data buffer that includes a Null-terminated
|
|
string, optionally followed by additional binary data.
|
|
|
|
@retval EFI_SUCCESS Boot from the input boot option successfully.
|
|
@retval EFI_INVALID_PARAMETER BdsLoadOption is NULL.
|
|
@retval EFI_NOT_FOUND If the Device Path is not found in the system
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
LaunchDriverOption (
|
|
IN OUT H2O_BDS_LOAD_OPTION *BdsLoadOption,
|
|
OUT UINTN *ExitDataSize,
|
|
OUT CHAR16 **ExitData OPTIONAL
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_HANDLE ImageHandle;
|
|
EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;
|
|
|
|
if (BdsLoadOption == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if ((BdsLoadOption->Attributes & LOAD_OPTION_ACTIVE) != LOAD_OPTION_ACTIVE) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
//
|
|
// Make sure the driver path is connected.
|
|
//
|
|
BdsLibConnectDevicePath (BdsLoadOption->DevicePath);
|
|
|
|
//
|
|
// Load and start the image that Driver#### describes
|
|
//
|
|
Status = gBS->LoadImage (
|
|
FALSE,
|
|
gImageHandle,
|
|
BdsLoadOption->DevicePath,
|
|
NULL,
|
|
0,
|
|
&ImageHandle
|
|
);
|
|
if (Status != EFI_SUCCESS) {
|
|
return Status;
|
|
}
|
|
|
|
gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);
|
|
|
|
if (BdsLoadOption->LoadOptionalDataSize != 0) {
|
|
ImageInfo->LoadOptionsSize = BdsLoadOption->LoadOptionalDataSize;
|
|
ImageInfo->LoadOptions = BdsLoadOption->LoadOptionalData;
|
|
}
|
|
|
|
Status = gBS->StartImage (ImageHandle, ExitDataSize, ExitData);
|
|
DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Driver Return Status = %r\n", Status));
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Initialize gH2OBdsServicesProtocolGuid protocol data and install gH2OBdsServicesProtocolGuid protocol.
|
|
|
|
@retval EFI_SUCCESS Install gH2OBdsServicesProtocolGuid protocol successfully.
|
|
@return Others Any error occurred while installing gH2OBdsServicesProtocolGuid protocol.
|
|
**/
|
|
EFI_STATUS
|
|
InstallH2OBdsServicesProtocol (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_HANDLE Handle;
|
|
EFI_STATUS Status;
|
|
H2O_BDS_LOAD_OPTION *LoadOption;
|
|
UINTN Index;
|
|
|
|
for (Index = 0; Index < sizeof (mOptionTypeInfo) / sizeof (H2O_BDS_OPTION_TYPE_INFO); Index++) {
|
|
InitializeListHead (&mOptionTypeInfo[Index].OptionList);
|
|
}
|
|
|
|
Status = BdsServicesConvertVarToLoadOption (&mH2OBdsServices, EFI_BOOT_NEXT_VARIABLE_NAME, &gEfiGlobalVariableGuid, &LoadOption);
|
|
if (Status == EFI_SUCCESS) {
|
|
mH2OBdsServices.BootNextLoadOption = LoadOption;
|
|
}
|
|
Handle = NULL;
|
|
return gBS->InstallMultipleProtocolInterfaces (
|
|
&Handle,
|
|
&gH2OBdsServicesProtocolGuid,
|
|
&mH2OBdsServices,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
/**
|
|
Return the current value of the OsIndications and OsIndicationsSupported UEFI variable.
|
|
|
|
@param[in] This A Pointer to current instance of this protocol.
|
|
@param[out] OsIndications A pointer to contain the value of the OsIndications.
|
|
@param[out] OsIndicationsSupported A pointer to contain the value of the OsIndicationsSupported.
|
|
|
|
@retval EFI_SUCCESS Get OsIndications and OsIndicationsSupported successfully.
|
|
@retval EFI_INVALID_PARAMETER OsIndications or OsIndicationsSupported is NULL.
|
|
@retval EFI_NOT_FOUND Cannot find OsIndications or OsIndicationsSupported value.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
BdsServicesGetOsIndications (
|
|
IN H2O_BDS_SERVICES_PROTOCOL *This,
|
|
OUT UINT64 *OsIndications,
|
|
OUT UINT64 *OsIndicationsSupported
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT64 Indications;
|
|
UINT64 IndicationsSupport;
|
|
UINTN Size;
|
|
|
|
if (OsIndications == NULL || OsIndicationsSupported == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Size = sizeof (Indications);
|
|
Status = CommonGetVariable (
|
|
EFI_OS_INDICATIONS_VARIABLE_NAME,
|
|
&gEfiGlobalVariableGuid,
|
|
&Size,
|
|
&Indications
|
|
);
|
|
if (Status != EFI_SUCCESS) {
|
|
return Status;
|
|
}
|
|
Size = sizeof (IndicationsSupport);
|
|
Status = CommonGetVariable (
|
|
EFI_OS_INDICATIONS_SUPPORT_VARIABLE_NAME,
|
|
&gEfiGlobalVariableGuid,
|
|
&Size,
|
|
&IndicationsSupport
|
|
);
|
|
if (Status != EFI_SUCCESS) {
|
|
return Status;
|
|
}
|
|
|
|
*OsIndications = Indications;
|
|
*OsIndicationsSupported = IndicationsSupport;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Return the current value of the OS loader timeout.
|
|
|
|
@param[in] This A Pointer to current instance of this protocol.
|
|
@param[out] Timeout A pointer to contain the value of the timeout.
|
|
|
|
@retval EFI_SUCCESS Get Timeout value successfully.
|
|
@retval EFI_INVALID_PARAMETER Timeout is NULL.
|
|
@retval EFI_NOT_FOUND Cannot find Timeout value.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
BdsServicesGetTimeout (
|
|
IN H2O_BDS_SERVICES_PROTOCOL *This,
|
|
OUT UINT16 *Timeout
|
|
)
|
|
{
|
|
UINTN Size;
|
|
|
|
if (Timeout == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
Size = sizeof (UINT16);
|
|
return CommonGetVariable (
|
|
EFI_TIME_OUT_VARIABLE_NAME,
|
|
&gEfiGlobalVariableGuid,
|
|
&Size,
|
|
Timeout
|
|
);
|
|
}
|
|
|
|
/**
|
|
Return the current boot mode, such as S4 resume, diagnostics, full configuration, etc.
|
|
|
|
@param[in] This A Pointer to current instance of this protocol.
|
|
@param[in] BootMode A pointer to contain the value of the boot mode.
|
|
|
|
@retval EFI_SUCCESS Get BootMode successfully.
|
|
@retval EFI_INVALID_PARAMETER BootMode is NULL.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
BdsServicesGetBootMode (
|
|
IN H2O_BDS_SERVICES_PROTOCOL *This,
|
|
OUT EFI_BOOT_MODE *BootMode
|
|
)
|
|
{
|
|
if (BootMode == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
*BootMode = GetBootModeHob ();
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Return the current boot type, uch as legacy, UEFI or dual.
|
|
|
|
@param[in] This A Pointer to current instance of this protocol.
|
|
@param[in] BootType A pointer to contain the value of the boot mode.
|
|
|
|
@retval EFI_SUCCESS Get BootType successfully.
|
|
@retval EFI_INVALID_PARAMETER BootType is NULL.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
BdsServicesGetBootType (
|
|
IN H2O_BDS_SERVICES_PROTOCOL *This,
|
|
OUT UINT8 *BootType
|
|
)
|
|
{
|
|
if (BootType == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
*BootType = H2OGetBootType ();
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
/**
|
|
Return linked list of BDS boot options derived from the BootOrder and Boot#### UEFI variables.
|
|
|
|
@param[in] This A Pointer to current instance of this protocol.
|
|
@param[out] BootList Pointer to linked list of BDS boot options derived from the BootOrder and Boot#### UEFI variables.
|
|
|
|
@retval EFI_SUCCESS Get boot list successfully.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
BdsServicesGetBootList (
|
|
IN H2O_BDS_SERVICES_PROTOCOL *This,
|
|
OUT LIST_ENTRY **BootList
|
|
)
|
|
{
|
|
return GetBdsLoadList (H2O_BDS_LOAD_OPTION_TYPE_BOOT, BootList);
|
|
}
|
|
|
|
/**
|
|
Return linked list of BDS boot options derived from the DriverOrder and Driver#### UEFI variables.
|
|
|
|
@param[in] This A Pointer to current instance of this protocol.
|
|
@param[out] DriverList Pointer to linked list of BDS boot options derived from the DriverOrder and Driver#### UEFI variables.
|
|
|
|
@retval EFI_SUCCESS Get driver list successfully.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
BdsServicesGetDriverList (
|
|
IN H2O_BDS_SERVICES_PROTOCOL *This,
|
|
OUT LIST_ENTRY **DriverList
|
|
)
|
|
{
|
|
return GetBdsLoadList (H2O_BDS_LOAD_OPTION_TYPE_DRIVER, DriverList);
|
|
}
|
|
|
|
/**
|
|
Get load order from input load order type.
|
|
|
|
@param[in] Type Input load order type.
|
|
|
|
@return the load order number get from load order type.
|
|
**/
|
|
STATIC
|
|
UINT16
|
|
GetLoadOrderFromType (
|
|
IN UINT16 Type
|
|
)
|
|
{
|
|
UINT16 LoadOrder;
|
|
UINTN DataSize;
|
|
|
|
|
|
LoadOrder = BOOT_NEXT_LOAD_ORDER;
|
|
if (Type != BOOT_PREVIOUS_LOAD_ORDER && Type != BOOT_CURRENT_LOAD_ORDER && Type != BOOT_NEXT_LOAD_ORDER) {
|
|
return LoadOrder;
|
|
}
|
|
|
|
DataSize = sizeof (UINT16);
|
|
switch (Type) {
|
|
|
|
case BOOT_PREVIOUS_LOAD_ORDER:
|
|
gRT->GetVariable (H2O_BOOT_PREVIOUS_VARIABLE_NAME, &gEfiGenericVariableGuid, NULL, &DataSize, &LoadOrder);
|
|
break;
|
|
|
|
case BOOT_CURRENT_LOAD_ORDER:
|
|
gRT->GetVariable (EFI_BOOT_CURRENT_VARIABLE_NAME, &gEfiGlobalVariableGuid, NULL, &DataSize, &LoadOrder);
|
|
break;
|
|
|
|
case BOOT_NEXT_LOAD_ORDER:
|
|
gRT->GetVariable (EFI_BOOT_NEXT_VARIABLE_NAME, &gEfiGlobalVariableGuid, NULL, &DataSize, &LoadOrder);
|
|
break;
|
|
}
|
|
|
|
return LoadOrder;
|
|
}
|
|
|
|
|
|
/**
|
|
Create a BDS load option in a buffer allocated from pool.
|
|
|
|
@param[in] This A Pointer to current instance of this protocol.
|
|
@param[in] DriverOrBoot Boolean that specifies whether this load option represents a Driver load option
|
|
(FALSE) or Boot load option (TRUE).
|
|
@param[in] OptionName A Null-terminated string that is the name of the vendor's variable.
|
|
@param[in] OptionGuid A unique identifier for the vendor.
|
|
@param[in] Attributes The attributes for this load option entry.
|
|
@param[in] DevicePath A Pointer to a packed array of UEFI device paths.
|
|
@param[in] Description The user readable description for the load option.
|
|
@param[in] OptionalData A Pointer to optional data for load option.
|
|
@param[in] OptionalDataSize The size by bytes of optional data.
|
|
@param[out] LoadOption Dynamically allocated memory that contains a new created H2O_BDS_LOAD_OPTION
|
|
instance. Caller is responsible freeing the buffer
|
|
|
|
@retval EFI_SUCCESS Create load option successfully.
|
|
@retval EFI_INVALID_PARAMETER DevicePath is NULL or LoadOption is NULL.
|
|
@retval EFI_INVALID_PARAMETER The OptionName is correct boot#### or driver#### variable name.
|
|
@retval EFI_OUT_OF_RESOURCES Allocate memory to create H2O_BDS_LOAD_OPTION failed.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
BdsServicesCreateLoadOption (
|
|
IN H2O_BDS_SERVICES_PROTOCOL *This,
|
|
IN BOOLEAN DriverOrBoot,
|
|
IN CONST CHAR16 *OptionName OPTIONAL,
|
|
IN CONST EFI_GUID *OptionGuid OPTIONAL,
|
|
IN UINT32 Attributes,
|
|
IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,
|
|
IN CONST CHAR16 *Description OPTIONAL,
|
|
IN CONST UINT8 *OptionalData OPTIONAL,
|
|
IN UINT32 OptionalDataSize,
|
|
OUT H2O_BDS_LOAD_OPTION **LoadOption
|
|
)
|
|
{
|
|
return BdsServicesCreateLoadOption2 (
|
|
This,
|
|
DriverOrBoot == DRIVER_OPTION ? H2O_BDS_LOAD_OPTION_TYPE_DRIVER : H2O_BDS_LOAD_OPTION_TYPE_BOOT,
|
|
OptionName,
|
|
OptionGuid,
|
|
Attributes,
|
|
DevicePath,
|
|
Description,
|
|
OptionalData,
|
|
OptionalDataSize,
|
|
LoadOption
|
|
);
|
|
}
|
|
|
|
/**
|
|
Create a BDS load option in a buffer allocated from pool.
|
|
|
|
These functions allocation and initialize a BDS load option structure. They do not create a UEFI variable nor do
|
|
they add the load option to one of the BDS load option lists.
|
|
|
|
@param[in] This A Pointer to current instance of this protocol.
|
|
@param[in] OptionType Enumerated value that specifies the type of load option. Valid values are:
|
|
H2O_BDS_LOAD_OPTION_TYPE_DRIVER (0)
|
|
H2O_BDS_LOAD_OPTION_TYPE_BOOT (1)
|
|
H2O_BDS_LOAD_OPTION_TYPE_SYSPREP (2)
|
|
H2O_BDS_LOAD_OPTION_TYPE_OS_RECOVERY (3)
|
|
H2O_BDS_LOAD_OPTION_TYPE_PLATFORM_RECOVERY (4)
|
|
@param[in] OptionName A Null-terminated string that is the name of the vendor's variable.
|
|
@param[in] OptionGuid A unique identifier for the vendor.
|
|
@param[in] Attributes The attributes for this load option entry.
|
|
@param[in] DevicePath A Pointer to a packed array of UEFI device paths.
|
|
@param[in] Description The user readable description for the load option.
|
|
@param[in] OptionalData A Pointer to optional data for load option.
|
|
@param[in] OptionalDataSize The size by bytes of optional data.
|
|
|
|
@retval EFI_SUCCESS Create load option successfully.
|
|
@retval EFI_INVALID_PARAMETER DevicePath is NULL or LoadOption is NULL.
|
|
@retval EFI_INVALID_PARAMETER The OptionName is correct boot#### or driver#### variable name.
|
|
@retval EFI_OUT_OF_RESOURCES Allocate memory to create H2O_BDS_LOAD_OPTION failed.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
BdsServicesCreateLoadOption2 (
|
|
IN H2O_BDS_SERVICES_PROTOCOL *This,
|
|
IN UINT8 OptionType,
|
|
IN CONST CHAR16 *OptionName OPTIONAL,
|
|
IN CONST EFI_GUID *OptionGuid OPTIONAL,
|
|
IN UINT32 Attributes,
|
|
IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,
|
|
IN CONST CHAR16 *Description OPTIONAL,
|
|
IN CONST UINT8 *OptionalData OPTIONAL,
|
|
IN UINT32 OptionalDataSize,
|
|
OUT H2O_BDS_LOAD_OPTION **LoadOption
|
|
)
|
|
{
|
|
H2O_BDS_LOAD_OPTION *CurrentOption;
|
|
EFI_STATUS Status;
|
|
UINTN Index;
|
|
UINTN OptionNameLen;
|
|
|
|
if (DevicePath == NULL || LoadOption == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Status = EFI_SUCCESS;
|
|
CurrentOption = AllocateZeroPool (sizeof (H2O_BDS_LOAD_OPTION));
|
|
if (CurrentOption == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
CurrentOption->Signature = H2O_BDS_LOAD_OPTION_SIGNATURE;
|
|
InitializeListHead (&CurrentOption->Link);
|
|
CurrentOption->DevicePath = AllocateCopyPool (GetDevicePathSize (DevicePath), DevicePath);
|
|
if (CurrentOption->DevicePath == NULL) {
|
|
InternalFreeBdsLoadOption (CurrentOption);
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
CurrentOption->Connected = FALSE;
|
|
|
|
//
|
|
// Determine option type and load order
|
|
//
|
|
if (OptionName != NULL && OptionGuid != NULL) {
|
|
if (IsBootPreviousVariable (OptionName, OptionGuid)) {
|
|
CurrentOption->OptionType = H2O_BDS_LOAD_OPTION_TYPE_BOOT;
|
|
CurrentOption->LoadOrder = GetLoadOrderFromType (BOOT_PREVIOUS_LOAD_ORDER);
|
|
} else if (IsBootCurrentVariable (OptionName, OptionGuid)) {
|
|
CurrentOption->OptionType = H2O_BDS_LOAD_OPTION_TYPE_BOOT;
|
|
CurrentOption->LoadOrder = GetLoadOrderFromType (BOOT_CURRENT_LOAD_ORDER);
|
|
} else if (IsBootNextVariable (OptionName, OptionGuid)) {
|
|
CurrentOption->OptionType = H2O_BDS_LOAD_OPTION_TYPE_BOOT;
|
|
CurrentOption->LoadOrder = GetLoadOrderFromType (BOOT_NEXT_LOAD_ORDER);
|
|
} else {
|
|
OptionNameLen = StrLen (OptionName);
|
|
for (Index = 0; Index < sizeof (mOptionTypeInfo) / sizeof (H2O_BDS_OPTION_TYPE_INFO); Index++) {
|
|
if (StrLen (mOptionTypeInfo[Index].OptionVarPrefixName) + 4 == OptionNameLen &&
|
|
StrnCmp (mOptionTypeInfo[Index].OptionVarPrefixName, OptionName, OptionNameLen - 4) == 0 &&
|
|
IsValidOptionNumber (&OptionName[OptionNameLen - 4])) {
|
|
break;
|
|
}
|
|
}
|
|
if (Index == sizeof (mOptionTypeInfo) / sizeof (H2O_BDS_OPTION_TYPE_INFO)) {
|
|
InternalFreeBdsLoadOption (CurrentOption);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
CurrentOption->OptionType = mOptionTypeInfo[Index].OptionType;
|
|
CurrentOption->LoadOrder = GetOptionNumber (&OptionName[OptionNameLen - 4]);
|
|
}
|
|
StrCpyS (CurrentOption->LoadOrderVarName, sizeof(CurrentOption->LoadOrderVarName) / sizeof(CHAR16), OptionName);
|
|
CopyGuid (&CurrentOption->LoadOrderVarGuid, OptionGuid);
|
|
} else {
|
|
CurrentOption->OptionType = OptionType;
|
|
}
|
|
CurrentOption->DriverOrBoot = (CurrentOption->OptionType == H2O_BDS_LOAD_OPTION_TYPE_BOOT) ? BOOT_OPTION : DRIVER_OPTION;
|
|
|
|
CurrentOption->Expanded = FALSE;
|
|
InitializeListHead (&CurrentOption->ExpandedLoadOptions);
|
|
CurrentOption->Attributes = Attributes;
|
|
|
|
if (Description != NULL) {
|
|
CurrentOption->Description = AllocateCopyPool (StrSize (Description), Description);
|
|
if (CurrentOption->Description == NULL) {
|
|
InternalFreeBdsLoadOption (CurrentOption);
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
}
|
|
if (OptionalDataSize != 0 && OptionalData != NULL) {
|
|
CurrentOption->LoadOptionalData = AllocateCopyPool (OptionalDataSize, OptionalData);
|
|
if (CurrentOption->LoadOptionalData == NULL) {
|
|
InternalFreeBdsLoadOption (CurrentOption);
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
CurrentOption->LoadOptionalDataSize = OptionalDataSize;
|
|
}
|
|
|
|
*LoadOption = CurrentOption;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Free the memory associated with a BDS load option.
|
|
|
|
@param[in] This A Pointer to current instance of this protocol.
|
|
@param[in] LoadOption The allocated H2O_BDS_LOAD_OPTION instance to free.
|
|
|
|
@retval EFI_SUCCESS Get BootType successfully.
|
|
@retval EFI_INVALID_PARAMETER LoadOption is NULL.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
BdsServicesFreeLoadOption (
|
|
IN H2O_BDS_SERVICES_PROTOCOL *This,
|
|
IN H2O_BDS_LOAD_OPTION *LoadOption
|
|
)
|
|
{
|
|
LIST_ENTRY *ExpandedOptions;
|
|
LIST_ENTRY *Link;
|
|
LIST_ENTRY *CurrentLink;
|
|
|
|
if (LoadOption == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
if (LoadOption->Expanded) {
|
|
ExpandedOptions = &LoadOption->ExpandedLoadOptions;
|
|
for (Link = GetFirstNode (ExpandedOptions); !IsNull (ExpandedOptions, Link); Link = GetNextNode (ExpandedOptions, Link)) {
|
|
CurrentLink = Link;
|
|
Link = CurrentLink->BackLink;
|
|
RemoveEntryList (CurrentLink);
|
|
InternalFreeBdsLoadOption (BDS_OPTION_FROM_LINK (CurrentLink));
|
|
}
|
|
}
|
|
InternalFreeBdsLoadOption (LoadOption);
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Converts a UEFI variable formatted as a UEFI load option to a BDS load option.
|
|
|
|
@param[in] This A Pointer to current instance of this protocol.
|
|
@param[in] VariableName A Null-terminated string that is the name of the vendor's variable.
|
|
@param[in] VariableGuid A unique identifier for the vendor.
|
|
@param[out] BdsLoadOption Dynamically allocated memory that contains a new created H2O_BDS_LOAD_OPTION
|
|
instance. Caller is responsible freeing the buffer.
|
|
|
|
@retval EFI_SUCCESS Convert BDS load option to UEFI load option successfully.
|
|
@retval EFI_INVALID_PARAMETER VariableName is NULL VariableGuid is NULL or BdsLoadOption is NULL.
|
|
@retval EFI_NOT_FOUND Variable doesn't exist.
|
|
@retval EFI_OUT_OF_RESOURCES Allocate memory to create H2O_BDS_LOAD_OPTION failed.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
BdsServicesConvertVarToLoadOption (
|
|
IN H2O_BDS_SERVICES_PROTOCOL *This,
|
|
IN CONST CHAR16 *VariableName,
|
|
IN CONST EFI_GUID *VariableGuid,
|
|
OUT H2O_BDS_LOAD_OPTION **BdsLoadOption
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT8 *EfiLoadOption;
|
|
UINTN EfiLoadOptionSize;
|
|
UINT8 *WorkingPtr;
|
|
UINT16 DevicePathLength;
|
|
CHAR16 *Description;
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
|
UINTN UsedSize;
|
|
UINT8 *OptionalData;
|
|
UINT32 OptionalDataSize;
|
|
UINT32 Attributes;
|
|
CHAR16 OptionName[OPTION_VAR_NAME_BUFFER_CHAR_COUNT];
|
|
|
|
if (VariableName == NULL || VariableGuid == NULL || BdsLoadOption == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Status = CommonGetVariableDataAndSize (
|
|
(CHAR16 *) VariableName,
|
|
(EFI_GUID *) VariableGuid,
|
|
&EfiLoadOptionSize,
|
|
(VOID **) &EfiLoadOption
|
|
);
|
|
if (Status != EFI_SUCCESS) {
|
|
return Status;
|
|
}
|
|
if (IsBootPreviousVariable (VariableName, VariableGuid) || IsBootCurrentVariable (VariableName, VariableGuid) ||
|
|
IsBootNextVariable (VariableName, VariableGuid)) {
|
|
UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", *((UINT16 *) EfiLoadOption));
|
|
FreePool (EfiLoadOption);
|
|
Status = CommonGetVariableDataAndSize (
|
|
OptionName,
|
|
&gEfiGlobalVariableGuid,
|
|
&EfiLoadOptionSize,
|
|
(VOID **) &EfiLoadOption
|
|
);
|
|
if (Status != EFI_SUCCESS) {
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
WorkingPtr = (UINT8 *) EfiLoadOption;
|
|
Attributes = *((UINT32 *) WorkingPtr);
|
|
WorkingPtr += sizeof (UINT32);
|
|
DevicePathLength = *((UINT16 *) WorkingPtr);
|
|
WorkingPtr += sizeof (UINT16);
|
|
Description = (CHAR16 *) WorkingPtr;
|
|
WorkingPtr += StrSize (Description);
|
|
DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) WorkingPtr;
|
|
WorkingPtr += DevicePathLength;
|
|
UsedSize = (UINTN) (WorkingPtr - (UINT8 *) EfiLoadOption);
|
|
if (EfiLoadOptionSize > UsedSize && EfiLoadOption != NULL) {
|
|
OptionalDataSize = (UINT32) (EfiLoadOptionSize - UsedSize);
|
|
OptionalData = WorkingPtr;
|
|
} else {
|
|
OptionalData = NULL;
|
|
OptionalDataSize = 0;
|
|
}
|
|
Status = BdsServicesCreateLoadOption (
|
|
&mH2OBdsServices,
|
|
VariableName[0] == L'B' ? BOOT_OPTION : DRIVER_OPTION,
|
|
VariableName,
|
|
VariableGuid,
|
|
Attributes,
|
|
DevicePath,
|
|
Description,
|
|
OptionalData,
|
|
OptionalDataSize,
|
|
BdsLoadOption
|
|
);
|
|
FreePool (EfiLoadOption);
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Converts a BDS load option in a UEFI variable formatted as a UEFI load option.
|
|
|
|
@param[in] This A Pointer to current instance of this protocol.
|
|
@param[in] BdsLoadOption A pointer to BDS load option.
|
|
@param[out] VariableName A Null-terminated string that is the name of the vendor's variable.
|
|
Caller is responsible freeing the buffer.
|
|
@Param[out] VariableGuid A unique identifier for the vendor.
|
|
|
|
@retval EFI_SUCCESS Convert UEFI load option to BDS load option successfully.
|
|
@retval EFI_INVALID_PARAMETER BdsLoadOption is NULL, VariableName is NULL or VariableGuid is NULL.
|
|
@retval EFI_INVALID_PARAMETER BdsLoadOption format is incorrect.
|
|
@retval EFI_OUT_OF_RESOURCES Allocate memory to contain variable name is failed.
|
|
@retval Others Any other error occurred in this function.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
BdsServicesConvertLoadOptionToVar (
|
|
IN H2O_BDS_SERVICES_PROTOCOL *This,
|
|
IN H2O_BDS_LOAD_OPTION *BdsLoadOption,
|
|
OUT CHAR16 **VariableName,
|
|
OUT EFI_GUID *VariableGuid
|
|
)
|
|
{
|
|
UINT8 *EfiLoadOption;
|
|
UINTN EfiLoadOptionSize;
|
|
UINT8 *WorkingPtr;
|
|
EFI_STATUS Status;
|
|
H2O_BDS_OPTION_TYPE_INFO *OptionTypeInfo;
|
|
|
|
if (BdsLoadOption == NULL || BdsLoadOption->Signature != H2O_BDS_LOAD_OPTION_SIGNATURE ||
|
|
VariableName == NULL || VariableGuid == NULL ||
|
|
!BDS_OPTION_HAVE_LOAD_ORDER_VAR_NAME(BdsLoadOption)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
OptionTypeInfo = GetOptionTypeInfo (BdsLoadOption->OptionType);
|
|
if (OptionTypeInfo == NULL) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
//
|
|
// For BootPrev, BootCurrent, BootNext variable, needn't save related variable and just return variable name
|
|
// variable GUID. other variable will save corresponding Boot#### and Driver#### variable.
|
|
//
|
|
if (!(StrCmp (BdsLoadOption->LoadOrderVarName, H2O_BOOT_PREVIOUS_VARIABLE_NAME) == 0 || StrCmp (BdsLoadOption->LoadOrderVarName, EFI_BOOT_CURRENT_VARIABLE_NAME) == 0 ||
|
|
StrCmp (BdsLoadOption->LoadOrderVarName, EFI_BOOT_NEXT_VARIABLE_NAME) == 0)) {
|
|
EfiLoadOptionSize = sizeof (UINT32) + sizeof (UINT16) + StrSize (BdsLoadOption->Description) +
|
|
GetDevicePathSize (BdsLoadOption->DevicePath) + BdsLoadOption->LoadOptionalDataSize;
|
|
EfiLoadOption = AllocateZeroPool (EfiLoadOptionSize);
|
|
if (EfiLoadOption == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
WorkingPtr = EfiLoadOption;
|
|
*(UINT32 *) WorkingPtr = BdsLoadOption->Attributes;
|
|
WorkingPtr += sizeof (UINT32);
|
|
*(UINT16 *) WorkingPtr = (UINT16) GetDevicePathSize (BdsLoadOption->DevicePath);
|
|
WorkingPtr += sizeof (UINT16);
|
|
CopyMem (WorkingPtr, BdsLoadOption->Description, StrSize (BdsLoadOption->Description));
|
|
WorkingPtr += StrSize (BdsLoadOption->Description);
|
|
CopyMem (WorkingPtr, BdsLoadOption->DevicePath, GetDevicePathSize (BdsLoadOption->DevicePath));
|
|
WorkingPtr += GetDevicePathSize (BdsLoadOption->DevicePath);
|
|
CopyMem (WorkingPtr, BdsLoadOption->LoadOptionalData, BdsLoadOption->LoadOptionalDataSize);
|
|
|
|
Status = CommonSetVariable (
|
|
BdsLoadOption->LoadOrderVarName,
|
|
&BdsLoadOption->LoadOrderVarGuid,
|
|
OptionTypeInfo->VarAttribute,
|
|
EfiLoadOptionSize,
|
|
EfiLoadOption
|
|
);
|
|
if (Status != EFI_SUCCESS) {
|
|
FreePool (EfiLoadOption);
|
|
return Status;
|
|
}
|
|
FreePool (EfiLoadOption);
|
|
}
|
|
|
|
*VariableName = AllocateCopyPool (StrSize (BdsLoadOption->LoadOrderVarName), BdsLoadOption->LoadOrderVarName);
|
|
if (*VariableName == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
CopyGuid (VariableGuid, &BdsLoadOption->LoadOrderVarGuid);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Insert a BDS load option into either the Driver or Boot order.
|
|
|
|
@param[in] This A Pointer to current instance of this protocol.
|
|
@param[in] BdsLoadOption A pointer to BDS load option.
|
|
|
|
@retval EFI_SUCCESS Insert a BDS load option into either the Driver or Boot order successfully.
|
|
@retval EFI_INVALID_PARAMETER BdsLoadOption is NULL.
|
|
@retval EFI_INVALID_PARAMETER BdsLoadOption format is incorrect.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
BdsServicesInsertLoadOption (
|
|
IN H2O_BDS_SERVICES_PROTOCOL *This,
|
|
IN H2O_BDS_LOAD_OPTION *BdsLoadOption
|
|
)
|
|
{
|
|
H2O_BDS_OPTION_TYPE_INFO *OptionTypeInfo;
|
|
H2O_BDS_ORDER_VAR_INFO OrderVarInfo;
|
|
UINTN Index;
|
|
EFI_STATUS Status;
|
|
EFI_BOOT_OPTION_POLICY_PROTOCOL *BootOptionPolicy;
|
|
UINTN BootOptionType;
|
|
UINTN NewPosition;
|
|
UINT16 *NewOptionOrder;
|
|
|
|
if (!IsValidLoadOption (BdsLoadOption)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (BdsLoadOption->OptionType != H2O_BDS_LOAD_OPTION_TYPE_BOOT) {
|
|
return BdsServicesInsertLoadOption2 (This, BdsLoadOption, NULL);
|
|
}
|
|
|
|
OptionTypeInfo = GetOptionTypeInfo (BdsLoadOption->OptionType);
|
|
if (OptionTypeInfo == NULL) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
Status = GetOrderVarInfo (BdsLoadOption->OptionType, &OrderVarInfo);
|
|
if (EFI_ERROR (Status)) {
|
|
ZeroMem (&OrderVarInfo, sizeof (OrderVarInfo));
|
|
}
|
|
|
|
Status = GetOrderIndexInOrderVar (BdsLoadOption, &Index);
|
|
if (!EFI_ERROR (Status)) {
|
|
InsertLoadOptionToList (BdsLoadOption, &OrderVarInfo, Index);
|
|
FreeOrderVarInfo (&OrderVarInfo);
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
Status = gBS->LocateProtocol (
|
|
&gEfiBootOptionPolicyProtocolGuid,
|
|
NULL,
|
|
(VOID **) &BootOptionPolicy
|
|
);
|
|
|
|
if (Status == EFI_SUCCESS) {
|
|
BootOptionType = IsLegacyBootOption (BdsLoadOption->DevicePath) ? LEGACY_BOOT_DEV : EFI_BOOT_DEV;
|
|
BootOptionPolicy->FindPositionOfNewBootOption (
|
|
BootOptionPolicy,
|
|
BdsLoadOption->DevicePath,
|
|
OrderVarInfo.OptionOrder,
|
|
BootOptionType,
|
|
OrderVarInfo.OptionCount,
|
|
BdsLoadOption->LoadOrder,
|
|
&NewPosition
|
|
);
|
|
} else {
|
|
NewPosition = 0;
|
|
}
|
|
BdsLibNewBootOptionPolicy (
|
|
&NewOptionOrder,
|
|
OrderVarInfo.OptionOrder,
|
|
OrderVarInfo.OptionCount,
|
|
BdsLoadOption->LoadOrder,
|
|
NewPosition
|
|
);
|
|
Status = CommonSetVariable (
|
|
OptionTypeInfo->OrderVarName,
|
|
&gEfiGlobalVariableGuid,
|
|
OptionTypeInfo->VarAttribute,
|
|
(OrderVarInfo.OptionCount + 1) * sizeof (UINT16),
|
|
NewOptionOrder
|
|
);
|
|
FreeOrderVarInfo (&OrderVarInfo);
|
|
GetOrderVarInfo (BdsLoadOption->OptionType, &OrderVarInfo);
|
|
InsertLoadOptionToList (BdsLoadOption, &OrderVarInfo, NewPosition);
|
|
FreeOrderVarInfo (&OrderVarInfo);
|
|
InternalFreePool (NewOptionOrder);
|
|
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Insert a BDS load option into the Driver, Boot, SysPrep, OS Recovery or Platform Recovery orders.
|
|
|
|
This function inserts the specified load option into one of the BDS load option lists, depending on the value of
|
|
the OptionType member of the load option.
|
|
|
|
@param[in] This A Pointer to current instance of this protocol.
|
|
@param[in] BdsLoadOption A pointer to BDS load option.
|
|
@param[in] BdsLoadOptionAfter An optional pointer to the load option which must precede the load option in the load
|
|
option list. If NULL, then the load option will be inserted at the beginning of the
|
|
load option list.
|
|
|
|
@retval EFI_SUCCESS Insert a BDS load option into either the Driver or Boot order successfully.
|
|
@retval EFI_INVALID_PARAMETER BdsLoadOption is NULL.
|
|
@retval EFI_INVALID_PARAMETER BdsLoadOptionAfter is non-NULL, but the OptionType member of the load option does not
|
|
match that of BdsLoadOption.
|
|
@retval EFI_INVALID_PARAMETER BdsLoadOption or BdsLoadOptionAfter format is incorrect.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
BdsServicesInsertLoadOption2 (
|
|
IN H2O_BDS_SERVICES_PROTOCOL *This,
|
|
IN H2O_BDS_LOAD_OPTION *BdsLoadOption,
|
|
IN H2O_BDS_LOAD_OPTION *BdsLoadOptionAfter OPTIONAL
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
H2O_BDS_ORDER_VAR_INFO OrderVarInfo;
|
|
UINTN OptionAfterOrderIndex;
|
|
UINTN OptionOrderIndex;
|
|
UINTN TargetIndex;
|
|
UINT16 Count;
|
|
UINT16 *Order;
|
|
EFI_GUID *VarGuid;
|
|
|
|
if (!IsValidLoadOption (BdsLoadOption) ||
|
|
(BdsLoadOptionAfter != NULL && (!IsValidLoadOption (BdsLoadOptionAfter) ||
|
|
BdsLoadOptionAfter->OptionType != BdsLoadOption->OptionType))) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Status = GetOrderVarInfo (BdsLoadOption->OptionType, &OrderVarInfo);
|
|
if (EFI_ERROR (Status)) {
|
|
ZeroMem (&OrderVarInfo, sizeof (OrderVarInfo));
|
|
}
|
|
|
|
Status = GetOrderIndexInOrderVar (BdsLoadOption, &OptionOrderIndex);
|
|
if (!EFI_ERROR (Status)) {
|
|
//
|
|
// Load option exist in boot order, insert it to list and return,
|
|
//
|
|
InsertLoadOptionToList (BdsLoadOption, &OrderVarInfo, OptionOrderIndex);
|
|
goto Exit;
|
|
}
|
|
|
|
Status = EFI_SUCCESS;
|
|
if (BdsLoadOptionAfter == NULL) {
|
|
TargetIndex = 0;
|
|
} else {
|
|
Status = GetOrderIndexInOrderVar (BdsLoadOptionAfter, &OptionAfterOrderIndex);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Exit;
|
|
}
|
|
TargetIndex = OptionAfterOrderIndex + 1;
|
|
}
|
|
|
|
//
|
|
// Update order variable and insert load option into option list.
|
|
//
|
|
Count = OrderVarInfo.OptionCount;
|
|
Order = OrderVarInfo.OptionOrder;
|
|
VarGuid = OrderVarInfo.OptionVarGuid;
|
|
|
|
Order = ReallocatePool (Count * sizeof (UINT16) , (Count + 1) * sizeof (UINT16) , Order);
|
|
VarGuid = ReallocatePool (Count * sizeof (EFI_GUID), (Count + 1) * sizeof (EFI_GUID), VarGuid);
|
|
if (Order == NULL || VarGuid == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto Exit;
|
|
}
|
|
CopyMem (&Order[TargetIndex + 1] , &Order[TargetIndex] , (Count - TargetIndex) * sizeof (UINT16));
|
|
CopyMem (&VarGuid[TargetIndex + 1], &VarGuid[TargetIndex], (Count - TargetIndex) * sizeof (EFI_GUID));
|
|
Order[TargetIndex] = BdsLoadOption->LoadOrder;
|
|
CopyGuid (&VarGuid[TargetIndex], &BdsLoadOption->LoadOrderVarGuid);
|
|
Count++;
|
|
|
|
OrderVarInfo.OptionCount = Count;
|
|
OrderVarInfo.OptionOrder = Order;
|
|
OrderVarInfo.OptionVarGuid = VarGuid;
|
|
|
|
SetOrderVar (BdsLoadOption->OptionType, &OrderVarInfo);
|
|
InsertLoadOptionToList (BdsLoadOption, &OrderVarInfo, TargetIndex);
|
|
|
|
Exit:
|
|
FreeOrderVarInfo (&OrderVarInfo);
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Remove a BDS load option from either the Driver or Boot order.
|
|
|
|
@param[in] This A Pointer to current instance of this protocol.
|
|
@param[in] DriverOrBoot Boolean that specifies whether this load option represents a Driver load option
|
|
(FALSE) or Boot load option (TRUE).
|
|
@param[in] LoadOrder Unsigned integer that specifies the current boot option being booted. Corresponds to the four
|
|
hexadecimal digits in the #### portion of the UEFI variable name Boot#### or Driver####.
|
|
|
|
@retval EFI_SUCCESS Remove a BDS load option from either the Driver or Boot order successfully.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
BdsServicesRemoveLoadOption (
|
|
IN H2O_BDS_SERVICES_PROTOCOL *This,
|
|
IN BOOLEAN DriverOrBoot,
|
|
IN UINT16 LoadOrder
|
|
)
|
|
{
|
|
return BdsServicesRemoveLoadOption2 (
|
|
This,
|
|
DriverOrBoot == DRIVER_OPTION ? H2O_BDS_LOAD_OPTION_TYPE_DRIVER : H2O_BDS_LOAD_OPTION_TYPE_BOOT,
|
|
LoadOrder,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
/**
|
|
Remove a BDS load option from either the Driver or Boot order.
|
|
|
|
This function removes the load option associated with the value LoadOrder from the load option list specified by OptionType.
|
|
If OptionType is H2O_LOAD_OPTION_TYPE_OS_RECOVERY or H2O_LOAD_OPTION_TYPE_PLATFORM_RECOVERY, the load option list is
|
|
further qualified by the OptionVendorGuid.
|
|
|
|
@param[in] This A Pointer to current instance of this protocol.
|
|
@param[in] OptionType Enumerated value that specifies the type of load option to remove. Valid values are:
|
|
H2O_BDS_LOAD_OPTION_TYPE_DRIVER (0)
|
|
H2O_BDS_LOAD_OPTION_TYPE_BOOT (1)
|
|
H2O_BDS_LOAD_OPTION_TYPE_SYSPREP (2)
|
|
H2O_BDS_LOAD_OPTION_TYPE_OS_RECOVERY (3)
|
|
H2O_BDS_LOAD_OPTION_TYPE_PLATFORM_RECOVERY (4)
|
|
@param[in] LoadOrder Unsigned integer that specifies the current boot option being booted. Corresponds to the four
|
|
hexadecimal digits in the #### portion of the UEFI variable name Boot#### or Driver####.
|
|
@param[in] OptionVendorGuid Pointer to an optional GUID that specifies the group of OS Recovery or Platform Recovery
|
|
load options to search for the specified load option. For Driver, Boot or SysPrep load
|
|
options, this must be NULL.
|
|
|
|
@retval EFI_SUCCESS Remove a BDS load option from either the Driver or Boot order successfully.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
BdsServicesRemoveLoadOption2 (
|
|
IN H2O_BDS_SERVICES_PROTOCOL *This,
|
|
IN UINT8 OptionType,
|
|
IN UINT16 LoadOrder,
|
|
IN CONST EFI_GUID *OptionVendorGuid OPTIONAL
|
|
)
|
|
{
|
|
H2O_BDS_OPTION_TYPE_INFO *OptionTypeInfo;
|
|
LIST_ENTRY *OptionList;
|
|
LIST_ENTRY *Link;
|
|
H2O_BDS_LOAD_OPTION *CurrentLoadOption;
|
|
H2O_BDS_ORDER_VAR_INFO OrderVarInfo;
|
|
UINTN Index;
|
|
EFI_STATUS Status;
|
|
CHAR16 LoadOptionName[OPTION_VAR_NAME_BUFFER_CHAR_COUNT];
|
|
|
|
if (OptionType == H2O_BDS_LOAD_OPTION_TYPE_OS_RECOVERY) {
|
|
if (OptionVendorGuid == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
} else {
|
|
if (OptionVendorGuid != NULL && !CompareGuid (OptionVendorGuid, &gEfiGlobalVariableGuid)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
OptionTypeInfo = GetOptionTypeInfo (OptionType);
|
|
if (OptionTypeInfo == NULL) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
OptionList = &OptionTypeInfo->OptionList;
|
|
for (Link = GetFirstNode (OptionList); !IsNull (OptionList, Link); Link = GetNextNode (OptionList, Link)) {
|
|
CurrentLoadOption = BDS_OPTION_FROM_LINK (Link);
|
|
if (CurrentLoadOption->LoadOrder == LoadOrder) {
|
|
RemoveEntryList (&CurrentLoadOption->Link);
|
|
BdsServicesFreeLoadOption (NULL, CurrentLoadOption);
|
|
break;
|
|
}
|
|
}
|
|
|
|
Status = GetOrderVarInfo (OptionType, &OrderVarInfo);
|
|
if (EFI_ERROR (Status)) {
|
|
ZeroMem (&OrderVarInfo, sizeof (OrderVarInfo));
|
|
}
|
|
|
|
for (Index = 0; Index < OrderVarInfo.OptionCount; Index++) {
|
|
if (OrderVarInfo.OptionOrder[Index] == LoadOrder &&
|
|
(OptionVendorGuid == NULL ||
|
|
CompareGuid (OptionVendorGuid, &OrderVarInfo.OptionVarGuid[Index]))) {
|
|
CopyMem (
|
|
&OrderVarInfo.OptionOrder[Index],
|
|
&OrderVarInfo.OptionOrder[Index + 1],
|
|
(OrderVarInfo.OptionCount - (Index + 1)) * sizeof (UINT16)
|
|
);
|
|
CopyMem (
|
|
&OrderVarInfo.OptionVarGuid[Index],
|
|
&OrderVarInfo.OptionVarGuid[Index + 1],
|
|
(OrderVarInfo.OptionCount - (Index + 1)) * sizeof (EFI_GUID)
|
|
);
|
|
OrderVarInfo.OptionCount--;
|
|
SetOrderVar (OptionType, &OrderVarInfo);
|
|
break;
|
|
}
|
|
}
|
|
FreeOrderVarInfo (&OrderVarInfo);
|
|
|
|
UnicodeSPrint (LoadOptionName, sizeof (LoadOptionName), OPTION_VAR_NAME_FORMAT_STR, OptionTypeInfo->OptionVarPrefixName, LoadOrder);
|
|
CommonSetVariable (
|
|
LoadOptionName,
|
|
OptionVendorGuid == NULL ? &gEfiGlobalVariableGuid : (EFI_GUID *) OptionVendorGuid,
|
|
0,
|
|
0,
|
|
NULL
|
|
);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Expand a partial load option to one or more fully qualified load options using the rules specified in the
|
|
UEFI specification (USB WWID, hard disk) and the InsydeH2O boot groups.
|
|
|
|
@param[in] This A Pointer to current instance of this protocol.
|
|
@param[in] BdsLoadOption A pointer to BDS load option.
|
|
|
|
@retval EFI_SUCCESS Expand load option successfully.
|
|
@retval EFI_INVALID_PARAMETER BdsLoadOption is NULL.
|
|
@retval EFI_INVALID_PARAMETER BdsLoadOption format is incorrect.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
BdsServicesExpandLoadOption (
|
|
IN H2O_BDS_SERVICES_PROTOCOL *This,
|
|
IN H2O_BDS_LOAD_OPTION *BdsLoadOption
|
|
)
|
|
{
|
|
USB_CLASS_DEVICE_PATH *DevicePath;
|
|
|
|
if (BdsLoadOption == NULL || BdsLoadOption->Signature != H2O_BDS_LOAD_OPTION_SIGNATURE) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
DevicePath = (USB_CLASS_DEVICE_PATH *) BdsLoadOption->DevicePath;
|
|
if ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH && DevicePathSubType (DevicePath) == MSG_USB_CLASS_DP) &&
|
|
DevicePath->VendorId == 0xFFFF && DevicePath->ProductId == 0xFFFF && DevicePath->DeviceClass == 0xFF &&
|
|
DevicePath->DeviceSubClass == 0xFF && DevicePath->DeviceProtocol == 0xFF) {
|
|
ExpandWinowsToGoOption (BdsLoadOption);
|
|
} else if (DevicePathType (BdsLoadOption->DevicePath) == MEDIA_DEVICE_PATH &&
|
|
(DevicePathSubType (BdsLoadOption->DevicePath) == MEDIA_HARDDRIVE_DP)) {
|
|
ExpandHddOption (BdsLoadOption);
|
|
} else if ((DevicePathType (BdsLoadOption->DevicePath) == MEDIA_DEVICE_PATH) &&
|
|
(DevicePathSubType (BdsLoadOption->DevicePath) == MEDIA_PIWG_FW_FILE_DP)) {
|
|
ExpandFvFileOption (BdsLoadOption);
|
|
} else if ((DevicePathType (BdsLoadOption->DevicePath) == HARDWARE_DEVICE_PATH) &&
|
|
(DevicePathSubType (BdsLoadOption->DevicePath) == HW_VENDOR_DP) &&
|
|
(CompareGuid (&((VENDOR_DEVICE_PATH *) BdsLoadOption->DevicePath)->Guid, &gH2OBdsBootDeviceGroupGuid))) {
|
|
ExpandBootGroupOption (BdsLoadOption);
|
|
} else if (IS_USB_SHORT_FORM_DEVICE_PATH(BdsLoadOption->DevicePath)) {
|
|
ExpandUsbShortFormOption (BdsLoadOption);
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Launch a BDS load option.
|
|
|
|
@param[in] This A Pointer to current instance of this protocol.
|
|
@param[in] BdsLoadOption A pointer to BDS load option.
|
|
@param[out] ExitDataSize Pointer to the size, in bytes, of ExitData.
|
|
@param[out] ExitData Pointer to a pointer to a data buffer that includes a Null-terminated
|
|
string, optionally followed by additional binary data.
|
|
|
|
@retval EFI_SUCCESS Boot from the input boot option successfully.
|
|
@retval EFI_INVALID_PARAMETER BdsLoadOption is NULL.
|
|
@retval EFI_INVALID_PARAMETER BdsLoadOption format is incorrect.
|
|
@retval EFI_NOT_FOUND If the Device Path is not found in the system
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
BdsServicesLaunchLoadOption (
|
|
IN H2O_BDS_SERVICES_PROTOCOL *This,
|
|
IN H2O_BDS_LOAD_OPTION *BdsLoadOption,
|
|
OUT UINTN *ExitDataSize,
|
|
OUT CHAR16 **ExitData OPTIONAL
|
|
)
|
|
{
|
|
if (BdsLoadOption == NULL || BdsLoadOption->Signature != H2O_BDS_LOAD_OPTION_SIGNATURE) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (BdsLoadOption->DriverOrBoot == BOOT_OPTION) {
|
|
return LaunchBootOption (BdsLoadOption, ExitDataSize, ExitData);
|
|
} else {
|
|
return LaunchDriverOption (BdsLoadOption, ExitDataSize, ExitData);
|
|
}
|
|
}
|
|
|
|
/**
|
|
Return linked list of BDS system preparation options derived from the SysPrepOrder and SysPrep#### UEFI variables.
|
|
|
|
@param[in] This A pointer to the protocol interface structure for this protocol.
|
|
@param[in] SysPrepList A pointer to a pointer to the first list entry in a linked list. Each list entry
|
|
describes a single system preparation load option using a "H2O_BDS_LOAD_OPTION" structure.
|
|
This structure can be retrieved from the list entry using the "BDS_OPTION_FROM_LINK()" macro.
|
|
|
|
@retval EFI_SUCCESS The function completed successfully.
|
|
@retval EFI_INVALID_PARAMETER This is set to NULL or SysPrepList is set to NULL.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
BdsServicesGetSysPrepList (
|
|
IN H2O_BDS_SERVICES_PROTOCOL *This,
|
|
OUT LIST_ENTRY **SysPrepList
|
|
)
|
|
{
|
|
return GetBdsLoadList (H2O_BDS_LOAD_OPTION_TYPE_SYSPREP, SysPrepList);
|
|
}
|
|
|
|
/**
|
|
Return linked list of BDS OS recovery load options derived from the OsRecoveryOrder and OsRecovery#### UEFI variables.
|
|
|
|
@param[in] This A pointer to the protocol interface structure for this protocol.
|
|
@param[in] OsRecoveryList A pointer to a pointer to the first list entry in a linked list. Each list entry
|
|
describes a single OS recovery load option using a "H2O_BDS_LOAD_OPTION" structure.
|
|
This structure can be retrieved from the list entry using the "BDS_OPTION_FROM_LINK()" macro.
|
|
|
|
@retval EFI_SUCCESS The function completed successfully.
|
|
@retval EFI_INVALID_PARAMETER This is set to NULL or OsRecoveryList is set to NULL.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
BdsServicesGetOsRecoveryList (
|
|
IN H2O_BDS_SERVICES_PROTOCOL *This,
|
|
OUT LIST_ENTRY **OsRecoveryList
|
|
)
|
|
{
|
|
return GetBdsLoadList (H2O_BDS_LOAD_OPTION_TYPE_OS_RECOVERY, OsRecoveryList);
|
|
}
|
|
|
|
/**
|
|
Return linked list of BDS platform recovery load options derived from the PlatformRecovery#### UEFI variables.
|
|
|
|
@param[in] This A pointer to the protocol interface structure for this protocol.
|
|
@param[in] OsRecoveryList A pointer to a pointer to the first list entry in a linked list. Each list entry
|
|
describes a single platform recovery load option using a "H2O_BDS_LOAD_OPTION" structure.
|
|
This structure can be retrieved from the list entry using the "BDS_OPTION_FROM_LINK()" macro.
|
|
|
|
@retval EFI_SUCCESS The function completed successfully.
|
|
@retval EFI_INVALID_PARAMETER This is set to NULL or PlatformRecoveryList is set to NULL.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
BdsServicesGetPlatformRecoveryList (
|
|
IN H2O_BDS_SERVICES_PROTOCOL *This,
|
|
OUT LIST_ENTRY **PlatformRecoveryList
|
|
)
|
|
{
|
|
return GetBdsLoadList (H2O_BDS_LOAD_OPTION_TYPE_PLATFORM_RECOVERY, PlatformRecoveryList);
|
|
}
|
|
|