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