/** @file Legacy Boot Maintainence UI implementation. Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.
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 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 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 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 . // 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 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; }