mirror of https://github.com/acidanthera/audk.git
1509 lines
48 KiB
C
1509 lines
48 KiB
C
/** @file
|
|
Legacy Boot Maintainence UI implementation.
|
|
|
|
Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR>
|
|
This program and the accompanying materials
|
|
are licensed and made available under the terms and conditions of the BSD License
|
|
which accompanies this distribution. The full text of the license may be found at
|
|
http://opensource.org/licenses/bsd-license.php
|
|
|
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
|
|
**/
|
|
|
|
|
|
#include "LegacyBootMaintUi.h"
|
|
|
|
LEGACY_BOOT_OPTION_CALLBACK_DATA *mLegacyBootOptionPrivate;
|
|
EFI_GUID mLegacyBootOptionGuid = LEGACY_BOOT_OPTION_FORMSET_GUID;
|
|
CHAR16 mLegacyBootStorageName[] = L"LegacyBootData";
|
|
BBS_TYPE mBbsType[] = {BBS_FLOPPY, BBS_HARDDISK, BBS_CDROM, BBS_EMBED_NETWORK, BBS_BEV_DEVICE, BBS_UNKNOWN};
|
|
BOOLEAN mFirstEnterLegacyForm = FALSE;
|
|
|
|
|
|
///
|
|
/// Legacy FD Info from LegacyBios.GetBbsInfo()
|
|
///
|
|
LEGACY_MENU_OPTION LegacyFDMenu = {
|
|
LEGACY_MENU_OPTION_SIGNATURE,
|
|
{NULL},
|
|
0
|
|
};
|
|
|
|
///
|
|
/// Legacy HD Info from LegacyBios.GetBbsInfo()
|
|
///
|
|
LEGACY_MENU_OPTION LegacyHDMenu = {
|
|
LEGACY_MENU_OPTION_SIGNATURE,
|
|
{NULL},
|
|
0
|
|
};
|
|
|
|
///
|
|
/// Legacy CD Info from LegacyBios.GetBbsInfo()
|
|
///
|
|
LEGACY_MENU_OPTION LegacyCDMenu = {
|
|
LEGACY_MENU_OPTION_SIGNATURE,
|
|
{NULL},
|
|
0
|
|
};
|
|
|
|
///
|
|
/// Legacy NET Info from LegacyBios.GetBbsInfo()
|
|
///
|
|
LEGACY_MENU_OPTION LegacyNETMenu = {
|
|
LEGACY_MENU_OPTION_SIGNATURE,
|
|
{NULL},
|
|
0
|
|
};
|
|
|
|
///
|
|
/// Legacy NET Info from LegacyBios.GetBbsInfo()
|
|
///
|
|
LEGACY_MENU_OPTION LegacyBEVMenu = {
|
|
LEGACY_MENU_OPTION_SIGNATURE,
|
|
{NULL},
|
|
0
|
|
};
|
|
|
|
|
|
VOID *mLegacyStartOpCodeHandle = NULL;
|
|
VOID *mLegacyEndOpCodeHandle = NULL;
|
|
EFI_IFR_GUID_LABEL *mLegacyStartLabel = NULL;
|
|
EFI_IFR_GUID_LABEL *mLegacyEndLabel = NULL;
|
|
|
|
|
|
HII_VENDOR_DEVICE_PATH mLegacyBootOptionHiiVendorDevicePath = {
|
|
{
|
|
{
|
|
HARDWARE_DEVICE_PATH,
|
|
HW_VENDOR_DP,
|
|
{
|
|
(UINT8) (sizeof (VENDOR_DEVICE_PATH)),
|
|
(UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
|
|
}
|
|
},
|
|
{ 0x6bc75598, 0x89b4, 0x483d, { 0x91, 0x60, 0x7f, 0x46, 0x9a, 0x96, 0x35, 0x31 } }
|
|
},
|
|
{
|
|
END_DEVICE_PATH_TYPE,
|
|
END_ENTIRE_DEVICE_PATH_SUBTYPE,
|
|
{
|
|
(UINT8) (END_DEVICE_PATH_LENGTH),
|
|
(UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
|
|
Build the LegacyFDMenu LegacyHDMenu LegacyCDMenu according to LegacyBios.GetBbsInfo().
|
|
|
|
**/
|
|
VOID
|
|
GetLegacyOptions (
|
|
VOID
|
|
);
|
|
|
|
|
|
/**
|
|
|
|
Base on the L"LegacyDevOrder" variable to build the current order data.
|
|
|
|
**/
|
|
VOID
|
|
GetLegacyOptionsOrder (
|
|
VOID
|
|
);
|
|
|
|
/**
|
|
Re-order the Boot Option according to the DevOrder.
|
|
|
|
The routine re-orders the Boot Option in BootOption array according to
|
|
the order specified by DevOrder.
|
|
|
|
@param DevOrder Pointer to buffer containing the BBS Index,
|
|
high 8-bit value 0xFF indicating a disabled boot option
|
|
@param DevOrderCount Count of the BBS Index
|
|
@param EnBootOption Callee allocated buffer containing the enabled Boot Option Numbers
|
|
@param EnBootOptionCount Count of the enabled Boot Option Numbers
|
|
@param DisBootOption Callee allocated buffer containing the disabled Boot Option Numbers
|
|
@param DisBootOptionCount Count of the disabled Boot Option Numbers
|
|
|
|
@return EFI_SUCCESS The function completed successfully.
|
|
@retval other Contain some error, details see the status return by gRT->SetVariable.
|
|
**/
|
|
EFI_STATUS
|
|
OrderLegacyBootOption4SameType (
|
|
UINT16 *DevOrder,
|
|
UINTN DevOrderCount,
|
|
UINT16 **EnBootOption,
|
|
UINTN *EnBootOptionCount,
|
|
UINT16 **DisBootOption,
|
|
UINTN *DisBootOptionCount
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT16 *NewBootOption;
|
|
UINT16 *BootOrder;
|
|
UINTN BootOrderSize;
|
|
UINTN Index;
|
|
UINTN StartPosition;
|
|
|
|
EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
|
|
|
|
CHAR16 OptionName[sizeof ("Boot####")];
|
|
UINT16 *BbsIndexArray;
|
|
UINT16 *DeviceTypeArray;
|
|
|
|
GetEfiGlobalVariable2 (L"BootOrder", (VOID **) &BootOrder, &BootOrderSize);
|
|
ASSERT (BootOrder != NULL);
|
|
|
|
BbsIndexArray = AllocatePool (BootOrderSize);
|
|
DeviceTypeArray = AllocatePool (BootOrderSize);
|
|
*EnBootOption = AllocatePool (BootOrderSize);
|
|
*DisBootOption = AllocatePool (BootOrderSize);
|
|
*DisBootOptionCount = 0;
|
|
*EnBootOptionCount = 0;
|
|
Index = 0;
|
|
Status = EFI_SUCCESS;
|
|
|
|
ASSERT (BbsIndexArray != NULL);
|
|
ASSERT (DeviceTypeArray != NULL);
|
|
ASSERT (*EnBootOption != NULL);
|
|
ASSERT (*DisBootOption != NULL);
|
|
|
|
for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {
|
|
|
|
UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", BootOrder[Index]);
|
|
Status = EfiBootManagerVariableToLoadOption (OptionName, &BootOption);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
if ((DevicePathType (BootOption.FilePath) == BBS_DEVICE_PATH) &&
|
|
(DevicePathSubType (BootOption.FilePath) == BBS_BBS_DP)) {
|
|
//
|
|
// Legacy Boot Option
|
|
//
|
|
ASSERT (BootOption.OptionalDataSize == sizeof (LEGACY_BOOT_OPTION_BBS_DATA));
|
|
|
|
DeviceTypeArray[Index] = ((BBS_BBS_DEVICE_PATH *) BootOption.FilePath)->DeviceType;
|
|
BbsIndexArray [Index] = ((LEGACY_BOOT_OPTION_BBS_DATA *) BootOption.OptionalData)->BbsIndex;
|
|
} else {
|
|
DeviceTypeArray[Index] = BBS_TYPE_UNKNOWN;
|
|
BbsIndexArray [Index] = 0xFFFF;
|
|
}
|
|
EfiBootManagerFreeLoadOption (&BootOption);
|
|
}
|
|
|
|
//
|
|
// Record the corresponding Boot Option Numbers according to the DevOrder
|
|
// Record the EnBootOption and DisBootOption according to the DevOrder
|
|
//
|
|
StartPosition = BootOrderSize / sizeof (UINT16);
|
|
NewBootOption = AllocatePool (DevOrderCount * sizeof (UINT16));
|
|
ASSERT (NewBootOption != NULL);
|
|
while (DevOrderCount-- != 0) {
|
|
for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {
|
|
if (BbsIndexArray[Index] == (DevOrder[DevOrderCount] & 0xFF)) {
|
|
StartPosition = MIN (StartPosition, Index);
|
|
NewBootOption[DevOrderCount] = BootOrder[Index];
|
|
|
|
if ((DevOrder[DevOrderCount] & 0xFF00) == 0xFF00) {
|
|
(*DisBootOption)[*DisBootOptionCount] = BootOrder[Index];
|
|
(*DisBootOptionCount)++;
|
|
} else {
|
|
(*EnBootOption)[*EnBootOptionCount] = BootOrder[Index];
|
|
(*EnBootOptionCount)++;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Overwrite the old BootOption
|
|
//
|
|
CopyMem (&BootOrder[StartPosition], NewBootOption, (*DisBootOptionCount + *EnBootOptionCount) * sizeof (UINT16));
|
|
Status = gRT->SetVariable (
|
|
L"BootOrder",
|
|
&gEfiGlobalVariableGuid,
|
|
VAR_FLAG,
|
|
BootOrderSize,
|
|
BootOrder
|
|
);
|
|
|
|
FreePool (NewBootOption);
|
|
FreePool (DeviceTypeArray);
|
|
FreePool (BbsIndexArray);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Update the legacy BBS boot option. L"LegacyDevOrder" and gEfiLegacyDevOrderVariableGuid EFI Variable
|
|
is udpated with the new Legacy Boot order. The EFI Variable of "Boot####" and gEfiGlobalVariableGuid
|
|
is also updated.
|
|
|
|
@param NVMapData The data for egacy BBS boot.
|
|
|
|
@return EFI_SUCCESS The function completed successfully.
|
|
@retval EFI_NOT_FOUND If L"LegacyDevOrder" and gEfiLegacyDevOrderVariableGuid EFI Variable can not be found.
|
|
@retval EFI_OUT_OF_RESOURCES Fail to allocate memory resource
|
|
@retval other Contain some error, details see the status return by gRT->SetVariable.
|
|
**/
|
|
EFI_STATUS
|
|
UpdateBBSOption (
|
|
IN LEGACY_BOOT_NV_DATA *NVMapData
|
|
)
|
|
{
|
|
UINTN Index;
|
|
UINTN Index2;
|
|
UINTN CurrentType;
|
|
VOID *BootOptionVar;
|
|
CHAR16 VarName[100];
|
|
UINTN OptionSize;
|
|
EFI_STATUS Status;
|
|
UINT32 *Attribute;
|
|
LEGACY_MENU_OPTION *OptionMenu;
|
|
UINT16 *LegacyDev;
|
|
UINT16 *InitialLegacyDev;
|
|
UINT8 *VarData;
|
|
UINTN VarSize;
|
|
LEGACY_DEV_ORDER_ENTRY *DevOrder;
|
|
UINT8 *OriginalPtr;
|
|
UINT8 *DisMap;
|
|
UINTN Pos;
|
|
UINTN Bit;
|
|
UINT16 *NewOrder;
|
|
UINT16 Tmp;
|
|
UINT16 *EnBootOption;
|
|
UINTN EnBootOptionCount;
|
|
UINT16 *DisBootOption;
|
|
UINTN DisBootOptionCount;
|
|
UINTN BufferSize;
|
|
|
|
|
|
DisMap = NULL;
|
|
NewOrder = NULL;
|
|
CurrentType = 0;
|
|
EnBootOption = NULL;
|
|
DisBootOption = NULL;
|
|
|
|
|
|
DisMap = mLegacyBootOptionPrivate->MaintainMapData->DisableMap;
|
|
Status = EFI_SUCCESS;
|
|
|
|
//
|
|
// Update the Variable "LegacyDevOrder"
|
|
//
|
|
GetVariable2 (VAR_LEGACY_DEV_ORDER, &gEfiLegacyDevOrderVariableGuid, (VOID **) &VarData, &VarSize);
|
|
if (VarData == NULL) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
OriginalPtr = VarData;
|
|
|
|
while (mBbsType[CurrentType] != BBS_UNKNOWN) {
|
|
switch (mBbsType[CurrentType]) {
|
|
case BBS_FLOPPY:
|
|
OptionMenu = (LEGACY_MENU_OPTION *) &LegacyFDMenu;
|
|
LegacyDev = NVMapData->LegacyFD;
|
|
InitialLegacyDev = mLegacyBootOptionPrivate->MaintainMapData->InitialNvData.LegacyFD;
|
|
BufferSize = sizeof (NVMapData->LegacyFD);
|
|
break;
|
|
|
|
case BBS_HARDDISK:
|
|
OptionMenu = (LEGACY_MENU_OPTION *) &LegacyHDMenu;
|
|
LegacyDev = NVMapData->LegacyHD;
|
|
InitialLegacyDev = mLegacyBootOptionPrivate->MaintainMapData->InitialNvData.LegacyHD;
|
|
|
|
BufferSize = sizeof (NVMapData->LegacyHD);
|
|
break;
|
|
|
|
case BBS_CDROM:
|
|
OptionMenu = (LEGACY_MENU_OPTION *) &LegacyCDMenu;
|
|
LegacyDev = NVMapData->LegacyCD;
|
|
InitialLegacyDev = mLegacyBootOptionPrivate->MaintainMapData->InitialNvData.LegacyCD;
|
|
BufferSize = sizeof (NVMapData->LegacyCD);
|
|
break;
|
|
|
|
case BBS_EMBED_NETWORK:
|
|
OptionMenu = (LEGACY_MENU_OPTION *) &LegacyNETMenu;
|
|
LegacyDev = NVMapData->LegacyNET;
|
|
InitialLegacyDev = mLegacyBootOptionPrivate->MaintainMapData->InitialNvData.LegacyNET;
|
|
BufferSize = sizeof (NVMapData->LegacyNET);
|
|
break;
|
|
|
|
default:
|
|
ASSERT (mBbsType[CurrentType] == BBS_BEV_DEVICE);
|
|
OptionMenu = (LEGACY_MENU_OPTION *) &LegacyBEVMenu;
|
|
LegacyDev = NVMapData->LegacyBEV;
|
|
InitialLegacyDev = mLegacyBootOptionPrivate->MaintainMapData->InitialNvData.LegacyBEV;
|
|
BufferSize = sizeof (NVMapData->LegacyBEV);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Check whether has value changed.
|
|
//
|
|
if (CompareMem (LegacyDev, InitialLegacyDev, BufferSize) == 0) {
|
|
CurrentType++;
|
|
continue;
|
|
}
|
|
|
|
DevOrder = (LEGACY_DEV_ORDER_ENTRY *) OriginalPtr;
|
|
while (VarData < OriginalPtr + VarSize) {
|
|
if (DevOrder->BbsType == mBbsType[CurrentType]) {
|
|
break;
|
|
}
|
|
|
|
VarData += sizeof (BBS_TYPE) + DevOrder->Length;
|
|
DevOrder = (LEGACY_DEV_ORDER_ENTRY *) VarData;
|
|
}
|
|
|
|
if (VarData >= OriginalPtr + VarSize) {
|
|
FreePool (OriginalPtr);
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
NewOrder = AllocateZeroPool (DevOrder->Length - sizeof (DevOrder->Length));
|
|
if (NewOrder == NULL) {
|
|
FreePool (OriginalPtr);
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
for (Index = 0; Index < OptionMenu->MenuNumber; Index++) {
|
|
if (0xFF == LegacyDev[Index]) {
|
|
break;
|
|
}
|
|
|
|
NewOrder[Index] = LegacyDev[Index];
|
|
}
|
|
|
|
//
|
|
// Only the enable/disable state of each boot device with same device type can be changed,
|
|
// so we can count on the index information in DevOrder.
|
|
// DisMap bit array is the only reliable source to check a device's en/dis state,
|
|
// so we use DisMap to set en/dis state of each item in NewOrder array
|
|
//
|
|
for (Index2 = 0; Index2 < OptionMenu->MenuNumber; Index2++) {
|
|
Tmp = (UINT16) (DevOrder->Data[Index2] & 0xFF);
|
|
Pos = Tmp / 8;
|
|
Bit = 7 - (Tmp % 8);
|
|
if ((DisMap[Pos] & (1 << Bit)) != 0) {
|
|
NewOrder[Index] = (UINT16) (0xFF00 | Tmp);
|
|
Index++;
|
|
}
|
|
}
|
|
|
|
CopyMem (
|
|
DevOrder->Data,
|
|
NewOrder,
|
|
DevOrder->Length - sizeof (DevOrder->Length)
|
|
);
|
|
FreePool (NewOrder);
|
|
|
|
//
|
|
// Update BootOrder and Boot####.Attribute
|
|
//
|
|
// 1. Re-order the Option Number in BootOrder according to Legacy Dev Order
|
|
//
|
|
ASSERT (OptionMenu->MenuNumber == DevOrder->Length / sizeof (UINT16) - 1);
|
|
|
|
Status = OrderLegacyBootOption4SameType (
|
|
DevOrder->Data,
|
|
DevOrder->Length / sizeof (UINT16) - 1,
|
|
&EnBootOption,
|
|
&EnBootOptionCount,
|
|
&DisBootOption,
|
|
&DisBootOptionCount
|
|
);
|
|
if (EFI_ERROR(Status)) {
|
|
goto Fail;
|
|
}
|
|
|
|
//
|
|
// 2. Deactivate the DisBootOption and activate the EnBootOption
|
|
//
|
|
for (Index = 0; Index < DisBootOptionCount; Index++) {
|
|
UnicodeSPrint (VarName, sizeof (VarName), L"Boot%04x", DisBootOption[Index]);
|
|
GetEfiGlobalVariable2 (VarName, (VOID **) &BootOptionVar, &OptionSize);
|
|
if (BootOptionVar != NULL) {
|
|
Attribute = (UINT32 *) BootOptionVar;
|
|
*Attribute &= ~LOAD_OPTION_ACTIVE;
|
|
|
|
Status = gRT->SetVariable (
|
|
VarName,
|
|
&gEfiGlobalVariableGuid,
|
|
VAR_FLAG,
|
|
OptionSize,
|
|
BootOptionVar
|
|
);
|
|
|
|
FreePool (BootOptionVar);
|
|
}
|
|
}
|
|
|
|
for (Index = 0; Index < EnBootOptionCount; Index++) {
|
|
UnicodeSPrint (VarName, sizeof (VarName), L"Boot%04x", EnBootOption[Index]);
|
|
GetEfiGlobalVariable2 (VarName, (VOID **) &BootOptionVar, &OptionSize);
|
|
if (BootOptionVar != NULL) {
|
|
Attribute = (UINT32 *) BootOptionVar;
|
|
*Attribute |= LOAD_OPTION_ACTIVE;
|
|
|
|
Status = gRT->SetVariable (
|
|
VarName,
|
|
&gEfiGlobalVariableGuid,
|
|
VAR_FLAG,
|
|
OptionSize,
|
|
BootOptionVar
|
|
);
|
|
|
|
FreePool (BootOptionVar);
|
|
}
|
|
}
|
|
|
|
|
|
FreePool (EnBootOption);
|
|
FreePool (DisBootOption);
|
|
|
|
CurrentType++;
|
|
}
|
|
|
|
Status = gRT->SetVariable (
|
|
VAR_LEGACY_DEV_ORDER,
|
|
&gEfiLegacyDevOrderVariableGuid,
|
|
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
|
|
VarSize,
|
|
OriginalPtr
|
|
);
|
|
|
|
Fail:
|
|
if (EnBootOption != NULL) {
|
|
FreePool (EnBootOption);
|
|
}
|
|
|
|
if (DisBootOption != NULL) {
|
|
FreePool (DisBootOption);
|
|
}
|
|
|
|
FreePool (OriginalPtr);
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
This function allows a caller to extract the current configuration for one
|
|
or more named elements from the target driver.
|
|
|
|
|
|
@param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
|
|
@param Request A null-terminated Unicode string in <ConfigRequest> format.
|
|
@param Progress On return, points to a character in the Request string.
|
|
Points to the string's null terminator if request was successful.
|
|
Points to the most recent '&' before the first failing name/value
|
|
pair (or the beginning of the string if the failure is in the
|
|
first name/value pair) if the request was not successful.
|
|
@param Results A null-terminated Unicode string in <ConfigAltResp> format which
|
|
has all values filled in for the names in the Request string.
|
|
String to be allocated by the called function.
|
|
|
|
@retval EFI_SUCCESS The Results is filled with the requested values.
|
|
@retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.
|
|
@retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name.
|
|
@retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
LegacyBootOptionExtractConfig (
|
|
IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
|
|
IN CONST EFI_STRING Request,
|
|
OUT EFI_STRING *Progress,
|
|
OUT EFI_STRING *Results
|
|
)
|
|
{
|
|
if (Progress == NULL || Results == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
*Progress = Request;
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
/**
|
|
This function processes the results of changes in configuration.
|
|
|
|
|
|
@param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
|
|
@param Configuration A null-terminated Unicode string in <ConfigResp> format.
|
|
@param Progress A pointer to a string filled in with the offset of the most
|
|
recent '&' before the first failing name/value pair (or the
|
|
beginning of the string if the failure is in the first
|
|
name/value pair) or the terminating NULL if all was successful.
|
|
|
|
@retval EFI_SUCCESS The Results is processed successfully.
|
|
@retval EFI_INVALID_PARAMETER Configuration is NULL.
|
|
@retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
LegacyBootOptionRouteConfig (
|
|
IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
|
|
IN CONST EFI_STRING Configuration,
|
|
OUT EFI_STRING *Progress
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_HII_CONFIG_ROUTING_PROTOCOL *ConfigRouting;
|
|
LEGACY_BOOT_NV_DATA *CurrentNVMapData;
|
|
UINTN BufferSize;
|
|
|
|
|
|
if (Configuration == NULL || Progress == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Check routing data in <ConfigHdr>.
|
|
// Note: there is no name for Name/Value storage, only GUID will be checked
|
|
//
|
|
if (!HiiIsConfigHdrMatch (Configuration, &mLegacyBootOptionGuid, mLegacyBootStorageName)) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
Status = gBS->LocateProtocol (
|
|
&gEfiHiiConfigRoutingProtocolGuid,
|
|
NULL,
|
|
(VOID **) &ConfigRouting
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Convert <ConfigResp> to buffer data by helper function ConfigToBlock()
|
|
//
|
|
CurrentNVMapData = &mLegacyBootOptionPrivate->MaintainMapData->CurrentNvData;
|
|
Status = ConfigRouting->ConfigToBlock (
|
|
ConfigRouting,
|
|
Configuration,
|
|
(UINT8 *) CurrentNVMapData,
|
|
&BufferSize,
|
|
Progress
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
Status = UpdateBBSOption (CurrentNVMapData);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Refresh the global UpdateData structure.
|
|
|
|
**/
|
|
VOID
|
|
RefreshLegacyUpdateData (
|
|
VOID
|
|
)
|
|
{
|
|
//
|
|
// Free current updated date
|
|
//
|
|
if (mLegacyStartOpCodeHandle != NULL) {
|
|
HiiFreeOpCodeHandle (mLegacyStartOpCodeHandle);
|
|
}
|
|
if (mLegacyEndOpCodeHandle != NULL) {
|
|
HiiFreeOpCodeHandle (mLegacyEndOpCodeHandle);
|
|
}
|
|
|
|
//
|
|
// Create new OpCode Handle
|
|
//
|
|
mLegacyStartOpCodeHandle = HiiAllocateOpCodeHandle ();
|
|
mLegacyEndOpCodeHandle = HiiAllocateOpCodeHandle ();
|
|
|
|
//
|
|
// Create Hii Extend Label OpCode as the start opcode
|
|
//
|
|
mLegacyStartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
|
|
mLegacyStartOpCodeHandle,
|
|
&gEfiIfrTianoGuid,
|
|
NULL,
|
|
sizeof (EFI_IFR_GUID_LABEL)
|
|
);
|
|
mLegacyStartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
|
|
|
|
mLegacyStartLabel->Number = FORM_BOOT_LEGACY_DEVICE_ID;
|
|
|
|
//
|
|
// Create Hii Extend Label OpCode as the start opcode
|
|
//
|
|
mLegacyEndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
|
|
mLegacyEndOpCodeHandle,
|
|
&gEfiIfrTianoGuid,
|
|
NULL,
|
|
sizeof (EFI_IFR_GUID_LABEL)
|
|
);
|
|
mLegacyEndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
|
|
|
|
mLegacyEndLabel->Number = FORM_BOOT_LEGACY_LABEL_END;
|
|
|
|
}
|
|
|
|
/**
|
|
Get the Menu Entry from the list in Menu Entry List.
|
|
|
|
If MenuNumber is great or equal to the number of Menu
|
|
Entry in the list, then ASSERT.
|
|
|
|
@param MenuOption The Menu Entry List to read the menu entry.
|
|
@param MenuNumber The index of Menu Entry.
|
|
|
|
@return The Menu Entry.
|
|
|
|
**/
|
|
LEGACY_MENU_ENTRY *
|
|
GetMenuEntry (
|
|
LEGACY_MENU_OPTION *MenuOption,
|
|
UINTN MenuNumber
|
|
)
|
|
{
|
|
LEGACY_MENU_ENTRY *NewMenuEntry;
|
|
UINTN Index;
|
|
LIST_ENTRY *List;
|
|
|
|
ASSERT (MenuNumber < MenuOption->MenuNumber);
|
|
|
|
List = MenuOption->Head.ForwardLink;
|
|
for (Index = 0; Index < MenuNumber; Index++) {
|
|
List = List->ForwardLink;
|
|
}
|
|
|
|
NewMenuEntry = CR (List, LEGACY_MENU_ENTRY, Link, LEGACY_MENU_ENTRY_SIGNATURE);
|
|
|
|
return NewMenuEntry;
|
|
}
|
|
|
|
/**
|
|
Create string tokens for a menu from its help strings and display strings
|
|
|
|
@param HiiHandle Hii Handle of the package to be updated.
|
|
@param MenuOption The Menu whose string tokens need to be created
|
|
|
|
**/
|
|
VOID
|
|
CreateLegacyMenuStringToken (
|
|
IN EFI_HII_HANDLE HiiHandle,
|
|
IN LEGACY_MENU_OPTION *MenuOption
|
|
)
|
|
{
|
|
LEGACY_MENU_ENTRY *NewMenuEntry;
|
|
UINTN Index;
|
|
|
|
for (Index = 0; Index < MenuOption->MenuNumber; Index++) {
|
|
NewMenuEntry = GetMenuEntry (MenuOption, Index);
|
|
|
|
NewMenuEntry->DisplayStringToken = HiiSetString (
|
|
HiiHandle,
|
|
0,
|
|
NewMenuEntry->DisplayString,
|
|
NULL
|
|
);
|
|
|
|
if (NULL == NewMenuEntry->HelpString) {
|
|
NewMenuEntry->HelpStringToken = NewMenuEntry->DisplayStringToken;
|
|
} else {
|
|
NewMenuEntry->HelpStringToken = HiiSetString (
|
|
HiiHandle,
|
|
0,
|
|
NewMenuEntry->HelpString,
|
|
NULL
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
Create a dynamic page so that Legacy Device boot order
|
|
can be set for specified device type.
|
|
|
|
@param UpdatePageId The form ID. It also spefies the legacy device type.
|
|
|
|
|
|
**/
|
|
VOID
|
|
UpdateLegacyDeviceOrderPage (
|
|
IN UINT16 UpdatePageId
|
|
)
|
|
{
|
|
LEGACY_MENU_OPTION *OptionMenu;
|
|
LEGACY_MENU_ENTRY *NewMenuEntry;
|
|
EFI_STRING_ID StrRef;
|
|
EFI_STRING_ID StrRefHelp;
|
|
UINT16 *Default;
|
|
UINT16 Index;
|
|
UINT16 Key;
|
|
CHAR16 String[100];
|
|
CHAR16 *TypeStr;
|
|
CHAR16 *TypeStrHelp;
|
|
CHAR16 *FormTitle;
|
|
VOID *OptionsOpCodeHandle;
|
|
VOID *DefaultOpCodeHandle;
|
|
|
|
Key = 0;
|
|
StrRef = 0;
|
|
StrRefHelp = 0;
|
|
OptionMenu = NULL;
|
|
TypeStr = NULL;
|
|
TypeStrHelp = NULL;
|
|
Default = NULL;
|
|
|
|
RefreshLegacyUpdateData();
|
|
|
|
//
|
|
// Create oneof option list
|
|
//
|
|
switch (UpdatePageId) {
|
|
case FORM_FLOPPY_BOOT_ID:
|
|
OptionMenu = (LEGACY_MENU_OPTION *) &LegacyFDMenu;
|
|
Key = (UINT16) LEGACY_FD_QUESTION_ID;
|
|
TypeStr = STR_FLOPPY;
|
|
TypeStrHelp = STR_FLOPPY_HELP;
|
|
FormTitle = STR_FLOPPY_TITLE;
|
|
Default = mLegacyBootOptionPrivate->MaintainMapData->CurrentNvData.LegacyFD;
|
|
break;
|
|
|
|
case FORM_HARDDISK_BOOT_ID:
|
|
OptionMenu = (LEGACY_MENU_OPTION *) &LegacyHDMenu;
|
|
Key = (UINT16) LEGACY_HD_QUESTION_ID;
|
|
TypeStr = STR_HARDDISK;
|
|
TypeStrHelp = STR_HARDDISK_HELP;
|
|
FormTitle = STR_HARDDISK_TITLE;
|
|
Default = mLegacyBootOptionPrivate->MaintainMapData->CurrentNvData.LegacyHD;
|
|
break;
|
|
|
|
case FORM_CDROM_BOOT_ID:
|
|
OptionMenu = (LEGACY_MENU_OPTION *) &LegacyCDMenu;
|
|
Key = (UINT16) LEGACY_CD_QUESTION_ID;
|
|
TypeStr = STR_CDROM;
|
|
TypeStrHelp = STR_CDROM_HELP;
|
|
FormTitle = STR_CDROM_TITLE;
|
|
Default = mLegacyBootOptionPrivate->MaintainMapData->CurrentNvData.LegacyCD;
|
|
break;
|
|
|
|
case FORM_NET_BOOT_ID:
|
|
OptionMenu = (LEGACY_MENU_OPTION *) &LegacyNETMenu;
|
|
Key = (UINT16) LEGACY_NET_QUESTION_ID;
|
|
TypeStr = STR_NET;
|
|
TypeStrHelp = STR_NET_HELP;
|
|
FormTitle = STR_NET_TITLE;
|
|
Default = mLegacyBootOptionPrivate->MaintainMapData->CurrentNvData.LegacyNET;
|
|
break;
|
|
|
|
case FORM_BEV_BOOT_ID:
|
|
OptionMenu = (LEGACY_MENU_OPTION *) &LegacyBEVMenu;
|
|
Key = (UINT16) LEGACY_BEV_QUESTION_ID;
|
|
TypeStr = STR_BEV;
|
|
TypeStrHelp = STR_BEV_HELP;
|
|
FormTitle = STR_BEV_TITLE;
|
|
Default = mLegacyBootOptionPrivate->MaintainMapData->CurrentNvData.LegacyBEV;
|
|
break;
|
|
|
|
default:
|
|
DEBUG ((EFI_D_ERROR, "Invalid command ID for updating page!\n"));
|
|
return;
|
|
}
|
|
|
|
HiiSetString (mLegacyBootOptionPrivate->HiiHandle, STRING_TOKEN(STR_ORDER_CHANGE_PROMPT), FormTitle, NULL);
|
|
|
|
CreateLegacyMenuStringToken (mLegacyBootOptionPrivate->HiiHandle, OptionMenu);
|
|
|
|
OptionsOpCodeHandle = HiiAllocateOpCodeHandle ();
|
|
ASSERT (OptionsOpCodeHandle != NULL);
|
|
|
|
|
|
for (Index = 0; Index < OptionMenu->MenuNumber; Index++) {
|
|
NewMenuEntry = GetMenuEntry (OptionMenu, Index);
|
|
//
|
|
// Create OneOf for each legacy device
|
|
//
|
|
HiiCreateOneOfOptionOpCode (
|
|
OptionsOpCodeHandle,
|
|
NewMenuEntry->DisplayStringToken,
|
|
0,
|
|
EFI_IFR_TYPE_NUM_SIZE_16,
|
|
((LEGACY_DEVICE_CONTEXT *) NewMenuEntry->VariableContext)->BbsIndex
|
|
);
|
|
}
|
|
|
|
//
|
|
// Create OneOf for item "Disabled"
|
|
//
|
|
HiiCreateOneOfOptionOpCode (
|
|
OptionsOpCodeHandle,
|
|
STRING_TOKEN (STR_DISABLE_LEGACY_DEVICE),
|
|
0,
|
|
EFI_IFR_TYPE_NUM_SIZE_16,
|
|
0xFF
|
|
);
|
|
|
|
//
|
|
// Create oneof tag here for FD/HD/CD #1 #2
|
|
//
|
|
for (Index = 0; Index < OptionMenu->MenuNumber; Index++) {
|
|
DefaultOpCodeHandle = HiiAllocateOpCodeHandle ();
|
|
ASSERT (DefaultOpCodeHandle != NULL);
|
|
|
|
HiiCreateDefaultOpCode (
|
|
DefaultOpCodeHandle,
|
|
EFI_HII_DEFAULT_CLASS_STANDARD,
|
|
EFI_IFR_TYPE_NUM_SIZE_16,
|
|
*Default++
|
|
);
|
|
|
|
//
|
|
// Create the string for oneof tag
|
|
//
|
|
UnicodeSPrint (String, sizeof (String), TypeStr, Index);
|
|
StrRef = HiiSetString (mLegacyBootOptionPrivate->HiiHandle, 0, String, NULL);
|
|
|
|
UnicodeSPrint (String, sizeof (String), TypeStrHelp, Index);
|
|
StrRefHelp = HiiSetString (mLegacyBootOptionPrivate->HiiHandle, 0, String, NULL);
|
|
|
|
HiiCreateOneOfOpCode (
|
|
mLegacyStartOpCodeHandle,
|
|
(EFI_QUESTION_ID) (Key + Index),
|
|
VARSTORE_ID_LEGACY_BOOT,
|
|
(UINT16) (Key + Index * 2 - CONFIG_OPTION_OFFSET),
|
|
StrRef,
|
|
StrRefHelp,
|
|
EFI_IFR_FLAG_CALLBACK,
|
|
EFI_IFR_NUMERIC_SIZE_2,
|
|
OptionsOpCodeHandle,
|
|
DefaultOpCodeHandle //NULL //
|
|
);
|
|
|
|
HiiFreeOpCodeHandle (DefaultOpCodeHandle);
|
|
}
|
|
|
|
HiiUpdateForm (
|
|
mLegacyBootOptionPrivate->HiiHandle,
|
|
&mLegacyBootOptionGuid,
|
|
LEGACY_ORDER_CHANGE_FORM_ID,
|
|
mLegacyStartOpCodeHandle,
|
|
mLegacyEndOpCodeHandle
|
|
);
|
|
|
|
HiiFreeOpCodeHandle (OptionsOpCodeHandle);
|
|
}
|
|
|
|
|
|
/**
|
|
Adjust question value when one question value has been changed.
|
|
|
|
@param QuestionId The question id for the value changed question.
|
|
@param Value The value for the changed question.
|
|
|
|
**/
|
|
VOID
|
|
AdjustOptionValue (
|
|
IN UINT16 QuestionId,
|
|
IN EFI_IFR_TYPE_VALUE *Value
|
|
)
|
|
{
|
|
UINTN Number;
|
|
UINT16 *Default;
|
|
LEGACY_BOOT_NV_DATA *CurrentNVMap;
|
|
UINT16 *CurrentVal;
|
|
UINTN Index;
|
|
UINTN Index2;
|
|
UINTN Index3;
|
|
UINTN NewValuePos;
|
|
UINTN OldValue;
|
|
UINTN NewValue;
|
|
UINT8 *DisMap;
|
|
UINTN Pos;
|
|
UINTN Bit;
|
|
|
|
Number = 0;
|
|
CurrentVal = 0;
|
|
Default = NULL;
|
|
NewValue = 0;
|
|
NewValuePos = 0;
|
|
OldValue = 0;
|
|
|
|
//
|
|
// Update Select FD/HD/CD/NET/BEV Order Form
|
|
//
|
|
ASSERT ((QuestionId >= LEGACY_FD_QUESTION_ID) && (QuestionId < LEGACY_BEV_QUESTION_ID + MAX_MENU_NUMBER));
|
|
|
|
CurrentNVMap = &mLegacyBootOptionPrivate->MaintainMapData->CurrentNvData;
|
|
HiiGetBrowserData (&mLegacyBootOptionGuid, mLegacyBootStorageName, sizeof (LEGACY_BOOT_NV_DATA), (UINT8 *) CurrentNVMap);
|
|
DisMap = mLegacyBootOptionPrivate->MaintainMapData->DisableMap;
|
|
|
|
if (QuestionId >= LEGACY_FD_QUESTION_ID && QuestionId < LEGACY_FD_QUESTION_ID + MAX_MENU_NUMBER) {
|
|
Number = (UINT16) LegacyFDMenu.MenuNumber;
|
|
CurrentVal = CurrentNVMap->LegacyFD;
|
|
Default = mLegacyBootOptionPrivate->MaintainMapData->LastTimeNvData.LegacyFD;
|
|
} else if (QuestionId >= LEGACY_HD_QUESTION_ID && QuestionId < LEGACY_HD_QUESTION_ID + MAX_MENU_NUMBER) {
|
|
Number = (UINT16) LegacyHDMenu.MenuNumber;
|
|
CurrentVal = CurrentNVMap->LegacyHD;
|
|
Default = mLegacyBootOptionPrivate->MaintainMapData->LastTimeNvData.LegacyHD;
|
|
} else if (QuestionId >= LEGACY_CD_QUESTION_ID && QuestionId < LEGACY_CD_QUESTION_ID + MAX_MENU_NUMBER) {
|
|
Number = (UINT16) LegacyCDMenu.MenuNumber;
|
|
CurrentVal = CurrentNVMap->LegacyCD;
|
|
Default = mLegacyBootOptionPrivate->MaintainMapData->LastTimeNvData.LegacyCD;
|
|
} else if (QuestionId >= LEGACY_NET_QUESTION_ID && QuestionId < LEGACY_NET_QUESTION_ID + MAX_MENU_NUMBER) {
|
|
Number = (UINT16) LegacyNETMenu.MenuNumber;
|
|
CurrentVal = CurrentNVMap->LegacyNET;
|
|
Default = mLegacyBootOptionPrivate->MaintainMapData->LastTimeNvData.LegacyNET;
|
|
} else if (QuestionId >= LEGACY_BEV_QUESTION_ID && QuestionId < LEGACY_BEV_QUESTION_ID + MAX_MENU_NUMBER) {
|
|
Number = (UINT16) LegacyBEVMenu.MenuNumber;
|
|
CurrentVal = CurrentNVMap->LegacyBEV;
|
|
Default = mLegacyBootOptionPrivate->MaintainMapData->LastTimeNvData.LegacyBEV;
|
|
}
|
|
|
|
//
|
|
// First, find the different position
|
|
// if there is change, it should be only one
|
|
//
|
|
for (Index = 0; Index < Number; Index++) {
|
|
if (CurrentVal[Index] != Default[Index]) {
|
|
OldValue = Default[Index];
|
|
NewValue = CurrentVal[Index];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (Index != Number) {
|
|
//
|
|
// there is change, now process
|
|
//
|
|
if (0xFF == NewValue) {
|
|
//
|
|
// This item will be disable
|
|
// Just move the items behind this forward to overlap it
|
|
//
|
|
Pos = OldValue / 8;
|
|
Bit = 7 - (OldValue % 8);
|
|
DisMap[Pos] = (UINT8) (DisMap[Pos] | (UINT8) (1 << Bit));
|
|
for (Index2 = Index; Index2 < Number - 1; Index2++) {
|
|
CurrentVal[Index2] = CurrentVal[Index2 + 1];
|
|
}
|
|
|
|
CurrentVal[Index2] = 0xFF;
|
|
} else {
|
|
for (Index2 = 0; Index2 < Number; Index2++) {
|
|
if (Index2 == Index) {
|
|
continue;
|
|
}
|
|
|
|
if (Default[Index2] == NewValue) {
|
|
//
|
|
// If NewValue is in OldLegacyDev array
|
|
// remember its old position
|
|
//
|
|
NewValuePos = Index2;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (Index2 != Number) {
|
|
//
|
|
// We will change current item to an existing item
|
|
// (It's hard to describe here, please read code, it's like a cycle-moving)
|
|
//
|
|
for (Index2 = NewValuePos; Index2 != Index;) {
|
|
if (NewValuePos < Index) {
|
|
CurrentVal[Index2] = Default[Index2 + 1];
|
|
Index2++;
|
|
} else {
|
|
CurrentVal[Index2] = Default[Index2 - 1];
|
|
Index2--;
|
|
}
|
|
}
|
|
} else {
|
|
//
|
|
// If NewValue is not in OldlegacyDev array, we are changing to a disabled item
|
|
// so we should modify DisMap to reflect the change
|
|
//
|
|
Pos = NewValue / 8;
|
|
Bit = 7 - (NewValue % 8);
|
|
DisMap[Pos] = (UINT8) (DisMap[Pos] & (~ (UINT8) (1 << Bit)));
|
|
if (0xFF != OldValue) {
|
|
//
|
|
// Because NewValue is a item that was disabled before
|
|
// so after changing the OldValue should be disabled
|
|
// actually we are doing a swap of enable-disable states of two items
|
|
//
|
|
Pos = OldValue / 8;
|
|
Bit = 7 - (OldValue % 8);
|
|
DisMap[Pos] = (UINT8) (DisMap[Pos] | (UINT8) (1 << Bit));
|
|
}
|
|
}
|
|
}
|
|
//
|
|
// To prevent DISABLE appears in the middle of the list
|
|
// we should perform a re-ordering
|
|
//
|
|
Index3 = Index;
|
|
Index = 0;
|
|
while (Index < Number) {
|
|
if (0xFF != CurrentVal[Index]) {
|
|
Index++;
|
|
continue;
|
|
}
|
|
|
|
Index2 = Index;
|
|
Index2++;
|
|
while (Index2 < Number) {
|
|
if (0xFF != CurrentVal[Index2]) {
|
|
break;
|
|
}
|
|
|
|
Index2++;
|
|
}
|
|
|
|
if (Index2 < Number) {
|
|
CurrentVal[Index] = CurrentVal[Index2];
|
|
CurrentVal[Index2] = 0xFF;
|
|
}
|
|
|
|
Index++;
|
|
}
|
|
|
|
//
|
|
// Return correct question value.
|
|
//
|
|
Value->u16 = CurrentVal[Index3];
|
|
CopyMem (Default, CurrentVal, sizeof (UINT16) * Number);
|
|
}
|
|
|
|
//
|
|
// Pass changed uncommitted data back to Form Browser
|
|
//
|
|
HiiSetBrowserData (&mLegacyBootOptionGuid, mLegacyBootStorageName, sizeof (LEGACY_BOOT_NV_DATA), (UINT8 *) CurrentNVMap, NULL);
|
|
}
|
|
|
|
/**
|
|
This call back function is registered with Boot Manager formset.
|
|
When user selects a boot option, this call back function will
|
|
be triggered. The boot option is saved for later processing.
|
|
|
|
|
|
@param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
|
|
@param Action Specifies the type of action taken by the browser.
|
|
@param QuestionId A unique value which is sent to the original exporting driver
|
|
so that it can identify the type of data to expect.
|
|
@param Type The type of value for the question.
|
|
@param Value A pointer to the data being sent to the original exporting driver.
|
|
@param ActionRequest On return, points to the action requested by the callback function.
|
|
|
|
@retval EFI_SUCCESS The callback successfully handled the action.
|
|
@retval EFI_INVALID_PARAMETER The setup browser call this function with invalid parameters.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
LegacyBootOptionCallback (
|
|
IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
|
|
IN EFI_BROWSER_ACTION Action,
|
|
IN EFI_QUESTION_ID QuestionId,
|
|
IN UINT8 Type,
|
|
IN EFI_IFR_TYPE_VALUE *Value,
|
|
OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
|
|
)
|
|
{
|
|
if (Action != EFI_BROWSER_ACTION_CHANGED && Action != EFI_BROWSER_ACTION_CHANGING && Action != EFI_BROWSER_ACTION_FORM_OPEN) {
|
|
//
|
|
// Do nothing for other UEFI Action. Only do call back when data is changed or the form is open.
|
|
//
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
if ((Value == NULL) || (ActionRequest == NULL)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (Action == EFI_BROWSER_ACTION_FORM_OPEN) {
|
|
if (QuestionId == FORM_FLOPPY_BOOT_ID) {
|
|
if (!mFirstEnterLegacyForm) {
|
|
//
|
|
// The leagcyBootMaintUiLib depends on the LegacyBootManagerLib to realize its functionality.
|
|
// We need to do the leagcy boot options related actions after the LegacyBootManagerLib has been initialized.
|
|
// Opening the legacy menus is the appropriate time that the LegacyBootManagerLib has already been initialized.
|
|
//
|
|
mFirstEnterLegacyForm = TRUE;
|
|
GetLegacyOptions ();
|
|
GetLegacyOptionsOrder ();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Action == EFI_BROWSER_ACTION_CHANGING) {
|
|
switch (QuestionId) {
|
|
case FORM_FLOPPY_BOOT_ID:
|
|
case FORM_HARDDISK_BOOT_ID:
|
|
case FORM_CDROM_BOOT_ID:
|
|
case FORM_NET_BOOT_ID:
|
|
case FORM_BEV_BOOT_ID:
|
|
UpdateLegacyDeviceOrderPage (QuestionId);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
} else if (Action == EFI_BROWSER_ACTION_CHANGED) {
|
|
if ((Value == NULL) || (ActionRequest == NULL)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if ((QuestionId >= LEGACY_FD_QUESTION_ID) && (QuestionId < LEGACY_BEV_QUESTION_ID + MAX_MENU_NUMBER)) {
|
|
AdjustOptionValue(QuestionId, Value);
|
|
}
|
|
}
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
Create a menu entry by given menu type.
|
|
|
|
@param MenuType The Menu type to be created.
|
|
|
|
@retval NULL If failed to create the menu.
|
|
@return the new menu entry.
|
|
|
|
**/
|
|
LEGACY_MENU_ENTRY *
|
|
CreateMenuEntry (
|
|
VOID
|
|
)
|
|
{
|
|
LEGACY_MENU_ENTRY *MenuEntry;
|
|
|
|
//
|
|
// Create new menu entry
|
|
//
|
|
MenuEntry = AllocateZeroPool (sizeof (LEGACY_MENU_ENTRY));
|
|
if (MenuEntry == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
MenuEntry->VariableContext = AllocateZeroPool (sizeof (LEGACY_DEVICE_CONTEXT));
|
|
if (MenuEntry->VariableContext == NULL) {
|
|
FreePool (MenuEntry);
|
|
return NULL;
|
|
}
|
|
|
|
MenuEntry->Signature = LEGACY_MENU_ENTRY_SIGNATURE;
|
|
return MenuEntry;
|
|
}
|
|
|
|
/**
|
|
|
|
Base on the L"LegacyDevOrder" variable to build the current order data.
|
|
|
|
**/
|
|
VOID
|
|
GetLegacyOptionsOrder (
|
|
VOID
|
|
)
|
|
{
|
|
UINTN VarSize;
|
|
UINT8 *VarData;
|
|
UINT8 *VarTmp;
|
|
LEGACY_DEV_ORDER_ENTRY *DevOrder;
|
|
UINT16 *LegacyDev;
|
|
UINTN Index;
|
|
LEGACY_MENU_OPTION *OptionMenu;
|
|
UINT16 VarDevOrder;
|
|
UINTN Pos;
|
|
UINTN Bit;
|
|
UINT8 *DisMap;
|
|
UINTN TotalLength;
|
|
|
|
LegacyDev = NULL;
|
|
OptionMenu = NULL;
|
|
|
|
DisMap = ZeroMem (mLegacyBootOptionPrivate->MaintainMapData->DisableMap, sizeof (mLegacyBootOptionPrivate->MaintainMapData->DisableMap));
|
|
|
|
//
|
|
// Get Device Order from variable
|
|
//
|
|
GetVariable2 (VAR_LEGACY_DEV_ORDER, &gEfiLegacyDevOrderVariableGuid, (VOID **) &VarData, &VarSize);
|
|
VarTmp = VarData;
|
|
if (NULL != VarData) {
|
|
DevOrder = (LEGACY_DEV_ORDER_ENTRY *) VarData;
|
|
while (VarData < VarTmp + VarSize) {
|
|
switch (DevOrder->BbsType) {
|
|
case BBS_FLOPPY:
|
|
LegacyDev = mLegacyBootOptionPrivate->MaintainMapData->InitialNvData.LegacyFD;
|
|
OptionMenu = &LegacyFDMenu;
|
|
break;
|
|
|
|
case BBS_HARDDISK:
|
|
LegacyDev = mLegacyBootOptionPrivate->MaintainMapData->InitialNvData.LegacyHD;
|
|
OptionMenu = &LegacyHDMenu;
|
|
break;
|
|
|
|
case BBS_CDROM:
|
|
LegacyDev = mLegacyBootOptionPrivate->MaintainMapData->InitialNvData.LegacyCD;
|
|
OptionMenu = &LegacyCDMenu;
|
|
break;
|
|
|
|
case BBS_EMBED_NETWORK:
|
|
LegacyDev = mLegacyBootOptionPrivate->MaintainMapData->InitialNvData.LegacyNET;
|
|
OptionMenu = &LegacyNETMenu;
|
|
break;
|
|
|
|
case BBS_BEV_DEVICE:
|
|
LegacyDev = mLegacyBootOptionPrivate->MaintainMapData->InitialNvData.LegacyBEV;
|
|
OptionMenu = &LegacyBEVMenu;
|
|
break;
|
|
|
|
case BBS_UNKNOWN:
|
|
default:
|
|
ASSERT (FALSE);
|
|
DEBUG ((DEBUG_ERROR, "Unsupported device type found!\n"));
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Create oneof tag here for FD/HD/CD #1 #2
|
|
//
|
|
for (Index = 0; Index < OptionMenu->MenuNumber; Index++) {
|
|
TotalLength = sizeof (BBS_TYPE) + sizeof (UINT16) + Index * sizeof (UINT16);
|
|
VarDevOrder = *(UINT16 *) ((UINT8 *) DevOrder + TotalLength);
|
|
|
|
if (0xFF00 == (VarDevOrder & 0xFF00)) {
|
|
LegacyDev[Index] = 0xFF;
|
|
Pos = (VarDevOrder & 0xFF) / 8;
|
|
Bit = 7 - ((VarDevOrder & 0xFF) % 8);
|
|
DisMap[Pos] = (UINT8) (DisMap[Pos] | (UINT8) (1 << Bit));
|
|
} else {
|
|
LegacyDev[Index] = VarDevOrder & 0xFF;
|
|
}
|
|
}
|
|
|
|
VarData ++;
|
|
VarData += *(UINT16 *) VarData;
|
|
DevOrder = (LEGACY_DEV_ORDER_ENTRY *) VarData;
|
|
}
|
|
}
|
|
|
|
CopyMem (&mLegacyBootOptionPrivate->MaintainMapData->LastTimeNvData, &mLegacyBootOptionPrivate->MaintainMapData->InitialNvData, sizeof (LEGACY_BOOT_NV_DATA));
|
|
CopyMem (&mLegacyBootOptionPrivate->MaintainMapData->CurrentNvData, &mLegacyBootOptionPrivate->MaintainMapData->InitialNvData, sizeof (LEGACY_BOOT_NV_DATA));
|
|
}
|
|
|
|
/**
|
|
|
|
Build the LegacyFDMenu LegacyHDMenu LegacyCDMenu according to LegacyBios.GetBbsInfo().
|
|
|
|
**/
|
|
VOID
|
|
GetLegacyOptions (
|
|
VOID
|
|
)
|
|
{
|
|
LEGACY_MENU_ENTRY *NewMenuEntry;
|
|
LEGACY_DEVICE_CONTEXT *NewLegacyDevContext;
|
|
EFI_BOOT_MANAGER_LOAD_OPTION *BootOption;
|
|
UINTN BootOptionCount;
|
|
UINT16 Index;
|
|
UINTN FDNum;
|
|
UINTN HDNum;
|
|
UINTN CDNum;
|
|
UINTN NETNum;
|
|
UINTN BEVNum;
|
|
|
|
//
|
|
// Initialize Bbs Table Context from BBS info data
|
|
//
|
|
InitializeListHead (&LegacyFDMenu.Head);
|
|
InitializeListHead (&LegacyHDMenu.Head);
|
|
InitializeListHead (&LegacyCDMenu.Head);
|
|
InitializeListHead (&LegacyNETMenu.Head);
|
|
InitializeListHead (&LegacyBEVMenu.Head);
|
|
|
|
FDNum = 0;
|
|
HDNum = 0;
|
|
CDNum = 0;
|
|
NETNum = 0;
|
|
BEVNum = 0;
|
|
|
|
EfiBootManagerConnectAll ();
|
|
|
|
//
|
|
// for better user experience
|
|
// 1. User changes HD configuration (e.g.: unplug HDD), here we have a chance to remove the HDD boot option
|
|
// 2. User enables/disables UEFI PXE, here we have a chance to add/remove EFI Network boot option
|
|
//
|
|
EfiBootManagerRefreshAllBootOption ();
|
|
|
|
BootOption = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
|
|
for (Index = 0; Index < BootOptionCount; Index++) {
|
|
if ((DevicePathType (BootOption[Index].FilePath) != BBS_DEVICE_PATH) ||
|
|
(DevicePathSubType (BootOption[Index].FilePath) != BBS_BBS_DP)
|
|
) {
|
|
continue;
|
|
}
|
|
ASSERT (BootOption[Index].OptionalDataSize == sizeof (LEGACY_BOOT_OPTION_BBS_DATA));
|
|
NewMenuEntry = CreateMenuEntry ();
|
|
ASSERT (NewMenuEntry != NULL);
|
|
|
|
NewLegacyDevContext = (LEGACY_DEVICE_CONTEXT *) NewMenuEntry->VariableContext;
|
|
NewLegacyDevContext->BbsIndex = ((LEGACY_BOOT_OPTION_BBS_DATA *) BootOption[Index].OptionalData)->BbsIndex;
|
|
NewLegacyDevContext->Description = AllocateCopyPool (StrSize (BootOption[Index].Description), BootOption[Index].Description);
|
|
ASSERT (NewLegacyDevContext->Description != NULL);
|
|
|
|
NewMenuEntry->DisplayString = NewLegacyDevContext->Description;
|
|
NewMenuEntry->HelpString = NULL;
|
|
|
|
switch (((BBS_BBS_DEVICE_PATH *) BootOption[Index].FilePath)->DeviceType) {
|
|
case BBS_TYPE_FLOPPY:
|
|
InsertTailList (&LegacyFDMenu.Head, &NewMenuEntry->Link);
|
|
FDNum++;
|
|
break;
|
|
|
|
case BBS_TYPE_HARDDRIVE:
|
|
InsertTailList (&LegacyHDMenu.Head, &NewMenuEntry->Link);
|
|
HDNum++;
|
|
break;
|
|
|
|
case BBS_TYPE_CDROM:
|
|
InsertTailList (&LegacyCDMenu.Head, &NewMenuEntry->Link);
|
|
CDNum++;
|
|
break;
|
|
|
|
case BBS_TYPE_EMBEDDED_NETWORK:
|
|
InsertTailList (&LegacyNETMenu.Head, &NewMenuEntry->Link);
|
|
NETNum++;
|
|
break;
|
|
|
|
case BBS_TYPE_BEV:
|
|
InsertTailList (&LegacyBEVMenu.Head, &NewMenuEntry->Link);
|
|
BEVNum++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
EfiBootManagerFreeLoadOptions (BootOption, BootOptionCount);
|
|
|
|
LegacyFDMenu.MenuNumber = FDNum;
|
|
LegacyHDMenu.MenuNumber = HDNum;
|
|
LegacyCDMenu.MenuNumber = CDNum;
|
|
LegacyNETMenu.MenuNumber = NETNum;
|
|
LegacyBEVMenu.MenuNumber = BEVNum;
|
|
}
|
|
|
|
|
|
/**
|
|
|
|
Install Boot Manager Menu driver.
|
|
|
|
@param ImageHandle The image handle.
|
|
@param SystemTable The system table.
|
|
|
|
@retval EFI_SUCEESS Install Boot manager menu success.
|
|
@retval Other Return error status.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
LegacyBootMaintUiLibConstructor (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
|
|
LEGACY_BOOT_OPTION_CALLBACK_DATA *LegacyBootOptionData;
|
|
|
|
Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
|
|
if (!EFI_ERROR (Status)) {
|
|
//
|
|
// Create LegacyBootOptionData structures for Driver Callback
|
|
//
|
|
LegacyBootOptionData = AllocateZeroPool (sizeof (LEGACY_BOOT_OPTION_CALLBACK_DATA));
|
|
ASSERT (LegacyBootOptionData != NULL);
|
|
|
|
LegacyBootOptionData->MaintainMapData = AllocateZeroPool (sizeof (LEGACY_BOOT_MAINTAIN_DATA));
|
|
ASSERT (LegacyBootOptionData->MaintainMapData != NULL);
|
|
|
|
LegacyBootOptionData->ConfigAccess.ExtractConfig = LegacyBootOptionExtractConfig;
|
|
LegacyBootOptionData->ConfigAccess.RouteConfig = LegacyBootOptionRouteConfig;
|
|
LegacyBootOptionData->ConfigAccess.Callback = LegacyBootOptionCallback;
|
|
|
|
//
|
|
// Install Device Path Protocol and Config Access protocol to driver handle
|
|
//
|
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
|
&LegacyBootOptionData->DriverHandle,
|
|
&gEfiDevicePathProtocolGuid,
|
|
&mLegacyBootOptionHiiVendorDevicePath,
|
|
&gEfiHiiConfigAccessProtocolGuid,
|
|
&LegacyBootOptionData->ConfigAccess,
|
|
NULL
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
//
|
|
// Publish our HII data
|
|
//
|
|
LegacyBootOptionData->HiiHandle = HiiAddPackages (
|
|
&mLegacyBootOptionGuid,
|
|
LegacyBootOptionData->DriverHandle,
|
|
LegacyBootMaintUiVfrBin,
|
|
LegacyBootMaintUiLibStrings,
|
|
NULL
|
|
);
|
|
ASSERT (LegacyBootOptionData->HiiHandle != NULL);
|
|
|
|
mLegacyBootOptionPrivate = LegacyBootOptionData;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Destructor of Customized Display Library Instance.
|
|
|
|
@param ImageHandle The firmware allocated handle for the EFI image.
|
|
@param SystemTable A pointer to the EFI System Table.
|
|
|
|
@retval EFI_SUCCESS The destructor completed successfully.
|
|
@retval Other value The destructor did not complete successfully.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
LegacyBootMaintUiLibDestructor (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
if (mLegacyBootOptionPrivate->DriverHandle != NULL) {
|
|
Status = gBS->UninstallMultipleProtocolInterfaces (
|
|
mLegacyBootOptionPrivate->DriverHandle,
|
|
&gEfiDevicePathProtocolGuid,
|
|
&mLegacyBootOptionHiiVendorDevicePath,
|
|
&gEfiHiiConfigAccessProtocolGuid,
|
|
&mLegacyBootOptionPrivate->ConfigAccess,
|
|
NULL
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
HiiRemovePackages (mLegacyBootOptionPrivate->HiiHandle);
|
|
|
|
FreePool (mLegacyBootOptionPrivate->MaintainMapData);
|
|
FreePool (mLegacyBootOptionPrivate);
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|