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