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