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