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