Fixes CodeQL alerts for CWE-457: https://cwe.mitre.org/data/definitions/457.html Cc: Dandan Bi <dandan.bi@intel.com> Cc: Eric Dong <eric.dong@intel.com> Cc: Erich McMillan <emcmillan@microsoft.com> Cc: Guomin Jiang <guomin.jiang@intel.com> Cc: Jian J Wang <jian.j.wang@intel.com> Cc: Liming Gao <gaoliming@byosoft.com.cn> Cc: Michael Kubacki <mikuback@linux.microsoft.com> Cc: Ray Ni <ray.ni@intel.com> Cc: Zhichao Gao <zhichao.gao@intel.com> Co-authored-by: Erich McMillan <emcmillan@microsoft.com> Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com> Reviewed-by: Liming Gao <gaoliming@byosoft.com.cn> Reviewed-by: Oliver Smith-Denny <osd@smith-denny.com>
		
			
				
	
	
		
			1018 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1018 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   Provide boot option support for Application "BootMaint"
 | |
| 
 | |
|   Include file system navigation, system handle selection
 | |
| 
 | |
|   Boot option manipulation
 | |
| 
 | |
| Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
 | |
| SPDX-License-Identifier: BSD-2-Clause-Patent
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include "BootMaintenanceManager.h"
 | |
| 
 | |
| ///
 | |
| /// Define the maximum characters that will be accepted.
 | |
| ///
 | |
| #define MAX_CHAR  480
 | |
| 
 | |
| /**
 | |
| 
 | |
|   Check whether a reset is needed, if reset is needed, Popup a menu to notice user.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| BmmSetupResetReminder (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   EFI_INPUT_KEY                           Key;
 | |
|   CHAR16                                  *StringBuffer1;
 | |
|   CHAR16                                  *StringBuffer2;
 | |
|   EFI_STATUS                              Status;
 | |
|   EDKII_FORM_BROWSER_EXTENSION2_PROTOCOL  *FormBrowserEx2;
 | |
| 
 | |
|   //
 | |
|   // Use BrowserEx2 protocol to check whether reset is required.
 | |
|   //
 | |
|   Status = gBS->LocateProtocol (&gEdkiiFormBrowserEx2ProtocolGuid, NULL, (VOID **)&FormBrowserEx2);
 | |
| 
 | |
|   //
 | |
|   // check any reset required change is applied? if yes, reset system
 | |
|   //
 | |
|   if (!EFI_ERROR (Status) && FormBrowserEx2->IsResetRequired ()) {
 | |
|     StringBuffer1 = AllocateZeroPool (MAX_CHAR * sizeof (CHAR16));
 | |
|     ASSERT (StringBuffer1 != NULL);
 | |
|     StringBuffer2 = AllocateZeroPool (MAX_CHAR * sizeof (CHAR16));
 | |
|     ASSERT (StringBuffer2 != NULL);
 | |
|     StrCpyS (StringBuffer1, MAX_CHAR, L"Configuration changed. Reset to apply it Now.");
 | |
|     StrCpyS (StringBuffer2, MAX_CHAR, L"Press ENTER to reset");
 | |
|     //
 | |
|     // Popup a menu to notice user
 | |
|     //
 | |
|     do {
 | |
|       CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, StringBuffer1, StringBuffer2, NULL);
 | |
|     } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
 | |
| 
 | |
|     FreePool (StringBuffer1);
 | |
|     FreePool (StringBuffer2);
 | |
| 
 | |
|     gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Create a menu entry by given menu type.
 | |
| 
 | |
|   @param MenuType        The Menu type to be created.
 | |
| 
 | |
|   @retval NULL           If failed to create the menu.
 | |
|   @return the new menu entry.
 | |
| 
 | |
| **/
 | |
| BM_MENU_ENTRY *
 | |
| BOpt_CreateMenuEntry (
 | |
|   UINTN  MenuType
 | |
|   )
 | |
