]> git.proxmox.com Git - mirror_edk2.git/blobdiff - IntelFrameworkModulePkg/Universal/SetupBrowserDxe/Ui.c
Port DriverSample.inf, HiiDatabase.inf and SetupBrowser.inf
[mirror_edk2.git] / IntelFrameworkModulePkg / Universal / SetupBrowserDxe / Ui.c
diff --git a/IntelFrameworkModulePkg/Universal/SetupBrowserDxe/Ui.c b/IntelFrameworkModulePkg/Universal/SetupBrowserDxe/Ui.c
new file mode 100644 (file)
index 0000000..8a514a0
--- /dev/null
@@ -0,0 +1,3155 @@
+/**@file\r
+  Implementation for UI.\r
+\r
+Copyright (c) 2006 - 2007, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+//\r
+// Include common header file for this module.\r
+//\r
+#include "CommonHeader.h"\r
+\r
+#include "Setup.h"\r
+#include "Ui.h"\r
+#include "Colors.h"\r
+\r
+//\r
+// Implementation\r
+//\r
+VOID\r
+SetUnicodeMem (\r
+  IN VOID   *Buffer,\r
+  IN UINTN  Size,\r
+  IN CHAR16 Value\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Set Buffer to Value for Size bytes.\r
+\r
+Arguments:\r
+\r
+  Buffer  - Memory to set.\r
+\r
+  Size    - Number of bytes to set\r
+\r
+  Value   - Value of the set operation.\r
+\r
+Returns:\r
+\r
+  None\r
+\r
+--*/\r
+{\r
+  CHAR16  *Ptr;\r
+\r
+  Ptr = Buffer;\r
+  while (Size--) {\r
+    *(Ptr++) = Value;\r
+  }\r
+}\r
+\r
+VOID\r
+UiInitMenu (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Initialize Menu option list.\r
+\r
+Arguments:\r
+\r
+Returns:\r
+\r
+--*/\r
+{\r
+  InitializeListHead (&Menu);\r
+}\r
+\r
+VOID\r
+UiInitMenuList (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Initialize Menu option list.\r
+\r
+Arguments:\r
+\r
+Returns:\r
+\r
+--*/\r
+{\r
+  InitializeListHead (&gMenuList);\r
+}\r
+\r
+VOID\r
+UiRemoveMenuListEntry (\r
+  IN  UI_MENU_OPTION    *Selection,\r
+  OUT UI_MENU_OPTION    **PreviousSelection\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Remove Menu option list.\r
+\r
+Arguments:\r
+\r
+Returns:\r
+\r
+--*/\r
+{\r
+  UI_MENU_LIST  *UiMenuList;\r
+\r
+  *PreviousSelection = AllocateZeroPool (sizeof (UI_MENU_OPTION));\r
+  ASSERT (*PreviousSelection != NULL);\r
+\r
+  if (!IsListEmpty (&gMenuList)) {\r
+    UiMenuList                      = CR (gMenuList.ForwardLink, UI_MENU_LIST, MenuLink, UI_MENU_LIST_SIGNATURE);\r
+    (*PreviousSelection)->IfrNumber = UiMenuList->Selection.IfrNumber;\r
+    (*PreviousSelection)->FormId    = UiMenuList->Selection.FormId;\r
+    (*PreviousSelection)->Tags      = UiMenuList->Selection.Tags;\r
+    (*PreviousSelection)->ThisTag   = UiMenuList->Selection.ThisTag;\r
+    (*PreviousSelection)->Handle    = UiMenuList->Selection.Handle;\r
+    gEntryNumber                    = UiMenuList->FormerEntryNumber;\r
+    RemoveEntryList (&UiMenuList->MenuLink);\r
+    FreePool (UiMenuList);\r
+  }\r
+}\r
+\r
+VOID\r
+UiFreeMenuList (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Free Menu option linked list.\r
+\r
+Arguments:\r
+\r
+Returns:\r
+\r
+--*/\r
+{\r
+  UI_MENU_LIST  *UiMenuList;\r
+\r
+  while (!IsListEmpty (&gMenuList)) {\r
+    UiMenuList = CR (gMenuList.ForwardLink, UI_MENU_LIST, MenuLink, UI_MENU_LIST_SIGNATURE);\r
+    RemoveEntryList (&UiMenuList->MenuLink);\r
+    FreePool (UiMenuList);\r
+  }\r
+}\r
+\r
+VOID\r
+UiAddMenuListEntry (\r
+  IN UI_MENU_OPTION   *Selection\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Add one menu entry to the linked lst\r
+\r
+Arguments:\r
+\r
+Returns:\r
+\r
+--*/\r
+{\r
+  UI_MENU_LIST  *UiMenuList;\r
+\r
+  UiMenuList = AllocateZeroPool (sizeof (UI_MENU_LIST));\r
+  ASSERT (UiMenuList != NULL);\r
+\r
+  UiMenuList->Signature = UI_MENU_LIST_SIGNATURE;\r
+  CopyMem (&UiMenuList->Selection, Selection, sizeof (UI_MENU_OPTION));\r
+\r
+  InsertHeadList (&gMenuList, &UiMenuList->MenuLink);\r
+}\r
+\r
+VOID\r
+UiFreeMenu (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Free Menu option linked list.\r
+\r
+Arguments:\r
+\r
+Returns:\r
+\r
+--*/\r
+{\r
+  UI_MENU_OPTION  *MenuOption;\r
+\r
+  while (!IsListEmpty (&Menu)) {\r
+    MenuOption = CR (Menu.ForwardLink, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
+    RemoveEntryList (&MenuOption->Link);\r
+\r
+    //\r
+    // We allocated space for this description when we did a GetToken, free it here\r
+    //\r
+    FreePool (MenuOption->Description);\r
+    FreePool (MenuOption);\r
+  }\r
+}\r
+\r
+STATIC\r
+VOID\r
+UpdateDateAndTime (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Refresh screen with current date and/or time based on screen context\r
+\r
+Arguments:\r
+\r
+Returns:\r
+\r
+--*/\r
+{\r
+  CHAR16              *OptionString;\r
+  MENU_REFRESH_ENTRY  *MenuRefreshEntry;\r
+  UINTN               Index;\r
+  UINTN               Loop;\r
+\r
+  OptionString = NULL;\r
+\r
+  if (gMenuRefreshHead != NULL) {\r
+\r
+    MenuRefreshEntry = gMenuRefreshHead;\r
+\r
+    do {\r
+      gST->ConOut->SetAttribute (gST->ConOut, MenuRefreshEntry->CurrentAttribute);\r
+      ProcessOptions (MenuRefreshEntry->MenuOption, FALSE, MenuRefreshEntry->FileFormTagsHead, NULL, &OptionString);\r
+\r
+      if (OptionString != NULL) {\r
+        //\r
+        // If leading spaces on OptionString - remove the spaces\r
+        //\r
+        for (Index = 0; OptionString[Index] == L' '; Index++)\r
+          ;\r
+\r
+        for (Loop = 0; OptionString[Index] != CHAR_NULL; Index++) {\r
+          OptionString[Loop] = OptionString[Index];\r
+          Loop++;\r
+        }\r
+\r
+        OptionString[Loop] = CHAR_NULL;\r
+\r
+        PrintStringAt (MenuRefreshEntry->CurrentColumn, MenuRefreshEntry->CurrentRow, OptionString);\r
+      }\r
+\r
+      MenuRefreshEntry = MenuRefreshEntry->Next;\r
+\r
+    } while (MenuRefreshEntry != NULL);\r
+  }\r
+\r
+  if (OptionString != NULL) {\r
+    FreePool (OptionString);\r
+  }\r
+}\r
+\r
+EFI_STATUS\r
+UiWaitForSingleEvent (\r
+  IN EFI_EVENT                Event,\r
+  IN UINT64                   Timeout OPTIONAL\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Wait for a given event to fire, or for an optional timeout to expire.\r
+\r
+Arguments:\r
+  Event            - The event to wait for\r
+\r
+  Timeout          - An optional timeout value in 100 ns units.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS      - Event fired before Timeout expired.\r
+  EFI_TIME_OUT     - Timout expired before Event fired.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS  Status;\r
+  UINTN       Index;\r
+  EFI_EVENT   TimerEvent;\r
+  EFI_EVENT   WaitList[2];\r
+\r
+  if (Timeout) {\r
+    //\r
+    // Create a timer event\r
+    //\r
+    Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);\r
+    if (!EFI_ERROR (Status)) {\r
+      //\r
+      // Set the timer event\r
+      //\r
+      gBS->SetTimer (\r
+            TimerEvent,\r
+            TimerRelative,\r
+            Timeout\r
+            );\r
+\r
+      //\r
+      // Wait for the original event or the timer\r
+      //\r
+      WaitList[0] = Event;\r
+      WaitList[1] = TimerEvent;\r
+      Status      = gBS->WaitForEvent (2, WaitList, &Index);\r
+      gBS->CloseEvent (TimerEvent);\r
+\r
+      //\r
+      // If the timer expired, change the return to timed out\r
+      //\r
+      if (!EFI_ERROR (Status) && Index == 1) {\r
+        Status = EFI_TIMEOUT;\r
+      }\r
+    }\r
+  } else {\r
+    //\r
+    // Update screen every second\r
+    //\r
+    Timeout = ONE_SECOND;\r
+\r
+    do {\r
+      Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);\r
+\r
+      //\r
+      // Set the timer event\r
+      //\r
+      gBS->SetTimer (\r
+            TimerEvent,\r
+            TimerRelative,\r
+            Timeout\r
+            );\r
+\r
+      //\r
+      // Wait for the original event or the timer\r
+      //\r
+      WaitList[0] = Event;\r
+      WaitList[1] = TimerEvent;\r
+      Status      = gBS->WaitForEvent (2, WaitList, &Index);\r
+\r
+      //\r
+      // If the timer expired, update anything that needs a refresh and keep waiting\r
+      //\r
+      if (!EFI_ERROR (Status) && Index == 1) {\r
+        Status = EFI_TIMEOUT;\r
+        UpdateDateAndTime ();\r
+      }\r
+\r
+      gBS->CloseEvent (TimerEvent);\r
+    } while (Status == EFI_TIMEOUT);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+VOID\r
+UiAddMenuOption (\r
+  IN CHAR16         *String,\r
+  IN EFI_HII_HANDLE Handle,\r
+  IN EFI_TAG        *Tags,\r
+  IN VOID           *FormBinary,\r
+  IN UINTN          IfrNumber\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Add one menu option by specified description and context.\r
+\r
+Arguments:\r
+  String - String description for this option.\r
+  Context - Context data for entry.\r
+\r
+Returns:\r
+\r
+--*/\r
+{\r
+  UI_MENU_OPTION  *MenuOption;\r
+\r
+  MenuOption = AllocateZeroPool (sizeof (UI_MENU_OPTION));\r
+  ASSERT (MenuOption);\r
+\r
+  MenuOption->Signature   = UI_MENU_OPTION_SIGNATURE;\r
+  MenuOption->Description = String;\r
+  MenuOption->Handle      = Handle;\r
+  MenuOption->FormBinary  = FormBinary;\r
+  MenuOption->IfrNumber   = IfrNumber;\r
+  MenuOption->Skip        = 1;\r
+  MenuOption->Tags        = Tags;\r
+  MenuOption->TagIndex    = 0;\r
+  MenuOption->ThisTag     = &(MenuOption->Tags[MenuOption->TagIndex]);\r
+  MenuOption->EntryNumber = (UINT16) IfrNumber;\r
+\r
+  InsertTailList (&Menu, &MenuOption->Link);\r
+}\r
+\r
+VOID\r
+UiAddSubMenuOption (\r
+  IN CHAR16           *String,\r
+  IN EFI_HII_HANDLE   Handle,\r
+  IN EFI_TAG          *Tags,\r
+  IN UINTN            TagIndex,\r
+  IN UINT16           FormId,\r
+  IN UINT16           MenuItemCount\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Add one menu option by specified description and context.\r
+\r
+Arguments:\r
+  String - String description for this option.\r
+  Context - Context data for entry.\r
+\r
+Returns:\r
+\r
+--*/\r
+{\r
+  UI_MENU_OPTION  *MenuOption;\r
+\r
+  MenuOption = AllocateZeroPool (sizeof (UI_MENU_OPTION));\r
+  ASSERT (MenuOption);\r
+\r
+  MenuOption->Signature   = UI_MENU_OPTION_SIGNATURE;\r
+  MenuOption->Description = String;\r
+  MenuOption->Handle      = Handle;\r
+  MenuOption->Skip        = Tags[TagIndex].NumberOfLines;\r
+  MenuOption->IfrNumber   = gActiveIfr;\r
+  MenuOption->Tags        = Tags;\r
+  MenuOption->TagIndex    = TagIndex;\r
+  MenuOption->ThisTag     = &(MenuOption->Tags[MenuOption->TagIndex]);\r
+  MenuOption->Consistency = Tags[TagIndex].Consistency;\r
+  MenuOption->FormId      = FormId;\r
+  MenuOption->GrayOut     = Tags[TagIndex].GrayOut;\r
+  MenuOption->EntryNumber = MenuItemCount;\r
+\r
+  InsertTailList (&Menu, &MenuOption->Link);\r
+}\r
+\r
+EFI_STATUS\r
+CreateDialog (\r
+  IN  UINTN                       NumberOfLines,\r
+  IN  BOOLEAN                     HotKey,\r
+  IN  UINTN                       MaximumStringSize,\r
+  OUT CHAR16                      *StringBuffer,\r
+  OUT EFI_INPUT_KEY               *KeyValue,\r
+  IN  CHAR16                      *String,\r
+  ...\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Routine used to abstract a generic dialog interface and return the selected key or string\r
+\r
+Arguments:\r
+  NumberOfLines -     The number of lines for the dialog box\r
+  HotKey -            Defines whether a single character is parsed (TRUE) and returned in KeyValue\r
+                      or a string is returned in StringBuffer.  Two special characters are considered when entering a string, a SCAN_ESC and\r
+                      an CHAR_CARRIAGE_RETURN.  SCAN_ESC terminates string input and returns\r
+  MaximumStringSize - The maximum size in bytes of a typed in string (each character is a CHAR16) and the minimum string returned is two bytes\r
+  StringBuffer -      The passed in pointer to the buffer which will hold the typed in string if HotKey is FALSE\r
+  KeyValue -          The EFI_KEY value returned if HotKey is TRUE..\r
+  String -            Pointer to the first string in the list\r
+  ... -               A series of (quantity == NumberOfLines) text strings which will be used to construct the dialog box\r
+\r
+Returns:\r
+  EFI_SUCCESS -           Displayed dialog and received user interaction\r
+  EFI_INVALID_PARAMETER - One of the parameters was invalid (e.g. (StringBuffer == NULL) && (HotKey == FALSE))\r
+  EFI_DEVICE_ERROR -      User typed in an ESC character to exit the routine\r
+\r
+--*/\r
+{\r
+  VA_LIST       Marker;\r
+  UINTN         Count;\r
+  EFI_INPUT_KEY Key;\r
+  UINTN         LargestString;\r
+  CHAR16        *TempString;\r
+  CHAR16        *BufferedString;\r
+  CHAR16        *StackString;\r
+  CHAR16        KeyPad[2];\r
+  UINTN         Start;\r
+  UINTN         Top;\r
+  UINTN         Index;\r
+  BOOLEAN       SelectionComplete;\r
+  UINTN         InputOffset;\r
+  UINTN         CurrentAttribute;\r
+  UINTN         DimensionsWidth;\r
+  UINTN         DimensionsHeight;\r
+\r
+  DimensionsWidth   = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn;\r
+  DimensionsHeight  = gScreenDimensions.BottomRow - gScreenDimensions.TopRow;\r
+\r
+  SelectionComplete = FALSE;\r
+  InputOffset       = 0;\r
+  TempString        = AllocateZeroPool (MaximumStringSize * 2);\r
+  BufferedString    = AllocateZeroPool (MaximumStringSize * 2);\r
+  CurrentAttribute  = gST->ConOut->Mode->Attribute;\r
+\r
+  ASSERT (TempString);\r
+  ASSERT (BufferedString);\r
+\r
+  VA_START (Marker, String);\r
+\r
+  //\r
+  // Zero the outgoing buffer\r
+  //\r
+  ZeroMem (StringBuffer, MaximumStringSize);\r
+\r
+  if (HotKey) {\r
+    if (KeyValue == NULL) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+  } else {\r
+    if (StringBuffer == NULL) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+  }\r
+  //\r
+  // Disable cursor\r
+  //\r
+  gST->ConOut->EnableCursor (gST->ConOut, FALSE);\r
+\r
+  LargestString = (GetStringWidth (String) / 2);\r
+\r
+  if (LargestString == L' ') {\r
+    InputOffset = 1;\r
+  }\r
+  //\r
+  // Determine the largest string in the dialog box\r
+  // Notice we are starting with 1 since String is the first string\r
+  //\r
+  for (Count = 1; Count < NumberOfLines; Count++) {\r
+    StackString = VA_ARG (Marker, CHAR16 *);\r
+\r
+    if (StackString[0] == L' ') {\r
+      InputOffset = Count + 1;\r
+    }\r
+\r
+    if ((GetStringWidth (StackString) / 2) > LargestString) {\r
+      //\r
+      // Size of the string visually and subtract the width by one for the null-terminator\r
+      //\r
+      LargestString = (GetStringWidth (StackString) / 2);\r
+    }\r
+  }\r
+\r
+  Start = (DimensionsWidth - LargestString - 2) / 2 + gScreenDimensions.LeftColumn + 1;\r
+  Top   = ((DimensionsHeight - NumberOfLines - 2) / 2) + gScreenDimensions.TopRow - 1;\r
+\r
+  Count = 0;\r
+\r
+  //\r
+  // Display the Popup\r
+  //\r
+  CreateSharedPopUp (LargestString, NumberOfLines, &String);\r
+\r
+  //\r
+  // Take the first key typed and report it back?\r
+  //\r
+  if (HotKey) {\r
+    WaitForKeyStroke (&Key);\r
+    CopyMem (KeyValue, &Key, sizeof (EFI_INPUT_KEY));\r
+\r
+  } else {\r
+    do {\r
+      WaitForKeyStroke (&Key);\r
+\r
+      switch (Key.UnicodeChar) {\r
+      case CHAR_NULL:\r
+        switch (Key.ScanCode) {\r
+        case SCAN_ESC:\r
+          FreePool (TempString);\r
+          FreePool (BufferedString);\r
+          gST->ConOut->SetAttribute (gST->ConOut, CurrentAttribute);\r
+          gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
+          return EFI_DEVICE_ERROR;\r
+\r
+        default:\r
+          break;\r
+        }\r
+\r
+        break;\r
+\r
+      case CHAR_CARRIAGE_RETURN:\r
+        SelectionComplete = TRUE;\r
+        FreePool (TempString);\r
+        FreePool (BufferedString);\r
+        gST->ConOut->SetAttribute (gST->ConOut, CurrentAttribute);\r
+        gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
+        return EFI_SUCCESS;\r
+        break;\r
+\r
+      case CHAR_BACKSPACE:\r
+        if (StringBuffer[0] != CHAR_NULL) {\r
+          for (Index = 0; StringBuffer[Index] != CHAR_NULL; Index++) {\r
+            TempString[Index] = StringBuffer[Index];\r
+          }\r
+          //\r
+          // Effectively truncate string by 1 character\r
+          //\r
+          TempString[Index - 1] = CHAR_NULL;\r
+          StrCpy (StringBuffer, TempString);\r
+        }\r
+\r
+      default:\r
+        //\r
+        // If it is the beginning of the string, don't worry about checking maximum limits\r
+        //\r
+        if ((StringBuffer[0] == CHAR_NULL) && (Key.UnicodeChar != CHAR_BACKSPACE)) {\r
+          StrnCpy (StringBuffer, &Key.UnicodeChar, 1);\r
+          StrnCpy (TempString, &Key.UnicodeChar, 1);\r
+        } else if ((GetStringWidth (StringBuffer) < MaximumStringSize) && (Key.UnicodeChar != CHAR_BACKSPACE)) {\r
+          KeyPad[0] = Key.UnicodeChar;\r
+          KeyPad[1] = CHAR_NULL;\r
+          StrCat (StringBuffer, KeyPad);\r
+          StrCat (TempString, KeyPad);\r
+        }\r
+        //\r
+        // If the width of the input string is now larger than the screen, we nee to\r
+        // adjust the index to start printing portions of the string\r
+        //\r
+        SetUnicodeMem (BufferedString, LargestString, L' ');\r
+\r
+        PrintStringAt (Start + 1, Top + InputOffset, BufferedString);\r
+\r
+        if ((GetStringWidth (StringBuffer) / 2) > (DimensionsWidth - 2)) {\r
+          Index = (GetStringWidth (StringBuffer) / 2) - DimensionsWidth + 2;\r
+        } else {\r
+          Index = 0;\r
+        }\r
+\r
+        for (Count = 0; Index + 1 < GetStringWidth (StringBuffer) / 2; Index++, Count++) {\r
+          BufferedString[Count] = StringBuffer[Index];\r
+        }\r
+\r
+        PrintStringAt (Start + 1, Top + InputOffset, BufferedString);\r
+        break;\r
+      }\r
+    } while (!SelectionComplete);\r
+  }\r
+\r
+  gST->ConOut->SetAttribute (gST->ConOut, CurrentAttribute);\r
+  gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+VOID\r
+CreateSharedPopUp (\r
+  IN  UINTN                       RequestedWidth,\r
+  IN  UINTN                       NumberOfLines,\r
+  IN  CHAR16                      **ArrayOfStrings\r
+  )\r
+{\r
+  UINTN   Index;\r
+  UINTN   Count;\r
+  CHAR16  Character;\r
+  UINTN   Start;\r
+  UINTN   End;\r
+  UINTN   Top;\r
+  UINTN   Bottom;\r
+  CHAR16  *String;\r
+\r
+  UINTN   DimensionsWidth;\r
+  UINTN   DimensionsHeight;\r
+\r
+  DimensionsWidth   = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn;\r
+  DimensionsHeight  = gScreenDimensions.BottomRow - gScreenDimensions.TopRow;\r
+\r
+  Count             = 0;\r
+\r
+  gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);\r
+\r
+  if ((RequestedWidth + 2) > DimensionsWidth) {\r
+    RequestedWidth = DimensionsWidth - 2;\r
+  }\r
+  //\r
+  // Subtract the PopUp width from total Columns, allow for one space extra on\r
+  // each end plus a border.\r
+  //\r
+  Start     = (DimensionsWidth - RequestedWidth - 2) / 2 + gScreenDimensions.LeftColumn + 1;\r
+  End       = Start + RequestedWidth + 1;\r
+\r
+  Top       = ((DimensionsHeight - NumberOfLines - 2) / 2) + gScreenDimensions.TopRow - 1;\r
+  Bottom    = Top + NumberOfLines + 2;\r
+\r
+  Character = (CHAR16) BOXDRAW_DOWN_RIGHT;\r
+  PrintCharAt (Start, Top, Character);\r
+  Character = (CHAR16) BOXDRAW_HORIZONTAL;\r
+  for (Index = Start; Index + 2 < End; Index++) {\r
+    PrintChar (Character);\r
+  }\r
+\r
+  Character = (CHAR16) BOXDRAW_DOWN_LEFT;\r
+  PrintChar (Character);\r
+  Character = (CHAR16) BOXDRAW_VERTICAL;\r
+  for (Index = Top; Index + 2 < Bottom; Index++) {\r
+    String = ArrayOfStrings[Count];\r
+    Count++;\r
+\r
+    //\r
+    // This will clear the background of the line - we never know who might have been\r
+    // here before us.  This differs from the next clear in that it used the non-reverse\r
+    // video for normal printing.\r
+    //\r
+    if (GetStringWidth (String) / 2 > 1) {\r
+      ClearLines (Start, End, Index + 1, Index + 1, POPUP_TEXT | POPUP_BACKGROUND);\r
+    }\r
+    //\r
+    // Passing in a space results in the assumption that this is where typing will occur\r
+    //\r
+    if (String[0] == L' ') {\r
+      ClearLines (Start + 1, End - 1, Index + 1, Index + 1, POPUP_INVERSE_TEXT | POPUP_INVERSE_BACKGROUND);\r
+    }\r
+    //\r
+    // Passing in a NULL results in a blank space\r
+    //\r
+    if (String[0] == CHAR_NULL) {\r
+      ClearLines (Start, End, Index + 1, Index + 1, POPUP_TEXT | POPUP_BACKGROUND);\r
+    }\r
+\r
+    PrintStringAt (\r
+      ((DimensionsWidth - GetStringWidth (String) / 2) / 2) + gScreenDimensions.LeftColumn + 1,\r
+      Index + 1,\r
+      String\r
+      );\r
+    gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);\r
+    PrintCharAt (Start, Index + 1, Character);\r
+    PrintCharAt (End - 1, Index + 1, Character);\r
+  }\r
+\r
+  Character = (CHAR16) BOXDRAW_UP_RIGHT;\r
+  PrintCharAt (Start, Bottom - 1, Character);\r
+  Character = (CHAR16) BOXDRAW_HORIZONTAL;\r
+  for (Index = Start; Index + 2 < End; Index++) {\r
+    PrintChar (Character);\r
+  }\r
+\r
+  Character = (CHAR16) BOXDRAW_UP_LEFT;\r
+  PrintChar (Character);\r
+}\r
+\r
+VOID\r
+CreatePopUp (\r
+  IN  UINTN                       RequestedWidth,\r
+  IN  UINTN                       NumberOfLines,\r
+  IN  CHAR16                      *ArrayOfStrings,\r
+  ...\r
+  )\r
+{\r
+  CreateSharedPopUp (RequestedWidth, NumberOfLines, &ArrayOfStrings);\r
+}\r
+\r
+VOID\r
+UpdateStatusBar (\r
+  IN  UINTN                       MessageType,\r
+  IN  UINT8                       Flags,\r
+  IN  BOOLEAN                     State\r
+  )\r
+{\r
+  UINTN           Index;\r
+  STATIC BOOLEAN  InputError;\r
+  CHAR16          *NvUpdateMessage;\r
+  CHAR16          *InputErrorMessage;\r
+\r
+  NvUpdateMessage   = GetToken (STRING_TOKEN (NV_UPDATE_MESSAGE), gHiiHandle);\r
+  InputErrorMessage = GetToken (STRING_TOKEN (INPUT_ERROR_MESSAGE), gHiiHandle);\r
+\r
+  switch (MessageType) {\r
+  case INPUT_ERROR:\r
+    if (State) {\r
+      gST->ConOut->SetAttribute (gST->ConOut, ERROR_TEXT);\r
+      PrintStringAt (\r
+        gScreenDimensions.LeftColumn + gPromptBlockWidth,\r
+        gScreenDimensions.BottomRow - 1,\r
+        InputErrorMessage\r
+        );\r
+      InputError = TRUE;\r
+    } else {\r
+      gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT);\r
+      for (Index = 0; Index < (GetStringWidth (InputErrorMessage) - 2) / 2; Index++) {\r
+        PrintAt (gScreenDimensions.LeftColumn + gPromptBlockWidth + Index, gScreenDimensions.BottomRow - 1, (CHAR16 *) L"  ");\r
+      }\r
+\r
+      InputError = FALSE;\r
+    }\r
+    break;\r
+\r
+  case NV_UPDATE_REQUIRED:\r
+    if (gClassOfVfr != EFI_FRONT_PAGE_SUBCLASS) {\r
+      if (State) {\r
+        gST->ConOut->SetAttribute (gST->ConOut, INFO_TEXT);\r
+        PrintStringAt (\r
+          gScreenDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth,\r
+          gScreenDimensions.BottomRow - 1,\r
+          NvUpdateMessage\r
+          );\r
+        gResetRequired    = (BOOLEAN) (gResetRequired | ((Flags & EFI_IFR_FLAG_RESET_REQUIRED) == EFI_IFR_FLAG_RESET_REQUIRED));\r
+\r
+        gNvUpdateRequired = TRUE;\r
+      } else {\r
+        gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT);\r
+        for (Index = 0; Index < (GetStringWidth (NvUpdateMessage) - 2) / 2; Index++) {\r
+          PrintAt (\r
+            (gScreenDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + Index),\r
+            gScreenDimensions.BottomRow - 1,\r
+            (CHAR16 *) L"  "\r
+            );\r
+        }\r
+\r
+        gNvUpdateRequired = FALSE;\r
+      }\r
+    }\r
+    break;\r
+\r
+  case REFRESH_STATUS_BAR:\r
+    if (InputError) {\r
+      UpdateStatusBar (INPUT_ERROR, Flags, TRUE);\r
+    }\r
+\r
+    if (gNvUpdateRequired) {\r
+      UpdateStatusBar (NV_UPDATE_REQUIRED, Flags, TRUE);\r
+    }\r
+    break;\r
+\r
+  default:\r
+    break;\r
+  }\r
+\r
+  FreePool (InputErrorMessage);\r
+  FreePool (NvUpdateMessage);\r
+  return ;\r
+}\r
+\r
+VOID\r
+FreeData (\r
+  IN EFI_FILE_FORM_TAGS           *FileFormTagsHead,\r
+  IN CHAR16                       *FormattedString,\r
+  IN CHAR16                       *OptionString\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Used to remove the allocated data instances\r
+\r
+Arguments:\r
+\r
+Returns:\r
+\r
+--*/\r
+{\r
+  EFI_FILE_FORM_TAGS      *FileForm;\r
+  EFI_FILE_FORM_TAGS      *PreviousFileForm;\r
+  EFI_FORM_TAGS           *FormTags;\r
+  EFI_FORM_TAGS           *PreviousFormTags;\r
+  EFI_IFR_BINARY          *IfrBinary;\r
+  EFI_IFR_BINARY          *PreviousIfrBinary;\r
+  EFI_INCONSISTENCY_DATA  *Inconsistent;\r
+  EFI_VARIABLE_DEFINITION *VariableDefinition;\r
+  EFI_VARIABLE_DEFINITION *PreviousVariableDefinition;\r
+  VOID                    *Buffer;\r
+  UINTN                   Index;\r
+\r
+  FileForm = FileFormTagsHead;\r
+\r
+  if (FormattedString != NULL) {\r
+    FreePool (FormattedString);\r
+  }\r
+\r
+  if (OptionString != NULL) {\r
+    FreePool (OptionString);\r
+  }\r
+\r
+  for (; FileForm != NULL;) {\r
+    PreviousFileForm = NULL;\r
+\r
+    //\r
+    // Advance FileForm to the last entry\r
+    //\r
+    for (; FileForm->NextFile != NULL; FileForm = FileForm->NextFile) {\r
+      PreviousFileForm = FileForm;\r
+    }\r
+\r
+    FormTags = &FileForm->FormTags;\r
+\r
+    for (; FormTags != NULL;) {\r
+      FormTags          = &FileForm->FormTags;\r
+      PreviousFormTags  = NULL;\r
+\r
+      //\r
+      // Advance FormTags to the last entry\r
+      //\r
+      for (; FormTags->Next != NULL; FormTags = FormTags->Next) {\r
+        PreviousFormTags = FormTags;\r
+      }\r
+      //\r
+      // Walk through each of the tags and free the IntList allocation\r
+      //\r
+      for (Index = 0; FormTags->Tags[Index].Operand != EFI_IFR_END_FORM_OP; Index++) {\r
+        //\r
+        // It is more than likely that the very last page will contain an end formset\r
+        //\r
+        if (FormTags->Tags[Index].Operand == EFI_IFR_END_FORM_SET_OP) {\r
+          break;\r
+        }\r
+\r
+        if (FormTags->Tags[Index].IntList != NULL) {\r
+          FreePool (FormTags->Tags[Index].IntList);\r
+        }\r
+      }\r
+\r
+      if (PreviousFormTags != NULL) {\r
+        FreePool (FormTags->Tags);\r
+        FormTags = PreviousFormTags;\r
+        FreePool (FormTags->Next);\r
+        FormTags->Next = NULL;\r
+      } else {\r
+        FreePool (FormTags->Tags);\r
+        FormTags = NULL;\r
+      }\r
+    }\r
+    //\r
+    // Last FileForm entry's Inconsistent database\r
+    //\r
+    Inconsistent = FileForm->InconsistentTags;\r
+\r
+    //\r
+    // Advance Inconsistent to the last entry\r
+    //\r
+    for (; Inconsistent->Next != NULL; Inconsistent = Inconsistent->Next)\r
+      ;\r
+\r
+    for (; Inconsistent != NULL;) {\r
+      //\r
+      // Preserve the Previous pointer\r
+      //\r
+      Buffer = (VOID *) Inconsistent->Previous;\r
+\r
+      //\r
+      // Free the current entry\r
+      //\r
+      FreePool (Inconsistent);\r
+\r
+      //\r
+      // Restore the Previous pointer\r
+      //\r
+      Inconsistent = (EFI_INCONSISTENCY_DATA *) Buffer;\r
+    }\r
+\r
+    VariableDefinition = FileForm->VariableDefinitions;\r
+\r
+    for (; VariableDefinition != NULL;) {\r
+      VariableDefinition          = FileForm->VariableDefinitions;\r
+      PreviousVariableDefinition  = NULL;\r
+\r
+      //\r
+      // Advance VariableDefinitions to the last entry\r
+      //\r
+      for (; VariableDefinition->Next != NULL; VariableDefinition = VariableDefinition->Next) {\r
+        PreviousVariableDefinition = VariableDefinition;\r
+      }\r
+\r
+      FreePool (VariableDefinition->VariableName);\r
+\r
+      if (VariableDefinition->NvRamMap != NULL) {\r
+        FreePool (VariableDefinition->NvRamMap);\r
+      }\r
+\r
+      if (VariableDefinition->FakeNvRamMap != NULL) {\r
+        FreePool (VariableDefinition->FakeNvRamMap);\r
+      }\r
+\r
+      if (PreviousVariableDefinition != NULL) {\r
+        VariableDefinition = PreviousVariableDefinition;\r
+        FreePool (VariableDefinition->Next);\r
+        VariableDefinition->Next = NULL;\r
+      } else {\r
+        FreePool (VariableDefinition);\r
+        VariableDefinition = NULL;\r
+      }\r
+    }\r
+\r
+    if (PreviousFileForm != NULL) {\r
+      FileForm = PreviousFileForm;\r
+      FreePool (FileForm->NextFile);\r
+      FileForm->NextFile = NULL;\r
+    } else {\r
+      FreePool (FileForm);\r
+      FileForm = NULL;\r
+    }\r
+  }\r
+\r
+  IfrBinary = gBinaryDataHead;\r
+\r
+  for (; IfrBinary != NULL;) {\r
+    IfrBinary         = gBinaryDataHead;\r
+    PreviousIfrBinary = NULL;\r
+\r
+    //\r
+    // Advance IfrBinary to the last entry\r
+    //\r
+    for (; IfrBinary->Next != NULL; IfrBinary = IfrBinary->Next) {\r
+      PreviousIfrBinary = IfrBinary;\r
+    }\r
+\r
+    FreePool (IfrBinary->IfrPackage);\r
+\r
+    if (PreviousIfrBinary != NULL) {\r
+      IfrBinary = PreviousIfrBinary;\r
+      FreePool (IfrBinary->Next);\r
+      IfrBinary->Next = NULL;\r
+    } else {\r
+      FreePool (IfrBinary);\r
+      IfrBinary = NULL;\r
+    }\r
+  }\r
+\r
+  FreePool (gPreviousValue);\r
+  gPreviousValue = NULL;\r
+\r
+  //\r
+  // Free Browser Strings\r
+  //\r
+  FreePool (gPressEnter);\r
+  FreePool (gConfirmError);\r
+  FreePool (gConfirmPassword);\r
+  FreePool (gPromptForNewPassword);\r
+  FreePool (gPromptForPassword);\r
+  FreePool (gToggleCheckBox);\r
+  FreePool (gNumericInput);\r
+  FreePool (gMakeSelection);\r
+  FreePool (gMoveHighlight);\r
+  FreePool (gEscapeString);\r
+  FreePool (gEnterCommitString);\r
+  FreePool (gEnterString);\r
+  FreePool (gFunctionOneString);\r
+  FreePool (gFunctionTwoString);\r
+  FreePool (gFunctionNineString);\r
+  FreePool (gFunctionTenString);\r
+  return ;\r
+}\r
+\r
+STATIC\r
+BOOLEAN\r
+SelectionsAreValid (\r
+  IN  UI_MENU_OPTION               *MenuOption,\r
+  IN  EFI_FILE_FORM_TAGS           *FileFormTagsHead\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Initiate late consistency checks against the current page.\r
+\r
+Arguments:\r
+  None\r
+\r
+Returns:\r
+\r
+--*/\r
+{\r
+  LIST_ENTRY              *Link;\r
+  EFI_TAG                 *Tag;\r
+  EFI_FILE_FORM_TAGS      *FileFormTags;\r
+  CHAR16                  *StringPtr;\r
+  CHAR16                  NullCharacter;\r
+  UINTN                   Index;\r
+  UINT16                  *NvRamMap;\r
+  STRING_REF              PopUp;\r
+  EFI_INPUT_KEY           Key;\r
+  EFI_VARIABLE_DEFINITION *VariableDefinition;\r
+\r
+  StringPtr     = (CHAR16 *) L"\0";\r
+  NullCharacter = CHAR_NULL;\r
+\r
+  FileFormTags  = FileFormTagsHead;\r
+\r
+  for (Index = 0; Index < MenuOption->IfrNumber; Index++) {\r
+    FileFormTags = FileFormTags->NextFile;\r
+  }\r
+\r
+  for (Link = Menu.ForwardLink; Link != &Menu; Link = Link->ForwardLink) {\r
+    MenuOption  = CR (Link, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
+\r
+    Tag         = MenuOption->ThisTag;\r
+\r
+    ExtractRequestedNvMap (FileFormTags, Tag->VariableNumber, &VariableDefinition);\r
+    NvRamMap = (UINT16 *) &VariableDefinition->NvRamMap[Tag->StorageStart];\r
+\r
+    //\r
+    // If the op-code has a late check, ensure consistency checks are now applied\r
+    //\r
+    if (Tag->Flags & EFI_IFR_FLAG_LATE_CHECK) {\r
+      if (ValueIsNotValid (TRUE, 0, Tag, FileFormTags, &PopUp)) {\r
+        if (PopUp != 0x0000) {\r
+          StringPtr = GetToken (PopUp, MenuOption->Handle);\r
+\r
+          CreatePopUp (GetStringWidth (StringPtr) / 2, 3, &NullCharacter, StringPtr, &NullCharacter);\r
+\r
+          do {\r
+            WaitForKeyStroke (&Key);\r
+\r
+            switch (Key.UnicodeChar) {\r
+\r
+            case CHAR_CARRIAGE_RETURN:\r
+              //\r
+              // Since the value can be one byte long or two bytes long, do a CopyMem based on StorageWidth\r
+              //\r
+              CopyMem (NvRamMap, &Tag->OldValue, Tag->StorageWidth);\r
+              FreePool (StringPtr);\r
+              break;\r
+\r
+            default:\r
+              break;\r
+            }\r
+          } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+        }\r
+\r
+        return FALSE;\r
+      }\r
+    }\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+UINT16\r
+GetWidth (\r
+  IN EFI_TAG                        *Tag,\r
+  IN EFI_HII_HANDLE                 Handle\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Get the supported width for a particular op-code\r
+\r
+Arguments:\r
+  Tag - The Tag structure passed in.\r
+  Handle - The handle in the HII database being used\r
+\r
+Returns:\r
+  Returns the number of CHAR16 characters that is support.\r
+\r
+\r
+--*/\r
+{\r
+  CHAR16  *String;\r
+  UINTN   Size;\r
+\r
+  Size = 0x00;\r
+\r
+  //\r
+  // See if the second text parameter is really NULL\r
+  //\r
+  if ((Tag->Operand == EFI_IFR_TEXT_OP) && (Tag->TextTwo != 0)) {\r
+    String  = GetToken (Tag->TextTwo, Handle);\r
+    Size    = StrLen (String);\r
+    FreePool (String);\r
+  }\r
+\r
+  if ((Tag->Operand == EFI_IFR_SUBTITLE_OP) ||\r
+      (Tag->Operand == EFI_IFR_REF_OP) ||\r
+      (Tag->Operand == EFI_IFR_PASSWORD_OP) ||\r
+      (Tag->Operand == EFI_IFR_STRING_OP) ||\r
+      (Tag->Operand == EFI_IFR_INVENTORY_OP) ||\r
+      //\r
+      // Allow a wide display if text op-code and no secondary text op-code\r
+      //\r
+      ((Tag->Operand == EFI_IFR_TEXT_OP) && (Size == 0x0000))\r
+      ) {\r
+    return (UINT16) (gPromptBlockWidth + gOptionBlockWidth);\r
+  } else {\r
+    return (UINT16) gPromptBlockWidth;\r
+  }\r
+}\r
+\r
+UINT16\r
+GetLineByWidth (\r
+  IN      CHAR16                      *InputString,\r
+  IN      UINT16                      LineWidth,\r
+  IN OUT  UINTN                       *Index,\r
+  OUT     CHAR16                      **OutputString\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Will copy LineWidth amount of a string in the OutputString buffer and return the\r
+  number of CHAR16 characters that were copied into the OutputString buffer.\r
+\r
+Arguments:\r
+  InputString - String description for this option.\r
+  LineWidth - Width of the desired string to extract in CHAR16 characters\r
+  Index - Where in InputString to start the copy process\r
+  OutputString - Buffer to copy the string into\r
+\r
+Returns:\r
+  Returns the number of CHAR16 characters that were copied into the OutputString buffer.\r
+\r
+\r
+--*/\r
+{\r
+  static BOOLEAN  Finished;\r
+  UINT16          Count;\r
+  UINT16          Count2;\r
+\r
+  if (Finished) {\r
+    Finished = FALSE;\r
+    return (UINT16) 0;\r
+  }\r
+\r
+  Count         = LineWidth;\r
+  Count2        = 0;\r
+\r
+  *OutputString = AllocateZeroPool (((UINTN) (LineWidth + 1) * 2));\r
+\r
+  //\r
+  // Ensure we have got a valid buffer\r
+  //\r
+  if (*OutputString != NULL) {\r
+\r
+    //\r
+    //NARROW_CHAR can not be printed in screen, so if a line only contain  the two CHARs: 'NARROW_CHAR + CHAR_CARRIAGE_RETURN' , it is a empty line  in Screen.\r
+    //To avoid displaying this  empty line in screen,  just skip  the two CHARs here.\r
+    //\r
+   if ((InputString[*Index] == NARROW_CHAR) && (InputString[*Index + 1] == CHAR_CARRIAGE_RETURN)) {\r
+     *Index = *Index + 2;\r
+   }\r
+\r
+    //\r
+    // Fast-forward the string and see if there is a carriage-return in the string\r
+    //\r
+    for (; (InputString[*Index + Count2] != CHAR_CARRIAGE_RETURN) && (Count2 != LineWidth); Count2++)\r
+      ;\r
+\r
+    //\r
+    // Copy the desired LineWidth of data to the output buffer.\r
+    // Also make sure that we don't copy more than the string.\r
+    // Also make sure that if there are linefeeds, we account for them.\r
+    //\r
+    if ((StrSize (&InputString[*Index]) <= ((UINTN) (LineWidth + 1) * 2)) &&\r
+        (StrSize (&InputString[*Index]) <= ((UINTN) (Count2 + 1) * 2))\r
+        ) {\r
+      //\r
+      // Convert to CHAR16 value and show that we are done with this operation\r
+      //\r
+      LineWidth = (UINT16) ((StrSize (&InputString[*Index]) - 2) / 2);\r
+      if (LineWidth != 0) {\r
+        Finished = TRUE;\r
+      }\r
+    } else {\r
+      if (Count2 == LineWidth) {\r
+        //\r
+        // Rewind the string from the maximum size until we see a space to break the line\r
+        //\r
+        for (; (InputString[*Index + LineWidth] != CHAR_SPACE) && (LineWidth != 0); LineWidth--)\r
+          ;\r
+        if (LineWidth == 0) {\r
+          LineWidth = Count;\r
+        }\r
+      } else {\r
+        LineWidth = Count2;\r
+      }\r
+    }\r
+\r
+    CopyMem (*OutputString, &InputString[*Index], LineWidth * 2);\r
+\r
+    //\r
+    // If currently pointing to a space, increment the index to the first non-space character\r
+    //\r
+    for (;\r
+         (InputString[*Index + LineWidth] == CHAR_SPACE) || (InputString[*Index + LineWidth] == CHAR_CARRIAGE_RETURN);\r
+         (*Index)++\r
+        )\r
+      ;\r
+    *Index = (UINT16) (*Index + LineWidth);\r
+    return LineWidth;\r
+  } else {\r
+    return (UINT16) 0;\r
+  }\r
+}\r
+\r
+STATIC\r
+VOID\r
+UpdateOptionSkipLines (\r
+  IN EFI_IFR_DATA_ARRAY           *PageData,\r
+  IN UI_MENU_OPTION               *MenuOption,\r
+  IN EFI_FILE_FORM_TAGS           *FileFormTagsHead,\r
+  IN CHAR16                       **OptionalString,\r
+  IN UINTN                        SkipValue\r
+  )\r
+{\r
+  UINTN   Index;\r
+  UINT16  Width;\r
+  UINTN   Row;\r
+  UINTN   OriginalRow;\r
+  CHAR16  *OutputString;\r
+  CHAR16  *OptionString;\r
+\r
+  Row           = 0;\r
+  OptionString  = *OptionalString;\r
+  OutputString  = NULL;\r
+\r
+  ProcessOptions (MenuOption, FALSE, FileFormTagsHead, PageData, &OptionString);\r
+\r
+  if (OptionString != NULL) {\r
+    Width               = (UINT16) gOptionBlockWidth;\r
+\r
+    OriginalRow         = Row;\r
+\r
+    for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {\r
+      //\r
+      // If there is more string to process print on the next row and increment the Skip value\r
+      //\r
+      if (StrLen (&OptionString[Index])) {\r
+        if (SkipValue == 0) {\r
+          Row++;\r
+          //\r
+          // Since the Number of lines for this menu entry may or may not be reflected accurately\r
+          // since the prompt might be 1 lines and option might be many, and vice versa, we need to do\r
+          // some testing to ensure we are keeping this in-sync.\r
+          //\r
+          // If the difference in rows is greater than or equal to the skip value, increase the skip value\r
+          //\r
+          if ((Row - OriginalRow) >= MenuOption->Skip) {\r
+            MenuOption->Skip++;\r
+          }\r
+        }\r
+      }\r
+\r
+      FreePool (OutputString);\r
+      if (SkipValue != 0) {\r
+        SkipValue--;\r
+      }\r
+    }\r
+\r
+    Row = OriginalRow;\r
+  }\r
+\r
+  *OptionalString = OptionString;\r
+}\r
+//\r
+// Search table for UiDisplayMenu()\r
+//\r
+SCAN_CODE_TO_SCREEN_OPERATION     gScanCodeToOperation[] = {\r
+  { SCAN_UP,        UiUp },\r
+  { SCAN_DOWN,      UiDown },\r
+  { SCAN_PAGE_UP,   UiPageUp },\r
+  { SCAN_PAGE_DOWN, UiPageDown},\r
+  { SCAN_ESC,       UiReset},\r
+  { SCAN_F2,        UiPrevious},\r
+  { SCAN_LEFT,      UiLeft },\r
+  { SCAN_RIGHT,     UiRight },\r
+  { SCAN_F9,        UiDefault},\r
+  { SCAN_F10,       UiSave }\r
+};\r
+\r
+SCREEN_OPERATION_T0_CONTROL_FLAG  gScreenOperationToControlFlag[] = {\r
+  { UiNoOperation,  CfUiNoOperation },\r
+  { UiDefault,      CfUiDefault },\r
+  { UiSelect,       CfUiSelect },\r
+  { UiUp,           CfUiUp},\r
+  { UiDown,         CfUiDown },\r
+  { UiLeft,         CfUiLeft },\r
+  { UiRight,        CfUiRight },\r
+  { UiReset,        CfUiReset },\r
+  { UiSave,         CfUiSave },\r
+  { UiPrevious,     CfUiPrevious },\r
+  { UiPageUp,       CfUiPageUp },\r
+  { UiPageDown,     CfUiPageDown }\r
+};\r
+\r
+UI_MENU_OPTION *\r
+UiDisplayMenu (\r
+  IN  BOOLEAN                      SubMenu,\r
+  IN  EFI_FILE_FORM_TAGS           *FileFormTagsHead,\r
+  OUT EFI_IFR_DATA_ARRAY           *PageData\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Display menu and wait for user to select one menu option, then return it.\r
+  If AutoBoot is enabled, then if user doesn't select any option,\r
+  after period of time, it will automatically return the first menu option.\r
+\r
+Arguments:\r
+  SubMenu          - Indicate is sub menu.\r
+  FileFormTagsHead - A pointer to the EFI_FILE_FORM_TAGS structure.\r
+  PageData         - A pointer to the EFI_IFR_DATA_ARRAY.\r
+\r
+Returns:\r
+  Return the pointer of the menu which selected,\r
+  otherwise return NULL.\r
+\r
+--*/\r
+{\r
+  INTN                        SkipValue;\r
+  INTN                        Difference;\r
+  INTN                        OldSkipValue;\r
+  UINTN                       Row;\r
+  UINTN                       Col;\r
+  UINTN                       Temp;\r
+  UINTN                       Temp2;\r
+  UINTN                       TopRow;\r
+  UINTN                       BottomRow;\r
+  UINTN                       OriginalRow;\r
+  UINTN                       Index;\r
+  UINTN                       DataAndTimeLineNumberPad;\r
+  UINT32                      Count;\r
+  INT16                       OriginalTimeOut;\r
+  UINT8                       *Location;\r
+  UINT16                      Width;\r
+  CHAR16                      *StringPtr;\r
+  CHAR16                      *OptionString;\r
+  CHAR16                      *OutputString;\r
+  CHAR16                      *FormattedString;\r
+  CHAR16                      YesResponse;\r
+  CHAR16                      NoResponse;\r
+  BOOLEAN                     NewLine;\r
+  BOOLEAN                     Repaint;\r
+  BOOLEAN                     SavedValue;\r
+  EFI_STATUS                  Status;\r
+  UI_MENU_LIST                *UiMenuList;\r
+  EFI_INPUT_KEY               Key;\r
+  LIST_ENTRY                  *Link;\r
+  LIST_ENTRY                  *NewPos;\r
+  LIST_ENTRY                  *TopOfScreen;\r
+  LIST_ENTRY                  *SavedListEntry;\r
+  UI_MENU_OPTION              *Selection;\r
+  UI_MENU_OPTION              *MenuOption;\r
+  UI_MENU_OPTION              *NextMenuOption;\r
+  UI_MENU_OPTION              *SavedMenuOption;\r
+  UI_MENU_OPTION              *PreviousMenuOption;\r
+  EFI_IFR_BINARY              *IfrBinary;\r
+  UI_CONTROL_FLAG             ControlFlag;\r
+  EFI_SCREEN_DESCRIPTOR       LocalScreen;\r
+  EFI_FILE_FORM_TAGS          *FileFormTags;\r
+  MENU_REFRESH_ENTRY          *MenuRefreshEntry;\r
+  MENU_REFRESH_ENTRY          *OldMenuRefreshEntry;\r
+  UI_SCREEN_OPERATION         ScreenOperation;\r
+  EFI_VARIABLE_DEFINITION     *VariableDefinition;\r
+  EFI_FORM_CALLBACK_PROTOCOL  *FormCallback;\r
+  EFI_HII_VARIABLE_PACK_LIST  *NvMapListHead;\r
+  EFI_HII_VARIABLE_PACK_LIST  *NvMapListNode;\r
+  VOID                        *NvMap;\r
+  UINTN                       NvMapSize;\r
+\r
+  CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));\r
+\r
+  VariableDefinition  = NULL;\r
+  Status              = EFI_SUCCESS;\r
+  FormattedString     = NULL;\r
+  OptionString        = NULL;\r
+  ScreenOperation     = UiNoOperation;\r
+  NewLine             = TRUE;\r
+  FormCallback        = NULL;\r
+  FileFormTags        = NULL;\r
+  OutputString        = NULL;\r
+  gUpArrow            = FALSE;\r
+  gDownArrow          = FALSE;\r
+  SkipValue           = 0;\r
+  OldSkipValue        = 0;\r
+  MenuRefreshEntry    = gMenuRefreshHead;\r
+  OldMenuRefreshEntry = gMenuRefreshHead;\r
+  NextMenuOption      = NULL;\r
+  PreviousMenuOption  = NULL;\r
+  SavedMenuOption     = NULL;\r
+  IfrBinary           = NULL;\r
+  NvMap               = NULL;\r
+  NvMapSize           = 0;\r
+\r
+  ZeroMem (&Key, sizeof (EFI_INPUT_KEY));\r
+\r
+  if (gClassOfVfr == EFI_FRONT_PAGE_SUBCLASS) {\r
+    TopRow  = LocalScreen.TopRow + FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;\r
+    Row     = LocalScreen.TopRow + FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;\r
+  } else {\r
+    TopRow  = LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;\r
+    Row     = LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;\r
+  }\r
+\r
+  if (SubMenu) {\r
+    Col = LocalScreen.LeftColumn;\r
+  } else {\r
+    Col = LocalScreen.LeftColumn + LEFT_SKIPPED_COLUMNS;\r
+  }\r
+\r
+  BottomRow   = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT - SCROLL_ARROW_HEIGHT - 1;\r
+\r
+  TopOfScreen = Menu.ForwardLink;\r
+  Repaint     = TRUE;\r
+  MenuOption  = NULL;\r
+\r
+  //\r
+  // Get user's selection\r
+  //\r
+  Selection = NULL;\r
+  NewPos    = Menu.ForwardLink;\r
+  gST->ConOut->EnableCursor (gST->ConOut, FALSE);\r
+\r
+  UpdateStatusBar (REFRESH_STATUS_BAR, (UINT8) 0, TRUE);\r
+\r
+  ControlFlag = CfInitialization;\r
+\r
+  while (TRUE) {\r
+    switch (ControlFlag) {\r
+    case CfInitialization:\r
+      ControlFlag = CfCheckSelection;\r
+      if (gExitRequired) {\r
+        ScreenOperation = UiReset;\r
+        ControlFlag     = CfScreenOperation;\r
+      } else if (gSaveRequired) {\r
+        ScreenOperation = UiSave;\r
+        ControlFlag     = CfScreenOperation;\r
+      } else if (IsListEmpty (&Menu)) {\r
+        ControlFlag = CfReadKey;\r
+      }\r
+      break;\r
+\r
+    case CfCheckSelection:\r
+      if (Selection != NULL) {\r
+        ControlFlag = CfExit;\r
+      } else {\r
+        ControlFlag = CfRepaint;\r
+      }\r
+\r
+      FileFormTags = FileFormTagsHead;\r
+      break;\r
+\r
+    case CfRepaint:\r
+      ControlFlag = CfRefreshHighLight;\r
+\r
+      if (Repaint) {\r
+        //\r
+        // Display menu\r
+        //\r
+        SavedMenuOption = MenuOption;\r
+        gDownArrow      = FALSE;\r
+        gUpArrow        = FALSE;\r
+        Row             = TopRow;\r
+\r
+        Temp            = SkipValue;\r
+        Temp2           = SkipValue;\r
+\r
+        ClearLines (\r
+          LocalScreen.LeftColumn,\r
+          LocalScreen.RightColumn,\r
+          TopRow - SCROLL_ARROW_HEIGHT,\r
+          BottomRow + SCROLL_ARROW_HEIGHT,\r
+          FIELD_TEXT | FIELD_BACKGROUND\r
+          );\r
+\r
+        while (gMenuRefreshHead != NULL) {\r
+          OldMenuRefreshEntry = gMenuRefreshHead->Next;\r
+\r
+          FreePool (gMenuRefreshHead);\r
+\r
+          gMenuRefreshHead = OldMenuRefreshEntry;\r
+        }\r
+\r
+        for (Link = TopOfScreen; Link != &Menu; Link = Link->ForwardLink) {\r
+          MenuOption          = CR (Link, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
+          MenuOption->Row     = Row;\r
+          OriginalRow         = Row;\r
+          MenuOption->Col     = Col;\r
+          MenuOption->OptCol  = gPromptBlockWidth + 1 + LocalScreen.LeftColumn;\r
+\r
+          if (SubMenu) {\r
+            if (MenuOption->ThisTag->GrayOut) {\r
+              gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_GRAYED | FIELD_BACKGROUND);\r
+            } else {\r
+              if (MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP) {\r
+                gST->ConOut->SetAttribute (gST->ConOut, SUBTITLE_TEXT | FIELD_BACKGROUND);\r
+              }\r
+            }\r
+\r
+            Width       = GetWidth (MenuOption->ThisTag, MenuOption->Handle);\r
+\r
+            OriginalRow = Row;\r
+\r
+            for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) {\r
+              if ((Temp == 0) && (Row <= BottomRow)) {\r
+                PrintStringAt (Col, Row, OutputString);\r
+              }\r
+              //\r
+              // If there is more string to process print on the next row and increment the Skip value\r
+              //\r
+              if (StrLen (&MenuOption->Description[Index])) {\r
+                if (Temp == 0) {\r
+                  Row++;\r
+                }\r
+              }\r
+\r
+              FreePool (OutputString);\r
+              if (Temp != 0) {\r
+                Temp--;\r
+              }\r
+            }\r
+\r
+            Temp  = 0;\r
+\r
+            Row   = OriginalRow;\r
+\r
+            gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
+            ProcessOptions (MenuOption, FALSE, FileFormTagsHead, PageData, &OptionString);\r
+\r
+            if (OptionString != NULL) {\r
+              if (MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP ||\r
+                  MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP\r
+                  ) {\r
+                //\r
+                // If leading spaces on OptionString - remove the spaces\r
+                //\r
+                for (Index = 0; OptionString[Index] == L' '; Index++) {\r
+                  MenuOption->OptCol++;\r
+                }\r
+\r
+                for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) {\r
+                  OptionString[Count] = OptionString[Index];\r
+                  Count++;\r
+                }\r
+\r
+                OptionString[Count] = CHAR_NULL;\r
+              }\r
+\r
+              //\r
+              // If this is a date or time op-code and is used to reflect an RTC, register the op-code\r
+              //\r
+                if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP ||\r
+                     MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP) &&\r
+                    (MenuOption->ThisTag->StorageStart >= FileFormTags->FormTags.Tags[0].NvDataSize)) {\r
+\r
+                if (gMenuRefreshHead == NULL) {\r
+                  MenuRefreshEntry = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY));\r
+                  ASSERT (MenuRefreshEntry != NULL);\r
+                  MenuRefreshEntry->MenuOption        = MenuOption;\r
+                  MenuRefreshEntry->FileFormTagsHead  = FileFormTagsHead;\r
+                  MenuRefreshEntry->CurrentColumn     = MenuOption->OptCol;\r
+                  MenuRefreshEntry->CurrentRow        = MenuOption->Row;\r
+                  MenuRefreshEntry->CurrentAttribute  = FIELD_TEXT | FIELD_BACKGROUND;\r
+                  gMenuRefreshHead                    = MenuRefreshEntry;\r
+                } else {\r
+                  //\r
+                  // Advance to the last entry\r
+                  //\r
+                  for (MenuRefreshEntry = gMenuRefreshHead;\r
+                       MenuRefreshEntry->Next != NULL;\r
+                       MenuRefreshEntry = MenuRefreshEntry->Next\r
+                      )\r
+                    ;\r
+                  MenuRefreshEntry->Next = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY));\r
+                  ASSERT (MenuRefreshEntry->Next != NULL);\r
+                  MenuRefreshEntry                    = MenuRefreshEntry->Next;\r
+                  MenuRefreshEntry->MenuOption        = MenuOption;\r
+                  MenuRefreshEntry->FileFormTagsHead  = FileFormTagsHead;\r
+                  MenuRefreshEntry->CurrentColumn     = MenuOption->OptCol;\r
+                  MenuRefreshEntry->CurrentRow        = MenuOption->Row;\r
+                  MenuRefreshEntry->CurrentAttribute  = FIELD_TEXT | FIELD_BACKGROUND;\r
+                }\r
+              }\r
+\r
+              Width       = (UINT16) gOptionBlockWidth;\r
+\r
+              OriginalRow = Row;\r
+\r
+              for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {\r
+                if ((Temp2 == 0) && (Row <= BottomRow)) {\r
+                  PrintStringAt (MenuOption->OptCol, Row, OutputString);\r
+                }\r
+                //\r
+                // If there is more string to process print on the next row and increment the Skip value\r
+                //\r
+                if (StrLen (&OptionString[Index])) {\r
+                  if (Temp2 == 0) {\r
+                    Row++;\r
+                    //\r
+                    // Since the Number of lines for this menu entry may or may not be reflected accurately\r
+                    // since the prompt might be 1 lines and option might be many, and vice versa, we need to do\r
+                    // some testing to ensure we are keeping this in-sync.\r
+                    //\r
+                    // If the difference in rows is greater than or equal to the skip value, increase the skip value\r
+                    //\r
+                    if ((Row - OriginalRow) >= MenuOption->Skip) {\r
+                      MenuOption->Skip++;\r
+                    }\r
+                  }\r
+                }\r
+\r
+                FreePool (OutputString);\r
+                if (Temp2 != 0) {\r
+                  Temp2--;\r
+                }\r
+              }\r
+\r
+              Temp2 = 0;\r
+              Row   = OriginalRow;\r
+            }\r
+            //\r
+            // If this is a text op with secondary text information\r
+            //\r
+            if ((MenuOption->ThisTag->Operand == EFI_IFR_TEXT_OP) && (MenuOption->ThisTag->TextTwo != 0)) {\r
+              StringPtr   = GetToken (MenuOption->ThisTag->TextTwo, MenuOption->Handle);\r
+\r
+              Width       = (UINT16) gOptionBlockWidth;\r
+\r
+              OriginalRow = Row;\r
+\r
+              for (Index = 0; GetLineByWidth (StringPtr, Width, &Index, &OutputString) != 0x0000;) {\r
+                if ((Temp == 0) && (Row <= BottomRow)) {\r
+                  PrintStringAt (MenuOption->OptCol, Row, OutputString);\r
+                }\r
+                //\r
+                // If there is more string to process print on the next row and increment the Skip value\r
+                //\r
+                if (StrLen (&StringPtr[Index])) {\r
+                  if (Temp2 == 0) {\r
+                    Row++;\r
+                    //\r
+                    // Since the Number of lines for this menu entry may or may not be reflected accurately\r
+                    // since the prompt might be 1 lines and option might be many, and vice versa, we need to do\r
+                    // some testing to ensure we are keeping this in-sync.\r
+                    //\r
+                    // If the difference in rows is greater than or equal to the skip value, increase the skip value\r
+                    //\r
+                    if ((Row - OriginalRow) >= MenuOption->Skip) {\r
+                      MenuOption->Skip++;\r
+                    }\r
+                  }\r
+                }\r
+\r
+                FreePool (OutputString);\r
+                if (Temp2 != 0) {\r
+                  Temp2--;\r
+                }\r
+              }\r
+\r
+              Row = OriginalRow;\r
+              FreePool (StringPtr);\r
+            }\r
+          } else {\r
+            //\r
+            // For now, assume left-justified 72 width max setup entries\r
+            //\r
+            PrintStringAt (Col, Row, MenuOption->Description);\r
+          }\r
+          //\r
+          // Tracker 6210 - need to handle the bottom of the display\r
+          //\r
+          if (MenuOption->Skip > 1) {\r
+            Row += MenuOption->Skip - SkipValue;\r
+            SkipValue = 0;\r
+          } else {\r
+            Row += MenuOption->Skip;\r
+          }\r
+\r
+          if (Row > BottomRow) {\r
+            if (!ValueIsScroll (FALSE, Link)) {\r
+              gDownArrow = TRUE;\r
+            }\r
+\r
+            Row = BottomRow + 1;\r
+            break;\r
+          }\r
+        }\r
+\r
+        if (!ValueIsScroll (TRUE, TopOfScreen)) {\r
+          gUpArrow = TRUE;\r
+        }\r
+\r
+        if (gUpArrow) {\r
+          gST->ConOut->SetAttribute (gST->ConOut, ARROW_TEXT | ARROW_BACKGROUND);\r
+          PrintAt (\r
+            LocalScreen.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1,\r
+            TopRow - SCROLL_ARROW_HEIGHT,\r
+            (CHAR16 *) L"%c",\r
+            ARROW_UP\r
+            );\r
+          gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
+        }\r
+\r
+        if (gDownArrow) {\r
+          gST->ConOut->SetAttribute (gST->ConOut, ARROW_TEXT | ARROW_BACKGROUND);\r
+          PrintAt (\r
+            LocalScreen.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1,\r
+            BottomRow + SCROLL_ARROW_HEIGHT,\r
+            (CHAR16 *) L"%c",\r
+            ARROW_DOWN\r
+            );\r
+          gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
+        }\r
+\r
+        if (SavedMenuOption != NULL) {\r
+          MenuOption = SavedMenuOption;\r
+        }\r
+      }\r
+      break;\r
+\r
+    case CfRefreshHighLight:\r
+      ControlFlag = CfUpdateHelpString;\r
+      //\r
+      // Repaint flag is normally reset when finish processing CfUpdateHelpString. Temporarily\r
+      // reset Repaint flag because we may break halfway and skip CfUpdateHelpString processing.\r
+      //\r
+      SavedValue  = Repaint;\r
+      Repaint     = FALSE;\r
+\r
+      if (NewPos != NULL) {\r
+        gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row);\r
+        if (SubMenu) {\r
+          if (gLastOpr && (gEntryNumber != -1)) {\r
+            MenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
+            if (gEntryNumber != MenuOption->EntryNumber) {\r
+              ScreenOperation = UiDown;\r
+              ControlFlag     = CfScreenOperation;\r
+              break;\r
+            } else {\r
+              gLastOpr = FALSE;\r
+            }\r
+          }\r
+\r
+          ProcessOptions (MenuOption, FALSE, FileFormTagsHead, PageData, &OptionString);\r
+          gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
+          if (OptionString != NULL) {\r
+            if (MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP ||\r
+                MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP\r
+                ) {\r
+              //\r
+              // If leading spaces on OptionString - remove the spaces\r
+              //\r
+              for (Index = 0; OptionString[Index] == L' '; Index++)\r
+                ;\r
+\r
+              for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) {\r
+                OptionString[Count] = OptionString[Index];\r
+                Count++;\r
+              }\r
+\r
+              OptionString[Count] = CHAR_NULL;\r
+            }\r
+\r
+            Width               = (UINT16) gOptionBlockWidth;\r
+\r
+            OriginalRow         = MenuOption->Row;\r
+\r
+            for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {\r
+              if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {\r
+                PrintStringAt (MenuOption->OptCol, MenuOption->Row, OutputString);\r
+              }\r
+              //\r
+              // If there is more string to process print on the next row and increment the Skip value\r
+              //\r
+              if (StrLen (&OptionString[Index])) {\r
+                MenuOption->Row++;\r
+              }\r
+\r
+              FreePool (OutputString);\r
+            }\r
+\r
+            MenuOption->Row = OriginalRow;\r
+          } else {\r
+            if (NewLine) {\r
+              if (MenuOption->ThisTag->GrayOut) {\r
+                gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_GRAYED | FIELD_BACKGROUND);\r
+              } else {\r
+                if (MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP) {\r
+                  gST->ConOut->SetAttribute (gST->ConOut, SUBTITLE_TEXT | FIELD_BACKGROUND);\r
+                }\r
+              }\r
+\r
+              OriginalRow = MenuOption->Row;\r
+              Width       = GetWidth (MenuOption->ThisTag, MenuOption->Handle);\r
+\r
+              for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) {\r
+                if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {\r
+                  PrintStringAt (Col, MenuOption->Row, OutputString);\r
+                }\r
+                //\r
+                // If there is more string to process print on the next row and increment the Skip value\r
+                //\r
+                if (StrLen (&MenuOption->Description[Index])) {\r
+                  MenuOption->Row++;\r
+                }\r
+\r
+                FreePool (OutputString);\r
+              }\r
+\r
+              MenuOption->Row = OriginalRow;\r
+              gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
+            }\r
+          }\r
+        } else {\r
+          gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
+          gST->ConOut->OutputString (gST->ConOut, MenuOption->Description);\r
+        }\r
+\r
+        MenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
+\r
+        if ((gPriorMenuEntry != 0) && (MenuOption->EntryNumber != gPriorMenuEntry) && (NewPos->ForwardLink != &Menu)) {\r
+          ScreenOperation = UiDown;\r
+          ControlFlag     = CfScreenOperation;\r
+          break;\r
+        } else {\r
+          gPriorMenuEntry = 0;\r
+        }\r
+        //\r
+        // This is only possible if we entered this page and the first menu option is\r
+        // a "non-menu" item.  In that case, force it UiDown\r
+        //\r
+        if (MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP || MenuOption->ThisTag->GrayOut) {\r
+          //\r
+          // If we previously hit an UP command and we are still sitting on a text operation\r
+          // we must continue going up\r
+          //\r
+          if (ScreenOperation == UiUp) {\r
+            ControlFlag = CfScreenOperation;\r
+            break;\r
+          } else {\r
+            ScreenOperation = UiDown;\r
+            ControlFlag     = CfScreenOperation;\r
+            break;\r
+          }\r
+        }\r
+        //\r
+        // Set reverse attribute\r
+        //\r
+        gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT | FIELD_BACKGROUND_HIGHLIGHT);\r
+        gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row);\r
+\r
+        //\r
+        // Assuming that we have a refresh linked-list created, lets annotate the\r
+        // appropriate entry that we are highlighting with its new attribute.  Just prior to this\r
+        // lets reset all of the entries' attribute so we do not get multiple highlights in he refresh\r
+        //\r
+        if (gMenuRefreshHead != NULL) {\r
+          for (MenuRefreshEntry = gMenuRefreshHead; MenuRefreshEntry != NULL; MenuRefreshEntry = MenuRefreshEntry->Next) {\r
+            MenuRefreshEntry->CurrentAttribute = FIELD_TEXT | FIELD_BACKGROUND;\r
+            if (MenuRefreshEntry->MenuOption == MenuOption) {\r
+              MenuRefreshEntry->CurrentAttribute = FIELD_TEXT_HIGHLIGHT | FIELD_BACKGROUND_HIGHLIGHT;\r
+            }\r
+          }\r
+        }\r
+\r
+        if (SubMenu) {\r
+          ProcessOptions (MenuOption, FALSE, FileFormTagsHead, PageData, &OptionString);\r
+          if (OptionString != NULL) {\r
+            if (MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP ||\r
+                MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP\r
+                ) {\r
+              //\r
+              // If leading spaces on OptionString - remove the spaces\r
+              //\r
+              for (Index = 0; OptionString[Index] == L' '; Index++)\r
+                ;\r
+\r
+              for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) {\r
+                OptionString[Count] = OptionString[Index];\r
+                Count++;\r
+              }\r
+\r
+              OptionString[Count] = CHAR_NULL;\r
+            }\r
+            Width               = (UINT16) gOptionBlockWidth;\r
+\r
+            OriginalRow         = MenuOption->Row;\r
+\r
+            for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {\r
+              if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {\r
+                PrintStringAt (MenuOption->OptCol, MenuOption->Row, OutputString);\r
+              }\r
+              //\r
+              // If there is more string to process print on the next row and increment the Skip value\r
+              //\r
+              if (StrLen (&OptionString[Index])) {\r
+                MenuOption->Row++;\r
+              }\r
+\r
+              FreePool (OutputString);\r
+            }\r
+\r
+            MenuOption->Row = OriginalRow;\r
+          } else {\r
+            if (NewLine) {\r
+              OriginalRow = MenuOption->Row;\r
+\r
+              Width       = GetWidth (MenuOption->ThisTag, MenuOption->Handle);\r
+\r
+              for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) {\r
+                if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {\r
+                  PrintStringAt (Col, MenuOption->Row, OutputString);\r
+                }\r
+                //\r
+                // If there is more string to process print on the next row and increment the Skip value\r
+                //\r
+                if (StrLen (&MenuOption->Description[Index])) {\r
+                  MenuOption->Row++;\r
+                }\r
+\r
+                FreePool (OutputString);\r
+              }\r
+\r
+              MenuOption->Row = OriginalRow;\r
+\r
+            }\r
+          }\r
+\r
+          if (((NewPos->ForwardLink != &Menu) && (ScreenOperation == UiDown)) ||\r
+              ((NewPos->BackLink != &Menu) && (ScreenOperation == UiUp)) ||\r
+              (ScreenOperation == UiNoOperation)\r
+              ) {\r
+            UpdateKeyHelp (MenuOption, FALSE);\r
+          }\r
+        } else {\r
+          gST->ConOut->OutputString (gST->ConOut, MenuOption->Description);\r
+        }\r
+        //\r
+        // Clear reverse attribute\r
+        //\r
+        gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
+      }\r
+      //\r
+      // Repaint flag will be used when process CfUpdateHelpString, so restore its value\r
+      // if we didn't break halfway when process CfRefreshHighLight.\r
+      //\r
+      Repaint = SavedValue;\r
+      break;\r
+\r
+    case CfUpdateHelpString:\r
+      ControlFlag = CfPrepareToReadKey;\r
+\r
+        if (SubMenu &&\r
+            (Repaint || NewLine ||\r
+             (MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) ||\r
+             (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) &&\r
+            !(gClassOfVfr == EFI_GENERAL_APPLICATION_SUBCLASS)) {\r
+        //\r
+        // Don't print anything if it is a NULL help token\r
+        //\r
+        if (MenuOption->ThisTag->Help == 0x00000000) {\r
+          StringPtr = (CHAR16 *) L"\0";\r
+        } else {\r
+          StringPtr = GetToken (MenuOption->ThisTag->Help, MenuOption->Handle);\r
+        }\r
+\r
+        ProcessHelpString (StringPtr, &FormattedString, BottomRow - TopRow);\r
+\r
+        gST->ConOut->SetAttribute (gST->ConOut, HELP_TEXT | FIELD_BACKGROUND);\r
+\r
+        for (Index = 0; Index < BottomRow - TopRow; Index++) {\r
+          //\r
+          // Pad String with spaces to simulate a clearing of the previous line\r
+          //\r
+          for (; GetStringWidth (&FormattedString[Index * gHelpBlockWidth * 2]) / 2 < gHelpBlockWidth;) {\r
+            StrCat (&FormattedString[Index * gHelpBlockWidth * 2], (CHAR16 *) L" ");\r
+          }\r
+\r
+          PrintStringAt (\r
+            LocalScreen.RightColumn - gHelpBlockWidth,\r
+            Index + TopRow,\r
+            &FormattedString[Index * gHelpBlockWidth * 2]\r
+            );\r
+        }\r
+      }\r
+      //\r
+      // Reset this flag every time we finish using it.\r
+      //\r
+      Repaint = FALSE;\r
+      NewLine = FALSE;\r
+      break;\r
+\r
+    case CfPrepareToReadKey:\r
+      ControlFlag = CfReadKey;\r
+\r
+      for (Index = 0; Index < MenuOption->IfrNumber; Index++) {\r
+        FileFormTags = FileFormTags->NextFile;\r
+      }\r
+\r
+      ScreenOperation = UiNoOperation;\r
+\r
+      Status = gBS->HandleProtocol (\r
+                      (VOID *) (UINTN) FileFormTags->FormTags.Tags[0].CallbackHandle,\r
+                      &gEfiFormCallbackProtocolGuid,\r
+                      (VOID **) &FormCallback\r
+                      );\r
+\r
+      break;\r
+\r
+    case CfReadKey:\r
+      ControlFlag     = CfScreenOperation;\r
+\r
+      OriginalTimeOut = FrontPageTimeOutValue;\r
+      do {\r
+        if (FrontPageTimeOutValue >= 0 && (gClassOfVfr == EFI_FRONT_PAGE_SUBCLASS) && FrontPageTimeOutValue != (INT16) -1) {\r
+          //\r
+          // Remember that if set to 0, must immediately boot an option\r
+          //\r
+          if (FrontPageTimeOutValue == 0) {\r
+            FrontPageTimeOutValue = 0xFFFF;\r
+            Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
+            if (EFI_ERROR (Status)) {\r
+              Status = EFI_TIMEOUT;\r
+            }\r
+            break;\r
+          }\r
+\r
+          Status = UiWaitForSingleEvent (gST->ConIn->WaitForKey, ONE_SECOND);\r
+          if (Status == EFI_TIMEOUT) {\r
+            EFI_IFR_DATA_ENTRY *DataEntry;\r
+\r
+            DataEntry = (EFI_IFR_DATA_ENTRY *) (PageData + 1);\r
+\r
+            PageData->EntryCount  = 1;\r
+            Count                 = (UINT32) ((OriginalTimeOut - FrontPageTimeOutValue) * 100 / OriginalTimeOut);\r
+            CopyMem (&DataEntry->Data, &Count, sizeof (UINT32));\r
+\r
+            if ((FormCallback != NULL) && (FormCallback->Callback != NULL)) {\r
+              FormCallback->Callback (\r
+                              FormCallback,\r
+                              0xFFFF,\r
+                              (EFI_IFR_DATA_ARRAY *) PageData,\r
+                              NULL\r
+                              );\r
+            }\r
+            //\r
+            // Count down 1 second\r
+            //\r
+            FrontPageTimeOutValue--;\r
+\r
+          } else {\r
+            ASSERT (!EFI_ERROR (Status));\r
+            PageData->EntryCount = 0;\r
+            if ((FormCallback != NULL) && (FormCallback->Callback != NULL)) {\r
+              FormCallback->Callback (\r
+                              FormCallback,\r
+                              0xFFFE,\r
+                              (EFI_IFR_DATA_ARRAY *) PageData,\r
+                              NULL\r
+                              );\r
+            }\r
+\r
+            FrontPageTimeOutValue = 0xFFFF;\r
+          }\r
+        } else {\r
+          //\r
+          // Wait for user's selection, no auto boot\r
+          //\r
+          Status = UiWaitForSingleEvent (gST->ConIn->WaitForKey, 0);\r
+        }\r
+      } while (Status == EFI_TIMEOUT);\r
+\r
+      if (gFirstIn) {\r
+        gFirstIn = FALSE;\r
+        gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
+        DisableQuietBoot ();\r
+      }\r
+\r
+      if (Status == EFI_TIMEOUT) {\r
+        Key.UnicodeChar = CHAR_CARRIAGE_RETURN;\r
+      } else {\r
+        Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
+        //\r
+        // if we encounter error, continue to read another key in.\r
+        //\r
+        if (EFI_ERROR (Status)) {\r
+          ControlFlag = CfReadKey;\r
+          continue;\r
+        }\r
+      }\r
+\r
+      switch (Key.UnicodeChar) {\r
+      case CHAR_CARRIAGE_RETURN:\r
+        Selection       = MenuOption;\r
+        ScreenOperation = UiSelect;\r
+        gDirection      = 0;\r
+        break;\r
+\r
+      //\r
+      // We will push the adjustment of these numeric values directly to the input handler\r
+      //\r
+      case '+':\r
+      case '-':\r
+        if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) {\r
+\r
+          if (Key.UnicodeChar == '+') {\r
+            gDirection = SCAN_RIGHT;\r
+          } else {\r
+            gDirection = SCAN_LEFT;\r
+          }\r
+\r
+          Status = ProcessOptions (MenuOption, TRUE, FileFormTagsHead, NULL, &OptionString);\r
+        }\r
+        break;\r
+\r
+      case '^':\r
+        ScreenOperation = UiUp;\r
+        break;\r
+\r
+      case 'V':\r
+      case 'v':\r
+        ScreenOperation = UiDown;\r
+        break;\r
+\r
+      case ' ':\r
+        if (gClassOfVfr != EFI_FRONT_PAGE_SUBCLASS) {\r
+          if (SubMenu) {\r
+            if (MenuOption->ThisTag->Operand == EFI_IFR_CHECKBOX_OP && !(MenuOption->ThisTag->GrayOut)) {\r
+              gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row);\r
+              gST->ConOut->OutputString (gST->ConOut, MenuOption->Description);\r
+              Selection       = MenuOption;\r
+              ScreenOperation = UiSelect;\r
+            }\r
+          }\r
+        }\r
+        break;\r
+\r
+      case CHAR_NULL:\r
+        if (((Key.ScanCode == SCAN_F1) && ((gFunctionKeySetting & FUNCTION_ONE) != FUNCTION_ONE)) ||\r
+            ((Key.ScanCode == SCAN_F2) && ((gFunctionKeySetting & FUNCTION_TWO) != FUNCTION_TWO)) ||\r
+            ((Key.ScanCode == SCAN_F9) && ((gFunctionKeySetting & FUNCTION_NINE) != FUNCTION_NINE)) ||\r
+            ((Key.ScanCode == SCAN_F10) && ((gFunctionKeySetting & FUNCTION_TEN) != FUNCTION_TEN))\r
+            ) {\r
+          //\r
+          // If the function key has been disabled, just ignore the key.\r
+          //\r
+        } else {\r
+          for (Index = 0; Index < sizeof (gScanCodeToOperation) / sizeof (gScanCodeToOperation[0]); Index++) {\r
+            if (Key.ScanCode == gScanCodeToOperation[Index].ScanCode) {\r
+              if ((Key.ScanCode == SCAN_F9) || (Key.ScanCode == SCAN_F10)) {\r
+                if (SubMenu) {\r
+                  ScreenOperation = gScanCodeToOperation[Index].ScreenOperation;\r
+                }\r
+              } else {\r
+                ScreenOperation = gScanCodeToOperation[Index].ScreenOperation;\r
+              }\r
+            }\r
+          }\r
+        }\r
+        break;\r
+      }\r
+      break;\r
+\r
+    case CfScreenOperation:\r
+      IfrBinary = gBinaryDataHead;\r
+\r
+      //\r
+      // Advance to the Ifr we are using\r
+      //\r
+      for (Index = 0; Index < gActiveIfr; Index++) {\r
+        IfrBinary = IfrBinary->Next;\r
+      }\r
+\r
+      if (ScreenOperation != UiPrevious && ScreenOperation != UiReset) {\r
+        //\r
+        // If the screen has no menu items, and the user didn't select UiPrevious, or UiReset\r
+        // ignore the selection and go back to reading keys.\r
+        //\r
+        if (IsListEmpty (&Menu)) {\r
+          ControlFlag = CfReadKey;\r
+          break;\r
+        }\r
+        //\r
+        // if there is nothing logical to place a cursor on, just move on to wait for a key.\r
+        //\r
+        for (Link = Menu.ForwardLink; Link != &Menu; Link = Link->ForwardLink) {\r
+          NextMenuOption = CR (Link, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
+          if (!(NextMenuOption->ThisTag->GrayOut) && (NextMenuOption->ThisTag->Operand != EFI_IFR_SUBTITLE_OP)) {\r
+            break;\r
+          }\r
+        }\r
+\r
+        if (Link == &Menu) {\r
+          ControlFlag = CfPrepareToReadKey;\r
+          break;\r
+        }\r
+      }\r
+\r
+      for (Index = 0;\r
+           Index < sizeof (gScreenOperationToControlFlag) / sizeof (gScreenOperationToControlFlag[0]);\r
+           Index++\r
+          ) {\r
+        if (ScreenOperation == gScreenOperationToControlFlag[Index].ScreenOperation) {\r
+          ControlFlag = gScreenOperationToControlFlag[Index].ControlFlag;\r
+        }\r
+      }\r
+\r
+      break;\r
+\r
+    case CfUiPrevious:\r
+      ControlFlag = CfCheckSelection;\r
+      //\r
+      // Check for tags that might have LATE_CHECK enabled.  If they do, we can't switch pages or save NV data.\r
+      //\r
+      if (MenuOption != NULL) {\r
+        if (!SelectionsAreValid (MenuOption, FileFormTagsHead)) {\r
+          Selection = NULL;\r
+          Repaint   = TRUE;\r
+          break;\r
+        }\r
+      }\r
+\r
+      if (IsListEmpty (&gMenuList)) {\r
+        Selection = NULL;\r
+        if (IsListEmpty (&Menu)) {\r
+          ControlFlag = CfReadKey;\r
+        }\r
+        break;\r
+      }\r
+\r
+      gLastOpr = TRUE;\r
+\r
+      while (gMenuRefreshHead != NULL) {\r
+        OldMenuRefreshEntry = gMenuRefreshHead->Next;\r
+\r
+        FreePool (gMenuRefreshHead);\r
+\r
+        gMenuRefreshHead = OldMenuRefreshEntry;\r
+      }\r
+      //\r
+      // Remove the Cached page entry, free and init the menus, flag Selection as jumping to previous page and a valid Tag\r
+      //\r
+      if (SubMenu) {\r
+        UiRemoveMenuListEntry (MenuOption, &Selection);\r
+        Selection->Previous = TRUE;\r
+        UiFreeMenu ();\r
+        UiInitMenu ();\r
+      }\r
+\r
+      gActiveIfr = Selection->IfrNumber;\r
+      return Selection;\r
+\r
+    case CfUiSelect:\r
+      ControlFlag = CfCheckSelection;\r
+\r
+      ExtractRequestedNvMap (FileFormTags, MenuOption->ThisTag->VariableNumber, &VariableDefinition);\r
+\r
+      if (SubMenu) {\r
+        if ((MenuOption->ThisTag->Operand == EFI_IFR_TEXT_OP &&\r
+            !(MenuOption->ThisTag->Flags & EFI_IFR_FLAG_INTERACTIVE)) ||\r
+            (MenuOption->ThisTag->GrayOut) ||\r
+            (MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) ||\r
+            (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) {\r
+            Selection = NULL;\r
+            break;\r
+          }\r
+\r
+        NewLine = TRUE;\r
+        UpdateKeyHelp (MenuOption, TRUE);\r
+        Status = ProcessOptions (MenuOption, TRUE, FileFormTagsHead, PageData, &OptionString);\r
+\r
+        if (EFI_ERROR (Status)) {\r
+          Selection = NULL;\r
+          Repaint   = TRUE;\r
+          break;\r
+        }\r
+\r
+        if (OptionString != NULL) {\r
+          PrintStringAt (LocalScreen.LeftColumn + gPromptBlockWidth + 1, MenuOption->Row, OptionString);\r
+        }\r
+\r
+        if (MenuOption->ThisTag->Flags & EFI_IFR_FLAG_INTERACTIVE) {\r
+          Selection = MenuOption;\r
+        }\r
+\r
+        if (Selection == NULL) {\r
+          break;\r
+        }\r
+\r
+        Location = (UINT8 *) &PageData->EntryCount;\r
+\r
+        //\r
+        // If not a goto, dump single piece of data, otherwise dump everything\r
+        //\r
+        if (Selection->ThisTag->Operand == EFI_IFR_REF_OP) {\r
+          //\r
+          // Check for tags that might have LATE_CHECK enabled.  If they do, we can't switch pages or save NV data.\r
+          //\r
+          if (!SelectionsAreValid (MenuOption, FileFormTagsHead)) {\r
+            Selection = NULL;\r
+            Repaint   = TRUE;\r
+            break;\r
+          }\r
+\r
+          UiAddMenuListEntry (Selection);\r
+          gPriorMenuEntry = 0;\r
+\r
+          //\r
+          // Now that we added a menu entry specific to a goto, we can always go back when someone hits the UiPrevious\r
+          //\r
+          UiMenuList                    = CR (gMenuList.ForwardLink, UI_MENU_LIST, MenuLink, UI_MENU_LIST_SIGNATURE);\r
+          UiMenuList->FormerEntryNumber = MenuOption->EntryNumber;\r
+\r
+          gLastOpr                      = FALSE;\r
+\r
+          //\r
+          // Rewind to the beginning of the menu\r
+          //\r
+          for (; NewPos->BackLink != &Menu; NewPos = NewPos->BackLink)\r
+            ;\r
+\r
+          //\r
+          // Get Total Count of Menu entries\r
+          //\r
+          for (Count = 1; NewPos->ForwardLink != &Menu; NewPos = NewPos->ForwardLink) {\r
+            Count++;\r
+          }\r
+          //\r
+          // Rewind to the beginning of the menu\r
+          //\r
+          for (; NewPos->BackLink != &Menu; NewPos = NewPos->BackLink)\r
+            ;\r
+\r
+          //\r
+          // Copy the number of entries being described to the PageData location\r
+          //\r
+          CopyMem (&Location[0], &Count, sizeof (UINT32));\r
+\r
+          for (Index = 4; NewPos->ForwardLink != &Menu; Index = Index + MenuOption->ThisTag->StorageWidth + 2) {\r
+\r
+            MenuOption          = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
+            Location[Index]     = MenuOption->ThisTag->Operand;\r
+            Location[Index + 1] = (UINT8) (MenuOption->ThisTag->StorageWidth + 4);\r
+            CopyMem (\r
+              &Location[Index + 4],\r
+              &VariableDefinition->NvRamMap[MenuOption->ThisTag->StorageStart],\r
+              MenuOption->ThisTag->StorageWidth\r
+              );\r
+            NewPos = NewPos->ForwardLink;\r
+          }\r
+        } else {\r
+\r
+          gPriorMenuEntry = MenuOption->EntryNumber;\r
+\r
+          Count           = 1;\r
+\r
+          //\r
+          // Copy the number of entries being described to the PageData location\r
+          //\r
+          CopyMem (&Location[0], &Count, sizeof (UINT32));\r
+\r
+          //\r
+          // Start at PageData[4] since the EntryCount is a UINT32\r
+          //\r
+          Index = 4;\r
+\r
+          //\r
+          // Copy data to destination\r
+          //\r
+          Location[Index]     = MenuOption->ThisTag->Operand;\r
+          Location[Index + 1] = (UINT8) (MenuOption->ThisTag->StorageWidth + 4);\r
+          CopyMem (\r
+            &Location[Index + 4],\r
+            &VariableDefinition->NvRamMap[MenuOption->ThisTag->StorageStart],\r
+            MenuOption->ThisTag->StorageWidth\r
+            );\r
+        }\r
+      }\r
+      break;\r
+\r
+    case CfUiReset:\r
+      ControlFlag = CfCheckSelection;\r
+      gLastOpr    = FALSE;\r
+      if (gClassOfVfr == EFI_FRONT_PAGE_SUBCLASS) {\r
+        break;\r
+      }\r
+      //\r
+      // If NV flag is up, prompt user\r
+      //\r
+      if (gNvUpdateRequired) {\r
+        Status      = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
+\r
+        YesResponse = gYesResponse[0];\r
+        NoResponse  = gNoResponse[0];\r
+\r
+        do {\r
+          CreateDialog (3, TRUE, 0, NULL, &Key, gEmptyString, gAreYouSure, gEmptyString);\r
+        } while\r
+        (\r
+          (Key.ScanCode != SCAN_ESC) &&\r
+          ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (NoResponse | UPPER_LOWER_CASE_OFFSET)) &&\r
+          ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (YesResponse | UPPER_LOWER_CASE_OFFSET))\r
+        );\r
+\r
+        //\r
+        // If the user hits the YesResponse key\r
+        //\r
+        if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (YesResponse | UPPER_LOWER_CASE_OFFSET)) {\r
+        } else {\r
+          Repaint = TRUE;\r
+          NewLine = TRUE;\r
+          break;\r
+        }\r
+      }\r
+      //\r
+      // Check for tags that might have LATE_CHECK enabled.  If they do, we can't switch pages or save NV data.\r
+      //\r
+      if (MenuOption != NULL) {\r
+        if (!SelectionsAreValid (MenuOption, FileFormTagsHead)) {\r
+          Selection = NULL;\r
+          Repaint   = TRUE;\r
+          NewLine   = TRUE;\r
+          break;\r
+        }\r
+      }\r
+\r
+      gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
+      gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
+\r
+      if (SubMenu) {\r
+        UiFreeMenuList ();\r
+        gST->ConOut->ClearScreen (gST->ConOut);\r
+        return NULL;\r
+      }\r
+\r
+      UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->Flags, FALSE);\r
+      UpdateStatusBar (NV_UPDATE_REQUIRED, MenuOption->ThisTag->Flags, FALSE);\r
+\r
+      if (IfrBinary->UnRegisterOnExit) {\r
+        Hii->RemovePack (Hii, MenuOption->Handle);\r
+      }\r
+\r
+      UiFreeMenu ();\r
+\r
+      //\r
+      // Clean up the allocated data buffers\r
+      //\r
+      FreeData (FileFormTagsHead, FormattedString, OptionString);\r
+\r
+      gST->ConOut->ClearScreen (gST->ConOut);\r
+      return NULL;\r
+\r
+    case CfUiLeft:\r
+      ControlFlag = CfCheckSelection;\r
+      if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) {\r
+        if (MenuOption->Skip == 1) {\r
+          //\r
+          // In the tail of the Date/Time op-code set, go left.\r
+          //\r
+          NewPos = NewPos->BackLink;\r
+        } else {\r
+          //\r
+          // In the middle of the Data/Time op-code set, go left.\r
+          //\r
+          NextMenuOption = CR (NewPos->ForwardLink, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
+          if (NextMenuOption->Skip == 1) {\r
+            NewPos = NewPos->BackLink;\r
+          }\r
+        }\r
+      }\r
+      break;\r
+\r
+    case CfUiRight:\r
+      ControlFlag = CfCheckSelection;\r
+      if ((MenuOption->Skip == 0) &&\r
+          ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP))\r
+          ) {\r
+        //\r
+        // We are in the head or middle of the Date/Time op-code set, advance right.\r
+        //\r
+        NewPos = NewPos->ForwardLink;\r
+      }\r
+      break;\r
+\r
+    case CfUiUp:\r
+      ControlFlag = CfCheckSelection;\r
+\r
+      if (NewPos->BackLink != &Menu) {\r
+        NewLine = TRUE;\r
+        //\r
+        // Adjust Date/Time position before we advance forward.\r
+        //\r
+        AdjustDateAndTimePosition (TRUE, &NewPos);\r
+\r
+        //\r
+        // Caution that we have already rewind to the top, don't go backward in this situation.\r
+        //\r
+        if (NewPos->BackLink != &Menu) {\r
+          NewPos = NewPos->BackLink;\r
+        }\r
+\r
+        PreviousMenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
+\r
+        //\r
+        // Since the behavior of hitting the up arrow on a Date/Time op-code is intended\r
+        // to be one that back to the previous set of op-codes, we need to advance to the sencond\r
+        // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate\r
+        // checking can be done.\r
+        //\r
+        DataAndTimeLineNumberPad = AdjustDateAndTimePosition (TRUE, &NewPos);\r
+\r
+        if (SubMenu) {\r
+          //\r
+          // If the previous MenuOption contains a display-only op-code, skip to the next one\r
+          //\r
+          if (PreviousMenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP || PreviousMenuOption->ThisTag->GrayOut) {\r
+            //\r
+            // This is ok as long as not at the end of the list\r
+            //\r
+            if (NewPos->BackLink == &Menu) {\r
+              //\r
+              // If we are at the start of the list, then this list must start with a display only\r
+              // piece of data, so do not allow the backward motion\r
+              //\r
+              ScreenOperation = UiDown;\r
+\r
+              if (PreviousMenuOption->Row <= TopRow) {\r
+                if (TopOfScreen->BackLink != &Menu) {\r
+                  TopOfScreen = TopOfScreen->BackLink;\r
+                  Repaint     = TRUE;\r
+                }\r
+              }\r
+\r
+              UpdateStatusBar (INPUT_ERROR, PreviousMenuOption->ThisTag->Flags, FALSE);\r
+              break;\r
+            }\r
+          }\r
+        }\r
+        //\r
+        // Check the previous menu entry to see if it was a zero-length advance.  If it was,\r
+        // don't worry about a redraw.\r
+        //\r
+        if ((MenuOption->Row - PreviousMenuOption->Skip - DataAndTimeLineNumberPad < TopRow) ||\r
+            (PreviousMenuOption->Skip > MenuOption->Row)\r
+            ) {\r
+          do {\r
+            if (TopOfScreen->BackLink == &Menu) {\r
+              break;\r
+            }\r
+\r
+            Repaint = TRUE;\r
+\r
+            //\r
+            // Is the current top of screen a zero-advance op-code?\r
+            // If so, keep moving forward till we hit a >0 advance op-code\r
+            //\r
+            SavedMenuOption = CR (TopOfScreen->BackLink, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
+            TopOfScreen     = TopOfScreen->BackLink;\r
+          } while (SavedMenuOption->Skip == 0);\r
+          //\r
+          // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.\r
+          //\r
+          AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
+        }\r
+\r
+        UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->Flags, FALSE);\r
+      } else {\r
+        if (SubMenu) {\r
+          SavedMenuOption = MenuOption;\r
+          MenuOption      = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
+          if (MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP || MenuOption->ThisTag->GrayOut) {\r
+            //\r
+            // If we are at the end of the list and sitting on a text op, we need to more forward\r
+            //\r
+            ScreenOperation = UiDown;\r
+            ControlFlag     = CfScreenOperation;\r
+            break;\r
+          }\r
+\r
+          MenuOption = SavedMenuOption;\r
+        }\r
+      }\r
+      break;\r
+\r
+    case CfUiPageUp:\r
+      ControlFlag     = CfCheckSelection;\r
+\r
+      SavedListEntry  = NewPos;\r
+      Link            = TopOfScreen;\r
+      for (Index = BottomRow; Index >= TopRow + 1; Index -= MenuOption->Skip) {\r
+        if (Link->BackLink == &Menu) {\r
+          TopOfScreen = Link;\r
+          Link        = SavedListEntry;\r
+          MenuOption  = CR (Link, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
+          break;\r
+        }\r
+\r
+        NewLine         = TRUE;\r
+        Repaint         = TRUE;\r
+        Link            = Link->BackLink;\r
+        MenuOption      = CR (Link, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
+        TopOfScreen     = Link;\r
+        SavedListEntry  = Link;\r
+      }\r
+\r
+      NewPos = Link;\r
+\r
+      //\r
+      // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.\r
+      // Don't do this when we are already in the first page.\r
+      //\r
+      if (Repaint) {\r
+        AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
+        AdjustDateAndTimePosition (TRUE, &NewPos);\r
+        MenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
+      }\r
+      break;\r
+\r
+    case CfUiPageDown:\r
+      ControlFlag     = CfCheckSelection;\r
+\r
+      SavedListEntry  = NewPos;\r
+      Link            = TopOfScreen;\r
+      NewPos          = TopOfScreen;\r
+      for (Index = TopRow; Index <= BottomRow - 1; Index += MenuOption->Skip) {\r
+        if (NewPos->ForwardLink == &Menu) {\r
+          NewPos      = SavedListEntry;\r
+          MenuOption  = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
+          Link        = TopOfScreen;\r
+          NewLine     = FALSE;\r
+          Repaint     = FALSE;\r
+          break;\r
+        }\r
+\r
+        NewLine     = TRUE;\r
+        Repaint     = TRUE;\r
+        MenuOption  = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
+        NewPos      = NewPos->ForwardLink;\r
+        Link        = NewPos;\r
+      }\r
+\r
+      TopOfScreen = Link;\r
+\r
+      //\r
+      // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.\r
+      // Don't do this when we are already in the last page.\r
+      //\r
+      if (Repaint) {\r
+        AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
+        AdjustDateAndTimePosition (TRUE, &NewPos);\r
+        MenuOption = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
+      }\r
+      break;\r
+\r
+    case CfUiDown:\r
+      ControlFlag = CfCheckSelection;\r
+      //\r
+      // Since the behavior of hitting the down arrow on a Date/Time op-code is intended\r
+      // to be one that progresses to the next set of op-codes, we need to advance to the last\r
+      // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate\r
+      // checking can be done.  The only other logic we need to introduce is that if a Date/Time\r
+      // op-code is the last entry in the menu, we need to rewind back to the first op-code of\r
+      // the Date/Time op-code.\r
+      //\r
+      DataAndTimeLineNumberPad = AdjustDateAndTimePosition (FALSE, &NewPos);\r
+\r
+      if (NewPos->ForwardLink != &Menu) {\r
+        NewLine         = TRUE;\r
+        NewPos          = NewPos->ForwardLink;\r
+        NextMenuOption  = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
+\r
+        if (SubMenu) {\r
+          //\r
+          // If the next MenuOption contains a display-only op-code, skip to the next one\r
+          // Also if the next MenuOption is date or time,\r
+          //\r
+          if (NextMenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP || NextMenuOption->ThisTag->GrayOut) {\r
+            //\r
+            // This is ok as long as not at the end of the list\r
+            //\r
+            if (NewPos == &Menu) {\r
+              //\r
+              // If we are at the end of the list, then this list must end with a display only\r
+              // piece of data, so do not allow the forward motion\r
+              //\r
+              UpdateStatusBar (INPUT_ERROR, NextMenuOption->ThisTag->Flags, FALSE);\r
+              NewPos          = NewPos->BackLink;\r
+              ScreenOperation = UiUp;\r
+              break;\r
+            }\r
+          }\r
+        }\r
+        //\r
+        // An option might be multi-line, so we need to reflect that data in the overall skip value\r
+        //\r
+        UpdateOptionSkipLines (PageData, NextMenuOption, FileFormTagsHead, &OptionString, SkipValue);\r
+\r
+        if (NextMenuOption->Skip > 1) {\r
+          Temp = MenuOption->Row + MenuOption->Skip + NextMenuOption->Skip - 1;\r
+        } else {\r
+          Temp = MenuOption->Row + MenuOption->Skip + DataAndTimeLineNumberPad;\r
+        }\r
+        //\r
+        // If we are going to scroll\r
+        //\r
+        if (Temp > BottomRow) {\r
+          do {\r
+            //\r
+            // Is the current top of screen a zero-advance op-code?\r
+            // If so, keep moving forward till we hit a >0 advance op-code\r
+            //\r
+            SavedMenuOption = CR (TopOfScreen, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
+\r
+            //\r
+            // If bottom op-code is more than one line or top op-code is more than one line\r
+            //\r
+            if ((NextMenuOption->Skip > 1) || (MenuOption->Skip > 1)) {\r
+              //\r
+              // Is the bottom op-code greater than or equal in size to the top op-code?\r
+              //\r
+              if ((Temp - BottomRow) >= (SavedMenuOption->Skip - OldSkipValue)) {\r
+                //\r
+                // Skip the top op-code\r
+                //\r
+                TopOfScreen     = TopOfScreen->ForwardLink;\r
+                Difference      = (Temp - BottomRow) - (SavedMenuOption->Skip - OldSkipValue);\r
+\r
+                OldSkipValue    = Difference;\r
+\r
+                SavedMenuOption = CR (TopOfScreen, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
+\r
+                //\r
+                // If we have a remainder, skip that many more op-codes until we drain the remainder\r
+                //\r
+                for (;\r
+                     Difference >= (INTN) SavedMenuOption->Skip;\r
+                     Difference = Difference - (INTN) SavedMenuOption->Skip\r
+                    ) {\r
+                  //\r
+                  // Since the Difference is greater than or equal to this op-code's skip value, skip it\r
+                  //\r
+                  TopOfScreen     = TopOfScreen->ForwardLink;\r
+                  SavedMenuOption = CR (TopOfScreen, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
+                  if (Difference < (INTN) SavedMenuOption->Skip) {\r
+                    Difference = SavedMenuOption->Skip - Difference - 1;\r
+                    break;\r
+                  } else {\r
+                    if (Difference == (INTN) SavedMenuOption->Skip) {\r
+                      TopOfScreen     = TopOfScreen->ForwardLink;\r
+                      SavedMenuOption = CR (TopOfScreen, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
+                      Difference      = SavedMenuOption->Skip - Difference;\r
+                      break;\r
+                    }\r
+                  }\r
+                }\r
+                //\r
+                // Since we will act on this op-code in the next routine, and increment the\r
+                // SkipValue, set the skips to one less than what is required.\r
+                //\r
+                SkipValue = Difference - 1;\r
+\r
+              } else {\r
+                //\r
+                // Since we will act on this op-code in the next routine, and increment the\r
+                // SkipValue, set the skips to one less than what is required.\r
+                //\r
+                SkipValue = OldSkipValue + (Temp - BottomRow) - 1;\r
+              }\r
+            } else {\r
+              if ((OldSkipValue + 1) == (INTN) SavedMenuOption->Skip) {\r
+                TopOfScreen = TopOfScreen->ForwardLink;\r
+                break;\r
+              } else {\r
+                SkipValue = OldSkipValue;\r
+              }\r
+            }\r
+            //\r
+            // If the op-code at the top of the screen is more than one line, let's not skip it yet\r
+            // Let's set a skip flag to smoothly scroll the top of the screen.\r
+            //\r
+            if (SavedMenuOption->Skip > 1) {\r
+              if (SavedMenuOption == NextMenuOption) {\r
+                SkipValue = 0;\r
+              } else {\r
+                SkipValue++;\r
+              }\r
+            } else {\r
+              SkipValue   = 0;\r
+              TopOfScreen = TopOfScreen->ForwardLink;\r
+            }\r
+          } while (SavedMenuOption->Skip == 0);\r
+\r
+          Repaint       = TRUE;\r
+          OldSkipValue  = SkipValue;\r
+        }\r
+\r
+        UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->Flags, FALSE);\r
+\r
+      } else {\r
+        if (SubMenu) {\r
+          SavedMenuOption = MenuOption;\r
+          MenuOption      = CR (NewPos, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
+          if (MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP || MenuOption->ThisTag->GrayOut) {\r
+            //\r
+            // If we are at the end of the list and sitting on a text op, we need to more forward\r
+            //\r
+            ScreenOperation = UiUp;\r
+            ControlFlag     = CfScreenOperation;\r
+            break;\r
+          }\r
+\r
+          MenuOption = SavedMenuOption;\r
+          //\r
+          // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.\r
+          //\r
+          AdjustDateAndTimePosition (TRUE, &NewPos);\r
+        }\r
+      }\r
+      break;\r
+\r
+    case CfUiSave:\r
+      ControlFlag = CfCheckSelection;\r
+      //\r
+      // Check for tags that might have LATE_CHECK enabled.  If they do, we can't switch pages or save NV data.\r
+      //\r
+      if (MenuOption != NULL) {\r
+        if (!SelectionsAreValid (MenuOption, FileFormTagsHead)) {\r
+          Selection = NULL;\r
+          Repaint   = TRUE;\r
+          break;\r
+        }\r
+      }\r
+      //\r
+      // If callbacks are active, and the callback has a Write method, try to use it\r
+      //\r
+      if (FileFormTags->VariableDefinitions->VariableName == NULL) {\r
+        if ((FormCallback != NULL) && (FormCallback->NvWrite != NULL)) {\r
+          Status = FormCallback->NvWrite (\r
+                                  FormCallback,\r
+                                  (CHAR16 *) L"Setup",\r
+                                  &FileFormTags->FormTags.Tags[0].GuidValue,\r
+                                  EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+                                  VariableDefinition->VariableSize,\r
+                                  (VOID *) VariableDefinition->NvRamMap,\r
+                                  &gResetRequired\r
+                                  );\r
+\r
+        } else {\r
+          Status = gRT->SetVariable (\r
+                          (CHAR16 *) L"Setup",\r
+                          &FileFormTags->FormTags.Tags[0].GuidValue,\r
+                          EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+                          VariableDefinition->VariableSize,\r
+                          (VOID *) VariableDefinition->NvRamMap\r
+                          );\r
+        }\r
+      } else {\r
+        VariableDefinition = FileFormTags->VariableDefinitions;\r
+\r
+        for (; VariableDefinition != NULL; VariableDefinition = VariableDefinition->Next) {\r
+          if ((FormCallback != NULL) && (FormCallback->NvWrite != NULL)) {\r
+            Status = FormCallback->NvWrite (\r
+                                    FormCallback,\r
+                                    VariableDefinition->VariableName,\r
+                                    &VariableDefinition->Guid,\r
+                                    EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+                                    VariableDefinition->VariableSize,\r
+                                    (VOID *) VariableDefinition->NvRamMap,\r
+                                    &gResetRequired\r
+                                    );\r
+\r
+          } else {\r
+            Status = gRT->SetVariable (\r
+                            VariableDefinition->VariableName,\r
+                            &VariableDefinition->Guid,\r
+                            EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+                            VariableDefinition->VariableSize,\r
+                            (VOID *) VariableDefinition->NvRamMap\r
+                            );\r
+          }\r
+        }\r
+      }\r
+\r
+      UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->Flags, FALSE);\r
+      UpdateStatusBar (NV_UPDATE_REQUIRED, MenuOption->ThisTag->Flags, FALSE);\r
+      break;\r
+\r
+    case CfUiDefault:\r
+      ControlFlag = CfCheckSelection;\r
+\r
+      NvMapListHead = NULL;\r
+\r
+      Status = Hii->GetDefaultImage (Hii, MenuOption->Handle, EFI_IFR_FLAG_DEFAULT, &NvMapListHead);\r
+\r
+      if (!EFI_ERROR (Status)) {\r
+        ASSERT_EFI_ERROR (NULL != NvMapListHead);\r
+\r
+        NvMapListNode = NvMapListHead;\r
+\r
+        while (NULL != NvMapListNode) {\r
+          if (FileFormTags->VariableDefinitions->VariableId == NvMapListNode->VariablePack->VariableId) {\r
+            NvMap     = (VOID *) ((CHAR8 *) NvMapListNode->VariablePack + sizeof (EFI_HII_VARIABLE_PACK) + NvMapListNode->VariablePack->VariableNameLength);\r
+            NvMapSize = NvMapListNode->VariablePack->Header.Length  - sizeof (EFI_HII_VARIABLE_PACK) - NvMapListNode->VariablePack->VariableNameLength;\r
+            break;\r
+            }\r
+          NvMapListNode = NvMapListNode->NextVariablePack;\r
+        }\r
+\r
+        //\r
+        // Free the buffer that was allocated.\r
+        //\r
+        FreePool (FileFormTags->VariableDefinitions->NvRamMap);\r
+        FreePool (FileFormTags->VariableDefinitions->FakeNvRamMap);\r
+\r
+        //\r
+        // Allocate, copy the NvRamMap.\r
+        //\r
+        FileFormTags->VariableDefinitions->VariableFakeSize = (UINT16) (FileFormTags->VariableDefinitions->VariableFakeSize - FileFormTags->VariableDefinitions->VariableSize);\r
+        FileFormTags->VariableDefinitions->VariableSize = (UINT16) NvMapSize;\r
+        FileFormTags->VariableDefinitions->VariableFakeSize = (UINT16) (FileFormTags->VariableDefinitions->VariableFakeSize + FileFormTags->VariableDefinitions->VariableSize);\r
+\r
+        FileFormTags->VariableDefinitions->NvRamMap = AllocateZeroPool (FileFormTags->VariableDefinitions->VariableSize);\r
+        ASSERT (FileFormTags->VariableDefinitions->NvRamMap != NULL);\r
+\r
+        FileFormTags->VariableDefinitions->FakeNvRamMap = AllocateZeroPool (NvMapSize + FileFormTags->VariableDefinitions->VariableFakeSize);\r
+        ASSERT (FileFormTags->VariableDefinitions->FakeNvRamMap != NULL);\r
+\r
+        CopyMem (FileFormTags->VariableDefinitions->NvRamMap, NvMap, NvMapSize);\r
+        FreePool (NvMapListHead);\r
+      }\r
+\r
+      UpdateStatusBar (NV_UPDATE_REQUIRED, MenuOption->ThisTag->Flags, TRUE);\r
+      Repaint = TRUE;\r
+      //\r
+      // After the repaint operation, we should refresh the highlight.\r
+      //\r
+      NewLine = TRUE;\r
+      break;\r
+\r
+    case CfUiNoOperation:\r
+      ControlFlag = CfCheckSelection;\r
+      break;\r
+\r
+    case CfExit:\r
+      while (gMenuRefreshHead != NULL) {\r
+        OldMenuRefreshEntry = gMenuRefreshHead->Next;\r
+\r
+        FreePool (gMenuRefreshHead);\r
+\r
+        gMenuRefreshHead = OldMenuRefreshEntry;\r
+      }\r
+\r
+      gST->ConOut->SetCursorPosition (gST->ConOut, 0, Row + 4);\r
+      gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
+      gST->ConOut->OutputString (gST->ConOut, (CHAR16 *) L"\n");\r
+\r
+      gActiveIfr = MenuOption->IfrNumber;\r
+      return Selection;\r
+\r
+    default:\r
+      break;\r
+    }\r
+  }\r
+}\r
+\r
+BOOLEAN\r
+ValueIsScroll (\r
+  IN  BOOLEAN                 Direction,\r
+  IN  LIST_ENTRY              *CurrentPos\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Determine if the menu is the last menu that can be selected.\r
+\r
+Arguments:\r
+  Direction - the scroll direction. False is down. True is up.\r
+\r
+Returns:\r
+  FALSE -- the menu isn't the last menu that can be selected.\r
+  TRUE  -- the menu is the last menu that can be selected.\r
+--*/\r
+{\r
+  LIST_ENTRY      *Temp;\r
+  UI_MENU_OPTION  *MenuOption;\r
+  MenuOption  = NULL;\r
+\r
+  Temp        = Direction ? CurrentPos->BackLink : CurrentPos->ForwardLink;\r
+\r
+  if (Temp == &Menu) {\r
+    return TRUE;\r
+  }\r
+\r
+  for (; Temp != &Menu; Temp = Direction ? Temp->BackLink : Temp->ForwardLink) {\r
+    MenuOption = CR (Temp, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
+    if (!(MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP || MenuOption->ThisTag->GrayOut)) {\r
+      return FALSE;\r
+    }\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+UINTN\r
+AdjustDateAndTimePosition (\r
+  IN  BOOLEAN                 DirectionUp,\r
+  IN  LIST_ENTRY              **CurrentPosition\r
+  )\r
+/*++\r
+Routine Description:\r
+  Adjust Data and Time tag position accordingly.\r
+  Data format :      [01/02/2004]      [11:22:33]\r
+  Line number :        0  0    1         0  0  1\r
+\r
+Arguments:\r
+  Direction - the up or down direction. False is down. True is up.\r
+  CurrentPos - Current position.\r
+\r
+Returns:\r
+  Return line number to pad. It is possible that we stand on a zero-advance\r
+  data or time opcode, so pad one line when we judge if we are going to scroll outside.\r
+--*/\r
+{\r
+  UINTN           Count;\r
+  LIST_ENTRY      *NewPosition;\r
+  UI_MENU_OPTION  *MenuOption;\r
+  UINTN           PadLineNumber;\r
+\r
+  PadLineNumber = 0;\r
+  NewPosition   = *CurrentPosition;\r
+  MenuOption    = CR (NewPosition, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
+\r
+  if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) {\r
+    //\r
+    // Calculate the distance from current position to the last Date/Time op-code.\r
+    //\r
+    Count = 0;\r
+    while (MenuOption->ThisTag->NumberOfLines == 0) {\r
+      Count++;\r
+      NewPosition   = NewPosition->ForwardLink;\r
+      MenuOption    = CR (NewPosition, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE);\r
+      PadLineNumber = 1;\r
+    }\r
+\r
+    NewPosition = *CurrentPosition;\r
+    if (DirectionUp) {\r
+      //\r
+      // Since the behavior of hitting the up arrow on a Date/Time op-code is intended\r
+      // to be one that back to the previous set of op-codes, we need to advance to the first\r
+      // Date/Time op-code and leave the remaining logic in CfUiUp intact so the appropriate\r
+      // checking can be done.\r
+      //\r
+      while (Count++ < 2) {\r
+        NewPosition = NewPosition->BackLink;\r
+      }\r
+    } else {\r
+      //\r
+      // Since the behavior of hitting the down arrow on a Date/Time op-code is intended\r
+      // to be one that progresses to the next set of op-codes, we need to advance to the last\r
+      // Date/Time op-code and leave the remaining logic in CfUiDown intact so the appropriate\r
+      // checking can be done.\r
+      //\r
+      while (Count-- > 0) {\r
+        NewPosition = NewPosition->ForwardLink;\r
+      }\r
+    }\r
+\r
+    *CurrentPosition = NewPosition;\r
+  }\r
+\r
+  return PadLineNumber;\r
+}\r