--- /dev/null
+/** @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