1 /** @file
2   HII Library implementation that uses DXE protocols and services.
3 
4   Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
5   SPDX-License-Identifier: BSD-2-Clause-Patent
6 
7 **/
8 
9 #include "InternalHiiLib.h"
10 
11 #define GUID_CONFIG_STRING_TYPE 0x00
12 #define NAME_CONFIG_STRING_TYPE 0x01
13 #define PATH_CONFIG_STRING_TYPE 0x02
14 
15 #define ACTION_SET_DEFAUTL_VALUE 0x01
16 #define ACTION_VALIDATE_SETTING  0x02
17 
18 #define HII_LIB_DEFAULT_VARSTORE_SIZE  0x200
19 
20 typedef struct {
21   LIST_ENTRY          Entry;      // Link to Block array
22   UINT16              Offset;
23   UINT16              Width;
24   UINT8               OpCode;
25   UINT8               Scope;
26 } IFR_BLOCK_DATA;
27 
28 typedef struct {
29   EFI_VARSTORE_ID     VarStoreId;
30   UINT16              Size;
31 } IFR_VARSTORAGE_DATA;
32 
33 //
34 // <ConfigHdr> Template
35 //
36 GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR16 mConfigHdrTemplate[] = L"GUID=00000000000000000000000000000000&NAME=0000&PATH=00";
37 
38 EFI_FORM_BROWSER2_PROTOCOL  *mUefiFormBrowser2 = NULL;
39 
40 //
41 // Template used to mark the end of a list of packages
42 //
43 GLOBAL_REMOVE_IF_UNREFERENCED CONST EFI_HII_PACKAGE_HEADER  mEndOfPakageList = {
44   sizeof (EFI_HII_PACKAGE_HEADER),
45   EFI_HII_PACKAGE_END
46 };
47 
48 /**
49   Extract Hii package list GUID for given HII handle.
50 
51   If HiiHandle could not be found in the HII database, then ASSERT.
52   If Guid is NULL, then ASSERT.
53 
54   @param  Handle              Hii handle
55   @param  Guid                Package list GUID
56 
57   @retval EFI_SUCCESS         Successfully extract GUID from Hii database.
58 
59 **/
60 EFI_STATUS
61 EFIAPI
InternalHiiExtractGuidFromHiiHandle(IN EFI_HII_HANDLE Handle,OUT EFI_GUID * Guid)62 InternalHiiExtractGuidFromHiiHandle (
63   IN      EFI_HII_HANDLE      Handle,
64   OUT     EFI_GUID            *Guid
65   )
66 {
67   EFI_STATUS                   Status;
68   UINTN                        BufferSize;
69   EFI_HII_PACKAGE_LIST_HEADER  *HiiPackageList;
70 
71   ASSERT (Guid != NULL);
72   ASSERT (Handle != NULL);
73 
74   //
75   // Get HII PackageList
76   //
77   BufferSize = 0;
78   HiiPackageList = NULL;
79 
80   Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, Handle, &BufferSize, HiiPackageList);
81   ASSERT (Status != EFI_NOT_FOUND);
82 
83   if (Status == EFI_BUFFER_TOO_SMALL) {
84     HiiPackageList = AllocatePool (BufferSize);
85     ASSERT (HiiPackageList != NULL);
86 
87     Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, Handle, &BufferSize, HiiPackageList);
88   }
89   if (EFI_ERROR (Status)) {
90     FreePool (HiiPackageList);
91     return Status;
92   }
93 
94   //
95   // Extract GUID
96   //
97   CopyGuid (Guid, &HiiPackageList->PackageListGuid);
98 
99   FreePool (HiiPackageList);
100 
101   return EFI_SUCCESS;
102 }
103 
104 /**
105   Registers a list of packages in the HII Database and returns the HII Handle
106   associated with that registration.  If an HII Handle has already been registered
107   with the same PackageListGuid and DeviceHandle, then NULL is returned.  If there
108   are not enough resources to perform the registration, then NULL is returned.
109   If an empty list of packages is passed in, then NULL is returned.  If the size of
110   the list of package is 0, then NULL is returned.
111 
112   The variable arguments are pointers which point to package header that defined
113   by UEFI VFR compiler and StringGather tool.
114 
115   #pragma pack (push, 1)
116   typedef struct {
117     UINT32                  BinaryLength;
118     EFI_HII_PACKAGE_HEADER  PackageHeader;
119   } EDKII_AUTOGEN_PACKAGES_HEADER;
120   #pragma pack (pop)
121 
122   @param[in]  PackageListGuid  The GUID of the package list.
123   @param[in]  DeviceHandle     If not NULL, the Device Handle on which
124                                an instance of DEVICE_PATH_PROTOCOL is installed.
125                                This Device Handle uniquely defines the device that
126                                the added packages are associated with.
127   @param[in]  ...              The variable argument list that contains pointers
128                                to packages terminated by a NULL.
129 
130   @retval NULL   A HII Handle has already been registered in the HII Database with
131                  the same PackageListGuid and DeviceHandle.
132   @retval NULL   The HII Handle could not be created.
133   @retval NULL   An empty list of packages was passed in.
134   @retval NULL   All packages are empty.
135   @retval Other  The HII Handle associated with the newly registered package list.
136 
137 **/
138 EFI_HII_HANDLE
139 EFIAPI
HiiAddPackages(IN CONST EFI_GUID * PackageListGuid,IN EFI_HANDLE DeviceHandle OPTIONAL,...)140 HiiAddPackages (
141   IN CONST EFI_GUID    *PackageListGuid,
142   IN       EFI_HANDLE  DeviceHandle  OPTIONAL,
143   ...
144   )
145 {
146   EFI_STATUS                   Status;
147   VA_LIST                      Args;
148   UINT32                       *Package;
149   EFI_HII_PACKAGE_LIST_HEADER  *PackageListHeader;
150   EFI_HII_HANDLE               HiiHandle;
151   UINT32                       Length;
152   UINT8                        *Data;
153 
154   ASSERT (PackageListGuid != NULL);
155 
156   //
157   // Calculate the length of all the packages in the variable argument list
158   //
159   for (Length = 0, VA_START (Args, DeviceHandle); (Package = VA_ARG (Args, UINT32 *)) != NULL; ) {
160     Length += (ReadUnaligned32 (Package) - sizeof (UINT32));
161   }
162   VA_END (Args);
163 
164   //
165   // If there are no packages in the variable argument list or all the packages
166   // are empty, then return a NULL HII Handle
167   //
168   if (Length == 0) {
169     return NULL;
170   }
171 
172   //
173   // Add the length of the Package List Header and the terminating Package Header
174   //
175   Length += sizeof (EFI_HII_PACKAGE_LIST_HEADER) + sizeof (EFI_HII_PACKAGE_HEADER);
176 
177   //
178   // Allocate the storage for the entire Package List
179   //
180   PackageListHeader = AllocateZeroPool (Length);
181 
182   //
183   // If the Package List can not be allocated, then return a NULL HII Handle
184   //
185   if (PackageListHeader == NULL) {
186     return NULL;
187   }
188 
189   //
190   // Fill in the GUID and Length of the Package List Header
191   //
192   CopyGuid (&PackageListHeader->PackageListGuid, PackageListGuid);
193   PackageListHeader->PackageLength = Length;
194 
195   //
196   // Initialize a pointer to the beginning if the Package List data
197   //
198   Data = (UINT8 *)(PackageListHeader + 1);
199 
200   //
201   // Copy the data from each package in the variable argument list
202   //
203   for (VA_START (Args, DeviceHandle); (Package = VA_ARG (Args, UINT32 *)) != NULL; ) {
204     Length = ReadUnaligned32 (Package) - sizeof (UINT32);
205     CopyMem (Data, Package + 1, Length);
206     Data += Length;
207   }
208   VA_END (Args);
209 
210   //
211   // Append a package of type EFI_HII_PACKAGE_END to mark the end of the package list
212   //
213   CopyMem (Data, &mEndOfPakageList, sizeof (mEndOfPakageList));
214 
215   //
216   // Register the package list with the HII Database
217   //
218   Status = gHiiDatabase->NewPackageList (
219                            gHiiDatabase,
220                            PackageListHeader,
221                            DeviceHandle,
222                            &HiiHandle
223                            );
224   if (EFI_ERROR (Status)) {
225     HiiHandle = NULL;
226   }
227 
228   //
229   // Free the allocated package list
230   //
231   FreePool (PackageListHeader);
232 
233   //
234   // Return the new HII Handle
235   //
236   return HiiHandle;
237 }
238 
239 /**
240   Removes a package list from the HII database.
241 
242   If HiiHandle is NULL, then ASSERT.
243   If HiiHandle is not a valid EFI_HII_HANDLE in the HII database, then ASSERT.
244 
245   @param[in]  HiiHandle   The handle that was previously registered in the HII database
246 
247 **/
248 VOID
249 EFIAPI
HiiRemovePackages(IN EFI_HII_HANDLE HiiHandle)250 HiiRemovePackages (
251   IN      EFI_HII_HANDLE      HiiHandle
252   )
253 {
254   EFI_STATUS Status;
255 
256   ASSERT (HiiHandle != NULL);
257   Status = gHiiDatabase->RemovePackageList (gHiiDatabase, HiiHandle);
258   ASSERT_EFI_ERROR (Status);
259 }
260 
261 
262 /**
263   Retrieves the array of all the HII Handles or the HII handles of a specific
264   package list GUID in the HII Database.
265   This array is terminated with a NULL HII Handle.
266   This function allocates the returned array using AllocatePool().
267   The caller is responsible for freeing the array with FreePool().
268 
269   @param[in]  PackageListGuid  An optional parameter that is used to request
270                                HII Handles associated with a specific
271                                Package List GUID.  If this parameter is NULL,
272                                then all the HII Handles in the HII Database
273                                are returned.  If this parameter is not NULL,
274                                then zero or more HII Handles associated with
275                                PackageListGuid are returned.
276 
277   @retval NULL   No HII handles were found in the HII database
278   @retval NULL   The array of HII Handles could not be retrieved
279   @retval Other  A pointer to the NULL terminated array of HII Handles
280 
281 **/
282 EFI_HII_HANDLE *
283 EFIAPI
HiiGetHiiHandles(IN CONST EFI_GUID * PackageListGuid OPTIONAL)284 HiiGetHiiHandles (
285   IN CONST EFI_GUID  *PackageListGuid  OPTIONAL
286   )
287 {
288   EFI_STATUS      Status;
289   UINTN           HandleBufferLength;
290   EFI_HII_HANDLE  TempHiiHandleBuffer;
291   EFI_HII_HANDLE  *HiiHandleBuffer;
292   EFI_GUID        Guid;
293   UINTN           Index1;
294   UINTN           Index2;
295 
296   //
297   // Retrieve the size required for the buffer of all HII handles.
298   //
299   HandleBufferLength = 0;
300   Status = gHiiDatabase->ListPackageLists (
301                            gHiiDatabase,
302                            EFI_HII_PACKAGE_TYPE_ALL,
303                            NULL,
304                            &HandleBufferLength,
305                            &TempHiiHandleBuffer
306                            );
307 
308   //
309   // If ListPackageLists() returns EFI_SUCCESS for a zero size,
310   // then there are no HII handles in the HII database.  If ListPackageLists()
311   // returns an error other than EFI_BUFFER_TOO_SMALL, then there are no HII
312   // handles in the HII database.
313   //
314   if (Status != EFI_BUFFER_TOO_SMALL) {
315     //
316     // Return NULL if the size can not be retrieved, or if there are no HII
317     // handles in the HII Database
318     //
319     return NULL;
320   }
321 
322   //
323   // Allocate the array of HII handles to hold all the HII Handles and a NULL terminator
324   //
325   HiiHandleBuffer = AllocateZeroPool (HandleBufferLength + sizeof (EFI_HII_HANDLE));
326   if (HiiHandleBuffer == NULL) {
327     //
328     // Return NULL if allocation fails.
329     //
330     return NULL;
331   }
332 
333   //
334   // Retrieve the array of HII Handles in the HII Database
335   //
336   Status = gHiiDatabase->ListPackageLists (
337                            gHiiDatabase,
338                            EFI_HII_PACKAGE_TYPE_ALL,
339                            NULL,
340                            &HandleBufferLength,
341                            HiiHandleBuffer
342                            );
343   if (EFI_ERROR (Status)) {
344     //
345     // Free the buffer and return NULL if the HII handles can not be retrieved.
346     //
347     FreePool (HiiHandleBuffer);
348     return NULL;
349   }
350 
351   if (PackageListGuid == NULL) {
352     //
353     // Return the NULL terminated array of HII handles in the HII Database
354     //
355     return HiiHandleBuffer;
356   } else {
357     for (Index1 = 0, Index2 = 0; HiiHandleBuffer[Index1] != NULL; Index1++) {
358       Status = InternalHiiExtractGuidFromHiiHandle (HiiHandleBuffer[Index1], &Guid);
359       ASSERT_EFI_ERROR (Status);
360       if (CompareGuid (&Guid, PackageListGuid)) {
361         HiiHandleBuffer[Index2++] = HiiHandleBuffer[Index1];
362       }
363     }
364     if (Index2 > 0) {
365       HiiHandleBuffer[Index2] = NULL;
366       return HiiHandleBuffer;
367     } else {
368       FreePool (HiiHandleBuffer);
369       return NULL;
370     }
371   }
372 }
373 
374 /**
375   This function allows a caller to extract the form set opcode form the Hii Handle.
376   The returned buffer is allocated using AllocatePool().The caller is responsible
377   for freeing the allocated buffer using FreePool().
378 
379   @param Handle            The HII handle.
380   @param Buffer            On return, points to a pointer which point to the buffer that contain the formset opcode.
381   @param BufferSize        On return, points to the length of the buffer.
382 
383   @retval EFI_OUT_OF_RESOURCES   No enough memory resource is allocated.
384   @retval EFI_NOT_FOUND          Can't find the package data for the input Handle.
385   @retval EFI_INVALID_PARAMETER  The input parameters are not correct.
386   @retval EFI_SUCCESS            Get the formset opcode from the hii handle successfully.
387 
388 **/
389 EFI_STATUS
390 EFIAPI
HiiGetFormSetFromHiiHandle(IN EFI_HII_HANDLE Handle,OUT EFI_IFR_FORM_SET ** Buffer,OUT UINTN * BufferSize)391 HiiGetFormSetFromHiiHandle(
392   IN  EFI_HII_HANDLE     Handle,
393   OUT EFI_IFR_FORM_SET   **Buffer,
394   OUT UINTN              *BufferSize
395   )
396 {
397   EFI_STATUS                   Status;
398   UINTN                        PackageListSize;
399   UINTN                        TempSize;
400   EFI_HII_PACKAGE_LIST_HEADER  *HiiPackageList;
401   UINT8                        *Package;
402   UINT8                        *OpCodeData;
403   UINT8                        *FormSetBuffer;
404   UINT8                        *TempBuffer;
405   UINT32                       Offset;
406   UINT32                       Offset2;
407   UINT32                       PackageListLength;
408   EFI_HII_PACKAGE_HEADER       PackageHeader;
409 
410   TempSize = 0;
411   FormSetBuffer = NULL;
412   TempBuffer    = NULL;
413 
414   //
415   // Get HII PackageList
416   //
417   PackageListSize = 0;
418   HiiPackageList = NULL;
419   Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, Handle, &PackageListSize, HiiPackageList);
420   if (EFI_ERROR (Status) && (Status != EFI_BUFFER_TOO_SMALL)) {
421     return Status;
422   }
423 
424   HiiPackageList = AllocatePool (PackageListSize);
425   if (HiiPackageList == NULL) {
426     return EFI_OUT_OF_RESOURCES;
427   }
428 
429   Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, Handle, &PackageListSize, HiiPackageList);
430   ASSERT_EFI_ERROR (Status);
431 
432   //
433   // Get Form package from this HII package List
434   //
435   Status = EFI_NOT_FOUND;
436   Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
437   PackageListLength = ReadUnaligned32 (&HiiPackageList->PackageLength);
438 
439   while (Offset < PackageListLength) {
440     Package = ((UINT8 *) HiiPackageList) + Offset;
441     CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
442     Offset += PackageHeader.Length;
443 
444     if (PackageHeader.Type != EFI_HII_PACKAGE_FORMS) {
445       continue;
446     }
447 
448     //
449     // Search FormSet Opcode in this Form Package
450     //
451     Offset2 = sizeof (EFI_HII_PACKAGE_HEADER);
452     while (Offset2 < PackageHeader.Length) {
453       OpCodeData = Package + Offset2;
454       Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;
455 
456       if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode != EFI_IFR_FORM_SET_OP) {
457         continue;
458       }
459 
460       if (FormSetBuffer != NULL){
461         TempBuffer = ReallocatePool (
462                        TempSize,
463                        TempSize + ((EFI_IFR_OP_HEADER *) OpCodeData)->Length,
464                        FormSetBuffer
465                        );
466         if (TempBuffer == NULL) {
467           Status = EFI_OUT_OF_RESOURCES;
468           goto Done;
469         }
470         CopyMem (TempBuffer + TempSize,  OpCodeData, ((EFI_IFR_OP_HEADER *) OpCodeData)->Length);
471         FormSetBuffer = NULL;
472       } else {
473         TempBuffer = AllocatePool (TempSize + ((EFI_IFR_OP_HEADER *) OpCodeData)->Length);
474         if (TempBuffer == NULL) {
475           Status = EFI_OUT_OF_RESOURCES;
476           goto Done;
477         }
478         CopyMem (TempBuffer, OpCodeData, ((EFI_IFR_OP_HEADER *) OpCodeData)->Length);
479       }
480       TempSize += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;
481       FormSetBuffer = TempBuffer;
482 
483       Status = EFI_SUCCESS;
484       //
485       //One form package has one formset, exit current form package to search other form package in the packagelist.
486       //
487       break;
488     }
489   }
490 Done:
491   FreePool (HiiPackageList);
492 
493   *BufferSize = TempSize;
494   *Buffer = (EFI_IFR_FORM_SET *)FormSetBuffer;
495 
496   return Status;
497 }
498 
499 /**
500   Converts all hex dtring characters in range ['A'..'F'] to ['a'..'f'] for
501   hex digits that appear between a '=' and a '&' in a config string.
502 
503   If ConfigString is NULL, then ASSERT().
504 
505   @param[in] ConfigString  Pointer to a Null-terminated Unicode string.
506 
507   @return  Pointer to the Null-terminated Unicode result string.
508 
509 **/
510 EFI_STRING
511 EFIAPI
InternalHiiLowerConfigString(IN EFI_STRING ConfigString)512 InternalHiiLowerConfigString (
513   IN EFI_STRING  ConfigString
514   )
515 {
516   EFI_STRING  String;
517   BOOLEAN     Lower;
518 
519   ASSERT (ConfigString != NULL);
520 
521   //
522   // Convert all hex digits in range [A-F] in the configuration header to [a-f]
523   //
524   for (String = ConfigString, Lower = FALSE; *String != L'\0'; String++) {
525     if (*String == L'=') {
526       Lower = TRUE;
527     } else if (*String == L'&') {
528       Lower = FALSE;
529     } else if (Lower && *String >= L'A' && *String <= L'F') {
530       *String = (CHAR16) (*String - L'A' + L'a');
531     }
532   }
533 
534   return ConfigString;
535 }
536 
537 /**
538   Uses the BlockToConfig() service of the Config Routing Protocol to
539   convert <ConfigRequest> and a buffer to a <ConfigResp>
540 
541   If ConfigRequest is NULL, then ASSERT().
542   If Block is NULL, then ASSERT().
543 
544   @param[in] ConfigRequest  Pointer to a Null-terminated Unicode string.
545   @param[in] Block          Pointer to a block of data.
546   @param[in] BlockSize      The zie, in bytes, of Block.
547 
548   @retval NULL   The <ConfigResp> string could not be generated.
549   @retval Other  Pointer to the Null-terminated Unicode <ConfigResp> string.
550 
551 **/
552 EFI_STRING
553 EFIAPI
InternalHiiBlockToConfig(IN CONST EFI_STRING ConfigRequest,IN CONST UINT8 * Block,IN UINTN BlockSize)554 InternalHiiBlockToConfig (
555   IN CONST EFI_STRING  ConfigRequest,
556   IN CONST UINT8       *Block,
557   IN UINTN             BlockSize
558   )
559 {
560   EFI_STATUS  Status;
561   EFI_STRING  ConfigResp;
562   CHAR16      *Progress;
563 
564   ASSERT (ConfigRequest != NULL);
565   ASSERT (Block != NULL);
566 
567   //
568   // Convert <ConfigRequest> to <ConfigResp>
569   //
570   Status = gHiiConfigRouting->BlockToConfig (
571                                 gHiiConfigRouting,
572                                 ConfigRequest,
573                                 Block,
574                                 BlockSize,
575                                 &ConfigResp,
576                                 &Progress
577                                 );
578   if (EFI_ERROR (Status)) {
579     return NULL;
580   }
581   return ConfigResp;
582 }
583 
584 /**
585   Uses the BrowserCallback() service of the Form Browser Protocol to retrieve
586   or set uncommitted data.  If sata i being retrieved, then the buffer is
587   allocated using AllocatePool().  The caller is then responsible for freeing
588   the buffer using FreePool().
589 
590   @param[in]  VariableGuid    Pointer to an EFI_GUID structure.  This is an optional
591                               parameter that may be NULL.
592   @param[in]  VariableName    Pointer to a Null-terminated Unicode string.  This
593                               is an optional parameter that may be NULL.
594   @param[in]  SetResultsData  If not NULL, then this parameter specified the buffer
595                               of uncommited data to set.  If this parameter is NULL,
596                               then the caller is requesting to get the uncommited data
597                               from the Form Browser.
598 
599   @retval NULL   The uncommitted data could not be retrieved.
600   @retval Other  A pointer to a buffer containing the uncommitted data.
601 
602 **/
603 EFI_STRING
604 EFIAPI
InternalHiiBrowserCallback(IN CONST EFI_GUID * VariableGuid,OPTIONAL IN CONST CHAR16 * VariableName,OPTIONAL IN CONST EFI_STRING SetResultsData OPTIONAL)605 InternalHiiBrowserCallback (
606   IN CONST EFI_GUID    *VariableGuid,  OPTIONAL
607   IN CONST CHAR16      *VariableName,  OPTIONAL
608   IN CONST EFI_STRING  SetResultsData  OPTIONAL
609   )
610 {
611   EFI_STATUS  Status;
612   UINTN       ResultsDataSize;
613   EFI_STRING  ResultsData;
614   CHAR16      TempResultsData;
615 
616   //
617   // Locate protocols
618   //
619   if (mUefiFormBrowser2 == NULL) {
620     Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &mUefiFormBrowser2);
621     if (EFI_ERROR (Status) || mUefiFormBrowser2 == NULL) {
622       return NULL;
623     }
624   }
625 
626   ResultsDataSize = 0;
627 
628   if (SetResultsData != NULL) {
629     //
630     // Request to to set data in the uncommitted browser state information
631     //
632     ResultsData = SetResultsData;
633   } else {
634     //
635     // Retrieve the length of the buffer required ResultsData from the Browser Callback
636     //
637     Status = mUefiFormBrowser2->BrowserCallback (
638                               mUefiFormBrowser2,
639                               &ResultsDataSize,
640                               &TempResultsData,
641                               TRUE,
642                               VariableGuid,
643                               VariableName
644                               );
645 
646     if (!EFI_ERROR (Status)) {
647       //
648       // No Resluts Data, only allocate one char for '\0'
649       //
650       ResultsData = AllocateZeroPool (sizeof (CHAR16));
651       return ResultsData;
652     }
653 
654     if (Status != EFI_BUFFER_TOO_SMALL) {
655       return NULL;
656     }
657 
658     //
659     // Allocate the ResultsData buffer
660     //
661     ResultsData = AllocateZeroPool (ResultsDataSize);
662     if (ResultsData == NULL) {
663       return NULL;
664     }
665   }
666 
667   //
668   // Retrieve or set the ResultsData from the Browser Callback
669   //
670   Status = mUefiFormBrowser2->BrowserCallback (
671                             mUefiFormBrowser2,
672                             &ResultsDataSize,
673                             ResultsData,
674                             (BOOLEAN)(SetResultsData == NULL),
675                             VariableGuid,
676                             VariableName
677                             );
678   if (EFI_ERROR (Status)) {
679     return NULL;
680   }
681 
682   return ResultsData;
683 }
684 
685 /**
686   Allocates and returns a Null-terminated Unicode <ConfigHdr> string using routing
687   information that includes a GUID, an optional Unicode string name, and a device
688   path.  The string returned is allocated with AllocatePool().  The caller is
689   responsible for freeing the allocated string with FreePool().
690 
691   The format of a <ConfigHdr> is as follows:
692 
693     GUID=<HexCh>32&NAME=<Char>NameLength&PATH=<HexChar>DevicePathSize<Null>
694 
695   @param[in]  Guid          Pointer to an EFI_GUID that is the routing information
696                             GUID.  Each of the 16 bytes in Guid is converted to
697                             a 2 Unicode character hexadecimal string.  This is
698                             an optional parameter that may be NULL.
699   @param[in]  Name          Pointer to a Null-terminated Unicode string that is
700                             the routing information NAME.  This is an optional
701                             parameter that may be NULL.  Each 16-bit Unicode
702                             character in Name is converted to a 4 character Unicode
703                             hexadecimal string.
704   @param[in]  DriverHandle  The driver handle which supports a Device Path Protocol
705                             that is the routing information PATH.  Each byte of
706                             the Device Path associated with DriverHandle is converted
707                             to a 2 Unicode character hexadecimal string.
708 
709   @retval NULL   DriverHandle does not support the Device Path Protocol.
710   @retval Other  A pointer to the Null-terminate Unicode <ConfigHdr> string
711 
712 **/
713 EFI_STRING
714 EFIAPI
HiiConstructConfigHdr(IN CONST EFI_GUID * Guid,OPTIONAL IN CONST CHAR16 * Name,OPTIONAL IN EFI_HANDLE DriverHandle)715 HiiConstructConfigHdr (
716   IN CONST EFI_GUID  *Guid,  OPTIONAL
717   IN CONST CHAR16    *Name,  OPTIONAL
718   IN EFI_HANDLE      DriverHandle
719   )
720 {
721   UINTN                     NameLength;
722   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
723   UINTN                     DevicePathSize;
724   CHAR16                    *String;
725   CHAR16                    *ReturnString;
726   UINTN                     Index;
727   UINT8                     *Buffer;
728   UINTN                     MaxLen;
729 
730   //
731   // Compute the length of Name in Unicode characters.
732   // If Name is NULL, then the length is 0.
733   //
734   NameLength = 0;
735   if (Name != NULL) {
736     NameLength = StrLen (Name);
737   }
738 
739   DevicePath = NULL;
740   DevicePathSize = 0;
741   //
742   // Retrieve DevicePath Protocol associated with DriverHandle
743   //
744   if (DriverHandle != NULL) {
745     DevicePath = DevicePathFromHandle (DriverHandle);
746     if (DevicePath == NULL) {
747       return NULL;
748     }
749     //
750     // Compute the size of the device path in bytes
751     //
752     DevicePathSize = GetDevicePathSize (DevicePath);
753   }
754 
755   //
756   // GUID=<HexCh>32&NAME=<Char>NameLength&PATH=<HexChar>DevicePathSize <Null>
757   // | 5 | sizeof (EFI_GUID) * 2 | 6 | NameStrLen*4 | 6 | DevicePathSize * 2 | 1 |
758   //
759   MaxLen = 5 + sizeof (EFI_GUID) * 2 + 6 + NameLength * 4 + 6 + DevicePathSize * 2 + 1;
760   String = AllocateZeroPool (MaxLen * sizeof (CHAR16));
761   if (String == NULL) {
762     return NULL;
763   }
764 
765   //
766   // Start with L"GUID="
767   //
768   StrCpyS (String, MaxLen, L"GUID=");
769   ReturnString = String;
770   String += StrLen (String);
771 
772   if (Guid != NULL) {
773     //
774     // Append Guid converted to <HexCh>32
775     //
776     for (Index = 0, Buffer = (UINT8 *)Guid; Index < sizeof (EFI_GUID); Index++) {
777       UnicodeValueToStringS (
778         String,
779         MaxLen * sizeof (CHAR16) - ((UINTN)String - (UINTN)ReturnString),
780         PREFIX_ZERO | RADIX_HEX,
781         *(Buffer++),
782         2
783         );
784       String += StrnLenS (String, MaxLen - ((UINTN)String - (UINTN)ReturnString) / sizeof (CHAR16));
785     }
786   }
787 
788   //
789   // Append L"&NAME="
790   //
791   StrCatS (ReturnString, MaxLen, L"&NAME=");
792   String += StrLen (String);
793 
794   if (Name != NULL) {
795     //
796     // Append Name converted to <Char>NameLength
797     //
798     for (; *Name != L'\0'; Name++) {
799       UnicodeValueToStringS (
800         String,
801         sizeof (CHAR16) * MaxLen - ((UINTN)String - (UINTN)ReturnString),
802         PREFIX_ZERO | RADIX_HEX,
803         *Name,
804         4
805         );
806       String += StrnLenS (String, MaxLen - ((UINTN)String - (UINTN)ReturnString) / sizeof (CHAR16));
807     }
808   }
809 
810   //
811   // Append L"&PATH="
812   //
813   StrCatS (ReturnString, MaxLen, L"&PATH=");
814   String += StrLen (String);
815 
816   //
817   // Append the device path associated with DriverHandle converted to <HexChar>DevicePathSize
818   //
819   for (Index = 0, Buffer = (UINT8 *)DevicePath; Index < DevicePathSize; Index++) {
820     UnicodeValueToStringS (
821       String,
822       sizeof (CHAR16) * MaxLen - ((UINTN)String - (UINTN)ReturnString),
823       PREFIX_ZERO | RADIX_HEX,
824       *(Buffer++),
825       2
826       );
827     String += StrnLenS (String, MaxLen - ((UINTN)String - (UINTN)ReturnString) / sizeof (CHAR16));
828   }
829 
830   //
831   // Null terminate the Unicode string
832   //
833   *String = L'\0';
834 
835   //
836   // Convert all hex digits in range [A-F] in the configuration header to [a-f]
837   //
838   return InternalHiiLowerConfigString (ReturnString);
839 }
840 
841 /**
842   Convert the hex UNICODE encoding string of UEFI GUID, NAME or device path
843   to binary buffer from <ConfigHdr>.
844 
845   This is a internal function.
846 
847   @param  String                 UEFI configuration string.
848   @param  Flag                   Flag specifies what type buffer will be retrieved.
849   @param  Buffer                 Binary of Guid, Name or Device path.
850 
851   @retval EFI_INVALID_PARAMETER  Any incoming parameter is invalid.
852   @retval EFI_OUT_OF_RESOURCES   Lake of resources to store neccesary structures.
853   @retval EFI_SUCCESS            The buffer data is retrieved and translated to
854                                  binary format.
855 
856 **/
857 EFI_STATUS
InternalHiiGetBufferFromString(IN EFI_STRING String,IN UINT8 Flag,OUT UINT8 ** Buffer)858 InternalHiiGetBufferFromString (
859   IN  EFI_STRING                 String,
860   IN  UINT8                      Flag,
861   OUT UINT8                      **Buffer
862   )
863 {
864   UINTN      Length;
865   EFI_STRING ConfigHdr;
866   CHAR16     *StringPtr;
867   UINT8      *DataBuffer;
868   CHAR16     TemStr[5];
869   UINTN      Index;
870   UINT8      DigitUint8;
871 
872   if (String == NULL || Buffer == NULL) {
873     return EFI_INVALID_PARAMETER;
874   }
875 
876   DataBuffer = NULL;
877   StringPtr  = NULL;
878   ConfigHdr  = String;
879   //
880   // The content between 'GUID', 'NAME', 'PATH' of <ConfigHdr> and '&' of next element
881   // or '\0' (end of configuration string) is the UNICODE %02x bytes encoding string.
882   //
883   for (Length = 0; *String != 0 && *String != L'&'; String++, Length++);
884 
885   switch (Flag) {
886   case GUID_CONFIG_STRING_TYPE:
887   case PATH_CONFIG_STRING_TYPE:
888     //
889     // The data in <ConfigHdr> is encoded as hex UNICODE %02x bytes in the same order
890     // as the device path and Guid resides in RAM memory.
891     // Translate the data into binary.
892     //
893     DataBuffer = (UINT8 *) AllocateZeroPool ((Length + 1) / 2);
894     if (DataBuffer == NULL) {
895       return EFI_OUT_OF_RESOURCES;
896     }
897     //
898     // Convert binary byte one by one
899     //
900     ZeroMem (TemStr, sizeof (TemStr));
901     for (Index = 0; Index < Length; Index ++) {
902       TemStr[0] = ConfigHdr[Index];
903       DigitUint8 = (UINT8) StrHexToUint64 (TemStr);
904       if ((Index & 1) == 0) {
905         DataBuffer [Index/2] = DigitUint8;
906       } else {
907         DataBuffer [Index/2] = (UINT8) ((DataBuffer [Index/2] << 4) + DigitUint8);
908       }
909     }
910 
911     *Buffer = DataBuffer;
912     break;
913 
914   case NAME_CONFIG_STRING_TYPE:
915     //
916     // Convert Config String to Unicode String, e.g. "0041004200430044" => "ABCD"
917     //
918 
919     //
920     // Add the tailling char L'\0'
921     //
922     DataBuffer = (UINT8 *) AllocateZeroPool ((Length/4 + 1) * sizeof (CHAR16));
923     if (DataBuffer == NULL) {
924       return EFI_OUT_OF_RESOURCES;
925     }
926     //
927     // Convert character one by one
928     //
929     StringPtr = (CHAR16 *) DataBuffer;
930     ZeroMem (TemStr, sizeof (TemStr));
931     for (Index = 0; Index < Length; Index += 4) {
932       StrnCpyS (TemStr, sizeof (TemStr) / sizeof (CHAR16), ConfigHdr + Index, 4);
933       StringPtr[Index/4] = (CHAR16) StrHexToUint64 (TemStr);
934     }
935     //
936     // Add tailing L'\0' character
937     //
938     StringPtr[Index/4] = L'\0';
939 
940     *Buffer = DataBuffer;
941     break;
942 
943   default:
944     return EFI_INVALID_PARAMETER;
945   }
946 
947   return EFI_SUCCESS;
948 }
949 
950 /**
951   This function checks VarOffset and VarWidth is in the block range.
952 
953   @param  BlockArray         The block array is to be checked.
954   @param  VarOffset          Offset of var to the structure
955   @param  VarWidth           Width of var.
956 
957   @retval TRUE   This Var is in the block range.
958   @retval FALSE  This Var is not in the block range.
959 **/
960 BOOLEAN
BlockArrayCheck(IN IFR_BLOCK_DATA * BlockArray,IN UINT16 VarOffset,IN UINT16 VarWidth)961 BlockArrayCheck (
962   IN IFR_BLOCK_DATA  *BlockArray,
963   IN UINT16          VarOffset,
964   IN UINT16          VarWidth
965   )
966 {
967   LIST_ENTRY          *Link;
968   IFR_BLOCK_DATA      *BlockData;
969 
970   //
971   // No Request Block array, all vars are got.
972   //
973   if (BlockArray == NULL) {
974     return TRUE;
975   }
976 
977   //
978   // Check the input var is in the request block range.
979   //
980   for (Link = BlockArray->Entry.ForwardLink; Link != &BlockArray->Entry; Link = Link->ForwardLink) {
981     BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
982     if ((VarOffset >= BlockData->Offset) && ((VarOffset + VarWidth) <= (BlockData->Offset + BlockData->Width))) {
983       return TRUE;
984     }
985   }
986 
987   return FALSE;
988 }
989 
990 /**
991   Get the value of <Number> in <BlockConfig> format, i.e. the value of OFFSET
992   or WIDTH or VALUE.
993   <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE'=<Number>
994 
995   @param  ValueString            String in <BlockConfig> format and points to the
996                                  first character of <Number>.
997   @param  ValueData              The output value. Caller takes the responsibility
998                                  to free memory.
999   @param  ValueLength            Length of the <Number>, in characters.
1000 
1001   @retval EFI_OUT_OF_RESOURCES   Insufficient resources to store neccessary
1002                                  structures.
1003   @retval EFI_SUCCESS            Value of <Number> is outputted in Number
1004                                  successfully.
1005 
1006 **/
1007 EFI_STATUS
1008 EFIAPI
InternalHiiGetValueOfNumber(IN EFI_STRING ValueString,OUT UINT8 ** ValueData,OUT UINTN * ValueLength)1009 InternalHiiGetValueOfNumber (
1010   IN  EFI_STRING           ValueString,
1011   OUT UINT8                **ValueData,
1012   OUT UINTN                *ValueLength
1013   )
1014 {
1015   EFI_STRING               StringPtr;
1016   UINTN                    Length;
1017   UINT8                    *Buf;
1018   UINT8                    DigitUint8;
1019   UINTN                    Index;
1020   CHAR16                   TemStr[2];
1021 
1022   ASSERT (ValueString != NULL && ValueData != NULL && ValueLength != NULL);
1023   ASSERT (*ValueString != L'\0');
1024 
1025   //
1026   // Get the length of value string
1027   //
1028   StringPtr = ValueString;
1029   while (*StringPtr != L'\0' && *StringPtr != L'&') {
1030     StringPtr++;
1031   }
1032   Length = StringPtr - ValueString;
1033 
1034   //
1035   // Allocate buffer to store the value
1036   //
1037   Buf = (UINT8 *) AllocateZeroPool ((Length + 1) / 2);
1038   if (Buf == NULL) {
1039     return EFI_OUT_OF_RESOURCES;
1040   }
1041 
1042   //
1043   // Convert character one by one to the value buffer
1044   //
1045   ZeroMem (TemStr, sizeof (TemStr));
1046   for (Index = 0; Index < Length; Index ++) {
1047     TemStr[0] = ValueString[Length - Index - 1];
1048     DigitUint8 = (UINT8) StrHexToUint64 (TemStr);
1049     if ((Index & 1) == 0) {
1050       Buf [Index/2] = DigitUint8;
1051     } else {
1052       Buf [Index/2] = (UINT8) ((DigitUint8 << 4) + Buf [Index/2]);
1053     }
1054   }
1055 
1056   //
1057   // Set the converted value and string length.
1058   //
1059   *ValueData    = Buf;
1060   *ValueLength  = Length;
1061   return EFI_SUCCESS;
1062 }
1063 
1064 /**
1065   Get value from config request resp string.
1066 
1067   @param ConfigElement           ConfigResp string contains the current setting.
1068   @param VarName                 The variable name which need to get value.
1069   @param VarValue                The return value.
1070 
1071   @retval EFI_SUCCESS            Get the value for the VarName
1072   @retval EFI_OUT_OF_RESOURCES   The memory is not enough.
1073 **/
1074 EFI_STATUS
GetValueFromRequest(IN CHAR16 * ConfigElement,IN CHAR16 * VarName,OUT UINT64 * VarValue)1075 GetValueFromRequest (
1076   IN CHAR16                       *ConfigElement,
1077   IN CHAR16                       *VarName,
1078   OUT UINT64                      *VarValue
1079   )
1080 {
1081   UINT8                        *TmpBuffer;
1082   CHAR16                       *StringPtr;
1083   UINTN                        Length;
1084   EFI_STATUS                   Status;
1085 
1086   //
1087   // Find VarName related string.
1088   //
1089   StringPtr = StrStr (ConfigElement, VarName);
1090   ASSERT (StringPtr != NULL);
1091 
1092   //
1093   // Skip the "VarName=" string
1094   //
1095   StringPtr += StrLen (VarName) + 1;
1096 
1097   //
1098   // Get Offset
1099   //
1100   Status = InternalHiiGetValueOfNumber (StringPtr, &TmpBuffer, &Length);
1101   if (EFI_ERROR (Status)) {
1102     return Status;
1103   }
1104 
1105   *VarValue = 0;
1106   CopyMem (VarValue, TmpBuffer, (((Length + 1) / 2) < sizeof (UINT64)) ? ((Length + 1) / 2) : sizeof (UINT64));
1107 
1108   FreePool (TmpBuffer);
1109 
1110   return EFI_SUCCESS;
1111 }
1112 
1113 /**
1114   This internal function parses IFR data to validate current setting.
1115 
1116   Base on the NameValueType, if it is TRUE, RequestElement and HiiHandle is valid;
1117   else the VarBuffer and CurrentBlockArray is valid.
1118 
1119   @param HiiPackageList     Point to Hii package list.
1120   @param PackageListLength  The length of the pacakge.
1121   @param VarGuid            Guid of the buffer storage.
1122   @param VarName            Name of the buffer storage.
1123   @param VarBuffer          The data buffer for the storage.
1124   @param CurrentBlockArray  The block array from the config Requst string.
1125   @param RequestElement     The config string for this storage.
1126   @param HiiHandle          The HiiHandle for this formset.
1127   @param NameValueType      Whether current storage is name/value varstore or not.
1128 
1129   @retval EFI_SUCCESS            The current setting is valid.
1130   @retval EFI_OUT_OF_RESOURCES   The memory is not enough.
1131   @retval EFI_INVALID_PARAMETER  The config string or the Hii package is invalid.
1132 **/
1133 EFI_STATUS
ValidateQuestionFromVfr(IN EFI_HII_PACKAGE_LIST_HEADER * HiiPackageList,IN UINTN PackageListLength,IN EFI_GUID * VarGuid,IN CHAR16 * VarName,IN UINT8 * VarBuffer,IN IFR_BLOCK_DATA * CurrentBlockArray,IN CHAR16 * RequestElement,IN EFI_HII_HANDLE HiiHandle,IN BOOLEAN NameValueType)1134 ValidateQuestionFromVfr (
1135   IN EFI_HII_PACKAGE_LIST_HEADER   *HiiPackageList,
1136   IN UINTN                         PackageListLength,
1137   IN EFI_GUID                      *VarGuid,
1138   IN CHAR16                        *VarName,
1139   IN UINT8                         *VarBuffer,
1140   IN IFR_BLOCK_DATA                *CurrentBlockArray,
1141   IN CHAR16                        *RequestElement,
1142   IN EFI_HII_HANDLE                HiiHandle,
1143   IN BOOLEAN                       NameValueType
1144   )
1145 {
1146   IFR_BLOCK_DATA               VarBlockData;
1147   UINT16                       Offset;
1148   UINT16                       Width;
1149   UINT64                       VarValue;
1150   EFI_IFR_TYPE_VALUE           TmpValue;
1151   EFI_STATUS                   Status;
1152   EFI_HII_PACKAGE_HEADER       PackageHeader;
1153   UINT32                       PackageOffset;
1154   UINT8                        *PackageData;
1155   UINTN                        IfrOffset;
1156   EFI_IFR_OP_HEADER            *IfrOpHdr;
1157   EFI_IFR_VARSTORE             *IfrVarStore;
1158   EFI_IFR_VARSTORE_NAME_VALUE  *IfrNameValueStore;
1159   EFI_IFR_VARSTORE_EFI         *IfrEfiVarStore;
1160   IFR_VARSTORAGE_DATA          VarStoreData;
1161   EFI_IFR_ONE_OF               *IfrOneOf;
1162   EFI_IFR_NUMERIC              *IfrNumeric;
1163   EFI_IFR_ONE_OF_OPTION        *IfrOneOfOption;
1164   EFI_IFR_CHECKBOX             *IfrCheckBox;
1165   EFI_IFR_STRING               *IfrString;
1166   CHAR8                        *VarStoreName;
1167   UINTN                        Index;
1168   CHAR16                       *QuestionName;
1169   CHAR16                       *StringPtr;
1170   UINT16                       BitOffset;
1171   UINT16                       BitWidth;
1172   UINT16                       TotalBits;
1173   UINTN                        StartBit;
1174   UINTN                        EndBit;
1175   BOOLEAN                      QuestionReferBitField;
1176   UINT32                       BufferValue;
1177 
1178   //
1179   // Initialize the local variables.
1180   //
1181   Index             = 0;
1182   VarStoreName      = NULL;
1183   Status            = EFI_SUCCESS;
1184   VarValue          = 0;
1185   IfrVarStore       = NULL;
1186   IfrNameValueStore = NULL;
1187   IfrEfiVarStore    = NULL;
1188   ZeroMem (&VarStoreData, sizeof (IFR_VARSTORAGE_DATA));
1189   ZeroMem (&VarBlockData, sizeof (VarBlockData));
1190   BitOffset = 0;
1191   BitWidth = 0;
1192   QuestionReferBitField = FALSE;
1193 
1194   //
1195   // Check IFR value is in block data, then Validate Value
1196   //
1197   PackageOffset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
1198   while (PackageOffset < PackageListLength) {
1199     CopyMem (&PackageHeader, (UINT8 *) HiiPackageList + PackageOffset, sizeof (PackageHeader));
1200 
1201     //
1202     // Parse IFR opcode from the form package.
1203     //
1204     if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) {
1205       IfrOffset   = sizeof (PackageHeader);
1206       PackageData = (UINT8 *) HiiPackageList + PackageOffset;
1207       while (IfrOffset < PackageHeader.Length) {
1208         IfrOpHdr = (EFI_IFR_OP_HEADER *) (PackageData + IfrOffset);
1209         //
1210         // Validate current setting to the value built in IFR opcode
1211         //
1212         switch (IfrOpHdr->OpCode) {
1213         case EFI_IFR_VARSTORE_OP:
1214           //
1215           // VarStoreId has been found. No further found.
1216           //
1217           if (VarStoreData.VarStoreId != 0) {
1218             break;
1219           }
1220           //
1221           // Find the matched VarStoreId to the input VarGuid and VarName
1222           //
1223           IfrVarStore = (EFI_IFR_VARSTORE *) IfrOpHdr;
1224           if (CompareGuid ((EFI_GUID *) (VOID *) &IfrVarStore->Guid, VarGuid)) {
1225             VarStoreName = (CHAR8 *) IfrVarStore->Name;
1226             for (Index = 0; VarStoreName[Index] != 0; Index ++) {
1227               if ((CHAR16) VarStoreName[Index] != VarName[Index]) {
1228                 break;
1229               }
1230             }
1231             //
1232             // The matched VarStore is found.
1233             //
1234             if ((VarStoreName[Index] != 0) || (VarName[Index] != 0)) {
1235               IfrVarStore = NULL;
1236             }
1237           } else {
1238             IfrVarStore = NULL;
1239           }
1240 
1241           if (IfrVarStore != NULL) {
1242             VarStoreData.VarStoreId = IfrVarStore->VarStoreId;
1243             VarStoreData.Size       = IfrVarStore->Size;
1244           }
1245           break;
1246         case EFI_IFR_VARSTORE_NAME_VALUE_OP:
1247           //
1248           // VarStoreId has been found. No further found.
1249           //
1250           if (VarStoreData.VarStoreId != 0) {
1251             break;
1252           }
1253           //
1254           // Find the matched VarStoreId to the input VarGuid
1255           //
1256           IfrNameValueStore = (EFI_IFR_VARSTORE_NAME_VALUE *) IfrOpHdr;
1257           if (!CompareGuid ((EFI_GUID *) (VOID *) &IfrNameValueStore->Guid, VarGuid)) {
1258             IfrNameValueStore = NULL;
1259           }
1260 
1261           if (IfrNameValueStore != NULL) {
1262             VarStoreData.VarStoreId = IfrNameValueStore->VarStoreId;
1263           }
1264           break;
1265         case EFI_IFR_VARSTORE_EFI_OP:
1266           //
1267           // VarStore is found. Don't need to search any more.
1268           //
1269           if (VarStoreData.VarStoreId != 0) {
1270             break;
1271           }
1272 
1273           IfrEfiVarStore = (EFI_IFR_VARSTORE_EFI *) IfrOpHdr;
1274 
1275           //
1276           // If the length is small than the structure, this is from old efi
1277           // varstore definition. Old efi varstore get config directly from
1278           // GetVariable function.
1279           //
1280           if (IfrOpHdr->Length < sizeof (EFI_IFR_VARSTORE_EFI)) {
1281             break;
1282           }
1283 
1284           if (CompareGuid ((EFI_GUID *) (VOID *) &IfrEfiVarStore->Guid, VarGuid)) {
1285             VarStoreName = (CHAR8 *) IfrEfiVarStore->Name;
1286             for (Index = 0; VarStoreName[Index] != 0; Index ++) {
1287               if ((CHAR16) VarStoreName[Index] != VarName[Index]) {
1288                 break;
1289               }
1290             }
1291             //
1292             // The matched VarStore is found.
1293             //
1294             if ((VarStoreName[Index] != 0) || (VarName[Index] != 0)) {
1295               IfrEfiVarStore = NULL;
1296             }
1297           } else {
1298             IfrEfiVarStore = NULL;
1299           }
1300 
1301           if (IfrEfiVarStore != NULL) {
1302             //
1303             // Find the matched VarStore
1304             //
1305             VarStoreData.VarStoreId = IfrEfiVarStore->VarStoreId;
1306             VarStoreData.Size       = IfrEfiVarStore->Size;
1307           }
1308           break;
1309         case EFI_IFR_FORM_OP:
1310         case EFI_IFR_FORM_MAP_OP:
1311           //
1312           // Check the matched VarStoreId is found.
1313           //
1314           if (VarStoreData.VarStoreId == 0) {
1315             return EFI_SUCCESS;
1316           }
1317           break;
1318         case EFI_IFR_ONE_OF_OP:
1319           //
1320           // Check whether current value is the one of option.
1321           //
1322 
1323           //
1324           // OneOf question is not in IFR Form. This IFR form is not valid.
1325           //
1326           if (VarStoreData.VarStoreId == 0) {
1327             return EFI_INVALID_PARAMETER;
1328           }
1329           //
1330           // Check whether this question is for the requested varstore.
1331           //
1332           IfrOneOf = (EFI_IFR_ONE_OF *) IfrOpHdr;
1333           if (IfrOneOf->Question.VarStoreId != VarStoreData.VarStoreId) {
1334             break;
1335           }
1336 
1337           if (NameValueType) {
1338             QuestionName = HiiGetString (HiiHandle, IfrOneOf->Question.VarStoreInfo.VarName, NULL);
1339             ASSERT (QuestionName != NULL);
1340 
1341             if (StrStr (RequestElement, QuestionName) == NULL) {
1342               //
1343               // This question is not in the current configuration string. Skip it.
1344               //
1345               break;
1346             }
1347 
1348             Status = GetValueFromRequest (RequestElement, QuestionName, &VarValue);
1349             if (EFI_ERROR (Status)) {
1350               return Status;
1351             }
1352           } else {
1353             //
1354             // Get Offset by Question header and Width by DataType Flags
1355             //
1356             if (QuestionReferBitField) {
1357               //
1358               // Get the byte offset/width for bit field.
1359               //
1360               BitOffset = IfrOneOf->Question.VarStoreInfo.VarOffset;
1361               BitWidth = IfrOneOf->Flags & EDKII_IFR_NUMERIC_SIZE_BIT;
1362               Offset = BitOffset / 8;
1363               TotalBits = BitOffset % 8 + BitWidth;
1364               Width = (TotalBits % 8 == 0 ? TotalBits / 8: TotalBits / 8 + 1);
1365             } else {
1366               Offset = IfrOneOf->Question.VarStoreInfo.VarOffset;
1367               Width  = (UINT16) (1 << (IfrOneOf->Flags & EFI_IFR_NUMERIC_SIZE));
1368             }
1369             //
1370             // Check whether this question is in current block array.
1371             //
1372             if (!BlockArrayCheck (CurrentBlockArray, Offset, Width)) {
1373               //
1374               // This question is not in the current configuration string. Skip it.
1375               //
1376               break;
1377             }
1378             //
1379             // Check this var question is in the var storage
1380             //
1381             if ((Offset + Width) > VarStoreData.Size) {
1382               //
1383               // This question exceeds the var store size.
1384               //
1385               return EFI_INVALID_PARAMETER;
1386             }
1387 
1388             //
1389             // Get the current value for oneof opcode
1390             //
1391             VarValue = 0;
1392             if (QuestionReferBitField) {
1393               //
1394               // Get the value in bit fields.
1395               //
1396               StartBit = BitOffset % 8;
1397               EndBit = StartBit + BitWidth - 1;
1398               CopyMem ((UINT8 *) &BufferValue, VarBuffer + Offset, Width);
1399               VarValue = BitFieldRead32 (BufferValue, StartBit, EndBit);
1400             } else {
1401               CopyMem (&VarValue, VarBuffer +  Offset, Width);
1402             }
1403           }
1404           //
1405           // Set Block Data, to be checked in the following Oneof option opcode.
1406           //
1407           VarBlockData.OpCode     = IfrOpHdr->OpCode;
1408           VarBlockData.Scope      = IfrOpHdr->Scope;
1409           break;
1410         case EFI_IFR_NUMERIC_OP:
1411           //
1412           // Check the current value is in the numeric range.
1413           //
1414 
1415           //
1416           // Numeric question is not in IFR Form. This IFR form is not valid.
1417           //
1418           if (VarStoreData.VarStoreId == 0) {
1419             return EFI_INVALID_PARAMETER;
1420           }
1421           //
1422           // Check whether this question is for the requested varstore.
1423           //
1424           IfrNumeric = (EFI_IFR_NUMERIC *) IfrOpHdr;
1425           if (IfrNumeric->Question.VarStoreId != VarStoreData.VarStoreId) {
1426             break;
1427           }
1428 
1429           if (NameValueType) {
1430             QuestionName = HiiGetString (HiiHandle, IfrNumeric->Question.VarStoreInfo.VarName, NULL);
1431             ASSERT (QuestionName != NULL);
1432 
1433             if (StrStr (RequestElement, QuestionName) == NULL) {
1434               //
1435               // This question is not in the current configuration string. Skip it.
1436               //
1437               break;
1438             }
1439 
1440             Status = GetValueFromRequest (RequestElement, QuestionName, &VarValue);
1441             if (EFI_ERROR (Status)) {
1442               return Status;
1443             }
1444           } else {
1445             //
1446             // Get Offset by Question header and Width by DataType Flags
1447             //
1448             if (QuestionReferBitField) {
1449               //
1450               // Get the byte offset/width for bit field.
1451               //
1452               BitOffset = IfrNumeric->Question.VarStoreInfo.VarOffset;
1453               BitWidth = IfrNumeric->Flags & EDKII_IFR_NUMERIC_SIZE_BIT;
1454               Offset = BitOffset / 8;
1455               TotalBits = BitOffset % 8 + BitWidth;
1456               Width  = (TotalBits % 8 == 0 ? TotalBits / 8: TotalBits / 8 + 1);
1457             } else {
1458               Offset = IfrNumeric->Question.VarStoreInfo.VarOffset;
1459               Width  = (UINT16) (1 << (IfrNumeric->Flags & EFI_IFR_NUMERIC_SIZE));
1460             }
1461             //
1462             // Check whether this question is in current block array.
1463             //
1464             if (!BlockArrayCheck (CurrentBlockArray, Offset, Width)) {
1465               //
1466               // This question is not in the current configuration string. Skip it.
1467               //
1468               break;
1469             }
1470             //
1471             // Check this var question is in the var storage
1472             //
1473             if ((Offset + Width) > VarStoreData.Size) {
1474               //
1475               // This question exceeds the var store size.
1476               //
1477               return EFI_INVALID_PARAMETER;
1478             }
1479 
1480             //
1481             // Check the current value is in the numeric range.
1482             //
1483             VarValue = 0;
1484             if (QuestionReferBitField) {
1485               //
1486               // Get the value in the bit fields.
1487               //
1488               StartBit = BitOffset % 8;
1489               EndBit = StartBit + BitWidth - 1;
1490               CopyMem ((UINT8 *) &BufferValue, VarBuffer + Offset, Width);
1491               VarValue = BitFieldRead32 (BufferValue, StartBit, EndBit);
1492             } else {
1493               CopyMem (&VarValue, VarBuffer +  Offset, Width);
1494             }
1495           }
1496           if ( QuestionReferBitField) {
1497              //
1498              // Value in bit fields was stored as UINt32 type.
1499              //
1500              if ((IfrNumeric->Flags & EDKII_IFR_DISPLAY_BIT) == 0) {
1501                if ((INT32) VarValue < (INT32) IfrNumeric->data.u32.MinValue || (INT32) VarValue > (INT32) IfrNumeric->data.u32.MaxValue) {
1502                   //
1503                   // Not in the valid range.
1504                   //
1505                   return EFI_INVALID_PARAMETER;
1506                 }
1507              } else {
1508                if (VarValue < IfrNumeric->data.u32.MinValue || VarValue > IfrNumeric->data.u32.MaxValue) {
1509                   //
1510                   // Not in the valid range.
1511                   //
1512                   return EFI_INVALID_PARAMETER;
1513                 }
1514              }
1515           } else {
1516             if ((IfrNumeric->Flags & EFI_IFR_DISPLAY) == 0) {
1517               switch (IfrNumeric->Flags & EFI_IFR_NUMERIC_SIZE) {
1518               case EFI_IFR_NUMERIC_SIZE_1:
1519                 if ((INT8) VarValue < (INT8) IfrNumeric->data.u8.MinValue || (INT8) VarValue > (INT8) IfrNumeric->data.u8.MaxValue) {
1520                   //
1521                   // Not in the valid range.
1522                   //
1523                   return EFI_INVALID_PARAMETER;
1524                 }
1525                 break;
1526               case EFI_IFR_NUMERIC_SIZE_2:
1527                 if ((INT16) VarValue < (INT16) IfrNumeric->data.u16.MinValue || (INT16) VarValue > (INT16) IfrNumeric->data.u16.MaxValue) {
1528                   //
1529                   // Not in the valid range.
1530                   //
1531                   return EFI_INVALID_PARAMETER;
1532                 }
1533                 break;
1534               case EFI_IFR_NUMERIC_SIZE_4:
1535                 if ((INT32) VarValue < (INT32) IfrNumeric->data.u32.MinValue || (INT32) VarValue > (INT32) IfrNumeric->data.u32.MaxValue) {
1536                   //
1537                   // Not in the valid range.
1538                   //
1539                   return EFI_INVALID_PARAMETER;
1540                 }
1541                 break;
1542               case EFI_IFR_NUMERIC_SIZE_8:
1543                 if ((INT64) VarValue < (INT64) IfrNumeric->data.u64.MinValue || (INT64) VarValue > (INT64) IfrNumeric->data.u64.MaxValue) {
1544                   //
1545                   // Not in the valid range.
1546                   //
1547                   return EFI_INVALID_PARAMETER;
1548                 }
1549                 break;
1550               }
1551             } else {
1552               switch (IfrNumeric->Flags & EFI_IFR_NUMERIC_SIZE) {
1553               case EFI_IFR_NUMERIC_SIZE_1:
1554                 if ((UINT8) VarValue < IfrNumeric->data.u8.MinValue || (UINT8) VarValue > IfrNumeric->data.u8.MaxValue) {
1555                   //
1556                   // Not in the valid range.
1557                   //
1558                   return EFI_INVALID_PARAMETER;
1559                 }
1560                 break;
1561               case EFI_IFR_NUMERIC_SIZE_2:
1562                 if ((UINT16) VarValue < IfrNumeric->data.u16.MinValue || (UINT16) VarValue > IfrNumeric->data.u16.MaxValue) {
1563                   //
1564                   // Not in the valid range.
1565                   //
1566                   return EFI_INVALID_PARAMETER;
1567                 }
1568                 break;
1569               case EFI_IFR_NUMERIC_SIZE_4:
1570                 if ((UINT32) VarValue < IfrNumeric->data.u32.MinValue || (UINT32) VarValue > IfrNumeric->data.u32.MaxValue) {
1571                   //
1572                   // Not in the valid range.
1573                   //
1574                   return EFI_INVALID_PARAMETER;
1575                 }
1576                 break;
1577               case EFI_IFR_NUMERIC_SIZE_8:
1578                 if ((UINT64) VarValue < IfrNumeric->data.u64.MinValue || (UINT64) VarValue > IfrNumeric->data.u64.MaxValue) {
1579                   //
1580                   // Not in the valid range.
1581                   //
1582                   return EFI_INVALID_PARAMETER;
1583                 }
1584                 break;
1585               }
1586             }
1587           }
1588           break;
1589         case EFI_IFR_CHECKBOX_OP:
1590           //
1591           // Check value is BOOLEAN type, only 0 and 1 is valid.
1592           //
1593 
1594           //
1595           // CheckBox question is not in IFR Form. This IFR form is not valid.
1596           //
1597           if (VarStoreData.VarStoreId == 0) {
1598             return EFI_INVALID_PARAMETER;
1599           }
1600 
1601           //
1602           // Check whether this question is for the requested varstore.
1603           //
1604           IfrCheckBox = (EFI_IFR_CHECKBOX *) IfrOpHdr;
1605           if (IfrCheckBox->Question.VarStoreId != VarStoreData.VarStoreId) {
1606             break;
1607           }
1608 
1609           if (NameValueType) {
1610             QuestionName = HiiGetString (HiiHandle, IfrCheckBox->Question.VarStoreInfo.VarName, NULL);
1611             ASSERT (QuestionName != NULL);
1612 
1613             if (StrStr (RequestElement, QuestionName) == NULL) {
1614               //
1615               // This question is not in the current configuration string. Skip it.
1616               //
1617               break;
1618             }
1619 
1620             Status = GetValueFromRequest (RequestElement, QuestionName, &VarValue);
1621             if (EFI_ERROR (Status)) {
1622               return Status;
1623             }
1624           } else {
1625             //
1626             // Get Offset by Question header
1627             //
1628            if (QuestionReferBitField) {
1629               //
1630               // Get the byte offset/width for bit field.
1631               //
1632               BitOffset = IfrCheckBox->Question.VarStoreInfo.VarOffset;
1633               BitWidth = 1;
1634               Offset = BitOffset / 8;
1635               TotalBits = BitOffset % 8 + BitWidth;
1636               Width = (TotalBits % 8 == 0 ? TotalBits / 8: TotalBits / 8 + 1);
1637             } else {
1638               Offset = IfrCheckBox->Question.VarStoreInfo.VarOffset;
1639               Width  = (UINT16) sizeof (BOOLEAN);
1640             }
1641             //
1642             // Check whether this question is in current block array.
1643             //
1644             if (!BlockArrayCheck (CurrentBlockArray, Offset, Width)) {
1645               //
1646               // This question is not in the current configuration string. Skip it.
1647               //
1648               break;
1649             }
1650             //
1651             // Check this var question is in the var storage
1652             //
1653             if ((Offset + Width) > VarStoreData.Size) {
1654               //
1655               // This question exceeds the var store size.
1656               //
1657               return EFI_INVALID_PARAMETER;
1658             }
1659             //
1660             // Check the current value is in the numeric range.
1661             //
1662             VarValue = 0;
1663             if (QuestionReferBitField) {
1664               //
1665               // Get the value in bit fields.
1666               //
1667               StartBit = BitOffset % 8;
1668               EndBit = StartBit + BitWidth - 1;
1669               CopyMem ((UINT8 *) &BufferValue, VarBuffer + Offset, Width);
1670               VarValue = BitFieldRead32 (BufferValue, StartBit, EndBit);
1671             } else {
1672               CopyMem (&VarValue, VarBuffer +  Offset, Width);
1673             }
1674           }
1675           //
1676           // Boolean type, only 1 and 0 is valid.
1677           //
1678           if (VarValue > 1) {
1679             return EFI_INVALID_PARAMETER;
1680           }
1681           break;
1682         case EFI_IFR_STRING_OP:
1683           //
1684           // Check current string length is less than maxsize
1685           //
1686 
1687           //
1688           // CheckBox question is not in IFR Form. This IFR form is not valid.
1689           //
1690           if (VarStoreData.VarStoreId == 0) {
1691             return EFI_INVALID_PARAMETER;
1692           }
1693 
1694           //
1695           // Check whether this question is for the requested varstore.
1696           //
1697           IfrString = (EFI_IFR_STRING *) IfrOpHdr;
1698           if (IfrString->Question.VarStoreId != VarStoreData.VarStoreId) {
1699             break;
1700           }
1701           //
1702           // Get the Max size of the string.
1703           //
1704           Width  = (UINT16) (IfrString->MaxSize * sizeof (UINT16));
1705           if (NameValueType) {
1706             QuestionName = HiiGetString (HiiHandle, IfrString->Question.VarStoreInfo.VarName, NULL);
1707             ASSERT (QuestionName != NULL);
1708 
1709             StringPtr = StrStr (RequestElement, QuestionName);
1710             if (StringPtr == NULL) {
1711               //
1712               // This question is not in the current configuration string. Skip it.
1713               //
1714               break;
1715             }
1716             //
1717             // Skip the VarName.
1718             //
1719             StringPtr += StrLen (QuestionName);
1720 
1721             //
1722             // Skip the "=".
1723             //
1724             StringPtr += 1;
1725 
1726             //
1727             // Check current string length is less than maxsize
1728             // e.g Config String: "0041004200430044", Unicode String: "ABCD". Unicode String length = Config String length / 4.
1729             // Config string format in UEFI spec.
1730             // <NvConfig> ::= <Label>'='<String>
1731             // <String> ::= [<Char>]+
1732             // <Char> ::= <HexCh>4
1733             //
1734             if (StrLen (StringPtr) / 4 > IfrString->MaxSize) {
1735               return EFI_INVALID_PARAMETER;
1736             }
1737           } else {
1738             //
1739             // Get Offset/Width by Question header and OneOf Flags
1740             //
1741             Offset = IfrString->Question.VarStoreInfo.VarOffset;
1742             //
1743             // Check whether this question is in current block array.
1744             //
1745             if (!BlockArrayCheck (CurrentBlockArray, Offset, Width)) {
1746               //
1747               // This question is not in the current configuration string. Skip it.
1748               //
1749               break;
1750             }
1751             //
1752             // Check this var question is in the var storage
1753             //
1754             if ((Offset + Width) > VarStoreData.Size) {
1755               //
1756               // This question exceeds the var store size.
1757               //
1758               return EFI_INVALID_PARAMETER;
1759             }
1760 
1761             //
1762             // Check current string length is less than maxsize
1763             //
1764             if (StrLen ((CHAR16 *) (VarBuffer + Offset)) > IfrString->MaxSize) {
1765               return EFI_INVALID_PARAMETER;
1766             }
1767           }
1768           break;
1769         case EFI_IFR_ONE_OF_OPTION_OP:
1770           //
1771           // Opcode Scope is zero. This one of option is not to be checked.
1772           //
1773           if (VarBlockData.Scope == 0) {
1774             break;
1775           }
1776 
1777           //
1778           // Only check for OneOf and OrderList opcode
1779           //
1780           IfrOneOfOption = (EFI_IFR_ONE_OF_OPTION *) IfrOpHdr;
1781           if (VarBlockData.OpCode == EFI_IFR_ONE_OF_OP) {
1782             //
1783             // Check current value is the value of one of option.
1784             //
1785             ASSERT (IfrOneOfOption->Type <= EFI_IFR_TYPE_NUM_SIZE_64);
1786             ZeroMem (&TmpValue, sizeof (EFI_IFR_TYPE_VALUE));
1787             CopyMem (&TmpValue, &IfrOneOfOption->Value, IfrOneOfOption->Header.Length - OFFSET_OF (EFI_IFR_ONE_OF_OPTION, Value));
1788             if (VarValue == TmpValue.u64) {
1789               //
1790               // The value is one of option value.
1791               // Set OpCode to Zero, don't need check again.
1792               //
1793               VarBlockData.OpCode = 0;
1794             }
1795           }
1796           break;
1797         case EFI_IFR_END_OP:
1798           QuestionReferBitField = FALSE;
1799           //
1800           // Decrease opcode scope for the validated opcode
1801           //
1802           if (VarBlockData.Scope > 0) {
1803             VarBlockData.Scope --;
1804           }
1805 
1806           //
1807           // OneOf value doesn't belong to one of option value.
1808           //
1809           if ((VarBlockData.Scope == 0) && (VarBlockData.OpCode == EFI_IFR_ONE_OF_OP)) {
1810             return EFI_INVALID_PARAMETER;
1811           }
1812           break;
1813         case EFI_IFR_GUID_OP:
1814           if (CompareGuid ((EFI_GUID *)((UINT8*)IfrOpHdr + sizeof (EFI_IFR_OP_HEADER)), &gEdkiiIfrBitVarstoreGuid)) {
1815             QuestionReferBitField = TRUE;
1816           }
1817           break;
1818         default:
1819           //
1820           // Increase Scope for the validated opcode
1821           //
1822           if (VarBlockData.Scope > 0) {
1823             VarBlockData.Scope = (UINT8) (VarBlockData.Scope + IfrOpHdr->Scope);
1824           }
1825           break;
1826         }
1827         //
1828         // Go to the next opcode
1829         //
1830         IfrOffset += IfrOpHdr->Length;
1831       }
1832       //
1833       // Only one form is in a package list.
1834       //
1835       break;
1836     }
1837 
1838     //
1839     // Go to next package.
1840     //
1841     PackageOffset += PackageHeader.Length;
1842   }
1843 
1844   return EFI_SUCCESS;
1845 }
1846 
1847 /**
1848   This internal function parses IFR data to validate current setting.
1849 
1850   @param ConfigElement         ConfigResp element string contains the current setting.
1851   @param CurrentBlockArray     Current block array.
1852   @param VarBuffer             Data buffer for this varstore.
1853 
1854   @retval EFI_SUCCESS            The current setting is valid.
1855   @retval EFI_OUT_OF_RESOURCES   The memory is not enough.
1856   @retval EFI_INVALID_PARAMETER  The config string or the Hii package is invalid.
1857 **/
1858 EFI_STATUS
GetBlockDataInfo(IN CHAR16 * ConfigElement,OUT IFR_BLOCK_DATA ** CurrentBlockArray,OUT UINT8 ** VarBuffer)1859 GetBlockDataInfo (
1860   IN  CHAR16                        *ConfigElement,
1861   OUT IFR_BLOCK_DATA                **CurrentBlockArray,
1862   OUT UINT8                         **VarBuffer
1863   )
1864 {
1865   IFR_BLOCK_DATA               *BlockData;
1866   IFR_BLOCK_DATA               *NewBlockData;
1867   EFI_STRING                   StringPtr;
1868   UINTN                        Length;
1869   UINT8                        *TmpBuffer;
1870   UINT16                       Offset;
1871   UINT16                       Width;
1872   LIST_ENTRY                   *Link;
1873   UINTN                        MaxBufferSize;
1874   EFI_STATUS                   Status;
1875   IFR_BLOCK_DATA               *BlockArray;
1876   UINT8                        *DataBuffer;
1877 
1878   //
1879   // Initialize the local variables.
1880   //
1881   Status        = EFI_SUCCESS;
1882   BlockData     = NULL;
1883   NewBlockData  = NULL;
1884   TmpBuffer     = NULL;
1885   BlockArray    = NULL;
1886   MaxBufferSize = HII_LIB_DEFAULT_VARSTORE_SIZE;
1887   DataBuffer     = AllocateZeroPool (MaxBufferSize);
1888   if (DataBuffer == NULL) {
1889     return EFI_OUT_OF_RESOURCES;
1890   }
1891 
1892   //
1893   // Init BlockArray
1894   //
1895   BlockArray = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
1896   if (BlockArray == NULL) {
1897     Status = EFI_OUT_OF_RESOURCES;
1898     goto Done;
1899   }
1900   InitializeListHead (&BlockArray->Entry);
1901 
1902   StringPtr = StrStr (ConfigElement, L"&OFFSET=");
1903   ASSERT (StringPtr != NULL);
1904 
1905   //
1906   // Parse each <RequestElement> if exists
1907   // Only <BlockName> format is supported by this help function.
1908   // <BlockName> ::= &'OFFSET='<Number>&'WIDTH='<Number>
1909   //
1910   while (*StringPtr != 0 && StrnCmp (StringPtr, L"&OFFSET=", StrLen (L"&OFFSET=")) == 0) {
1911     //
1912     // Skip the &OFFSET= string
1913     //
1914     StringPtr += StrLen (L"&OFFSET=");
1915 
1916     //
1917     // Get Offset
1918     //
1919     Status = InternalHiiGetValueOfNumber (StringPtr, &TmpBuffer, &Length);
1920     if (EFI_ERROR (Status)) {
1921       goto Done;
1922     }
1923     Offset = 0;
1924     CopyMem (
1925       &Offset,
1926       TmpBuffer,
1927       (((Length + 1) / 2) < sizeof (UINT16)) ? ((Length + 1) / 2) : sizeof (UINT16)
1928       );
1929     FreePool (TmpBuffer);
1930     TmpBuffer = NULL;
1931 
1932     StringPtr += Length;
1933     if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {
1934       Status = EFI_INVALID_PARAMETER;
1935       goto Done;
1936     }
1937     StringPtr += StrLen (L"&WIDTH=");
1938 
1939     //
1940     // Get Width
1941     //
1942     Status = InternalHiiGetValueOfNumber (StringPtr, &TmpBuffer, &Length);
1943     if (EFI_ERROR (Status)) {
1944       goto Done;
1945     }
1946     Width = 0;
1947     CopyMem (
1948       &Width,
1949       TmpBuffer,
1950       (((Length + 1) / 2) < sizeof (UINT16)) ? ((Length + 1) / 2) : sizeof (UINT16)
1951       );
1952     FreePool (TmpBuffer);
1953     TmpBuffer = NULL;
1954 
1955     StringPtr += Length;
1956     if (*StringPtr != 0 && *StringPtr != L'&') {
1957       Status = EFI_INVALID_PARAMETER;
1958       goto Done;
1959     }
1960 
1961     if (StrnCmp (StringPtr, L"&VALUE=", StrLen (L"&VALUE=")) != 0) {
1962       Status = EFI_INVALID_PARAMETER;
1963       goto Done;
1964     }
1965     StringPtr += StrLen (L"&VALUE=");
1966 
1967     //
1968     // Get Value
1969     //
1970     Status = InternalHiiGetValueOfNumber (StringPtr, &TmpBuffer, &Length);
1971     if (EFI_ERROR (Status)) {
1972       goto Done;
1973     }
1974 
1975     StringPtr += Length;
1976     if (*StringPtr != 0 && *StringPtr != L'&') {
1977       Status = EFI_INVALID_PARAMETER;
1978       goto Done;
1979     }
1980 
1981     //
1982     // Check whether VarBuffer is enough
1983     //
1984     if ((UINT32)Offset + Width > MaxBufferSize) {
1985       DataBuffer = ReallocatePool (
1986                     MaxBufferSize,
1987                     Offset + Width + HII_LIB_DEFAULT_VARSTORE_SIZE,
1988                     DataBuffer
1989                     );
1990       if (DataBuffer == NULL) {
1991         Status = EFI_OUT_OF_RESOURCES;
1992         goto Done;
1993       }
1994       MaxBufferSize = Offset + Width + HII_LIB_DEFAULT_VARSTORE_SIZE;
1995     }
1996 
1997     //
1998     // Update the Block with configuration info
1999     //
2000     CopyMem (DataBuffer + Offset, TmpBuffer, Width);
2001     FreePool (TmpBuffer);
2002     TmpBuffer = NULL;
2003 
2004     //
2005     // Set new Block Data
2006     //
2007     NewBlockData = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
2008     if (NewBlockData == NULL) {
2009       Status = EFI_OUT_OF_RESOURCES;
2010       goto Done;
2011     }
2012     NewBlockData->Offset = Offset;
2013     NewBlockData->Width  = Width;
2014 
2015     //
2016     // Insert the new block data into the block data array.
2017     //
2018     for (Link = BlockArray->Entry.ForwardLink; Link != &BlockArray->Entry; Link = Link->ForwardLink) {
2019       BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
2020       if (NewBlockData->Offset == BlockData->Offset) {
2021         if (NewBlockData->Width > BlockData->Width) {
2022           BlockData->Width = NewBlockData->Width;
2023         }
2024         FreePool (NewBlockData);
2025         break;
2026       } else if (NewBlockData->Offset < BlockData->Offset) {
2027         //
2028         // Insert new block data as the previous one of this link.
2029         //
2030         InsertTailList (Link, &NewBlockData->Entry);
2031         break;
2032       }
2033     }
2034 
2035     //
2036     // Insert new block data into the array tail.
2037     //
2038     if (Link == &BlockArray->Entry) {
2039       InsertTailList (Link, &NewBlockData->Entry);
2040     }
2041 
2042     //
2043     // If '\0', parsing is finished.
2044     //
2045     if (*StringPtr == 0) {
2046       break;
2047     }
2048     //
2049     // Go to next ConfigBlock
2050     //
2051   }
2052 
2053   //
2054   // Merge the aligned block data into the single block data.
2055   //
2056   Link = BlockArray->Entry.ForwardLink;
2057   while ((Link != &BlockArray->Entry) && (Link->ForwardLink != &BlockArray->Entry)) {
2058     BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
2059     NewBlockData = BASE_CR (Link->ForwardLink, IFR_BLOCK_DATA, Entry);
2060     if ((NewBlockData->Offset >= BlockData->Offset) && (NewBlockData->Offset <= (BlockData->Offset + BlockData->Width))) {
2061       if ((NewBlockData->Offset + NewBlockData->Width) > (BlockData->Offset + BlockData->Width)) {
2062         BlockData->Width = (UINT16) (NewBlockData->Offset + NewBlockData->Width - BlockData->Offset);
2063       }
2064       RemoveEntryList (Link->ForwardLink);
2065       FreePool (NewBlockData);
2066       continue;
2067     }
2068     Link = Link->ForwardLink;
2069   }
2070 
2071   *VarBuffer         = DataBuffer;
2072   *CurrentBlockArray = BlockArray;
2073   return EFI_SUCCESS;
2074 
2075 Done:
2076   if (DataBuffer != NULL) {
2077     FreePool (DataBuffer);
2078   }
2079 
2080   if (BlockArray != NULL) {
2081     //
2082     // Free Link Array CurrentBlockArray
2083     //
2084     while (!IsListEmpty (&BlockArray->Entry)) {
2085       BlockData = BASE_CR (BlockArray->Entry.ForwardLink, IFR_BLOCK_DATA, Entry);
2086       RemoveEntryList (&BlockData->Entry);
2087       FreePool (BlockData);
2088     }
2089     FreePool (BlockArray);
2090   }
2091 
2092   return Status;
2093 }
2094 
2095 /**
2096   This internal function parses IFR data to validate current setting.
2097 
2098   @param ConfigResp         ConfigResp string contains the current setting.
2099   @param HiiPackageList     Point to Hii package list.
2100   @param PackageListLength  The length of the pacakge.
2101   @param VarGuid            Guid of the buffer storage.
2102   @param VarName            Name of the buffer storage.
2103   @param HiiHandle          The HiiHandle for this package.
2104 
2105   @retval EFI_SUCCESS            The current setting is valid.
2106   @retval EFI_OUT_OF_RESOURCES   The memory is not enough.
2107   @retval EFI_INVALID_PARAMETER  The config string or the Hii package is invalid.
2108 **/
2109 EFI_STATUS
2110 EFIAPI
InternalHiiValidateCurrentSetting(IN EFI_STRING ConfigResp,IN EFI_HII_PACKAGE_LIST_HEADER * HiiPackageList,IN UINTN PackageListLength,IN EFI_GUID * VarGuid,IN CHAR16 * VarName,IN EFI_HII_HANDLE HiiHandle)2111 InternalHiiValidateCurrentSetting (
2112   IN EFI_STRING                    ConfigResp,
2113   IN EFI_HII_PACKAGE_LIST_HEADER   *HiiPackageList,
2114   IN UINTN                         PackageListLength,
2115   IN EFI_GUID                      *VarGuid,
2116   IN CHAR16                        *VarName,
2117   IN EFI_HII_HANDLE                HiiHandle
2118   )
2119 {
2120   CHAR16              *StringPtr;
2121   EFI_STATUS          Status;
2122   IFR_BLOCK_DATA      *CurrentBlockArray;
2123   IFR_BLOCK_DATA      *BlockData;
2124   UINT8               *VarBuffer;
2125   BOOLEAN             NameValueType;
2126 
2127   CurrentBlockArray = NULL;
2128   VarBuffer         = NULL;
2129   StringPtr         = NULL;
2130   Status            = EFI_SUCCESS;
2131 
2132   //
2133   // If StringPtr != NULL, get the request elements.
2134   //
2135   if (StrStr (ConfigResp, L"&OFFSET=") != NULL) {
2136     Status = GetBlockDataInfo(ConfigResp, &CurrentBlockArray, &VarBuffer);
2137     if (EFI_ERROR (Status)) {
2138       return Status;
2139     }
2140     NameValueType = FALSE;
2141   } else {
2142     //
2143     // Skip header part.
2144     //
2145     StringPtr = StrStr (ConfigResp, L"PATH=");
2146     ASSERT (StringPtr != NULL);
2147 
2148     if (StrStr (StringPtr, L"&") != NULL) {
2149       NameValueType = TRUE;
2150     } else {
2151       //
2152       // Not found Request element, return success.
2153       //
2154       return EFI_SUCCESS;
2155     }
2156   }
2157 
2158   Status = ValidateQuestionFromVfr(
2159                           HiiPackageList,
2160                           PackageListLength,
2161                           VarGuid,
2162                           VarName,
2163                           VarBuffer,
2164                           CurrentBlockArray,
2165                           ConfigResp,
2166                           HiiHandle,
2167                           NameValueType
2168                           );
2169 
2170   if (VarBuffer != NULL) {
2171     FreePool (VarBuffer);
2172   }
2173 
2174   if (CurrentBlockArray != NULL) {
2175     //
2176     // Free Link Array CurrentBlockArray
2177     //
2178     while (!IsListEmpty (&CurrentBlockArray->Entry)) {
2179       BlockData = BASE_CR (CurrentBlockArray->Entry.ForwardLink, IFR_BLOCK_DATA, Entry);
2180       RemoveEntryList (&BlockData->Entry);
2181       FreePool (BlockData);
2182     }
2183     FreePool (CurrentBlockArray);
2184   }
2185 
2186   return Status;
2187 }
2188 
2189 /**
2190   Check whether the ConfigRequest string has the request elements.
2191   For EFI_HII_VARSTORE_BUFFER type, the request has "&OFFSET=****&WIDTH=****..." format.
2192   For EFI_HII_VARSTORE_NAME_VALUE type, the request has "&NAME1**&NAME2..." format.
2193 
2194   @param  ConfigRequest      The input config request string.
2195 
2196   @retval  TRUE              The input include config request elements.
2197   @retval  FALSE             The input string not includes.
2198 
2199 **/
2200 BOOLEAN
GetElementsFromRequest(IN EFI_STRING ConfigRequest)2201 GetElementsFromRequest (
2202   IN EFI_STRING    ConfigRequest
2203   )
2204 {
2205   EFI_STRING   TmpRequest;
2206 
2207   TmpRequest = StrStr (ConfigRequest, L"PATH=");
2208   ASSERT (TmpRequest != NULL);
2209 
2210   if ((StrStr (TmpRequest, L"&OFFSET=") != NULL) || (StrStr (TmpRequest, L"&") != NULL)) {
2211     return TRUE;
2212   }
2213 
2214   return FALSE;
2215 }
2216 
2217 /**
2218   This function parses the input ConfigRequest string and its matched IFR code
2219   string for setting default value and validating current setting.
2220 
2221   1. For setting default action, Reset the default value specified by DefaultId
2222   to the driver configuration got by Request string.
2223   2. For validating current setting, Validate the current configuration
2224   by parsing HII form IFR opcode.
2225 
2226   NULL request string support depends on the ExportConfig interface of
2227   HiiConfigRouting protocol in UEFI specification.
2228 
2229   @param Request    A null-terminated Unicode string in
2230                     <MultiConfigRequest> format. It can be NULL.
2231                     If it is NULL, all current configuration for the
2232                     entirety of the current HII database will be validated.
2233                     If it is NULL, all configuration for the
2234                     entirety of the current HII database will be reset.
2235   @param DefaultId  Specifies the type of defaults to retrieve only for setting default action.
2236   @param ActionType Action supports setting defaults and validate current setting.
2237 
2238   @retval TRUE    Action runs successfully.
2239   @retval FALSE   Action is not valid or Action can't be executed successfully..
2240 **/
2241 BOOLEAN
2242 EFIAPI
InternalHiiIfrValueAction(IN CONST EFI_STRING Request,OPTIONAL IN UINT16 DefaultId,IN UINT8 ActionType)2243 InternalHiiIfrValueAction (
2244   IN CONST EFI_STRING Request,  OPTIONAL
2245   IN UINT16           DefaultId,
2246   IN UINT8            ActionType
2247   )
2248 {
2249   EFI_STRING     ConfigAltResp;
2250   EFI_STRING     ConfigAltHdr;
2251   EFI_STRING     ConfigResp;
2252   EFI_STRING     Progress;
2253   EFI_STRING     StringPtr;
2254   EFI_STRING     StringHdr;
2255   EFI_STATUS     Status;
2256   EFI_HANDLE     DriverHandle;
2257   EFI_HANDLE     TempDriverHandle;
2258   EFI_HII_HANDLE *HiiHandleBuffer;
2259   EFI_HII_HANDLE HiiHandle;
2260   UINT32         Index;
2261   EFI_GUID       *VarGuid;
2262   EFI_STRING     VarName;
2263 
2264   EFI_HII_PACKAGE_LIST_HEADER  *HiiPackageList;
2265   UINTN                        PackageListLength;
2266   UINTN                        MaxLen;
2267   EFI_DEVICE_PATH_PROTOCOL     *DevicePath;
2268   EFI_DEVICE_PATH_PROTOCOL     *TempDevicePath;
2269 
2270   ConfigAltResp = NULL;
2271   ConfigResp    = NULL;
2272   VarGuid       = NULL;
2273   VarName       = NULL;
2274   DevicePath    = NULL;
2275   ConfigAltHdr  = NULL;
2276   HiiHandleBuffer  = NULL;
2277   Index            = 0;
2278   TempDriverHandle = NULL;
2279   HiiHandle        = NULL;
2280   HiiPackageList   = NULL;
2281 
2282   //
2283   // Only support set default and validate setting action.
2284   //
2285   if ((ActionType != ACTION_SET_DEFAUTL_VALUE) && (ActionType != ACTION_VALIDATE_SETTING)) {
2286     return FALSE;
2287   }
2288 
2289   //
2290   // Get the full requested value and deault value string.
2291   //
2292   if (Request != NULL) {
2293     Status = gHiiConfigRouting->ExtractConfig (
2294                                   gHiiConfigRouting,
2295                                   Request,
2296                                   &Progress,
2297                                   &ConfigAltResp
2298                                 );
2299   } else {
2300     Status = gHiiConfigRouting->ExportConfig (
2301                                   gHiiConfigRouting,
2302                                   &ConfigAltResp
2303                                 );
2304   }
2305 
2306   if (EFI_ERROR (Status)) {
2307     return FALSE;
2308   }
2309 
2310   StringPtr = ConfigAltResp;
2311   ASSERT (StringPtr != NULL);
2312 
2313   while (*StringPtr != L'\0') {
2314     //
2315     // 1. Find <ConfigHdr> GUID=...&NAME=...&PATH=...
2316     //
2317     StringHdr = StringPtr;
2318 
2319     //
2320     // Get Guid value
2321     //
2322     if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
2323       Status = EFI_INVALID_PARAMETER;
2324       goto Done;
2325     }
2326     StringPtr += StrLen (L"GUID=");
2327     Status = InternalHiiGetBufferFromString (StringPtr, GUID_CONFIG_STRING_TYPE, (UINT8 **) &VarGuid);
2328     if (EFI_ERROR (Status)) {
2329       goto Done;
2330     }
2331 
2332     //
2333     // Get Name value VarName
2334     //
2335     while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&NAME=", StrLen (L"&NAME=")) != 0) {
2336       StringPtr++;
2337     }
2338     if (*StringPtr == L'\0') {
2339       Status = EFI_INVALID_PARAMETER;
2340       goto Done;
2341     }
2342     StringPtr += StrLen (L"&NAME=");
2343     Status = InternalHiiGetBufferFromString (StringPtr, NAME_CONFIG_STRING_TYPE, (UINT8 **) &VarName);
2344     if (EFI_ERROR (Status)) {
2345       goto Done;
2346     }
2347 
2348     //
2349     // Get Path value DevicePath
2350     //
2351     while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&PATH=", StrLen (L"&PATH=")) != 0) {
2352       StringPtr++;
2353     }
2354     if (*StringPtr == L'\0') {
2355       Status = EFI_INVALID_PARAMETER;
2356       goto Done;
2357     }
2358     StringPtr += StrLen (L"&PATH=");
2359     Status = InternalHiiGetBufferFromString (StringPtr, PATH_CONFIG_STRING_TYPE, (UINT8 **) &DevicePath);
2360     if (EFI_ERROR (Status)) {
2361       goto Done;
2362     }
2363 
2364     //
2365     // Get the Driver handle by the got device path.
2366     //
2367     TempDevicePath = DevicePath;
2368     Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &TempDevicePath, &DriverHandle);
2369     if (EFI_ERROR (Status)) {
2370       goto Done;
2371     }
2372 
2373     //
2374     // Find the matched Hii Handle for the found Driver handle
2375     //
2376     HiiHandleBuffer = HiiGetHiiHandles (NULL);
2377     if (HiiHandleBuffer == NULL) {
2378       Status = EFI_NOT_FOUND;
2379       goto Done;
2380     }
2381 
2382     for (Index = 0; HiiHandleBuffer[Index] != NULL; Index ++) {
2383       gHiiDatabase->GetPackageListHandle (gHiiDatabase, HiiHandleBuffer[Index], &TempDriverHandle);
2384       if (TempDriverHandle == DriverHandle) {
2385         break;
2386       }
2387     }
2388 
2389     HiiHandle = HiiHandleBuffer[Index];
2390     FreePool (HiiHandleBuffer);
2391 
2392     if (HiiHandle == NULL) {
2393       //
2394       // This request string has no its Hii package.
2395       // Its default value and validating can't execute by parsing IFR data.
2396       // Directly jump into the next ConfigAltResp string for another pair Guid, Name, and Path.
2397       //
2398       Status = EFI_SUCCESS;
2399       goto NextConfigAltResp;
2400     }
2401 
2402     //
2403     // 2. Get HiiPackage by HiiHandle
2404     //
2405     PackageListLength  = 0;
2406     HiiPackageList     = NULL;
2407     Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, HiiHandle, &PackageListLength, HiiPackageList);
2408 
2409     //
2410     // The return status should always be EFI_BUFFER_TOO_SMALL as input buffer's size is 0.
2411     //
2412     if (Status != EFI_BUFFER_TOO_SMALL) {
2413       Status = EFI_INVALID_PARAMETER;
2414       goto Done;
2415     }
2416 
2417     HiiPackageList = AllocatePool (PackageListLength);
2418     if (HiiPackageList == NULL) {
2419       Status = EFI_OUT_OF_RESOURCES;
2420       goto Done;
2421     }
2422 
2423     //
2424     // Get PackageList on HiiHandle
2425     //
2426     Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, HiiHandle, &PackageListLength, HiiPackageList);
2427     if (EFI_ERROR (Status)) {
2428       goto Done;
2429     }
2430 
2431     //
2432     // 3. Call ConfigRouting GetAltCfg(ConfigRoute, <ConfigResponse>, Guid, Name, DevicePath, AltCfgId, AltCfgResp)
2433     //    Get the default configuration string according to the default ID.
2434     //
2435     Status = gHiiConfigRouting->GetAltConfig (
2436                                   gHiiConfigRouting,
2437                                   ConfigAltResp,
2438                                   VarGuid,
2439                                   VarName,
2440                                   DevicePath,
2441                                   (ActionType == ACTION_SET_DEFAUTL_VALUE) ? &DefaultId:NULL,  // it can be NULL to get the current setting.
2442                                   &ConfigResp
2443                                 );
2444 
2445     //
2446     // The required setting can't be found. So, it is not required to be validated and set.
2447     //
2448     if (EFI_ERROR (Status)) {
2449       Status = EFI_SUCCESS;
2450       goto NextConfigAltResp;
2451     }
2452     //
2453     // Only the ConfigHdr is found. Not any block data is found. No data is required to be validated and set.
2454     //
2455     if (!GetElementsFromRequest (ConfigResp)) {
2456       goto NextConfigAltResp;
2457     }
2458 
2459     //
2460     // 4. Set the default configuration information or Validate current setting by parse IFR code.
2461     //    Current Setting is in ConfigResp, will be set into buffer, then check it again.
2462     //
2463     if (ActionType == ACTION_SET_DEFAUTL_VALUE) {
2464       //
2465       // Set the default configuration information.
2466       //
2467       Status = gHiiConfigRouting->RouteConfig (gHiiConfigRouting, ConfigResp, &Progress);
2468     } else {
2469       //
2470       // Current Setting is in ConfigResp, will be set into buffer, then check it again.
2471       //
2472       Status = InternalHiiValidateCurrentSetting (ConfigResp, HiiPackageList, PackageListLength, VarGuid, VarName, HiiHandle);
2473     }
2474 
2475     if (EFI_ERROR (Status)) {
2476       goto Done;
2477     }
2478 
2479 NextConfigAltResp:
2480     //
2481     // Free the allocated pacakge buffer and the got ConfigResp string.
2482     //
2483     if (HiiPackageList != NULL) {
2484       FreePool (HiiPackageList);
2485       HiiPackageList = NULL;
2486     }
2487 
2488     if (ConfigResp != NULL) {
2489       FreePool (ConfigResp);
2490       ConfigResp = NULL;
2491     }
2492 
2493     //
2494     // Free the allocated buffer.
2495     //
2496     FreePool (VarGuid);
2497     VarGuid = NULL;
2498 
2499     FreePool (VarName);
2500     VarName = NULL;
2501 
2502     FreePool (DevicePath);
2503     DevicePath = NULL;
2504 
2505     //
2506     // 5. Jump to next ConfigAltResp for another Guid, Name, Path.
2507     //
2508 
2509     //
2510     // Get and Skip ConfigHdr
2511     //
2512     while (*StringPtr != L'\0' && *StringPtr != L'&') {
2513       StringPtr++;
2514     }
2515     if (*StringPtr == L'\0') {
2516       break;
2517     }
2518 
2519     //
2520     // Construct ConfigAltHdr string  "&<ConfigHdr>&ALTCFG=\0"
2521     //                               | 1 | StrLen (ConfigHdr) | 8 | 1 |
2522     //
2523     MaxLen = 1 + StringPtr - StringHdr + 8 + 1;
2524     ConfigAltHdr = AllocateZeroPool ( MaxLen * sizeof (CHAR16));
2525     if (ConfigAltHdr == NULL) {
2526       Status = EFI_OUT_OF_RESOURCES;
2527       goto Done;
2528     }
2529     StrCpyS (ConfigAltHdr, MaxLen, L"&");
2530     StrnCatS (ConfigAltHdr, MaxLen, StringHdr, StringPtr - StringHdr);
2531     StrCatS (ConfigAltHdr, MaxLen, L"&ALTCFG=");
2532 
2533     //
2534     // Skip all AltResp (AltConfigHdr ConfigBody) for the same ConfigHdr
2535     //
2536     while ((StringHdr = StrStr (StringPtr, ConfigAltHdr)) != NULL) {
2537       StringPtr = StringHdr + StrLen (ConfigAltHdr);
2538       if (*StringPtr == L'\0') {
2539         break;
2540       }
2541     }
2542 
2543     //
2544     // Free the allocated ConfigAltHdr string
2545     //
2546     FreePool (ConfigAltHdr);
2547     if (*StringPtr == L'\0') {
2548       break;
2549     }
2550 
2551     //
2552     // Find &GUID as the next ConfigHdr
2553     //
2554     StringPtr = StrStr (StringPtr, L"&GUID");
2555     if (StringPtr == NULL) {
2556       break;
2557     }
2558 
2559     //
2560     // Skip char '&'
2561     //
2562     StringPtr ++;
2563   }
2564 
2565 Done:
2566   if (VarGuid != NULL) {
2567     FreePool (VarGuid);
2568   }
2569 
2570   if (VarName != NULL) {
2571     FreePool (VarName);
2572   }
2573 
2574   if (DevicePath != NULL) {
2575     FreePool (DevicePath);
2576   }
2577 
2578   if (ConfigResp != NULL) {
2579     FreePool (ConfigResp);
2580   }
2581 
2582   if (ConfigAltResp != NULL) {
2583     FreePool (ConfigAltResp);
2584   }
2585 
2586   if (HiiPackageList != NULL) {
2587     FreePool (HiiPackageList);
2588   }
2589 
2590   if (EFI_ERROR (Status)) {
2591     return FALSE;
2592   }
2593 
2594   return TRUE;
2595 }
2596 
2597 /**
2598   Validate the current configuration by parsing HII form IFR opcode.
2599 
2600   NULL request string support depends on the ExportConfig interface of
2601   HiiConfigRouting protocol in UEFI specification.
2602 
2603   @param  Request   A null-terminated Unicode string in
2604                     <MultiConfigRequest> format. It can be NULL.
2605                     If it is NULL, all current configuration for the
2606                     entirety of the current HII database will be validated.
2607 
2608   @retval TRUE    Current configuration is valid.
2609   @retval FALSE   Current configuration is invalid.
2610 **/
2611 BOOLEAN
2612 EFIAPI
HiiValidateSettings(IN CONST EFI_STRING Request OPTIONAL)2613 HiiValidateSettings (
2614   IN CONST EFI_STRING Request  OPTIONAL
2615   )
2616 {
2617   return InternalHiiIfrValueAction (Request, 0, ACTION_VALIDATE_SETTING);
2618 }
2619 
2620 /**
2621   Reset the default value specified by DefaultId to the driver
2622   configuration got by Request string.
2623 
2624   NULL request string support depends on the ExportConfig interface of
2625   HiiConfigRouting protocol in UEFI specification.
2626 
2627   @param Request    A null-terminated Unicode string in
2628                     <MultiConfigRequest> format. It can be NULL.
2629                     If it is NULL, all configuration for the
2630                     entirety of the current HII database will be reset.
2631   @param DefaultId  Specifies the type of defaults to retrieve.
2632 
2633   @retval TRUE    The default value is set successfully.
2634   @retval FALSE   The default value can't be found and set.
2635 **/
2636 BOOLEAN
2637 EFIAPI
HiiSetToDefaults(IN CONST EFI_STRING Request,OPTIONAL IN UINT16 DefaultId)2638 HiiSetToDefaults (
2639   IN CONST EFI_STRING Request,  OPTIONAL
2640   IN UINT16        DefaultId
2641   )
2642 {
2643   return InternalHiiIfrValueAction (Request, DefaultId, ACTION_SET_DEFAUTL_VALUE);
2644 }
2645 
2646 /**
2647   Determines if two values in config strings match.
2648 
2649   Compares the substring between StartSearchString and StopSearchString in
2650   FirstString to the substring between StartSearchString and StopSearchString
2651   in SecondString.  If the two substrings match, then TRUE is returned.  If the
2652   two substrings do not match, then FALSE is returned.
2653 
2654   If FirstString is NULL, then ASSERT().
2655   If SecondString is NULL, then ASSERT().
2656   If StartSearchString is NULL, then ASSERT().
2657   If StopSearchString is NULL, then ASSERT().
2658 
2659   @param FirstString        Pointer to the first Null-terminated Unicode string.
2660   @param SecondString       Pointer to the second Null-terminated Unicode string.
2661   @param StartSearchString  Pointer to the Null-terminated Unicode string that
2662                             marks the start of the value string to compare.
2663   @param StopSearchString   Pointer to the Null-terminated Unicode string that
2664                             marks the end of the value string to compare.
2665 
2666   @retval FALSE             StartSearchString is not present in FirstString.
2667   @retval FALSE             StartSearchString is not present in SecondString.
2668   @retval FALSE             StopSearchString is not present in FirstString.
2669   @retval FALSE             StopSearchString is not present in SecondString.
2670   @retval FALSE             The length of the substring in FirstString is not the
2671                             same length as the substring in SecondString.
2672   @retval FALSE             The value string in FirstString does not matche the
2673                             value string in SecondString.
2674   @retval TRUE              The value string in FirstString matches the value
2675                             string in SecondString.
2676 
2677 **/
2678 BOOLEAN
2679 EFIAPI
InternalHiiCompareSubString(IN CHAR16 * FirstString,IN CHAR16 * SecondString,IN CHAR16 * StartSearchString,IN CHAR16 * StopSearchString)2680 InternalHiiCompareSubString (
2681   IN CHAR16  *FirstString,
2682   IN CHAR16  *SecondString,
2683   IN CHAR16  *StartSearchString,
2684   IN CHAR16  *StopSearchString
2685   )
2686 {
2687   CHAR16  *EndFirstString;
2688   CHAR16  *EndSecondString;
2689 
2690   ASSERT (FirstString != NULL);
2691   ASSERT (SecondString != NULL);
2692   ASSERT (StartSearchString != NULL);
2693   ASSERT (StopSearchString != NULL);
2694 
2695   FirstString = StrStr (FirstString, StartSearchString);
2696   if (FirstString == NULL) {
2697     return FALSE;
2698   }
2699 
2700   SecondString = StrStr (SecondString, StartSearchString);
2701   if (SecondString == NULL) {
2702     return FALSE;
2703   }
2704 
2705   EndFirstString = StrStr (FirstString, StopSearchString);
2706   if (EndFirstString == NULL) {
2707     return FALSE;
2708   }
2709 
2710   EndSecondString = StrStr (SecondString, StopSearchString);
2711   if (EndSecondString == NULL) {
2712     return FALSE;
2713   }
2714 
2715   if ((EndFirstString - FirstString) != (EndSecondString - SecondString)) {
2716     return FALSE;
2717   }
2718 
2719   return (BOOLEAN)(StrnCmp (FirstString, SecondString, EndFirstString - FirstString) == 0);
2720 }
2721 
2722 /**
2723   Determines if the routing data specified by GUID and NAME match a <ConfigHdr>.
2724 
2725   If ConfigHdr is NULL, then ASSERT().
2726 
2727   @param[in] ConfigHdr  Either <ConfigRequest> or <ConfigResp>.
2728   @param[in] Guid       GUID of the storage.
2729   @param[in] Name       NAME of the storage.
2730 
2731   @retval TRUE   Routing information matches <ConfigHdr>.
2732   @retval FALSE  Routing information does not match <ConfigHdr>.
2733 
2734 **/
2735 BOOLEAN
2736 EFIAPI
HiiIsConfigHdrMatch(IN CONST EFI_STRING ConfigHdr,IN CONST EFI_GUID * Guid,OPTIONAL IN CONST CHAR16 * Name OPTIONAL)2737 HiiIsConfigHdrMatch (
2738   IN CONST EFI_STRING  ConfigHdr,
2739   IN CONST EFI_GUID    *Guid,     OPTIONAL
2740   IN CONST CHAR16      *Name      OPTIONAL
2741   )
2742 {
2743   EFI_STRING  CompareConfigHdr;
2744   BOOLEAN     Result;
2745 
2746   ASSERT (ConfigHdr != NULL);
2747 
2748   //
2749   // Use Guid and Name to generate a <ConfigHdr> string
2750   //
2751   CompareConfigHdr = HiiConstructConfigHdr (Guid, Name, NULL);
2752   if (CompareConfigHdr == NULL) {
2753     return FALSE;
2754   }
2755 
2756   Result = TRUE;
2757   if (Guid != NULL) {
2758     //
2759     // Compare GUID value strings
2760     //
2761     Result = InternalHiiCompareSubString (ConfigHdr, CompareConfigHdr, L"GUID=", L"&NAME=");
2762   }
2763 
2764   if (Result && Name != NULL) {
2765     //
2766     // Compare NAME value strings
2767     //
2768     Result = InternalHiiCompareSubString (ConfigHdr, CompareConfigHdr, L"&NAME=", L"&PATH=");
2769   }
2770 
2771   //
2772   // Free the <ConfigHdr> string
2773   //
2774   FreePool (CompareConfigHdr);
2775 
2776   return Result;
2777 }
2778 
2779 /**
2780   Retrieves uncommitted data from the Form Browser and converts it to a binary
2781   buffer.
2782 
2783   @param[in]  VariableGuid  Pointer to an EFI_GUID structure.  This is an optional
2784                             parameter that may be NULL.
2785   @param[in]  VariableName  Pointer to a Null-terminated Unicode string.  This
2786                             is an optional parameter that may be NULL.
2787   @param[in]  BufferSize    Length in bytes of buffer to hold retrieved data.
2788   @param[out] Buffer        Buffer of data to be updated.
2789 
2790   @retval FALSE  The uncommitted data could not be retrieved.
2791   @retval TRUE   The uncommitted data was retrieved.
2792 
2793 **/
2794 BOOLEAN
2795 EFIAPI
HiiGetBrowserData(IN CONST EFI_GUID * VariableGuid,OPTIONAL IN CONST CHAR16 * VariableName,OPTIONAL IN UINTN BufferSize,OUT UINT8 * Buffer)2796 HiiGetBrowserData (
2797   IN CONST EFI_GUID  *VariableGuid,  OPTIONAL
2798   IN CONST CHAR16    *VariableName,  OPTIONAL
2799   IN UINTN           BufferSize,
2800   OUT UINT8          *Buffer
2801   )
2802 {
2803   EFI_STRING  ResultsData;
2804   UINTN       Size;
2805   EFI_STRING  ConfigResp;
2806   EFI_STATUS  Status;
2807   CHAR16      *Progress;
2808 
2809   //
2810   // Retrieve the results data from the Browser Callback
2811   //
2812   ResultsData = InternalHiiBrowserCallback (VariableGuid, VariableName, NULL);
2813   if (ResultsData == NULL) {
2814     return FALSE;
2815   }
2816 
2817   //
2818   // Construct <ConfigResp> mConfigHdrTemplate L'&' ResultsData L'\0'
2819   //
2820   Size = (StrLen (mConfigHdrTemplate) + 1) * sizeof (CHAR16);
2821   Size = Size + (StrLen (ResultsData) + 1) * sizeof (CHAR16);
2822   ConfigResp = AllocateZeroPool (Size);
2823   UnicodeSPrint (ConfigResp, Size, L"%s&%s", mConfigHdrTemplate, ResultsData);
2824 
2825   //
2826   // Free the allocated buffer
2827   //
2828   FreePool (ResultsData);
2829   if (ConfigResp == NULL) {
2830     return FALSE;
2831   }
2832 
2833   //
2834   // Convert <ConfigResp> to a buffer
2835   //
2836   Status = gHiiConfigRouting->ConfigToBlock (
2837                                 gHiiConfigRouting,
2838                                 ConfigResp,
2839                                 Buffer,
2840                                 &BufferSize,
2841                                 &Progress
2842                                 );
2843   //
2844   // Free the allocated buffer
2845   //
2846   FreePool (ConfigResp);
2847 
2848   if (EFI_ERROR (Status)) {
2849     return FALSE;
2850   }
2851 
2852   return TRUE;
2853 }
2854 
2855 /**
2856   Updates uncommitted data in the Form Browser.
2857 
2858   If Buffer is NULL, then ASSERT().
2859 
2860   @param[in]  VariableGuid    Pointer to an EFI_GUID structure.  This is an optional
2861                               parameter that may be NULL.
2862   @param[in]  VariableName    Pointer to a Null-terminated Unicode string.  This
2863                               is an optional parameter that may be NULL.
2864   @param[in]  BufferSize      Length, in bytes, of Buffer.
2865   @param[in]  Buffer          Buffer of data to commit.
2866   @param[in]  RequestElement  An optional field to specify which part of the
2867                               buffer data will be send back to Browser. If NULL,
2868                               the whole buffer of data will be committed to
2869                               Browser.
2870                               <RequestElement> ::= &OFFSET=<Number>&WIDTH=<Number>*
2871 
2872   @retval FALSE  The uncommitted data could not be updated.
2873   @retval TRUE   The uncommitted data was updated.
2874 
2875 **/
2876 BOOLEAN
2877 EFIAPI
HiiSetBrowserData(IN CONST EFI_GUID * VariableGuid,OPTIONAL IN CONST CHAR16 * VariableName,OPTIONAL IN UINTN BufferSize,IN CONST UINT8 * Buffer,IN CONST CHAR16 * RequestElement OPTIONAL)2878 HiiSetBrowserData (
2879   IN CONST EFI_GUID  *VariableGuid, OPTIONAL
2880   IN CONST CHAR16    *VariableName, OPTIONAL
2881   IN UINTN           BufferSize,
2882   IN CONST UINT8     *Buffer,
2883   IN CONST CHAR16    *RequestElement  OPTIONAL
2884   )
2885 {
2886   UINTN       Size;
2887   EFI_STRING  ConfigRequest;
2888   EFI_STRING  ConfigResp;
2889   EFI_STRING  ResultsData;
2890 
2891   ASSERT (Buffer != NULL);
2892 
2893   //
2894   // Construct <ConfigRequest>
2895   //
2896   if (RequestElement == NULL) {
2897     //
2898     // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
2899     // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator
2900     //
2901     Size = (StrLen (mConfigHdrTemplate) + 32 + 1) * sizeof (CHAR16);
2902     ConfigRequest = AllocateZeroPool (Size);
2903     UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", mConfigHdrTemplate, (UINT64)BufferSize);
2904   } else {
2905     //
2906     // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
2907     // followed by <RequestElement> followed by a Null-terminator
2908     //
2909     Size = StrLen (mConfigHdrTemplate) * sizeof (CHAR16);
2910     Size = Size + (StrLen (RequestElement) + 1) * sizeof (CHAR16);
2911     ConfigRequest = AllocateZeroPool (Size);
2912     UnicodeSPrint (ConfigRequest, Size, L"%s%s", mConfigHdrTemplate, RequestElement);
2913   }
2914   if (ConfigRequest == NULL) {
2915     return FALSE;
2916   }
2917 
2918   //
2919   // Convert <ConfigRequest> to <ConfigResp>
2920   //
2921   ConfigResp = InternalHiiBlockToConfig (ConfigRequest, Buffer, BufferSize);
2922   FreePool (ConfigRequest);
2923   if (ConfigResp == NULL) {
2924     return FALSE;
2925   }
2926 
2927   //
2928   // Set data in the uncommitted browser state information
2929   //
2930   ResultsData = InternalHiiBrowserCallback (VariableGuid, VariableName, ConfigResp + StrLen(mConfigHdrTemplate) + 1);
2931   FreePool (ConfigResp);
2932 
2933   return (BOOLEAN)(ResultsData != NULL);
2934 }
2935 
2936 /////////////////////////////////////////
2937 /////////////////////////////////////////
2938 /// IFR Functions
2939 /////////////////////////////////////////
2940 /////////////////////////////////////////
2941 
2942 #define HII_LIB_OPCODE_ALLOCATION_SIZE  0x200
2943 
2944 typedef struct {
2945   UINT8  *Buffer;
2946   UINTN  BufferSize;
2947   UINTN  Position;
2948 } HII_LIB_OPCODE_BUFFER;
2949 
2950 ///
2951 /// Lookup table that converts EFI_IFR_TYPE_X enum values to a width in bytes
2952 ///
2953 GLOBAL_REMOVE_IF_UNREFERENCED CONST UINT8 mHiiDefaultTypeToWidth[] = {
2954   1, // EFI_IFR_TYPE_NUM_SIZE_8
2955   2, // EFI_IFR_TYPE_NUM_SIZE_16
2956   4, // EFI_IFR_TYPE_NUM_SIZE_32
2957   8, // EFI_IFR_TYPE_NUM_SIZE_64
2958   1, // EFI_IFR_TYPE_BOOLEAN
2959   3, // EFI_IFR_TYPE_TIME
2960   4, // EFI_IFR_TYPE_DATE
2961   2  // EFI_IFR_TYPE_STRING
2962 };
2963 
2964 /**
2965   Allocates and returns a new OpCode Handle.  OpCode Handles must be freed with
2966   HiiFreeOpCodeHandle().
2967 
2968   @retval NULL   There are not enough resources to allocate a new OpCode Handle.
2969   @retval Other  A new OpCode handle.
2970 
2971 **/
2972 VOID *
2973 EFIAPI
HiiAllocateOpCodeHandle(VOID)2974 HiiAllocateOpCodeHandle (
2975   VOID
2976   )
2977 {
2978   HII_LIB_OPCODE_BUFFER  *OpCodeBuffer;
2979 
2980   OpCodeBuffer = (HII_LIB_OPCODE_BUFFER *)AllocatePool (sizeof (HII_LIB_OPCODE_BUFFER));
2981   if (OpCodeBuffer == NULL) {
2982     return NULL;
2983   }
2984   OpCodeBuffer->Buffer = (UINT8 *)AllocatePool (HII_LIB_OPCODE_ALLOCATION_SIZE);
2985   if (OpCodeBuffer->Buffer == NULL) {
2986     FreePool (OpCodeBuffer);
2987     return NULL;
2988   }
2989   OpCodeBuffer->BufferSize = HII_LIB_OPCODE_ALLOCATION_SIZE;
2990   OpCodeBuffer->Position = 0;
2991   return (VOID *)OpCodeBuffer;
2992 }
2993 
2994 /**
2995   Frees an OpCode Handle that was previously allocated with HiiAllocateOpCodeHandle().
2996   When an OpCode Handle is freed, all of the opcodes associated with the OpCode
2997   Handle are also freed.
2998 
2999   If OpCodeHandle is NULL, then ASSERT().
3000 
3001   @param[in]  OpCodeHandle   Handle to the buffer of opcodes.
3002 
3003 **/
3004 VOID
3005 EFIAPI
HiiFreeOpCodeHandle(VOID * OpCodeHandle)3006 HiiFreeOpCodeHandle (
3007   VOID  *OpCodeHandle
3008   )
3009 {
3010   HII_LIB_OPCODE_BUFFER  *OpCodeBuffer;
3011 
3012   ASSERT (OpCodeHandle != NULL);
3013 
3014   OpCodeBuffer = (HII_LIB_OPCODE_BUFFER *)OpCodeHandle;
3015   if (OpCodeBuffer->Buffer != NULL) {
3016     FreePool (OpCodeBuffer->Buffer);
3017   }
3018   FreePool (OpCodeBuffer);
3019 }
3020 
3021 /**
3022   Internal function gets the current position of opcode buffer.
3023 
3024   @param[in]  OpCodeHandle   Handle to the buffer of opcodes.
3025 
3026   @return Current position of opcode buffer.
3027 **/
3028 UINTN
3029 EFIAPI
InternalHiiOpCodeHandlePosition(IN VOID * OpCodeHandle)3030 InternalHiiOpCodeHandlePosition (
3031   IN VOID  *OpCodeHandle
3032   )
3033 {
3034   return ((HII_LIB_OPCODE_BUFFER  *)OpCodeHandle)->Position;
3035 }
3036 
3037 /**
3038   Internal function gets the start pointer of opcode buffer.
3039 
3040   @param[in]  OpCodeHandle   Handle to the buffer of opcodes.
3041 
3042   @return Pointer to the opcode buffer base.
3043 **/
3044 UINT8 *
3045 EFIAPI
InternalHiiOpCodeHandleBuffer(IN VOID * OpCodeHandle)3046 InternalHiiOpCodeHandleBuffer (
3047   IN VOID  *OpCodeHandle
3048   )
3049 {
3050   return ((HII_LIB_OPCODE_BUFFER  *)OpCodeHandle)->Buffer;
3051 }
3052 
3053 /**
3054   Internal function reserves the enough buffer for current opcode.
3055   When the buffer is not enough, Opcode buffer will be extended.
3056 
3057   @param[in]  OpCodeHandle   Handle to the buffer of opcodes.
3058   @param[in]  Size           Size of current opcode.
3059 
3060   @return Pointer to the current opcode.
3061 **/
3062 UINT8 *
3063 EFIAPI
InternalHiiGrowOpCodeHandle(IN VOID * OpCodeHandle,IN UINTN Size)3064 InternalHiiGrowOpCodeHandle (
3065   IN VOID   *OpCodeHandle,
3066   IN UINTN  Size
3067   )
3068 {
3069   HII_LIB_OPCODE_BUFFER  *OpCodeBuffer;
3070   UINT8                  *Buffer;
3071 
3072   ASSERT (OpCodeHandle != NULL);
3073 
3074   OpCodeBuffer = (HII_LIB_OPCODE_BUFFER *)OpCodeHandle;
3075   if (OpCodeBuffer->Position + Size > OpCodeBuffer->BufferSize) {
3076     Buffer = ReallocatePool (
3077               OpCodeBuffer->BufferSize,
3078               OpCodeBuffer->BufferSize + (Size + HII_LIB_OPCODE_ALLOCATION_SIZE),
3079               OpCodeBuffer->Buffer
3080               );
3081     ASSERT (Buffer != NULL);
3082     OpCodeBuffer->Buffer = Buffer;
3083     OpCodeBuffer->BufferSize += (Size + HII_LIB_OPCODE_ALLOCATION_SIZE);
3084   }
3085   Buffer = OpCodeBuffer->Buffer + OpCodeBuffer->Position;
3086   OpCodeBuffer->Position += Size;
3087   return Buffer;
3088 }
3089 
3090 /**
3091   Internal function creates opcode based on the template opcode.
3092 
3093   @param[in]  OpCodeHandle    Handle to the buffer of opcodes.
3094   @param[in]  OpCodeTemplate  Pointer to the template buffer of opcode.
3095   @param[in]  OpCode          OpCode IFR value.
3096   @param[in]  OpCodeSize      Size of opcode.
3097   @param[in]  ExtensionSize   Size of extended opcode.
3098   @param[in]  Scope           Scope bit of opcode.
3099 
3100   @return Pointer to the current opcode with opcode data.
3101 **/
3102 UINT8 *
3103 EFIAPI
InternalHiiCreateOpCodeExtended(IN VOID * OpCodeHandle,IN VOID * OpCodeTemplate,IN UINT8 OpCode,IN UINTN OpCodeSize,IN UINTN ExtensionSize,IN UINT8 Scope)3104 InternalHiiCreateOpCodeExtended (
3105   IN VOID   *OpCodeHandle,
3106   IN VOID   *OpCodeTemplate,
3107   IN UINT8  OpCode,
3108   IN UINTN  OpCodeSize,
3109   IN UINTN  ExtensionSize,
3110   IN UINT8  Scope
3111   )
3112 {
3113   EFI_IFR_OP_HEADER  *Header;
3114   UINT8              *Buffer;
3115 
3116   ASSERT (OpCodeTemplate != NULL);
3117   ASSERT ((OpCodeSize + ExtensionSize) <= 0x7F);
3118 
3119   Header = (EFI_IFR_OP_HEADER *)OpCodeTemplate;
3120   Header->OpCode = OpCode;
3121   Header->Scope  = Scope;
3122   Header->Length = (UINT8)(OpCodeSize + ExtensionSize);
3123   Buffer = InternalHiiGrowOpCodeHandle (OpCodeHandle, Header->Length);
3124   return (UINT8 *)CopyMem (Buffer, Header, OpCodeSize);
3125 }
3126 
3127 /**
3128   Internal function creates opcode based on the template opcode for the normal opcode.
3129 
3130   @param[in]  OpCodeHandle    Handle to the buffer of opcodes.
3131   @param[in]  OpCodeTemplate  Pointer to the template buffer of opcode.
3132   @param[in]  OpCode          OpCode IFR value.
3133   @param[in]  OpCodeSize      Size of opcode.
3134 
3135   @return Pointer to the current opcode with opcode data.
3136 **/
3137 UINT8 *
3138 EFIAPI
InternalHiiCreateOpCode(IN VOID * OpCodeHandle,IN VOID * OpCodeTemplate,IN UINT8 OpCode,IN UINTN OpCodeSize)3139 InternalHiiCreateOpCode (
3140   IN VOID   *OpCodeHandle,
3141   IN VOID   *OpCodeTemplate,
3142   IN UINT8  OpCode,
3143   IN UINTN  OpCodeSize
3144   )
3145 {
3146   return InternalHiiCreateOpCodeExtended (OpCodeHandle, OpCodeTemplate, OpCode, OpCodeSize, 0, 0);
3147 }
3148 
3149 /**
3150   Append raw opcodes to an OpCodeHandle.
3151 
3152   If OpCodeHandle is NULL, then ASSERT().
3153   If RawBuffer is NULL, then ASSERT();
3154 
3155   @param[in]  OpCodeHandle   Handle to the buffer of opcodes.
3156   @param[in]  RawBuffer      Buffer of opcodes to append.
3157   @param[in]  RawBufferSize  The size, in bytes, of Buffer.
3158 
3159   @retval NULL   There is not enough space left in Buffer to add the opcode.
3160   @retval Other  A pointer to the appended opcodes.
3161 
3162 **/
3163 UINT8 *
3164 EFIAPI
HiiCreateRawOpCodes(IN VOID * OpCodeHandle,IN UINT8 * RawBuffer,IN UINTN RawBufferSize)3165 HiiCreateRawOpCodes (
3166   IN VOID   *OpCodeHandle,
3167   IN UINT8  *RawBuffer,
3168   IN UINTN  RawBufferSize
3169   )
3170 {
3171   UINT8  *Buffer;
3172 
3173   ASSERT (RawBuffer != NULL);
3174 
3175   Buffer = InternalHiiGrowOpCodeHandle (OpCodeHandle, RawBufferSize);
3176   return (UINT8 *)CopyMem (Buffer, RawBuffer, RawBufferSize);
3177 }
3178 
3179 /**
3180   Append opcodes from one OpCode Handle to another OpCode handle.
3181 
3182   If OpCodeHandle is NULL, then ASSERT().
3183   If RawOpCodeHandle is NULL, then ASSERT();
3184 
3185   @param[in]  OpCodeHandle     Handle to the buffer of opcodes.
3186   @param[in]  RawOpCodeHandle  Handle to the buffer of opcodes.
3187 
3188   @retval NULL   There is not enough space left in Buffer to add the opcode.
3189   @retval Other  A pointer to the appended opcodes.
3190 
3191 **/
3192 UINT8 *
3193 EFIAPI
InternalHiiAppendOpCodes(IN VOID * OpCodeHandle,IN VOID * RawOpCodeHandle)3194 InternalHiiAppendOpCodes (
3195   IN VOID  *OpCodeHandle,
3196   IN VOID  *RawOpCodeHandle
3197   )
3198 {
3199   HII_LIB_OPCODE_BUFFER  *RawOpCodeBuffer;
3200 
3201   ASSERT (RawOpCodeHandle != NULL);
3202 
3203   RawOpCodeBuffer = (HII_LIB_OPCODE_BUFFER *)RawOpCodeHandle;
3204   return HiiCreateRawOpCodes (OpCodeHandle, RawOpCodeBuffer->Buffer, RawOpCodeBuffer->Position);
3205 }
3206 
3207 /**
3208   Create EFI_IFR_END_OP opcode.
3209 
3210   If OpCodeHandle is NULL, then ASSERT().
3211 
3212   @param[in]  OpCodeHandle  Handle to the buffer of opcodes.
3213 
3214   @retval NULL   There is not enough space left in Buffer to add the opcode.
3215   @retval Other  A pointer to the created opcode.
3216 
3217 **/
3218 UINT8 *
3219 EFIAPI
HiiCreateEndOpCode(IN VOID * OpCodeHandle)3220 HiiCreateEndOpCode (
3221   IN VOID  *OpCodeHandle
3222   )
3223 {
3224   EFI_IFR_END  OpCode;
3225 
3226   return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_END_OP, sizeof (OpCode));
3227 }
3228 
3229 /**
3230   Create EFI_IFR_ONE_OF_OPTION_OP opcode.
3231 
3232   If OpCodeHandle is NULL, then ASSERT().
3233   If Type is invalid, then ASSERT().
3234   If Flags is invalid, then ASSERT().
3235 
3236   @param[in]  OpCodeHandle  Handle to the buffer of opcodes.
3237   @param[in]  StringId      StringId for the option
3238   @param[in]  Flags         Flags for the option
3239   @param[in]  Type          Type for the option
3240   @param[in]  Value         Value for the option
3241 
3242   @retval NULL   There is not enough space left in Buffer to add the opcode.
3243   @retval Other  A pointer to the created opcode.
3244 
3245 **/
3246 UINT8 *
3247 EFIAPI
HiiCreateOneOfOptionOpCode(IN VOID * OpCodeHandle,IN UINT16 StringId,IN UINT8 Flags,IN UINT8 Type,IN UINT64 Value)3248 HiiCreateOneOfOptionOpCode (
3249   IN VOID    *OpCodeHandle,
3250   IN UINT16  StringId,
3251   IN UINT8   Flags,
3252   IN UINT8   Type,
3253   IN UINT64  Value
3254   )
3255 {
3256   EFI_IFR_ONE_OF_OPTION  OpCode;
3257 
3258   ASSERT (Type < EFI_IFR_TYPE_OTHER);
3259 
3260   ZeroMem (&OpCode, sizeof (OpCode));
3261   OpCode.Option = StringId;
3262   OpCode.Flags  = (UINT8) (Flags & (EFI_IFR_OPTION_DEFAULT | EFI_IFR_OPTION_DEFAULT_MFG));
3263   OpCode.Type   = Type;
3264   CopyMem (&OpCode.Value, &Value, mHiiDefaultTypeToWidth[Type]);
3265 
3266   return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_ONE_OF_OPTION_OP, OFFSET_OF(EFI_IFR_ONE_OF_OPTION, Value) + mHiiDefaultTypeToWidth[Type]);
3267 }
3268 
3269 /**
3270   Create EFI_IFR_DEFAULT_OP opcode.
3271 
3272   If OpCodeHandle is NULL, then ASSERT().
3273   If Type is invalid, then ASSERT().
3274 
3275   @param[in]  OpCodeHandle  Handle to the buffer of opcodes.
3276   @param[in]  DefaultId     DefaultId for the default
3277   @param[in]  Type          Type for the default
3278   @param[in]  Value         Value for the default
3279 
3280   @retval NULL   There is not enough space left in Buffer to add the opcode.
3281   @retval Other  A pointer to the created opcode.
3282 
3283 **/
3284 UINT8 *
3285 EFIAPI
HiiCreateDefaultOpCode(IN VOID * OpCodeHandle,IN UINT16 DefaultId,IN UINT8 Type,IN UINT64 Value)3286 HiiCreateDefaultOpCode (
3287   IN VOID    *OpCodeHandle,
3288   IN UINT16  DefaultId,
3289   IN UINT8   Type,
3290   IN UINT64  Value
3291   )
3292 {
3293   EFI_IFR_DEFAULT  OpCode;
3294 
3295   ASSERT (Type < EFI_IFR_TYPE_OTHER);
3296 
3297   ZeroMem (&OpCode, sizeof (OpCode));
3298   OpCode.Type      = Type;
3299   OpCode.DefaultId = DefaultId;
3300   CopyMem (&OpCode.Value, &Value, mHiiDefaultTypeToWidth[Type]);
3301 
3302   return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_DEFAULT_OP, OFFSET_OF(EFI_IFR_DEFAULT, Value) + mHiiDefaultTypeToWidth[Type]);
3303 }
3304 
3305 /**
3306   Create EFI_IFR_GUID opcode.
3307 
3308   If OpCodeHandle is NULL, then ASSERT().
3309   If Guid is NULL, then ASSERT().
3310   If OpCodeSize < sizeof (EFI_IFR_GUID), then ASSERT().
3311 
3312   @param[in]  OpCodeHandle  Handle to the buffer of opcodes.
3313   @param[in]  Guid          Pointer to EFI_GUID of this guided opcode.
3314   @param[in]  GuidOpCode    Pointer to an EFI_IFR_GUID opcode.  This is an
3315                             optional parameter that may be NULL.  If this
3316                             parameter is NULL, then the GUID extension
3317                             region of the created opcode is filled with zeros.
3318                             If this parameter is not NULL, then the GUID
3319                             extension region of GuidData will be copied to
3320                             the GUID extension region of the created opcode.
3321   @param[in]  OpCodeSize    The size, in bytes, of created opcode.  This value
3322                             must be >= sizeof(EFI_IFR_GUID).
3323 
3324   @retval NULL   There is not enough space left in Buffer to add the opcode.
3325   @retval Other  A pointer to the created opcode.
3326 
3327 **/
3328 UINT8 *
3329 EFIAPI
HiiCreateGuidOpCode(IN VOID * OpCodeHandle,IN CONST EFI_GUID * Guid,IN CONST VOID * GuidOpCode,OPTIONAL IN UINTN OpCodeSize)3330 HiiCreateGuidOpCode (
3331   IN VOID            *OpCodeHandle,
3332   IN CONST EFI_GUID  *Guid,
3333   IN CONST VOID      *GuidOpCode,    OPTIONAL
3334   IN UINTN           OpCodeSize
3335   )
3336 {
3337   EFI_IFR_GUID  OpCode;
3338   EFI_IFR_GUID  *OpCodePointer;
3339 
3340   ASSERT (Guid != NULL);
3341   ASSERT (OpCodeSize >= sizeof (OpCode));
3342 
3343   ZeroMem (&OpCode, sizeof (OpCode));
3344   CopyGuid ((EFI_GUID *)(VOID *)&OpCode.Guid, Guid);
3345 
3346   OpCodePointer = (EFI_IFR_GUID *)InternalHiiCreateOpCodeExtended (
3347                                     OpCodeHandle,
3348                                     &OpCode,
3349                                     EFI_IFR_GUID_OP,
3350                                     sizeof (OpCode),
3351                                     OpCodeSize - sizeof (OpCode),
3352                                     0
3353                                     );
3354   if (OpCodePointer != NULL && GuidOpCode != NULL) {
3355     CopyMem (OpCodePointer + 1, (EFI_IFR_GUID *)GuidOpCode + 1, OpCodeSize - sizeof (OpCode));
3356   }
3357   return (UINT8 *)OpCodePointer;
3358 }
3359 
3360 /**
3361   Create EFI_IFR_ACTION_OP opcode.
3362 
3363   If OpCodeHandle is NULL, then ASSERT().
3364   If any reserved bits are set in QuestionFlags, then ASSERT().
3365 
3366   @param[in]  OpCodeHandle  Handle to the buffer of opcodes.
3367   @param[in]  QuestionId      Question ID
3368   @param[in]  Prompt          String ID for Prompt
3369   @param[in]  Help            String ID for Help
3370   @param[in]  QuestionFlags   Flags in Question Header
3371   @param[in]  QuestionConfig  String ID for configuration
3372 
3373   @retval NULL   There is not enough space left in Buffer to add the opcode.
3374   @retval Other  A pointer to the created opcode.
3375 
3376 **/
3377 UINT8 *
3378 EFIAPI
HiiCreateActionOpCode(IN VOID * OpCodeHandle,IN EFI_QUESTION_ID QuestionId,IN EFI_STRING_ID Prompt,IN EFI_STRING_ID Help,IN UINT8 QuestionFlags,IN EFI_STRING_ID QuestionConfig)3379 HiiCreateActionOpCode (
3380   IN VOID             *OpCodeHandle,
3381   IN EFI_QUESTION_ID  QuestionId,
3382   IN EFI_STRING_ID    Prompt,
3383   IN EFI_STRING_ID    Help,
3384   IN UINT8            QuestionFlags,
3385   IN EFI_STRING_ID    QuestionConfig
3386   )
3387 {
3388   EFI_IFR_ACTION  OpCode;
3389 
3390   ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED))) == 0);
3391 
3392   ZeroMem (&OpCode, sizeof (OpCode));
3393   OpCode.Question.QuestionId    = QuestionId;
3394   OpCode.Question.Header.Prompt = Prompt;
3395   OpCode.Question.Header.Help   = Help;
3396   OpCode.Question.Flags         = QuestionFlags;
3397   OpCode.QuestionConfig         = QuestionConfig;
3398 
3399   return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_ACTION_OP, sizeof (OpCode));
3400 }
3401 
3402 /**
3403   Create EFI_IFR_SUBTITLE_OP opcode.
3404 
3405   If OpCodeHandle is NULL, then ASSERT().
3406   If any reserved bits are set in Flags, then ASSERT().
3407   If Scope > 1, then ASSERT().
3408 
3409   @param[in]  OpCodeHandle  Handle to the buffer of opcodes.
3410   @param[in]  Prompt      String ID for Prompt
3411   @param[in]  Help        String ID for Help
3412   @param[in]  Flags       Subtitle opcode flags
3413   @param[in]  Scope       1 if this opcpde is the beginning of a new scope.
3414                           0 if this opcode is within the current scope.
3415 
3416   @retval NULL   There is not enough space left in Buffer to add the opcode.
3417   @retval Other  A pointer to the created opcode.
3418 
3419 **/
3420 UINT8 *
3421 EFIAPI
HiiCreateSubTitleOpCode(IN VOID * OpCodeHandle,IN EFI_STRING_ID Prompt,IN EFI_STRING_ID Help,IN UINT8 Flags,IN UINT8 Scope)3422 HiiCreateSubTitleOpCode (
3423   IN VOID           *OpCodeHandle,
3424   IN EFI_STRING_ID  Prompt,
3425   IN EFI_STRING_ID  Help,
3426   IN UINT8          Flags,
3427   IN UINT8          Scope
3428   )
3429 {
3430   EFI_IFR_SUBTITLE  OpCode;
3431 
3432   ASSERT (Scope <= 1);
3433   ASSERT ((Flags & (~(EFI_IFR_FLAGS_HORIZONTAL))) == 0);
3434 
3435   ZeroMem (&OpCode, sizeof (OpCode));
3436   OpCode.Statement.Prompt = Prompt;
3437   OpCode.Statement.Help   = Help;
3438   OpCode.Flags            = Flags;
3439 
3440   return InternalHiiCreateOpCodeExtended (
3441            OpCodeHandle,
3442            &OpCode,
3443            EFI_IFR_SUBTITLE_OP,
3444            sizeof (OpCode),
3445            0,
3446            Scope
3447            );
3448 }
3449 
3450 /**
3451   Create EFI_IFR_REF_OP opcode.
3452 
3453   If OpCodeHandle is NULL, then ASSERT().
3454   If any reserved bits are set in QuestionFlags, then ASSERT().
3455 
3456   @param[in]  OpCodeHandle   Handle to the buffer of opcodes.
3457   @param[in]  FormId         Destination Form ID
3458   @param[in]  Prompt         String ID for Prompt
3459   @param[in]  Help           String ID for Help
3460   @param[in]  QuestionFlags  Flags in Question Header
3461   @param[in]  QuestionId     Question ID
3462 
3463   @retval NULL   There is not enough space left in Buffer to add the opcode.
3464   @retval Other  A pointer to the created opcode.
3465 
3466 **/
3467 UINT8 *
3468 EFIAPI
HiiCreateGotoOpCode(IN VOID * OpCodeHandle,IN EFI_FORM_ID FormId,IN EFI_STRING_ID Prompt,IN EFI_STRING_ID Help,IN UINT8 QuestionFlags,IN EFI_QUESTION_ID QuestionId)3469 HiiCreateGotoOpCode (
3470   IN VOID             *OpCodeHandle,
3471   IN EFI_FORM_ID      FormId,
3472   IN EFI_STRING_ID    Prompt,
3473   IN EFI_STRING_ID    Help,
3474   IN UINT8            QuestionFlags,
3475   IN EFI_QUESTION_ID  QuestionId
3476   )
3477 {
3478   EFI_IFR_REF  OpCode;
3479 
3480   ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED))) == 0);
3481 
3482   ZeroMem (&OpCode, sizeof (OpCode));
3483   OpCode.Question.Header.Prompt = Prompt;
3484   OpCode.Question.Header.Help   = Help;
3485   OpCode.Question.QuestionId    = QuestionId;
3486   OpCode.Question.Flags         = QuestionFlags;
3487   OpCode.FormId                 = FormId;
3488 
3489   return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_REF_OP, sizeof (OpCode));
3490 }
3491 
3492 /**
3493   Create EFI_IFR_REF_OP, EFI_IFR_REF2_OP, EFI_IFR_REF3_OP and EFI_IFR_REF4_OP opcode.
3494 
3495   When RefDevicePath is not zero, EFI_IFR_REF4 opcode will be created.
3496   When RefDevicePath is zero and RefFormSetId is not NULL, EFI_IFR_REF3 opcode will be created.
3497   When RefDevicePath is zero, RefFormSetId is NULL and RefQuestionId is not zero, EFI_IFR_REF2 opcode will be created.
3498   When RefDevicePath is zero, RefFormSetId is NULL and RefQuestionId is zero, EFI_IFR_REF opcode will be created.
3499 
3500   If OpCodeHandle is NULL, then ASSERT().
3501   If any reserved bits are set in QuestionFlags, then ASSERT().
3502 
3503   @param[in]  OpCodeHandle   The handle to the buffer of opcodes.
3504   @param[in]  RefFormId      The Destination Form ID.
3505   @param[in]  Prompt         The string ID for Prompt.
3506   @param[in]  Help           The string ID for Help.
3507   @param[in]  QuestionFlags  The flags in Question Header
3508   @param[in]  QuestionId     Question ID.
3509   @param[in]  RefQuestionId  The question on the form to which this link is referring.
3510                              If its value is zero, then the link refers to the top of the form.
3511   @param[in]  RefFormSetId   The form set to which this link is referring. If its value is NULL, and RefDevicePath is
3512                              zero, then the link is to the current form set.
3513   @param[in]  RefDevicePath  The string identifier that specifies the string containing the text representation of
3514                              the device path to which the form set containing the form specified by FormId.
3515                              If its value is zero, then the link refers to the current page.
3516 
3517   @retval NULL   There is not enough space left in Buffer to add the opcode.
3518   @retval Other  A pointer to the created opcode.
3519 
3520 **/
3521 UINT8 *
3522 EFIAPI
HiiCreateGotoExOpCode(IN VOID * OpCodeHandle,IN EFI_FORM_ID RefFormId,IN EFI_STRING_ID Prompt,IN EFI_STRING_ID Help,IN UINT8 QuestionFlags,IN EFI_QUESTION_ID QuestionId,IN EFI_QUESTION_ID RefQuestionId,IN EFI_GUID * RefFormSetId,OPTIONAL IN EFI_STRING_ID RefDevicePath)3523 HiiCreateGotoExOpCode (
3524   IN VOID             *OpCodeHandle,
3525   IN EFI_FORM_ID      RefFormId,
3526   IN EFI_STRING_ID    Prompt,
3527   IN EFI_STRING_ID    Help,
3528   IN UINT8            QuestionFlags,
3529   IN EFI_QUESTION_ID  QuestionId,
3530   IN EFI_QUESTION_ID  RefQuestionId,
3531   IN EFI_GUID         *RefFormSetId,    OPTIONAL
3532   IN EFI_STRING_ID    RefDevicePath
3533   )
3534 {
3535   EFI_IFR_REF4  OpCode;
3536   UINTN         OpCodeSize;
3537 
3538   ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED))) == 0);
3539 
3540   ZeroMem (&OpCode, sizeof (OpCode));
3541   OpCode.Question.Header.Prompt = Prompt;
3542   OpCode.Question.Header.Help   = Help;
3543   OpCode.Question.QuestionId    = QuestionId;
3544   OpCode.Question.Flags         = QuestionFlags;
3545   OpCode.FormId                 = RefFormId;
3546   OpCode.QuestionId             = RefQuestionId;
3547   OpCode.DevicePath             = RefDevicePath;
3548   if (RefFormSetId != NULL) {
3549     CopyMem (&OpCode.FormSetId, RefFormSetId, sizeof (OpCode.FormSetId));
3550   }
3551 
3552   //
3553   // Cacluate OpCodeSize based on the input Ref value.
3554   // Try to use the small OpCode to save size.
3555   //
3556   OpCodeSize = sizeof (EFI_IFR_REF);
3557   if (RefDevicePath != 0) {
3558     OpCodeSize = sizeof (EFI_IFR_REF4);
3559   } else if (RefFormSetId != NULL) {
3560     OpCodeSize = sizeof (EFI_IFR_REF3);
3561   } else if (RefQuestionId != 0) {
3562     OpCodeSize = sizeof (EFI_IFR_REF2);
3563   }
3564 
3565   return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_REF_OP, OpCodeSize);
3566 }
3567 
3568 /**
3569   Create EFI_IFR_CHECKBOX_OP opcode.
3570 
3571   If OpCodeHandle is NULL, then ASSERT().
3572   If any reserved bits are set in QuestionFlags, then ASSERT().
3573   If any reserved bits are set in CheckBoxFlags, then ASSERT().
3574 
3575   @param[in]  OpCodeHandle          Handle to the buffer of opcodes.
3576   @param[in]  QuestionId            Question ID
3577   @param[in]  VarStoreId            Storage ID
3578   @param[in]  VarOffset             Offset in Storage or String ID of the name (VarName)
3579                                     for this name/value pair.
3580   @param[in]  Prompt                String ID for Prompt
3581   @param[in]  Help                  String ID for Help
3582   @param[in]  QuestionFlags         Flags in Question Header
3583   @param[in]  CheckBoxFlags         Flags for checkbox opcode
3584   @param[in]  DefaultsOpCodeHandle  Handle for a buffer of DEFAULT opcodes.  This
3585                                     is an optional parameter that may be NULL.
3586 
3587   @retval NULL   There is not enough space left in Buffer to add the opcode.
3588   @retval Other  A pointer to the created opcode.
3589 
3590 **/
3591 UINT8 *
3592 EFIAPI
HiiCreateCheckBoxOpCode(IN VOID * OpCodeHandle,IN EFI_QUESTION_ID QuestionId,IN EFI_VARSTORE_ID VarStoreId,IN UINT16 VarOffset,IN EFI_STRING_ID Prompt,IN EFI_STRING_ID Help,IN UINT8 QuestionFlags,IN UINT8 CheckBoxFlags,IN VOID * DefaultsOpCodeHandle OPTIONAL)3593 HiiCreateCheckBoxOpCode (
3594   IN VOID             *OpCodeHandle,
3595   IN EFI_QUESTION_ID  QuestionId,
3596   IN EFI_VARSTORE_ID  VarStoreId,
3597   IN UINT16           VarOffset,
3598   IN EFI_STRING_ID    Prompt,
3599   IN EFI_STRING_ID    Help,
3600   IN UINT8            QuestionFlags,
3601   IN UINT8            CheckBoxFlags,
3602   IN VOID             *DefaultsOpCodeHandle  OPTIONAL
3603   )
3604 {
3605   EFI_IFR_CHECKBOX  OpCode;
3606   UINTN             Position;
3607 
3608   ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED))) == 0);
3609 
3610   ZeroMem (&OpCode, sizeof (OpCode));
3611   OpCode.Question.QuestionId             = QuestionId;
3612   OpCode.Question.VarStoreId             = VarStoreId;
3613   OpCode.Question.VarStoreInfo.VarOffset = VarOffset;
3614   OpCode.Question.Header.Prompt          = Prompt;
3615   OpCode.Question.Header.Help            = Help;
3616   OpCode.Question.Flags                  = QuestionFlags;
3617   OpCode.Flags                           = CheckBoxFlags;
3618 
3619   if (DefaultsOpCodeHandle == NULL) {
3620     return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_CHECKBOX_OP, sizeof (OpCode));
3621   }
3622 
3623   Position = InternalHiiOpCodeHandlePosition (OpCodeHandle);
3624   InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_CHECKBOX_OP, sizeof (OpCode), 0, 1);
3625   InternalHiiAppendOpCodes (OpCodeHandle, DefaultsOpCodeHandle);
3626   HiiCreateEndOpCode (OpCodeHandle);
3627   return InternalHiiOpCodeHandleBuffer (OpCodeHandle) + Position;
3628 }
3629 
3630 /**
3631   Create EFI_IFR_NUMERIC_OP opcode.
3632 
3633   If OpCodeHandle is NULL, then ASSERT().
3634   If any reserved bits are set in QuestionFlags, then ASSERT().
3635   If any reserved bits are set in NumericFlags, then ASSERT().
3636 
3637   @param[in]  OpCodeHandle          Handle to the buffer of opcodes.
3638   @param[in]  QuestionId            Question ID
3639   @param[in]  VarStoreId            Storage ID
3640   @param[in]  VarOffset             Offset in Storage or String ID of the name (VarName)
3641                                     for this name/value pair.
3642   @param[in]  Prompt                String ID for Prompt
3643   @param[in]  Help                  String ID for Help
3644   @param[in]  QuestionFlags         Flags in Question Header
3645   @param[in]  NumericFlags          Flags for numeric opcode
3646   @param[in]  Minimum               Numeric minimum value
3647   @param[in]  Maximum               Numeric maximum value
3648   @param[in]  Step                  Numeric step for edit
3649   @param[in]  DefaultsOpCodeHandle  Handle for a buffer of DEFAULT opcodes.  This
3650                                     is an optional parameter that may be NULL.
3651 
3652   @retval NULL   There is not enough space left in Buffer to add the opcode.
3653   @retval Other  A pointer to the created opcode.
3654 
3655 **/
3656 UINT8 *
3657 EFIAPI
HiiCreateNumericOpCode(IN VOID * OpCodeHandle,IN EFI_QUESTION_ID QuestionId,IN EFI_VARSTORE_ID VarStoreId,IN UINT16 VarOffset,IN EFI_STRING_ID Prompt,IN EFI_STRING_ID Help,IN UINT8 QuestionFlags,IN UINT8 NumericFlags,IN UINT64 Minimum,IN UINT64 Maximum,IN UINT64 Step,IN VOID * DefaultsOpCodeHandle OPTIONAL)3658 HiiCreateNumericOpCode (
3659   IN VOID             *OpCodeHandle,
3660   IN EFI_QUESTION_ID  QuestionId,
3661   IN EFI_VARSTORE_ID  VarStoreId,
3662   IN UINT16           VarOffset,
3663   IN EFI_STRING_ID    Prompt,
3664   IN EFI_STRING_ID    Help,
3665   IN UINT8            QuestionFlags,
3666   IN UINT8            NumericFlags,
3667   IN UINT64           Minimum,
3668   IN UINT64           Maximum,
3669   IN UINT64           Step,
3670   IN VOID             *DefaultsOpCodeHandle  OPTIONAL
3671   )
3672 {
3673   EFI_IFR_NUMERIC  OpCode;
3674   UINTN            Position;
3675   UINTN            Length;
3676 
3677   ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED))) == 0);
3678 
3679   Length  = 0;
3680   ZeroMem (&OpCode, sizeof (OpCode));
3681   OpCode.Question.QuestionId             = QuestionId;
3682   OpCode.Question.VarStoreId             = VarStoreId;
3683   OpCode.Question.VarStoreInfo.VarOffset = VarOffset;
3684   OpCode.Question.Header.Prompt          = Prompt;
3685   OpCode.Question.Header.Help            = Help;
3686   OpCode.Question.Flags                  = QuestionFlags;
3687   OpCode.Flags                           = NumericFlags;
3688 
3689   switch (NumericFlags & EFI_IFR_NUMERIC_SIZE) {
3690   case EFI_IFR_NUMERIC_SIZE_1:
3691     OpCode.data.u8.MinValue = (UINT8)Minimum;
3692     OpCode.data.u8.MaxValue = (UINT8)Maximum;
3693     OpCode.data.u8.Step     = (UINT8)Step;
3694     Length                  = 3;
3695     break;
3696 
3697   case EFI_IFR_NUMERIC_SIZE_2:
3698     OpCode.data.u16.MinValue = (UINT16)Minimum;
3699     OpCode.data.u16.MaxValue = (UINT16)Maximum;
3700     OpCode.data.u16.Step     = (UINT16)Step;
3701     Length                   = 6;
3702     break;
3703 
3704   case EFI_IFR_NUMERIC_SIZE_4:
3705     OpCode.data.u32.MinValue = (UINT32)Minimum;
3706     OpCode.data.u32.MaxValue = (UINT32)Maximum;
3707     OpCode.data.u32.Step     = (UINT32)Step;
3708     Length                   = 12;
3709     break;
3710 
3711   case EFI_IFR_NUMERIC_SIZE_8:
3712     OpCode.data.u64.MinValue = Minimum;
3713     OpCode.data.u64.MaxValue = Maximum;
3714     OpCode.data.u64.Step     = Step;
3715     Length                   = 24;
3716     break;
3717   }
3718 
3719   Length += OFFSET_OF (EFI_IFR_NUMERIC, data);
3720 
3721   if (DefaultsOpCodeHandle == NULL) {
3722     return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_NUMERIC_OP, Length);
3723   }
3724 
3725   Position = InternalHiiOpCodeHandlePosition (OpCodeHandle);
3726   InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_NUMERIC_OP, Length, 0, 1);
3727   InternalHiiAppendOpCodes (OpCodeHandle, DefaultsOpCodeHandle);
3728   HiiCreateEndOpCode (OpCodeHandle);
3729   return InternalHiiOpCodeHandleBuffer (OpCodeHandle) + Position;
3730 }
3731 
3732 /**
3733   Create EFI_IFR_STRING_OP opcode.
3734 
3735   If OpCodeHandle is NULL, then ASSERT().
3736   If any reserved bits are set in QuestionFlags, then ASSERT().
3737   If any reserved bits are set in StringFlags, then ASSERT().
3738 
3739   @param[in]  OpCodeHandle          Handle to the buffer of opcodes.
3740   @param[in]  QuestionId            Question ID
3741   @param[in]  VarStoreId            Storage ID
3742   @param[in]  VarOffset             Offset in Storage or String ID of the name (VarName)
3743                                     for this name/value pair.
3744   @param[in]  Prompt                String ID for Prompt
3745   @param[in]  Help                  String ID for Help
3746   @param[in]  QuestionFlags         Flags in Question Header
3747   @param[in]  StringFlags           Flags for string opcode
3748   @param[in]  MinSize               String minimum length
3749   @param[in]  MaxSize               String maximum length
3750   @param[in]  DefaultsOpCodeHandle  Handle for a buffer of DEFAULT opcodes.  This
3751                                     is an optional parameter that may be NULL.
3752 
3753   @retval NULL   There is not enough space left in Buffer to add the opcode.
3754   @retval Other  A pointer to the created opcode.
3755 
3756 **/
3757 UINT8 *
3758 EFIAPI
HiiCreateStringOpCode(IN VOID * OpCodeHandle,IN EFI_QUESTION_ID QuestionId,IN EFI_VARSTORE_ID VarStoreId,IN UINT16 VarOffset,IN EFI_STRING_ID Prompt,IN EFI_STRING_ID Help,IN UINT8 QuestionFlags,IN UINT8 StringFlags,IN UINT8 MinSize,IN UINT8 MaxSize,IN VOID * DefaultsOpCodeHandle OPTIONAL)3759 HiiCreateStringOpCode (
3760   IN VOID             *OpCodeHandle,
3761   IN EFI_QUESTION_ID  QuestionId,
3762   IN EFI_VARSTORE_ID  VarStoreId,
3763   IN UINT16           VarOffset,
3764   IN EFI_STRING_ID    Prompt,
3765   IN EFI_STRING_ID    Help,
3766   IN UINT8            QuestionFlags,
3767   IN UINT8            StringFlags,
3768   IN UINT8            MinSize,
3769   IN UINT8            MaxSize,
3770   IN VOID             *DefaultsOpCodeHandle  OPTIONAL
3771   )
3772 {
3773   EFI_IFR_STRING  OpCode;
3774   UINTN           Position;
3775 
3776   ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED))) == 0);
3777 
3778   ZeroMem (&OpCode, sizeof (OpCode));
3779   OpCode.Question.Header.Prompt          = Prompt;
3780   OpCode.Question.Header.Help            = Help;
3781   OpCode.Question.QuestionId             = QuestionId;
3782   OpCode.Question.VarStoreId             = VarStoreId;
3783   OpCode.Question.VarStoreInfo.VarOffset = VarOffset;
3784   OpCode.Question.Flags                  = QuestionFlags;
3785   OpCode.MinSize                         = MinSize;
3786   OpCode.MaxSize                         = MaxSize;
3787   OpCode.Flags                           = (UINT8) (StringFlags & EFI_IFR_STRING_MULTI_LINE);
3788 
3789   if (DefaultsOpCodeHandle == NULL) {
3790     return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_STRING_OP, sizeof (OpCode));
3791   }
3792 
3793   Position = InternalHiiOpCodeHandlePosition (OpCodeHandle);
3794   InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_STRING_OP, sizeof (OpCode), 0, 1);
3795   InternalHiiAppendOpCodes (OpCodeHandle, DefaultsOpCodeHandle);
3796   HiiCreateEndOpCode (OpCodeHandle);
3797   return InternalHiiOpCodeHandleBuffer (OpCodeHandle) + Position;
3798 }
3799 
3800 /**
3801   Create EFI_IFR_ONE_OF_OP opcode.
3802 
3803   If OpCodeHandle is NULL, then ASSERT().
3804   If any reserved bits are set in QuestionFlags, then ASSERT().
3805   If any reserved bits are set in OneOfFlags, then ASSERT().
3806 
3807   @param[in]  OpCodeHandle          Handle to the buffer of opcodes.
3808   @param[in]  QuestionId            Question ID
3809   @param[in]  VarStoreId            Storage ID
3810   @param[in]  VarOffset             Offset in Storage or String ID of the name (VarName)
3811                                     for this name/value pair.
3812   @param[in]  Prompt                String ID for Prompt
3813   @param[in]  Help                  String ID for Help
3814   @param[in]  QuestionFlags         Flags in Question Header
3815   @param[in]  OneOfFlags            Flags for oneof opcode
3816   @param[in]  OptionsOpCodeHandle   Handle for a buffer of ONE_OF_OPTION opcodes.
3817   @param[in]  DefaultsOpCodeHandle  Handle for a buffer of DEFAULT opcodes.  This
3818                                     is an optional parameter that may be NULL.
3819 
3820   @retval NULL   There is not enough space left in Buffer to add the opcode.
3821   @retval Other  A pointer to the created opcode.
3822 
3823 **/
3824 UINT8 *
3825 EFIAPI
HiiCreateOneOfOpCode(IN VOID * OpCodeHandle,IN EFI_QUESTION_ID QuestionId,IN EFI_VARSTORE_ID VarStoreId,IN UINT16 VarOffset,IN EFI_STRING_ID Prompt,IN EFI_STRING_ID Help,IN UINT8 QuestionFlags,IN UINT8 OneOfFlags,IN VOID * OptionsOpCodeHandle,IN VOID * DefaultsOpCodeHandle OPTIONAL)3826 HiiCreateOneOfOpCode (
3827   IN VOID             *OpCodeHandle,
3828   IN EFI_QUESTION_ID  QuestionId,
3829   IN EFI_VARSTORE_ID  VarStoreId,
3830   IN UINT16           VarOffset,
3831   IN EFI_STRING_ID    Prompt,
3832   IN EFI_STRING_ID    Help,
3833   IN UINT8            QuestionFlags,
3834   IN UINT8            OneOfFlags,
3835   IN VOID             *OptionsOpCodeHandle,
3836   IN VOID             *DefaultsOpCodeHandle  OPTIONAL
3837   )
3838 {
3839   EFI_IFR_ONE_OF  OpCode;
3840   UINTN           Position;
3841   UINTN           Length;
3842 
3843   ASSERT (OptionsOpCodeHandle != NULL);
3844   ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED | EFI_IFR_FLAG_OPTIONS_ONLY))) == 0);
3845 
3846   ZeroMem (&OpCode, sizeof (OpCode));
3847   OpCode.Question.Header.Prompt          = Prompt;
3848   OpCode.Question.Header.Help            = Help;
3849   OpCode.Question.QuestionId             = QuestionId;
3850   OpCode.Question.VarStoreId             = VarStoreId;
3851   OpCode.Question.VarStoreInfo.VarOffset = VarOffset;
3852   OpCode.Question.Flags                  = QuestionFlags;
3853   OpCode.Flags                           = OneOfFlags;
3854 
3855   Length  = OFFSET_OF (EFI_IFR_ONE_OF, data);
3856   Length += (1 << (OneOfFlags & EFI_IFR_NUMERIC_SIZE)) * 3;
3857 
3858   Position = InternalHiiOpCodeHandlePosition (OpCodeHandle);
3859   InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_ONE_OF_OP, Length, 0, 1);
3860   InternalHiiAppendOpCodes (OpCodeHandle, OptionsOpCodeHandle);
3861   if (DefaultsOpCodeHandle != NULL) {
3862     InternalHiiAppendOpCodes (OpCodeHandle, DefaultsOpCodeHandle);
3863   }
3864   HiiCreateEndOpCode (OpCodeHandle);
3865   return InternalHiiOpCodeHandleBuffer (OpCodeHandle) + Position;
3866 }
3867 
3868 /**
3869   Create EFI_IFR_ORDERED_LIST_OP opcode.
3870 
3871   If OpCodeHandle is NULL, then ASSERT().
3872   If any reserved bits are set in QuestionFlags, then ASSERT().
3873   If any reserved bits are set in OrderedListFlags, then ASSERT().
3874 
3875   @param[in]  OpCodeHandle          Handle to the buffer of opcodes.
3876   @param[in]  QuestionId            Question ID
3877   @param[in]  VarStoreId            Storage ID
3878   @param[in]  VarOffset             Offset in Storage or String ID of the name (VarName)
3879                                     for this name/value pair.
3880   @param[in]  Prompt                String ID for Prompt
3881   @param[in]  Help                  String ID for Help
3882   @param[in]  QuestionFlags         Flags in Question Header
3883   @param[in]  OrderedListFlags      Flags for ordered list opcode
3884   @param[in]  DataType              Type for option value
3885   @param[in]  MaxContainers         Maximum count for options in this ordered list
3886   @param[in]  OptionsOpCodeHandle   Handle for a buffer of ONE_OF_OPTION opcodes.
3887   @param[in]  DefaultsOpCodeHandle  Handle for a buffer of DEFAULT opcodes.  This
3888                                     is an optional parameter that may be NULL.
3889 
3890   @retval NULL   There is not enough space left in Buffer to add the opcode.
3891   @retval Other  A pointer to the created opcode.
3892 
3893 **/
3894 UINT8 *
3895 EFIAPI
HiiCreateOrderedListOpCode(IN VOID * OpCodeHandle,IN EFI_QUESTION_ID QuestionId,IN EFI_VARSTORE_ID VarStoreId,IN UINT16 VarOffset,IN EFI_STRING_ID Prompt,IN EFI_STRING_ID Help,IN UINT8 QuestionFlags,IN UINT8 OrderedListFlags,IN UINT8 DataType,IN UINT8 MaxContainers,IN VOID * OptionsOpCodeHandle,IN VOID * DefaultsOpCodeHandle OPTIONAL)3896 HiiCreateOrderedListOpCode (
3897   IN VOID             *OpCodeHandle,
3898   IN EFI_QUESTION_ID  QuestionId,
3899   IN EFI_VARSTORE_ID  VarStoreId,
3900   IN UINT16           VarOffset,
3901   IN EFI_STRING_ID    Prompt,
3902   IN EFI_STRING_ID    Help,
3903   IN UINT8            QuestionFlags,
3904   IN UINT8            OrderedListFlags,
3905   IN UINT8            DataType,
3906   IN UINT8            MaxContainers,
3907   IN VOID             *OptionsOpCodeHandle,
3908   IN VOID             *DefaultsOpCodeHandle  OPTIONAL
3909   )
3910 {
3911   EFI_IFR_ORDERED_LIST  OpCode;
3912   UINTN                 Position;
3913 
3914   ASSERT (OptionsOpCodeHandle != NULL);
3915   ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED | EFI_IFR_FLAG_OPTIONS_ONLY))) == 0);
3916 
3917   ZeroMem (&OpCode, sizeof (OpCode));
3918   OpCode.Question.Header.Prompt          = Prompt;
3919   OpCode.Question.Header.Help            = Help;
3920   OpCode.Question.QuestionId             = QuestionId;
3921   OpCode.Question.VarStoreId             = VarStoreId;
3922   OpCode.Question.VarStoreInfo.VarOffset = VarOffset;
3923   OpCode.Question.Flags                  = QuestionFlags;
3924   OpCode.MaxContainers                   = MaxContainers;
3925   OpCode.Flags                           = OrderedListFlags;
3926 
3927   Position = InternalHiiOpCodeHandlePosition (OpCodeHandle);
3928   InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_ORDERED_LIST_OP, sizeof (OpCode), 0, 1);
3929   InternalHiiAppendOpCodes (OpCodeHandle, OptionsOpCodeHandle);
3930   if (DefaultsOpCodeHandle != NULL) {
3931     InternalHiiAppendOpCodes (OpCodeHandle, DefaultsOpCodeHandle);
3932   }
3933   HiiCreateEndOpCode (OpCodeHandle);
3934   return InternalHiiOpCodeHandleBuffer (OpCodeHandle) + Position;
3935 }
3936 
3937 /**
3938   Create EFI_IFR_TEXT_OP opcode.
3939 
3940   If OpCodeHandle is NULL, then ASSERT().
3941 
3942   @param[in]  OpCodeHandle  Handle to the buffer of opcodes.
3943   @param[in]  Prompt        String ID for Prompt.
3944   @param[in]  Help          String ID for Help.
3945   @param[in]  TextTwo       String ID for TextTwo.
3946 
3947   @retval NULL   There is not enough space left in Buffer to add the opcode.
3948   @retval Other  A pointer to the created opcode.
3949 
3950 **/
3951 UINT8 *
3952 EFIAPI
HiiCreateTextOpCode(IN VOID * OpCodeHandle,IN EFI_STRING_ID Prompt,IN EFI_STRING_ID Help,IN EFI_STRING_ID TextTwo)3953 HiiCreateTextOpCode (
3954   IN VOID           *OpCodeHandle,
3955   IN EFI_STRING_ID  Prompt,
3956   IN EFI_STRING_ID  Help,
3957   IN EFI_STRING_ID  TextTwo
3958   )
3959 {
3960   EFI_IFR_TEXT  OpCode;
3961 
3962   ZeroMem (&OpCode, sizeof (OpCode));
3963   OpCode.Statement.Prompt = Prompt;
3964   OpCode.Statement.Help   = Help;
3965   OpCode.TextTwo          = TextTwo;
3966 
3967   return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_TEXT_OP, sizeof (OpCode));
3968 }
3969 
3970 /**
3971   Create EFI_IFR_DATE_OP opcode.
3972 
3973   If OpCodeHandle is NULL, then ASSERT().
3974   If any reserved bits are set in QuestionFlags, then ASSERT().
3975   If any reserved bits are set in DateFlags, then ASSERT().
3976 
3977   @param[in]  OpCodeHandle          Handle to the buffer of opcodes.
3978   @param[in]  QuestionId            Question ID
3979   @param[in]  VarStoreId            Storage ID, optional. If DateFlags is not
3980                                     QF_DATE_STORAGE_NORMAL, this parameter is ignored.
3981   @param[in]  VarOffset             Offset in Storage or String ID of the name (VarName)
3982                                     for this name/value pair, optional. If DateFlags is not
3983                                     QF_DATE_STORAGE_NORMAL, this parameter is ignored.
3984   @param[in]  Prompt                String ID for Prompt
3985   @param[in]  Help                  String ID for Help
3986   @param[in]  QuestionFlags         Flags in Question Header
3987   @param[in]  DateFlags             Flags for date opcode
3988   @param[in]  DefaultsOpCodeHandle  Handle for a buffer of DEFAULT opcodes.  This
3989                                     is an optional parameter that may be NULL.
3990 
3991   @retval NULL   There is not enough space left in Buffer to add the opcode.
3992   @retval Other  A pointer to the created opcode.
3993 
3994 **/
3995 UINT8 *
3996 EFIAPI
HiiCreateDateOpCode(IN VOID * OpCodeHandle,IN EFI_QUESTION_ID QuestionId,IN EFI_VARSTORE_ID VarStoreId,OPTIONAL IN UINT16 VarOffset,OPTIONAL IN EFI_STRING_ID Prompt,IN EFI_STRING_ID Help,IN UINT8 QuestionFlags,IN UINT8 DateFlags,IN VOID * DefaultsOpCodeHandle OPTIONAL)3997 HiiCreateDateOpCode (
3998   IN VOID             *OpCodeHandle,
3999   IN EFI_QUESTION_ID  QuestionId,
4000   IN EFI_VARSTORE_ID  VarStoreId,   OPTIONAL
4001   IN UINT16           VarOffset,    OPTIONAL
4002   IN EFI_STRING_ID    Prompt,
4003   IN EFI_STRING_ID    Help,
4004   IN UINT8            QuestionFlags,
4005   IN UINT8            DateFlags,
4006   IN VOID             *DefaultsOpCodeHandle  OPTIONAL
4007   )
4008 {
4009   EFI_IFR_DATE    OpCode;
4010   UINTN           Position;
4011 
4012   ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED))) == 0);
4013   ASSERT ((DateFlags & (~(EFI_QF_DATE_YEAR_SUPPRESS | EFI_QF_DATE_MONTH_SUPPRESS | EFI_QF_DATE_DAY_SUPPRESS | EFI_QF_DATE_STORAGE))) == 0);
4014 
4015   ZeroMem (&OpCode, sizeof (OpCode));
4016   OpCode.Question.Header.Prompt          = Prompt;
4017   OpCode.Question.Header.Help            = Help;
4018   OpCode.Question.QuestionId             = QuestionId;
4019   OpCode.Question.VarStoreId             = VarStoreId;
4020   OpCode.Question.VarStoreInfo.VarOffset = VarOffset;
4021   OpCode.Question.Flags                  = QuestionFlags;
4022   OpCode.Flags                           = DateFlags;
4023 
4024   if (DefaultsOpCodeHandle == NULL) {
4025     return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_DATE_OP, sizeof (OpCode));
4026   }
4027 
4028   Position = InternalHiiOpCodeHandlePosition (OpCodeHandle);
4029   InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_DATE_OP, sizeof (OpCode), 0, 1);
4030   InternalHiiAppendOpCodes (OpCodeHandle, DefaultsOpCodeHandle);
4031   HiiCreateEndOpCode (OpCodeHandle);
4032   return InternalHiiOpCodeHandleBuffer (OpCodeHandle) + Position;
4033 }
4034 
4035 /**
4036   Create EFI_IFR_TIME_OP opcode.
4037 
4038   If OpCodeHandle is NULL, then ASSERT().
4039   If any reserved bits are set in QuestionFlags, then ASSERT().
4040   If any reserved bits are set in TimeFlags, then ASSERT().
4041 
4042   @param[in]  OpCodeHandle          Handle to the buffer of opcodes.
4043   @param[in]  QuestionId            Question ID
4044   @param[in]  VarStoreId            Storage ID, optional. If TimeFlags is not
4045                                     QF_TIME_STORAGE_NORMAL, this parameter is ignored.
4046   @param[in]  VarOffset             Offset in Storage or String ID of the name (VarName)
4047                                     for this name/value pair, optional. If TimeFlags is not
4048                                     QF_TIME_STORAGE_NORMAL, this parameter is ignored.
4049   @param[in]  Prompt                String ID for Prompt
4050   @param[in]  Help                  String ID for Help
4051   @param[in]  QuestionFlags         Flags in Question Header
4052   @param[in]  TimeFlags             Flags for time opcode
4053   @param[in]  DefaultsOpCodeHandle  Handle for a buffer of DEFAULT opcodes.  This
4054                                     is an optional parameter that may be NULL.
4055 
4056   @retval NULL   There is not enough space left in Buffer to add the opcode.
4057   @retval Other  A pointer to the created opcode.
4058 
4059 **/
4060 UINT8 *
4061 EFIAPI
HiiCreateTimeOpCode(IN VOID * OpCodeHandle,IN EFI_QUESTION_ID QuestionId,IN EFI_VARSTORE_ID VarStoreId,OPTIONAL IN UINT16 VarOffset,OPTIONAL IN EFI_STRING_ID Prompt,IN EFI_STRING_ID Help,IN UINT8 QuestionFlags,IN UINT8 TimeFlags,IN VOID * DefaultsOpCodeHandle OPTIONAL)4062 HiiCreateTimeOpCode (
4063   IN VOID             *OpCodeHandle,
4064   IN EFI_QUESTION_ID  QuestionId,
4065   IN EFI_VARSTORE_ID  VarStoreId,   OPTIONAL
4066   IN UINT16           VarOffset,    OPTIONAL
4067   IN EFI_STRING_ID    Prompt,
4068   IN EFI_STRING_ID    Help,
4069   IN UINT8            QuestionFlags,
4070   IN UINT8            TimeFlags,
4071   IN VOID             *DefaultsOpCodeHandle  OPTIONAL
4072   )
4073 {
4074   EFI_IFR_TIME    OpCode;
4075   UINTN           Position;
4076 
4077   ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED))) == 0);
4078   ASSERT ((TimeFlags & (~(QF_TIME_HOUR_SUPPRESS | QF_TIME_MINUTE_SUPPRESS | QF_TIME_SECOND_SUPPRESS | QF_TIME_STORAGE))) == 0);
4079 
4080   ZeroMem (&OpCode, sizeof (OpCode));
4081   OpCode.Question.Header.Prompt          = Prompt;
4082   OpCode.Question.Header.Help            = Help;
4083   OpCode.Question.QuestionId             = QuestionId;
4084   OpCode.Question.VarStoreId             = VarStoreId;
4085   OpCode.Question.VarStoreInfo.VarOffset = VarOffset;
4086   OpCode.Question.Flags                  = QuestionFlags;
4087   OpCode.Flags                           = TimeFlags;
4088 
4089   if (DefaultsOpCodeHandle == NULL) {
4090     return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_TIME_OP, sizeof (OpCode));
4091   }
4092 
4093   Position = InternalHiiOpCodeHandlePosition (OpCodeHandle);
4094   InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_TIME_OP, sizeof (OpCode), 0, 1);
4095   InternalHiiAppendOpCodes (OpCodeHandle, DefaultsOpCodeHandle);
4096   HiiCreateEndOpCode (OpCodeHandle);
4097   return InternalHiiOpCodeHandleBuffer (OpCodeHandle) + Position;
4098 }
4099 
4100 /**
4101   This is the internal worker function to update the data in
4102   a form specified by FormSetGuid, FormId and Label.
4103 
4104   @param[in] FormSetGuid       The optional Formset GUID.
4105   @param[in] FormId            The Form ID.
4106   @param[in] Package           The package header.
4107   @param[in] OpCodeBufferStart An OpCode buffer that contains the set of IFR
4108                                opcodes to be inserted or replaced in the form.
4109   @param[in] OpCodeBufferEnd   An OpCcode buffer that contains the IFR opcode
4110                                that marks the end of a replace operation in the form.
4111   @param[out] TempPackage      The resultant package.
4112 
4113   @retval EFI_SUCCESS    The function completes successfully.
4114   @retval EFI_NOT_FOUND  The updated opcode or endopcode is not found.
4115 
4116 **/
4117 EFI_STATUS
4118 EFIAPI
InternalHiiUpdateFormPackageData(IN EFI_GUID * FormSetGuid,OPTIONAL IN EFI_FORM_ID FormId,IN EFI_HII_PACKAGE_HEADER * Package,IN HII_LIB_OPCODE_BUFFER * OpCodeBufferStart,IN HII_LIB_OPCODE_BUFFER * OpCodeBufferEnd,OPTIONAL OUT EFI_HII_PACKAGE_HEADER * TempPackage)4119 InternalHiiUpdateFormPackageData (
4120   IN  EFI_GUID               *FormSetGuid, OPTIONAL
4121   IN  EFI_FORM_ID            FormId,
4122   IN  EFI_HII_PACKAGE_HEADER *Package,
4123   IN  HII_LIB_OPCODE_BUFFER  *OpCodeBufferStart,
4124   IN  HII_LIB_OPCODE_BUFFER  *OpCodeBufferEnd,    OPTIONAL
4125   OUT EFI_HII_PACKAGE_HEADER *TempPackage
4126   )
4127 {
4128   UINTN                     AddSize;
4129   UINT8                     *BufferPos;
4130   EFI_HII_PACKAGE_HEADER    PackageHeader;
4131   UINTN                     Offset;
4132   EFI_IFR_OP_HEADER         *IfrOpHdr;
4133   EFI_IFR_OP_HEADER         *UpdateIfrOpHdr;
4134   BOOLEAN                   GetFormSet;
4135   BOOLEAN                   GetForm;
4136   BOOLEAN                   Updated;
4137   UINTN                     UpdatePackageLength;
4138 
4139   CopyMem (TempPackage, Package, sizeof (EFI_HII_PACKAGE_HEADER));
4140   UpdatePackageLength = sizeof (EFI_HII_PACKAGE_HEADER);
4141   BufferPos           = (UINT8 *) (TempPackage + 1);
4142 
4143   CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
4144   IfrOpHdr   = (EFI_IFR_OP_HEADER *)((UINT8 *) Package + sizeof (EFI_HII_PACKAGE_HEADER));
4145   Offset     = sizeof (EFI_HII_PACKAGE_HEADER);
4146   GetFormSet = (BOOLEAN) ((FormSetGuid == NULL) ? TRUE : FALSE);
4147   GetForm    = FALSE;
4148   Updated    = FALSE;
4149 
4150   while (Offset < PackageHeader.Length) {
4151     CopyMem (BufferPos, IfrOpHdr, IfrOpHdr->Length);
4152     BufferPos           += IfrOpHdr->Length;
4153     UpdatePackageLength += IfrOpHdr->Length;
4154 
4155     //
4156     // Find the matched FormSet and Form
4157     //
4158     if ((IfrOpHdr->OpCode == EFI_IFR_FORM_SET_OP) && (FormSetGuid != NULL)) {
4159       if (CompareGuid((GUID *)(VOID *)&((EFI_IFR_FORM_SET *) IfrOpHdr)->Guid, FormSetGuid)) {
4160         GetFormSet = TRUE;
4161       } else {
4162         GetFormSet = FALSE;
4163       }
4164     } else if (IfrOpHdr->OpCode == EFI_IFR_FORM_OP || IfrOpHdr->OpCode == EFI_IFR_FORM_MAP_OP) {
4165       if (CompareMem (&((EFI_IFR_FORM *) IfrOpHdr)->FormId, &FormId, sizeof (EFI_FORM_ID)) == 0) {
4166         GetForm = TRUE;
4167       } else {
4168         GetForm = FALSE;
4169       }
4170     }
4171 
4172     //
4173     // The matched Form is found, and Update data in this form
4174     //
4175     if (GetFormSet && GetForm) {
4176       UpdateIfrOpHdr = (EFI_IFR_OP_HEADER *) OpCodeBufferStart->Buffer;
4177       if ((UpdateIfrOpHdr->Length == IfrOpHdr->Length) && \
4178           (CompareMem (IfrOpHdr, UpdateIfrOpHdr, UpdateIfrOpHdr->Length) == 0)) {
4179         //
4180         // Remove the original data when End OpCode buffer exist.
4181         //
4182         if (OpCodeBufferEnd != NULL) {
4183           Offset        += IfrOpHdr->Length;
4184           IfrOpHdr       = (EFI_IFR_OP_HEADER *) ((UINT8 *) (IfrOpHdr) + IfrOpHdr->Length);
4185           UpdateIfrOpHdr = (EFI_IFR_OP_HEADER *) OpCodeBufferEnd->Buffer;
4186           while (Offset < PackageHeader.Length) {
4187             //
4188             // Search the matched end opcode
4189             //
4190             if ((UpdateIfrOpHdr->Length == IfrOpHdr->Length) && \
4191                 (CompareMem (IfrOpHdr, UpdateIfrOpHdr, UpdateIfrOpHdr->Length) == 0)) {
4192               break;
4193             }
4194             //
4195             // Go to the next Op-Code
4196             //
4197             Offset        += IfrOpHdr->Length;
4198             IfrOpHdr       = (EFI_IFR_OP_HEADER *) ((UINT8 *) (IfrOpHdr) + IfrOpHdr->Length);
4199           }
4200 
4201           if (Offset >= PackageHeader.Length) {
4202             //
4203             // The end opcode is not found.
4204             //
4205             return EFI_NOT_FOUND;
4206           }
4207         }
4208 
4209         //
4210         // Insert the updated data
4211         //
4212         AddSize = ((EFI_IFR_OP_HEADER *) OpCodeBufferStart->Buffer)->Length;
4213         CopyMem (BufferPos, OpCodeBufferStart->Buffer + AddSize, OpCodeBufferStart->Position - AddSize);
4214         BufferPos           += OpCodeBufferStart->Position - AddSize;
4215         UpdatePackageLength += OpCodeBufferStart->Position - AddSize;
4216 
4217         if (OpCodeBufferEnd != NULL) {
4218           //
4219           // Add the end opcode
4220           //
4221           CopyMem (BufferPos, IfrOpHdr, IfrOpHdr->Length);
4222           BufferPos           += IfrOpHdr->Length;
4223           UpdatePackageLength += IfrOpHdr->Length;
4224         }
4225 
4226         //
4227         // Copy the left package data.
4228         //
4229         Offset += IfrOpHdr->Length;
4230         CopyMem (BufferPos, (UINT8 *) Package + Offset, PackageHeader.Length - Offset);
4231         UpdatePackageLength += PackageHeader.Length - Offset;
4232 
4233         //
4234         // Set update flag
4235         //
4236         Updated = TRUE;
4237         break;
4238       }
4239     }
4240 
4241     //
4242     // Go to the next Op-Code
4243     //
4244     Offset   += IfrOpHdr->Length;
4245     IfrOpHdr = (EFI_IFR_OP_HEADER *) ((CHAR8 *) (IfrOpHdr) + IfrOpHdr->Length);
4246   }
4247 
4248   if (!Updated) {
4249     //
4250     // The updated opcode buffer is not found.
4251     //
4252     return EFI_NOT_FOUND;
4253   }
4254   //
4255   // Update the package length.
4256   //
4257   PackageHeader.Length = (UINT32) UpdatePackageLength;
4258   CopyMem (TempPackage, &PackageHeader, sizeof (EFI_HII_PACKAGE_HEADER));
4259 
4260   return EFI_SUCCESS;
4261 }
4262 
4263 /**
4264   This function updates a form that has previously been registered with the HII
4265   Database.  This function will perform at most one update operation.
4266 
4267   The form to update is specified by Handle, FormSetGuid, and FormId.  Binary
4268   comparisons of IFR opcodes are performed from the beginning of the form being
4269   updated until an IFR opcode is found that exactly matches the first IFR opcode
4270   specified by StartOpCodeHandle.  The following rules are used to determine if
4271   an insert, replace, or delete operation is performed.
4272 
4273   1) If no matches are found, then NULL is returned.
4274   2) If a match is found, and EndOpCodeHandle is NULL, then all of the IFR opcodes
4275      from StartOpCodeHandle except the first opcode are inserted immediately after
4276      the matching IFR opcode in the form to be updated.
4277   3) If a match is found, and EndOpCodeHandle is not NULL, then a search is made
4278      from the matching IFR opcode until an IFR opcode exactly matches the first
4279      IFR opcode specified by EndOpCodeHandle.  If no match is found for the first
4280      IFR opcode specified by EndOpCodeHandle, then NULL is returned.  If a match
4281      is found, then all of the IFR opcodes between the start match and the end
4282      match are deleted from the form being updated and all of the IFR opcodes
4283      from StartOpCodeHandle except the first opcode are inserted immediately after
4284      the matching start IFR opcode.  If StartOpCcodeHandle only contains one
4285      IFR instruction, then the result of this operation will delete all of the IFR
4286      opcodes between the start end matches.
4287 
4288   If HiiHandle is NULL, then ASSERT().
4289   If StartOpCodeHandle is NULL, then ASSERT().
4290 
4291   @param[in]  HiiHandle          The HII Handle of the form to update.
4292   @param[in]  FormSetGuid        The Formset GUID of the form to update.  This
4293                                  is an optional parameter that may be NULL.
4294                                  If it is NULL, all FormSet will be updated.
4295   @param[in]  FormId             The ID of the form to update.
4296   @param[in]  StartOpCodeHandle  An OpCode Handle that contains the set of IFR
4297                                  opcodes to be inserted or replaced in the form.
4298                                  The first IFR instruction in StartOpCodeHandle
4299                                  is used to find matching IFR opcode in the
4300                                  form.
4301   @param[in]  EndOpCodeHandle    An OpCcode Handle that contains the IFR opcode
4302                                  that marks the end of a replace operation in
4303                                  the form.  This is an optional parameter that
4304                                  may be NULL.  If it is NULL, then an the IFR
4305                                  opcodes specified by StartOpCodeHandle are
4306                                  inserted into the form.
4307 
4308   @retval EFI_OUT_OF_RESOURCES   No enough memory resource is allocated.
4309   @retval EFI_NOT_FOUND          The following cases will return EFI_NOT_FOUND.
4310                                  1) The form specified by HiiHandle, FormSetGuid,
4311                                  and FormId could not be found in the HII Database.
4312                                  2) No IFR opcodes in the target form match the first
4313                                  IFR opcode in StartOpCodeHandle.
4314                                  3) EndOpCOde is not NULL, and no IFR opcodes in the
4315                                  target form following a matching start opcode match
4316                                  the first IFR opcode in EndOpCodeHandle.
4317   @retval EFI_SUCCESS            The matched form is updated by StartOpcode.
4318 
4319 **/
4320 EFI_STATUS
4321 EFIAPI
HiiUpdateForm(IN EFI_HII_HANDLE HiiHandle,IN EFI_GUID * FormSetGuid,OPTIONAL IN EFI_FORM_ID FormId,IN VOID * StartOpCodeHandle,IN VOID * EndOpCodeHandle OPTIONAL)4322 HiiUpdateForm (
4323   IN EFI_HII_HANDLE  HiiHandle,
4324   IN EFI_GUID        *FormSetGuid,        OPTIONAL
4325   IN EFI_FORM_ID     FormId,
4326   IN VOID            *StartOpCodeHandle,
4327   IN VOID            *EndOpCodeHandle     OPTIONAL
4328   )
4329 {
4330   EFI_STATUS                   Status;
4331   EFI_HII_PACKAGE_LIST_HEADER  *HiiPackageList;
4332   UINT32                       PackageListLength;
4333   UINT32                       Offset;
4334   EFI_HII_PACKAGE_LIST_HEADER  *UpdatePackageList;
4335   UINTN                        BufferSize;
4336   UINT8                        *UpdateBufferPos;
4337   EFI_HII_PACKAGE_HEADER       *Package;
4338   EFI_HII_PACKAGE_HEADER       *TempPackage;
4339   EFI_HII_PACKAGE_HEADER       PackageHeader;
4340   BOOLEAN                      Updated;
4341   HII_LIB_OPCODE_BUFFER        *OpCodeBufferStart;
4342   HII_LIB_OPCODE_BUFFER        *OpCodeBufferEnd;
4343 
4344   //
4345   // Input update data can't be NULL.
4346   //
4347   ASSERT (HiiHandle != NULL);
4348   ASSERT (StartOpCodeHandle != NULL);
4349   UpdatePackageList = NULL;
4350   TempPackage       = NULL;
4351   HiiPackageList    = NULL;
4352 
4353   //
4354   // Retrieve buffer data from Opcode Handle
4355   //
4356   OpCodeBufferStart = (HII_LIB_OPCODE_BUFFER *) StartOpCodeHandle;
4357   OpCodeBufferEnd   = (HII_LIB_OPCODE_BUFFER *) EndOpCodeHandle;
4358 
4359   //
4360   // Get the original package list
4361   //
4362   BufferSize = 0;
4363   HiiPackageList   = NULL;
4364   Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, HiiHandle, &BufferSize, HiiPackageList);
4365   //
4366   // The return status should always be EFI_BUFFER_TOO_SMALL as input buffer's size is 0.
4367   //
4368   if (Status != EFI_BUFFER_TOO_SMALL) {
4369     return Status;
4370   }
4371 
4372   HiiPackageList = AllocatePool (BufferSize);
4373   if (HiiPackageList == NULL) {
4374     Status = EFI_OUT_OF_RESOURCES;
4375     goto Finish;
4376   }
4377 
4378   Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, HiiHandle, &BufferSize, HiiPackageList);
4379   if (EFI_ERROR (Status)) {
4380     goto Finish;
4381   }
4382 
4383   //
4384   // Calculate and allocate space for retrieval of IFR data
4385   //
4386   BufferSize += OpCodeBufferStart->Position;
4387   UpdatePackageList = AllocateZeroPool (BufferSize);
4388   if (UpdatePackageList == NULL) {
4389     Status = EFI_OUT_OF_RESOURCES;
4390     goto Finish;
4391   }
4392 
4393   //
4394   // Allocate temp buffer to store the temp updated package buffer
4395   //
4396   TempPackage = AllocateZeroPool (BufferSize);
4397   if (TempPackage == NULL) {
4398     Status = EFI_OUT_OF_RESOURCES;
4399     goto Finish;
4400   }
4401 
4402   UpdateBufferPos = (UINT8 *) UpdatePackageList;
4403 
4404   //
4405   // Copy the package list header
4406   //
4407   CopyMem (UpdateBufferPos, HiiPackageList, sizeof (EFI_HII_PACKAGE_LIST_HEADER));
4408   UpdateBufferPos += sizeof (EFI_HII_PACKAGE_LIST_HEADER);
4409 
4410   //
4411   // Go through each package to find the matched package and update one by one
4412   //
4413   Updated = FALSE;
4414   Offset  = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
4415   PackageListLength = ReadUnaligned32 (&HiiPackageList->PackageLength);
4416   while (Offset < PackageListLength) {
4417     Package = (EFI_HII_PACKAGE_HEADER *) (((UINT8 *) HiiPackageList) + Offset);
4418     CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
4419     Offset += Package->Length;
4420 
4421     if (Package->Type == EFI_HII_PACKAGE_FORMS) {
4422       //
4423       // Check this package is the matched package.
4424       //
4425       Status = InternalHiiUpdateFormPackageData (FormSetGuid, FormId, Package, OpCodeBufferStart, OpCodeBufferEnd, TempPackage);
4426       //
4427       // The matched package is found. Its package buffer will be updated by the input new data.
4428       //
4429       if (!EFI_ERROR(Status)) {
4430         //
4431         // Set Update Flag
4432         //
4433         Updated = TRUE;
4434         //
4435         // Add updated package buffer
4436         //
4437         Package = TempPackage;
4438       }
4439     }
4440 
4441     //
4442     // Add pacakge buffer
4443     //
4444     CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
4445     CopyMem (UpdateBufferPos, Package, PackageHeader.Length);
4446     UpdateBufferPos += PackageHeader.Length;
4447   }
4448 
4449   if (Updated) {
4450     //
4451     // Update package list length
4452     //
4453     BufferSize = UpdateBufferPos - (UINT8 *) UpdatePackageList;
4454     WriteUnaligned32 (&UpdatePackageList->PackageLength, (UINT32) BufferSize);
4455 
4456     //
4457     // Update Package to show form
4458     //
4459     Status = gHiiDatabase->UpdatePackageList (gHiiDatabase, HiiHandle, UpdatePackageList);
4460   } else {
4461     //
4462     // Not matched form is found and updated.
4463     //
4464     Status = EFI_NOT_FOUND;
4465   }
4466 
4467 Finish:
4468   if (HiiPackageList != NULL) {
4469     FreePool (HiiPackageList);
4470   }
4471 
4472   if (UpdatePackageList != NULL) {
4473     FreePool (UpdatePackageList);
4474   }
4475 
4476   if (TempPackage != NULL) {
4477     FreePool (TempPackage);
4478   }
4479 
4480   return Status;
4481 }
4482