From 878ddf1fc3540a715f63594ed22b6929e881afb4 Mon Sep 17 00:00:00 2001 From: bbahnsen Date: Fri, 21 Apr 2006 22:54:32 +0000 Subject: Initial import. git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3 6f19259b-4bc3-4df7-8a09-765794883524 --- .../UserInterface/SetupBrowser/Dxe/Setup.c | 2217 ++++++++++++++++++++ 1 file changed, 2217 insertions(+) create mode 100644 EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Setup.c (limited to 'EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Setup.c') diff --git a/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Setup.c b/EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/Setup.c new file mode 100644 index 0000000000..f62bc120f0 --- /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 + ); +} -- cgit v1.2.3