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