1 /** @file
2   Var Check Hii bin generation.
3 
4 Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6 
7 **/
8 
9 #include "VarCheckHiiGen.h"
10 
11 LIST_ENTRY mVarCheckHiiList = INITIALIZE_LIST_HEAD_VARIABLE (mVarCheckHiiList);
12 
13 #define VAR_CHECK_HII_VARIABLE_NODE_SIGNATURE   SIGNATURE_32 ('V', 'C', 'H', 'V')
14 
15 typedef struct {
16   UINTN                         Signature;
17   LIST_ENTRY                    Link;
18   VAR_CHECK_HII_VARIABLE_HEADER *HiiVariable;
19   EFI_VARSTORE_ID               VarStoreId;
20 
21   VAR_CHECK_HII_QUESTION_HEADER **HiiQuestionArray;
22 } VAR_CHECK_HII_VARIABLE_NODE;
23 
24 #define VAR_CHECK_HII_VARIABLE_FROM_LINK(a) CR (a, VAR_CHECK_HII_VARIABLE_NODE, Link, VAR_CHECK_HII_VARIABLE_NODE_SIGNATURE)
25 
26 CHAR16 *mVarName = NULL;
27 UINTN  mMaxVarNameSize = 0;
28 
29 #ifdef DUMP_HII_DATA
30 GLOBAL_REMOVE_IF_UNREFERENCED VAR_CHECK_HII_OPCODE_STRING   mIfrOpCodeStringTable[] = {
31   {EFI_IFR_VARSTORE_OP,             "EFI_IFR_VARSTORE_OP"},
32   {EFI_IFR_VARSTORE_EFI_OP,         "EFI_IFR_VARSTORE_EFI_OP"},
33   {EFI_IFR_ONE_OF_OP,               "EFI_IFR_ONE_OF_OP"},
34   {EFI_IFR_CHECKBOX_OP,             "EFI_IFR_CHECKBOX_OP"},
35   {EFI_IFR_NUMERIC_OP,              "EFI_IFR_NUMERIC_OP"},
36   {EFI_IFR_ORDERED_LIST_OP,         "EFI_IFR_ORDERED_LIST_OP"},
37   {EFI_IFR_ONE_OF_OPTION_OP,        "EFI_IFR_ONE_OF_OPTION_OP"},
38 };
39 
40 /**
41   Ifr opcode to string.
42 
43   @param[in] IfrOpCode  Ifr OpCode.
44 
45   @return Pointer to string.
46 
47 **/
48 CHAR8 *
IfrOpCodeToStr(IN UINT8 IfrOpCode)49 IfrOpCodeToStr (
50   IN UINT8  IfrOpCode
51   )
52 {
53   UINTN  Index;
54   for (Index = 0; Index < ARRAY_SIZE (mIfrOpCodeStringTable); Index++) {
55     if (mIfrOpCodeStringTable[Index].HiiOpCode == IfrOpCode) {
56       return mIfrOpCodeStringTable[Index].HiiOpCodeStr;
57     }
58   }
59 
60   return "<UnknownIfrOpCode>";
61 }
62 
63 GLOBAL_REMOVE_IF_UNREFERENCED VAR_CHECK_HII_PACKAGE_TYPE_STRING  mPackageTypeStringTable[] = {
64   {EFI_HII_PACKAGE_TYPE_ALL,            "EFI_HII_PACKAGE_TYPE_ALL"},
65   {EFI_HII_PACKAGE_TYPE_GUID,           "EFI_HII_PACKAGE_TYPE_GUID"},
66   {EFI_HII_PACKAGE_FORMS,               "EFI_HII_PACKAGE_FORMS"},
67   {EFI_HII_PACKAGE_STRINGS,             "EFI_HII_PACKAGE_STRINGS"},
68   {EFI_HII_PACKAGE_FONTS,               "EFI_HII_PACKAGE_FONTS"},
69   {EFI_HII_PACKAGE_IMAGES,              "EFI_HII_PACKAGE_IMAGES"},
70   {EFI_HII_PACKAGE_SIMPLE_FONTS,        "EFI_HII_PACKAGE_SIMPLE_FONTS"},
71   {EFI_HII_PACKAGE_DEVICE_PATH,         "EFI_HII_PACKAGE_DEVICE_PATH"},
72   {EFI_HII_PACKAGE_KEYBOARD_LAYOUT,     "EFI_HII_PACKAGE_KEYBOARD_LAYOUT"},
73   {EFI_HII_PACKAGE_ANIMATIONS,          "EFI_HII_PACKAGE_ANIMATIONS"},
74   {EFI_HII_PACKAGE_END,                 "EFI_HII_PACKAGE_END"},
75   {EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN,   "EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN"},
76   {EFI_HII_PACKAGE_TYPE_SYSTEM_END,     "EFI_HII_PACKAGE_TYPE_SYSTEM_END"},
77 };
78 
79 /**
80   Hii Package type to string.
81 
82   @param[in] PackageType    Package Type
83 
84   @return Pointer to string.
85 
86 **/
87 CHAR8 *
HiiPackageTypeToStr(IN UINT8 PackageType)88 HiiPackageTypeToStr (
89   IN UINT8  PackageType
90   )
91 {
92   UINTN     Index;
93   for (Index = 0; Index < ARRAY_SIZE (mPackageTypeStringTable); Index++) {
94     if (mPackageTypeStringTable[Index].PackageType == PackageType) {
95       return mPackageTypeStringTable[Index].PackageTypeStr;
96     }
97   }
98 
99   return "<UnknownPackageType>";
100 }
101 
102 /**
103   Dump Hii Package.
104 
105   @param[in] HiiPackage         Pointer to Hii Package.
106 
107 **/
108 VOID
DumpHiiPackage(IN VOID * HiiPackage)109 DumpHiiPackage (
110   IN VOID       *HiiPackage
111   )
112 {
113   EFI_HII_PACKAGE_HEADER        *HiiPackageHeader;
114   EFI_IFR_OP_HEADER             *IfrOpCodeHeader;
115   EFI_IFR_VARSTORE              *IfrVarStore;
116   EFI_IFR_VARSTORE_EFI          *IfrEfiVarStore;
117   BOOLEAN                       QuestionStoredInBitField;
118 
119   HiiPackageHeader = (EFI_HII_PACKAGE_HEADER *) HiiPackage;
120   QuestionStoredInBitField = FALSE;
121 
122   DEBUG ((DEBUG_INFO, "  HiiPackageHeader->Type   - 0x%02x (%a)\n", HiiPackageHeader->Type, HiiPackageTypeToStr ((UINT8) HiiPackageHeader->Type)));
123   DEBUG ((DEBUG_INFO, "  HiiPackageHeader->Length - 0x%06x\n", HiiPackageHeader->Length));
124 
125   switch (HiiPackageHeader->Type) {
126     case EFI_HII_PACKAGE_FORMS:
127       IfrOpCodeHeader = (EFI_IFR_OP_HEADER *) (HiiPackageHeader + 1);
128 
129       while ((UINTN) IfrOpCodeHeader < ((UINTN) HiiPackageHeader + HiiPackageHeader->Length)) {
130         switch (IfrOpCodeHeader->OpCode) {
131           case EFI_IFR_VARSTORE_OP:
132             IfrVarStore = (EFI_IFR_VARSTORE *) IfrOpCodeHeader;
133             DEBUG ((DEBUG_INFO, "    IfrOpCodeHeader->OpCode - 0x%02x (%a)\n", IfrOpCodeHeader->OpCode, IfrOpCodeToStr (IfrOpCodeHeader->OpCode)));
134             DEBUG ((DEBUG_INFO, "    IfrOpCodeHeader->Length - 0x%02x\n", IfrOpCodeHeader->Length));
135             DEBUG ((DEBUG_INFO, "    IfrOpCodeHeader->Scope  - 0x%02x\n", IfrOpCodeHeader->Scope));
136             DEBUG ((DEBUG_INFO, "      Guid       - %g\n", &IfrVarStore->Guid));
137             DEBUG ((DEBUG_INFO, "      VarStoreId - 0x%04x\n", IfrVarStore->VarStoreId));
138             DEBUG ((DEBUG_INFO, "      Size       - 0x%04x\n", IfrVarStore->Size));
139             DEBUG ((DEBUG_INFO, "      Name       - %a\n", IfrVarStore->Name));
140             break;
141 
142           case EFI_IFR_VARSTORE_EFI_OP:
143             IfrEfiVarStore = (EFI_IFR_VARSTORE_EFI *) IfrOpCodeHeader;
144             if (IfrEfiVarStore->Header.Length >= sizeof (EFI_IFR_VARSTORE_EFI)) {
145               DEBUG ((DEBUG_INFO, "    IfrOpCodeHeader->OpCode - 0x%02x (%a)\n", IfrOpCodeHeader->OpCode, IfrOpCodeToStr (IfrOpCodeHeader->OpCode)));
146               DEBUG ((DEBUG_INFO, "    IfrOpCodeHeader->Length - 0x%02x\n", IfrOpCodeHeader->Length));
147               DEBUG ((DEBUG_INFO, "    IfrOpCodeHeader->Scope  - 0x%02x\n", IfrOpCodeHeader->Scope));
148               DEBUG ((DEBUG_INFO, "      Guid       - %g\n", &IfrEfiVarStore->Guid));
149               DEBUG ((DEBUG_INFO, "      VarStoreId - 0x%04x\n", IfrEfiVarStore->VarStoreId));
150               DEBUG ((DEBUG_INFO, "      Size       - 0x%04x\n", IfrEfiVarStore->Size));
151               DEBUG ((DEBUG_INFO, "      Attributes - 0x%08x\n", IfrEfiVarStore->Attributes));
152               DEBUG ((DEBUG_INFO, "      Name       - %a\n", IfrEfiVarStore->Name));
153             }
154             break;
155 
156           case EFI_IFR_GUID_OP:
157             if (CompareGuid ((EFI_GUID *)((UINTN)IfrOpCodeHeader + sizeof (EFI_IFR_OP_HEADER)), &gEdkiiIfrBitVarstoreGuid)) {
158               QuestionStoredInBitField = TRUE;
159             }
160             break;
161 
162           case EFI_IFR_ONE_OF_OP:
163           case EFI_IFR_CHECKBOX_OP:
164           case EFI_IFR_NUMERIC_OP:
165           case EFI_IFR_ORDERED_LIST_OP:
166             DEBUG ((DEBUG_INFO, "    IfrOpCodeHeader->OpCode - 0x%02x (%a) (%a)\n", IfrOpCodeHeader->OpCode, IfrOpCodeToStr (IfrOpCodeHeader->OpCode), (QuestionStoredInBitField? "bit level": "byte level")));
167             DEBUG ((DEBUG_INFO, "    IfrOpCodeHeader->Length - 0x%02x\n", IfrOpCodeHeader->Length));
168             DEBUG ((DEBUG_INFO, "    IfrOpCodeHeader->Scope  - 0x%02x\n", IfrOpCodeHeader->Scope));
169             DEBUG ((DEBUG_INFO, "      Prompt       - 0x%04x\n", ((EFI_IFR_ONE_OF *) IfrOpCodeHeader)->Question.Header.Prompt));
170             DEBUG ((DEBUG_INFO, "      Help         - 0x%04x\n", ((EFI_IFR_ONE_OF *) IfrOpCodeHeader)->Question.Header.Help));
171             DEBUG ((DEBUG_INFO, "      QuestionId   - 0x%04x\n", ((EFI_IFR_ONE_OF *) IfrOpCodeHeader)->Question.QuestionId));
172             DEBUG ((DEBUG_INFO, "      VarStoreId   - 0x%04x\n", ((EFI_IFR_ONE_OF *) IfrOpCodeHeader)->Question.VarStoreId));
173             DEBUG ((DEBUG_INFO, "      VarStoreInfo - 0x%04x (%a)\n", ((EFI_IFR_ONE_OF * )IfrOpCodeHeader)->Question.VarStoreInfo.VarOffset, (QuestionStoredInBitField? "bit level": "byte level")));
174             {
175               EFI_IFR_ONE_OF            *IfrOneOf;
176               EFI_IFR_CHECKBOX          *IfrCheckBox;
177               EFI_IFR_NUMERIC           *IfrNumeric;
178               EFI_IFR_ORDERED_LIST      *IfrOrderedList;
179 
180               switch (IfrOpCodeHeader->OpCode) {
181                 case EFI_IFR_ONE_OF_OP:
182                   IfrOneOf = (EFI_IFR_ONE_OF *) IfrOpCodeHeader;
183                   DEBUG ((DEBUG_INFO, "      Flags         - 0x%02x\n", IfrOneOf->Flags));
184                   if (QuestionStoredInBitField) {
185                     //
186                     // For OneOf stored in bit field, the option value are saved as UINT32 type.
187                     //
188                     DEBUG ((DEBUG_INFO, "      MinValue      - 0x%08x\n", IfrOneOf->data.u32.MinValue));
189                     DEBUG ((DEBUG_INFO, "      MaxValue      - 0x%08x\n", IfrOneOf->data.u32.MaxValue));
190                     DEBUG ((DEBUG_INFO, "      Step          - 0x%08x\n", IfrOneOf->data.u32.Step));
191                   } else {
192                     switch (IfrOneOf->Flags & EFI_IFR_NUMERIC_SIZE) {
193                     case EFI_IFR_NUMERIC_SIZE_1:
194                       DEBUG ((DEBUG_INFO, "      MinValue      - 0x%02x\n", IfrOneOf->data.u8.MinValue));
195                       DEBUG ((DEBUG_INFO, "      MaxValue      - 0x%02x\n", IfrOneOf->data.u8.MaxValue));
196                       DEBUG ((DEBUG_INFO, "      Step          - 0x%02x\n", IfrOneOf->data.u8.Step));
197                       break;
198                     case EFI_IFR_NUMERIC_SIZE_2:
199                       DEBUG ((DEBUG_INFO, "      MinValue      - 0x%04x\n", IfrOneOf->data.u16.MinValue));
200                       DEBUG ((DEBUG_INFO, "      MaxValue      - 0x%04x\n", IfrOneOf->data.u16.MaxValue));
201                       DEBUG ((DEBUG_INFO, "      Step          - 0x%04x\n", IfrOneOf->data.u16.Step));
202                       break;
203                     case EFI_IFR_NUMERIC_SIZE_4:
204                       DEBUG ((DEBUG_INFO, "      MinValue      - 0x%08x\n", IfrOneOf->data.u32.MinValue));
205                       DEBUG ((DEBUG_INFO, "      MaxValue      - 0x%08x\n", IfrOneOf->data.u32.MaxValue));
206                       DEBUG ((DEBUG_INFO, "      Step          - 0x%08x\n", IfrOneOf->data.u32.Step));
207                       break;
208                     case EFI_IFR_NUMERIC_SIZE_8:
209                       DEBUG ((DEBUG_INFO, "      MinValue      - 0x%016lx\n", IfrOneOf->data.u64.MinValue));
210                       DEBUG ((DEBUG_INFO, "      MaxValue      - 0x%016lx\n", IfrOneOf->data.u64.MaxValue));
211                       DEBUG ((DEBUG_INFO, "      Step          - 0x%016lx\n", IfrOneOf->data.u64.Step));
212                       break;
213                     }
214                   }
215                   break;
216                 case EFI_IFR_CHECKBOX_OP:
217                   IfrCheckBox = (EFI_IFR_CHECKBOX *) IfrOpCodeHeader;
218                   DEBUG ((DEBUG_INFO, "      Flags         - 0x%02x\n", IfrCheckBox->Flags));
219                   break;
220                 case EFI_IFR_NUMERIC_OP:
221                   IfrNumeric = (EFI_IFR_NUMERIC *) IfrOpCodeHeader;
222                   DEBUG ((DEBUG_INFO, "      Flags         - 0x%02x\n", IfrNumeric->Flags));
223                   if (QuestionStoredInBitField) {
224                     //
225                     // For Numeric stored in bit field, the MinValue,MaxValue and Step are saved as UINT32 type.
226                     //
227                     DEBUG ((DEBUG_INFO, "      MinValue      - 0x%08x\n", IfrNumeric->data.u32.MinValue));
228                     DEBUG ((DEBUG_INFO, "      MaxValue      - 0x%08x\n", IfrNumeric->data.u32.MaxValue));
229                     DEBUG ((DEBUG_INFO, "      Step          - 0x%08x\n", IfrNumeric->data.u32.Step));
230                   } else {
231                     switch (IfrNumeric->Flags & EFI_IFR_NUMERIC_SIZE) {
232                     case EFI_IFR_NUMERIC_SIZE_1:
233                       DEBUG ((DEBUG_INFO, "      MinValue      - 0x%02x\n", IfrNumeric->data.u8.MinValue));
234                       DEBUG ((DEBUG_INFO, "      MaxValue      - 0x%02x\n", IfrNumeric->data.u8.MaxValue));
235                       DEBUG ((DEBUG_INFO, "      Step          - 0x%02x\n", IfrNumeric->data.u8.Step));
236                       break;
237                     case EFI_IFR_NUMERIC_SIZE_2:
238                       DEBUG ((DEBUG_INFO, "      MinValue      - 0x%04x\n", IfrNumeric->data.u16.MinValue));
239                       DEBUG ((DEBUG_INFO, "      MaxValue      - 0x%04x\n", IfrNumeric->data.u16.MaxValue));
240                       DEBUG ((DEBUG_INFO, "      Step          - 0x%04x\n", IfrNumeric->data.u16.Step));
241                       break;
242                     case EFI_IFR_NUMERIC_SIZE_4:
243                       DEBUG ((DEBUG_INFO, "      MinValue      - 0x%08x\n", IfrNumeric->data.u32.MinValue));
244                       DEBUG ((DEBUG_INFO, "      MaxValue      - 0x%08x\n", IfrNumeric->data.u32.MaxValue));
245                       DEBUG ((DEBUG_INFO, "      Step          - 0x%08x\n", IfrNumeric->data.u32.Step));
246                       break;
247                     case EFI_IFR_NUMERIC_SIZE_8:
248                       DEBUG ((DEBUG_INFO, "      MinValue      - 0x%016lx\n", IfrNumeric->data.u64.MinValue));
249                       DEBUG ((DEBUG_INFO, "      MaxValue      - 0x%016lx\n", IfrNumeric->data.u64.MaxValue));
250                       DEBUG ((DEBUG_INFO, "      Step          - 0x%016lx\n", IfrNumeric->data.u64.Step));
251                       break;
252                     }
253                   }
254                   break;
255                 case EFI_IFR_ORDERED_LIST_OP:
256                   IfrOrderedList = (EFI_IFR_ORDERED_LIST *) IfrOpCodeHeader;
257                   DEBUG ((DEBUG_INFO, "      MaxContainers - 0x%02x\n", IfrOrderedList->MaxContainers));
258                   DEBUG ((DEBUG_INFO, "      Flags         - 0x%02x\n", IfrOrderedList->Flags));
259                   break;
260                 default:
261                   break;
262               }
263 
264               if (IfrOpCodeHeader->Scope != 0) {
265                 UINTN                       Scope;
266                 EFI_IFR_ONE_OF_OPTION       *IfrOneOfOption;
267 
268                 IfrOpCodeHeader = (EFI_IFR_OP_HEADER *) ((UINTN) IfrOpCodeHeader + IfrOpCodeHeader->Length);
269                 Scope = 1;
270                 while (Scope != 0) {
271                   switch (IfrOpCodeHeader->OpCode) {
272                     case EFI_IFR_ONE_OF_OPTION_OP:
273                       IfrOneOfOption = (EFI_IFR_ONE_OF_OPTION *)IfrOpCodeHeader;
274                       DEBUG ((DEBUG_INFO, "!!!!    IfrOpCodeHeader->OpCode - 0x%02x (%a)\n", (UINTN)IfrOpCodeHeader->OpCode, IfrOpCodeToStr (IfrOpCodeHeader->OpCode)));
275                       DEBUG ((DEBUG_INFO, "!!!!    IfrOpCodeHeader->Scope  - 0x%02x\n", IfrOpCodeHeader->Scope));
276                       DEBUG ((DEBUG_INFO, "!!!!      Option                - 0x%04x\n", IfrOneOfOption->Option));
277                       DEBUG ((DEBUG_INFO, "!!!!      Flags                 - 0x%02x\n", IfrOneOfOption->Flags));
278                       DEBUG ((DEBUG_INFO, "!!!!      Type                  - 0x%02x\n", IfrOneOfOption->Type));
279                       switch (IfrOneOfOption->Type) {
280                         case EFI_IFR_TYPE_NUM_SIZE_8:
281                           DEBUG ((DEBUG_INFO, "!!!!      Value                 - 0x%02x\n", IfrOneOfOption->Value.u8));
282                           break;
283                         case EFI_IFR_TYPE_NUM_SIZE_16:
284                           DEBUG ((DEBUG_INFO, "!!!!      Value                 - 0x%04x\n", IfrOneOfOption->Value.u16));
285                           break;
286                         case EFI_IFR_TYPE_NUM_SIZE_32:
287                           DEBUG ((DEBUG_INFO, "!!!!      Value                 - 0x%08x\n", IfrOneOfOption->Value.u32));
288                           break;
289                         case EFI_IFR_TYPE_NUM_SIZE_64:
290                           DEBUG ((DEBUG_INFO, "!!!!      Value                 - 0x%016lx\n", IfrOneOfOption->Value.u64));
291                           break;
292                         case EFI_IFR_TYPE_BOOLEAN:
293                           DEBUG ((DEBUG_INFO, "!!!!      Value                 - 0x%02x\n", IfrOneOfOption->Value.b));
294                           break;
295                         default:
296                           break;
297                       }
298                       break;
299                   }
300 
301                   if (IfrOpCodeHeader->OpCode == EFI_IFR_END_OP) {
302                     QuestionStoredInBitField = FALSE;
303                     ASSERT (Scope > 0);
304                     Scope--;
305                     if (Scope == 0) {
306                       break;
307                     }
308                   } else if (IfrOpCodeHeader->Scope != 0) {
309                     Scope++;
310                   }
311                   IfrOpCodeHeader = (EFI_IFR_OP_HEADER *) ((UINTN) IfrOpCodeHeader + IfrOpCodeHeader->Length);
312                 }
313               }
314             }
315           default:
316             break;
317         }
318         IfrOpCodeHeader = (EFI_IFR_OP_HEADER *) ((UINTN) IfrOpCodeHeader + IfrOpCodeHeader->Length);
319       }
320       break;
321     default:
322       break;
323   }
324 }
325 
326 /**
327   Dump Hii Database.
328 
329   @param[in] HiiDatabase        Pointer to Hii Database.
330   @param[in] HiiDatabaseSize    Hii Database size.
331 
332 **/
333 VOID
DumpHiiDatabase(IN VOID * HiiDatabase,IN UINTN HiiDatabaseSize)334 DumpHiiDatabase (
335   IN VOID       *HiiDatabase,
336   IN UINTN      HiiDatabaseSize
337   )
338 {
339   EFI_HII_PACKAGE_LIST_HEADER   *HiiPackageListHeader;
340   EFI_HII_PACKAGE_HEADER        *HiiPackageHeader;
341 
342   DEBUG ((DEBUG_INFO, "HiiDatabaseSize - 0x%x\n", HiiDatabaseSize));
343   HiiPackageListHeader = (EFI_HII_PACKAGE_LIST_HEADER *) HiiDatabase;
344 
345   while ((UINTN) HiiPackageListHeader < ((UINTN) HiiDatabase + HiiDatabaseSize)) {
346     DEBUG ((DEBUG_INFO, "HiiPackageListHeader->PackageListGuid - %g\n", &HiiPackageListHeader->PackageListGuid));
347     DEBUG ((DEBUG_INFO, "HiiPackageListHeader->PackageLength   - 0x%x\n", (UINTN)HiiPackageListHeader->PackageLength));
348     HiiPackageHeader = (EFI_HII_PACKAGE_HEADER *)(HiiPackageListHeader + 1);
349 
350     while ((UINTN) HiiPackageHeader < (UINTN) HiiPackageListHeader + HiiPackageListHeader->PackageLength) {
351 
352       DumpHiiPackage (HiiPackageHeader);
353 
354       HiiPackageHeader = (EFI_HII_PACKAGE_HEADER *) ((UINTN) HiiPackageHeader + HiiPackageHeader->Length);
355     }
356 
357     HiiPackageListHeader = (EFI_HII_PACKAGE_LIST_HEADER *) ((UINTN) HiiPackageListHeader + HiiPackageListHeader->PackageLength);
358   }
359 
360   return ;
361 }
362 #endif
363 
364 /**
365   Allocates a buffer of a certain pool type.
366 
367   Allocates the number bytes specified by AllocationSize of a certain pool type and returns a
368   pointer to the allocated buffer.  If AllocationSize is 0, then a valid buffer of 0 size is
369   returned.  If there is not enough memory remaining to satisfy the request, then NULL is returned.
370 
371   @param  MemoryType            The type of memory to allocate.
372   @param  AllocationSize        The number of bytes to allocate.
373 
374   @return A pointer to the allocated buffer or NULL if allocation fails.
375 
376 **/
377 VOID *
InternalVarCheckAllocatePool(IN EFI_MEMORY_TYPE MemoryType,IN UINTN AllocationSize)378 InternalVarCheckAllocatePool (
379   IN EFI_MEMORY_TYPE  MemoryType,
380   IN UINTN            AllocationSize
381   )
382 {
383   EFI_STATUS  Status;
384   VOID        *Memory;
385 
386   Status = gBS->AllocatePool (MemoryType, AllocationSize, &Memory);
387   if (EFI_ERROR (Status)) {
388     Memory = NULL;
389   }
390   return Memory;
391 }
392 
393 /**
394   Allocates and zeros a buffer of type EfiBootServicesData.
395 
396   Allocates the number bytes specified by AllocationSize of type EfiBootServicesData, clears the
397   buffer with zeros, and returns a pointer to the allocated buffer.  If AllocationSize is 0, then a
398   valid buffer of 0 size is returned.  If there is not enough memory remaining to satisfy the
399   request, then NULL is returned.
400 
401   @param  AllocationSize        The number of bytes to allocate and zero.
402 
403   @return A pointer to the allocated buffer or NULL if allocation fails.
404 
405 **/
406 VOID *
InternalVarCheckAllocateZeroPool(IN UINTN AllocationSize)407 InternalVarCheckAllocateZeroPool (
408   IN UINTN            AllocationSize
409   )
410 {
411   VOID  *Memory;
412 
413   Memory = InternalVarCheckAllocatePool (EfiBootServicesData, AllocationSize);
414   if (Memory != NULL) {
415     Memory = ZeroMem (Memory, AllocationSize);
416   }
417   return Memory;
418 }
419 
420 /**
421   Frees a buffer that was previously allocated with one of the pool allocation functions in the
422   Memory Allocation Library.
423 
424   Frees the buffer specified by Buffer.  Buffer must have been allocated on a previous call to the
425   pool allocation services of the Memory Allocation Library.  If it is not possible to free pool
426   resources, then this function will perform no actions.
427 
428   If Buffer was not allocated with a pool allocation function in the Memory Allocation Library,
429   then ASSERT().
430 
431   @param  Buffer                The pointer to the buffer to free.
432 
433 **/
434 VOID
435 EFIAPI
InternalVarCheckFreePool(IN VOID * Buffer)436 InternalVarCheckFreePool (
437   IN VOID   *Buffer
438   )
439 {
440   EFI_STATUS    Status;
441 
442   Status = gBS->FreePool (Buffer);
443   ASSERT_EFI_ERROR (Status);
444 }
445 
446 /**
447   Reallocates a buffer of type EfiBootServicesData.
448 
449   Allocates and zeros the number bytes specified by NewSize from memory of type
450   EfiBootServicesData.  If OldBuffer is not NULL, then the smaller of OldSize and
451   NewSize bytes are copied from OldBuffer to the newly allocated buffer, and
452   OldBuffer is freed.  A pointer to the newly allocated buffer is returned.
453   If NewSize is 0, then a valid buffer of 0 size is  returned.  If there is not
454   enough memory remaining to satisfy the request, then NULL is returned.
455 
456   If the allocation of the new buffer is successful and the smaller of NewSize and OldSize
457   is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT().
458 
459   @param  OldSize        The size, in bytes, of OldBuffer.
460   @param  NewSize        The size, in bytes, of the buffer to reallocate.
461   @param  OldBuffer      The buffer to copy to the allocated buffer.  This is an optional
462                          parameter that may be NULL.
463 
464   @return A pointer to the allocated buffer or NULL if allocation fails.
465 
466 **/
467 VOID *
InternalVarCheckReallocatePool(IN UINTN OldSize,IN UINTN NewSize,IN VOID * OldBuffer OPTIONAL)468 InternalVarCheckReallocatePool (
469   IN UINTN            OldSize,
470   IN UINTN            NewSize,
471   IN VOID             *OldBuffer  OPTIONAL
472   )
473 {
474   VOID  *NewBuffer;
475 
476   NewBuffer = InternalVarCheckAllocateZeroPool (NewSize);
477   if (NewBuffer != NULL && OldBuffer != NULL) {
478     CopyMem (NewBuffer, OldBuffer, MIN (OldSize, NewSize));
479     InternalVarCheckFreePool (OldBuffer);
480   }
481   return NewBuffer;
482 }
483 
484 /**
485   Merge Hii Question.
486 
487   @param[in, out] HiiVariableNode   Pointer to Hii Variable node.
488   @param[in]      HiiQuestion       Pointer to Hii Question.
489   @param[in]      FromFv            Hii Question from FV.
490 
491 **/
492 VOID
MergeHiiQuestion(IN OUT VAR_CHECK_HII_VARIABLE_NODE * HiiVariableNode,IN VAR_CHECK_HII_QUESTION_HEADER * HiiQuestion,IN BOOLEAN FromFv)493 MergeHiiQuestion (
494   IN OUT VAR_CHECK_HII_VARIABLE_NODE    *HiiVariableNode,
495   IN VAR_CHECK_HII_QUESTION_HEADER      *HiiQuestion,
496   IN BOOLEAN                            FromFv
497   )
498 {
499   VAR_CHECK_HII_QUESTION_HEADER     *HiiQuestion1;
500   VAR_CHECK_HII_QUESTION_HEADER     *HiiQuestion2;
501   VAR_CHECK_HII_QUESTION_HEADER     *NewHiiQuestion;
502   UINT8                             NewLength;
503   UINT64                            Minimum1;
504   UINT64                            Maximum1;
505   UINT64                            OneValue1;
506   UINT64                            Minimum2;
507   UINT64                            Maximum2;
508   UINT64                            OneValue2;
509   UINT8                             *Ptr;
510   UINT8                             *Ptr1;
511   UINT8                             *Ptr2;
512   UINTN                             ArrayIndex;
513 
514   //
515   // Hii Question from Hii Database has high priority.
516   // Do not to merge Hii Question from Fv to Hii Question from Hii Database.
517   //
518   if (FromFv) {
519     InternalVarCheckFreePool (HiiQuestion);
520     return;
521   }
522 
523   if (HiiQuestion->BitFieldStore) {
524     ArrayIndex = HiiQuestion->VarOffset;
525   } else {
526     ArrayIndex = HiiQuestion->VarOffset * 8;
527   }
528 
529   HiiQuestion1 = HiiVariableNode->HiiQuestionArray[ArrayIndex];
530   HiiQuestion2 = HiiQuestion;
531 
532   ASSERT ((HiiQuestion1->OpCode == HiiQuestion2->OpCode) && (HiiQuestion1->StorageWidth == HiiQuestion2->StorageWidth));
533 
534   switch (HiiQuestion1->OpCode) {
535     case EFI_IFR_ONE_OF_OP:
536       DEBUG ((DEBUG_INFO, "MergeHiiQuestion - EFI_IFR_ONE_OF_OP VarOffset = 0x%04x (%a)\n", HiiQuestion1->VarOffset, (HiiQuestion1->BitFieldStore? "bit level": "byte level")));
537       //
538       // Get the length of Hii Question 1.
539       //
540       NewLength = HiiQuestion1->Length;
541 
542       //
543       // Check if the one of options in Hii Question 2 have been in Hii Question 1.
544       //
545       Ptr2 = (UINT8 *) ((VAR_CHECK_HII_QUESTION_ONEOF *) HiiQuestion2 + 1);
546       while ((UINTN) Ptr2 < (UINTN) HiiQuestion2 + HiiQuestion2->Length) {
547         OneValue2 = 0;
548         CopyMem (&OneValue2, Ptr2, HiiQuestion2->StorageWidth);
549 
550         Ptr1 = (UINT8 *) ((VAR_CHECK_HII_QUESTION_ONEOF *) HiiQuestion1 + 1);
551         while ((UINTN) Ptr1 < (UINTN) HiiQuestion1 + HiiQuestion1->Length) {
552           OneValue1 = 0;
553           CopyMem (&OneValue1, Ptr1, HiiQuestion1->StorageWidth);
554           if (OneValue2 == OneValue1) {
555             //
556             // Match
557             //
558             break;
559           }
560           Ptr1 += HiiQuestion1->StorageWidth;
561         }
562         if ((UINTN) Ptr1 >= ((UINTN) HiiQuestion1 + HiiQuestion1->Length)) {
563           //
564           // No match
565           //
566           NewLength = (UINT8) (NewLength + HiiQuestion1->StorageWidth);
567         }
568         Ptr2 += HiiQuestion2->StorageWidth;
569       }
570 
571       if (NewLength > HiiQuestion1->Length) {
572         //
573         // Merge the one of options of Hii Question 2 and Hii Question 1.
574         //
575         NewHiiQuestion = InternalVarCheckAllocateZeroPool (NewLength);
576         ASSERT (NewHiiQuestion != NULL);
577         CopyMem (NewHiiQuestion, HiiQuestion1, HiiQuestion1->Length);
578         //
579         // Use the new length.
580         //
581         NewHiiQuestion->Length = NewLength;
582         Ptr = (UINT8 *) NewHiiQuestion + HiiQuestion1->Length;
583 
584         Ptr2 = (UINT8 *) ((VAR_CHECK_HII_QUESTION_ONEOF *) HiiQuestion2 + 1);
585         while ((UINTN) Ptr2 < (UINTN) HiiQuestion2 + HiiQuestion2->Length) {
586           OneValue2 = 0;
587           CopyMem (&OneValue2, Ptr2, HiiQuestion2->StorageWidth);
588 
589           Ptr1 = (UINT8 *) ((VAR_CHECK_HII_QUESTION_ONEOF *) HiiQuestion1 + 1);
590           while ((UINTN) Ptr1 < (UINTN) HiiQuestion1 + HiiQuestion1->Length) {
591             OneValue1 = 0;
592             CopyMem (&OneValue1, Ptr1, HiiQuestion1->StorageWidth);
593             if (OneValue2 == OneValue1) {
594               //
595               // Match
596               //
597               break;
598             }
599             Ptr1 += HiiQuestion1->StorageWidth;
600           }
601           if ((UINTN) Ptr1 >= ((UINTN) HiiQuestion1 + HiiQuestion1->Length)) {
602             //
603             // No match
604             //
605             CopyMem (Ptr, &OneValue2, HiiQuestion1->StorageWidth);
606             Ptr += HiiQuestion1->StorageWidth;
607           }
608           Ptr2 += HiiQuestion2->StorageWidth;
609         }
610 
611         HiiVariableNode->HiiQuestionArray[ArrayIndex] = NewHiiQuestion;
612         InternalVarCheckFreePool (HiiQuestion1);
613       }
614       break;
615 
616     case EFI_IFR_CHECKBOX_OP:
617       DEBUG ((DEBUG_INFO, "MergeHiiQuestion - EFI_IFR_CHECKBOX_OP VarOffset = 0x%04x (%a)\n", HiiQuestion1->VarOffset, (HiiQuestion1->BitFieldStore? "bit level": "byte level")));
618       break;
619 
620     case EFI_IFR_NUMERIC_OP:
621       DEBUG ((DEBUG_INFO, "MergeHiiQuestion - EFI_IFR_NUMERIC_OP VarOffset = 0x%04x (%a)\n", HiiQuestion1->VarOffset, (HiiQuestion1->BitFieldStore? "bit level": "byte level")));
622       //
623       // Get minimum and maximum of Hii Question 1.
624       //
625       Minimum1 = 0;
626       Maximum1 = 0;
627       Ptr = (UINT8 *) ((VAR_CHECK_HII_QUESTION_NUMERIC *) HiiQuestion1 + 1);
628       CopyMem (&Minimum1, Ptr, HiiQuestion1->StorageWidth);
629       Ptr += HiiQuestion1->StorageWidth;
630       CopyMem (&Maximum1, Ptr, HiiQuestion1->StorageWidth);
631 
632       //
633       // Get minimum and maximum of Hii Question 2.
634       //
635       Minimum2 = 0;
636       Maximum2 = 0;
637       Ptr = (UINT8 *) ((VAR_CHECK_HII_QUESTION_NUMERIC *) HiiQuestion2 + 1);
638       CopyMem (&Minimum2, Ptr, HiiQuestion2->StorageWidth);
639       Ptr += HiiQuestion2->StorageWidth;
640       CopyMem (&Maximum2, Ptr, HiiQuestion2->StorageWidth);
641 
642       //
643       // Update minimum.
644       //
645       Ptr = (UINT8 *) ((VAR_CHECK_HII_QUESTION_NUMERIC *) HiiQuestion1 + 1);
646       if (Minimum2 < Minimum1) {
647         Minimum1 = Minimum2;
648         CopyMem (Ptr, &Minimum1, HiiQuestion1->StorageWidth);
649       }
650       //
651       // Update maximum.
652       //
653       Ptr += HiiQuestion1->StorageWidth;
654       if (Maximum2 > Maximum1) {
655         Maximum1 = Maximum2;
656         CopyMem (Ptr, &Maximum1, HiiQuestion1->StorageWidth);
657       }
658       break;
659 
660     case EFI_IFR_ORDERED_LIST_OP:
661       DEBUG ((DEBUG_INFO, "MergeHiiQuestion - EFI_IFR_ORDERED_LIST_OP VarOffset = 0x%04x\n", HiiQuestion1->VarOffset));
662       //
663       // Get the length of Hii Question 1.
664       //
665       NewLength = HiiQuestion1->Length;
666 
667       //
668       // Check if the one of options in Hii Question 2 have been in Hii Question 1.
669       //
670       Ptr2 = (UINT8 *) ((VAR_CHECK_HII_QUESTION_ORDEREDLIST *) HiiQuestion2 + 1);
671       while ((UINTN) Ptr2 < (UINTN) HiiQuestion2 + HiiQuestion2->Length) {
672         OneValue2 = 0;
673         CopyMem (&OneValue2, Ptr2, HiiQuestion2->StorageWidth);
674 
675         Ptr1 = (UINT8 *) ((VAR_CHECK_HII_QUESTION_ORDEREDLIST *) HiiQuestion1 + 1);
676         while ((UINTN) Ptr1 < (UINTN) HiiQuestion1 + HiiQuestion1->Length) {
677           OneValue1 = 0;
678           CopyMem (&OneValue1, Ptr1, HiiQuestion1->StorageWidth);
679           if (OneValue2 == OneValue1) {
680             //
681             // Match
682             //
683             break;
684           }
685           Ptr1 += HiiQuestion1->StorageWidth;
686         }
687         if ((UINTN) Ptr1 >= ((UINTN) HiiQuestion1 + HiiQuestion1->Length)) {
688           //
689           // No match
690           //
691           NewLength = (UINT8) (NewLength + HiiQuestion1->StorageWidth);
692         }
693         Ptr2 += HiiQuestion2->StorageWidth;
694       }
695 
696       if (NewLength > HiiQuestion1->Length) {
697         //
698         // Merge the one of options of Hii Question 2 and Hii Question 1.
699         //
700         NewHiiQuestion = InternalVarCheckAllocateZeroPool (NewLength);
701         ASSERT (NewHiiQuestion != NULL);
702         CopyMem (NewHiiQuestion, HiiQuestion1, HiiQuestion1->Length);
703         //
704         // Use the new length.
705         //
706         NewHiiQuestion->Length = NewLength;
707         Ptr = (UINT8 *) NewHiiQuestion + HiiQuestion1->Length;
708 
709         Ptr2 = (UINT8 *) ((VAR_CHECK_HII_QUESTION_ORDEREDLIST *) HiiQuestion2 + 1);
710         while ((UINTN) Ptr2 < (UINTN) HiiQuestion2 + HiiQuestion2->Length) {
711           OneValue2 = 0;
712           CopyMem (&OneValue2, Ptr2, HiiQuestion2->StorageWidth);
713 
714           Ptr1 = (UINT8 *) ((VAR_CHECK_HII_QUESTION_ORDEREDLIST *) HiiQuestion1 + 1);
715           while ((UINTN) Ptr1 < (UINTN) HiiQuestion1 + HiiQuestion1->Length) {
716             OneValue1 = 0;
717             CopyMem (&OneValue1, Ptr1, HiiQuestion1->StorageWidth);
718             if (OneValue2 == OneValue1) {
719               //
720               // Match
721               //
722               break;
723             }
724             Ptr1 += HiiQuestion1->StorageWidth;
725           }
726           if ((UINTN) Ptr1 >= ((UINTN) HiiQuestion1 + HiiQuestion1->Length)) {
727             //
728             // No match
729             //
730             CopyMem (Ptr, &OneValue2, HiiQuestion1->StorageWidth);
731             Ptr += HiiQuestion1->StorageWidth;
732           }
733           Ptr2 += HiiQuestion2->StorageWidth;
734         }
735 
736         HiiVariableNode->HiiQuestionArray[ArrayIndex] = NewHiiQuestion;
737         InternalVarCheckFreePool (HiiQuestion1);
738       }
739       break;
740 
741     default:
742       ASSERT (FALSE);
743       return;
744       break;
745   }
746 
747   //
748   //
749   // Hii Question 2 has been merged with Hii Question 1.
750   //
751   InternalVarCheckFreePool (HiiQuestion2);
752 }
753 
754 /**
755   Get OneOf option data.
756 
757   @param[in]  IfrOpCodeHeader   Pointer to Ifr OpCode header.
758   @param[out] Count             Pointer to option count.
759   @param[out] Width             Pointer to option width.
760   @param[out] OptionBuffer      Pointer to option buffer.
761 
762 **/
763 VOID
GetOneOfOption(IN EFI_IFR_OP_HEADER * IfrOpCodeHeader,OUT UINTN * Count,OUT UINT8 * Width,OUT VOID * OptionBuffer OPTIONAL)764 GetOneOfOption (
765   IN  EFI_IFR_OP_HEADER     *IfrOpCodeHeader,
766   OUT UINTN                 *Count,
767   OUT UINT8                 *Width,
768   OUT VOID                  *OptionBuffer OPTIONAL
769   )
770 {
771   UINTN                     Scope;
772   EFI_IFR_ONE_OF_OPTION     *IfrOneOfOption;
773 
774   //
775   // Assume all OPTION has same Width.
776   //
777   *Count = 0;
778 
779   if (IfrOpCodeHeader->Scope != 0) {
780     //
781     // Nested OpCode.
782     //
783     Scope = 1;
784     IfrOpCodeHeader = (EFI_IFR_OP_HEADER *) ((UINTN) IfrOpCodeHeader + IfrOpCodeHeader->Length);
785     while (Scope != 0) {
786       switch (IfrOpCodeHeader->OpCode) {
787         case EFI_IFR_ONE_OF_OPTION_OP:
788           IfrOneOfOption = (EFI_IFR_ONE_OF_OPTION *) IfrOpCodeHeader;
789           switch (IfrOneOfOption->Type) {
790             case EFI_IFR_TYPE_NUM_SIZE_8:
791               *Count = *Count + 1;
792               *Width = sizeof (UINT8);
793               if (OptionBuffer != NULL) {
794                 CopyMem (OptionBuffer, &IfrOneOfOption->Value.u8, sizeof (UINT8));
795                 OptionBuffer = (UINT8 *) OptionBuffer + 1;
796               }
797               break;
798             case EFI_IFR_TYPE_NUM_SIZE_16:
799               *Count = *Count + 1;
800               *Width = sizeof (UINT16);
801               if (OptionBuffer != NULL) {
802                 CopyMem (OptionBuffer, &IfrOneOfOption->Value.u16, sizeof (UINT16));
803                 OptionBuffer = (UINT16 *) OptionBuffer + 1;
804               }
805               break;
806             case EFI_IFR_TYPE_NUM_SIZE_32:
807               *Count = *Count + 1;
808               *Width = sizeof (UINT32);
809               if (OptionBuffer != NULL) {
810                 CopyMem (OptionBuffer, &IfrOneOfOption->Value.u32, sizeof (UINT32));
811                 OptionBuffer = (UINT32 *) OptionBuffer + 1;
812               }
813               break;
814             case EFI_IFR_TYPE_NUM_SIZE_64:
815               *Count = *Count + 1;
816               *Width = sizeof (UINT64);
817               if (OptionBuffer != NULL) {
818                 CopyMem (OptionBuffer, &IfrOneOfOption->Value.u64, sizeof (UINT64));
819                 OptionBuffer = (UINT64 *) OptionBuffer + 1;
820               }
821               break;
822             case EFI_IFR_TYPE_BOOLEAN:
823               *Count = *Count + 1;
824               *Width = sizeof (BOOLEAN);
825               if (OptionBuffer != NULL) {
826                 CopyMem (OptionBuffer, &IfrOneOfOption->Value.b, sizeof (BOOLEAN));
827                 OptionBuffer = (BOOLEAN *) OptionBuffer + 1;
828               }
829               break;
830             default:
831               break;
832           }
833           break;
834       }
835 
836       //
837       // Until End OpCode.
838       //
839       if (IfrOpCodeHeader->OpCode == EFI_IFR_END_OP) {
840         ASSERT (Scope > 0);
841         Scope--;
842         if (Scope == 0) {
843           break;
844         }
845       } else if (IfrOpCodeHeader->Scope != 0) {
846         //
847         // Nested OpCode.
848         //
849         Scope++;
850       }
851       IfrOpCodeHeader = (EFI_IFR_OP_HEADER *) ((UINTN) IfrOpCodeHeader + IfrOpCodeHeader->Length);
852     }
853   }
854 
855   return ;
856 }
857 
858 /**
859   Parse Hii Question Oneof.
860 
861   @param[in] IfrOpCodeHeader    Pointer to Ifr OpCode header.
862   @param[in] StoredInBitField   Whether the OneOf is stored in bit field Storage.
863 
864   return Pointer to Hii Question.
865 
866 **/
867 VAR_CHECK_HII_QUESTION_HEADER *
ParseHiiQuestionOneOf(IN EFI_IFR_OP_HEADER * IfrOpCodeHeader,IN BOOLEAN StoredInBitField)868 ParseHiiQuestionOneOf (
869   IN EFI_IFR_OP_HEADER  *IfrOpCodeHeader,
870   IN BOOLEAN            StoredInBitField
871   )
872 {
873   EFI_IFR_ONE_OF                *IfrOneOf;
874   VAR_CHECK_HII_QUESTION_ONEOF  *OneOf;
875   UINTN                         Length;
876   UINT8                         Width;
877   UINTN                         OptionCount;
878   UINT8                         OptionWidth;
879   UINT8                         BitWidth;
880 
881   IfrOneOf = (EFI_IFR_ONE_OF *) IfrOpCodeHeader;
882   BitWidth = 0;
883 
884   if (StoredInBitField) {
885     //
886     // When OneOf stored in bit field, the bit width is saved in the lower six bits of the flag.
887     // And the options in the OneOf is saved as UINT32 type.
888     //
889     BitWidth = IfrOneOf->Flags & EDKII_IFR_NUMERIC_SIZE_BIT;
890     Width = sizeof (UINT32);
891   } else {
892     Width = (UINT8) (1 << (IfrOneOf->Flags & EFI_IFR_NUMERIC_SIZE));
893   }
894 
895   GetOneOfOption (IfrOpCodeHeader, &OptionCount, &OptionWidth, NULL);
896   ASSERT (Width == OptionWidth);
897 
898   Length = sizeof (*OneOf) + OptionCount * Width;
899 
900   OneOf = InternalVarCheckAllocateZeroPool (Length);
901   ASSERT (OneOf != NULL);
902   OneOf->OpCode         = EFI_IFR_ONE_OF_OP;
903   OneOf->Length         = (UINT8) Length;
904   OneOf->VarOffset      = IfrOneOf->Question.VarStoreInfo.VarOffset;
905   OneOf->BitFieldStore  = StoredInBitField;
906   if (StoredInBitField) {
907     OneOf->StorageWidth = BitWidth;
908   } else {
909     OneOf->StorageWidth = Width;
910   }
911 
912   GetOneOfOption (IfrOpCodeHeader, &OptionCount, &OptionWidth, OneOf + 1);
913 
914   return (VAR_CHECK_HII_QUESTION_HEADER *) OneOf;
915 }
916 
917 /**
918   Parse Hii Question CheckBox.
919 
920   @param[in] IfrOpCodeHeader    Pointer to Ifr OpCode header.
921   @param[in] StoredInBitField   Whether the CheckBox is stored in bit field Storage.
922 
923   return Pointer to Hii Question.
924 
925 **/
926 VAR_CHECK_HII_QUESTION_HEADER *
ParseHiiQuestionCheckBox(IN EFI_IFR_OP_HEADER * IfrOpCodeHeader,IN BOOLEAN StoredInBitField)927 ParseHiiQuestionCheckBox (
928   IN EFI_IFR_OP_HEADER  *IfrOpCodeHeader,
929   IN BOOLEAN            StoredInBitField
930   )
931 {
932   EFI_IFR_CHECKBOX                  *IfrCheckBox;
933   VAR_CHECK_HII_QUESTION_CHECKBOX   *CheckBox;
934 
935   IfrCheckBox = (EFI_IFR_CHECKBOX *) IfrOpCodeHeader;
936 
937   CheckBox = InternalVarCheckAllocateZeroPool (sizeof (*CheckBox));
938   ASSERT (CheckBox != NULL);
939   CheckBox->OpCode         = EFI_IFR_CHECKBOX_OP;
940   CheckBox->Length         = (UINT8) sizeof (*CheckBox);;
941   CheckBox->VarOffset      = IfrCheckBox->Question.VarStoreInfo.VarOffset;
942   CheckBox->BitFieldStore  = StoredInBitField;
943   if (StoredInBitField) {
944     CheckBox->StorageWidth = 1;
945   } else {
946     CheckBox->StorageWidth = (UINT8) sizeof (BOOLEAN);
947   }
948 
949   return (VAR_CHECK_HII_QUESTION_HEADER *) CheckBox;
950 }
951 
952 /**
953   Parse Hii Question Numeric.
954 
955   @param[in] IfrOpCodeHeader    Pointer to Ifr OpCode header.
956   @param[in] StoredInBitField   Whether the Numeric is stored in bit field Storage.
957 
958   return Pointer to Hii Question.
959 
960 **/
961 VAR_CHECK_HII_QUESTION_HEADER *
ParseHiiQuestionNumeric(IN EFI_IFR_OP_HEADER * IfrOpCodeHeader,IN BOOLEAN StoredInBitField)962 ParseHiiQuestionNumeric (
963   IN EFI_IFR_OP_HEADER  *IfrOpCodeHeader,
964   IN BOOLEAN            StoredInBitField
965   )
966 {
967   EFI_IFR_NUMERIC                   *IfrNumeric;
968   VAR_CHECK_HII_QUESTION_NUMERIC    *Numeric;
969   UINT8                             Width;
970   UINT8                             BitWidth;
971 
972   IfrNumeric = (EFI_IFR_NUMERIC *) IfrOpCodeHeader;
973   BitWidth = 0;
974 
975   Numeric = InternalVarCheckAllocateZeroPool (sizeof (VAR_CHECK_HII_QUESTION_NUMERIC) + 2 * sizeof (UINT64));
976   ASSERT (Numeric != NULL);
977 
978   if (StoredInBitField) {
979     //
980     // When Numeric stored in bit field, the bit field width is saved in the lower six bits of the flag.
981     // And the Minimum Maximum of Numeric is saved as UINT32 type.
982     //
983     BitWidth = IfrNumeric->Flags & EDKII_IFR_NUMERIC_SIZE_BIT;
984     Width = sizeof (UINT32);
985   } else {
986     Width = (UINT8) (1 << (IfrNumeric->Flags & EFI_IFR_NUMERIC_SIZE));
987   }
988 
989   Numeric->OpCode         = EFI_IFR_NUMERIC_OP;
990   Numeric->Length         = (UINT8) (sizeof (VAR_CHECK_HII_QUESTION_NUMERIC) + 2 * Width);
991   Numeric->VarOffset      = IfrNumeric->Question.VarStoreInfo.VarOffset;
992   Numeric->BitFieldStore  = StoredInBitField;
993   if (StoredInBitField) {
994     Numeric->StorageWidth = BitWidth;
995   } else {
996     Numeric->StorageWidth = Width;
997   }
998 
999   CopyMem (Numeric + 1, &IfrNumeric->data, Width * 2);
1000 
1001   return (VAR_CHECK_HII_QUESTION_HEADER *) Numeric;
1002 }
1003 
1004 /**
1005   Parse Hii Question OrderedList.
1006 
1007   @param[in] IfrOpCodeHeader    Pointer to Ifr OpCode header.
1008 
1009   return Pointer to Hii Question.
1010 
1011 **/
1012 VAR_CHECK_HII_QUESTION_HEADER *
ParseHiiQuestionOrderedList(IN EFI_IFR_OP_HEADER * IfrOpCodeHeader)1013 ParseHiiQuestionOrderedList (
1014   IN EFI_IFR_OP_HEADER  *IfrOpCodeHeader
1015   )
1016 {
1017   EFI_IFR_ORDERED_LIST                  *IfrOrderedList;
1018   VAR_CHECK_HII_QUESTION_ORDEREDLIST    *OrderedList;
1019   UINTN                                 Length;
1020   UINTN                                 OptionCount;
1021   UINT8                                 OptionWidth;
1022 
1023   IfrOrderedList = (EFI_IFR_ORDERED_LIST *) IfrOpCodeHeader;
1024 
1025   GetOneOfOption (IfrOpCodeHeader, &OptionCount, &OptionWidth, NULL);
1026 
1027   Length = sizeof (*OrderedList) + OptionCount * OptionWidth;
1028 
1029   OrderedList = InternalVarCheckAllocateZeroPool (Length);
1030   ASSERT (OrderedList != NULL);
1031   OrderedList->OpCode        = EFI_IFR_ORDERED_LIST_OP;
1032   OrderedList->Length        = (UINT8) Length;
1033   OrderedList->VarOffset     = IfrOrderedList->Question.VarStoreInfo.VarOffset;
1034   OrderedList->StorageWidth  = OptionWidth;
1035   OrderedList->MaxContainers = IfrOrderedList->MaxContainers;
1036   OrderedList->BitFieldStore = FALSE;
1037 
1038   GetOneOfOption (IfrOpCodeHeader, &OptionCount, &OptionWidth, OrderedList + 1);
1039 
1040   return (VAR_CHECK_HII_QUESTION_HEADER *) OrderedList;
1041 }
1042 
1043 /**
1044   Parse and create Hii Question node.
1045 
1046   @param[in] HiiVariableNode    Pointer to Hii Variable node.
1047   @param[in] IfrOpCodeHeader    Pointer to Ifr OpCode header.
1048   @param[in] FromFv             Hii Question from FV.
1049   @param[in] StoredInBitField   Whether the Question is stored in bit field Storage.
1050 
1051 **/
1052 VOID
ParseHiiQuestion(IN VAR_CHECK_HII_VARIABLE_NODE * HiiVariableNode,IN EFI_IFR_OP_HEADER * IfrOpCodeHeader,IN BOOLEAN FromFv,IN BOOLEAN StoredInBitField)1053 ParseHiiQuestion (
1054   IN VAR_CHECK_HII_VARIABLE_NODE    *HiiVariableNode,
1055   IN  EFI_IFR_OP_HEADER             *IfrOpCodeHeader,
1056   IN BOOLEAN                        FromFv,
1057   IN BOOLEAN                        StoredInBitField
1058   )
1059 {
1060   VAR_CHECK_HII_QUESTION_HEADER *HiiQuestion;
1061   UINTN                         ArrayIndex;
1062 
1063   //
1064   // Currently only OneOf, CheckBox and Numeric can be stored in bit field.
1065   //
1066   switch (IfrOpCodeHeader->OpCode) {
1067     case EFI_IFR_ONE_OF_OP:
1068       HiiQuestion = ParseHiiQuestionOneOf (IfrOpCodeHeader, StoredInBitField);
1069       break;
1070 
1071     case EFI_IFR_CHECKBOX_OP:
1072       HiiQuestion = ParseHiiQuestionCheckBox (IfrOpCodeHeader, StoredInBitField);
1073       break;
1074 
1075     case EFI_IFR_NUMERIC_OP:
1076       HiiQuestion = ParseHiiQuestionNumeric (IfrOpCodeHeader, StoredInBitField);
1077       break;
1078 
1079     case EFI_IFR_ORDERED_LIST_OP:
1080       HiiQuestion = ParseHiiQuestionOrderedList (IfrOpCodeHeader);
1081       break;
1082 
1083     default:
1084       ASSERT (FALSE);
1085       return;
1086       break;
1087   }
1088 
1089   if (StoredInBitField) {
1090     ArrayIndex = HiiQuestion->VarOffset;
1091   } else {
1092     ArrayIndex = HiiQuestion->VarOffset * 8;
1093   }
1094   if (HiiVariableNode->HiiQuestionArray[ArrayIndex] != NULL) {
1095     MergeHiiQuestion (HiiVariableNode, HiiQuestion, FromFv);
1096   } else {
1097     HiiVariableNode->HiiQuestionArray[ArrayIndex] = HiiQuestion;
1098   }
1099 }
1100 
1101 /**
1102   Find Hii variable node by name and GUID.
1103 
1104   @param[in] Name   Pointer to variable name.
1105   @param[in] Guid   Pointer to vendor GUID.
1106 
1107   @return Pointer to Hii Variable node.
1108 
1109 **/
1110 VAR_CHECK_HII_VARIABLE_NODE *
FindHiiVariableNode(IN CHAR16 * Name,IN EFI_GUID * Guid)1111 FindHiiVariableNode (
1112   IN CHAR16     *Name,
1113   IN EFI_GUID   *Guid
1114   )
1115 {
1116   VAR_CHECK_HII_VARIABLE_NODE   *HiiVariableNode;
1117   LIST_ENTRY                    *Link;
1118 
1119   for (Link = mVarCheckHiiList.ForwardLink
1120       ;Link != &mVarCheckHiiList
1121       ;Link = Link->ForwardLink) {
1122     HiiVariableNode = VAR_CHECK_HII_VARIABLE_FROM_LINK (Link);
1123 
1124     if ((StrCmp (Name, (CHAR16 *) (HiiVariableNode->HiiVariable + 1)) == 0) &&
1125         CompareGuid (Guid, &HiiVariableNode->HiiVariable->Guid)) {
1126       return HiiVariableNode;
1127     }
1128   }
1129 
1130   return NULL;
1131 }
1132 
1133 /**
1134   Find Hii variable node by var store id.
1135 
1136   @param[in] VarStoreId         Var store id.
1137 
1138   @return Pointer to Hii Variable node.
1139 
1140 **/
1141 VAR_CHECK_HII_VARIABLE_NODE *
FindHiiVariableNodeByVarStoreId(IN EFI_VARSTORE_ID VarStoreId)1142 FindHiiVariableNodeByVarStoreId (
1143   IN EFI_VARSTORE_ID            VarStoreId
1144   )
1145 {
1146   VAR_CHECK_HII_VARIABLE_NODE   *HiiVariableNode;
1147   LIST_ENTRY                    *Link;
1148 
1149   if (VarStoreId == 0) {
1150     //
1151     // The variable store identifier, which is unique within the current form set.
1152     // A value of zero is invalid.
1153     //
1154     return NULL;
1155   }
1156 
1157   for (Link = mVarCheckHiiList.ForwardLink
1158       ;Link != &mVarCheckHiiList
1159       ;Link = Link->ForwardLink) {
1160     HiiVariableNode = VAR_CHECK_HII_VARIABLE_FROM_LINK (Link);
1161     //
1162     // The variable store identifier, which is unique within the current form set.
1163     //
1164     if (VarStoreId == HiiVariableNode->VarStoreId) {
1165       return HiiVariableNode;
1166     }
1167   }
1168 
1169   return NULL;
1170 }
1171 
1172 /**
1173   Destroy var store id in the Hii Variable node after parsing one Hii Package.
1174 
1175 **/
1176 VOID
DestroyVarStoreId(VOID)1177 DestroyVarStoreId (
1178   VOID
1179   )
1180 {
1181   VAR_CHECK_HII_VARIABLE_NODE   *HiiVariableNode;
1182   LIST_ENTRY                    *Link;
1183 
1184   for (Link = mVarCheckHiiList.ForwardLink
1185       ;Link != &mVarCheckHiiList
1186       ;Link = Link->ForwardLink) {
1187     HiiVariableNode = VAR_CHECK_HII_VARIABLE_FROM_LINK (Link);
1188     //
1189     // The variable store identifier, which is unique within the current form set.
1190     // A value of zero is invalid.
1191     //
1192     HiiVariableNode->VarStoreId = 0;
1193   }
1194 }
1195 
1196 /**
1197   Create Hii Variable node.
1198 
1199   @param[in] IfrEfiVarStore  Pointer to EFI VARSTORE.
1200 
1201 **/
1202 VOID
CreateHiiVariableNode(IN EFI_IFR_VARSTORE_EFI * IfrEfiVarStore)1203 CreateHiiVariableNode (
1204   IN EFI_IFR_VARSTORE_EFI   *IfrEfiVarStore
1205   )
1206 {
1207   VAR_CHECK_HII_VARIABLE_NODE   *HiiVariableNode;
1208   VAR_CHECK_HII_VARIABLE_HEADER *HiiVariable;
1209   UINTN                         HeaderLength;
1210   CHAR16                        *VarName;
1211   UINTN                         VarNameSize;
1212 
1213   //
1214   // Get variable name.
1215   //
1216   VarNameSize = AsciiStrSize ((CHAR8 *) IfrEfiVarStore->Name) * sizeof (CHAR16);
1217   if (VarNameSize > mMaxVarNameSize) {
1218     mVarName = InternalVarCheckReallocatePool (mMaxVarNameSize, VarNameSize, mVarName);
1219     ASSERT (mVarName != NULL);
1220     mMaxVarNameSize = VarNameSize;
1221   }
1222   AsciiStrToUnicodeStrS ((CHAR8 *) IfrEfiVarStore->Name, mVarName, mMaxVarNameSize / sizeof (CHAR16));
1223   VarName = mVarName;
1224 
1225   HiiVariableNode = FindHiiVariableNode (
1226                       VarName,
1227                       &IfrEfiVarStore->Guid
1228                       );
1229   if (HiiVariableNode == NULL) {
1230     //
1231     // Not found, then create new.
1232     //
1233     HeaderLength = sizeof (*HiiVariable) + VarNameSize;
1234     HiiVariable = InternalVarCheckAllocateZeroPool (HeaderLength);
1235     ASSERT (HiiVariable != NULL);
1236     HiiVariable->Revision = VAR_CHECK_HII_REVISION;
1237     HiiVariable->OpCode = EFI_IFR_VARSTORE_EFI_OP;
1238     HiiVariable->HeaderLength = (UINT16) HeaderLength;
1239     HiiVariable->Size = IfrEfiVarStore->Size;
1240     HiiVariable->Attributes = IfrEfiVarStore->Attributes;
1241     CopyGuid (&HiiVariable->Guid, &IfrEfiVarStore->Guid);
1242     StrCpyS ((CHAR16 *) (HiiVariable + 1), VarNameSize / sizeof (CHAR16), VarName);
1243 
1244     HiiVariableNode = InternalVarCheckAllocateZeroPool (sizeof (*HiiVariableNode));
1245     ASSERT (HiiVariableNode != NULL);
1246     HiiVariableNode->Signature = VAR_CHECK_HII_VARIABLE_NODE_SIGNATURE;
1247     HiiVariableNode->HiiVariable = HiiVariable;
1248     //
1249     // The variable store identifier, which is unique within the current form set.
1250     //
1251     HiiVariableNode->VarStoreId = IfrEfiVarStore->VarStoreId;
1252     HiiVariableNode->HiiQuestionArray = InternalVarCheckAllocateZeroPool (IfrEfiVarStore->Size * 8 * sizeof (VAR_CHECK_HII_QUESTION_HEADER *));
1253 
1254     InsertTailList (&mVarCheckHiiList, &HiiVariableNode->Link);
1255   } else {
1256     HiiVariableNode->VarStoreId = IfrEfiVarStore->VarStoreId;
1257   }
1258 }
1259 
1260 /**
1261   Parse and create Hii Variable node list.
1262 
1263   @param[in] HiiPackage         Pointer to Hii Package.
1264 
1265 **/
1266 VOID
ParseHiiVariable(IN VOID * HiiPackage)1267 ParseHiiVariable (
1268   IN VOID       *HiiPackage
1269   )
1270 {
1271   EFI_HII_PACKAGE_HEADER    *HiiPackageHeader;
1272   EFI_IFR_OP_HEADER         *IfrOpCodeHeader;
1273   EFI_IFR_VARSTORE_EFI      *IfrEfiVarStore;
1274 
1275   HiiPackageHeader = (EFI_HII_PACKAGE_HEADER *) HiiPackage;
1276 
1277   switch (HiiPackageHeader->Type) {
1278     case EFI_HII_PACKAGE_FORMS:
1279       IfrOpCodeHeader = (EFI_IFR_OP_HEADER *) (HiiPackageHeader + 1);
1280 
1281       while ((UINTN) IfrOpCodeHeader < (UINTN) HiiPackageHeader + HiiPackageHeader->Length) {
1282         switch (IfrOpCodeHeader->OpCode) {
1283           case EFI_IFR_VARSTORE_EFI_OP:
1284             //
1285             // Come to EFI VARSTORE in Form Package.
1286             //
1287             IfrEfiVarStore = (EFI_IFR_VARSTORE_EFI *) IfrOpCodeHeader;
1288             if ((IfrEfiVarStore->Header.Length >= sizeof (EFI_IFR_VARSTORE_EFI)) &&
1289                 ((IfrEfiVarStore->Attributes & EFI_VARIABLE_NON_VOLATILE) != 0)) {
1290               //
1291               // Only create node list for Hii Variable with NV attribute.
1292               //
1293               CreateHiiVariableNode (IfrEfiVarStore);
1294             }
1295             break;
1296 
1297           default:
1298             break;
1299         }
1300       IfrOpCodeHeader = (EFI_IFR_OP_HEADER *) ((UINTN) IfrOpCodeHeader + IfrOpCodeHeader->Length);
1301       }
1302       break;
1303 
1304     default:
1305       break;
1306   }
1307 }
1308 
1309 /**
1310   Var Check Parse Hii Package.
1311 
1312   @param[in] HiiPackage         Pointer to Hii Package.
1313   @param[in] FromFv             Hii Package from FV.
1314 
1315 **/
1316 VOID
VarCheckParseHiiPackage(IN VOID * HiiPackage,IN BOOLEAN FromFv)1317 VarCheckParseHiiPackage (
1318   IN VOID       *HiiPackage,
1319   IN BOOLEAN    FromFv
1320   )
1321 {
1322   EFI_HII_PACKAGE_HEADER        *HiiPackageHeader;
1323   EFI_IFR_OP_HEADER             *IfrOpCodeHeader;
1324   VAR_CHECK_HII_VARIABLE_NODE   *HiiVariableNode;
1325   BOOLEAN                       QuestionStoredInBitField;
1326 
1327   //
1328   // Parse and create Hii Variable node list for this Hii Package.
1329   //
1330   ParseHiiVariable (HiiPackage);
1331 
1332   HiiPackageHeader = (EFI_HII_PACKAGE_HEADER *) HiiPackage;
1333 
1334   QuestionStoredInBitField = FALSE;
1335 
1336   switch (HiiPackageHeader->Type) {
1337     case EFI_HII_PACKAGE_FORMS:
1338       IfrOpCodeHeader = (EFI_IFR_OP_HEADER *) (HiiPackageHeader + 1);
1339 
1340       while ((UINTN) IfrOpCodeHeader < (UINTN) HiiPackageHeader + HiiPackageHeader->Length) {
1341         switch (IfrOpCodeHeader->OpCode) {
1342           case EFI_IFR_GUID_OP:
1343             if (CompareGuid ((EFI_GUID *)((UINTN)IfrOpCodeHeader + sizeof (EFI_IFR_OP_HEADER)), &gEdkiiIfrBitVarstoreGuid)) {
1344               QuestionStoredInBitField = TRUE;
1345             }
1346             break;
1347 
1348           case EFI_IFR_END_OP:
1349             QuestionStoredInBitField = FALSE;
1350             break;
1351 
1352           case EFI_IFR_ONE_OF_OP:
1353           case EFI_IFR_CHECKBOX_OP:
1354           case EFI_IFR_NUMERIC_OP:
1355           case EFI_IFR_ORDERED_LIST_OP:
1356             HiiVariableNode = FindHiiVariableNodeByVarStoreId (((EFI_IFR_ONE_OF *) IfrOpCodeHeader)->Question.VarStoreId);
1357             if ((HiiVariableNode == NULL) ||
1358                 //
1359                 // No related Hii Variable node found.
1360                 //
1361                 ((((EFI_IFR_ONE_OF *) IfrOpCodeHeader)->Question.Header.Prompt == 0) && (((EFI_IFR_ONE_OF *) IfrOpCodeHeader)->Question.Header.Help == 0))) {
1362                 //
1363                 // meanless IFR item introduced by ECP.
1364                 //
1365             } else {
1366               //
1367               // Normal IFR
1368               //
1369               ParseHiiQuestion (HiiVariableNode, IfrOpCodeHeader, FromFv, QuestionStoredInBitField);
1370             }
1371           default:
1372             break;
1373         }
1374         IfrOpCodeHeader = (EFI_IFR_OP_HEADER *) ((UINTN) IfrOpCodeHeader + IfrOpCodeHeader->Length);
1375       }
1376       break;
1377 
1378     default:
1379       break;
1380   }
1381   DestroyVarStoreId ();
1382 }
1383 
1384 /**
1385   Var Check Parse Hii Database.
1386 
1387   @param[in] HiiDatabase        Pointer to Hii Database.
1388   @param[in] HiiDatabaseSize    Hii Database size.
1389 
1390 **/
1391 VOID
VarCheckParseHiiDatabase(IN VOID * HiiDatabase,IN UINTN HiiDatabaseSize)1392 VarCheckParseHiiDatabase (
1393   IN VOID       *HiiDatabase,
1394   IN UINTN      HiiDatabaseSize
1395   )
1396 {
1397   EFI_HII_PACKAGE_LIST_HEADER   *HiiPackageListHeader;
1398   EFI_HII_PACKAGE_HEADER        *HiiPackageHeader;
1399 
1400   HiiPackageListHeader = (EFI_HII_PACKAGE_LIST_HEADER *) HiiDatabase;
1401 
1402   while ((UINTN) HiiPackageListHeader < ((UINTN) HiiDatabase + HiiDatabaseSize)) {
1403     HiiPackageHeader = (EFI_HII_PACKAGE_HEADER *) (HiiPackageListHeader + 1);
1404 
1405     while ((UINTN) HiiPackageHeader < ((UINTN) HiiPackageListHeader + HiiPackageListHeader->PackageLength)) {
1406       //
1407       // Parse Hii Package.
1408       //
1409       VarCheckParseHiiPackage (HiiPackageHeader, FALSE);
1410 
1411       HiiPackageHeader = (EFI_HII_PACKAGE_HEADER *) ((UINTN) HiiPackageHeader + HiiPackageHeader->Length);
1412     }
1413 
1414     HiiPackageListHeader = (EFI_HII_PACKAGE_LIST_HEADER *) ((UINTN) HiiPackageListHeader + HiiPackageListHeader->PackageLength);
1415   }
1416 }
1417 
1418 /**
1419   Destroy Hii Variable node.
1420 
1421 **/
1422 VOID
DestroyHiiVariableNode(VOID)1423 DestroyHiiVariableNode (
1424   VOID
1425   )
1426 {
1427   VAR_CHECK_HII_VARIABLE_NODE   *HiiVariableNode;
1428   LIST_ENTRY                    *HiiVariableLink;
1429   UINTN                         Index;
1430 
1431   while (mVarCheckHiiList.ForwardLink != &mVarCheckHiiList) {
1432     HiiVariableLink = mVarCheckHiiList.ForwardLink;
1433     HiiVariableNode = VAR_CHECK_HII_VARIABLE_FROM_LINK (HiiVariableLink);
1434 
1435     RemoveEntryList (&HiiVariableNode->Link);
1436 
1437     //
1438     // Free the allocated buffer.
1439     //
1440     for (Index = 0; Index < HiiVariableNode->HiiVariable->Size * (UINTN) 8; Index++) {
1441       if (HiiVariableNode->HiiQuestionArray[Index] != NULL) {
1442         InternalVarCheckFreePool (HiiVariableNode->HiiQuestionArray[Index]);
1443       }
1444     }
1445     InternalVarCheckFreePool (HiiVariableNode->HiiQuestionArray);
1446     InternalVarCheckFreePool (HiiVariableNode->HiiVariable);
1447     InternalVarCheckFreePool (HiiVariableNode);
1448   }
1449 }
1450 
1451 /**
1452   Build VarCheckHiiBin.
1453 
1454   @param[out] Size      Pointer to VarCheckHii size.
1455 
1456   @return Pointer to VarCheckHiiBin.
1457 
1458 **/
1459 VOID *
BuildVarCheckHiiBin(OUT UINTN * Size)1460 BuildVarCheckHiiBin (
1461   OUT UINTN  *Size
1462   )
1463 {
1464   VAR_CHECK_HII_VARIABLE_NODE   *HiiVariableNode;
1465   LIST_ENTRY                    *HiiVariableLink;
1466   UINTN                         Index;
1467   VOID                          *Data;
1468   UINT8                         *Ptr;
1469   UINT32                        BinSize;
1470   UINT32                        HiiVariableLength;
1471 
1472   //
1473   // Get Size
1474   //
1475   BinSize = 0;
1476 
1477   for (HiiVariableLink = mVarCheckHiiList.ForwardLink
1478       ;HiiVariableLink != &mVarCheckHiiList
1479       ;HiiVariableLink = HiiVariableLink->ForwardLink) {
1480     //
1481     // For Hii Variable header align.
1482     //
1483     BinSize = (UINT32) HEADER_ALIGN (BinSize);
1484 
1485     HiiVariableNode = VAR_CHECK_HII_VARIABLE_FROM_LINK (HiiVariableLink);
1486     HiiVariableLength = HiiVariableNode->HiiVariable->HeaderLength;
1487 
1488     for (Index = 0; Index < HiiVariableNode->HiiVariable->Size * (UINTN) 8; Index++) {
1489       if (HiiVariableNode->HiiQuestionArray[Index] != NULL) {
1490         //
1491         // For Hii Question header align.
1492         //
1493         HiiVariableLength = (UINT32) HEADER_ALIGN (HiiVariableLength);
1494         HiiVariableLength += HiiVariableNode->HiiQuestionArray[Index]->Length;
1495       }
1496     }
1497 
1498     HiiVariableNode->HiiVariable->Length = HiiVariableLength;
1499     BinSize += HiiVariableLength;
1500   }
1501 
1502   DEBUG ((DEBUG_INFO, "VarCheckHiiBin - size = 0x%x\n", BinSize));
1503   if (BinSize == 0) {
1504     *Size = BinSize;
1505     return NULL;
1506   }
1507 
1508   //
1509   // AllocatePages () and AllocatePool () from gBS are used for the process of VarCheckHiiBin generation.
1510   // Only here AllocateRuntimeZeroPool () from MemoryAllocateLib is used for runtime access
1511   // in SetVariable check handler.
1512   //
1513   Data = AllocateRuntimeZeroPool (BinSize);
1514   ASSERT (Data != NULL);
1515   //
1516   // Make sure the allocated buffer for VarCheckHiiBin at required alignment.
1517   //
1518   ASSERT ((((UINTN) Data) & (HEADER_ALIGNMENT - 1)) == 0);
1519   DEBUG ((DEBUG_INFO, "VarCheckHiiBin - built at 0x%x\n", Data));
1520 
1521   //
1522   // Gen Data
1523   //
1524   Ptr = Data;
1525   for (HiiVariableLink = mVarCheckHiiList.ForwardLink
1526       ;HiiVariableLink != &mVarCheckHiiList
1527       ;HiiVariableLink = HiiVariableLink->ForwardLink) {
1528     //
1529     // For Hii Variable header align.
1530     //
1531     Ptr = (UINT8 *) HEADER_ALIGN (Ptr);
1532 
1533     HiiVariableNode = VAR_CHECK_HII_VARIABLE_FROM_LINK (HiiVariableLink);
1534     CopyMem (Ptr, HiiVariableNode->HiiVariable, HiiVariableNode->HiiVariable->HeaderLength);
1535     Ptr += HiiVariableNode->HiiVariable->HeaderLength;
1536 
1537     for (Index = 0; Index < HiiVariableNode->HiiVariable->Size * (UINTN) 8; Index++) {
1538       if (HiiVariableNode->HiiQuestionArray[Index] != NULL) {
1539         //
1540         // For Hii Question header align.
1541         //
1542         Ptr = (UINT8 *) HEADER_ALIGN (Ptr);
1543         CopyMem (Ptr, HiiVariableNode->HiiQuestionArray[Index], HiiVariableNode->HiiQuestionArray[Index]->Length);
1544         Ptr += HiiVariableNode->HiiQuestionArray[Index]->Length;
1545       }
1546     }
1547   }
1548 
1549   *Size = BinSize;
1550   return Data;
1551 }
1552 
1553 /**
1554   Generate VarCheckHiiBin from Hii Database and FV.
1555 
1556 **/
1557 VOID
1558 EFIAPI
VarCheckHiiGen(VOID)1559 VarCheckHiiGen (
1560   VOID
1561   )
1562 {
1563   VarCheckHiiGenFromHiiDatabase ();
1564   VarCheckHiiGenFromFv ();
1565 
1566   mVarCheckHiiBin = BuildVarCheckHiiBin (&mVarCheckHiiBinSize);
1567   if (mVarCheckHiiBin == NULL) {
1568     DEBUG ((DEBUG_INFO, "[VarCheckHii] This driver could be removed from *.dsc and *.fdf\n"));
1569     return;
1570   }
1571 
1572   DestroyHiiVariableNode ();
1573   if (mVarName != NULL) {
1574     InternalVarCheckFreePool (mVarName);
1575   }
1576 
1577 #ifdef DUMP_VAR_CHECK_HII
1578   DEBUG_CODE (
1579     DumpVarCheckHii (mVarCheckHiiBin, mVarCheckHiiBinSize);
1580   );
1581 #endif
1582 }
1583 
1584