/** @file The functions for Boot Maintainence Main menu. Copyright (c) 2004 - 2019, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "BootMaintenanceManager.h" #define FRONT_PAGE_KEY_OFFSET 0x4000 // // Boot video resolution and text mode. // UINT32 mBmmBootHorizontalResolution = 0; UINT32 mBmmBootVerticalResolution = 0; UINT32 mBmmBootTextModeColumn = 0; UINT32 mBmmBootTextModeRow = 0; // // BIOS setup video resolution and text mode. // UINT32 mBmmSetupTextModeColumn = 0; UINT32 mBmmSetupTextModeRow = 0; UINT32 mBmmSetupHorizontalResolution = 0; UINT32 mBmmSetupVerticalResolution = 0; BOOLEAN mBmmModeInitialized = FALSE; EFI_DEVICE_PATH_PROTOCOL EndDevicePath[] = { { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { END_DEVICE_PATH_LENGTH, 0 } } }; HII_VENDOR_DEVICE_PATH mBmmHiiVendorDevicePath = { { { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, { (UINT8)(sizeof (VENDOR_DEVICE_PATH)), (UINT8)((sizeof (VENDOR_DEVICE_PATH)) >> 8) } }, // // {165A028F-0BB2-4b5f-8747-77592E3F6499} // { 0x165a028f, 0xbb2, 0x4b5f, { 0x87, 0x47, 0x77, 0x59, 0x2e, 0x3f, 0x64, 0x99 } } }, { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { (UINT8)(END_DEVICE_PATH_LENGTH), (UINT8)((END_DEVICE_PATH_LENGTH) >> 8) } } }; EFI_GUID mBootMaintGuid = BOOT_MAINT_FORMSET_GUID; CHAR16 mBootMaintStorageName[] = L"BmmData"; BMM_CALLBACK_DATA gBootMaintenancePrivate = { BMM_CALLBACK_DATA_SIGNATURE, NULL, NULL, { BootMaintExtractConfig, BootMaintRouteConfig, BootMaintCallback } }; BMM_CALLBACK_DATA *mBmmCallbackInfo = &gBootMaintenancePrivate; BOOLEAN mAllMenuInit = FALSE; BOOLEAN mFirstEnterBMMForm = FALSE; /** Init all memu. @param CallbackData The BMM context data. **/ VOID InitAllMenu ( IN BMM_CALLBACK_DATA *CallbackData ); /** Free up all Menu Option list. **/ VOID FreeAllMenu ( VOID ); /** Update the menus in the BMM page. **/ VOID CustomizeMenus ( VOID ); /** This function will change video resolution and text mode according to defined setup mode or defined boot mode @param IsSetupMode Indicate mode is changed to setup mode or boot mode. @retval EFI_SUCCESS Mode is changed successfully. @retval Others Mode failed to be changed. **/ EFI_STATUS BmmSetConsoleMode ( BOOLEAN IsSetupMode ) { EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput; EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOut; UINTN SizeOfInfo; EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info; UINT32 MaxGopMode; UINT32 MaxTextMode; UINT32 ModeNumber; UINT32 NewHorizontalResolution; UINT32 NewVerticalResolution; UINT32 NewColumns; UINT32 NewRows; UINTN HandleCount; EFI_HANDLE *HandleBuffer; EFI_STATUS Status; UINTN Index; UINTN CurrentColumn; UINTN CurrentRow; MaxGopMode = 0; MaxTextMode = 0; // // Get current video resolution and text mode // Status = gBS->HandleProtocol ( gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID **)&GraphicsOutput ); if (EFI_ERROR (Status)) { GraphicsOutput = NULL; } Status = gBS->HandleProtocol ( gST->ConsoleOutHandle, &gEfiSimpleTextOutProtocolGuid, (VOID **)&SimpleTextOut ); if (EFI_ERROR (Status)) { SimpleTextOut = NULL; } if ((GraphicsOutput == NULL) || (SimpleTextOut == NULL)) { return EFI_UNSUPPORTED; } if (IsSetupMode) { // // The required resolution and text mode is setup mode. // NewHorizontalResolution = mBmmSetupHorizontalResolution; NewVerticalResolution = mBmmSetupVerticalResolution; NewColumns = mBmmSetupTextModeColumn; NewRows = mBmmSetupTextModeRow; } else { // // The required resolution and text mode is boot mode. // NewHorizontalResolution = mBmmBootHorizontalResolution; NewVerticalResolution = mBmmBootVerticalResolution; NewColumns = mBmmBootTextModeColumn; NewRows = mBmmBootTextModeRow; } if (GraphicsOutput != NULL) { MaxGopMode = GraphicsOutput->Mode->MaxMode; } if (SimpleTextOut != NULL) { MaxTextMode = SimpleTextOut->Mode->MaxMode; } // // 1. If current video resolution is same with required video resolution, // video resolution need not be changed. // 1.1. If current text mode is same with required text mode, text mode need not be changed. // 1.2. If current text mode is different from required text mode, text mode need be changed. // 2. If current video resolution is different from required video resolution, we need restart whole console drivers. // for (ModeNumber = 0; ModeNumber < MaxGopMode; ModeNumber++) { Status = GraphicsOutput->QueryMode ( GraphicsOutput, ModeNumber, &SizeOfInfo, &Info ); if (!EFI_ERROR (Status)) { if ((Info->HorizontalResolution == NewHorizontalResolution) && (Info->VerticalResolution == NewVerticalResolution)) { if ((GraphicsOutput->Mode->Info->HorizontalResolution == NewHorizontalResolution) && (GraphicsOutput->Mode->Info->VerticalResolution == NewVerticalResolution)) { // // Current resolution is same with required resolution, check if text mode need be set // Status = SimpleTextOut->QueryMode (SimpleTextOut, SimpleTextOut->Mode->Mode, &CurrentColumn, &CurrentRow); ASSERT_EFI_ERROR (Status); if ((CurrentColumn == NewColumns) && (CurrentRow == NewRows)) { // // If current text mode is same with required text mode. Do nothing // FreePool (Info); return EFI_SUCCESS; } else { // // If current text mode is different from required text mode. Set new video mode // for (Index = 0; Index < MaxTextMode; Index++) { Status = SimpleTextOut->QueryMode (SimpleTextOut, Index, &CurrentColumn, &CurrentRow); if (!EFI_ERROR (Status)) { if ((CurrentColumn == NewColumns) && (CurrentRow == NewRows)) { // // Required text mode is supported, set it. // Status = SimpleTextOut->SetMode (SimpleTextOut, Index); ASSERT_EFI_ERROR (Status); // // Update text mode PCD. // Status = PcdSet32S (PcdConOutColumn, mBmmSetupTextModeColumn); ASSERT_EFI_ERROR (Status); Status = PcdSet32S (PcdConOutRow, mBmmSetupTextModeRow); ASSERT_EFI_ERROR (Status); FreePool (Info); return EFI_SUCCESS; } } } if (Index == MaxTextMode) { // // If required text mode is not supported, return error. // FreePool (Info); return EFI_UNSUPPORTED; } } } else { // // If current video resolution is not same with the new one, set new video resolution. // In this case, the driver which produces simple text out need be restarted. // Status = GraphicsOutput->SetMode (GraphicsOutput, ModeNumber); if (!EFI_ERROR (Status)) { FreePool (Info); break; } } } FreePool (Info); } } if (ModeNumber == MaxGopMode) { // // If the resolution is not supported, return error. // return EFI_UNSUPPORTED; } // // Set PCD to Inform GraphicsConsole to change video resolution. // Set PCD to Inform Consplitter to change text mode. // Status = PcdSet32S (PcdVideoHorizontalResolution, NewHorizontalResolution); ASSERT_EFI_ERROR (Status); Status = PcdSet32S (PcdVideoVerticalResolution, NewVerticalResolution); ASSERT_EFI_ERROR (Status); Status = PcdSet32S (PcdConOutColumn, NewColumns); ASSERT_EFI_ERROR (Status); Status = PcdSet32S (PcdConOutRow, NewRows); ASSERT_EFI_ERROR (Status); // // Video mode is changed, so restart graphics console driver and higher level driver. // Reconnect graphics console driver and higher level driver. // Locate all the handles with GOP protocol and reconnect it. // Status = gBS->LocateHandleBuffer ( ByProtocol, &gEfiSimpleTextOutProtocolGuid, NULL, &HandleCount, &HandleBuffer ); if (!EFI_ERROR (Status)) { for (Index = 0; Index < HandleCount; Index++) { gBS->DisconnectController (HandleBuffer[Index], NULL, NULL); } for (Index = 0; Index < HandleCount; Index++) { gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE); } if (HandleBuffer != NULL) { FreePool (HandleBuffer); } } return EFI_SUCCESS; } /** This function converts an input device structure to a Unicode string. @param DevPath A pointer to the device path structure. @return A new allocated Unicode string that represents the device path. **/ CHAR16 * UiDevicePathToStr ( IN EFI_DEVICE_PATH_PROTOCOL *DevPath ) { EFI_STATUS Status; CHAR16 *ToText; EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *DevPathToText; if (DevPath == NULL) { return NULL; } Status = gBS->LocateProtocol ( &gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevPathToText ); ASSERT_EFI_ERROR (Status); ToText = DevPathToText->ConvertDevicePathToText ( DevPath, FALSE, TRUE ); ASSERT (ToText != NULL); return ToText; } /** Extract filename from device path. The returned buffer is allocated using AllocateCopyPool. The caller is responsible for freeing the allocated buffer using FreePool(). @param DevicePath Device path. @return A new allocated string that represents the file name. **/ CHAR16 * ExtractFileNameFromDevicePath ( IN EFI_DEVICE_PATH_PROTOCOL *DevicePath ) { CHAR16 *String; CHAR16 *MatchString; CHAR16 *LastMatch; CHAR16 *FileName; UINTN Length; ASSERT (DevicePath != NULL); String = UiDevicePathToStr (DevicePath); MatchString = String; LastMatch = String; FileName = NULL; while (MatchString != NULL) { LastMatch = MatchString + 1; MatchString = StrStr (LastMatch, L"\\"); } Length = StrLen (LastMatch); FileName = AllocateCopyPool ((Length + 1) * sizeof (CHAR16), LastMatch); if (FileName != NULL) { *(FileName + Length) = 0; } FreePool (String); return FileName; } /** Extract device path for given HII handle and class guid. @param Handle The HII handle. @retval NULL Fail to get the device path string. @return PathString Get the device path string. **/ CHAR16 * BmmExtractDevicePathFromHiiHandle ( IN EFI_HII_HANDLE Handle ) { EFI_STATUS Status; EFI_HANDLE DriverHandle; ASSERT (Handle != NULL); if (Handle == NULL) { return NULL; } Status = gHiiDatabase->GetPackageListHandle (gHiiDatabase, Handle, &DriverHandle); if (EFI_ERROR (Status)) { return NULL; } // // Get device path string. // return ConvertDevicePathToText (DevicePathFromHandle (DriverHandle), FALSE, FALSE); } /** Converts the unicode character of the string from uppercase to lowercase. This is a internal function. @param ConfigString String to be converted **/ VOID HiiToLower ( IN EFI_STRING ConfigString ) { EFI_STRING String; BOOLEAN Lower; ASSERT (ConfigString != NULL); // // Convert all hex digits in range [A-F] in the configuration header to [a-f] // for (String = ConfigString, Lower = FALSE; *String != L'\0'; String++) { if (*String == L'=') { Lower = TRUE; } else if (*String == L'&') { Lower = FALSE; } else if (Lower && (*String >= L'A') && (*String <= L'F')) { *String = (CHAR16)(*String - L'A' + L'a'); } } } /** Update the progress string through the offset value. @param Offset The offset value @param Configuration Point to the configuration string. **/ EFI_STRING UpdateProgress ( IN UINTN Offset, IN EFI_STRING Configuration ) { UINTN Length; EFI_STRING StringPtr; EFI_STRING ReturnString; StringPtr = NULL; ReturnString = NULL; // // &OFFSET=XXXX followed by a Null-terminator. // Length = StrLen (L"&OFFSET=") + 4 + 1 // Length = StrLen (L"&OFFSET=") + 4 + 1; StringPtr = AllocateZeroPool (Length * sizeof (CHAR16)); if (StringPtr == NULL) { return NULL; } UnicodeSPrint ( StringPtr, (8 + 4 + 1) * sizeof (CHAR16), L"&OFFSET=%04x", Offset ); ReturnString = StrStr (Configuration, StringPtr); if (ReturnString == NULL) { // // If doesn't find the string in Configuration, convert the string to lower case then search again. // HiiToLower (StringPtr); ReturnString = StrStr (Configuration, StringPtr); } FreePool (StringPtr); return ReturnString; } /** Update the terminal content in TerminalMenu. @param BmmData The BMM fake NV data. **/ VOID UpdateTerminalContent ( IN BMM_FAKE_NV_DATA *BmmData ) { UINT16 Index; BM_TERMINAL_CONTEXT *NewTerminalContext; BM_MENU_ENTRY *NewMenuEntry; for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) { NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Index); ASSERT (NewMenuEntry != NULL); NewTerminalContext = (BM_TERMINAL_CONTEXT *)NewMenuEntry->VariableContext; NewTerminalContext->BaudRateIndex = BmmData->COMBaudRate[Index]; ASSERT (BmmData->COMBaudRate[Index] < (ARRAY_SIZE (BaudRateList))); NewTerminalContext->BaudRate = BaudRateList[BmmData->COMBaudRate[Index]].Value; NewTerminalContext->DataBitsIndex = BmmData->COMDataRate[Index]; ASSERT (BmmData->COMDataRate[Index] < (ARRAY_SIZE (DataBitsList))); NewTerminalContext->DataBits = (UINT8)DataBitsList[BmmData->COMDataRate[Index]].Value; NewTerminalContext->StopBitsIndex = BmmData->COMStopBits[Index]; ASSERT (BmmData->COMStopBits[Index] < (ARRAY_SIZE (StopBitsList))); NewTerminalContext->StopBits = (UINT8)StopBitsList[BmmData->COMStopBits[Index]].Value; NewTerminalContext->ParityIndex = BmmData->COMParity[Index]; ASSERT (BmmData->COMParity[Index] < (ARRAY_SIZE (ParityList))); NewTerminalContext->Parity = (UINT8)ParityList[BmmData->COMParity[Index]].Value; NewTerminalContext->TerminalType = BmmData->COMTerminalType[Index]; NewTerminalContext->FlowControl = BmmData->COMFlowControl[Index]; ChangeTerminalDevicePath ( NewTerminalContext->DevicePath, FALSE ); } } /** Update the console content in ConsoleMenu. @param ConsoleName The name for the console device type. @param BmmData The BMM fake NV data. **/ VOID UpdateConsoleContent ( IN CHAR16 *ConsoleName, IN BMM_FAKE_NV_DATA *BmmData ) { UINT16 Index; BM_CONSOLE_CONTEXT *NewConsoleContext; BM_TERMINAL_CONTEXT *NewTerminalContext; BM_MENU_ENTRY *NewMenuEntry; if (StrCmp (ConsoleName, L"ConIn") == 0) { for (Index = 0; Index < ConsoleInpMenu.MenuNumber; Index++) { NewMenuEntry = BOpt_GetMenuEntry (&ConsoleInpMenu, Index); NewConsoleContext = (BM_CONSOLE_CONTEXT *)NewMenuEntry->VariableContext; ASSERT (Index < MAX_MENU_NUMBER); NewConsoleContext->IsActive = BmmData->ConsoleInCheck[Index]; } for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) { NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Index); NewTerminalContext = (BM_TERMINAL_CONTEXT *)NewMenuEntry->VariableContext; ASSERT (Index + ConsoleInpMenu.MenuNumber < MAX_MENU_NUMBER); NewTerminalContext->IsConIn = BmmData->ConsoleInCheck[Index + ConsoleInpMenu.MenuNumber]; } } if (StrCmp (ConsoleName, L"ConOut") == 0) { for (Index = 0; Index < ConsoleOutMenu.MenuNumber; Index++) { NewMenuEntry = BOpt_GetMenuEntry (&ConsoleOutMenu, Index); NewConsoleContext = (BM_CONSOLE_CONTEXT *)NewMenuEntry->VariableContext; ASSERT (Index < MAX_MENU_NUMBER); NewConsoleContext->IsActive = BmmData->ConsoleOutCheck[Index]; } for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) { NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Index); NewTerminalContext = (BM_TERMINAL_CONTEXT *)NewMenuEntry->VariableContext; ASSERT (Index + ConsoleOutMenu.MenuNumber < MAX_MENU_NUMBER); NewTerminalContext->IsConOut = BmmData->ConsoleOutCheck[Index + ConsoleOutMenu.MenuNumber]; } } if (StrCmp (ConsoleName, L"ErrOut") == 0) { for (Index = 0; Index < ConsoleErrMenu.MenuNumber; Index++) { NewMenuEntry = BOpt_GetMenuEntry (&ConsoleErrMenu, Index); NewConsoleContext = (BM_CONSOLE_CONTEXT *)NewMenuEntry->VariableContext; ASSERT (Index < MAX_MENU_NUMBER); NewConsoleContext->IsActive = BmmData->ConsoleErrCheck[Index]; } for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) { NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Index); NewTerminalContext = (BM_TERMINAL_CONTEXT *)NewMenuEntry->VariableContext; ASSERT (Index + ConsoleErrMenu.MenuNumber < MAX_MENU_NUMBER); NewTerminalContext->IsStdErr = BmmData->ConsoleErrCheck[Index + ConsoleErrMenu.MenuNumber]; } } } /** This function allows a caller to extract the current configuration for one or more named elements from the target driver. @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. @param Request A null-terminated Unicode string in format. @param Progress On return, points to a character in the Request string. Points to the string's null terminator if request was successful. Points to the most recent '&' before the first failing name/value pair (or the beginning of the string if the failure is in the first name/value pair) if the request was not successful. @param Results A null-terminated Unicode string in format which has all values filled in for the names in the Request string. String to be allocated by the called function. @retval EFI_SUCCESS The Results is filled with the requested values. @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results. @retval EFI_INVALID_PARAMETER Request is NULL, illegal syntax, or unknown name. @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver. **/ EFI_STATUS EFIAPI BootMaintExtractConfig ( IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, IN CONST EFI_STRING Request, OUT EFI_STRING *Progress, OUT EFI_STRING *Results ) { EFI_STATUS Status; UINTN BufferSize; BMM_CALLBACK_DATA *Private; EFI_STRING ConfigRequestHdr; EFI_STRING ConfigRequest; BOOLEAN AllocatedRequest; UINTN Size; if ((Progress == NULL) || (Results == NULL)) { return EFI_INVALID_PARAMETER; } *Progress = Request; if ((Request != NULL) && !HiiIsConfigHdrMatch (Request, &mBootMaintGuid, mBootMaintStorageName)) { return EFI_NOT_FOUND; } ConfigRequestHdr = NULL; ConfigRequest = NULL; AllocatedRequest = FALSE; Size = 0; Private = BMM_CALLBACK_DATA_FROM_THIS (This); // // Convert buffer data to by helper function BlockToConfig() // BufferSize = sizeof (BMM_FAKE_NV_DATA); ConfigRequest = Request; if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) { // // Request has no request element, construct full request string. // Allocate and fill a buffer large enough to hold the template // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator // ConfigRequestHdr = HiiConstructConfigHdr (&mBootMaintGuid, mBootMaintStorageName, Private->BmmDriverHandle); Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16); ConfigRequest = AllocateZeroPool (Size); ASSERT (ConfigRequest != NULL); AllocatedRequest = TRUE; UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, (UINT64)BufferSize); FreePool (ConfigRequestHdr); } Status = gHiiConfigRouting->BlockToConfig ( gHiiConfigRouting, ConfigRequest, (UINT8 *)&Private->BmmFakeNvData, BufferSize, Results, Progress ); // // Free the allocated config request string. // if (AllocatedRequest) { FreePool (ConfigRequest); ConfigRequest = NULL; } // // Set Progress string to the original request string. // if (Request == NULL) { *Progress = NULL; } else if (StrStr (Request, L"OFFSET") == NULL) { *Progress = Request + StrLen (Request); } return Status; } /** This function applies changes in a driver's configuration. Input is a Configuration, which has the routing data for this driver followed by name / value configuration pairs. The driver must apply those pairs to its configurable storage. If the driver's configuration is stored in a linear block of data and the driver's name / value pairs are in format, it may use the ConfigToBlock helper function (above) to simplify the job. Currently not implemented. @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. @param[in] Configuration A null-terminated Unicode string in format. @param[out] Progress A pointer to a string filled in with the offset of the most recent '&' before the first failing name / value pair (or the beginn ing of the string if the failure is in the first name / value pair) or the terminating NULL if all was successful. @retval EFI_SUCCESS The results have been distributed or are awaiting distribution. @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the results that must be stored awaiting possible future protocols. @retval EFI_INVALID_PARAMETERS Passing in a NULL for the Results parameter would result in this type of error. @retval EFI_NOT_FOUND Target for the specified routing data was not found. **/ EFI_STATUS EFIAPI BootMaintRouteConfig ( IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, IN CONST EFI_STRING Configuration, OUT EFI_STRING *Progress ) { EFI_STATUS Status; UINTN BufferSize; EFI_HII_CONFIG_ROUTING_PROTOCOL *ConfigRouting; BMM_FAKE_NV_DATA *NewBmmData; BMM_FAKE_NV_DATA *OldBmmData; BM_MENU_ENTRY *NewMenuEntry; BM_LOAD_CONTEXT *NewLoadContext; UINT16 Index; BOOLEAN TerminalAttChange; BMM_CALLBACK_DATA *Private; UINTN Offset; if (Progress == NULL) { return EFI_INVALID_PARAMETER; } *Progress = Configuration; if (Configuration == NULL) { return EFI_INVALID_PARAMETER; } // // Check routing data in . // Note: there is no name for Name/Value storage, only GUID will be checked // if (!HiiIsConfigHdrMatch (Configuration, &mBootMaintGuid, mBootMaintStorageName)) { return EFI_NOT_FOUND; } Status = gBS->LocateProtocol ( &gEfiHiiConfigRoutingProtocolGuid, NULL, (VOID **)&ConfigRouting ); if (EFI_ERROR (Status)) { return Status; } Private = BMM_CALLBACK_DATA_FROM_THIS (This); // // Get Buffer Storage data from EFI variable // BufferSize = sizeof (BMM_FAKE_NV_DATA); OldBmmData = &Private->BmmOldFakeNVData; NewBmmData = &Private->BmmFakeNvData; Offset = 0; // // Convert to buffer data by helper function ConfigToBlock() // Status = ConfigRouting->ConfigToBlock ( ConfigRouting, Configuration, (UINT8 *)NewBmmData, &BufferSize, Progress ); ASSERT_EFI_ERROR (Status); // // Compare new and old BMM configuration data and only do action for modified item to // avoid setting unnecessary non-volatile variable // // // Check data which located in BMM main page and save the settings if need // if (CompareMem (&NewBmmData->BootNext, &OldBmmData->BootNext, sizeof (NewBmmData->BootNext)) != 0) { Status = Var_UpdateBootNext (Private); if (EFI_ERROR (Status)) { Offset = OFFSET_OF (BMM_FAKE_NV_DATA, BootNext); goto Exit; } } // // Check data which located in Boot Options Menu and save the settings if need // if (CompareMem (NewBmmData->BootOptionDel, OldBmmData->BootOptionDel, sizeof (NewBmmData->BootOptionDel)) != 0) { for (Index = 0; ((Index < BootOptionMenu.MenuNumber) && (Index < (sizeof (NewBmmData->BootOptionDel) / sizeof (NewBmmData->BootOptionDel[0])))); Index++) { NewMenuEntry = BOpt_GetMenuEntry (&BootOptionMenu, Index); NewLoadContext = (BM_LOAD_CONTEXT *)NewMenuEntry->VariableContext; NewLoadContext->Deleted = NewBmmData->BootOptionDel[Index]; NewBmmData->BootOptionDel[Index] = FALSE; NewBmmData->BootOptionDelMark[Index] = FALSE; } Status = Var_DelBootOption (); if (EFI_ERROR (Status)) { Offset = OFFSET_OF (BMM_FAKE_NV_DATA, BootOptionDel); goto Exit; } } if (CompareMem (NewBmmData->BootOptionOrder, OldBmmData->BootOptionOrder, sizeof (NewBmmData->BootOptionOrder)) != 0) { Status = Var_UpdateBootOrder (Private); if (EFI_ERROR (Status)) { Offset = OFFSET_OF (BMM_FAKE_NV_DATA, BootOptionOrder); goto Exit; } } if (CompareMem (&NewBmmData->BootTimeOut, &OldBmmData->BootTimeOut, sizeof (NewBmmData->BootTimeOut)) != 0) { Status = gRT->SetVariable ( L"Timeout", &gEfiGlobalVariableGuid, EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, sizeof (UINT16), &(NewBmmData->BootTimeOut) ); if (EFI_ERROR (Status)) { Offset = OFFSET_OF (BMM_FAKE_NV_DATA, BootTimeOut); goto Exit; } Private->BmmOldFakeNVData.BootTimeOut = NewBmmData->BootTimeOut; } // // Check data which located in Driver Options Menu and save the settings if need // if (CompareMem (NewBmmData->DriverOptionDel, OldBmmData->DriverOptionDel, sizeof (NewBmmData->DriverOptionDel)) != 0) { for (Index = 0; ((Index < DriverOptionMenu.MenuNumber) && (Index < (sizeof (NewBmmData->DriverOptionDel) / sizeof (NewBmmData->DriverOptionDel[0])))); Index++) { NewMenuEntry = BOpt_GetMenuEntry (&DriverOptionMenu, Index); NewLoadContext = (BM_LOAD_CONTEXT *)NewMenuEntry->VariableContext; NewLoadContext->Deleted = NewBmmData->DriverOptionDel[Index]; NewBmmData->DriverOptionDel[Index] = FALSE; NewBmmData->DriverOptionDelMark[Index] = FALSE; } Status = Var_DelDriverOption (); if (EFI_ERROR (Status)) { Offset = OFFSET_OF (BMM_FAKE_NV_DATA, DriverOptionDel); goto Exit; } } if (CompareMem (NewBmmData->DriverOptionOrder, OldBmmData->DriverOptionOrder, sizeof (NewBmmData->DriverOptionOrder)) != 0) { Status = Var_UpdateDriverOrder (Private); if (EFI_ERROR (Status)) { Offset = OFFSET_OF (BMM_FAKE_NV_DATA, DriverOptionOrder); goto Exit; } } if (CompareMem (&NewBmmData->ConsoleOutMode, &OldBmmData->ConsoleOutMode, sizeof (NewBmmData->ConsoleOutMode)) != 0) { Status = Var_UpdateConMode (Private); if (EFI_ERROR (Status)) { Offset = OFFSET_OF (BMM_FAKE_NV_DATA, ConsoleOutMode); goto Exit; } } TerminalAttChange = FALSE; for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) { // // only need update modified items // if ((CompareMem (&NewBmmData->COMBaudRate[Index], &OldBmmData->COMBaudRate[Index], sizeof (NewBmmData->COMBaudRate[Index])) == 0) && (CompareMem (&NewBmmData->COMDataRate[Index], &OldBmmData->COMDataRate[Index], sizeof (NewBmmData->COMDataRate[Index])) == 0) && (CompareMem (&NewBmmData->COMStopBits[Index], &OldBmmData->COMStopBits[Index], sizeof (NewBmmData->COMStopBits[Index])) == 0) && (CompareMem (&NewBmmData->COMParity[Index], &OldBmmData->COMParity[Index], sizeof (NewBmmData->COMParity[Index])) == 0) && (CompareMem (&NewBmmData->COMTerminalType[Index], &OldBmmData->COMTerminalType[Index], sizeof (NewBmmData->COMTerminalType[Index])) == 0) && (CompareMem (&NewBmmData->COMFlowControl[Index], &OldBmmData->COMFlowControl[Index], sizeof (NewBmmData->COMFlowControl[Index])) == 0)) { continue; } TerminalAttChange = TRUE; } if (TerminalAttChange) { if (CompareMem (&NewBmmData->COMBaudRate[Index], &OldBmmData->COMBaudRate[Index], sizeof (NewBmmData->COMBaudRate[Index])) != 0) { Offset = OFFSET_OF (BMM_FAKE_NV_DATA, COMBaudRate); } else if (CompareMem (&NewBmmData->COMDataRate[Index], &OldBmmData->COMDataRate[Index], sizeof (NewBmmData->COMDataRate[Index])) != 0) { Offset = OFFSET_OF (BMM_FAKE_NV_DATA, COMDataRate); } else if (CompareMem (&NewBmmData->COMStopBits[Index], &OldBmmData->COMStopBits[Index], sizeof (NewBmmData->COMStopBits[Index])) != 0) { Offset = OFFSET_OF (BMM_FAKE_NV_DATA, COMStopBits); } else if (CompareMem (&NewBmmData->COMParity[Index], &OldBmmData->COMParity[Index], sizeof (NewBmmData->COMParity[Index])) != 0) { Offset = OFFSET_OF (BMM_FAKE_NV_DATA, COMParity); } else if (CompareMem (&NewBmmData->COMTerminalType[Index], &OldBmmData->COMTerminalType[Index], sizeof (NewBmmData->COMTerminalType[Index])) != 0) { Offset = OFFSET_OF (BMM_FAKE_NV_DATA, COMTerminalType); } else if (CompareMem (&NewBmmData->COMFlowControl[Index], &OldBmmData->COMFlowControl[Index], sizeof (NewBmmData->COMFlowControl[Index])) != 0) { Offset = OFFSET_OF (BMM_FAKE_NV_DATA, COMFlowControl); } Status = Var_UpdateConsoleInpOption (); if (EFI_ERROR (Status)) { goto Exit; } Status = Var_UpdateConsoleOutOption (); if (EFI_ERROR (Status)) { goto Exit; } Status = Var_UpdateErrorOutOption (); if (EFI_ERROR (Status)) { goto Exit; } } // // Check data which located in Console Options Menu and save the settings if need // if (CompareMem (NewBmmData->ConsoleInCheck, OldBmmData->ConsoleInCheck, sizeof (NewBmmData->ConsoleInCheck)) != 0) { Status = Var_UpdateConsoleInpOption (); if (EFI_ERROR (Status)) { Offset = OFFSET_OF (BMM_FAKE_NV_DATA, ConsoleInCheck); goto Exit; } } if (CompareMem (NewBmmData->ConsoleOutCheck, OldBmmData->ConsoleOutCheck, sizeof (NewBmmData->ConsoleOutCheck)) != 0) { Status = Var_UpdateConsoleOutOption (); if (EFI_ERROR (Status)) { Offset = OFFSET_OF (BMM_FAKE_NV_DATA, ConsoleOutCheck); goto Exit; } } if (CompareMem (NewBmmData->ConsoleErrCheck, OldBmmData->ConsoleErrCheck, sizeof (NewBmmData->ConsoleErrCheck)) != 0) { Status = Var_UpdateErrorOutOption (); if (EFI_ERROR (Status)) { Offset = OFFSET_OF (BMM_FAKE_NV_DATA, ConsoleErrCheck); goto Exit; } } if ((CompareMem (NewBmmData->BootDescriptionData, OldBmmData->BootDescriptionData, sizeof (NewBmmData->BootDescriptionData)) != 0) || (CompareMem (NewBmmData->BootOptionalData, OldBmmData->BootOptionalData, sizeof (NewBmmData->BootOptionalData)) != 0)) { Status = Var_UpdateBootOption (Private); NewBmmData->BootOptionChanged = FALSE; if (EFI_ERROR (Status)) { if (CompareMem (NewBmmData->BootDescriptionData, OldBmmData->BootDescriptionData, sizeof (NewBmmData->BootDescriptionData)) != 0) { Offset = OFFSET_OF (BMM_FAKE_NV_DATA, BootDescriptionData); } else { Offset = OFFSET_OF (BMM_FAKE_NV_DATA, BootOptionalData); } goto Exit; } BOpt_GetBootOptions (Private); } if ((CompareMem (NewBmmData->DriverDescriptionData, OldBmmData->DriverDescriptionData, sizeof (NewBmmData->DriverDescriptionData)) != 0) || (CompareMem (NewBmmData->DriverOptionalData, OldBmmData->DriverOptionalData, sizeof (NewBmmData->DriverOptionalData)) != 0)) { Status = Var_UpdateDriverOption ( Private, Private->BmmHiiHandle, NewBmmData->DriverDescriptionData, NewBmmData->DriverOptionalData, NewBmmData->ForceReconnect ); NewBmmData->DriverOptionChanged = FALSE; NewBmmData->ForceReconnect = TRUE; if (EFI_ERROR (Status)) { if (CompareMem (NewBmmData->DriverDescriptionData, OldBmmData->DriverDescriptionData, sizeof (NewBmmData->DriverDescriptionData)) != 0) { Offset = OFFSET_OF (BMM_FAKE_NV_DATA, DriverDescriptionData); } else { Offset = OFFSET_OF (BMM_FAKE_NV_DATA, DriverOptionalData); } goto Exit; } BOpt_GetDriverOptions (Private); } // // After user do the save action, need to update OldBmmData. // CopyMem (OldBmmData, NewBmmData, sizeof (BMM_FAKE_NV_DATA)); return EFI_SUCCESS; Exit: // // Fail to save the data, update the progress string. // *Progress = UpdateProgress (Offset, Configuration); if (Status == EFI_OUT_OF_RESOURCES) { return Status; } else { return EFI_NOT_FOUND; } } /** This function processes the results of changes in configuration. @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. @param Action Specifies the type of action taken by the browser. @param QuestionId A unique value which is sent to the original exporting driver so that it can identify the type of data to expect. @param Type The type of value for the question. @param Value A pointer to the data being sent to the original exporting driver. @param ActionRequest On return, points to the action requested by the callback function. @retval EFI_SUCCESS The callback successfully handled the action. @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data. @retval EFI_DEVICE_ERROR The variable could not be saved. @retval EFI_UNSUPPORTED The specified Action is not supported by the callback. @retval EFI_INVALID_PARAMETER The parameter of Value or ActionRequest is invalid. **/ EFI_STATUS EFIAPI BootMaintCallback ( IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, IN EFI_BROWSER_ACTION Action, IN EFI_QUESTION_ID QuestionId, IN UINT8 Type, IN EFI_IFR_TYPE_VALUE *Value, OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest ) { BMM_CALLBACK_DATA *Private; BM_MENU_ENTRY *NewMenuEntry; BMM_FAKE_NV_DATA *CurrentFakeNVMap; BMM_FAKE_NV_DATA *OldFakeNVMap; UINTN Index; EFI_DEVICE_PATH_PROTOCOL *File; if ((Action != EFI_BROWSER_ACTION_CHANGING) && (Action != EFI_BROWSER_ACTION_CHANGED) && (Action != EFI_BROWSER_ACTION_FORM_OPEN)) { // // Do nothing for other UEFI Action. Only do call back when data is changed or the form is open. // return EFI_UNSUPPORTED; } Private = BMM_CALLBACK_DATA_FROM_THIS (This); if (Action == EFI_BROWSER_ACTION_FORM_OPEN) { if (QuestionId == KEY_VALUE_TRIGGER_FORM_OPEN_ACTION) { if (!mFirstEnterBMMForm) { // // BMMUiLib depends on LegacyUi library to show legacy menus. // If we want to show Legacy menus correctly in BMM page, // we must do it after the LegacyUi library has already been initialized. // Opening the BMM form is the appropriate time that the LegacyUi library has already been initialized. // So we do the tasks which are related to legacy menus here. // 1. Update the menus (including legacy munu) show in BootMiantenanceManager page. // 2. Re-scan the BootOption menus (including the legacy boot option). // CustomizeMenus (); EfiBootManagerRefreshAllBootOption (); BOpt_GetBootOptions (Private); mFirstEnterBMMForm = TRUE; } } } // // Retrieve uncommitted data from Form Browser // CurrentFakeNVMap = &Private->BmmFakeNvData; OldFakeNVMap = &Private->BmmOldFakeNVData; HiiGetBrowserData (&mBootMaintGuid, mBootMaintStorageName, sizeof (BMM_FAKE_NV_DATA), (UINT8 *)CurrentFakeNVMap); if (Action == EFI_BROWSER_ACTION_CHANGING) { if (Value == NULL) { return EFI_INVALID_PARAMETER; } UpdatePageId (Private, QuestionId); if (QuestionId < FILE_OPTION_OFFSET) { if (QuestionId < CONFIG_OPTION_OFFSET) { switch (QuestionId) { case FORM_BOOT_ADD_ID: // Leave BMM and enter FileExplorer. ChooseFile (NULL, L".efi", CreateBootOptionFromFile, &File); break; case FORM_DRV_ADD_FILE_ID: // Leave BMM and enter FileExplorer. ChooseFile (NULL, L".efi", CreateDriverOptionFromFile, &File); break; case FORM_DRV_ADD_HANDLE_ID: CleanUpPage (FORM_DRV_ADD_HANDLE_ID, Private); UpdateDrvAddHandlePage (Private); break; case FORM_BOOT_DEL_ID: CleanUpPage (FORM_BOOT_DEL_ID, Private); UpdateBootDelPage (Private); break; case FORM_BOOT_CHG_ID: case FORM_DRV_CHG_ID: UpdatePageBody (QuestionId, Private); break; case FORM_DRV_DEL_ID: CleanUpPage (FORM_DRV_DEL_ID, Private); UpdateDrvDelPage (Private); break; case FORM_CON_IN_ID: case FORM_CON_OUT_ID: case FORM_CON_ERR_ID: UpdatePageBody (QuestionId, Private); break; case FORM_CON_MODE_ID: CleanUpPage (FORM_CON_MODE_ID, Private); UpdateConModePage (Private); break; case FORM_CON_COM_ID: CleanUpPage (FORM_CON_COM_ID, Private); UpdateConCOMPage (Private); break; default: break; } } else if ((QuestionId >= TERMINAL_OPTION_OFFSET) && (QuestionId < CONSOLE_OPTION_OFFSET)) { Index = (UINT16)(QuestionId - TERMINAL_OPTION_OFFSET); Private->CurrentTerminal = Index; CleanUpPage (FORM_CON_COM_SETUP_ID, Private); UpdateTerminalPage (Private); } else if (QuestionId >= HANDLE_OPTION_OFFSET) { Index = (UINT16)(QuestionId - HANDLE_OPTION_OFFSET); NewMenuEntry = BOpt_GetMenuEntry (&DriverMenu, Index); ASSERT (NewMenuEntry != NULL); Private->HandleContext = (BM_HANDLE_CONTEXT *)NewMenuEntry->VariableContext; CleanUpPage (FORM_DRV_ADD_HANDLE_DESC_ID, Private); Private->MenuEntry = NewMenuEntry; Private->LoadContext->FilePathList = Private->HandleContext->DevicePath; UpdateDriverAddHandleDescPage (Private); } } if (QuestionId == KEY_VALUE_BOOT_FROM_FILE) { // Leave BMM and enter FileExplorer. ChooseFile (NULL, L".efi", BootFromFile, &File); } } else if (Action == EFI_BROWSER_ACTION_CHANGED) { if ((Value == NULL) || (ActionRequest == NULL)) { return EFI_INVALID_PARAMETER; } if (QuestionId == KEY_VALUE_SAVE_AND_EXIT_BOOT) { CleanUselessBeforeSubmit (Private); CurrentFakeNVMap->BootOptionChanged = FALSE; *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT; } else if (QuestionId == KEY_VALUE_SAVE_AND_EXIT_DRIVER) { CleanUselessBeforeSubmit (Private); CurrentFakeNVMap->DriverOptionChanged = FALSE; *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT; } else if (QuestionId == KEY_VALUE_NO_SAVE_AND_EXIT_DRIVER) { // // Discard changes and exit formset // ZeroMem (CurrentFakeNVMap->DriverOptionalData, sizeof (CurrentFakeNVMap->DriverOptionalData)); ZeroMem (CurrentFakeNVMap->BootDescriptionData, sizeof (CurrentFakeNVMap->BootDescriptionData)); ZeroMem (OldFakeNVMap->DriverOptionalData, sizeof (OldFakeNVMap->DriverOptionalData)); ZeroMem (OldFakeNVMap->DriverDescriptionData, sizeof (OldFakeNVMap->DriverDescriptionData)); CurrentFakeNVMap->DriverOptionChanged = FALSE; CurrentFakeNVMap->ForceReconnect = TRUE; *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT; } else if (QuestionId == KEY_VALUE_NO_SAVE_AND_EXIT_BOOT) { // // Discard changes and exit formset // ZeroMem (CurrentFakeNVMap->BootOptionalData, sizeof (CurrentFakeNVMap->BootOptionalData)); ZeroMem (CurrentFakeNVMap->BootDescriptionData, sizeof (CurrentFakeNVMap->BootDescriptionData)); ZeroMem (OldFakeNVMap->BootOptionalData, sizeof (OldFakeNVMap->BootOptionalData)); ZeroMem (OldFakeNVMap->BootDescriptionData, sizeof (OldFakeNVMap->BootDescriptionData)); CurrentFakeNVMap->BootOptionChanged = FALSE; *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT; } else if ((QuestionId == KEY_VALUE_BOOT_DESCRIPTION) || (QuestionId == KEY_VALUE_BOOT_OPTION)) { CurrentFakeNVMap->BootOptionChanged = TRUE; } else if ((QuestionId == KEY_VALUE_DRIVER_DESCRIPTION) || (QuestionId == KEY_VALUE_DRIVER_OPTION)) { CurrentFakeNVMap->DriverOptionChanged = TRUE; } if ((QuestionId >= BOOT_OPTION_DEL_QUESTION_ID) && (QuestionId < BOOT_OPTION_DEL_QUESTION_ID + MAX_MENU_NUMBER)) { if (Value->b) { // // Means user try to delete this boot option but not press F10 or "Commit Changes and Exit" menu. // CurrentFakeNVMap->BootOptionDelMark[QuestionId - BOOT_OPTION_DEL_QUESTION_ID] = TRUE; } else { // // Means user remove the old check status. // CurrentFakeNVMap->BootOptionDelMark[QuestionId - BOOT_OPTION_DEL_QUESTION_ID] = FALSE; } } else if ((QuestionId >= DRIVER_OPTION_DEL_QUESTION_ID) && (QuestionId < DRIVER_OPTION_DEL_QUESTION_ID + MAX_MENU_NUMBER)) { if (Value->b) { CurrentFakeNVMap->DriverOptionDelMark[QuestionId - DRIVER_OPTION_DEL_QUESTION_ID] = TRUE; } else { CurrentFakeNVMap->DriverOptionDelMark[QuestionId - DRIVER_OPTION_DEL_QUESTION_ID] = FALSE; } } else { switch (QuestionId) { case KEY_VALUE_SAVE_AND_EXIT: case KEY_VALUE_NO_SAVE_AND_EXIT: if (QuestionId == KEY_VALUE_SAVE_AND_EXIT) { CleanUselessBeforeSubmit (Private); *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT; } else if (QuestionId == KEY_VALUE_NO_SAVE_AND_EXIT) { DiscardChangeHandler (Private, CurrentFakeNVMap); *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT; } break; case FORM_RESET: gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL); return EFI_UNSUPPORTED; default: break; } } // // Update the content in Terminal menu and Console menu here. // if ((QuestionId == COM_BAUD_RATE_QUESTION_ID + Private->CurrentTerminal) || (QuestionId == COM_DATA_RATE_QUESTION_ID + Private->CurrentTerminal) || (QuestionId == COM_PARITY_QUESTION_ID + Private->CurrentTerminal) || (QuestionId == COM_STOP_BITS_QUESTION_ID + Private->CurrentTerminal) || (QuestionId == COM_TERMINAL_QUESTION_ID + Private->CurrentTerminal) || (QuestionId == COM_FLOWCONTROL_QUESTION_ID + Private->CurrentTerminal) ) { UpdateTerminalContent (CurrentFakeNVMap); } if ((QuestionId >= CON_IN_DEVICE_QUESTION_ID) && (QuestionId < CON_IN_DEVICE_QUESTION_ID + MAX_MENU_NUMBER)) { UpdateConsoleContent (L"ConIn", CurrentFakeNVMap); } else if ((QuestionId >= CON_OUT_DEVICE_QUESTION_ID) && (QuestionId < CON_OUT_DEVICE_QUESTION_ID + MAX_MENU_NUMBER)) { UpdateConsoleContent (L"ConOut", CurrentFakeNVMap); } else if ((QuestionId >= CON_ERR_DEVICE_QUESTION_ID) && (QuestionId < CON_ERR_DEVICE_QUESTION_ID + MAX_MENU_NUMBER)) { UpdateConsoleContent (L"ErrOut", CurrentFakeNVMap); } } // // Pass changed uncommitted data back to Form Browser // HiiSetBrowserData (&mBootMaintGuid, mBootMaintStorageName, sizeof (BMM_FAKE_NV_DATA), (UINT8 *)CurrentFakeNVMap, NULL); return EFI_SUCCESS; } /** Discard all changes done to the BMM pages such as Boot Order change, Driver order change. @param Private The BMM context data. @param CurrentFakeNVMap The current Fack NV Map. **/ VOID DiscardChangeHandler ( IN BMM_CALLBACK_DATA *Private, IN BMM_FAKE_NV_DATA *CurrentFakeNVMap ) { UINT16 Index; switch (Private->BmmPreviousPageId) { case FORM_BOOT_CHG_ID: CopyMem (CurrentFakeNVMap->BootOptionOrder, Private->BmmOldFakeNVData.BootOptionOrder, sizeof (CurrentFakeNVMap->BootOptionOrder)); break; case FORM_DRV_CHG_ID: CopyMem (CurrentFakeNVMap->DriverOptionOrder, Private->BmmOldFakeNVData.DriverOptionOrder, sizeof (CurrentFakeNVMap->DriverOptionOrder)); break; case FORM_BOOT_DEL_ID: ASSERT (BootOptionMenu.MenuNumber <= (sizeof (CurrentFakeNVMap->BootOptionDel) / sizeof (CurrentFakeNVMap->BootOptionDel[0]))); for (Index = 0; Index < BootOptionMenu.MenuNumber; Index++) { CurrentFakeNVMap->BootOptionDel[Index] = FALSE; } break; case FORM_DRV_DEL_ID: ASSERT (DriverOptionMenu.MenuNumber <= (sizeof (CurrentFakeNVMap->DriverOptionDel) / sizeof (CurrentFakeNVMap->DriverOptionDel[0]))); for (Index = 0; Index < DriverOptionMenu.MenuNumber; Index++) { CurrentFakeNVMap->DriverOptionDel[Index] = FALSE; } break; case FORM_BOOT_NEXT_ID: CurrentFakeNVMap->BootNext = Private->BmmOldFakeNVData.BootNext; break; case FORM_TIME_OUT_ID: CurrentFakeNVMap->BootTimeOut = Private->BmmOldFakeNVData.BootTimeOut; break; case FORM_DRV_ADD_HANDLE_DESC_ID: case FORM_DRV_ADD_FILE_ID: case FORM_DRV_ADD_HANDLE_ID: CurrentFakeNVMap->DriverAddHandleDesc[0] = 0x0000; CurrentFakeNVMap->DriverAddHandleOptionalData[0] = 0x0000; break; default: break; } } /** This function is to clean some useless data before submit changes. @param Private The BMM context data. **/ VOID CleanUselessBeforeSubmit ( IN BMM_CALLBACK_DATA *Private ) { UINT16 Index; if (Private->BmmPreviousPageId != FORM_BOOT_DEL_ID) { for (Index = 0; Index < BootOptionMenu.MenuNumber; Index++) { if (Private->BmmFakeNvData.BootOptionDel[Index] && !Private->BmmFakeNvData.BootOptionDelMark[Index]) { Private->BmmFakeNvData.BootOptionDel[Index] = FALSE; Private->BmmOldFakeNVData.BootOptionDel[Index] = FALSE; } } } if (Private->BmmPreviousPageId != FORM_DRV_DEL_ID) { for (Index = 0; Index < DriverOptionMenu.MenuNumber; Index++) { if (Private->BmmFakeNvData.DriverOptionDel[Index] && !Private->BmmFakeNvData.DriverOptionDelMark[Index]) { Private->BmmFakeNvData.DriverOptionDel[Index] = FALSE; Private->BmmOldFakeNVData.DriverOptionDel[Index] = FALSE; } } } } /** Update the menus in the BMM page. **/ VOID CustomizeMenus ( VOID ) { VOID *StartOpCodeHandle; VOID *EndOpCodeHandle; EFI_IFR_GUID_LABEL *StartGuidLabel; EFI_IFR_GUID_LABEL *EndGuidLabel; // // Allocate space for creation of UpdateData Buffer // StartOpCodeHandle = HiiAllocateOpCodeHandle (); ASSERT (StartOpCodeHandle != NULL); EndOpCodeHandle = HiiAllocateOpCodeHandle (); ASSERT (EndOpCodeHandle != NULL); // // Create Hii Extend Label OpCode as the start opcode // StartGuidLabel = (EFI_IFR_GUID_LABEL *)HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL)); StartGuidLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; StartGuidLabel->Number = LABEL_FORM_MAIN_START; // // Create Hii Extend Label OpCode as the end opcode // EndGuidLabel = (EFI_IFR_GUID_LABEL *)HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL)); EndGuidLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; EndGuidLabel->Number = LABEL_FORM_MAIN_END; // // Updata Front Page form // UiCustomizeBMMPage ( mBmmCallbackInfo->BmmHiiHandle, StartOpCodeHandle ); HiiUpdateForm ( mBmmCallbackInfo->BmmHiiHandle, &mBootMaintGuid, FORM_MAIN_ID, StartOpCodeHandle, EndOpCodeHandle ); HiiFreeOpCodeHandle (StartOpCodeHandle); HiiFreeOpCodeHandle (EndOpCodeHandle); } /** Create dynamic code for BMM and initialize all of BMM configuration data in BmmFakeNvData and BmmOldFakeNVData member in BMM context data. @param CallbackData The BMM context data. **/ VOID InitializeBmmConfig ( IN BMM_CALLBACK_DATA *CallbackData ) { BM_MENU_ENTRY *NewMenuEntry; BM_LOAD_CONTEXT *NewLoadContext; UINT16 Index; ASSERT (CallbackData != NULL); // // Initialize data which located in BMM main page // CallbackData->BmmFakeNvData.BootNext = NONE_BOOTNEXT_VALUE; for (Index = 0; Index < BootOptionMenu.MenuNumber; Index++) { NewMenuEntry = BOpt_GetMenuEntry (&BootOptionMenu, Index); NewLoadContext = (BM_LOAD_CONTEXT *)NewMenuEntry->VariableContext; if (NewLoadContext->IsBootNext) { CallbackData->BmmFakeNvData.BootNext = Index; break; } } CallbackData->BmmFakeNvData.BootTimeOut = PcdGet16 (PcdPlatformBootTimeOut); // // Initialize data which located in Boot Options Menu // GetBootOrder (CallbackData); // // Initialize data which located in Driver Options Menu // GetDriverOrder (CallbackData); // // Initialize data which located in Console Options Menu // GetConsoleOutMode (CallbackData); GetConsoleInCheck (CallbackData); GetConsoleOutCheck (CallbackData); GetConsoleErrCheck (CallbackData); GetTerminalAttribute (CallbackData); CallbackData->BmmFakeNvData.ForceReconnect = TRUE; // // Backup Initialize BMM configuartion data to BmmOldFakeNVData // CopyMem (&CallbackData->BmmOldFakeNVData, &CallbackData->BmmFakeNvData, sizeof (BMM_FAKE_NV_DATA)); } /** Initialized all Menu Option List. @param CallbackData The BMM context data. **/ VOID InitAllMenu ( IN BMM_CALLBACK_DATA *CallbackData ) { InitializeListHead (&BootOptionMenu.Head); InitializeListHead (&DriverOptionMenu.Head); BOpt_GetBootOptions (CallbackData); BOpt_GetDriverOptions (CallbackData); BOpt_FindDrivers (); InitializeListHead (&ConsoleInpMenu.Head); InitializeListHead (&ConsoleOutMenu.Head); InitializeListHead (&ConsoleErrMenu.Head); InitializeListHead (&TerminalMenu.Head); LocateSerialIo (); GetAllConsoles (); mAllMenuInit = TRUE; } /** Free up all Menu Option list. **/ VOID FreeAllMenu ( VOID ) { if (!mAllMenuInit) { return; } BOpt_FreeMenu (&BootOptionMenu); BOpt_FreeMenu (&DriverOptionMenu); BOpt_FreeMenu (&DriverMenu); FreeAllConsoles (); mAllMenuInit = FALSE; } /** Initial the boot mode related parameters. **/ VOID BmmInitialBootModeInfo ( VOID ) { EFI_STATUS Status; EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput; EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOut; UINTN BootTextColumn; UINTN BootTextRow; if (mBmmModeInitialized) { return; } // // After the console is ready, get current video resolution // and text mode before launching setup at first time. // Status = gBS->HandleProtocol ( gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID **)&GraphicsOutput ); if (EFI_ERROR (Status)) { GraphicsOutput = NULL; } Status = gBS->HandleProtocol ( gST->ConsoleOutHandle, &gEfiSimpleTextOutProtocolGuid, (VOID **)&SimpleTextOut ); if (EFI_ERROR (Status)) { SimpleTextOut = NULL; } if (GraphicsOutput != NULL) { // // Get current video resolution and text mode. // mBmmBootHorizontalResolution = GraphicsOutput->Mode->Info->HorizontalResolution; mBmmBootVerticalResolution = GraphicsOutput->Mode->Info->VerticalResolution; } if (SimpleTextOut != NULL) { Status = SimpleTextOut->QueryMode ( SimpleTextOut, SimpleTextOut->Mode->Mode, &BootTextColumn, &BootTextRow ); mBmmBootTextModeColumn = (UINT32)BootTextColumn; mBmmBootTextModeRow = (UINT32)BootTextRow; } // // Get user defined text mode for setup. // mBmmSetupHorizontalResolution = PcdGet32 (PcdSetupVideoHorizontalResolution); mBmmSetupVerticalResolution = PcdGet32 (PcdSetupVideoVerticalResolution); mBmmSetupTextModeColumn = PcdGet32 (PcdSetupConOutColumn); mBmmSetupTextModeRow = PcdGet32 (PcdSetupConOutRow); mBmmModeInitialized = TRUE; } /** Install Boot Maintenance Manager Menu driver. @param ImageHandle The image handle. @param SystemTable The system table. @retval EFI_SUCEESS Install Boot manager menu success. @retval Other Return error status. **/ EFI_STATUS EFIAPI BootMaintenanceManagerUiLibConstructor ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; UINT8 *Ptr; Status = EFI_SUCCESS; // // Install Device Path Protocol and Config Access protocol to driver handle // Status = gBS->InstallMultipleProtocolInterfaces ( &mBmmCallbackInfo->BmmDriverHandle, &gEfiDevicePathProtocolGuid, &mBmmHiiVendorDevicePath, &gEfiHiiConfigAccessProtocolGuid, &mBmmCallbackInfo->BmmConfigAccess, NULL ); ASSERT_EFI_ERROR (Status); // // Post our Boot Maint VFR binary to the HII database. // mBmmCallbackInfo->BmmHiiHandle = HiiAddPackages ( &mBootMaintGuid, mBmmCallbackInfo->BmmDriverHandle, BootMaintenanceManagerBin, BootMaintenanceManagerUiLibStrings, NULL ); ASSERT (mBmmCallbackInfo->BmmHiiHandle != NULL); // // Locate Formbrowser2 protocol // Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **)&mBmmCallbackInfo->FormBrowser2); ASSERT_EFI_ERROR (Status); // // Create LoadOption in BmmCallbackInfo for Driver Callback // Ptr = AllocateZeroPool (sizeof (BM_LOAD_CONTEXT) + sizeof (BM_FILE_CONTEXT) + sizeof (BM_HANDLE_CONTEXT) + sizeof (BM_MENU_ENTRY)); ASSERT (Ptr != NULL); // // Initialize Bmm callback data. // mBmmCallbackInfo->LoadContext = (BM_LOAD_CONTEXT *)Ptr; Ptr += sizeof (BM_LOAD_CONTEXT); mBmmCallbackInfo->FileContext = (BM_FILE_CONTEXT *)Ptr; Ptr += sizeof (BM_FILE_CONTEXT); mBmmCallbackInfo->HandleContext = (BM_HANDLE_CONTEXT *)Ptr; Ptr += sizeof (BM_HANDLE_CONTEXT); mBmmCallbackInfo->MenuEntry = (BM_MENU_ENTRY *)Ptr; mBmmCallbackInfo->BmmPreviousPageId = FORM_MAIN_ID; mBmmCallbackInfo->BmmCurrentPageId = FORM_MAIN_ID; InitAllMenu (mBmmCallbackInfo); CreateUpdateData (); // // Update boot maintenance manager page // InitializeBmmConfig (mBmmCallbackInfo); BmmInitialBootModeInfo (); return EFI_SUCCESS; } /** Unloads the application and its installed protocol. @param ImageHandle Handle that identifies the image to be unloaded. @param SystemTable The system table. @retval EFI_SUCCESS The image has been unloaded. **/ EFI_STATUS EFIAPI BootMaintenanceManagerUiLibDestructor ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { if (mStartOpCodeHandle != NULL) { HiiFreeOpCodeHandle (mStartOpCodeHandle); } if (mEndOpCodeHandle != NULL) { HiiFreeOpCodeHandle (mEndOpCodeHandle); } FreeAllMenu (); // // Remove our IFR data from HII database // HiiRemovePackages (mBmmCallbackInfo->BmmHiiHandle); gBS->UninstallMultipleProtocolInterfaces ( mBmmCallbackInfo->BmmDriverHandle, &gEfiDevicePathProtocolGuid, &mBmmHiiVendorDevicePath, &gEfiHiiConfigAccessProtocolGuid, &mBmmCallbackInfo->BmmConfigAccess, NULL ); FreePool (mBmmCallbackInfo->LoadContext); mBmmCallbackInfo->BmmDriverHandle = NULL; return EFI_SUCCESS; }