]> git.proxmox.com Git - mirror_edk2.git/commitdiff
Update Browser to provide the customization possibilities.
authorEric Dong <eric.dong@intel.com>
Mon, 12 Aug 2013 02:19:56 +0000 (02:19 +0000)
committerydong10 <ydong10@6f19259b-4bc3-4df7-8a09-765794883524>
Mon, 12 Aug 2013 02:19:56 +0000 (02:19 +0000)
Signed-off-by: Eric Dong <eric.dong@intel.com>
Reviewed-by: Liming Gao <liming.gao@intel.com>
Tested-by: Laszlo Ersek <lersek@redhat.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@14540 6f19259b-4bc3-4df7-8a09-765794883524

25 files changed:
MdeModulePkg/Include/Library/CustomizedDisplayLib.h [new file with mode: 0644]
MdeModulePkg/Include/Protocol/DisplayProtocol.h [new file with mode: 0644]
MdeModulePkg/Include/Protocol/FormBrowserEx2.h [new file with mode: 0644]
MdeModulePkg/Library/CustomizedDisplayLib/Colors.h [new file with mode: 0644]
MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.c [new file with mode: 0644]
MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf [new file with mode: 0644]
MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.uni [new file with mode: 0644]
MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLibInternal.c [new file with mode: 0644]
MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLibInternal.h [new file with mode: 0644]
MdeModulePkg/MdeModulePkg.dec
MdeModulePkg/MdeModulePkg.dsc
MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf [new file with mode: 0644]
MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.c [new file with mode: 0644]
MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.h [new file with mode: 0644]
MdeModulePkg/Universal/DisplayEngineDxe/FormDisplayStr.uni [new file with mode: 0644]
MdeModulePkg/Universal/DisplayEngineDxe/InputHandler.c [new file with mode: 0644]
MdeModulePkg/Universal/DisplayEngineDxe/Print.c [new file with mode: 0644]
MdeModulePkg/Universal/DisplayEngineDxe/ProcessOptions.c [new file with mode: 0644]
MdeModulePkg/Universal/SetupBrowserDxe/Expression.c
MdeModulePkg/Universal/SetupBrowserDxe/Expression.h [new file with mode: 0644]
MdeModulePkg/Universal/SetupBrowserDxe/IfrParse.c
MdeModulePkg/Universal/SetupBrowserDxe/Presentation.c
MdeModulePkg/Universal/SetupBrowserDxe/Setup.c
MdeModulePkg/Universal/SetupBrowserDxe/Setup.h
MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf

diff --git a/MdeModulePkg/Include/Library/CustomizedDisplayLib.h b/MdeModulePkg/Include/Library/CustomizedDisplayLib.h
new file mode 100644 (file)
index 0000000..9644d93
--- /dev/null
@@ -0,0 +1,356 @@
+/** @file\r
+  This library class defines a set of interfaces to customize Display module\r
+\r
+Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials are licensed and made available under \r
+the terms and conditions of the BSD License that accompanies this distribution.  \r
+The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php.                                            \r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef __CUSTOMIZED_DISPLAY_LIB_H__\r
+#define __CUSTOMIZED_DISPLAY_LIB_H__\r
+\r
+#include <Protocol/DisplayProtocol.h>\r
+\r
+/**\r
++------------------------------------------------------------------------------+\r
+?                                 Setup Page                                  ?\r
++------------------------------------------------------------------------------+\r
+\r
+Statement\r
+Statement\r
+Statement\r
+\r
+\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
+  StatusBar\r
+**/\r
+\r
+/**\r
+  This funtion defines Page Frame and Backgroud. \r
+  \r
+  Based on the above layout, it will be responsible for HeaderHeight, FooterHeight, \r
+  StatusBarHeight and Backgroud. And, it will reserve Screen for Statement. \r
+\r
+  @param[in]  FormData             Form Data to be shown in Page.\r
+  @param[out] ScreenForStatement   Screen to be used for Statement. (Prompt, Value and Help)\r
+  \r
+  @return Status\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DisplayPageFrame (\r
+  IN FORM_DISPLAY_ENGINE_FORM       *FormData,\r
+  OUT EFI_SCREEN_DESCRIPTOR         *ScreenForStatement\r
+  );\r
+\r
+/**\r
+  Clear Screen to the initial state.\r
+**/\r
+VOID\r
+EFIAPI \r
+ClearDisplayPage (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  This function updates customized key panel's help information.\r
+  The library will prepare those Strings for the basic key, ESC, Enter, Up/Down/Left/Right, +/-.\r
+  and arrange them in Footer panel.\r
+  \r
+  @param[in]  FormData       Form Data to be shown in Page. FormData has the highlighted statement. \r
+  @param[in]  Statement      The statement current selected.\r
+  @param[in]  Selected       Whether or not a tag be selected. TRUE means Enter has hit this question.\r
+**/\r
+VOID\r
+EFIAPI\r
+RefreshKeyHelp (\r
+  IN FORM_DISPLAY_ENGINE_FORM      *FormData,\r
+  IN FORM_DISPLAY_ENGINE_STATEMENT *Statement,\r
+  IN  BOOLEAN                      Selected\r
+  );\r
+\r
+/**\r
+  Update status bar.\r
+\r
+  This function updates the status bar on the bottom of menu screen. It just shows StatusBar. \r
+  Original logic in this function should be splitted out.\r
+\r
+  @param[in]  MessageType            The type of message to be shown. InputError or Configuration Changed. \r
+  @param[in]  State                  Show or Clear Message.\r
+**/\r
+VOID\r
+EFIAPI\r
+UpdateStatusBar (\r
+  IN  UINTN                  MessageType,\r
+  IN  BOOLEAN                State\r
+  );\r
+\r
+/**\r
+  Create popup window. \r
+\r
+  This function draws OEM/Vendor specific pop up windows.\r
+\r
+  @param[out]  Key    User Input Key\r
+  @param       ...    String to be shown in Popup. The variable argument list is terminated by a NULL.\r
+  \r
+**/\r
+VOID\r
+EFIAPI\r
+CreateDialog (\r
+  OUT EFI_INPUT_KEY  *Key,        OPTIONAL\r
+  ...\r
+  );\r
+\r
+/**\r
+  Confirm how to handle the changed data. \r
+  \r
+  @return Action BROWSER_ACTION_SUBMIT, BROWSER_ACTION_DISCARD or other values.\r
+**/\r
+UINTN\r
+EFIAPI\r
+ConfirmDataChange (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  OEM specifies whether Setup exits Page by ESC key.\r
+\r
+  This function customized the behavior that whether Setup exits Page so that \r
+  system able to boot when configuration is not changed.\r
+\r
+  @retval  TRUE     Exits FrontPage\r
+  @retval  FALSE    Don't exit FrontPage.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+FormExitPolicy (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Set Timeout value for a ceratain Form to get user response. \r
+  \r
+  This function allows to set timeout value on a ceratain form if necessary.\r
+  If timeout is not zero, the form will exit if user has no response in timeout. \r
+  \r
+  @param[in]  FormData   Form Data to be shown in Page\r
+\r
+  @return 0     No timeout for this form. \r
+  @return > 0   Timeout value in 100 ns units.\r
+**/\r
+UINT64\r
+EFIAPI\r
+FormExitTimeout (\r
+  IN FORM_DISPLAY_ENGINE_FORM      *FormData\r
+  );\r
+\r
+//\r
+// Print Functions\r
+//\r
+/**\r
+  Prints a unicode string to the default console, at\r
+  the supplied cursor position, using L"%s" format.\r
+\r
+  @param  Column     The cursor position to print the string at. When it is -1, use current Position.\r
+  @param  Row        The cursor position to print the string at. When it is -1, use current Position.\r
+  @param  String     String pointer.\r
+\r
+  @return Length of string printed to the console\r
+\r
+**/\r
+UINTN\r
+EFIAPI\r
+PrintStringAt (\r
+  IN UINTN     Column,\r
+  IN UINTN     Row,\r
+  IN CHAR16    *String\r
+  );\r
+\r
+\r
+/**\r
+  Prints a unicode string with the specified width to the default console, at\r
+  the supplied cursor position, using L"%s" format.\r
+\r
+  @param  Column     The cursor position to print the string at. When it is -1, use current Position.\r
+  @param  Row        The cursor position to print the string at. When it is -1, use current Position.\r
+  @param  String     String pointer.\r
+  @param  Width      Width for String to be printed. If the print length of String < Width, \r
+                     Space char (L' ') will be used to append String. \r
+\r
+  @return Length of string printed to the console\r
+\r
+**/\r
+UINTN\r
+EFIAPI\r
+PrintStringAtWithWidth (\r
+  IN UINTN     Column,\r
+  IN UINTN     Row,\r
+  IN CHAR16    *String,\r
+  IN UINTN     Width\r
+  );\r
+\r
+/**\r
+  Prints a chracter to the default console, at\r
+  the supplied cursor position, using L"%c" format.\r
+\r
+  @param  Column     The cursor position to print the string at. When it is -1, use current Position.\r
+  @param  Row        The cursor position to print the string at. When it is -1, use current Position.\r
+  @param  Character  Character to print.\r
+\r
+  @return Length of string printed to the console.\r
+\r
+**/\r
+UINTN\r
+EFIAPI\r
+PrintCharAt (\r
+  IN UINTN     Column,\r
+  IN UINTN     Row,\r
+  CHAR16       Character\r
+  );\r
+\r
+/**\r
+  Clear retangle with specified text attribute.\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
+\r
+**/\r
+VOID\r
+EFIAPI\r
+ClearLines (\r
+  IN UINTN               LeftColumn,\r
+  IN UINTN               RightColumn,\r
+  IN UINTN               TopRow,\r
+  IN UINTN               BottomRow,\r
+  IN UINTN               TextAttribute\r
+  );\r
+\r
+//\r
+// Color Setting Functions\r
+//\r
+/**\r
+  Get OEM/Vendor specific popup attribute colors.\r
+\r
+  @retval  Byte code color setting for popup color.\r
+**/\r
+UINT8\r
+EFIAPI\r
+GetPopupColor (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Get OEM/Vendor specific popup attribute colors.\r
+\r
+  @retval  Byte code color setting for popup inverse color.\r
+**/\r
+UINT8\r
+EFIAPI\r
+GetPopupInverseColor (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Get OEM/Vendor specific PickList color attribute.\r
+\r
+  @retval  Byte code color setting for pick list color.\r
+**/\r
+UINT8\r
+EFIAPI\r
+GetPickListColor (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Get OEM/Vendor specific arrow color attribute.\r
+\r
+  @retval  Byte code color setting for arrow color.\r
+**/\r
+UINT8\r
+EFIAPI\r
+GetArrowColor (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Get OEM/Vendor specific info text color attribute.\r
+\r
+  @retval  Byte code color setting for info text color.\r
+**/\r
+UINT8\r
+EFIAPI\r
+GetInfoTextColor (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Get OEM/Vendor specific help text color attribute.\r
+\r
+  @retval  Byte code color setting for help text color.\r
+**/\r
+UINT8\r
+EFIAPI\r
+GetHelpTextColor (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Get OEM/Vendor specific grayed out text color attribute.\r
+\r
+  @retval  Byte code color setting for grayed out text color.\r
+**/\r
+UINT8\r
+EFIAPI\r
+GetGrayedTextColor (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Get OEM/Vendor specific highlighted text color attribute.\r
+\r
+  @retval  Byte code color setting for highlight text color.\r
+**/\r
+UINT8\r
+EFIAPI\r
+GetHighlightTextColor (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Get OEM/Vendor specific field text color attribute.\r
+\r
+  @retval  Byte code color setting for field text color.\r
+**/\r
+UINT8\r
+EFIAPI\r
+GetFieldTextColor (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Get OEM/Vendor specific subtitle text color attribute.\r
+\r
+  @retval  Byte code color setting for subtitle text color.\r
+**/\r
+UINT8\r
+EFIAPI\r
+GetSubTitleTextColor (\r
+  VOID\r
+  );\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Include/Protocol/DisplayProtocol.h b/MdeModulePkg/Include/Protocol/DisplayProtocol.h
new file mode 100644 (file)
index 0000000..d4f0deb
--- /dev/null
@@ -0,0 +1,350 @@
+/** @file\r
+  FormDiplay protocol to show Form\r
+\r
+Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials are licensed and made available under \r
+the terms and conditions of the BSD License that accompanies this distribution.  \r
+The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php.                                            \r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef __DISPLAY_PROTOCOL_H__\r
+#define __DISPLAY_PROTOCOL_H__\r
+\r
+#include <Protocol/FormBrowser2.h>\r
+\r
+#define EDKII_FORM_DISPLAY_ENGINE_PROTOCOL_GUID  \\r
+  { 0x9bbe29e9, 0xfda1, 0x41ec, { 0xad, 0x52, 0x45, 0x22, 0x13, 0x74, 0x2d, 0x2e } }\r
+\r
+// \r
+// Do nothing.\r
+//\r
+#define BROWSER_ACTION_NONE         BIT16\r
+//\r
+// ESC Exit\r
+//\r
+#define BROWSER_ACTION_FORM_EXIT    BIT17\r
+\r
+#define BROWSER_SUCCESS             0x0\r
+#define BROWSER_ERROR               BIT31\r
+#define BROWSER_SUBMIT_FAIL         BROWSER_ERROR | 0x01\r
+#define BROWSER_NO_SUBMIT_IF        BROWSER_ERROR | 0x02\r
+#define BROWSER_FORM_NOT_FOUND      BROWSER_ERROR | 0x03\r
+#define BROWSER_FORM_SUPPRESS       BROWSER_ERROR | 0x04\r
+#define BROWSER_PROTOCOL_NOT_FOUND  BROWSER_ERROR | 0x05\r
+\r
+#define FORM_DISPLAY_ENGINE_STATEMENT_VERSION_1  0x10000\r
+#define FORM_DISPLAY_ENGINE_VERSION_1            0x10000\r
+\r
+typedef struct {\r
+  //\r
+  // HII Data Type\r
+  //\r
+  UINT8               Type;\r
+  //\r
+  // Buffer Data and Length if Type is EFI_IFR_TYPE_BUFFER or EFI_IFR_TYPE_STRING\r
+  //\r
+  UINT8               *Buffer;\r
+  UINT16              BufferLen;\r
+  EFI_IFR_TYPE_VALUE  Value;\r
+} EFI_HII_VALUE;\r
+\r
+#define DISPLAY_QUESTION_OPTION_SIGNATURE  SIGNATURE_32 ('Q', 'O', 'P', 'T')\r
+\r
+typedef struct {\r
+  UINTN                  Signature;\r
+  LIST_ENTRY             Link;\r
+  //\r
+  // OneOfOption Data\r
+  //\r
+  EFI_IFR_ONE_OF_OPTION  *OptionOpCode;\r
+  //\r
+  // Option ImageId and AnimationId\r
+  //\r
+  EFI_IMAGE_ID           ImageId;\r
+  EFI_ANIMATION_ID       AnimationId;\r
+} DISPLAY_QUESTION_OPTION;\r
+\r
+#define DISPLAY_QUESTION_OPTION_FROM_LINK(a)  CR (a, DISPLAY_QUESTION_OPTION, Link, DISPLAY_QUESTION_OPTION_SIGNATURE)\r
+\r
+typedef struct _FORM_DISPLAY_ENGINE_STATEMENT FORM_DISPLAY_ENGINE_STATEMENT;\r
+typedef struct _FORM_DISPLAY_ENGINE_FORM      FORM_DISPLAY_ENGINE_FORM;\r
+\r
+#define STATEMENT_VALID             0x0\r
+#define STATEMENT_INVALID           BIT31\r
+\r
+#define INCOSISTENT_IF_TRUE         STATEMENT_INVALID | 0x01\r
+#define WARNING_IF_TRUE             STATEMENT_INVALID | 0x02\r
+#define STRING_TOO_LONG             STATEMENT_INVALID | 0x03\r
+// ... to be extended.\r
+\r
+typedef struct {\r
+  //\r
+  // StringId for INCONSITENT_IF or WARNING_IF\r
+  //\r
+  EFI_STRING_ID  StringId;\r
+  //\r
+  // TimeOut for WARNING_IF\r
+  //\r
+  UINT8          TimeOut;\r
+} STATEMENT_ERROR_INFO;\r
+\r
+/**\r
+  Perform value check for a question.\r
+  \r
+  @param  Form       Form where Statement is in.\r
+  @param  Statement  Value will check for it.\r
+  @param  Value      New value will be checked.\r
+  \r
+  @retval Status     Value Status\r
+\r
+**/\r
+typedef\r
+UINT32\r
+(EFIAPI *VALIDATE_QUESTION) (\r
+  IN FORM_DISPLAY_ENGINE_FORM      *Form,\r
+  IN FORM_DISPLAY_ENGINE_STATEMENT *Statement,\r
+  IN EFI_HII_VALUE                 *Value, \r
+  OUT STATEMENT_ERROR_INFO         *ErrorInfo\r
+  );\r
+\r
+/**\r
+  Perform Password check. \r
+  Passwork may be encrypted by driver that requires the specific check.\r
+  \r
+  @param  Form             Form where Password Statement is in.\r
+  @param  Statement        Password statement\r
+  @param  PasswordString   Password string to be checked. It may be NULL.\r
+                           NULL means to restore password.\r
+                           "" string can be used to checked whether old password does exist.\r
+  \r
+  @return Status     Status of Password check.\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *PASSWORD_CHECK) (\r
+  IN FORM_DISPLAY_ENGINE_FORM      *Form,\r
+  IN FORM_DISPLAY_ENGINE_STATEMENT *Statement,\r
+  IN EFI_STRING                    PasswordString  OPTIONAL\r
+  );\r
+\r
+#define FORM_DISPLAY_ENGINE_STATEMENT_SIGNATURE  SIGNATURE_32 ('F', 'S', 'T', 'A')\r
+\r
+//\r
+// Attribute for Statement and Form\r
+//\r
+#define HII_DISPLAY_GRAYOUT          BIT0\r
+#define HII_DISPLAY_LOCK             BIT1\r
+#define HII_DISPLAY_READONLY         BIT2\r
+#define HII_DISPLAY_MODAL            BIT3\r
+\r
+struct _FORM_DISPLAY_ENGINE_STATEMENT{\r
+  UINTN                 Signature;\r
+  //\r
+  // Version for future structure extension\r
+  //\r
+  UINTN                 Version;\r
+  //\r
+  // link to all the statement which will show in the display form.\r
+  //\r
+  LIST_ENTRY            DisplayLink;\r
+  //\r
+  // Pointer to statement opcode.\r
+  // for Guided Opcode. All buffers will be here if GUIDED opcode scope is set.\r
+  //\r
+  EFI_IFR_OP_HEADER     *OpCode;\r
+  //\r
+  // Question CurrentValue\r
+  //\r
+  EFI_HII_VALUE         CurrentValue;\r
+  //\r
+  // Flag to describe whether setting is changed or not.\r
+  // Displayer may depend on it to show it with the different color. \r
+  //\r
+  BOOLEAN               SettingChangedFlag;\r
+  //\r
+  // nested Statement list inside of EFI_IFR_SUBTITLE\r
+  //\r
+  LIST_ENTRY            NestStatementList;\r
+  //\r
+  // nested EFI_IFR_ONE_OF_OPTION list (QUESTION_OPTION)\r
+  //\r
+  LIST_ENTRY            OptionListHead;\r
+  //\r
+  // Statement attributes: GRAYOUT, LOCK and READONLY\r
+  //\r
+  UINT32                Attribute;\r
+\r
+  //\r
+  // ValidateQuestion to do InconsistIf check\r
+  // It may be NULL if any value is valid.\r
+  //\r
+  VALIDATE_QUESTION     ValidateQuestion;\r
+  \r
+  //\r
+  // Password additional check. It may be NULL when the additional check is not required.\r
+  //\r
+  PASSWORD_CHECK        PasswordCheck;\r
+\r
+  //\r
+  // Statement ImageId and AnimationId\r
+  //\r
+  EFI_IMAGE_ID          ImageId;\r
+  EFI_ANIMATION_ID      AnimationId;\r
+};\r
+\r
+#define FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK(a)  CR (a, FORM_DISPLAY_ENGINE_STATEMENT, DisplayLink, FORM_DISPLAY_ENGINE_STATEMENT_SIGNATURE)\r
+\r
+#define BROWSER_HOT_KEY_SIGNATURE  SIGNATURE_32 ('B', 'H', 'K', 'S')\r
+\r
+typedef struct {\r
+  UINTN                 Signature;\r
+  LIST_ENTRY            Link;\r
+  \r
+  EFI_INPUT_KEY         *KeyData;\r
+  //\r
+  // Action is Discard, Default, Submit, Reset and Exit.\r
+  //\r
+  UINT32                 Action;\r
+  UINT16                 DefaultId;\r
+  //\r
+  // HotKey Help String\r
+  //\r
+  EFI_STRING             HelpString;\r
+} BROWSER_HOT_KEY;\r
+\r
+#define BROWSER_HOT_KEY_FROM_LINK(a)  CR (a, BROWSER_HOT_KEY, Link, BROWSER_HOT_KEY_SIGNATURE)\r
+\r
+#define FORM_DISPLAY_ENGINE_FORM_SIGNATURE  SIGNATURE_32 ('F', 'F', 'R', 'M')\r
+\r
+struct _FORM_DISPLAY_ENGINE_FORM {\r
+  UINTN                Signature;\r
+  //\r
+  // Version for future structure extension\r
+  //\r
+  UINTN                Version;\r
+  //\r
+  // Statement List inside of Form\r
+  //\r
+  LIST_ENTRY            StatementListHead;\r
+  //\r
+  // Statement List outside of Form  \r
+  //\r
+  LIST_ENTRY            StatementListOSF;\r
+  //\r
+  // The input screen dimenstions info.\r
+  //\r
+  EFI_SCREEN_DESCRIPTOR *ScreenDimensions;\r
+  //\r
+  // FormSet information\r
+  //\r
+  EFI_GUID             FormSetGuid;\r
+  //\r
+  // HiiHandle can be used to get String, Image or Animation\r
+  //\r
+  EFI_HII_HANDLE       HiiHandle;\r
+  \r
+  //\r
+  // Form ID and Title.\r
+  //\r
+  UINT16               FormId;\r
+  EFI_STRING_ID        FormTitle;\r
+  //\r
+  // Form Attributes: Lock, Modal.\r
+  //\r
+  UINT32               Attribute;\r
+  //\r
+  // Flag to describe whether setting is changed or not.\r
+  // Displayer depends on it to show ChangedFlag.\r
+  //\r
+  BOOLEAN              SettingChangedFlag;\r
+\r
+  //\r
+  // Statement to be HighLighted\r
+  //\r
+  FORM_DISPLAY_ENGINE_STATEMENT *HighLightedStatement;\r
+  //\r
+  // Event to notify Displayer that FormData is updated to be refreshed.\r
+  //\r
+  EFI_EVENT              FormRefreshEvent;\r
+  //\r
+  // Additional Hotkey registered by BrowserEx protocol.\r
+  //\r
+  LIST_ENTRY             HotKeyListHead;\r
+\r
+  //\r
+  // Form ImageId and AnimationId\r
+  //\r
+  EFI_IMAGE_ID         ImageId;\r
+  EFI_ANIMATION_ID     AnimationId;\r
+  \r
+  //\r
+  // If Status is error, display needs to handle it.  \r
+  //\r
+  UINT32               BrowserStatus;\r
+  //\r
+  // String for error status. It may be NULL. \r
+  //\r
+  EFI_STRING           ErrorString;\r
+};\r
+\r
+#define FORM_DISPLAY_ENGINE_FORM_FROM_LINK(a)  CR (a, FORM_DISPLAY_ENGINE_FORM, Link, FORM_DISPLAY_ENGINE_FORM_SIGNATURE)\r
+\r
+typedef struct {\r
+  FORM_DISPLAY_ENGINE_STATEMENT  *SelectedStatement; // Selected Statement and InputValue\r
+  \r
+  EFI_HII_VALUE                  InputValue;\r
+  \r
+  UINT32                         Action;             // If SelectedStatement is NULL, Action will be used.\r
+                                                     // Trig Action (Discard, Default, Submit, Reset and Exit)\r
+  UINT16                         DefaultId;\r
+} USER_INPUT;\r
+\r
+/**\r
+  Display one form, and return user input.\r
+  \r
+  @param FormData                Form Data to be shown.\r
+  @param UserInputData           User input data.\r
+  \r
+  @retval EFI_SUCCESS            Form Data is shown, and user input is got.\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *FORM_DISPLAY) (\r
+  IN FORM_DISPLAY_ENGINE_FORM  *FormData,\r
+  OUT USER_INPUT               *UserInputData\r
+);\r
+\r
+/**\r
+  Exit Display and Clear Screen to the original state.\r
+\r
+**/\r
+typedef\r
+VOID\r
+(EFIAPI *EXIT_DISPLAY) (\r
+  VOID\r
+);\r
+\r
+/**\r
+  Confirm how to handle the changed data. \r
+  \r
+  @return Action of Submit, Discard and None\r
+**/\r
+typedef\r
+UINTN\r
+(EFIAPI *CONFIRM_DATA_CHANGE) (\r
+  VOID\r
+);\r
+\r
+typedef struct {\r
+  FORM_DISPLAY        FormDisplay;\r
+  EXIT_DISPLAY        ExitDisplay;\r
+  CONFIRM_DATA_CHANGE ConfirmDataChange;\r
+} EDKII_FORM_DISPLAY_ENGINE_PROTOCOL;\r
+\r
+extern EFI_GUID gEdkiiFormDisplayEngineProtocolGuid;\r
+#endif\r
diff --git a/MdeModulePkg/Include/Protocol/FormBrowserEx2.h b/MdeModulePkg/Include/Protocol/FormBrowserEx2.h
new file mode 100644 (file)
index 0000000..817f80d
--- /dev/null
@@ -0,0 +1,90 @@
+/** @file\r
+  Extension Form Browser Protocol provides the services that can be used to \r
+  register the different hot keys for the standard Browser actions described in UEFI specification.\r
+\r
+Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials are licensed and made available under \r
+the terms and conditions of the BSD License that accompanies this distribution.  \r
+The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php.                                            \r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef __FORM_BROWSER_EXTENSION2_H__\r
+#define __FORM_BROWSER_EXTENSION2_H__\r
+\r
+#include <Protocol/FormBrowserEx.h>\r
+\r
+#define EDKII_FORM_BROWSER_EXTENSION2_PROTOCOL_GUID  \\r
+  { 0xa770c357, 0xb693, 0x4e6d, { 0xa6, 0xcf, 0xd2, 0x1c, 0x72, 0x8e, 0x55, 0xb }}\r
+\r
+typedef struct _EDKII_FORM_BROWSER_EXTENSION2_PROTOCOL   EDKII_FORM_BROWSER_EXTENSION2_PROTOCOL;\r
+\r
+#define BROWSER_EXTENSION2_VERSION_1  0x10000\r
+\r
+/**\r
+  Check whether the browser data has been modified.\r
+\r
+  @retval TRUE        Browser data is modified.\r
+  @retval FALSE       No browser data is modified.\r
+\r
+**/\r
+typedef\r
+BOOLEAN\r
+(EFIAPI *IS_BROWSER_DATA_MODIFIED) (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Execute the action requested by the Action parameter.\r
+\r
+  @param[in] Action     Execute the request action.\r
+  @param[in] DefaultId  The default Id info when need to load default value.\r
+\r
+  @retval EFI_SUCCESS              Execute the request action succss.\r
+\r
+**/\r
+typedef \r
+EFI_STATUS \r
+(EFIAPI *EXECUTE_ACTION) (\r
+  IN UINT32        Action,\r
+  IN UINT16        DefaultId\r
+  );\r
+\r
+#define FORM_ENTRY_INFO_SIGNATURE    SIGNATURE_32 ('f', 'e', 'i', 's')\r
+\r
+typedef struct {\r
+  UINTN           Signature;\r
+  LIST_ENTRY      Link;\r
+\r
+  EFI_HII_HANDLE  HiiHandle;\r
+  EFI_GUID        FormSetGuid;\r
+  UINT16          FormId;\r
+  UINT16          QuestionId;\r
+} FORM_ENTRY_INFO;\r
+\r
+#define FORM_ENTRY_INFO_FROM_LINK(a)  CR (a, FORM_ENTRY_INFO, Link, FORM_ENTRY_INFO_SIGNATURE)\r
+\r
+struct _EDKII_FORM_BROWSER_EXTENSION2_PROTOCOL {\r
+  ///\r
+  /// Version for protocol future extension.\r
+  ///\r
+  UINT32                    Version;\r
+  SET_SCOPE                 SetScope;\r
+  REGISTER_HOT_KEY          RegisterHotKey;\r
+  REGISTER_EXIT_HANDLER     RegiserExitHandler;\r
+  IS_BROWSER_DATA_MODIFIED  IsBrowserDataModified;\r
+  EXECUTE_ACTION            ExecuteAction;\r
+  ///\r
+  /// A list of type FORMID_INFO is Browser View Form History List.\r
+  ///\r
+  LIST_ENTRY                FormViewHistoryHead;\r
+};\r
+\r
+extern EFI_GUID gEdkiiFormBrowserEx2ProtocolGuid;\r
+\r
+#endif\r
+\r
diff --git a/MdeModulePkg/Library/CustomizedDisplayLib/Colors.h b/MdeModulePkg/Library/CustomizedDisplayLib/Colors.h
new file mode 100644 (file)
index 0000000..2db8b99
--- /dev/null
@@ -0,0 +1,44 @@
+/** @file\r
+MACRO definitions for color used in Setup Browser.\r
+\r
+Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+//\r
+// Unicode collation protocol in\r
+\r
+#ifndef _COLORS_H_\r
+#define _COLORS_H_\r
+\r
+//\r
+// Screen Color Settings\r
+//\r
+#define PICKLIST_HIGHLIGHT_TEXT       EFI_WHITE\r
+#define PICKLIST_HIGHLIGHT_BACKGROUND EFI_BACKGROUND_CYAN\r
+#define TITLE_TEXT                    EFI_WHITE\r
+#define TITLE_BACKGROUND              EFI_BACKGROUND_BLUE\r
+#define KEYHELP_TEXT                  EFI_LIGHTGRAY\r
+#define KEYHELP_BACKGROUND            EFI_BACKGROUND_BLACK\r
+#define SUBTITLE_BACKGROUND           EFI_BACKGROUND_LIGHTGRAY\r
+#define BANNER_TEXT                   EFI_BLUE\r
+#define BANNER_BACKGROUND             EFI_BACKGROUND_LIGHTGRAY\r
+#define FIELD_TEXT_GRAYED             EFI_DARKGRAY\r
+#define FIELD_BACKGROUND              EFI_BACKGROUND_LIGHTGRAY\r
+#define POPUP_TEXT                    EFI_LIGHTGRAY\r
+#define POPUP_BACKGROUND              EFI_BACKGROUND_BLUE\r
+#define POPUP_INVERSE_TEXT            EFI_LIGHTGRAY\r
+#define POPUP_INVERSE_BACKGROUND      EFI_BACKGROUND_BLACK\r
+#define HELP_TEXT                     EFI_BLUE\r
+#define ERROR_TEXT                    EFI_RED | EFI_BRIGHT\r
+#define INFO_TEXT                     EFI_YELLOW | EFI_BRIGHT\r
+#define ARROW_TEXT                    EFI_RED | EFI_BRIGHT\r
+#define ARROW_BACKGROUND              EFI_BACKGROUND_LIGHTGRAY\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.c b/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.c
new file mode 100644 (file)
index 0000000..84df7cc
--- /dev/null
@@ -0,0 +1,936 @@
+/** @file\r
+\r
+  This library class defines a set of interfaces to customize Display module\r
+\r
+Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials are licensed and made available under \r
+the terms and conditions of the BSD License that accompanies this distribution.  \r
+The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php.                                            \r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+#include "CustomizedDisplayLibInternal.h"\r
+\r
+EFI_GUID          gCustomizedDisplayLibGuid = { 0x99fdc8fd, 0x849b, 0x4eba, { 0xad, 0x13, 0xfb, 0x96, 0x99, 0xc9, 0xa, 0x4d } };\r
+\r
+EFI_HII_HANDLE    mCDLStringPackHandle;\r
+UINT16            gClassOfVfr;                 // Formset class information\r
+UINT16            gLastClassOfVfr = 0;\r
+BANNER_DATA       *gBannerData;\r
+\r
+UINTN             gFooterHeight;\r
+\r
+/**\r
++------------------------------------------------------------------------------+\r
+|                                 Setup Page                                   |\r
++------------------------------------------------------------------------------+\r
+\r
+Statement\r
+Statement\r
+Statement\r
+\r
+\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
+  StatusBar\r
+**/\r
+\r
+/**\r
+  This funtion defines Page Frame and Backgroud. \r
+  \r
+  Based on the above layout, it will be responsible for HeaderHeight, FooterHeight, \r
+  StatusBarHeight and Backgroud. And, it will reserve Screen for Statement. \r
+\r
+  @param[in]  FormData             Form Data to be shown in Page.\r
+  @param[out] ScreenForStatement   Screen to be used for Statement. (Prompt, Value and Help)\r
+  \r
+  @return Status\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DisplayPageFrame (\r
+  IN FORM_DISPLAY_ENGINE_FORM       *FormData,\r
+  OUT EFI_SCREEN_DESCRIPTOR         *ScreenForStatement\r
+  )\r
+{\r
+  EFI_STATUS             Status;\r
+\r
+  ASSERT (FormData != NULL && ScreenForStatement != NULL);\r
+  if (FormData == NULL || ScreenForStatement == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status = ScreenDiemensionInfoValidate (FormData);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  gClassOfVfr = FORMSET_CLASS_PLATFORM_SETUP;\r
+  if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) {\r
+    gClassOfVfr = FORMSET_CLASS_MODEL_PAGE;\r
+  }\r
+\r
+  ProcessExternedOpcode(FormData);\r
+\r
+  //\r
+  // Calculate the ScreenForStatement.\r
+  //\r
+  ScreenForStatement->BottomRow   = gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight;\r
+  if ((gClassOfVfr & FORMSET_CLASS_FRONT_PAGE) == FORMSET_CLASS_FRONT_PAGE) {\r
+    ScreenForStatement->TopRow    = gScreenDimensions.TopRow + FRONT_PAGE_HEADER_HEIGHT;\r
+  } else {\r
+    ScreenForStatement->TopRow    = gScreenDimensions.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT;\r
+  }\r
+  ScreenForStatement->LeftColumn  = gScreenDimensions.LeftColumn;\r
+  ScreenForStatement->RightColumn = gScreenDimensions.RightColumn;\r
+\r
+  //\r
+  // If Last Vfr Class is same to current Vfr Class, \r
+  // they will have the same page frame. So, Page Frame is not required to be repainted.\r
+  //\r
+  if (gLastClassOfVfr == gClassOfVfr) {\r
+    UpdateStatusBar(NV_UPDATE_REQUIRED, FormData->SettingChangedFlag);\r
+    PrintFormTitle(FormData);\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Record last ClassOfVfr and Streen Information.\r
+  //\r
+  gLastClassOfVfr = gClassOfVfr;\r
+\r
+  //\r
+  // Ensure we are in Text mode\r
+  //\r
+  gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
+\r
+  ClearLines (0, gScreenDimensions.RightColumn, 0, gScreenDimensions.BottomRow, KEYHELP_BACKGROUND);\r
+\r
+  if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if ((gClassOfVfr & FORMSET_CLASS_FRONT_PAGE) == FORMSET_CLASS_FRONT_PAGE) {\r
+    PrintBannerInfo (FormData);\r
+  }\r
+\r
+  PrintFramework ();\r
+\r
+  UpdateStatusBar(NV_UPDATE_REQUIRED, FormData->SettingChangedFlag);\r
+\r
+  PrintFormTitle(FormData);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  This function updates customized key panel's help information.\r
+  The library will prepare those Strings for the basic key, ESC, Enter, Up/Down/Left/Right, +/-.\r
+  and arrange them in Footer panel.\r
+  \r
+  @param[in]  FormData       Form Data to be shown in Page. FormData has the highlighted statement. \r
+  @param[in]  Statement      The statement current selected.\r
+  @param[in]  Selected       Whether or not a tag be selected. TRUE means Enter has hit this question.\r
+**/\r
+VOID\r
+EFIAPI\r
+RefreshKeyHelp (\r
+  IN FORM_DISPLAY_ENGINE_FORM      *FormData,\r
+  IN FORM_DISPLAY_ENGINE_STATEMENT *Statement,\r
+  IN  BOOLEAN                      Selected\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_IFR_NUMERIC        *NumericOp;\r
+  EFI_IFR_DATE           *DateOp;\r
+  EFI_IFR_TIME           *TimeOp;\r
+  BOOLEAN                HexDisplay;\r
+\r
+  ASSERT (FormData != NULL);\r
+  if (FormData == NULL) {\r
+    return;\r
+  }\r
+\r
+  gST->ConOut->SetAttribute (gST->ConOut, KEYHELP_TEXT | KEYHELP_BACKGROUND);\r
+\r
+  if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) {\r
+    return;\r
+  }\r
+\r
+  SecCol            = gScreenDimensions.LeftColumn + (gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn) / 3;\r
+  ThdCol            = gScreenDimensions.LeftColumn + (gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn) / 3 * 2;\r
+\r
+  StartColumnOfHelp = gScreenDimensions.LeftColumn + 2;\r
+  LeftColumnOfHelp  = gScreenDimensions.LeftColumn + 1;\r
+  RightColumnOfHelp = gScreenDimensions.RightColumn - 2;\r
+  TopRowOfHelp      = gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight + 1;\r
+  BottomRowOfHelp   = gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - 2;\r
+\r
+  ClearLines (LeftColumnOfHelp, RightColumnOfHelp, TopRowOfHelp, BottomRowOfHelp, KEYHELP_TEXT | KEYHELP_BACKGROUND);\r
+  if (Statement == NULL) {\r
+    //\r
+    // Print Key for Form without showable statement.\r
+    //\r
+    PrintHotKeyHelpString (FormData);\r
+    PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString);\r
+    return;\r
+  }\r
+\r
+  HexDisplay = FALSE;\r
+  NumericOp = NULL;\r
+  DateOp    = NULL;\r
+  TimeOp    = NULL;\r
+  if (Statement->OpCode->OpCode == EFI_IFR_NUMERIC_OP) {\r
+    NumericOp = (EFI_IFR_NUMERIC *) Statement->OpCode;\r
+    HexDisplay = (NumericOp->Flags & EFI_IFR_DISPLAY_UINT_HEX) == EFI_IFR_DISPLAY_UINT_HEX;\r
+  } else if (Statement->OpCode->OpCode == EFI_IFR_DATE_OP) {\r
+    DateOp   = (EFI_IFR_DATE *) Statement->OpCode;\r
+    HexDisplay = (DateOp->Flags & EFI_IFR_DISPLAY_UINT_HEX) == EFI_IFR_DISPLAY_UINT_HEX;\r
+  } else if (Statement->OpCode->OpCode == EFI_IFR_TIME_OP) {\r
+    TimeOp  = (EFI_IFR_TIME *) Statement->OpCode;\r
+    HexDisplay = (TimeOp->Flags & EFI_IFR_DISPLAY_UINT_HEX) == EFI_IFR_DISPLAY_UINT_HEX;\r
+  }  \r
+  switch (Statement->OpCode->OpCode) {\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
+    if (!Selected) {\r
+        PrintHotKeyHelpString (FormData);\r
+\r
+      if ((gClassOfVfr & FORMSET_CLASS_PLATFORM_SETUP) == FORMSET_CLASS_PLATFORM_SETUP) {\r
+        PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString);\r
+      }\r
+\r
+      if ((Statement->OpCode->OpCode == EFI_IFR_DATE_OP) ||\r
+          (Statement->OpCode->OpCode == EFI_IFR_TIME_OP)) {\r
+        PrintAt (\r
+          0, \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, gEnterString);\r
+        PrintStringAt (StartColumnOfHelp, TopRowOfHelp, gAdjustNumber);\r
+      } else {\r
+        PrintAt (0, StartColumnOfHelp, BottomRowOfHelp, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight);\r
+        if (Statement->OpCode->OpCode == EFI_IFR_NUMERIC_OP && NumericOp != NULL && LibGetFieldFromNum(Statement->OpCode) != 0) {\r
+          PrintStringAt (StartColumnOfHelp, TopRowOfHelp, gAdjustNumber);\r
+        } \r
+        PrintStringAt (SecCol, BottomRowOfHelp, gEnterString);\r
+      }\r
+    } else {\r
+      PrintStringAt (SecCol, BottomRowOfHelp, gEnterCommitString);\r
+\r
+      //\r
+      // If it is a selected numeric with manual input, display different message\r
+      //\r
+      if ((Statement->OpCode->OpCode == EFI_IFR_NUMERIC_OP) || \r
+          (Statement->OpCode->OpCode == EFI_IFR_DATE_OP) ||\r
+          (Statement->OpCode->OpCode == EFI_IFR_TIME_OP)) {\r
+        PrintStringAt (\r
+          SecCol,\r
+          TopRowOfHelp,\r
+          HexDisplay ? gHexNumericInput : gDecNumericInput\r
+          );\r
+      } else if (Statement->OpCode->OpCode != EFI_IFR_ORDERED_LIST_OP) {\r
+        PrintAt (0, StartColumnOfHelp, BottomRowOfHelp, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight);\r
+      }\r
+\r
+      if (Statement->OpCode->OpCode == EFI_IFR_ORDERED_LIST_OP) {\r
+        PrintStringAt (StartColumnOfHelp, TopRowOfHelp, gPlusString);\r
+        PrintStringAt (ThdCol, TopRowOfHelp, gMinusString);\r
+      }\r
+\r
+      PrintStringAt (ThdCol, BottomRowOfHelp, gEnterEscapeString);\r
+    }\r
+    break;\r
+\r
+  case EFI_IFR_CHECKBOX_OP:\r
+    PrintHotKeyHelpString (FormData);\r
+\r
+    if ((gClassOfVfr & FORMSET_CLASS_PLATFORM_SETUP) == FORMSET_CLASS_PLATFORM_SETUP) {\r
+      PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString);\r
+    }\r
+\r
+    PrintAt (0, StartColumnOfHelp, BottomRowOfHelp, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight);\r
+    PrintStringAt (SecCol, BottomRowOfHelp, gToggleCheckBox);\r
+    break;\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
+  case EFI_IFR_SUBTITLE_OP:\r
+     if (!Selected) {\r
+      PrintHotKeyHelpString (FormData);\r
+\r
+      if ((gClassOfVfr & FORMSET_CLASS_PLATFORM_SETUP) == FORMSET_CLASS_PLATFORM_SETUP) {\r
+        PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString);\r
+      }\r
+\r
+      PrintAt (0, StartColumnOfHelp, BottomRowOfHelp, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight);\r
+      if (Statement->OpCode->OpCode != EFI_IFR_TEXT_OP && Statement->OpCode->OpCode != EFI_IFR_SUBTITLE_OP) {\r
+        PrintStringAt (SecCol, BottomRowOfHelp, gEnterString);\r
+      }\r
+    } else {\r
+      if (Statement->OpCode->OpCode  != EFI_IFR_REF_OP) {\r
+        PrintStringAt (\r
+          (gScreenDimensions.RightColumn - LibGetStringWidth (gEnterCommitString) / 2) / 2,\r
+          BottomRowOfHelp,\r
+          gEnterCommitString\r
+          );\r
+        PrintStringAt (ThdCol, BottomRowOfHelp, gEnterEscapeString);\r
+      }\r
+    }\r
+    break;\r
+\r
+  default:\r
+    break;\r
+  }  \r
+}\r
+\r
+/**\r
+  Update status bar.\r
+\r
+  This function updates the status bar on the bottom of menu screen. It just shows StatusBar. \r
+  Original logic in this function should be splitted out.\r
+\r
+  @param[in]  MessageType            The type of message to be shown. InputError or Configuration Changed. \r
+  @param[in]  State                  Show or Clear Message.\r
+**/\r
+VOID\r
+EFIAPI\r
+UpdateStatusBar (\r
+  IN  UINTN                  MessageType,\r
+  IN  BOOLEAN                State\r
+  )\r
+{\r
+  UINTN           Index;\r
+  CHAR16          OptionWidth;\r
+\r
+  OptionWidth = (CHAR16) ((gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn) / 3);\r
+\r
+  switch (MessageType) {\r
+  case INPUT_ERROR:\r
+    if (State) {\r
+      gST->ConOut->SetAttribute (gST->ConOut, ERROR_TEXT);\r
+      PrintStringAt (\r
+        gScreenDimensions.LeftColumn + OptionWidth,\r
+        gScreenDimensions.BottomRow - 1,\r
+        gInputErrorMessage\r
+        );\r
+    } else {\r
+      gST->ConOut->SetAttribute (gST->ConOut, KEYHELP_BACKGROUND);\r
+      for (Index = 0; Index < (LibGetStringWidth (gInputErrorMessage) - 2) / 2; Index++) {\r
+        PrintStringAt (gScreenDimensions.LeftColumn + OptionWidth + Index, gScreenDimensions.BottomRow - 1, L"  ");\r
+      }\r
+    }\r
+    break;\r
+\r
+  case NV_UPDATE_REQUIRED:\r
+    //\r
+    // Global setting support. Show configuration change on every form.\r
+    //\r
+    if (State) {\r
+      gST->ConOut->SetAttribute (gST->ConOut, INFO_TEXT);\r
+      PrintStringAt (\r
+        gScreenDimensions.LeftColumn + OptionWidth * 2,\r
+        gScreenDimensions.BottomRow - 1,\r
+        gNvUpdateMessage\r
+        );\r
+    } else {\r
+      gST->ConOut->SetAttribute (gST->ConOut, KEYHELP_BACKGROUND);\r
+      for (Index = 0; Index < (LibGetStringWidth (gNvUpdateMessage) - 2) / 2; Index++) {\r
+        PrintStringAt (\r
+          (gScreenDimensions.LeftColumn + OptionWidth * 2 + Index),\r
+          gScreenDimensions.BottomRow - 1,\r
+          L"  "\r
+          );\r
+      }\r
+    }\r
+    break;\r
+\r
+  default:\r
+    break;\r
+  } \r
+}\r
+\r
+/**\r
+  Create popup window. It will replace CreateDialog(). \r
+\r
+  This function draws OEM/Vendor specific pop up windows.\r
+\r
+  @param[out]  Key    User Input Key\r
+  @param       ...    String to be shown in Popup. The variable argument list is terminated by a NULL.\r
+  \r
+**/\r
+VOID\r
+EFIAPI\r
+CreateDialog (\r
+  OUT EFI_INPUT_KEY  *Key,        OPTIONAL\r
+  ...\r
+  )\r
+{\r
+  VA_LIST       Marker;\r
+  EFI_INPUT_KEY KeyValue;\r
+  EFI_STATUS    Status;\r
+  UINTN         LargestString;\r
+  UINTN         LineNum;\r
+  UINTN   Index;\r
+  UINTN   Count;\r
+  CHAR16  Character;\r
+  UINTN   Start;\r
+  UINTN   End;\r
+  UINTN   Top;\r
+  UINTN   Bottom;\r
+  CHAR16  *String;\r
+  UINTN   DimensionsWidth;\r
+  UINTN   DimensionsHeight;\r
+  UINTN   CurrentAttribute;\r
+\r
+  //\r
+  // If screen dimension info is not ready, get it from console.\r
+  //\r
+  if (gScreenDimensions.RightColumn == 0 || gScreenDimensions.BottomRow == 0) {\r
+    ZeroMem (&gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));\r
+    gST->ConOut->QueryMode (\r
+                   gST->ConOut,\r
+                   gST->ConOut->Mode->Mode,\r
+                   &gScreenDimensions.RightColumn,\r
+                   &gScreenDimensions.BottomRow\r
+                   );\r
+  }\r
+\r
+  DimensionsWidth   = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn;\r
+  DimensionsHeight  = gScreenDimensions.BottomRow - gScreenDimensions.TopRow;\r
+\r
+  LargestString = 0;\r
+  LineNum       = 0;\r
+  VA_START (Marker, Key);\r
+  while  ((String = VA_ARG (Marker, CHAR16 *)) != NULL) {\r
+    LineNum ++;\r
+    \r
+    if ((LibGetStringWidth (String) / 2) > LargestString) {\r
+      LargestString = (LibGetStringWidth (String) / 2);\r
+    }\r
+  } \r
+  VA_END (Marker);\r
+\r
+  if ((LargestString + 2) > DimensionsWidth) {\r
+    LargestString = DimensionsWidth - 2;\r
+  }\r
+  \r
+  CurrentAttribute  = gST->ConOut->Mode->Attribute;  \r
+  gST->ConOut->EnableCursor (gST->ConOut, FALSE);\r
+  gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ());\r
+\r
+  //\r
+  // Subtract the PopUp width from total Columns, allow for one space extra on\r
+  // each end plus a border.\r
+  //\r
+  Start     = (DimensionsWidth - LargestString - 2) / 2 + gScreenDimensions.LeftColumn + 1;\r
+  End       = Start + LargestString + 1;\r
+\r
+  Top       = ((DimensionsHeight - LineNum - 2) / 2) + gScreenDimensions.TopRow - 1;\r
+  Bottom    = Top + LineNum + 2;\r
+\r
+  Character = BOXDRAW_DOWN_RIGHT;\r
+  PrintCharAt (Start, Top, Character);\r
+  Character = BOXDRAW_HORIZONTAL;\r
+  for (Index = Start; Index + 2 < End; Index++) {\r
+    PrintCharAt ((UINTN)-1, (UINTN)-1, Character);\r
+  }\r
+\r
+  Character = BOXDRAW_DOWN_LEFT;\r
+  PrintCharAt ((UINTN)-1, (UINTN)-1, Character);\r
+  Character = BOXDRAW_VERTICAL;\r
+\r
+  Count = 0;\r
+  VA_START (Marker, Key);\r
+  for (Index = Top; Index + 2 < Bottom; Index++, Count++) {\r
+    String = VA_ARG (Marker, CHAR16*);\r
+\r
+    if (String[0] == CHAR_NULL) {\r
+      //\r
+      // Passing in a NULL results in a blank space\r
+      //\r
+      ClearLines (Start, End, Index + 1, Index + 1, GetPopupColor ());\r
+    } else if (String[0] == L' ') {\r
+      //\r
+      // Passing in a space results in the assumption that this is where typing will occur\r
+      //\r
+      ClearLines (Start + 1, End - 1, Index + 1, Index + 1, POPUP_INVERSE_TEXT | POPUP_INVERSE_BACKGROUND);\r
+      PrintStringAt (\r
+        ((DimensionsWidth - LibGetStringWidth (String) / 2) / 2) + gScreenDimensions.LeftColumn + 1,\r
+        Index + 1,\r
+        String + 1\r
+        );\r
+    } else {\r
+      //\r
+      // This will clear the background of the line - we never know who might have been\r
+      // here before us.  This differs from the next clear in that it used the non-reverse\r
+      // video for normal printing.\r
+      //\r
+      ClearLines (Start, End, Index + 1, Index + 1, GetPopupColor ());\r
+      PrintStringAt (\r
+        ((DimensionsWidth - LibGetStringWidth (String) / 2) / 2) + gScreenDimensions.LeftColumn + 1,\r
+        Index + 1,\r
+        String\r
+        );\r
+    }\r
+\r
+    gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ());\r
+    PrintCharAt (Start, Index + 1, Character);\r
+    PrintCharAt (End - 1, Index + 1, Character);\r
+  }\r
+  VA_END (Marker);\r
+\r
+  Character = BOXDRAW_UP_RIGHT;\r
+  PrintCharAt (Start, Bottom - 1, Character);\r
+  Character = BOXDRAW_HORIZONTAL;\r
+  for (Index = Start; Index + 2 < End; Index++) {\r
+    PrintCharAt ((UINTN)-1, (UINTN) -1, Character);\r
+  }\r
+\r
+  Character = BOXDRAW_UP_LEFT;\r
+  PrintCharAt ((UINTN)-1, (UINTN) -1, Character);\r
+\r
+  if (Key != NULL) {\r
+    Status = WaitForKeyStroke (&KeyValue);\r
+    ASSERT_EFI_ERROR (Status);\r
+    CopyMem (Key, &KeyValue, sizeof (EFI_INPUT_KEY));\r
+  }\r
+\r
+  gST->ConOut->SetAttribute (gST->ConOut, CurrentAttribute);\r
+  gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
+}\r
+\r
+/**\r
+  Confirm how to handle the changed data. \r
+  \r
+  @return Action BROWSER_ACTION_SUBMIT, BROWSER_ACTION_DISCARD or other values.\r
+**/\r
+UINTN\r
+EFIAPI\r
+ConfirmDataChange (\r
+  VOID\r
+  )\r
+{\r
+  CHAR16                  YesResponse;\r
+  CHAR16                  NoResponse;\r
+  EFI_INPUT_KEY           Key;\r
+\r
+  gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
+  \r
+  YesResponse = gYesResponse[0];\r
+  NoResponse  = gNoResponse[0];\r
+  \r
+  //\r
+  // If NV flag is up, prompt user\r
+  //\r
+  do {\r
+    CreateDialog (&Key, gLibEmptyString, gSaveChanges, gAreYouSure, gLibEmptyString, NULL);\r
+  } while\r
+  (\r
+    (Key.ScanCode != SCAN_ESC) &&\r
+    ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (NoResponse | UPPER_LOWER_CASE_OFFSET)) &&\r
+    ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (YesResponse | UPPER_LOWER_CASE_OFFSET))\r
+  );\r
+  \r
+  if (Key.ScanCode == SCAN_ESC) {\r
+    return BROWSER_ACTION_NONE;\r
+  } else if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (YesResponse | UPPER_LOWER_CASE_OFFSET)) {\r
+    return BROWSER_ACTION_SUBMIT;\r
+  } else {\r
+    return BROWSER_ACTION_DISCARD;\r
+  }\r
+}\r
+\r
+/**\r
+  OEM specifies whether Setup exits Page by ESC key.\r
+\r
+  This function customized the behavior that whether Setup exits Page so that \r
+  system able to boot when configuration is not changed.\r
+\r
+  @retval  TRUE     Exits FrontPage\r
+  @retval  FALSE    Don't exit FrontPage.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+FormExitPolicy (\r
+  VOID\r
+  )\r
+{\r
+  return (gClassOfVfr & FORMSET_CLASS_FRONT_PAGE) == FORMSET_CLASS_FRONT_PAGE ? FALSE : TRUE;\r
+}\r
+\r
+/**\r
+  Set Timeout value for a ceratain Form to get user response. \r
+  \r
+  This function allows to set timeout value on a ceratain form if necessary.\r
+  If timeout is not zero, the form will exit if user has no response in timeout. \r
+  \r
+  @param[in]  FormData   Form Data to be shown in Page\r
+\r
+  @return 0     No timeout for this form. \r
+  @return > 0   Timeout value in 100 ns units.\r
+**/\r
+UINT64\r
+EFIAPI\r
+FormExitTimeout (\r
+  IN FORM_DISPLAY_ENGINE_FORM      *FormData\r
+  )\r
+{\r
+  return 0;\r
+}\r
+//\r
+// Print Functions\r
+//\r
+/**\r
+  Prints a unicode string to the default console, at\r
+  the supplied cursor position, using L"%s" format.\r
+\r
+  @param  Column     The cursor position to print the string at. When it is -1, use current Position.\r
+  @param  Row        The cursor position to print the string at. When it is -1, use current Position.\r
+  @param  String     String pointer.\r
+\r
+  @return Length of string printed to the console\r
+\r
+**/\r
+UINTN\r
+EFIAPI\r
+PrintStringAt (\r
+  IN UINTN     Column,\r
+  IN UINTN     Row,\r
+  IN CHAR16    *String\r
+  )\r
+{\r
+  return PrintAt (0, Column, Row, L"%s", String);\r
+}\r
+\r
+/**\r
+  Prints a unicode string to the default console, at\r
+  the supplied cursor position, using L"%s" format.\r
+\r
+  @param  Column     The cursor position to print the string at. When it is -1, use current Position.\r
+  @param  Row        The cursor position to print the string at. When it is -1, use current Position.\r
+  @param  String     String pointer.\r
+  @param  Width      Width for String.\r
+\r
+  @return Length of string printed to the console\r
+\r
+**/\r
+UINTN\r
+EFIAPI\r
+PrintStringAtWithWidth (\r
+  IN UINTN     Column,\r
+  IN UINTN     Row,\r
+  IN CHAR16    *String,\r
+  IN UINTN     Width\r
+  )\r
+{\r
+  return PrintAt (Width, Column, Row, L"%s", String);\r
+}\r
+\r
+/**\r
+  Prints a chracter to the default console, at\r
+  the supplied cursor position, using L"%c" format.\r
+\r
+  @param  Column     The cursor position to print the string at. When it is -1, use current Position.\r
+  @param  Row        The cursor position to print the string at. When it is -1, use current Position.\r
+  @param  Character  Character to print.\r
+\r
+  @return Length of string printed to the console.\r
+\r
+**/\r
+UINTN\r
+EFIAPI\r
+PrintCharAt (\r
+  IN UINTN     Column,\r
+  IN UINTN     Row,\r
+  CHAR16       Character\r
+  )\r
+{\r
+  return PrintAt (0, Column, Row, L"%c", Character);\r
+}\r
+\r
+/**\r
+  Clear retangle with specified text attribute.\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
+\r
+**/\r
+VOID\r
+EFIAPI\r
+ClearLines (\r
+  IN UINTN               LeftColumn,\r
+  IN UINTN               RightColumn,\r
+  IN UINTN               TopRow,\r
+  IN UINTN               BottomRow,\r
+  IN UINTN               TextAttribute\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
+\r
+  //\r
+  // Set foreground and background as defined\r
+  //\r
+  gST->ConOut->SetAttribute (gST->ConOut, TextAttribute);\r
+\r
+  //\r
+  // Much faster to buffer the long string instead of print it a character at a time\r
+  //\r
+  LibSetUnicodeMem (Buffer, RightColumn - LeftColumn, L' ');\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
+  }\r
+\r
+  gST->ConOut->SetCursorPosition (gST->ConOut, LeftColumn, TopRow);\r
+\r
+  FreePool (Buffer);\r
+}\r
+\r
+//\r
+// Color Setting Functions\r
+//\r
+\r
+/**\r
+  Get OEM/Vendor specific popup attribute colors.\r
+\r
+  @retval  Byte code color setting for popup color.\r
+**/\r
+UINT8\r
+EFIAPI\r
+GetPopupColor (\r
+  VOID\r
+  )\r
+{\r
+  return POPUP_TEXT | POPUP_BACKGROUND;\r
+}\r
+\r
+/**\r
+  Get OEM/Vendor specific popup attribute colors.\r
+\r
+  @retval  Byte code color setting for popup inverse color.\r
+**/\r
+UINT8\r
+EFIAPI\r
+GetPopupInverseColor (\r
+  VOID\r
+  )\r
+{\r
+  return POPUP_INVERSE_TEXT | POPUP_INVERSE_BACKGROUND;\r
+}\r
+\r
+/**\r
+  Get OEM/Vendor specific PickList color attribute.\r
+\r
+  @retval  Byte code color setting for pick list color.\r
+**/\r
+UINT8\r
+EFIAPI\r
+GetPickListColor (\r
+  VOID\r
+  )\r
+{\r
+  return PICKLIST_HIGHLIGHT_TEXT | PICKLIST_HIGHLIGHT_BACKGROUND;\r
+}\r
+\r
+/**\r
+  Get OEM/Vendor specific arrow color attribute.\r
+\r
+  @retval  Byte code color setting for arrow color.\r
+**/\r
+UINT8\r
+EFIAPI\r
+GetArrowColor (\r
+  VOID\r
+  )\r
+{\r
+  return ARROW_TEXT | ARROW_BACKGROUND;\r
+}\r
+\r
+/**\r
+  Get OEM/Vendor specific info text color attribute.\r
+\r
+  @retval  Byte code color setting for info text color.\r
+**/\r
+UINT8\r
+EFIAPI\r
+GetInfoTextColor (\r
+  VOID\r
+  )\r
+{\r
+  return INFO_TEXT | FIELD_BACKGROUND;\r
+}\r
+\r
+/**\r
+  Get OEM/Vendor specific help text color attribute.\r
+\r
+  @retval  Byte code color setting for help text color.\r
+**/\r
+UINT8\r
+EFIAPI\r
+GetHelpTextColor (\r
+  VOID\r
+  )\r
+{\r
+  return HELP_TEXT | FIELD_BACKGROUND;\r
+}\r
+\r
+/**\r
+  Get OEM/Vendor specific grayed out text color attribute.\r
+\r
+  @retval  Byte code color setting for grayed out text color.\r
+**/\r
+UINT8\r
+EFIAPI\r
+GetGrayedTextColor (\r
+  VOID\r
+  )\r
+{\r
+  return FIELD_TEXT_GRAYED | FIELD_BACKGROUND;\r
+}\r
+\r
+/**\r
+  Get OEM/Vendor specific highlighted text color attribute.\r
+\r
+  @retval  Byte code color setting for highlight text color.\r
+**/\r
+UINT8\r
+EFIAPI\r
+GetHighlightTextColor (\r
+  VOID\r
+  )\r
+{\r
+  return PcdGet8 (PcdBrowserFieldTextHighlightColor) | PcdGet8 (PcdBrowserFieldBackgroundHighlightColor);\r
+}\r
+\r
+/**\r
+  Get OEM/Vendor specific field text color attribute.\r
+\r
+  @retval  Byte code color setting for field text color.\r
+**/\r
+UINT8\r
+EFIAPI\r
+GetFieldTextColor (\r
+  VOID\r
+  )\r
+{\r
+  return PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND;\r
+}\r
+\r
+/**\r
+  Get OEM/Vendor specific subtitle text color attribute.\r
+\r
+  @retval  Byte code color setting for subtitle text color.\r
+**/\r
+UINT8\r
+EFIAPI\r
+GetSubTitleTextColor (\r
+  VOID\r
+  )\r
+{\r
+  return PcdGet8 (PcdBrowserSubtitleTextColor) | FIELD_BACKGROUND;\r
+}\r
+\r
+/**\r
+  Clear Screen to the initial state.\r
+**/\r
+VOID\r
+EFIAPI \r
+ClearDisplayPage (\r
+  VOID\r
+  )\r
+{\r
+  gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
+  gST->ConOut->ClearScreen (gST->ConOut);\r
+  gLastClassOfVfr = 0;\r
+}\r
+\r
+/**\r
+  Constructor of Customized Display Library Instance.\r
+\r
+  @param  ImageHandle   The firmware allocated handle for the EFI image.\r
+  @param  SystemTable   A pointer to the EFI System Table.\r
+\r
+  @retval EFI_SUCCESS   The constructor always returns EFI_SUCCESS.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CustomizedDisplayLibConstructor (\r
+  IN      EFI_HANDLE                ImageHandle,\r
+  IN      EFI_SYSTEM_TABLE          *SystemTable\r
+  )\r
+{\r
+  mCDLStringPackHandle = HiiAddPackages (&gCustomizedDisplayLibGuid, ImageHandle, CustomizedDisplayLibStrings, NULL);\r
+  ASSERT (mCDLStringPackHandle != NULL);\r
+\r
+  InitializeLibStrings();\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Destructor of Customized Display Library Instance.\r
+\r
+  @param  ImageHandle   The firmware allocated handle for the EFI image.\r
+  @param  SystemTable   A pointer to the EFI System Table.\r
+\r
+  @retval EFI_SUCCESS   The destructor completed successfully.\r
+  @retval Other value   The destructor did not complete successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CustomizedDisplayLibDestructor (\r
+  IN EFI_HANDLE        ImageHandle,\r
+  IN EFI_SYSTEM_TABLE  *SystemTable\r
+  )\r
+{\r
+  HiiRemovePackages(mCDLStringPackHandle);\r
+  \r
+  FreeLibStrings ();\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
diff --git a/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf b/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf
new file mode 100644 (file)
index 0000000..ade45b6
--- /dev/null
@@ -0,0 +1,74 @@
+##\r
+#  This file contains an 'Intel Peripheral Driver' and is        \r
+#  licensed for Intel CPUs and chipsets under the terms of your  \r
+#  license agreement with Intel or your vendor.  This file may   \r
+#  be modified by the user, subject to additional terms of the   \r
+#  license agreement                                             \r
+##\r
+## @file\r
+#  \r
+#  General BDS defines and produce general interfaces for platform BDS driver including:\r
+#  1) BDS boot policy interface;\r
+#  2) BDS boot device connect interface;\r
+#  3) BDS Misc interfaces for mainting boot variable, ouput string, etc.\r
+#  \r
+#  Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR>\r
+#  This software and associated documentation (if any) is furnished\r
+#  under a license and may only be used or copied in accordance\r
+#  with the terms of the license. Except as permitted by such\r
+#  license, no part of this software or documentation may be\r
+#  reproduced, stored in a retrieval system, or transmitted in any\r
+#  form or by any means without the express written consent of\r
+#  Intel Corporation.\r
+#  \r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = CustomizedDisplayLib\r
+  FILE_GUID                      = 80B92017-EC64-4923-938D-94FAEE85832E\r
+  MODULE_TYPE                    = DXE_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+  LIBRARY_CLASS                  = CustomizedDisplayLib|DXE_DRIVER UEFI_APPLICATION\r
+  CONSTRUCTOR                    = CustomizedDisplayLibConstructor\r
+  DESTRUCTOR                     = CustomizedDisplayLibDestructor\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources]\r
+  CustomizedDisplayLib.c\r
+  Colors.h\r
+  CustomizedDisplayLibInternal.h\r
+  CustomizedDisplayLibInternal.c\r
+  CustomizedDisplayLib.uni\r
+  \r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+\r
+[LibraryClasses]\r
+  MemoryAllocationLib\r
+  BaseLib\r
+  UefiBootServicesTableLib\r
+  UefiDriverEntryPoint\r
+  UefiRuntimeServicesTableLib\r
+  BaseMemoryLib\r
+  DebugLib\r
+  PrintLib\r
+  HiiLib\r
+  DevicePathLib\r
+  PcdLib\r
+\r
+[Guids]\r
+  gEfiIfrTianoGuid\r
+  \r
+[Protocols]\r
+\r
+[Pcd]\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdBrowserSubtitleTextColor               ## CONSUMES\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdBrowserFieldTextColor                  ## CONSUMES\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdBrowserFieldTextHighlightColor         ## CONSUMES\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdBrowserFieldBackgroundHighlightColor   ## CONSUMES
\ No newline at end of file
diff --git a/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.uni b/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.uni
new file mode 100644 (file)
index 0000000..18a5c3b
Binary files /dev/null and b/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.uni differ
diff --git a/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLibInternal.c b/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLibInternal.c
new file mode 100644 (file)
index 0000000..9b6ddb5
--- /dev/null
@@ -0,0 +1,937 @@
+/** @file\r
+\r
+  This library class defines a set of interfaces to customize Display module\r
+\r
+Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials are licensed and made available under \r
+the terms and conditions of the BSD License that accompanies this distribution.  \r
+The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php.                                            \r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+#include "CustomizedDisplayLibInternal.h"\r
+\r
+EFI_SCREEN_DESCRIPTOR         gScreenDimensions;\r
+CHAR16                        *mLibUnknownString;\r
+extern EFI_HII_HANDLE         mCDLStringPackHandle;\r
+CHAR16                        *mSpaceBuffer;\r
+#define SPACE_BUFFER_SIZE      1000\r
+\r
+//\r
+// Browser Global Strings\r
+//\r
+CHAR16            *gEnterString;\r
+CHAR16            *gEnterCommitString;\r
+CHAR16            *gEnterEscapeString;\r
+CHAR16            *gEscapeString;\r
+CHAR16            *gMoveHighlight;\r
+CHAR16            *gDecNumericInput;\r
+CHAR16            *gHexNumericInput;\r
+CHAR16            *gToggleCheckBox;\r
+CHAR16            *gLibEmptyString;\r
+CHAR16            *gAreYouSure;\r
+CHAR16            *gYesResponse;\r
+CHAR16            *gNoResponse;\r
+CHAR16            *gPlusString;\r
+CHAR16            *gMinusString;\r
+CHAR16            *gAdjustNumber;\r
+CHAR16            *gSaveChanges;\r
+CHAR16            *gNvUpdateMessage;\r
+CHAR16            *gInputErrorMessage;\r
+\r
+/**\r
+\r
+  Print banner info for front page.\r
+\r
+  @param[in]  FormData             Form Data to be shown in Page\r
+  \r
+**/\r
+VOID\r
+PrintBannerInfo ( \r
+  IN FORM_DISPLAY_ENGINE_FORM       *FormData\r
+  )\r
+{\r
+  UINT8                  Line;\r
+  UINT8                  Alignment;\r
+  CHAR16                 *StrFrontPageBanner;\r
+  UINT8                  RowIdx;\r
+  UINT8                  ColumnIdx;\r
+\r
+  //\r
+  //    ClearLines(0, LocalScreen.RightColumn, 0, BANNER_HEIGHT-1, BANNER_TEXT | BANNER_BACKGROUND);\r
+  //\r
+  ClearLines (\r
+    gScreenDimensions.LeftColumn,\r
+    gScreenDimensions.RightColumn,\r
+    gScreenDimensions.TopRow,\r
+    FRONT_PAGE_HEADER_HEIGHT - 1 + gScreenDimensions.TopRow,\r
+    BANNER_TEXT | BANNER_BACKGROUND\r
+    );\r
+\r
+  //\r
+  //    for (Line = 0; Line < BANNER_HEIGHT; Line++) {\r
+  //\r
+  for (Line = (UINT8) gScreenDimensions.TopRow; Line < BANNER_HEIGHT + (UINT8) gScreenDimensions.TopRow; Line++) {\r
+    //\r
+    //      for (Alignment = 0; Alignment < BANNER_COLUMNS; Alignment++) {\r
+    //\r
+    for (Alignment = (UINT8) gScreenDimensions.LeftColumn;\r
+         Alignment < BANNER_COLUMNS + (UINT8) gScreenDimensions.LeftColumn;\r
+         Alignment++\r
+        ) {\r
+      RowIdx    = (UINT8) (Line - (UINT8) gScreenDimensions.TopRow);\r
+      ColumnIdx = (UINT8) (Alignment - (UINT8) gScreenDimensions.LeftColumn);\r
+  \r
+      ASSERT (RowIdx < BANNER_HEIGHT && ColumnIdx < BANNER_COLUMNS);\r
+  \r
+      if (gBannerData!= NULL && gBannerData->Banner[RowIdx][ColumnIdx] != 0x0000) {\r
+        StrFrontPageBanner = LibGetToken (gBannerData->Banner[RowIdx][ColumnIdx], FormData->HiiHandle);\r
+      } else {\r
+        continue;\r
+      }\r
+  \r
+      switch (Alignment - gScreenDimensions.LeftColumn) {\r
+      case 0:\r
+        //\r
+        // Handle left column\r
+        //\r
+        PrintStringAt (gScreenDimensions.LeftColumn + BANNER_LEFT_COLUMN_INDENT, Line, StrFrontPageBanner);\r
+        break;\r
+  \r
+      case 1:\r
+        //\r
+        // Handle center column\r
+        //\r
+        PrintStringAt (\r
+          gScreenDimensions.LeftColumn + (gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn) / 3,\r
+          Line,\r
+          StrFrontPageBanner\r
+          );\r
+        break;\r
+  \r
+      case 2:\r
+        //\r
+        // Handle right column\r
+        //\r
+        PrintStringAt (\r
+          gScreenDimensions.LeftColumn + (gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn) * 2 / 3,\r
+          Line,\r
+          StrFrontPageBanner\r
+          );\r
+        break;\r
+      }\r
+  \r
+      FreePool (StrFrontPageBanner);\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+\r
+  Print framework for a page.\r
+  \r
+**/\r
+VOID\r
+PrintFramework (\r
+  VOID\r
+  )\r
+{\r
+  UINTN                  Index;\r
+  CHAR16                 Character;\r
+  CHAR16                 *Buffer;\r
+  UINTN                  Row;\r
+\r
+  Buffer = AllocateZeroPool (0x10000);\r
+  ASSERT (Buffer != NULL);\r
+  Character = BOXDRAW_HORIZONTAL;\r
+  for (Index = 0; Index + 2 < (gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn); Index++) {\r
+    Buffer[Index] = Character;\r
+  }\r
+\r
+  ClearLines (\r
+    gScreenDimensions.LeftColumn,\r
+    gScreenDimensions.RightColumn,\r
+    gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight,\r
+    gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - 1,\r
+    KEYHELP_TEXT | KEYHELP_BACKGROUND\r
+    );\r
+\r
+  if ((gClassOfVfr & FORMSET_CLASS_PLATFORM_SETUP) == FORMSET_CLASS_PLATFORM_SETUP) {\r
+    ClearLines (\r
+      gScreenDimensions.LeftColumn,\r
+      gScreenDimensions.RightColumn,\r
+      gScreenDimensions.TopRow,\r
+      gScreenDimensions.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
+    PrintCharAt ((UINTN) -1, (UINTN) -1, Character);\r
+    PrintStringAt ((UINTN) -1, (UINTN) -1, Buffer);\r
+\r
+    Character = BOXDRAW_DOWN_LEFT;\r
+    PrintCharAt ((UINTN) -1, (UINTN) -1, Character);\r
+\r
+    Character = BOXDRAW_VERTICAL;\r
+    for (Row = gScreenDimensions.TopRow + 1; Row <= gScreenDimensions.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT - 2; Row++) {\r
+      PrintCharAt (gScreenDimensions.LeftColumn, Row, Character);\r
+      PrintCharAt (gScreenDimensions.RightColumn - 1, Row, Character);\r
+    }\r
+\r
+    Character = BOXDRAW_UP_RIGHT;\r
+    PrintCharAt (gScreenDimensions.LeftColumn, gScreenDimensions.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT - 1, Character);\r
+    PrintStringAt ((UINTN) -1, (UINTN) -1, Buffer);\r
+\r
+    Character = BOXDRAW_UP_LEFT;\r
+    PrintCharAt ((UINTN) -1, (UINTN) -1, Character);\r
+\r
+    //\r
+    // Print Bottom border line\r
+    // +------------------------------------------------------------------------------+\r
+    // ?                                                                             ?\r
+    // +------------------------------------------------------------------------------+\r
+    //\r
+    Character = BOXDRAW_DOWN_RIGHT;\r
+    PrintCharAt (gScreenDimensions.LeftColumn, gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight, Character);\r
+\r
+    PrintStringAt ((UINTN) -1, (UINTN) -1, Buffer);\r
+\r
+    Character = BOXDRAW_DOWN_LEFT;\r
+    PrintCharAt ((UINTN) -1, (UINTN) -1, Character);\r
+    Character = BOXDRAW_VERTICAL;\r
+    for (Row = gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight + 1;\r
+         Row <= gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - 2;\r
+         Row++\r
+        ) {\r
+      PrintCharAt (gScreenDimensions.LeftColumn, Row, Character);\r
+      PrintCharAt (gScreenDimensions.RightColumn - 1, Row, Character);\r
+    }\r
+\r
+    Character = BOXDRAW_UP_RIGHT;\r
+    PrintCharAt (gScreenDimensions.LeftColumn, gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - 1, Character);\r
+\r
+    PrintStringAt ((UINTN) -1, (UINTN) -1, Buffer);\r
+\r
+    Character = BOXDRAW_UP_LEFT;\r
+    PrintCharAt ((UINTN) -1, (UINTN) -1, Character);\r
+  }\r
+  \r
+  FreePool (Buffer);\r
+}\r
+\r
+/**\r
+  Print the form title.\r
+\r
+  @param[in]  FormData             Form Data to be shown in Page\r
+\r
+**/\r
+VOID\r
+PrintFormTitle (\r
+  IN FORM_DISPLAY_ENGINE_FORM       *FormData\r
+  )\r
+{\r
+  CHAR16                 *TitleStr;\r
+\r
+  if ((gClassOfVfr & FORMSET_CLASS_PLATFORM_SETUP) != FORMSET_CLASS_PLATFORM_SETUP) {  \r
+    //\r
+    // Only Setup Page need Title.\r
+    //\r
+    return;\r
+  }\r
+  \r
+  TitleStr = LibGetToken (FormData->FormTitle, FormData->HiiHandle);\r
+  ASSERT (TitleStr != NULL);\r
+  \r
+  gST->ConOut->SetAttribute (gST->ConOut, TITLE_TEXT | TITLE_BACKGROUND);\r
+\r
+  ClearLines (\r
+    gScreenDimensions.LeftColumn + 1,\r
+    gScreenDimensions.RightColumn - 1,\r
+    gScreenDimensions.TopRow + 1,\r
+    gScreenDimensions.TopRow + 1,\r
+    TITLE_TEXT | TITLE_BACKGROUND\r
+    );\r
+\r
+  PrintStringAt (\r
+    (gScreenDimensions.RightColumn + gScreenDimensions.LeftColumn - LibGetStringWidth (TitleStr) / 2) / 2,\r
+    gScreenDimensions.TopRow + 1,\r
+    TitleStr\r
+    );\r
+\r
+  FreePool (TitleStr);\r
+}\r
+\r
+/**\r
+  Process some op code which is not recognized by browser core.\r
+\r
+  @param OpCodeData                  The pointer to the op code buffer.\r
+\r
+  @return EFI_SUCCESS            Pass the statement success.\r
+\r
+**/\r
+VOID\r
+ProcessUserOpcode(\r
+  IN  EFI_IFR_OP_HEADER         *OpCodeData\r
+  )\r
+{\r
+  switch (OpCodeData->OpCode) {\r
+    case EFI_IFR_GUID_OP:     \r
+      if (CompareGuid (&gEfiIfrTianoGuid, (EFI_GUID *)((CHAR8*) OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) {\r
+        //\r
+        // Tiano specific GUIDed opcodes\r
+        //\r
+        switch (((EFI_IFR_GUID_LABEL *) OpCodeData)->ExtendOpCode) {\r
+        case EFI_IFR_EXTEND_OP_LABEL:\r
+          //\r
+          // just ignore label\r
+          //\r
+          break;\r
+\r
+        case EFI_IFR_EXTEND_OP_BANNER:\r
+          //\r
+          // Only in front page form set, we care about the banner data.\r
+          //\r
+          if ((gClassOfVfr & FORMSET_CLASS_FRONT_PAGE) == FORMSET_CLASS_FRONT_PAGE) {\r
+            //\r
+            // Initialize Driver private data\r
+            //\r
+            if (gBannerData == NULL) {\r
+              gBannerData = AllocateZeroPool (sizeof (BANNER_DATA));\r
+              ASSERT (gBannerData != NULL);\r
+            }\r
+            \r
+            CopyMem (\r
+              &gBannerData->Banner[((EFI_IFR_GUID_BANNER *) OpCodeData)->LineNumber][\r
+              ((EFI_IFR_GUID_BANNER *) OpCodeData)->Alignment],\r
+              &((EFI_IFR_GUID_BANNER *) OpCodeData)->Title,\r
+              sizeof (EFI_STRING_ID)\r
+              );\r
+          }\r
+          break;\r
+\r
+        case EFI_IFR_EXTEND_OP_SUBCLASS:\r
+          if (((EFI_IFR_GUID_SUBCLASS *) OpCodeData)->SubClass == EFI_FRONT_PAGE_SUBCLASS) {\r
+            gClassOfVfr = FORMSET_CLASS_FRONT_PAGE;\r
+          }\r
+          break;\r
+\r
+        default:\r
+          break;\r
+        }\r
+      }\r
+      break;\r
+\r
+    default:\r
+      break;\r
+  }\r
+}\r
+\r
+/**\r
+  Process some op codes which is out side of current form.\r
+  \r
+  @param FormData                Pointer to the form data.\r
+\r
+  @return EFI_SUCCESS            Pass the statement success.\r
+\r
+**/\r
+VOID\r
+ProcessExternedOpcode (\r
+  IN FORM_DISPLAY_ENGINE_FORM       *FormData\r
+  )\r
+{\r
+  LIST_ENTRY                    *Link;\r
+  FORM_DISPLAY_ENGINE_STATEMENT *Statement;\r
+\r
+  Link = GetFirstNode (&FormData->StatementListOSF);\r
+  while (!IsNull (&FormData->StatementListOSF, Link)) {\r
+    Statement = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (Link);\r
+    Link = GetNextNode (&FormData->StatementListOSF, Link);\r
+\r
+    ProcessUserOpcode(Statement->OpCode);\r
+  }\r
+\r
+  Link = GetFirstNode (&FormData->StatementListHead);\r
+  while (!IsNull (&FormData->StatementListHead, Link)) {\r
+    Statement = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (Link);\r
+    Link = GetNextNode (&FormData->StatementListHead, Link);\r
+\r
+    ProcessUserOpcode(Statement->OpCode);\r
+  }\r
+}\r
+\r
+/**\r
+  Validate the input screen diemenstion info.\r
+\r
+  @param  FormData               The input form data info.\r
+\r
+  @return EFI_SUCCESS            The input screen info is acceptable.\r
+  @return EFI_INVALID_PARAMETER  The input screen info is not acceptable.\r
+\r
+**/\r
+EFI_STATUS \r
+ScreenDiemensionInfoValidate (\r
+  IN FORM_DISPLAY_ENGINE_FORM       *FormData\r
+  )\r
+{\r
+  LIST_ENTRY           *Link;\r
+  UINTN                Index;\r
+\r
+  //\r
+  // Calculate total number of Register HotKeys. \r
+  //\r
+  Index = 0;\r
+  if (!IsListEmpty (&FormData->HotKeyListHead)){\r
+    Link  = GetFirstNode (&FormData->HotKeyListHead);\r
+    while (!IsNull (&FormData->HotKeyListHead, Link)) {\r
+      Link = GetNextNode (&FormData->HotKeyListHead, Link);\r
+      Index ++;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Show three HotKeys help information on one row.\r
+  //\r
+  gFooterHeight = FOOTER_HEIGHT + (Index / 3);\r
+\r
+\r
+  ZeroMem (&gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));\r
+  gST->ConOut->QueryMode (\r
+                 gST->ConOut,\r
+                 gST->ConOut->Mode->Mode,\r
+                 &gScreenDimensions.RightColumn,\r
+                 &gScreenDimensions.BottomRow\r
+                 );\r
+\r
+  //\r
+  // Check local dimension vs. global dimension.\r
+  //\r
+  if (FormData->ScreenDimensions != NULL) {\r
+    if ((gScreenDimensions.RightColumn < FormData->ScreenDimensions->RightColumn) ||\r
+        (gScreenDimensions.BottomRow < FormData->ScreenDimensions->BottomRow)\r
+        ) {\r
+      return EFI_INVALID_PARAMETER;\r
+    } else {\r
+      //\r
+      // Local dimension validation.\r
+      //\r
+      if ((FormData->ScreenDimensions->RightColumn > FormData->ScreenDimensions->LeftColumn) &&\r
+          (FormData->ScreenDimensions->BottomRow > FormData->ScreenDimensions->TopRow) &&\r
+          ((FormData->ScreenDimensions->RightColumn - FormData->ScreenDimensions->LeftColumn) > 2) &&\r
+          ((FormData->ScreenDimensions->BottomRow - FormData->ScreenDimensions->TopRow) > STATUS_BAR_HEIGHT +\r
+            FRONT_PAGE_HEADER_HEIGHT + gFooterHeight + 3)) {\r
+        CopyMem (&gScreenDimensions, (VOID *) FormData->ScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));\r
+      } else {\r
+        return EFI_INVALID_PARAMETER;\r
+      }\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Get the string based on the StringId and HII Package List Handle.\r
+\r
+  @param  Token                  The String's ID.\r
+  @param  HiiHandle              The package list in the HII database to search for\r
+                                 the specified string.\r
+\r
+  @return The output string.\r
+\r
+**/\r
+CHAR16 *\r
+LibGetToken (\r
+  IN  EFI_STRING_ID                Token,\r
+  IN  EFI_HII_HANDLE               HiiHandle\r
+  )\r
+{\r
+  EFI_STRING  String;\r
+\r
+  String = HiiGetString (HiiHandle, Token, NULL);\r
+  if (String == NULL) {\r
+    String = AllocateCopyPool (StrSize (mLibUnknownString), mLibUnknownString);\r
+    ASSERT (String != NULL);\r
+  }\r
+\r
+  return (CHAR16 *) String;\r
+}\r
+\r
+\r
+/**\r
+  Count the storage space of a Unicode string.\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
+\r
+  If String is NULL, then ASSERT ().\r
+\r
+  @param String          The input string to be counted.\r
+\r
+  @return Storage space for the input string.\r
+\r
+**/\r
+UINTN\r
+LibGetStringWidth (\r
+  IN CHAR16               *String\r
+  )\r
+{\r
+  UINTN Index;\r
+  UINTN Count;\r
+  UINTN IncrementValue;\r
+\r
+  ASSERT (String != NULL);\r
+  if (String == NULL) {\r
+    return 0;\r
+  }\r
+\r
+  Index           = 0;\r
+  Count           = 0;\r
+  IncrementValue  = 1;\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
+    //\r
+    // We hit the null-terminator, we now have a count\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
+\r
+  //\r
+  // Increment by one to include the null-terminator in the size\r
+  //\r
+  Count++;\r
+\r
+  return Count * sizeof (CHAR16);\r
+}\r
+\r
+/**\r
+  Show all registered HotKey help strings on bottom Rows.\r
+\r
+  @param FormData          The curent input form data info.\r
+\r
+**/\r
+VOID\r
+PrintHotKeyHelpString (\r
+  IN FORM_DISPLAY_ENGINE_FORM      *FormData\r
+  )\r
+{\r
+  UINTN                  CurrentCol;\r
+  UINTN                  CurrentRow;\r
+  UINTN                  BottomRowOfHotKeyHelp;\r
+  UINTN                  ColumnWidth;\r
+  UINTN                  Index;\r
+  EFI_SCREEN_DESCRIPTOR  LocalScreen;\r
+  LIST_ENTRY             *Link;\r
+  BROWSER_HOT_KEY        *HotKey;\r
+\r
+  if (IsListEmpty (&FormData->HotKeyListHead)) {\r
+    return;\r
+  }\r
+\r
+  CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));\r
+  ColumnWidth            = (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 3;\r
+  BottomRowOfHotKeyHelp  = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 3;\r
+\r
+  //\r
+  // Calculate total number of Register HotKeys. \r
+  //\r
+  Index = 0;\r
+  Link  = GetFirstNode (&FormData->HotKeyListHead);\r
+  while (!IsNull (&FormData->HotKeyListHead, Link)) {\r
+    HotKey = BROWSER_HOT_KEY_FROM_LINK (Link);\r
+    //\r
+    // Help string can't exceed ColumnWidth. One Row will show three Help information. \r
+    //\r
+    if (StrLen (HotKey->HelpString) > ColumnWidth) {\r
+      HotKey->HelpString[ColumnWidth] = L'\0';\r
+    }\r
+    //\r
+    // Calculate help information Column and Row.\r
+    //\r
+    if ((Index % 3) != 2) {\r
+      CurrentCol = LocalScreen.LeftColumn + (2 - Index % 3) * ColumnWidth;\r
+    } else {\r
+      CurrentCol = LocalScreen.LeftColumn + 2;\r
+    }\r
+    CurrentRow = BottomRowOfHotKeyHelp - Index / 3;\r
+    //\r
+    // Print HotKey help string on bottom Row.\r
+    //\r
+    PrintStringAt (CurrentCol, CurrentRow, HotKey->HelpString);\r
+\r
+    //\r
+    // Get Next Hot Key.\r
+    //\r
+    Link = GetNextNode (&FormData->HotKeyListHead, Link);\r
+    Index ++;\r
+  }\r
+  \r
+  return;\r
+}\r
+\r
+/**\r
+  Get step info from numeric opcode.\r
+  \r
+  @param[in] OpCode     The input numeric op code.\r
+\r
+  @return step info for this opcode.\r
+**/\r
+UINT64\r
+LibGetFieldFromNum (\r
+  IN  EFI_IFR_OP_HEADER     *OpCode\r
+  )\r
+{\r
+  EFI_IFR_NUMERIC       *NumericOp;\r
+  UINT64                Step;\r
+\r
+  NumericOp = (EFI_IFR_NUMERIC *) OpCode;\r
+  \r
+  switch (NumericOp->Flags & EFI_IFR_NUMERIC_SIZE) {\r
+  case EFI_IFR_NUMERIC_SIZE_1:\r
+    Step    = NumericOp->data.u8.Step;\r
+    break;\r
+  \r
+  case EFI_IFR_NUMERIC_SIZE_2:\r
+    Step    = NumericOp->data.u16.Step;\r
+    break;\r
+  \r
+  case EFI_IFR_NUMERIC_SIZE_4:\r
+    Step    = NumericOp->data.u32.Step;\r
+    break;\r
+  \r
+  case EFI_IFR_NUMERIC_SIZE_8:\r
+    Step    = NumericOp->data.u64.Step;\r
+    break;\r
+  \r
+  default:\r
+    Step = 0;\r
+    break;\r
+  }\r
+\r
+  return Step;\r
+}\r
+\r
+/**\r
+  Initialize the HII String Token to the correct values.\r
+\r
+**/\r
+VOID\r
+InitializeLibStrings (\r
+  VOID\r
+  )\r
+{\r
+  mLibUnknownString        = L"!";\r
+\r
+  gEnterString          = LibGetToken (STRING_TOKEN (ENTER_STRING), mCDLStringPackHandle);\r
+  gEnterCommitString    = LibGetToken (STRING_TOKEN (ENTER_COMMIT_STRING), mCDLStringPackHandle);\r
+  gEnterEscapeString    = LibGetToken (STRING_TOKEN (ENTER_ESCAPE_STRING), mCDLStringPackHandle);\r
+  gEscapeString         = LibGetToken (STRING_TOKEN (ESCAPE_STRING), mCDLStringPackHandle);\r
+  gMoveHighlight        = LibGetToken (STRING_TOKEN (MOVE_HIGHLIGHT), mCDLStringPackHandle);\r
+  gDecNumericInput      = LibGetToken (STRING_TOKEN (DEC_NUMERIC_INPUT), mCDLStringPackHandle);\r
+  gHexNumericInput      = LibGetToken (STRING_TOKEN (HEX_NUMERIC_INPUT), mCDLStringPackHandle);\r
+  gToggleCheckBox       = LibGetToken (STRING_TOKEN (TOGGLE_CHECK_BOX), mCDLStringPackHandle);\r
+\r
+  gAreYouSure           = LibGetToken (STRING_TOKEN (ARE_YOU_SURE), mCDLStringPackHandle);\r
+  gYesResponse          = LibGetToken (STRING_TOKEN (ARE_YOU_SURE_YES), mCDLStringPackHandle);\r
+  gNoResponse           = LibGetToken (STRING_TOKEN (ARE_YOU_SURE_NO), mCDLStringPackHandle);\r
+  gPlusString           = LibGetToken (STRING_TOKEN (PLUS_STRING), mCDLStringPackHandle);\r
+  gMinusString          = LibGetToken (STRING_TOKEN (MINUS_STRING), mCDLStringPackHandle);\r
+  gAdjustNumber         = LibGetToken (STRING_TOKEN (ADJUST_NUMBER), mCDLStringPackHandle);\r
+  gSaveChanges          = LibGetToken (STRING_TOKEN (SAVE_CHANGES), mCDLStringPackHandle);\r
+\r
+  gLibEmptyString       = LibGetToken (STRING_TOKEN (EMPTY_STRING), mCDLStringPackHandle);\r
+\r
+  gNvUpdateMessage      = LibGetToken (STRING_TOKEN (NV_UPDATE_MESSAGE), mCDLStringPackHandle);\r
+  gInputErrorMessage    = LibGetToken (STRING_TOKEN (INPUT_ERROR_MESSAGE), mCDLStringPackHandle);\r
+  \r
+  //\r
+  // SpaceBuffer;\r
+  //\r
+  mSpaceBuffer = AllocatePool ((SPACE_BUFFER_SIZE + 1) * sizeof (CHAR16));\r
+  ASSERT (mSpaceBuffer != NULL);\r
+  LibSetUnicodeMem (mSpaceBuffer, SPACE_BUFFER_SIZE, L' ');\r
+  mSpaceBuffer[SPACE_BUFFER_SIZE] = L'\0';\r
+}\r
+\r
+\r
+/**\r
+  Free the HII String.\r
+\r
+**/\r
+VOID\r
+FreeLibStrings (\r
+  VOID\r
+  )\r
+{\r
+  FreePool (gEnterString);\r
+  FreePool (gEnterCommitString);\r
+  FreePool (gEnterEscapeString);\r
+  FreePool (gEscapeString);\r
+  FreePool (gMoveHighlight);\r
+  FreePool (gDecNumericInput);\r
+  FreePool (gHexNumericInput);\r
+  FreePool (gToggleCheckBox);\r
+\r
+  FreePool (gAreYouSure);\r
+  FreePool (gYesResponse);\r
+  FreePool (gNoResponse);\r
+  FreePool (gPlusString);\r
+  FreePool (gMinusString);\r
+  FreePool (gAdjustNumber);\r
+  FreePool (gSaveChanges);\r
+\r
+  FreePool (gLibEmptyString);\r
+\r
+  FreePool (gNvUpdateMessage);\r
+  FreePool (gInputErrorMessage);\r
+  \r
+  FreePool (mSpaceBuffer);\r
+}\r
+\r
+/**\r
+  Wait for a key to be pressed by user.\r
+\r
+  @param Key         The key which is pressed by user.\r
+\r
+  @retval EFI_SUCCESS The function always completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+WaitForKeyStroke (\r
+  OUT  EFI_INPUT_KEY           *Key\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINTN       Index;\r
+\r
+  while (TRUE) {\r
+    Status = gST->ConIn->ReadKeyStroke (gST->ConIn, Key);\r
+    if (!EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+\r
+    if (Status != EFI_NOT_READY) {\r
+      continue;\r
+    }\r
+    \r
+    gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &Index);\r
+  }\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Set Buffer to Value for Size bytes.\r
+\r
+  @param  Buffer                 Memory to set.\r
+  @param  Size                   Number of bytes to set\r
+  @param  Value                  Value of the set operation.\r
+\r
+**/\r
+VOID\r
+LibSetUnicodeMem (\r
+  IN VOID   *Buffer,\r
+  IN UINTN  Size,\r
+  IN CHAR16 Value\r
+  )\r
+{\r
+  CHAR16  *Ptr;\r
+\r
+  Ptr = Buffer;\r
+  while ((Size--)  != 0) {\r
+    *(Ptr++) = Value;\r
+  }\r
+}\r
+\r
+/**\r
+  The internal function prints to the EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL\r
+  protocol instance.\r
+\r
+  @param Width           Width of string to be print.\r
+  @param Column          The position of the output string.\r
+  @param Row             The position of the output string.\r
+  @param Out             The EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL instance.\r
+  @param Fmt             The format string.\r
+  @param Args            The additional argument for the variables in the format string.\r
+\r
+  @return Number of Unicode character printed.\r
+\r
+**/\r
+UINTN\r
+PrintInternal (\r
+  IN UINTN                            Width, \r
+  IN UINTN                            Column,\r
+  IN UINTN                            Row,\r
+  IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *Out,\r
+  IN CHAR16                           *Fmt,\r
+  IN VA_LIST                          Args\r
+  )\r
+{\r
+  CHAR16  *Buffer;\r
+  CHAR16  *BackupBuffer;\r
+  UINTN   Index;\r
+  UINTN   PreviousIndex;\r
+  UINTN   Count;\r
+  UINTN   PrintWidth;\r
+  UINTN   CharWidth;\r
+\r
+  //\r
+  // For now, allocate an arbitrarily long buffer\r
+  //\r
+  Buffer        = AllocateZeroPool (0x10000);\r
+  BackupBuffer  = AllocateZeroPool (0x10000);\r
+  ASSERT (Buffer);\r
+  ASSERT (BackupBuffer);\r
+\r
+  if (Column != (UINTN) -1) {\r
+    Out->SetCursorPosition (Out, Column, Row);\r
+  }\r
+\r
+  UnicodeVSPrint (Buffer, 0x10000, Fmt, Args);\r
+\r
+  Out->Mode->Attribute = Out->Mode->Attribute & 0x7f;\r
+\r
+  Out->SetAttribute (Out, Out->Mode->Attribute);\r
+\r
+  Index         = 0;\r
+  PreviousIndex = 0;\r
+  Count         = 0;\r
+  PrintWidth    = 0;\r
+  CharWidth     = 1;\r
+\r
+  do {\r
+    for (; (Buffer[Index] != NARROW_CHAR) && (Buffer[Index] != WIDE_CHAR) && (Buffer[Index] != 0); Index++) {\r
+      BackupBuffer[Index] = Buffer[Index];\r
+    }\r
+\r
+    if (Buffer[Index] == 0) {\r
+      break;\r
+    }\r
+    //\r
+    // Null-terminate the temporary string\r
+    //\r
+    BackupBuffer[Index] = 0;\r
+\r
+    //\r
+    // Print this out, we are about to switch widths\r
+    //\r
+    Out->OutputString (Out, &BackupBuffer[PreviousIndex]);\r
+    Count += StrLen (&BackupBuffer[PreviousIndex]);\r
+    PrintWidth += Count * CharWidth;\r
+\r
+    //\r
+    // Preserve the current index + 1, since this is where we will start printing from next\r
+    //\r
+    PreviousIndex = Index + 1;\r
+\r
+    //\r
+    // We are at a narrow or wide character directive.  Set attributes and strip it and print it\r
+    //\r
+    if (Buffer[Index] == NARROW_CHAR) {\r
+      //\r
+      // Preserve bits 0 - 6 and zero out the rest\r
+      //\r
+      Out->Mode->Attribute = Out->Mode->Attribute & 0x7f;\r
+      Out->SetAttribute (Out, Out->Mode->Attribute);\r
+      CharWidth = 1;\r
+    } else {\r
+      //\r
+      // Must be wide, set bit 7 ON\r
+      //\r
+      Out->Mode->Attribute = Out->Mode->Attribute | EFI_WIDE_ATTRIBUTE;\r
+      Out->SetAttribute (Out, Out->Mode->Attribute);\r
+      CharWidth = 2;\r
+    }\r
+\r
+    Index++;\r
+\r
+  } while (Buffer[Index] != 0);\r
+\r
+  //\r
+  // We hit the end of the string - print it\r
+  //\r
+  Out->OutputString (Out, &BackupBuffer[PreviousIndex]);\r
+  Count += StrLen (&BackupBuffer[PreviousIndex]);\r
+  PrintWidth += Count * CharWidth;\r
+  if (PrintWidth < Width) {\r
+    Out->Mode->Attribute = Out->Mode->Attribute & 0x7f;\r
+    Out->SetAttribute (Out, Out->Mode->Attribute);\r
+    Out->OutputString (Out, &mSpaceBuffer[SPACE_BUFFER_SIZE - Width + PrintWidth]);\r
+  }\r
+\r
+  FreePool (Buffer);\r
+  FreePool (BackupBuffer);\r
+  return Count;\r
+}\r
+\r
+/**\r
+  Prints a formatted unicode string to the default console, at\r
+  the supplied cursor position.\r
+\r
+  @param  Width      Width of String to be printed.\r
+  @param  Column     The cursor position to print the string at.\r
+  @param  Row        The cursor position to print the string at.\r
+  @param  Fmt        Format string.\r
+  @param  ...        Variable argument list for format string.\r
+\r
+  @return Length of string printed to the console\r
+\r
+**/\r
+UINTN\r
+EFIAPI\r
+PrintAt (\r
+  IN UINTN     Width,\r
+  IN UINTN     Column,\r
+  IN UINTN     Row,\r
+  IN CHAR16    *Fmt,\r
+  ...\r
+  )\r
+{\r
+  VA_LIST Args;\r
+  UINTN   LengthOfPrinted;\r
+\r
+  VA_START (Args, Fmt);\r
+  LengthOfPrinted = PrintInternal (Width, Column, Row, gST->ConOut, Fmt, Args);\r
+  VA_END (Args);\r
+  return LengthOfPrinted;\r
+}\r
+\r
diff --git a/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLibInternal.h b/MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLibInternal.h
new file mode 100644 (file)
index 0000000..ab197cf
--- /dev/null
@@ -0,0 +1,307 @@
+/** @file\r
+\r
+  This library class defines a set of interfaces to customize Display module\r
+\r
+Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials are licensed and made available under \r
+the terms and conditions of the BSD License that accompanies this distribution.  \r
+The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php.                                            \r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef __CUSTOMIZED_DISPLAY_LIB_INTERNAL_H__\r
+#define __CUSTOMIZED_DISPLAY_LIB_INTERNAL_H__\r
+\r
+\r
+\r
+#include <PiDxe.h>\r
+\r
+#include <Protocol/SimpleTextOut.h>\r
+#include <Protocol/SimpleTextIn.h>\r
+#include <Protocol/FormBrowser2.h>\r
+#include <Protocol/FormBrowserEx2.h>\r
+#include <Protocol/DisplayProtocol.h>\r
+#include <Protocol/DevicePath.h>\r
+#include <Protocol/UnicodeCollation.h>\r
+#include <Protocol/HiiConfigAccess.h>\r
+#include <Protocol/HiiConfigRouting.h>\r
+#include <Protocol/HiiDatabase.h>\r
+#include <Protocol/HiiString.h>\r
+#include <Protocol/UserManager.h>\r
+#include <Protocol/DevicePathFromText.h>\r
+\r
+#include <Guid/MdeModuleHii.h>\r
+#include <Guid/HiiPlatformSetupFormset.h>\r
+#include <Guid/HiiFormMapMethodGuid.h>\r
+\r
+#include <Library/PrintLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/HiiLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/DevicePathLib.h>\r
+#include <Library/CustomizedDisplayLib.h>\r
+\r
+#include "Colors.h"\r
+\r
+\r
+\r
+#define FORMSET_CLASS_PLATFORM_SETUP         0x0001\r
+#define FORMSET_CLASS_FRONT_PAGE             0x0002\r
+#define FORMSET_CLASS_MODEL_PAGE             0x0004\r
+\r
+\r
+#define FRONT_PAGE_HEADER_HEIGHT      6\r
+#define NONE_FRONT_PAGE_HEADER_HEIGHT 3\r
+#define FOOTER_HEIGHT                 4\r
+#define STATUS_BAR_HEIGHT             1\r
+\r
+//\r
+// Screen definitions\r
+//\r
+#define BANNER_HEIGHT                 6\r
+#define BANNER_COLUMNS                3\r
+#define BANNER_LEFT_COLUMN_INDENT     1\r
+\r
+//\r
+// Character definitions\r
+//\r
+#define UPPER_LOWER_CASE_OFFSET 0x20\r
+\r
+//\r
+// This is the Input Error Message\r
+//\r
+#define INPUT_ERROR 1\r
+\r
+//\r
+// This is the NV RAM update required Message\r
+//\r
+#define NV_UPDATE_REQUIRED  2\r
+\r
+typedef struct {\r
+  EFI_STRING_ID  Banner[BANNER_HEIGHT][BANNER_COLUMNS];\r
+} BANNER_DATA;\r
+\r
+extern  UINT16                        gClassOfVfr;                 // Formset class information\r
+extern  BANNER_DATA                   *gBannerData;\r
+extern  EFI_SCREEN_DESCRIPTOR         gScreenDimensions;\r
+extern  UINTN                         gFooterHeight;\r
+\r
+//\r
+// Browser Global Strings\r
+//\r
+extern CHAR16            *gEnterString;\r
+extern CHAR16            *gEnterCommitString;\r
+extern CHAR16            *gEnterEscapeString;\r
+extern CHAR16            *gEscapeString;\r
+extern CHAR16            *gMoveHighlight;\r
+extern CHAR16            *gDecNumericInput;\r
+extern CHAR16            *gHexNumericInput;\r
+extern CHAR16            *gToggleCheckBox;\r
+extern CHAR16            *gLibEmptyString;\r
+extern CHAR16            *gAreYouSure;\r
+extern CHAR16            *gYesResponse;\r
+extern CHAR16            *gNoResponse;\r
+extern CHAR16            *gPlusString;\r
+extern CHAR16            *gMinusString;\r
+extern CHAR16            *gAdjustNumber;\r
+extern CHAR16            *gSaveChanges;\r
+extern CHAR16            *gNvUpdateMessage;\r
+extern CHAR16            *gInputErrorMessage;\r
+/**\r
+\r
+  Print banner info for front page.\r
+\r
+  @param[in]  FormData             Form Data to be shown in Page\r
+  \r
+**/\r
+VOID\r
+PrintBannerInfo ( \r
+  IN FORM_DISPLAY_ENGINE_FORM       *FormData\r
+  );\r
+\r
+/**\r
+\r
+  Print framework for a page.\r
+  \r
+**/\r
+VOID\r
+PrintFramework (\r
+  VOID\r
+  );\r
+  \r
+/**\r
+  Print the form title.\r
+\r
+  @param[in]  FormData             Form Data to be shown in Page\r
+\r
+**/\r
+VOID\r
+PrintFormTitle (\r
+  IN FORM_DISPLAY_ENGINE_FORM       *FormData\r
+  );\r
+\r
+/**\r
+  Validate the input screen diemenstion info.\r
+\r
+  @param  FormData               The input form data info.\r
+\r
+  @return EFI_SUCCESS            The input screen info is acceptable.\r
+  @return EFI_INVALID_PARAMETER  The input screen info is not acceptable.\r
+\r
+**/\r
+EFI_STATUS \r
+ScreenDiemensionInfoValidate (\r
+  IN FORM_DISPLAY_ENGINE_FORM       *FormData\r
+  );\r
+\r
+/**\r
+  Get the string based on the StringId and HII Package List Handle.\r
+\r
+  @param  Token                  The String's ID.\r
+  @param  HiiHandle              The package list in the HII database to search for\r
+                                 the specified string.\r
+\r
+  @return The output string.\r
+\r
+**/\r
+CHAR16 *\r
+LibGetToken (\r
+  IN  EFI_STRING_ID                Token,\r
+  IN  EFI_HII_HANDLE               HiiHandle\r
+  );\r
+\r
+/**\r
+  Count the storage space of a Unicode string.\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
+\r
+  If String is NULL, then ASSERT ().\r
+\r
+  @param String          The input string to be counted.\r
+\r
+  @return Storage space for the input string.\r
+\r
+**/\r
+UINTN\r
+LibGetStringWidth (\r
+  IN CHAR16               *String\r
+  );\r
+\r
+/**\r
+  Show all registered HotKey help strings on bottom Rows.\r
+\r
+  @param FormData          The curent input form data info.\r
+\r
+**/\r
+VOID\r
+PrintHotKeyHelpString (\r
+  IN FORM_DISPLAY_ENGINE_FORM      *FormData\r
+  );\r
+  \r
+/**\r
+  Get step info from numeric opcode.\r
+  \r
+  @param[in] OpCode     The input numeric op code.\r
+\r
+  @return step info for this opcode.\r
+**/\r
+UINT64\r
+LibGetFieldFromNum (\r
+  IN  EFI_IFR_OP_HEADER     *OpCode\r
+  );\r
+\r
+/**\r
+  Initialize the HII String Token to the correct values.\r
+\r
+**/\r
+VOID\r
+InitializeLibStrings (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Free the HII String.\r
+\r
+**/\r
+VOID\r
+FreeLibStrings (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Wait for a key to be pressed by user.\r
+\r
+  @param Key         The key which is pressed by user.\r
+\r
+  @retval EFI_SUCCESS The function always completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+WaitForKeyStroke (\r
+  OUT  EFI_INPUT_KEY           *Key\r
+  );\r
+\r
+/**\r
+  Set Buffer to Value for Size bytes.\r
+\r
+  @param  Buffer                 Memory to set.\r
+  @param  Size                   Number of bytes to set\r
+  @param  Value                  Value of the set operation.\r
+\r
+**/\r
+VOID\r
+LibSetUnicodeMem (\r
+  IN VOID   *Buffer,\r
+  IN UINTN  Size,\r
+  IN CHAR16 Value\r
+  );\r
+\r
+/**\r
+  Prints a formatted unicode string to the default console, at\r
+  the supplied cursor position.\r
+\r
+  @param  Width      Width of String to be printed.\r
+  @param  Column     The cursor position to print the string at.\r
+  @param  Row        The cursor position to print the string at.\r
+  @param  Fmt        Format string.\r
+  @param  ...        Variable argument list for format string.\r
+\r
+  @return Length of string printed to the console\r
+\r
+**/\r
+UINTN\r
+EFIAPI\r
+PrintAt (\r
+  IN UINTN     Width,\r
+  IN UINTN     Column,\r
+  IN UINTN     Row,\r
+  IN CHAR16    *Fmt,\r
+  ...\r
+  );\r
+\r
+/**\r
+  Process some op codes which is out side of current form.\r
+  \r
+  @param FormData                Pointer to the form data.\r
+\r
+**/\r
+VOID\r
+ProcessExternedOpcode (\r
+  IN FORM_DISPLAY_ENGINE_FORM       *FormData\r
+  );\r
+\r
+#endif\r
index 31055192973ea8179645fbff4757770d0808ce80..4ae24eb80ee86563689e5b52243816ae0e6314c6 100644 (file)
   #\r
   CpuExceptionHandlerLib|Include/Library/CpuExceptionHandlerLib.h\r
   \r
+  ##  @libraryclass    Provides platform specific display interface.\r
+  #\r
+  CustomizedDisplayLib|Include/Library/CustomizedDisplayLib.h\r
+\r
 [Guids]\r
   ## MdeModule package token space guid\r
   # Include/Guid/MdeModulePkgTokenSpace.h\r
   ## Include/Protocol/BootLogo.h\r
   gEfiBootLogoProtocolGuid = { 0xcdea2bd3, 0xfc25, 0x4c1c, { 0xb9, 0x7c, 0xb3, 0x11, 0x86, 0x6, 0x49, 0x90 } }\r
 \r
+  ## Include/Protocol/DisplayProtocol.h\r
+  gEdkiiFormDisplayEngineProtocolGuid = { 0x9bbe29e9, 0xfda1, 0x41ec, { 0xad, 0x52, 0x45, 0x22, 0x13, 0x74, 0x2d, 0x2e } }\r
+\r
+  ## Include/Protocol/FormBrowserEx2.h\r
+  gEdkiiFormBrowserEx2ProtocolGuid = { 0xa770c357, 0xb693, 0x4e6d, { 0xa6, 0xcf, 0xd2, 0x1c, 0x72, 0x8e, 0x55, 0xb } }\r
+\r
 [PcdsFeatureFlag]\r
   ## Indicate whether platform can support update capsule across a system reset\r
   gEfiMdeModulePkgTokenSpaceGuid.PcdSupportUpdateCapsuleReset|FALSE|BOOLEAN|0x0001001d\r
index 781fbbf3b45a88b9a5003fdbbca6986ffb3688e5..7895834c245fc90b10bfa47427bb8b63c78d5cce 100644 (file)
@@ -76,6 +76,7 @@
   CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf\r
   PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf\r
   PalLib|MdePkg/Library/BasePalLibNull/BasePalLibNull.inf\r
+  CustomizedDisplayLib|MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf\r
   #\r
   # Misc\r
   #\r
 \r
   MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf\r
   MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf\r
+  MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf\r
   MdeModulePkg/Application/VariableInfo/VariableInfo.inf\r
   MdeModulePkg/Universal/FaultTolerantWritePei/FaultTolerantWritePei.inf\r
   MdeModulePkg/Universal/Variable/Pei/VariablePei.inf\r
diff --git a/MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf b/MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf
new file mode 100644 (file)
index 0000000..2170369
--- /dev/null
@@ -0,0 +1,70 @@
+## @file\r
+# The DXE driver produces FORM BROWSER protocols defined in UEFI HII 2.1 specificatin.\r
+#\r
+# Copyright (c) 2007 - 2013, Intel Corporation. All rights reserved.<BR>\r
+#\r
+#  This program and the accompanying materials\r
+#  are licensed and made available under the terms and conditions of the BSD License\r
+#  which accompanies this distribution. The full text of the license may be found at\r
+#  http://opensource.org/licenses/bsd-license.php\r
+#\r
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = DisplayEngine\r
+  FILE_GUID                      = E660EA85-058E-4b55-A54B-F02F83A24707\r
+  MODULE_TYPE                    = DXE_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+  ENTRY_POINT                    = InitializeDisplayEngine\r
+  UNLOAD_IMAGE                   = UnloadDisplayEngine\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources]\r
+  FormDisplayStr.uni\r
+  FormDisplay.c\r
+  FormDisplay.h\r
+  Print.c\r
+  ProcessOptions.c\r
+  InputHandler.c\r
+  \r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+  \r
+[LibraryClasses]\r
+  UefiDriverEntryPoint\r
+  UefiBootServicesTableLib\r
+  DebugLib\r
+  BaseMemoryLib\r
+  BaseLib\r
+  PrintLib\r
+  HiiLib\r
+  MemoryAllocationLib\r
+  CustomizedDisplayLib\r
+\r
+[Protocols]\r
+  gEdkiiFormDisplayEngineProtocolGuid\r
+  gEdkiiFormBrowserEx2ProtocolGuid\r
+\r
+[Guids]\r
+  gEfiIfrTianoGuid                              ## CONSUMES  ## GUID  \r
+  \r
+[Depex]\r
+  gEfiHiiDatabaseProtocolGuid AND gEfiHiiConfigRoutingProtocolGuid AND gEdkiiFormBrowserEx2ProtocolGuid\r
+  \r
+[FeaturePcd]\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdBrowserGrayOutTextStatement            ## CONSUMES\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdBrowerGrayOutReadOnlyMenu              ## CONSUMES\r
+\r
+[BuildOptions] \r
+  MSFT:*_*_*_CC_FLAGS     = /Od \r
+\r
diff --git a/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.c b/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.c
new file mode 100644 (file)
index 0000000..f632229
--- /dev/null
@@ -0,0 +1,3200 @@
+/** @file\r
+Entry and initialization module for the browser.\r
+\r
+Copyright (c) 2007 - 2013, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "FormDisplay.h"\r
+\r
+//\r
+// Search table for UiDisplayMenu()\r
+//\r
+SCAN_CODE_TO_SCREEN_OPERATION     gScanCodeToOperation[] = {\r
+  {\r
+    SCAN_UP,\r
+    UiUp,\r
+  },\r
+  {\r
+    SCAN_DOWN,\r
+    UiDown,\r
+  },\r
+  {\r
+    SCAN_PAGE_UP,\r
+    UiPageUp,\r
+  },\r
+  {\r
+    SCAN_PAGE_DOWN,\r
+    UiPageDown,\r
+  },\r
+  {\r
+    SCAN_ESC,\r
+    UiReset,\r
+  },\r
+  {\r
+    SCAN_LEFT,\r
+    UiLeft,\r
+  },\r
+  {\r
+    SCAN_RIGHT,\r
+    UiRight,\r
+  }\r
+};\r
+\r
+UINTN mScanCodeNumber = sizeof (gScanCodeToOperation) / sizeof (gScanCodeToOperation[0]);\r
+\r
+SCREEN_OPERATION_T0_CONTROL_FLAG  gScreenOperationToControlFlag[] = {\r
+  {\r
+    UiNoOperation,\r
+    CfUiNoOperation,\r
+  },\r
+  {\r
+    UiSelect,\r
+    CfUiSelect,\r
+  },\r
+  {\r
+    UiUp,\r
+    CfUiUp,\r
+  },\r
+  {\r
+    UiDown,\r
+    CfUiDown,\r
+  },\r
+  {\r
+    UiLeft,\r
+    CfUiLeft,\r
+  },\r
+  {\r
+    UiRight,\r
+    CfUiRight,\r
+  },\r
+  {\r
+    UiReset,\r
+    CfUiReset,\r
+  },\r
+  {\r
+    UiPageUp,\r
+    CfUiPageUp,\r
+  },\r
+  {\r
+    UiPageDown,\r
+    CfUiPageDown\r
+  }, \r
+  {\r
+    UiHotKey,\r
+    CfUiHotKey\r
+  }\r
+};\r
+\r
+EFI_GUID  gDisplayEngineGuid = {\r
+  0xE38C1029, 0xE38F, 0x45b9, {0x8F, 0x0D, 0xE2, 0xE6, 0x0B, 0xC9, 0xB2, 0x62}\r
+};\r
+\r
+UINTN                         gSequence;\r
+EFI_SCREEN_DESCRIPTOR         gStatementDimensions;\r
+EFI_SCREEN_DESCRIPTOR         gOldStatementDimensions = {0};\r
+BOOLEAN                       mStatementLayoutIsChanged = TRUE;\r
+USER_INPUT                    *gUserInput;\r
+FORM_DISPLAY_ENGINE_FORM      *gFormData;\r
+EFI_HII_HANDLE                gHiiHandle;\r
+UINT16                        gDirection;\r
+LIST_ENTRY                    gMenuOption;\r
+DISPLAY_HIGHLIGHT_MENU_INFO   gHighligthMenuInfo = {0};\r
+\r
+//\r
+// Browser Global Strings\r
+//\r
+CHAR16            *gFormNotFound;\r
+CHAR16            *gNoSubmitIf;\r
+CHAR16            *gBrwoserError;\r
+CHAR16            *gSaveFailed;\r
+CHAR16            *gPromptForData;\r
+CHAR16            *gPromptForPassword;\r
+CHAR16            *gPromptForNewPassword;\r
+CHAR16            *gConfirmPassword;\r
+CHAR16            *gConfirmError;\r
+CHAR16            *gPassowordInvalid;\r
+CHAR16            *gPressEnter;\r
+CHAR16            *gEmptyString;\r
+CHAR16            *gMiniString;\r
+CHAR16            *gOptionMismatch;\r
+CHAR16            *gFormSuppress;\r
+CHAR16            *gProtocolNotFound;\r
+\r
+CHAR16            gPromptBlockWidth;\r
+CHAR16            gOptionBlockWidth;\r
+CHAR16            gHelpBlockWidth;\r
+CHAR16            *mUnknownString;\r
+\r
+FORM_DISPLAY_DRIVER_PRIVATE_DATA  mPrivateData = {\r
+  FORM_DISPLAY_DRIVER_SIGNATURE,\r
+  NULL,\r
+  {\r
+    FormDisplay,\r
+    ClearDisplayPage,\r
+    ConfirmDataChange\r
+  }\r
+};\r
+\r
+\r
+/**\r
+  Get the string based on the StringId and HII Package List Handle.\r
+\r
+  @param  Token                  The String's ID.\r
+  @param  HiiHandle              The package list in the HII database to search for\r
+                                 the specified string.\r
+\r
+  @return The output string.\r
+\r
+**/\r
+CHAR16 *\r
+GetToken (\r
+  IN  EFI_STRING_ID                Token,\r
+  IN  EFI_HII_HANDLE               HiiHandle\r
+  )\r
+{\r
+  EFI_STRING  String;\r
+\r
+  String = HiiGetString (HiiHandle, Token, NULL);\r
+  if (String == NULL) {\r
+    String = AllocateCopyPool (StrSize (mUnknownString), mUnknownString);\r
+    ASSERT (String != NULL);\r
+  }\r
+\r
+  return (CHAR16 *) String;\r
+}\r
+\r
+\r
+/**\r
+  Initialize the HII String Token to the correct values.\r
+\r
+**/\r
+VOID\r
+InitializeDisplayStrings (\r
+  VOID\r
+  )\r
+{\r
+  mUnknownString        = GetToken (STRING_TOKEN (UNKNOWN_STRING), gHiiHandle);\r
+  gSaveFailed           = GetToken (STRING_TOKEN (SAVE_FAILED), 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
+  gMiniString           = GetToken (STRING_TOKEN (MINI_STRING), gHiiHandle);\r
+  gOptionMismatch       = GetToken (STRING_TOKEN (OPTION_MISMATCH), gHiiHandle);\r
+  gFormSuppress         = GetToken (STRING_TOKEN (FORM_SUPPRESSED), gHiiHandle);\r
+  gProtocolNotFound     = GetToken (STRING_TOKEN (PROTOCOL_NOT_FOUND), gHiiHandle);\r
+  gFormNotFound         = GetToken (STRING_TOKEN (STATUS_BROWSER_FORM_NOT_FOUND), gHiiHandle);\r
+  gNoSubmitIf           = GetToken (STRING_TOKEN (STATUS_BROWSER_NO_SUBMIT_IF), gHiiHandle);\r
+  gBrwoserError         = GetToken (STRING_TOKEN (STATUS_BROWSER_ERROR), gHiiHandle);\r
+}\r
+\r
+/**\r
+  Free up the resource allocated for all strings required\r
+  by Setup Browser.\r
+\r
+**/\r
+VOID\r
+FreeDisplayStrings (\r
+  VOID\r
+  )\r
+{\r
+  FreePool (mUnknownString);\r
+  FreePool (gEmptyString);\r
+  FreePool (gSaveFailed);\r
+  FreePool (gPromptForData);\r
+  FreePool (gPromptForPassword);\r
+  FreePool (gPromptForNewPassword);\r
+  FreePool (gConfirmPassword);\r
+  FreePool (gConfirmError);\r
+  FreePool (gPassowordInvalid);\r
+  FreePool (gPressEnter);\r
+  FreePool (gMiniString);\r
+  FreePool (gOptionMismatch);\r
+  FreePool (gFormSuppress);\r
+  FreePool (gProtocolNotFound);\r
+  FreePool (gBrwoserError);\r
+  FreePool (gNoSubmitIf);\r
+  FreePool (gFormNotFound);\r
+}\r
+\r
+/**\r
+  Get prompt string id from the opcode data buffer.\r
+\r
+  @param  OpCode                 The input opcode buffer.\r
+\r
+  @return The prompt string id.\r
+\r
+**/\r
+EFI_STRING_ID\r
+GetPrompt (\r
+  IN EFI_IFR_OP_HEADER     *OpCode\r
+  )\r
+{\r
+  EFI_IFR_STATEMENT_HEADER  *Header;\r
+\r
+  if (OpCode->Length <= sizeof (EFI_IFR_OP_HEADER)) {\r
+    return 0;\r
+  }\r
+\r
+  Header = (EFI_IFR_STATEMENT_HEADER  *) (OpCode + 1);\r
+\r
+  return Header->Prompt;\r
+}\r
+\r
+/**\r
+  Get the supported width for a particular op-code\r
+\r
+  @param  Statement              The curent statement.\r
+\r
+  @return Returns the number of CHAR16 characters that is support.\r
+\r
+**/\r
+UINT16\r
+GetWidth (\r
+  IN FORM_DISPLAY_ENGINE_STATEMENT        *Statement\r
+  )\r
+{\r
+  CHAR16       *String;\r
+  UINTN        Size;\r
+  UINT16       Width;\r
+  EFI_IFR_TEXT *TestOp;\r
+\r
+  Size = 0;\r
+\r
+  //\r
+  // See if the second text parameter is really NULL\r
+  //\r
+  if (Statement->OpCode->OpCode == EFI_IFR_TEXT_OP) {\r
+    TestOp = (EFI_IFR_TEXT *) Statement->OpCode;\r
+    if (TestOp->TextTwo != 0) {\r
+      String = GetToken (TestOp->TextTwo, gFormData->HiiHandle);\r
+      Size   = StrLen (String);\r
+      FreePool (String);\r
+    }\r
+  }\r
+\r
+  if ((Statement->OpCode->OpCode == EFI_IFR_SUBTITLE_OP) ||\r
+      (Statement->OpCode->OpCode == EFI_IFR_REF_OP) ||\r
+      (Statement->OpCode->OpCode == EFI_IFR_PASSWORD_OP) ||\r
+      (Statement->OpCode->OpCode == EFI_IFR_ACTION_OP) ||\r
+      (Statement->OpCode->OpCode == EFI_IFR_RESET_BUTTON_OP) ||\r
+      //\r
+      // Allow a wide display if text op-code and no secondary text op-code\r
+      //\r
+      ((Statement->OpCode->OpCode == EFI_IFR_TEXT_OP) && (Size == 0))\r
+      ) {\r
+    Width = (UINT16) (gPromptBlockWidth + gOptionBlockWidth);\r
+  } else {\r
+    Width = (UINT16) gPromptBlockWidth;\r
+  }\r
+\r
+  return (UINT16) (Width - LEFT_SKIPPED_COLUMNS);\r
+}\r
+\r
+/**\r
+  Will copy LineWidth amount of a string in the OutputString buffer and return the\r
+  number of CHAR16 characters that were copied into the OutputString buffer.\r
+  The output string format is:\r
+    Glyph Info + String info + '\0'.\r
+\r
+  In the code, it deals \r,\n,\r\n same as \n\r, also it not process the \r or \g.\r
+\r
+  @param  InputString            String description for this option.\r
+  @param  LineWidth              Width of the desired string to extract in CHAR16\r
+                                 characters\r
+  @param  GlyphWidth             The glyph width of the begin of the char in the string.\r
+  @param  Index                  Where in InputString to start the copy process\r
+  @param  OutputString           Buffer to copy the string into\r
+\r
+  @return Returns the number of CHAR16 characters that were copied into the OutputString \r
+  buffer, include extra glyph info and '\0' info.\r
+\r
+**/\r
+UINT16\r
+GetLineByWidth (\r
+  IN      CHAR16                      *InputString,\r
+  IN      UINT16                      LineWidth,\r
+  IN OUT  UINT16                      *GlyphWidth,\r
+  IN OUT  UINTN                       *Index,\r
+  OUT     CHAR16                      **OutputString\r
+  )\r
+{\r
+  UINT16          StrOffset;\r
+  UINT16          GlyphOffset;\r
+  UINT16          OriginalGlyphWidth;\r
+  BOOLEAN         ReturnFlag;\r
+  UINT16          LastSpaceOffset;\r
+  UINT16          LastGlyphWidth;\r
+\r
+  if (InputString == NULL || Index == NULL || OutputString == NULL) {\r
+    return 0;\r
+  }\r
+\r
+  if (LineWidth == 0 || *GlyphWidth == 0) {\r
+    return 0;\r
+  }\r
+\r
+  //\r
+  // Save original glyph width.\r
+  //\r
+  OriginalGlyphWidth = *GlyphWidth;\r
+  LastGlyphWidth     = OriginalGlyphWidth;\r
+  ReturnFlag         = FALSE;\r
+  LastSpaceOffset    = 0;\r
+\r
+  //\r
+  // NARROW_CHAR can not be printed in screen, so if a line only contain  the two CHARs: 'NARROW_CHAR + CHAR_CARRIAGE_RETURN' , it is a empty line  in Screen.\r
+  // To avoid displaying this  empty line in screen,  just skip  the two CHARs here.\r
+  //\r
+  if ((InputString[*Index] == NARROW_CHAR) && (InputString[*Index + 1] == CHAR_CARRIAGE_RETURN)) {\r
+    *Index = *Index + 2;\r
+  }\r
+\r
+  //\r
+  // Fast-forward the string and see if there is a carriage-return in the string\r
+  //\r
+  for (StrOffset = 0, GlyphOffset = 0; GlyphOffset <= LineWidth; StrOffset++) {\r
+    switch (InputString[*Index + StrOffset]) {\r
+      case NARROW_CHAR:\r
+        *GlyphWidth = 1;\r
+        break;\r
+\r
+      case WIDE_CHAR:\r
+        *GlyphWidth = 2;\r
+        break;\r
+\r
+      case CHAR_CARRIAGE_RETURN:\r
+      case CHAR_LINEFEED:\r
+      case CHAR_NULL:\r
+        ReturnFlag = TRUE;\r
+        break;\r
+\r
+      default:\r
+        GlyphOffset = GlyphOffset + *GlyphWidth;\r
+\r
+        //\r
+        // Record the last space info in this line. Will be used in rewind.\r
+        //\r
+        if ((InputString[*Index + StrOffset] == CHAR_SPACE) && (GlyphOffset <= LineWidth)) {\r
+          LastSpaceOffset = StrOffset;\r
+          LastGlyphWidth  = *GlyphWidth;\r
+        }\r
+        break;\r
+    }\r
+\r
+    if (ReturnFlag) {\r
+      break;\r
+    }\r
+  } \r
+\r
+  //\r
+  // Rewind the string from the maximum size until we see a space to break the line\r
+  //\r
+  if (GlyphOffset > LineWidth) {\r
+    //\r
+    // Rewind the string to last space char in this line.\r
+    //\r
+    if (LastSpaceOffset != 0) {\r
+      StrOffset   = LastSpaceOffset;\r
+      *GlyphWidth = LastGlyphWidth;\r
+    } else {\r
+      //\r
+      // Roll back to last char in the line width.\r
+      //\r
+      StrOffset--;\r
+    }\r
+  }\r
+\r
+  //\r
+  // The CHAR_NULL has process last time, this time just return 0 to stand for the end.\r
+  //\r
+  if (StrOffset == 0 && (InputString[*Index + StrOffset] == CHAR_NULL)) {\r
+    return 0;\r
+  }\r
+\r
+  //\r
+  // Need extra glyph info and '\0' info, so +2.\r
+  //\r
+  *OutputString = AllocateZeroPool (((UINTN) (StrOffset + 2) * sizeof(CHAR16)));\r
+  if (*OutputString == NULL) {\r
+    return 0;\r
+  }\r
+\r
+  //\r
+  // Save the glyph info at the begin of the string, will used by Print function.\r
+  //\r
+  if (OriginalGlyphWidth == 1) {\r
+    *(*OutputString) = NARROW_CHAR;\r
+  } else  {\r
+    *(*OutputString) = WIDE_CHAR;\r
+  }\r
+\r
+  CopyMem ((*OutputString) + 1, &InputString[*Index], StrOffset * sizeof(CHAR16));\r
+\r
+  if (InputString[*Index + StrOffset] == CHAR_SPACE) {\r
+    //\r
+    // Skip the space info at the begin of next line.\r
+    //  \r
+    *Index = (UINT16) (*Index + StrOffset + 1);\r
+  } else if (InputString[*Index + StrOffset] == CHAR_LINEFEED) {\r
+    //\r
+    // Skip the /n or /n/r info.\r
+    //\r
+    if (InputString[*Index + StrOffset + 1] == CHAR_CARRIAGE_RETURN) {\r
+      *Index = (UINT16) (*Index + StrOffset + 2);\r
+    } else {\r
+      *Index = (UINT16) (*Index + StrOffset + 1);\r
+    }\r
+  } else if (InputString[*Index + StrOffset] == CHAR_CARRIAGE_RETURN) {\r
+    //\r
+    // Skip the /r or /r/n info.\r
+    //  \r
+    if (InputString[*Index + StrOffset + 1] == CHAR_LINEFEED) {\r
+      *Index = (UINT16) (*Index + StrOffset + 2);\r
+    } else {\r
+      *Index = (UINT16) (*Index + StrOffset + 1);\r
+    }\r
+  } else {\r
+    *Index = (UINT16) (*Index + StrOffset);\r
+  }\r
+\r
+  //\r
+  // Include extra glyph info and '\0' info, so +2.\r
+  //\r
+  return StrOffset + 2;\r
+}\r
+\r
+/**\r
+  Add one menu option by specified description and context.\r
+\r
+  @param  Statement              Statement of this Menu Option.\r
+  @param  MenuItemCount          The index for this Option in the Menu.\r
+  @param  NestIn                 Whether this statement is nest in another statement.\r
+\r
+**/\r
+VOID\r
+UiAddMenuOption (\r
+  IN FORM_DISPLAY_ENGINE_STATEMENT   *Statement,\r
+  IN UINT16                          *MenuItemCount,\r
+  IN BOOLEAN                         NestIn\r
+  )\r
+{\r
+  UI_MENU_OPTION   *MenuOption;\r
+  UINTN            Index;\r
+  UINTN            Count;\r
+  CHAR16           *String;\r
+  UINT16           NumberOfLines;\r
+  UINT16           GlyphWidth;\r
+  UINT16           Width;\r
+  UINTN            ArrayEntry;\r
+  CHAR16           *OutputString;\r
+  EFI_STRING_ID    PromptId;\r
+\r
+  NumberOfLines = 1;\r
+  ArrayEntry    = 0;\r
+  GlyphWidth    = 1;\r
+  Count         = 1;\r
+  MenuOption    = NULL;\r
+\r
+  PromptId = GetPrompt (Statement->OpCode);\r
+  ASSERT (PromptId != 0);\r
+\r
+  String = GetToken (PromptId, gFormData->HiiHandle);\r
+  ASSERT (String != NULL);\r
+\r
+  Width  = GetWidth (Statement);\r
+  for (; GetLineByWidth (String, Width, &GlyphWidth,&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 (&String[ArrayEntry]) != 0) {\r
+      NumberOfLines++;\r
+    }\r
+    FreePool (OutputString);\r
+  }\r
+\r
+  if (Statement->OpCode->OpCode == EFI_IFR_DATE_OP || Statement->OpCode->OpCode == EFI_IFR_TIME_OP) {\r
+    //\r
+    // Add three MenuOptions for Date/Time\r
+    // Data format :      [01/02/2004]      [11:22:33]\r
+    // Line number :        0  0    1         0  0  1\r
+    //\r
+    NumberOfLines = 0;\r
+    Count = 3;\r
+  }\r
+\r
+  for (Index = 0; Index < Count; Index++) {\r
+    MenuOption = AllocateZeroPool (sizeof (UI_MENU_OPTION));\r
+    ASSERT (MenuOption);\r
+\r
+    MenuOption->Signature   = UI_MENU_OPTION_SIGNATURE;\r
+    MenuOption->Description = String;\r
+    MenuOption->Handle      = gFormData->HiiHandle;\r
+    MenuOption->ThisTag     = Statement;\r
+    MenuOption->NestInStatement = NestIn;\r
+    MenuOption->EntryNumber = *MenuItemCount;\r
+\r
+    if (Index == 2) {\r
+      //\r
+      // Override LineNumber for the MenuOption in Date/Time sequence\r
+      //\r
+      MenuOption->Skip = 1;\r
+    } else {\r
+      MenuOption->Skip = NumberOfLines;\r
+    }\r
+    MenuOption->Sequence = Index;\r
+\r
+    if ((Statement->Attribute & HII_DISPLAY_GRAYOUT) != 0) {\r
+      MenuOption->GrayOut = TRUE;\r
+    } else {\r
+      MenuOption->GrayOut = FALSE;\r
+    }\r
+\r
+    if ((Statement->Attribute & HII_DISPLAY_LOCK) != 0 || (gFormData->Attribute & HII_DISPLAY_LOCK) != 0) {\r
+      MenuOption->GrayOut = TRUE;\r
+    }\r
+\r
+    //\r
+    // If the form or the question has the lock attribute, deal same as grayout.\r
+    //\r
+    if ((gFormData->Attribute & HII_DISPLAY_LOCK) != 0 || (Statement->Attribute & HII_DISPLAY_LOCK) != 0) {\r
+      MenuOption->GrayOut = TRUE;\r
+    }\r
+\r
+    switch (Statement->OpCode->OpCode) {\r
+    case EFI_IFR_ORDERED_LIST_OP:\r
+    case EFI_IFR_ONE_OF_OP:\r
+    case EFI_IFR_NUMERIC_OP:\r
+    case EFI_IFR_TIME_OP:\r
+    case EFI_IFR_DATE_OP:\r
+    case EFI_IFR_CHECKBOX_OP:\r
+    case EFI_IFR_PASSWORD_OP:\r
+    case EFI_IFR_STRING_OP:\r
+      //\r
+      // User could change the value of these items\r
+      //\r
+      MenuOption->IsQuestion = TRUE;\r
+      break;\r
+    case EFI_IFR_TEXT_OP:\r
+      if (FeaturePcdGet (PcdBrowserGrayOutTextStatement)) {\r
+        //\r
+        // Initializing GrayOut option as TRUE for Text setup options \r
+        // so that those options will be Gray in colour and un selectable.\r
+        //\r
+        MenuOption->GrayOut = TRUE;\r
+      }\r
+      break;\r
+    default:\r
+      MenuOption->IsQuestion = FALSE;\r
+      break;\r
+    }\r
+\r
+    if ((Statement->Attribute & HII_DISPLAY_READONLY) != 0) {\r
+      MenuOption->ReadOnly = TRUE;\r
+      if (FeaturePcdGet (PcdBrowerGrayOutReadOnlyMenu)) {\r
+        MenuOption->GrayOut = TRUE;\r
+      }\r
+    }\r
+\r
+    InsertTailList (&gMenuOption, &MenuOption->Link);\r
+  }\r
+\r
+  (*MenuItemCount)++;\r
+}\r
+\r
+/**\r
+  Create the menu list base on the form data info.\r
+\r
+**/\r
+VOID\r
+ConvertStatementToMenu (\r
+  VOID\r
+  )\r
+{\r
+  UINT16                        MenuItemCount;\r
+  LIST_ENTRY                    *Link;\r
+  LIST_ENTRY                    *NestLink;\r
+  FORM_DISPLAY_ENGINE_STATEMENT *Statement;\r
+  FORM_DISPLAY_ENGINE_STATEMENT *NestStatement;\r
+\r
+  MenuItemCount = 0;\r
+  InitializeListHead (&gMenuOption);\r
+\r
+  Link = GetFirstNode (&gFormData->StatementListHead);\r
+  while (!IsNull (&gFormData->StatementListHead, Link)) {\r
+    Statement = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (Link);\r
+    Link = GetNextNode (&gFormData->StatementListHead, Link);\r
+\r
+    //\r
+    // Skip the opcode not recognized by Display core.\r
+    //\r
+    if (Statement->OpCode->OpCode == EFI_IFR_GUID_OP) {\r
+      continue;\r
+    }\r
+\r
+    UiAddMenuOption (Statement, &MenuItemCount, FALSE);\r
+\r
+    //\r
+    // Check the statement nest in this host statement.\r
+    //\r
+    NestLink = GetFirstNode (&Statement->NestStatementList);\r
+    while (!IsNull (&Statement->NestStatementList, NestLink)) {\r
+      NestStatement = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (NestLink);\r
+      NestLink = GetNextNode (&Statement->NestStatementList, NestLink);\r
+\r
+      UiAddMenuOption (NestStatement, &MenuItemCount, TRUE);\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  Count the storage space of a Unicode string.\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
+\r
+  If String is NULL, then ASSERT ().\r
+\r
+  @param String          The input string to be counted.\r
+\r
+  @return Storage space for the input string.\r
+\r
+**/\r
+UINTN\r
+GetStringWidth (\r
+  IN CHAR16               *String\r
+  )\r
+{\r
+  UINTN Index;\r
+  UINTN Count;\r
+  UINTN IncrementValue;\r
+\r
+  ASSERT (String != NULL);\r
+  if (String == NULL) {\r
+    return 0;\r
+  }\r
+\r
+  Index           = 0;\r
+  Count           = 0;\r
+  IncrementValue  = 1;\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
+    //\r
+    // We hit the null-terminator, we now have a count\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
+\r
+  //\r
+  // Increment by one to include the null-terminator in the size\r
+  //\r
+  Count++;\r
+\r
+  return Count * sizeof (CHAR16);\r
+}\r
+\r
+/**\r
+  Base on the input option string to update the skip value for a menu option.\r
+\r
+  @param  MenuOption             The MenuOption to be checked.\r
+  @param  OptionString           The input option string.\r
+\r
+**/\r
+VOID\r
+UpdateSkipInfoForMenu (\r
+  IN UI_MENU_OPTION               *MenuOption,\r
+  IN CHAR16                       *OptionString\r
+  )\r
+{\r
+  UINTN   Index;\r
+  UINT16  Width;\r
+  UINTN   Row;\r
+  CHAR16  *OutputString;\r
+  UINT16  GlyphWidth;\r
+\r
+  Width         = (UINT16) gOptionBlockWidth;\r
+  GlyphWidth    = 1;\r
+  Row           = 1;\r
+\r
+  for (Index = 0; GetLineByWidth (OptionString, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) {\r
+    if (StrLen (&OptionString[Index]) != 0) {\r
+      Row++;\r
+    }\r
+\r
+    FreePool (OutputString);\r
+  }\r
+\r
+  if ((Row > MenuOption->Skip) && \r
+      (MenuOption->ThisTag->OpCode->OpCode != EFI_IFR_DATE_OP) && \r
+      (MenuOption->ThisTag->OpCode->OpCode != EFI_IFR_TIME_OP)) {\r
+    MenuOption->Skip = Row;\r
+  }\r
+}\r
+\r
+/**\r
+  Update display lines for a Menu Option.\r
+\r
+  @param  MenuOption             The MenuOption to be checked.\r
+\r
+**/\r
+VOID\r
+UpdateOptionSkipLines (\r
+  IN UI_MENU_OPTION               *MenuOption\r
+  )\r
+{\r
+  CHAR16  *OptionString;\r
+\r
+  OptionString  = NULL;\r
+\r
+  ProcessOptions (MenuOption, FALSE, &OptionString, TRUE);\r
+  if (OptionString != NULL) {\r
+    UpdateSkipInfoForMenu (MenuOption, OptionString);\r
+\r
+    FreePool (OptionString);\r
+  }\r
+\r
+  if ((MenuOption->ThisTag->OpCode->OpCode  == EFI_IFR_TEXT_OP) && (((EFI_IFR_TEXT*)MenuOption->ThisTag->OpCode)->TextTwo != 0)) {\r
+    OptionString   = GetToken (((EFI_IFR_TEXT*)MenuOption->ThisTag->OpCode)->TextTwo, gFormData->HiiHandle);\r
+\r
+    if (OptionString != NULL) {\r
+      UpdateSkipInfoForMenu (MenuOption, OptionString);\r
+\r
+      FreePool (OptionString);\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  Check whether this Menu Option could be highlighted.\r
+\r
+  This is an internal function.\r
+\r
+  @param  MenuOption             The MenuOption to be checked.\r
+\r
+  @retval TRUE                   This Menu Option is selectable.\r
+  @retval FALSE                  This Menu Option could not be selected.\r
+\r
+**/\r
+BOOLEAN\r
+IsSelectable (\r
+  UI_MENU_OPTION   *MenuOption\r
+  )\r
+{\r
+  if ((MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_SUBTITLE_OP) ||\r
+      MenuOption->GrayOut || MenuOption->ReadOnly) {\r
+    return FALSE;\r
+  } else {\r
+    return TRUE;\r
+  }\r
+}\r
+\r
+/**\r
+  Move to next selectable statement.\r
+\r
+  This is an internal function.\r
+\r
+  @param  GoUp                   The navigation direction. TRUE: up, FALSE: down.\r
+  @param  CurrentPosition        Current position.\r
+  @param  GapToTop               Gap position to top or bottom.\r
+\r
+  @return The row distance from current MenuOption to next selectable MenuOption.\r
+\r
+  @retval -1       Reach the begin of the menu, still can't find the selectable menu.\r
+  @retval Value    Find the selectable menu, maybe the truly selectable, maybe the l\r
+                   last menu showing at current form.\r
+\r
+**/\r
+INTN\r
+MoveToNextStatement (\r
+  IN     BOOLEAN                   GoUp,\r
+  IN OUT LIST_ENTRY                **CurrentPosition,\r
+  IN     UINTN                     GapToTop\r
+  )\r
+{\r
+  INTN             Distance;\r
+  LIST_ENTRY       *Pos;\r
+  UI_MENU_OPTION   *NextMenuOption;\r
+  UI_MENU_OPTION   *PreMenuOption;\r
+\r
+  Distance      = 0;\r
+  Pos           = *CurrentPosition;\r
+  PreMenuOption = MENU_OPTION_FROM_LINK (Pos);\r
+\r
+  while (TRUE) {\r
+    NextMenuOption = MENU_OPTION_FROM_LINK (Pos);\r
+    //\r
+    // NextMenuOption->Row == 0 means this menu has not calculate\r
+    // the NextMenuOption->Skip value yet, just calculate here.\r
+    //\r
+    if (NextMenuOption->Row == 0) {\r
+      UpdateOptionSkipLines (NextMenuOption);\r
+    }\r
+    \r
+    if (GoUp && (PreMenuOption != NextMenuOption)) {\r
+      //\r
+      // In this case, still can't find the selectable menu,\r
+      // return the last one in the showing form.\r
+      //\r
+      if ((UINTN) Distance + NextMenuOption->Skip > GapToTop) {\r
+        NextMenuOption = PreMenuOption;\r
+        break;\r
+      }\r
+\r
+      //\r
+      // Current Position doesn't need to be caculated when go up.\r
+      // Caculate distanct at first when go up\r
+      //      \r
+      Distance += NextMenuOption->Skip;\r
+    }\r
+\r
+    if (IsSelectable (NextMenuOption)) {\r
+      break;\r
+    }\r
+\r
+    //\r
+    // Arrive at begin of the menu list.\r
+    //\r
+    if ((GoUp ? Pos->BackLink : Pos->ForwardLink) == &gMenuOption) {\r
+      Distance = -1;\r
+      break;\r
+    }\r
+\r
+    if (!GoUp) {\r
+      //\r
+      // In this case, still can't find the selectable menu,\r
+      // return the last one in the showing form.\r
+      //\r
+      if ((UINTN) Distance + NextMenuOption->Skip > GapToTop) {\r
+        NextMenuOption = PreMenuOption;\r
+        break;\r
+      }\r
+\r
+      Distance += NextMenuOption->Skip;\r
+    }\r
+\r
+    PreMenuOption = NextMenuOption;\r
+    Pos = (GoUp ? Pos->BackLink : Pos->ForwardLink);\r
+  }\r
+\r
+  *CurrentPosition = &NextMenuOption->Link;\r
+  return Distance;\r
+}\r
+\r
+\r
+/**\r
+  Process option string for date/time opcode.\r
+\r
+  @param  MenuOption              Menu option point to date/time.\r
+  @param  OptionString            Option string input for process.\r
+  @param  AddOptCol               Whether need to update MenuOption->OptCol. \r
+\r
+**/\r
+VOID \r
+ProcessStringForDateTime (\r
+  UI_MENU_OPTION                  *MenuOption,\r
+  CHAR16                          *OptionString,\r
+  BOOLEAN                         AddOptCol\r
+  )\r
+{\r
+  UINTN Index;\r
+  UINTN Count;\r
+  FORM_DISPLAY_ENGINE_STATEMENT          *Statement;\r
+  EFI_IFR_DATE                           *Date;\r
+  EFI_IFR_TIME                           *Time;\r
+\r
+  ASSERT (MenuOption != NULL && OptionString != NULL);\r
+  \r
+  Statement = MenuOption->ThisTag;\r
+  Date      = NULL;\r
+  Time      = NULL;\r
+  if (Statement->OpCode->OpCode == EFI_IFR_DATE_OP) {\r
+    Date = (EFI_IFR_DATE *) Statement->OpCode;\r
+  } else if (Statement->OpCode->OpCode == EFI_IFR_TIME_OP) {\r
+    Time = (EFI_IFR_TIME *) Statement->OpCode;\r
+  }\r
+  \r
+  //\r
+  // If leading spaces on OptionString - remove the spaces\r
+  //\r
+  for (Index = 0; OptionString[Index] == L' '; Index++) {\r
+    //\r
+    // Base on the blockspace to get the option column info.\r
+    //\r
+    if (AddOptCol) {\r
+      MenuOption->OptCol++;\r
+    }\r
+  }\r
+  \r
+  for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) {\r
+    OptionString[Count] = OptionString[Index];\r
+    Count++;\r
+  }\r
+  OptionString[Count] = CHAR_NULL;\r
+  \r
+  //\r
+  // Enable to suppress field in the opcode base on the flag.\r
+  //\r
+  if (Statement->OpCode->OpCode == EFI_IFR_DATE_OP) {\r
+    //\r
+    // OptionString format is: <**:  **: ****>\r
+    //                        |month|day|year|\r
+    //                          4     3    5\r
+    //\r
+    if ((Date->Flags & EFI_QF_DATE_MONTH_SUPPRESS) && (MenuOption->Sequence == 0)) {\r
+      //\r
+      // At this point, only "<**:" in the optionstring. \r
+      // Clean the day's ** field, after clean, the format is "<  :"\r
+      //\r
+      SetUnicodeMem (&OptionString[1], 2, L' ');\r
+    } else if ((Date->Flags & EFI_QF_DATE_DAY_SUPPRESS) && (MenuOption->Sequence == 1)) {\r
+      //\r
+      // At this point, only "**:" in the optionstring. \r
+      // Clean the month's "**" field, after clean, the format is "  :"\r
+      //                \r
+      SetUnicodeMem (&OptionString[0], 2, L' ');\r
+    } else if ((Date->Flags & EFI_QF_DATE_YEAR_SUPPRESS) && (MenuOption->Sequence == 2)) {\r
+      //\r
+      // At this point, only "****>" in the optionstring. \r
+      // Clean the year's "****" field, after clean, the format is "  >"\r
+      //                \r
+      SetUnicodeMem (&OptionString[0], 4, L' ');\r
+    }\r
+  } else if (Statement->OpCode->OpCode == EFI_IFR_TIME_OP) {\r
+    //\r
+    // OptionString format is: <**:  **:    **>\r
+    //                        |hour|minute|second|\r
+    //                          4     3      3\r
+    //\r
+    if ((Time->Flags & QF_TIME_HOUR_SUPPRESS) && (MenuOption->Sequence == 0)) {\r
+      //\r
+      // At this point, only "<**:" in the optionstring. \r
+      // Clean the hour's ** field, after clean, the format is "<  :"\r
+      //\r
+      SetUnicodeMem (&OptionString[1], 2, L' ');\r
+    } else if ((Time->Flags & QF_TIME_MINUTE_SUPPRESS) && (MenuOption->Sequence == 1)) {\r
+      //\r
+      // At this point, only "**:" in the optionstring. \r
+      // Clean the minute's "**" field, after clean, the format is "  :"\r
+      //                \r
+      SetUnicodeMem (&OptionString[0], 2, L' ');\r
+    } else if ((Time->Flags & QF_TIME_SECOND_SUPPRESS) && (MenuOption->Sequence == 2)) {\r
+      //\r
+      // At this point, only "**>" in the optionstring. \r
+      // Clean the second's "**" field, after clean, the format is "  >"\r
+      //                \r
+      SetUnicodeMem (&OptionString[0], 2, L' ');\r
+    }\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Adjust Data and Time position accordingly.\r
+  Data format :      [01/02/2004]      [11:22:33]\r
+  Line number :        0  0    1         0  0  1\r
+\r
+  This is an internal function.\r
+\r
+  @param  DirectionUp            the up or down direction. False is down. True is\r
+                                 up.\r
+  @param  CurrentPosition        Current position. On return: Point to the last\r
+                                 Option (Year or Second) if up; Point to the first\r
+                                 Option (Month or Hour) if down.\r
+\r
+  @return Return line number to pad. It is possible that we stand on a zero-advance\r
+  @return data or time opcode, so pad one line when we judge if we are going to scroll outside.\r
+\r
+**/\r
+UINTN\r
+AdjustDateAndTimePosition (\r
+  IN     BOOLEAN                     DirectionUp,\r
+  IN OUT LIST_ENTRY                  **CurrentPosition\r
+  )\r
+{\r
+  UINTN           Count;\r
+  LIST_ENTRY      *NewPosition;\r
+  UI_MENU_OPTION  *MenuOption;\r
+  UINTN           PadLineNumber;\r
+\r
+  PadLineNumber = 0;\r
+  NewPosition   = *CurrentPosition;\r
+  MenuOption    = MENU_OPTION_FROM_LINK (NewPosition);\r
+\r
+  if ((MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_DATE_OP) ||\r
+      (MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_TIME_OP)) {\r
+    //\r
+    // Calculate the distance from current position to the last Date/Time MenuOption\r
+    //\r
+    Count = 0;\r
+    while (MenuOption->Skip == 0) {\r
+      Count++;\r
+      NewPosition   = NewPosition->ForwardLink;\r
+      MenuOption    = MENU_OPTION_FROM_LINK (NewPosition);\r
+      PadLineNumber = 1;\r
+    }\r
+\r
+    NewPosition = *CurrentPosition;\r
+    if (DirectionUp) {\r
+      //\r
+      // Since the behavior of hitting the up arrow on a Date/Time MenuOption is intended\r
+      // to be one that back to the previous set of MenuOptions, we need to advance to the first\r
+      // Date/Time MenuOption and leave the remaining logic in CfUiUp intact so the appropriate\r
+      // checking can be done.\r
+      //\r
+      while (Count++ < 2) {\r
+        NewPosition = NewPosition->BackLink;\r
+      }\r
+    } else {\r
+      //\r
+      // Since the behavior of hitting the down arrow on a Date/Time MenuOption is intended\r
+      // to be one that progresses to the next set of MenuOptions, we need to advance to the last\r
+      // Date/Time MenuOption and leave the remaining logic in CfUiDown intact so the appropriate\r
+      // checking can be done.\r
+      //\r
+      while (Count-- > 0) {\r
+        NewPosition = NewPosition->ForwardLink;\r
+      }\r
+    }\r
+\r
+    *CurrentPosition = NewPosition;\r
+  }\r
+\r
+  return PadLineNumber;\r
+}\r
+\r
+/**\r
+  Get step info from numeric opcode.\r
+  \r
+  @param[in] OpCode     The input numeric op code.\r
+\r
+  @return step info for this opcode.\r
+**/\r
+UINT64\r
+GetFieldFromNum (\r
+  IN  EFI_IFR_OP_HEADER     *OpCode\r
+  )\r
+{\r
+  EFI_IFR_NUMERIC       *NumericOp;\r
+  UINT64                Step;\r
+\r
+  NumericOp = (EFI_IFR_NUMERIC *) OpCode;\r
+  \r
+  switch (NumericOp->Flags & EFI_IFR_NUMERIC_SIZE) {\r
+  case EFI_IFR_NUMERIC_SIZE_1:\r
+    Step    = NumericOp->data.u8.Step;\r
+    break;\r
+  \r
+  case EFI_IFR_NUMERIC_SIZE_2:\r
+    Step    = NumericOp->data.u16.Step;\r
+    break;\r
+  \r
+  case EFI_IFR_NUMERIC_SIZE_4:\r
+    Step    = NumericOp->data.u32.Step;\r
+    break;\r
+  \r
+  case EFI_IFR_NUMERIC_SIZE_8:\r
+    Step    = NumericOp->data.u64.Step;\r
+    break;\r
+  \r
+  default:\r
+    Step = 0;\r
+    break;\r
+  }\r
+\r
+  return Step;\r
+}\r
+\r
+/**\r
+  Find the registered HotKey based on KeyData.\r
+  \r
+  @param[in] KeyData     A pointer to a buffer that describes the keystroke\r
+                         information for the hot key.\r
+\r
+  @return The registered HotKey context. If no found, NULL will return.\r
+**/\r
+BROWSER_HOT_KEY *\r
+GetHotKeyFromRegisterList (\r
+  IN EFI_INPUT_KEY *KeyData\r
+  )\r
+{\r
+  LIST_ENTRY       *Link;\r
+  BROWSER_HOT_KEY  *HotKey;\r
+\r
+  Link = GetFirstNode (&gFormData->HotKeyListHead);\r
+  while (!IsNull (&gFormData->HotKeyListHead, Link)) {\r
+    HotKey = BROWSER_HOT_KEY_FROM_LINK (Link);\r
+    \r
+    if (HotKey->KeyData->ScanCode == KeyData->ScanCode) {\r
+      return HotKey;\r
+    }\r
+\r
+    Link = GetNextNode (&gFormData->HotKeyListHead, Link);\r
+  }\r
+  \r
+  return NULL;\r
+}\r
+\r
+\r
+/**\r
+  Determine if the menu is the last menu that can be selected.\r
+\r
+  This is an internal function.\r
+\r
+  @param  Direction              The scroll direction. False is down. True is up.\r
+  @param  CurrentPos             The current focus.\r
+\r
+  @return FALSE -- the menu isn't the last menu that can be selected.\r
+  @return TRUE  -- the menu is the last menu that can be selected.\r
+\r
+**/\r
+BOOLEAN\r
+ValueIsScroll (\r
+  IN  BOOLEAN                     Direction,\r
+  IN  LIST_ENTRY                  *CurrentPos\r
+  )\r
+{\r
+  LIST_ENTRY      *Temp;\r
+\r
+  Temp = Direction ? CurrentPos->BackLink : CurrentPos->ForwardLink;\r
+\r
+  if (Temp == &gMenuOption) {\r
+    return TRUE;\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  Wait for a given event to fire, or for an optional timeout to expire.\r
+\r
+  @param  Event                  The event to wait for\r
+\r
+  @retval UI_EVENT_TYPE          The type of the event which is trigged.\r
+\r
+**/\r
+UI_EVENT_TYPE\r
+UiWaitForEvent (\r
+  IN EFI_EVENT                Event\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINTN       Index;\r
+  UINTN       EventNum;\r
+  UINT64      Timeout;\r
+  EFI_EVENT   TimerEvent;\r
+  EFI_EVENT   WaitList[3];\r
+  UI_EVENT_TYPE  EventType;\r
+\r
+  TimerEvent = NULL;\r
+  Timeout    = FormExitTimeout(gFormData);\r
+\r
+  if (Timeout != 0) {\r
+    Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);\r
+\r
+    //\r
+    // Set the timer event\r
+    //\r
+    gBS->SetTimer (\r
+          TimerEvent,\r
+          TimerRelative,\r
+          Timeout\r
+          );\r
+  }\r
+  \r
+  WaitList[0] = Event;\r
+  EventNum    = 1;\r
+  if (gFormData->FormRefreshEvent != NULL) {\r
+    WaitList[EventNum] = gFormData->FormRefreshEvent;\r
+    EventNum ++;\r
+  } \r
+\r
+  if (Timeout != 0) {\r
+    WaitList[EventNum] = TimerEvent;\r
+    EventNum ++;\r
+  }\r
+\r
+  Status = gBS->WaitForEvent (EventNum, WaitList, &Index);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  switch (Index) {\r
+  case 0:\r
+   EventType = UIEventKey;\r
+   break;\r
+\r
+  case 1:\r
+    if (gFormData->FormRefreshEvent != NULL) {\r
+      EventType = UIEventDriver;\r
+    } else {\r
+      ASSERT (Timeout != 0 && EventNum == 2);\r
+      EventType = UIEventTimeOut;\r
+    }\r
+    break;\r
+\r
+  default:\r
+    ASSERT (Index == 2 && EventNum == 3);\r
+    EventType = UIEventTimeOut;\r
+    break;\r
+  }\r
+\r
+  if (Timeout != 0) {\r
+    gBS->CloseEvent (TimerEvent);\r
+  }\r
+  \r
+  return EventType;\r
+}\r
+\r
+/**\r
+  Get question id info from the input opcode header.\r
+\r
+  @param  OpCode                 The input opcode header pointer.\r
+\r
+  @retval                        The question id for this opcode.\r
+\r
+**/\r
+EFI_QUESTION_ID\r
+GetQuestionIdInfo (\r
+  IN   EFI_IFR_OP_HEADER     *OpCode\r
+  )\r
+{\r
+  EFI_IFR_QUESTION_HEADER   *QuestionHeader;\r
+\r
+  if (OpCode->Length < sizeof (EFI_IFR_OP_HEADER) + sizeof (EFI_IFR_QUESTION_HEADER)) {\r
+    return 0;\r
+  }\r
+\r
+  QuestionHeader = (EFI_IFR_QUESTION_HEADER *)((UINT8 *) OpCode + sizeof(EFI_IFR_OP_HEADER));\r
+\r
+  return QuestionHeader->QuestionId;\r
+}\r
+\r
+/**\r
+  Find the first menu which will be show at the top.\r
+\r
+  @param  FormData               The data info for this form.\r
+  @param  TopOfScreen            The link_entry pointer to top menu.\r
+  @param  HighlightMenu          The menu which will be highlight.\r
+  @param  SkipValue              The skip value for the top menu.\r
+\r
+**/\r
+VOID\r
+FindTopMenu (\r
+  IN  FORM_DISPLAY_ENGINE_FORM  *FormData,\r
+  OUT LIST_ENTRY                **TopOfScreen,\r
+  OUT LIST_ENTRY                **HighlightMenu,\r
+  OUT INTN                      *SkipValue\r
+  )\r
+{\r
+  LIST_ENTRY                      *Link;\r
+  LIST_ENTRY                      *NewPos;\r
+  UINTN                           TopRow;\r
+  UINTN                           BottomRow;\r
+  UINTN                           Index;\r
+  UI_MENU_OPTION                  *SavedMenuOption;\r
+  UINTN                           EndRow;\r
+\r
+  TopRow    = gStatementDimensions.TopRow    + SCROLL_ARROW_HEIGHT;\r
+  BottomRow = gStatementDimensions.BottomRow - SCROLL_ARROW_HEIGHT;\r
+\r
+  //\r
+  // If not has input highlight statement, just return the first one in this form.\r
+  //\r
+  if (FormData->HighLightedStatement == NULL) {\r
+    *TopOfScreen   = gMenuOption.ForwardLink;\r
+    *HighlightMenu = gMenuOption.ForwardLink;\r
+    if (!IsListEmpty (&gMenuOption)) {\r
+      MoveToNextStatement (FALSE, HighlightMenu, BottomRow - TopRow);\r
+    }\r
+    *SkipValue     = 0;\r
+    return;\r
+  }\r
+\r
+  //\r
+  // Now base on the input highlight menu to find the top menu in this page.\r
+  // Will base on the highlight menu show at the bottom to find the top menu.\r
+  //\r
+  NewPos = gMenuOption.ForwardLink;\r
+  SavedMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
+\r
+  while ((SavedMenuOption->ThisTag != FormData->HighLightedStatement) ||\r
+         (SavedMenuOption->Sequence != gSequence)) {\r
+    NewPos     = NewPos->ForwardLink;\r
+    if (NewPos == &gMenuOption) {\r
+      //\r
+      // Not Found it, break\r
+      //\r
+      break;\r
+    }\r
+    SavedMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
+  }\r
+  ASSERT (SavedMenuOption->ThisTag == FormData->HighLightedStatement);\r
+\r
+  *HighlightMenu = NewPos;\r
+\r
+  AdjustDateAndTimePosition(FALSE, &NewPos);\r
+  SavedMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
+  UpdateOptionSkipLines (SavedMenuOption);\r
+\r
+  //\r
+  // If highlight opcode is date/time, keep the highlight row info not change.\r
+  //\r
+  if ((SavedMenuOption->ThisTag->OpCode->OpCode == EFI_IFR_DATE_OP || SavedMenuOption->ThisTag->OpCode->OpCode == EFI_IFR_TIME_OP) &&\r
+      (gHighligthMenuInfo.QuestionId != 0) && \r
+      (gHighligthMenuInfo.QuestionId == GetQuestionIdInfo(SavedMenuOption->ThisTag->OpCode))) {\r
+    //\r
+    // Still show the highlight menu before exit from display engine.\r
+    //\r
+    EndRow = gHighligthMenuInfo.DisplayRow + SavedMenuOption->Skip;\r
+  } else {\r
+    EndRow = BottomRow;\r
+  }\r
+\r
+  //\r
+  // Base on the selected menu will show at the bottome of next page, \r
+  // select the menu show at the top of the next page. \r
+  //\r
+  Link    = NewPos;\r
+  for (Index = TopRow + SavedMenuOption->Skip; Index <= EndRow; ) {\r
+    Link = Link->BackLink;\r
+    //\r
+    // Already find the first menu in this form, means highlight menu \r
+    // will show in first page of this form.\r
+    //\r
+    if (Link == &gMenuOption) {\r
+      *TopOfScreen   = gMenuOption.ForwardLink;\r
+      *SkipValue     = 0;\r
+      return;\r
+    }\r
+    SavedMenuOption = MENU_OPTION_FROM_LINK (Link);\r
+    UpdateOptionSkipLines (SavedMenuOption);\r
+    Index += SavedMenuOption->Skip;\r
+  }\r
+\r
+  //\r
+  // Found the menu which will show at the top of the page.\r
+  //\r
+  if (Link == NewPos) {\r
+    //\r
+    // The menu can show more than one pages, just show the menu at the top of the page.\r
+    //\r
+    *SkipValue    = 0;\r
+    *TopOfScreen  = Link;\r
+  } else {\r
+    //\r
+    // Check whether need to skip some line for menu shows at the top of the page.\r
+    //\r
+    *SkipValue = Index - EndRow;\r
+    if (*SkipValue > 0 && *SkipValue < (INTN) SavedMenuOption->Skip) {\r
+      *TopOfScreen     = Link;\r
+    } else {\r
+      *SkipValue       = 0;\r
+      *TopOfScreen     = Link->ForwardLink;\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  Display menu and wait for user to select one menu option, then return it.\r
+  If AutoBoot is enabled, then if user doesn't select any option,\r
+  after period of time, it will automatically return the first menu option.\r
+\r
+  @param  FormData               The current form data info.\r
+\r
+  @retval EFI_SUCESSS            Process the user selection success.\r
+  @retval EFI_NOT_FOUND          Process option string for orderedlist/Oneof fail.\r
+\r
+**/\r
+EFI_STATUS\r
+UiDisplayMenu (\r
+  IN  FORM_DISPLAY_ENGINE_FORM  *FormData\r
+  )\r
+{\r
+  INTN                            SkipValue;\r
+  INTN                            Difference;\r
+  UINTN                           DistanceValue;\r
+  UINTN                           Row;\r
+  UINTN                           Col;\r
+  UINTN                           TempRightCol;\r
+  UINTN                           Temp;\r
+  UINTN                           Temp2;\r
+  UINTN                           Temp3;\r
+  UINTN                           TopRow;\r
+  UINTN                           BottomRow;\r
+  UINTN                           OriginalRow;\r
+  UINTN                           Index;\r
+  UINT16                          Width;\r
+  CHAR16                          *StringPtr;\r
+  CHAR16                          *OptionString;\r
+  CHAR16                          *OutputString;\r
+  CHAR16                          *HelpString;\r
+  CHAR16                          *HelpHeaderString;\r
+  CHAR16                          *HelpBottomString;\r
+  BOOLEAN                         NewLine;\r
+  BOOLEAN                         Repaint;\r
+  BOOLEAN                         UpArrow;\r
+  BOOLEAN                         DownArrow;\r
+  EFI_STATUS                      Status;\r
+  EFI_INPUT_KEY                   Key;\r
+  LIST_ENTRY                      *Link;\r
+  LIST_ENTRY                      *NewPos;\r
+  LIST_ENTRY                      *TopOfScreen;\r
+  LIST_ENTRY                      *SavedListEntry;\r
+  UI_MENU_OPTION                  *MenuOption;\r
+  UI_MENU_OPTION                  *NextMenuOption;\r
+  UI_MENU_OPTION                  *SavedMenuOption;\r
+  UI_MENU_OPTION                  *PreviousMenuOption;\r
+  UI_CONTROL_FLAG                 ControlFlag;\r
+  UI_SCREEN_OPERATION             ScreenOperation;\r
+  UINT16                          DefaultId;\r
+  FORM_DISPLAY_ENGINE_STATEMENT   *Statement;\r
+  UINTN                           ModalSkipColumn;\r
+  BROWSER_HOT_KEY                 *HotKey;\r
+  UINTN                           HelpPageIndex;\r
+  UINTN                           HelpPageCount;\r
+  UINTN                           RowCount;\r
+  UINTN                           HelpLine;\r
+  UINTN                           HelpHeaderLine;\r
+  UINTN                           HelpBottomLine;\r
+  BOOLEAN                         MultiHelpPage;\r
+  UINT16                          GlyphWidth;\r
+  UINT16                          EachLineWidth;\r
+  UINT16                          HeaderLineWidth;\r
+  UINT16                          BottomLineWidth;\r
+  EFI_STRING_ID                   HelpInfo;\r
+  UI_EVENT_TYPE                   EventType;\r
+  FORM_DISPLAY_ENGINE_STATEMENT   *InitialHighlight;\r
+\r
+  EventType           = UIEventNone;\r
+  Status              = EFI_SUCCESS;\r
+  HelpString          = NULL;\r
+  HelpHeaderString    = NULL;\r
+  HelpBottomString    = NULL;\r
+  OptionString        = NULL;\r
+  ScreenOperation     = UiNoOperation;\r
+  NewLine             = TRUE;\r
+  DefaultId           = 0;\r
+  HelpPageCount       = 0;\r
+  HelpLine            = 0;\r
+  RowCount            = 0;\r
+  HelpBottomLine      = 0;\r
+  HelpHeaderLine      = 0;\r
+  HelpPageIndex       = 0;\r
+  MultiHelpPage       = FALSE;\r
+  EachLineWidth       = 0;\r
+  HeaderLineWidth     = 0;\r
+  BottomLineWidth     = 0;\r
+  OutputString        = NULL;\r
+  UpArrow             = FALSE;\r
+  DownArrow           = FALSE;\r
+  SkipValue           = 0;\r
+\r
+  NextMenuOption      = NULL;\r
+  PreviousMenuOption  = NULL;\r
+  SavedMenuOption     = NULL;\r
+  HotKey              = NULL;\r
+  Repaint             = TRUE;\r
+  MenuOption          = NULL;\r
+  ModalSkipColumn     = (gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn) / 6;\r
+  InitialHighlight    = gFormData->HighLightedStatement;\r
+\r
+  ZeroMem (&Key, sizeof (EFI_INPUT_KEY));\r
+\r
+  gOptionBlockWidth = (CHAR16) ((gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn) / 3);\r
+  gPromptBlockWidth = (CHAR16) (gOptionBlockWidth + LEFT_SKIPPED_COLUMNS);\r
+  gHelpBlockWidth   = (CHAR16) (gOptionBlockWidth - LEFT_SKIPPED_COLUMNS);\r
+\r
+  TopRow    = gStatementDimensions.TopRow    + SCROLL_ARROW_HEIGHT;\r
+  BottomRow = gStatementDimensions.BottomRow - SCROLL_ARROW_HEIGHT - 1;\r
+\r
+  Row = TopRow;\r
+  if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) {\r
+    Col = gStatementDimensions.LeftColumn + LEFT_SKIPPED_COLUMNS + ModalSkipColumn;\r
+  } else {\r
+    Col = gStatementDimensions.LeftColumn + LEFT_SKIPPED_COLUMNS;\r
+  }\r
+\r
+  FindTopMenu(FormData, &TopOfScreen, &NewPos, &SkipValue);\r
+\r
+  gST->ConOut->EnableCursor (gST->ConOut, FALSE);\r
+\r
+  ControlFlag = CfInitialization;\r
+  while (TRUE) {\r
+    switch (ControlFlag) {\r
+    case CfInitialization:\r
+      if (IsListEmpty (&gMenuOption)) {\r
+        \r
+        if ((FormData->Attribute & HII_DISPLAY_MODAL) == 0) {\r
+          //\r
+          // Clear Statement range.\r
+          //\r
+          ClearLines (\r
+            gStatementDimensions.LeftColumn,\r
+            gStatementDimensions.RightColumn,\r
+            TopRow - SCROLL_ARROW_HEIGHT,\r
+            BottomRow + SCROLL_ARROW_HEIGHT,\r
+            GetFieldTextColor ()\r
+            );\r
+            \r
+          //\r
+          // Clear Key Range\r
+          //\r
+          RefreshKeyHelp (gFormData, NULL, FALSE);\r
+        }\r
+\r
+        ControlFlag = CfReadKey;\r
+      } else {\r
+        ControlFlag = CfRepaint;\r
+      }\r
+      break;\r
+\r
+    case CfRepaint:\r
+      ControlFlag = CfRefreshHighLight;\r
+\r
+      if (Repaint) {\r
+        //\r
+        // Display menu\r
+        //\r
+        DownArrow       = FALSE;\r
+        UpArrow         = FALSE;\r
+        Row             = TopRow;\r
+\r
+        Temp            = (UINTN) SkipValue;\r
+        Temp2           = (UINTN) SkipValue;\r
+        Temp3           = (UINTN) SkipValue;\r
+\r
+        //\r
+        // 1. Clear the screen.\r
+        //\r
+        if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) {\r
+          ClearLines (\r
+            gStatementDimensions.LeftColumn + ModalSkipColumn,\r
+            gStatementDimensions.LeftColumn + ModalSkipColumn + gPromptBlockWidth + gOptionBlockWidth,\r
+            TopRow - SCROLL_ARROW_HEIGHT,\r
+            BottomRow + SCROLL_ARROW_HEIGHT,\r
+            GetFieldTextColor ()\r
+            );\r
+        } else {\r
+          TempRightCol = gStatementDimensions.RightColumn;\r
+          if (!mStatementLayoutIsChanged) {\r
+            TempRightCol = gStatementDimensions.RightColumn - gHelpBlockWidth;\r
+          }\r
+          ClearLines (\r
+            gStatementDimensions.LeftColumn,\r
+            gStatementDimensions.RightColumn,\r
+            TopRow - SCROLL_ARROW_HEIGHT,\r
+            TopRow - 1,\r
+            GetFieldTextColor ()\r
+            );\r
+          ClearLines (\r
+            gStatementDimensions.LeftColumn,\r
+            TempRightCol,\r
+            TopRow,\r
+            BottomRow,\r
+            GetFieldTextColor ()\r
+            );\r
+          ClearLines (\r
+            gStatementDimensions.LeftColumn,\r
+            gStatementDimensions.RightColumn,\r
+            BottomRow + 1,\r
+            BottomRow + SCROLL_ARROW_HEIGHT,\r
+            GetFieldTextColor ()\r
+            );\r
+        }\r
+\r
+        //\r
+        // 2.Paint the menu.\r
+        //\r
+        for (Link = TopOfScreen; Link != &gMenuOption; Link = Link->ForwardLink) {\r
+          MenuOption          = MENU_OPTION_FROM_LINK (Link);\r
+          MenuOption->Row     = Row;\r
+          MenuOption->Col     = Col;\r
+          if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) {\r
+            MenuOption->OptCol  = gPromptBlockWidth + 1 + gStatementDimensions.LeftColumn + ModalSkipColumn;\r
+          } else {\r
+            MenuOption->OptCol  = gPromptBlockWidth + 1 + gStatementDimensions.LeftColumn;\r
+          }\r
+\r
+          Statement = MenuOption->ThisTag;\r
+          if (MenuOption->NestInStatement) {\r
+            MenuOption->Col += SUBTITLE_INDENT;\r
+          }\r
+\r
+          if (MenuOption->GrayOut) {\r
+            gST->ConOut->SetAttribute (gST->ConOut, GetGrayedTextColor ());\r
+          } else {\r
+            if (Statement->OpCode->OpCode == EFI_IFR_SUBTITLE_OP) {\r
+              gST->ConOut->SetAttribute (gST->ConOut, GetSubTitleTextColor ());\r
+            }\r
+          }\r
+\r
+          Width       = GetWidth (Statement);\r
+          OriginalRow = Row;\r
+          GlyphWidth  = 1;\r
+\r
+          if (Statement->OpCode->OpCode == EFI_IFR_REF_OP && MenuOption->Col >= 2) {\r
+            //\r
+            // Print Arrow for Goto button.\r
+            //\r
+            PrintCharAt (\r
+              MenuOption->Col - 2,\r
+              Row,\r
+              GEOMETRICSHAPE_RIGHT_TRIANGLE\r
+              );\r
+          }\r
+\r
+          //\r
+          // 2.1. Paint the description.\r
+          //\r
+          for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) {\r
+            //\r
+            // Temp means need to skip how many lines from the start.\r
+            //\r
+            if ((Temp == 0) && (Row <= BottomRow)) {\r
+              PrintStringAt (MenuOption->Col, Row, OutputString);\r
+            }\r
+            //\r
+            // If there is more string to process print on the next row and increment the Skip value\r
+            //\r
+            if (StrLen (&MenuOption->Description[Index]) != 0) {\r
+              if (Temp == 0) {\r
+                Row++;\r
+              }\r
+            }\r
+\r
+            FreePool (OutputString);\r
+            if (Temp != 0) {\r
+              Temp--;\r
+            }\r
+          }\r
+\r
+          Temp  = 0;\r
+          Row   = OriginalRow;\r
+\r
+          //\r
+          // 2.2. Paint the option string.\r
+          //\r
+          Status = ProcessOptions (MenuOption, FALSE, &OptionString, FALSE);\r
+          //\r
+          // If Error occur, question value update in ProcessOptions.\r
+          // Exit current FormDisplay with new question value.\r
+          //\r
+          if (EFI_ERROR (Status)) {\r
+            return Status;\r
+          }\r
+\r
+          if (OptionString != NULL) {\r
+            if (Statement->OpCode->OpCode == EFI_IFR_DATE_OP || Statement->OpCode->OpCode == EFI_IFR_TIME_OP) {\r
+              ProcessStringForDateTime(MenuOption, OptionString, TRUE);\r
+            }\r
+\r
+            Width       = (UINT16) gOptionBlockWidth;\r
+            OriginalRow = Row;\r
+            GlyphWidth  = 1;\r
+\r
+            for (Index = 0; GetLineByWidth (OptionString, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) {\r
+              if ((Temp2 == 0) && (Row <= BottomRow)) {\r
+                PrintStringAt (MenuOption->OptCol, Row, OutputString);\r
+              }\r
+              //\r
+              // If there is more string to process print on the next row and increment the Skip value\r
+              //\r
+              if (StrLen (&OptionString[Index]) != 0) {\r
+                if (Temp2 == 0) {\r
+                  Row++;\r
+                  //\r
+                  // Since the Number of lines for this menu entry may or may not be reflected accurately\r
+                  // since the prompt might be 1 lines and option might be many, and vice versa, we need to do\r
+                  // some testing to ensure we are keeping this in-sync.\r
+                  //\r
+                  // If the difference in rows is greater than or equal to the skip value, increase the skip value\r
+                  //\r
+                  if ((Row - OriginalRow) >= MenuOption->Skip) {\r
+                    MenuOption->Skip++;\r
+                  }\r
+                }\r
+              }\r
+\r
+              FreePool (OutputString);\r
+              if (Temp2 != 0) {\r
+                Temp2--;\r
+              }\r
+            }\r
+\r
+            Row   = OriginalRow;\r
+\r
+            FreePool (OptionString);\r
+          }\r
+          Temp2 = 0;\r
+\r
+          //\r
+          // If this is a text op with secondary text information\r
+          //\r
+          if ((Statement->OpCode->OpCode  == EFI_IFR_TEXT_OP) && (((EFI_IFR_TEXT*)Statement->OpCode)->TextTwo != 0)) {\r
+            StringPtr   = GetToken (((EFI_IFR_TEXT*)Statement->OpCode)->TextTwo, gFormData->HiiHandle);\r
+\r
+            Width       = (UINT16) gOptionBlockWidth;\r
+            OriginalRow = Row;\r
+            GlyphWidth = 1;\r
+\r
+            for (Index = 0; GetLineByWidth (StringPtr, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) {\r
+              if ((Temp3 == 0) && (Row <= BottomRow)) {\r
+                PrintStringAt (MenuOption->OptCol, Row, OutputString);\r
+              }\r
+              //\r
+              // If there is more string to process print on the next row and increment the Skip value\r
+              //\r
+              if (StrLen (&StringPtr[Index]) != 0) {\r
+                if (Temp3 == 0) {\r
+                  Row++;\r
+                  //\r
+                  // Since the Number of lines for this menu entry may or may not be reflected accurately\r
+                  // since the prompt might be 1 lines and option might be many, and vice versa, we need to do\r
+                  // some testing to ensure we are keeping this in-sync.\r
+                  //\r
+                  // If the difference in rows is greater than or equal to the skip value, increase the skip value\r
+                  //\r
+                  if ((Row - OriginalRow) >= MenuOption->Skip) {\r
+                    MenuOption->Skip++;\r
+                  }\r
+                }\r
+              }\r
+\r
+              FreePool (OutputString);\r
+              if (Temp3 != 0) {\r
+                Temp3--;\r
+              }\r
+            }\r
+\r
+            Row = OriginalRow;\r
+            FreePool (StringPtr);\r
+          }\r
+          Temp3 = 0;\r
+\r
+          gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ());\r
+\r
+          //\r
+          // 3. Update the row info which will be used by next menu.\r
+          //\r
+          if (Link == TopOfScreen) {\r
+            Row += MenuOption->Skip - SkipValue;\r
+          } else {\r
+            Row += MenuOption->Skip;\r
+          }\r
+\r
+          if (Row > BottomRow) {\r
+            if (!ValueIsScroll (FALSE, Link)) {\r
+              DownArrow = TRUE;\r
+            }\r
+\r
+            Row = BottomRow + 1;\r
+            break;\r
+          }\r
+        }\r
+\r
+        if (!ValueIsScroll (TRUE, TopOfScreen)) {\r
+          UpArrow = TRUE;\r
+        }\r
+\r
+        if (UpArrow) {\r
+          gST->ConOut->SetAttribute (gST->ConOut, GetArrowColor ());\r
+          PrintCharAt (\r
+            gStatementDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1,\r
+            TopRow - SCROLL_ARROW_HEIGHT,\r
+            ARROW_UP\r
+            );\r
+          gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ());\r
+        }\r
+\r
+        if (DownArrow) {\r
+          gST->ConOut->SetAttribute (gST->ConOut, GetArrowColor ());\r
+          PrintCharAt (\r
+            gStatementDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1,\r
+            BottomRow + SCROLL_ARROW_HEIGHT,\r
+            ARROW_DOWN\r
+            );\r
+          gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ());\r
+        }\r
+\r
+        MenuOption = NULL;\r
+      }\r
+      break;\r
+\r
+    case CfRefreshHighLight:\r
+\r
+      //\r
+      // MenuOption: Last menu option that need to remove hilight\r
+      //             MenuOption is set to NULL in Repaint\r
+      // NewPos:     Current menu option that need to hilight\r
+      //\r
+      ControlFlag = CfUpdateHelpString;\r
+\r
+      if (MenuOption != NULL && TopOfScreen == &MenuOption->Link) {\r
+        Temp = SkipValue;\r
+      } else {\r
+        Temp = 0;\r
+      }\r
+      if (NewPos == TopOfScreen) {\r
+        Temp2 = SkipValue;\r
+      } else {\r
+        Temp2 = 0;\r
+      }\r
+\r
+      if (NewPos != NULL && (MenuOption == NULL || NewPos != &MenuOption->Link)) {\r
+        if (MenuOption != NULL) {\r
+          //\r
+          // Remove highlight on last Menu Option\r
+          //\r
+          gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row);\r
+          ProcessOptions (MenuOption, FALSE, &OptionString, TRUE);\r
+          gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ());\r
+          if (OptionString != NULL) {\r
+            if ((MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_DATE_OP) ||\r
+                (MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_TIME_OP)\r
+               ) {\r
+              ProcessStringForDateTime(MenuOption, OptionString, FALSE);\r
+            }\r
+\r
+            Width               = (UINT16) gOptionBlockWidth;\r
+            OriginalRow         = MenuOption->Row;\r
+            GlyphWidth          = 1;\r
+\r
+            for (Index = 0; GetLineByWidth (OptionString, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) {\r
+              if ((Temp == 0) && (MenuOption->Row >= TopRow) && (MenuOption->Row <= BottomRow)) {\r
+                PrintStringAt (MenuOption->OptCol, MenuOption->Row, OutputString);\r
+              }\r
+              //\r
+              // If there is more string to process print on the next row and increment the Skip value\r
+              //\r
+              if (StrLen (&OptionString[Index]) != 0) {\r
+                if (Temp == 0) {\r
+                  MenuOption->Row++;\r
+                }\r
+              }\r
+\r
+              FreePool (OutputString);\r
+              if (Temp != 0) {\r
+                Temp--;\r
+              }\r
+            }\r
+\r
+            MenuOption->Row = OriginalRow;\r
+\r
+            FreePool (OptionString);\r
+          } else {\r
+            if (NewLine) {\r
+              if (MenuOption->GrayOut) {\r
+                gST->ConOut->SetAttribute (gST->ConOut, GetGrayedTextColor ());\r
+              } else if (MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_SUBTITLE_OP) {\r
+                gST->ConOut->SetAttribute (gST->ConOut, GetSubTitleTextColor ());\r
+              }\r
+\r
+              OriginalRow = MenuOption->Row;\r
+              Width       = GetWidth (MenuOption->ThisTag);\r
+              GlyphWidth  = 1;\r
+\r
+              for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) {\r
+                if ((Temp == 0) && (MenuOption->Row >= TopRow) && (MenuOption->Row <= BottomRow)) {\r
+                  PrintStringAt (MenuOption->Col, MenuOption->Row, OutputString);\r
+                }\r
+                //\r
+                // If there is more string to process print on the next row and increment the Skip value\r
+                //\r
+                if (StrLen (&MenuOption->Description[Index]) != 0) {\r
+                  if (Temp == 0) {\r
+                    MenuOption->Row++;\r
+                  }\r
+                }\r
+\r
+                FreePool (OutputString);\r
+                if (Temp != 0) {\r
+                  Temp--;\r
+                }\r
+              }\r
+\r
+              MenuOption->Row = OriginalRow;\r
+              gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ());\r
+            }\r
+          }\r
+        }\r
+\r
+        //\r
+        // This is the current selected statement\r
+        //\r
+        MenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
+        Statement = MenuOption->ThisTag;\r
+\r
+        //\r
+        // Get the highlight statement.\r
+        //\r
+        gUserInput->SelectedStatement = Statement;\r
+        gSequence = (UINT16) MenuOption->Sequence;\r
+\r
+        //\r
+        // Record highlight row info for date/time opcode.\r
+        //\r
+        if (Statement->OpCode->OpCode == EFI_IFR_DATE_OP || Statement->OpCode->OpCode == EFI_IFR_TIME_OP) {\r
+          gHighligthMenuInfo.QuestionId = GetQuestionIdInfo(Statement->OpCode);\r
+          gHighligthMenuInfo.DisplayRow = (UINT16) MenuOption->Row;\r
+        } else {\r
+          gHighligthMenuInfo.QuestionId = 0;\r
+          gHighligthMenuInfo.DisplayRow = 0;\r
+        }\r
+\r
+        if (!IsSelectable (MenuOption)) {\r
+          RefreshKeyHelp(gFormData, Statement, FALSE);\r
+          break;\r
+        }\r
+\r
+        //\r
+        // Set reverse attribute\r
+        //\r
+        gST->ConOut->SetAttribute (gST->ConOut, GetHighlightTextColor ());\r
+        gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row);\r
+\r
+        ProcessOptions (MenuOption, FALSE, &OptionString, TRUE);\r
+        if (OptionString != NULL) {\r
+          if (Statement->OpCode->OpCode == EFI_IFR_DATE_OP || Statement->OpCode->OpCode == EFI_IFR_TIME_OP) {\r
+            ProcessStringForDateTime(MenuOption, OptionString, FALSE);\r
+          }\r
+          Width               = (UINT16) gOptionBlockWidth;\r
+\r
+          OriginalRow         = MenuOption->Row;\r
+          GlyphWidth          = 1;\r
+\r
+          for (Index = 0; GetLineByWidth (OptionString, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) {\r
+            if ((Temp2 == 0) && (MenuOption->Row >= TopRow) && (MenuOption->Row <= BottomRow) ) {\r
+              PrintStringAt (MenuOption->OptCol, MenuOption->Row, OutputString);\r
+            }\r
+            //\r
+            // If there is more string to process print on the next row and increment the Skip value\r
+            //\r
+            if (StrLen (&OptionString[Index]) != 0) {\r
+              if (Temp2 == 0) {\r
+              MenuOption->Row++;\r
+              }\r
+            }\r
+\r
+            FreePool (OutputString);\r
+            if (Temp2 != 0) {\r
+              Temp2--;\r
+            }\r
+          }\r
+\r
+          MenuOption->Row = OriginalRow;\r
+\r
+          FreePool (OptionString);\r
+        } else {\r
+          if (NewLine) {\r
+            OriginalRow = MenuOption->Row;\r
+\r
+            Width       = GetWidth (Statement);\r
+            GlyphWidth          = 1;\r
+\r
+            for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &GlyphWidth, &Index, &OutputString) != 0x0000;) {\r
+              if ((Temp2 == 0) && (MenuOption->Row >= TopRow) && (MenuOption->Row <= BottomRow) ) {\r
+                PrintStringAt (MenuOption->Col, MenuOption->Row, OutputString);\r
+              }\r
+              //\r
+              // If there is more string to process print on the next row and increment the Skip value\r
+              //\r
+              if (StrLen (&MenuOption->Description[Index]) != 0) {\r
+                if (Temp2 == 0) {\r
+                  MenuOption->Row++;\r
+                }\r
+              }\r
+\r
+              FreePool (OutputString);\r
+              if (Temp2 != 0) {\r
+                Temp2--;\r
+              }\r
+            }\r
+\r
+            MenuOption->Row = OriginalRow;\r
+\r
+          }\r
+        }\r
+\r
+        RefreshKeyHelp(gFormData, MenuOption->ThisTag, FALSE);\r
+\r
+        //\r
+        // Clear reverse attribute\r
+        //\r
+        gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ());\r
+      }\r
+      break;\r
+\r
+    case CfUpdateHelpString:\r
+      ControlFlag = CfPrepareToReadKey;\r
+      if ((FormData->Attribute & HII_DISPLAY_MODAL) != 0) {\r
+        break;\r
+      }\r
+\r
+      if (Repaint || NewLine) {\r
+        //\r
+        // Don't print anything if it is a NULL help token\r
+        //\r
+        ASSERT(MenuOption != NULL);\r
+        HelpInfo = ((EFI_IFR_STATEMENT_HEADER *) ((CHAR8 *)MenuOption->ThisTag->OpCode + sizeof (EFI_IFR_OP_HEADER)))->Help;\r
+        if (HelpInfo == 0 || !IsSelectable (MenuOption)) {\r
+          StringPtr = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle);\r
+        } else {\r
+          StringPtr = GetToken (HelpInfo, gFormData->HiiHandle);\r
+        }\r
+\r
+        RowCount      = BottomRow - TopRow + 1;\r
+        HelpPageIndex = 0;\r
+        //\r
+        // 1.Calculate how many line the help string need to print.\r
+        //\r
+        if (HelpString != NULL) {\r
+          FreePool (HelpString);\r
+          HelpString = NULL;\r
+        }\r
+        HelpLine = ProcessHelpString (StringPtr, &HelpString, &EachLineWidth, RowCount);\r
+        FreePool (StringPtr);\r
+\r
+        if (HelpLine > RowCount) {\r
+          MultiHelpPage   = TRUE;\r
+          StringPtr       = GetToken (STRING_TOKEN(ADJUST_HELP_PAGE_UP), gHiiHandle);\r
+          if (HelpHeaderString != NULL) {\r
+            FreePool (HelpHeaderString);\r
+            HelpHeaderString = NULL;\r
+          }\r
+          HelpHeaderLine  = ProcessHelpString (StringPtr, &HelpHeaderString, &HeaderLineWidth, 0);\r
+          FreePool (StringPtr);\r
+          StringPtr       = GetToken (STRING_TOKEN(ADJUST_HELP_PAGE_DOWN), gHiiHandle);\r
+          if (HelpBottomString != NULL) {\r
+            FreePool (HelpBottomString);\r
+            HelpBottomString = NULL;\r
+          }\r
+          HelpBottomLine  = ProcessHelpString (StringPtr, &HelpBottomString, &BottomLineWidth, 0);\r
+          FreePool (StringPtr);\r
+          //\r
+          // Calculate the help page count.\r
+          //\r
+          if (HelpLine > 2 * RowCount - 2) {\r
+            HelpPageCount = (HelpLine - RowCount + 1) / (RowCount - 2) + 1;\r
+            if ((HelpLine - RowCount + 1) % (RowCount - 2) > 1) {\r
+              HelpPageCount += 1;\r
+            }\r
+          } else {\r
+            HelpPageCount = 2;\r
+          }\r
+        } else {\r
+          MultiHelpPage = FALSE;\r
+        }\r
+      }\r
+\r
+      //\r
+      // Check whether need to show the 'More(U/u)' at the begin.\r
+      // Base on current direct info, here shows aligned to the right side of the column.\r
+      // If the direction is multi line and aligned to right side may have problem, so \r
+      // add ASSERT code here.\r
+      //\r
+      if (HelpPageIndex > 0) {\r
+        gST->ConOut->SetAttribute (gST->ConOut, GetInfoTextColor ());\r
+        for (Index = 0; Index < HelpHeaderLine; Index++) {\r
+          ASSERT (HelpHeaderLine == 1);\r
+          ASSERT (GetStringWidth (HelpHeaderString) / 2 < (UINTN) (gHelpBlockWidth - 1));\r
+          PrintStringAtWithWidth (\r
+            gStatementDimensions.RightColumn - gHelpBlockWidth,\r
+            Index + TopRow,\r
+            gEmptyString,\r
+            gHelpBlockWidth\r
+            );\r
+          PrintStringAt (\r
+            gStatementDimensions.RightColumn - GetStringWidth (HelpHeaderString) / 2 - 1,\r
+            Index + TopRow,\r
+            &HelpHeaderString[Index * HeaderLineWidth]\r
+            );\r
+        }\r
+      }\r
+\r
+      gST->ConOut->SetAttribute (gST->ConOut, GetHelpTextColor ());\r
+      //\r
+      // Print the help string info.\r
+      //\r
+      if (!MultiHelpPage) {\r
+        for (Index = 0; Index < HelpLine; Index++) {\r
+          PrintStringAtWithWidth (\r
+            gStatementDimensions.RightColumn - gHelpBlockWidth,\r
+            Index + TopRow,\r
+            &HelpString[Index * EachLineWidth],\r
+            gHelpBlockWidth\r
+            );\r
+        }\r
+        for (; Index < RowCount; Index ++) {\r
+          PrintStringAtWithWidth (\r
+            gStatementDimensions.RightColumn - gHelpBlockWidth,\r
+            Index + TopRow,\r
+            gEmptyString,\r
+            gHelpBlockWidth\r
+            );\r
+        }\r
+        gST->ConOut->SetCursorPosition(gST->ConOut, gStatementDimensions.RightColumn-1, BottomRow);\r
+      } else  {\r
+        if (HelpPageIndex == 0) {\r
+          for (Index = 0; Index < RowCount - HelpBottomLine; Index++) {\r
+            PrintStringAtWithWidth (\r
+              gStatementDimensions.RightColumn - gHelpBlockWidth,\r
+              Index + TopRow,\r
+              &HelpString[Index * EachLineWidth],\r
+              gHelpBlockWidth\r
+              );\r
+          }\r
+        } else {\r
+          for (Index = 0; (Index < RowCount - HelpBottomLine - HelpHeaderLine) && \r
+              (Index + HelpPageIndex * (RowCount - 2) + 1 < HelpLine); Index++) {\r
+            PrintStringAtWithWidth (\r
+              gStatementDimensions.RightColumn - gHelpBlockWidth,\r
+              Index + TopRow + HelpHeaderLine,\r
+              &HelpString[(Index + HelpPageIndex * (RowCount - 2) + 1)* EachLineWidth],\r
+              gHelpBlockWidth\r
+              );\r
+          }\r
+          if (HelpPageIndex == HelpPageCount - 1) {\r
+            for (; Index < RowCount - HelpHeaderLine; Index ++) {\r
+              PrintStringAtWithWidth (\r
+                gStatementDimensions.RightColumn - gHelpBlockWidth,\r
+                Index + TopRow + HelpHeaderLine,\r
+                gEmptyString,\r
+                gHelpBlockWidth\r
+                );\r
+            }\r
+            gST->ConOut->SetCursorPosition(gST->ConOut, gStatementDimensions.RightColumn-1, BottomRow);\r
+          }\r
+        } \r
+      }\r
+\r
+      //\r
+      // Check whether need to print the 'More(D/d)' at the bottom.\r
+      // Base on current direct info, here shows aligned to the right side of the column.\r
+      // If the direction is multi line and aligned to right side may have problem, so \r
+      // add ASSERT code here.\r
+      //\r
+      if (HelpPageIndex < HelpPageCount - 1 && MultiHelpPage) {\r
+        gST->ConOut->SetAttribute (gST->ConOut, GetInfoTextColor ());\r
+        for (Index = 0; Index < HelpBottomLine; Index++) {\r
+          ASSERT (HelpBottomLine == 1);\r
+          ASSERT (GetStringWidth (HelpBottomString) / 2 < (UINTN) (gHelpBlockWidth - 1)); \r
+          PrintStringAtWithWidth (\r
+            gStatementDimensions.RightColumn - gHelpBlockWidth,\r
+            BottomRow + Index - HelpBottomLine + 1,\r
+            gEmptyString,\r
+            gHelpBlockWidth\r
+            );\r
+          PrintStringAt (\r
+            gStatementDimensions.RightColumn - GetStringWidth (HelpBottomString) / 2 - 1,\r
+            BottomRow + Index - HelpBottomLine + 1,\r
+            &HelpBottomString[Index * BottomLineWidth]\r
+            );\r
+        }\r
+      }\r
+      //\r
+      // Reset this flag every time we finish using it.\r
+      //\r
+      Repaint = FALSE;\r
+      NewLine = FALSE;\r
+      break;\r
+\r
+    case CfPrepareToReadKey:\r
+      ControlFlag = CfReadKey;\r
+      ScreenOperation = UiNoOperation;\r
+      break;\r
+\r
+    case CfReadKey:\r
+      ControlFlag = CfScreenOperation;\r
+\r
+      //\r
+      // Wait for user's selection\r
+      //\r
+      while (TRUE) {\r
+        Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
+        if (!EFI_ERROR (Status)) {\r
+          EventType = UIEventKey;\r
+          break;\r
+        }\r
+\r
+        //\r
+        // If we encounter error, continue to read another key in.\r
+        //\r
+        if (Status != EFI_NOT_READY) {\r
+          continue;\r
+        }\r
+        \r
+        EventType = UiWaitForEvent(gST->ConIn->WaitForKey);\r
+        if (EventType == UIEventKey) {\r
+          gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
+        }\r
+        break;\r
+      }\r
+\r
+      if (EventType == UIEventDriver) {\r
+        gUserInput->Action = BROWSER_ACTION_NONE;\r
+        ControlFlag = CfExit;\r
+        break;\r
+      }\r
+      \r
+      if (EventType == UIEventTimeOut) {\r
+        gUserInput->Action = BROWSER_ACTION_FORM_EXIT;\r
+        ControlFlag = CfExit;\r
+        break;\r
+      }\r
+\r
+      switch (Key.UnicodeChar) {\r
+      case CHAR_CARRIAGE_RETURN:\r
+        if(MenuOption == NULL || MenuOption->GrayOut || MenuOption->ReadOnly) {\r
+          ControlFlag = CfReadKey;\r
+          break;\r
+        }\r
+\r
+        ScreenOperation = UiSelect;\r
+        gDirection      = 0;\r
+        break;\r
+\r
+      //\r
+      // We will push the adjustment of these numeric values directly to the input handler\r
+      //  NOTE: we won't handle manual input numeric\r
+      //\r
+      case '+':\r
+      case '-':\r
+        //\r
+        // If the screen has no menu items, and the user didn't select UiReset\r
+        // ignore the selection and go back to reading keys.\r
+        //\r
+        if(IsListEmpty (&gMenuOption) || MenuOption->GrayOut || MenuOption->ReadOnly) {\r
+          ControlFlag = CfReadKey;\r
+          break;\r
+        }\r
+\r
+        ASSERT(MenuOption != NULL);\r
+        Statement = MenuOption->ThisTag;\r
+        if ((Statement->OpCode->OpCode == EFI_IFR_DATE_OP)\r
+          || (Statement->OpCode->OpCode == EFI_IFR_TIME_OP)\r
+          || ((Statement->OpCode->OpCode == EFI_IFR_NUMERIC_OP) && (GetFieldFromNum(Statement->OpCode) != 0))\r
+        ){\r
+          if (Key.UnicodeChar == '+') {\r
+            gDirection = SCAN_RIGHT;\r
+          } else {\r
+            gDirection = SCAN_LEFT;\r
+          }\r
+          \r
+          Status = ProcessOptions (MenuOption, TRUE, &OptionString, TRUE);\r
+          if (OptionString != NULL) {\r
+            FreePool (OptionString);\r
+          }\r
+          if (EFI_ERROR (Status)) {\r
+            //\r
+            // Repaint to clear possible error prompt pop-up\r
+            //\r
+            Repaint = TRUE;\r
+            NewLine = TRUE;\r
+          } else {\r
+            ControlFlag = CfExit;\r
+          }\r
+        }\r
+        break;\r
+\r
+      case '^':\r
+        ScreenOperation = UiUp;\r
+        break;\r
+\r
+      case 'V':\r
+      case 'v':\r
+        ScreenOperation = UiDown;\r
+        break;\r
+\r
+      case ' ':\r
+        if(IsListEmpty (&gMenuOption)) {\r
+          ControlFlag = CfReadKey;\r
+          break;\r
+        }\r
+        \r
+        ASSERT(MenuOption != NULL);\r
+        if (MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_CHECKBOX_OP && !MenuOption->GrayOut && !MenuOption->ReadOnly) {\r
+          ScreenOperation = UiSelect;\r
+        }\r
+        break;\r
+\r
+      case 'D':\r
+      case 'd':\r
+        if (!MultiHelpPage) {\r
+          ControlFlag = CfReadKey;\r
+          break;\r
+        }\r
+        ControlFlag    = CfUpdateHelpString;\r
+        HelpPageIndex  = HelpPageIndex < HelpPageCount - 1 ? HelpPageIndex + 1 : HelpPageCount - 1;\r
+        break;\r
+\r
+      case 'U':\r
+      case 'u':\r
+        if (!MultiHelpPage) {\r
+          ControlFlag = CfReadKey;\r
+          break;\r
+        }\r
+        ControlFlag    = CfUpdateHelpString;\r
+        HelpPageIndex  = HelpPageIndex > 0 ? HelpPageIndex - 1 : 0;\r
+        break;\r
+\r
+      case CHAR_NULL:\r
+        for (Index = 0; Index < mScanCodeNumber; Index++) {\r
+          if (Key.ScanCode == gScanCodeToOperation[Index].ScanCode) {\r
+            ScreenOperation = gScanCodeToOperation[Index].ScreenOperation;\r
+            break;\r
+          }\r
+        }\r
+        \r
+        if (((FormData->Attribute & HII_DISPLAY_MODAL) != 0) && (Key.ScanCode == SCAN_ESC || Index == mScanCodeNumber)) {\r
+          //\r
+          // ModalForm has no ESC key and Hot Key.\r
+          //\r
+          ControlFlag = CfReadKey;\r
+        } else if (Index == mScanCodeNumber) {\r
+          //\r
+          // Check whether Key matches the registered hot key.\r
+          //\r
+          HotKey = NULL;\r
+          HotKey = GetHotKeyFromRegisterList (&Key);\r
+          if (HotKey != NULL) {\r
+            ScreenOperation = UiHotKey;\r
+          }\r
+        }\r
+        break;\r
+      }\r
+      break;\r
+\r
+    case CfScreenOperation:\r
+      if (ScreenOperation != UiReset) {\r
+        //\r
+        // If the screen has no menu items, and the user didn't select UiReset\r
+        // ignore the selection and go back to reading keys.\r
+        //\r
+        if (IsListEmpty (&gMenuOption)) {\r
+          ControlFlag = CfReadKey;\r
+          break;\r
+        }\r
+      }\r
+\r
+      for (Index = 0;\r
+           Index < sizeof (gScreenOperationToControlFlag) / sizeof (gScreenOperationToControlFlag[0]);\r
+           Index++\r
+          ) {\r
+        if (ScreenOperation == gScreenOperationToControlFlag[Index].ScreenOperation) {\r
+          ControlFlag = gScreenOperationToControlFlag[Index].ControlFlag;\r
+          break;\r
+        }\r
+      }\r
+      break;\r
+\r
+    case CfUiSelect:\r
+      ControlFlag = CfRepaint;\r
+\r
+      ASSERT(MenuOption != NULL);\r
+      Statement = MenuOption->ThisTag;\r
+      if (Statement->OpCode->OpCode == EFI_IFR_TEXT_OP) {\r
+        break;\r
+      }\r
+\r
+      switch (Statement->OpCode->OpCode) {\r
+      case EFI_IFR_REF_OP:\r
+      case EFI_IFR_ACTION_OP:\r
+      case EFI_IFR_RESET_BUTTON_OP:\r
+        ControlFlag = CfExit;\r
+        break;\r
+\r
+      default:\r
+        //\r
+        // Editable Questions: oneof, ordered list, checkbox, numeric, string, password\r
+        //\r
+        RefreshKeyHelp (gFormData, Statement, TRUE);\r
+        Status = ProcessOptions (MenuOption, TRUE, &OptionString, TRUE);\r
+        \r
+        if (OptionString != NULL) {\r
+          FreePool (OptionString);\r
+        }\r
+        \r
+        if (EFI_ERROR (Status)) {\r
+          Repaint = TRUE;\r
+          NewLine = TRUE;\r
+          RefreshKeyHelp (gFormData, Statement, FALSE);\r
+          break;\r
+        } else {\r
+          ControlFlag = CfExit;\r
+          break;\r
+        }\r
+      }\r
+      break;\r
+\r
+    case CfUiReset:\r
+      //\r
+      // We come here when someone press ESC\r
+      // If the policy is not exit front page when user press ESC, process here.\r
+      //\r
+      if (!FormExitPolicy()) {\r
+        Repaint     = TRUE;\r
+        NewLine     = TRUE;\r
+        ControlFlag = CfRepaint;\r
+        break;\r
+      }\r
+\r
+      //\r
+      // When user press ESC, it will try to show another menu, should clean the gSequence info.\r
+      //\r
+      if (gSequence != 0) {\r
+        gSequence = 0;\r
+      }\r
+\r
+      gUserInput->Action = BROWSER_ACTION_FORM_EXIT;\r
+      ControlFlag = CfExit;\r
+      break;\r
+\r
+    case CfUiHotKey:\r
+      ControlFlag = CfRepaint;\r
+      \r
+      gUserInput->Action = HotKey->Action;\r
+      ControlFlag = CfExit;\r
+      break;\r
+\r
+    case CfUiLeft:\r
+      ControlFlag = CfRepaint;\r
+      ASSERT(MenuOption != NULL);\r
+      if ((MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_TIME_OP)) {\r
+        if (MenuOption->Sequence != 0) {\r
+          //\r
+          // In the middle or tail of the Date/Time op-code set, go left.\r
+          //\r
+          ASSERT(NewPos != NULL);\r
+          NewPos = NewPos->BackLink;\r
+        }\r
+      }\r
+      break;\r
+\r
+    case CfUiRight:\r
+      ControlFlag = CfRepaint;\r
+      ASSERT(MenuOption != NULL);\r
+      if ((MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->OpCode->OpCode == EFI_IFR_TIME_OP)) {\r
+        if (MenuOption->Sequence != 2) {\r
+          //\r
+          // In the middle or tail of the Date/Time op-code set, go left.\r
+          //\r
+          ASSERT(NewPos != NULL);\r
+          NewPos = NewPos->ForwardLink;\r
+        }\r
+      }\r
+      break;\r
+\r
+    case CfUiUp:\r
+      ControlFlag = CfRepaint;\r
+\r
+      SavedListEntry = NewPos;\r
+\r
+      ASSERT(NewPos != NULL);\r
+      //\r
+      // Adjust Date/Time position before we advance forward.\r
+      //\r
+      AdjustDateAndTimePosition (TRUE, &NewPos);\r
+      if (NewPos->BackLink != &gMenuOption) {\r
+        MenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
+        ASSERT (MenuOption != NULL);\r
+        NewLine    = TRUE;\r
+        NewPos     = NewPos->BackLink;\r
+\r
+        PreviousMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
+        if (PreviousMenuOption->Row == 0) {\r
+          UpdateOptionSkipLines (PreviousMenuOption);\r
+        }\r
+        DistanceValue = PreviousMenuOption->Skip;\r
+        Difference    = 0;\r
+        if (MenuOption->Row >= DistanceValue + TopRow) {\r
+          Difference = MoveToNextStatement (TRUE, &NewPos, MenuOption->Row - TopRow - DistanceValue);\r
+        }\r
+        NextMenuOption = MENU_OPTION_FROM_LINK (NewPos);\r
+       \r
+        if (Difference < 0) {\r
+          //\r
+          // We hit the begining MenuOption that can be focused\r
+          // so we simply scroll to the top.\r
+          //\r
+          if (TopOfScreen != gMenuOption.ForwardLink) {\r
+            TopOfScreen = gMenuOption.ForwardLink;\r
+            Repaint     = TRUE;\r
+          } else {\r
+            //\r
+            // Scroll up to the last page when we have arrived at top page.\r
+            //\r
+            NewPos          = &gMenuOption;\r
+            TopOfScreen     = &gMenuOption;\r
+            MenuOption      = MENU_OPTION_FROM_LINK (SavedListEntry);\r
+            ScreenOperation = UiPageUp;\r
+            ControlFlag     = CfScreenOperation;\r
+            break;\r
+          }\r
+        } else if (MenuOption->Row < TopRow + DistanceValue + Difference) {\r
+          //\r
+          // Previous focus MenuOption is above the TopOfScreen, so we need to scroll\r
+          //\r
+          TopOfScreen = NewPos;\r
+          Repaint     = TRUE;\r
+          SkipValue = 0;\r
+        } else if (!IsSelectable (NextMenuOption)) {\r
+          //\r
+          // Continue to go up until scroll to next page or the selectable option is found.\r
+          //\r
+          ScreenOperation = UiUp;\r
+          ControlFlag     = CfScreenOperation;\r
+        }\r
+\r
+        //\r
+        // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.\r
+        //\r
+        AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
+        AdjustDateAndTimePosition (TRUE, &NewPos);\r
+        MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);\r
+        UpdateStatusBar (INPUT_ERROR, FALSE);\r
+      } else {\r
+        //\r
+        // Scroll up to the last page.\r
+        //\r
+        NewPos          = &gMenuOption;\r
+        TopOfScreen     = &gMenuOption;\r
+        MenuOption      = MENU_OPTION_FROM_LINK (SavedListEntry);\r
+        ScreenOperation = UiPageUp;\r
+        ControlFlag     = CfScreenOperation;\r
+      }\r
+      break;\r
+\r
+    case CfUiPageUp:\r
+      //\r
+      // SkipValue means lines is skipped when show the top menu option.\r
+      //\r
+      ControlFlag     = CfRepaint;\r
+\r
+      ASSERT(NewPos != NULL);\r
+      //\r
+      // Already at the first menu option, Check the skip value.\r
+      //\r
+      if (NewPos->BackLink == &gMenuOption) {\r
+        if (SkipValue == 0) {\r
+          NewLine = FALSE;\r
+          Repaint = FALSE;\r
+        } else {\r
+          NewLine = TRUE;\r
+          Repaint = TRUE;\r
+          SkipValue = 0;\r
+        }\r
+        break;\r
+      }\r
+\r
+      NewLine   = TRUE;\r
+      Repaint   = TRUE;\r
+\r
+      //\r
+      // SkipValue > (BottomRow - TopRow + 1) means current menu has more than one\r
+      // form of options to be show, so just update the SkipValue to show the next\r
+      // parts of options.\r
+      //\r
+      if (SkipValue > (INTN) (BottomRow - TopRow + 1)) {\r
+        SkipValue -= BottomRow - TopRow + 1;\r
+        break;\r
+      }\r
+\r
+      Link      = TopOfScreen;\r
+      //\r
+      // First minus the menu of the top screen, it's value is SkipValue.\r
+      //\r
+      Index     = (BottomRow + 1) - SkipValue;\r
+      while ((Index > TopRow) && (Link->BackLink != &gMenuOption)) {\r
+        Link = Link->BackLink;\r
+        PreviousMenuOption = MENU_OPTION_FROM_LINK (Link);\r
+        if (PreviousMenuOption->Row == 0) {\r
+          UpdateOptionSkipLines (PreviousMenuOption);\r
+        }        \r
+        if (Index < PreviousMenuOption->Skip) {\r
+          break;\r
+        }\r
+        Index = Index - PreviousMenuOption->Skip;\r
+      }\r
+      \r
+      if ((Link->BackLink == &gMenuOption) && (Index >= TopRow)) {\r
+        SkipValue = 0;\r
+        if (TopOfScreen == &gMenuOption) {\r
+          TopOfScreen = gMenuOption.ForwardLink;\r
+          NewPos      = gMenuOption.BackLink;\r
+          MoveToNextStatement (TRUE, &NewPos, BottomRow - TopRow);\r
+          Repaint = FALSE;\r
+        } else if (TopOfScreen != Link) {\r
+          TopOfScreen = Link;\r
+          NewPos      = Link;\r
+          MoveToNextStatement (FALSE, &NewPos, BottomRow - TopRow);\r
+        } else {\r
+          //\r
+          // Finally we know that NewPos is the last MenuOption can be focused.\r
+          //\r
+          Repaint = FALSE;\r
+          NewPos  = Link;\r
+          MoveToNextStatement (FALSE, &NewPos, BottomRow - TopRow);\r
+        }\r
+      } else {\r
+        if (Index > TopRow) {\r
+          //\r
+          // At here, only case "Index < PreviousMenuOption->Skip" can reach here.\r
+          //\r
+          SkipValue = PreviousMenuOption->Skip - (Index - TopRow);\r
+        } else if (Index == TopRow) {\r
+          SkipValue = 0;\r
+        } else {\r
+          SkipValue = TopRow - Index;\r
+        }\r
+\r
+        //\r
+        // Move to the option in Next page.\r
+        //\r
+        if (TopOfScreen == &gMenuOption) {\r
+          NewPos = gMenuOption.BackLink;\r
+          MoveToNextStatement (TRUE, &NewPos, BottomRow - TopRow);\r
+        } else {\r
+          NewPos = Link;\r
+          MoveToNextStatement (FALSE, &NewPos, BottomRow - TopRow);\r
+        }\r
+\r
+        //\r
+        // There are more MenuOption needing scrolling up.\r
+        //\r
+        TopOfScreen = Link;\r
+        MenuOption  = NULL;\r
+      }\r
+\r
+      //\r
+      // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.\r
+      // Don't do this when we are already in the first page.\r
+      //\r
+      AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
+      AdjustDateAndTimePosition (TRUE, &NewPos);\r
+      break;\r
+\r
+    case CfUiPageDown:\r
+      //\r
+      // SkipValue means lines is skipped when show the top menu option.\r
+      //\r
+      ControlFlag     = CfRepaint;\r
+\r
+      ASSERT (NewPos != NULL);\r
+      if (NewPos->ForwardLink == &gMenuOption) {\r
+        NewLine = FALSE;\r
+        Repaint = FALSE;\r
+        break;\r
+      }\r
+\r
+      NewLine = TRUE;\r
+      Repaint = TRUE;\r
+      Link    = TopOfScreen;\r
+      NextMenuOption = MENU_OPTION_FROM_LINK (Link);\r
+      Index = TopRow + NextMenuOption->Skip - SkipValue;\r
+      //\r
+      // Count to the menu option which will show at the top of the next form.\r
+      //\r
+      while ((Index <= BottomRow + 1) && (Link->ForwardLink != &gMenuOption)) {\r
+        Link           = Link->ForwardLink;\r
+        NextMenuOption = MENU_OPTION_FROM_LINK (Link);\r
+        Index = Index + NextMenuOption->Skip;\r
+      }\r
+\r
+      if ((Link->ForwardLink == &gMenuOption) && (Index <= BottomRow + 1)) {\r
+        //\r
+        // Finally we know that NewPos is the last MenuOption can be focused.\r
+        //\r
+        Repaint = FALSE;\r
+        MoveToNextStatement (TRUE, &Link, Index - TopRow);\r
+      } else {\r
+        //\r
+        // Calculate the skip line for top of screen menu.\r
+        //\r
+        if (Link == TopOfScreen) {\r
+          //\r
+          // The top of screen menu option occupies the entire form.\r
+          //\r
+          SkipValue += BottomRow - TopRow + 1;\r
+        } else {\r
+          SkipValue = NextMenuOption->Skip - (Index - (BottomRow + 1));\r
+        }\r
+\r
+        TopOfScreen = Link;\r
+        MenuOption = NULL;\r
+        //\r
+        // Move to the Next selectable menu.\r
+        //\r
+        MoveToNextStatement (FALSE, &Link, BottomRow - TopRow);\r
+      }\r
+\r
+      //\r
+      // Save the menu as the next highlight menu.\r
+      //\r
+      NewPos  = Link;\r
+\r
+      //\r
+      // If we encounter a Date/Time op-code set, rewind to the first op-code of the set.\r
+      // Don't do this when we are already in the last page.\r
+      //\r
+      AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
+      AdjustDateAndTimePosition (TRUE, &NewPos);\r
+      break;\r
+\r
+    case CfUiDown:\r
+      //\r
+      // SkipValue means lines is skipped when show the top menu option.\r
+      // NewPos  points to the menu which is highlighted now.\r
+      //\r
+      ControlFlag = CfRepaint;\r
+\r
+      //\r
+      // Since the behavior of hitting the down arrow on a Date/Time op-code is intended\r
+      // to be one that progresses to the next set of op-codes, we need to advance to the last\r
+      // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate\r
+      // checking can be done.  The only other logic we need to introduce is that if a Date/Time\r
+      // op-code is the last entry in the menu, we need to rewind back to the first op-code of\r
+      // the Date/Time op-code.\r
+      //\r
+      SavedListEntry = NewPos;\r
+      AdjustDateAndTimePosition (FALSE, &NewPos);\r
+\r
+      if (NewPos->ForwardLink != &gMenuOption) {\r
+        MenuOption      = MENU_OPTION_FROM_LINK (NewPos);\r
+        NewLine         = TRUE;\r
+        NewPos          = NewPos->ForwardLink;\r
+\r
+        Difference      = 0;\r
+        //\r
+        // Current menu not at the bottom of the form.\r
+        //\r
+        if (BottomRow >= MenuOption->Row + MenuOption->Skip) {\r
+          //\r
+          // Find the next selectable menu.\r
+          //\r
+          Difference = MoveToNextStatement (FALSE, &NewPos, BottomRow - MenuOption->Row - MenuOption->Skip);\r
+          //\r
+          // We hit the end of MenuOption that can be focused\r
+          // so we simply scroll to the first page.\r
+          //\r
+          if (Difference < 0) {\r
+            //\r
+            // Scroll to the first page.\r
+            //\r
+            if (TopOfScreen != gMenuOption.ForwardLink) {\r
+              TopOfScreen = gMenuOption.ForwardLink;\r
+              Repaint     = TRUE;\r
+              MenuOption  = NULL;\r
+            } else {\r
+              MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);\r
+            }\r
+            NewPos        = gMenuOption.ForwardLink;\r
+            MoveToNextStatement (FALSE, &NewPos, BottomRow - TopRow);\r
+\r
+            SkipValue = 0;\r
+            //\r
+            // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.\r
+            //\r
+            AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
+            AdjustDateAndTimePosition (TRUE, &NewPos);\r
+            break;\r
+          }\r
+        }\r
+        NextMenuOption  = MENU_OPTION_FROM_LINK (NewPos);\r
+        if (NextMenuOption->Row == 0) {\r
+          UpdateOptionSkipLines (NextMenuOption);\r
+        }\r
+        DistanceValue  = Difference + NextMenuOption->Skip;\r
+\r
+        Temp = MenuOption->Row + MenuOption->Skip + DistanceValue - 1;\r
+        if ((MenuOption->Row + MenuOption->Skip == BottomRow + 1) &&\r
+            (NextMenuOption->ThisTag->OpCode->OpCode == EFI_IFR_DATE_OP ||\r
+             NextMenuOption->ThisTag->OpCode->OpCode == EFI_IFR_TIME_OP)\r
+            ) {\r
+          Temp ++;\r
+        }\r
+\r
+        //\r
+        // If we are going to scroll, update TopOfScreen\r
+        //\r
+        if (Temp > BottomRow) {\r
+          do {\r
+            //\r
+            // Is the current top of screen a zero-advance op-code?\r
+            // If so, keep moving forward till we hit a >0 advance op-code\r
+            //\r
+            SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);\r
+\r
+            //\r
+            // If bottom op-code is more than one line or top op-code is more than one line\r
+            //\r
+            if ((DistanceValue > 1) || (SavedMenuOption->Skip > 1)) {\r
+              //\r
+              // Is the bottom op-code greater than or equal in size to the top op-code?\r
+              //\r
+              if ((Temp - BottomRow) >= (SavedMenuOption->Skip - SkipValue)) {\r
+                //\r
+                // Skip the top op-code\r
+                //\r
+                TopOfScreen     = TopOfScreen->ForwardLink;\r
+                Difference      = (Temp - BottomRow) - (SavedMenuOption->Skip - SkipValue);\r
+\r
+                SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);\r
+\r
+                //\r
+                // If we have a remainder, skip that many more op-codes until we drain the remainder\r
+                //\r
+                while (Difference >= (INTN) SavedMenuOption->Skip) {\r
+                  //\r
+                  // Since the Difference is greater than or equal to this op-code's skip value, skip it\r
+                  //\r
+                  Difference      = Difference - (INTN) SavedMenuOption->Skip;\r
+                  TopOfScreen     = TopOfScreen->ForwardLink;\r
+                  SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen);\r
+                }\r
+                //\r
+                // Since we will act on this op-code in the next routine, and increment the\r
+                // SkipValue, set the skips to one less than what is required.\r
+                //\r
+                SkipValue = Difference - 1;\r
+              } else {\r
+                //\r
+                // Since we will act on this op-code in the next routine, and increment the\r
+                // SkipValue, set the skips to one less than what is required.\r
+                //\r
+                SkipValue += (Temp - BottomRow) - 1;\r
+              }\r
+            } else {\r
+              if ((SkipValue + 1) == (INTN) SavedMenuOption->Skip) {\r
+                TopOfScreen = TopOfScreen->ForwardLink;\r
+                break;\r
+              }\r
+            }\r
+            //\r
+            // If the op-code at the top of the screen is more than one line, let's not skip it yet\r
+            // Let's set a skip flag to smoothly scroll the top of the screen.\r
+            //\r
+            if (SavedMenuOption->Skip > 1) {\r
+              if (SavedMenuOption == NextMenuOption) {\r
+                SkipValue = 0;\r
+              } else {\r
+                SkipValue++;\r
+              }\r
+            } else if (SavedMenuOption->Skip == 1) {\r
+              SkipValue   = 0;\r
+            } else {\r
+              SkipValue   = 0;\r
+              TopOfScreen = TopOfScreen->ForwardLink;\r
+            }\r
+          } while (SavedMenuOption->Skip == 0);\r
+\r
+          Repaint       = TRUE;\r
+        } else if (!IsSelectable (NextMenuOption)) {\r
+          //\r
+          // Continue to go down until scroll to next page or the selectable option is found.\r
+          //\r
+          ScreenOperation = UiDown;\r
+          ControlFlag     = CfScreenOperation;\r
+        }\r
+\r
+        MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);\r
+\r
+        UpdateStatusBar (INPUT_ERROR, FALSE);\r
+\r
+      } else {\r
+        //\r
+        // Scroll to the first page.\r
+        //\r
+        if (TopOfScreen != gMenuOption.ForwardLink) {\r
+          TopOfScreen = gMenuOption.ForwardLink;\r
+          Repaint     = TRUE;\r
+          MenuOption  = NULL;\r
+        } else {\r
+          //\r
+          // Need to remove the current highlight menu.\r
+          // MenuOption saved the last highlight menu info.\r
+          //\r
+          MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry);\r
+        }\r
+\r
+        SkipValue     = 0;\r
+        NewLine       = TRUE;\r
+        //\r
+        // Get the next highlight menu.\r
+        //\r
+        NewPos        = gMenuOption.ForwardLink;\r
+        MoveToNextStatement (FALSE, &NewPos, BottomRow - TopRow);\r
+      }\r
+\r
+      //\r
+      // If we are at the end of the list and sitting on a Date/Time op, rewind to the head.\r
+      //\r
+      AdjustDateAndTimePosition (TRUE, &TopOfScreen);\r
+      AdjustDateAndTimePosition (TRUE, &NewPos);\r
+      break;\r
+\r
+    case CfUiNoOperation:\r
+      ControlFlag = CfRepaint;\r
+      break;\r
+\r
+    case CfExit:\r
+      if (HelpString != NULL) {\r
+        FreePool (HelpString);\r
+      }\r
+      if (HelpHeaderString != NULL) {\r
+        FreePool (HelpHeaderString);\r
+      }\r
+      if (HelpBottomString != NULL) {\r
+        FreePool (HelpBottomString);\r
+      }\r
+      return EFI_SUCCESS;\r
+\r
+    default:\r
+      break;\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+\r
+  Base on the browser status info to show an pop up message.\r
+\r
+**/\r
+VOID\r
+BrowserStatusProcess (\r
+  VOID\r
+  )\r
+{\r
+  CHAR16         *ErrorInfo;\r
+  EFI_INPUT_KEY  Key;\r
+\r
+  if (gFormData->BrowserStatus == BROWSER_SUCCESS) {\r
+    return;\r
+  }\r
+\r
+  if (gFormData->ErrorString != NULL) {\r
+    ErrorInfo = gFormData->ErrorString;\r
+  } else {\r
+    switch (gFormData->BrowserStatus) {\r
+    case BROWSER_SUBMIT_FAIL:\r
+      ErrorInfo = gSaveFailed;\r
+      break;\r
+\r
+    case BROWSER_NO_SUBMIT_IF:\r
+      ErrorInfo = gNoSubmitIf;\r
+      break;\r
+\r
+    case BROWSER_FORM_NOT_FOUND:\r
+      ErrorInfo = gFormNotFound;\r
+      break;\r
+\r
+    case BROWSER_FORM_SUPPRESS:\r
+      ErrorInfo = gFormSuppress;\r
+      break;\r
+\r
+    case BROWSER_PROTOCOL_NOT_FOUND:\r
+      ErrorInfo = gProtocolNotFound;\r
+      break;\r
+\r
+    default:\r
+      ErrorInfo = gBrwoserError;\r
+      break;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Error occur, prompt error message.\r
+  //\r
+  do {\r
+    CreateDialog (&Key, gEmptyString, ErrorInfo, gPressEnter, gEmptyString, NULL);\r
+  } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+}\r
+\r
+/**\r
+  Display one form, and return user input.\r
+  \r
+  @param FormData                Form Data to be shown.\r
+  @param UserInputData           User input data.\r
+  \r
+  @retval EFI_SUCCESS            1.Form Data is shown, and user input is got.\r
+                                 2.Error info has show and return.\r
+  @retval EFI_INVALID_PARAMETER  The input screen dimension is not valid\r
+  @retval EFI_NOT_FOUND          New form data has some error.\r
+**/\r
+EFI_STATUS\r
+EFIAPI \r
+FormDisplay (\r
+  IN  FORM_DISPLAY_ENGINE_FORM  *FormData,\r
+  OUT USER_INPUT                *UserInputData\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  ASSERT (FormData != NULL);\r
+  if (FormData == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  gUserInput = UserInputData;\r
+  gFormData  = FormData;\r
+\r
+  //\r
+  // Process the status info first.\r
+  //\r
+  BrowserStatusProcess();\r
+  if (UserInputData == NULL) {\r
+    //\r
+    // UserInputData == NULL, means only need to print the error info, return here.\r
+    //\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  ConvertStatementToMenu();\r
+\r
+  Status = DisplayPageFrame (FormData, &gStatementDimensions);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if (CompareMem (&gOldStatementDimensions, &gStatementDimensions, sizeof (gStatementDimensions)) == 0) {\r
+    mStatementLayoutIsChanged = FALSE;\r
+  } else {\r
+    mStatementLayoutIsChanged = TRUE;\r
+    CopyMem (&gOldStatementDimensions, &gStatementDimensions, sizeof (gStatementDimensions));\r
+  }\r
+\r
+  Status = UiDisplayMenu(FormData);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Initialize Setup Browser driver.\r
+\r
+  @param ImageHandle     The image handle.\r
+  @param SystemTable     The system table.\r
+\r
+  @retval EFI_SUCCESS    The Setup Browser module is initialized correctly..\r
+  @return Other value if failed to initialize the Setup Browser module.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InitializeDisplayEngine (\r
+  IN EFI_HANDLE           ImageHandle,\r
+  IN EFI_SYSTEM_TABLE     *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS                          Status;\r
+  EFI_INPUT_KEY                       HotKey;\r
+  EFI_STRING                          NewString;\r
+  EDKII_FORM_BROWSER_EXTENSION2_PROTOCOL *FormBrowserEx2;\r
+\r
+  //\r
+  // Publish our HII data\r
+  //\r
+  gHiiHandle = HiiAddPackages (\r
+                 &gDisplayEngineGuid,\r
+                 ImageHandle,\r
+                 DisplayEngineStrings,\r
+                 NULL\r
+                 );\r
+  ASSERT (gHiiHandle != NULL);\r
+\r
+  //\r
+  // Install Form Display protocol\r
+  //\r
+  Status = gBS->InstallProtocolInterface (\r
+                  &mPrivateData.Handle,\r
+                  &gEdkiiFormDisplayEngineProtocolGuid,\r
+                  EFI_NATIVE_INTERFACE,\r
+                  &mPrivateData.FromDisplayProt\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  InitializeDisplayStrings();\r
+\r
+  //\r
+  // Use BrowserEx2 protocol to register HotKey.\r
+  // \r
+  Status = gBS->LocateProtocol (&gEdkiiFormBrowserEx2ProtocolGuid, NULL, (VOID **) &FormBrowserEx2);\r
+  if (!EFI_ERROR (Status)) {\r
+    //\r
+    // Register the default HotKey F9 and F10 again.\r
+    //\r
+    HotKey.UnicodeChar = CHAR_NULL;\r
+    HotKey.ScanCode   = SCAN_F10;\r
+    NewString         = HiiGetString (gHiiHandle, STRING_TOKEN (FUNCTION_TEN_STRING), NULL);\r
+    ASSERT (NewString != NULL);\r
+    FormBrowserEx2->RegisterHotKey (&HotKey, BROWSER_ACTION_SUBMIT, 0, NewString);\r
+\r
+    HotKey.ScanCode   = SCAN_F9;\r
+    NewString         = HiiGetString (gHiiHandle, STRING_TOKEN (FUNCTION_NINE_STRING), NULL);\r
+    ASSERT (NewString != NULL);\r
+    FormBrowserEx2->RegisterHotKey (&HotKey, BROWSER_ACTION_DEFAULT, EFI_HII_DEFAULT_CLASS_STANDARD, NewString);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  This is the default unload handle for display core drivers.\r
+\r
+  @param[in]  ImageHandle       The drivers' driver image.\r
+\r
+  @retval EFI_SUCCESS           The image is unloaded.\r
+  @retval Others                Failed to unload the image.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UnloadDisplayEngine (\r
+  IN EFI_HANDLE             ImageHandle\r
+  )\r
+{\r
+  HiiRemovePackages(gHiiHandle);\r
+\r
+  FreeDisplayStrings ();\r
+\r
+  return EFI_SUCCESS;\r
+}\r
diff --git a/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.h b/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplay.h
new file mode 100644 (file)
index 0000000..ad4684e
--- /dev/null
@@ -0,0 +1,580 @@
+/** @file\r
+  FormDiplay protocol to show Form\r
+\r
+Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials are licensed and made available under \r
+the terms and conditions of the BSD License that accompanies this distribution.  \r
+The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php.                                            \r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef __FORM_DISPLAY_H__\r
+#define __FORM_DISPLAY_H__\r
+\r
+\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/HiiLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/PrintLib.h>\r
+#include <Library/CustomizedDisplayLib.h>\r
+\r
+#include <Protocol/FormBrowserEx2.h>\r
+#include <Protocol/SimpleTextIn.h>\r
+#include <Protocol/DisplayProtocol.h>\r
+\r
+#include <Guid/MdeModuleHii.h>\r
+\r
+//\r
+// This is the generated header file which includes whatever needs to be exported (strings + IFR)\r
+//\r
+extern UINT8  DisplayEngineStrings[];\r
+extern EFI_SCREEN_DESCRIPTOR         gStatementDimensions;\r
+extern USER_INPUT                    *gUserInput;\r
+extern FORM_DISPLAY_ENGINE_FORM      *gFormData;\r
+extern EFI_HII_HANDLE                gHiiHandle;\r
+extern UINT16                        gDirection;\r
+extern LIST_ENTRY                    gMenuOption;\r
+\r
+//\r
+// Browser Global Strings\r
+//\r
+extern CHAR16            *gSaveFailed;\r
+extern CHAR16            *gPromptForData;\r
+extern CHAR16            *gPromptForPassword;\r
+extern CHAR16            *gPromptForNewPassword;\r
+extern CHAR16            *gConfirmPassword;\r
+extern CHAR16            *gConfirmError;\r
+extern CHAR16            *gPassowordInvalid;\r
+extern CHAR16            *gPressEnter;\r
+extern CHAR16            *gEmptyString;\r
+extern CHAR16            *gMiniString;\r
+extern CHAR16            *gOptionMismatch;\r
+extern CHAR16            *gFormSuppress;\r
+extern CHAR16            *gProtocolNotFound;\r
+\r
+extern CHAR16            gPromptBlockWidth;\r
+extern CHAR16            gOptionBlockWidth;\r
+extern CHAR16            gHelpBlockWidth;\r
+extern CHAR16            *mUnknownString;\r
+\r
+//\r
+// Screen definitions\r
+//\r
+\r
+#define LEFT_SKIPPED_COLUMNS          3\r
+#define SCROLL_ARROW_HEIGHT           1\r
+#define POPUP_PAD_SPACE_COUNT         5\r
+#define POPUP_FRAME_WIDTH             2\r
+\r
+//\r
+// Display definitions\r
+//\r
+#define LEFT_ONEOF_DELIMITER      L'<'\r
+#define RIGHT_ONEOF_DELIMITER     L'>'\r
+\r
+#define LEFT_NUMERIC_DELIMITER    L'['\r
+#define RIGHT_NUMERIC_DELIMITER   L']'\r
+\r
+#define LEFT_CHECKBOX_DELIMITER   L'['\r
+#define RIGHT_CHECKBOX_DELIMITER  L']'\r
+\r
+#define CHECK_ON                  L'X'\r
+#define CHECK_OFF                 L' '\r
+\r
+#define TIME_SEPARATOR            L':'\r
+#define DATE_SEPARATOR            L'/'\r
+\r
+#define SUBTITLE_INDENT  2\r
+\r
+//\r
+// This is the Input Error Message\r
+//\r
+#define INPUT_ERROR 1\r
+\r
+//\r
+// This is the NV RAM update required Message\r
+//\r
+#define NV_UPDATE_REQUIRED  2\r
+//\r
+// Time definitions\r
+//\r
+#define ONE_SECOND  10000000\r
+\r
+//\r
+// It take 23 characters including the NULL to print a 64 bits number with "[" and "]".\r
+// pow(2, 64) = [18446744073709551616]\r
+//\r
+#define MAX_NUMERIC_INPUT_WIDTH 23\r
+\r
+#define EFI_HII_EXPRESSION_INCONSISTENT_IF   0\r
+#define EFI_HII_EXPRESSION_NO_SUBMIT_IF      1\r
+#define EFI_HII_EXPRESSION_GRAY_OUT_IF       2\r
+#define EFI_HII_EXPRESSION_SUPPRESS_IF       3\r
+#define EFI_HII_EXPRESSION_DISABLE_IF        4\r
+\r
+//\r
+// Character definitions\r
+//\r
+#define CHAR_SPACE              0x0020\r
+\r
+#define FORM_DISPLAY_DRIVER_SIGNATURE SIGNATURE_32 ('F', 'D', 'D', 'V')\r
+typedef struct {\r
+  UINT32                             Signature;\r
+\r
+  EFI_HANDLE                         Handle;\r
+\r
+  //\r
+  // Produced protocol\r
+  //\r
+  EDKII_FORM_DISPLAY_ENGINE_PROTOCOL FromDisplayProt;\r
+} FORM_DISPLAY_DRIVER_PRIVATE_DATA;\r
+\r
+\r
+typedef enum {\r
+  UiNoOperation,\r
+  UiSelect,\r
+  UiUp,\r
+  UiDown,\r
+  UiLeft,\r
+  UiRight,\r
+  UiReset,\r
+  UiPrevious,\r
+  UiPageUp,\r
+  UiPageDown,\r
+  UiHotKey,\r
+  UiMaxOperation\r
+} UI_SCREEN_OPERATION;\r
+\r
+typedef enum {\r
+  CfInitialization,\r
+  CfCheckSelection,\r
+  CfRepaint,\r
+  CfRefreshHighLight,\r
+  CfUpdateHelpString,\r
+  CfPrepareToReadKey,\r
+  CfReadKey,\r
+  CfScreenOperation,\r
+  CfUiSelect,\r
+  CfUiReset,\r
+  CfUiLeft,\r
+  CfUiRight,\r
+  CfUiUp,\r
+  CfUiPageUp,\r
+  CfUiPageDown,\r
+  CfUiDown,\r
+  CfUiDefault,\r
+  CfUiNoOperation,\r
+  CfExit,\r
+  CfUiHotKey,\r
+  CfMaxControlFlag\r
+} UI_CONTROL_FLAG;\r
+\r
+typedef enum {\r
+  UIEventNone,\r
+  UIEventKey,\r
+  UIEventTimeOut,\r
+  UIEventDriver\r
+} UI_EVENT_TYPE;\r
+\r
+typedef struct {\r
+  UINT16              ScanCode;\r
+  UI_SCREEN_OPERATION ScreenOperation;\r
+} SCAN_CODE_TO_SCREEN_OPERATION;\r
+\r
+typedef struct {\r
+  UI_SCREEN_OPERATION ScreenOperation;\r
+  UI_CONTROL_FLAG     ControlFlag;\r
+} SCREEN_OPERATION_T0_CONTROL_FLAG;\r
+\r
+typedef struct {\r
+  EFI_QUESTION_ID    QuestionId;\r
+  UINT16             DisplayRow;\r
+} DISPLAY_HIGHLIGHT_MENU_INFO;\r
+\r
+#define UI_MENU_OPTION_SIGNATURE  SIGNATURE_32 ('u', 'i', 'm', 'm')\r
+\r
+typedef struct {\r
+  UINTN                   Signature;\r
+  LIST_ENTRY              Link;\r
+\r
+  EFI_HII_HANDLE          Handle;\r
+  FORM_DISPLAY_ENGINE_STATEMENT  *ThisTag;\r
+  UINT16                  EntryNumber;\r
+\r
+  UINTN                   Row;\r
+  UINTN                   Col;\r
+  UINTN                   OptCol;\r
+  CHAR16                  *Description;\r
+  UINTN                   Skip;           // Number of lines\r
+\r
+  //\r
+  // Display item sequence for date/time\r
+  //  Date:      Month/Day/Year\r
+  //  Sequence:  0     1   2\r
+  //\r
+  //  Time:      Hour : Minute : Second\r
+  //  Sequence:  0      1        2\r
+  //\r
+  //\r
+  UINTN                   Sequence;\r
+\r
+  BOOLEAN                 GrayOut;\r
+  BOOLEAN                 ReadOnly;\r
+\r
+  //\r
+  // Whether user could change value of this item\r
+  //\r
+  BOOLEAN                 IsQuestion;\r
+  BOOLEAN                 NestInStatement;\r
+} UI_MENU_OPTION;\r
+\r
+#define MENU_OPTION_FROM_LINK(a)  CR (a, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE)\r
+\r
+/**\r
+  Print Question Value according to it's storage width and display attributes.\r
+\r
+  @param  Question               The Question to be printed.\r
+  @param  FormattedNumber        Buffer for output string.\r
+  @param  BufferSize             The FormattedNumber buffer size in bytes.\r
+\r
+  @retval EFI_SUCCESS            Print success.\r
+  @retval EFI_BUFFER_TOO_SMALL   Buffer size is not enough for formatted number.\r
+\r
+**/\r
+EFI_STATUS\r
+PrintFormattedNumber (\r
+  IN FORM_DISPLAY_ENGINE_STATEMENT   *Question,\r
+  IN OUT CHAR16               *FormattedNumber,\r
+  IN UINTN                    BufferSize\r
+  );\r
+\r
+/**\r
+  Set value of a data element in an Array by its Index.\r
+\r
+  @param  Array                  The data array.\r
+  @param  Type                   Type of the data in this array.\r
+  @param  Index                  Zero based index for data in this array.\r
+  @param  Value                  The value to be set.\r
+\r
+**/\r
+VOID\r
+SetArrayData (\r
+  IN VOID                     *Array,\r
+  IN UINT8                    Type,\r
+  IN UINTN                    Index,\r
+  IN UINT64                   Value\r
+  );\r
+\r
+/**\r
+  Return data element in an Array by its Index.\r
+\r
+  @param  Array                  The data array.\r
+  @param  Type                   Type of the data in this array.\r
+  @param  Index                  Zero based index for data in this array.\r
+\r
+  @retval Value                  The data to be returned\r
+\r
+**/\r
+UINT64\r
+GetArrayData (\r
+  IN VOID                     *Array,\r
+  IN UINT8                    Type,\r
+  IN UINTN                    Index\r
+  );\r
+  \r
+/**\r
+  Search an Option of a Question by its value.\r
+\r
+  @param  Question               The Question\r
+  @param  OptionValue            Value for Option to be searched.\r
+\r
+  @retval Pointer                Pointer to the found Option.\r
+  @retval NULL                   Option not found.\r
+\r
+**/\r
+DISPLAY_QUESTION_OPTION *\r
+ValueToOption (\r
+  IN FORM_DISPLAY_ENGINE_STATEMENT   *Question,\r
+  IN EFI_HII_VALUE                   *OptionValue\r
+  );\r
+\r
+/**\r
+  Compare two Hii value.\r
+\r
+  @param  Value1                 Expression value to compare on left-hand.\r
+  @param  Value2                 Expression value to compare on right-hand.\r
+  @param  Result                 Return value after compare.\r
+                                 retval 0                      Two operators equal.\r
+                                 return Positive value if Value1 is greater than Value2.\r
+                                 retval Negative value if Value1 is less than Value2.\r
+  @param  HiiHandle              Only required for string compare.\r
+\r
+  @retval other                  Could not perform compare on two values.\r
+  @retval EFI_SUCCESS            Compare the value success.\r
+\r
+**/\r
+EFI_STATUS\r
+CompareHiiValue (\r
+  IN  EFI_HII_VALUE   *Value1,\r
+  IN  EFI_HII_VALUE   *Value2,\r
+  OUT INTN            *Result,\r
+  IN  EFI_HII_HANDLE  HiiHandle OPTIONAL\r
+  );\r
+\r
+/**\r
+  Draw a pop up windows based on the dimension, number of lines and\r
+  strings specified.\r
+\r
+  @param RequestedWidth  The width of the pop-up.\r
+  @param NumberOfLines   The number of lines.\r
+  @param ...             A series of text strings that displayed in the pop-up.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+CreateMultiStringPopUp (\r
+  IN  UINTN                       RequestedWidth,\r
+  IN  UINTN                       NumberOfLines,\r
+  ...\r
+  );\r
+\r
+/**\r
+  Will copy LineWidth amount of a string in the OutputString buffer and return the\r
+  number of CHAR16 characters that were copied into the OutputString buffer.\r
+  The output string format is:\r
+    Glyph Info + String info + '\0'.\r
+\r
+  In the code, it deals \r,\n,\r\n same as \n\r, also it not process the \r or \g.\r
+\r
+  @param  InputString            String description for this option.\r
+  @param  LineWidth              Width of the desired string to extract in CHAR16\r
+                                 characters\r
+  @param  GlyphWidth             The glyph width of the begin of the char in the string.\r
+  @param  Index                  Where in InputString to start the copy process\r
+  @param  OutputString           Buffer to copy the string into\r
+\r
+  @return Returns the number of CHAR16 characters that were copied into the OutputString \r
+  buffer, include extra glyph info and '\0' info.\r
+\r
+**/\r
+UINT16\r
+GetLineByWidth (\r
+  IN      CHAR16                      *InputString,\r
+  IN      UINT16                      LineWidth,\r
+  IN OUT  UINT16                      *GlyphWidth,\r
+  IN OUT  UINTN                       *Index,\r
+  OUT     CHAR16                      **OutputString\r
+  );\r
+\r
+\r
+/**\r
+  Get the string based on the StringId and HII Package List Handle.\r
+\r
+  @param  Token                  The String's ID.\r
+  @param  HiiHandle              The Hii handle for this string package.\r
+\r
+  @return The output string.\r
+\r
+**/\r
+CHAR16 *\r
+GetToken (\r
+  IN  EFI_STRING_ID                Token,\r
+  IN  EFI_HII_HANDLE               HiiHandle\r
+  );\r
+  \r
+/**\r
+  Count the storage space of a Unicode string.\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
+\r
+  If String is NULL, then ASSERT ().\r
+\r
+  @param String          The input string to be counted.\r
+\r
+  @return Storage space for the input string.\r
+\r
+**/\r
+UINTN\r
+GetStringWidth (\r
+  IN CHAR16               *String\r
+  );\r
+\r
+/**\r
+  This routine reads a numeric value from the user input.\r
+\r
+  @param  MenuOption        Pointer to the current input menu.\r
+\r
+  @retval EFI_SUCCESS       If numerical input is read successfully\r
+  @retval EFI_DEVICE_ERROR  If operation fails\r
+\r
+**/\r
+EFI_STATUS\r
+GetNumericInput (\r
+  IN  UI_MENU_OPTION              *MenuOption\r
+  );\r
+\r
+/**\r
+  Get string or password input from user.\r
+\r
+  @param  MenuOption        Pointer to the current input menu.\r
+  @param  Prompt            The prompt string shown on popup window.\r
+  @param  StringPtr         Old user input and destination for use input string.\r
+\r
+  @retval EFI_SUCCESS       If string input is read successfully\r
+  @retval EFI_DEVICE_ERROR  If operation fails\r
+\r
+**/\r
+EFI_STATUS\r
+ReadString (\r
+  IN     UI_MENU_OPTION              *MenuOption,\r
+  IN     CHAR16                      *Prompt,\r
+  IN OUT CHAR16                      *StringPtr\r
+  );\r
+\r
+/**\r
+  Draw a pop up windows based on the dimension, number of lines and\r
+  strings specified.\r
+\r
+  @param RequestedWidth  The width of the pop-up.\r
+  @param NumberOfLines   The number of lines.\r
+  @param Marker          The variable argument list for the list of string to be printed.\r
+\r
+**/\r
+VOID\r
+CreateSharedPopUp (\r
+  IN  UINTN                       RequestedWidth,\r
+  IN  UINTN                       NumberOfLines,\r
+  IN  VA_LIST                     Marker\r
+  );\r
+  \r
+/**\r
+  Wait for a key to be pressed by user.\r
+\r
+  @param Key         The key which is pressed by user.\r
+\r
+  @retval EFI_SUCCESS The function always completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+WaitForKeyStroke (\r
+  OUT  EFI_INPUT_KEY           *Key\r
+  );\r
+\r
+/**\r
+  Get selection for OneOf and OrderedList (Left/Right will be ignored).\r
+\r
+  @param  MenuOption        Pointer to the current input menu.\r
+\r
+  @retval EFI_SUCCESS       If Option input is processed successfully\r
+  @retval EFI_DEVICE_ERROR  If operation fails\r
+\r
+**/\r
+EFI_STATUS\r
+GetSelectionInputPopUp (\r
+  IN  UI_MENU_OPTION              *MenuOption\r
+  );\r
+\r
+/**\r
+  Process the help string: Split StringPtr to several lines of strings stored in\r
+  FormattedString and the glyph width of each line cannot exceed gHelpBlockWidth.\r
+\r
+  @param  StringPtr              The entire help string.\r
+  @param  FormattedString        The oupput formatted string.\r
+  @param  EachLineWidth          The max string length of each line in the formatted string.\r
+  @param  RowCount               TRUE: if Question is selected.\r
+\r
+**/\r
+UINTN\r
+ProcessHelpString (\r
+  IN  CHAR16  *StringPtr,\r
+  OUT CHAR16  **FormattedString,\r
+  OUT UINT16  *EachLineWidth,\r
+  IN  UINTN   RowCount\r
+  );\r
+\r
+/**\r
+  Process a Question's Option (whether selected or un-selected).\r
+\r
+  @param  MenuOption             The MenuOption for this Question.\r
+  @param  Selected               TRUE: if Question is selected.\r
+  @param  OptionString           Pointer of the Option String to be displayed.\r
+  @param  SkipErrorValue         Whether need to return when value without option for it.\r
+\r
+  @retval EFI_SUCCESS            Question Option process success.\r
+  @retval Other                  Question Option process fail.\r
+\r
+**/\r
+EFI_STATUS\r
+ProcessOptions (\r
+  IN  UI_MENU_OPTION              *MenuOption,\r
+  IN  BOOLEAN                     Selected,\r
+  OUT CHAR16                      **OptionString,\r
+  IN  BOOLEAN                     SkipErrorValue\r
+  );\r
+\r
+/**\r
+  Set Buffer to Value for Size bytes.\r
+\r
+  @param  Buffer                 Memory to set.\r
+  @param  Size                   Number of bytes to set\r
+  @param  Value                  Value of the set operation.\r
+\r
+**/\r
+VOID\r
+SetUnicodeMem (\r
+  IN VOID   *Buffer,\r
+  IN UINTN  Size,\r
+  IN CHAR16 Value\r
+  );\r
+\r
+/**\r
+  Display one form, and return user input.\r
+  \r
+  @param FormData                Form Data to be shown.\r
+  @param UserInputData           User input data.\r
+  \r
+  @retval EFI_SUCCESS            Form Data is shown, and user input is got.\r
+**/\r
+EFI_STATUS\r
+EFIAPI \r
+FormDisplay (\r
+  IN  FORM_DISPLAY_ENGINE_FORM  *FormData,\r
+  OUT USER_INPUT                *UserInputData\r
+  );\r
+\r
+/**\r
+  Exit Display and Clear Screen to the original state.\r
+\r
+**/\r
+VOID\r
+EFIAPI \r
+ExitDisplay (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Process validate for one question.\r
+\r
+  @param  Question               The question which need to validate.\r
+\r
+  @retval EFI_SUCCESS            Question Option process success.\r
+  @retval Other                  Question Option process fail.\r
+\r
+**/\r
+EFI_STATUS \r
+ValidateQuestion (\r
+  IN FORM_DISPLAY_ENGINE_STATEMENT   *Question\r
+  );\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplayStr.uni b/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplayStr.uni
new file mode 100644 (file)
index 0000000..0ee7f46
Binary files /dev/null and b/MdeModulePkg/Universal/DisplayEngineDxe/FormDisplayStr.uni differ
diff --git a/MdeModulePkg/Universal/DisplayEngineDxe/InputHandler.c b/MdeModulePkg/Universal/DisplayEngineDxe/InputHandler.c
new file mode 100644 (file)
index 0000000..607f0df
--- /dev/null
@@ -0,0 +1,1531 @@
+/** @file\r
+Implementation for handling user input from the User Interfaces.\r
+\r
+Copyright (c) 2004 - 2012, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "FormDisplay.h"\r
+\r
+/**\r
+  Get maximum and minimum info from this opcode.\r
+\r
+  @param  OpCode            Pointer to the current input opcode.\r
+  @param  Minimum           The minimum size info for this opcode.\r
+  @param  Maximum           The maximum size info for this opcode.\r
+\r
+**/\r
+VOID\r
+GetFieldFromOp (\r
+  IN   EFI_IFR_OP_HEADER       *OpCode,\r
+  OUT  UINTN                   *Minimum,\r
+  OUT  UINTN                   *Maximum\r
+  )\r
+{\r
+  EFI_IFR_STRING    *StringOp;\r
+  EFI_IFR_PASSWORD  *PasswordOp;\r
+  if (OpCode->OpCode == EFI_IFR_STRING_OP) {\r
+    StringOp = (EFI_IFR_STRING *) OpCode;\r
+    *Minimum = StringOp->MinSize;\r
+    *Maximum = StringOp->MaxSize;    \r
+  } else if (OpCode->OpCode == EFI_IFR_PASSWORD_OP) {\r
+    PasswordOp = (EFI_IFR_PASSWORD *) OpCode;\r
+    *Minimum = PasswordOp->MinSize;\r
+    *Maximum = PasswordOp->MaxSize;       \r
+  } else {\r
+    *Minimum = 0;\r
+    *Maximum = 0;       \r
+  }\r
+}\r
+\r
+/**\r
+  Get string or password input from user.\r
+\r
+  @param  MenuOption        Pointer to the current input menu.\r
+  @param  Prompt            The prompt string shown on popup window.\r
+  @param  StringPtr         Old user input and destination for use input string.\r
+\r
+  @retval EFI_SUCCESS       If string input is read successfully\r
+  @retval EFI_DEVICE_ERROR  If operation fails\r
+\r
+**/\r
+EFI_STATUS\r
+ReadString (\r
+  IN     UI_MENU_OPTION              *MenuOption,\r
+  IN     CHAR16                      *Prompt,\r
+  IN OUT CHAR16                      *StringPtr\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  EFI_INPUT_KEY           Key;\r
+  CHAR16                  NullCharacter;\r
+  UINTN                   ScreenSize;\r
+  CHAR16                  Space[2];\r
+  CHAR16                  KeyPad[2];\r
+  CHAR16                  *TempString;\r
+  CHAR16                  *BufferedString;\r
+  UINTN                   Index;\r
+  UINTN                   Index2;\r
+  UINTN                   Count;\r
+  UINTN                   Start;\r
+  UINTN                   Top;\r
+  UINTN                   DimensionsWidth;\r
+  UINTN                   DimensionsHeight;\r
+  UINTN                   CurrentCursor;\r
+  BOOLEAN                 CursorVisible;\r
+  UINTN                   Minimum;\r
+  UINTN                   Maximum;\r
+  FORM_DISPLAY_ENGINE_STATEMENT  *Question;\r
+  BOOLEAN                 IsPassword;\r
+\r
+  DimensionsWidth  = gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn;\r
+  DimensionsHeight = gStatementDimensions.BottomRow - gStatementDimensions.TopRow;\r
+\r
+  NullCharacter    = CHAR_NULL;\r
+  ScreenSize       = GetStringWidth (Prompt) / sizeof (CHAR16);\r
+  Space[0]         = L' ';\r
+  Space[1]         = CHAR_NULL;\r
+\r
+  Question         = MenuOption->ThisTag;\r
+  GetFieldFromOp(Question->OpCode, &Minimum, &Maximum);\r
+\r
+  if (Question->OpCode->OpCode == EFI_IFR_PASSWORD_OP) {\r
+    IsPassword = TRUE;\r
+  } else {\r
+    IsPassword = FALSE;\r
+  }\r
+\r
+  TempString = AllocateZeroPool ((Maximum + 1)* sizeof (CHAR16));\r
+  ASSERT (TempString);\r
+\r
+  if (ScreenSize < (Maximum + 1)) {\r
+    ScreenSize = Maximum + 1;\r
+  }\r
+\r
+  if ((ScreenSize + 2) > DimensionsWidth) {\r
+    ScreenSize = DimensionsWidth - 2;\r
+  }\r
+\r
+  BufferedString = AllocateZeroPool (ScreenSize * 2);\r
+  ASSERT (BufferedString);\r
+\r
+  Start = (DimensionsWidth - ScreenSize - 2) / 2 + gStatementDimensions.LeftColumn + 1;\r
+  Top   = ((DimensionsHeight - 6) / 2) + gStatementDimensions.TopRow - 1;\r
+\r
+  //\r
+  // Display prompt for string\r
+  //\r
+  // CreateDialog (NULL, "", Prompt, Space, "", NULL);\r
+  CreateMultiStringPopUp (ScreenSize, 4, &NullCharacter, Prompt, Space, &NullCharacter);\r
+  gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY));\r
+\r
+  CursorVisible = gST->ConOut->Mode->CursorVisible;\r
+  gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
+\r
+  CurrentCursor = GetStringWidth (StringPtr) / 2 - 1;\r
+  if (CurrentCursor != 0) {\r
+    //\r
+    // Show the string which has beed saved before.\r
+    //\r
+    SetUnicodeMem (BufferedString, ScreenSize - 1, L' ');\r
+    PrintStringAt (Start + 1, Top + 3, BufferedString);\r
+\r
+    if ((GetStringWidth (StringPtr) / 2) > (DimensionsWidth - 2)) {\r
+      Index = (GetStringWidth (StringPtr) / 2) - DimensionsWidth + 2;\r
+    } else {\r
+      Index = 0;\r
+    }\r
+\r
+    if (IsPassword) {\r
+      gST->ConOut->SetCursorPosition (gST->ConOut, Start + 1, Top + 3);\r
+    }\r
+\r
+    for (Count = 0; Index + 1 < GetStringWidth (StringPtr) / 2; Index++, Count++) {\r
+      BufferedString[Count] = StringPtr[Index];\r
+\r
+      if (IsPassword) {\r
+        PrintCharAt ((UINTN)-1, (UINTN)-1, L'*');\r
+      }\r
+    }\r
+\r
+    if (!IsPassword) {\r
+      PrintStringAt (Start + 1, Top + 3, BufferedString);\r
+    }\r
+    \r
+    gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
+    gST->ConOut->SetCursorPosition (gST->ConOut, Start + GetStringWidth (StringPtr) / 2, Top + 3);\r
+  }\r
+  \r
+  do {\r
+    Status = WaitForKeyStroke (&Key);\r
+    ASSERT_EFI_ERROR (Status);\r
+\r
+    gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY));\r
+    switch (Key.UnicodeChar) {\r
+    case CHAR_NULL:\r
+      switch (Key.ScanCode) {\r
+      case SCAN_LEFT:\r
+        if (CurrentCursor > 0) {\r
+          CurrentCursor--;\r
+        }\r
+        break;\r
+\r
+      case SCAN_RIGHT:\r
+        if (CurrentCursor < (GetStringWidth (StringPtr) / 2 - 1)) {\r
+          CurrentCursor++;\r
+        }\r
+        break;\r
+\r
+      case SCAN_ESC:\r
+        FreePool (TempString);\r
+        FreePool (BufferedString);\r
+        gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
+        gST->ConOut->EnableCursor (gST->ConOut, CursorVisible);\r
+        return EFI_DEVICE_ERROR;\r
+\r
+      default:\r
+        break;\r
+      }\r
+\r
+      break;\r
+\r
+    case CHAR_CARRIAGE_RETURN:\r
+      if (GetStringWidth (StringPtr) >= ((Minimum + 1) * sizeof (CHAR16))) {\r
+\r
+        FreePool (TempString);\r
+        FreePool (BufferedString);\r
+        gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
+        gST->ConOut->EnableCursor (gST->ConOut, CursorVisible);\r
+        return EFI_SUCCESS;\r
+      } else {\r
+        //\r
+        // Simply create a popup to tell the user that they had typed in too few characters.\r
+        // To save code space, we can then treat this as an error and return back to the menu.\r
+        //\r
+        do {\r
+          CreateDialog (&Key, &NullCharacter, gMiniString, gPressEnter, &NullCharacter, NULL);\r
+        } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+\r
+        FreePool (TempString);\r
+        FreePool (BufferedString);\r
+        gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
+        gST->ConOut->EnableCursor (gST->ConOut, CursorVisible);\r
+        return EFI_DEVICE_ERROR;\r
+      }\r
+\r
+      break;\r
+\r
+    case CHAR_BACKSPACE:\r
+      if (StringPtr[0] != CHAR_NULL && CurrentCursor != 0) {\r
+        for (Index = 0; Index < CurrentCursor - 1; Index++) {\r
+          TempString[Index] = StringPtr[Index];\r
+        }\r
+        Count = GetStringWidth (StringPtr) / 2 - 1;\r
+        if (Count >= CurrentCursor) {\r
+          for (Index = CurrentCursor - 1, Index2 = CurrentCursor; Index2 < Count; Index++, Index2++) {\r
+            TempString[Index] = StringPtr[Index2];\r
+          }\r
+          TempString[Index] = CHAR_NULL;\r
+        }\r
+        //\r
+        // Effectively truncate string by 1 character\r
+        //\r
+        StrCpy (StringPtr, TempString);\r
+        CurrentCursor --;\r
+      }\r
+\r
+    default:\r
+      //\r
+      // If it is the beginning of the string, don't worry about checking maximum limits\r
+      //\r
+      if ((StringPtr[0] == CHAR_NULL) && (Key.UnicodeChar != CHAR_BACKSPACE)) {\r
+        StrnCpy (StringPtr, &Key.UnicodeChar, 1);\r
+        CurrentCursor++;\r
+      } else if ((GetStringWidth (StringPtr) < ((Maximum + 1) * sizeof (CHAR16))) && (Key.UnicodeChar != CHAR_BACKSPACE)) {\r
+        KeyPad[0] = Key.UnicodeChar;\r
+        KeyPad[1] = CHAR_NULL;\r
+        Count = GetStringWidth (StringPtr) / 2 - 1;\r
+        if (CurrentCursor < Count) {\r
+          for (Index = 0; Index < CurrentCursor; Index++) {\r
+            TempString[Index] = StringPtr[Index];\r
+          }\r
+                 TempString[Index] = CHAR_NULL;\r
+          StrCat (TempString, KeyPad);\r
+          StrCat (TempString, StringPtr + CurrentCursor);\r
+          StrCpy (StringPtr, TempString);\r
+        } else {\r
+          StrCat (StringPtr, KeyPad);\r
+        }\r
+        CurrentCursor++;\r
+      }\r
+\r
+      //\r
+      // If the width of the input string is now larger than the screen, we nee to\r
+      // adjust the index to start printing portions of the string\r
+      //\r
+      SetUnicodeMem (BufferedString, ScreenSize - 1, L' ');\r
+      PrintStringAt (Start + 1, Top + 3, BufferedString);\r
+\r
+      if ((GetStringWidth (StringPtr) / 2) > (DimensionsWidth - 2)) {\r
+        Index = (GetStringWidth (StringPtr) / 2) - DimensionsWidth + 2;\r
+      } else {\r
+        Index = 0;\r
+      }\r
+\r
+      if (IsPassword) {\r
+        gST->ConOut->SetCursorPosition (gST->ConOut, Start + 1, Top + 3);\r
+      }\r
+\r
+      for (Count = 0; Index + 1 < GetStringWidth (StringPtr) / 2; Index++, Count++) {\r
+        BufferedString[Count] = StringPtr[Index];\r
+\r
+        if (IsPassword) {\r
+          PrintCharAt ((UINTN)-1, (UINTN)-1, L'*');\r
+        }\r
+      }\r
+\r
+      if (!IsPassword) {\r
+        PrintStringAt (Start + 1, Top + 3, BufferedString);\r
+      }\r
+      break;\r
+    }\r
+\r
+    gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
+    gST->ConOut->SetCursorPosition (gST->ConOut, Start + CurrentCursor + 1, Top + 3);\r
+  } while (TRUE);\r
+\r
+}\r
+\r
+/**\r
+  Adjust the value to the correct one. Rules follow the sample:\r
+  like:  Year change:  2012.02.29 -> 2013.02.29 -> 2013.02.01\r
+         Month change: 2013.03.29 -> 2013.02.29 -> 2013.02.28\r
+\r
+  @param  QuestionValue     Pointer to current question.\r
+  @param  Sequence          The sequence of the field in the question.\r
+**/\r
+VOID\r
+AdjustQuestionValue (\r
+  IN  EFI_HII_VALUE           *QuestionValue,\r
+  IN  UINT8                   Sequence\r
+  )\r
+{\r
+  UINT8     Month;\r
+  UINT16    Year;\r
+  UINT8     Maximum;\r
+  UINT8     Minimum;\r
+\r
+  Month   = QuestionValue->Value.date.Month;\r
+  Year    = QuestionValue->Value.date.Year;\r
+  Minimum = 1;\r
+\r
+  switch (Month) {\r
+  case 2:\r
+    if ((Year % 4) == 0 && ((Year % 100) != 0 || (Year % 400) == 0)) {\r
+      Maximum = 29;\r
+    } else {\r
+      Maximum = 28;\r
+    }\r
+    break;\r
+  case 4:\r
+  case 6:\r
+  case 9:\r
+  case 11:\r
+    Maximum = 30;\r
+    break;\r
+  default:\r
+    Maximum = 31;\r
+    break;\r
+  }\r
+\r
+  //\r
+  // Change the month area.\r
+  //\r
+  if (Sequence == 0) {\r
+    if (QuestionValue->Value.date.Day > Maximum) {\r
+      QuestionValue->Value.date.Day = Maximum;\r
+    }\r
+  }\r
+  \r
+  //\r
+  // Change the Year area.\r
+  //\r
+  if (Sequence == 2) {\r
+    if (QuestionValue->Value.date.Day > Maximum) {\r
+      QuestionValue->Value.date.Day = Minimum;\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  Get field info from numeric opcode.\r
+\r
+  @param  OpCode            Pointer to the current input opcode.\r
+  @param  Minimum           The minimum size info for this opcode.\r
+  @param  Maximum           The maximum size info for this opcode.\r
+  @param  Step              The step size info for this opcode.\r
+  @param  StorageWidth      The storage width info for this opcode.\r
+\r
+**/\r
+VOID\r
+GetValueFromNum (\r
+  IN  EFI_IFR_OP_HEADER     *OpCode,\r
+  OUT UINT64                *Minimum,\r
+  OUT UINT64                *Maximum,\r
+  OUT UINT64                *Step,\r
+  OUT UINT16                *StorageWidth\r
+)\r
+{\r
+  EFI_IFR_NUMERIC       *NumericOp;\r
+\r
+  NumericOp = (EFI_IFR_NUMERIC *) OpCode;\r
+  \r
+  switch (NumericOp->Flags & EFI_IFR_NUMERIC_SIZE) {\r
+  case EFI_IFR_NUMERIC_SIZE_1:\r
+    *Minimum = NumericOp->data.u8.MinValue;\r
+    *Maximum = NumericOp->data.u8.MaxValue;\r
+    *Step    = NumericOp->data.u8.Step;\r
+    *StorageWidth = (UINT16) sizeof (UINT8);\r
+    break;\r
+  \r
+  case EFI_IFR_NUMERIC_SIZE_2:\r
+    *Minimum = NumericOp->data.u16.MinValue;\r
+    *Maximum = NumericOp->data.u16.MaxValue;\r
+    *Step    = NumericOp->data.u16.Step;\r
+    *StorageWidth = (UINT16) sizeof (UINT16);\r
+    break;\r
+  \r
+  case EFI_IFR_NUMERIC_SIZE_4:\r
+    *Minimum = NumericOp->data.u32.MinValue;\r
+    *Maximum = NumericOp->data.u32.MaxValue;\r
+    *Step    = NumericOp->data.u32.Step;\r
+    *StorageWidth = (UINT16) sizeof (UINT32);\r
+    break;\r
+  \r
+  case EFI_IFR_NUMERIC_SIZE_8:\r
+    *Minimum = NumericOp->data.u64.MinValue;\r
+    *Maximum = NumericOp->data.u64.MaxValue;\r
+    *Step    = NumericOp->data.u64.Step;\r
+    *StorageWidth = (UINT16) sizeof (UINT64);\r
+    break;\r
+  \r
+  default:\r
+    break;\r
+  }\r
+\r
+  if (*Maximum == 0) {\r
+    *Maximum = (UINT64) -1;\r
+  }\r
+}\r
+\r
+/**\r
+  This routine reads a numeric value from the user input.\r
+\r
+  @param  MenuOption        Pointer to the current input menu.\r
+\r
+  @retval EFI_SUCCESS       If numerical input is read successfully\r
+  @retval EFI_DEVICE_ERROR  If operation fails\r
+\r
+**/\r
+EFI_STATUS\r
+GetNumericInput (\r
+  IN  UI_MENU_OPTION              *MenuOption\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  UINTN                   Column;\r
+  UINTN                   Row;\r
+  CHAR16                  InputText[MAX_NUMERIC_INPUT_WIDTH];\r
+  CHAR16                  FormattedNumber[MAX_NUMERIC_INPUT_WIDTH - 1];\r
+  UINT64                  PreviousNumber[MAX_NUMERIC_INPUT_WIDTH - 3];\r
+  UINTN                   Count;\r
+  UINTN                   Loop;\r
+  BOOLEAN                 ManualInput;\r
+  BOOLEAN                 HexInput;\r
+  BOOLEAN                 DateOrTime;\r
+  UINTN                   InputWidth;\r
+  UINT64                  EditValue;\r
+  UINT64                  Step;\r
+  UINT64                  Minimum;\r
+  UINT64                  Maximum;\r
+  UINTN                   EraseLen;\r
+  UINT8                   Digital;\r
+  EFI_INPUT_KEY           Key;\r
+  EFI_HII_VALUE           *QuestionValue;\r
+  FORM_DISPLAY_ENGINE_STATEMENT  *Question;\r
+  EFI_IFR_NUMERIC                *NumericOp;\r
+  UINT16                         StorageWidth;\r
+\r
+  Column            = MenuOption->OptCol;\r
+  Row               = MenuOption->Row;\r
+  PreviousNumber[0] = 0;\r
+  Count             = 0;\r
+  InputWidth        = 0;\r
+  Digital           = 0;\r
+  StorageWidth      = 0;\r
+  Minimum           = 0;\r
+  Maximum           = 0;\r
+  NumericOp         = NULL;\r
+\r
+  Question      = MenuOption->ThisTag;\r
+  QuestionValue = &Question->CurrentValue;\r
+\r
+  //\r
+  // Only two case, user can enter to this function: Enter and +/- case.\r
+  // In Enter case, gDirection = 0; in +/- case, gDirection = SCAN_LEFT/SCAN_WRIGHT\r
+  //\r
+  ManualInput        = (BOOLEAN)(gDirection == 0 ? TRUE : FALSE);\r
+\r
+  if ((Question->OpCode->OpCode == EFI_IFR_DATE_OP) || (Question->OpCode->OpCode == EFI_IFR_TIME_OP)) {\r
+    DateOrTime = TRUE;\r
+  } else {\r
+    DateOrTime = FALSE;\r
+  }\r
+\r
+  //\r
+  // Prepare Value to be edit\r
+  //\r
+  EraseLen = 0;\r
+  EditValue = 0;\r
+  if (Question->OpCode->OpCode == EFI_IFR_DATE_OP) {\r
+    Step = 1;\r
+    Minimum = 1;\r
+\r
+    switch (MenuOption->Sequence) {\r
+    case 0:\r
+      Maximum = 12;\r
+      EraseLen = 4;\r
+      EditValue = QuestionValue->Value.date.Month;\r
+      break;\r
+\r
+    case 1:\r
+      switch (QuestionValue->Value.date.Month) {\r
+      case 2:\r
+        if ((QuestionValue->Value.date.Year % 4) == 0  && \r
+            ((QuestionValue->Value.date.Year % 100) != 0 || \r
+            (QuestionValue->Value.date.Year % 400) == 0)) {\r
+          Maximum = 29;\r
+        } else {\r
+          Maximum = 28;\r
+        }\r
+        break;\r
+      case 4:\r
+      case 6:\r
+      case 9:\r
+      case 11:\r
+        Maximum = 30;\r
+        break;\r
+      default:\r
+        Maximum = 31;\r
+        break;\r
+      } \r
+\r
+      EraseLen = 3;\r
+      EditValue = QuestionValue->Value.date.Day;\r
+      break;\r
+\r
+    case 2:\r
+      Maximum = 0xffff;\r
+      EraseLen = 5;\r
+      EditValue = QuestionValue->Value.date.Year;\r
+      break;\r
+\r
+    default:\r
+      break;\r
+    }\r
+  } else if (Question->OpCode->OpCode == EFI_IFR_TIME_OP) {\r
+    Step = 1;\r
+    Minimum = 0;\r
+\r
+    switch (MenuOption->Sequence) {\r
+    case 0:\r
+      Maximum = 23;\r
+      EraseLen = 4;\r
+      EditValue = QuestionValue->Value.time.Hour;\r
+      break;\r
+\r
+    case 1:\r
+      Maximum = 59;\r
+      EraseLen = 3;\r
+      EditValue = QuestionValue->Value.time.Minute;\r
+      break;\r
+\r
+    case 2:\r
+      Maximum = 59;\r
+      EraseLen = 3;\r
+      EditValue = QuestionValue->Value.time.Second;\r
+      break;\r
+\r
+    default:\r
+      break;\r
+    }\r
+  } else {\r
+    ASSERT (Question->OpCode->OpCode == EFI_IFR_NUMERIC_OP);\r
+    NumericOp = (EFI_IFR_NUMERIC *) Question->OpCode;\r
+    GetValueFromNum(Question->OpCode, &Minimum, &Maximum, &Step, &StorageWidth);\r
+    EditValue = QuestionValue->Value.u64;\r
+    EraseLen  = gOptionBlockWidth;\r
+  }\r
+\r
+  if ((Question->OpCode->OpCode == EFI_IFR_NUMERIC_OP) && (NumericOp != NULL) &&\r
+      ((NumericOp->Flags & EFI_IFR_DISPLAY) == EFI_IFR_DISPLAY_UINT_HEX)) {\r
+    HexInput = TRUE;\r
+  } else {\r
+    HexInput = FALSE;\r
+  }\r
+\r
+  //\r
+  // Enter from "Enter" input, clear the old word showing.\r
+  //\r
+  if (ManualInput) {\r
+    if (Question->OpCode->OpCode == EFI_IFR_NUMERIC_OP) {\r
+      if (HexInput) {\r
+        InputWidth = StorageWidth * 2;\r
+      } else {\r
+        switch (StorageWidth) {\r
+        case 1:\r
+          InputWidth = 3;\r
+          break;\r
+\r
+        case 2:\r
+          InputWidth = 5;\r
+          break;\r
+\r
+        case 4:\r
+          InputWidth = 10;\r
+          break;\r
+\r
+        case 8:\r
+          InputWidth = 20;\r
+          break;\r
+\r
+        default:\r
+          InputWidth = 0;\r
+          break;\r
+        }\r
+      }\r
+\r
+      InputText[0] = LEFT_NUMERIC_DELIMITER;\r
+      SetUnicodeMem (InputText + 1, InputWidth, L' ');\r
+      ASSERT (InputWidth + 2 < MAX_NUMERIC_INPUT_WIDTH);\r
+      InputText[InputWidth + 1] = RIGHT_NUMERIC_DELIMITER;\r
+      InputText[InputWidth + 2] = L'\0';\r
+\r
+      PrintStringAt (Column, Row, InputText);\r
+      Column++;\r
+    }\r
+\r
+    if (Question->OpCode->OpCode == EFI_IFR_DATE_OP) {\r
+      if (MenuOption->Sequence == 2) {\r
+        InputWidth = 4;\r
+      } else {\r
+        InputWidth = 2;\r
+      }\r
+\r
+      if (MenuOption->Sequence == 0) {\r
+        InputText[0] = LEFT_NUMERIC_DELIMITER;\r
+        SetUnicodeMem (InputText + 1, InputWidth, L' ');\r
+      } else {\r
+        SetUnicodeMem (InputText, InputWidth, L' ');\r
+      }\r
+\r
+      if (MenuOption->Sequence == 2) {\r
+        InputText[InputWidth + 1] = RIGHT_NUMERIC_DELIMITER;\r
+      } else {\r
+        InputText[InputWidth + 1] = DATE_SEPARATOR;\r
+      }\r
+      InputText[InputWidth + 2] = L'\0';\r
+\r
+      PrintStringAt (Column, Row, InputText);\r
+      if (MenuOption->Sequence == 0) {\r
+        Column++;\r
+      }\r
+    }\r
+\r
+    if (Question->OpCode->OpCode == EFI_IFR_TIME_OP) {\r
+      InputWidth = 2;\r
+\r
+      if (MenuOption->Sequence == 0) {\r
+        InputText[0] = LEFT_NUMERIC_DELIMITER;\r
+        SetUnicodeMem (InputText + 1, InputWidth, L' ');\r
+      } else {\r
+        SetUnicodeMem (InputText, InputWidth, L' ');\r
+      }\r
+\r
+      if (MenuOption->Sequence == 2) {\r
+        InputText[InputWidth + 1] = RIGHT_NUMERIC_DELIMITER;\r
+      } else {\r
+        InputText[InputWidth + 1] = TIME_SEPARATOR;\r
+      }\r
+      InputText[InputWidth + 2] = L'\0';\r
+\r
+      PrintStringAt (Column, Row, InputText);\r
+      if (MenuOption->Sequence == 0) {\r
+        Column++;\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // First time we enter this handler, we need to check to see if\r
+  // we were passed an increment or decrement directive\r
+  //\r
+  do {\r
+    Key.UnicodeChar = CHAR_NULL;\r
+    if (gDirection != 0) {\r
+      Key.ScanCode  = gDirection;\r
+      gDirection    = 0;\r
+      goto TheKey2;\r
+    }\r
+\r
+    Status = WaitForKeyStroke (&Key);\r
+\r
+TheKey2:\r
+    switch (Key.UnicodeChar) {\r
+\r
+    case '+':\r
+    case '-':\r
+      if (Key.UnicodeChar == '+') {\r
+        Key.ScanCode = SCAN_RIGHT;\r
+      } else {\r
+        Key.ScanCode = SCAN_LEFT;\r
+      }\r
+      Key.UnicodeChar = CHAR_NULL;\r
+      goto TheKey2;\r
+\r
+    case CHAR_NULL:\r
+      switch (Key.ScanCode) {\r
+      case SCAN_LEFT:\r
+      case SCAN_RIGHT:\r
+        if (DateOrTime && !ManualInput) {\r
+          //\r
+          // By setting this value, we will return back to the caller.\r
+          // We need to do this since an auto-refresh will destroy the adjustment\r
+          // based on what the real-time-clock is showing.  So we always commit\r
+          // upon changing the value.\r
+          //\r
+          gDirection = SCAN_DOWN;\r
+        }\r
+\r
+        if ((Step != 0) && !ManualInput) {\r
+          if (Key.ScanCode == SCAN_LEFT) {\r
+            if (EditValue >= Minimum + Step) {\r
+              EditValue = EditValue - Step;\r
+            } else if (EditValue > Minimum){\r
+              EditValue = Minimum;\r
+            } else {\r
+              EditValue = Maximum;\r
+            }\r
+          } else if (Key.ScanCode == SCAN_RIGHT) {\r
+            if (EditValue + Step <= Maximum) {\r
+              EditValue = EditValue + Step;\r
+            } else if (EditValue < Maximum) {\r
+              EditValue = Maximum;\r
+            } else {\r
+              EditValue = Minimum;\r
+            }\r
+          }\r
+\r
+          ZeroMem (FormattedNumber, 21 * sizeof (CHAR16));\r
+          if (Question->OpCode->OpCode == EFI_IFR_DATE_OP) {\r
+            if (MenuOption->Sequence == 2) {\r
+              //\r
+              // Year\r
+              //\r
+              UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%04d", (UINT16) EditValue);\r
+            } else {\r
+              //\r
+              // Month/Day\r
+              //\r
+              UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%02d", (UINT8) EditValue);\r
+            }\r
+\r
+            if (MenuOption->Sequence == 0) {\r
+              ASSERT (EraseLen >= 2);\r
+              FormattedNumber[EraseLen - 2] = DATE_SEPARATOR;\r
+            } else if (MenuOption->Sequence == 1) {\r
+              ASSERT (EraseLen >= 1);\r
+              FormattedNumber[EraseLen - 1] = DATE_SEPARATOR;\r
+            }\r
+          } else if (Question->OpCode->OpCode == EFI_IFR_TIME_OP) {\r
+            UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%02d", (UINT8) EditValue);\r
+\r
+            if (MenuOption->Sequence == 0) {\r
+              ASSERT (EraseLen >= 2);\r
+              FormattedNumber[EraseLen - 2] = TIME_SEPARATOR;\r
+            } else if (MenuOption->Sequence == 1) {\r
+              ASSERT (EraseLen >= 1);\r
+              FormattedNumber[EraseLen - 1] = TIME_SEPARATOR;\r
+            }\r
+          } else {\r
+            QuestionValue->Value.u64 = EditValue;\r
+            PrintFormattedNumber (Question, FormattedNumber, 21 * sizeof (CHAR16));\r
+          }\r
+\r
+          gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ());\r
+          for (Loop = 0; Loop < EraseLen; Loop++) {\r
+            PrintStringAt (MenuOption->OptCol + Loop, MenuOption->Row, L" ");\r
+          }\r
+          gST->ConOut->SetAttribute (gST->ConOut, GetHighlightTextColor ());\r
+\r
+          if (MenuOption->Sequence == 0) {\r
+            PrintCharAt (MenuOption->OptCol, Row, LEFT_NUMERIC_DELIMITER);\r
+            Column = MenuOption->OptCol + 1;\r
+          }\r
+\r
+          PrintStringAt (Column, Row, FormattedNumber);\r
+\r
+          if (!DateOrTime || MenuOption->Sequence == 2) {\r
+            PrintCharAt ((UINTN)-1, (UINTN)-1, RIGHT_NUMERIC_DELIMITER);\r
+          }\r
+        }\r
+\r
+        goto EnterCarriageReturn;\r
+        break;\r
+\r
+      case SCAN_UP:\r
+      case SCAN_DOWN:\r
+        goto EnterCarriageReturn;\r
+\r
+      case SCAN_ESC:\r
+        return EFI_DEVICE_ERROR;\r
+\r
+      default:\r
+        break;\r
+      }\r
+\r
+      break;\r
+\r
+EnterCarriageReturn:\r
+\r
+    case CHAR_CARRIAGE_RETURN:\r
+      //\r
+      // Validate input value with Minimum value.\r
+      //\r
+      if (EditValue < Minimum) {\r
+        UpdateStatusBar (INPUT_ERROR, TRUE);\r
+        break;\r
+      } else {\r
+        UpdateStatusBar (INPUT_ERROR, FALSE);\r
+      }\r
+      \r
+      CopyMem (&gUserInput->InputValue, &Question->CurrentValue, sizeof (EFI_HII_VALUE));\r
+      QuestionValue = &gUserInput->InputValue;\r
+      //\r
+      // Store Edit value back to Question\r
+      //\r
+      if (Question->OpCode->OpCode == EFI_IFR_DATE_OP) {\r
+        switch (MenuOption->Sequence) {\r
+        case 0:\r
+          QuestionValue->Value.date.Month = (UINT8) EditValue;\r
+          break;\r
+\r
+        case 1:\r
+          QuestionValue->Value.date.Day = (UINT8) EditValue;\r
+          break;\r
+\r
+        case 2:\r
+          QuestionValue->Value.date.Year = (UINT16) EditValue;\r
+          break;\r
+\r
+        default:\r
+          break;\r
+        }\r
+      } else if (Question->OpCode->OpCode  == EFI_IFR_TIME_OP) {\r
+        switch (MenuOption->Sequence) {\r
+        case 0:\r
+          QuestionValue->Value.time.Hour = (UINT8) EditValue;\r
+          break;\r
+\r
+        case 1:\r
+          QuestionValue->Value.time.Minute = (UINT8) EditValue;\r
+          break;\r
+\r
+        case 2:\r
+          QuestionValue->Value.time.Second = (UINT8) EditValue;\r
+          break;\r
+\r
+        default:\r
+          break;\r
+        }\r
+      } else {\r
+        //\r
+        // Numeric\r
+        //\r
+        QuestionValue->Value.u64 = EditValue;\r
+      }\r
+\r
+      //\r
+      // Adjust the value to the correct one.\r
+      // Sample like: 2012.02.29 -> 2013.02.29 -> 2013.02.01\r
+      //              2013.03.29 -> 2013.02.29 -> 2013.02.28\r
+      //\r
+      if (Question->OpCode->OpCode  == EFI_IFR_DATE_OP && \r
+        (MenuOption->Sequence == 0 || MenuOption->Sequence == 2)) {\r
+        AdjustQuestionValue (QuestionValue, (UINT8)MenuOption->Sequence);\r
+      }\r
+\r
+      return ValidateQuestion (Question);\r
+      break;\r
+\r
+    case CHAR_BACKSPACE:\r
+      if (ManualInput) {\r
+        if (Count == 0) {\r
+          break;\r
+        }\r
+        //\r
+        // Remove a character\r
+        //\r
+        EditValue = PreviousNumber[Count - 1];\r
+        UpdateStatusBar (INPUT_ERROR,  FALSE);\r
+        Count--;\r
+        Column--;\r
+        PrintStringAt (Column, Row, L" ");\r
+      }\r
+      break;\r
+\r
+    default:\r
+      if (ManualInput) {\r
+        if (HexInput) {\r
+          if ((Key.UnicodeChar >= L'0') && (Key.UnicodeChar <= L'9')) {\r
+            Digital = (UINT8) (Key.UnicodeChar - L'0');\r
+          } else if ((Key.UnicodeChar >= L'A') && (Key.UnicodeChar <= L'F')) {\r
+            Digital = (UINT8) (Key.UnicodeChar - L'A' + 0x0A);\r
+          } else if ((Key.UnicodeChar >= L'a') && (Key.UnicodeChar <= L'f')) {\r
+            Digital = (UINT8) (Key.UnicodeChar - L'a' + 0x0A);\r
+          } else {\r
+            UpdateStatusBar (INPUT_ERROR, TRUE);\r
+            break;\r
+          }\r
+        } else {\r
+          if (Key.UnicodeChar > L'9' || Key.UnicodeChar < L'0') {\r
+            UpdateStatusBar (INPUT_ERROR, TRUE);\r
+            break;\r
+          }\r
+        }\r
+\r
+        //\r
+        // If Count exceed input width, there is no way more is valid\r
+        //\r
+        if (Count >= InputWidth) {\r
+          break;\r
+        }\r
+        //\r
+        // Someone typed something valid!\r
+        //\r
+        if (Count != 0) {\r
+          if (HexInput) {\r
+            EditValue = LShiftU64 (EditValue, 4) + Digital;\r
+          } else {\r
+            EditValue = MultU64x32 (EditValue, 10) + (Key.UnicodeChar - L'0');\r
+          }\r
+        } else {\r
+          if (HexInput) {\r
+            EditValue = Digital;\r
+          } else {\r
+            EditValue = Key.UnicodeChar - L'0';\r
+          }\r
+        }\r
+\r
+        if (EditValue > Maximum) {\r
+          UpdateStatusBar (INPUT_ERROR, TRUE);\r
+          ASSERT (Count < sizeof (PreviousNumber) / sizeof (PreviousNumber[0]));\r
+          EditValue = PreviousNumber[Count];\r
+          break;\r
+        } else {\r
+          UpdateStatusBar (INPUT_ERROR, FALSE);\r
+        }\r
+\r
+        Count++;\r
+        ASSERT (Count < (sizeof (PreviousNumber) / sizeof (PreviousNumber[0])));\r
+        PreviousNumber[Count] = EditValue;\r
+\r
+        gST->ConOut->SetAttribute (gST->ConOut, GetHighlightTextColor ());\r
+        PrintCharAt (Column, Row, Key.UnicodeChar);\r
+        Column++;\r
+      }\r
+      break;\r
+    }\r
+  } while (TRUE);\r
+}\r
+\r
+/**\r
+  Adjust option order base on the question value.\r
+\r
+  @param  Question           Pointer to current question.\r
+  @param  PopUpMenuLines     The line number of the pop up menu.\r
+\r
+  @retval EFI_SUCCESS       If Option input is processed successfully\r
+  @retval EFI_DEVICE_ERROR  If operation fails\r
+\r
+**/\r
+EFI_STATUS\r
+AdjustOptionOrder (\r
+  IN  FORM_DISPLAY_ENGINE_STATEMENT  *Question,\r
+  OUT UINTN                          *PopUpMenuLines\r
+  )\r
+{\r
+  UINTN                   Index;\r
+  EFI_IFR_ORDERED_LIST    *OrderList;\r
+  UINT8                   *ValueArray;\r
+  UINT8                   ValueType;\r
+  LIST_ENTRY              *Link;\r
+  DISPLAY_QUESTION_OPTION *OneOfOption;\r
+  EFI_HII_VALUE           *HiiValueArray;\r
+\r
+  Link        = GetFirstNode (&Question->OptionListHead);\r
+  OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);\r
+  ValueArray  = Question->CurrentValue.Buffer;\r
+  ValueType   =  OneOfOption->OptionOpCode->Type;\r
+  OrderList   = (EFI_IFR_ORDERED_LIST *) Question->OpCode;\r
+\r
+  for (Index = 0; Index < OrderList->MaxContainers; Index++) {\r
+    if (GetArrayData (ValueArray, ValueType, Index) == 0) {\r
+      break;\r
+    }\r
+  }\r
+  \r
+  *PopUpMenuLines = Index;\r
+  \r
+  //\r
+  // Prepare HiiValue array\r
+  //  \r
+  HiiValueArray = AllocateZeroPool (*PopUpMenuLines * sizeof (EFI_HII_VALUE));\r
+  ASSERT (HiiValueArray != NULL);\r
+\r
+  for (Index = 0; Index < *PopUpMenuLines; Index++) {\r
+    HiiValueArray[Index].Type = ValueType;\r
+    HiiValueArray[Index].Value.u64 = GetArrayData (ValueArray, ValueType, Index);\r
+  }\r
+  \r
+  for (Index = 0; Index < *PopUpMenuLines; Index++) {\r
+    OneOfOption = ValueToOption (Question, &HiiValueArray[*PopUpMenuLines - Index - 1]);\r
+    if (OneOfOption == NULL) {\r
+      return EFI_NOT_FOUND;\r
+    }\r
+  \r
+    RemoveEntryList (&OneOfOption->Link);\r
+  \r
+    //\r
+    // Insert to head.\r
+    //\r
+    InsertHeadList (&Question->OptionListHead, &OneOfOption->Link);\r
+  }\r
+  \r
+  FreePool (HiiValueArray);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Base on the type to compare the value.\r
+\r
+  @param  Value1                The first value need to compare.\r
+  @param  Value2                The second value need to compare.\r
+  @param  Type                  The value type for above two values.\r
+\r
+  @retval TRUE                  The two value are same.\r
+  @retval FALSE                 The two value are different.\r
+\r
+**/\r
+BOOLEAN\r
+IsValuesEqual (\r
+  IN EFI_IFR_TYPE_VALUE *Value1,\r
+  IN EFI_IFR_TYPE_VALUE *Value2,\r
+  IN UINT8              Type\r
+  )\r
+{\r
+  switch (Type) {\r
+  case EFI_IFR_TYPE_BOOLEAN:\r
+  case EFI_IFR_TYPE_NUM_SIZE_8:\r
+    return Value1->u8 == Value2->u8;\r
+  \r
+  case EFI_IFR_TYPE_NUM_SIZE_16:\r
+    return Value1->u16 == Value2->u16;\r
+\r
+  case EFI_IFR_TYPE_NUM_SIZE_32:\r
+    return Value1->u32 == Value2->u32;\r
+\r
+  case EFI_IFR_TYPE_NUM_SIZE_64:\r
+    return Value1->u64 == Value2->u64;\r
+\r
+  default:\r
+    ASSERT (FALSE);\r
+    return FALSE;\r
+  }\r
+}\r
+\r
+/**\r
+  Base on the type to set the value.\r
+\r
+  @param  Dest                  The dest value.\r
+  @param  Source                The source value.\r
+  @param  Type                  The value type for above two values.\r
+\r
+**/\r
+VOID\r
+SetValuesByType (\r
+  OUT EFI_IFR_TYPE_VALUE *Dest,\r
+  IN  EFI_IFR_TYPE_VALUE *Source,\r
+  IN  UINT8              Type\r
+  )\r
+{\r
+  switch (Type) {\r
+  case EFI_IFR_TYPE_BOOLEAN:\r
+    Dest->b = Source->b;\r
+    break;\r
+\r
+  case EFI_IFR_TYPE_NUM_SIZE_8:\r
+    Dest->u8 = Source->u8;\r
+    break;\r
+\r
+  case EFI_IFR_TYPE_NUM_SIZE_16:\r
+    Dest->u16 = Source->u16;\r
+    break;\r
+\r
+  case EFI_IFR_TYPE_NUM_SIZE_32:\r
+    Dest->u32 = Source->u32;\r
+    break;\r
+\r
+  case EFI_IFR_TYPE_NUM_SIZE_64:\r
+    Dest->u64 = Source->u64;\r
+    break;\r
+\r
+  default:\r
+    ASSERT (FALSE);\r
+    break;\r
+  }\r
+}\r
+\r
+/**\r
+  Get selection for OneOf and OrderedList (Left/Right will be ignored).\r
+\r
+  @param  MenuOption        Pointer to the current input menu.\r
+\r
+  @retval EFI_SUCCESS       If Option input is processed successfully\r
+  @retval EFI_DEVICE_ERROR  If operation fails\r
+\r
+**/\r
+EFI_STATUS\r
+GetSelectionInputPopUp (\r
+  IN  UI_MENU_OPTION              *MenuOption\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  EFI_INPUT_KEY           Key;\r
+  UINTN                   Index;\r
+  CHAR16                  *StringPtr;\r
+  CHAR16                  *TempStringPtr;\r
+  UINTN                   Index2;\r
+  UINTN                   TopOptionIndex;\r
+  UINTN                   HighlightOptionIndex;\r
+  UINTN                   Start;\r
+  UINTN                   End;\r
+  UINTN                   Top;\r
+  UINTN                   Bottom;\r
+  UINTN                   PopUpMenuLines;\r
+  UINTN                   MenuLinesInView;\r
+  UINTN                   PopUpWidth;\r
+  CHAR16                  Character;\r
+  INT32                   SavedAttribute;\r
+  BOOLEAN                 ShowDownArrow;\r
+  BOOLEAN                 ShowUpArrow;\r
+  UINTN                   DimensionsWidth;\r
+  LIST_ENTRY              *Link;\r
+  BOOLEAN                 OrderedList;\r
+  UINT8                   *ValueArray;\r
+  UINT8                   *ReturnValue;\r
+  UINT8                   ValueType;\r
+  EFI_HII_VALUE           HiiValue;\r
+  DISPLAY_QUESTION_OPTION         *OneOfOption;\r
+  DISPLAY_QUESTION_OPTION         *CurrentOption;\r
+  FORM_DISPLAY_ENGINE_STATEMENT  *Question;\r
+  INTN                    Result;\r
+  EFI_IFR_ORDERED_LIST    *OrderList;\r
+\r
+  DimensionsWidth   = gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn;\r
+\r
+  ValueArray        = NULL;\r
+  ValueType         = 0;\r
+  CurrentOption     = NULL;\r
+  ShowDownArrow     = FALSE;\r
+  ShowUpArrow       = FALSE;\r
+\r
+  StringPtr = AllocateZeroPool ((gOptionBlockWidth + 1) * 2);\r
+  ASSERT (StringPtr);\r
+\r
+  ZeroMem (&HiiValue, sizeof (EFI_HII_VALUE));\r
+\r
+  Question = MenuOption->ThisTag;\r
+  if (Question->OpCode->OpCode == EFI_IFR_ORDERED_LIST_OP) {\r
+    Link = GetFirstNode (&Question->OptionListHead);\r
+    OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);\r
+    ValueArray = Question->CurrentValue.Buffer;\r
+    ValueType =  OneOfOption->OptionOpCode->Type;\r
+    OrderedList = TRUE;\r
+    OrderList = (EFI_IFR_ORDERED_LIST *) Question->OpCode;\r
+  } else {\r
+    OrderedList = FALSE;\r
+    OrderList = NULL;\r
+  }\r
+\r
+  //\r
+  // Calculate Option count\r
+  //\r
+  PopUpMenuLines = 0;\r
+  if (OrderedList) {\r
+    AdjustOptionOrder(Question, &PopUpMenuLines);\r
+  } else {\r
+    Link = GetFirstNode (&Question->OptionListHead);\r
+    while (!IsNull (&Question->OptionListHead, Link)) {\r
+      OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);\r
+      PopUpMenuLines++;\r
+      Link = GetNextNode (&Question->OptionListHead, Link);\r
+    }\r
+  }\r
+\r
+  //\r
+  // Get the number of one of options present and its size\r
+  //\r
+  PopUpWidth = 0;\r
+  HighlightOptionIndex = 0;\r
+  Link = GetFirstNode (&Question->OptionListHead);\r
+  for (Index = 0; Index < PopUpMenuLines; Index++) {\r
+    OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);\r
+\r
+    StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle);\r
+    if (StrLen (StringPtr) > PopUpWidth) {\r
+      PopUpWidth = StrLen (StringPtr);\r
+    }\r
+    FreePool (StringPtr);\r
+    HiiValue.Type = OneOfOption->OptionOpCode->Type;\r
+    SetValuesByType (&HiiValue.Value, &OneOfOption->OptionOpCode->Value, HiiValue.Type);\r
+    if (!OrderedList && (CompareHiiValue (&Question->CurrentValue, &HiiValue, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) {\r
+      //\r
+      // Find current selected Option for OneOf\r
+      //\r
+      HighlightOptionIndex = Index;\r
+    }\r
+\r
+    Link = GetNextNode (&Question->OptionListHead, Link);\r
+  }\r
+\r
+  //\r
+  // Perform popup menu initialization.\r
+  //\r
+  PopUpWidth = PopUpWidth + POPUP_PAD_SPACE_COUNT;\r
+\r
+  SavedAttribute = gST->ConOut->Mode->Attribute;\r
+  gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ());\r
+\r
+  if ((PopUpWidth + POPUP_FRAME_WIDTH) > DimensionsWidth) {\r
+    PopUpWidth = DimensionsWidth - POPUP_FRAME_WIDTH;\r
+  }\r
+\r
+  Start  = (DimensionsWidth - PopUpWidth - POPUP_FRAME_WIDTH) / 2 + gStatementDimensions.LeftColumn;\r
+  End    = Start + PopUpWidth + POPUP_FRAME_WIDTH;\r
+  Top    = gStatementDimensions.TopRow;\r
+  Bottom = gStatementDimensions.BottomRow - 1;\r
+\r
+  MenuLinesInView = Bottom - Top - 1;\r
+  if (MenuLinesInView >= PopUpMenuLines) {\r
+    Top     = Top + (MenuLinesInView - PopUpMenuLines) / 2;\r
+    Bottom  = Top + PopUpMenuLines + 1;\r
+  } else {\r
+    ShowDownArrow = TRUE;\r
+  }\r
+\r
+  if (HighlightOptionIndex > (MenuLinesInView - 1)) {\r
+    TopOptionIndex = HighlightOptionIndex - MenuLinesInView + 1;\r
+  } else {\r
+    TopOptionIndex = 0;\r
+  }\r
+\r
+  do {\r
+    //\r
+    // Clear that portion of the screen\r
+    //\r
+    ClearLines (Start, End, Top, Bottom, GetPopupColor ());\r
+\r
+    //\r
+    // Draw "One of" pop-up menu\r
+    //\r
+    Character = BOXDRAW_DOWN_RIGHT;\r
+    PrintCharAt (Start, Top, Character);\r
+    for (Index = Start; Index + 2 < End; Index++) {\r
+      if ((ShowUpArrow) && ((Index + 1) == (Start + End) / 2)) {\r
+        Character = GEOMETRICSHAPE_UP_TRIANGLE;\r
+      } else {\r
+        Character = BOXDRAW_HORIZONTAL;\r
+      }\r
+\r
+      PrintCharAt ((UINTN)-1, (UINTN)-1, Character);\r
+    }\r
+\r
+    Character = BOXDRAW_DOWN_LEFT;\r
+    PrintCharAt ((UINTN)-1, (UINTN)-1, Character);\r
+    Character = BOXDRAW_VERTICAL;\r
+    for (Index = Top + 1; Index < Bottom; Index++) {\r
+      PrintCharAt (Start, Index, Character);\r
+      PrintCharAt (End - 1, Index, Character);\r
+    }\r
+\r
+    //\r
+    // Move to top Option\r
+    //\r
+    Link = GetFirstNode (&Question->OptionListHead);\r
+    for (Index = 0; Index < TopOptionIndex; Index++) {\r
+      Link = GetNextNode (&Question->OptionListHead, Link);\r
+    }\r
+\r
+    //\r
+    // Display the One of options\r
+    //\r
+    Index2 = Top + 1;\r
+    for (Index = TopOptionIndex; (Index < PopUpMenuLines) && (Index2 < Bottom); Index++) {\r
+      OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);\r
+      Link = GetNextNode (&Question->OptionListHead, Link);\r
+\r
+      StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle);\r
+      ASSERT (StringPtr != NULL);\r
+      //\r
+      // If the string occupies multiple lines, truncate it to fit in one line,\r
+      // and append a "..." for indication.\r
+      //\r
+      if (StrLen (StringPtr) > (PopUpWidth - 1)) {\r
+        TempStringPtr = AllocateZeroPool (sizeof (CHAR16) * (PopUpWidth - 1));\r
+        ASSERT ( TempStringPtr != NULL );\r
+        CopyMem (TempStringPtr, StringPtr, (sizeof (CHAR16) * (PopUpWidth - 5)));\r
+        FreePool (StringPtr);\r
+        StringPtr = TempStringPtr;\r
+        StrCat (StringPtr, L"...");\r
+      }\r
+\r
+      if (Index == HighlightOptionIndex) {\r
+          //\r
+          // Highlight the selected one\r
+          //\r
+          CurrentOption = OneOfOption;\r
+\r
+          gST->ConOut->SetAttribute (gST->ConOut, GetPickListColor ());\r
+          PrintStringAt (Start + 2, Index2, StringPtr);\r
+          gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ());\r
+        } else {\r
+          gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ());\r
+          PrintStringAt (Start + 2, Index2, StringPtr);\r
+        }\r
+\r
+      Index2++;\r
+      FreePool (StringPtr);\r
+    }\r
+\r
+    Character = BOXDRAW_UP_RIGHT;\r
+    PrintCharAt (Start, Bottom, Character);\r
+    for (Index = Start; Index + 2 < End; Index++) {\r
+      if ((ShowDownArrow) && ((Index + 1) == (Start + End) / 2)) {\r
+        Character = GEOMETRICSHAPE_DOWN_TRIANGLE;\r
+      } else {\r
+        Character = BOXDRAW_HORIZONTAL;\r
+      }\r
+\r
+      PrintCharAt ((UINTN)-1, (UINTN)-1, Character);\r
+    }\r
+\r
+    Character = BOXDRAW_UP_LEFT;\r
+    PrintCharAt ((UINTN)-1, (UINTN)-1, Character);\r
+\r
+    //\r
+    // Get User selection\r
+    //\r
+    Key.UnicodeChar = CHAR_NULL;\r
+    if ((gDirection == SCAN_UP) || (gDirection == SCAN_DOWN)) {\r
+      Key.ScanCode  = gDirection;\r
+      gDirection    = 0;\r
+      goto TheKey;\r
+    }\r
+\r
+    Status = WaitForKeyStroke (&Key);\r
+\r
+TheKey:\r
+    switch (Key.UnicodeChar) {\r
+    case '+':\r
+      if (OrderedList) {\r
+        if ((TopOptionIndex > 0) && (TopOptionIndex == HighlightOptionIndex)) {\r
+          //\r
+          // Highlight reaches the top of the popup window, scroll one menu item.\r
+          //\r
+          TopOptionIndex--;\r
+          ShowDownArrow = TRUE;\r
+        }\r
+\r
+        if (TopOptionIndex == 0) {\r
+          ShowUpArrow = FALSE;\r
+        }\r
+\r
+        if (HighlightOptionIndex > 0) {\r
+          HighlightOptionIndex--;\r
+\r
+          ASSERT (CurrentOption != NULL);\r
+          SwapListEntries (CurrentOption->Link.BackLink, &CurrentOption->Link);\r
+        }\r
+      }\r
+      break;\r
+\r
+    case '-':\r
+      //\r
+      // If an ordered list op-code, we will allow for a popup of +/- keys\r
+      // to create an ordered list of items\r
+      //\r
+      if (OrderedList) {\r
+        if (((TopOptionIndex + MenuLinesInView) < PopUpMenuLines) &&\r
+            (HighlightOptionIndex == (TopOptionIndex + MenuLinesInView - 1))) {\r
+          //\r
+          // Highlight reaches the bottom of the popup window, scroll one menu item.\r
+          //\r
+          TopOptionIndex++;\r
+          ShowUpArrow = TRUE;\r
+        }\r
+\r
+        if ((TopOptionIndex + MenuLinesInView) == PopUpMenuLines) {\r
+          ShowDownArrow = FALSE;\r
+        }\r
+\r
+        if (HighlightOptionIndex < (PopUpMenuLines - 1)) {\r
+          HighlightOptionIndex++;\r
+\r
+          ASSERT (CurrentOption != NULL);\r
+          SwapListEntries (&CurrentOption->Link, CurrentOption->Link.ForwardLink);\r
+        }\r
+      }\r
+      break;\r
+\r
+    case CHAR_NULL:\r
+      switch (Key.ScanCode) {\r
+      case SCAN_UP:\r
+      case SCAN_DOWN:\r
+        if (Key.ScanCode == SCAN_UP) {\r
+          if ((TopOptionIndex > 0) && (TopOptionIndex == HighlightOptionIndex)) {\r
+            //\r
+            // Highlight reaches the top of the popup window, scroll one menu item.\r
+            //\r
+            TopOptionIndex--;\r
+            ShowDownArrow = TRUE;\r
+          }\r
+\r
+          if (TopOptionIndex == 0) {\r
+            ShowUpArrow = FALSE;\r
+          }\r
+\r
+          if (HighlightOptionIndex > 0) {\r
+            HighlightOptionIndex--;\r
+          }\r
+        } else {\r
+          if (((TopOptionIndex + MenuLinesInView) < PopUpMenuLines) &&\r
+              (HighlightOptionIndex == (TopOptionIndex + MenuLinesInView - 1))) {\r
+            //\r
+            // Highlight reaches the bottom of the popup window, scroll one menu item.\r
+            //\r
+            TopOptionIndex++;\r
+            ShowUpArrow = TRUE;\r
+          }\r
+\r
+          if ((TopOptionIndex + MenuLinesInView) == PopUpMenuLines) {\r
+            ShowDownArrow = FALSE;\r
+          }\r
+\r
+          if (HighlightOptionIndex < (PopUpMenuLines - 1)) {\r
+            HighlightOptionIndex++;\r
+          }\r
+        }\r
+        break;\r
+\r
+      case SCAN_ESC:\r
+        gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);\r
+\r
+        //\r
+        // Restore link list order for orderedlist\r
+        //\r
+        if (OrderedList) {\r
+          HiiValue.Type = ValueType;\r
+          HiiValue.Value.u64 = 0;\r
+          for (Index = 0; Index < OrderList->MaxContainers; Index++) {\r
+            HiiValue.Value.u64 = GetArrayData (ValueArray, ValueType, Index);\r
+            if (HiiValue.Value.u64 == 0) {\r
+              break;\r
+            }\r
+\r
+            OneOfOption = ValueToOption (Question, &HiiValue);\r
+            if (OneOfOption == NULL) {\r
+              return EFI_NOT_FOUND;\r
+            }\r
+\r
+            RemoveEntryList (&OneOfOption->Link);\r
+            InsertTailList (&Question->OptionListHead, &OneOfOption->Link);\r
+          }\r
+        }\r
+\r
+        return EFI_DEVICE_ERROR;\r
+\r
+      default:\r
+        break;\r
+      }\r
+\r
+      break;\r
+\r
+    case CHAR_CARRIAGE_RETURN:\r
+      //\r
+      // return the current selection\r
+      //\r
+      if (OrderedList) {\r
+        ReturnValue = AllocateZeroPool (Question->CurrentValue.BufferLen);\r
+        ASSERT (ReturnValue != NULL);\r
+        Index = 0;\r
+        Link = GetFirstNode (&Question->OptionListHead);\r
+        while (!IsNull (&Question->OptionListHead, Link)) {\r
+          OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);\r
+          Link = GetNextNode (&Question->OptionListHead, Link);\r
+\r
+          SetArrayData (ReturnValue, ValueType, Index, OneOfOption->OptionOpCode->Value.u64);\r
+\r
+          Index++;\r
+          if (Index > OrderList->MaxContainers) {\r
+            break;\r
+          }\r
+        }\r
+        if (CompareMem (ReturnValue, ValueArray, Question->CurrentValue.BufferLen) == 0) {\r
+          FreePool (ReturnValue);\r
+          return EFI_DEVICE_ERROR;\r
+        } else {\r
+          gUserInput->InputValue.Buffer = ReturnValue;\r
+          gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen;\r
+          Status = EFI_SUCCESS;\r
+        }\r
+      } else {\r
+        ASSERT (CurrentOption != NULL);\r
+        gUserInput->InputValue.Type = CurrentOption->OptionOpCode->Type;\r
+        if (IsValuesEqual (&Question->CurrentValue.Value, &CurrentOption->OptionOpCode->Value, gUserInput->InputValue.Type)) {\r
+          return EFI_DEVICE_ERROR;\r
+        } else {\r
+          SetValuesByType (&gUserInput->InputValue.Value, &CurrentOption->OptionOpCode->Value, gUserInput->InputValue.Type);\r
+          Status = EFI_SUCCESS;\r
+        }\r
+      }\r
+\r
+      gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);\r
+\r
+      return ValidateQuestion (Question);\r
+      \r
+    default:\r
+      break;\r
+    }\r
+  } while (TRUE);\r
+\r
+}\r
+\r
diff --git a/MdeModulePkg/Universal/DisplayEngineDxe/Print.c b/MdeModulePkg/Universal/DisplayEngineDxe/Print.c
new file mode 100644 (file)
index 0000000..f5a95c4
--- /dev/null
@@ -0,0 +1,54 @@
+/** @file\r
+Basic Ascii AvSPrintf() function named VSPrint(). VSPrint() enables very\r
+simple implemenation of SPrint() and Print() to support debug.\r
+\r
+You can not Print more than EFI_DRIVER_LIB_MAX_PRINT_BUFFER characters at a\r
+time. This makes the implementation very simple.\r
+\r
+VSPrint, Print, SPrint format specification has the follwoing form\r
+\r
+%type\r
+\r
+type:\r
+  'S','s' - argument is an Unicode string\r
+  'c' - argument is an ascii character\r
+  '%' - Print a %\r
+\r
+\r
+Copyright (c) 2004 - 2012, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "FormDisplay.h"\r
+\r
+\r
+/**\r
+  Set Buffer to Value for Size bytes.\r
+\r
+  @param  Buffer                 Memory to set.\r
+  @param  Size                   Number of bytes to set\r
+  @param  Value                  Value of the set operation.\r
+\r
+**/\r
+VOID\r
+SetUnicodeMem (\r
+  IN VOID   *Buffer,\r
+  IN UINTN  Size,\r
+  IN CHAR16 Value\r
+  )\r
+{\r
+  CHAR16  *Ptr;\r
+\r
+  Ptr = Buffer;\r
+  while ((Size--)  != 0) {\r
+    *(Ptr++) = Value;\r
+  }\r
+}\r
+\r
diff --git a/MdeModulePkg/Universal/DisplayEngineDxe/ProcessOptions.c b/MdeModulePkg/Universal/DisplayEngineDxe/ProcessOptions.c
new file mode 100644 (file)
index 0000000..aca043a
--- /dev/null
@@ -0,0 +1,1286 @@
+/** @file\r
+Implementation for handling the User Interface option processing.\r
+\r
+\r
+Copyright (c) 2004 - 2012, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "FormDisplay.h"\r
+\r
+/**\r
+  Concatenate a narrow string to another string.\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
+\r
+**/\r
+VOID\r
+NewStrCat (\r
+  IN OUT CHAR16               *Destination,\r
+  IN     CHAR16               *Source\r
+  )\r
+{\r
+  UINTN Length;\r
+\r
+  for (Length = 0; Destination[Length] != 0; Length++)\r
+    ;\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
+\r
+  StrCpy (Destination + Length, Source);\r
+}\r
+\r
+/**\r
+  Compare two Hii value.\r
+\r
+  @param  Value1                 Expression value to compare on left-hand.\r
+  @param  Value2                 Expression value to compare on right-hand.\r
+  @param  Result                 Return value after compare.\r
+                                 retval 0                      Two operators equal.\r
+                                 return Positive value if Value1 is greater than Value2.\r
+                                 retval Negative value if Value1 is less than Value2.\r
+  @param  HiiHandle              Only required for string compare.\r
+\r
+  @retval other                  Could not perform compare on two values.\r
+  @retval EFI_SUCCESS            Compare the value success.\r
+\r
+**/\r
+EFI_STATUS\r
+CompareHiiValue (\r
+  IN  EFI_HII_VALUE   *Value1,\r
+  IN  EFI_HII_VALUE   *Value2,\r
+  OUT INTN            *Result,\r
+  IN  EFI_HII_HANDLE  HiiHandle OPTIONAL\r
+  )\r
+{\r
+  INT64   Temp64;\r
+  CHAR16  *Str1;\r
+  CHAR16  *Str2;\r
+  UINTN   Len;\r
+\r
+  if (Value1->Type >= EFI_IFR_TYPE_OTHER || Value2->Type >= EFI_IFR_TYPE_OTHER ) {\r
+    if (Value1->Type != EFI_IFR_TYPE_BUFFER && Value2->Type != EFI_IFR_TYPE_BUFFER) {\r
+      return EFI_UNSUPPORTED;\r
+    }\r
+  }\r
+\r
+  if (Value1->Type == EFI_IFR_TYPE_STRING || Value2->Type == EFI_IFR_TYPE_STRING ) {\r
+    if (Value1->Type != Value2->Type) {\r
+      //\r
+      // Both Operator should be type of String\r
+      //\r
+      return EFI_UNSUPPORTED;\r
+    }\r
+\r
+    if (Value1->Value.string == 0 || Value2->Value.string == 0) {\r
+      //\r
+      // StringId 0 is reserved\r
+      //\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    if (Value1->Value.string == Value2->Value.string) {\r
+      *Result = 0;\r
+      return EFI_SUCCESS;\r
+    }\r
+\r
+    Str1 = GetToken (Value1->Value.string, HiiHandle);\r
+    if (Str1 == NULL) {\r
+      //\r
+      // String not found\r
+      //\r
+      return EFI_NOT_FOUND;\r
+    }\r
+\r
+    Str2 = GetToken (Value2->Value.string, HiiHandle);\r
+    if (Str2 == NULL) {\r
+      FreePool (Str1);\r
+      return EFI_NOT_FOUND;\r
+    }\r
+\r
+    *Result = StrCmp (Str1, Str2);\r
+\r
+    FreePool (Str1);\r
+    FreePool (Str2);\r
+\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if (Value1->Type == EFI_IFR_TYPE_BUFFER || Value2->Type == EFI_IFR_TYPE_BUFFER ) {\r
+    if (Value1->Type != Value2->Type) {\r
+      //\r
+      // Both Operator should be type of Buffer.\r
+      //\r
+      return EFI_UNSUPPORTED;\r
+    }\r
+    Len = Value1->BufferLen > Value2->BufferLen ? Value2->BufferLen : Value1->BufferLen;\r
+    *Result = CompareMem (Value1->Buffer, Value2->Buffer, Len);\r
+    if ((*Result == 0) && (Value1->BufferLen != Value2->BufferLen))\r
+    {\r
+      //\r
+      // In this case, means base on samll number buffer, the data is same\r
+      // So which value has more data, which value is bigger.\r
+      //\r
+      *Result = Value1->BufferLen > Value2->BufferLen ? 1 : -1;\r
+    }\r
+    return EFI_SUCCESS;\r
+  }  \r
+\r
+  //\r
+  // Take remain types(integer, boolean, date/time) as integer\r
+  //\r
+  Temp64 = (INT64) (Value1->Value.u64 - Value2->Value.u64);\r
+  if (Temp64 > 0) {\r
+    *Result = 1;\r
+  } else if (Temp64 < 0) {\r
+    *Result = -1;\r
+  } else {\r
+    *Result = 0;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Search an Option of a Question by its value.\r
+\r
+  @param  Question               The Question\r
+  @param  OptionValue            Value for Option to be searched.\r
+\r
+  @retval Pointer                Pointer to the found Option.\r
+  @retval NULL                   Option not found.\r
+\r
+**/\r
+DISPLAY_QUESTION_OPTION *\r
+ValueToOption (\r
+  IN FORM_DISPLAY_ENGINE_STATEMENT   *Question,\r
+  IN EFI_HII_VALUE                   *OptionValue\r
+  )\r
+{\r
+  LIST_ENTRY               *Link;\r
+  DISPLAY_QUESTION_OPTION  *Option;\r
+  INTN                     Result;\r
+  EFI_HII_VALUE            Value;\r
+\r
+  Link = GetFirstNode (&Question->OptionListHead);\r
+  while (!IsNull (&Question->OptionListHead, Link)) {\r
+    Option = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);\r
+\r
+    ZeroMem (&Value, sizeof (EFI_HII_VALUE));\r
+    Value.Type = Option->OptionOpCode->Type;\r
+    CopyMem (&Value.Value, &Option->OptionOpCode->Value, Option->OptionOpCode->Header.Length - OFFSET_OF (EFI_IFR_ONE_OF_OPTION, Value));\r
+    \r
+    if ((CompareHiiValue (&Value, OptionValue, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) {\r
+      return Option;\r
+    }\r
+\r
+    Link = GetNextNode (&Question->OptionListHead, Link);\r
+  }\r
+\r
+  return NULL;\r
+}\r
+\r
+\r
+/**\r
+  Return data element in an Array by its Index.\r
+\r
+  @param  Array                  The data array.\r
+  @param  Type                   Type of the data in this array.\r
+  @param  Index                  Zero based index for data in this array.\r
+\r
+  @retval Value                  The data to be returned\r
+\r
+**/\r
+UINT64\r
+GetArrayData (\r
+  IN VOID                     *Array,\r
+  IN UINT8                    Type,\r
+  IN UINTN                    Index\r
+  )\r
+{\r
+  UINT64 Data;\r
+\r
+  ASSERT (Array != NULL);\r
+\r
+  Data = 0;\r
+  switch (Type) {\r
+  case EFI_IFR_TYPE_NUM_SIZE_8:\r
+    Data = (UINT64) *(((UINT8 *) Array) + Index);\r
+    break;\r
+\r
+  case EFI_IFR_TYPE_NUM_SIZE_16:\r
+    Data = (UINT64) *(((UINT16 *) Array) + Index);\r
+    break;\r
+\r
+  case EFI_IFR_TYPE_NUM_SIZE_32:\r
+    Data = (UINT64) *(((UINT32 *) Array) + Index);\r
+    break;\r
+\r
+  case EFI_IFR_TYPE_NUM_SIZE_64:\r
+    Data = (UINT64) *(((UINT64 *) Array) + Index);\r
+    break;\r
+\r
+  default:\r
+    break;\r
+  }\r
+\r
+  return Data;\r
+}\r
+\r
+\r
+/**\r
+  Set value of a data element in an Array by its Index.\r
+\r
+  @param  Array                  The data array.\r
+  @param  Type                   Type of the data in this array.\r
+  @param  Index                  Zero based index for data in this array.\r
+  @param  Value                  The value to be set.\r
+\r
+**/\r
+VOID\r
+SetArrayData (\r
+  IN VOID                     *Array,\r
+  IN UINT8                    Type,\r
+  IN UINTN                    Index,\r
+  IN UINT64                   Value\r
+  )\r
+{\r
+\r
+  ASSERT (Array != NULL);\r
+\r
+  switch (Type) {\r
+  case EFI_IFR_TYPE_NUM_SIZE_8:\r
+    *(((UINT8 *) Array) + Index) = (UINT8) Value;\r
+    break;\r
+\r
+  case EFI_IFR_TYPE_NUM_SIZE_16:\r
+    *(((UINT16 *) Array) + Index) = (UINT16) Value;\r
+    break;\r
+\r
+  case EFI_IFR_TYPE_NUM_SIZE_32:\r
+    *(((UINT32 *) Array) + Index) = (UINT32) Value;\r
+    break;\r
+\r
+  case EFI_IFR_TYPE_NUM_SIZE_64:\r
+    *(((UINT64 *) Array) + Index) = (UINT64) Value;\r
+    break;\r
+\r
+  default:\r
+    break;\r
+  }\r
+}\r
+\r
+/**\r
+  Check whether this value already in the array, if yes, return the index.\r
+\r
+  @param  Array                  The data array.\r
+  @param  Type                   Type of the data in this array.\r
+  @param  Value                  The value to be find.\r
+  @param  Index                  The index in the array which has same value with Value.\r
+  \r
+  @retval   TRUE Found the value in the array.\r
+  @retval   FALSE Not found the value.\r
+\r
+**/\r
+BOOLEAN \r
+FindArrayData (\r
+  IN VOID                     *Array,\r
+  IN UINT8                    Type,\r
+  IN UINT64                   Value,\r
+  OUT UINTN                   *Index OPTIONAL\r
+  )\r
+{\r
+  UINTN  Count;\r
+  UINT64 TmpValue;\r
+  UINT64 ValueComp;\r
+  \r
+  ASSERT (Array != NULL);\r
+\r
+  Count    = 0;\r
+  TmpValue = 0;\r
+\r
+  switch (Type) {\r
+  case EFI_IFR_TYPE_NUM_SIZE_8:\r
+    ValueComp = (UINT8) Value;\r
+    break;\r
+\r
+  case EFI_IFR_TYPE_NUM_SIZE_16:\r
+    ValueComp = (UINT16) Value;\r
+    break;\r
+\r
+  case EFI_IFR_TYPE_NUM_SIZE_32:\r
+    ValueComp = (UINT32) Value;\r
+    break;\r
+\r
+  case EFI_IFR_TYPE_NUM_SIZE_64:\r
+    ValueComp = (UINT64) Value;\r
+    break;\r
+\r
+  default:\r
+    ValueComp = 0;\r
+    break;\r
+  }\r
+\r
+  while ((TmpValue = GetArrayData (Array, Type, Count)) != 0) {\r
+    if (ValueComp == TmpValue) {\r
+      if (Index != NULL) {\r
+        *Index = Count;\r
+      }\r
+      return TRUE;\r
+    }\r
+\r
+    Count ++;\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  Print Question Value according to it's storage width and display attributes.\r
+\r
+  @param  Question               The Question to be printed.\r
+  @param  FormattedNumber        Buffer for output string.\r
+  @param  BufferSize             The FormattedNumber buffer size in bytes.\r
+\r
+  @retval EFI_SUCCESS            Print success.\r
+  @retval EFI_BUFFER_TOO_SMALL   Buffer size is not enough for formatted number.\r
+\r
+**/\r
+EFI_STATUS\r
+PrintFormattedNumber (\r
+  IN FORM_DISPLAY_ENGINE_STATEMENT   *Question,\r
+  IN OUT CHAR16               *FormattedNumber,\r
+  IN UINTN                    BufferSize\r
+  )\r
+{\r
+  INT64          Value;\r
+  CHAR16         *Format;\r
+  EFI_HII_VALUE  *QuestionValue;\r
+  EFI_IFR_NUMERIC *NumericOp;\r
+\r
+  if (BufferSize < (21 * sizeof (CHAR16))) {\r
+    return EFI_BUFFER_TOO_SMALL;\r
+  }\r
+\r
+  QuestionValue = &Question->CurrentValue;\r
+  NumericOp     = (EFI_IFR_NUMERIC *) Question->OpCode;\r
+\r
+  Value = (INT64) QuestionValue->Value.u64;\r
+  switch (NumericOp->Flags & EFI_IFR_DISPLAY) {\r
+  case EFI_IFR_DISPLAY_INT_DEC:\r
+    switch (QuestionValue->Type) {\r
+    case EFI_IFR_NUMERIC_SIZE_1:\r
+      Value = (INT64) ((INT8) QuestionValue->Value.u8);\r
+      break;\r
+\r
+    case EFI_IFR_NUMERIC_SIZE_2:\r
+      Value = (INT64) ((INT16) QuestionValue->Value.u16);\r
+      break;\r
+\r
+    case EFI_IFR_NUMERIC_SIZE_4:\r
+      Value = (INT64) ((INT32) QuestionValue->Value.u32);\r
+      break;\r
+\r
+    case EFI_IFR_NUMERIC_SIZE_8:\r
+    default:\r
+      break;\r
+    }\r
+\r
+    if (Value < 0) {\r
+      Value = -Value;\r
+      Format = L"-%ld";\r
+    } else {\r
+      Format = L"%ld";\r
+    }\r
+    break;\r
+\r
+  case EFI_IFR_DISPLAY_UINT_DEC:\r
+    Format = L"%ld";\r
+    break;\r
+\r
+  case EFI_IFR_DISPLAY_UINT_HEX:\r
+    Format = L"%lx";\r
+    break;\r
+\r
+  default:\r
+    return EFI_UNSUPPORTED;\r
+    break;\r
+  }\r
+\r
+  UnicodeSPrint (FormattedNumber, BufferSize, Format, Value);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Draw a pop up windows based on the dimension, number of lines and\r
+  strings specified.\r
+\r
+  @param RequestedWidth  The width of the pop-up.\r
+  @param NumberOfLines   The number of lines.\r
+  @param Marker          The variable argument list for the list of string to be printed.\r
+\r
+**/\r
+VOID\r
+CreateSharedPopUp (\r
+  IN  UINTN                       RequestedWidth,\r
+  IN  UINTN                       NumberOfLines,\r
+  IN  VA_LIST                     Marker\r
+  )\r
+{\r
+  UINTN   Index;\r
+  UINTN   Count;\r
+  CHAR16  Character;\r
+  UINTN   Start;\r
+  UINTN   End;\r
+  UINTN   Top;\r
+  UINTN   Bottom;\r
+  CHAR16  *String;\r
+  UINTN   DimensionsWidth;\r
+  UINTN   DimensionsHeight;\r
+\r
+  DimensionsWidth   = gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn;\r
+  DimensionsHeight  = gStatementDimensions.BottomRow - gStatementDimensions.TopRow;\r
+\r
+  gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ());\r
+\r
+  if ((RequestedWidth + 2) > DimensionsWidth) {\r
+    RequestedWidth = DimensionsWidth - 2;\r
+  }\r
+\r
+  //\r
+  // Subtract the PopUp width from total Columns, allow for one space extra on\r
+  // each end plus a border.\r
+  //\r
+  Start     = (DimensionsWidth - RequestedWidth - 2) / 2 + gStatementDimensions.LeftColumn + 1;\r
+  End       = Start + RequestedWidth + 1;\r
+\r
+  Top       = ((DimensionsHeight - NumberOfLines - 2) / 2) + gStatementDimensions.TopRow - 1;\r
+  Bottom    = Top + NumberOfLines + 2;\r
+\r
+  Character = BOXDRAW_DOWN_RIGHT;\r
+  PrintCharAt (Start, Top, Character);\r
+  Character = BOXDRAW_HORIZONTAL;\r
+  for (Index = Start; Index + 2 < End; Index++) {\r
+    PrintCharAt ((UINTN)-1, (UINTN)-1, Character);\r
+  }\r
+\r
+  Character = BOXDRAW_DOWN_LEFT;\r
+  PrintCharAt ((UINTN)-1, (UINTN)-1, Character);\r
+  Character = BOXDRAW_VERTICAL;\r
+\r
+  Count = 0;\r
+  for (Index = Top; Index + 2 < Bottom; Index++, Count++) {\r
+    String = VA_ARG (Marker, CHAR16*);\r
+\r
+    //\r
+    // This will clear the background of the line - we never know who might have been\r
+    // here before us.  This differs from the next clear in that it used the non-reverse\r
+    // video for normal printing.\r
+    //\r
+    if (GetStringWidth (String) / 2 > 1) {\r
+      ClearLines (Start, End, Index + 1, Index + 1, GetPopupColor ());\r
+    }\r
+\r
+    //\r
+    // Passing in a space results in the assumption that this is where typing will occur\r
+    //\r
+    if (String[0] == L' ') {\r
+      ClearLines (Start + 1, End - 1, Index + 1, Index + 1, GetPopupInverseColor ());\r
+    }\r
+\r
+    //\r
+    // Passing in a NULL results in a blank space\r
+    //\r
+    if (String[0] == CHAR_NULL) {\r
+      ClearLines (Start, End, Index + 1, Index + 1, GetPopupColor ());\r
+    }\r
+\r
+    PrintStringAt (\r
+      ((DimensionsWidth - GetStringWidth (String) / 2) / 2) + gStatementDimensions.LeftColumn + 1,\r
+      Index + 1,\r
+      String\r
+      );\r
+    gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ());\r
+    PrintCharAt (Start, Index + 1, Character);\r
+    PrintCharAt (End - 1, Index + 1, Character);\r
+  }\r
+\r
+  Character = BOXDRAW_UP_RIGHT;\r
+  PrintCharAt (Start, Bottom - 1, Character);\r
+  Character = BOXDRAW_HORIZONTAL;\r
+  for (Index = Start; Index + 2 < End; Index++) {\r
+    PrintCharAt ((UINTN)-1, (UINTN)-1, Character);\r
+  }\r
+\r
+  Character = BOXDRAW_UP_LEFT;\r
+  PrintCharAt ((UINTN)-1, (UINTN)-1, Character);\r
+}\r
+\r
+/**\r
+  Draw a pop up windows based on the dimension, number of lines and\r
+  strings specified.\r
+\r
+  @param RequestedWidth  The width of the pop-up.\r
+  @param NumberOfLines   The number of lines.\r
+  @param ...             A series of text strings that displayed in the pop-up.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+CreateMultiStringPopUp (\r
+  IN  UINTN                       RequestedWidth,\r
+  IN  UINTN                       NumberOfLines,\r
+  ...\r
+  )\r
+{\r
+  VA_LIST Marker;\r
+\r
+  VA_START (Marker, NumberOfLines);\r
+\r
+  CreateSharedPopUp (RequestedWidth, NumberOfLines, Marker);\r
+\r
+  VA_END (Marker);\r
+}\r
+\r
+/**\r
+  Process validate for one question.\r
+\r
+  @param  Question               The question need to be validate.\r
+\r
+  @retval EFI_SUCCESS            Question Option process success.\r
+  @retval EFI_INVALID_PARAMETER  Question Option process fail.\r
+\r
+**/\r
+EFI_STATUS \r
+ValidateQuestion (\r
+  IN FORM_DISPLAY_ENGINE_STATEMENT   *Question\r
+  )\r
+{\r
+  CHAR16                          *ErrorInfo;\r
+  EFI_INPUT_KEY                   Key;\r
+  EFI_STATUS                      Status;\r
+  STATEMENT_ERROR_INFO            RetInfo;\r
+  UINT32                          RetVal;\r
+\r
+  if (Question->ValidateQuestion == NULL) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  Status = EFI_SUCCESS; \r
+  RetVal = Question->ValidateQuestion(gFormData, Question, &gUserInput->InputValue, &RetInfo);\r
\r
+  switch (RetVal) {\r
+  case INCOSISTENT_IF_TRUE:\r
+    //\r
+    // Condition meet, show up error message\r
+    //\r
+    ASSERT (RetInfo.StringId != 0);\r
+    ErrorInfo = GetToken (RetInfo.StringId, gFormData->HiiHandle);\r
+    do {\r
+      CreateDialog (&Key, gEmptyString, ErrorInfo, gPressEnter, gEmptyString, NULL);\r
+    } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+    FreePool (ErrorInfo);\r
+\r
+    Status = EFI_INVALID_PARAMETER;\r
+  break;\r
+\r
+  default:\r
+    break;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Display error message for invalid password.\r
+\r
+**/\r
+VOID\r
+PasswordInvalid (\r
+  VOID\r
+  )\r
+{\r
+  EFI_INPUT_KEY  Key;\r
+\r
+  //\r
+  // Invalid password, prompt error message\r
+  //\r
+  do {\r
+    CreateDialog (&Key, gEmptyString, gPassowordInvalid, gPressEnter, gEmptyString, NULL);\r
+  } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+}\r
+\r
+/**\r
+  Process password op code.\r
+\r
+  @param  MenuOption             The menu for current password op code.\r
+\r
+  @retval EFI_SUCCESS            Question Option process success.\r
+  @retval Other                  Question Option process fail.\r
+\r
+**/\r
+EFI_STATUS\r
+PasswordProcess (\r
+  IN  UI_MENU_OPTION              *MenuOption\r
+  )\r
+{\r
+  CHAR16                          *StringPtr;\r
+  CHAR16                          *TempString;\r
+  UINTN                           Maximum;\r
+  EFI_STATUS                      Status;\r
+  EFI_IFR_PASSWORD                *PasswordInfo;\r
+  FORM_DISPLAY_ENGINE_STATEMENT   *Question;\r
+  EFI_INPUT_KEY                   Key;\r
+\r
+  Question     = MenuOption->ThisTag;\r
+  PasswordInfo = (EFI_IFR_PASSWORD *) Question->OpCode;\r
+  Maximum      = PasswordInfo->MaxSize;\r
+  Status       = EFI_SUCCESS;\r
+\r
+  StringPtr = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16));\r
+  ASSERT (StringPtr);\r
+  \r
+  //\r
+  // Use a NULL password to test whether old password is required\r
+  //\r
+  *StringPtr = 0;\r
+  Status = Question->PasswordCheck (gFormData, Question, StringPtr);\r
+  if (Status == EFI_NOT_AVAILABLE_YET || Status == EFI_UNSUPPORTED) {\r
+    //\r
+    // Password can't be set now. \r
+    //\r
+    FreePool (StringPtr);\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // Old password exist, ask user for the old password\r
+    //\r
+    Status = ReadString (MenuOption, gPromptForPassword, StringPtr);\r
+    if (EFI_ERROR (Status)) {\r
+      FreePool (StringPtr);\r
+      return Status;\r
+    }\r
+\r
+    //\r
+    // Check user input old password\r
+    //\r
+    Status = Question->PasswordCheck (gFormData, Question, StringPtr);\r
+    if (EFI_ERROR (Status)) {\r
+      if (Status == EFI_NOT_READY) {\r
+        //\r
+        // Typed in old password incorrect\r
+        //\r
+        PasswordInvalid ();\r
+      } else {\r
+        Status = EFI_SUCCESS;\r
+      }\r
+\r
+      FreePool (StringPtr);\r
+      return Status;\r
+    }\r
+  }\r
+  \r
+  //\r
+  // Ask for new password\r
+  //\r
+  ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16));\r
+  Status = ReadString (MenuOption, gPromptForNewPassword, StringPtr);\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // Reset state machine for password\r
+    //\r
+    Question->PasswordCheck (gFormData, Question, NULL);\r
+    FreePool (StringPtr);\r
+    return Status;\r
+  }\r
+  \r
+  //\r
+  // Confirm new password\r
+  //\r
+  TempString = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16));\r
+  ASSERT (TempString);\r
+  Status = ReadString (MenuOption, gConfirmPassword, TempString);\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // Reset state machine for password\r
+    //\r
+    Question->PasswordCheck (gFormData, Question, NULL);\r
+    FreePool (StringPtr);\r
+    FreePool (TempString);\r
+    return Status;\r
+  }\r
+  \r
+  //\r
+  // Compare two typed-in new passwords\r
+  //\r
+  if (StrCmp (StringPtr, TempString) == 0) {     \r
+    gUserInput->InputValue.Buffer = AllocateCopyPool (Question->CurrentValue.BufferLen, StringPtr);\r
+    gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen;\r
+    gUserInput->InputValue.Type = Question->CurrentValue.Type;\r
+    gUserInput->InputValue.Value.string = HiiSetString(gFormData->HiiHandle, gUserInput->InputValue.Value.string, StringPtr, NULL);\r
+    FreePool (StringPtr); \r
+\r
+    Status = ValidateQuestion (Question);\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      //\r
+      // Reset state machine for password\r
+      //\r
+      Question->PasswordCheck (gFormData, Question, NULL);\r
+    }\r
+\r
+    return Status;\r
+  } else {\r
+    //\r
+    // Reset state machine for password\r
+    //\r
+    Question->PasswordCheck (gFormData, Question, NULL);\r
+  \r
+    //\r
+    // Two password mismatch, prompt error message\r
+    //\r
+    do {\r
+      CreateDialog (&Key, gEmptyString, gConfirmError, gPressEnter, gEmptyString, NULL);\r
+    } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+\r
+    Status = EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  FreePool (TempString);\r
+  FreePool (StringPtr);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Process a Question's Option (whether selected or un-selected).\r
+\r
+  @param  MenuOption             The MenuOption for this Question.\r
+  @param  Selected               TRUE: if Question is selected.\r
+  @param  OptionString           Pointer of the Option String to be displayed.\r
+  @param  SkipErrorValue         Whether need to return when value without option for it.\r
+\r
+  @retval EFI_SUCCESS            Question Option process success.\r
+  @retval Other                  Question Option process fail.\r
+\r
+**/\r
+EFI_STATUS\r
+ProcessOptions (\r
+  IN  UI_MENU_OPTION              *MenuOption,\r
+  IN  BOOLEAN                     Selected,\r
+  OUT CHAR16                      **OptionString,\r
+  IN  BOOLEAN                     SkipErrorValue\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  CHAR16                          *StringPtr;\r
+  UINTN                           Index;\r
+  FORM_DISPLAY_ENGINE_STATEMENT   *Question;\r
+  CHAR16                          FormattedNumber[21];\r
+  UINT16                          Number;\r
+  CHAR16                          Character[2];\r
+  EFI_INPUT_KEY                   Key;\r
+  UINTN                           BufferSize;\r
+  DISPLAY_QUESTION_OPTION         *OneOfOption;\r
+  LIST_ENTRY                      *Link;\r
+  EFI_HII_VALUE                   HiiValue;\r
+  EFI_HII_VALUE                   *QuestionValue;\r
+  DISPLAY_QUESTION_OPTION         *Option;\r
+  UINTN                           Index2;\r
+  UINT8                           *ValueArray;\r
+  UINT8                           ValueType;\r
+  EFI_STRING_ID                   StringId;\r
+  EFI_IFR_ORDERED_LIST            *OrderList;\r
+  BOOLEAN                         ValueInvalid;\r
+\r
+  Status        = EFI_SUCCESS;\r
+\r
+  StringPtr     = NULL;\r
+  Character[1]  = L'\0';\r
+  *OptionString = NULL;\r
+  StringId      = 0;\r
+  ValueInvalid  = FALSE;\r
+\r
+  ZeroMem (FormattedNumber, 21 * sizeof (CHAR16));\r
+  BufferSize = (gOptionBlockWidth + 1) * 2 * gStatementDimensions.BottomRow;\r
+\r
+  Question = MenuOption->ThisTag;\r
+  QuestionValue = &Question->CurrentValue;\r
+\r
+  switch (Question->OpCode->OpCode) {\r
+  case EFI_IFR_ORDERED_LIST_OP:\r
+\r
+    //\r
+    // Check whether there are Options of this OrderedList\r
+    //\r
+    if (IsListEmpty (&Question->OptionListHead)) {\r
+      break;\r
+    }\r
+\r
+    OrderList = (EFI_IFR_ORDERED_LIST *) Question->OpCode;\r
+\r
+    Link = GetFirstNode (&Question->OptionListHead);\r
+    OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);\r
+\r
+    ValueType =  OneOfOption->OptionOpCode->Type;\r
+    ValueArray = Question->CurrentValue.Buffer;\r
+\r
+    if (Selected) {\r
+      //\r
+      // Go ask for input\r
+      //\r
+      Status = GetSelectionInputPopUp (MenuOption);\r
+    } else {\r
+      //\r
+      // We now know how many strings we will have, so we can allocate the\r
+      // space required for the array or strings.\r
+      //\r
+      *OptionString = AllocateZeroPool (OrderList->MaxContainers * BufferSize);\r
+      ASSERT (*OptionString);\r
+\r
+      HiiValue.Type = ValueType;\r
+      HiiValue.Value.u64 = 0;\r
+      for (Index = 0; Index < OrderList->MaxContainers; Index++) {\r
+        HiiValue.Value.u64 = GetArrayData (ValueArray, ValueType, Index);\r
+        if (HiiValue.Value.u64 == 0) {\r
+          //\r
+          // Values for the options in ordered lists should never be a 0\r
+          //\r
+          break;\r
+        }\r
+\r
+        OneOfOption = ValueToOption (Question, &HiiValue);\r
+        if (OneOfOption == NULL) {\r
+          if (SkipErrorValue) {\r
+            //\r
+            // Just try to get the option string, skip the value which not has option.\r
+            //\r
+            continue;\r
+          }\r
+\r
+          //\r
+          // Show error message\r
+          //\r
+          do {\r
+            CreateDialog (&Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString, NULL);\r
+          } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+\r
+          //\r
+          // The initial value of the orderedlist is invalid, force to be valid value\r
+          // Exit current DisplayForm with new value.\r
+          //\r
+          gUserInput->SelectedStatement = Question;\r
+          \r
+          ValueArray = AllocateZeroPool (Question->CurrentValue.BufferLen);\r
+          ASSERT (ValueArray != NULL);\r
+          gUserInput->InputValue.Buffer    = ValueArray;\r
+          gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen;\r
+          gUserInput->InputValue.Type      = Question->CurrentValue.Type;\r
+          \r
+          Link = GetFirstNode (&Question->OptionListHead);\r
+          Index2 = 0;\r
+          while (!IsNull (&Question->OptionListHead, Link) && Index2 < OrderList->MaxContainers) {\r
+            Option = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);\r
+            Link = GetNextNode (&Question->OptionListHead, Link);\r
+            SetArrayData (ValueArray, ValueType, Index2, Option->OptionOpCode->Value.u64);\r
+            Index2++;\r
+          }\r
+          SetArrayData (ValueArray, ValueType, Index2, 0);\r
+\r
+          FreePool (*OptionString);\r
+          *OptionString = NULL;\r
+          return EFI_NOT_FOUND;\r
+        }\r
+\r
+        Character[0] = LEFT_ONEOF_DELIMITER;\r
+        NewStrCat (OptionString[0], Character);\r
+        StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle);\r
+        ASSERT (StringPtr != NULL);\r
+        NewStrCat (OptionString[0], StringPtr);\r
+        Character[0] = RIGHT_ONEOF_DELIMITER;\r
+        NewStrCat (OptionString[0], Character);\r
+        Character[0] = CHAR_CARRIAGE_RETURN;\r
+        NewStrCat (OptionString[0], Character);\r
+        FreePool (StringPtr);\r
+      }\r
+\r
+      //\r
+      // If valid option more than the max container, skip these options.\r
+      //\r
+      if (Index >= OrderList->MaxContainers) {\r
+        break;\r
+      }\r
+\r
+      //\r
+      // Search the other options, try to find the one not in the container.\r
+      //\r
+      Link = GetFirstNode (&Question->OptionListHead);\r
+      while (!IsNull (&Question->OptionListHead, Link)) {\r
+        OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);\r
+        Link = GetNextNode (&Question->OptionListHead, Link);\r
+\r
+        if (FindArrayData (ValueArray, ValueType, OneOfOption->OptionOpCode->Value.u64, NULL)) {\r
+          continue;\r
+        }\r
+\r
+        if (SkipErrorValue) {\r
+          //\r
+          // Not report error, just get the correct option string info.\r
+          //\r
+          Character[0] = LEFT_ONEOF_DELIMITER;\r
+          NewStrCat (OptionString[0], Character);\r
+          StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle);\r
+          ASSERT (StringPtr != NULL);\r
+          NewStrCat (OptionString[0], StringPtr);\r
+          Character[0] = RIGHT_ONEOF_DELIMITER;\r
+          NewStrCat (OptionString[0], Character);\r
+          Character[0] = CHAR_CARRIAGE_RETURN;\r
+          NewStrCat (OptionString[0], Character);\r
+          FreePool (StringPtr);\r
+\r
+          continue;\r
+        }\r
+\r
+        if (!ValueInvalid) {\r
+          ValueInvalid = TRUE;\r
+          //\r
+          // Show error message\r
+          //\r
+          do {\r
+            CreateDialog (&Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString, NULL);\r
+          } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+\r
+          //\r
+          // The initial value of the orderedlist is invalid, force to be valid value\r
+          // Exit current DisplayForm with new value.\r
+          //\r
+          gUserInput->SelectedStatement = Question;\r
+          \r
+          ValueArray = AllocateCopyPool (Question->CurrentValue.BufferLen, Question->CurrentValue.Buffer);\r
+          ASSERT (ValueArray != NULL);\r
+          gUserInput->InputValue.Buffer    = ValueArray;\r
+          gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen;\r
+          gUserInput->InputValue.Type      = Question->CurrentValue.Type;\r
+        }\r
+       \r
+        SetArrayData (ValueArray, ValueType, Index++, OneOfOption->OptionOpCode->Value.u64);\r
+      }\r
+\r
+      if (ValueInvalid) {\r
+        FreePool (*OptionString);\r
+        *OptionString = NULL;\r
+        return EFI_NOT_FOUND;\r
+      }\r
+    }\r
+    break;\r
+\r
+  case EFI_IFR_ONE_OF_OP:\r
+    //\r
+    // Check whether there are Options of this OneOf\r
+    //\r
+    if (IsListEmpty (&Question->OptionListHead)) {\r
+      break;\r
+    }\r
+    if (Selected) {\r
+      //\r
+      // Go ask for input\r
+      //\r
+      Status = GetSelectionInputPopUp (MenuOption);\r
+    } else {\r
+      *OptionString = AllocateZeroPool (BufferSize);\r
+      ASSERT (*OptionString);\r
+\r
+      OneOfOption = ValueToOption (Question, QuestionValue);\r
+      if (OneOfOption == NULL) {\r
+        if (SkipErrorValue) {\r
+          //\r
+          // Not report error, just get the correct option string info.\r
+          //          \r
+          Link = GetFirstNode (&Question->OptionListHead);\r
+          OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);\r
+        } else {\r
+          //\r
+          // Show error message\r
+          //\r
+          do {\r
+            CreateDialog (&Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString, NULL);\r
+          } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+\r
+          //\r
+          // Force the Question value to be valid\r
+          // Exit current DisplayForm with new value.\r
+          //\r
+          Link = GetFirstNode (&Question->OptionListHead);\r
+          Option = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);\r
+\r
+          CopyMem (&gUserInput->InputValue.Value, &Option->OptionOpCode->Value, sizeof (EFI_IFR_TYPE_VALUE));\r
+          gUserInput->InputValue.Type = Option->OptionOpCode->Type;\r
+          gUserInput->SelectedStatement = Question;\r
+\r
+          FreePool (*OptionString);\r
+          *OptionString = NULL;\r
+          return EFI_NOT_FOUND;\r
+        }\r
+      }\r
+\r
+      Character[0] = LEFT_ONEOF_DELIMITER;\r
+      NewStrCat (OptionString[0], Character);\r
+      StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle);\r
+      ASSERT (StringPtr != NULL);\r
+      NewStrCat (OptionString[0], StringPtr);\r
+      Character[0] = RIGHT_ONEOF_DELIMITER;\r
+      NewStrCat (OptionString[0], Character);\r
+\r
+      FreePool (StringPtr);\r
+    }\r
+    break;\r
+\r
+  case EFI_IFR_CHECKBOX_OP:\r
+    if (Selected) {\r
+      //\r
+      // Since this is a BOOLEAN operation, flip it upon selection\r
+      //\r
+      gUserInput->InputValue.Type    = QuestionValue->Type;\r
+      gUserInput->InputValue.Value.b = (BOOLEAN) (QuestionValue->Value.b ? FALSE : TRUE);\r
+\r
+      //\r
+      // Perform inconsistent check\r
+      //\r
+      return ValidateQuestion (Question);\r
+    } else {    \r
+      *OptionString = AllocateZeroPool (BufferSize);\r
+      ASSERT (*OptionString);\r
+\r
+      *OptionString[0] = LEFT_CHECKBOX_DELIMITER;\r
+\r
+      if (QuestionValue->Value.b) {\r
+        *(OptionString[0] + 1) = CHECK_ON;\r
+      } else {\r
+        *(OptionString[0] + 1) = CHECK_OFF;\r
+      }\r
+      *(OptionString[0] + 2) = RIGHT_CHECKBOX_DELIMITER;\r
+    }\r
+    break;\r
+\r
+  case EFI_IFR_NUMERIC_OP:\r
+    if (Selected) {\r
+      //\r
+      // Go ask for input\r
+      //\r
+      Status = GetNumericInput (MenuOption);\r
+    } else {\r
+      *OptionString = AllocateZeroPool (BufferSize);\r
+      ASSERT (*OptionString);\r
+\r
+      *OptionString[0] = LEFT_NUMERIC_DELIMITER;\r
+\r
+      //\r
+      // Formatted print\r
+      //\r
+      PrintFormattedNumber (Question, FormattedNumber, 21 * sizeof (CHAR16));\r
+      Number = (UINT16) GetStringWidth (FormattedNumber);\r
+      CopyMem (OptionString[0] + 1, FormattedNumber, Number);\r
+\r
+      *(OptionString[0] + Number / 2) = RIGHT_NUMERIC_DELIMITER;\r
+    }\r
+    break;\r
+\r
+  case EFI_IFR_DATE_OP:\r
+    if (Selected) {\r
+      //\r
+      // This is similar to numerics\r
+      //\r
+      Status = GetNumericInput (MenuOption);\r
+    } else {\r
+      *OptionString = AllocateZeroPool (BufferSize);\r
+      ASSERT (*OptionString);\r
+\r
+      switch (MenuOption->Sequence) {\r
+      case 0:\r
+        *OptionString[0] = LEFT_NUMERIC_DELIMITER;\r
+        UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.date.Month);\r
+        *(OptionString[0] + 3) = DATE_SEPARATOR;\r
+        break;\r
+\r
+      case 1:\r
+        SetUnicodeMem (OptionString[0], 4, L' ');\r
+        UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.date.Day);\r
+        *(OptionString[0] + 6) = DATE_SEPARATOR;\r
+        break;\r
+\r
+      case 2:\r
+        SetUnicodeMem (OptionString[0], 7, L' ');\r
+        UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"%04d", QuestionValue->Value.date.Year);\r
+        *(OptionString[0] + 11) = RIGHT_NUMERIC_DELIMITER;\r
+        break;\r
+      }\r
+    }\r
+    break;\r
+\r
+  case EFI_IFR_TIME_OP:\r
+    if (Selected) {\r
+      //\r
+      // This is similar to numerics\r
+      //\r
+      Status = GetNumericInput (MenuOption);\r
+    } else {\r
+      *OptionString = AllocateZeroPool (BufferSize);\r
+      ASSERT (*OptionString);\r
+\r
+      switch (MenuOption->Sequence) {\r
+      case 0:\r
+        *OptionString[0] = LEFT_NUMERIC_DELIMITER;\r
+        UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Hour);\r
+        *(OptionString[0] + 3) = TIME_SEPARATOR;\r
+        break;\r
+\r
+      case 1:\r
+        SetUnicodeMem (OptionString[0], 4, L' ');\r
+        UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Minute);\r
+        *(OptionString[0] + 6) = TIME_SEPARATOR;\r
+        break;\r
+\r
+      case 2:\r
+        SetUnicodeMem (OptionString[0], 7, L' ');\r
+        UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Second);\r
+        *(OptionString[0] + 9) = RIGHT_NUMERIC_DELIMITER;\r
+        break;\r
+      }\r
+    }\r
+    break;\r
+\r
+  case EFI_IFR_STRING_OP:\r
+    if (Selected) {\r
+      StringPtr = AllocateZeroPool (Question->CurrentValue.BufferLen + sizeof (CHAR16));\r
+      ASSERT (StringPtr);\r
+      CopyMem(StringPtr, Question->CurrentValue.Buffer, Question->CurrentValue.BufferLen);\r
+\r
+      Status = ReadString (MenuOption, gPromptForData, StringPtr);\r
+      if (EFI_ERROR (Status)) {\r
+        FreePool (StringPtr);\r
+        return Status;\r
+      }\r
+      \r
+      gUserInput->InputValue.Buffer = AllocateCopyPool (Question->CurrentValue.BufferLen, StringPtr);\r
+      gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen;\r
+      gUserInput->InputValue.Type = Question->CurrentValue.Type;\r
+      gUserInput->InputValue.Value.string = HiiSetString(gFormData->HiiHandle, gUserInput->InputValue.Value.string, StringPtr, NULL);\r
+      FreePool (StringPtr);\r
+      return ValidateQuestion (Question);\r
+    } else {\r
+      *OptionString = AllocateZeroPool (BufferSize);\r
+      ASSERT (*OptionString);\r
+\r
+      if (((CHAR16 *) Question->CurrentValue.Buffer)[0] == 0x0000) {\r
+        *(OptionString[0]) = '_';\r
+      } else {\r
+        if (Question->CurrentValue.BufferLen < BufferSize) {\r
+          BufferSize = Question->CurrentValue.BufferLen;\r
+        }\r
+        CopyMem (OptionString[0], (CHAR16 *) Question->CurrentValue.Buffer, BufferSize);\r
+      }\r
+    }\r
+    break;\r
+\r
+  case EFI_IFR_PASSWORD_OP:\r
+    if (Selected) {\r
+      Status = PasswordProcess (MenuOption);\r
+    }\r
+    break;\r
+\r
+  default:\r
+    break;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Process the help string: Split StringPtr to several lines of strings stored in\r
+  FormattedString and the glyph width of each line cannot exceed gHelpBlockWidth.\r
+\r
+  @param  StringPtr              The entire help string.\r
+  @param  FormattedString        The oupput formatted string.\r
+  @param  EachLineWidth          The max string length of each line in the formatted string.\r
+  @param  RowCount               TRUE: if Question is selected.\r
+\r
+**/\r
+UINTN\r
+ProcessHelpString (\r
+  IN  CHAR16  *StringPtr,\r
+  OUT CHAR16  **FormattedString,\r
+  OUT UINT16  *EachLineWidth,\r
+  IN  UINTN   RowCount\r
+  )\r
+{\r
+  UINTN   Index;\r
+  CHAR16  *OutputString;\r
+  UINTN   TotalRowNum;\r
+  UINTN   CheckedNum;\r
+  UINT16  GlyphWidth;\r
+  UINT16  LineWidth;\r
+  UINT16  MaxStringLen;\r
+  UINT16  StringLen;\r
+\r
+  TotalRowNum    = 0;\r
+  CheckedNum     = 0;\r
+  GlyphWidth     = 1;\r
+  Index          = 0;\r
+  MaxStringLen   = 0;\r
+  StringLen      = 0;\r
+\r
+  //\r
+  // Set default help string width.\r
+  //\r
+  LineWidth      = (UINT16) (gHelpBlockWidth - 1);\r
+\r
+  //\r
+  // Get row number of the String.\r
+  //\r
+  while ((StringLen = GetLineByWidth (StringPtr, LineWidth, &GlyphWidth, &Index, &OutputString)) != 0) {\r
+    if (StringLen > MaxStringLen) {\r
+      MaxStringLen = StringLen;\r
+    }\r
+\r
+    TotalRowNum ++;\r
+    FreePool (OutputString);\r
+  }\r
+  *EachLineWidth = MaxStringLen;\r
+\r
+  *FormattedString = AllocateZeroPool (TotalRowNum * MaxStringLen * sizeof (CHAR16));\r
+  ASSERT (*FormattedString != NULL);\r
+\r
+  //\r
+  // Generate formatted help string array.\r
+  //\r
+  GlyphWidth  = 1;\r
+  Index       = 0;\r
+  while((StringLen = GetLineByWidth (StringPtr, LineWidth, &GlyphWidth, &Index, &OutputString)) != 0) {\r
+    CopyMem (*FormattedString + CheckedNum * MaxStringLen, OutputString, StringLen * sizeof (CHAR16));\r
+    CheckedNum ++;\r
+    FreePool (OutputString);\r
+  }\r
+\r
+  return TotalRowNum; \r
+}\r
index cd29e294385ccc5adf1d58b84ed9bda1317f5594..44dae1ba03c76f77d79fdf3d7da0ed31e97910f2 100644 (file)
@@ -787,7 +787,7 @@ FORM_BROWSER_FORM *
 IdToForm (\r
   IN FORM_BROWSER_FORMSET  *FormSet,\r
   IN UINT16                FormId\r
-)\r
+  )\r
 {\r
   LIST_ENTRY         *Link;\r
   FORM_BROWSER_FORM  *Form;\r
@@ -2105,7 +2105,7 @@ GetQuestionValueFromForm (
   //\r
   FormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET));\r
   ASSERT (FormSet != NULL);\r
-  Status = InitializeFormSet(HiiHandle, FormSetGuid, FormSet, FALSE);\r
+  Status = InitializeFormSet(HiiHandle, FormSetGuid, FormSet);\r
   if (EFI_ERROR (Status)) {\r
     GetTheVal = FALSE;\r
     goto Done;\r
@@ -2800,7 +2800,7 @@ EvaluateExpression (
             for (Index = 0; Index < OpCode->ValueWidth; Index ++, TempBuffer --) {\r
               StrPtr += UnicodeValueToString (StrPtr, PREFIX_ZERO | RADIX_HEX, *TempBuffer, 2);\r
             }\r
-            Status = SetValueByName (OpCode->VarStorage, OpCode->ValueName, NameValue, GetSetValueWithEditBuffer);\r
+            Status = SetValueByName (OpCode->VarStorage, OpCode->ValueName, NameValue, GetSetValueWithEditBuffer, NULL);\r
             FreePool (NameValue);\r
             if (!EFI_ERROR (Status)) {\r
               Data1.Value.b = TRUE;\r
diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Expression.h b/MdeModulePkg/Universal/SetupBrowserDxe/Expression.h
new file mode 100644 (file)
index 0000000..5660a99
--- /dev/null
@@ -0,0 +1,265 @@
+/** @file\r
+Private structure, MACRO and function definitions for User Interface related functionalities.\r
+\r
+Copyright (c) 2004 - 2013, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _EXPRESSION_H_\r
+#define _EXPRESSION_H_\r
+\r
+/**\r
+  Get the expression list count.\r
+  \r
+  @param  Level                  Which type this expression belong to. Form, \r
+                                 statement or option?\r
+\r
+  @retval >=0                    The expression count\r
+  @retval -1                     Input parameter error.\r
+\r
+**/\r
+INTN \r
+GetConditionalExpressionCount (\r
+  IN EXPRESS_LEVEL       Level\r
+  );\r
+\r
+/**\r
+  Reset stack pointer to begin of the stack.\r
+\r
+**/\r
+VOID\r
+ResetCurrentExpressionStack (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Reset stack pointer to begin of the stack.\r
+\r
+**/\r
+VOID\r
+ResetMapExpressionListStack (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Reset stack pointer to begin of the stack.\r
+\r
+**/\r
+VOID\r
+ResetScopeStack (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Push an Operand onto the Stack\r
+\r
+  @param  Operand                Operand to push.\r
+\r
+  @retval EFI_SUCCESS            The value was pushed onto the stack.\r
+  @retval EFI_OUT_OF_RESOURCES   There is not enough system memory to grow the\r
+                                 stack.\r
+\r
+**/\r
+EFI_STATUS\r
+PushScope (\r
+  IN UINT8   Operand\r
+  );\r
+\r
+/**\r
+  Get the expression Buffer pointer.\r
+  \r
+  @param  Level                  Which type this expression belong to. Form, \r
+                                 statement or option?\r
+\r
+  @retval  The start pointer of the expression buffer or NULL.\r
+\r
+**/\r
+FORM_EXPRESSION **\r
+GetConditionalExpressionList (\r
+  IN EXPRESS_LEVEL       Level\r
+  );\r
+\r
+/**\r
+  Pop an Operand from the Stack\r
+\r
+  @param  Operand                Operand to pop.\r
+\r
+  @retval EFI_SUCCESS            The value was pushed onto the stack.\r
+  @retval EFI_OUT_OF_RESOURCES   There is not enough system memory to grow the\r
+                                 stack.\r
+\r
+**/\r
+EFI_STATUS\r
+PopScope (\r
+  OUT UINT8     *Operand\r
+  );\r
+\r
+/**\r
+  Push the list of map expression onto the Stack\r
+\r
+  @param  Pointer                Pointer to the list of map expression to be pushed.\r
+\r
+  @retval EFI_SUCCESS            The value was pushed onto the stack.\r
+  @retval EFI_OUT_OF_RESOURCES   There is not enough system memory to grow the stack.\r
+\r
+**/\r
+EFI_STATUS\r
+PushMapExpressionList (\r
+  IN VOID  *Pointer\r
+  );\r
+\r
+/**\r
+  Push current expression onto the Stack\r
+\r
+  @param  Pointer                Pointer to current expression.\r
+\r
+  @retval EFI_SUCCESS            The value was pushed onto the stack.\r
+  @retval EFI_OUT_OF_RESOURCES   There is not enough system memory to grow the stack.\r
+\r
+**/\r
+EFI_STATUS\r
+PushCurrentExpression (\r
+  IN VOID  *Pointer\r
+  );\r
+\r
+/**\r
+  Zero extend integer/boolean/date/time to UINT64 for comparing.\r
+\r
+  @param  Value                  HII Value to be converted.\r
+\r
+**/\r
+VOID\r
+ExtendValueToU64 (\r
+  IN  EFI_HII_VALUE   *Value\r
+  );\r
+\r
+/**\r
+  Push the expression options onto the Stack.\r
+\r
+  @param  Pointer                Pointer to the current expression.\r
+  @param  Level                  Which type this expression belong to. Form, \r
+                                 statement or option?\r
+\r
+  @retval EFI_SUCCESS            The value was pushed onto the stack.\r
+  @retval EFI_OUT_OF_RESOURCES   There is not enough system memory to grow the stack.\r
+\r
+**/\r
+EFI_STATUS\r
+PushConditionalExpression (\r
+  IN FORM_EXPRESSION   *Pointer,\r
+  IN EXPRESS_LEVEL     Level\r
+  );\r
+\r
+/**\r
+  Pop the expression options from the Stack\r
+\r
+  @param  Level                  Which type this expression belong to. Form, \r
+                                 statement or option?\r
+\r
+  @retval EFI_SUCCESS            The value was pushed onto the stack.\r
+  @retval EFI_OUT_OF_RESOURCES   There is not enough system memory to grow the stack.\r
+\r
+**/\r
+EFI_STATUS\r
+PopConditionalExpression (\r
+  IN  EXPRESS_LEVEL      Level\r
+  );\r
+\r
+/**\r
+  Pop the list of map expression from the Stack\r
+\r
+  @param  Pointer                Pointer to the list of map expression to be pop.\r
+\r
+  @retval EFI_SUCCESS            The value was pushed onto the stack.\r
+  @retval EFI_OUT_OF_RESOURCES   There is not enough system memory to grow the stack.\r
+\r
+**/\r
+EFI_STATUS\r
+PopMapExpressionList (\r
+  OUT VOID    **Pointer\r
+  );\r
+\r
+/**\r
+  Pop current expression from the Stack\r
+\r
+  @param  Pointer                Pointer to current expression to be pop.\r
+\r
+  @retval EFI_SUCCESS            The value was pushed onto the stack.\r
+  @retval EFI_OUT_OF_RESOURCES   There is not enough system memory to grow the stack.\r
+\r
+**/\r
+EFI_STATUS\r
+PopCurrentExpression (\r
+  OUT VOID    **Pointer\r
+  );\r
+\r
+/**\r
+  Evaluate the result of a HII expression.\r
+\r
+  If Expression is NULL, then ASSERT.\r
+\r
+  @param  FormSet                FormSet associated with this expression.\r
+  @param  Form                   Form associated with this expression.\r
+  @param  Expression             Expression to be evaluated.\r
+\r
+  @retval EFI_SUCCESS            The expression evaluated successfuly\r
+  @retval EFI_NOT_FOUND          The Question which referenced by a QuestionId\r
+                                 could not be found.\r
+  @retval EFI_OUT_OF_RESOURCES   There is not enough system memory to grow the\r
+                                 stack.\r
+  @retval EFI_ACCESS_DENIED      The pop operation underflowed the stack\r
+  @retval EFI_INVALID_PARAMETER  Syntax error with the Expression\r
+\r
+**/\r
+EFI_STATUS\r
+EvaluateExpression (\r
+  IN FORM_BROWSER_FORMSET  *FormSet,\r
+  IN FORM_BROWSER_FORM     *Form,\r
+  IN OUT FORM_EXPRESSION   *Expression\r
+  );\r
+/**\r
+  Return the result of the expression list. Check the expression list and \r
+  return the highest priority express result.  \r
+  Priority: DisableIf > SuppressIf > GrayOutIf > FALSE\r
+\r
+  @param  ExpList             The input expression list.\r
+  @param  Evaluate            Whether need to evaluate the expression first.\r
+  @param  FormSet             FormSet associated with this expression.\r
+  @param  Form                Form associated with this expression.  \r
+\r
+  @retval EXPRESS_RESULT      Return the higher priority express result. \r
+                              DisableIf > SuppressIf > GrayOutIf > FALSE\r
+\r
+**/\r
+EXPRESS_RESULT \r
+EvaluateExpressionList (\r
+  IN FORM_EXPRESSION_LIST *ExpList,\r
+  IN BOOLEAN              Evaluate,\r
+  IN FORM_BROWSER_FORMSET *FormSet, OPTIONAL\r
+  IN FORM_BROWSER_FORM    *Form OPTIONAL\r
+  );\r
+\r
+/**\r
+  Get Form given its FormId.\r
+\r
+  @param  FormSet                The formset which contains this form.\r
+  @param  FormId                 Id of this form.\r
+\r
+  @retval Pointer                The form.\r
+  @retval NULL                   Specified Form is not found in the formset.\r
+\r
+**/\r
+FORM_BROWSER_FORM *\r
+IdToForm (\r
+  IN FORM_BROWSER_FORMSET  *FormSet,\r
+  IN UINT16                FormId\r
+  );\r
+\r
+#endif // _EXPRESSION_H\r
index 2464aebd095b0b561a2c9f302d52ae1dfabde546..1c3ab2bedca4e1e45b6160c7b1ce027827a4501e 100644 (file)
@@ -16,7 +16,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 \r
 UINT16           mStatementIndex;\r
 UINT16           mExpressionOpCodeIndex;\r
-\r
+EFI_QUESTION_ID  mUsedQuestionId;\r
 BOOLEAN          mInScopeSubtitle;\r
 extern LIST_ENTRY      gBrowserStorageList;\r
 /**\r
@@ -42,9 +42,9 @@ CreateStatement (
 \r
   if (Form == NULL) {\r
     //\r
-    // We are currently not in a Form Scope, so just skip this Statement\r
+    // Only guid op may out side the form level.\r
     //\r
-    return NULL;\r
+    ASSERT (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_GUID_OP);\r
   }\r
 \r
   Statement = &FormSet->StatementBuffer[mStatementIndex];\r
@@ -58,6 +58,7 @@ CreateStatement (
   Statement->Signature = FORM_BROWSER_STATEMENT_SIGNATURE;\r
 \r
   Statement->Operand = ((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode;\r
+  Statement->OpCode  = (EFI_IFR_OP_HEADER *) OpCodeData;\r
 \r
   StatementHdr = (EFI_IFR_STATEMENT_HEADER *) (OpCodeData + sizeof (EFI_IFR_OP_HEADER));\r
   CopyMem (&Statement->Prompt, &StatementHdr->Prompt, sizeof (EFI_STRING_ID));\r
@@ -82,8 +83,11 @@ CreateStatement (
   //\r
   // Insert this Statement into current Form\r
   //\r
-  InsertTailList (&Form->StatementListHead, &Statement->Link);\r
-\r
+  if (Form == NULL) {\r
+    InsertTailList (&FormSet->StatementListOSF, &Statement->Link);\r
+  } else {\r
+    InsertTailList (&Form->StatementListHead, &Statement->Link);\r
+  }\r
   return Statement;\r
 }\r
 \r
@@ -1133,6 +1137,7 @@ ParseOpCodes (
   CountOpCodes (FormSet, &NumberOfStatement, &NumberOfExpression);\r
 \r
   mStatementIndex = 0;\r
+  mUsedQuestionId = 1;\r
   FormSet->StatementBuffer = AllocateZeroPool (NumberOfStatement * sizeof (FORM_BROWSER_STATEMENT));\r
   if (FormSet->StatementBuffer == NULL) {\r
     return EFI_OUT_OF_RESOURCES;\r
@@ -1144,6 +1149,7 @@ ParseOpCodes (
     return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
+  InitializeListHead (&FormSet->StatementListOSF);\r
   InitializeListHead (&FormSet->StorageListHead);\r
   InitializeListHead (&FormSet->DefaultStoreListHead);\r
   InitializeListHead (&FormSet->FormListHead);\r
@@ -1502,7 +1508,6 @@ ParseOpCodes (
       InitializeListHead (&CurrentForm->ConfigRequestHead);\r
 \r
       CurrentForm->FormType = STANDARD_MAP_FORM_TYPE;\r
-      CurrentForm->NvUpdateRequired = FALSE;\r
       CopyMem (&CurrentForm->FormId,    &((EFI_IFR_FORM *) OpCodeData)->FormId,    sizeof (UINT16));\r
       CopyMem (&CurrentForm->FormTitle, &((EFI_IFR_FORM *) OpCodeData)->FormTitle, sizeof (EFI_STRING_ID));\r
 \r
@@ -1539,7 +1544,6 @@ ParseOpCodes (
       CurrentForm = AllocateZeroPool (sizeof (FORM_BROWSER_FORM));\r
       ASSERT (CurrentForm != NULL);\r
       CurrentForm->Signature = FORM_BROWSER_FORM_SIGNATURE;\r
-      CurrentForm->NvUpdateRequired = FALSE;\r
       InitializeListHead (&CurrentForm->ExpressionListHead);\r
       InitializeListHead (&CurrentForm->StatementListHead);\r
       InitializeListHead (&CurrentForm->ConfigRequestHead);\r
@@ -1653,7 +1657,7 @@ ParseOpCodes (
       ASSERT (CurrentStatement != NULL);\r
 \r
       CurrentStatement->Flags = ((EFI_IFR_SUBTITLE *) OpCodeData)->Flags;\r
-\r
+      CurrentStatement->FakeQuestionId = mUsedQuestionId++;\r
       if (Scope != 0) {\r
         mInScopeSubtitle = TRUE;\r
       }\r
@@ -1662,13 +1666,14 @@ ParseOpCodes (
     case EFI_IFR_TEXT_OP:\r
       CurrentStatement = CreateStatement (OpCodeData, FormSet, CurrentForm);\r
       ASSERT (CurrentStatement != NULL);\r
-\r
+      CurrentStatement->FakeQuestionId = mUsedQuestionId++;\r
       CopyMem (&CurrentStatement->TextTwo, &((EFI_IFR_TEXT *) OpCodeData)->TextTwo, sizeof (EFI_STRING_ID));\r
       break;\r
 \r
     case EFI_IFR_RESET_BUTTON_OP:\r
       CurrentStatement = CreateStatement (OpCodeData, FormSet, CurrentForm);\r
       ASSERT (CurrentStatement != NULL);\r
+      CurrentStatement->FakeQuestionId = mUsedQuestionId++;\r
       CopyMem (&CurrentStatement->DefaultId, &((EFI_IFR_RESET_BUTTON *) OpCodeData)->DefaultId, sizeof (EFI_DEFAULT_ID));\r
       break;\r
 \r
@@ -1913,6 +1918,7 @@ ParseOpCodes (
       CurrentOption = AllocateZeroPool (sizeof (QUESTION_OPTION));\r
       ASSERT (CurrentOption != NULL);\r
       CurrentOption->Signature = QUESTION_OPTION_SIGNATURE;\r
+      CurrentOption->OpCode    = (EFI_IFR_ONE_OF_OPTION *) OpCodeData;\r
 \r
       CurrentOption->Flags = ((EFI_IFR_ONE_OF_OPTION *) OpCodeData)->Flags;\r
       CurrentOption->Value.Type = ((EFI_IFR_ONE_OF_OPTION *) OpCodeData)->Type;\r
@@ -2270,45 +2276,8 @@ ParseOpCodes (
     //\r
     // Vendor specific\r
     //\r
-    case EFI_IFR_GUID_OP:\r
-      if (CompareGuid (&gEfiIfrTianoGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) {\r
-        //\r
-        // Tiano specific GUIDed opcodes\r
-        //\r
-        switch (((EFI_IFR_GUID_LABEL *) OpCodeData)->ExtendOpCode) {\r
-        case EFI_IFR_EXTEND_OP_LABEL:\r
-          //\r
-          // just ignore label\r
-          //\r
-          break;\r
-\r
-        case EFI_IFR_EXTEND_OP_BANNER:\r
-          //\r
-          // By SubClass to get Banner Data from Front Page\r
-          //\r
-          if (FormSet->SubClass == EFI_FRONT_PAGE_SUBCLASS) {\r
-            CopyMem (\r
-              &gBannerData->Banner[((EFI_IFR_GUID_BANNER *) OpCodeData)->LineNumber][\r
-              ((EFI_IFR_GUID_BANNER *) OpCodeData)->Alignment],\r
-              &((EFI_IFR_GUID_BANNER *) OpCodeData)->Title,\r
-              sizeof (EFI_STRING_ID)\r
-              );\r
-          }\r
-          break;\r
-\r
-        case EFI_IFR_EXTEND_OP_CLASS:\r
-          CopyMem (&FormSet->Class, &((EFI_IFR_GUID_CLASS *) OpCodeData)->Class, sizeof (UINT16));\r
-          break;\r
-\r
-        case EFI_IFR_EXTEND_OP_SUBCLASS:\r
-          CopyMem (&FormSet->SubClass, &((EFI_IFR_GUID_SUBCLASS *) OpCodeData)->SubClass, sizeof (UINT16));\r
-          break;\r
-\r
-        default:\r
-          break;\r
-        }\r
-      }\r
-\r
+    case EFI_IFR_GUID_OP:     \r
+      CurrentStatement = CreateStatement (OpCodeData, FormSet, CurrentForm);\r
       break;\r
 \r
     //\r
index 4cd71e5d440d04e8653243361d9d1b705045c99d..def18fd9f90b3eaec623fc9107df1d5d4d06da94 100644 (file)
@@ -19,863 +19,1658 @@ UI_MENU_SELECTION  *gCurrentSelection;
 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
+UINT32             gBrowserStatus = BROWSER_SUCCESS;\r
+CHAR16             *gErrorInfo;\r
+UINT16             mCurFakeQestId;\r
+FORM_DISPLAY_ENGINE_FORM gDisplayFormData;\r
+\r
+/**\r
+  Evaluate all expressions in a Form.\r
+\r
+  @param  FormSet        FormSet this Form belongs to.\r
+  @param  Form           The Form.\r
+\r
+  @retval EFI_SUCCESS    The expression evaluated successfuly\r
+\r
+**/\r
+EFI_STATUS\r
+EvaluateFormExpressions (\r
+  IN FORM_BROWSER_FORMSET  *FormSet,\r
+  IN FORM_BROWSER_FORM     *Form\r
+  )\r
+{\r
+  EFI_STATUS       Status;\r
+  LIST_ENTRY       *Link;\r
+  FORM_EXPRESSION  *Expression;\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
+\r
+    if (Expression->Type == EFI_HII_EXPRESSION_INCONSISTENT_IF ||\r
+        Expression->Type == EFI_HII_EXPRESSION_NO_SUBMIT_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
+    Status = EvaluateExpression (FormSet, Form, Expression);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Add empty function for event process function.\r
+\r
+  @param Event    The Event need to be process\r
+  @param Context  The context of the event.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+SetupBrowserEmptyFunction (\r
+  IN  EFI_EVENT    Event,\r
+  IN  VOID         *Context\r
+  )\r
+{\r
+}\r
+\r
+/**\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
+  @retval Statement  The statement use this opcode buffer.\r
+\r
+**/\r
+FORM_DISPLAY_ENGINE_STATEMENT *\r
+GetDisplayStatement (\r
+  IN EFI_IFR_OP_HEADER     *OpCode\r
+  )\r
+{\r
+  FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement;\r
+  LIST_ENTRY                    *Link;\r
+\r
+  Link = GetFirstNode (&gDisplayFormData.StatementListHead);\r
+  while (!IsNull (&gDisplayFormData.StatementListHead, Link)) {\r
+    DisplayStatement = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (Link);\r
+\r
+    if (DisplayStatement->OpCode == OpCode) {\r
+      return DisplayStatement;\r
+    }\r
+    Link = GetNextNode (&gDisplayFormData.StatementListHead, Link);\r
+  }\r
+\r
+  return NULL;\r
+}\r
+\r
+/**\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
+    gBS->CloseEvent (EventNode->RefreshEvent);\r
+\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
+  @param Statement           The statement need to check.\r
+\r
+**/\r
+VOID\r
+UpdateStatement (\r
+  IN OUT FORM_BROWSER_STATEMENT        *Statement\r
+  )\r
+{\r
+  GetQuestionValue (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithHiiDriver);\r
+\r
+  //\r
+  // Reset FormPackage update flag\r
+  //\r
+  mHiiPackageListUpdated = FALSE;\r
+\r
+  //\r
+  // Question value may be changed, need invoke its Callback()\r
+  //\r
+  ProcessCallBackFunction (gCurrentSelection, Statement, EFI_BROWSER_ACTION_CHANGING, FALSE);\r
+  \r
+  if (mHiiPackageListUpdated) {\r
+    //\r
+    // Package list is updated, force to reparse IFR binary of target Formset\r
+    //\r
+    mHiiPackageListUpdated = FALSE;\r
+    gCurrentSelection->Action = UI_ACTION_REFRESH_FORMSET;\r
+  }\r
+}\r
+\r
+/**\r
+  Refresh the question which has refresh guid event attribute.\r
+  \r
+  @param Event    The event which has this function related.     \r
+  @param Context  The input context info related to this event or the status code return to the caller.\r
+**/\r
+VOID\r
+EFIAPI\r
+RefreshEventNotify(\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
+/**\r
+  Create refresh hook event for statement which has refresh event or interval.\r
+\r
+  @param Statement           The statement need to check.\r
+\r
+**/\r
+VOID\r
+CreateRefreshEvent (\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
+  // If question has refresh guid, create the notify function.\r
+  //\r
+  Status = gBS->CreateEventEx (\r
+                    EVT_NOTIFY_SIGNAL,\r
+                    TPL_CALLBACK,\r
+                    RefreshEventNotify,\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
+/**\r
+  Perform value check for a question.\r
+  \r
+  @param  Question       The question need to do check.\r
+  @param  ErrorInfo      Return info about the error.\r
+  \r
+  @retval  The check result.\r
+**/\r
+UINT32\r
+InConsistentIfCheck (\r
+  IN  FORM_BROWSER_STATEMENT        *Question,\r
+  OUT STATEMENT_ERROR_INFO          *ErrorInfo\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  LIST_ENTRY              *Link;\r
+  FORM_EXPRESSION         *Expression;\r
+  LIST_ENTRY              *ListHead;\r
+  UINT32                  RetVal;\r
+\r
+  RetVal     = STATEMENT_VALID;\r
+  ListHead   = &Question->InconsistentListHead;\r
+\r
+  Link = GetFirstNode (ListHead);\r
+  while (!IsNull (ListHead, Link)) {\r
+    Expression = FORM_EXPRESSION_FROM_LINK (Link);\r
+    Link = GetNextNode (ListHead, Link);\r
+\r
+    //\r
+    // Evaluate the expression\r
+    //\r
+    Status = EvaluateExpression (gCurrentSelection->FormSet, gCurrentSelection->Form, Expression);\r
+    if (EFI_ERROR (Status)) {\r
+      continue;\r
+    }\r
+\r
+    if ((Expression->Result.Type == EFI_IFR_TYPE_BOOLEAN) && Expression->Result.Value.b) {\r
+      ErrorInfo->StringId = Expression->Error;\r
+      ErrorInfo->TimeOut  = 0;\r
+      RetVal              = INCOSISTENT_IF_TRUE;\r
+      break;\r
+    }\r
+  }\r
+\r
+  return RetVal;\r
+}\r
+\r
+/**\r
+  Perform value check for a question.\r
+  \r
+  @param  Form       Form where Statement is in.\r
+  @param  Statement  Value will check for it.\r
+  @param  InputValue New value will be checked.\r
+  @param  ErrorInfo  Return the error info for this check.\r
+  \r
+  @retval TRUE   Input Value is valid.\r
+  @retval FALSE  Input Value is invalid.\r
+**/\r
+UINT32\r
+EFIAPI\r
+QuestionCheck (\r
+  IN  FORM_DISPLAY_ENGINE_FORM      *Form,\r
+  IN  FORM_DISPLAY_ENGINE_STATEMENT *Statement,\r
+  IN  EFI_HII_VALUE                 *InputValue,\r
+  OUT STATEMENT_ERROR_INFO          *ErrorInfo\r
+  )\r
+{\r
+  FORM_BROWSER_STATEMENT  *Question;\r
+  EFI_HII_VALUE           BackUpValue;\r
+  UINT8                   *BackUpBuffer;\r
+  UINT32                  RetVal;\r
+\r
+  BackUpBuffer = NULL;\r
+  RetVal       = STATEMENT_VALID;\r
+\r
+  ASSERT (Form != NULL && Statement != NULL && InputValue != NULL && ErrorInfo != NULL);\r
+\r
+  Question = GetBrowserStatement(Statement);\r
+  ASSERT (Question != NULL);\r
+\r
+  //\r
+  // Back up the quesion value.\r
+  //\r
+  switch (Question->Operand) {\r
+  case EFI_IFR_ORDERED_LIST_OP:\r
+    BackUpBuffer = AllocateCopyPool (Question->StorageWidth, Question->BufferValue);\r
+    ASSERT (BackUpBuffer != NULL);\r
+    CopyMem (Question->BufferValue, InputValue->Buffer, Question->StorageWidth);\r
+    break;\r
+\r
+  default:\r
+    CopyMem (&BackUpValue, &Question->HiiValue, sizeof (EFI_HII_VALUE));\r
+    CopyMem (&Question->HiiValue, InputValue, sizeof (EFI_HII_VALUE));\r
+    break;\r
+  }\r
+\r
+  //\r
+  // Do the inconsistentif check.\r
+  //\r
+  if (!IsListEmpty (&Question->InconsistentListHead)) {\r
+    RetVal = InConsistentIfCheck(Question, ErrorInfo);\r
+  }\r
+\r
+  //\r
+  // Restore the quesion value.\r
+  //\r
+  switch (Question->Operand) {\r
+  case EFI_IFR_ORDERED_LIST_OP:\r
+    CopyMem (Question->BufferValue, BackUpBuffer, Question->StorageWidth);\r
+    break;\r
+\r
+  default:\r
+    CopyMem (&Question->HiiValue, &BackUpValue, sizeof (EFI_HII_VALUE));\r
+    break;\r
+  }\r
+\r
+  return RetVal;\r
+}\r
+\r
+/**\r
+\r
+  Initialize the Display statement structure data.\r
+\r
+  @param DisplayStatement      Pointer to the display Statement data strucure.\r
+  @param Statement             The statement need to check.\r
+  @param HostDisplayStatement  Pointer to the display Statement data strucure which is an host statement.\r
+**/\r
+VOID\r
+InitializeDisplayStatement (\r
+  IN OUT FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement,\r
+  IN     FORM_BROWSER_STATEMENT        *Statement,\r
+  IN     FORM_DISPLAY_ENGINE_STATEMENT *HostDisplayStatement\r
+  )\r
+{\r
+  LIST_ENTRY                 *Link;\r
+  QUESTION_OPTION            *Option;\r
+  DISPLAY_QUESTION_OPTION    *DisplayOption;\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
+  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
+    DisplayStatement->CurrentValue.Buffer    = AllocateCopyPool(Statement->StorageWidth,Statement->BufferValue);\r
+    DisplayStatement->CurrentValue.BufferLen = Statement->StorageWidth;\r
+  }\r
+\r
+  DisplayStatement->SettingChangedFlag = Statement->ValueChanged;\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
+  //\r
+  // Create the refresh event process function.\r
+  //\r
+  if (!CompareGuid (&Statement->RefreshGuid, &gZeroGuid)) {\r
+    CreateRefreshEvent (Statement);\r
+  }\r
+\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
+  //\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 ((!CompareGuid (&Statement->RefreshGuid, &gZeroGuid)) || (Statement->RefreshInterval != 0)) {\r
+    gDisplayFormData.FormRefreshEvent = mValueChangedEvent;\r
+  }\r
+\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
+  // Save the validate check question for later use.\r
+  //\r
+  if (!IsListEmpty (&Statement->InconsistentListHead)) {\r
+    DisplayStatement->ValidateQuestion = QuestionCheck;\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->InSubtitle) {\r
+    InsertTailList(&HostDisplayStatement->NestStatementList, &DisplayStatement->DisplayLink);\r
+  } else {\r
+    InsertTailList(&gDisplayFormData.StatementListHead, &DisplayStatement->DisplayLink);\r
+  }\r
+}\r
+\r
+/**\r
+  Process for the refresh interval statement.\r
+\r
+  @param Event    The Event need to be process\r
+  @param Context  The context of the event.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+RefreshIntervalProcess (\r
+  IN  EFI_EVENT    Event,\r
+  IN  VOID         *Context\r
+  )\r
+{\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
+    Link = GetNextNode (&gCurrentSelection->Form->StatementListHead, Link);\r
+\r
+    if (Statement->RefreshInterval == 0) {\r
+      continue;\r
+    }\r
+\r
+    UpdateStatement(Statement);\r
+  }\r
+\r
+  gBS->SignalEvent (mValueChangedEvent);\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
+    CopyKey->KeyData    = AllocateCopyPool(sizeof (EFI_INPUT_KEY), HotKey->KeyData);\r
+    CopyKey->HelpString = AllocateCopyPool(StrSize (HotKey->HelpString), HotKey->HelpString);\r
+\r
+    InsertTailList(&gDisplayFormData.HotKeyListHead, &CopyKey->Link);\r
+\r
+    Link = GetNextNode (&gBrowserHotKeyList, Link);\r
+  }\r
+}\r
 \r
 /**\r
-  Clear retangle with specified text attribute.\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
+  Enum all statement in current form, find all the statement can be display and\r
+  add to the display form.\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
+AddStatementToDisplayForm (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  LIST_ENTRY                    *Link;\r
+  FORM_BROWSER_STATEMENT        *Statement;\r
+  FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement;\r
+  FORM_DISPLAY_ENGINE_STATEMENT *HostDisplayStatement;\r
+  UINT8                         MinRefreshInterval;\r
+  EFI_EVENT                     RefreshIntervalEvent;\r
+  FORM_BROWSER_REFRESH_EVENT_NODE *EventNode;\r
+  BOOLEAN                       FormEditable;\r
+\r
+  HostDisplayStatement = NULL;\r
+  MinRefreshInterval   = 0;\r
+  FormEditable         = FALSE;\r
+\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
+    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
+    InitializeListHead (&DisplayStatement->NestStatementList);\r
+    InitializeListHead (&DisplayStatement->OptionListHead);\r
+\r
+    InsertTailList(&gDisplayFormData.StatementListOSF, &DisplayStatement->DisplayLink);\r
+  }\r
+\r
+  //\r
+  // Process the statement in this form.\r
+  //\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
+    //\r
+    // This statement can't be show, skip it.\r
+    //\r
+    if (EvaluateExpressionList(Statement->Expression, FALSE, NULL, NULL) > ExpressGrayOut) {\r
+      continue;\r
+    }\r
+\r
+    DisplayStatement = AllocateZeroPool (sizeof (FORM_DISPLAY_ENGINE_STATEMENT));\r
+    ASSERT (DisplayStatement != NULL);\r
+\r
+    //\r
+    // Initialize this statement and add it to the display form.\r
+    //\r
+    InitializeDisplayStatement(DisplayStatement, Statement, HostDisplayStatement);\r
+\r
+    //\r
+    // Save the Host statement info.\r
+    // Host statement may has nest statement follow it.\r
+    //\r
+    if (!Statement->InSubtitle) {\r
+      HostDisplayStatement = DisplayStatement;\r
+    }\r
+\r
+    if (Statement->Storage != NULL) {\r
+      FormEditable = TRUE;\r
+    }\r
+\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
+  //\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
+  // 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
+  default:\r
+    break;\r
+  }\r
+}\r
+\r
+/**\r
+\r
+  Initialize the Display form structure data.\r
+\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
+        SetupBrowserEmptyFunction,\r
+        NULL,\r
+        &mValueChangedEvent\r
+        );\r
+  ASSERT_EFI_ERROR (Status); \r
+}\r
+\r
+/**\r
+\r
+  Free the kotkey info saved in form data.\r
+\r
+**/\r
+VOID\r
+FreeHotkeyList (\r
+  VOID\r
+  )\r
+{\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
+\r
+  Update the Display form structure data.\r
+\r
+**/\r
+VOID\r
+UpdateDisplayFormData (\r
+  VOID\r
+  )\r
+{\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
+  gDisplayFormData.BrowserStatus = gBrowserStatus;\r
+  gDisplayFormData.ErrorString   = gErrorInfo;\r
+\r
+  gBrowserStatus = BROWSER_SUCCESS;\r
+  gErrorInfo     = 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
+\r
+  Free the Display form structure data.\r
+\r
+**/\r
+VOID\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
+  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
+\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
+  EFI_STATUS    Status;\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);\r
+  }\r
+\r
+  if ((Action & BROWSER_ACTION_SUBMIT) == BROWSER_ACTION_SUBMIT) {\r
+    Status = SubmitForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope);\r
+    if (EFI_ERROR (Status)) {\r
+      gBrowserStatus = BROWSER_SUBMIT_FAIL;\r
+    }\r
+  }\r
+\r
+  if ((Action & BROWSER_ACTION_RESET) == BROWSER_ACTION_RESET) {\r
+    gResetRequired = 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
+/**\r
+  Find HII Handle in the HII database associated with given Device Path.\r
+\r
+  If DevicePath is NULL, then ASSERT.\r
+\r
+  @param  DevicePath             Device Path associated with the HII package list\r
+                                 handle.\r
+\r
+  @retval Handle                 HII package list Handle associated with the Device\r
+                                        Path.\r
+  @retval NULL                   Hii Package list handle is not found.\r
+\r
+**/\r
+EFI_HII_HANDLE\r
+EFIAPI\r
+DevicePathToHiiHandle (\r
+  IN EFI_DEVICE_PATH_PROTOCOL   *DevicePath\r
   )\r
 {\r
-  CHAR16  *Buffer;\r
-  UINTN   Row;\r
+  EFI_STATUS                  Status;\r
+  EFI_DEVICE_PATH_PROTOCOL    *TmpDevicePath;\r
+  UINTN                       BufferSize;\r
+  UINTN                       HandleCount;\r
+  UINTN                       Index;\r
+  EFI_HANDLE                  Handle;\r
+  EFI_HANDLE                  DriverHandle;\r
+  EFI_HII_HANDLE              *HiiHandles;\r
+  EFI_HII_HANDLE              HiiHandle;\r
+\r
+  ASSERT (DevicePath != NULL);\r
+\r
+  TmpDevicePath = DevicePath;\r
+  //\r
+  // Locate Device Path Protocol handle buffer\r
+  //\r
+  Status = gBS->LocateDevicePath (\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  &TmpDevicePath,\r
+                  &DriverHandle\r
+                  );\r
+  if (EFI_ERROR (Status) || !IsDevicePathEnd (TmpDevicePath)) {\r
+    return NULL;\r
+  }\r
 \r
   //\r
-  // For now, allocate an arbitrarily long buffer\r
+  // Retrieve all HII Handles from HII database\r
   //\r
-  Buffer = AllocateZeroPool (0x10000);\r
-  ASSERT (Buffer != NULL);\r
+  BufferSize = 0x1000;\r
+  HiiHandles = AllocatePool (BufferSize);\r
+  ASSERT (HiiHandles != NULL);\r
+  Status = mHiiDatabase->ListPackageLists (\r
+                           mHiiDatabase,\r
+                           EFI_HII_PACKAGE_TYPE_ALL,\r
+                           NULL,\r
+                           &BufferSize,\r
+                           HiiHandles\r
+                           );\r
+  if (Status == EFI_BUFFER_TOO_SMALL) {\r
+    FreePool (HiiHandles);\r
+    HiiHandles = AllocatePool (BufferSize);\r
+    ASSERT (HiiHandles != NULL);\r
+\r
+    Status = mHiiDatabase->ListPackageLists (\r
+                             mHiiDatabase,\r
+                             EFI_HII_PACKAGE_TYPE_ALL,\r
+                             NULL,\r
+                             &BufferSize,\r
+                             HiiHandles\r
+                             );\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    FreePool (HiiHandles);\r
+    return NULL;\r
+  }\r
 \r
   //\r
-  // Set foreground and background as defined\r
+  // Search Hii Handle by Driver Handle\r
   //\r
-  gST->ConOut->SetAttribute (gST->ConOut, TextAttribute);\r
+  HiiHandle = NULL;\r
+  HandleCount = BufferSize / sizeof (EFI_HII_HANDLE);\r
+  for (Index = 0; Index < HandleCount; Index++) {\r
+    Status = mHiiDatabase->GetPackageListHandle (\r
+                             mHiiDatabase,\r
+                             HiiHandles[Index],\r
+                             &Handle\r
+                             );\r
+    if (!EFI_ERROR (Status) && (Handle == DriverHandle)) {\r
+      HiiHandle = HiiHandles[Index];\r
+      break;\r
+    }\r
+  }\r
+\r
+  FreePool (HiiHandles);\r
+  return HiiHandle;\r
+}\r
+\r
+/**\r
+  Find HII Handle in the HII database associated with given form set guid.\r
+\r
+  If FormSetGuid is NULL, then ASSERT.\r
+\r
+  @param  ComparingGuid          FormSet Guid associated with the HII package list\r
+                                 handle.\r
+\r
+  @retval Handle                 HII package list Handle associated with the Device\r
+                                        Path.\r
+  @retval NULL                   Hii Package list handle is not found.\r
 \r
+**/\r
+EFI_HII_HANDLE\r
+FormSetGuidToHiiHandle (\r
+  EFI_GUID     *ComparingGuid\r
+  )\r
+{\r
+  EFI_HII_HANDLE               *HiiHandles;\r
+  UINTN                        Index;\r
+  EFI_HII_PACKAGE_LIST_HEADER  *HiiPackageList;\r
+  UINTN                        BufferSize;\r
+  UINT32                       Offset;\r
+  UINT32                       Offset2;\r
+  UINT32                       PackageListLength;\r
+  EFI_HII_PACKAGE_HEADER       PackageHeader;\r
+  UINT8                        *Package;\r
+  UINT8                        *OpCodeData;\r
+  EFI_STATUS                   Status;\r
+  EFI_HII_HANDLE               HiiHandle;\r
+\r
+  ASSERT (ComparingGuid != NULL);\r
+\r
+  HiiHandle  = NULL;\r
   //\r
-  // Much faster to buffer the long string instead of print it a character at a time\r
+  // Get all the Hii handles\r
   //\r
-  SetUnicodeMem (Buffer, RightColumn - LeftColumn, L' ');\r
+  HiiHandles = HiiGetHiiHandles (NULL);\r
+  ASSERT (HiiHandles != NULL);\r
 \r
   //\r
-  // Clear the desired area with the appropriate foreground/background\r
+  // Search for formset of each class type\r
   //\r
-  for (Row = TopRow; Row <= BottomRow; Row++) {\r
-    PrintStringAt (LeftColumn, Row, Buffer);\r
+  for (Index = 0; HiiHandles[Index] != NULL; Index++) {\r
+    BufferSize = 0;\r
+    HiiPackageList = NULL;\r
+    Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, HiiHandles[Index], &BufferSize, HiiPackageList);\r
+    if (Status == EFI_BUFFER_TOO_SMALL) {\r
+      HiiPackageList = AllocatePool (BufferSize);\r
+      ASSERT (HiiPackageList != NULL);\r
+\r
+      Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, HiiHandles[Index], &BufferSize, HiiPackageList);\r
+    }\r
+    if (EFI_ERROR (Status) || HiiPackageList == NULL) {\r
+      return NULL;\r
+    }\r
+\r
+    //\r
+    // Get Form package from this HII package List\r
+    //\r
+    Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);\r
+    Offset2 = 0;\r
+    CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32)); \r
+\r
+    while (Offset < PackageListLength) {\r
+      Package = ((UINT8 *) HiiPackageList) + Offset;\r
+      CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));\r
+\r
+      if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) {\r
+        //\r
+        // Search FormSet in this Form Package\r
+        //\r
+        Offset2 = sizeof (EFI_HII_PACKAGE_HEADER);\r
+        while (Offset2 < PackageHeader.Length) {\r
+          OpCodeData = Package + Offset2;\r
+\r
+          if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) {\r
+            //\r
+            // Try to compare against formset GUID\r
+            //\r
+            if (CompareGuid (ComparingGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) {\r
+              HiiHandle = HiiHandles[Index];\r
+              break;\r
+            }\r
+          }\r
+\r
+          Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;\r
+        }\r
+      }\r
+      if (HiiHandle != NULL) {\r
+        break;\r
+      }\r
+      Offset += PackageHeader.Length;\r
+    }\r
+    \r
+    FreePool (HiiPackageList);\r
+       if (HiiHandle != NULL) {\r
+               break;\r
+       }\r
   }\r
 \r
-  gST->ConOut->SetCursorPosition (gST->ConOut, LeftColumn, TopRow);\r
+  FreePool (HiiHandles);\r
 \r
-  FreePool (Buffer);\r
-  return ;\r
+  return HiiHandle;\r
 }\r
 \r
 /**\r
-  Concatenate a narrow string to another string.\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 Destination The destination string.\r
-  @param Source      The source string. The string to be concatenated.\r
-                     to the end of Destination.\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
-VOID\r
-NewStrCat (\r
-  IN OUT CHAR16               *Destination,\r
-  IN     CHAR16               *Source\r
+BOOLEAN\r
+ProcessChangedData (\r
+  IN OUT UI_MENU_SELECTION       *Selection,\r
+  IN     BROWSER_SETTING_SCOPE   Scope\r
   )\r
 {\r
-  UINTN Length;\r
+  BOOLEAN  RetValue;\r
 \r
-  for (Length = 0; Destination[Length] != 0; Length++)\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
+      SubmitForm (Selection->FormSet, Selection->Form, Scope);\r
+      break;\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
+    case BROWSER_ACTION_NONE:\r
+      RetValue = FALSE;\r
+      break;\r
 \r
-  StrCpy (Destination + Length, Source);\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
-  Count the storage space of a Unicode string.\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
-\r
-  If String is NULL, then ASSERT ().\r
-\r
-  @param String          The input string to be counted.\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
-  @return Storage space for the input string.\r
+  @param Selection    The selection info.\r
 \r
 **/\r
-UINTN\r
-GetStringWidth (\r
-  IN CHAR16               *String\r
+VOID\r
+FindParentFormSet (\r
+  IN OUT   UI_MENU_SELECTION           *Selection\r
   )\r
 {\r
-  UINTN Index;\r
-  UINTN Count;\r
-  UINTN IncrementValue;\r
-\r
-  ASSERT (String != NULL);\r
-  if (String == NULL) {\r
-    return 0;\r
-  }\r
-\r
-  Index           = 0;\r
-  Count           = 0;\r
-  IncrementValue  = 1;\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
+  FORM_ENTRY_INFO            *CurrentMenu;\r
+  FORM_ENTRY_INFO            *ParentMenu;\r
 \r
-    //\r
-    // We hit the null-terminator, we now have a count\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
+  CurrentMenu = Selection->CurrentMenu;\r
+  ParentMenu  = UiFindParentMenu(CurrentMenu);\r
 \r
   //\r
-  // Increment by one to include the null-terminator in the size\r
+  // Find a menu which has different formset guid with current.\r
   //\r
-  Count++;\r
+  while (ParentMenu != NULL && CompareGuid (&CurrentMenu->FormSetGuid, &ParentMenu->FormSetGuid)) {\r
+    CurrentMenu = ParentMenu;\r
+    ParentMenu  = UiFindParentMenu(CurrentMenu);\r
+  }\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
-  return Count * sizeof (CHAR16);\r
+  Selection->Statement  = NULL;\r
 }\r
 \r
 /**\r
-  This function displays the page frame.\r
+  Process the goto op code, update the info in the selection structure.\r
 \r
-  @param  Selection              Selection contains the information about \r
-                                 the Selection, form and formset to be displayed.\r
-                                 Selection action may be updated in retrieve callback.\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
-VOID\r
-DisplayPageFrame (\r
-  IN UI_MENU_SELECTION    *Selection\r
+EFI_STATUS\r
+ProcessGotoOpCode (\r
+  IN OUT   FORM_BROWSER_STATEMENT      *Statement,\r
+  IN OUT   UI_MENU_SELECTION           *Selection\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
-\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
-\r
-  if (Selection->Form->ModalForm) {\r
-    return;\r
-  }\r
-\r
-  CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));\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
-  // For now, allocate an arbitrarily long buffer\r
+  // Prepare the device path check, get the device path info first.\r
   //\r
-  Buffer = AllocateZeroPool (0x10000);\r
-  ASSERT (Buffer != NULL);\r
-\r
-  Character = BOXDRAW_HORIZONTAL;\r
-\r
-  for (Index = 0; Index + 2 < (LocalScreen.RightColumn - LocalScreen.LeftColumn); Index++) {\r
-    Buffer[Index] = Character;\r
+  if (Statement->HiiValue.Value.ref.DevicePath != 0) {\r
+    StringPtr = GetToken (Statement->HiiValue.Value.ref.DevicePath, Selection->FormSet->HiiHandle);\r
   }\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
+  // Check whether the device path string is a valid string.\r
+  //\r
+  if (Statement->HiiValue.Value.ref.DevicePath != 0 && StringPtr != NULL) {\r
+    if (Selection->Form->ModalForm) {\r
+      return Status;\r
+    }\r
+\r
     //\r
-    //    for (Line = 0; Line < BANNER_HEIGHT; Line++) {\r
+    // Goto another Hii Package list\r
     //\r
-    for (Line = (UINT8) LocalScreen.TopRow; Line < BANNER_HEIGHT + (UINT8) LocalScreen.TopRow; Line++) {\r
+    if (mPathFromText != NULL) {\r
+      DevicePath = mPathFromText->ConvertTextToDevicePath(StringPtr);\r
+      if (DevicePath != NULL) {\r
+        HiiHandle = DevicePathToHiiHandle (DevicePath);\r
+        FreePool (DevicePath);\r
+      }\r
+      FreePool (StringPtr);\r
+    } else {\r
       //\r
-      //      for (Alignment = 0; Alignment < BANNER_COLUMNS; Alignment++) {\r
+      // Not found the EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL protocol.\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
-        switch (Alignment - LocalScreen.LeftColumn) {\r
-        case 0:\r
-          //\r
-          // Handle left column\r
-          //\r
-          PrintStringAt (LocalScreen.LeftColumn + BANNER_LEFT_COLUMN_INDENT, Line, StrFrontPageBanner);\r
-          break;\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
+      gBrowserStatus = BROWSER_PROTOCOL_NOT_FOUND;\r
+      FreePool (StringPtr);\r
+      return Status;\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
+    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
-        FreePool (StrFrontPageBanner);\r
       }\r
     }\r
-  }\r
 \r
-  ClearLines (\r
-    LocalScreen.LeftColumn,\r
-    LocalScreen.RightColumn,\r
-    LocalScreen.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight,\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
+    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
-    Character = BOXDRAW_UP_RIGHT;\r
-    PrintCharAt (LocalScreen.LeftColumn, LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT - 1, Character);\r
-    PrintString (Buffer);\r
-\r
-    Character = BOXDRAW_UP_LEFT;\r
-    PrintChar (Character);\r
-\r
-    if ((gClassOfVfr & FORMSET_CLASS_PLATFORM_SETUP) == FORMSET_CLASS_PLATFORM_SETUP) {\r
+    CopyMem (&Selection->FormSetGuid,&Statement->HiiValue.Value.ref.FormSetGuid, sizeof (EFI_GUID));\r
+    Selection->FormId = Statement->HiiValue.Value.ref.FormId;\r
+    Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;\r
+  } else if (!CompareGuid (&Statement->HiiValue.Value.ref.FormSetGuid, &gZeroGuid)) {\r
+    if (Selection->Form->ModalForm) {\r
+      return Status;\r
+    }\r
+    if (!CompareGuid (&Statement->HiiValue.Value.ref.FormSetGuid, &Selection->FormSetGuid)) {\r
       //\r
-      // Print Bottom border line\r
-      // +------------------------------------------------------------------------------+\r
-      // ?                                                                             ?\r
-      // +------------------------------------------------------------------------------+\r
+      // Goto another Formset, check for uncommitted data\r
       //\r
-      Character = BOXDRAW_DOWN_RIGHT;\r
-      PrintCharAt (LocalScreen.LeftColumn, LocalScreen.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight, 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 - gFooterHeight + 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
+      if ((gBrowserSettingScope == FormLevel || gBrowserSettingScope == FormSetLevel) &&\r
+         IsNvUpdateRequiredForFormSet(Selection->FormSet)) {\r
+        if (!ProcessChangedData(Selection, FormSetLevel)) {\r
+          return EFI_SUCCESS;\r
+        }\r
       }\r
+    }\r
 \r
-      Character = BOXDRAW_UP_RIGHT;\r
-      PrintCharAt (LocalScreen.LeftColumn, LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 1, Character);\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
-      PrintString (Buffer);\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
-      Character = BOXDRAW_UP_LEFT;\r
-      PrintChar (Character);\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
+        gBrowserStatus = BROWSER_FORM_SUPPRESS;\r
+        return EFI_SUCCESS;\r
+      }\r
     }\r
-  }\r
 \r
-  FreePool (Buffer);\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
-  Evaluate all expressions in a Form.\r
+  Process Question Config.\r
 \r
-  @param  FormSet        FormSet this Form belongs to.\r
-  @param  Form           The Form.\r
+  @param  Selection              The UI menu selection.\r
+  @param  Question               The Question to be peocessed.\r
 \r
-  @retval EFI_SUCCESS    The expression evaluated successfuly\r
+  @retval EFI_SUCCESS            Question Config process success.\r
+  @retval Other                  Question Config process fail.\r
 \r
 **/\r
 EFI_STATUS\r
-EvaluateFormExpressions (\r
-  IN FORM_BROWSER_FORMSET  *FormSet,\r
-  IN FORM_BROWSER_FORM     *Form\r
+ProcessQuestionConfig (\r
+  IN  UI_MENU_SELECTION       *Selection,\r
+  IN  FORM_BROWSER_STATEMENT  *Question\r
   )\r
 {\r
-  EFI_STATUS       Status;\r
-  LIST_ENTRY       *Link;\r
-  FORM_EXPRESSION  *Expression;\r
+  EFI_STATUS                      Status;\r
+  CHAR16                          *ConfigResp;\r
+  CHAR16                          *Progress;\r
+  EFI_HII_CONFIG_ACCESS_PROTOCOL  *ConfigAccess;\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
+  if (Question->QuestionConfig == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
 \r
-    if (Expression->Type == EFI_HII_EXPRESSION_INCONSISTENT_IF ||\r
-        Expression->Type == EFI_HII_EXPRESSION_NO_SUBMIT_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
+  // Get <ConfigResp>\r
+  //\r
+  ConfigResp = GetToken (Question->QuestionConfig, Selection->FormSet->HiiHandle);\r
+  if (ConfigResp == NULL) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
 \r
-    Status = EvaluateExpression (FormSet, Form, Expression);\r
-    if (EFI_ERROR (Status)) {\r
-      return Status;\r
-    }\r
+  //\r
+  // Send config to Configuration Driver\r
+  //\r
+  ConfigAccess = Selection->FormSet->ConfigAccess;\r
+  if (ConfigAccess == NULL) {\r
+    return EFI_UNSUPPORTED;\r
   }\r
+  Status = ConfigAccess->RouteConfig (\r
+                           ConfigAccess,\r
+                           ConfigResp,\r
+                           &Progress\r
+                           );\r
 \r
-  return EFI_SUCCESS;\r
+  return Status;\r
 }\r
 \r
-/*\r
-+------------------------------------------------------------------------------+\r
-?                                 Setup Page                                  ?\r
-+------------------------------------------------------------------------------+\r
-\r
-\r
-\r
-\r
-\r
-\r
-\r
-\r
-\r
-\r
-\r
-\r
-\r
-\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
-\r
 /**\r
 \r
+  Process the user input data.\r
 \r
-  Display form and wait for user to select one menu option, then return it.\r
+  @param UserInput               The user input data.\r
+  @param ChangeHighlight         Whether need to change the highlight statement.  \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
 \r
 **/\r
 EFI_STATUS\r
-DisplayForm (\r
-  IN OUT UI_MENU_SELECTION           *Selection\r
+ProcessUserInput (\r
+  IN USER_INPUT               *UserInput,\r
+  IN BOOLEAN                  ChangeHighlight\r
   )\r
 {\r
-  CHAR16                 *StringPtr;\r
-  UINT16                 MenuItemCount;\r
-  EFI_HII_HANDLE         Handle;\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
-  UINT16                 GlyphWidth;\r
-\r
-  Handle        = Selection->Handle;\r
-  MenuItemCount = 0;\r
-  ArrayEntry    = 0;\r
-  OutputString  = NULL;\r
-\r
-  UiInitMenu ();\r
-\r
-  CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));\r
-\r
-  StringPtr = GetToken (Selection->Form->FormTitle, Handle);\r
+  EFI_STATUS                    Status;\r
+  FORM_BROWSER_STATEMENT        *Statement;\r
 \r
-  if ((gClassOfVfr & FORMSET_CLASS_FRONT_PAGE) != FORMSET_CLASS_FRONT_PAGE) {\r
-    if (Selection->Form->ModalForm) {\r
-      gST->ConOut->SetAttribute (gST->ConOut, TITLE_TEXT | EFI_BACKGROUND_BLACK);\r
-    } else {\r
-      gST->ConOut->SetAttribute (gST->ConOut, TITLE_TEXT | TITLE_BACKGROUND);\r
-    }\r
-    PrintStringAt (\r
-      (LocalScreen.RightColumn + LocalScreen.LeftColumn - GetStringWidth (StringPtr) / 2) / 2,\r
-      LocalScreen.TopRow + 1,\r
-      StringPtr\r
-      );\r
-  }\r
+  Status = EFI_SUCCESS;\r
 \r
   //\r
-  // Remove Buffer allocated for StringPtr after it has been used.\r
+  // When Exit from FormDisplay function, one of the below two cases must be true.\r
   //\r
-  FreePool (StringPtr);\r
+  ASSERT (UserInput->Action != 0 || UserInput->SelectedStatement != NULL);\r
 \r
   //\r
-  // Evaluate all the Expressions in this Form\r
+  // Remove the last highligh question id, this id will update when show next form.\r
   //\r
-  Status = EvaluateFormExpressions (Selection->FormSet, Selection->Form);\r
-  if (EFI_ERROR (Status)) {\r
-    return Status;\r
-  }\r
+  gCurrentSelection->QuestionId = 0;\r
 \r
-  Selection->FormEditable = FALSE;\r
-  Link = GetFirstNode (&Selection->Form->StatementListHead);\r
-  while (!IsNull (&Selection->Form->StatementListHead, Link)) {\r
-    Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);\r
+  //\r
+  // First process the Action field in USER_INPUT.\r
+  //\r
+  if (UserInput->Action != 0) {\r
+    Status = ProcessAction (UserInput->Action, UserInput->DefaultId);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
 \r
-    if (EvaluateExpressionList(Statement->Expression, FALSE, NULL, NULL) <= ExpressGrayOut) {\r
-      StringPtr = GetToken (Statement->Prompt, Handle);\r
-      ASSERT (StringPtr != NULL);\r
+    //\r
+    // Clear the highlight info.\r
+    //\r
+    gCurrentSelection->Statement = NULL;\r
 \r
-      Width     = GetWidth (Statement, Handle);\r
+    if (UserInput->SelectedStatement != NULL) {\r
+      Statement = GetBrowserStatement(UserInput->SelectedStatement);\r
+      ASSERT (Statement != NULL);\r
+      //\r
+      // Save the current highlight menu in the menu history data.\r
+      // which will be used when later browse back to this form.\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
+  } else {\r
+    Statement = GetBrowserStatement(UserInput->SelectedStatement);\r
+    ASSERT (Statement != NULL);\r
 \r
-      NumberOfLines = 1;\r
-      ArrayEntry = 0;\r
-      GlyphWidth = 1;\r
-      for (; GetLineByWidth (StringPtr, Width, &GlyphWidth,&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
+    gCurrentSelection->Statement = Statement;\r
 \r
-        FreePool (OutputString);\r
+    if (ChangeHighlight) {\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
+    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
-      // 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
+      // Reset Question to default value specified by DefaultId\r
       //\r
-      MenuOption = UiAddMenuOption (StringPtr, Selection->Handle, Selection->Form, Statement, NumberOfLines, MenuItemCount);\r
-      MenuItemCount++;\r
+      Status = ExtractDefault (gCurrentSelection->FormSet, NULL, Statement->DefaultId, FormSetLevel, GetDefaultForAll, NULL, FALSE);\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
-      if (MenuOption->IsQuestion && !MenuOption->ReadOnly) {\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
         //\r
-        // At least one item is not readonly, this Form is considered as editable\r
+        // Two password match, send it to Configuration Driver\r
         //\r
-        Selection->FormEditable = TRUE;\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
+      if (Statement->Operand != EFI_IFR_PASSWORD_OP) {\r
+        SetQuestionValue (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithEditBuffer);\r
       }\r
+      break;\r
     }\r
-\r
-    Link = GetNextNode (&Selection->Form->StatementListHead, Link);\r
   }\r
 \r
-  Status = UiDisplayMenu (Selection);\r
-\r
-  UiFreeMenu ();\r
-\r
   return Status;\r
 }\r
 \r
 /**\r
-  Initialize the HII String Token to the correct values.\r
-\r
-**/\r
-VOID\r
-InitializeBrowserStrings (\r
-  VOID\r
-  )\r
-{\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
-  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
-  gProtocolNotFound     = GetToken (STRING_TOKEN (PROTOCOL_NOT_FOUND), gHiiHandle);\r
-  return ;\r
-}\r
-\r
-/**\r
-  Free up the resource allocated for all strings required\r
-  by Setup Browser.\r
 \r
-**/\r
-VOID\r
-FreeBrowserStrings (\r
-  VOID\r
-  )\r
-{\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
-  FreePool (gProtocolNotFound);\r
-  return ;\r
-}\r
+  Display form and wait for user to select one menu option, then return it.\r
 \r
-/**\r
-  Show all registered HotKey help strings on bottom Rows.\r
+  @retval EFI_SUCESSS            This function always return successfully for now.\r
 \r
 **/\r
-VOID\r
-PrintHotKeyHelpString (\r
+EFI_STATUS\r
+DisplayForm (\r
   VOID\r
   )\r
 {\r
-  UINTN                  CurrentCol;\r
-  UINTN                  CurrentRow;\r
-  UINTN                  BottomRowOfHotKeyHelp;\r
-  UINTN                  ColumnWidth;\r
-  UINTN                  Index;\r
-  EFI_SCREEN_DESCRIPTOR  LocalScreen;\r
-  LIST_ENTRY             *Link;\r
-  BROWSER_HOT_KEY        *HotKey;\r
+  EFI_STATUS               Status;\r
+  USER_INPUT               UserInput;\r
+  FORM_ENTRY_INFO          *CurrentMenu;\r
+  BOOLEAN                  ChangeHighlight;\r
 \r
-  CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));\r
-  ColumnWidth            = (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 3;\r
-  BottomRowOfHotKeyHelp  = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 3;\r
+  ZeroMem (&UserInput, sizeof (USER_INPUT));\r
 \r
   //\r
-  // Calculate total number of Register HotKeys. \r
+  // Update the menu history data.\r
   //\r
-  Index = 0;\r
-  Link  = GetFirstNode (&gBrowserHotKeyList);\r
-  while (!IsNull (&gBrowserHotKeyList, Link)) {\r
-    HotKey = BROWSER_HOT_KEY_FROM_LINK (Link);\r
-    //\r
-    // Help string can't exceed ColumnWidth. One Row will show three Help information. \r
+  CurrentMenu = UiFindMenuList (gCurrentSelection->Handle, &gCurrentSelection->FormSetGuid, gCurrentSelection->FormId);\r
+  if (CurrentMenu == NULL) {\r
     //\r
-    if (StrLen (HotKey->HelpString) > ColumnWidth) {\r
-      HotKey->HelpString[ColumnWidth] = L'\0';\r
-    }\r
-    //\r
-    // Calculate help information Column and Row.\r
-    //\r
-    if ((Index % 3) != 2) {\r
-      CurrentCol = LocalScreen.LeftColumn + (2 - Index % 3) * ColumnWidth;\r
-    } else {\r
-      CurrentCol = LocalScreen.LeftColumn + 2;\r
-    }\r
-    CurrentRow = BottomRowOfHotKeyHelp - Index / 3;\r
-    //\r
-    // Print HotKey help string on bottom Row.\r
+    // Current menu not found, add it to the menu tree\r
     //\r
-    PrintStringAt (CurrentCol, CurrentRow, HotKey->HelpString);\r
+    CurrentMenu = UiAddMenuList (gCurrentSelection->Handle, &gCurrentSelection->FormSetGuid,\r
+                                 gCurrentSelection->FormId, gCurrentSelection->QuestionId);\r
+    ASSERT (CurrentMenu != NULL);\r
+  }\r
+  gCurrentSelection->CurrentMenu = CurrentMenu;\r
 \r
+  //\r
+  // Find currrent highlight statement.\r
+  //\r
+  if (gCurrentSelection->QuestionId == 0) {\r
     //\r
-    // Get Next Hot Key.\r
+    // Highlight not specified, fetch it from cached menu\r
     //\r
-    Link = GetNextNode (&gBrowserHotKeyList, Link);\r
-    Index ++;\r
+    gCurrentSelection->QuestionId = CurrentMenu->QuestionId;\r
   }\r
-  \r
-  return;\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
-\r
-**/\r
-VOID\r
-UpdateKeyHelp (\r
-  IN  UI_MENU_SELECTION           *Selection,\r
-  IN  UI_MENU_OPTION              *MenuOption,\r
-  IN  BOOLEAN                     Selected\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
-\r
-  gST->ConOut->SetAttribute (gST->ConOut, KEYHELP_TEXT | KEYHELP_BACKGROUND);\r
 \r
-  if (Selection->Form->ModalForm) {\r
-    return;\r
+  //\r
+  // Evaluate all the Expressions in this Form\r
+  //\r
+  Status = EvaluateFormExpressions (gCurrentSelection->FormSet, gCurrentSelection->Form);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
   }\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) / 3 * 2;\r
-\r
-  StartColumnOfHelp = LocalScreen.LeftColumn + 2;\r
-  LeftColumnOfHelp  = LocalScreen.LeftColumn + 1;\r
-  RightColumnOfHelp = LocalScreen.RightColumn - 2;\r
-  TopRowOfHelp      = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight + 1;\r
-  BottomRowOfHelp   = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 2;\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
-      //\r
-      // On system setting, HotKey will show on every form.\r
-      //\r
-      if (gBrowserSettingScope == SystemLevel ||\r
-          (Selection->FormEditable && gFunctionKeySetting != NONE_FUNCTION_KEY_SETTING)) {\r
-        PrintHotKeyHelpString ();\r
-      }\r
-\r
-      if ((gClassOfVfr & FORMSET_CLASS_PLATFORM_SETUP) == FORMSET_CLASS_PLATFORM_SETUP) {\r
-        PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString);\r
-      }\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, gEnterString);\r
-        PrintStringAt (StartColumnOfHelp, TopRowOfHelp, 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 (StartColumnOfHelp, TopRowOfHelp, gAdjustNumber);\r
-        } \r
-        PrintStringAt (SecCol, BottomRowOfHelp, gEnterString);\r
-      }\r
-    } else {\r
-      PrintStringAt (SecCol, BottomRowOfHelp, gEnterCommitString);\r
-\r
-      //\r
-      // If it is a selected numeric with manual input, display different message\r
-      //\r
-      if ((Statement->Operand == EFI_IFR_NUMERIC_OP) || \r
-          (Statement->Operand == EFI_IFR_DATE_OP) ||\r
-          (Statement->Operand == EFI_IFR_TIME_OP)) {\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
-      }\r
-\r
-      if (Statement->Operand == EFI_IFR_ORDERED_LIST_OP) {\r
-        PrintStringAt (StartColumnOfHelp, TopRowOfHelp, gPlusString);\r
-        PrintStringAt (ThdCol, TopRowOfHelp, gMinusString);\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
-    //\r
-    // On system setting, HotKey will show on every form.\r
-    //\r
-    if (gBrowserSettingScope == SystemLevel ||\r
-        (Selection->FormEditable && gFunctionKeySetting != NONE_FUNCTION_KEY_SETTING)) {\r
-      PrintHotKeyHelpString ();\r
-    }\r
-    if ((gClassOfVfr & FORMSET_CLASS_PLATFORM_SETUP) == FORMSET_CLASS_PLATFORM_SETUP) {\r
-      PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString);\r
-    }\r
+  UpdateDisplayFormData ();\r
 \r
-    PrintAt (StartColumnOfHelp, BottomRowOfHelp, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight);\r
-    PrintStringAt (SecCol, BottomRowOfHelp, gToggleCheckBox);\r
-    break;\r
+  //\r
+  // Three possible status maybe return.\r
+  //\r
+  // EFI_INVALID_PARAMETER: The input dimension info is not valid.\r
+  // EFI_NOT_FOUND:         The input value for oneof/orderedlist opcode is not valid\r
+  //                        and an valid value has return.\r
+  // EFI_SUCCESS:           Success shows form and get user input in UserInput paramenter.\r
+  //\r
+  Status = mFormDisplay->FormDisplay (&gDisplayFormData, &UserInput);\r
+  if (EFI_ERROR (Status) && Status != EFI_NOT_FOUND) {\r
+    FreeDisplayFormData();\r
+    return Status;\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
-  case EFI_IFR_SUBTITLE_OP:\r
-    ClearLines (LeftColumnOfHelp, RightColumnOfHelp, TopRowOfHelp, BottomRowOfHelp, KEYHELP_TEXT | KEYHELP_BACKGROUND);\r
+  //\r
+  // If status is EFI_SUCCESS, means user has change the highlight menu and new user input return.\r
+  //                           in this case, browser need to change the highlight menu.\r
+  // If status is EFI_NOT_FOUND, means the input DisplayFormData has error for oneof/orderedlist \r
+  //                          opcode and new valid value has return, browser core need to adjust\r
+  //                          value for this opcode and shows this form again.\r
+  //\r
+  ChangeHighlight = (Status == EFI_SUCCESS ? TRUE :FALSE);\r
 \r
-    if (!Selected) {\r
-      //\r
-      // On system setting, HotKey will show on every form.\r
-      //\r
-      if (gBrowserSettingScope == SystemLevel ||\r
-          (Selection->FormEditable && gFunctionKeySetting != NONE_FUNCTION_KEY_SETTING)) {\r
-        PrintHotKeyHelpString ();\r
-      }\r
-      if ((gClassOfVfr & FORMSET_CLASS_PLATFORM_SETUP) == FORMSET_CLASS_PLATFORM_SETUP) {\r
-        PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString);\r
-      }\r
+  Status = ProcessUserInput (&UserInput, ChangeHighlight);\r
 \r
-      PrintAt (StartColumnOfHelp, BottomRowOfHelp, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight);\r
-      if (Statement->Operand != EFI_IFR_TEXT_OP && Statement->Operand != EFI_IFR_SUBTITLE_OP) {\r
-        PrintStringAt (SecCol, BottomRowOfHelp, gEnterString);\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
-    }\r
-    break;\r
+  FreeDisplayFormData();\r
 \r
-  default:\r
-    break;\r
-  }\r
+  return Status;\r
 }\r
 \r
 /**\r
@@ -920,60 +1715,136 @@ FormUpdateNotify (
 }\r
 \r
 /**\r
-  check whether the formset need to update the NV.\r
+  Update the NV flag info for this form set.\r
 \r
   @param  FormSet                FormSet data structure.\r
 \r
-  @retval TRUE                   Need to update the NV.\r
-  @retval FALSE                  No need to update the NV.\r
 **/\r
-BOOLEAN \r
-IsNvUpdateRequired (\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
-    if (Form->NvUpdateRequired ) {\r
-      return TRUE;\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
-  check whether the formset need to update the NV.\r
+  Check whether the storage data for current form set is changed.\r
 \r
-  @param  FormSet                FormSet data structure.\r
-  @param  SetValue               Whether set new value or clear old value.\r
+  @param  FormSet           FormSet data structure.\r
 \r
+  @retval TRUE              Data is changed.\r
+  @retval FALSE             Data is not changed.\r
 **/\r
-VOID\r
-UpdateNvInfoInForm (\r
-  IN FORM_BROWSER_FORMSET  *FormSet,\r
-  IN BOOLEAN               SetValue\r
+BOOLEAN \r
+IsStorageDataChangedForFormSet (\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
+  FORMSET_STORAGE         *Storage;\r
+  BROWSER_STORAGE         *BrowserStorage;\r
+  CHAR16                  *ConfigRespNew;\r
+  CHAR16                  *ConfigRespOld;\r
+  BOOLEAN                 RetVal;\r
 \r
-    Form->NvUpdateRequired = SetValue;\r
+  RetVal        = FALSE;\r
+  ConfigRespNew = NULL;\r
+  ConfigRespOld = NULL;\r
 \r
-    Link = GetNextNode (&FormSet->FormListHead, Link);\r
+  //\r
+  // Request current settings from Configuration Driver\r
+  //\r
+  Link = GetFirstNode (&FormSet->StorageListHead);\r
+  while (!IsNull (&FormSet->StorageListHead, Link)) {\r
+    Storage = FORMSET_STORAGE_FROM_LINK (Link);\r
+    Link = GetNextNode (&FormSet->StorageListHead, Link);\r
+\r
+    BrowserStorage = Storage->BrowserStorage;\r
+\r
+    if (BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {\r
+      continue;\r
+    }\r
+\r
+    if (Storage->ElementCount == 0) {\r
+      continue;\r
+    }\r
+\r
+    StorageToConfigResp (BrowserStorage, &ConfigRespNew, Storage->ConfigRequest, TRUE);\r
+    StorageToConfigResp (BrowserStorage, &ConfigRespOld, Storage->ConfigRequest, FALSE);\r
+    ASSERT (ConfigRespNew != NULL && ConfigRespOld != NULL);\r
+\r
+    if (StrCmp (ConfigRespNew, ConfigRespOld) != 0) {\r
+      RetVal = TRUE;\r
+    }\r
+\r
+    FreePool (ConfigRespNew);\r
+    ConfigRespNew = NULL;\r
+\r
+    FreePool (ConfigRespOld);\r
+    ConfigRespOld = NULL;\r
+\r
+    if (RetVal) {\r
+      break;\r
+    }\r
   }\r
+\r
+  return RetVal;\r
 }\r
+\r
 /**\r
   Find menu which will show next time.\r
 \r
@@ -981,170 +1852,92 @@ UpdateNvInfoInForm (
                          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 Repaint         Whether need to repaint the menu.\r
-  @param NewLine         Whether need to show at new line.\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           Need return.\r
-  @retval FALSE          No need to return.\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     BOOLEAN              *Repaint, \r
-  IN     BOOLEAN              *NewLine  \r
+  IN OUT UI_MENU_SELECTION        *Selection,\r
+  IN       BROWSER_SETTING_SCOPE  SettingLevel\r
   )\r
 {\r
-  UI_MENU_LIST            *CurrentMenu;\r
-  CHAR16                  YesResponse;\r
-  CHAR16                  NoResponse;\r
-  EFI_INPUT_KEY           Key;\r
-  BROWSER_SETTING_SCOPE   Scope;\r
+  FORM_ENTRY_INFO            *CurrentMenu;\r
+  FORM_ENTRY_INFO            *ParentMenu;\r
+  BROWSER_SETTING_SCOPE      Scope;\r
   \r
   CurrentMenu = Selection->CurrentMenu;\r
+  ParentMenu  = NULL;\r
+  Scope       = FormSetLevel;\r
 \r
-  if (CurrentMenu != NULL && CurrentMenu->Parent != NULL) {\r
+  if (CurrentMenu != NULL && (ParentMenu = UiFindParentMenu(CurrentMenu)) != NULL) {\r
     //\r
     // we have a parent, so go to the parent menu\r
     //\r
-    if (CompareGuid (&CurrentMenu->FormSetGuid, &CurrentMenu->Parent->FormSetGuid)) {\r
-      //\r
-      // The parent menu and current menu are in the same formset\r
-      //\r
-      Selection->Action = UI_ACTION_REFRESH_FORM;\r
-      Scope             = FormLevel;\r
-    } else {\r
-      Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
-      CopyMem (&Selection->FormSetGuid, &CurrentMenu->Parent->FormSetGuid, sizeof (EFI_GUID));\r
-      Selection->Handle = CurrentMenu->Parent->HiiHandle;\r
-      Scope             = FormSetLevel;\r
-    }\r
-\r
-    //\r
-    // Form Level Check whether the data is changed.\r
-    //\r
-    if ((gBrowserSettingScope == FormLevel && Selection->Form->NvUpdateRequired) ||\r
-        (gBrowserSettingScope == FormSetLevel && IsNvUpdateRequired(Selection->FormSet) && Scope == FormSetLevel)) {\r
-      gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
-  \r
-      YesResponse = gYesResponse[0];\r
-      NoResponse  = gNoResponse[0];\r
-  \r
-      //\r
-      // If NV flag is up, prompt user\r
-      //\r
-      do {\r
-        CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gSaveChanges, gAreYouSure, gEmptyString);\r
-      } while\r
-      (\r
-        (Key.ScanCode != SCAN_ESC) &&\r
-        ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (NoResponse | UPPER_LOWER_CASE_OFFSET)) &&\r
-        ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (YesResponse | UPPER_LOWER_CASE_OFFSET))\r
-      );\r
-  \r
-      if (Key.ScanCode == SCAN_ESC) {\r
+    if (CompareGuid (&CurrentMenu->FormSetGuid, &ParentMenu->FormSetGuid)) {\r
+      if (SettingLevel == FormSetLevel) {\r
         //\r
-        // User hits the ESC key, Ingore. \r
+        // Find a menu which has different formset guid with current.\r
         //\r
-        if (Repaint != NULL) {\r
-          *Repaint = TRUE;\r
-        }\r
-        if (NewLine != NULL) {\r
-          *NewLine = TRUE;\r
+        while (CompareGuid (&CurrentMenu->FormSetGuid, &ParentMenu->FormSetGuid)) {\r
+          CurrentMenu = ParentMenu;\r
+          if ((ParentMenu = UiFindParentMenu(CurrentMenu)) == NULL) {\r
+            break;\r
+          }\r
         }\r
 \r
-        Selection->Action = UI_ACTION_NONE;\r
-        return FALSE;\r
-      }\r
-  \r
-      if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (YesResponse | UPPER_LOWER_CASE_OFFSET)) {\r
-        //\r
-        // If the user hits the YesResponse key\r
-        //\r
-        SubmitForm (Selection->FormSet, Selection->Form, Scope);\r
+        if (ParentMenu != NULL) {\r
+          Scope = FormSetLevel;\r
+        }\r
       } else {\r
-        //\r
-        // If the user hits the NoResponse key\r
-        //\r
-        DiscardForm (Selection->FormSet, Selection->Form, Scope);\r
+        Scope = FormLevel;\r
       }\r
+    } else {\r
+      Scope = FormSetLevel;\r
     }\r
-\r
-    Selection->Statement = NULL;\r
-\r
-    Selection->FormId = CurrentMenu->Parent->FormId;\r
-    Selection->QuestionId = CurrentMenu->Parent->QuestionId;\r
-\r
-    //\r
-    // Clear highlight record for this menu\r
-    //\r
-    CurrentMenu->QuestionId = 0;\r
-    return FALSE;\r
-  }\r
-\r
-  if ((gClassOfVfr & FORMSET_CLASS_FRONT_PAGE) == FORMSET_CLASS_FRONT_PAGE) {\r
-    //\r
-    // We never exit FrontPage, so skip the ESC\r
-    //\r
-    Selection->Action = UI_ACTION_NONE;\r
-    return FALSE;\r
   }\r
 \r
   //\r
-  // We are going to leave current FormSet, so check uncommited data in this FormSet\r
+  // Form Level Check whether the data is changed.\r
   //\r
-  if (gBrowserSettingScope != SystemLevel && IsNvUpdateRequired(Selection->FormSet)) {\r
-    gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
-\r
-    YesResponse = gYesResponse[0];\r
-    NoResponse  = gNoResponse[0];\r
-\r
-    //\r
-    // If NV flag is up, prompt user\r
-    //\r
-    do {\r
-      CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gSaveChanges, gAreYouSure, gEmptyString);\r
-    } while\r
-    (\r
-      (Key.ScanCode != SCAN_ESC) &&\r
-      ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (NoResponse | UPPER_LOWER_CASE_OFFSET)) &&\r
-      ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (YesResponse | UPPER_LOWER_CASE_OFFSET))\r
-    );\r
-\r
-    if (Key.ScanCode == SCAN_ESC) {\r
-      //\r
-      // User hits the ESC key\r
-      //\r
-      if (Repaint != NULL) {\r
-        *Repaint = TRUE;\r
-      }\r
-\r
-      if (NewLine != NULL) {\r
-        *NewLine = TRUE;\r
-      }\r
-\r
-      Selection->Action = UI_ACTION_NONE;\r
+  if ((gBrowserSettingScope == FormLevel && IsNvUpdateRequiredForForm (Selection->Form)) ||\r
+      (gBrowserSettingScope == FormSetLevel && IsNvUpdateRequiredForFormSet(Selection->FormSet) && Scope == FormSetLevel)) {\r
+    if (!ProcessChangedData(Selection, Scope)) {\r
       return FALSE;\r
     }\r
+  }\r
 \r
-    if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (YesResponse | UPPER_LOWER_CASE_OFFSET)) {\r
-      //\r
-      // If the user hits the YesResponse key\r
-      //\r
-      SubmitForm (Selection->FormSet, Selection->Form, FormSetLevel);\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
-      //\r
-      // If the user hits the NoResponse key\r
-      //\r
-      DiscardForm (Selection->FormSet, Selection->Form, FormSetLevel);\r
+      Selection->Action = UI_ACTION_REFRESH_FORMSET;\r
+      CopyMem (&Selection->FormSetGuid, &ParentMenu->FormSetGuid, sizeof (EFI_GUID));\r
+      Selection->Handle = ParentMenu->HiiHandle;\r
     }\r
-  }\r
 \r
-  Selection->Statement = NULL;\r
-  if (CurrentMenu != NULL) {\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
@@ -1246,17 +2039,17 @@ ProcessCallBackFunction (
         case EFI_BROWSER_ACTION_REQUEST_RESET:\r
           DiscardFormIsRequired = TRUE;\r
           gResetRequired = TRUE;\r
-          Selection->Action = UI_ACTION_EXIT;\r
+          NeedExit              = TRUE;\r
           break;\r
 \r
         case EFI_BROWSER_ACTION_REQUEST_SUBMIT:\r
           SubmitFormIsRequired = TRUE;\r
-          Selection->Action = UI_ACTION_EXIT;\r
+          NeedExit              = TRUE;\r
           break;\r
 \r
         case EFI_BROWSER_ACTION_REQUEST_EXIT:\r
           DiscardFormIsRequired = TRUE;\r
-          Selection->Action = UI_ACTION_EXIT;\r
+          NeedExit              = TRUE;\r
           break;\r
 \r
         case EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT:\r
@@ -1267,7 +2060,7 @@ ProcessCallBackFunction (
 \r
         case EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT:\r
           DiscardFormIsRequired = TRUE;\r
-          SettingLevel          = FormLevel;      \r
+          SettingLevel          = FormLevel;\r
           NeedExit              = TRUE;\r
           break;\r
 \r
@@ -1320,7 +2113,7 @@ ProcessCallBackFunction (
   }\r
 \r
   if (NeedExit) {\r
-    FindNextMenu (Selection, NULL, NULL);\r
+    FindNextMenu (Selection, SettingLevel);\r
   }\r
 \r
   return Status;\r
@@ -1400,9 +2193,7 @@ SetupBrowser (
   EFI_HANDLE                      NotifyHandle;\r
   FORM_BROWSER_STATEMENT          *Statement;\r
   EFI_HII_CONFIG_ACCESS_PROTOCOL  *ConfigAccess;\r
-  EFI_INPUT_KEY                   Key;\r
 \r
-  gMenuRefreshHead = NULL;\r
   ConfigAccess = Selection->FormSet->ConfigAccess;\r
 \r
   //\r
@@ -1423,21 +2214,17 @@ SetupBrowser (
   //\r
   // Initialize current settings of Questions in this FormSet\r
   //\r
-  Status = InitializeCurrentSetting (Selection->FormSet);\r
-  if (EFI_ERROR (Status)) {\r
-    goto Done;\r
-  }\r
+  InitializeCurrentSetting (Selection->FormSet);\r
 \r
   //\r
-  // Update gOldFormSet on maintain back up FormSet list.\r
-  // And, make gOldFormSet point to current FormSet. \r
+  // Initilize Action field.\r
   //\r
-  if (gOldFormSet != NULL) {\r
-    RemoveEntryList (&gOldFormSet->Link);\r
-    DestroyFormSet (gOldFormSet);\r
-  }\r
-  gOldFormSet = Selection->FormSet;\r
-  InsertTailList (&gBrowserFormSetList, &gOldFormSet->Link);\r
+  Selection->Action = UI_ACTION_REFRESH_FORM;\r
+\r
+  //\r
+  // Clean the mCurFakeQestId value is formset refreshed.\r
+  //\r
+  mCurFakeQestId = 0;\r
 \r
   do {\r
     //\r
@@ -1480,10 +2267,7 @@ SetupBrowser (
         //\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
+        gBrowserStatus = BROWSER_FORM_SUPPRESS;\r
         Status = EFI_NOT_FOUND;\r
         goto Done;\r
       }\r
@@ -1498,7 +2282,6 @@ SetupBrowser (
         ((Selection->Handle != mCurrentHiiHandle) ||\r
         (!CompareGuid (&Selection->FormSetGuid, &mCurrentFormSetGuid)) ||\r
         (Selection->FormId != mCurrentFormId))) {\r
-\r
       //\r
       // Keep current form information\r
       //\r
@@ -1511,12 +2294,6 @@ SetupBrowser (
         goto Done;\r
       }\r
 \r
-      //\r
-      // EXIT requests to close form.\r
-      //\r
-      if (Selection->Action == UI_ACTION_EXIT) {\r
-        goto Done;\r
-      }\r
       //\r
       // IFR is updated during callback of open form, force to reparse the IFR binary\r
       //\r
@@ -1535,12 +2312,6 @@ SetupBrowser (
       goto Done;\r
     }\r
 \r
-    //\r
-    // EXIT requests to close form.\r
-    //\r
-    if (Selection->Action == UI_ACTION_EXIT) {\r
-      goto Done;\r
-    }\r
     //\r
     // IFR is updated during callback of read value, force to reparse the IFR binary\r
     //\r
@@ -1550,15 +2321,10 @@ SetupBrowser (
       break;\r
     }\r
 \r
-    //\r
-    // Displays the Header and Footer borders\r
-    //\r
-    DisplayPageFrame (Selection);\r
-\r
     //\r
     // Display form\r
     //\r
-    Status = DisplayForm (Selection);\r
+    Status = DisplayForm ();\r
     if (EFI_ERROR (Status)) {\r
       goto Done;\r
     }\r
@@ -1568,20 +2334,16 @@ 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
       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, Statement, EFI_BROWSER_ACTION_CHANGING, FALSE);         \r
-        if (Statement->Operand == EFI_IFR_REF_OP && Selection->Action != UI_ACTION_EXIT) {\r
+        Status = ProcessCallBackFunction(Selection, Statement, EFI_BROWSER_ACTION_CHANGING, FALSE);\r
+        if (Statement->Operand == EFI_IFR_REF_OP) {\r
           //\r
           // Process dynamic update ref opcode.\r
           //\r
           if (!EFI_ERROR (Status)) {\r
-            Status = ProcessGotoOpCode(Statement, Selection, NULL, NULL);\r
+            Status = ProcessGotoOpCode(Statement, Selection);\r
           }\r
           \r
           //\r
@@ -1602,6 +2364,27 @@ SetupBrowser (
       }\r
     }\r
 \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 FormSetLevel:\r
+      case FormLevel:\r
+        FindNextMenu (Selection, gBrowserSettingScope);\r
+        break;\r
+\r
+      default:\r
+        break;\r
+      }\r
+\r
+      gExitRequired = FALSE;\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
index ed904161b619dd538b8ce296c83764791da2f225..c4dd18a04fd664e4320d71ffabad670625763088 100644 (file)
@@ -26,13 +26,21 @@ SETUP_DRIVER_PRIVATE_DATA  mPrivateData = {
     RegisterHotKey,\r
     RegiserExitHandler,\r
     SaveReminder\r
+  },\r
+  {\r
+    BROWSER_EXTENSION2_VERSION_1,\r
+    SetScope,\r
+    RegisterHotKey,\r
+    RegiserExitHandler,\r
+    IsBrowserDataModified,\r
+    ExecuteAction,\r
   }\r
 };\r
 \r
 EFI_HII_DATABASE_PROTOCOL         *mHiiDatabase;\r
-EFI_HII_STRING_PROTOCOL           *mHiiString;\r
 EFI_HII_CONFIG_ROUTING_PROTOCOL   *mHiiConfigRouting;\r
 EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *mPathFromText;\r
+EDKII_FORM_DISPLAY_ENGINE_PROTOCOL *mFormDisplay;\r
 \r
 UINTN           gBrowserContextCount = 0;\r
 LIST_ENTRY      gBrowserContextList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserContextList);\r
@@ -40,153 +48,261 @@ LIST_ENTRY      gBrowserFormSetList = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserFor
 LIST_ENTRY      gBrowserHotKeyList  = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserHotKeyList);\r
 LIST_ENTRY      gBrowserStorageList  = INITIALIZE_LIST_HEAD_VARIABLE (gBrowserStorageList);\r
 \r
-BANNER_DATA           *gBannerData;\r
-EFI_HII_HANDLE        gFrontPageHandle;\r
-UINTN                 gClassOfVfr;\r
-UINTN                 gFunctionKeySetting;\r
 BOOLEAN               gResetRequired;\r
-EFI_HII_HANDLE        gHiiHandle;\r
-UINT16                gDirection;\r
-EFI_SCREEN_DESCRIPTOR gScreenDimensions;\r
+BOOLEAN               gExitRequired;\r
 BROWSER_SETTING_SCOPE gBrowserSettingScope = FormSetLevel;\r
 BOOLEAN               mBrowserScopeFirstSet = TRUE;\r
 EXIT_HANDLER          ExitHandlerFunction = NULL;\r
-UINTN                 gFooterHeight;\r
 \r
 //\r
 // Browser Global Strings\r
 //\r
-CHAR16            *gSaveFailed;\r
-CHAR16            *gDiscardFailed;\r
-CHAR16            *gDefaultFailed;\r
-CHAR16            *gEnterString;\r
-CHAR16            *gEnterCommitString;\r
-CHAR16            *gEnterEscapeString;\r
-CHAR16            *gEscapeString;\r
-CHAR16            *gMoveHighlight;\r
-CHAR16            *gMakeSelection;\r
-CHAR16            *gDecNumericInput;\r
-CHAR16            *gHexNumericInput;\r
-CHAR16            *gToggleCheckBox;\r
-CHAR16            *gPromptForData;\r
-CHAR16            *gPromptForPassword;\r
-CHAR16            *gPromptForNewPassword;\r
-CHAR16            *gConfirmPassword;\r
-CHAR16            *gConfirmError;\r
-CHAR16            *gPassowordInvalid;\r
-CHAR16            *gPressEnter;\r
 CHAR16            *gEmptyString;\r
-CHAR16            *gAreYouSure;\r
-CHAR16            *gYesResponse;\r
-CHAR16            *gNoResponse;\r
-CHAR16            *gMiniString;\r
-CHAR16            *gPlusString;\r
-CHAR16            *gMinusString;\r
-CHAR16            *gAdjustNumber;\r
-CHAR16            *gSaveChanges;\r
-CHAR16            *gOptionMismatch;\r
-CHAR16            *gFormSuppress;\r
-CHAR16            *gProtocolNotFound;\r
 \r
 CHAR16            *mUnknownString = L"!";\r
 \r
-CHAR16            gPromptBlockWidth;\r
-CHAR16            gOptionBlockWidth;\r
-CHAR16            gHelpBlockWidth;\r
-\r
 EFI_GUID  gZeroGuid = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}};\r
 EFI_GUID  gSetupBrowserGuid = {\r
   0xab368524, 0xb60c, 0x495b, {0xa0, 0x9, 0x12, 0xe8, 0x5b, 0x1a, 0xea, 0x32}\r
 };\r
 \r
 FORM_BROWSER_FORMSET  *gOldFormSet = NULL;\r
+extern UINT32   gBrowserStatus;\r
+extern CHAR16   *gErrorInfo;\r
+extern FORM_DISPLAY_ENGINE_FORM gDisplayFormData;\r
+\r
+/**\r
+  Create a menu with specified formset GUID and form ID, and add it as a child\r
+  of the given parent menu.\r
+\r
+  @param  HiiHandle              Hii handle related to this formset.\r
+  @param  FormSetGuid            The Formset Guid of menu to be added.\r
+  @param  FormId                 The Form ID of menu to be added.\r
+  @param  QuestionId             The question id of this menu to be added.\r
+\r
+  @return A pointer to the newly added menu or NULL if memory is insufficient.\r
+\r
+**/\r
+FORM_ENTRY_INFO *\r
+UiAddMenuList (\r
+  IN EFI_HII_HANDLE       HiiHandle,\r
+  IN EFI_GUID             *FormSetGuid,\r
+  IN UINT16               FormId,\r
+  IN UINT16               QuestionId\r
+  )\r
+{\r
+  FORM_ENTRY_INFO  *MenuList;\r
+\r
+  MenuList = AllocateZeroPool (sizeof (FORM_ENTRY_INFO));\r
+  if (MenuList == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  MenuList->Signature = FORM_ENTRY_INFO_SIGNATURE;\r
+\r
+  MenuList->HiiHandle  = HiiHandle;\r
+  CopyMem (&MenuList->FormSetGuid, FormSetGuid, sizeof (EFI_GUID));\r
+  MenuList->FormId     = FormId;\r
+  MenuList->QuestionId = QuestionId;\r
 \r
-FUNCTIION_KEY_SETTING gFunctionKeySettingTable[] = {\r
   //\r
-  // Boot Manager\r
+  // If parent is not specified, it is the root Form of a Formset\r
   //\r
-  {\r
-    {\r
-      0x847bc3fe,\r
-      0xb974,\r
-      0x446d,\r
-      {\r
-        0x94,\r
-        0x49,\r
-        0x5a,\r
-        0xd5,\r
-        0x41,\r
-        0x2e,\r
-        0x99,\r
-        0x3b\r
+  InsertTailList (&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &MenuList->Link);\r
+\r
+  return MenuList;\r
+}\r
+\r
+/**\r
+  Return the form id for the input hiihandle and formset.\r
+\r
+  @param  HiiHandle              HiiHandle for FormSet.\r
+  @param  FormSetGuid            The Formset GUID of the menu to search.\r
+\r
+  @return First form's id for this form set.\r
+\r
+**/\r
+EFI_FORM_ID\r
+GetFirstFormId (\r
+  IN EFI_HII_HANDLE       HiiHandle,\r
+  IN EFI_GUID             *FormSetGuid\r
+  )\r
+{\r
+  LIST_ENTRY         *Link;\r
+  FORM_BROWSER_FORM  *Form;\r
+\r
+  Link = GetFirstNode (&gCurrentSelection->FormSet->FormListHead);\r
+  Form = FORM_BROWSER_FORM_FROM_LINK (Link);\r
+\r
+  return Form->FormId;\r
+}\r
+\r
+/**\r
+  Search Menu with given FormSetGuid and FormId in all cached menu list.\r
+\r
+  @param  HiiHandle              HiiHandle for FormSet.\r
+  @param  FormSetGuid            The Formset GUID of the menu to search.\r
+  @param  FormId                 The Form ID of menu to search.\r
+\r
+  @return A pointer to menu found or NULL if not found.\r
+\r
+**/\r
+FORM_ENTRY_INFO *\r
+UiFindMenuList (\r
+  IN EFI_HII_HANDLE       HiiHandle, \r
+  IN EFI_GUID             *FormSetGuid,\r
+  IN UINT16               FormId\r
+  )\r
+{\r
+  LIST_ENTRY         *Link;\r
+  FORM_ENTRY_INFO    *MenuList;\r
+  FORM_ENTRY_INFO    *RetMenu;\r
+  EFI_FORM_ID        FirstFormId;\r
+\r
+  RetMenu = NULL;\r
+\r
+  Link = GetFirstNode (&mPrivateData.FormBrowserEx2.FormViewHistoryHead);\r
+  while (!IsNull (&mPrivateData.FormBrowserEx2.FormViewHistoryHead, Link)) {\r
+    MenuList = FORM_ENTRY_INFO_FROM_LINK (Link);\r
+    Link = GetNextNode (&mPrivateData.FormBrowserEx2.FormViewHistoryHead, Link);\r
+    \r
+    //\r
+    // If already find the menu, free the menus behind it.\r
+    //\r
+    if (RetMenu != NULL) {\r
+      RemoveEntryList (&MenuList->Link);\r
+      FreePool (MenuList);\r
+      continue;\r
+    }\r
+\r
+    //\r
+    // Find the same FromSet.\r
+    //\r
+    if (MenuList->HiiHandle == HiiHandle) {\r
+      if (CompareGuid (&MenuList->FormSetGuid, &gZeroGuid)) {\r
+        //\r
+        // FormSetGuid is not specified.\r
+        //\r
+        RetMenu = MenuList;\r
+      } else if (CompareGuid (&MenuList->FormSetGuid, FormSetGuid)) {\r
+        if (MenuList->FormId == FormId) {\r
+          RetMenu = MenuList;\r
+        } else if (FormId == 0 || MenuList->FormId == 0 ) {\r
+          FirstFormId = GetFirstFormId (HiiHandle, FormSetGuid);\r
+          if ((FormId == 0 && FirstFormId == MenuList->FormId) || (MenuList->FormId ==0 && FirstFormId == FormId)) {\r
+            RetMenu = MenuList;\r
+          }\r
+        }\r
       }\r
-    },\r
-    NONE_FUNCTION_KEY_SETTING\r
-  },\r
+    }\r
+  }\r
+\r
+  return RetMenu;\r
+}\r
+\r
+/**\r
+  Find parent menu for current menu.\r
+\r
+  @param  CurrentMenu    Current Menu\r
+\r
+  @retval   The parent menu for current menu.\r
+**/\r
+FORM_ENTRY_INFO *\r
+UiFindParentMenu (\r
+  IN FORM_ENTRY_INFO  *CurrentMenu\r
+  )\r
+{\r
+  FORM_ENTRY_INFO    *ParentMenu;\r
+\r
+  ParentMenu = NULL;\r
+  if (CurrentMenu->Link.BackLink != &mPrivateData.FormBrowserEx2.FormViewHistoryHead) {\r
+    ParentMenu = FORM_ENTRY_INFO_FROM_LINK (CurrentMenu->Link.BackLink);\r
+  }\r
+\r
+  return ParentMenu;\r
+}\r
+\r
+/**\r
+  Free Menu list linked list.\r
+\r
+  @param  MenuListHead    One Menu list point in the menu list.\r
+\r
+**/\r
+VOID\r
+UiFreeMenuList (\r
+  LIST_ENTRY   *MenuListHead\r
+  )\r
+{\r
+  FORM_ENTRY_INFO    *MenuList;\r
+\r
+  while (!IsListEmpty (MenuListHead)) {\r
+    MenuList = FORM_ENTRY_INFO_FROM_LINK (MenuListHead->ForwardLink);\r
+    RemoveEntryList (&MenuList->Link);\r
+\r
+    FreePool (MenuList);\r
+  }\r
+}\r
+\r
+/**\r
+  Load all hii formset to the browser.\r
+\r
+**/\r
+VOID\r
+LoadAllHiiFormset (\r
+  VOID\r
+  )\r
+{\r
+  FORM_BROWSER_FORMSET    *LocalFormSet;\r
+  EFI_HII_HANDLE          *HiiHandles;\r
+  UINTN                   Index;\r
+  EFI_GUID                ZeroGuid;\r
+  EFI_STATUS              Status;\r
+\r
   //\r
-  // Device Manager\r
+  // Get all the Hii handles\r
   //\r
-  {\r
-    {\r
-      0x3ebfa8e6,\r
-      0x511d,\r
-      0x4b5b,\r
-      {\r
-        0xa9,\r
-        0x5f,\r
-        0xfb,\r
-        0x38,\r
-        0x26,\r
-        0xf,\r
-        0x1c,\r
-        0x27\r
-      }\r
-    },\r
-    NONE_FUNCTION_KEY_SETTING\r
-  },\r
+  HiiHandles = HiiGetHiiHandles (NULL);\r
+  ASSERT (HiiHandles != NULL);\r
+\r
   //\r
-  // BMM FormSet.\r
+  // Search for formset of each class type\r
   //\r
-  {\r
-    {\r
-      0x642237c7,\r
-      0x35d4,\r
-      0x472d,\r
-      {\r
-        0x83,\r
-        0x65,\r
-        0x12,\r
-        0xe0,\r
-        0xcc,\r
-        0xf2,\r
-        0x7a,\r
-        0x22\r
-      }\r
-    },\r
-    NONE_FUNCTION_KEY_SETTING\r
-  },\r
+  for (Index = 0; HiiHandles[Index] != NULL; Index++) {\r
+    //\r
+    // Check HiiHandles[Index] does exist in global maintain list.\r
+    //\r
+    if (GetFormSetFromHiiHandle (HiiHandles[Index]) != NULL) {\r
+      continue;\r
+    }\r
+\r
+    //\r
+    // Initilize FormSet Setting\r
+    //\r
+    LocalFormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET));\r
+    ASSERT (LocalFormSet != NULL);\r
+    ZeroMem (&ZeroGuid, sizeof (ZeroGuid));\r
+    Status = InitializeFormSet (HiiHandles[Index], &ZeroGuid, LocalFormSet);\r
+    if (EFI_ERROR (Status) || IsListEmpty (&LocalFormSet->FormListHead)) {\r
+      DestroyFormSet (LocalFormSet);\r
+      continue;\r
+    }\r
+    InitializeCurrentSetting (LocalFormSet);\r
+\r
+    //\r
+    // Initilize Questions' Value\r
+    //\r
+    Status = LoadFormSetConfig (NULL, LocalFormSet);\r
+    if (EFI_ERROR (Status)) {\r
+      DestroyFormSet (LocalFormSet);\r
+      continue;\r
+    }\r
+  }\r
+\r
   //\r
-  // BMM File Explorer FormSet.\r
+  // Free resources, and restore gOldFormSet and gClassOfVfr\r
   //\r
-  {\r
-    {\r
-      0x1f2d63e1,\r
-      0xfebd,\r
-      0x4dc7,\r
-      {\r
-        0x9c,\r
-        0xc5,\r
-        0xba,\r
-        0x2b,\r
-        0x1c,\r
-        0xef,\r
-        0x9c,\r
-        0x5b\r
-      }\r
-    },\r
-    NONE_FUNCTION_KEY_SETTING\r
-  },\r
-};\r
+  FreePool (HiiHandles);\r
+}\r
 \r
 /**\r
   This is the routine which an external caller uses to direct the browser\r
@@ -229,26 +345,14 @@ SendForm (
   UI_MENU_SELECTION             *Selection;\r
   UINTN                         Index;\r
   FORM_BROWSER_FORMSET          *FormSet;\r
-  LIST_ENTRY                    *Link;\r
+  FORM_ENTRY_INFO               *MenuList;\r
 \r
   //\r
-  // Calculate total number of Register HotKeys. \r
+  // If EDKII_FORM_DISPLAY_ENGINE_PROTOCOL not found, return EFI_UNSUPPORTED.\r
   //\r
-  Index = 0;\r
-  Link  = GetFirstNode (&gBrowserHotKeyList);\r
-  while (!IsNull (&gBrowserHotKeyList, Link)) {\r
-    Link = GetNextNode (&gBrowserHotKeyList, Link);\r
-    Index ++;\r
+  if (mFormDisplay == NULL) {\r
+    return EFI_UNSUPPORTED;\r
   }\r
-  //\r
-  // Show three HotKeys help information on one ROW.\r
-  //\r
-  gFooterHeight = FOOTER_HEIGHT + (Index / 3);\r
-\r
-  //\r
-  // Clean the history menu list.\r
-  //\r
-  InitializeListHead (&gMenuList);\r
 \r
   //\r
   // Save globals used by SendForm()\r
@@ -256,65 +360,10 @@ SendForm (
   SaveBrowserContext ();\r
 \r
   gResetRequired = FALSE;\r
-  Status = EFI_SUCCESS;\r
-  ZeroMem (&gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));\r
-\r
-  //\r
-  // Seed the dimensions in the global\r
-  //\r
-  gST->ConOut->QueryMode (\r
-                 gST->ConOut,\r
-                 gST->ConOut->Mode->Mode,\r
-                 &gScreenDimensions.RightColumn,\r
-                 &gScreenDimensions.BottomRow\r
-                 );\r
-\r
-  if (ScreenDimensions != NULL) {\r
-    //\r
-    // Check local dimension vs. global dimension.\r
-    //\r
-    if ((gScreenDimensions.RightColumn < ScreenDimensions->RightColumn) ||\r
-        (gScreenDimensions.BottomRow < ScreenDimensions->BottomRow)\r
-        ) {\r
-      Status = EFI_INVALID_PARAMETER;\r
-      goto Done;\r
-    } else {\r
-      //\r
-      // Local dimension validation.\r
-      //\r
-      if ((ScreenDimensions->RightColumn > ScreenDimensions->LeftColumn) &&\r
-          (ScreenDimensions->BottomRow > ScreenDimensions->TopRow) &&\r
-          ((ScreenDimensions->RightColumn - ScreenDimensions->LeftColumn) > 2) &&\r
-          (\r
-            (ScreenDimensions->BottomRow - ScreenDimensions->TopRow) > STATUS_BAR_HEIGHT +\r
-            SCROLL_ARROW_HEIGHT *\r
-            2 +\r
-            FRONT_PAGE_HEADER_HEIGHT +\r
-            gFooterHeight +\r
-            1\r
-          )\r
-        ) {\r
-        CopyMem (&gScreenDimensions, (VOID *) ScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR));\r
-      } else {\r
-        Status = EFI_INVALID_PARAMETER;\r
-        goto Done;\r
-      }\r
-    }\r
-  }\r
-\r
-  gOptionBlockWidth = (CHAR16) ((gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn) / 3);\r
-  gPromptBlockWidth = (CHAR16) (gOptionBlockWidth + LEFT_SKIPPED_COLUMNS);\r
-  gHelpBlockWidth   = (CHAR16) (gOptionBlockWidth - LEFT_SKIPPED_COLUMNS);\r
-\r
-  //\r
-  // Initialize the strings for the browser, upon exit of the browser, the strings will be freed\r
-  //\r
-  InitializeBrowserStrings ();\r
-\r
-  //\r
-  // Ensure we are in Text mode\r
-  //\r
-  gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
+  gExitRequired  = FALSE;\r
+  Status         = EFI_SUCCESS;\r
+  gEmptyString   = L"";\r
+  gDisplayFormData.ScreenDimensions = (EFI_SCREEN_DESCRIPTOR *) ScreenDimensions;\r
 \r
   for (Index = 0; Index < HandleCount; Index++) {\r
     Selection = AllocateZeroPool (sizeof (UI_MENU_SELECTION));\r
@@ -335,18 +384,13 @@ SendForm (
       //\r
       // Initialize internal data structures of FormSet\r
       //\r
-      Status = InitializeFormSet (Selection->Handle, &Selection->FormSetGuid, FormSet, TRUE);\r
+      Status = InitializeFormSet (Selection->Handle, &Selection->FormSetGuid, FormSet);\r
       if (EFI_ERROR (Status) || IsListEmpty (&FormSet->FormListHead)) {\r
         DestroyFormSet (FormSet);\r
         break;\r
       }\r
       Selection->FormSet = FormSet;\r
 \r
-      //\r
-      // Try to find pre FormSet in the maintain backup list.\r
-      //\r
-      gOldFormSet = GetFormSetFromHiiHandle (Selection->Handle);\r
-\r
       //\r
       // Display this formset\r
       //\r
@@ -356,27 +400,36 @@ SendForm (
 \r
       gCurrentSelection = NULL;\r
 \r
-      if (EFI_ERROR (Status)) {\r
-        break;\r
-      }\r
-\r
-    } while (Selection->Action == UI_ACTION_REFRESH_FORMSET);\r
-\r
-    if (gOldFormSet != NULL) {\r
       //\r
       // If no data is changed, don't need to save current FormSet into the maintain list.\r
       //\r
-      if (!IsNvUpdateRequired (gOldFormSet)) {\r
-        CleanBrowserStorage(gOldFormSet);\r
-        RemoveEntryList (&gOldFormSet->Link);\r
-        DestroyFormSet (gOldFormSet);\r
+      if (!IsNvUpdateRequiredForFormSet (FormSet) && !IsStorageDataChangedForFormSet(FormSet)) {\r
+        CleanBrowserStorage(FormSet);\r
+        RemoveEntryList (&FormSet->Link);\r
+        DestroyFormSet (FormSet);\r
       }\r
-      gOldFormSet = NULL;\r
-    }\r
+\r
+      if (EFI_ERROR (Status)) {\r
+        break;\r
+      }\r
+    } while (Selection->Action == UI_ACTION_REFRESH_FORMSET);\r
 \r
     FreePool (Selection);\r
   }\r
 \r
+  //\r
+  // Still has error info, pop up a message.\r
+  //\r
+  if (gBrowserStatus != BROWSER_SUCCESS) {\r
+    gDisplayFormData.BrowserStatus = gBrowserStatus;\r
+    gDisplayFormData.ErrorString   = gErrorInfo;\r
+\r
+    gBrowserStatus = BROWSER_SUCCESS;\r
+    gErrorInfo     = NULL;\r
+\r
+    mFormDisplay->FormDisplay (&gDisplayFormData, NULL);\r
+  }\r
+\r
   if (ActionRequest != NULL) {\r
     *ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;\r
     if (gResetRequired) {\r
@@ -384,13 +437,17 @@ SendForm (
     }\r
   }\r
 \r
-  FreeBrowserStrings ();\r
-  UiFreeMenuList(&gMenuList);\r
+  mFormDisplay->ExitDisplay();\r
 \r
-  gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
-  gST->ConOut->ClearScreen (gST->ConOut);\r
+  //\r
+  // Clear the menu history data.\r
+  //\r
+  while (!IsListEmpty (&mPrivateData.FormBrowserEx2.FormViewHistoryHead)) {\r
+    MenuList = FORM_ENTRY_INFO_FROM_LINK (mPrivateData.FormBrowserEx2.FormViewHistoryHead.ForwardLink);\r
+    RemoveEntryList (&MenuList->Link);\r
+    FreePool (MenuList);\r
+  }\r
 \r
-Done:\r
   //\r
   // Restore globals used by SendForm()\r
   //\r
@@ -399,10 +456,93 @@ Done:
   return Status;\r
 }\r
 \r
+/**\r
+  Get or set data to the storage.\r
+\r
+  @param  ResultsDataSize        The size of the buffer associatedwith ResultsData.\r
+  @param  ResultsData            A string returned from an IFR browser or\r
+                                 equivalent. The results string will have no\r
+                                 routing information in them.\r
+  @param  RetrieveData           A BOOLEAN field which allows an agent to retrieve\r
+                                 (if RetrieveData = TRUE) data from the uncommitted\r
+                                 browser state information or set (if RetrieveData\r
+                                 = FALSE) data in the uncommitted browser state\r
+                                 information.\r
+  @param  Storage                The pointer to the storage.\r
+\r
+  @retval EFI_SUCCESS            The results have been distributed or are awaiting\r
+                                 distribution.\r
+\r
+**/\r
+EFI_STATUS \r
+ProcessStorage (\r
+  IN OUT UINTN                         *ResultsDataSize,\r
+  IN OUT EFI_STRING                    *ResultsData,\r
+  IN BOOLEAN                           RetrieveData,\r
+  IN BROWSER_STORAGE                   *Storage\r
+  )\r
+{\r
+  CHAR16                *ConfigResp;\r
+  EFI_STATUS            Status;\r
+  CHAR16                *StrPtr;\r
+  UINTN                 BufferSize;\r
+  UINTN                 TmpSize;\r
+\r
+  if (RetrieveData) {\r
+    //\r
+    // Generate <ConfigResp>\r
+    //\r
+    Status = StorageToConfigResp (Storage, &ConfigResp, Storage->ConfigRequest, TRUE);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    //\r
+    // Skip <ConfigHdr> and '&' to point to <ConfigBody> when first copy the configbody.\r
+    // Also need to consider add "\0" at first time.\r
+    //\r
+    StrPtr     = ConfigResp + StrLen (Storage->ConfigHdr) + 1;\r
+    BufferSize = StrSize (StrPtr);\r
+\r
+\r
+    //\r
+    // Copy the data if the input buffer is bigger enough.\r
+    //\r
+    if (*ResultsDataSize >= BufferSize) {\r
+      StrCpy (*ResultsData, StrPtr);\r
+    }\r
+\r
+    *ResultsDataSize = BufferSize;\r
+    FreePool (ConfigResp);\r
+  } else {\r
+    //\r
+    // Prepare <ConfigResp>\r
+    //\r
+    TmpSize = StrLen (*ResultsData);\r
+    BufferSize = (TmpSize + StrLen (Storage->ConfigHdr) + 2) * sizeof (CHAR16);\r
+    ConfigResp = AllocateZeroPool (BufferSize);\r
+    ASSERT (ConfigResp != NULL);\r
+\r
+    StrCpy (ConfigResp, Storage->ConfigHdr);\r
+    StrCat (ConfigResp, L"&");\r
+    StrCat (ConfigResp, *ResultsData);\r
+\r
+    //\r
+    // Update Browser uncommited data\r
+    //\r
+    Status = ConfigRespToStorage (Storage, ConfigResp);\r
+    FreePool (ConfigResp);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
 \r
 /**\r
-  This function is called by a callback handler to retrieve uncommitted state\r
-  data from the browser.\r
+  This routine called this service in the browser to retrieve or set certain uncommitted \r
+  state information that resides in the open formsets. \r
 \r
   @param  This                   A pointer to the EFI_FORM_BROWSER2_PROTOCOL\r
                                  instance.\r
@@ -440,60 +580,69 @@ BrowserCallback (
 {\r
   EFI_STATUS            Status;\r
   LIST_ENTRY            *Link;\r
-  FORMSET_STORAGE       *Storage;\r
+  BROWSER_STORAGE       *Storage;\r
+  FORMSET_STORAGE       *FormsetStorage;\r
   FORM_BROWSER_FORMSET  *FormSet;\r
+  UINTN                 TotalSize;\r
   BOOLEAN               Found;\r
-  CHAR16                *ConfigResp;\r
-  CHAR16                *StrPtr;\r
-  UINTN                 BufferSize;\r
-  UINTN                 TmpSize;\r
 \r
   if (ResultsDataSize == NULL || ResultsData == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  if (gCurrentSelection == NULL) {\r
-    return EFI_NOT_READY;\r
-  }\r
-\r
-  Storage = NULL;\r
-  ConfigResp = NULL;\r
-  FormSet = gCurrentSelection->FormSet;\r
+  TotalSize = *ResultsDataSize;\r
+  Storage   = NULL;\r
+  Found     = FALSE;\r
+  Status    = EFI_SUCCESS;\r
 \r
   //\r
-  // Find target storage\r
+  // If set browser data, pre load all hii formset to avoid set the varstore which is not \r
+  // saved in browser.\r
   //\r
-  Link = GetFirstNode (&FormSet->StorageListHead);\r
-  if (IsNull (&FormSet->StorageListHead, Link)) {\r
-    return EFI_UNSUPPORTED;\r
+  if (!RetrieveData && (gBrowserSettingScope == SystemLevel)) {\r
+    LoadAllHiiFormset();\r
   }\r
 \r
   if (VariableGuid != NULL) {\r
     //\r
-    // Try to find target storage\r
+    // Try to find target storage in the current formset.\r
     //\r
-    Found = FALSE;\r
-    while (!IsNull (&FormSet->StorageListHead, Link)) {\r
-      Storage = FORMSET_STORAGE_FROM_LINK (Link);\r
-      Link = GetNextNode (&FormSet->StorageListHead, Link);\r
+    Link = GetFirstNode (&gBrowserStorageList);\r
+    while (!IsNull (&gBrowserStorageList, Link)) {\r
+      Storage = BROWSER_STORAGE_FROM_LINK (Link);\r
+      Link = GetNextNode (&gBrowserStorageList, Link);\r
+      //\r
+      // Check the current storage.\r
+      //\r
+      if (!CompareGuid (&Storage->Guid, (EFI_GUID *) VariableGuid)) {\r
+        continue;\r
+      }\r
 \r
-      if (CompareGuid (&Storage->BrowserStorage->Guid, (EFI_GUID *) VariableGuid)) {\r
-        if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_BUFFER ||\r
-            Storage->BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {\r
-          //\r
-          // Buffer storage require both GUID and Name\r
-          //\r
-          if (VariableName == NULL) {\r
-            return EFI_NOT_FOUND;\r
-          }\r
+      if (Storage->Type == EFI_HII_VARSTORE_BUFFER ||\r
+          Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {\r
+        //\r
+        // Buffer storage require both GUID and Name\r
+        //\r
+        if (VariableName == NULL) {\r
+          return EFI_NOT_FOUND;\r
+        }\r
 \r
-          if (StrCmp (Storage->BrowserStorage->Name, (CHAR16 *) VariableName) != 0) {\r
-            continue;\r
-          }\r
+        if (StrCmp (Storage->Name, (CHAR16 *) VariableName) != 0) {\r
+          continue;\r
         }\r
-        Found = TRUE;\r
-        break;\r
       }\r
+\r
+      Status = ProcessStorage (&TotalSize, &ResultsData, RetrieveData, Storage);\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+\r
+      //\r
+      // Different formsets may have same varstore, so here just set the flag\r
+      // not exit the circle.\r
+      // \r
+      Found = TRUE;\r
+      break;\r
     }\r
 \r
     if (!Found) {\r
@@ -503,65 +652,62 @@ BrowserCallback (
     //\r
     // GUID/Name is not specified, take the first storage in FormSet\r
     //\r
-    Storage = FORMSET_STORAGE_FROM_LINK (Link);\r
-  }\r
-\r
-  if (RetrieveData) {\r
-    //\r
-    // Skip if there is no RequestElement\r
-    //\r
-    if (Storage->ElementCount == 0) {\r
-      return EFI_SUCCESS;\r
+    if (gCurrentSelection == NULL) {\r
+      return EFI_NOT_READY;\r
     }\r
 \r
     //\r
     // Generate <ConfigResp>\r
     //\r
-    Status = StorageToConfigResp (Storage->BrowserStorage, &ConfigResp, Storage->ConfigRequest);\r
+    FormSet = gCurrentSelection->FormSet;\r
+    Link = GetFirstNode (&FormSet->StorageListHead);\r
+    if (IsNull (&FormSet->StorageListHead, Link)) {\r
+      return EFI_UNSUPPORTED;\r
+    }\r
+\r
+    FormsetStorage = FORMSET_STORAGE_FROM_LINK (Link);\r
+    \r
+    Status = ProcessStorage (&TotalSize, &ResultsData, RetrieveData, FormsetStorage->BrowserStorage);\r
     if (EFI_ERROR (Status)) {\r
       return Status;\r
     }\r
+  }\r
 \r
-    //\r
-    // Skip <ConfigHdr> and '&' to point to <ConfigBody>\r
-    //\r
-    StrPtr = ConfigResp + StrLen (Storage->BrowserStorage->ConfigHdr) + 1;\r
+  if (RetrieveData) {\r
+    Status = TotalSize <= *ResultsDataSize ? EFI_SUCCESS : EFI_BUFFER_TOO_SMALL;\r
+    *ResultsDataSize = TotalSize;\r
+  }\r
+   \r
+  return Status;\r
 \r
-    BufferSize = StrSize (StrPtr);\r
-    if (*ResultsDataSize < BufferSize) {\r
-      *ResultsDataSize = BufferSize;\r
+}\r
 \r
-      FreePool (ConfigResp);\r
-      return EFI_BUFFER_TOO_SMALL;\r
-    }\r
 \r
-    *ResultsDataSize = BufferSize;\r
-    CopyMem (ResultsData, StrPtr, BufferSize);\r
+/**\r
+  Callback function for SimpleTextInEx protocol install events\r
 \r
-    FreePool (ConfigResp);\r
-  } else {\r
-    //\r
-    // Prepare <ConfigResp>\r
-    //\r
-    TmpSize = StrLen (ResultsData);\r
-    BufferSize = (TmpSize + StrLen (Storage->BrowserStorage->ConfigHdr) + 2) * sizeof (CHAR16);\r
-    ConfigResp = AllocateZeroPool (BufferSize);\r
-    ASSERT (ConfigResp != NULL);\r
+  @param Event           the event that is signaled.\r
+  @param Context         not used here.\r
 \r
-    StrCpy (ConfigResp, Storage->BrowserStorage->ConfigHdr);\r
-    StrCat (ConfigResp, L"&");\r
-    StrCat (ConfigResp, ResultsData);\r
+**/\r
+VOID\r
+EFIAPI\r
+FormDisplayCallback (\r
+  IN EFI_EVENT    Event,\r
+  IN VOID         *Context\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
 \r
-    //\r
-    // Update Browser uncommited data\r
-    //\r
-    Status = ConfigRespToStorage (Storage->BrowserStorage, ConfigResp);\r
-    if (EFI_ERROR (Status)) {\r
-      return Status;\r
-    }\r
+  if (mFormDisplay != NULL) {\r
+    return;\r
   }\r
 \r
-  return EFI_SUCCESS;\r
+  Status = gBS->LocateProtocol (\r
+                  &gEdkiiFormDisplayEngineProtocolGuid,\r
+                  NULL,\r
+                  (VOID **) &mFormDisplay\r
+                  );\r
 }\r
 \r
 /**\r
@@ -582,8 +728,7 @@ InitializeSetup (
   )\r
 {\r
   EFI_STATUS                  Status;\r
-  EFI_INPUT_KEY               DefaultHotKey;\r
-  EFI_STRING                  HelpString;\r
+  VOID                        *Registration;\r
 \r
   //\r
   // Locate required Hii relative protocols\r
@@ -595,13 +740,6 @@ InitializeSetup (
                   );\r
   ASSERT_EFI_ERROR (Status);\r
 \r
-  Status = gBS->LocateProtocol (\r
-                  &gEfiHiiStringProtocolGuid,\r
-                  NULL,\r
-                  (VOID **) &mHiiString\r
-                  );\r
-  ASSERT_EFI_ERROR (Status);\r
-\r
   Status = gBS->LocateProtocol (\r
                   &gEfiHiiConfigRoutingProtocolGuid,\r
                   NULL,\r
@@ -615,30 +753,6 @@ InitializeSetup (
                   (VOID **) &mPathFromText\r
                   );\r
 \r
-  //\r
-  // Publish our HII data\r
-  //\r
-  gHiiHandle = HiiAddPackages (\r
-                 &gSetupBrowserGuid,\r
-                 ImageHandle,\r
-                 SetupBrowserStrings,\r
-                 NULL\r
-                 );\r
-  ASSERT (gHiiHandle != NULL);\r
-\r
-  //\r
-  // Initialize Driver private data\r
-  //\r
-  gBannerData = AllocateZeroPool (sizeof (BANNER_DATA));\r
-  ASSERT (gBannerData != NULL);\r
-  \r
-  //\r
-  // Initialize generic help strings.\r
-  //\r
-  gSaveFailed    = GetToken (STRING_TOKEN (SAVE_FAILED), gHiiHandle);\r
-  gDiscardFailed = GetToken (STRING_TOKEN (DISCARD_FAILED), gHiiHandle);\r
-  gDefaultFailed = GetToken (STRING_TOKEN (DEFAULT_FAILED), gHiiHandle);\r
-\r
   //\r
   // Install FormBrowser2 protocol\r
   //\r
@@ -652,34 +766,45 @@ InitializeSetup (
   ASSERT_EFI_ERROR (Status);\r
 \r
   //\r
-  // Install default HotKey F10 for Save\r
-  //\r
-  DefaultHotKey.UnicodeChar = CHAR_NULL;\r
-  HelpString             = GetToken (STRING_TOKEN (FUNCTION_TEN_STRING), gHiiHandle);\r
-  DefaultHotKey.ScanCode = SCAN_F10;\r
-  RegisterHotKey (&DefaultHotKey, BROWSER_ACTION_SUBMIT, 0, HelpString);\r
-  FreePool (HelpString);\r
-  //\r
-  // Install default HotKey F9 for Reset To Defaults\r
-  //\r
-  DefaultHotKey.ScanCode    = SCAN_F9;\r
-  HelpString                = GetToken (STRING_TOKEN (FUNCTION_NINE_STRING), gHiiHandle);\r
-  RegisterHotKey (&DefaultHotKey, BROWSER_ACTION_DEFAULT, EFI_HII_DEFAULT_CLASS_STANDARD, HelpString);\r
-  FreePool (HelpString);\r
-\r
-  //\r
-  // Install FormBrowserEx protocol\r
+  // Install FormBrowserEx2 protocol\r
   //\r
+  InitializeListHead (&mPrivateData.FormBrowserEx2.FormViewHistoryHead);  \r
   mPrivateData.Handle = NULL;\r
+  Status = gBS->InstallProtocolInterface (\r
+                  &mPrivateData.Handle,\r
+                  &gEdkiiFormBrowserEx2ProtocolGuid,\r
+                  EFI_NATIVE_INTERFACE,\r
+                  &mPrivateData.FormBrowserEx2\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+  \r
   Status = gBS->InstallProtocolInterface (\r
                   &mPrivateData.Handle,\r
                   &gEfiFormBrowserExProtocolGuid,\r
                   EFI_NATIVE_INTERFACE,\r
                   &mPrivateData.FormBrowserEx\r
                   );\r
-  ASSERT_EFI_ERROR (Status);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  InitializeDisplayFormData ();\r
+\r
+  Status = gBS->LocateProtocol (\r
+                  &gEdkiiFormDisplayEngineProtocolGuid,\r
+                  NULL,\r
+                  (VOID **) &mFormDisplay\r
+                  );\r
 \r
-  return Status;\r
+  if (EFI_ERROR (Status)) {\r
+    EfiCreateProtocolNotifyEvent (\r
+      &gEdkiiFormDisplayEngineProtocolGuid,\r
+      TPL_CALLBACK,\r
+      FormDisplayCallback,\r
+      NULL,\r
+      &Registration\r
+      );\r
+  }\r
+  \r
+  return EFI_SUCCESS;\r
 }\r
 \r
 \r
@@ -815,58 +940,6 @@ NewStringCat (
   *Dest = NewString;\r
 }\r
 \r
-\r
-/**\r
-  Synchronize or restore Storage's Edit copy and Shadow copy.\r
-\r
-  @param  Storage          The Storage to be synchronized.\r
-  @param  SyncOrRestore    Sync the buffer to editbuffer or Restore  the \r
-                           editbuffer to buffer\r
-                           if TRUE, copy the editbuffer to the buffer.\r
-                           if FALSE, copy the buffer to the editbuffer.\r
-\r
-**/\r
-VOID\r
-SynchronizeStorage (\r
-  IN BROWSER_STORAGE         *Storage,\r
-  IN BOOLEAN                 SyncOrRestore\r
-  )\r
-{\r
-  LIST_ENTRY              *Link;\r
-  NAME_VALUE_NODE         *Node;\r
-\r
-  switch (Storage->Type) {\r
-  case EFI_HII_VARSTORE_BUFFER:\r
-  case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:\r
-    if (SyncOrRestore) {\r
-      CopyMem (Storage->Buffer, Storage->EditBuffer, Storage->Size);\r
-    } else {\r
-      CopyMem (Storage->EditBuffer, Storage->Buffer, Storage->Size);\r
-    }\r
-    break;\r
-\r
-  case EFI_HII_VARSTORE_NAME_VALUE:\r
-    Link = GetFirstNode (&Storage->NameValueListHead);\r
-    while (!IsNull (&Storage->NameValueListHead, Link)) {\r
-      Node = NAME_VALUE_NODE_FROM_LINK (Link);\r
-\r
-      if (SyncOrRestore) {\r
-        NewStringCpy (&Node->Value, Node->EditValue);\r
-      } else {\r
-        NewStringCpy (&Node->EditValue, Node->Value);\r
-      }\r
-\r
-      Link = GetNextNode (&Storage->NameValueListHead, Link);\r
-    }\r
-    break;\r
-\r
-  case EFI_HII_VARSTORE_EFI_VARIABLE:\r
-  default:\r
-    break;\r
-  }\r
-}\r
-\r
-\r
 /**\r
   Get Value for given Name from a NameValue Storage.\r
 \r
@@ -923,6 +996,7 @@ GetValueByName (
   @param  Name                   The Name.\r
   @param  Value                  The Value to set.\r
   @param  SetValueTo             Whether update editValue or Value.\r
+  @param  ReturnNode             The node use the input name.\r
 \r
   @retval EFI_SUCCESS            Value found for given Name.\r
   @retval EFI_NOT_FOUND          No such Name found in NameValue storage.\r
@@ -930,10 +1004,11 @@ GetValueByName (
 **/\r
 EFI_STATUS\r
 SetValueByName (\r
-  IN BROWSER_STORAGE         *Storage,\r
-  IN CHAR16                  *Name,\r
-  IN CHAR16                  *Value,\r
-  IN GET_SET_QUESTION_VALUE_WITH SetValueTo\r
+  IN  BROWSER_STORAGE             *Storage,\r
+  IN  CHAR16                      *Name,\r
+  IN  CHAR16                      *Value,\r
+  IN  GET_SET_QUESTION_VALUE_WITH SetValueTo,\r
+  OUT NAME_VALUE_NODE             **ReturnNode\r
   )\r
 {\r
   LIST_ENTRY              *Link;\r
@@ -964,6 +1039,11 @@ SetValueByName (
       } else {\r
         Node->Value = Buffer;\r
       }\r
+\r
+      if (ReturnNode != NULL) {\r
+        *ReturnNode = Node;\r
+      }\r
+\r
       return EFI_SUCCESS;\r
     }\r
 \r
@@ -980,6 +1060,7 @@ SetValueByName (
   @param  Storage                The Storage to be conveted.\r
   @param  ConfigResp             The returned <ConfigResp>.\r
   @param  ConfigRequest          The ConfigRequest string.\r
+  @param  GetEditBuf             Get the data from editbuffer or buffer.\r
 \r
   @retval EFI_SUCCESS            Convert success.\r
   @retval EFI_INVALID_PARAMETER  Incorrect storage type.\r
@@ -989,23 +1070,26 @@ EFI_STATUS
 StorageToConfigResp (\r
   IN BROWSER_STORAGE         *Storage,\r
   IN CHAR16                  **ConfigResp,\r
-  IN CHAR16                  *ConfigRequest\r
+  IN CHAR16                  *ConfigRequest,\r
+  IN BOOLEAN                 GetEditBuf\r
   )\r
 {\r
   EFI_STATUS              Status;\r
   EFI_STRING              Progress;\r
   LIST_ENTRY              *Link;\r
   NAME_VALUE_NODE         *Node;\r
+  UINT8                   *SourceBuf;\r
 \r
   Status = EFI_SUCCESS;\r
 \r
   switch (Storage->Type) {\r
   case EFI_HII_VARSTORE_BUFFER:\r
   case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:\r
+    SourceBuf = GetEditBuf ? Storage->EditBuffer : Storage->Buffer;\r
     Status = mHiiConfigRouting->BlockToConfig (\r
                                   mHiiConfigRouting,\r
                                   ConfigRequest,\r
-                                  Storage->EditBuffer,\r
+                                  SourceBuf,\r
                                   Storage->Size,\r
                                   ConfigResp,\r
                                   &Progress\r
@@ -1024,7 +1108,11 @@ StorageToConfigResp (
         NewStringCat (ConfigResp, L"&");\r
         NewStringCat (ConfigResp, Node->Name);\r
         NewStringCat (ConfigResp, L"=");\r
-        NewStringCat (ConfigResp, Node->EditValue);\r
+        if (GetEditBuf) {\r
+          NewStringCat (ConfigResp, Node->EditValue);\r
+        } else {\r
+          NewStringCat (ConfigResp, Node->Value);\r
+        }\r
       }\r
       Link = GetNextNode (&Storage->NameValueListHead, Link);\r
     }\r
@@ -1105,7 +1193,7 @@ ConfigRespToStorage (
       if (StrPtr != NULL) {\r
         *StrPtr = 0;\r
       }\r
-      SetValueByName (Storage, Name, Value, GetSetValueWithEditBuffer);\r
+      SetValueByName (Storage, Name, Value, GetSetValueWithEditBuffer, NULL);\r
     }\r
     break;\r
 \r
@@ -1531,7 +1619,7 @@ GetQuestionValue (
     if (IsBufferStorage) {\r
       CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Dst, StorageWidth);\r
     } else {\r
-      SetValueByName (Storage, Question->VariableName, Value, GetSetValueWithEditBuffer);\r
+      SetValueByName (Storage, Question->VariableName, Value, GetSetValueWithEditBuffer, NULL);\r
     }\r
 \r
     if (Result != NULL) {\r
@@ -1581,8 +1669,10 @@ SetQuestionValue (
   CHAR16              *TemName;\r
   CHAR16              *TemString;\r
   UINTN               Index;\r
+  NAME_VALUE_NODE     *Node;\r
 \r
   Status = EFI_SUCCESS;\r
+  Node   = NULL;\r
 \r
   if (SetValueTo >= GetSetValueWithMax) {\r
     return EFI_INVALID_PARAMETER;\r
@@ -1717,6 +1807,14 @@ SetQuestionValue (
         //     \r
         CopyMem (Storage->Buffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth);\r
       }\r
+      //\r
+      // Check whether question value has been changed.\r
+      //\r
+      if (CompareMem (Storage->Buffer + Question->VarStoreInfo.VarOffset, Storage->EditBuffer + Question->VarStoreInfo.VarOffset, StorageWidth) != 0) {\r
+        Question->ValueChanged = TRUE;\r
+      } else {\r
+        Question->ValueChanged = FALSE;\r
+      }\r
     } else {\r
       if (IsString) {\r
         //\r
@@ -1748,8 +1846,19 @@ SetQuestionValue (
         }\r
       }\r
 \r
-      Status = SetValueByName (Storage, Question->VariableName, Value, SetValueTo);\r
+      Status = SetValueByName (Storage, Question->VariableName, Value, SetValueTo, &Node);\r
       FreePool (Value);\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+      //\r
+      // Check whether question value has been changed.\r
+      //\r
+      if (StrCmp (Node->Value, Node->EditValue) != 0) {\r
+        Question->ValueChanged = TRUE;\r
+      } else {\r
+        Question->ValueChanged = FALSE;\r
+      }\r
     }\r
   } else if (SetValueTo == GetSetValueWithHiiDriver) {\r
     if (Storage->Type == EFI_HII_VARSTORE_BUFFER || Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {\r
@@ -1868,12 +1977,12 @@ SetQuestionValue (
 \r
 \r
 /**\r
-  Perform inconsistent check for a Form.\r
+  Perform nosubmitif check for a Form.\r
 \r
   @param  FormSet                FormSet data structure.\r
   @param  Form                   Form data structure.\r
   @param  Question               The Question to be validated.\r
-  @param  Type                   Validation type: InConsistent or NoSubmit\r
+  @param  Type                   Validation type: NoSubmit\r
 \r
   @retval EFI_SUCCESS            Form validation pass.\r
   @retval other                  Form validation failed.\r
@@ -1891,12 +2000,9 @@ ValidateQuestion (
   LIST_ENTRY              *Link;\r
   LIST_ENTRY              *ListHead;\r
   EFI_STRING              PopUp;\r
-  EFI_INPUT_KEY           Key;\r
   FORM_EXPRESSION         *Expression;\r
 \r
-  if (Type == EFI_HII_EXPRESSION_INCONSISTENT_IF) {\r
-    ListHead = &Question->InconsistentListHead;\r
-  } else if (Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF) {\r
+  if (Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF) {\r
     ListHead = &Question->NoSubmitListHead;\r
   } else {\r
     return EFI_UNSUPPORTED;\r
@@ -1920,10 +2026,10 @@ ValidateQuestion (
       //\r
       if (Expression->Error != 0) {\r
         PopUp = GetToken (Expression->Error, FormSet->HiiHandle);\r
-        do {\r
-          CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, PopUp, gPressEnter, gEmptyString);\r
-        } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
-        FreePool (PopUp);\r
+        if (Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF) {\r
+          gBrowserStatus = BROWSER_NO_SUBMIT_IF;\r
+          gErrorInfo     = PopUp;\r
+        }\r
       }\r
 \r
       return EFI_NOT_READY;\r
@@ -1987,7 +2093,8 @@ NoSubmitCheck (
   Fill storage's edit copy with settings requested from Configuration Driver.\r
 \r
   @param  FormSet                FormSet data structure.\r
-  @param  ConfigInfo             The config info related to this form.\r
+  @param  Storage                The storage which need to sync.\r
+  @param  ConfigRequest          The config request string which used to sync storage.\r
   @param  SyncOrRestore          Sync the buffer to editbuffer or Restore  the \r
                                  editbuffer to buffer\r
                                  if TRUE, copy the editbuffer to the buffer.\r
@@ -1997,10 +2104,11 @@ NoSubmitCheck (
 \r
 **/\r
 EFI_STATUS\r
-SynchronizeStorageForForm (\r
-  IN FORM_BROWSER_FORMSET        *FormSet,\r
-  IN FORM_BROWSER_CONFIG_REQUEST *ConfigInfo,\r
-  IN BOOLEAN                     SyncOrRestore\r
+SynchronizeStorage (\r
+  IN  FORM_BROWSER_FORMSET        *FormSet,\r
+  OUT BROWSER_STORAGE             *Storage,\r
+  IN  CHAR16                      *ConfigRequest,\r
+  IN  BOOLEAN                     SyncOrRestore\r
   )\r
 {\r
   EFI_STATUS              Status;\r
@@ -2014,57 +2122,52 @@ SynchronizeStorageForForm (
 \r
   Status = EFI_SUCCESS;\r
   Result = NULL;\r
-  if (FormSet->ConfigAccess == NULL && ConfigInfo->Storage->Type != EFI_HII_VARSTORE_NAME_VALUE) {\r
-    return EFI_NOT_FOUND;\r
-  }\r
-\r
-  if (ConfigInfo->ElementCount == 0) {\r
-    //\r
-    // Skip if there is no RequestElement\r
-    //\r
-    return EFI_SUCCESS;\r
-  }\r
 \r
-  if (ConfigInfo->Storage->Type == EFI_HII_VARSTORE_BUFFER || \r
-      (ConfigInfo->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {\r
-    BufferSize = ConfigInfo->Storage->Size;\r
+  if (Storage->Type == EFI_HII_VARSTORE_BUFFER || \r
+      (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {\r
+    BufferSize = Storage->Size;\r
 \r
     if (SyncOrRestore) {\r
-      Src = ConfigInfo->Storage->EditBuffer;\r
-      Dst = ConfigInfo->Storage->Buffer;\r
+      Src = Storage->EditBuffer;\r
+      Dst = Storage->Buffer;\r
     } else {\r
-      Src = ConfigInfo->Storage->Buffer;\r
-      Dst = ConfigInfo->Storage->EditBuffer;\r
+      Src = Storage->Buffer;\r
+      Dst = Storage->EditBuffer;\r
     }\r
 \r
-    Status = mHiiConfigRouting->BlockToConfig(\r
-                                  mHiiConfigRouting,\r
-                                  ConfigInfo->ConfigRequest,\r
-                                  Src,\r
-                                  BufferSize,\r
-                                  &Result,\r
-                                  &Progress\r
-                                  );\r
-    if (EFI_ERROR (Status)) {\r
-      return Status;\r
-    }\r
+    if (ConfigRequest != NULL) {\r
+      Status = mHiiConfigRouting->BlockToConfig(\r
+                                    mHiiConfigRouting,\r
+                                    ConfigRequest,\r
+                                    Src,\r
+                                    BufferSize,\r
+                                    &Result,\r
+                                    &Progress\r
+                                    );\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
 \r
-    Status = mHiiConfigRouting->ConfigToBlock (\r
-                                  mHiiConfigRouting,\r
-                                  Result,\r
-                                  Dst,\r
-                                  &BufferSize,\r
-                                  &Progress\r
-                                  );\r
-    if (Result != NULL) {\r
-      FreePool (Result);\r
+      Status = mHiiConfigRouting->ConfigToBlock (\r
+                                    mHiiConfigRouting,\r
+                                    Result,\r
+                                    Dst,\r
+                                    &BufferSize,\r
+                                    &Progress\r
+                                    );\r
+      if (Result != NULL) {\r
+        FreePool (Result);\r
+      }\r
+    } else {\r
+      CopyMem (Dst, Src, BufferSize);\r
     }\r
-  } else if (ConfigInfo->Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {\r
-    Link = GetFirstNode (&ConfigInfo->Storage->NameValueListHead);\r
-    while (!IsNull (&ConfigInfo->Storage->NameValueListHead, Link)) {\r
+  } else if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {\r
+    Link = GetFirstNode (&Storage->NameValueListHead);\r
+    while (!IsNull (&Storage->NameValueListHead, Link)) {\r
       Node = NAME_VALUE_NODE_FROM_LINK (Link);\r
 \r
-      if (StrStr (ConfigInfo->ConfigRequest, Node->Name) != NULL) {\r
+      if ((ConfigRequest != NULL && StrStr (ConfigRequest, Node->Name) != NULL) ||\r
+          (ConfigRequest == NULL)) {\r
         if (SyncOrRestore) {\r
           NewStringCpy (&Node->Value, Node->EditValue);\r
         } else {\r
@@ -2072,7 +2175,7 @@ SynchronizeStorageForForm (
         }\r
       }\r
 \r
-      Link = GetNextNode (&ConfigInfo->Storage->NameValueListHead, Link);\r
+      Link = GetNextNode (&Storage->NameValueListHead, Link);\r
     }\r
   }\r
 \r
@@ -2095,20 +2198,9 @@ SendDiscardInfoToDriver (
 {\r
   LIST_ENTRY                  *Link;\r
   FORM_BROWSER_STATEMENT      *Question;\r
-  EFI_STATUS                  Status;\r
-  EFI_HII_VALUE               HiiValue;\r
-  UINT8                       *BufferValue;\r
-  BOOLEAN                     ValueChanged;\r
   EFI_IFR_TYPE_VALUE          *TypeValue;\r
   EFI_BROWSER_ACTION_REQUEST  ActionRequest;\r
 \r
-  ValueChanged = FALSE;\r
-  BufferValue  = NULL;\r
-\r
-  if(!Form->NvUpdateRequired) {\r
-    return;\r
-  }\r
-\r
   Link = GetFirstNode (&Form->StatementListHead);\r
   while (!IsNull (&Form->StatementListHead, Link)) {\r
     Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);\r
@@ -2122,45 +2214,10 @@ SendDiscardInfoToDriver (
       continue;\r
     }\r
 \r
-    if (Question->BufferValue != NULL) {\r
-      BufferValue = AllocateZeroPool (Question->StorageWidth);\r
-      ASSERT (BufferValue != NULL);\r
-      CopyMem (BufferValue, Question->BufferValue, Question->StorageWidth);\r
-    } else {\r
-      HiiValue.Type = Question->HiiValue.Type;\r
-      CopyMem (&HiiValue.Value, &Question->HiiValue.Value, sizeof (EFI_IFR_TYPE_VALUE));\r
-    }\r
-\r
-    Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithBuffer);\r
-    if (EFI_ERROR (Status)) {\r
-      if (BufferValue != NULL) {\r
-        FreePool (BufferValue);\r
-        BufferValue = NULL;\r
-      }\r
-      continue;\r
-    }\r
-\r
-    if (Question->BufferValue != NULL) {\r
-      if (CompareMem (BufferValue, Question->BufferValue, Question->StorageWidth)) {\r
-        ValueChanged = TRUE;\r
-      }\r
-    } else {\r
-      if (CompareMem (&HiiValue.Value, &Question->HiiValue.Value, sizeof (EFI_IFR_TYPE_VALUE))) {\r
-        ValueChanged = TRUE;\r
-      }\r
-    }\r
-\r
-    if (BufferValue != NULL) {\r
-      FreePool (BufferValue);\r
-      BufferValue = NULL;\r
-    }\r
-\r
-    if (!ValueChanged) {\r
+    if (!Question->ValueChanged) {\r
       continue;\r
     }\r
 \r
-    ValueChanged = FALSE;\r
-\r
     if (Question->HiiValue.Type == EFI_IFR_TYPE_BUFFER) {\r
       TypeValue = (EFI_IFR_TYPE_VALUE *) Question->BufferValue;\r
     } else {\r
@@ -2225,6 +2282,78 @@ ValidateFormSet (
 \r
   return Find;\r
 }\r
+/**\r
+  Check whether need to enable the reset flag in form level.\r
+  Also clean all ValueChanged flag in question.\r
+\r
+  @param  SetFlag                Whether need to set the Reset Flag.\r
+  @param  Form                   Form data structure.\r
+\r
+**/\r
+VOID\r
+UpdateFlagForForm (\r
+  IN BOOLEAN                          SetFlag,\r
+  IN FORM_BROWSER_FORM                *Form\r
+  )\r
+{\r
+  LIST_ENTRY              *Link;\r
+  FORM_BROWSER_STATEMENT  *Question;\r
+  BOOLEAN                 FindOne;\r
+\r
+  FindOne = FALSE;\r
+  Link = GetFirstNode (&Form->StatementListHead);\r
+  while (!IsNull (&Form->StatementListHead, Link)) {\r
+    Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);\r
+  \r
+    if (SetFlag && Question->ValueChanged && ((Question->QuestionFlags & EFI_IFR_FLAG_RESET_REQUIRED) != 0)) {\r
+      gResetRequired = TRUE;\r
+    } \r
+\r
+    if (Question->ValueChanged) {\r
+      Question->ValueChanged = FALSE;\r
+    }\r
+  \r
+    Link = GetNextNode (&Form->StatementListHead, Link);\r
+  }\r
+}\r
+\r
+/**\r
+  Check whether need to enable the reset flag.\r
+  Also clean ValueChanged flag for all statements.\r
+\r
+  Form level or formset level, only one.\r
+  \r
+  @param  SetFlag                Whether need to set the Reset Flag.\r
+  @param  FormSet                FormSet data structure.\r
+  @param  Form                   Form data structure.\r
+\r
+**/\r
+VOID\r
+ValueChangeResetFlagUpdate (\r
+  IN BOOLEAN                          SetFlag,\r
+  IN FORM_BROWSER_FORMSET             *FormSet,\r
+  IN FORM_BROWSER_FORM                *Form  \r
+  )\r
+{\r
+  FORM_BROWSER_FORM       *CurrentForm;\r
+  LIST_ENTRY              *Link;\r
+\r
+  //\r
+  // Form != NULL means only check form level.\r
+  //\r
+  if (Form != NULL) {\r
+    UpdateFlagForForm(SetFlag, Form);\r
+    return;\r
+  }\r
+\r
+  Link = GetFirstNode (&FormSet->FormListHead);\r
+  while (!IsNull (&FormSet->FormListHead, Link)) {\r
+    CurrentForm = FORM_BROWSER_FORM_FROM_LINK (Link);\r
+    Link = GetNextNode (&FormSet->FormListHead, Link);\r
+\r
+    UpdateFlagForForm(SetFlag, CurrentForm);\r
+  }\r
+}\r
 \r
 /**\r
   Discard data based on the input setting scope (Form, FormSet or System).\r
@@ -2256,7 +2385,7 @@ DiscardForm (
     return EFI_UNSUPPORTED;\r
   }\r
 \r
-  if (SettingScope == FormLevel && Form->NvUpdateRequired) {\r
+  if (SettingScope == FormLevel && IsNvUpdateRequiredForForm (Form)) {\r
     ConfigInfo = NULL;\r
     Link = GetFirstNode (&Form->ConfigRequestHead);\r
     while (!IsNull (&Form->ConfigRequestHead, Link)) {\r
@@ -2277,7 +2406,7 @@ DiscardForm (
       //\r
       // Prepare <ConfigResp>\r
       //\r
-      SynchronizeStorageForForm(FormSet, ConfigInfo, FALSE);\r
+      SynchronizeStorage(FormSet, ConfigInfo->Storage, ConfigInfo->ConfigRequest, FALSE);\r
 \r
       //\r
       // Call callback with Changed type to inform the driver.\r
@@ -2285,8 +2414,8 @@ DiscardForm (
       SendDiscardInfoToDriver (FormSet, Form);\r
     }\r
 \r
-    Form->NvUpdateRequired = FALSE;\r
-  } else if (SettingScope == FormSetLevel && IsNvUpdateRequired(FormSet)) {\r
+    ValueChangeResetFlagUpdate (FALSE, NULL, Form);\r
+  } else if (SettingScope == FormSetLevel && IsNvUpdateRequiredForFormSet (FormSet)) {\r
 \r
     //\r
     // Discard Buffer storage or Name/Value storage\r
@@ -2307,7 +2436,7 @@ DiscardForm (
         continue;\r
       }\r
 \r
-      SynchronizeStorage(Storage->BrowserStorage, FALSE);\r
+      SynchronizeStorage(FormSet, Storage->BrowserStorage, Storage->ConfigRequest, FALSE);\r
     }\r
 \r
     Link = GetFirstNode (&FormSet->FormListHead);\r
@@ -2321,7 +2450,7 @@ DiscardForm (
       SendDiscardInfoToDriver (FormSet, Form);\r
     }\r
 \r
-    UpdateNvInfoInForm (FormSet, FALSE);   \r
+    ValueChangeResetFlagUpdate(FALSE, FormSet, NULL);\r
   } else if (SettingScope == SystemLevel) {\r
     //\r
     // System Level Discard.\r
@@ -2401,7 +2530,7 @@ SubmitForm (
     return Status;\r
   }\r
 \r
-  if (SettingScope == FormLevel && Form->NvUpdateRequired) {\r
+  if (SettingScope == FormLevel && IsNvUpdateRequiredForForm (Form)) {\r
     ConfigInfo = NULL;\r
     Link = GetFirstNode (&Form->ConfigRequestHead);\r
     while (!IsNull (&Form->ConfigRequestHead, Link)) {\r
@@ -2423,7 +2552,7 @@ SubmitForm (
       //\r
       // 1. Prepare <ConfigResp>\r
       //\r
-      Status = StorageToConfigResp (ConfigInfo->Storage, &ConfigResp, ConfigInfo->ConfigRequest);\r
+      Status = StorageToConfigResp (ConfigInfo->Storage, &ConfigResp, ConfigInfo->ConfigRequest, TRUE);\r
       if (EFI_ERROR (Status)) {\r
         return Status;\r
       }\r
@@ -2499,14 +2628,14 @@ SubmitForm (
       //\r
       // 3. Config success, update storage shadow Buffer, only update the data belong to this form.\r
       //\r
-      SynchronizeStorageForForm(FormSet, ConfigInfo, TRUE);\r
+      SynchronizeStorage (FormSet, ConfigInfo->Storage, ConfigInfo->ConfigRequest, TRUE);\r
     }\r
 \r
     //\r
     // 4. Update the NV flag.\r
     // \r
-    Form->NvUpdateRequired = FALSE;\r
-  } else if (SettingScope == FormSetLevel && IsNvUpdateRequired(FormSet)) {\r
+    ValueChangeResetFlagUpdate(TRUE, NULL, Form);\r
+  } else if (SettingScope == FormSetLevel && IsNvUpdateRequiredForFormSet (FormSet)) {\r
     //\r
     // Submit Buffer storage or Name/Value storage\r
     //\r
@@ -2530,7 +2659,7 @@ SubmitForm (
       //\r
       // 1. Prepare <ConfigResp>\r
       //\r
-      Status = StorageToConfigResp (Storage, &ConfigResp, FormSetStorage->ConfigRequest);\r
+      Status = StorageToConfigResp (Storage, &ConfigResp, FormSetStorage->ConfigRequest, TRUE);\r
       if (EFI_ERROR (Status)) {\r
         return Status;\r
       }\r
@@ -2602,13 +2731,13 @@ SubmitForm (
       //\r
       // 3. Config success, update storage shadow Buffer\r
       //\r
-      SynchronizeStorage (Storage, TRUE);\r
+      SynchronizeStorage (FormSet, Storage, FormSetStorage->ConfigRequest, TRUE);\r
     }\r
 \r
     //\r
     // 4. Update the NV flag.\r
     // \r
-    UpdateNvInfoInForm (FormSet, FALSE);\r
+    ValueChangeResetFlagUpdate(TRUE, FormSet, NULL);\r
   } else if (SettingScope == SystemLevel) {\r
     //\r
     // System Level Save.\r
@@ -2818,52 +2947,184 @@ GetDefaultValueFromAltCfg (
     }\r
   }\r
 \r
-Done:\r
-  if (ConfigRequest != NULL){\r
-    FreePool (ConfigRequest);\r
-  }\r
+Done:\r
+  if (ConfigRequest != NULL){\r
+    FreePool (ConfigRequest);\r
+  }\r
+\r
+  if (ConfigResp != NULL) {\r
+    FreePool (ConfigResp);\r
+  }\r
+  \r
+  if (Result != NULL) {\r
+    FreePool (Result);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Get default Id value used for browser.\r
+\r
+  @param  DefaultId              The default id value used by hii.\r
+\r
+  @retval Browser used default value.\r
+\r
+**/\r
+INTN\r
+GetDefaultIdForCallBack (\r
+  UINTN DefaultId\r
+  )\r
+{ \r
+  if (DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) {\r
+    return EFI_BROWSER_ACTION_DEFAULT_STANDARD;\r
+  } else if (DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) {\r
+    return EFI_BROWSER_ACTION_DEFAULT_MANUFACTURING;\r
+  } else if (DefaultId == EFI_HII_DEFAULT_CLASS_SAFE) {\r
+    return EFI_BROWSER_ACTION_DEFAULT_SAFE;\r
+  } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN + 0x1000) {\r
+    return EFI_BROWSER_ACTION_DEFAULT_PLATFORM + DefaultId - EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN;\r
+  } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN + 0x1000) {\r
+    return EFI_BROWSER_ACTION_DEFAULT_HARDWARE + DefaultId - EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN;\r
+  } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN + 0x1000) {\r
+    return EFI_BROWSER_ACTION_DEFAULT_FIRMWARE + DefaultId - EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN;\r
+  } else {\r
+    return -1;\r
+  }\r
+}\r
+\r
+\r
+\r
+/**\r
+  Return data element in an Array by its Index.\r
+\r
+  @param  Array                  The data array.\r
+  @param  Type                   Type of the data in this array.\r
+  @param  Index                  Zero based index for data in this array.\r
+\r
+  @retval Value                  The data to be returned\r
+\r
+**/\r
+UINT64\r
+GetArrayData (\r
+  IN VOID                     *Array,\r
+  IN UINT8                    Type,\r
+  IN UINTN                    Index\r
+  )\r
+{\r
+  UINT64 Data;\r
+\r
+  ASSERT (Array != NULL);\r
+\r
+  Data = 0;\r
+  switch (Type) {\r
+  case EFI_IFR_TYPE_NUM_SIZE_8:\r
+    Data = (UINT64) *(((UINT8 *) Array) + Index);\r
+    break;\r
+\r
+  case EFI_IFR_TYPE_NUM_SIZE_16:\r
+    Data = (UINT64) *(((UINT16 *) Array) + Index);\r
+    break;\r
+\r
+  case EFI_IFR_TYPE_NUM_SIZE_32:\r
+    Data = (UINT64) *(((UINT32 *) Array) + Index);\r
+    break;\r
+\r
+  case EFI_IFR_TYPE_NUM_SIZE_64:\r
+    Data = (UINT64) *(((UINT64 *) Array) + Index);\r
+    break;\r
+\r
+  default:\r
+    break;\r
+  }\r
+\r
+  return Data;\r
+}\r
+\r
+\r
+/**\r
+  Set value of a data element in an Array by its Index.\r
+\r
+  @param  Array                  The data array.\r
+  @param  Type                   Type of the data in this array.\r
+  @param  Index                  Zero based index for data in this array.\r
+  @param  Value                  The value to be set.\r
+\r
+**/\r
+VOID\r
+SetArrayData (\r
+  IN VOID                     *Array,\r
+  IN UINT8                    Type,\r
+  IN UINTN                    Index,\r
+  IN UINT64                   Value\r
+  )\r
+{\r
+\r
+  ASSERT (Array != NULL);\r
 \r
-  if (ConfigResp != NULL) {\r
-    FreePool (ConfigResp);\r
-  }\r
-  \r
-  if (Result != NULL) {\r
-    FreePool (Result);\r
-  }\r
+  switch (Type) {\r
+  case EFI_IFR_TYPE_NUM_SIZE_8:\r
+    *(((UINT8 *) Array) + Index) = (UINT8) Value;\r
+    break;\r
 \r
-  return Status;\r
+  case EFI_IFR_TYPE_NUM_SIZE_16:\r
+    *(((UINT16 *) Array) + Index) = (UINT16) Value;\r
+    break;\r
+\r
+  case EFI_IFR_TYPE_NUM_SIZE_32:\r
+    *(((UINT32 *) Array) + Index) = (UINT32) Value;\r
+    break;\r
+\r
+  case EFI_IFR_TYPE_NUM_SIZE_64:\r
+    *(((UINT64 *) Array) + Index) = (UINT64) Value;\r
+    break;\r
+\r
+  default:\r
+    break;\r
+  }\r
 }\r
 \r
 /**\r
-  Get default Id value used for browser.\r
+  Search an Option of a Question by its value.\r
 \r
-  @param  DefaultId              The default id value used by hii.\r
+  @param  Question               The Question\r
+  @param  OptionValue            Value for Option to be searched.\r
 \r
-  @retval Browser used default value.\r
+  @retval Pointer                Pointer to the found Option.\r
+  @retval NULL                   Option not found.\r
 \r
 **/\r
-INTN\r
-GetDefaultIdForCallBack (\r
-  UINTN DefaultId\r
+QUESTION_OPTION *\r
+ValueToOption (\r
+  IN FORM_BROWSER_STATEMENT   *Question,\r
+  IN EFI_HII_VALUE            *OptionValue\r
   )\r
-{ \r
-  if (DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) {\r
-    return EFI_BROWSER_ACTION_DEFAULT_STANDARD;\r
-  } else if (DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) {\r
-    return EFI_BROWSER_ACTION_DEFAULT_MANUFACTURING;\r
-  } else if (DefaultId == EFI_HII_DEFAULT_CLASS_SAFE) {\r
-    return EFI_BROWSER_ACTION_DEFAULT_SAFE;\r
-  } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN + 0x1000) {\r
-    return EFI_BROWSER_ACTION_DEFAULT_PLATFORM + DefaultId - EFI_HII_DEFAULT_CLASS_PLATFORM_BEGIN;\r
-  } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN + 0x1000) {\r
-    return EFI_BROWSER_ACTION_DEFAULT_HARDWARE + DefaultId - EFI_HII_DEFAULT_CLASS_HARDWARE_BEGIN;\r
-  } else if (DefaultId >= EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN && DefaultId < EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN + 0x1000) {\r
-    return EFI_BROWSER_ACTION_DEFAULT_FIRMWARE + DefaultId - EFI_HII_DEFAULT_CLASS_FIRMWARE_BEGIN;\r
-  } else {\r
-    return -1;\r
+{\r
+  LIST_ENTRY       *Link;\r
+  QUESTION_OPTION  *Option;\r
+  INTN             Result;\r
+\r
+  Link = GetFirstNode (&Question->OptionListHead);\r
+  while (!IsNull (&Question->OptionListHead, Link)) {\r
+    Option = QUESTION_OPTION_FROM_LINK (Link);\r
+\r
+    if ((CompareHiiValue (&Option->Value, OptionValue, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) {\r
+      //\r
+      // Check the suppressif condition, only a valid option can be return.\r
+      //\r
+      if ((Option->SuppressExpression == NULL) ||\r
+          ((EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) == ExpressFalse))) {\r
+        return Option;\r
+      }\r
+    }\r
+\r
+    Link = GetNextNode (&Question->OptionListHead, Link);\r
   }\r
+\r
+  return NULL;\r
 }\r
 \r
+\r
 /**\r
   Reset Question to its default value.\r
 \r
@@ -3155,11 +3416,7 @@ ExtractDefault (
   LIST_ENTRY              *FormLink;\r
   LIST_ENTRY              *Link;\r
   FORM_BROWSER_STATEMENT  *Question;\r
-  FORM_BROWSER_FORMSET    *BackUpFormSet;\r
   FORM_BROWSER_FORMSET    *LocalFormSet;\r
-  EFI_HII_HANDLE          *HiiHandles;\r
-  UINTN                   Index;\r
-  EFI_GUID                ZeroGuid;\r
 \r
   Status = EFI_SUCCESS;\r
 \r
@@ -3229,10 +3486,6 @@ ExtractDefault (
       if ((Question->Storage != NULL) &&\r
           (Question->Storage->Type != EFI_HII_VARSTORE_EFI_VARIABLE)) {\r
         SetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);\r
-        //\r
-        // Update Form NV flag.\r
-        //\r
-        Form->NvUpdateRequired = TRUE;\r
       }\r
     }\r
   } else if (SettingScope == FormSetLevel) {\r
@@ -3244,65 +3497,9 @@ ExtractDefault (
     }\r
   } else if (SettingScope == SystemLevel) {\r
     //\r
-    // Open all FormSet by locate HII packages.\r
-    // Initiliaze the maintain FormSet to store default data as back up data.\r
-    //\r
-    BackUpFormSet    = gOldFormSet;\r
-    gOldFormSet      = NULL;\r
-\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
-      //\r
-      // Check HiiHandles[Index] does exist in global maintain list. \r
-      //\r
-      if (GetFormSetFromHiiHandle (HiiHandles[Index]) != NULL) {\r
-        continue;\r
-      }\r
-      \r
-      //\r
-      // Initilize FormSet Setting\r
-      //\r
-      LocalFormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET));\r
-      ASSERT (LocalFormSet != NULL);\r
-      ZeroMem (&ZeroGuid, sizeof (ZeroGuid));\r
-      Status = InitializeFormSet (HiiHandles[Index], &ZeroGuid, LocalFormSet, FALSE);\r
-      if (EFI_ERROR (Status) || IsListEmpty (&LocalFormSet->FormListHead)) {\r
-        DestroyFormSet (LocalFormSet);\r
-        continue;\r
-      }\r
-      Status = InitializeCurrentSetting (LocalFormSet);\r
-      if (EFI_ERROR (Status)) {\r
-        DestroyFormSet (LocalFormSet);\r
-        continue;\r
-      }\r
-      //\r
-      // Initilize Questions' Value\r
-      //\r
-      Status = LoadFormSetConfig (NULL, LocalFormSet);\r
-      if (EFI_ERROR (Status)) {\r
-        DestroyFormSet (LocalFormSet);\r
-        continue;\r
-      }\r
-\r
-      //\r
-      // Add FormSet into the maintain list.\r
-      //\r
-      InsertTailList (&gBrowserFormSetList, &LocalFormSet->Link);\r
-    }\r
-    \r
-    //\r
-    // Free resources, and restore gOldFormSet and gClassOfVfr\r
+    // Preload all Hii formset.\r
     //\r
-    FreePool (HiiHandles);\r
-    gOldFormSet = BackUpFormSet;\r
+    LoadAllHiiFormset();\r
        \r
     //\r
     // Set Default Value for each FormSet in the maintain list.\r
@@ -3321,6 +3518,81 @@ ExtractDefault (
   return EFI_SUCCESS;\r
 }\r
 \r
+\r
+/**\r
+  Validate whether this question's value has changed.\r
+\r
+  @param  FormSet                FormSet data structure.\r
+  @param  Form                   Form data structure.\r
+  @param  Question               Question to be initialized.\r
+  @param  GetValueFrom           Where to get value, may from editbuffer, buffer or hii driver.\r
+\r
+  @retval TRUE                   Question's value has changed.\r
+  @retval FALSE                  Question's value has not changed\r
+\r
+**/\r
+BOOLEAN\r
+IsQuestionValueChanged (\r
+  IN FORM_BROWSER_FORMSET             *FormSet,\r
+  IN FORM_BROWSER_FORM                *Form,\r
+  IN OUT FORM_BROWSER_STATEMENT       *Question,\r
+  IN GET_SET_QUESTION_VALUE_WITH      GetValueFrom\r
+  )\r
+{\r
+  EFI_HII_VALUE    BackUpValue;\r
+  CHAR8            *BackUpBuffer;\r
+  EFI_STATUS       Status;\r
+  BOOLEAN          ValueChanged;\r
+  UINTN            BufferWidth;\r
+\r
+  //\r
+  // For quetion without storage, always mark it as data not changed.\r
+  //\r
+  if (Question->Storage == NULL && Question->Operand != EFI_IFR_TIME_OP && Question->Operand != EFI_IFR_DATE_OP) {\r
+    return FALSE;\r
+  }\r
+\r
+  BackUpBuffer = NULL;\r
+  ValueChanged = FALSE;\r
+\r
+  switch (Question->Operand) {\r
+    case EFI_IFR_ORDERED_LIST_OP:\r
+      BufferWidth  = Question->StorageWidth;\r
+      BackUpBuffer = AllocateCopyPool (BufferWidth, Question->BufferValue);\r
+      ASSERT (BackUpBuffer != NULL);\r
+      break;\r
+\r
+    case EFI_IFR_STRING_OP:\r
+    case EFI_IFR_PASSWORD_OP:\r
+      BufferWidth  = (UINTN) Question->Maximum * sizeof (CHAR16);\r
+      BackUpBuffer = AllocateCopyPool (BufferWidth, Question->BufferValue);\r
+      ASSERT (BackUpBuffer != NULL);\r
+      break;\r
+\r
+    default:\r
+      BufferWidth = 0;\r
+      break;\r
+  }\r
+  CopyMem (&BackUpValue, &Question->HiiValue, sizeof (EFI_HII_VALUE));\r
+\r
+  Status = GetQuestionValue (FormSet, Form, Question, GetValueFrom);\r
+  ASSERT_EFI_ERROR(Status);\r
+\r
+  if (CompareMem (&BackUpValue, &Question->HiiValue, sizeof (EFI_HII_VALUE)) != 0 ||\r
+      CompareMem (BackUpBuffer, Question->BufferValue, BufferWidth) != 0) {\r
+    ValueChanged = TRUE;\r
+  }\r
+\r
+  CopyMem (&Question->HiiValue, &BackUpValue, sizeof (EFI_HII_VALUE));\r
+  CopyMem (Question->BufferValue, BackUpBuffer, BufferWidth);\r
+\r
+  if (BackUpBuffer != NULL) {\r
+    FreePool (BackUpBuffer);\r
+  }\r
+\r
+  return ValueChanged;\r
+}\r
+\r
 /**\r
   Initialize Question's Edit copy from Storage.\r
 \r
@@ -3354,7 +3626,11 @@ LoadFormConfig (
     //\r
     // Initialize local copy of Value for each Question\r
     //\r
-    Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);\r
+    if (Question->Operand == EFI_IFR_PASSWORD_OP && (Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK)== 0) {\r
+      Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithHiiDriver);\r
+    } else {\r
+      Status = GetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);\r
+    }\r
     if (EFI_ERROR (Status)) {\r
       return Status;\r
     }\r
@@ -3394,6 +3670,11 @@ LoadFormConfig (
       Status = ProcessCallBackFunction(Selection, Question, EFI_BROWSER_ACTION_RETRIEVE, TRUE);\r
     }\r
 \r
+    //\r
+    // Update Question Value changed flag.\r
+    //\r
+    Question->ValueChanged = IsQuestionValueChanged(FormSet, Form, Question, GetSetValueWithBuffer);\r
+\r
     Link = GetNextNode (&Form->StatementListHead, Link);\r
   }\r
 \r
@@ -3437,6 +3718,11 @@ LoadFormSetConfig (
     Link = GetNextNode (&FormSet->FormListHead, Link);\r
   }\r
 \r
+  //\r
+  // Finished question initialization.\r
+  // \r
+  FormSet->QuestionInited = TRUE;\r
+\r
   return EFI_SUCCESS;\r
 }\r
 \r
@@ -3491,6 +3777,13 @@ RemoveConfigRequest (
   CHAR16       *NextRequestElement;\r
   CHAR16       *SearchKey;\r
 \r
+  //\r
+  // No request element in it, just return.\r
+  //\r
+  if (ConfigRequest == NULL) {\r
+    return;\r
+  }\r
+\r
   if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {\r
     //\r
     // "&Name1&Name2" section for EFI_HII_VARSTORE_NAME_VALUE storage\r
@@ -3565,6 +3858,7 @@ CleanBrowserStorage (
 {\r
   LIST_ENTRY            *Link;\r
   FORMSET_STORAGE       *Storage;\r
+  CHAR16                *ConfigRequest;\r
 \r
   Link = GetFirstNode (&FormSet->StorageListHead);\r
   while (!IsNull (&FormSet->StorageListHead, Link)) {\r
@@ -3572,7 +3866,8 @@ CleanBrowserStorage (
     Link = GetNextNode (&FormSet->StorageListHead, Link);\r
 \r
     if ((Storage->BrowserStorage->Type != EFI_HII_VARSTORE_BUFFER) && \r
-        (Storage->BrowserStorage->Type != EFI_HII_VARSTORE_NAME_VALUE)) {\r
+        (Storage->BrowserStorage->Type != EFI_HII_VARSTORE_NAME_VALUE) && \r
+        (Storage->BrowserStorage->Type != EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {\r
       continue;\r
     }\r
 \r
@@ -3580,7 +3875,8 @@ CleanBrowserStorage (
       continue;\r
     }\r
 \r
-    RemoveConfigRequest (Storage->BrowserStorage, Storage->ConfigRequest);\r
+    ConfigRequest = FormSet->QuestionInited ? Storage->ConfigRequest : Storage->ConfigElements;\r
+    RemoveConfigRequest (Storage->BrowserStorage, ConfigRequest);\r
   }\r
 }\r
 \r
@@ -3651,7 +3947,6 @@ AppendConfigRequest (
   Adjust the config request info, remove the request elements which already in AllConfigRequest string.\r
 \r
   @param  Storage                Form set Storage.\r
-  @param  ConfigRequest          Return the ConfigRequest info.\r
 \r
   @retval TRUE                   Has element not covered by current used elements, need to continue to call ExtractConfig\r
   @retval FALSE                  All elements covered by current used elements.\r
@@ -3659,8 +3954,7 @@ AppendConfigRequest (
 **/\r
 BOOLEAN \r
 ConfigRequestAdjust (\r
-  IN  FORMSET_STORAGE         *Storage,\r
-  OUT CHAR16                  **ConfigRequest\r
+  IN  FORMSET_STORAGE         *Storage\r
   )\r
 {\r
   CHAR16       *RequestElement;\r
@@ -3676,7 +3970,10 @@ ConfigRequestAdjust (
 \r
   if (Storage->BrowserStorage->ConfigRequest == NULL) {\r
     Storage->BrowserStorage->ConfigRequest = AllocateCopyPool (StrSize (Storage->ConfigRequest), Storage->ConfigRequest);\r
-    *ConfigRequest = AllocateCopyPool (StrSize (Storage->ConfigRequest), Storage->ConfigRequest);\r
+    if (Storage->ConfigElements != NULL) {\r
+      FreePool (Storage->ConfigElements);\r
+    }\r
+    Storage->ConfigElements = AllocateCopyPool (StrSize (Storage->ConfigRequest), Storage->ConfigRequest);\r
     return TRUE;\r
   }\r
 \r
@@ -3745,7 +4042,10 @@ ConfigRequestAdjust (
   }\r
 \r
   if (RetVal) {\r
-    *ConfigRequest = RetBuf;\r
+    if (Storage->ConfigElements != NULL) {\r
+      FreePool (Storage->ConfigElements);\r
+    }\r
+    Storage->ConfigElements = RetBuf;\r
   } else {\r
     FreePool (RetBuf);\r
   }\r
@@ -3753,16 +4053,163 @@ ConfigRequestAdjust (
   return RetVal;\r
 }\r
 \r
+/**\r
+\r
+  Base on ConfigRequest info to get default value for current formset. \r
+\r
+  ConfigRequest info include the info about which questions in current formset need to \r
+  get default value. This function only get these questions default value.\r
+  \r
+  @param  FormSet                FormSet data structure.\r
+  @param  Storage                Storage need to update value.\r
+  @param  ConfigRequest          The config request string.\r
+\r
+**/\r
+VOID\r
+GetDefaultForFormset (\r
+  IN FORM_BROWSER_FORMSET    *FormSet,\r
+  IN BROWSER_STORAGE         *Storage,\r
+  IN CHAR16                  *ConfigRequest\r
+  )\r
+{\r
+  UINT8             *BackUpBuf;\r
+  UINTN             BufferSize;\r
+  LIST_ENTRY        BackUpList;\r
+  NAME_VALUE_NODE   *Node;\r
+  LIST_ENTRY        *Link;\r
+  LIST_ENTRY        *NodeLink;\r
+  NAME_VALUE_NODE   *TmpNode;\r
+  EFI_STATUS        Status;\r
+  EFI_STRING        Progress;\r
+  EFI_STRING        Result;\r
+\r
+  BackUpBuf = NULL;\r
+  InitializeListHead(&BackUpList);\r
+\r
+  //\r
+  // Back update the edit buffer.\r
+  // \r
+  if (Storage->Type == EFI_HII_VARSTORE_BUFFER || \r
+      (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {\r
+    BackUpBuf = AllocateCopyPool (Storage->Size, Storage->EditBuffer);\r
+    ASSERT (BackUpBuf != NULL);\r
+  } else if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {\r
+    Link = GetFirstNode (&Storage->NameValueListHead);\r
+    while (!IsNull (&Storage->NameValueListHead, Link)) {\r
+      Node = NAME_VALUE_NODE_FROM_LINK (Link);\r
+      Link = GetNextNode (&Storage->NameValueListHead, Link);\r
+\r
+      //\r
+      // Only back Node belong to this formset.\r
+      //\r
+      if (StrStr (Storage->ConfigRequest, Node->Name) == NULL) {\r
+        continue;\r
+      }\r
+\r
+      TmpNode = AllocateCopyPool (sizeof (NAME_VALUE_NODE), Node);\r
+      TmpNode->Name = AllocateCopyPool (StrSize(Node->Name) * sizeof (CHAR16), Node->Name);\r
+      TmpNode->EditValue = AllocateCopyPool (StrSize(Node->EditValue) * sizeof (CHAR16), Node->EditValue);\r
+\r
+      InsertTailList(&BackUpList, &TmpNode->Link);\r
+    }\r
+  }\r
+\r
+  //\r
+  // Get default value.\r
+  //\r
+  ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForStorage, Storage, TRUE);\r
+\r
+  //\r
+  // Update the question value based on the input ConfigRequest.\r
+  //\r
+  if (Storage->Type == EFI_HII_VARSTORE_BUFFER || \r
+      (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER)) {\r
+    ASSERT (BackUpBuf != NULL);\r
+    BufferSize = Storage->Size;\r
+    Status = mHiiConfigRouting->BlockToConfig(\r
+                                  mHiiConfigRouting,\r
+                                  ConfigRequest,\r
+                                  Storage->EditBuffer,\r
+                                  BufferSize,\r
+                                  &Result,\r
+                                  &Progress\r
+                                  );\r
+    ASSERT_EFI_ERROR (Status);\r
+    \r
+    Status = mHiiConfigRouting->ConfigToBlock (\r
+                                  mHiiConfigRouting,\r
+                                  Result,\r
+                                  BackUpBuf,\r
+                                  &BufferSize,\r
+                                  &Progress\r
+                                  );\r
+    ASSERT_EFI_ERROR (Status);\r
+\r
+    if (Result != NULL) {\r
+      FreePool (Result);\r
+    }\r
+    \r
+    CopyMem (Storage->EditBuffer, BackUpBuf, Storage->Size);\r
+    FreePool (BackUpBuf);\r
+  } else if (Storage->Type == EFI_HII_VARSTORE_NAME_VALUE) {\r
+    //\r
+    // Update question value, only element in ConfigReqeust will be update.\r
+    //\r
+    Link = GetFirstNode (&BackUpList);\r
+    while (!IsNull (&BackUpList, Link)) {\r
+      Node = NAME_VALUE_NODE_FROM_LINK (Link);\r
+      Link = GetNextNode (&BackUpList, Link);\r
+\r
+      if (StrStr (ConfigRequest, Node->Name) != NULL) {\r
+        continue;\r
+      }\r
+\r
+      NodeLink = GetFirstNode (&Storage->NameValueListHead);\r
+      while (!IsNull (&Storage->NameValueListHead, NodeLink)) {\r
+        TmpNode  = NAME_VALUE_NODE_FROM_LINK (NodeLink);\r
+        NodeLink = GetNextNode (&Storage->NameValueListHead, NodeLink);\r
+      \r
+        if (StrCmp (Node->Name, TmpNode->Name) != 0) {\r
+          continue;\r
+        }\r
+\r
+        FreePool (TmpNode->EditValue);\r
+        TmpNode->EditValue = AllocateCopyPool (StrSize(Node->EditValue) * sizeof (CHAR16), Node->EditValue);\r
+\r
+        RemoveEntryList (&Node->Link);\r
+        FreePool (Node->EditValue);\r
+        FreePool (Node->Name);\r
+        FreePool (Node);\r
+      }\r
+    }\r
+\r
+    //\r
+    // Restore the Name/Value node.\r
+    //  \r
+    Link = GetFirstNode (&BackUpList);\r
+    while (!IsNull (&BackUpList, Link)) {\r
+      Node = NAME_VALUE_NODE_FROM_LINK (Link);\r
+      Link = GetNextNode (&BackUpList, Link);\r
\r
+      //\r
+      // Free this node.\r
+      //\r
+      RemoveEntryList (&Node->Link);\r
+      FreePool (Node->EditValue);\r
+      FreePool (Node->Name);\r
+      FreePool (Node);\r
+    }\r
+  }\r
+}\r
+\r
 /**\r
   Fill storage's edit copy with settings requested from Configuration Driver.\r
 \r
   @param  FormSet                FormSet data structure.\r
   @param  Storage                Buffer Storage.\r
 \r
-  @retval EFI_SUCCESS            The function completed successfully.\r
-\r
 **/\r
-EFI_STATUS\r
+VOID\r
 LoadStorage (\r
   IN FORM_BROWSER_FORMSET    *FormSet,\r
   IN FORMSET_STORAGE         *Storage\r
@@ -3772,18 +4219,17 @@ LoadStorage (
   EFI_STRING  Progress;\r
   EFI_STRING  Result;\r
   CHAR16      *StrPtr;\r
-  CHAR16      *ConfigRequest;\r
 \r
-  if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {\r
-    return EFI_SUCCESS;\r
-  }\r
+  switch (Storage->BrowserStorage->Type) {\r
+    case EFI_HII_VARSTORE_EFI_VARIABLE:\r
+      return;\r
+\r
+    case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:\r
+      if (Storage->BrowserStorage->ReferenceCount > 1) {\r
+        ConfigRequestAdjust(Storage);\r
+        return;\r
+      }\r
 \r
-  if (Storage->BrowserStorage->Type == EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER) {\r
-    Status = EFI_SUCCESS;\r
-    //\r
-    // EFI varstore data all get from variable, so no need to get again.\r
-    //\r
-    if (Storage->BrowserStorage->ReferenceCount == 1) {\r
       Status = gRT->GetVariable (\r
                        Storage->BrowserStorage->Name,\r
                        &Storage->BrowserStorage->Guid,\r
@@ -3791,55 +4237,78 @@ LoadStorage (
                        (UINTN*)&Storage->BrowserStorage->Size,\r
                        Storage->BrowserStorage->EditBuffer\r
                        );\r
-    }\r
-    return Status;\r
-  }\r
+      //\r
+      // If get variable fail, extract default from IFR binary\r
+      //\r
+      if (EFI_ERROR (Status)) {\r
+        ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForStorage, Storage->BrowserStorage, TRUE);\r
+      }\r
+\r
+      Storage->BrowserStorage->ConfigRequest = AllocateCopyPool (StrSize (Storage->ConfigRequest), Storage->ConfigRequest);\r
+      //\r
+      // Input NULL for ConfigRequest field means sync all fields from editbuffer to buffer. \r
+      //\r
+      SynchronizeStorage(FormSet, Storage->BrowserStorage, NULL, TRUE);\r
+      break;\r
 \r
-  if (FormSet->ConfigAccess == NULL) {\r
-    return EFI_NOT_FOUND;\r
-  }\r
+    case EFI_HII_VARSTORE_BUFFER:\r
+    case EFI_HII_VARSTORE_NAME_VALUE:\r
+      //\r
+      // Skip if there is no RequestElement\r
+      //\r
+      if (Storage->ElementCount == 0) {\r
+        return;\r
+      }\r
 \r
-  if (Storage->ElementCount == 0) {\r
-    //\r
-    // Skip if there is no RequestElement\r
-    //\r
-    return EFI_SUCCESS;\r
-  }\r
+      //\r
+      // Adjust the ConfigRequest string, only the field not saved in BrowserStorage->AllConfig\r
+      // will used to call ExtractConfig.\r
+      // If not elements need to udpate, return.\r
+      //\r
+      if (!ConfigRequestAdjust(Storage)) {\r
+        return;\r
+      }\r
+      ASSERT (Storage->ConfigElements != NULL);\r
 \r
-  //\r
-  // Adjust the ConfigRequest string, only the field not saved in BrowserStorage->AllConfig\r
-  // will used to call ExtractConfig.\r
-  //\r
-  if (!ConfigRequestAdjust(Storage, &ConfigRequest)) {\r
-    return EFI_SUCCESS;\r
-  }\r
+      Status = EFI_NOT_FOUND;\r
+      if (FormSet->ConfigAccess != NULL) { \r
+        //\r
+        // Request current settings from Configuration Driver\r
+        //\r
+        Status = FormSet->ConfigAccess->ExtractConfig (\r
+                                          FormSet->ConfigAccess,\r
+                                          Storage->ConfigElements,\r
+                                          &Progress,\r
+                                          &Result\r
+                                          );\r
+        \r
+        if (!EFI_ERROR (Status)) {\r
+          //\r
+          // Convert Result from <ConfigAltResp> to <ConfigResp>\r
+          //\r
+          StrPtr = StrStr (Result, L"&GUID=");\r
+          if (StrPtr != NULL) {\r
+            *StrPtr = L'\0';\r
+          }\r
+          \r
+          Status = ConfigRespToStorage (Storage->BrowserStorage, Result);\r
+          FreePool (Result);\r
+        }\r
+      }\r
 \r
-  //\r
-  // Request current settings from Configuration Driver\r
-  //\r
-  Status = FormSet->ConfigAccess->ExtractConfig (\r
-                                    FormSet->ConfigAccess,\r
-                                    ConfigRequest,\r
-                                    &Progress,\r
-                                    &Result\r
-                                    );\r
-  FreePool (ConfigRequest);\r
+      if (EFI_ERROR (Status)) {\r
+        //\r
+        // Base on the configRequest string to get default value.\r
+        //\r
+        GetDefaultForFormset (FormSet, Storage->BrowserStorage, Storage->ConfigElements);\r
+      }\r
 \r
-  if (EFI_ERROR (Status)) {\r
-    return Status;\r
-  }\r
+      SynchronizeStorage(FormSet, Storage->BrowserStorage, Storage->ConfigElements, TRUE);\r
+      break;\r
 \r
-  //\r
-  // Convert Result from <ConfigAltResp> to <ConfigResp>\r
-  //\r
-  StrPtr = StrStr (Result, L"&GUID=");\r
-  if (StrPtr != NULL) {\r
-    *StrPtr = L'\0';\r
+    default:\r
+      break;\r
   }\r
-\r
-  Status = ConfigRespToStorage (Storage->BrowserStorage, Result);\r
-  FreePool (Result);\r
-  return Status;\r
 }\r
 \r
 /**\r
@@ -3847,22 +4316,15 @@ LoadStorage (
 \r
   @param  FormSet                FormSet data structure.\r
 \r
-  @retval EFI_SUCCESS            The function completed successfully.\r
-\r
 **/\r
-EFI_STATUS\r
+VOID\r
 InitializeCurrentSetting (\r
   IN OUT FORM_BROWSER_FORMSET             *FormSet\r
   )\r
 {\r
   LIST_ENTRY              *Link;\r
-  LIST_ENTRY              *Link2;\r
   FORMSET_STORAGE         *Storage;\r
-  FORMSET_STORAGE         *StorageSrc;\r
-  FORMSET_STORAGE         *OldStorage;\r
-  FORM_BROWSER_FORM       *Form;\r
-  FORM_BROWSER_FORM       *Form2;\r
-  EFI_STATUS              Status;\r
+  FORM_BROWSER_FORMSET    *OldFormSet;\r
 \r
   //\r
   // Extract default from IFR binary for no storage questions.\r
@@ -3876,77 +4338,21 @@ InitializeCurrentSetting (
   while (!IsNull (&FormSet->StorageListHead, Link)) {\r
     Storage = FORMSET_STORAGE_FROM_LINK (Link);\r
 \r
-    OldStorage = NULL;\r
-    if (gOldFormSet != NULL) {\r
-      //\r
-      // Try to find the Storage in backup formset gOldFormSet\r
-      //\r
-      Link2 = GetFirstNode (&gOldFormSet->StorageListHead);\r
-      while (!IsNull (&gOldFormSet->StorageListHead, Link2)) {\r
-        StorageSrc = FORMSET_STORAGE_FROM_LINK (Link2);\r
-\r
-        if (StorageSrc->VarStoreId == Storage->VarStoreId) {\r
-          OldStorage = StorageSrc;\r
-          break;\r
-        }\r
-\r
-        Link2 = GetNextNode (&gOldFormSet->StorageListHead, Link2);\r
-      }\r
-    }\r
-\r
-    //\r
-    // Storage is not found in backup formset and current global storage not has other driver used,\r
-    // request it from ConfigDriver\r
-    //\r
-    if (OldStorage == NULL) {\r
-      Status = LoadStorage (FormSet, Storage);\r
-\r
-      if (EFI_ERROR (Status)) {\r
-        //\r
-        // If get last time changed value failed, extract default from IFR binary\r
-        //\r
-        ExtractDefault (FormSet, NULL, EFI_HII_DEFAULT_CLASS_STANDARD, FormSetLevel, GetDefaultForStorage, Storage->BrowserStorage, TRUE);\r
-        //\r
-        // ExtractDefault will set the NV flag to TRUE, so need this function to clean the flag\r
-        // in current situation.\r
-        //\r
-        UpdateNvInfoInForm (FormSet, FALSE);\r
-      }\r
-\r
-      //\r
-      // Now Edit Buffer is filled with default values(lower priority) or current\r
-      // settings(higher priority), sychronize it to shadow Buffer\r
-      //\r
-      SynchronizeStorage (Storage->BrowserStorage, TRUE);\r
-    }\r
+    LoadStorage (FormSet, Storage);\r
 \r
     Link = GetNextNode (&FormSet->StorageListHead, Link);\r
   }\r
 \r
   //\r
-  // If has old formset, get the old nv update status.\r
+  // Try to find pre FormSet in the maintain backup list.\r
+  // If old formset != NULL, destroy this formset. Add new formset to gBrowserFormSetList.\r
   //\r
-  if (gOldFormSet != NULL) {\r
-    Link = GetFirstNode (&FormSet->FormListHead);\r
-    while (!IsNull (&FormSet->FormListHead, Link)) {\r
-      Form = FORM_BROWSER_FORM_FROM_LINK (Link);\r
-\r
-      Link2 = GetFirstNode (&gOldFormSet->FormListHead);\r
-      while (!IsNull (&gOldFormSet->FormListHead, Link2)) {\r
-        Form2 = FORM_BROWSER_FORM_FROM_LINK (Link2);\r
-\r
-        if (Form->FormId == Form2->FormId) {\r
-          Form->NvUpdateRequired = Form2->NvUpdateRequired;\r
-          break;\r
-        }\r
-\r
-        Link2 = GetNextNode (&gOldFormSet->FormListHead, Link2);\r
-      }\r
-      Link = GetNextNode (&FormSet->FormListHead, Link);\r
-    }\r
+  OldFormSet = GetFormSetFromHiiHandle (FormSet->HiiHandle);\r
+  if (OldFormSet != NULL) {\r
+    RemoveEntryList (&OldFormSet->Link);\r
+    DestroyFormSet (OldFormSet);\r
   }\r
-\r
-  return EFI_SUCCESS;\r
+  InsertTailList (&gBrowserFormSetList, &FormSet->Link);\r
 }\r
 \r
 \r
@@ -4129,7 +4535,6 @@ GetIfrBinaryData (
                                  found in package list.\r
                                  On output, GUID of the formset found(if not NULL).\r
   @param  FormSet                FormSet data structure.\r
-  @param  UpdateGlobalVar        Whether need to update the global variable.\r
 \r
   @retval EFI_SUCCESS            The function completed successfully.\r
   @retval EFI_NOT_FOUND          The specified FormSet could not be found.\r
@@ -4139,13 +4544,11 @@ EFI_STATUS
 InitializeFormSet (\r
   IN  EFI_HII_HANDLE                   Handle,\r
   IN OUT EFI_GUID                      *FormSetGuid,\r
-  OUT FORM_BROWSER_FORMSET             *FormSet,\r
-  IN  BOOLEAN                          UpdateGlobalVar                   \r
+  OUT FORM_BROWSER_FORMSET             *FormSet\r
   )\r
 {\r
   EFI_STATUS                Status;\r
   EFI_HANDLE                DriverHandle;\r
-  UINT16                    Index;\r
 \r
   Status = GetIfrBinaryData (Handle, FormSetGuid, &FormSet->IfrBinaryLength, &FormSet->IfrBinaryData);\r
   if (EFI_ERROR (Status)) {\r
@@ -4155,6 +4558,7 @@ InitializeFormSet (
   FormSet->Signature = FORM_BROWSER_FORMSET_SIGNATURE;\r
   FormSet->HiiHandle = Handle;\r
   CopyMem (&FormSet->Guid, FormSetGuid, sizeof (EFI_GUID));\r
+  FormSet->QuestionInited = FALSE;\r
 \r
   //\r
   // Retrieve ConfigAccess Protocol associated with this HiiPackageList\r
@@ -4181,55 +4585,8 @@ InitializeFormSet (
   // Parse the IFR binary OpCodes\r
   //\r
   Status = ParseOpCodes (FormSet);\r
-  if (EFI_ERROR (Status)) {\r
-    return Status;\r
-  }\r
-\r
-  // \r
-  // If not need to update the global variable, just return.\r
-  //\r
-  if (!UpdateGlobalVar) {\r
-    return Status;\r
-  }\r
-\r
-  //\r
-  // Set VFR type by FormSet SubClass field\r
-  //\r
-  gClassOfVfr = FORMSET_CLASS_PLATFORM_SETUP;\r
-  if (FormSet->SubClass == EFI_FRONT_PAGE_SUBCLASS) {\r
-    gClassOfVfr = FORMSET_CLASS_FRONT_PAGE;\r
-  }\r
-  \r
-  //\r
-  // Set VFR type by FormSet class guid\r
-  //\r
-  for (Index = 0; Index < 3; Index ++) {\r
-    if (CompareGuid (&FormSet->ClassGuid[Index], &gEfiHiiPlatformSetupFormsetGuid)) {\r
-      gClassOfVfr |= FORMSET_CLASS_PLATFORM_SETUP;\r
-      break;\r
-    }\r
-  }\r
-\r
-  gFunctionKeySetting = ENABLE_FUNCTION_KEY_SETTING;\r
-\r
-  if ((gClassOfVfr & FORMSET_CLASS_FRONT_PAGE) == FORMSET_CLASS_FRONT_PAGE) {\r
-    gFrontPageHandle = FormSet->HiiHandle;\r
-    gFunctionKeySetting = NONE_FUNCTION_KEY_SETTING;\r
-  }\r
-\r
-  //\r
-  // Match GUID to find out the function key setting. If match fail, use the default setting.\r
-  //\r
-  for (Index = 0; Index < sizeof (gFunctionKeySettingTable) / sizeof (FUNCTIION_KEY_SETTING); Index++) {\r
-    if (CompareGuid (&FormSet->Guid, &(gFunctionKeySettingTable[Index].FormSetGuid))) {\r
-      //\r
-      // Update the function key setting.\r
-      //\r
-      gFunctionKeySetting = gFunctionKeySettingTable[Index].KeySetting;\r
-    }\r
-  }\r
 \r
-  return EFI_SUCCESS;\r
+  return Status;\r
 }\r
 \r
 \r
@@ -4245,6 +4602,7 @@ SaveBrowserContext (
   )\r
 {\r
   BROWSER_CONTEXT  *Context;\r
+  FORM_ENTRY_INFO     *MenuList;\r
 \r
   gBrowserContextCount++;\r
   if (gBrowserContextCount == 1) {\r
@@ -4254,6 +4612,11 @@ SaveBrowserContext (
     return;\r
   }\r
 \r
+  //\r
+  // Not support SendForm nest in another SendForm, assert here.\r
+  //\r
+  ASSERT (FALSE);\r
+\r
   Context = AllocatePool (sizeof (BROWSER_CONTEXT));\r
   ASSERT (Context != NULL);\r
 \r
@@ -4262,47 +4625,20 @@ SaveBrowserContext (
   //\r
   // Save FormBrowser context\r
   //\r
-  Context->BannerData           = gBannerData;\r
-  Context->ClassOfVfr           = gClassOfVfr;\r
-  Context->FunctionKeySetting   = gFunctionKeySetting;\r
   Context->ResetRequired        = gResetRequired;\r
-  Context->Direction            = gDirection;\r
-  Context->EnterString          = gEnterString;\r
-  Context->EnterCommitString    = gEnterCommitString;\r
-  Context->EnterEscapeString    = gEnterEscapeString;\r
-  Context->EscapeString         = gEscapeString;\r
-  Context->MoveHighlight        = gMoveHighlight;\r
-  Context->MakeSelection        = gMakeSelection;\r
-  Context->DecNumericInput      = gDecNumericInput;\r
-  Context->HexNumericInput      = gHexNumericInput;\r
-  Context->ToggleCheckBox       = gToggleCheckBox;\r
-  Context->PromptForData        = gPromptForData;\r
-  Context->PromptForPassword    = gPromptForPassword;\r
-  Context->PromptForNewPassword = gPromptForNewPassword;\r
-  Context->ConfirmPassword      = gConfirmPassword;\r
-  Context->ConfirmError         = gConfirmError;\r
-  Context->PassowordInvalid     = gPassowordInvalid;\r
-  Context->PressEnter           = gPressEnter;\r
-  Context->EmptyString          = gEmptyString;\r
-  Context->AreYouSure           = gAreYouSure;\r
-  Context->YesResponse          = gYesResponse;\r
-  Context->NoResponse           = gNoResponse;\r
-  Context->MiniString           = gMiniString;\r
-  Context->PlusString           = gPlusString;\r
-  Context->MinusString          = gMinusString;\r
-  Context->AdjustNumber         = gAdjustNumber;\r
-  Context->SaveChanges          = gSaveChanges;\r
-  Context->OptionMismatch       = gOptionMismatch;\r
-  Context->FormSuppress         = gFormSuppress;\r
-  Context->PromptBlockWidth     = gPromptBlockWidth;\r
-  Context->OptionBlockWidth     = gOptionBlockWidth;\r
-  Context->HelpBlockWidth       = gHelpBlockWidth;\r
-  Context->OldFormSet           = gOldFormSet;\r
-  Context->MenuRefreshHead      = gMenuRefreshHead;\r
-  Context->ProtocolNotFound     = gProtocolNotFound;\r
-\r
-  CopyMem (&Context->ScreenDimensions, &gScreenDimensions, sizeof (gScreenDimensions));\r
-  CopyMem (&Context->MenuOption, &gMenuOption, sizeof (gMenuOption));\r
+  Context->ExitRequired         = gExitRequired;\r
+  Context->HiiHandle            = mCurrentHiiHandle;\r
+\r
+  //\r
+  // Save the menu history data.\r
+  //\r
+  InitializeListHead(&Context->FormHistoryList);\r
+  while (!IsListEmpty (&mPrivateData.FormBrowserEx2.FormViewHistoryHead)) {\r
+    MenuList = FORM_ENTRY_INFO_FROM_LINK (mPrivateData.FormBrowserEx2.FormViewHistoryHead.ForwardLink);\r
+    RemoveEntryList (&MenuList->Link);\r
+\r
+    InsertTailList(&Context->FormHistoryList, &MenuList->Link);\r
+  }\r
 \r
   //\r
   // Insert to FormBrowser context list\r
@@ -4322,6 +4658,7 @@ RestoreBrowserContext (
 {\r
   LIST_ENTRY       *Link;\r
   BROWSER_CONTEXT  *Context;\r
+  FORM_ENTRY_INFO     *MenuList;\r
 \r
   ASSERT (gBrowserContextCount != 0);\r
   gBrowserContextCount--;\r
@@ -4340,47 +4677,19 @@ RestoreBrowserContext (
   //\r
   // Restore FormBrowser context\r
   //\r
-  gBannerData           = Context->BannerData;\r
-  gClassOfVfr           = Context->ClassOfVfr;\r
-  gFunctionKeySetting   = Context->FunctionKeySetting;\r
   gResetRequired        = Context->ResetRequired;\r
-  gDirection            = Context->Direction;\r
-  gEnterString          = Context->EnterString;\r
-  gEnterCommitString    = Context->EnterCommitString;\r
-  gEnterEscapeString    = Context->EnterEscapeString;\r
-  gEscapeString         = Context->EscapeString;\r
-  gMoveHighlight        = Context->MoveHighlight;\r
-  gMakeSelection        = Context->MakeSelection;\r
-  gDecNumericInput      = Context->DecNumericInput;\r
-  gHexNumericInput      = Context->HexNumericInput;\r
-  gToggleCheckBox       = Context->ToggleCheckBox;\r
-  gPromptForData        = Context->PromptForData;\r
-  gPromptForPassword    = Context->PromptForPassword;\r
-  gPromptForNewPassword = Context->PromptForNewPassword;\r
-  gConfirmPassword      = Context->ConfirmPassword;\r
-  gConfirmError         = Context->ConfirmError;\r
-  gPassowordInvalid     = Context->PassowordInvalid;\r
-  gPressEnter           = Context->PressEnter;\r
-  gEmptyString          = Context->EmptyString;\r
-  gAreYouSure           = Context->AreYouSure;\r
-  gYesResponse          = Context->YesResponse;\r
-  gNoResponse           = Context->NoResponse;\r
-  gMiniString           = Context->MiniString;\r
-  gPlusString           = Context->PlusString;\r
-  gMinusString          = Context->MinusString;\r
-  gAdjustNumber         = Context->AdjustNumber;\r
-  gSaveChanges          = Context->SaveChanges;\r
-  gOptionMismatch       = Context->OptionMismatch;\r
-  gFormSuppress         = Context->FormSuppress;\r
-  gPromptBlockWidth     = Context->PromptBlockWidth;\r
-  gOptionBlockWidth     = Context->OptionBlockWidth;\r
-  gHelpBlockWidth       = Context->HelpBlockWidth;\r
-  gOldFormSet           = Context->OldFormSet;\r
-  gMenuRefreshHead      = Context->MenuRefreshHead;\r
-  gProtocolNotFound     = Context->ProtocolNotFound;\r
-\r
-  CopyMem (&gScreenDimensions, &Context->ScreenDimensions, sizeof (gScreenDimensions));\r
-  CopyMem (&gMenuOption, &Context->MenuOption, sizeof (gMenuOption));\r
+  gExitRequired         = Context->ExitRequired;\r
+  mCurrentHiiHandle     = Context->HiiHandle;\r
+\r
+  //\r
+  // Restore the menu history data.\r
+  //\r
+  while (!IsListEmpty (&Context->FormHistoryList)) {\r
+    MenuList = FORM_ENTRY_INFO_FROM_LINK (Context->FormHistoryList.ForwardLink);\r
+    RemoveEntryList (&MenuList->Link);\r
+\r
+    InsertTailList(&mPrivateData.FormBrowserEx2.FormViewHistoryHead, &MenuList->Link);\r
+  }\r
 \r
   //\r
   // Remove from FormBrowser context list\r
@@ -4440,7 +4749,7 @@ IsHiiHandleInBrowserContext (
   //\r
   // HiiHandle is Current FormSet.\r
   //\r
-  if ((gOldFormSet != NULL) && (gOldFormSet->HiiHandle == Handle)) {\r
+  if (mCurrentHiiHandle == Handle) {\r
     return TRUE;\r
   }\r
 \r
@@ -4450,7 +4759,7 @@ IsHiiHandleInBrowserContext (
   Link = GetFirstNode (&gBrowserContextList);\r
   while (!IsNull (&gBrowserContextList, Link)) {\r
     Context = BROWSER_CONTEXT_FROM_LINK (Link);\r
-    if (Context->OldFormSet->HiiHandle == Handle) {\r
+    if (Context->HiiHandle == Handle) {\r
       //\r
       // HiiHandle is in BrowserContext\r
       //\r
@@ -4462,6 +4771,83 @@ IsHiiHandleInBrowserContext (
   return FALSE;\r
 }\r
 \r
+/**\r
+  Perform Password check. \r
+  Passwork may be encrypted by driver that requires the specific check.\r
+  \r
+  @param  Form             Form where Password Statement is in.\r
+  @param  Statement        Password statement\r
+  @param  PasswordString   Password string to be checked. It may be NULL.\r
+                           NULL means to restore password.\r
+                           "" string can be used to checked whether old password does exist.\r
+  \r
+  @return Status     Status of Password check.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PasswordCheck (\r
+  IN FORM_DISPLAY_ENGINE_FORM      *Form,\r
+  IN FORM_DISPLAY_ENGINE_STATEMENT *Statement,\r
+  IN EFI_STRING                    PasswordString  OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  EFI_HII_CONFIG_ACCESS_PROTOCOL  *ConfigAccess;\r
+  EFI_BROWSER_ACTION_REQUEST      ActionRequest;\r
+  EFI_IFR_TYPE_VALUE              IfrTypeValue;\r
+  FORM_BROWSER_STATEMENT          *Question;\r
+\r
+  ConfigAccess = gCurrentSelection->FormSet->ConfigAccess;\r
+  Question = GetBrowserStatement(Statement);\r
+  ASSERT (Question != NULL);\r
+\r
+  if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK) {\r
+    if (ConfigAccess == NULL) {\r
+      return EFI_UNSUPPORTED;\r
+    }\r
+  } else {\r
+    if (PasswordString == NULL) {\r
+      return EFI_SUCCESS;\r
+    } \r
+    \r
+    if (StrnCmp (PasswordString, (CHAR16 *) Question->BufferValue, Question->StorageWidth/sizeof (CHAR16)) == 0) {\r
+      return EFI_SUCCESS;\r
+    } else {\r
+      return EFI_NOT_READY;\r
+    }\r
+  }\r
+    \r
+  //\r
+  // Prepare password string in HII database\r
+  //\r
+  if (PasswordString != NULL) {\r
+    IfrTypeValue.string = NewString (PasswordString, gCurrentSelection->FormSet->HiiHandle);\r
+  } else {\r
+    IfrTypeValue.string = 0;\r
+  }\r
+\r
+  //\r
+  // Send password to Configuration Driver for validation\r
+  //\r
+  Status = ConfigAccess->Callback (\r
+                           ConfigAccess,\r
+                           EFI_BROWSER_ACTION_CHANGING,\r
+                           Question->QuestionId,\r
+                           Question->HiiValue.Type,\r
+                           &IfrTypeValue,\r
+                           &ActionRequest\r
+                           );\r
+\r
+  //\r
+  // Remove password string from HII database\r
+  //\r
+  if (PasswordString != NULL) {\r
+    DeleteString (IfrTypeValue.string, gCurrentSelection->FormSet->HiiHandle);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
 /**\r
   Find the registered HotKey based on KeyData.\r
   \r
@@ -4512,7 +4898,7 @@ SetScope (
   if (Scope >= MaxLevel) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
-  \r
+\r
   //\r
   // When no hot key registered in system or on the first setting,\r
   // Scope can be set.\r
@@ -4636,6 +5022,128 @@ RegiserExitHandler (
   return;\r
 }\r
 \r
+/**\r
+  Check whether the browser data has been modified.\r
+\r
+  @retval TRUE        Browser data is modified.\r
+  @retval FALSE       No browser data is modified.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+IsBrowserDataModified (\r
+  VOID\r
+  )\r
+{\r
+  LIST_ENTRY              *Link;\r
+  FORM_BROWSER_FORMSET    *FormSet;\r
+\r
+  if (gCurrentSelection == NULL) {\r
+    return FALSE;\r
+  }\r
+\r
+  switch (gBrowserSettingScope) {\r
+    case FormLevel:\r
+      return IsNvUpdateRequiredForForm (gCurrentSelection->Form);\r
+\r
+    case FormSetLevel:\r
+      return IsNvUpdateRequiredForFormSet (gCurrentSelection->FormSet);\r
+\r
+    case SystemLevel:\r
+      Link = GetFirstNode (&gBrowserFormSetList);\r
+      while (!IsNull (&gBrowserFormSetList, Link)) {\r
+        FormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);\r
+        if (IsNvUpdateRequiredForFormSet (FormSet)) {\r
+          return TRUE;\r
+        }\r
+        Link = GetNextNode (&gBrowserFormSetList, Link);\r
+      }\r
+      return FALSE;\r
+\r
+    default:\r
+      return FALSE;\r
+  }\r
+}\r
+\r
+/**\r
+  Execute the action requested by the Action parameter.\r
+\r
+  @param[in] Action     Execute the request action.\r
+  @param[in] DefaultId  The default Id info when need to load default value. Only used when Action is BROWSER_ACTION_DEFAULT.\r
+\r
+  @retval EFI_SUCCESS              Execute the request action succss.\r
+  @retval EFI_INVALID_PARAMETER    The input action value is invalid.\r
+\r
+**/\r
+EFI_STATUS \r
+EFIAPI\r
+ExecuteAction (\r
+  IN UINT32        Action,\r
+  IN UINT16        DefaultId\r
+  )\r
+{\r
+  EFI_STATUS Status;\r
+\r
+  if (gCurrentSelection == NULL) {\r
+    return EFI_NOT_READY;\r
+  }\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  //\r
+  // Executet the discard action.\r
+  //\r
+  if ((Action & BROWSER_ACTION_DISCARD) != 0) {\r
+    Status = DiscardForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Executet the difault action.\r
+  //\r
+  if ((Action & BROWSER_ACTION_DEFAULT) != 0) {\r
+    Status = ExtractDefault (gCurrentSelection->FormSet, gCurrentSelection->Form, DefaultId, gBrowserSettingScope, GetDefaultForAll, NULL, FALSE);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Executet the submit action.\r
+  //\r
+  if ((Action & BROWSER_ACTION_SUBMIT) != 0) {\r
+    Status = SubmitForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Executet the reset action.\r
+  //\r
+  if ((Action & BROWSER_ACTION_RESET) != 0) {\r
+    gResetRequired = TRUE;\r
+  }\r
+\r
+  //\r
+  // Executet the exit action.\r
+  //\r
+  if ((Action & BROWSER_ACTION_EXIT) != 0) {\r
+    DiscardForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope);\r
+    if (gBrowserSettingScope == SystemLevel) {\r
+      if (ExitHandlerFunction != NULL) {\r
+        ExitHandlerFunction ();\r
+      }\r
+    }\r
+\r
+    gExitRequired = TRUE;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
 /**\r
   Create reminder to let user to choose save or discard the changed browser data.\r
   Caller can use it to actively check the changed browser data.\r
@@ -4655,12 +5163,6 @@ SaveReminder (
   FORM_BROWSER_FORMSET    *FormSet;\r
   BOOLEAN                 IsDataChanged;\r
   UINT32                  DataSavedAction;\r
-  CHAR16                  *YesResponse;\r
-  CHAR16                  *NoResponse;\r
-  CHAR16                  *EmptyString;\r
-  CHAR16                  *ChangeReminderString;\r
-  CHAR16                  *SaveConfirmString;\r
-  EFI_INPUT_KEY           Key;\r
 \r
   DataSavedAction  = BROWSER_NO_CHANGES;\r
   IsDataChanged    = FALSE;\r
@@ -4671,7 +5173,7 @@ SaveReminder (
     if (!ValidateFormSet(FormSet)) {\r
       continue;\r
     }\r
-    if (IsNvUpdateRequired (FormSet)) {\r
+    if (IsNvUpdateRequiredForFormSet (FormSet)) {\r
       IsDataChanged = TRUE;\r
       break;\r
     }\r
@@ -4685,42 +5187,19 @@ SaveReminder (
   }\r
   \r
   //\r
-  // If data is changed, prompt user\r
+  // If data is changed, prompt user to save or discard it. \r
   //\r
-  gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
-\r
-  YesResponse          = GetToken (STRING_TOKEN (ARE_YOU_SURE_YES), gHiiHandle);\r
-  ASSERT (YesResponse != NULL);\r
-  NoResponse           = GetToken (STRING_TOKEN (ARE_YOU_SURE_NO), gHiiHandle);\r
-  ASSERT (NoResponse  != NULL);\r
-  EmptyString          = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle);\r
-  ChangeReminderString = GetToken (STRING_TOKEN (CHANGE_REMINDER), gHiiHandle);\r
-  SaveConfirmString    = GetToken (STRING_TOKEN (SAVE_CONFIRM), gHiiHandle);\r
-\r
   do {\r
-    CreateDialog (4, TRUE, 0, NULL, &Key, EmptyString, ChangeReminderString, SaveConfirmString, EmptyString);\r
-  } while\r
-  (((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (NoResponse[0] | UPPER_LOWER_CASE_OFFSET)) &&\r
-   ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (YesResponse[0] | UPPER_LOWER_CASE_OFFSET))\r
-  );\r
+    DataSavedAction = (UINT32) mFormDisplay->ConfirmDataChange();\r
 \r
-  //\r
-  // If the user hits the YesResponse key\r
-  //\r
-  if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (YesResponse[0] | UPPER_LOWER_CASE_OFFSET)) {\r
-    SubmitForm (NULL, NULL, SystemLevel);\r
-    DataSavedAction = BROWSER_SAVE_CHANGES;\r
-  } else {\r
-    DiscardForm (NULL, NULL, SystemLevel);\r
-    DataSavedAction = BROWSER_DISCARD_CHANGES;\r
-    gResetRequired  = FALSE;\r
-  }\r
-\r
-  FreePool (YesResponse);\r
-  FreePool (NoResponse);\r
-  FreePool (EmptyString);\r
-  FreePool (SaveConfirmString);\r
-  FreePool (ChangeReminderString);\r
+    if (DataSavedAction == BROWSER_SAVE_CHANGES) {\r
+      SubmitForm (NULL, NULL, SystemLevel);\r
+      break;\r
+    } else if (DataSavedAction == BROWSER_DISCARD_CHANGES) {\r
+      DiscardForm (NULL, NULL, SystemLevel);\r
+      break;\r
+    }\r
+  } while (1);\r
 \r
   return DataSavedAction;\r
 }\r
index 9a0c739094017a5ce74d42bb379bb604230d3b6c..1be2c0d5a03a020889475d98fffb64bb4c9a9609 100644 (file)
@@ -22,7 +22,8 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #include <Protocol/SimpleTextOut.h>\r
 #include <Protocol/SimpleTextIn.h>\r
 #include <Protocol/FormBrowser2.h>\r
-#include <Protocol/FormBrowserEx.h>\r
+#include <Protocol/FormBrowserEx2.h>\r
+#include <Protocol/DisplayProtocol.h>\r
 #include <Protocol/DevicePath.h>\r
 #include <Protocol/UnicodeCollation.h>\r
 #include <Protocol/HiiConfigAccess.h>\r
@@ -47,105 +48,28 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #include <Library/HiiLib.h>\r
 #include <Library/PcdLib.h>\r
 #include <Library/DevicePathLib.h>\r
+#include <Library/UefiLib.h>\r
 \r
-#include "Colors.h"\r
 \r
 //\r
 // This is the generated header file which includes whatever needs to be exported (strings + IFR)\r
 //\r
 \r
-extern UINT8  SetupBrowserStrings[];\r
+#define UI_ACTION_NONE               0\r
+#define UI_ACTION_REFRESH_FORM       1\r
+#define UI_ACTION_REFRESH_FORMSET    2\r
+#define UI_ACTION_EXIT               3\r
 \r
 //\r
-// Screen definitions\r
-//\r
-#define BANNER_HEIGHT                 6\r
-#define BANNER_COLUMNS                3\r
-#define BANNER_LEFT_COLUMN_INDENT     1\r
-\r
-#define FRONT_PAGE_HEADER_HEIGHT      6\r
-#define NONE_FRONT_PAGE_HEADER_HEIGHT 3\r
-#define LEFT_SKIPPED_COLUMNS          3\r
-#define FOOTER_HEIGHT                 4\r
-#define STATUS_BAR_HEIGHT             1\r
-#define SCROLL_ARROW_HEIGHT           1\r
-#define POPUP_PAD_SPACE_COUNT         5\r
-#define POPUP_FRAME_WIDTH             2\r
-\r
-//\r
-// Definition for function key setting\r
-//\r
-#define NONE_FUNCTION_KEY_SETTING     0\r
-#define ENABLE_FUNCTION_KEY_SETTING   1\r
-\r
-typedef struct {\r
-  EFI_GUID  FormSetGuid;\r
-  UINTN     KeySetting;\r
-} FUNCTIION_KEY_SETTING;\r
-\r
-//\r
-// Character definitions\r
-//\r
-#define CHAR_SPACE              0x0020\r
-#define UPPER_LOWER_CASE_OFFSET 0x20\r
-\r
 //\r
 // Time definitions\r
 //\r
 #define ONE_SECOND  10000000\r
 \r
-//\r
-// Display definitions\r
-//\r
-#define LEFT_HYPER_DELIMITER      L'<'\r
-#define RIGHT_HYPER_DELIMITER     L'>'\r
-\r
-#define LEFT_ONEOF_DELIMITER      L'<'\r
-#define RIGHT_ONEOF_DELIMITER     L'>'\r
-\r
-#define LEFT_NUMERIC_DELIMITER    L'['\r
-#define RIGHT_NUMERIC_DELIMITER   L']'\r
-\r
-#define LEFT_CHECKBOX_DELIMITER   L'['\r
-#define RIGHT_CHECKBOX_DELIMITER  L']'\r
-\r
-#define CHECK_ON                  L'X'\r
-#define CHECK_OFF                 L' '\r
-\r
-#define TIME_SEPARATOR            L':'\r
-#define DATE_SEPARATOR            L'/'\r
-\r
-#define YES_ANSWER                L'Y'\r
-#define NO_ANSWER                 L'N'\r
-\r
-//\r
-// This is the Input Error Message\r
-//\r
-#define INPUT_ERROR 1\r
-\r
-//\r
-// This is the NV RAM update required Message\r
-//\r
-#define NV_UPDATE_REQUIRED  2\r
-\r
-//\r
-// Refresh the Status Bar with flags\r
-//\r
-#define REFRESH_STATUS_BAR  0xff\r
-\r
-//\r
 // Incremental string lenght of ConfigRequest\r
 //\r
 #define CONFIG_REQUEST_STRING_INCREMENTAL  1024\r
 \r
-//\r
-// HII value compare result\r
-//\r
-#define HII_VALUE_UNDEFINED     0\r
-#define HII_VALUE_EQUAL         1\r
-#define HII_VALUE_LESS_THAN     2\r
-#define HII_VALUE_GREATER_THAN  3\r
-\r
 //\r
 // Incremental size of stack for expression\r
 //\r
@@ -163,15 +87,12 @@ typedef struct {
   //\r
   // Produced protocol\r
   //\r
-  EFI_FORM_BROWSER2_PROTOCOL          FormBrowser2;\r
-  \r
-  EFI_FORM_BROWSER_EXTENSION_PROTOCOL FormBrowserEx;\r
+  EFI_FORM_BROWSER2_PROTOCOL            FormBrowser2;\r
+  EFI_FORM_BROWSER_EXTENSION_PROTOCOL   FormBrowserEx;\r
 \r
-} SETUP_DRIVER_PRIVATE_DATA;\r
+  EDKII_FORM_BROWSER_EXTENSION2_PROTOCOL FormBrowserEx2;\r
 \r
-typedef struct {\r
-  EFI_STRING_ID  Banner[BANNER_HEIGHT][BANNER_COLUMNS];\r
-} BANNER_DATA;\r
+} SETUP_DRIVER_PRIVATE_DATA;\r
 \r
 //\r
 // IFR relative definition\r
@@ -194,16 +115,6 @@ typedef struct {
 #define FORM_INCONSISTENT_VALIDATION         0\r
 #define FORM_NO_SUBMIT_VALIDATION            1\r
 \r
-#define FORMSET_CLASS_PLATFORM_SETUP         0x0001\r
-#define FORMSET_CLASS_FRONT_PAGE             0x0002\r
-\r
-typedef struct {\r
-  UINT8               Type;\r
-  UINT8               *Buffer;\r
-  UINT16              BufferLen;\r
-  EFI_IFR_TYPE_VALUE  Value;\r
-} EFI_HII_VALUE;\r
-\r
 #define NAME_VALUE_NODE_SIGNATURE  SIGNATURE_32 ('N', 'V', 'S', 'T')\r
 \r
 typedef struct {\r
@@ -255,6 +166,7 @@ typedef struct {
   BROWSER_STORAGE  *BrowserStorage;\r
 \r
   CHAR16           *ConfigRequest; // <ConfigRequest> = <ConfigHdr> + <RequestElement>\r
+  CHAR16           *ConfigElements;// Elements need to load initial data.\r
   UINTN            ElementCount;   // Number of <RequestElement> in the <ConfigRequest>\r
   UINTN            SpareStrLen;    // Spare length of ConfigRequest string buffer\r
 } FORMSET_STORAGE;\r
@@ -344,6 +256,8 @@ typedef struct {
 typedef struct {\r
   UINTN                Signature;\r
   LIST_ENTRY           Link;\r
+  \r
+  EFI_IFR_ONE_OF_OPTION  *OpCode;   // OneOfOption Data\r
 \r
   EFI_STRING_ID        Text;\r
   UINT8                Flags;\r
@@ -376,6 +290,7 @@ typedef struct {
   LIST_ENTRY            Link;\r
 \r
   UINT8                 Operand;          // The operand (first byte) of this Statement or Question\r
+  EFI_IFR_OP_HEADER     *OpCode;\r
 \r
   //\r
   // Statement Header\r
@@ -384,6 +299,11 @@ typedef struct {
   EFI_STRING_ID         Help;\r
   EFI_STRING_ID         TextTwo;          // For EFI_IFR_TEXT\r
 \r
+  //\r
+  // Fake Question Id, used for statement not has true QuestionId.\r
+  //\r
+  EFI_QUESTION_ID       FakeQuestionId;\r
+\r
   //\r
   // Question Header\r
   //\r
@@ -417,6 +337,7 @@ typedef struct {
   EFI_DEFAULT_ID        DefaultId;        // for EFI_IFR_RESET_BUTTON\r
   EFI_GUID              RefreshGuid;      // for EFI_IFR_REFRESH_ID\r
   BOOLEAN               Locked;           // Whether this statement is locked.\r
+  BOOLEAN               ValueChanged;     // Whether this statement's value is changed.\r
   //\r
   // Get from IFR parsing\r
   //\r
@@ -467,8 +388,6 @@ typedef struct {
   BOOLEAN              ModalForm;            // Whether this is a modal form.\r
   BOOLEAN              Locked;               // Whether this form is locked.\r
 \r
-  BOOLEAN              NvUpdateRequired;     // Whether this form has NV update request.\r
-\r
   LIST_ENTRY           ExpressionListHead;   // List of Expressions (FORM_EXPRESSION)\r
   LIST_ENTRY           StatementListHead;    // List of Statements and Questions (FORM_BROWSER_STATEMENT)\r
   LIST_ENTRY           ConfigRequestHead;    // List of configreques for all storage.\r
@@ -502,6 +421,7 @@ typedef struct {
   UINTN                           IfrBinaryLength;\r
   UINT8                           *IfrBinaryData;\r
 \r
+  BOOLEAN                         QuestionInited;   // Have finished question initilization?\r
   EFI_GUID                        Guid;\r
   EFI_STRING_ID                   FormSetTitle;\r
   EFI_STRING_ID                   Help;\r
@@ -514,14 +434,21 @@ typedef struct {
   FORM_BROWSER_STATEMENT          *StatementBuffer;     // Buffer for all Statements and Questions\r
   EXPRESSION_OPCODE               *ExpressionBuffer;    // Buffer for all Expression OpCode\r
 \r
+  LIST_ENTRY                      StatementListOSF;     // Statement list out side of the form.\r
   LIST_ENTRY                      StorageListHead;      // Storage list (FORMSET_STORAGE)\r
   LIST_ENTRY                      DefaultStoreListHead; // DefaultStore list (FORMSET_DEFAULTSTORE)\r
   LIST_ENTRY                      FormListHead;         // Form list (FORM_BROWSER_FORM)\r
   LIST_ENTRY                      ExpressionListHead;   // List of Expressions (FORM_EXPRESSION)\r
 } FORM_BROWSER_FORMSET;\r
-\r
 #define FORM_BROWSER_FORMSET_FROM_LINK(a)  CR (a, FORM_BROWSER_FORMSET, Link, FORM_BROWSER_FORMSET_SIGNATURE)\r
 \r
+typedef struct {\r
+  LIST_ENTRY   Link;\r
+  EFI_EVENT    RefreshEvent;\r
+} FORM_BROWSER_REFRESH_EVENT_NODE;\r
+\r
+#define FORM_BROWSER_REFRESH_EVENT_FROM_LINK(a) BASE_CR (a, FORM_BROWSER_REFRESH_EVENT_NODE, Link)\r
+\r
 #define BROWSER_CONTEXT_SIGNATURE  SIGNATURE_32 ('B', 'C', 'T', 'X')\r
 \r
 typedef struct {\r
@@ -531,67 +458,54 @@ typedef struct {
   //\r
   // Globals defined in Setup.c\r
   //\r
-  BANNER_DATA           *BannerData;\r
-  UINTN                 ClassOfVfr;\r
-  UINTN                 FunctionKeySetting;\r
-  BOOLEAN               ResetRequired;\r
-  UINT16                Direction;\r
-  EFI_SCREEN_DESCRIPTOR ScreenDimensions;\r
-  CHAR16                *EnterString;\r
-  CHAR16                *EnterCommitString;\r
-  CHAR16                *EnterEscapeString;\r
-  CHAR16                *EscapeString;\r
-  CHAR16                *MoveHighlight;\r
-  CHAR16                *MakeSelection;\r
-  CHAR16                *DecNumericInput;\r
-  CHAR16                *HexNumericInput;\r
-  CHAR16                *ToggleCheckBox;\r
-  CHAR16                *PromptForData;\r
-  CHAR16                *PromptForPassword;\r
-  CHAR16                *PromptForNewPassword;\r
-  CHAR16                *ConfirmPassword;\r
-  CHAR16                *ConfirmError;\r
-  CHAR16                *PassowordInvalid;\r
-  CHAR16                *PressEnter;\r
-  CHAR16                *EmptyString;\r
-  CHAR16                *AreYouSure;\r
-  CHAR16                *YesResponse;\r
-  CHAR16                *NoResponse;\r
-  CHAR16                *MiniString;\r
-  CHAR16                *PlusString;\r
-  CHAR16                *MinusString;\r
-  CHAR16                *AdjustNumber;\r
-  CHAR16                *SaveChanges;\r
-  CHAR16                *OptionMismatch;\r
-  CHAR16                *FormSuppress;\r
-  CHAR16                *ProtocolNotFound;\r
-  CHAR16                PromptBlockWidth;\r
-  CHAR16                OptionBlockWidth;\r
-  CHAR16                HelpBlockWidth;\r
-  FORM_BROWSER_FORMSET  *OldFormSet;\r
+  BOOLEAN                  ResetRequired;\r
+  BOOLEAN                  ExitRequired;\r
+  EFI_HII_HANDLE           HiiHandle;\r
 \r
-  //\r
-  // Globals defined in Ui.c\r
-  //\r
-  LIST_ENTRY           MenuOption;\r
-  VOID                 *MenuRefreshHead;\r
+  LIST_ENTRY           FormHistoryList;\r
 } BROWSER_CONTEXT;\r
 \r
 #define BROWSER_CONTEXT_FROM_LINK(a)  CR (a, BROWSER_CONTEXT, Link, BROWSER_CONTEXT_SIGNATURE)\r
 \r
-#define BROWSER_HOT_KEY_SIGNATURE  SIGNATURE_32 ('B', 'H', 'K', 'S')\r
-\r
 typedef struct {\r
-  UINTN                 Signature;\r
-  LIST_ENTRY            Link;\r
-  \r
-  EFI_INPUT_KEY         *KeyData;\r
-  IN UINT32             Action;\r
-  IN UINT16             DefaultId;\r
-  IN EFI_STRING         HelpString;\r
-} BROWSER_HOT_KEY;\r
+  EFI_HII_HANDLE  Handle;\r
 \r
-#define BROWSER_HOT_KEY_FROM_LINK(a)  CR (a, BROWSER_HOT_KEY, Link, BROWSER_HOT_KEY_SIGNATURE)\r
+  //\r
+  // Target formset/form/Question information\r
+  //\r
+  EFI_GUID        FormSetGuid;\r
+  UINT16          FormId;\r
+  UINT16          QuestionId;\r
+  UINTN           Sequence;  // used for time/date only.\r
+\r
+  UINTN           TopRow;\r
+  UINTN           BottomRow;\r
+  UINTN           PromptCol;\r
+  UINTN           OptionCol;\r
+  UINTN           CurrentRow;\r
+\r
+  //\r
+  // Ation for Browser to taken:\r
+  //   UI_ACTION_NONE            - navigation inside a form\r
+  //   UI_ACTION_REFRESH_FORM    - re-evaluate expressions and repaint form\r
+  //   UI_ACTION_REFRESH_FORMSET - re-parse formset IFR binary\r
+  //\r
+  UINTN           Action;\r
+\r
+  //\r
+  // Current selected fomset/form/Question\r
+  //\r
+  FORM_BROWSER_FORMSET    *FormSet;\r
+  FORM_BROWSER_FORM       *Form;\r
+  FORM_BROWSER_STATEMENT  *Statement;\r
+\r
+  //\r
+  // Whether the Form is editable\r
+  //\r
+  BOOLEAN                 FormEditable;\r
+\r
+  FORM_ENTRY_INFO            *CurrentMenu;\r
+} UI_MENU_SELECTION;\r
 \r
 //\r
 // Scope for get defaut value. It may be GetDefaultForNoStorage, GetDefaultForStorage or GetDefaultForAll.\r
@@ -614,72 +528,32 @@ typedef enum {
 } GET_SET_QUESTION_VALUE_WITH;\r
 \r
 extern EFI_HII_DATABASE_PROTOCOL         *mHiiDatabase;\r
-extern EFI_HII_STRING_PROTOCOL           *mHiiString;\r
 extern EFI_HII_CONFIG_ROUTING_PROTOCOL   *mHiiConfigRouting;\r
 extern EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *mPathFromText;\r
+extern EDKII_FORM_DISPLAY_ENGINE_PROTOCOL *mFormDisplay;\r
 \r
-extern BANNER_DATA           *gBannerData;\r
-extern EFI_HII_HANDLE        gFrontPageHandle;\r
-extern UINTN                 gClassOfVfr;\r
-extern UINTN                 gFunctionKeySetting;\r
 extern BOOLEAN               gResetRequired;\r
-extern EFI_HII_HANDLE        gHiiHandle;\r
-extern UINT16                gDirection;\r
-extern EFI_SCREEN_DESCRIPTOR gScreenDimensions;\r
+extern BOOLEAN               gExitRequired;\r
 \r
 extern FORM_BROWSER_FORMSET  *gOldFormSet;\r
 extern LIST_ENTRY            gBrowserFormSetList;\r
 extern LIST_ENTRY            gBrowserHotKeyList;\r
 extern BROWSER_SETTING_SCOPE gBrowserSettingScope;\r
 extern EXIT_HANDLER          ExitHandlerFunction;\r
-extern UINTN                 gFooterHeight;\r
-\r
+extern EFI_HII_HANDLE        mCurrentHiiHandle;\r
 //\r
 // Browser Global Strings\r
 //\r
-extern CHAR16            *gDiscardFailed;\r
-extern CHAR16            *gDefaultFailed;\r
-extern CHAR16            *gEnterString;\r
-extern CHAR16            *gEnterCommitString;\r
-extern CHAR16            *gEnterEscapeString;\r
-extern CHAR16            *gEscapeString;\r
-extern CHAR16            *gSaveFailed;\r
-extern CHAR16            *gMoveHighlight;\r
-extern CHAR16            *gMakeSelection;\r
-extern CHAR16            *gDecNumericInput;\r
-extern CHAR16            *gHexNumericInput;\r
-extern CHAR16            *gToggleCheckBox;\r
-extern CHAR16            *gPromptForData;\r
-extern CHAR16            *gPromptForPassword;\r
-extern CHAR16            *gPromptForNewPassword;\r
-extern CHAR16            *gConfirmPassword;\r
-extern CHAR16            *gConfirmError;\r
-extern CHAR16            *gPassowordInvalid;\r
-extern CHAR16            *gPressEnter;\r
 extern CHAR16            *gEmptyString;\r
-extern CHAR16            *gAreYouSure;\r
-extern CHAR16            *gYesResponse;\r
-extern CHAR16            *gNoResponse;\r
-extern CHAR16            *gMiniString;\r
-extern CHAR16            *gPlusString;\r
-extern CHAR16            *gMinusString;\r
-extern CHAR16            *gAdjustNumber;\r
-extern CHAR16            *gSaveChanges;\r
-extern CHAR16            *gOptionMismatch;\r
-extern CHAR16            *gFormSuppress;\r
-extern CHAR16            *gProtocolNotFound;\r
-\r
-extern CHAR16            gPromptBlockWidth;\r
-extern CHAR16            gOptionBlockWidth;\r
-extern CHAR16            gHelpBlockWidth;\r
 \r
 extern EFI_GUID          gZeroGuid;\r
-extern EFI_GUID          gTianoHiiIfrGuid;\r
 \r
-#include "Ui.h"\r
+extern UI_MENU_SELECTION  *gCurrentSelection;\r
+\r
 //\r
 // Global Procedure Defines\r
 //\r
+#include "Expression.h"\r
 \r
 /**\r
   Initialize the HII String Token to the correct values.\r
@@ -690,91 +564,6 @@ InitializeBrowserStrings (
   VOID\r
   );\r
 \r
-/**\r
-  Prints a unicode string to the default console,\r
-  using L"%s" format.\r
-\r
-  @param  String     String pointer.\r
-\r
-  @return Length of string printed to the console\r
-\r
-**/\r
-UINTN\r
-PrintString (\r
-  IN CHAR16       *String\r
-  );\r
-\r
-/**\r
-  Prints a chracter to the default console,\r
-  using L"%c" format.\r
-\r
-  @param  Character  Character to print.\r
-\r
-  @return Length of string printed to the console.\r
-\r
-**/\r
-UINTN\r
-PrintChar (\r
-  CHAR16       Character\r
-  );\r
-\r
-/**\r
-  Prints a formatted unicode string to the default console, at\r
-  the supplied cursor position.\r
-\r
-  @param  Column     The cursor position to print the string at.\r
-  @param  Row        The cursor position to print the string at\r
-  @param  Fmt        Format string\r
-  @param  ...        Variable argument list for formating string.\r
-\r
-  @return Length of string printed to the console\r
-\r
-**/\r
-UINTN\r
-EFIAPI\r
-PrintAt (\r
-  IN UINTN     Column,\r
-  IN UINTN     Row,\r
-  IN CHAR16    *Fmt,\r
-  ...\r
-  );\r
-\r
-/**\r
-  Prints a unicode string to the default console, at\r
-  the supplied cursor position, using L"%s" format.\r
-\r
-  @param  Column     The cursor position to print the string at.\r
-  @param  Row        The cursor position to print the string at\r
-  @param  String     String pointer.\r
-\r
-  @return Length of string printed to the console\r
-\r
-**/\r
-UINTN\r
-PrintStringAt (\r
-  IN UINTN     Column,\r
-  IN UINTN     Row,\r
-  IN CHAR16    *String\r
-  );\r
-\r
-/**\r
-  Prints a chracter to the default console, at\r
-  the supplied cursor position, using L"%c" format.\r
-\r
-  @param  Column     The cursor position to print the string at.\r
-  @param  Row        The cursor position to print the string at.\r
-  @param  Character  Character to print.\r
-\r
-  @return Length of string printed to the console.\r
-\r
-**/\r
-UINTN\r
-PrintCharAt (\r
-  IN UINTN     Column,\r
-  IN UINTN     Row,\r
-  CHAR16       Character\r
-  );\r
-\r
 /**\r
   Parse opcodes in the formset IFR binary.\r
 \r
@@ -800,17 +589,6 @@ DestroyFormSet (
   IN OUT FORM_BROWSER_FORMSET  *FormSet\r
   );\r
 \r
-/**\r
-  This function displays the page frame.\r
-\r
-  @param  Selection              Selection contains the information about \r
-                                 the Selection, form and formset to be displayed.\r
-                                 Selection action may be updated in retrieve callback.\r
-**/\r
-VOID\r
-DisplayPageFrame (\r
-  IN UI_MENU_SELECTION    *Selection\r
-  );\r
 \r
 /**\r
   Create a new string in HII Package List.\r
@@ -859,59 +637,6 @@ GetToken (
   IN  EFI_HII_HANDLE               HiiHandle\r
   );\r
 \r
-/**\r
-  Draw a pop up windows based on the dimension, number of lines and\r
-  strings specified.\r
-\r
-  @param RequestedWidth  The width of the pop-up.\r
-  @param NumberOfLines   The number of lines.\r
-  @param Marker          The variable argument list for the list of string to be printed.\r
-\r
-**/\r
-VOID\r
-CreateSharedPopUp (\r
-  IN  UINTN                       RequestedWidth,\r
-  IN  UINTN                       NumberOfLines,\r
-  IN  VA_LIST                     Marker\r
-  );\r
-\r
-/**\r
-  Routine used to abstract a generic dialog interface and return the selected key or string\r
-\r
-  @param  NumberOfLines          The number of lines for the dialog box\r
-  @param  HotKey                 Defines whether a single character is parsed\r
-                                 (TRUE) and returned in KeyValue or a string is\r
-                                 returned in StringBuffer.  Two special characters\r
-                                 are considered when entering a string, a SCAN_ESC\r
-                                 and an CHAR_CARRIAGE_RETURN.  SCAN_ESC terminates\r
-                                 string input and returns\r
-  @param  MaximumStringSize      The maximum size in bytes of a typed in string\r
-                                 (each character is a CHAR16) and the minimum\r
-                                 string returned is two bytes\r
-  @param  StringBuffer           The passed in pointer to the buffer which will\r
-                                 hold the typed in string if HotKey is FALSE\r
-  @param  KeyValue               The EFI_KEY value returned if HotKey is TRUE..\r
-  @param  ...                    A series of (quantity == NumberOfLines) text\r
-                                 strings which will be used to construct the dialog\r
-                                 box\r
-\r
-  @retval EFI_SUCCESS            Displayed dialog and received user interaction\r
-  @retval EFI_INVALID_PARAMETER  One of the parameters was invalid (e.g.\r
-                                 (StringBuffer == NULL) && (HotKey == FALSE))\r
-  @retval EFI_DEVICE_ERROR       User typed in an ESC character to exit the routine\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-CreateDialog (\r
-  IN  UINTN                       NumberOfLines,\r
-  IN  BOOLEAN                     HotKey,\r
-  IN  UINTN                       MaximumStringSize,\r
-  OUT CHAR16                      *StringBuffer,\r
-  OUT EFI_INPUT_KEY               *KeyValue,\r
-  ...\r
-  );\r
-\r
 /**\r
   Get Value for given Name from a NameValue Storage.\r
 \r
@@ -939,6 +664,7 @@ GetValueByName (
   @param  Name                   The Name.\r
   @param  Value                  The Value to set.\r
   @param  SetValueTo             Whether update editValue or Value.\r
+  @param  ReturnNode             The node use the input name.\r
 \r
   @retval EFI_SUCCESS            Value found for given Name.\r
   @retval EFI_NOT_FOUND          No such Name found in NameValue storage.\r
@@ -946,10 +672,31 @@ GetValueByName (
 **/\r
 EFI_STATUS\r
 SetValueByName (\r
-  IN BROWSER_STORAGE             *Storage,\r
-  IN CHAR16                      *Name,\r
-  IN CHAR16                      *Value,\r
-  IN GET_SET_QUESTION_VALUE_WITH SetValueTo\r
+  IN  BROWSER_STORAGE             *Storage,\r
+  IN  CHAR16                      *Name,\r
+  IN  CHAR16                      *Value,\r
+  IN  GET_SET_QUESTION_VALUE_WITH SetValueTo,\r
+  OUT NAME_VALUE_NODE             **ReturnNode\r
+  );\r
+\r
+/**\r
+  Validate whether this question's value has changed.\r
+\r
+  @param  FormSet                FormSet data structure.\r
+  @param  Form                   Form data structure.\r
+  @param  Question               Question to be initialized.\r
+  @param  GetValueFrom           Where to get value, may from editbuffer, buffer or hii driver.\r
+\r
+  @retval TRUE                   Question's value has changed.\r
+  @retval FALSE                  Question's value has not changed\r
+\r
+**/\r
+BOOLEAN\r
+IsQuestionValueChanged (\r
+  IN FORM_BROWSER_FORMSET             *FormSet,\r
+  IN FORM_BROWSER_FORM                *Form,\r
+  IN OUT FORM_BROWSER_STATEMENT       *Question,\r
+  IN GET_SET_QUESTION_VALUE_WITH      GetValueFrom\r
   );\r
 \r
 /**\r
@@ -1071,10 +818,8 @@ GetQuestionDefault (
 \r
   @param  FormSet                FormSet data structure.\r
 \r
-  @retval EFI_SUCCESS            The function completed successfully.\r
-\r
 **/\r
-EFI_STATUS\r
+VOID\r
 InitializeCurrentSetting (\r
   IN OUT FORM_BROWSER_FORMSET             *FormSet\r
   );\r
@@ -1087,7 +832,6 @@ InitializeCurrentSetting (
                                  GUID), take the first FormSet found in package\r
                                  list.\r
   @param  FormSet                FormSet data structure.\r
-  @param  UpdateGlobalVar        Whether need to update the global variable.\r
 \r
   @retval EFI_SUCCESS            The function completed successfully.\r
   @retval EFI_NOT_FOUND          The specified FormSet could not be found.\r
@@ -1097,8 +841,7 @@ EFI_STATUS
 InitializeFormSet (\r
   IN  EFI_HII_HANDLE                   Handle,\r
   IN OUT EFI_GUID                      *FormSetGuid,\r
-  OUT FORM_BROWSER_FORMSET             *FormSet,\r
-  IN  BOOLEAN                          UpdateGlobalVar                   \r
+  OUT FORM_BROWSER_FORMSET             *FormSet                   \r
   );\r
 \r
 /**\r
@@ -1176,6 +919,7 @@ LoadFormSetConfig (
   @param  Storage                The Storage to be conveted.\r
   @param  ConfigResp             The returned <ConfigResp>.\r
   @param  ConfigRequest          The ConfigRequest string.\r
+  @param  GetEditBuf             Get the data from editbuffer or buffer.\r
 \r
   @retval EFI_SUCCESS            Convert success.\r
   @retval EFI_INVALID_PARAMETER  Incorrect storage type.\r
@@ -1185,7 +929,8 @@ EFI_STATUS
 StorageToConfigResp (\r
   IN BROWSER_STORAGE         *Storage,\r
   IN CHAR16                  **ConfigResp,\r
-  IN CHAR16                  *ConfigRequest\r
+  IN CHAR16                  *ConfigRequest,\r
+  IN BOOLEAN                 GetEditBuf\r
   );\r
 \r
 /**\r
@@ -1210,10 +955,8 @@ ConfigRespToStorage (
   @param  FormSet                FormSet data structure.\r
   @param  Storage                Buffer Storage.\r
 \r
-  @retval EFI_SUCCESS            The function completed successfully.\r
-\r
 **/\r
-EFI_STATUS\r
+VOID\r
 LoadStorage (\r
   IN FORM_BROWSER_FORMSET    *FormSet,\r
   IN FORMSET_STORAGE         *Storage\r
@@ -1349,30 +1092,29 @@ BrowserCallback (
                          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 Repaint         Whether need to repaint the menu.\r
-  @param NewLine         Whether need to show at new line.\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           Need return.\r
-  @retval FALSE          No need to return.\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     BOOLEAN              *Repaint, \r
-  IN     BOOLEAN              *NewLine  \r
+  IN OUT UI_MENU_SELECTION        *Selection,\r
+  IN       BROWSER_SETTING_SCOPE  SettingLevel\r
   );\r
 \r
 /**\r
-  check whether the formset need to update the NV.\r
+  check whether the form need to update the NV.\r
 \r
-  @param  FormSet                FormSet data structure.\r
-  @param  SetValue               Whether set new value or clear old value.\r
+  @param  Form                Form data structure.\r
 \r
+  @retval TRUE                   Need to update the NV.\r
+  @retval FALSE                  No need to update the NV.\r
 **/\r
-VOID\r
-UpdateNvInfoInForm (\r
-  IN FORM_BROWSER_FORMSET  *FormSet,\r
-  IN BOOLEAN               SetValue\r
+BOOLEAN\r
+IsNvUpdateRequiredForForm (\r
+  IN FORM_BROWSER_FORM    *Form\r
   );\r
 \r
 /**\r
@@ -1383,11 +1125,24 @@ UpdateNvInfoInForm (
   @retval TRUE                   Need to update the NV.\r
   @retval FALSE                  No need to update the NV.\r
 **/\r
-BOOLEAN \r
-IsNvUpdateRequired (\r
+BOOLEAN\r
+IsNvUpdateRequiredForFormSet (\r
   IN FORM_BROWSER_FORMSET  *FormSet\r
   );\r
 \r
+/**\r
+  Check whether the storage data for current form set is changed.\r
+\r
+  @param  FormSet           FormSet data structure.\r
+\r
+  @retval TRUE              Data is changed.\r
+  @retval FALSE             Data is not changed.\r
+**/\r
+BOOLEAN \r
+IsStorageDataChangedForFormSet (\r
+  IN FORM_BROWSER_FORMSET             *FormSet\r
+  );\r
+\r
 /**\r
   Call the call back function for the question and process the return action.\r
 \r
@@ -1516,6 +1271,38 @@ RegiserExitHandler (
   IN EXIT_HANDLER Handler\r
   );\r
 \r
+/**\r
+  \r
+  Check whether the browser data has been modified. \r
+\r
+  @retval TRUE        Browser data is changed.\r
+  @retval FALSE       No browser data is changed.\r
+\r
+**/\r
+BOOLEAN \r
+EFIAPI\r
+IsBrowserDataModified (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  \r
+  Execute the action requested by the Action parameter. \r
+\r
+  @param[in] Action     Execute the request action.\r
+  @param[in] DefaultId  The default Id info when need to load default value.\r
+\r
+  @retval EFI_SUCCESS              Execute the request action succss.\r
+  @retval EFI_INVALID_PARAMETER    The input action value is invalid.\r
+\r
+**/\r
+EFI_STATUS \r
+EFIAPI\r
+ExecuteAction (\r
+  IN UINT32        Action,\r
+  IN UINT16        DefaultId\r
+  );\r
+\r
 /**\r
   Create reminder to let user to choose save or discard the changed browser data.\r
   Caller can use it to actively check the changed browser data.\r
@@ -1544,6 +1331,267 @@ GetHotKeyFromRegisterList (
   IN EFI_INPUT_KEY *KeyData\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
+/**\r
+  Password may be stored as encrypted by Configuration Driver. When change a\r
+  password, user will be challenged with old password. To validate user input old\r
+  password, we will send the clear text to Configuration Driver via Callback().\r
+  Configuration driver is responsible to check the passed in password and return\r
+  the validation result. If validation pass, state machine in password Callback()\r
+  will transit from BROWSER_STATE_VALIDATE_PASSWORD to BROWSER_STATE_SET_PASSWORD.\r
+  After user type in new password twice, Callback() will be invoked to send the\r
+  new password to Configuration Driver.\r
+\r
+  @param  Selection              Pointer to UI_MENU_SELECTION.\r
+  @param  MenuOption             The MenuOption for this password Question.\r
+  @param  String                 The clear text of password.\r
+\r
+  @retval EFI_NOT_AVAILABLE_YET  Callback() request to terminate password input.\r
+  @return In state of BROWSER_STATE_VALIDATE_PASSWORD:\r
+  @retval EFI_SUCCESS            Password correct, Browser will prompt for new\r
+                                 password.\r
+  @retval EFI_NOT_READY          Password incorrect, Browser will show error\r
+                                 message.\r
+  @retval Other                  Browser will do nothing.\r
+  @return In state of BROWSER_STATE_SET_PASSWORD:\r
+  @retval EFI_SUCCESS            Set password success.\r
+  @retval Other                  Set password failed.\r
+\r
+**/\r
+EFI_STATUS\r
+PasswordCallback (\r
+  IN  UI_MENU_SELECTION           *Selection,\r
+  IN  FORM_BROWSER_STATEMENT      *Question,\r
+  IN  CHAR16                      *String\r
+  );\r
+\r
+/**\r
+  Display error message for invalid password.\r
+\r
+**/\r
+VOID\r
+PasswordInvalid (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  The worker function that send the displays to the screen. On output,\r
+  the selection made by user is returned.\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
+  @retval EFI_SUCCESS    The page is displayed successfully.\r
+  @return Other value if the page failed to be diplayed.\r
+\r
+**/\r
+EFI_STATUS\r
+SetupBrowser (\r
+  IN OUT UI_MENU_SELECTION    *Selection\r
+  );\r
+  \r
+/**\r
+  Free up the resource allocated for all strings required\r
+  by Setup Browser.\r
+\r
+**/\r
+VOID\r
+FreeBrowserStrings (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Create a menu with specified formset GUID and form ID, and add it as a child\r
+  of the given parent menu.\r
+\r
+  @param  HiiHandle              Hii handle related to this formset.\r
+  @param  FormSetGuid            The Formset Guid of menu to be added.\r
+  @param  FormId                 The Form ID of menu to be added.\r
+  @param  QuestionId             The question id of this menu to be added.\r
+\r
+  @return A pointer to the newly added menu or NULL if memory is insufficient.\r
+\r
+**/\r
+FORM_ENTRY_INFO *\r
+UiAddMenuList (\r
+  IN EFI_HII_HANDLE       HiiHandle,\r
+  IN EFI_GUID             *FormSetGuid,\r
+  IN UINT16               FormId,\r
+  IN UINT16               QuestionId\r
+  );\r
+\r
+/**\r
+  Search Menu with given FormSetGuid and FormId in all cached menu list.\r
+\r
+  @param  HiiHandle              HiiHandle for FormSet.\r
+  @param  FormSetGuid            The Formset GUID of the menu to search.\r
+  @param  FormId                 The Form ID of menu to search.\r
+\r
+  @return A pointer to menu found or NULL if not found.\r
+\r
+**/\r
+FORM_ENTRY_INFO *\r
+UiFindMenuList (\r
+  IN EFI_HII_HANDLE       HiiHandle, \r
+  IN EFI_GUID             *FormSetGuid,\r
+  IN UINT16               FormId\r
+  );\r
+\r
+/**\r
+  Free Menu list linked list.\r
+\r
+  @param  MenuListHead    One Menu list point in the menu list.\r
+\r
+**/\r
+VOID\r
+UiFreeMenuList (\r
+  LIST_ENTRY   *MenuListHead\r
+  );\r
+\r
+/**\r
+  Find parent menu for current menu.\r
+\r
+  @param  CurrentMenu    Current Menu\r
+\r
+  @retval   The parent menu for current menu.\r
+**/\r
+FORM_ENTRY_INFO *\r
+UiFindParentMenu (\r
+  IN FORM_ENTRY_INFO  *CurrentMenu\r
+  );\r
+\r
+/**\r
+  Search an Option of a Question by its value.\r
+\r
+  @param  Question               The Question\r
+  @param  OptionValue            Value for Option to be searched.\r
+\r
+  @retval Pointer                Pointer to the found Option.\r
+  @retval NULL                   Option not found.\r
+\r
+**/\r
+QUESTION_OPTION *\r
+ValueToOption (\r
+  IN FORM_BROWSER_STATEMENT   *Question,\r
+  IN EFI_HII_VALUE            *OptionValue\r
+  );\r
+/**\r
+  Return data element in an Array by its Index.\r
+\r
+  @param  Array                  The data array.\r
+  @param  Type                   Type of the data in this array.\r
+  @param  Index                  Zero based index for data in this array.\r
+\r
+  @retval Value                  The data to be returned\r
+\r
+**/\r
+UINT64\r
+GetArrayData (\r
+  IN VOID                     *Array,\r
+  IN UINT8                    Type,\r
+  IN UINTN                    Index\r
+  );\r
+\r
+/**\r
+  Set value of a data element in an Array by its Index.\r
+\r
+  @param  Array                  The data array.\r
+  @param  Type                   Type of the data in this array.\r
+  @param  Index                  Zero based index for data in this array.\r
+  @param  Value                  The value to be set.\r
+\r
+**/\r
+VOID\r
+SetArrayData (\r
+  IN VOID                     *Array,\r
+  IN UINT8                    Type,\r
+  IN UINTN                    Index,\r
+  IN UINT64                   Value\r
+  );\r
+\r
+/**\r
+   Compare two Hii value.\r
\r
+   @param  Value1                 Expression value to compare on left-hand.\r
+   @param  Value2                 Expression value to compare on right-hand.\r
+   @param  Result                 Return value after compare.\r
+                                  retval 0                      Two operators equal.\r
+                                  return Positive value if Value1 is greater than Value2.\r
+                                  retval Negative value if Value1 is less than Value2.\r
+   @param  HiiHandle              Only required for string compare.\r
\r
+   @retval other                  Could not perform compare on two values.\r
+   @retval EFI_SUCCESS            Compare the value success.\r
\r
+**/\r
+EFI_STATUS\r
+CompareHiiValue (\r
+  IN  EFI_HII_VALUE   *Value1,\r
+  IN  EFI_HII_VALUE   *Value2,\r
+  OUT INTN            *Result,\r
+  IN  EFI_HII_HANDLE  HiiHandle OPTIONAL\r
+  );\r
+\r
+/**\r
+  Perform Password check. \r
+  Passwork may be encrypted by driver that requires the specific check.\r
+  \r
+  @param  Form             Form where Password Statement is in.\r
+  @param  Statement        Password statement\r
+  @param  PasswordString   Password string to be checked. It may be NULL.\r
+                           NULL means to restore password.\r
+                           "" string can be used to checked whether old password does exist.\r
+  \r
+  @return Status     Status of Password check.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PasswordCheck (\r
+  IN FORM_DISPLAY_ENGINE_FORM      *Form,\r
+  IN FORM_DISPLAY_ENGINE_STATEMENT *Statement,\r
+  IN EFI_STRING                    PasswordString  OPTIONAL\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
+/**\r
+\r
+  Initialize the Display form structure data.\r
+\r
+**/\r
+VOID\r
+InitializeDisplayFormData (\r
+  VOID\r
+  );\r
+\r
+\r
 /**\r
   Base on the current formset info, clean the ConfigRequest string in browser storage.\r
 \r
@@ -1554,5 +1602,5 @@ VOID
 CleanBrowserStorage (\r
   IN OUT FORM_BROWSER_FORMSET  *FormSet\r
   );\r
-\r
+  \r
 #endif\r
index 7e740bc0990548c0041afafa1c623dc5d8432587..395c9383d546e60ba967e621f19778b12e046bcb 100644 (file)
@@ -19,7 +19,7 @@
   BASE_NAME                      = SetupBrowser\r
   FILE_GUID                      = EBf342FE-B1D3-4EF8-957C-8048606FF671\r
   MODULE_TYPE                    = DXE_DRIVER\r
-  VERSION_STRING                 = 1.0\r
+  VERSION_STRING                 = 2.0\r
   ENTRY_POINT                    = InitializeSetup\r
 \r
 #\r
 #\r
 \r
 [Sources]\r
-  SetupBrowserStr.uni\r
   Setup.c\r
   Setup.h\r
   IfrParse.c\r
   Expression.c\r
-  InputHandler.c\r
-  Print.c\r
   Presentation.c\r
-  ProcessOptions.c\r
-  Ui.c\r
-  Ui.h\r
-  Colors.h\r
-\r
+  Expression.h\r
 \r
 [Packages]\r
   MdePkg/MdePkg.dec\r
   HiiLib\r
   DevicePathLib\r
   PcdLib\r
+  UefiLib\r
 \r
 [Guids]\r
-  gEfiIfrTianoGuid                              ## CONSUMES  ## GUID\r
   gEfiIfrFrameworkGuid                          ## CONSUMES  ## GUID\r
   gEfiHiiPlatformSetupFormsetGuid\r
   gEfiHiiStandardFormGuid                       ## SOMETIMES_CONSUMES ## GUID\r
 \r
 [Protocols]\r
   gEfiHiiConfigAccessProtocolGuid               ## CONSUMES\r
-  gEfiHiiStringProtocolGuid                     ## CONSUMES\r
   gEfiFormBrowser2ProtocolGuid                  ## PRODUCES\r
-  gEfiFormBrowserExProtocolGuid                 ## PRODUCES\r
+  gEdkiiFormBrowserEx2ProtocolGuid              ## PRODUCES\r
   gEfiHiiConfigRoutingProtocolGuid              ## CONSUMES\r
   gEfiHiiDatabaseProtocolGuid                   ## CONSUMES\r
   gEfiUnicodeCollation2ProtocolGuid             ## CONSUMES\r
   gEfiUserManagerProtocolGuid                   ## SOMETIMES_CONSUMES\r
   gEfiDevicePathFromTextProtocolGuid            ## SOMETIMES_CONSUMES\r
+  gEdkiiFormDisplayEngineProtocolGuid           ## PRODUCE\r
+  gEfiFormBrowserExProtocolGuid                 ## PRODUCE\r
 \r
 [FeaturePcd]\r
   gEfiMdeModulePkgTokenSpaceGuid.PcdFrameworkCompatibilitySupport          ## CONSUMES\r
-  gEfiMdeModulePkgTokenSpaceGuid.PcdBrowserGrayOutTextStatement            ## CONSUMES\r
-  gEfiMdeModulePkgTokenSpaceGuid.PcdBrowerGrayOutReadOnlyMenu              ## CONSUMES\r
-\r
-[Pcd]\r
-  gEfiMdeModulePkgTokenSpaceGuid.PcdBrowserSubtitleTextColor               ## CONSUMES\r
-  gEfiMdeModulePkgTokenSpaceGuid.PcdBrowserFieldTextColor                  ## CONSUMES\r
-  gEfiMdeModulePkgTokenSpaceGuid.PcdBrowserFieldTextHighlightColor         ## CONSUMES\r
-  gEfiMdeModulePkgTokenSpaceGuid.PcdBrowserFieldBackgroundHighlightColor   ## CONSUMES\r
 \r
 [Depex]\r
   gEfiHiiDatabaseProtocolGuid AND gEfiHiiConfigRoutingProtocolGuid\r
 \r
+[BuildOptions] \r
+  MSFT:*_*_*_CC_FLAGS     = /Od \r
 \r