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