]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/SetupBrowserDxe/Presentation.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Universal / SetupBrowserDxe / Presentation.c
index 4e3e9811df11c9e8140161e7abf5c88b9aafea07..d7927725b231cc46e65dbd7739a42baf2946b7e1 100644 (file)
@@ -1,14 +1,9 @@
 /** @file\r
 Utility functions for UI presentation.\r
 \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
-http://opensource.org/licenses/bsd-license.php\r
-\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>\r
+(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
@@ -16,821 +11,2279 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 \r
 BOOLEAN            mHiiPackageListUpdated;\r
 UI_MENU_SELECTION  *gCurrentSelection;\r
-\r
+EFI_HII_HANDLE     mCurrentHiiHandle = NULL;\r
+EFI_GUID           mCurrentFormSetGuid = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}};\r
+UINT16             mCurrentFormId = 0;\r
+EFI_EVENT          mValueChangedEvent = NULL;\r
+LIST_ENTRY         mRefreshEventList = INITIALIZE_LIST_HEAD_VARIABLE (mRefreshEventList);\r
+UINT16             mCurFakeQestId;\r
+FORM_DISPLAY_ENGINE_FORM gDisplayFormData;\r
+BOOLEAN            mFinishRetrieveCall = FALSE;\r
 \r
 /**\r
-  Clear retangle with specified text attribute.\r
+  Evaluate all expressions in a Form.\r
+\r
+  @param  FormSet        FormSet this Form belongs to.\r
+  @param  Form           The Form.\r
 \r
-  @param  LeftColumn     Left column of retangle.\r
-  @param  RightColumn    Right column of retangle.\r
-  @param  TopRow         Start row of retangle.\r
-  @param  BottomRow      End row of retangle.\r
-  @param  TextAttribute  The character foreground and background.\r
+  @retval EFI_SUCCESS    The expression evaluated successfuly\r
 \r
 **/\r
