• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2 Utility functions for UI presentation.
3 
4 Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR>
5 (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution.  The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10 
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 
14 **/
15 
16 #include "Setup.h"
17 
18 BOOLEAN            mHiiPackageListUpdated;
19 UI_MENU_SELECTION  *gCurrentSelection;
20 EFI_HII_HANDLE     mCurrentHiiHandle = NULL;
21 EFI_GUID           mCurrentFormSetGuid = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}};
22 UINT16             mCurrentFormId = 0;
23 EFI_EVENT          mValueChangedEvent = NULL;
24 LIST_ENTRY         mRefreshEventList = INITIALIZE_LIST_HEAD_VARIABLE (mRefreshEventList);
25 UINT16             mCurFakeQestId;
26 FORM_DISPLAY_ENGINE_FORM gDisplayFormData;
27 BOOLEAN            mFinishRetrieveCall = FALSE;
28 
29 /**
30   Evaluate all expressions in a Form.
31 
32   @param  FormSet        FormSet this Form belongs to.
33   @param  Form           The Form.
34 
35   @retval EFI_SUCCESS    The expression evaluated successfuly
36 
37 **/
38 EFI_STATUS
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 (!IsZeroGuid (&Statement->RefreshGuid)) {
362     CreateRefreshEventForStatement (Statement);
363   }
364 
365   //
366   // For RTC type of date/time, set default refresh interval to be 1 second.
367   //
368   if ((Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) && Statement->Storage == NULL) {
369     Statement->RefreshInterval = 1;
370   }
371 
372   //
373   // Create the refresh guid hook event.
374   // If the statement in this form has refresh event or refresh interval, browser will create this event for display engine.
375   //
376   if ((!IsZeroGuid (&Statement->RefreshGuid)) || (Statement->RefreshInterval != 0)) {
377     gDisplayFormData.FormRefreshEvent = mValueChangedEvent;
378   }
379 
380   //
381   // Save the password check function for later use.
382   //
383   if (Statement->Operand == EFI_IFR_PASSWORD_OP) {
384     DisplayStatement->PasswordCheck = PasswordCheck;
385   }
386 
387   //
388   // If this statement is nest in the subtitle, insert to the host statement.
389   // else insert to the form it belongs to.
390   //
391   if (Statement->ParentStatement != NULL) {
392     ParentStatement = GetDisplayStatement(Statement->ParentStatement->OpCode);
393     ASSERT (ParentStatement != NULL);
394     InsertTailList(&ParentStatement->NestStatementList, &DisplayStatement->DisplayLink);
395   } else {
396     InsertTailList(&gDisplayFormData.StatementListHead, &DisplayStatement->DisplayLink);
397   }
398 }
399 
400 /**
401   Process for the refresh interval statement.
402 
403   @param Event    The Event need to be process
404   @param Context  The context of the event.
405 
406 **/
407 VOID
408 EFIAPI
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 (!IsZeroGuid (&gCurrentSelection->Form->RefreshGuid)) {
632     CreateRefreshEventForForm (gCurrentSelection->Form);
633     if (gDisplayFormData.FormRefreshEvent == NULL) {
634       gDisplayFormData.FormRefreshEvent = mValueChangedEvent;
635     }
636   }
637 
638   //
639   // Update hotkey list field.
640   //
641   if (gBrowserSettingScope == SystemLevel || FormEditable) {
642     UpdateHotkeyList();
643   }
644 }
645 
646 /**
647 
648   Initialize the SettingChangedFlag variable in the display form.
649 
650 **/
651 VOID
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 (!IsZeroGuid (&Statement->HiiValue.Value.ref.FormSetGuid)) {
1414     if (Selection->Form->ModalForm) {
1415       return Status;
1416     }
1417     if (!CompareGuid (&Statement->HiiValue.Value.ref.FormSetGuid, &Selection->FormSetGuid)) {
1418       //
1419       // Goto another Formset, check for uncommitted data
1420       //
1421       if ((gBrowserSettingScope == FormLevel || gBrowserSettingScope == FormSetLevel) &&
1422          IsNvUpdateRequiredForFormSet(Selection->FormSet)) {
1423         if (!ProcessChangedData(Selection, FormSetLevel)) {
1424           return EFI_SUCCESS;
1425         }
1426       }
1427     }
1428 
1429     Selection->Action = UI_ACTION_REFRESH_FORMSET;
1430     Selection->Handle = FormSetGuidToHiiHandle(&Statement->HiiValue.Value.ref.FormSetGuid);
1431     if (Selection->Handle == NULL) {
1432       //
1433       // If target Hii Handle not found, exit current formset.
1434       //
1435       FindParentFormSet(Selection);
1436       return EFI_SUCCESS;
1437     }
1438 
1439     CopyMem (&Selection->FormSetGuid, &Statement->HiiValue.Value.ref.FormSetGuid, sizeof (EFI_GUID));
1440     Selection->FormId = Statement->HiiValue.Value.ref.FormId;
1441     Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;
1442   } else if (Statement->HiiValue.Value.ref.FormId != 0) {
1443     //
1444     // Goto another Form, check for uncommitted data
1445     //
1446     if (Statement->HiiValue.Value.ref.FormId != Selection->FormId) {
1447       if ((gBrowserSettingScope == FormLevel && IsNvUpdateRequiredForForm(Selection->Form))) {
1448         if (!ProcessChangedData (Selection, FormLevel)) {
1449           return EFI_SUCCESS;
1450         }
1451       }
1452     }
1453 
1454     RefForm = IdToForm (Selection->FormSet, Statement->HiiValue.Value.ref.FormId);
1455     if ((RefForm != NULL) && (RefForm->SuppressExpression != NULL)) {
1456       if (EvaluateExpressionList(RefForm->SuppressExpression, TRUE, Selection->FormSet, RefForm) != ExpressFalse) {
1457         //
1458         // Form is suppressed.
1459         //
1460         PopupErrorMessage(BROWSER_FORM_SUPPRESS, NULL, NULL, NULL);
1461         return EFI_SUCCESS;
1462       }
1463     }
1464 
1465     Selection->FormId = Statement->HiiValue.Value.ref.FormId;
1466     Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;
1467   } else if (Statement->HiiValue.Value.ref.QuestionId != 0) {
1468     Selection->QuestionId = Statement->HiiValue.Value.ref.QuestionId;
1469   }
1470 
1471   return Status;
1472 }
1473 
1474 
1475 /**
1476   Process Question Config.
1477 
1478   @param  Selection              The UI menu selection.
1479   @param  Question               The Question to be peocessed.
1480 
1481   @retval EFI_SUCCESS            Question Config process success.
1482   @retval Other                  Question Config process fail.
1483 
1484 **/
1485 EFI_STATUS
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         ZeroMem (UserInput->InputValue.Buffer, (UINTN) UserInput->InputValue.BufferLen);
1620         FreePool (UserInput->InputValue.Buffer);
1621         //
1622         // Two password match, send it to Configuration Driver
1623         //
1624         if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {
1625           PasswordCheck (NULL, UserInput->SelectedStatement, (CHAR16 *) Statement->BufferValue);
1626           //
1627           // Clean the value after saved it.
1628           //
1629           ZeroMem (Statement->BufferValue, (UINTN) UserInput->InputValue.BufferLen);
1630           HiiSetString (gCurrentSelection->FormSet->HiiHandle, Statement->HiiValue.Value.string, (CHAR16*)Statement->BufferValue, NULL);
1631         } else {
1632           SetQuestionValue (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithHiiDriver);
1633         }
1634         break;
1635 
1636       case EFI_IFR_ORDERED_LIST_OP:
1637         CopyMem (Statement->BufferValue, UserInput->InputValue.Buffer, UserInput->InputValue.BufferLen);
1638         break;
1639 
1640       default:
1641         CopyMem (&Statement->HiiValue, &UserInput->InputValue, sizeof (EFI_HII_VALUE));
1642         break;
1643       }
1644       break;
1645     }
1646   }
1647 
1648   return Status;
1649 }
1650 
1651 /**
1652 
1653   Display form and wait for user to select one menu option, then return it.
1654 
1655   @retval EFI_SUCESSS            This function always return successfully for now.
1656 
1657 **/
1658 EFI_STATUS
DisplayForm(VOID)1659 DisplayForm (
1660   VOID
1661   )
1662 {
1663   EFI_STATUS               Status;
1664   USER_INPUT               UserInput;
1665   FORM_ENTRY_INFO          *CurrentMenu;
1666 
1667   ZeroMem (&UserInput, sizeof (USER_INPUT));
1668 
1669   //
1670   // Update the menu history data.
1671   //
1672   CurrentMenu = UiFindMenuList (gCurrentSelection->Handle, &gCurrentSelection->FormSetGuid, gCurrentSelection->FormId);
1673   if (CurrentMenu == NULL) {
1674     //
1675     // Current menu not found, add it to the menu tree
1676     //
1677     CurrentMenu = UiAddMenuList (gCurrentSelection->Handle, &gCurrentSelection->FormSetGuid,
1678                                  gCurrentSelection->FormId, gCurrentSelection->QuestionId);
1679     ASSERT (CurrentMenu != NULL);
1680   }
1681 
1682   //
1683   // Back up the form view history data for this form.
1684   //
1685   UiCopyMenuList(&gCurrentSelection->Form->FormViewListHead, &mPrivateData.FormBrowserEx2.FormViewHistoryHead);
1686 
1687   gCurrentSelection->CurrentMenu = CurrentMenu;
1688 
1689   if (gCurrentSelection->QuestionId == 0) {
1690     //
1691     // Highlight not specified, fetch it from cached menu
1692     //
1693     gCurrentSelection->QuestionId = CurrentMenu->QuestionId;
1694   }
1695 
1696   Status = EvaluateFormExpressions (gCurrentSelection->FormSet, gCurrentSelection->Form);
1697   if (EFI_ERROR (Status)) {
1698     return Status;
1699   }
1700 
1701   UpdateDisplayFormData ();
1702 
1703   ASSERT (gDisplayFormData.BrowserStatus == BROWSER_SUCCESS);
1704   Status = mFormDisplay->FormDisplay (&gDisplayFormData, &UserInput);
1705   if (EFI_ERROR (Status)) {
1706     FreeDisplayFormData();
1707     return Status;
1708   }
1709 
1710   Status = ProcessUserInput (&UserInput);
1711   FreeDisplayFormData();
1712   return Status;
1713 }
1714 
1715 /**
1716   Functions which are registered to receive notification of
1717   database events have this prototype. The actual event is encoded
1718   in NotifyType. The following table describes how PackageType,
1719   PackageGuid, Handle, and Package are used for each of the
1720   notification types.
1721 
1722   @param PackageType  Package type of the notification.
1723 
1724   @param PackageGuid  If PackageType is
1725                       EFI_HII_PACKAGE_TYPE_GUID, then this is
1726                       the pointer to the GUID from the Guid
1727                       field of EFI_HII_PACKAGE_GUID_HEADER.
1728                       Otherwise, it must be NULL.
1729 
1730   @param Package  Points to the package referred to by the
1731                   notification Handle The handle of the package
1732                   list which contains the specified package.
1733 
1734   @param Handle       The HII handle.
1735 
1736   @param NotifyType   The type of change concerning the
1737                       database. See
1738                       EFI_HII_DATABASE_NOTIFY_TYPE.
1739 
1740 **/
1741 EFI_STATUS
1742 EFIAPI
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)1743 FormUpdateNotify (
1744   IN UINT8                              PackageType,
1745   IN CONST EFI_GUID                     *PackageGuid,
1746   IN CONST EFI_HII_PACKAGE_HEADER       *Package,
1747   IN EFI_HII_HANDLE                     Handle,
1748   IN EFI_HII_DATABASE_NOTIFY_TYPE       NotifyType
1749   )
1750 {
1751   mHiiPackageListUpdated = TRUE;
1752 
1753   return EFI_SUCCESS;
1754 }
1755 
1756 /**
1757   Update the NV flag info for this form set.
1758 
1759   @param  FormSet                FormSet data structure.
1760 
1761 **/
1762 BOOLEAN
IsNvUpdateRequiredForFormSet(IN FORM_BROWSER_FORMSET * FormSet)1763 IsNvUpdateRequiredForFormSet (
1764   IN FORM_BROWSER_FORMSET  *FormSet
1765   )
1766 {
1767   LIST_ENTRY              *Link;
1768   FORM_BROWSER_FORM       *Form;
1769   BOOLEAN                 RetVal;
1770 
1771   //
1772   // Not finished question initialization, return FALSE.
1773   //
1774   if (!FormSet->QuestionInited) {
1775     return FALSE;
1776   }
1777 
1778   RetVal = FALSE;
1779 
1780   Link = GetFirstNode (&FormSet->FormListHead);
1781   while (!IsNull (&FormSet->FormListHead, Link)) {
1782     Form = FORM_BROWSER_FORM_FROM_LINK (Link);
1783 
1784     RetVal = IsNvUpdateRequiredForForm(Form);
1785     if (RetVal) {
1786       break;
1787     }
1788 
1789     Link = GetNextNode (&FormSet->FormListHead, Link);
1790   }
1791 
1792   return RetVal;
1793 }
1794 
1795 /**
1796   Update the NvUpdateRequired flag for a form.
1797 
1798   @param  Form                Form data structure.
1799 
1800 **/
1801 BOOLEAN
IsNvUpdateRequiredForForm(IN FORM_BROWSER_FORM * Form)1802 IsNvUpdateRequiredForForm (
1803   IN FORM_BROWSER_FORM    *Form
1804   )
1805 {
1806   LIST_ENTRY              *Link;
1807   FORM_BROWSER_STATEMENT  *Statement;
1808 
1809   Link = GetFirstNode (&Form->StatementListHead);
1810   while (!IsNull (&Form->StatementListHead, Link)) {
1811     Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
1812 
1813     if (Statement->ValueChanged) {
1814       return TRUE;
1815     }
1816 
1817     Link = GetNextNode (&Form->StatementListHead, Link);
1818   }
1819 
1820   return FALSE;
1821 }
1822 
1823 /**
1824   Find menu which will show next time.
1825 
1826   @param Selection       On input, Selection tell setup browser the information
1827                          about the Selection, form and formset to be displayed.
1828                          On output, Selection return the screen item that is selected
1829                          by user.
1830   @param SettingLevel    Input Settting level, if it is FormLevel, just exit current form.
1831                          else, we need to exit current formset.
1832 
1833   @retval TRUE           Exit current form.
1834   @retval FALSE          User press ESC and keep in current form.
1835 **/
1836 BOOLEAN
FindNextMenu(IN OUT UI_MENU_SELECTION * Selection,IN BROWSER_SETTING_SCOPE SettingLevel)1837 FindNextMenu (
1838   IN OUT UI_MENU_SELECTION        *Selection,
1839   IN     BROWSER_SETTING_SCOPE     SettingLevel
1840   )
1841 {
1842   FORM_ENTRY_INFO            *CurrentMenu;
1843   FORM_ENTRY_INFO            *ParentMenu;
1844   BROWSER_SETTING_SCOPE      Scope;
1845 
1846   CurrentMenu = Selection->CurrentMenu;
1847   Scope       = FormSetLevel;
1848 
1849   ParentMenu = UiFindParentMenu(CurrentMenu, SettingLevel);
1850   while (ParentMenu != NULL && !ValidateHiiHandle(ParentMenu->HiiHandle)) {
1851     ParentMenu = UiFindParentMenu(ParentMenu, SettingLevel);
1852   }
1853 
1854   if (ParentMenu != NULL) {
1855     if (CompareGuid (&CurrentMenu->FormSetGuid, &ParentMenu->FormSetGuid)) {
1856       Scope = FormLevel;
1857     } else {
1858       Scope = FormSetLevel;
1859     }
1860   }
1861 
1862   //
1863   // Form Level Check whether the data is changed.
1864   //
1865   if ((gBrowserSettingScope == FormLevel && IsNvUpdateRequiredForForm (Selection->Form)) ||
1866       (gBrowserSettingScope == FormSetLevel && IsNvUpdateRequiredForFormSet(Selection->FormSet) && Scope == FormSetLevel)) {
1867     if (!ProcessChangedData(Selection, gBrowserSettingScope)) {
1868       return FALSE;
1869     }
1870   }
1871 
1872   if (ParentMenu != NULL) {
1873     //
1874     // ParentMenu is found. Then, go to it.
1875     //
1876     if (Scope == FormLevel) {
1877       Selection->Action = UI_ACTION_REFRESH_FORM;
1878     } else {
1879       Selection->Action = UI_ACTION_REFRESH_FORMSET;
1880       CopyMem (&Selection->FormSetGuid, &ParentMenu->FormSetGuid, sizeof (EFI_GUID));
1881       Selection->Handle = ParentMenu->HiiHandle;
1882     }
1883 
1884     Selection->Statement = NULL;
1885 
1886     Selection->FormId = ParentMenu->FormId;
1887     Selection->QuestionId = ParentMenu->QuestionId;
1888 
1889     //
1890     // Clear highlight record for this menu
1891     //
1892     CurrentMenu->QuestionId = 0;
1893     return FALSE;
1894   }
1895 
1896   //
1897   // Current in root page, exit the SendForm
1898   //
1899   Selection->Action = UI_ACTION_EXIT;
1900 
1901   return TRUE;
1902 }
1903 
1904 /**
1905   Reconnect the controller.
1906 
1907   @param DriverHandle          The controller handle which need to be reconnect.
1908 
1909   @retval   TRUE     do the reconnect behavior success.
1910   @retval   FALSE    do the reconnect behavior failed.
1911 
1912 **/
1913 BOOLEAN
ReconnectController(IN EFI_HANDLE DriverHandle)1914 ReconnectController (
1915   IN EFI_HANDLE   DriverHandle
1916   )
1917 {
1918   EFI_STATUS                      Status;
1919 
1920   Status = gBS->DisconnectController(DriverHandle, NULL, NULL);
1921   if (!EFI_ERROR (Status)) {
1922     Status = gBS->ConnectController(DriverHandle, NULL, NULL, TRUE);
1923   }
1924 
1925   return Status == EFI_SUCCESS;
1926 }
1927 
1928 /**
1929   Call the call back function for the question and process the return action.
1930 
1931   @param Selection             On input, Selection tell setup browser the information
1932                                about the Selection, form and formset to be displayed.
1933                                On output, Selection return the screen item that is selected
1934                                by user.
1935   @param FormSet               The formset this question belong to.
1936   @param Form                  The form this question belong to.
1937   @param Question              The Question which need to call.
1938   @param Action                The action request.
1939   @param SkipSaveOrDiscard     Whether skip save or discard action.
1940 
1941   @retval EFI_SUCCESS          The call back function executes successfully.
1942   @return Other value if the call back function failed to execute.
1943 **/
1944 EFI_STATUS
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)1945 ProcessCallBackFunction (
1946   IN OUT UI_MENU_SELECTION               *Selection,
1947   IN     FORM_BROWSER_FORMSET            *FormSet,
1948   IN     FORM_BROWSER_FORM               *Form,
1949   IN     FORM_BROWSER_STATEMENT          *Question,
1950   IN     EFI_BROWSER_ACTION              Action,
1951   IN     BOOLEAN                         SkipSaveOrDiscard
1952   )
1953 {
1954   EFI_STATUS                      Status;
1955   EFI_STATUS                      InternalStatus;
1956   EFI_BROWSER_ACTION_REQUEST      ActionRequest;
1957   EFI_HII_CONFIG_ACCESS_PROTOCOL  *ConfigAccess;
1958   EFI_HII_VALUE                   *HiiValue;
1959   EFI_IFR_TYPE_VALUE              *TypeValue;
1960   FORM_BROWSER_STATEMENT          *Statement;
1961   BOOLEAN                         SubmitFormIsRequired;
1962   BOOLEAN                         DiscardFormIsRequired;
1963   BOOLEAN                         NeedExit;
1964   LIST_ENTRY                      *Link;
1965   BROWSER_SETTING_SCOPE           SettingLevel;
1966   EFI_IFR_TYPE_VALUE              BackUpValue;
1967   UINT8                           *BackUpBuffer;
1968   CHAR16                          *NewString;
1969 
1970   ConfigAccess = FormSet->ConfigAccess;
1971   SubmitFormIsRequired  = FALSE;
1972   SettingLevel          = FormSetLevel;
1973   DiscardFormIsRequired = FALSE;
1974   NeedExit              = FALSE;
1975   Status                = EFI_SUCCESS;
1976   ActionRequest         = EFI_BROWSER_ACTION_REQUEST_NONE;
1977   BackUpBuffer          = NULL;
1978 
1979   if (ConfigAccess == NULL) {
1980     return EFI_SUCCESS;
1981   }
1982 
1983   Link = GetFirstNode (&Form->StatementListHead);
1984   while (!IsNull (&Form->StatementListHead, Link)) {
1985     Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
1986     Link = GetNextNode (&Form->StatementListHead, Link);
1987 
1988     //
1989     // if Question != NULL, only process the question. Else, process all question in this form.
1990     //
1991     if ((Question != NULL) && (Statement != Question)) {
1992       continue;
1993     }
1994 
1995     if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != EFI_IFR_FLAG_CALLBACK) {
1996       continue;
1997     }
1998 
1999     //
2000     // Check whether Statement is disabled.
2001     //
2002     if (Statement->Expression != NULL) {
2003       if (EvaluateExpressionList(Statement->Expression, TRUE, FormSet, Form) == ExpressDisable) {
2004         continue;
2005       }
2006     }
2007 
2008     HiiValue = &Statement->HiiValue;
2009     TypeValue = &HiiValue->Value;
2010     if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {
2011       //
2012       // For OrderedList, passing in the value buffer to Callback()
2013       //
2014       TypeValue = (EFI_IFR_TYPE_VALUE *) Statement->BufferValue;
2015     }
2016 
2017     //
2018     // If EFI_BROWSER_ACTION_CHANGING type, back up the new question value.
2019     //
2020     if (Action == EFI_BROWSER_ACTION_CHANGING) {
2021       if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {
2022         BackUpBuffer = AllocateCopyPool(Statement->StorageWidth + sizeof(CHAR16), Statement->BufferValue);
2023         ASSERT (BackUpBuffer != NULL);
2024       } else {
2025         CopyMem (&BackUpValue, &HiiValue->Value, sizeof (EFI_IFR_TYPE_VALUE));
2026       }
2027     }
2028 
2029     ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
2030     Status = ConfigAccess->Callback (
2031                              ConfigAccess,
2032                              Action,
2033                              Statement->QuestionId,
2034                              HiiValue->Type,
2035                              TypeValue,
2036                              &ActionRequest
2037                              );
2038     if (!EFI_ERROR (Status)) {
2039       //
2040       // Need to sync the value between Statement->HiiValue->Value and Statement->BufferValue
2041       //
2042       if (HiiValue->Type == EFI_IFR_TYPE_STRING) {
2043         NewString = GetToken (Statement->HiiValue.Value.string, FormSet->HiiHandle);
2044         ASSERT (NewString != NULL);
2045 
2046         ASSERT (StrLen (NewString) * sizeof (CHAR16) <= Statement->StorageWidth);
2047         if (StrLen (NewString) * sizeof (CHAR16) <= Statement->StorageWidth) {
2048           ZeroMem (Statement->BufferValue, Statement->StorageWidth);
2049           CopyMem (Statement->BufferValue, NewString, StrSize (NewString));
2050         } else {
2051           CopyMem (Statement->BufferValue, NewString, Statement->StorageWidth);
2052         }
2053         FreePool (NewString);
2054       }
2055 
2056       //
2057       // Only for EFI_BROWSER_ACTION_CHANGED need to handle this ActionRequest.
2058       //
2059       switch (Action) {
2060       case EFI_BROWSER_ACTION_CHANGED:
2061         switch (ActionRequest) {
2062         case EFI_BROWSER_ACTION_REQUEST_RESET:
2063           DiscardFormIsRequired = TRUE;
2064           gResetRequired = TRUE;
2065           NeedExit              = TRUE;
2066           break;
2067 
2068         case EFI_BROWSER_ACTION_REQUEST_SUBMIT:
2069           SubmitFormIsRequired = TRUE;
2070           NeedExit              = TRUE;
2071           break;
2072 
2073         case EFI_BROWSER_ACTION_REQUEST_EXIT:
2074           DiscardFormIsRequired = TRUE;
2075           NeedExit              = TRUE;
2076           break;
2077 
2078         case EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT:
2079           SubmitFormIsRequired  = TRUE;
2080           SettingLevel          = FormLevel;
2081           NeedExit              = TRUE;
2082           break;
2083 
2084         case EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT:
2085           DiscardFormIsRequired = TRUE;
2086           SettingLevel          = FormLevel;
2087           NeedExit              = TRUE;
2088           break;
2089 
2090         case EFI_BROWSER_ACTION_REQUEST_FORM_APPLY:
2091           SubmitFormIsRequired  = TRUE;
2092           SettingLevel          = FormLevel;
2093           break;
2094 
2095         case EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD:
2096           DiscardFormIsRequired = TRUE;
2097           SettingLevel          = FormLevel;
2098           break;
2099 
2100         case EFI_BROWSER_ACTION_REQUEST_RECONNECT:
2101           gCallbackReconnect    = TRUE;
2102           break;
2103 
2104         default:
2105           break;
2106         }
2107         break;
2108 
2109       case EFI_BROWSER_ACTION_CHANGING:
2110         //
2111         // Do the question validation.
2112         //
2113         Status = ValueChangedValidation (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement);
2114         if (!EFI_ERROR (Status)) {
2115           //
2116           //check whether the question value  changed compared with edit buffer before updating edit buffer
2117           // if changed, set the ValueChanged flag to TRUE,in order to trig the CHANGED callback function
2118           //
2119           IsQuestionValueChanged(gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithEditBuffer);
2120           //
2121           // According the spec, return value from call back of "changing" and
2122           // "retrieve" should update to the question's temp buffer.
2123           //
2124           SetQuestionValue(FormSet, Form, Statement, GetSetValueWithEditBuffer);
2125         }
2126         break;
2127 
2128       case EFI_BROWSER_ACTION_RETRIEVE:
2129         //
2130         // According the spec, return value from call back of "changing" and
2131         // "retrieve" should update to the question's temp buffer.
2132         //
2133         SetQuestionValue(FormSet, Form, Statement, GetSetValueWithEditBuffer);
2134         break;
2135 
2136       default:
2137         break;
2138       }
2139     } else {
2140       //
2141       // If the callback returns EFI_UNSUPPORTED for EFI_BROWSER_ACTION_CHANGING,
2142       // then the browser will use the value passed to Callback() and ignore the
2143       // value returned by Callback().
2144       //
2145       if (Action  == EFI_BROWSER_ACTION_CHANGING && Status == EFI_UNSUPPORTED) {
2146         if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {
2147           CopyMem (Statement->BufferValue, BackUpBuffer, Statement->StorageWidth + sizeof(CHAR16));
2148         } else {
2149           CopyMem (&HiiValue->Value, &BackUpValue, sizeof (EFI_IFR_TYPE_VALUE));
2150         }
2151 
2152         //
2153         // Do the question validation.
2154         //
2155         InternalStatus = ValueChangedValidation (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement);
2156         if (!EFI_ERROR (InternalStatus)) {
2157           //
2158           //check whether the question value  changed compared with edit buffer before updating edit buffer
2159           // if changed, set the ValueChanged flag to TRUE,in order to trig the CHANGED callback function
2160           //
2161           IsQuestionValueChanged(gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithEditBuffer);
2162           SetQuestionValue(FormSet, Form, Statement, GetSetValueWithEditBuffer);
2163         }
2164       }
2165 
2166       //
2167       // According the spec, return fail from call back of "changing" and
2168       // "retrieve", should restore the question's value.
2169       //
2170       if (Action == EFI_BROWSER_ACTION_CHANGING && Status != EFI_UNSUPPORTED) {
2171         if (Statement->Storage != NULL) {
2172           GetQuestionValue(FormSet, Form, Statement, GetSetValueWithEditBuffer);
2173         } else if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {
2174           ProcessCallBackFunction (Selection, FormSet, Form, Question, EFI_BROWSER_ACTION_RETRIEVE, FALSE);
2175         }
2176       }
2177 
2178       if (Action == EFI_BROWSER_ACTION_RETRIEVE) {
2179         GetQuestionValue(FormSet, Form, Statement, GetSetValueWithEditBuffer);
2180       }
2181 
2182       if (Status == EFI_UNSUPPORTED) {
2183         //
2184         // If return EFI_UNSUPPORTED, also consider Hii driver suceess deal with it.
2185         //
2186         Status = EFI_SUCCESS;
2187       }
2188     }
2189 
2190     if (BackUpBuffer != NULL) {
2191       FreePool (BackUpBuffer);
2192     }
2193 
2194     //
2195     // If Question != NULL, means just process one question
2196     // and if code reach here means this question has finished
2197     // processing, so just break.
2198     //
2199     if (Question != NULL) {
2200       break;
2201     }
2202   }
2203 
2204   if (gCallbackReconnect && (EFI_BROWSER_ACTION_CHANGED == Action)) {
2205     //
2206     // Confirm changes with user first.
2207     //
2208     if (IsNvUpdateRequiredForFormSet(FormSet)) {
2209       if (BROWSER_ACTION_DISCARD == PopupErrorMessage(BROWSER_RECONNECT_SAVE_CHANGES, NULL, NULL, NULL)) {
2210         gCallbackReconnect = FALSE;
2211         DiscardFormIsRequired = TRUE;
2212       } else {
2213         SubmitFormIsRequired = TRUE;
2214       }
2215     } else {
2216       PopupErrorMessage(BROWSER_RECONNECT_REQUIRED, NULL, NULL, NULL);
2217     }
2218 
2219     //
2220     // Exit current formset before do the reconnect.
2221     //
2222     NeedExit = TRUE;
2223     SettingLevel = FormSetLevel;
2224   }
2225 
2226   if (SubmitFormIsRequired && !SkipSaveOrDiscard) {
2227     SubmitForm (FormSet, Form, SettingLevel);
2228   }
2229 
2230   if (DiscardFormIsRequired && !SkipSaveOrDiscard) {
2231     DiscardForm (FormSet, Form, SettingLevel);
2232   }
2233 
2234   if (NeedExit) {
2235     FindNextMenu (Selection, SettingLevel);
2236   }
2237 
2238   return Status;
2239 }
2240 
2241 /**
2242   Call the retrieve type call back function for one question to get the initialize data.
2243 
2244   This function only used when in the initialize stage, because in this stage, the
2245   Selection->Form is not ready. For other case, use the ProcessCallBackFunction instead.
2246 
2247   @param ConfigAccess          The config access protocol produced by the hii driver.
2248   @param Statement             The Question which need to call.
2249   @param FormSet               The formset this question belong to.
2250 
2251   @retval EFI_SUCCESS          The call back function executes successfully.
2252   @return Other value if the call back function failed to execute.
2253 **/
2254 EFI_STATUS
ProcessRetrieveForQuestion(IN EFI_HII_CONFIG_ACCESS_PROTOCOL * ConfigAccess,IN FORM_BROWSER_STATEMENT * Statement,IN FORM_BROWSER_FORMSET * FormSet)2255 ProcessRetrieveForQuestion (
2256   IN     EFI_HII_CONFIG_ACCESS_PROTOCOL  *ConfigAccess,
2257   IN     FORM_BROWSER_STATEMENT          *Statement,
2258   IN     FORM_BROWSER_FORMSET            *FormSet
2259   )
2260 {
2261   EFI_STATUS                      Status;
2262   EFI_BROWSER_ACTION_REQUEST      ActionRequest;
2263   EFI_HII_VALUE                   *HiiValue;
2264   EFI_IFR_TYPE_VALUE              *TypeValue;
2265   CHAR16                          *NewString;
2266 
2267   Status                = EFI_SUCCESS;
2268   ActionRequest         = EFI_BROWSER_ACTION_REQUEST_NONE;
2269 
2270   if (((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != EFI_IFR_FLAG_CALLBACK) || ConfigAccess == NULL) {
2271     return EFI_UNSUPPORTED;
2272   }
2273 
2274   HiiValue  = &Statement->HiiValue;
2275   TypeValue = &HiiValue->Value;
2276   if (HiiValue->Type == EFI_IFR_TYPE_BUFFER) {
2277     //
2278     // For OrderedList, passing in the value buffer to Callback()
2279     //
2280     TypeValue = (EFI_IFR_TYPE_VALUE *) Statement->BufferValue;
2281   }
2282 
2283   ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
2284   Status = ConfigAccess->Callback (
2285                            ConfigAccess,
2286                            EFI_BROWSER_ACTION_RETRIEVE,
2287                            Statement->QuestionId,
2288                            HiiValue->Type,
2289                            TypeValue,
2290                            &ActionRequest
2291                            );
2292   if (!EFI_ERROR (Status) && HiiValue->Type == EFI_IFR_TYPE_STRING) {
2293     NewString = GetToken (Statement->HiiValue.Value.string, FormSet->HiiHandle);
2294     ASSERT (NewString != NULL);
2295 
2296     ASSERT (StrLen (NewString) * sizeof (CHAR16) <= Statement->StorageWidth);
2297     if (StrLen (NewString) * sizeof (CHAR16) <= Statement->StorageWidth) {
2298       ZeroMem (Statement->BufferValue, Statement->StorageWidth);
2299       CopyMem (Statement->BufferValue, NewString, StrSize (NewString));
2300     } else {
2301       CopyMem (Statement->BufferValue, NewString, Statement->StorageWidth);
2302     }
2303     FreePool (NewString);
2304   }
2305 
2306   return Status;
2307 }
2308 
2309 /**
2310   The worker function that send the displays to the screen. On output,
2311   the selection made by user is returned.
2312 
2313   @param Selection       On input, Selection tell setup browser the information
2314                          about the Selection, form and formset to be displayed.
2315                          On output, Selection return the screen item that is selected
2316                          by user.
2317 
2318   @retval EFI_SUCCESS    The page is displayed successfully.
2319   @return Other value if the page failed to be diplayed.
2320 
2321 **/
2322 EFI_STATUS
SetupBrowser(IN OUT UI_MENU_SELECTION * Selection)2323 SetupBrowser (
2324   IN OUT UI_MENU_SELECTION    *Selection
2325   )
2326 {
2327   EFI_STATUS                      Status;
2328   LIST_ENTRY                      *Link;
2329   EFI_HANDLE                      NotifyHandle;
2330   FORM_BROWSER_STATEMENT          *Statement;
2331   EFI_HII_CONFIG_ACCESS_PROTOCOL  *ConfigAccess;
2332 
2333   ConfigAccess = Selection->FormSet->ConfigAccess;
2334 
2335   //
2336   // Register notify for Form package update
2337   //
2338   Status = mHiiDatabase->RegisterPackageNotify (
2339                            mHiiDatabase,
2340                            EFI_HII_PACKAGE_FORMS,
2341                            NULL,
2342                            FormUpdateNotify,
2343                            EFI_HII_DATABASE_NOTIFY_REMOVE_PACK,
2344                            &NotifyHandle
2345                            );
2346   if (EFI_ERROR (Status)) {
2347     return Status;
2348   }
2349 
2350   //
2351   // Initialize current settings of Questions in this FormSet
2352   //
2353   InitializeCurrentSetting (Selection->FormSet);
2354 
2355   //
2356   // Initilize Action field.
2357   //
2358   Selection->Action = UI_ACTION_REFRESH_FORM;
2359 
2360   //
2361   // Clean the mCurFakeQestId value is formset refreshed.
2362   //
2363   mCurFakeQestId = 0;
2364 
2365   do {
2366 
2367     //
2368     // Reset Status to prevent the next break from returning incorrect error status.
2369     //
2370     Status = EFI_SUCCESS;
2371 
2372     //
2373     // IFR is updated, force to reparse the IFR binary
2374     // This check is shared by EFI_BROWSER_ACTION_FORM_CLOSE and
2375     // EFI_BROWSER_ACTION_RETRIEVE, so code place here.
2376     //
2377     if (mHiiPackageListUpdated) {
2378       Selection->Action = UI_ACTION_REFRESH_FORMSET;
2379       mHiiPackageListUpdated = FALSE;
2380       break;
2381     }
2382 
2383     //
2384     // Initialize Selection->Form
2385     //
2386     if (Selection->FormId == 0) {
2387       //
2388       // Zero FormId indicates display the first Form in a FormSet
2389       //
2390       Link = GetFirstNode (&Selection->FormSet->FormListHead);
2391 
2392       Selection->Form = FORM_BROWSER_FORM_FROM_LINK (Link);
2393       Selection->FormId = Selection->Form->FormId;
2394     } else {
2395       Selection->Form = IdToForm (Selection->FormSet, Selection->FormId);
2396     }
2397 
2398     if (Selection->Form == NULL) {
2399       //
2400       // No Form to display
2401       //
2402       Status = EFI_NOT_FOUND;
2403       goto Done;
2404     }
2405 
2406     //
2407     // Check Form is suppressed.
2408     //
2409     if (Selection->Form->SuppressExpression != NULL) {
2410       if (EvaluateExpressionList(Selection->Form->SuppressExpression, TRUE, Selection->FormSet, Selection->Form) == ExpressSuppress) {
2411         //
2412         // Form is suppressed.
2413         //
2414         PopupErrorMessage(BROWSER_FORM_SUPPRESS, NULL, NULL, NULL);
2415         Status = EFI_NOT_FOUND;
2416         goto Done;
2417       }
2418     }
2419 
2420     //
2421     // Before display new form, invoke ConfigAccess.Callback() with EFI_BROWSER_ACTION_FORM_OPEN
2422     // for each question with callback flag.
2423     // New form may be the first form, or the different form after another form close.
2424     //
2425     if (((Selection->Handle != mCurrentHiiHandle) ||
2426         (!CompareGuid (&Selection->FormSetGuid, &mCurrentFormSetGuid)) ||
2427         (Selection->FormId != mCurrentFormId))) {
2428       //
2429       // Update Retrieve flag.
2430       //
2431       mFinishRetrieveCall = FALSE;
2432 
2433       //
2434       // Keep current form information
2435       //
2436       mCurrentHiiHandle   = Selection->Handle;
2437       CopyGuid (&mCurrentFormSetGuid, &Selection->FormSetGuid);
2438       mCurrentFormId      = Selection->FormId;
2439 
2440       if (ConfigAccess != NULL) {
2441         Status = ProcessCallBackFunction (Selection, Selection->FormSet, Selection->Form, NULL, EFI_BROWSER_ACTION_FORM_OPEN, FALSE);
2442         if (EFI_ERROR (Status)) {
2443           goto Done;
2444         }
2445 
2446         //
2447         // IFR is updated during callback of EFI_BROWSER_ACTION_FORM_OPEN, force to reparse the IFR binary
2448         //
2449         if (mHiiPackageListUpdated) {
2450           Selection->Action = UI_ACTION_REFRESH_FORMSET;
2451           mHiiPackageListUpdated = FALSE;
2452           break;
2453         }
2454       }
2455     }
2456 
2457     //
2458     // Load Questions' Value for display
2459     //
2460     Status = LoadFormSetConfig (Selection, Selection->FormSet);
2461     if (EFI_ERROR (Status)) {
2462       goto Done;
2463     }
2464 
2465     if (!mFinishRetrieveCall) {
2466       //
2467       // Finish call RETRIEVE callback for this form.
2468       //
2469       mFinishRetrieveCall = TRUE;
2470 
2471       if (ConfigAccess != NULL) {
2472         Status = ProcessCallBackFunction (Selection, Selection->FormSet, Selection->Form, NULL, EFI_BROWSER_ACTION_RETRIEVE, FALSE);
2473         if (EFI_ERROR (Status)) {
2474           goto Done;
2475         }
2476 
2477         //
2478         // IFR is updated during callback of open form, force to reparse the IFR binary
2479         //
2480         if (mHiiPackageListUpdated) {
2481           Selection->Action = UI_ACTION_REFRESH_FORMSET;
2482           mHiiPackageListUpdated = FALSE;
2483           break;
2484         }
2485       }
2486     }
2487 
2488     //
2489     // Display form
2490     //
2491     Status = DisplayForm ();
2492     if (EFI_ERROR (Status)) {
2493       goto Done;
2494     }
2495 
2496     //
2497     // Check Selected Statement (if press ESC, Selection->Statement will be NULL)
2498     //
2499     Statement = Selection->Statement;
2500     if (Statement != NULL) {
2501       if ((ConfigAccess != NULL) &&
2502           ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK) &&
2503           (Statement->Operand != EFI_IFR_PASSWORD_OP)) {
2504         Status = ProcessCallBackFunction(Selection, Selection->FormSet, Selection->Form, Statement, EFI_BROWSER_ACTION_CHANGING, FALSE);
2505         if (Statement->Operand == EFI_IFR_REF_OP) {
2506           //
2507           // Process dynamic update ref opcode.
2508           //
2509           if (!EFI_ERROR (Status)) {
2510             Status = ProcessGotoOpCode(Statement, Selection);
2511           }
2512 
2513           //
2514           // Callback return error status or status return from process goto opcode.
2515           //
2516           if (EFI_ERROR (Status)) {
2517             //
2518             // Cross reference will not be taken, restore all essential field
2519             //
2520             Selection->Handle = mCurrentHiiHandle;
2521             CopyMem (&Selection->FormSetGuid, &mCurrentFormSetGuid, sizeof (EFI_GUID));
2522             Selection->FormId = mCurrentFormId;
2523             Selection->QuestionId = 0;
2524             Selection->Action = UI_ACTION_REFRESH_FORM;
2525           }
2526         }
2527 
2528 
2529         if (!EFI_ERROR (Status) &&
2530             (Statement->Operand != EFI_IFR_REF_OP) &&
2531             ((Statement->Storage == NULL) || (Statement->Storage != NULL && Statement->ValueChanged))) {
2532           //
2533           // Only question value has been changed, browser will trig CHANGED callback.
2534           //
2535           ProcessCallBackFunction(Selection, Selection->FormSet, Selection->Form, Statement, EFI_BROWSER_ACTION_CHANGED, FALSE);
2536           //
2537           //check whether the question value changed compared with buffer value
2538           //if doesn't change ,set the ValueChanged flag to FALSE ,in order not to display the "configuration changed "information on the screen
2539           //
2540           IsQuestionValueChanged(gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithBuffer);
2541         }
2542       } else {
2543         //
2544         // Do the question validation.
2545         //
2546         Status = ValueChangedValidation (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement);
2547         if (!EFI_ERROR (Status) && (Statement->Operand != EFI_IFR_PASSWORD_OP)) {
2548           SetQuestionValue (gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithEditBuffer);
2549           //
2550           // Verify whether question value has checked, update the ValueChanged flag in Question.
2551           //
2552           IsQuestionValueChanged(gCurrentSelection->FormSet, gCurrentSelection->Form, Statement, GetSetValueWithBuffer);
2553         }
2554       }
2555 
2556       //
2557       // If question has EFI_IFR_FLAG_RESET_REQUIRED/EFI_IFR_FLAG_RECONNECT_REQUIRED flag and without storage
2558       // and process question success till here, trig the gResetFlag/gFlagReconnect.
2559       //
2560       if ((Status == EFI_SUCCESS) &&
2561           (Statement->Storage == NULL)) {
2562         if ((Statement->QuestionFlags & EFI_IFR_FLAG_RESET_REQUIRED) != 0) {
2563           gResetRequired = TRUE;
2564         }
2565 
2566         if ((Statement->QuestionFlags & EFI_IFR_FLAG_RECONNECT_REQUIRED) != 0) {
2567           gFlagReconnect = TRUE;
2568         }
2569       }
2570     }
2571 
2572     //
2573     // Check whether Exit flag is TRUE.
2574     //
2575     if (gExitRequired) {
2576       switch (gBrowserSettingScope) {
2577       case SystemLevel:
2578         Selection->Action = UI_ACTION_EXIT;
2579         break;
2580 
2581       case FormSetLevel:
2582       case FormLevel:
2583         FindNextMenu (Selection, gBrowserSettingScope);
2584         break;
2585 
2586       default:
2587         break;
2588       }
2589 
2590       gExitRequired = FALSE;
2591     }
2592 
2593     //
2594     // Before exit the form, invoke ConfigAccess.Callback() with EFI_BROWSER_ACTION_FORM_CLOSE
2595     // for each question with callback flag.
2596     //
2597     if ((ConfigAccess != NULL) &&
2598         ((Selection->Action == UI_ACTION_EXIT) ||
2599          (Selection->Handle != mCurrentHiiHandle) ||
2600          (!CompareGuid (&Selection->FormSetGuid, &mCurrentFormSetGuid)) ||
2601          (Selection->FormId != mCurrentFormId))) {
2602 
2603       Status = ProcessCallBackFunction (Selection, Selection->FormSet, Selection->Form, NULL, EFI_BROWSER_ACTION_FORM_CLOSE, FALSE);
2604       if (EFI_ERROR (Status)) {
2605         goto Done;
2606       }
2607     }
2608   } while (Selection->Action == UI_ACTION_REFRESH_FORM);
2609 
2610 Done:
2611   //
2612   // Reset current form information to the initial setting when error happens or form exit.
2613   //
2614   if (EFI_ERROR (Status) || Selection->Action == UI_ACTION_EXIT) {
2615     mCurrentHiiHandle = NULL;
2616     CopyGuid (&mCurrentFormSetGuid, &gZeroGuid);
2617     mCurrentFormId = 0;
2618   }
2619 
2620   //
2621   // Unregister notify for Form package update
2622   //
2623   mHiiDatabase->UnregisterPackageNotify (
2624                    mHiiDatabase,
2625                    NotifyHandle
2626                    );
2627   return Status;
2628 }
2629