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