Home | History | Annotate | Download | only in SetupBrowserDxe
      1 /** @file
      2 Utility functions for UI presentation.
      3 
      4 Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR>
      5 (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
      6 This program and the accompanying materials
      7 are licensed and made available under the terms and conditions of the BSD License
      8 which accompanies this distribution.  The full text of the license may be found at
      9 http://opensource.org/licenses/bsd-license.php
     10 
     11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #include "Setup.h"
     17 
     18 BOOLEAN            mHiiPackageListUpdated;
     19 UI_MENU_SELECTION  *gCurrentSelection;
     20 EFI_HII_HANDLE     mCurrentHiiHandle = NULL;
     21 EFI_GUID           mCurrentFormSetGuid = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}};
     22 UINT16             mCurrentFormId = 0;
     23 EFI_EVENT          mValueChangedEvent = NULL;
     24 LIST_ENTRY         mRefreshEventList = INITIALIZE_LIST_HEAD_VARIABLE (mRefreshEventList);
     25 UINT16             mCurFakeQestId;
     26 FORM_DISPLAY_ENGINE_FORM gDisplayFormData;
     27 BOOLEAN            mFinishRetrieveCall = FALSE;
     28 
     29 /**
     30   Evaluate all expressions in a Form.
     31 
     32   @param  FormSet        FormSet this Form belongs to.
     33   @param  Form           The Form.
     34 
     35   @retval EFI_SUCCESS    The expression evaluated successfuly
     36 
     37 **/
     38 EFI_STATUS
     39 EvaluateFormExpressions (
     40   IN FORM_BROWSER_FORMSET  *FormSet,
     41   IN FORM_BROWSER_FORM     *Form
     42   )
     43 {
     44   EFI_STATUS       Status;
     45   LIST_ENTRY       *Link;
     46   FORM_EXPRESSION  *Expression;
     47 
     48   Link = GetFirstNode (&Form->ExpressionListHead);
     49   while (!IsNull (&Form->ExpressionListHead, Link)) {
     50     Expression = FORM_EXPRESSION_FROM_LINK (Link);
     51     Link = GetNextNode (&Form->ExpressionListHead, Link);
     52 
     53     if (Expression->Type == EFI_HII_EXPRESSION_INCONSISTENT_IF ||
     54         Expression->Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF ||
     55         Expression->Type == EFI_HII_EXPRESSION_WARNING_IF ||
     56         Expression->Type == EFI_HII_EXPRESSION_WRITE ||
     57         (Expression->Type == EFI_HII_EXPRESSION_READ && Form->FormType != STANDARD_MAP_FORM_TYPE)) {
     58       //
     59       // Postpone Form validation to Question editing or Form submitting or Question Write or Question Read for nonstandard form.
     60       //
     61       continue;
     62     }
     63 
     64     Status = EvaluateExpression (FormSet, Form, Expression);
     65     if (EFI_ERROR (Status)) {
     66       return Status;
     67     }
     68   }
     69 
     70   return EFI_SUCCESS;
     71 }
     72 
     73 /**
     74   Add empty function for event process function.
     75 
     76   @param Event    The Event need to be process
     77   @param Context  The context of the event.
     78 
     79 **/
     80 VOID
     81 EFIAPI
     82 SetupBrowserEmptyFunction (
     83   IN  EFI_EVENT    Event,
     84   IN  VOID         *Context
     85   )
     86 {
     87 }
     88 
     89 /**
     90   Base on the opcode buffer info to get the display statement.
     91 
     92   @param OpCode    The input opcode buffer for this statement.
     93 
     94   @retval Statement  The statement use this opcode buffer.
     95 
     96 **/
     97 FORM_DISPLAY_ENGINE_STATEMENT *
     98 GetDisplayStatement (
     99   IN EFI_IFR_OP_HEADER     *OpCode
    100   )
    101 {
    102   FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement;
    103   LIST_ENTRY                    *Link;
    104 
    105   Link = GetFirstNode (&gDisplayFormData.StatementListHead);
    106   while (!IsNull (&gDisplayFormData.StatementListHead, Link)) {
    107     DisplayStatement = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (Link);
    108 
    109     if (DisplayStatement->OpCode == OpCode) {
    110       return DisplayStatement;
    111     }
    112     Link = GetNextNode (&gDisplayFormData.StatementListHead, Link);
    113   }
    114 
    115   return NULL;
    116 }
    117 
    118 /**
    119   Free the refresh event list.
    120 
    121 **/
    122 VOID
    123 FreeRefreshEvent (
    124   VOID
    125   )
    126 {
    127   LIST_ENTRY   *Link;
    128   FORM_BROWSER_REFRESH_EVENT_NODE *EventNode;
    129 
    130   while (!IsListEmpty (&mRefreshEventList)) {
    131     Link = GetFirstNode (&mRefreshEventList);
    132     EventNode = FORM_BROWSER_REFRESH_EVENT_FROM_LINK (Link);
    133     RemoveEntryList (&EventNode->Link);
    134 
    135     gBS->CloseEvent (EventNode->RefreshEvent);
    136 
    137     FreePool (EventNode);
    138   }
    139 }
    140 
    141 /**
    142   Check whether this statement value is changed. If yes, update the statement value and return TRUE;
    143   else return FALSE.
    144 
    145   @param Statement           The statement need to check.
    146 
    147 **/
    148 VOID
    149 UpdateStatement (
    150   IN OUT FORM_BROWSER_STATEMENT        *Statement
    151   )
    152 {
    153   GetQuestionValue (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithHiiDriver);
    154 
    155   //
    156   // Reset FormPackage update flag
    157   //
    158   mHiiPackageListUpdated = FALSE;
    159 
    160   //
    161   // Question value may be changed, need invoke its Callback()
    162   //
    163   ProcessCallBackFunction (gCurrentSelection, gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, EFI_BROWSER_ACTION_RETRIEVE, FALSE);
    164 
    165   if (mHiiPackageListUpdated) {
    166     //
    167     // Package list is updated, force to reparse IFR binary of target Formset
    168     //
    169     mHiiPackageListUpdated = FALSE;
    170     gCurrentSelection->Action = UI_ACTION_REFRESH_FORMSET;
    171   }
    172 }
    173 
    174 /**
    175   Refresh the question which has refresh guid event attribute.
    176 
    177   @param Event    The event which has this function related.
    178   @param Context  The input context info related to this event or the status code return to the caller.
    179 **/
    180 VOID
    181 EFIAPI
    182 RefreshEventNotifyForStatement(
    183   IN      EFI_EVENT Event,
    184   IN      VOID      *Context
    185   )
    186 {
    187   FORM_BROWSER_STATEMENT        *Statement;
    188 
    189   Statement = (FORM_BROWSER_STATEMENT *)Context;
    190   UpdateStatement(Statement);
    191   gBS->SignalEvent (mValueChangedEvent);
    192 }
    193 
    194 /**
    195   Refresh the questions within this form.
    196 
    197   @param Event    The event which has this function related.
    198   @param Context  The input context info related to this event or the status code return to the caller.
    199 **/
    200 VOID
    201 EFIAPI
    202 RefreshEventNotifyForForm(
    203   IN      EFI_EVENT Event,
    204   IN      VOID      *Context
    205   )
    206 {
    207   gCurrentSelection->Action = UI_ACTION_REFRESH_FORMSET;
    208 
    209   gBS->SignalEvent (mValueChangedEvent);
    210 }
    211 
    212 /**
    213   Create refresh hook event for statement which has refresh event or interval.
    214 
    215   @param Statement           The statement need to check.
    216 
    217 **/
    218 VOID
    219 CreateRefreshEventForStatement (
    220   IN     FORM_BROWSER_STATEMENT        *Statement
    221   )
    222 {
    223   EFI_STATUS                      Status;
    224   EFI_EVENT                       RefreshEvent;
    225   FORM_BROWSER_REFRESH_EVENT_NODE *EventNode;
    226 
    227   //
    228   // If question has refresh guid, create the notify function.
    229   //
    230   Status = gBS->CreateEventEx (
    231                     EVT_NOTIFY_SIGNAL,
    232                     TPL_CALLBACK,
    233                     RefreshEventNotifyForStatement,
    234                     Statement,
    235                     &Statement->RefreshGuid,
    236                     &RefreshEvent);
    237   ASSERT_EFI_ERROR (Status);
    238 
    239   EventNode = AllocateZeroPool (sizeof (FORM_BROWSER_REFRESH_EVENT_NODE));
    240   ASSERT (EventNode != NULL);
    241   EventNode->RefreshEvent = RefreshEvent;
    242   InsertTailList(&mRefreshEventList, &EventNode->Link);
    243 }
    244 
    245 /**
    246   Create refresh hook event for form which has refresh event or interval.
    247 
    248   @param Form           The form need to check.
    249 
    250 **/
    251 VOID
    252 CreateRefreshEventForForm (
    253   IN     FORM_BROWSER_FORM        *Form
    254   )
    255 {
    256   EFI_STATUS                      Status;
    257   EFI_EVENT                       RefreshEvent;
    258   FORM_BROWSER_REFRESH_EVENT_NODE *EventNode;
    259 
    260   //
    261   // If question has refresh guid, create the notify function.
    262   //
    263   Status = gBS->CreateEventEx (
    264                     EVT_NOTIFY_SIGNAL,
    265                     TPL_CALLBACK,
    266                     RefreshEventNotifyForForm,
    267                     Form,
    268                     &Form->RefreshGuid,
    269                     &RefreshEvent);
    270   ASSERT_EFI_ERROR (Status);
    271 
    272   EventNode = AllocateZeroPool (sizeof (FORM_BROWSER_REFRESH_EVENT_NODE));
    273   ASSERT (EventNode != NULL);
    274   EventNode->RefreshEvent = RefreshEvent;
    275   InsertTailList(&mRefreshEventList, &EventNode->Link);
    276 }
    277 
    278 /**
    279 
    280   Initialize the Display statement structure data.
    281 
    282   @param DisplayStatement      Pointer to the display Statement data strucure.
    283   @param Statement             The statement need to check.
    284 **/
    285 VOID
    286 InitializeDisplayStatement (
    287   IN OUT FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement,
    288   IN     FORM_BROWSER_STATEMENT        *Statement
    289   )
    290 {
    291   LIST_ENTRY                 *Link;
    292   QUESTION_OPTION            *Option;
    293   DISPLAY_QUESTION_OPTION    *DisplayOption;
    294   FORM_DISPLAY_ENGINE_STATEMENT *ParentStatement;
    295 
    296   DisplayStatement->Signature = FORM_DISPLAY_ENGINE_STATEMENT_SIGNATURE;
    297   DisplayStatement->Version   = FORM_DISPLAY_ENGINE_STATEMENT_VERSION_1;
    298   DisplayStatement->OpCode    = Statement->OpCode;
    299   InitializeListHead (&DisplayStatement->NestStatementList);
    300   InitializeListHead (&DisplayStatement->OptionListHead);
    301 
    302   if ((EvaluateExpressionList(Statement->Expression, FALSE, NULL, NULL) == ExpressGrayOut) || Statement->Locked) {
    303     DisplayStatement->Attribute |= HII_DISPLAY_GRAYOUT;
    304   }
    305   if ((Statement->ValueExpression != NULL) || ((Statement->QuestionFlags & EFI_IFR_FLAG_READ_ONLY) != 0)) {
    306     DisplayStatement->Attribute |= HII_DISPLAY_READONLY;
    307   }
    308 
    309   //
    310   // Initilize the option list in statement.
    311   //
    312   Link = GetFirstNode (&Statement->OptionListHead);
    313   while (!IsNull (&Statement->OptionListHead, Link)) {
    314     Option = QUESTION_OPTION_FROM_LINK (Link);
    315     Link = GetNextNode (&Statement->OptionListHead, Link);
    316     if ((Option->SuppressExpression != NULL) &&
    317         ((EvaluateExpressionList(Option->SuppressExpression, FALSE, NULL, NULL) == ExpressSuppress))) {
    318       continue;
    319     }
    320 
    321     DisplayOption = AllocateZeroPool (sizeof (DISPLAY_QUESTION_OPTION));
    322     ASSERT (DisplayOption != NULL);
    323 
    324     DisplayOption->ImageId      = Option->ImageId;
    325     DisplayOption->Signature    = DISPLAY_QUESTION_OPTION_SIGNATURE;
    326     DisplayOption->OptionOpCode = Option->OpCode;
    327     InsertTailList(&DisplayStatement->OptionListHead, &DisplayOption->Link);
    328   }
    329 
    330   CopyMem (&DisplayStatement->CurrentValue, &Statement->HiiValue, sizeof (EFI_HII_VALUE));
    331 
    332   //
    333   // Some special op code need an extra buffer to save the data.
    334   // Such as string, password, orderedlist...
    335   //
    336   if (Statement->BufferValue != NULL) {
    337     //
    338     // Ordered list opcode may not initilized, get default value here.
    339     //
    340     if (Statement->OpCode->OpCode == EFI_IFR_ORDERED_LIST_OP && GetArrayData (Statement->BufferValue, Statement->ValueType, 0) == 0) {
    341       GetQuestionDefault (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, 0);
    342     }
    343 
    344     DisplayStatement->CurrentValue.Buffer    = AllocateCopyPool(Statement->StorageWidth,Statement->BufferValue);
    345     DisplayStatement->CurrentValue.BufferLen = Statement->StorageWidth;
    346   }
    347 
    348   DisplayStatement->SettingChangedFlag = Statement->ValueChanged;
    349 
    350   //
    351   // Get the highlight statement for current form.
    352   //
    353   if (((gCurrentSelection->QuestionId != 0) && (Statement->QuestionId == gCurrentSelection->QuestionId)) ||
    354       ((mCurFakeQestId != 0) && (Statement->FakeQuestionId == mCurFakeQestId))) {
    355     gDisplayFormData.HighLightedStatement = DisplayStatement;
    356   }
    357 
    358   //
    359   // Create the refresh event process function.
    360   //
    361   if (!IsZeroGuid (&Statement->RefreshGuid)) {
    362     CreateRefreshEventForStatement (Statement);
    363   }
    364 
    365   //
    366   // For RTC type of date/time, set default refresh interval to be 1 second.
    367   //
    368   if ((Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) && Statement->Storage == NULL) {
    369     Statement->RefreshInterval = 1;
    370   }
    371 
    372   //
    373   // Create the refresh guid hook event.
    374   // If the statement in this form has refresh event or refresh interval, browser will create this event for display engine.
    375   //
    376   if ((!IsZeroGuid (&Statement->RefreshGuid)) || (Statement->RefreshInterval != 0)) {
    377     gDisplayFormData.FormRefreshEvent = mValueChangedEvent;
    378   }
    379 
    380   //
    381   // Save the password check function for later use.
    382   //
    383   if (Statement->Operand == EFI_IFR_PASSWORD_OP) {
    384     DisplayStatement->PasswordCheck = PasswordCheck;
    385   }
    386 
    387   //
    388   // If this statement is nest in the subtitle, insert to the host statement.
    389   // else insert to the form it belongs to.
    390   //
    391   if (Statement->ParentStatement != NULL) {
    392     ParentStatement = GetDisplayStatement(Statement->ParentStatement->OpCode);
    393     ASSERT (ParentStatement != NULL);
    394     InsertTailList(&ParentStatement->NestStatementList, &DisplayStatement->DisplayLink);
    395   } else {
    396     InsertTailList(&gDisplayFormData.StatementListHead, &DisplayStatement->DisplayLink);
    397   }
    398 }
    399 
    400 /**
    401   Process for the refresh interval statement.
    402 
    403   @param Event    The Event need to be process
    404   @param Context  The context of the event.
    405 
    406 **/
    407 VOID
    408 EFIAPI
    409 RefreshIntervalProcess (
    410   IN  EFI_EVENT    Event,
    411   IN  VOID         *Context
    412   )
    413 {
    414   FORM_BROWSER_STATEMENT        *Statement;
    415   LIST_ENTRY                    *Link;
    416 
    417   Link = GetFirstNode (&gCurrentSelection->Form->StatementListHead);
    418   while (!IsNull (&gCurrentSelection->Form->StatementListHead, Link)) {
    419     Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
    420     Link = GetNextNode (&gCurrentSelection->Form->StatementListHead, Link);
    421 
    422     if (Statement->RefreshInterval == 0) {
    423       continue;
    424     }
    425 
    426     UpdateStatement(Statement);
    427   }
    428 
    429   gBS->SignalEvent (mValueChangedEvent);
    430 }
    431 
    432 /**
    433 
    434   Make a copy of the global hotkey info.
    435 
    436 **/
    437 VOID
    438 UpdateHotkeyList (
    439   VOID
    440   )
    441 {
    442   BROWSER_HOT_KEY  *HotKey;
    443   BROWSER_HOT_KEY  *CopyKey;
    444   LIST_ENTRY       *Link;
    445 
    446   Link = GetFirstNode (&gBrowserHotKeyList);
    447   while (!IsNull (&gBrowserHotKeyList, Link)) {
    448     HotKey = BROWSER_HOT_KEY_FROM_LINK (Link);
    449 
    450     CopyKey             = AllocateCopyPool(sizeof (BROWSER_HOT_KEY), HotKey);
    451     ASSERT (CopyKey != NULL);
    452     CopyKey->KeyData    = AllocateCopyPool(sizeof (EFI_INPUT_KEY), HotKey->KeyData);
    453     ASSERT (CopyKey->KeyData != NULL);
    454     CopyKey->HelpString = AllocateCopyPool(StrSize (HotKey->HelpString), HotKey->HelpString);
    455     ASSERT (CopyKey->HelpString != NULL);
    456 
    457     InsertTailList(&gDisplayFormData.HotKeyListHead, &CopyKey->Link);
    458 
    459     Link = GetNextNode (&gBrowserHotKeyList, Link);
    460   }
    461 }
    462 
    463 /**
    464 
    465   Get the extra question attribute from override question list.
    466 
    467   @param    QuestionId    The question id for this request question.
    468 
    469   @retval   The attribute for this question or NULL if not found this
    470             question in the list.
    471 
    472 **/
    473 UINT32
    474 ProcessQuestionExtraAttr (
    475   IN   EFI_QUESTION_ID  QuestionId
    476   )
    477 {
    478   LIST_ENTRY                   *Link;
    479   QUESTION_ATTRIBUTE_OVERRIDE  *QuestionDesc;
    480 
    481   //
    482   // Return HII_DISPLAY_NONE if input a invalid question id.
    483   //
    484   if (QuestionId == 0) {
    485     return HII_DISPLAY_NONE;
    486   }
    487 
    488   Link = GetFirstNode (&mPrivateData.FormBrowserEx2.OverrideQestListHead);
    489   while (!IsNull (&mPrivateData.FormBrowserEx2.OverrideQestListHead, Link)) {
    490     QuestionDesc = FORM_QUESTION_ATTRIBUTE_OVERRIDE_FROM_LINK (Link);
    491     Link = GetNextNode (&mPrivateData.FormBrowserEx2.OverrideQestListHead, Link);
    492 
    493     if ((QuestionDesc->QuestionId == QuestionId) &&
    494         (QuestionDesc->FormId     == gCurrentSelection->FormId) &&
    495         (QuestionDesc->HiiHandle  == gCurrentSelection->Handle) &&
    496         CompareGuid (&QuestionDesc->FormSetGuid, &gCurrentSelection->FormSetGuid)) {
    497       return QuestionDesc->Attribute;
    498     }
    499   }
    500 
    501   return HII_DISPLAY_NONE;
    502 }
    503 
    504 /**
    505 
    506   Enum all statement in current form, find all the statement can be display and
    507   add to the display form.
    508 
    509 **/
    510 VOID
    511 AddStatementToDisplayForm (
    512   VOID
    513   )
    514 {
    515   EFI_STATUS                    Status;
    516   LIST_ENTRY                    *Link;
    517   FORM_BROWSER_STATEMENT        *Statement;
    518   FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement;
    519   UINT8                         MinRefreshInterval;
    520   EFI_EVENT                     RefreshIntervalEvent;
    521   FORM_BROWSER_REFRESH_EVENT_NODE *EventNode;
    522   BOOLEAN                       FormEditable;
    523   UINT32                        ExtraAttribute;
    524 
    525   MinRefreshInterval   = 0;
    526   FormEditable         = FALSE;
    527 
    528   //
    529   // Process the statement outside the form, these statements are not recognized
    530   // by browser core.
    531   //
    532   Link = GetFirstNode (&gCurrentSelection->FormSet->StatementListOSF);
    533   while (!IsNull (&gCurrentSelection->FormSet->StatementListOSF, Link)) {
    534     Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
    535     Link = GetNextNode (&gCurrentSelection->FormSet->StatementListOSF, Link);
    536 
    537     DisplayStatement = AllocateZeroPool (sizeof (FORM_DISPLAY_ENGINE_STATEMENT));
    538     ASSERT (DisplayStatement != NULL);
    539     DisplayStatement->Signature = FORM_DISPLAY_ENGINE_STATEMENT_SIGNATURE;
    540     DisplayStatement->Version   = FORM_DISPLAY_ENGINE_STATEMENT_VERSION_1;
    541     DisplayStatement->OpCode = Statement->OpCode;
    542 
    543     InitializeListHead (&DisplayStatement->NestStatementList);
    544     InitializeListHead (&DisplayStatement->OptionListHead);
    545 
    546     InsertTailList(&gDisplayFormData.StatementListOSF, &DisplayStatement->DisplayLink);
    547   }
    548 
    549   //
    550   // treat formset as statement outside the form,get its opcode.
    551   //
    552   DisplayStatement = AllocateZeroPool (sizeof (FORM_DISPLAY_ENGINE_STATEMENT));
    553   ASSERT (DisplayStatement != NULL);
    554 
    555   DisplayStatement->Signature = FORM_DISPLAY_ENGINE_STATEMENT_SIGNATURE;
    556   DisplayStatement->Version   = FORM_DISPLAY_ENGINE_STATEMENT_VERSION_1;
    557   DisplayStatement->OpCode = gCurrentSelection->FormSet->OpCode;
    558 
    559   InitializeListHead (&DisplayStatement->NestStatementList);
    560   InitializeListHead (&DisplayStatement->OptionListHead);
    561 
    562   InsertTailList(&gDisplayFormData.StatementListOSF, &DisplayStatement->DisplayLink);
    563 
    564   //
    565   // Process the statement in this form.
    566   //
    567   Link = GetFirstNode (&gCurrentSelection->Form->StatementListHead);
    568   while (!IsNull (&gCurrentSelection->Form->StatementListHead, Link)) {
    569     Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
    570     Link = GetNextNode (&gCurrentSelection->Form->StatementListHead, Link);
    571 
    572     //
    573     // This statement can't be show, skip it.
    574     //
    575     if (EvaluateExpressionList(Statement->Expression, FALSE, NULL, NULL) > ExpressGrayOut) {
    576       continue;
    577     }
    578 
    579     //
    580     // Check the extra attribute.
    581     //
    582     ExtraAttribute = ProcessQuestionExtraAttr (Statement->QuestionId);
    583     if ((ExtraAttribute & HII_DISPLAY_SUPPRESS) != 0) {
    584       continue;
    585     }
    586 
    587     DisplayStatement = AllocateZeroPool (sizeof (FORM_DISPLAY_ENGINE_STATEMENT));
    588     ASSERT (DisplayStatement != NULL);
    589 
    590     //
    591     // Initialize this statement and add it to the display form.
    592     //
    593     InitializeDisplayStatement(DisplayStatement, Statement);
    594 
    595     //
    596     // Set the extra attribute.
    597     //
    598     DisplayStatement->Attribute |= ExtraAttribute;
    599 
    600     if (Statement->Storage != NULL) {
    601       FormEditable = TRUE;
    602     }
    603 
    604     //
    605     // Get the minimal refresh interval value for later use.
    606     //
    607     if ((Statement->RefreshInterval != 0) &&
    608       (MinRefreshInterval == 0 || Statement->RefreshInterval < MinRefreshInterval)) {
    609       MinRefreshInterval = Statement->RefreshInterval;
    610     }
    611   }
    612 
    613   //
    614   // Create the periodic timer for refresh interval statement.
    615   //
    616   if (MinRefreshInterval != 0) {
    617     Status = gBS->CreateEvent (EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK, RefreshIntervalProcess, NULL, &RefreshIntervalEvent);
    618     ASSERT_EFI_ERROR (Status);
    619     Status = gBS->SetTimer (RefreshIntervalEvent, TimerPeriodic, MinRefreshInterval * ONE_SECOND);
    620     ASSERT_EFI_ERROR (Status);
    621 
    622     EventNode = AllocateZeroPool (sizeof (FORM_BROWSER_REFRESH_EVENT_NODE));
    623     ASSERT (EventNode != NULL);
    624     EventNode->RefreshEvent = RefreshIntervalEvent;
    625     InsertTailList(&mRefreshEventList, &EventNode->Link);
    626   }
    627 
    628   //
    629   // Create the refresh event process function for Form.
    630   //
    631   if (!IsZeroGuid (&gCurrentSelection->Form->RefreshGuid)) {
    632     CreateRefreshEventForForm (gCurrentSelection->Form);
    633     if (gDisplayFormData.FormRefreshEvent == NULL) {
    634       gDisplayFormData.FormRefreshEvent = mValueChangedEvent;
    635     }
    636   }
    637 
    638   //
    639   // Update hotkey list field.
    640   //
    641   if (gBrowserSettingScope == SystemLevel || FormEditable) {
    642     UpdateHotkeyList();
    643   }
    644 }
    645 
    646 /**
    647 
    648   Initialize the SettingChangedFlag variable in the display form.
    649 
    650 **/
    651 VOID
    652 UpdateDataChangedFlag (
    653   VOID
    654   )
    655 {
    656   LIST_ENTRY           *Link;
    657   FORM_BROWSER_FORMSET *LocalFormSet;
    658 
    659   gDisplayFormData.SettingChangedFlag   = FALSE;
    660 
    661   if (IsNvUpdateRequiredForForm (gCurrentSelection->Form)) {
    662     gDisplayFormData.SettingChangedFlag = TRUE;
    663     return;
    664   }
    665 
    666   //
    667   // Base on the system level to check whether need to show the NV flag.
    668   //
    669   switch (gBrowserSettingScope) {
    670   case SystemLevel:
    671     //
    672     // Check the maintain list to see whether there is any change.
    673     //
    674     Link = GetFirstNode (&gBrowserFormSetList);
    675     while (!IsNull (&gBrowserFormSetList, Link)) {
    676       LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
    677       if (IsNvUpdateRequiredForFormSet(LocalFormSet)) {
    678         gDisplayFormData.SettingChangedFlag = TRUE;
    679         return;
    680       }
    681       Link = GetNextNode (&gBrowserFormSetList, Link);
    682     }
    683     break;
    684 
    685   case FormSetLevel:
    686     if (IsNvUpdateRequiredForFormSet(gCurrentSelection->FormSet)) {
    687       gDisplayFormData.SettingChangedFlag = TRUE;
    688       return;
    689     }
    690     break;
    691 
    692   default:
    693     break;
    694   }
    695 }
    696 
    697 /**
    698 
    699   Initialize the Display form structure data.
    700 
    701 **/
    702 VOID
    703 InitializeDisplayFormData (
    704   VOID
    705   )
    706 {
    707   EFI_STATUS  Status;
    708 
    709   gDisplayFormData.Signature   = FORM_DISPLAY_ENGINE_FORM_SIGNATURE;
    710   gDisplayFormData.Version     = FORM_DISPLAY_ENGINE_VERSION_1;
    711   gDisplayFormData.ImageId     = 0;
    712   gDisplayFormData.AnimationId = 0;
    713 
    714   InitializeListHead (&gDisplayFormData.StatementListHead);
    715   InitializeListHead (&gDisplayFormData.StatementListOSF);
    716   InitializeListHead (&gDisplayFormData.HotKeyListHead);
    717 
    718   Status = gBS->CreateEvent (
    719         EVT_NOTIFY_WAIT,
    720         TPL_CALLBACK,
    721         SetupBrowserEmptyFunction,
    722         NULL,
    723         &mValueChangedEvent
    724         );
    725   ASSERT_EFI_ERROR (Status);
    726 }
    727 
    728 /**
    729 
    730   Free the kotkey info saved in form data.
    731 
    732 **/
    733 VOID
    734 FreeHotkeyList (
    735   VOID
    736   )
    737 {
    738   BROWSER_HOT_KEY  *HotKey;
    739   LIST_ENTRY       *Link;
    740 
    741   while (!IsListEmpty (&gDisplayFormData.HotKeyListHead)) {
    742     Link = GetFirstNode (&gDisplayFormData.HotKeyListHead);
    743     HotKey = BROWSER_HOT_KEY_FROM_LINK (Link);
    744 
    745     RemoveEntryList (&HotKey->Link);
    746 
    747     FreePool (HotKey->KeyData);
    748     FreePool (HotKey->HelpString);
    749     FreePool (HotKey);
    750   }
    751 }
    752 
    753 /**
    754 
    755   Update the Display form structure data.
    756 
    757 **/
    758 VOID
    759 UpdateDisplayFormData (
    760   VOID
    761   )
    762 {
    763   gDisplayFormData.FormTitle        = gCurrentSelection->Form->FormTitle;
    764   gDisplayFormData.FormId           = gCurrentSelection->FormId;
    765   gDisplayFormData.HiiHandle        = gCurrentSelection->Handle;
    766   CopyGuid (&gDisplayFormData.FormSetGuid, &gCurrentSelection->FormSetGuid);
    767 
    768   gDisplayFormData.Attribute        = 0;
    769   gDisplayFormData.Attribute       |= gCurrentSelection->Form->ModalForm ? HII_DISPLAY_MODAL : 0;
    770   gDisplayFormData.Attribute       |= gCurrentSelection->Form->Locked    ? HII_DISPLAY_LOCK  : 0;
    771 
    772   gDisplayFormData.FormRefreshEvent     = NULL;
    773   gDisplayFormData.HighLightedStatement = NULL;
    774 
    775   UpdateDataChangedFlag ();
    776 
    777   AddStatementToDisplayForm ();
    778 }
    779 
    780 /**
    781 
    782   Free the Display Statement structure data.
    783 
    784   @param   StatementList         Point to the statement list which need to be free.
    785 
    786 **/
    787 VOID
    788 FreeStatementData (
    789   LIST_ENTRY           *StatementList
    790   )
    791 {
    792   LIST_ENTRY                    *Link;
    793   LIST_ENTRY                    *OptionLink;
    794   FORM_DISPLAY_ENGINE_STATEMENT *Statement;
    795   DISPLAY_QUESTION_OPTION       *Option;
    796 
    797   //
    798   // Free Statements/Questions
    799   //
    800   while (!IsListEmpty (StatementList)) {
    801     Link = GetFirstNode (StatementList);
    802     Statement = FORM_DISPLAY_ENGINE_STATEMENT_FROM_LINK (Link);
    803 
    804     //
    805     // Free Options List
    806     //
    807     while (!IsListEmpty (&Statement->OptionListHead)) {
    808       OptionLink = GetFirstNode (&Statement->OptionListHead);
    809       Option = DISPLAY_QUESTION_OPTION_FROM_LINK (OptionLink);
    810       RemoveEntryList (&Option->Link);
    811       FreePool (Option);
    812     }
    813 
    814     //
    815     // Free nest statement List
    816     //
    817     if (!IsListEmpty (&Statement->NestStatementList)) {
    818       FreeStatementData(&Statement->NestStatementList);
    819     }
    820 
    821     RemoveEntryList (&Statement->DisplayLink);
    822     FreePool (Statement);
    823   }
    824 }
    825 
    826 /**
    827 
    828   Free the Display form structure data.
    829 
    830 **/
    831 VOID
    832 FreeDisplayFormData (
    833   VOID
    834   )
    835 {
    836   FreeStatementData (&gDisplayFormData.StatementListHead);
    837   FreeStatementData (&gDisplayFormData.StatementListOSF);
    838 
    839   FreeRefreshEvent();
    840 
    841   FreeHotkeyList();
    842 }
    843 
    844 /**
    845 
    846   Get FORM_BROWSER_STATEMENT from FORM_DISPLAY_ENGINE_STATEMENT based on the OpCode info.
    847 
    848   @param DisplayStatement        The input FORM_DISPLAY_ENGINE_STATEMENT.
    849 
    850   @retval FORM_BROWSER_STATEMENT  The return FORM_BROWSER_STATEMENT info.
    851 
    852 **/
    853 FORM_BROWSER_STATEMENT *
    854 GetBrowserStatement (
    855   IN FORM_DISPLAY_ENGINE_STATEMENT *DisplayStatement
    856   )
    857 {
    858   FORM_BROWSER_STATEMENT *Statement;
    859   LIST_ENTRY             *Link;
    860 
    861   Link = GetFirstNode (&gCurrentSelection->Form->StatementListHead);
    862   while (!IsNull (&gCurrentSelection->Form->StatementListHead, Link)) {
    863     Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
    864 
    865     if (Statement->OpCode == DisplayStatement->OpCode) {
    866       return Statement;
    867     }
    868 
    869     Link = GetNextNode (&gCurrentSelection->Form->StatementListHead, Link);
    870   }
    871 
    872   return NULL;
    873 }
    874 
    875 /**
    876   Update the ValueChanged status for questions in this form.
    877 
    878   @param  FormSet                FormSet data structure.
    879   @param  Form                   Form data structure.
    880 
    881 **/
    882 VOID
    883 UpdateStatementStatusForForm (
    884   IN FORM_BROWSER_FORMSET             *FormSet,
    885   IN FORM_BROWSER_FORM                *Form
    886   )
    887 {
    888   LIST_ENTRY                  *Link;
    889   FORM_BROWSER_STATEMENT      *Question;
    890 
    891   Link = GetFirstNode (&Form->StatementListHead);
    892   while (!IsNull (&Form->StatementListHead, Link)) {
    893     Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
    894     Link = GetNextNode (&Form->StatementListHead, Link);
    895 
    896     //
    897     // For password opcode, not set the the value changed flag.
    898     //
    899     if (Question->Operand == EFI_IFR_PASSWORD_OP) {
    900       continue;
    901     }
    902 
    903     IsQuestionValueChanged(FormSet, Form, Question, GetSetValueWithBuffer);
    904   }
    905 }
    906 
    907 /**
    908   Update the ValueChanged status for questions in this formset.
    909 
    910   @param  FormSet                FormSet data structure.
    911 
    912 **/
    913 VOID
    914 UpdateStatementStatusForFormSet (
    915   IN FORM_BROWSER_FORMSET                *FormSet
    916   )
    917 {
    918   LIST_ENTRY                  *Link;
    919   FORM_BROWSER_FORM           *Form;
    920 
    921   Link = GetFirstNode (&FormSet->FormListHead);
    922   while (!IsNull (&FormSet->FormListHead, Link)) {
    923     Form = FORM_BROWSER_FORM_FROM_LINK (Link);
    924     Link = GetNextNode (&FormSet->FormListHead, Link);
    925 
    926     UpdateStatementStatusForForm (FormSet, Form);
    927   }
    928 }
    929 
    930 /**
    931   Update the ValueChanged status for questions.
    932 
    933   @param  FormSet                FormSet data structure.
    934   @param  Form                   Form data structure.
    935   @param  SettingScope           Setting Scope for Default action.
    936 
    937 **/
    938 VOID
    939 UpdateStatementStatus (
    940   IN FORM_BROWSER_FORMSET             *FormSet,
    941   IN FORM_BROWSER_FORM                *Form,
    942   IN BROWSER_SETTING_SCOPE            SettingScope
    943   )
    944 {
    945   LIST_ENTRY                  *Link;
    946   FORM_BROWSER_FORMSET        *LocalFormSet;
    947 
    948   switch (SettingScope) {
    949   case SystemLevel:
    950     Link = GetFirstNode (&gBrowserFormSetList);
    951     while (!IsNull (&gBrowserFormSetList, Link)) {
    952       LocalFormSet = FORM_BROWSER_FORMSET_FROM_LINK (Link);
    953       Link = GetNextNode (&gBrowserFormSetList, Link);
    954       if (!ValidateFormSet(LocalFormSet)) {
    955         continue;
    956       }
    957 
    958       UpdateStatementStatusForFormSet (LocalFormSet);
    959     }
    960     break;
    961 
    962   case FormSetLevel:
    963     UpdateStatementStatusForFormSet (FormSet);
    964     break;
    965 
    966   case FormLevel:
    967     UpdateStatementStatusForForm (FormSet, Form);
    968     break;
    969 
    970   default:
    971     break;
    972   }
    973 }
    974 
    975 /**
    976 
    977   Process the action request in user input.
    978 
    979   @param Action                  The user input action request info.
    980   @param DefaultId               The user input default Id info.
    981 
    982   @retval EFI_SUCESSS            This function always return successfully for now.
    983 
    984 **/
    985 EFI_STATUS
    986 ProcessAction (
    987   IN UINT32        Action,
    988   IN UINT16        DefaultId
    989   )
    990 {
    991   //
    992   // This is caused by use press ESC, and it should not combine with other action type.
    993   //
    994   if ((Action & BROWSER_ACTION_FORM_EXIT) == BROWSER_ACTION_FORM_EXIT) {
    995     FindNextMenu (gCurrentSelection, FormLevel);
    996     return EFI_SUCCESS;
    997   }
    998 
    999   //
   1000   // Below is normal hotkey trigged action, these action maybe combine with each other.
   1001   //
   1002   if ((Action & BROWSER_ACTION_DISCARD) == BROWSER_ACTION_DISCARD) {
   1003     DiscardForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope);
   1004   }
   1005 
   1006   if ((Action & BROWSER_ACTION_DEFAULT) == BROWSER_ACTION_DEFAULT) {
   1007     ExtractDefault (gCurrentSelection->FormSet, gCurrentSelection->Form, DefaultId, gBrowserSettingScope, GetDefaultForAll, NULL, FALSE, FALSE);
   1008     UpdateStatementStatus (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope);
   1009   }
   1010 
   1011   if ((Action & BROWSER_ACTION_SUBMIT) == BROWSER_ACTION_SUBMIT) {
   1012     SubmitForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope);
   1013   }
   1014 
   1015   if ((Action & BROWSER_ACTION_RESET) == BROWSER_ACTION_RESET) {
   1016     gResetRequired = TRUE;
   1017   }
   1018 
   1019   if ((Action & BROWSER_ACTION_EXIT) == BROWSER_ACTION_EXIT) {
   1020     //
   1021     // Form Exit without saving, Similar to ESC Key.
   1022     // FormSet Exit without saving, Exit SendForm.
   1023     // System Exit without saving, CallExitHandler and Exit SendForm.
   1024     //
   1025     DiscardForm (gCurrentSelection->FormSet, gCurrentSelection->Form, gBrowserSettingScope);
   1026     if (gBrowserSettingScope == FormLevel || gBrowserSettingScope == FormSetLevel) {
   1027       FindNextMenu (gCurrentSelection, gBrowserSettingScope);
   1028     } else if (gBrowserSettingScope == SystemLevel) {
   1029       if (ExitHandlerFunction != NULL) {
   1030         ExitHandlerFunction ();
   1031       }
   1032       gCurrentSelection->Action = UI_ACTION_EXIT;
   1033     }
   1034   }
   1035 
   1036   return EFI_SUCCESS;
   1037 }
   1038 
   1039 /**
   1040   Check whether the formset guid is in this Hii package list.
   1041 
   1042   @param  HiiHandle              The HiiHandle for this HII package list.
   1043   @param  FormSetGuid            The formset guid for the request formset.
   1044 
   1045   @retval TRUE                   Find the formset guid.
   1046   @retval FALSE                  Not found the formset guid.
   1047 
   1048 **/
   1049 BOOLEAN
   1050 GetFormsetGuidFromHiiHandle (
   1051   IN EFI_HII_HANDLE       HiiHandle,
   1052   IN EFI_GUID             *FormSetGuid
   1053   )
   1054 {
   1055   EFI_HII_PACKAGE_LIST_HEADER  *HiiPackageList;
   1056   UINTN                        BufferSize;
   1057   UINT32                       Offset;
   1058   UINT32                       Offset2;
   1059   UINT32                       PackageListLength;
   1060   EFI_HII_PACKAGE_HEADER       PackageHeader;
   1061   UINT8                        *Package;
   1062   UINT8                        *OpCodeData;
   1063   EFI_STATUS                   Status;
   1064   BOOLEAN                      FindGuid;
   1065 
   1066   BufferSize     = 0;
   1067   HiiPackageList = NULL;
   1068   FindGuid       = FALSE;
   1069 
   1070   Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, HiiHandle, &BufferSize, HiiPackageList);
   1071   if (Status == EFI_BUFFER_TOO_SMALL) {
   1072     HiiPackageList = AllocatePool (BufferSize);
   1073     ASSERT (HiiPackageList != NULL);
   1074 
   1075     Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, HiiHandle, &BufferSize, HiiPackageList);
   1076   }
   1077   if (EFI_ERROR (Status) || HiiPackageList == NULL) {
   1078     return FALSE;
   1079   }
   1080 
   1081   //
   1082   // Get Form package from this HII package List
   1083   //
   1084   Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
   1085   Offset2 = 0;
   1086   CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32));
   1087 
   1088   while (Offset < PackageListLength) {
   1089     Package = ((UINT8 *) HiiPackageList) + Offset;
   1090     CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
   1091     Offset += PackageHeader.Length;
   1092 
   1093     if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) {
   1094       //
   1095       // Search FormSet in this Form Package
   1096       //
   1097       Offset2 = sizeof (EFI_HII_PACKAGE_HEADER);
   1098       while (Offset2 < PackageHeader.Length) {
   1099         OpCodeData = Package + Offset2;
   1100 
   1101         if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) {
   1102           if (CompareGuid (FormSetGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))){
   1103             FindGuid = TRUE;
   1104             break;
   1105           }
   1106         }
   1107 
   1108         Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;
   1109       }
   1110     }
   1111     if (FindGuid) {
   1112       break;
   1113     }
   1114   }
   1115 
   1116   FreePool (HiiPackageList);
   1117 
   1118   return FindGuid;
   1119 }
   1120 
   1121 /**
   1122   Find HII Handle in the HII database associated with given Device Path.
   1123 
   1124   If DevicePath is NULL, then ASSERT.
   1125 
   1126   @param  DevicePath             Device Path associated with the HII package list
   1127                                  handle.
   1128   @param  FormsetGuid            The formset guid for this formset.
   1129 
   1130   @retval Handle                 HII package list Handle associated with the Device
   1131                                         Path.
   1132   @retval NULL                   Hii Package list handle is not found.
   1133 
   1134 **/
   1135 EFI_HII_HANDLE
   1136 DevicePathToHiiHandle (
   1137   IN EFI_DEVICE_PATH_PROTOCOL   *DevicePath,
   1138   IN EFI_GUID                   *FormsetGuid
   1139   )
   1140 {
   1141   EFI_STATUS                  Status;
   1142   EFI_DEVICE_PATH_PROTOCOL    *TmpDevicePath;
   1143   UINTN                       Index;
   1144   EFI_HANDLE                  Handle;
   1145   EFI_HANDLE                  DriverHandle;
   1146   EFI_HII_HANDLE              *HiiHandles;
   1147   EFI_HII_HANDLE              HiiHandle;
   1148 
   1149   ASSERT (DevicePath != NULL);
   1150 
   1151   TmpDevicePath = DevicePath;
   1152   //
   1153   // Locate Device Path Protocol handle buffer
   1154   //
   1155   Status = gBS->LocateDevicePath (
   1156                   &gEfiDevicePathProtocolGuid,
   1157                   &TmpDevicePath,
   1158                   &DriverHandle
   1159                   );
   1160   if (EFI_ERROR (Status) || !IsDevicePathEnd (TmpDevicePath)) {
   1161     return NULL;
   1162   }
   1163 
   1164   //
   1165   // Retrieve all HII Handles from HII database
   1166   //
   1167   HiiHandles = HiiGetHiiHandles (NULL);
   1168   if (HiiHandles == NULL) {
   1169     return NULL;
   1170   }
   1171 
   1172   //
   1173   // Search Hii Handle by Driver Handle
   1174   //
   1175   HiiHandle = NULL;
   1176   for (Index = 0; HiiHandles[Index] != NULL; Index++) {
   1177     Status = mHiiDatabase->GetPackageListHandle (
   1178                              mHiiDatabase,
   1179                              HiiHandles[Index],
   1180                              &Handle
   1181                              );
   1182     if (!EFI_ERROR (Status) && (Handle == DriverHandle)) {
   1183       if (GetFormsetGuidFromHiiHandle(HiiHandles[Index], FormsetGuid)) {
   1184         HiiHandle = HiiHandles[Index];
   1185         break;
   1186       }
   1187 
   1188       if (HiiHandle != NULL) {
   1189         break;
   1190       }
   1191     }
   1192   }
   1193 
   1194   FreePool (HiiHandles);
   1195   return HiiHandle;
   1196 }
   1197 
   1198 /**
   1199   Find HII Handle in the HII database associated with given form set guid.
   1200 
   1201   If FormSetGuid is NULL, then ASSERT.
   1202 
   1203   @param  ComparingGuid          FormSet Guid associated with the HII package list
   1204                                  handle.
   1205 
   1206   @retval Handle                 HII package list Handle associated with the Device
   1207                                         Path.
   1208   @retval NULL                   Hii Package list handle is not found.
   1209 
   1210 **/
   1211 EFI_HII_HANDLE
   1212 FormSetGuidToHiiHandle (
   1213   EFI_GUID     *ComparingGuid
   1214   )
   1215 {
   1216   EFI_HII_HANDLE               *HiiHandles;
   1217   EFI_HII_HANDLE               HiiHandle;
   1218   UINTN                        Index;
   1219 
   1220   ASSERT (ComparingGuid != NULL);
   1221 
   1222   HiiHandle  = NULL;
   1223   //
   1224   // Get all the Hii handles
   1225   //
   1226   HiiHandles = HiiGetHiiHandles (NULL);
   1227   ASSERT (HiiHandles != NULL);
   1228 
   1229   //
   1230   // Search for formset of each class type
   1231   //
   1232   for (Index = 0; HiiHandles[Index] != NULL; Index++) {
   1233     if (GetFormsetGuidFromHiiHandle(HiiHandles[Index], ComparingGuid)) {
   1234       HiiHandle = HiiHandles[Index];
   1235       break;
   1236     }
   1237 
   1238     if (HiiHandle != NULL) {
   1239       break;
   1240     }
   1241   }
   1242 
   1243   FreePool (HiiHandles);
   1244 
   1245   return HiiHandle;
   1246 }
   1247 
   1248 /**
   1249   check how to process the changed data in current form or form set.
   1250 
   1251   @param Selection       On input, Selection tell setup browser the information
   1252                          about the Selection, form and formset to be displayed.
   1253                          On output, Selection return the screen item that is selected
   1254                          by user.
   1255 
   1256   @param Scope           Data save or discard scope, form or formset.
   1257 
   1258   @retval                TRUE   Success process the changed data, will return to the parent form.
   1259   @retval                FALSE  Reject to process the changed data, will stay at  current form.
   1260 **/
   1261 BOOLEAN
   1262 ProcessChangedData (
   1263   IN OUT UI_MENU_SELECTION       *Selection,
   1264   IN     BROWSER_SETTING_SCOPE   Scope
   1265   )
   1266 {
   1267   BOOLEAN    RetValue;
   1268   EFI_STATUS Status;
   1269 
   1270   RetValue = TRUE;
   1271   switch (mFormDisplay->ConfirmDataChange()) {
   1272     case BROWSER_ACTION_DISCARD:
   1273       DiscardForm (Selection->FormSet, Selection->Form, Scope);
   1274       break;
   1275 
   1276     case BROWSER_ACTION_SUBMIT:
   1277       Status = SubmitForm (Selection->FormSet, Selection->Form, Scope);
   1278       if (EFI_ERROR (Status)) {
   1279         RetValue = FALSE;
   1280       }
   1281       break;
   1282 
   1283     case BROWSER_ACTION_NONE:
   1284       RetValue = FALSE;
   1285       break;
   1286 
   1287     default:
   1288       //
   1289       // if Invalid value return, process same as BROWSER_ACTION_NONE.
   1290       //
   1291       RetValue = FALSE;
   1292       break;
   1293   }
   1294 
   1295   return RetValue;
   1296 }
   1297 
   1298 /**
   1299   Find parent formset menu(the first menu which has different formset) for current menu.
   1300   If not find, just return to the first menu.
   1301 
   1302   @param Selection    The selection info.
   1303 
   1304 **/
   1305 VOID
   1306 FindParentFormSet (
   1307   IN OUT   UI_MENU_SELECTION           *Selection
   1308   )
   1309 {
   1310   FORM_ENTRY_INFO            *CurrentMenu;
   1311   FORM_ENTRY_INFO            *ParentMenu;
   1312 
   1313   CurrentMenu = Selection->CurrentMenu;
   1314   ParentMenu  = UiFindParentMenu(CurrentMenu, FormSetLevel);
   1315 
   1316   if (ParentMenu != NULL) {
   1317     CopyMem (&Selection->FormSetGuid, &ParentMenu->FormSetGuid, sizeof (EFI_GUID));
   1318     Selection->Handle = ParentMenu->HiiHandle;
   1319     Selection->FormId     = ParentMenu->FormId;
   1320     Selection->QuestionId = ParentMenu->QuestionId;
   1321   } else {
   1322     Selection->FormId     = CurrentMenu->FormId;
   1323     Selection->QuestionId = CurrentMenu->QuestionId;
   1324   }
   1325 
   1326   Selection->Statement  = NULL;
   1327 }
   1328 
   1329 /**
   1330   Process the goto op code, update the info in the selection structure.
   1331 
   1332   @param Statement    The statement belong to goto op code.
   1333   @param Selection    The selection info.
   1334 
   1335   @retval EFI_SUCCESS    The menu process successfully.
   1336   @return Other value if the process failed.
   1337 **/
   1338 EFI_STATUS
   1339 ProcessGotoOpCode (
   1340   IN OUT   FORM_BROWSER_STATEMENT      *Statement,
   1341   IN OUT   UI_MENU_SELECTION           *Selection
   1342   )
   1343 {
   1344   CHAR16                          *StringPtr;
   1345   EFI_DEVICE_PATH_PROTOCOL        *DevicePath;
   1346   FORM_BROWSER_FORM               *RefForm;
   1347   EFI_STATUS                      Status;
   1348   EFI_HII_HANDLE                  HiiHandle;
   1349 
   1350   Status    = EFI_SUCCESS;
   1351   StringPtr = NULL;
   1352   HiiHandle = NULL;
   1353 
   1354   //
   1355   // Prepare the device path check, get the device path info first.
   1356   //
   1357   if (Statement->HiiValue.Value.ref.DevicePath != 0) {
   1358     StringPtr = GetToken (Statement->HiiValue.Value.ref.DevicePath, Selection->FormSet->HiiHandle);
   1359   }
   1360 
   1361   //
   1362   // Check whether the device path string is a valid string.
   1363   //
   1364   if (Statement->HiiValue.Value.ref.DevicePath != 0 && StringPtr != NULL && StringPtr[0] != L'\0') {
   1365     if (Selection->Form->ModalForm) {
   1366       return Status;
   1367     }
   1368 
   1369     //
   1370     // Goto another Hii Package list
   1371     //
   1372     if (mPathFromText != NULL) {
   1373       DevicePath = mPathFromText->ConvertTextToDevicePath(StringPtr);
   1374       if (DevicePath != NULL) {
   1375         HiiHandle = DevicePathToHiiHandle (DevicePath, &Statement->HiiValue.Value.ref.FormSetGuid);
   1376         FreePool (DevicePath);
   1377       }
   1378       FreePool (StringPtr);
   1379     } else {
   1380       //
   1381       // Not found the EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL protocol.
   1382       //
   1383       PopupErrorMessage(BROWSER_PROTOCOL_NOT_FOUND, NULL, NULL, NULL);
   1384       FreePool (StringPtr);
   1385       return Status;
   1386     }
   1387 
   1388     if (HiiHandle != Selection->Handle) {
   1389       //
   1390       // Goto another Formset, check for uncommitted data
   1391       //
   1392       if ((gBrowserSettingScope == FormLevel || gBrowserSettingScope == FormSetLevel) &&
   1393           IsNvUpdateRequiredForFormSet(Selection->FormSet)) {
   1394         if (!ProcessChangedData(Selection, FormSetLevel)) {
   1395           return EFI_SUCCESS;
   1396         }
   1397       }
   1398     }
   1399 
   1400     Selection->Action = UI_ACTION_REFRESH_FORMSET;
   1401     Selection->Handle = HiiHandle;
   1402     if (Selection->Handle == NULL) {
   1403       //
   1404       // If target Hii Handle not found, exit current formset.
   1405       //
   1406       FindParentFormSet(Selection);
   1407       return EFI_SUCCESS;
   1408     }
   1409 
   1410     CopyMem (&Selection->FormSetGuid,&Statement->HiiValue.Value.ref.FormSetGuid, sizeof (EFI_GUID));
   1411     Selection->FormId = Statement->HiiValue.Value.ref.FormId;
   1412     Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;
   1413   } else if (!IsZeroGuid (&Statement->HiiValue.Value.ref.FormSetGuid)) {
   1414     if (Selection->Form->ModalForm) {
   1415       return Status;
   1416     }
   1417     if (!CompareGuid (&Statement->HiiValue.Value.ref.FormSetGuid, &Selection->FormSetGuid)) {
   1418       //
   1419       // Goto another Formset, check for uncommitted data
   1420       //
   1421       if ((gBrowserSettingScope == FormLevel || gBrowserSettingScope == FormSetLevel) &&
   1422          IsNvUpdateRequiredForFormSet(Selection->FormSet)) {
   1423         if (!ProcessChangedData(Selection, FormSetLevel)) {
   1424           return EFI_SUCCESS;
   1425         }
   1426       }
   1427     }
   1428 
   1429     Selection->Action = UI_ACTION_REFRESH_FORMSET;
   1430     Selection->Handle = FormSetGuidToHiiHandle(&Statement->HiiValue.Value.ref.FormSetGuid);
   1431     if (Selection->Handle == NULL) {
   1432       //
   1433       // If target Hii Handle not found, exit current formset.
   1434       //
   1435       FindParentFormSet(Selection);
   1436       return EFI_SUCCESS;
   1437     }
   1438 
   1439     CopyMem (&Selection->FormSetGuid, &Statement->HiiValue.Value.ref.FormSetGuid, sizeof (EFI_GUID));
   1440     Selection->FormId = Statement->HiiValue.Value.ref.FormId;
   1441     Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;
   1442   } else if (Statement->HiiValue.Value.ref.FormId != 0) {
   1443     //
   1444     // Goto another Form, check for uncommitted data
   1445     //
   1446     if (Statement->HiiValue.Value.ref.FormId != Selection->FormId) {
   1447       if ((gBrowserSettingScope == FormLevel && IsNvUpdateRequiredForForm(Selection->Form))) {
   1448         if (!ProcessChangedData (Selection, FormLevel)) {
   1449           return EFI_SUCCESS;
   1450         }
   1451       }
   1452     }
   1453 
   1454     RefForm = IdToForm (Selection->FormSet, Statement->HiiValue.Value.ref.FormId);
   1455     if ((RefForm != NULL) && (RefForm->SuppressExpression != NULL)) {
   1456       if (EvaluateExpressionList(RefForm->SuppressExpression, TRUE, Selection->FormSet, RefForm) != ExpressFalse) {
   1457         //
   1458         // Form is suppressed.
   1459         //
   1460         PopupErrorMessage(BROWSER_FORM_SUPPRESS, NULL, NULL, NULL);
   1461         return EFI_SUCCESS;
   1462       }
   1463     }
   1464 
   1465     Selection->FormId = Statement->HiiValue.Value.ref.FormId;
   1466     Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;
   1467   } else if (Statement->HiiValue.Value.ref.QuestionId != 0) {
   1468     Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;
   1469   }
   1470 
   1471   return Status;
   1472 }
   1473 
   1474 
   1475 /**
   1476   Process Question Config.
   1477 
   1478   @param  Selection              The UI menu selection.
   1479   @param  Question               The Question to be peocessed.
   1480 
   1481   @retval EFI_SUCCESS            Question Config process success.
   1482   @retval Other                  Question Config process fail.
   1483 
   1484 **/
   1485 EFI_STATUS
   1486 ProcessQuestionConfig (
   1487   IN  UI_MENU_SELECTION       *Selection,
   1488   IN  FORM_BROWSER_STATEMENT  *Question
   1489   )
   1490 {
   1491   EFI_STATUS                      Status;
   1492   CHAR16                          *ConfigResp;
   1493   CHAR16                          *Progress;
   1494 
   1495   if (Question->QuestionConfig == 0) {
   1496     return EFI_SUCCESS;
   1497   }
   1498 
   1499   //
   1500   // Get <ConfigResp>
   1501   //
   1502   ConfigResp = GetToken (Question->QuestionConfig, Selection->FormSet->HiiHandle);
   1503   if (ConfigResp == NULL) {
   1504     return EFI_NOT_FOUND;
   1505   } else if (ConfigResp[0] == L'\0') {
   1506     return EFI_SUCCESS;
   1507   }
   1508 
   1509   //
   1510   // Send config to Configuration Driver
   1511   //
   1512   Status = mHiiConfigRouting->RouteConfig (
   1513                            mHiiConfigRouting,
   1514                            ConfigResp,
   1515                            &Progress
   1516                            );
   1517 
   1518   return Status;
   1519 }
   1520 
   1521 /**
   1522 
   1523   Process the user input data.
   1524 
   1525   @param UserInput               The user input data.
   1526 
   1527   @retval EFI_SUCESSS            This function always return successfully for now.
   1528 
   1529 **/
   1530 EFI_STATUS
   1531 ProcessUserInput (
   1532   IN USER_INPUT               *UserInput
   1533   )
   1534 {
   1535   EFI_STATUS                    Status;
   1536   FORM_BROWSER_STATEMENT        *Statement;
   1537 
   1538   Status    = EFI_SUCCESS;
   1539   Statement = NULL;
   1540 
   1541   //
   1542   // When Exit from FormDisplay function, one of the below two cases must be true.
   1543   //
   1544   ASSERT (UserInput->Action != 0 || UserInput->SelectedStatement != NULL);
   1545 
   1546   //
   1547   // Remove the last highligh question id, this id will update when show next form.
   1548   //
   1549   gCurrentSelection->QuestionId = 0;
   1550   if (UserInput->SelectedStatement != NULL){
   1551     Statement = GetBrowserStatement(UserInput->SelectedStatement);
   1552     ASSERT (Statement != NULL);
   1553 
   1554     //
   1555     // This question is the current user select one,record it and later
   1556     // show it as the highlight question.
   1557     //
   1558     gCurrentSelection->CurrentMenu->QuestionId = Statement->QuestionId;
   1559     //
   1560     // For statement like text, actio, it not has question id.
   1561     // So use FakeQuestionId to save the question.
   1562     //
   1563     if (gCurrentSelection->CurrentMenu->QuestionId == 0) {
   1564       mCurFakeQestId = Statement->FakeQuestionId;
   1565     } else {
   1566       mCurFakeQestId = 0;
   1567     }
   1568   }
   1569 
   1570   //
   1571   // First process the Action field in USER_INPUT.
   1572   //
   1573   if (UserInput->Action != 0) {
   1574     Status = ProcessAction (UserInput->Action, UserInput->DefaultId);
   1575     gCurrentSelection->Statement = NULL;
   1576   } else {
   1577     ASSERT (Statement != NULL);
   1578     gCurrentSelection->Statement = Statement;
   1579     switch (Statement->Operand) {
   1580     case EFI_IFR_REF_OP:
   1581       Status = ProcessGotoOpCode(Statement, gCurrentSelection);
   1582       break;
   1583 
   1584     case EFI_IFR_ACTION_OP:
   1585       //
   1586       // Process the Config string <ConfigResp>
   1587       //
   1588       Status = ProcessQuestionConfig (gCurrentSelection, Statement);
   1589       break;
   1590 
   1591     case EFI_IFR_RESET_BUTTON_OP:
   1592       //
   1593       // Reset Question to default value specified by DefaultId
   1594       //
   1595       Status = ExtractDefault (gCurrentSelection->FormSet, NULL, Statement->DefaultId, FormSetLevel, GetDefaultForAll, NULL, FALSE, FALSE);
   1596       UpdateStatementStatus (gCurrentSelection->FormSet, NULL, FormSetLevel);
   1597       break;
   1598 
   1599     default:
   1600       switch (Statement->Operand) {
   1601       case EFI_IFR_STRING_OP:
   1602         DeleteString(Statement->HiiValue.Value.string, gCurrentSelection->FormSet->HiiHandle);
   1603         Statement->HiiValue.Value.string = UserInput->InputValue.Value.string;
   1604         CopyMem (Statement->BufferValue, UserInput->InputValue.Buffer, (UINTN) UserInput->InputValue.BufferLen);
   1605         FreePool (UserInput->InputValue.Buffer);
   1606         break;
   1607 
   1608       case EFI_IFR_PASSWORD_OP:
   1609         if (UserInput->InputValue.Buffer == NULL) {
   1610           //
   1611           // User not input new password, just return.
   1612           //
   1613           break;
   1614         }
   1615 
   1616         DeleteString(Statement->HiiValue.Value.string, gCurrentSelection->FormSet->HiiHandle);
   1617         Statement->HiiValue.Value.string = UserInput->InputValue.Value.string;
   1618         CopyMem (Statement->BufferValue, UserInput->InputValue.Buffer, (UINTN) UserInput->InputValue.BufferLen);
   1619         ZeroMem (UserInput->InputValue.Buffer, (UINTN) UserInput->InputValue.BufferLen);
   1620         FreePool (UserInput->InputValue.Buffer);
   1621         //
   1622         // Two password match, send it to Configuration Driver
   1623         //
   1624         if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {
   1625           PasswordCheck (NULL, UserInput->SelectedStatement, (CHAR16 *) Statement->BufferValue);
   1626           //
   1627           // Clean the value after saved it.
   1628           //
   1629           ZeroMem (Statement->BufferValue, (UINTN) UserInput->InputValue.BufferLen);
   1630           HiiSetString (gCurrentSelection->FormSet->HiiHandle, Statement->HiiValue.Value.string, (CHAR16*)Statement->BufferValue, NULL);
   1631         } else {
   1632           SetQuestionValue (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithHiiDriver);
   1633         }
   1634         break;
   1635 
   1636       case EFI_IFR_ORDERED_LIST_OP:
   1637         CopyMem (Statement->BufferValue, UserInput->InputValue.Buffer, UserInput->InputValue.BufferLen);
   1638         break;
   1639 
   1640       default:
   1641         CopyMem (&Statement->HiiValue, &UserInput->InputValue, sizeof (EFI_HII_VALUE));
   1642         break;
   1643       }
   1644       break;
   1645     }
   1646   }
   1647 
   1648   return Status;
   1649 }
   1650 
   1651 /**
   1652 
   1653   Display form and wait for user to select one menu option, then return it.
   1654 
   1655   @retval EFI_SUCESSS            This function always return successfully for now.
   1656 
   1657 **/
   1658 EFI_STATUS
   1659 DisplayForm (
   1660   VOID
   1661   )
   1662 {
   1663   EFI_STATUS               Status;
   1664   USER_INPUT               UserInput;
   1665   FORM_ENTRY_INFO          *CurrentMenu;
   1666 
   1667   ZeroMem (&UserInput, sizeof (USER_INPUT));
   1668 
   1669   //
   1670   // Update the menu history data.
   1671   //
   1672   CurrentMenu = UiFindMenuList (gCurrentSelection->Handle, &gCurrentSelection->FormSetGuid, gCurrentSelection->FormId);
   1673   if (CurrentMenu == NULL) {
   1674     //
   1675     // Current menu not found, add it to the menu tree
   1676     //
   1677     CurrentMenu = UiAddMenuList (gCurrentSelection->Handle, &gCurrentSelection->FormSetGuid,
   1678                                  gCurrentSelection->FormId, gCurrentSelection->QuestionId);
   1679     ASSERT (CurrentMenu != NULL);
   1680   }
   1681 
   1682   //
   1683   // Back up the form view history data for this form.
   1684   //
   1685   UiCopyMenuList(&gCurrentSelection->Form->FormViewListHead, &mPrivateData.FormBrowserEx2.FormViewHistoryHead);
   1686 
   1687   gCurrentSelection->CurrentMenu = CurrentMenu;
   1688 
   1689   if (gCurrentSelection->QuestionId == 0) {
   1690     //
   1691     // Highlight not specified, fetch it from cached menu
   1692     //
   1693     gCurrentSelection->QuestionId = CurrentMenu->QuestionId;
   1694   }
   1695 
   1696   Status = EvaluateFormExpressions (gCurrentSelection->FormSet, gCurrentSelection->Form);
   1697   if (EFI_ERROR (Status)) {
   1698     return Status;
   1699   }
   1700 
   1701   UpdateDisplayFormData ();
   1702 
   1703   ASSERT (gDisplayFormData.BrowserStatus == BROWSER_SUCCESS);
   1704   Status = mFormDisplay->FormDisplay (&gDisplayFormData, &UserInput);
   1705   if (EFI_ERROR (Status)) {
   1706     FreeDisplayFormData();
   1707     return Status;
   1708   }
   1709 
   1710   Status = ProcessUserInput (&UserInput);
   1711   FreeDisplayFormData();
   1712   return Status;
   1713 }
   1714 
   1715 /**
   1716   Functions which are registered to receive notification of
   1717   database events have this prototype. The actual event is encoded
   1718   in NotifyType. The following table describes how PackageType,
   1719   PackageGuid, Handle, and Package are used for each of the
   1720   notification types.
   1721 
   1722   @param PackageType  Package type of the notification.
   1723 
   1724   @param PackageGuid  If PackageType is
   1725                       EFI_HII_PACKAGE_TYPE_GUID, then this is
   1726                       the pointer to the GUID from the Guid
   1727                       field of EFI_HII_PACKAGE_GUID_HEADER.
   1728                       Otherwise, it must be NULL.
   1729 
   1730   @param Package  Points to the package referred to by the
   1731                   notification Handle The handle of the package
   1732                   list which contains the specified package.
   1733 
   1734   @param Handle       The HII handle.
   1735 
   1736   @param NotifyType   The type of change concerning the
   1737                       database. See
   1738                       EFI_HII_DATABASE_NOTIFY_TYPE.
   1739 
   1740 **/
   1741 EFI_STATUS
   1742 EFIAPI
   1743 FormUpdateNotify (
   1744   IN UINT8                              PackageType,
   1745   IN CONST EFI_GUID                     *PackageGuid,
   1746   IN CONST EFI_HII_PACKAGE_HEADER       *Package,
   1747   IN EFI_HII_HANDLE                     Handle,
   1748   IN EFI_HII_DATABASE_NOTIFY_TYPE       NotifyType
   1749   )
   1750 {
   1751   mHiiPackageListUpdated = TRUE;
   1752 
   1753   return EFI_SUCCESS;
   1754 }
   1755 
   1756 /**
   1757   Update the NV flag info for this form set.
   1758 
   1759   @param  FormSet                FormSet data structure.
   1760 
   1761 **/
   1762 BOOLEAN
   1763 IsNvUpdateRequiredForFormSet (
   1764   IN FORM_BROWSER_FORMSET  *FormSet
   1765   )
   1766 {
   1767   LIST_ENTRY              *Link;
   1768   FORM_BROWSER_FORM       *Form;
   1769   BOOLEAN                 RetVal;
   1770 
   1771   //
   1772   // Not finished question initialization, return FALSE.
   1773   //
   1774   if (!FormSet->QuestionInited) {
   1775     return FALSE;
   1776   }
   1777 
   1778   RetVal = FALSE;
   1779 
   1780   Link = GetFirstNode (&FormSet->FormListHead);
   1781   while (!IsNull (&FormSet->FormListHead, Link)) {
   1782     Form = FORM_BROWSER_FORM_FROM_LINK (Link);
   1783 
   1784     RetVal = IsNvUpdateRequiredForForm(Form);
   1785     if (RetVal) {
   1786       break;
   1787     }
   1788 
   1789     Link = GetNextNode (&FormSet->FormListHead, Link);
   1790   }
   1791 
   1792   return RetVal;
   1793 }
   1794 
   1795 /**
   1796   Update the NvUpdateRequired flag for a form.
   1797 
   1798   @param  Form                Form data structure.
   1799 
   1800 **/
   1801 BOOLEAN
   1802 IsNvUpdateRequiredForForm (
   1803   IN FORM_BROWSER_FORM    *Form
   1804   )
   1805 {
   1806   LIST_ENTRY              *Link;
   1807   FORM_BROWSER_STATEMENT  *Statement;
   1808 
   1809   Link = GetFirstNode (&Form->StatementListHead);
   1810   while (!IsNull (&Form->StatementListHead, Link)) {
   1811     Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
   1812 
   1813     if (Statement->ValueChanged) {
   1814       return TRUE;
   1815     }
   1816 
   1817     Link = GetNextNode (&Form->StatementListHead, Link);
   1818   }
   1819 
   1820   return FALSE;
   1821 }
   1822 
   1823 /**
   1824   Find menu which will show next time.
   1825 
   1826   @param Selection       On input, Selection tell setup browser the information
   1827                          about the Selection, form and formset to be displayed.
   1828                          On output, Selection return the screen item that is selected
   1829                          by user.
   1830   @param SettingLevel    Input Settting level, if it is FormLevel, just exit current form.
   1831                          else, we need to exit current formset.
   1832 
   1833   @retval TRUE           Exit current form.
   1834   @retval FALSE          User press ESC and keep in current form.
   1835 **/
   1836 BOOLEAN
   1837 FindNextMenu (
   1838   IN OUT UI_MENU_SELECTION        *Selection,
   1839   IN     BROWSER_SETTING_SCOPE     SettingLevel
   1840   )
   1841 {
   1842   FORM_ENTRY_INFO            *CurrentMenu;
   1843   FORM_ENTRY_INFO            *ParentMenu;
   1844   BROWSER_SETTING_SCOPE      Scope;
   1845 
   1846   CurrentMenu = Selection->CurrentMenu;
   1847   Scope       = FormSetLevel;
   1848 
   1849   ParentMenu = UiFindParentMenu(CurrentMenu, SettingLevel);
   1850   while (ParentMenu != NULL && !ValidateHiiHandle(ParentMenu->HiiHandle)) {
   1851     ParentMenu = UiFindParentMenu(ParentMenu, SettingLevel);
   1852   }
   1853 
   1854   if (ParentMenu != NULL) {
   1855     if (CompareGuid (&CurrentMenu->FormSetGuid, &ParentMenu->FormSetGuid)) {
   1856       Scope = FormLevel;
   1857     } else {
   1858       Scope = FormSetLevel;
   1859     }
   1860   }
   1861 
   1862   //
   1863   // Form Level Check whether the data is changed.
   1864   //
   1865   if ((gBrowserSettingScope == FormLevel && IsNvUpdateRequiredForForm (Selection->Form)) ||
   1866       (gBrowserSettingScope == FormSetLevel && IsNvUpdateRequiredForFormSet(Selection->FormSet) && Scope == FormSetLevel)) {
   1867     if (!ProcessChangedData(Selection, gBrowserSettingScope)) {
   1868       return FALSE;
   1869     }
   1870   }
   1871 
   1872   if (ParentMenu != NULL) {
   1873     //
   1874     // ParentMenu is found. Then, go to it.
   1875     //
   1876     if (Scope == FormLevel) {
   1877       Selection->Action = UI_ACTION_REFRESH_FORM;
   1878     } else {
   1879       Selection->Action = UI_ACTION_REFRESH_FORMSET;
   1880       CopyMem (&Selection->FormSetGuid, &ParentMenu->FormSetGuid, sizeof (EFI_GUID));
   1881       Selection->Handle = ParentMenu->HiiHandle;
   1882     }
   1883 
   1884     Selection->Statement = NULL;
   1885 
   1886     Selection->FormId = ParentMenu->FormId;
   1887     Selection->QuestionId = ParentMenu->QuestionId;
   1888 
   1889     //
   1890     // Clear highlight record for this menu
   1891     //
   1892     CurrentMenu->QuestionId = 0;
   1893     return FALSE;
   1894   }
   1895 
   1896   //
   1897   // Current in root page, exit the SendForm
   1898   //
   1899   Selection->Action = UI_ACTION_EXIT;
   1900 
   1901   return TRUE;
   1902 }
   1903 
   1904 /**
   1905   Reconnect the controller.
   1906 
   1907   @param DriverHandle          The controller handle which need to be reconnect.
   1908 
   1909   @retval   TRUE     do the reconnect behavior success.
   1910   @retval   FALSE    do the reconnect behavior failed.
   1911 
   1912 **/
   1913 BOOLEAN
   1914 ReconnectController (
   1915   IN EFI_HANDLE   DriverHandle
   1916   )
   1917 {
   1918   EFI_STATUS                      Status;
   1919 
   1920   Status = gBS->DisconnectController(DriverHandle, NULL, NULL);
   1921   if (!EFI_ERROR (Status)) {
   1922     Status = gBS->ConnectController(DriverHandle, NULL, NULL, TRUE);
   1923   }
   1924 
   1925   return Status == EFI_SUCCESS;
   1926 }
   1927 
   1928 /**
   1929   Call the call back function for the question and process the return action.
   1930 
   1931   @param Selection             On input, Selection tell setup browser the information
   1932                                about the Selection, form and formset to be displayed.
   1933                                On output, Selection return the screen item that is selected
   1934                                by user.
   1935   @param FormSet               The formset this question belong to.
   1936   @param Form                  The form this question belong to.
   1937   @param Question              The Question which need to call.
   1938   @param Action                The action request.
   1939   @param SkipSaveOrDiscard     Whether skip save or discard action.
   1940 
   1941   @retval EFI_SUCCESS          The call back function executes successfully.
   1942   @return Other value if the call back function failed to execute.
   1943 **/
   1944 EFI_STATUS
   1945 ProcessCallBackFunction (
   1946   IN OUT UI_MENU_SELECTION               *Selection,
   1947   IN     FORM_BROWSER_FORMSET            *FormSet,
   1948   IN     FORM_BROWSER_FORM               *Form,
   1949   IN     FORM_BROWSER_STATEMENT          *Question,
   1950   IN     EFI_BROWSER_ACTION              Action,
   1951   IN     BOOLEAN                         SkipSaveOrDiscard
   1952   )
   1953 {
   1954   EFI_STATUS                      Status;
   1955   EFI_STATUS                      InternalStatus;
   1956   EFI_BROWSER_ACTION_REQUEST      ActionRequest;
   1957   EFI_HII_CONFIG_ACCESS_PROTOCOL  *ConfigAccess;
   1958   EFI_HII_VALUE                   *HiiValue;
   1959   EFI_IFR_TYPE_VALUE              *TypeValue;
   1960   FORM_BROWSER_STATEMENT          *Statement;
   1961   BOOLEAN                         SubmitFormIsRequired;
   1962   BOOLEAN                         DiscardFormIsRequired;
   1963   BOOLEAN                         NeedExit;
   1964   LIST_ENTRY                      *Link;
   1965   BROWSER_SETTING_SCOPE           SettingLevel;
   1966   EFI_IFR_TYPE_VALUE              BackUpValue;
   1967   UINT8                           *BackUpBuffer;
   1968   CHAR16                          *NewString;
   1969 
   1970   ConfigAccess = FormSet->ConfigAccess;
   1971   SubmitFormIsRequired  = FALSE;
   1972   SettingLevel          = FormSetLevel;
   1973   DiscardFormIsRequired = FALSE;
   1974   NeedExit              = FALSE;
   1975   Status                = EFI_SUCCESS;
   1976   ActionRequest         = EFI_BROWSER_ACTION_REQUEST_NONE;
   1977   BackUpBuffer          = NULL;
   1978 
   1979   if (ConfigAccess == NULL) {
   1980     return EFI_SUCCESS;
   1981   }
   1982 
   1983   Link = GetFirstNode (&Form->StatementListHead);
   1984   while (!IsNull (&Form->StatementListHead, Link)) {
   1985     Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
   1986     Link = GetNextNode (&Form->StatementListHead, Link);
   1987 
   1988     //
   1989     // if Question != NULL, only process the question. Else, process all question in this form.
   1990     //
   1991     if ((Question != NULL) && (Statement != Question)) {
   1992       continue;
   1993     }
   1994 
   1995     if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != EFI_IFR_FLAG_CALLBACK) {
   1996       continue;
   1997     }
   1998 
   1999     //
   2000     // Check whether Statement is disabled.
   2001     //
   2002     if (Statement->Expression != NULL) {
   2003       if (EvaluateExpressionList(Statement->Expression, TRUE, FormSet, Form) == ExpressDisable) {
   2004         continue;
   2005       }
   2006     }
   2007 
   2008     HiiValue = &Statement->HiiValue;
   2009     TypeValue = &HiiValue->Value;
   2010     if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {
   2011       //
   2012       // For OrderedList, passing in the value buffer to Callback()
   2013       //
   2014       TypeValue = (EFI_IFR_TYPE_VALUE *) Statement->BufferValue;
   2015     }
   2016 
   2017     //
   2018     // If EFI_BROWSER_ACTION_CHANGING type, back up the new question value.
   2019     //
   2020     if (Action == EFI_BROWSER_ACTION_CHANGING) {
   2021       if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {
   2022         BackUpBuffer = AllocateCopyPool(Statement->StorageWidth + sizeof(CHAR16), Statement->BufferValue);
   2023         ASSERT (BackUpBuffer != NULL);
   2024       } else {
   2025         CopyMem (&BackUpValue, &HiiValue->Value, sizeof (EFI_IFR_TYPE_VALUE));
   2026       }
   2027     }
   2028 
   2029     ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
   2030     Status = ConfigAccess->Callback (
   2031                              ConfigAccess,
   2032                              Action,
   2033                              Statement->QuestionId,
   2034                              HiiValue->Type,
   2035                              TypeValue,
   2036                              &ActionRequest
   2037                              );
   2038     if (!EFI_ERROR (Status)) {
   2039       //
   2040       // Need to sync the value between Statement->HiiValue->Value and Statement->BufferValue
   2041       //
   2042       if (HiiValue->Type == EFI_IFR_TYPE_STRING) {
   2043         NewString = GetToken (Statement->HiiValue.Value.string, FormSet->HiiHandle);
   2044         ASSERT (NewString != NULL);
   2045 
   2046         ASSERT (StrLen (NewString) * sizeof (CHAR16) <= Statement->StorageWidth);
   2047         if (StrLen (NewString) * sizeof (CHAR16) <= Statement->StorageWidth) {
   2048           ZeroMem (Statement->BufferValue, Statement->StorageWidth);
   2049           CopyMem (Statement->BufferValue, NewString, StrSize (NewString));
   2050         } else {
   2051           CopyMem (Statement->BufferValue, NewString, Statement->StorageWidth);
   2052         }
   2053         FreePool (NewString);
   2054       }
   2055 
   2056       //
   2057       // Only for EFI_BROWSER_ACTION_CHANGED need to handle this ActionRequest.
   2058       //
   2059       switch (Action) {
   2060       case EFI_BROWSER_ACTION_CHANGED:
   2061         switch (ActionRequest) {
   2062         case EFI_BROWSER_ACTION_REQUEST_RESET:
   2063           DiscardFormIsRequired = TRUE;
   2064           gResetRequired = TRUE;
   2065           NeedExit              = TRUE;
   2066           break;
   2067 
   2068         case EFI_BROWSER_ACTION_REQUEST_SUBMIT:
   2069           SubmitFormIsRequired = TRUE;
   2070           NeedExit              = TRUE;
   2071           break;
   2072 
   2073         case EFI_BROWSER_ACTION_REQUEST_EXIT:
   2074           DiscardFormIsRequired = TRUE;
   2075           NeedExit              = TRUE;
   2076           break;
   2077 
   2078         case EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT:
   2079           SubmitFormIsRequired  = TRUE;
   2080           SettingLevel          = FormLevel;
   2081           NeedExit              = TRUE;
   2082           break;
   2083 
   2084         case EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT:
   2085           DiscardFormIsRequired = TRUE;
   2086           SettingLevel          = FormLevel;
   2087           NeedExit              = TRUE;
   2088           break;
   2089 
   2090         case EFI_BROWSER_ACTION_REQUEST_FORM_APPLY:
   2091           SubmitFormIsRequired  = TRUE;
   2092           SettingLevel          = FormLevel;
   2093           break;
   2094 
   2095         case EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD:
   2096           DiscardFormIsRequired = TRUE;
   2097           SettingLevel          = FormLevel;
   2098           break;
   2099 
   2100         case EFI_BROWSER_ACTION_REQUEST_RECONNECT:
   2101           gCallbackReconnect    = TRUE;
   2102           break;
   2103 
   2104         default:
   2105           break;
   2106         }
   2107         break;
   2108 
   2109       case EFI_BROWSER_ACTION_CHANGING:
   2110         //
   2111         // Do the question validation.
   2112         //
   2113         Status = ValueChangedValidation (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement);
   2114         if (!EFI_ERROR (Status)) {
   2115           //
   2116           //check whether the question value  changed compared with edit buffer before updating edit buffer
   2117           // if changed, set the ValueChanged flag to TRUE,in order to trig the CHANGED callback function
   2118           //
   2119           IsQuestionValueChanged(gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithEditBuffer);
   2120           //
   2121           // According the spec, return value from call back of "changing" and
   2122           // "retrieve" should update to the question's temp buffer.
   2123           //
   2124           SetQuestionValue(FormSet, Form, Statement, GetSetValueWithEditBuffer);
   2125         }
   2126         break;
   2127 
   2128       case EFI_BROWSER_ACTION_RETRIEVE:
   2129         //
   2130         // According the spec, return value from call back of "changing" and
   2131         // "retrieve" should update to the question's temp buffer.
   2132         //
   2133         SetQuestionValue(FormSet, Form, Statement, GetSetValueWithEditBuffer);
   2134         break;
   2135 
   2136       default:
   2137         break;
   2138       }
   2139     } else {
   2140       //
   2141       // If the callback returns EFI_UNSUPPORTED for EFI_BROWSER_ACTION_CHANGING,
   2142       // then the browser will use the value passed to Callback() and ignore the
   2143       // value returned by Callback().
   2144       //
   2145       if (Action  == EFI_BROWSER_ACTION_CHANGING && Status == EFI_UNSUPPORTED) {
   2146         if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {
   2147           CopyMem (Statement->BufferValue, BackUpBuffer, Statement->StorageWidth + sizeof(CHAR16));
   2148         } else {
   2149           CopyMem (&HiiValue->Value, &BackUpValue, sizeof (EFI_IFR_TYPE_VALUE));
   2150         }
   2151 
   2152         //
   2153         // Do the question validation.
   2154         //
   2155         InternalStatus = ValueChangedValidation (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement);
   2156         if (!EFI_ERROR (InternalStatus)) {
   2157           //
   2158           //check whether the question value  changed compared with edit buffer before updating edit buffer
   2159           // if changed, set the ValueChanged flag to TRUE,in order to trig the CHANGED callback function
   2160           //
   2161           IsQuestionValueChanged(gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithEditBuffer);
   2162           SetQuestionValue(FormSet, Form, Statement, GetSetValueWithEditBuffer);
   2163         }
   2164       }
   2165 
   2166       //
   2167       // According the spec, return fail from call back of "changing" and
   2168       // "retrieve", should restore the question's value.
   2169       //
   2170       if (Action == EFI_BROWSER_ACTION_CHANGING && Status != EFI_UNSUPPORTED) {
   2171         if (Statement->Storage != NULL) {
   2172           GetQuestionValue(FormSet, Form, Statement, GetSetValueWithEditBuffer);
   2173         } else if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {
   2174           ProcessCallBackFunction (Selection, FormSet, Form, Question, EFI_BROWSER_ACTION_RETRIEVE, FALSE);
   2175         }
   2176       }
   2177 
   2178       if (Action == EFI_BROWSER_ACTION_RETRIEVE) {
   2179         GetQuestionValue(FormSet, Form, Statement, GetSetValueWithEditBuffer);
   2180       }
   2181 
   2182       if (Status == EFI_UNSUPPORTED) {
   2183         //
   2184         // If return EFI_UNSUPPORTED, also consider Hii driver suceess deal with it.
   2185         //
   2186         Status = EFI_SUCCESS;
   2187       }
   2188     }
   2189 
   2190     if (BackUpBuffer != NULL) {
   2191       FreePool (BackUpBuffer);
   2192     }
   2193 
   2194     //
   2195     // If Question != NULL, means just process one question
   2196     // and if code reach here means this question has finished
   2197     // processing, so just break.
   2198     //
   2199     if (Question != NULL) {
   2200       break;
   2201     }
   2202   }
   2203 
   2204   if (gCallbackReconnect && (EFI_BROWSER_ACTION_CHANGED == Action)) {
   2205     //
   2206     // Confirm changes with user first.
   2207     //
   2208     if (IsNvUpdateRequiredForFormSet(FormSet)) {
   2209       if (BROWSER_ACTION_DISCARD == PopupErrorMessage(BROWSER_RECONNECT_SAVE_CHANGES, NULL, NULL, NULL)) {
   2210         gCallbackReconnect = FALSE;
   2211         DiscardFormIsRequired = TRUE;
   2212       } else {
   2213         SubmitFormIsRequired = TRUE;
   2214       }
   2215     } else {
   2216       PopupErrorMessage(BROWSER_RECONNECT_REQUIRED, NULL, NULL, NULL);
   2217     }
   2218 
   2219     //
   2220     // Exit current formset before do the reconnect.
   2221     //
   2222     NeedExit = TRUE;
   2223     SettingLevel = FormSetLevel;
   2224   }
   2225 
   2226   if (SubmitFormIsRequired && !SkipSaveOrDiscard) {
   2227     SubmitForm (FormSet, Form, SettingLevel);
   2228   }
   2229 
   2230   if (DiscardFormIsRequired && !SkipSaveOrDiscard) {
   2231     DiscardForm (FormSet, Form, SettingLevel);
   2232   }
   2233 
   2234   if (NeedExit) {
   2235     FindNextMenu (Selection, SettingLevel);
   2236   }
   2237 
   2238   return Status;
   2239 }
   2240 
   2241 /**
   2242   Call the retrieve type call back function for one question to get the initialize data.
   2243 
   2244   This function only used when in the initialize stage, because in this stage, the
   2245   Selection->Form is not ready. For other case, use the ProcessCallBackFunction instead.
   2246 
   2247   @param ConfigAccess          The config access protocol produced by the hii driver.
   2248   @param Statement             The Question which need to call.
   2249   @param FormSet               The formset this question belong to.
   2250 
   2251   @retval EFI_SUCCESS          The call back function executes successfully.
   2252   @return Other value if the call back function failed to execute.
   2253 **/
   2254 EFI_STATUS
   2255 ProcessRetrieveForQuestion (
   2256   IN     EFI_HII_CONFIG_ACCESS_PROTOCOL  *ConfigAccess,
   2257   IN     FORM_BROWSER_STATEMENT          *Statement,
   2258   IN     FORM_BROWSER_FORMSET            *FormSet
   2259   )
   2260 {
   2261   EFI_STATUS                      Status;
   2262   EFI_BROWSER_ACTION_REQUEST      ActionRequest;
   2263   EFI_HII_VALUE                   *HiiValue;
   2264   EFI_IFR_TYPE_VALUE              *TypeValue;
   2265   CHAR16                          *NewString;
   2266 
   2267   Status                = EFI_SUCCESS;
   2268   ActionRequest         = EFI_BROWSER_ACTION_REQUEST_NONE;
   2269 
   2270   if (((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != EFI_IFR_FLAG_CALLBACK) || ConfigAccess == NULL) {
   2271     return EFI_UNSUPPORTED;
   2272   }
   2273 
   2274   HiiValue  = &Statement->HiiValue;
   2275   TypeValue = &HiiValue->Value;
   2276   if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {
   2277     //
   2278     // For OrderedList, passing in the value buffer to Callback()
   2279     //
   2280     TypeValue = (EFI_IFR_TYPE_VALUE *) Statement->BufferValue;
   2281   }
   2282 
   2283   ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
   2284   Status = ConfigAccess->Callback (
   2285                            ConfigAccess,
   2286                            EFI_BROWSER_ACTION_RETRIEVE,
   2287                            Statement->QuestionId,
   2288                            HiiValue->Type,
   2289                            TypeValue,
   2290                            &ActionRequest
   2291                            );
   2292   if (!EFI_ERROR (Status) && HiiValue->Type == EFI_IFR_TYPE_STRING) {
   2293     NewString = GetToken (Statement->HiiValue.Value.string, FormSet->HiiHandle);
   2294     ASSERT (NewString != NULL);
   2295 
   2296     ASSERT (StrLen (NewString) * sizeof (CHAR16) <= Statement->StorageWidth);
   2297     if (StrLen (NewString) * sizeof (CHAR16) <= Statement->StorageWidth) {
   2298       ZeroMem (Statement->BufferValue, Statement->StorageWidth);
   2299       CopyMem (Statement->BufferValue, NewString, StrSize (NewString));
   2300     } else {
   2301       CopyMem (Statement->BufferValue, NewString, Statement->StorageWidth);
   2302     }
   2303     FreePool (NewString);
   2304   }
   2305 
   2306   return Status;
   2307 }
   2308 
   2309 /**
   2310   The worker function that send the displays to the screen. On output,
   2311   the selection made by user is returned.
   2312 
   2313   @param Selection       On input, Selection tell setup browser the information
   2314                          about the Selection, form and formset to be displayed.
   2315                          On output, Selection return the screen item that is selected
   2316                          by user.
   2317 
   2318   @retval EFI_SUCCESS    The page is displayed successfully.
   2319   @return Other value if the page failed to be diplayed.
   2320 
   2321 **/
   2322 EFI_STATUS
   2323 SetupBrowser (
   2324   IN OUT UI_MENU_SELECTION    *Selection
   2325   )
   2326 {
   2327   EFI_STATUS                      Status;
   2328   LIST_ENTRY                      *Link;
   2329   EFI_HANDLE                      NotifyHandle;
   2330   FORM_BROWSER_STATEMENT          *Statement;
   2331   EFI_HII_CONFIG_ACCESS_PROTOCOL  *ConfigAccess;
   2332 
   2333   ConfigAccess = Selection->FormSet->ConfigAccess;
   2334 
   2335   //
   2336   // Register notify for Form package update
   2337   //
   2338   Status = mHiiDatabase->RegisterPackageNotify (
   2339                            mHiiDatabase,
   2340                            EFI_HII_PACKAGE_FORMS,
   2341                            NULL,
   2342                            FormUpdateNotify,
   2343                            EFI_HII_DATABASE_NOTIFY_REMOVE_PACK,
   2344                            &NotifyHandle
   2345                            );
   2346   if (EFI_ERROR (Status)) {
   2347     return Status;
   2348   }
   2349 
   2350   //
   2351   // Initialize current settings of Questions in this FormSet
   2352   //
   2353   InitializeCurrentSetting (Selection->FormSet);
   2354 
   2355   //
   2356   // Initilize Action field.
   2357   //
   2358   Selection->Action = UI_ACTION_REFRESH_FORM;
   2359 
   2360   //
   2361   // Clean the mCurFakeQestId value is formset refreshed.
   2362   //
   2363   mCurFakeQestId = 0;
   2364 
   2365   do {
   2366 
   2367     //
   2368     // Reset Status to prevent the next break from returning incorrect error status.
   2369     //
   2370     Status = EFI_SUCCESS;
   2371 
   2372     //
   2373     // IFR is updated, force to reparse the IFR binary
   2374     // This check is shared by EFI_BROWSER_ACTION_FORM_CLOSE and
   2375     // EFI_BROWSER_ACTION_RETRIEVE, so code place here.
   2376     //
   2377     if (mHiiPackageListUpdated) {
   2378       Selection->Action = UI_ACTION_REFRESH_FORMSET;
   2379       mHiiPackageListUpdated = FALSE;
   2380       break;
   2381     }
   2382 
   2383     //
   2384     // Initialize Selection->Form
   2385     //
   2386     if (Selection->FormId == 0) {
   2387       //
   2388       // Zero FormId indicates display the first Form in a FormSet
   2389       //
   2390       Link = GetFirstNode (&Selection->FormSet->FormListHead);
   2391 
   2392       Selection->Form = FORM_BROWSER_FORM_FROM_LINK (Link);
   2393       Selection->FormId = Selection->Form->FormId;
   2394     } else {
   2395       Selection->Form = IdToForm (Selection->FormSet, Selection->FormId);
   2396     }
   2397 
   2398     if (Selection->Form == NULL) {
   2399       //
   2400       // No Form to display
   2401       //
   2402       Status = EFI_NOT_FOUND;
   2403       goto Done;
   2404     }
   2405 
   2406     //
   2407     // Check Form is suppressed.
   2408     //
   2409     if (Selection->Form->SuppressExpression != NULL) {
   2410       if (EvaluateExpressionList(Selection->Form->SuppressExpression, TRUE, Selection->FormSet, Selection->Form) == ExpressSuppress) {
   2411         //
   2412         // Form is suppressed.
   2413         //
   2414         PopupErrorMessage(BROWSER_FORM_SUPPRESS, NULL, NULL, NULL);
   2415         Status = EFI_NOT_FOUND;
   2416         goto Done;
   2417       }
   2418     }
   2419 
   2420     //
   2421     // Before display new form, invoke ConfigAccess.Callback() with EFI_BROWSER_ACTION_FORM_OPEN
   2422     // for each question with callback flag.
   2423     // New form may be the first form, or the different form after another form close.
   2424     //
   2425     if (((Selection->Handle != mCurrentHiiHandle) ||
   2426         (!CompareGuid (&Selection->FormSetGuid, &mCurrentFormSetGuid)) ||
   2427         (Selection->FormId != mCurrentFormId))) {
   2428       //
   2429       // Update Retrieve flag.
   2430       //
   2431       mFinishRetrieveCall = FALSE;
   2432 
   2433       //
   2434       // Keep current form information
   2435       //
   2436       mCurrentHiiHandle   = Selection->Handle;
   2437       CopyGuid (&mCurrentFormSetGuid, &Selection->FormSetGuid);
   2438       mCurrentFormId      = Selection->FormId;
   2439 
   2440       if (ConfigAccess != NULL) {
   2441         Status = ProcessCallBackFunction (Selection, Selection->FormSet, Selection->Form, NULL, EFI_BROWSER_ACTION_FORM_OPEN, FALSE);
   2442         if (EFI_ERROR (Status)) {
   2443           goto Done;
   2444         }
   2445 
   2446         //
   2447         // IFR is updated during callback of EFI_BROWSER_ACTION_FORM_OPEN, force to reparse the IFR binary
   2448         //
   2449         if (mHiiPackageListUpdated) {
   2450           Selection->Action = UI_ACTION_REFRESH_FORMSET;
   2451           mHiiPackageListUpdated = FALSE;
   2452           break;
   2453         }
   2454       }
   2455     }
   2456 
   2457     //
   2458     // Load Questions' Value for display
   2459     //
   2460     Status = LoadFormSetConfig (Selection, Selection->FormSet);
   2461     if (EFI_ERROR (Status)) {
   2462       goto Done;
   2463     }
   2464 
   2465     if (!mFinishRetrieveCall) {
   2466       //
   2467       // Finish call RETRIEVE callback for this form.
   2468       //
   2469       mFinishRetrieveCall = TRUE;
   2470 
   2471       if (ConfigAccess != NULL) {
   2472         Status = ProcessCallBackFunction (Selection, Selection->FormSet, Selection->Form, NULL, EFI_BROWSER_ACTION_RETRIEVE, FALSE);
   2473         if (EFI_ERROR (Status)) {
   2474           goto Done;
   2475         }
   2476 
   2477         //
   2478         // IFR is updated during callback of open form, force to reparse the IFR binary
   2479         //
   2480         if (mHiiPackageListUpdated) {
   2481           Selection->Action = UI_ACTION_REFRESH_FORMSET;
   2482           mHiiPackageListUpdated = FALSE;
   2483           break;
   2484         }
   2485       }
   2486     }
   2487 
   2488     //
   2489     // Display form
   2490     //
   2491     Status = DisplayForm ();
   2492     if (EFI_ERROR (Status)) {
   2493       goto Done;
   2494     }
   2495 
   2496     //
   2497     // Check Selected Statement (if press ESC, Selection->Statement will be NULL)
   2498     //
   2499     Statement = Selection->Statement;
   2500     if (Statement != NULL) {
   2501       if ((ConfigAccess != NULL) &&
   2502           ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK) &&
   2503           (Statement->Operand != EFI_IFR_PASSWORD_OP)) {
   2504         Status = ProcessCallBackFunction(Selection, Selection->FormSet, Selection->Form, Statement, EFI_BROWSER_ACTION_CHANGING, FALSE);
   2505         if (Statement->Operand == EFI_IFR_REF_OP) {
   2506           //
   2507           // Process dynamic update ref opcode.
   2508           //
   2509           if (!EFI_ERROR (Status)) {
   2510             Status = ProcessGotoOpCode(Statement, Selection);
   2511           }
   2512 
   2513           //
   2514           // Callback return error status or status return from process goto opcode.
   2515           //
   2516           if (EFI_ERROR (Status)) {
   2517             //
   2518             // Cross reference will not be taken, restore all essential field
   2519             //
   2520             Selection->Handle = mCurrentHiiHandle;
   2521             CopyMem (&Selection->FormSetGuid, &mCurrentFormSetGuid, sizeof (EFI_GUID));
   2522             Selection->FormId = mCurrentFormId;
   2523             Selection->QuestionId = 0;
   2524             Selection->Action = UI_ACTION_REFRESH_FORM;
   2525           }
   2526         }
   2527 
   2528 
   2529         if (!EFI_ERROR (Status) &&
   2530             (Statement->Operand != EFI_IFR_REF_OP) &&
   2531             ((Statement->Storage == NULL) || (Statement->Storage != NULL && Statement->ValueChanged))) {
   2532           //
   2533           // Only question value has been changed, browser will trig CHANGED callback.
   2534           //
   2535           ProcessCallBackFunction(Selection, Selection->FormSet, Selection->Form, Statement, EFI_BROWSER_ACTION_CHANGED, FALSE);
   2536           //
   2537           //check whether the question value changed compared with buffer value
   2538           //if doesn't change ,set the ValueChanged flag to FALSE ,in order not to display the "configuration changed "information on the screen
   2539           //
   2540           IsQuestionValueChanged(gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithBuffer);
   2541         }
   2542       } else {
   2543         //
   2544         // Do the question validation.
   2545         //
   2546         Status = ValueChangedValidation (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement);
   2547         if (!EFI_ERROR (Status) && (Statement->Operand != EFI_IFR_PASSWORD_OP)) {
   2548           SetQuestionValue (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithEditBuffer);
   2549           //
   2550           // Verify whether question value has checked, update the ValueChanged flag in Question.
   2551           //
   2552           IsQuestionValueChanged(gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithBuffer);
   2553         }
   2554       }
   2555 
   2556       //
   2557       // If question has EFI_IFR_FLAG_RESET_REQUIRED/EFI_IFR_FLAG_RECONNECT_REQUIRED flag and without storage
   2558       // and process question success till here, trig the gResetFlag/gFlagReconnect.
   2559       //
   2560       if ((Status == EFI_SUCCESS) &&
   2561           (Statement->Storage == NULL)) {
   2562         if ((Statement->QuestionFlags & EFI_IFR_FLAG_RESET_REQUIRED) != 0) {
   2563           gResetRequired = TRUE;
   2564         }
   2565 
   2566         if ((Statement->QuestionFlags & EFI_IFR_FLAG_RECONNECT_REQUIRED) != 0) {
   2567           gFlagReconnect = TRUE;
   2568         }
   2569       }
   2570     }
   2571 
   2572     //
   2573     // Check whether Exit flag is TRUE.
   2574     //
   2575     if (gExitRequired) {
   2576       switch (gBrowserSettingScope) {
   2577       case SystemLevel:
   2578         Selection->Action = UI_ACTION_EXIT;
   2579         break;
   2580 
   2581       case FormSetLevel:
   2582       case FormLevel:
   2583         FindNextMenu (Selection, gBrowserSettingScope);
   2584         break;
   2585 
   2586       default:
   2587         break;
   2588       }
   2589 
   2590       gExitRequired = FALSE;
   2591     }
   2592 
   2593     //
   2594     // Before exit the form, invoke ConfigAccess.Callback() with EFI_BROWSER_ACTION_FORM_CLOSE
   2595     // for each question with callback flag.
   2596     //
   2597     if ((ConfigAccess != NULL) &&
   2598         ((Selection->Action == UI_ACTION_EXIT) ||
   2599          (Selection->Handle != mCurrentHiiHandle) ||
   2600          (!CompareGuid (&Selection->FormSetGuid, &mCurrentFormSetGuid)) ||
   2601          (Selection->FormId != mCurrentFormId))) {
   2602 
   2603       Status = ProcessCallBackFunction (Selection, Selection->FormSet, Selection->Form, NULL, EFI_BROWSER_ACTION_FORM_CLOSE, FALSE);
   2604       if (EFI_ERROR (Status)) {
   2605         goto Done;
   2606       }
   2607     }
   2608   } while (Selection->Action == UI_ACTION_REFRESH_FORM);
   2609 
   2610 Done:
   2611   //
   2612   // Reset current form information to the initial setting when error happens or form exit.
   2613   //
   2614   if (EFI_ERROR (Status) || Selection->Action == UI_ACTION_EXIT) {
   2615     mCurrentHiiHandle = NULL;
   2616     CopyGuid (&mCurrentFormSetGuid, &gZeroGuid);
   2617     mCurrentFormId = 0;
   2618   }
   2619 
   2620   //
   2621   // Unregister notify for Form package update
   2622   //
   2623   mHiiDatabase->UnregisterPackageNotify (
   2624                    mHiiDatabase,
   2625                    NotifyHandle
   2626                    );
   2627   return Status;
   2628 }
   2629