audk/OvmfPkg/Csm/LegacyBootMaintUiLib/LegacyBootMaintUi.c

1506 lines
48 KiB
C

/** @file
Legacy Boot Maintenance UI implementation.
Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
(C) Copyright 2018 Hewlett Packard Enterprise Development LP<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "LegacyBootMaintUi.h"
LEGACY_BOOT_OPTION_CALLBACK_DATA *mLegacyBootOptionPrivate = NULL;
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 updated with the new Legacy Boot order. The EFI Variable of "Boot####" and gEfiGlobalVariableGuid
is also updated.
@param NVMapData The data for legacy 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;
}
*Progress = Configuration;
//
// 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 specifies 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 ((DEBUG_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 legacyBootMaintUiLib depends on the LegacyBootManagerLib to realize its functionality.
// We need to do the legacy 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_SUCCESS 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 != NULL && 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;
}