]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/SetupBrowserDxe/Ui.c
Disable change value for grayout or readonly menu.
[mirror_edk2.git] / MdeModulePkg / Universal / SetupBrowserDxe / Ui.c
index cc9652ee1767cb18c8216822bb11e19e4e5e3c08..ca2ec3b169f7ff97db9e6c9f31218bc9da49a27f 100644 (file)
@@ -1,8 +1,8 @@
 /** @file\r
 Utility functions for User Interface functions.\r
 \r
-Copyright (c) 2004 - 2008, Intel Corporation\r
-All rights reserved. This program and the accompanying materials\r
+Copyright (c) 2004 - 2011, 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
@@ -12,12 +12,12 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 \r
 **/\r
 \r
-#include "Ui.h"\r
 #include "Setup.h"\r
 \r
-LIST_ENTRY          Menu;\r
-LIST_ENTRY          gMenuList;\r
-MENU_REFRESH_ENTRY  *gMenuRefreshHead;\r
+LIST_ENTRY          gMenuOption;\r
+LIST_ENTRY          gMenuList = INITIALIZE_LIST_HEAD_VARIABLE (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
@@ -43,10 +43,6 @@ SCAN_CODE_TO_SCREEN_OPERATION     gScanCodeToOperation[] = {
     SCAN_ESC,\r
     UiReset,\r
   },\r
-  {\r
-    SCAN_F2,\r
-    UiPrevious,\r
-  },\r
   {\r
     SCAN_LEFT,\r
     UiLeft,\r
@@ -54,26 +50,16 @@ SCAN_CODE_TO_SCREEN_OPERATION     gScanCodeToOperation[] = {
   {\r
     SCAN_RIGHT,\r
     UiRight,\r
-  },\r
-  {\r
-    SCAN_F9,\r
-    UiDefault,\r
-  },\r
-  {\r
-    SCAN_F10,\r
-    UiSave\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
-    UiDefault,\r
-    CfUiDefault,\r
-  },\r
   {\r
     UiSelect,\r
     CfUiSelect,\r
@@ -98,14 +84,6 @@ SCREEN_OPERATION_T0_CONTROL_FLAG  gScreenOperationToControlFlag[] = {
     UiReset,\r
     CfUiReset,\r
   },\r
-  {\r
-    UiSave,\r
-    CfUiSave,\r
-  },\r
-  {\r
-    UiPrevious,\r
-    CfUiPrevious,\r
-  },\r
   {\r
     UiPageUp,\r
     CfUiPageUp,\r
@@ -113,6 +91,10 @@ SCREEN_OPERATION_T0_CONTROL_FLAG  gScreenOperationToControlFlag[] = {
   {\r
     UiPageDown,\r
     CfUiPageDown\r
+  }, \r
+  {\r
+    UiHotKey,\r
+    CfUiHotKey\r
   }\r
 };\r
 \r
@@ -127,8 +109,6 @@ BOOLEAN GetLineByWidthFinished = FALSE;
   @param  Size                   Number of bytes to set\r
   @param  Value                  Value of the set operation.\r
 \r
-  @return Value.\r
-\r
 **/\r
 VOID\r
 SetUnicodeMem (\r
@@ -155,87 +135,164 @@ UiInitMenu (
   VOID\r
   )\r
 {\r
-  InitializeListHead (&Menu);\r
+  InitializeListHead (&gMenuOption);\r
 }\r
 \r
 \r
 /**\r
-  Initialize Menu option list.\r
+  Free Menu option linked list.\r
 \r
 **/\r
 VOID\r
-UiInitMenuList (\r
+UiFreeMenu (\r
   VOID\r
   )\r
 {\r
-  InitializeListHead (&gMenuList);\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
-  Remove a Menu in list, and return FormId/QuestionId for previous Menu.\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  Selection              Menu selection.\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
-VOID\r
-UiRemoveMenuListEntry (\r
-  OUT UI_MENU_SELECTION  *Selection\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  *UiMenuList;\r
+  UI_MENU_LIST  *MenuList;\r
+\r
+  MenuList = AllocateZeroPool (sizeof (UI_MENU_LIST));\r
+  if (MenuList == NULL) {\r
+    return NULL;\r
+  }\r
 \r
-  if (!IsListEmpty (&gMenuList)) {\r
-    UiMenuList = CR (gMenuList.ForwardLink, UI_MENU_LIST, MenuLink, UI_MENU_LIST_SIGNATURE);\r
+  MenuList->Signature = UI_MENU_LIST_SIGNATURE;\r
+  InitializeListHead (&MenuList->ChildListHead);\r
 \r
-    Selection->FormId = UiMenuList->FormId;\r
-    Selection->QuestionId = UiMenuList->QuestionId;\r
-    RemoveEntryList (&UiMenuList->MenuLink);\r
-    FreePool (UiMenuList);\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
-  Free Menu option linked list.\r
+  Search Menu with given FormId and FormSetGuid in all cached menu list.\r
+\r
+  @param  Parent                 The parent of menu to search.\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
-VOID\r
-UiFreeMenuList (\r
-  VOID\r
+UI_MENU_LIST *\r
+UiFindChildMenuList (\r
+  IN UI_MENU_LIST         *Parent,\r
+  IN EFI_GUID             *FormSetGuid, \r
+  IN UINT16               FormId\r
   )\r
 {\r
-  UI_MENU_LIST  *UiMenuList;\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)) {\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, FormSetGuid, FormId);\r
+    if (MenuList != NULL) {\r
+      return MenuList;\r
+    }\r
 \r
-  while (!IsListEmpty (&gMenuList)) {\r
-    UiMenuList = CR (gMenuList.ForwardLink, UI_MENU_LIST, MenuLink, UI_MENU_LIST_SIGNATURE);\r
-    RemoveEntryList (&UiMenuList->MenuLink);\r
-    FreePool (UiMenuList);\r
+    Link = GetNextNode (&Parent->ChildListHead, Link);\r
   }\r
+\r
+  return NULL;\r
 }\r
 \r
 \r
 /**\r
-  Add one menu entry to the linked lst\r
+  Search Menu with given FormSetGuid and FormId in all cached menu list.\r
 \r
-  @param  Selection              Menu selection.\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
-VOID\r
-UiAddMenuListEntry (\r
-  IN UI_MENU_SELECTION            *Selection\r
+UI_MENU_LIST *\r
+UiFindMenuList (\r
+  IN EFI_GUID             *FormSetGuid,\r
+  IN UINT16               FormId\r
   )\r
 {\r
-  UI_MENU_LIST  *UiMenuList;\r
+  LIST_ENTRY      *Link;\r
+  UI_MENU_LIST    *MenuList;\r
+  UI_MENU_LIST    *Child;\r
 \r
-  UiMenuList = AllocateZeroPool (sizeof (UI_MENU_LIST));\r
-  ASSERT (UiMenuList != NULL);\r
+  Link = GetFirstNode (&gMenuList);\r
+  while (!IsNull (&gMenuList, Link)) {\r
+    MenuList = UI_MENU_LIST_FROM_LINK (Link);\r
 \r
-  UiMenuList->Signature = UI_MENU_LIST_SIGNATURE;\r
-  UiMenuList->FormId = Selection->FormId;\r
-  UiMenuList->QuestionId = Selection->QuestionId;\r
+    Child = UiFindChildMenuList(MenuList, FormSetGuid, FormId);\r
+    if (Child != NULL) {\r
+      return Child;\r
+    }\r
+\r
+    Link = GetNextNode (&gMenuList, Link);\r
+  }\r
 \r
-  InsertHeadList (&gMenuList, &UiMenuList->MenuLink);\r
+  return NULL;\r
 }\r
 \r
 \r
@@ -244,52 +301,217 @@ UiAddMenuListEntry (
 \r
 **/\r
 VOID\r
-UiFreeMenu (\r
+UiFreeRefreshList (\r
   VOID\r
   )\r
 {\r
-  UI_MENU_OPTION  *MenuOption;\r
+  MENU_REFRESH_ENTRY  *OldMenuRefreshEntry;\r
 \r
-  while (!IsListEmpty (&Menu)) {\r
-    MenuOption = MENU_OPTION_FROM_LINK (Menu.ForwardLink);\r
-    RemoveEntryList (&MenuOption->Link);\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
-    // We allocated space for this description when we did a GetToken, free it here\r
+    // Base on the blockspace to get the option column info.\r
     //\r
-    if (MenuOption->Skip != 0) {\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
-      // 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
+      // At this point, only "<**:" in the optionstring. \r
+      // Clean the day's ** field, after clean, the format is "<  :"\r
       //\r
-      FreePool (MenuOption->Description);\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
-    FreePool (MenuOption);\r
   }\r
 }\r
 \r
-\r
 /**\r
-  Free Menu option linked list.\r
+  Refresh question.\r
 \r
+  @param     MenuRefreshEntry    Menu refresh structure which has info about the refresh question.\r
 **/\r
-VOID\r
-UiFreeRefreshList (\r
-  VOID\r
+EFI_STATUS \r
+RefreshQuestion (\r
+  IN   MENU_REFRESH_ENTRY    *MenuRefreshEntry\r
   )\r
 {\r
-  MENU_REFRESH_ENTRY  *OldMenuRefreshEntry;\r
+  CHAR16                          *OptionString;\r
+  EFI_STATUS                      Status;\r
+  UI_MENU_SELECTION               *Selection;\r
+  FORM_BROWSER_STATEMENT          *Question;\r
 \r
-  while (gMenuRefreshHead != NULL) {\r
-    OldMenuRefreshEntry = gMenuRefreshHead->Next;\r
-    FreePool (gMenuRefreshHead);\r
-    gMenuRefreshHead = OldMenuRefreshEntry;\r
+  Selection = MenuRefreshEntry->Selection;\r
+  Question = MenuRefreshEntry->MenuOption->ThisTag;\r
+\r
+  Status = GetQuestionValue (Selection->FormSet, Selection->Form, Question, FALSE);\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
-  gMenuRefreshHead = NULL;\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
@@ -301,102 +523,27 @@ RefreshForm (
   VOID\r
   )\r
 {\r
-  CHAR16                          *OptionString;\r
   MENU_REFRESH_ENTRY              *MenuRefreshEntry;\r
-  UINTN                           Index;\r
   EFI_STATUS                      Status;\r
   UI_MENU_SELECTION               *Selection;\r
-  FORM_BROWSER_STATEMENT          *Question;\r
-  EFI_HII_CONFIG_ACCESS_PROTOCOL  *ConfigAccess;\r
-  EFI_HII_VALUE                   *HiiValue;\r
-  EFI_BROWSER_ACTION_REQUEST      ActionRequest;\r
 \r
   if (gMenuRefreshHead != NULL) {\r
-\r
+    //\r
+    // call from refresh interval process.\r
+    //\r
     MenuRefreshEntry = gMenuRefreshHead;\r
-\r
+    Selection = MenuRefreshEntry->Selection;\r
     //\r
     // Reset FormPackage update flag\r
     //\r
     mHiiPackageListUpdated = FALSE;\r
 \r
     do {\r
-      gST->ConOut->SetAttribute (gST->ConOut, MenuRefreshEntry->CurrentAttribute);\r
-\r
-      Selection = MenuRefreshEntry->Selection;\r
-      Question = MenuRefreshEntry->MenuOption->ThisTag;\r
-\r
-      Status = GetQuestionValue (Selection->FormSet, Selection->Form, Question, FALSE);\r
+      Status = RefreshQuestion (MenuRefreshEntry);\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 leading spaces on OptionString - remove the spaces\r
-        //\r
-        for (Index = 0; OptionString[Index] == L' '; Index++)\r
-          ;\r
-\r
-        PrintStringAt (MenuRefreshEntry->CurrentColumn, MenuRefreshEntry->CurrentRow, &OptionString[Index]);\r
-        FreePool (OptionString);\r
-      }\r
-\r
-      //\r
-      // Question value may be changed, need invoke its Callback()\r
-      //\r
-      ConfigAccess = Selection->FormSet->ConfigAccess;\r
-      if (((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) && (ConfigAccess != NULL)) {\r
-        ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;\r
-\r
-        HiiValue = &Question->HiiValue;\r
-        if (HiiValue->Type == EFI_IFR_TYPE_STRING) {\r
-          //\r
-          // Create String in HII database for Configuration Driver to retrieve\r
-          //\r
-          HiiValue->Value.string = NewString ((CHAR16 *) Question->BufferValue, Selection->FormSet->HiiHandle);\r
-        }\r
-\r
-        Status = ConfigAccess->Callback (\r
-                                 ConfigAccess,\r
-                                 EFI_BROWSER_ACTION_CHANGING,\r
-                                 Question->QuestionId,\r
-                                 HiiValue->Type,\r
-                                 &HiiValue->Value,\r
-                                 &ActionRequest\r
-                                 );\r
-\r
-        if (HiiValue->Type == EFI_IFR_TYPE_STRING) {\r
-          //\r
-          // Clean the String in HII Database\r
-          //\r
-          DeleteString (HiiValue->Value.string, Selection->FormSet->HiiHandle);\r
-        }\r
-\r
-        if (!EFI_ERROR (Status)) {\r
-          switch (ActionRequest) {\r
-          case EFI_BROWSER_ACTION_REQUEST_RESET:\r
-            gResetRequired = TRUE;\r
-            break;\r
-\r
-          case EFI_BROWSER_ACTION_REQUEST_SUBMIT:\r
-            SubmitForm (Selection->FormSet, Selection->Form);\r
-            break;\r
-\r
-          case EFI_BROWSER_ACTION_REQUEST_EXIT:\r
-            Selection->Action = UI_ACTION_EXIT;\r
-            gNvUpdateRequired = FALSE;\r
-            break;\r
-\r
-          default:\r
-            break;\r
-          }\r
-        }\r
-      }\r
-\r
       MenuRefreshEntry = MenuRefreshEntry->Next;\r
 \r
     } while (MenuRefreshEntry != NULL);\r
@@ -520,15 +667,19 @@ UiWaitForSingleEvent (
 \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
-VOID\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
@@ -539,6 +690,7 @@ UiAddMenuOption (
   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
@@ -583,13 +735,51 @@ UiAddMenuOption (
       MenuOption->GrayOut = Statement->GrayOutExpression->Result.Value.b;\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
+    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
     }\r
 \r
-    InsertTailList (&Menu, &MenuOption->Link);\r
+    InsertTailList (&gMenuOption, &MenuOption->Link);\r
   }\r
+\r
+  return MenuOption;\r
 }\r
 \r
 \r
@@ -620,6 +810,7 @@ UiAddMenuOption (
 \r
 **/\r
 EFI_STATUS\r
+EFIAPI\r
 CreateDialog (\r
   IN  UINTN                       NumberOfLines,\r
   IN  BOOLEAN                     HotKey,\r
@@ -630,7 +821,6 @@ CreateDialog (
   )\r
 {\r
   VA_LIST       Marker;\r
-  VA_LIST       MarkerBackup;\r
   UINTN         Count;\r
   EFI_INPUT_KEY Key;\r
   UINTN         LargestString;\r
@@ -661,7 +851,6 @@ CreateDialog (
   ASSERT (BufferedString);\r
 \r
   VA_START (Marker, KeyValue);\r
-  MarkerBackup = Marker;\r
 \r
   //\r
   // Zero the outgoing buffer\r
@@ -702,6 +891,7 @@ CreateDialog (
       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
@@ -711,7 +901,9 @@ CreateDialog (
   //\r
   // Display the Popup\r
   //\r
-  CreateSharedPopUp (LargestString, NumberOfLines, MarkerBackup);\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
@@ -919,7 +1111,8 @@ CreateSharedPopUp (
 \r
 **/\r
 VOID\r
-CreatePopUp (\r
+EFIAPI\r
+CreateMultiStringPopUp (\r
   IN  UINTN                       RequestedWidth,\r
   IN  UINTN                       NumberOfLines,\r
   ...\r
@@ -928,7 +1121,7 @@ CreatePopUp (
   VA_LIST Marker;\r
 \r
   VA_START (Marker, NumberOfLines);\r
-  \r
+\r
   CreateSharedPopUp (RequestedWidth, NumberOfLines, Marker);\r
 \r
   VA_END (Marker);\r
@@ -938,6 +1131,7 @@ CreatePopUp (
 /**\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
@@ -945,6 +1139,7 @@ CreatePopUp (
 **/\r
 VOID\r
 UpdateStatusBar (\r
+  IN  UI_MENU_SELECTION           *Selection,\r
   IN  UINTN                       MessageType,\r
   IN  UINT8                       Flags,\r
   IN  BOOLEAN                     State\r
@@ -953,7 +1148,10 @@ UpdateStatusBar (
   UINTN           Index;\r
   CHAR16          *NvUpdateMessage;\r
   CHAR16          *InputErrorMessage;\r
-\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
@@ -968,7 +1166,7 @@ UpdateStatusBar (
         );\r
       mInputError = TRUE;\r
     } else {\r
-      gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT);\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
@@ -978,40 +1176,69 @@ UpdateStatusBar (
     break;\r
 \r
   case NV_UPDATE_REQUIRED:\r
-    if (gClassOfVfr != EFI_FRONT_PAGE_SUBCLASS) {\r
-      if (State) {\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
-        gResetRequired    = (BOOLEAN) (gResetRequired | ((Flags & EFI_IFR_FLAG_RESET_REQUIRED) == EFI_IFR_FLAG_RESET_REQUIRED));\r
-\r
-        gNvUpdateRequired = TRUE;\r
-      } else {\r
-        gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT);\r
-        for (Index = 0; Index < (GetStringWidth (NvUpdateMessage) - 2) / 2; Index++) {\r
-          PrintAt (\r
-            (gScreenDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + Index),\r
-            gScreenDimensions.BottomRow - 1,\r
-            L"  "\r
-            );\r
-        }\r
-\r
-        gNvUpdateRequired = FALSE;\r
+      }\r
+    } 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 (INPUT_ERROR, Flags, TRUE);\r
+      UpdateStatusBar (Selection, INPUT_ERROR, Flags, TRUE);\r
     }\r
 \r
-    if (gNvUpdateRequired) {\r
-      UpdateStatusBar (NV_UPDATE_REQUIRED, Flags, TRUE);\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
@@ -1073,7 +1300,7 @@ GetWidth (
     Width -= SUBTITLE_INDENT;\r
   }\r
 \r
-  return Width;\r
+  return (UINT16) (Width - LEFT_SKIPPED_COLUMNS);\r
 }\r
 \r
 /**\r
@@ -1182,16 +1409,12 @@ GetLineByWidth (
 \r
   @param  Selection              The user's selection.\r
   @param  MenuOption             The MenuOption to be checked.\r
-  @param  OptionalString         The option string.\r
-  @param  SkipValue              The number of lins to skip.\r
 \r
 **/\r
 VOID\r
 UpdateOptionSkipLines (\r
   IN UI_MENU_SELECTION            *Selection,\r
-  IN UI_MENU_OPTION               *MenuOption,\r
-  OUT CHAR16                       **OptionalString,\r
-  IN UINTN                        SkipValue\r
+  IN UI_MENU_OPTION               *MenuOption\r
   )\r
 {\r
   UINTN   Index;\r
@@ -1202,9 +1425,7 @@ UpdateOptionSkipLines (
   CHAR16  *OptionString;\r
 \r
   Row           = 0;\r
-  OptionString  = *OptionalString;\r
-  OutputString  = NULL;\r
-\r
+  OptionString  = NULL;\r
   ProcessOptions (Selection, MenuOption, FALSE, &OptionString);\r
 \r
   if (OptionString != NULL) {\r
@@ -1216,32 +1437,29 @@ UpdateOptionSkipLines (
       //\r
       // If there is more string to process print on the next row and increment the Skip value\r
       //\r
-      if (StrLen (&OptionString[Index])) {\r
-        if (SkipValue == 0) {\r
-          Row++;\r
-          //\r
-          // Since the Number of lines for this menu entry may or may not be reflected accurately\r
-          // since the prompt might be 1 lines and option might be many, and vice versa, we need to do\r
-          // some testing to ensure we are keeping this in-sync.\r
-          //\r
-          // If the difference in rows is greater than or equal to the skip value, increase the skip value\r
-          //\r
-          if ((Row - OriginalRow) >= MenuOption->Skip) {\r
-            MenuOption->Skip++;\r
-          }\r
+      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
-      if (SkipValue != 0) {\r
-        SkipValue--;\r
-      }\r
     }\r
 \r
     Row = OriginalRow;\r
   }\r
 \r
-  *OptionalString = OptionString;\r
+  if (OptionString != NULL) {\r
+    FreePool (OptionString);\r
+  }\r
 }\r
 \r
 \r
@@ -1274,7 +1492,7 @@ IsSelectable (
   Determine if the menu is the last menu that can be selected.\r
 \r
   This is an internal function.\r
-  \r
+\r
   @param  Direction              The scroll direction. False is down. True is up.\r
   @param  CurrentPos             The current focus.\r
 \r
@@ -1289,84 +1507,86 @@ ValueIsScroll (
   )\r
 {\r
   LIST_ENTRY      *Temp;\r
-  UI_MENU_OPTION  *MenuOption;\r
 \r
   Temp = Direction ? CurrentPos->BackLink : CurrentPos->ForwardLink;\r
 \r
-  if (Temp == &Menu) {\r
+  if (Temp == &gMenuOption) {\r
     return TRUE;\r
   }\r
 \r
-  for (; Temp != &Menu; Temp = Direction ? Temp->BackLink : Temp->ForwardLink) {\r
-    MenuOption = MENU_OPTION_FROM_LINK (Temp);\r
-    if (IsSelectable (MenuOption)) {\r
-      return FALSE;\r
-    }\r
-  }\r
-\r
-  return TRUE;\r
+  return FALSE;\r
 }\r
 \r
 \r
 /**\r
   Move to next selectable statement.\r
-  \r
+\r
   This is an internal function.\r
-  \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
 **/\r
 INTN\r
 MoveToNextStatement (\r
+  IN     UI_MENU_SELECTION         *Selection,\r
   IN     BOOLEAN                   GoUp,\r
-  IN OUT LIST_ENTRY                **CurrentPosition\r
+  IN OUT LIST_ENTRY                **CurrentPosition,\r
+  IN     UINTN                     GapToTop\r
   )\r
 {\r
   INTN             Distance;\r
   LIST_ENTRY       *Pos;\r
-  BOOLEAN          HitEnd;\r
   UI_MENU_OPTION   *NextMenuOption;\r
+  UI_MENU_OPTION   *PreMenuOption;\r
 \r
-  Distance = 0;\r
-  Pos      = *CurrentPosition;\r
-  HitEnd   = FALSE;\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
+    if (NextMenuOption->Row == 0) {\r
+      UpdateOptionSkipLines (Selection, NextMenuOption);\r
+    }\r
+    \r
+    if (GoUp && (PreMenuOption != NextMenuOption)) {\r
+      //\r
+      // Current Position doesn't need to be caculated when go up.\r
+      // Caculate distanct at first when go up\r
+      //\r
+      if ((UINTN) Distance + NextMenuOption->Skip > GapToTop) {\r
+        NextMenuOption = PreMenuOption;\r
+        break;\r
+      }\r
+      Distance += NextMenuOption->Skip;\r
+    }\r
     if (IsSelectable (NextMenuOption)) {\r
       break;\r
     }\r
-    if ((GoUp ? Pos->BackLink : Pos->ForwardLink) == &Menu) {\r
-      HitEnd = TRUE;\r
+    if ((GoUp ? Pos->BackLink : Pos->ForwardLink) == &gMenuOption) {\r
+      //\r
+      // Arrive at top.\r
+      //\r
+      Distance = -1;\r
       break;\r
     }\r
-    Distance += NextMenuOption->Skip;\r
-    Pos = (GoUp ? Pos->BackLink : Pos->ForwardLink);\r
-  }\r
-\r
-  if (HitEnd) {\r
-    //\r
-    // If we hit end there is still no statement can be focused,\r
-    // we go backwards to find the statement can be focused.\r
-    //\r
-    Distance = 0;\r
-    Pos = *CurrentPosition;\r
-\r
-    while (TRUE) {\r
-      NextMenuOption = MENU_OPTION_FROM_LINK (Pos);\r
-      if (IsSelectable (NextMenuOption)) {\r
-        break;\r
-      }\r
-      if ((!GoUp ? Pos->BackLink : Pos->ForwardLink) == &Menu) {\r
-        ASSERT (FALSE);\r
+    if (!GoUp) {\r
+      //\r
+      // Caculate distanct at later when go down\r
+      //\r
+      if ((UINTN) Distance + NextMenuOption->Skip > GapToTop) {\r
+        NextMenuOption = PreMenuOption;\r
         break;\r
       }\r
-      Distance -= NextMenuOption->Skip;\r
-      Pos = (!GoUp ? Pos->BackLink : Pos->ForwardLink);\r
+      Distance += NextMenuOption->Skip;\r
     }\r
+    PreMenuOption = NextMenuOption;\r
+    Pos = (GoUp ? Pos->BackLink : Pos->ForwardLink);\r
   }\r
 \r
   *CurrentPosition = &NextMenuOption->Link;\r
@@ -1378,7 +1598,7 @@ MoveToNextStatement (
   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
+\r
   This is an internal function.\r
 \r
   @param  DirectionUp            the up or down direction. False is down. True is\r
@@ -1448,6 +1668,399 @@ AdjustDateAndTimePosition (
   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
+  UINTN                           StringLen;\r
+  UINTN                           BufferSize;\r
+  EFI_DEVICE_PATH_PROTOCOL        *DevicePath;\r
+  CHAR16                          TemStr[2];\r
+  UINT8                           *DevicePathBuffer;\r
+  UINTN                           Index;\r
+  UINT8                           DigitUint8;\r
+  FORM_BROWSER_FORM               *RefForm;\r
+  EFI_INPUT_KEY                   Key;\r
+  EFI_STATUS                      Status;\r
+  UI_MENU_LIST                    *MenuList;\r
+  BOOLEAN                         UpdateFormInfo;\r
+  \r
+  Status = EFI_SUCCESS;\r
+  UpdateFormInfo = TRUE;\r
+  StringPtr = NULL;\r
+  StringLen = 0;\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
+    if (StringPtr != NULL) {\r
+      StringLen = StrLen (StringPtr);\r
+    }\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 && StringLen != 0) {\r
+    if (Selection->Form->ModalForm) {\r
+      return Status;\r
+    }\r
+    //\r
+    // Goto another Hii Package list\r
+    //\r
+    Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
+    BufferSize = StrLen (StringPtr) / 2;\r
+    DevicePath = AllocatePool (BufferSize);\r
+    ASSERT (DevicePath != NULL);\r
+\r
+    //\r
+    // Convert from Device Path String to DevicePath Buffer in the reverse order.\r
+    //\r
+    DevicePathBuffer = (UINT8 *) DevicePath;\r
+    for (Index = 0; StringPtr[Index] != L'\0'; Index ++) {\r
+      TemStr[0] = StringPtr[Index];\r
+      DigitUint8 = (UINT8) StrHexToUint64 (TemStr);\r
+      if (DigitUint8 == 0 && TemStr[0] != L'0') {\r
+        //\r
+        // Invalid Hex Char as the tail.\r
+        //\r
+        break;\r
+      }\r
+      if ((Index & 1) == 0) {\r
+        DevicePathBuffer [Index/2] = DigitUint8;\r
+      } else {\r
+        DevicePathBuffer [Index/2] = (UINT8) ((DevicePathBuffer [Index/2] << 4) + DigitUint8);\r
+      }\r
+    }\r
+    FreePool (StringPtr);\r
+\r
+    Selection->Handle = DevicePathToHiiHandle (DevicePath);\r
+    FreePool (DevicePath);\r
+\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
+      Status = EvaluateExpression (Selection->FormSet, RefForm, RefForm->SuppressExpression);\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+\r
+      if (RefForm->SuppressExpression->Result.Value.b) {\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
+    UpdateFormInfo = FALSE;\r
+  } else {\r
+    if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {\r
+      Selection->Action = UI_ACTION_REFRESH_FORM;\r
+    }\r
+    UpdateFormInfo = FALSE;\r
+  }\r
+\r
+  if (UpdateFormInfo) {\r
+    //\r
+    // Link current form so that we can always go back when someone hits the ESC\r
+    //\r
+    MenuList = UiFindMenuList (&Selection->FormSetGuid, Selection->FormId);\r
+    if (MenuList == NULL && Selection->CurrentMenu != NULL) {\r
+      MenuList = UiAddMenuList (Selection->CurrentMenu, Selection->Handle, &Selection->FormSetGuid, Selection->FormId);\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
@@ -1476,17 +2089,17 @@ UiDisplayMenu (
   UINTN                           BottomRow;\r
   UINTN                           OriginalRow;\r
   UINTN                           Index;\r
-  UINT32                          Count;\r
   UINT16                          Width;\r
   CHAR16                          *StringPtr;\r
   CHAR16                          *OptionString;\r
   CHAR16                          *OutputString;\r
   CHAR16                          *FormattedString;\r
-  CHAR16                          YesResponse;\r
-  CHAR16                          NoResponse;\r
   BOOLEAN                         NewLine;\r
   BOOLEAN                         Repaint;\r
   BOOLEAN                         SavedValue;\r
+  BOOLEAN                         UpArrow;\r
+  BOOLEAN                         DownArrow;\r
+  BOOLEAN                         InitializedFlag;\r
   EFI_STATUS                      Status;\r
   EFI_INPUT_KEY                   Key;\r
   LIST_ENTRY                      *Link;\r
@@ -1500,12 +2113,14 @@ UiDisplayMenu (
   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
-  UINTN                           BufferSize;\r
   UINT16                          DefaultId;\r
-  EFI_DEVICE_PATH_PROTOCOL        *DevicePath;\r
   FORM_BROWSER_STATEMENT          *Statement;\r
+  UI_MENU_LIST                    *CurrentMenu;\r
+  UINTN                           ModalSkipColumn;\r
+  BROWSER_HOT_KEY                 *HotKey;\r
 \r
   CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));\r
 \r
@@ -1518,8 +2133,8 @@ UiDisplayMenu (
   DefaultId           = 0;\r
 \r
   OutputString        = NULL;\r
-  gUpArrow            = FALSE;\r
-  gDownArrow          = FALSE;\r
+  UpArrow             = FALSE;\r
+  DownArrow           = FALSE;\r
   SkipValue           = 0;\r
   OldSkipValue        = 0;\r
   MenuRefreshEntry    = gMenuRefreshHead;\r
@@ -1527,10 +2142,12 @@ UiDisplayMenu (
   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 == EFI_FRONT_PAGE_SUBCLASS) {\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
@@ -1538,8 +2155,13 @@ UiDisplayMenu (
     Row     = LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT;\r
   }\r
 \r
-  Col = LocalScreen.LeftColumn;\r
-  BottomRow = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT - SCROLL_ARROW_HEIGHT - 1;\r
+  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
@@ -1547,24 +2169,46 @@ UiDisplayMenu (
   Selection->OptionCol = gPromptBlockWidth + 1 + LocalScreen.LeftColumn;\r
   Selection->Statement = NULL;\r
 \r
-  TopOfScreen = Menu.ForwardLink;\r
+  TopOfScreen = gMenuOption.ForwardLink;\r
   Repaint     = TRUE;\r
   MenuOption  = NULL;\r
 \r
   //\r
-  // Get user's selection\r
+  // Find current Menu\r
+  //\r
+  CurrentMenu = UiFindMenuList (&Selection->FormSetGuid, Selection->FormId);\r
+  if (CurrentMenu == NULL) {\r
+    //\r
+    // Current menu not found, add it to the menu tree\r
+    //\r
+    CurrentMenu = UiAddMenuList (NULL, 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
-  NewPos = Menu.ForwardLink;\r
+  InitializedFlag = TRUE;\r
+  NewPos = gMenuOption.ForwardLink;\r
 \r
   gST->ConOut->EnableCursor (gST->ConOut, FALSE);\r
-  UpdateStatusBar (REFRESH_STATUS_BAR, (UINT8) 0, TRUE);\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 (&Menu)) {\r
+      if (IsListEmpty (&gMenuOption)) {\r
         ControlFlag = CfReadKey;\r
       } else {\r
         ControlFlag = CfCheckSelection;\r
@@ -1586,29 +2230,42 @@ UiDisplayMenu (
         //\r
         // Display menu\r
         //\r
-        gDownArrow      = FALSE;\r
-        gUpArrow        = FALSE;\r
+        DownArrow       = FALSE;\r
+        UpArrow         = FALSE;\r
         Row             = TopRow;\r
 \r
-        Temp            = SkipValue;\r
-        Temp2           = SkipValue;\r
-\r
-        ClearLines (\r
-          LocalScreen.LeftColumn,\r
-          LocalScreen.RightColumn,\r
-          TopRow - SCROLL_ARROW_HEIGHT,\r
-          BottomRow + SCROLL_ARROW_HEIGHT,\r
-          FIELD_TEXT | FIELD_BACKGROUND\r
-          );\r
+        Temp            = (UINTN) SkipValue;\r
+        Temp2           = (UINTN) SkipValue;\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
-        for (Link = TopOfScreen; Link != &Menu; Link = Link->ForwardLink) {\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
-          MenuOption->OptCol  = gPromptBlockWidth + 1 + LocalScreen.LeftColumn;\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
@@ -1619,13 +2276,25 @@ UiDisplayMenu (
             gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_GRAYED | FIELD_BACKGROUND);\r
           } else {\r
             if (Statement->Operand == EFI_IFR_SUBTITLE_OP) {\r
-              gST->ConOut->SetAttribute (gST->ConOut, SUBTITLE_TEXT | FIELD_BACKGROUND);\r
+              gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserSubtitleTextColor) | FIELD_BACKGROUND);\r
             }\r
           }\r
 \r
           Width       = GetWidth (Statement, MenuOption->Handle);\r
           OriginalRow = Row;\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
           for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) {\r
             if ((Temp == 0) && (Row <= BottomRow)) {\r
               PrintStringAt (MenuOption->Col, Row, OutputString);\r
@@ -1633,7 +2302,7 @@ UiDisplayMenu (
             //\r
             // If there is more string to process print on the next row and increment the Skip value\r
             //\r
-            if (StrLen (&MenuOption->Description[Index])) {\r
+            if (StrLen (&MenuOption->Description[Index]) != 0) {\r
               if (Temp == 0) {\r
                 Row++;\r
               }\r
@@ -1648,7 +2317,6 @@ UiDisplayMenu (
           Temp  = 0;\r
           Row   = OriginalRow;\r
 \r
-          gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
           Status = ProcessOptions (Selection, MenuOption, FALSE, &OptionString);\r
           if (EFI_ERROR (Status)) {\r
             //\r
@@ -1662,60 +2330,7 @@ UiDisplayMenu (
 \r
           if (OptionString != NULL) {\r
             if (Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) {\r
-              //\r
-              // If leading spaces on OptionString - remove the spaces\r
-              //\r
-              for (Index = 0; OptionString[Index] == L' '; Index++) {\r
-                MenuOption->OptCol++;\r
-              }\r
-\r
-              for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) {\r
-                OptionString[Count] = OptionString[Index];\r
-                Count++;\r
-              }\r
-\r
-              OptionString[Count] = CHAR_NULL;\r
-            }\r
-\r
-            //\r
-            // If Question request refresh, register the op-code\r
-            //\r
-            if (Statement->RefreshInterval != 0) {\r
-              //\r
-              // Menu will be refreshed at minimal interval of all Questions\r
-              // which have refresh request\r
-              //\r
-              if (MinRefreshInterval == 0 || Statement->RefreshInterval < MinRefreshInterval) {\r
-                MinRefreshInterval = Statement->RefreshInterval;\r
-              }\r
-\r
-              if (gMenuRefreshHead == NULL) {\r
-                MenuRefreshEntry = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY));\r
-                ASSERT (MenuRefreshEntry != NULL);\r
-                MenuRefreshEntry->MenuOption        = MenuOption;\r
-                MenuRefreshEntry->Selection         = Selection;\r
-                MenuRefreshEntry->CurrentColumn     = MenuOption->OptCol;\r
-                MenuRefreshEntry->CurrentRow        = MenuOption->Row;\r
-                MenuRefreshEntry->CurrentAttribute  = FIELD_TEXT | FIELD_BACKGROUND;\r
-                gMenuRefreshHead                    = MenuRefreshEntry;\r
-              } else {\r
-                //\r
-                // Advance to the last entry\r
-                //\r
-                for (MenuRefreshEntry = gMenuRefreshHead;\r
-                     MenuRefreshEntry->Next != NULL;\r
-                     MenuRefreshEntry = MenuRefreshEntry->Next\r
-                    )\r
-                  ;\r
-                MenuRefreshEntry->Next = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY));\r
-                ASSERT (MenuRefreshEntry->Next != NULL);\r
-                MenuRefreshEntry                    = MenuRefreshEntry->Next;\r
-                MenuRefreshEntry->MenuOption        = MenuOption;\r
-                MenuRefreshEntry->Selection         = Selection;\r
-                MenuRefreshEntry->CurrentColumn     = MenuOption->OptCol;\r
-                MenuRefreshEntry->CurrentRow        = MenuOption->Row;\r
-                MenuRefreshEntry->CurrentAttribute  = FIELD_TEXT | FIELD_BACKGROUND;\r
-              }\r
+              ProcessStringForDateTime(MenuOption, OptionString, TRUE);\r
             }\r
 \r
             Width       = (UINT16) gOptionBlockWidth;\r
@@ -1728,7 +2343,7 @@ UiDisplayMenu (
               //\r
               // If there is more string to process print on the next row and increment the Skip value\r
               //\r
-              if (StrLen (&OptionString[Index])) {\r
+              if (StrLen (&OptionString[Index]) != 0) {\r
                 if (Temp2 == 0) {\r
                   Row++;\r
                   //\r
@@ -1755,26 +2370,91 @@ UiDisplayMenu (
 \r
             FreePool (OptionString);\r
           }\r
+\r
           //\r
-          // If this is a text op with secondary text information\r
+          // If Question has refresh guid, register the op-code.\r
           //\r
-          if ((Statement->Operand == EFI_IFR_TEXT_OP) && (Statement->TextTwo != 0)) {\r
-            StringPtr   = GetToken (Statement->TextTwo, MenuOption->Handle);\r
-\r
-            Width       = (UINT16) gOptionBlockWidth;\r
-            OriginalRow = Row;\r
-\r
-            for (Index = 0; GetLineByWidth (StringPtr, Width, &Index, &OutputString) != 0x0000;) {\r
-              if ((Temp == 0) && (Row <= BottomRow)) {\r
-                PrintStringAt (MenuOption->OptCol, Row, OutputString);\r
+          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
-              //\r
-              // If there is more string to process print on the next row and increment the Skip value\r
-              //\r
-              if (StrLen (&StringPtr[Index])) {\r
-                if (Temp2 == 0) {\r
-                  Row++;\r
-                  //\r
+              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
+\r
+            for (Index = 0; GetLineByWidth (StringPtr, Width, &Index, &OutputString) != 0x0000;) {\r
+              if ((Temp == 0) && (Row <= BottomRow)) {\r
+                PrintStringAt (MenuOption->OptCol, Row, OutputString);\r
+              }\r
+              //\r
+              // If there is more string to process print on the next row and increment the Skip value\r
+              //\r
+              if (StrLen (&StringPtr[Index]) != 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
@@ -1796,6 +2476,7 @@ UiDisplayMenu (
             Row = OriginalRow;\r
             FreePool (StringPtr);\r
           }\r
+          gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND);\r
 \r
           //\r
           // Need to handle the bottom of the display\r
@@ -1809,7 +2490,7 @@ UiDisplayMenu (
 \r
           if (Row > BottomRow) {\r
             if (!ValueIsScroll (FALSE, Link)) {\r
-              gDownArrow = TRUE;\r
+              DownArrow = TRUE;\r
             }\r
 \r
             Row = BottomRow + 1;\r
@@ -1818,10 +2499,10 @@ UiDisplayMenu (
         }\r
 \r
         if (!ValueIsScroll (TRUE, TopOfScreen)) {\r
-          gUpArrow = TRUE;\r
+          UpArrow = TRUE;\r
         }\r
 \r
-        if (gUpArrow) {\r
+        if (UpArrow) {\r
           gST->ConOut->SetAttribute (gST->ConOut, ARROW_TEXT | ARROW_BACKGROUND);\r
           PrintAt (\r
             LocalScreen.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1,\r
@@ -1829,10 +2510,10 @@ UiDisplayMenu (
             L"%c",\r
             ARROW_UP\r
             );\r
-          gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
+          gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND);\r
         }\r
 \r
-        if (gDownArrow) {\r
+        if (DownArrow) {\r
           gST->ConOut->SetAttribute (gST->ConOut, ARROW_TEXT | ARROW_BACKGROUND);\r
           PrintAt (\r
             LocalScreen.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1,\r
@@ -1840,7 +2521,7 @@ UiDisplayMenu (
             L"%c",\r
             ARROW_DOWN\r
             );\r
-          gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
+          gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND);\r
         }\r
 \r
         MenuOption = NULL;\r
@@ -1854,6 +2535,10 @@ UiDisplayMenu (
       // NewPos:     Current menu option that need to hilight\r
       //\r
       ControlFlag = CfUpdateHelpString;\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
@@ -1863,10 +2548,12 @@ UiDisplayMenu (
       Repaint     = FALSE;\r
 \r
       if (Selection->QuestionId != 0) {\r
-        NewPos = Menu.ForwardLink;\r
+        NewPos = gMenuOption.ForwardLink;\r
         SavedMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
 \r
-        while (SavedMenuOption->ThisTag->QuestionId != Selection->QuestionId && NewPos->ForwardLink != &Menu) {\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
@@ -1879,20 +2566,49 @@ UiDisplayMenu (
           for (Index = TopRow; Index <= BottomRow && Link != NewPos;) {\r
             SavedMenuOption = MENU_OPTION_FROM_LINK (Link);\r
             Index += SavedMenuOption->Skip;\r
+            if (Link == TopOfScreen) {\r
+              Index -= OldSkipValue;\r
+            }\r
             Link = Link->ForwardLink;\r
           }\r
+          if (NewPos == Link) {\r
+            SavedMenuOption = MENU_OPTION_FROM_LINK (Link);\r
+          }\r
 \r
-          if (Link != NewPos || Index > BottomRow) {\r
+          if (Link != NewPos || Index > BottomRow || (Link == NewPos && SavedMenuOption->Row + SavedMenuOption->Skip - 1 > BottomRow)) {\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
             Link    = NewPos;\r
-            for (Index = TopRow; Index <= BottomRow; ) {\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
-            TopOfScreen     = Link->ForwardLink;\r
+            \r
+            SkipValue = Index - BottomRow - 1;\r
+            if (SkipValue > 0 && SkipValue < (INTN) SavedMenuOption->Skip) {\r
+              TopOfScreen     = Link;\r
+              OldSkipValue    = SkipValue;\r
+            } else {\r
+              SkipValue       = 0;\r
+              TopOfScreen     = Link->ForwardLink;\r
+            }\r
 \r
             Repaint = TRUE;\r
             NewLine = TRUE;\r
@@ -1916,23 +2632,12 @@ UiDisplayMenu (
           //\r
           gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row);\r
           ProcessOptions (Selection, MenuOption, FALSE, &OptionString);\r
-          gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
+          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
-              //\r
-              // If leading spaces on OptionString - remove the spaces\r
-              //\r
-              for (Index = 0; OptionString[Index] == L' '; Index++)\r
-                ;\r
-\r
-              for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) {\r
-                OptionString[Count] = OptionString[Index];\r
-                Count++;\r
-              }\r
-\r
-              OptionString[Count] = CHAR_NULL;\r
+              ProcessStringForDateTime(MenuOption, OptionString, FALSE);\r
             }\r
 \r
             Width               = (UINT16) gOptionBlockWidth;\r
@@ -1945,7 +2650,7 @@ UiDisplayMenu (
               //\r
               // If there is more string to process print on the next row and increment the Skip value\r
               //\r
-              if (StrLen (&OptionString[Index])) {\r
+              if (StrLen (&OptionString[Index]) != 0) {\r
                 MenuOption->Row++;\r
               }\r
 \r
@@ -1960,7 +2665,7 @@ UiDisplayMenu (
               if (MenuOption->GrayOut) {\r
                 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_GRAYED | FIELD_BACKGROUND);\r
               } else if (MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP) {\r
-                gST->ConOut->SetAttribute (gST->ConOut, SUBTITLE_TEXT | FIELD_BACKGROUND);\r
+                gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserSubtitleTextColor) | FIELD_BACKGROUND);\r
               }\r
 \r
               OriginalRow = MenuOption->Row;\r
@@ -1973,7 +2678,7 @@ UiDisplayMenu (
                 //\r
                 // If there is more string to process print on the next row and increment the Skip value\r
                 //\r
-                if (StrLen (&MenuOption->Description[Index])) {\r
+                if (StrLen (&MenuOption->Description[Index]) != 0) {\r
                   MenuOption->Row++;\r
                 }\r
 \r
@@ -1981,33 +2686,33 @@ UiDisplayMenu (
               }\r
 \r
               MenuOption->Row = OriginalRow;\r
-              gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
+              gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND);\r
             }\r
           }\r
         }\r
 \r
         //\r
-        // This is only possible if we entered this page and the first menu option is\r
-        // a "non-menu" item.  In that case, force it UiDown\r
+        // 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
-          ASSERT (ScreenOperation == UiNoOperation);\r
-          ScreenOperation = UiDown;\r
-          ControlFlag     = CfScreenOperation;\r
+          Repaint = SavedValue;\r
+          UpdateKeyHelp (Selection, MenuOption, FALSE);\r
           break;\r
         }\r
 \r
         //\r
-        // This is the current selected statement\r
+        // Record highlight for current menu\r
         //\r
-        Statement = MenuOption->ThisTag;\r
-        Selection->Statement = Statement;\r
+        CurrentMenu->QuestionId = Statement->QuestionId;\r
+        CurrentMenu->Sequence   = MenuOption->Sequence;\r
 \r
         //\r
         // Set reverse attribute\r
         //\r
-        gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT | FIELD_BACKGROUND_HIGHLIGHT);\r
+        gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextHighlightColor) | PcdGet8 (PcdBrowserFieldBackgroundHighlightColor));\r
         gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row);\r
 \r
         //\r
@@ -2017,9 +2722,13 @@ UiDisplayMenu (
         //\r
         if (gMenuRefreshHead != NULL) {\r
           for (MenuRefreshEntry = gMenuRefreshHead; MenuRefreshEntry != NULL; MenuRefreshEntry = MenuRefreshEntry->Next) {\r
-            MenuRefreshEntry->CurrentAttribute = FIELD_TEXT | FIELD_BACKGROUND;\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 = FIELD_TEXT_HIGHLIGHT | FIELD_BACKGROUND_HIGHLIGHT;\r
+              MenuRefreshEntry->CurrentAttribute = PcdGet8 (PcdBrowserFieldTextHighlightColor) | PcdGet8 (PcdBrowserFieldBackgroundHighlightColor);\r
             }\r
           }\r
         }\r
@@ -2027,18 +2736,7 @@ UiDisplayMenu (
         ProcessOptions (Selection, MenuOption, FALSE, &OptionString);\r
         if (OptionString != NULL) {\r
           if (Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) {\r
-            //\r
-            // If leading spaces on OptionString - remove the spaces\r
-            //\r
-            for (Index = 0; OptionString[Index] == L' '; Index++)\r
-              ;\r
-\r
-            for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) {\r
-              OptionString[Count] = OptionString[Index];\r
-              Count++;\r
-            }\r
-\r
-            OptionString[Count] = CHAR_NULL;\r
+            ProcessStringForDateTime(MenuOption, OptionString, FALSE);\r
           }\r
           Width               = (UINT16) gOptionBlockWidth;\r
 \r
@@ -2051,7 +2749,7 @@ UiDisplayMenu (
             //\r
             // If there is more string to process print on the next row and increment the Skip value\r
             //\r
-            if (StrLen (&OptionString[Index])) {\r
+            if (StrLen (&OptionString[Index]) != 0) {\r
               MenuOption->Row++;\r
             }\r
 \r
@@ -2074,7 +2772,7 @@ UiDisplayMenu (
               //\r
               // If there is more string to process print on the next row and increment the Skip value\r
               //\r
-              if (StrLen (&MenuOption->Description[Index])) {\r
+              if (StrLen (&MenuOption->Description[Index]) != 0) {\r
                 MenuOption->Row++;\r
               }\r
 \r
@@ -2086,12 +2784,12 @@ UiDisplayMenu (
           }\r
         }\r
 \r
-        UpdateKeyHelp (MenuOption, FALSE);\r
+        UpdateKeyHelp (Selection, MenuOption, FALSE);\r
 \r
         //\r
         // Clear reverse attribute\r
         //\r
-        gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\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
@@ -2102,12 +2800,16 @@ UiDisplayMenu (
 \r
     case CfUpdateHelpString:\r
       ControlFlag = CfPrepareToReadKey;\r
+      if (Selection->Form->ModalForm) {\r
+        break;\r
+      }\r
 \r
-        if ((Repaint || NewLine) && (gClassOfVfr != EFI_GENERAL_APPLICATION_SUBCLASS)) {\r
+      if (Repaint || NewLine) {\r
         //\r
         // Don't print anything if it is a NULL help token\r
         //\r
-        if (MenuOption->ThisTag->Help == 0) {\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
@@ -2158,29 +2860,27 @@ UiDisplayMenu (
         //\r
         // IFR is updated in Callback of refresh opcode, re-parse it\r
         //\r
-        ControlFlag = CfUiReset;\r
+        ControlFlag = CfCheckSelection;\r
         Selection->Statement = NULL;\r
         break;\r
       }\r
 \r
       Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
       //\r
-      // if we encounter error, continue to read another key in.\r
+      // If we encounter error, continue to read another key in.\r
       //\r
       if (EFI_ERROR (Status)) {\r
         ControlFlag = CfReadKey;\r
         break;\r
       }\r
 \r
-      if (IsListEmpty (&Menu) && Key.UnicodeChar != CHAR_NULL) {\r
-        //\r
-        // If the screen has no menu items, and the user didn't select UiPrevious, or UiReset\r
-        //\r
-        break;\r
-      }\r
-\r
       switch (Key.UnicodeChar) {\r
       case CHAR_CARRIAGE_RETURN:\r
+        if(MenuOption->GrayOut || MenuOption->ReadOnly) {\r
+          ControlFlag = CfReadKey;\r
+          break;\r
+        }\r
+\r
         ScreenOperation = UiSelect;\r
         gDirection      = 0;\r
         break;\r
@@ -2191,6 +2891,16 @@ UiDisplayMenu (
       //\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
@@ -2208,6 +2918,8 @@ UiDisplayMenu (
             //\r
             Repaint = TRUE;\r
             NewLine = TRUE;\r
+          } else {\r
+            Selection->Action = UI_ACTION_REFRESH_FORM;\r
           }\r
           if (OptionString != NULL) {\r
             FreePool (OptionString);\r
@@ -2225,34 +2937,46 @@ UiDisplayMenu (
         break;\r
 \r
       case ' ':\r
-        if (gClassOfVfr != EFI_FRONT_PAGE_SUBCLASS) {\r
-          if (MenuOption->ThisTag->Operand == EFI_IFR_CHECKBOX_OP && !MenuOption->GrayOut) {\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 CHAR_NULL:\r
-        if (((Key.ScanCode == SCAN_F1) && ((gFunctionKeySetting & FUNCTION_ONE) != FUNCTION_ONE)) ||\r
-            ((Key.ScanCode == SCAN_F2) && ((gFunctionKeySetting & FUNCTION_TWO) != FUNCTION_TWO)) ||\r
-            ((Key.ScanCode == SCAN_F9) && ((gFunctionKeySetting & FUNCTION_NINE) != FUNCTION_NINE)) ||\r
-            ((Key.ScanCode == SCAN_F10) && ((gFunctionKeySetting & FUNCTION_TEN) != FUNCTION_TEN))\r
-            ) {\r
+        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
-          // If the function key has been disabled, just ignore the key.\r
+          // ModalForm has no ESC key and Hot Key.\r
           //\r
-        } else {\r
-          for (Index = 0; Index < sizeof (gScanCodeToOperation) / sizeof (gScanCodeToOperation[0]); Index++) {\r
-            if (Key.ScanCode == gScanCodeToOperation[Index].ScanCode) {\r
-              if (Key.ScanCode == SCAN_F9) {\r
-                //\r
-                // Reset to standard default\r
-                //\r
-                DefaultId = EFI_HII_DEFAULT_CLASS_STANDARD;\r
-              }\r
-              ScreenOperation = gScanCodeToOperation[Index].ScreenOperation;\r
-              break;\r
-            }\r
+          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) || (gFunctionKeySetting != NONE_FUNCTION_KEY_SETTING)) {\r
+            HotKey = GetHotKeyFromRegisterList (&Key);\r
+          }\r
+          if (HotKey != NULL) {\r
+            ScreenOperation = UiHotKey;\r
           }\r
         }\r
         break;\r
@@ -2260,35 +2984,15 @@ UiDisplayMenu (
       break;\r
 \r
     case CfScreenOperation:\r
-      if (ScreenOperation != UiPrevious && ScreenOperation != UiReset) {\r
+      if (ScreenOperation != UiReset) {\r
         //\r
-        // If the screen has no menu items, and the user didn't select UiPrevious, or UiReset\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 (&Menu)) {\r
+        if (IsListEmpty (&gMenuOption)) {\r
           ControlFlag = CfReadKey;\r
           break;\r
         }\r
-        //\r
-        // if there is nothing logical to place a cursor on, just move on to wait for a key.\r
-        //\r
-        for (Link = Menu.ForwardLink; Link != &Menu; Link = Link->ForwardLink) {\r
-          NextMenuOption = MENU_OPTION_FROM_LINK (Link);\r
-          if (IsSelectable (NextMenuOption)) {\r
-            break;\r
-          }\r
-        }\r
-\r
-        if (Link == &Menu) {\r
-          ControlFlag = CfPrepareToReadKey;\r
-          break;\r
-        }\r
-      } else if (ScreenOperation == UiReset) {\r
-        //\r
-        // Press ESC to exit FormSet\r
-        //\r
-        Selection->Action = UI_ACTION_EXIT;\r
-        Selection->Statement = NULL;\r
       }\r
 \r
       for (Index = 0;\r
@@ -2302,34 +3006,12 @@ UiDisplayMenu (
       }\r
       break;\r
 \r
-    case CfUiPrevious:\r
-      ControlFlag = CfCheckSelection;\r
-\r
-      if (IsListEmpty (&gMenuList)) {\r
-        Selection->Action = UI_ACTION_NONE;\r
-        if (IsListEmpty (&Menu)) {\r
-          ControlFlag = CfReadKey;\r
-        }\r
-        break;\r
-      }\r
-\r
-      //\r
-      // Remove the Cached page entry\r
-      //\r
-      UiRemoveMenuListEntry (Selection);\r
-\r
-      Selection->Action = UI_ACTION_REFRESH_FORM;\r
-      Selection->Statement = NULL;\r
-      break;\r
-\r
     case CfUiSelect:\r
       ControlFlag = CfCheckSelection;\r
 \r
+      ASSERT(MenuOption != NULL);\r
       Statement = MenuOption->ThisTag;\r
-      if ((Statement->Operand == EFI_IFR_TEXT_OP) ||\r
-          (Statement->Operand == EFI_IFR_DATE_OP) ||\r
-          (Statement->Operand == EFI_IFR_TIME_OP) ||\r
-          (Statement->Operand == EFI_IFR_NUMERIC_OP && Statement->Step != 0)) {\r
+      if (Statement->Operand == EFI_IFR_TEXT_OP) {\r
         break;\r
       }\r
 \r
@@ -2340,79 +3022,7 @@ UiDisplayMenu (
 \r
       switch (Statement->Operand) {\r
       case EFI_IFR_REF_OP:\r
-        if (Statement->RefDevicePath != 0) {\r
-          //\r
-          // Goto another Hii Package list\r
-          //\r
-          ControlFlag = CfUiReset;\r
-          Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
-\r
-          StringPtr = GetToken (Statement->RefDevicePath, Selection->FormSet->HiiHandle);\r
-          if (StringPtr == NULL) {\r
-            //\r
-            // No device path string not found, exit\r
-            //\r
-            Selection->Action = UI_ACTION_EXIT;\r
-            Selection->Statement = NULL;\r
-            break;\r
-          }\r
-          BufferSize = StrLen (StringPtr) / 2;\r
-          DevicePath = AllocatePool (BufferSize);\r
-\r
-          HexStringToBufInReverseOrder ((UINT8 *) DevicePath, &BufferSize, StringPtr);\r
-          Selection->Handle = HiiLibDevicePathToHiiHandle (DevicePath);\r
-          if (Selection->Handle == NULL) {\r
-            //\r
-            // If target Hii Handle not found, exit\r
-            //\r
-            Selection->Action = UI_ACTION_EXIT;\r
-            Selection->Statement = NULL;\r
-            break;\r
-          }\r
-\r
-          FreePool (StringPtr);\r
-          FreePool (DevicePath);\r
-\r
-          CopyMem (&Selection->FormSetGuid, &Statement->RefFormSetId, sizeof (EFI_GUID));\r
-          Selection->FormId = Statement->RefFormId;\r
-          Selection->QuestionId = Statement->RefQuestionId;\r
-        } else if (!CompareGuid (&Statement->RefFormSetId, &gZeroGuid)) {\r
-          //\r
-          // Goto another Formset, check for uncommitted data\r
-          //\r
-          ControlFlag = CfUiReset;\r
-          Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
-\r
-          CopyMem (&Selection->FormSetGuid, &Statement->RefFormSetId, sizeof (EFI_GUID));\r
-          Selection->FormId = Statement->RefFormId;\r
-          Selection->QuestionId = Statement->RefQuestionId;\r
-        } else if (Statement->RefFormId != 0) {\r
-          //\r
-          // Goto another form inside this formset,\r
-          //\r
-          Selection->Action = UI_ACTION_REFRESH_FORM;\r
-\r
-          //\r
-          // Link current form so that we can always go back when someone hits the UiPrevious\r
-          //\r
-          UiAddMenuListEntry (Selection);\r
-\r
-          Selection->FormId = Statement->RefFormId;\r
-          Selection->QuestionId = Statement->RefQuestionId;\r
-        } else if (Statement->RefQuestionId != 0) {\r
-          //\r
-          // Goto another Question\r
-          //\r
-          Selection->QuestionId = Statement->RefQuestionId;\r
-\r
-          if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {\r
-            Selection->Action = UI_ACTION_REFRESH_FORM;\r
-          } else {\r
-            Repaint = TRUE;\r
-            NewLine = TRUE;\r
-            break;\r
-          }\r
-        }\r
+        ProcessGotoOpCode(Statement, Selection, &Repaint, &NewLine);\r
         break;\r
 \r
       case EFI_IFR_ACTION_OP:\r
@@ -2443,84 +3053,41 @@ UiDisplayMenu (
         //\r
         // Editable Questions: oneof, ordered list, checkbox, numeric, string, password\r
         //\r
-        UpdateKeyHelp (MenuOption, TRUE);\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 (MenuOption, FALSE);\r
-          } else {\r
-            Selection->Action = UI_ACTION_REFRESH_FORM;\r
-          }\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
+        if (OptionString != NULL) {\r
+          FreePool (OptionString);\r
+        }\r
         break;\r
       }\r
       break;\r
 \r
     case CfUiReset:\r
       //\r
-      // We are going to leave current FormSet, so check uncommited data in this FormSet\r
+      // We come here when someone press ESC\r
       //\r
       ControlFlag = CfCheckSelection;\r
-\r
-      if (gClassOfVfr == EFI_FRONT_PAGE_SUBCLASS) {\r
-        //\r
-        // There is no parent menu for FrontPage\r
-        //\r
-        Selection->Action = UI_ACTION_NONE;\r
-        Selection->Statement = MenuOption->ThisTag;\r
-        break;\r
-      }\r
-\r
-      //\r
-      // If NV flag is up, prompt user\r
-      //\r
-      if (gNvUpdateRequired) {\r
-        Status      = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
-\r
-        YesResponse = gYesResponse[0];\r
-        NoResponse  = gNoResponse[0];\r
-\r
-        do {\r
-          CreateDialog (3, TRUE, 0, NULL, &Key, gEmptyString, gAreYouSure, gEmptyString);\r
-        } while\r
-        (\r
-          (Key.ScanCode != SCAN_ESC) &&\r
-          ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (NoResponse | UPPER_LOWER_CASE_OFFSET)) &&\r
-          ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (YesResponse | UPPER_LOWER_CASE_OFFSET))\r
-        );\r
-\r
-        //\r
-        // If the user hits the YesResponse key\r
-        //\r
-        if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (YesResponse | UPPER_LOWER_CASE_OFFSET)) {\r
-        } else {\r
-          Repaint = TRUE;\r
-          NewLine = TRUE;\r
-\r
-          Selection->Action = UI_ACTION_NONE;\r
-          break;\r
-        }\r
-      }\r
-\r
-      gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
-      gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
-\r
-      UiFreeMenuList ();\r
-      gST->ConOut->ClearScreen (gST->ConOut);\r
-      return EFI_SUCCESS;\r
+      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
@@ -2528,11 +3095,13 @@ UiDisplayMenu (
 \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
@@ -2541,90 +3110,89 @@ UiDisplayMenu (
     case CfUiUp:\r
       ControlFlag = CfCheckSelection;\r
 \r
-      SavedListEntry = TopOfScreen;\r
-\r
-      if (NewPos->BackLink != &Menu) {\r
-        NewLine = TRUE;\r
-        //\r
-        // Adjust Date/Time position before we advance forward.\r
-        //\r
-        AdjustDateAndTimePosition (TRUE, &NewPos);\r
+      SavedListEntry = NewPos;\r
 \r
-        //\r
-        // Caution that we have already rewind to the top, don't go backward in this situation.\r
-        //\r
-        if (NewPos->BackLink != &Menu) {\r
-          NewPos = NewPos->BackLink;\r
-        }\r
+      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
-        DistanceValue = PreviousMenuOption->Skip;\r
-\r
-        //\r
-        // Since the behavior of hitting the up arrow on a Date/Time op-code is intended\r
-        // to be one that back to the previous set of op-codes, we need to advance to the sencond\r
-        // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate\r
-        // checking can be done.\r
-        //\r
-        DistanceValue += AdjustDateAndTimePosition (TRUE, &NewPos);\r
-\r
-        //\r
-        // Check the previous menu entry to see if it was a zero-length advance.  If it was,\r
-        // don't worry about a redraw.\r
-        //\r
-        if ((INTN) MenuOption->Row - (INTN) DistanceValue < (INTN) TopRow) {\r
-          Repaint     = TRUE;\r
-          TopOfScreen = NewPos;\r
+        if (PreviousMenuOption->Row == 0) {\r
+          UpdateOptionSkipLines (Selection, PreviousMenuOption);\r
         }\r
-\r
-        Difference = MoveToNextStatement (TRUE, &NewPos);\r
-        if ((INTN) MenuOption->Row - (INTN) DistanceValue < (INTN) TopRow) {\r
-          if (Difference > 0) {\r
-            //\r
-            // Previous focus MenuOption is above the TopOfScreen, so we need to scroll\r
-            //\r
-            TopOfScreen = NewPos;\r
-            Repaint     = TRUE;\r
-          }\r
+        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 want to goto previous MenuOption, but finally we go down.\r
-          // it means that we hit the begining MenuOption that can be focused\r
-          // so we simply scroll to the top\r
+          // We hit the begining MenuOption that can be focused\r
+          // so we simply scroll to the top.\r
           //\r
-          if (SavedListEntry != Menu.ForwardLink) {\r
-            TopOfScreen = Menu.ForwardLink;\r
+          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
+          OldSkipValue = 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
-\r
-        UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE);\r
+        AdjustDateAndTimePosition (TRUE, &NewPos);\r
+        MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);\r
+        UpdateStatusBar (Selection, INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE);\r
       } else {\r
-        SavedMenuOption = MenuOption;\r
-        MenuOption      = MENU_OPTION_FROM_LINK (NewPos);\r
-        if (!IsSelectable (MenuOption)) {\r
-          //\r
-          // If we are at the end of the list and sitting on a text op, we need to more forward\r
-          //\r
-          ScreenOperation = UiDown;\r
-          ControlFlag     = CfScreenOperation;\r
-          break;\r
-        }\r
-\r
-        MenuOption = SavedMenuOption;\r
+        //\r
+        // 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
       ControlFlag     = CfCheckSelection;\r
 \r
-      if (NewPos->BackLink == &Menu) {\r
+      ASSERT(NewPos != NULL);\r
+      if (NewPos->BackLink == &gMenuOption) {\r
         NewLine = FALSE;\r
         Repaint = FALSE;\r
         break;\r
@@ -2633,38 +3201,62 @@ UiDisplayMenu (
       NewLine   = TRUE;\r
       Repaint   = TRUE;\r
       Link      = TopOfScreen;\r
-      PreviousMenuOption = MENU_OPTION_FROM_LINK (Link);\r
-      Index = BottomRow;\r
-      while ((Index >= TopRow) && (Link->BackLink != &Menu)) {\r
-        Index = Index - PreviousMenuOption->Skip;\r
+      Index     = BottomRow;\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
+          Index = 0;\r
+          break;\r
+        }\r
+        Index = Index - PreviousMenuOption->Skip;\r
       }\r
+      \r
+      if ((Link->BackLink == &gMenuOption) && (Index >= TopRow)) {\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 + 1 < TopRow) {\r
+          //\r
+          // Back up the previous option.\r
+          //\r
+          Link = Link->ForwardLink;\r
+        }\r
 \r
-      TopOfScreen = Link;\r
-      Difference = MoveToNextStatement (TRUE, &Link);\r
-      if (Difference > 0) {\r
         //\r
-        // The focus MenuOption is above the TopOfScreen\r
+        // Move to the option in Next page.\r
         //\r
-        TopOfScreen = Link;\r
-      } else if (Difference < 0) {\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
-        // This happens when there is no MenuOption can be focused from\r
-        // Current MenuOption to the first MenuOption\r
+        // There are more MenuOption needing scrolling up.\r
         //\r
-        TopOfScreen = Menu.ForwardLink;\r
-      }\r
-      Index += Difference;\r
-      if (Index < TopRow) {\r
-        MenuOption = NULL;\r
-      }\r
-\r
-      if (NewPos == Link) {\r
-        Repaint = FALSE;\r
-        NewLine = FALSE;\r
-      } else {\r
-        NewPos = Link;\r
+        TopOfScreen = Link;\r
+        MenuOption  = NULL;\r
       }\r
 \r
       //\r
@@ -2678,7 +3270,8 @@ UiDisplayMenu (
     case CfUiPageDown:\r
       ControlFlag     = CfCheckSelection;\r
 \r
-      if (NewPos->ForwardLink == &Menu) {\r
+      ASSERT (NewPos != NULL);\r
+      if (NewPos->ForwardLink == &gMenuOption) {\r
         NewLine = FALSE;\r
         Repaint = FALSE;\r
         break;\r
@@ -2689,34 +3282,41 @@ UiDisplayMenu (
       Link    = TopOfScreen;\r
       NextMenuOption = MENU_OPTION_FROM_LINK (Link);\r
       Index = TopRow;\r
-      while ((Index <= BottomRow) && (Link->ForwardLink != &Menu)) {\r
+      while ((Index <= BottomRow) && (Link->ForwardLink != &gMenuOption)) {\r
         Index = Index + NextMenuOption->Skip;\r
         Link           = Link->ForwardLink;\r
         NextMenuOption = MENU_OPTION_FROM_LINK (Link);\r
       }\r
 \r
-      Index += MoveToNextStatement (FALSE, &Link);\r
-      if (Index > BottomRow) {\r
+      if ((Link->ForwardLink == &gMenuOption) && (Index <= BottomRow)) {\r
         //\r
-        // There are more MenuOption needing scrolling\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
+      } else {\r
+        if (Index - 1 > BottomRow) {\r
+          //\r
+          // Back up the previous option.\r
+          //\r
+          Link = Link->BackLink;\r
+        }\r
+        //\r
+        // There are more MenuOption needing scrolling down.\r
         //\r
         TopOfScreen = Link;\r
         MenuOption = NULL;\r
-      }\r
-      if (NewPos == Link && Index <= BottomRow) {\r
         //\r
-        // Finally we know that NewPos is the last MenuOption can be focused.\r
+        // Move to the option in Next page.\r
         //\r
-        NewLine = FALSE;\r
-        Repaint = FALSE;\r
-      } else {\r
-        NewPos  = Link;\r
+        MoveToNextStatement (Selection, FALSE, &Link, BottomRow - TopRow);\r
       }\r
 \r
       //\r
       // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.\r
       // Don't do this when we are already in the last page.\r
       //\r
+      NewPos  = Link;\r
       AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
       AdjustDateAndTimePosition (TRUE, &NewPos);\r
       break;\r
@@ -2732,20 +3332,49 @@ UiDisplayMenu (
       // the Date/Time op-code.\r
       //\r
       SavedListEntry = NewPos;\r
-      DistanceValue  = AdjustDateAndTimePosition (FALSE, &NewPos);\r
+      AdjustDateAndTimePosition (FALSE, &NewPos);\r
 \r
-      if (NewPos->ForwardLink != &Menu) {\r
+      if (NewPos->ForwardLink != &gMenuOption) {\r
         MenuOption      = MENU_OPTION_FROM_LINK (NewPos);\r
         NewLine         = TRUE;\r
         NewPos          = NewPos->ForwardLink;\r
+\r
+        Difference      = 0;\r
+        if (BottomRow >= MenuOption->Row + MenuOption->Skip) {\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
+            //\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
 \r
-        DistanceValue  += NextMenuOption->Skip;\r
-        DistanceValue  += MoveToNextStatement (FALSE, &NewPos);\r
         //\r
         // An option might be multi-line, so we need to reflect that data in the overall skip value\r
         //\r
-        UpdateOptionSkipLines (Selection, NextMenuOption, &OptionString, SkipValue);\r
+        UpdateOptionSkipLines (Selection, NextMenuOption);\r
+        DistanceValue  = Difference + NextMenuOption->Skip;\r
 \r
         Temp = MenuOption->Row + MenuOption->Skip + DistanceValue - 1;\r
         if ((MenuOption->Row + MenuOption->Skip == BottomRow + 1) &&\r
@@ -2787,26 +3416,13 @@ UiDisplayMenu (
                 //\r
                 // If we have a remainder, skip that many more op-codes until we drain the remainder\r
                 //\r
-                for (;\r
-                     Difference >= (INTN) SavedMenuOption->Skip;\r
-                     Difference = Difference - (INTN) SavedMenuOption->Skip\r
-                    ) {\r
+                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
-                  if (Difference < (INTN) SavedMenuOption->Skip) {\r
-                    Difference = SavedMenuOption->Skip - Difference - 1;\r
-                    break;\r
-                  } else {\r
-                    if (Difference == (INTN) SavedMenuOption->Skip) {\r
-                      TopOfScreen     = TopOfScreen->ForwardLink;\r
-                      SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);\r
-                      Difference      = SavedMenuOption->Skip - Difference;\r
-                      break;\r
-                    }\r
-                  }\r
                 }\r
                 //\r
                 // Since we will act on this op-code in the next routine, and increment the\r
@@ -2839,6 +3455,8 @@ UiDisplayMenu (
               } else {\r
                 SkipValue++;\r
               }\r
+            } else if (SavedMenuOption->Skip == 1) {\r
+              SkipValue   = 0;\r
             } else {\r
               SkipValue   = 0;\r
               TopOfScreen = TopOfScreen->ForwardLink;\r
@@ -2847,66 +3465,156 @@ UiDisplayMenu (
 \r
           Repaint       = TRUE;\r
           OldSkipValue  = SkipValue;\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 (INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE);\r
+        UpdateStatusBar (Selection, INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE);\r
 \r
       } else {\r
-        SavedMenuOption = MenuOption;\r
-        MenuOption      = MENU_OPTION_FROM_LINK (NewPos);\r
-        if (!IsSelectable (MenuOption)) {\r
-          //\r
-          // If we are at the end of the list and sitting on a text op, we need to more forward\r
-          //\r
-          ScreenOperation = UiUp;\r
-          ControlFlag     = CfScreenOperation;\r
-          break;\r
-        }\r
-\r
-        MenuOption = SavedMenuOption;\r
         //\r
-        // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.\r
+        // Scroll to the first page.\r
         //\r
-        AdjustDateAndTimePosition (TRUE, &NewPos);\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
+        NewLine       = TRUE;\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 CfUiSave:\r
+    case CfUiHotKey:\r
       ControlFlag = CfCheckSelection;\r
-\r
+      \r
+      Status = EFI_SUCCESS;\r
       //\r
-      // Submit the form\r
+      // Discard changes. After it, no NV flag is showed.\r
       //\r
-      Status = SubmitForm (Selection->FormSet, Selection->Form);\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
-      if (!EFI_ERROR (Status)) {\r
-        UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE);\r
-        UpdateStatusBar (NV_UPDATE_REQUIRED, MenuOption->ThisTag->QuestionFlags, FALSE);\r
-      } else {\r
-        do {\r
-          CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gSaveFailed, gPressEnter, gEmptyString);\r
-        } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+      //\r
+      // 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);\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
-        Repaint = TRUE;\r
-        NewLine = TRUE;\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
-      Status = ExtractFormDefault (Selection->FormSet, Selection->Form, DefaultId);\r
+      //\r
+      // Reset to default value for all forms in the whole system.\r
+      //\r
+      Status = ExtractDefault (Selection->FormSet, NULL, DefaultId, FormSetLevel);\r
 \r
       if (!EFI_ERROR (Status)) {\r
         Selection->Action = UI_ACTION_REFRESH_FORM;\r
         Selection->Statement = NULL;\r
-\r
-        //\r
-        // Show NV update flag on status bar\r
-        //\r
-        gNvUpdateRequired = TRUE;\r
+        gResetRequired = TRUE;\r
       }\r
       break;\r
 \r