This change checks REST_STYLE flag. Signed-off-by: Jiaxin Wu <jiaxin.wu@intel.com> Signed-off-by: Ting Ye <ting.ye@intel.com> Signed-off-by: Siyuan Fu <siyuan.fu@intel.com> Signed-off-by: Fan Wang <fan.wang@intel.com> Signed-off-by: Abner Chang <abner.chang@hpe.com> Cc: Dandan Bi <dandan.bi@intel.com> Cc: Eric Dong <eric.dong@intel.com> Cc: Nickle Wang <nickle.wang@hpe.com> Reviewed-by: Liming Gao <gaoliming@byosoft.com.cn>
		
			
				
	
	
		
			4482 lines
		
	
	
		
			146 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			4482 lines
		
	
	
		
			146 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   HII Library implementation that uses DXE protocols and services.
 | |
| 
 | |
|   Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
 | |
|   SPDX-License-Identifier: BSD-2-Clause-Patent
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include "InternalHiiLib.h"
 | |
| 
 | |
| #define GUID_CONFIG_STRING_TYPE 0x00
 | |
| #define NAME_CONFIG_STRING_TYPE 0x01
 | |
| #define PATH_CONFIG_STRING_TYPE 0x02
 | |
| 
 | |
| #define ACTION_SET_DEFAUTL_VALUE 0x01
 | |
| #define ACTION_VALIDATE_SETTING  0x02
 | |
| 
 | |
| #define HII_LIB_DEFAULT_VARSTORE_SIZE  0x200
 | |
| 
 | |
| typedef struct {
 | |
|   LIST_ENTRY          Entry;      // Link to Block array
 | |
|   UINT16              Offset;
 | |
|   UINT16              Width;
 | |
|   UINT8               OpCode;
 | |
|   UINT8               Scope;
 | |
| } IFR_BLOCK_DATA;
 | |
| 
 | |
| typedef struct {
 | |
|   EFI_VARSTORE_ID     VarStoreId;
 | |
|   UINT16              Size;
 | |
| } IFR_VARSTORAGE_DATA;
 | |
| 
 | |
| //
 | |
| // <ConfigHdr> Template
 | |
| //
 | |
| GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR16 mConfigHdrTemplate[] = L"GUID=00000000000000000000000000000000&NAME=0000&PATH=00";
 | |
| 
 | |
| EFI_FORM_BROWSER2_PROTOCOL  *mUefiFormBrowser2 = NULL;
 | |
| 
 | |
| //
 | |
| // Template used to mark the end of a list of packages
 | |
| //
 | |
| GLOBAL_REMOVE_IF_UNREFERENCED CONST EFI_HII_PACKAGE_HEADER  mEndOfPakageList = {
 | |
|   sizeof (EFI_HII_PACKAGE_HEADER),
 | |
|   EFI_HII_PACKAGE_END
 | |
| };
 | |
| 
 | |
| /**
 | |
|   Extract Hii package list GUID for given HII handle.
 | |
| 
 | |
|   If HiiHandle could not be found in the HII database, then ASSERT.
 | |
|   If Guid is NULL, then ASSERT.
 | |
| 
 | |
|   @param  Handle              Hii handle
 | |
|   @param  Guid                Package list GUID
 | |
| 
 | |
|   @retval EFI_SUCCESS         Successfully extract GUID from Hii database.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| InternalHiiExtractGuidFromHiiHandle (
 | |
|   IN      EFI_HII_HANDLE      Handle,
 | |
|   OUT     EFI_GUID            *Guid
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                   Status;
 | |
|   UINTN                        BufferSize;
 | |
|   EFI_HII_PACKAGE_LIST_HEADER  *HiiPackageList;
 | |
| 
 | |
|   ASSERT (Guid != NULL);
 | |
|   ASSERT (Handle != NULL);
 | |
| 
 | |
|   //
 | |
|   // Get HII PackageList
 | |
|   //
 | |
|   BufferSize = 0;
 | |
|   HiiPackageList = NULL;
 | |
| 
 | |
|   Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, Handle, &BufferSize, HiiPackageList);
 | |
|   ASSERT (Status != EFI_NOT_FOUND);
 | |
| 
 | |
|   if (Status == EFI_BUFFER_TOO_SMALL) {
 | |
|     HiiPackageList = AllocatePool (BufferSize);
 | |
|     ASSERT (HiiPackageList != NULL);
 | |
| 
 | |
|     Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, Handle, &BufferSize, HiiPackageList);
 | |
|   }
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     FreePool (HiiPackageList);
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Extract GUID
 | |
|   //
 | |
|   CopyGuid (Guid, &HiiPackageList->PackageListGuid);
 | |
| 
 | |
|   FreePool (HiiPackageList);
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Registers a list of packages in the HII Database and returns the HII Handle
 | |
|   associated with that registration.  If an HII Handle has already been registered
 | |
|   with the same PackageListGuid and DeviceHandle, then NULL is returned.  If there
 | |
|   are not enough resources to perform the registration, then NULL is returned.
 | |
|   If an empty list of packages is passed in, then NULL is returned.  If the size of
 | |
|   the list of package is 0, then NULL is returned.
 | |
| 
 | |
|   The variable arguments are pointers which point to package header that defined
 | |
|   by UEFI VFR compiler and StringGather tool.
 | |
| 
 | |
|   #pragma pack (push, 1)
 | |
|   typedef struct {
 | |
|     UINT32                  BinaryLength;
 | |
|     EFI_HII_PACKAGE_HEADER  PackageHeader;
 | |
|   } EDKII_AUTOGEN_PACKAGES_HEADER;
 | |
|   #pragma pack (pop)
 | |
| 
 | |
|   @param[in]  PackageListGuid  The GUID of the package list.
 | |
|   @param[in]  DeviceHandle     If not NULL, the Device Handle on which
 | |
|                                an instance of DEVICE_PATH_PROTOCOL is installed.
 | |
|                                This Device Handle uniquely defines the device that
 | |
|                                the added packages are associated with.
 | |
|   @param[in]  ...              The variable argument list that contains pointers
 | |
|                                to packages terminated by a NULL.
 | |
| 
 | |
|   @retval NULL   A HII Handle has already been registered in the HII Database with
 | |
|                  the same PackageListGuid and DeviceHandle.
 | |
|   @retval NULL   The HII Handle could not be created.
 | |
|   @retval NULL   An empty list of packages was passed in.
 | |
|   @retval NULL   All packages are empty.
 | |
|   @retval Other  The HII Handle associated with the newly registered package list.
 | |
| 
 | |
| **/
 | |
| EFI_HII_HANDLE
 | |
| EFIAPI
 | |
