/** @file | |
Framework to UEFI 2.1 Setup Browser Thunk. The file consume EFI_FORM_BROWSER2_PROTOCOL | |
to produce a EFI_FORM_BROWSER_PROTOCOL. | |
Copyright (c) 2008 - 2011, Intel Corporation. All rights reserved.<BR> | |
This program and the accompanying materials | |
are licensed and made available under the terms and conditions of the BSD License | |
which accompanies this distribution. The full text of the license may be found at | |
http://opensource.org/licenses/bsd-license.php | |
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
**/ | |
#include "HiiDatabase.h" | |
#include "SetupBrowser.h" | |
EFI_HII_HANDLE gStringPackHandle = NULL; | |
BOOLEAN mFrontPageDisplayed = FALSE; | |
// | |
// 106F3545-B788-4cb5-9D2A-CE0CDB208DF5 | |
// | |
EFI_GUID gEfiHiiThunkProducerGuid = { 0x106f3545, 0xb788, 0x4cb5, { 0x9d, 0x2a, 0xce, 0xc, 0xdb, 0x20, 0x8d, 0xf5 } }; | |
/** | |
Get string by string id from HII Interface | |
@param Id String ID. | |
@retval CHAR16 * String from ID. | |
@retval NULL If error occurs. | |
**/ | |
CHAR16 * | |
GetStringById ( | |
IN EFI_STRING_ID Id | |
) | |
{ | |
return HiiGetString (gStringPackHandle, Id, NULL); | |
} | |
/** | |
Show progress bar with title above it. It only works in Graphics mode. | |
@param TitleForeground Foreground color for Title. | |
@param TitleBackground Background color for Title. | |
@param Title Title above progress bar. | |
@param ProgressColor Progress bar color. | |
@param Progress Progress (0-100) | |
@param PreviousValue The previous value of the progress. | |
@retval EFI_STATUS Success update the progress bar | |
**/ | |
EFI_STATUS | |
PlatformBdsShowProgress ( | |
IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL TitleForeground, | |
IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL TitleBackground, | |
IN CHAR16 *Title, | |
IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL ProgressColor, | |
IN UINTN Progress, | |
IN UINTN PreviousValue | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput; | |
EFI_UGA_DRAW_PROTOCOL *UgaDraw; | |
UINT32 SizeOfX; | |
UINT32 SizeOfY; | |
UINT32 ColorDepth; | |
UINT32 RefreshRate; | |
EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color; | |
UINTN BlockHeight; | |
UINTN BlockWidth; | |
UINTN BlockNum; | |
UINTN PosX; | |
UINTN PosY; | |
UINTN Index; | |
if (Progress > 100) { | |
return EFI_INVALID_PARAMETER; | |
} | |
UgaDraw = NULL; | |
Status = gBS->HandleProtocol ( | |
gST->ConsoleOutHandle, | |
&gEfiGraphicsOutputProtocolGuid, | |
(VOID **) &GraphicsOutput | |
); | |
if (EFI_ERROR (Status)) { | |
GraphicsOutput = NULL; | |
Status = gBS->HandleProtocol ( | |
gST->ConsoleOutHandle, | |
&gEfiUgaDrawProtocolGuid, | |
(VOID **) &UgaDraw | |
); | |
} | |
if (EFI_ERROR (Status) || (GraphicsOutput == NULL && UgaDraw == NULL)) { | |
return EFI_UNSUPPORTED; | |
} | |
SizeOfX = 0; | |
SizeOfY = 0; | |
if (GraphicsOutput != NULL) { | |
SizeOfX = GraphicsOutput->Mode->Info->HorizontalResolution; | |
SizeOfY = GraphicsOutput->Mode->Info->VerticalResolution; | |
} else { | |
Status = UgaDraw->GetMode ( | |
UgaDraw, | |
&SizeOfX, | |
&SizeOfY, | |
&ColorDepth, | |
&RefreshRate | |
); | |
if (EFI_ERROR (Status)) { | |
return EFI_UNSUPPORTED; | |
} | |
} | |
BlockWidth = SizeOfX / 100; | |
BlockHeight = SizeOfY / 50; | |
BlockNum = Progress; | |
PosX = 0; | |
PosY = SizeOfY * 48 / 50; | |
if (BlockNum == 0) { | |
// | |
// Clear progress area | |
// | |
SetMem (&Color, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0x0); | |
if (GraphicsOutput != NULL) { | |
Status = GraphicsOutput->Blt ( | |
GraphicsOutput, | |
&Color, | |
EfiBltVideoFill, | |
0, | |
0, | |
0, | |
PosY - EFI_GLYPH_HEIGHT - 1, | |
SizeOfX, | |
SizeOfY - (PosY - EFI_GLYPH_HEIGHT - 1), | |
SizeOfX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) | |
); | |
} else { | |
Status = UgaDraw->Blt ( | |
UgaDraw, | |
(EFI_UGA_PIXEL *) &Color, | |
EfiUgaVideoFill, | |
0, | |
0, | |
0, | |
PosY - EFI_GLYPH_HEIGHT - 1, | |
SizeOfX, | |
SizeOfY - (PosY - EFI_GLYPH_HEIGHT - 1), | |
SizeOfX * sizeof (EFI_UGA_PIXEL) | |
); | |
} | |
} | |
// | |
// Show progress by drawing blocks | |
// | |
for (Index = PreviousValue; Index < BlockNum; Index++) { | |
PosX = Index * BlockWidth; | |
if (GraphicsOutput != NULL) { | |
Status = GraphicsOutput->Blt ( | |
GraphicsOutput, | |
&ProgressColor, | |
EfiBltVideoFill, | |
0, | |
0, | |
PosX, | |
PosY, | |
BlockWidth - 1, | |
BlockHeight, | |
(BlockWidth) * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) | |
); | |
} else { | |
Status = UgaDraw->Blt ( | |
UgaDraw, | |
(EFI_UGA_PIXEL *) &ProgressColor, | |
EfiUgaVideoFill, | |
0, | |
0, | |
PosX, | |
PosY, | |
BlockWidth - 1, | |
BlockHeight, | |
(BlockWidth) * sizeof (EFI_UGA_PIXEL) | |
); | |
} | |
} | |
PrintXY ( | |
(SizeOfX - StrLen (Title) * EFI_GLYPH_WIDTH) / 2, | |
PosY - EFI_GLYPH_HEIGHT - 1, | |
&TitleForeground, | |
&TitleBackground, | |
Title | |
); | |
return EFI_SUCCESS; | |
} | |
/** | |
Function waits for a given event to fire, or for an optional timeout to expire. | |
@param Event The event to wait for | |
@param Timeout An optional timeout value in 100 ns units. | |
@retval EFI_SUCCESS Event fired before Timeout expired. | |
@retval EFI_TIME_OUT Timout expired before Event fired.. | |
**/ | |
EFI_STATUS | |
WaitForSingleEvent ( | |
IN EFI_EVENT Event, | |
IN UINT64 Timeout OPTIONAL | |
) | |
{ | |
EFI_STATUS Status; | |
UINTN Index; | |
EFI_EVENT TimerEvent; | |
EFI_EVENT WaitList[2]; | |
if (Timeout != 0) { | |
// | |
// Create a timer event | |
// | |
Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent); | |
if (!EFI_ERROR (Status)) { | |
// | |
// Set the timer event | |
// | |
gBS->SetTimer ( | |
TimerEvent, | |
TimerRelative, | |
Timeout | |
); | |
// | |
// Wait for the original event or the timer | |
// | |
WaitList[0] = Event; | |
WaitList[1] = TimerEvent; | |
Status = gBS->WaitForEvent (2, WaitList, &Index); | |
gBS->CloseEvent (TimerEvent); | |
// | |
// If the timer expired, change the return to timed out | |
// | |
if (!EFI_ERROR (Status) && Index == 1) { | |
Status = EFI_TIMEOUT; | |
} | |
} | |
} else { | |
// | |
// No timeout... just wait on the event | |
// | |
Status = gBS->WaitForEvent (1, &Event, &Index); | |
ASSERT (!EFI_ERROR (Status)); | |
ASSERT (Index == 0); | |
} | |
return Status; | |
} | |
/** | |
Function show progress bar to wait for user input. | |
@param TimeoutDefault - The fault time out value before the system | |
continue to boot. | |
@retval EFI_SUCCESS User pressed some key except "Enter" | |
@retval EFI_TIME_OUT Timout expired or user press "Enter" | |
**/ | |
EFI_STATUS | |
ShowProgress ( | |
IN UINT16 TimeoutDefault | |
) | |
{ | |
EFI_STATUS Status; | |
CHAR16 *TmpStr; | |
EFI_GRAPHICS_OUTPUT_BLT_PIXEL Foreground; | |
EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background; | |
EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color; | |
EFI_INPUT_KEY Key; | |
UINT16 TimeoutRemain; | |
if (TimeoutDefault == 0) { | |
return EFI_TIMEOUT; | |
} | |
DEBUG ((EFI_D_INFO, "\n\nStart showing progress bar... Press any key to stop it! ...Zzz....\n")); | |
SetMem (&Foreground, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0xff); | |
SetMem (&Background, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0x0); | |
SetMem (&Color, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0xff); | |
// | |
// Clear the progress status bar first | |
// | |
TmpStr = GetStringById (STRING_TOKEN (STR_START_BOOT_OPTION)); | |
if (TmpStr != NULL) { | |
PlatformBdsShowProgress (Foreground, Background, TmpStr, Color, 0, 0); | |
} | |
TimeoutRemain = TimeoutDefault; | |
while (TimeoutRemain != 0) { | |
DEBUG ((EFI_D_INFO, "Showing progress bar...Remaining %d second!\n", TimeoutRemain)); | |
Status = WaitForSingleEvent (gST->ConIn->WaitForKey, ONE_SECOND); | |
if (Status != EFI_TIMEOUT) { | |
break; | |
} | |
TimeoutRemain--; | |
// | |
// Show progress | |
// | |
if (TmpStr != NULL) { | |
PlatformBdsShowProgress ( | |
Foreground, | |
Background, | |
TmpStr, | |
Color, | |
((TimeoutDefault - TimeoutRemain) * 100 / TimeoutDefault), | |
0 | |
); | |
} | |
} | |
gBS->FreePool (TmpStr); | |
// | |
// Timeout expired | |
// | |
if (TimeoutRemain == 0) { | |
return EFI_TIMEOUT; | |
} | |
// | |
// User pressed some key | |
// | |
Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) { | |
// | |
// User pressed enter, equivalent to select "continue" | |
// | |
return EFI_TIMEOUT; | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
Return the default value for system Timeout variable. | |
@return Timeout value. | |
**/ | |
UINT16 | |
EFIAPI | |
GetTimeout ( | |
VOID | |
) | |
{ | |
return PcdGet16 (PcdPlatformBootTimeOut); | |
} | |
/** | |
This is the Framework Setup Browser interface which displays a FormSet. | |
@param This The EFI_FORM_BROWSER_PROTOCOL context. | |
@param UseDatabase TRUE if the FormSet is from HII database. The Thunk implementation | |
only support UseDatabase is TRUE. | |
@param Handle The Handle buffer. | |
@param HandleCount The number of Handle in the Handle Buffer. It must be 1 for this implementation. | |
@param Packet The pointer to data buffer containing IFR and String package. Not supported. | |
@param CallbackHandle Not supported. | |
@param NvMapOverride The buffer is used only when there is no NV variable to define the | |
current settings and the caller needs to provide to the browser the | |
current settings for the the "fake" NV variable. If used, no saving of | |
an NV variable is possbile. This parameter is also ignored if Handle is NULL. | |
@param ScreenDimensions | |
Allows the browser to be called so that it occupies a portion of the physical | |
screen instead of dynamically determining the screen dimensions. | |
@param ResetRequired This BOOLEAN value denotes whether a reset is required based on the data that | |
might have been changed. The ResetRequired parameter is primarily applicable | |
for configuration applications, and is an optional parameter. | |
@retval EFI_SUCCESS If the Formset is displayed correctly. | |
@retval EFI_UNSUPPORTED If UseDatabase is FALSE or HandleCount is not 1. | |
@retval EFI_INVALID_PARAMETER If the *Handle passed in is not found in the database. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
ThunkSendForm ( | |
IN EFI_FORM_BROWSER_PROTOCOL *This, | |
IN BOOLEAN UseDatabase, | |
IN FRAMEWORK_EFI_HII_HANDLE *Handle, | |
IN UINTN HandleCount, | |
IN EFI_IFR_PACKET *Packet, OPTIONAL | |
IN EFI_HANDLE CallbackHandle, OPTIONAL | |
IN UINT8 *NvMapOverride, OPTIONAL | |
IN FRAMEWORK_EFI_SCREEN_DESCRIPTOR *ScreenDimensions, OPTIONAL | |
OUT BOOLEAN *ResetRequired OPTIONAL | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_BROWSER_ACTION_REQUEST ActionRequest; | |
HII_THUNK_CONTEXT *ThunkContext; | |
HII_THUNK_PRIVATE_DATA *Private; | |
EFI_FORMBROWSER_THUNK_PRIVATE_DATA *BrowserPrivate; | |
if (!UseDatabase) { | |
// | |
// ThunkSendForm only support displays forms registered into the HII database. | |
// | |
return EFI_UNSUPPORTED; | |
} | |
if (HandleCount != 1 ) { | |
return EFI_UNSUPPORTED; | |
} | |
BrowserPrivate = EFI_FORMBROWSER_THUNK_PRIVATE_DATA_FROM_THIS (This); | |
Private = BrowserPrivate->ThunkPrivate; | |
ThunkContext = FwHiiHandleToThunkContext (Private, *Handle); | |
if (ThunkContext == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
// | |
// Following UEFI spec to do auto booting after a time-out. This feature is implemented | |
// in Framework Setup Browser and moved to MdeModulePkg/Universal/BdsDxe. The auto booting is | |
// moved here in HII Thunk module. | |
// | |
if (CompareGuid (&gFrameworkBdsFrontPageFormsetGuid, &ThunkContext->FormSet->Guid) && !mFrontPageDisplayed) { | |
// | |
// Send form is called before entering the | |
// | |
mFrontPageDisplayed = TRUE; | |
Status = ShowProgress (GetTimeout ()); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
} | |
if (NvMapOverride != NULL) { | |
ThunkContext->NvMapOverride = NvMapOverride; | |
} | |
Status = mFormBrowser2Protocol->SendForm ( | |
mFormBrowser2Protocol, | |
&ThunkContext->UefiHiiHandle, | |
1, | |
NULL, | |
0, | |
(EFI_SCREEN_DESCRIPTOR *) ScreenDimensions, | |
&ActionRequest | |
); | |
if (ActionRequest == EFI_BROWSER_ACTION_REQUEST_RESET) { | |
*ResetRequired = TRUE; | |
} | |
return Status; | |
} | |
/** | |
Rountine used to display a generic dialog interface and return | |
the Key or Input from user input. | |
@param LinesNumber The number of lines for the dialog box. | |
@param HotKey Defines if a single character is parsed (TRUE) and returned in KeyValue | |
or if a string is returned in StringBuffer. | |
@param MaximumStringSize The maximum size in bytes of a typed-in string. | |
@param StringBuffer On return contains the typed-in string if HotKey is FALSE. | |
@param Key The EFI_INPUT_KEY value returned if HotKey is TRUE. | |
@param FirstString The pointer to the first string in the list of strings | |
that comprise the dialog box. | |
@param ... A series of NumberOfLines text strings that will be used | |
to construct the dialog box. | |
@retval EFI_SUCCESS The dialog is created successfully and user interaction was received. | |
@retval EFI_DEVICE_ERROR The user typed in an ESC. | |
@retval EFI_INVALID_PARAMETER One of the parameters was invalid.(StringBuffer == NULL && HotKey == FALSE). | |
**/ | |
EFI_STATUS | |
EFIAPI | |
ThunkCreatePopUp ( | |
IN UINTN LinesNumber, | |
IN BOOLEAN HotKey, | |
IN UINTN MaximumStringSize, | |
OUT CHAR16 *StringBuffer, | |
OUT EFI_INPUT_KEY *Key, | |
IN CHAR16 *FirstString, | |
... | |
) | |
{ | |
VA_LIST Args; | |
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut; | |
EFI_SIMPLE_TEXT_OUTPUT_MODE SavedConsoleMode; | |
UINTN Columns; | |
UINTN Rows; | |
UINTN Column; | |
UINTN Row; | |
UINTN NumberOfLines; | |
UINTN MaxLength; | |
CHAR16 *String; | |
UINTN Length; | |
CHAR16 *Line; | |
UINTN EventIndex; | |
if (!HotKey) { | |
return EFI_UNSUPPORTED; | |
} | |
if (MaximumStringSize == 0) { | |
// | |
// Blank strint to output | |
// | |
return EFI_INVALID_PARAMETER; | |
} | |
// | |
// Determine the length of the longest line in the popup and the the total | |
// number of lines in the popup | |
// | |
MaxLength = StrLen (FirstString); | |
NumberOfLines = 1; | |
VA_START (Args, FirstString); | |
while ((String = VA_ARG (Args, CHAR16 *)) != NULL) { | |
MaxLength = MAX (MaxLength, StrLen (String)); | |
NumberOfLines++; | |
} | |
VA_END (Args); | |
// | |
// If the total number of lines in the popup is not same to the input NumberOfLines | |
// the parameter is not valid. Not check. | |
// | |
// if (NumberOfLines != LinesNumber) { | |
// return EFI_INVALID_PARAMETER; | |
// } | |
// | |
// If the maximum length of all the strings is not same to the input MaximumStringSize | |
// the parameter is not valid. Not check. | |
// | |
// if (MaxLength != MaximumStringSize) { | |
// return EFI_INVALID_PARAMETER; | |
// } | |
// | |
// Cache a pointer to the Simple Text Output Protocol in the EFI System Table | |
// | |
ConOut = gST->ConOut; | |
// | |
// Save the current console cursor position and attributes | |
// | |
CopyMem (&SavedConsoleMode, ConOut->Mode, sizeof (SavedConsoleMode)); | |
// | |
// Retrieve the number of columns and rows in the current console mode | |
// | |
ConOut->QueryMode (ConOut, SavedConsoleMode.Mode, &Columns, &Rows); | |
// | |
// Disable cursor and set the foreground and background colors specified by Attribute | |
// | |
ConOut->EnableCursor (ConOut, FALSE); | |
ConOut->SetAttribute (ConOut, EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE); | |
// | |
// Limit NumberOfLines to height of the screen minus 3 rows for the box itself | |
// | |
NumberOfLines = MIN (NumberOfLines, Rows - 3); | |
// | |
// Limit MaxLength to width of the screen minus 2 columns for the box itself | |
// | |
MaxLength = MIN (MaxLength, Columns - 2); | |
// | |
// Compute the starting row and starting column for the popup | |
// | |
Row = (Rows - (NumberOfLines + 3)) / 2; | |
Column = (Columns - (MaxLength + 2)) / 2; | |
// | |
// Allocate a buffer for a single line of the popup with borders and a Null-terminator | |
// | |
Line = AllocateZeroPool ((MaxLength + 3) * sizeof (CHAR16)); | |
ASSERT (Line != NULL); | |
// | |
// Draw top of popup box | |
// | |
SetMem16 (Line, (MaxLength + 2) * 2, BOXDRAW_HORIZONTAL); | |
Line[0] = BOXDRAW_DOWN_RIGHT; | |
Line[MaxLength + 1] = BOXDRAW_DOWN_LEFT; | |
Line[MaxLength + 2] = L'\0'; | |
ConOut->SetCursorPosition (ConOut, Column, Row++); | |
ConOut->OutputString (ConOut, Line); | |
// | |
// Draw middle of the popup with strings | |
// | |
VA_START (Args, FirstString); | |
String = FirstString; | |
while ((String != NULL) && (NumberOfLines > 0)) { | |
Length = StrLen (String); | |
SetMem16 (Line, (MaxLength + 2) * 2, L' '); | |
if (Length <= MaxLength) { | |
// | |
// Length <= MaxLength | |
// | |
CopyMem (Line + 1 + (MaxLength - Length) / 2, String , Length * sizeof (CHAR16)); | |
} else { | |
// | |
// Length > MaxLength | |
// | |
CopyMem (Line + 1, String + (Length - MaxLength) / 2 , MaxLength * sizeof (CHAR16)); | |
} | |
Line[0] = BOXDRAW_VERTICAL; | |
Line[MaxLength + 1] = BOXDRAW_VERTICAL; | |
Line[MaxLength + 2] = L'\0'; | |
ConOut->SetCursorPosition (ConOut, Column, Row++); | |
ConOut->OutputString (ConOut, Line); | |
String = VA_ARG (Args, CHAR16 *); | |
NumberOfLines--; | |
} | |
VA_END (Args); | |
// | |
// Draw bottom of popup box | |
// | |
SetMem16 (Line, (MaxLength + 2) * 2, BOXDRAW_HORIZONTAL); | |
Line[0] = BOXDRAW_UP_RIGHT; | |
Line[MaxLength + 1] = BOXDRAW_UP_LEFT; | |
Line[MaxLength + 2] = L'\0'; | |
ConOut->SetCursorPosition (ConOut, Column, Row++); | |
ConOut->OutputString (ConOut, Line); | |
// | |
// Free the allocated line buffer | |
// | |
FreePool (Line); | |
// | |
// Restore the cursor visibility, position, and attributes | |
// | |
ConOut->EnableCursor (ConOut, SavedConsoleMode.CursorVisible); | |
ConOut->SetCursorPosition (ConOut, SavedConsoleMode.CursorColumn, SavedConsoleMode.CursorRow); | |
ConOut->SetAttribute (ConOut, SavedConsoleMode.Attribute); | |
// | |
// Wait for a keystroke | |
// | |
if (Key != NULL) { | |
gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex); | |
gST->ConIn->ReadKeyStroke (gST->ConIn, Key); | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
Initialize string packages in HII database. | |
**/ | |
VOID | |
InitSetBrowserStrings ( | |
VOID | |
) | |
{ | |
// | |
// Initialize strings to HII database | |
// | |
gStringPackHandle = HiiAddPackages ( | |
&gEfiHiiThunkProducerGuid, | |
NULL, | |
STRING_ARRAY_NAME, | |
NULL | |
); | |
ASSERT (gStringPackHandle != NULL); | |
} |