]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/SetupBrowserDxe/Ui.c
Enable SetupBrowser to support multiple form class guid.
[mirror_edk2.git] / MdeModulePkg / Universal / SetupBrowserDxe / Ui.c
index 4d2fc8871aaf7dd3f6831cea115ebac5971889bd..f8d0e07ab613da824b55da7cf53f9a9d3dc4416b 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
 Utility functions for User Interface functions.\r
 \r
-Copyright (c) 2004 - 2008, Intel Corporation\r
+Copyright (c) 2004 - 2009, Intel Corporation\r
 All rights reserved. This program and the accompanying materials\r
 are licensed and made available under the terms and conditions of the BSD License\r
 which accompanies this distribution.  The full text of the license may be found at\r
@@ -12,11 +12,10 @@ 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
+LIST_ENTRY          gMenuOption;\r
+LIST_ENTRY          gMenuList = INITIALIZE_LIST_HEAD_VARIABLE (gMenuList);\r
 MENU_REFRESH_ENTRY  *gMenuRefreshHead;\r
 \r
 //\r
@@ -43,10 +42,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
@@ -102,10 +97,6 @@ SCREEN_OPERATION_T0_CONTROL_FLAG  gScreenOperationToControlFlag[] = {
     UiSave,\r
     CfUiSave,\r
   },\r
