Home | History | Annotate | Download | only in BootMaint
      1 /** @file
      2   Variable operation that will be used by bootmaint
      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 #include "BootMaint.h"
     16 
     17 /**
     18   Delete Boot Option that represent a Deleted state in BootOptionMenu.
     19   After deleting this boot option, call Var_ChangeBootOrder to
     20   make sure BootOrder is in valid state.
     21 
     22   @retval EFI_SUCCESS   If all boot load option EFI Variables corresponding to
     23                         BM_LOAD_CONTEXT marked for deletion is deleted.
     24   @retval EFI_NOT_FOUND If can not find the boot option want to be deleted.
     25   @return Others        If failed to update the "BootOrder" variable after deletion.
     26 
     27 **/
     28 EFI_STATUS
     29 Var_DelBootOption (
     30   VOID
     31   )
     32 {
     33   BM_MENU_ENTRY   *NewMenuEntry;
     34   BM_LOAD_CONTEXT *NewLoadContext;
     35   UINT16          BootString[10];
     36   EFI_STATUS      Status;
     37   UINTN           Index;
     38   UINTN           Index2;
     39 
     40   Status  = EFI_SUCCESS;
     41   Index2  = 0;
     42   for (Index = 0; Index < BootOptionMenu.MenuNumber; Index++) {
     43     NewMenuEntry = BOpt_GetMenuEntry (&BootOptionMenu, (Index - Index2));
     44     if (NULL == NewMenuEntry) {
     45       return EFI_NOT_FOUND;
     46     }
     47 
     48     NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
     49     if (!NewLoadContext->Deleted) {
     50       continue;
     51     }
     52 
     53     UnicodeSPrint (
     54       BootString,
     55       sizeof (BootString),
     56       L"Boot%04x",
     57       NewMenuEntry->OptionNumber
     58       );
     59 
     60     EfiLibDeleteVariable (BootString, &gEfiGlobalVariableGuid);
     61     Index2++;
     62     //
     63     // If current Load Option is the same as BootNext,
     64     // must delete BootNext in order to make sure
     65     // there will be no panic on next boot
     66     //
     67     if (NewLoadContext->IsBootNext) {
     68       EfiLibDeleteVariable (L"BootNext", &gEfiGlobalVariableGuid);
     69     }
     70 
     71     RemoveEntryList (&NewMenuEntry->Link);
     72     BOpt_DestroyMenuEntry (NewMenuEntry);
     73     NewMenuEntry = NULL;
     74   }
     75 
     76   BootOptionMenu.MenuNumber -= Index2;
     77 
     78   Status = Var_ChangeBootOrder ();
     79   return Status;
     80 }
     81 
     82 /**
     83   After any operation on Boot####, there will be a discrepancy in BootOrder.
     84   Since some are missing but in BootOrder, while some are present but are
     85   not reflected by BootOrder. Then a function rebuild BootOrder from
     86   scratch by content from BootOptionMenu is needed.
     87 
     88 
     89 
     90 
     91   @retval  EFI_SUCCESS  The boot order is updated successfully.
     92   @return               EFI_STATUS other than EFI_SUCCESS if failed to
     93                         Set the "BootOrder" EFI Variable.
     94 
     95 **/
     96 EFI_STATUS
     97 Var_ChangeBootOrder (
     98   VOID
     99   )
    100 {
    101 
    102   EFI_STATUS    Status;
    103   BM_MENU_ENTRY *NewMenuEntry;
    104   UINT16        *BootOrderList;
    105   UINT16        *BootOrderListPtr;
    106   UINTN         BootOrderListSize;
    107   UINTN         Index;
    108 
    109   BootOrderList     = NULL;
    110   BootOrderListSize = 0;
    111 
    112   //
    113   // First check whether BootOrder is present in current configuration
    114   //
    115   BootOrderList = BdsLibGetVariableAndSize (
    116                     L"BootOrder",
    117                     &gEfiGlobalVariableGuid,
    118                     &BootOrderListSize
    119                     );
    120 
    121   //
    122   // If exists, delete it to hold new BootOrder
    123   //
    124   if (BootOrderList != NULL) {
    125     EfiLibDeleteVariable (L"BootOrder", &gEfiGlobalVariableGuid);
    126     FreePool (BootOrderList);
    127     BootOrderList = NULL;
    128   }
    129   //
    130   // Maybe here should be some check method to ensure that
    131   // no new added boot options will be added
    132   // but the setup engine now will give only one callback
    133   // that is to say, user are granted only one chance to
    134   // decide whether the boot option will be added or not
    135   // there should be no indictor to show whether this
    136   // is a "new" boot option
    137   //
    138   BootOrderListSize = BootOptionMenu.MenuNumber;
    139 
    140   if (BootOrderListSize > 0) {
    141     BootOrderList = AllocateZeroPool (BootOrderListSize * sizeof (UINT16));
    142     ASSERT (BootOrderList != NULL);
    143     BootOrderListPtr = BootOrderList;
    144 
    145     //
    146     // Get all current used Boot#### from BootOptionMenu.
    147     // OptionNumber in each BM_LOAD_OPTION is really its
    148     // #### value.
    149     //
    150     for (Index = 0; Index < BootOrderListSize; Index++) {
    151       NewMenuEntry    = BOpt_GetMenuEntry (&BootOptionMenu, Index);
    152       *BootOrderList  = (UINT16) NewMenuEntry->OptionNumber;
    153       BootOrderList++;
    154     }
    155 
    156     BootOrderList = BootOrderListPtr;
    157 
    158     //
    159     // After building the BootOrderList, write it back
    160     //
    161     Status = gRT->SetVariable (
    162                     L"BootOrder",
    163                     &gEfiGlobalVariableGuid,
    164                     EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
    165                     BootOrderListSize * sizeof (UINT16),
    166                     BootOrderList
    167                     );
    168     //
    169     // Changing variable without increasing its size with current variable implementation shouldn't fail.
    170     //
    171     ASSERT_EFI_ERROR (Status);
    172   }
    173   return EFI_SUCCESS;
    174 }
    175 
    176 /**
    177   Delete Load Option that represent a Deleted state in BootOptionMenu.
    178   After deleting this Driver option, call Var_ChangeDriverOrder to
    179   make sure DriverOrder is in valid state.
    180 
    181   @retval EFI_SUCCESS       Load Option is successfully updated.
    182   @retval EFI_NOT_FOUND     Fail to find the driver option want to be deleted.
    183   @return Other value than EFI_SUCCESS if failed to update "Driver Order" EFI
    184           Variable.
    185 
    186 **/
    187 EFI_STATUS
    188 Var_DelDriverOption (
    189   VOID
    190   )
    191 {
    192   BM_MENU_ENTRY   *NewMenuEntry;
    193   BM_LOAD_CONTEXT *NewLoadContext;
    194   UINT16          DriverString[12];
    195   EFI_STATUS      Status;
    196   UINTN           Index;
    197   UINTN           Index2;
    198 
    199   Status  = EFI_SUCCESS;
    200   Index2  = 0;
    201   for (Index = 0; Index < DriverOptionMenu.MenuNumber; Index++) {
    202     NewMenuEntry = BOpt_GetMenuEntry (&DriverOptionMenu, (Index - Index2));
    203     if (NULL == NewMenuEntry) {
    204       return EFI_NOT_FOUND;
    205     }
    206 
    207     NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
    208     if (!NewLoadContext->Deleted) {
    209       continue;
    210     }
    211 
    212     UnicodeSPrint (
    213       DriverString,
    214       sizeof (DriverString),
    215       L"Driver%04x",
    216       NewMenuEntry->OptionNumber
    217       );
    218 
    219     EfiLibDeleteVariable (DriverString, &gEfiGlobalVariableGuid);
    220     Index2++;
    221 
    222     RemoveEntryList (&NewMenuEntry->Link);
    223     BOpt_DestroyMenuEntry (NewMenuEntry);
    224     NewMenuEntry = NULL;
    225   }
    226 
    227   DriverOptionMenu.MenuNumber -= Index2;
    228 
    229   Status = Var_ChangeDriverOrder ();
    230   return Status;
    231 }
    232 
    233 /**
    234   After any operation on Driver####, there will be a discrepancy in
    235   DriverOrder. Since some are missing but in DriverOrder, while some
    236   are present but are not reflected by DriverOrder. Then a function
    237   rebuild DriverOrder from scratch by content from DriverOptionMenu is
    238   needed.
    239 
    240   @retval  EFI_SUCCESS  The driver order is updated successfully.
    241   @return  Other status than EFI_SUCCESS if failed to set the "DriverOrder" EFI Variable.
    242 
    243 **/
    244 EFI_STATUS
    245 Var_ChangeDriverOrder (
    246   VOID
    247   )
    248 {
    249   EFI_STATUS    Status;
    250   BM_MENU_ENTRY *NewMenuEntry;
    251   UINT16        *DriverOrderList;
    252   UINT16        *DriverOrderListPtr;
    253   UINTN         DriverOrderListSize;
    254   UINTN         Index;
    255 
    256   DriverOrderList     = NULL;
    257   DriverOrderListSize = 0;
    258 
    259   //
    260   // First check whether DriverOrder is present in current configuration
    261   //
    262   DriverOrderList = BdsLibGetVariableAndSize (
    263                       L"DriverOrder",
    264                       &gEfiGlobalVariableGuid,
    265                       &DriverOrderListSize
    266                       );
    267 
    268   //
    269   // If exists, delete it to hold new DriverOrder
    270   //
    271   if (DriverOrderList != NULL) {
    272     EfiLibDeleteVariable (L"DriverOrder", &gEfiGlobalVariableGuid);
    273     FreePool (DriverOrderList);
    274     DriverOrderList = NULL;
    275   }
    276 
    277   DriverOrderListSize = DriverOptionMenu.MenuNumber;
    278 
    279   if (DriverOrderListSize > 0) {
    280     DriverOrderList = AllocateZeroPool (DriverOrderListSize * sizeof (UINT16));
    281     ASSERT (DriverOrderList != NULL);
    282     DriverOrderListPtr = DriverOrderList;
    283 
    284     //
    285     // Get all current used Driver#### from DriverOptionMenu.
    286     // OptionNumber in each BM_LOAD_OPTION is really its
    287     // #### value.
    288     //
    289     for (Index = 0; Index < DriverOrderListSize; Index++) {
    290       NewMenuEntry      = BOpt_GetMenuEntry (&DriverOptionMenu, Index);
    291       *DriverOrderList  = (UINT16) NewMenuEntry->OptionNumber;
    292       DriverOrderList++;
    293     }
    294 
    295     DriverOrderList = DriverOrderListPtr;
    296 
    297     //
    298     // After building the DriverOrderList, write it back
    299     //
    300     Status = gRT->SetVariable (
    301                     L"DriverOrder",
    302                     &gEfiGlobalVariableGuid,
    303                     EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
    304                     DriverOrderListSize * sizeof (UINT16),
    305                     DriverOrderList
    306                     );
    307     //
    308     // Changing variable without increasing its size with current variable implementation shouldn't fail.
    309     //
    310     ASSERT_EFI_ERROR (Status);
    311   }
    312   return EFI_SUCCESS;
    313 }
    314 
    315 /**
    316   Update the device path of "ConOut", "ConIn" and "ErrOut"
    317   based on the new BaudRate, Data Bits, parity and Stop Bits
    318   set.
    319 
    320 **/
    321 VOID
    322 Var_UpdateAllConsoleOption (
    323   VOID
    324   )
    325 {
    326   EFI_DEVICE_PATH_PROTOCOL  *OutDevicePath;
    327   EFI_DEVICE_PATH_PROTOCOL  *InpDevicePath;
    328   EFI_DEVICE_PATH_PROTOCOL  *ErrDevicePath;
    329   EFI_STATUS                Status;
    330 
    331   OutDevicePath = EfiLibGetVariable (L"ConOut", &gEfiGlobalVariableGuid);
    332   InpDevicePath = EfiLibGetVariable (L"ConIn", &gEfiGlobalVariableGuid);
    333   ErrDevicePath = EfiLibGetVariable (L"ErrOut", &gEfiGlobalVariableGuid);
    334   if (OutDevicePath != NULL) {
    335     ChangeVariableDevicePath (OutDevicePath);
    336     Status = gRT->SetVariable (
    337                     L"ConOut",
    338                     &gEfiGlobalVariableGuid,
    339                     EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
    340                     GetDevicePathSize (OutDevicePath),
    341                     OutDevicePath
    342                     );
    343     //
    344     // Changing variable without increasing its size with current variable implementation shouldn't fail.
    345     //
    346     ASSERT_EFI_ERROR (Status);
    347   }
    348 
    349   if (InpDevicePath != NULL) {
    350     ChangeVariableDevicePath (InpDevicePath);
    351     Status = gRT->SetVariable (
    352                     L"ConIn",
    353                     &gEfiGlobalVariableGuid,
    354                     EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
    355                     GetDevicePathSize (InpDevicePath),
    356                     InpDevicePath
    357                     );
    358     //
    359     // Changing variable without increasing its size with current variable implementation shouldn't fail.
    360     //
    361     ASSERT_EFI_ERROR (Status);
    362   }
    363 
    364   if (ErrDevicePath != NULL) {
    365     ChangeVariableDevicePath (ErrDevicePath);
    366     Status = gRT->SetVariable (
    367                     L"ErrOut",
    368                     &gEfiGlobalVariableGuid,
    369                     EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
    370                     GetDevicePathSize (ErrDevicePath),
    371                     ErrDevicePath
    372                     );
    373     //
    374     // Changing variable without increasing its size with current variable implementation shouldn't fail.
    375     //
    376     ASSERT_EFI_ERROR (Status);
    377   }
    378 }
    379 
    380 /**
    381   This function delete and build multi-instance device path for
    382   specified type of console device.
    383 
    384   This function clear the EFI variable defined by ConsoleName and
    385   gEfiGlobalVariableGuid. It then build the multi-instance device
    386   path by appending the device path of the Console (In/Out/Err) instance
    387   in ConsoleMenu. Then it scan all corresponding console device by
    388   scanning Terminal (built from device supporting Serial I/O instances)
    389   devices in TerminalMenu. At last, it save a EFI variable specifed
    390   by ConsoleName and gEfiGlobalVariableGuid.
    391 
    392   @param ConsoleName     The name for the console device type. They are
    393                          usually "ConIn", "ConOut" and "ErrOut".
    394   @param ConsoleMenu     The console memu which is a list of console devices.
    395   @param UpdatePageId    The flag specifying which type of console device
    396                          to be processed.
    397 
    398   @retval EFI_SUCCESS    The function complete successfully.
    399   @return The EFI variable can not be saved. See gRT->SetVariable for detail return information.
    400 
    401 **/
    402 EFI_STATUS
    403 Var_UpdateConsoleOption (
    404   IN UINT16                     *ConsoleName,
    405   IN BM_MENU_OPTION             *ConsoleMenu,
    406   IN UINT16                     UpdatePageId
    407   )
    408 {
    409   EFI_DEVICE_PATH_PROTOCOL  *ConDevicePath;
    410   BM_MENU_ENTRY             *NewMenuEntry;
    411   BM_CONSOLE_CONTEXT        *NewConsoleContext;
    412   BM_TERMINAL_CONTEXT       *NewTerminalContext;
    413   EFI_STATUS                Status;
    414   VENDOR_DEVICE_PATH        Vendor;
    415   EFI_DEVICE_PATH_PROTOCOL  *TerminalDevicePath;
    416   UINTN                     Index;
    417 
    418   ConDevicePath = EfiLibGetVariable (ConsoleName, &gEfiGlobalVariableGuid);
    419   if (ConDevicePath != NULL) {
    420     EfiLibDeleteVariable (ConsoleName, &gEfiGlobalVariableGuid);
    421     FreePool (ConDevicePath);
    422     ConDevicePath = NULL;
    423   };
    424 
    425   //
    426   // First add all console input device from console input menu
    427   //
    428   for (Index = 0; Index < ConsoleMenu->MenuNumber; Index++) {
    429     NewMenuEntry = BOpt_GetMenuEntry (ConsoleMenu, Index);
    430 
    431     NewConsoleContext = (BM_CONSOLE_CONTEXT *) NewMenuEntry->VariableContext;
    432     if (NewConsoleContext->IsActive) {
    433       ConDevicePath = AppendDevicePathInstance (
    434                         ConDevicePath,
    435                         NewConsoleContext->DevicePath
    436                         );
    437     }
    438   }
    439 
    440   for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) {
    441     NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Index);
    442 
    443     NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
    444     if (((NewTerminalContext->IsConIn != 0) && (UpdatePageId == FORM_CON_IN_ID)) ||
    445         ((NewTerminalContext->IsConOut != 0)  && (UpdatePageId == FORM_CON_OUT_ID)) ||
    446         ((NewTerminalContext->IsStdErr  != 0) && (UpdatePageId == FORM_CON_ERR_ID))
    447         ) {
    448       Vendor.Header.Type    = MESSAGING_DEVICE_PATH;
    449       Vendor.Header.SubType = MSG_VENDOR_DP;
    450 
    451       ASSERT (NewTerminalContext->TerminalType < (ARRAY_SIZE (TerminalTypeGuid)));
    452       CopyMem (
    453         &Vendor.Guid,
    454         &TerminalTypeGuid[NewTerminalContext->TerminalType],
    455         sizeof (EFI_GUID)
    456         );
    457       SetDevicePathNodeLength (&Vendor.Header, sizeof (VENDOR_DEVICE_PATH));
    458       TerminalDevicePath = AppendDevicePathNode (
    459                             NewTerminalContext->DevicePath,
    460                             (EFI_DEVICE_PATH_PROTOCOL *) &Vendor
    461                             );
    462       ASSERT (TerminalDevicePath != NULL);
    463       ChangeTerminalDevicePath (&TerminalDevicePath, TRUE);
    464       ConDevicePath = AppendDevicePathInstance (
    465                         ConDevicePath,
    466                         TerminalDevicePath
    467                         );
    468     }
    469   }
    470 
    471   if (ConDevicePath != NULL) {
    472     Status = gRT->SetVariable (
    473                     ConsoleName,
    474                     &gEfiGlobalVariableGuid,
    475                     EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
    476                     GetDevicePathSize (ConDevicePath),
    477                     ConDevicePath
    478                     );
    479     if (EFI_ERROR (Status)) {
    480       return Status;
    481     }
    482   }
    483 
    484   return EFI_SUCCESS;
    485 
    486 }
    487 
    488 /**
    489   This function delete and build multi-instance device path ConIn
    490   console device.
    491 
    492   @retval EFI_SUCCESS    The function complete successfully.
    493   @return The EFI variable can not be saved. See gRT->SetVariable for detail return information.
    494 **/
    495 EFI_STATUS
    496 Var_UpdateConsoleInpOption (
    497   VOID
    498   )
    499 {
    500   return Var_UpdateConsoleOption (L"ConIn", &ConsoleInpMenu, FORM_CON_IN_ID);
    501 }
    502 
    503 /**
    504   This function delete and build multi-instance device path ConOut
    505   console device.
    506 
    507   @retval EFI_SUCCESS    The function complete successfully.
    508   @return The EFI variable can not be saved. See gRT->SetVariable for detail return information.
    509 **/
    510 EFI_STATUS
    511 Var_UpdateConsoleOutOption (
    512   VOID
    513   )
    514 {
    515   return Var_UpdateConsoleOption (L"ConOut", &ConsoleOutMenu, FORM_CON_OUT_ID);
    516 }
    517 
    518 /**
    519   This function delete and build multi-instance device path ErrOut
    520   console device.
    521 
    522   @retval EFI_SUCCESS    The function complete successfully.
    523   @return The EFI variable can not be saved. See gRT->SetVariable for detail return information.
    524 **/
    525 EFI_STATUS
    526 Var_UpdateErrorOutOption (
    527   VOID
    528   )
    529 {
    530   return Var_UpdateConsoleOption (L"ErrOut", &ConsoleErrMenu, FORM_CON_ERR_ID);
    531 }
    532 
    533 /**
    534   This function create a currently loaded Drive Option from
    535   the BMM. It then appends this Driver Option to the end of
    536   the "DriverOrder" list. It append this Driver Opotion to the end
    537   of DriverOptionMenu.
    538 
    539   @param CallbackData    The BMM context data.
    540   @param HiiHandle       The HII handle associated with the BMM formset.
    541   @param DescriptionData The description of this driver option.
    542   @param OptionalData    The optional load option.
    543   @param ForceReconnect  If to force reconnect.
    544 
    545   @retval EFI_OUT_OF_RESOURCES If not enought memory to complete the operation.
    546   @retval EFI_SUCCESS          If function completes successfully.
    547 
    548 **/
    549 EFI_STATUS
    550 Var_UpdateDriverOption (
    551   IN  BMM_CALLBACK_DATA         *CallbackData,
    552   IN  EFI_HII_HANDLE            HiiHandle,
    553   IN  UINT16                    *DescriptionData,
    554   IN  UINT16                    *OptionalData,
    555   IN  UINT8                     ForceReconnect
    556   )
    557 {
    558   UINT16          Index;
    559   UINT16          *DriverOrderList;
    560   UINT16          *NewDriverOrderList;
    561   UINT16          DriverString[12];
    562   UINTN           DriverOrderListSize;
    563   VOID            *Buffer;
    564   UINTN           BufferSize;
    565   UINT8           *Ptr;
    566   BM_MENU_ENTRY   *NewMenuEntry;
    567   BM_LOAD_CONTEXT *NewLoadContext;
    568   BOOLEAN         OptionalDataExist;
    569   EFI_STATUS      Status;
    570 
    571   OptionalDataExist = FALSE;
    572 
    573   Index             = BOpt_GetDriverOptionNumber ();
    574   UnicodeSPrint (
    575     DriverString,
    576     sizeof (DriverString),
    577     L"Driver%04x",
    578     Index
    579     );
    580 
    581   if (*DescriptionData == 0x0000) {
    582     StrCpyS (DescriptionData, DESCRIPTION_DATA_SIZE, DriverString);
    583   }
    584 
    585   BufferSize = sizeof (UINT32) + sizeof (UINT16) + StrSize (DescriptionData);
    586   BufferSize += GetDevicePathSize (CallbackData->LoadContext->FilePathList);
    587 
    588   if (*OptionalData != 0x0000) {
    589     OptionalDataExist = TRUE;
    590     BufferSize += StrSize (OptionalData);
    591   }
    592 
    593   Buffer = AllocateZeroPool (BufferSize);
    594   if (NULL == Buffer) {
    595     return EFI_OUT_OF_RESOURCES;
    596   }
    597 
    598   NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);
    599   if (NULL == NewMenuEntry) {
    600     FreePool (Buffer);
    601     return EFI_OUT_OF_RESOURCES;
    602   }
    603 
    604   NewLoadContext                  = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
    605   NewLoadContext->Deleted         = FALSE;
    606   NewLoadContext->LoadOptionSize  = BufferSize;
    607   Ptr = (UINT8 *) Buffer;
    608   NewLoadContext->LoadOption = Ptr;
    609   *((UINT32 *) Ptr) = LOAD_OPTION_ACTIVE | (ForceReconnect << 1);
    610   NewLoadContext->Attributes = *((UINT32 *) Ptr);
    611   NewLoadContext->IsActive = TRUE;
    612   NewLoadContext->ForceReconnect = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_FORCE_RECONNECT);
    613 
    614   Ptr += sizeof (UINT32);
    615   *((UINT16 *) Ptr) = (UINT16) GetDevicePathSize (CallbackData->LoadContext->FilePathList);
    616   NewLoadContext->FilePathListLength = *((UINT16 *) Ptr);
    617 
    618   Ptr += sizeof (UINT16);
    619   CopyMem (
    620     Ptr,
    621     DescriptionData,
    622     StrSize (DescriptionData)
    623     );
    624 
    625   NewLoadContext->Description = AllocateZeroPool (StrSize (DescriptionData));
    626   ASSERT (NewLoadContext->Description != NULL);
    627   NewMenuEntry->DisplayString = NewLoadContext->Description;
    628   CopyMem (
    629     NewLoadContext->Description,
    630     (VOID *) Ptr,
    631     StrSize (DescriptionData)
    632     );
    633 
    634   Ptr += StrSize (DescriptionData);
    635   CopyMem (
    636     Ptr,
    637     CallbackData->LoadContext->FilePathList,
    638     GetDevicePathSize (CallbackData->LoadContext->FilePathList)
    639     );
    640 
    641   NewLoadContext->FilePathList = AllocateZeroPool (GetDevicePathSize (CallbackData->LoadContext->FilePathList));
    642   ASSERT (NewLoadContext->FilePathList != NULL);
    643 
    644   CopyMem (
    645     NewLoadContext->FilePathList,
    646     (VOID *) Ptr,
    647     GetDevicePathSize (CallbackData->LoadContext->FilePathList)
    648     );
    649 
    650   NewMenuEntry->HelpString    = DevicePathToStr (NewLoadContext->FilePathList);
    651   NewMenuEntry->OptionNumber  = Index;
    652   NewMenuEntry->DisplayStringToken = GetStringTokenFromDepository (
    653                                       CallbackData,
    654                                       DriverOptionStrDepository
    655                                       );
    656   NewMenuEntry->DisplayStringToken = HiiSetString (HiiHandle, 0, NewMenuEntry->DisplayString, NULL);
    657 
    658   NewMenuEntry->HelpStringToken = GetStringTokenFromDepository (
    659                                     CallbackData,
    660                                     DriverOptionHelpStrDepository
    661                                     );
    662   NewMenuEntry->HelpStringToken = HiiSetString (HiiHandle, 0, NewMenuEntry->HelpString, NULL);
    663 
    664   if (OptionalDataExist) {
    665     Ptr += (UINT8) GetDevicePathSize (CallbackData->LoadContext->FilePathList);
    666 
    667     CopyMem (
    668       Ptr,
    669       OptionalData,
    670       StrSize (OptionalData)
    671       );
    672   }
    673 
    674   Status = gRT->SetVariable (
    675                   DriverString,
    676                   &gEfiGlobalVariableGuid,
    677                   EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
    678                   BufferSize,
    679                   Buffer
    680                   );
    681   if (!EFI_ERROR (Status)) {
    682     DriverOrderList = BdsLibGetVariableAndSize (
    683                         L"DriverOrder",
    684                         &gEfiGlobalVariableGuid,
    685                         &DriverOrderListSize
    686                         );
    687     NewDriverOrderList = AllocateZeroPool (DriverOrderListSize + sizeof (UINT16));
    688     ASSERT (NewDriverOrderList != NULL);
    689     if (DriverOrderList != NULL) {
    690       CopyMem (NewDriverOrderList, DriverOrderList, DriverOrderListSize);
    691       EfiLibDeleteVariable (L"DriverOrder", &gEfiGlobalVariableGuid);
    692     }
    693     NewDriverOrderList[DriverOrderListSize / sizeof (UINT16)] = Index;
    694 
    695     Status = gRT->SetVariable (
    696                     L"DriverOrder",
    697                     &gEfiGlobalVariableGuid,
    698                     EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
    699                     DriverOrderListSize + sizeof (UINT16),
    700                     NewDriverOrderList
    701                     );
    702     if (DriverOrderList != NULL) {
    703       FreePool (DriverOrderList);
    704     }
    705     DriverOrderList = NULL;
    706     FreePool (NewDriverOrderList);
    707     if (!EFI_ERROR (Status)) {
    708       InsertTailList (&DriverOptionMenu.Head, &NewMenuEntry->Link);
    709       DriverOptionMenu.MenuNumber++;
    710 
    711       //
    712       // Update "change boot order" page used data, append the new add boot
    713       // option at the end.
    714       //
    715       Index = 0;
    716       while (CallbackData->BmmFakeNvData.DriverOptionOrder[Index] != 0) {
    717         Index++;
    718       }
    719       CallbackData->BmmFakeNvData.DriverOptionOrder[Index] = (UINT32) (NewMenuEntry->OptionNumber + 1);
    720 
    721       *DescriptionData  = 0x0000;
    722       *OptionalData     = 0x0000;
    723     }
    724   }
    725   return EFI_SUCCESS;
    726 }
    727 
    728 /**
    729   This function create a currently loaded Boot Option from
    730   the BMM. It then appends this Boot Option to the end of
    731   the "BootOrder" list. It also append this Boot Opotion to the end
    732   of BootOptionMenu.
    733 
    734   @param CallbackData    The BMM context data.
    735   @param NvRamMap        The file explorer formset internal state.
    736 
    737   @retval EFI_OUT_OF_RESOURCES If not enought memory to complete the operation.
    738   @retval EFI_SUCCESS          If function completes successfully.
    739 
    740 **/
    741 EFI_STATUS
    742 Var_UpdateBootOption (
    743   IN  BMM_CALLBACK_DATA                   *CallbackData,
    744   IN  FILE_EXPLORER_NV_DATA               *NvRamMap
    745   )
    746 {
    747   UINT16          *BootOrderList;
    748   UINT16          *NewBootOrderList;
    749   UINTN           BootOrderListSize;
    750   UINT16          BootString[10];
    751   VOID            *Buffer;
    752   UINTN           BufferSize;
    753   UINT8           *Ptr;
    754   UINT16          Index;
    755   BM_MENU_ENTRY   *NewMenuEntry;
    756   BM_LOAD_CONTEXT *NewLoadContext;
    757   BOOLEAN         OptionalDataExist;
    758   EFI_STATUS      Status;
    759 
    760   OptionalDataExist = FALSE;
    761 
    762   Index = BOpt_GetBootOptionNumber () ;
    763   UnicodeSPrint (BootString, sizeof (BootString), L"Boot%04x", Index);
    764 
    765   if (NvRamMap->BootDescriptionData[0] == 0x0000) {
    766     StrCpyS (
    767       NvRamMap->BootDescriptionData,
    768       sizeof (NvRamMap->BootDescriptionData) / sizeof (NvRamMap->BootDescriptionData[0]),
    769       BootString
    770       );
    771   }
    772 
    773   BufferSize = sizeof (UINT32) + sizeof (UINT16) + StrSize (NvRamMap->BootDescriptionData);
    774   BufferSize += GetDevicePathSize (CallbackData->LoadContext->FilePathList);
    775 
    776   if (NvRamMap->BootOptionalData[0] != 0x0000) {
    777     OptionalDataExist = TRUE;
    778     BufferSize += StrSize (NvRamMap->BootOptionalData);
    779   }
    780 
    781   Buffer = AllocateZeroPool (BufferSize);
    782   if (NULL == Buffer) {
    783     return EFI_OUT_OF_RESOURCES;
    784   }
    785 
    786   NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);
    787   if (NULL == NewMenuEntry) {
    788     return EFI_OUT_OF_RESOURCES;
    789   }
    790 
    791   NewLoadContext                  = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
    792   NewLoadContext->Deleted         = FALSE;
    793   NewLoadContext->LoadOptionSize  = BufferSize;
    794   Ptr = (UINT8 *) Buffer;
    795   NewLoadContext->LoadOption = Ptr;
    796   *((UINT32 *) Ptr) = LOAD_OPTION_ACTIVE;
    797   NewLoadContext->Attributes = *((UINT32 *) Ptr);
    798   NewLoadContext->IsActive = TRUE;
    799   NewLoadContext->ForceReconnect = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_FORCE_RECONNECT);
    800 
    801   Ptr += sizeof (UINT32);
    802   *((UINT16 *) Ptr) = (UINT16) GetDevicePathSize (CallbackData->LoadContext->FilePathList);
    803   NewLoadContext->FilePathListLength = *((UINT16 *) Ptr);
    804   Ptr += sizeof (UINT16);
    805 
    806   CopyMem (
    807     Ptr,
    808     NvRamMap->BootDescriptionData,
    809     StrSize (NvRamMap->BootDescriptionData)
    810     );
    811 
    812   NewLoadContext->Description = AllocateZeroPool (StrSize (NvRamMap->BootDescriptionData));
    813   ASSERT (NewLoadContext->Description != NULL);
    814 
    815   NewMenuEntry->DisplayString = NewLoadContext->Description;
    816   CopyMem (
    817     NewLoadContext->Description,
    818     (VOID *) Ptr,
    819     StrSize (NvRamMap->BootDescriptionData)
    820     );
    821 
    822   Ptr += StrSize (NvRamMap->BootDescriptionData);
    823   CopyMem (
    824     Ptr,
    825     CallbackData->LoadContext->FilePathList,
    826     GetDevicePathSize (CallbackData->LoadContext->FilePathList)
    827     );
    828 
    829   NewLoadContext->FilePathList = AllocateZeroPool (GetDevicePathSize (CallbackData->LoadContext->FilePathList));
    830   ASSERT (NewLoadContext->FilePathList != NULL);
    831 
    832   CopyMem (
    833     NewLoadContext->FilePathList,
    834     (VOID *) Ptr,
    835     GetDevicePathSize (CallbackData->LoadContext->FilePathList)
    836     );
    837 
    838   NewMenuEntry->HelpString    = DevicePathToStr (NewLoadContext->FilePathList);
    839   NewMenuEntry->OptionNumber  = Index;
    840   NewMenuEntry->DisplayStringToken = GetStringTokenFromDepository (
    841                                       CallbackData,
    842                                       BootOptionStrDepository
    843                                       );
    844   NewMenuEntry->DisplayStringToken = HiiSetString (CallbackData->FeHiiHandle, 0, NewMenuEntry->DisplayString, NULL);
    845 
    846   NewMenuEntry->HelpStringToken = GetStringTokenFromDepository (
    847                                     CallbackData,
    848                                     BootOptionHelpStrDepository
    849                                     );
    850   NewMenuEntry->HelpStringToken = HiiSetString (CallbackData->FeHiiHandle, 0, NewMenuEntry->HelpString, NULL);
    851 
    852   if (OptionalDataExist) {
    853     Ptr += (UINT8) GetDevicePathSize (CallbackData->LoadContext->FilePathList);
    854 
    855     CopyMem (Ptr, NvRamMap->BootOptionalData, StrSize (NvRamMap->BootOptionalData));
    856   }
    857 
    858   Status = gRT->SetVariable (
    859                   BootString,
    860                   &gEfiGlobalVariableGuid,
    861                   EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
    862                   BufferSize,
    863                   Buffer
    864                   );
    865   if (!EFI_ERROR (Status)) {
    866 
    867     BootOrderList = BdsLibGetVariableAndSize (
    868                       L"BootOrder",
    869                       &gEfiGlobalVariableGuid,
    870                       &BootOrderListSize
    871                       );
    872     ASSERT (BootOrderList != NULL);
    873     NewBootOrderList = AllocateZeroPool (BootOrderListSize + sizeof (UINT16));
    874     ASSERT (NewBootOrderList != NULL);
    875     CopyMem (NewBootOrderList, BootOrderList, BootOrderListSize);
    876     NewBootOrderList[BootOrderListSize / sizeof (UINT16)] = Index;
    877 
    878     if (BootOrderList != NULL) {
    879       FreePool (BootOrderList);
    880     }
    881 
    882     Status = gRT->SetVariable (
    883                     L"BootOrder",
    884                     &gEfiGlobalVariableGuid,
    885                     EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
    886                     BootOrderListSize + sizeof (UINT16),
    887                     NewBootOrderList
    888                     );
    889     if (!EFI_ERROR (Status)) {
    890 
    891       FreePool (NewBootOrderList);
    892       NewBootOrderList = NULL;
    893       InsertTailList (&BootOptionMenu.Head, &NewMenuEntry->Link);
    894       BootOptionMenu.MenuNumber++;
    895 
    896       //
    897       // Update "change driver order" page used data, append the new add driver
    898       // option at the end.
    899       //
    900       Index = 0;
    901       while (CallbackData->BmmFakeNvData.BootOptionOrder[Index] != 0) {
    902         Index++;
    903       }
    904       CallbackData->BmmFakeNvData.BootOptionOrder[Index] = (UINT32) (NewMenuEntry->OptionNumber + 1);
    905 
    906       NvRamMap->BootDescriptionData[0]  = 0x0000;
    907       NvRamMap->BootOptionalData[0]     = 0x0000;
    908     }
    909   }
    910   return EFI_SUCCESS;
    911 }
    912 
    913 /**
    914   This function update the "BootNext" EFI Variable. If there is
    915   no "BootNext" specified in BMM, this EFI Variable is deleted.
    916   It also update the BMM context data specified the "BootNext"
    917   vaule.
    918 
    919   @param CallbackData    The BMM context data.
    920 
    921   @retval EFI_SUCCESS    The function complete successfully.
    922   @return                The EFI variable can be saved. See gRT->SetVariable
    923                          for detail return information.
    924 
    925 **/
    926 EFI_STATUS
    927 Var_UpdateBootNext (
    928   IN BMM_CALLBACK_DATA            *CallbackData
    929   )
    930 {
    931   BM_MENU_ENTRY     *NewMenuEntry;
    932   BM_LOAD_CONTEXT   *NewLoadContext;
    933   BMM_FAKE_NV_DATA  *CurrentFakeNVMap;
    934   UINT16            Index;
    935   EFI_STATUS        Status;
    936 
    937   Status            = EFI_SUCCESS;
    938   CurrentFakeNVMap  = &CallbackData->BmmFakeNvData;
    939   for (Index = 0; Index < BootOptionMenu.MenuNumber; Index++) {
    940     NewMenuEntry = BOpt_GetMenuEntry (&BootOptionMenu, Index);
    941     ASSERT (NULL != NewMenuEntry);
    942 
    943     NewLoadContext              = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
    944     NewLoadContext->IsBootNext  = FALSE;
    945   }
    946 
    947   if (CurrentFakeNVMap->BootNext == BootOptionMenu.MenuNumber) {
    948     EfiLibDeleteVariable (L"BootNext", &gEfiGlobalVariableGuid);
    949     return EFI_SUCCESS;
    950   }
    951 
    952   NewMenuEntry = BOpt_GetMenuEntry (
    953                   &BootOptionMenu,
    954                   CurrentFakeNVMap->BootNext
    955                   );
    956   ASSERT (NewMenuEntry != NULL);
    957 
    958   NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
    959   Status = gRT->SetVariable (
    960                   L"BootNext",
    961                   &gEfiGlobalVariableGuid,
    962                   EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
    963                   sizeof (UINT16),
    964                   &NewMenuEntry->OptionNumber
    965                   );
    966   NewLoadContext->IsBootNext              = TRUE;
    967   CallbackData->BmmOldFakeNVData.BootNext = CurrentFakeNVMap->BootNext;
    968   return Status;
    969 }
    970 
    971 /**
    972   This function update the "BootOrder" EFI Variable based on
    973   BMM Formset's NV map. It then refresh BootOptionMenu
    974   with the new "BootOrder" list.
    975 
    976   @param CallbackData    The BMM context data.
    977 
    978   @retval EFI_SUCCESS             The function complete successfully.
    979   @retval EFI_OUT_OF_RESOURCES    Not enough memory to complete the function.
    980   @return The EFI variable can not be saved. See gRT->SetVariable for detail return information.
    981 
    982 **/
    983 EFI_STATUS
    984 Var_UpdateBootOrder (
    985   IN BMM_CALLBACK_DATA            *CallbackData
    986   )
    987 {
    988   EFI_STATUS  Status;
    989   UINT16      Index;
    990   UINT16      OrderIndex;
    991   UINT16      *BootOrderList;
    992   UINTN       BootOrderListSize;
    993   UINT16      OptionNumber;
    994 
    995   BootOrderList     = NULL;
    996   BootOrderListSize = 0;
    997 
    998   //
    999   // First check whether BootOrder is present in current configuration
   1000   //
   1001   BootOrderList = BdsLibGetVariableAndSize (
   1002                     L"BootOrder",
   1003                     &gEfiGlobalVariableGuid,
   1004                     &BootOrderListSize
   1005                     );
   1006   if (BootOrderList == NULL) {
   1007     return EFI_OUT_OF_RESOURCES;
   1008   }
   1009 
   1010   ASSERT (BootOptionMenu.MenuNumber <= (sizeof (CallbackData->BmmFakeNvData.BootOptionOrder) / sizeof (CallbackData->BmmFakeNvData.BootOptionOrder[0])));
   1011 
   1012   for (OrderIndex = 0; (OrderIndex < BootOptionMenu.MenuNumber) && (CallbackData->BmmFakeNvData.BootOptionOrder[OrderIndex] != 0); OrderIndex++) {
   1013     for (Index = OrderIndex; Index < BootOrderListSize / sizeof (UINT16); Index++) {
   1014       if ((BootOrderList[Index] == (UINT16) (CallbackData->BmmFakeNvData.BootOptionOrder[OrderIndex] - 1)) && (OrderIndex != Index)) {
   1015         OptionNumber = BootOrderList[Index];
   1016         CopyMem (&BootOrderList[OrderIndex + 1], &BootOrderList[OrderIndex], (Index - OrderIndex) * sizeof (UINT16));
   1017         BootOrderList[OrderIndex] = OptionNumber;
   1018       }
   1019     }
   1020   }
   1021 
   1022   Status = gRT->SetVariable (
   1023                   L"BootOrder",
   1024                   &gEfiGlobalVariableGuid,
   1025                   EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
   1026                   BootOrderListSize,
   1027                   BootOrderList
   1028                   );
   1029   //
   1030   // Changing the content without increasing its size with current variable implementation shouldn't fail.
   1031   //
   1032   ASSERT_EFI_ERROR (Status);
   1033   FreePool (BootOrderList);
   1034 
   1035   GroupMultipleLegacyBootOption4SameType ();
   1036 
   1037   BOpt_FreeMenu (&BootOptionMenu);
   1038   BOpt_GetBootOptions (CallbackData);
   1039 
   1040   return Status;
   1041 
   1042 }
   1043 
   1044 /**
   1045   This function update the "DriverOrder" EFI Variable based on
   1046   BMM Formset's NV map. It then refresh DriverOptionMenu
   1047   with the new "DriverOrder" list.
   1048 
   1049   @param CallbackData    The BMM context data.
   1050 
   1051   @retval EFI_SUCCESS           The function complete successfully.
   1052   @retval EFI_OUT_OF_RESOURCES  Not enough memory to complete the function.
   1053   @return The EFI variable can not be saved. See gRT->SetVariable for detail return information.
   1054 
   1055 **/
   1056 EFI_STATUS
   1057 Var_UpdateDriverOrder (
   1058   IN BMM_CALLBACK_DATA            *CallbackData
   1059   )
   1060 {
   1061   EFI_STATUS  Status;
   1062   UINT16      Index;
   1063   UINT16      *DriverOrderList;
   1064   UINT16      *NewDriverOrderList;
   1065   UINTN       DriverOrderListSize;
   1066 
   1067   DriverOrderList     = NULL;
   1068   DriverOrderListSize = 0;
   1069 
   1070   //
   1071   // First check whether DriverOrder is present in current configuration
   1072   //
   1073   DriverOrderList = BdsLibGetVariableAndSize (
   1074                       L"DriverOrder",
   1075                       &gEfiGlobalVariableGuid,
   1076                       &DriverOrderListSize
   1077                       );
   1078 
   1079   NewDriverOrderList = AllocateZeroPool (DriverOrderListSize);
   1080 
   1081   if (NewDriverOrderList == NULL) {
   1082     return EFI_OUT_OF_RESOURCES;
   1083   }
   1084   //
   1085   // If exists, delete it to hold new DriverOrder
   1086   //
   1087   if (DriverOrderList != NULL) {
   1088     EfiLibDeleteVariable (L"DriverOrder", &gEfiGlobalVariableGuid);
   1089     FreePool (DriverOrderList);
   1090   }
   1091 
   1092   ASSERT (DriverOptionMenu.MenuNumber <= (sizeof (CallbackData->BmmFakeNvData.DriverOptionOrder) / sizeof (CallbackData->BmmFakeNvData.DriverOptionOrder[0])));
   1093   for (Index = 0; Index < DriverOptionMenu.MenuNumber; Index++) {
   1094     NewDriverOrderList[Index] = (UINT16) (CallbackData->BmmFakeNvData.DriverOptionOrder[Index] - 1);
   1095   }
   1096 
   1097   Status = gRT->SetVariable (
   1098                   L"DriverOrder",
   1099                   &gEfiGlobalVariableGuid,
   1100                   EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
   1101                   DriverOrderListSize,
   1102                   NewDriverOrderList
   1103                   );
   1104   //
   1105   // Changing the content without increasing its size with current variable implementation shouldn't fail.
   1106   //
   1107   ASSERT_EFI_ERROR (Status);
   1108 
   1109   BOpt_FreeMenu (&DriverOptionMenu);
   1110   BOpt_GetDriverOptions (CallbackData);
   1111   return EFI_SUCCESS;
   1112 }
   1113 
   1114 /**
   1115   Update the legacy BBS boot option. VAR_LEGACY_DEV_ORDER and gEfiLegacyDevOrderVariableGuid EFI Variable
   1116   is udpated with the new Legacy Boot order. The EFI Variable of "Boot####" and gEfiGlobalVariableGuid
   1117   is also updated.
   1118 
   1119   @param CallbackData    The context data for BMM.
   1120   @param FormId          The form id.
   1121 
   1122   @return EFI_SUCCESS           The function completed successfully.
   1123   @retval EFI_NOT_FOUND         If VAR_LEGACY_DEV_ORDER and gEfiLegacyDevOrderVariableGuid EFI Variable can be found.
   1124   @retval EFI_OUT_OF_RESOURCES  Fail to allocate memory resource
   1125 **/
   1126 EFI_STATUS
   1127 Var_UpdateBBSOption (
   1128   IN BMM_CALLBACK_DATA            *CallbackData,
   1129   IN EFI_FORM_ID                  FormId
   1130   )
   1131 {
   1132   UINTN                       Index;
   1133   UINTN                       Index2;
   1134   VOID                        *BootOptionVar;
   1135   CHAR16                      VarName[100];
   1136   UINTN                       OptionSize;
   1137   EFI_STATUS                  Status;
   1138   UINT32                      *Attribute;
   1139   BM_MENU_OPTION              *OptionMenu;
   1140   UINT8                       *LegacyDev;
   1141   UINT8                       *VarData;
   1142   UINTN                       VarSize;
   1143   LEGACY_DEV_ORDER_ENTRY      *DevOrder;
   1144   UINT8                       *OriginalPtr;
   1145   UINT8                       *DisMap;
   1146   UINTN                       Pos;
   1147   UINTN                       Bit;
   1148   UINT16                      *NewOrder;
   1149   UINT16                      Tmp;
   1150   UINT16                      *EnBootOption;
   1151   UINTN                       EnBootOptionCount;
   1152   UINT16                      *DisBootOption;
   1153   UINTN                       DisBootOptionCount;
   1154 
   1155   DisMap              = NULL;
   1156   NewOrder            = NULL;
   1157 
   1158   switch (FormId) {
   1159     case FORM_SET_FD_ORDER_ID:
   1160       OptionMenu            = (BM_MENU_OPTION *) &LegacyFDMenu;
   1161       LegacyDev             = CallbackData->BmmFakeNvData.LegacyFD;
   1162       CallbackData->BbsType = BBS_FLOPPY;
   1163       break;
   1164 
   1165     case FORM_SET_HD_ORDER_ID:
   1166       OptionMenu            = (BM_MENU_OPTION *) &LegacyHDMenu;
   1167       LegacyDev             = CallbackData->BmmFakeNvData.LegacyHD;
   1168       CallbackData->BbsType = BBS_HARDDISK;
   1169       break;
   1170 
   1171     case FORM_SET_CD_ORDER_ID:
   1172       OptionMenu            = (BM_MENU_OPTION *) &LegacyCDMenu;
   1173       LegacyDev             = CallbackData->BmmFakeNvData.LegacyCD;
   1174       CallbackData->BbsType = BBS_CDROM;
   1175       break;
   1176 
   1177     case FORM_SET_NET_ORDER_ID:
   1178       OptionMenu            = (BM_MENU_OPTION *) &LegacyNETMenu;
   1179       LegacyDev             = CallbackData->BmmFakeNvData.LegacyNET;
   1180       CallbackData->BbsType = BBS_EMBED_NETWORK;
   1181       break;
   1182 
   1183     default:
   1184       ASSERT (FORM_SET_BEV_ORDER_ID == CallbackData->BmmPreviousPageId);
   1185       OptionMenu            = (BM_MENU_OPTION *) &LegacyBEVMenu;
   1186       LegacyDev             = CallbackData->BmmFakeNvData.LegacyBEV;
   1187       CallbackData->BbsType = BBS_BEV_DEVICE;
   1188       break;
   1189   }
   1190 
   1191   DisMap  = CallbackData->BmmOldFakeNVData.DisableMap;
   1192   Status  = EFI_SUCCESS;
   1193 
   1194 
   1195   //
   1196   // Update the Variable "LegacyDevOrder"
   1197   //
   1198   VarData = (UINT8 *) BdsLibGetVariableAndSize (
   1199                         VAR_LEGACY_DEV_ORDER,
   1200                         &gEfiLegacyDevOrderVariableGuid,
   1201                         &VarSize
   1202                         );
   1203 
   1204   if (VarData == NULL) {
   1205     return EFI_NOT_FOUND;
   1206   }
   1207 
   1208   OriginalPtr = VarData;
   1209   DevOrder    = (LEGACY_DEV_ORDER_ENTRY *) VarData;
   1210 
   1211   while (VarData < OriginalPtr + VarSize) {
   1212     if (DevOrder->BbsType == CallbackData->BbsType) {
   1213       break;
   1214     }
   1215 
   1216     VarData += sizeof (BBS_TYPE) + DevOrder->Length;
   1217     DevOrder = (LEGACY_DEV_ORDER_ENTRY *) VarData;
   1218   }
   1219 
   1220   if (VarData >= OriginalPtr + VarSize) {
   1221     FreePool (OriginalPtr);
   1222     return EFI_NOT_FOUND;
   1223   }
   1224 
   1225   NewOrder = AllocateZeroPool (DevOrder->Length - sizeof (DevOrder->Length));
   1226   if (NewOrder == NULL) {
   1227     FreePool (OriginalPtr);
   1228     return EFI_OUT_OF_RESOURCES;
   1229   }
   1230 
   1231   for (Index = 0; Index < OptionMenu->MenuNumber; Index++) {
   1232     if (0xFF == LegacyDev[Index]) {
   1233       break;
   1234     }
   1235 
   1236     NewOrder[Index] = LegacyDev[Index];
   1237   }
   1238   //
   1239   // Only the enable/disable state of each boot device with same device type can be changed,
   1240   // so we can count on the index information in DevOrder.
   1241   // DisMap bit array is the only reliable source to check a device's en/dis state,
   1242   // so we use DisMap to set en/dis state of each item in NewOrder array
   1243   //
   1244   for (Index2 = 0; Index2 < OptionMenu->MenuNumber; Index2++) {
   1245     Tmp = (UINT16) (DevOrder->Data[Index2] & 0xFF);
   1246     Pos = Tmp / 8;
   1247     Bit = 7 - (Tmp % 8);
   1248     if ((DisMap[Pos] & (1 << Bit)) != 0) {
   1249       NewOrder[Index] = (UINT16) (0xFF00 | Tmp);
   1250       Index++;
   1251     }
   1252   }
   1253 
   1254   CopyMem (
   1255     DevOrder->Data,
   1256     NewOrder,
   1257     DevOrder->Length - sizeof (DevOrder->Length)
   1258     );
   1259   FreePool (NewOrder);
   1260 
   1261   Status = gRT->SetVariable (
   1262                   VAR_LEGACY_DEV_ORDER,
   1263                   &gEfiLegacyDevOrderVariableGuid,
   1264                   EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
   1265                   VarSize,
   1266                   OriginalPtr
   1267                   );
   1268 
   1269 
   1270   //
   1271   // Update BootOrder and Boot####.Attribute
   1272   //
   1273   // 1. Re-order the Option Number in BootOrder according to Legacy Dev Order
   1274   //
   1275   ASSERT (OptionMenu->MenuNumber == DevOrder->Length / sizeof (UINT16) - 1);
   1276 
   1277   OrderLegacyBootOption4SameType (
   1278     DevOrder->Data,
   1279     DevOrder->Length / sizeof (UINT16) - 1,
   1280     &EnBootOption,
   1281     &EnBootOptionCount,
   1282     &DisBootOption,
   1283     &DisBootOptionCount
   1284     );
   1285 
   1286   //
   1287   // 2. Deactivate the DisBootOption and activate the EnBootOption
   1288   //
   1289   for (Index = 0; Index < DisBootOptionCount; Index++) {
   1290     UnicodeSPrint (VarName, sizeof (VarName), L"Boot%04x", DisBootOption[Index]);
   1291     BootOptionVar = BdsLibGetVariableAndSize (
   1292                       VarName,
   1293                       &gEfiGlobalVariableGuid,
   1294                       &OptionSize
   1295                       );
   1296     if (BootOptionVar != NULL) {
   1297       Attribute   = (UINT32 *) BootOptionVar;
   1298       *Attribute &= ~LOAD_OPTION_ACTIVE;
   1299 
   1300       Status = gRT->SetVariable (
   1301                       VarName,
   1302                       &gEfiGlobalVariableGuid,
   1303                       EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
   1304                       OptionSize,
   1305                       BootOptionVar
   1306                       );
   1307       //
   1308       // Changing the content without increasing its size with current variable implementation shouldn't fail.
   1309       //
   1310       ASSERT_EFI_ERROR (Status);
   1311 
   1312       FreePool (BootOptionVar);
   1313     }
   1314   }
   1315 
   1316   for (Index = 0; Index < EnBootOptionCount; Index++) {
   1317     UnicodeSPrint (VarName, sizeof (VarName), L"Boot%04x", EnBootOption[Index]);
   1318     BootOptionVar = BdsLibGetVariableAndSize (
   1319                       VarName,
   1320                       &gEfiGlobalVariableGuid,
   1321                       &OptionSize
   1322                       );
   1323     if (BootOptionVar != NULL) {
   1324       Attribute   = (UINT32 *) BootOptionVar;
   1325       *Attribute |= LOAD_OPTION_ACTIVE;
   1326 
   1327       Status = gRT->SetVariable (
   1328                       VarName,
   1329                       &gEfiGlobalVariableGuid,
   1330                       EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
   1331                       OptionSize,
   1332                       BootOptionVar
   1333                       );
   1334       //
   1335       // Changing the content without increasing its size with current variable implementation shouldn't fail.
   1336       //
   1337       ASSERT_EFI_ERROR (Status);
   1338 
   1339       FreePool (BootOptionVar);
   1340     }
   1341   }
   1342 
   1343   BOpt_GetBootOptions (CallbackData);
   1344 
   1345   FreePool (OriginalPtr);
   1346   FreePool (EnBootOption);
   1347   FreePool (DisBootOption);
   1348   return Status;
   1349 }
   1350 
   1351 /**
   1352   Update the Text Mode of Console.
   1353 
   1354   @param CallbackData  The context data for BMM.
   1355 
   1356   @retval EFI_SUCCSS If the Text Mode of Console is updated.
   1357   @return Other value if the Text Mode of Console is not updated.
   1358 
   1359 **/
   1360 EFI_STATUS
   1361 Var_UpdateConMode (
   1362   IN BMM_CALLBACK_DATA            *CallbackData
   1363   )
   1364 {
   1365   EFI_STATUS        Status;
   1366   UINTN             Mode;
   1367   CONSOLE_OUT_MODE  ModeInfo;
   1368 
   1369   Mode = CallbackData->BmmFakeNvData.ConsoleOutMode;
   1370 
   1371   Status = gST->ConOut->QueryMode (gST->ConOut, Mode, &(ModeInfo.Column), &(ModeInfo.Row));
   1372   if (!EFI_ERROR(Status)) {
   1373     Status = PcdSet32S (PcdSetupConOutColumn, (UINT32) ModeInfo.Column);
   1374     if (!EFI_ERROR (Status)){
   1375       Status = PcdSet32S (PcdSetupConOutRow, (UINT32) ModeInfo.Row);
   1376     }
   1377   }
   1378 
   1379   return Status;
   1380 }
   1381