/** 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 CallbackData The context data for BMM. @return EFI_SUCCESS The function completed successfully. @retval EFI_NOT_FOUND If L"LegacyDevOrder" and gEfiLegacyDevOrderVariableGuid EFI Variable can be found. @retval EFI_OUT_OF_RESOURCES Fail to allocate memory resource **/ 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; 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); OrderLegacyBootOption4SameType ( DevOrder->Data, DevOrder->Length / sizeof (UINT16) - 1, &EnBootOption, &EnBootOptionCount, &DisBootOption, &DisBootOptionCount ); // // 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 ); FreePool (OriginalPtr); return Status; }
/** Update the legacy BBS boot option. VAR_LEGACY_DEV_ORDER and gEfiLegacyDevOrderVariableGuid EFI Variable is udpated with the new Legacy Boot order. The EFI Variable of "Boot####" and gEfiGlobalVariableGuid is also updated. @param CallbackData The context data for BMM. @return EFI_SUCCESS The function completed successfully. @retval EFI_NOT_FOUND If VAR_LEGACY_DEV_ORDER and gEfiLegacyDevOrderVariableGuid EFI Variable can be found. @retval EFI_OUT_OF_RESOURCES Fail to allocate memory resource **/ EFI_STATUS Var_UpdateBBSOption ( IN BMM_CALLBACK_DATA *CallbackData, IN EFI_FORM_ID FormId ) { UINTN Index; UINTN Index2; VOID *BootOptionVar; CHAR16 VarName[100]; UINTN OptionSize; EFI_STATUS Status; UINT32 *Attribute; BM_MENU_OPTION *OptionMenu; UINT8 *LegacyDev; 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; DisMap = NULL; NewOrder = NULL; switch (FormId) { case FORM_SET_FD_ORDER_ID: OptionMenu = (BM_MENU_OPTION *) &LegacyFDMenu; LegacyDev = CallbackData->BmmFakeNvData.LegacyFD; CallbackData->BbsType = BBS_FLOPPY; break; case FORM_SET_HD_ORDER_ID: OptionMenu = (BM_MENU_OPTION *) &LegacyHDMenu; LegacyDev = CallbackData->BmmFakeNvData.LegacyHD; CallbackData->BbsType = BBS_HARDDISK; break; case FORM_SET_CD_ORDER_ID: OptionMenu = (BM_MENU_OPTION *) &LegacyCDMenu; LegacyDev = CallbackData->BmmFakeNvData.LegacyCD; CallbackData->BbsType = BBS_CDROM; break; case FORM_SET_NET_ORDER_ID: OptionMenu = (BM_MENU_OPTION *) &LegacyNETMenu; LegacyDev = CallbackData->BmmFakeNvData.LegacyNET; CallbackData->BbsType = BBS_EMBED_NETWORK; break; default: ASSERT (FORM_SET_BEV_ORDER_ID == CallbackData->BmmPreviousPageId); OptionMenu = (BM_MENU_OPTION *) &LegacyBEVMenu; LegacyDev = CallbackData->BmmFakeNvData.LegacyBEV; CallbackData->BbsType = BBS_BEV_DEVICE; break; } DisMap = CallbackData->BmmOldFakeNVData.DisableMap; Status = EFI_SUCCESS; // // Update the Variable "LegacyDevOrder" // VarData = (UINT8 *) BdsLibGetVariableAndSize ( VAR_LEGACY_DEV_ORDER, &gEfiLegacyDevOrderVariableGuid, &VarSize ); if (VarData == NULL) { return EFI_NOT_FOUND; } OriginalPtr = VarData; DevOrder = (LEGACY_DEV_ORDER_ENTRY *) VarData; while (VarData < OriginalPtr + VarSize) { if (DevOrder->BbsType == CallbackData->BbsType) { 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); Status = gRT->SetVariable ( VAR_LEGACY_DEV_ORDER, &gEfiLegacyDevOrderVariableGuid, EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE, VarSize, OriginalPtr ); // // 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); OrderLegacyBootOption4SameType ( DevOrder->Data, DevOrder->Length / sizeof (UINT16) - 1, &EnBootOption, &EnBootOptionCount, &DisBootOption, &DisBootOptionCount ); // // 2. Deactivate the DisBootOption and activate the EnBootOption // for (Index = 0; Index < DisBootOptionCount; Index++) { UnicodeSPrint (VarName, sizeof (VarName), L"Boot%04x", DisBootOption[Index]); BootOptionVar = BdsLibGetVariableAndSize ( VarName, &gEfiGlobalVariableGuid, &OptionSize ); if (BootOptionVar != NULL) { Attribute = (UINT32 *) BootOptionVar; *Attribute &= ~LOAD_OPTION_ACTIVE; Status = gRT->SetVariable ( VarName, &gEfiGlobalVariableGuid, EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, OptionSize, BootOptionVar ); // // Changing the content without increasing its size with current variable implementation shouldn't fail. // ASSERT_EFI_ERROR (Status); FreePool (BootOptionVar); } } for (Index = 0; Index < EnBootOptionCount; Index++) { UnicodeSPrint (VarName, sizeof (VarName), L"Boot%04x", EnBootOption[Index]); BootOptionVar = BdsLibGetVariableAndSize ( VarName, &gEfiGlobalVariableGuid, &OptionSize ); if (BootOptionVar != NULL) { Attribute = (UINT32 *) BootOptionVar; *Attribute |= LOAD_OPTION_ACTIVE; Status = gRT->SetVariable ( VarName, &gEfiGlobalVariableGuid, EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, OptionSize, BootOptionVar ); // // Changing the content without increasing its size with current variable implementation shouldn't fail. // ASSERT_EFI_ERROR (Status); FreePool (BootOptionVar); } } BOpt_GetBootOptions (CallbackData); FreePool (OriginalPtr); FreePool (EnBootOption); FreePool (DisBootOption); return Status; }