/** @file | |
The functions for Boot Maintainence Main menu. | |
Copyright (c) 2004 - 2019, Intel Corporation. All rights reserved.<BR> | |
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 <ConfigRequest> 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 <ConfigAltResp> 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 <ConfigResp> 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 <ConfigHdr> 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 <BlockConfig> | |
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 | |
<ConfigString> 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 <ConfigHdr>. | |
// 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 <ConfigResp> 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; | |
} |