| /** @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; | |
| } |