Home | History | Annotate | Download | only in BootMaint
      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 - 2015, 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 "BootMaint.h"
     20 #include "BBSsupport.h"
     21 
     22 /**
     23   Create a menu entry by given menu type.
     24 
     25   @param MenuType        The Menu type to be created.
     26 
     27   @retval NULL           If failed to create the menu.
     28   @return the new menu entry.
     29 
     30 **/
     31 BM_MENU_ENTRY *
     32 BOpt_CreateMenuEntry (
     33   UINTN           MenuType
     34   )
     35 {
     36   BM_MENU_ENTRY *MenuEntry;
     37   UINTN         ContextSize;
     38 
     39   //
     40   // Get context size according to menu type
     41   //
     42   switch (MenuType) {
     43   case BM_LOAD_CONTEXT_SELECT:
     44     ContextSize = sizeof (BM_LOAD_CONTEXT);
     45     break;
     46 
     47   case BM_FILE_CONTEXT_SELECT:
     48     ContextSize = sizeof (BM_FILE_CONTEXT);
     49     break;
     50 
     51   case BM_CONSOLE_CONTEXT_SELECT:
     52     ContextSize = sizeof (BM_CONSOLE_CONTEXT);
     53     break;
     54 
     55   case BM_TERMINAL_CONTEXT_SELECT:
     56     ContextSize = sizeof (BM_TERMINAL_CONTEXT);
     57     break;
     58 
     59   case BM_HANDLE_CONTEXT_SELECT:
     60     ContextSize = sizeof (BM_HANDLE_CONTEXT);
     61     break;
     62 
     63   case BM_LEGACY_DEV_CONTEXT_SELECT:
     64     ContextSize = sizeof (BM_LEGACY_DEVICE_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   BM_LEGACY_DEVICE_CONTEXT  *LegacyDevContext;
    112 
    113   //
    114   //  Select by the type in Menu entry for current context type
    115   //
    116   switch (MenuEntry->ContextSelection) {
    117   case BM_LOAD_CONTEXT_SELECT:
    118     LoadContext = (BM_LOAD_CONTEXT *) MenuEntry->VariableContext;
    119     FreePool (LoadContext->FilePathList);
    120     FreePool (LoadContext->LoadOption);
    121     if (LoadContext->OptionalData != NULL) {
    122       FreePool (LoadContext->OptionalData);
    123     }
    124     FreePool (LoadContext);
    125     break;
    126 
    127   case BM_FILE_CONTEXT_SELECT:
    128     FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;
    129 
    130     if (!FileContext->IsRoot) {
    131       FreePool (FileContext->DevicePath);
    132     } else {
    133       if (FileContext->FHandle != NULL) {
    134         FileContext->FHandle->Close (FileContext->FHandle);
    135       }
    136     }
    137 
    138     if (FileContext->FileName != NULL) {
    139       FreePool (FileContext->FileName);
    140     }
    141     if (FileContext->Info != NULL) {
    142       FreePool (FileContext->Info);
    143     }
    144     FreePool (FileContext);
    145     break;
    146 
    147   case BM_CONSOLE_CONTEXT_SELECT:
    148     ConsoleContext = (BM_CONSOLE_CONTEXT *) MenuEntry->VariableContext;
    149     FreePool (ConsoleContext->DevicePath);
    150     FreePool (ConsoleContext);
    151     break;
    152 
    153   case BM_TERMINAL_CONTEXT_SELECT:
    154     TerminalContext = (BM_TERMINAL_CONTEXT *) MenuEntry->VariableContext;
    155     FreePool (TerminalContext->DevicePath);
    156     FreePool (TerminalContext);
    157     break;
    158 
    159   case BM_HANDLE_CONTEXT_SELECT:
    160     HandleContext = (BM_HANDLE_CONTEXT *) MenuEntry->VariableContext;
    161     FreePool (HandleContext);
    162     break;
    163 
    164   case BM_LEGACY_DEV_CONTEXT_SELECT:
    165     LegacyDevContext = (BM_LEGACY_DEVICE_CONTEXT *) MenuEntry->VariableContext;
    166     FreePool (LegacyDevContext);
    167 
    168   default:
    169     break;
    170   }
    171 
    172   FreePool (MenuEntry->DisplayString);
    173   if (MenuEntry->HelpString != NULL) {
    174     FreePool (MenuEntry->HelpString);
    175   }
    176 
    177   FreePool (MenuEntry);
    178 }
    179 
    180 /**
    181   Get the Menu Entry from the list in Menu Entry List.
    182 
    183   If MenuNumber is great or equal to the number of Menu
    184   Entry in the list, then ASSERT.
    185 
    186   @param MenuOption      The Menu Entry List to read the menu entry.
    187   @param MenuNumber      The index of Menu Entry.
    188 
    189   @return The Menu Entry.
    190 
    191 **/
    192 BM_MENU_ENTRY *
    193 BOpt_GetMenuEntry (
    194   BM_MENU_OPTION      *MenuOption,
    195   UINTN               MenuNumber
    196   )
    197 {
    198   BM_MENU_ENTRY   *NewMenuEntry;
    199   UINTN           Index;
    200   LIST_ENTRY      *List;
    201 
    202   ASSERT (MenuNumber < MenuOption->MenuNumber);
    203 
    204   List = MenuOption->Head.ForwardLink;
    205   for (Index = 0; Index < MenuNumber; Index++) {
    206     List = List->ForwardLink;
    207   }
    208 
    209   NewMenuEntry = CR (List, BM_MENU_ENTRY, Link, BM_MENU_ENTRY_SIGNATURE);
    210 
    211   return NewMenuEntry;
    212 }
    213 
    214 /**
    215   This function build the FsOptionMenu list which records all
    216   available file system in the system. They includes all instances
    217   of EFI_SIMPLE_FILE_SYSTEM_PROTOCOL, all instances of EFI_LOAD_FILE_SYSTEM
    218   and all type of legacy boot device.
    219 
    220   @param CallbackData    BMM context data
    221 
    222   @retval  EFI_SUCCESS             Success find the file system
    223   @retval  EFI_OUT_OF_RESOURCES    Can not create menu entry
    224 
    225 **/
    226 EFI_STATUS
    227 BOpt_FindFileSystem (
    228   IN BMM_CALLBACK_DATA          *CallbackData
    229   )
    230 {
    231   UINTN                     NoBlkIoHandles;
    232   UINTN                     NoSimpleFsHandles;
    233   UINTN                     NoLoadFileHandles;
    234   EFI_HANDLE                *BlkIoHandle;
    235   EFI_HANDLE                *SimpleFsHandle;
    236   EFI_HANDLE                *LoadFileHandle;
    237   UINT16                    *VolumeLabel;
    238   EFI_BLOCK_IO_PROTOCOL     *BlkIo;
    239   UINTN                     Index;
    240   EFI_STATUS                Status;
    241   BM_MENU_ENTRY             *MenuEntry;
    242   BM_FILE_CONTEXT           *FileContext;
    243   UINT16                    *TempStr;
    244   UINTN                     OptionNumber;
    245   VOID                      *Buffer;
    246   EFI_LEGACY_BIOS_PROTOCOL  *LegacyBios;
    247   UINT16                    DeviceType;
    248   BBS_BBS_DEVICE_PATH       BbsDevicePathNode;
    249   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
    250   BOOLEAN                   RemovableMedia;
    251 
    252 
    253   NoSimpleFsHandles = 0;
    254   NoLoadFileHandles = 0;
    255   OptionNumber      = 0;
    256   InitializeListHead (&FsOptionMenu.Head);
    257 
    258   //
    259   // Locate Handles that support BlockIo protocol
    260   //
    261   Status = gBS->LocateHandleBuffer (
    262                   ByProtocol,
    263                   &gEfiBlockIoProtocolGuid,
    264                   NULL,
    265                   &NoBlkIoHandles,
    266                   &BlkIoHandle
    267                   );
    268   if (!EFI_ERROR (Status)) {
    269 
    270     for (Index = 0; Index < NoBlkIoHandles; Index++) {
    271       Status = gBS->HandleProtocol (
    272                       BlkIoHandle[Index],
    273                       &gEfiBlockIoProtocolGuid,
    274                       (VOID **) &BlkIo
    275                       );
    276 
    277       if (EFI_ERROR (Status)) {
    278         continue;
    279       }
    280 
    281       //
    282       // Issue a dummy read to trigger reinstall of BlockIo protocol for removable media
    283       //
    284       if (BlkIo->Media->RemovableMedia) {
    285         Buffer = AllocateZeroPool (BlkIo->Media->BlockSize);
    286         if (NULL == Buffer) {
    287           FreePool (BlkIoHandle);
    288           return EFI_OUT_OF_RESOURCES;
    289         }
    290 
    291         BlkIo->ReadBlocks (
    292                 BlkIo,
    293                 BlkIo->Media->MediaId,
    294                 0,
    295                 BlkIo->Media->BlockSize,
    296                 Buffer
    297                 );
    298         FreePool (Buffer);
    299       }
    300     }
    301     FreePool (BlkIoHandle);
    302   }
    303 
    304   //
    305   // Locate Handles that support Simple File System protocol
    306   //
    307   Status = gBS->LocateHandleBuffer (
    308                   ByProtocol,
    309                   &gEfiSimpleFileSystemProtocolGuid,
    310                   NULL,
    311                   &NoSimpleFsHandles,
    312                   &SimpleFsHandle
    313                   );
    314   if (!EFI_ERROR (Status)) {
    315     //
    316     // Find all the instances of the File System prototocol
    317     //
    318     for (Index = 0; Index < NoSimpleFsHandles; Index++) {
    319       Status = gBS->HandleProtocol (
    320                       SimpleFsHandle[Index],
    321                       &gEfiBlockIoProtocolGuid,
    322                       (VOID **) &BlkIo
    323                       );
    324       if (EFI_ERROR (Status)) {
    325         //
    326         // If no block IO exists assume it's NOT a removable media
    327         //
    328         RemovableMedia = FALSE;
    329       } else {
    330         //
    331         // If block IO exists check to see if it's remobable media
    332         //
    333         RemovableMedia = BlkIo->Media->RemovableMedia;
    334       }
    335 
    336       //
    337       // Allocate pool for this load option
    338       //
    339       MenuEntry = BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT);
    340       if (NULL == MenuEntry) {
    341         FreePool (SimpleFsHandle);
    342         return EFI_OUT_OF_RESOURCES;
    343       }
    344 
    345       FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;
    346 
    347       FileContext->Handle     = SimpleFsHandle[Index];
    348       MenuEntry->OptionNumber = Index;
    349       FileContext->FHandle    = EfiLibOpenRoot (FileContext->Handle);
    350       if (FileContext->FHandle == NULL) {
    351         BOpt_DestroyMenuEntry (MenuEntry);
    352         continue;
    353       }
    354 
    355       MenuEntry->HelpString = DevicePathToStr (DevicePathFromHandle (FileContext->Handle));
    356       FileContext->Info = EfiLibFileSystemVolumeLabelInfo (FileContext->FHandle);
    357       FileContext->FileName = EfiStrDuplicate (L"\\");
    358       FileContext->DevicePath = FileDevicePath (
    359                                   FileContext->Handle,
    360                                   FileContext->FileName
    361                                   );
    362       FileContext->IsDir            = TRUE;
    363       FileContext->IsRoot           = TRUE;
    364       FileContext->IsRemovableMedia = RemovableMedia;
    365       FileContext->IsLoadFile       = FALSE;
    366 
    367       //
    368       // Get current file system's Volume Label
    369       //
    370       if (FileContext->Info == NULL) {
    371         VolumeLabel = L"NO FILE SYSTEM INFO";
    372       } else {
    373         VolumeLabel = FileContext->Info->VolumeLabel;
    374         if (*VolumeLabel == 0x0000) {
    375           VolumeLabel = L"NO VOLUME LABEL";
    376         }
    377       }
    378 
    379       TempStr                   = MenuEntry->HelpString;
    380       MenuEntry->DisplayString  = AllocateZeroPool (MAX_CHAR);
    381       ASSERT (MenuEntry->DisplayString != NULL);
    382       UnicodeSPrint (
    383         MenuEntry->DisplayString,
    384         MAX_CHAR,
    385         L"%s, [%s]",
    386         VolumeLabel,
    387         TempStr
    388         );
    389       OptionNumber++;
    390       InsertTailList (&FsOptionMenu.Head, &MenuEntry->Link);
    391     }
    392   }
    393 
    394   if (NoSimpleFsHandles != 0) {
    395     FreePool (SimpleFsHandle);
    396   }
    397   //
    398   // Searching for handles that support Load File protocol
    399   //
    400   Status = gBS->LocateHandleBuffer (
    401                   ByProtocol,
    402                   &gEfiLoadFileProtocolGuid,
    403                   NULL,
    404                   &NoLoadFileHandles,
    405                   &LoadFileHandle
    406                   );
    407 
    408   if (!EFI_ERROR (Status)) {
    409     for (Index = 0; Index < NoLoadFileHandles; Index++) {
    410       MenuEntry = BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT);
    411       if (NULL == MenuEntry) {
    412         FreePool (LoadFileHandle);
    413         return EFI_OUT_OF_RESOURCES;
    414       }
    415 
    416       FileContext                   = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;
    417       FileContext->IsRemovableMedia = FALSE;
    418       FileContext->IsLoadFile       = TRUE;
    419       FileContext->Handle           = LoadFileHandle[Index];
    420       FileContext->IsRoot           = TRUE;
    421 
    422       FileContext->DevicePath       = DevicePathFromHandle (FileContext->Handle);
    423       FileContext->FileName         = DevicePathToStr (FileContext->DevicePath);
    424 
    425       MenuEntry->HelpString     = DevicePathToStr (FileContext->DevicePath);
    426 
    427       TempStr                   = MenuEntry->HelpString;
    428       MenuEntry->DisplayString  = AllocateZeroPool (MAX_CHAR);
    429       ASSERT (MenuEntry->DisplayString != NULL);
    430       UnicodeSPrint (
    431         MenuEntry->DisplayString,
    432         MAX_CHAR,
    433         L"Load File [%s]",
    434         TempStr
    435         );
    436 
    437       MenuEntry->OptionNumber = OptionNumber;
    438       OptionNumber++;
    439       InsertTailList (&FsOptionMenu.Head, &MenuEntry->Link);
    440     }
    441   }
    442 
    443   if (NoLoadFileHandles != 0) {
    444     FreePool (LoadFileHandle);
    445   }
    446 
    447   //
    448   // Add Legacy Boot Option Support Here
    449   //
    450   Status = gBS->LocateProtocol (
    451                   &gEfiLegacyBiosProtocolGuid,
    452                   NULL,
    453                   (VOID **) &LegacyBios
    454                   );
    455   if (!EFI_ERROR (Status)) {
    456 
    457     for (Index = BBS_TYPE_FLOPPY; Index <= BBS_TYPE_EMBEDDED_NETWORK; Index++) {
    458       MenuEntry = BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT);
    459       if (NULL == MenuEntry) {
    460         return EFI_OUT_OF_RESOURCES;
    461       }
    462 
    463       FileContext                       = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;
    464 
    465       FileContext->IsRemovableMedia     = FALSE;
    466       FileContext->IsLoadFile           = TRUE;
    467       FileContext->IsBootLegacy         = TRUE;
    468       DeviceType                        = (UINT16) Index;
    469       BbsDevicePathNode.Header.Type     = BBS_DEVICE_PATH;
    470       BbsDevicePathNode.Header.SubType  = BBS_BBS_DP;
    471       SetDevicePathNodeLength (
    472         &BbsDevicePathNode.Header,
    473         sizeof (BBS_BBS_DEVICE_PATH)
    474         );
    475       BbsDevicePathNode.DeviceType  = DeviceType;
    476       BbsDevicePathNode.StatusFlag  = 0;
    477       BbsDevicePathNode.String[0]   = 0;
    478       DevicePath = AppendDevicePathNode (
    479                     EndDevicePath,
    480                     (EFI_DEVICE_PATH_PROTOCOL *) &BbsDevicePathNode
    481                     );
    482 
    483       FileContext->DevicePath   = DevicePath;
    484       MenuEntry->HelpString     = DevicePathToStr (FileContext->DevicePath);
    485 
    486       TempStr                   = MenuEntry->HelpString;
    487       MenuEntry->DisplayString  = AllocateZeroPool (MAX_CHAR);
    488       ASSERT (MenuEntry->DisplayString != NULL);
    489       UnicodeSPrint (
    490         MenuEntry->DisplayString,
    491         MAX_CHAR,
    492         L"Boot Legacy [%s]",
    493         TempStr
    494         );
    495       MenuEntry->OptionNumber = OptionNumber;
    496       OptionNumber++;
    497       InsertTailList (&FsOptionMenu.Head, &MenuEntry->Link);
    498     }
    499   }
    500   //
    501   // Remember how many file system options are here
    502   //
    503   FsOptionMenu.MenuNumber = OptionNumber;
    504   return EFI_SUCCESS;
    505 }
    506 
    507 /**
    508   Free resources allocated in Allocate Rountine.
    509 
    510   @param FreeMenu        Menu to be freed
    511 **/
    512 VOID
    513 BOpt_FreeMenu (
    514   BM_MENU_OPTION        *FreeMenu
    515   )
    516 {
    517   BM_MENU_ENTRY *MenuEntry;
    518   while (!IsListEmpty (&FreeMenu->Head)) {
    519     MenuEntry = CR (
    520                   FreeMenu->Head.ForwardLink,
    521                   BM_MENU_ENTRY,
    522                   Link,
    523                   BM_MENU_ENTRY_SIGNATURE
    524                   );
    525     RemoveEntryList (&MenuEntry->Link);
    526     BOpt_DestroyMenuEntry (MenuEntry);
    527   }
    528   FreeMenu->MenuNumber = 0;
    529 }
    530 
    531 /**
    532   Find files under current directory
    533   All files and sub-directories in current directory
    534   will be stored in DirectoryMenu for future use.
    535 
    536   @param CallbackData  The BMM context data.
    537   @param MenuEntry     The Menu Entry.
    538 
    539   @retval EFI_SUCCESS         Get files from current dir successfully.
    540   @return Other value if can't get files from current dir.
    541 
    542 **/
    543 EFI_STATUS
    544 BOpt_FindFiles (
    545   IN BMM_CALLBACK_DATA          *CallbackData,
    546   IN BM_MENU_ENTRY              *MenuEntry
    547   )
    548 {
    549   EFI_FILE_HANDLE NewDir;
    550   EFI_FILE_HANDLE Dir;
    551   EFI_FILE_INFO   *DirInfo;
    552   UINTN           BufferSize;
    553   UINTN           DirBufferSize;
    554   BM_MENU_ENTRY   *NewMenuEntry;
    555   BM_FILE_CONTEXT *FileContext;
    556   BM_FILE_CONTEXT *NewFileContext;
    557   UINTN           Pass;
    558   EFI_STATUS      Status;
    559   UINTN           OptionNumber;
    560 
    561   FileContext   = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;
    562   Dir           = FileContext->FHandle;
    563   OptionNumber  = 0;
    564   //
    565   // Open current directory to get files from it
    566   //
    567   Status = Dir->Open (
    568                   Dir,
    569                   &NewDir,
    570                   FileContext->FileName,
    571                   EFI_FILE_READ_ONLY,
    572                   0
    573                   );
    574   if (!FileContext->IsRoot) {
    575     Dir->Close (Dir);
    576   }
    577 
    578   if (EFI_ERROR (Status)) {
    579     return Status;
    580   }
    581 
    582   DirInfo = EfiLibFileInfo (NewDir);
    583   if (DirInfo == NULL) {
    584     return EFI_NOT_FOUND;
    585   }
    586 
    587   if ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == 0) {
    588     return EFI_INVALID_PARAMETER;
    589   }
    590 
    591   FileContext->DevicePath = FileDevicePath (
    592                               FileContext->Handle,
    593                               FileContext->FileName
    594                               );
    595 
    596   DirBufferSize = sizeof (EFI_FILE_INFO) + 1024;
    597   DirInfo       = AllocateZeroPool (DirBufferSize);
    598   if (DirInfo == NULL) {
    599     return EFI_OUT_OF_RESOURCES;
    600   }
    601   //
    602   // Get all files in current directory
    603   // Pass 1 to get Directories
    604   // Pass 2 to get files that are EFI images
    605   //
    606   for (Pass = 1; Pass <= 2; Pass++) {
    607     NewDir->SetPosition (NewDir, 0);
    608     for (;;) {
    609       BufferSize  = DirBufferSize;
    610       Status      = NewDir->Read (NewDir, &BufferSize, DirInfo);
    611       if (EFI_ERROR (Status) || BufferSize == 0) {
    612         break;
    613       }
    614 
    615       if (((DirInfo->Attribute & EFI_FILE_DIRECTORY) != 0 && Pass == 2) ||
    616           ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == 0 && Pass == 1)
    617           ) {
    618         //
    619         // Pass 1 is for Directories
    620         // Pass 2 is for file names
    621         //
    622         continue;
    623       }
    624 
    625       if (!(BOpt_IsEfiImageName (DirInfo->FileName) || (DirInfo->Attribute & EFI_FILE_DIRECTORY) != 0)) {
    626         //
    627         // Slip file unless it is a directory entry or a .EFI file
    628         //
    629         continue;
    630       }
    631 
    632       NewMenuEntry = BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT);
    633       if (NULL == NewMenuEntry) {
    634         return EFI_OUT_OF_RESOURCES;
    635       }
    636 
    637       NewFileContext          = (BM_FILE_CONTEXT *) NewMenuEntry->VariableContext;
    638       NewFileContext->Handle  = FileContext->Handle;
    639       NewFileContext->FileName = BOpt_AppendFileName (
    640                                   FileContext->FileName,
    641                                   DirInfo->FileName
    642                                   );
    643       NewFileContext->FHandle = NewDir;
    644       NewFileContext->DevicePath = FileDevicePath (
    645                                     NewFileContext->Handle,
    646                                     NewFileContext->FileName
    647                                     );
    648       NewMenuEntry->HelpString = NULL;
    649 
    650       MenuEntry->DisplayStringToken = GetStringTokenFromDepository (
    651                                         CallbackData,
    652                                         FileOptionStrDepository
    653                                         );
    654 
    655       NewFileContext->IsDir = (BOOLEAN) ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY);
    656 
    657       if (NewFileContext->IsDir) {
    658         BufferSize                  = StrLen (DirInfo->FileName) * 2 + 6;
    659         NewMenuEntry->DisplayString = AllocateZeroPool (BufferSize);
    660 
    661         UnicodeSPrint (
    662           NewMenuEntry->DisplayString,
    663           BufferSize,
    664           L"<%s>",
    665           DirInfo->FileName
    666           );
    667 
    668       } else {
    669         NewMenuEntry->DisplayString = EfiStrDuplicate (DirInfo->FileName);
    670       }
    671 
    672       NewFileContext->IsRoot            = FALSE;
    673       NewFileContext->IsLoadFile        = FALSE;
    674       NewFileContext->IsRemovableMedia  = FALSE;
    675 
    676       NewMenuEntry->OptionNumber        = OptionNumber;
    677       OptionNumber++;
    678       InsertTailList (&DirectoryMenu.Head, &NewMenuEntry->Link);
    679     }
    680   }
    681 
    682   DirectoryMenu.MenuNumber = OptionNumber;
    683   FreePool (DirInfo);
    684   return EFI_SUCCESS;
    685 }
    686 
    687 /**
    688   Build the LegacyFDMenu LegacyHDMenu LegacyCDMenu according to LegacyBios.GetBbsInfo().
    689 
    690   @retval EFI_SUCCESS The function complete successfully.
    691   @retval EFI_OUT_OF_RESOURCES No enough memory to complete this function.
    692 
    693 **/
    694 EFI_STATUS
    695 BOpt_GetLegacyOptions (
    696   VOID
    697   )
    698 {
    699   BM_MENU_ENTRY             *NewMenuEntry;
    700   BM_LEGACY_DEVICE_CONTEXT  *NewLegacyDevContext;
    701   EFI_STATUS                Status;
    702   EFI_LEGACY_BIOS_PROTOCOL  *LegacyBios;
    703   UINT16                    HddCount;
    704   HDD_INFO                  *HddInfo;
    705   UINT16                    BbsCount;
    706   BBS_TABLE                 *BbsTable;
    707   UINT16                    Index;
    708   CHAR16                    DescString[100];
    709   UINTN                     FDNum;
    710   UINTN                     HDNum;
    711   UINTN                     CDNum;
    712   UINTN                     NETNum;
    713   UINTN                     BEVNum;
    714 
    715   NewMenuEntry  = NULL;
    716   HddInfo       = NULL;
    717   BbsTable      = NULL;
    718   BbsCount      = 0;
    719 
    720   //
    721   // Initialize Bbs Table Context from BBS info data
    722   //
    723   InitializeListHead (&LegacyFDMenu.Head);
    724   InitializeListHead (&LegacyHDMenu.Head);
    725   InitializeListHead (&LegacyCDMenu.Head);
    726   InitializeListHead (&LegacyNETMenu.Head);
    727   InitializeListHead (&LegacyBEVMenu.Head);
    728 
    729   Status = gBS->LocateProtocol (
    730                   &gEfiLegacyBiosProtocolGuid,
    731                   NULL,
    732                   (VOID **) &LegacyBios
    733                   );
    734   if (!EFI_ERROR (Status)) {
    735     Status = LegacyBios->GetBbsInfo (
    736                           LegacyBios,
    737                           &HddCount,
    738                           &HddInfo,
    739                           &BbsCount,
    740                           &BbsTable
    741                           );
    742     if (EFI_ERROR (Status)) {
    743       return Status;
    744     }
    745   }
    746 
    747   FDNum   = 0;
    748   HDNum   = 0;
    749   CDNum   = 0;
    750   NETNum  = 0;
    751   BEVNum  = 0;
    752 
    753   for (Index = 0; Index < BbsCount; Index++) {
    754     if ((BBS_IGNORE_ENTRY == BbsTable[Index].BootPriority) ||
    755         (BBS_DO_NOT_BOOT_FROM == BbsTable[Index].BootPriority)
    756         ) {
    757       continue;
    758     }
    759 
    760     NewMenuEntry = BOpt_CreateMenuEntry (BM_LEGACY_DEV_CONTEXT_SELECT);
    761     if (NULL == NewMenuEntry) {
    762       break;
    763     }
    764 
    765     NewLegacyDevContext           = (BM_LEGACY_DEVICE_CONTEXT *) NewMenuEntry->VariableContext;
    766     NewLegacyDevContext->BbsEntry = &BbsTable[Index];
    767     NewLegacyDevContext->BbsIndex = Index;
    768     NewLegacyDevContext->BbsCount = BbsCount;
    769     BdsBuildLegacyDevNameString (
    770       &BbsTable[Index],
    771       Index,
    772       sizeof (DescString),
    773       DescString
    774       );
    775     NewLegacyDevContext->Description = AllocateCopyPool (StrSize (DescString), DescString);
    776     if (NULL == NewLegacyDevContext->Description) {
    777       break;
    778     }
    779 
    780     NewMenuEntry->DisplayString = NewLegacyDevContext->Description;
    781     NewMenuEntry->HelpString    = NULL;
    782 
    783     switch (BbsTable[Index].DeviceType) {
    784     case BBS_FLOPPY:
    785       InsertTailList (&LegacyFDMenu.Head, &NewMenuEntry->Link);
    786       FDNum++;
    787       break;
    788 
    789     case BBS_HARDDISK:
    790       InsertTailList (&LegacyHDMenu.Head, &NewMenuEntry->Link);
    791       HDNum++;
    792       break;
    793 
    794     case BBS_CDROM:
    795       InsertTailList (&LegacyCDMenu.Head, &NewMenuEntry->Link);
    796       CDNum++;
    797       break;
    798 
    799     case BBS_EMBED_NETWORK:
    800       InsertTailList (&LegacyNETMenu.Head, &NewMenuEntry->Link);
    801       NETNum++;
    802       break;
    803 
    804     case BBS_BEV_DEVICE:
    805       InsertTailList (&LegacyBEVMenu.Head, &NewMenuEntry->Link);
    806       BEVNum++;
    807       break;
    808     }
    809   }
    810 
    811   if (Index != BbsCount) {
    812     BOpt_FreeLegacyOptions ();
    813     return EFI_OUT_OF_RESOURCES;
    814   }
    815 
    816   LegacyFDMenu.MenuNumber   = FDNum;
    817   LegacyHDMenu.MenuNumber   = HDNum;
    818   LegacyCDMenu.MenuNumber   = CDNum;
    819   LegacyNETMenu.MenuNumber  = NETNum;
    820   LegacyBEVMenu.MenuNumber  = BEVNum;
    821   return EFI_SUCCESS;
    822 }
    823 
    824 /**
    825   Free out resouce allocated from Legacy Boot Options.
    826 
    827 **/
    828 VOID
    829 BOpt_FreeLegacyOptions (
    830   VOID
    831   )
    832 {
    833   BOpt_FreeMenu (&LegacyFDMenu);
    834   BOpt_FreeMenu (&LegacyHDMenu);
    835   BOpt_FreeMenu (&LegacyCDMenu);
    836   BOpt_FreeMenu (&LegacyNETMenu);
    837   BOpt_FreeMenu (&LegacyBEVMenu);
    838 }
    839 
    840 /**
    841 
    842   Build the BootOptionMenu according to BootOrder Variable.
    843   This Routine will access the Boot#### to get EFI_LOAD_OPTION.
    844 
    845   @param CallbackData The BMM context data.
    846 
    847   @return EFI_NOT_FOUND Fail to find "BootOrder" variable.
    848   @return EFI_SUCESS    Success build boot option menu.
    849 
    850 **/
    851 EFI_STATUS
    852 BOpt_GetBootOptions (
    853   IN  BMM_CALLBACK_DATA         *CallbackData
    854   )
    855 {
    856   UINTN                     Index;
    857   UINT16                    BootString[10];
    858   UINT8                     *LoadOptionFromVar;
    859   UINT8                     *LoadOption;
    860   UINTN                     BootOptionSize;
    861   BOOLEAN                   BootNextFlag;
    862   UINT16                    *BootOrderList;
    863   UINTN                     BootOrderListSize;
    864   UINT16                    *BootNext;
    865   UINTN                     BootNextSize;
    866   BM_MENU_ENTRY             *NewMenuEntry;
    867   BM_LOAD_CONTEXT           *NewLoadContext;
    868   UINT8                     *LoadOptionPtr;
    869   UINTN                     StringSize;
    870   UINTN                     OptionalDataSize;
    871   UINT8                     *LoadOptionEnd;
    872   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
    873   UINTN                     MenuCount;
    874   UINT8                     *Ptr;
    875 
    876   MenuCount         = 0;
    877   BootOrderListSize = 0;
    878   BootNextSize      = 0;
    879   BootOrderList     = NULL;
    880   BootNext          = NULL;
    881   LoadOptionFromVar = NULL;
    882   BOpt_FreeMenu (&BootOptionMenu);
    883   InitializeListHead (&BootOptionMenu.Head);
    884 
    885   //
    886   // Get the BootOrder from the Var
    887   //
    888   BootOrderList = BdsLibGetVariableAndSize (
    889                     L"BootOrder",
    890                     &gEfiGlobalVariableGuid,
    891                     &BootOrderListSize
    892                     );
    893   if (BootOrderList == NULL) {
    894     return EFI_NOT_FOUND;
    895   }
    896 
    897   //
    898   // Get the BootNext from the Var
    899   //
    900   BootNext = BdsLibGetVariableAndSize (
    901               L"BootNext",
    902               &gEfiGlobalVariableGuid,
    903               &BootNextSize
    904               );
    905 
    906   if (BootNext != NULL) {
    907     if (BootNextSize != sizeof (UINT16)) {
    908       FreePool (BootNext);
    909       BootNext = NULL;
    910     }
    911   }
    912 
    913   for (Index = 0; Index < BootOrderListSize / sizeof (UINT16); Index++) {
    914     UnicodeSPrint (BootString, sizeof (BootString), L"Boot%04x", BootOrderList[Index]);
    915     //
    916     //  Get all loadoptions from the VAR
    917     //
    918     LoadOptionFromVar = BdsLibGetVariableAndSize (
    919                           BootString,
    920                           &gEfiGlobalVariableGuid,
    921                           &BootOptionSize
    922                           );
    923     if (LoadOptionFromVar == NULL) {
    924       continue;
    925     }
    926 
    927     LoadOption = AllocateZeroPool (BootOptionSize);
    928     if (LoadOption == NULL) {
    929       continue;
    930     }
    931 
    932     CopyMem (LoadOption, LoadOptionFromVar, BootOptionSize);
    933     FreePool (LoadOptionFromVar);
    934 
    935     if (BootNext != NULL) {
    936       BootNextFlag = (BOOLEAN) (*BootNext == BootOrderList[Index]);
    937     } else {
    938       BootNextFlag = FALSE;
    939     }
    940 
    941     if (0 == (*((UINT32 *) LoadOption) & LOAD_OPTION_ACTIVE)) {
    942       FreePool (LoadOption);
    943       continue;
    944     }
    945     //
    946     // BUGBUG: could not return EFI_OUT_OF_RESOURCES here directly.
    947     // the buffer allocated already should be freed before returning.
    948     //
    949     NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);
    950     if (NULL == NewMenuEntry) {
    951       return EFI_OUT_OF_RESOURCES;
    952     }
    953 
    954     NewLoadContext                      = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
    955 
    956     LoadOptionPtr                       = LoadOption;
    957     LoadOptionEnd                       = LoadOption + BootOptionSize;
    958 
    959     NewMenuEntry->OptionNumber          = BootOrderList[Index];
    960     NewLoadContext->LoadOptionModified  = FALSE;
    961     NewLoadContext->Deleted             = FALSE;
    962     NewLoadContext->IsBootNext          = BootNextFlag;
    963 
    964     //
    965     // Is a Legacy Device?
    966     //
    967     Ptr = (UINT8 *) LoadOption;
    968 
    969     //
    970     // Attribute = *(UINT32 *)Ptr;
    971     //
    972     Ptr += sizeof (UINT32);
    973 
    974     //
    975     // FilePathSize = *(UINT16 *)Ptr;
    976     //
    977     Ptr += sizeof (UINT16);
    978 
    979     //
    980     // Description = (CHAR16 *)Ptr;
    981     //
    982     Ptr += StrSize ((CHAR16 *) Ptr);
    983 
    984     //
    985     // Now Ptr point to Device Path
    986     //
    987     DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr;
    988     if ((BBS_DEVICE_PATH == DevicePath->Type) && (BBS_BBS_DP == DevicePath->SubType)) {
    989       NewLoadContext->IsLegacy = TRUE;
    990     } else {
    991       NewLoadContext->IsLegacy = FALSE;
    992     }
    993     //
    994     // LoadOption is a pointer type of UINT8
    995     // for easy use with following LOAD_OPTION
    996     // embedded in this struct
    997     //
    998     NewLoadContext->LoadOption      = LoadOption;
    999     NewLoadContext->LoadOptionSize  = BootOptionSize;
   1000 
   1001     NewLoadContext->Attributes      = *(UINT32 *) LoadOptionPtr;
   1002     NewLoadContext->IsActive        = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_ACTIVE);
   1003 
   1004     NewLoadContext->ForceReconnect  = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_FORCE_RECONNECT);
   1005 
   1006     LoadOptionPtr += sizeof (UINT32);
   1007 
   1008     NewLoadContext->FilePathListLength = *(UINT16 *) LoadOptionPtr;
   1009     LoadOptionPtr += sizeof (UINT16);
   1010 
   1011     StringSize = StrSize((UINT16*)LoadOptionPtr);
   1012 
   1013     NewLoadContext->Description = AllocateCopyPool (StrSize((UINT16*)LoadOptionPtr), LoadOptionPtr);
   1014     ASSERT (NewLoadContext->Description != NULL);
   1015 
   1016     NewMenuEntry->DisplayString = NewLoadContext->Description;
   1017 
   1018     LoadOptionPtr += StringSize;
   1019 
   1020     NewLoadContext->FilePathList = AllocateZeroPool (NewLoadContext->FilePathListLength);
   1021     ASSERT (NewLoadContext->FilePathList != NULL);
   1022     CopyMem (
   1023       NewLoadContext->FilePathList,
   1024       (EFI_DEVICE_PATH_PROTOCOL *) LoadOptionPtr,
   1025       NewLoadContext->FilePathListLength
   1026       );
   1027 
   1028     NewMenuEntry->HelpString = DevicePathToStr (NewLoadContext->FilePathList);
   1029     NewMenuEntry->DisplayStringToken = GetStringTokenFromDepository (
   1030                                         CallbackData,
   1031                                         BootOptionStrDepository
   1032                                         );
   1033     NewMenuEntry->HelpStringToken = GetStringTokenFromDepository (
   1034                                       CallbackData,
   1035                                       BootOptionHelpStrDepository
   1036                                       );
   1037     LoadOptionPtr += NewLoadContext->FilePathListLength;
   1038 
   1039     if (LoadOptionPtr < LoadOptionEnd) {
   1040       OptionalDataSize = BootOptionSize -
   1041         sizeof (UINT32) -
   1042         sizeof (UINT16) -
   1043         StringSize -
   1044         NewLoadContext->FilePathListLength;
   1045 
   1046       NewLoadContext->OptionalData = AllocateZeroPool (OptionalDataSize);
   1047       ASSERT (NewLoadContext->OptionalData != NULL);
   1048       CopyMem (
   1049         NewLoadContext->OptionalData,
   1050         LoadOptionPtr,
   1051         OptionalDataSize
   1052         );
   1053 
   1054       NewLoadContext->OptionalDataSize = OptionalDataSize;
   1055     }
   1056 
   1057     InsertTailList (&BootOptionMenu.Head, &NewMenuEntry->Link);
   1058     MenuCount++;
   1059   }
   1060 
   1061   if (BootNext != NULL) {
   1062     FreePool (BootNext);
   1063   }
   1064   if (BootOrderList != NULL) {
   1065     FreePool (BootOrderList);
   1066   }
   1067   BootOptionMenu.MenuNumber = MenuCount;
   1068   return EFI_SUCCESS;
   1069 }
   1070 
   1071 /**
   1072 
   1073   Append file name to existing file name.
   1074 
   1075   @param Str1  The existing file name
   1076   @param Str2  The file name to be appended
   1077 
   1078   @return Allocate a new string to hold the appended result.
   1079           Caller is responsible to free the returned string.
   1080 
   1081 **/
   1082 CHAR16 *
   1083 BOpt_AppendFileName (
   1084   IN  CHAR16  *Str1,
   1085   IN  CHAR16  *Str2
   1086   )
   1087 {
   1088   UINTN   Size1;
   1089   UINTN   Size2;
   1090   UINTN   MaxLen;
   1091   CHAR16  *Str;
   1092   CHAR16  *TmpStr;
   1093   CHAR16  *Ptr;
   1094   CHAR16  *LastSlash;
   1095 
   1096   Size1 = StrSize (Str1);
   1097   Size2 = StrSize (Str2);
   1098   MaxLen = (Size1 + Size2 + sizeof (CHAR16)) / sizeof (CHAR16);
   1099   Str   = AllocateZeroPool (MaxLen * sizeof (CHAR16));
   1100   ASSERT (Str != NULL);
   1101 
   1102   TmpStr = AllocateZeroPool (MaxLen * sizeof (CHAR16));
   1103   ASSERT (TmpStr != NULL);
   1104 
   1105   StrCatS (Str, MaxLen, Str1);
   1106   if (!((*Str == '\\') && (*(Str + 1) == 0))) {
   1107     StrCatS (Str, MaxLen, L"\\");
   1108   }
   1109 
   1110   StrCatS (Str, MaxLen, Str2);
   1111 
   1112   Ptr       = Str;
   1113   LastSlash = Str;
   1114   while (*Ptr != 0) {
   1115     if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '.' && *(Ptr + 3) == L'\\') {
   1116       //
   1117       // Convert "\Name\..\" to "\"
   1118       // DO NOT convert the .. if it is at the end of the string. This will
   1119       // break the .. behavior in changing directories.
   1120       //
   1121 
   1122       //
   1123       // Use TmpStr as a backup, as StrCpyS in BaseLib does not handle copy of two strings
   1124       // that overlap.
   1125       //
   1126       StrCpyS (TmpStr, MaxLen, Ptr + 3);
   1127       StrCpyS (LastSlash, MaxLen - (UINTN) (LastSlash - Str), TmpStr);
   1128       Ptr = LastSlash;
   1129     } else if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '\\') {
   1130       //
   1131       // Convert a "\.\" to a "\"
   1132       //
   1133 
   1134       //
   1135       // Use TmpStr as a backup, as StrCpyS in BaseLib does not handle copy of two strings
   1136       // that overlap.
   1137       //
   1138       StrCpyS (TmpStr, MaxLen, Ptr + 2);
   1139       StrCpyS (Ptr, MaxLen - (UINTN) (Ptr - Str), TmpStr);
   1140       Ptr = LastSlash;
   1141     } else if (*Ptr == '\\') {
   1142       LastSlash = Ptr;
   1143     }
   1144 
   1145     Ptr++;
   1146   }
   1147 
   1148   FreePool (TmpStr);
   1149 
   1150   return Str;
   1151 }
   1152 
   1153 /**
   1154 
   1155   Check whether current FileName point to a valid
   1156   Efi Image File.
   1157 
   1158   @param FileName  File need to be checked.
   1159 
   1160   @retval TRUE  Is Efi Image
   1161   @retval FALSE Not a valid Efi Image
   1162 
   1163 **/
   1164 BOOLEAN
   1165 BOpt_IsEfiImageName (
   1166   IN UINT16  *FileName
   1167   )
   1168 {
   1169   //
   1170   // Search for ".efi" extension
   1171   //
   1172   while (*FileName != L'\0') {
   1173     if (FileName[0] == '.') {
   1174       if (FileName[1] == 'e' || FileName[1] == 'E') {
   1175         if (FileName[2] == 'f' || FileName[2] == 'F') {
   1176           if (FileName[3] == 'i' || FileName[3] == 'I') {
   1177             return TRUE;
   1178           } else if (FileName[3] == 0x0000) {
   1179             return FALSE;
   1180           }
   1181         } else if (FileName[2] == 0x0000) {
   1182           return FALSE;
   1183         }
   1184       } else if (FileName[1] == 0x0000) {
   1185         return FALSE;
   1186       }
   1187     }
   1188 
   1189     FileName += 1;
   1190   }
   1191 
   1192   return FALSE;
   1193 }
   1194 
   1195 /**
   1196 
   1197   Check whether current FileName point to a valid Efi Application
   1198 
   1199   @param Dir       Pointer to current Directory
   1200   @param FileName  Pointer to current File name.
   1201 
   1202   @retval TRUE      Is a valid Efi Application
   1203   @retval FALSE     not a valid Efi Application
   1204 
   1205 **/
   1206 BOOLEAN
   1207 BOpt_IsEfiApp (
   1208   IN EFI_FILE_HANDLE Dir,
   1209   IN UINT16          *FileName
   1210   )
   1211 {
   1212   UINTN                       BufferSize;
   1213   EFI_IMAGE_DOS_HEADER        DosHdr;
   1214   UINT16                      Subsystem;
   1215   EFI_FILE_HANDLE             File;
   1216   EFI_STATUS                  Status;
   1217   EFI_IMAGE_OPTIONAL_HEADER_UNION PeHdr;
   1218 
   1219   Status = Dir->Open (Dir, &File, FileName, EFI_FILE_MODE_READ, 0);
   1220 
   1221   if (EFI_ERROR (Status)) {
   1222     return FALSE;
   1223   }
   1224 
   1225   BufferSize = sizeof (EFI_IMAGE_DOS_HEADER);
   1226   File->Read (File, &BufferSize, &DosHdr);
   1227   if (DosHdr.e_magic != EFI_IMAGE_DOS_SIGNATURE) {
   1228     File->Close (File);
   1229     return FALSE;
   1230   }
   1231 
   1232   File->SetPosition (File, DosHdr.e_lfanew);
   1233   BufferSize = sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION);
   1234   File->Read (File, &BufferSize, &PeHdr);
   1235   if (PeHdr.Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) {
   1236     File->Close (File);
   1237     return FALSE;
   1238   }
   1239   //
   1240   // Determine PE type and read subsytem
   1241   //
   1242   if (PeHdr.Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
   1243     Subsystem = PeHdr.Pe32.OptionalHeader.Subsystem;
   1244   } else if (PeHdr.Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
   1245     Subsystem = PeHdr.Pe32Plus.OptionalHeader.Subsystem;
   1246   } else {
   1247     return FALSE;
   1248   }
   1249 
   1250   if (Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {
   1251     File->Close (File);
   1252     return TRUE;
   1253   } else {
   1254     File->Close (File);
   1255     return FALSE;
   1256   }
   1257 }
   1258 
   1259 /**
   1260 
   1261   Find drivers that will be added as Driver#### variables from handles
   1262   in current system environment
   1263   All valid handles in the system except those consume SimpleFs, LoadFile
   1264   are stored in DriverMenu for future use.
   1265 
   1266   @retval EFI_SUCCESS The function complets successfully.
   1267   @return Other value if failed to build the DriverMenu.
   1268 
   1269 **/
   1270 EFI_STATUS
   1271 BOpt_FindDrivers (
   1272   VOID
   1273   )
   1274 {
   1275   UINTN                           NoDevicePathHandles;
   1276   EFI_HANDLE                      *DevicePathHandle;
   1277   UINTN                           Index;
   1278   EFI_STATUS                      Status;
   1279   BM_MENU_ENTRY                   *NewMenuEntry;
   1280   BM_HANDLE_CONTEXT               *NewHandleContext;
   1281   EFI_HANDLE                      CurHandle;
   1282   UINTN                           OptionNumber;
   1283   EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFs;
   1284   EFI_LOAD_FILE_PROTOCOL          *LoadFile;
   1285 
   1286   SimpleFs  = NULL;
   1287   LoadFile  = NULL;
   1288 
   1289   InitializeListHead (&DriverMenu.Head);
   1290 
   1291   //
   1292   // At first, get all handles that support Device Path
   1293   // protocol which is the basic requirement for
   1294   // Driver####
   1295   //
   1296   Status = gBS->LocateHandleBuffer (
   1297                   ByProtocol,
   1298                   &gEfiDevicePathProtocolGuid,
   1299                   NULL,
   1300                   &NoDevicePathHandles,
   1301                   &DevicePathHandle
   1302                   );
   1303   if (EFI_ERROR (Status)) {
   1304     return Status;
   1305   }
   1306 
   1307   OptionNumber = 0;
   1308   for (Index = 0; Index < NoDevicePathHandles; Index++) {
   1309     CurHandle = DevicePathHandle[Index];
   1310 
   1311     Status = gBS->HandleProtocol (
   1312                     CurHandle,
   1313                     &gEfiSimpleFileSystemProtocolGuid,
   1314                     (VOID **) &SimpleFs
   1315                     );
   1316     if (Status == EFI_SUCCESS) {
   1317       continue;
   1318     }
   1319 
   1320     Status = gBS->HandleProtocol (
   1321                     CurHandle,
   1322                     &gEfiLoadFileProtocolGuid,
   1323                     (VOID **) &LoadFile
   1324                     );
   1325     if (Status == EFI_SUCCESS) {
   1326       continue;
   1327     }
   1328 
   1329     NewMenuEntry = BOpt_CreateMenuEntry (BM_HANDLE_CONTEXT_SELECT);
   1330     if (NULL == NewMenuEntry) {
   1331       FreePool (DevicePathHandle);
   1332       return EFI_OUT_OF_RESOURCES;
   1333     }
   1334 
   1335     NewHandleContext              = (BM_HANDLE_CONTEXT *) NewMenuEntry->VariableContext;
   1336     NewHandleContext->Handle      = CurHandle;
   1337     NewHandleContext->DevicePath  = DevicePathFromHandle (CurHandle);
   1338     NewMenuEntry->DisplayString = DevicePathToStr (NewHandleContext->DevicePath);
   1339     NewMenuEntry->HelpString    = NULL;
   1340     NewMenuEntry->OptionNumber  = OptionNumber;
   1341     OptionNumber++;
   1342     InsertTailList (&DriverMenu.Head, &NewMenuEntry->Link);
   1343 
   1344   }
   1345 
   1346   if (DevicePathHandle != NULL) {
   1347     FreePool (DevicePathHandle);
   1348   }
   1349 
   1350   DriverMenu.MenuNumber = OptionNumber;
   1351   return EFI_SUCCESS;
   1352 }
   1353 
   1354 /**
   1355 
   1356   Get the Option Number that has not been allocated for use.
   1357 
   1358   @param Type  The type of Option.
   1359 
   1360   @return The available Option Number.
   1361 
   1362 **/
   1363 UINT16
   1364 BOpt_GetOptionNumber (
   1365   CHAR16        *Type
   1366   )
   1367 {
   1368   UINT16        *OrderList;
   1369   UINTN         OrderListSize;
   1370   UINTN         Index;
   1371   CHAR16        StrTemp[20];
   1372   UINT16        *OptionBuffer;
   1373   UINT16        OptionNumber;
   1374   UINTN         OptionSize;
   1375 
   1376   OrderListSize = 0;
   1377   OrderList     = NULL;
   1378   OptionNumber  = 0;
   1379   Index         = 0;
   1380 
   1381   UnicodeSPrint (StrTemp, sizeof (StrTemp), L"%sOrder", Type);
   1382 
   1383   OrderList = BdsLibGetVariableAndSize (
   1384                           StrTemp,
   1385                           &gEfiGlobalVariableGuid,
   1386                           &OrderListSize
   1387                           );
   1388 
   1389   for (OptionNumber = 0; ; OptionNumber++) {
   1390     if (OrderList != NULL) {
   1391       for (Index = 0; Index < OrderListSize / sizeof (UINT16); Index++) {
   1392         if (OptionNumber == OrderList[Index]) {
   1393           break;
   1394         }
   1395       }
   1396     }
   1397 
   1398     if (Index < OrderListSize / sizeof (UINT16)) {
   1399       //
   1400       // The OptionNumber occurs in the OrderList, continue to use next one
   1401       //
   1402       continue;
   1403     }
   1404     UnicodeSPrint (StrTemp, sizeof (StrTemp), L"%s%04x", Type, (UINTN) OptionNumber);
   1405     DEBUG((EFI_D_ERROR,"Option = %s\n", StrTemp));
   1406     OptionBuffer = BdsLibGetVariableAndSize (
   1407                        StrTemp,
   1408                        &gEfiGlobalVariableGuid,
   1409                        &OptionSize
   1410                        );
   1411     if (NULL == OptionBuffer) {
   1412       //
   1413       // The Boot[OptionNumber] / Driver[OptionNumber] NOT occurs, we found it
   1414       //
   1415       break;
   1416     }
   1417   }
   1418 
   1419   return OptionNumber;
   1420 }
   1421 
   1422 /**
   1423 
   1424   Get the Option Number for Boot#### that does not used.
   1425 
   1426   @return The available Option Number.
   1427 
   1428 **/
   1429 UINT16
   1430 BOpt_GetBootOptionNumber (
   1431   VOID
   1432   )
   1433 {
   1434   return BOpt_GetOptionNumber (L"Boot");
   1435 }
   1436 
   1437 /**
   1438 
   1439   Get the Option Number for Driver#### that does not used.
   1440 
   1441   @return The unused Option Number.
   1442 
   1443 **/
   1444 UINT16
   1445 BOpt_GetDriverOptionNumber (
   1446   VOID
   1447   )
   1448 {
   1449   return BOpt_GetOptionNumber (L"Driver");
   1450 }
   1451 
   1452 /**
   1453 
   1454   Build up all DriverOptionMenu
   1455 
   1456   @param CallbackData The BMM context data.
   1457 
   1458   @retval EFI_SUCESS           The functin completes successfully.
   1459   @retval EFI_OUT_OF_RESOURCES Not enough memory to compete the operation.
   1460   @retval EFI_NOT_FOUND        Fail to get "DriverOrder" variable.
   1461 
   1462 **/
   1463 EFI_STATUS
   1464 BOpt_GetDriverOptions (
   1465   IN  BMM_CALLBACK_DATA         *CallbackData
   1466   )
   1467 {
   1468   UINTN           Index;
   1469   UINT16          DriverString[12];
   1470   UINT8           *LoadOptionFromVar;
   1471   UINT8           *LoadOption;
   1472   UINTN           DriverOptionSize;
   1473 
   1474   UINT16          *DriverOrderList;
   1475   UINTN           DriverOrderListSize;
   1476   BM_MENU_ENTRY   *NewMenuEntry;
   1477   BM_LOAD_CONTEXT *NewLoadContext;
   1478   UINT8           *LoadOptionPtr;
   1479   UINTN           StringSize;
   1480   UINTN           OptionalDataSize;
   1481   UINT8           *LoadOptionEnd;
   1482 
   1483   DriverOrderListSize = 0;
   1484   DriverOrderList     = NULL;
   1485   DriverOptionSize    = 0;
   1486   LoadOptionFromVar   = NULL;
   1487   BOpt_FreeMenu (&DriverOptionMenu);
   1488   InitializeListHead (&DriverOptionMenu.Head);
   1489   //
   1490   // Get the DriverOrder from the Var
   1491   //
   1492   DriverOrderList = BdsLibGetVariableAndSize (
   1493                       L"DriverOrder",
   1494                       &gEfiGlobalVariableGuid,
   1495                       &DriverOrderListSize
   1496                       );
   1497   if (DriverOrderList == NULL) {
   1498     return EFI_NOT_FOUND;
   1499   }
   1500 
   1501   for (Index = 0; Index < DriverOrderListSize / sizeof (UINT16); Index++) {
   1502     UnicodeSPrint (
   1503       DriverString,
   1504       sizeof (DriverString),
   1505       L"Driver%04x",
   1506       DriverOrderList[Index]
   1507       );
   1508     //
   1509     //  Get all loadoptions from the VAR
   1510     //
   1511     LoadOptionFromVar = BdsLibGetVariableAndSize (
   1512                           DriverString,
   1513                           &gEfiGlobalVariableGuid,
   1514                           &DriverOptionSize
   1515                           );
   1516     if (LoadOptionFromVar == NULL) {
   1517       continue;
   1518     }
   1519 
   1520     LoadOption = AllocateZeroPool (DriverOptionSize);
   1521     if (LoadOption == NULL) {
   1522       continue;
   1523     }
   1524 
   1525     CopyMem (LoadOption, LoadOptionFromVar, DriverOptionSize);
   1526     FreePool (LoadOptionFromVar);
   1527 
   1528     NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);
   1529     if (NULL == NewMenuEntry) {
   1530       return EFI_OUT_OF_RESOURCES;
   1531     }
   1532 
   1533     NewLoadContext                      = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
   1534     LoadOptionPtr                       = LoadOption;
   1535     LoadOptionEnd                       = LoadOption + DriverOptionSize;
   1536     NewMenuEntry->OptionNumber          = DriverOrderList[Index];
   1537     NewLoadContext->LoadOptionModified  = FALSE;
   1538     NewLoadContext->Deleted             = FALSE;
   1539     NewLoadContext->IsLegacy            = FALSE;
   1540 
   1541     //
   1542     // LoadOption is a pointer type of UINT8
   1543     // for easy use with following LOAD_OPTION
   1544     // embedded in this struct
   1545     //
   1546     NewLoadContext->LoadOption      = LoadOption;
   1547     NewLoadContext->LoadOptionSize  = DriverOptionSize;
   1548 
   1549     NewLoadContext->Attributes      = *(UINT32 *) LoadOptionPtr;
   1550     NewLoadContext->IsActive        = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_ACTIVE);
   1551 
   1552     NewLoadContext->ForceReconnect  = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_FORCE_RECONNECT);
   1553 
   1554     LoadOptionPtr += sizeof (UINT32);
   1555 
   1556     NewLoadContext->FilePathListLength = *(UINT16 *) LoadOptionPtr;
   1557     LoadOptionPtr += sizeof (UINT16);
   1558 
   1559     StringSize                  = StrSize ((UINT16 *) LoadOptionPtr);
   1560     NewLoadContext->Description = AllocateZeroPool (StringSize);
   1561     ASSERT (NewLoadContext->Description != NULL);
   1562     CopyMem (
   1563       NewLoadContext->Description,
   1564       (UINT16 *) LoadOptionPtr,
   1565       StringSize
   1566       );
   1567     NewMenuEntry->DisplayString = NewLoadContext->Description;
   1568 
   1569     LoadOptionPtr += StringSize;
   1570 
   1571     NewLoadContext->FilePathList = AllocateZeroPool (NewLoadContext->FilePathListLength);
   1572     ASSERT (NewLoadContext->FilePathList != NULL);
   1573     CopyMem (
   1574       NewLoadContext->FilePathList,
   1575       (EFI_DEVICE_PATH_PROTOCOL *) LoadOptionPtr,
   1576       NewLoadContext->FilePathListLength
   1577       );
   1578 
   1579     NewMenuEntry->HelpString = DevicePathToStr (NewLoadContext->FilePathList);
   1580     NewMenuEntry->DisplayStringToken = GetStringTokenFromDepository (
   1581                                         CallbackData,
   1582                                         DriverOptionStrDepository
   1583                                         );
   1584     NewMenuEntry->HelpStringToken = GetStringTokenFromDepository (
   1585                                       CallbackData,
   1586                                       DriverOptionHelpStrDepository
   1587                                       );
   1588     LoadOptionPtr += NewLoadContext->FilePathListLength;
   1589 
   1590     if (LoadOptionPtr < LoadOptionEnd) {
   1591       OptionalDataSize = DriverOptionSize -
   1592         sizeof (UINT32) -
   1593         sizeof (UINT16) -
   1594         StringSize -
   1595         NewLoadContext->FilePathListLength;
   1596 
   1597       NewLoadContext->OptionalData = AllocateZeroPool (OptionalDataSize);
   1598       ASSERT (NewLoadContext->OptionalData != NULL);
   1599       CopyMem (
   1600         NewLoadContext->OptionalData,
   1601         LoadOptionPtr,
   1602         OptionalDataSize
   1603         );
   1604 
   1605       NewLoadContext->OptionalDataSize = OptionalDataSize;
   1606     }
   1607 
   1608     InsertTailList (&DriverOptionMenu.Head, &NewMenuEntry->Link);
   1609 
   1610   }
   1611 
   1612   if (DriverOrderList != NULL) {
   1613     FreePool (DriverOrderList);
   1614   }
   1615   DriverOptionMenu.MenuNumber = Index;
   1616   return EFI_SUCCESS;
   1617 
   1618 }
   1619 
   1620 /**
   1621   Get option number according to Boot#### and BootOrder variable.
   1622   The value is saved as #### + 1.
   1623 
   1624   @param CallbackData    The BMM context data.
   1625 **/
   1626 VOID
   1627 GetBootOrder (
   1628   IN  BMM_CALLBACK_DATA    *CallbackData
   1629   )
   1630 {
   1631   BMM_FAKE_NV_DATA          *BmmConfig;
   1632   UINT16                    Index;
   1633   UINT16                    OptionOrderIndex;
   1634   UINTN                     DeviceType;
   1635   BM_MENU_ENTRY             *NewMenuEntry;
   1636   BM_LOAD_CONTEXT           *NewLoadContext;
   1637 
   1638   ASSERT (CallbackData != NULL);
   1639 
   1640   DeviceType = (UINTN) -1;
   1641   BmmConfig  = &CallbackData->BmmFakeNvData;
   1642   ZeroMem (BmmConfig->BootOptionOrder, sizeof (BmmConfig->BootOptionOrder));
   1643 
   1644   for (Index = 0, OptionOrderIndex = 0; ((Index < BootOptionMenu.MenuNumber) &&
   1645        (OptionOrderIndex < (sizeof (BmmConfig->BootOptionOrder) / sizeof (BmmConfig->BootOptionOrder[0]))));
   1646        Index++) {
   1647     NewMenuEntry   = BOpt_GetMenuEntry (&BootOptionMenu, Index);
   1648     NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
   1649 
   1650     if (NewLoadContext->IsLegacy) {
   1651       if (((BBS_BBS_DEVICE_PATH *) NewLoadContext->FilePathList)->DeviceType != DeviceType) {
   1652         DeviceType = ((BBS_BBS_DEVICE_PATH *) NewLoadContext->FilePathList)->DeviceType;
   1653       } else {
   1654         //
   1655         // Only show one legacy boot option for the same device type
   1656         // assuming the boot options are grouped by the device type
   1657         //
   1658         continue;
   1659       }
   1660     }
   1661     BmmConfig->BootOptionOrder[OptionOrderIndex++] = (UINT32) (NewMenuEntry->OptionNumber + 1);
   1662   }
   1663 }
   1664 
   1665 /**
   1666   According to LegacyDevOrder variable to get legacy FD\HD\CD\NET\BEV
   1667   devices list .
   1668 
   1669   @param CallbackData    The BMM context data.
   1670 **/
   1671 VOID
   1672 GetLegacyDeviceOrder (
   1673   IN  BMM_CALLBACK_DATA    *CallbackData
   1674   )
   1675 {
   1676   UINTN                     Index;
   1677   UINTN                     OptionIndex;
   1678   UINT16                    PageIdList[5];
   1679   UINTN                     PageNum;
   1680   UINTN                     VarSize;
   1681   UINT8                     *VarData;
   1682   UINT8                     *WorkingVarData;
   1683   LEGACY_DEV_ORDER_ENTRY    *DevOrder;
   1684   UINT16                    VarDevOrder;
   1685   UINT8                     *DisMap;
   1686   BM_MENU_OPTION            *OptionMenu;
   1687   BBS_TYPE                  BbsType;
   1688   UINT8                     *LegacyOrder;
   1689   UINT8                     *OldData;
   1690   UINTN                     Pos;
   1691   UINTN                     Bit;
   1692 
   1693   ASSERT (CallbackData != NULL);
   1694 
   1695   PageIdList[0] = FORM_SET_FD_ORDER_ID;
   1696   PageIdList[1] = FORM_SET_HD_ORDER_ID;
   1697   PageIdList[2] = FORM_SET_CD_ORDER_ID;
   1698   PageIdList[3] = FORM_SET_NET_ORDER_ID;
   1699   PageIdList[4] = FORM_SET_BEV_ORDER_ID;
   1700   OptionMenu  = NULL;
   1701   BbsType     = 0;
   1702   LegacyOrder = NULL;
   1703   OldData     = NULL;
   1704   DisMap      = ZeroMem (CallbackData->BmmFakeNvData.DisableMap, sizeof (CallbackData->BmmFakeNvData.DisableMap));
   1705   PageNum     = ARRAY_SIZE (PageIdList);
   1706   VarData     = BdsLibGetVariableAndSize (
   1707                   VAR_LEGACY_DEV_ORDER,
   1708                   &gEfiLegacyDevOrderVariableGuid,
   1709                   &VarSize
   1710                   );
   1711 
   1712   for (Index = 0; Index < PageNum; Index++) {
   1713     switch (PageIdList[Index]) {
   1714 
   1715     case FORM_SET_FD_ORDER_ID:
   1716       OptionMenu  = (BM_MENU_OPTION *) &LegacyFDMenu;
   1717       BbsType     = BBS_FLOPPY;
   1718       LegacyOrder = CallbackData->BmmFakeNvData.LegacyFD;
   1719       OldData     = CallbackData->BmmOldFakeNVData.LegacyFD;
   1720       break;
   1721 
   1722     case FORM_SET_HD_ORDER_ID:
   1723       OptionMenu  = (BM_MENU_OPTION *) &LegacyHDMenu;
   1724       BbsType     = BBS_HARDDISK;
   1725       LegacyOrder = CallbackData->BmmFakeNvData.LegacyHD;
   1726       OldData     = CallbackData->BmmOldFakeNVData.LegacyHD;
   1727       break;
   1728 
   1729     case FORM_SET_CD_ORDER_ID:
   1730       OptionMenu  = (BM_MENU_OPTION *) &LegacyCDMenu;
   1731       BbsType     = BBS_CDROM;
   1732       LegacyOrder = CallbackData->BmmFakeNvData.LegacyCD;
   1733       OldData     = CallbackData->BmmOldFakeNVData.LegacyCD;
   1734       break;
   1735 
   1736     case FORM_SET_NET_ORDER_ID:
   1737       OptionMenu  = (BM_MENU_OPTION *) &LegacyNETMenu;
   1738       BbsType     = BBS_EMBED_NETWORK;
   1739       LegacyOrder = CallbackData->BmmFakeNvData.LegacyNET;
   1740       OldData     = CallbackData->BmmOldFakeNVData.LegacyNET;
   1741       break;
   1742 
   1743     default:
   1744       ASSERT (PageIdList[Index] == FORM_SET_BEV_ORDER_ID);
   1745       OptionMenu  = (BM_MENU_OPTION *) &LegacyBEVMenu;
   1746       BbsType     = BBS_BEV_DEVICE;
   1747       LegacyOrder = CallbackData->BmmFakeNvData.LegacyBEV;
   1748       OldData     = CallbackData->BmmOldFakeNVData.LegacyBEV;
   1749       break;
   1750     }
   1751 
   1752     if (NULL != VarData) {
   1753       WorkingVarData = VarData;
   1754       DevOrder    = (LEGACY_DEV_ORDER_ENTRY *) WorkingVarData;
   1755       while (WorkingVarData < VarData + VarSize) {
   1756         if (DevOrder->BbsType == BbsType) {
   1757           break;
   1758         }
   1759 
   1760         WorkingVarData  = (UINT8 *)((UINTN)WorkingVarData + sizeof (BBS_TYPE));
   1761         WorkingVarData += *(UINT16 *) WorkingVarData;
   1762         DevOrder = (LEGACY_DEV_ORDER_ENTRY *) WorkingVarData;
   1763       }
   1764       for (OptionIndex = 0; OptionIndex < OptionMenu->MenuNumber; OptionIndex++) {
   1765         VarDevOrder = *(UINT16 *) ((UINTN) DevOrder + sizeof (BBS_TYPE) + sizeof (UINT16) + OptionIndex * sizeof (UINT16));
   1766          if (0xFF00 == (VarDevOrder & 0xFF00)) {
   1767           LegacyOrder[OptionIndex]  = 0xFF;
   1768           Pos                       = (VarDevOrder & 0xFF) / 8;
   1769           Bit                       = 7 - ((VarDevOrder & 0xFF) % 8);
   1770           DisMap[Pos] = (UINT8) (DisMap[Pos] | (UINT8) (1 << Bit));
   1771         } else {
   1772           LegacyOrder[OptionIndex] = (UINT8) (VarDevOrder & 0xFF);
   1773         }
   1774       }
   1775       CopyMem (OldData, LegacyOrder, 100);
   1776     }
   1777   }
   1778 }
   1779 
   1780 /**
   1781   Get driver option order from globalc DriverOptionMenu.
   1782 
   1783   @param CallbackData    The BMM context data.
   1784 
   1785 **/
   1786 VOID
   1787 GetDriverOrder (
   1788   IN  BMM_CALLBACK_DATA    *CallbackData
   1789   )
   1790 {
   1791   BMM_FAKE_NV_DATA          *BmmConfig;
   1792   UINT16                    Index;
   1793   UINT16                    OptionOrderIndex;
   1794   UINTN                     DeviceType;
   1795   BM_MENU_ENTRY             *NewMenuEntry;
   1796   BM_LOAD_CONTEXT           *NewLoadContext;
   1797 
   1798   ASSERT (CallbackData != NULL);
   1799 
   1800   DeviceType = (UINTN) -1;
   1801   BmmConfig  = &CallbackData->BmmFakeNvData;
   1802   ZeroMem (BmmConfig->DriverOptionOrder, sizeof (BmmConfig->DriverOptionOrder));
   1803 
   1804   for (Index = 0, OptionOrderIndex = 0; ((Index < DriverOptionMenu.MenuNumber) &&
   1805        (OptionOrderIndex < (sizeof (BmmConfig->DriverOptionOrder) / sizeof (BmmConfig->DriverOptionOrder[0]))));
   1806        Index++) {
   1807     NewMenuEntry   = BOpt_GetMenuEntry (&DriverOptionMenu, Index);
   1808     NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
   1809 
   1810     if (NewLoadContext->IsLegacy) {
   1811       if (((BBS_BBS_DEVICE_PATH *) NewLoadContext->FilePathList)->DeviceType != DeviceType) {
   1812         DeviceType = ((BBS_BBS_DEVICE_PATH *) NewLoadContext->FilePathList)->DeviceType;
   1813       } else {
   1814         //
   1815         // Only show one legacy boot option for the same device type
   1816         // assuming the boot options are grouped by the device type
   1817         //
   1818         continue;
   1819       }
   1820     }
   1821     BmmConfig->DriverOptionOrder[OptionOrderIndex++] = (UINT32) (NewMenuEntry->OptionNumber + 1);
   1822   }
   1823 }
   1824