diff options
Diffstat (limited to 'OvmfPkg/Csm/LegacyBootMaintUiLib/LegacyBootMaintUi.c')
-rw-r--r-- | OvmfPkg/Csm/LegacyBootMaintUiLib/LegacyBootMaintUi.c | 1505 |
1 files changed, 1505 insertions, 0 deletions
diff --git a/OvmfPkg/Csm/LegacyBootMaintUiLib/LegacyBootMaintUi.c b/OvmfPkg/Csm/LegacyBootMaintUiLib/LegacyBootMaintUi.c new file mode 100644 index 0000000000..af7d80eb5f --- /dev/null +++ b/OvmfPkg/Csm/LegacyBootMaintUiLib/LegacyBootMaintUi.c @@ -0,0 +1,1505 @@ +/** @file
+ Legacy Boot Maintainence 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 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;
+ }
+
+ *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 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 != 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;
+}
+
|