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