Home | History | Annotate | Download | only in LegacyBootMaintUiLib
      1 /** @file
      2   Legacy Boot Maintainence UI implementation.
      3 
      4 Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions of the BSD License
      7 which accompanies this distribution.  The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 
     16 #include "LegacyBootMaintUi.h"
     17 
     18 LEGACY_BOOT_OPTION_CALLBACK_DATA  *mLegacyBootOptionPrivate;
     19 EFI_GUID  mLegacyBootOptionGuid     = LEGACY_BOOT_OPTION_FORMSET_GUID;
     20 CHAR16    mLegacyBootStorageName[]  = L"LegacyBootData";
     21 BBS_TYPE  mBbsType[] = {BBS_FLOPPY, BBS_HARDDISK, BBS_CDROM, BBS_EMBED_NETWORK, BBS_BEV_DEVICE, BBS_UNKNOWN};
     22 
     23 
     24 ///
     25 /// Legacy FD Info from LegacyBios.GetBbsInfo()
     26 ///
     27 LEGACY_MENU_OPTION      LegacyFDMenu = {
     28   LEGACY_MENU_OPTION_SIGNATURE,
     29   {NULL},
     30   0
     31 };
     32 
     33 ///
     34 /// Legacy HD Info from LegacyBios.GetBbsInfo()
     35 ///
     36 LEGACY_MENU_OPTION      LegacyHDMenu = {
     37   LEGACY_MENU_OPTION_SIGNATURE,
     38   {NULL},
     39   0
     40 };
     41 
     42 ///
     43 /// Legacy CD Info from LegacyBios.GetBbsInfo()
     44 ///
     45 LEGACY_MENU_OPTION      LegacyCDMenu = {
     46   LEGACY_MENU_OPTION_SIGNATURE,
     47   {NULL},
     48   0
     49 };
     50 
     51 ///
     52 /// Legacy NET Info from LegacyBios.GetBbsInfo()
     53 ///
     54 LEGACY_MENU_OPTION      LegacyNETMenu = {
     55   LEGACY_MENU_OPTION_SIGNATURE,
     56   {NULL},
     57   0
     58 };
     59 
     60 ///
     61 /// Legacy NET Info from LegacyBios.GetBbsInfo()
     62 ///
     63 LEGACY_MENU_OPTION      LegacyBEVMenu = {
     64   LEGACY_MENU_OPTION_SIGNATURE,
     65   {NULL},
     66   0
     67 };
     68 
     69 
     70 VOID                *mLegacyStartOpCodeHandle = NULL;
     71 VOID                *mLegacyEndOpCodeHandle = NULL;
     72 EFI_IFR_GUID_LABEL  *mLegacyStartLabel = NULL;
     73 EFI_IFR_GUID_LABEL  *mLegacyEndLabel = NULL;
     74 
     75 
     76 HII_VENDOR_DEVICE_PATH  mLegacyBootOptionHiiVendorDevicePath = {
     77   {
     78     {
     79       HARDWARE_DEVICE_PATH,
     80       HW_VENDOR_DP,
     81       {
     82         (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
     83         (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
     84       }
     85     },
     86     { 0x6bc75598, 0x89b4, 0x483d, { 0x91, 0x60, 0x7f, 0x46, 0x9a, 0x96, 0x35, 0x31 } }
     87   },
     88   {
     89     END_DEVICE_PATH_TYPE,
     90     END_ENTIRE_DEVICE_PATH_SUBTYPE,
     91     {
     92       (UINT8) (END_DEVICE_PATH_LENGTH),
     93       (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
     94     }
     95   }
     96 };
     97 
     98 
     99 /**
    100   Re-order the Boot Option according to the DevOrder.
    101 
    102   The routine re-orders the Boot Option in BootOption array according to
    103   the order specified by DevOrder.
    104 
    105   @param DevOrder           Pointer to buffer containing the BBS Index,
    106                             high 8-bit value 0xFF indicating a disabled boot option
    107   @param DevOrderCount      Count of the BBS Index
    108   @param EnBootOption       Callee allocated buffer containing the enabled Boot Option Numbers
    109   @param EnBootOptionCount  Count of the enabled Boot Option Numbers
    110   @param DisBootOption      Callee allocated buffer containing the disabled Boot Option Numbers
    111   @param DisBootOptionCount Count of the disabled Boot Option Numbers
    112 **/
    113 VOID
    114 OrderLegacyBootOption4SameType (
    115   UINT16                   *DevOrder,
    116   UINTN                    DevOrderCount,
    117   UINT16                   **EnBootOption,
    118   UINTN                    *EnBootOptionCount,
    119   UINT16                   **DisBootOption,
    120   UINTN                    *DisBootOptionCount
    121   )
    122 {
    123   EFI_STATUS               Status;
    124   UINT16                   *NewBootOption;
    125   UINT16                   *BootOrder;
    126   UINTN                    BootOrderSize;
    127   UINTN                    Index;
    128   UINTN                    StartPosition;
    129 
    130   EFI_BOOT_MANAGER_LOAD_OPTION    BootOption;
    131 
    132   CHAR16                           OptionName[sizeof ("Boot####")];
    133   UINT16                   *BbsIndexArray;
    134   UINT16                   *DeviceTypeArray;
    135 
    136   GetEfiGlobalVariable2 (L"BootOrder", (VOID **) &BootOrder, &BootOrderSize);
    137   ASSERT (BootOrder != NULL);
    138 
    139   BbsIndexArray       = AllocatePool (BootOrderSize);
    140   DeviceTypeArray     = AllocatePool (BootOrderSize);
    141   *EnBootOption       = AllocatePool (BootOrderSize);
    142   *DisBootOption      = AllocatePool (BootOrderSize);
    143   *DisBootOptionCount = 0;
    144   *EnBootOptionCount  = 0;
    145   Index               = 0;
    146 
    147   ASSERT (BbsIndexArray != NULL);
    148   ASSERT (DeviceTypeArray != NULL);
    149   ASSERT (*EnBootOption != NULL);
    150   ASSERT (*DisBootOption != NULL);
    151 
    152   for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {
    153 
    154     UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", BootOrder[Index]);
    155     Status = EfiBootManagerVariableToLoadOption (OptionName, &BootOption);
    156     ASSERT_EFI_ERROR (Status);
    157 
    158     if ((DevicePathType (BootOption.FilePath) == BBS_DEVICE_PATH) &&
    159         (DevicePathSubType (BootOption.FilePath) == BBS_BBS_DP)) {
    160       //
    161       // Legacy Boot Option
    162       //
    163       ASSERT (BootOption.OptionalDataSize == sizeof (LEGACY_BOOT_OPTION_BBS_DATA));
    164 
    165       DeviceTypeArray[Index] = ((BBS_BBS_DEVICE_PATH *) BootOption.FilePath)->DeviceType;
    166       BbsIndexArray  [Index] = ((LEGACY_BOOT_OPTION_BBS_DATA *) BootOption.OptionalData)->BbsIndex;
    167     } else {
    168       DeviceTypeArray[Index] = BBS_TYPE_UNKNOWN;
    169       BbsIndexArray  [Index] = 0xFFFF;
    170     }
    171     EfiBootManagerFreeLoadOption (&BootOption);
    172   }
    173 
    174   //
    175   // Record the corresponding Boot Option Numbers according to the DevOrder
    176   // Record the EnBootOption and DisBootOption according to the DevOrder
    177   //
    178   StartPosition = BootOrderSize / sizeof (UINT16);
    179   NewBootOption = AllocatePool (DevOrderCount * sizeof (UINT16));
    180   ASSERT (NewBootOption != NULL);
    181   while (DevOrderCount-- != 0) {
    182     for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {
    183       if (BbsIndexArray[Index] == (DevOrder[DevOrderCount] & 0xFF)) {
    184         StartPosition = MIN (StartPosition, Index);
    185         NewBootOption[DevOrderCount] = BootOrder[Index];
    186 
    187         if ((DevOrder[DevOrderCount] & 0xFF00) == 0xFF00) {
    188           (*DisBootOption)[*DisBootOptionCount] = BootOrder[Index];
    189           (*DisBootOptionCount)++;
    190         } else {
    191           (*EnBootOption)[*EnBootOptionCount] = BootOrder[Index];
    192           (*EnBootOptionCount)++;
    193         }
    194         break;
    195       }
    196     }
    197   }
    198 
    199   //
    200   // Overwrite the old BootOption
    201   //
    202   CopyMem (&BootOrder[StartPosition], NewBootOption, (*DisBootOptionCount + *EnBootOptionCount) * sizeof (UINT16));
    203   Status = gRT->SetVariable (
    204                   L"BootOrder",
    205                   &gEfiGlobalVariableGuid,
    206                   VAR_FLAG,
    207                   BootOrderSize,
    208                   BootOrder
    209                   );
    210   ASSERT_EFI_ERROR (Status);
    211 
    212   FreePool (NewBootOption);
    213   FreePool (DeviceTypeArray);
    214   FreePool (BbsIndexArray);
    215 }
    216 
    217 /**
    218   Update the legacy BBS boot option. L"LegacyDevOrder" and gEfiLegacyDevOrderVariableGuid EFI Variable
    219   is udpated with the new Legacy Boot order. The EFI Variable of "Boot####" and gEfiGlobalVariableGuid
    220   is also updated.
    221 
    222   @param NVMapData   The data for egacy BBS boot.
    223 
    224   @return EFI_SUCCESS           The function completed successfully.
    225   @retval EFI_NOT_FOUND         If L"LegacyDevOrder" and gEfiLegacyDevOrderVariableGuid EFI Variable can be found.
    226   @retval EFI_OUT_OF_RESOURCES  Fail to allocate memory resource
    227 **/
    228 EFI_STATUS
    229 UpdateBBSOption (
    230   IN LEGACY_BOOT_NV_DATA            *NVMapData
    231   )
    232 {
    233   UINTN                       Index;
    234   UINTN                       Index2;
    235   UINTN                       CurrentType;
    236   VOID                        *BootOptionVar;
    237   CHAR16                      VarName[100];
    238   UINTN                       OptionSize;
    239   EFI_STATUS                  Status;
    240   UINT32                      *Attribute;
    241   LEGACY_MENU_OPTION          *OptionMenu;
    242   UINT16                      *LegacyDev;
    243   UINT16                      *InitialLegacyDev;
    244   UINT8                       *VarData;
    245   UINTN                       VarSize;
    246   LEGACY_DEV_ORDER_ENTRY      *DevOrder;
    247   UINT8                       *OriginalPtr;
    248   UINT8                       *DisMap;
    249   UINTN                       Pos;
    250   UINTN                       Bit;
    251   UINT16                      *NewOrder;
    252   UINT16                      Tmp;
    253   UINT16                      *EnBootOption;
    254   UINTN                       EnBootOptionCount;
    255   UINT16                      *DisBootOption;
    256   UINTN                       DisBootOptionCount;
    257   UINTN                       BufferSize;
    258 
    259 
    260   DisMap              = NULL;
    261   NewOrder            = NULL;
    262   CurrentType         = 0;
    263 
    264 
    265   DisMap  = mLegacyBootOptionPrivate->MaintainMapData->DisableMap;
    266   Status  = EFI_SUCCESS;
    267 
    268   //
    269   // Update the Variable "LegacyDevOrder"
    270   //
    271   GetVariable2 (VAR_LEGACY_DEV_ORDER, &gEfiLegacyDevOrderVariableGuid, (VOID **) &VarData, &VarSize);
    272   if (VarData == NULL) {
    273     return EFI_NOT_FOUND;
    274   }
    275   OriginalPtr = VarData;
    276 
    277   while (mBbsType[CurrentType] != BBS_UNKNOWN) {
    278     switch (mBbsType[CurrentType]) {
    279     case BBS_FLOPPY:
    280       OptionMenu            = (LEGACY_MENU_OPTION *) &LegacyFDMenu;
    281       LegacyDev             = NVMapData->LegacyFD;
    282       InitialLegacyDev     = mLegacyBootOptionPrivate->MaintainMapData->InitialNvData.LegacyFD;
    283       BufferSize            = sizeof (NVMapData->LegacyFD);
    284       break;
    285 
    286     case BBS_HARDDISK:
    287       OptionMenu            = (LEGACY_MENU_OPTION *) &LegacyHDMenu;
    288       LegacyDev             = NVMapData->LegacyHD;
    289       InitialLegacyDev     = mLegacyBootOptionPrivate->MaintainMapData->InitialNvData.LegacyHD;
    290 
    291       BufferSize            = sizeof (NVMapData->LegacyHD);
    292       break;
    293 
    294     case BBS_CDROM:
    295       OptionMenu            = (LEGACY_MENU_OPTION *) &LegacyCDMenu;
    296       LegacyDev             = NVMapData->LegacyCD;
    297       InitialLegacyDev     = mLegacyBootOptionPrivate->MaintainMapData->InitialNvData.LegacyCD;
    298       BufferSize            = sizeof (NVMapData->LegacyCD);
    299       break;
    300 
    301     case BBS_EMBED_NETWORK:
    302       OptionMenu            = (LEGACY_MENU_OPTION *) &LegacyNETMenu;
    303       LegacyDev             = NVMapData->LegacyNET;
    304       InitialLegacyDev     = mLegacyBootOptionPrivate->MaintainMapData->InitialNvData.LegacyNET;
    305       BufferSize            = sizeof (NVMapData->LegacyNET);
    306       break;
    307 
    308     default:
    309       ASSERT (mBbsType[CurrentType] == BBS_BEV_DEVICE);
    310       OptionMenu            = (LEGACY_MENU_OPTION *) &LegacyBEVMenu;
    311       LegacyDev             = NVMapData->LegacyBEV;
    312       InitialLegacyDev     = mLegacyBootOptionPrivate->MaintainMapData->InitialNvData.LegacyBEV;
    313       BufferSize            = sizeof (NVMapData->LegacyBEV);
    314       break;
    315     }
    316 
    317     //
    318     // Check whether has value changed.
    319     //
    320     if (CompareMem (LegacyDev, InitialLegacyDev, BufferSize) == 0) {
    321       CurrentType++;
    322       continue;
    323     }
    324 
    325     DevOrder    = (LEGACY_DEV_ORDER_ENTRY *) OriginalPtr;
    326     while (VarData < OriginalPtr + VarSize) {
    327       if (DevOrder->BbsType == mBbsType[CurrentType]) {
    328         break;
    329       }
    330 
    331       VarData += sizeof (BBS_TYPE) + DevOrder->Length;
    332       DevOrder = (LEGACY_DEV_ORDER_ENTRY *) VarData;
    333     }
    334 
    335     if (VarData >= OriginalPtr + VarSize) {
    336       FreePool (OriginalPtr);
    337       return EFI_NOT_FOUND;
    338     }
    339 
    340     NewOrder = AllocateZeroPool (DevOrder->Length - sizeof (DevOrder->Length));
    341     if (NewOrder == NULL) {
    342       FreePool (OriginalPtr);
    343       return EFI_OUT_OF_RESOURCES;
    344     }
    345 
    346     for (Index = 0; Index < OptionMenu->MenuNumber; Index++) {
    347       if (0xFF == LegacyDev[Index]) {
    348         break;
    349       }
    350 
    351       NewOrder[Index] = LegacyDev[Index];
    352     }
    353 
    354     //
    355     // Only the enable/disable state of each boot device with same device type can be changed,
    356     // so we can count on the index information in DevOrder.
    357     // DisMap bit array is the only reliable source to check a device's en/dis state,
    358     // so we use DisMap to set en/dis state of each item in NewOrder array
    359     //
    360     for (Index2 = 0; Index2 < OptionMenu->MenuNumber; Index2++) {
    361       Tmp = (UINT16) (DevOrder->Data[Index2] & 0xFF);
    362       Pos = Tmp / 8;
    363       Bit = 7 - (Tmp % 8);
    364       if ((DisMap[Pos] & (1 << Bit)) != 0) {
    365         NewOrder[Index] = (UINT16) (0xFF00 | Tmp);
    366         Index++;
    367       }
    368     }
    369 
    370     CopyMem (
    371       DevOrder->Data,
    372       NewOrder,
    373       DevOrder->Length - sizeof (DevOrder->Length)
    374       );
    375     FreePool (NewOrder);
    376 
    377     //
    378     // Update BootOrder and Boot####.Attribute
    379     //
    380     // 1. Re-order the Option Number in BootOrder according to Legacy Dev Order
    381     //
    382     ASSERT (OptionMenu->MenuNumber == DevOrder->Length / sizeof (UINT16) - 1);
    383 
    384     OrderLegacyBootOption4SameType (
    385       DevOrder->Data,
    386       DevOrder->Length / sizeof (UINT16) - 1,
    387       &EnBootOption,
    388       &EnBootOptionCount,
    389       &DisBootOption,
    390       &DisBootOptionCount
    391       );
    392 
    393     //
    394     // 2. Deactivate the DisBootOption and activate the EnBootOption
    395     //
    396     for (Index = 0; Index < DisBootOptionCount; Index++) {
    397       UnicodeSPrint (VarName, sizeof (VarName), L"Boot%04x", DisBootOption[Index]);
    398       GetEfiGlobalVariable2 (VarName, (VOID **) &BootOptionVar, &OptionSize);
    399       if (BootOptionVar != NULL) {
    400         Attribute   = (UINT32 *) BootOptionVar;
    401         *Attribute &= ~LOAD_OPTION_ACTIVE;
    402 
    403         Status = gRT->SetVariable (
    404                         VarName,
    405                         &gEfiGlobalVariableGuid,
    406                         VAR_FLAG,
    407                         OptionSize,
    408                         BootOptionVar
    409                         );
    410 
    411         FreePool (BootOptionVar);
    412       }
    413     }
    414 
    415     for (Index = 0; Index < EnBootOptionCount; Index++) {
    416       UnicodeSPrint (VarName, sizeof (VarName), L"Boot%04x", EnBootOption[Index]);
    417       GetEfiGlobalVariable2 (VarName, (VOID **) &BootOptionVar, &OptionSize);
    418       if (BootOptionVar != NULL) {
    419         Attribute   = (UINT32 *) BootOptionVar;
    420         *Attribute |= LOAD_OPTION_ACTIVE;
    421 
    422         Status = gRT->SetVariable (
    423                         VarName,
    424                         &gEfiGlobalVariableGuid,
    425                         VAR_FLAG,
    426                         OptionSize,
    427                         BootOptionVar
    428                         );
    429 
    430         FreePool (BootOptionVar);
    431       }
    432     }
    433 
    434 
    435     FreePool (EnBootOption);
    436     FreePool (DisBootOption);
    437 
    438     CurrentType++;
    439   }
    440 
    441   Status = gRT->SetVariable (
    442                   VAR_LEGACY_DEV_ORDER,
    443                   &gEfiLegacyDevOrderVariableGuid,
    444                   EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
    445                   VarSize,
    446                   OriginalPtr
    447                   );
    448 
    449   FreePool (OriginalPtr);
    450   return Status;
    451 }
    452 
    453 /**
    454   This function allows a caller to extract the current configuration for one
    455   or more named elements from the target driver.
    456 
    457 
    458   @param This            Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
    459   @param Request         A null-terminated Unicode string in <ConfigRequest> format.
    460   @param Progress        On return, points to a character in the Request string.
    461                          Points to the string's null terminator if request was successful.
    462                          Points to the most recent '&' before the first failing name/value
    463                          pair (or the beginning of the string if the failure is in the
    464                          first name/value pair) if the request was not successful.
    465   @param Results         A null-terminated Unicode string in <ConfigAltResp> format which
    466                          has all values filled in for the names in the Request string.
    467                          String to be allocated by the called function.
    468 
    469   @retval  EFI_SUCCESS            The Results is filled with the requested values.
    470   @retval  EFI_OUT_OF_RESOURCES   Not enough memory to store the results.
    471   @retval  EFI_INVALID_PARAMETER  Request is illegal syntax, or unknown name.
    472   @retval  EFI_NOT_FOUND          Routing data doesn't match any storage in this driver.
    473 
    474 **/
    475 EFI_STATUS
    476 EFIAPI
    477 LegacyBootOptionExtractConfig (
    478   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
    479   IN  CONST EFI_STRING                       Request,
    480   OUT EFI_STRING                             *Progress,
    481   OUT EFI_STRING                             *Results
    482   )
    483 {
    484   if (Progress == NULL || Results == NULL) {
    485     return EFI_INVALID_PARAMETER;
    486   }
    487   *Progress = Request;
    488   return EFI_NOT_FOUND;
    489 }
    490 
    491 /**
    492   This function processes the results of changes in configuration.
    493 
    494 
    495   @param This            Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
    496   @param Configuration   A null-terminated Unicode string in <ConfigResp> format.
    497   @param Progress        A pointer to a string filled in with the offset of the most
    498                          recent '&' before the first failing name/value pair (or the
    499                          beginning of the string if the failure is in the first
    500                          name/value pair) or the terminating NULL if all was successful.
    501 
    502   @retval  EFI_SUCCESS            The Results is processed successfully.
    503   @retval  EFI_INVALID_PARAMETER  Configuration is NULL.
    504   @retval  EFI_NOT_FOUND          Routing data doesn't match any storage in this driver.
    505 
    506 **/
    507 EFI_STATUS
    508 EFIAPI
    509 LegacyBootOptionRouteConfig (
    510   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
    511   IN  CONST EFI_STRING                       Configuration,
    512   OUT       EFI_STRING                       *Progress
    513   )
    514 {
    515   EFI_STATUS                      Status;
    516   EFI_HII_CONFIG_ROUTING_PROTOCOL *ConfigRouting;
    517   LEGACY_BOOT_NV_DATA             *CurrentNVMapData;
    518   UINTN                           BufferSize;
    519 
    520 
    521   if (Configuration == NULL || Progress == NULL) {
    522     return EFI_INVALID_PARAMETER;
    523   }
    524 
    525   //
    526   // Check routing data in <ConfigHdr>.
    527   // Note: there is no name for Name/Value storage, only GUID will be checked
    528   //
    529   if (!HiiIsConfigHdrMatch (Configuration, &mLegacyBootOptionGuid, mLegacyBootStorageName)) {
    530     return EFI_NOT_FOUND;
    531   }
    532 
    533   Status = gBS->LocateProtocol (
    534                   &gEfiHiiConfigRoutingProtocolGuid,
    535                   NULL,
    536                   (VOID **) &ConfigRouting
    537                   );
    538   if (EFI_ERROR (Status)) {
    539     return Status;
    540   }
    541 
    542   //
    543   // Convert <ConfigResp> to buffer data by helper function ConfigToBlock()
    544   //
    545   CurrentNVMapData = &mLegacyBootOptionPrivate->MaintainMapData->CurrentNvData;
    546   Status = ConfigRouting->ConfigToBlock (
    547                             ConfigRouting,
    548                             Configuration,
    549                             (UINT8 *) CurrentNVMapData,
    550                             &BufferSize,
    551                             Progress
    552                             );
    553   ASSERT_EFI_ERROR (Status);
    554 
    555   Status = UpdateBBSOption (CurrentNVMapData);
    556 
    557   return Status;
    558 }
    559 
    560 /**
    561   Refresh the global UpdateData structure.
    562 
    563 **/
    564 VOID
    565 RefreshLegacyUpdateData (
    566   VOID
    567   )
    568 {
    569   //
    570   // Free current updated date
    571   //
    572   if (mLegacyStartOpCodeHandle != NULL) {
    573     HiiFreeOpCodeHandle (mLegacyStartOpCodeHandle);
    574   }
    575   if (mLegacyEndOpCodeHandle != NULL) {
    576     HiiFreeOpCodeHandle (mLegacyEndOpCodeHandle);
    577   }
    578 
    579   //
    580   // Create new OpCode Handle
    581   //
    582   mLegacyStartOpCodeHandle = HiiAllocateOpCodeHandle ();
    583   mLegacyEndOpCodeHandle = HiiAllocateOpCodeHandle ();
    584 
    585   //
    586   // Create Hii Extend Label OpCode as the start opcode
    587   //
    588   mLegacyStartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
    589                                          mLegacyStartOpCodeHandle,
    590                                          &gEfiIfrTianoGuid,
    591                                          NULL,
    592                                          sizeof (EFI_IFR_GUID_LABEL)
    593                                          );
    594   mLegacyStartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
    595 
    596   mLegacyStartLabel->Number = FORM_BOOT_LEGACY_DEVICE_ID;
    597 
    598   //
    599   // Create Hii Extend Label OpCode as the start opcode
    600   //
    601   mLegacyEndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
    602                                          mLegacyEndOpCodeHandle,
    603                                          &gEfiIfrTianoGuid,
    604                                          NULL,
    605                                          sizeof (EFI_IFR_GUID_LABEL)
    606                                          );
    607   mLegacyEndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
    608 
    609   mLegacyEndLabel->Number = FORM_BOOT_LEGACY_LABEL_END;
    610 
    611 }
    612 
    613 /**
    614   Get the Menu Entry from the list in Menu Entry List.
    615 
    616   If MenuNumber is great or equal to the number of Menu
    617   Entry in the list, then ASSERT.
    618 
    619   @param MenuOption      The Menu Entry List to read the menu entry.
    620   @param MenuNumber      The index of Menu Entry.
    621 
    622   @return The Menu Entry.
    623 
    624 **/
    625 LEGACY_MENU_ENTRY *
    626 GetMenuEntry (
    627   LEGACY_MENU_OPTION      *MenuOption,
    628   UINTN                   MenuNumber
    629   )
    630 {
    631   LEGACY_MENU_ENTRY   *NewMenuEntry;
    632   UINTN               Index;
    633   LIST_ENTRY          *List;
    634 
    635   ASSERT (MenuNumber < MenuOption->MenuNumber);
    636 
    637   List = MenuOption->Head.ForwardLink;
    638   for (Index = 0; Index < MenuNumber; Index++) {
    639     List = List->ForwardLink;
    640   }
    641 
    642   NewMenuEntry = CR (List, LEGACY_MENU_ENTRY, Link, LEGACY_MENU_ENTRY_SIGNATURE);
    643 
    644   return NewMenuEntry;
    645 }
    646 
    647 /**
    648   Create string tokens for a menu from its help strings and display strings
    649 
    650   @param HiiHandle          Hii Handle of the package to be updated.
    651   @param MenuOption         The Menu whose string tokens need to be created
    652 
    653 **/
    654 VOID
    655 CreateLegacyMenuStringToken (
    656   IN EFI_HII_HANDLE                   HiiHandle,
    657   IN LEGACY_MENU_OPTION               *MenuOption
    658   )
    659 {
    660   LEGACY_MENU_ENTRY *NewMenuEntry;
    661   UINTN             Index;
    662 
    663   for (Index = 0; Index < MenuOption->MenuNumber; Index++) {
    664     NewMenuEntry = GetMenuEntry (MenuOption, Index);
    665 
    666     NewMenuEntry->DisplayStringToken = HiiSetString (
    667                                          HiiHandle,
    668                                          0,
    669                                          NewMenuEntry->DisplayString,
    670                                          NULL
    671                                          );
    672 
    673     if (NULL == NewMenuEntry->HelpString) {
    674       NewMenuEntry->HelpStringToken = NewMenuEntry->DisplayStringToken;
    675     } else {
    676       NewMenuEntry->HelpStringToken = HiiSetString (
    677                                         HiiHandle,
    678                                         0,
    679                                         NewMenuEntry->HelpString,
    680                                         NULL
    681                                         );
    682     }
    683   }
    684 }
    685 
    686 /**
    687   Create a dynamic page so that Legacy Device boot order
    688   can be set for specified device type.
    689 
    690   @param UpdatePageId    The form ID. It also spefies the legacy device type.
    691 
    692 
    693 **/
    694 VOID
    695 UpdateLegacyDeviceOrderPage (
    696   IN UINT16                           UpdatePageId
    697   )
    698 {
    699   LEGACY_MENU_OPTION          *OptionMenu;
    700   LEGACY_MENU_ENTRY           *NewMenuEntry;
    701   EFI_STRING_ID               StrRef;
    702   EFI_STRING_ID               StrRefHelp;
    703   BBS_TYPE                    BbsType;
    704   UINT16                      *Default;
    705   UINT16                      Index;
    706   UINT16                      Key;
    707   CHAR16                      String[100];
    708   CHAR16                      *TypeStr;
    709   CHAR16                      *TypeStrHelp;
    710   CHAR16                      *FormTitle;
    711   VOID                        *OptionsOpCodeHandle;
    712   VOID                        *DefaultOpCodeHandle;
    713 
    714   Key         = 0;
    715   StrRef      = 0;
    716   StrRefHelp  = 0;
    717   OptionMenu  = NULL;
    718   TypeStr     = NULL;
    719   TypeStrHelp = NULL;
    720   Default     = NULL;
    721   BbsType     = BBS_FLOPPY;
    722 
    723   RefreshLegacyUpdateData();
    724 
    725   //
    726   // Create oneof option list
    727   //
    728   switch (UpdatePageId) {
    729   case FORM_FLOPPY_BOOT_ID:
    730     OptionMenu  = (LEGACY_MENU_OPTION *) &LegacyFDMenu;
    731     Key         = (UINT16) LEGACY_FD_QUESTION_ID;
    732     TypeStr     = STR_FLOPPY;
    733     TypeStrHelp = STR_FLOPPY_HELP;
    734     FormTitle   = STR_FLOPPY_TITLE;
    735     BbsType     = BBS_FLOPPY;
    736     Default     = mLegacyBootOptionPrivate->MaintainMapData->CurrentNvData.LegacyFD;
    737     break;
    738 
    739   case FORM_HARDDISK_BOOT_ID:
    740     OptionMenu  = (LEGACY_MENU_OPTION *) &LegacyHDMenu;
    741     Key         = (UINT16) LEGACY_HD_QUESTION_ID;
    742     TypeStr     = STR_HARDDISK;
    743     TypeStrHelp = STR_HARDDISK_HELP;
    744     FormTitle   = STR_HARDDISK_TITLE;
    745     BbsType     = BBS_HARDDISK;
    746     Default     = mLegacyBootOptionPrivate->MaintainMapData->CurrentNvData.LegacyHD;
    747     break;
    748 
    749   case FORM_CDROM_BOOT_ID:
    750     OptionMenu  = (LEGACY_MENU_OPTION *) &LegacyCDMenu;
    751     Key         = (UINT16) LEGACY_CD_QUESTION_ID;
    752     TypeStr     = STR_CDROM;
    753     TypeStrHelp = STR_CDROM_HELP;
    754     FormTitle   = STR_CDROM_TITLE;
    755     BbsType     = BBS_CDROM;
    756     Default     = mLegacyBootOptionPrivate->MaintainMapData->CurrentNvData.LegacyCD;
    757     break;
    758 
    759   case FORM_NET_BOOT_ID:
    760     OptionMenu  = (LEGACY_MENU_OPTION *) &LegacyNETMenu;
    761     Key         = (UINT16) LEGACY_NET_QUESTION_ID;
    762     TypeStr     = STR_NET;
    763     TypeStrHelp = STR_NET_HELP;
    764     FormTitle   = STR_NET_TITLE;
    765     BbsType     = BBS_EMBED_NETWORK;
    766     Default     = mLegacyBootOptionPrivate->MaintainMapData->CurrentNvData.LegacyNET;
    767     break;
    768 
    769   case FORM_BEV_BOOT_ID:
    770     OptionMenu  = (LEGACY_MENU_OPTION *) &LegacyBEVMenu;
    771     Key         = (UINT16) LEGACY_BEV_QUESTION_ID;
    772     TypeStr     = STR_BEV;
    773     TypeStrHelp = STR_BEV_HELP;
    774     FormTitle   = STR_BEV_TITLE;
    775     BbsType     = BBS_BEV_DEVICE;
    776     Default     = mLegacyBootOptionPrivate->MaintainMapData->CurrentNvData.LegacyBEV;
    777     break;
    778 
    779   default:
    780     DEBUG ((EFI_D_ERROR, "Invalid command ID for updating page!\n"));
    781     return;
    782   }
    783 
    784   HiiSetString (mLegacyBootOptionPrivate->HiiHandle, STRING_TOKEN(STR_ORDER_CHANGE_PROMPT), FormTitle, NULL);
    785 
    786   CreateLegacyMenuStringToken (mLegacyBootOptionPrivate->HiiHandle, OptionMenu);
    787 
    788   OptionsOpCodeHandle = HiiAllocateOpCodeHandle ();
    789   ASSERT (OptionsOpCodeHandle != NULL);
    790 
    791 
    792   for (Index = 0; Index < OptionMenu->MenuNumber; Index++) {
    793     NewMenuEntry = GetMenuEntry (OptionMenu, Index);
    794     //
    795     // Create OneOf for each legacy device
    796     //
    797     HiiCreateOneOfOptionOpCode (
    798       OptionsOpCodeHandle,
    799       NewMenuEntry->DisplayStringToken,
    800       0,
    801       EFI_IFR_TYPE_NUM_SIZE_16,
    802       ((LEGACY_DEVICE_CONTEXT *) NewMenuEntry->VariableContext)->BbsIndex
    803       );
    804   }
    805 
    806   //
    807   // Create OneOf for item "Disabled"
    808   //
    809   HiiCreateOneOfOptionOpCode (
    810     OptionsOpCodeHandle,
    811     STRING_TOKEN (STR_DISABLE_LEGACY_DEVICE),
    812     0,
    813     EFI_IFR_TYPE_NUM_SIZE_16,
    814     0xFF
    815     );
    816 
    817   //
    818   // Create oneof tag here for FD/HD/CD #1 #2
    819   //
    820   for (Index = 0; Index < OptionMenu->MenuNumber; Index++) {
    821     DefaultOpCodeHandle = HiiAllocateOpCodeHandle ();
    822     ASSERT (DefaultOpCodeHandle != NULL);
    823 
    824     HiiCreateDefaultOpCode (
    825       DefaultOpCodeHandle,
    826       EFI_HII_DEFAULT_CLASS_STANDARD,
    827       EFI_IFR_TYPE_NUM_SIZE_16,
    828       *Default++
    829       );
    830 
    831     //
    832     // Create the string for oneof tag
    833     //
    834     UnicodeSPrint (String, sizeof (String), TypeStr, Index);
    835     StrRef = HiiSetString (mLegacyBootOptionPrivate->HiiHandle, 0, String, NULL);
    836 
    837     UnicodeSPrint (String, sizeof (String), TypeStrHelp, Index);
    838     StrRefHelp = HiiSetString (mLegacyBootOptionPrivate->HiiHandle, 0, String, NULL);
    839 
    840     HiiCreateOneOfOpCode (
    841       mLegacyStartOpCodeHandle,
    842       (EFI_QUESTION_ID) (Key + Index),
    843       VARSTORE_ID_LEGACY_BOOT,
    844       (UINT16) (Key + Index * 2 - CONFIG_OPTION_OFFSET),
    845       StrRef,
    846       StrRefHelp,
    847       EFI_IFR_FLAG_CALLBACK,
    848       EFI_IFR_NUMERIC_SIZE_2,
    849       OptionsOpCodeHandle,
    850       DefaultOpCodeHandle //NULL //
    851       );
    852 
    853     HiiFreeOpCodeHandle (DefaultOpCodeHandle);
    854   }
    855 
    856   HiiUpdateForm (
    857     mLegacyBootOptionPrivate->HiiHandle,
    858     &mLegacyBootOptionGuid,
    859     LEGACY_ORDER_CHANGE_FORM_ID,
    860     mLegacyStartOpCodeHandle,
    861     mLegacyEndOpCodeHandle
    862     );
    863 
    864   HiiFreeOpCodeHandle (OptionsOpCodeHandle);
    865 }
    866 
    867 
    868 /**
    869   Adjust question value when one question value has been changed.
    870 
    871   @param QuestionId    The question id for the value changed question.
    872   @param Value         The value for the changed question.
    873 
    874 **/
    875 VOID
    876 AdjustOptionValue (
    877   IN  UINT16                                 QuestionId,
    878   IN  EFI_IFR_TYPE_VALUE                     *Value
    879   )
    880 {
    881   UINTN                       Number;
    882   BBS_TYPE                    BbsType;
    883   LEGACY_DEV_ORDER_ENTRY      *DevOrder;
    884   UINT16                      *Default;
    885   LEGACY_BOOT_NV_DATA         *CurrentNVMap;
    886   UINT16                      *CurrentVal;
    887   UINTN                       Index;
    888   UINTN                       Index2;
    889   UINTN                       Index3;
    890   UINTN                       NewValuePos;
    891   UINTN                       OldValue;
    892   UINTN                       NewValue;
    893   UINT8                       *DisMap;
    894   UINTN                       Pos;
    895   UINTN                       Bit;
    896 
    897   Number = 0;
    898   BbsType = BBS_UNKNOWN;
    899   CurrentVal = 0;
    900   DevOrder = NULL;
    901   Default = NULL;
    902   NewValue = 0;
    903   NewValuePos = 0;
    904   OldValue = 0;
    905 
    906   //
    907   // Update Select FD/HD/CD/NET/BEV Order Form
    908   //
    909   ASSERT ((QuestionId >= LEGACY_FD_QUESTION_ID) && (QuestionId < LEGACY_BEV_QUESTION_ID + MAX_MENU_NUMBER));
    910 
    911   CurrentNVMap = &mLegacyBootOptionPrivate->MaintainMapData->CurrentNvData;
    912   HiiGetBrowserData (&mLegacyBootOptionGuid, mLegacyBootStorageName, sizeof (LEGACY_BOOT_NV_DATA), (UINT8 *) CurrentNVMap);
    913   DisMap  = mLegacyBootOptionPrivate->MaintainMapData->DisableMap;
    914 
    915   if (QuestionId >= LEGACY_FD_QUESTION_ID && QuestionId < LEGACY_FD_QUESTION_ID + MAX_MENU_NUMBER) {
    916     Number      = (UINT16) LegacyFDMenu.MenuNumber;
    917     BbsType     = BBS_FLOPPY;
    918     CurrentVal  = CurrentNVMap->LegacyFD;
    919     Default     = mLegacyBootOptionPrivate->MaintainMapData->LastTimeNvData.LegacyFD;
    920   } else if (QuestionId >= LEGACY_HD_QUESTION_ID && QuestionId < LEGACY_HD_QUESTION_ID + MAX_MENU_NUMBER) {
    921     Number      = (UINT16) LegacyHDMenu.MenuNumber;
    922     BbsType     = BBS_HARDDISK;
    923     CurrentVal  = CurrentNVMap->LegacyHD;
    924     Default     = mLegacyBootOptionPrivate->MaintainMapData->LastTimeNvData.LegacyHD;
    925   } else if (QuestionId >= LEGACY_CD_QUESTION_ID && QuestionId < LEGACY_CD_QUESTION_ID + MAX_MENU_NUMBER) {
    926     Number      = (UINT16) LegacyCDMenu.MenuNumber;
    927     BbsType     = BBS_CDROM;
    928     CurrentVal  = CurrentNVMap->LegacyCD;
    929     Default     = mLegacyBootOptionPrivate->MaintainMapData->LastTimeNvData.LegacyCD;
    930   } else if (QuestionId >= LEGACY_NET_QUESTION_ID && QuestionId < LEGACY_NET_QUESTION_ID + MAX_MENU_NUMBER) {
    931     Number      = (UINT16) LegacyNETMenu.MenuNumber;
    932     BbsType     = BBS_EMBED_NETWORK;
    933     CurrentVal  = CurrentNVMap->LegacyNET;
    934     Default     = mLegacyBootOptionPrivate->MaintainMapData->LastTimeNvData.LegacyNET;
    935   } else if (QuestionId >= LEGACY_BEV_QUESTION_ID && QuestionId < LEGACY_BEV_QUESTION_ID + MAX_MENU_NUMBER) {
    936     Number      = (UINT16) LegacyBEVMenu.MenuNumber;
    937     BbsType     = BBS_BEV_DEVICE;
    938     CurrentVal  = CurrentNVMap->LegacyBEV;
    939     Default     = mLegacyBootOptionPrivate->MaintainMapData->LastTimeNvData.LegacyBEV;
    940   }
    941 
    942   //
    943   //  First, find the different position
    944   //  if there is change, it should be only one
    945   //
    946   for (Index = 0; Index < Number; Index++) {
    947     if (CurrentVal[Index] != Default[Index]) {
    948       OldValue  = Default[Index];
    949       NewValue  = CurrentVal[Index];
    950       break;
    951     }
    952   }
    953 
    954   if (Index != Number) {
    955     //
    956     // there is change, now process
    957     //
    958     if (0xFF == NewValue) {
    959       //
    960       // This item will be disable
    961       // Just move the items behind this forward to overlap it
    962       //
    963       Pos = OldValue / 8;
    964       Bit = 7 - (OldValue % 8);
    965       DisMap[Pos] = (UINT8) (DisMap[Pos] | (UINT8) (1 << Bit));
    966       for (Index2 = Index; Index2 < Number - 1; Index2++) {
    967         CurrentVal[Index2] = CurrentVal[Index2 + 1];
    968       }
    969 
    970       CurrentVal[Index2] = 0xFF;
    971     } else {
    972       for (Index2 = 0; Index2 < Number; Index2++) {
    973         if (Index2 == Index) {
    974           continue;
    975         }
    976 
    977         if (Default[Index2] == NewValue) {
    978           //
    979           // If NewValue is in OldLegacyDev array
    980           // remember its old position
    981           //
    982           NewValuePos = Index2;
    983           break;
    984         }
    985       }
    986 
    987       if (Index2 != Number) {
    988         //
    989         // We will change current item to an existing item
    990         // (It's hard to describe here, please read code, it's like a cycle-moving)
    991         //
    992         for (Index2 = NewValuePos; Index2 != Index;) {
    993           if (NewValuePos < Index) {
    994             CurrentVal[Index2] = Default[Index2 + 1];
    995             Index2++;
    996           } else {
    997             CurrentVal[Index2] = Default[Index2 - 1];
    998             Index2--;
    999           }
   1000         }
   1001       } else {
   1002         //
   1003         // If NewValue is not in OldlegacyDev array, we are changing to a disabled item
   1004         // so we should modify DisMap to reflect the change
   1005         //
   1006         Pos = NewValue / 8;
   1007         Bit = 7 - (NewValue % 8);
   1008         DisMap[Pos] = (UINT8) (DisMap[Pos] & (~ (UINT8) (1 << Bit)));
   1009         if (0xFF != OldValue) {
   1010           //
   1011           // Because NewValue is a item that was disabled before
   1012           // so after changing the OldValue should be disabled
   1013           // actually we are doing a swap of enable-disable states of two items
   1014           //
   1015           Pos = OldValue / 8;
   1016           Bit = 7 - (OldValue % 8);
   1017           DisMap[Pos] = (UINT8) (DisMap[Pos] | (UINT8) (1 << Bit));
   1018         }
   1019       }
   1020     }
   1021     //
   1022     // To prevent DISABLE appears in the middle of the list
   1023     // we should perform a re-ordering
   1024     //
   1025     Index3 = Index;
   1026     Index = 0;
   1027     while (Index < Number) {
   1028       if (0xFF != CurrentVal[Index]) {
   1029         Index++;
   1030         continue;
   1031       }
   1032 
   1033       Index2 = Index;
   1034       Index2++;
   1035       while (Index2 < Number) {
   1036         if (0xFF != CurrentVal[Index2]) {
   1037           break;
   1038         }
   1039 
   1040         Index2++;
   1041       }
   1042 
   1043       if (Index2 < Number) {
   1044         CurrentVal[Index]   = CurrentVal[Index2];
   1045         CurrentVal[Index2]  = 0xFF;
   1046       }
   1047 
   1048       Index++;
   1049     }
   1050 
   1051     //
   1052     // Return correct question value.
   1053     //
   1054     Value->u16 = CurrentVal[Index3];
   1055     CopyMem (Default, CurrentVal, sizeof (UINT16) * Number);
   1056   }
   1057 
   1058   //
   1059   // Pass changed uncommitted data back to Form Browser
   1060   //
   1061   HiiSetBrowserData (&mLegacyBootOptionGuid, mLegacyBootStorageName, sizeof (LEGACY_BOOT_NV_DATA), (UINT8 *) CurrentNVMap, NULL);
   1062 }
   1063 
   1064 /**
   1065   This call back function is registered with Boot Manager formset.
   1066   When user selects a boot option, this call back function will
   1067   be triggered. The boot option is saved for later processing.
   1068 
   1069 
   1070   @param This            Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
   1071   @param Action          Specifies the type of action taken by the browser.
   1072   @param QuestionId      A unique value which is sent to the original exporting driver
   1073                          so that it can identify the type of data to expect.
   1074   @param Type            The type of value for the question.
   1075   @param Value           A pointer to the data being sent to the original exporting driver.
   1076   @param ActionRequest   On return, points to the action requested by the callback function.
   1077 
   1078   @retval  EFI_SUCCESS           The callback successfully handled the action.
   1079   @retval  EFI_INVALID_PARAMETER The setup browser call this function with invalid parameters.
   1080 
   1081 **/
   1082 EFI_STATUS
   1083 EFIAPI
   1084 LegacyBootOptionCallback (
   1085   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
   1086   IN  EFI_BROWSER_ACTION                     Action,
   1087   IN  EFI_QUESTION_ID                        QuestionId,
   1088   IN  UINT8                                  Type,
   1089   IN  EFI_IFR_TYPE_VALUE                     *Value,
   1090   OUT EFI_BROWSER_ACTION_REQUEST             *ActionRequest
   1091   )
   1092 {
   1093   if (Action != EFI_BROWSER_ACTION_CHANGED && Action != EFI_BROWSER_ACTION_CHANGING) {
   1094     //
   1095     // Do nothing for other UEFI Action. Only do call back when data is changed.
   1096     //
   1097     return EFI_UNSUPPORTED;
   1098   }
   1099 
   1100   if ((Value == NULL) || (ActionRequest == NULL)) {
   1101     return EFI_INVALID_PARAMETER;
   1102   }
   1103 
   1104   if (Action == EFI_BROWSER_ACTION_CHANGING) {
   1105     switch (QuestionId) {
   1106     case FORM_FLOPPY_BOOT_ID:
   1107     case FORM_HARDDISK_BOOT_ID:
   1108     case FORM_CDROM_BOOT_ID:
   1109     case FORM_NET_BOOT_ID:
   1110     case FORM_BEV_BOOT_ID:
   1111       UpdateLegacyDeviceOrderPage (QuestionId);
   1112       break;
   1113 
   1114     default:
   1115       break;
   1116     }
   1117   } else if (Action == EFI_BROWSER_ACTION_CHANGED) {
   1118     if ((Value == NULL) || (ActionRequest == NULL)) {
   1119       return EFI_INVALID_PARAMETER;
   1120     }
   1121 
   1122     if ((QuestionId >= LEGACY_FD_QUESTION_ID) && (QuestionId < LEGACY_BEV_QUESTION_ID + MAX_MENU_NUMBER)) {
   1123       AdjustOptionValue(QuestionId, Value);
   1124     }
   1125   }
   1126   return EFI_SUCCESS;
   1127 }
   1128 
   1129 
   1130 /**
   1131   Create a menu entry by given menu type.
   1132 
   1133   @param MenuType        The Menu type to be created.
   1134 
   1135   @retval NULL           If failed to create the menu.
   1136   @return the new menu entry.
   1137 
   1138 **/
   1139 LEGACY_MENU_ENTRY *
   1140 CreateMenuEntry (
   1141   VOID
   1142   )
   1143 {
   1144   LEGACY_MENU_ENTRY *MenuEntry;
   1145 
   1146   //
   1147   // Create new menu entry
   1148   //
   1149   MenuEntry = AllocateZeroPool (sizeof (LEGACY_MENU_ENTRY));
   1150   if (MenuEntry == NULL) {
   1151     return NULL;
   1152   }
   1153 
   1154   MenuEntry->VariableContext = AllocateZeroPool (sizeof (LEGACY_DEVICE_CONTEXT));
   1155   if (MenuEntry->VariableContext == NULL) {
   1156     FreePool (MenuEntry);
   1157     return NULL;
   1158   }
   1159 
   1160   MenuEntry->Signature        = LEGACY_MENU_ENTRY_SIGNATURE;
   1161   return MenuEntry;
   1162 }
   1163 
   1164 /**
   1165 
   1166   Base on the L"LegacyDevOrder" variable to build the current order data.
   1167 
   1168 **/
   1169 VOID
   1170 GetLegacyOptionsOrder (
   1171   VOID
   1172   )
   1173 {
   1174   UINTN                       VarSize;
   1175   UINT8                       *VarData;
   1176   UINT8                       *VarTmp;
   1177   LEGACY_DEV_ORDER_ENTRY      *DevOrder;
   1178   UINT16                      *LegacyDev;
   1179   UINTN                       Index;
   1180   LEGACY_MENU_OPTION          *OptionMenu;
   1181   UINT16                      VarDevOrder;
   1182   UINTN                       Pos;
   1183   UINTN                       Bit;
   1184   UINT8                       *DisMap;
   1185   UINTN                       TotalLength;
   1186 
   1187   LegacyDev = NULL;
   1188   OptionMenu = NULL;
   1189 
   1190   DisMap = ZeroMem (mLegacyBootOptionPrivate->MaintainMapData->DisableMap, sizeof (mLegacyBootOptionPrivate->MaintainMapData->DisableMap));
   1191 
   1192   //
   1193   // Get Device Order from variable
   1194   //
   1195   GetVariable2 (VAR_LEGACY_DEV_ORDER, &gEfiLegacyDevOrderVariableGuid, (VOID **) &VarData, &VarSize);
   1196   VarTmp = VarData;
   1197   if (NULL != VarData) {
   1198     DevOrder    = (LEGACY_DEV_ORDER_ENTRY *) VarData;
   1199     while (VarData < VarTmp + VarSize) {
   1200       switch (DevOrder->BbsType) {
   1201       case BBS_FLOPPY:
   1202         LegacyDev = mLegacyBootOptionPrivate->MaintainMapData->InitialNvData.LegacyFD;
   1203         OptionMenu = &LegacyFDMenu;
   1204         break;
   1205 
   1206       case BBS_HARDDISK:
   1207         LegacyDev = mLegacyBootOptionPrivate->MaintainMapData->InitialNvData.LegacyHD;
   1208         OptionMenu = &LegacyHDMenu;
   1209         break;
   1210 
   1211       case BBS_CDROM:
   1212         LegacyDev = mLegacyBootOptionPrivate->MaintainMapData->InitialNvData.LegacyCD;
   1213         OptionMenu = &LegacyCDMenu;
   1214         break;
   1215 
   1216       case BBS_EMBED_NETWORK:
   1217         LegacyDev = mLegacyBootOptionPrivate->MaintainMapData->InitialNvData.LegacyNET;
   1218         OptionMenu = &LegacyNETMenu;
   1219         break;
   1220 
   1221       case BBS_BEV_DEVICE:
   1222         LegacyDev = mLegacyBootOptionPrivate->MaintainMapData->InitialNvData.LegacyBEV;
   1223         OptionMenu = &LegacyBEVMenu;
   1224         break;
   1225 
   1226       case BBS_UNKNOWN:
   1227       default:
   1228         ASSERT (FALSE);
   1229         DEBUG ((DEBUG_ERROR, "Unsupported device type found!\n"));
   1230         break;
   1231       }
   1232 
   1233       //
   1234       // Create oneof tag here for FD/HD/CD #1 #2
   1235       //
   1236       for (Index = 0; Index < OptionMenu->MenuNumber; Index++) {
   1237         TotalLength = sizeof (BBS_TYPE) + sizeof (UINT16) + Index * sizeof (UINT16);
   1238         VarDevOrder = *(UINT16 *) ((UINT8 *) DevOrder + TotalLength);
   1239 
   1240         if (0xFF00 == (VarDevOrder & 0xFF00)) {
   1241           LegacyDev[Index]  = 0xFF;
   1242           Pos               = (VarDevOrder & 0xFF) / 8;
   1243           Bit               = 7 - ((VarDevOrder & 0xFF) % 8);
   1244           DisMap[Pos]       = (UINT8) (DisMap[Pos] | (UINT8) (1 << Bit));
   1245         } else {
   1246           LegacyDev[Index] = VarDevOrder & 0xFF;
   1247         }
   1248       }
   1249 
   1250       VarData ++;
   1251       VarData += *(UINT16 *) VarData;
   1252       DevOrder = (LEGACY_DEV_ORDER_ENTRY *) VarData;
   1253     }
   1254   }
   1255 
   1256   CopyMem (&mLegacyBootOptionPrivate->MaintainMapData->LastTimeNvData, &mLegacyBootOptionPrivate->MaintainMapData->InitialNvData, sizeof (LEGACY_BOOT_NV_DATA));
   1257   CopyMem (&mLegacyBootOptionPrivate->MaintainMapData->CurrentNvData, &mLegacyBootOptionPrivate->MaintainMapData->InitialNvData, sizeof (LEGACY_BOOT_NV_DATA));
   1258 }
   1259 
   1260 /**
   1261 
   1262   Build the LegacyFDMenu LegacyHDMenu LegacyCDMenu according to LegacyBios.GetBbsInfo().
   1263 
   1264 **/
   1265 VOID
   1266 GetLegacyOptions (
   1267   VOID
   1268   )
   1269 {
   1270   LEGACY_MENU_ENTRY             *NewMenuEntry;
   1271   LEGACY_DEVICE_CONTEXT         *NewLegacyDevContext;
   1272   EFI_BOOT_MANAGER_LOAD_OPTION  *BootOption;
   1273   UINTN                         BootOptionCount;
   1274   UINT16                        Index;
   1275   UINTN                         FDNum;
   1276   UINTN                         HDNum;
   1277   UINTN                         CDNum;
   1278   UINTN                         NETNum;
   1279   UINTN                         BEVNum;
   1280 
   1281   //
   1282   // Initialize Bbs Table Context from BBS info data
   1283   //
   1284   InitializeListHead (&LegacyFDMenu.Head);
   1285   InitializeListHead (&LegacyHDMenu.Head);
   1286   InitializeListHead (&LegacyCDMenu.Head);
   1287   InitializeListHead (&LegacyNETMenu.Head);
   1288   InitializeListHead (&LegacyBEVMenu.Head);
   1289 
   1290   FDNum   = 0;
   1291   HDNum   = 0;
   1292   CDNum   = 0;
   1293   NETNum  = 0;
   1294   BEVNum  = 0;
   1295 
   1296   EfiBootManagerConnectAll ();
   1297 
   1298   //
   1299   // for better user experience
   1300   // 1. User changes HD configuration (e.g.: unplug HDD), here we have a chance to remove the HDD boot option
   1301   // 2. User enables/disables UEFI PXE, here we have a chance to add/remove EFI Network boot option
   1302   //
   1303   EfiBootManagerRefreshAllBootOption ();
   1304 
   1305   BootOption = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
   1306   for (Index = 0; Index < BootOptionCount; Index++) {
   1307     if ((DevicePathType (BootOption[Index].FilePath) != BBS_DEVICE_PATH) ||
   1308         (DevicePathSubType (BootOption[Index].FilePath) != BBS_BBS_DP)
   1309        ) {
   1310       continue;
   1311     }
   1312     ASSERT (BootOption[Index].OptionalDataSize == sizeof (LEGACY_BOOT_OPTION_BBS_DATA));
   1313     NewMenuEntry = CreateMenuEntry ();
   1314     ASSERT (NewMenuEntry != NULL);
   1315 
   1316     NewLegacyDevContext              = (LEGACY_DEVICE_CONTEXT *) NewMenuEntry->VariableContext;
   1317     NewLegacyDevContext->BbsIndex    = ((LEGACY_BOOT_OPTION_BBS_DATA *) BootOption[Index].OptionalData)->BbsIndex;
   1318     NewLegacyDevContext->Description = AllocateCopyPool (StrSize (BootOption[Index].Description), BootOption[Index].Description);
   1319     ASSERT (NewLegacyDevContext->Description != NULL);
   1320 
   1321     NewMenuEntry->DisplayString = NewLegacyDevContext->Description;
   1322     NewMenuEntry->HelpString    = NULL;
   1323 
   1324     switch (((BBS_BBS_DEVICE_PATH *) BootOption[Index].FilePath)->DeviceType) {
   1325     case BBS_TYPE_FLOPPY:
   1326       InsertTailList (&LegacyFDMenu.Head, &NewMenuEntry->Link);
   1327       FDNum++;
   1328       break;
   1329 
   1330     case BBS_TYPE_HARDDRIVE:
   1331       InsertTailList (&LegacyHDMenu.Head, &NewMenuEntry->Link);
   1332       HDNum++;
   1333       break;
   1334 
   1335     case BBS_TYPE_CDROM:
   1336       InsertTailList (&LegacyCDMenu.Head, &NewMenuEntry->Link);
   1337       CDNum++;
   1338       break;
   1339 
   1340     case BBS_TYPE_EMBEDDED_NETWORK:
   1341       InsertTailList (&LegacyNETMenu.Head, &NewMenuEntry->Link);
   1342       NETNum++;
   1343       break;
   1344 
   1345     case BBS_TYPE_BEV:
   1346       InsertTailList (&LegacyBEVMenu.Head, &NewMenuEntry->Link);
   1347       BEVNum++;
   1348       break;
   1349     }
   1350   }
   1351 
   1352   EfiBootManagerFreeLoadOptions (BootOption, BootOptionCount);
   1353 
   1354   LegacyFDMenu.MenuNumber   = FDNum;
   1355   LegacyHDMenu.MenuNumber   = HDNum;
   1356   LegacyCDMenu.MenuNumber   = CDNum;
   1357   LegacyNETMenu.MenuNumber  = NETNum;
   1358   LegacyBEVMenu.MenuNumber  = BEVNum;
   1359 }
   1360 
   1361 
   1362 /**
   1363 
   1364   Install Boot Manager Menu driver.
   1365 
   1366   @param ImageHandle     The image handle.
   1367   @param SystemTable     The system table.
   1368 
   1369   @retval  EFI_SUCEESS  Install Boot manager menu success.
   1370   @retval  Other        Return error status.
   1371 
   1372 **/
   1373 EFI_STATUS
   1374 EFIAPI
   1375 LegacyBootMaintUiLibConstructor (
   1376   IN EFI_HANDLE                            ImageHandle,
   1377   IN EFI_SYSTEM_TABLE                      *SystemTable
   1378   )
   1379 {
   1380   EFI_STATUS                        Status;
   1381   EFI_LEGACY_BIOS_PROTOCOL          *LegacyBios;
   1382   LEGACY_BOOT_OPTION_CALLBACK_DATA  *LegacyBootOptionData;
   1383 
   1384   Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
   1385   if (!EFI_ERROR (Status)) {
   1386     //
   1387     // Create LegacyBootOptionData structures for Driver Callback
   1388     //
   1389     LegacyBootOptionData = AllocateZeroPool (sizeof (LEGACY_BOOT_OPTION_CALLBACK_DATA));
   1390     ASSERT (LegacyBootOptionData != NULL);
   1391 
   1392     LegacyBootOptionData->MaintainMapData = AllocateZeroPool (sizeof (LEGACY_BOOT_MAINTAIN_DATA));
   1393     ASSERT (LegacyBootOptionData->MaintainMapData != NULL);
   1394 
   1395     LegacyBootOptionData->ConfigAccess.ExtractConfig = LegacyBootOptionExtractConfig;
   1396     LegacyBootOptionData->ConfigAccess.RouteConfig   = LegacyBootOptionRouteConfig;
   1397     LegacyBootOptionData->ConfigAccess.Callback      = LegacyBootOptionCallback;
   1398 
   1399     //
   1400     // Install Device Path Protocol and Config Access protocol to driver handle
   1401     //
   1402     Status = gBS->InstallMultipleProtocolInterfaces (
   1403                     &LegacyBootOptionData->DriverHandle,
   1404                     &gEfiDevicePathProtocolGuid,
   1405                     &mLegacyBootOptionHiiVendorDevicePath,
   1406                     &gEfiHiiConfigAccessProtocolGuid,
   1407                     &LegacyBootOptionData->ConfigAccess,
   1408                     NULL
   1409                     );
   1410     ASSERT_EFI_ERROR (Status);
   1411 
   1412     //
   1413     // Publish our HII data
   1414     //
   1415     LegacyBootOptionData->HiiHandle = HiiAddPackages (
   1416                                       &mLegacyBootOptionGuid,
   1417                                       LegacyBootOptionData->DriverHandle,
   1418                                       LegacyBootMaintUiVfrBin,
   1419                                       LegacyBootMaintUiLibStrings,
   1420                                       NULL
   1421                                       );
   1422     ASSERT (LegacyBootOptionData->HiiHandle != NULL);
   1423 
   1424     mLegacyBootOptionPrivate = LegacyBootOptionData;
   1425 
   1426     GetLegacyOptions ();
   1427 
   1428     GetLegacyOptionsOrder();
   1429   }
   1430 
   1431   return EFI_SUCCESS;
   1432 }
   1433 
   1434 /**
   1435   Destructor of Customized Display Library Instance.
   1436 
   1437   @param  ImageHandle   The firmware allocated handle for the EFI image.
   1438   @param  SystemTable   A pointer to the EFI System Table.
   1439 
   1440   @retval EFI_SUCCESS   The destructor completed successfully.
   1441   @retval Other value   The destructor did not complete successfully.
   1442 
   1443 **/
   1444 EFI_STATUS
   1445 EFIAPI
   1446 LegacyBootMaintUiLibDestructor (
   1447   IN EFI_HANDLE        ImageHandle,
   1448   IN EFI_SYSTEM_TABLE  *SystemTable
   1449   )
   1450 {
   1451   EFI_STATUS    Status;
   1452 
   1453   if (mLegacyBootOptionPrivate->DriverHandle != NULL) {
   1454     Status = gBS->UninstallMultipleProtocolInterfaces (
   1455                     mLegacyBootOptionPrivate->DriverHandle,
   1456                     &gEfiDevicePathProtocolGuid,
   1457                     &mLegacyBootOptionHiiVendorDevicePath,
   1458                     &gEfiHiiConfigAccessProtocolGuid,
   1459                     &mLegacyBootOptionPrivate->ConfigAccess,
   1460                     NULL
   1461                     );
   1462     ASSERT_EFI_ERROR (Status);
   1463 
   1464     HiiRemovePackages (mLegacyBootOptionPrivate->HiiHandle);
   1465 
   1466     FreePool (mLegacyBootOptionPrivate->MaintainMapData);
   1467     FreePool (mLegacyBootOptionPrivate);
   1468   }
   1469 
   1470   return EFI_SUCCESS;
   1471 }
   1472 
   1473