/** @file | |
HII Library implementation that uses DXE protocols and services. | |
Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR> | |
This program and the accompanying materials | |
are licensed and made available under the terms and conditions of the BSD License | |
which accompanies this distribution. The full text of the license may be found at | |
http://opensource.org/licenses/bsd-license.php | |
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
**/ | |
#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; | |
} | |
} | |
} | |
/** | |
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 hexidecimal 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 | |
hexidecimal 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 hexidecimal 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; | |
// | |
// 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 | | |
// | |
String = AllocateZeroPool ((5 + sizeof (EFI_GUID) * 2 + 6 + NameLength * 4 + 6 + DevicePathSize * 2 + 1) * sizeof (CHAR16)); | |
if (String == NULL) { | |
return NULL; | |
} | |
// | |
// Start with L"GUID=" | |
// | |
ReturnString = StrCpy (String, L"GUID="); | |
String += StrLen (String); | |
if (Guid != NULL) { | |
// | |
// Append Guid converted to <HexCh>32 | |
// | |
for (Index = 0, Buffer = (UINT8 *)Guid; Index < sizeof (EFI_GUID); Index++) { | |
String += UnicodeValueToString (String, PREFIX_ZERO | RADIX_HEX, *(Buffer++), 2); | |
} | |
} | |
// | |
// Append L"&NAME=" | |
// | |
StrCpy (String, L"&NAME="); | |
String += StrLen (String); | |
if (Name != NULL) { | |
// | |
// Append Name converted to <Char>NameLength | |
// | |
for (; *Name != L'\0'; Name++) { | |
String += UnicodeValueToString (String, PREFIX_ZERO | RADIX_HEX, *Name, 4); | |
} | |
} | |
// | |
// Append L"&PATH=" | |
// | |
StrCpy (String, 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++) { | |
String += UnicodeValueToString (String, PREFIX_ZERO | RADIX_HEX, *(Buffer++), 2); | |
} | |
// | |
// 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) { | |
StrnCpy (TemStr, 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 PacakgeHeader; | |
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; | |
// | |
// 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)); | |
// | |
// Check IFR value is in block data, then Validate Value | |
// | |
PackageOffset = sizeof (EFI_HII_PACKAGE_LIST_HEADER); | |
while (PackageOffset < PackageListLength) { | |
CopyMem (&PacakgeHeader, (UINT8 *) HiiPackageList + PackageOffset, sizeof (PacakgeHeader)); | |
// | |
// Parse IFR opcode from the form package. | |
// | |
if (PacakgeHeader.Type == EFI_HII_PACKAGE_FORMS) { | |
IfrOffset = sizeof (PacakgeHeader); | |
PackageData = (UINT8 *) HiiPackageList + PackageOffset; | |
while (IfrOffset < PacakgeHeader.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 | |
// | |
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; | |
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 | |
// | |
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; | |
CopyMem (&VarValue, VarBuffer + Offset, Width); | |
} | |
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 | |
// | |
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; | |
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 Width by OneOf Flags | |
// | |
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 "=". | |
// | |
StringPtr += 1; | |
// | |
// Check current string length is less than maxsize | |
// | |
if (StrSize (StringPtr) > Width) { | |
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 (StrSize ((CHAR16 *) (VarBuffer + Offset)) > Width) { | |
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: | |
// | |
// 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; | |
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 += PacakgeHeader.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 ((UINTN) (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 TURE 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; | |
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; | |
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 | | |
// | |
ConfigAltHdr = AllocateZeroPool ((1 + StringPtr - StringHdr + 8 + 1) * sizeof (CHAR16)); | |
if (ConfigAltHdr == NULL) { | |
Status = EFI_OUT_OF_RESOURCES; | |
goto Done; | |
} | |
StrCpy (ConfigAltHdr, L"&"); | |
StrnCat (ConfigAltHdr, StringHdr, StringPtr - StringHdr); | |
StrCat (ConfigAltHdr, 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 TURE 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))) == 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))) == 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))) == 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_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_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))) == 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))) == 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 *TempPacakge; | |
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; | |
TempPacakge = 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 | |
// | |
TempPacakge = AllocateZeroPool (BufferSize); | |
if (TempPacakge == 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, TempPacakge); | |
// | |
// 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 = TempPacakge; | |
} | |
} | |
// | |
// 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 (TempPacakge != NULL) { | |
FreePool (TempPacakge); | |
} | |
return Status; | |
} |