]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootOption.c
MdeModulePkg:Rename BootMaintenanceManagerLib to BootMaintenanceManagerUiLib
[mirror_edk2.git] / MdeModulePkg / Library / BootMaintenanceManagerUiLib / BootOption.c
diff --git a/MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootOption.c b/MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootOption.c
new file mode 100644 (file)
index 0000000..a375d61
--- /dev/null
@@ -0,0 +1,984 @@
+/** @file\r
+  Provide boot option support for Application "BootMaint"\r
+\r
+  Include file system navigation, system handle selection\r
+\r
+  Boot option manipulation\r
+\r
+Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>\r
+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
+**/\r
+\r
+#include "BootMaintenanceManager.h"\r
+\r
+///\r
+/// Define the maximum characters that will be accepted.\r
+///\r
+#define MAX_CHAR            480\r
+\r
+/**\r
+  Create a menu entry by given menu type.\r
+\r
+  @param MenuType        The Menu type to be created.\r
+\r
+  @retval NULL           If failed to create the menu.\r
+  @return the new menu entry.\r
+\r
+**/\r
+BM_MENU_ENTRY *\r
+BOpt_CreateMenuEntry (\r
+  UINTN           MenuType\r
+  )\r
+{\r
+  BM_MENU_ENTRY *MenuEntry;\r
+  UINTN         ContextSize;\r
+\r
+  //\r
+  // Get context size according to menu type\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
+  default:\r
+    ContextSize = 0;\r
+    break;\r
+  }\r
+\r
+  if (ContextSize == 0) {\r
+    return NULL;\r
+  }\r
+\r
+  //\r
+  // Create new menu entry\r
+  //\r
+  MenuEntry = AllocateZeroPool (sizeof (BM_MENU_ENTRY));\r
+  if (MenuEntry == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  MenuEntry->VariableContext = AllocateZeroPool (ContextSize);\r
+  if (MenuEntry->VariableContext == NULL) {\r
+    FreePool (MenuEntry);\r
+    return NULL;\r
+  }\r
+\r
+  MenuEntry->Signature        = BM_MENU_ENTRY_SIGNATURE;\r
+  MenuEntry->ContextSelection = MenuType;\r
+  return MenuEntry;\r
+}\r
+\r
+/**\r
+  Free up all resource allocated for a BM_MENU_ENTRY.\r
+\r
+  @param MenuEntry   A pointer to BM_MENU_ENTRY.\r
+\r
+**/\r
+VOID\r
+BOpt_DestroyMenuEntry (\r
+  BM_MENU_ENTRY         *MenuEntry\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
+\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
+    FreePool (LoadContext->FilePathList);\r
+    FreePool (LoadContext->LoadOption);\r
+    if (LoadContext->OptionalData != NULL) {\r
+      FreePool (LoadContext->OptionalData);\r
+    }\r
+    FreePool (LoadContext);\r
+    break;\r
+\r
+  case BM_FILE_CONTEXT_SELECT:\r
+    FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;\r
+\r
+    if (!FileContext->IsRoot) {\r
+      FreePool (FileContext->DevicePath);\r
+    } else {\r
+      if (FileContext->FHandle != NULL) {\r
+        FileContext->FHandle->Close (FileContext->FHandle);\r
+      }\r
+    }\r
+\r
+    if (FileContext->FileName != NULL) {\r
+      FreePool (FileContext->FileName);\r
+    }\r
+    if (FileContext->Info != NULL) {\r
+      FreePool (FileContext->Info);\r
+    }\r
+    FreePool (FileContext);\r
+    break;\r
+\r
+  case BM_CONSOLE_CONTEXT_SELECT:\r
+    ConsoleContext = (BM_CONSOLE_CONTEXT *) MenuEntry->VariableContext;\r
+    FreePool (ConsoleContext->DevicePath);\r
+    FreePool (ConsoleContext);\r
+    break;\r
+\r
+  case BM_TERMINAL_CONTEXT_SELECT:\r
+    TerminalContext = (BM_TERMINAL_CONTEXT *) MenuEntry->VariableContext;\r
+    FreePool (TerminalContext->DevicePath);\r
+    FreePool (TerminalContext);\r
+    break;\r
+\r
+  case BM_HANDLE_CONTEXT_SELECT:\r
+    HandleContext = (BM_HANDLE_CONTEXT *) MenuEntry->VariableContext;\r
+    FreePool (HandleContext);\r
+    break;\r
+\r
+  default:\r
+    break;\r
+  }\r
+\r
+  FreePool (MenuEntry->DisplayString);\r
+  if (MenuEntry->HelpString != NULL) {\r
+    FreePool (MenuEntry->HelpString);\r
+  }\r
+\r
+  FreePool (MenuEntry);\r
+}\r
+\r
+/**\r
+  Get the Menu Entry from the list in Menu Entry List.\r
+\r
+  If MenuNumber is great or equal to the number of Menu\r
+  Entry in the list, then ASSERT.\r
+\r
+  @param MenuOption      The Menu Entry List to read the menu entry.\r
+  @param MenuNumber      The index of Menu Entry.\r
+\r
+  @return The Menu Entry.\r
+\r
+**/\r
+BM_MENU_ENTRY *\r
+BOpt_GetMenuEntry (\r
+  BM_MENU_OPTION      *MenuOption,\r
+  UINTN               MenuNumber\r
+  )\r
+{\r
+  BM_MENU_ENTRY   *NewMenuEntry;\r
+  UINTN           Index;\r
+  LIST_ENTRY      *List;\r
+\r
+  ASSERT (MenuNumber < MenuOption->MenuNumber);\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
+/**\r
+  Free resources allocated in Allocate Rountine.\r
+\r
+  @param FreeMenu        Menu to be freed\r
+**/\r
+VOID\r
+BOpt_FreeMenu (\r
+  BM_MENU_OPTION        *FreeMenu\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
+  FreeMenu->MenuNumber = 0;\r
+}\r
+\r
+/**\r
+\r
+  Build the BootOptionMenu according to BootOrder Variable.\r
+  This Routine will access the Boot#### to get EFI_LOAD_OPTION.\r
+\r
+  @param CallbackData The BMM context data.\r
+\r
+  @return EFI_NOT_FOUND Fail to find "BootOrder" variable.\r
+  @return EFI_SUCESS    Success build boot option menu.\r
+\r
+**/\r
+EFI_STATUS\r
+BOpt_GetBootOptions (\r
+  IN  BMM_CALLBACK_DATA         *CallbackData\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
+  EFI_BOOT_MANAGER_LOAD_OPTION  *BootOption;\r
+  UINTN                         BootOptionCount;  \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
+  GetEfiGlobalVariable2 (L"BootOrder", (VOID **) &BootOrderList, &BootOrderListSize);\r
+  if (BootOrderList == NULL) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+  \r
+  //\r
+  // Get the BootNext from the Var\r
+  //\r
+  GetEfiGlobalVariable2 (L"BootNext", (VOID **) &BootNext, &BootNextSize);\r
+  if (BootNext != NULL) {\r
+    if (BootNextSize != sizeof (UINT16)) {\r
+      FreePool (BootNext);\r
+      BootNext = NULL;\r
+    }\r
+  }\r
+  BootOption = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);\r
+  for (Index = 0; Index < BootOrderListSize / sizeof (UINT16); Index++) {\r
+    //\r
+    // Don't display the hidden/inactive boot option\r
+    //\r
+    if (((BootOption[Index].Attributes & LOAD_OPTION_HIDDEN) != 0) || ((BootOption[Index].Attributes & LOAD_OPTION_ACTIVE) == 0)) {\r
+      continue;\r
+    }\r
+      \r
+    UnicodeSPrint (BootString, sizeof (BootString), L"Boot%04x", BootOrderList[Index]);\r
+    //\r
+    //  Get all loadoptions from the VAR\r
+    //\r
+    GetEfiGlobalVariable2 (BootString, (VOID **) &LoadOptionFromVar, &BootOptionSize);\r
+    if (LoadOptionFromVar == NULL) {\r
+      continue;\r
+    }\r
+\r
+    LoadOption = AllocateZeroPool (BootOptionSize);\r
+    if (LoadOption == NULL) {\r
+      continue;\r
+    }\r
+\r
+    CopyMem (LoadOption, LoadOptionFromVar, BootOptionSize);\r
+    FreePool (LoadOptionFromVar);\r
+\r
+    if (BootNext != NULL) {\r
+      BootNextFlag = (BOOLEAN) (*BootNext == BootOrderList[Index]);\r
+    } else {\r
+      BootNextFlag = FALSE;\r
+    }\r
+\r
+    NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);\r
+    ASSERT (NULL != NewMenuEntry);\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
+\r
+    NewLoadContext->Description = AllocateZeroPool (StrSize((UINT16*)LoadOptionPtr));\r
+    ASSERT (NewLoadContext->Description != NULL);\r
+    StrCpyS (NewLoadContext->Description, StrSize((UINT16*)LoadOptionPtr) / sizeof (UINT16), (UINT16*)LoadOptionPtr);\r
+    \r
+    ASSERT (NewLoadContext->Description != NULL);\r
+    NewMenuEntry->DisplayString = NewLoadContext->Description;\r
+    NewMenuEntry->DisplayStringToken = HiiSetString (CallbackData->BmmHiiHandle, 0, NewMenuEntry->DisplayString, NULL);\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 = UiDevicePathToStr (NewLoadContext->FilePathList);\r
+    NewMenuEntry->HelpStringToken = HiiSetString (CallbackData->BmmHiiHandle, 0, NewMenuEntry->HelpString, NULL); \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
+  EfiBootManagerFreeLoadOptions (BootOption, BootOptionCount);\r
+\r
+  if (BootNext != NULL) {\r
+    FreePool (BootNext);\r
+  }\r
+  if (BootOrderList != NULL) {\r
+    FreePool (BootOrderList);\r
+  }\r
+  BootOptionMenu.MenuNumber = MenuCount;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+\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
+  @retval EFI_SUCCESS The function complets successfully.\r
+  @return Other value if failed to build the DriverMenu.\r
+\r
+**/\r
+EFI_STATUS\r
+BOpt_FindDrivers (\r
+  VOID\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
+    Status = gBS->HandleProtocol (\r
+                    CurHandle,\r
+                    &gEfiSimpleFileSystemProtocolGuid,\r
+                    (VOID **) &SimpleFs\r
+                    );\r
+    if (Status == EFI_SUCCESS) {\r
+      continue;\r
+    }\r
+\r
+    Status = gBS->HandleProtocol (\r
+                    CurHandle,\r
+                    &gEfiLoadFileProtocolGuid,\r
+                    (VOID **) &LoadFile\r
+                    );\r
+    if (Status == EFI_SUCCESS) {\r
+      continue;\r
+    }\r
+\r
+    NewMenuEntry = BOpt_CreateMenuEntry (BM_HANDLE_CONTEXT_SELECT);\r
+    if (NULL == NewMenuEntry) {\r
+      FreePool (DevicePathHandle);\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 = UiDevicePathToStr (NewHandleContext->DevicePath);\r
+    NewMenuEntry->DisplayStringToken = HiiSetString (mBmmCallbackInfo->BmmHiiHandle,0,NewMenuEntry->DisplayString,NULL);\r
+    NewMenuEntry->HelpString    = NULL;\r
+    NewMenuEntry->HelpStringToken = NewMenuEntry->DisplayStringToken;\r
+    NewMenuEntry->OptionNumber  = OptionNumber;\r
+    OptionNumber++;\r
+    InsertTailList (&DriverMenu.Head, &NewMenuEntry->Link);\r
+\r
+  }\r
+\r
+  if (DevicePathHandle != NULL) {\r
+    FreePool (DevicePathHandle);\r
+  }\r
+\r
+  DriverMenu.MenuNumber = OptionNumber;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+\r
+  Get the Option Number that has not been allocated for use.\r
+\r
+  @param Type  The type of Option.\r
+\r
+  @return The available Option Number.\r
+\r
+**/\r
+UINT16\r
+BOpt_GetOptionNumber (\r
+  CHAR16        *Type\r
+  )\r
+{\r
+  UINT16        *OrderList;\r
+  UINTN         OrderListSize;\r
+  UINTN         Index;\r
+  CHAR16        StrTemp[20];\r
+  UINT16        *OptionBuffer;\r
+  UINT16        OptionNumber;\r
+  UINTN         OptionSize;\r
+\r
+  OrderListSize = 0;\r
+  OrderList     = NULL;\r
+  OptionNumber  = 0;\r
+  Index         = 0;\r
+\r
+  UnicodeSPrint (StrTemp, sizeof (StrTemp), L"%sOrder", Type);\r
+\r
+  GetEfiGlobalVariable2 (StrTemp, (VOID **) &OrderList, &OrderListSize);\r
+  for (OptionNumber = 0; ; OptionNumber++) {\r
+    if (OrderList != NULL) {\r
+      for (Index = 0; Index < OrderListSize / sizeof (UINT16); Index++) {\r
+        if (OptionNumber == OrderList[Index]) {\r
+          break;\r
+        }\r
+      }\r
+    }\r
+\r
+    if (Index < OrderListSize / sizeof (UINT16)) {\r
+      //\r
+      // The OptionNumber occurs in the OrderList, continue to use next one\r
+      //\r
+      continue;\r
+    }\r
+    UnicodeSPrint (StrTemp, sizeof (StrTemp), L"%s%04x", Type, (UINTN) OptionNumber);\r
+    DEBUG((EFI_D_ERROR,"Option = %s\n", StrTemp));\r
+    GetEfiGlobalVariable2 (StrTemp, (VOID **) &OptionBuffer, &OptionSize);\r
+    if (NULL == OptionBuffer) {\r
+      //\r
+      // The Boot[OptionNumber] / Driver[OptionNumber] NOT occurs, we found it\r
+      //\r
+      break;\r
+    }\r
+  }\r
+\r
+  return OptionNumber;\r
+}\r
+\r
+/**\r
+\r
+  Get the Option Number for Boot#### that does not used.\r
+\r
+  @return The available Option Number.\r
+\r
+**/\r
+UINT16\r
+BOpt_GetBootOptionNumber (\r
+  VOID\r
+  )\r
+{\r
+  return BOpt_GetOptionNumber (L"Boot");\r
+}\r
+\r
+/**\r
+\r
+  Get the Option Number for Driver#### that does not used.\r
+\r
+  @return The unused Option Number.\r
+\r
+**/\r
+UINT16\r
+BOpt_GetDriverOptionNumber (\r
+  VOID\r
+  )\r
+{\r
+  return BOpt_GetOptionNumber (L"Driver");\r
+}\r
+\r
+/**\r
+\r
+  Build up all DriverOptionMenu\r
+\r
+  @param CallbackData The BMM context data.\r
+\r
+  @retval EFI_SUCESS           The functin completes successfully.\r
+  @retval EFI_OUT_OF_RESOURCES Not enough memory to compete the operation.\r
+  @retval EFI_NOT_FOUND        Fail to get "DriverOrder" variable.\r
+\r
+**/\r
+EFI_STATUS\r
+BOpt_GetDriverOptions (\r
+  IN  BMM_CALLBACK_DATA         *CallbackData\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
+  GetEfiGlobalVariable2 (L"DriverOrder", (VOID **) &DriverOrderList, &DriverOrderListSize);\r
+  if (DriverOrderList == NULL) {\r
+    return EFI_NOT_FOUND;\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
+    GetEfiGlobalVariable2 (DriverString, (VOID **) &LoadOptionFromVar, &DriverOptionSize);\r
+    if (LoadOptionFromVar == NULL) {\r
+      continue;\r
+    }\r
+\r
+    LoadOption = AllocateZeroPool (DriverOptionSize);\r
+    if (LoadOption == NULL) {\r
+      continue;\r
+    }\r
+\r
+    CopyMem (LoadOption, LoadOptionFromVar, DriverOptionSize);\r
+    FreePool (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
+    NewMenuEntry->DisplayStringToken = HiiSetString (CallbackData->BmmHiiHandle, 0, NewMenuEntry->DisplayString, NULL);\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 = UiDevicePathToStr (NewLoadContext->FilePathList);\r
+    NewMenuEntry->HelpStringToken = HiiSetString (CallbackData->BmmHiiHandle, 0, NewMenuEntry->HelpString, NULL); \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
+  if (DriverOrderList != NULL) {\r
+    FreePool (DriverOrderList);\r
+  }\r
+  DriverOptionMenu.MenuNumber = Index;\r
+  return EFI_SUCCESS;\r
+\r
+}\r
+\r
+/**\r
+  Get option number according to Boot#### and BootOrder variable. \r
+  The value is saved as #### + 1.\r
+\r
+  @param CallbackData    The BMM context data.\r
+**/\r
+VOID  \r
+GetBootOrder (\r
+  IN  BMM_CALLBACK_DATA    *CallbackData\r
+  )\r
+{\r
+  BMM_FAKE_NV_DATA          *BmmConfig;\r
+  UINT16                    Index;\r
+  UINT16                    OptionOrderIndex; \r
+  UINTN                     DeviceType;\r
+  BM_MENU_ENTRY             *NewMenuEntry;\r
+  BM_LOAD_CONTEXT           *NewLoadContext;  \r
+\r
+  ASSERT (CallbackData != NULL);\r
+  \r
+  DeviceType = (UINTN) -1;   \r
+  BmmConfig  = &CallbackData->BmmFakeNvData;  \r
+  ZeroMem (BmmConfig->BootOptionOrder, sizeof (BmmConfig->BootOptionOrder));\r
+  \r
+  for (Index = 0, OptionOrderIndex = 0; ((Index < BootOptionMenu.MenuNumber) &&\r
+       (OptionOrderIndex < (sizeof (BmmConfig->BootOptionOrder) / sizeof (BmmConfig->BootOptionOrder[0]))));\r
+       Index++) {\r
+    NewMenuEntry   = BOpt_GetMenuEntry (&BootOptionMenu, Index);\r
+    NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;\r
+\r
+    if (NewLoadContext->IsLegacy) {\r
+      if (((BBS_BBS_DEVICE_PATH *) NewLoadContext->FilePathList)->DeviceType != DeviceType) {\r
+        DeviceType = ((BBS_BBS_DEVICE_PATH *) NewLoadContext->FilePathList)->DeviceType;\r
+      } else {\r
+        //\r
+        // Only show one legacy boot option for the same device type\r
+        // assuming the boot options are grouped by the device type\r
+        //\r
+        continue;\r
+      }\r
+    }\r
+    BmmConfig->BootOptionOrder[OptionOrderIndex++] = (UINT32) (NewMenuEntry->OptionNumber + 1);\r
+  }  \r
+}\r
+\r
+/**\r
+  Get driver option order from globalc DriverOptionMenu.\r
+\r
+  @param CallbackData    The BMM context data.\r
+  \r
+**/\r
+VOID  \r
+GetDriverOrder (\r
+  IN  BMM_CALLBACK_DATA    *CallbackData\r
+  )\r
+{\r
+  BMM_FAKE_NV_DATA          *BmmConfig;\r
+  UINT16                    Index;\r
+  UINT16                    OptionOrderIndex; \r
+  UINTN                     DeviceType;\r
+  BM_MENU_ENTRY             *NewMenuEntry;\r
+  BM_LOAD_CONTEXT           *NewLoadContext;  \r
+\r
+\r
+  ASSERT (CallbackData != NULL);\r
+  \r
+  DeviceType = (UINTN) -1;   \r
+  BmmConfig  = &CallbackData->BmmFakeNvData;  \r
+  ZeroMem (BmmConfig->DriverOptionOrder, sizeof (BmmConfig->DriverOptionOrder));\r
+  \r
+  for (Index = 0, OptionOrderIndex = 0; ((Index < DriverOptionMenu.MenuNumber) &&\r
+       (OptionOrderIndex < (sizeof (BmmConfig->DriverOptionOrder) / sizeof (BmmConfig->DriverOptionOrder[0]))));\r
+       Index++) {\r
+    NewMenuEntry   = BOpt_GetMenuEntry (&DriverOptionMenu, Index);\r
+    NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;\r
+\r
+    if (NewLoadContext->IsLegacy) {\r
+      if (((BBS_BBS_DEVICE_PATH *) NewLoadContext->FilePathList)->DeviceType != DeviceType) {\r
+        DeviceType = ((BBS_BBS_DEVICE_PATH *) NewLoadContext->FilePathList)->DeviceType;\r
+      } else {\r
+        //\r
+        // Only show one legacy boot option for the same device type\r
+        // assuming the boot options are grouped by the device type\r
+        //\r
+        continue;\r
+      }\r
+    }\r
+    BmmConfig->DriverOptionOrder[OptionOrderIndex++] = (UINT32) (NewMenuEntry->OptionNumber + 1);\r
+  }  \r
+}  \r
+\r
+/**\r
+  Boot the file specified by the input file path info.\r
+\r
+  @param FilePath    Point to the file path.\r
+\r
+  @retval TRUE   Exit caller function.\r
+  @retval FALSE  Not exit caller function.\r
+**/\r
+BOOLEAN \r
+BootFromFile (\r
+  IN EFI_DEVICE_PATH_PROTOCOL    *FilePath\r
+  )\r
+{\r
+  EFI_BOOT_MANAGER_LOAD_OPTION BootOption;\r
+  CHAR16                       *FileName;\r
+\r
+  FileName = ExtractFileNameFromDevicePath(FilePath);\r
+  EfiBootManagerInitializeLoadOption (\r
+    &BootOption,\r
+    0,\r
+    LoadOptionTypeBoot,\r
+    LOAD_OPTION_ACTIVE,\r
+    FileName,\r
+    FilePath,\r
+    NULL,\r
+    0\r
+    );\r
+  //\r
+  // Since current no boot from removable media directly is allowed */\r
+  //\r
+  gST->ConOut->ClearScreen (gST->ConOut);\r
+\r
+  BmmBdsSetConsoleMode (FALSE);\r
+  EfiBootManagerBoot (&BootOption);\r
+  BmmBdsSetConsoleMode (TRUE);\r
+\r
+  FreePool(FileName);\r
+\r
+  EfiBootManagerFreeLoadOption (&BootOption);\r
+\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  Display the form base on the selected file.\r
+\r
+  @param FilePath   Point to the file path.\r
+  @param FormId     The form need to display.\r
+\r
+**/\r
+BOOLEAN\r
+ReSendForm(\r
+  IN  EFI_DEVICE_PATH_PROTOCOL  *FilePath,\r
+  IN  EFI_FORM_ID               FormId\r
+  )\r
+{\r
+  gBootMaintenancePrivate.LoadContext->FilePathList = FilePath;\r
+\r
+  UpdateOptionPage(&gBootMaintenancePrivate, FormId, FilePath);\r
+\r
+  gBootMaintenancePrivate.FormBrowser2->SendForm (\r
+                         gBootMaintenancePrivate.FormBrowser2,\r
+                         &gBootMaintenancePrivate.BmmHiiHandle,\r
+                         1,\r
+                         &mBootMaintGuid,\r
+                         FormId,\r
+                         NULL,\r
+                         NULL\r
+                         );\r
+  return TRUE;\r
+}\r
+\r
+/**\r
+  Create boot option base on the input file path info.\r
+\r
+  @param FilePath    Point to the file path.\r
+\r
+  @retval TRUE   Exit caller function.\r
+  @retval FALSE  Not exit caller function.\r
+**/\r
+BOOLEAN \r
+CreateBootOptionFromFile (\r
+  IN EFI_DEVICE_PATH_PROTOCOL    *FilePath\r
+  )\r
+{\r
+  return ReSendForm(FilePath, FORM_BOOT_ADD_ID);\r
+}\r
+\r
+/**\r
+  Create driver option base on the input file path info.\r
+\r
+  @param FilePath    Point to the file path.\r
+\r
+  @retval TRUE   Exit caller function.\r
+  @retval FALSE  Not exit caller function.\r
+\r
+**/\r
+BOOLEAN \r
+CreateDriverOptionFromFile (\r
+  IN EFI_DEVICE_PATH_PROTOCOL    *FilePath\r
+  )\r
+{\r
+  return ReSendForm(FilePath, FORM_DRV_ADD_FILE_ID);\r
+}\r
+\r