]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/SetupBrowserDxe/Ui.c
Patch to remove STATIC modifier. This is on longer recommended by EFI Framework codin...
[mirror_edk2.git] / MdeModulePkg / Universal / SetupBrowserDxe / Ui.c
index 06479c74094c35a6b0dba9353d1d711b34684eb1..8421ad977702e4771877613bbbea6aec28dca5c9 100644 (file)
-/** @file
-
-Copyright (c) 2004 - 2007, Intel Corporation
-All rights reserved. This program and the accompanying materials
-are licensed and made available under the terms and conditions of the BSD License
-which accompanies this distribution.  The full text of the license may be found at
-http://opensource.org/licenses/bsd-license.php
-
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
-
-Module Name:
-
-  Ui.c
-
-Abstract:
-
-  Implementation for UI.
-
-Revision History
-
-
-**/
-
-#include "Ui.h"
-#include "Setup.h"
-
-LIST_ENTRY          Menu;
-LIST_ENTRY          gMenuList;
-MENU_REFRESH_ENTRY  *gMenuRefreshHead;
-
-//
-// Search table for UiDisplayMenu()
-//
-SCAN_CODE_TO_SCREEN_OPERATION     gScanCodeToOperation[] = {
-  SCAN_UP,
-  UiUp,
-  SCAN_DOWN,
-  UiDown,
-  SCAN_PAGE_UP,
-  UiPageUp,
-  SCAN_PAGE_DOWN,
-  UiPageDown,
-  SCAN_ESC,
-  UiReset,
-  SCAN_F2,
-  UiPrevious,
-  SCAN_LEFT,
-  UiLeft,
-  SCAN_RIGHT,
-  UiRight,
-  SCAN_F9,
-  UiDefault,
-  SCAN_F10,
-  UiSave
-};
-
-SCREEN_OPERATION_T0_CONTROL_FLAG  gScreenOperationToControlFlag[] = {
-  UiNoOperation,
-  CfUiNoOperation,
-  UiDefault,
-  CfUiDefault,
-  UiSelect,
-  CfUiSelect,
-  UiUp,
-  CfUiUp,
-  UiDown,
-  CfUiDown,
-  UiLeft,
-  CfUiLeft,
-  UiRight,
-  CfUiRight,
-  UiReset,
-  CfUiReset,
-  UiSave,
-  CfUiSave,
-  UiPrevious,
-  CfUiPrevious,
-  UiPageUp,
-  CfUiPageUp,
-  UiPageDown,
-  CfUiPageDown
-};
-
-
-/**
-  Set Buffer to Value for Size bytes.
-
-  @param  Buffer                 Memory to set.
-  @param  Size                   Number of bytes to set
-  @param  Value                  Value of the set operation.
-
-  @return None
-
-**/
-VOID
-SetUnicodeMem (
-  IN VOID   *Buffer,
-  IN UINTN  Size,
-  IN CHAR16 Value
-  )
-{
-  CHAR16  *Ptr;
-
-  Ptr = Buffer;
-  while (Size--) {
-    *(Ptr++) = Value;
-  }
-}
-
-
-/**
-  Initialize Menu option list.
-
-  None.
-
-  @return None.
-
-**/
-VOID
-UiInitMenu (
-  VOID
-  )
-{
-  InitializeListHead (&Menu);
-}
-
-
-/**
-  Initialize Menu option list.
-
-  None.
-
-  @return None.
-
-**/
-VOID
-UiInitMenuList (
-  VOID
-  )
-{
-  InitializeListHead (&gMenuList);
-}
-
-
-/**
-  Remove a Menu in list, and return FormId/QuestionId for previous Menu.
-
-  @param  Selection              Menu selection.
-
-  @return None.
-
-**/
-VOID
-UiRemoveMenuListEntry (
-  IN OUT UI_MENU_SELECTION  *Selection
-  )
-{
-  UI_MENU_LIST  *UiMenuList;
-
-  if (!IsListEmpty (&gMenuList)) {
-    UiMenuList = CR (gMenuList.ForwardLink, UI_MENU_LIST, MenuLink, UI_MENU_LIST_SIGNATURE);
-
-    Selection->FormId = UiMenuList->FormId;
-    Selection->QuestionId = UiMenuList->QuestionId;
-    RemoveEntryList (&UiMenuList->MenuLink);
-    gBS->FreePool (UiMenuList);
-  }
-}
-
-
-/**
-  Free Menu option linked list.
-
-  None.
-
-  @return None.
-
-**/
-VOID
-UiFreeMenuList (
-  VOID
-  )
-{
-  UI_MENU_LIST  *UiMenuList;
-
-  while (!IsListEmpty (&gMenuList)) {
-    UiMenuList = CR (gMenuList.ForwardLink, UI_MENU_LIST, MenuLink, UI_MENU_LIST_SIGNATURE);
-    RemoveEntryList (&UiMenuList->MenuLink);
-    gBS->FreePool (UiMenuList);
-  }
-}
-
-
-/**
-  Add one menu entry to the linked lst
-
-  @param  Selection              Menu selection.
-
-  @return None.
-
-**/
-VOID
-UiAddMenuListEntry (
-  IN UI_MENU_SELECTION            *Selection
-  )
-{
-  UI_MENU_LIST  *UiMenuList;
-
-  UiMenuList = AllocateZeroPool (sizeof (UI_MENU_LIST));
-  ASSERT (UiMenuList != NULL);
-
-  UiMenuList->Signature = UI_MENU_LIST_SIGNATURE;
-  UiMenuList->FormId = Selection->FormId;
-  UiMenuList->QuestionId = Selection->QuestionId;
-
-  InsertHeadList (&gMenuList, &UiMenuList->MenuLink);
-}
-
-
-/**
-  Free Menu option linked list.
-
-  None.
-
-  @return None.
-
-**/
-VOID
-UiFreeMenu (
-  VOID
-  )
-{
-  UI_MENU_OPTION  *MenuOption;
-
-  while (!IsListEmpty (&Menu)) {
-    MenuOption = MENU_OPTION_FROM_LINK (Menu.ForwardLink);
-    RemoveEntryList (&MenuOption->Link);
-
-    //
-    // We allocated space for this description when we did a GetToken, free it here
-    //
-    if (MenuOption->Skip != 0) {
-      //
-      // For date/time, MenuOption->Description is shared by three Menu Options
-      // Data format :      [01/02/2004]      [11:22:33]
-      // Line number :        0  0    1         0  0  1
-      //
-      gBS->FreePool (MenuOption->Description);
-    }
-    gBS->FreePool (MenuOption);
-  }
-}
-
-
-/**
-  Free Menu option linked list.
-
-  None.
-
-  @return None.
-
-**/
-VOID
-UiFreeRefreshList (
-  VOID
-  )
-{
-  MENU_REFRESH_ENTRY  *OldMenuRefreshEntry;
-
-  while (gMenuRefreshHead != NULL) {
-    OldMenuRefreshEntry = gMenuRefreshHead->Next;
-    gBS->FreePool (gMenuRefreshHead);
-    gMenuRefreshHead = OldMenuRefreshEntry;
-  }
-
-  gMenuRefreshHead = NULL;
-}
-
-
-
-/**
-  Refresh screen.
-
-  None.
-
-  @return None.
-
-**/
-VOID
-RefreshForm (
-  VOID
-  )
-{
-  CHAR16                  *OptionString;
-  MENU_REFRESH_ENTRY      *MenuRefreshEntry;
-  UINTN                   Index;
-  UINTN                   Loop;
-  EFI_STATUS              Status;
-  UI_MENU_SELECTION       *Selection;
-  FORM_BROWSER_STATEMENT  *Question;
-
-  OptionString = NULL;
-
-  if (gMenuRefreshHead != NULL) {
-
-    MenuRefreshEntry = gMenuRefreshHead;
-
-    do {
-      gST->ConOut->SetAttribute (gST->ConOut, MenuRefreshEntry->CurrentAttribute);
-
-      Selection = MenuRefreshEntry->Selection;
-      Question = MenuRefreshEntry->MenuOption->ThisTag;
-
-      //
-      // Don't update Question being edited
-      //
-      if (Question != MenuRefreshEntry->Selection->Statement) {
-
-        Status = GetQuestionValue (Selection->FormSet, Selection->Form, Question, FALSE);
-        if (EFI_ERROR (Status)) {
-          return;
-        }
-
-        ProcessOptions (Selection, MenuRefreshEntry->MenuOption, FALSE, &OptionString);
-
-        if (OptionString != NULL) {
-          //
-          // If leading spaces on OptionString - remove the spaces
-          //
-          for (Index = 0; OptionString[Index] == L' '; Index++)
-            ;
-
-          for (Loop = 0; OptionString[Index] != CHAR_NULL; Index++) {
-            OptionString[Loop] = OptionString[Index];
-            Loop++;
-          }
-
-          OptionString[Loop] = CHAR_NULL;
-
-          PrintStringAt (MenuRefreshEntry->CurrentColumn, MenuRefreshEntry->CurrentRow, OptionString);
-          gBS->FreePool (OptionString);
-        }
-      }
-
-      MenuRefreshEntry = MenuRefreshEntry->Next;
-
-    } while (MenuRefreshEntry != NULL);
-  }
-}
-
-
-/**
-  Wait for a given event to fire, or for an optional timeout to expire.
-
-  @param  Event                  The event to wait for
-  @param  Timeout                An optional timeout value in 100 ns units.
-  @param  RefreshInterval        Menu refresh interval (in seconds).
-
-  @retval EFI_SUCCESS            Event fired before Timeout expired.
-  @retval EFI_TIME_OUT           Timout expired before Event fired.
-
-**/
-EFI_STATUS
-UiWaitForSingleEvent (
-  IN EFI_EVENT                Event,
-  IN UINT64                   Timeout, OPTIONAL
-  IN UINT8                    RefreshInterval OPTIONAL
-  )
-{
-  EFI_STATUS  Status;
-  UINTN       Index;
-  EFI_EVENT   TimerEvent;
-  EFI_EVENT   WaitList[2];
-
-  if (Timeout) {
-    //
-    // Create a timer event
-    //
-    Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);
-    if (!EFI_ERROR (Status)) {
-      //
-      // Set the timer event
-      //
-      gBS->SetTimer (
-            TimerEvent,
-            TimerRelative,
-            Timeout
-            );
-
-      //
-      // Wait for the original event or the timer
-      //
-      WaitList[0] = Event;
-      WaitList[1] = TimerEvent;
-      Status      = gBS->WaitForEvent (2, WaitList, &Index);
-      gBS->CloseEvent (TimerEvent);
-
-      //
-      // If the timer expired, change the return to timed out
-      //
-      if (!EFI_ERROR (Status) && Index == 1) {
-        Status = EFI_TIMEOUT;
-      }
-    }
-  } else {
-    //
-    // Update screen every second
-    //
-    if (RefreshInterval == 0) {
-      Timeout = ONE_SECOND;
-    } else {
-      Timeout = RefreshInterval * ONE_SECOND;
-    }
-
-    do {
-      Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);
-
-      //
-      // Set the timer event
-      //
-      gBS->SetTimer (
-            TimerEvent,
-            TimerRelative,
-            Timeout
-            );
-
-      //
-      // Wait for the original event or the timer
-      //
-      WaitList[0] = Event;
-      WaitList[1] = TimerEvent;
-      Status      = gBS->WaitForEvent (2, WaitList, &Index);
-
-      //
-      // If the timer expired, update anything that needs a refresh and keep waiting
-      //
-      if (!EFI_ERROR (Status) && Index == 1) {
-        Status = EFI_TIMEOUT;
-        if (RefreshInterval != 0) {
-          RefreshForm ();
-        }
-      }
-
-      gBS->CloseEvent (TimerEvent);
-    } while (Status == EFI_TIMEOUT);
-  }
-
-  return Status;
-}
-
-
-/**
-  Add one menu option by specified description and context.
-
-  @param  String                 String description for this option.
-  @param  Handle                 Hii handle for the package list.
-  @param  Statement              Statement of this Menu Option.
-  @param  NumberOfLines          Display lines for this Menu Option.
-  @param  MenuItemCount          The index for this Option in the Menu.
-
-  @return None.
-
-**/
-VOID
-UiAddMenuOption (
-  IN CHAR16                  *String,
-  IN EFI_HII_HANDLE          Handle,
-  IN FORM_BROWSER_STATEMENT  *Statement,
-  IN UINT16                  NumberOfLines,
-  IN UINT16                  MenuItemCount
-  )
-{
-  UI_MENU_OPTION  *MenuOption;
-  UINTN           Index;
-  UINTN           Count;
-
-  Count = 1;
-
-  if (Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) {
-    //
-    // Add three MenuOptions for Date/Time
-    // Data format :      [01/02/2004]      [11:22:33]
-    // Line number :        0  0    1         0  0  1
-    //
-    NumberOfLines = 0;
-    Count = 3;
-
-    if (Statement->Storage == NULL) {
-      //
-      // For RTC type of date/time, set default refresh interval to be 1 second
-      //
-      if (Statement->RefreshInterval == 0) {
-        Statement->RefreshInterval = 1;
-      }
-    }
-  }
-
-  for (Index = 0; Index < Count; Index++) {
-    MenuOption = AllocateZeroPool (sizeof (UI_MENU_OPTION));
-    ASSERT (MenuOption);
-
-    MenuOption->Signature   = UI_MENU_OPTION_SIGNATURE;
-    MenuOption->Description = String;
-    MenuOption->Handle      = Handle;
-    MenuOption->ThisTag     = Statement;
-    MenuOption->EntryNumber = MenuItemCount;
-
-    if (Index == 2) {
-      //
-      // Override LineNumber for the MenuOption in Date/Time sequence
-      //
-      MenuOption->Skip = 1;
-    } else {
-      MenuOption->Skip = NumberOfLines;
-    }
-    MenuOption->Sequence = Index;
-
-    if (Statement->GrayOutExpression != NULL) {
-      MenuOption->GrayOut = Statement->GrayOutExpression->Result.Value.b;
-    }
-
-    if ((Statement->ValueExpression != NULL) ||
-        (Statement->QuestionFlags & EFI_IFR_FLAG_READ_ONLY)) {
-      MenuOption->ReadOnly = TRUE;
-    }
-
-    InsertTailList (&Menu, &MenuOption->Link);
-  }
-}
-
-
-/**
-  Routine used to abstract a generic dialog interface and return the selected key or string
-
-  @param  NumberOfLines          The number of lines for the dialog box
-  @param  HotKey                 Defines whether a single character is parsed
-                                 (TRUE) and returned in KeyValue or a string is
-                                 returned in StringBuffer.  Two special characters
-                                 are considered when entering a string, a SCAN_ESC
-                                 and an CHAR_CARRIAGE_RETURN.  SCAN_ESC terminates
-                                 string input and returns
-  @param  MaximumStringSize      The maximum size in bytes of a typed in string
-                                 (each character is a CHAR16) and the minimum
-                                 string returned is two bytes
-  @param  StringBuffer           The passed in pointer to the buffer which will
-                                 hold the typed in string if HotKey is FALSE
-  @param  KeyValue               The EFI_KEY value returned if HotKey is TRUE..
-  @param  String                 Pointer to the first string in the list
-  @param  ...                    A series of (quantity == NumberOfLines) text
-                                 strings which will be used to construct the dialog
-                                 box
-
-  @retval EFI_SUCCESS            Displayed dialog and received user interaction
-  @retval EFI_INVALID_PARAMETER  One of the parameters was invalid (e.g.
-                                 (StringBuffer == NULL) && (HotKey == FALSE))
-  @retval EFI_DEVICE_ERROR       User typed in an ESC character to exit the routine
-
-**/
-EFI_STATUS
-CreateDialog (
-  IN  UINTN                       NumberOfLines,
-  IN  BOOLEAN                     HotKey,
-  IN  UINTN                       MaximumStringSize,
-  OUT CHAR16                      *StringBuffer,
-  OUT EFI_INPUT_KEY               *KeyValue,
-  IN  CHAR16                      *String,
-  ...
-  )
-{
-  VA_LIST       Marker;
-  UINTN         Count;
-  EFI_INPUT_KEY Key;
-  UINTN         LargestString;
-  CHAR16        *TempString;
-  CHAR16        *BufferedString;
-  CHAR16        *StackString;
-  CHAR16        KeyPad[2];
-  UINTN         Start;
-  UINTN         Top;
-  UINTN         Index;
-  EFI_STATUS    Status;
-  BOOLEAN       SelectionComplete;
-  UINTN         InputOffset;
-  UINTN         CurrentAttribute;
-  UINTN         DimensionsWidth;
-  UINTN         DimensionsHeight;
-
-  DimensionsWidth   = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn;
-  DimensionsHeight  = gScreenDimensions.BottomRow - gScreenDimensions.TopRow;
-
-  SelectionComplete = FALSE;
-  InputOffset       = 0;
-  TempString        = AllocateZeroPool (MaximumStringSize * 2);
-  BufferedString    = AllocateZeroPool (MaximumStringSize * 2);
-  CurrentAttribute  = gST->ConOut->Mode->Attribute;
-
-  ASSERT (TempString);
-  ASSERT (BufferedString);
-
-  VA_START (Marker, String);
-
-  //
-  // Zero the outgoing buffer
-  //
-  ZeroMem (StringBuffer, MaximumStringSize);
-
-  if (HotKey) {
-    if (KeyValue == NULL) {
-      return EFI_INVALID_PARAMETER;
-    }
-  } else {
-    if (StringBuffer == NULL) {
-      return EFI_INVALID_PARAMETER;
-    }
-  }
-  //
-  // Disable cursor
-  //
-  gST->ConOut->EnableCursor (gST->ConOut, FALSE);
-
-  LargestString = (GetStringWidth (String) / 2);
-
-  if (*String == L' ') {
-    InputOffset = 1;
-  }
-  //
-  // Determine the largest string in the dialog box
-  // Notice we are starting with 1 since String is the first string
-  //
-  for (Count = 1; Count < NumberOfLines; Count++) {
-    StackString = VA_ARG (Marker, CHAR16 *);
-
-    if (StackString[0] == L' ') {
-      InputOffset = Count + 1;
-    }
-
-    if ((GetStringWidth (StackString) / 2) > LargestString) {
-      //
-      // Size of the string visually and subtract the width by one for the null-terminator
-      //
-      LargestString = (GetStringWidth (StackString) / 2);
-    }
-  }
-
-  Start = (DimensionsWidth - LargestString - 2) / 2 + gScreenDimensions.LeftColumn + 1;
-  Top   = ((DimensionsHeight - NumberOfLines - 2) / 2) + gScreenDimensions.TopRow - 1;
-
-  Count = 0;
-
-  //
-  // Display the Popup
-  //
-  CreateSharedPopUp (LargestString, NumberOfLines, &String);
-
-  //
-  // Take the first key typed and report it back?
-  //
-  if (HotKey) {
-    Status = WaitForKeyStroke (&Key);
-    ASSERT_EFI_ERROR (Status);
-    CopyMem (KeyValue, &Key, sizeof (EFI_INPUT_KEY));
-
-  } else {
-    do {
-      Status = WaitForKeyStroke (&Key);
-
-      switch (Key.UnicodeChar) {
-      case CHAR_NULL:
-        switch (Key.ScanCode) {
-        case SCAN_ESC:
-          gBS->FreePool (TempString);
-          gBS->FreePool (BufferedString);
-          gST->ConOut->SetAttribute (gST->ConOut, CurrentAttribute);
-          gST->ConOut->EnableCursor (gST->ConOut, TRUE);
-          return EFI_DEVICE_ERROR;
-
-        default:
-          break;
-        }
-
-        break;
-
-      case CHAR_CARRIAGE_RETURN:
-        SelectionComplete = TRUE;
-        gBS->FreePool (TempString);
-        gBS->FreePool (BufferedString);
-        gST->ConOut->SetAttribute (gST->ConOut, CurrentAttribute);
-        gST->ConOut->EnableCursor (gST->ConOut, TRUE);
-        return EFI_SUCCESS;
-        break;
-
-      case CHAR_BACKSPACE:
-        if (StringBuffer[0] != CHAR_NULL) {
-          for (Index = 0; StringBuffer[Index] != CHAR_NULL; Index++) {
-            TempString[Index] = StringBuffer[Index];
-          }
-          //
-          // Effectively truncate string by 1 character
-          //
-          TempString[Index - 1] = CHAR_NULL;
-          StrCpy (StringBuffer, TempString);
-        }
-
-      default:
-        //
-        // If it is the beginning of the string, don't worry about checking maximum limits
-        //
-        if ((StringBuffer[0] == CHAR_NULL) && (Key.UnicodeChar != CHAR_BACKSPACE)) {
-          StrnCpy (StringBuffer, &Key.UnicodeChar, 1);
-          StrnCpy (TempString, &Key.UnicodeChar, 1);
-        } else if ((GetStringWidth (StringBuffer) < MaximumStringSize) && (Key.UnicodeChar != CHAR_BACKSPACE)) {
-          KeyPad[0] = Key.UnicodeChar;
-          KeyPad[1] = CHAR_NULL;
-          StrCat (StringBuffer, KeyPad);
-          StrCat (TempString, KeyPad);
-        }
-        //
-        // If the width of the input string is now larger than the screen, we nee to
-        // adjust the index to start printing portions of the string
-        //
-        SetUnicodeMem (BufferedString, LargestString, L' ');
-
-        PrintStringAt (Start + 1, Top + InputOffset, BufferedString);
-
-        if ((GetStringWidth (StringBuffer) / 2) > (DimensionsWidth - 2)) {
-          Index = (GetStringWidth (StringBuffer) / 2) - DimensionsWidth + 2;
-        } else {
-          Index = 0;
-        }
-
-        for (Count = 0; Index + 1 < GetStringWidth (StringBuffer) / 2; Index++, Count++) {
-          BufferedString[Count] = StringBuffer[Index];
-        }
-
-        PrintStringAt (Start + 1, Top + InputOffset, BufferedString);
-        break;
-      }
-    } while (!SelectionComplete);
-  }
-
-  gST->ConOut->SetAttribute (gST->ConOut, CurrentAttribute);
-  gST->ConOut->EnableCursor (gST->ConOut, TRUE);
-  return EFI_SUCCESS;
-}
-
-VOID
-CreateSharedPopUp (
-  IN  UINTN                       RequestedWidth,
-  IN  UINTN                       NumberOfLines,
-  IN  CHAR16                      **ArrayOfStrings
-  )
-{
-  UINTN   Index;
-  UINTN   Count;
-  CHAR16  Character;
-  UINTN   Start;
-  UINTN   End;
-  UINTN   Top;
-  UINTN   Bottom;
-  CHAR16  *String;
-  UINTN   DimensionsWidth;
-  UINTN   DimensionsHeight;
-
-  DimensionsWidth   = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn;
-  DimensionsHeight  = gScreenDimensions.BottomRow - gScreenDimensions.TopRow;
-
-  Count = 0;
-
-  gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);
-
-  if ((RequestedWidth + 2) > DimensionsWidth) {
-    RequestedWidth = DimensionsWidth - 2;
-  }
-
-  //
-  // Subtract the PopUp width from total Columns, allow for one space extra on
-  // each end plus a border.
-  //
-  Start     = (DimensionsWidth - RequestedWidth - 2) / 2 + gScreenDimensions.LeftColumn + 1;
-  End       = Start + RequestedWidth + 1;
-
-  Top       = ((DimensionsHeight - NumberOfLines - 2) / 2) + gScreenDimensions.TopRow - 1;
-  Bottom    = Top + NumberOfLines + 2;
-
-  Character = BOXDRAW_DOWN_RIGHT;
-  PrintCharAt (Start, Top, Character);
-  Character = BOXDRAW_HORIZONTAL;
-  for (Index = Start; Index + 2 < End; Index++) {
-    PrintChar (Character);
-  }
-
-  Character = BOXDRAW_DOWN_LEFT;
-  PrintChar (Character);
-  Character = BOXDRAW_VERTICAL;
-  for (Index = Top; Index + 2 < Bottom; Index++) {
-    String = ArrayOfStrings[Count];
-    Count++;
-
-    //
-    // This will clear the background of the line - we never know who might have been
-    // here before us.  This differs from the next clear in that it used the non-reverse
-    // video for normal printing.
-    //
-    if (GetStringWidth (String) / 2 > 1) {
-      ClearLines (Start, End, Index + 1, Index + 1, POPUP_TEXT | POPUP_BACKGROUND);
-    }
-
-    //
-    // Passing in a space results in the assumption that this is where typing will occur
-    //
-    if (String[0] == L' ') {
-      ClearLines (Start + 1, End - 1, Index + 1, Index + 1, POPUP_INVERSE_TEXT | POPUP_INVERSE_BACKGROUND);
-    }
-
-    //
-    // Passing in a NULL results in a blank space
-    //
-    if (String[0] == CHAR_NULL) {
-      ClearLines (Start, End, Index + 1, Index + 1, POPUP_TEXT | POPUP_BACKGROUND);
-    }
-
-    PrintStringAt (
-      ((DimensionsWidth - GetStringWidth (String) / 2) / 2) + gScreenDimensions.LeftColumn + 1,
-      Index + 1,
-      String
-      );
-    gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);
-    PrintCharAt (Start, Index + 1, Character);
-    PrintCharAt (End - 1, Index + 1, Character);
-  }
-
-  Character = BOXDRAW_UP_RIGHT;
-  PrintCharAt (Start, Bottom - 1, Character);
-  Character = BOXDRAW_HORIZONTAL;
-  for (Index = Start; Index + 2 < End; Index++) {
-    PrintChar (Character);
-  }
-
-  Character = BOXDRAW_UP_LEFT;
-  PrintChar (Character);
-}
-
-VOID
-CreatePopUp (
-  IN  UINTN                       RequestedWidth,
-  IN  UINTN                       NumberOfLines,
-  IN  CHAR16                      *ArrayOfStrings,
-  ...
-  )
-{
-  CreateSharedPopUp (RequestedWidth, NumberOfLines, &ArrayOfStrings);
-}
-
-
-/**
-  Update status bar on the bottom of menu.
-
-  @param  MessageType            The type of message to be shown.
-  @param  Flags                  The flags in Question header.
-  @param  State                  Set or clear.
-
-  @return None.
-
-**/
-VOID
-UpdateStatusBar (
-  IN  UINTN                       MessageType,
-  IN  UINT8                       Flags,
-  IN  BOOLEAN                     State
-  )
-{
-  UINTN           Index;
-  STATIC BOOLEAN  InputError;
-  CHAR16          *NvUpdateMessage;
-  CHAR16          *InputErrorMessage;
-
-  NvUpdateMessage   = GetToken (STRING_TOKEN (NV_UPDATE_MESSAGE), gHiiHandle);
-  InputErrorMessage = GetToken (STRING_TOKEN (INPUT_ERROR_MESSAGE), gHiiHandle);
-
-  switch (MessageType) {
-  case INPUT_ERROR:
-    if (State) {
-      gST->ConOut->SetAttribute (gST->ConOut, ERROR_TEXT);
-      PrintStringAt (
-        gScreenDimensions.LeftColumn + gPromptBlockWidth,
-        gScreenDimensions.BottomRow - 1,
-        InputErrorMessage
-        );
-      InputError = TRUE;
-    } else {
-      gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT);
-      for (Index = 0; Index < (GetStringWidth (InputErrorMessage) - 2) / 2; Index++) {
-        PrintAt (gScreenDimensions.LeftColumn + gPromptBlockWidth + Index, gScreenDimensions.BottomRow - 1, L"  ");
-      }
-
-      InputError = FALSE;
-    }
-    break;
-
-  case NV_UPDATE_REQUIRED:
-    if (gClassOfVfr != EFI_FRONT_PAGE_SUBCLASS) {
-      if (State) {
-        gST->ConOut->SetAttribute (gST->ConOut, INFO_TEXT);
-        PrintStringAt (
-          gScreenDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth,
-          gScreenDimensions.BottomRow - 1,
-          NvUpdateMessage
-          );
-        gResetRequired    = (BOOLEAN) (gResetRequired | ((Flags & EFI_IFR_FLAG_RESET_REQUIRED) == EFI_IFR_FLAG_RESET_REQUIRED));
-
-        gNvUpdateRequired = TRUE;
-      } else {
-        gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT);
-        for (Index = 0; Index < (GetStringWidth (NvUpdateMessage) - 2) / 2; Index++) {
-          PrintAt (
-            (gScreenDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + Index),
-            gScreenDimensions.BottomRow - 1,
-            L"  "
-            );
-        }
-
-        gNvUpdateRequired = FALSE;
-      }
-    }
-    break;
-
-  case REFRESH_STATUS_BAR:
-    if (InputError) {
-      UpdateStatusBar (INPUT_ERROR, Flags, TRUE);
-    }
-
-    if (gNvUpdateRequired) {
-      UpdateStatusBar (NV_UPDATE_REQUIRED, Flags, TRUE);
-    }
-    break;
-
-  default:
-    break;
-  }
-
-  gBS->FreePool (InputErrorMessage);
-  gBS->FreePool (NvUpdateMessage);
-  return ;
-}
-
-
-/**
-  Get the supported width for a particular op-code
-
-  @param  Statement              The FORM_BROWSER_STATEMENT structure passed in.
-  @param  Handle                 The handle in the HII database being used
-
-  @return Returns the number of CHAR16 characters that is support.
-
-**/
-UINT16
-GetWidth (
-  IN FORM_BROWSER_STATEMENT        *Statement,
-  IN EFI_HII_HANDLE                 Handle
-  )
-{
-  CHAR16  *String;
-  UINTN   Size;
-  UINT16  Width;
-
-  Size = 0;
-
-  //
-  // See if the second text parameter is really NULL
-  //
-  if ((Statement->Operand == EFI_IFR_TEXT_OP) && (Statement->TextTwo != 0)) {
-    String = GetToken (Statement->TextTwo, Handle);
-    Size   = StrLen (String);
-    gBS->FreePool (String);
-  }
-
-  if ((Statement->Operand == EFI_IFR_SUBTITLE_OP) ||
-      (Statement->Operand == EFI_IFR_REF_OP) ||
-      (Statement->Operand == EFI_IFR_PASSWORD_OP) ||
-      (Statement->Operand == EFI_IFR_ACTION_OP) ||
-      (Statement->Operand == EFI_IFR_RESET_BUTTON_OP) ||
-      //
-      // Allow a wide display if text op-code and no secondary text op-code
-      //
-      ((Statement->Operand == EFI_IFR_TEXT_OP) && (Size == 0))
-      ) {
-    Width = (UINT16) (gPromptBlockWidth + gOptionBlockWidth);
-  } else {
-    Width = (UINT16) gPromptBlockWidth;
-  }
-
-  if (Statement->InSubtitle) {
-    Width -= SUBTITLE_INDENT;
-  }
-
-  return Width;
-}
-
-
-/**
-  Will copy LineWidth amount of a string in the OutputString buffer and return the
-  number of CHAR16 characters that were copied into the OutputString buffer.
-
-  @param  InputString            String description for this option.
-  @param  LineWidth              Width of the desired string to extract in CHAR16
-                                 characters
-  @param  Index                  Where in InputString to start the copy process
-  @param  OutputString           Buffer to copy the string into
-
-  @return Returns the number of CHAR16 characters that were copied into the OutputString buffer.
-
-**/
-UINT16
-GetLineByWidth (
-  IN      CHAR16                      *InputString,
-  IN      UINT16                      LineWidth,
-  IN OUT  UINTN                       *Index,
-  OUT     CHAR16                      **OutputString
-  )
-{
-  static BOOLEAN  Finished;
-  UINT16          Count;
-  UINT16          Count2;
-
-  if (Finished) {
-    Finished = FALSE;
-    return (UINT16) 0;
-  }
-
-  Count         = LineWidth;
-  Count2        = 0;
-
-  *OutputString = AllocateZeroPool (((UINTN) (LineWidth + 1) * 2));
-
-  //
-  // Ensure we have got a valid buffer
-  //
-  if (*OutputString != NULL) {
-
-    //
-    //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.
-    //To avoid displaying this  empty line in screen,  just skip  the two CHARs here.
-    //
-   if ((InputString[*Index] == NARROW_CHAR) && (InputString[*Index + 1] == CHAR_CARRIAGE_RETURN)) {
-     *Index = *Index + 2;
-   }
-
-    //
-    // Fast-forward the string and see if there is a carriage-return in the string
-    //
-    for (; (InputString[*Index + Count2] != CHAR_CARRIAGE_RETURN) && (Count2 != LineWidth); Count2++)
-      ;
-
-    //
-    // Copy the desired LineWidth of data to the output buffer.
-    // Also make sure that we don't copy more than the string.
-    // Also make sure that if there are linefeeds, we account for them.
-    //
-    if ((StrSize (&InputString[*Index]) <= ((UINTN) (LineWidth + 1) * 2)) &&
-        (StrSize (&InputString[*Index]) <= ((UINTN) (Count2 + 1) * 2))
-        ) {
-      //
-      // Convert to CHAR16 value and show that we are done with this operation
-      //
-      LineWidth = (UINT16) ((StrSize (&InputString[*Index]) - 2) / 2);
-      if (LineWidth != 0) {
-        Finished = TRUE;
-      }
-    } else {
-      if (Count2 == LineWidth) {
-        //
-        // Rewind the string from the maximum size until we see a space to break the line
-        //
-        for (; (InputString[*Index + LineWidth] != CHAR_SPACE) && (LineWidth != 0); LineWidth--)
-          ;
-        if (LineWidth == 0) {
-          LineWidth = Count;
-        }
-      } else {
-        LineWidth = Count2;
-      }
-    }
-
-    CopyMem (*OutputString, &InputString[*Index], LineWidth * 2);
-
-    //
-    // If currently pointing to a space, increment the index to the first non-space character
-    //
-    for (;
-         (InputString[*Index + LineWidth] == CHAR_SPACE) || (InputString[*Index + LineWidth] == CHAR_CARRIAGE_RETURN);
-         (*Index)++
-        )
-      ;
-    *Index = (UINT16) (*Index + LineWidth);
-    return LineWidth;
-  } else {
-    return (UINT16) 0;
-  }
-}
-
-
-/**
-  Update display lines for a Menu Option.
-
-  @param  MenuOption             The MenuOption to be checked.
-
-  @retval TRUE                   This Menu Option is selectable.
-  @retval FALSE                  This Menu Option could not be selected.
-
-**/
-VOID
-UpdateOptionSkipLines (
-  IN UI_MENU_SELECTION            *Selection,
-  IN UI_MENU_OPTION               *MenuOption,
-  IN CHAR16                       **OptionalString,
-  IN UINTN                        SkipValue
-  )
-{
-  UINTN   Index;
-  UINT16  Width;
-  UINTN   Row;
-  UINTN   OriginalRow;
-  CHAR16  *OutputString;
-  CHAR16  *OptionString;
-
-  Row           = 0;
-  OptionString  = *OptionalString;
-  OutputString  = NULL;
-
-  ProcessOptions (Selection, MenuOption, FALSE, &OptionString);
-
-  if (OptionString != NULL) {
-    Width               = (UINT16) gOptionBlockWidth;
-
-    OriginalRow         = Row;
-
-    for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {
-      //
-      // If there is more string to process print on the next row and increment the Skip value
-      //
-      if (StrLen (&OptionString[Index])) {
-        if (SkipValue == 0) {
-          Row++;
-          //
-          // Since the Number of lines for this menu entry may or may not be reflected accurately
-          // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
-          // some testing to ensure we are keeping this in-sync.
-          //
-          // If the difference in rows is greater than or equal to the skip value, increase the skip value
-          //
-          if ((Row - OriginalRow) >= MenuOption->Skip) {
-            MenuOption->Skip++;
-          }
-        }
-      }
-
-      gBS->FreePool (OutputString);
-      if (SkipValue != 0) {
-        SkipValue--;
-      }
-    }
-
-    Row = OriginalRow;
-  }
-
-  *OptionalString = OptionString;
-}
-
-
-/**
-  Check whether this Menu Option could be highlighted.
-
-  @param  MenuOption             The MenuOption to be checked.
-
-  @retval TRUE                   This Menu Option is selectable.
-  @retval FALSE                  This Menu Option could not be selected.
-
-**/
-STATIC
-BOOLEAN
-IsSelectable (
-  UI_MENU_OPTION   *MenuOption
-  )
-{
-  if ((MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP) ||
-      MenuOption->GrayOut || MenuOption->ReadOnly) {
-    return FALSE;
-  } else {
-    return TRUE;
-  }
-}
-
-
-/**
-  Determine if the menu is the last menu that can be selected.
-
-  @param  Direction              the scroll direction. False is down. True is up.
-
-  @return FALSE -- the menu isn't the last menu that can be selected.
-  @return TRUE  -- the menu is the last menu that can be selected.
-
-**/
-STATIC
-BOOLEAN
-ValueIsScroll (
-  IN  BOOLEAN                     Direction,
-  IN  LIST_ENTRY                  *CurrentPos
-  )
-{
-  LIST_ENTRY      *Temp;
-  UI_MENU_OPTION  *MenuOption;
-
-  Temp = Direction ? CurrentPos->BackLink : CurrentPos->ForwardLink;
-
-  if (Temp == &Menu) {
-    return TRUE;
-  }
-
-  for (; Temp != &Menu; Temp = Direction ? Temp->BackLink : Temp->ForwardLink) {
-    MenuOption = MENU_OPTION_FROM_LINK (Temp);
-    if (IsSelectable (MenuOption)) {
-      return FALSE;
-    }
-  }
-
-  return TRUE;
-}
-
-
-/**
-  Move to next selectable statement.
-
-  @param  GoUp                   The navigation direction. TRUE: up, FALSE: down.
-  @param  CurrentPosition        Current position.
-
-  @return The row distance from current MenuOption to next selectable MenuOption.
-
-**/
-STATIC
-INTN
-MoveToNextStatement (
-  IN     BOOLEAN                   GoUp,
-  IN OUT LIST_ENTRY                **CurrentPosition
-  )
-{
-  INTN             Distance;
-  LIST_ENTRY       *Pos;
-  BOOLEAN          HitEnd;
-  UI_MENU_OPTION   *NextMenuOption;
-
-  Distance = 0;
-  Pos      = *CurrentPosition;
-  HitEnd   = FALSE;
-
-  while (TRUE) {
-    NextMenuOption = MENU_OPTION_FROM_LINK (Pos);
-    if (IsSelectable (NextMenuOption)) {
-      break;
-    }
-    if ((GoUp ? Pos->BackLink : Pos->ForwardLink) == &Menu) {
-      HitEnd = TRUE;
-      break;
-    }
-    Distance += NextMenuOption->Skip;
-    Pos = (GoUp ? Pos->BackLink : Pos->ForwardLink);
-  }
-
-  if (HitEnd) {
-    //
-    // If we hit end there is still no statement can be focused,
-    // we go backwards to find the statement can be focused.
-    //
-    Distance = 0;
-    Pos = *CurrentPosition;
-
-    while (TRUE) {
-      NextMenuOption = MENU_OPTION_FROM_LINK (Pos);
-      if (IsSelectable (NextMenuOption)) {
-        break;
-      }
-      if ((!GoUp ? Pos->BackLink : Pos->ForwardLink) == &Menu) {
-        ASSERT (FALSE);
-        break;
-      }
-      Distance -= NextMenuOption->Skip;
-      Pos = (!GoUp ? Pos->BackLink : Pos->ForwardLink);
-    }
-  }
-
-  *CurrentPosition = &NextMenuOption->Link;
-  return Distance;
-}
-
-
-/**
-  Adjust Data and Time position accordingly.
-  Data format :      [01/02/2004]      [11:22:33]
-  Line number :        0  0    1         0  0  1
-
-  @param  DirectionUp            the up or down direction. False is down. True is
-                                 up.
-  @param  CurrentPosition        Current position. On return: Point to the last
-                                 Option (Year or Second) if up; Point to the first
-                                 Option (Month or Hour) if down.
-
-  @return Return line number to pad. It is possible that we stand on a zero-advance
-  @return data or time opcode, so pad one line when we judge if we are going to scroll outside.
-
-**/
-STATIC
-UINTN
-AdjustDateAndTimePosition (
-  IN     BOOLEAN                     DirectionUp,
-  IN OUT LIST_ENTRY                  **CurrentPosition
-  )
-{
-  UINTN           Count;
-  LIST_ENTRY      *NewPosition;
-  UI_MENU_OPTION  *MenuOption;
-  UINTN           PadLineNumber;
-
-  PadLineNumber = 0;
-  NewPosition   = *CurrentPosition;
-  MenuOption    = MENU_OPTION_FROM_LINK (NewPosition);
-
-  if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) ||
-      (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) {
-    //
-    // Calculate the distance from current position to the last Date/Time MenuOption
-    //
-    Count = 0;
-    while (MenuOption->Skip == 0) {
-      Count++;
-      NewPosition   = NewPosition->ForwardLink;
-      MenuOption    = MENU_OPTION_FROM_LINK (NewPosition);
-      PadLineNumber = 1;
-    }
-
-    NewPosition = *CurrentPosition;
-    if (DirectionUp) {
-      //
-      // Since the behavior of hitting the up arrow on a Date/Time MenuOption is intended
-      // to be one that back to the previous set of MenuOptions, we need to advance to the first
-      // Date/Time MenuOption and leave the remaining logic in CfUiUp intact so the appropriate
-      // checking can be done.
-      //
-      while (Count++ < 2) {
-        NewPosition = NewPosition->BackLink;
-      }
-    } else {
-      //
-      // Since the behavior of hitting the down arrow on a Date/Time MenuOption is intended
-      // to be one that progresses to the next set of MenuOptions, we need to advance to the last
-      // Date/Time MenuOption and leave the remaining logic in CfUiDown intact so the appropriate
-      // checking can be done.
-      //
-      while (Count-- > 0) {
-        NewPosition = NewPosition->ForwardLink;
-      }
-    }
-
-    *CurrentPosition = NewPosition;
-  }
-
-  return PadLineNumber;
-}
-
-
-/**
-  Display menu and wait for user to select one menu option, then return it.
-  If AutoBoot is enabled, then if user doesn't select any option,
-  after period of time, it will automatically return the first menu option.
-
-
-  @return Return the pointer of the menu which selected,
-  @return otherwise return NULL.
-
-**/
-EFI_STATUS
-UiDisplayMenu (
-  IN OUT UI_MENU_SELECTION           *Selection
-  )
-{
-  INTN                            SkipValue;
-  INTN                            Difference;
-  INTN                            OldSkipValue;
-  UINTN                           DistanceValue;
-  UINTN                           Row;
-  UINTN                           Col;
-  UINTN                           Temp;
-  UINTN                           Temp2;
-  UINTN                           TopRow;
-  UINTN                           BottomRow;
-  UINTN                           OriginalRow;
-  UINTN                           Index;
-  UINT32                          Count;
-  UINT16                          Width;
-  CHAR16                          *StringPtr;
-  CHAR16                          *OptionString;
-  CHAR16                          *OutputString;
-  CHAR16                          *FormattedString;
-  CHAR16                          YesResponse;
-  CHAR16                          NoResponse;
-  BOOLEAN                         NewLine;
-  BOOLEAN                         Repaint;
-  BOOLEAN                         SavedValue;
-  EFI_STATUS                      Status;
-  EFI_INPUT_KEY                   Key;
-  LIST_ENTRY                      *Link;
-  LIST_ENTRY                      *NewPos;
-  LIST_ENTRY                      *TopOfScreen;
-  LIST_ENTRY                      *SavedListEntry;
-  UI_MENU_OPTION                  *MenuOption;
-  UI_MENU_OPTION                  *NextMenuOption;
-  UI_MENU_OPTION                  *SavedMenuOption;
-  UI_MENU_OPTION                  *PreviousMenuOption;
-  UI_CONTROL_FLAG                 ControlFlag;
-  EFI_SCREEN_DESCRIPTOR           LocalScreen;
-  MENU_REFRESH_ENTRY              *MenuRefreshEntry;
-  UI_SCREEN_OPERATION             ScreenOperation;
-  UINT8                           MinRefreshInterval;
-  UINTN                           BufferSize;
-  UINT16                          DefaultId;
-  EFI_DEVICE_PATH_PROTOCOL        *DevicePath;
-  FORM_BROWSER_STATEMENT          *Statement;
-
-  CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));
-
-  Status              = EFI_SUCCESS;
-  FormattedString     = NULL;
-  OptionString        = NULL;
-  ScreenOperation     = UiNoOperation;
-  NewLine             = TRUE;
-  MinRefreshInterval  = 0;
-  DefaultId           = 0;
-
-  OutputString        = NULL;
-  gUpArrow            = FALSE;
-  gDownArrow          = FALSE;
-  SkipValue           = 0;
-  OldSkipValue        = 0;
-  MenuRefreshEntry    = gMenuRefreshHead;
-
-  NextMenuOption      = NULL;
-  PreviousMenuOption  = NULL;
-  SavedMenuOption     = NULL;
-
-  ZeroMem (&Key, sizeof (EFI_INPUT_KEY));
-
-  if (gClassOfVfr == EFI_FRONT_PAGE_SUBCLASS) {
-    TopRow  = LocalScreen.TopRow + FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;
-    Row     = LocalScreen.TopRow + FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;
-  } else {
-    TopRow  = LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;
-    Row     = LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;
-  }
-
-  Col = LocalScreen.LeftColumn;
-  BottomRow = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT - SCROLL_ARROW_HEIGHT - 1;
-
-  Selection->TopRow = TopRow;
-  Selection->BottomRow = BottomRow;
-  Selection->PromptCol = Col;
-  Selection->OptionCol = gPromptBlockWidth + 1 + LocalScreen.LeftColumn;
-  Selection->Statement = NULL;
-
-  TopOfScreen = Menu.ForwardLink;
-  Repaint     = TRUE;
-  MenuOption  = NULL;
-
-  //
-  // Get user's selection
-  //
-  NewPos = Menu.ForwardLink;
-
-  gST->ConOut->EnableCursor (gST->ConOut, FALSE);
-  UpdateStatusBar (REFRESH_STATUS_BAR, (UINT8) 0, TRUE);
-
-  ControlFlag = CfInitialization;
-  Selection->Action = UI_ACTION_NONE;
-  while (TRUE) {
-    switch (ControlFlag) {
-    case CfInitialization:
-      if (IsListEmpty (&Menu)) {
-        ControlFlag = CfReadKey;
-      } else {
-        ControlFlag = CfCheckSelection;
-      }
-      break;
-
-    case CfCheckSelection:
-      if (Selection->Action != UI_ACTION_NONE) {
-        ControlFlag = CfExit;
-      } else {
-        ControlFlag = CfRepaint;
-      }
-      break;
-
-    case CfRepaint:
-      ControlFlag = CfRefreshHighLight;
-
-      if (Repaint) {
-        //
-        // Display menu
-        //
-        gDownArrow      = FALSE;
-        gUpArrow        = FALSE;
-        Row             = TopRow;
-
-        Temp            = SkipValue;
-        Temp2           = SkipValue;
-
-        ClearLines (
-          LocalScreen.LeftColumn,
-          LocalScreen.RightColumn,
-          TopRow - SCROLL_ARROW_HEIGHT,
-          BottomRow + SCROLL_ARROW_HEIGHT,
-          FIELD_TEXT | FIELD_BACKGROUND
-          );
-
-        UiFreeRefreshList ();
-        MinRefreshInterval = 0;
-
-        for (Link = TopOfScreen; Link != &Menu; Link = Link->ForwardLink) {
-          MenuOption          = MENU_OPTION_FROM_LINK (Link);
-          MenuOption->Row     = Row;
-          MenuOption->Col     = Col;
-          MenuOption->OptCol  = gPromptBlockWidth + 1 + LocalScreen.LeftColumn;
-
-          Statement = MenuOption->ThisTag;
-          if (Statement->InSubtitle) {
-            MenuOption->Col += SUBTITLE_INDENT;
-          }
-
-          if (MenuOption->GrayOut) {
-            gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_GRAYED | FIELD_BACKGROUND);
-          } else {
-            if (Statement->Operand == EFI_IFR_SUBTITLE_OP) {
-              gST->ConOut->SetAttribute (gST->ConOut, SUBTITLE_TEXT | FIELD_BACKGROUND);
-            }
-          }
-
-          Width       = GetWidth (Statement, MenuOption->Handle);
-          OriginalRow = Row;
-
-          for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) {
-            if ((Temp == 0) && (Row <= BottomRow)) {
-              PrintStringAt (MenuOption->Col, Row, OutputString);
-            }
-            //
-            // If there is more string to process print on the next row and increment the Skip value
-            //
-            if (StrLen (&MenuOption->Description[Index])) {
-              if (Temp == 0) {
-                Row++;
-              }
-            }
-
-            gBS->FreePool (OutputString);
-            if (Temp != 0) {
-              Temp--;
-            }
-          }
-
-          Temp  = 0;
-          Row   = OriginalRow;
-
-          gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);
-          ProcessOptions (Selection, MenuOption, FALSE, &OptionString);
-
-          if (OptionString != NULL) {
-            if (Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) {
-              //
-              // If leading spaces on OptionString - remove the spaces
-              //
-              for (Index = 0; OptionString[Index] == L' '; Index++) {
-                MenuOption->OptCol++;
-              }
-
-              for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) {
-                OptionString[Count] = OptionString[Index];
-                Count++;
-              }
-
-              OptionString[Count] = CHAR_NULL;
-            }
-
-            //
-            // If Question request refresh, register the op-code
-            //
-            if (Statement->RefreshInterval != 0) {
-              //
-              // Menu will be refreshed at minimal interval of all Questions
-              // which have refresh request
-              //
-              if (MinRefreshInterval == 0 || Statement->RefreshInterval < MinRefreshInterval) {
-                MinRefreshInterval = Statement->RefreshInterval;
-              }
-
-              if (gMenuRefreshHead == NULL) {
-                MenuRefreshEntry = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY));
-                ASSERT (MenuRefreshEntry != NULL);
-                MenuRefreshEntry->MenuOption        = MenuOption;
-                MenuRefreshEntry->Selection         = Selection;
-                MenuRefreshEntry->CurrentColumn     = MenuOption->OptCol;
-                MenuRefreshEntry->CurrentRow        = MenuOption->Row;
-                MenuRefreshEntry->CurrentAttribute  = FIELD_TEXT | FIELD_BACKGROUND;
-                gMenuRefreshHead                    = MenuRefreshEntry;
-              } else {
-                //
-                // Advance to the last entry
-                //
-                for (MenuRefreshEntry = gMenuRefreshHead;
-                     MenuRefreshEntry->Next != NULL;
-                     MenuRefreshEntry = MenuRefreshEntry->Next
-                    )
-                  ;
-                MenuRefreshEntry->Next = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY));
-                ASSERT (MenuRefreshEntry->Next != NULL);
-                MenuRefreshEntry                    = MenuRefreshEntry->Next;
-                MenuRefreshEntry->MenuOption        = MenuOption;
-                MenuRefreshEntry->Selection         = Selection;
-                MenuRefreshEntry->CurrentColumn     = MenuOption->OptCol;
-                MenuRefreshEntry->CurrentRow        = MenuOption->Row;
-                MenuRefreshEntry->CurrentAttribute  = FIELD_TEXT | FIELD_BACKGROUND;
-              }
-            }
-
-            Width       = (UINT16) gOptionBlockWidth;
-            OriginalRow = Row;
-
-            for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {
-              if ((Temp2 == 0) && (Row <= BottomRow)) {
-                PrintStringAt (MenuOption->OptCol, Row, OutputString);
-              }
-              //
-              // If there is more string to process print on the next row and increment the Skip value
-              //
-              if (StrLen (&OptionString[Index])) {
-                if (Temp2 == 0) {
-                  Row++;
-                  //
-                  // Since the Number of lines for this menu entry may or may not be reflected accurately
-                  // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
-                  // some testing to ensure we are keeping this in-sync.
-                  //
-                  // If the difference in rows is greater than or equal to the skip value, increase the skip value
-                  //
-                  if ((Row - OriginalRow) >= MenuOption->Skip) {
-                    MenuOption->Skip++;
-                  }
-                }
-              }
-
-              gBS->FreePool (OutputString);
-              if (Temp2 != 0) {
-                Temp2--;
-              }
-            }
-
-            Temp2 = 0;
-            Row   = OriginalRow;
-
-            gBS->FreePool (OptionString);
-          }
-          //
-          // If this is a text op with secondary text information
-          //
-          if ((Statement->Operand == EFI_IFR_TEXT_OP) && (Statement->TextTwo != 0)) {
-            StringPtr   = GetToken (Statement->TextTwo, MenuOption->Handle);
-
-            Width       = (UINT16) gOptionBlockWidth;
-            OriginalRow = Row;
-
-            for (Index = 0; GetLineByWidth (StringPtr, Width, &Index, &OutputString) != 0x0000;) {
-              if ((Temp == 0) && (Row <= BottomRow)) {
-                PrintStringAt (MenuOption->OptCol, Row, OutputString);
-              }
-              //
-              // If there is more string to process print on the next row and increment the Skip value
-              //
-              if (StrLen (&StringPtr[Index])) {
-                if (Temp2 == 0) {
-                  Row++;
-                  //
-                  // Since the Number of lines for this menu entry may or may not be reflected accurately
-                  // since the prompt might be 1 lines and option might be many, and vice versa, we need to do
-                  // some testing to ensure we are keeping this in-sync.
-                  //
-                  // If the difference in rows is greater than or equal to the skip value, increase the skip value
-                  //
-                  if ((Row - OriginalRow) >= MenuOption->Skip) {
-                    MenuOption->Skip++;
-                  }
-                }
-              }
-
-              gBS->FreePool (OutputString);
-              if (Temp2 != 0) {
-                Temp2--;
-              }
-            }
-
-            Row = OriginalRow;
-            gBS->FreePool (StringPtr);
-          }
-
-          //
-          // Need to handle the bottom of the display
-          //
-          if (MenuOption->Skip > 1) {
-            Row += MenuOption->Skip - SkipValue;
-            SkipValue = 0;
-          } else {
-            Row += MenuOption->Skip;
-          }
-
-          if (Row > BottomRow) {
-            if (!ValueIsScroll (FALSE, Link)) {
-              gDownArrow = TRUE;
-            }
-
-            Row = BottomRow + 1;
-            break;
-          }
-        }
-
-        if (!ValueIsScroll (TRUE, TopOfScreen)) {
-          gUpArrow = TRUE;
-        }
-
-        if (gUpArrow) {
-          gST->ConOut->SetAttribute (gST->ConOut, ARROW_TEXT | ARROW_BACKGROUND);
-          PrintAt (
-            LocalScreen.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1,
-            TopRow - SCROLL_ARROW_HEIGHT,
-            L"%c",
-            ARROW_UP
-            );
-          gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);
-        }
-
-        if (gDownArrow) {
-          gST->ConOut->SetAttribute (gST->ConOut, ARROW_TEXT | ARROW_BACKGROUND);
-          PrintAt (
-            LocalScreen.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1,
-            BottomRow + SCROLL_ARROW_HEIGHT,
-            L"%c",
-            ARROW_DOWN
-            );
-          gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);
-        }
-
-        MenuOption = NULL;
-      }
-      break;
-
-    case CfRefreshHighLight:
-      //
-      // MenuOption: Last menu option that need to remove hilight
-      //             MenuOption is set to NULL in Repaint
-      // NewPos:     Current menu option that need to hilight
-      //
-      ControlFlag = CfUpdateHelpString;
-
-      //
-      // Repaint flag is normally reset when finish processing CfUpdateHelpString. Temporarily
-      // reset Repaint flag because we may break halfway and skip CfUpdateHelpString processing.
-      //
-      SavedValue  = Repaint;
-      Repaint     = FALSE;
-
-      if (Selection->QuestionId != 0) {
-        NewPos = Menu.ForwardLink;
-        SavedMenuOption = MENU_OPTION_FROM_LINK (NewPos);
-
-        while (SavedMenuOption->ThisTag->QuestionId != Selection->QuestionId && NewPos->ForwardLink != &Menu) {
-          NewPos     = NewPos->ForwardLink;
-          SavedMenuOption = MENU_OPTION_FROM_LINK (NewPos);
-        }
-        if (SavedMenuOption->ThisTag->QuestionId == Selection->QuestionId) {
-          //
-          // Target Question found, find its MenuOption
-          //
-          Link = TopOfScreen;
-
-          for (Index = TopRow; Index <= BottomRow && Link != NewPos;) {
-            SavedMenuOption = MENU_OPTION_FROM_LINK (Link);
-            Index += SavedMenuOption->Skip;
-            Link = Link->ForwardLink;
-          }
-
-          if (Link != NewPos || Index > BottomRow) {
-            //
-            // NewPos is not in the current page, simply scroll page so that NewPos is in the end of the page
-            //
-            Link    = NewPos;
-            for (Index = TopRow; Index <= BottomRow; ) {
-              Link = Link->BackLink;
-              SavedMenuOption = MENU_OPTION_FROM_LINK (Link);
-              Index     += SavedMenuOption->Skip;
-            }
-            TopOfScreen     = Link->ForwardLink;
-
-            Repaint = TRUE;
-            NewLine = TRUE;
-            ControlFlag = CfRepaint;
-            break;
-          }
-        } else {
-          //
-          // Target Question not found, highlight the default menu option
-          //
-          NewPos = TopOfScreen;
-        }
-
-        Selection->QuestionId = 0;
-      }
-
-      if (NewPos != NULL && (MenuOption == NULL || NewPos != &MenuOption->Link)) {
-        if (MenuOption != NULL) {
-          //
-          // Remove highlight on last Menu Option
-          //
-          gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row);
-          ProcessOptions (Selection, MenuOption, FALSE, &OptionString);
-          gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);
-          if (OptionString != NULL) {
-            if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) ||
-                (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)
-               ) {
-              //
-              // If leading spaces on OptionString - remove the spaces
-              //
-              for (Index = 0; OptionString[Index] == L' '; Index++)
-                ;
-
-              for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) {
-                OptionString[Count] = OptionString[Index];
-                Count++;
-              }
-
-              OptionString[Count] = CHAR_NULL;
-            }
-
-            Width               = (UINT16) gOptionBlockWidth;
-            OriginalRow         = MenuOption->Row;
-
-            for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {
-              if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {
-                PrintStringAt (MenuOption->OptCol, MenuOption->Row, OutputString);
-              }
-              //
-              // If there is more string to process print on the next row and increment the Skip value
-              //
-              if (StrLen (&OptionString[Index])) {
-                MenuOption->Row++;
-              }
-
-              gBS->FreePool (OutputString);
-            }
-
-            MenuOption->Row = OriginalRow;
-
-            gBS->FreePool (OptionString);
-          } else {
-            if (NewLine) {
-              if (MenuOption->GrayOut) {
-                gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_GRAYED | FIELD_BACKGROUND);
-              } else if (MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP) {
-                gST->ConOut->SetAttribute (gST->ConOut, SUBTITLE_TEXT | FIELD_BACKGROUND);
-              }
-
-              OriginalRow = MenuOption->Row;
-              Width       = GetWidth (MenuOption->ThisTag, MenuOption->Handle);
-
-              for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) {
-                if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {
-                  PrintStringAt (MenuOption->Col, MenuOption->Row, OutputString);
-                }
-                //
-                // If there is more string to process print on the next row and increment the Skip value
-                //
-                if (StrLen (&MenuOption->Description[Index])) {
-                  MenuOption->Row++;
-                }
-
-                gBS->FreePool (OutputString);
-              }
-
-              MenuOption->Row = OriginalRow;
-              gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);
-            }
-          }
-        }
-
-        //
-        // This is only possible if we entered this page and the first menu option is
-        // a "non-menu" item.  In that case, force it UiDown
-        //
-        MenuOption = MENU_OPTION_FROM_LINK (NewPos);
-        if (!IsSelectable (MenuOption)) {
-          ASSERT (ScreenOperation == UiNoOperation);
-          ScreenOperation = UiDown;
-          ControlFlag     = CfScreenOperation;
-          break;
-        }
-
-        //
-        // This is the current selected statement
-        //
-        Statement = MenuOption->ThisTag;
-        Selection->Statement = Statement;
-
-        //
-        // Set reverse attribute
-        //
-        gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT | FIELD_BACKGROUND_HIGHLIGHT);
-        gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row);
-
-        //
-        // Assuming that we have a refresh linked-list created, lets annotate the
-        // appropriate entry that we are highlighting with its new attribute.  Just prior to this
-        // lets reset all of the entries' attribute so we do not get multiple highlights in he refresh
-        //
-        if (gMenuRefreshHead != NULL) {
-          for (MenuRefreshEntry = gMenuRefreshHead; MenuRefreshEntry != NULL; MenuRefreshEntry = MenuRefreshEntry->Next) {
-            MenuRefreshEntry->CurrentAttribute = FIELD_TEXT | FIELD_BACKGROUND;
-            if (MenuRefreshEntry->MenuOption == MenuOption) {
-              MenuRefreshEntry->CurrentAttribute = FIELD_TEXT_HIGHLIGHT | FIELD_BACKGROUND_HIGHLIGHT;
-            }
-          }
-        }
-
-        ProcessOptions (Selection, MenuOption, FALSE, &OptionString);
-        if (OptionString != NULL) {
-          if (Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) {
-            //
-            // If leading spaces on OptionString - remove the spaces
-            //
-            for (Index = 0; OptionString[Index] == L' '; Index++)
-              ;
-
-            for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) {
-              OptionString[Count] = OptionString[Index];
-              Count++;
-            }
-
-            OptionString[Count] = CHAR_NULL;
-          }
-          Width               = (UINT16) gOptionBlockWidth;
-
-          OriginalRow         = MenuOption->Row;
-
-          for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) {
-            if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {
-              PrintStringAt (MenuOption->OptCol, MenuOption->Row, OutputString);
-            }
-            //
-            // If there is more string to process print on the next row and increment the Skip value
-            //
-            if (StrLen (&OptionString[Index])) {
-              MenuOption->Row++;
-            }
-
-            gBS->FreePool (OutputString);
-          }
-
-          MenuOption->Row = OriginalRow;
-
-          gBS->FreePool (OptionString);
-        } else {
-          if (NewLine) {
-            OriginalRow = MenuOption->Row;
-
-            Width       = GetWidth (Statement, MenuOption->Handle);
-
-            for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) {
-              if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {
-                PrintStringAt (MenuOption->Col, MenuOption->Row, OutputString);
-              }
-              //
-              // If there is more string to process print on the next row and increment the Skip value
-              //
-              if (StrLen (&MenuOption->Description[Index])) {
-                MenuOption->Row++;
-              }
-
-              gBS->FreePool (OutputString);
-            }
-
-            MenuOption->Row = OriginalRow;
-
-          }
-        }
-
-        if (((NewPos->ForwardLink != &Menu) && (ScreenOperation == UiDown)) ||
-            ((NewPos->BackLink != &Menu) && (ScreenOperation == UiUp)) ||
-            (ScreenOperation == UiNoOperation)
-            ) {
-          UpdateKeyHelp (MenuOption, FALSE);
-        }
-        //
-        // Clear reverse attribute
-        //
-        gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);
-      }
-      //
-      // Repaint flag will be used when process CfUpdateHelpString, so restore its value
-      // if we didn't break halfway when process CfRefreshHighLight.
-      //
-      Repaint = SavedValue;
-      break;
-
-    case CfUpdateHelpString:
-      ControlFlag = CfPrepareToReadKey;
-
-        if ((Repaint || NewLine) && (gClassOfVfr != EFI_GENERAL_APPLICATION_SUBCLASS)) {
-        //
-        // Don't print anything if it is a NULL help token
-        //
-        if (MenuOption->ThisTag->Help == 0) {
-          StringPtr = L"\0";
-        } else {
-          StringPtr = GetToken (MenuOption->ThisTag->Help, MenuOption->Handle);
-        }
-
-        ProcessHelpString (StringPtr, &FormattedString, BottomRow - TopRow);
-
-        gST->ConOut->SetAttribute (gST->ConOut, HELP_TEXT | FIELD_BACKGROUND);
-
-        for (Index = 0; Index < BottomRow - TopRow; Index++) {
-          //
-          // Pad String with spaces to simulate a clearing of the previous line
-          //
-          for (; GetStringWidth (&FormattedString[Index * gHelpBlockWidth * 2]) / 2 < gHelpBlockWidth;) {
-            StrCat (&FormattedString[Index * gHelpBlockWidth * 2], L" ");
-          }
-
-          PrintStringAt (
-            LocalScreen.RightColumn - gHelpBlockWidth,
-            Index + TopRow,
-            &FormattedString[Index * gHelpBlockWidth * 2]
-            );
-        }
-      }
-      //
-      // Reset this flag every time we finish using it.
-      //
-      Repaint = FALSE;
-      NewLine = FALSE;
-      break;
-
-    case CfPrepareToReadKey:
-      ControlFlag = CfReadKey;
-      ScreenOperation = UiNoOperation;
-      break;
-
-    case CfReadKey:
-      ControlFlag = CfScreenOperation;
-
-      //
-      // Wait for user's selection
-      //
-      do {
-        Status = UiWaitForSingleEvent (gST->ConIn->WaitForKey, 0, MinRefreshInterval);
-      } while (Status == EFI_TIMEOUT);
-
-      if (Status == EFI_TIMEOUT) {
-        Key.UnicodeChar = CHAR_CARRIAGE_RETURN;
-      } else {
-        Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
-        //
-        // if we encounter error, continue to read another key in.
-        //
-        if (EFI_ERROR (Status)) {
-          ControlFlag = CfReadKey;
-          continue;
-        }
-      }
-
-      if (IsListEmpty (&Menu) && Key.UnicodeChar != CHAR_NULL) {
-        //
-        // If the screen has no menu items, and the user didn't select UiPrevious, or UiReset
-        //
-        break;
-      }
-
-      switch (Key.UnicodeChar) {
-      case CHAR_CARRIAGE_RETURN:
-        ScreenOperation = UiSelect;
-        gDirection      = 0;
-        break;
-
-      //
-      // We will push the adjustment of these numeric values directly to the input handler
-      //  NOTE: we won't handle manual input numeric
-      //
-      case '+':
-      case '-':
-        Statement = MenuOption->ThisTag;
-        if ((Statement->Operand == EFI_IFR_DATE_OP)
-          || (Statement->Operand == EFI_IFR_TIME_OP)
-          || ((Statement->Operand == EFI_IFR_NUMERIC_OP) && (Statement->Step != 0))
-        ){
-          if (Key.UnicodeChar == '+') {
-            gDirection = SCAN_RIGHT;
-          } else {
-            gDirection = SCAN_LEFT;
-          }
-          Status = ProcessOptions (Selection, MenuOption, TRUE, &OptionString);
-          SafeFreePool (OptionString);
-        }
-        break;
-
-      case '^':
-        ScreenOperation = UiUp;
-        break;
-
-      case 'V':
-      case 'v':
-        ScreenOperation = UiDown;
-        break;
-
-      case ' ':
-        if (gClassOfVfr != EFI_FRONT_PAGE_SUBCLASS) {
-          if (MenuOption->ThisTag->Operand == EFI_IFR_CHECKBOX_OP && !MenuOption->GrayOut) {
-            ScreenOperation = UiSelect;
-          }
-        }
-        break;
-
-      case CHAR_NULL:
-        if (((Key.ScanCode == SCAN_F1) && ((gFunctionKeySetting & FUNCTION_ONE) != FUNCTION_ONE)) ||
-            ((Key.ScanCode == SCAN_F2) && ((gFunctionKeySetting & FUNCTION_TWO) != FUNCTION_TWO)) ||
-            ((Key.ScanCode == SCAN_F9) && ((gFunctionKeySetting & FUNCTION_NINE) != FUNCTION_NINE)) ||
-            ((Key.ScanCode == SCAN_F10) && ((gFunctionKeySetting & FUNCTION_TEN) != FUNCTION_TEN))
-            ) {
-          //
-          // If the function key has been disabled, just ignore the key.
-          //
-        } else {
-          for (Index = 0; Index < sizeof (gScanCodeToOperation) / sizeof (gScanCodeToOperation[0]); Index++) {
-            if (Key.ScanCode == gScanCodeToOperation[Index].ScanCode) {
-              if (Key.ScanCode == SCAN_F9) {
-                //
-                // Reset to standard default
-                //
-                DefaultId = EFI_HII_DEFAULT_CLASS_STANDARD;
-              }
-              ScreenOperation = gScanCodeToOperation[Index].ScreenOperation;
-              break;
-            }
-          }
-        }
-        break;
-      }
-      break;
-
-    case CfScreenOperation:
-      if (ScreenOperation != UiPrevious && ScreenOperation != UiReset) {
-        //
-        // If the screen has no menu items, and the user didn't select UiPrevious, or UiReset
-        // ignore the selection and go back to reading keys.
-        //
-        if (IsListEmpty (&Menu)) {
-          ControlFlag = CfReadKey;
-          break;
-        }
-        //
-        // if there is nothing logical to place a cursor on, just move on to wait for a key.
-        //
-        for (Link = Menu.ForwardLink; Link != &Menu; Link = Link->ForwardLink) {
-          NextMenuOption = MENU_OPTION_FROM_LINK (Link);
-          if (IsSelectable (NextMenuOption)) {
-            break;
-          }
-        }
-
-        if (Link == &Menu) {
-          ControlFlag = CfPrepareToReadKey;
-          break;
-        }
-      } else if (ScreenOperation == UiReset) {
-        //
-        // Press ESC to exit FormSet
-        //
-        Selection->Action = UI_ACTION_EXIT;
-        Selection->Statement = NULL;
-      }
-
-      for (Index = 0;
-           Index < sizeof (gScreenOperationToControlFlag) / sizeof (gScreenOperationToControlFlag[0]);
-           Index++
-          ) {
-        if (ScreenOperation == gScreenOperationToControlFlag[Index].ScreenOperation) {
-          ControlFlag = gScreenOperationToControlFlag[Index].ControlFlag;
-          break;
-        }
-      }
-      break;
-
-    case CfUiPrevious:
-      ControlFlag = CfCheckSelection;
-
-      if (IsListEmpty (&gMenuList)) {
-        Selection->Action = UI_ACTION_NONE;
-        if (IsListEmpty (&Menu)) {
-          ControlFlag = CfReadKey;
-        }
-        break;
-      }
-
-      //
-      // Remove the Cached page entry
-      //
-      UiRemoveMenuListEntry (Selection);
-
-      Selection->Action = UI_ACTION_REFRESH_FORM;
-      Selection->Statement = NULL;
-      break;
-
-    case CfUiSelect:
-      ControlFlag = CfCheckSelection;
-
-      Statement = MenuOption->ThisTag;
-      if ((Statement->Operand == EFI_IFR_TEXT_OP) ||
-          (Statement->Operand == EFI_IFR_DATE_OP) ||
-          (Statement->Operand == EFI_IFR_TIME_OP) ||
-          (Statement->Operand == EFI_IFR_NUMERIC_OP && Statement->Step != 0)) {
-        break;
-      }
-
-      //
-      // Keep highlight on current MenuOption
-      //
-      Selection->QuestionId = Statement->QuestionId;
-
-      switch (Statement->Operand) {
-      case EFI_IFR_REF_OP:
-        if (Statement->RefDevicePath != 0) {
-          //
-          // Goto another Hii Package list
-          //
-          ControlFlag = CfUiReset;
-          Selection->Action = UI_ACTION_REFRESH_FORMSET;
-
-          StringPtr = GetToken (Statement->RefDevicePath, Selection->FormSet->HiiHandle);
-          if (StringPtr == NULL) {
-            //
-            // No device path string not found, exit
-            //
-            Selection->Action = UI_ACTION_EXIT;
-            Selection->Statement = NULL;
-            break;
-          }
-          BufferSize = StrLen (StringPtr) / 4;
-          DevicePath = AllocatePool (BufferSize);
-
-          HexStringToBuffer ((UINT8 *) DevicePath, &BufferSize, StringPtr);
-          Selection->Handle = HiiLibDevicePathToHiiHandle (DevicePath);
-          if (Selection->Handle == NULL) {
-            //
-            // If target Hii Handle not found, exit
-            //
-            Selection->Action = UI_ACTION_EXIT;
-            Selection->Statement = NULL;
-            break;
-          }
-
-          gBS->FreePool (StringPtr);
-          gBS->FreePool (DevicePath);
-
-          CopyMem (&Selection->FormSetGuid, &Statement->RefFormSetId, sizeof (EFI_GUID));
-          Selection->FormId = Statement->RefFormId;
-          Selection->QuestionId = Statement->RefQuestionId;
-        } else if (!CompareGuid (&Statement->RefFormSetId, &gZeroGuid)) {
-          //
-          // Goto another Formset, check for uncommitted data
-          //
-          ControlFlag = CfUiReset;
-          Selection->Action = UI_ACTION_REFRESH_FORMSET;
-
-          CopyMem (&Selection->FormSetGuid, &Statement->RefFormSetId, sizeof (EFI_GUID));
-          Selection->FormId = Statement->RefFormId;
-          Selection->QuestionId = Statement->RefQuestionId;
-        } else if (Statement->RefFormId != 0) {
-          //
-          // Goto another form inside this formset,
-          //
-          Selection->Action = UI_ACTION_REFRESH_FORM;
-
-          //
-          // Link current form so that we can always go back when someone hits the UiPrevious
-          //
-          UiAddMenuListEntry (Selection);
-
-          Selection->FormId = Statement->RefFormId;
-          Selection->QuestionId = Statement->RefQuestionId;
-        } else if (Statement->RefQuestionId != 0) {
-          //
-          // Goto another Question
-          //
-          Selection->QuestionId = Statement->RefQuestionId;
-
-          if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK)) {
-            Selection->Action = UI_ACTION_REFRESH_FORM;
-          } else {
-            Repaint = TRUE;
-            NewLine = TRUE;
-            break;
-          }
-        }
-        break;
-
-      case EFI_IFR_ACTION_OP:
-        //
-        // Process the Config string <ConfigResp>
-        //
-        Status = ProcessQuestionConfig (Selection, Statement);
-
-        if (EFI_ERROR (Status)) {
-          break;
-        }
-
-        //
-        // The action button may change some Question value, so refresh the form
-        //
-        Selection->Action = UI_ACTION_REFRESH_FORM;
-        break;
-
-      case EFI_IFR_RESET_BUTTON_OP:
-        //
-        // Reset Question to default value specified by DefaultId
-        //
-        ControlFlag = CfUiDefault;
-        DefaultId = Statement->DefaultId;
-        break;
-
-      default:
-        //
-        // Editable Questions: oneof, ordered list, checkbox, numeric, string, password
-        //
-        UpdateKeyHelp (MenuOption, TRUE);
-        Status = ProcessOptions (Selection, MenuOption, TRUE, &OptionString);
-
-        if (EFI_ERROR (Status)) {
-          Repaint = TRUE;
-          NewLine = TRUE;
-          break;
-        }
-
-        if (OptionString != NULL) {
-          PrintStringAt (LocalScreen.LeftColumn + gPromptBlockWidth + 1, MenuOption->Row, OptionString);
-          gBS->FreePool (OptionString);
-        }
-
-        Selection->Action = UI_ACTION_REFRESH_FORM;
-        break;
-      }
-      break;
-
-    case CfUiReset:
-      //
-      // We are going to leave current FormSet, so check uncommited data in this FormSet
-      //
-      ControlFlag = CfCheckSelection;
-
-      if (gClassOfVfr == EFI_FRONT_PAGE_SUBCLASS) {
-        //
-        // There is no parent menu for FrontPage
-        //
-        Selection->Action = UI_ACTION_NONE;
-        Selection->Statement = MenuOption->ThisTag;
-        break;
-      }
-
-      //
-      // If NV flag is up, prompt user
-      //
-      if (gNvUpdateRequired) {
-        Status      = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
-
-        YesResponse = gYesResponse[0];
-        NoResponse  = gNoResponse[0];
-
-        do {
-          CreateDialog (3, TRUE, 0, NULL, &Key, gEmptyString, gAreYouSure, gEmptyString);
-        } while
-        (
-          (Key.ScanCode != SCAN_ESC) &&
-          ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (NoResponse | UPPER_LOWER_CASE_OFFSET)) &&
-          ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (YesResponse | UPPER_LOWER_CASE_OFFSET))
-        );
-
-        //
-        // If the user hits the YesResponse key
-        //
-        if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (YesResponse | UPPER_LOWER_CASE_OFFSET)) {
-        } else {
-          Repaint = TRUE;
-          NewLine = TRUE;
-
-          Selection->Action = UI_ACTION_NONE;
-          break;
-        }
-      }
-
-      gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
-      gST->ConOut->EnableCursor (gST->ConOut, TRUE);
-
-      UiFreeMenuList ();
-      gST->ConOut->ClearScreen (gST->ConOut);
-      return EFI_SUCCESS;
-
-    case CfUiLeft:
-      ControlFlag = CfCheckSelection;
-      if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) {
-        if (MenuOption->Sequence != 0) {
-          //
-          // In the middle or tail of the Date/Time op-code set, go left.
-          //
-          NewPos = NewPos->BackLink;
-        }
-      }
-      break;
-
-    case CfUiRight:
-      ControlFlag = CfCheckSelection;
-      if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) {
-        if (MenuOption->Sequence != 2) {
-          //
-          // In the middle or tail of the Date/Time op-code set, go left.
-          //
-          NewPos = NewPos->ForwardLink;
-        }
-      }
-      break;
-
-    case CfUiUp:
-      ControlFlag = CfCheckSelection;
-
-      SavedListEntry = TopOfScreen;
-
-      if (NewPos->BackLink != &Menu) {
-        NewLine = TRUE;
-        //
-        // Adjust Date/Time position before we advance forward.
-        //
-        AdjustDateAndTimePosition (TRUE, &NewPos);
-
-        //
-        // Caution that we have already rewind to the top, don't go backward in this situation.
-        //
-        if (NewPos->BackLink != &Menu) {
-          NewPos = NewPos->BackLink;
-        }
-
-        PreviousMenuOption = MENU_OPTION_FROM_LINK (NewPos);
-        DistanceValue = PreviousMenuOption->Skip;
-
-        //
-        // Since the behavior of hitting the up arrow on a Date/Time op-code is intended
-        // to be one that back to the previous set of op-codes, we need to advance to the sencond
-        // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate
-        // checking can be done.
-        //
-        DistanceValue += AdjustDateAndTimePosition (TRUE, &NewPos);
-
-        //
-        // Check the previous menu entry to see if it was a zero-length advance.  If it was,
-        // don't worry about a redraw.
-        //
-        if ((INTN) MenuOption->Row - (INTN) DistanceValue < (INTN) TopRow) {
-          Repaint     = TRUE;
-          TopOfScreen = NewPos;
-        }
-
-        Difference = MoveToNextStatement (TRUE, &NewPos);
-        if ((INTN) MenuOption->Row - (INTN) DistanceValue < (INTN) TopRow) {
-          if (Difference > 0) {
-            //
-            // Previous focus MenuOption is above the TopOfScreen, so we need to scroll
-            //
-            TopOfScreen = NewPos;
-            Repaint     = TRUE;
-          }
-        }
-        if (Difference < 0) {
-          //
-          // We want to goto previous MenuOption, but finally we go down.
-          // it means that we hit the begining MenuOption that can be focused
-          // so we simply scroll to the top
-          //
-          if (SavedListEntry != Menu.ForwardLink) {
-            TopOfScreen = Menu.ForwardLink;
-            Repaint     = TRUE;
-          }
-        }
-
-        //
-        // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
-        //
-        AdjustDateAndTimePosition (TRUE, &TopOfScreen);
-
-        UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE);
-      } else {
-        SavedMenuOption = MenuOption;
-        MenuOption      = MENU_OPTION_FROM_LINK (NewPos);
-        if (!IsSelectable (MenuOption)) {
-          //
-          // If we are at the end of the list and sitting on a text op, we need to more forward
-          //
-          ScreenOperation = UiDown;
-          ControlFlag     = CfScreenOperation;
-          break;
-        }
-
-        MenuOption = SavedMenuOption;
-      }
-      break;
-
-    case CfUiPageUp:
-      ControlFlag     = CfCheckSelection;
-
-      if (NewPos->BackLink == &Menu) {
-        NewLine = FALSE;
-        Repaint = FALSE;
-        break;
-      }
-
-      NewLine   = TRUE;
-      Repaint   = TRUE;
-      Link      = TopOfScreen;
-      PreviousMenuOption = MENU_OPTION_FROM_LINK (Link);
-      Index = BottomRow;
-      while ((Index >= TopRow) && (Link->BackLink != &Menu)) {
-        Index = Index - PreviousMenuOption->Skip;
-        Link = Link->BackLink;
-        PreviousMenuOption = MENU_OPTION_FROM_LINK (Link);
-      }
-
-      TopOfScreen = Link;
-      Difference = MoveToNextStatement (TRUE, &Link);
-      if (Difference > 0) {
-        //
-        // The focus MenuOption is above the TopOfScreen
-        //
-        TopOfScreen = Link;
-      } else if (Difference < 0) {
-        //
-        // This happens when there is no MenuOption can be focused from
-        // Current MenuOption to the first MenuOption
-        //
-        TopOfScreen = Menu.ForwardLink;
-      }
-      Index += Difference;
-      if (Index < TopRow) {
-        MenuOption = NULL;
-      }
-
-      if (NewPos == Link) {
-        Repaint = FALSE;
-        NewLine = FALSE;
-      } else {
-        NewPos = Link;
-      }
-
-      //
-      // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
-      // Don't do this when we are already in the first page.
-      //
-      AdjustDateAndTimePosition (TRUE, &TopOfScreen);
-      AdjustDateAndTimePosition (TRUE, &NewPos);
-      break;
-
-    case CfUiPageDown:
-      ControlFlag     = CfCheckSelection;
-
-      if (NewPos->ForwardLink == &Menu) {
-        NewLine = FALSE;
-        Repaint = FALSE;
-        break;
-      }
-
-      NewLine = TRUE;
-      Repaint = TRUE;
-      Link    = TopOfScreen;
-      NextMenuOption = MENU_OPTION_FROM_LINK (Link);
-      Index = TopRow;
-      while ((Index <= BottomRow) && (Link->ForwardLink != &Menu)) {
-        Index = Index + NextMenuOption->Skip;
-        Link           = Link->ForwardLink;
-        NextMenuOption = MENU_OPTION_FROM_LINK (Link);
-      }
-
-      Index += MoveToNextStatement (FALSE, &Link);
-      if (Index > BottomRow) {
-        //
-        // There are more MenuOption needing scrolling
-        //
-        TopOfScreen = Link;
-        MenuOption = NULL;
-      }
-      if (NewPos == Link && Index <= BottomRow) {
-        //
-        // Finally we know that NewPos is the last MenuOption can be focused.
-        //
-        NewLine = FALSE;
-        Repaint = FALSE;
-      } else {
-        NewPos  = Link;
-      }
-
-      //
-      // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.
-      // Don't do this when we are already in the last page.
-      //
-      AdjustDateAndTimePosition (TRUE, &TopOfScreen);
-      AdjustDateAndTimePosition (TRUE, &NewPos);
-      break;
-
-    case CfUiDown:
-      ControlFlag = CfCheckSelection;
-      //
-      // Since the behavior of hitting the down arrow on a Date/Time op-code is intended
-      // to be one that progresses to the next set of op-codes, we need to advance to the last
-      // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate
-      // checking can be done.  The only other logic we need to introduce is that if a Date/Time
-      // op-code is the last entry in the menu, we need to rewind back to the first op-code of
-      // the Date/Time op-code.
-      //
-      SavedListEntry = NewPos;
-      DistanceValue  = AdjustDateAndTimePosition (FALSE, &NewPos);
-
-      if (NewPos->ForwardLink != &Menu) {
-        MenuOption      = MENU_OPTION_FROM_LINK (NewPos);
-        NewLine         = TRUE;
-        NewPos          = NewPos->ForwardLink;
-        NextMenuOption  = MENU_OPTION_FROM_LINK (NewPos);
-
-        DistanceValue  += NextMenuOption->Skip;
-        DistanceValue  += MoveToNextStatement (FALSE, &NewPos);
-        //
-        // An option might be multi-line, so we need to reflect that data in the overall skip value
-        //
-        UpdateOptionSkipLines (Selection, NextMenuOption, &OptionString, SkipValue);
-
-        Temp = MenuOption->Row + MenuOption->Skip + DistanceValue - 1;
-        if ((MenuOption->Row + MenuOption->Skip == BottomRow + 1) &&
-            (NextMenuOption->ThisTag->Operand == EFI_IFR_DATE_OP ||
-             NextMenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)
-            ) {
-          Temp ++;
-        }
-
-        //
-        // If we are going to scroll, update TopOfScreen
-        //
-        if (Temp > BottomRow) {
-          do {
-            //
-            // Is the current top of screen a zero-advance op-code?
-            // If so, keep moving forward till we hit a >0 advance op-code
-            //
-            SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);
-
-            //
-            // If bottom op-code is more than one line or top op-code is more than one line
-            //
-            if ((DistanceValue > 1) || (MenuOption->Skip > 1)) {
-              //
-              // Is the bottom op-code greater than or equal in size to the top op-code?
-              //
-              if ((Temp - BottomRow) >= (SavedMenuOption->Skip - OldSkipValue)) {
-                //
-                // Skip the top op-code
-                //
-                TopOfScreen     = TopOfScreen->ForwardLink;
-                Difference      = (Temp - BottomRow) - (SavedMenuOption->Skip - OldSkipValue);
-
-                OldSkipValue    = Difference;
-
-                SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);
-
-                //
-                // If we have a remainder, skip that many more op-codes until we drain the remainder
-                //
-                for (;
-                     Difference >= (INTN) SavedMenuOption->Skip;
-                     Difference = Difference - (INTN) SavedMenuOption->Skip
-                    ) {
-                  //
-                  // Since the Difference is greater than or equal to this op-code's skip value, skip it
-                  //
-                  TopOfScreen     = TopOfScreen->ForwardLink;
-                  SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);
-                  if (Difference < (INTN) SavedMenuOption->Skip) {
-                    Difference = SavedMenuOption->Skip - Difference - 1;
-                    break;
-                  } else {
-                    if (Difference == (INTN) SavedMenuOption->Skip) {
-                      TopOfScreen     = TopOfScreen->ForwardLink;
-                      SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);
-                      Difference      = SavedMenuOption->Skip - Difference;
-                      break;
-                    }
-                  }
-                }
-                //
-                // Since we will act on this op-code in the next routine, and increment the
-                // SkipValue, set the skips to one less than what is required.
-                //
-                SkipValue = Difference - 1;
-
-              } else {
-                //
-                // Since we will act on this op-code in the next routine, and increment the
-                // SkipValue, set the skips to one less than what is required.
-                //
-                SkipValue = OldSkipValue + (Temp - BottomRow) - 1;
-              }
-            } else {
-              if ((OldSkipValue + 1) == (INTN) SavedMenuOption->Skip) {
-                TopOfScreen = TopOfScreen->ForwardLink;
-                break;
-              } else {
-                SkipValue = OldSkipValue;
-              }
-            }
-            //
-            // If the op-code at the top of the screen is more than one line, let's not skip it yet
-            // Let's set a skip flag to smoothly scroll the top of the screen.
-            //
-            if (SavedMenuOption->Skip > 1) {
-              if (SavedMenuOption == NextMenuOption) {
-                SkipValue = 0;
-              } else {
-                SkipValue++;
-              }
-            } else {
-              SkipValue   = 0;
-              TopOfScreen = TopOfScreen->ForwardLink;
-            }
-          } while (SavedMenuOption->Skip == 0);
-
-          Repaint       = TRUE;
-          OldSkipValue  = SkipValue;
-        }
-
-        MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);
-
-        UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE);
-
-      } else {
-        SavedMenuOption = MenuOption;
-        MenuOption      = MENU_OPTION_FROM_LINK (NewPos);
-        if (!IsSelectable (MenuOption)) {
-          //
-          // If we are at the end of the list and sitting on a text op, we need to more forward
-          //
-          ScreenOperation = UiUp;
-          ControlFlag     = CfScreenOperation;
-          break;
-        }
-
-        MenuOption = SavedMenuOption;
-        //
-        // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.
-        //
-        AdjustDateAndTimePosition (TRUE, &NewPos);
-      }
-      break;
-
-    case CfUiSave:
-      ControlFlag = CfCheckSelection;
-
-      //
-      // Submit the form
-      //
-      Status = SubmitForm (Selection->FormSet, Selection->Form);
-
-      if (!EFI_ERROR (Status)) {
-        UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE);
-        UpdateStatusBar (NV_UPDATE_REQUIRED, MenuOption->ThisTag->QuestionFlags, FALSE);
-      } else {
-        do {
-          CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gSaveFailed, gPressEnter, gEmptyString);
-        } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
-
-        Repaint = TRUE;
-        NewLine = TRUE;
-      }
-      break;
-
-    case CfUiDefault:
-      ControlFlag = CfCheckSelection;
-
-      Status = ExtractFormDefault (Selection->FormSet, Selection->Form, DefaultId);
-
-      if (!EFI_ERROR (Status)) {
-        Selection->Action = UI_ACTION_REFRESH_FORM;
-
-        //
-        // Show NV update flag on status bar
-        //
-        gNvUpdateRequired = TRUE;
-      }
-      break;
-
-    case CfUiNoOperation:
-      ControlFlag = CfCheckSelection;
-      break;
-
-    case CfExit:
-      UiFreeRefreshList ();
-
-      gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
-      gST->ConOut->SetCursorPosition (gST->ConOut, 0, Row + 4);
-      gST->ConOut->EnableCursor (gST->ConOut, TRUE);
-      gST->ConOut->OutputString (gST->ConOut, L"\n");
-
-      return EFI_SUCCESS;
-
-    default:
-      break;
-    }
-  }
-}
+/** @file\r
+Utility functions for User Interface functions.\r
+\r
+Copyright (c) 2004 - 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
+#include "Ui.h"\r
+#include "Setup.h"\r
+\r
+LIST_ENTRY          Menu;\r
+LIST_ENTRY          gMenuList;\r
+MENU_REFRESH_ENTRY  *gMenuRefreshHead;\r
+\r
+//\r
+// Search table for UiDisplayMenu()\r
+//\r
+SCAN_CODE_TO_SCREEN_OPERATION     gScanCodeToOperation[] = {\r
+  {\r
+    SCAN_UP,\r
+    UiUp,\r
+  },\r
+  {\r
+    SCAN_DOWN,\r
+    UiDown,\r
+  },\r
+  {\r
+    SCAN_PAGE_UP,\r
+    UiPageUp,\r
+  },\r
+  {\r
+    SCAN_PAGE_DOWN,\r
+    UiPageDown,\r
+  },\r
+  {\r
+    SCAN_ESC,\r
+    UiReset,\r
+  },\r
+  {\r
+    SCAN_F2,\r
+    UiPrevious,\r
+  },\r
+  {\r
+    SCAN_LEFT,\r
+    UiLeft,\r
+  },\r
+  {\r
+    SCAN_RIGHT,\r
+    UiRight,\r
+  },\r
+  {\r
+    SCAN_F9,\r
+    UiDefault,\r
+  },\r
+  {\r
+    SCAN_F10,\r
+    UiSave\r
+  }\r
+};\r
+\r
+SCREEN_OPERATION_T0_CONTROL_FLAG  gScreenOperationToControlFlag[] = {\r
+  {\r
+    UiNoOperation,\r
+    CfUiNoOperation,\r
+  },\r
+  {\r
+    UiDefault,\r
+    CfUiDefault,\r
+  },\r
+  {\r
+    UiSelect,\r
+    CfUiSelect,\r
+  },\r
+  {\r
+    UiUp,\r
+    CfUiUp,\r
+  },\r
+  {\r
+    UiDown,\r
+    CfUiDown,\r
+  },\r
+  {\r
+    UiLeft,\r
+    CfUiLeft,\r
+  },\r
+  {\r
+    UiRight,\r
+    CfUiRight,\r
+  },\r
+  {\r
+    UiReset,\r
+    CfUiReset,\r
+  },\r
+  {\r
+    UiSave,\r
+    CfUiSave,\r
+  },\r
+  {\r
+    UiPrevious,\r
+    CfUiPrevious,\r
+  },\r
+  {\r
+    UiPageUp,\r
+    CfUiPageUp,\r
+  },\r
+  {\r
+    UiPageDown,\r
+    CfUiPageDown\r
+  }\r
+};\r
+\r
+\r
+/**\r
+  Set Buffer to Value for Size bytes.\r
+\r
+  @param  Buffer                 Memory to set.\r
+  @param  Size                   Number of bytes to set\r
+  @param  Value                  Value of the set operation.\r
+\r
+  @return Value.\r
+\r
+**/\r
+VOID\r
+SetUnicodeMem (\r
+  IN VOID   *Buffer,\r
+  IN UINTN  Size,\r
+  IN CHAR16 Value\r
+  )\r
+{\r
+  CHAR16  *Ptr;\r
+\r
+  Ptr = Buffer;\r
+  while ((Size--)  != 0) {\r
+    *(Ptr++) = Value;\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Initialize Menu option list.\r
+\r
+**/\r
+VOID\r
+UiInitMenu (\r
+  VOID\r
+  )\r
+{\r
+  InitializeListHead (&Menu);\r
+}\r
+\r
+\r
+/**\r
+  Initialize Menu option list.\r
+\r
+**/\r
+VOID\r
+UiInitMenuList (\r
+  VOID\r
+  )\r
+{\r
+  InitializeListHead (&gMenuList);\r
+}\r
+\r
+\r
+/**\r
+  Remove a Menu in list, and return FormId/QuestionId for previous Menu.\r
+\r
+  @param  Selection              Menu selection.\r
+\r
+**/\r
+VOID\r
+UiRemoveMenuListEntry (\r
+  OUT UI_MENU_SELECTION  *Selection\r
+  )\r
+{\r
+  UI_MENU_LIST  *UiMenuList;\r
+\r
+  if (!IsListEmpty (&gMenuList)) {\r
+    UiMenuList = CR (gMenuList.ForwardLink, UI_MENU_LIST, MenuLink, UI_MENU_LIST_SIGNATURE);\r
+\r
+    Selection->FormId = UiMenuList->FormId;\r
+    Selection->QuestionId = UiMenuList->QuestionId;\r
+    RemoveEntryList (&UiMenuList->MenuLink);\r
+    gBS->FreePool (UiMenuList);\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Free Menu option linked list.\r
+\r
+**/\r
+VOID\r
+UiFreeMenuList (\r
+  VOID\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
+    gBS->FreePool (UiMenuList);\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Add one menu entry to the linked lst\r
+\r
+  @param  Selection              Menu selection.\r
+\r
+**/\r
+VOID\r
+UiAddMenuListEntry (\r
+  IN UI_MENU_SELECTION            *Selection\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
+  UiMenuList->FormId = Selection->FormId;\r
+  UiMenuList->QuestionId = Selection->QuestionId;\r
+\r
+  InsertHeadList (&gMenuList, &UiMenuList->MenuLink);\r
+}\r
+\r
+\r
+/**\r
+  Free Menu option linked list.\r
+\r
+**/\r
+VOID\r
+UiFreeMenu (\r
+  VOID\r
+  )\r
+{\r
+  UI_MENU_OPTION  *MenuOption;\r
+\r
+  while (!IsListEmpty (&Menu)) {\r
+    MenuOption = MENU_OPTION_FROM_LINK (Menu.ForwardLink);\r
+    RemoveEntryList (&MenuOption->Link);\r
+\r
+    //\r
+    // We allocated space for this description when we did a GetToken, free it here\r
+    //\r
+    if (MenuOption->Skip != 0) {\r
+      //\r
+      // For date/time, MenuOption->Description is shared by three Menu Options\r
+      // Data format :      [01/02/2004]      [11:22:33]\r
+      // Line number :        0  0    1         0  0  1\r
+      //\r
+      gBS->FreePool (MenuOption->Description);\r
+    }\r
+    gBS->FreePool (MenuOption);\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Free Menu option linked list.\r
+\r
+**/\r
+VOID\r
+UiFreeRefreshList (\r
+  VOID\r
+  )\r
+{\r
+  MENU_REFRESH_ENTRY  *OldMenuRefreshEntry;\r
+\r
+  while (gMenuRefreshHead != NULL) {\r
+    OldMenuRefreshEntry = gMenuRefreshHead->Next;\r
+    gBS->FreePool (gMenuRefreshHead);\r
+    gMenuRefreshHead = OldMenuRefreshEntry;\r
+  }\r
+\r
+  gMenuRefreshHead = NULL;\r
+}\r
+\r
+\r
+\r
+/**\r
+  Refresh screen.\r
+\r
+**/\r
+VOID\r
+RefreshForm (\r
+  VOID\r
+  )\r
+{\r
+  CHAR16                  *OptionString;\r
+  MENU_REFRESH_ENTRY      *MenuRefreshEntry;\r
+  UINTN                   Index;\r
+  UINTN                   Loop;\r
+  EFI_STATUS              Status;\r
+  UI_MENU_SELECTION       *Selection;\r
+  FORM_BROWSER_STATEMENT  *Question;\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
+\r
+      Selection = MenuRefreshEntry->Selection;\r
+      Question = MenuRefreshEntry->MenuOption->ThisTag;\r
+\r
+      //\r
+      // Don't update Question being edited\r
+      //\r
+      if (Question != MenuRefreshEntry->Selection->Statement) {\r
+\r
+        Status = GetQuestionValue (Selection->FormSet, Selection->Form, Question, FALSE);\r
+        if (EFI_ERROR (Status)) {\r
+          return;\r
+        }\r
+\r
+        ProcessOptions (Selection, MenuRefreshEntry->MenuOption, FALSE, &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
+          gBS->FreePool (OptionString);\r
+        }\r
+      }\r
+\r
+      MenuRefreshEntry = MenuRefreshEntry->Next;\r
+\r
+    } while (MenuRefreshEntry != NULL);\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Wait for a given event to fire, or for an optional timeout to expire.\r
+\r
+  @param  Event                  The event to wait for\r
+  @param  Timeout                An optional timeout value in 100 ns units.\r
+  @param  RefreshInterval        Menu refresh interval (in seconds).\r
+\r
+  @retval EFI_SUCCESS            Event fired before Timeout expired.\r
+  @retval EFI_TIME_OUT           Timout expired before Event fired.\r
+\r
+**/\r
+EFI_STATUS\r
+UiWaitForSingleEvent (\r
+  IN EFI_EVENT                Event,\r
+  IN UINT64                   Timeout, OPTIONAL\r
+  IN UINT8                    RefreshInterval OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINTN       Index;\r
+  EFI_EVENT   TimerEvent;\r
+  EFI_EVENT   WaitList[2];\r
+\r
+  if (Timeout != 0) {\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
+    if (RefreshInterval == 0) {\r
+      Timeout = ONE_SECOND;\r
+    } else {\r
+      Timeout = RefreshInterval * ONE_SECOND;\r
+    }\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
+        if (RefreshInterval != 0) {\r
+          RefreshForm ();\r
+        }\r
+      }\r
+\r
+      gBS->CloseEvent (TimerEvent);\r
+    } while (Status == EFI_TIMEOUT);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Add one menu option by specified description and context.\r
+\r
+  @param  String                 String description for this option.\r
+  @param  Handle                 Hii handle for the package list.\r
+  @param  Statement              Statement of this Menu Option.\r
+  @param  NumberOfLines          Display lines for this Menu Option.\r
+  @param  MenuItemCount          The index for this Option in the Menu.\r
+\r
+**/\r
+VOID\r
+UiAddMenuOption (\r
+  IN CHAR16                  *String,\r
+  IN EFI_HII_HANDLE          Handle,\r
+  IN FORM_BROWSER_STATEMENT  *Statement,\r
+  IN UINT16                  NumberOfLines,\r
+  IN UINT16                  MenuItemCount\r
+  )\r
+{\r
+  UI_MENU_OPTION  *MenuOption;\r
+  UINTN           Index;\r
+  UINTN           Count;\r
+\r
+  Count = 1;\r
+\r
+  if (Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) {\r
+    //\r
+    // Add three MenuOptions for Date/Time\r
+    // Data format :      [01/02/2004]      [11:22:33]\r
+    // Line number :        0  0    1         0  0  1\r
+    //\r
+    NumberOfLines = 0;\r
+    Count = 3;\r
+\r
+    if (Statement->Storage == NULL) {\r
+      //\r
+      // For RTC type of date/time, set default refresh interval to be 1 second\r
+      //\r
+      if (Statement->RefreshInterval == 0) {\r
+        Statement->RefreshInterval = 1;\r
+      }\r
+    }\r
+  }\r
+\r
+  for (Index = 0; Index < Count; Index++) {\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->ThisTag     = Statement;\r
+    MenuOption->EntryNumber = MenuItemCount;\r
+\r
+    if (Index == 2) {\r
+      //\r
+      // Override LineNumber for the MenuOption in Date/Time sequence\r
+      //\r
+      MenuOption->Skip = 1;\r
+    } else {\r
+      MenuOption->Skip = NumberOfLines;\r
+    }\r
+    MenuOption->Sequence = Index;\r
+\r
+    if (Statement->GrayOutExpression != NULL) {\r
+      MenuOption->GrayOut = Statement->GrayOutExpression->Result.Value.b;\r
+    }\r
+\r
+    if ((Statement->ValueExpression != NULL) ||\r
+        ((Statement->QuestionFlags & EFI_IFR_FLAG_READ_ONLY) != 0)) {\r
+      MenuOption->ReadOnly = TRUE;\r
+    }\r
+\r
+    InsertTailList (&Menu, &MenuOption->Link);\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Routine used to abstract a generic dialog interface and return the selected key or string\r
+\r
+  @param  NumberOfLines          The number of lines for the dialog box\r
+  @param  HotKey                 Defines whether a single character is parsed\r
+                                 (TRUE) and returned in KeyValue or a string is\r
+                                 returned in StringBuffer.  Two special characters\r
+                                 are considered when entering a string, a SCAN_ESC\r
+                                 and an CHAR_CARRIAGE_RETURN.  SCAN_ESC terminates\r
+                                 string input and returns\r
+  @param  MaximumStringSize      The maximum size in bytes of a typed in string\r
+                                 (each character is a CHAR16) and the minimum\r
+                                 string returned is two bytes\r
+  @param  StringBuffer           The passed in pointer to the buffer which will\r
+                                 hold the typed in string if HotKey is FALSE\r
+  @param  KeyValue               The EFI_KEY value returned if HotKey is TRUE..\r
+  @param  ...                    A series of (quantity == NumberOfLines) text\r
+                                 strings which will be used to construct the dialog\r
+                                 box\r
+\r
+  @retval EFI_SUCCESS            Displayed dialog and received user interaction\r
+  @retval EFI_INVALID_PARAMETER  One of the parameters was invalid (e.g.\r
+                                 (StringBuffer == NULL) && (HotKey == FALSE))\r
+  @retval EFI_DEVICE_ERROR       User typed in an ESC character to exit the routine\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
+  ...\r
+  )\r
+{\r
+  VA_LIST       Marker;\r
+  VA_LIST       MarkerBackup;\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
+  EFI_STATUS    Status;\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, KeyValue);\r
+  MarkerBackup = Marker;\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 = 0;\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 = 0; 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, MarkerBackup);\r
+\r
+  //\r
+  // Take the first key typed and report it back?\r
+  //\r
+  if (HotKey) {\r
+    Status = WaitForKeyStroke (&Key);\r
+    ASSERT_EFI_ERROR (Status);\r
+    CopyMem (KeyValue, &Key, sizeof (EFI_INPUT_KEY));\r
+\r
+  } else {\r
+    do {\r
+      Status = WaitForKeyStroke (&Key);\r
+\r
+      switch (Key.UnicodeChar) {\r
+      case CHAR_NULL:\r
+        switch (Key.ScanCode) {\r
+        case SCAN_ESC:\r
+          gBS->FreePool (TempString);\r
+          gBS->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
+        gBS->FreePool (TempString);\r
+        gBS->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
+/**\r
+  Draw a pop up windows based on the dimension, number of lines and\r
+  strings specified.\r
+\r
+  @param RequestedWidth  The width of the pop-up.\r
+  @param NumberOfLines   The number of lines.\r
+  @param Marker          The variable argument list for the list of string to be printed.\r
+\r
+**/\r
+VOID\r
+CreateSharedPopUp (\r
+  IN  UINTN                       RequestedWidth,\r
+  IN  UINTN                       NumberOfLines,\r
+  IN  VA_LIST                     Marker\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
+  UINTN   DimensionsWidth;\r
+  UINTN   DimensionsHeight;\r
+\r
+  DimensionsWidth   = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn;\r
+  DimensionsHeight  = gScreenDimensions.BottomRow - gScreenDimensions.TopRow;\r
+\r
+  gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);\r
+\r
+  if ((RequestedWidth + 2) > DimensionsWidth) {\r
+    RequestedWidth = DimensionsWidth - 2;\r
+  }\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 = BOXDRAW_DOWN_RIGHT;\r
+  PrintCharAt (Start, Top, Character);\r
+  Character = BOXDRAW_HORIZONTAL;\r
+  for (Index = Start; Index + 2 < End; Index++) {\r
+    PrintChar (Character);\r
+  }\r
+\r
+  Character = BOXDRAW_DOWN_LEFT;\r
+  PrintChar (Character);\r
+  Character = BOXDRAW_VERTICAL;\r
+\r
+  Count = 0;\r
+  for (Index = Top; Index + 2 < Bottom; Index++, Count++) {\r
+    String = VA_ARG (Marker, CHAR16*);\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
+    //\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
+    //\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 = BOXDRAW_UP_RIGHT;\r
+  PrintCharAt (Start, Bottom - 1, Character);\r
+  Character = BOXDRAW_HORIZONTAL;\r
+  for (Index = Start; Index + 2 < End; Index++) {\r
+    PrintChar (Character);\r
+  }\r
+\r
+  Character = BOXDRAW_UP_LEFT;\r
+  PrintChar (Character);\r
+}\r
+\r
+/**\r
+  Draw a pop up windows based on the dimension, number of lines and\r
+  strings specified.\r
+\r
+  @param RequestedWidth  The width of the pop-up.\r
+  @param NumberOfLines   The number of lines.\r
+  @param ...             A series of text strings that displayed in the pop-up.\r
+\r
+**/\r
+VOID\r
+CreatePopUp (\r
+  IN  UINTN                       RequestedWidth,\r
+  IN  UINTN                       NumberOfLines,\r
+  ...\r
+  )\r
+{\r
+  VA_LIST Marker;\r
+\r
+  VA_START (Marker, NumberOfLines);\r
+  \r
+  CreateSharedPopUp (RequestedWidth, NumberOfLines, Marker);\r
+\r
+  VA_END (Marker);\r
+}\r
+\r
+\r
+/**\r
+  Update status bar on the bottom of menu.\r
+\r
+  @param  MessageType            The type of message to be shown.\r
+  @param  Flags                  The flags in Question header.\r
+  @param  State                  Set or clear.\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, 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
+            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
+  gBS->FreePool (InputErrorMessage);\r
+  gBS->FreePool (NvUpdateMessage);\r
+  return ;\r
+}\r
+\r
+\r
+/**\r
+  Get the supported width for a particular op-code\r
+\r
+  @param  Statement              The FORM_BROWSER_STATEMENT structure passed in.\r
+  @param  Handle                 The handle in the HII database being used\r
+\r
+  @return Returns the number of CHAR16 characters that is support.\r
+\r
+**/\r
+UINT16\r
+GetWidth (\r
+  IN FORM_BROWSER_STATEMENT        *Statement,\r
+  IN EFI_HII_HANDLE                 Handle\r
+  )\r
+{\r
+  CHAR16  *String;\r
+  UINTN   Size;\r
+  UINT16  Width;\r
+\r
+  Size = 0;\r
+\r
+  //\r
+  // See if the second text parameter is really NULL\r
+  //\r
+  if ((Statement->Operand == EFI_IFR_TEXT_OP) && (Statement->TextTwo != 0)) {\r
+    String = GetToken (Statement->TextTwo, Handle);\r
+    Size   = StrLen (String);\r
+    gBS->FreePool (String);\r
+  }\r
+\r
+  if ((Statement->Operand == EFI_IFR_SUBTITLE_OP) ||\r
+      (Statement->Operand == EFI_IFR_REF_OP) ||\r
+      (Statement->Operand == EFI_IFR_PASSWORD_OP) ||\r
+      (Statement->Operand == EFI_IFR_ACTION_OP) ||\r
+      (Statement->Operand == EFI_IFR_RESET_BUTTON_OP) ||\r
+      //\r
+      // Allow a wide display if text op-code and no secondary text op-code\r
+      //\r
+      ((Statement->Operand == EFI_IFR_TEXT_OP) && (Size == 0))\r
+      ) {\r
+    Width = (UINT16) (gPromptBlockWidth + gOptionBlockWidth);\r
+  } else {\r
+    Width = (UINT16) gPromptBlockWidth;\r
+  }\r
+\r
+  if (Statement->InSubtitle) {\r
+    Width -= SUBTITLE_INDENT;\r
+  }\r
+\r
+  return Width;\r
+}\r
+\r
+\r
+BOOLEAN GetLineByWidthFinished = FALSE;\r
+\r
+/**\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
+  @param  InputString            String description for this option.\r
+  @param  LineWidth              Width of the desired string to extract in CHAR16\r
+                                 characters\r
+  @param  Index                  Where in InputString to start the copy process\r
+  @param  OutputString           Buffer to copy the string into\r
+\r
+  @return Returns the number of CHAR16 characters that were copied into the OutputString buffer.\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
+  UINT16          Count;\r
+  UINT16          Count2;\r
+\r
+  if (GetLineByWidthFinished) {\r
+    GetLineByWidthFinished = 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
+        GetLineByWidthFinished = 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
+\r
+/**\r
+  Update display lines for a Menu Option.\r
+\r
+  @param  Selection              The user's selection.\r
+  @param  MenuOption             The MenuOption to be checked.\r
+  @param  OptionalString         The option string.\r
+  @param  SkipValue              The number of lins to skip.\r
+\r
+**/\r
+VOID\r
+UpdateOptionSkipLines (\r
+  IN UI_MENU_SELECTION            *Selection,\r
+  IN UI_MENU_OPTION               *MenuOption,\r
+  OUT 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 (Selection, MenuOption, FALSE, &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
+      gBS->FreePool (OutputString);\r
+      if (SkipValue != 0) {\r
+        SkipValue--;\r
+      }\r
+    }\r
+\r
+    Row = OriginalRow;\r
+  }\r
+\r
+  *OptionalString = OptionString;\r
+}\r
+\r
+\r
+/**\r
+  Check whether this Menu Option could be highlighted.\r
+\r
+  This is an internal function.\r
+\r
+  @param  MenuOption             The MenuOption to be checked.\r
+\r
+  @retval TRUE                   This Menu Option is selectable.\r
+  @retval FALSE                  This Menu Option could not be selected.\r
+\r
+**/\r
+BOOLEAN\r
+IsSelectable (\r
+  UI_MENU_OPTION   *MenuOption\r
+  )\r
+{\r
+  if ((MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP) ||\r
+      MenuOption->GrayOut || MenuOption->ReadOnly) {\r
+    return FALSE;\r
+  } else {\r
+    return TRUE;\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Determine if the menu is the last menu that can be selected.\r
+\r
+  This is an internal function.\r
+  \r
+  @param  Direction              The scroll direction. False is down. True is up.\r
+  @param  CurrentPos             The current focus.\r
+\r
+  @return FALSE -- the menu isn't the last menu that can be selected.\r
+  @return TRUE  -- the menu is the last menu that can be selected.\r
+\r
+**/\r
+BOOLEAN\r
+ValueIsScroll (\r
+  IN  BOOLEAN                     Direction,\r
+  IN  LIST_ENTRY                  *CurrentPos\r
+  )\r
+{\r
+  LIST_ENTRY      *Temp;\r
+  UI_MENU_OPTION  *MenuOption;\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 = MENU_OPTION_FROM_LINK (Temp);\r
+    if (IsSelectable (MenuOption)) {\r
+      return FALSE;\r
+    }\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+\r
+/**\r
+  Move to next selectable statement.\r
+  \r
+  This is an internal function.\r
+  \r
+  @param  GoUp                   The navigation direction. TRUE: up, FALSE: down.\r
+  @param  CurrentPosition        Current position.\r
+\r
+  @return The row distance from current MenuOption to next selectable MenuOption.\r
+\r
+**/\r
+INTN\r
+MoveToNextStatement (\r
+  IN     BOOLEAN                   GoUp,\r
+  IN OUT LIST_ENTRY                **CurrentPosition\r
+  )\r
+{\r
+  INTN             Distance;\r
+  LIST_ENTRY       *Pos;\r
+  BOOLEAN          HitEnd;\r
+  UI_MENU_OPTION   *NextMenuOption;\r
+\r
+  Distance = 0;\r
+  Pos      = *CurrentPosition;\r
+  HitEnd   = FALSE;\r
+\r
+  while (TRUE) {\r
+    NextMenuOption = MENU_OPTION_FROM_LINK (Pos);\r
+    if (IsSelectable (NextMenuOption)) {\r
+      break;\r
+    }\r
+    if ((GoUp ? Pos->BackLink : Pos->ForwardLink) == &Menu) {\r
+      HitEnd = TRUE;\r
+      break;\r
+    }\r
+    Distance += NextMenuOption->Skip;\r
+    Pos = (GoUp ? Pos->BackLink : Pos->ForwardLink);\r
+  }\r
+\r
+  if (HitEnd) {\r
+    //\r
+    // If we hit end there is still no statement can be focused,\r
+    // we go backwards to find the statement can be focused.\r
+    //\r
+    Distance = 0;\r
+    Pos = *CurrentPosition;\r
+\r
+    while (TRUE) {\r
+      NextMenuOption = MENU_OPTION_FROM_LINK (Pos);\r
+      if (IsSelectable (NextMenuOption)) {\r
+        break;\r
+      }\r
+      if ((!GoUp ? Pos->BackLink : Pos->ForwardLink) == &Menu) {\r
+        ASSERT (FALSE);\r
+        break;\r
+      }\r
+      Distance -= NextMenuOption->Skip;\r
+      Pos = (!GoUp ? Pos->BackLink : Pos->ForwardLink);\r
+    }\r
+  }\r
+\r
+  *CurrentPosition = &NextMenuOption->Link;\r
+  return Distance;\r
+}\r
+\r
+\r
+/**\r
+  Adjust Data and Time position accordingly.\r
+  Data format :      [01/02/2004]      [11:22:33]\r
+  Line number :        0  0    1         0  0  1\r
+  \r
+  This is an internal function.\r
+\r
+  @param  DirectionUp            the up or down direction. False is down. True is\r
+                                 up.\r
+  @param  CurrentPosition        Current position. On return: Point to the last\r
+                                 Option (Year or Second) if up; Point to the first\r
+                                 Option (Month or Hour) if down.\r
+\r
+  @return Return line number to pad. It is possible that we stand on a zero-advance\r
+  @return data or time opcode, so pad one line when we judge if we are going to scroll outside.\r
+\r
+**/\r
+UINTN\r
+AdjustDateAndTimePosition (\r
+  IN     BOOLEAN                     DirectionUp,\r
+  IN OUT LIST_ENTRY                  **CurrentPosition\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    = MENU_OPTION_FROM_LINK (NewPosition);\r
+\r
+  if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) ||\r
+      (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) {\r
+    //\r
+    // Calculate the distance from current position to the last Date/Time MenuOption\r
+    //\r
+    Count = 0;\r
+    while (MenuOption->Skip == 0) {\r
+      Count++;\r
+      NewPosition   = NewPosition->ForwardLink;\r
+      MenuOption    = MENU_OPTION_FROM_LINK (NewPosition);\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 MenuOption is intended\r
+      // to be one that back to the previous set of MenuOptions, we need to advance to the first\r
+      // Date/Time MenuOption 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 MenuOption is intended\r
+      // to be one that progresses to the next set of MenuOptions, we need to advance to the last\r
+      // Date/Time MenuOption 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
+\r
+\r
+/**\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
+  @param  Selection              Menu selection.\r
+\r
+  @retval EFI_SUCESSS            This function always return successfully for now.\r
+\r
+**/\r
+EFI_STATUS\r
+UiDisplayMenu (\r
+  IN OUT UI_MENU_SELECTION           *Selection\r
+  )\r
+{\r
+  INTN                            SkipValue;\r
+  INTN                            Difference;\r
+  INTN                            OldSkipValue;\r
+  UINTN                           DistanceValue;\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
+  UINT32                          Count;\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
+  EFI_INPUT_KEY                   Key;\r
+  LIST_ENTRY                      *Link;\r
+  LIST_ENTRY                      *NewPos;\r
+  LIST_ENTRY                      *TopOfScreen;\r
+  LIST_ENTRY                      *SavedListEntry;\r
+  UI_MENU_OPTION                  *MenuOption;\r
+  UI_MENU_OPTION                  *NextMenuOption;\r
+  UI_MENU_OPTION                  *SavedMenuOption;\r
+  UI_MENU_OPTION                  *PreviousMenuOption;\r
+  UI_CONTROL_FLAG                 ControlFlag;\r
+  EFI_SCREEN_DESCRIPTOR           LocalScreen;\r
+  MENU_REFRESH_ENTRY              *MenuRefreshEntry;\r
+  UI_SCREEN_OPERATION             ScreenOperation;\r
+  UINT8                           MinRefreshInterval;\r
+  UINTN                           BufferSize;\r
+  UINT16                          DefaultId;\r
+  EFI_DEVICE_PATH_PROTOCOL        *DevicePath;\r
+  FORM_BROWSER_STATEMENT          *Statement;\r
+\r
+  CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));\r
+\r
+  Status              = EFI_SUCCESS;\r
+  FormattedString     = NULL;\r
+  OptionString        = NULL;\r
+  ScreenOperation     = UiNoOperation;\r
+  NewLine             = TRUE;\r
+  MinRefreshInterval  = 0;\r
+  DefaultId           = 0;\r
+\r
+  OutputString        = NULL;\r
+  gUpArrow            = FALSE;\r
+  gDownArrow          = FALSE;\r
+  SkipValue           = 0;\r
+  OldSkipValue        = 0;\r
+  MenuRefreshEntry    = gMenuRefreshHead;\r
+\r
+  NextMenuOption      = NULL;\r
+  PreviousMenuOption  = NULL;\r
+  SavedMenuOption     = NULL;\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
+  Col = LocalScreen.LeftColumn;\r
+  BottomRow = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT - SCROLL_ARROW_HEIGHT - 1;\r
+\r
+  Selection->TopRow = TopRow;\r
+  Selection->BottomRow = BottomRow;\r
+  Selection->PromptCol = Col;\r
+  Selection->OptionCol = gPromptBlockWidth + 1 + LocalScreen.LeftColumn;\r
+  Selection->Statement = NULL;\r
+\r
+  TopOfScreen = Menu.ForwardLink;\r
+  Repaint     = TRUE;\r
+  MenuOption  = NULL;\r
+\r
+  //\r
+  // Get user's selection\r
+  //\r
+  NewPos = Menu.ForwardLink;\r
+\r
+  gST->ConOut->EnableCursor (gST->ConOut, FALSE);\r
+  UpdateStatusBar (REFRESH_STATUS_BAR, (UINT8) 0, TRUE);\r
+\r
+  ControlFlag = CfInitialization;\r
+  Selection->Action = UI_ACTION_NONE;\r
+  while (TRUE) {\r
+    switch (ControlFlag) {\r
+    case CfInitialization:\r
+      if (IsListEmpty (&Menu)) {\r
+        ControlFlag = CfReadKey;\r
+      } else {\r
+        ControlFlag = CfCheckSelection;\r
+      }\r
+      break;\r
+\r
+    case CfCheckSelection:\r
+      if (Selection->Action != UI_ACTION_NONE) {\r
+        ControlFlag = CfExit;\r
+      } else {\r
+        ControlFlag = CfRepaint;\r
+      }\r
+      break;\r
+\r
+    case CfRepaint:\r
+      ControlFlag = CfRefreshHighLight;\r
+\r
+      if (Repaint) {\r
+        //\r
+        // Display menu\r
+        //\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
+        UiFreeRefreshList ();\r
+        MinRefreshInterval = 0;\r
+\r
+        for (Link = TopOfScreen; Link != &Menu; Link = Link->ForwardLink) {\r
+          MenuOption          = MENU_OPTION_FROM_LINK (Link);\r
+          MenuOption->Row     = Row;\r
+          MenuOption->Col     = Col;\r
+          MenuOption->OptCol  = gPromptBlockWidth + 1 + LocalScreen.LeftColumn;\r
+\r
+          Statement = MenuOption->ThisTag;\r
+          if (Statement->InSubtitle) {\r
+            MenuOption->Col += SUBTITLE_INDENT;\r
+          }\r
+\r
+          if (MenuOption->GrayOut) {\r
+            gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_GRAYED | FIELD_BACKGROUND);\r
+          } else {\r
+            if (Statement->Operand == EFI_IFR_SUBTITLE_OP) {\r
+              gST->ConOut->SetAttribute (gST->ConOut, SUBTITLE_TEXT | FIELD_BACKGROUND);\r
+            }\r
+          }\r
+\r
+          Width       = GetWidth (Statement, MenuOption->Handle);\r
+          OriginalRow = Row;\r
+\r
+          for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) {\r
+            if ((Temp == 0) && (Row <= BottomRow)) {\r
+              PrintStringAt (MenuOption->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
+            gBS->FreePool (OutputString);\r
+            if (Temp != 0) {\r
+              Temp--;\r
+            }\r
+          }\r
+\r
+          Temp  = 0;\r
+          Row   = OriginalRow;\r
+\r
+          gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
+          ProcessOptions (Selection, MenuOption, FALSE, &OptionString);\r
+\r
+          if (OptionString != NULL) {\r
+            if (Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) {\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 Question request refresh, register the op-code\r
+            //\r
+            if (Statement->RefreshInterval != 0) {\r
+              //\r
+              // Menu will be refreshed at minimal interval of all Questions\r
+              // which have refresh request\r
+              //\r
+              if (MinRefreshInterval == 0 || Statement->RefreshInterval < MinRefreshInterval) {\r
+                MinRefreshInterval = Statement->RefreshInterval;\r
+              }\r
+\r
+              if (gMenuRefreshHead == NULL) {\r
+                MenuRefreshEntry = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY));\r
+                ASSERT (MenuRefreshEntry != NULL);\r
+                MenuRefreshEntry->MenuOption        = MenuOption;\r
+                MenuRefreshEntry->Selection         = Selection;\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->Selection         = Selection;\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
+            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
+              gBS->FreePool (OutputString);\r
+              if (Temp2 != 0) {\r
+                Temp2--;\r
+              }\r
+            }\r
+\r
+            Temp2 = 0;\r
+            Row   = OriginalRow;\r
+\r
+            gBS->FreePool (OptionString);\r
+          }\r
+          //\r
+          // If this is a text op with secondary text information\r
+          //\r
+          if ((Statement->Operand == EFI_IFR_TEXT_OP) && (Statement->TextTwo != 0)) {\r
+            StringPtr   = GetToken (Statement->TextTwo, MenuOption->Handle);\r
+\r
+            Width       = (UINT16) gOptionBlockWidth;\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
+              gBS->FreePool (OutputString);\r
+              if (Temp2 != 0) {\r
+                Temp2--;\r
+              }\r
+            }\r
+\r
+            Row = OriginalRow;\r
+            gBS->FreePool (StringPtr);\r
+          }\r
+\r
+          //\r
+          // 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
+            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
+            L"%c",\r
+            ARROW_DOWN\r
+            );\r
+          gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
+        }\r
+\r
+        MenuOption = NULL;\r
+      }\r
+      break;\r
+\r
+    case CfRefreshHighLight:\r
+      //\r
+      // MenuOption: Last menu option that need to remove hilight\r
+      //             MenuOption is set to NULL in Repaint\r
+      // NewPos:     Current menu option that need to hilight\r
+      //\r
+      ControlFlag = CfUpdateHelpString;\r
+\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 (Selection->QuestionId != 0) {\r
+        NewPos = Menu.ForwardLink;\r
+        SavedMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
+\r
+        while (SavedMenuOption->ThisTag->QuestionId != Selection->QuestionId && NewPos->ForwardLink != &Menu) {\r
+          NewPos     = NewPos->ForwardLink;\r
+          SavedMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
+        }\r
+        if (SavedMenuOption->ThisTag->QuestionId == Selection->QuestionId) {\r
+          //\r
+          // Target Question found, find its MenuOption\r
+          //\r
+          Link = TopOfScreen;\r
+\r
+          for (Index = TopRow; Index <= BottomRow && Link != NewPos;) {\r
+            SavedMenuOption = MENU_OPTION_FROM_LINK (Link);\r
+            Index += SavedMenuOption->Skip;\r
+            Link = Link->ForwardLink;\r
+          }\r
+\r
+          if (Link != NewPos || Index > BottomRow) {\r
+            //\r
+            // NewPos is not in the current page, simply scroll page so that NewPos is in the end of the page\r
+            //\r
+            Link    = NewPos;\r
+            for (Index = TopRow; Index <= BottomRow; ) {\r
+              Link = Link->BackLink;\r
+              SavedMenuOption = MENU_OPTION_FROM_LINK (Link);\r
+              Index     += SavedMenuOption->Skip;\r
+            }\r
+            TopOfScreen     = Link->ForwardLink;\r
+\r
+            Repaint = TRUE;\r
+            NewLine = TRUE;\r
+            ControlFlag = CfRepaint;\r
+            break;\r
+          }\r
+        } else {\r
+          //\r
+          // Target Question not found, highlight the default menu option\r
+          //\r
+          NewPos = TopOfScreen;\r
+        }\r
+\r
+        Selection->QuestionId = 0;\r
+      }\r
+\r
+      if (NewPos != NULL && (MenuOption == NULL || NewPos != &MenuOption->Link)) {\r
+        if (MenuOption != NULL) {\r
+          //\r
+          // Remove highlight on last Menu Option\r
+          //\r
+          gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row);\r
+          ProcessOptions (Selection, MenuOption, FALSE, &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
+            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
+              gBS->FreePool (OutputString);\r
+            }\r
+\r
+            MenuOption->Row = OriginalRow;\r
+\r
+            gBS->FreePool (OptionString);\r
+          } else {\r
+            if (NewLine) {\r
+              if (MenuOption->GrayOut) {\r
+                gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_GRAYED | FIELD_BACKGROUND);\r
+              } else if (MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP) {\r
+                gST->ConOut->SetAttribute (gST->ConOut, SUBTITLE_TEXT | FIELD_BACKGROUND);\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 (MenuOption->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
+                gBS->FreePool (OutputString);\r
+              }\r
+\r
+              MenuOption->Row = OriginalRow;\r
+              gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
+            }\r
+          }\r
+        }\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
+        MenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
+        if (!IsSelectable (MenuOption)) {\r
+          ASSERT (ScreenOperation == UiNoOperation);\r
+          ScreenOperation = UiDown;\r
+          ControlFlag     = CfScreenOperation;\r
+          break;\r
+        }\r
+\r
+        //\r
+        // This is the current selected statement\r
+        //\r
+        Statement = MenuOption->ThisTag;\r
+        Selection->Statement = Statement;\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
+        ProcessOptions (Selection, MenuOption, FALSE, &OptionString);\r
+        if (OptionString != NULL) {\r
+          if (Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) {\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
+            gBS->FreePool (OutputString);\r
+          }\r
+\r
+          MenuOption->Row = OriginalRow;\r
+\r
+          gBS->FreePool (OptionString);\r
+        } else {\r
+          if (NewLine) {\r
+            OriginalRow = MenuOption->Row;\r
+\r
+            Width       = GetWidth (Statement, MenuOption->Handle);\r
+\r
+            for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) {\r
+              if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) {\r
+                PrintStringAt (MenuOption->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
+              gBS->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
+        //\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 ((Repaint || NewLine) && (gClassOfVfr != EFI_GENERAL_APPLICATION_SUBCLASS)) {\r
+        //\r
+        // Don't print anything if it is a NULL help token\r
+        //\r
+        if (MenuOption->ThisTag->Help == 0) {\r
+          StringPtr = 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], 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
+      ScreenOperation = UiNoOperation;\r
+      break;\r
+\r
+    case CfReadKey:\r
+      ControlFlag = CfScreenOperation;\r
+\r
+      //\r
+      // Wait for user's selection\r
+      //\r
+      do {\r
+        Status = UiWaitForSingleEvent (gST->ConIn->WaitForKey, 0, MinRefreshInterval);\r
+      } while (Status == EFI_TIMEOUT);\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
+      if (IsListEmpty (&Menu) && Key.UnicodeChar != CHAR_NULL) {\r
+        //\r
+        // If the screen has no menu items, and the user didn't select UiPrevious, or UiReset\r
+        //\r
+        break;\r
+      }\r
+\r
+      switch (Key.UnicodeChar) {\r
+      case CHAR_CARRIAGE_RETURN:\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
+      //  NOTE: we won't handle manual input numeric\r
+      //\r
+      case '+':\r
+      case '-':\r
+        Statement = MenuOption->ThisTag;\r
+        if ((Statement->Operand == EFI_IFR_DATE_OP)\r
+          || (Statement->Operand == EFI_IFR_TIME_OP)\r
+          || ((Statement->Operand == EFI_IFR_NUMERIC_OP) && (Statement->Step != 0))\r
+        ){\r
+          if (Key.UnicodeChar == '+') {\r
+            gDirection = SCAN_RIGHT;\r
+          } else {\r
+            gDirection = SCAN_LEFT;\r
+          }\r
+          Status = ProcessOptions (Selection, MenuOption, TRUE, &OptionString);\r
+          SafeFreePool (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 (MenuOption->ThisTag->Operand == EFI_IFR_CHECKBOX_OP && !MenuOption->GrayOut) {\r
+            ScreenOperation = UiSelect;\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) {\r
+                //\r
+                // Reset to standard default\r
+                //\r
+                DefaultId = EFI_HII_DEFAULT_CLASS_STANDARD;\r
+              }\r
+              ScreenOperation = gScanCodeToOperation[Index].ScreenOperation;\r
+              break;\r
+            }\r
+          }\r
+        }\r
+        break;\r
+      }\r
+      break;\r
+\r
+    case CfScreenOperation:\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 = MENU_OPTION_FROM_LINK (Link);\r
+          if (IsSelectable (NextMenuOption)) {\r
+            break;\r
+          }\r
+        }\r
+\r
+        if (Link == &Menu) {\r
+          ControlFlag = CfPrepareToReadKey;\r
+          break;\r
+        }\r
+      } else if (ScreenOperation == UiReset) {\r
+        //\r
+        // Press ESC to exit FormSet\r
+        //\r
+        Selection->Action = UI_ACTION_EXIT;\r
+        Selection->Statement = NULL;\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
+          break;\r
+        }\r
+      }\r
+      break;\r
+\r
+    case CfUiPrevious:\r
+      ControlFlag = CfCheckSelection;\r
+\r
+      if (IsListEmpty (&gMenuList)) {\r
+        Selection->Action = UI_ACTION_NONE;\r
+        if (IsListEmpty (&Menu)) {\r
+          ControlFlag = CfReadKey;\r
+        }\r
+        break;\r
+      }\r
+\r
+      //\r
+      // Remove the Cached page entry\r
+      //\r
+      UiRemoveMenuListEntry (Selection);\r
+\r
+      Selection->Action = UI_ACTION_REFRESH_FORM;\r
+      Selection->Statement = NULL;\r
+      break;\r
+\r
+    case CfUiSelect:\r
+      ControlFlag = CfCheckSelection;\r
+\r
+      Statement = MenuOption->ThisTag;\r
+      if ((Statement->Operand == EFI_IFR_TEXT_OP) ||\r
+          (Statement->Operand == EFI_IFR_DATE_OP) ||\r
+          (Statement->Operand == EFI_IFR_TIME_OP) ||\r
+          (Statement->Operand == EFI_IFR_NUMERIC_OP && Statement->Step != 0)) {\r
+        break;\r
+      }\r
+\r
+      //\r
+      // Keep highlight on current MenuOption\r
+      //\r
+      Selection->QuestionId = Statement->QuestionId;\r
+\r
+      switch (Statement->Operand) {\r
+      case EFI_IFR_REF_OP:\r
+        if (Statement->RefDevicePath != 0) {\r
+          //\r
+          // Goto another Hii Package list\r
+          //\r
+          ControlFlag = CfUiReset;\r
+          Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
+\r
+          StringPtr = GetToken (Statement->RefDevicePath, Selection->FormSet->HiiHandle);\r
+          if (StringPtr == NULL) {\r
+            //\r
+            // No device path string not found, exit\r
+            //\r
+            Selection->Action = UI_ACTION_EXIT;\r
+            Selection->Statement = NULL;\r
+            break;\r
+          }\r
+          BufferSize = StrLen (StringPtr) / 2;\r
+          DevicePath = AllocatePool (BufferSize);\r
+\r
+          HexStringToBufInReverseOrder ((UINT8 *) DevicePath, &BufferSize, StringPtr);\r
+          Selection->Handle = HiiLibDevicePathToHiiHandle (DevicePath);\r
+          if (Selection->Handle == NULL) {\r
+            //\r
+            // If target Hii Handle not found, exit\r
+            //\r
+            Selection->Action = UI_ACTION_EXIT;\r
+            Selection->Statement = NULL;\r
+            break;\r
+          }\r
+\r
+          gBS->FreePool (StringPtr);\r
+          gBS->FreePool (DevicePath);\r
+\r
+          CopyMem (&Selection->FormSetGuid, &Statement->RefFormSetId, sizeof (EFI_GUID));\r
+          Selection->FormId = Statement->RefFormId;\r
+          Selection->QuestionId = Statement->RefQuestionId;\r
+        } else if (!CompareGuid (&Statement->RefFormSetId, &gZeroGuid)) {\r
+          //\r
+          // Goto another Formset, check for uncommitted data\r
+          //\r
+          ControlFlag = CfUiReset;\r
+          Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
+\r
+          CopyMem (&Selection->FormSetGuid, &Statement->RefFormSetId, sizeof (EFI_GUID));\r
+          Selection->FormId = Statement->RefFormId;\r
+          Selection->QuestionId = Statement->RefQuestionId;\r
+        } else if (Statement->RefFormId != 0) {\r
+          //\r
+          // Goto another form inside this formset,\r
+          //\r
+          Selection->Action = UI_ACTION_REFRESH_FORM;\r
+\r
+          //\r
+          // Link current form so that we can always go back when someone hits the UiPrevious\r
+          //\r
+          UiAddMenuListEntry (Selection);\r
+\r
+          Selection->FormId = Statement->RefFormId;\r
+          Selection->QuestionId = Statement->RefQuestionId;\r
+        } else if (Statement->RefQuestionId != 0) {\r
+          //\r
+          // Goto another Question\r
+          //\r
+          Selection->QuestionId = Statement->RefQuestionId;\r
+\r
+          if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {\r
+            Selection->Action = UI_ACTION_REFRESH_FORM;\r
+          } else {\r
+            Repaint = TRUE;\r
+            NewLine = TRUE;\r
+            break;\r
+          }\r
+        }\r
+        break;\r
+\r
+      case EFI_IFR_ACTION_OP:\r
+        //\r
+        // Process the Config string <ConfigResp>\r
+        //\r
+        Status = ProcessQuestionConfig (Selection, Statement);\r
+\r
+        if (EFI_ERROR (Status)) {\r
+          break;\r
+        }\r
+\r
+        //\r
+        // The action button may change some Question value, so refresh the form\r
+        //\r
+        Selection->Action = UI_ACTION_REFRESH_FORM;\r
+        break;\r
+\r
+      case EFI_IFR_RESET_BUTTON_OP:\r
+        //\r
+        // Reset Question to default value specified by DefaultId\r
+        //\r
+        ControlFlag = CfUiDefault;\r
+        DefaultId = Statement->DefaultId;\r
+        break;\r
+\r
+      default:\r
+        //\r
+        // Editable Questions: oneof, ordered list, checkbox, numeric, string, password\r
+        //\r
+        UpdateKeyHelp (MenuOption, TRUE);\r
+        Status = ProcessOptions (Selection, MenuOption, TRUE, &OptionString);\r
+\r
+        if (EFI_ERROR (Status)) {\r
+          Repaint = TRUE;\r
+          NewLine = TRUE;\r
+          break;\r
+        }\r
+\r
+        if (OptionString != NULL) {\r
+          PrintStringAt (LocalScreen.LeftColumn + gPromptBlockWidth + 1, MenuOption->Row, OptionString);\r
+          gBS->FreePool (OptionString);\r
+        }\r
+\r
+        Selection->Action = UI_ACTION_REFRESH_FORM;\r
+        break;\r
+      }\r
+      break;\r
+\r
+    case CfUiReset:\r
+      //\r
+      // We are going to leave current FormSet, so check uncommited data in this FormSet\r
+      //\r
+      ControlFlag = CfCheckSelection;\r
+\r
+      if (gClassOfVfr == EFI_FRONT_PAGE_SUBCLASS) {\r
+        //\r
+        // There is no parent menu for FrontPage\r
+        //\r
+        Selection->Action = UI_ACTION_NONE;\r
+        Selection->Statement = MenuOption->ThisTag;\r
+        break;\r
+      }\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
+\r
+          Selection->Action = UI_ACTION_NONE;\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
+      UiFreeMenuList ();\r
+      gST->ConOut->ClearScreen (gST->ConOut);\r
+      return EFI_SUCCESS;\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->Sequence != 0) {\r
+          //\r
+          // In the middle or tail of the Date/Time op-code set, go left.\r
+          //\r
+          NewPos = NewPos->BackLink;\r
+        }\r
+      }\r
+      break;\r
+\r
+    case CfUiRight:\r
+      ControlFlag = CfCheckSelection;\r
+      if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) {\r
+        if (MenuOption->Sequence != 2) {\r
+          //\r
+          // In the middle or tail of the Date/Time op-code set, go left.\r
+          //\r
+          NewPos = NewPos->ForwardLink;\r
+        }\r
+      }\r
+      break;\r
+\r
+    case CfUiUp:\r
+      ControlFlag = CfCheckSelection;\r
+\r
+      SavedListEntry = TopOfScreen;\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 = MENU_OPTION_FROM_LINK (NewPos);\r
+        DistanceValue = PreviousMenuOption->Skip;\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
+        DistanceValue += AdjustDateAndTimePosition (TRUE, &NewPos);\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 ((INTN) MenuOption->Row - (INTN) DistanceValue < (INTN) TopRow) {\r
+          Repaint     = TRUE;\r
+          TopOfScreen = NewPos;\r
+        }\r
+\r
+        Difference = MoveToNextStatement (TRUE, &NewPos);\r
+        if ((INTN) MenuOption->Row - (INTN) DistanceValue < (INTN) TopRow) {\r
+          if (Difference > 0) {\r
+            //\r
+            // Previous focus MenuOption is above the TopOfScreen, so we need to scroll\r
+            //\r
+            TopOfScreen = NewPos;\r
+            Repaint     = TRUE;\r
+          }\r
+        }\r
+        if (Difference < 0) {\r
+          //\r
+          // We want to goto previous MenuOption, but finally we go down.\r
+          // it means that we hit the begining MenuOption that can be focused\r
+          // so we simply scroll to the top\r
+          //\r
+          if (SavedListEntry != Menu.ForwardLink) {\r
+            TopOfScreen = Menu.ForwardLink;\r
+            Repaint     = TRUE;\r
+          }\r
+        }\r
+\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
+        UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE);\r
+      } else {\r
+        SavedMenuOption = MenuOption;\r
+        MenuOption      = MENU_OPTION_FROM_LINK (NewPos);\r
+        if (!IsSelectable (MenuOption)) {\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
+      break;\r
+\r
+    case CfUiPageUp:\r
+      ControlFlag     = CfCheckSelection;\r
+\r
+      if (NewPos->BackLink == &Menu) {\r
+        NewLine = FALSE;\r
+        Repaint = FALSE;\r
+        break;\r
+      }\r
+\r
+      NewLine   = TRUE;\r
+      Repaint   = TRUE;\r
+      Link      = TopOfScreen;\r
+      PreviousMenuOption = MENU_OPTION_FROM_LINK (Link);\r
+      Index = BottomRow;\r
+      while ((Index >= TopRow) && (Link->BackLink != &Menu)) {\r
+        Index = Index - PreviousMenuOption->Skip;\r
+        Link = Link->BackLink;\r
+        PreviousMenuOption = MENU_OPTION_FROM_LINK (Link);\r
+      }\r
+\r
+      TopOfScreen = Link;\r
+      Difference = MoveToNextStatement (TRUE, &Link);\r
+      if (Difference > 0) {\r
+        //\r
+        // The focus MenuOption is above the TopOfScreen\r
+        //\r
+        TopOfScreen = Link;\r
+      } else if (Difference < 0) {\r
+        //\r
+        // This happens when there is no MenuOption can be focused from\r
+        // Current MenuOption to the first MenuOption\r
+        //\r
+        TopOfScreen = Menu.ForwardLink;\r
+      }\r
+      Index += Difference;\r
+      if (Index < TopRow) {\r
+        MenuOption = NULL;\r
+      }\r
+\r
+      if (NewPos == Link) {\r
+        Repaint = FALSE;\r
+        NewLine = FALSE;\r
+      } else {\r
+        NewPos = Link;\r
+      }\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
+      AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
+      AdjustDateAndTimePosition (TRUE, &NewPos);\r
+      break;\r
+\r
+    case CfUiPageDown:\r
+      ControlFlag     = CfCheckSelection;\r
+\r
+      if (NewPos->ForwardLink == &Menu) {\r
+        NewLine = FALSE;\r
+        Repaint = FALSE;\r
+        break;\r
+      }\r
+\r
+      NewLine = TRUE;\r
+      Repaint = TRUE;\r
+      Link    = TopOfScreen;\r
+      NextMenuOption = MENU_OPTION_FROM_LINK (Link);\r
+      Index = TopRow;\r
+      while ((Index <= BottomRow) && (Link->ForwardLink != &Menu)) {\r
+        Index = Index + NextMenuOption->Skip;\r
+        Link           = Link->ForwardLink;\r
+        NextMenuOption = MENU_OPTION_FROM_LINK (Link);\r
+      }\r
+\r
+      Index += MoveToNextStatement (FALSE, &Link);\r
+      if (Index > BottomRow) {\r
+        //\r
+        // There are more MenuOption needing scrolling\r
+        //\r
+        TopOfScreen = Link;\r
+        MenuOption = NULL;\r
+      }\r
+      if (NewPos == Link && Index <= BottomRow) {\r
+        //\r
+        // Finally we know that NewPos is the last MenuOption can be focused.\r
+        //\r
+        NewLine = FALSE;\r
+        Repaint = FALSE;\r
+      } else {\r
+        NewPos  = Link;\r
+      }\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
+      AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
+      AdjustDateAndTimePosition (TRUE, &NewPos);\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
+      SavedListEntry = NewPos;\r
+      DistanceValue  = AdjustDateAndTimePosition (FALSE, &NewPos);\r
+\r
+      if (NewPos->ForwardLink != &Menu) {\r
+        MenuOption      = MENU_OPTION_FROM_LINK (NewPos);\r
+        NewLine         = TRUE;\r
+        NewPos          = NewPos->ForwardLink;\r
+        NextMenuOption  = MENU_OPTION_FROM_LINK (NewPos);\r
+\r
+        DistanceValue  += NextMenuOption->Skip;\r
+        DistanceValue  += MoveToNextStatement (FALSE, &NewPos);\r
+        //\r
+        // An option might be multi-line, so we need to reflect that data in the overall skip value\r
+        //\r
+        UpdateOptionSkipLines (Selection, NextMenuOption, &OptionString, SkipValue);\r
+\r
+        Temp = MenuOption->Row + MenuOption->Skip + DistanceValue - 1;\r
+        if ((MenuOption->Row + MenuOption->Skip == BottomRow + 1) &&\r
+            (NextMenuOption->ThisTag->Operand == EFI_IFR_DATE_OP ||\r
+             NextMenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)\r
+            ) {\r
+          Temp ++;\r
+        }\r
+\r
+        //\r
+        // If we are going to scroll, update TopOfScreen\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 = MENU_OPTION_FROM_LINK (TopOfScreen);\r
+\r
+            //\r
+            // If bottom op-code is more than one line or top op-code is more than one line\r
+            //\r
+            if ((DistanceValue > 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 = MENU_OPTION_FROM_LINK (TopOfScreen);\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 = MENU_OPTION_FROM_LINK (TopOfScreen);\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 = MENU_OPTION_FROM_LINK (TopOfScreen);\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
+        MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);\r
+\r
+        UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE);\r
+\r
+      } else {\r
+        SavedMenuOption = MenuOption;\r
+        MenuOption      = MENU_OPTION_FROM_LINK (NewPos);\r
+        if (!IsSelectable (MenuOption)) {\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
+      break;\r
+\r
+    case CfUiSave:\r
+      ControlFlag = CfCheckSelection;\r
+\r
+      //\r
+      // Submit the form\r
+      //\r
+      Status = SubmitForm (Selection->FormSet, Selection->Form);\r
+\r
+      if (!EFI_ERROR (Status)) {\r
+        UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE);\r
+        UpdateStatusBar (NV_UPDATE_REQUIRED, MenuOption->ThisTag->QuestionFlags, FALSE);\r
+      } else {\r
+        do {\r
+          CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gSaveFailed, gPressEnter, gEmptyString);\r
+        } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+\r
+        Repaint = TRUE;\r
+        NewLine = TRUE;\r
+      }\r
+      break;\r
+\r
+    case CfUiDefault:\r
+      ControlFlag = CfCheckSelection;\r
+\r
+      Status = ExtractFormDefault (Selection->FormSet, Selection->Form, DefaultId);\r
+\r
+      if (!EFI_ERROR (Status)) {\r
+        Selection->Action = UI_ACTION_REFRESH_FORM;\r
+        Selection->Statement = NULL;\r
+\r
+        //\r
+        // Show NV update flag on status bar\r
+        //\r
+        gNvUpdateRequired = TRUE;\r
+      }\r
+      break;\r
+\r
+    case CfUiNoOperation:\r
+      ControlFlag = CfCheckSelection;\r
+      break;\r
+\r
+    case CfExit:\r
+      UiFreeRefreshList ();\r
+\r
+      gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
+      gST->ConOut->SetCursorPosition (gST->ConOut, 0, Row + 4);\r
+      gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
+      gST->ConOut->OutputString (gST->ConOut, L"\n");\r
+\r
+      return EFI_SUCCESS;\r
+\r
+    default:\r
+      break;\r
+    }\r
+  }\r
+}\r