| {
 | |
|   BM_MENU_ENTRY  *MenuEntry;
 | |
|   UINTN          ContextSize;
 | |
| 
 | |
|   //
 | |
|   // Get context size according to menu type
 | |
|   //
 | |
|   switch (MenuType) {
 | |
|     case BM_LOAD_CONTEXT_SELECT:
 | |
|       ContextSize = sizeof (BM_LOAD_CONTEXT);
 | |
|       break;
 | |
| 
 | |
|     case BM_FILE_CONTEXT_SELECT:
 | |
|       ContextSize = sizeof (BM_FILE_CONTEXT);
 | |
|       break;
 | |
| 
 | |
|     case BM_CONSOLE_CONTEXT_SELECT:
 | |
|       ContextSize = sizeof (BM_CONSOLE_CONTEXT);
 | |
|       break;
 | |
| 
 | |
|     case BM_TERMINAL_CONTEXT_SELECT:
 | |
|       ContextSize = sizeof (BM_TERMINAL_CONTEXT);
 | |
|       break;
 | |
| 
 | |
|     case BM_HANDLE_CONTEXT_SELECT:
 | |
|       ContextSize = sizeof (BM_HANDLE_CONTEXT);
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       ContextSize = 0;
 | |
|       break;
 | |
|   }
 | |
| 
 | |
|   if (ContextSize == 0) {
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Create new menu entry
 | |
|   //
 | |
|   MenuEntry = AllocateZeroPool (sizeof (BM_MENU_ENTRY));
 | |
|   if (MenuEntry == NULL) {
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   MenuEntry->VariableContext = AllocateZeroPool (ContextSize);
 | |
|   if (MenuEntry->VariableContext == NULL) {
 | |
|     FreePool (MenuEntry);
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   MenuEntry->Signature        = BM_MENU_ENTRY_SIGNATURE;
 | |
|   MenuEntry->ContextSelection = MenuType;
 | |
|   return MenuEntry;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Free up all resource allocated for a BM_MENU_ENTRY.
 | |
| 
 | |
|   @param MenuEntry   A pointer to BM_MENU_ENTRY.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| BOpt_DestroyMenuEntry (
 | |
|   BM_MENU_ENTRY  *MenuEntry
 | |
|   )
 | |
| {
 | |
|   BM_LOAD_CONTEXT      *LoadContext;
 | |
|   BM_FILE_CONTEXT      *FileContext;
 | |
|   BM_CONSOLE_CONTEXT   *ConsoleContext;
 | |
|   BM_TERMINAL_CONTEXT  *TerminalContext;
 | |
|   BM_HANDLE_CONTEXT    *HandleContext;
 | |
| 
 | |
|   //
 | |
|   //  Select by the type in Menu entry for current context type
 | |
|   //
 | |
|   switch (MenuEntry->ContextSelection) {
 | |
|     case BM_LOAD_CONTEXT_SELECT:
 | |
|       LoadContext = (BM_LOAD_CONTEXT *)MenuEntry->VariableContext;
 | |
|       FreePool (LoadContext->FilePathList);
 | |
|       if (LoadContext->OptionalData != NULL) {
 | |
|         FreePool (LoadContext->OptionalData);
 | |
|       }
 | |
| 
 | |
|       FreePool (LoadContext);
 | |
|       break;
 | |
| 
 | |
|     case BM_FILE_CONTEXT_SELECT:
 | |
|       FileContext = (BM_FILE_CONTEXT *)MenuEntry->VariableContext;
 | |
| 
 | |
|       if (!FileContext->IsRoot) {
 | |
|         FreePool (FileContext->DevicePath);
 | |
|       } else {
 | |
|         if (FileContext->FHandle != NULL) {
 | |
|           FileContext->FHandle->Close (FileContext->FHandle);
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       if (FileContext->FileName != NULL) {
 | |
|         FreePool (FileContext->FileName);
 | |
|       }
 | |
| 
 | |
|       if (FileContext->Info != NULL) {
 | |
|         FreePool (FileContext->Info);
 | |
|       }
 | |
| 
 | |
|       FreePool (FileContext);
 | |
|       break;
 | |
| 
 | |
|     case BM_CONSOLE_CONTEXT_SELECT:
 | |
|       ConsoleContext = (BM_CONSOLE_CONTEXT *)MenuEntry->VariableContext;
 | |
|       FreePool (ConsoleContext->DevicePath);
 | |
|       FreePool (ConsoleContext);
 | |
|       break;
 | |
| 
 | |
|     case BM_TERMINAL_CONTEXT_SELECT:
 | |
|       TerminalContext = (BM_TERMINAL_CONTEXT *)MenuEntry->VariableContext;
 | |
|       FreePool (TerminalContext->DevicePath);
 | |
|       FreePool (TerminalContext);
 | |
|       break;
 | |
| 
 | |
|     case BM_HANDLE_CONTEXT_SELECT:
 | |
|       HandleContext = (BM_HANDLE_CONTEXT *)MenuEntry->VariableContext;
 | |
|       FreePool (HandleContext);
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       break;
 | |
|   }
 | |
| 
 | |
|   FreePool (MenuEntry->DisplayString);
 | |
|   if (MenuEntry->HelpString != NULL) {
 | |
|     FreePool (MenuEntry->HelpString);
 | |
|   }
 | |
| 
 | |
|   FreePool (MenuEntry);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get the Menu Entry from the list in Menu Entry List.
 | |
| 
 | |
|   If MenuNumber is great or equal to the number of Menu
 | |
|   Entry in the list, then ASSERT.
 | |
| 
 | |
|   @param MenuOption      The Menu Entry List to read the menu entry.
 | |
|   @param MenuNumber      The index of Menu Entry.
 | |
| 
 | |
|   @return The Menu Entry.
 | |
| 
 | |
| **/
 | |
| BM_MENU_ENTRY *
 | |
| BOpt_GetMenuEntry (
 | |
|   BM_MENU_OPTION  *MenuOption,
 | |
|   UINTN           MenuNumber
 | |
|   )
 | |
| {
 | |
|   BM_MENU_ENTRY  *NewMenuEntry;
 | |
|   UINTN          Index;
 | |
|   LIST_ENTRY     *List;
 | |
| 
 | |
|   ASSERT (MenuNumber < MenuOption->MenuNumber);
 | |
| 
 | |
|   List = MenuOption->Head.ForwardLink;
 | |
|   for (Index = 0; Index < MenuNumber; Index++) {
 | |
|     List = List->ForwardLink;
 | |
|   }
 | |
| 
 | |
|   NewMenuEntry = CR (List, BM_MENU_ENTRY, Link, BM_MENU_ENTRY_SIGNATURE);
 | |
| 
 | |
|   return NewMenuEntry;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Free resources allocated in Allocate Rountine.
 | |
| 
 | |
|   @param FreeMenu        Menu to be freed
 | |
| **/
 | |
| VOID
 | |
| BOpt_FreeMenu (
 | |
|   BM_MENU_OPTION  *FreeMenu
 | |
|   )
 | |
| {
 | |
|   BM_MENU_ENTRY  *MenuEntry;
 | |
| 
 | |
|   while (!IsListEmpty (&FreeMenu->Head)) {
 | |
|     MenuEntry = CR (
 | |
|                   FreeMenu->Head.ForwardLink,
 | |
|                   BM_MENU_ENTRY,
 | |
|                   Link,
 | |
|                   BM_MENU_ENTRY_SIGNATURE
 | |
|                   );
 | |
|     RemoveEntryList (&MenuEntry->Link);
 | |
|     BOpt_DestroyMenuEntry (MenuEntry);
 | |
|   }
 | |
| 
 | |
|   FreeMenu->MenuNumber = 0;
 | |
| }
 | |
| 
 | |
| /**
 | |
| 
 | |
|   Build the BootOptionMenu according to BootOrder Variable.
 | |
|   This Routine will access the Boot#### to get EFI_LOAD_OPTION.
 | |
| 
 | |
|   @param CallbackData The BMM context data.
 | |
| 
 | |
|   @return EFI_NOT_FOUND Fail to find "BootOrder" variable.
 | |
|   @return EFI_SUCESS    Success build boot option menu.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| BOpt_GetBootOptions (
 | |
|   IN  BMM_CALLBACK_DATA  *CallbackData
 | |
|   )
 | |
| {
 | |
|   UINTN                         Index;
 | |
|   UINT16                        BootString[10];
 | |
|   UINT8                         *LoadOptionFromVar;
 | |
|   UINTN                         BootOptionSize;
 | |
|   BOOLEAN                       BootNextFlag;
 | |
|   UINT16                        *BootOrderList;
 | |
|   UINTN                         BootOrderListSize;
 | |
|   UINT16                        *BootNext;
 | |
|   UINTN                         BootNextSize;
 | |
|   BM_MENU_ENTRY                 *NewMenuEntry;
 | |
|   BM_LOAD_CONTEXT               *NewLoadContext;
 | |
|   UINT8                         *LoadOptionPtr;
 | |
|   UINTN                         StringSize;
 | |
|   UINTN                         OptionalDataSize;
 | |
|   UINT8                         *LoadOptionEnd;
 | |
|   EFI_DEVICE_PATH_PROTOCOL      *DevicePath;
 | |
|   UINTN                         MenuCount;
 | |
|   UINT8                         *Ptr;
 | |
|   EFI_BOOT_MANAGER_LOAD_OPTION  *BootOption;
 | |
|   UINTN                         BootOptionCount;
 | |
| 
 | |
|   MenuCount         = 0;
 | |
|   BootOrderListSize = 0;
 | |
|   BootNextSize      = 0;
 | |
|   BootOrderList     = NULL;
 | |
|   BootNext          = NULL;
 | |
|   LoadOptionFromVar = NULL;
 | |
|   BOpt_FreeMenu (&BootOptionMenu);
 | |
|   InitializeListHead (&BootOptionMenu.Head);
 | |
| 
 | |
|   //
 | |
|   // Get the BootOrder from the Var
 | |
|   //
 | |
|   GetEfiGlobalVariable2 (L"BootOrder", (VOID **)&BootOrderList, &BootOrderListSize);
 | |
|   if (BootOrderList == NULL) {
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Get the BootNext from the Var
 | |
|   //
 | |
|   GetEfiGlobalVariable2 (L"BootNext", (VOID **)&BootNext, &BootNextSize);
 | |
|   if (BootNext != NULL) {
 | |
|     if (BootNextSize != sizeof (UINT16)) {
 | |
|       FreePool (BootNext);
 | |
|       BootNext = NULL;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   BootOption = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
 | |
|   for (Index = 0; Index < BootOrderListSize / sizeof (UINT16); Index++) {
 | |
|     //
 | |
|     // Don't display the hidden/inactive boot option
 | |
|     //
 | |
|     if (((BootOption[Index].Attributes & LOAD_OPTION_HIDDEN) != 0) || ((BootOption[Index].Attributes & LOAD_OPTION_ACTIVE) == 0)) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     UnicodeSPrint (BootString, sizeof (BootString), L"Boot%04x", BootOrderList[Index]);
 | |
|     //
 | |
|     //  Get all loadoptions from the VAR
 | |
|     //
 | |
|     GetEfiGlobalVariable2 (BootString, (VOID **)&LoadOptionFromVar, &BootOptionSize);
 | |
|     if (LoadOptionFromVar == NULL) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     if (BootNext != NULL) {
 | |
|       BootNextFlag = (BOOLEAN)(*BootNext == BootOrderList[Index]);
 | |
|     } else {
 | |
|       BootNextFlag = FALSE;
 | |
|     }
 | |
| 
 | |
|     NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);
 | |
|     ASSERT (NULL != NewMenuEntry);
 | |
| 
 | |
|     NewLoadContext = (BM_LOAD_CONTEXT *)NewMenuEntry->VariableContext;
 | |
| 
 | |
|     LoadOptionPtr = LoadOptionFromVar;
 | |
|     LoadOptionEnd = LoadOptionFromVar + BootOptionSize;
 | |
| 
 | |
|     NewMenuEntry->OptionNumber = BootOrderList[Index];
 | |
|     NewLoadContext->Deleted    = FALSE;
 | |
|     NewLoadContext->IsBootNext = BootNextFlag;
 | |
| 
 | |
|     //
 | |
|     // Is a Legacy Device?
 | |
|     //
 | |
|     Ptr = (UINT8 *)LoadOptionFromVar;
 | |
| 
 | |
|     //
 | |
|     // Attribute = *(UINT32 *)Ptr;
 | |
|     //
 | |
|     Ptr += sizeof (UINT32);
 | |
| 
 | |
|     //
 | |
|     // FilePathSize = *(UINT16 *)Ptr;
 | |
|     //
 | |
|     Ptr += sizeof (UINT16);
 | |
| 
 | |
|     //
 | |
|     // Description = (CHAR16 *)Ptr;
 | |
|     //
 | |
|     Ptr += StrSize ((CHAR16 *)Ptr);
 | |
| 
 | |
|     //
 | |
|     // Now Ptr point to Device Path
 | |
|     //
 | |
|     DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)Ptr;
 | |
|     if ((BBS_DEVICE_PATH == DevicePath->Type) && (BBS_BBS_DP == DevicePath->SubType)) {
 | |
|       NewLoadContext->IsLegacy = TRUE;
 | |
|     } else {
 | |
|       NewLoadContext->IsLegacy = FALSE;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // LoadOption is a pointer type of UINT8
 | |
|     // for easy use with following LOAD_OPTION
 | |
|     // embedded in this struct
 | |
|     //
 | |
| 
 | |
|     NewLoadContext->Attributes = *(UINT32 *)LoadOptionPtr;
 | |
| 
 | |
|     LoadOptionPtr += sizeof (UINT32);
 | |
| 
 | |
|     NewLoadContext->FilePathListLength = *(UINT16 *)LoadOptionPtr;
 | |
|     LoadOptionPtr                     += sizeof (UINT16);
 | |
| 
 | |
|     StringSize = StrSize ((UINT16 *)LoadOptionPtr);
 | |
| 
 | |
|     NewLoadContext->Description = AllocateZeroPool (StrSize ((UINT16 *)LoadOptionPtr));
 | |
|     ASSERT (NewLoadContext->Description != NULL);
 | |
|     StrCpyS (NewLoadContext->Description, StrSize ((UINT16 *)LoadOptionPtr) / sizeof (UINT16), (UINT16 *)LoadOptionPtr);
 | |
| 
 | |
|     ASSERT (NewLoadContext->Description != NULL);
 | |
|     NewMenuEntry->DisplayString      = NewLoadContext->Description;
 | |
|     NewMenuEntry->DisplayStringToken = HiiSetString (CallbackData->BmmHiiHandle, 0, NewMenuEntry->DisplayString, NULL);
 | |
| 
 | |
|     LoadOptionPtr += StringSize;
 | |
| 
 | |
|     NewLoadContext->FilePathList = AllocateZeroPool (NewLoadContext->FilePathListLength);
 | |
|     ASSERT (NewLoadContext->FilePathList != NULL);
 | |
|     CopyMem (
 | |
|       NewLoadContext->FilePathList,
 | |
|       (EFI_DEVICE_PATH_PROTOCOL *)LoadOptionPtr,
 | |
|       NewLoadContext->FilePathListLength
 | |
|       );
 | |
| 
 | |
|     NewMenuEntry->HelpString      = UiDevicePathToStr (NewLoadContext->FilePathList);
 | |
|     NewMenuEntry->HelpStringToken = HiiSetString (CallbackData->BmmHiiHandle, 0, NewMenuEntry->HelpString, NULL);
 | |
| 
 | |
|     LoadOptionPtr += NewLoadContext->FilePathListLength;
 | |
| 
 | |
|     if (LoadOptionPtr < LoadOptionEnd) {
 | |
|       OptionalDataSize = BootOptionSize -
 | |
|                          sizeof (UINT32) -
 | |
|                          sizeof (UINT16) -
 | |
|                          StringSize -
 | |
|                          NewLoadContext->FilePathListLength;
 | |
| 
 | |
|       NewLoadContext->OptionalData = AllocateZeroPool (OptionalDataSize);
 | |
|       ASSERT (NewLoadContext->OptionalData != NULL);
 | |
|       CopyMem (
 | |
|         NewLoadContext->OptionalData,
 | |
|         LoadOptionPtr,
 | |
|         OptionalDataSize
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     InsertTailList (&BootOptionMenu.Head, &NewMenuEntry->Link);
 | |
|     MenuCount++;
 | |
|     FreePool (LoadOptionFromVar);
 | |
|   }
 | |
| 
 | |
|   EfiBootManagerFreeLoadOptions (BootOption, BootOptionCount);
 | |
| 
 | |
|   if (BootNext != NULL) {
 | |
|     FreePool (BootNext);
 | |
|   }
 | |
| 
 | |
|   if (BootOrderList != NULL) {
 | |
|     FreePool (BootOrderList);
 | |
|   }
 | |
| 
 | |
|   BootOptionMenu.MenuNumber = MenuCount;
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
| 
 | |
|   Find drivers that will be added as Driver#### variables from handles
 | |
|   in current system environment
 | |
|   All valid handles in the system except those consume SimpleFs, LoadFile
 | |
|   are stored in DriverMenu for future use.
 | |
| 
 | |
|   @retval EFI_SUCCESS The function complets successfully.
 | |
|   @return Other value if failed to build the DriverMenu.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| BOpt_FindDrivers (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   UINTN                            NoDevicePathHandles;
 | |
|   EFI_HANDLE                       *DevicePathHandle;
 | |
|   UINTN                            Index;
 | |
|   EFI_STATUS                       Status;
 | |
|   BM_MENU_ENTRY                    *NewMenuEntry;
 | |
|   BM_HANDLE_CONTEXT                *NewHandleContext;
 | |
|   EFI_HANDLE                       CurHandle;
 | |
|   UINTN                            OptionNumber;
 | |
|   EFI_SIMPLE_FILE_SYSTEM_PROTOCOL  *SimpleFs;
 | |
|   EFI_LOAD_FILE_PROTOCOL           *LoadFile;
 | |
| 
 | |
|   SimpleFs = NULL;
 | |
|   LoadFile = NULL;
 | |
| 
 | |
|   InitializeListHead (&DriverMenu.Head);
 | |
| 
 | |
|   //
 | |
|   // At first, get all handles that support Device Path
 | |
|   // protocol which is the basic requirement for
 | |
|   // Driver####
 | |
|   //
 | |
|   Status = gBS->LocateHandleBuffer (
 | |
|                   ByProtocol,
 | |
|                   &gEfiDevicePathProtocolGuid,
 | |
|                   NULL,
 | |
|                   &NoDevicePathHandles,
 | |
|                   &DevicePathHandle
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   OptionNumber = 0;
 | |
|   for (Index = 0; Index < NoDevicePathHandles; Index++) {
 | |
|     CurHandle = DevicePathHandle[Index];
 | |
| 
 | |
|     Status = gBS->HandleProtocol (
 | |
|                     CurHandle,
 | |
|                     &gEfiSimpleFileSystemProtocolGuid,
 | |
|                     (VOID **)&SimpleFs
 | |
|                     );
 | |
|     if (Status == EFI_SUCCESS) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     Status = gBS->HandleProtocol (
 | |
|                     CurHandle,
 | |
|                     &gEfiLoadFileProtocolGuid,
 | |
|                     (VOID **)&LoadFile
 | |
|                     );
 | |
|     if (Status == EFI_SUCCESS) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     NewMenuEntry = BOpt_CreateMenuEntry (BM_HANDLE_CONTEXT_SELECT);
 | |
|     if (NULL == NewMenuEntry) {
 | |
|       FreePool (DevicePathHandle);
 | |
|       return EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
| 
 | |
|     NewHandleContext                 = (BM_HANDLE_CONTEXT *)NewMenuEntry->VariableContext;
 | |
|     NewHandleContext->Handle         = CurHandle;
 | |
|     NewHandleContext->DevicePath     = DevicePathFromHandle (CurHandle);
 | |
|     NewMenuEntry->DisplayString      = UiDevicePathToStr (NewHandleContext->DevicePath);
 | |
|     NewMenuEntry->DisplayStringToken = HiiSetString (mBmmCallbackInfo->BmmHiiHandle, 0, NewMenuEntry->DisplayString, NULL);
 | |
|     NewMenuEntry->HelpString         = NULL;
 | |
|     NewMenuEntry->HelpStringToken    = NewMenuEntry->DisplayStringToken;
 | |
|     NewMenuEntry->OptionNumber       = OptionNumber;
 | |
|     OptionNumber++;
 | |
|     InsertTailList (&DriverMenu.Head, &NewMenuEntry->Link);
 | |
|   }
 | |
| 
 | |
|   if (DevicePathHandle != NULL) {
 | |
|     FreePool (DevicePathHandle);
 | |
|   }
 | |
| 
 | |
|   DriverMenu.MenuNumber = OptionNumber;
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
| 
 | |
|   Get the Option Number that has not been allocated for use.
 | |
| 
 | |
|   @param Type  The type of Option.
 | |
| 
 | |
|   @return The available Option Number.
 | |
| 
 | |
| **/
 | |
| UINT16
 | |
| BOpt_GetOptionNumber (
 | |
|   CHAR16  *Type
 | |
|   )
 | |
| {
 | |
|   UINT16  *OrderList;
 | |
|   UINTN   OrderListSize;
 | |
|   UINTN   Index;
 | |
|   CHAR16  StrTemp[20];
 | |
|   UINT16  *OptionBuffer;
 | |
|   UINT16  OptionNumber;
 | |
|   UINTN   OptionSize;
 | |
| 
 | |
|   OrderListSize = 0;
 | |
|   OrderList     = NULL;
 | |
|   OptionNumber  = 0;
 | |
|   Index         = 0;
 | |
| 
 | |
|   UnicodeSPrint (StrTemp, sizeof (StrTemp), L"%sOrder", Type);
 | |
| 
 | |
|   GetEfiGlobalVariable2 (StrTemp, (VOID **)&OrderList, &OrderListSize);
 | |
|   for (OptionNumber = 0; ; OptionNumber++) {
 | |
|     if (OrderList != NULL) {
 | |
|       for (Index = 0; Index < OrderListSize / sizeof (UINT16); Index++) {
 | |
|         if (OptionNumber == OrderList[Index]) {
 | |
|           break;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (Index < OrderListSize / sizeof (UINT16)) {
 | |
|       //
 | |
|       // The OptionNumber occurs in the OrderList, continue to use next one
 | |
|       //
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     UnicodeSPrint (StrTemp, sizeof (StrTemp), L"%s%04x", Type, (UINTN)OptionNumber);
 | |
|     DEBUG ((DEBUG_ERROR, "Option = %s\n", StrTemp));
 | |
|     GetEfiGlobalVariable2 (StrTemp, (VOID **)&OptionBuffer, &OptionSize);
 | |
|     if (NULL == OptionBuffer) {
 | |
|       //
 | |
|       // The Boot[OptionNumber] / Driver[OptionNumber] NOT occurs, we found it
 | |
|       //
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return OptionNumber;
 | |
| }
 | |
| 
 | |
| /**
 | |
| 
 | |
|   Get the Option Number for Boot#### that does not used.
 | |
| 
 | |
|   @return The available Option Number.
 | |
| 
 | |
| **/
 | |
| UINT16
 | |
| BOpt_GetBootOptionNumber (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   return BOpt_GetOptionNumber (L"Boot");
 | |
| }
 | |
| 
 | |
| /**
 | |
| 
 | |
|   Get the Option Number for Driver#### that does not used.
 | |
| 
 | |
|   @return The unused Option Number.
 | |
| 
 | |
| **/
 | |
| UINT16
 | |
| BOpt_GetDriverOptionNumber (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   return BOpt_GetOptionNumber (L"Driver");
 | |
| }
 | |
| 
 | |
| /**
 | |
| 
 | |
|   Build up all DriverOptionMenu
 | |
| 
 | |
|   @param CallbackData The BMM context data.
 | |
| 
 | |
|   @retval EFI_SUCESS           The functin completes successfully.
 | |
|   @retval EFI_OUT_OF_RESOURCES Not enough memory to compete the operation.
 | |
|   @retval EFI_NOT_FOUND        Fail to get "DriverOrder" variable.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| BOpt_GetDriverOptions (
 | |
|   IN  BMM_CALLBACK_DATA  *CallbackData
 | |
|   )
 | |
| {
 | |
|   UINTN   Index;
 | |
|   UINT16  DriverString[12];
 | |
|   UINT8   *LoadOptionFromVar;
 | |
|   UINTN   DriverOptionSize;
 | |
| 
 | |
|   UINT16           *DriverOrderList;
 | |
|   UINTN            DriverOrderListSize;
 | |
|   BM_MENU_ENTRY    *NewMenuEntry;
 | |
|   BM_LOAD_CONTEXT  *NewLoadContext;
 | |
|   UINT8            *LoadOptionPtr;
 | |
|   UINTN            StringSize;
 | |
|   UINTN            OptionalDataSize;
 | |
|   UINT8            *LoadOptionEnd;
 | |
| 
 | |
|   DriverOrderListSize = 0;
 | |
|   DriverOrderList     = NULL;
 | |
|   DriverOptionSize    = 0;
 | |
|   LoadOptionFromVar   = NULL;
 | |
|   BOpt_FreeMenu (&DriverOptionMenu);
 | |
|   InitializeListHead (&DriverOptionMenu.Head);
 | |
|   //
 | |
|   // Get the DriverOrder from the Var
 | |
|   //
 | |
|   GetEfiGlobalVariable2 (L"DriverOrder", (VOID **)&DriverOrderList, &DriverOrderListSize);
 | |
|   if (DriverOrderList == NULL) {
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   for (Index = 0; Index < DriverOrderListSize / sizeof (UINT16); Index++) {
 | |
|     UnicodeSPrint (
 | |
|       DriverString,
 | |
|       sizeof (DriverString),
 | |
|       L"Driver%04x",
 | |
|       DriverOrderList[Index]
 | |
|       );
 | |
|     //
 | |
|     //  Get all loadoptions from the VAR
 | |
|     //
 | |
|     GetEfiGlobalVariable2 (DriverString, (VOID **)&LoadOptionFromVar, &DriverOptionSize);
 | |
|     if (LoadOptionFromVar == NULL) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);
 | |
|     if (NULL == NewMenuEntry) {
 | |
|       return EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
| 
 | |
|     NewLoadContext             = (BM_LOAD_CONTEXT *)NewMenuEntry->VariableContext;
 | |
|     LoadOptionPtr              = LoadOptionFromVar;
 | |
|     LoadOptionEnd              = LoadOptionFromVar + DriverOptionSize;
 | |
|     NewMenuEntry->OptionNumber = DriverOrderList[Index];
 | |
|     NewLoadContext->Deleted    = FALSE;
 | |
|     NewLoadContext->IsLegacy   = FALSE;
 | |
| 
 | |
|     //
 | |
|     // LoadOption is a pointer type of UINT8
 | |
|     // for easy use with following LOAD_OPTION
 | |
|     // embedded in this struct
 | |
|     //
 | |
| 
 | |
|     NewLoadContext->Attributes = *(UINT32 *)LoadOptionPtr;
 | |
| 
 | |
|     LoadOptionPtr += sizeof (UINT32);
 | |
| 
 | |
|     NewLoadContext->FilePathListLength = *(UINT16 *)LoadOptionPtr;
 | |
|     LoadOptionPtr                     += sizeof (UINT16);
 | |
| 
 | |
|     StringSize                  = StrSize ((UINT16 *)LoadOptionPtr);
 | |
|     NewLoadContext->Description = AllocateZeroPool (StringSize);
 | |
|     ASSERT (NewLoadContext->Description != NULL);
 | |
|     CopyMem (
 | |
|       NewLoadContext->Description,
 | |
|       (UINT16 *)LoadOptionPtr,
 | |
|       StringSize
 | |
|       );
 | |
|     NewMenuEntry->DisplayString      = NewLoadContext->Description;
 | |
|     NewMenuEntry->DisplayStringToken = HiiSetString (CallbackData->BmmHiiHandle, 0, NewMenuEntry->DisplayString, NULL);
 | |
| 
 | |
|     LoadOptionPtr += StringSize;
 | |
| 
 | |
|     NewLoadContext->FilePathList = AllocateZeroPool (NewLoadContext->FilePathListLength);
 | |
|     ASSERT (NewLoadContext->FilePathList != NULL);
 | |
|     CopyMem (
 | |
|       NewLoadContext->FilePathList,
 | |
|       (EFI_DEVICE_PATH_PROTOCOL *)LoadOptionPtr,
 | |
|       NewLoadContext->FilePathListLength
 | |
|       );
 | |
| 
 | |
|     NewMenuEntry->HelpString      = UiDevicePathToStr (NewLoadContext->FilePathList);
 | |
|     NewMenuEntry->HelpStringToken = HiiSetString (CallbackData->BmmHiiHandle, 0, NewMenuEntry->HelpString, NULL);
 | |
| 
 | |
|     LoadOptionPtr += NewLoadContext->FilePathListLength;
 | |
| 
 | |
|     if (LoadOptionPtr < LoadOptionEnd) {
 | |
|       OptionalDataSize = DriverOptionSize -
 | |
|                          sizeof (UINT32) -
 | |
|                          sizeof (UINT16) -
 | |
|                          StringSize -
 | |
|                          NewLoadContext->FilePathListLength;
 | |
| 
 | |
|       NewLoadContext->OptionalData = AllocateZeroPool (OptionalDataSize);
 | |
|       ASSERT (NewLoadContext->OptionalData != NULL);
 | |
|       CopyMem (
 | |
|         NewLoadContext->OptionalData,
 | |
|         LoadOptionPtr,
 | |
|         OptionalDataSize
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     InsertTailList (&DriverOptionMenu.Head, &NewMenuEntry->Link);
 | |
|     FreePool (LoadOptionFromVar);
 | |
|   }
 | |
| 
 | |
|   if (DriverOrderList != NULL) {
 | |
|     FreePool (DriverOrderList);
 | |
|   }
 | |
| 
 | |
|   DriverOptionMenu.MenuNumber = Index;
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get option number according to Boot#### and BootOrder variable.
 | |
|   The value is saved as #### + 1.
 | |
| 
 | |
|   @param CallbackData    The BMM context data.
 | |
| **/
 | |
| VOID
 | |
| GetBootOrder (
 | |
|   IN  BMM_CALLBACK_DATA  *CallbackData
 | |
|   )
 | |
| {
 | |
|   BMM_FAKE_NV_DATA  *BmmConfig;
 | |
|   UINT16            Index;
 | |
|   UINT16            OptionOrderIndex;
 | |
|   UINTN             DeviceType;
 | |
|   BM_MENU_ENTRY     *NewMenuEntry;
 | |
|   BM_LOAD_CONTEXT   *NewLoadContext;
 | |
| 
 | |
|   ASSERT (CallbackData != NULL);
 | |
| 
 | |
|   DeviceType = (UINTN)-1;
 | |
|   BmmConfig  = &CallbackData->BmmFakeNvData;
 | |
|   ZeroMem (BmmConfig->BootOptionOrder, sizeof (BmmConfig->BootOptionOrder));
 | |
| 
 | |
|   for (Index = 0, OptionOrderIndex = 0; ((Index < BootOptionMenu.MenuNumber) &&
 | |
|                                          (OptionOrderIndex < (sizeof (BmmConfig->BootOptionOrder) / sizeof (BmmConfig->BootOptionOrder[0]))));
 | |
|        Index++)
 | |
|   {
 | |
|     NewMenuEntry   = BOpt_GetMenuEntry (&BootOptionMenu, Index);
 | |
|     NewLoadContext = (BM_LOAD_CONTEXT *)NewMenuEntry->VariableContext;
 | |
| 
 | |
|     if (NewLoadContext->IsLegacy) {
 | |
|       if (((BBS_BBS_DEVICE_PATH *)NewLoadContext->FilePathList)->DeviceType != DeviceType) {
 | |
|         DeviceType = ((BBS_BBS_DEVICE_PATH *)NewLoadContext->FilePathList)->DeviceType;
 | |
|       } else {
 | |
|         //
 | |
|         // Only show one legacy boot option for the same device type
 | |
|         // assuming the boot options are grouped by the device type
 | |
|         //
 | |
|         continue;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     BmmConfig->BootOptionOrder[OptionOrderIndex++] = (UINT32)(NewMenuEntry->OptionNumber + 1);
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get driver option order from globalc DriverOptionMenu.
 | |
| 
 | |
|   @param CallbackData    The BMM context data.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| GetDriverOrder (
 | |
|   IN  BMM_CALLBACK_DATA  *CallbackData
 | |
|   )
 | |
| {
 | |
|   BMM_FAKE_NV_DATA  *BmmConfig;
 | |
|   UINT16            Index;
 | |
|   UINT16            OptionOrderIndex;
 | |
|   UINTN             DeviceType;
 | |
|   BM_MENU_ENTRY     *NewMenuEntry;
 | |
|   BM_LOAD_CONTEXT   *NewLoadContext;
 | |
| 
 | |
|   ASSERT (CallbackData != NULL);
 | |
| 
 | |
|   DeviceType = (UINTN)-1;
 | |
|   BmmConfig  = &CallbackData->BmmFakeNvData;
 | |
|   ZeroMem (BmmConfig->DriverOptionOrder, sizeof (BmmConfig->DriverOptionOrder));
 | |
| 
 | |
|   for (Index = 0, OptionOrderIndex = 0; ((Index < DriverOptionMenu.MenuNumber) &&
 | |
|                                          (OptionOrderIndex < (sizeof (BmmConfig->DriverOptionOrder) / sizeof (BmmConfig->DriverOptionOrder[0]))));
 | |
|        Index++)
 | |
|   {
 | |
|     NewMenuEntry   = BOpt_GetMenuEntry (&DriverOptionMenu, Index);
 | |
|     NewLoadContext = (BM_LOAD_CONTEXT *)NewMenuEntry->VariableContext;
 | |
| 
 | |
|     if (NewLoadContext->IsLegacy) {
 | |
|       if (((BBS_BBS_DEVICE_PATH *)NewLoadContext->FilePathList)->DeviceType != DeviceType) {
 | |
|         DeviceType = ((BBS_BBS_DEVICE_PATH *)NewLoadContext->FilePathList)->DeviceType;
 | |
|       } else {
 | |
|         //
 | |
|         // Only show one legacy boot option for the same device type
 | |
|         // assuming the boot options are grouped by the device type
 | |
|         //
 | |
|         continue;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     BmmConfig->DriverOptionOrder[OptionOrderIndex++] = (UINT32)(NewMenuEntry->OptionNumber + 1);
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Boot the file specified by the input file path info.
 | |
| 
 | |
|   @param FilePath    Point to the file path.
 | |
| 
 | |
|   @retval TRUE   Exit caller function.
 | |
|   @retval FALSE  Not exit caller function.
 | |
| **/
 | |
| BOOLEAN
 | |
| EFIAPI
 | |
| BootFromFile (
 | |
|   IN EFI_DEVICE_PATH_PROTOCOL  *FilePath
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                    Status;
 | |
|   EFI_BOOT_MANAGER_LOAD_OPTION  BootOption;
 | |
|   CHAR16                        *FileName;
 | |
| 
 | |
|   Status   = EFI_NOT_STARTED;
 | |
|   FileName = NULL;
 | |
| 
 | |
|   FileName = ExtractFileNameFromDevicePath (FilePath);
 | |
|   if (FileName != NULL) {
 | |
|     Status = EfiBootManagerInitializeLoadOption (
 | |
|                &BootOption,
 | |
|                0,
 | |
|                LoadOptionTypeBoot,
 | |
|                LOAD_OPTION_ACTIVE,
 | |
|                FileName,
 | |
|                FilePath,
 | |
|                NULL,
 | |
|                0
 | |
|                );
 | |
|   }
 | |
| 
 | |
|   if (!EFI_ERROR (Status)) {
 | |
|     //
 | |
|     // Since current no boot from removable media directly is allowed */
 | |
|     //
 | |
|     gST->ConOut->ClearScreen (gST->ConOut);
 | |
|     //
 | |
|     // Check whether need to reset system.
 | |
|     //
 | |
|     BmmSetupResetReminder ();
 | |
| 
 | |
|     BmmSetConsoleMode (FALSE);
 | |
|     EfiBootManagerBoot (&BootOption);
 | |
|     BmmSetConsoleMode (TRUE);
 | |
| 
 | |
|     FreePool (FileName);
 | |
| 
 | |
|     EfiBootManagerFreeLoadOption (&BootOption);
 | |
|   }
 | |
| 
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Display the form base on the selected file.
 | |
| 
 | |
|   @param FilePath   Point to the file path.
 | |
|   @param FormId     The form need to display.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| ReSendForm (
 | |
|   IN  EFI_DEVICE_PATH_PROTOCOL  *FilePath,
 | |
|   IN  EFI_FORM_ID               FormId
 | |
|   )
 | |
| {
 | |
|   gBootMaintenancePrivate.LoadContext->FilePathList = FilePath;
 | |
| 
 | |
|   UpdateOptionPage (&gBootMaintenancePrivate, FormId, FilePath);
 | |
| 
 | |
|   gBootMaintenancePrivate.FormBrowser2->SendForm (
 | |
|                                           gBootMaintenancePrivate.FormBrowser2,
 | |
|                                           &gBootMaintenancePrivate.BmmHiiHandle,
 | |
|                                           1,
 | |
|                                           &mBootMaintGuid,
 | |
|                                           FormId,
 | |
|                                           NULL,
 | |
|                                           NULL
 | |
|                                           );
 | |
|   return TRUE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Create boot option base on the input file path info.
 | |
| 
 | |
|   @param FilePath    Point to the file path.
 | |
| 
 | |
|   @retval TRUE   Exit caller function.
 | |
|   @retval FALSE  Not exit caller function.
 | |
| **/
 | |
| BOOLEAN
 | |
| EFIAPI
 | |
| CreateBootOptionFromFile (
 | |
|   IN EFI_DEVICE_PATH_PROTOCOL  *FilePath
 | |
|   )
 | |
| {
 | |
|   return ReSendForm (FilePath, FORM_BOOT_ADD_ID);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Create driver option base on the input file path info.
 | |
| 
 | |
|   @param FilePath    Point to the file path.
 | |
| 
 | |
|   @retval TRUE   Exit caller function.
 | |
|   @retval FALSE  Not exit caller function.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| EFIAPI
 | |
| CreateDriverOptionFromFile (
 | |
|   IN EFI_DEVICE_PATH_PROTOCOL  *FilePath
 | |
|   )
 | |
| {
 | |
|   return ReSendForm (FilePath, FORM_DRV_ADD_FILE_ID);
 | |
| }
 |