mirror of https://github.com/acidanthera/audk.git
2229 lines
72 KiB
C
2229 lines
72 KiB
C
/**@file
|
|
Entry and initialization module for the browser.
|
|
|
|
Copyright (c) 2006 - 2007 Intel Corporation. <BR>
|
|
All rights reserved. This program and the accompanying materials
|
|
are licensed and made available under the terms and conditions of the BSD License
|
|
which accompanies this distribution. The full text of the license may be found at
|
|
http://opensource.org/licenses/bsd-license.php
|
|
|
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
|
|
**/
|
|
|
|
|
|
#include "Setup.h"
|
|
#include "Ui.h"
|
|
|
|
FUNCTIION_KEY_SETTING gFunctionKeySettingTable[] = {
|
|
//
|
|
// Boot Manager
|
|
//
|
|
{
|
|
{
|
|
0x847bc3fe,
|
|
0xb974,
|
|
0x446d,
|
|
{
|
|
0x94,
|
|
0x49,
|
|
0x5a,
|
|
0xd5,
|
|
0x41,
|
|
0x2e,
|
|
0x99,
|
|
0x3b
|
|
}
|
|
},
|
|
NONE_FUNCTION_KEY_SETTING
|
|
},
|
|
//
|
|
// Device Manager
|
|
//
|
|
{
|
|
{
|
|
0x3ebfa8e6,
|
|
0x511d,
|
|
0x4b5b,
|
|
{
|
|
0xa9,
|
|
0x5f,
|
|
0xfb,
|
|
0x38,
|
|
0x26,
|
|
0xf,
|
|
0x1c,
|
|
0x27
|
|
}
|
|
},
|
|
NONE_FUNCTION_KEY_SETTING
|
|
},
|
|
//
|
|
// BMM Formset.
|
|
//
|
|
{
|
|
{
|
|
0x642237c7,
|
|
0x35d4,
|
|
0x472d,
|
|
{
|
|
0x83,
|
|
0x65,
|
|
0x12,
|
|
0xe0,
|
|
0xcc,
|
|
0xf2,
|
|
0x7a,
|
|
0x22
|
|
}
|
|
},
|
|
NONE_FUNCTION_KEY_SETTING
|
|
},
|
|
//
|
|
// BMM File Explorer Formset.
|
|
//
|
|
{
|
|
{
|
|
0x1f2d63e1,
|
|
0xfebd,
|
|
0x4dc7,
|
|
{
|
|
0x9c,
|
|
0xc5,
|
|
0xba,
|
|
0x2b,
|
|
0x1c,
|
|
0xef,
|
|
0x9c,
|
|
0x5b
|
|
}
|
|
},
|
|
NONE_FUNCTION_KEY_SETTING
|
|
},
|
|
};
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
InitializeBinaryStructures (
|
|
IN EFI_HII_HANDLE *Handle,
|
|
IN BOOLEAN UseDatabase,
|
|
IN EFI_IFR_PACKET *Packet,
|
|
IN UINT8 *NvMapOverride,
|
|
IN UINTN NumberOfIfrImages,
|
|
EFI_FILE_FORM_TAGS **FileFormTagsHead
|
|
);
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
InitializeTagStructures (
|
|
IN EFI_IFR_BINARY *BinaryData,
|
|
OUT EFI_FILE_FORM_TAGS *FileFormTags
|
|
);
|
|
|
|
STATIC
|
|
UI_MENU_OPTION *
|
|
DisplayHomePage (
|
|
IN UINTN NumberOfIfrImages,
|
|
IN EFI_FILE_FORM_TAGS *FileFormTagsHead,
|
|
IN UINT8 *CallbackData
|
|
);
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
GetIfrBinaryData (
|
|
IN EFI_HII_PROTOCOL *Hii,
|
|
IN EFI_HII_HANDLE HiiHandle,
|
|
IN EFI_IFR_PACKET *Packet,
|
|
IN EFI_IFR_BINARY *BinaryData
|
|
);
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
InstallPrint (
|
|
VOID
|
|
);
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
SendForm (
|
|
IN EFI_FORM_BROWSER_PROTOCOL * This,
|
|
IN BOOLEAN UseDatabase,
|
|
IN EFI_HII_HANDLE * Handle,
|
|
IN UINTN HandleCount,
|
|
IN EFI_IFR_PACKET * Packet,
|
|
IN EFI_HANDLE CallbackHandle,
|
|
IN UINT8 *NvMapOverride,
|
|
IN EFI_SCREEN_DESCRIPTOR *ScreenDimensions, OPTIONAL
|
|
OUT BOOLEAN *ResetRequired OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the routine which an external caller uses to direct the browser
|
|
where to obtain it's information.
|
|
|
|
Arguments:
|
|
|
|
UseDatabase - If set to TRUE, then all information is retrieved from the HII database handle specified
|
|
If set to FALSE, then the passed in Packet and CallbackHandle is used and Handle is ignored
|
|
|
|
Handle - A pointer to an array of Handles. If HandleCount > 1 we display a list of the formsets for the handles specified
|
|
|
|
HandleCount - The number of Handles specified in Handle.
|
|
|
|
Packet - Valid only if UseDatabase is FALSE. Packet defines the pages being passed into
|
|
the browser. This is composed of IFR data as well as String information.
|
|
|
|
CallbackHandle - The handle which contains the calling driver's EFI_FORM_CALLBACK_PROTOCOL interface.
|
|
|
|
ScreenDimenions - This allows the browser to be called so that it occupies a portion of the physical screen instead of
|
|
dynamically determining the screen dimensions.
|
|
|
|
NvMapOverride - This 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 "fake" NV variable. If used, no saving
|
|
of an NV variable will be possible. This parameter is also ignored if HandleCount > 1.
|
|
|
|
Returns:
|
|
|
|
--*/
|
|
{
|
|
EFI_FORM_CALLBACK_PROTOCOL *FormCallback;
|
|
EFI_FILE_FORM_TAGS *FileFormTagsHead;
|
|
UI_MENU_OPTION *Selection;
|
|
UI_MENU_OPTION *AltSelection;
|
|
EFI_STATUS Status;
|
|
BOOLEAN Callback;
|
|
VOID *CallbackData;
|
|
EFI_HII_HANDLE BackupHandle;
|
|
|
|
ZeroMem (&gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));
|
|
|
|
gPreviousValue = AllocatePool (0x1000);
|
|
CallbackData = AllocatePool (0x10000);
|
|
ASSERT (gPreviousValue != NULL);
|
|
ASSERT (CallbackData != NULL);
|
|
|
|
do {
|
|
//
|
|
// Seed the dimensions in the global
|
|
//
|
|
gST->ConOut->QueryMode (
|
|
gST->ConOut,
|
|
gST->ConOut->Mode->Mode,
|
|
&gScreenDimensions.RightColumn,
|
|
&gScreenDimensions.BottomRow
|
|
);
|
|
|
|
if (ScreenDimensions != NULL) {
|
|
//
|
|
// Check local dimension vs. global dimension.
|
|
//
|
|
if ((gScreenDimensions.RightColumn < ScreenDimensions->RightColumn) ||
|
|
(gScreenDimensions.BottomRow < ScreenDimensions->BottomRow)
|
|
) {
|
|
return EFI_INVALID_PARAMETER;
|
|
} else {
|
|
//
|
|
// Local dimension validation.
|
|
//
|
|
if ((ScreenDimensions->RightColumn > ScreenDimensions->LeftColumn) &&
|
|
(ScreenDimensions->BottomRow > ScreenDimensions->TopRow) &&
|
|
((ScreenDimensions->RightColumn - ScreenDimensions->LeftColumn) > 2) &&
|
|
(
|
|
(ScreenDimensions->BottomRow - ScreenDimensions->TopRow) > STATUS_BAR_HEIGHT +
|
|
SCROLL_ARROW_HEIGHT *
|
|
2 +
|
|
FRONT_PAGE_HEADER_HEIGHT +
|
|
FOOTER_HEIGHT +
|
|
1
|
|
)
|
|
) {
|
|
CopyMem (&gScreenDimensions, ScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));
|
|
} else {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
}
|
|
|
|
gOptionBlockWidth = (CHAR16) ((gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn) / 3);
|
|
gHelpBlockWidth = gOptionBlockWidth;
|
|
gPromptBlockWidth = gOptionBlockWidth;
|
|
|
|
//
|
|
// Initialize the strings for the browser, upon exit of the browser, the strings will be freed
|
|
//
|
|
InitializeBrowserStrings ();
|
|
|
|
gFunctionKeySetting = DEFAULT_FUNCTION_KEY_SETTING;
|
|
gClassOfVfr = EFI_SETUP_APPLICATION_SUBCLASS;
|
|
gResetRequired = FALSE;
|
|
gExitRequired = FALSE;
|
|
gSaveRequired = FALSE;
|
|
gNvUpdateRequired = FALSE;
|
|
gActiveIfr = 0;
|
|
gConsistencyId = 0;
|
|
gPriorMenuEntry = 0;
|
|
BackupHandle = *Handle;
|
|
gMenuRefreshHead = NULL;
|
|
ASSERT (CallbackData);
|
|
ZeroMem (CallbackData, 0x10000);
|
|
|
|
//
|
|
// We can recurse through this and might need to re-allocate this particular buffer
|
|
//
|
|
if (gPreviousValue == NULL) {
|
|
gPreviousValue = AllocatePool (0x1000);
|
|
ASSERT (gPreviousValue != NULL);
|
|
}
|
|
|
|
Callback = FALSE;
|
|
FormCallback = NULL;
|
|
|
|
if (CallbackHandle != NULL) {
|
|
//
|
|
// Retrieve the Callback protocol interface
|
|
//
|
|
Status = gBS->HandleProtocol (
|
|
CallbackHandle,
|
|
&gEfiFormCallbackProtocolGuid,
|
|
(VOID **) &FormCallback
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
FreePool (CallbackData);
|
|
return Status;;
|
|
}
|
|
|
|
Callback = TRUE;
|
|
}
|
|
//
|
|
// Initializes all the internal state structures for all IFR images in system
|
|
//
|
|
Status = InitializeBinaryStructures (Handle, UseDatabase, Packet, NvMapOverride, HandleCount, &FileFormTagsHead);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
FreePool (CallbackData);
|
|
return Status;
|
|
}
|
|
//
|
|
// Beginning of the Presentation of the Data
|
|
//
|
|
if (UseDatabase && (HandleCount > 1)) {
|
|
Selection = DisplayHomePage (HandleCount, FileFormTagsHead, CallbackData);
|
|
} else {
|
|
//
|
|
// If passing something specific, we know there is only one Ifr
|
|
//
|
|
Selection = AllocateZeroPool (sizeof (UI_MENU_OPTION));
|
|
ASSERT (Selection != NULL);
|
|
Selection->IfrNumber = 0;
|
|
Selection->Handle = Handle[0];
|
|
UiInitMenu ();
|
|
}
|
|
|
|
UiInitMenuList ();
|
|
|
|
if (UseDatabase && (HandleCount > 1)) {
|
|
if (Selection == NULL) {
|
|
FreePool (CallbackData);
|
|
return EFI_SUCCESS;
|
|
}
|
|
}
|
|
//
|
|
// Launch the setup browser with the user's selection information
|
|
//
|
|
AltSelection = SetupBrowser (Selection, Callback, FileFormTagsHead, CallbackData);
|
|
|
|
//
|
|
// If the caller cares about Reset status, we can return to the caller if something happened that required a reset
|
|
//
|
|
if (ResetRequired != NULL) {
|
|
*ResetRequired = gResetRequired;
|
|
}
|
|
|
|
if (Callback && (AltSelection != NULL)) {
|
|
if ((FormCallback != NULL) && (FormCallback->Callback != NULL)) {
|
|
Status = FormCallback->Callback (
|
|
FormCallback,
|
|
AltSelection->ThisTag->Key,
|
|
CallbackData,
|
|
(EFI_HII_CALLBACK_PACKET **) &Packet
|
|
);
|
|
}
|
|
}
|
|
|
|
*Handle = BackupHandle;
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
FreePool (CallbackData);
|
|
return Status;
|
|
}
|
|
|
|
if (Callback && (AltSelection == NULL)) {
|
|
FreePool (CallbackData);
|
|
return Status;
|
|
}
|
|
|
|
if (UseDatabase && (HandleCount > 1)) {
|
|
} else {
|
|
|
|
if (gBinaryDataHead->UnRegisterOnExit) {
|
|
Hii->RemovePack (Hii, Handle[0]);
|
|
}
|
|
|
|
if (Callback &&
|
|
((AltSelection->ThisTag->SubClass == EFI_FRONT_PAGE_SUBCLASS) ||
|
|
(AltSelection->ThisTag->SubClass == EFI_SINGLE_USE_SUBCLASS))) {
|
|
//
|
|
// If this is the FrontPage, return after every selection
|
|
//
|
|
FreePool (Selection);
|
|
UiFreeMenu ();
|
|
|
|
//
|
|
// Clean up the allocated data buffers
|
|
//
|
|
FreeData (FileFormTagsHead, NULL, NULL);
|
|
|
|
gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
|
|
gST->ConOut->ClearScreen (gST->ConOut);
|
|
|
|
FreePool (CallbackData);
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
FreePool (Selection);
|
|
UiFreeMenu ();
|
|
|
|
//
|
|
// Clean up the allocated data buffers
|
|
//
|
|
FreeData (FileFormTagsHead, NULL, NULL);
|
|
|
|
gST->ConOut->ClearScreen (gST->ConOut);
|
|
|
|
if (!Callback) {
|
|
FreePool (CallbackData);
|
|
return EFI_SUCCESS;
|
|
}
|
|
}
|
|
|
|
} while (!EFI_ERROR (Status));
|
|
|
|
FreePool (CallbackData);
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
InitializeSetup (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Initialize Setup
|
|
|
|
Arguments:
|
|
(Standard EFI Image entry - EFI_IMAGE_ENTRY_POINT)
|
|
|
|
Returns:
|
|
EFI_SUCCESS - Setup loaded.
|
|
other - Setup Error
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_FORM_CONFIGURATION_DATA *FormData;
|
|
EFI_FORM_BROWSER_PROTOCOL *FormBrowser;
|
|
EFI_HANDLE Handle;
|
|
EFI_HII_PACKAGES *PackageList;
|
|
|
|
//
|
|
// There will be only one FormConfig in the system
|
|
// If there is another out there, someone is trying to install us
|
|
// again. Fail that scenario.
|
|
//
|
|
Status = gBS->LocateProtocol (
|
|
&gEfiFormBrowserProtocolGuid,
|
|
NULL,
|
|
(VOID **) &FormBrowser
|
|
);
|
|
|
|
gFirstIn = TRUE;
|
|
|
|
//
|
|
// If there was no error, assume there is an installation and fail to load
|
|
//
|
|
if (!EFI_ERROR (Status)) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
FormData = AllocatePool (sizeof (EFI_FORM_CONFIGURATION_DATA));
|
|
|
|
if (FormData == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
//
|
|
// Fill in HII data
|
|
//
|
|
FormData->Signature = EFI_FORM_DATA_SIGNATURE;
|
|
FormData->FormConfig.SendForm = SendForm;
|
|
FormData->FormConfig.CreatePopUp = CreateDialog;
|
|
|
|
//
|
|
// There should only be one HII image
|
|
//
|
|
Status = gBS->LocateProtocol (
|
|
&gEfiHiiProtocolGuid,
|
|
NULL,
|
|
(VOID **) &FormData->Hii
|
|
);
|
|
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
Hii = FormData->Hii;
|
|
|
|
PackageList = PreparePackages (1, &gEfiFormBrowserProtocolGuid, SetupBrowserStrings);
|
|
|
|
Status = Hii->NewPack (Hii, PackageList, &gHiiHandle);
|
|
|
|
FreePool (PackageList);
|
|
|
|
//
|
|
// Install protocol interface
|
|
//
|
|
Handle = NULL;
|
|
Status = gBS->InstallProtocolInterface (
|
|
&Handle,
|
|
&gEfiFormBrowserProtocolGuid,
|
|
EFI_NATIVE_INTERFACE,
|
|
&FormData->FormConfig
|
|
);
|
|
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
BannerData = AllocateZeroPool (sizeof (BANNER_DATA));
|
|
ASSERT (BannerData != NULL);
|
|
|
|
Status = InstallPrint ();
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
GetQuestionHeader (
|
|
IN EFI_TAG *Tag,
|
|
IN UINT8 *RawFormSet,
|
|
IN UINT16 Index,
|
|
IN EFI_FILE_FORM_TAGS *FileFormTags,
|
|
IN UINT16 CurrentVariable
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Initialize question tag's members.
|
|
|
|
Arguments:
|
|
Tag - Pointer of the current EFI_TAG structure.
|
|
RawFormSet - Pointer of the formset raw data.
|
|
Index - Offset of the current opcode in the Ifr raw data.
|
|
FileFormTags - Pointer of current EFI_FILE_FORM_TAGS structure.
|
|
CurrentVariable - Current variable number.
|
|
|
|
Returns:
|
|
None.
|
|
--*/
|
|
{
|
|
EFI_VARIABLE_DEFINITION *VariableDefinition;
|
|
|
|
Tag->NumberOfLines = 1;
|
|
Tag->VariableNumber = CurrentVariable;
|
|
CopyMem (&Tag->Id, &((EFI_IFR_ONE_OF *) &RawFormSet[Index])->QuestionId, sizeof (UINT16));
|
|
CopyMem (&Tag->StorageStart, &((EFI_IFR_ONE_OF *) &RawFormSet[Index])->QuestionId, sizeof (UINT16));
|
|
CopyMem (&Tag->StorageWidth, &((EFI_IFR_ONE_OF *) &RawFormSet[Index])->Width, sizeof (UINT8));
|
|
CopyMem (&Tag->Text, &((EFI_IFR_ONE_OF *) &RawFormSet[Index])->Prompt, sizeof (UINT16));
|
|
CopyMem (&Tag->Help, &((EFI_IFR_ONE_OF *) &RawFormSet[Index])->Help, sizeof (UINT16));
|
|
|
|
VariableDefinition = FileFormTags->VariableDefinitions;
|
|
|
|
for (; VariableDefinition != NULL; VariableDefinition = VariableDefinition->Next) {
|
|
//
|
|
// Have we found the correct variable for the request?
|
|
//
|
|
if (CurrentVariable == VariableDefinition->VariableId) {
|
|
if (VariableDefinition->VariableSize < (UINTN) (Tag->StorageStart + Tag->StorageWidth)) {
|
|
VariableDefinition->VariableFakeSize = (UINT16) (VariableDefinition->VariableFakeSize + Tag->StorageWidth);
|
|
}
|
|
|
|
if (VariableDefinition->NvRamMap != NULL) {
|
|
//
|
|
// If it is an 8bit or 16bit width, then move it to Tag->Value, otherwise
|
|
// we will never be looking for the data in Tag->Value (e.g. strings, password, etc)
|
|
//
|
|
if (Tag->StorageWidth == (UINT16) 1) {
|
|
CopyMem (&Tag->Value, &VariableDefinition->NvRamMap[Tag->StorageStart], sizeof (UINT16));
|
|
}
|
|
|
|
if (Tag->StorageWidth == (UINT16) 2) {
|
|
Index = (UINT16)
|
|
(
|
|
VariableDefinition->NvRamMap[Tag->StorageStart] +
|
|
(VariableDefinition->NvRamMap[Tag->StorageStart + 1] * 0x100)
|
|
);
|
|
CopyMem (&Tag->Value, &Index, sizeof (UINT16));
|
|
}
|
|
} else {
|
|
Index = 0;
|
|
CopyMem (&Tag->Value, &Index, sizeof (UINT16));
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID
|
|
GetNumericHeader (
|
|
IN EFI_TAG *Tag,
|
|
IN UINT8 *RawFormSet,
|
|
IN UINT16 Index,
|
|
IN UINT16 NumberOfLines,
|
|
IN EFI_FILE_FORM_TAGS *FileFormTags,
|
|
IN UINT16 CurrentVariable
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Initialize numeric tag's members.
|
|
|
|
Arguments:
|
|
Tag - Pointer of the current EFI_TAG structure.
|
|
RawFormSet - Pointer of the formset raw data.
|
|
Index - Offset of the current opcode in the Ifr raw data.
|
|
NumberOfLines - Number of lines this opcode occupied.
|
|
FileFormTags - Pointer of current EFI_FILE_FORM_TAGS structure.
|
|
CurrentVariable - Current variable number.
|
|
|
|
Returns:
|
|
None.
|
|
--*/
|
|
{
|
|
EFI_VARIABLE_DEFINITION *VariableDefinition;
|
|
|
|
Tag->NumberOfLines = NumberOfLines;
|
|
Tag->VariableNumber = CurrentVariable;
|
|
CopyMem (&Tag->Id, &((EFI_IFR_ONE_OF *) &RawFormSet[Index])->QuestionId, sizeof (UINT16));
|
|
CopyMem (&Tag->StorageStart, &((EFI_IFR_ONE_OF *) &RawFormSet[Index])->QuestionId, sizeof (UINT16));
|
|
CopyMem (&Tag->StorageWidth, &((EFI_IFR_ONE_OF *) &RawFormSet[Index])->Width, sizeof (UINT8));
|
|
CopyMem (&Tag->Text, &((EFI_IFR_ONE_OF *) &RawFormSet[Index])->Prompt, sizeof (UINT16));
|
|
CopyMem (&Tag->Help, &((EFI_IFR_ONE_OF *) &RawFormSet[Index])->Help, sizeof (UINT16));
|
|
CopyMem (&Tag->Minimum, &((EFI_IFR_NUMERIC *) &RawFormSet[Index])->Minimum, sizeof (UINT16));
|
|
CopyMem (&Tag->Maximum, &((EFI_IFR_NUMERIC *) &RawFormSet[Index])->Maximum, sizeof (UINT16));
|
|
CopyMem (&Tag->Step, &((EFI_IFR_NUMERIC *) &RawFormSet[Index])->Step, sizeof (UINT16));
|
|
CopyMem (&Tag->Default, &((EFI_IFR_NUMERIC *) &RawFormSet[Index])->Default, sizeof (UINT16));
|
|
Tag->ResetRequired = (BOOLEAN) (((EFI_IFR_NUMERIC *) &RawFormSet[Index])->Flags & EFI_IFR_FLAG_RESET_REQUIRED);
|
|
|
|
VariableDefinition = FileFormTags->VariableDefinitions;
|
|
|
|
for (; VariableDefinition != NULL; VariableDefinition = VariableDefinition->Next) {
|
|
//
|
|
// Have we found the correct variable for the request?
|
|
//
|
|
if (CurrentVariable == VariableDefinition->VariableId) {
|
|
if (VariableDefinition->VariableSize <= (UINTN) (Tag->StorageStart + Tag->StorageWidth)) {
|
|
if (Tag->StorageWidth == 0) {
|
|
VariableDefinition->VariableFakeSize = (UINT16) (VariableDefinition->VariableFakeSize + 2);
|
|
} else {
|
|
VariableDefinition->VariableFakeSize = (UINT16) (VariableDefinition->VariableFakeSize + Tag->StorageWidth);
|
|
}
|
|
}
|
|
|
|
if (VariableDefinition->NvRamMap != NULL) {
|
|
//
|
|
// If it is an 8bit or 16bit width, then move it to Tag->Value, otherwise
|
|
// we will never be looking for the data in Tag->Value (e.g. strings, password, etc)
|
|
//
|
|
if (Tag->StorageWidth == (UINT16) 1) {
|
|
CopyMem (&Tag->Value, &VariableDefinition->NvRamMap[Tag->StorageStart], sizeof (UINT16));
|
|
}
|
|
|
|
if (Tag->StorageWidth == (UINT16) 2) {
|
|
Index = (UINT16)
|
|
(
|
|
VariableDefinition->NvRamMap[Tag->StorageStart] +
|
|
(VariableDefinition->NvRamMap[Tag->StorageStart + 1] * 0x100)
|
|
);
|
|
CopyMem (&Tag->Value, &Index, sizeof (UINT16));
|
|
}
|
|
} else {
|
|
CopyMem (&Tag->Value, &Tag->Default, sizeof (UINT16));
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID
|
|
GetTagCount (
|
|
IN UINT8 *RawFormSet,
|
|
IN OUT UINT16 *NumberOfTags
|
|
)
|
|
{
|
|
UINT16 Index;
|
|
|
|
//
|
|
// Assume on entry we are pointing to an OpCode - reasonably this should
|
|
// be a FormOp since the purpose is to count the tags in a particular Form.
|
|
//
|
|
for (Index = 0; RawFormSet[Index] != EFI_IFR_END_FORM_OP;) {
|
|
//
|
|
// If we encounter the end of a form set, bail out
|
|
//
|
|
if (RawFormSet[Index] == EFI_IFR_END_FORM_SET_OP) {
|
|
break;
|
|
}
|
|
//
|
|
// We treat date/time internally as three op-codes
|
|
//
|
|
if (RawFormSet[Index] == EFI_IFR_DATE_OP || RawFormSet[Index] == EFI_IFR_TIME_OP) {
|
|
*NumberOfTags = (UINT16) (*NumberOfTags + 3);
|
|
} else {
|
|
//
|
|
// Assume that we could have no more tags than op-codes
|
|
//
|
|
(*NumberOfTags)++;
|
|
}
|
|
|
|
Index = (UINT16) (Index + RawFormSet[Index + 1]);
|
|
}
|
|
//
|
|
// Increase the tag count by one so it is inclusive of the end_form_op
|
|
//
|
|
(*NumberOfTags)++;
|
|
}
|
|
|
|
STATIC
|
|
VOID
|
|
AddNextInconsistentTag (
|
|
IN OUT EFI_INCONSISTENCY_DATA **InconsistentTagsPtr
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Initialize the next inconsistent tag data and add it to the inconsistent tag list.
|
|
|
|
Arguments:
|
|
InconsistentTagsPtr - Pointer of the inconsistent tag's pointer.
|
|
|
|
Returns:
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
EFI_INCONSISTENCY_DATA *PreviousInconsistentTags;
|
|
EFI_INCONSISTENCY_DATA *InconsistentTags;
|
|
|
|
InconsistentTags = *InconsistentTagsPtr;
|
|
//
|
|
// We just hit the end of an inconsistent expression. Let's allocate the ->Next structure
|
|
//
|
|
InconsistentTags->Next = AllocatePool (sizeof (EFI_INCONSISTENCY_DATA));
|
|
ASSERT (InconsistentTags->Next != NULL);
|
|
|
|
//
|
|
// Preserve current Tag entry
|
|
//
|
|
PreviousInconsistentTags = InconsistentTags;
|
|
|
|
InconsistentTags = InconsistentTags->Next;
|
|
|
|
//
|
|
// This will zero on the entry including the ->Next so I don't have to do it
|
|
//
|
|
ZeroMem (InconsistentTags, sizeof (EFI_INCONSISTENCY_DATA));
|
|
|
|
//
|
|
// Point our Previous field to the previous entry
|
|
//
|
|
InconsistentTags->Previous = PreviousInconsistentTags;
|
|
|
|
*InconsistentTagsPtr = InconsistentTags;
|
|
|
|
return ;
|
|
}
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
InitializeTagStructures (
|
|
IN EFI_IFR_BINARY *BinaryData,
|
|
OUT EFI_FILE_FORM_TAGS *FileFormTags
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT8 *RawFormSet;
|
|
UINT16 Index;
|
|
UINT16 QuestionIndex;
|
|
UINT16 NumberOfTags;
|
|
INT16 CurrTag;
|
|
UINT8 TagLength;
|
|
EFI_FORM_TAGS *FormTags;
|
|
EFI_FORM_TAGS *SavedFormTags;
|
|
EFI_INCONSISTENCY_DATA *InconsistentTags;
|
|
EFI_VARIABLE_DEFINITION *VariableDefinitions;
|
|
UINTN Count;
|
|
UINT16 Class;
|
|
UINT16 SubClass;
|
|
UINT16 TempValue;
|
|
UINT16 CurrentVariable;
|
|
UINT16 CurrentVariable2;
|
|
|
|
//
|
|
// Initialize some Index variable and Status
|
|
//
|
|
Count = 0;
|
|
Class = 0;
|
|
SubClass = 0;
|
|
CurrentVariable = 0;
|
|
CurrentVariable2 = 0;
|
|
QuestionIndex = 0;
|
|
NumberOfTags = 1;
|
|
Status = EFI_SUCCESS;
|
|
FormTags = &FileFormTags->FormTags;
|
|
FormTags->Next = NULL;
|
|
if (FileFormTags->InconsistentTags == NULL) {
|
|
InconsistentTags = NULL;
|
|
} else {
|
|
InconsistentTags = FileFormTags->InconsistentTags;
|
|
}
|
|
|
|
if (FileFormTags->VariableDefinitions == NULL) {
|
|
VariableDefinitions = NULL;
|
|
} else {
|
|
VariableDefinitions = FileFormTags->VariableDefinitions;
|
|
}
|
|
//
|
|
// RawFormSet now points to the beginning of the forms portion of
|
|
// the specific IFR Binary.
|
|
//
|
|
RawFormSet = (UINT8 *) BinaryData->FormBinary;
|
|
|
|
//
|
|
// Determine the number of tags for the first form
|
|
//
|
|
GetTagCount (&RawFormSet[0], &NumberOfTags);
|
|
|
|
SavedFormTags = FormTags;
|
|
|
|
if (FormTags->Tags != NULL) {
|
|
do {
|
|
//
|
|
// Advance FormTags to the last entry
|
|
//
|
|
for (; FormTags->Next != NULL; FormTags = FormTags->Next)
|
|
;
|
|
|
|
//
|
|
// Walk through each of the tags and free the IntList allocation
|
|
//
|
|
for (Index = 0; Index < NumberOfTags; Index++) {
|
|
if (FormTags->Tags[Index].IntList != NULL) {
|
|
FreePool (FormTags->Tags[Index].IntList);
|
|
}
|
|
}
|
|
|
|
FreePool (FormTags->Tags);
|
|
|
|
ASSERT (FormTags->Next == NULL);
|
|
|
|
FormTags->Tags = NULL;
|
|
|
|
FormTags = SavedFormTags;
|
|
|
|
} while (FormTags->Next != NULL);
|
|
}
|
|
|
|
Index = 0;
|
|
|
|
//
|
|
// Test for an allocated buffer. If already allocated this is due to having called this routine
|
|
// once for sizing of the NV storage. We then loaded the NV variable and can correctly initialize
|
|
// the tag structure with current values from the NV
|
|
//
|
|
if (FormTags->Tags == NULL) {
|
|
//
|
|
// Allocate memory for our tags on the first form
|
|
//
|
|
FormTags->Tags = AllocateZeroPool (NumberOfTags * sizeof (EFI_TAG));
|
|
ASSERT (FormTags->Tags);
|
|
}
|
|
//
|
|
// Test for an allocated buffer. If already allocated this is due to having called this routine
|
|
// once for sizing of the NV storage. We then loaded the NV variable and can correctly initialize
|
|
// the tag structure with current values from the NV
|
|
//
|
|
if (InconsistentTags == NULL) {
|
|
//
|
|
// We just hit the end of an inconsistent expression. Let's allocate the ->Next structure
|
|
//
|
|
InconsistentTags = AllocateZeroPool (sizeof (EFI_INCONSISTENCY_DATA));
|
|
ASSERT (InconsistentTags != NULL);
|
|
|
|
FileFormTags->InconsistentTags = InconsistentTags;
|
|
}
|
|
|
|
ZeroMem (FormTags->Tags, NumberOfTags * sizeof (EFI_TAG));
|
|
|
|
for (CurrTag = 0; RawFormSet[Index] != EFI_IFR_END_FORM_SET_OP; CurrTag++) {
|
|
//
|
|
// Operand = IFR OpCode
|
|
//
|
|
FormTags->Tags[CurrTag].Operand = RawFormSet[Index];
|
|
|
|
//
|
|
// Assume for now 0 lines occupied by this OpCode
|
|
//
|
|
FormTags->Tags[CurrTag].NumberOfLines = 0;
|
|
|
|
FormTags->Tags[CurrTag].Class = Class;
|
|
FormTags->Tags[CurrTag].SubClass = SubClass;
|
|
|
|
//
|
|
// Determine the length of the Tag so we can later skip to the next tag in the form
|
|
//
|
|
TagLength = RawFormSet[Index + 1];
|
|
//
|
|
// get the length
|
|
//
|
|
// Operate on the Found OpCode
|
|
//
|
|
switch (RawFormSet[Index]) {
|
|
|
|
case EFI_IFR_FORM_OP:
|
|
//
|
|
// If there was no variable op-code defined, create a dummy entry for one
|
|
//
|
|
if (FileFormTags->VariableDefinitions == NULL) {
|
|
FileFormTags->VariableDefinitions = AllocateZeroPool (sizeof (EFI_VARIABLE_DEFINITION));
|
|
ASSERT (FileFormTags->VariableDefinitions != NULL);
|
|
IfrToFormTag (
|
|
RawFormSet[Index],
|
|
&FormTags->Tags[CurrTag],
|
|
(VOID *) &RawFormSet[Index],
|
|
FileFormTags->VariableDefinitions
|
|
);
|
|
} else {
|
|
IfrToFormTag (RawFormSet[Index], &FormTags->Tags[CurrTag], (VOID *) &RawFormSet[Index], NULL);
|
|
}
|
|
break;
|
|
|
|
case EFI_IFR_SUBTITLE_OP:
|
|
case EFI_IFR_TEXT_OP:
|
|
case EFI_IFR_REF_OP:
|
|
IfrToFormTag (RawFormSet[Index], &FormTags->Tags[CurrTag], (VOID *) &RawFormSet[Index], NULL);
|
|
break;
|
|
|
|
case EFI_IFR_VARSTORE_OP:
|
|
if (FileFormTags->VariableDefinitions == NULL) {
|
|
VariableDefinitions = AllocateZeroPool (sizeof (EFI_VARIABLE_DEFINITION));
|
|
ASSERT (VariableDefinitions != NULL);
|
|
FileFormTags->VariableDefinitions = VariableDefinitions;
|
|
}
|
|
|
|
IfrToFormTag (
|
|
RawFormSet[Index],
|
|
&FormTags->Tags[CurrTag],
|
|
(VOID *) &RawFormSet[Index],
|
|
FileFormTags->VariableDefinitions
|
|
);
|
|
break;
|
|
|
|
case EFI_IFR_VARSTORE_SELECT_OP:
|
|
IfrToFormTag (RawFormSet[Index], &FormTags->Tags[CurrTag], (VOID *) &RawFormSet[Index], NULL);
|
|
CopyMem (&CurrentVariable, &((EFI_IFR_VARSTORE_SELECT *) &RawFormSet[Index])->VarId, sizeof (UINT16));
|
|
CurrentVariable2 = CurrentVariable;
|
|
break;
|
|
|
|
case EFI_IFR_VARSTORE_SELECT_PAIR_OP:
|
|
IfrToFormTag (RawFormSet[Index], &FormTags->Tags[CurrTag], (VOID *) &RawFormSet[Index], NULL);
|
|
CopyMem(&CurrentVariable, &((EFI_IFR_VARSTORE_SELECT_PAIR *)&RawFormSet[Index])->VarId, sizeof (UINT16));
|
|
CopyMem (
|
|
&CurrentVariable2,
|
|
&((EFI_IFR_VARSTORE_SELECT_PAIR *) &RawFormSet[Index])->SecondaryVarId,
|
|
sizeof (UINT16)
|
|
);
|
|
break;
|
|
|
|
case EFI_IFR_END_FORM_OP:
|
|
//
|
|
// Test for an allocated buffer. If already allocated this is due to having called this routine
|
|
// once for sizing of the NV storage. We then loaded the NV variable and can correctly initialize
|
|
// the tag structure with current values from the NV
|
|
//
|
|
if (FormTags->Next == NULL) {
|
|
//
|
|
// We just hit the end of a form. Let's allocate the ->Next structure
|
|
//
|
|
FormTags->Next = AllocatePool (sizeof (EFI_FORM_TAGS));
|
|
ASSERT (FormTags->Next);
|
|
}
|
|
|
|
FormTags = FormTags->Next;
|
|
ZeroMem (FormTags, sizeof (EFI_FORM_TAGS));
|
|
|
|
//
|
|
// Reset the tag count to one
|
|
//
|
|
NumberOfTags = 1;
|
|
|
|
//
|
|
// Reset the CurrTag value (it will be incremented, after this case statement
|
|
// so set to a negative one so that we get the desired effect.) Fish can beat me later.
|
|
//
|
|
CurrTag = -1;
|
|
|
|
//
|
|
// Determine the number of tags after this form. If this is the last
|
|
// form, then we will count the endformset and preserve that information
|
|
// in the tag structure.
|
|
//
|
|
GetTagCount (&RawFormSet[Index + TagLength], &NumberOfTags);
|
|
|
|
//
|
|
// Allocate memory for our tags
|
|
//
|
|
FormTags->Tags = AllocateZeroPool (NumberOfTags * sizeof (EFI_TAG));
|
|
ASSERT (FormTags->Tags);
|
|
break;
|
|
|
|
//
|
|
// Two types of tags constitute the One Of question: a one-of header and
|
|
// several one-of options.
|
|
//
|
|
case EFI_IFR_ONE_OF_OP:
|
|
case EFI_IFR_ORDERED_LIST_OP:
|
|
GetQuestionHeader (&FormTags->Tags[CurrTag], RawFormSet, Index, FileFormTags, CurrentVariable);
|
|
|
|
//
|
|
// Store away the CurrTag since what follows will be the answer that we
|
|
// need to place into the appropriate location in the tag array
|
|
//
|
|
//
|
|
// record for setting default later
|
|
//
|
|
QuestionIndex = (UINT16) CurrTag;
|
|
break;
|
|
|
|
case EFI_IFR_ONE_OF_OPTION_OP:
|
|
IfrToFormTag (RawFormSet[Index], &FormTags->Tags[CurrTag], (VOID *) &RawFormSet[Index], NULL);
|
|
FormTags->Tags[QuestionIndex].Flags = ((EFI_IFR_ONE_OF_OPTION *) &RawFormSet[Index])->Flags;
|
|
CopyMem (
|
|
&FormTags->Tags[QuestionIndex].Key,
|
|
&((EFI_IFR_ONE_OF_OPTION *) &RawFormSet[Index])->Key,
|
|
sizeof (UINT16)
|
|
);
|
|
FormTags->Tags[QuestionIndex].ResetRequired = (BOOLEAN) (FormTags->Tags[QuestionIndex].Flags & EFI_IFR_FLAG_RESET_REQUIRED);
|
|
break;
|
|
|
|
case EFI_IFR_CHECKBOX_OP:
|
|
GetQuestionHeader (&FormTags->Tags[CurrTag], RawFormSet, Index, FileFormTags, CurrentVariable);
|
|
IfrToFormTag (RawFormSet[Index], &FormTags->Tags[CurrTag], (VOID *) &RawFormSet[Index], NULL);
|
|
break;
|
|
|
|
case EFI_IFR_NUMERIC_OP:
|
|
GetNumericHeader (&FormTags->Tags[CurrTag], RawFormSet, Index, (UINT16) 1, FileFormTags, CurrentVariable);
|
|
IfrToFormTag (RawFormSet[Index], &FormTags->Tags[CurrTag], (VOID *) &RawFormSet[Index], NULL);
|
|
break;
|
|
|
|
case EFI_IFR_DATE_OP:
|
|
//
|
|
// Date elements come in as a Year, Month, Day. We need to process them as a country-based
|
|
// Order. It is much easier to do it here than anywhere else.
|
|
//
|
|
// For US standards - we want Month/Day/Year, thus we advance "Index" +1, +2, +0 while CurrTag is +0, +1, +2
|
|
//
|
|
GetNumericHeader (
|
|
&FormTags->Tags[CurrTag],
|
|
RawFormSet,
|
|
(UINT16) (Index + TagLength),
|
|
(UINT16) 0,
|
|
FileFormTags,
|
|
CurrentVariable
|
|
);
|
|
|
|
//
|
|
// The current language selected + the Date operand
|
|
//
|
|
FormTags->Tags[CurrTag + 1].Operand = RawFormSet[Index];
|
|
GetNumericHeader (
|
|
&FormTags->Tags[CurrTag + 1],
|
|
RawFormSet,
|
|
(UINT16) (Index + TagLength + RawFormSet[Index + TagLength + 1]),
|
|
(UINT16) 0,
|
|
FileFormTags,
|
|
CurrentVariable
|
|
);
|
|
|
|
//
|
|
// The current language selected + the Date operand
|
|
//
|
|
FormTags->Tags[CurrTag + 2].Operand = RawFormSet[Index];
|
|
GetNumericHeader (&FormTags->Tags[CurrTag + 2], RawFormSet, Index, (UINT16) 1, FileFormTags, CurrentVariable);
|
|
|
|
CurrTag = (INT16) (CurrTag + 2);
|
|
|
|
Index = (UINT16) (Index + TagLength);
|
|
//
|
|
// get the length
|
|
//
|
|
TagLength = RawFormSet[Index + 1];
|
|
Index = (UINT16) (Index + TagLength);
|
|
//
|
|
// get the length
|
|
//
|
|
TagLength = RawFormSet[Index + 1];
|
|
break;
|
|
|
|
case EFI_IFR_TIME_OP:
|
|
GetNumericHeader (&FormTags->Tags[CurrTag], RawFormSet, Index, (UINT16) 0, FileFormTags, CurrentVariable);
|
|
|
|
if (Count == 2) {
|
|
//
|
|
// Override the GetQuestionHeader information - date/time are treated very differently
|
|
//
|
|
FormTags->Tags[CurrTag].NumberOfLines = 1;
|
|
Count = 0;
|
|
} else {
|
|
//
|
|
// The premise is that every date/time op-code have 3 elements, the first 2 have 0 lines
|
|
// associated with them, and the third has 1 line to allow to space beyond the choice.
|
|
//
|
|
Count++;
|
|
}
|
|
break;
|
|
|
|
case EFI_IFR_PASSWORD_OP:
|
|
case EFI_IFR_STRING_OP:
|
|
GetQuestionHeader (&FormTags->Tags[CurrTag], RawFormSet, Index, FileFormTags, CurrentVariable);
|
|
IfrToFormTag (RawFormSet[Index], &FormTags->Tags[CurrTag], (VOID *) &RawFormSet[Index], NULL);
|
|
break;
|
|
|
|
case EFI_IFR_SUPPRESS_IF_OP:
|
|
case EFI_IFR_GRAYOUT_IF_OP:
|
|
InconsistentTags->Operand = ((EFI_IFR_INCONSISTENT *) &RawFormSet[Index])->Header.OpCode;
|
|
gConsistencyId++;
|
|
|
|
//
|
|
// Since this op-code doesn't use the next field(s), initialize them with something invalid.
|
|
// Unfortunately 0 is a valid offset value for a QuestionId
|
|
//
|
|
InconsistentTags->QuestionId1 = INVALID_OFFSET_VALUE;
|
|
InconsistentTags->QuestionId2 = INVALID_OFFSET_VALUE;
|
|
|
|
//
|
|
// Test for an allocated buffer. If already allocated this is due to having called this routine
|
|
// once for sizing of the NV storage. We then loaded the NV variable and can correctly initialize
|
|
// the tag structure with current values from the NV
|
|
//
|
|
if (InconsistentTags->Next == NULL) {
|
|
AddNextInconsistentTag (&InconsistentTags);
|
|
break;
|
|
}
|
|
|
|
InconsistentTags = InconsistentTags->Next;
|
|
break;
|
|
|
|
case EFI_IFR_FORM_SET_OP:
|
|
CopyMem (
|
|
&FormTags->Tags[CurrTag].GuidValue,
|
|
&((EFI_IFR_FORM_SET *) &RawFormSet[Index])->Guid,
|
|
sizeof (EFI_GUID)
|
|
);
|
|
CopyMem (
|
|
&FormTags->Tags[CurrTag].CallbackHandle,
|
|
&((EFI_IFR_FORM_SET *) &RawFormSet[Index])->CallbackHandle,
|
|
sizeof (EFI_PHYSICAL_ADDRESS)
|
|
);
|
|
CopyMem (&FormTags->Tags[CurrTag].Class, &((EFI_IFR_FORM_SET *) &RawFormSet[Index])->Class, sizeof (UINT8));
|
|
CopyMem (
|
|
&FormTags->Tags[CurrTag].SubClass,
|
|
&((EFI_IFR_FORM_SET *) &RawFormSet[Index])->SubClass,
|
|
sizeof (UINT8)
|
|
);
|
|
CopyMem (
|
|
&FormTags->Tags[CurrTag].NvDataSize,
|
|
&((EFI_IFR_FORM_SET *) &RawFormSet[Index])->NvDataSize,
|
|
sizeof (UINT16)
|
|
);
|
|
Class = ((EFI_IFR_FORM_SET *) &RawFormSet[Index])->Class;
|
|
SubClass = ((EFI_IFR_FORM_SET *) &RawFormSet[Index])->SubClass;
|
|
//
|
|
// If the formset has a size value, that means someone must be using this, so create a variable
|
|
// We also shall reserve the formid of 0 for this specific purpose.
|
|
//
|
|
if ((FileFormTags->VariableDefinitions == NULL) && (FormTags->Tags[CurrTag].NvDataSize > 0)) {
|
|
FileFormTags->VariableDefinitions = AllocateZeroPool (sizeof (EFI_VARIABLE_DEFINITION));
|
|
ASSERT (FileFormTags->VariableDefinitions != NULL);
|
|
IfrToFormTag (
|
|
RawFormSet[Index],
|
|
&FormTags->Tags[CurrTag],
|
|
(VOID *) &RawFormSet[Index],
|
|
FileFormTags->VariableDefinitions
|
|
);
|
|
} else {
|
|
IfrToFormTag (RawFormSet[Index], &FormTags->Tags[CurrTag], (VOID *) &RawFormSet[Index], NULL);
|
|
}
|
|
break;
|
|
|
|
case EFI_IFR_BANNER_OP:
|
|
if (gClassOfVfr == EFI_FRONT_PAGE_SUBCLASS) {
|
|
TempValue = 0;
|
|
CopyMem (&TempValue, &((EFI_IFR_BANNER *) &RawFormSet[Index])->Alignment, sizeof (UINT8));
|
|
//
|
|
// If this is the special timeout value, we will dynamically figure out where to put it
|
|
// Also the least significant byte refers to the TimeOut desired.
|
|
//
|
|
if (TempValue == EFI_IFR_BANNER_TIMEOUT) {
|
|
CopyMem (&FrontPageTimeOutTitle, &((EFI_IFR_BANNER *) &RawFormSet[Index])->Title, sizeof (UINT16));
|
|
if (FrontPageTimeOutValue != (INT16) -1) {
|
|
CopyMem (&FrontPageTimeOutValue, &((EFI_IFR_BANNER *) &RawFormSet[Index])->LineNumber, sizeof (UINT16));
|
|
}
|
|
break;
|
|
}
|
|
|
|
CopyMem (
|
|
&BannerData->Banner[((EFI_IFR_BANNER *) &RawFormSet[Index])->LineNumber][
|
|
((EFI_IFR_BANNER *) &RawFormSet[Index])->Alignment],
|
|
&((EFI_IFR_BANNER *) &RawFormSet[Index])->Title,
|
|
sizeof (STRING_REF)
|
|
);
|
|
}
|
|
break;
|
|
|
|
case EFI_IFR_INCONSISTENT_IF_OP:
|
|
CopyMem (
|
|
&FormTags->Tags[CurrTag].Text,
|
|
&((EFI_IFR_INCONSISTENT *) &RawFormSet[Index])->Popup,
|
|
sizeof (UINT16)
|
|
);
|
|
gConsistencyId++;
|
|
|
|
InconsistentTags->Operand = ((EFI_IFR_INCONSISTENT *) &RawFormSet[Index])->Header.OpCode;
|
|
CopyMem (&InconsistentTags->Popup, &((EFI_IFR_INCONSISTENT *) &RawFormSet[Index])->Popup, sizeof (UINT16));
|
|
|
|
//
|
|
// Since this op-code doesn't use the next field(s), initialize them with something invalid.
|
|
// Unfortunately 0 is a valid offset value for a QuestionId
|
|
//
|
|
InconsistentTags->QuestionId1 = INVALID_OFFSET_VALUE;
|
|
InconsistentTags->QuestionId2 = INVALID_OFFSET_VALUE;
|
|
|
|
InconsistentTags->VariableNumber = CurrentVariable;
|
|
|
|
//
|
|
// Test for an allocated buffer. If already allocated this is due to having called this routine
|
|
// once for sizing of the NV storage. We then loaded the NV variable and can correctly initialize
|
|
// the tag structure with current values from the NV
|
|
//
|
|
if (InconsistentTags->Next == NULL) {
|
|
AddNextInconsistentTag (&InconsistentTags);
|
|
break;
|
|
}
|
|
|
|
InconsistentTags = InconsistentTags->Next;
|
|
break;
|
|
|
|
case EFI_IFR_EQ_ID_VAL_OP:
|
|
IfrToFormTag (RawFormSet[Index], &FormTags->Tags[CurrTag], (VOID *) &RawFormSet[Index], NULL);
|
|
|
|
InconsistentTags->Operand = ((EFI_IFR_EQ_ID_VAL *) &RawFormSet[Index])->Header.OpCode;
|
|
CopyMem (&InconsistentTags->Value, &((EFI_IFR_EQ_ID_VAL *) &RawFormSet[Index])->Value, sizeof (UINT16));
|
|
CopyMem (
|
|
&InconsistentTags->QuestionId1,
|
|
&((EFI_IFR_EQ_ID_VAL *) &RawFormSet[Index])->QuestionId,
|
|
sizeof (UINT16)
|
|
);
|
|
|
|
//
|
|
// Since this op-code doesn't use the next field(s), initialize them with something invalid.
|
|
// Unfortunately 0 is a valid offset value for a QuestionId
|
|
//
|
|
InconsistentTags->Width = FormTags->Tags[CurrTag].StorageWidth;
|
|
InconsistentTags->QuestionId2 = INVALID_OFFSET_VALUE;
|
|
InconsistentTags->ConsistencyId = gConsistencyId;
|
|
FormTags->Tags[CurrTag].ConsistencyId = gConsistencyId;
|
|
|
|
InconsistentTags->VariableNumber = CurrentVariable;
|
|
|
|
//
|
|
// Test for an allocated buffer. If already allocated this is due to having called this routine
|
|
// once for sizing of the NV storage. We then loaded the NV variable and can correctly initialize
|
|
// the tag structure with current values from the NV
|
|
//
|
|
if (InconsistentTags->Next == NULL) {
|
|
AddNextInconsistentTag (&InconsistentTags);
|
|
break;
|
|
}
|
|
|
|
InconsistentTags = InconsistentTags->Next;
|
|
break;
|
|
|
|
case EFI_IFR_EQ_VAR_VAL_OP:
|
|
IfrToFormTag (RawFormSet[Index], &FormTags->Tags[CurrTag], (VOID *) &RawFormSet[Index], NULL);
|
|
|
|
InconsistentTags->Operand = ((EFI_IFR_EQ_VAR_VAL *) &RawFormSet[Index])->Header.OpCode;
|
|
CopyMem (&InconsistentTags->Value, &((EFI_IFR_EQ_VAR_VAL *) &RawFormSet[Index])->Value, sizeof (UINT16));
|
|
CopyMem (
|
|
&InconsistentTags->QuestionId1,
|
|
&((EFI_IFR_EQ_VAR_VAL *) &RawFormSet[Index])->VariableId,
|
|
sizeof (UINT16)
|
|
);
|
|
|
|
//
|
|
// Since this op-code doesn't use the next field(s), initialize them with something invalid.
|
|
// Unfortunately 0 is a valid offset value for a QuestionId
|
|
//
|
|
InconsistentTags->QuestionId2 = INVALID_OFFSET_VALUE;
|
|
InconsistentTags->ConsistencyId = gConsistencyId;
|
|
FormTags->Tags[CurrTag].ConsistencyId = gConsistencyId;
|
|
|
|
InconsistentTags->VariableNumber = CurrentVariable;
|
|
|
|
//
|
|
// Test for an allocated buffer. If already allocated this is due to having called this routine
|
|
// once for sizing of the NV storage. We then loaded the NV variable and can correctly initialize
|
|
// the tag structure with current values from the NV
|
|
//
|
|
if (InconsistentTags->Next == NULL) {
|
|
AddNextInconsistentTag (&InconsistentTags);
|
|
break;
|
|
}
|
|
|
|
InconsistentTags = InconsistentTags->Next;
|
|
break;
|
|
|
|
case EFI_IFR_EQ_ID_ID_OP:
|
|
IfrToFormTag (RawFormSet[Index], &FormTags->Tags[CurrTag], (VOID *) &RawFormSet[Index], NULL);
|
|
|
|
InconsistentTags->Operand = ((EFI_IFR_EQ_ID_ID *) &RawFormSet[Index])->Header.OpCode;
|
|
CopyMem (
|
|
&InconsistentTags->QuestionId1,
|
|
&((EFI_IFR_EQ_ID_ID *) &RawFormSet[Index])->QuestionId1,
|
|
sizeof (UINT16)
|
|
);
|
|
CopyMem (
|
|
&InconsistentTags->QuestionId2,
|
|
&((EFI_IFR_EQ_ID_ID *) &RawFormSet[Index])->QuestionId2,
|
|
sizeof (UINT16)
|
|
);
|
|
|
|
InconsistentTags->Width = FormTags->Tags[CurrTag].StorageWidth;
|
|
InconsistentTags->ConsistencyId = gConsistencyId;
|
|
FormTags->Tags[CurrTag].ConsistencyId = gConsistencyId;
|
|
|
|
InconsistentTags->VariableNumber = CurrentVariable;
|
|
InconsistentTags->VariableNumber2 = CurrentVariable2;
|
|
|
|
//
|
|
// Test for an allocated buffer. If already allocated this is due to having called this routine
|
|
// once for sizing of the NV storage. We then loaded the NV variable and can correctly initialize
|
|
// the tag structure with current values from the NV
|
|
//
|
|
if (InconsistentTags->Next == NULL) {
|
|
AddNextInconsistentTag (&InconsistentTags);
|
|
break;
|
|
}
|
|
|
|
InconsistentTags = InconsistentTags->Next;
|
|
break;
|
|
|
|
case EFI_IFR_AND_OP:
|
|
case EFI_IFR_OR_OP:
|
|
case EFI_IFR_NOT_OP:
|
|
case EFI_IFR_GT_OP:
|
|
case EFI_IFR_GE_OP:
|
|
case EFI_IFR_TRUE_OP:
|
|
case EFI_IFR_FALSE_OP:
|
|
InconsistentTags->Operand = ((EFI_IFR_NOT *) &RawFormSet[Index])->Header.OpCode;
|
|
|
|
//
|
|
// Since this op-code doesn't use the next field(s), initialize them with something invalid.
|
|
// Unfortunately 0 is a valid offset value for a QuestionId
|
|
//
|
|
|
|
//
|
|
// Reserve INVALID_OFFSET_VALUE - 1 for TRUE or FALSE because they are inconsistency tags also, but
|
|
// have no coresponding id. The examination of id is needed by evaluating boolean expression.
|
|
//
|
|
if (RawFormSet[Index] == EFI_IFR_TRUE_OP ||
|
|
RawFormSet[Index] == EFI_IFR_FALSE_OP) {
|
|
InconsistentTags->QuestionId1 = INVALID_OFFSET_VALUE - 1;
|
|
} else {
|
|
InconsistentTags->QuestionId1 = INVALID_OFFSET_VALUE;
|
|
}
|
|
InconsistentTags->QuestionId2 = INVALID_OFFSET_VALUE;
|
|
InconsistentTags->ConsistencyId = gConsistencyId;
|
|
FormTags->Tags[CurrTag].ConsistencyId = gConsistencyId;
|
|
|
|
//
|
|
// Test for an allocated buffer. If already allocated this is due to having called this routine
|
|
// once for sizing of the NV storage. We then loaded the NV variable and can correctly initialize
|
|
// the tag structure with current values from the NV
|
|
//
|
|
if (InconsistentTags->Next == NULL) {
|
|
AddNextInconsistentTag (&InconsistentTags);
|
|
break;
|
|
}
|
|
|
|
InconsistentTags = InconsistentTags->Next;
|
|
break;
|
|
|
|
case EFI_IFR_EQ_ID_LIST_OP:
|
|
IfrToFormTag (RawFormSet[Index], &FormTags->Tags[CurrTag], (VOID *) &RawFormSet[Index], NULL);
|
|
|
|
InconsistentTags->Operand = ((EFI_IFR_EQ_ID_LIST *) &RawFormSet[Index])->Header.OpCode;
|
|
CopyMem (
|
|
&InconsistentTags->QuestionId1,
|
|
&((EFI_IFR_EQ_ID_LIST *) &RawFormSet[Index])->QuestionId,
|
|
sizeof (UINT16)
|
|
);
|
|
CopyMem (
|
|
&InconsistentTags->ListLength,
|
|
&((EFI_IFR_EQ_ID_LIST *) &RawFormSet[Index])->ListLength,
|
|
sizeof (UINT16)
|
|
);
|
|
InconsistentTags->ValueList = FormTags->Tags[CurrTag].IntList;
|
|
|
|
//
|
|
// Since this op-code doesn't use the next field(s), initialize them with something invalid.
|
|
// Unfortunately 0 is a valid offset value for a QuestionId
|
|
//
|
|
InconsistentTags->Width = FormTags->Tags[CurrTag].StorageWidth;
|
|
InconsistentTags->QuestionId2 = INVALID_OFFSET_VALUE;
|
|
InconsistentTags->ConsistencyId = gConsistencyId;
|
|
FormTags->Tags[CurrTag].ConsistencyId = gConsistencyId;
|
|
|
|
//
|
|
// Test for an allocated buffer. If already allocated this is due to having called this routine
|
|
// once for sizing of the NV storage. We then loaded the NV variable and can correctly initialize
|
|
// the tag structure with current values from the NV
|
|
//
|
|
if (InconsistentTags->Next == NULL) {
|
|
AddNextInconsistentTag (&InconsistentTags);
|
|
break;
|
|
}
|
|
|
|
InconsistentTags = InconsistentTags->Next;
|
|
break;
|
|
|
|
case EFI_IFR_END_IF_OP:
|
|
InconsistentTags->Operand = ((EFI_IFR_END_EXPR *) &RawFormSet[Index])->Header.OpCode;
|
|
|
|
//
|
|
// Since this op-code doesn't use the next field(s), initialize them with something invalid.
|
|
// Unfortunately 0 is a valid offset value for a QuestionId
|
|
//
|
|
InconsistentTags->QuestionId1 = INVALID_OFFSET_VALUE;
|
|
InconsistentTags->QuestionId2 = INVALID_OFFSET_VALUE;
|
|
|
|
//
|
|
// Test for an allocated buffer. If already allocated this is due to having called this routine
|
|
// once for sizing of the NV storage. We then loaded the NV variable and can correctly initialize
|
|
// the tag structure with current values from the NV
|
|
//
|
|
if (InconsistentTags->Next == NULL) {
|
|
AddNextInconsistentTag (&InconsistentTags);
|
|
break;
|
|
}
|
|
|
|
InconsistentTags = InconsistentTags->Next;
|
|
break;
|
|
|
|
case EFI_IFR_END_ONE_OF_OP:
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
//
|
|
// End of switch
|
|
//
|
|
// Per spec., we ignore ops that we don't know how to deal with. Skip to next tag
|
|
//
|
|
Index = (UINT16) (Index + TagLength);
|
|
}
|
|
//
|
|
// End of Index
|
|
//
|
|
// When we eventually exit, make sure we mark the last tag with an op-code
|
|
//
|
|
FormTags->Tags[CurrTag].Operand = RawFormSet[Index];
|
|
|
|
IfrToFormTag (RawFormSet[Index], &FormTags->Tags[CurrTag], (VOID *) &RawFormSet[Index], NULL);
|
|
|
|
//
|
|
// Place this as an end of the database marker
|
|
//
|
|
InconsistentTags->Operand = 0xFF;
|
|
|
|
//
|
|
// This is the Head of the linked list of pages. Each page is an array of tags
|
|
//
|
|
FormTags = &FileFormTags->FormTags;
|
|
InconsistentTags = FileFormTags->InconsistentTags;
|
|
|
|
for (; InconsistentTags->Operand != 0xFF;) {
|
|
if (InconsistentTags->QuestionId1 != INVALID_OFFSET_VALUE) {
|
|
//
|
|
// Search the tags for the tag which corresponds to this ID
|
|
//
|
|
for (CurrTag = 0; FormTags->Tags[0].Operand != EFI_IFR_END_FORM_SET_OP; CurrTag++) {
|
|
//
|
|
// If we hit the end of a form, go to the next set of Tags.
|
|
// Remember - EndFormSet op-codes sit on their own page after an end form.
|
|
//
|
|
if (FormTags->Tags[CurrTag].Operand == EFI_IFR_END_FORM_OP) {
|
|
//
|
|
// Reset the CurrTag value (it will be incremented, after this case statement
|
|
// so set to a negative one so that we get the desired effect.) Fish can beat me later.
|
|
//
|
|
CurrTag = -1;
|
|
FormTags = FormTags->Next;
|
|
continue;
|
|
}
|
|
|
|
if (FormTags->Tags[CurrTag].Id == InconsistentTags->QuestionId1) {
|
|
FormTags->Tags[CurrTag].Consistency++;
|
|
}
|
|
}
|
|
}
|
|
|
|
FormTags = &FileFormTags->FormTags;
|
|
|
|
if (InconsistentTags->QuestionId2 != INVALID_OFFSET_VALUE) {
|
|
//
|
|
// Search the tags for the tag which corresponds to this ID
|
|
//
|
|
for (CurrTag = 0; FormTags->Tags[CurrTag].Operand != EFI_IFR_END_FORM_SET_OP; CurrTag++) {
|
|
//
|
|
// If we hit the end of a form, go to the next set of Tags.
|
|
// Remember - EndFormSet op-codes sit on their own page after an end form.
|
|
//
|
|
if (FormTags->Tags[CurrTag].Operand == EFI_IFR_END_FORM_OP) {
|
|
//
|
|
// Reset the CurrTag value (it will be incremented, after this case statement
|
|
// so set to a negative one so that we get the desired effect.) Fish can beat me later.
|
|
//
|
|
CurrTag = -1;
|
|
FormTags = FormTags->Next;
|
|
continue;
|
|
}
|
|
|
|
if (FormTags->Tags[CurrTag].Id == InconsistentTags->QuestionId2) {
|
|
FormTags->Tags[CurrTag].Consistency++;
|
|
}
|
|
}
|
|
}
|
|
|
|
InconsistentTags = InconsistentTags->Next;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
InitPage (
|
|
VOID
|
|
)
|
|
{
|
|
CHAR16 *HomePageString;
|
|
CHAR16 *HomeEscapeString;
|
|
|
|
//
|
|
// Displays the Header and Footer borders
|
|
//
|
|
DisplayPageFrame ();
|
|
|
|
HomePageString = GetToken (STRING_TOKEN (HOME_PAGE_TITLE), gHiiHandle);
|
|
HomeEscapeString = GetToken (STRING_TOKEN (HOME_ESCAPE_STRING), gHiiHandle);
|
|
|
|
gST->ConOut->SetAttribute (gST->ConOut, EFI_YELLOW | EFI_BRIGHT);
|
|
//
|
|
// PrintStringAt ((gScreenDimensions.RightColumn - GetStringWidth(HomePageString)/2)/2, 1, HomePageString);
|
|
//
|
|
PrintStringAt (
|
|
(gScreenDimensions.RightColumn + gScreenDimensions.LeftColumn - GetStringWidth (HomePageString) / 2) / 2,
|
|
1,
|
|
HomePageString
|
|
);
|
|
PrintAt (
|
|
gScreenDimensions.LeftColumn + 2,
|
|
gScreenDimensions.BottomRow - 3,
|
|
(CHAR16 *) L"%c%c%s",
|
|
ARROW_UP,
|
|
ARROW_DOWN,
|
|
gMoveHighlight
|
|
);
|
|
PrintAt (
|
|
gScreenDimensions.RightColumn - (GetStringWidth (HomeEscapeString) / 2) - 2,
|
|
gScreenDimensions.BottomRow - 3,
|
|
(CHAR16 *) L" %s",
|
|
HomeEscapeString
|
|
);
|
|
gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
|
|
FreePool (HomeEscapeString);
|
|
FreePool (HomePageString);
|
|
|
|
return ;
|
|
}
|
|
|
|
CHAR16 *
|
|
GetToken (
|
|
IN STRING_REF Token,
|
|
IN EFI_HII_HANDLE HiiHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get the string based on the TokenID and HII Handle.
|
|
|
|
Arguments:
|
|
|
|
Token - The Token ID.
|
|
HiiHandle - Handle of Ifr to be fetched.
|
|
|
|
Returns:
|
|
|
|
The output string.
|
|
|
|
--*/
|
|
{
|
|
CHAR16 *Buffer;
|
|
UINTN BufferLength;
|
|
EFI_STATUS Status;
|
|
|
|
//
|
|
// Set default string size assumption at no more than 256 bytes
|
|
//
|
|
BufferLength = 0x100;
|
|
|
|
Buffer = AllocateZeroPool (BufferLength);
|
|
ASSERT (Buffer != NULL);
|
|
|
|
Status = Hii->GetString (Hii, HiiHandle, Token, TRUE, NULL, &BufferLength, Buffer);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
if (Status == EFI_BUFFER_TOO_SMALL) {
|
|
//
|
|
// Free the old pool
|
|
//
|
|
FreePool (Buffer);
|
|
|
|
//
|
|
// Allocate new pool with correct value
|
|
//
|
|
Buffer = AllocatePool (BufferLength);
|
|
ASSERT (Buffer != NULL);
|
|
|
|
Status = Hii->GetString (Hii, HiiHandle, Token, TRUE, NULL, &BufferLength, Buffer);
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
return Buffer;
|
|
}
|
|
}
|
|
|
|
ASSERT_EFI_ERROR (Status);
|
|
}
|
|
|
|
return Buffer;
|
|
}
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
PopulateHomePage (
|
|
IN UINTN NumberOfIfrImages,
|
|
IN EFI_FILE_FORM_TAGS *FileFormTagsHead
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN Index;
|
|
EFI_IFR_BINARY *IfrBinary;
|
|
CHAR16 *StringPtr;
|
|
EFI_FILE_FORM_TAGS *FileFormTags;
|
|
EFI_FORM_TAGS LocalTags;
|
|
|
|
FileFormTags = FileFormTagsHead;
|
|
|
|
UiInitMenu ();
|
|
|
|
Status = EFI_SUCCESS;
|
|
|
|
//
|
|
// If there are no images
|
|
//
|
|
if (NumberOfIfrImages == 0) {
|
|
Status = EFI_NO_MEDIA;
|
|
return Status;
|
|
}
|
|
//
|
|
// IfrBinary points to the beginning of the Binary data linked-list
|
|
//
|
|
IfrBinary = gBinaryDataHead;
|
|
|
|
//
|
|
// Print the entries which were in the default language.
|
|
//
|
|
for (Index = 0; Index < NumberOfIfrImages; Index++) {
|
|
LocalTags = FileFormTags->FormTags;
|
|
|
|
//
|
|
// Populate the Menu
|
|
//
|
|
StringPtr = GetToken (IfrBinary->TitleToken, IfrBinary->Handle);
|
|
|
|
//
|
|
// If the default language doesn't exist, don't add a menu option yet
|
|
//
|
|
if (StringPtr[0] != CHAR_NULL) {
|
|
//
|
|
// We are NOT!! removing this StringPtr buffer via FreePool since it is being used in the menuoptions, we will do
|
|
// it in UiFreeMenu.
|
|
//
|
|
UiAddMenuOption (StringPtr, IfrBinary->Handle, LocalTags.Tags, IfrBinary->FormBinary, Index);
|
|
}
|
|
//
|
|
// Advance to the next HII handle
|
|
//
|
|
IfrBinary = IfrBinary->Next;
|
|
FileFormTags = FileFormTags->NextFile;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
STATIC
|
|
UI_MENU_OPTION *
|
|
DisplayHomePage (
|
|
IN UINTN NumberOfIfrImages,
|
|
IN EFI_FILE_FORM_TAGS *FileFormTagsHead,
|
|
IN UINT8 *CallbackData
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UI_MENU_OPTION *Selection;
|
|
|
|
//
|
|
// This prints the basic home page template which the user sees
|
|
//
|
|
InitPage ();
|
|
|
|
Status = PopulateHomePage (NumberOfIfrImages, FileFormTagsHead);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
Selection = NULL;
|
|
return Selection;
|
|
}
|
|
|
|
Selection = UiDisplayMenu (FALSE, FileFormTagsHead, (EFI_IFR_DATA_ARRAY *) CallbackData);
|
|
|
|
return Selection;
|
|
}
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
InitializeBinaryStructures (
|
|
IN EFI_HII_HANDLE *Handle,
|
|
IN BOOLEAN UseDatabase,
|
|
IN EFI_IFR_PACKET *Packet,
|
|
IN UINT8 *NvMapOverride,
|
|
IN UINTN NumberOfIfrImages,
|
|
OUT EFI_FILE_FORM_TAGS **FileFormTagsHead
|
|
)
|
|
{
|
|
UINTN HandleIndex;
|
|
EFI_STATUS Status;
|
|
EFI_IFR_BINARY *BinaryData;
|
|
EFI_FILE_FORM_TAGS *FileFormTags;
|
|
UINTN SizeOfNvStore;
|
|
EFI_FORM_CALLBACK_PROTOCOL *FormCallback;
|
|
EFI_VARIABLE_DEFINITION *VariableDefinition;
|
|
EFI_VARIABLE_DEFINITION *OverrideDefinition;
|
|
VOID *NvMap;
|
|
UINTN NvMapSize;
|
|
EFI_HII_VARIABLE_PACK_LIST *NvMapListHead;
|
|
EFI_HII_VARIABLE_PACK_LIST *NvMapListNode;
|
|
|
|
//
|
|
// Initialize some variables to avoid warnings
|
|
//
|
|
BinaryData = NULL;
|
|
*FileFormTagsHead = NULL;
|
|
FileFormTags = NULL;
|
|
gBinaryDataHead = NULL;
|
|
Status = EFI_SUCCESS;
|
|
FormCallback = NULL;
|
|
NvMap = NULL;
|
|
NvMapSize = 0;
|
|
|
|
if (NumberOfIfrImages > 1) {
|
|
NvMapOverride = NULL;
|
|
}
|
|
|
|
for (HandleIndex = 0; HandleIndex < NumberOfIfrImages; HandleIndex += 1) {
|
|
//
|
|
// If the buffers are uninitialized, allocate them, otherwise work on the ->Next members
|
|
//
|
|
if ((BinaryData == NULL) || (FileFormTags == NULL)) {
|
|
//
|
|
// Allocate memory for our Binary Data
|
|
//
|
|
BinaryData = AllocateZeroPool (sizeof (EFI_IFR_BINARY));
|
|
ASSERT (BinaryData);
|
|
|
|
//
|
|
// Preserve the Head of what will be a linked-list.
|
|
//
|
|
gBinaryDataHead = BinaryData;
|
|
gBinaryDataHead->Next = NULL;
|
|
|
|
if (UseDatabase) {
|
|
Status = GetIfrBinaryData (Hii, Handle[HandleIndex], NULL, BinaryData);
|
|
} else {
|
|
Status = GetIfrBinaryData (Hii, Handle[HandleIndex], Packet, BinaryData);
|
|
}
|
|
//
|
|
// Allocate memory for our File Form Tags
|
|
//
|
|
FileFormTags = AllocateZeroPool (sizeof (EFI_FILE_FORM_TAGS));
|
|
ASSERT (FileFormTags);
|
|
|
|
//
|
|
// Preserve the Head of what will be a linked-list.
|
|
//
|
|
*FileFormTagsHead = FileFormTags;
|
|
(*FileFormTagsHead)->NextFile = NULL;
|
|
|
|
} else {
|
|
//
|
|
// Allocate memory for our Binary Data linked-list
|
|
// Each handle represents a Binary and we will store that data away.
|
|
//
|
|
BinaryData->Next = AllocateZeroPool (sizeof (EFI_IFR_BINARY));
|
|
ASSERT (BinaryData->Next);
|
|
|
|
BinaryData = BinaryData->Next;
|
|
BinaryData->Next = NULL;
|
|
|
|
if (UseDatabase) {
|
|
Status = GetIfrBinaryData (Hii, Handle[HandleIndex], NULL, BinaryData);
|
|
} else {
|
|
Status = GetIfrBinaryData (Hii, Handle[HandleIndex], Packet, BinaryData);
|
|
}
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
//
|
|
// Allocate memory for our FileFormTags linked-list
|
|
// Each allocation reserves handle represents a Binary and we will store that data away.
|
|
//
|
|
FileFormTags->NextFile = AllocateZeroPool (sizeof (EFI_FILE_FORM_TAGS));
|
|
ASSERT (FileFormTags->NextFile);
|
|
|
|
FileFormTags = FileFormTags->NextFile;
|
|
}
|
|
//
|
|
// endif
|
|
//
|
|
// Tag Structure Initialization
|
|
//
|
|
Status = InitializeTagStructures (BinaryData, FileFormTags);
|
|
|
|
VariableDefinition = FileFormTags->VariableDefinitions;
|
|
|
|
//
|
|
// Allocate memory for our NVRAM Maps for all of our variables
|
|
//
|
|
for (; VariableDefinition != NULL; VariableDefinition = VariableDefinition->Next) {
|
|
//
|
|
// Pad the fake variable size accordingly - this value should reflect the size of information that is not accounted by
|
|
// the mainstream NVRAM variable such as DATE/TIME information that the browser needs to track but is saved to an RTC
|
|
//
|
|
VariableDefinition->VariableFakeSize = (UINT16) (VariableDefinition->VariableSize + VariableDefinition->VariableFakeSize);
|
|
|
|
//
|
|
// In the case where a file has no "real" NV data, we should pad the buffer accordingly
|
|
//
|
|
if (VariableDefinition->VariableSize == 0) {
|
|
if (VariableDefinition->VariableFakeSize != 0) {
|
|
VariableDefinition->NvRamMap = AllocateZeroPool (VariableDefinition->VariableFakeSize);
|
|
ASSERT (VariableDefinition->NvRamMap != NULL);
|
|
}
|
|
} else {
|
|
VariableDefinition->NvRamMap = AllocateZeroPool (VariableDefinition->VariableSize);
|
|
ASSERT (VariableDefinition->NvRamMap != NULL);
|
|
}
|
|
|
|
if (VariableDefinition->VariableFakeSize != 0) {
|
|
VariableDefinition->FakeNvRamMap = AllocateZeroPool (VariableDefinition->VariableFakeSize);
|
|
ASSERT (VariableDefinition->FakeNvRamMap != NULL);
|
|
}
|
|
}
|
|
|
|
Status = gBS->HandleProtocol (
|
|
(VOID *) (UINTN) FileFormTags->FormTags.Tags[0].CallbackHandle,
|
|
&gEfiFormCallbackProtocolGuid,
|
|
(VOID **) &FormCallback
|
|
);
|
|
|
|
//
|
|
// Since we might have multiple variables, if there is an NvMapOverride we need to use the EFI_VARIABLE_DEFINITION
|
|
// information as the information that we pass back and forth. NOTE that callbacks that are initiated will only have the
|
|
// NVRAM data refreshed based on the op-code that initiated the callback. In other words, we will pass to the caller a single
|
|
// NVRAM map for a single variable based on the op-code that the user selected.
|
|
//
|
|
if (NvMapOverride != NULL) {
|
|
VariableDefinition = FileFormTags->VariableDefinitions;
|
|
OverrideDefinition = ((EFI_VARIABLE_DEFINITION *) NvMapOverride);
|
|
|
|
//
|
|
// Search through the variable definitions. There should be sufficient passed in settings for the variable op-codes specified
|
|
//
|
|
for (; VariableDefinition != NULL; VariableDefinition = VariableDefinition->Next) {
|
|
if ((!CompareMem (VariableDefinition->VariableName, L"Setup", 10)) && (VariableDefinition->Next == NULL)) {
|
|
if (VariableDefinition->VariableSize != 0) {
|
|
CopyMem (VariableDefinition->NvRamMap, NvMapOverride, VariableDefinition->VariableSize);
|
|
} else {
|
|
CopyMem (VariableDefinition->NvRamMap, NvMapOverride, VariableDefinition->VariableFakeSize);
|
|
}
|
|
break;
|
|
} else {
|
|
VariableDefinition->NvRamMap = OverrideDefinition->NvRamMap;
|
|
}
|
|
//
|
|
// There should NEVER be a ->Next for VariableDefinition and a NULL ->Next for the OverrideDefinition
|
|
//
|
|
ASSERT (OverrideDefinition->Next);
|
|
OverrideDefinition = OverrideDefinition->Next;
|
|
}
|
|
} else {
|
|
VariableDefinition = FileFormTags->VariableDefinitions;
|
|
|
|
//
|
|
// Search through the variable definitions. There should be sufficient passed in settings for the variable op-codes specified
|
|
//
|
|
for (; VariableDefinition != NULL; VariableDefinition = VariableDefinition->Next) {
|
|
SizeOfNvStore = VariableDefinition->VariableSize;
|
|
|
|
//
|
|
// Getting the NvStore and placing it into our Global Data
|
|
//
|
|
if ((FormCallback != NULL) && (FormCallback->NvRead != NULL)) {
|
|
Status = FormCallback->NvRead (
|
|
FormCallback,
|
|
VariableDefinition->VariableName,
|
|
&VariableDefinition->Guid,
|
|
NULL,
|
|
&SizeOfNvStore,
|
|
(VOID *) VariableDefinition->NvRamMap
|
|
);
|
|
} else {
|
|
Status = gRT->GetVariable (
|
|
VariableDefinition->VariableName,
|
|
&VariableDefinition->Guid,
|
|
NULL,
|
|
&SizeOfNvStore,
|
|
(VOID *) VariableDefinition->NvRamMap
|
|
);
|
|
}
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
//
|
|
// If there is a variable that exists already and it is larger than what we calculated the
|
|
// storage needs to be, we must assume the variable size from GetVariable is correct and not
|
|
// allow the truncation of the variable. It is very possible that the user who created the IFR
|
|
// we are cracking is not referring to a variable that was in a previous map, however we cannot
|
|
// allow it's truncation.
|
|
//
|
|
if (Status == EFI_BUFFER_TOO_SMALL) {
|
|
//
|
|
// If the buffer was too small, we should have the expanded size requirement in SizeOfNvStore now.
|
|
//
|
|
VariableDefinition->VariableSize = (UINT16) SizeOfNvStore;
|
|
|
|
//
|
|
// Free the buffer that was allocated that was too small
|
|
//
|
|
FreePool (VariableDefinition->NvRamMap);
|
|
FreePool (VariableDefinition->FakeNvRamMap);
|
|
|
|
VariableDefinition->NvRamMap = AllocateZeroPool (SizeOfNvStore);
|
|
VariableDefinition->FakeNvRamMap = AllocateZeroPool (SizeOfNvStore + VariableDefinition->VariableFakeSize);
|
|
ASSERT (VariableDefinition->NvRamMap);
|
|
ASSERT (VariableDefinition->FakeNvRamMap);
|
|
|
|
if ((FormCallback != NULL) && (FormCallback->NvRead != NULL)) {
|
|
Status = FormCallback->NvRead (
|
|
FormCallback,
|
|
VariableDefinition->VariableName,
|
|
&VariableDefinition->Guid,
|
|
NULL,
|
|
&SizeOfNvStore,
|
|
(VOID *) VariableDefinition->NvRamMap
|
|
);
|
|
} else {
|
|
Status = gRT->GetVariable (
|
|
VariableDefinition->VariableName,
|
|
&VariableDefinition->Guid,
|
|
NULL,
|
|
&SizeOfNvStore,
|
|
(VOID *) VariableDefinition->NvRamMap
|
|
);
|
|
}
|
|
}
|
|
//
|
|
// if the variable was not found, we will retrieve default values
|
|
//
|
|
if (Status == EFI_NOT_FOUND) {
|
|
|
|
if (0 == CompareMem (VariableDefinition->VariableName, L"Setup", 10)) {
|
|
|
|
NvMapListHead = NULL;
|
|
|
|
Status = Hii->GetDefaultImage (Hii, Handle[HandleIndex], EFI_IFR_FLAG_DEFAULT, &NvMapListHead);
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
ASSERT_EFI_ERROR (NULL != NvMapListHead);
|
|
|
|
NvMapListNode = NvMapListHead;
|
|
|
|
while (NULL != NvMapListNode) {
|
|
if (VariableDefinition->VariableId == NvMapListNode->VariablePack->VariableId) {
|
|
NvMap = (VOID *) ((CHAR8 *) NvMapListNode->VariablePack + sizeof (EFI_HII_VARIABLE_PACK) + NvMapListNode->VariablePack->VariableNameLength);
|
|
NvMapSize = NvMapListNode->VariablePack->Header.Length - sizeof (EFI_HII_VARIABLE_PACK) - NvMapListNode->VariablePack->VariableNameLength;
|
|
break;
|
|
}
|
|
NvMapListNode = NvMapListNode->NextVariablePack;
|
|
}
|
|
|
|
//
|
|
// Free the buffer that was allocated.
|
|
//
|
|
FreePool (VariableDefinition->NvRamMap);
|
|
FreePool (VariableDefinition->FakeNvRamMap);
|
|
|
|
//
|
|
// Allocate, copy the NvRamMap.
|
|
//
|
|
VariableDefinition->VariableFakeSize = (UINT16) (VariableDefinition->VariableFakeSize - VariableDefinition->VariableSize);
|
|
VariableDefinition->VariableSize = (UINT16) NvMapSize;
|
|
VariableDefinition->VariableFakeSize = (UINT16) (VariableDefinition->VariableFakeSize + VariableDefinition->VariableSize);
|
|
|
|
VariableDefinition->NvRamMap = AllocateZeroPool (VariableDefinition->VariableSize);
|
|
VariableDefinition->FakeNvRamMap = AllocateZeroPool (NvMapSize + VariableDefinition->VariableFakeSize);
|
|
|
|
CopyMem (VariableDefinition->NvRamMap, NvMap, NvMapSize);
|
|
FreePool (NvMapListHead);
|
|
}
|
|
|
|
}
|
|
Status = EFI_SUCCESS;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
InitializeTagStructures (BinaryData, FileFormTags);
|
|
}
|
|
//
|
|
// endfor
|
|
//
|
|
return Status;
|
|
}
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
GetIfrBinaryData (
|
|
IN EFI_HII_PROTOCOL *Hii,
|
|
IN EFI_HII_HANDLE HiiHandle,
|
|
IN EFI_IFR_PACKET *Packet,
|
|
IN OUT EFI_IFR_BINARY *BinaryData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Fetch the Ifr binary data.
|
|
|
|
Arguments:
|
|
Hii - Point to HII protocol.
|
|
HiiHandle - Handle of Ifr to be fetched.
|
|
Packet - Pointer to IFR packet.
|
|
BinaryData - Buffer to copy the string into
|
|
|
|
Returns:
|
|
Returns the number of CHAR16 characters that were copied into the OutputString buffer.
|
|
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_HII_PACKAGES *PackageList;
|
|
UINTN BufferSize;
|
|
VOID *Buffer;
|
|
UINT8 *RawFormBinary;
|
|
EFI_IFR_FORM_SET *FormOp;
|
|
UINT16 Index;
|
|
UINT16 Index2;
|
|
UINT16 TitleToken;
|
|
|
|
//
|
|
// Initialize the TitleToken to 0 just in case not found
|
|
//
|
|
TitleToken = 0;
|
|
|
|
//
|
|
// Try for a 32K Buffer
|
|
//
|
|
BufferSize = 0x8000;
|
|
|
|
//
|
|
// Allocate memory for our Form binary
|
|
//
|
|
Buffer = AllocateZeroPool (BufferSize);
|
|
ASSERT (Buffer);
|
|
|
|
if (Packet == NULL) {
|
|
Status = Hii->GetForms (Hii, HiiHandle, 0, &BufferSize, Buffer);
|
|
|
|
if (Status == EFI_BUFFER_TOO_SMALL) {
|
|
|
|
FreePool (Buffer);
|
|
|
|
//
|
|
// Allocate memory for our Form binary
|
|
//
|
|
Buffer = AllocatePool (BufferSize);
|
|
ASSERT (Buffer);
|
|
|
|
Status = Hii->GetForms (Hii, HiiHandle, 0, &BufferSize, Buffer);
|
|
}
|
|
} else {
|
|
//
|
|
// Copies the data to local usable buffer
|
|
//
|
|
CopyMem (Buffer, Packet->IfrData, Packet->IfrData->Header.Length);
|
|
|
|
//
|
|
// Register the string data with HII
|
|
//
|
|
PackageList = PreparePackages (2, NULL, Packet->IfrData, Packet->StringData);
|
|
|
|
Status = Hii->NewPack (Hii, PackageList, &HiiHandle);
|
|
|
|
FreePool (PackageList);
|
|
}
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
//
|
|
// We now have the IFR binary in our Buffer
|
|
//
|
|
BinaryData->IfrPackage = Buffer;
|
|
RawFormBinary = (UINT8 *) ((CHAR8 *) (Buffer) + sizeof (EFI_HII_PACK_HEADER));
|
|
BinaryData->FormBinary = (UINT8 *) ((CHAR8 *) (Buffer) + sizeof (EFI_HII_PACK_HEADER));
|
|
BinaryData->Handle = HiiHandle;
|
|
|
|
//
|
|
// If a packet was passed in, remove the string data when exiting.
|
|
//
|
|
if (Packet != NULL) {
|
|
BinaryData->UnRegisterOnExit = TRUE;
|
|
} else {
|
|
BinaryData->UnRegisterOnExit = FALSE;
|
|
}
|
|
//
|
|
// Walk through the FormSet Opcodes looking for the FormSet opcode
|
|
// If we hit EFI_IFR_END_SET_OP we know we hit the end of the FormSet.
|
|
//
|
|
for (Index = 0; RawFormBinary[Index] != EFI_IFR_END_FORM_SET_OP;) {
|
|
FormOp = (EFI_IFR_FORM_SET *) &RawFormBinary[Index];
|
|
Index = (UINT16) (Index + FormOp->Header.Length);
|
|
|
|
if (FormOp->Header.OpCode == EFI_IFR_FORM_SET_OP) {
|
|
TitleToken = FormOp->FormSetTitle;
|
|
//
|
|
// If displaying FrontPage - set the flag signifying it
|
|
//
|
|
switch (FormOp->SubClass) {
|
|
case EFI_FRONT_PAGE_SUBCLASS:
|
|
FrontPageHandle = HiiHandle;
|
|
|
|
default:
|
|
gClassOfVfr = FormOp->SubClass;
|
|
}
|
|
//
|
|
// Match GUID to find out the function key setting. If match fail, use the default setting.
|
|
//
|
|
for (Index2 = 0; Index2 < sizeof (gFunctionKeySettingTable) / sizeof (FUNCTIION_KEY_SETTING); Index2++) {
|
|
if (CompareGuid ((EFI_GUID *)(UINTN)&FormOp->Guid, &(gFunctionKeySettingTable[Index2].FormSetGuid))) {
|
|
//
|
|
// Update the function key setting.
|
|
//
|
|
gFunctionKeySetting = gFunctionKeySettingTable[Index2].KeySetting;
|
|
//
|
|
// Function key prompt can not be displayed if the function key has been disabled.
|
|
//
|
|
if ((gFunctionKeySetting & FUNCTION_ONE) != FUNCTION_ONE) {
|
|
gFunctionOneString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle);
|
|
}
|
|
|
|
if ((gFunctionKeySetting & FUNCTION_TWO) != FUNCTION_TWO) {
|
|
gFunctionTwoString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle);
|
|
}
|
|
|
|
if ((gFunctionKeySetting & FUNCTION_NINE) != FUNCTION_NINE) {
|
|
gFunctionNineString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle);
|
|
}
|
|
|
|
if ((gFunctionKeySetting & FUNCTION_TEN) != FUNCTION_TEN) {
|
|
gFunctionTenString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
BinaryData->TitleToken = TitleToken;
|
|
|
|
return Status;
|
|
}
|
|
|
|
EFI_HANDLE PrintHandle = NULL;
|
|
EFI_PRINT_PROTOCOL mPrintProtocol =
|
|
{
|
|
UnicodeVSPrint,
|
|
UnicodeVSPrintAsciiFormat,
|
|
UnicodeValueToString,
|
|
AsciiVSPrint,
|
|
AsciiVSPrintUnicodeFormat,
|
|
AsciiValueToString
|
|
};
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
InstallPrint (
|
|
VOID
|
|
)
|
|
{
|
|
return gBS->InstallProtocolInterface (
|
|
&PrintHandle,
|
|
&gEfiPrintProtocolGuid,
|
|
EFI_NATIVE_INTERFACE,
|
|
&mPrintProtocol
|
|
);
|
|
}
|