blob: e8829c1855fcbe50ca683893452345f6204e21b2 [file] [log] [blame]
Vishal Bhoj82c80712015-12-15 21:13:33 +05301/** @file
2Utility functions for expression evaluation.
3
4Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
5This program and the accompanying materials
6are licensed and made available under the terms and conditions of the BSD License
7which accompanies this distribution. The full text of the license may be found at
8http://opensource.org/licenses/bsd-license.php
9
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11WITHOUT 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//
20EFI_HII_VALUE *mOpCodeScopeStack = NULL;
21EFI_HII_VALUE *mOpCodeScopeStackEnd = NULL;
22EFI_HII_VALUE *mOpCodeScopeStackPointer = NULL;
23
24EFI_HII_VALUE *mExpressionEvaluationStack = NULL;
25EFI_HII_VALUE *mExpressionEvaluationStackEnd = NULL;
26EFI_HII_VALUE *mExpressionEvaluationStackPointer = NULL;
27UINTN mExpressionEvaluationStackOffset = 0;
28
29EFI_HII_VALUE *mCurrentExpressionStack = NULL;
30EFI_HII_VALUE *mCurrentExpressionEnd = NULL;
31EFI_HII_VALUE *mCurrentExpressionPointer = NULL;
32
33EFI_HII_VALUE *mMapExpressionListStack = NULL;
34EFI_HII_VALUE *mMapExpressionListEnd = NULL;
35EFI_HII_VALUE *mMapExpressionListPointer = NULL;
36
37FORM_EXPRESSION **mFormExpressionStack = NULL;
38FORM_EXPRESSION **mFormExpressionEnd = NULL;
39FORM_EXPRESSION **mFormExpressionPointer = NULL;
40
41FORM_EXPRESSION **mStatementExpressionStack = NULL;
42FORM_EXPRESSION **mStatementExpressionEnd = NULL;
43FORM_EXPRESSION **mStatementExpressionPointer = NULL;
44
45FORM_EXPRESSION **mOptionExpressionStack = NULL;
46FORM_EXPRESSION **mOptionExpressionEnd = NULL;
47FORM_EXPRESSION **mOptionExpressionPointer = NULL;
48
49
50//
51// Unicode collation protocol interface
52//
53EFI_UNICODE_COLLATION_PROTOCOL *mUnicodeCollation = NULL;
54EFI_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**/
70EFI_STATUS
71GrowStack (
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**/
129EFI_STATUS
130PushStack (
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**/
178EFI_STATUS
179PopStack (
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**/
205VOID
206ResetCurrentExpressionStack (
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**/
226EFI_STATUS
227PushCurrentExpression (
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**/
254EFI_STATUS
255PopCurrentExpression (
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**/
277VOID
278ResetMapExpressionListStack (
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**/
301EFI_STATUS
302GrowConditionalStack (
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**/
360EFI_STATUS
361PushConditionalStack (
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**/
404EFI_STATUS
405PopConditionalStack (
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**/
437INTN
438GetConditionalExpressionCount (
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**/
464FORM_EXPRESSION **
465GetConditionalExpressionList (
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**/
494EFI_STATUS
495PushConditionalExpression (
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**/
538EFI_STATUS
539PopConditionalExpression (
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**/
583EFI_STATUS
584PushMapExpressionList (
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**/
611EFI_STATUS
612PopMapExpressionList (
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**/
634VOID
635ResetScopeStack (
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**/
653EFI_STATUS
654PushScope (
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**/
682EFI_STATUS
683PopScope (
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**/
712EFI_STATUS
713PushExpression (
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**/
735EFI_STATUS
736PopExpression (
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**/
752UINTN
753SaveExpressionEvaluationStackOffset (
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**/
768VOID
769RestoreExpressionEvaluationStackOffset (
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**/
786FORM_BROWSER_FORM *
787IdToForm (
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**/
820FORM_BROWSER_STATEMENT *
821IdToQuestion2 (
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**/
862FORM_BROWSER_STATEMENT *
863IdToQuestion (
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**/
917FORM_EXPRESSION *
918RuleIdToExpression (
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**/
948EFI_STATUS
949InitializeUnicodeCollationProtocol (
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**/
978VOID
979IfrStrToUpper (
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**/
1003BOOLEAN
1004IsTypeInBuffer (
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**/
1029BOOLEAN
1030IsTypeInUINT64 (
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**/
1058UINT16
1059GetLengthForValue (
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**/
1092UINT8 *
1093GetBufferForValue (
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**/
1126EFI_STATUS
1127IfrToString (
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**/
1239EFI_STATUS
1240IfrToUint (
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**/
1312EFI_STATUS
1313IfrCatenate (
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
1328 //
1329 // String[0] - The second string
1330 // String[1] - The first string
1331 //
1332 String[0] = NULL;
1333 String[1] = NULL;
1334 StringPtr = NULL;
1335 Status = EFI_SUCCESS;
1336 ZeroMem (Value, sizeof (Value));
1337
1338 Status = PopExpression (&Value[0]);
1339 if (EFI_ERROR (Status)) {
1340 goto Done;
1341 }
1342
1343 Status = PopExpression (&Value[1]);
1344 if (EFI_ERROR (Status)) {
1345 goto Done;
1346 }
1347
1348 for (Index = 0; Index < 2; Index++) {
1349 if (Value[Index].Type != EFI_IFR_TYPE_STRING && !IsTypeInBuffer(&Value[Index])) {
1350 Result->Type = EFI_IFR_TYPE_UNDEFINED;
1351 Status = EFI_SUCCESS;
1352 goto Done;
1353 }
1354
1355 if (Value[Index].Type == EFI_IFR_TYPE_STRING) {
1356 String[Index] = GetToken (Value[Index].Value.string, FormSet->HiiHandle);
1357 if (String[Index] == NULL) {
1358 Status = EFI_NOT_FOUND;
1359 goto Done;
1360 }
1361 }
1362 }
1363
1364 if (Value[0].Type == EFI_IFR_TYPE_STRING) {
1365 Size = StrSize (String[0]);
1366 StringPtr= AllocatePool (StrSize (String[1]) + Size);
1367 ASSERT (StringPtr != NULL);
1368 StrCpy (StringPtr, String[1]);
1369 StrCat (StringPtr, String[0]);
1370
1371 Result->Type = EFI_IFR_TYPE_STRING;
1372 Result->Value.string = NewString (StringPtr, FormSet->HiiHandle);
1373 } else {
1374 Result->Type = EFI_IFR_TYPE_BUFFER;
1375 Length0 = GetLengthForValue(&Value[0]);
1376 Length1 = GetLengthForValue(&Value[1]);
1377 Result->BufferLen = (UINT16) (Length0 + Length1);
1378
1379 Result->Buffer = AllocateZeroPool (Result->BufferLen);
1380 ASSERT (Result->Buffer != NULL);
1381
1382 TmpBuf = GetBufferForValue(&Value[0]);
1383 ASSERT (TmpBuf != NULL);
1384 CopyMem (Result->Buffer, TmpBuf, Length0);
1385 TmpBuf = GetBufferForValue(&Value[1]);
1386 ASSERT (TmpBuf != NULL);
1387 CopyMem (&Result->Buffer[Length0], TmpBuf, Length1);
1388 }
1389Done:
1390 if (Value[0].Buffer != NULL) {
1391 FreePool (Value[0].Buffer);
1392 }
1393 if (Value[1].Buffer != NULL) {
1394 FreePool (Value[1].Buffer);
1395 }
1396 if (String[0] != NULL) {
1397 FreePool (String[0]);
1398 }
1399 if (String[1] != NULL) {
1400 FreePool (String[1]);
1401 }
1402 if (StringPtr != NULL) {
1403 FreePool (StringPtr);
1404 }
1405
1406 return Status;
1407}
1408
1409
1410/**
1411 Evaluate opcode EFI_IFR_MATCH.
1412
1413 @param FormSet Formset which contains this opcode.
1414 @param Result Evaluation result for this opcode.
1415
1416 @retval EFI_SUCCESS Opcode evaluation success.
1417 @retval Other Opcode evaluation failed.
1418
1419**/
1420EFI_STATUS
1421IfrMatch (
1422 IN FORM_BROWSER_FORMSET *FormSet,
1423 OUT EFI_HII_VALUE *Result
1424 )
1425{
1426 EFI_STATUS Status;
1427 EFI_HII_VALUE Value[2];
1428 CHAR16 *String[2];
1429 UINTN Index;
1430
1431 //
1432 // String[0] - The string to search
1433 // String[1] - pattern
1434 //
1435 String[0] = NULL;
1436 String[1] = NULL;
1437 Status = EFI_SUCCESS;
1438 ZeroMem (Value, sizeof (Value));
1439
1440 Status = PopExpression (&Value[0]);
1441 if (EFI_ERROR (Status)) {
1442 goto Done;
1443 }
1444
1445 Status = PopExpression (&Value[1]);
1446 if (EFI_ERROR (Status)) {
1447 goto Done;
1448 }
1449
1450 for (Index = 0; Index < 2; Index++) {
1451 if (Value[Index].Type != EFI_IFR_TYPE_STRING) {
1452 Result->Type = EFI_IFR_TYPE_UNDEFINED;
1453 Status = EFI_SUCCESS;
1454 goto Done;
1455 }
1456
1457 String[Index] = GetToken (Value[Index].Value.string, FormSet->HiiHandle);
1458 if (String [Index] == NULL) {
1459 Status = EFI_NOT_FOUND;
1460 goto Done;
1461 }
1462 }
1463
1464 Result->Type = EFI_IFR_TYPE_BOOLEAN;
1465 Result->Value.b = mUnicodeCollation->MetaiMatch (mUnicodeCollation, String[0], String[1]);
1466
1467Done:
1468 if (String[0] != NULL) {
1469 FreePool (String[0]);
1470 }
1471 if (String[1] != NULL) {
1472 FreePool (String[1]);
1473 }
1474
1475 return Status;
1476}
1477
1478
1479/**
1480 Evaluate opcode EFI_IFR_FIND.
1481
1482 @param FormSet Formset which contains this opcode.
1483 @param Format Case sensitive or insensitive.
1484 @param Result Evaluation result for this opcode.
1485
1486 @retval EFI_SUCCESS Opcode evaluation success.
1487 @retval Other Opcode evaluation failed.
1488
1489**/
1490EFI_STATUS
1491IfrFind (
1492 IN FORM_BROWSER_FORMSET *FormSet,
1493 IN UINT8 Format,
1494 OUT EFI_HII_VALUE *Result
1495 )
1496{
1497 EFI_STATUS Status;
1498 EFI_HII_VALUE Value[3];
1499 CHAR16 *String[2];
1500 UINTN Base;
1501 CHAR16 *StringPtr;
1502 UINTN Index;
1503
1504 ZeroMem (Value, sizeof (Value));
1505
1506 if (Format > EFI_IFR_FF_CASE_INSENSITIVE) {
1507 return EFI_INVALID_PARAMETER;
1508 }
1509
1510 Status = PopExpression (&Value[0]);
1511 if (EFI_ERROR (Status)) {
1512 return Status;
1513 }
1514
1515 Status = PopExpression (&Value[1]);
1516 if (EFI_ERROR (Status)) {
1517 return Status;
1518 }
1519
1520 Status = PopExpression (&Value[2]);
1521 if (EFI_ERROR (Status)) {
1522 return Status;
1523 }
1524
1525 if (Value[0].Type > EFI_IFR_TYPE_NUM_SIZE_64) {
1526 Result->Type = EFI_IFR_TYPE_UNDEFINED;
1527 return EFI_SUCCESS;
1528 }
1529 Base = (UINTN) Value[0].Value.u64;
1530
1531 //
1532 // String[0] - sub-string
1533 // String[1] - The string to search
1534 //
1535 String[0] = NULL;
1536 String[1] = NULL;
1537 for (Index = 0; Index < 2; Index++) {
1538 if (Value[Index + 1].Type != EFI_IFR_TYPE_STRING) {
1539 Result->Type = EFI_IFR_TYPE_UNDEFINED;
1540 Status = EFI_SUCCESS;
1541 goto Done;
1542 }
1543
1544 String[Index] = GetToken (Value[Index + 1].Value.string, FormSet->HiiHandle);
1545 if (String[Index] == NULL) {
1546 Status = EFI_NOT_FOUND;
1547 goto Done;
1548 }
1549
1550 if (Format == EFI_IFR_FF_CASE_INSENSITIVE) {
1551 //
1552 // Case insensitive, convert both string to upper case
1553 //
1554 IfrStrToUpper (String[Index]);
1555 }
1556 }
1557
1558 Result->Type = EFI_IFR_TYPE_NUM_SIZE_64;
1559 if (Base >= StrLen (String[1])) {
1560 Result->Value.u64 = 0xFFFFFFFFFFFFFFFFULL;
1561 } else {
1562 StringPtr = StrStr (String[1] + Base, String[0]);
1563 Result->Value.u64 = (StringPtr == NULL) ? 0xFFFFFFFFFFFFFFFFULL : (StringPtr - String[1]);
1564 }
1565
1566Done:
1567 if (String[0] != NULL) {
1568 FreePool (String[0]);
1569 }
1570 if (String[1] != NULL) {
1571 FreePool (String[1]);
1572 }
1573
1574 return Status;
1575}
1576
1577
1578/**
1579 Evaluate opcode EFI_IFR_MID.
1580
1581 @param FormSet Formset which contains this opcode.
1582 @param Result Evaluation result for this opcode.
1583
1584 @retval EFI_SUCCESS Opcode evaluation success.
1585 @retval Other Opcode evaluation failed.
1586
1587**/
1588EFI_STATUS
1589IfrMid (
1590 IN FORM_BROWSER_FORMSET *FormSet,
1591 OUT EFI_HII_VALUE *Result
1592 )
1593{
1594 EFI_STATUS Status;
1595 EFI_HII_VALUE Value[3];
1596 CHAR16 *String;
1597 UINTN Base;
1598 UINTN Length;
1599 CHAR16 *SubString;
1600 UINT16 BufferLen;
1601 UINT8 *Buffer;
1602
1603 ZeroMem (Value, sizeof (Value));
1604
1605 Status = PopExpression (&Value[0]);
1606 if (EFI_ERROR (Status)) {
1607 return Status;
1608 }
1609
1610 Status = PopExpression (&Value[1]);
1611 if (EFI_ERROR (Status)) {
1612 return Status;
1613 }
1614
1615 Status = PopExpression (&Value[2]);
1616 if (EFI_ERROR (Status)) {
1617 return Status;
1618 }
1619
1620 if (Value[0].Type > EFI_IFR_TYPE_NUM_SIZE_64) {
1621 Result->Type = EFI_IFR_TYPE_UNDEFINED;
1622 return EFI_SUCCESS;
1623 }
1624 Length = (UINTN) Value[0].Value.u64;
1625
1626 if (Value[1].Type > EFI_IFR_TYPE_NUM_SIZE_64) {
1627 Result->Type = EFI_IFR_TYPE_UNDEFINED;
1628 return EFI_SUCCESS;
1629 }
1630 Base = (UINTN) Value[1].Value.u64;
1631
1632 if (Value[2].Type != EFI_IFR_TYPE_STRING && !IsTypeInBuffer(&Value[2])) {
1633 Result->Type = EFI_IFR_TYPE_UNDEFINED;
1634 return EFI_SUCCESS;
1635 }
1636 if (Value[2].Type == EFI_IFR_TYPE_STRING) {
1637 String = GetToken (Value[2].Value.string, FormSet->HiiHandle);
1638 if (String == NULL) {
1639 return EFI_NOT_FOUND;
1640 }
1641
1642 if (Length == 0 || Base >= StrLen (String)) {
1643 SubString = gEmptyString;
1644 } else {
1645 SubString = String + Base;
1646 if ((Base + Length) < StrLen (String)) {
1647 SubString[Length] = L'\0';
1648 }
1649 }
1650
1651 Result->Type = EFI_IFR_TYPE_STRING;
1652 Result->Value.string = NewString (SubString, FormSet->HiiHandle);
1653
1654 FreePool (String);
1655 } else {
1656 BufferLen = GetLengthForValue (&Value[2]);
1657 Buffer = GetBufferForValue (&Value[2]);
1658
1659 Result->Type = EFI_IFR_TYPE_BUFFER;
1660 if (Length == 0 || Base >= BufferLen) {
1661 Result->BufferLen = 0;
1662 Result->Buffer = NULL;
1663 } else {
1664 Result->BufferLen = (UINT16)((BufferLen - Base) < Length ? (BufferLen - Base) : Length);
1665 Result->Buffer = AllocateZeroPool (Result->BufferLen);
1666 ASSERT (Result->Buffer != NULL);
1667 CopyMem (Result->Buffer, &Buffer[Base], Result->BufferLen);
1668 }
1669
1670 if (Value[2].Type == EFI_IFR_TYPE_BUFFER) {
1671 FreePool (Value[2].Buffer);
1672 }
1673 }
1674
1675 return Status;
1676}
1677
1678
1679/**
1680 Evaluate opcode EFI_IFR_TOKEN.
1681
1682 @param FormSet Formset which contains this opcode.
1683 @param Result Evaluation result for this opcode.
1684
1685 @retval EFI_SUCCESS Opcode evaluation success.
1686 @retval Other Opcode evaluation failed.
1687
1688**/
1689EFI_STATUS
1690IfrToken (
1691 IN FORM_BROWSER_FORMSET *FormSet,
1692 OUT EFI_HII_VALUE *Result
1693 )
1694{
1695 EFI_STATUS Status;
1696 EFI_HII_VALUE Value[3];
1697 CHAR16 *String[2];
1698 UINTN Count;
1699 CHAR16 *Delimiter;
1700 CHAR16 *SubString;
1701 CHAR16 *StringPtr;
1702 UINTN Index;
1703
1704 ZeroMem (Value, sizeof (Value));
1705
1706 Status = PopExpression (&Value[0]);
1707 if (EFI_ERROR (Status)) {
1708 return Status;
1709 }
1710
1711 Status = PopExpression (&Value[1]);
1712 if (EFI_ERROR (Status)) {
1713 return Status;
1714 }
1715
1716 Status = PopExpression (&Value[2]);
1717 if (EFI_ERROR (Status)) {
1718 return Status;
1719 }
1720
1721 if (Value[0].Type > EFI_IFR_TYPE_NUM_SIZE_64) {
1722 Result->Type = EFI_IFR_TYPE_UNDEFINED;
1723 return EFI_SUCCESS;
1724 }
1725 Count = (UINTN) Value[0].Value.u64;
1726
1727 //
1728 // String[0] - Delimiter
1729 // String[1] - The string to search
1730 //
1731 String[0] = NULL;
1732 String[1] = NULL;
1733 for (Index = 0; Index < 2; Index++) {
1734 if (Value[Index + 1].Type != EFI_IFR_TYPE_STRING) {
1735 Result->Type = EFI_IFR_TYPE_UNDEFINED;
1736 Status = EFI_SUCCESS;
1737 goto Done;
1738 }
1739
1740 String[Index] = GetToken (Value[Index + 1].Value.string, FormSet->HiiHandle);
1741 if (String[Index] == NULL) {
1742 Status = EFI_NOT_FOUND;
1743 goto Done;
1744 }
1745 }
1746
1747 Delimiter = String[0];
1748 SubString = String[1];
1749 while (Count > 0) {
1750 SubString = StrStr (SubString, Delimiter);
1751 if (SubString != NULL) {
1752 //
1753 // Skip over the delimiter
1754 //
1755 SubString = SubString + StrLen (Delimiter);
1756 } else {
1757 break;
1758 }
1759 Count--;
1760 }
1761
1762 if (SubString == NULL) {
1763 //
1764 // nth delimited sub-string not found, push an empty string
1765 //
1766 SubString = gEmptyString;
1767 } else {
1768 //
1769 // Put a NULL terminator for nth delimited sub-string
1770 //
1771 StringPtr = StrStr (SubString, Delimiter);
1772 if (StringPtr != NULL) {
1773 *StringPtr = L'\0';
1774 }
1775 }
1776
1777 Result->Type = EFI_IFR_TYPE_STRING;
1778 Result->Value.string = NewString (SubString, FormSet->HiiHandle);
1779
1780Done:
1781 if (String[0] != NULL) {
1782 FreePool (String[0]);
1783 }
1784 if (String[1] != NULL) {
1785 FreePool (String[1]);
1786 }
1787
1788 return Status;
1789}
1790
1791
1792/**
1793 Evaluate opcode EFI_IFR_SPAN.
1794
1795 @param FormSet Formset which contains this opcode.
1796 @param Flags FIRST_MATCHING or FIRST_NON_MATCHING.
1797 @param Result Evaluation result for this opcode.
1798
1799 @retval EFI_SUCCESS Opcode evaluation success.
1800 @retval Other Opcode evaluation failed.
1801
1802**/
1803EFI_STATUS
1804IfrSpan (
1805 IN FORM_BROWSER_FORMSET *FormSet,
1806 IN UINT8 Flags,
1807 OUT EFI_HII_VALUE *Result
1808 )
1809{
1810 EFI_STATUS Status;
1811 EFI_HII_VALUE Value[3];
1812 CHAR16 *String[2];
1813 CHAR16 *Charset;
1814 UINTN Base;
1815 UINTN Index;
1816 CHAR16 *StringPtr;
1817 BOOLEAN Found;
1818
1819 ZeroMem (Value, sizeof (Value));
1820
1821 Status = PopExpression (&Value[0]);
1822 if (EFI_ERROR (Status)) {
1823 return Status;
1824 }
1825
1826 Status = PopExpression (&Value[1]);
1827 if (EFI_ERROR (Status)) {
1828 return Status;
1829 }
1830
1831 Status = PopExpression (&Value[2]);
1832 if (EFI_ERROR (Status)) {
1833 return Status;
1834 }
1835
1836 if (Value[0].Type > EFI_IFR_TYPE_NUM_SIZE_64) {
1837 Result->Type = EFI_IFR_TYPE_UNDEFINED;
1838 return EFI_SUCCESS;
1839 }
1840 Base = (UINTN) Value[0].Value.u64;
1841
1842 //
1843 // String[0] - Charset
1844 // String[1] - The string to search
1845 //
1846 String[0] = NULL;
1847 String[1] = NULL;
1848 for (Index = 0; Index < 2; Index++) {
1849 if (Value[Index + 1].Type != EFI_IFR_TYPE_STRING) {
1850 Result->Type = EFI_IFR_TYPE_UNDEFINED;
1851 Status = EFI_SUCCESS;
1852 goto Done;
1853 }
1854
1855 String[Index] = GetToken (Value[Index + 1].Value.string, FormSet->HiiHandle);
1856 if (String [Index] == NULL) {
1857 Status = EFI_NOT_FOUND;
1858 goto Done;
1859 }
1860 }
1861
1862 if (Base >= StrLen (String[1])) {
1863 Result->Type = EFI_IFR_TYPE_UNDEFINED;
1864 Status = EFI_SUCCESS;
1865 goto Done;
1866 }
1867
1868 Found = FALSE;
1869 StringPtr = String[1] + Base;
1870 Charset = String[0];
1871 while (*StringPtr != 0 && !Found) {
1872 Index = 0;
1873 while (Charset[Index] != 0) {
1874 if (*StringPtr >= Charset[Index] && *StringPtr <= Charset[Index + 1]) {
1875 if (Flags == EFI_IFR_FLAGS_FIRST_MATCHING) {
1876 Found = TRUE;
1877 break;
1878 }
1879 } else {
1880 if (Flags == EFI_IFR_FLAGS_FIRST_NON_MATCHING) {
1881 Found = TRUE;
1882 break;
1883 }
1884 }
1885 //
1886 // Skip characters pair representing low-end of a range and high-end of a range
1887 //
1888 Index += 2;
1889 }
1890
1891 if (!Found) {
1892 StringPtr++;
1893 }
1894 }
1895
1896 Result->Type = EFI_IFR_TYPE_NUM_SIZE_64;
1897 Result->Value.u64 = StringPtr - String[1];
1898
1899Done:
1900 if (String[0] != NULL) {
1901 FreePool (String[0]);
1902 }
1903 if (String[1] != NULL) {
1904 FreePool (String[1]);
1905 }
1906
1907 return Status;
1908}
1909
1910
1911/**
1912 Zero extend integer/boolean/date/time to UINT64 for comparing.
1913
1914 @param Value HII Value to be converted.
1915
1916**/
1917VOID
1918ExtendValueToU64 (
1919 IN EFI_HII_VALUE *Value
1920 )
1921{
1922 UINT64 Temp;
1923
1924 Temp = 0;
1925 switch (Value->Type) {
1926 case EFI_IFR_TYPE_NUM_SIZE_8:
1927 Temp = Value->Value.u8;
1928 break;
1929
1930 case EFI_IFR_TYPE_NUM_SIZE_16:
1931 Temp = Value->Value.u16;
1932 break;
1933
1934 case EFI_IFR_TYPE_NUM_SIZE_32:
1935 Temp = Value->Value.u32;
1936 break;
1937
1938 case EFI_IFR_TYPE_BOOLEAN:
1939 Temp = Value->Value.b;
1940 break;
1941
1942 case EFI_IFR_TYPE_TIME:
1943 Temp = Value->Value.u32 & 0xffffff;
1944 break;
1945
1946 case EFI_IFR_TYPE_DATE:
1947 Temp = Value->Value.u32;
1948 break;
1949
1950 default:
1951 return;
1952 }
1953
1954 Value->Value.u64 = Temp;
1955}
1956
1957/**
1958 Get UINT64 type value.
1959
1960 @param Value Input Hii value.
1961
1962 @retval UINT64 Return the UINT64 type value.
1963
1964**/
1965UINT64
1966HiiValueToUINT64 (
1967 IN EFI_HII_VALUE *Value
1968 )
1969{
1970 UINT64 RetVal;
1971
1972 RetVal = 0;
1973
1974 switch (Value->Type) {
1975 case EFI_IFR_TYPE_NUM_SIZE_8:
1976 RetVal = Value->Value.u8;
1977 break;
1978
1979 case EFI_IFR_TYPE_NUM_SIZE_16:
1980 RetVal = Value->Value.u16;
1981 break;
1982
1983 case EFI_IFR_TYPE_NUM_SIZE_32:
1984 RetVal = Value->Value.u32;
1985 break;
1986
1987 case EFI_IFR_TYPE_BOOLEAN:
1988 RetVal = Value->Value.b;
1989 break;
1990
1991 case EFI_IFR_TYPE_DATE:
1992 RetVal = *(UINT64*) &Value->Value.date;
1993 break;
1994
1995 case EFI_IFR_TYPE_TIME:
1996 RetVal = (*(UINT64*) &Value->Value.time) & 0xffffff;
1997 break;
1998
1999 default:
2000 RetVal = Value->Value.u64;
2001 break;
2002 }
2003
2004 return RetVal;
2005}
2006
2007/**
2008 Compare two Hii value.
2009
2010 @param Value1 Expression value to compare on left-hand.
2011 @param Value2 Expression value to compare on right-hand.
2012 @param Result Return value after compare.
2013 retval 0 Two operators equal.
2014 return Positive value if Value1 is greater than Value2.
2015 retval Negative value if Value1 is less than Value2.
2016 @param HiiHandle Only required for string compare.
2017
2018 @retval other Could not perform compare on two values.
2019 @retval EFI_SUCCESS Compare the value success.
2020
2021**/
2022EFI_STATUS
2023CompareHiiValue (
2024 IN EFI_HII_VALUE *Value1,
2025 IN EFI_HII_VALUE *Value2,
2026 OUT INTN *Result,
2027 IN EFI_HII_HANDLE HiiHandle OPTIONAL
2028 )
2029{
2030 INT64 Temp64;
2031 CHAR16 *Str1;
2032 CHAR16 *Str2;
2033 UINTN Len;
2034 UINT8 *Buf1;
2035 UINT16 Buf1Len;
2036 UINT8 *Buf2;
2037 UINT16 Buf2Len;
2038
2039 if (Value1->Type == EFI_IFR_TYPE_STRING && Value2->Type == EFI_IFR_TYPE_STRING) {
2040 if (Value1->Value.string == 0 || Value2->Value.string == 0) {
2041 //
2042 // StringId 0 is reserved
2043 //
2044 return EFI_INVALID_PARAMETER;
2045 }
2046
2047 if (Value1->Value.string == Value2->Value.string) {
2048 *Result = 0;
2049 return EFI_SUCCESS;
2050 }
2051
2052 Str1 = GetToken (Value1->Value.string, HiiHandle);
2053 if (Str1 == NULL) {
2054 //
2055 // String not found
2056 //
2057 return EFI_NOT_FOUND;
2058 }
2059
2060 Str2 = GetToken (Value2->Value.string, HiiHandle);
2061 if (Str2 == NULL) {
2062 FreePool (Str1);
2063 return EFI_NOT_FOUND;
2064 }
2065
2066 *Result = StrCmp (Str1, Str2);
2067
2068 FreePool (Str1);
2069 FreePool (Str2);
2070
2071 return EFI_SUCCESS;
2072 }
2073
2074 //
2075 // Take types(date, time, ref, buffer) as buffer
2076 //
2077 if (IsTypeInBuffer(Value1) && IsTypeInBuffer(Value2)) {
2078 Buf1 = GetBufferForValue(Value1);
2079 Buf1Len = GetLengthForValue(Value1);
2080 Buf2 = GetBufferForValue(Value2);
2081 Buf2Len = GetLengthForValue(Value2);
2082
2083 Len = Buf1Len > Buf2Len ? Buf2Len : Buf1Len;
2084 *Result = CompareMem (Buf1, Buf2, Len);
2085 if ((*Result == 0) && (Buf1Len != Buf2Len)) {
2086 //
2087 // In this case, means base on samll number buffer, the data is same
2088 // So which value has more data, which value is bigger.
2089 //
2090 *Result = Buf1Len > Buf2Len ? 1 : -1;
2091 }
2092 return EFI_SUCCESS;
2093 }
2094
2095 //
2096 // Take types(integer, boolean) as integer
2097 //
2098 if (IsTypeInUINT64(Value1) && IsTypeInUINT64(Value2)) {
2099 Temp64 = HiiValueToUINT64(Value1) - HiiValueToUINT64(Value2);
2100 if (Temp64 > 0) {
2101 *Result = 1;
2102 } else if (Temp64 < 0) {
2103 *Result = -1;
2104 } else {
2105 *Result = 0;
2106 }
2107
2108 return EFI_SUCCESS;
2109 }
2110
2111 return EFI_UNSUPPORTED;
2112}
2113
2114/**
2115 Check if current user has the privilege specified by the permissions GUID.
2116
2117 @param[in] Guid A GUID specifying setup access permissions.
2118
2119 @retval TRUE Current user has the privilege.
2120 @retval FALSE Current user does not have the privilege.
2121**/
2122BOOLEAN
2123CheckUserPrivilege (
2124 IN EFI_GUID *Guid
2125 )
2126{
2127 EFI_STATUS Status;
2128 EFI_USER_PROFILE_HANDLE UserProfileHandle;
2129 EFI_USER_INFO_HANDLE UserInfoHandle;
2130 EFI_USER_INFO *UserInfo;
2131 EFI_GUID *UserPermissionsGuid;
2132 UINTN UserInfoSize;
2133 UINTN AccessControlDataSize;
2134 EFI_USER_INFO_ACCESS_CONTROL *AccessControl;
2135 UINTN RemainSize;
2136
2137 if (mUserManager == NULL) {
2138 Status = gBS->LocateProtocol (
2139 &gEfiUserManagerProtocolGuid,
2140 NULL,
2141 (VOID **) &mUserManager
2142 );
2143 if (EFI_ERROR (Status)) {
2144 ///
2145 /// If the system does not support user management, then it is assumed that
2146 /// all users have admin privilege and evaluation of each EFI_IFR_SECURITY
2147 /// op-code is always TRUE.
2148 ///
2149 return TRUE;
2150 }
2151 }
2152
2153 Status = mUserManager->Current (mUserManager, &UserProfileHandle);
2154 ASSERT_EFI_ERROR (Status);
2155
2156 ///
2157 /// Enumerate all user information of the current user profile
2158 /// to look for any EFI_USER_INFO_ACCESS_SETUP record.
2159 ///
2160
2161 for (UserInfoHandle = NULL;;) {
2162 Status = mUserManager->GetNextInfo (mUserManager, UserProfileHandle, &UserInfoHandle);
2163 if (EFI_ERROR (Status)) {
2164 break;
2165 }
2166
2167 UserInfoSize = 0;
2168 Status = mUserManager->GetInfo (mUserManager, UserProfileHandle, UserInfoHandle, NULL, &UserInfoSize);
2169 if (Status != EFI_BUFFER_TOO_SMALL) {
2170 continue;
2171 }
2172
2173 UserInfo = (EFI_USER_INFO *) AllocatePool (UserInfoSize);
2174 if (UserInfo == NULL) {
2175 break;
2176 }
2177
2178 Status = mUserManager->GetInfo (mUserManager, UserProfileHandle, UserInfoHandle, UserInfo, &UserInfoSize);
2179 if (EFI_ERROR (Status) ||
2180 UserInfo->InfoType != EFI_USER_INFO_ACCESS_POLICY_RECORD ||
2181 UserInfo->InfoSize <= sizeof (EFI_USER_INFO)) {
2182 FreePool (UserInfo);
2183 continue;
2184 }
2185
2186 RemainSize = UserInfo->InfoSize - sizeof (EFI_USER_INFO);
2187 AccessControl = (EFI_USER_INFO_ACCESS_CONTROL *)(UserInfo + 1);
2188 while (RemainSize >= sizeof (EFI_USER_INFO_ACCESS_CONTROL)) {
2189 if (RemainSize < AccessControl->Size || AccessControl->Size < sizeof (EFI_USER_INFO_ACCESS_CONTROL)) {
2190 break;
2191 }
2192 if (AccessControl->Type == EFI_USER_INFO_ACCESS_SETUP) {
2193 ///
2194 /// Check if current user has the privilege specified by the permissions GUID.
2195 ///
2196
2197 UserPermissionsGuid = (EFI_GUID *)(AccessControl + 1);
2198 AccessControlDataSize = AccessControl->Size - sizeof (EFI_USER_INFO_ACCESS_CONTROL);
2199 while (AccessControlDataSize >= sizeof (EFI_GUID)) {
2200 if (CompareGuid (Guid, UserPermissionsGuid)) {
2201 FreePool (UserInfo);
2202 return TRUE;
2203 }
2204 UserPermissionsGuid++;
2205 AccessControlDataSize -= sizeof (EFI_GUID);
2206 }
2207 }
2208 RemainSize -= AccessControl->Size;
2209 AccessControl = (EFI_USER_INFO_ACCESS_CONTROL *)((UINT8 *)AccessControl + AccessControl->Size);
2210 }
2211
2212 FreePool (UserInfo);
2213 }
2214 return FALSE;
2215}
2216
2217/**
2218 Get question value from the predefined formset.
2219
2220 @param DevicePath The driver's device path which produece the formset data.
2221 @param InputHiiHandle The hii handle associate with the formset data.
2222 @param FormSetGuid The formset guid which include the question.
2223 @param QuestionId The question id which need to get value from.
2224 @param Value The return data about question's value.
2225
2226 @retval TRUE Get the question value success.
2227 @retval FALSE Get the question value failed.
2228**/
2229BOOLEAN
2230GetQuestionValueFromForm (
2231 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
2232 IN EFI_HII_HANDLE InputHiiHandle,
2233 IN EFI_GUID *FormSetGuid,
2234 IN EFI_QUESTION_ID QuestionId,
2235 OUT EFI_HII_VALUE *Value
2236 )
2237{
2238 EFI_STATUS Status;
2239 EFI_HII_HANDLE HiiHandle;
2240 FORM_BROWSER_STATEMENT *Question;
2241 FORM_BROWSER_FORMSET *FormSet;
2242 FORM_BROWSER_FORM *Form;
2243 BOOLEAN GetTheVal;
2244 LIST_ENTRY *Link;
2245
2246 //
2247 // The input parameter DevicePath or InputHiiHandle must have one valid input.
2248 //
2249 ASSERT ((DevicePath != NULL && InputHiiHandle == NULL) ||
2250 (DevicePath == NULL && InputHiiHandle != NULL) );
2251
2252 GetTheVal = TRUE;
2253 HiiHandle = NULL;
2254 Question = NULL;
2255 Form = NULL;
2256
2257 //
2258 // Get HiiHandle.
2259 //
2260 if (DevicePath != NULL) {
2261 HiiHandle = DevicePathToHiiHandle (DevicePath, FormSetGuid);
2262 if (HiiHandle == NULL) {
2263 return FALSE;
2264 }
2265 } else {
2266 HiiHandle = InputHiiHandle;
2267 }
2268 ASSERT (HiiHandle != NULL);
2269
2270 //
2271 // Get the formset data include this question.
2272 //
2273 FormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET));
2274 ASSERT (FormSet != NULL);
2275 Status = InitializeFormSet(HiiHandle, FormSetGuid, FormSet);
2276 if (EFI_ERROR (Status)) {
2277 GetTheVal = FALSE;
2278 goto Done;
2279 }
2280
2281 //
2282 // Base on the Question Id to get the question info.
2283 //
2284 Question = IdToQuestion(FormSet, NULL, QuestionId);
2285 if (Question == NULL) {
2286 GetTheVal = FALSE;
2287 goto Done;
2288 }
2289
2290 //
2291 // Search form in the formset scope
2292 //
2293 Link = GetFirstNode (&FormSet->FormListHead);
2294 while (!IsNull (&FormSet->FormListHead, Link)) {
2295 Form = FORM_BROWSER_FORM_FROM_LINK (Link);
2296
2297 Question = IdToQuestion2 (Form, QuestionId);
2298 if (Question != NULL) {
2299 break;
2300 }
2301
2302 Link = GetNextNode (&FormSet->FormListHead, Link);
2303 Form = NULL;
2304 }
2305 ASSERT (Form != NULL);
2306
2307 //
2308 // Get the question value.
2309 //
2310 Status = GetQuestionValue(FormSet, Form, Question, GetSetValueWithHiiDriver);
2311 if (EFI_ERROR (Status)) {
2312 GetTheVal = FALSE;
2313 goto Done;
2314 }
2315
2316 CopyMem (Value, &Question->HiiValue, sizeof (EFI_HII_VALUE));
2317
2318Done:
2319 //
2320 // Clean the formset structure and restore the global parameter.
2321 //
2322 if (FormSet != NULL) {
2323 DestroyFormSet (FormSet);
2324 }
2325
2326 return GetTheVal;
2327}
2328
2329/**
2330 Evaluate the result of a HII expression.
2331
2332 If Expression is NULL, then ASSERT.
2333
2334 @param FormSet FormSet associated with this expression.
2335 @param Form Form associated with this expression.
2336 @param Expression Expression to be evaluated.
2337
2338 @retval EFI_SUCCESS The expression evaluated successfuly
2339 @retval EFI_NOT_FOUND The Question which referenced by a QuestionId
2340 could not be found.
2341 @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the
2342 stack.
2343 @retval EFI_ACCESS_DENIED The pop operation underflowed the stack
2344 @retval EFI_INVALID_PARAMETER Syntax error with the Expression
2345
2346**/
2347EFI_STATUS
2348EvaluateExpression (
2349 IN FORM_BROWSER_FORMSET *FormSet,
2350 IN FORM_BROWSER_FORM *Form,
2351 IN OUT FORM_EXPRESSION *Expression
2352 )
2353{
2354 EFI_STATUS Status;
2355 LIST_ENTRY *Link;
2356 EXPRESSION_OPCODE *OpCode;
2357 FORM_BROWSER_STATEMENT *Question;
2358 FORM_BROWSER_STATEMENT *Question2;
2359 UINT16 Index;
2360 EFI_HII_VALUE Data1;
2361 EFI_HII_VALUE Data2;
2362 EFI_HII_VALUE Data3;
2363 FORM_EXPRESSION *RuleExpression;
2364 EFI_HII_VALUE *Value;
2365 INTN Result;
2366 CHAR16 *StrPtr;
2367 CHAR16 *NameValue;
2368 UINT32 TempValue;
2369 LIST_ENTRY *SubExpressionLink;
2370 FORM_EXPRESSION *SubExpression;
2371 UINTN StackOffset;
2372 UINTN TempLength;
2373 CHAR16 TempStr[5];
2374 UINT8 DigitUint8;
2375 UINT8 *TempBuffer;
2376 EFI_TIME EfiTime;
2377 EFI_HII_VALUE QuestionVal;
2378 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
2379
2380 StrPtr = NULL;
2381
2382 //
2383 // Save current stack offset.
2384 //
2385 StackOffset = SaveExpressionEvaluationStackOffset ();
2386
2387 ASSERT (Expression != NULL);
2388 Expression->Result.Type = EFI_IFR_TYPE_OTHER;
2389
2390 Link = GetFirstNode (&Expression->OpCodeListHead);
2391 while (!IsNull (&Expression->OpCodeListHead, Link)) {
2392 OpCode = EXPRESSION_OPCODE_FROM_LINK (Link);
2393
2394 Link = GetNextNode (&Expression->OpCodeListHead, Link);
2395
2396 ZeroMem (&Data1, sizeof (EFI_HII_VALUE));
2397 ZeroMem (&Data2, sizeof (EFI_HII_VALUE));
2398 ZeroMem (&Data3, sizeof (EFI_HII_VALUE));
2399
2400 Value = &Data3;
2401 Value->Type = EFI_IFR_TYPE_BOOLEAN;
2402 Status = EFI_SUCCESS;
2403
2404 switch (OpCode->Operand) {
2405 //
2406 // Built-in functions
2407 //
2408 case EFI_IFR_EQ_ID_VAL_OP:
2409 Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);
2410 if (Question == NULL) {
2411 Value->Type = EFI_IFR_TYPE_UNDEFINED;
2412 break;
2413 }
2414
2415 Status = CompareHiiValue (&Question->HiiValue, &OpCode->Value, &Result, NULL);
2416 if (Status == EFI_UNSUPPORTED) {
2417 Status = EFI_SUCCESS;
2418 Value->Type = EFI_IFR_TYPE_UNDEFINED;
2419 break;
2420 }
2421
2422 if (EFI_ERROR (Status)) {
2423 goto Done;
2424 }
2425 Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE);
2426 break;
2427
2428 case EFI_IFR_EQ_ID_ID_OP:
2429 Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);
2430 if (Question == NULL) {
2431 Value->Type = EFI_IFR_TYPE_UNDEFINED;
2432 break;
2433 }
2434
2435 Question2 = IdToQuestion (FormSet, Form, OpCode->QuestionId2);
2436 if (Question2 == NULL) {
2437 Value->Type = EFI_IFR_TYPE_UNDEFINED;
2438 break;
2439 }
2440
2441 Status = CompareHiiValue (&Question->HiiValue, &Question2->HiiValue, &Result, FormSet->HiiHandle);
2442 if (Status == EFI_UNSUPPORTED) {
2443 Value->Type = EFI_IFR_TYPE_UNDEFINED;
2444 Status = EFI_SUCCESS;
2445 break;
2446 }
2447 if (EFI_ERROR (Status)) {
2448 goto Done;
2449 }
2450 Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE);
2451 break;
2452
2453 case EFI_IFR_EQ_ID_VAL_LIST_OP:
2454 Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);
2455 if (Question == NULL) {
2456 Value->Type = EFI_IFR_TYPE_UNDEFINED;
2457 break;
2458 }
2459
2460 Value->Value.b = FALSE;
2461 for (Index =0; Index < OpCode->ListLength; Index++) {
2462 if (Question->HiiValue.Value.u16 == OpCode->ValueList[Index]) {
2463 Value->Value.b = TRUE;
2464 break;
2465 }
2466 }
2467 break;
2468
2469 case EFI_IFR_DUP_OP:
2470 Status = PopExpression (Value);
2471 if (EFI_ERROR (Status)) {
2472 goto Done;
2473 }
2474
2475 Status = PushExpression (Value);
2476 break;
2477
2478 case EFI_IFR_QUESTION_REF1_OP:
2479 case EFI_IFR_THIS_OP:
2480 Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);
2481 if (Question == NULL) {
2482 Status = EFI_NOT_FOUND;
2483 goto Done;
2484 }
2485
2486 Value = &Question->HiiValue;
2487 break;
2488
2489 case EFI_IFR_SECURITY_OP:
2490 Value->Value.b = CheckUserPrivilege (&OpCode->Guid);
2491 break;
2492
2493 case EFI_IFR_GET_OP:
2494 //
2495 // Get Value from VarStore buffer, EFI VarStore, Name/Value VarStore.
2496 //
2497 Value->Type = EFI_IFR_TYPE_UNDEFINED;
2498 Value->Value.u8 = 0;
2499 if (OpCode->VarStorage != NULL) {
2500 switch (OpCode->VarStorage->Type) {
2501 case EFI_HII_VARSTORE_BUFFER:
2502 case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:
2503 //
2504 // Get value from Edit Buffer
2505 //
2506 Value->Type = OpCode->ValueType;
2507 CopyMem (&Value->Value, OpCode->VarStorage->EditBuffer + OpCode->VarStoreInfo.VarOffset, OpCode->ValueWidth);
2508 break;
2509 case EFI_HII_VARSTORE_NAME_VALUE:
2510 if (OpCode->ValueType != EFI_IFR_TYPE_STRING) {
2511 //
2512 // Get value from string except for STRING value.
2513 //
2514 Status = GetValueByName (OpCode->VarStorage, OpCode->ValueName, &StrPtr, GetSetValueWithEditBuffer);
2515 if (!EFI_ERROR (Status)) {
2516 ASSERT (StrPtr != NULL);
2517 TempLength = StrLen (StrPtr);
2518 if (OpCode->ValueWidth >= ((TempLength + 1) / 2)) {
2519 Value->Type = OpCode->ValueType;
2520 TempBuffer = (UINT8 *) &Value->Value;
2521 ZeroMem (TempStr, sizeof (TempStr));
2522 for (Index = 0; Index < TempLength; Index ++) {
2523 TempStr[0] = StrPtr[TempLength - Index - 1];
2524 DigitUint8 = (UINT8) StrHexToUint64 (TempStr);
2525 if ((Index & 1) == 0) {
2526 TempBuffer [Index/2] = DigitUint8;
2527 } else {
2528 TempBuffer [Index/2] = (UINT8) ((DigitUint8 << 4) + TempBuffer [Index/2]);
2529 }
2530 }
2531 }
2532 }
2533 }
2534 break;
2535 case EFI_HII_VARSTORE_EFI_VARIABLE:
2536 //
2537 // Get value from variable.
2538 //
2539 TempLength = OpCode->ValueWidth;
2540 Value->Type = OpCode->ValueType;
2541 Status = gRT->GetVariable (
2542 OpCode->ValueName,
2543 &OpCode->VarStorage->Guid,
2544 NULL,
2545 &TempLength,
2546 &Value->Value
2547 );
2548 if (EFI_ERROR (Status)) {
2549 Value->Type = EFI_IFR_TYPE_UNDEFINED;
2550 Value->Value.u8 = 0;
2551 }
2552 break;
2553 default:
2554 //
2555 // Not recognize storage.
2556 //
2557 Status = EFI_UNSUPPORTED;
2558 goto Done;
2559 }
2560 } else {
2561 //
2562 // For Time/Date Data
2563 //
2564 if (OpCode->ValueType != EFI_IFR_TYPE_DATE && OpCode->ValueType != EFI_IFR_TYPE_TIME) {
2565 //
2566 // Only support Data/Time data when storage doesn't exist.
2567 //
2568 Status = EFI_UNSUPPORTED;
2569 goto Done;
2570 }
2571 Status = gRT->GetTime (&EfiTime, NULL);
2572 if (!EFI_ERROR (Status)) {
2573 if (OpCode->ValueType == EFI_IFR_TYPE_DATE) {
2574 switch (OpCode->VarStoreInfo.VarOffset) {
2575 case 0x00:
2576 Value->Type = EFI_IFR_TYPE_NUM_SIZE_16;
2577 Value->Value.u16 = EfiTime.Year;
2578 break;
2579 case 0x02:
2580 Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
2581 Value->Value.u8 = EfiTime.Month;
2582 break;
2583 case 0x03:
2584 Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
2585 Value->Value.u8 = EfiTime.Day;
2586 break;
2587 default:
2588 //
2589 // Invalid Date field.
2590 //
2591 Status = EFI_INVALID_PARAMETER;
2592 goto Done;
2593 }
2594 } else {
2595 switch (OpCode->VarStoreInfo.VarOffset) {
2596 case 0x00:
2597 Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
2598 Value->Value.u8 = EfiTime.Hour;
2599 break;
2600 case 0x01:
2601 Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
2602 Value->Value.u8 = EfiTime.Minute;
2603 break;
2604 case 0x02:
2605 Value->Type = EFI_IFR_TYPE_NUM_SIZE_8;
2606 Value->Value.u8 = EfiTime.Second;
2607 break;
2608 default:
2609 //
2610 // Invalid Time field.
2611 //
2612 Status = EFI_INVALID_PARAMETER;
2613 goto Done;
2614 }
2615 }
2616 }
2617 }
2618
2619 break;
2620
2621 case EFI_IFR_QUESTION_REF3_OP:
2622 //
2623 // EFI_IFR_QUESTION_REF3
2624 // Pop an expression from the expression stack
2625 //
2626 Status = PopExpression (Value);
2627 if (EFI_ERROR (Status)) {
2628 goto Done;
2629 }
2630
2631 //
2632 // Validate the expression value
2633 //
2634 if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) {
2635 Value->Type = EFI_IFR_TYPE_UNDEFINED;
2636 break;
2637 }
2638
2639 if (OpCode->DevicePath != 0) {
2640 Value->Type = EFI_IFR_TYPE_UNDEFINED;
2641
2642 StrPtr = GetToken (OpCode->DevicePath, FormSet->HiiHandle);
2643 if (StrPtr != NULL && mPathFromText != NULL) {
2644 DevicePath = mPathFromText->ConvertTextToDevicePath(StrPtr);
2645 if (DevicePath != NULL && GetQuestionValueFromForm(DevicePath, NULL, &OpCode->Guid, Value->Value.u16, &QuestionVal)) {
2646 Value = &QuestionVal;
2647 }
2648 if (DevicePath != NULL) {
2649 FreePool (DevicePath);
2650 }
2651 }
2652
2653 if (StrPtr != NULL) {
2654 FreePool (StrPtr);
2655 }
2656 } else if (CompareGuid (&OpCode->Guid, &gZeroGuid) != 0) {
2657 if (!GetQuestionValueFromForm(NULL, FormSet->HiiHandle, &OpCode->Guid, Value->Value.u16, &QuestionVal)){
2658 Value->Type = EFI_IFR_TYPE_UNDEFINED;
2659 break;
2660 }
2661 Value = &QuestionVal;
2662 } else {
2663 Question = IdToQuestion (FormSet, Form, Value->Value.u16);
2664 if (Question == NULL) {
2665 Value->Type = EFI_IFR_TYPE_UNDEFINED;
2666 break;
2667 }
2668
2669 //
2670 // push the questions' value on to the expression stack
2671 //
2672 Value = &Question->HiiValue;
2673 }
2674 break;
2675
2676 case EFI_IFR_RULE_REF_OP:
2677 //
2678 // Find expression for this rule
2679 //
2680 RuleExpression = RuleIdToExpression (Form, OpCode->RuleId);
2681 if (RuleExpression == NULL) {
2682 Value->Type = EFI_IFR_TYPE_UNDEFINED;
2683 break;
2684 }
2685
2686 //
2687 // Evaluate this rule expression
2688 //
2689 Status = EvaluateExpression (FormSet, Form, RuleExpression);
2690 if (EFI_ERROR (Status) || RuleExpression->Result.Type == EFI_IFR_TYPE_UNDEFINED) {
2691 Value->Type = EFI_IFR_TYPE_UNDEFINED;
2692 break;
2693 }
2694
2695 Value = &RuleExpression->Result;
2696 break;
2697
2698 case EFI_IFR_STRING_REF1_OP:
2699 Value->Type = EFI_IFR_TYPE_STRING;
2700 Value->Value.string = OpCode->Value.Value.string;
2701 break;
2702
2703 //
2704 // Constant
2705 //
2706 case EFI_IFR_TRUE_OP:
2707 case EFI_IFR_FALSE_OP:
2708 case EFI_IFR_ONE_OP:
2709 case EFI_IFR_ONES_OP:
2710 case EFI_IFR_UINT8_OP:
2711 case EFI_IFR_UINT16_OP:
2712 case EFI_IFR_UINT32_OP:
2713 case EFI_IFR_UINT64_OP:
2714 case EFI_IFR_UNDEFINED_OP:
2715 case EFI_IFR_VERSION_OP:
2716 case EFI_IFR_ZERO_OP:
2717 Value = &OpCode->Value;
2718 break;
2719
2720 //
2721 // unary-op
2722 //
2723 case EFI_IFR_LENGTH_OP:
2724 Status = PopExpression (Value);
2725 if (EFI_ERROR (Status)) {
2726 goto Done;
2727 }
2728 if (Value->Type != EFI_IFR_TYPE_STRING && !IsTypeInBuffer (Value)) {
2729 Value->Type = EFI_IFR_TYPE_UNDEFINED;
2730 break;
2731 }
2732
2733 if (Value->Type == EFI_IFR_TYPE_STRING) {
2734 StrPtr = GetToken (Value->Value.string, FormSet->HiiHandle);
2735 if (StrPtr == NULL) {
2736 Status = EFI_INVALID_PARAMETER;
2737 goto Done;
2738 }
2739
2740 Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
2741 Value->Value.u64 = StrLen (StrPtr);
2742 FreePool (StrPtr);
2743 } else {
2744 Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
2745 Value->Value.u64 = GetLengthForValue(Value);
2746 FreePool (Value->Buffer);
2747 }
2748 break;
2749
2750 case EFI_IFR_NOT_OP:
2751 Status = PopExpression (Value);
2752 if (EFI_ERROR (Status)) {
2753 goto Done;
2754 }
2755 if (Value->Type != EFI_IFR_TYPE_BOOLEAN) {
2756 Value->Type = EFI_IFR_TYPE_UNDEFINED;
2757 break;
2758 }
2759 Value->Value.b = (BOOLEAN) (!Value->Value.b);
2760 break;
2761
2762 case EFI_IFR_QUESTION_REF2_OP:
2763 //
2764 // Pop an expression from the expression stack
2765 //
2766 Status = PopExpression (Value);
2767 if (EFI_ERROR (Status)) {
2768 goto Done;
2769 }
2770
2771 //
2772 // Validate the expression value
2773 //
2774 if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) {
2775 Value->Type = EFI_IFR_TYPE_UNDEFINED;
2776 break;
2777 }
2778
2779 Question = IdToQuestion (FormSet, Form, Value->Value.u16);
2780 if (Question == NULL) {
2781 Value->Type = EFI_IFR_TYPE_UNDEFINED;
2782 break;
2783 }
2784
2785 Value = &Question->HiiValue;
2786 break;
2787
2788 case EFI_IFR_STRING_REF2_OP:
2789 //
2790 // Pop an expression from the expression stack
2791 //
2792 Status = PopExpression (Value);
2793 if (EFI_ERROR (Status)) {
2794 goto Done;
2795 }
2796
2797 //
2798 // Validate the expression value
2799 //
2800 if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) {
2801 Value->Type = EFI_IFR_TYPE_UNDEFINED;
2802 break;
2803 }
2804
2805 Value->Type = EFI_IFR_TYPE_STRING;
2806 StrPtr = GetToken (Value->Value.u16, FormSet->HiiHandle);
2807 if (StrPtr == NULL) {
2808 //
2809 // If String not exit, push an empty string
2810 //
2811 Value->Value.string = NewString (gEmptyString, FormSet->HiiHandle);
2812 } else {
2813 Index = (UINT16) Value->Value.u64;
2814 Value->Value.string = Index;
2815 FreePool (StrPtr);
2816 }
2817 break;
2818
2819 case EFI_IFR_TO_BOOLEAN_OP:
2820 //
2821 // Pop an expression from the expression stack
2822 //
2823 Status = PopExpression (Value);
2824 if (EFI_ERROR (Status)) {
2825 goto Done;
2826 }
2827
2828 //
2829 // Convert an expression to a Boolean
2830 //
2831 if (Value->Type <= EFI_IFR_TYPE_DATE) {
2832 //
2833 // When converting from an unsigned integer, zero will be converted to
2834 // FALSE and any other value will be converted to TRUE.
2835 //
2836 Value->Value.b = (BOOLEAN) (HiiValueToUINT64(Value) != 0);
2837
2838 Value->Type = EFI_IFR_TYPE_BOOLEAN;
2839 } else if (Value->Type == EFI_IFR_TYPE_STRING) {
2840 //
2841 // When converting from a string, if case-insensitive compare
2842 // with "true" is True, then push True. If a case-insensitive compare
2843 // with "false" is True, then push False. Otherwise, push Undefined.
2844 //
2845 StrPtr = GetToken (Value->Value.string, FormSet->HiiHandle);
2846 if (StrPtr == NULL) {
2847 Status = EFI_INVALID_PARAMETER;
2848 goto Done;
2849 }
2850
2851 IfrStrToUpper (StrPtr);
2852 if (StrCmp (StrPtr, L"TRUE") == 0){
2853 Value->Value.b = TRUE;
2854 Value->Type = EFI_IFR_TYPE_BOOLEAN;
2855 } else if (StrCmp (StrPtr, L"FALSE") == 0) {
2856 Value->Value.b = FALSE;
2857 Value->Type = EFI_IFR_TYPE_BOOLEAN;
2858 } else {
2859 Value->Type = EFI_IFR_TYPE_UNDEFINED;
2860 }
2861 FreePool (StrPtr);
2862 } else if (Value->Type == EFI_IFR_TYPE_BUFFER) {
2863 //
2864 // When converting from a buffer, if the buffer is all zeroes,
2865 // then push False. Otherwise push True.
2866 //
2867 for (Index =0; Index < Value->BufferLen; Index ++) {
2868 if (Value->Buffer[Index] != 0) {
2869 break;
2870 }
2871 }
2872
2873 if (Index >= Value->BufferLen) {
2874 Value->Value.b = FALSE;
2875 } else {
2876 Value->Value.b = TRUE;
2877 }
2878 Value->Type = EFI_IFR_TYPE_BOOLEAN;
2879 FreePool (Value->Buffer);
2880 }
2881 break;
2882
2883 case EFI_IFR_TO_STRING_OP:
2884 Status = IfrToString (FormSet, OpCode->Format, Value);
2885 break;
2886
2887 case EFI_IFR_TO_UINT_OP:
2888 Status = IfrToUint (FormSet, Value);
2889 break;
2890
2891 case EFI_IFR_TO_LOWER_OP:
2892 case EFI_IFR_TO_UPPER_OP:
2893 Status = InitializeUnicodeCollationProtocol ();
2894 if (EFI_ERROR (Status)) {
2895 goto Done;
2896 }
2897
2898 Status = PopExpression (Value);
2899 if (EFI_ERROR (Status)) {
2900 goto Done;
2901 }
2902
2903 if (Value->Type != EFI_IFR_TYPE_STRING) {
2904 Value->Type = EFI_IFR_TYPE_UNDEFINED;
2905 break;
2906 }
2907
2908 StrPtr = GetToken (Value->Value.string, FormSet->HiiHandle);
2909 if (StrPtr == NULL) {
2910 Status = EFI_NOT_FOUND;
2911 goto Done;
2912 }
2913
2914 if (OpCode->Operand == EFI_IFR_TO_LOWER_OP) {
2915 mUnicodeCollation->StrLwr (mUnicodeCollation, StrPtr);
2916 } else {
2917 mUnicodeCollation->StrUpr (mUnicodeCollation, StrPtr);
2918 }
2919 Value->Value.string = NewString (StrPtr, FormSet->HiiHandle);
2920 FreePool (StrPtr);
2921 break;
2922
2923 case EFI_IFR_BITWISE_NOT_OP:
2924 //
2925 // Pop an expression from the expression stack
2926 //
2927 Status = PopExpression (Value);
2928 if (EFI_ERROR (Status)) {
2929 goto Done;
2930 }
2931 if (Value->Type > EFI_IFR_TYPE_DATE) {
2932 Value->Type = EFI_IFR_TYPE_UNDEFINED;
2933 break;
2934 }
2935
2936 Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
2937 Value->Value.u64 = ~ HiiValueToUINT64(Value);
2938 break;
2939
2940 case EFI_IFR_SET_OP:
2941 //
2942 // Pop an expression from the expression stack
2943 //
2944 Status = PopExpression (Value);
2945 if (EFI_ERROR (Status)) {
2946 goto Done;
2947 }
2948 Data1.Type = EFI_IFR_TYPE_BOOLEAN;
2949 Data1.Value.b = FALSE;
2950 //
2951 // Set value to var storage buffer
2952 //
2953 if (OpCode->VarStorage != NULL) {
2954 switch (OpCode->VarStorage->Type) {
2955 case EFI_HII_VARSTORE_BUFFER:
2956 case EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER:
2957 CopyMem (OpCode->VarStorage->EditBuffer + OpCode->VarStoreInfo.VarOffset, &Value->Value, OpCode->ValueWidth);
2958 Data1.Value.b = TRUE;
2959 break;
2960 case EFI_HII_VARSTORE_NAME_VALUE:
2961 if (OpCode->ValueType != EFI_IFR_TYPE_STRING) {
2962 NameValue = AllocateZeroPool ((OpCode->ValueWidth * 2 + 1) * sizeof (CHAR16));
2963 ASSERT (Value != NULL);
2964 //
2965 // Convert Buffer to Hex String
2966 //
2967 TempBuffer = (UINT8 *) &Value->Value + OpCode->ValueWidth - 1;
2968 StrPtr = NameValue;
2969 for (Index = 0; Index < OpCode->ValueWidth; Index ++, TempBuffer --) {
2970 StrPtr += UnicodeValueToString (StrPtr, PREFIX_ZERO | RADIX_HEX, *TempBuffer, 2);
2971 }
2972 Status = SetValueByName (OpCode->VarStorage, OpCode->ValueName, NameValue, GetSetValueWithEditBuffer, NULL);
2973 FreePool (NameValue);
2974 if (!EFI_ERROR (Status)) {
2975 Data1.Value.b = TRUE;
2976 }
2977 }
2978 break;
2979 case EFI_HII_VARSTORE_EFI_VARIABLE:
2980 Status = gRT->SetVariable (
2981 OpCode->ValueName,
2982 &OpCode->VarStorage->Guid,
2983 OpCode->VarStorage->Attributes,
2984 OpCode->ValueWidth,
2985 &Value->Value
2986 );
2987 if (!EFI_ERROR (Status)) {
2988 Data1.Value.b = TRUE;
2989 }
2990 break;
2991 default:
2992 //
2993 // Not recognize storage.
2994 //
2995 Status = EFI_UNSUPPORTED;
2996 goto Done;
2997 break;
2998 }
2999 } else {
3000 //
3001 // For Time/Date Data
3002 //
3003 if (OpCode->ValueType != EFI_IFR_TYPE_DATE && OpCode->ValueType != EFI_IFR_TYPE_TIME) {
3004 //
3005 // Only support Data/Time data when storage doesn't exist.
3006 //
3007 Status = EFI_UNSUPPORTED;
3008 goto Done;
3009 }
3010 Status = gRT->GetTime (&EfiTime, NULL);
3011 if (!EFI_ERROR (Status)) {
3012 if (OpCode->ValueType == EFI_IFR_TYPE_DATE) {
3013 switch (OpCode->VarStoreInfo.VarOffset) {
3014 case 0x00:
3015 EfiTime.Year = Value->Value.u16;
3016 break;
3017 case 0x02:
3018 EfiTime.Month = Value->Value.u8;
3019 break;
3020 case 0x03:
3021 EfiTime.Day = Value->Value.u8;
3022 break;
3023 default:
3024 //
3025 // Invalid Date field.
3026 //
3027 Status = EFI_INVALID_PARAMETER;
3028 goto Done;
3029 }
3030 } else {
3031 switch (OpCode->VarStoreInfo.VarOffset) {
3032 case 0x00:
3033 EfiTime.Hour = Value->Value.u8;
3034 break;
3035 case 0x01:
3036 EfiTime.Minute = Value->Value.u8;
3037 break;
3038 case 0x02:
3039 EfiTime.Second = Value->Value.u8;
3040 break;
3041 default:
3042 //
3043 // Invalid Time field.
3044 //
3045 Status = EFI_INVALID_PARAMETER;
3046 goto Done;
3047 }
3048 }
3049 Status = gRT->SetTime (&EfiTime);
3050 if (!EFI_ERROR (Status)) {
3051 Data1.Value.b = TRUE;
3052 }
3053 }
3054 }
3055 Value = &Data1;
3056 break;
3057
3058 //
3059 // binary-op
3060 //
3061 case EFI_IFR_ADD_OP:
3062 case EFI_IFR_SUBTRACT_OP:
3063 case EFI_IFR_MULTIPLY_OP:
3064 case EFI_IFR_DIVIDE_OP:
3065 case EFI_IFR_MODULO_OP:
3066 case EFI_IFR_BITWISE_AND_OP:
3067 case EFI_IFR_BITWISE_OR_OP:
3068 case EFI_IFR_SHIFT_LEFT_OP:
3069 case EFI_IFR_SHIFT_RIGHT_OP:
3070 //
3071 // Pop an expression from the expression stack
3072 //
3073 Status = PopExpression (&Data2);
3074 if (EFI_ERROR (Status)) {
3075 goto Done;
3076 }
3077
3078 //
3079 // Pop another expression from the expression stack
3080 //
3081 Status = PopExpression (&Data1);
3082 if (EFI_ERROR (Status)) {
3083 goto Done;
3084 }
3085
3086 if (Data2.Type > EFI_IFR_TYPE_DATE) {
3087 Value->Type = EFI_IFR_TYPE_UNDEFINED;
3088 break;
3089 }
3090
3091
3092 if (Data1.Type > EFI_IFR_TYPE_DATE) {
3093 Value->Type = EFI_IFR_TYPE_UNDEFINED;
3094 break;
3095 }
3096
3097 Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
3098
3099 switch (OpCode->Operand) {
3100 case EFI_IFR_ADD_OP:
3101 Value->Value.u64 = HiiValueToUINT64(&Data1) + HiiValueToUINT64(&Data2);
3102 break;
3103
3104 case EFI_IFR_SUBTRACT_OP:
3105 Value->Value.u64 = HiiValueToUINT64(&Data1) - HiiValueToUINT64(&Data2);
3106 break;
3107
3108 case EFI_IFR_MULTIPLY_OP:
3109 Value->Value.u64 = MultU64x32 (HiiValueToUINT64(&Data1), (UINT32) HiiValueToUINT64(&Data2));
3110 break;
3111
3112 case EFI_IFR_DIVIDE_OP:
3113 Value->Value.u64 = DivU64x32 (HiiValueToUINT64(&Data1), (UINT32) HiiValueToUINT64(&Data2));
3114 break;
3115
3116 case EFI_IFR_MODULO_OP:
3117 DivU64x32Remainder (HiiValueToUINT64(&Data1), (UINT32) HiiValueToUINT64(&Data2), &TempValue);
3118 Value->Value.u64 = TempValue;
3119 break;
3120
3121 case EFI_IFR_BITWISE_AND_OP:
3122 Value->Value.u64 = HiiValueToUINT64(&Data1) & HiiValueToUINT64(&Data2);
3123 break;
3124
3125 case EFI_IFR_BITWISE_OR_OP:
3126 Value->Value.u64 = HiiValueToUINT64(&Data1) | HiiValueToUINT64(&Data2);
3127 break;
3128
3129 case EFI_IFR_SHIFT_LEFT_OP:
3130 Value->Value.u64 = LShiftU64 (HiiValueToUINT64(&Data1), (UINTN) HiiValueToUINT64(&Data2));
3131 break;
3132
3133 case EFI_IFR_SHIFT_RIGHT_OP:
3134 Value->Value.u64 = RShiftU64 (HiiValueToUINT64(&Data1), (UINTN) HiiValueToUINT64(&Data2));
3135 break;
3136
3137 default:
3138 break;
3139 }
3140 break;
3141
3142 case EFI_IFR_AND_OP:
3143 case EFI_IFR_OR_OP:
3144 //
3145 // Two Boolean operator
3146 //
3147 Status = PopExpression (&Data2);
3148 if (EFI_ERROR (Status)) {
3149 goto Done;
3150 }
3151
3152 //
3153 // Pop another expression from the expression stack
3154 //
3155 Status = PopExpression (&Data1);
3156 if (EFI_ERROR (Status)) {
3157 goto Done;
3158 }
3159
3160 if (Data2.Type != EFI_IFR_TYPE_BOOLEAN) {
3161 Value->Type = EFI_IFR_TYPE_UNDEFINED;
3162 break;
3163 }
3164
3165 if (Data1.Type != EFI_IFR_TYPE_BOOLEAN) {
3166 Value->Type = EFI_IFR_TYPE_UNDEFINED;
3167 break;
3168 }
3169
3170 if (OpCode->Operand == EFI_IFR_AND_OP) {
3171 Value->Value.b = (BOOLEAN) (Data1.Value.b && Data2.Value.b);
3172 } else {
3173 Value->Value.b = (BOOLEAN) (Data1.Value.b || Data2.Value.b);
3174 }
3175 break;
3176
3177 case EFI_IFR_EQUAL_OP:
3178 case EFI_IFR_NOT_EQUAL_OP:
3179 case EFI_IFR_GREATER_EQUAL_OP:
3180 case EFI_IFR_GREATER_THAN_OP:
3181 case EFI_IFR_LESS_EQUAL_OP:
3182 case EFI_IFR_LESS_THAN_OP:
3183 //
3184 // Compare two integer, string, boolean or date/time
3185 //
3186 Status = PopExpression (&Data2);
3187 if (EFI_ERROR (Status)) {
3188 goto Done;
3189 }
3190
3191 //
3192 // Pop another expression from the expression stack
3193 //
3194 Status = PopExpression (&Data1);
3195 if (EFI_ERROR (Status)) {
3196 goto Done;
3197 }
3198
3199 if (Data2.Type > EFI_IFR_TYPE_BOOLEAN &&
3200 Data2.Type != EFI_IFR_TYPE_STRING &&
3201 !IsTypeInBuffer(&Data2)) {
3202 Value->Type = EFI_IFR_TYPE_UNDEFINED;
3203 break;
3204 }
3205
3206 if (Data1.Type > EFI_IFR_TYPE_BOOLEAN &&
3207 Data1.Type != EFI_IFR_TYPE_STRING &&
3208 !IsTypeInBuffer(&Data1)) {
3209 Value->Type = EFI_IFR_TYPE_UNDEFINED;
3210 break;
3211 }
3212
3213 Status = CompareHiiValue (&Data1, &Data2, &Result, FormSet->HiiHandle);
3214 if (Data1.Type == EFI_IFR_TYPE_BUFFER) {
3215 FreePool (Data1.Buffer);
3216 }
3217 if (Data2.Type == EFI_IFR_TYPE_BUFFER) {
3218 FreePool (Data2.Buffer);
3219 }
3220
3221 if (Status == EFI_UNSUPPORTED) {
3222 Value->Type = EFI_IFR_TYPE_UNDEFINED;
3223 Status = EFI_SUCCESS;
3224 break;
3225 }
3226
3227 if (EFI_ERROR (Status)) {
3228 goto Done;
3229 }
3230
3231 switch (OpCode->Operand) {
3232 case EFI_IFR_EQUAL_OP:
3233 Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE);
3234 break;
3235
3236 case EFI_IFR_NOT_EQUAL_OP:
3237 Value->Value.b = (BOOLEAN) ((Result != 0) ? TRUE : FALSE);
3238 break;
3239
3240 case EFI_IFR_GREATER_EQUAL_OP:
3241 Value->Value.b = (BOOLEAN) ((Result >= 0) ? TRUE : FALSE);
3242 break;
3243
3244 case EFI_IFR_GREATER_THAN_OP:
3245 Value->Value.b = (BOOLEAN) ((Result > 0) ? TRUE : FALSE);
3246 break;
3247
3248 case EFI_IFR_LESS_EQUAL_OP:
3249 Value->Value.b = (BOOLEAN) ((Result <= 0) ? TRUE : FALSE);
3250 break;
3251
3252 case EFI_IFR_LESS_THAN_OP:
3253 Value->Value.b = (BOOLEAN) ((Result < 0) ? TRUE : FALSE);
3254 break;
3255
3256 default:
3257 break;
3258 }
3259 break;
3260
3261 case EFI_IFR_MATCH_OP:
3262 Status = InitializeUnicodeCollationProtocol ();
3263 if (EFI_ERROR (Status)) {
3264 goto Done;
3265 }
3266
3267 Status = IfrMatch (FormSet, Value);
3268 break;
3269
3270 case EFI_IFR_CATENATE_OP:
3271 Status = IfrCatenate (FormSet, Value);
3272 break;
3273
3274 //
3275 // ternary-op
3276 //
3277 case EFI_IFR_CONDITIONAL_OP:
3278 //
3279 // Pop third expression from the expression stack
3280 //
3281 Status = PopExpression (&Data3);
3282 if (EFI_ERROR (Status)) {
3283 goto Done;
3284 }
3285
3286 //
3287 // Pop second expression from the expression stack
3288 //
3289 Status = PopExpression (&Data2);
3290 if (EFI_ERROR (Status)) {
3291 goto Done;
3292 }
3293
3294 //
3295 // Pop first expression from the expression stack
3296 //
3297 Status = PopExpression (&Data1);
3298 if (EFI_ERROR (Status)) {
3299 goto Done;
3300 }
3301 if (Data1.Type != EFI_IFR_TYPE_BOOLEAN) {
3302 Value->Type = EFI_IFR_TYPE_UNDEFINED;
3303 break;
3304 }
3305
3306 if (Data1.Value.b) {
3307 Value = &Data3;
3308 } else {
3309 Value = &Data2;
3310 }
3311 break;
3312
3313 case EFI_IFR_FIND_OP:
3314 Status = IfrFind (FormSet, OpCode->Format, Value);
3315 break;
3316
3317 case EFI_IFR_MID_OP:
3318 Status = IfrMid (FormSet, Value);
3319 break;
3320
3321 case EFI_IFR_TOKEN_OP:
3322 Status = IfrToken (FormSet, Value);
3323 break;
3324
3325 case EFI_IFR_SPAN_OP:
3326 Status = IfrSpan (FormSet, OpCode->Flags, Value);
3327 break;
3328
3329 case EFI_IFR_MAP_OP:
3330 //
3331 // Pop the check value
3332 //
3333 Status = PopExpression (&Data1);
3334 if (EFI_ERROR (Status)) {
3335 goto Done;
3336 }
3337 //
3338 // Check MapExpression list is valid.
3339 //
3340 if (OpCode->MapExpressionList.ForwardLink == NULL) {
3341 Status = EFI_INVALID_PARAMETER;
3342 goto Done;
3343 }
3344 //
3345 // Go through map expression list.
3346 //
3347 SubExpressionLink = GetFirstNode(&OpCode->MapExpressionList);
3348 while (!IsNull (&OpCode->MapExpressionList, SubExpressionLink)) {
3349 SubExpression = FORM_EXPRESSION_FROM_LINK (SubExpressionLink);
3350 //
3351 // Evaluate the first expression in this pair.
3352 //
3353 Status = EvaluateExpression (FormSet, Form, SubExpression);
3354 if (EFI_ERROR (Status)) {
3355 goto Done;
3356 }
3357 //
3358 // Compare the expression value with current value
3359 //
3360 if ((CompareHiiValue (&Data1, &SubExpression->Result, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) {
3361 //
3362 // Try get the map value.
3363 //
3364 SubExpressionLink = GetNextNode (&OpCode->MapExpressionList, SubExpressionLink);
3365 if (IsNull (&OpCode->MapExpressionList, SubExpressionLink)) {
3366 Status = EFI_INVALID_PARAMETER;
3367 goto Done;
3368 }
3369 SubExpression = FORM_EXPRESSION_FROM_LINK (SubExpressionLink);
3370 Status = EvaluateExpression (FormSet, Form, SubExpression);
3371 if (EFI_ERROR (Status)) {
3372 goto Done;
3373 }
3374 Value = &SubExpression->Result;
3375 break;
3376 }
3377 //
3378 // Skip the second expression on this pair.
3379 //
3380 SubExpressionLink = GetNextNode (&OpCode->MapExpressionList, SubExpressionLink);
3381 if (IsNull (&OpCode->MapExpressionList, SubExpressionLink)) {
3382 Status = EFI_INVALID_PARAMETER;
3383 goto Done;
3384 }
3385 //
3386 // Goto the first expression on next pair.
3387 //
3388 SubExpressionLink = GetNextNode (&OpCode->MapExpressionList, SubExpressionLink);
3389 }
3390
3391 //
3392 // No map value is found.
3393 //
3394 if (IsNull (&OpCode->MapExpressionList, SubExpressionLink)) {
3395 Value->Type = EFI_IFR_TYPE_UNDEFINED;
3396 Value->Value.u8 = 0;
3397 }
3398 break;
3399
3400 default:
3401 break;
3402 }
3403 if (EFI_ERROR (Status) || Value->Type == EFI_IFR_TYPE_UNDEFINED) {
3404 goto Done;
3405 }
3406
3407 Status = PushExpression (Value);
3408 if (EFI_ERROR (Status)) {
3409 goto Done;
3410 }
3411 }
3412
3413 //
3414 // Pop the final result from expression stack
3415 //
3416 Value = &Data1;
3417 Status = PopExpression (Value);
3418 if (EFI_ERROR (Status)) {
3419 goto Done;
3420 }
3421
3422 //
3423 // After evaluating an expression, there should be only one value left on the expression stack
3424 //
3425 if (PopExpression (Value) != EFI_ACCESS_DENIED) {
3426 Status = EFI_INVALID_PARAMETER;
3427 }
3428
3429Done:
3430 RestoreExpressionEvaluationStackOffset (StackOffset);
3431 if (!EFI_ERROR (Status)) {
3432 CopyMem (&Expression->Result, Value, sizeof (EFI_HII_VALUE));
3433 }
3434
3435 return Status;
3436}
3437
3438/**
3439 Check whether the result is TRUE or FALSE.
3440
3441 For the EFI_HII_VALUE value type is numeric, return TRUE if the
3442 value is not 0.
3443
3444 @param Result Input the result data.
3445
3446 @retval TRUE The result is TRUE.
3447 @retval FALSE The result is FALSE.
3448
3449**/
3450BOOLEAN
3451IsTrue (
3452 IN EFI_HII_VALUE *Result
3453 )
3454{
3455 switch (Result->Type) {
3456 case EFI_IFR_TYPE_BOOLEAN:
3457 return Result->Value.b;
3458
3459 case EFI_IFR_TYPE_NUM_SIZE_8:
3460 return (BOOLEAN)(Result->Value.u8 != 0);
3461
3462 case EFI_IFR_TYPE_NUM_SIZE_16:
3463 return (BOOLEAN)(Result->Value.u16 != 0);
3464
3465 case EFI_IFR_TYPE_NUM_SIZE_32:
3466 return (BOOLEAN)(Result->Value.u32 != 0);
3467
3468 case EFI_IFR_TYPE_NUM_SIZE_64:
3469 return (BOOLEAN)(Result->Value.u64 != 0);
3470
3471 default:
3472 return FALSE;
3473 }
3474}
3475
3476/**
3477 Return the result of the expression list. Check the expression list and
3478 return the highest priority express result.
3479 Priority: DisableIf > SuppressIf > GrayOutIf > FALSE
3480
3481 @param ExpList The input expression list.
3482 @param Evaluate Whether need to evaluate the expression first.
3483 @param FormSet FormSet associated with this expression.
3484 @param Form Form associated with this expression.
3485
3486 @retval EXPRESS_RESULT Return the higher priority express result.
3487 DisableIf > SuppressIf > GrayOutIf > FALSE
3488
3489**/
3490EXPRESS_RESULT
3491EvaluateExpressionList (
3492 IN FORM_EXPRESSION_LIST *ExpList,
3493 IN BOOLEAN Evaluate,
3494 IN FORM_BROWSER_FORMSET *FormSet, OPTIONAL
3495 IN FORM_BROWSER_FORM *Form OPTIONAL
3496 )
3497{
3498 UINTN Index;
3499 EXPRESS_RESULT ReturnVal;
3500 EXPRESS_RESULT CompareOne;
3501 EFI_STATUS Status;
3502
3503 if (ExpList == NULL) {
3504 return ExpressFalse;
3505 }
3506
3507 ASSERT(ExpList->Signature == FORM_EXPRESSION_LIST_SIGNATURE);
3508 Index = 0;
3509
3510 //
3511 // Check whether need to evaluate the expression first.
3512 //
3513 if (Evaluate) {
3514 while (ExpList->Count > Index) {
3515 Status = EvaluateExpression (FormSet, Form, ExpList->Expression[Index++]);
3516 if (EFI_ERROR (Status)) {
3517 return ExpressFalse;
3518 }
3519 }
3520 }
3521
3522 //
3523 // Run the list of expressions.
3524 //
3525 ReturnVal = ExpressFalse;
3526 for (Index = 0; Index < ExpList->Count; Index++) {
3527 if (IsTrue (&ExpList->Expression[Index]->Result)) {
3528 switch (ExpList->Expression[Index]->Type) {
3529 case EFI_HII_EXPRESSION_SUPPRESS_IF:
3530 CompareOne = ExpressSuppress;
3531 break;
3532
3533 case EFI_HII_EXPRESSION_GRAY_OUT_IF:
3534 CompareOne = ExpressGrayOut;
3535 break;
3536
3537 case EFI_HII_EXPRESSION_DISABLE_IF:
3538 CompareOne = ExpressDisable;
3539 break;
3540
3541 default:
3542 return ExpressFalse;
3543 }
3544
3545 ReturnVal = ReturnVal < CompareOne ? CompareOne : ReturnVal;
3546 }
3547 }
3548
3549 return ReturnVal;
3550}