--- /dev/null
+/*++\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
+ (VOID**) &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
+ (VOID**) &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
+ (VOID**) &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
+ (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
+ 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