]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/SetupBrowserDxe/Ui.c
Rollback patch 14537 & 14538, because patch 14537 is not tested by Laszlo Ersek,...
[mirror_edk2.git] / MdeModulePkg / Universal / SetupBrowserDxe / Ui.c
diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Ui.c b/MdeModulePkg/Universal/SetupBrowserDxe/Ui.c
new file mode 100644 (file)
index 0000000..7c246b6
--- /dev/null
@@ -0,0 +1,4027 @@
+/** @file\r
+Utility functions for User Interface functions.\r
+\r
+Copyright (c) 2004 - 2013, Intel Corporation. All rights reserved.<BR>\r
+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 "Setup.h"\r
+\r
+LIST_ENTRY          gMenuOption;\r
+LIST_ENTRY          gMenuList;\r
+MENU_REFRESH_ENTRY  *gMenuRefreshHead;                // Menu list used for refresh timer opcode.\r
+MENU_REFRESH_ENTRY  *gMenuEventGuidRefreshHead;       // Menu list used for refresh event guid opcode.\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_LEFT,\r
+    UiLeft,\r
+  },\r
+  {\r
+    SCAN_RIGHT,\r
+    UiRight,\r
+  }\r
+};\r
+\r
+UINTN mScanCodeNumber = sizeof (gScanCodeToOperation) / sizeof (gScanCodeToOperation[0]);\r
+\r
+SCREEN_OPERATION_T0_CONTROL_FLAG  gScreenOperationToControlFlag[] = {\r
+  {\r
+    UiNoOperation,\r
+    CfUiNoOperation,\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
+    UiPageUp,\r
+    CfUiPageUp,\r
+  },\r
+  {\r
+    UiPageDown,\r
+    CfUiPageDown\r
+  }, \r
+  {\r
+    UiHotKey,\r
+    CfUiHotKey\r
+  }\r
+};\r
+\r
+BOOLEAN  mInputError;\r
+BOOLEAN GetLineByWidthFinished = FALSE;\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
+**/\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 (&gMenuOption);\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 (&gMenuOption)) {\r
+    MenuOption = MENU_OPTION_FROM_LINK (gMenuOption.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
+      FreePool (MenuOption->Description);\r
+    }\r
+    FreePool (MenuOption);\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Create a menu with specified formset GUID and form ID, and add it as a child\r
+  of the given parent menu.\r
+\r
+  @param  Parent                 The parent of menu to be added.\r
+  @param  HiiHandle              Hii handle related to this formset.\r
+  @param  FormSetGuid            The Formset Guid of menu to be added.\r
+  @param  FormId                 The Form ID of menu to be added.\r
+\r
+  @return A pointer to the newly added menu or NULL if memory is insufficient.\r
+\r
+**/\r
+UI_MENU_LIST *\r
+UiAddMenuList (\r
+  IN OUT UI_MENU_LIST     *Parent,\r
+  IN EFI_HII_HANDLE       HiiHandle,\r
+  IN EFI_GUID             *FormSetGuid,\r
+  IN UINT16               FormId\r
+  )\r
+{\r
+  UI_MENU_LIST  *MenuList;\r
+\r
+  MenuList = AllocateZeroPool (sizeof (UI_MENU_LIST));\r
+  if (MenuList == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  MenuList->Signature = UI_MENU_LIST_SIGNATURE;\r
+  InitializeListHead (&MenuList->ChildListHead);\r
+\r
+  MenuList->HiiHandle = HiiHandle;\r
+  CopyMem (&MenuList->FormSetGuid, FormSetGuid, sizeof (EFI_GUID));\r
+  MenuList->FormId = FormId;\r
+  MenuList->Parent = Parent;\r
+\r
+  if (Parent == NULL) {\r
+    //\r
+    // If parent is not specified, it is the root Form of a Formset\r
+    //\r
+    InsertTailList (&gMenuList, &MenuList->Link);\r
+  } else {\r
+    InsertTailList (&Parent->ChildListHead, &MenuList->Link);\r
+  }\r
+\r
+  return MenuList;\r
+}\r
+\r
+\r
+/**\r
+  Search Menu with given FormId, FormSetGuid and Handle in all cached menu list.\r
+\r
+  @param  Parent                 The parent of menu to search.\r
+  @param  Handle                 Hii handle related to this formset.\r
+  @param  FormSetGuid            The Formset GUID of the menu to search.  \r
+  @param  FormId                 The Form ID of menu to search.\r
+\r
+  @return A pointer to menu found or NULL if not found.\r
+\r
+**/\r
+UI_MENU_LIST *\r
+UiFindChildMenuList (\r
+  IN UI_MENU_LIST         *Parent,\r
+  IN EFI_HII_HANDLE       Handle,\r
+  IN EFI_GUID             *FormSetGuid, \r
+  IN UINT16               FormId\r
+  )\r
+{\r
+  LIST_ENTRY      *Link;\r
+  UI_MENU_LIST    *Child;\r
+  UI_MENU_LIST    *MenuList;\r
+\r
+  ASSERT (Parent != NULL);\r
+\r
+  if (Parent->FormId == FormId && CompareGuid (FormSetGuid, &Parent->FormSetGuid) && Parent->HiiHandle == Handle) {\r
+    return Parent;\r
+  }\r
+\r
+  Link = GetFirstNode (&Parent->ChildListHead);\r
+  while (!IsNull (&Parent->ChildListHead, Link)) {\r
+    Child = UI_MENU_LIST_FROM_LINK (Link);\r
+\r
+    MenuList = UiFindChildMenuList (Child, Handle, FormSetGuid, FormId);\r
+    if (MenuList != NULL) {\r
+      return MenuList;\r
+    }\r
+\r
+    Link = GetNextNode (&Parent->ChildListHead, Link);\r
+  }\r
+\r
+  return NULL;\r
+}\r
+\r
+\r
+/**\r
+  Search Menu with given Handle, FormSetGuid and FormId in all cached menu list.\r
+\r
+  @param  Handle                 Hii handle related to this formset.\r
+  @param  FormSetGuid            The Formset GUID of the menu to search.\r
+  @param  FormId                 The Form ID of menu to search.\r
+\r
+  @return A pointer to menu found or NULL if not found.\r
+\r
+**/\r
+UI_MENU_LIST *\r
+UiFindMenuList (\r
+  IN EFI_HII_HANDLE       Handle,\r
+  IN EFI_GUID             *FormSetGuid,\r
+  IN UINT16               FormId\r
+  )\r
+{\r
+  LIST_ENTRY      *Link;\r
+  UI_MENU_LIST    *MenuList;\r
+  UI_MENU_LIST    *Child;\r
+\r
+  Link = GetFirstNode (&gMenuList);\r
+  while (!IsNull (&gMenuList, Link)) {\r
+    MenuList = UI_MENU_LIST_FROM_LINK (Link);\r
+\r
+    Child = UiFindChildMenuList(MenuList, Handle, FormSetGuid, FormId);\r
+    if (Child != NULL) {\r
+\r
+      //\r
+      // If this form already in the menu history list,\r
+      // just free the list between old this form.\r
+      //\r
+      UiFreeMenuList(&Child->ChildListHead);\r
+      return Child;\r
+    }\r
+\r
+    Link = GetNextNode (&gMenuList, Link);\r
+  }\r
+\r
+  return NULL;\r
+}\r
+\r
+/**\r
+  Free Menu list linked list.\r
+\r
+  @param  MenuListHead    One Menu list point in the menu list.\r
+\r
+**/\r
+VOID\r
+UiFreeMenuList (\r
+  LIST_ENTRY   *MenuListHead\r
+  )\r
+{\r
+  UI_MENU_LIST    *MenuList;\r
+\r
+  while (!IsListEmpty (MenuListHead)) {\r
+    MenuList = UI_MENU_LIST_FROM_LINK (MenuListHead->ForwardLink);\r
+    RemoveEntryList (&MenuList->Link);\r
+    \r
+    UiFreeMenuList(&MenuList->ChildListHead);\r
+    FreePool (MenuList);\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
+    FreePool (gMenuRefreshHead);\r
+    gMenuRefreshHead = OldMenuRefreshEntry;\r
+  }\r
+\r
+  while (gMenuEventGuidRefreshHead != NULL) {\r
+    OldMenuRefreshEntry = gMenuEventGuidRefreshHead->Next;\r
+    if (gMenuEventGuidRefreshHead != NULL) {\r
+      gBS->CloseEvent(gMenuEventGuidRefreshHead->Event);\r
+    }\r
+    FreePool (gMenuEventGuidRefreshHead);\r
+    gMenuEventGuidRefreshHead = OldMenuRefreshEntry;\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Process option string for date/time opcode.\r
+\r
+  @param  MenuOption              Menu option point to date/time.\r
+  @param  OptionString            Option string input for process.\r
+  @param  AddOptCol               Whether need to update MenuOption->OptCol. \r
+\r
+**/\r
+VOID \r
+ProcessStringForDateTime (\r
+  UI_MENU_OPTION                  *MenuOption,\r
+  CHAR16                          *OptionString,\r
+  BOOLEAN                         AddOptCol\r
+  )\r
+{\r
+  UINTN Index;\r
+  UINTN Count;\r
+  FORM_BROWSER_STATEMENT          *Statement;\r
+\r
+  ASSERT (MenuOption != NULL && OptionString != NULL);\r
+  \r
+  Statement = MenuOption->ThisTag;\r
+  \r
+  //\r
+  // If leading spaces on OptionString - remove the spaces\r
+  //\r
+  for (Index = 0; OptionString[Index] == L' '; Index++) {\r
+    //\r
+    // Base on the blockspace to get the option column info.\r
+    //\r
+    if (AddOptCol) {\r
+      MenuOption->OptCol++;\r
+    }\r
+  }\r
+  \r
+  for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) {\r
+    OptionString[Count] = OptionString[Index];\r
+    Count++;\r
+  }\r
+  OptionString[Count] = CHAR_NULL;\r
+  \r
+  //\r
+  // Enable to suppress field in the opcode base on the flag.\r
+  //\r
+  if (Statement->Operand == EFI_IFR_DATE_OP) {\r
+    //\r
+    // OptionString format is: <**:  **: ****>\r
+    //                        |month|day|year|\r
+    //                          4     3    5\r
+    //\r
+    if ((Statement->Flags & EFI_QF_DATE_MONTH_SUPPRESS) && (MenuOption->Sequence == 0)) {\r
+      //\r
+      // At this point, only "<**:" in the optionstring. \r
+      // Clean the day's ** field, after clean, the format is "<  :"\r
+      //\r
+      SetUnicodeMem (&OptionString[1], 2, L' ');\r
+    } else if ((Statement->Flags & EFI_QF_DATE_DAY_SUPPRESS) && (MenuOption->Sequence == 1)) {\r
+      //\r
+      // At this point, only "**:" in the optionstring. \r
+      // Clean the month's "**" field, after clean, the format is "  :"\r
+      //                \r
+      SetUnicodeMem (&OptionString[0], 2, L' ');\r
+    } else if ((Statement->Flags & EFI_QF_DATE_YEAR_SUPPRESS) && (MenuOption->Sequence == 2)) {\r
+      //\r
+      // At this point, only "****>" in the optionstring. \r
+      // Clean the year's "****" field, after clean, the format is "  >"\r
+      //                \r
+      SetUnicodeMem (&OptionString[0], 4, L' ');\r
+    }\r
+  } else if (Statement->Operand == EFI_IFR_TIME_OP) {\r
+    //\r
+    // OptionString format is: <**:  **:    **>\r
+    //                        |hour|minute|second|\r
+    //                          4     3      3\r
+    //\r
+    if ((Statement->Flags & QF_TIME_HOUR_SUPPRESS) && (MenuOption->Sequence == 0)) {\r
+      //\r
+      // At this point, only "<**:" in the optionstring. \r
+      // Clean the hour's ** field, after clean, the format is "<  :"\r
+      //\r
+      SetUnicodeMem (&OptionString[1], 2, L' ');\r
+    } else if ((Statement->Flags & QF_TIME_MINUTE_SUPPRESS) && (MenuOption->Sequence == 1)) {\r
+      //\r
+      // At this point, only "**:" in the optionstring. \r
+      // Clean the minute's "**" field, after clean, the format is "  :"\r
+      //                \r
+      SetUnicodeMem (&OptionString[0], 2, L' ');\r
+    } else if ((Statement->Flags & QF_TIME_SECOND_SUPPRESS) && (MenuOption->Sequence == 2)) {\r
+      //\r
+      // At this point, only "**>" in the optionstring. \r
+      // Clean the second's "**" field, after clean, the format is "  >"\r
+      //                \r
+      SetUnicodeMem (&OptionString[0], 2, L' ');\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  Refresh question.\r
+\r
+  @param     MenuRefreshEntry    Menu refresh structure which has info about the refresh question.\r
+**/\r
+EFI_STATUS \r
+RefreshQuestion (\r
+  IN   MENU_REFRESH_ENTRY    *MenuRefreshEntry\r
+  )\r
+{\r
+  CHAR16                          *OptionString;\r
+  EFI_STATUS                      Status;\r
+  UI_MENU_SELECTION               *Selection;\r
+  FORM_BROWSER_STATEMENT          *Question;\r
+\r
+  Selection = MenuRefreshEntry->Selection;\r
+  Question = MenuRefreshEntry->MenuOption->ThisTag;\r
+\r
+  Status = GetQuestionValue (Selection->FormSet, Selection->Form, Question, GetSetValueWithHiiDriver);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  OptionString = NULL;\r
+  ProcessOptions (Selection, MenuRefreshEntry->MenuOption, FALSE, &OptionString);\r
+\r
+  if (OptionString != NULL) {\r
+    //\r
+    // If old Text is longer than new string, need to clean the old string before paint the newer.\r
+    // This option is no need for time/date opcode, because time/data opcode has fixed string length.\r
+    //\r
+    if ((MenuRefreshEntry->MenuOption->ThisTag->Operand != EFI_IFR_DATE_OP) &&\r
+      (MenuRefreshEntry->MenuOption->ThisTag->Operand != EFI_IFR_TIME_OP)) {\r
+      ClearLines (\r
+        MenuRefreshEntry->CurrentColumn, \r
+        MenuRefreshEntry->CurrentColumn + gOptionBlockWidth - 1,\r
+        MenuRefreshEntry->CurrentRow,\r
+        MenuRefreshEntry->CurrentRow,\r
+        PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND\r
+        );\r
+    }\r
+\r
+    gST->ConOut->SetAttribute (gST->ConOut, MenuRefreshEntry->CurrentAttribute);\r
+    ProcessStringForDateTime(MenuRefreshEntry->MenuOption, OptionString, FALSE);\r
+    PrintStringAt (MenuRefreshEntry->CurrentColumn, MenuRefreshEntry->CurrentRow, OptionString);\r
+    FreePool (OptionString);\r
+  }\r
+\r
+  //\r
+  // Question value may be changed, need invoke its Callback()\r
+  //\r
+  Status = ProcessCallBackFunction (Selection, Question, EFI_BROWSER_ACTION_CHANGING, FALSE);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Refresh the question which has refresh guid event attribute.\r
+  \r
+  @param Event    The event which has this function related.     \r
+  @param Context  The input context info related to this event or the status code return to the caller.\r
+**/\r
+VOID\r
+EFIAPI\r
+RefreshQuestionNotify(\r
+  IN      EFI_EVENT Event,\r
+  IN      VOID      *Context\r
+  )\r
+{\r
+  MENU_REFRESH_ENTRY              *MenuRefreshEntry;\r
+  UI_MENU_SELECTION               *Selection;\r
+\r
+  //\r
+  // Reset FormPackage update flag\r
+  //\r
+  mHiiPackageListUpdated = FALSE;\r
+\r
+  MenuRefreshEntry = (MENU_REFRESH_ENTRY *)Context;\r
+  ASSERT (MenuRefreshEntry != NULL);\r
+  Selection = MenuRefreshEntry->Selection;\r
+\r
+  RefreshQuestion (MenuRefreshEntry);\r
+  \r
+  if (mHiiPackageListUpdated) {\r
+    //\r
+    // Package list is updated, force to reparse IFR binary of target Formset\r
+    //\r
+    mHiiPackageListUpdated = FALSE;\r
+    Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
+  } \r
+}\r
+\r
+\r
+/**\r
+  Refresh screen.\r
+\r
+**/\r
+EFI_STATUS\r
+RefreshForm (\r
+  VOID\r
+  )\r
+{\r
+  MENU_REFRESH_ENTRY              *MenuRefreshEntry;\r
+  EFI_STATUS                      Status;\r
+  UI_MENU_SELECTION               *Selection;\r
+\r
+  if (gMenuRefreshHead != NULL) {\r
+    //\r
+    // call from refresh interval process.\r
+    //\r
+    MenuRefreshEntry = gMenuRefreshHead;\r
+    Selection = MenuRefreshEntry->Selection;\r
+    //\r
+    // Reset FormPackage update flag\r
+    //\r
+    mHiiPackageListUpdated = FALSE;\r
+\r
+    do {\r
+      Status = RefreshQuestion (MenuRefreshEntry);\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+\r
+      MenuRefreshEntry = MenuRefreshEntry->Next;\r
+\r
+    } while (MenuRefreshEntry != NULL);\r
+\r
+    if (mHiiPackageListUpdated) {\r
+      //\r
+      // Package list is updated, force to reparse IFR binary of target Formset\r
+      //\r
+      mHiiPackageListUpdated = FALSE;\r
+      Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
+      return EFI_SUCCESS;\r
+    }\r
+  }\r
+\r
+  return EFI_TIMEOUT;\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
+          Status = 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  Form                   The form this statement belong to.\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
+  @retval Pointer                Pointer to the added Menu Option.\r
+\r
+**/\r
+UI_MENU_OPTION *\r
+UiAddMenuOption (\r
+  IN CHAR16                  *String,\r
+  IN EFI_HII_HANDLE          Handle,\r
+  IN FORM_BROWSER_FORM       *Form,\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
+  MenuOption = NULL;\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 (EvaluateExpressionList(Statement->Expression, FALSE, NULL, NULL) == ExpressGrayOut ) {\r
+      MenuOption->GrayOut = TRUE;\r
+    } else {\r
+      MenuOption->GrayOut = FALSE;\r
+    }\r
+\r
+    //\r
+    // If the form or the question has the lock attribute, deal same as grayout.\r
+    //\r
+    if (Form->Locked || Statement->Locked) {\r
+      MenuOption->GrayOut = TRUE;\r
+    }\r
+    \r
+    switch (Statement->Operand) {\r
+    case EFI_IFR_ORDERED_LIST_OP:\r
+    case EFI_IFR_ONE_OF_OP:\r
+    case EFI_IFR_NUMERIC_OP:\r
+    case EFI_IFR_TIME_OP:\r
+    case EFI_IFR_DATE_OP:\r
+    case EFI_IFR_CHECKBOX_OP:\r
+    case EFI_IFR_PASSWORD_OP:\r
+    case EFI_IFR_STRING_OP:\r
+      //\r
+      // User could change the value of these items\r
+      //\r
+      MenuOption->IsQuestion = TRUE;\r
+      break;\r
+\r
+    case EFI_IFR_TEXT_OP:\r
+      if (FeaturePcdGet (PcdBrowserGrayOutTextStatement)) {\r
+        //\r
+        // Initializing GrayOut option as TRUE for Text setup options \r
+        // so that those options will be Gray in colour and un selectable.\r
+        //\r
+        MenuOption->GrayOut = TRUE;\r
+      }\r
+      //\r
+      // break skipped on purpose\r
+      //\r
+    default:\r
+      MenuOption->IsQuestion = FALSE;\r
+      break;\r
+    }\r
+\r
+    if ((Statement->ValueExpression != NULL) ||\r
+        ((Statement->QuestionFlags & EFI_IFR_FLAG_READ_ONLY) != 0)) {\r
+      MenuOption->ReadOnly = TRUE;\r
+      if (FeaturePcdGet (PcdBrowerGrayOutReadOnlyMenu)) {\r
+        MenuOption->GrayOut = TRUE;\r
+      }\r
+    }\r
+\r
+    InsertTailList (&gMenuOption, &MenuOption->Link);\r
+  }\r
+\r
+  return MenuOption;\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
+EFIAPI\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
+  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
+  //\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
+  VA_START (Marker, KeyValue);\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
+  VA_END (Marker);\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
+  VA_START (Marker, KeyValue);\r
+  CreateSharedPopUp (LargestString, NumberOfLines, Marker);\r
+  VA_END (Marker);\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
+          FreePool (TempString);\r
+          FreePool (BufferedString);\r
+          gST->ConOut->SetAttribute (gST->ConOut, CurrentAttribute);\r
+          gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
+          return EFI_DEVICE_ERROR;\r
+\r
+        default:\r
+          break;\r
+        }\r
+\r
+        break;\r
+\r
+      case CHAR_CARRIAGE_RETURN:\r
+        SelectionComplete = TRUE;\r
+        FreePool (TempString);\r
+        FreePool (BufferedString);\r
+        gST->ConOut->SetAttribute (gST->ConOut, CurrentAttribute);\r
+        gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
+        return EFI_SUCCESS;\r
+        break;\r
+\r
+      case CHAR_BACKSPACE:\r
+        if (StringBuffer[0] != CHAR_NULL) {\r
+          for (Index = 0; StringBuffer[Index] != CHAR_NULL; Index++) {\r
+            TempString[Index] = StringBuffer[Index];\r
+          }\r
+          //\r
+          // Effectively truncate string by 1 character\r
+          //\r
+          TempString[Index - 1] = CHAR_NULL;\r
+          StrCpy (StringBuffer, TempString);\r
+        }\r
+        //\r
+        // break skipped on purpose\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
+EFIAPI\r
+CreateMultiStringPopUp (\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  Selection              Current Selction info.\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  UI_MENU_SELECTION           *Selection,\r
+  IN  UINTN                       MessageType,\r
+  IN  UINT8                       Flags,\r
+  IN  BOOLEAN                     State\r
+  )\r
+{\r
+  UINTN           Index;\r
+  CHAR16          *NvUpdateMessage;\r
+  CHAR16          *InputErrorMessage;\r
+  LIST_ENTRY              *Link;\r
+  FORM_BROWSER_FORMSET    *LocalFormSet;\r
+  FORM_BROWSER_STATEMENT  *Question;\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
+      mInputError = TRUE;\r
+    } else {\r
+      gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextHighlightColor));\r
+      for (Index = 0; Index < (GetStringWidth (InputErrorMessage) - 2) / 2; Index++) {\r
+        PrintAt (gScreenDimensions.LeftColumn + gPromptBlockWidth + Index, gScreenDimensions.BottomRow - 1, L"  ");\r
+      }\r
+\r
+      mInputError = FALSE;\r
+    }\r
+    break;\r
+\r
+  case NV_UPDATE_REQUIRED:\r
+    //\r
+    // Global setting support. Show configuration change on every form.\r
+    //\r
+    if (State) {\r
+      gResetRequired    = (BOOLEAN) (gResetRequired | ((Flags & EFI_IFR_FLAG_RESET_REQUIRED) == EFI_IFR_FLAG_RESET_REQUIRED));\r
+\r
+      if (Selection != NULL && Selection->Statement != NULL) {\r
+        Question = Selection->Statement;\r
+        if (Question->Storage != NULL || Question->Operand == EFI_IFR_DATE_OP || Question->Operand == EFI_IFR_TIME_OP) {\r
+          //\r
+          // Update only for Question value that need to be saved into Storage.\r
+          //\r
+          Selection->Form->NvUpdateRequired = TRUE;\r
+        }\r
+      }\r
+      \r
+      if (Selection == NULL || IsNvUpdateRequired (Selection->FormSet)) {\r
+        gST->ConOut->SetAttribute (gST->ConOut, INFO_TEXT);\r
+        PrintStringAt (\r
+          gScreenDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth,\r
+          gScreenDimensions.BottomRow - 1,\r
+          NvUpdateMessage\r
+          );\r
+      }\r
+    } else {\r
+      gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextHighlightColor));\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
+    break;\r
+\r
+  case REFRESH_STATUS_BAR:\r
+    if (mInputError) {\r
+      UpdateStatusBar (Selection, INPUT_ERROR, Flags, TRUE);\r
+    }\r
+\r
+    switch (gBrowserSettingScope) {\r
+    case SystemLevel:\r
+      //\r
+      // Check the maintain list to see whether there is any change.\r
+      //\r
+      Link = GetFirstNode (&gBrowserFormSetList);\r
+      while (!IsNull (&gBrowserFormSetList, Link)) {\r
+        LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);\r
+        if (IsNvUpdateRequired(LocalFormSet)) {\r
+          UpdateStatusBar (NULL, NV_UPDATE_REQUIRED, Flags, TRUE);\r
+          break;\r
+        }\r
+        Link = GetNextNode (&gBrowserFormSetList, Link);\r
+      }\r
+      break;\r
+    case FormSetLevel:\r
+    case FormLevel:\r
+      UpdateStatusBar (Selection, NV_UPDATE_REQUIRED, Flags, TRUE);\r
+    default:\r
+      break;\r
+    }\r
+\r
+    break;\r
+\r
+  default:\r
+    break;\r
+  }\r
+\r
+  FreePool (InputErrorMessage);\r
+  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
+    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 (UINT16) (Width - LEFT_SKIPPED_COLUMNS);\r
+}\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
+  The output string format is:\r
+    Glyph Info + String info + '\0'.\r
+\r
+  In the code, it deals \r,\n,\r\n same as \n\r, also it not process the \r or \g.\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  GlyphWidth             The glyph width of the begin of the char in the string.\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 \r
+  buffer, include extra glyph info and '\0' info.\r
+\r
+**/\r
+UINT16\r
+GetLineByWidth (\r
+  IN      CHAR16                      *InputString,\r
+  IN      UINT16                      LineWidth,\r
+  IN OUT  UINT16                      *GlyphWidth,\r
+  IN OUT  UINTN                       *Index,\r
+  OUT     CHAR16                      **OutputString\r
+  )\r
+{\r
+  UINT16          StrOffset;\r
+  UINT16          GlyphOffset;\r
+  UINT16          OriginalGlyphWidth;\r
+  BOOLEAN         ReturnFlag;\r
+  UINT16          LastSpaceOffset;\r
+  UINT16          LastGlyphWidth;\r
+\r
+  if (InputString == NULL || Index == NULL || OutputString == NULL) {\r
+    return 0;\r
+  }\r
+\r
+  if (LineWidth == 0 || *GlyphWidth == 0) {\r
+    return 0;\r
+  }\r
+\r
+  //\r
+  // Save original glyph width.\r
+  //\r
+  OriginalGlyphWidth = *GlyphWidth;\r
+  LastGlyphWidth     = OriginalGlyphWidth;\r
+  ReturnFlag         = FALSE;\r
+  LastSpaceOffset    = 0;\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 (StrOffset = 0, GlyphOffset = 0; GlyphOffset <= LineWidth; StrOffset++) {\r
+    switch (InputString[*Index + StrOffset]) {\r
+      case NARROW_CHAR:\r
+        *GlyphWidth = 1;\r
+        break;\r
+\r
+      case WIDE_CHAR:\r
+        *GlyphWidth = 2;\r
+        break;\r
+\r
+      case CHAR_CARRIAGE_RETURN:\r
+      case CHAR_LINEFEED:\r
+      case CHAR_NULL:\r
+        ReturnFlag = TRUE;\r
+        break;\r
+\r
+      default:\r
+        GlyphOffset = GlyphOffset + *GlyphWidth;\r
+\r
+        //\r
+        // Record the last space info in this line. Will be used in rewind.\r
+        //\r
+        if ((InputString[*Index + StrOffset] == CHAR_SPACE) && (GlyphOffset <= LineWidth)) {\r
+          LastSpaceOffset = StrOffset;\r
+          LastGlyphWidth  = *GlyphWidth;\r
+        }\r
+        break;\r
+    }\r
+\r
+    if (ReturnFlag) {\r
+      break;\r
+    }\r
+  } \r
+\r
+  //\r
+  // Rewind the string from the maximum size until we see a space to break the line\r
+  //\r
+  if (GlyphOffset > LineWidth) {\r
+    //\r
+    // Rewind the string to last space char in this line.\r
+    //\r
+    if (LastSpaceOffset != 0) {\r
+      StrOffset   = LastSpaceOffset;\r
+      *GlyphWidth = LastGlyphWidth;\r
+    } else {\r
+      //\r
+      // Roll back to last char in the line width.\r
+      //\r
+      StrOffset--;\r
+    }\r
+  }\r
+\r
+  //\r
+  // The CHAR_NULL has process last time, this time just return 0 to stand for the end.\r
+  //\r
+  if (StrOffset == 0 && (InputString[*Index + StrOffset] == CHAR_NULL)) {\r
+    return 0;\r
+  }\r
+\r
+  //\r
+  // Need extra glyph info and '\0' info, so +2.\r
+  //\r
+  *OutputString = AllocateZeroPool (((UINTN) (StrOffset + 2) * sizeof(CHAR16)));\r
+  if (*OutputString == NULL) {\r
+    return 0;\r
+  }\r
+\r
+  //\r
+  // Save the glyph info at the begin of the string, will used by Print function.\r
+  //\r
+  if (OriginalGlyphWidth == 1) {\r
+    *(*OutputString) = NARROW_CHAR;\r
+  } else  {\r
+    *(*OutputString) = WIDE_CHAR;\r
+  }\r
+\r
+  CopyMem ((*OutputString) + 1, &InputString[*Index], StrOffset * sizeof(CHAR16));\r
+\r
+  if (InputString[*Index + StrOffset] == CHAR_SPACE) {\r
+    //\r
+    // Skip the space info at the begin of next line.\r
+    //  \r
+    *Index = (UINT16) (*Index + StrOffset + 1);\r
+  } else if (InputString[*Index + StrOffset] == CHAR_LINEFEED) {\r
+    //\r
+    // Skip the /n or /n/r info.\r
+    //\r
+    if (InputString[*Index + StrOffset + 1] == CHAR_CARRIAGE_RETURN) {\r
+      *Index = (UINT16) (*Index + StrOffset + 2);\r
+    } else {\r
+      *Index = (UINT16) (*Index + StrOffset + 1);\r
+    }\r
+  } else if (InputString[*Index + StrOffset] == CHAR_CARRIAGE_RETURN) {\r
+    //\r
+    // Skip the /r or /r/n info.\r
+    //  \r
+    if (InputString[*Index + StrOffset + 1] == CHAR_LINEFEED) {\r
+      *Index = (UINT16) (*Index + StrOffset + 2);\r
+    } else {\r
+      *Index = (UINT16) (*Index + StrOffset + 1);\r
+    }\r
+  } else {\r
+    *Index = (UINT16) (*Index + StrOffset);\r
+  }\r
+\r
+  //\r
+  // Include extra glyph info and '\0' info, so +2.\r
+  //\r
+  return StrOffset + 2;\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
+\r
+**/\r
+VOID\r
+UpdateOptionSkipLines (\r
+  IN UI_MENU_SELECTION            *Selection,\r
+  IN UI_MENU_OPTION               *MenuOption\r
+  )\r
+{\r
+  UINTN   Index;\r
+  UINT16  Width;\r
+  UINTN   Row;\r
+  UINTN   OriginalRow;\r
+  CHAR16  *OutputString;\r
+  CHAR16  *OptionString;\r
+  UINT16  GlyphWidth;\r
+\r
+  Row           = 0;\r
+  OptionString  = NULL;\r
+  Width         = (UINT16) gOptionBlockWidth;\r
+  OriginalRow   = 0;\r
+  GlyphWidth    = 1;\r
+  \r
+  ProcessOptions (Selection, MenuOption, FALSE, &OptionString);\r
+  if (OptionString == NULL) {\r
+    return;\r
+  }\r
+\r
+  for (Index = 0; GetLineByWidth (OptionString, Width, &GlyphWidth, &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]) != 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
+    FreePool (OutputString);\r
+  }\r
+\r
+  if (OptionString != NULL) {\r
+    FreePool (OptionString);\r
+  }\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
+\r
+  Temp = Direction ? CurrentPos->BackLink : CurrentPos->ForwardLink;\r
+\r
+  if (Temp == &gMenuOption) {\r
+    return TRUE;\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+\r
+/**\r
+  Move to next selectable statement.\r
+\r
+  This is an internal function.\r
+\r
+  @param  Selection              Menu selection.\r
+  @param  GoUp                   The navigation direction. TRUE: up, FALSE: down.\r
+  @param  CurrentPosition        Current position.\r
+  @param  GapToTop               Gap position to top or bottom.\r
+\r
+  @return The row distance from current MenuOption to next selectable MenuOption.\r
+\r
+  @retval -1       Reach the begin of the menu, still can't find the selectable menu.\r
+  @retval Value    Find the selectable menu, maybe the truly selectable, maybe the l\r
+                   last menu showing at current form.\r
+\r
+**/\r
+INTN\r
+MoveToNextStatement (\r
+  IN     UI_MENU_SELECTION         *Selection,\r
+  IN     BOOLEAN                   GoUp,\r
+  IN OUT LIST_ENTRY                **CurrentPosition,\r
+  IN     UINTN                     GapToTop\r
+  )\r
+{\r
+  INTN             Distance;\r
+  LIST_ENTRY       *Pos;\r
+  UI_MENU_OPTION   *NextMenuOption;\r
+  UI_MENU_OPTION   *PreMenuOption;\r
+\r
+  Distance      = 0;\r
+  Pos           = *CurrentPosition;\r
+  PreMenuOption = MENU_OPTION_FROM_LINK (Pos);\r
+\r
+  while (TRUE) {\r
+    NextMenuOption = MENU_OPTION_FROM_LINK (Pos);\r
+    //\r
+    // NextMenuOption->Row == 0 means this menu has not calculate\r
+    // the NextMenuOption->Skip value yet, just calculate here.\r
+    //\r
+    if (NextMenuOption->Row == 0) {\r
+      UpdateOptionSkipLines (Selection, NextMenuOption);\r
+    }\r
+    \r
+    if (GoUp && (PreMenuOption != NextMenuOption)) {\r
+      //\r
+      // In this case, still can't find the selectable menu,\r
+      // return the last one in the showing form.\r
+      //\r
+      if ((UINTN) Distance + NextMenuOption->Skip > GapToTop) {\r
+        NextMenuOption = PreMenuOption;\r
+        break;\r
+      }\r
+\r
+      //\r
+      // Current Position doesn't need to be caculated when go up.\r
+      // Caculate distanct at first when go up\r
+      //      \r
+      Distance += NextMenuOption->Skip;\r
+    }\r
+\r
+    if (IsSelectable (NextMenuOption)) {\r
+      break;\r
+    }\r
+\r
+    //\r
+    // Arrive at begin of the menu list.\r
+    //\r
+    if ((GoUp ? Pos->BackLink : Pos->ForwardLink) == &gMenuOption) {\r
+      Distance = -1;\r
+      break;\r
+    }\r
+\r
+    if (!GoUp) {\r
+      //\r
+      // In this case, still can't find the selectable menu,\r
+      // return the last one in the showing form.\r
+      //\r
+      if ((UINTN) Distance + NextMenuOption->Skip > GapToTop) {\r
+        NextMenuOption = PreMenuOption;\r
+        break;\r
+      }\r
+\r
+      Distance += NextMenuOption->Skip;\r
+    }\r
+\r
+    PreMenuOption = NextMenuOption;\r
+    Pos = (GoUp ? Pos->BackLink : Pos->ForwardLink);\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
+  Find HII Handle in the HII database associated with given Device Path.\r
+\r
+  If DevicePath is NULL, then ASSERT.\r
+\r
+  @param  DevicePath             Device Path associated with the HII package list\r
+                                 handle.\r
+\r
+  @retval Handle                 HII package list Handle associated with the Device\r
+                                        Path.\r
+  @retval NULL                   Hii Package list handle is not found.\r
+\r
+**/\r
+EFI_HII_HANDLE\r
+EFIAPI\r
+DevicePathToHiiHandle (\r
+  IN EFI_DEVICE_PATH_PROTOCOL   *DevicePath\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  EFI_DEVICE_PATH_PROTOCOL    *TmpDevicePath;\r
+  UINTN                       BufferSize;\r
+  UINTN                       HandleCount;\r
+  UINTN                       Index;\r
+  EFI_HANDLE                  Handle;\r
+  EFI_HANDLE                  DriverHandle;\r
+  EFI_HII_HANDLE              *HiiHandles;\r
+  EFI_HII_HANDLE              HiiHandle;\r
+\r
+  ASSERT (DevicePath != NULL);\r
+\r
+  TmpDevicePath = DevicePath;\r
+  //\r
+  // Locate Device Path Protocol handle buffer\r
+  //\r
+  Status = gBS->LocateDevicePath (\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  &TmpDevicePath,\r
+                  &DriverHandle\r
+                  );\r
+  if (EFI_ERROR (Status) || !IsDevicePathEnd (TmpDevicePath)) {\r
+    return NULL;\r
+  }\r
+\r
+  //\r
+  // Retrieve all HII Handles from HII database\r
+  //\r
+  BufferSize = 0x1000;\r
+  HiiHandles = AllocatePool (BufferSize);\r
+  ASSERT (HiiHandles != NULL);\r
+  Status = mHiiDatabase->ListPackageLists (\r
+                           mHiiDatabase,\r
+                           EFI_HII_PACKAGE_TYPE_ALL,\r
+                           NULL,\r
+                           &BufferSize,\r
+                           HiiHandles\r
+                           );\r
+  if (Status == EFI_BUFFER_TOO_SMALL) {\r
+    FreePool (HiiHandles);\r
+    HiiHandles = AllocatePool (BufferSize);\r
+    ASSERT (HiiHandles != NULL);\r
+\r
+    Status = mHiiDatabase->ListPackageLists (\r
+                             mHiiDatabase,\r
+                             EFI_HII_PACKAGE_TYPE_ALL,\r
+                             NULL,\r
+                             &BufferSize,\r
+                             HiiHandles\r
+                             );\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    FreePool (HiiHandles);\r
+    return NULL;\r
+  }\r
+\r
+  //\r
+  // Search Hii Handle by Driver Handle\r
+  //\r
+  HiiHandle = NULL;\r
+  HandleCount = BufferSize / sizeof (EFI_HII_HANDLE);\r
+  for (Index = 0; Index < HandleCount; Index++) {\r
+    Status = mHiiDatabase->GetPackageListHandle (\r
+                             mHiiDatabase,\r
+                             HiiHandles[Index],\r
+                             &Handle\r
+                             );\r
+    if (!EFI_ERROR (Status) && (Handle == DriverHandle)) {\r
+      HiiHandle = HiiHandles[Index];\r
+      break;\r
+    }\r
+  }\r
+\r
+  FreePool (HiiHandles);\r
+  return HiiHandle;\r
+}\r
+\r
+/**\r
+  Find HII Handle in the HII database associated with given form set guid.\r
+\r
+  If FormSetGuid is NULL, then ASSERT.\r
+\r
+  @param  ComparingGuid          FormSet Guid associated with the HII package list\r
+                                 handle.\r
+\r
+  @retval Handle                 HII package list Handle associated with the Device\r
+                                        Path.\r
+  @retval NULL                   Hii Package list handle is not found.\r
+\r
+**/\r
+EFI_HII_HANDLE\r
+FormSetGuidToHiiHandle (\r
+  EFI_GUID     *ComparingGuid\r
+  )\r
+{\r
+  EFI_HII_HANDLE               *HiiHandles;\r
+  UINTN                        Index;\r
+  EFI_HII_PACKAGE_LIST_HEADER  *HiiPackageList;\r
+  UINTN                        BufferSize;\r
+  UINT32                       Offset;\r
+  UINT32                       Offset2;\r
+  UINT32                       PackageListLength;\r
+  EFI_HII_PACKAGE_HEADER       PackageHeader;\r
+  UINT8                        *Package;\r
+  UINT8                        *OpCodeData;\r
+  EFI_STATUS                   Status;\r
+  EFI_HII_HANDLE               HiiHandle;\r
+\r
+  ASSERT (ComparingGuid != NULL);\r
+\r
+  HiiHandle  = NULL;\r
+  //\r
+  // Get all the Hii handles\r
+  //\r
+  HiiHandles = HiiGetHiiHandles (NULL);\r
+  ASSERT (HiiHandles != NULL);\r
+\r
+  //\r
+  // Search for formset of each class type\r
+  //\r
+  for (Index = 0; HiiHandles[Index] != NULL; Index++) {\r
+    BufferSize = 0;\r
+    HiiPackageList = NULL;\r
+    Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, HiiHandles[Index], &BufferSize, HiiPackageList);\r
+    if (Status == EFI_BUFFER_TOO_SMALL) {\r
+      HiiPackageList = AllocatePool (BufferSize);\r
+      ASSERT (HiiPackageList != NULL);\r
+\r
+      Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, HiiHandles[Index], &BufferSize, HiiPackageList);\r
+    }\r
+    if (EFI_ERROR (Status) || HiiPackageList == NULL) {\r
+      return NULL;\r
+    }\r
+\r
+    //\r
+    // Get Form package from this HII package List\r
+    //\r
+    Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);\r
+    Offset2 = 0;\r
+    CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32)); \r
+\r
+    while (Offset < PackageListLength) {\r
+      Package = ((UINT8 *) HiiPackageList) + Offset;\r
+      CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));\r
+\r
+      if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) {\r
+        //\r
+        // Search FormSet in this Form Package\r
+        //\r
+        Offset2 = sizeof (EFI_HII_PACKAGE_HEADER);\r
+        while (Offset2 < PackageHeader.Length) {\r
+          OpCodeData = Package + Offset2;\r
+\r
+          if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) {\r
+            //\r
+            // Try to compare against formset GUID\r
+            //\r
+            if (CompareGuid (ComparingGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) {\r
+              HiiHandle = HiiHandles[Index];\r
+              break;\r
+            }\r
+          }\r
+\r
+          Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;\r
+        }\r
+      }\r
+      if (HiiHandle != NULL) {\r
+        break;\r
+      }\r
+      Offset += PackageHeader.Length;\r
+    }\r
+    \r
+    FreePool (HiiPackageList);\r
+       if (HiiHandle != NULL) {\r
+               break;\r
+       }\r
+  }\r
+\r
+  FreePool (HiiHandles);\r
+\r
+  return HiiHandle;\r
+}\r
+\r
+/**\r
+  Process the goto op code, update the info in the selection structure.\r
+\r
+  @param Statement    The statement belong to goto op code.\r
+  @param Selection    The selection info.\r
+  @param Repaint      Whether need to repaint the menu.\r
+  @param NewLine      Whether need to create new line.\r
+\r
+  @retval EFI_SUCCESS    The menu process successfully.\r
+  @return Other value if the process failed.\r
+**/\r
+EFI_STATUS\r
+ProcessGotoOpCode (\r
+  IN OUT   FORM_BROWSER_STATEMENT      *Statement,\r
+  IN OUT   UI_MENU_SELECTION           *Selection,\r
+  OUT      BOOLEAN                     *Repaint,\r
+  OUT      BOOLEAN                     *NewLine\r
+  )\r
+{\r
+  CHAR16                          *StringPtr;\r
+  EFI_DEVICE_PATH_PROTOCOL        *DevicePath;\r
+  FORM_BROWSER_FORM               *RefForm;\r
+  EFI_INPUT_KEY                   Key;\r
+  EFI_STATUS                      Status;\r
+\r
+  Status    = EFI_SUCCESS;\r
+  StringPtr = NULL;\r
+\r
+  //\r
+  // Prepare the device path check, get the device path info first.\r
+  //\r
+  if (Statement->HiiValue.Value.ref.DevicePath != 0) {\r
+    StringPtr = GetToken (Statement->HiiValue.Value.ref.DevicePath, Selection->FormSet->HiiHandle);\r
+  }\r
+\r
+  //\r
+  // Check whether the device path string is a valid string.\r
+  //\r
+  if (Statement->HiiValue.Value.ref.DevicePath != 0 && StringPtr != NULL) {\r
+    if (Selection->Form->ModalForm) {\r
+      return Status;\r
+    }\r
+\r
+    //\r
+    // Goto another Hii Package list\r
+    //\r
+    if (mPathFromText != NULL) {\r
+      DevicePath = mPathFromText->ConvertTextToDevicePath(StringPtr);\r
+      if (DevicePath != NULL) {\r
+        Selection->Handle = DevicePathToHiiHandle (DevicePath);\r
+        FreePool (DevicePath);\r
+      }\r
+      FreePool (StringPtr);\r
+    } else {\r
+      //\r
+      // Not found the EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL protocol.\r
+      //\r
+      do {\r
+        CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gProtocolNotFound, gPressEnter, gEmptyString);\r
+      } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+      if (Repaint != NULL) {\r
+        *Repaint = TRUE;\r
+      }\r
+      FreePool (StringPtr);\r
+      return Status;\r
+    }\r
+\r
+    Selection->Action = UI_ACTION_REFRESH_FORMSET;\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
+      return Status;\r
+    }\r
+\r
+    CopyMem (&Selection->FormSetGuid,&Statement->HiiValue.Value.ref.FormSetGuid, sizeof (EFI_GUID));\r
+    Selection->FormId = Statement->HiiValue.Value.ref.FormId;\r
+    Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;\r
+  } else if (!CompareGuid (&Statement->HiiValue.Value.ref.FormSetGuid, &gZeroGuid)) {\r
+    if (Selection->Form->ModalForm) {\r
+      return Status;\r
+    }  \r
+    //\r
+    // Goto another Formset, check for uncommitted data\r
+    //\r
+    Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
+    \r
+    Selection->Handle = FormSetGuidToHiiHandle(&Statement->HiiValue.Value.ref.FormSetGuid);\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
+      return Status;\r
+    } \r
+\r
+    CopyMem (&Selection->FormSetGuid, &Statement->HiiValue.Value.ref.FormSetGuid, sizeof (EFI_GUID));\r
+    Selection->FormId = Statement->HiiValue.Value.ref.FormId;\r
+    Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;\r
+  } else if (Statement->HiiValue.Value.ref.FormId != 0) {\r
+    //\r
+    // Check whether target From is suppressed.\r
+    //\r
+    RefForm = IdToForm (Selection->FormSet, Statement->HiiValue.Value.ref.FormId);\r
+\r
+    if ((RefForm != NULL) && (RefForm->SuppressExpression != NULL)) {\r
+      if (EvaluateExpressionList(RefForm->SuppressExpression, TRUE, Selection->FormSet, RefForm) != ExpressFalse) {\r
+        //\r
+        // Form is suppressed. \r
+        //\r
+        do {\r
+          CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gFormSuppress, gPressEnter, gEmptyString);\r
+        } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+        if (Repaint != NULL) {\r
+          *Repaint = TRUE;\r
+        }\r
+        return Status;\r
+      }\r
+    }\r
+\r
+    //\r
+    // Goto another form inside this formset,\r
+    //\r
+    Selection->Action = UI_ACTION_REFRESH_FORM;\r
+\r
+    Selection->FormId = Statement->HiiValue.Value.ref.FormId;\r
+    Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;\r
+  } else if (Statement->HiiValue.Value.ref.QuestionId != 0) {\r
+    //\r
+    // Goto another Question\r
+    //\r
+    Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;\r
+\r
+    if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {\r
+      Selection->Action = UI_ACTION_REFRESH_FORM;\r
+    } else {\r
+      if (Repaint != NULL) {\r
+        *Repaint = TRUE;\r
+      }\r
+      if (NewLine != NULL) {\r
+        *NewLine = TRUE;\r
+      }\r
+    }\r
+  } else {\r
+    if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {\r
+      Selection->Action = UI_ACTION_REFRESH_FORM;\r
+    }\r
+  }\r
+\r
+  return Status;\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
+  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
+  UINT16                          Width;\r
+  CHAR16                          *StringPtr;\r
+  CHAR16                          *OptionString;\r
+  CHAR16                          *OutputString;\r
+  CHAR16                          *HelpString;\r
+  CHAR16                          *HelpHeaderString;\r
+  CHAR16                          *HelpBottomString;\r
+  BOOLEAN                         NewLine;\r
+  BOOLEAN                         Repaint;\r
+  BOOLEAN                         SavedValue;\r
+  BOOLEAN                         UpArrow;\r
+  BOOLEAN                         DownArrow;\r
+  BOOLEAN                         InitializedFlag;\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
+  MENU_REFRESH_ENTRY              *MenuUpdateEntry;  \r
+  UI_SCREEN_OPERATION             ScreenOperation;\r
+  UINT8                           MinRefreshInterval;\r
+  UINT16                          DefaultId;\r
+  FORM_BROWSER_STATEMENT          *Statement;\r
+  UI_MENU_LIST                    *CurrentMenu;\r
+  UINTN                           ModalSkipColumn;\r
+  BROWSER_HOT_KEY                 *HotKey;\r
+  UINTN                           HelpPageIndex;\r
+  UINTN                           HelpPageCount;\r
+  UINTN                           RowCount;\r
+  UINTN                           HelpLine;\r
+  UINTN                           HelpHeaderLine;\r
+  UINTN                           HelpBottomLine;\r
+  BOOLEAN                         MultiHelpPage;\r
+  UINT16                          GlyphWidth;\r
+  UINT16                          EachLineWidth;\r
+  UINT16                          HeaderLineWidth;\r
+  UINT16                          BottomLineWidth;\r
+\r
+  CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));\r
+\r
+  Status              = EFI_SUCCESS;\r
+  HelpString          = NULL;\r
+  HelpHeaderString    = NULL;\r
+  HelpBottomString    = NULL;\r
+  OptionString        = NULL;\r
+  ScreenOperation     = UiNoOperation;\r
+  NewLine             = TRUE;\r
+  MinRefreshInterval  = 0;\r
+  DefaultId           = 0;\r
+  HelpPageCount       = 0;\r
+  HelpLine            = 0;\r
+  RowCount            = 0;\r
+  HelpBottomLine      = 0;\r
+  HelpHeaderLine      = 0;\r
+  HelpPageIndex       = 0;\r
+  MultiHelpPage       = FALSE;\r
+  EachLineWidth       = 0;\r
+  HeaderLineWidth     = 0;\r
+  BottomLineWidth     = 0;\r
+  OutputString        = NULL;\r
+  UpArrow             = FALSE;\r
+  DownArrow           = FALSE;\r
+  SkipValue           = 0;\r
+  MenuRefreshEntry    = gMenuRefreshHead;\r
+\r
+  NextMenuOption      = NULL;\r
+  PreviousMenuOption  = NULL;\r
+  SavedMenuOption     = NULL;\r
+  HotKey              = NULL;\r
+  ModalSkipColumn     = (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 6;\r
+\r
+  ZeroMem (&Key, sizeof (EFI_INPUT_KEY));\r
+\r
+  if ((gClassOfVfr & FORMSET_CLASS_FRONT_PAGE) == FORMSET_CLASS_FRONT_PAGE){\r
+    TopRow  = LocalScreen.TopRow + FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;\r
+    Row     = LocalScreen.TopRow + FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;\r
+  } else {\r
+    TopRow  = LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;\r
+    Row     = LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;\r
+  }\r
+\r
+  if (Selection->Form->ModalForm) {\r
+    Col = LocalScreen.LeftColumn + LEFT_SKIPPED_COLUMNS + ModalSkipColumn;\r
+  } else {\r
+    Col = LocalScreen.LeftColumn + LEFT_SKIPPED_COLUMNS;\r
+  }\r
+\r
+  BottomRow = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight - 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 = gMenuOption.ForwardLink;\r
+  Repaint     = TRUE;\r
+  MenuOption  = NULL;\r
+\r
+  //\r
+  // Find current Menu\r
+  //\r
+  CurrentMenu = UiFindMenuList (Selection->Handle, &Selection->FormSetGuid, Selection->FormId);\r
+  if (CurrentMenu == NULL) {\r
+    //\r
+    // Current menu not found, add it to the menu tree\r
+    //\r
+    CurrentMenu = UiAddMenuList (Selection->CurrentMenu, Selection->Handle, &Selection->FormSetGuid, Selection->FormId);\r
+  }\r
+  ASSERT (CurrentMenu != NULL);\r
+  Selection->CurrentMenu = CurrentMenu;\r
+\r
+  if (Selection->QuestionId == 0) {\r
+    //\r
+    // Highlight not specified, fetch it from cached menu\r
+    //\r
+    Selection->QuestionId = CurrentMenu->QuestionId;\r
+    Selection->Sequence   = CurrentMenu->Sequence;\r
+  }\r
+\r
+  //\r
+  // Init option as the current user's selection\r
+  //\r
+  InitializedFlag = TRUE;\r
+  NewPos = gMenuOption.ForwardLink;\r
+\r
+  gST->ConOut->EnableCursor (gST->ConOut, FALSE);\r
+  UpdateStatusBar (Selection, 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 (&gMenuOption)) {\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
+        DownArrow       = FALSE;\r
+        UpArrow         = FALSE;\r
+        Row             = TopRow;\r
+\r
+        Temp            = (UINTN) SkipValue;\r
+        Temp2           = (UINTN) SkipValue;\r
+\r
+        //\r
+        // 1. Clear the screen.\r
+        //\r
+        if (Selection->Form->ModalForm) {\r
+          ClearLines (\r
+            LocalScreen.LeftColumn + ModalSkipColumn,\r
+            LocalScreen.LeftColumn + ModalSkipColumn + gPromptBlockWidth + gOptionBlockWidth,\r
+            TopRow - SCROLL_ARROW_HEIGHT,\r
+            BottomRow + SCROLL_ARROW_HEIGHT,\r
+            PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND\r
+            );   \r
+        } else {\r
+          ClearLines (\r
+            LocalScreen.LeftColumn,\r
+            LocalScreen.RightColumn,\r
+            TopRow - SCROLL_ARROW_HEIGHT,\r
+            BottomRow + SCROLL_ARROW_HEIGHT,\r
+            PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND\r
+            );\r
+        }\r
+        UiFreeRefreshList ();\r
+        MinRefreshInterval = 0;\r
+\r
+        //\r
+        // 2.Paint the menu.\r
+        //\r
+        for (Link = TopOfScreen; Link != &gMenuOption; Link = Link->ForwardLink) {\r
+          MenuOption          = MENU_OPTION_FROM_LINK (Link);\r
+          MenuOption->Row     = Row;\r
+          MenuOption->Col     = Col;\r
+          if (Selection->Form->ModalForm) {\r
+            MenuOption->OptCol  = gPromptBlockWidth + 1 + LocalScreen.LeftColumn + ModalSkipColumn;\r
+          } else {\r
+            MenuOption->OptCol  = gPromptBlockWidth + 1 + LocalScreen.LeftColumn;\r
+          }\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, PcdGet8 (PcdBrowserSubtitleTextColor) | FIELD_BACKGROUND);\r
+            }\r
+          }\r
+\r
+          Width       = GetWidth (Statement, MenuOption->Handle);\r
+          OriginalRow = Row;\r
+          GlyphWidth  = 1;\r
+\r
+          if (Statement->Operand == EFI_IFR_REF_OP && MenuOption->Col >= 2) {\r
+            //\r
+            // Print Arrow for Goto button.\r
+            //\r
+            PrintAt (\r
+              MenuOption->Col - 2,\r
+              Row,\r
+              L"%c",\r
+              GEOMETRICSHAPE_RIGHT_TRIANGLE\r
+              );\r
+          }\r
+\r
+          //\r
+          // 2.1. Paint the description.\r
+          //\r
+          for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) {\r
+            //\r
+            // Temp means need to skip how many lines from the start.\r
+            //\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]) != 0) {\r
+              if (Temp == 0) {\r
+                Row++;\r
+              }\r
+            }\r
+\r
+            FreePool (OutputString);\r
+            if (Temp != 0) {\r
+              Temp--;\r
+            }\r
+          }\r
+\r
+          Temp  = 0;\r
+          Row   = OriginalRow;\r
+\r
+          //\r
+          // 2.2. Paint the option string.\r
+          //\r
+          Status = ProcessOptions (Selection, MenuOption, FALSE, &OptionString);\r
+          if (EFI_ERROR (Status)) {\r
+            //\r
+            // Repaint to clear possible error prompt pop-up\r
+            //\r
+            Repaint = TRUE;\r
+            NewLine = TRUE;\r
+            ControlFlag = CfRepaint;\r
+            break;\r
+          }\r
+\r
+          if (OptionString != NULL) {\r
+            if (Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) {\r
+              ProcessStringForDateTime(MenuOption, OptionString, TRUE);\r
+            }\r
+\r
+            Width       = (UINT16) gOptionBlockWidth;\r
+            OriginalRow = Row;\r
+            GlyphWidth  = 1;\r
+\r
+            for (Index = 0; GetLineByWidth (OptionString, Width, &GlyphWidth, &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]) != 0) {\r
+                if (Temp2 == 0) {\r
+                  Row++;\r
+                  //\r
+                  // Since the Number of lines for this menu entry may or may not be reflected accurately\r
+                  // since the prompt might be 1 lines and option might be many, and vice versa, we need to do\r
+                  // some testing to ensure we are keeping this in-sync.\r
+                  //\r
+                  // If the difference in rows is greater than or equal to the skip value, increase the skip value\r
+                  //\r
+                  if ((Row - OriginalRow) >= MenuOption->Skip) {\r
+                    MenuOption->Skip++;\r
+                  }\r
+                }\r
+              }\r
+\r
+              FreePool (OutputString);\r
+              if (Temp2 != 0) {\r
+                Temp2--;\r
+              }\r
+            }\r
+\r
+            Temp2 = 0;\r
+            Row   = OriginalRow;\r
+\r
+            FreePool (OptionString);\r
+          }\r
+\r
+          //\r
+          // 2.4 Special process for Test opcode with test two.\r
+          //\r
+          if (!CompareGuid (&Statement->RefreshGuid, &gZeroGuid)) {\r
+            if (gMenuEventGuidRefreshHead == NULL) {\r
+              MenuUpdateEntry = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY));\r
+              gMenuEventGuidRefreshHead = MenuUpdateEntry;\r
+            } else {\r
+              MenuUpdateEntry = gMenuEventGuidRefreshHead;\r
+              while (MenuUpdateEntry->Next != NULL) {\r
+                MenuUpdateEntry = MenuUpdateEntry->Next; \r
+              }\r
+              MenuUpdateEntry->Next = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY));\r
+              MenuUpdateEntry = MenuUpdateEntry->Next; \r
+            }\r
+            ASSERT (MenuUpdateEntry != NULL);\r
+            Status = gBS->CreateEventEx (EVT_NOTIFY_SIGNAL, TPL_NOTIFY, RefreshQuestionNotify, MenuUpdateEntry, &Statement->RefreshGuid, &MenuUpdateEntry->Event);\r
+            ASSERT (!EFI_ERROR (Status));\r
+            MenuUpdateEntry->MenuOption        = MenuOption;\r
+            MenuUpdateEntry->Selection         = Selection;\r
+            MenuUpdateEntry->CurrentColumn     = MenuOption->OptCol;\r
+            MenuUpdateEntry->CurrentRow        = MenuOption->Row;\r
+            if (MenuOption->GrayOut) {\r
+              MenuUpdateEntry->CurrentAttribute = FIELD_TEXT_GRAYED | FIELD_BACKGROUND;\r
+            } else {\r
+              MenuUpdateEntry->CurrentAttribute = PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND;\r
+            }\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
+              gMenuRefreshHead = MenuRefreshEntry;\r
+            } else {\r
+              MenuRefreshEntry = gMenuRefreshHead;\r
+              while (MenuRefreshEntry->Next != NULL) {\r
+                MenuRefreshEntry = MenuRefreshEntry->Next; \r
+              }\r
+              MenuRefreshEntry->Next = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY));\r
+              MenuRefreshEntry = MenuRefreshEntry->Next;\r
+            }\r
+            ASSERT (MenuRefreshEntry != NULL);            \r
+            MenuRefreshEntry->MenuOption        = MenuOption;\r
+            MenuRefreshEntry->Selection         = Selection;\r
+            MenuRefreshEntry->CurrentColumn     = MenuOption->OptCol;\r
+            MenuRefreshEntry->CurrentRow        = MenuOption->Row;\r
+            if (MenuOption->GrayOut) {\r
+              MenuRefreshEntry->CurrentAttribute = FIELD_TEXT_GRAYED | FIELD_BACKGROUND;\r
+            } else {               \r
+              MenuRefreshEntry->CurrentAttribute = PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND;\r
+            }\r
+          }\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
+            GlyphWidth = 1;\r
+\r
+            for (Index = 0; GetLineByWidth (StringPtr, Width, &GlyphWidth, &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]) != 0) {\r
+                if (Temp2 == 0) {\r
+                  Row++;\r
+                  //\r
+                  // Since the Number of lines for this menu entry may or may not be reflected accurately\r
+                  // since the prompt might be 1 lines and option might be many, and vice versa, we need to do\r
+                  // some testing to ensure we are keeping this in-sync.\r
+                  //\r
+                  // If the difference in rows is greater than or equal to the skip value, increase the skip value\r
+                  //\r
+                  if ((Row - OriginalRow) >= MenuOption->Skip) {\r
+                    MenuOption->Skip++;\r
+                  }\r
+                }\r
+              }\r
+\r
+              FreePool (OutputString);\r
+              if (Temp2 != 0) {\r
+                Temp2--;\r
+              }\r
+            }\r
+\r
+            Row = OriginalRow;\r
+            FreePool (StringPtr);\r
+          }\r
+          gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND);\r
+\r
+          //\r
+          // 3. Update the row info which will be used by next menu.\r
+          //\r
+          if (Link == TopOfScreen) {\r
+            Row += MenuOption->Skip - SkipValue;\r
+          } else {\r
+            Row += MenuOption->Skip;\r
+          }\r
+\r
+          if (Row > BottomRow) {\r
+            if (!ValueIsScroll (FALSE, Link)) {\r
+              DownArrow = TRUE;\r
+            }\r
+\r
+            Row = BottomRow + 1;\r
+            break;\r
+          }\r
+        }\r
+\r
+        if (!ValueIsScroll (TRUE, TopOfScreen)) {\r
+          UpArrow = TRUE;\r
+        }\r
+\r
+        if (UpArrow) {\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, PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND);\r
+        }\r
+\r
+        if (DownArrow) {\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, PcdGet8 (PcdBrowserFieldTextColor) | 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
+      if (TopOfScreen == &MenuOption->Link) {\r
+        Temp = SkipValue;\r
+      } else {\r
+        Temp = 0;\r
+      }\r
+      if (NewPos == TopOfScreen) {\r
+        Temp2 = SkipValue;\r
+      } else {\r
+        Temp2 = 0;\r
+      }\r
+      if (InitializedFlag) {\r
+        InitializedFlag = FALSE;\r
+        MoveToNextStatement (Selection, FALSE, &NewPos, BottomRow - TopRow);\r
+      }\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 = gMenuOption.ForwardLink;\r
+        SavedMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
+\r
+        while ((SavedMenuOption->ThisTag->QuestionId != Selection->QuestionId ||\r
+                SavedMenuOption->Sequence != Selection->Sequence) &&\r
+                NewPos->ForwardLink != &gMenuOption) {\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
+            if (Link == TopOfScreen) {\r
+              Index -= SkipValue;\r
+            }\r
+            Link = Link->ForwardLink;\r
+          }\r
+          if (NewPos == Link) {\r
+            SavedMenuOption = MENU_OPTION_FROM_LINK (Link);\r
+          }\r
+\r
+          //\r
+          // Not find the selected menu in current show page.\r
+          // Have two case to enter this if:\r
+          // 1. Not find the menu at current page.\r
+          // 2. Find the menu in current page, but the menu shows at the bottom and not all info shows.\r
+          //    For case 2, has an exception: The menu can show more than one pages and now only this menu shows.\r
+          //\r
+          // Base on the selected menu will show at the bottom of the page,\r
+          // select the menu which will show at the top of the page.\r
+          //\r
+          if (Link != NewPos || Index > BottomRow || \r
+              (Link == NewPos && (SavedMenuOption->Row + SavedMenuOption->Skip - 1 > BottomRow) && (Link != TopOfScreen))) {\r
+            //\r
+            // Find the MenuOption which has the skip value for Date/Time opcode. \r
+            //\r
+            AdjustDateAndTimePosition(FALSE, &NewPos);\r
+            //\r
+            // NewPos is not in the current page, simply scroll page so that NewPos is in the end of the page\r
+            //\r
+            SavedMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
+            //\r
+            // SavedMenuOption->Row == 0 means the menu not show yet.\r
+            //\r
+            if (SavedMenuOption->Row == 0) {\r
+              UpdateOptionSkipLines (Selection, SavedMenuOption);\r
+            }\r
+\r
+            //\r
+            // Base on the selected menu will show at the bottome of next page, \r
+            // select the menu show at the top of the next page. \r
+            //\r
+            Link    = NewPos;\r
+            for (Index = TopRow + SavedMenuOption->Skip; Index <= BottomRow + 1; ) {            \r
+              Link = Link->BackLink;\r
+              SavedMenuOption = MENU_OPTION_FROM_LINK (Link);\r
+              if (SavedMenuOption->Row == 0) {\r
+                UpdateOptionSkipLines (Selection, SavedMenuOption);\r
+              }\r
+              Index += SavedMenuOption->Skip;\r
+            }\r
+\r
+            //\r
+            // Found the menu which will show at the top of the page.\r
+            //\r
+            if (Link == NewPos) {\r
+              //\r
+              // The menu can show more than one pages, just show the menu at the top of the page.\r
+              //\r
+              SkipValue    = 0;\r
+              TopOfScreen  = Link;\r
+            } else {\r
+              //\r
+              // Check whether need to skip some line for menu shows at the top of the page.\r
+              //\r
+              SkipValue = Index - BottomRow - 1;\r
+              if (SkipValue > 0 && SkipValue < (INTN) SavedMenuOption->Skip) {\r
+                TopOfScreen     = Link;\r
+              } else {\r
+                SkipValue       = 0;\r
+                TopOfScreen     = Link->ForwardLink;\r
+              }\r
+            }\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, PcdGet8 (PcdBrowserFieldTextColor) | 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
+              ProcessStringForDateTime(MenuOption, OptionString, FALSE);\r
+            }\r
+\r
+            Width               = (UINT16) gOptionBlockWidth;\r
+            OriginalRow         = MenuOption->Row;\r
+            GlyphWidth          = 1;\r
+\r
+            for (Index = 0; GetLineByWidth (OptionString, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) {\r
+              if ((Temp == 0) && (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]) != 0) {\r
+                if (Temp == 0) {\r
+                  MenuOption->Row++;\r
+                }\r
+              }\r
+\r
+              FreePool (OutputString);\r
+              if (Temp != 0) {\r
+                Temp--;\r
+              }\r
+            }\r
+\r
+            MenuOption->Row = OriginalRow;\r
+\r
+            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, PcdGet8 (PcdBrowserSubtitleTextColor) | FIELD_BACKGROUND);\r
+              }\r
+\r
+              OriginalRow = MenuOption->Row;\r
+              Width       = GetWidth (MenuOption->ThisTag, MenuOption->Handle);\r
+              GlyphWidth  = 1;\r
+\r
+              for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) {\r
+                if ((Temp == 0) && (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]) != 0) {\r
+                  if (Temp == 0) {\r
+                    MenuOption->Row++;\r
+                  }\r
+                }\r
+\r
+                FreePool (OutputString);\r
+                if (Temp != 0) {\r
+                  Temp--;\r
+                }\r
+              }\r
+\r
+              MenuOption->Row = OriginalRow;\r
+              gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND);\r
+            }\r
+          }\r
+        }\r
+\r
+        //\r
+        // This is the current selected statement\r
+        //\r
+        MenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
+        Statement = MenuOption->ThisTag;\r
+        Selection->Statement = Statement;\r
+        if (!IsSelectable (MenuOption)) {\r
+          Repaint = SavedValue;\r
+          UpdateKeyHelp (Selection, MenuOption, FALSE);\r
+          break;\r
+        }\r
+\r
+        //\r
+        // Record highlight for current menu\r
+        //\r
+        CurrentMenu->QuestionId = Statement->QuestionId;\r
+        CurrentMenu->Sequence   = MenuOption->Sequence;\r
+\r
+        //\r
+        // Set reverse attribute\r
+        //\r
+        gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextHighlightColor) | PcdGet8 (PcdBrowserFieldBackgroundHighlightColor));\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
+            if (MenuRefreshEntry->MenuOption->GrayOut) {\r
+              MenuRefreshEntry->CurrentAttribute = FIELD_TEXT_GRAYED | FIELD_BACKGROUND;\r
+            } else {               \r
+              MenuRefreshEntry->CurrentAttribute = PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND;\r
+            }\r
+            if (MenuRefreshEntry->MenuOption == MenuOption) {\r
+              MenuRefreshEntry->CurrentAttribute = PcdGet8 (PcdBrowserFieldTextHighlightColor) | PcdGet8 (PcdBrowserFieldBackgroundHighlightColor);\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
+            ProcessStringForDateTime(MenuOption, OptionString, FALSE);\r
+          }\r
+          Width               = (UINT16) gOptionBlockWidth;\r
+\r
+          OriginalRow         = MenuOption->Row;\r
+          GlyphWidth          = 1;\r
+\r
+          for (Index = 0; GetLineByWidth (OptionString, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) {\r
+            if ((Temp2 == 0) && (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]) != 0) {\r
+              if (Temp2 == 0) {\r
+              MenuOption->Row++;\r
+              }\r
+            }\r
+\r
+            FreePool (OutputString);\r
+            if (Temp2 != 0) {\r
+              Temp2--;\r
+            }\r
+          }\r
+\r
+          MenuOption->Row = OriginalRow;\r
+\r
+          FreePool (OptionString);\r
+        } else {\r
+          if (NewLine) {\r
+            OriginalRow = MenuOption->Row;\r
+\r
+            Width       = GetWidth (Statement, MenuOption->Handle);\r
+            GlyphWidth          = 1;\r
+\r
+            for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) {\r
+              if ((Temp2 == 0) && (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]) != 0) {\r
+                if (Temp2 == 0) {\r
+                  MenuOption->Row++;\r
+                }\r
+              }\r
+\r
+              FreePool (OutputString);\r
+              if (Temp2 != 0) {\r
+                Temp2--;\r
+              }\r
+            }\r
+\r
+            MenuOption->Row = OriginalRow;\r
+\r
+          }\r
+        }\r
+\r
+        UpdateKeyHelp (Selection, MenuOption, FALSE);\r
+\r
+        //\r
+        // Clear reverse attribute\r
+        //\r
+        gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextColor) | 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
+      if (Selection->Form->ModalForm) {\r
+        break;\r
+      }\r
+\r
+      if (Repaint || NewLine) {\r
+        //\r
+        // Don't print anything if it is a NULL help token\r
+        //\r
+        ASSERT(MenuOption != NULL);\r
+        if (MenuOption->ThisTag->Help == 0 || !IsSelectable (MenuOption)) {\r
+          StringPtr = L"\0";\r
+        } else {\r
+          StringPtr = GetToken (MenuOption->ThisTag->Help, MenuOption->Handle);\r
+        }\r
+\r
+        RowCount      = BottomRow - TopRow;\r
+        HelpPageIndex = 0;\r
+        //\r
+        // 1.Calculate how many line the help string need to print.\r
+        //\r
+        if (HelpString != NULL) {\r
+          FreePool (HelpString);\r
+        }\r
+        HelpLine = ProcessHelpString (StringPtr, &HelpString, &EachLineWidth, RowCount);\r
+        if (HelpLine > RowCount) {\r
+          MultiHelpPage   = TRUE;\r
+          StringPtr       = GetToken (STRING_TOKEN(ADJUST_HELP_PAGE_UP), gHiiHandle);\r
+          if (HelpHeaderString != NULL) {\r
+            FreePool (HelpHeaderString);\r
+          }\r
+          HelpHeaderLine  = ProcessHelpString (StringPtr, &HelpHeaderString, &HeaderLineWidth, RowCount);\r
+          StringPtr       = GetToken (STRING_TOKEN(ADJUST_HELP_PAGE_DOWN), gHiiHandle);\r
+          if (HelpBottomString != NULL) {\r
+            FreePool (HelpBottomString);\r
+          }\r
+          HelpBottomLine  = ProcessHelpString (StringPtr, &HelpBottomString, &BottomLineWidth, RowCount);\r
+          //\r
+          // Calculate the help page count.\r
+          //\r
+          if (HelpLine > 2 * RowCount - 2) {\r
+            HelpPageCount = (HelpLine - RowCount + 1) / (RowCount - 2) + 1;\r
+            if ((HelpLine - RowCount + 1) % (RowCount - 2) > 1) {\r
+              HelpPageCount += 1;\r
+            }\r
+          } else {\r
+            HelpPageCount = 2;\r
+          }\r
+        } else {\r
+          MultiHelpPage = FALSE;\r
+        }\r
+      }\r
+\r
+      //\r
+      // Clean the help field first.\r
+      //\r
+      ClearLines (\r
+        LocalScreen.RightColumn - gHelpBlockWidth,\r
+        LocalScreen.RightColumn,\r
+        TopRow,\r
+        BottomRow,\r
+        PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND\r
+        );\r
+\r
+      //\r
+      // Check whether need to show the 'More(U/u)' at the begin.\r
+      // Base on current direct info, here shows aligned to the right side of the column.\r
+      // If the direction is multi line and aligned to right side may have problem, so \r
+      // add ASSERT code here.\r
+      //\r
+      if (HelpPageIndex > 0) {\r
+        gST->ConOut->SetAttribute (gST->ConOut, INFO_TEXT | FIELD_BACKGROUND);\r
+        for (Index = 0; Index < HelpHeaderLine; Index++) {\r
+          ASSERT (HelpHeaderLine == 1);\r
+          ASSERT (GetStringWidth (HelpHeaderString) / 2 < (UINTN) (gHelpBlockWidth - 1));\r
+          PrintStringAt (\r
+            LocalScreen.RightColumn - GetStringWidth (HelpHeaderString) / 2 - 1,\r
+            Index + TopRow,\r
+            &HelpHeaderString[Index * HeaderLineWidth]\r
+            );\r
+        }\r
+      }\r
+\r
+      gST->ConOut->SetAttribute (gST->ConOut, HELP_TEXT | FIELD_BACKGROUND);\r
+      //\r
+      // Print the help string info.\r
+      //\r
+      if (!MultiHelpPage) {\r
+        for (Index = 0; Index < HelpLine; Index++) {\r
+          PrintStringAt (\r
+            LocalScreen.RightColumn - gHelpBlockWidth,\r
+            Index + TopRow,\r
+            &HelpString[Index * EachLineWidth]\r
+            );\r
+        }\r
+        gST->ConOut->SetCursorPosition(gST->ConOut, LocalScreen.RightColumn-1, BottomRow);\r
+      } else  {\r
+        if (HelpPageIndex == 0) {\r
+          for (Index = 0; Index < RowCount - HelpBottomLine; Index++) {\r
+            PrintStringAt (\r
+              LocalScreen.RightColumn - gHelpBlockWidth,\r
+              Index + TopRow,\r
+              &HelpString[Index * EachLineWidth]\r
+              );\r
+          }\r
+        } else {\r
+          for (Index = 0; (Index < RowCount - HelpBottomLine - HelpHeaderLine) && \r
+              (Index + HelpPageIndex * (RowCount - 2) + 1 < HelpLine); Index++) {\r
+            PrintStringAt (\r
+              LocalScreen.RightColumn - gHelpBlockWidth,\r
+              Index + TopRow + HelpHeaderLine,\r
+              &HelpString[(Index + HelpPageIndex * (RowCount - 2) + 1)* EachLineWidth]\r
+              );\r
+          }\r
+          if (HelpPageIndex == HelpPageCount - 1) {\r
+            gST->ConOut->SetCursorPosition(gST->ConOut, LocalScreen.RightColumn-1, BottomRow);\r
+          }\r
+        } \r
+      }\r
+\r
+      //\r
+      // Check whether need to print the 'More(D/d)' at the bottom.\r
+      // Base on current direct info, here shows aligned to the right side of the column.\r
+      // If the direction is multi line and aligned to right side may have problem, so \r
+      // add ASSERT code here.\r
+      //\r
+      if (HelpPageIndex < HelpPageCount - 1 && MultiHelpPage) {\r
+        gST->ConOut->SetAttribute (gST->ConOut, INFO_TEXT | FIELD_BACKGROUND);\r
+        for (Index = 0; Index < HelpBottomLine; Index++) {\r
+          ASSERT (HelpBottomLine == 1);\r
+          ASSERT (GetStringWidth (HelpBottomString) / 2 < (UINTN) (gHelpBlockWidth - 1)); \r
+          PrintStringAt (\r
+            LocalScreen.RightColumn - GetStringWidth (HelpBottomString) / 2 - 1,\r
+            Index + BottomRow - HelpBottomLine,\r
+            &HelpBottomString[Index * BottomLineWidth]\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
+      while (TRUE) {\r
+        Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
+        if (!EFI_ERROR (Status)) {\r
+          break;\r
+        }\r
+\r
+        //\r
+        // If we encounter error, continue to read another key in.\r
+        //\r
+        if (Status != EFI_NOT_READY) {\r
+          continue;\r
+        }\r
+\r
+        Status = UiWaitForSingleEvent (gST->ConIn->WaitForKey, 0, MinRefreshInterval);\r
+        ASSERT_EFI_ERROR (Status);\r
+\r
+        if (Selection->Action == UI_ACTION_REFRESH_FORMSET) {\r
+          //\r
+          // IFR is updated in Callback of refresh opcode, re-parse it\r
+          //\r
+          ControlFlag = CfCheckSelection;\r
+          Selection->Statement = NULL;\r
+          break;\r
+        }\r
+      }\r
+\r
+      if (ControlFlag == CfCheckSelection) {\r
+        break;\r
+      }\r
+\r
+      switch (Key.UnicodeChar) {\r
+      case CHAR_CARRIAGE_RETURN:\r
+        if(MenuOption->GrayOut || MenuOption->ReadOnly) {\r
+          ControlFlag = CfReadKey;\r
+          break;\r
+        }\r
+\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
+        //\r
+        // If the screen has no menu items, and the user didn't select UiReset\r
+        // ignore the selection and go back to reading keys.\r
+        //\r
+        if(IsListEmpty (&gMenuOption) || MenuOption->GrayOut || MenuOption->ReadOnly) {\r
+          ControlFlag = CfReadKey;\r
+          break;\r
+        }\r
+\r
+        ASSERT(MenuOption != NULL);\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
+          if (EFI_ERROR (Status)) {\r
+            //\r
+            // Repaint to clear possible error prompt pop-up\r
+            //\r
+            Repaint = TRUE;\r
+            NewLine = TRUE;\r
+          } else {\r
+            Selection->Action = UI_ACTION_REFRESH_FORM;\r
+          }\r
+          if (OptionString != NULL) {\r
+            FreePool (OptionString);\r
+          }\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 & FORMSET_CLASS_FRONT_PAGE) != FORMSET_CLASS_FRONT_PAGE) {\r
+          //\r
+          // If the screen has no menu items, and the user didn't select UiReset\r
+          // ignore the selection and go back to reading keys.\r
+          //\r
+          if(IsListEmpty (&gMenuOption)) {\r
+            ControlFlag = CfReadKey;\r
+            break;\r
+          }\r
+          \r
+          ASSERT(MenuOption != NULL);\r
+          if (MenuOption->ThisTag->Operand == EFI_IFR_CHECKBOX_OP && !MenuOption->GrayOut && !MenuOption->ReadOnly) {\r
+            ScreenOperation = UiSelect;\r
+          }\r
+        }\r
+        break;\r
+\r
+      case 'D':\r
+      case 'd':\r
+        if (!MultiHelpPage) {\r
+          ControlFlag = CfReadKey;\r
+          break;\r
+        }\r
+        ControlFlag    = CfUpdateHelpString;\r
+        HelpPageIndex  = HelpPageIndex < HelpPageCount - 1 ? HelpPageIndex + 1 : HelpPageCount - 1;\r
+        break;\r
+\r
+      case 'U':\r
+      case 'u':\r
+        if (!MultiHelpPage) {\r
+          ControlFlag = CfReadKey;\r
+          break;\r
+        }\r
+        ControlFlag    = CfUpdateHelpString;\r
+        HelpPageIndex  = HelpPageIndex > 0 ? HelpPageIndex - 1 : 0;\r
+        break;\r
+\r
+      case CHAR_NULL:\r
+        for (Index = 0; Index < mScanCodeNumber; Index++) {\r
+          if (Key.ScanCode == gScanCodeToOperation[Index].ScanCode) {\r
+            ScreenOperation = gScanCodeToOperation[Index].ScreenOperation;\r
+            break;\r
+          }\r
+        }\r
+        \r
+        if (Selection->Form->ModalForm && (Key.ScanCode == SCAN_ESC || Index == mScanCodeNumber)) {\r
+          //\r
+          // ModalForm has no ESC key and Hot Key.\r
+          //\r
+          ControlFlag = CfReadKey;\r
+        } else if (Index == mScanCodeNumber) {\r
+          //\r
+          // Check whether Key matches the registered hot key.\r
+          //\r
+          HotKey = NULL;\r
+          if ((gBrowserSettingScope == SystemLevel) || \r
+              (Selection->FormEditable && gFunctionKeySetting != NONE_FUNCTION_KEY_SETTING)) {\r
+            HotKey = GetHotKeyFromRegisterList (&Key);\r
+          }\r
+          if (HotKey != NULL) {\r
+            ScreenOperation = UiHotKey;\r
+          }\r
+        }\r
+        break;\r
+      }\r
+      break;\r
+\r
+    case CfScreenOperation:\r
+      if (ScreenOperation != UiReset) {\r
+        //\r
+        // If the screen has no menu items, and the user didn't select UiReset\r
+        // ignore the selection and go back to reading keys.\r
+        //\r
+        if (IsListEmpty (&gMenuOption)) {\r
+          ControlFlag = CfReadKey;\r
+          break;\r
+        }\r
+      }\r
+\r
+      for (Index = 0;\r
+           Index < sizeof (gScreenOperationToControlFlag) / sizeof (gScreenOperationToControlFlag[0]);\r
+           Index++\r
+          ) {\r
+        if (ScreenOperation == gScreenOperationToControlFlag[Index].ScreenOperation) {\r
+          ControlFlag = gScreenOperationToControlFlag[Index].ControlFlag;\r
+          break;\r
+        }\r
+      }\r
+      break;\r
+\r
+    case CfUiSelect:\r
+      ControlFlag = CfCheckSelection;\r
+\r
+      ASSERT(MenuOption != NULL);\r
+      Statement = MenuOption->ThisTag;\r
+      if (Statement->Operand == EFI_IFR_TEXT_OP) {\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
+        ProcessGotoOpCode(Statement, Selection, &Repaint, &NewLine);\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 (Selection, MenuOption, TRUE);\r
+        Status = ProcessOptions (Selection, MenuOption, TRUE, &OptionString);\r
+\r
+        if (EFI_ERROR (Status)) {\r
+          Repaint = TRUE;\r
+          NewLine = TRUE;\r
+          UpdateKeyHelp (Selection, MenuOption, FALSE);\r
+        } else {\r
+          Selection->Action = UI_ACTION_REFRESH_FORM;\r
+        }\r
+\r
+        if (OptionString != NULL) {\r
+          FreePool (OptionString);\r
+        }\r
+        break;\r
+      }\r
+      break;\r
+\r
+    case CfUiReset:\r
+      //\r
+      // We come here when someone press ESC\r
+      //\r
+      ControlFlag = CfCheckSelection;\r
+      FindNextMenu (Selection, &Repaint, &NewLine);\r
+      break;\r
+\r
+    case CfUiLeft:\r
+      ControlFlag = CfCheckSelection;\r
+      ASSERT(MenuOption != NULL);\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
+          ASSERT(NewPos != NULL);\r
+          NewPos = NewPos->BackLink;\r
+        }\r
+      }\r
+      break;\r
+\r
+    case CfUiRight:\r
+      ControlFlag = CfCheckSelection;\r
+      ASSERT(MenuOption != NULL);\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
+          ASSERT(NewPos != NULL);\r
+          NewPos = NewPos->ForwardLink;\r
+        }\r
+      }\r
+      break;\r
+\r
+    case CfUiUp:\r
+      ControlFlag = CfCheckSelection;\r
+\r
+      SavedListEntry = NewPos;\r
+\r
+      ASSERT(NewPos != NULL);\r
+      //\r
+      // Adjust Date/Time position before we advance forward.\r
+      //\r
+      AdjustDateAndTimePosition (TRUE, &NewPos);\r
+      if (NewPos->BackLink != &gMenuOption) {\r
+        MenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
+        ASSERT (MenuOption != NULL);\r
+        NewLine    = TRUE;\r
+        NewPos     = NewPos->BackLink;\r
+\r
+        PreviousMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
+        if (PreviousMenuOption->Row == 0) {\r
+          UpdateOptionSkipLines (Selection, PreviousMenuOption);\r
+        }\r
+        DistanceValue = PreviousMenuOption->Skip;\r
+        Difference    = 0;\r
+        if (MenuOption->Row >= DistanceValue + TopRow) {\r
+          Difference = MoveToNextStatement (Selection, TRUE, &NewPos, MenuOption->Row - TopRow - DistanceValue);\r
+        }\r
+        NextMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
+       \r
+        if (Difference < 0) {\r
+          //\r
+          // We hit the begining MenuOption that can be focused\r
+          // so we simply scroll to the top.\r
+          //\r
+          if (TopOfScreen != gMenuOption.ForwardLink) {\r
+            TopOfScreen = gMenuOption.ForwardLink;\r
+            Repaint     = TRUE;\r
+          } else {\r
+            //\r
+            // Scroll up to the last page when we have arrived at top page.\r
+            //\r
+            NewPos          = &gMenuOption;\r
+            TopOfScreen     = &gMenuOption;\r
+            MenuOption      = MENU_OPTION_FROM_LINK (SavedListEntry);\r
+            ScreenOperation = UiPageUp;\r
+            ControlFlag     = CfScreenOperation;\r
+            break;\r
+          }\r
+        } else if (MenuOption->Row < TopRow + DistanceValue + Difference) {\r
+          //\r
+          // Previous focus MenuOption is above the TopOfScreen, so we need to scroll\r
+          //\r
+          TopOfScreen = NewPos;\r
+          Repaint     = TRUE;\r
+          SkipValue = 0;\r
+        } else if (!IsSelectable (NextMenuOption)) {\r
+          //\r
+          // Continue to go up until scroll to next page or the selectable option is found.\r
+          //\r
+          ScreenOperation = UiUp;\r
+          ControlFlag     = CfScreenOperation;\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
+        AdjustDateAndTimePosition (TRUE, &NewPos);\r
+        MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);\r
+        UpdateStatusBar (Selection, INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE);\r
+      } else {\r
+        //\r
+        // Scroll up to the last page.\r
+        //\r
+        NewPos          = &gMenuOption;\r
+        TopOfScreen     = &gMenuOption;\r
+        MenuOption      = MENU_OPTION_FROM_LINK (SavedListEntry);\r
+        ScreenOperation = UiPageUp;\r
+        ControlFlag     = CfScreenOperation;\r
+      }\r
+      break;\r
+\r
+    case CfUiPageUp:\r
+      //\r
+      // SkipValue means lines is skipped when show the top menu option.\r
+      //\r
+      ControlFlag     = CfCheckSelection;\r
+\r
+      ASSERT(NewPos != NULL);\r
+      //\r
+      // Already at the first menu option, so do nothing.\r
+      //\r
+      if (NewPos->BackLink == &gMenuOption) {\r
+        NewLine = FALSE;\r
+        Repaint = FALSE;\r
+        break;\r
+      }\r
+\r
+      NewLine   = TRUE;\r
+      Repaint   = TRUE;\r
+\r
+      //\r
+      // SkipValue > (BottomRow - TopRow + 1) means current menu has more than one\r
+      // form of options to be show, so just update the SkipValue to show the next\r
+      // parts of options.\r
+      //\r
+      if (SkipValue > (INTN) (BottomRow - TopRow + 1)) {\r
+        SkipValue -= BottomRow - TopRow + 1;\r
+        break;\r
+      }\r
+\r
+      Link      = TopOfScreen;\r
+      //\r
+      // First minus the menu of the top screen, it's value is SkipValue.\r
+      //\r
+      Index     = (BottomRow + 1) - SkipValue;\r
+      while ((Index >= TopRow) && (Link->BackLink != &gMenuOption)) {\r
+        Link = Link->BackLink;\r
+        PreviousMenuOption = MENU_OPTION_FROM_LINK (Link);\r
+        if (PreviousMenuOption->Row == 0) {\r
+          UpdateOptionSkipLines (Selection, PreviousMenuOption);\r
+        }        \r
+        if (Index < PreviousMenuOption->Skip) {\r
+          break;\r
+        }\r
+        Index = Index - PreviousMenuOption->Skip;\r
+      }\r
+      \r
+      if ((Link->BackLink == &gMenuOption) && (Index >= TopRow)) {\r
+        SkipValue = 0;\r
+        if (TopOfScreen == &gMenuOption) {\r
+          TopOfScreen = gMenuOption.ForwardLink;\r
+          NewPos      = gMenuOption.BackLink;\r
+          MoveToNextStatement (Selection, TRUE, &NewPos, BottomRow - TopRow);\r
+          Repaint = FALSE;\r
+        } else if (TopOfScreen != Link) {\r
+          TopOfScreen = Link;\r
+          NewPos      = Link;\r
+          MoveToNextStatement (Selection, FALSE, &NewPos, BottomRow - TopRow);\r
+        } else {\r
+          //\r
+          // Finally we know that NewPos is the last MenuOption can be focused.\r
+          //\r
+          Repaint = FALSE;\r
+          NewPos  = Link;\r
+          MoveToNextStatement (Selection, FALSE, &NewPos, BottomRow - TopRow);\r
+        }\r
+      } else {\r
+        if (Index >= TopRow) {\r
+          //\r
+          // At here, only case "Index < PreviousMenuOption->Skip" can reach here.\r
+          //\r
+          SkipValue = PreviousMenuOption->Skip - (Index - TopRow);\r
+        } else {\r
+          SkipValue = PreviousMenuOption->Skip - (TopRow - Index);\r
+          Link = Link->ForwardLink;\r
+        }\r
+\r
+        //\r
+        // Move to the option in Next page.\r
+        //\r
+        if (TopOfScreen == &gMenuOption) {\r
+          NewPos = gMenuOption.BackLink;\r
+          MoveToNextStatement (Selection, TRUE, &NewPos, BottomRow - TopRow);\r
+        } else {\r
+          NewPos = Link;\r
+          MoveToNextStatement (Selection, FALSE, &NewPos, BottomRow - TopRow);\r
+        }\r
+\r
+        //\r
+        // There are more MenuOption needing scrolling up.\r
+        //\r
+        TopOfScreen = Link;\r
+        MenuOption  = NULL;\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
+      //\r
+      // SkipValue means lines is skipped when show the top menu option.\r
+      //\r
+      ControlFlag     = CfCheckSelection;\r
+\r
+      ASSERT (NewPos != NULL);\r
+      if (NewPos->ForwardLink == &gMenuOption) {\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 + NextMenuOption->Skip - SkipValue;\r
+      //\r
+      // Count to the menu option which will show at the top of the next form.\r
+      //\r
+      while ((Index <= BottomRow + 1) && (Link->ForwardLink != &gMenuOption)) {\r
+        Link           = Link->ForwardLink;\r
+        NextMenuOption = MENU_OPTION_FROM_LINK (Link);\r
+        Index = Index + NextMenuOption->Skip;\r
+      }\r
+\r
+      if ((Link->ForwardLink == &gMenuOption) && (Index <= BottomRow + 1)) {\r
+        //\r
+        // Finally we know that NewPos is the last MenuOption can be focused.\r
+        //\r
+        Repaint = FALSE;\r
+        MoveToNextStatement (Selection, TRUE, &Link, Index - TopRow);\r
+        SkipValue = 0;\r
+      } else {\r
+        //\r
+        // Calculate the skip line for top of screen menu.\r
+        //\r
+        if (Link == TopOfScreen) {\r
+          //\r
+          // The top of screen menu option occupies the entire form.\r
+          //\r
+          SkipValue += BottomRow - TopRow + 1;\r
+        } else {\r
+          SkipValue = NextMenuOption->Skip - (Index - (BottomRow + 1));\r
+        }\r
+\r
+        TopOfScreen = Link;\r
+        MenuOption = NULL;\r
+        //\r
+        // Move to the Next selectable menu.\r
+        //\r
+        MoveToNextStatement (Selection, FALSE, &Link, BottomRow - TopRow);\r
+      }\r
+\r
+      //\r
+      // Save the menu as the next highlight menu.\r
+      //\r
+      NewPos  = Link;\r
+\r
+      //\r
+      // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.\r
+      // Don't do this when we are already in the last page.\r
+      //\r
+      AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
+      AdjustDateAndTimePosition (TRUE, &NewPos);\r
+      break;\r
+\r
+    case CfUiDown:\r
+      //\r
+      // SkipValue means lines is skipped when show the top menu option.\r
+      // NewPos  points to the menu which is highlighted now.\r
+      //\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
+      AdjustDateAndTimePosition (FALSE, &NewPos);\r
+\r
+      if (NewPos->ForwardLink != &gMenuOption) {\r
+        MenuOption      = MENU_OPTION_FROM_LINK (NewPos);\r
+        NewLine         = TRUE;\r
+        NewPos          = NewPos->ForwardLink;\r
+\r
+        Difference      = 0;\r
+        //\r
+        // Current menu not at the bottom of the form.\r
+        //\r
+        if (BottomRow >= MenuOption->Row + MenuOption->Skip) {\r
+          //\r
+          // Find the next selectable menu.\r
+          //\r
+          Difference = MoveToNextStatement (Selection, FALSE, &NewPos, BottomRow - MenuOption->Row - MenuOption->Skip);\r
+          //\r
+          // We hit the end of MenuOption that can be focused\r
+          // so we simply scroll to the first page.\r
+          //\r
+          if (Difference < 0) {\r
+            //\r
+            // Scroll to the first page.\r
+            //\r
+            if (TopOfScreen != gMenuOption.ForwardLink) {\r
+              TopOfScreen = gMenuOption.ForwardLink;\r
+              Repaint     = TRUE;\r
+              MenuOption  = NULL;\r
+            } else {\r
+              MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);\r
+            }\r
+            NewPos        = gMenuOption.ForwardLink;\r
+            MoveToNextStatement (Selection, FALSE, &NewPos, BottomRow - TopRow);\r
+\r
+            SkipValue = 0;\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, &TopOfScreen);\r
+            AdjustDateAndTimePosition (TRUE, &NewPos);\r
+            break;\r
+          }\r
+        }\r
+        NextMenuOption  = MENU_OPTION_FROM_LINK (NewPos);\r
+        if (NextMenuOption->Row == 0) {\r
+          UpdateOptionSkipLines (Selection, NextMenuOption);\r
+        }\r
+        DistanceValue  = Difference + NextMenuOption->Skip;\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) || (SavedMenuOption->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 - SkipValue)) {\r
+                //\r
+                // Skip the top op-code\r
+                //\r
+                TopOfScreen     = TopOfScreen->ForwardLink;\r
+                Difference      = (Temp - BottomRow) - (SavedMenuOption->Skip - SkipValue);\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
+                while (Difference >= (INTN) SavedMenuOption->Skip) {\r
+                  //\r
+                  // Since the Difference is greater than or equal to this op-code's skip value, skip it\r
+                  //\r
+                  Difference      = Difference - (INTN) SavedMenuOption->Skip;\r
+                  TopOfScreen     = TopOfScreen->ForwardLink;\r
+                  SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);\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
+              } 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 += (Temp - BottomRow) - 1;\r
+              }\r
+            } else {\r
+              if ((SkipValue + 1) == (INTN) SavedMenuOption->Skip) {\r
+                TopOfScreen = TopOfScreen->ForwardLink;\r
+                break;\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 if (SavedMenuOption->Skip == 1) {\r
+              SkipValue   = 0;\r
+            } else {\r
+              SkipValue   = 0;\r
+              TopOfScreen = TopOfScreen->ForwardLink;\r
+            }\r
+          } while (SavedMenuOption->Skip == 0);\r
+\r
+          Repaint       = TRUE;\r
+        } else if (!IsSelectable (NextMenuOption)) {\r
+          //\r
+          // Continue to go down until scroll to next page or the selectable option is found.\r
+          //\r
+          ScreenOperation = UiDown;\r
+          ControlFlag     = CfScreenOperation;\r
+        }\r
+\r
+        MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);\r
+\r
+        UpdateStatusBar (Selection, INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE);\r
+\r
+      } else {\r
+        //\r
+        // Scroll to the first page.\r
+        //\r
+        if (TopOfScreen != gMenuOption.ForwardLink) {\r
+          TopOfScreen = gMenuOption.ForwardLink;\r
+          Repaint     = TRUE;\r
+          MenuOption  = NULL;\r
+        } else {\r
+          //\r
+          // Need to remove the current highlight menu.\r
+          // MenuOption saved the last highlight menu info.\r
+          //\r
+          MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);\r
+        }\r
+\r
+        SkipValue     = 0;\r
+        NewLine       = TRUE;\r
+        //\r
+        // Get the next highlight menu.\r
+        //\r
+        NewPos        = gMenuOption.ForwardLink;\r
+        MoveToNextStatement (Selection, FALSE, &NewPos, BottomRow - TopRow);\r
+      }\r
+\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, &TopOfScreen);\r
+      AdjustDateAndTimePosition (TRUE, &NewPos);\r
+      break;\r
+\r
+    case CfUiHotKey:\r
+      ControlFlag = CfCheckSelection;\r
+      \r
+      Status = EFI_SUCCESS;\r
+      //\r
+      // Discard changes. After it, no NV flag is showed.\r
+      //\r
+      if ((HotKey->Action & BROWSER_ACTION_DISCARD) == BROWSER_ACTION_DISCARD) {\r
+        Status = DiscardForm (Selection->FormSet, Selection->Form, gBrowserSettingScope);\r
+        if (!EFI_ERROR (Status)) {\r
+          Selection->Action = UI_ACTION_REFRESH_FORM;\r
+          Selection->Statement = NULL;\r
+          gResetRequired = FALSE;\r
+        } else {\r
+          do {\r
+            CreateDialog (4, TRUE, 0, NULL, &Key, HotKey->HelpString, gDiscardFailed, gPressEnter, gEmptyString);\r
+          } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+          //\r
+          // Still show current page.\r
+          //\r
+          Selection->Action = UI_ACTION_NONE;\r
+          Repaint = TRUE;\r
+          NewLine = TRUE;\r
+          break;\r
+        }\r
+      }\r
+\r
+      //\r
+      // Reterieve default setting. After it. NV flag will be showed.\r
+      //\r
+      if ((HotKey->Action & BROWSER_ACTION_DEFAULT) == BROWSER_ACTION_DEFAULT) {\r
+        Status = ExtractDefault (Selection->FormSet, Selection->Form, HotKey->DefaultId, gBrowserSettingScope, GetDefaultForAll, NULL, FALSE);\r
+        if (!EFI_ERROR (Status)) {\r
+          Selection->Action = UI_ACTION_REFRESH_FORM;\r
+          Selection->Statement = NULL;\r
+          gResetRequired = TRUE;\r
+        } else {\r
+          do {\r
+            CreateDialog (4, TRUE, 0, NULL, &Key, HotKey->HelpString, gDefaultFailed, gPressEnter, gEmptyString);\r
+          } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+          //\r
+          // Still show current page.\r
+          //\r
+          Selection->Action = UI_ACTION_NONE;\r
+          Repaint = TRUE;\r
+          NewLine = TRUE;\r
+          break;\r
+        }\r
+      }\r
+\r
+      //\r
+      // Save changes. After it, no NV flag is showed.\r
+      //\r
+      if ((HotKey->Action & BROWSER_ACTION_SUBMIT) == BROWSER_ACTION_SUBMIT) {\r
+        Status = SubmitForm (Selection->FormSet, Selection->Form, gBrowserSettingScope);\r
+        if (!EFI_ERROR (Status)) {\r
+          ASSERT(MenuOption != NULL);\r
+          UpdateStatusBar (Selection, INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE);\r
+          UpdateStatusBar (Selection, NV_UPDATE_REQUIRED, MenuOption->ThisTag->QuestionFlags, FALSE);\r
+        } else {\r
+          do {\r
+            CreateDialog (4, TRUE, 0, NULL, &Key, HotKey->HelpString, gSaveFailed, gPressEnter, gEmptyString);\r
+          } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+          //\r
+          // Still show current page.\r
+          //\r
+          Selection->Action = UI_ACTION_NONE;\r
+          Repaint = TRUE;\r
+          NewLine = TRUE;\r
+          break;\r
+        }\r
+      }\r
+      \r
+      //\r
+      // Set Reset required Flag\r
+      //\r
+      if ((HotKey->Action & BROWSER_ACTION_RESET) == BROWSER_ACTION_RESET) {\r
+        gResetRequired = TRUE;\r
+      }\r
+      \r
+      //\r
+      // Exit Action\r
+      //\r
+      if ((HotKey->Action & BROWSER_ACTION_EXIT) == BROWSER_ACTION_EXIT) {\r
+        //\r
+        // Form Exit without saving, Similar to ESC Key.\r
+        // FormSet Exit without saving, Exit SendForm.\r
+        // System Exit without saving, CallExitHandler and Exit SendForm.\r
+        //\r
+        DiscardForm (Selection->FormSet, Selection->Form, gBrowserSettingScope);\r
+        if (gBrowserSettingScope == FormLevel) {\r
+          ControlFlag = CfUiReset;\r
+        } else if (gBrowserSettingScope == FormSetLevel) {\r
+          Selection->Action = UI_ACTION_EXIT;\r
+        } else if (gBrowserSettingScope == SystemLevel) {\r
+          if (ExitHandlerFunction != NULL) {\r
+            ExitHandlerFunction ();\r
+          }\r
+          Selection->Action = UI_ACTION_EXIT;\r
+        }\r
+        Selection->Statement = NULL;\r
+      }\r
+      break;\r
+\r
+    case CfUiDefault:\r
+      ControlFlag = CfCheckSelection;\r
+      //\r
+      // Reset to default value for all forms in the whole system.\r
+      //\r
+      Status = ExtractDefault (Selection->FormSet, NULL, DefaultId, FormSetLevel, GetDefaultForAll, NULL, FALSE);\r
+\r
+      if (!EFI_ERROR (Status)) {\r
+        Selection->Action = UI_ACTION_REFRESH_FORM;\r
+        Selection->Statement = NULL;\r
+        gResetRequired = 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
+      if (HelpString != NULL) {\r
+        FreePool (HelpString);\r
+      }\r
+      if (HelpHeaderString != NULL) {\r
+        FreePool (HelpHeaderString);\r
+      }\r
+      if (HelpBottomString != NULL) {\r
+        FreePool (HelpBottomString);\r
+      }\r
+\r
+      return EFI_SUCCESS;\r
+\r
+    default:\r
+      break;\r
+    }\r
+  }\r
+}\r