-VOID\r
-ClearLines (\r
-  IN UINTN               LeftColumn,\r
-  IN UINTN               RightColumn,\r
-  IN UINTN               TopRow,\r
-  IN UINTN               BottomRow,\r
-  IN UINTN               TextAttribute\r
+EFI_STATUS\r
+EvaluateFormExpressions (\r
+  IN FORM_BROWSER_FORMSET  *FormSet,\r
+  IN FORM_BROWSER_FORM     *Form\r
   )\r
 {\r
-  CHAR16  *Buffer;\r
-  UINTN   Row;\r
-\r
-  //\r
-  // For now, allocate an arbitrarily long buffer\r
-  //\r
-  Buffer = AllocateZeroPool (0x10000);\r
-  ASSERT (Buffer != NULL);\r
+  EFI_STATUS       Status;\r
+  LIST_ENTRY       *Link;\r
+  FORM_EXPRESSION  *Expression;\r
 \r
-  //\r
-  // Set foreground and background as defined\r
-  //\r
-  gST->ConOut->SetAttribute (gST->ConOut, TextAttribute);\r
+  Link = GetFirstNode (&Form->ExpressionListHead);\r
+  while (!IsNull (&Form->ExpressionListHead, Link)) {\r
+    Expression = FORM_EXPRESSION_FROM_LINK (Link);\r
+    Link = GetNextNode (&Form->ExpressionListHead, Link);\r
 \r
-  //\r
-  // Much faster to buffer the long string instead of print it a character at a time\r
-  //\r
-  SetUnicodeMem (Buffer, RightColumn - LeftColumn, L' ');\r
+    if (Expression->Type == EFI_HII_EXPRESSION_INCONSISTENT_IF ||\r
+        Expression->Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF ||\r
+        Expression->Type == EFI_HII_EXPRESSION_WARNING_IF ||\r
+        Expression->Type == EFI_HII_EXPRESSION_WRITE ||\r
+        (Expression->Type == EFI_HII_EXPRESSION_READ && Form->FormType != STANDARD_MAP_FORM_TYPE)) {\r
+      //\r
+      // Postpone Form validation to Question editing or Form submitting or Question Write or Question Read for nonstandard form.\r
+      //\r
+      continue;\r
+    }\r
 \r
-  //\r
-  // Clear the desired area with the appropriate foreground/background\r
-  //\r
-  for (Row = TopRow; Row <= BottomRow; Row++) {\r
-    PrintStringAt (LeftColumn, Row, Buffer);\r
+    Status = EvaluateExpression (FormSet, Form, Expression);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
   }\r
 \r
-  gST->ConOut->SetCursorPosition (gST->ConOut, LeftColumn, TopRow);\r
-\r
-  FreePool (Buffer);\r
-  return ;\r
+  return EFI_SUCCESS;\r
 }\r
 \r
 /**\r
-  Concatenate a narrow string to another string.\r
+  Base on the opcode buffer info to get the display statement.\r
+\r
+  @param OpCode    The input opcode buffer for this statement.\r
 \r
-  @param Destination The destination string.\r
-  @param Source      The source string. The string to be concatenated.\r
-                     to the end of Destination.\r
+  @retval Statement  The statement use this opcode buffer.\r
 \r
 **/\r
-VOID\r
-NewStrCat (\r
-  IN OUT CHAR16               *Destination,\r
-  IN     CHAR16               *Source\r
+FORM_DISPLAY_ENGINE_STATEMENT *\r
+GetDisplayStatement (\r
+  IN EFI_IFR_OP_HEADER     *OpCode\r
   )\r
 {\r
-  UINTN Length;\r
+  FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement;\r
+  LIST_ENTRY                    *Link;\r
 \r
-  for (Length = 0; Destination[Length] != 0; Length++)\r
-    ;\r
+  Link = GetFirstNode (&gDisplayFormData.StatementListHead);\r
+  while (!IsNull (&gDisplayFormData.StatementListHead, Link)) {\r
+    DisplayStatement = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (Link);\r
 \r
-  //\r
-  // We now have the length of the original string\r
-  // We can safely assume for now that we are concatenating a narrow value to this string.\r
-  // For instance, the string is "XYZ" and cat'ing ">"\r
-  // If this assumption changes, we need to make this routine a bit more complex\r
-  //\r
-  Destination[Length] = NARROW_CHAR;\r
-  Length++;\r
+    if (DisplayStatement->OpCode == OpCode) {\r
+      return DisplayStatement;\r
+    }\r
+    Link = GetNextNode (&gDisplayFormData.StatementListHead, Link);\r
+  }\r
 \r
-  StrCpy (Destination + Length, Source);\r
+  return NULL;\r
 }\r
 \r
 /**\r
-  Count the storage space of a Unicode string.\r
+  Free the refresh event list.\r
+\r
+**/\r
+VOID\r
+FreeRefreshEvent (\r
+  VOID\r
+  )\r
+{\r
+  LIST_ENTRY   *Link;\r
+  FORM_BROWSER_REFRESH_EVENT_NODE *EventNode;\r
+\r
+  while (!IsListEmpty (&mRefreshEventList)) {\r
+    Link = GetFirstNode (&mRefreshEventList);\r
+    EventNode = FORM_BROWSER_REFRESH_EVENT_FROM_LINK (Link);\r
+    RemoveEntryList (&EventNode->Link);\r
 \r
-  This function handles the Unicode string with NARROW_CHAR\r
-  and WIDE_CHAR control characters. NARROW_HCAR and WIDE_CHAR\r
-  does not count in the resultant output. If a WIDE_CHAR is\r
-  hit, then 2 Unicode character will consume an output storage\r
-  space with size of CHAR16 till a NARROW_CHAR is hit.\r
+    gBS->CloseEvent (EventNode->RefreshEvent);\r
 \r
-  @param String          The input string to be counted.\r
+    FreePool (EventNode);\r
+  }\r
+}\r
+\r
+/**\r
+  Check whether this statement value is changed. If yes, update the statement value and return TRUE;\r
+  else return FALSE.\r
 \r
-  @return Storage space for the input string.\r
+  @param Statement           The statement need to check.\r
 \r
 **/\r
-UINTN\r
-GetStringWidth (\r
-  IN CHAR16               *String\r
+VOID\r
+UpdateStatement (\r
+  IN OUT FORM_BROWSER_STATEMENT        *Statement\r
   )\r
 {\r
-  UINTN Index;\r
-  UINTN Count;\r
-  UINTN IncrementValue;\r
+  GetQuestionValue (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithHiiDriver);\r
 \r
-  Index           = 0;\r
-  Count           = 0;\r
-  IncrementValue  = 1;\r
+  //\r
+  // Reset FormPackage update flag\r
+  //\r
+  mHiiPackageListUpdated = FALSE;\r
 \r
-  do {\r
-    //\r
-    // Advance to the null-terminator or to the first width directive\r
-    //\r
-    for (;\r
-         (String[Index] != NARROW_CHAR) && (String[Index] != WIDE_CHAR) && (String[Index] != 0);\r
-         Index++, Count = Count + IncrementValue\r
-        )\r
-      ;\r
+  //\r
+  // Question value may be changed, need invoke its Callback()\r
+  //\r
+  ProcessCallBackFunction (gCurrentSelection, gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, EFI_BROWSER_ACTION_RETRIEVE, FALSE);\r
 \r
+  if (mHiiPackageListUpdated) {\r
     //\r
-    // We hit the null-terminator, we now have a count\r
+    // Package list is updated, force to reparse IFR binary of target Formset\r
     //\r
-    if (String[Index] == 0) {\r
-      break;\r
-    }\r
-    //\r
-    // We encountered a narrow directive - strip it from the size calculation since it doesn't get printed\r
-    // and also set the flag that determines what we increment by.(if narrow, increment by 1, if wide increment by 2)\r
-    //\r
-    if (String[Index] == NARROW_CHAR) {\r
-      //\r
-      // Skip to the next character\r
-      //\r
-      Index++;\r
-      IncrementValue = 1;\r
-    } else {\r
-      //\r
-      // Skip to the next character\r
-      //\r
-      Index++;\r
-      IncrementValue = 2;\r
-    }\r
-  } while (String[Index] != 0);\r
+    mHiiPackageListUpdated = FALSE;\r
+    gCurrentSelection->Action = UI_ACTION_REFRESH_FORMSET;\r
+  }\r
+}\r
 \r
-  //\r
-  // Increment by one to include the null-terminator in the size\r
-  //\r
-  Count++;\r
+/**\r
+  Refresh the question which has refresh guid event attribute.\r
 \r
-  return Count * sizeof (CHAR16);\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
+RefreshEventNotifyForStatement(\r
+  IN      EFI_EVENT Event,\r
+  IN      VOID      *Context\r
+  )\r
+{\r
+  FORM_BROWSER_STATEMENT        *Statement;\r
+\r
+  Statement = (FORM_BROWSER_STATEMENT *)Context;\r
+  UpdateStatement(Statement);\r
+  gBS->SignalEvent (mValueChangedEvent);\r
 }\r
 \r
 /**\r
-  This function displays the page frame.\r
+  Refresh the questions within this form.\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
-DisplayPageFrame (\r
-  VOID\r
+EFIAPI\r
+RefreshEventNotifyForForm(\r
+  IN      EFI_EVENT Event,\r
+  IN      VOID      *Context\r
   )\r
 {\r
-  UINTN                  Index;\r
-  UINT8                  Line;\r
-  UINT8                  Alignment;\r
-  CHAR16                 Character;\r
-  CHAR16                 *Buffer;\r
-  CHAR16                 *StrFrontPageBanner;\r
-  UINTN                  Row;\r
-  EFI_SCREEN_DESCRIPTOR  LocalScreen;\r
-  UINT8                  RowIdx;\r
-  UINT8                  ColumnIdx;\r
+  gCurrentSelection->Action = UI_ACTION_REFRESH_FORMSET;\r
 \r
-  ZeroMem (&LocalScreen, sizeof (EFI_SCREEN_DESCRIPTOR));\r
-  gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &LocalScreen.RightColumn, &LocalScreen.BottomRow);\r
-  ClearLines (0, LocalScreen.RightColumn, 0, LocalScreen.BottomRow, KEYHELP_BACKGROUND);\r
+  gBS->SignalEvent (mValueChangedEvent);\r
+}\r
+\r
+/**\r
+  Create refresh hook event for statement which has refresh event or interval.\r
+\r
+  @param Statement           The statement need to check.\r
 \r
-  CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));\r
+**/\r
+VOID\r
+CreateRefreshEventForStatement (\r
+  IN     FORM_BROWSER_STATEMENT        *Statement\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  EFI_EVENT                       RefreshEvent;\r
+  FORM_BROWSER_REFRESH_EVENT_NODE *EventNode;\r
 \r
   //\r
-  // For now, allocate an arbitrarily long buffer\r
+  // If question has refresh guid, create the notify function.\r
   //\r
-  Buffer = AllocateZeroPool (0x10000);\r
-  ASSERT (Buffer != NULL);\r
+  Status = gBS->CreateEventEx (\r
+                    EVT_NOTIFY_SIGNAL,\r
+                    TPL_CALLBACK,\r
+                    RefreshEventNotifyForStatement,\r
+                    Statement,\r
+                    &Statement->RefreshGuid,\r
+                    &RefreshEvent);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  EventNode = AllocateZeroPool (sizeof (FORM_BROWSER_REFRESH_EVENT_NODE));\r
+  ASSERT (EventNode != NULL);\r
+  EventNode->RefreshEvent = RefreshEvent;\r
+  InsertTailList(&mRefreshEventList, &EventNode->Link);\r
+}\r
 \r
-  Character = BOXDRAW_HORIZONTAL;\r
+/**\r
+  Create refresh hook event for form which has refresh event or interval.\r
 \r
-  for (Index = 0; Index + 2 < (LocalScreen.RightColumn - LocalScreen.LeftColumn); Index++) {\r
-    Buffer[Index] = Character;\r
-  }\r
+  @param Form           The form need to check.\r
 \r
-  if ((gClassOfVfr & FORMSET_CLASS_FRONT_PAGE) == FORMSET_CLASS_FRONT_PAGE) {\r
-    //\r
-    //    ClearLines(0, LocalScreen.RightColumn, 0, BANNER_HEIGHT-1, BANNER_TEXT | BANNER_BACKGROUND);\r
-    //\r
-    ClearLines (\r
-      LocalScreen.LeftColumn,\r
-      LocalScreen.RightColumn,\r
-      LocalScreen.TopRow,\r
-      FRONT_PAGE_HEADER_HEIGHT - 1 + LocalScreen.TopRow,\r
-      BANNER_TEXT | BANNER_BACKGROUND\r
-      );\r
-    //\r
-    //    for (Line = 0; Line < BANNER_HEIGHT; Line++) {\r
-    //\r
-    for (Line = (UINT8) LocalScreen.TopRow; Line < BANNER_HEIGHT + (UINT8) LocalScreen.TopRow; Line++) {\r
-      //\r
-      //      for (Alignment = 0; Alignment < BANNER_COLUMNS; Alignment++) {\r
-      //\r
-      for (Alignment = (UINT8) LocalScreen.LeftColumn;\r
-           Alignment < BANNER_COLUMNS + (UINT8) LocalScreen.LeftColumn;\r
-           Alignment++\r
-          ) {\r
-        RowIdx = (UINT8) (Line - (UINT8) LocalScreen.TopRow);\r
-        ColumnIdx = (UINT8) (Alignment - (UINT8) LocalScreen.LeftColumn);\r
-\r
-        ASSERT (RowIdx < BANNER_HEIGHT);\r
-        ASSERT (ColumnIdx < BANNER_COLUMNS);\r
-\r
-        if (gBannerData->Banner[RowIdx][ColumnIdx] != 0x0000) {\r
-          StrFrontPageBanner = GetToken (\r
-                                gBannerData->Banner[RowIdx][ColumnIdx],\r
-                                gFrontPageHandle\r
-                                );\r
-        } else {\r
-          continue;\r
-        }\r
+**/\r
+VOID\r
+CreateRefreshEventForForm (\r
+  IN     FORM_BROWSER_FORM        *Form\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  EFI_EVENT                       RefreshEvent;\r
+  FORM_BROWSER_REFRESH_EVENT_NODE *EventNode;\r
 \r
-        switch (Alignment - LocalScreen.LeftColumn) {\r
-        case 0:\r
-          //\r
-          // Handle left column\r
-          //\r
-          PrintStringAt (LocalScreen.LeftColumn, Line, StrFrontPageBanner);\r
-          break;\r
+  //\r
+  // If question has refresh guid, create the notify function.\r
+  //\r
+  Status = gBS->CreateEventEx (\r
+                    EVT_NOTIFY_SIGNAL,\r
+                    TPL_CALLBACK,\r
+                    RefreshEventNotifyForForm,\r
+                    Form,\r
+                    &Form->RefreshGuid,\r
+                    &RefreshEvent);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  EventNode = AllocateZeroPool (sizeof (FORM_BROWSER_REFRESH_EVENT_NODE));\r
+  ASSERT (EventNode != NULL);\r
+  EventNode->RefreshEvent = RefreshEvent;\r
+  InsertTailList(&mRefreshEventList, &EventNode->Link);\r
+}\r
 \r
-        case 1:\r
-          //\r
-          // Handle center column\r
-          //\r
-          PrintStringAt (\r
-            LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 3,\r
-            Line,\r
-            StrFrontPageBanner\r
-            );\r
-          break;\r
+/**\r
 \r
-        case 2:\r
-          //\r
-          // Handle right column\r
-          //\r
-          PrintStringAt (\r
-            LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) * 2 / 3,\r
-            Line,\r
-            StrFrontPageBanner\r
-            );\r
-          break;\r
-        }\r
+  Initialize the Display statement structure data.\r
 \r
-        FreePool (StrFrontPageBanner);\r
-      }\r
+  @param DisplayStatement      Pointer to the display Statement data strucure.\r
+  @param Statement             The statement need to check.\r
+**/\r
+VOID\r
+InitializeDisplayStatement (\r
+  IN OUT FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement,\r
+  IN     FORM_BROWSER_STATEMENT        *Statement\r
+  )\r
+{\r
+  LIST_ENTRY                 *Link;\r
+  QUESTION_OPTION            *Option;\r
+  DISPLAY_QUESTION_OPTION    *DisplayOption;\r
+  FORM_DISPLAY_ENGINE_STATEMENT *ParentStatement;\r
+\r
+  DisplayStatement->Signature = FORM_DISPLAY_ENGINE_STATEMENT_SIGNATURE;\r
+  DisplayStatement->Version   = FORM_DISPLAY_ENGINE_STATEMENT_VERSION_1;\r
+  DisplayStatement->OpCode    = Statement->OpCode;\r
+  InitializeListHead (&DisplayStatement->NestStatementList);\r
+  InitializeListHead (&DisplayStatement->OptionListHead);\r
+\r
+  if ((EvaluateExpressionList(Statement->Expression, FALSE, NULL, NULL) == ExpressGrayOut) || Statement->Locked) {\r
+    DisplayStatement->Attribute |= HII_DISPLAY_GRAYOUT;\r
+  }\r
+  if ((Statement->ValueExpression != NULL) || ((Statement->QuestionFlags & EFI_IFR_FLAG_READ_ONLY) != 0)) {\r
+    DisplayStatement->Attribute |= HII_DISPLAY_READONLY;\r
+  }\r
+\r
+  //\r
+  // Initilize the option list in statement.\r
+  //\r
+  Link = GetFirstNode (&Statement->OptionListHead);\r
+  while (!IsNull (&Statement->OptionListHead, Link)) {\r
+    Option = QUESTION_OPTION_FROM_LINK (Link);\r
+    Link = GetNextNode (&Statement->OptionListHead, Link);\r
+    if ((Option->SuppressExpression != NULL) &&\r
+        ((EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) == ExpressSuppress))) {\r
+      continue;\r
     }\r
+\r
+    DisplayOption = AllocateZeroPool (sizeof (DISPLAY_QUESTION_OPTION));\r
+    ASSERT (DisplayOption != NULL);\r
+\r
+    DisplayOption->ImageId      = Option->ImageId;\r
+    DisplayOption->Signature    = DISPLAY_QUESTION_OPTION_SIGNATURE;\r
+    DisplayOption->OptionOpCode = Option->OpCode;\r
+    InsertTailList(&DisplayStatement->OptionListHead, &DisplayOption->Link);\r
   }\r
 \r
-  ClearLines (\r
-    LocalScreen.LeftColumn,\r
-    LocalScreen.RightColumn,\r
-    LocalScreen.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT,\r
-    LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 1,\r
-    KEYHELP_TEXT | KEYHELP_BACKGROUND\r
-    );\r
-\r
-  if ((gClassOfVfr & FORMSET_CLASS_FRONT_PAGE) != FORMSET_CLASS_FRONT_PAGE) {\r
-    ClearLines (\r
-      LocalScreen.LeftColumn,\r
-      LocalScreen.RightColumn,\r
-      LocalScreen.TopRow,\r
-      LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT - 1,\r
-      TITLE_TEXT | TITLE_BACKGROUND\r
-      );\r
-    //\r
-    // Print Top border line\r
-    // +------------------------------------------------------------------------------+\r
-    // ?                                                                             ?\r
-    // +------------------------------------------------------------------------------+\r
-    //\r
-    Character = BOXDRAW_DOWN_RIGHT;\r
-\r
-    PrintChar (Character);\r
-    PrintString (Buffer);\r
-\r
-    Character = BOXDRAW_DOWN_LEFT;\r
-    PrintChar (Character);\r
-\r
-    Character = BOXDRAW_VERTICAL;\r
-    for (Row = LocalScreen.TopRow + 1; Row <= LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT - 2; Row++) {\r
-      PrintCharAt (LocalScreen.LeftColumn, Row, Character);\r
-      PrintCharAt (LocalScreen.RightColumn - 1, Row, Character);\r
+  CopyMem (&DisplayStatement->CurrentValue, &Statement->HiiValue, sizeof (EFI_HII_VALUE));\r
+\r
+  //\r
+  // Some special op code need an extra buffer to save the data.\r
+  // Such as string, password, orderedlist...\r
+  //\r
+  if (Statement->BufferValue != NULL) {\r
+    //\r
+    // Ordered list opcode may not initilized, get default value here.\r
+    //\r
+    if (Statement->OpCode->OpCode == EFI_IFR_ORDERED_LIST_OP && GetArrayData (Statement->BufferValue, Statement->ValueType, 0) == 0) {\r
+      GetQuestionDefault (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, 0);\r
     }\r
 \r
-    Character = BOXDRAW_UP_RIGHT;\r
-    PrintCharAt (LocalScreen.LeftColumn, LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT - 1, Character);\r
-    PrintString (Buffer);\r
+    DisplayStatement->CurrentValue.Buffer    = AllocateCopyPool(Statement->StorageWidth,Statement->BufferValue);\r
+    DisplayStatement->CurrentValue.BufferLen = Statement->StorageWidth;\r
+  }\r
 \r
-    Character = BOXDRAW_UP_LEFT;\r
-    PrintChar (Character);\r
+  DisplayStatement->SettingChangedFlag = Statement->ValueChanged;\r
 \r
-    if ((gClassOfVfr & FORMSET_CLASS_PLATFORM_SETUP) == FORMSET_CLASS_PLATFORM_SETUP) {\r
-      //\r
-      // Print Bottom border line\r
-      // +------------------------------------------------------------------------------+\r
-      // ?                                                                             ?\r
-      // +------------------------------------------------------------------------------+\r
-      //\r
-      Character = BOXDRAW_DOWN_RIGHT;\r
-      PrintCharAt (LocalScreen.LeftColumn, LocalScreen.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT, Character);\r
-\r
-      PrintString (Buffer);\r
-\r
-      Character = BOXDRAW_DOWN_LEFT;\r
-      PrintChar (Character);\r
-      Character = BOXDRAW_VERTICAL;\r
-      for (Row = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT + 1;\r
-           Row <= LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 2;\r
-           Row++\r
-          ) {\r
-        PrintCharAt (LocalScreen.LeftColumn, Row, Character);\r
-        PrintCharAt (LocalScreen.RightColumn - 1, Row, Character);\r
-      }\r
+  //\r
+  // Get the highlight statement for current form.\r
+  //\r
+  if (((gCurrentSelection->QuestionId != 0) && (Statement->QuestionId == gCurrentSelection->QuestionId)) ||\r
+      ((mCurFakeQestId != 0) && (Statement->FakeQuestionId == mCurFakeQestId))) {\r
+    gDisplayFormData.HighLightedStatement = DisplayStatement;\r
+  }\r
 \r
-      Character = BOXDRAW_UP_RIGHT;\r
-      PrintCharAt (LocalScreen.LeftColumn, LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 1, Character);\r
+  //\r
+  // Create the refresh event process function.\r
+  //\r
+  if (!IsZeroGuid (&Statement->RefreshGuid)) {\r
+    CreateRefreshEventForStatement (Statement);\r
+  }\r
 \r
-      PrintString (Buffer);\r
+  //\r
+  // For RTC type of date/time, set default refresh interval to be 1 second.\r
+  //\r
+  if ((Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) && Statement->Storage == NULL) {\r
+    Statement->RefreshInterval = 1;\r
+  }\r
 \r
-      Character = BOXDRAW_UP_LEFT;\r
-      PrintChar (Character);\r
-    }\r
+  //\r
+  // Create the refresh guid hook event.\r
+  // If the statement in this form has refresh event or refresh interval, browser will create this event for display engine.\r
+  //\r
+  if ((!IsZeroGuid (&Statement->RefreshGuid)) || (Statement->RefreshInterval != 0)) {\r
+    gDisplayFormData.FormRefreshEvent = mValueChangedEvent;\r
   }\r
 \r
-  FreePool (Buffer);\r
+  //\r
+  // Save the password check function for later use.\r
+  //\r
+  if (Statement->Operand == EFI_IFR_PASSWORD_OP) {\r
+    DisplayStatement->PasswordCheck = PasswordCheck;\r
+  }\r
 \r
+  //\r
+  // If this statement is nest in the subtitle, insert to the host statement.\r
+  // else insert to the form it belongs to.\r
+  //\r
+  if (Statement->ParentStatement != NULL) {\r
+    ParentStatement = GetDisplayStatement(Statement->ParentStatement->OpCode);\r
+    ASSERT (ParentStatement != NULL);\r
+    InsertTailList(&ParentStatement->NestStatementList, &DisplayStatement->DisplayLink);\r
+  } else {\r
+    InsertTailList(&gDisplayFormData.StatementListHead, &DisplayStatement->DisplayLink);\r
+  }\r
 }\r
 \r
-\r
 /**\r
-  Evaluate all expressions in a Form.\r
-\r
-  @param  FormSet        FormSet this Form belongs to.\r
-  @param  Form           The Form.\r
+  Process for the refresh interval statement.\r
 \r
-  @retval EFI_SUCCESS    The expression evaluated successfuly\r
+  @param Event    The Event need to be process\r
+  @param Context  The context of the event.\r
 \r
 **/\r
-EFI_STATUS\r
-EvaluateFormExpressions (\r
-  IN FORM_BROWSER_FORMSET  *FormSet,\r
-  IN FORM_BROWSER_FORM     *Form\r
+VOID\r
+EFIAPI\r
+RefreshIntervalProcess (\r
+  IN  EFI_EVENT    Event,\r
+  IN  VOID         *Context\r
   )\r
 {\r
-  EFI_STATUS       Status;\r
-  LIST_ENTRY       *Link;\r
-  FORM_EXPRESSION  *Expression;\r
+  FORM_BROWSER_STATEMENT        *Statement;\r
+  LIST_ENTRY                    *Link;\r
 \r
-  Link = GetFirstNode (&Form->ExpressionListHead);\r
-  while (!IsNull (&Form->ExpressionListHead, Link)) {\r
-    Expression = FORM_EXPRESSION_FROM_LINK (Link);\r
-    Link = GetNextNode (&Form->ExpressionListHead, Link);\r
+  Link = GetFirstNode (&gCurrentSelection->Form->StatementListHead);\r
+  while (!IsNull (&gCurrentSelection->Form->StatementListHead, Link)) {\r
+    Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);\r
+    Link = GetNextNode (&gCurrentSelection->Form->StatementListHead, Link);\r
 \r
-    if (Expression->Type == EFI_HII_EXPRESSION_INCONSISTENT_IF ||\r
-        Expression->Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF) {\r
-      //\r
-      // Postpone Form validation to Question editing or Form submiting\r
-      //\r
+    if (Statement->RefreshInterval == 0) {\r
       continue;\r
     }\r
 \r
-    Status = EvaluateExpression (FormSet, Form, Expression);\r
-    if (EFI_ERROR (Status)) {\r
-      return Status;\r
-    }\r
+    UpdateStatement(Statement);\r
   }\r
 \r
-  return EFI_SUCCESS;\r
+  gBS->SignalEvent (mValueChangedEvent);\r
 }\r
 \r
-/*\r
-+------------------------------------------------------------------------------+\r
-?                                 Setup Page                                  ?\r
-+------------------------------------------------------------------------------+\r
-\r
-\r
+/**\r
 \r
+  Make a copy of the global hotkey info.\r
 \r
+**/\r
+VOID\r
+UpdateHotkeyList (\r
+  VOID\r
+  )\r
+{\r
+  BROWSER_HOT_KEY  *HotKey;\r
+  BROWSER_HOT_KEY  *CopyKey;\r
+  LIST_ENTRY       *Link;\r
 \r
+  Link = GetFirstNode (&gBrowserHotKeyList);\r
+  while (!IsNull (&gBrowserHotKeyList, Link)) {\r
+    HotKey = BROWSER_HOT_KEY_FROM_LINK (Link);\r
 \r
+    CopyKey             = AllocateCopyPool(sizeof (BROWSER_HOT_KEY), HotKey);\r
+    ASSERT (CopyKey != NULL);\r
+    CopyKey->KeyData    = AllocateCopyPool(sizeof (EFI_INPUT_KEY), HotKey->KeyData);\r
+    ASSERT (CopyKey->KeyData != NULL);\r
+    CopyKey->HelpString = AllocateCopyPool(StrSize (HotKey->HelpString), HotKey->HelpString);\r
+    ASSERT (CopyKey->HelpString != NULL);\r
 \r
+    InsertTailList(&gDisplayFormData.HotKeyListHead, &CopyKey->Link);\r
 \r
+    Link = GetNextNode (&gBrowserHotKeyList, Link);\r
+  }\r
+}\r
 \r
+/**\r
 \r
+  Get the extra question attribute from override question list.\r
 \r
+  @param    QuestionId    The question id for this request question.\r
 \r
+  @retval   The attribute for this question or NULL if not found this\r
+            question in the list.\r
 \r
+**/\r
+UINT32\r
+ProcessQuestionExtraAttr (\r
+  IN   EFI_QUESTION_ID  QuestionId\r
+  )\r
+{\r
+  LIST_ENTRY                   *Link;\r
+  QUESTION_ATTRIBUTE_OVERRIDE  *QuestionDesc;\r
 \r
+  //\r
+  // Return HII_DISPLAY_NONE if input a invalid question id.\r
+  //\r
+  if (QuestionId == 0) {\r
+    return HII_DISPLAY_NONE;\r
+  }\r
 \r
+  Link = GetFirstNode (&mPrivateData.FormBrowserEx2.OverrideQestListHead);\r
+  while (!IsNull (&mPrivateData.FormBrowserEx2.OverrideQestListHead, Link)) {\r
+    QuestionDesc = FORM_QUESTION_ATTRIBUTE_OVERRIDE_FROM_LINK (Link);\r
+    Link = GetNextNode (&mPrivateData.FormBrowserEx2.OverrideQestListHead, Link);\r
 \r
+    if ((QuestionDesc->QuestionId == QuestionId) &&\r
+        (QuestionDesc->FormId     == gCurrentSelection->FormId) &&\r
+        (QuestionDesc->HiiHandle  == gCurrentSelection->Handle) &&\r
+        CompareGuid (&QuestionDesc->FormSetGuid, &gCurrentSelection->FormSetGuid)) {\r
+      return QuestionDesc->Attribute;\r
+    }\r
+  }\r
 \r
-+------------------------------------------------------------------------------+\r
-?F1=Scroll Help                 F9=Reset to Defaults        F10=Save and Exit ?\r
-| ^"=Move Highlight          <Spacebar> Toggles Checkbox   Esc=Discard Changes |\r
-+------------------------------------------------------------------------------+\r
-*/\r
+  return HII_DISPLAY_NONE;\r
+}\r
 \r
 /**\r
 \r
-\r
-  Display form and wait for user to select one menu option, then return it.\r
-\r
-  @param Selection       On input, Selection tell setup browser the information\r
-                         about the Selection, form and formset to be displayed.\r
-                         On output, Selection return the screen item that is selected\r
-                         by user.\r
-  @retval EFI_SUCESSS            This function always return successfully for now.\r
+  Enum all statement in current form, find all the statement can be display and\r
+  add to the display form.\r
 \r
 **/\r
-EFI_STATUS\r
-DisplayForm (\r
-  IN OUT UI_MENU_SELECTION           *Selection\r
+VOID\r
+AddStatementToDisplayForm (\r
+  VOID\r
   )\r
 {\r
-  CHAR16                 *StringPtr;\r
-  UINT16                 MenuItemCount;\r
-  EFI_HII_HANDLE         Handle;\r
-  BOOLEAN                Suppress;\r
-  EFI_SCREEN_DESCRIPTOR  LocalScreen;\r
-  UINT16                 Width;\r
-  UINTN                  ArrayEntry;\r
-  CHAR16                 *OutputString;\r
-  LIST_ENTRY             *Link;\r
-  FORM_BROWSER_STATEMENT *Statement;\r
-  UINT16                 NumberOfLines;\r
-  EFI_STATUS             Status;\r
-  UI_MENU_OPTION         *MenuOption;\r
+  EFI_STATUS                    Status;\r
+  LIST_ENTRY                    *Link;\r
+  FORM_BROWSER_STATEMENT        *Statement;\r
+  FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement;\r
+  UINT8                         MinRefreshInterval;\r
+  EFI_EVENT                     RefreshIntervalEvent;\r
+  FORM_BROWSER_REFRESH_EVENT_NODE *EventNode;\r
+  BOOLEAN                       FormEditable;\r
+  UINT32                        ExtraAttribute;\r
+\r
+  MinRefreshInterval   = 0;\r
+  FormEditable         = FALSE;\r
 \r
-  Handle        = Selection->Handle;\r
-  MenuItemCount = 0;\r
-  ArrayEntry    = 0;\r
-  OutputString  = NULL;\r
-\r
-  UiInitMenu ();\r
+  //\r
+  // Process the statement outside the form, these statements are not recognized\r
+  // by browser core.\r
+  //\r
+  Link = GetFirstNode (&gCurrentSelection->FormSet->StatementListOSF);\r
+  while (!IsNull (&gCurrentSelection->FormSet->StatementListOSF, Link)) {\r
+    Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);\r
+    Link = GetNextNode (&gCurrentSelection->FormSet->StatementListOSF, Link);\r
 \r
-  CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));\r
+    DisplayStatement = AllocateZeroPool (sizeof (FORM_DISPLAY_ENGINE_STATEMENT));\r
+    ASSERT (DisplayStatement != NULL);\r
+    DisplayStatement->Signature = FORM_DISPLAY_ENGINE_STATEMENT_SIGNATURE;\r
+    DisplayStatement->Version   = FORM_DISPLAY_ENGINE_STATEMENT_VERSION_1;\r
+    DisplayStatement->OpCode = Statement->OpCode;\r
 \r
-  StringPtr = GetToken (Selection->Form->FormTitle, Handle);\r
+    InitializeListHead (&DisplayStatement->NestStatementList);\r
+    InitializeListHead (&DisplayStatement->OptionListHead);\r
 \r
-  if ((gClassOfVfr & FORMSET_CLASS_FRONT_PAGE) != FORMSET_CLASS_FRONT_PAGE) {\r
-    gST->ConOut->SetAttribute (gST->ConOut, TITLE_TEXT | TITLE_BACKGROUND);\r
-    PrintStringAt (\r
-      (LocalScreen.RightColumn + LocalScreen.LeftColumn - GetStringWidth (StringPtr) / 2) / 2,\r
-      LocalScreen.TopRow + 1,\r
-      StringPtr\r
-      );\r
+    InsertTailList(&gDisplayFormData.StatementListOSF, &DisplayStatement->DisplayLink);\r
   }\r
 \r
   //\r
-  // Remove Buffer allocated for StringPtr after it has been used.\r
+  // treat formset as statement outside the form,get its opcode.\r
   //\r
-  FreePool (StringPtr);\r
+  DisplayStatement = AllocateZeroPool (sizeof (FORM_DISPLAY_ENGINE_STATEMENT));\r
+  ASSERT (DisplayStatement != NULL);\r
+\r
+  DisplayStatement->Signature = FORM_DISPLAY_ENGINE_STATEMENT_SIGNATURE;\r
+  DisplayStatement->Version   = FORM_DISPLAY_ENGINE_STATEMENT_VERSION_1;\r
+  DisplayStatement->OpCode = gCurrentSelection->FormSet->OpCode;\r
+\r
+  InitializeListHead (&DisplayStatement->NestStatementList);\r
+  InitializeListHead (&DisplayStatement->OptionListHead);\r
+\r
+  InsertTailList(&gDisplayFormData.StatementListOSF, &DisplayStatement->DisplayLink);\r
 \r
   //\r
-  // Evaluate all the Expressions in this Form\r
+  // Process the statement in this form.\r
   //\r
-  Status = EvaluateFormExpressions (Selection->FormSet, Selection->Form);\r
-  if (EFI_ERROR (Status)) {\r
-    return Status;\r
-  }\r
-\r
-  Selection->FormEditable = FALSE;\r
-  Link = GetFirstNode (&Selection->Form->StatementListHead);\r
-  while (!IsNull (&Selection->Form->StatementListHead, Link)) {\r
+  Link = GetFirstNode (&gCurrentSelection->Form->StatementListHead);\r
+  while (!IsNull (&gCurrentSelection->Form->StatementListHead, Link)) {\r
     Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);\r
+    Link = GetNextNode (&gCurrentSelection->Form->StatementListHead, Link);\r
 \r
-    if (Statement->SuppressExpression != NULL) {\r
-      Suppress = Statement->SuppressExpression->Result.Value.b;\r
-    } else {\r
-      Suppress = FALSE;\r
+    //\r
+    // This statement can't be show, skip it.\r
+    //\r
+    if (EvaluateExpressionList(Statement->Expression, FALSE, NULL, NULL) > ExpressGrayOut) {\r
+      continue;\r
     }\r
 \r
-    if (Statement->DisableExpression != NULL) {\r
-      Suppress = (BOOLEAN) (Suppress || Statement->DisableExpression->Result.Value.b);\r
+    //\r
+    // Check the extra attribute.\r
+    //\r
+    ExtraAttribute = ProcessQuestionExtraAttr (Statement->QuestionId);\r
+    if ((ExtraAttribute & HII_DISPLAY_SUPPRESS) != 0) {\r
+      continue;\r
     }\r
 \r
-    if (!Suppress) {\r
-      StringPtr = GetToken (Statement->Prompt, Handle);\r
+    DisplayStatement = AllocateZeroPool (sizeof (FORM_DISPLAY_ENGINE_STATEMENT));\r
+    ASSERT (DisplayStatement != NULL);\r
 \r
-      Width     = GetWidth (Statement, Handle);\r
+    //\r
+    // Initialize this statement and add it to the display form.\r
+    //\r
+    InitializeDisplayStatement(DisplayStatement, Statement);\r
 \r
-      NumberOfLines = 1;\r
-      ArrayEntry = 0;\r
-      for (; GetLineByWidth (StringPtr, Width, &ArrayEntry, &OutputString) != 0x0000;) {\r
-        //\r
-        // If there is more string to process print on the next row and increment the Skip value\r
-        //\r
-        if (StrLen (&StringPtr[ArrayEntry]) != 0) {\r
-          NumberOfLines++;\r
-        }\r
+    //\r
+    // Set the extra attribute.\r
+    //\r
+    DisplayStatement->Attribute |= ExtraAttribute;\r
 \r
-        FreePool (OutputString);\r
-      }\r
+    if (Statement->Storage != NULL) {\r
+      FormEditable = TRUE;\r
+    }\r
 \r
-      //\r
-      // We are NOT!! removing this StringPtr buffer via FreePool since it is being used in the menuoptions, we will do\r
-      // it in UiFreeMenu.\r
-      //\r
-      MenuOption = UiAddMenuOption (StringPtr, Selection->Handle, Statement, NumberOfLines, MenuItemCount);\r
-      MenuItemCount++;\r
+    //\r
+    // Get the minimal refresh interval value for later use.\r
+    //\r
+    if ((Statement->RefreshInterval != 0) &&\r
+      (MinRefreshInterval == 0 || Statement->RefreshInterval < MinRefreshInterval)) {\r
+      MinRefreshInterval = Statement->RefreshInterval;\r
+    }\r
+  }\r
 \r
-      if (MenuOption->IsQuestion && !MenuOption->ReadOnly) {\r
-        //\r
-        // At least one item is not readonly, this Form is considered as editable\r
-        //\r
-        Selection->FormEditable = TRUE;\r
+  //\r
+  // Create the periodic timer for refresh interval statement.\r
+  //\r
+  if (MinRefreshInterval != 0) {\r
+    Status = gBS->CreateEvent (EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK, RefreshIntervalProcess, NULL, &RefreshIntervalEvent);\r
+    ASSERT_EFI_ERROR (Status);\r
+    Status = gBS->SetTimer (RefreshIntervalEvent, TimerPeriodic, MinRefreshInterval * ONE_SECOND);\r
+    ASSERT_EFI_ERROR (Status);\r
+\r
+    EventNode = AllocateZeroPool (sizeof (FORM_BROWSER_REFRESH_EVENT_NODE));\r
+    ASSERT (EventNode != NULL);\r
+    EventNode->RefreshEvent = RefreshIntervalEvent;\r
+    InsertTailList(&mRefreshEventList, &EventNode->Link);\r
+  }\r
+\r
+  //\r
+  // Create the refresh event process function for Form.\r
+  //\r
+  if (!IsZeroGuid (&gCurrentSelection->Form->RefreshGuid)) {\r
+    CreateRefreshEventForForm (gCurrentSelection->Form);\r
+    if (gDisplayFormData.FormRefreshEvent == NULL) {\r
+      gDisplayFormData.FormRefreshEvent = mValueChangedEvent;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Update hotkey list field.\r
+  //\r
+  if (gBrowserSettingScope == SystemLevel || FormEditable) {\r
+    UpdateHotkeyList();\r
+  }\r
+}\r
+\r
+/**\r
+\r
+  Initialize the SettingChangedFlag variable in the display form.\r
+\r
+**/\r
+VOID\r
+UpdateDataChangedFlag (\r
+  VOID\r
+  )\r
+{\r
+  LIST_ENTRY           *Link;\r
+  FORM_BROWSER_FORMSET *LocalFormSet;\r
+\r
+  gDisplayFormData.SettingChangedFlag   = FALSE;\r
+\r
+  if (IsNvUpdateRequiredForForm (gCurrentSelection->Form)) {\r
+    gDisplayFormData.SettingChangedFlag = TRUE;\r
+    return;\r
+  }\r
+\r
+  //\r
+  // Base on the system level to check whether need to show the NV flag.\r
+  //\r
+  switch (gBrowserSettingScope) {\r
+  case SystemLevel:\r
+    //\r
+    // Check the maintain list to see whether there is any change.\r
+    //\r
+    Link = GetFirstNode (&gBrowserFormSetList);\r
+    while (!IsNull (&gBrowserFormSetList, Link)) {\r
+      LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);\r
+      if (IsNvUpdateRequiredForFormSet(LocalFormSet)) {\r
+        gDisplayFormData.SettingChangedFlag = TRUE;\r
+        return;\r
       }\r
+      Link = GetNextNode (&gBrowserFormSetList, Link);\r
+    }\r
+    break;\r
+\r
+  case FormSetLevel:\r
+    if (IsNvUpdateRequiredForFormSet(gCurrentSelection->FormSet)) {\r
+      gDisplayFormData.SettingChangedFlag = TRUE;\r
+      return;\r
     }\r
+    break;\r
 \r
-    Link = GetNextNode (&Selection->Form->StatementListHead, Link);\r
+  default:\r
+    break;\r
   }\r
+}\r
 \r
-  Status = UiDisplayMenu (Selection);\r
+/**\r
 \r
-  UiFreeMenu ();\r
+  Initialize the Display form structure data.\r
 \r
-  return Status;\r
+**/\r
+VOID\r
+InitializeDisplayFormData (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  gDisplayFormData.Signature   = FORM_DISPLAY_ENGINE_FORM_SIGNATURE;\r
+  gDisplayFormData.Version     = FORM_DISPLAY_ENGINE_VERSION_1;\r
+  gDisplayFormData.ImageId     = 0;\r
+  gDisplayFormData.AnimationId = 0;\r
+\r
+  InitializeListHead (&gDisplayFormData.StatementListHead);\r
+  InitializeListHead (&gDisplayFormData.StatementListOSF);\r
+  InitializeListHead (&gDisplayFormData.HotKeyListHead);\r
+\r
+  Status = gBS->CreateEvent (\r
+        EVT_NOTIFY_WAIT,\r
+        TPL_CALLBACK,\r
+        EfiEventEmptyFunction,\r
+        NULL,\r
+        &mValueChangedEvent\r
+        );\r
+  ASSERT_EFI_ERROR (Status);\r
 }\r
 \r
 /**\r
-  Initialize the HII String Token to the correct values.\r
+\r
+  Free the kotkey info saved in form data.\r
 \r
 **/\r
 VOID\r
-InitializeBrowserStrings (\r
+FreeHotkeyList (\r
   VOID\r
   )\r
 {\r
-  gFunctionNineString   = GetToken (STRING_TOKEN (FUNCTION_NINE_STRING), gHiiHandle);\r
-  gFunctionTenString    = GetToken (STRING_TOKEN (FUNCTION_TEN_STRING), gHiiHandle);\r
-  gEnterString          = GetToken (STRING_TOKEN (ENTER_STRING), gHiiHandle);\r
-  gEnterCommitString    = GetToken (STRING_TOKEN (ENTER_COMMIT_STRING), gHiiHandle);\r
-  gEnterEscapeString    = GetToken (STRING_TOKEN (ENTER_ESCAPE_STRING), gHiiHandle);\r
-  gEscapeString         = GetToken (STRING_TOKEN (ESCAPE_STRING), gHiiHandle);\r
-  gSaveFailed           = GetToken (STRING_TOKEN (SAVE_FAILED), gHiiHandle);\r
-  gMoveHighlight        = GetToken (STRING_TOKEN (MOVE_HIGHLIGHT), gHiiHandle);\r
-  gMakeSelection        = GetToken (STRING_TOKEN (MAKE_SELECTION), gHiiHandle);\r
-  gDecNumericInput      = GetToken (STRING_TOKEN (DEC_NUMERIC_INPUT), gHiiHandle);\r
-  gHexNumericInput      = GetToken (STRING_TOKEN (HEX_NUMERIC_INPUT), gHiiHandle);\r
-  gToggleCheckBox       = GetToken (STRING_TOKEN (TOGGLE_CHECK_BOX), gHiiHandle);\r
-  gPromptForData        = GetToken (STRING_TOKEN (PROMPT_FOR_DATA), gHiiHandle);\r
-  gPromptForPassword    = GetToken (STRING_TOKEN (PROMPT_FOR_PASSWORD), gHiiHandle);\r
-  gPromptForNewPassword = GetToken (STRING_TOKEN (PROMPT_FOR_NEW_PASSWORD), gHiiHandle);\r
-  gConfirmPassword      = GetToken (STRING_TOKEN (CONFIRM_PASSWORD), gHiiHandle);\r
-  gConfirmError         = GetToken (STRING_TOKEN (CONFIRM_ERROR), gHiiHandle);\r
-  gPassowordInvalid     = GetToken (STRING_TOKEN (PASSWORD_INVALID), gHiiHandle);\r
-  gPressEnter           = GetToken (STRING_TOKEN (PRESS_ENTER), gHiiHandle);\r
-  gEmptyString          = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle);\r
-  gAreYouSure           = GetToken (STRING_TOKEN (ARE_YOU_SURE), gHiiHandle);\r
-  gYesResponse          = GetToken (STRING_TOKEN (ARE_YOU_SURE_YES), gHiiHandle);\r
-  gNoResponse           = GetToken (STRING_TOKEN (ARE_YOU_SURE_NO), gHiiHandle);\r
-  gMiniString           = GetToken (STRING_TOKEN (MINI_STRING), gHiiHandle);\r
-  gPlusString           = GetToken (STRING_TOKEN (PLUS_STRING), gHiiHandle);\r
-  gMinusString          = GetToken (STRING_TOKEN (MINUS_STRING), gHiiHandle);\r
-  gAdjustNumber         = GetToken (STRING_TOKEN (ADJUST_NUMBER), gHiiHandle);\r
-  gSaveChanges          = GetToken (STRING_TOKEN (SAVE_CHANGES), gHiiHandle);\r
-  gOptionMismatch       = GetToken (STRING_TOKEN (OPTION_MISMATCH), gHiiHandle);\r
-  gFormSuppress         = GetToken (STRING_TOKEN (FORM_SUPPRESSED), gHiiHandle);\r
-  return ;\r
+  BROWSER_HOT_KEY  *HotKey;\r
+  LIST_ENTRY       *Link;\r
+\r
+  while (!IsListEmpty (&gDisplayFormData.HotKeyListHead)) {\r
+    Link = GetFirstNode (&gDisplayFormData.HotKeyListHead);\r
+    HotKey = BROWSER_HOT_KEY_FROM_LINK (Link);\r
+\r
+    RemoveEntryList (&HotKey->Link);\r
+\r
+    FreePool (HotKey->KeyData);\r
+    FreePool (HotKey->HelpString);\r
+    FreePool (HotKey);\r
+  }\r
 }\r
 \r
 /**\r
-  Free up the resource allocated for all strings required\r
-  by Setup Browser.\r
+\r
+  Update the Display form structure data.\r
 \r
 **/\r
 VOID\r
-FreeBrowserStrings (\r
+UpdateDisplayFormData (\r
   VOID\r
   )\r
 {\r
-  FreePool (gFunctionNineString);\r
-  FreePool (gFunctionTenString);\r
-  FreePool (gEnterString);\r
-  FreePool (gEnterCommitString);\r
-  FreePool (gEnterEscapeString);\r
-  FreePool (gEscapeString);\r
-  FreePool (gMoveHighlight);\r
-  FreePool (gMakeSelection);\r
-  FreePool (gDecNumericInput);\r
-  FreePool (gHexNumericInput);\r
-  FreePool (gToggleCheckBox);\r
-  FreePool (gPromptForData);\r
-  FreePool (gPromptForPassword);\r
-  FreePool (gPromptForNewPassword);\r
-  FreePool (gConfirmPassword);\r
-  FreePool (gPassowordInvalid);\r
-  FreePool (gConfirmError);\r
-  FreePool (gPressEnter);\r
-  FreePool (gEmptyString);\r
-  FreePool (gAreYouSure);\r
-  FreePool (gYesResponse);\r
-  FreePool (gNoResponse);\r
-  FreePool (gMiniString);\r
-  FreePool (gPlusString);\r
-  FreePool (gMinusString);\r
-  FreePool (gAdjustNumber);\r
-  FreePool (gSaveChanges);\r
-  FreePool (gOptionMismatch);\r
-  FreePool (gFormSuppress);\r
-  return ;\r
+  gDisplayFormData.FormTitle        = gCurrentSelection->Form->FormTitle;\r
+  gDisplayFormData.FormId           = gCurrentSelection->FormId;\r
+  gDisplayFormData.HiiHandle        = gCurrentSelection->Handle;\r
+  CopyGuid (&gDisplayFormData.FormSetGuid, &gCurrentSelection->FormSetGuid);\r
+\r
+  gDisplayFormData.Attribute        = 0;\r
+  gDisplayFormData.Attribute       |= gCurrentSelection->Form->ModalForm ? HII_DISPLAY_MODAL : 0;\r
+  gDisplayFormData.Attribute       |= gCurrentSelection->Form->Locked    ? HII_DISPLAY_LOCK  : 0;\r
+\r
+  gDisplayFormData.FormRefreshEvent     = NULL;\r
+  gDisplayFormData.HighLightedStatement = NULL;\r
+\r
+  UpdateDataChangedFlag ();\r
+\r
+  AddStatementToDisplayForm ();\r
 }\r
 \r
+/**\r
+\r
+  Free the Display Statement structure data.\r
+\r
+  @param   StatementList         Point to the statement list which need to be free.\r
+\r
+**/\r
+VOID\r
+FreeStatementData (\r
+  LIST_ENTRY           *StatementList\r
+  )\r
+{\r
+  LIST_ENTRY                    *Link;\r
+  LIST_ENTRY                    *OptionLink;\r
+  FORM_DISPLAY_ENGINE_STATEMENT *Statement;\r
+  DISPLAY_QUESTION_OPTION       *Option;\r
+\r
+  //\r
+  // Free Statements/Questions\r
+  //\r
+  while (!IsListEmpty (StatementList)) {\r
+    Link = GetFirstNode (StatementList);\r
+    Statement = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (Link);\r
+\r
+    //\r
+    // Free Options List\r
+    //\r
+    while (!IsListEmpty (&Statement->OptionListHead)) {\r
+      OptionLink = GetFirstNode (&Statement->OptionListHead);\r
+      Option = DISPLAY_QUESTION_OPTION_FROM_LINK (OptionLink);\r
+      RemoveEntryList (&Option->Link);\r
+      FreePool (Option);\r
+    }\r
+\r
+    //\r
+    // Free nest statement List\r
+    //\r
+    if (!IsListEmpty (&Statement->NestStatementList)) {\r
+      FreeStatementData(&Statement->NestStatementList);\r
+    }\r
+\r
+    RemoveEntryList (&Statement->DisplayLink);\r
+    FreePool (Statement);\r
+  }\r
+}\r
 \r
 /**\r
-  Update key's help imformation.\r
 \r
-  @param Selection       Tell setup browser the information about the Selection\r
-  @param  MenuOption     The Menu option\r
-  @param  Selected       Whether or not a tag be selected\r
+  Free the Display form structure data.\r
 \r
 **/\r
 VOID\r
-UpdateKeyHelp (\r
-  IN  UI_MENU_SELECTION           *Selection,\r
-  IN  UI_MENU_OPTION              *MenuOption,\r
-  IN  BOOLEAN                     Selected\r
+FreeDisplayFormData (\r
+  VOID\r
+  )\r
+{\r
+  FreeStatementData (&gDisplayFormData.StatementListHead);\r
+  FreeStatementData (&gDisplayFormData.StatementListOSF);\r
+\r
+  FreeRefreshEvent();\r
+\r
+  FreeHotkeyList();\r
+}\r
+\r
+/**\r
+\r
+  Get FORM_BROWSER_STATEMENT from FORM_DISPLAY_ENGINE_STATEMENT based on the OpCode info.\r
+\r
+  @param DisplayStatement        The input FORM_DISPLAY_ENGINE_STATEMENT.\r
+\r
+  @retval FORM_BROWSER_STATEMENT  The return FORM_BROWSER_STATEMENT info.\r
+\r
+**/\r
+FORM_BROWSER_STATEMENT *\r
+GetBrowserStatement (\r
+  IN FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement\r
   )\r
 {\r
-  UINTN                  SecCol;\r
-  UINTN                  ThdCol;\r
-  UINTN                  LeftColumnOfHelp;\r
-  UINTN                  RightColumnOfHelp;\r
-  UINTN                  TopRowOfHelp;\r
-  UINTN                  BottomRowOfHelp;\r
-  UINTN                  StartColumnOfHelp;\r
-  EFI_SCREEN_DESCRIPTOR  LocalScreen;\r
   FORM_BROWSER_STATEMENT *Statement;\r
+  LIST_ENTRY             *Link;\r
+\r
+  Link = GetFirstNode (&gCurrentSelection->Form->StatementListHead);\r
+  while (!IsNull (&gCurrentSelection->Form->StatementListHead, Link)) {\r
+    Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);\r
+\r
+    if (Statement->OpCode == DisplayStatement->OpCode) {\r
+      return Statement;\r
+    }\r
+\r
+    Link = GetNextNode (&gCurrentSelection->Form->StatementListHead, Link);\r
+  }\r
+\r
+  return NULL;\r
+}\r
+\r
+/**\r
+  Update the ValueChanged status for questions in this form.\r
+\r
+  @param  FormSet                FormSet data structure.\r
+  @param  Form                   Form data structure.\r
+\r
+**/\r
+VOID\r
+UpdateStatementStatusForForm (\r
+  IN FORM_BROWSER_FORMSET             *FormSet,\r
+  IN FORM_BROWSER_FORM                *Form\r
+  )\r
+{\r
+  LIST_ENTRY                  *Link;\r
+  FORM_BROWSER_STATEMENT      *Question;\r
+\r
+  Link = GetFirstNode (&Form->StatementListHead);\r
+  while (!IsNull (&Form->StatementListHead, Link)) {\r
+    Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);\r
+    Link = GetNextNode (&Form->StatementListHead, Link);\r
+\r
+    //\r
+    // For password opcode, not set the the value changed flag.\r
+    //\r
+    if (Question->Operand == EFI_IFR_PASSWORD_OP) {\r
+      continue;\r
+    }\r
+\r
+    IsQuestionValueChanged(FormSet, Form, Question, GetSetValueWithBuffer);\r
+  }\r
+}\r
+\r
+/**\r
+  Update the ValueChanged status for questions in this formset.\r
+\r
+  @param  FormSet                FormSet data structure.\r
+\r
+**/\r
+VOID\r
+UpdateStatementStatusForFormSet (\r
+  IN FORM_BROWSER_FORMSET                *FormSet\r
+  )\r
+{\r
+  LIST_ENTRY                  *Link;\r
+  FORM_BROWSER_FORM           *Form;\r
+\r
+  Link = GetFirstNode (&FormSet->FormListHead);\r
+  while (!IsNull (&FormSet->FormListHead, Link)) {\r
+    Form = FORM_BROWSER_FORM_FROM_LINK (Link);\r
+    Link = GetNextNode (&FormSet->FormListHead, Link);\r
+\r
+    UpdateStatementStatusForForm (FormSet, Form);\r
+  }\r
+}\r
+\r
+/**\r
+  Update the ValueChanged status for questions.\r
+\r
+  @param  FormSet                FormSet data structure.\r
+  @param  Form                   Form data structure.\r
+  @param  SettingScope           Setting Scope for Default action.\r
+\r
+**/\r
+VOID\r
+UpdateStatementStatus (\r
+  IN FORM_BROWSER_FORMSET             *FormSet,\r
+  IN FORM_BROWSER_FORM                *Form,\r
+  IN BROWSER_SETTING_SCOPE            SettingScope\r
+  )\r
+{\r
+  LIST_ENTRY                  *Link;\r
+  FORM_BROWSER_FORMSET        *LocalFormSet;\r
+\r
+  switch (SettingScope) {\r
+  case SystemLevel:\r
+    Link = GetFirstNode (&gBrowserFormSetList);\r
+    while (!IsNull (&gBrowserFormSetList, Link)) {\r
+      LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);\r
+      Link = GetNextNode (&gBrowserFormSetList, Link);\r
+      if (!ValidateFormSet(LocalFormSet)) {\r
+        continue;\r
+      }\r
+\r
+      UpdateStatementStatusForFormSet (LocalFormSet);\r
+    }\r
+    break;\r
+\r
+  case FormSetLevel:\r
+    UpdateStatementStatusForFormSet (FormSet);\r
+    break;\r
+\r
+  case FormLevel:\r
+    UpdateStatementStatusForForm (FormSet, Form);\r
+    break;\r
+\r
+  default:\r
+    break;\r
+  }\r
+}\r
+\r
+/**\r
+\r
+  Process the action request in user input.\r
+\r
+  @param Action                  The user input action request info.\r
+  @param DefaultId               The user input default Id info.\r
+\r
+  @retval EFI_SUCESSS            This function always return successfully for now.\r
+\r
+**/\r
+EFI_STATUS\r
+ProcessAction (\r
+  IN UINT32        Action,\r
+  IN UINT16        DefaultId\r
+  )\r
+{\r
+  //\r
+  // This is caused by use press ESC, and it should not combine with other action type.\r
+  //\r
+  if ((Action & BROWSER_ACTION_FORM_EXIT) == BROWSER_ACTION_FORM_EXIT) {\r
+    FindNextMenu (gCurrentSelection, FormLevel);\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Below is normal hotkey trigged action, these action maybe combine with each other.\r
+  //\r
+  if ((Action & BROWSER_ACTION_DISCARD) == BROWSER_ACTION_DISCARD) {\r
+    DiscardForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope);\r
+  }\r
+\r
+  if ((Action & BROWSER_ACTION_DEFAULT) == BROWSER_ACTION_DEFAULT) {\r
+    ExtractDefault (gCurrentSelection->FormSet, gCurrentSelection->Form, DefaultId, gBrowserSettingScope, GetDefaultForAll, NULL, FALSE, FALSE);\r
+    UpdateStatementStatus (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope);\r
+  }\r
+\r
+  if ((Action & BROWSER_ACTION_SUBMIT) == BROWSER_ACTION_SUBMIT) {\r
+    SubmitForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope);\r
+  }\r
+\r
+  if ((Action & BROWSER_ACTION_RESET) == BROWSER_ACTION_RESET) {\r
+    gResetRequiredFormLevel = TRUE;\r
+    gResetRequiredSystemLevel = TRUE;\r
+  }\r
+\r
+  if ((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 (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope);\r
+    if (gBrowserSettingScope == FormLevel || gBrowserSettingScope == FormSetLevel) {\r
+      FindNextMenu (gCurrentSelection, gBrowserSettingScope);\r
+    } else if (gBrowserSettingScope == SystemLevel) {\r
+      if (ExitHandlerFunction != NULL) {\r
+        ExitHandlerFunction ();\r
+      }\r
+      gCurrentSelection->Action = UI_ACTION_EXIT;\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Check whether the formset guid is in this Hii package list.\r
+\r
+  @param  HiiHandle              The HiiHandle for this HII package list.\r
+  @param  FormSetGuid            The formset guid for the request formset.\r
+\r
+  @retval TRUE                   Find the formset guid.\r
+  @retval FALSE                  Not found the formset guid.\r
+\r
+**/\r
+BOOLEAN\r
+GetFormsetGuidFromHiiHandle (\r
+  IN EFI_HII_HANDLE       HiiHandle,\r
+  IN EFI_GUID             *FormSetGuid\r
+  )\r
+{\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
+  BOOLEAN                      FindGuid;\r
+\r
+  BufferSize     = 0;\r
+  HiiPackageList = NULL;\r
+  FindGuid       = FALSE;\r
+\r
+  Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, HiiHandle, &BufferSize, HiiPackageList);\r
+  if (Status == EFI_BUFFER_TOO_SMALL) {\r
+    HiiPackageList = AllocatePool (BufferSize);\r
+    ASSERT (HiiPackageList != NULL);\r
+\r
+    Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, HiiHandle, &BufferSize, HiiPackageList);\r
+  }\r
+  if (EFI_ERROR (Status) || HiiPackageList == NULL) {\r
+    return FALSE;\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
+    Offset += PackageHeader.Length;\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
+          if (CompareGuid (FormSetGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))){\r
+            FindGuid = TRUE;\r
+            break;\r
+          }\r
+        }\r
+\r
+        Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;\r
+      }\r
+    }\r
+    if (FindGuid) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  FreePool (HiiPackageList);\r
+\r
+  return FindGuid;\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
+  @param  FormsetGuid            The formset guid for this formset.\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
+DevicePathToHiiHandle (\r
+  IN EFI_DEVICE_PATH_PROTOCOL   *DevicePath,\r
+  IN EFI_GUID                   *FormsetGuid\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  EFI_DEVICE_PATH_PROTOCOL    *TmpDevicePath;\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
+  HiiHandles = HiiGetHiiHandles (NULL);\r
+  if (HiiHandles == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  //\r
+  // Search Hii Handle by Driver Handle\r
+  //\r
+  HiiHandle = NULL;\r
+  for (Index = 0; HiiHandles[Index] != NULL; Index++) {\r
+    Status = mHiiDatabase->GetPackageListHandle (\r
+                             mHiiDatabase,\r
+                             HiiHandles[Index],\r
+                             &Handle\r
+                             );\r
+    if (!EFI_ERROR (Status) && (Handle == DriverHandle)) {\r
+      if (GetFormsetGuidFromHiiHandle(HiiHandles[Index], FormsetGuid)) {\r
+        HiiHandle = HiiHandles[Index];\r
+        break;\r
+      }\r
+\r
+      if (HiiHandle != NULL) {\r
+        break;\r
+      }\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
-  CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));\r
-\r
-  SecCol            = LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 3;\r
-  ThdCol            = LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) * 2 / 3;\r
-\r
-  StartColumnOfHelp = LocalScreen.LeftColumn + 2;\r
-  LeftColumnOfHelp  = LocalScreen.LeftColumn + 1;\r
-  RightColumnOfHelp = LocalScreen.RightColumn - 2;\r
-  TopRowOfHelp      = LocalScreen.BottomRow - 4;\r
-  BottomRowOfHelp   = LocalScreen.BottomRow - 3;\r
-\r
-  gST->ConOut->SetAttribute (gST->ConOut, KEYHELP_TEXT | KEYHELP_BACKGROUND);\r
-\r
-  Statement = MenuOption->ThisTag;\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
-    ClearLines (LeftColumnOfHelp, RightColumnOfHelp, TopRowOfHelp, BottomRowOfHelp, KEYHELP_TEXT | KEYHELP_BACKGROUND);\r
-\r
-    if (!Selected) {\r
-      if ((gClassOfVfr & FORMSET_CLASS_PLATFORM_SETUP) == FORMSET_CLASS_PLATFORM_SETUP) {\r
-        if (Selection->FormEditable) {\r
-          PrintStringAt (SecCol, TopRowOfHelp, gFunctionNineString);\r
-          PrintStringAt (ThdCol, TopRowOfHelp, gFunctionTenString);\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
+  EFI_HII_HANDLE               HiiHandle;\r
+  UINTN                        Index;\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
+    if (GetFormsetGuidFromHiiHandle(HiiHandles[Index], ComparingGuid)) {\r
+      HiiHandle = HiiHandles[Index];\r
+      break;\r
+    }\r
+\r
+    if (HiiHandle != NULL) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  FreePool (HiiHandles);\r
+\r
+  return HiiHandle;\r
+}\r
+\r
+/**\r
+  check how to process the changed data in current form or form set.\r
+\r
+  @param Selection       On input, Selection tell setup browser the information\r
+                         about the Selection, form and formset to be displayed.\r
+                         On output, Selection return the screen item that is selected\r
+                         by user.\r
+\r
+  @param Scope           Data save or discard scope, form or formset.\r
+\r
+  @retval                TRUE   Success process the changed data, will return to the parent form.\r
+  @retval                FALSE  Reject to process the changed data, will stay at  current form.\r
+**/\r
+BOOLEAN\r
+ProcessChangedData (\r
+  IN OUT UI_MENU_SELECTION       *Selection,\r
+  IN     BROWSER_SETTING_SCOPE   Scope\r
+  )\r
+{\r
+  BOOLEAN    RetValue;\r
+  EFI_STATUS Status;\r
+\r
+  RetValue = TRUE;\r
+  switch (mFormDisplay->ConfirmDataChange()) {\r
+    case BROWSER_ACTION_DISCARD:\r
+      DiscardForm (Selection->FormSet, Selection->Form, Scope);\r
+      break;\r
+\r
+    case BROWSER_ACTION_SUBMIT:\r
+      Status = SubmitForm (Selection->FormSet, Selection->Form, Scope);\r
+      if (EFI_ERROR (Status)) {\r
+        RetValue = FALSE;\r
+      }\r
+      break;\r
+\r
+    case BROWSER_ACTION_NONE:\r
+      RetValue = FALSE;\r
+      break;\r
+\r
+    default:\r
+      //\r
+      // if Invalid value return, process same as BROWSER_ACTION_NONE.\r
+      //\r
+      RetValue = FALSE;\r
+      break;\r
+  }\r
+\r
+  return RetValue;\r
+}\r
+\r
+/**\r
+  Find parent formset menu(the first menu which has different formset) for current menu.\r
+  If not find, just return to the first menu.\r
+\r
+  @param Selection    The selection info.\r
+\r
+**/\r
+VOID\r
+FindParentFormSet (\r
+  IN OUT   UI_MENU_SELECTION           *Selection\r
+  )\r
+{\r
+  FORM_ENTRY_INFO            *CurrentMenu;\r
+  FORM_ENTRY_INFO            *ParentMenu;\r
+\r
+  CurrentMenu = Selection->CurrentMenu;\r
+  ParentMenu  = UiFindParentMenu(CurrentMenu, FormSetLevel);\r
+\r
+  if (ParentMenu != NULL) {\r
+    CopyMem (&Selection->FormSetGuid, &ParentMenu->FormSetGuid, sizeof (EFI_GUID));\r
+    Selection->Handle = ParentMenu->HiiHandle;\r
+    Selection->FormId     = ParentMenu->FormId;\r
+    Selection->QuestionId = ParentMenu->QuestionId;\r
+  } else {\r
+    Selection->FormId     = CurrentMenu->FormId;\r
+    Selection->QuestionId = CurrentMenu->QuestionId;\r
+  }\r
+\r
+  Selection->Statement  = NULL;\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
+\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
+  )\r
+{\r
+  CHAR16                          *StringPtr;\r
+  EFI_DEVICE_PATH_PROTOCOL        *DevicePath;\r
+  FORM_BROWSER_FORM               *RefForm;\r
+  EFI_STATUS                      Status;\r
+  EFI_HII_HANDLE                  HiiHandle;\r
+\r
+  Status    = EFI_SUCCESS;\r
+  StringPtr = NULL;\r
+  HiiHandle = NULL;\r
+\r
+  //\r
+  // Prepare the device path check, get the device path info first.\r
+  //\r
+  if (Statement->HiiValue.Value.ref.DevicePath != 0) {\r
+    StringPtr = GetToken (Statement->HiiValue.Value.ref.DevicePath, Selection->FormSet->HiiHandle);\r
+  }\r
+\r
+  //\r
+  // Check whether the device path string is a valid string.\r
+  //\r
+  if (Statement->HiiValue.Value.ref.DevicePath != 0 && StringPtr != NULL && StringPtr[0] != L'\0') {\r
+    if (Selection->Form->ModalForm) {\r
+      return Status;\r
+    }\r
+\r
+    //\r
+    // Goto another Hii Package list\r
+    //\r
+    if (mPathFromText != NULL) {\r
+      DevicePath = mPathFromText->ConvertTextToDevicePath(StringPtr);\r
+      if (DevicePath != NULL) {\r
+        HiiHandle = DevicePathToHiiHandle (DevicePath, &Statement->HiiValue.Value.ref.FormSetGuid);\r
+        FreePool (DevicePath);\r
+      }\r
+      FreePool (StringPtr);\r
+    } else {\r
+      //\r
+      // Not found the EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL protocol.\r
+      //\r
+      PopupErrorMessage(BROWSER_PROTOCOL_NOT_FOUND, NULL, NULL, NULL);\r
+      FreePool (StringPtr);\r
+      return Status;\r
+    }\r
+\r
+    if (HiiHandle != Selection->Handle) {\r
+      //\r
+      // Goto another Formset, check for uncommitted data\r
+      //\r
+      if ((gBrowserSettingScope == FormLevel || gBrowserSettingScope == FormSetLevel) &&\r
+          IsNvUpdateRequiredForFormSet(Selection->FormSet)) {\r
+        if (!ProcessChangedData(Selection, FormSetLevel)) {\r
+          return EFI_SUCCESS;\r
+        }\r
+      }\r
+    }\r
+\r
+    Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
+    Selection->Handle = HiiHandle;\r
+    if (Selection->Handle == NULL) {\r
+      //\r
+      // If target Hii Handle not found, exit current formset.\r
+      //\r
+      FindParentFormSet(Selection);\r
+      return EFI_SUCCESS;\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 (!IsZeroGuid (&Statement->HiiValue.Value.ref.FormSetGuid)) {\r
+    if (Selection->Form->ModalForm) {\r
+      return Status;\r
+    }\r
+    if (!CompareGuid (&Statement->HiiValue.Value.ref.FormSetGuid, &Selection->FormSetGuid)) {\r
+      //\r
+      // Goto another Formset, check for uncommitted data\r
+      //\r
+      if ((gBrowserSettingScope == FormLevel || gBrowserSettingScope == FormSetLevel) &&\r
+         IsNvUpdateRequiredForFormSet(Selection->FormSet)) {\r
+        if (!ProcessChangedData(Selection, FormSetLevel)) {\r
+          return EFI_SUCCESS;\r
+        }\r
+      }\r
+    }\r
+\r
+    Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
+    Selection->Handle = FormSetGuidToHiiHandle(&Statement->HiiValue.Value.ref.FormSetGuid);\r
+    if (Selection->Handle == NULL) {\r
+      //\r
+      // If target Hii Handle not found, exit current formset.\r
+      //\r
+      FindParentFormSet(Selection);\r
+      return EFI_SUCCESS;\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
+    // Goto another Form, check for uncommitted data\r
+    //\r
+    if (Statement->HiiValue.Value.ref.FormId != Selection->FormId) {\r
+      if ((gBrowserSettingScope == FormLevel && IsNvUpdateRequiredForForm(Selection->Form))) {\r
+        if (!ProcessChangedData (Selection, FormLevel)) {\r
+          return EFI_SUCCESS;\r
+        }\r
+      }\r
+    }\r
+\r
+    RefForm = IdToForm (Selection->FormSet, Statement->HiiValue.Value.ref.FormId);\r
+    if ((RefForm != NULL) && (RefForm->SuppressExpression != NULL)) {\r
+      if (EvaluateExpressionList(RefForm->SuppressExpression, TRUE, Selection->FormSet, RefForm) != ExpressFalse) {\r
+        //\r
+        // Form is suppressed.\r
+        //\r
+        PopupErrorMessage(BROWSER_FORM_SUPPRESS, NULL, NULL, NULL);\r
+        return EFI_SUCCESS;\r
+      }\r
+    }\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
+    Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Process Question Config.\r
+\r
+  @param  Selection              The UI menu selection.\r
+  @param  Question               The Question to be peocessed.\r
+\r
+  @retval EFI_SUCCESS            Question Config process success.\r
+  @retval Other                  Question Config process fail.\r
+\r
+**/\r
+EFI_STATUS\r
+ProcessQuestionConfig (\r
+  IN  UI_MENU_SELECTION       *Selection,\r
+  IN  FORM_BROWSER_STATEMENT  *Question\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  CHAR16                          *ConfigResp;\r
+  CHAR16                          *Progress;\r
+\r
+  if (Question->QuestionConfig == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Get <ConfigResp>\r
+  //\r
+  ConfigResp = GetToken (Question->QuestionConfig, Selection->FormSet->HiiHandle);\r
+  if (ConfigResp == NULL) {\r
+    return EFI_NOT_FOUND;\r
+  } else if (ConfigResp[0] == L'\0') {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Send config to Configuration Driver\r
+  //\r
+  Status = mHiiConfigRouting->RouteConfig (\r
+                           mHiiConfigRouting,\r
+                           ConfigResp,\r
+                           &Progress\r
+                           );\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+\r
+  Process the user input data.\r
+\r
+  @param UserInput               The user input data.\r
+\r
+  @retval EFI_SUCESSS            This function always return successfully for now.\r
+\r
+**/\r
+EFI_STATUS\r
+ProcessUserInput (\r
+  IN USER_INPUT               *UserInput\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  FORM_BROWSER_STATEMENT        *Statement;\r
+\r
+  Status    = EFI_SUCCESS;\r
+  Statement = NULL;\r
+\r
+  //\r
+  // When Exit from FormDisplay function, one of the below two cases must be true.\r
+  //\r
+  ASSERT (UserInput->Action != 0 || UserInput->SelectedStatement != NULL);\r
+\r
+  //\r
+  // Remove the last highligh question id, this id will update when show next form.\r
+  //\r
+  gCurrentSelection->QuestionId = 0;\r
+  if (UserInput->SelectedStatement != NULL){\r
+    Statement = GetBrowserStatement(UserInput->SelectedStatement);\r
+    ASSERT (Statement != NULL);\r
+\r
+    //\r
+    // This question is the current user select one,record it and later\r
+    // show it as the highlight question.\r
+    //\r
+    gCurrentSelection->CurrentMenu->QuestionId = Statement->QuestionId;\r
+    //\r
+    // For statement like text, actio, it not has question id.\r
+    // So use FakeQuestionId to save the question.\r
+    //\r
+    if (gCurrentSelection->CurrentMenu->QuestionId == 0) {\r
+      mCurFakeQestId = Statement->FakeQuestionId;\r
+    } else {\r
+      mCurFakeQestId = 0;\r
+    }\r
+  }\r
+\r
+  //\r
+  // First process the Action field in USER_INPUT.\r
+  //\r
+  if (UserInput->Action != 0) {\r
+    Status = ProcessAction (UserInput->Action, UserInput->DefaultId);\r
+    gCurrentSelection->Statement = NULL;\r
+  } else {\r
+    ASSERT (Statement != NULL);\r
+    gCurrentSelection->Statement = Statement;\r
+    switch (Statement->Operand) {\r
+    case EFI_IFR_REF_OP:\r
+      Status = ProcessGotoOpCode(Statement, gCurrentSelection);\r
+      break;\r
+\r
+    case EFI_IFR_ACTION_OP:\r
+      //\r
+      // Process the Config string <ConfigResp>\r
+      //\r
+      Status = ProcessQuestionConfig (gCurrentSelection, Statement);\r
+      break;\r
+\r
+    case EFI_IFR_RESET_BUTTON_OP:\r
+      //\r
+      // Reset Question to default value specified by DefaultId\r
+      //\r
+      Status = ExtractDefault (gCurrentSelection->FormSet, NULL, Statement->DefaultId, FormSetLevel, GetDefaultForAll, NULL, FALSE, FALSE);\r
+      UpdateStatementStatus (gCurrentSelection->FormSet, NULL, FormSetLevel);\r
+      break;\r
+\r
+    default:\r
+      switch (Statement->Operand) {\r
+      case EFI_IFR_STRING_OP:\r
+        DeleteString(Statement->HiiValue.Value.string, gCurrentSelection->FormSet->HiiHandle);\r
+        Statement->HiiValue.Value.string = UserInput->InputValue.Value.string;\r
+        CopyMem (Statement->BufferValue, UserInput->InputValue.Buffer, (UINTN) UserInput->InputValue.BufferLen);\r
+        FreePool (UserInput->InputValue.Buffer);\r
+        break;\r
+\r
+      case EFI_IFR_PASSWORD_OP:\r
+        if (UserInput->InputValue.Buffer == NULL) {\r
+          //\r
+          // User not input new password, just return.\r
+          //\r
+          break;\r
+        }\r
+\r
+        DeleteString(Statement->HiiValue.Value.string, gCurrentSelection->FormSet->HiiHandle);\r
+        Statement->HiiValue.Value.string = UserInput->InputValue.Value.string;\r
+        CopyMem (Statement->BufferValue, UserInput->InputValue.Buffer, (UINTN) UserInput->InputValue.BufferLen);\r
+        ZeroMem (UserInput->InputValue.Buffer, (UINTN) UserInput->InputValue.BufferLen);\r
+        FreePool (UserInput->InputValue.Buffer);\r
+        //\r
+        // Two password match, send it to Configuration Driver\r
+        //\r
+        if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {\r
+          PasswordCheck (NULL, UserInput->SelectedStatement, (CHAR16 *) Statement->BufferValue);\r
+          //\r
+          // Clean the value after saved it.\r
+          //\r
+          ZeroMem (Statement->BufferValue, (UINTN) UserInput->InputValue.BufferLen);\r
+          HiiSetString (gCurrentSelection->FormSet->HiiHandle, Statement->HiiValue.Value.string, (CHAR16*)Statement->BufferValue, NULL);\r
+        } else {\r
+          SetQuestionValue (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithHiiDriver);\r
+        }\r
+        break;\r
+\r
+      case EFI_IFR_ORDERED_LIST_OP:\r
+        CopyMem (Statement->BufferValue, UserInput->InputValue.Buffer, UserInput->InputValue.BufferLen);\r
+        break;\r
+\r
+      default:\r
+        CopyMem (&Statement->HiiValue, &UserInput->InputValue, sizeof (EFI_HII_VALUE));\r
+        break;\r
+      }\r
+      break;\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+\r
+  Display form and wait for user to select one menu option, then return it.\r
+\r
+  @retval EFI_SUCESSS            This function always return successfully for now.\r
+\r
+**/\r
+EFI_STATUS\r
+DisplayForm (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS               Status;\r
+  USER_INPUT               UserInput;\r
+  FORM_ENTRY_INFO          *CurrentMenu;\r
+\r
+  ZeroMem (&UserInput, sizeof (USER_INPUT));\r
+\r
+  //\r
+  // Update the menu history data.\r
+  //\r
+  CurrentMenu = UiFindMenuList (gCurrentSelection->Handle, &gCurrentSelection->FormSetGuid, gCurrentSelection->FormId);\r
+  if (CurrentMenu == NULL) {\r
+    //\r
+    // Current menu not found, add it to the menu tree\r
+    //\r
+    CurrentMenu = UiAddMenuList (gCurrentSelection->Handle, &gCurrentSelection->FormSetGuid,\r
+                                 gCurrentSelection->FormId, gCurrentSelection->QuestionId);\r
+    ASSERT (CurrentMenu != NULL);\r
+  }\r
+\r
+  //\r
+  // Back up the form view history data for this form.\r
+  //\r
+  UiCopyMenuList(&gCurrentSelection->Form->FormViewListHead, &mPrivateData.FormBrowserEx2.FormViewHistoryHead);\r
+\r
+  gCurrentSelection->CurrentMenu = CurrentMenu;\r
+\r
+  if (gCurrentSelection->QuestionId == 0) {\r
+    //\r
+    // Highlight not specified, fetch it from cached menu\r
+    //\r
+    gCurrentSelection->QuestionId = CurrentMenu->QuestionId;\r
+  }\r
+\r
+  Status = EvaluateFormExpressions (gCurrentSelection->FormSet, gCurrentSelection->Form);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  UpdateDisplayFormData ();\r
+\r
+  ASSERT (gDisplayFormData.BrowserStatus == BROWSER_SUCCESS);\r
+  Status = mFormDisplay->FormDisplay (&gDisplayFormData, &UserInput);\r
+  if (EFI_ERROR (Status)) {\r
+    FreeDisplayFormData();\r
+    return Status;\r
+  }\r
+\r
+  Status = ProcessUserInput (&UserInput);\r
+  FreeDisplayFormData();\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Functions which are registered to receive notification of\r
+  database events have this prototype. The actual event is encoded\r
+  in NotifyType. The following table describes how PackageType,\r
+  PackageGuid, Handle, and Package are used for each of the\r
+  notification types.\r
+\r
+  @param PackageType  Package type of the notification.\r
+\r
+  @param PackageGuid  If PackageType is\r
+                      EFI_HII_PACKAGE_TYPE_GUID, then this is\r
+                      the pointer to the GUID from the Guid\r
+                      field of EFI_HII_PACKAGE_GUID_HEADER.\r
+                      Otherwise, it must be NULL.\r
+\r
+  @param Package  Points to the package referred to by the\r
+                  notification Handle The handle of the package\r
+                  list which contains the specified package.\r
+\r
+  @param Handle       The HII handle.\r
+\r
+  @param NotifyType   The type of change concerning the\r
+                      database. See\r
+                      EFI_HII_DATABASE_NOTIFY_TYPE.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FormUpdateNotify (\r
+  IN UINT8                              PackageType,\r
+  IN CONST EFI_GUID                     *PackageGuid,\r
+  IN CONST EFI_HII_PACKAGE_HEADER       *Package,\r
+  IN EFI_HII_HANDLE                     Handle,\r
+  IN EFI_HII_DATABASE_NOTIFY_TYPE       NotifyType\r
+  )\r
+{\r
+  mHiiPackageListUpdated = TRUE;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Update the NV flag info for this form set.\r
+\r
+  @param  FormSet                FormSet data structure.\r
+\r
+**/\r
+BOOLEAN\r
+IsNvUpdateRequiredForFormSet (\r
+  IN FORM_BROWSER_FORMSET  *FormSet\r
+  )\r
+{\r
+  LIST_ENTRY              *Link;\r
+  FORM_BROWSER_FORM       *Form;\r
+  BOOLEAN                 RetVal;\r
+\r
+  //\r
+  // Not finished question initialization, return FALSE.\r
+  //\r
+  if (!FormSet->QuestionInited) {\r
+    return FALSE;\r
+  }\r
+\r
+  RetVal = FALSE;\r
+\r
+  Link = GetFirstNode (&FormSet->FormListHead);\r
+  while (!IsNull (&FormSet->FormListHead, Link)) {\r
+    Form = FORM_BROWSER_FORM_FROM_LINK (Link);\r
+\r
+    RetVal = IsNvUpdateRequiredForForm(Form);\r
+    if (RetVal) {\r
+      break;\r
+    }\r
+\r
+    Link = GetNextNode (&FormSet->FormListHead, Link);\r
+  }\r
+\r
+  return RetVal;\r
+}\r
+\r
+/**\r
+  Update the NvUpdateRequired flag for a form.\r
+\r
+  @param  Form                Form data structure.\r
+\r
+**/\r
+BOOLEAN\r
+IsNvUpdateRequiredForForm (\r
+  IN FORM_BROWSER_FORM    *Form\r
+  )\r
+{\r
+  LIST_ENTRY              *Link;\r
+  FORM_BROWSER_STATEMENT  *Statement;\r
+\r
+  Link = GetFirstNode (&Form->StatementListHead);\r
+  while (!IsNull (&Form->StatementListHead, Link)) {\r
+    Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);\r
+\r
+    if (Statement->ValueChanged) {\r
+      return TRUE;\r
+    }\r
+\r
+    Link = GetNextNode (&Form->StatementListHead, Link);\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  Find menu which will show next time.\r
+\r
+  @param Selection       On input, Selection tell setup browser the information\r
+                         about the Selection, form and formset to be displayed.\r
+                         On output, Selection return the screen item that is selected\r
+                         by user.\r
+  @param SettingLevel    Input Settting level, if it is FormLevel, just exit current form.\r
+                         else, we need to exit current formset.\r
+\r
+  @retval TRUE           Exit current form.\r
+  @retval FALSE          User press ESC and keep in current form.\r
+**/\r
+BOOLEAN\r
+FindNextMenu (\r
+  IN OUT UI_MENU_SELECTION        *Selection,\r
+  IN     BROWSER_SETTING_SCOPE     SettingLevel\r
+  )\r
+{\r
+  FORM_ENTRY_INFO            *CurrentMenu;\r
+  FORM_ENTRY_INFO            *ParentMenu;\r
+  BROWSER_SETTING_SCOPE      Scope;\r
+\r
+  CurrentMenu = Selection->CurrentMenu;\r
+  Scope       = FormSetLevel;\r
+\r
+  ParentMenu = UiFindParentMenu(CurrentMenu, SettingLevel);\r
+  while (ParentMenu != NULL && !ValidateHiiHandle(ParentMenu->HiiHandle)) {\r
+    ParentMenu = UiFindParentMenu(ParentMenu, SettingLevel);\r
+  }\r
+\r
+  if (ParentMenu != NULL) {\r
+    if (CompareGuid (&CurrentMenu->FormSetGuid, &ParentMenu->FormSetGuid)) {\r
+      Scope = FormLevel;\r
+    } else {\r
+      Scope = FormSetLevel;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Form Level Check whether the data is changed.\r
+  //\r
+  if ((gBrowserSettingScope == FormLevel && IsNvUpdateRequiredForForm (Selection->Form)) ||\r
+      (gBrowserSettingScope == FormSetLevel && IsNvUpdateRequiredForFormSet(Selection->FormSet) && Scope == FormSetLevel)) {\r
+    if (!ProcessChangedData(Selection, gBrowserSettingScope)) {\r
+      return FALSE;\r
+    }\r
+  }\r
+\r
+  if (ParentMenu != NULL) {\r
+    //\r
+    // ParentMenu is found. Then, go to it.\r
+    //\r
+    if (Scope == FormLevel) {\r
+      Selection->Action = UI_ACTION_REFRESH_FORM;\r
+    } else {\r
+      Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
+      CopyMem (&Selection->FormSetGuid, &ParentMenu->FormSetGuid, sizeof (EFI_GUID));\r
+      Selection->Handle = ParentMenu->HiiHandle;\r
+    }\r
+\r
+    Selection->Statement = NULL;\r
+\r
+    Selection->FormId = ParentMenu->FormId;\r
+    Selection->QuestionId = ParentMenu->QuestionId;\r
+\r
+    //\r
+    // Clear highlight record for this menu\r
+    //\r
+    CurrentMenu->QuestionId = 0;\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // Current in root page, exit the SendForm\r
+  //\r
+  Selection->Action = UI_ACTION_EXIT;\r
+\r
+  return TRUE;\r
+}\r
+\r
+/**\r
+  Reconnect the controller.\r
+\r
+  @param DriverHandle          The controller handle which need to be reconnect.\r
+\r
+  @retval   TRUE     do the reconnect behavior success.\r
+  @retval   FALSE    do the reconnect behavior failed.\r
+\r
+**/\r
+BOOLEAN\r
+ReconnectController (\r
+  IN EFI_HANDLE   DriverHandle\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+\r
+  Status = gBS->DisconnectController(DriverHandle, NULL, NULL);\r
+  if (!EFI_ERROR (Status)) {\r
+    Status = gBS->ConnectController(DriverHandle, NULL, NULL, TRUE);\r
+  }\r
+\r
+  return Status == EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Call the call back function for the question and process the return action.\r
+\r
+  @param Selection             On input, Selection tell setup browser the information\r
+                               about the Selection, form and formset to be displayed.\r
+                               On output, Selection return the screen item that is selected\r
+                               by user.\r
+  @param FormSet               The formset this question belong to.\r
+  @param Form                  The form this question belong to.\r
+  @param Question              The Question which need to call.\r
+  @param Action                The action request.\r
+  @param SkipSaveOrDiscard     Whether skip save or discard action.\r
+\r
+  @retval EFI_SUCCESS          The call back function executes successfully.\r
+  @return Other value if the call back function failed to execute.\r
+**/\r
+EFI_STATUS\r
+ProcessCallBackFunction (\r
+  IN OUT UI_MENU_SELECTION               *Selection,\r
+  IN     FORM_BROWSER_FORMSET            *FormSet,\r
+  IN     FORM_BROWSER_FORM               *Form,\r
+  IN     FORM_BROWSER_STATEMENT          *Question,\r
+  IN     EFI_BROWSER_ACTION              Action,\r
+  IN     BOOLEAN                         SkipSaveOrDiscard\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  EFI_STATUS                      InternalStatus;\r
+  EFI_BROWSER_ACTION_REQUEST      ActionRequest;\r
+  EFI_HII_CONFIG_ACCESS_PROTOCOL  *ConfigAccess;\r
+  EFI_HII_VALUE                   *HiiValue;\r
+  EFI_IFR_TYPE_VALUE              *TypeValue;\r
+  FORM_BROWSER_STATEMENT          *Statement;\r
+  BOOLEAN                         SubmitFormIsRequired;\r
+  BOOLEAN                         DiscardFormIsRequired;\r
+  BOOLEAN                         NeedExit;\r
+  LIST_ENTRY                      *Link;\r
+  BROWSER_SETTING_SCOPE           SettingLevel;\r
+  EFI_IFR_TYPE_VALUE              BackUpValue;\r
+  UINT8                           *BackUpBuffer;\r
+  CHAR16                          *NewString;\r
+\r
+  ConfigAccess = FormSet->ConfigAccess;\r
+  SubmitFormIsRequired  = FALSE;\r
+  SettingLevel          = FormSetLevel;\r
+  DiscardFormIsRequired = FALSE;\r
+  NeedExit              = FALSE;\r
+  Status                = EFI_SUCCESS;\r
+  ActionRequest         = EFI_BROWSER_ACTION_REQUEST_NONE;\r
+  BackUpBuffer          = NULL;\r
+\r
+  if (ConfigAccess == NULL) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  Link = GetFirstNode (&Form->StatementListHead);\r
+  while (!IsNull (&Form->StatementListHead, Link)) {\r
+    Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);\r
+    Link = GetNextNode (&Form->StatementListHead, Link);\r
+\r
+    //\r
+    // if Question != NULL, only process the question. Else, process all question in this form.\r
+    //\r
+    if ((Question != NULL) && (Statement != Question)) {\r
+      continue;\r
+    }\r
+\r
+    if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != EFI_IFR_FLAG_CALLBACK) {\r
+      continue;\r
+    }\r
+\r
+    //\r
+    // Check whether Statement is disabled.\r
+    //\r
+    if (Statement->Expression != NULL) {\r
+      if (EvaluateExpressionList(Statement->Expression, TRUE, FormSet, Form) == ExpressDisable) {\r
+        continue;\r
+      }\r
+    }\r
+\r
+    HiiValue = &Statement->HiiValue;\r
+    TypeValue = &HiiValue->Value;\r
+    if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {\r
+      //\r
+      // For OrderedList, passing in the value buffer to Callback()\r
+      //\r
+      TypeValue = (EFI_IFR_TYPE_VALUE *) Statement->BufferValue;\r
+    }\r
+\r
+    //\r
+    // If EFI_BROWSER_ACTION_CHANGING type, back up the new question value.\r
+    //\r
+    if (Action == EFI_BROWSER_ACTION_CHANGING) {\r
+      if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {\r
+        BackUpBuffer = AllocateCopyPool(Statement->StorageWidth, Statement->BufferValue);\r
+        ASSERT (BackUpBuffer != NULL);\r
+      } else {\r
+        CopyMem (&BackUpValue, &HiiValue->Value, sizeof (EFI_IFR_TYPE_VALUE));\r
+      }\r
+    }\r
+\r
+    ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;\r
+    Status = ConfigAccess->Callback (\r
+                             ConfigAccess,\r
+                             Action,\r
+                             Statement->QuestionId,\r
+                             HiiValue->Type,\r
+                             TypeValue,\r
+                             &ActionRequest\r
+                             );\r
+    if (!EFI_ERROR (Status)) {\r
+      //\r
+      // Need to sync the value between Statement->HiiValue->Value and Statement->BufferValue\r
+      //\r
+      if (HiiValue->Type == EFI_IFR_TYPE_STRING) {\r
+        NewString = GetToken (Statement->HiiValue.Value.string, FormSet->HiiHandle);\r
+        ASSERT (NewString != NULL);\r
+\r
+        ASSERT (StrLen (NewString) * sizeof (CHAR16) <= Statement->StorageWidth);\r
+        if (StrLen (NewString) * sizeof (CHAR16) <= Statement->StorageWidth) {\r
+          ZeroMem (Statement->BufferValue, Statement->StorageWidth);\r
+          CopyMem (Statement->BufferValue, NewString, StrSize (NewString));\r
+        } else {\r
+          CopyMem (Statement->BufferValue, NewString, Statement->StorageWidth);\r
+        }\r
+        FreePool (NewString);\r
+      }\r
+\r
+      //\r
+      // Only for EFI_BROWSER_ACTION_CHANGED need to handle this ActionRequest.\r
+      //\r
+      switch (Action) {\r
+      case EFI_BROWSER_ACTION_CHANGED:\r
+        switch (ActionRequest) {\r
+        case EFI_BROWSER_ACTION_REQUEST_RESET:\r
+          DiscardFormIsRequired = TRUE;\r
+          gResetRequiredFormLevel = TRUE;\r
+          gResetRequiredSystemLevel = TRUE;\r
+          NeedExit              = TRUE;\r
+          break;\r
+\r
+        case EFI_BROWSER_ACTION_REQUEST_SUBMIT:\r
+          SubmitFormIsRequired = TRUE;\r
+          NeedExit              = TRUE;\r
+          break;\r
+\r
+        case EFI_BROWSER_ACTION_REQUEST_EXIT:\r
+          DiscardFormIsRequired = TRUE;\r
+          NeedExit              = TRUE;\r
+          break;\r
+\r
+        case EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT:\r
+          SubmitFormIsRequired  = TRUE;\r
+          SettingLevel          = FormLevel;\r
+          NeedExit              = TRUE;\r
+          break;\r
+\r
+        case EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT:\r
+          DiscardFormIsRequired = TRUE;\r
+          SettingLevel          = FormLevel;\r
+          NeedExit              = TRUE;\r
+          break;\r
+\r
+        case EFI_BROWSER_ACTION_REQUEST_FORM_APPLY:\r
+          SubmitFormIsRequired  = TRUE;\r
+          SettingLevel          = FormLevel;\r
+          break;\r
+\r
+        case EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD:\r
+          DiscardFormIsRequired = TRUE;\r
+          SettingLevel          = FormLevel;\r
+          break;\r
+\r
+        case EFI_BROWSER_ACTION_REQUEST_RECONNECT:\r
+          gCallbackReconnect    = TRUE;\r
+          break;\r
+\r
+        default:\r
+          break;\r
+        }\r
+        break;\r
+\r
+      case EFI_BROWSER_ACTION_CHANGING:\r
+        //\r
+        // Do the question validation.\r
+        //\r
+        Status = ValueChangedValidation (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement);\r
+        if (!EFI_ERROR (Status)) {\r
+          //\r
+          //check whether the question value  changed compared with edit buffer before updating edit buffer\r
+          // if changed, set the ValueChanged flag to TRUE,in order to trig the CHANGED callback function\r
+          //\r
+          IsQuestionValueChanged(gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithEditBuffer);\r
+          //\r
+          // According the spec, return value from call back of "changing" and\r
+          // "retrieve" should update to the question's temp buffer.\r
+          //\r
+          SetQuestionValue(FormSet, Form, Statement, GetSetValueWithEditBuffer);\r
         }\r
-        PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString);\r
-      }\r
+        break;\r
 \r
-      if ((Statement->Operand == EFI_IFR_DATE_OP) ||\r
-          (Statement->Operand == EFI_IFR_TIME_OP)) {\r
-        PrintAt (\r
-          StartColumnOfHelp,\r
-          BottomRowOfHelp,\r
-          L"%c%c%c%c%s",\r
-          ARROW_UP,\r
-          ARROW_DOWN,\r
-          ARROW_RIGHT,\r
-          ARROW_LEFT,\r
-          gMoveHighlight\r
-          );\r
-        PrintStringAt (SecCol, BottomRowOfHelp, gAdjustNumber);\r
-      } else {\r
-        PrintAt (StartColumnOfHelp, BottomRowOfHelp, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight);\r
-        if (Statement->Operand == EFI_IFR_NUMERIC_OP && Statement->Step != 0) {\r
-          PrintStringAt (SecCol, BottomRowOfHelp, gAdjustNumber);\r
+      case EFI_BROWSER_ACTION_RETRIEVE:\r
+        //\r
+        // According the spec, return value from call back of "changing" and\r
+        // "retrieve" should update to the question's temp buffer.\r
+        //\r
+        SetQuestionValue(FormSet, Form, Statement, GetSetValueWithEditBuffer);\r
+        break;\r
+\r
+      default:\r
+        break;\r
+      }\r
+    } else {\r
+      //\r
+      // If the callback returns EFI_UNSUPPORTED for EFI_BROWSER_ACTION_CHANGING,\r
+      // then the browser will use the value passed to Callback() and ignore the\r
+      // value returned by Callback().\r
+      //\r
+      if (Action  == EFI_BROWSER_ACTION_CHANGING && Status == EFI_UNSUPPORTED) {\r
+        if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {\r
+          CopyMem (Statement->BufferValue, BackUpBuffer, Statement->StorageWidth);\r
         } else {\r
-          PrintStringAt (SecCol, BottomRowOfHelp, gEnterString);\r
+          CopyMem (&HiiValue->Value, &BackUpValue, sizeof (EFI_IFR_TYPE_VALUE));\r
+        }\r
+\r
+        //\r
+        // Do the question validation.\r
+        //\r
+        InternalStatus = ValueChangedValidation (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement);\r
+        if (!EFI_ERROR (InternalStatus)) {\r
+          //\r
+          //check whether the question value  changed compared with edit buffer before updating edit buffer\r
+          // if changed, set the ValueChanged flag to TRUE,in order to trig the CHANGED callback function\r
+          //\r
+          IsQuestionValueChanged(gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithEditBuffer);\r
+          SetQuestionValue(FormSet, Form, Statement, GetSetValueWithEditBuffer);\r
         }\r
       }\r
-    } else {\r
-      PrintStringAt (SecCol, BottomRowOfHelp, gEnterCommitString);\r
 \r
       //\r
-      // If it is a selected numeric with manual input, display different message\r
+      // According the spec, return fail from call back of "changing" and\r
+      // "retrieve", should restore the question's value.\r
       //\r
-      if ((Statement->Operand == EFI_IFR_NUMERIC_OP) && (Statement->Step == 0)) {\r
-        PrintStringAt (\r
-          SecCol,\r
-          TopRowOfHelp,\r
-          ((Statement->Flags & EFI_IFR_DISPLAY_UINT_HEX) == EFI_IFR_DISPLAY_UINT_HEX) ? gHexNumericInput : gDecNumericInput\r
-          );\r
-      } else if (Statement->Operand != EFI_IFR_ORDERED_LIST_OP) {\r
-        PrintAt (StartColumnOfHelp, BottomRowOfHelp, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight);\r
+      if (Action == EFI_BROWSER_ACTION_CHANGING && Status != EFI_UNSUPPORTED) {\r
+        if (Statement->Storage != NULL) {\r
+          GetQuestionValue(FormSet, Form, Statement, GetSetValueWithEditBuffer);\r
+        } else if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {\r
+          ProcessCallBackFunction (Selection, FormSet, Form, Question, EFI_BROWSER_ACTION_RETRIEVE, FALSE);\r
+        }\r
       }\r
 \r
-      if (Statement->Operand == EFI_IFR_ORDERED_LIST_OP) {\r
-        PrintStringAt (StartColumnOfHelp, TopRowOfHelp, gPlusString);\r
-        PrintStringAt (ThdCol, TopRowOfHelp, gMinusString);\r
+      if (Action == EFI_BROWSER_ACTION_RETRIEVE) {\r
+        GetQuestionValue(FormSet, Form, Statement, GetSetValueWithEditBuffer);\r
       }\r
 \r
-      PrintStringAt (ThdCol, BottomRowOfHelp, gEnterEscapeString);\r
-    }\r
-    break;\r
-\r
-  case EFI_IFR_CHECKBOX_OP:\r
-    ClearLines (LeftColumnOfHelp, RightColumnOfHelp, TopRowOfHelp, BottomRowOfHelp, KEYHELP_TEXT | KEYHELP_BACKGROUND);\r
-\r
-    if ((gClassOfVfr & FORMSET_CLASS_PLATFORM_SETUP) == FORMSET_CLASS_PLATFORM_SETUP) {\r
-      if (Selection->FormEditable) {\r
-        PrintStringAt (SecCol, TopRowOfHelp, gFunctionNineString);\r
-        PrintStringAt (ThdCol, TopRowOfHelp, gFunctionTenString);\r
+      if (Status == EFI_UNSUPPORTED) {\r
+        //\r
+        // If return EFI_UNSUPPORTED, also consider Hii driver suceess deal with it.\r
+        //\r
+        Status = EFI_SUCCESS;\r
       }\r
-      PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString);\r
     }\r
 \r
-    PrintAt (StartColumnOfHelp, BottomRowOfHelp, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight);\r
-    PrintStringAt (SecCol, BottomRowOfHelp, gToggleCheckBox);\r
-    break;\r
+    if (BackUpBuffer != NULL) {\r
+      FreePool (BackUpBuffer);\r
+    }\r
 \r
-  case EFI_IFR_REF_OP:\r
-  case EFI_IFR_PASSWORD_OP:\r
-  case EFI_IFR_STRING_OP:\r
-  case EFI_IFR_TEXT_OP:\r
-  case EFI_IFR_ACTION_OP:\r
-  case EFI_IFR_RESET_BUTTON_OP:\r
-    ClearLines (LeftColumnOfHelp, RightColumnOfHelp, TopRowOfHelp, BottomRowOfHelp, KEYHELP_TEXT | KEYHELP_BACKGROUND);\r
-\r
-    if (!Selected) {\r
-      if ((gClassOfVfr & FORMSET_CLASS_PLATFORM_SETUP) == FORMSET_CLASS_PLATFORM_SETUP) {\r
-        if (Selection->FormEditable) {\r
-          PrintStringAt (SecCol, TopRowOfHelp, gFunctionNineString);\r
-          PrintStringAt (ThdCol, TopRowOfHelp, gFunctionTenString);\r
-        }\r
-        PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString);\r
-      }\r
+    //\r
+    // If Question != NULL, means just process one question\r
+    // and if code reach here means this question has finished\r
+    // processing, so just break.\r
+    //\r
+    if (Question != NULL) {\r
+      break;\r
+    }\r
+  }\r
 \r
-      PrintAt (StartColumnOfHelp, BottomRowOfHelp, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight);\r
-      if (Statement->Operand != EFI_IFR_TEXT_OP) {\r
-        PrintStringAt (SecCol, BottomRowOfHelp, gEnterString);\r
+  if (gCallbackReconnect && (EFI_BROWSER_ACTION_CHANGED == Action)) {\r
+    //\r
+    // Confirm changes with user first.\r
+    //\r
+    if (IsNvUpdateRequiredForFormSet(FormSet)) {\r
+      if (BROWSER_ACTION_DISCARD == PopupErrorMessage(BROWSER_RECONNECT_SAVE_CHANGES, NULL, NULL, NULL)) {\r
+        gCallbackReconnect = FALSE;\r
+        DiscardFormIsRequired = TRUE;\r
+      } else {\r
+        SubmitFormIsRequired = TRUE;\r
       }\r
     } else {\r
-      if (Statement->Operand != EFI_IFR_REF_OP) {\r
-        PrintStringAt (\r
-          (LocalScreen.RightColumn - GetStringWidth (gEnterCommitString) / 2) / 2,\r
-          BottomRowOfHelp,\r
-          gEnterCommitString\r
-          );\r
-        PrintStringAt (ThdCol, BottomRowOfHelp, gEnterEscapeString);\r
-      }\r
+      PopupErrorMessage(BROWSER_RECONNECT_REQUIRED, NULL, NULL, NULL);\r
     }\r
-    break;\r
 \r
-  default:\r
-    break;\r
+    //\r
+    // Exit current formset before do the reconnect.\r
+    //\r
+    NeedExit = TRUE;\r
+    SettingLevel = FormSetLevel;\r
   }\r
-}\r
 \r
-/**\r
-  Functions which are registered to receive notification of\r
-  database events have this prototype. The actual event is encoded\r
-  in NotifyType. The following table describes how PackageType,\r
-  PackageGuid, Handle, and Package are used for each of the\r
-  notification types.\r
+  if (SubmitFormIsRequired && !SkipSaveOrDiscard) {\r
+    SubmitForm (FormSet, Form, SettingLevel);\r
+  }\r
 \r
-  @param PackageType  Package type of the notification.\r
+  if (DiscardFormIsRequired && !SkipSaveOrDiscard) {\r
+    DiscardForm (FormSet, Form, SettingLevel);\r
+  }\r
 \r
-  @param PackageGuid  If PackageType is\r
-                      EFI_HII_PACKAGE_TYPE_GUID, then this is\r
-                      the pointer to the GUID from the Guid\r
-                      field of EFI_HII_PACKAGE_GUID_HEADER.\r
-                      Otherwise, it must be NULL.\r
+  if (NeedExit) {\r
+    FindNextMenu (Selection, SettingLevel);\r
+  }\r
 \r
-  @param Package  Points to the package referred to by the\r
-                  notification Handle The handle of the package\r
-                  list which contains the specified package.\r
+  return Status;\r
+}\r
 \r
-  @param Handle       The HII handle.\r
+/**\r
+  Call the retrieve type call back function for one question to get the initialize data.\r
 \r
-  @param NotifyType   The type of change concerning the\r
-                      database. See\r
-                      EFI_HII_DATABASE_NOTIFY_TYPE.\r
+  This function only used when in the initialize stage, because in this stage, the\r
+  Selection->Form is not ready. For other case, use the ProcessCallBackFunction instead.\r
 \r
+  @param ConfigAccess          The config access protocol produced by the hii driver.\r
+  @param Statement             The Question which need to call.\r
+  @param FormSet               The formset this question belong to.\r
+\r
+  @retval EFI_SUCCESS          The call back function executes successfully.\r
+  @return Other value if the call back function failed to execute.\r
 **/\r
 EFI_STATUS\r
-EFIAPI\r
-FormUpdateNotify (\r
-  IN UINT8                              PackageType,\r
-  IN CONST EFI_GUID                     *PackageGuid,\r
-  IN CONST EFI_HII_PACKAGE_HEADER       *Package,\r
-  IN EFI_HII_HANDLE                     Handle,\r
-  IN EFI_HII_DATABASE_NOTIFY_TYPE       NotifyType\r
+ProcessRetrieveForQuestion (\r
+  IN     EFI_HII_CONFIG_ACCESS_PROTOCOL  *ConfigAccess,\r
+  IN     FORM_BROWSER_STATEMENT          *Statement,\r
+  IN     FORM_BROWSER_FORMSET            *FormSet\r
   )\r
 {\r
-  mHiiPackageListUpdated = TRUE;\r
+  EFI_STATUS                      Status;\r
+  EFI_BROWSER_ACTION_REQUEST      ActionRequest;\r
+  EFI_HII_VALUE                   *HiiValue;\r
+  EFI_IFR_TYPE_VALUE              *TypeValue;\r
+  CHAR16                          *NewString;\r
 \r
-  return EFI_SUCCESS;\r
+  Status                = EFI_SUCCESS;\r
+  ActionRequest         = EFI_BROWSER_ACTION_REQUEST_NONE;\r
+\r
+  if (((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != EFI_IFR_FLAG_CALLBACK) || ConfigAccess == NULL) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  HiiValue  = &Statement->HiiValue;\r
+  TypeValue = &HiiValue->Value;\r
+  if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {\r
+    //\r
+    // For OrderedList, passing in the value buffer to Callback()\r
+    //\r
+    TypeValue = (EFI_IFR_TYPE_VALUE *) Statement->BufferValue;\r
+  }\r
+\r
+  ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;\r
+  Status = ConfigAccess->Callback (\r
+                           ConfigAccess,\r
+                           EFI_BROWSER_ACTION_RETRIEVE,\r
+                           Statement->QuestionId,\r
+                           HiiValue->Type,\r
+                           TypeValue,\r
+                           &ActionRequest\r
+                           );\r
+  if (!EFI_ERROR (Status) && HiiValue->Type == EFI_IFR_TYPE_STRING) {\r
+    NewString = GetToken (Statement->HiiValue.Value.string, FormSet->HiiHandle);\r
+    ASSERT (NewString != NULL);\r
+\r
+    ASSERT (StrLen (NewString) * sizeof (CHAR16) <= Statement->StorageWidth);\r
+    if (StrLen (NewString) * sizeof (CHAR16) <= Statement->StorageWidth) {\r
+      ZeroMem (Statement->BufferValue, Statement->StorageWidth);\r
+      CopyMem (Statement->BufferValue, NewString, StrSize (NewString));\r
+    } else {\r
+      CopyMem (Statement->BufferValue, NewString, Statement->StorageWidth);\r
+    }\r
+    FreePool (NewString);\r
+  }\r
+\r
+  return Status;\r
 }\r
 \r
 /**\r
@@ -853,18 +2306,11 @@ SetupBrowser (
 {\r
   EFI_STATUS                      Status;\r
   LIST_ENTRY                      *Link;\r
-  EFI_BROWSER_ACTION_REQUEST      ActionRequest;\r
   EFI_HANDLE                      NotifyHandle;\r
-  EFI_HII_VALUE                   *HiiValue;\r
-  EFI_IFR_TYPE_VALUE              *TypeValue;\r
   FORM_BROWSER_STATEMENT          *Statement;\r
   EFI_HII_CONFIG_ACCESS_PROTOCOL  *ConfigAccess;\r
-  FORM_BROWSER_FORMSET            *FormSet;\r
-  EFI_INPUT_KEY                   Key;\r
 \r
-  gMenuRefreshHead = NULL;\r
-  gResetRequired = FALSE;\r
-  FormSet = Selection->FormSet;\r
+  ConfigAccess = Selection->FormSet->ConfigAccess;\r
 \r
   //\r
   // Register notify for Form package update\r
@@ -882,62 +2328,38 @@ SetupBrowser (
   }\r
 \r
   //\r
-  // Before display the formset, invoke ConfigAccess.Callback() with EFI_BROWSER_ACTION_FORM_OPEN\r
+  // Initialize current settings of Questions in this FormSet\r
   //\r
-  ConfigAccess = Selection->FormSet->ConfigAccess;\r
-  if ((ConfigAccess != NULL) && (Selection->Action != UI_ACTION_REFRESH_FORMSET)) {\r
-    ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;\r
-    mHiiPackageListUpdated = FALSE;\r
-    Status = ConfigAccess->Callback (\r
-                             ConfigAccess,\r
-                             EFI_BROWSER_ACTION_FORM_OPEN,\r
-                             0,\r
-                             EFI_IFR_TYPE_UNDEFINED,\r
-                             NULL,\r
-                             &ActionRequest\r
-                             );\r
+  InitializeCurrentSetting (Selection->FormSet);\r
 \r
-    if (!EFI_ERROR (Status)) {\r
-      switch (ActionRequest) {\r
-      case EFI_BROWSER_ACTION_REQUEST_RESET:\r
-        gResetRequired = TRUE;\r
-        break;\r
+  //\r
+  // Initilize Action field.\r
+  //\r
+  Selection->Action = UI_ACTION_REFRESH_FORM;\r
 \r
-      case EFI_BROWSER_ACTION_REQUEST_SUBMIT:\r
-        //\r
-        // Till now there is no uncommitted data, so ignore this request\r
-        //\r
-        break;\r
+  //\r
+  // Clean the mCurFakeQestId value is formset refreshed.\r
+  //\r
+  mCurFakeQestId = 0;\r
 \r
-      case EFI_BROWSER_ACTION_REQUEST_EXIT:\r
-        Selection->Action = UI_ACTION_EXIT;\r
-        break;\r
+  do {\r
 \r
-      default:\r
-        break;\r
-      }\r
-    }\r
+    //\r
+    // Reset Status to prevent the next break from returning incorrect error status.\r
+    //\r
+    Status = EFI_SUCCESS;\r
 \r
+    //\r
+    // IFR is updated, force to reparse the IFR binary\r
+    // This check is shared by EFI_BROWSER_ACTION_FORM_CLOSE and\r
+    // EFI_BROWSER_ACTION_RETRIEVE, so code place here.\r
+    //\r
     if (mHiiPackageListUpdated) {\r
-      //\r
-      // IFR is updated during callback, force to reparse the IFR binary\r
-      //\r
-      mHiiPackageListUpdated = FALSE;\r
       Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
-      goto Done;\r
+      mHiiPackageListUpdated = FALSE;\r
+      break;\r
     }\r
-  }\r
-\r
-  //\r
-  // Initialize current settings of Questions in this FormSet\r
-  //\r
-  Status = InitializeCurrentSetting (Selection->FormSet);\r
-  if (EFI_ERROR (Status)) {\r
-    Selection->Action = UI_ACTION_EXIT;\r
-    goto Done;\r
-  }\r
 \r
-  do {\r
     //\r
     // Initialize Selection->Form\r
     //\r
@@ -957,63 +2379,98 @@ SetupBrowser (
       //\r
       // No Form to display\r
       //\r
-      return EFI_NOT_FOUND;\r
+      Status = EFI_NOT_FOUND;\r
+      goto Done;\r
     }\r
 \r
     //\r
     // Check Form is suppressed.\r
     //\r
     if (Selection->Form->SuppressExpression != NULL) {\r
-      Status = EvaluateExpression (Selection->FormSet, Selection->Form, Selection->Form->SuppressExpression);\r
-      if (EFI_ERROR (Status)) {\r
-        return Status;\r
-      }\r
-\r
-      if (Selection->Form->SuppressExpression->Result.Value.b) {\r
+      if (EvaluateExpressionList(Selection->Form->SuppressExpression, TRUE, Selection->FormSet, Selection->Form) == ExpressSuppress) {\r
         //\r
-        // Form is suppressed. \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
-        return EFI_NOT_FOUND;\r
+        PopupErrorMessage(BROWSER_FORM_SUPPRESS, NULL, NULL, NULL);\r
+        Status = EFI_NOT_FOUND;\r
+        goto Done;\r
       }\r
     }\r
-    \r
+\r
     //\r
-    // Reset FormPackage update flag\r
+    // Before display new form, invoke ConfigAccess.Callback() with EFI_BROWSER_ACTION_FORM_OPEN\r
+    // for each question with callback flag.\r
+    // New form may be the first form, or the different form after another form close.\r
     //\r
-    mHiiPackageListUpdated = FALSE;\r
+    if (((Selection->Handle != mCurrentHiiHandle) ||\r
+        (!CompareGuid (&Selection->FormSetGuid, &mCurrentFormSetGuid)) ||\r
+        (Selection->FormId != mCurrentFormId))) {\r
+      //\r
+      // Update Retrieve flag.\r
+      //\r
+      mFinishRetrieveCall = FALSE;\r
+\r
+      //\r
+      // Keep current form information\r
+      //\r
+      mCurrentHiiHandle   = Selection->Handle;\r
+      CopyGuid (&mCurrentFormSetGuid, &Selection->FormSetGuid);\r
+      mCurrentFormId      = Selection->FormId;\r
+\r
+      if (ConfigAccess != NULL) {\r
+        Status = ProcessCallBackFunction (Selection, Selection->FormSet, Selection->Form, NULL, EFI_BROWSER_ACTION_FORM_OPEN, FALSE);\r
+        if (EFI_ERROR (Status)) {\r
+          goto Done;\r
+        }\r
+\r
+        //\r
+        // IFR is updated during callback of EFI_BROWSER_ACTION_FORM_OPEN, force to reparse the IFR binary\r
+        //\r
+        if (mHiiPackageListUpdated) {\r
+          Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
+          mHiiPackageListUpdated = FALSE;\r
+          break;\r
+        }\r
+      }\r
+    }\r
 \r
     //\r
     // Load Questions' Value for display\r
     //\r
     Status = LoadFormSetConfig (Selection, Selection->FormSet);\r
     if (EFI_ERROR (Status)) {\r
-      return Status;\r
-    }\r
-\r
-    //\r
-    // IFR is updated during callback of read value, force to reparse the IFR binary\r
-    //\r
-    if (mHiiPackageListUpdated) {\r
-      Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
-      mHiiPackageListUpdated = FALSE;\r
       goto Done;\r
     }\r
 \r
-    //\r
-    // Displays the Header and Footer borders\r
-    //\r
-    DisplayPageFrame ();\r
+    if (!mFinishRetrieveCall) {\r
+      //\r
+      // Finish call RETRIEVE callback for this form.\r
+      //\r
+      mFinishRetrieveCall = TRUE;\r
+\r
+      if (ConfigAccess != NULL) {\r
+        Status = ProcessCallBackFunction (Selection, Selection->FormSet, Selection->Form, NULL, EFI_BROWSER_ACTION_RETRIEVE, FALSE);\r
+        if (EFI_ERROR (Status)) {\r
+          goto Done;\r
+        }\r
+\r
+        //\r
+        // IFR is updated during callback of open form, force to reparse the IFR binary\r
+        //\r
+        if (mHiiPackageListUpdated) {\r
+          Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
+          mHiiPackageListUpdated = FALSE;\r
+          break;\r
+        }\r
+      }\r
+    }\r
 \r
     //\r
     // Display form\r
     //\r
-    Status = DisplayForm (Selection);\r
+    Status = DisplayForm ();\r
     if (EFI_ERROR (Status)) {\r
-      return Status;\r
+      goto Done;\r
     }\r
 \r
     //\r
@@ -1021,146 +2478,132 @@ SetupBrowser (
     //\r
     Statement = Selection->Statement;\r
     if (Statement != NULL) {\r
-      if ((Statement->QuestionFlags & EFI_IFR_FLAG_RESET_REQUIRED) == EFI_IFR_FLAG_RESET_REQUIRED) {\r
-        gResetRequired = TRUE;\r
-      }\r
-\r
-      //\r
-      // Reset FormPackage update flag\r
-      //\r
-      mHiiPackageListUpdated = FALSE;\r
-\r
-      if (((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK) && (Statement->Operand != EFI_IFR_PASSWORD_OP)) {\r
-        ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;\r
-\r
-        if (ConfigAccess == NULL) {\r
-          return EFI_UNSUPPORTED;\r
-        }\r
-\r
-        HiiValue = &Statement->HiiValue;\r
-        TypeValue = &HiiValue->Value;\r
-        if (HiiValue->Type == EFI_IFR_TYPE_STRING) {\r
+      if ((ConfigAccess != NULL) &&\r
+          ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK) &&\r
+          (Statement->Operand != EFI_IFR_PASSWORD_OP)) {\r
+        Status = ProcessCallBackFunction(Selection, Selection->FormSet, Selection->Form, Statement, EFI_BROWSER_ACTION_CHANGING, FALSE);\r
+        if (Statement->Operand == EFI_IFR_REF_OP) {\r
           //\r
-          // Create String in HII database for Configuration Driver to retrieve\r
+          // Process dynamic update ref opcode.\r
           //\r
-          HiiValue->Value.string = NewString ((CHAR16 *) Statement->BufferValue, Selection->FormSet->HiiHandle);\r
-        } else if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {\r
+          if (!EFI_ERROR (Status)) {\r
+            Status = ProcessGotoOpCode(Statement, Selection);\r
+          }\r
+\r
           //\r
-          // For OrderedList, passing in the value buffer to Callback()\r
+          // Callback return error status or status return from process goto opcode.\r
           //\r
-          TypeValue = (EFI_IFR_TYPE_VALUE *) Statement->BufferValue;\r
+          if (EFI_ERROR (Status)) {\r
+            //\r
+            // Cross reference will not be taken, restore all essential field\r
+            //\r
+            Selection->Handle = mCurrentHiiHandle;\r
+            CopyMem (&Selection->FormSetGuid, &mCurrentFormSetGuid, sizeof (EFI_GUID));\r
+            Selection->FormId = mCurrentFormId;\r
+            Selection->QuestionId = 0;\r
+            Selection->Action = UI_ACTION_REFRESH_FORM;\r
+          }\r
         }\r
 \r
-        Status = ConfigAccess->Callback (\r
-                                 ConfigAccess,\r
-                                 EFI_BROWSER_ACTION_CHANGING,\r
-                                 Statement->QuestionId,\r
-                                 HiiValue->Type,\r
-                                 TypeValue,\r
-                                 &ActionRequest\r
-                                 );\r
 \r
-        if (HiiValue->Type == EFI_IFR_TYPE_STRING) {\r
+        if (!EFI_ERROR (Status) &&\r
+            (Statement->Operand != EFI_IFR_REF_OP) &&\r
+            ((Statement->Storage == NULL) || (Statement->Storage != NULL && Statement->ValueChanged))) {\r
+          //\r
+          // Only question value has been changed, browser will trig CHANGED callback.\r
           //\r
-          // Clean the String in HII Database\r
+          ProcessCallBackFunction(Selection, Selection->FormSet, Selection->Form, Statement, EFI_BROWSER_ACTION_CHANGED, FALSE);\r
           //\r
-          DeleteString (HiiValue->Value.string, Selection->FormSet->HiiHandle);\r
+          //check whether the question value changed compared with buffer value\r
+          //if doesn't change ,set the ValueChanged flag to FALSE ,in order not to display the "configuration changed "information on the screen\r
+          //\r
+          IsQuestionValueChanged(gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithBuffer);\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
-        } else if (Status != EFI_UNSUPPORTED) {\r
+      } else {\r
+        //\r
+        // Do the question validation.\r
+        //\r
+        Status = ValueChangedValidation (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement);\r
+        if (!EFI_ERROR (Status) && (Statement->Operand != EFI_IFR_PASSWORD_OP)) {\r
+          SetQuestionValue (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithEditBuffer);\r
           //\r
-          // Callback return error status other than EFI_UNSUPPORTED\r
+          // Verify whether question value has checked, update the ValueChanged flag in Question.\r
           //\r
-          if (Statement->Operand == EFI_IFR_REF_OP) {\r
-            //\r
-            // Cross reference will not be taken\r
-            //\r
-            Selection->FormId = Selection->Form->FormId;\r
-            Selection->QuestionId = 0;\r
-          }\r
+          IsQuestionValueChanged(gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithBuffer);\r
         }\r
       }\r
 \r
       //\r
-      // Check whether Form Package has been updated during Callback\r
+      // If question has EFI_IFR_FLAG_RESET_REQUIRED/EFI_IFR_FLAG_RECONNECT_REQUIRED flag and without storage\r
+      // and process question success till here, trig the gResetFlag/gFlagReconnect.\r
       //\r
-      if (mHiiPackageListUpdated && (Selection->Action == UI_ACTION_REFRESH_FORM)) {\r
-        //\r
-        // Force to reparse IFR binary of target Formset\r
-        //\r
-        mHiiPackageListUpdated = FALSE;\r
-        Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
+      if ((Status == EFI_SUCCESS) &&\r
+          (Statement->Storage == NULL)) {\r
+        if ((Statement->QuestionFlags & EFI_IFR_FLAG_RESET_REQUIRED) != 0) {\r
+          gResetRequiredFormLevel = TRUE;\r
+          gResetRequiredSystemLevel = TRUE;\r
+        }\r
+\r
+        if ((Statement->QuestionFlags & EFI_IFR_FLAG_RECONNECT_REQUIRED) != 0) {\r
+          gFlagReconnect = TRUE;\r
+        }\r
       }\r
     }\r
-  } while (Selection->Action == UI_ACTION_REFRESH_FORM);\r
-\r
-  //\r
-  // Before exit the formset, invoke ConfigAccess.Callback() with EFI_BROWSER_ACTION_FORM_CLOSE\r
-  //\r
-  if ((ConfigAccess != NULL) && (Selection->Action == UI_ACTION_EXIT)) {\r
-    ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;\r
-    Status = ConfigAccess->Callback (\r
-                             ConfigAccess,\r
-                             EFI_BROWSER_ACTION_FORM_CLOSE,\r
-                             0,\r
-                             EFI_IFR_TYPE_UNDEFINED,\r
-                             NULL,\r
-                             &ActionRequest\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
+    //\r
+    // Check whether Exit flag is TRUE.\r
+    //\r
+    if (gExitRequired) {\r
+      switch (gBrowserSettingScope) {\r
+      case SystemLevel:\r
+        Selection->Action = UI_ACTION_EXIT;\r
         break;\r
 \r
-      case EFI_BROWSER_ACTION_REQUEST_EXIT:\r
-        gNvUpdateRequired = FALSE;\r
+      case FormSetLevel:\r
+      case FormLevel:\r
+        FindNextMenu (Selection, gBrowserSettingScope);\r
         break;\r
 \r
       default:\r
         break;\r
       }\r
+\r
+      gExitRequired = FALSE;\r
     }\r
-  }\r
 \r
+    //\r
+    // Before exit the form, invoke ConfigAccess.Callback() with EFI_BROWSER_ACTION_FORM_CLOSE\r
+    // for each question with callback flag.\r
+    //\r
+    if ((ConfigAccess != NULL) &&\r
+        ((Selection->Action == UI_ACTION_EXIT) ||\r
+         (Selection->Handle != mCurrentHiiHandle) ||\r
+         (!CompareGuid (&Selection->FormSetGuid, &mCurrentFormSetGuid)) ||\r
+         (Selection->FormId != mCurrentFormId))) {\r
+\r
+      Status = ProcessCallBackFunction (Selection, Selection->FormSet, Selection->Form, NULL, EFI_BROWSER_ACTION_FORM_CLOSE, FALSE);\r
+      if (EFI_ERROR (Status)) {\r
+        goto Done;\r
+      }\r
+    }\r
+  } while (Selection->Action == UI_ACTION_REFRESH_FORM);\r
+\r
+Done:\r
   //\r
-  // Record the old formset\r
+  // Reset current form information to the initial setting when error happens or form exit.\r
   //\r
-  if (gOldFormSet != NULL) {\r
-    DestroyFormSet (gOldFormSet);\r
+  if (EFI_ERROR (Status) || Selection->Action == UI_ACTION_EXIT) {\r
+    mCurrentHiiHandle = NULL;\r
+    CopyGuid (&mCurrentFormSetGuid, &gZeroGuid);\r
+    mCurrentFormId = 0;\r
   }\r
-  gOldFormSet = FormSet;\r
 \r
-Done:\r
   //\r
   // Unregister notify for Form package update\r
   //\r
-  Status = mHiiDatabase->UnregisterPackageNotify (\r
-                           mHiiDatabase,\r
-                           NotifyHandle\r
-                           );\r
+  mHiiDatabase->UnregisterPackageNotify (\r
+                   mHiiDatabase,\r
+                   NotifyHandle\r
+                   );\r
   return Status;\r
 }\r