summaryrefslogtreecommitdiff
path: root/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Setup.c
diff options
context:
space:
mode:
Diffstat (limited to 'EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Setup.c')
-rw-r--r--EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Setup.c2217
1 files changed, 2217 insertions, 0 deletions
diff --git a/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Setup.c b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Setup.c
new file mode 100644
index 0000000..f62bc12
--- /dev/null
+++ b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Setup.c
@@ -0,0 +1,2217 @@
+/*++
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+ Setup.c
+
+Abstract:
+
+ Entry and initialization module for the browser
+
+Revision History:
+--*/
+
+#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
+ },
+};
+
+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
+ );
+
+EFI_STATUS
+InitializeTagStructures (
+ IN EFI_IFR_BINARY *BinaryData,
+ OUT EFI_FILE_FORM_TAGS *FileFormTags
+ );
+
+UI_MENU_OPTION *
+DisplayHomePage (
+ IN UINTN NumberOfIfrImages,
+ IN EFI_FILE_FORM_TAGS *FileFormTagsHead,
+ IN UINT8 *CallbackData
+ );
+
+EFI_STATUS
+GetIfrBinaryData (
+ IN EFI_HII_PROTOCOL *Hii,
+ IN EFI_HII_HANDLE HiiHandle,
+ IN EFI_IFR_PACKET *Packet,
+ IN EFI_IFR_BINARY *BinaryData
+ );
+
+EFI_STATUS
+InstallPrint (
+ VOID
+ );
+
+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_CONFIGURATION_DATA *FormData;
+ 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);
+ }
+
+ FormData = EFI_FORM_DATA_FROM_THIS (This);
+ Callback = FALSE;
+ FormCallback = NULL;
+
+ if (CallbackHandle != NULL) {
+ //
+ // Retrieve the Callback protocol interface
+ //
+ Status = gBS->HandleProtocol (
+ CallbackHandle,
+ &gEfiFormCallbackProtocolGuid,
+ (VOID **) &FormCallback
+ );
+
+ if (EFI_ERROR (Status)) {
+ gBS->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)) {
+ gBS->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) {
+ gBS->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)) {
+ gBS->FreePool (CallbackData);
+ return Status;
+ }
+
+ if (Callback && (AltSelection == NULL)) {
+ gBS->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
+ //
+ gBS->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);
+
+ gBS->FreePool (CallbackData);
+ return EFI_SUCCESS;
+ }
+
+ gBS->FreePool (Selection);
+ UiFreeMenu ();
+
+ //
+ // Clean up the allocated data buffers
+ //
+ FreeData (FileFormTagsHead, NULL, NULL);
+
+ gST->ConOut->ClearScreen (gST->ConOut);
+
+ if (!Callback) {
+ gBS->FreePool (CallbackData);
+ return EFI_SUCCESS;
+ }
+ }
+
+ } while (!EFI_ERROR (Status));
+
+ gBS->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);
+
+ gBS->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;
+ } else {
+ continue;
+ }
+ }
+}
+
+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;
+ } else {
+ continue;
+ }
+ }
+}
+
+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)++;
+}
+
+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 ;
+}
+
+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) {
+ gBS->FreePool (FormTags->Tags[Index].IntList);
+ }
+ }
+
+ gBS->FreePool (FormTags->Tags);
+ gBS->FreePool (FormTags->Next);
+ 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));
+ gBS->FreePool (HomeEscapeString);
+ gBS->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
+ //
+ gBS->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;
+}
+
+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;
+}
+
+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;
+}
+
+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
+ //
+ gBS->FreePool (VariableDefinition->NvRamMap);
+ gBS->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.
+ //
+ gBS->FreePool (VariableDefinition->NvRamMap);
+ gBS->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);
+ gBS->FreePool (NvMapListHead);
+ }
+
+ }
+ Status = EFI_SUCCESS;
+ }
+ }
+ }
+ }
+
+ InitializeTagStructures (BinaryData, FileFormTags);
+ }
+ //
+ // endfor
+ //
+ return Status;
+}
+
+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) {
+
+ gBS->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);
+
+ gBS->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 };
+
+EFI_STATUS
+InstallPrint (
+ VOID
+ )
+{
+ return gBS->InstallProtocolInterface (
+ &PrintHandle,
+ &gEfiPrintProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mPrintProtocol
+ );
+}