-  {\r
-    UiPrevious,\r
-    CfUiPrevious,\r
-  },\r
   {\r
     UiPageUp,\r
     CfUiPageUp,\r
@@ -127,8 +118,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,118 +144,162 @@ 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  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_GUID             *FormSetGuid,\r
+  IN UINT16               FormId\r
   )\r
 {\r
-  UI_MENU_LIST  *UiMenuList;\r
+  UI_MENU_LIST  *MenuList;\r
 \r
-  if (!IsListEmpty (&gMenuList)) {\r
-    UiMenuList = CR (gMenuList.ForwardLink, UI_MENU_LIST, MenuLink, UI_MENU_LIST_SIGNATURE);\r
-\r
-    Selection->FormId = UiMenuList->FormId;\r
-    Selection->QuestionId = UiMenuList->QuestionId;\r
-    RemoveEntryList (&UiMenuList->MenuLink);\r
-    FreePool (UiMenuList);\r
+  MenuList = AllocateZeroPool (sizeof (UI_MENU_LIST));\r
+  if (MenuList == NULL) {\r
+    return NULL;\r
   }\r
-}\r
 \r
+  MenuList->Signature = UI_MENU_LIST_SIGNATURE;\r
+  InitializeListHead (&MenuList->ChildListHead);\r
 \r
-/**\r
-  Free Menu option linked list.\r
-\r
-**/\r
-VOID\r
-UiFreeMenuList (\r
-  VOID\r
-  )\r
-{\r
-  UI_MENU_LIST  *UiMenuList;\r
+  CopyMem (&MenuList->FormSetGuid, FormSetGuid, sizeof (EFI_GUID));\r
+  MenuList->FormId = FormId;\r
+  MenuList->Parent = Parent;\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
+  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
-  Add one menu entry to the linked lst\r
+  Search Menu with given FormId in the parent menu and all its child menus.\r
 \r
-  @param  Selection              Menu selection.\r
+  @param  Parent                 The parent of 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
+UiFindChildMenuList (\r
+  IN UI_MENU_LIST         *Parent,\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
+  if (Parent->FormId == FormId) {\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
-  UiMenuList = AllocateZeroPool (sizeof (UI_MENU_LIST));\r
-  ASSERT (UiMenuList != NULL);\r
+    MenuList = UiFindChildMenuList (Child, FormId);\r
+    if (MenuList != NULL) {\r
+      return MenuList;\r
+    }\r
 \r
-  UiMenuList->Signature = UI_MENU_LIST_SIGNATURE;\r
-  UiMenuList->FormId = Selection->FormId;\r
-  UiMenuList->QuestionId = Selection->QuestionId;\r
+    Link = GetNextNode (&Parent->ChildListHead, Link);\r
+  }\r
 \r
-  InsertHeadList (&gMenuList, &UiMenuList->MenuLink);\r
+  return NULL;\r
 }\r
 \r
 \r
 /**\r
-  Free Menu option linked list.\r
+  Search Menu with given FormSetGuid and FormId in all cached menu list.\r
+\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
-UiFreeMenu (\r
-  VOID\r
+UI_MENU_LIST *\r
+UiFindMenuList (\r
+  IN EFI_GUID             *FormSetGuid,\r
+  IN UINT16               FormId\r
   )\r
 {\r
-  UI_MENU_OPTION  *MenuOption;\r
+  LIST_ENTRY      *Link;\r
+  UI_MENU_LIST    *MenuList;\r
+  UI_MENU_LIST    *Child;\r
 \r
-  while (!IsListEmpty (&Menu)) {\r
-    MenuOption = MENU_OPTION_FROM_LINK (Menu.ForwardLink);\r
-    RemoveEntryList (&MenuOption->Link);\r
+  Link = GetFirstNode (&gMenuList);\r
+  while (!IsNull (&gMenuList, Link)) {\r
+    MenuList = UI_MENU_LIST_FROM_LINK (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
+    if (CompareGuid (FormSetGuid, &MenuList->FormSetGuid)) {\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
+      // This is the formset we are looking for, find the form in this formset\r
       //\r
-      FreePool (MenuOption->Description);\r
+      Child = UiFindChildMenuList (MenuList, FormId);\r
+      if (Child != NULL) {\r
+        return Child;\r
+      }\r
     }\r
-    FreePool (MenuOption);\r
+\r
+    Link = GetNextNode (&gMenuList, Link);\r
   }\r
+\r
+  return NULL;\r
 }\r
 \r
 \r
@@ -524,8 +557,10 @@ UiWaitForSingleEvent (
   @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
@@ -539,6 +574,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 +619,35 @@ UiAddMenuOption (
       MenuOption->GrayOut = Statement->GrayOutExpression->Result.Value.b;\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
+    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
@@ -630,7 +688,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 +718,6 @@ CreateDialog (
   ASSERT (BufferedString);\r
 \r
   VA_START (Marker, KeyValue);\r
-  MarkerBackup = Marker;\r
 \r
   //\r
   // Zero the outgoing buffer\r
@@ -702,6 +758,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 +768,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 +978,7 @@ CreateSharedPopUp (
 \r
 **/\r
 VOID\r
-CreatePopUp (\r
+CreateMultiStringPopUp (\r
   IN  UINTN                       RequestedWidth,\r
   IN  UINTN                       NumberOfLines,\r
   ...\r
@@ -928,7 +987,7 @@ CreatePopUp (
   VA_LIST Marker;\r
 \r
   VA_START (Marker, NumberOfLines);\r
-  \r
+\r
   CreateSharedPopUp (RequestedWidth, NumberOfLines, Marker);\r
 \r
   VA_END (Marker);\r
@@ -978,7 +1037,7 @@ UpdateStatusBar (
     break;\r
 \r
   case NV_UPDATE_REQUIRED:\r
-    if (gClassOfVfr != EFI_FRONT_PAGE_SUBCLASS) {\r
+    if ((gClassOfVfr & FORMSET_CLASS_FRONT_PAGE) != FORMSET_CLASS_FRONT_PAGE) {\r
       if (State) {\r
         gST->ConOut->SetAttribute (gST->ConOut, INFO_TEXT);\r
         PrintStringAt (\r
@@ -1274,7 +1333,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
@@ -1293,11 +1352,11 @@ ValueIsScroll (
 \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
+  for (; Temp != &gMenuOption; Temp = Direction ? Temp->BackLink : Temp->ForwardLink) {\r
     MenuOption = MENU_OPTION_FROM_LINK (Temp);\r
     if (IsSelectable (MenuOption)) {\r
       return FALSE;\r
@@ -1310,9 +1369,9 @@ ValueIsScroll (
 \r
 /**\r
   Move to next selectable statement.\r
-  \r
+\r
   This is an internal function.\r
-  \r
+\r
   @param  GoUp                   The navigation direction. TRUE: up, FALSE: down.\r
   @param  CurrentPosition        Current position.\r
 \r
@@ -1339,7 +1398,7 @@ MoveToNextStatement (
     if (IsSelectable (NextMenuOption)) {\r
       break;\r
     }\r
-    if ((GoUp ? Pos->BackLink : Pos->ForwardLink) == &Menu) {\r
+    if ((GoUp ? Pos->BackLink : Pos->ForwardLink) == &gMenuOption) {\r
       HitEnd = TRUE;\r
       break;\r
     }\r
@@ -1360,7 +1419,7 @@ MoveToNextStatement (
       if (IsSelectable (NextMenuOption)) {\r
         break;\r
       }\r
-      if ((!GoUp ? Pos->BackLink : Pos->ForwardLink) == &Menu) {\r
+      if ((!GoUp ? Pos->BackLink : Pos->ForwardLink) == &gMenuOption) {\r
         ASSERT (FALSE);\r
         break;\r
       }\r
@@ -1378,7 +1437,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
@@ -1583,6 +1642,8 @@ UiDisplayMenu (
   BOOLEAN                         NewLine;\r
   BOOLEAN                         Repaint;\r
   BOOLEAN                         SavedValue;\r
+  BOOLEAN                         UpArrow;\r
+  BOOLEAN                         DownArrow;\r
   EFI_STATUS                      Status;\r
   EFI_INPUT_KEY                   Key;\r
   LIST_ENTRY                      *Link;\r
@@ -1605,6 +1666,9 @@ UiDisplayMenu (
   CHAR16                          TemStr[2];\r
   UINT8                           *DevicePathBuffer;\r
   UINT8                           DigitUint8;\r
+  UI_MENU_LIST                    *CurrentMenu;\r
+  UI_MENU_LIST                    *MenuList;\r
+  FORM_BROWSER_FORM               *RefForm;\r
 \r
   CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));\r
 \r
@@ -1617,8 +1681,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
@@ -1626,10 +1690,11 @@ UiDisplayMenu (
   NextMenuOption      = NULL;\r
   PreviousMenuOption  = NULL;\r
   SavedMenuOption     = NULL;\r
+  RefForm             = NULL;\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
@@ -1646,14 +1711,33 @@ 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
+  // 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->FormSetGuid, Selection->FormId);\r
+  }\r
+  ASSERT (CurrentMenu != NULL);\r
+\r
+  if (Selection->QuestionId == 0) {\r
+    //\r
+    // Highlight not specified, fetch it from cached menu\r
+    //\r
+    Selection->QuestionId = CurrentMenu->QuestionId;\r
+  }\r
+\r
   //\r
   // Get user's selection\r
   //\r
-  NewPos = Menu.ForwardLink;\r
+  NewPos = gMenuOption.ForwardLink;\r
 \r
   gST->ConOut->EnableCursor (gST->ConOut, FALSE);\r
   UpdateStatusBar (REFRESH_STATUS_BAR, (UINT8) 0, TRUE);\r
@@ -1663,7 +1747,7 @@ UiDisplayMenu (
   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
@@ -1685,8 +1769,8 @@ 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
@@ -1703,7 +1787,7 @@ UiDisplayMenu (
         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
@@ -1908,7 +1992,7 @@ UiDisplayMenu (
 \r
           if (Row > BottomRow) {\r
             if (!ValueIsScroll (FALSE, Link)) {\r
-              gDownArrow = TRUE;\r
+              DownArrow = TRUE;\r
             }\r
 \r
             Row = BottomRow + 1;\r
@@ -1917,10 +2001,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
@@ -1931,7 +2015,7 @@ UiDisplayMenu (
           gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | 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
@@ -1962,10 +2046,10 @@ 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 && NewPos->ForwardLink != &gMenuOption) {\r
           NewPos     = NewPos->ForwardLink;\r
           SavedMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
         }\r
@@ -2102,6 +2186,10 @@ UiDisplayMenu (
         //\r
         Statement = MenuOption->ThisTag;\r
         Selection->Statement = Statement;\r
+        //\r
+        // Record highlight for current menu\r
+        //\r
+        CurrentMenu->QuestionId = Statement->QuestionId;\r
 \r
         //\r
         // Set reverse attribute\r
@@ -2185,7 +2273,7 @@ UiDisplayMenu (
           }\r
         }\r
 \r
-        UpdateKeyHelp (MenuOption, FALSE);\r
+        UpdateKeyHelp (Selection, MenuOption, FALSE);\r
 \r
         //\r
         // Clear reverse attribute\r
@@ -2202,7 +2290,7 @@ UiDisplayMenu (
     case CfUpdateHelpString:\r
       ControlFlag = CfPrepareToReadKey;\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
@@ -2257,27 +2345,19 @@ UiDisplayMenu (
         //\r
         // IFR is updated in Callback of refresh opcode, re-parse it\r
         //\r
-        ControlFlag = CfUiReset;\r
         Selection->Statement = NULL;\r
-        break;\r
+        return EFI_SUCCESS;\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
         ScreenOperation = UiSelect;\r
@@ -2324,7 +2404,7 @@ UiDisplayMenu (
         break;\r
 \r
       case ' ':\r
-        if (gClassOfVfr != EFI_FRONT_PAGE_SUBCLASS) {\r
+        if ((gClassOfVfr & FORMSET_CLASS_FRONT_PAGE) != FORMSET_CLASS_FRONT_PAGE) {\r
           if (MenuOption->ThisTag->Operand == EFI_IFR_CHECKBOX_OP && !MenuOption->GrayOut) {\r
             ScreenOperation = UiSelect;\r
           }\r
@@ -2332,9 +2412,7 @@ UiDisplayMenu (
         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
+        if (((Key.ScanCode == SCAN_F9) && ((gFunctionKeySetting & FUNCTION_NINE) != FUNCTION_NINE)) ||\r
             ((Key.ScanCode == SCAN_F10) && ((gFunctionKeySetting & FUNCTION_TEN) != FUNCTION_TEN))\r
             ) {\r
           //\r
@@ -2359,35 +2437,29 @@ 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
+        for (Link = gMenuOption.ForwardLink; Link != &gMenuOption; Link = Link->ForwardLink) {\r
           NextMenuOption = MENU_OPTION_FROM_LINK (Link);\r
           if (IsSelectable (NextMenuOption)) {\r
             break;\r
           }\r
         }\r
 \r
-        if (Link == &Menu) {\r
+        if (Link == &gMenuOption) {\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
@@ -2401,26 +2473,6 @@ 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
@@ -2443,7 +2495,6 @@ UiDisplayMenu (
           //\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
@@ -2457,7 +2508,7 @@ UiDisplayMenu (
           }\r
           BufferSize = StrLen (StringPtr) / 2;\r
           DevicePath = AllocatePool (BufferSize);\r
-          \r
+\r
           //\r
           // Convert from Device Path String to DevicePath Buffer in the reverse order.\r
           //\r
@@ -2498,22 +2549,48 @@ UiDisplayMenu (
           //\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
+          // Check whether target From is suppressed.\r
+          //\r
+          RefForm = IdToForm (Selection->FormSet, Statement->RefFormId);\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
+\r
+              Repaint = TRUE;\r
+              break;\r
+            }\r
+          }\r
+\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
+          // Link current form so that we can always go back when someone hits the ESC\r
           //\r
-          UiAddMenuListEntry (Selection);\r
+          MenuList = UiFindMenuList (&Selection->FormSetGuid, Statement->RefFormId);\r
+          if (MenuList == NULL) {\r
+            MenuList = UiAddMenuList (CurrentMenu, &Selection->FormSetGuid, Statement->RefFormId);\r
+          }\r
 \r
           Selection->FormId = Statement->RefFormId;\r
           Selection->QuestionId = Statement->RefQuestionId;\r
@@ -2561,41 +2638,64 @@ 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
+      if (CurrentMenu->Parent != NULL) {\r
         //\r
-        // There is no parent menu for FrontPage\r
+        // we have a parent, so go to the parent menu\r
+        //\r
+        if (CompareGuid (&CurrentMenu->FormSetGuid, &CurrentMenu->Parent->FormSetGuid)) {\r
+          //\r
+          // The parent menu and current menu are in the same formset\r
+          //\r
+          Selection->Action = UI_ACTION_REFRESH_FORM;\r
+        } else {\r
+          Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
+        }\r
+        Selection->Statement = NULL;\r
+\r
+        Selection->FormId = CurrentMenu->Parent->FormId;\r
+        Selection->QuestionId = CurrentMenu->Parent->QuestionId;\r
+\r
+        //\r
+        // Clear highlight record for this menu\r
+        //\r
+        CurrentMenu->QuestionId = 0;\r
+        break;\r
+      }\r
+\r
+      if ((gClassOfVfr & FORMSET_CLASS_FRONT_PAGE) == FORMSET_CLASS_FRONT_PAGE) {\r
+        //\r
+        // We never exit FrontPage, so skip the ESC\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
+      // We are going to leave current FormSet, so check uncommited data in this FormSet\r
       //\r
       if (gNvUpdateRequired) {\r
         Status      = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
@@ -2603,8 +2703,11 @@ UiDisplayMenu (
         YesResponse = gYesResponse[0];\r
         NoResponse  = gNoResponse[0];\r
 \r
+        //\r
+        // If NV flag is up, prompt user\r
+        //\r
         do {\r
-          CreateDialog (3, TRUE, 0, NULL, &Key, gEmptyString, gAreYouSure, gEmptyString);\r
+          CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gSaveChanges, gAreYouSure, gEmptyString);\r
         } while\r
         (\r
           (Key.ScanCode != SCAN_ESC) &&\r
@@ -2612,24 +2715,29 @@ UiDisplayMenu (
           ((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
+        if (Key.ScanCode == SCAN_ESC) {\r
+          //\r
+          // User hits the ESC key\r
+          //\r
           Repaint = TRUE;\r
           NewLine = TRUE;\r
 \r
           Selection->Action = UI_ACTION_NONE;\r
           break;\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
+          Status = SubmitForm (Selection->FormSet, Selection->Form);\r
+        }\r
       }\r
 \r
-      gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
-      gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
+      Selection->Action = UI_ACTION_EXIT;\r
+      Selection->Statement = NULL;\r
+      CurrentMenu->QuestionId = 0;\r
 \r
-      UiFreeMenuList ();\r
-      gST->ConOut->ClearScreen (gST->ConOut);\r
       return EFI_SUCCESS;\r
 \r
     case CfUiLeft:\r
@@ -2661,7 +2769,7 @@ UiDisplayMenu (
 \r
       SavedListEntry = TopOfScreen;\r
 \r
-      if (NewPos->BackLink != &Menu) {\r
+      if (NewPos->BackLink != &gMenuOption) {\r
         NewLine = TRUE;\r
         //\r
         // Adjust Date/Time position before we advance forward.\r
@@ -2671,7 +2779,7 @@ UiDisplayMenu (
         //\r
         // Caution that we have already rewind to the top, don't go backward in this situation.\r
         //\r
-        if (NewPos->BackLink != &Menu) {\r
+        if (NewPos->BackLink != &gMenuOption) {\r
           NewPos = NewPos->BackLink;\r
         }\r
 \r
@@ -2696,13 +2804,18 @@ UiDisplayMenu (
         }\r
 \r
         Difference = MoveToNextStatement (TRUE, &NewPos);\r
-        if ((INTN) MenuOption->Row - (INTN) DistanceValue < (INTN) TopRow) {\r
+        PreviousMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
+        DistanceValue += PreviousMenuOption->Skip;\r
+\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
+            SkipValue = 0;\r
+            OldSkipValue = 0;\r
           }\r
         }\r
         if (Difference < 0) {\r
@@ -2711,8 +2824,8 @@ UiDisplayMenu (
           // it means that we hit the begining MenuOption that can be focused\r
           // so we simply scroll to the top\r
           //\r
-          if (SavedListEntry != Menu.ForwardLink) {\r
-            TopOfScreen = Menu.ForwardLink;\r
+          if (SavedListEntry != gMenuOption.ForwardLink) {\r
+            TopOfScreen = gMenuOption.ForwardLink;\r
             Repaint     = TRUE;\r
           }\r
         }\r
@@ -2742,7 +2855,7 @@ UiDisplayMenu (
     case CfUiPageUp:\r
       ControlFlag     = CfCheckSelection;\r
 \r
-      if (NewPos->BackLink == &Menu) {\r
+      if (NewPos->BackLink == &gMenuOption) {\r
         NewLine = FALSE;\r
         Repaint = FALSE;\r
         break;\r
@@ -2753,7 +2866,7 @@ UiDisplayMenu (
       Link      = TopOfScreen;\r
       PreviousMenuOption = MENU_OPTION_FROM_LINK (Link);\r
       Index = BottomRow;\r
-      while ((Index >= TopRow) && (Link->BackLink != &Menu)) {\r
+      while ((Index >= TopRow) && (Link->BackLink != &gMenuOption)) {\r
         Index = Index - PreviousMenuOption->Skip;\r
         Link = Link->BackLink;\r
         PreviousMenuOption = MENU_OPTION_FROM_LINK (Link);\r
@@ -2771,7 +2884,7 @@ UiDisplayMenu (
         // This happens when there is no MenuOption can be focused from\r
         // Current MenuOption to the first MenuOption\r
         //\r
-        TopOfScreen = Menu.ForwardLink;\r
+        TopOfScreen = gMenuOption.ForwardLink;\r
       }\r
       Index += Difference;\r
       if (Index < TopRow) {\r
@@ -2796,7 +2909,7 @@ UiDisplayMenu (
     case CfUiPageDown:\r
       ControlFlag     = CfCheckSelection;\r
 \r
-      if (NewPos->ForwardLink == &Menu) {\r
+      if (NewPos->ForwardLink == &gMenuOption) {\r
         NewLine = FALSE;\r
         Repaint = FALSE;\r
         break;\r
@@ -2807,7 +2920,7 @@ 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
@@ -2852,7 +2965,7 @@ UiDisplayMenu (
       SavedListEntry = NewPos;\r
       DistanceValue  = 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
@@ -3014,6 +3127,12 @@ UiDisplayMenu (
 \r
     case CfUiDefault:\r
       ControlFlag = CfCheckSelection;\r
+      if (!Selection->FormEditable) {\r
+        //\r
+        // This Form is not editable, ignore the F9 (reset to default)\r
+        //\r
+        break;\r
+      }\r
 \r
       Status = ExtractFormDefault (Selection->FormSet, Selection->Form, DefaultId);\r
 \r