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