1 /** @file
2 Utility functions for expression evaluation.
3 
4 Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6 
7 **/
8 
9 #include "Setup.h"
10 
11 //
12 // Global stack used to evaluate boolean expresions
13 //
14 EFI_HII_VALUE *mOpCodeScopeStack = NULL;
15 EFI_HII_VALUE *mOpCodeScopeStackEnd = NULL;
16 EFI_HII_VALUE *mOpCodeScopeStackPointer = NULL;
17 
18 EFI_HII_VALUE *mExpressionEvaluationStack = NULL;
19 EFI_HII_VALUE *mExpressionEvaluationStackEnd = NULL;
20 EFI_HII_VALUE *mExpressionEvaluationStackPointer = NULL;
21 UINTN         mExpressionEvaluationStackOffset = 0;
22 
23 EFI_HII_VALUE *mCurrentExpressionStack = NULL;
24 EFI_HII_VALUE *mCurrentExpressionEnd = NULL;
25 EFI_HII_VALUE *mCurrentExpressionPointer = NULL;
26 
27 EFI_HII_VALUE *mMapExpressionListStack = NULL;
28 EFI_HII_VALUE *mMapExpressionListEnd = NULL;
29 EFI_HII_VALUE *mMapExpressionListPointer = NULL;
30 
31 FORM_EXPRESSION   **mFormExpressionStack = NULL;
32 FORM_EXPRESSION   **mFormExpressionEnd = NULL;
33 FORM_EXPRESSION   **mFormExpressionPointer = NULL;
34 
35 FORM_EXPRESSION   **mStatementExpressionStack = NULL;
36 FORM_EXPRESSION   **mStatementExpressionEnd = NULL;
37 FORM_EXPRESSION   **mStatementExpressionPointer = NULL;
38 
39 FORM_EXPRESSION   **mOptionExpressionStack = NULL;
40 FORM_EXPRESSION   **mOptionExpressionEnd = NULL;
41 FORM_EXPRESSION   **mOptionExpressionPointer = NULL;
42 
43 
44 //
45 // Unicode collation protocol interface
46 //
47 EFI_UNICODE_COLLATION_PROTOCOL *mUnicodeCollation = NULL;
48 EFI_USER_MANAGER_PROTOCOL      *mUserManager = NULL;
49 
50 /**
51   Grow size of the stack.
52 
53   This is an internal function.
54 
55   @param  Stack                  On input: old stack; On output: new stack
56   @param  StackPtr               On input: old stack pointer; On output: new stack
57                                  pointer
58   @param  StackEnd               On input: old stack end; On output: new stack end
59 
60   @retval EFI_SUCCESS            Grow stack success.
61   @retval EFI_OUT_OF_RESOURCES   No enough memory for stack space.
62 
63 **/
64 EFI_STATUS
GrowStack(IN OUT EFI_HII_VALUE ** Stack,IN OUT EFI_HII_VALUE ** StackPtr,IN OUT EFI_HII_VALUE ** StackEnd)65 GrowStack (
66   IN OUT EFI_HII_VALUE  **Stack,
67   IN OUT EFI_HII_VALUE  **StackPtr,
68   IN OUT EFI_HII_VALUE  **StackEnd
69   )
70 {
71   UINTN           Size;
72   EFI_HII_VALUE  *NewStack;
73 
74   Size = EXPRESSION_STACK_SIZE_INCREMENT;
75   if (*StackPtr != NULL) {
76     Size = Size + (*StackEnd - *Stack);
77   }
78 
79   NewStack = AllocatePool (Size * sizeof (EFI_HII_VALUE));
80   if (NewStack == NULL) {
81     return EFI_OUT_OF_RESOURCES;
82   }
83 
84   if (*StackPtr != NULL) {
85     //
86     // Copy from Old Stack to the New Stack
87     //
88     CopyMem (
89       NewStack,
90       *Stack,
91       (*StackEnd - *Stack) * sizeof (EFI_HII_VALUE)
92       );
93 
94     //
95     // Free The Old Stack
96     //
97     FreePool (*Stack);
98   }
99 
100   //
101   // Make the Stack pointer point to the old data in the new stack
102   //
103   *StackPtr = NewStack + (*StackPtr - *Stack);
104   *Stack    = NewStack;
105   *StackEnd = NewStack + Size;
106 
107   return EFI_SUCCESS;
108 }
109 
110 
111 /**
112   Push an element onto the Boolean Stack.
113 
114   @param  Stack                  On input: old stack; On output: new stack
115   @param  StackPtr               On input: old stack pointer; On output: new stack
116                                  pointer
117   @param  StackEnd               On input: old stack end; On output: new stack end
118   @param  Data                   Data to push.
119 
120   @retval EFI_SUCCESS            Push stack success.
121 
122 **/
123 EFI_STATUS
PushStack(IN OUT EFI_HII_VALUE ** Stack,IN OUT EFI_HII_VALUE ** StackPtr,IN OUT EFI_HII_VALUE ** StackEnd,IN EFI_HII_VALUE * Data)124 PushStack (
125   IN OUT EFI_HII_VALUE       **Stack,
126   IN OUT EFI_HII_VALUE       **StackPtr,
127   IN OUT EFI_HII_VALUE       **StackEnd,
128   IN EFI_HII_VALUE           *Data
129   )
130 {
131   EFI_STATUS  Status;
132 
133   //
134   // Check for a stack overflow condition
135   //
136   if (*StackPtr >= *StackEnd) {
137     //
138     // Grow the stack
139     //
140     Status = GrowStack (Stack, StackPtr, StackEnd);
141     if (EFI_ERROR (Status)) {
142       return Status;
143     }
144   }
145 
146   //
147   // Push the item onto the stack
148   //
149   CopyMem (*StackPtr, Data, sizeof (EFI_HII_VALUE));
150   if (Data->Type == EFI_IFR_TYPE_BUFFER) {
151     (*StackPtr)->Buffer = AllocateCopyPool(Data->BufferLen, Data->Buffer);
152     ASSERT ((*StackPtr)->Buffer != NULL);
153   }
154 
155   *StackPtr = *StackPtr + 1;
156 
157   return EFI_SUCCESS;
158 }
159 
160 
161 /**
162   Pop an element from the stack.
163 
164   @param  Stack                  On input: old stack
165   @param  StackPtr               On input: old stack pointer; On output: new stack pointer
166   @param  Data                   Data to pop.
167 
168   @retval EFI_SUCCESS            The value was popped onto the stack.
169   @retval EFI_ACCESS_DENIED      The pop operation underflowed the stack
170 
171 **/
172 EFI_STATUS
PopStack(IN EFI_HII_VALUE * Stack,IN OUT EFI_HII_VALUE ** StackPtr,OUT EFI_HII_VALUE * Data)173 PopStack (
174   IN  EFI_HII_VALUE          *Stack,
175   IN OUT EFI_HII_VALUE       **StackPtr,
176   OUT EFI_HII_VALUE          *Data
177   )
178 {
179   //
180   // Check for a stack underflow condition
181   //
182   if (*StackPtr == Stack) {
183     return EFI_ACCESS_DENIED;
184   }
185 
186   //
187   // Pop the item off the stack
188   //
189   *StackPtr = *StackPtr - 1;
190   CopyMem (Data, *StackPtr, sizeof (EFI_HII_VALUE));
191   return EFI_SUCCESS;
192 }
193 
194 
195 /**
196   Reset stack pointer to begin of the stack.
197 
198 **/
199 VOID
ResetCurrentExpressionStack(VOID)200 ResetCurrentExpressionStack (
201   VOID
202   )
203 {
204   mCurrentExpressionPointer   = mCurrentExpressionStack;
205   mFormExpressionPointer      = mFormExpressionStack;
206   mStatementExpressionPointer = mStatementExpressionStack;
207   mOptionExpressionPointer    = mOptionExpressionStack;
208 }
209 
210 
211 /**
212   Push current expression onto the Stack
213 
214   @param  Pointer                Pointer to current expression.
215 
216   @retval EFI_SUCCESS            The value was pushed onto the stack.
217   @retval EFI_OUT_OF_RESOURCES   There is not enough system memory to grow the stack.
218 
219 **/
220 EFI_STATUS
PushCurrentExpression(IN VOID * Pointer)221 PushCurrentExpression (
222   IN VOID  *Pointer
223   )
224 {
225   EFI_HII_VALUE  Data;
226 
227   Data.Type = EFI_IFR_TYPE_NUM_SIZE_64;
228   Data.Value.u64 = (UINT64) (UINTN) Pointer;
229 
230   return PushStack (
231     &mCurrentExpressionStack,
232     &mCurrentExpressionPointer,
233     &mCurrentExpressionEnd,
234     &Data
235     );
236 }
237 
238 
239 /**
240   Pop current expression from the Stack
241 
242   @param  Pointer                Pointer to current expression to be pop.
243 
244   @retval EFI_SUCCESS            The value was pushed onto the stack.
245   @retval EFI_OUT_OF_RESOURCES   There is not enough system memory to grow the stack.
246 
247 **/
248 EFI_STATUS
PopCurrentExpression(OUT VOID ** Pointer)249 PopCurrentExpression (
250   OUT VOID    **Pointer
251   )
252 {
253   EFI_STATUS     Status;
254   EFI_HII_VALUE  Data;
255 
256   Status = PopStack (
257     mCurrentExpressionStack,
258     &mCurrentExpressionPointer,
259     &Data
260     );
261 
262   *Pointer = (VOID *) (UINTN) Data.Value.u64;
263 
264   return Status;
265 }
266 
267 /**
268   Reset stack pointer to begin of the stack.
269 
270 **/
271 VOID
ResetMapExpressionListStack(VOID)272 ResetMapExpressionListStack (
273   VOID
274   )
275 {
276   mMapExpressionListPointer = mMapExpressionListStack;
277 }
278 
279 
280 /**
281   Grow size of the stack.
282 
283   This is an internal function.
284 
285   @param  Stack                  On input: old stack; On output: new stack
286   @param  StackPtr               On input: old stack pointer; On output: new stack
287                                  pointer
288   @param  StackEnd               On input: old stack end; On output: new stack end
289   @param  MemberSize             The stack member size.
290 
291   @retval EFI_SUCCESS            Grow stack success.
292   @retval EFI_OUT_OF_RESOURCES   No enough memory for stack space.
293 
294 **/
295 EFI_STATUS
GrowConditionalStack(IN OUT FORM_EXPRESSION *** Stack,IN OUT FORM_EXPRESSION *** StackPtr,IN OUT FORM_EXPRESSION *** StackEnd,IN UINTN MemberSize)296 GrowConditionalStack (
297   IN OUT FORM_EXPRESSION   ***Stack,
298   IN OUT FORM_EXPRESSION   ***StackPtr,
299   IN OUT FORM_EXPRESSION   ***StackEnd,
300   IN     UINTN             MemberSize
301   )
302 {
303   UINTN             Size;
304   FORM_EXPRESSION   **NewStack;
305 
306   Size = EXPRESSION_STACK_SIZE_INCREMENT;
307   if (*StackPtr != NULL) {
308     Size = Size + (*StackEnd - *Stack);
309   }
310 
311   NewStack = AllocatePool (Size * MemberSize);
312   if (NewStack == NULL) {
313     return EFI_OUT_OF_RESOURCES;
314   }
315 
316   if (*StackPtr != NULL) {
317     //
318     // Copy from Old Stack to the New Stack
319     //
320     CopyMem (
321       NewStack,
322       *Stack,
323       (*StackEnd - *Stack) * MemberSize
324       );
325 
326     //
327     // Free The Old Stack
328     //
329     FreePool (*Stack);
330   }
331 
332   //
333   // Make the Stack pointer point to the old data in the new stack
334   //
335   *StackPtr = NewStack + (*StackPtr - *Stack);
336   *Stack    = NewStack;
337   *StackEnd = NewStack + Size;
338 
339   return EFI_SUCCESS;
340 }
341 
342 /**
343   Push an element onto the Stack.
344 
345   @param  Stack                  On input: old stack; On output: new stack
346   @param  StackPtr               On input: old stack pointer; On output: new stack
347                                  pointer
348   @param  StackEnd               On input: old stack end; On output: new stack end
349   @param  Data                   Data to push.
350 
351   @retval EFI_SUCCESS            Push stack success.
352 
353 **/
354 EFI_STATUS
PushConditionalStack(IN OUT FORM_EXPRESSION *** Stack,IN OUT FORM_EXPRESSION *** StackPtr,IN OUT FORM_EXPRESSION *** StackEnd,IN FORM_EXPRESSION ** Data)355 PushConditionalStack (
356   IN OUT FORM_EXPRESSION   ***Stack,
357   IN OUT FORM_EXPRESSION   ***StackPtr,
358   IN OUT FORM_EXPRESSION   ***StackEnd,
359   IN     FORM_EXPRESSION   **Data
360   )
361 {
362   EFI_STATUS  Status;
363 
364   //
365   // Check for a stack overflow condition
366   //
367   if (*StackPtr >= *StackEnd) {
368     //
369     // Grow the stack
370     //
371     Status = GrowConditionalStack (Stack, StackPtr, StackEnd, sizeof (FORM_EXPRESSION *));
372     if (EFI_ERROR (Status)) {
373       return Status;
374     }
375   }
376 
377   //
378   // Push the item onto the stack
379   //
380   CopyMem (*StackPtr, Data, sizeof (FORM_EXPRESSION *));
381   *StackPtr = *StackPtr + 1;
382 
383   return EFI_SUCCESS;
384 
385 }
386 
387 /**
388   Pop an element from the stack.
389 
390   @param  Stack                  On input: old stack
391   @param  StackPtr               On input: old stack pointer; On output: new stack pointer
392   @param  Data                   Data to pop.
393 
394   @retval EFI_SUCCESS            The value was popped onto the stack.
395   @retval EFI_ACCESS_DENIED      The pop operation underflowed the stack
396 
397 **/
398 EFI_STATUS
PopConditionalStack(IN FORM_EXPRESSION ** Stack,IN OUT FORM_EXPRESSION *** StackPtr,OUT FORM_EXPRESSION ** Data)399 PopConditionalStack (
400   IN     FORM_EXPRESSION   **Stack,
401   IN OUT FORM_EXPRESSION   ***StackPtr,
402   OUT    FORM_EXPRESSION   **Data
403   )
404 {
405   //
406   // Check for a stack underflow condition
407   //
408   if (*StackPtr == Stack) {
409     return EFI_ACCESS_DENIED;
410   }
411 
412   //
413   // Pop the item off the stack
414   //
415   *StackPtr = *StackPtr - 1;
416   CopyMem (Data, *StackPtr, sizeof (FORM_EXPRESSION  *));
417   return EFI_SUCCESS;
418 
419 }
420 
421 /**
422   Get the expression list count.
423 
424   @param  Level                  Which type this expression belong to. Form,
425                                  statement or option?
426 
427   @retval >=0                    The expression count
428   @retval -1                     Input parameter error.
429 
430 **/
431 INTN
GetConditionalExpressionCount(IN EXPRESS_LEVEL Level)432 GetConditionalExpressionCount (
433   IN EXPRESS_LEVEL       Level
434   )
435 {
436   switch (Level) {
437     case ExpressForm:
438       return mFormExpressionPointer - mFormExpressionStack;
439     case ExpressStatement:
440       return mStatementExpressionPointer - mStatementExpressionStack;
441     case ExpressOption:
442       return mOptionExpressionPointer - mOptionExpressionStack;
443     default:
444       ASSERT (FALSE);
445       return -1;
446   }
447 }
448 
449 /**
450   Get the expression Buffer pointer.
451 
452   @param  Level                  Which type this expression belong to. Form,
453                                  statement or option?
454 
455   @retval  The start pointer of the expression buffer or NULL.
456 
457 **/
458 FORM_EXPRESSION **
GetConditionalExpressionList(IN EXPRESS_LEVEL Level)459 GetConditionalExpressionList (
460   IN EXPRESS_LEVEL       Level
461   )
462 {
463   switch (Level) {
464     case ExpressForm:
465       return mFormExpressionStack;
466     case ExpressStatement:
467       return mStatementExpressionStack;
468     case ExpressOption:
469       return mOptionExpressionStack;
470     default:
471       ASSERT (FALSE);
472       return NULL;
473   }
474 }
475 
476 
477 /**
478   Push the expression options onto the Stack.
479 
480   @param  Pointer                Pointer to the current expression.
481   @param  Level                  Which type this expression belong to. Form,
482                                  statement or option?
483 
484   @retval EFI_SUCCESS            The value was pushed onto the stack.
485   @retval EFI_OUT_OF_RESOURCES   There is not enough system memory to grow the stack.
486 
487 **/
488 EFI_STATUS
PushConditionalExpression(IN FORM_EXPRESSION * Pointer,IN EXPRESS_LEVEL Level)489 PushConditionalExpression (
490   IN FORM_EXPRESSION   *Pointer,
491   IN EXPRESS_LEVEL     Level
492   )
493 {
494   switch (Level) {
495     case ExpressForm:
496       return PushConditionalStack (
497         &mFormExpressionStack,
498         &mFormExpressionPointer,
499         &mFormExpressionEnd,
500         &Pointer
501         );
502     case ExpressStatement:
503       return PushConditionalStack (
504         &mStatementExpressionStack,
505         &mStatementExpressionPointer,
506         &mStatementExpressionEnd,
507         &Pointer
508         );
509     case ExpressOption:
510       return PushConditionalStack (
511         &mOptionExpressionStack,
512         &mOptionExpressionPointer,
513         &mOptionExpressionEnd,
514         &Pointer
515         );
516     default:
517       ASSERT (FALSE);
518       return EFI_INVALID_PARAMETER;
519   }
520 }
521 
522 /**
523   Pop the expression options from the Stack
524 
525   @param  Level                  Which type this expression belong to. Form,
526                                  statement or option?
527 
528   @retval EFI_SUCCESS            The value was pushed onto the stack.
529   @retval EFI_OUT_OF_RESOURCES   There is not enough system memory to grow the stack.
530 
531 **/
532 EFI_STATUS
PopConditionalExpression(IN EXPRESS_LEVEL Level)533 PopConditionalExpression (
534   IN  EXPRESS_LEVEL      Level
535   )
536 {
537   FORM_EXPRESSION   *Pointer;
538 
539   switch (Level) {
540     case ExpressForm:
541       return PopConditionalStack (
542         mFormExpressionStack,
543         &mFormExpressionPointer,
544         &Pointer
545       );
546 
547     case ExpressStatement:
548       return PopConditionalStack (
549         mStatementExpressionStack,
550         &mStatementExpressionPointer,
551         &Pointer
552       );
553 
554     case ExpressOption:
555       return PopConditionalStack (
556         mOptionExpressionStack,
557         &mOptionExpressionPointer,
558         &Pointer
559       );
560 
561     default:
562       ASSERT (FALSE);
563       return EFI_INVALID_PARAMETER;
564   }
565 }
566 
567 
568 /**
569   Push the list of map expression onto the Stack
570 
571   @param  Pointer                Pointer to the list of map expression to be pushed.
572 
573   @retval EFI_SUCCESS            The value was pushed onto the stack.
574   @retval EFI_OUT_OF_RESOURCES   There is not enough system memory to grow the stack.
575 
576 **/
577 EFI_STATUS
PushMapExpressionList(IN VOID * Pointer)578 PushMapExpressionList (
579   IN VOID  *Pointer
580   )
581 {
582   EFI_HII_VALUE  Data;
583 
584   Data.Type = EFI_IFR_TYPE_NUM_SIZE_64;
585   Data.Value.u64 = (UINT64) (UINTN) Pointer;
586 
587   return PushStack (
588     &mMapExpressionListStack,
589     &mMapExpressionListPointer,
590     &mMapExpressionListEnd,
591     &Data
592     );
593 }
594 
595 
596 /**
597   Pop the list of map expression from the Stack
598 
599   @param  Pointer                Pointer to the list of map expression to be pop.
600 
601   @retval EFI_SUCCESS            The value was pushed onto the stack.
602   @retval EFI_OUT_OF_RESOURCES   There is not enough system memory to grow the stack.
603 
604 **/
605 EFI_STATUS
PopMapExpressionList(OUT VOID ** Pointer)606 PopMapExpressionList (
607   OUT VOID    **Pointer
608   )
609 {
610   EFI_STATUS     Status;
611   EFI_HII_VALUE  Data;
612 
613   Status = PopStack (
614     mMapExpressionListStack,
615     &mMapExpressionListPointer,
616     &Data
617     );
618 
619   *Pointer = (VOID *) (UINTN) Data.Value.u64;
620 
621   return Status;
622 }
623 
624 /**
625   Reset stack pointer to begin of the stack.
626 
627 **/
628 VOID
ResetScopeStack(VOID)629 ResetScopeStack (
630   VOID
631   )
632 {
633   mOpCodeScopeStackPointer = mOpCodeScopeStack;
634 }
635 
636 
637 /**
638   Push an Operand onto the Stack
639 
640   @param  Operand                Operand to push.
641 
642   @retval EFI_SUCCESS            The value was pushed onto the stack.
643   @retval EFI_OUT_OF_RESOURCES   There is not enough system memory to grow the
644                                  stack.
645 
646 **/
647 EFI_STATUS
PushScope(IN UINT8 Operand)648 PushScope (
649   IN UINT8   Operand
650   )
651 {
652   EFI_HII_VALUE  Data;
653 
654   Data.Type = EFI_IFR_TYPE_NUM_SIZE_8;
655   Data.Value.u8 = Operand;
656 
657   return PushStack (
658            &mOpCodeScopeStack,
659            &mOpCodeScopeStackPointer,
660            &mOpCodeScopeStackEnd,
661            &Data
662            );
663 }
664 
665 
666 /**
667   Pop an Operand from the Stack
668 
669   @param  Operand                Operand to pop.
670 
671   @retval EFI_SUCCESS            The value was pushed onto the stack.
672   @retval EFI_OUT_OF_RESOURCES   There is not enough system memory to grow the
673                                  stack.
674 
675 **/
676 EFI_STATUS
PopScope(OUT UINT8 * Operand)677 PopScope (
678   OUT UINT8     *Operand
679   )
680 {
681   EFI_STATUS     Status;
682   EFI_HII_VALUE  Data;
683 
684   Status = PopStack (
685              mOpCodeScopeStack,
686              &mOpCodeScopeStackPointer,
687              &Data
688              );
689 
690   *Operand = Data.Value.u8;
691 
692   return Status;
693 }
694 
695 
696 /**
697   Push an Expression value onto the Stack
698 
699   @param  Value                  Expression value to push.
700 
701   @retval EFI_SUCCESS            The value was pushed onto the stack.
702   @retval EFI_OUT_OF_RESOURCES   There is not enough system memory to grow the
703                                  stack.
704 
705 **/
706 EFI_STATUS
PushExpression(IN EFI_HII_VALUE * Value)707 PushExpression (
708   IN EFI_HII_VALUE  *Value
709   )
710 {
711   return PushStack (
712            &mExpressionEvaluationStack,
713            &mExpressionEvaluationStackPointer,
714            &mExpressionEvaluationStackEnd,
715            Value
716            );
717 }
718 
719 
720 /**
721   Pop an Expression value from the stack.
722 
723   @param  Value                  Expression value to pop.
724 
725   @retval EFI_SUCCESS            The value was popped onto the stack.
726   @retval EFI_ACCESS_DENIED      The pop operation underflowed the stack
727 
728 **/
729 EFI_STATUS
PopExpression(OUT EFI_HII_VALUE * Value)730 PopExpression (
731   OUT EFI_HII_VALUE  *Value
732   )
733 {
734   return PopStack (
735            mExpressionEvaluationStack + mExpressionEvaluationStackOffset,
736            &mExpressionEvaluationStackPointer,
737            Value
738            );
739 }
740 
741 /**
742   Get current stack offset from stack start.
743 
744   @return Stack offset to stack start.
745 **/
746 UINTN
SaveExpressionEvaluationStackOffset(VOID)747 SaveExpressionEvaluationStackOffset (
748   VOID
749   )
750 {
751   UINTN TempStackOffset;
752   TempStackOffset = mExpressionEvaluationStackOffset;
753   mExpressionEvaluationStackOffset = mExpressionEvaluationStackPointer - mExpressionEvaluationStack;
754   return TempStackOffset;
755 }
756 
757 /**
758   Restore stack offset based on input stack offset
759 
760   @param  StackOffset  Offset to stack start.
761 
762 **/
763 VOID
RestoreExpressionEvaluationStackOffset(UINTN StackOffset)764 RestoreExpressionEvaluationStackOffset (
765   UINTN StackOffset
766   )
767 {
768   mExpressionEvaluationStackOffset = StackOffset;
769 }
770 
771 /**
772   Get Form given its FormId.
773 
774   @param  FormSet                The formset which contains this form.
775   @param  FormId                 Id of this form.
776 
777   @retval Pointer                The form.
778   @retval NULL                   Specified Form is not found in the formset.
779 
780 **/
781 FORM_BROWSER_FORM *
IdToForm(IN FORM_BROWSER_FORMSET * FormSet,IN UINT16 FormId)782 IdToForm (
783   IN FORM_BROWSER_FORMSET  *FormSet,
784   IN UINT16                FormId
785   )
786 {
787   LIST_ENTRY         *Link;
788   FORM_BROWSER_FORM  *Form;
789 
790   Link = GetFirstNode (&FormSet->FormListHead);
791   while (!IsNull (&FormSet->FormListHead, Link)) {
792     Form = FORM_BROWSER_FORM_FROM_LINK (Link);
793 
794     if (Form->FormId == FormId) {
795       return Form;
796     }
797 
798     Link = GetNextNode (&FormSet->FormListHead, Link);
799   }
800 
801   return NULL;
802 }
803 
804 
805 /**
806   Search a Question in Form scope using its QuestionId.
807 
808   @param  Form                   The form which contains this Question.
809   @param  QuestionId             Id of this Question.
810 
811   @retval Pointer                The Question.
812   @retval NULL                   Specified Question not found in the form.
813 
814 **/
815 FORM_BROWSER_STATEMENT *
IdToQuestion2(IN FORM_BROWSER_FORM * Form,IN UINT16 QuestionId)816 IdToQuestion2 (
817   IN FORM_BROWSER_FORM  *Form,
818   IN UINT16             QuestionId
819   )
820 {
821   LIST_ENTRY              *Link;
822   FORM_BROWSER_STATEMENT  *Question;
823 
824   if (QuestionId == 0 || Form == NULL) {
825     //
826     // The value of zero is reserved
827     //
828     return NULL;
829   }
830 
831   Link = GetFirstNode (&Form->StatementListHead);
832   while (!IsNull (&Form->StatementListHead, Link)) {
833     Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link);
834 
835     if (Question->QuestionId == QuestionId) {
836       return Question;
837     }
838 
839     Link = GetNextNode (&Form->StatementListHead, Link);
840   }
841 
842   return NULL;
843 }
844 
845 
846 /**
847   Search a Question in Formset scope using its QuestionId.
848 
849   @param  FormSet                The formset which contains this form.
850   @param  Form                   The form which contains this Question.
851   @param  QuestionId             Id of this Question.
852 
853   @retval Pointer                The Question.
854   @retval NULL                   Specified Question not found in the form.
855 
856 **/
857 FORM_BROWSER_STATEMENT *
IdToQuestion(IN FORM_BROWSER_FORMSET * FormSet,IN FORM_BROWSER_FORM * Form,IN UINT16 QuestionId)858 IdToQuestion (
859   IN FORM_BROWSER_FORMSET  *FormSet,
860   IN FORM_BROWSER_FORM     *Form,
861   IN UINT16                QuestionId
862   )
863 {
864   LIST_ENTRY              *Link;
865   FORM_BROWSER_STATEMENT  *Question;
866 
867   //
868   // Search in the form scope first
869   //
870   Question = IdToQuestion2 (Form, QuestionId);
871   if (Question != NULL) {
872     return Question;
873   }
874 
875   //
876   // Search in the formset scope
877   //
878   Link = GetFirstNode (&FormSet->FormListHead);
879   while (!IsNull (&FormSet->FormListHead, Link)) {
880     Form = FORM_BROWSER_FORM_FROM_LINK (Link);
881 
882     Question = IdToQuestion2 (Form, QuestionId);
883     if (Question != NULL) {
884       //
885       // EFI variable storage may be updated by Callback() asynchronous,
886       // to keep synchronous, always reload the Question Value.
887       //
888       if (Question->Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) {
889         GetQuestionValue (FormSet, Form, Question, GetSetValueWithHiiDriver);
890       }
891 
892       return Question;
893     }
894 
895     Link = GetNextNode (&FormSet->FormListHead, Link);
896   }
897 
898   return NULL;
899 }
900 
901 
902 /**
903   Get Expression given its RuleId.
904 
905   @param  Form                   The form which contains this Expression.
906   @param  RuleId                 Id of this Expression.
907 
908   @retval Pointer                The Expression.
909   @retval NULL                   Specified Expression not found in the form.
910 
911 **/
912 FORM_EXPRESSION *
RuleIdToExpression(IN FORM_BROWSER_FORM * Form,IN UINT8 RuleId)913 RuleIdToExpression (
914   IN FORM_BROWSER_FORM  *Form,
915   IN UINT8              RuleId
916   )
917 {
918   LIST_ENTRY       *Link;
919   FORM_EXPRESSION  *Expression;
920 
921   Link = GetFirstNode (&Form->ExpressionListHead);
922   while (!IsNull (&Form->ExpressionListHead, Link)) {
923     Expression = FORM_EXPRESSION_FROM_LINK (Link);
924 
925     if (Expression->Type == EFI_HII_EXPRESSION_RULE && Expression->RuleId == RuleId) {
926       return Expression;
927     }
928 
929     Link = GetNextNode (&Form->ExpressionListHead, Link);
930   }
931 
932   return NULL;
933 }
934 
935 
936 /**
937   Locate the Unicode Collation Protocol interface for later use.
938 
939   @retval EFI_SUCCESS            Protocol interface initialize success.
940   @retval Other                  Protocol interface initialize failed.
941 
942 **/
943 EFI_STATUS
InitializeUnicodeCollationProtocol(VOID)944 InitializeUnicodeCollationProtocol (
945   VOID
946   )
947 {
948   EFI_STATUS  Status;
949 
950   if (mUnicodeCollation != NULL) {
951     return EFI_SUCCESS;
952   }
953 
954   //
955   // BUGBUG: Proper impelmentation is to locate all Unicode Collation Protocol
956   // instances first and then select one which support English language.
957   // Current implementation just pick the first instance.
958   //
959   Status = gBS->LocateProtocol (
960                   &gEfiUnicodeCollation2ProtocolGuid,
961                   NULL,
962                   (VOID **) &mUnicodeCollation
963                   );
964   return Status;
965 }
966 
967 /**
968   Convert the input Unicode character to upper.
969 
970   @param String  Th Unicode character to be converted.
971 
972 **/
973 VOID
IfrStrToUpper(IN CHAR16 * String)974 IfrStrToUpper (
975   IN CHAR16                   *String
976   )
977 {
978   while (*String != 0) {
979     if ((*String >= 'a') && (*String <= 'z')) {
980       *String = (UINT16) ((*String) & ((UINT16) ~0x20));
981     }
982     String++;
983   }
984 }
985 
986 /**
987   Check whether this value type can be transfer to EFI_IFR_TYPE_BUFFER type.
988 
989   EFI_IFR_TYPE_REF, EFI_IFR_TYPE_DATE and EFI_IFR_TYPE_TIME are converted to
990   EFI_IFR_TYPE_BUFFER when do the value compare.
991 
992   @param  Value                  Expression value to compare on.
993 
994   @retval TRUE                   This value type can be transter to EFI_IFR_TYPE_BUFFER type.
995   @retval FALSE                  This value type can't be transter to EFI_IFR_TYPE_BUFFER type.
996 
997 **/
998 BOOLEAN
IsTypeInBuffer(IN EFI_HII_VALUE * Value)999 IsTypeInBuffer (
1000   IN  EFI_HII_VALUE   *Value
1001   )
1002 {
1003   switch (Value->Type) {
1004   case EFI_IFR_TYPE_BUFFER:
1005   case EFI_IFR_TYPE_DATE:
1006   case EFI_IFR_TYPE_TIME:
1007   case EFI_IFR_TYPE_REF:
1008     return TRUE;
1009 
1010   default:
1011     return FALSE;
1012   }
1013 }
1014 
1015 /**
1016   Check whether this value type can be transfer to EFI_IFR_TYPE_UINT64
1017 
1018   @param  Value                  Expression value to compare on.
1019 
1020   @retval TRUE                   This value type can be transter to EFI_IFR_TYPE_BUFFER type.
1021   @retval FALSE                  This value type can't be transter to EFI_IFR_TYPE_BUFFER type.
1022 
1023 **/
1024 BOOLEAN
IsTypeInUINT64(IN EFI_HII_VALUE * Value)1025 IsTypeInUINT64 (
1026   IN  EFI_HII_VALUE   *Value
1027   )
1028 {
1029   switch (Value->Type) {
1030   case EFI_IFR_TYPE_NUM_SIZE_8:
1031   case EFI_IFR_TYPE_NUM_SIZE_16:
1032   case EFI_IFR_TYPE_NUM_SIZE_32:
1033   case EFI_IFR_TYPE_NUM_SIZE_64:
1034   case EFI_IFR_TYPE_BOOLEAN:
1035     return TRUE;
1036 
1037   default:
1038     return FALSE;
1039   }
1040 }
1041 
1042 /**
1043   Return the buffer length for this value.
1044 
1045   EFI_IFR_TYPE_REF, EFI_IFR_TYPE_DATE and EFI_IFR_TYPE_TIME are converted to
1046   EFI_IFR_TYPE_BUFFER when do the value compare.
1047 
1048   @param   Value                  Expression value to compare on.
1049 
1050   @retval  BufLen                 Return the buffer length.
1051 
1052 **/
1053 UINT16
GetLengthForValue(IN EFI_HII_VALUE * Value)1054 GetLengthForValue (
1055   IN  EFI_HII_VALUE   *Value
1056   )
1057 {
1058   switch (Value->Type) {
1059   case EFI_IFR_TYPE_BUFFER:
1060     return Value->BufferLen;
1061 
1062   case EFI_IFR_TYPE_DATE:
1063     return (UINT16) sizeof (EFI_HII_DATE);
1064 
1065   case EFI_IFR_TYPE_TIME:
1066     return (UINT16) sizeof (EFI_HII_TIME);
1067 
1068   case EFI_IFR_TYPE_REF:
1069     return (UINT16) sizeof (EFI_HII_REF);
1070 
1071   default:
1072     return 0;
1073   }
1074 }
1075 
1076 /**
1077   Return the buffer pointer for this value.
1078 
1079   EFI_IFR_TYPE_REF, EFI_IFR_TYPE_DATE and EFI_IFR_TYPE_TIME are converted to
1080   EFI_IFR_TYPE_BUFFER when do the value compare.
1081 
1082   @param  Value                  Expression value to compare on.
1083 
1084   @retval Buf                    Return the buffer pointer.
1085 
1086 **/
1087 UINT8 *
GetBufferForValue(IN EFI_HII_VALUE * Value)1088 GetBufferForValue (
1089   IN  EFI_HII_VALUE   *Value
1090   )
1091 {
1092   switch (Value->Type) {
1093   case EFI_IFR_TYPE_BUFFER:
1094     return Value->Buffer;
1095 
1096   case EFI_IFR_TYPE_DATE:
1097     return (UINT8 *) (&Value->Value.date);
1098 
1099   case EFI_IFR_TYPE_TIME:
1100     return (UINT8 *) (&Value->Value.time);
1101 
1102   case EFI_IFR_TYPE_REF:
1103     return (UINT8 *) (&Value->Value.ref);
1104 
1105   default:
1106     return NULL;
1107   }
1108 }
1109 
1110 /**
1111   Evaluate opcode EFI_IFR_TO_STRING.
1112 
1113   @param  FormSet                Formset which contains this opcode.
1114   @param  Format                 String format in EFI_IFR_TO_STRING.
1115   @param  Result                 Evaluation result for this opcode.
1116 
1117   @retval EFI_SUCCESS            Opcode evaluation success.
1118   @retval Other                  Opcode evaluation failed.
1119 
1120 **/
1121 EFI_STATUS
IfrToString(IN FORM_BROWSER_FORMSET * FormSet,IN UINT8 Format,OUT EFI_HII_VALUE * Result)1122 IfrToString (
1123   IN FORM_BROWSER_FORMSET  *FormSet,
1124   IN UINT8                 Format,
1125   OUT  EFI_HII_VALUE       *Result
1126   )
1127 {
1128   EFI_STATUS     Status;
1129   EFI_HII_VALUE  Value;
1130   CHAR16         *String;
1131   CHAR16         *PrintFormat;
1132   CHAR16         Buffer[MAXIMUM_VALUE_CHARACTERS];
1133   UINT8          *TmpBuf;
1134   UINT8          *SrcBuf;
1135   UINTN          SrcLen;
1136   UINTN          BufferSize;
1137 
1138   Status = PopExpression (&Value);
1139   if (EFI_ERROR (Status)) {
1140     return Status;
1141   }
1142 
1143   switch (Value.Type) {
1144   case EFI_IFR_TYPE_NUM_SIZE_8:
1145   case EFI_IFR_TYPE_NUM_SIZE_16:
1146   case EFI_IFR_TYPE_NUM_SIZE_32:
1147   case EFI_IFR_TYPE_NUM_SIZE_64:
1148     BufferSize = MAXIMUM_VALUE_CHARACTERS * sizeof (CHAR16);
1149     switch (Format) {
1150     case EFI_IFR_STRING_UNSIGNED_DEC:
1151     case EFI_IFR_STRING_SIGNED_DEC:
1152       PrintFormat = L"%ld";
1153       break;
1154 
1155     case EFI_IFR_STRING_LOWERCASE_HEX:
1156       PrintFormat = L"%lx";
1157       break;
1158 
1159     case EFI_IFR_STRING_UPPERCASE_HEX:
1160       PrintFormat = L"%lX";
1161       break;
1162 
1163     default:
1164       Result->Type = EFI_IFR_TYPE_UNDEFINED;
1165       return EFI_SUCCESS;
1166     }
1167     UnicodeSPrint (Buffer, BufferSize, PrintFormat, Value.Value.u64);
1168     String = Buffer;
1169     break;
1170 
1171   case EFI_IFR_TYPE_STRING:
1172     CopyMem (Result, &Value, sizeof (EFI_HII_VALUE));
1173     return EFI_SUCCESS;
1174 
1175   case EFI_IFR_TYPE_BOOLEAN:
1176     String = (Value.Value.b) ? L"True" : L"False";
1177     break;
1178 
1179   case EFI_IFR_TYPE_BUFFER:
1180   case EFI_IFR_TYPE_DATE:
1181   case EFI_IFR_TYPE_TIME:
1182   case EFI_IFR_TYPE_REF:
1183     //
1184     // + 3 is base on the unicode format, the length may be odd number,
1185     // so need 1 byte to align, also need 2 bytes for L'\0'.
1186     //
1187     if (Value.Type == EFI_IFR_TYPE_BUFFER) {
1188       SrcLen = Value.BufferLen;
1189       SrcBuf = Value.Buffer;
1190     } else {
1191       SrcBuf = GetBufferForValue(&Value);
1192       SrcLen = GetLengthForValue(&Value);
1193     }
1194 
1195     TmpBuf = AllocateZeroPool (SrcLen + 3);
1196     ASSERT (TmpBuf != NULL);
1197     if (Format == EFI_IFR_STRING_ASCII) {
1198       CopyMem (TmpBuf, SrcBuf, SrcLen);
1199       PrintFormat = L"%a";
1200     } else {
1201       // Format == EFI_IFR_STRING_UNICODE
1202       CopyMem (TmpBuf, SrcBuf, SrcLen * sizeof (CHAR16));
1203       PrintFormat = L"%s";
1204     }
1205     UnicodeSPrint (Buffer, sizeof (Buffer), PrintFormat, TmpBuf);
1206     String = Buffer;
1207     FreePool (TmpBuf);
1208     if (Value.Type == EFI_IFR_TYPE_BUFFER) {
1209       FreePool (Value.Buffer);
1210     }
1211     break;
1212 
1213   default:
1214     Result->Type = EFI_IFR_TYPE_UNDEFINED;
1215     return EFI_SUCCESS;
1216   }
1217 
1218   Result->Type = EFI_IFR_TYPE_STRING;
1219   Result->Value.string = NewString (String, FormSet->HiiHandle);
1220   return EFI_SUCCESS;
1221 }
1222 
1223 
1224 /**
1225   Evaluate opcode EFI_IFR_TO_UINT.
1226 
1227   @param  FormSet                Formset which contains this opcode.
1228   @param  Result                 Evaluation result for this opcode.
1229 
1230   @retval EFI_SUCCESS            Opcode evaluation success.
1231   @retval Other                  Opcode evaluation failed.
1232 
1233 **/
1234 EFI_STATUS
IfrToUint(IN FORM_BROWSER_FORMSET * FormSet,OUT EFI_HII_VALUE * Result)1235 IfrToUint (
1236   IN FORM_BROWSER_FORMSET  *FormSet,
1237   OUT  EFI_HII_VALUE       *Result
1238   )
1239 {
1240   EFI_STATUS     Status;
1241   EFI_HII_VALUE  Value;
1242   CHAR16         *String;
1243   CHAR16         *StringPtr;
1244 
1245   Status = PopExpression (&Value);
1246   if (EFI_ERROR (Status)) {
1247     return Status;
1248   }
1249 
1250   if (Value.Type >= EFI_IFR_TYPE_OTHER && !IsTypeInBuffer(&Value)) {
1251     Result->Type = EFI_IFR_TYPE_UNDEFINED;
1252     return EFI_SUCCESS;
1253   }
1254 
1255   Status = EFI_SUCCESS;
1256   if (Value.Type == EFI_IFR_TYPE_STRING) {
1257     String = GetToken (Value.Value.string, FormSet->HiiHandle);
1258     if (String == NULL) {
1259       return EFI_NOT_FOUND;
1260     }
1261 
1262     IfrStrToUpper (String);
1263     StringPtr = StrStr (String, L"0X");
1264     if (StringPtr != NULL) {
1265       //
1266       // Hex string
1267       //
1268       Result->Value.u64 = StrHexToUint64 (String);
1269     } else {
1270       //
1271       // decimal string
1272       //
1273       Result->Value.u64 = StrDecimalToUint64 (String);
1274     }
1275     FreePool (String);
1276   } else if (IsTypeInBuffer(&Value)) {
1277     if (GetLengthForValue (&Value) > 8) {
1278       if (Value.Type == EFI_IFR_TYPE_BUFFER) {
1279         FreePool (Value.Buffer);
1280       }
1281       Result->Type = EFI_IFR_TYPE_UNDEFINED;
1282       return EFI_SUCCESS;
1283     }
1284 
1285     ASSERT (GetBufferForValue (&Value) != NULL);
1286     Result->Value.u64 = *(UINT64*) GetBufferForValue (&Value);
1287 
1288     if (Value.Type == EFI_IFR_TYPE_BUFFER) {
1289       FreePool (Value.Buffer);
1290     }
1291   } else {
1292     CopyMem (Result, &Value, sizeof (EFI_HII_VALUE));
1293   }
1294 
1295   Result->Type = EFI_IFR_TYPE_NUM_SIZE_64;
1296   return Status;
1297 }
1298 
1299 
1300 /**
1301   Evaluate opcode EFI_IFR_CATENATE.
1302 
1303   @param  FormSet                Formset which contains this opcode.
1304   @param  Result                 Evaluation result for this opcode.
1305 
1306   @retval EFI_SUCCESS            Opcode evaluation success.
1307   @retval Other                  Opcode evaluation failed.
1308 
1309 **/
1310 EFI_STATUS
IfrCatenate(IN FORM_BROWSER_FORMSET * FormSet,OUT EFI_HII_VALUE * Result)1311 IfrCatenate (
1312   IN FORM_BROWSER_FORMSET  *FormSet,
1313   OUT  EFI_HII_VALUE       *Result
1314   )
1315 {
1316   EFI_STATUS     Status;
1317   EFI_HII_VALUE  Value[2];
1318   CHAR16         *String[2];
1319   UINTN          Index;
1320   CHAR16         *StringPtr;
1321   UINTN          Size;
1322   UINT16         Length0;
1323   UINT16         Length1;
1324   UINT8          *TmpBuf;
1325   UINTN          MaxLen;
1326 
1327   //
1328   // String[0] - The second string
1329   // String[1] - The first string
1330   //
1331   String[0] = NULL;
1332   String[1] = NULL;
1333   StringPtr = NULL;
1334   Status = EFI_SUCCESS;
1335   ZeroMem (Value, sizeof (Value));
1336 
1337   Status = PopExpression (&Value[0]);
1338   if (EFI_ERROR (Status)) {
1339     goto Done;
1340   }
1341 
1342   Status = PopExpression (&Value[1]);
1343   if (EFI_ERROR (Status)) {
1344     goto Done;
1345   }
1346 
1347   for (Index = 0; Index < 2; Index++) {
1348     if (Value[Index].Type != EFI_IFR_TYPE_STRING && !IsTypeInBuffer(&Value[Index])) {
1349       Result->Type = EFI_IFR_TYPE_UNDEFINED;
1350       Status = EFI_SUCCESS;
1351       goto Done;
1352     }
1353 
1354     if (Value[Index].Type == EFI_IFR_TYPE_STRING) {
1355       String[Index] = GetToken (Value[Index].Value.string, FormSet->HiiHandle);
1356       if (String[Index] == NULL) {
1357         Status = EFI_NOT_FOUND;
1358         goto Done;
1359       }
1360     }
1361   }
1362 
1363   if (Value[0].Type == EFI_IFR_TYPE_STRING) {
1364     Size = StrSize (String[0]);
1365     MaxLen = (StrSize (String[1]) + Size) / sizeof (CHAR16);
1366     StringPtr= AllocatePool (MaxLen * sizeof (CHAR16));
1367     ASSERT (StringPtr != NULL);
1368     StrCpyS (StringPtr, MaxLen, String[1]);
1369     StrCatS (StringPtr, MaxLen, String[0]);
1370 
1371     Result->Type = EFI_IFR_TYPE_STRING;
1372     Result->Value.string = NewString (StringPtr, FormSet->HiiHandle);
1373   } else {
1374     Result->Type = EFI_IFR_TYPE_BUFFER;
1375     Length0 = GetLengthForValue(&Value[0]);
1376     Length1 = GetLengthForValue(&Value[1]);
1377     Result->BufferLen = (UINT16) (Length0 + Length1);
1378 
1379     Result->Buffer = AllocateZeroPool (Result->BufferLen);
1380     ASSERT (Result->Buffer != NULL);
1381 
1382     TmpBuf = GetBufferForValue(&Value[0]);
1383     ASSERT (TmpBuf != NULL);
1384     CopyMem (Result->Buffer, TmpBuf, Length0);
1385     TmpBuf = GetBufferForValue(&Value[1]);
1386     ASSERT (TmpBuf != NULL);
1387     CopyMem (&Result->Buffer[Length0], TmpBuf, Length1);
1388   }
1389 Done:
1390   if (Value[0].Buffer != NULL) {
1391     FreePool (Value[0].Buffer);
1392   }
1393   if (Value[1].Buffer != NULL) {
1394     FreePool (Value[1].Buffer);
1395   }
1396   if (String[0] != NULL) {
1397     FreePool (String[0]);
1398   }
1399   if (String[1] != NULL) {
1400     FreePool (String[1]);
1401   }
1402   if (StringPtr != NULL) {
1403     FreePool (StringPtr);
1404   }
1405 
1406   return Status;
1407 }
1408 
1409 
1410 /**
1411   Evaluate opcode EFI_IFR_MATCH.
1412 
1413   @param  FormSet                Formset which contains this opcode.
1414   @param  Result                 Evaluation result for this opcode.
1415 
1416   @retval EFI_SUCCESS            Opcode evaluation success.
1417   @retval Other                  Opcode evaluation failed.
1418 
1419 **/
1420 EFI_STATUS
IfrMatch(IN FORM_BROWSER_FORMSET * FormSet,OUT EFI_HII_VALUE * Result)1421 IfrMatch (
1422   IN FORM_BROWSER_FORMSET  *FormSet,
1423   OUT  EFI_HII_VALUE       *Result
1424   )
1425 {
1426   EFI_STATUS     Status;
1427   EFI_HII_VALUE  Value[2];
1428   CHAR16         *String[2];
1429   UINTN          Index;
1430 
1431   //
1432   // String[0] - The string to search
1433   // String[1] - pattern
1434   //
1435   String[0] = NULL;
1436   String[1] = NULL;
1437   Status = EFI_SUCCESS;
1438   ZeroMem (Value, sizeof (Value));
1439 
1440   Status = PopExpression (&Value[0]);
1441   if (EFI_ERROR (Status)) {
1442     goto Done;
1443   }
1444 
1445   Status = PopExpression (&Value[1]);
1446   if (EFI_ERROR (Status)) {
1447     goto Done;
1448   }
1449 
1450   for (Index = 0; Index < 2; Index++) {
1451     if (Value[Index].Type != EFI_IFR_TYPE_STRING) {
1452       Result->Type = EFI_IFR_TYPE_UNDEFINED;
1453       Status = EFI_SUCCESS;
1454       goto Done;
1455     }
1456 
1457     String[Index] = GetToken (Value[Index].Value.string, FormSet->HiiHandle);
1458     if (String [Index] == NULL) {
1459       Status = EFI_NOT_FOUND;
1460       goto Done;
1461     }
1462   }
1463 
1464   Result->Type = EFI_IFR_TYPE_BOOLEAN;
1465   Result->Value.b = mUnicodeCollation->MetaiMatch (mUnicodeCollation, String[0], String[1]);
1466 
1467 Done:
1468   if (String[0] != NULL) {
1469     FreePool (String[0]);
1470   }
1471   if (String[1] != NULL) {
1472     FreePool (String[1]);
1473   }
1474 
1475   return Status;
1476 }
1477 
1478 /**
1479   Evaluate opcode EFI_IFR_MATCH2.
1480 
1481   @param  FormSet                Formset which contains this opcode.
1482   @param  SyntaxType             Syntax type for match2.
1483   @param  Result                 Evaluation result for this opcode.
1484 
1485   @retval EFI_SUCCESS            Opcode evaluation success.
1486   @retval Other                  Opcode evaluation failed.
1487 
1488 **/
1489 EFI_STATUS
IfrMatch2(IN FORM_BROWSER_FORMSET * FormSet,IN EFI_GUID * SyntaxType,OUT EFI_HII_VALUE * Result)1490 IfrMatch2 (
1491   IN FORM_BROWSER_FORMSET  *FormSet,
1492   IN EFI_GUID              *SyntaxType,
1493   OUT  EFI_HII_VALUE       *Result
1494   )
1495 {
1496   EFI_STATUS                       Status;
1497   EFI_HII_VALUE                    Value[2];
1498   CHAR16                           *String[2];
1499   UINTN                            Index;
1500   UINTN                            GuidIndex;
1501   EFI_HANDLE                       *HandleBuffer;
1502   UINTN                            BufferSize;
1503   EFI_REGULAR_EXPRESSION_PROTOCOL  *RegularExpressionProtocol;
1504   UINTN                            RegExSyntaxTypeListSize;
1505   EFI_REGEX_SYNTAX_TYPE            *RegExSyntaxTypeList;
1506   UINTN                            CapturesCount;
1507 
1508   //
1509   // String[0] - The string to search
1510   // String[1] - pattern
1511   //
1512   String[0] = NULL;
1513   String[1] = NULL;
1514   HandleBuffer = NULL;
1515   RegExSyntaxTypeList = NULL;
1516   Status = EFI_SUCCESS;
1517   ZeroMem (Value, sizeof (Value));
1518 
1519   Status = PopExpression (&Value[0]);
1520   if (EFI_ERROR (Status)) {
1521     goto Done;
1522   }
1523 
1524   Status = PopExpression (&Value[1]);
1525   if (EFI_ERROR (Status)) {
1526     goto Done;
1527   }
1528 
1529   for (Index = 0; Index < 2; Index++) {
1530     if (Value[Index].Type != EFI_IFR_TYPE_STRING) {
1531       Result->Type = EFI_IFR_TYPE_UNDEFINED;
1532       Status = EFI_SUCCESS;
1533       goto Done;
1534     }
1535 
1536     String[Index] = GetToken (Value[Index].Value.string, FormSet->HiiHandle);
1537     if (String [Index] == NULL) {
1538       Status = EFI_NOT_FOUND;
1539       goto Done;
1540     }
1541   }
1542 
1543   BufferSize    = 0;
1544   HandleBuffer  = NULL;
1545   Status = gBS->LocateHandle(
1546                       ByProtocol,
1547                       &gEfiRegularExpressionProtocolGuid,
1548                       NULL,
1549                       &BufferSize,
1550                       HandleBuffer);
1551   if (Status == EFI_BUFFER_TOO_SMALL) {
1552     HandleBuffer = AllocateZeroPool(BufferSize);
1553     if (HandleBuffer == NULL) {
1554       Status = EFI_OUT_OF_RESOURCES;
1555       goto Done;
1556     }
1557     Status = gBS->LocateHandle(
1558                         ByProtocol,
1559                         &gEfiRegularExpressionProtocolGuid,
1560                         NULL,
1561                         &BufferSize,
1562                         HandleBuffer);
1563 
1564   }
1565 
1566   if (EFI_ERROR (Status)) {
1567     Result->Type = EFI_IFR_TYPE_UNDEFINED;
1568     Status = EFI_SUCCESS;
1569     goto Done;
1570   }
1571 
1572   ASSERT (HandleBuffer != NULL);
1573   for ( Index = 0; Index < BufferSize / sizeof(EFI_HANDLE); Index ++) {
1574     Status = gBS->HandleProtocol (
1575                   HandleBuffer[Index],
1576                   &gEfiRegularExpressionProtocolGuid,
1577                   (VOID**)&RegularExpressionProtocol
1578                  );
1579     if (EFI_ERROR (Status)) {
1580       goto Done;
1581     }
1582 
1583     RegExSyntaxTypeListSize = 0;
1584     RegExSyntaxTypeList = NULL;
1585 
1586     Status = RegularExpressionProtocol->GetInfo (
1587                                           RegularExpressionProtocol,
1588                                           &RegExSyntaxTypeListSize,
1589                                           RegExSyntaxTypeList
1590                                           );
1591     if (Status == EFI_BUFFER_TOO_SMALL) {
1592       RegExSyntaxTypeList = AllocateZeroPool(RegExSyntaxTypeListSize);
1593       if (RegExSyntaxTypeList == NULL) {
1594         Status = EFI_OUT_OF_RESOURCES;
1595         goto Done;
1596       }
1597       Status = RegularExpressionProtocol->GetInfo (
1598                                             RegularExpressionProtocol,
1599                                             &RegExSyntaxTypeListSize,
1600                                             RegExSyntaxTypeList
1601                                             );
1602     } else if (EFI_ERROR (Status)) {
1603       goto Done;
1604     }
1605 
1606     for (GuidIndex = 0; GuidIndex < RegExSyntaxTypeListSize / sizeof(EFI_GUID); GuidIndex++) {
1607       if (CompareGuid (&RegExSyntaxTypeList[GuidIndex], SyntaxType)) {
1608         //
1609         // Find the match type, return the value.
1610         //
1611         Result->Type = EFI_IFR_TYPE_BOOLEAN;
1612         Status = RegularExpressionProtocol->MatchString (
1613                                               RegularExpressionProtocol,
1614                                               String[0],
1615                                               String[1],
1616                                               SyntaxType,
1617                                               &Result->Value.b,
1618                                               NULL,
1619                                               &CapturesCount
1620                                               );
1621         goto Done;
1622       }
1623     }
1624 
1625     if (RegExSyntaxTypeList != NULL) {
1626       FreePool (RegExSyntaxTypeList);
1627     }
1628   }
1629 
1630   //
1631   // Type specified by SyntaxType is not supported
1632   // in any of the EFI_REGULAR_EXPRESSION_PROTOCOL instances.
1633   //
1634   Result->Type = EFI_IFR_TYPE_UNDEFINED;
1635   Status = EFI_SUCCESS;
1636 
1637 Done:
1638   if (String[0] != NULL) {
1639     FreePool (String[0]);
1640   }
1641   if (String[1] != NULL) {
1642     FreePool (String[1]);
1643   }
1644   if (RegExSyntaxTypeList != NULL) {
1645     FreePool (RegExSyntaxTypeList);
1646   }
1647   if (HandleBuffer != NULL) {
1648     FreePool (HandleBuffer);
1649   }
1650   return Status;
1651 }
1652 
1653 /**
1654   Evaluate opcode EFI_IFR_FIND.
1655 
1656   @param  FormSet                Formset which contains this opcode.
1657   @param  Format                 Case sensitive or insensitive.
1658   @param  Result                 Evaluation result for this opcode.
1659 
1660   @retval EFI_SUCCESS            Opcode evaluation success.
1661   @retval Other                  Opcode evaluation failed.
1662 
1663 **/
1664 EFI_STATUS
IfrFind(IN FORM_BROWSER_FORMSET * FormSet,IN UINT8 Format,OUT EFI_HII_VALUE * Result)1665 IfrFind (
1666   IN FORM_BROWSER_FORMSET  *FormSet,
1667   IN UINT8                 Format,
1668   OUT  EFI_HII_VALUE       *Result
1669   )
1670 {
1671   EFI_STATUS     Status;
1672   EFI_HII_VALUE  Value[3];
1673   CHAR16         *String[2];
1674   UINTN          Base;
1675   CHAR16         *StringPtr;
1676   UINTN          Index;
1677 
1678   ZeroMem (Value, sizeof (Value));
1679 
1680   if (Format > EFI_IFR_FF_CASE_INSENSITIVE) {
1681     return EFI_INVALID_PARAMETER;
1682   }
1683 
1684   Status = PopExpression (&Value[0]);
1685   if (EFI_ERROR (Status)) {
1686     return Status;
1687   }
1688 
1689   Status = PopExpression (&Value[1]);
1690   if (EFI_ERROR (Status)) {
1691     return Status;
1692   }
1693 
1694   Status = PopExpression (&Value[2]);
1695   if (EFI_ERROR (Status)) {
1696     return Status;
1697   }
1698 
1699   if (Value[0].Type > EFI_IFR_TYPE_NUM_SIZE_64) {
1700     Result->Type = EFI_IFR_TYPE_UNDEFINED;
1701     return EFI_SUCCESS;
1702   }
1703   Base = (UINTN) Value[0].Value.u64;
1704 
1705   //
1706   // String[0] - sub-string
1707   // String[1] - The string to search
1708   //
1709   String[0] = NULL;
1710   String[1] = NULL;
1711   for (Index = 0; Index < 2; Index++) {
1712     if (Value[Index + 1].Type != EFI_IFR_TYPE_STRING) {
1713       Result->Type = EFI_IFR_TYPE_UNDEFINED;
1714       Status = EFI_SUCCESS;
1715       goto Done;
1716     }
1717 
1718     String[Index] = GetToken (Value[Index + 1].Value.string, FormSet->HiiHandle);
1719     if (String[Index] == NULL) {
1720       Status = EFI_NOT_FOUND;
1721       goto Done;
1722     }
1723 
1724     if (Format == EFI_IFR_FF_CASE_INSENSITIVE) {
1725       //
1726       // Case insensitive, convert both string to upper case
1727       //
1728       IfrStrToUpper (String[Index]);
1729     }
1730   }
1731 
1732   Result->Type = EFI_IFR_TYPE_NUM_SIZE_64;
1733   if (Base >= StrLen (String[1])) {
1734     Result->Value.u64 = 0xFFFFFFFFFFFFFFFFULL;
1735   } else {
1736     StringPtr = StrStr (String[1] + Base, String[0]);
1737     Result->Value.u64 = (StringPtr == NULL) ? 0xFFFFFFFFFFFFFFFFULL : (StringPtr - String[1]);
1738   }
1739 
1740 Done:
1741   if (String[0] != NULL) {
1742     FreePool (String[0]);
1743   }
1744   if (String[1] != NULL) {
1745     FreePool (String[1]);
1746   }
1747 
1748   return Status;
1749 }
1750 
1751 
1752 /**
1753   Evaluate opcode EFI_IFR_MID.
1754 
1755   @param  FormSet                Formset which contains this opcode.
1756   @param  Result                 Evaluation result for this opcode.
1757 
1758   @retval EFI_SUCCESS            Opcode evaluation success.
1759   @retval Other                  Opcode evaluation failed.
1760 
1761 **/
1762 EFI_STATUS
IfrMid(IN FORM_BROWSER_FORMSET * FormSet,OUT EFI_HII_VALUE * Result)1763 IfrMid (
1764   IN FORM_BROWSER_FORMSET  *FormSet,
1765   OUT  EFI_HII_VALUE       *Result
1766   )
1767 {
1768   EFI_STATUS     Status;
1769   EFI_HII_VALUE  Value[3];
1770   CHAR16         *String;
1771   UINTN          Base;
1772   UINTN          Length;
1773   CHAR16         *SubString;
1774   UINT16         BufferLen;
1775   UINT8          *Buffer;
1776 
1777   ZeroMem (Value, sizeof (Value));
1778 
1779   Status = PopExpression (&Value[0]);
1780   if (EFI_ERROR (Status)) {
1781     return Status;
1782   }
1783 
1784   Status = PopExpression (&Value[1]);
1785   if (EFI_ERROR (Status)) {
1786     return Status;
1787   }
1788 
1789   Status = PopExpression (&Value[2]);
1790   if (EFI_ERROR (Status)) {
1791     return Status;
1792   }
1793 
1794   if (Value[0].Type > EFI_IFR_TYPE_NUM_SIZE_64) {
1795     Result->Type = EFI_IFR_TYPE_UNDEFINED;
1796     return EFI_SUCCESS;
1797   }
1798   Length = (UINTN) Value[0].Value.u64;
1799 
1800   if (Value[1].Type > EFI_IFR_TYPE_NUM_SIZE_64) {
1801     Result->Type = EFI_IFR_TYPE_UNDEFINED;
1802     return EFI_SUCCESS;
1803   }
1804   Base = (UINTN) Value[1].Value.u64;
1805 
1806   if (Value[2].Type != EFI_IFR_TYPE_STRING && !IsTypeInBuffer(&Value[2])) {
1807     Result->Type = EFI_IFR_TYPE_UNDEFINED;
1808     return EFI_SUCCESS;
1809   }
1810   if (Value[2].Type == EFI_IFR_TYPE_STRING) {
1811     String = GetToken (Value[2].Value.string, FormSet->HiiHandle);
1812     if (String == NULL) {
1813       return EFI_NOT_FOUND;
1814     }
1815 
1816     if (Length == 0 || Base >= StrLen (String)) {
1817       SubString = gEmptyString;
1818     } else {
1819       SubString = String + Base;
1820       if ((Base + Length) < StrLen (String)) {
1821         SubString[Length] = L'\0';
1822       }
1823     }
1824 
1825     Result->Type = EFI_IFR_TYPE_STRING;
1826     Result->Value.string = NewString (SubString, FormSet->HiiHandle);
1827 
1828     FreePool (String);
1829   } else {
1830     BufferLen = GetLengthForValue (&Value[2]);
1831     Buffer = GetBufferForValue (&Value[2]);
1832 
1833     Result->Type = EFI_IFR_TYPE_BUFFER;
1834     if (Length == 0 || Base >= BufferLen) {
1835       Result->BufferLen = 0;
1836       Result->Buffer = NULL;
1837     } else {
1838       Result->BufferLen = (UINT16)((BufferLen - Base) < Length ? (BufferLen - Base) : Length);
1839       Result->Buffer = AllocateZeroPool (Result->BufferLen);
1840       ASSERT (Result->Buffer != NULL);
1841       CopyMem (Result->Buffer, &Buffer[Base], Result->BufferLen);
1842     }
1843 
1844     if (Value[2].Type == EFI_IFR_TYPE_BUFFER) {
1845       FreePool (Value[2].Buffer);
1846     }
1847   }
1848 
1849   return Status;
1850 }
1851 
1852 
1853 /**
1854   Evaluate opcode EFI_IFR_TOKEN.
1855 
1856   @param  FormSet                Formset which contains this opcode.
1857   @param  Result                 Evaluation result for this opcode.
1858 
1859   @retval EFI_SUCCESS            Opcode evaluation success.
1860   @retval Other                  Opcode evaluation failed.
1861 
1862 **/
1863 EFI_STATUS
IfrToken(IN FORM_BROWSER_FORMSET * FormSet,OUT EFI_HII_VALUE * Result)1864 IfrToken (
1865   IN FORM_BROWSER_FORMSET  *FormSet,
1866   OUT  EFI_HII_VALUE       *Result
1867   )
1868 {
1869   EFI_STATUS     Status;
1870   EFI_HII_VALUE  Value[3];
1871   CHAR16         *String[2];
1872   UINTN          Count;
1873   CHAR16         *Delimiter;
1874   CHAR16         *SubString;
1875   CHAR16         *StringPtr;
1876   UINTN          Index;
1877 
1878   ZeroMem (Value, sizeof (Value));
1879 
1880   Status = PopExpression (&Value[0]);
1881   if (EFI_ERROR (Status)) {
1882     return Status;
1883   }
1884 
1885   Status = PopExpression (&Value[1]);
1886   if (EFI_ERROR (Status)) {
1887     return Status;
1888   }
1889 
1890   Status = PopExpression (&Value[2]);
1891   if (EFI_ERROR (Status)) {
1892     return Status;
1893   }
1894 
1895   if (Value[0].Type > EFI_IFR_TYPE_NUM_SIZE_64) {
1896     Result->Type = EFI_IFR_TYPE_UNDEFINED;
1897     return EFI_SUCCESS;
1898   }
1899   Count = (UINTN) Value[0].Value.u64;
1900 
1901   //
1902   // String[0] - Delimiter
1903   // String[1] - The string to search
1904   //
1905   String[0] = NULL;
1906   String[1] = NULL;
1907   for (Index = 0; Index < 2; Index++) {
1908     if (Value[Index + 1].Type != EFI_IFR_TYPE_STRING) {
1909       Result->Type = EFI_IFR_TYPE_UNDEFINED;
1910       Status = EFI_SUCCESS;
1911       goto Done;
1912     }
1913 
1914     String[Index] = GetToken (Value[Index + 1].Value.string, FormSet->HiiHandle);
1915     if (String[Index] == NULL) {
1916       Status = EFI_NOT_FOUND;
1917       goto Done;
1918     }
1919   }
1920 
1921   Delimiter = String[0];
1922   SubString = String[1];
1923   while (Count > 0) {
1924     SubString = StrStr (SubString, Delimiter);
1925     if (SubString != NULL) {
1926       //
1927       // Skip over the delimiter
1928       //
1929       SubString = SubString + StrLen (Delimiter);
1930     } else {
1931       break;
1932     }
1933     Count--;
1934   }
1935 
1936   if (SubString == NULL) {
1937     //
1938     // nth delimited sub-string not found, push an empty string
1939     //
1940     SubString = gEmptyString;
1941   } else {
1942     //
1943     // Put a NULL terminator for nth delimited sub-string
1944     //
1945     StringPtr = StrStr (SubString, Delimiter);
1946     if (StringPtr != NULL) {
1947       *StringPtr = L'\0';
1948     }
1949   }
1950 
1951   Result->Type = EFI_IFR_TYPE_STRING;
1952   Result->Value.string = NewString (SubString, FormSet->HiiHandle);
1953 
1954 Done:
1955   if (String[0] != NULL) {
1956     FreePool (String[0]);
1957   }
1958   if (String[1] != NULL) {
1959     FreePool (String[1]);
1960   }
1961 
1962   return Status;
1963 }
1964 
1965 
1966 /**
1967   Evaluate opcode EFI_IFR_SPAN.
1968 
1969   @param  FormSet                Formset which contains this opcode.
1970   @param  Flags                  FIRST_MATCHING or FIRST_NON_MATCHING.
1971   @param  Result                 Evaluation result for this opcode.
1972 
1973   @retval EFI_SUCCESS            Opcode evaluation success.
1974   @retval Other                  Opcode evaluation failed.
1975 
1976 **/
1977 EFI_STATUS
IfrSpan(IN FORM_BROWSER_FORMSET * FormSet,IN UINT8 Flags,OUT EFI_HII_VALUE * Result)1978 IfrSpan (
1979   IN FORM_BROWSER_FORMSET  *FormSet,
1980   IN UINT8                 Flags,
1981   OUT  EFI_HII_VALUE       *Result
1982   )
1983 {
1984   EFI_STATUS     Status;
1985   EFI_HII_VALUE  Value[3];
1986   CHAR16         *String[2];
1987   CHAR16         *Charset;
1988   UINTN          Base;
1989   UINTN          Index;
1990   CHAR16         *StringPtr;
1991   BOOLEAN        Found;
1992 
1993   ZeroMem (Value, sizeof (Value));
1994 
1995   Status = PopExpression (&Value[0]);
1996   if (EFI_ERROR (Status)) {
1997     return Status;
1998   }
1999 
2000   Status = PopExpression (&Value[1]);
2001   if (EFI_ERROR (Status)) {
2002     return Status;
2003   }
2004 
2005   Status = PopExpression (&Value[2]);
2006   if (EFI_ERROR (Status)) {
2007     return Status;
2008   }
2009 
2010   if (Value[0].Type > EFI_IFR_TYPE_NUM_SIZE_64) {
2011     Result->Type = EFI_IFR_TYPE_UNDEFINED;
2012     return EFI_SUCCESS;
2013   }
2014   Base = (UINTN) Value[0].Value.u64;
2015 
2016   //
2017   // String[0] - Charset
2018   // String[1] - The string to search
2019   //
2020   String[0] = NULL;
2021   String[1] = NULL;
2022   for (Index = 0; Index < 2; Index++) {
2023     if (Value[Index + 1].Type != EFI_IFR_TYPE_STRING) {
2024       Result->Type = EFI_IFR_TYPE_UNDEFINED;
2025       Status = EFI_SUCCESS;
2026       goto Done;
2027     }
2028 
2029     String[Index] = GetToken (Value[Index + 1].Value.string, FormSet->HiiHandle);
2030     if (String [Index] == NULL) {
2031       Status = EFI_NOT_FOUND;
2032       goto Done;
2033     }
2034   }
2035 
2036   if (Base >= StrLen (String[1])) {
2037     Result->Type = EFI_IFR_TYPE_UNDEFINED;
2038     Status = EFI_SUCCESS;
2039     goto Done;
2040   }
2041 
2042   Found = FALSE;
2043   StringPtr = String[1] + Base;
2044   Charset = String[0];
2045   while (*StringPtr != 0 && !Found) {
2046     Index = 0;
2047     while (Charset[Index] != 0) {
2048       if (*StringPtr >= Charset[Index] && *StringPtr <= Charset[Index + 1]) {
2049         if (Flags == EFI_IFR_FLAGS_FIRST_MATCHING) {
2050           Found = TRUE;
2051           break;
2052         }
2053       } else {
2054         if (Flags == EFI_IFR_FLAGS_FIRST_NON_MATCHING) {
2055           Found = TRUE;
2056           break;
2057         }
2058       }
2059       //
2060       // Skip characters pair representing low-end of a range and high-end of a range
2061       //
2062       Index += 2;
2063     }
2064 
2065     if (!Found) {
2066       StringPtr++;
2067     }
2068   }
2069 
2070   Result->Type = EFI_IFR_TYPE_NUM_SIZE_64;
2071   Result->Value.u64 = StringPtr - String[1];
2072 
2073 Done:
2074   if (String[0] != NULL) {
2075     FreePool (String[0]);
2076   }
2077   if (String[1] != NULL) {
2078     FreePool (String[1]);
2079   }
2080 
2081   return Status;
2082 }
2083 
2084 
2085 /**
2086   Zero extend integer/boolean/date/time to UINT64 for comparing.
2087 
2088   @param  Value                  HII Value to be converted.
2089 
2090 **/
2091 VOID
ExtendValueToU64(IN EFI_HII_VALUE * Value)2092 ExtendValueToU64 (
2093   IN  EFI_HII_VALUE   *Value
2094   )
2095 {
2096   UINT64  Temp;
2097 
2098   Temp = 0;
2099   switch (Value->Type) {
2100   case EFI_IFR_TYPE_NUM_SIZE_8:
2101     Temp = Value->Value.u8;
2102     break;
2103 
2104   case EFI_IFR_TYPE_NUM_SIZE_16:
2105     Temp = Value->Value.u16;
2106     break;
2107 
2108   case EFI_IFR_TYPE_NUM_SIZE_32:
2109     Temp = Value->Value.u32;
2110     break;
2111 
2112   case EFI_IFR_TYPE_BOOLEAN:
2113     Temp = Value->Value.b;
2114     break;
2115 
2116   case EFI_IFR_TYPE_TIME:
2117     Temp = Value->Value.u32 & 0xffffff;
2118     break;
2119 
2120   case EFI_IFR_TYPE_DATE:
2121     Temp = Value->Value.u32;
2122     break;
2123 
2124   default:
2125     return;
2126   }
2127 
2128   Value->Value.u64 = Temp;
2129 }
2130 
2131 /**
2132   Get UINT64 type value.
2133 
2134   @param  Value                  Input Hii value.
2135 
2136   @retval UINT64                 Return the UINT64 type value.
2137 
2138 **/
2139 UINT64
HiiValueToUINT64(IN EFI_HII_VALUE * Value)2140 HiiValueToUINT64 (
2141   IN EFI_HII_VALUE      *Value
2142   )
2143 {
2144   UINT64  RetVal;
2145 
2146   RetVal = 0;
2147 
2148   switch (Value->Type) {
2149   case EFI_IFR_TYPE_NUM_SIZE_8:
2150     RetVal = Value->Value.u8;
2151     break;
2152 
2153   case EFI_IFR_TYPE_NUM_SIZE_16:
2154     RetVal = Value->Value.u16;
2155     break;
2156 
2157   case EFI_IFR_TYPE_NUM_SIZE_32:
2158     RetVal = Value->Value.u32;
2159     break;
2160 
2161   case EFI_IFR_TYPE_BOOLEAN:
2162     RetVal = Value->Value.b;
2163     break;
2164 
2165   case EFI_IFR_TYPE_DATE:
2166     RetVal = *(UINT64*) &Value->Value.date;
2167     break;
2168 
2169   case EFI_IFR_TYPE_TIME:
2170     RetVal = (*(UINT64*) &Value->Value.time) & 0xffffff;
2171     break;
2172 
2173   default:
2174     RetVal = Value->Value.u64;
2175     break;
2176   }
2177 
2178   return RetVal;
2179 }
2180 
2181 /**
2182   Compare two Hii value.
2183 
2184   @param  Value1                 Expression value to compare on left-hand.
2185   @param  Value2                 Expression value to compare on right-hand.
2186   @param  Result                 Return value after compare.
2187                                  retval 0                      Two operators equal.
2188                                  return Positive value if Value1 is greater than Value2.
2189                                  retval Negative value if Value1 is less than Value2.
2190   @param  HiiHandle              Only required for string compare.
2191 
2192   @retval other                  Could not perform compare on two values.
2193   @retval EFI_SUCCESS            Compare the value success.
2194 
2195 **/
2196 EFI_STATUS
CompareHiiValue(IN EFI_HII_VALUE * Value1,IN EFI_HII_VALUE * Value2,OUT INTN * Result,IN EFI_HII_HANDLE HiiHandle OPTIONAL)2197 CompareHiiValue (
2198   IN  EFI_HII_VALUE   *Value1,
2199   IN  EFI_HII_VALUE   *Value2,
2200   OUT INTN            *Result,
2201   IN  EFI_HII_HANDLE  HiiHandle OPTIONAL
2202   )
2203 {
2204   INT64   Temp64;
2205   CHAR16  *Str1;
2206   CHAR16  *Str2;
2207   UINTN   Len;
2208   UINT8   *Buf1;
2209   UINT16  Buf1Len;
2210   UINT8   *Buf2;
2211   UINT16  Buf2Len;
2212 
2213   if (Value1->Type == EFI_IFR_TYPE_STRING && Value2->Type == EFI_IFR_TYPE_STRING) {
2214     if (Value1->Value.string == 0 || Value2->Value.string == 0) {
2215       //
2216       // StringId 0 is reserved
2217       //
2218       return EFI_INVALID_PARAMETER;
2219     }
2220 
2221     if (Value1->Value.string == Value2->Value.string) {
2222       *Result = 0;
2223       return EFI_SUCCESS;
2224     }
2225 
2226     Str1 = GetToken (Value1->Value.string, HiiHandle);
2227     if (Str1 == NULL) {
2228       //
2229       // String not found
2230       //
2231       return EFI_NOT_FOUND;
2232     }
2233 
2234     Str2 = GetToken (Value2->Value.string, HiiHandle);
2235     if (Str2 == NULL) {
2236       FreePool (Str1);
2237       return EFI_NOT_FOUND;
2238     }
2239 
2240     *Result = StrCmp (Str1, Str2);
2241 
2242     FreePool (Str1);
2243     FreePool (Str2);
2244 
2245     return EFI_SUCCESS;
2246   }
2247 
2248   //
2249   // Take types(date, time, ref, buffer) as buffer
2250   //
2251   if (IsTypeInBuffer(Value1) && IsTypeInBuffer(Value2)) {
2252     Buf1    = GetBufferForValue(Value1);
2253     Buf1Len = GetLengthForValue(Value1);
2254     Buf2    = GetBufferForValue(Value2);
2255     Buf2Len = GetLengthForValue(Value2);
2256 
2257     Len = Buf1Len > Buf2Len ? Buf2Len : Buf1Len;
2258     *Result = CompareMem (Buf1, Buf2, Len);
2259     if ((*Result == 0) && (Buf1Len != Buf2Len)) {
2260       //
2261       // In this case, means base on samll number buffer, the data is same
2262       // So which value has more data, which value is bigger.
2263       //
2264       *Result = Buf1Len > Buf2Len ? 1 : -1;
2265     }
2266     return EFI_SUCCESS;
2267   }
2268 
2269   //
2270   // Take types(integer, boolean) as integer
2271   //
2272   if (IsTypeInUINT64(Value1) && IsTypeInUINT64(Value2)) {
2273     Temp64 = HiiValueToUINT64(Value1) - HiiValueToUINT64(Value2);
2274     if (Temp64 > 0) {
2275       *Result = 1;
2276     } else if (Temp64 < 0) {
2277       *Result = -1;
2278     } else {
2279       *Result = 0;
2280     }
2281 
2282     return EFI_SUCCESS;
2283   }
2284 
2285   return EFI_UNSUPPORTED;
2286 }
2287 
2288 /**
2289   Check if current user has the privilege specified by the permissions GUID.
2290 
2291   @param[in] Guid  A GUID specifying setup access permissions.
2292 
2293   @retval TRUE     Current user has the privilege.
2294   @retval FALSE    Current user does not have the privilege.
2295 **/
2296 BOOLEAN
CheckUserPrivilege(IN EFI_GUID * Guid)2297 CheckUserPrivilege (
2298   IN EFI_GUID *Guid
2299   )
2300 {
2301   EFI_STATUS                   Status;
2302   EFI_USER_PROFILE_HANDLE      UserProfileHandle;
2303   EFI_USER_INFO_HANDLE         UserInfoHandle;
2304   EFI_USER_INFO                *UserInfo;
2305   EFI_GUID                     *UserPermissionsGuid;
2306   UINTN                        UserInfoSize;
2307   UINTN                        AccessControlDataSize;
2308   EFI_USER_INFO_ACCESS_CONTROL *AccessControl;
2309   UINTN                        RemainSize;
2310 
2311   if (mUserManager == NULL) {
2312     Status = gBS->LocateProtocol (
2313                     &gEfiUserManagerProtocolGuid,
2314                     NULL,
2315                     (VOID **) &mUserManager
2316                     );
2317     if (EFI_ERROR (Status)) {
2318       ///
2319       /// If the system does not support user management, then it is assumed that
2320       /// all users have admin privilege and evaluation of each EFI_IFR_SECURITY
2321       /// op-code is always TRUE.
2322       ///
2323       return TRUE;
2324     }
2325   }
2326 
2327   Status = mUserManager->Current (mUserManager, &UserProfileHandle);
2328   ASSERT_EFI_ERROR (Status);
2329 
2330   ///
2331   /// Enumerate all user information of the current user profile
2332   /// to look for any EFI_USER_INFO_ACCESS_SETUP record.
2333   ///
2334 
2335   for (UserInfoHandle = NULL;;) {
2336     Status = mUserManager->GetNextInfo (mUserManager, UserProfileHandle, &UserInfoHandle);
2337     if (EFI_ERROR (Status)) {
2338       break;
2339     }
2340 
2341     UserInfoSize = 0;
2342     Status = mUserManager->GetInfo (mUserManager, UserProfileHandle, UserInfoHandle, NULL, &UserInfoSize);
2343     if (Status != EFI_BUFFER_TOO_SMALL) {
2344       continue;
2345     }
2346 
2347     UserInfo = (EFI_USER_INFO *) AllocatePool (UserInfoSize);
2348     if (UserInfo == NULL) {
2349       break;
2350     }
2351 
2352     Status = mUserManager->GetInfo (mUserManager, UserProfileHandle, UserInfoHandle, UserInfo, &UserInfoSize);
2353     if (EFI_ERROR (Status) ||
2354         UserInfo->InfoType != EFI_USER_INFO_ACCESS_POLICY_RECORD ||
2355         UserInfo->InfoSize <= sizeof (EFI_USER_INFO)) {
2356       FreePool (UserInfo);
2357       continue;
2358     }
2359 
2360     RemainSize = UserInfo->InfoSize - sizeof (EFI_USER_INFO);
2361     AccessControl = (EFI_USER_INFO_ACCESS_CONTROL *)(UserInfo + 1);
2362     while (RemainSize >= sizeof (EFI_USER_INFO_ACCESS_CONTROL)) {
2363       if (RemainSize < AccessControl->Size || AccessControl->Size < sizeof (EFI_USER_INFO_ACCESS_CONTROL)) {
2364         break;
2365       }
2366       if (AccessControl->Type == EFI_USER_INFO_ACCESS_SETUP) {
2367         ///
2368         /// Check if current user has the privilege specified by the permissions GUID.
2369         ///
2370 
2371         UserPermissionsGuid = (EFI_GUID *)(AccessControl + 1);
2372         AccessControlDataSize = AccessControl->Size - sizeof (EFI_USER_INFO_ACCESS_CONTROL);
2373         while (AccessControlDataSize >= sizeof (EFI_GUID)) {
2374           if (CompareGuid (Guid, UserPermissionsGuid)) {
2375             FreePool (UserInfo);
2376             return TRUE;
2377           }
2378           UserPermissionsGuid++;
2379           AccessControlDataSize -= sizeof (EFI_GUID);
2380         }
2381       }
2382       RemainSize -= AccessControl->Size;
2383       AccessControl = (EFI_USER_INFO_ACCESS_CONTROL *)((UINT8 *)AccessControl + AccessControl->Size);
2384     }
2385 
2386     FreePool (UserInfo);
2387   }
2388   return FALSE;
2389 }
2390 
2391 /**
2392   Get question value from the predefined formset.
2393 
2394   @param  DevicePath             The driver's device path which produece the formset data.
2395   @param  InputHiiHandle         The hii handle associate with the formset data.
2396   @param  FormSetGuid            The formset guid which include the question.
2397   @param  QuestionId             The question id which need to get value from.
2398   @param  Value                  The return data about question's value.
2399 
2400   @retval TRUE                   Get the question value success.
2401   @retval FALSE                  Get the question value failed.
2402 **/
2403 BOOLEAN
GetQuestionValueFromForm(IN EFI_DEVICE_PATH_PROTOCOL * DevicePath,IN EFI_HII_HANDLE InputHiiHandle,IN EFI_GUID * FormSetGuid,IN EFI_QUESTION_ID QuestionId,OUT EFI_HII_VALUE * Value)2404 GetQuestionValueFromForm (
2405   IN EFI_DEVICE_PATH_PROTOCOL  *DevicePath,
2406   IN EFI_HII_HANDLE            InputHiiHandle,
2407   IN EFI_GUID                  *FormSetGuid,
2408   IN EFI_QUESTION_ID           QuestionId,
2409   OUT EFI_HII_VALUE            *Value
2410   )
2411 {
2412   EFI_STATUS                   Status;
2413   EFI_HII_HANDLE               HiiHandle;
2414   FORM_BROWSER_STATEMENT       *Question;
2415   FORM_BROWSER_FORMSET         *FormSet;
2416   FORM_BROWSER_FORM            *Form;
2417   BOOLEAN                      GetTheVal;
2418   LIST_ENTRY                   *Link;
2419 
2420   //
2421   // The input parameter DevicePath or InputHiiHandle must have one valid input.
2422   //
2423   ASSERT ((DevicePath != NULL && InputHiiHandle == NULL) ||
2424           (DevicePath == NULL && InputHiiHandle != NULL) );
2425 
2426   GetTheVal    = TRUE;
2427   HiiHandle    = NULL;
2428   Question     = NULL;
2429   Form         = NULL;
2430 
2431   //
2432   // Get HiiHandle.
2433   //
2434   if (DevicePath != NULL) {
2435     HiiHandle = DevicePathToHiiHandle (DevicePath, FormSetGuid);
2436     if (HiiHandle == NULL) {
2437       return FALSE;
2438     }
2439   } else {
2440     HiiHandle = InputHiiHandle;
2441   }
2442   ASSERT (HiiHandle != NULL);
2443 
2444   //
2445   // Get the formset data include this question.
2446   //
2447   FormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET));
2448   ASSERT (FormSet != NULL);
2449   Status = InitializeFormSet(HiiHandle, FormSetGuid, FormSet);
2450   if (EFI_ERROR (Status)) {
2451     GetTheVal = FALSE;
2452     goto Done;
2453   }
2454 
2455   //
2456   // Base on the Question Id to get the question info.
2457   //
2458   Question = IdToQuestion(FormSet, NULL, QuestionId);
2459   if (Question == NULL) {
2460     GetTheVal = FALSE;
2461     goto Done;
2462   }
2463 
2464   //
2465   // Search form in the formset scope
2466   //
2467   Link = GetFirstNode (&FormSet->FormListHead);
2468   while (!IsNull (&FormSet->FormListHead, Link)) {
2469     Form = FORM_BROWSER_FORM_FROM_LINK (Link);
2470 
2471     Question = IdToQuestion2 (Form, QuestionId);
2472     if (Question != NULL) {
2473       break;
2474     }
2475 
2476     Link = GetNextNode (&FormSet->FormListHead, Link);
2477     Form = NULL;
2478   }
2479   ASSERT (Form != NULL);
2480 
2481   //
2482   // Get the question value.
2483   //
2484   Status = GetQuestionValue(FormSet, Form, Question, GetSetValueWithEditBuffer);
2485   if (EFI_ERROR (Status)) {
2486     GetTheVal = FALSE;
2487     goto Done;
2488   }
2489 
2490   CopyMem (Value, &Question->HiiValue, sizeof (EFI_HII_VALUE));
2491 
2492 Done:
2493   //
2494   // Clean the formset structure and restore the global parameter.
2495   //
2496   if (FormSet != NULL) {
2497     DestroyFormSet (FormSet);
2498   }
2499 
2500   return GetTheVal;
2501 }
2502 
2503 /**
2504   Evaluate the result of a HII expression.
2505 
2506   If Expression is NULL, then ASSERT.
2507 
2508   @param  FormSet                FormSet associated with this expression.
2509   @param  Form                   Form associated with this expression.
2510   @param  Expression             Expression to be evaluated.
2511 
2512   @retval EFI_SUCCESS            The expression evaluated successfuly
2513   @retval EFI_NOT_FOUND          The Question which referenced by a QuestionId
2514                                  could not be found.
2515   @retval EFI_OUT_OF_RESOURCES   There is not enough system memory to grow the
2516                                  stack.
2517   @retval EFI_ACCESS_DENIED      The pop operation underflowed the stack
2518   @retval EFI_INVALID_PARAMETER  Syntax error with the Expression
2519 
2520 **/
2521 EFI_STATUS
EvaluateExpression(IN FORM_BROWSER_FORMSET * FormSet,IN FORM_BROWSER_FORM * Form,IN OUT FORM_EXPRESSION * Expression)2522 EvaluateExpression (
2523   IN FORM_BROWSER_FORMSET  *FormSet,
2524   IN FORM_BROWSER_FORM     *Form,
2525   IN OUT FORM_EXPRESSION   *Expression
2526   )
2527 {
2528   EFI_STATUS              Status;
2529   LIST_ENTRY              *Link;
2530   EXPRESSION_OPCODE       *OpCode;
2531   FORM_BROWSER_STATEMENT  *Question;
2532   FORM_BROWSER_STATEMENT  *Question2;
2533   UINT16                  Index;
2534   EFI_HII_VALUE           Data1;
2535   EFI_HII_VALUE           Data2;
2536   EFI_HII_VALUE           Data3;
2537   FORM_EXPRESSION         *RuleExpression;
2538   EFI_HII_VALUE           *Value;
2539   INTN                    Result;
2540   CHAR16                  *StrPtr;
2541   CHAR16                  *NameValue;
2542   UINT32                  TempValue;
2543   LIST_ENTRY              *SubExpressionLink;
2544   FORM_EXPRESSION         *SubExpression;
2545   UINTN                   StackOffset;
2546   UINTN                   TempLength;
2547   CHAR16                  TempStr[5];
2548   UINT8                   DigitUint8;
2549   UINT8                   *TempBuffer;
2550   EFI_TIME                EfiTime;
2551   EFI_HII_VALUE           QuestionVal;
2552   EFI_DEVICE_PATH_PROTOCOL *DevicePath;
2553 
2554   StrPtr = NULL;
2555 
2556   //
2557   // Save current stack offset.
2558   //
2559   StackOffset = SaveExpressionEvaluationStackOffset ();
2560 
2561   ASSERT (Expression != NULL);
2562   Expression->Result.Type = EFI_IFR_TYPE_OTHER;
2563 
2564   Link = GetFirstNode (&Expression->OpCodeListHead);
2565   while (!IsNull (&Expression->OpCodeListHead, Link)) {
2566     OpCode = EXPRESSION_OPCODE_FROM_LINK (Link);
2567 
2568     Link = GetNextNode (&Expression->OpCodeListHead, Link);
2569 
2570     ZeroMem (&Data1, sizeof (EFI_HII_VALUE));
2571     ZeroMem (&Data2, sizeof (EFI_HII_VALUE));
2572     ZeroMem (&Data3, sizeof (EFI_HII_VALUE));
2573 
2574     Value = &Data3;
2575     Value->Type = EFI_IFR_TYPE_BOOLEAN;
2576     Status = EFI_SUCCESS;
2577 
2578     switch (OpCode->Operand) {
2579     //
2580     // Built-in functions
2581     //
2582     case EFI_IFR_EQ_ID_VAL_OP:
2583       Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);
2584       if (Question == NULL) {
2585         Value->Type = EFI_IFR_TYPE_UNDEFINED;
2586         break;
2587       }
2588 
2589       Status = CompareHiiValue (&Question->HiiValue, &OpCode->Value, &Result, NULL);
2590       if (Status == EFI_UNSUPPORTED) {
2591         Status = EFI_SUCCESS;
2592         Value->Type = EFI_IFR_TYPE_UNDEFINED;
2593         break;
2594       }
2595 
2596       if (EFI_ERROR (Status)) {
2597         goto Done;
2598       }
2599       Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE);
2600       break;
2601 
2602     case EFI_IFR_EQ_ID_ID_OP:
2603       Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);
2604       if (Question == NULL) {
2605         Value->Type = EFI_IFR_TYPE_UNDEFINED;
2606         break;
2607       }
2608 
2609       Question2 = IdToQuestion (FormSet, Form, OpCode->QuestionId2);
2610       if (Question2 == NULL) {
2611         Value->Type = EFI_IFR_TYPE_UNDEFINED;
2612         break;
2613       }
2614 
2615       Status = CompareHiiValue (&Question->HiiValue, &Question2->HiiValue, &Result, FormSet->HiiHandle);
2616       if (Status == EFI_UNSUPPORTED) {
2617         Value->Type = EFI_IFR_TYPE_UNDEFINED;
2618         Status = EFI_SUCCESS;
2619         break;
2620       }
2621       if (EFI_ERROR (Status)) {
2622         goto Done;
2623       }
2624       Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE);
2625       break;
2626 
2627     case EFI_IFR_EQ_ID_VAL_LIST_OP:
2628       Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);
2629       if (Question == NULL) {
2630         Value->Type = EFI_IFR_TYPE_UNDEFINED;
2631         break;
2632       }
2633 
2634       Value->Value.b = FALSE;
2635       for (Index =0; Index < OpCode->ListLength; Index++) {
2636         if (Question->HiiValue.Value.u16 == OpCode->ValueList[Index]) {
2637           Value->Value.b = TRUE;
2638           break;
2639         }
2640       }
2641       break;
2642 
2643     case EFI_IFR_DUP_OP:
2644       Status = PopExpression (Value);
2645       if (EFI_ERROR (Status)) {
2646         goto Done;
2647       }
2648 
2649       Status = PushExpression (Value);
2650       break;
2651 
2652     case EFI_IFR_QUESTION_REF1_OP:
2653     case EFI_IFR_THIS_OP:
2654       Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);
2655       if (Question == NULL) {
2656         Status = EFI_NOT_FOUND;
2657         goto Done;
2658       }
2659 
2660       Value = &Question->HiiValue;
2661       break;
2662 
2663     case EFI_IFR_SECURITY_OP:
2664       Value->Value.b = CheckUserPrivilege (&OpCode->Guid);
2665       break;
2666 
2667     case EFI_IFR_GET_OP:
2668       //
2669       // Get Value from VarStore buffer, EFI VarStore, Name/Value VarStore.
2670       //
2671       Value->Type = EFI_IFR_TYPE_UNDEFINED;
2672       Value->Value.u8 = 0;
2673       if (OpCode->VarStorage != NULL) {
2674         switch (OpCode->VarStorage->Type) {
2675         case EFI_HII_VARSTORE_BUFFER:
2676         case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:
2677           //
2678           // Get value from Edit Buffer
2679           //
2680           Value->Type = OpCode->ValueType;
2681           CopyMem (&Value->Value, OpCode->VarStorage->EditBuffer + OpCode->VarStoreInfo.VarOffset, OpCode->ValueWidth);
2682           break;
2683         case EFI_HII_VARSTORE_NAME_VALUE:
2684           if (OpCode->ValueType != EFI_IFR_TYPE_STRING) {
2685             //
2686             // Get value from string except for STRING value.
2687             //
2688             Status = GetValueByName (OpCode->VarStorage, OpCode->ValueName, &StrPtr, GetSetValueWithEditBuffer);
2689             if (!EFI_ERROR (Status)) {
2690               ASSERT (StrPtr != NULL);
2691               TempLength = StrLen (StrPtr);
2692               if (OpCode->ValueWidth >= ((TempLength + 1) / 2)) {
2693                 Value->Type = OpCode->ValueType;
2694                 TempBuffer = (UINT8 *) &Value->Value;
2695                 ZeroMem (TempStr, sizeof (TempStr));
2696                 for (Index = 0; Index < TempLength; Index ++) {
2697                   TempStr[0] = StrPtr[TempLength - Index - 1];
2698                   DigitUint8 = (UINT8) StrHexToUint64 (TempStr);
2699                   if ((Index & 1) == 0) {
2700                     TempBuffer [Index/2] = DigitUint8;
2701                   } else {
2702                     TempBuffer [Index/2] = (UINT8) ((DigitUint8 << 4) + TempBuffer [Index/2]);
2703                   }
2704                 }
2705               }
2706             }
2707           }
2708           break;
2709         case EFI_HII_VARSTORE_EFI_VARIABLE:
2710           //
2711           // Get value from variable.
2712           //
2713           TempLength = OpCode->ValueWidth;
2714           Value->Type = OpCode->ValueType;
2715           Status = gRT->GetVariable (
2716                           OpCode->ValueName,
2717                           &OpCode->VarStorage->Guid,
2718                           NULL,
2719                           &TempLength,
2720                           &Value->Value
2721                           );
2722           if (EFI_ERROR (Status)) {
2723             Value->Type = EFI_IFR_TYPE_UNDEFINED;
2724             Value->Value.u8 = 0;
2725           }
2726           break;
2727         default:
2728           //
2729           // Not recognize storage.
2730           //
2731           Status = EFI_UNSUPPORTED;
2732           goto Done;
2733         }
2734       } else {
2735         //
2736         // For Time/Date Data
2737         //
2738         if (OpCode->ValueType != EFI_IFR_TYPE_DATE && OpCode->ValueType != EFI_IFR_TYPE_TIME) {
2739           //
2740           // Only support Data/Time data when storage doesn't exist.
2741           //
2742           Status = EFI_UNSUPPORTED;
2743           goto Done;
2744         }
2745         Status = gRT->GetTime (&EfiTime, NULL);
2746         if (!EFI_ERROR (Status)) {
2747           if (OpCode->ValueType == EFI_IFR_TYPE_DATE) {
2748             switch (OpCode->VarStoreInfo.VarOffset) {
2749             case 0x00:
2750               Value->Type = EFI_IFR_TYPE_NUM_SIZE_16;
2751               Value->Value.u16 = EfiTime.Year;
2752               break;
2753             case 0x02:
2754               Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
2755               Value->Value.u8 = EfiTime.Month;
2756               break;
2757             case 0x03:
2758               Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
2759               Value->Value.u8 = EfiTime.Day;
2760               break;
2761             default:
2762               //
2763               // Invalid Date field.
2764               //
2765               Status = EFI_INVALID_PARAMETER;
2766               goto Done;
2767             }
2768           } else {
2769             switch (OpCode->VarStoreInfo.VarOffset) {
2770             case 0x00:
2771               Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
2772               Value->Value.u8 = EfiTime.Hour;
2773               break;
2774             case 0x01:
2775               Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
2776               Value->Value.u8 = EfiTime.Minute;
2777               break;
2778             case 0x02:
2779               Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
2780               Value->Value.u8 = EfiTime.Second;
2781               break;
2782             default:
2783               //
2784               // Invalid Time field.
2785               //
2786               Status = EFI_INVALID_PARAMETER;
2787               goto Done;
2788             }
2789           }
2790         }
2791       }
2792 
2793       break;
2794 
2795     case EFI_IFR_QUESTION_REF3_OP:
2796       //
2797       // EFI_IFR_QUESTION_REF3
2798       // Pop an expression from the expression stack
2799       //
2800       Status = PopExpression (Value);
2801       if (EFI_ERROR (Status)) {
2802         goto Done;
2803       }
2804 
2805       //
2806       // Validate the expression value
2807       //
2808       if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) {
2809         Value->Type = EFI_IFR_TYPE_UNDEFINED;
2810         break;
2811       }
2812 
2813       if (OpCode->DevicePath != 0) {
2814         Value->Type = EFI_IFR_TYPE_UNDEFINED;
2815 
2816         StrPtr = GetToken (OpCode->DevicePath, FormSet->HiiHandle);
2817         if (StrPtr != NULL && mPathFromText != NULL) {
2818           DevicePath = mPathFromText->ConvertTextToDevicePath(StrPtr);
2819           if (DevicePath != NULL && GetQuestionValueFromForm(DevicePath, NULL, &OpCode->Guid, Value->Value.u16, &QuestionVal)) {
2820             Value = &QuestionVal;
2821           }
2822           if (DevicePath != NULL) {
2823             FreePool (DevicePath);
2824           }
2825         }
2826 
2827         if (StrPtr != NULL) {
2828           FreePool (StrPtr);
2829         }
2830       } else if (IsZeroGuid (&OpCode->Guid)) {
2831         if (!GetQuestionValueFromForm(NULL, FormSet->HiiHandle, &OpCode->Guid, Value->Value.u16, &QuestionVal)){
2832           Value->Type = EFI_IFR_TYPE_UNDEFINED;
2833           break;
2834         }
2835         Value = &QuestionVal;
2836       } else {
2837         Question = IdToQuestion (FormSet, Form, Value->Value.u16);
2838         if (Question == NULL) {
2839           Value->Type = EFI_IFR_TYPE_UNDEFINED;
2840           break;
2841         }
2842 
2843         //
2844         // push the questions' value on to the expression stack
2845         //
2846         Value = &Question->HiiValue;
2847       }
2848       break;
2849 
2850     case EFI_IFR_RULE_REF_OP:
2851       //
2852       // Find expression for this rule
2853       //
2854       RuleExpression = RuleIdToExpression (Form, OpCode->RuleId);
2855       if (RuleExpression == NULL) {
2856         Value->Type = EFI_IFR_TYPE_UNDEFINED;
2857         break;
2858       }
2859 
2860       //
2861       // Evaluate this rule expression
2862       //
2863       Status = EvaluateExpression (FormSet, Form, RuleExpression);
2864       if (EFI_ERROR (Status) || RuleExpression->Result.Type == EFI_IFR_TYPE_UNDEFINED) {
2865         Value->Type = EFI_IFR_TYPE_UNDEFINED;
2866         break;
2867       }
2868 
2869       Value = &RuleExpression->Result;
2870       break;
2871 
2872     case EFI_IFR_STRING_REF1_OP:
2873       Value->Type = EFI_IFR_TYPE_STRING;
2874       Value->Value.string = OpCode->Value.Value.string;
2875       break;
2876 
2877     //
2878     // Constant
2879     //
2880     case EFI_IFR_TRUE_OP:
2881     case EFI_IFR_FALSE_OP:
2882     case EFI_IFR_ONE_OP:
2883     case EFI_IFR_ONES_OP:
2884     case EFI_IFR_UINT8_OP:
2885     case EFI_IFR_UINT16_OP:
2886     case EFI_IFR_UINT32_OP:
2887     case EFI_IFR_UINT64_OP:
2888     case EFI_IFR_UNDEFINED_OP:
2889     case EFI_IFR_VERSION_OP:
2890     case EFI_IFR_ZERO_OP:
2891       Value = &OpCode->Value;
2892       break;
2893 
2894     //
2895     // unary-op
2896     //
2897     case EFI_IFR_LENGTH_OP:
2898       Status = PopExpression (Value);
2899       if (EFI_ERROR (Status)) {
2900         goto Done;
2901       }
2902       if (Value->Type != EFI_IFR_TYPE_STRING && !IsTypeInBuffer (Value)) {
2903         Value->Type = EFI_IFR_TYPE_UNDEFINED;
2904         break;
2905       }
2906 
2907       if (Value->Type == EFI_IFR_TYPE_STRING) {
2908         StrPtr = GetToken (Value->Value.string, FormSet->HiiHandle);
2909         if (StrPtr == NULL) {
2910           Status = EFI_INVALID_PARAMETER;
2911           goto Done;
2912         }
2913 
2914         Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
2915         Value->Value.u64 = StrLen (StrPtr);
2916         FreePool (StrPtr);
2917       } else {
2918         Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
2919         Value->Value.u64 = GetLengthForValue(Value);
2920         FreePool (Value->Buffer);
2921       }
2922       break;
2923 
2924     case EFI_IFR_NOT_OP:
2925       Status = PopExpression (Value);
2926       if (EFI_ERROR (Status)) {
2927         goto Done;
2928       }
2929       if (Value->Type != EFI_IFR_TYPE_BOOLEAN) {
2930         Value->Type = EFI_IFR_TYPE_UNDEFINED;
2931         break;
2932       }
2933       Value->Value.b = (BOOLEAN) (!Value->Value.b);
2934       break;
2935 
2936     case EFI_IFR_QUESTION_REF2_OP:
2937       //
2938       // Pop an expression from the expression stack
2939       //
2940       Status = PopExpression (Value);
2941       if (EFI_ERROR (Status)) {
2942         goto Done;
2943       }
2944 
2945       //
2946       // Validate the expression value
2947       //
2948       if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) {
2949         Value->Type = EFI_IFR_TYPE_UNDEFINED;
2950         break;
2951       }
2952 
2953       Question = IdToQuestion (FormSet, Form, Value->Value.u16);
2954       if (Question == NULL) {
2955         Value->Type = EFI_IFR_TYPE_UNDEFINED;
2956         break;
2957       }
2958 
2959       Value = &Question->HiiValue;
2960       break;
2961 
2962     case EFI_IFR_STRING_REF2_OP:
2963       //
2964       // Pop an expression from the expression stack
2965       //
2966       Status = PopExpression (Value);
2967       if (EFI_ERROR (Status)) {
2968         goto Done;
2969       }
2970 
2971       //
2972       // Validate the expression value
2973       //
2974       if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) {
2975         Value->Type = EFI_IFR_TYPE_UNDEFINED;
2976         break;
2977       }
2978 
2979       Value->Type = EFI_IFR_TYPE_STRING;
2980       StrPtr = GetToken (Value->Value.u16, FormSet->HiiHandle);
2981       if (StrPtr == NULL) {
2982         //
2983         // If String not exit, push an empty string
2984         //
2985         Value->Value.string = NewString (gEmptyString, FormSet->HiiHandle);
2986       } else {
2987         Index = (UINT16) Value->Value.u64;
2988         Value->Value.string = Index;
2989         FreePool (StrPtr);
2990       }
2991       break;
2992 
2993     case EFI_IFR_TO_BOOLEAN_OP:
2994       //
2995       // Pop an expression from the expression stack
2996       //
2997       Status = PopExpression (Value);
2998       if (EFI_ERROR (Status)) {
2999         goto Done;
3000       }
3001 
3002       //
3003       // Convert an expression to a Boolean
3004       //
3005       if (Value->Type <= EFI_IFR_TYPE_DATE) {
3006         //
3007         // When converting from an unsigned integer, zero will be converted to
3008         // FALSE and any other value will be converted to TRUE.
3009         //
3010         Value->Value.b = (BOOLEAN) (HiiValueToUINT64(Value) != 0);
3011 
3012         Value->Type = EFI_IFR_TYPE_BOOLEAN;
3013       } else if (Value->Type == EFI_IFR_TYPE_STRING) {
3014         //
3015         // When converting from a string, if case-insensitive compare
3016         // with "true" is True, then push True. If a case-insensitive compare
3017         // with "false" is True, then push False. Otherwise, push Undefined.
3018         //
3019         StrPtr = GetToken (Value->Value.string, FormSet->HiiHandle);
3020         if (StrPtr == NULL) {
3021           Status = EFI_INVALID_PARAMETER;
3022           goto Done;
3023         }
3024 
3025         IfrStrToUpper (StrPtr);
3026         if (StrCmp (StrPtr, L"TRUE") == 0){
3027           Value->Value.b = TRUE;
3028           Value->Type = EFI_IFR_TYPE_BOOLEAN;
3029         } else if (StrCmp (StrPtr, L"FALSE") == 0) {
3030           Value->Value.b = FALSE;
3031           Value->Type = EFI_IFR_TYPE_BOOLEAN;
3032         } else {
3033           Value->Type = EFI_IFR_TYPE_UNDEFINED;
3034         }
3035         FreePool (StrPtr);
3036       } else if (Value->Type == EFI_IFR_TYPE_BUFFER) {
3037         //
3038         // When converting from a buffer, if the buffer is all zeroes,
3039         // then push False. Otherwise push True.
3040         //
3041         for (Index =0; Index < Value->BufferLen; Index ++) {
3042           if (Value->Buffer[Index] != 0) {
3043             break;
3044           }
3045         }
3046 
3047         if (Index >= Value->BufferLen) {
3048           Value->Value.b = FALSE;
3049         } else {
3050           Value->Value.b = TRUE;
3051         }
3052         Value->Type = EFI_IFR_TYPE_BOOLEAN;
3053         FreePool (Value->Buffer);
3054       }
3055       break;
3056 
3057     case EFI_IFR_TO_STRING_OP:
3058       Status = IfrToString (FormSet, OpCode->Format, Value);
3059       break;
3060 
3061     case EFI_IFR_TO_UINT_OP:
3062       Status = IfrToUint (FormSet, Value);
3063       break;
3064 
3065     case EFI_IFR_TO_LOWER_OP:
3066     case EFI_IFR_TO_UPPER_OP:
3067       Status = InitializeUnicodeCollationProtocol ();
3068       if (EFI_ERROR (Status)) {
3069         goto Done;
3070       }
3071 
3072       Status = PopExpression (Value);
3073       if (EFI_ERROR (Status)) {
3074         goto Done;
3075       }
3076 
3077       if (Value->Type != EFI_IFR_TYPE_STRING) {
3078         Value->Type = EFI_IFR_TYPE_UNDEFINED;
3079         break;
3080       }
3081 
3082       StrPtr = GetToken (Value->Value.string, FormSet->HiiHandle);
3083       if (StrPtr == NULL) {
3084         Status = EFI_NOT_FOUND;
3085         goto Done;
3086       }
3087 
3088       if (OpCode->Operand == EFI_IFR_TO_LOWER_OP) {
3089         mUnicodeCollation->StrLwr (mUnicodeCollation, StrPtr);
3090       } else {
3091         mUnicodeCollation->StrUpr (mUnicodeCollation, StrPtr);
3092       }
3093       Value->Value.string = NewString (StrPtr, FormSet->HiiHandle);
3094       FreePool (StrPtr);
3095       break;
3096 
3097     case EFI_IFR_BITWISE_NOT_OP:
3098       //
3099       // Pop an expression from the expression stack
3100       //
3101       Status = PopExpression (Value);
3102       if (EFI_ERROR (Status)) {
3103         goto Done;
3104       }
3105       if (Value->Type > EFI_IFR_TYPE_DATE) {
3106         Value->Type = EFI_IFR_TYPE_UNDEFINED;
3107         break;
3108       }
3109 
3110       Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
3111       Value->Value.u64 = ~ HiiValueToUINT64(Value);
3112       break;
3113 
3114     case EFI_IFR_SET_OP:
3115       //
3116       // Pop an expression from the expression stack
3117       //
3118       Status = PopExpression (Value);
3119       if (EFI_ERROR (Status)) {
3120         goto Done;
3121       }
3122       Data1.Type = EFI_IFR_TYPE_BOOLEAN;
3123       Data1.Value.b = FALSE;
3124       //
3125       // Set value to var storage buffer
3126       //
3127       if (OpCode->VarStorage != NULL) {
3128         switch (OpCode->VarStorage->Type) {
3129         case EFI_HII_VARSTORE_BUFFER:
3130         case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:
3131           CopyMem (OpCode->VarStorage->EditBuffer + OpCode->VarStoreInfo.VarOffset, &Value->Value, OpCode->ValueWidth);
3132           Data1.Value.b = TRUE;
3133           break;
3134         case EFI_HII_VARSTORE_NAME_VALUE:
3135           if (OpCode->ValueType != EFI_IFR_TYPE_STRING) {
3136             NameValue = AllocateZeroPool ((OpCode->ValueWidth * 2 + 1) * sizeof (CHAR16));
3137             ASSERT (NameValue != NULL);
3138             //
3139             // Convert Buffer to Hex String
3140             //
3141             TempBuffer = (UINT8 *) &Value->Value + OpCode->ValueWidth - 1;
3142             StrPtr = NameValue;
3143             for (Index = 0; Index < OpCode->ValueWidth; Index ++, TempBuffer --) {
3144               UnicodeValueToStringS (
3145                 StrPtr,
3146                 (OpCode->ValueWidth * 2 + 1) * sizeof (CHAR16) - ((UINTN)StrPtr - (UINTN)NameValue),
3147                 PREFIX_ZERO | RADIX_HEX,
3148                 *TempBuffer,
3149                 2
3150                 );
3151               StrPtr += StrnLenS (StrPtr, OpCode->ValueWidth * 2 + 1 - ((UINTN)StrPtr - (UINTN)NameValue) / sizeof (CHAR16));
3152             }
3153             Status = SetValueByName (OpCode->VarStorage, OpCode->ValueName, NameValue, GetSetValueWithEditBuffer, NULL);
3154             FreePool (NameValue);
3155             if (!EFI_ERROR (Status)) {
3156               Data1.Value.b = TRUE;
3157             }
3158           }
3159           break;
3160         case EFI_HII_VARSTORE_EFI_VARIABLE:
3161           Status = gRT->SetVariable (
3162                           OpCode->ValueName,
3163                           &OpCode->VarStorage->Guid,
3164                           OpCode->VarStorage->Attributes,
3165                           OpCode->ValueWidth,
3166                           &Value->Value
3167                           );
3168           if (!EFI_ERROR (Status)) {
3169             Data1.Value.b = TRUE;
3170           }
3171           break;
3172         default:
3173           //
3174           // Not recognize storage.
3175           //
3176           Status = EFI_UNSUPPORTED;
3177           goto Done;
3178         }
3179       } else {
3180         //
3181         // For Time/Date Data
3182         //
3183         if (OpCode->ValueType != EFI_IFR_TYPE_DATE && OpCode->ValueType != EFI_IFR_TYPE_TIME) {
3184           //
3185           // Only support Data/Time data when storage doesn't exist.
3186           //
3187           Status = EFI_UNSUPPORTED;
3188           goto Done;
3189         }
3190         Status = gRT->GetTime (&EfiTime, NULL);
3191         if (!EFI_ERROR (Status)) {
3192           if (OpCode->ValueType == EFI_IFR_TYPE_DATE) {
3193             switch (OpCode->VarStoreInfo.VarOffset) {
3194             case 0x00:
3195               EfiTime.Year = Value->Value.u16;
3196               break;
3197             case 0x02:
3198               EfiTime.Month = Value->Value.u8;
3199               break;
3200             case 0x03:
3201               EfiTime.Day = Value->Value.u8;
3202               break;
3203             default:
3204               //
3205               // Invalid Date field.
3206               //
3207               Status = EFI_INVALID_PARAMETER;
3208               goto Done;
3209             }
3210           } else {
3211             switch (OpCode->VarStoreInfo.VarOffset) {
3212             case 0x00:
3213               EfiTime.Hour = Value->Value.u8;
3214               break;
3215             case 0x01:
3216               EfiTime.Minute = Value->Value.u8;
3217               break;
3218             case 0x02:
3219               EfiTime.Second = Value->Value.u8;
3220               break;
3221             default:
3222               //
3223               // Invalid Time field.
3224               //
3225               Status = EFI_INVALID_PARAMETER;
3226               goto Done;
3227             }
3228           }
3229           Status = gRT->SetTime (&EfiTime);
3230           if (!EFI_ERROR (Status)) {
3231             Data1.Value.b = TRUE;
3232           }
3233         }
3234       }
3235       Value = &Data1;
3236       break;
3237 
3238     //
3239     // binary-op
3240     //
3241     case EFI_IFR_ADD_OP:
3242     case EFI_IFR_SUBTRACT_OP:
3243     case EFI_IFR_MULTIPLY_OP:
3244     case EFI_IFR_DIVIDE_OP:
3245     case EFI_IFR_MODULO_OP:
3246     case EFI_IFR_BITWISE_AND_OP:
3247     case EFI_IFR_BITWISE_OR_OP:
3248     case EFI_IFR_SHIFT_LEFT_OP:
3249     case EFI_IFR_SHIFT_RIGHT_OP:
3250       //
3251       // Pop an expression from the expression stack
3252       //
3253       Status = PopExpression (&Data2);
3254       if (EFI_ERROR (Status)) {
3255         goto Done;
3256       }
3257 
3258       //
3259       // Pop another expression from the expression stack
3260       //
3261       Status = PopExpression (&Data1);
3262       if (EFI_ERROR (Status)) {
3263         goto Done;
3264       }
3265 
3266       if (Data2.Type > EFI_IFR_TYPE_DATE) {
3267         Value->Type = EFI_IFR_TYPE_UNDEFINED;
3268         break;
3269       }
3270 
3271 
3272       if (Data1.Type > EFI_IFR_TYPE_DATE) {
3273         Value->Type = EFI_IFR_TYPE_UNDEFINED;
3274         break;
3275       }
3276 
3277       Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
3278 
3279       switch (OpCode->Operand) {
3280         case EFI_IFR_ADD_OP:
3281           Value->Value.u64 = HiiValueToUINT64(&Data1) + HiiValueToUINT64(&Data2);
3282           break;
3283 
3284         case EFI_IFR_SUBTRACT_OP:
3285           Value->Value.u64 = HiiValueToUINT64(&Data1) - HiiValueToUINT64(&Data2);
3286           break;
3287 
3288         case EFI_IFR_MULTIPLY_OP:
3289           Value->Value.u64 = MultU64x32 (HiiValueToUINT64(&Data1), (UINT32) HiiValueToUINT64(&Data2));
3290           break;
3291 
3292         case EFI_IFR_DIVIDE_OP:
3293           Value->Value.u64 = DivU64x32 (HiiValueToUINT64(&Data1), (UINT32) HiiValueToUINT64(&Data2));
3294           break;
3295 
3296         case EFI_IFR_MODULO_OP:
3297           DivU64x32Remainder  (HiiValueToUINT64(&Data1), (UINT32) HiiValueToUINT64(&Data2), &TempValue);
3298           Value->Value.u64 = TempValue;
3299           break;
3300 
3301         case EFI_IFR_BITWISE_AND_OP:
3302           Value->Value.u64 = HiiValueToUINT64(&Data1) & HiiValueToUINT64(&Data2);
3303           break;
3304 
3305         case EFI_IFR_BITWISE_OR_OP:
3306           Value->Value.u64 = HiiValueToUINT64(&Data1) | HiiValueToUINT64(&Data2);
3307           break;
3308 
3309         case EFI_IFR_SHIFT_LEFT_OP:
3310           Value->Value.u64 = LShiftU64 (HiiValueToUINT64(&Data1), (UINTN) HiiValueToUINT64(&Data2));
3311           break;
3312 
3313         case EFI_IFR_SHIFT_RIGHT_OP:
3314           Value->Value.u64 = RShiftU64 (HiiValueToUINT64(&Data1), (UINTN) HiiValueToUINT64(&Data2));
3315           break;
3316 
3317         default:
3318           break;
3319       }
3320       break;
3321 
3322     case EFI_IFR_AND_OP:
3323     case EFI_IFR_OR_OP:
3324       //
3325       // Two Boolean operator
3326       //
3327       Status = PopExpression (&Data2);
3328       if (EFI_ERROR (Status)) {
3329         goto Done;
3330       }
3331 
3332       //
3333       // Pop another expression from the expression stack
3334       //
3335       Status = PopExpression (&Data1);
3336       if (EFI_ERROR (Status)) {
3337         goto Done;
3338       }
3339 
3340       if (Data2.Type != EFI_IFR_TYPE_BOOLEAN) {
3341         Value->Type = EFI_IFR_TYPE_UNDEFINED;
3342         break;
3343       }
3344 
3345       if (Data1.Type != EFI_IFR_TYPE_BOOLEAN) {
3346         Value->Type = EFI_IFR_TYPE_UNDEFINED;
3347         break;
3348       }
3349 
3350       if (OpCode->Operand == EFI_IFR_AND_OP) {
3351         Value->Value.b = (BOOLEAN) (Data1.Value.b && Data2.Value.b);
3352       } else {
3353         Value->Value.b = (BOOLEAN) (Data1.Value.b || Data2.Value.b);
3354       }
3355       break;
3356 
3357     case EFI_IFR_EQUAL_OP:
3358     case EFI_IFR_NOT_EQUAL_OP:
3359     case EFI_IFR_GREATER_EQUAL_OP:
3360     case EFI_IFR_GREATER_THAN_OP:
3361     case EFI_IFR_LESS_EQUAL_OP:
3362     case EFI_IFR_LESS_THAN_OP:
3363       //
3364       // Compare two integer, string, boolean or date/time
3365       //
3366       Status = PopExpression (&Data2);
3367       if (EFI_ERROR (Status)) {
3368         goto Done;
3369       }
3370 
3371       //
3372       // Pop another expression from the expression stack
3373       //
3374       Status = PopExpression (&Data1);
3375       if (EFI_ERROR (Status)) {
3376         goto Done;
3377       }
3378 
3379       if (Data2.Type > EFI_IFR_TYPE_BOOLEAN &&
3380           Data2.Type != EFI_IFR_TYPE_STRING &&
3381           !IsTypeInBuffer(&Data2)) {
3382         Value->Type = EFI_IFR_TYPE_UNDEFINED;
3383         break;
3384       }
3385 
3386       if (Data1.Type > EFI_IFR_TYPE_BOOLEAN &&
3387           Data1.Type != EFI_IFR_TYPE_STRING &&
3388           !IsTypeInBuffer(&Data1)) {
3389         Value->Type = EFI_IFR_TYPE_UNDEFINED;
3390         break;
3391       }
3392 
3393       Status = CompareHiiValue (&Data1, &Data2, &Result, FormSet->HiiHandle);
3394       if (Data1.Type == EFI_IFR_TYPE_BUFFER) {
3395         FreePool (Data1.Buffer);
3396       }
3397       if (Data2.Type == EFI_IFR_TYPE_BUFFER) {
3398         FreePool (Data2.Buffer);
3399       }
3400 
3401       if (Status == EFI_UNSUPPORTED) {
3402         Value->Type = EFI_IFR_TYPE_UNDEFINED;
3403         Status = EFI_SUCCESS;
3404         break;
3405       }
3406 
3407       if (EFI_ERROR (Status)) {
3408         goto Done;
3409       }
3410 
3411       switch (OpCode->Operand) {
3412       case EFI_IFR_EQUAL_OP:
3413         Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE);
3414         break;
3415 
3416       case EFI_IFR_NOT_EQUAL_OP:
3417         Value->Value.b = (BOOLEAN) ((Result != 0) ? TRUE : FALSE);
3418         break;
3419 
3420       case EFI_IFR_GREATER_EQUAL_OP:
3421         Value->Value.b = (BOOLEAN) ((Result >= 0) ? TRUE : FALSE);
3422         break;
3423 
3424       case EFI_IFR_GREATER_THAN_OP:
3425         Value->Value.b = (BOOLEAN) ((Result > 0) ? TRUE : FALSE);
3426         break;
3427 
3428       case EFI_IFR_LESS_EQUAL_OP:
3429         Value->Value.b = (BOOLEAN) ((Result <= 0) ? TRUE : FALSE);
3430         break;
3431 
3432       case EFI_IFR_LESS_THAN_OP:
3433         Value->Value.b = (BOOLEAN) ((Result < 0) ? TRUE : FALSE);
3434         break;
3435 
3436       default:
3437         break;
3438       }
3439       break;
3440 
3441     case EFI_IFR_MATCH_OP:
3442       Status = InitializeUnicodeCollationProtocol ();
3443       if (EFI_ERROR (Status)) {
3444         goto Done;
3445       }
3446 
3447       Status = IfrMatch (FormSet, Value);
3448       break;
3449 
3450     case EFI_IFR_MATCH2_OP:
3451       Status = IfrMatch2 (FormSet, &OpCode->Guid, Value);
3452       break;
3453 
3454     case EFI_IFR_CATENATE_OP:
3455       Status = IfrCatenate (FormSet, Value);
3456       break;
3457 
3458     //
3459     // ternary-op
3460     //
3461     case EFI_IFR_CONDITIONAL_OP:
3462       //
3463       // Pop third expression from the expression stack
3464       //
3465       Status = PopExpression (&Data3);
3466       if (EFI_ERROR (Status)) {
3467         goto Done;
3468       }
3469 
3470       //
3471       // Pop second expression from the expression stack
3472       //
3473       Status = PopExpression (&Data2);
3474       if (EFI_ERROR (Status)) {
3475         goto Done;
3476       }
3477 
3478       //
3479       // Pop first expression from the expression stack
3480       //
3481       Status = PopExpression (&Data1);
3482       if (EFI_ERROR (Status)) {
3483         goto Done;
3484       }
3485       if (Data1.Type != EFI_IFR_TYPE_BOOLEAN) {
3486         Value->Type = EFI_IFR_TYPE_UNDEFINED;
3487         break;
3488       }
3489 
3490       if (Data1.Value.b) {
3491         Value = &Data3;
3492       } else {
3493         Value = &Data2;
3494       }
3495       break;
3496 
3497     case EFI_IFR_FIND_OP:
3498       Status = IfrFind (FormSet, OpCode->Format, Value);
3499       break;
3500 
3501     case EFI_IFR_MID_OP:
3502       Status = IfrMid (FormSet, Value);
3503       break;
3504 
3505     case EFI_IFR_TOKEN_OP:
3506       Status = IfrToken (FormSet, Value);
3507       break;
3508 
3509     case EFI_IFR_SPAN_OP:
3510       Status = IfrSpan (FormSet, OpCode->Flags, Value);
3511       break;
3512 
3513     case EFI_IFR_MAP_OP:
3514       //
3515       // Pop the check value
3516       //
3517       Status = PopExpression (&Data1);
3518       if (EFI_ERROR (Status)) {
3519         goto Done;
3520       }
3521       //
3522       // Check MapExpression list is valid.
3523       //
3524       if (OpCode->MapExpressionList.ForwardLink == NULL) {
3525         Status = EFI_INVALID_PARAMETER;
3526         goto Done;
3527       }
3528       //
3529       // Go through map expression list.
3530       //
3531       SubExpressionLink = GetFirstNode(&OpCode->MapExpressionList);
3532       while (!IsNull (&OpCode->MapExpressionList, SubExpressionLink)) {
3533         SubExpression = FORM_EXPRESSION_FROM_LINK (SubExpressionLink);
3534         //
3535         // Evaluate the first expression in this pair.
3536         //
3537         Status = EvaluateExpression (FormSet, Form, SubExpression);
3538         if (EFI_ERROR (Status)) {
3539           goto Done;
3540         }
3541         //
3542         // Compare the expression value with current value
3543         //
3544         if ((CompareHiiValue (&Data1, &SubExpression->Result, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) {
3545           //
3546           // Try get the map value.
3547           //
3548           SubExpressionLink = GetNextNode (&OpCode->MapExpressionList, SubExpressionLink);
3549           if (IsNull (&OpCode->MapExpressionList, SubExpressionLink)) {
3550             Status = EFI_INVALID_PARAMETER;
3551             goto Done;
3552           }
3553           SubExpression = FORM_EXPRESSION_FROM_LINK (SubExpressionLink);
3554           Status = EvaluateExpression (FormSet, Form, SubExpression);
3555           if (EFI_ERROR (Status)) {
3556             goto Done;
3557           }
3558           Value = &SubExpression->Result;
3559           break;
3560         }
3561         //
3562         // Skip the second expression on this pair.
3563         //
3564         SubExpressionLink = GetNextNode (&OpCode->MapExpressionList, SubExpressionLink);
3565         if (IsNull (&OpCode->MapExpressionList, SubExpressionLink)) {
3566           Status = EFI_INVALID_PARAMETER;
3567           goto Done;
3568         }
3569         //
3570         // Goto the first expression on next pair.
3571         //
3572         SubExpressionLink = GetNextNode (&OpCode->MapExpressionList, SubExpressionLink);
3573       }
3574 
3575       //
3576       // No map value is found.
3577       //
3578       if (IsNull (&OpCode->MapExpressionList, SubExpressionLink)) {
3579         Value->Type = EFI_IFR_TYPE_UNDEFINED;
3580         Value->Value.u8 = 0;
3581       }
3582       break;
3583 
3584     default:
3585       break;
3586     }
3587     if (EFI_ERROR (Status) || Value->Type == EFI_IFR_TYPE_UNDEFINED) {
3588       goto Done;
3589     }
3590 
3591     Status = PushExpression (Value);
3592     if (EFI_ERROR (Status)) {
3593       goto Done;
3594     }
3595   }
3596 
3597   //
3598   // Pop the final result from expression stack
3599   //
3600   Value = &Data1;
3601   Status = PopExpression (Value);
3602   if (EFI_ERROR (Status)) {
3603     goto Done;
3604   }
3605 
3606   //
3607   // After evaluating an expression, there should be only one value left on the expression stack
3608   //
3609   if (PopExpression (Value) != EFI_ACCESS_DENIED) {
3610     Status = EFI_INVALID_PARAMETER;
3611   }
3612 
3613 Done:
3614   RestoreExpressionEvaluationStackOffset (StackOffset);
3615   if (!EFI_ERROR (Status)) {
3616     CopyMem (&Expression->Result, Value, sizeof (EFI_HII_VALUE));
3617   }
3618 
3619   return Status;
3620 }
3621 
3622 /**
3623   Check whether the result is TRUE or FALSE.
3624 
3625   For the EFI_HII_VALUE value type is numeric, return TRUE if the
3626   value is not 0.
3627 
3628   @param  Result             Input the result data.
3629 
3630   @retval TRUE               The result is TRUE.
3631   @retval FALSE              The result is FALSE.
3632 
3633 **/
3634 BOOLEAN
IsTrue(IN EFI_HII_VALUE * Result)3635 IsTrue (
3636   IN EFI_HII_VALUE     *Result
3637   )
3638 {
3639   switch (Result->Type) {
3640   case EFI_IFR_TYPE_BOOLEAN:
3641     return Result->Value.b;
3642 
3643   case EFI_IFR_TYPE_NUM_SIZE_8:
3644     return (BOOLEAN)(Result->Value.u8 != 0);
3645 
3646   case EFI_IFR_TYPE_NUM_SIZE_16:
3647     return (BOOLEAN)(Result->Value.u16 != 0);
3648 
3649   case EFI_IFR_TYPE_NUM_SIZE_32:
3650     return (BOOLEAN)(Result->Value.u32 != 0);
3651 
3652   case EFI_IFR_TYPE_NUM_SIZE_64:
3653     return (BOOLEAN)(Result->Value.u64 != 0);
3654 
3655   default:
3656     return FALSE;
3657   }
3658 }
3659 
3660 /**
3661   Return the result of the expression list. Check the expression list and
3662   return the highest priority express result.
3663   Priority: DisableIf > SuppressIf > GrayOutIf > FALSE
3664 
3665   @param  ExpList             The input expression list.
3666   @param  Evaluate            Whether need to evaluate the expression first.
3667   @param  FormSet             FormSet associated with this expression.
3668   @param  Form                Form associated with this expression.
3669 
3670   @retval EXPRESS_RESULT      Return the higher priority express result.
3671                               DisableIf > SuppressIf > GrayOutIf > FALSE
3672 
3673 **/
3674 EXPRESS_RESULT
EvaluateExpressionList(IN FORM_EXPRESSION_LIST * ExpList,IN BOOLEAN Evaluate,IN FORM_BROWSER_FORMSET * FormSet,OPTIONAL IN FORM_BROWSER_FORM * Form OPTIONAL)3675 EvaluateExpressionList (
3676   IN FORM_EXPRESSION_LIST *ExpList,
3677   IN BOOLEAN              Evaluate,
3678   IN FORM_BROWSER_FORMSET *FormSet, OPTIONAL
3679   IN FORM_BROWSER_FORM    *Form OPTIONAL
3680   )
3681 {
3682   UINTN              Index;
3683   EXPRESS_RESULT     ReturnVal;
3684   EXPRESS_RESULT     CompareOne;
3685   EFI_STATUS         Status;
3686 
3687   if (ExpList == NULL) {
3688     return ExpressFalse;
3689   }
3690 
3691   ASSERT(ExpList->Signature == FORM_EXPRESSION_LIST_SIGNATURE);
3692   Index     = 0;
3693 
3694   //
3695   // Check whether need to evaluate the expression first.
3696   //
3697   if (Evaluate) {
3698     while (ExpList->Count > Index) {
3699       Status = EvaluateExpression (FormSet, Form, ExpList->Expression[Index++]);
3700       if (EFI_ERROR (Status)) {
3701         return ExpressFalse;
3702       }
3703     }
3704   }
3705 
3706   //
3707   // Run the list of expressions.
3708   //
3709   ReturnVal = ExpressFalse;
3710   for (Index = 0; Index < ExpList->Count; Index++) {
3711     if (IsTrue (&ExpList->Expression[Index]->Result)) {
3712       switch (ExpList->Expression[Index]->Type) {
3713         case EFI_HII_EXPRESSION_SUPPRESS_IF:
3714           CompareOne = ExpressSuppress;
3715           break;
3716 
3717         case EFI_HII_EXPRESSION_GRAY_OUT_IF:
3718           CompareOne = ExpressGrayOut;
3719           break;
3720 
3721         case EFI_HII_EXPRESSION_DISABLE_IF:
3722           CompareOne = ExpressDisable;
3723           break;
3724 
3725         default:
3726           return ExpressFalse;
3727       }
3728 
3729       ReturnVal = ReturnVal < CompareOne ? CompareOne : ReturnVal;
3730     }
3731   }
3732 
3733   return ReturnVal;
3734 }
3735