| HiiAddPackages (
 | |
|   IN CONST EFI_GUID    *PackageListGuid,
 | |
|   IN       EFI_HANDLE  DeviceHandle  OPTIONAL,
 | |
|   ...
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                   Status;
 | |
|   VA_LIST                      Args;
 | |
|   UINT32                       *Package;
 | |
|   EFI_HII_PACKAGE_LIST_HEADER  *PackageListHeader;
 | |
|   EFI_HII_HANDLE               HiiHandle;
 | |
|   UINT32                       Length;
 | |
|   UINT8                        *Data;
 | |
| 
 | |
|   ASSERT (PackageListGuid != NULL);
 | |
| 
 | |
|   //
 | |
|   // Calculate the length of all the packages in the variable argument list
 | |
|   //
 | |
|   for (Length = 0, VA_START (Args, DeviceHandle); (Package = VA_ARG (Args, UINT32 *)) != NULL; ) {
 | |
|     Length += (ReadUnaligned32 (Package) - sizeof (UINT32));
 | |
|   }
 | |
|   VA_END (Args);
 | |
| 
 | |
|   //
 | |
|   // If there are no packages in the variable argument list or all the packages
 | |
|   // are empty, then return a NULL HII Handle
 | |
|   //
 | |
|   if (Length == 0) {
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Add the length of the Package List Header and the terminating Package Header
 | |
|   //
 | |
|   Length += sizeof (EFI_HII_PACKAGE_LIST_HEADER) + sizeof (EFI_HII_PACKAGE_HEADER);
 | |
| 
 | |
|   //
 | |
|   // Allocate the storage for the entire Package List
 | |
|   //
 | |
|   PackageListHeader = AllocateZeroPool (Length);
 | |
| 
 | |
|   //
 | |
|   // If the Package List can not be allocated, then return a NULL HII Handle
 | |
|   //
 | |
|   if (PackageListHeader == NULL) {
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Fill in the GUID and Length of the Package List Header
 | |
|   //
 | |
|   CopyGuid (&PackageListHeader->PackageListGuid, PackageListGuid);
 | |
|   PackageListHeader->PackageLength = Length;
 | |
| 
 | |
|   //
 | |
|   // Initialize a pointer to the beginning if the Package List data
 | |
|   //
 | |
|   Data = (UINT8 *)(PackageListHeader + 1);
 | |
| 
 | |
|   //
 | |
|   // Copy the data from each package in the variable argument list
 | |
|   //
 | |
|   for (VA_START (Args, DeviceHandle); (Package = VA_ARG (Args, UINT32 *)) != NULL; ) {
 | |
|     Length = ReadUnaligned32 (Package) - sizeof (UINT32);
 | |
|     CopyMem (Data, Package + 1, Length);
 | |
|     Data += Length;
 | |
|   }
 | |
|   VA_END (Args);
 | |
| 
 | |
|   //
 | |
|   // Append a package of type EFI_HII_PACKAGE_END to mark the end of the package list
 | |
|   //
 | |
|   CopyMem (Data, &mEndOfPakageList, sizeof (mEndOfPakageList));
 | |
| 
 | |
|   //
 | |
|   // Register the package list with the HII Database
 | |
|   //
 | |
|   Status = gHiiDatabase->NewPackageList (
 | |
|                            gHiiDatabase,
 | |
|                            PackageListHeader,
 | |
|                            DeviceHandle,
 | |
|                            &HiiHandle
 | |
|                            );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     HiiHandle = NULL;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Free the allocated package list
 | |
|   //
 | |
|   FreePool (PackageListHeader);
 | |
| 
 | |
|   //
 | |
|   // Return the new HII Handle
 | |
|   //
 | |
|   return HiiHandle;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Removes a package list from the HII database.
 | |
| 
 | |
|   If HiiHandle is NULL, then ASSERT.
 | |
|   If HiiHandle is not a valid EFI_HII_HANDLE in the HII database, then ASSERT.
 | |
| 
 | |
|   @param[in]  HiiHandle   The handle that was previously registered in the HII database
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| HiiRemovePackages (
 | |
|   IN      EFI_HII_HANDLE      HiiHandle
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS Status;
 | |
| 
 | |
|   ASSERT (HiiHandle != NULL);
 | |
|   Status = gHiiDatabase->RemovePackageList (gHiiDatabase, HiiHandle);
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Retrieves the array of all the HII Handles or the HII handles of a specific
 | |
|   package list GUID in the HII Database.
 | |
|   This array is terminated with a NULL HII Handle.
 | |
|   This function allocates the returned array using AllocatePool().
 | |
|   The caller is responsible for freeing the array with FreePool().
 | |
| 
 | |
|   @param[in]  PackageListGuid  An optional parameter that is used to request
 | |
|                                HII Handles associated with a specific
 | |
|                                Package List GUID.  If this parameter is NULL,
 | |
|                                then all the HII Handles in the HII Database
 | |
|                                are returned.  If this parameter is not NULL,
 | |
|                                then zero or more HII Handles associated with
 | |
|                                PackageListGuid are returned.
 | |
| 
 | |
|   @retval NULL   No HII handles were found in the HII database
 | |
|   @retval NULL   The array of HII Handles could not be retrieved
 | |
|   @retval Other  A pointer to the NULL terminated array of HII Handles
 | |
| 
 | |
| **/
 | |
| EFI_HII_HANDLE *
 | |
| EFIAPI
 | |
| HiiGetHiiHandles (
 | |
|   IN CONST EFI_GUID  *PackageListGuid  OPTIONAL
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS      Status;
 | |
|   UINTN           HandleBufferLength;
 | |
|   EFI_HII_HANDLE  TempHiiHandleBuffer;
 | |
|   EFI_HII_HANDLE  *HiiHandleBuffer;
 | |
|   EFI_GUID        Guid;
 | |
|   UINTN           Index1;
 | |
|   UINTN           Index2;
 | |
| 
 | |
|   //
 | |
|   // Retrieve the size required for the buffer of all HII handles.
 | |
|   //
 | |
|   HandleBufferLength = 0;
 | |
|   Status = gHiiDatabase->ListPackageLists (
 | |
|                            gHiiDatabase,
 | |
|                            EFI_HII_PACKAGE_TYPE_ALL,
 | |
|                            NULL,
 | |
|                            &HandleBufferLength,
 | |
|                            &TempHiiHandleBuffer
 | |
|                            );
 | |
| 
 | |
|   //
 | |
|   // If ListPackageLists() returns EFI_SUCCESS for a zero size,
 | |
|   // then there are no HII handles in the HII database.  If ListPackageLists()
 | |
|   // returns an error other than EFI_BUFFER_TOO_SMALL, then there are no HII
 | |
|   // handles in the HII database.
 | |
|   //
 | |
|   if (Status != EFI_BUFFER_TOO_SMALL) {
 | |
|     //
 | |
|     // Return NULL if the size can not be retrieved, or if there are no HII
 | |
|     // handles in the HII Database
 | |
|     //
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Allocate the array of HII handles to hold all the HII Handles and a NULL terminator
 | |
|   //
 | |
|   HiiHandleBuffer = AllocateZeroPool (HandleBufferLength + sizeof (EFI_HII_HANDLE));
 | |
|   if (HiiHandleBuffer == NULL) {
 | |
|     //
 | |
|     // Return NULL if allocation fails.
 | |
|     //
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Retrieve the array of HII Handles in the HII Database
 | |
|   //
 | |
|   Status = gHiiDatabase->ListPackageLists (
 | |
|                            gHiiDatabase,
 | |
|                            EFI_HII_PACKAGE_TYPE_ALL,
 | |
|                            NULL,
 | |
|                            &HandleBufferLength,
 | |
|                            HiiHandleBuffer
 | |
|                            );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     //
 | |
|     // Free the buffer and return NULL if the HII handles can not be retrieved.
 | |
|     //
 | |
|     FreePool (HiiHandleBuffer);
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   if (PackageListGuid == NULL) {
 | |
|     //
 | |
|     // Return the NULL terminated array of HII handles in the HII Database
 | |
|     //
 | |
|     return HiiHandleBuffer;
 | |
|   } else {
 | |
|     for (Index1 = 0, Index2 = 0; HiiHandleBuffer[Index1] != NULL; Index1++) {
 | |
|       Status = InternalHiiExtractGuidFromHiiHandle (HiiHandleBuffer[Index1], &Guid);
 | |
|       ASSERT_EFI_ERROR (Status);
 | |
|       if (CompareGuid (&Guid, PackageListGuid)) {
 | |
|         HiiHandleBuffer[Index2++] = HiiHandleBuffer[Index1];
 | |
|       }
 | |
|     }
 | |
|     if (Index2 > 0) {
 | |
|       HiiHandleBuffer[Index2] = NULL;
 | |
|       return HiiHandleBuffer;
 | |
|     } else {
 | |
|       FreePool (HiiHandleBuffer);
 | |
|       return NULL;
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function allows a caller to extract the form set opcode form the Hii Handle.
 | |
|   The returned buffer is allocated using AllocatePool().The caller is responsible
 | |
|   for freeing the allocated buffer using FreePool().
 | |
| 
 | |
|   @param Handle            The HII handle.
 | |
|   @param Buffer            On return, points to a pointer which point to the buffer that contain the formset opcode.
 | |
|   @param BufferSize        On return, points to the length of the buffer.
 | |
| 
 | |
|   @retval EFI_OUT_OF_RESOURCES   No enough memory resource is allocated.
 | |
|   @retval EFI_NOT_FOUND          Can't find the package data for the input Handle.
 | |
|   @retval EFI_INVALID_PARAMETER  The input parameters are not correct.
 | |
|   @retval EFI_SUCCESS            Get the formset opcode from the hii handle successfully.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| HiiGetFormSetFromHiiHandle(
 | |
|   IN  EFI_HII_HANDLE     Handle,
 | |
|   OUT EFI_IFR_FORM_SET   **Buffer,
 | |
|   OUT UINTN              *BufferSize
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                   Status;
 | |
|   UINTN                        PackageListSize;
 | |
|   UINTN                        TempSize;
 | |
|   EFI_HII_PACKAGE_LIST_HEADER  *HiiPackageList;
 | |
|   UINT8                        *Package;
 | |
|   UINT8                        *OpCodeData;
 | |
|   UINT8                        *FormSetBuffer;
 | |
|   UINT8                        *TempBuffer;
 | |
|   UINT32                       Offset;
 | |
|   UINT32                       Offset2;
 | |
|   UINT32                       PackageListLength;
 | |
|   EFI_HII_PACKAGE_HEADER       PackageHeader;
 | |
| 
 | |
|   TempSize = 0;
 | |
|   FormSetBuffer = NULL;
 | |
|   TempBuffer    = NULL;
 | |
| 
 | |
|   //
 | |
|   // Get HII PackageList
 | |
|   //
 | |
|   PackageListSize = 0;
 | |
|   HiiPackageList = NULL;
 | |
|   Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, Handle, &PackageListSize, HiiPackageList);
 | |
|   if (EFI_ERROR (Status) && (Status != EFI_BUFFER_TOO_SMALL)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   HiiPackageList = AllocatePool (PackageListSize);
 | |
|   if (HiiPackageList == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, Handle, &PackageListSize, HiiPackageList);
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   //
 | |
|   // Get Form package from this HII package List
 | |
|   //
 | |
|   Status = EFI_NOT_FOUND;
 | |
|   Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
 | |
|   PackageListLength = ReadUnaligned32 (&HiiPackageList->PackageLength);
 | |
| 
 | |
|   while (Offset < PackageListLength) {
 | |
|     Package = ((UINT8 *) HiiPackageList) + Offset;
 | |
|     CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
 | |
|     Offset += PackageHeader.Length;
 | |
| 
 | |
|     if (PackageHeader.Type != EFI_HII_PACKAGE_FORMS) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Search FormSet Opcode in this Form Package
 | |
|     //
 | |
|     Offset2 = sizeof (EFI_HII_PACKAGE_HEADER);
 | |
|     while (Offset2 < PackageHeader.Length) {
 | |
|       OpCodeData = Package + Offset2;
 | |
|       Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;
 | |
| 
 | |
|       if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode != EFI_IFR_FORM_SET_OP) {
 | |
|         continue;
 | |
|       }
 | |
| 
 | |
|       if (FormSetBuffer != NULL){
 | |
|         TempBuffer = ReallocatePool (
 | |
|                        TempSize,
 | |
|                        TempSize + ((EFI_IFR_OP_HEADER *) OpCodeData)->Length,
 | |
|                        FormSetBuffer
 | |
|                        );
 | |
|         if (TempBuffer == NULL) {
 | |
|           Status = EFI_OUT_OF_RESOURCES;
 | |
|           goto Done;
 | |
|         }
 | |
|         CopyMem (TempBuffer + TempSize,  OpCodeData, ((EFI_IFR_OP_HEADER *) OpCodeData)->Length);
 | |
|         FormSetBuffer = NULL;
 | |
|       } else {
 | |
|         TempBuffer = AllocatePool (TempSize + ((EFI_IFR_OP_HEADER *) OpCodeData)->Length);
 | |
|         if (TempBuffer == NULL) {
 | |
|           Status = EFI_OUT_OF_RESOURCES;
 | |
|           goto Done;
 | |
|         }
 | |
|         CopyMem (TempBuffer, OpCodeData, ((EFI_IFR_OP_HEADER *) OpCodeData)->Length);
 | |
|       }
 | |
|       TempSize += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;
 | |
|       FormSetBuffer = TempBuffer;
 | |
| 
 | |
|       Status = EFI_SUCCESS;
 | |
|       //
 | |
|       //One form package has one formset, exit current form package to search other form package in the packagelist.
 | |
|       //
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
| Done:
 | |
|   FreePool (HiiPackageList);
 | |
| 
 | |
|   *BufferSize = TempSize;
 | |
|   *Buffer = (EFI_IFR_FORM_SET *)FormSetBuffer;
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Converts all hex dtring characters in range ['A'..'F'] to ['a'..'f'] for
 | |
|   hex digits that appear between a '=' and a '&' in a config string.
 | |
| 
 | |
|   If ConfigString is NULL, then ASSERT().
 | |
| 
 | |
|   @param[in] ConfigString  Pointer to a Null-terminated Unicode string.
 | |
| 
 | |
|   @return  Pointer to the Null-terminated Unicode result string.
 | |
| 
 | |
| **/
 | |
| EFI_STRING
 | |
| EFIAPI
 | |
| InternalHiiLowerConfigString (
 | |
|   IN EFI_STRING  ConfigString
 | |
|   )
 | |
| {
 | |
|   EFI_STRING  String;
 | |
|   BOOLEAN     Lower;
 | |
| 
 | |
|   ASSERT (ConfigString != NULL);
 | |
| 
 | |
|   //
 | |
|   // Convert all hex digits in range [A-F] in the configuration header to [a-f]
 | |
|   //
 | |
|   for (String = ConfigString, Lower = FALSE; *String != L'\0'; String++) {
 | |
|     if (*String == L'=') {
 | |
|       Lower = TRUE;
 | |
|     } else if (*String == L'&') {
 | |
|       Lower = FALSE;
 | |
|     } else if (Lower && *String >= L'A' && *String <= L'F') {
 | |
|       *String = (CHAR16) (*String - L'A' + L'a');
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return ConfigString;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Uses the BlockToConfig() service of the Config Routing Protocol to
 | |
|   convert <ConfigRequest> and a buffer to a <ConfigResp>
 | |
| 
 | |
|   If ConfigRequest is NULL, then ASSERT().
 | |
|   If Block is NULL, then ASSERT().
 | |
| 
 | |
|   @param[in] ConfigRequest  Pointer to a Null-terminated Unicode string.
 | |
|   @param[in] Block          Pointer to a block of data.
 | |
|   @param[in] BlockSize      The zie, in bytes, of Block.
 | |
| 
 | |
|   @retval NULL   The <ConfigResp> string could not be generated.
 | |
|   @retval Other  Pointer to the Null-terminated Unicode <ConfigResp> string.
 | |
| 
 | |
| **/
 | |
| EFI_STRING
 | |
| EFIAPI
 | |
| InternalHiiBlockToConfig (
 | |
|   IN CONST EFI_STRING  ConfigRequest,
 | |
|   IN CONST UINT8       *Block,
 | |
|   IN UINTN             BlockSize
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   EFI_STRING  ConfigResp;
 | |
|   CHAR16      *Progress;
 | |
| 
 | |
|   ASSERT (ConfigRequest != NULL);
 | |
|   ASSERT (Block != NULL);
 | |
| 
 | |
|   //
 | |
|   // Convert <ConfigRequest> to <ConfigResp>
 | |
|   //
 | |
|   Status = gHiiConfigRouting->BlockToConfig (
 | |
|                                 gHiiConfigRouting,
 | |
|                                 ConfigRequest,
 | |
|                                 Block,
 | |
|                                 BlockSize,
 | |
|                                 &ConfigResp,
 | |
|                                 &Progress
 | |
|                                 );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return NULL;
 | |
|   }
 | |
|   return ConfigResp;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Uses the BrowserCallback() service of the Form Browser Protocol to retrieve
 | |
|   or set uncommitted data.  If sata i being retrieved, then the buffer is
 | |
|   allocated using AllocatePool().  The caller is then responsible for freeing
 | |
|   the buffer using FreePool().
 | |
| 
 | |
|   @param[in]  VariableGuid    Pointer to an EFI_GUID structure.  This is an optional
 | |
|                               parameter that may be NULL.
 | |
|   @param[in]  VariableName    Pointer to a Null-terminated Unicode string.  This
 | |
|                               is an optional parameter that may be NULL.
 | |
|   @param[in]  SetResultsData  If not NULL, then this parameter specified the buffer
 | |
|                               of uncommited data to set.  If this parameter is NULL,
 | |
|                               then the caller is requesting to get the uncommited data
 | |
|                               from the Form Browser.
 | |
| 
 | |
|   @retval NULL   The uncommitted data could not be retrieved.
 | |
|   @retval Other  A pointer to a buffer containing the uncommitted data.
 | |
| 
 | |
| **/
 | |
| EFI_STRING
 | |
| EFIAPI
 | |
| InternalHiiBrowserCallback (
 | |
|   IN CONST EFI_GUID    *VariableGuid,  OPTIONAL
 | |
|   IN CONST CHAR16      *VariableName,  OPTIONAL
 | |
|   IN CONST EFI_STRING  SetResultsData  OPTIONAL
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   UINTN       ResultsDataSize;
 | |
|   EFI_STRING  ResultsData;
 | |
|   CHAR16      TempResultsData;
 | |
| 
 | |
|   //
 | |
|   // Locate protocols
 | |
|   //
 | |
|   if (mUefiFormBrowser2 == NULL) {
 | |
|     Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &mUefiFormBrowser2);
 | |
|     if (EFI_ERROR (Status) || mUefiFormBrowser2 == NULL) {
 | |
|       return NULL;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   ResultsDataSize = 0;
 | |
| 
 | |
|   if (SetResultsData != NULL) {
 | |
|     //
 | |
|     // Request to to set data in the uncommitted browser state information
 | |
|     //
 | |
|     ResultsData = SetResultsData;
 | |
|   } else {
 | |
|     //
 | |
|     // Retrieve the length of the buffer required ResultsData from the Browser Callback
 | |
|     //
 | |
|     Status = mUefiFormBrowser2->BrowserCallback (
 | |
|                               mUefiFormBrowser2,
 | |
|                               &ResultsDataSize,
 | |
|                               &TempResultsData,
 | |
|                               TRUE,
 | |
|                               VariableGuid,
 | |
|                               VariableName
 | |
|                               );
 | |
| 
 | |
|     if (!EFI_ERROR (Status)) {
 | |
|       //
 | |
|       // No Resluts Data, only allocate one char for '\0'
 | |
|       //
 | |
|       ResultsData = AllocateZeroPool (sizeof (CHAR16));
 | |
|       return ResultsData;
 | |
|     }
 | |
| 
 | |
|     if (Status != EFI_BUFFER_TOO_SMALL) {
 | |
|       return NULL;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Allocate the ResultsData buffer
 | |
|     //
 | |
|     ResultsData = AllocateZeroPool (ResultsDataSize);
 | |
|     if (ResultsData == NULL) {
 | |
|       return NULL;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Retrieve or set the ResultsData from the Browser Callback
 | |
|   //
 | |
|   Status = mUefiFormBrowser2->BrowserCallback (
 | |
|                             mUefiFormBrowser2,
 | |
|                             &ResultsDataSize,
 | |
|                             ResultsData,
 | |
|                             (BOOLEAN)(SetResultsData == NULL),
 | |
|                             VariableGuid,
 | |
|                             VariableName
 | |
|                             );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   return ResultsData;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Allocates and returns a Null-terminated Unicode <ConfigHdr> string using routing
 | |
|   information that includes a GUID, an optional Unicode string name, and a device
 | |
|   path.  The string returned is allocated with AllocatePool().  The caller is
 | |
|   responsible for freeing the allocated string with FreePool().
 | |
| 
 | |
|   The format of a <ConfigHdr> is as follows:
 | |
| 
 | |
|     GUID=<HexCh>32&NAME=<Char>NameLength&PATH=<HexChar>DevicePathSize<Null>
 | |
| 
 | |
|   @param[in]  Guid          Pointer to an EFI_GUID that is the routing information
 | |
|                             GUID.  Each of the 16 bytes in Guid is converted to
 | |
|                             a 2 Unicode character hexadecimal string.  This is
 | |
|                             an optional parameter that may be NULL.
 | |
|   @param[in]  Name          Pointer to a Null-terminated Unicode string that is
 | |
|                             the routing information NAME.  This is an optional
 | |
|                             parameter that may be NULL.  Each 16-bit Unicode
 | |
|                             character in Name is converted to a 4 character Unicode
 | |
|                             hexadecimal string.
 | |
|   @param[in]  DriverHandle  The driver handle which supports a Device Path Protocol
 | |
|                             that is the routing information PATH.  Each byte of
 | |
|                             the Device Path associated with DriverHandle is converted
 | |
|                             to a 2 Unicode character hexadecimal string.
 | |
| 
 | |
|   @retval NULL   DriverHandle does not support the Device Path Protocol.
 | |
|   @retval Other  A pointer to the Null-terminate Unicode <ConfigHdr> string
 | |
| 
 | |
| **/
 | |
| EFI_STRING
 | |
| EFIAPI
 | |
| HiiConstructConfigHdr (
 | |
|   IN CONST EFI_GUID  *Guid,  OPTIONAL
 | |
|   IN CONST CHAR16    *Name,  OPTIONAL
 | |
|   IN EFI_HANDLE      DriverHandle
 | |
|   )
 | |
| {
 | |
|   UINTN                     NameLength;
 | |
|   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
 | |
|   UINTN                     DevicePathSize;
 | |
|   CHAR16                    *String;
 | |
|   CHAR16                    *ReturnString;
 | |
|   UINTN                     Index;
 | |
|   UINT8                     *Buffer;
 | |
|   UINTN                     MaxLen;
 | |
| 
 | |
|   //
 | |
|   // Compute the length of Name in Unicode characters.
 | |
|   // If Name is NULL, then the length is 0.
 | |
|   //
 | |
|   NameLength = 0;
 | |
|   if (Name != NULL) {
 | |
|     NameLength = StrLen (Name);
 | |
|   }
 | |
| 
 | |
|   DevicePath = NULL;
 | |
|   DevicePathSize = 0;
 | |
|   //
 | |
|   // Retrieve DevicePath Protocol associated with DriverHandle
 | |
|   //
 | |
|   if (DriverHandle != NULL) {
 | |
|     DevicePath = DevicePathFromHandle (DriverHandle);
 | |
|     if (DevicePath == NULL) {
 | |
|       return NULL;
 | |
|     }
 | |
|     //
 | |
|     // Compute the size of the device path in bytes
 | |
|     //
 | |
|     DevicePathSize = GetDevicePathSize (DevicePath);
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // GUID=<HexCh>32&NAME=<Char>NameLength&PATH=<HexChar>DevicePathSize <Null>
 | |
|   // | 5 | sizeof (EFI_GUID) * 2 | 6 | NameStrLen*4 | 6 | DevicePathSize * 2 | 1 |
 | |
|   //
 | |
|   MaxLen = 5 + sizeof (EFI_GUID) * 2 + 6 + NameLength * 4 + 6 + DevicePathSize * 2 + 1;
 | |
|   String = AllocateZeroPool (MaxLen * sizeof (CHAR16));
 | |
|   if (String == NULL) {
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Start with L"GUID="
 | |
|   //
 | |
|   StrCpyS (String, MaxLen, L"GUID=");
 | |
|   ReturnString = String;
 | |
|   String += StrLen (String);
 | |
| 
 | |
|   if (Guid != NULL) {
 | |
|     //
 | |
|     // Append Guid converted to <HexCh>32
 | |
|     //
 | |
|     for (Index = 0, Buffer = (UINT8 *)Guid; Index < sizeof (EFI_GUID); Index++) {
 | |
|       UnicodeValueToStringS (
 | |
|         String,
 | |
|         MaxLen * sizeof (CHAR16) - ((UINTN)String - (UINTN)ReturnString),
 | |
|         PREFIX_ZERO | RADIX_HEX,
 | |
|         *(Buffer++),
 | |
|         2
 | |
|         );
 | |
|       String += StrnLenS (String, MaxLen - ((UINTN)String - (UINTN)ReturnString) / sizeof (CHAR16));
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Append L"&NAME="
 | |
|   //
 | |
|   StrCatS (ReturnString, MaxLen, L"&NAME=");
 | |
|   String += StrLen (String);
 | |
| 
 | |
|   if (Name != NULL) {
 | |
|     //
 | |
|     // Append Name converted to <Char>NameLength
 | |
|     //
 | |
|     for (; *Name != L'\0'; Name++) {
 | |
|       UnicodeValueToStringS (
 | |
|         String,
 | |
|         sizeof (CHAR16) * MaxLen - ((UINTN)String - (UINTN)ReturnString),
 | |
|         PREFIX_ZERO | RADIX_HEX,
 | |
|         *Name,
 | |
|         4
 | |
|         );
 | |
|       String += StrnLenS (String, MaxLen - ((UINTN)String - (UINTN)ReturnString) / sizeof (CHAR16));
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Append L"&PATH="
 | |
|   //
 | |
|   StrCatS (ReturnString, MaxLen, L"&PATH=");
 | |
|   String += StrLen (String);
 | |
| 
 | |
|   //
 | |
|   // Append the device path associated with DriverHandle converted to <HexChar>DevicePathSize
 | |
|   //
 | |
|   for (Index = 0, Buffer = (UINT8 *)DevicePath; Index < DevicePathSize; Index++) {
 | |
|     UnicodeValueToStringS (
 | |
|       String,
 | |
|       sizeof (CHAR16) * MaxLen - ((UINTN)String - (UINTN)ReturnString),
 | |
|       PREFIX_ZERO | RADIX_HEX,
 | |
|       *(Buffer++),
 | |
|       2
 | |
|       );
 | |
|     String += StrnLenS (String, MaxLen - ((UINTN)String - (UINTN)ReturnString) / sizeof (CHAR16));
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Null terminate the Unicode string
 | |
|   //
 | |
|   *String = L'\0';
 | |
| 
 | |
|   //
 | |
|   // Convert all hex digits in range [A-F] in the configuration header to [a-f]
 | |
|   //
 | |
|   return InternalHiiLowerConfigString (ReturnString);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Convert the hex UNICODE encoding string of UEFI GUID, NAME or device path
 | |
|   to binary buffer from <ConfigHdr>.
 | |
| 
 | |
|   This is a internal function.
 | |
| 
 | |
|   @param  String                 UEFI configuration string.
 | |
|   @param  Flag                   Flag specifies what type buffer will be retrieved.
 | |
|   @param  Buffer                 Binary of Guid, Name or Device path.
 | |
| 
 | |
|   @retval EFI_INVALID_PARAMETER  Any incoming parameter is invalid.
 | |
|   @retval EFI_OUT_OF_RESOURCES   Lake of resources to store neccesary structures.
 | |
|   @retval EFI_SUCCESS            The buffer data is retrieved and translated to
 | |
|                                  binary format.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| InternalHiiGetBufferFromString (
 | |
|   IN  EFI_STRING                 String,
 | |
|   IN  UINT8                      Flag,
 | |
|   OUT UINT8                      **Buffer
 | |
|   )
 | |
| {
 | |
|   UINTN      Length;
 | |
|   EFI_STRING ConfigHdr;
 | |
|   CHAR16     *StringPtr;
 | |
|   UINT8      *DataBuffer;
 | |
|   CHAR16     TemStr[5];
 | |
|   UINTN      Index;
 | |
|   UINT8      DigitUint8;
 | |
| 
 | |
|   if (String == NULL || Buffer == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   DataBuffer = NULL;
 | |
|   StringPtr  = NULL;
 | |
|   ConfigHdr  = String;
 | |
|   //
 | |
|   // The content between 'GUID', 'NAME', 'PATH' of <ConfigHdr> and '&' of next element
 | |
|   // or '\0' (end of configuration string) is the UNICODE %02x bytes encoding string.
 | |
|   //
 | |
|   for (Length = 0; *String != 0 && *String != L'&'; String++, Length++);
 | |
| 
 | |
|   switch (Flag) {
 | |
|   case GUID_CONFIG_STRING_TYPE:
 | |
|   case PATH_CONFIG_STRING_TYPE:
 | |
|     //
 | |
|     // The data in <ConfigHdr> is encoded as hex UNICODE %02x bytes in the same order
 | |
|     // as the device path and Guid resides in RAM memory.
 | |
|     // Translate the data into binary.
 | |
|     //
 | |
|     DataBuffer = (UINT8 *) AllocateZeroPool ((Length + 1) / 2);
 | |
|     if (DataBuffer == NULL) {
 | |
|       return EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
|     //
 | |
|     // Convert binary byte one by one
 | |
|     //
 | |
|     ZeroMem (TemStr, sizeof (TemStr));
 | |
|     for (Index = 0; Index < Length; Index ++) {
 | |
|       TemStr[0] = ConfigHdr[Index];
 | |
|       DigitUint8 = (UINT8) StrHexToUint64 (TemStr);
 | |
|       if ((Index & 1) == 0) {
 | |
|         DataBuffer [Index/2] = DigitUint8;
 | |
|       } else {
 | |
|         DataBuffer [Index/2] = (UINT8) ((DataBuffer [Index/2] << 4) + DigitUint8);
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     *Buffer = DataBuffer;
 | |
|     break;
 | |
| 
 | |
|   case NAME_CONFIG_STRING_TYPE:
 | |
|     //
 | |
|     // Convert Config String to Unicode String, e.g. "0041004200430044" => "ABCD"
 | |
|     //
 | |
| 
 | |
|     //
 | |
|     // Add the tailling char L'\0'
 | |
|     //
 | |
|     DataBuffer = (UINT8 *) AllocateZeroPool ((Length/4 + 1) * sizeof (CHAR16));
 | |
|     if (DataBuffer == NULL) {
 | |
|       return EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
|     //
 | |
|     // Convert character one by one
 | |
|     //
 | |
|     StringPtr = (CHAR16 *) DataBuffer;
 | |
|     ZeroMem (TemStr, sizeof (TemStr));
 | |
|     for (Index = 0; Index < Length; Index += 4) {
 | |
|       StrnCpyS (TemStr, sizeof (TemStr) / sizeof (CHAR16), ConfigHdr + Index, 4);
 | |
|       StringPtr[Index/4] = (CHAR16) StrHexToUint64 (TemStr);
 | |
|     }
 | |
|     //
 | |
|     // Add tailing L'\0' character
 | |
|     //
 | |
|     StringPtr[Index/4] = L'\0';
 | |
| 
 | |
|     *Buffer = DataBuffer;
 | |
|     break;
 | |
| 
 | |
|   default:
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function checks VarOffset and VarWidth is in the block range.
 | |
| 
 | |
|   @param  BlockArray         The block array is to be checked.
 | |
|   @param  VarOffset          Offset of var to the structure
 | |
|   @param  VarWidth           Width of var.
 | |
| 
 | |
|   @retval TRUE   This Var is in the block range.
 | |
|   @retval FALSE  This Var is not in the block range.
 | |
| **/
 | |
| BOOLEAN
 | |
| BlockArrayCheck (
 | |
|   IN IFR_BLOCK_DATA  *BlockArray,
 | |
|   IN UINT16          VarOffset,
 | |
|   IN UINT16          VarWidth
 | |
|   )
 | |
| {
 | |
|   LIST_ENTRY          *Link;
 | |
|   IFR_BLOCK_DATA      *BlockData;
 | |
| 
 | |
|   //
 | |
|   // No Request Block array, all vars are got.
 | |
|   //
 | |
|   if (BlockArray == NULL) {
 | |
|     return TRUE;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Check the input var is in the request block range.
 | |
|   //
 | |
|   for (Link = BlockArray->Entry.ForwardLink; Link != &BlockArray->Entry; Link = Link->ForwardLink) {
 | |
|     BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
 | |
|     if ((VarOffset >= BlockData->Offset) && ((VarOffset + VarWidth) <= (BlockData->Offset + BlockData->Width))) {
 | |
|       return TRUE;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get the value of <Number> in <BlockConfig> format, i.e. the value of OFFSET
 | |
|   or WIDTH or VALUE.
 | |
|   <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE'=<Number>
 | |
| 
 | |
|   @param  ValueString            String in <BlockConfig> format and points to the
 | |
|                                  first character of <Number>.
 | |
|   @param  ValueData              The output value. Caller takes the responsibility
 | |
|                                  to free memory.
 | |
|   @param  ValueLength            Length of the <Number>, in characters.
 | |
| 
 | |
|   @retval EFI_OUT_OF_RESOURCES   Insufficient resources to store neccessary
 | |
|                                  structures.
 | |
|   @retval EFI_SUCCESS            Value of <Number> is outputted in Number
 | |
|                                  successfully.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| InternalHiiGetValueOfNumber (
 | |
|   IN  EFI_STRING           ValueString,
 | |
|   OUT UINT8                **ValueData,
 | |
|   OUT UINTN                *ValueLength
 | |
|   )
 | |
| {
 | |
|   EFI_STRING               StringPtr;
 | |
|   UINTN                    Length;
 | |
|   UINT8                    *Buf;
 | |
|   UINT8                    DigitUint8;
 | |
|   UINTN                    Index;
 | |
|   CHAR16                   TemStr[2];
 | |
| 
 | |
|   ASSERT (ValueString != NULL && ValueData != NULL && ValueLength != NULL);
 | |
|   ASSERT (*ValueString != L'\0');
 | |
| 
 | |
|   //
 | |
|   // Get the length of value string
 | |
|   //
 | |
|   StringPtr = ValueString;
 | |
|   while (*StringPtr != L'\0' && *StringPtr != L'&') {
 | |
|     StringPtr++;
 | |
|   }
 | |
|   Length = StringPtr - ValueString;
 | |
| 
 | |
|   //
 | |
|   // Allocate buffer to store the value
 | |
|   //
 | |
|   Buf = (UINT8 *) AllocateZeroPool ((Length + 1) / 2);
 | |
|   if (Buf == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Convert character one by one to the value buffer
 | |
|   //
 | |
|   ZeroMem (TemStr, sizeof (TemStr));
 | |
|   for (Index = 0; Index < Length; Index ++) {
 | |
|     TemStr[0] = ValueString[Length - Index - 1];
 | |
|     DigitUint8 = (UINT8) StrHexToUint64 (TemStr);
 | |
|     if ((Index & 1) == 0) {
 | |
|       Buf [Index/2] = DigitUint8;
 | |
|     } else {
 | |
|       Buf [Index/2] = (UINT8) ((DigitUint8 << 4) + Buf [Index/2]);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Set the converted value and string length.
 | |
|   //
 | |
|   *ValueData    = Buf;
 | |
|   *ValueLength  = Length;
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get value from config request resp string.
 | |
| 
 | |
|   @param ConfigElement           ConfigResp string contains the current setting.
 | |
|   @param VarName                 The variable name which need to get value.
 | |
|   @param VarValue                The return value.
 | |
| 
 | |
|   @retval EFI_SUCCESS            Get the value for the VarName
 | |
|   @retval EFI_OUT_OF_RESOURCES   The memory is not enough.
 | |
| **/
 | |
| EFI_STATUS
 | |
| GetValueFromRequest (
 | |
|   IN CHAR16                       *ConfigElement,
 | |
|   IN CHAR16                       *VarName,
 | |
|   OUT UINT64                      *VarValue
 | |
|   )
 | |
| {
 | |
|   UINT8                        *TmpBuffer;
 | |
|   CHAR16                       *StringPtr;
 | |
|   UINTN                        Length;
 | |
|   EFI_STATUS                   Status;
 | |
| 
 | |
|   //
 | |
|   // Find VarName related string.
 | |
|   //
 | |
|   StringPtr = StrStr (ConfigElement, VarName);
 | |
|   ASSERT (StringPtr != NULL);
 | |
| 
 | |
|   //
 | |
|   // Skip the "VarName=" string
 | |
|   //
 | |
|   StringPtr += StrLen (VarName) + 1;
 | |
| 
 | |
|   //
 | |
|   // Get Offset
 | |
|   //
 | |
|   Status = InternalHiiGetValueOfNumber (StringPtr, &TmpBuffer, &Length);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   *VarValue = 0;
 | |
|   CopyMem (VarValue, TmpBuffer, (((Length + 1) / 2) < sizeof (UINT64)) ? ((Length + 1) / 2) : sizeof (UINT64));
 | |
| 
 | |
|   FreePool (TmpBuffer);
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This internal function parses IFR data to validate current setting.
 | |
| 
 | |
|   Base on the NameValueType, if it is TRUE, RequestElement and HiiHandle is valid;
 | |
|   else the VarBuffer and CurrentBlockArray is valid.
 | |
| 
 | |
|   @param HiiPackageList     Point to Hii package list.
 | |
|   @param PackageListLength  The length of the pacakge.
 | |
|   @param VarGuid            Guid of the buffer storage.
 | |
|   @param VarName            Name of the buffer storage.
 | |
|   @param VarBuffer          The data buffer for the storage.
 | |
|   @param CurrentBlockArray  The block array from the config Requst string.
 | |
|   @param RequestElement     The config string for this storage.
 | |
|   @param HiiHandle          The HiiHandle for this formset.
 | |
|   @param NameValueType      Whether current storage is name/value varstore or not.
 | |
| 
 | |
|   @retval EFI_SUCCESS            The current setting is valid.
 | |
|   @retval EFI_OUT_OF_RESOURCES   The memory is not enough.
 | |
|   @retval EFI_INVALID_PARAMETER  The config string or the Hii package is invalid.
 | |
| **/
 | |
| EFI_STATUS
 | |
| ValidateQuestionFromVfr (
 | |
|   IN EFI_HII_PACKAGE_LIST_HEADER   *HiiPackageList,
 | |
|   IN UINTN                         PackageListLength,
 | |
|   IN EFI_GUID                      *VarGuid,
 | |
|   IN CHAR16                        *VarName,
 | |
|   IN UINT8                         *VarBuffer,
 | |
|   IN IFR_BLOCK_DATA                *CurrentBlockArray,
 | |
|   IN CHAR16                        *RequestElement,
 | |
|   IN EFI_HII_HANDLE                HiiHandle,
 | |
|   IN BOOLEAN                       NameValueType
 | |
|   )
 | |
| {
 | |
|   IFR_BLOCK_DATA               VarBlockData;
 | |
|   UINT16                       Offset;
 | |
|   UINT16                       Width;
 | |
|   UINT64                       VarValue;
 | |
|   EFI_IFR_TYPE_VALUE           TmpValue;
 | |
|   EFI_STATUS                   Status;
 | |
|   EFI_HII_PACKAGE_HEADER       PackageHeader;
 | |
|   UINT32                       PackageOffset;
 | |
|   UINT8                        *PackageData;
 | |
|   UINTN                        IfrOffset;
 | |
|   EFI_IFR_OP_HEADER            *IfrOpHdr;
 | |
|   EFI_IFR_VARSTORE             *IfrVarStore;
 | |
|   EFI_IFR_VARSTORE_NAME_VALUE  *IfrNameValueStore;
 | |
|   EFI_IFR_VARSTORE_EFI         *IfrEfiVarStore;
 | |
|   IFR_VARSTORAGE_DATA          VarStoreData;
 | |
|   EFI_IFR_ONE_OF               *IfrOneOf;
 | |
|   EFI_IFR_NUMERIC              *IfrNumeric;
 | |
|   EFI_IFR_ONE_OF_OPTION        *IfrOneOfOption;
 | |
|   EFI_IFR_CHECKBOX             *IfrCheckBox;
 | |
|   EFI_IFR_STRING               *IfrString;
 | |
|   CHAR8                        *VarStoreName;
 | |
|   UINTN                        Index;
 | |
|   CHAR16                       *QuestionName;
 | |
|   CHAR16                       *StringPtr;
 | |
|   UINT16                       BitOffset;
 | |
|   UINT16                       BitWidth;
 | |
|   UINT16                       TotalBits;
 | |
|   UINTN                        StartBit;
 | |
|   UINTN                        EndBit;
 | |
|   BOOLEAN                      QuestionReferBitField;
 | |
|   UINT32                       BufferValue;
 | |
| 
 | |
|   //
 | |
|   // Initialize the local variables.
 | |
|   //
 | |
|   Index             = 0;
 | |
|   VarStoreName      = NULL;
 | |
|   Status            = EFI_SUCCESS;
 | |
|   VarValue          = 0;
 | |
|   IfrVarStore       = NULL;
 | |
|   IfrNameValueStore = NULL;
 | |
|   IfrEfiVarStore    = NULL;
 | |
|   ZeroMem (&VarStoreData, sizeof (IFR_VARSTORAGE_DATA));
 | |
|   ZeroMem (&VarBlockData, sizeof (VarBlockData));
 | |
|   BitOffset = 0;
 | |
|   BitWidth = 0;
 | |
|   QuestionReferBitField = FALSE;
 | |
| 
 | |
|   //
 | |
|   // Check IFR value is in block data, then Validate Value
 | |
|   //
 | |
|   PackageOffset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
 | |
|   while (PackageOffset < PackageListLength) {
 | |
|     CopyMem (&PackageHeader, (UINT8 *) HiiPackageList + PackageOffset, sizeof (PackageHeader));
 | |
| 
 | |
|     //
 | |
|     // Parse IFR opcode from the form package.
 | |
|     //
 | |
|     if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) {
 | |
|       IfrOffset   = sizeof (PackageHeader);
 | |
|       PackageData = (UINT8 *) HiiPackageList + PackageOffset;
 | |
|       while (IfrOffset < PackageHeader.Length) {
 | |
|         IfrOpHdr = (EFI_IFR_OP_HEADER *) (PackageData + IfrOffset);
 | |
|         //
 | |
|         // Validate current setting to the value built in IFR opcode
 | |
|         //
 | |
|         switch (IfrOpHdr->OpCode) {
 | |
|         case EFI_IFR_VARSTORE_OP:
 | |
|           //
 | |
|           // VarStoreId has been found. No further found.
 | |
|           //
 | |
|           if (VarStoreData.VarStoreId != 0) {
 | |
|             break;
 | |
|           }
 | |
|           //
 | |
|           // Find the matched VarStoreId to the input VarGuid and VarName
 | |
|           //
 | |
|           IfrVarStore = (EFI_IFR_VARSTORE *) IfrOpHdr;
 | |
|           if (CompareGuid ((EFI_GUID *) (VOID *) &IfrVarStore->Guid, VarGuid)) {
 | |
|             VarStoreName = (CHAR8 *) IfrVarStore->Name;
 | |
|             for (Index = 0; VarStoreName[Index] != 0; Index ++) {
 | |
|               if ((CHAR16) VarStoreName[Index] != VarName[Index]) {
 | |
|                 break;
 | |
|               }
 | |
|             }
 | |
|             //
 | |
|             // The matched VarStore is found.
 | |
|             //
 | |
|             if ((VarStoreName[Index] != 0) || (VarName[Index] != 0)) {
 | |
|               IfrVarStore = NULL;
 | |
|             }
 | |
|           } else {
 | |
|             IfrVarStore = NULL;
 | |
|           }
 | |
| 
 | |
|           if (IfrVarStore != NULL) {
 | |
|             VarStoreData.VarStoreId = IfrVarStore->VarStoreId;
 | |
|             VarStoreData.Size       = IfrVarStore->Size;
 | |
|           }
 | |
|           break;
 | |
|         case EFI_IFR_VARSTORE_NAME_VALUE_OP:
 | |
|           //
 | |
|           // VarStoreId has been found. No further found.
 | |
|           //
 | |
|           if (VarStoreData.VarStoreId != 0) {
 | |
|             break;
 | |
|           }
 | |
|           //
 | |
|           // Find the matched VarStoreId to the input VarGuid
 | |
|           //
 | |
|           IfrNameValueStore = (EFI_IFR_VARSTORE_NAME_VALUE *) IfrOpHdr;
 | |
|           if (!CompareGuid ((EFI_GUID *) (VOID *) &IfrNameValueStore->Guid, VarGuid)) {
 | |
|             IfrNameValueStore = NULL;
 | |
|           }
 | |
| 
 | |
|           if (IfrNameValueStore != NULL) {
 | |
|             VarStoreData.VarStoreId = IfrNameValueStore->VarStoreId;
 | |
|           }
 | |
|           break;
 | |
|         case EFI_IFR_VARSTORE_EFI_OP:
 | |
|           //
 | |
|           // VarStore is found. Don't need to search any more.
 | |
|           //
 | |
|           if (VarStoreData.VarStoreId != 0) {
 | |
|             break;
 | |
|           }
 | |
| 
 | |
|           IfrEfiVarStore = (EFI_IFR_VARSTORE_EFI *) IfrOpHdr;
 | |
| 
 | |
|           //
 | |
|           // If the length is small than the structure, this is from old efi
 | |
|           // varstore definition. Old efi varstore get config directly from
 | |
|           // GetVariable function.
 | |
|           //
 | |
|           if (IfrOpHdr->Length < sizeof (EFI_IFR_VARSTORE_EFI)) {
 | |
|             break;
 | |
|           }
 | |
| 
 | |
|           if (CompareGuid ((EFI_GUID *) (VOID *) &IfrEfiVarStore->Guid, VarGuid)) {
 | |
|             VarStoreName = (CHAR8 *) IfrEfiVarStore->Name;
 | |
|             for (Index = 0; VarStoreName[Index] != 0; Index ++) {
 | |
|               if ((CHAR16) VarStoreName[Index] != VarName[Index]) {
 | |
|                 break;
 | |
|               }
 | |
|             }
 | |
|             //
 | |
|             // The matched VarStore is found.
 | |
|             //
 | |
|             if ((VarStoreName[Index] != 0) || (VarName[Index] != 0)) {
 | |
|               IfrEfiVarStore = NULL;
 | |
|             }
 | |
|           } else {
 | |
|             IfrEfiVarStore = NULL;
 | |
|           }
 | |
| 
 | |
|           if (IfrEfiVarStore != NULL) {
 | |
|             //
 | |
|             // Find the matched VarStore
 | |
|             //
 | |
|             VarStoreData.VarStoreId = IfrEfiVarStore->VarStoreId;
 | |
|             VarStoreData.Size       = IfrEfiVarStore->Size;
 | |
|           }
 | |
|           break;
 | |
|         case EFI_IFR_FORM_OP:
 | |
|         case EFI_IFR_FORM_MAP_OP:
 | |
|           //
 | |
|           // Check the matched VarStoreId is found.
 | |
|           //
 | |
|           if (VarStoreData.VarStoreId == 0) {
 | |
|             return EFI_SUCCESS;
 | |
|           }
 | |
|           break;
 | |
|         case EFI_IFR_ONE_OF_OP:
 | |
|           //
 | |
|           // Check whether current value is the one of option.
 | |
|           //
 | |
| 
 | |
|           //
 | |
|           // OneOf question is not in IFR Form. This IFR form is not valid.
 | |
|           //
 | |
|           if (VarStoreData.VarStoreId == 0) {
 | |
|             return EFI_INVALID_PARAMETER;
 | |
|           }
 | |
|           //
 | |
|           // Check whether this question is for the requested varstore.
 | |
|           //
 | |
|           IfrOneOf = (EFI_IFR_ONE_OF *) IfrOpHdr;
 | |
|           if (IfrOneOf->Question.VarStoreId != VarStoreData.VarStoreId) {
 | |
|             break;
 | |
|           }
 | |
| 
 | |
|           if (NameValueType) {
 | |
|             QuestionName = HiiGetString (HiiHandle, IfrOneOf->Question.VarStoreInfo.VarName, NULL);
 | |
|             ASSERT (QuestionName != NULL);
 | |
| 
 | |
|             if (StrStr (RequestElement, QuestionName) == NULL) {
 | |
|               //
 | |
|               // This question is not in the current configuration string. Skip it.
 | |
|               //
 | |
|               break;
 | |
|             }
 | |
| 
 | |
|             Status = GetValueFromRequest (RequestElement, QuestionName, &VarValue);
 | |
|             if (EFI_ERROR (Status)) {
 | |
|               return Status;
 | |
|             }
 | |
|           } else {
 | |
|             //
 | |
|             // Get Offset by Question header and Width by DataType Flags
 | |
|             //
 | |
|             if (QuestionReferBitField) {
 | |
|               //
 | |
|               // Get the byte offset/width for bit field.
 | |
|               //
 | |
|               BitOffset = IfrOneOf->Question.VarStoreInfo.VarOffset;
 | |
|               BitWidth = IfrOneOf->Flags & EDKII_IFR_NUMERIC_SIZE_BIT;
 | |
|               Offset = BitOffset / 8;
 | |
|               TotalBits = BitOffset % 8 + BitWidth;
 | |
|               Width = (TotalBits % 8 == 0 ? TotalBits / 8: TotalBits / 8 + 1);
 | |
|             } else {
 | |
|               Offset = IfrOneOf->Question.VarStoreInfo.VarOffset;
 | |
|               Width  = (UINT16) (1 << (IfrOneOf->Flags & EFI_IFR_NUMERIC_SIZE));
 | |
|             }
 | |
|             //
 | |
|             // Check whether this question is in current block array.
 | |
|             //
 | |
|             if (!BlockArrayCheck (CurrentBlockArray, Offset, Width)) {
 | |
|               //
 | |
|               // This question is not in the current configuration string. Skip it.
 | |
|               //
 | |
|               break;
 | |
|             }
 | |
|             //
 | |
|             // Check this var question is in the var storage
 | |
|             //
 | |
|             if ((Offset + Width) > VarStoreData.Size) {
 | |
|               //
 | |
|               // This question exceeds the var store size.
 | |
|               //
 | |
|               return EFI_INVALID_PARAMETER;
 | |
|             }
 | |
| 
 | |
|             //
 | |
|             // Get the current value for oneof opcode
 | |
|             //
 | |
|             VarValue = 0;
 | |
|             if (QuestionReferBitField) {
 | |
|               //
 | |
|               // Get the value in bit fields.
 | |
|               //
 | |
|               StartBit = BitOffset % 8;
 | |
|               EndBit = StartBit + BitWidth - 1;
 | |
|               CopyMem ((UINT8 *) &BufferValue, VarBuffer + Offset, Width);
 | |
|               VarValue = BitFieldRead32 (BufferValue, StartBit, EndBit);
 | |
|             } else {
 | |
|               CopyMem (&VarValue, VarBuffer +  Offset, Width);
 | |
|             }
 | |
|           }
 | |
|           //
 | |
|           // Set Block Data, to be checked in the following Oneof option opcode.
 | |
|           //
 | |
|           VarBlockData.OpCode     = IfrOpHdr->OpCode;
 | |
|           VarBlockData.Scope      = IfrOpHdr->Scope;
 | |
|           break;
 | |
|         case EFI_IFR_NUMERIC_OP:
 | |
|           //
 | |
|           // Check the current value is in the numeric range.
 | |
|           //
 | |
| 
 | |
|           //
 | |
|           // Numeric question is not in IFR Form. This IFR form is not valid.
 | |
|           //
 | |
|           if (VarStoreData.VarStoreId == 0) {
 | |
|             return EFI_INVALID_PARAMETER;
 | |
|           }
 | |
|           //
 | |
|           // Check whether this question is for the requested varstore.
 | |
|           //
 | |
|           IfrNumeric = (EFI_IFR_NUMERIC *) IfrOpHdr;
 | |
|           if (IfrNumeric->Question.VarStoreId != VarStoreData.VarStoreId) {
 | |
|             break;
 | |
|           }
 | |
| 
 | |
|           if (NameValueType) {
 | |
|             QuestionName = HiiGetString (HiiHandle, IfrNumeric->Question.VarStoreInfo.VarName, NULL);
 | |
|             ASSERT (QuestionName != NULL);
 | |
| 
 | |
|             if (StrStr (RequestElement, QuestionName) == NULL) {
 | |
|               //
 | |
|               // This question is not in the current configuration string. Skip it.
 | |
|               //
 | |
|               break;
 | |
|             }
 | |
| 
 | |
|             Status = GetValueFromRequest (RequestElement, QuestionName, &VarValue);
 | |
|             if (EFI_ERROR (Status)) {
 | |
|               return Status;
 | |
|             }
 | |
|           } else {
 | |
|             //
 | |
|             // Get Offset by Question header and Width by DataType Flags
 | |
|             //
 | |
|             if (QuestionReferBitField) {
 | |
|               //
 | |
|               // Get the byte offset/width for bit field.
 | |
|               //
 | |
|               BitOffset = IfrNumeric->Question.VarStoreInfo.VarOffset;
 | |
|               BitWidth = IfrNumeric->Flags & EDKII_IFR_NUMERIC_SIZE_BIT;
 | |
|               Offset = BitOffset / 8;
 | |
|               TotalBits = BitOffset % 8 + BitWidth;
 | |
|               Width  = (TotalBits % 8 == 0 ? TotalBits / 8: TotalBits / 8 + 1);
 | |
|             } else {
 | |
|               Offset = IfrNumeric->Question.VarStoreInfo.VarOffset;
 | |
|               Width  = (UINT16) (1 << (IfrNumeric->Flags & EFI_IFR_NUMERIC_SIZE));
 | |
|             }
 | |
|             //
 | |
|             // Check whether this question is in current block array.
 | |
|             //
 | |
|             if (!BlockArrayCheck (CurrentBlockArray, Offset, Width)) {
 | |
|               //
 | |
|               // This question is not in the current configuration string. Skip it.
 | |
|               //
 | |
|               break;
 | |
|             }
 | |
|             //
 | |
|             // Check this var question is in the var storage
 | |
|             //
 | |
|             if ((Offset + Width) > VarStoreData.Size) {
 | |
|               //
 | |
|               // This question exceeds the var store size.
 | |
|               //
 | |
|               return EFI_INVALID_PARAMETER;
 | |
|             }
 | |
| 
 | |
|             //
 | |
|             // Check the current value is in the numeric range.
 | |
|             //
 | |
|             VarValue = 0;
 | |
|             if (QuestionReferBitField) {
 | |
|               //
 | |
|               // Get the value in the bit fields.
 | |
|               //
 | |
|               StartBit = BitOffset % 8;
 | |
|               EndBit = StartBit + BitWidth - 1;
 | |
|               CopyMem ((UINT8 *) &BufferValue, VarBuffer + Offset, Width);
 | |
|               VarValue = BitFieldRead32 (BufferValue, StartBit, EndBit);
 | |
|             } else {
 | |
|               CopyMem (&VarValue, VarBuffer +  Offset, Width);
 | |
|             }
 | |
|           }
 | |
|           if ( QuestionReferBitField) {
 | |
|              //
 | |
|              // Value in bit fields was stored as UINt32 type.
 | |
|              //
 | |
|              if ((IfrNumeric->Flags & EDKII_IFR_DISPLAY_BIT) == 0) {
 | |
|                if ((INT32) VarValue < (INT32) IfrNumeric->data.u32.MinValue || (INT32) VarValue > (INT32) IfrNumeric->data.u32.MaxValue) {
 | |
|                   //
 | |
|                   // Not in the valid range.
 | |
|                   //
 | |
|                   return EFI_INVALID_PARAMETER;
 | |
|                 }
 | |
|              } else {
 | |
|                if (VarValue < IfrNumeric->data.u32.MinValue || VarValue > IfrNumeric->data.u32.MaxValue) {
 | |
|                   //
 | |
|                   // Not in the valid range.
 | |
|                   //
 | |
|                   return EFI_INVALID_PARAMETER;
 | |
|                 }
 | |
|              }
 | |
|           } else {
 | |
|             if ((IfrNumeric->Flags & EFI_IFR_DISPLAY) == 0) {
 | |
|               switch (IfrNumeric->Flags & EFI_IFR_NUMERIC_SIZE) {
 | |
|               case EFI_IFR_NUMERIC_SIZE_1:
 | |
|                 if ((INT8) VarValue < (INT8) IfrNumeric->data.u8.MinValue || (INT8) VarValue > (INT8) IfrNumeric->data.u8.MaxValue) {
 | |
|                   //
 | |
|                   // Not in the valid range.
 | |
|                   //
 | |
|                   return EFI_INVALID_PARAMETER;
 | |
|                 }
 | |
|                 break;
 | |
|               case EFI_IFR_NUMERIC_SIZE_2:
 | |
|                 if ((INT16) VarValue < (INT16) IfrNumeric->data.u16.MinValue || (INT16) VarValue > (INT16) IfrNumeric->data.u16.MaxValue) {
 | |
|                   //
 | |
|                   // Not in the valid range.
 | |
|                   //
 | |
|                   return EFI_INVALID_PARAMETER;
 | |
|                 }
 | |
|                 break;
 | |
|               case EFI_IFR_NUMERIC_SIZE_4:
 | |
|                 if ((INT32) VarValue < (INT32) IfrNumeric->data.u32.MinValue || (INT32) VarValue > (INT32) IfrNumeric->data.u32.MaxValue) {
 | |
|                   //
 | |
|                   // Not in the valid range.
 | |
|                   //
 | |
|                   return EFI_INVALID_PARAMETER;
 | |
|                 }
 | |
|                 break;
 | |
|               case EFI_IFR_NUMERIC_SIZE_8:
 | |
|                 if ((INT64) VarValue < (INT64) IfrNumeric->data.u64.MinValue || (INT64) VarValue > (INT64) IfrNumeric->data.u64.MaxValue) {
 | |
|                   //
 | |
|                   // Not in the valid range.
 | |
|                   //
 | |
|                   return EFI_INVALID_PARAMETER;
 | |
|                 }
 | |
|                 break;
 | |
|               }
 | |
|             } else {
 | |
|               switch (IfrNumeric->Flags & EFI_IFR_NUMERIC_SIZE) {
 | |
|               case EFI_IFR_NUMERIC_SIZE_1:
 | |
|                 if ((UINT8) VarValue < IfrNumeric->data.u8.MinValue || (UINT8) VarValue > IfrNumeric->data.u8.MaxValue) {
 | |
|                   //
 | |
|                   // Not in the valid range.
 | |
|                   //
 | |
|                   return EFI_INVALID_PARAMETER;
 | |
|                 }
 | |
|                 break;
 | |
|               case EFI_IFR_NUMERIC_SIZE_2:
 | |
|                 if ((UINT16) VarValue < IfrNumeric->data.u16.MinValue || (UINT16) VarValue > IfrNumeric->data.u16.MaxValue) {
 | |
|                   //
 | |
|                   // Not in the valid range.
 | |
|                   //
 | |
|                   return EFI_INVALID_PARAMETER;
 | |
|                 }
 | |
|                 break;
 | |
|               case EFI_IFR_NUMERIC_SIZE_4:
 | |
|                 if ((UINT32) VarValue < IfrNumeric->data.u32.MinValue || (UINT32) VarValue > IfrNumeric->data.u32.MaxValue) {
 | |
|                   //
 | |
|                   // Not in the valid range.
 | |
|                   //
 | |
|                   return EFI_INVALID_PARAMETER;
 | |
|                 }
 | |
|                 break;
 | |
|               case EFI_IFR_NUMERIC_SIZE_8:
 | |
|                 if ((UINT64) VarValue < IfrNumeric->data.u64.MinValue || (UINT64) VarValue > IfrNumeric->data.u64.MaxValue) {
 | |
|                   //
 | |
|                   // Not in the valid range.
 | |
|                   //
 | |
|                   return EFI_INVALID_PARAMETER;
 | |
|                 }
 | |
|                 break;
 | |
|               }
 | |
|             }
 | |
|           }
 | |
|           break;
 | |
|         case EFI_IFR_CHECKBOX_OP:
 | |
|           //
 | |
|           // Check value is BOOLEAN type, only 0 and 1 is valid.
 | |
|           //
 | |
| 
 | |
|           //
 | |
|           // CheckBox question is not in IFR Form. This IFR form is not valid.
 | |
|           //
 | |
|           if (VarStoreData.VarStoreId == 0) {
 | |
|             return EFI_INVALID_PARAMETER;
 | |
|           }
 | |
| 
 | |
|           //
 | |
|           // Check whether this question is for the requested varstore.
 | |
|           //
 | |
|           IfrCheckBox = (EFI_IFR_CHECKBOX *) IfrOpHdr;
 | |
|           if (IfrCheckBox->Question.VarStoreId != VarStoreData.VarStoreId) {
 | |
|             break;
 | |
|           }
 | |
| 
 | |
|           if (NameValueType) {
 | |
|             QuestionName = HiiGetString (HiiHandle, IfrCheckBox->Question.VarStoreInfo.VarName, NULL);
 | |
|             ASSERT (QuestionName != NULL);
 | |
| 
 | |
|             if (StrStr (RequestElement, QuestionName) == NULL) {
 | |
|               //
 | |
|               // This question is not in the current configuration string. Skip it.
 | |
|               //
 | |
|               break;
 | |
|             }
 | |
| 
 | |
|             Status = GetValueFromRequest (RequestElement, QuestionName, &VarValue);
 | |
|             if (EFI_ERROR (Status)) {
 | |
|               return Status;
 | |
|             }
 | |
|           } else {
 | |
|             //
 | |
|             // Get Offset by Question header
 | |
|             //
 | |
|            if (QuestionReferBitField) {
 | |
|               //
 | |
|               // Get the byte offset/width for bit field.
 | |
|               //
 | |
|               BitOffset = IfrCheckBox->Question.VarStoreInfo.VarOffset;
 | |
|               BitWidth = 1;
 | |
|               Offset = BitOffset / 8;
 | |
|               TotalBits = BitOffset % 8 + BitWidth;
 | |
|               Width = (TotalBits % 8 == 0 ? TotalBits / 8: TotalBits / 8 + 1);
 | |
|             } else {
 | |
|               Offset = IfrCheckBox->Question.VarStoreInfo.VarOffset;
 | |
|               Width  = (UINT16) sizeof (BOOLEAN);
 | |
|             }
 | |
|             //
 | |
|             // Check whether this question is in current block array.
 | |
|             //
 | |
|             if (!BlockArrayCheck (CurrentBlockArray, Offset, Width)) {
 | |
|               //
 | |
|               // This question is not in the current configuration string. Skip it.
 | |
|               //
 | |
|               break;
 | |
|             }
 | |
|             //
 | |
|             // Check this var question is in the var storage
 | |
|             //
 | |
|             if ((Offset + Width) > VarStoreData.Size) {
 | |
|               //
 | |
|               // This question exceeds the var store size.
 | |
|               //
 | |
|               return EFI_INVALID_PARAMETER;
 | |
|             }
 | |
|             //
 | |
|             // Check the current value is in the numeric range.
 | |
|             //
 | |
|             VarValue = 0;
 | |
|             if (QuestionReferBitField) {
 | |
|               //
 | |
|               // Get the value in bit fields.
 | |
|               //
 | |
|               StartBit = BitOffset % 8;
 | |
|               EndBit = StartBit + BitWidth - 1;
 | |
|               CopyMem ((UINT8 *) &BufferValue, VarBuffer + Offset, Width);
 | |
|               VarValue = BitFieldRead32 (BufferValue, StartBit, EndBit);
 | |
|             } else {
 | |
|               CopyMem (&VarValue, VarBuffer +  Offset, Width);
 | |
|             }
 | |
|           }
 | |
|           //
 | |
|           // Boolean type, only 1 and 0 is valid.
 | |
|           //
 | |
|           if (VarValue > 1) {
 | |
|             return EFI_INVALID_PARAMETER;
 | |
|           }
 | |
|           break;
 | |
|         case EFI_IFR_STRING_OP:
 | |
|           //
 | |
|           // Check current string length is less than maxsize
 | |
|           //
 | |
| 
 | |
|           //
 | |
|           // CheckBox question is not in IFR Form. This IFR form is not valid.
 | |
|           //
 | |
|           if (VarStoreData.VarStoreId == 0) {
 | |
|             return EFI_INVALID_PARAMETER;
 | |
|           }
 | |
| 
 | |
|           //
 | |
|           // Check whether this question is for the requested varstore.
 | |
|           //
 | |
|           IfrString = (EFI_IFR_STRING *) IfrOpHdr;
 | |
|           if (IfrString->Question.VarStoreId != VarStoreData.VarStoreId) {
 | |
|             break;
 | |
|           }
 | |
|           //
 | |
|           // Get the Max size of the string.
 | |
|           //
 | |
|           Width  = (UINT16) (IfrString->MaxSize * sizeof (UINT16));
 | |
|           if (NameValueType) {
 | |
|             QuestionName = HiiGetString (HiiHandle, IfrString->Question.VarStoreInfo.VarName, NULL);
 | |
|             ASSERT (QuestionName != NULL);
 | |
| 
 | |
|             StringPtr = StrStr (RequestElement, QuestionName);
 | |
|             if (StringPtr == NULL) {
 | |
|               //
 | |
|               // This question is not in the current configuration string. Skip it.
 | |
|               //
 | |
|               break;
 | |
|             }
 | |
|             //
 | |
|             // Skip the VarName.
 | |
|             //
 | |
|             StringPtr += StrLen (QuestionName);
 | |
| 
 | |
|             //
 | |
|             // Skip the "=".
 | |
|             //
 | |
|             StringPtr += 1;
 | |
| 
 | |
|             //
 | |
|             // Check current string length is less than maxsize
 | |
|             // e.g Config String: "0041004200430044", Unicode String: "ABCD". Unicode String length = Config String length / 4.
 | |
|             // Config string format in UEFI spec.
 | |
|             // <NvConfig> ::= <Label>'='<String>
 | |
|             // <String> ::= [<Char>]+
 | |
|             // <Char> ::= <HexCh>4
 | |
|             //
 | |
|             if (StrLen (StringPtr) / 4 > IfrString->MaxSize) {
 | |
|               return EFI_INVALID_PARAMETER;
 | |
|             }
 | |
|           } else {
 | |
|             //
 | |
|             // Get Offset/Width by Question header and OneOf Flags
 | |
|             //
 | |
|             Offset = IfrString->Question.VarStoreInfo.VarOffset;
 | |
|             //
 | |
|             // Check whether this question is in current block array.
 | |
|             //
 | |
|             if (!BlockArrayCheck (CurrentBlockArray, Offset, Width)) {
 | |
|               //
 | |
|               // This question is not in the current configuration string. Skip it.
 | |
|               //
 | |
|               break;
 | |
|             }
 | |
|             //
 | |
|             // Check this var question is in the var storage
 | |
|             //
 | |
|             if ((Offset + Width) > VarStoreData.Size) {
 | |
|               //
 | |
|               // This question exceeds the var store size.
 | |
|               //
 | |
|               return EFI_INVALID_PARAMETER;
 | |
|             }
 | |
| 
 | |
|             //
 | |
|             // Check current string length is less than maxsize
 | |
|             //
 | |
|             if (StrLen ((CHAR16 *) (VarBuffer + Offset)) > IfrString->MaxSize) {
 | |
|               return EFI_INVALID_PARAMETER;
 | |
|             }
 | |
|           }
 | |
|           break;
 | |
|         case EFI_IFR_ONE_OF_OPTION_OP:
 | |
|           //
 | |
|           // Opcode Scope is zero. This one of option is not to be checked.
 | |
|           //
 | |
|           if (VarBlockData.Scope == 0) {
 | |
|             break;
 | |
|           }
 | |
| 
 | |
|           //
 | |
|           // Only check for OneOf and OrderList opcode
 | |
|           //
 | |
|           IfrOneOfOption = (EFI_IFR_ONE_OF_OPTION *) IfrOpHdr;
 | |
|           if (VarBlockData.OpCode == EFI_IFR_ONE_OF_OP) {
 | |
|             //
 | |
|             // Check current value is the value of one of option.
 | |
|             //
 | |
|             ASSERT (IfrOneOfOption->Type <= EFI_IFR_TYPE_NUM_SIZE_64);
 | |
|             ZeroMem (&TmpValue, sizeof (EFI_IFR_TYPE_VALUE));
 | |
|             CopyMem (&TmpValue, &IfrOneOfOption->Value, IfrOneOfOption->Header.Length - OFFSET_OF (EFI_IFR_ONE_OF_OPTION, Value));
 | |
|             if (VarValue == TmpValue.u64) {
 | |
|               //
 | |
|               // The value is one of option value.
 | |
|               // Set OpCode to Zero, don't need check again.
 | |
|               //
 | |
|               VarBlockData.OpCode = 0;
 | |
|             }
 | |
|           }
 | |
|           break;
 | |
|         case EFI_IFR_END_OP:
 | |
|           QuestionReferBitField = FALSE;
 | |
|           //
 | |
|           // Decrease opcode scope for the validated opcode
 | |
|           //
 | |
|           if (VarBlockData.Scope > 0) {
 | |
|             VarBlockData.Scope --;
 | |
|           }
 | |
| 
 | |
|           //
 | |
|           // OneOf value doesn't belong to one of option value.
 | |
|           //
 | |
|           if ((VarBlockData.Scope == 0) && (VarBlockData.OpCode == EFI_IFR_ONE_OF_OP)) {
 | |
|             return EFI_INVALID_PARAMETER;
 | |
|           }
 | |
|           break;
 | |
|         case EFI_IFR_GUID_OP:
 | |
|           if (CompareGuid ((EFI_GUID *)((UINT8*)IfrOpHdr + sizeof (EFI_IFR_OP_HEADER)), &gEdkiiIfrBitVarstoreGuid)) {
 | |
|             QuestionReferBitField = TRUE;
 | |
|           }
 | |
|           break;
 | |
|         default:
 | |
|           //
 | |
|           // Increase Scope for the validated opcode
 | |
|           //
 | |
|           if (VarBlockData.Scope > 0) {
 | |
|             VarBlockData.Scope = (UINT8) (VarBlockData.Scope + IfrOpHdr->Scope);
 | |
|           }
 | |
|           break;
 | |
|         }
 | |
|         //
 | |
|         // Go to the next opcode
 | |
|         //
 | |
|         IfrOffset += IfrOpHdr->Length;
 | |
|       }
 | |
|       //
 | |
|       // Only one form is in a package list.
 | |
|       //
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Go to next package.
 | |
|     //
 | |
|     PackageOffset += PackageHeader.Length;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This internal function parses IFR data to validate current setting.
 | |
| 
 | |
|   @param ConfigElement         ConfigResp element string contains the current setting.
 | |
|   @param CurrentBlockArray     Current block array.
 | |
|   @param VarBuffer             Data buffer for this varstore.
 | |
| 
 | |
|   @retval EFI_SUCCESS            The current setting is valid.
 | |
|   @retval EFI_OUT_OF_RESOURCES   The memory is not enough.
 | |
|   @retval EFI_INVALID_PARAMETER  The config string or the Hii package is invalid.
 | |
| **/
 | |
| EFI_STATUS
 | |
| GetBlockDataInfo (
 | |
|   IN  CHAR16                        *ConfigElement,
 | |
|   OUT IFR_BLOCK_DATA                **CurrentBlockArray,
 | |
|   OUT UINT8                         **VarBuffer
 | |
|   )
 | |
| {
 | |
|   IFR_BLOCK_DATA               *BlockData;
 | |
|   IFR_BLOCK_DATA               *NewBlockData;
 | |
|   EFI_STRING                   StringPtr;
 | |
|   UINTN                        Length;
 | |
|   UINT8                        *TmpBuffer;
 | |
|   UINT16                       Offset;
 | |
|   UINT16                       Width;
 | |
|   LIST_ENTRY                   *Link;
 | |
|   UINTN                        MaxBufferSize;
 | |
|   EFI_STATUS                   Status;
 | |
|   IFR_BLOCK_DATA               *BlockArray;
 | |
|   UINT8                        *DataBuffer;
 | |
| 
 | |
|   //
 | |
|   // Initialize the local variables.
 | |
|   //
 | |
|   Status        = EFI_SUCCESS;
 | |
|   BlockData     = NULL;
 | |
|   NewBlockData  = NULL;
 | |
|   TmpBuffer     = NULL;
 | |
|   BlockArray    = NULL;
 | |
|   MaxBufferSize = HII_LIB_DEFAULT_VARSTORE_SIZE;
 | |
|   DataBuffer     = AllocateZeroPool (MaxBufferSize);
 | |
|   if (DataBuffer == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Init BlockArray
 | |
|   //
 | |
|   BlockArray = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
 | |
|   if (BlockArray == NULL) {
 | |
|     Status = EFI_OUT_OF_RESOURCES;
 | |
|     goto Done;
 | |
|   }
 | |
|   InitializeListHead (&BlockArray->Entry);
 | |
| 
 | |
|   StringPtr = StrStr (ConfigElement, L"&OFFSET=");
 | |
|   ASSERT (StringPtr != NULL);
 | |
| 
 | |
|   //
 | |
|   // Parse each <RequestElement> if exists
 | |
|   // Only <BlockName> format is supported by this help function.
 | |
|   // <BlockName> ::= &'OFFSET='<Number>&'WIDTH='<Number>
 | |
|   //
 | |
|   while (*StringPtr != 0 && StrnCmp (StringPtr, L"&OFFSET=", StrLen (L"&OFFSET=")) == 0) {
 | |
|     //
 | |
|     // Skip the &OFFSET= string
 | |
|     //
 | |
|     StringPtr += StrLen (L"&OFFSET=");
 | |
| 
 | |
|     //
 | |
|     // Get Offset
 | |
|     //
 | |
|     Status = InternalHiiGetValueOfNumber (StringPtr, &TmpBuffer, &Length);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto Done;
 | |
|     }
 | |
|     Offset = 0;
 | |
|     CopyMem (
 | |
|       &Offset,
 | |
|       TmpBuffer,
 | |
|       (((Length + 1) / 2) < sizeof (UINT16)) ? ((Length + 1) / 2) : sizeof (UINT16)
 | |
|       );
 | |
|     FreePool (TmpBuffer);
 | |
|     TmpBuffer = NULL;
 | |
| 
 | |
|     StringPtr += Length;
 | |
|     if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {
 | |
|       Status = EFI_INVALID_PARAMETER;
 | |
|       goto Done;
 | |
|     }
 | |
|     StringPtr += StrLen (L"&WIDTH=");
 | |
| 
 | |
|     //
 | |
|     // Get Width
 | |
|     //
 | |
|     Status = InternalHiiGetValueOfNumber (StringPtr, &TmpBuffer, &Length);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto Done;
 | |
|     }
 | |
|     Width = 0;
 | |
|     CopyMem (
 | |
|       &Width,
 | |
|       TmpBuffer,
 | |
|       (((Length + 1) / 2) < sizeof (UINT16)) ? ((Length + 1) / 2) : sizeof (UINT16)
 | |
|       );
 | |
|     FreePool (TmpBuffer);
 | |
|     TmpBuffer = NULL;
 | |
| 
 | |
|     StringPtr += Length;
 | |
|     if (*StringPtr != 0 && *StringPtr != L'&') {
 | |
|       Status = EFI_INVALID_PARAMETER;
 | |
|       goto Done;
 | |
|     }
 | |
| 
 | |
|     if (StrnCmp (StringPtr, L"&VALUE=", StrLen (L"&VALUE=")) != 0) {
 | |
|       Status = EFI_INVALID_PARAMETER;
 | |
|       goto Done;
 | |
|     }
 | |
|     StringPtr += StrLen (L"&VALUE=");
 | |
| 
 | |
|     //
 | |
|     // Get Value
 | |
|     //
 | |
|     Status = InternalHiiGetValueOfNumber (StringPtr, &TmpBuffer, &Length);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto Done;
 | |
|     }
 | |
| 
 | |
|     StringPtr += Length;
 | |
|     if (*StringPtr != 0 && *StringPtr != L'&') {
 | |
|       Status = EFI_INVALID_PARAMETER;
 | |
|       goto Done;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Check whether VarBuffer is enough
 | |
|     //
 | |
|     if ((UINT32)Offset + Width > MaxBufferSize) {
 | |
|       DataBuffer = ReallocatePool (
 | |
|                     MaxBufferSize,
 | |
|                     Offset + Width + HII_LIB_DEFAULT_VARSTORE_SIZE,
 | |
|                     DataBuffer
 | |
|                     );
 | |
|       if (DataBuffer == NULL) {
 | |
|         Status = EFI_OUT_OF_RESOURCES;
 | |
|         goto Done;
 | |
|       }
 | |
|       MaxBufferSize = Offset + Width + HII_LIB_DEFAULT_VARSTORE_SIZE;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Update the Block with configuration info
 | |
|     //
 | |
|     CopyMem (DataBuffer + Offset, TmpBuffer, Width);
 | |
|     FreePool (TmpBuffer);
 | |
|     TmpBuffer = NULL;
 | |
| 
 | |
|     //
 | |
|     // Set new Block Data
 | |
|     //
 | |
|     NewBlockData = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
 | |
|     if (NewBlockData == NULL) {
 | |
|       Status = EFI_OUT_OF_RESOURCES;
 | |
|       goto Done;
 | |
|     }
 | |
|     NewBlockData->Offset = Offset;
 | |
|     NewBlockData->Width  = Width;
 | |
| 
 | |
|     //
 | |
|     // Insert the new block data into the block data array.
 | |
|     //
 | |
|     for (Link = BlockArray->Entry.ForwardLink; Link != &BlockArray->Entry; Link = Link->ForwardLink) {
 | |
|       BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
 | |
|       if (NewBlockData->Offset == BlockData->Offset) {
 | |
|         if (NewBlockData->Width > BlockData->Width) {
 | |
|           BlockData->Width = NewBlockData->Width;
 | |
|         }
 | |
|         FreePool (NewBlockData);
 | |
|         break;
 | |
|       } else if (NewBlockData->Offset < BlockData->Offset) {
 | |
|         //
 | |
|         // Insert new block data as the previous one of this link.
 | |
|         //
 | |
|         InsertTailList (Link, &NewBlockData->Entry);
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Insert new block data into the array tail.
 | |
|     //
 | |
|     if (Link == &BlockArray->Entry) {
 | |
|       InsertTailList (Link, &NewBlockData->Entry);
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // If '\0', parsing is finished.
 | |
|     //
 | |
|     if (*StringPtr == 0) {
 | |
|       break;
 | |
|     }
 | |
|     //
 | |
|     // Go to next ConfigBlock
 | |
|     //
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Merge the aligned block data into the single block data.
 | |
|   //
 | |
|   Link = BlockArray->Entry.ForwardLink;
 | |
|   while ((Link != &BlockArray->Entry) && (Link->ForwardLink != &BlockArray->Entry)) {
 | |
|     BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
 | |
|     NewBlockData = BASE_CR (Link->ForwardLink, IFR_BLOCK_DATA, Entry);
 | |
|     if ((NewBlockData->Offset >= BlockData->Offset) && (NewBlockData->Offset <= (BlockData->Offset + BlockData->Width))) {
 | |
|       if ((NewBlockData->Offset + NewBlockData->Width) > (BlockData->Offset + BlockData->Width)) {
 | |
|         BlockData->Width = (UINT16) (NewBlockData->Offset + NewBlockData->Width - BlockData->Offset);
 | |
|       }
 | |
|       RemoveEntryList (Link->ForwardLink);
 | |
|       FreePool (NewBlockData);
 | |
|       continue;
 | |
|     }
 | |
|     Link = Link->ForwardLink;
 | |
|   }
 | |
| 
 | |
|   *VarBuffer         = DataBuffer;
 | |
|   *CurrentBlockArray = BlockArray;
 | |
|   return EFI_SUCCESS;
 | |
| 
 | |
| Done:
 | |
|   if (DataBuffer != NULL) {
 | |
|     FreePool (DataBuffer);
 | |
|   }
 | |
| 
 | |
|   if (BlockArray != NULL) {
 | |
|     //
 | |
|     // Free Link Array CurrentBlockArray
 | |
|     //
 | |
|     while (!IsListEmpty (&BlockArray->Entry)) {
 | |
|       BlockData = BASE_CR (BlockArray->Entry.ForwardLink, IFR_BLOCK_DATA, Entry);
 | |
|       RemoveEntryList (&BlockData->Entry);
 | |
|       FreePool (BlockData);
 | |
|     }
 | |
|     FreePool (BlockArray);
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This internal function parses IFR data to validate current setting.
 | |
| 
 | |
|   @param ConfigResp         ConfigResp string contains the current setting.
 | |
|   @param HiiPackageList     Point to Hii package list.
 | |
|   @param PackageListLength  The length of the pacakge.
 | |
|   @param VarGuid            Guid of the buffer storage.
 | |
|   @param VarName            Name of the buffer storage.
 | |
|   @param HiiHandle          The HiiHandle for this package.
 | |
| 
 | |
|   @retval EFI_SUCCESS            The current setting is valid.
 | |
|   @retval EFI_OUT_OF_RESOURCES   The memory is not enough.
 | |
|   @retval EFI_INVALID_PARAMETER  The config string or the Hii package is invalid.
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| InternalHiiValidateCurrentSetting (
 | |
|   IN EFI_STRING                    ConfigResp,
 | |
|   IN EFI_HII_PACKAGE_LIST_HEADER   *HiiPackageList,
 | |
|   IN UINTN                         PackageListLength,
 | |
|   IN EFI_GUID                      *VarGuid,
 | |
|   IN CHAR16                        *VarName,
 | |
|   IN EFI_HII_HANDLE                HiiHandle
 | |
|   )
 | |
| {
 | |
|   CHAR16              *StringPtr;
 | |
|   EFI_STATUS          Status;
 | |
|   IFR_BLOCK_DATA      *CurrentBlockArray;
 | |
|   IFR_BLOCK_DATA      *BlockData;
 | |
|   UINT8               *VarBuffer;
 | |
|   BOOLEAN             NameValueType;
 | |
| 
 | |
|   CurrentBlockArray = NULL;
 | |
|   VarBuffer         = NULL;
 | |
|   StringPtr         = NULL;
 | |
|   Status            = EFI_SUCCESS;
 | |
| 
 | |
|   //
 | |
|   // If StringPtr != NULL, get the request elements.
 | |
|   //
 | |
|   if (StrStr (ConfigResp, L"&OFFSET=") != NULL) {
 | |
|     Status = GetBlockDataInfo(ConfigResp, &CurrentBlockArray, &VarBuffer);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
|     NameValueType = FALSE;
 | |
|   } else {
 | |
|     //
 | |
|     // Skip header part.
 | |
|     //
 | |
|     StringPtr = StrStr (ConfigResp, L"PATH=");
 | |
|     ASSERT (StringPtr != NULL);
 | |
| 
 | |
|     if (StrStr (StringPtr, L"&") != NULL) {
 | |
|       NameValueType = TRUE;
 | |
|     } else {
 | |
|       //
 | |
|       // Not found Request element, return success.
 | |
|       //
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   Status = ValidateQuestionFromVfr(
 | |
|                           HiiPackageList,
 | |
|                           PackageListLength,
 | |
|                           VarGuid,
 | |
|                           VarName,
 | |
|                           VarBuffer,
 | |
|                           CurrentBlockArray,
 | |
|                           ConfigResp,
 | |
|                           HiiHandle,
 | |
|                           NameValueType
 | |
|                           );
 | |
| 
 | |
|   if (VarBuffer != NULL) {
 | |
|     FreePool (VarBuffer);
 | |
|   }
 | |
| 
 | |
|   if (CurrentBlockArray != NULL) {
 | |
|     //
 | |
|     // Free Link Array CurrentBlockArray
 | |
|     //
 | |
|     while (!IsListEmpty (&CurrentBlockArray->Entry)) {
 | |
|       BlockData = BASE_CR (CurrentBlockArray->Entry.ForwardLink, IFR_BLOCK_DATA, Entry);
 | |
|       RemoveEntryList (&BlockData->Entry);
 | |
|       FreePool (BlockData);
 | |
|     }
 | |
|     FreePool (CurrentBlockArray);
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Check whether the ConfigRequest string has the request elements.
 | |
|   For EFI_HII_VARSTORE_BUFFER type, the request has "&OFFSET=****&WIDTH=****..." format.
 | |
|   For EFI_HII_VARSTORE_NAME_VALUE type, the request has "&NAME1**&NAME2..." format.
 | |
| 
 | |
|   @param  ConfigRequest      The input config request string.
 | |
| 
 | |
|   @retval  TRUE              The input include config request elements.
 | |
|   @retval  FALSE             The input string not includes.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| GetElementsFromRequest (
 | |
|   IN EFI_STRING    ConfigRequest
 | |
|   )
 | |
| {
 | |
|   EFI_STRING   TmpRequest;
 | |
| 
 | |
|   TmpRequest = StrStr (ConfigRequest, L"PATH=");
 | |
|   ASSERT (TmpRequest != NULL);
 | |
| 
 | |
|   if ((StrStr (TmpRequest, L"&OFFSET=") != NULL) || (StrStr (TmpRequest, L"&") != NULL)) {
 | |
|     return TRUE;
 | |
|   }
 | |
| 
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function parses the input ConfigRequest string and its matched IFR code
 | |
|   string for setting default value and validating current setting.
 | |
| 
 | |
|   1. For setting default action, Reset the default value specified by DefaultId
 | |
|   to the driver configuration got by Request string.
 | |
|   2. For validating current setting, Validate the current configuration
 | |
|   by parsing HII form IFR opcode.
 | |
| 
 | |
|   NULL request string support depends on the ExportConfig interface of
 | |
|   HiiConfigRouting protocol in UEFI specification.
 | |
| 
 | |
|   @param Request    A null-terminated Unicode string in
 | |
|                     <MultiConfigRequest> format. It can be NULL.
 | |
|                     If it is NULL, all current configuration for the
 | |
|                     entirety of the current HII database will be validated.
 | |
|                     If it is NULL, all configuration for the
 | |
|                     entirety of the current HII database will be reset.
 | |
|   @param DefaultId  Specifies the type of defaults to retrieve only for setting default action.
 | |
|   @param ActionType Action supports setting defaults and validate current setting.
 | |
| 
 | |
|   @retval TRUE    Action runs successfully.
 | |
|   @retval FALSE   Action is not valid or Action can't be executed successfully..
 | |
| **/
 | |
| BOOLEAN
 | |
| EFIAPI
 | |
| InternalHiiIfrValueAction (
 | |
|   IN CONST EFI_STRING Request,  OPTIONAL
 | |
|   IN UINT16           DefaultId,
 | |
|   IN UINT8            ActionType
 | |
|   )
 | |
| {
 | |
|   EFI_STRING     ConfigAltResp;
 | |
|   EFI_STRING     ConfigAltHdr;
 | |
|   EFI_STRING     ConfigResp;
 | |
|   EFI_STRING     Progress;
 | |
|   EFI_STRING     StringPtr;
 | |
|   EFI_STRING     StringHdr;
 | |
|   EFI_STATUS     Status;
 | |
|   EFI_HANDLE     DriverHandle;
 | |
|   EFI_HANDLE     TempDriverHandle;
 | |
|   EFI_HII_HANDLE *HiiHandleBuffer;
 | |
|   EFI_HII_HANDLE HiiHandle;
 | |
|   UINT32         Index;
 | |
|   EFI_GUID       *VarGuid;
 | |
|   EFI_STRING     VarName;
 | |
| 
 | |
|   EFI_HII_PACKAGE_LIST_HEADER  *HiiPackageList;
 | |
|   UINTN                        PackageListLength;
 | |
|   UINTN                        MaxLen;
 | |
|   EFI_DEVICE_PATH_PROTOCOL     *DevicePath;
 | |
|   EFI_DEVICE_PATH_PROTOCOL     *TempDevicePath;
 | |
| 
 | |
|   ConfigAltResp = NULL;
 | |
|   ConfigResp    = NULL;
 | |
|   VarGuid       = NULL;
 | |
|   VarName       = NULL;
 | |
|   DevicePath    = NULL;
 | |
|   ConfigAltHdr  = NULL;
 | |
|   HiiHandleBuffer  = NULL;
 | |
|   Index            = 0;
 | |
|   TempDriverHandle = NULL;
 | |
|   HiiHandle        = NULL;
 | |
|   HiiPackageList   = NULL;
 | |
| 
 | |
|   //
 | |
|   // Only support set default and validate setting action.
 | |
|   //
 | |
|   if ((ActionType != ACTION_SET_DEFAUTL_VALUE) && (ActionType != ACTION_VALIDATE_SETTING)) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Get the full requested value and deault value string.
 | |
|   //
 | |
|   if (Request != NULL) {
 | |
|     Status = gHiiConfigRouting->ExtractConfig (
 | |
|                                   gHiiConfigRouting,
 | |
|                                   Request,
 | |
|                                   &Progress,
 | |
|                                   &ConfigAltResp
 | |
|                                 );
 | |
|   } else {
 | |
|     Status = gHiiConfigRouting->ExportConfig (
 | |
|                                   gHiiConfigRouting,
 | |
|                                   &ConfigAltResp
 | |
|                                 );
 | |
|   }
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   StringPtr = ConfigAltResp;
 | |
|   ASSERT (StringPtr != NULL);
 | |
| 
 | |
|   while (*StringPtr != L'\0') {
 | |
|     //
 | |
|     // 1. Find <ConfigHdr> GUID=...&NAME=...&PATH=...
 | |
|     //
 | |
|     StringHdr = StringPtr;
 | |
| 
 | |
|     //
 | |
|     // Get Guid value
 | |
|     //
 | |
|     if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
 | |
|       Status = EFI_INVALID_PARAMETER;
 | |
|       goto Done;
 | |
|     }
 | |
|     StringPtr += StrLen (L"GUID=");
 | |
|     Status = InternalHiiGetBufferFromString (StringPtr, GUID_CONFIG_STRING_TYPE, (UINT8 **) &VarGuid);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto Done;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Get Name value VarName
 | |
|     //
 | |
|     while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&NAME=", StrLen (L"&NAME=")) != 0) {
 | |
|       StringPtr++;
 | |
|     }
 | |
|     if (*StringPtr == L'\0') {
 | |
|       Status = EFI_INVALID_PARAMETER;
 | |
|       goto Done;
 | |
|     }
 | |
|     StringPtr += StrLen (L"&NAME=");
 | |
|     Status = InternalHiiGetBufferFromString (StringPtr, NAME_CONFIG_STRING_TYPE, (UINT8 **) &VarName);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto Done;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Get Path value DevicePath
 | |
|     //
 | |
|     while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&PATH=", StrLen (L"&PATH=")) != 0) {
 | |
|       StringPtr++;
 | |
|     }
 | |
|     if (*StringPtr == L'\0') {
 | |
|       Status = EFI_INVALID_PARAMETER;
 | |
|       goto Done;
 | |
|     }
 | |
|     StringPtr += StrLen (L"&PATH=");
 | |
|     Status = InternalHiiGetBufferFromString (StringPtr, PATH_CONFIG_STRING_TYPE, (UINT8 **) &DevicePath);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto Done;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Get the Driver handle by the got device path.
 | |
|     //
 | |
|     TempDevicePath = DevicePath;
 | |
|     Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &TempDevicePath, &DriverHandle);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto Done;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Find the matched Hii Handle for the found Driver handle
 | |
|     //
 | |
|     HiiHandleBuffer = HiiGetHiiHandles (NULL);
 | |
|     if (HiiHandleBuffer == NULL) {
 | |
|       Status = EFI_NOT_FOUND;
 | |
|       goto Done;
 | |
|     }
 | |
| 
 | |
|     for (Index = 0; HiiHandleBuffer[Index] != NULL; Index ++) {
 | |
|       gHiiDatabase->GetPackageListHandle (gHiiDatabase, HiiHandleBuffer[Index], &TempDriverHandle);
 | |
|       if (TempDriverHandle == DriverHandle) {
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     HiiHandle = HiiHandleBuffer[Index];
 | |
|     FreePool (HiiHandleBuffer);
 | |
| 
 | |
|     if (HiiHandle == NULL) {
 | |
|       //
 | |
|       // This request string has no its Hii package.
 | |
|       // Its default value and validating can't execute by parsing IFR data.
 | |
|       // Directly jump into the next ConfigAltResp string for another pair Guid, Name, and Path.
 | |
|       //
 | |
|       Status = EFI_SUCCESS;
 | |
|       goto NextConfigAltResp;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // 2. Get HiiPackage by HiiHandle
 | |
|     //
 | |
|     PackageListLength  = 0;
 | |
|     HiiPackageList     = NULL;
 | |
|     Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, HiiHandle, &PackageListLength, HiiPackageList);
 | |
| 
 | |
|     //
 | |
|     // The return status should always be EFI_BUFFER_TOO_SMALL as input buffer's size is 0.
 | |
|     //
 | |
|     if (Status != EFI_BUFFER_TOO_SMALL) {
 | |
|       Status = EFI_INVALID_PARAMETER;
 | |
|       goto Done;
 | |
|     }
 | |
| 
 | |
|     HiiPackageList = AllocatePool (PackageListLength);
 | |
|     if (HiiPackageList == NULL) {
 | |
|       Status = EFI_OUT_OF_RESOURCES;
 | |
|       goto Done;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Get PackageList on HiiHandle
 | |
|     //
 | |
|     Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, HiiHandle, &PackageListLength, HiiPackageList);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto Done;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // 3. Call ConfigRouting GetAltCfg(ConfigRoute, <ConfigResponse>, Guid, Name, DevicePath, AltCfgId, AltCfgResp)
 | |
|     //    Get the default configuration string according to the default ID.
 | |
|     //
 | |
|     Status = gHiiConfigRouting->GetAltConfig (
 | |
|                                   gHiiConfigRouting,
 | |
|                                   ConfigAltResp,
 | |
|                                   VarGuid,
 | |
|                                   VarName,
 | |
|                                   DevicePath,
 | |
|                                   (ActionType == ACTION_SET_DEFAUTL_VALUE) ? &DefaultId:NULL,  // it can be NULL to get the current setting.
 | |
|                                   &ConfigResp
 | |
|                                 );
 | |
| 
 | |
|     //
 | |
|     // The required setting can't be found. So, it is not required to be validated and set.
 | |
|     //
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       Status = EFI_SUCCESS;
 | |
|       goto NextConfigAltResp;
 | |
|     }
 | |
|     //
 | |
|     // Only the ConfigHdr is found. Not any block data is found. No data is required to be validated and set.
 | |
|     //
 | |
|     if (!GetElementsFromRequest (ConfigResp)) {
 | |
|       goto NextConfigAltResp;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // 4. Set the default configuration information or Validate current setting by parse IFR code.
 | |
|     //    Current Setting is in ConfigResp, will be set into buffer, then check it again.
 | |
|     //
 | |
|     if (ActionType == ACTION_SET_DEFAUTL_VALUE) {
 | |
|       //
 | |
|       // Set the default configuration information.
 | |
|       //
 | |
|       Status = gHiiConfigRouting->RouteConfig (gHiiConfigRouting, ConfigResp, &Progress);
 | |
|     } else {
 | |
|       //
 | |
|       // Current Setting is in ConfigResp, will be set into buffer, then check it again.
 | |
|       //
 | |
|       Status = InternalHiiValidateCurrentSetting (ConfigResp, HiiPackageList, PackageListLength, VarGuid, VarName, HiiHandle);
 | |
|     }
 | |
| 
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto Done;
 | |
|     }
 | |
| 
 | |
| NextConfigAltResp:
 | |
|     //
 | |
|     // Free the allocated pacakge buffer and the got ConfigResp string.
 | |
|     //
 | |
|     if (HiiPackageList != NULL) {
 | |
|       FreePool (HiiPackageList);
 | |
|       HiiPackageList = NULL;
 | |
|     }
 | |
| 
 | |
|     if (ConfigResp != NULL) {
 | |
|       FreePool (ConfigResp);
 | |
|       ConfigResp = NULL;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Free the allocated buffer.
 | |
|     //
 | |
|     FreePool (VarGuid);
 | |
|     VarGuid = NULL;
 | |
| 
 | |
|     FreePool (VarName);
 | |
|     VarName = NULL;
 | |
| 
 | |
|     FreePool (DevicePath);
 | |
|     DevicePath = NULL;
 | |
| 
 | |
|     //
 | |
|     // 5. Jump to next ConfigAltResp for another Guid, Name, Path.
 | |
|     //
 | |
| 
 | |
|     //
 | |
|     // Get and Skip ConfigHdr
 | |
|     //
 | |
|     while (*StringPtr != L'\0' && *StringPtr != L'&') {
 | |
|       StringPtr++;
 | |
|     }
 | |
|     if (*StringPtr == L'\0') {
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Construct ConfigAltHdr string  "&<ConfigHdr>&ALTCFG=\0"
 | |
|     //                               | 1 | StrLen (ConfigHdr) | 8 | 1 |
 | |
|     //
 | |
|     MaxLen = 1 + StringPtr - StringHdr + 8 + 1;
 | |
|     ConfigAltHdr = AllocateZeroPool ( MaxLen * sizeof (CHAR16));
 | |
|     if (ConfigAltHdr == NULL) {
 | |
|       Status = EFI_OUT_OF_RESOURCES;
 | |
|       goto Done;
 | |
|     }
 | |
|     StrCpyS (ConfigAltHdr, MaxLen, L"&");
 | |
|     StrnCatS (ConfigAltHdr, MaxLen, StringHdr, StringPtr - StringHdr);
 | |
|     StrCatS (ConfigAltHdr, MaxLen, L"&ALTCFG=");
 | |
| 
 | |
|     //
 | |
|     // Skip all AltResp (AltConfigHdr ConfigBody) for the same ConfigHdr
 | |
|     //
 | |
|     while ((StringHdr = StrStr (StringPtr, ConfigAltHdr)) != NULL) {
 | |
|       StringPtr = StringHdr + StrLen (ConfigAltHdr);
 | |
|       if (*StringPtr == L'\0') {
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Free the allocated ConfigAltHdr string
 | |
|     //
 | |
|     FreePool (ConfigAltHdr);
 | |
|     if (*StringPtr == L'\0') {
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Find &GUID as the next ConfigHdr
 | |
|     //
 | |
|     StringPtr = StrStr (StringPtr, L"&GUID");
 | |
|     if (StringPtr == NULL) {
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Skip char '&'
 | |
|     //
 | |
|     StringPtr ++;
 | |
|   }
 | |
| 
 | |
| Done:
 | |
|   if (VarGuid != NULL) {
 | |
|     FreePool (VarGuid);
 | |
|   }
 | |
| 
 | |
|   if (VarName != NULL) {
 | |
|     FreePool (VarName);
 | |
|   }
 | |
| 
 | |
|   if (DevicePath != NULL) {
 | |
|     FreePool (DevicePath);
 | |
|   }
 | |
| 
 | |
|   if (ConfigResp != NULL) {
 | |
|     FreePool (ConfigResp);
 | |
|   }
 | |
| 
 | |
|   if (ConfigAltResp != NULL) {
 | |
|     FreePool (ConfigAltResp);
 | |
|   }
 | |
| 
 | |
|   if (HiiPackageList != NULL) {
 | |
|     FreePool (HiiPackageList);
 | |
|   }
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   return TRUE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Validate the current configuration by parsing HII form IFR opcode.
 | |
| 
 | |
|   NULL request string support depends on the ExportConfig interface of
 | |
|   HiiConfigRouting protocol in UEFI specification.
 | |
| 
 | |
|   @param  Request   A null-terminated Unicode string in
 | |
|                     <MultiConfigRequest> format. It can be NULL.
 | |
|                     If it is NULL, all current configuration for the
 | |
|                     entirety of the current HII database will be validated.
 | |
| 
 | |
|   @retval TRUE    Current configuration is valid.
 | |
|   @retval FALSE   Current configuration is invalid.
 | |
| **/
 | |
| BOOLEAN
 | |
| EFIAPI
 | |
| HiiValidateSettings (
 | |
|   IN CONST EFI_STRING Request  OPTIONAL
 | |
|   )
 | |
| {
 | |
|   return InternalHiiIfrValueAction (Request, 0, ACTION_VALIDATE_SETTING);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Reset the default value specified by DefaultId to the driver
 | |
|   configuration got by Request string.
 | |
| 
 | |
|   NULL request string support depends on the ExportConfig interface of
 | |
|   HiiConfigRouting protocol in UEFI specification.
 | |
| 
 | |
|   @param Request    A null-terminated Unicode string in
 | |
|                     <MultiConfigRequest> format. It can be NULL.
 | |
|                     If it is NULL, all configuration for the
 | |
|                     entirety of the current HII database will be reset.
 | |
|   @param DefaultId  Specifies the type of defaults to retrieve.
 | |
| 
 | |
|   @retval TRUE    The default value is set successfully.
 | |
|   @retval FALSE   The default value can't be found and set.
 | |
| **/
 | |
| BOOLEAN
 | |
| EFIAPI
 | |
| HiiSetToDefaults (
 | |
|   IN CONST EFI_STRING Request,  OPTIONAL
 | |
|   IN UINT16        DefaultId
 | |
|   )
 | |
| {
 | |
|   return InternalHiiIfrValueAction (Request, DefaultId, ACTION_SET_DEFAUTL_VALUE);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Determines if two values in config strings match.
 | |
| 
 | |
|   Compares the substring between StartSearchString and StopSearchString in
 | |
|   FirstString to the substring between StartSearchString and StopSearchString
 | |
|   in SecondString.  If the two substrings match, then TRUE is returned.  If the
 | |
|   two substrings do not match, then FALSE is returned.
 | |
| 
 | |
|   If FirstString is NULL, then ASSERT().
 | |
|   If SecondString is NULL, then ASSERT().
 | |
|   If StartSearchString is NULL, then ASSERT().
 | |
|   If StopSearchString is NULL, then ASSERT().
 | |
| 
 | |
|   @param FirstString        Pointer to the first Null-terminated Unicode string.
 | |
|   @param SecondString       Pointer to the second Null-terminated Unicode string.
 | |
|   @param StartSearchString  Pointer to the Null-terminated Unicode string that
 | |
|                             marks the start of the value string to compare.
 | |
|   @param StopSearchString   Pointer to the Null-terminated Unicode string that
 | |
|                             marks the end of the value string to compare.
 | |
| 
 | |
|   @retval FALSE             StartSearchString is not present in FirstString.
 | |
|   @retval FALSE             StartSearchString is not present in SecondString.
 | |
|   @retval FALSE             StopSearchString is not present in FirstString.
 | |
|   @retval FALSE             StopSearchString is not present in SecondString.
 | |
|   @retval FALSE             The length of the substring in FirstString is not the
 | |
|                             same length as the substring in SecondString.
 | |
|   @retval FALSE             The value string in FirstString does not matche the
 | |
|                             value string in SecondString.
 | |
|   @retval TRUE              The value string in FirstString matches the value
 | |
|                             string in SecondString.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| EFIAPI
 | |
| InternalHiiCompareSubString (
 | |
|   IN CHAR16  *FirstString,
 | |
|   IN CHAR16  *SecondString,
 | |
|   IN CHAR16  *StartSearchString,
 | |
|   IN CHAR16  *StopSearchString
 | |
|   )
 | |
| {
 | |
|   CHAR16  *EndFirstString;
 | |
|   CHAR16  *EndSecondString;
 | |
| 
 | |
|   ASSERT (FirstString != NULL);
 | |
|   ASSERT (SecondString != NULL);
 | |
|   ASSERT (StartSearchString != NULL);
 | |
|   ASSERT (StopSearchString != NULL);
 | |
| 
 | |
|   FirstString = StrStr (FirstString, StartSearchString);
 | |
|   if (FirstString == NULL) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   SecondString = StrStr (SecondString, StartSearchString);
 | |
|   if (SecondString == NULL) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   EndFirstString = StrStr (FirstString, StopSearchString);
 | |
|   if (EndFirstString == NULL) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   EndSecondString = StrStr (SecondString, StopSearchString);
 | |
|   if (EndSecondString == NULL) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   if ((EndFirstString - FirstString) != (EndSecondString - SecondString)) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   return (BOOLEAN)(StrnCmp (FirstString, SecondString, EndFirstString - FirstString) == 0);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Determines if the routing data specified by GUID and NAME match a <ConfigHdr>.
 | |
| 
 | |
|   If ConfigHdr is NULL, then ASSERT().
 | |
| 
 | |
|   @param[in] ConfigHdr  Either <ConfigRequest> or <ConfigResp>.
 | |
|   @param[in] Guid       GUID of the storage.
 | |
|   @param[in] Name       NAME of the storage.
 | |
| 
 | |
|   @retval TRUE   Routing information matches <ConfigHdr>.
 | |
|   @retval FALSE  Routing information does not match <ConfigHdr>.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| EFIAPI
 | |
| HiiIsConfigHdrMatch (
 | |
|   IN CONST EFI_STRING  ConfigHdr,
 | |
|   IN CONST EFI_GUID    *Guid,     OPTIONAL
 | |
|   IN CONST CHAR16      *Name      OPTIONAL
 | |
|   )
 | |
| {
 | |
|   EFI_STRING  CompareConfigHdr;
 | |
|   BOOLEAN     Result;
 | |
| 
 | |
|   ASSERT (ConfigHdr != NULL);
 | |
| 
 | |
|   //
 | |
|   // Use Guid and Name to generate a <ConfigHdr> string
 | |
|   //
 | |
|   CompareConfigHdr = HiiConstructConfigHdr (Guid, Name, NULL);
 | |
|   if (CompareConfigHdr == NULL) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   Result = TRUE;
 | |
|   if (Guid != NULL) {
 | |
|     //
 | |
|     // Compare GUID value strings
 | |
|     //
 | |
|     Result = InternalHiiCompareSubString (ConfigHdr, CompareConfigHdr, L"GUID=", L"&NAME=");
 | |
|   }
 | |
| 
 | |
|   if (Result && Name != NULL) {
 | |
|     //
 | |
|     // Compare NAME value strings
 | |
|     //
 | |
|     Result = InternalHiiCompareSubString (ConfigHdr, CompareConfigHdr, L"&NAME=", L"&PATH=");
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Free the <ConfigHdr> string
 | |
|   //
 | |
|   FreePool (CompareConfigHdr);
 | |
| 
 | |
|   return Result;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Retrieves uncommitted data from the Form Browser and converts it to a binary
 | |
|   buffer.
 | |
| 
 | |
|   @param[in]  VariableGuid  Pointer to an EFI_GUID structure.  This is an optional
 | |
|                             parameter that may be NULL.
 | |
|   @param[in]  VariableName  Pointer to a Null-terminated Unicode string.  This
 | |
|                             is an optional parameter that may be NULL.
 | |
|   @param[in]  BufferSize    Length in bytes of buffer to hold retrieved data.
 | |
|   @param[out] Buffer        Buffer of data to be updated.
 | |
| 
 | |
|   @retval FALSE  The uncommitted data could not be retrieved.
 | |
|   @retval TRUE   The uncommitted data was retrieved.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| EFIAPI
 | |
| HiiGetBrowserData (
 | |
|   IN CONST EFI_GUID  *VariableGuid,  OPTIONAL
 | |
|   IN CONST CHAR16    *VariableName,  OPTIONAL
 | |
|   IN UINTN           BufferSize,
 | |
|   OUT UINT8          *Buffer
 | |
|   )
 | |
| {
 | |
|   EFI_STRING  ResultsData;
 | |
|   UINTN       Size;
 | |
|   EFI_STRING  ConfigResp;
 | |
|   EFI_STATUS  Status;
 | |
|   CHAR16      *Progress;
 | |
| 
 | |
|   //
 | |
|   // Retrieve the results data from the Browser Callback
 | |
|   //
 | |
|   ResultsData = InternalHiiBrowserCallback (VariableGuid, VariableName, NULL);
 | |
|   if (ResultsData == NULL) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Construct <ConfigResp> mConfigHdrTemplate L'&' ResultsData L'\0'
 | |
|   //
 | |
|   Size = (StrLen (mConfigHdrTemplate) + 1) * sizeof (CHAR16);
 | |
|   Size = Size + (StrLen (ResultsData) + 1) * sizeof (CHAR16);
 | |
|   ConfigResp = AllocateZeroPool (Size);
 | |
|   UnicodeSPrint (ConfigResp, Size, L"%s&%s", mConfigHdrTemplate, ResultsData);
 | |
| 
 | |
|   //
 | |
|   // Free the allocated buffer
 | |
|   //
 | |
|   FreePool (ResultsData);
 | |
|   if (ConfigResp == NULL) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Convert <ConfigResp> to a buffer
 | |
|   //
 | |
|   Status = gHiiConfigRouting->ConfigToBlock (
 | |
|                                 gHiiConfigRouting,
 | |
|                                 ConfigResp,
 | |
|                                 Buffer,
 | |
|                                 &BufferSize,
 | |
|                                 &Progress
 | |
|                                 );
 | |
|   //
 | |
|   // Free the allocated buffer
 | |
|   //
 | |
|   FreePool (ConfigResp);
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   return TRUE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Updates uncommitted data in the Form Browser.
 | |
| 
 | |
|   If Buffer is NULL, then ASSERT().
 | |
| 
 | |
|   @param[in]  VariableGuid    Pointer to an EFI_GUID structure.  This is an optional
 | |
|                               parameter that may be NULL.
 | |
|   @param[in]  VariableName    Pointer to a Null-terminated Unicode string.  This
 | |
|                               is an optional parameter that may be NULL.
 | |
|   @param[in]  BufferSize      Length, in bytes, of Buffer.
 | |
|   @param[in]  Buffer          Buffer of data to commit.
 | |
|   @param[in]  RequestElement  An optional field to specify which part of the
 | |
|                               buffer data will be send back to Browser. If NULL,
 | |
|                               the whole buffer of data will be committed to
 | |
|                               Browser.
 | |
|                               <RequestElement> ::= &OFFSET=<Number>&WIDTH=<Number>*
 | |
| 
 | |
|   @retval FALSE  The uncommitted data could not be updated.
 | |
|   @retval TRUE   The uncommitted data was updated.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| EFIAPI
 | |
| HiiSetBrowserData (
 | |
|   IN CONST EFI_GUID  *VariableGuid, OPTIONAL
 | |
|   IN CONST CHAR16    *VariableName, OPTIONAL
 | |
|   IN UINTN           BufferSize,
 | |
|   IN CONST UINT8     *Buffer,
 | |
|   IN CONST CHAR16    *RequestElement  OPTIONAL
 | |
|   )
 | |
| {
 | |
|   UINTN       Size;
 | |
|   EFI_STRING  ConfigRequest;
 | |
|   EFI_STRING  ConfigResp;
 | |
|   EFI_STRING  ResultsData;
 | |
| 
 | |
|   ASSERT (Buffer != NULL);
 | |
| 
 | |
|   //
 | |
|   // Construct <ConfigRequest>
 | |
|   //
 | |
|   if (RequestElement == NULL) {
 | |
|     //
 | |
|     // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
 | |
|     // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator
 | |
|     //
 | |
|     Size = (StrLen (mConfigHdrTemplate) + 32 + 1) * sizeof (CHAR16);
 | |
|     ConfigRequest = AllocateZeroPool (Size);
 | |
|     UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", mConfigHdrTemplate, (UINT64)BufferSize);
 | |
|   } else {
 | |
|     //
 | |
|     // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
 | |
|     // followed by <RequestElement> followed by a Null-terminator
 | |
|     //
 | |
|     Size = StrLen (mConfigHdrTemplate) * sizeof (CHAR16);
 | |
|     Size = Size + (StrLen (RequestElement) + 1) * sizeof (CHAR16);
 | |
|     ConfigRequest = AllocateZeroPool (Size);
 | |
|     UnicodeSPrint (ConfigRequest, Size, L"%s%s", mConfigHdrTemplate, RequestElement);
 | |
|   }
 | |
|   if (ConfigRequest == NULL) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Convert <ConfigRequest> to <ConfigResp>
 | |
|   //
 | |
|   ConfigResp = InternalHiiBlockToConfig (ConfigRequest, Buffer, BufferSize);
 | |
|   FreePool (ConfigRequest);
 | |
|   if (ConfigResp == NULL) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Set data in the uncommitted browser state information
 | |
|   //
 | |
|   ResultsData = InternalHiiBrowserCallback (VariableGuid, VariableName, ConfigResp + StrLen(mConfigHdrTemplate) + 1);
 | |
|   FreePool (ConfigResp);
 | |
| 
 | |
|   return (BOOLEAN)(ResultsData != NULL);
 | |
| }
 | |
| 
 | |
| /////////////////////////////////////////
 | |
| /////////////////////////////////////////
 | |
| /// IFR Functions
 | |
| /////////////////////////////////////////
 | |
| /////////////////////////////////////////
 | |
| 
 | |
| #define HII_LIB_OPCODE_ALLOCATION_SIZE  0x200
 | |
| 
 | |
| typedef struct {
 | |
|   UINT8  *Buffer;
 | |
|   UINTN  BufferSize;
 | |
|   UINTN  Position;
 | |
| } HII_LIB_OPCODE_BUFFER;
 | |
| 
 | |
| ///
 | |
| /// Lookup table that converts EFI_IFR_TYPE_X enum values to a width in bytes
 | |
| ///
 | |
| GLOBAL_REMOVE_IF_UNREFERENCED CONST UINT8 mHiiDefaultTypeToWidth[] = {
 | |
|   1, // EFI_IFR_TYPE_NUM_SIZE_8
 | |
|   2, // EFI_IFR_TYPE_NUM_SIZE_16
 | |
|   4, // EFI_IFR_TYPE_NUM_SIZE_32
 | |
|   8, // EFI_IFR_TYPE_NUM_SIZE_64
 | |
|   1, // EFI_IFR_TYPE_BOOLEAN
 | |
|   3, // EFI_IFR_TYPE_TIME
 | |
|   4, // EFI_IFR_TYPE_DATE
 | |
|   2  // EFI_IFR_TYPE_STRING
 | |
| };
 | |
| 
 | |
| /**
 | |
|   Allocates and returns a new OpCode Handle.  OpCode Handles must be freed with
 | |
|   HiiFreeOpCodeHandle().
 | |
| 
 | |
|   @retval NULL   There are not enough resources to allocate a new OpCode Handle.
 | |
|   @retval Other  A new OpCode handle.
 | |
| 
 | |
| **/
 | |
| VOID *
 | |
| EFIAPI
 | |
| HiiAllocateOpCodeHandle (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   HII_LIB_OPCODE_BUFFER  *OpCodeBuffer;
 | |
| 
 | |
|   OpCodeBuffer = (HII_LIB_OPCODE_BUFFER *)AllocatePool (sizeof (HII_LIB_OPCODE_BUFFER));
 | |
|   if (OpCodeBuffer == NULL) {
 | |
|     return NULL;
 | |
|   }
 | |
|   OpCodeBuffer->Buffer = (UINT8 *)AllocatePool (HII_LIB_OPCODE_ALLOCATION_SIZE);
 | |
|   if (OpCodeBuffer->Buffer == NULL) {
 | |
|     FreePool (OpCodeBuffer);
 | |
|     return NULL;
 | |
|   }
 | |
|   OpCodeBuffer->BufferSize = HII_LIB_OPCODE_ALLOCATION_SIZE;
 | |
|   OpCodeBuffer->Position = 0;
 | |
|   return (VOID *)OpCodeBuffer;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Frees an OpCode Handle that was previously allocated with HiiAllocateOpCodeHandle().
 | |
|   When an OpCode Handle is freed, all of the opcodes associated with the OpCode
 | |
|   Handle are also freed.
 | |
| 
 | |
|   If OpCodeHandle is NULL, then ASSERT().
 | |
| 
 | |
|   @param[in]  OpCodeHandle   Handle to the buffer of opcodes.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| HiiFreeOpCodeHandle (
 | |
|   VOID  *OpCodeHandle
 | |
|   )
 | |
| {
 | |
|   HII_LIB_OPCODE_BUFFER  *OpCodeBuffer;
 | |
| 
 | |
|   ASSERT (OpCodeHandle != NULL);
 | |
| 
 | |
|   OpCodeBuffer = (HII_LIB_OPCODE_BUFFER *)OpCodeHandle;
 | |
|   if (OpCodeBuffer->Buffer != NULL) {
 | |
|     FreePool (OpCodeBuffer->Buffer);
 | |
|   }
 | |
|   FreePool (OpCodeBuffer);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Internal function gets the current position of opcode buffer.
 | |
| 
 | |
|   @param[in]  OpCodeHandle   Handle to the buffer of opcodes.
 | |
| 
 | |
|   @return Current position of opcode buffer.
 | |
| **/
 | |
| UINTN
 | |
| EFIAPI
 | |
| InternalHiiOpCodeHandlePosition (
 | |
|   IN VOID  *OpCodeHandle
 | |
|   )
 | |
| {
 | |
|   return ((HII_LIB_OPCODE_BUFFER  *)OpCodeHandle)->Position;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Internal function gets the start pointer of opcode buffer.
 | |
| 
 | |
|   @param[in]  OpCodeHandle   Handle to the buffer of opcodes.
 | |
| 
 | |
|   @return Pointer to the opcode buffer base.
 | |
| **/
 | |
| UINT8 *
 | |
| EFIAPI
 | |
| InternalHiiOpCodeHandleBuffer (
 | |
|   IN VOID  *OpCodeHandle
 | |
|   )
 | |
| {
 | |
|   return ((HII_LIB_OPCODE_BUFFER  *)OpCodeHandle)->Buffer;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Internal function reserves the enough buffer for current opcode.
 | |
|   When the buffer is not enough, Opcode buffer will be extended.
 | |
| 
 | |
|   @param[in]  OpCodeHandle   Handle to the buffer of opcodes.
 | |
|   @param[in]  Size           Size of current opcode.
 | |
| 
 | |
|   @return Pointer to the current opcode.
 | |
| **/
 | |
| UINT8 *
 | |
| EFIAPI
 | |
| InternalHiiGrowOpCodeHandle (
 | |
|   IN VOID   *OpCodeHandle,
 | |
|   IN UINTN  Size
 | |
|   )
 | |
| {
 | |
|   HII_LIB_OPCODE_BUFFER  *OpCodeBuffer;
 | |
|   UINT8                  *Buffer;
 | |
| 
 | |
|   ASSERT (OpCodeHandle != NULL);
 | |
| 
 | |
|   OpCodeBuffer = (HII_LIB_OPCODE_BUFFER *)OpCodeHandle;
 | |
|   if (OpCodeBuffer->Position + Size > OpCodeBuffer->BufferSize) {
 | |
|     Buffer = ReallocatePool (
 | |
|               OpCodeBuffer->BufferSize,
 | |
|               OpCodeBuffer->BufferSize + (Size + HII_LIB_OPCODE_ALLOCATION_SIZE),
 | |
|               OpCodeBuffer->Buffer
 | |
|               );
 | |
|     ASSERT (Buffer != NULL);
 | |
|     OpCodeBuffer->Buffer = Buffer;
 | |
|     OpCodeBuffer->BufferSize += (Size + HII_LIB_OPCODE_ALLOCATION_SIZE);
 | |
|   }
 | |
|   Buffer = OpCodeBuffer->Buffer + OpCodeBuffer->Position;
 | |
|   OpCodeBuffer->Position += Size;
 | |
|   return Buffer;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Internal function creates opcode based on the template opcode.
 | |
| 
 | |
|   @param[in]  OpCodeHandle    Handle to the buffer of opcodes.
 | |
|   @param[in]  OpCodeTemplate  Pointer to the template buffer of opcode.
 | |
|   @param[in]  OpCode          OpCode IFR value.
 | |
|   @param[in]  OpCodeSize      Size of opcode.
 | |
|   @param[in]  ExtensionSize   Size of extended opcode.
 | |
|   @param[in]  Scope           Scope bit of opcode.
 | |
| 
 | |
|   @return Pointer to the current opcode with opcode data.
 | |
| **/
 | |
| UINT8 *
 | |
| EFIAPI
 | |
| InternalHiiCreateOpCodeExtended (
 | |
|   IN VOID   *OpCodeHandle,
 | |
|   IN VOID   *OpCodeTemplate,
 | |
|   IN UINT8  OpCode,
 | |
|   IN UINTN  OpCodeSize,
 | |
|   IN UINTN  ExtensionSize,
 | |
|   IN UINT8  Scope
 | |
|   )
 | |
| {
 | |
|   EFI_IFR_OP_HEADER  *Header;
 | |
|   UINT8              *Buffer;
 | |
| 
 | |
|   ASSERT (OpCodeTemplate != NULL);
 | |
|   ASSERT ((OpCodeSize + ExtensionSize) <= 0x7F);
 | |
| 
 | |
|   Header = (EFI_IFR_OP_HEADER *)OpCodeTemplate;
 | |
|   Header->OpCode = OpCode;
 | |
|   Header->Scope  = Scope;
 | |
|   Header->Length = (UINT8)(OpCodeSize + ExtensionSize);
 | |
|   Buffer = InternalHiiGrowOpCodeHandle (OpCodeHandle, Header->Length);
 | |
|   return (UINT8 *)CopyMem (Buffer, Header, OpCodeSize);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Internal function creates opcode based on the template opcode for the normal opcode.
 | |
| 
 | |
|   @param[in]  OpCodeHandle    Handle to the buffer of opcodes.
 | |
|   @param[in]  OpCodeTemplate  Pointer to the template buffer of opcode.
 | |
|   @param[in]  OpCode          OpCode IFR value.
 | |
|   @param[in]  OpCodeSize      Size of opcode.
 | |
| 
 | |
|   @return Pointer to the current opcode with opcode data.
 | |
| **/
 | |
| UINT8 *
 | |
| EFIAPI
 | |
| InternalHiiCreateOpCode (
 | |
|   IN VOID   *OpCodeHandle,
 | |
|   IN VOID   *OpCodeTemplate,
 | |
|   IN UINT8  OpCode,
 | |
|   IN UINTN  OpCodeSize
 | |
|   )
 | |
| {
 | |
|   return InternalHiiCreateOpCodeExtended (OpCodeHandle, OpCodeTemplate, OpCode, OpCodeSize, 0, 0);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Append raw opcodes to an OpCodeHandle.
 | |
| 
 | |
|   If OpCodeHandle is NULL, then ASSERT().
 | |
|   If RawBuffer is NULL, then ASSERT();
 | |
| 
 | |
|   @param[in]  OpCodeHandle   Handle to the buffer of opcodes.
 | |
|   @param[in]  RawBuffer      Buffer of opcodes to append.
 | |
|   @param[in]  RawBufferSize  The size, in bytes, of Buffer.
 | |
| 
 | |
|   @retval NULL   There is not enough space left in Buffer to add the opcode.
 | |
|   @retval Other  A pointer to the appended opcodes.
 | |
| 
 | |
| **/
 | |
| UINT8 *
 | |
| EFIAPI
 | |
| HiiCreateRawOpCodes (
 | |
|   IN VOID   *OpCodeHandle,
 | |
|   IN UINT8  *RawBuffer,
 | |
|   IN UINTN  RawBufferSize
 | |
|   )
 | |
| {
 | |
|   UINT8  *Buffer;
 | |
| 
 | |
|   ASSERT (RawBuffer != NULL);
 | |
| 
 | |
|   Buffer = InternalHiiGrowOpCodeHandle (OpCodeHandle, RawBufferSize);
 | |
|   return (UINT8 *)CopyMem (Buffer, RawBuffer, RawBufferSize);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Append opcodes from one OpCode Handle to another OpCode handle.
 | |
| 
 | |
|   If OpCodeHandle is NULL, then ASSERT().
 | |
|   If RawOpCodeHandle is NULL, then ASSERT();
 | |
| 
 | |
|   @param[in]  OpCodeHandle     Handle to the buffer of opcodes.
 | |
|   @param[in]  RawOpCodeHandle  Handle to the buffer of opcodes.
 | |
| 
 | |
|   @retval NULL   There is not enough space left in Buffer to add the opcode.
 | |
|   @retval Other  A pointer to the appended opcodes.
 | |
| 
 | |
| **/
 | |
| UINT8 *
 | |
| EFIAPI
 | |
| InternalHiiAppendOpCodes (
 | |
|   IN VOID  *OpCodeHandle,
 | |
|   IN VOID  *RawOpCodeHandle
 | |
|   )
 | |
| {
 | |
|   HII_LIB_OPCODE_BUFFER  *RawOpCodeBuffer;
 | |
| 
 | |
|   ASSERT (RawOpCodeHandle != NULL);
 | |
| 
 | |
|   RawOpCodeBuffer = (HII_LIB_OPCODE_BUFFER *)RawOpCodeHandle;
 | |
|   return HiiCreateRawOpCodes (OpCodeHandle, RawOpCodeBuffer->Buffer, RawOpCodeBuffer->Position);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Create EFI_IFR_END_OP opcode.
 | |
| 
 | |
|   If OpCodeHandle is NULL, then ASSERT().
 | |
| 
 | |
|   @param[in]  OpCodeHandle  Handle to the buffer of opcodes.
 | |
| 
 | |
|   @retval NULL   There is not enough space left in Buffer to add the opcode.
 | |
|   @retval Other  A pointer to the created opcode.
 | |
| 
 | |
| **/
 | |
| UINT8 *
 | |
| EFIAPI
 | |
| HiiCreateEndOpCode (
 | |
|   IN VOID  *OpCodeHandle
 | |
|   )
 | |
| {
 | |
|   EFI_IFR_END  OpCode;
 | |
| 
 | |
|   return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_END_OP, sizeof (OpCode));
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Create EFI_IFR_ONE_OF_OPTION_OP opcode.
 | |
| 
 | |
|   If OpCodeHandle is NULL, then ASSERT().
 | |
|   If Type is invalid, then ASSERT().
 | |
|   If Flags is invalid, then ASSERT().
 | |
| 
 | |
|   @param[in]  OpCodeHandle  Handle to the buffer of opcodes.
 | |
|   @param[in]  StringId      StringId for the option
 | |
|   @param[in]  Flags         Flags for the option
 | |
|   @param[in]  Type          Type for the option
 | |
|   @param[in]  Value         Value for the option
 | |
| 
 | |
|   @retval NULL   There is not enough space left in Buffer to add the opcode.
 | |
|   @retval Other  A pointer to the created opcode.
 | |
| 
 | |
| **/
 | |
| UINT8 *
 | |
| EFIAPI
 | |
| HiiCreateOneOfOptionOpCode (
 | |
|   IN VOID    *OpCodeHandle,
 | |
|   IN UINT16  StringId,
 | |
|   IN UINT8   Flags,
 | |
|   IN UINT8   Type,
 | |
|   IN UINT64  Value
 | |
|   )
 | |
| {
 | |
|   EFI_IFR_ONE_OF_OPTION  OpCode;
 | |
| 
 | |
|   ASSERT (Type < EFI_IFR_TYPE_OTHER);
 | |
| 
 | |
|   ZeroMem (&OpCode, sizeof (OpCode));
 | |
|   OpCode.Option = StringId;
 | |
|   OpCode.Flags  = (UINT8) (Flags & (EFI_IFR_OPTION_DEFAULT | EFI_IFR_OPTION_DEFAULT_MFG));
 | |
|   OpCode.Type   = Type;
 | |
|   CopyMem (&OpCode.Value, &Value, mHiiDefaultTypeToWidth[Type]);
 | |
| 
 | |
|   return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_ONE_OF_OPTION_OP, OFFSET_OF(EFI_IFR_ONE_OF_OPTION, Value) + mHiiDefaultTypeToWidth[Type]);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Create EFI_IFR_DEFAULT_OP opcode.
 | |
| 
 | |
|   If OpCodeHandle is NULL, then ASSERT().
 | |
|   If Type is invalid, then ASSERT().
 | |
| 
 | |
|   @param[in]  OpCodeHandle  Handle to the buffer of opcodes.
 | |
|   @param[in]  DefaultId     DefaultId for the default
 | |
|   @param[in]  Type          Type for the default
 | |
|   @param[in]  Value         Value for the default
 | |
| 
 | |
|   @retval NULL   There is not enough space left in Buffer to add the opcode.
 | |
|   @retval Other  A pointer to the created opcode.
 | |
| 
 | |
| **/
 | |
| UINT8 *
 | |
| EFIAPI
 | |
| HiiCreateDefaultOpCode (
 | |
|   IN VOID    *OpCodeHandle,
 | |
|   IN UINT16  DefaultId,
 | |
|   IN UINT8   Type,
 | |
|   IN UINT64  Value
 | |
|   )
 | |
| {
 | |
|   EFI_IFR_DEFAULT  OpCode;
 | |
| 
 | |
|   ASSERT (Type < EFI_IFR_TYPE_OTHER);
 | |
| 
 | |
|   ZeroMem (&OpCode, sizeof (OpCode));
 | |
|   OpCode.Type      = Type;
 | |
|   OpCode.DefaultId = DefaultId;
 | |
|   CopyMem (&OpCode.Value, &Value, mHiiDefaultTypeToWidth[Type]);
 | |
| 
 | |
|   return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_DEFAULT_OP, OFFSET_OF(EFI_IFR_DEFAULT, Value) + mHiiDefaultTypeToWidth[Type]);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Create EFI_IFR_GUID opcode.
 | |
| 
 | |
|   If OpCodeHandle is NULL, then ASSERT().
 | |
|   If Guid is NULL, then ASSERT().
 | |
|   If OpCodeSize < sizeof (EFI_IFR_GUID), then ASSERT().
 | |
| 
 | |
|   @param[in]  OpCodeHandle  Handle to the buffer of opcodes.
 | |
|   @param[in]  Guid          Pointer to EFI_GUID of this guided opcode.
 | |
|   @param[in]  GuidOpCode    Pointer to an EFI_IFR_GUID opcode.  This is an
 | |
|                             optional parameter that may be NULL.  If this
 | |
|                             parameter is NULL, then the GUID extension
 | |
|                             region of the created opcode is filled with zeros.
 | |
|                             If this parameter is not NULL, then the GUID
 | |
|                             extension region of GuidData will be copied to
 | |
|                             the GUID extension region of the created opcode.
 | |
|   @param[in]  OpCodeSize    The size, in bytes, of created opcode.  This value
 | |
|                             must be >= sizeof(EFI_IFR_GUID).
 | |
| 
 | |
|   @retval NULL   There is not enough space left in Buffer to add the opcode.
 | |
|   @retval Other  A pointer to the created opcode.
 | |
| 
 | |
| **/
 | |
| UINT8 *
 | |
| EFIAPI
 | |
| HiiCreateGuidOpCode (
 | |
|   IN VOID            *OpCodeHandle,
 | |
|   IN CONST EFI_GUID  *Guid,
 | |
|   IN CONST VOID      *GuidOpCode,    OPTIONAL
 | |
|   IN UINTN           OpCodeSize
 | |
|   )
 | |
| {
 | |
|   EFI_IFR_GUID  OpCode;
 | |
|   EFI_IFR_GUID  *OpCodePointer;
 | |
| 
 | |
|   ASSERT (Guid != NULL);
 | |
|   ASSERT (OpCodeSize >= sizeof (OpCode));
 | |
| 
 | |
|   ZeroMem (&OpCode, sizeof (OpCode));
 | |
|   CopyGuid ((EFI_GUID *)(VOID *)&OpCode.Guid, Guid);
 | |
| 
 | |
|   OpCodePointer = (EFI_IFR_GUID *)InternalHiiCreateOpCodeExtended (
 | |
|                                     OpCodeHandle,
 | |
|                                     &OpCode,
 | |
|                                     EFI_IFR_GUID_OP,
 | |
|                                     sizeof (OpCode),
 | |
|                                     OpCodeSize - sizeof (OpCode),
 | |
|                                     0
 | |
|                                     );
 | |
|   if (OpCodePointer != NULL && GuidOpCode != NULL) {
 | |
|     CopyMem (OpCodePointer + 1, (EFI_IFR_GUID *)GuidOpCode + 1, OpCodeSize - sizeof (OpCode));
 | |
|   }
 | |
|   return (UINT8 *)OpCodePointer;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Create EFI_IFR_ACTION_OP opcode.
 | |
| 
 | |
|   If OpCodeHandle is NULL, then ASSERT().
 | |
|   If any reserved bits are set in QuestionFlags, then ASSERT().
 | |
| 
 | |
|   @param[in]  OpCodeHandle  Handle to the buffer of opcodes.
 | |
|   @param[in]  QuestionId      Question ID
 | |
|   @param[in]  Prompt          String ID for Prompt
 | |
|   @param[in]  Help            String ID for Help
 | |
|   @param[in]  QuestionFlags   Flags in Question Header
 | |
|   @param[in]  QuestionConfig  String ID for configuration
 | |
| 
 | |
|   @retval NULL   There is not enough space left in Buffer to add the opcode.
 | |
|   @retval Other  A pointer to the created opcode.
 | |
| 
 | |
| **/
 | |
| UINT8 *
 | |
| EFIAPI
 | |
| HiiCreateActionOpCode (
 | |
|   IN VOID             *OpCodeHandle,
 | |
|   IN EFI_QUESTION_ID  QuestionId,
 | |
|   IN EFI_STRING_ID    Prompt,
 | |
|   IN EFI_STRING_ID    Help,
 | |
|   IN UINT8            QuestionFlags,
 | |
|   IN EFI_STRING_ID    QuestionConfig
 | |
|   )
 | |
| {
 | |
|   EFI_IFR_ACTION  OpCode;
 | |
| 
 | |
|   ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED))) == 0);
 | |
| 
 | |
|   ZeroMem (&OpCode, sizeof (OpCode));
 | |
|   OpCode.Question.QuestionId    = QuestionId;
 | |
|   OpCode.Question.Header.Prompt = Prompt;
 | |
|   OpCode.Question.Header.Help   = Help;
 | |
|   OpCode.Question.Flags         = QuestionFlags;
 | |
|   OpCode.QuestionConfig         = QuestionConfig;
 | |
| 
 | |
|   return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_ACTION_OP, sizeof (OpCode));
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Create EFI_IFR_SUBTITLE_OP opcode.
 | |
| 
 | |
|   If OpCodeHandle is NULL, then ASSERT().
 | |
|   If any reserved bits are set in Flags, then ASSERT().
 | |
|   If Scope > 1, then ASSERT().
 | |
| 
 | |
|   @param[in]  OpCodeHandle  Handle to the buffer of opcodes.
 | |
|   @param[in]  Prompt      String ID for Prompt
 | |
|   @param[in]  Help        String ID for Help
 | |
|   @param[in]  Flags       Subtitle opcode flags
 | |
|   @param[in]  Scope       1 if this opcpde is the beginning of a new scope.
 | |
|                           0 if this opcode is within the current scope.
 | |
| 
 | |
|   @retval NULL   There is not enough space left in Buffer to add the opcode.
 | |
|   @retval Other  A pointer to the created opcode.
 | |
| 
 | |
| **/
 | |
| UINT8 *
 | |
| EFIAPI
 | |
| HiiCreateSubTitleOpCode (
 | |
|   IN VOID           *OpCodeHandle,
 | |
|   IN EFI_STRING_ID  Prompt,
 | |
|   IN EFI_STRING_ID  Help,
 | |
|   IN UINT8          Flags,
 | |
|   IN UINT8          Scope
 | |
|   )
 | |
| {
 | |
|   EFI_IFR_SUBTITLE  OpCode;
 | |
| 
 | |
|   ASSERT (Scope <= 1);
 | |
|   ASSERT ((Flags & (~(EFI_IFR_FLAGS_HORIZONTAL))) == 0);
 | |
| 
 | |
|   ZeroMem (&OpCode, sizeof (OpCode));
 | |
|   OpCode.Statement.Prompt = Prompt;
 | |
|   OpCode.Statement.Help   = Help;
 | |
|   OpCode.Flags            = Flags;
 | |
| 
 | |
|   return InternalHiiCreateOpCodeExtended (
 | |
|            OpCodeHandle,
 | |
|            &OpCode,
 | |
|            EFI_IFR_SUBTITLE_OP,
 | |
|            sizeof (OpCode),
 | |
|            0,
 | |
|            Scope
 | |
|            );
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Create EFI_IFR_REF_OP opcode.
 | |
| 
 | |
|   If OpCodeHandle is NULL, then ASSERT().
 | |
|   If any reserved bits are set in QuestionFlags, then ASSERT().
 | |
| 
 | |
|   @param[in]  OpCodeHandle   Handle to the buffer of opcodes.
 | |
|   @param[in]  FormId         Destination Form ID
 | |
|   @param[in]  Prompt         String ID for Prompt
 | |
|   @param[in]  Help           String ID for Help
 | |
|   @param[in]  QuestionFlags  Flags in Question Header
 | |
|   @param[in]  QuestionId     Question ID
 | |
| 
 | |
|   @retval NULL   There is not enough space left in Buffer to add the opcode.
 | |
|   @retval Other  A pointer to the created opcode.
 | |
| 
 | |
| **/
 | |
| UINT8 *
 | |
| EFIAPI
 | |
| HiiCreateGotoOpCode (
 | |
|   IN VOID             *OpCodeHandle,
 | |
|   IN EFI_FORM_ID      FormId,
 | |
|   IN EFI_STRING_ID    Prompt,
 | |
|   IN EFI_STRING_ID    Help,
 | |
|   IN UINT8            QuestionFlags,
 | |
|   IN EFI_QUESTION_ID  QuestionId
 | |
|   )
 | |
| {
 | |
|   EFI_IFR_REF  OpCode;
 | |
| 
 | |
|   ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED))) == 0);
 | |
| 
 | |
|   ZeroMem (&OpCode, sizeof (OpCode));
 | |
|   OpCode.Question.Header.Prompt = Prompt;
 | |
|   OpCode.Question.Header.Help   = Help;
 | |
|   OpCode.Question.QuestionId    = QuestionId;
 | |
|   OpCode.Question.Flags         = QuestionFlags;
 | |
|   OpCode.FormId                 = FormId;
 | |
| 
 | |
|   return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_REF_OP, sizeof (OpCode));
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Create EFI_IFR_REF_OP, EFI_IFR_REF2_OP, EFI_IFR_REF3_OP and EFI_IFR_REF4_OP opcode.
 | |
| 
 | |
|   When RefDevicePath is not zero, EFI_IFR_REF4 opcode will be created.
 | |
|   When RefDevicePath is zero and RefFormSetId is not NULL, EFI_IFR_REF3 opcode will be created.
 | |
|   When RefDevicePath is zero, RefFormSetId is NULL and RefQuestionId is not zero, EFI_IFR_REF2 opcode will be created.
 | |
|   When RefDevicePath is zero, RefFormSetId is NULL and RefQuestionId is zero, EFI_IFR_REF opcode will be created.
 | |
| 
 | |
|   If OpCodeHandle is NULL, then ASSERT().
 | |
|   If any reserved bits are set in QuestionFlags, then ASSERT().
 | |
| 
 | |
|   @param[in]  OpCodeHandle   The handle to the buffer of opcodes.
 | |
|   @param[in]  RefFormId      The Destination Form ID.
 | |
|   @param[in]  Prompt         The string ID for Prompt.
 | |
|   @param[in]  Help           The string ID for Help.
 | |
|   @param[in]  QuestionFlags  The flags in Question Header
 | |
|   @param[in]  QuestionId     Question ID.
 | |
|   @param[in]  RefQuestionId  The question on the form to which this link is referring.
 | |
|                              If its value is zero, then the link refers to the top of the form.
 | |
|   @param[in]  RefFormSetId   The form set to which this link is referring. If its value is NULL, and RefDevicePath is
 | |
|                              zero, then the link is to the current form set.
 | |
|   @param[in]  RefDevicePath  The string identifier that specifies the string containing the text representation of
 | |
|                              the device path to which the form set containing the form specified by FormId.
 | |
|                              If its value is zero, then the link refers to the current page.
 | |
| 
 | |
|   @retval NULL   There is not enough space left in Buffer to add the opcode.
 | |
|   @retval Other  A pointer to the created opcode.
 | |
| 
 | |
| **/
 | |
| UINT8 *
 | |
| EFIAPI
 | |
| HiiCreateGotoExOpCode (
 | |
|   IN VOID             *OpCodeHandle,
 | |
|   IN EFI_FORM_ID      RefFormId,
 | |
|   IN EFI_STRING_ID    Prompt,
 | |
|   IN EFI_STRING_ID    Help,
 | |
|   IN UINT8            QuestionFlags,
 | |
|   IN EFI_QUESTION_ID  QuestionId,
 | |
|   IN EFI_QUESTION_ID  RefQuestionId,
 | |
|   IN EFI_GUID         *RefFormSetId,    OPTIONAL
 | |
|   IN EFI_STRING_ID    RefDevicePath
 | |
|   )
 | |
| {
 | |
|   EFI_IFR_REF4  OpCode;
 | |
|   UINTN         OpCodeSize;
 | |
| 
 | |
|   ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED))) == 0);
 | |
| 
 | |
|   ZeroMem (&OpCode, sizeof (OpCode));
 | |
|   OpCode.Question.Header.Prompt = Prompt;
 | |
|   OpCode.Question.Header.Help   = Help;
 | |
|   OpCode.Question.QuestionId    = QuestionId;
 | |
|   OpCode.Question.Flags         = QuestionFlags;
 | |
|   OpCode.FormId                 = RefFormId;
 | |
|   OpCode.QuestionId             = RefQuestionId;
 | |
|   OpCode.DevicePath             = RefDevicePath;
 | |
|   if (RefFormSetId != NULL) {
 | |
|     CopyMem (&OpCode.FormSetId, RefFormSetId, sizeof (OpCode.FormSetId));
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Cacluate OpCodeSize based on the input Ref value.
 | |
|   // Try to use the small OpCode to save size.
 | |
|   //
 | |
|   OpCodeSize = sizeof (EFI_IFR_REF);
 | |
|   if (RefDevicePath != 0) {
 | |
|     OpCodeSize = sizeof (EFI_IFR_REF4);
 | |
|   } else if (RefFormSetId != NULL) {
 | |
|     OpCodeSize = sizeof (EFI_IFR_REF3);
 | |
|   } else if (RefQuestionId != 0) {
 | |
|     OpCodeSize = sizeof (EFI_IFR_REF2);
 | |
|   }
 | |
| 
 | |
|   return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_REF_OP, OpCodeSize);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Create EFI_IFR_CHECKBOX_OP opcode.
 | |
| 
 | |
|   If OpCodeHandle is NULL, then ASSERT().
 | |
|   If any reserved bits are set in QuestionFlags, then ASSERT().
 | |
|   If any reserved bits are set in CheckBoxFlags, then ASSERT().
 | |
| 
 | |
|   @param[in]  OpCodeHandle          Handle to the buffer of opcodes.
 | |
|   @param[in]  QuestionId            Question ID
 | |
|   @param[in]  VarStoreId            Storage ID
 | |
|   @param[in]  VarOffset             Offset in Storage or String ID of the name (VarName)
 | |
|                                     for this name/value pair.
 | |
|   @param[in]  Prompt                String ID for Prompt
 | |
|   @param[in]  Help                  String ID for Help
 | |
|   @param[in]  QuestionFlags         Flags in Question Header
 | |
|   @param[in]  CheckBoxFlags         Flags for checkbox opcode
 | |
|   @param[in]  DefaultsOpCodeHandle  Handle for a buffer of DEFAULT opcodes.  This
 | |
|                                     is an optional parameter that may be NULL.
 | |
| 
 | |
|   @retval NULL   There is not enough space left in Buffer to add the opcode.
 | |
|   @retval Other  A pointer to the created opcode.
 | |
| 
 | |
| **/
 | |
| UINT8 *
 | |
| EFIAPI
 | |
| HiiCreateCheckBoxOpCode (
 | |
|   IN VOID             *OpCodeHandle,
 | |
|   IN EFI_QUESTION_ID  QuestionId,
 | |
|   IN EFI_VARSTORE_ID  VarStoreId,
 | |
|   IN UINT16           VarOffset,
 | |
|   IN EFI_STRING_ID    Prompt,
 | |
|   IN EFI_STRING_ID    Help,
 | |
|   IN UINT8            QuestionFlags,
 | |
|   IN UINT8            CheckBoxFlags,
 | |
|   IN VOID             *DefaultsOpCodeHandle  OPTIONAL
 | |
|   )
 | |
| {
 | |
|   EFI_IFR_CHECKBOX  OpCode;
 | |
|   UINTN             Position;
 | |
| 
 | |
|   ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED | EFI_IFR_FLAG_REST_STYLE))) == 0);
 | |
| 
 | |
|   ZeroMem (&OpCode, sizeof (OpCode));
 | |
|   OpCode.Question.QuestionId             = QuestionId;
 | |
|   OpCode.Question.VarStoreId             = VarStoreId;
 | |
|   OpCode.Question.VarStoreInfo.VarOffset = VarOffset;
 | |
|   OpCode.Question.Header.Prompt          = Prompt;
 | |
|   OpCode.Question.Header.Help            = Help;
 | |
|   OpCode.Question.Flags                  = QuestionFlags;
 | |
|   OpCode.Flags                           = CheckBoxFlags;
 | |
| 
 | |
|   if (DefaultsOpCodeHandle == NULL) {
 | |
|     return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_CHECKBOX_OP, sizeof (OpCode));
 | |
|   }
 | |
| 
 | |
|   Position = InternalHiiOpCodeHandlePosition (OpCodeHandle);
 | |
|   InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_CHECKBOX_OP, sizeof (OpCode), 0, 1);
 | |
|   InternalHiiAppendOpCodes (OpCodeHandle, DefaultsOpCodeHandle);
 | |
|   HiiCreateEndOpCode (OpCodeHandle);
 | |
|   return InternalHiiOpCodeHandleBuffer (OpCodeHandle) + Position;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Create EFI_IFR_NUMERIC_OP opcode.
 | |
| 
 | |
|   If OpCodeHandle is NULL, then ASSERT().
 | |
|   If any reserved bits are set in QuestionFlags, then ASSERT().
 | |
|   If any reserved bits are set in NumericFlags, then ASSERT().
 | |
| 
 | |
|   @param[in]  OpCodeHandle          Handle to the buffer of opcodes.
 | |
|   @param[in]  QuestionId            Question ID
 | |
|   @param[in]  VarStoreId            Storage ID
 | |
|   @param[in]  VarOffset             Offset in Storage or String ID of the name (VarName)
 | |
|                                     for this name/value pair.
 | |
|   @param[in]  Prompt                String ID for Prompt
 | |
|   @param[in]  Help                  String ID for Help
 | |
|   @param[in]  QuestionFlags         Flags in Question Header
 | |
|   @param[in]  NumericFlags          Flags for numeric opcode
 | |
|   @param[in]  Minimum               Numeric minimum value
 | |
|   @param[in]  Maximum               Numeric maximum value
 | |
|   @param[in]  Step                  Numeric step for edit
 | |
|   @param[in]  DefaultsOpCodeHandle  Handle for a buffer of DEFAULT opcodes.  This
 | |
|                                     is an optional parameter that may be NULL.
 | |
| 
 | |
|   @retval NULL   There is not enough space left in Buffer to add the opcode.
 | |
|   @retval Other  A pointer to the created opcode.
 | |
| 
 | |
| **/
 | |
| UINT8 *
 | |
| EFIAPI
 | |
| HiiCreateNumericOpCode (
 | |
|   IN VOID             *OpCodeHandle,
 | |
|   IN EFI_QUESTION_ID  QuestionId,
 | |
|   IN EFI_VARSTORE_ID  VarStoreId,
 | |
|   IN UINT16           VarOffset,
 | |
|   IN EFI_STRING_ID    Prompt,
 | |
|   IN EFI_STRING_ID    Help,
 | |
|   IN UINT8            QuestionFlags,
 | |
|   IN UINT8            NumericFlags,
 | |
|   IN UINT64           Minimum,
 | |
|   IN UINT64           Maximum,
 | |
|   IN UINT64           Step,
 | |
|   IN VOID             *DefaultsOpCodeHandle  OPTIONAL
 | |
|   )
 | |
| {
 | |
|   EFI_IFR_NUMERIC  OpCode;
 | |
|   UINTN            Position;
 | |
|   UINTN            Length;
 | |
| 
 | |
|   ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED | EFI_IFR_FLAG_REST_STYLE))) == 0);
 | |
| 
 | |
|   Length  = 0;
 | |
|   ZeroMem (&OpCode, sizeof (OpCode));
 | |
|   OpCode.Question.QuestionId             = QuestionId;
 | |
|   OpCode.Question.VarStoreId             = VarStoreId;
 | |
|   OpCode.Question.VarStoreInfo.VarOffset = VarOffset;
 | |
|   OpCode.Question.Header.Prompt          = Prompt;
 | |
|   OpCode.Question.Header.Help            = Help;
 | |
|   OpCode.Question.Flags                  = QuestionFlags;
 | |
|   OpCode.Flags                           = NumericFlags;
 | |
| 
 | |
|   switch (NumericFlags & EFI_IFR_NUMERIC_SIZE) {
 | |
|   case EFI_IFR_NUMERIC_SIZE_1:
 | |
|     OpCode.data.u8.MinValue = (UINT8)Minimum;
 | |
|     OpCode.data.u8.MaxValue = (UINT8)Maximum;
 | |
|     OpCode.data.u8.Step     = (UINT8)Step;
 | |
|     Length                  = 3;
 | |
|     break;
 | |
| 
 | |
|   case EFI_IFR_NUMERIC_SIZE_2:
 | |
|     OpCode.data.u16.MinValue = (UINT16)Minimum;
 | |
|     OpCode.data.u16.MaxValue = (UINT16)Maximum;
 | |
|     OpCode.data.u16.Step     = (UINT16)Step;
 | |
|     Length                   = 6;
 | |
|     break;
 | |
| 
 | |
|   case EFI_IFR_NUMERIC_SIZE_4:
 | |
|     OpCode.data.u32.MinValue = (UINT32)Minimum;
 | |
|     OpCode.data.u32.MaxValue = (UINT32)Maximum;
 | |
|     OpCode.data.u32.Step     = (UINT32)Step;
 | |
|     Length                   = 12;
 | |
|     break;
 | |
| 
 | |
|   case EFI_IFR_NUMERIC_SIZE_8:
 | |
|     OpCode.data.u64.MinValue = Minimum;
 | |
|     OpCode.data.u64.MaxValue = Maximum;
 | |
|     OpCode.data.u64.Step     = Step;
 | |
|     Length                   = 24;
 | |
|     break;
 | |
|   }
 | |
| 
 | |
|   Length += OFFSET_OF (EFI_IFR_NUMERIC, data);
 | |
| 
 | |
|   if (DefaultsOpCodeHandle == NULL) {
 | |
|     return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_NUMERIC_OP, Length);
 | |
|   }
 | |
| 
 | |
|   Position = InternalHiiOpCodeHandlePosition (OpCodeHandle);
 | |
|   InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_NUMERIC_OP, Length, 0, 1);
 | |
|   InternalHiiAppendOpCodes (OpCodeHandle, DefaultsOpCodeHandle);
 | |
|   HiiCreateEndOpCode (OpCodeHandle);
 | |
|   return InternalHiiOpCodeHandleBuffer (OpCodeHandle) + Position;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Create EFI_IFR_STRING_OP opcode.
 | |
| 
 | |
|   If OpCodeHandle is NULL, then ASSERT().
 | |
|   If any reserved bits are set in QuestionFlags, then ASSERT().
 | |
|   If any reserved bits are set in StringFlags, then ASSERT().
 | |
| 
 | |
|   @param[in]  OpCodeHandle          Handle to the buffer of opcodes.
 | |
|   @param[in]  QuestionId            Question ID
 | |
|   @param[in]  VarStoreId            Storage ID
 | |
|   @param[in]  VarOffset             Offset in Storage or String ID of the name (VarName)
 | |
|                                     for this name/value pair.
 | |
|   @param[in]  Prompt                String ID for Prompt
 | |
|   @param[in]  Help                  String ID for Help
 | |
|   @param[in]  QuestionFlags         Flags in Question Header
 | |
|   @param[in]  StringFlags           Flags for string opcode
 | |
|   @param[in]  MinSize               String minimum length
 | |
|   @param[in]  MaxSize               String maximum length
 | |
|   @param[in]  DefaultsOpCodeHandle  Handle for a buffer of DEFAULT opcodes.  This
 | |
|                                     is an optional parameter that may be NULL.
 | |
| 
 | |
|   @retval NULL   There is not enough space left in Buffer to add the opcode.
 | |
|   @retval Other  A pointer to the created opcode.
 | |
| 
 | |
| **/
 | |
| UINT8 *
 | |
| EFIAPI
 | |
| HiiCreateStringOpCode (
 | |
|   IN VOID             *OpCodeHandle,
 | |
|   IN EFI_QUESTION_ID  QuestionId,
 | |
|   IN EFI_VARSTORE_ID  VarStoreId,
 | |
|   IN UINT16           VarOffset,
 | |
|   IN EFI_STRING_ID    Prompt,
 | |
|   IN EFI_STRING_ID    Help,
 | |
|   IN UINT8            QuestionFlags,
 | |
|   IN UINT8            StringFlags,
 | |
|   IN UINT8            MinSize,
 | |
|   IN UINT8            MaxSize,
 | |
|   IN VOID             *DefaultsOpCodeHandle  OPTIONAL
 | |
|   )
 | |
| {
 | |
|   EFI_IFR_STRING  OpCode;
 | |
|   UINTN           Position;
 | |
| 
 | |
|   ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED | EFI_IFR_FLAG_REST_STYLE))) == 0);
 | |
| 
 | |
|   ZeroMem (&OpCode, sizeof (OpCode));
 | |
|   OpCode.Question.Header.Prompt          = Prompt;
 | |
|   OpCode.Question.Header.Help            = Help;
 | |
|   OpCode.Question.QuestionId             = QuestionId;
 | |
|   OpCode.Question.VarStoreId             = VarStoreId;
 | |
|   OpCode.Question.VarStoreInfo.VarOffset = VarOffset;
 | |
|   OpCode.Question.Flags                  = QuestionFlags;
 | |
|   OpCode.MinSize                         = MinSize;
 | |
|   OpCode.MaxSize                         = MaxSize;
 | |
|   OpCode.Flags                           = (UINT8) (StringFlags & EFI_IFR_STRING_MULTI_LINE);
 | |
| 
 | |
|   if (DefaultsOpCodeHandle == NULL) {
 | |
|     return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_STRING_OP, sizeof (OpCode));
 | |
|   }
 | |
| 
 | |
|   Position = InternalHiiOpCodeHandlePosition (OpCodeHandle);
 | |
|   InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_STRING_OP, sizeof (OpCode), 0, 1);
 | |
|   InternalHiiAppendOpCodes (OpCodeHandle, DefaultsOpCodeHandle);
 | |
|   HiiCreateEndOpCode (OpCodeHandle);
 | |
|   return InternalHiiOpCodeHandleBuffer (OpCodeHandle) + Position;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Create EFI_IFR_ONE_OF_OP opcode.
 | |
| 
 | |
|   If OpCodeHandle is NULL, then ASSERT().
 | |
|   If any reserved bits are set in QuestionFlags, then ASSERT().
 | |
|   If any reserved bits are set in OneOfFlags, then ASSERT().
 | |
| 
 | |
|   @param[in]  OpCodeHandle          Handle to the buffer of opcodes.
 | |
|   @param[in]  QuestionId            Question ID
 | |
|   @param[in]  VarStoreId            Storage ID
 | |
|   @param[in]  VarOffset             Offset in Storage or String ID of the name (VarName)
 | |
|                                     for this name/value pair.
 | |
|   @param[in]  Prompt                String ID for Prompt
 | |
|   @param[in]  Help                  String ID for Help
 | |
|   @param[in]  QuestionFlags         Flags in Question Header
 | |
|   @param[in]  OneOfFlags            Flags for oneof opcode
 | |
|   @param[in]  OptionsOpCodeHandle   Handle for a buffer of ONE_OF_OPTION opcodes.
 | |
|   @param[in]  DefaultsOpCodeHandle  Handle for a buffer of DEFAULT opcodes.  This
 | |
|                                     is an optional parameter that may be NULL.
 | |
| 
 | |
|   @retval NULL   There is not enough space left in Buffer to add the opcode.
 | |
|   @retval Other  A pointer to the created opcode.
 | |
| 
 | |
| **/
 | |
| UINT8 *
 | |
| EFIAPI
 | |
| HiiCreateOneOfOpCode (
 | |
|   IN VOID             *OpCodeHandle,
 | |
|   IN EFI_QUESTION_ID  QuestionId,
 | |
|   IN EFI_VARSTORE_ID  VarStoreId,
 | |
|   IN UINT16           VarOffset,
 | |
|   IN EFI_STRING_ID    Prompt,
 | |
|   IN EFI_STRING_ID    Help,
 | |
|   IN UINT8            QuestionFlags,
 | |
|   IN UINT8            OneOfFlags,
 | |
|   IN VOID             *OptionsOpCodeHandle,
 | |
|   IN VOID             *DefaultsOpCodeHandle  OPTIONAL
 | |
|   )
 | |
| {
 | |
|   EFI_IFR_ONE_OF  OpCode;
 | |
|   UINTN           Position;
 | |
|   UINTN           Length;
 | |
| 
 | |
|   ASSERT (OptionsOpCodeHandle != NULL);
 | |
|   ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED | EFI_IFR_FLAG_REST_STYLE | EFI_IFR_FLAG_OPTIONS_ONLY))) == 0);
 | |
| 
 | |
|   ZeroMem (&OpCode, sizeof (OpCode));
 | |
|   OpCode.Question.Header.Prompt          = Prompt;
 | |
|   OpCode.Question.Header.Help            = Help;
 | |
|   OpCode.Question.QuestionId             = QuestionId;
 | |
|   OpCode.Question.VarStoreId             = VarStoreId;
 | |
|   OpCode.Question.VarStoreInfo.VarOffset = VarOffset;
 | |
|   OpCode.Question.Flags                  = QuestionFlags;
 | |
|   OpCode.Flags                           = OneOfFlags;
 | |
| 
 | |
|   Length  = OFFSET_OF (EFI_IFR_ONE_OF, data);
 | |
|   Length += (1 << (OneOfFlags & EFI_IFR_NUMERIC_SIZE)) * 3;
 | |
| 
 | |
|   Position = InternalHiiOpCodeHandlePosition (OpCodeHandle);
 | |
|   InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_ONE_OF_OP, Length, 0, 1);
 | |
|   InternalHiiAppendOpCodes (OpCodeHandle, OptionsOpCodeHandle);
 | |
|   if (DefaultsOpCodeHandle != NULL) {
 | |
|     InternalHiiAppendOpCodes (OpCodeHandle, DefaultsOpCodeHandle);
 | |
|   }
 | |
|   HiiCreateEndOpCode (OpCodeHandle);
 | |
|   return InternalHiiOpCodeHandleBuffer (OpCodeHandle) + Position;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Create EFI_IFR_ORDERED_LIST_OP opcode.
 | |
| 
 | |
|   If OpCodeHandle is NULL, then ASSERT().
 | |
|   If any reserved bits are set in QuestionFlags, then ASSERT().
 | |
|   If any reserved bits are set in OrderedListFlags, then ASSERT().
 | |
| 
 | |
|   @param[in]  OpCodeHandle          Handle to the buffer of opcodes.
 | |
|   @param[in]  QuestionId            Question ID
 | |
|   @param[in]  VarStoreId            Storage ID
 | |
|   @param[in]  VarOffset             Offset in Storage or String ID of the name (VarName)
 | |
|                                     for this name/value pair.
 | |
|   @param[in]  Prompt                String ID for Prompt
 | |
|   @param[in]  Help                  String ID for Help
 | |
|   @param[in]  QuestionFlags         Flags in Question Header
 | |
|   @param[in]  OrderedListFlags      Flags for ordered list opcode
 | |
|   @param[in]  DataType              Type for option value
 | |
|   @param[in]  MaxContainers         Maximum count for options in this ordered list
 | |
|   @param[in]  OptionsOpCodeHandle   Handle for a buffer of ONE_OF_OPTION opcodes.
 | |
|   @param[in]  DefaultsOpCodeHandle  Handle for a buffer of DEFAULT opcodes.  This
 | |
|                                     is an optional parameter that may be NULL.
 | |
| 
 | |
|   @retval NULL   There is not enough space left in Buffer to add the opcode.
 | |
|   @retval Other  A pointer to the created opcode.
 | |
| 
 | |
| **/
 | |
| UINT8 *
 | |
| EFIAPI
 | |
| HiiCreateOrderedListOpCode (
 | |
|   IN VOID             *OpCodeHandle,
 | |
|   IN EFI_QUESTION_ID  QuestionId,
 | |
|   IN EFI_VARSTORE_ID  VarStoreId,
 | |
|   IN UINT16           VarOffset,
 | |
|   IN EFI_STRING_ID    Prompt,
 | |
|   IN EFI_STRING_ID    Help,
 | |
|   IN UINT8            QuestionFlags,
 | |
|   IN UINT8            OrderedListFlags,
 | |
|   IN UINT8            DataType,
 | |
|   IN UINT8            MaxContainers,
 | |
|   IN VOID             *OptionsOpCodeHandle,
 | |
|   IN VOID             *DefaultsOpCodeHandle  OPTIONAL
 | |
|   )
 | |
| {
 | |
|   EFI_IFR_ORDERED_LIST  OpCode;
 | |
|   UINTN                 Position;
 | |
| 
 | |
|   ASSERT (OptionsOpCodeHandle != NULL);
 | |
|   ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED | EFI_IFR_FLAG_REST_STYLE | EFI_IFR_FLAG_OPTIONS_ONLY))) == 0);
 | |
| 
 | |
|   ZeroMem (&OpCode, sizeof (OpCode));
 | |
|   OpCode.Question.Header.Prompt          = Prompt;
 | |
|   OpCode.Question.Header.Help            = Help;
 | |
|   OpCode.Question.QuestionId             = QuestionId;
 | |
|   OpCode.Question.VarStoreId             = VarStoreId;
 | |
|   OpCode.Question.VarStoreInfo.VarOffset = VarOffset;
 | |
|   OpCode.Question.Flags                  = QuestionFlags;
 | |
|   OpCode.MaxContainers                   = MaxContainers;
 | |
|   OpCode.Flags                           = OrderedListFlags;
 | |
| 
 | |
|   Position = InternalHiiOpCodeHandlePosition (OpCodeHandle);
 | |
|   InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_ORDERED_LIST_OP, sizeof (OpCode), 0, 1);
 | |
|   InternalHiiAppendOpCodes (OpCodeHandle, OptionsOpCodeHandle);
 | |
|   if (DefaultsOpCodeHandle != NULL) {
 | |
|     InternalHiiAppendOpCodes (OpCodeHandle, DefaultsOpCodeHandle);
 | |
|   }
 | |
|   HiiCreateEndOpCode (OpCodeHandle);
 | |
|   return InternalHiiOpCodeHandleBuffer (OpCodeHandle) + Position;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Create EFI_IFR_TEXT_OP opcode.
 | |
| 
 | |
|   If OpCodeHandle is NULL, then ASSERT().
 | |
| 
 | |
|   @param[in]  OpCodeHandle  Handle to the buffer of opcodes.
 | |
|   @param[in]  Prompt        String ID for Prompt.
 | |
|   @param[in]  Help          String ID for Help.
 | |
|   @param[in]  TextTwo       String ID for TextTwo.
 | |
| 
 | |
|   @retval NULL   There is not enough space left in Buffer to add the opcode.
 | |
|   @retval Other  A pointer to the created opcode.
 | |
| 
 | |
| **/
 | |
| UINT8 *
 | |
| EFIAPI
 | |
| HiiCreateTextOpCode (
 | |
|   IN VOID           *OpCodeHandle,
 | |
|   IN EFI_STRING_ID  Prompt,
 | |
|   IN EFI_STRING_ID  Help,
 | |
|   IN EFI_STRING_ID  TextTwo
 | |
|   )
 | |
| {
 | |
|   EFI_IFR_TEXT  OpCode;
 | |
| 
 | |
|   ZeroMem (&OpCode, sizeof (OpCode));
 | |
|   OpCode.Statement.Prompt = Prompt;
 | |
|   OpCode.Statement.Help   = Help;
 | |
|   OpCode.TextTwo          = TextTwo;
 | |
| 
 | |
|   return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_TEXT_OP, sizeof (OpCode));
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Create EFI_IFR_DATE_OP opcode.
 | |
| 
 | |
|   If OpCodeHandle is NULL, then ASSERT().
 | |
|   If any reserved bits are set in QuestionFlags, then ASSERT().
 | |
|   If any reserved bits are set in DateFlags, then ASSERT().
 | |
| 
 | |
|   @param[in]  OpCodeHandle          Handle to the buffer of opcodes.
 | |
|   @param[in]  QuestionId            Question ID
 | |
|   @param[in]  VarStoreId            Storage ID, optional. If DateFlags is not
 | |
|                                     QF_DATE_STORAGE_NORMAL, this parameter is ignored.
 | |
|   @param[in]  VarOffset             Offset in Storage or String ID of the name (VarName)
 | |
|                                     for this name/value pair, optional. If DateFlags is not
 | |
|                                     QF_DATE_STORAGE_NORMAL, this parameter is ignored.
 | |
|   @param[in]  Prompt                String ID for Prompt
 | |
|   @param[in]  Help                  String ID for Help
 | |
|   @param[in]  QuestionFlags         Flags in Question Header
 | |
|   @param[in]  DateFlags             Flags for date opcode
 | |
|   @param[in]  DefaultsOpCodeHandle  Handle for a buffer of DEFAULT opcodes.  This
 | |
|                                     is an optional parameter that may be NULL.
 | |
| 
 | |
|   @retval NULL   There is not enough space left in Buffer to add the opcode.
 | |
|   @retval Other  A pointer to the created opcode.
 | |
| 
 | |
| **/
 | |
| UINT8 *
 | |
| EFIAPI
 | |
| HiiCreateDateOpCode (
 | |
|   IN VOID             *OpCodeHandle,
 | |
|   IN EFI_QUESTION_ID  QuestionId,
 | |
|   IN EFI_VARSTORE_ID  VarStoreId,   OPTIONAL
 | |
|   IN UINT16           VarOffset,    OPTIONAL
 | |
|   IN EFI_STRING_ID    Prompt,
 | |
|   IN EFI_STRING_ID    Help,
 | |
|   IN UINT8            QuestionFlags,
 | |
|   IN UINT8            DateFlags,
 | |
|   IN VOID             *DefaultsOpCodeHandle  OPTIONAL
 | |
|   )
 | |
| {
 | |
|   EFI_IFR_DATE    OpCode;
 | |
|   UINTN           Position;
 | |
| 
 | |
|   ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED | EFI_IFR_FLAG_REST_STYLE))) == 0);
 | |
|   ASSERT ((DateFlags & (~(EFI_QF_DATE_YEAR_SUPPRESS | EFI_QF_DATE_MONTH_SUPPRESS | EFI_QF_DATE_DAY_SUPPRESS | EFI_QF_DATE_STORAGE))) == 0);
 | |
| 
 | |
|   ZeroMem (&OpCode, sizeof (OpCode));
 | |
|   OpCode.Question.Header.Prompt          = Prompt;
 | |
|   OpCode.Question.Header.Help            = Help;
 | |
|   OpCode.Question.QuestionId             = QuestionId;
 | |
|   OpCode.Question.VarStoreId             = VarStoreId;
 | |
|   OpCode.Question.VarStoreInfo.VarOffset = VarOffset;
 | |
|   OpCode.Question.Flags                  = QuestionFlags;
 | |
|   OpCode.Flags                           = DateFlags;
 | |
| 
 | |
|   if (DefaultsOpCodeHandle == NULL) {
 | |
|     return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_DATE_OP, sizeof (OpCode));
 | |
|   }
 | |
| 
 | |
|   Position = InternalHiiOpCodeHandlePosition (OpCodeHandle);
 | |
|   InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_DATE_OP, sizeof (OpCode), 0, 1);
 | |
|   InternalHiiAppendOpCodes (OpCodeHandle, DefaultsOpCodeHandle);
 | |
|   HiiCreateEndOpCode (OpCodeHandle);
 | |
|   return InternalHiiOpCodeHandleBuffer (OpCodeHandle) + Position;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Create EFI_IFR_TIME_OP opcode.
 | |
| 
 | |
|   If OpCodeHandle is NULL, then ASSERT().
 | |
|   If any reserved bits are set in QuestionFlags, then ASSERT().
 | |
|   If any reserved bits are set in TimeFlags, then ASSERT().
 | |
| 
 | |
|   @param[in]  OpCodeHandle          Handle to the buffer of opcodes.
 | |
|   @param[in]  QuestionId            Question ID
 | |
|   @param[in]  VarStoreId            Storage ID, optional. If TimeFlags is not
 | |
|                                     QF_TIME_STORAGE_NORMAL, this parameter is ignored.
 | |
|   @param[in]  VarOffset             Offset in Storage or String ID of the name (VarName)
 | |
|                                     for this name/value pair, optional. If TimeFlags is not
 | |
|                                     QF_TIME_STORAGE_NORMAL, this parameter is ignored.
 | |
|   @param[in]  Prompt                String ID for Prompt
 | |
|   @param[in]  Help                  String ID for Help
 | |
|   @param[in]  QuestionFlags         Flags in Question Header
 | |
|   @param[in]  TimeFlags             Flags for time opcode
 | |
|   @param[in]  DefaultsOpCodeHandle  Handle for a buffer of DEFAULT opcodes.  This
 | |
|                                     is an optional parameter that may be NULL.
 | |
| 
 | |
|   @retval NULL   There is not enough space left in Buffer to add the opcode.
 | |
|   @retval Other  A pointer to the created opcode.
 | |
| 
 | |
| **/
 | |
| UINT8 *
 | |
| EFIAPI
 | |
| HiiCreateTimeOpCode (
 | |
|   IN VOID             *OpCodeHandle,
 | |
|   IN EFI_QUESTION_ID  QuestionId,
 | |
|   IN EFI_VARSTORE_ID  VarStoreId,   OPTIONAL
 | |
|   IN UINT16           VarOffset,    OPTIONAL
 | |
|   IN EFI_STRING_ID    Prompt,
 | |
|   IN EFI_STRING_ID    Help,
 | |
|   IN UINT8            QuestionFlags,
 | |
|   IN UINT8            TimeFlags,
 | |
|   IN VOID             *DefaultsOpCodeHandle  OPTIONAL
 | |
|   )
 | |
| {
 | |
|   EFI_IFR_TIME    OpCode;
 | |
|   UINTN           Position;
 | |
| 
 | |
|   ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED | EFI_IFR_FLAG_REST_STYLE))) == 0);
 | |
|   ASSERT ((TimeFlags & (~(QF_TIME_HOUR_SUPPRESS | QF_TIME_MINUTE_SUPPRESS | QF_TIME_SECOND_SUPPRESS | QF_TIME_STORAGE))) == 0);
 | |
| 
 | |
|   ZeroMem (&OpCode, sizeof (OpCode));
 | |
|   OpCode.Question.Header.Prompt          = Prompt;
 | |
|   OpCode.Question.Header.Help            = Help;
 | |
|   OpCode.Question.QuestionId             = QuestionId;
 | |
|   OpCode.Question.VarStoreId             = VarStoreId;
 | |
|   OpCode.Question.VarStoreInfo.VarOffset = VarOffset;
 | |
|   OpCode.Question.Flags                  = QuestionFlags;
 | |
|   OpCode.Flags                           = TimeFlags;
 | |
| 
 | |
|   if (DefaultsOpCodeHandle == NULL) {
 | |
|     return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_TIME_OP, sizeof (OpCode));
 | |
|   }
 | |
| 
 | |
|   Position = InternalHiiOpCodeHandlePosition (OpCodeHandle);
 | |
|   InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_TIME_OP, sizeof (OpCode), 0, 1);
 | |
|   InternalHiiAppendOpCodes (OpCodeHandle, DefaultsOpCodeHandle);
 | |
|   HiiCreateEndOpCode (OpCodeHandle);
 | |
|   return InternalHiiOpCodeHandleBuffer (OpCodeHandle) + Position;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This is the internal worker function to update the data in
 | |
|   a form specified by FormSetGuid, FormId and Label.
 | |
| 
 | |
|   @param[in] FormSetGuid       The optional Formset GUID.
 | |
|   @param[in] FormId            The Form ID.
 | |
|   @param[in] Package           The package header.
 | |
|   @param[in] OpCodeBufferStart An OpCode buffer that contains the set of IFR
 | |
|                                opcodes to be inserted or replaced in the form.
 | |
|   @param[in] OpCodeBufferEnd   An OpCcode buffer that contains the IFR opcode
 | |
|                                that marks the end of a replace operation in the form.
 | |
|   @param[out] TempPackage      The resultant package.
 | |
| 
 | |
|   @retval EFI_SUCCESS    The function completes successfully.
 | |
|   @retval EFI_NOT_FOUND  The updated opcode or endopcode is not found.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| InternalHiiUpdateFormPackageData (
 | |
|   IN  EFI_GUID               *FormSetGuid, OPTIONAL
 | |
|   IN  EFI_FORM_ID            FormId,
 | |
|   IN  EFI_HII_PACKAGE_HEADER *Package,
 | |
|   IN  HII_LIB_OPCODE_BUFFER  *OpCodeBufferStart,
 | |
|   IN  HII_LIB_OPCODE_BUFFER  *OpCodeBufferEnd,    OPTIONAL
 | |
|   OUT EFI_HII_PACKAGE_HEADER *TempPackage
 | |
|   )
 | |
| {
 | |
|   UINTN                     AddSize;
 | |
|   UINT8                     *BufferPos;
 | |
|   EFI_HII_PACKAGE_HEADER    PackageHeader;
 | |
|   UINTN                     Offset;
 | |
|   EFI_IFR_OP_HEADER         *IfrOpHdr;
 | |
|   EFI_IFR_OP_HEADER         *UpdateIfrOpHdr;
 | |
|   BOOLEAN                   GetFormSet;
 | |
|   BOOLEAN                   GetForm;
 | |
|   BOOLEAN                   Updated;
 | |
|   UINTN                     UpdatePackageLength;
 | |
| 
 | |
|   CopyMem (TempPackage, Package, sizeof (EFI_HII_PACKAGE_HEADER));
 | |
|   UpdatePackageLength = sizeof (EFI_HII_PACKAGE_HEADER);
 | |
|   BufferPos           = (UINT8 *) (TempPackage + 1);
 | |
| 
 | |
|   CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
 | |
|   IfrOpHdr   = (EFI_IFR_OP_HEADER *)((UINT8 *) Package + sizeof (EFI_HII_PACKAGE_HEADER));
 | |
|   Offset     = sizeof (EFI_HII_PACKAGE_HEADER);
 | |
|   GetFormSet = (BOOLEAN) ((FormSetGuid == NULL) ? TRUE : FALSE);
 | |
|   GetForm    = FALSE;
 | |
|   Updated    = FALSE;
 | |
| 
 | |
|   while (Offset < PackageHeader.Length) {
 | |
|     CopyMem (BufferPos, IfrOpHdr, IfrOpHdr->Length);
 | |
|     BufferPos           += IfrOpHdr->Length;
 | |
|     UpdatePackageLength += IfrOpHdr->Length;
 | |
| 
 | |
|     //
 | |
|     // Find the matched FormSet and Form
 | |
|     //
 | |
|     if ((IfrOpHdr->OpCode == EFI_IFR_FORM_SET_OP) && (FormSetGuid != NULL)) {
 | |
|       if (CompareGuid((GUID *)(VOID *)&((EFI_IFR_FORM_SET *) IfrOpHdr)->Guid, FormSetGuid)) {
 | |
|         GetFormSet = TRUE;
 | |
|       } else {
 | |
|         GetFormSet = FALSE;
 | |
|       }
 | |
|     } else if (IfrOpHdr->OpCode == EFI_IFR_FORM_OP || IfrOpHdr->OpCode == EFI_IFR_FORM_MAP_OP) {
 | |
|       if (CompareMem (&((EFI_IFR_FORM *) IfrOpHdr)->FormId, &FormId, sizeof (EFI_FORM_ID)) == 0) {
 | |
|         GetForm = TRUE;
 | |
|       } else {
 | |
|         GetForm = FALSE;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // The matched Form is found, and Update data in this form
 | |
|     //
 | |
|     if (GetFormSet && GetForm) {
 | |
|       UpdateIfrOpHdr = (EFI_IFR_OP_HEADER *) OpCodeBufferStart->Buffer;
 | |
|       if ((UpdateIfrOpHdr->Length == IfrOpHdr->Length) && \
 | |
|           (CompareMem (IfrOpHdr, UpdateIfrOpHdr, UpdateIfrOpHdr->Length) == 0)) {
 | |
|         //
 | |
|         // Remove the original data when End OpCode buffer exist.
 | |
|         //
 | |
|         if (OpCodeBufferEnd != NULL) {
 | |
|           Offset        += IfrOpHdr->Length;
 | |
|           IfrOpHdr       = (EFI_IFR_OP_HEADER *) ((UINT8 *) (IfrOpHdr) + IfrOpHdr->Length);
 | |
|           UpdateIfrOpHdr = (EFI_IFR_OP_HEADER *) OpCodeBufferEnd->Buffer;
 | |
|           while (Offset < PackageHeader.Length) {
 | |
|             //
 | |
|             // Search the matched end opcode
 | |
|             //
 | |
|             if ((UpdateIfrOpHdr->Length == IfrOpHdr->Length) && \
 | |
|                 (CompareMem (IfrOpHdr, UpdateIfrOpHdr, UpdateIfrOpHdr->Length) == 0)) {
 | |
|               break;
 | |
|             }
 | |
|             //
 | |
|             // Go to the next Op-Code
 | |
|             //
 | |
|             Offset        += IfrOpHdr->Length;
 | |
|             IfrOpHdr       = (EFI_IFR_OP_HEADER *) ((UINT8 *) (IfrOpHdr) + IfrOpHdr->Length);
 | |
|           }
 | |
| 
 | |
|           if (Offset >= PackageHeader.Length) {
 | |
|             //
 | |
|             // The end opcode is not found.
 | |
|             //
 | |
|             return EFI_NOT_FOUND;
 | |
|           }
 | |
|         }
 | |
| 
 | |
|         //
 | |
|         // Insert the updated data
 | |
|         //
 | |
|         AddSize = ((EFI_IFR_OP_HEADER *) OpCodeBufferStart->Buffer)->Length;
 | |
|         CopyMem (BufferPos, OpCodeBufferStart->Buffer + AddSize, OpCodeBufferStart->Position - AddSize);
 | |
|         BufferPos           += OpCodeBufferStart->Position - AddSize;
 | |
|         UpdatePackageLength += OpCodeBufferStart->Position - AddSize;
 | |
| 
 | |
|         if (OpCodeBufferEnd != NULL) {
 | |
|           //
 | |
|           // Add the end opcode
 | |
|           //
 | |
|           CopyMem (BufferPos, IfrOpHdr, IfrOpHdr->Length);
 | |
|           BufferPos           += IfrOpHdr->Length;
 | |
|           UpdatePackageLength += IfrOpHdr->Length;
 | |
|         }
 | |
| 
 | |
|         //
 | |
|         // Copy the left package data.
 | |
|         //
 | |
|         Offset += IfrOpHdr->Length;
 | |
|         CopyMem (BufferPos, (UINT8 *) Package + Offset, PackageHeader.Length - Offset);
 | |
|         UpdatePackageLength += PackageHeader.Length - Offset;
 | |
| 
 | |
|         //
 | |
|         // Set update flag
 | |
|         //
 | |
|         Updated = TRUE;
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Go to the next Op-Code
 | |
|     //
 | |
|     Offset   += IfrOpHdr->Length;
 | |
|     IfrOpHdr = (EFI_IFR_OP_HEADER *) ((CHAR8 *) (IfrOpHdr) + IfrOpHdr->Length);
 | |
|   }
 | |
| 
 | |
|   if (!Updated) {
 | |
|     //
 | |
|     // The updated opcode buffer is not found.
 | |
|     //
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
|   //
 | |
|   // Update the package length.
 | |
|   //
 | |
|   PackageHeader.Length = (UINT32) UpdatePackageLength;
 | |
|   CopyMem (TempPackage, &PackageHeader, sizeof (EFI_HII_PACKAGE_HEADER));
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function updates a form that has previously been registered with the HII
 | |
|   Database.  This function will perform at most one update operation.
 | |
| 
 | |
|   The form to update is specified by Handle, FormSetGuid, and FormId.  Binary
 | |
|   comparisons of IFR opcodes are performed from the beginning of the form being
 | |
|   updated until an IFR opcode is found that exactly matches the first IFR opcode
 | |
|   specified by StartOpCodeHandle.  The following rules are used to determine if
 | |
|   an insert, replace, or delete operation is performed.
 | |
| 
 | |
|   1) If no matches are found, then NULL is returned.
 | |
|   2) If a match is found, and EndOpCodeHandle is NULL, then all of the IFR opcodes
 | |
|      from StartOpCodeHandle except the first opcode are inserted immediately after
 | |
|      the matching IFR opcode in the form to be updated.
 | |
|   3) If a match is found, and EndOpCodeHandle is not NULL, then a search is made
 | |
|      from the matching IFR opcode until an IFR opcode exactly matches the first
 | |
|      IFR opcode specified by EndOpCodeHandle.  If no match is found for the first
 | |
|      IFR opcode specified by EndOpCodeHandle, then NULL is returned.  If a match
 | |
|      is found, then all of the IFR opcodes between the start match and the end
 | |
|      match are deleted from the form being updated and all of the IFR opcodes
 | |
|      from StartOpCodeHandle except the first opcode are inserted immediately after
 | |
|      the matching start IFR opcode.  If StartOpCcodeHandle only contains one
 | |
|      IFR instruction, then the result of this operation will delete all of the IFR
 | |
|      opcodes between the start end matches.
 | |
| 
 | |
|   If HiiHandle is NULL, then ASSERT().
 | |
|   If StartOpCodeHandle is NULL, then ASSERT().
 | |
| 
 | |
|   @param[in]  HiiHandle          The HII Handle of the form to update.
 | |
|   @param[in]  FormSetGuid        The Formset GUID of the form to update.  This
 | |
|                                  is an optional parameter that may be NULL.
 | |
|                                  If it is NULL, all FormSet will be updated.
 | |
|   @param[in]  FormId             The ID of the form to update.
 | |
|   @param[in]  StartOpCodeHandle  An OpCode Handle that contains the set of IFR
 | |
|                                  opcodes to be inserted or replaced in the form.
 | |
|                                  The first IFR instruction in StartOpCodeHandle
 | |
|                                  is used to find matching IFR opcode in the
 | |
|                                  form.
 | |
|   @param[in]  EndOpCodeHandle    An OpCcode Handle that contains the IFR opcode
 | |
|                                  that marks the end of a replace operation in
 | |
|                                  the form.  This is an optional parameter that
 | |
|                                  may be NULL.  If it is NULL, then an the IFR
 | |
|                                  opcodes specified by StartOpCodeHandle are
 | |
|                                  inserted into the form.
 | |
| 
 | |
|   @retval EFI_OUT_OF_RESOURCES   No enough memory resource is allocated.
 | |
|   @retval EFI_NOT_FOUND          The following cases will return EFI_NOT_FOUND.
 | |
|                                  1) The form specified by HiiHandle, FormSetGuid,
 | |
|                                  and FormId could not be found in the HII Database.
 | |
|                                  2) No IFR opcodes in the target form match the first
 | |
|                                  IFR opcode in StartOpCodeHandle.
 | |
|                                  3) EndOpCOde is not NULL, and no IFR opcodes in the
 | |
|                                  target form following a matching start opcode match
 | |
|                                  the first IFR opcode in EndOpCodeHandle.
 | |
|   @retval EFI_SUCCESS            The matched form is updated by StartOpcode.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| HiiUpdateForm (
 | |
|   IN EFI_HII_HANDLE  HiiHandle,
 | |
|   IN EFI_GUID        *FormSetGuid,        OPTIONAL
 | |
|   IN EFI_FORM_ID     FormId,
 | |
|   IN VOID            *StartOpCodeHandle,
 | |
|   IN VOID            *EndOpCodeHandle     OPTIONAL
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                   Status;
 | |
|   EFI_HII_PACKAGE_LIST_HEADER  *HiiPackageList;
 | |
|   UINT32                       PackageListLength;
 | |
|   UINT32                       Offset;
 | |
|   EFI_HII_PACKAGE_LIST_HEADER  *UpdatePackageList;
 | |
|   UINTN                        BufferSize;
 | |
|   UINT8                        *UpdateBufferPos;
 | |
|   EFI_HII_PACKAGE_HEADER       *Package;
 | |
|   EFI_HII_PACKAGE_HEADER       *TempPackage;
 | |
|   EFI_HII_PACKAGE_HEADER       PackageHeader;
 | |
|   BOOLEAN                      Updated;
 | |
|   HII_LIB_OPCODE_BUFFER        *OpCodeBufferStart;
 | |
|   HII_LIB_OPCODE_BUFFER        *OpCodeBufferEnd;
 | |
| 
 | |
|   //
 | |
|   // Input update data can't be NULL.
 | |
|   //
 | |
|   ASSERT (HiiHandle != NULL);
 | |
|   ASSERT (StartOpCodeHandle != NULL);
 | |
|   UpdatePackageList = NULL;
 | |
|   TempPackage       = NULL;
 | |
|   HiiPackageList    = NULL;
 | |
| 
 | |
|   //
 | |
|   // Retrieve buffer data from Opcode Handle
 | |
|   //
 | |
|   OpCodeBufferStart = (HII_LIB_OPCODE_BUFFER *) StartOpCodeHandle;
 | |
|   OpCodeBufferEnd   = (HII_LIB_OPCODE_BUFFER *) EndOpCodeHandle;
 | |
| 
 | |
|   //
 | |
|   // Get the original package list
 | |
|   //
 | |
|   BufferSize = 0;
 | |
|   HiiPackageList   = NULL;
 | |
|   Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, HiiHandle, &BufferSize, HiiPackageList);
 | |
|   //
 | |
|   // The return status should always be EFI_BUFFER_TOO_SMALL as input buffer's size is 0.
 | |
|   //
 | |
|   if (Status != EFI_BUFFER_TOO_SMALL) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   HiiPackageList = AllocatePool (BufferSize);
 | |
|   if (HiiPackageList == NULL) {
 | |
|     Status = EFI_OUT_OF_RESOURCES;
 | |
|     goto Finish;
 | |
|   }
 | |
| 
 | |
|   Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, HiiHandle, &BufferSize, HiiPackageList);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto Finish;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Calculate and allocate space for retrieval of IFR data
 | |
|   //
 | |
|   BufferSize += OpCodeBufferStart->Position;
 | |
|   UpdatePackageList = AllocateZeroPool (BufferSize);
 | |
|   if (UpdatePackageList == NULL) {
 | |
|     Status = EFI_OUT_OF_RESOURCES;
 | |
|     goto Finish;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Allocate temp buffer to store the temp updated package buffer
 | |
|   //
 | |
|   TempPackage = AllocateZeroPool (BufferSize);
 | |
|   if (TempPackage == NULL) {
 | |
|     Status = EFI_OUT_OF_RESOURCES;
 | |
|     goto Finish;
 | |
|   }
 | |
| 
 | |
|   UpdateBufferPos = (UINT8 *) UpdatePackageList;
 | |
| 
 | |
|   //
 | |
|   // Copy the package list header
 | |
|   //
 | |
|   CopyMem (UpdateBufferPos, HiiPackageList, sizeof (EFI_HII_PACKAGE_LIST_HEADER));
 | |
|   UpdateBufferPos += sizeof (EFI_HII_PACKAGE_LIST_HEADER);
 | |
| 
 | |
|   //
 | |
|   // Go through each package to find the matched package and update one by one
 | |
|   //
 | |
|   Updated = FALSE;
 | |
|   Offset  = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
 | |
|   PackageListLength = ReadUnaligned32 (&HiiPackageList->PackageLength);
 | |
|   while (Offset < PackageListLength) {
 | |
|     Package = (EFI_HII_PACKAGE_HEADER *) (((UINT8 *) HiiPackageList) + Offset);
 | |
|     CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
 | |
|     Offset += Package->Length;
 | |
| 
 | |
|     if (Package->Type == EFI_HII_PACKAGE_FORMS) {
 | |
|       //
 | |
|       // Check this package is the matched package.
 | |
|       //
 | |
|       Status = InternalHiiUpdateFormPackageData (FormSetGuid, FormId, Package, OpCodeBufferStart, OpCodeBufferEnd, TempPackage);
 | |
|       //
 | |
|       // The matched package is found. Its package buffer will be updated by the input new data.
 | |
|       //
 | |
|       if (!EFI_ERROR(Status)) {
 | |
|         //
 | |
|         // Set Update Flag
 | |
|         //
 | |
|         Updated = TRUE;
 | |
|         //
 | |
|         // Add updated package buffer
 | |
|         //
 | |
|         Package = TempPackage;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Add pacakge buffer
 | |
|     //
 | |
|     CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
 | |
|     CopyMem (UpdateBufferPos, Package, PackageHeader.Length);
 | |
|     UpdateBufferPos += PackageHeader.Length;
 | |
|   }
 | |
| 
 | |
|   if (Updated) {
 | |
|     //
 | |
|     // Update package list length
 | |
|     //
 | |
|     BufferSize = UpdateBufferPos - (UINT8 *) UpdatePackageList;
 | |
|     WriteUnaligned32 (&UpdatePackageList->PackageLength, (UINT32) BufferSize);
 | |
| 
 | |
|     //
 | |
|     // Update Package to show form
 | |
|     //
 | |
|     Status = gHiiDatabase->UpdatePackageList (gHiiDatabase, HiiHandle, UpdatePackageList);
 | |
|   } else {
 | |
|     //
 | |
|     // Not matched form is found and updated.
 | |
|     //
 | |
|     Status = EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
| Finish:
 | |
|   if (HiiPackageList != NULL) {
 | |
|     FreePool (HiiPackageList);
 | |
|   }
 | |
| 
 | |
|   if (UpdatePackageList != NULL) {
 | |
|     FreePool (UpdatePackageList);
 | |
|   }
 | |
| 
 | |
|   if (TempPackage != NULL) {
 | |
|     FreePool (TempPackage);
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 |