/** @file Provide boot option support for Application "BootMaint" Include file system navigation, system handle selection Boot option manipulation Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license.php THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ #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); }