/** @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.
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((EFI_D_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_BOOT_MANAGER_LOAD_OPTION BootOption; CHAR16 *FileName; FileName = NULL; FileName = ExtractFileNameFromDevicePath(FilePath); if (FileName != NULL) { EfiBootManagerInitializeLoadOption ( &BootOption, 0, LoadOptionTypeBoot, LOAD_OPTION_ACTIVE, FileName, FilePath, NULL, 0 ); // // 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); }