Home | History | Annotate | Download | only in BootMaintenanceManagerUiLib
      1 /** @file
      2   Provide boot option support for Application "BootMaint"
      3 
      4   Include file system navigation, system handle selection
      5 
      6   Boot option manipulation
      7 
      8 Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR>
      9 This program and the accompanying materials
     10 are licensed and made available under the terms and conditions of the BSD License
     11 which accompanies this distribution.  The full text of the license may be found at
     12 http://opensource.org/licenses/bsd-license.php
     13 
     14 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     15 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     16 
     17 **/
     18 
     19 #include "BootMaintenanceManager.h"
     20 
     21 ///
     22 /// Define the maximum characters that will be accepted.
     23 ///
     24 #define MAX_CHAR            480
     25 
     26 /**
     27   Create a menu entry by given menu type.
     28 
     29   @param MenuType        The Menu type to be created.
     30 
     31   @retval NULL           If failed to create the menu.
     32   @return the new menu entry.
     33 
     34 **/
     35 BM_MENU_ENTRY *
     36 BOpt_CreateMenuEntry (
     37   UINTN           MenuType
     38   )
     39 {
     40   BM_MENU_ENTRY *MenuEntry;
     41   UINTN         ContextSize;
     42 
     43   //
     44   // Get context size according to menu type
     45   //
     46   switch (MenuType) {
     47   case BM_LOAD_CONTEXT_SELECT:
     48     ContextSize = sizeof (BM_LOAD_CONTEXT);
     49     break;
     50 
     51   case BM_FILE_CONTEXT_SELECT:
     52     ContextSize = sizeof (BM_FILE_CONTEXT);
     53     break;
     54 
     55   case BM_CONSOLE_CONTEXT_SELECT:
     56     ContextSize = sizeof (BM_CONSOLE_CONTEXT);
     57     break;
     58 
     59   case BM_TERMINAL_CONTEXT_SELECT:
     60     ContextSize = sizeof (BM_TERMINAL_CONTEXT);
     61     break;
     62 
     63   case BM_HANDLE_CONTEXT_SELECT:
     64     ContextSize = sizeof (BM_HANDLE_CONTEXT);
     65     break;
     66 
     67   default:
     68     ContextSize = 0;
     69     break;
     70   }
     71 
     72   if (ContextSize == 0) {
     73     return NULL;
     74   }
     75 
     76   //
     77   // Create new menu entry
     78   //
     79   MenuEntry = AllocateZeroPool (sizeof (BM_MENU_ENTRY));
     80   if (MenuEntry == NULL) {
     81     return NULL;
     82   }
     83 
     84   MenuEntry->VariableContext = AllocateZeroPool (ContextSize);
     85   if (MenuEntry->VariableContext == NULL) {
     86     FreePool (MenuEntry);
     87     return NULL;
     88   }
     89 
     90   MenuEntry->Signature        = BM_MENU_ENTRY_SIGNATURE;
     91   MenuEntry->ContextSelection = MenuType;
     92   return MenuEntry;
     93 }
     94 
     95 /**
     96   Free up all resource allocated for a BM_MENU_ENTRY.
     97 
     98   @param MenuEntry   A pointer to BM_MENU_ENTRY.
     99 
    100 **/
    101 VOID
    102 BOpt_DestroyMenuEntry (
    103   BM_MENU_ENTRY         *MenuEntry
    104   )
    105 {
    106   BM_LOAD_CONTEXT           *LoadContext;
    107   BM_FILE_CONTEXT           *FileContext;
    108   BM_CONSOLE_CONTEXT        *ConsoleContext;
    109   BM_TERMINAL_CONTEXT       *TerminalContext;
    110   BM_HANDLE_CONTEXT         *HandleContext;
    111 
    112   //
    113   //  Select by the type in Menu entry for current context type
    114   //
    115   switch (MenuEntry->ContextSelection) {
    116   case BM_LOAD_CONTEXT_SELECT:
    117     LoadContext = (BM_LOAD_CONTEXT *) MenuEntry->VariableContext;
    118     FreePool (LoadContext->FilePathList);
    119     if (LoadContext->OptionalData != NULL) {
    120       FreePool (LoadContext->OptionalData);
    121     }
    122     FreePool (LoadContext);
    123     break;
    124 
    125   case BM_FILE_CONTEXT_SELECT:
    126     FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;
    127 
    128     if (!FileContext->IsRoot) {
    129       FreePool (FileContext->DevicePath);
    130     } else {
    131       if (FileContext->FHandle != NULL) {
    132         FileContext->FHandle->Close (FileContext->FHandle);
    133       }
    134     }
    135 
    136     if (FileContext->FileName != NULL) {
    137       FreePool (FileContext->FileName);
    138     }
    139     if (FileContext->Info != NULL) {
    140       FreePool (FileContext->Info);
    141     }
    142     FreePool (FileContext);
    143     break;
    144 
    145   case BM_CONSOLE_CONTEXT_SELECT:
    146     ConsoleContext = (BM_CONSOLE_CONTEXT *) MenuEntry->VariableContext;
    147     FreePool (ConsoleContext->DevicePath);
    148     FreePool (ConsoleContext);
    149     break;
    150 
    151   case BM_TERMINAL_CONTEXT_SELECT:
    152     TerminalContext = (BM_TERMINAL_CONTEXT *) MenuEntry->VariableContext;
    153     FreePool (TerminalContext->DevicePath);
    154     FreePool (TerminalContext);
    155     break;
    156 
    157   case BM_HANDLE_CONTEXT_SELECT:
    158     HandleContext = (BM_HANDLE_CONTEXT *) MenuEntry->VariableContext;
    159     FreePool (HandleContext);
    160     break;
    161 
    162   default:
    163     break;
    164   }
    165 
    166   FreePool (MenuEntry->DisplayString);
    167   if (MenuEntry->HelpString != NULL) {
    168     FreePool (MenuEntry->HelpString);
    169   }
    170 
    171   FreePool (MenuEntry);
    172 }
    173 
    174 /**
    175   Get the Menu Entry from the list in Menu Entry List.
    176 
    177   If MenuNumber is great or equal to the number of Menu
    178   Entry in the list, then ASSERT.
    179 
    180   @param MenuOption      The Menu Entry List to read the menu entry.
    181   @param MenuNumber      The index of Menu Entry.
    182 
    183   @return The Menu Entry.
    184 
    185 **/
    186 BM_MENU_ENTRY *
    187 BOpt_GetMenuEntry (
    188   BM_MENU_OPTION      *MenuOption,
    189   UINTN               MenuNumber
    190   )
    191 {
    192   BM_MENU_ENTRY   *NewMenuEntry;
    193   UINTN           Index;
    194   LIST_ENTRY      *List;
    195 
    196   ASSERT (MenuNumber < MenuOption->MenuNumber);
    197 
    198   List = MenuOption->Head.ForwardLink;
    199   for (Index = 0; Index < MenuNumber; Index++) {
    200     List = List->ForwardLink;
    201   }
    202 
    203   NewMenuEntry = CR (List, BM_MENU_ENTRY, Link, BM_MENU_ENTRY_SIGNATURE);
    204 
    205   return NewMenuEntry;
    206 }
    207 
    208 /**
    209   Free resources allocated in Allocate Rountine.
    210 
    211   @param FreeMenu        Menu to be freed
    212 **/
    213 VOID
    214 BOpt_FreeMenu (
    215   BM_MENU_OPTION        *FreeMenu
    216   )
    217 {
    218   BM_MENU_ENTRY *MenuEntry;
    219   while (!IsListEmpty (&FreeMenu->Head)) {
    220     MenuEntry = CR (
    221                   FreeMenu->Head.ForwardLink,
    222                   BM_MENU_ENTRY,
    223                   Link,
    224                   BM_MENU_ENTRY_SIGNATURE
    225                   );
    226     RemoveEntryList (&MenuEntry->Link);
    227     BOpt_DestroyMenuEntry (MenuEntry);
    228   }
    229   FreeMenu->MenuNumber = 0;
    230 }
    231 
    232 /**
    233 
    234   Build the BootOptionMenu according to BootOrder Variable.
    235   This Routine will access the Boot#### to get EFI_LOAD_OPTION.
    236 
    237   @param CallbackData The BMM context data.
    238 
    239   @return EFI_NOT_FOUND Fail to find "BootOrder" variable.
    240   @return EFI_SUCESS    Success build boot option menu.
    241 
    242 **/
    243 EFI_STATUS
    244 BOpt_GetBootOptions (
    245   IN  BMM_CALLBACK_DATA         *CallbackData
    246   )
    247 {
    248   UINTN                         Index;
    249   UINT16                        BootString[10];
    250   UINT8                         *LoadOptionFromVar;
    251   UINTN                         BootOptionSize;
    252   BOOLEAN                       BootNextFlag;
    253   UINT16                        *BootOrderList;
    254   UINTN                         BootOrderListSize;
    255   UINT16                        *BootNext;
    256   UINTN                         BootNextSize;
    257   BM_MENU_ENTRY                 *NewMenuEntry;
    258   BM_LOAD_CONTEXT               *NewLoadContext;
    259   UINT8                         *LoadOptionPtr;
    260   UINTN                         StringSize;
    261   UINTN                         OptionalDataSize;
    262   UINT8                         *LoadOptionEnd;
    263   EFI_DEVICE_PATH_PROTOCOL      *DevicePath;
    264   UINTN                         MenuCount;
    265   UINT8                         *Ptr;
    266   EFI_BOOT_MANAGER_LOAD_OPTION  *BootOption;
    267   UINTN                         BootOptionCount;
    268 
    269   MenuCount         = 0;
    270   BootOrderListSize = 0;
    271   BootNextSize      = 0;
    272   BootOrderList     = NULL;
    273   BootNext          = NULL;
    274   LoadOptionFromVar = NULL;
    275   BOpt_FreeMenu (&BootOptionMenu);
    276   InitializeListHead (&BootOptionMenu.Head);
    277 
    278   //
    279   // Get the BootOrder from the Var
    280   //
    281   GetEfiGlobalVariable2 (L"BootOrder", (VOID **) &BootOrderList, &BootOrderListSize);
    282   if (BootOrderList == NULL) {
    283     return EFI_NOT_FOUND;
    284   }
    285 
    286   //
    287   // Get the BootNext from the Var
    288   //
    289   GetEfiGlobalVariable2 (L"BootNext", (VOID **) &BootNext, &BootNextSize);
    290   if (BootNext != NULL) {
    291     if (BootNextSize != sizeof (UINT16)) {
    292       FreePool (BootNext);
    293       BootNext = NULL;
    294     }
    295   }
    296   BootOption = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
    297   for (Index = 0; Index < BootOrderListSize / sizeof (UINT16); Index++) {
    298     //
    299     // Don't display the hidden/inactive boot option
    300     //
    301     if (((BootOption[Index].Attributes & LOAD_OPTION_HIDDEN) != 0) || ((BootOption[Index].Attributes & LOAD_OPTION_ACTIVE) == 0)) {
    302       continue;
    303     }
    304 
    305     UnicodeSPrint (BootString, sizeof (BootString), L"Boot%04x", BootOrderList[Index]);
    306     //
    307     //  Get all loadoptions from the VAR
    308     //
    309     GetEfiGlobalVariable2 (BootString, (VOID **) &LoadOptionFromVar, &BootOptionSize);
    310     if (LoadOptionFromVar == NULL) {
    311       continue;
    312     }
    313 
    314     if (BootNext != NULL) {
    315       BootNextFlag = (BOOLEAN) (*BootNext == BootOrderList[Index]);
    316     } else {
    317       BootNextFlag = FALSE;
    318     }
    319 
    320     NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);
    321     ASSERT (NULL != NewMenuEntry);
    322 
    323     NewLoadContext                      = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
    324 
    325     LoadOptionPtr                       = LoadOptionFromVar;
    326     LoadOptionEnd                       = LoadOptionFromVar + BootOptionSize;
    327 
    328     NewMenuEntry->OptionNumber          = BootOrderList[Index];
    329     NewLoadContext->Deleted             = FALSE;
    330     NewLoadContext->IsBootNext          = BootNextFlag;
    331 
    332     //
    333     // Is a Legacy Device?
    334     //
    335     Ptr = (UINT8 *) LoadOptionFromVar;
    336 
    337     //
    338     // Attribute = *(UINT32 *)Ptr;
    339     //
    340     Ptr += sizeof (UINT32);
    341 
    342     //
    343     // FilePathSize = *(UINT16 *)Ptr;
    344     //
    345     Ptr += sizeof (UINT16);
    346 
    347     //
    348     // Description = (CHAR16 *)Ptr;
    349     //
    350     Ptr += StrSize ((CHAR16 *) Ptr);
    351 
    352     //
    353     // Now Ptr point to Device Path
    354     //
    355     DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr;
    356     if ((BBS_DEVICE_PATH == DevicePath->Type) && (BBS_BBS_DP == DevicePath->SubType)) {
    357       NewLoadContext->IsLegacy = TRUE;
    358     } else {
    359       NewLoadContext->IsLegacy = FALSE;
    360     }
    361     //
    362     // LoadOption is a pointer type of UINT8
    363     // for easy use with following LOAD_OPTION
    364     // embedded in this struct
    365     //
    366 
    367     NewLoadContext->Attributes      = *(UINT32 *) LoadOptionPtr;
    368 
    369     LoadOptionPtr += sizeof (UINT32);
    370 
    371     NewLoadContext->FilePathListLength = *(UINT16 *) LoadOptionPtr;
    372     LoadOptionPtr += sizeof (UINT16);
    373 
    374     StringSize = StrSize((UINT16*)LoadOptionPtr);
    375 
    376     NewLoadContext->Description = AllocateZeroPool (StrSize((UINT16*)LoadOptionPtr));
    377     ASSERT (NewLoadContext->Description != NULL);
    378     StrCpyS (NewLoadContext->Description, StrSize((UINT16*)LoadOptionPtr) / sizeof (UINT16), (UINT16*)LoadOptionPtr);
    379 
    380     ASSERT (NewLoadContext->Description != NULL);
    381     NewMenuEntry->DisplayString = NewLoadContext->Description;
    382     NewMenuEntry->DisplayStringToken = HiiSetString (CallbackData->BmmHiiHandle, 0, NewMenuEntry->DisplayString, NULL);
    383 
    384     LoadOptionPtr += StringSize;
    385 
    386     NewLoadContext->FilePathList = AllocateZeroPool (NewLoadContext->FilePathListLength);
    387     ASSERT (NewLoadContext->FilePathList != NULL);
    388     CopyMem (
    389       NewLoadContext->FilePathList,
    390       (EFI_DEVICE_PATH_PROTOCOL *) LoadOptionPtr,
    391       NewLoadContext->FilePathListLength
    392       );
    393 
    394     NewMenuEntry->HelpString = UiDevicePathToStr (NewLoadContext->FilePathList);
    395     NewMenuEntry->HelpStringToken = HiiSetString (CallbackData->BmmHiiHandle, 0, NewMenuEntry->HelpString, NULL);
    396 
    397     LoadOptionPtr += NewLoadContext->FilePathListLength;
    398 
    399     if (LoadOptionPtr < LoadOptionEnd) {
    400       OptionalDataSize = BootOptionSize -
    401         sizeof (UINT32) -
    402         sizeof (UINT16) -
    403         StringSize -
    404         NewLoadContext->FilePathListLength;
    405 
    406       NewLoadContext->OptionalData = AllocateZeroPool (OptionalDataSize);
    407       ASSERT (NewLoadContext->OptionalData != NULL);
    408       CopyMem (
    409         NewLoadContext->OptionalData,
    410         LoadOptionPtr,
    411         OptionalDataSize
    412         );
    413     }
    414 
    415     InsertTailList (&BootOptionMenu.Head, &NewMenuEntry->Link);
    416     MenuCount++;
    417     FreePool (LoadOptionFromVar);
    418   }
    419   EfiBootManagerFreeLoadOptions (BootOption, BootOptionCount);
    420 
    421   if (BootNext != NULL) {
    422     FreePool (BootNext);
    423   }
    424   if (BootOrderList != NULL) {
    425     FreePool (BootOrderList);
    426   }
    427 
    428   BootOptionMenu.MenuNumber = MenuCount;
    429   return EFI_SUCCESS;
    430 }
    431 
    432 /**
    433 
    434   Find drivers that will be added as Driver#### variables from handles
    435   in current system environment
    436   All valid handles in the system except those consume SimpleFs, LoadFile
    437   are stored in DriverMenu for future use.
    438 
    439   @retval EFI_SUCCESS The function complets successfully.
    440   @return Other value if failed to build the DriverMenu.
    441 
    442 **/
    443 EFI_STATUS
    444 BOpt_FindDrivers (
    445   VOID
    446   )
    447 {
    448   UINTN                           NoDevicePathHandles;
    449   EFI_HANDLE                      *DevicePathHandle;
    450   UINTN                           Index;
    451   EFI_STATUS                      Status;
    452   BM_MENU_ENTRY                   *NewMenuEntry;
    453   BM_HANDLE_CONTEXT               *NewHandleContext;
    454   EFI_HANDLE                      CurHandle;
    455   UINTN                           OptionNumber;
    456   EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFs;
    457   EFI_LOAD_FILE_PROTOCOL          *LoadFile;
    458 
    459   SimpleFs  = NULL;
    460   LoadFile  = NULL;
    461 
    462   InitializeListHead (&DriverMenu.Head);
    463 
    464   //
    465   // At first, get all handles that support Device Path
    466   // protocol which is the basic requirement for
    467   // Driver####
    468   //
    469   Status = gBS->LocateHandleBuffer (
    470                   ByProtocol,
    471                   &gEfiDevicePathProtocolGuid,
    472                   NULL,
    473                   &NoDevicePathHandles,
    474                   &DevicePathHandle
    475                   );
    476   if (EFI_ERROR (Status)) {
    477     return Status;
    478   }
    479 
    480   OptionNumber = 0;
    481   for (Index = 0; Index < NoDevicePathHandles; Index++) {
    482     CurHandle = DevicePathHandle[Index];
    483 
    484     Status = gBS->HandleProtocol (
    485                     CurHandle,
    486                     &gEfiSimpleFileSystemProtocolGuid,
    487                     (VOID **) &SimpleFs
    488                     );
    489     if (Status == EFI_SUCCESS) {
    490       continue;
    491     }
    492 
    493     Status = gBS->HandleProtocol (
    494                     CurHandle,
    495                     &gEfiLoadFileProtocolGuid,
    496                     (VOID **) &LoadFile
    497                     );
    498     if (Status == EFI_SUCCESS) {
    499       continue;
    500     }
    501 
    502     NewMenuEntry = BOpt_CreateMenuEntry (BM_HANDLE_CONTEXT_SELECT);
    503     if (NULL == NewMenuEntry) {
    504       FreePool (DevicePathHandle);
    505       return EFI_OUT_OF_RESOURCES;
    506     }
    507 
    508     NewHandleContext              = (BM_HANDLE_CONTEXT *) NewMenuEntry->VariableContext;
    509     NewHandleContext->Handle      = CurHandle;
    510     NewHandleContext->DevicePath  = DevicePathFromHandle (CurHandle);
    511     NewMenuEntry->DisplayString = UiDevicePathToStr (NewHandleContext->DevicePath);
    512     NewMenuEntry->DisplayStringToken = HiiSetString (mBmmCallbackInfo->BmmHiiHandle,0,NewMenuEntry->DisplayString,NULL);
    513     NewMenuEntry->HelpString    = NULL;
    514     NewMenuEntry->HelpStringToken = NewMenuEntry->DisplayStringToken;
    515     NewMenuEntry->OptionNumber  = OptionNumber;
    516     OptionNumber++;
    517     InsertTailList (&DriverMenu.Head, &NewMenuEntry->Link);
    518 
    519   }
    520 
    521   if (DevicePathHandle != NULL) {
    522     FreePool (DevicePathHandle);
    523   }
    524 
    525   DriverMenu.MenuNumber = OptionNumber;
    526   return EFI_SUCCESS;
    527 }
    528 
    529 /**
    530 
    531   Get the Option Number that has not been allocated for use.
    532 
    533   @param Type  The type of Option.
    534 
    535   @return The available Option Number.
    536 
    537 **/
    538 UINT16
    539 BOpt_GetOptionNumber (
    540   CHAR16        *Type
    541   )
    542 {
    543   UINT16        *OrderList;
    544   UINTN         OrderListSize;
    545   UINTN         Index;
    546   CHAR16        StrTemp[20];
    547   UINT16        *OptionBuffer;
    548   UINT16        OptionNumber;
    549   UINTN         OptionSize;
    550 
    551   OrderListSize = 0;
    552   OrderList     = NULL;
    553   OptionNumber  = 0;
    554   Index         = 0;
    555 
    556   UnicodeSPrint (StrTemp, sizeof (StrTemp), L"%sOrder", Type);
    557 
    558   GetEfiGlobalVariable2 (StrTemp, (VOID **) &OrderList, &OrderListSize);
    559   for (OptionNumber = 0; ; OptionNumber++) {
    560     if (OrderList != NULL) {
    561       for (Index = 0; Index < OrderListSize / sizeof (UINT16); Index++) {
    562         if (OptionNumber == OrderList[Index]) {
    563           break;
    564         }
    565       }
    566     }
    567 
    568     if (Index < OrderListSize / sizeof (UINT16)) {
    569       //
    570       // The OptionNumber occurs in the OrderList, continue to use next one
    571       //
    572       continue;
    573     }
    574     UnicodeSPrint (StrTemp, sizeof (StrTemp), L"%s%04x", Type, (UINTN) OptionNumber);
    575     DEBUG((EFI_D_ERROR,"Option = %s\n", StrTemp));
    576     GetEfiGlobalVariable2 (StrTemp, (VOID **) &OptionBuffer, &OptionSize);
    577     if (NULL == OptionBuffer) {
    578       //
    579       // The Boot[OptionNumber] / Driver[OptionNumber] NOT occurs, we found it
    580       //
    581       break;
    582     }
    583   }
    584 
    585   return OptionNumber;
    586 }
    587 
    588 /**
    589 
    590   Get the Option Number for Boot#### that does not used.
    591 
    592   @return The available Option Number.
    593 
    594 **/
    595 UINT16
    596 BOpt_GetBootOptionNumber (
    597   VOID
    598   )
    599 {
    600   return BOpt_GetOptionNumber (L"Boot");
    601 }
    602 
    603 /**
    604 
    605   Get the Option Number for Driver#### that does not used.
    606 
    607   @return The unused Option Number.
    608 
    609 **/
    610 UINT16
    611 BOpt_GetDriverOptionNumber (
    612   VOID
    613   )
    614 {
    615   return BOpt_GetOptionNumber (L"Driver");
    616 }
    617 
    618 /**
    619 
    620   Build up all DriverOptionMenu
    621 
    622   @param CallbackData The BMM context data.
    623 
    624   @retval EFI_SUCESS           The functin completes successfully.
    625   @retval EFI_OUT_OF_RESOURCES Not enough memory to compete the operation.
    626   @retval EFI_NOT_FOUND        Fail to get "DriverOrder" variable.
    627 
    628 **/
    629 EFI_STATUS
    630 BOpt_GetDriverOptions (
    631   IN  BMM_CALLBACK_DATA         *CallbackData
    632   )
    633 {
    634   UINTN           Index;
    635   UINT16          DriverString[12];
    636   UINT8           *LoadOptionFromVar;
    637   UINTN           DriverOptionSize;
    638 
    639   UINT16          *DriverOrderList;
    640   UINTN           DriverOrderListSize;
    641   BM_MENU_ENTRY   *NewMenuEntry;
    642   BM_LOAD_CONTEXT *NewLoadContext;
    643   UINT8           *LoadOptionPtr;
    644   UINTN           StringSize;
    645   UINTN           OptionalDataSize;
    646   UINT8           *LoadOptionEnd;
    647 
    648   DriverOrderListSize = 0;
    649   DriverOrderList     = NULL;
    650   DriverOptionSize    = 0;
    651   LoadOptionFromVar   = NULL;
    652   BOpt_FreeMenu (&DriverOptionMenu);
    653   InitializeListHead (&DriverOptionMenu.Head);
    654   //
    655   // Get the DriverOrder from the Var
    656   //
    657   GetEfiGlobalVariable2 (L"DriverOrder", (VOID **) &DriverOrderList, &DriverOrderListSize);
    658   if (DriverOrderList == NULL) {
    659     return EFI_NOT_FOUND;
    660   }
    661 
    662   for (Index = 0; Index < DriverOrderListSize / sizeof (UINT16); Index++) {
    663     UnicodeSPrint (
    664       DriverString,
    665       sizeof (DriverString),
    666       L"Driver%04x",
    667       DriverOrderList[Index]
    668       );
    669     //
    670     //  Get all loadoptions from the VAR
    671     //
    672     GetEfiGlobalVariable2 (DriverString, (VOID **) &LoadOptionFromVar, &DriverOptionSize);
    673     if (LoadOptionFromVar == NULL) {
    674       continue;
    675     }
    676 
    677 
    678     NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);
    679     if (NULL == NewMenuEntry) {
    680       return EFI_OUT_OF_RESOURCES;
    681     }
    682 
    683     NewLoadContext                      = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
    684     LoadOptionPtr                       = LoadOptionFromVar;
    685     LoadOptionEnd                       = LoadOptionFromVar + DriverOptionSize;
    686     NewMenuEntry->OptionNumber          = DriverOrderList[Index];
    687     NewLoadContext->Deleted             = FALSE;
    688     NewLoadContext->IsLegacy            = FALSE;
    689 
    690     //
    691     // LoadOption is a pointer type of UINT8
    692     // for easy use with following LOAD_OPTION
    693     // embedded in this struct
    694     //
    695 
    696     NewLoadContext->Attributes      = *(UINT32 *) LoadOptionPtr;
    697 
    698     LoadOptionPtr += sizeof (UINT32);
    699 
    700     NewLoadContext->FilePathListLength = *(UINT16 *) LoadOptionPtr;
    701     LoadOptionPtr += sizeof (UINT16);
    702 
    703     StringSize                  = StrSize ((UINT16 *) LoadOptionPtr);
    704     NewLoadContext->Description = AllocateZeroPool (StringSize);
    705     ASSERT (NewLoadContext->Description != NULL);
    706     CopyMem (
    707       NewLoadContext->Description,
    708       (UINT16 *) LoadOptionPtr,
    709       StringSize
    710       );
    711     NewMenuEntry->DisplayString = NewLoadContext->Description;
    712     NewMenuEntry->DisplayStringToken = HiiSetString (CallbackData->BmmHiiHandle, 0, NewMenuEntry->DisplayString, NULL);
    713 
    714     LoadOptionPtr += StringSize;
    715 
    716     NewLoadContext->FilePathList = AllocateZeroPool (NewLoadContext->FilePathListLength);
    717     ASSERT (NewLoadContext->FilePathList != NULL);
    718     CopyMem (
    719       NewLoadContext->FilePathList,
    720       (EFI_DEVICE_PATH_PROTOCOL *) LoadOptionPtr,
    721       NewLoadContext->FilePathListLength
    722       );
    723 
    724     NewMenuEntry->HelpString = UiDevicePathToStr (NewLoadContext->FilePathList);
    725     NewMenuEntry->HelpStringToken = HiiSetString (CallbackData->BmmHiiHandle, 0, NewMenuEntry->HelpString, NULL);
    726 
    727     LoadOptionPtr += NewLoadContext->FilePathListLength;
    728 
    729     if (LoadOptionPtr < LoadOptionEnd) {
    730       OptionalDataSize = DriverOptionSize -
    731         sizeof (UINT32) -
    732         sizeof (UINT16) -
    733         StringSize -
    734         NewLoadContext->FilePathListLength;
    735 
    736       NewLoadContext->OptionalData = AllocateZeroPool (OptionalDataSize);
    737       ASSERT (NewLoadContext->OptionalData != NULL);
    738       CopyMem (
    739         NewLoadContext->OptionalData,
    740         LoadOptionPtr,
    741         OptionalDataSize
    742         );
    743 
    744     }
    745 
    746     InsertTailList (&DriverOptionMenu.Head, &NewMenuEntry->Link);
    747     FreePool (LoadOptionFromVar);
    748 
    749   }
    750 
    751   if (DriverOrderList != NULL) {
    752     FreePool (DriverOrderList);
    753   }
    754 
    755   DriverOptionMenu.MenuNumber = Index;
    756   return EFI_SUCCESS;
    757 
    758 }
    759 
    760 /**
    761   Get option number according to Boot#### and BootOrder variable.
    762   The value is saved as #### + 1.
    763 
    764   @param CallbackData    The BMM context data.
    765 **/
    766 VOID
    767 GetBootOrder (
    768   IN  BMM_CALLBACK_DATA    *CallbackData
    769   )
    770 {
    771   BMM_FAKE_NV_DATA          *BmmConfig;
    772   UINT16                    Index;
    773   UINT16                    OptionOrderIndex;
    774   UINTN                     DeviceType;
    775   BM_MENU_ENTRY             *NewMenuEntry;
    776   BM_LOAD_CONTEXT           *NewLoadContext;
    777 
    778   ASSERT (CallbackData != NULL);
    779 
    780   DeviceType = (UINTN) -1;
    781   BmmConfig  = &CallbackData->BmmFakeNvData;
    782   ZeroMem (BmmConfig->BootOptionOrder, sizeof (BmmConfig->BootOptionOrder));
    783 
    784   for (Index = 0, OptionOrderIndex = 0; ((Index < BootOptionMenu.MenuNumber) &&
    785        (OptionOrderIndex < (sizeof (BmmConfig->BootOptionOrder) / sizeof (BmmConfig->BootOptionOrder[0]))));
    786        Index++) {
    787     NewMenuEntry   = BOpt_GetMenuEntry (&BootOptionMenu, Index);
    788     NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
    789 
    790     if (NewLoadContext->IsLegacy) {
    791       if (((BBS_BBS_DEVICE_PATH *) NewLoadContext->FilePathList)->DeviceType != DeviceType) {
    792         DeviceType = ((BBS_BBS_DEVICE_PATH *) NewLoadContext->FilePathList)->DeviceType;
    793       } else {
    794         //
    795         // Only show one legacy boot option for the same device type
    796         // assuming the boot options are grouped by the device type
    797         //
    798         continue;
    799       }
    800     }
    801     BmmConfig->BootOptionOrder[OptionOrderIndex++] = (UINT32) (NewMenuEntry->OptionNumber + 1);
    802   }
    803 }
    804 
    805 /**
    806   Get driver option order from globalc DriverOptionMenu.
    807 
    808   @param CallbackData    The BMM context data.
    809 
    810 **/
    811 VOID
    812 GetDriverOrder (
    813   IN  BMM_CALLBACK_DATA    *CallbackData
    814   )
    815 {
    816   BMM_FAKE_NV_DATA          *BmmConfig;
    817   UINT16                    Index;
    818   UINT16                    OptionOrderIndex;
    819   UINTN                     DeviceType;
    820   BM_MENU_ENTRY             *NewMenuEntry;
    821   BM_LOAD_CONTEXT           *NewLoadContext;
    822 
    823 
    824   ASSERT (CallbackData != NULL);
    825 
    826   DeviceType = (UINTN) -1;
    827   BmmConfig  = &CallbackData->BmmFakeNvData;
    828   ZeroMem (BmmConfig->DriverOptionOrder, sizeof (BmmConfig->DriverOptionOrder));
    829 
    830   for (Index = 0, OptionOrderIndex = 0; ((Index < DriverOptionMenu.MenuNumber) &&
    831        (OptionOrderIndex < (sizeof (BmmConfig->DriverOptionOrder) / sizeof (BmmConfig->DriverOptionOrder[0]))));
    832        Index++) {
    833     NewMenuEntry   = BOpt_GetMenuEntry (&DriverOptionMenu, Index);
    834     NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
    835 
    836     if (NewLoadContext->IsLegacy) {
    837       if (((BBS_BBS_DEVICE_PATH *) NewLoadContext->FilePathList)->DeviceType != DeviceType) {
    838         DeviceType = ((BBS_BBS_DEVICE_PATH *) NewLoadContext->FilePathList)->DeviceType;
    839       } else {
    840         //
    841         // Only show one legacy boot option for the same device type
    842         // assuming the boot options are grouped by the device type
    843         //
    844         continue;
    845       }
    846     }
    847     BmmConfig->DriverOptionOrder[OptionOrderIndex++] = (UINT32) (NewMenuEntry->OptionNumber + 1);
    848   }
    849 }
    850 
    851 /**
    852   Boot the file specified by the input file path info.
    853 
    854   @param FilePath    Point to the file path.
    855 
    856   @retval TRUE   Exit caller function.
    857   @retval FALSE  Not exit caller function.
    858 **/
    859 BOOLEAN
    860 EFIAPI
    861 BootFromFile (
    862   IN EFI_DEVICE_PATH_PROTOCOL    *FilePath
    863   )
    864 {
    865   EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
    866   CHAR16                       *FileName;
    867 
    868   FileName = NULL;
    869 
    870   FileName = ExtractFileNameFromDevicePath(FilePath);
    871   if (FileName != NULL) {
    872     EfiBootManagerInitializeLoadOption (
    873       &BootOption,
    874       0,
    875       LoadOptionTypeBoot,
    876       LOAD_OPTION_ACTIVE,
    877       FileName,
    878       FilePath,
    879       NULL,
    880       0
    881       );
    882     //
    883     // Since current no boot from removable media directly is allowed */
    884     //
    885     gST->ConOut->ClearScreen (gST->ConOut);
    886 
    887     BmmSetConsoleMode (FALSE);
    888     EfiBootManagerBoot (&BootOption);
    889     BmmSetConsoleMode (TRUE);
    890 
    891     FreePool(FileName);
    892 
    893     EfiBootManagerFreeLoadOption (&BootOption);
    894   }
    895 
    896   return FALSE;
    897 }
    898 
    899 /**
    900   Display the form base on the selected file.
    901 
    902   @param FilePath   Point to the file path.
    903   @param FormId     The form need to display.
    904 
    905 **/
    906 BOOLEAN
    907 ReSendForm(
    908   IN  EFI_DEVICE_PATH_PROTOCOL  *FilePath,
    909   IN  EFI_FORM_ID               FormId
    910   )
    911 {
    912   gBootMaintenancePrivate.LoadContext->FilePathList = FilePath;
    913 
    914   UpdateOptionPage(&gBootMaintenancePrivate, FormId, FilePath);
    915 
    916   gBootMaintenancePrivate.FormBrowser2->SendForm (
    917                          gBootMaintenancePrivate.FormBrowser2,
    918                          &gBootMaintenancePrivate.BmmHiiHandle,
    919                          1,
    920                          &mBootMaintGuid,
    921                          FormId,
    922                          NULL,
    923                          NULL
    924                          );
    925   return TRUE;
    926 }
    927 
    928 /**
    929   Create boot option base on the input file path info.
    930 
    931   @param FilePath    Point to the file path.
    932 
    933   @retval TRUE   Exit caller function.
    934   @retval FALSE  Not exit caller function.
    935 **/
    936 BOOLEAN
    937 EFIAPI
    938 CreateBootOptionFromFile (
    939   IN EFI_DEVICE_PATH_PROTOCOL    *FilePath
    940   )
    941 {
    942   return ReSendForm(FilePath, FORM_BOOT_ADD_ID);
    943 }
    944 
    945 /**
    946   Create driver option base on the input file path info.
    947 
    948   @param FilePath    Point to the file path.
    949 
    950   @retval TRUE   Exit caller function.
    951   @retval FALSE  Not exit caller function.
    952 
    953 **/
    954 BOOLEAN
    955 EFIAPI
    956 CreateDriverOptionFromFile (
    957   IN EFI_DEVICE_PATH_PROTOCOL    *FilePath
    958   )
    959 {
    960   return ReSendForm(FilePath, FORM_DRV_ADD_FILE_ID);
    961 }
    962 
    963