]> git.proxmox.com Git - mirror_edk2.git/blobdiff - EdkUnixPkg/Dxe/PlatformBds/Generic/BootMaint/BootOption.c
Unix version of EFI emulator
[mirror_edk2.git] / EdkUnixPkg / Dxe / PlatformBds / Generic / BootMaint / BootOption.c
diff --git a/EdkUnixPkg/Dxe/PlatformBds/Generic/BootMaint/BootOption.c b/EdkUnixPkg/Dxe/PlatformBds/Generic/BootMaint/BootOption.c
new file mode 100644 (file)
index 0000000..3fccd99
--- /dev/null
@@ -0,0 +1,1685 @@
+/*++\r
+Copyright (c) 2006, Intel Corporation                                                         \r
+All rights reserved. This program and the accompanying materials                          \r
+are licensed and made available under the terms and conditions of the BSD License         \r
+which accompanies this distribution.  The full text of the license may be found at        \r
+http://opensource.org/licenses/bsd-license.php                                            \r
+                                                                                          \r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
+\r
+Module Name:\r
+\r
+  BootOption.c\r
+  \r
+Abstract:\r
+\r
+  Provide boot option support for Application "BootMaint"\r
+\r
+  Include file system navigation, system handle selection\r
+\r
+  Boot option manipulation\r
+  \r
+Revision History\r
+\r
+--*/\r
+\r
+#include "BootMaint.h"\r
+#include "BBSsupport.h"\r
+\r
+BM_MENU_ENTRY *\r
+BOpt_CreateMenuEntry (\r
+  UINTN           MenuType\r
+  )\r
+/*++\r
+\r
+Routine Description\r
+  Create Menu Entry for future use, make all types together\r
+  in order to reduce code size\r
+\r
+Arguments:\r
+  MenuType            Use this parameter to identify current\r
+                      Menu type\r
+\r
+Returns:\r
+  NULL                Cannot allocate memory for current menu \r
+                      entry\r
+  Others              A valid pointer pointing to the allocated\r
+                      memory pool for current menu entry\r
+\r
+--*/\r
+{\r
+  BM_MENU_ENTRY *MenuEntry;\r
+  UINTN         ContextSize;\r
+\r
+  switch (MenuType) {\r
+  case BM_LOAD_CONTEXT_SELECT:\r
+    ContextSize = sizeof (BM_LOAD_CONTEXT);\r
+    break;\r
+\r
+  case BM_FILE_CONTEXT_SELECT:\r
+    ContextSize = sizeof (BM_FILE_CONTEXT);\r
+    break;\r
+\r
+  case BM_CONSOLE_CONTEXT_SELECT:\r
+    ContextSize = sizeof (BM_CONSOLE_CONTEXT);\r
+    break;\r
+\r
+  case BM_TERMINAL_CONTEXT_SELECT:\r
+    ContextSize = sizeof (BM_TERMINAL_CONTEXT);\r
+    break;\r
+\r
+  case BM_HANDLE_CONTEXT_SELECT:\r
+    ContextSize = sizeof (BM_HANDLE_CONTEXT);\r
+    break;\r
+\r
+  case BM_LEGACY_DEV_CONTEXT_SELECT:\r
+    ContextSize = sizeof (BM_LEGACY_DEVICE_CONTEXT);\r
+    break;\r
+\r
+  default:\r
+    ContextSize = 0;\r
+    break;\r
+\r
+  }\r
+\r
+  if (0 == ContextSize) {\r
+    return NULL;\r
+  }\r
+\r
+  MenuEntry = AllocateZeroPool (sizeof (BM_MENU_ENTRY));\r
+  if (NULL == MenuEntry) {\r
+    return MenuEntry;\r
+  }\r
+\r
+  MenuEntry->VariableContext = AllocateZeroPool (ContextSize);\r
+  if (NULL == MenuEntry->VariableContext) {\r
+    SafeFreePool (MenuEntry);\r
+    MenuEntry = NULL;\r
+    return MenuEntry;\r
+  }\r
+\r
+  MenuEntry->Signature        = BM_MENU_ENTRY_SIGNATURE;\r
+  MenuEntry->ContextSelection = MenuType;\r
+  return MenuEntry;\r
+}\r
+\r
+VOID\r
+BOpt_DestroyMenuEntry (\r
+  BM_MENU_ENTRY         *MenuEntry\r
+  )\r
+/*++\r
+  Routine Description :\r
+    Destroy the menu entry passed in\r
+\r
+  Arguments :\r
+    The menu entry need to be destroyed\r
+\r
+  Returns :\r
+    None\r
+\r
+--*/\r
+{\r
+  BM_LOAD_CONTEXT           *LoadContext;\r
+  BM_FILE_CONTEXT           *FileContext;\r
+  BM_CONSOLE_CONTEXT        *ConsoleContext;\r
+  BM_TERMINAL_CONTEXT       *TerminalContext;\r
+  BM_HANDLE_CONTEXT         *HandleContext;\r
+  BM_LEGACY_DEVICE_CONTEXT  *LegacyDevContext;\r
+\r
+  //\r
+  //  Select by the type in Menu entry for current context type\r
+  //\r
+  switch (MenuEntry->ContextSelection) {\r
+  case BM_LOAD_CONTEXT_SELECT:\r
+    LoadContext = (BM_LOAD_CONTEXT *) MenuEntry->VariableContext;\r
+    SafeFreePool (LoadContext->FilePathList);\r
+    SafeFreePool (LoadContext->LoadOption);\r
+    SafeFreePool (LoadContext->OptionalData);\r
+    SafeFreePool (LoadContext);\r
+    break;\r
+\r
+  case BM_FILE_CONTEXT_SELECT:\r
+    FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;\r
+\r
+    if (!FileContext->IsRoot) {\r
+      SafeFreePool (FileContext->DevicePath);\r
+    } else {\r
+      if (FileContext->FHandle != NULL) {\r
+        FileContext->FHandle->Close (FileContext->FHandle);\r
+      }\r
+    }\r
+\r
+    SafeFreePool (FileContext->FileName);\r
+    SafeFreePool (FileContext->Info);\r
+    SafeFreePool (FileContext);\r
+    break;\r
+\r
+  case BM_CONSOLE_CONTEXT_SELECT:\r
+    ConsoleContext = (BM_CONSOLE_CONTEXT *) MenuEntry->VariableContext;\r
+    SafeFreePool (ConsoleContext->DevicePath);\r
+    SafeFreePool (ConsoleContext);\r
+    break;\r
+\r
+  case BM_TERMINAL_CONTEXT_SELECT:\r
+    TerminalContext = (BM_TERMINAL_CONTEXT *) MenuEntry->VariableContext;\r
+    SafeFreePool (TerminalContext->DevicePath);\r
+    SafeFreePool (TerminalContext);\r
+    break;\r
+\r
+  case BM_HANDLE_CONTEXT_SELECT:\r
+    HandleContext = (BM_HANDLE_CONTEXT *) MenuEntry->VariableContext;\r
+    SafeFreePool (HandleContext);\r
+    break;\r
+\r
+  case BM_LEGACY_DEV_CONTEXT_SELECT:\r
+    LegacyDevContext = (BM_LEGACY_DEVICE_CONTEXT *) MenuEntry->VariableContext;\r
+    SafeFreePool (LegacyDevContext);\r
+\r
+  default:\r
+    break;\r
+  }\r
+\r
+  SafeFreePool (MenuEntry->DisplayString);\r
+  if (NULL != MenuEntry->HelpString) {\r
+    SafeFreePool (MenuEntry->HelpString);\r
+  }\r
+\r
+  SafeFreePool (MenuEntry);\r
+}\r
+\r
+BM_MENU_ENTRY *\r
+BOpt_GetMenuEntry (\r
+  BM_MENU_OPTION      *MenuOption,\r
+  UINTN               MenuNumber\r
+  )\r
+/*++\r
+  Rountine Description :\r
+    Use this routine to get one particular menu entry in specified \r
+    menu\r
+\r
+  Arguments :\r
+    MenuOption        The menu that we will search \r
+\r
+    MenuNumber        The menunubmer that we want\r
+\r
+  Returns :\r
+    The desired menu entry\r
+\r
+--*/\r
+{\r
+  BM_MENU_ENTRY   *NewMenuEntry;\r
+  UINTN           Index;\r
+  LIST_ENTRY      *List;\r
+\r
+  if (MenuNumber >= MenuOption->MenuNumber) {\r
+    return NULL;\r
+  }\r
+\r
+  List = MenuOption->Head.ForwardLink;\r
+  for (Index = 0; Index < MenuNumber; Index++) {\r
+    List = List->ForwardLink;\r
+  }\r
+\r
+  NewMenuEntry = CR (List, BM_MENU_ENTRY, Link, BM_MENU_ENTRY_SIGNATURE);\r
+\r
+  return NewMenuEntry;\r
+}\r
+\r
+EFI_STATUS\r
+BOpt_FindFileSystem (\r
+  IN BMM_CALLBACK_DATA          *CallbackData\r
+  )\r
+/*++\r
+\r
+Routine Description\r
+  Find file systems for current Extensible Firmware\r
+  Including Handles that support Simple File System\r
+  protocol, Load File protocol.\r
+\r
+  Building up the FileSystem Menu for user selection\r
+  All file system will be stored in FsOptionMenu \r
+  for future use.\r
+\r
+Arguments:\r
+  CallbackData           -   BMM context data\r
+\r
+Returns:\r
+  EFI_SUCCESS            -   Success find the file system\r
+  EFI_OUT_OF_RESOURCES   -   Can not create menu entry\r
+\r
+--*/\r
+{\r
+  UINTN                     NoSimpleFsHandles;\r
+  UINTN                     NoLoadFileHandles;\r
+  EFI_HANDLE                *SimpleFsHandle;\r
+  EFI_HANDLE                *LoadFileHandle;\r
+  UINT16                    *VolumeLabel;\r
+  EFI_BLOCK_IO_PROTOCOL     *BlkIo;\r
+  UINTN                     Index;\r
+  EFI_STATUS                Status;\r
+  BM_MENU_ENTRY             *MenuEntry;\r
+  BM_FILE_CONTEXT           *FileContext;\r
+  UINT16                    *TempStr;\r
+  UINTN                     OptionNumber;\r
+  EFI_LEGACY_BIOS_PROTOCOL  *LegacyBios;\r
+  UINT16                    DeviceType;\r
+  BBS_BBS_DEVICE_PATH       BbsDevicePathNode;\r
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
+  BOOLEAN                   RemovableMedia;\r
+\r
+\r
+  NoSimpleFsHandles = 0;\r
+  NoLoadFileHandles = 0;\r
+  OptionNumber      = 0;\r
+  InitializeListHead (&FsOptionMenu.Head);\r
+\r
+  //\r
+  // Locate Handles that support Simple File System protocol\r
+  //\r
+  Status = gBS->LocateHandleBuffer (\r
+                  ByProtocol,\r
+                  &gEfiSimpleFileSystemProtocolGuid,\r
+                  NULL,\r
+                  &NoSimpleFsHandles,\r
+                  &SimpleFsHandle\r
+                  );\r
+  if (!EFI_ERROR (Status)) {\r
+    //\r
+    // Find all the instances of the File System prototocol\r
+    //\r
+    for (Index = 0; Index < NoSimpleFsHandles; Index++) {\r
+      Status = gBS->HandleProtocol (\r
+                      SimpleFsHandle[Index],\r
+                      &gEfiBlockIoProtocolGuid,\r
+                      &BlkIo\r
+                      );\r
+      if (EFI_ERROR (Status)) {\r
+        //\r
+        // If no block IO exists assume it's NOT a removable media\r
+        //\r
+        RemovableMedia = FALSE;\r
+      } else {\r
+        //\r
+        // If block IO exists check to see if it's remobable media\r
+        //\r
+        RemovableMedia = BlkIo->Media->RemovableMedia; \r
+      }\r
+\r
+      //\r
+      // Allocate pool for this load option\r
+      //\r
+      MenuEntry = BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT);\r
+      if (NULL == MenuEntry) {\r
+        SafeFreePool (SimpleFsHandle);    \r
+        return EFI_OUT_OF_RESOURCES;\r
+      }\r
+\r
+      FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;\r
+            \r
+      FileContext->Handle     = SimpleFsHandle[Index];\r
+      MenuEntry->OptionNumber = Index;\r
+      FileContext->FHandle    = EfiLibOpenRoot (FileContext->Handle);\r
+      if (!FileContext->FHandle) {\r
+        BOpt_DestroyMenuEntry (MenuEntry);\r
+        continue;\r
+      }\r
+\r
+      MenuEntry->HelpString = DevicePathToStr (DevicePathFromHandle (FileContext->Handle));\r
+      FileContext->Info = EfiLibFileSystemVolumeLabelInfo (FileContext->FHandle);\r
+      FileContext->FileName = EfiStrDuplicate (L"\\");\r
+      FileContext->DevicePath = FileDevicePath (\r
+                                  FileContext->Handle,\r
+                                  FileContext->FileName\r
+                                  );\r
+      FileContext->IsDir            = TRUE;\r
+      FileContext->IsRoot           = TRUE;\r
+      FileContext->IsRemovableMedia = FALSE;\r
+      FileContext->IsLoadFile       = FALSE;\r
+\r
+      //\r
+      // Get current file system's Volume Label\r
+      //\r
+      if (FileContext->Info == NULL) {\r
+        VolumeLabel = L"NO FILE SYSTEM INFO";\r
+      } else {\r
+        if (FileContext->Info->VolumeLabel == NULL) {\r
+          VolumeLabel = L"NULL VOLUME LABEL";\r
+        } else {\r
+          VolumeLabel = FileContext->Info->VolumeLabel;\r
+          if (*VolumeLabel == 0x0000) {\r
+            VolumeLabel = L"NO VOLUME LABEL";\r
+          }\r
+        }\r
+      }\r
+\r
+      TempStr                   = MenuEntry->HelpString;\r
+      MenuEntry->DisplayString  = AllocateZeroPool (MAX_CHAR);\r
+      ASSERT (MenuEntry->DisplayString != NULL);\r
+      UnicodeSPrint (\r
+        MenuEntry->DisplayString,\r
+        MAX_CHAR,\r
+        L"%s, [%s]",\r
+        VolumeLabel,\r
+        TempStr\r
+        );\r
+      OptionNumber++;\r
+      InsertTailList (&FsOptionMenu.Head, &MenuEntry->Link);      \r
+    }\r
+  }\r
+\r
+  if (NoSimpleFsHandles != 0) {\r
+    SafeFreePool (SimpleFsHandle);\r
+  }\r
+  //\r
+  // Searching for handles that support Load File protocol\r
+  //\r
+  Status = gBS->LocateHandleBuffer (\r
+                  ByProtocol,\r
+                  &gEfiLoadFileProtocolGuid,\r
+                  NULL,\r
+                  &NoLoadFileHandles,\r
+                  &LoadFileHandle\r
+                  );\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    for (Index = 0; Index < NoLoadFileHandles; Index++) {\r
+      MenuEntry = BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT);\r
+      if (NULL == MenuEntry) {\r
+        SafeFreePool (LoadFileHandle);    \r
+        return EFI_OUT_OF_RESOURCES;\r
+      }\r
+\r
+      FileContext                   = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;\r
+      FileContext->IsRemovableMedia = FALSE;\r
+      FileContext->IsLoadFile       = TRUE;\r
+      FileContext->Handle           = LoadFileHandle[Index];\r
+      FileContext->IsRoot           = TRUE;\r
+\r
+      FileContext->DevicePath = DevicePathFromHandle (FileContext->Handle);\r
+\r
+      MenuEntry->HelpString     = DevicePathToStr (FileContext->DevicePath);\r
+\r
+      TempStr                   = MenuEntry->HelpString;\r
+      MenuEntry->DisplayString  = AllocateZeroPool (MAX_CHAR);\r
+      ASSERT (MenuEntry->DisplayString != NULL);\r
+      UnicodeSPrint (\r
+        MenuEntry->DisplayString,\r
+        MAX_CHAR,\r
+        L"Load File [%s]",\r
+        TempStr\r
+        );\r
+\r
+      MenuEntry->OptionNumber = OptionNumber;\r
+      OptionNumber++;\r
+      InsertTailList (&FsOptionMenu.Head, &MenuEntry->Link);\r
+    }\r
+  }\r
+\r
+  if (NoLoadFileHandles != 0) {\r
+    SafeFreePool (LoadFileHandle);\r
+  }\r
+\r
+  //\r
+  // Add Legacy Boot Option Support Here\r
+  //\r
+  Status = gBS->LocateProtocol (\r
+                  &gEfiLegacyBiosProtocolGuid,\r
+                  NULL,\r
+                  &LegacyBios\r
+                  );\r
+  if (!EFI_ERROR (Status)) {\r
+\r
+    for (Index = BBS_TYPE_FLOPPY; Index <= BBS_TYPE_EMBEDDED_NETWORK; Index++) {\r
+      MenuEntry = BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT);\r
+      if (NULL == MenuEntry) {\r
+        return EFI_OUT_OF_RESOURCES;\r
+      }\r
+\r
+      FileContext                       = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;\r
+\r
+      FileContext->IsRemovableMedia     = FALSE;\r
+      FileContext->IsLoadFile           = TRUE;\r
+      FileContext->IsBootLegacy         = TRUE;\r
+      DeviceType                        = (UINT16) Index;\r
+      BbsDevicePathNode.Header.Type     = BBS_DEVICE_PATH;\r
+      BbsDevicePathNode.Header.SubType  = BBS_BBS_DP;\r
+      SetDevicePathNodeLength (\r
+        &BbsDevicePathNode.Header,\r
+        sizeof (BBS_BBS_DEVICE_PATH)\r
+        );\r
+      BbsDevicePathNode.DeviceType  = DeviceType;\r
+      BbsDevicePathNode.StatusFlag  = 0;\r
+      BbsDevicePathNode.String[0]   = 0;\r
+      DevicePath = AppendDevicePathNode (\r
+                    EndDevicePath,\r
+                    (EFI_DEVICE_PATH_PROTOCOL *) &BbsDevicePathNode\r
+                    );\r
+\r
+      FileContext->DevicePath   = DevicePath;\r
+      MenuEntry->HelpString     = DevicePathToStr (FileContext->DevicePath);\r
+\r
+      TempStr                   = MenuEntry->HelpString;\r
+      MenuEntry->DisplayString  = AllocateZeroPool (MAX_CHAR);\r
+      ASSERT (MenuEntry->DisplayString != NULL);\r
+      UnicodeSPrint (\r
+        MenuEntry->DisplayString,\r
+        MAX_CHAR,\r
+        L"Boot Legacy [%s]",\r
+        TempStr\r
+        );\r
+      MenuEntry->OptionNumber = OptionNumber;\r
+      OptionNumber++;\r
+      InsertTailList (&FsOptionMenu.Head, &MenuEntry->Link);\r
+    }\r
+  }\r
+  //\r
+  // Remember how many file system options are here\r
+  //\r
+  FsOptionMenu.MenuNumber = OptionNumber;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+VOID\r
+BOpt_FreeMenu (\r
+  BM_MENU_OPTION        *FreeMenu\r
+  )\r
+/*++\r
+\r
+Routine Description\r
+  Free resources allocated in Allocate Rountine\r
+\r
+Arguments:\r
+  FreeMenu        Menu to be freed\r
+\r
+Returns:\r
+  VOID\r
+  \r
+--*/\r
+{\r
+  BM_MENU_ENTRY *MenuEntry;\r
+  while (!IsListEmpty (&FreeMenu->Head)) {\r
+    MenuEntry = CR (\r
+                  FreeMenu->Head.ForwardLink,\r
+                  BM_MENU_ENTRY,\r
+                  Link,\r
+                  BM_MENU_ENTRY_SIGNATURE\r
+                  );\r
+    RemoveEntryList (&MenuEntry->Link);\r
+    BOpt_DestroyMenuEntry (MenuEntry);\r
+  }\r
+}\r
+\r
+EFI_STATUS\r
+BOpt_FindFiles (\r
+  IN BMM_CALLBACK_DATA          *CallbackData,\r
+  IN BM_MENU_ENTRY              *MenuEntry\r
+  )\r
+/*++\r
+\r
+Routine Description\r
+  Find files under current directory\r
+  All files and sub-directories in current directory\r
+  will be stored in DirectoryMenu for future use.\r
+\r
+Arguments:\r
+  FileOption   -- Pointer for Dir to explore\r
+\r
+Returns:\r
+  TRUE         -- Get files from current dir successfully\r
+  FALSE        -- Can't get files from current dir\r
+\r
+--*/\r
+{\r
+  EFI_FILE_HANDLE NewDir;\r
+  EFI_FILE_HANDLE Dir;\r
+  EFI_FILE_INFO   *DirInfo;\r
+  UINTN           BufferSize;\r
+  UINTN           DirBufferSize;\r
+  BM_MENU_ENTRY   *NewMenuEntry;\r
+  BM_FILE_CONTEXT *FileContext;\r
+  BM_FILE_CONTEXT *NewFileContext;\r
+  UINTN           Pass;\r
+  EFI_STATUS      Status;\r
+  UINTN           OptionNumber;\r
+\r
+  FileContext   = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;\r
+  Dir           = FileContext->FHandle;\r
+  OptionNumber  = 0;\r
+  //\r
+  // Open current directory to get files from it\r
+  //\r
+  Status = Dir->Open (\r
+                  Dir,\r
+                  &NewDir,\r
+                  FileContext->FileName,\r
+                  EFI_FILE_READ_ONLY,\r
+                  0\r
+                  );\r
+  if (!FileContext->IsRoot) {\r
+    Dir->Close (Dir);\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  DirInfo = EfiLibFileInfo (NewDir);\r
+  if (!DirInfo) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  if (!(DirInfo->Attribute & EFI_FILE_DIRECTORY)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  FileContext->DevicePath = FileDevicePath (\r
+                              FileContext->Handle,\r
+                              FileContext->FileName\r
+                              );\r
+\r
+  DirBufferSize = sizeof (EFI_FILE_INFO) + 1024;\r
+  DirInfo       = AllocateZeroPool (DirBufferSize);\r
+  if (!DirInfo) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  //\r
+  // Get all files in current directory\r
+  // Pass 1 to get Directories\r
+  // Pass 2 to get files that are EFI images\r
+  //\r
+  for (Pass = 1; Pass <= 2; Pass++) {\r
+    NewDir->SetPosition (NewDir, 0);\r
+    for (;;) {\r
+      BufferSize  = DirBufferSize;\r
+      Status      = NewDir->Read (NewDir, &BufferSize, DirInfo);\r
+      if (EFI_ERROR (Status) || BufferSize == 0) {\r
+        break;\r
+      }\r
+\r
+      if ((DirInfo->Attribute & EFI_FILE_DIRECTORY && Pass == 2) ||\r
+          (!(DirInfo->Attribute & EFI_FILE_DIRECTORY) && Pass == 1)\r
+          ) {\r
+        //\r
+        // Pass 1 is for Directories\r
+        // Pass 2 is for file names\r
+        //\r
+        continue;\r
+      }\r
+\r
+      if (!(BOpt_IsEfiImageName (DirInfo->FileName) || DirInfo->Attribute & EFI_FILE_DIRECTORY)) {\r
+        //\r
+        // Slip file unless it is a directory entry or a .EFI file\r
+        //\r
+        continue;\r
+      }\r
+\r
+      NewMenuEntry = BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT);\r
+      if (NULL == NewMenuEntry) {\r
+        return EFI_OUT_OF_RESOURCES;\r
+      }\r
+\r
+      NewFileContext          = (BM_FILE_CONTEXT *) NewMenuEntry->VariableContext;\r
+      NewFileContext->Handle  = FileContext->Handle;\r
+      NewFileContext->FileName = BOpt_AppendFileName (\r
+                                  FileContext->FileName,\r
+                                  DirInfo->FileName\r
+                                  );\r
+      NewFileContext->FHandle = NewDir;\r
+      NewFileContext->DevicePath = FileDevicePath (\r
+                                    NewFileContext->Handle,\r
+                                    NewFileContext->FileName\r
+                                    );\r
+      NewMenuEntry->HelpString = NULL;\r
+\r
+      MenuEntry->DisplayStringToken = GetStringTokenFromDepository (\r
+                                        CallbackData,\r
+                                        FileOptionStrDepository\r
+                                        );\r
+\r
+      NewFileContext->IsDir = (BOOLEAN) ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY);\r
+\r
+      if (NewFileContext->IsDir) {\r
+        BufferSize                  = StrLen (DirInfo->FileName) * 2 + 6;\r
+        NewMenuEntry->DisplayString = AllocateZeroPool (BufferSize);\r
+\r
+        UnicodeSPrint (\r
+          NewMenuEntry->DisplayString,\r
+          BufferSize,\r
+          L"<%s>",\r
+          DirInfo->FileName\r
+          );\r
+\r
+      } else {\r
+        NewMenuEntry->DisplayString = EfiStrDuplicate (DirInfo->FileName);\r
+      }\r
+\r
+      NewFileContext->IsRoot            = FALSE;\r
+      NewFileContext->IsLoadFile        = FALSE;\r
+      NewFileContext->IsRemovableMedia  = FALSE;\r
+\r
+      NewMenuEntry->OptionNumber        = OptionNumber;\r
+      OptionNumber++;\r
+      InsertTailList (&DirectoryMenu.Head, &NewMenuEntry->Link);\r
+    }\r
+  }\r
+\r
+  DirectoryMenu.MenuNumber = OptionNumber;\r
+  SafeFreePool (DirInfo);\r
+  return TRUE;\r
+}\r
+\r
+EFI_STATUS\r
+BOpt_GetLegacyOptions (\r
+  VOID\r
+  )\r
+/*++\r
+Routine Description:\r
+  \r
+  Build the LegacyFDMenu LegacyHDMenu LegacyCDMenu according to LegacyBios.GetBbsInfo().\r
+    \r
+Arguments:\r
+  None\r
+\r
+Returns:\r
+  The device info of legacy device.\r
+  \r
+--*/\r
+{\r
+  BM_MENU_ENTRY             *NewMenuEntry;\r
+  BM_LEGACY_DEVICE_CONTEXT  *NewLegacyDevContext;\r
+  EFI_STATUS                Status;\r
+  EFI_LEGACY_BIOS_PROTOCOL  *LegacyBios;\r
+  UINT16                    HddCount;\r
+  HDD_INFO                  *HddInfo;\r
+  UINT16                    BbsCount;\r
+  BBS_TABLE                 *BbsTable;\r
+  UINTN                     Index;\r
+  CHAR16                    DescString[100];\r
+  UINTN                     FDNum;\r
+  UINTN                     HDNum;\r
+  UINTN                     CDNum;\r
+  UINTN                     NETNum;\r
+  UINTN                     BEVNum;\r
+\r
+  NewMenuEntry  = NULL;\r
+  HddInfo       = NULL;\r
+  BbsTable      = NULL;\r
+  BbsCount      = 0;\r
+\r
+  //\r
+  // Initialize Bbs Table Context from BBS info data\r
+  //\r
+  InitializeListHead (&LegacyFDMenu.Head);\r
+  InitializeListHead (&LegacyHDMenu.Head);\r
+  InitializeListHead (&LegacyCDMenu.Head);\r
+  InitializeListHead (&LegacyNETMenu.Head);\r
+  InitializeListHead (&LegacyBEVMenu.Head);\r
+\r
+  Status = gBS->LocateProtocol (\r
+                  &gEfiLegacyBiosProtocolGuid,\r
+                  NULL,\r
+                  &LegacyBios\r
+                  );\r
+  if (!EFI_ERROR (Status)) {\r
+    Status = LegacyBios->GetBbsInfo (\r
+                          LegacyBios,\r
+                          &HddCount,\r
+                          &HddInfo,\r
+                          &BbsCount,\r
+                          &BbsTable\r
+                          );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  FDNum   = 0;\r
+  HDNum   = 0;\r
+  CDNum   = 0;\r
+  NETNum  = 0;\r
+  BEVNum  = 0;\r
+\r
+  for (Index = 0; Index < BbsCount; Index++) {\r
+    if ((BBS_IGNORE_ENTRY == BbsTable[Index].BootPriority) ||\r
+        (BBS_DO_NOT_BOOT_FROM == BbsTable[Index].BootPriority) ||\r
+        (BBS_LOWEST_PRIORITY == BbsTable[Index].BootPriority)\r
+        ) {\r
+      continue;\r
+    }\r
+\r
+    NewMenuEntry = BOpt_CreateMenuEntry (BM_LEGACY_DEV_CONTEXT_SELECT);\r
+    if (NULL == NewMenuEntry) {\r
+      break;\r
+    }\r
+\r
+    NewLegacyDevContext           = (BM_LEGACY_DEVICE_CONTEXT *) NewMenuEntry->VariableContext;\r
+    NewLegacyDevContext->BbsTable = &BbsTable[Index];\r
+    NewLegacyDevContext->Index    = Index;\r
+    NewLegacyDevContext->BbsCount = BbsCount;\r
+    BdsBuildLegacyDevNameString (\r
+      &BbsTable[Index],\r
+      Index,\r
+      sizeof (DescString),\r
+      DescString\r
+      );\r
+    NewLegacyDevContext->Description = AllocateZeroPool (StrSize (DescString));\r
+    if (NULL == NewLegacyDevContext->Description) {\r
+      break;\r
+    }\r
+\r
+    CopyMem (NewLegacyDevContext->Description, DescString, StrSize (DescString));\r
+    NewMenuEntry->DisplayString = NewLegacyDevContext->Description;\r
+    NewMenuEntry->HelpString    = NULL;\r
+\r
+    switch (BbsTable[Index].DeviceType) {\r
+    case BBS_FLOPPY:\r
+      InsertTailList (&LegacyFDMenu.Head, &NewMenuEntry->Link);\r
+      FDNum++;\r
+      break;\r
+\r
+    case BBS_HARDDISK:\r
+      InsertTailList (&LegacyHDMenu.Head, &NewMenuEntry->Link);\r
+      HDNum++;\r
+      break;\r
+\r
+    case BBS_CDROM:\r
+      InsertTailList (&LegacyCDMenu.Head, &NewMenuEntry->Link);\r
+      CDNum++;\r
+      break;\r
+\r
+    case BBS_EMBED_NETWORK:\r
+      InsertTailList (&LegacyNETMenu.Head, &NewMenuEntry->Link);\r
+      NETNum++;\r
+      break;\r
+\r
+    case BBS_BEV_DEVICE:\r
+      InsertTailList (&LegacyBEVMenu.Head, &NewMenuEntry->Link);\r
+      BEVNum++;\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (Index != BbsCount) {\r
+    BOpt_FreeLegacyOptions ();\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  LegacyFDMenu.MenuNumber   = FDNum;\r
+  LegacyHDMenu.MenuNumber   = HDNum;\r
+  LegacyCDMenu.MenuNumber   = CDNum;\r
+  LegacyNETMenu.MenuNumber  = NETNum;\r
+  LegacyBEVMenu.MenuNumber  = BEVNum;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+VOID\r
+BOpt_FreeLegacyOptions (\r
+  VOID\r
+  )\r
+{\r
+  BOpt_FreeMenu (&LegacyFDMenu);\r
+  BOpt_FreeMenu (&LegacyHDMenu);\r
+  BOpt_FreeMenu (&LegacyCDMenu);\r
+  BOpt_FreeMenu (&LegacyNETMenu);\r
+  BOpt_FreeMenu (&LegacyBEVMenu);\r
+}\r
+\r
+EFI_STATUS\r
+BOpt_GetBootOptions (\r
+  IN  BMM_CALLBACK_DATA         *CallbackData\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  \r
+  Build the BootOptionMenu according to BootOrder Variable.\r
+  This Routine will access the Boot#### to get EFI_LOAD_OPTION \r
+  \r
+Arguments:\r
+  None\r
+\r
+Returns:\r
+  The number of the Var Boot####\r
+  \r
+--*/\r
+{\r
+  UINTN                     Index;\r
+  UINT16                    BootString[10];\r
+  UINT8                     *LoadOptionFromVar;\r
+  UINT8                     *LoadOption;\r
+  UINTN                     BootOptionSize;\r
+  BOOLEAN                   BootNextFlag;\r
+  UINT16                    *BootOrderList;\r
+  UINTN                     BootOrderListSize;\r
+  UINT16                    *BootNext;\r
+  UINTN                     BootNextSize;\r
+  BM_MENU_ENTRY             *NewMenuEntry;\r
+  BM_LOAD_CONTEXT           *NewLoadContext;\r
+  UINT8                     *LoadOptionPtr;\r
+  UINTN                     StringSize;\r
+  UINTN                     OptionalDataSize;\r
+  UINT8                     *LoadOptionEnd;\r
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
+  UINTN                     MenuCount;\r
+  UINT8                     *Ptr;\r
+\r
+  MenuCount         = 0;\r
+  BootOrderListSize = 0;\r
+  BootNextSize      = 0;\r
+  BootOrderList     = NULL;\r
+  BootNext          = NULL;\r
+  LoadOptionFromVar = NULL;\r
+  BOpt_FreeMenu (&BootOptionMenu);\r
+  InitializeListHead (&BootOptionMenu.Head);\r
+\r
+  //\r
+  // Get the BootOrder from the Var\r
+  //\r
+  BootOrderList = BdsLibGetVariableAndSize (\r
+                    L"BootOrder",\r
+                    &gEfiGlobalVariableGuid,\r
+                    &BootOrderListSize\r
+                    );\r
+\r
+  //\r
+  // Get the BootNext from the Var\r
+  //\r
+  BootNext = BdsLibGetVariableAndSize (\r
+              L"BootNext",\r
+              &gEfiGlobalVariableGuid,\r
+              &BootNextSize\r
+              );\r
+\r
+  if (BootNext) {\r
+    if (BootNextSize != sizeof (UINT16)) {\r
+      SafeFreePool (BootNext);\r
+      BootNext = NULL;\r
+    }\r
+  }\r
+\r
+  for (Index = 0; Index < BootOrderListSize / sizeof (UINT16); Index++) {\r
+    UnicodeSPrint (BootString, sizeof (BootString), L"Boot%04x", BootOrderList[Index]);\r
+    //\r
+    //  Get all loadoptions from the VAR\r
+    //\r
+    LoadOptionFromVar = BdsLibGetVariableAndSize (\r
+                          BootString,\r
+                          &gEfiGlobalVariableGuid,\r
+                          &BootOptionSize\r
+                          );\r
+    if (!LoadOptionFromVar) {\r
+      continue;\r
+    }\r
+\r
+    LoadOption = AllocateZeroPool (BootOptionSize);\r
+    if (!LoadOption) {\r
+      continue;\r
+    }\r
+\r
+    CopyMem (LoadOption, LoadOptionFromVar, BootOptionSize);\r
+    SafeFreePool (LoadOptionFromVar);\r
+\r
+    if (BootNext) {\r
+      BootNextFlag = (BOOLEAN) (*BootNext == BootOrderList[Index]);\r
+    } else {\r
+      BootNextFlag = FALSE;\r
+    }\r
+\r
+    if (0 == (*((UINT32 *) LoadOption) & LOAD_OPTION_ACTIVE)) {\r
+      SafeFreePool (LoadOption);\r
+      continue;\r
+    }\r
+    //\r
+    // BUGBUG: could not return EFI_OUT_OF_RESOURCES here directly.\r
+    // the buffer allocated already should be freed before returning.\r
+    //\r
+    NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);\r
+    if (NULL == NewMenuEntry) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    NewLoadContext                      = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;\r
+\r
+    LoadOptionPtr                       = LoadOption;\r
+    LoadOptionEnd                       = LoadOption + BootOptionSize;\r
+\r
+    NewMenuEntry->OptionNumber          = BootOrderList[Index];\r
+    NewLoadContext->LoadOptionModified  = FALSE;\r
+    NewLoadContext->Deleted             = FALSE;\r
+    NewLoadContext->IsBootNext          = BootNextFlag;\r
+\r
+    //\r
+    // Is a Legacy Device?\r
+    //\r
+    Ptr = (UINT8 *) LoadOption;\r
+\r
+    //\r
+    // Attribute = *(UINT32 *)Ptr;\r
+    //\r
+    Ptr += sizeof (UINT32);\r
+\r
+    //\r
+    // FilePathSize = *(UINT16 *)Ptr;\r
+    //\r
+    Ptr += sizeof (UINT16);\r
+\r
+    //\r
+    // Description = (CHAR16 *)Ptr;\r
+    //\r
+    Ptr += StrSize ((CHAR16 *) Ptr);\r
+\r
+    //\r
+    // Now Ptr point to Device Path\r
+    //\r
+    DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr;\r
+    if ((BBS_DEVICE_PATH == DevicePath->Type) && (BBS_BBS_DP == DevicePath->SubType)) {\r
+      NewLoadContext->IsLegacy = TRUE;\r
+    } else {\r
+      NewLoadContext->IsLegacy = FALSE;\r
+    }\r
+    //\r
+    // LoadOption is a pointer type of UINT8\r
+    // for easy use with following LOAD_OPTION\r
+    // embedded in this struct\r
+    //\r
+    NewLoadContext->LoadOption      = LoadOption;\r
+    NewLoadContext->LoadOptionSize  = BootOptionSize;\r
+\r
+    NewLoadContext->Attributes      = *(UINT32 *) LoadOptionPtr;\r
+    NewLoadContext->IsActive        = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_ACTIVE);\r
+\r
+    NewLoadContext->ForceReconnect  = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_FORCE_RECONNECT);\r
+\r
+    LoadOptionPtr += sizeof (UINT32);\r
+\r
+    NewLoadContext->FilePathListLength = *(UINT16 *) LoadOptionPtr;\r
+    LoadOptionPtr += sizeof (UINT16);\r
+\r
+    StringSize                  = StrSize ((UINT16 *) LoadOptionPtr);\r
+    NewLoadContext->Description = AllocateZeroPool (StringSize);\r
+    ASSERT (NewLoadContext->Description != NULL);\r
+    CopyMem (\r
+      NewLoadContext->Description,\r
+      (UINT16 *) LoadOptionPtr,\r
+      StringSize\r
+      );\r
+    NewMenuEntry->DisplayString = NewLoadContext->Description;\r
+\r
+    LoadOptionPtr += StringSize;\r
+\r
+    NewLoadContext->FilePathList = AllocateZeroPool (NewLoadContext->FilePathListLength);\r
+    ASSERT (NewLoadContext->FilePathList != NULL);\r
+    CopyMem (\r
+      NewLoadContext->FilePathList,\r
+      (EFI_DEVICE_PATH_PROTOCOL *) LoadOptionPtr,\r
+      NewLoadContext->FilePathListLength\r
+      );\r
+\r
+    NewMenuEntry->HelpString = DevicePathToStr (NewLoadContext->FilePathList);\r
+    NewMenuEntry->DisplayStringToken = GetStringTokenFromDepository (\r
+                                        CallbackData,\r
+                                        BootOptionStrDepository\r
+                                        );\r
+    NewMenuEntry->HelpStringToken = GetStringTokenFromDepository (\r
+                                      CallbackData,\r
+                                      BootOptionHelpStrDepository\r
+                                      );\r
+    LoadOptionPtr += NewLoadContext->FilePathListLength;\r
+\r
+    if (LoadOptionPtr < LoadOptionEnd) {\r
+      OptionalDataSize = BootOptionSize -\r
+        sizeof (UINT32) -\r
+        sizeof (UINT16) -\r
+        StringSize -\r
+        NewLoadContext->FilePathListLength;\r
+\r
+      NewLoadContext->OptionalData = AllocateZeroPool (OptionalDataSize);\r
+      ASSERT (NewLoadContext->OptionalData != NULL);\r
+      CopyMem (\r
+        NewLoadContext->OptionalData,\r
+        LoadOptionPtr,\r
+        OptionalDataSize\r
+        );\r
+\r
+      NewLoadContext->OptionalDataSize = OptionalDataSize;\r
+    }\r
+\r
+    InsertTailList (&BootOptionMenu.Head, &NewMenuEntry->Link);\r
+    MenuCount++;\r
+  }\r
+\r
+  SafeFreePool (BootNext);\r
+  SafeFreePool (BootOrderList);\r
+  BootOptionMenu.MenuNumber = MenuCount;\r
+  return MenuCount;\r
+}\r
+\r
+CHAR16 *\r
+BdsStrCpy (\r
+  OUT     CHAR16                    *Destination,\r
+  IN      CONST CHAR16              *Source\r
+  )\r
+{\r
+  CHAR16                            *ReturnValue;\r
+\r
+  //\r
+  // Destination cannot be NULL\r
+  //\r
+  ASSERT (Destination != NULL);\r
+\r
+  ReturnValue = Destination;\r
+  while (*Source) {\r
+    *(Destination++) = *(Source++);\r
+  }\r
+  *Destination = 0;\r
+  return ReturnValue;\r
+}\r
+\r
+CHAR16 *\r
+BOpt_AppendFileName (\r
+  IN  CHAR16  *Str1,\r
+  IN  CHAR16  *Str2\r
+  )\r
+/*++\r
+\r
+Routine Description\r
+  Append file name to existing file name.\r
+\r
+Arguments:\r
+  Str1  -   existing file name\r
+  Str2  -   file name to be appended\r
+\r
+Returns:\r
+  Allocate a new string to hold the appended result.\r
+  Caller is responsible to free the returned string.\r
+\r
+--*/\r
+{\r
+  UINTN   Size1;\r
+  UINTN   Size2;\r
+  CHAR16  *Str;\r
+  CHAR16  *Ptr;\r
+  CHAR16  *LastSlash;\r
+\r
+  Size1 = StrSize (Str1);\r
+  Size2 = StrSize (Str2);\r
+  Str   = AllocateZeroPool (Size1 + Size2 + sizeof (CHAR16));\r
+  ASSERT (Str != NULL);\r
+\r
+  StrCat (Str, Str1);\r
+  if (!((*Str == '\\') && (*(Str + 1) == 0))) {\r
+    StrCat (Str, L"\\");\r
+  }\r
+\r
+  StrCat (Str, Str2);\r
+\r
+  Ptr       = Str;\r
+  LastSlash = Str;\r
+  while (*Ptr != 0) {\r
+    if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '.' && *(Ptr + 3) != 0) {\r
+      //\r
+      // Convert \Name\..\ to \\r
+      // DO NOT convert the .. if it is at the end of the string. This will\r
+      // break the .. behavior in changing directories.\r
+      //\r
+      BdsStrCpy (LastSlash, Ptr + 3);\r
+      Ptr = LastSlash;\r
+    } else if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '\\') {\r
+      //\r
+      // Convert a \.\ to a \\r
+      //\r
+      BdsStrCpy (Ptr, Ptr + 2);\r
+      Ptr = LastSlash;\r
+    } else if (*Ptr == '\\') {\r
+      LastSlash = Ptr;\r
+    }\r
+\r
+    Ptr++;\r
+  }\r
+\r
+  return Str;\r
+}\r
+\r
+BOOLEAN\r
+BOpt_IsEfiImageName (\r
+  IN UINT16  *FileName\r
+  )\r
+/*++\r
+\r
+Routine Description\r
+  Check whether current FileName point to a valid \r
+  Efi Image File.\r
+\r
+Arguments:\r
+  FileName  -   File need to be checked.\r
+\r
+Returns:\r
+  TRUE  -   Is Efi Image\r
+  FALSE -   Not a valid Efi Image\r
+  \r
+--*/\r
+{\r
+  //\r
+  // Search for ".efi" extension\r
+  //\r
+  while (*FileName) {\r
+    if (FileName[0] == '.') {\r
+      if (FileName[1] == 'e' || FileName[1] == 'E') {\r
+        if (FileName[2] == 'f' || FileName[2] == 'F') {\r
+          if (FileName[3] == 'i' || FileName[3] == 'I') {\r
+            return TRUE;\r
+          } else if (FileName[3] == 0x0000) {\r
+            return FALSE;\r
+          }\r
+        } else if (FileName[2] == 0x0000) {\r
+          return FALSE;\r
+        }\r
+      } else if (FileName[1] == 0x0000) {\r
+        return FALSE;\r
+      }\r
+    }\r
+\r
+    FileName += 1;\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+\r
+RETURN_STATUS\r
+EFIAPI\r
+IsEfiAppReadFromFile (\r
+  IN     VOID    *FileHandle,\r
+  IN     UINTN   FileOffset,\r
+  IN OUT UINTN   *ReadSize,\r
+  OUT    VOID    *Buffer\r
+  )\r
+{\r
+  EFI_STATUS        Status;\r
+  EFI_FILE_HANDLE   File;\r
+    \r
+  File = (EFI_FILE_HANDLE)FileHandle;\r
+  Status = File->SetPosition (File, FileOffset);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  return File->Read (File, ReadSize, Buffer);\r
+}\r
+\r
+\r
+\r
+BOOLEAN\r
+BOpt_IsEfiApp (\r
+  IN EFI_FILE_HANDLE Dir,\r
+  IN UINT16          *FileName\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Check whether current FileName point to a valid Efi Application\r
+  \r
+Arguments:\r
+  Dir       -   Pointer to current Directory\r
+  FileName  -   Pointer to current File name.\r
+  \r
+Returns:\r
+  TRUE      -   Is a valid Efi Application\r
+  FALSE     -   not a valid Efi Application\r
+  \r
+--*/\r
+{\r
+  EFI_STATUS                            Status;\r
+  PE_COFF_LOADER_IMAGE_CONTEXT          ImageContext;\r
+  EFI_FILE_HANDLE                       File;\r
+\r
+  Status = Dir->Open (Dir, &File, FileName, EFI_FILE_MODE_READ, 0);\r
+  if (EFI_ERROR (Status)) {\r
+    return FALSE;\r
+  }\r
+\r
+  ZeroMem (&ImageContext, sizeof (ImageContext));\r
+  ImageContext.Handle    = (VOID *)File;\r
+  ImageContext.ImageRead = IsEfiAppReadFromFile;\r
+\r
+  Status = PeCoffLoaderGetImageInfo (&ImageContext);\r
+  File->Close (File);\r
+  if (EFI_ERROR (Status)) {\r
+    return FALSE;\r
+  }\r
+\r
+  if (ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {\r
+    return TRUE;\r
+  } else {\r
+    return FALSE;\r
+  }\r
+ }\r
+\r
+\r
+EFI_STATUS\r
+BOpt_FindDrivers (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description\r
+  Find drivers that will be added as Driver#### variables from handles\r
+  in current system environment\r
+  All valid handles in the system except those consume SimpleFs, LoadFile\r
+  are stored in DriverMenu for future use.\r
+  \r
+Arguments:\r
+  None\r
+\r
+Returns:\r
+  EFI_SUCCESS\r
+  Others\r
+\r
+--*/\r
+{\r
+  UINTN                           NoDevicePathHandles;\r
+  EFI_HANDLE                      *DevicePathHandle;\r
+  UINTN                           Index;\r
+  EFI_STATUS                      Status;\r
+  BM_MENU_ENTRY                   *NewMenuEntry;\r
+  BM_HANDLE_CONTEXT               *NewHandleContext;\r
+  EFI_HANDLE                      CurHandle;\r
+  UINTN                           OptionNumber;\r
+  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFs;\r
+  EFI_LOAD_FILE_PROTOCOL          *LoadFile;\r
+\r
+  SimpleFs  = NULL;\r
+  LoadFile  = NULL;\r
+\r
+  InitializeListHead (&DriverMenu.Head);\r
+\r
+  //\r
+  // At first, get all handles that support Device Path\r
+  // protocol which is the basic requirement for\r
+  // Driver####\r
+  //\r
+  Status = gBS->LocateHandleBuffer (\r
+                  ByProtocol,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  NULL,\r
+                  &NoDevicePathHandles,\r
+                  &DevicePathHandle\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  OptionNumber = 0;\r
+  for (Index = 0; Index < NoDevicePathHandles; Index++) {\r
+    CurHandle = DevicePathHandle[Index];\r
+\r
+    //\r
+    //  Check whether this handle support\r
+    //  driver binding\r
+    //\r
+    Status = gBS->HandleProtocol (\r
+                    CurHandle,\r
+                    &gEfiSimpleFileSystemProtocolGuid,\r
+                    &SimpleFs\r
+                    );\r
+    if (Status == EFI_SUCCESS) {\r
+      continue;\r
+    }\r
+\r
+    Status = gBS->HandleProtocol (\r
+                    CurHandle,\r
+                    &gEfiLoadFileProtocolGuid,\r
+                    &LoadFile\r
+                    );\r
+    if (Status == EFI_SUCCESS) {\r
+      continue;\r
+    }\r
+\r
+    NewMenuEntry = BOpt_CreateMenuEntry (BM_HANDLE_CONTEXT_SELECT);\r
+    if (NULL == NewMenuEntry) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    NewHandleContext              = (BM_HANDLE_CONTEXT *) NewMenuEntry->VariableContext;\r
+    NewHandleContext->Handle      = CurHandle;\r
+    NewHandleContext->DevicePath  = DevicePathFromHandle (CurHandle);\r
+    NewMenuEntry->DisplayString = DevicePathToStr (NewHandleContext->DevicePath);\r
+    NewMenuEntry->HelpString    = NULL;\r
+    NewMenuEntry->OptionNumber  = OptionNumber;\r
+    OptionNumber++;\r
+    InsertTailList (&DriverMenu.Head, &NewMenuEntry->Link);\r
+\r
+  }\r
+\r
+  DriverMenu.MenuNumber = OptionNumber;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+UINT16\r
+BOpt_GetBootOptionNumber (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Get the Option Number that does not used \r
+  \r
+Arguments:\r
+\r
+Returns:\r
+  The Option Number\r
+  \r
+--*/\r
+{\r
+  BM_MENU_ENTRY *NewMenuEntry;\r
+  UINT16        *BootOrderList;\r
+  UINTN         BootOrderListSize;\r
+  UINT16        Number;\r
+  UINTN         Index;\r
+  UINTN         Index2;\r
+  BOOLEAN       Found;\r
+  CHAR16        StrTemp[100];\r
+  UINT16        *OptionBuffer;\r
+  UINTN         OptionSize;\r
+\r
+  BootOrderListSize = 0;\r
+  BootOrderList     = NULL;\r
+\r
+  BootOrderList = BdsLibGetVariableAndSize (\r
+                    L"BootOrder",\r
+                    &gEfiGlobalVariableGuid,\r
+                    &BootOrderListSize\r
+                    );\r
+  if (BootOrderList) {\r
+    //\r
+    // already have Boot####\r
+    //\r
+    // AlreadyBootNumbers = BootOrderListSize / sizeof(UINT16);\r
+    //\r
+    for (Index = 0; Index < BootOrderListSize / sizeof (UINT16); Index++) {\r
+      Found = TRUE;\r
+      for (Index2 = 0; Index2 < BootOptionMenu.MenuNumber; Index2++) {\r
+        NewMenuEntry = BOpt_GetMenuEntry (&BootOptionMenu, Index2);\r
+        if (Index == NewMenuEntry->OptionNumber) {\r
+          Found = FALSE;\r
+          break;\r
+        }\r
+      }\r
+\r
+      if (Found) {\r
+          UnicodeSPrint (StrTemp, 100, L"Boot%04x", Index);\r
+          DEBUG((EFI_D_ERROR,"INdex= %s\n", StrTemp));\r
+       OptionBuffer = BdsLibGetVariableAndSize (\r
+                StrTemp,\r
+                &gEfiGlobalVariableGuid,\r
+                &OptionSize\r
+                );\r
+      if (NULL == OptionBuffer) \r
+        break;\r
+      }\r
+    }\r
+    //\r
+    // end for Index\r
+    //\r
+    Number = (UINT16) Index;\r
+  } else {\r
+    //\r
+    // No Boot####\r
+    //\r
+    Number = 0;\r
+  }\r
+\r
+  return Number;\r
+}\r
+\r
+UINT16\r
+BOpt_GetDriverOptionNumber (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Get the Option Number that does not used \r
+  \r
+Arguments:\r
+\r
+Returns:\r
+  The Option Number\r
+  \r
+--*/\r
+{\r
+  BM_MENU_ENTRY *NewMenuEntry;\r
+  UINT16        *DriverOrderList;\r
+  UINTN         DriverOrderListSize;\r
+  UINT16        Number;\r
+  UINTN         Index;\r
+  UINTN         Index2;\r
+  BOOLEAN       Found;\r
+\r
+  DriverOrderListSize = 0;\r
+  DriverOrderList     = NULL;\r
+\r
+  DriverOrderList = BdsLibGetVariableAndSize (\r
+                      L"DriverOrder",\r
+                      &gEfiGlobalVariableGuid,\r
+                      &DriverOrderListSize\r
+                      );\r
+  if (DriverOrderList) {\r
+    //\r
+    // already have Driver####\r
+    //\r
+    // AlreadyDriverNumbers = DriverOrderListSize / sizeof(UINT16);\r
+    //\r
+    for (Index = 0; Index < DriverOrderListSize / sizeof (UINT16); Index++) {\r
+      Found = TRUE;\r
+      for (Index2 = 0; Index2 < DriverOptionMenu.MenuNumber; Index2++) {\r
+        NewMenuEntry = BOpt_GetMenuEntry (&DriverOptionMenu, Index2);\r
+        if (Index == NewMenuEntry->OptionNumber) {\r
+          Found = FALSE;\r
+          break;\r
+        }\r
+      }\r
+\r
+      if (Found) {\r
+        break;\r
+      }\r
+    }\r
+    //\r
+    // end for Index\r
+    //\r
+    Number = (UINT16) Index;\r
+  } else {\r
+    //\r
+    // No Driver####\r
+    //\r
+    Number = 0;\r
+  }\r
+\r
+  return Number;\r
+}\r
+\r
+EFI_STATUS\r
+BOpt_GetDriverOptions (\r
+  IN  BMM_CALLBACK_DATA         *CallbackData\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Build up all DriverOptionMenu\r
+  \r
+Arguments:\r
+\r
+Returns:\r
+  The Option Number\r
+  \r
+--*/\r
+{\r
+  UINTN           Index;\r
+  UINT16          DriverString[12];\r
+  UINT8           *LoadOptionFromVar;\r
+  UINT8           *LoadOption;\r
+  UINTN           DriverOptionSize;\r
+\r
+  UINT16          *DriverOrderList;\r
+  UINTN           DriverOrderListSize;\r
+  BM_MENU_ENTRY   *NewMenuEntry;\r
+  BM_LOAD_CONTEXT *NewLoadContext;\r
+  UINT8           *LoadOptionPtr;\r
+  UINTN           StringSize;\r
+  UINTN           OptionalDataSize;\r
+  UINT8           *LoadOptionEnd;\r
+\r
+  DriverOrderListSize = 0;\r
+  DriverOrderList     = NULL;\r
+  DriverOptionSize    = 0;\r
+  LoadOptionFromVar   = NULL;\r
+  BOpt_FreeMenu (&DriverOptionMenu);\r
+  InitializeListHead (&DriverOptionMenu.Head);\r
+  //\r
+  // Get the DriverOrder from the Var\r
+  //\r
+  DriverOrderList = BdsLibGetVariableAndSize (\r
+                      L"DriverOrder",\r
+                      &gEfiGlobalVariableGuid,\r
+                      &DriverOrderListSize\r
+                      );\r
+\r
+  for (Index = 0; Index < DriverOrderListSize / sizeof (UINT16); Index++) {\r
+    UnicodeSPrint (\r
+      DriverString,\r
+      sizeof (DriverString),\r
+      L"Driver%04x",\r
+      DriverOrderList[Index]\r
+      );\r
+    //\r
+    //  Get all loadoptions from the VAR\r
+    //\r
+    LoadOptionFromVar = BdsLibGetVariableAndSize (\r
+                          DriverString,\r
+                          &gEfiGlobalVariableGuid,\r
+                          &DriverOptionSize\r
+                          );\r
+    if (!LoadOptionFromVar) {\r
+      continue;\r
+    }\r
+\r
+    LoadOption = AllocateZeroPool (DriverOptionSize);\r
+    if (!LoadOption) {\r
+      continue;\r
+    }\r
+\r
+    CopyMem (LoadOption, LoadOptionFromVar, DriverOptionSize);\r
+    SafeFreePool (LoadOptionFromVar);\r
+\r
+    NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);\r
+    if (NULL == NewMenuEntry) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    NewLoadContext                      = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;\r
+    LoadOptionPtr                       = LoadOption;\r
+    LoadOptionEnd                       = LoadOption + DriverOptionSize;\r
+    NewMenuEntry->OptionNumber          = DriverOrderList[Index];\r
+    NewLoadContext->LoadOptionModified  = FALSE;\r
+    NewLoadContext->Deleted             = FALSE;\r
+    NewLoadContext->IsLegacy            = FALSE;\r
+\r
+    //\r
+    // LoadOption is a pointer type of UINT8\r
+    // for easy use with following LOAD_OPTION\r
+    // embedded in this struct\r
+    //\r
+    NewLoadContext->LoadOption      = LoadOption;\r
+    NewLoadContext->LoadOptionSize  = DriverOptionSize;\r
+\r
+    NewLoadContext->Attributes      = *(UINT32 *) LoadOptionPtr;\r
+    NewLoadContext->IsActive        = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_ACTIVE);\r
+\r
+    NewLoadContext->ForceReconnect  = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_FORCE_RECONNECT);\r
+\r
+    LoadOptionPtr += sizeof (UINT32);\r
+\r
+    NewLoadContext->FilePathListLength = *(UINT16 *) LoadOptionPtr;\r
+    LoadOptionPtr += sizeof (UINT16);\r
+\r
+    StringSize                  = StrSize ((UINT16 *) LoadOptionPtr);\r
+    NewLoadContext->Description = AllocateZeroPool (StringSize);\r
+    ASSERT (NewLoadContext->Description != NULL);\r
+    CopyMem (\r
+      NewLoadContext->Description,\r
+      (UINT16 *) LoadOptionPtr,\r
+      StringSize\r
+      );\r
+    NewMenuEntry->DisplayString = NewLoadContext->Description;\r
+\r
+    LoadOptionPtr += StringSize;\r
+\r
+    NewLoadContext->FilePathList = AllocateZeroPool (NewLoadContext->FilePathListLength);\r
+    ASSERT (NewLoadContext->FilePathList != NULL);\r
+    CopyMem (\r
+      NewLoadContext->FilePathList,\r
+      (EFI_DEVICE_PATH_PROTOCOL *) LoadOptionPtr,\r
+      NewLoadContext->FilePathListLength\r
+      );\r
+\r
+    NewMenuEntry->HelpString = DevicePathToStr (NewLoadContext->FilePathList);\r
+    NewMenuEntry->DisplayStringToken = GetStringTokenFromDepository (\r
+                                        CallbackData,\r
+                                        DriverOptionStrDepository\r
+                                        );\r
+    NewMenuEntry->HelpStringToken = GetStringTokenFromDepository (\r
+                                      CallbackData,\r
+                                      DriverOptionHelpStrDepository\r
+                                      );\r
+    LoadOptionPtr += NewLoadContext->FilePathListLength;\r
+\r
+    if (LoadOptionPtr < LoadOptionEnd) {\r
+      OptionalDataSize = DriverOptionSize -\r
+        sizeof (UINT32) -\r
+        sizeof (UINT16) -\r
+        StringSize -\r
+        NewLoadContext->FilePathListLength;\r
+\r
+      NewLoadContext->OptionalData = AllocateZeroPool (OptionalDataSize);\r
+      ASSERT (NewLoadContext->OptionalData != NULL);\r
+      CopyMem (\r
+        NewLoadContext->OptionalData,\r
+        LoadOptionPtr,\r
+        OptionalDataSize\r
+        );\r
+\r
+      NewLoadContext->OptionalDataSize = OptionalDataSize;\r
+    }\r
+\r
+    InsertTailList (&DriverOptionMenu.Head, &NewMenuEntry->Link);\r
+\r
+  }\r
+\r
+  SafeFreePool (DriverOrderList);\r
+  DriverOptionMenu.MenuNumber = Index;\r
+  return EFI_SUCCESS;\r
+\r
+}\r
+\r
+VOID\r
+SafeFreePool (\r
+  IN VOID    *Buffer\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Wrap original FreePool gBS call\r
+  in order to decrease code length\r
+  \r
+Arguments:\r
+\r
+Returns:\r
+\r
+--*/\r
+{\r
+  if (Buffer != NULL) {\r
+    gBS->FreePool (Buffer);\r
+    Buffer = NULL;\r
+  }\r
+}\r