mirror of https://github.com/acidanthera/audk.git
3655 lines
115 KiB
C
3655 lines
115 KiB
C
/** @file
|
|
HII Library implementation that uses DXE protocols and services.
|
|
|
|
Copyright (c) 2006 - 2010, Intel Corporation<BR>
|
|
All rights reserved. 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;
|
|
|
|
//
|
|
// <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.
|
|
@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;
|
|
break;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
/**
|
|
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.
|
|
|
|
@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
|
|
)
|
|
{
|
|
IFR_BLOCK_DATA *CurrentBlockArray;
|
|
IFR_BLOCK_DATA *BlockData;
|
|
IFR_BLOCK_DATA *NewBlockData;
|
|
IFR_BLOCK_DATA VarBlockData;
|
|
EFI_STRING StringPtr;
|
|
UINTN Length;
|
|
UINT8 *TmpBuffer;
|
|
UINT16 Offset;
|
|
UINT16 Width;
|
|
UINT64 VarValue;
|
|
LIST_ENTRY *Link;
|
|
UINT8 *VarBuffer;
|
|
UINTN MaxBufferSize;
|
|
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_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;
|
|
|
|
//
|
|
// 1. Get the current setting to current block data array and Convert them into VarBuffer
|
|
//
|
|
|
|
//
|
|
// Skip ConfigHdr string
|
|
//
|
|
StringPtr = ConfigResp;
|
|
StringPtr = StrStr (ConfigResp, L"&OFFSET");
|
|
if (StringPtr == NULL) {
|
|
//
|
|
// No ConfigBlock value is required to be validated.
|
|
// EFI_SUCCESS directly return.
|
|
//
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Initialize the local variables.
|
|
//
|
|
Index = 0;
|
|
VarStoreName = NULL;
|
|
Status = EFI_SUCCESS;
|
|
BlockData = NULL;
|
|
NewBlockData = NULL;
|
|
TmpBuffer = NULL;
|
|
MaxBufferSize = HII_LIB_DEFAULT_VARSTORE_SIZE;
|
|
VarBuffer = AllocateZeroPool (MaxBufferSize);
|
|
if (VarBuffer == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Init CurrentBlockArray
|
|
//
|
|
CurrentBlockArray = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
|
|
if (CurrentBlockArray == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto Done;
|
|
}
|
|
InitializeListHead (&CurrentBlockArray->Entry);
|
|
|
|
//
|
|
// 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) {
|
|
VarBuffer = ReallocatePool (
|
|
MaxBufferSize,
|
|
Offset + Width + HII_LIB_DEFAULT_VARSTORE_SIZE,
|
|
VarBuffer
|
|
);
|
|
if (VarBuffer == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto Done;
|
|
}
|
|
MaxBufferSize = Offset + Width + HII_LIB_DEFAULT_VARSTORE_SIZE;
|
|
}
|
|
|
|
//
|
|
// Update the Block with configuration info
|
|
//
|
|
CopyMem (VarBuffer + 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 = CurrentBlockArray->Entry.ForwardLink; Link != &CurrentBlockArray->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 == &CurrentBlockArray->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 = CurrentBlockArray->Entry.ForwardLink;
|
|
while ((Link != &CurrentBlockArray->Entry) && (Link->ForwardLink != &CurrentBlockArray->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;
|
|
}
|
|
|
|
if (IsListEmpty (&CurrentBlockArray->Entry)) {
|
|
Status = EFI_SUCCESS;
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// 2. Check IFR value is in block data, then Validate Value
|
|
//
|
|
ZeroMem (&VarBlockData, sizeof (VarBlockData));
|
|
VarValue = 0;
|
|
IfrVarStore = NULL;
|
|
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 (IfrVarStore != NULL) {
|
|
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;
|
|
}
|
|
break;
|
|
case EFI_IFR_FORM_OP:
|
|
case EFI_IFR_FORM_MAP_OP:
|
|
//
|
|
// Check the matched VarStoreId is found.
|
|
//
|
|
if (IfrVarStore == NULL) {
|
|
Status = EFI_SUCCESS;
|
|
goto Done;
|
|
}
|
|
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 (IfrVarStore == NULL) {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto Done;
|
|
}
|
|
//
|
|
// Check whether this question is for the requested varstore.
|
|
//
|
|
IfrOneOf = (EFI_IFR_ONE_OF *) IfrOpHdr;
|
|
if (IfrOneOf->Question.VarStoreId != IfrVarStore->VarStoreId) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// 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) > IfrVarStore->Size) {
|
|
//
|
|
// This question exceeds the var store size.
|
|
//
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// 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.Offset = Offset;
|
|
VarBlockData.Width = Width;
|
|
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 (IfrVarStore == NULL) {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto Done;
|
|
}
|
|
//
|
|
// Check whether this question is for the requested varstore.
|
|
//
|
|
IfrNumeric = (EFI_IFR_NUMERIC *) IfrOpHdr;
|
|
if (IfrNumeric->Question.VarStoreId != IfrVarStore->VarStoreId) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// 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) > IfrVarStore->Size) {
|
|
//
|
|
// This question exceeds the var store size.
|
|
//
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// 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.
|
|
//
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto Done;
|
|
}
|
|
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.
|
|
//
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto Done;
|
|
}
|
|
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.
|
|
//
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto Done;
|
|
}
|
|
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.
|
|
//
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto Done;
|
|
}
|
|
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 (IfrVarStore == NULL) {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// Check whether this question is for the requested varstore.
|
|
//
|
|
IfrCheckBox = (EFI_IFR_CHECKBOX *) IfrOpHdr;
|
|
if (IfrCheckBox->Question.VarStoreId != IfrVarStore->VarStoreId) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Get Offset by Question header
|
|
//
|
|
Offset = IfrCheckBox->Question.VarStoreInfo.VarOffset;
|
|
Width = 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) > IfrVarStore->Size) {
|
|
//
|
|
// This question exceeds the var store size.
|
|
//
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// Boolean type, only 1 and 0 is valid.
|
|
//
|
|
if (*(VarBuffer + Offset) > 1) {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto Done;
|
|
}
|
|
|
|
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 (IfrVarStore == NULL) {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// Check whether this question is for the requested varstore.
|
|
//
|
|
IfrString = (EFI_IFR_STRING *) IfrOpHdr;
|
|
if (IfrString->Question.VarStoreId != IfrVarStore->VarStoreId) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Get Offset/Width by Question header and OneOf Flags
|
|
//
|
|
Offset = IfrString->Question.VarStoreInfo.VarOffset;
|
|
Width = (UINT16) (IfrString->MaxSize * sizeof (UINT16));
|
|
//
|
|
// 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) > IfrVarStore->Size) {
|
|
//
|
|
// This question exceeds the var store size.
|
|
//
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// Check current string length is less than maxsize
|
|
//
|
|
if (StrSize ((CHAR16 *) (VarBuffer + Offset)) > Width) {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto Done;
|
|
}
|
|
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.
|
|
//
|
|
if (VarValue == IfrOneOfOption->Value.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)) {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto Done;
|
|
}
|
|
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;
|
|
}
|
|
|
|
Done:
|
|
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;
|
|
}
|
|
|
|
/**
|
|
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_STRING_ID DefaultName;
|
|
|
|
UINT8 *PackageData;
|
|
UINTN IfrOffset;
|
|
EFI_IFR_OP_HEADER *IfrOpHdr;
|
|
EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList;
|
|
UINT32 PackageOffset;
|
|
UINTN PackageListLength;
|
|
EFI_HII_PACKAGE_HEADER PacakgeHeader;
|
|
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;
|
|
PackageData = 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 DefaultName string ID by parsing the PacakgeList
|
|
//
|
|
|
|
//
|
|
// 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;
|
|
}
|
|
|
|
//
|
|
// Parse the form package and get the default name string ID.
|
|
//
|
|
if (ActionType == ACTION_SET_DEFAUTL_VALUE) {
|
|
PackageOffset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
|
|
Status = EFI_NOT_FOUND;
|
|
while (PackageOffset < PackageListLength) {
|
|
CopyMem (&PacakgeHeader, (UINT8 *) HiiPackageList + PackageOffset, sizeof (PacakgeHeader));
|
|
|
|
//
|
|
// Parse IFR opcode to get default store opcode
|
|
//
|
|
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);
|
|
//
|
|
// Match DefaultId to find its DefaultName
|
|
//
|
|
if (IfrOpHdr->OpCode == EFI_IFR_DEFAULTSTORE_OP) {
|
|
if (((EFI_IFR_DEFAULTSTORE *) IfrOpHdr)->DefaultId == DefaultId) {
|
|
DefaultName = ((EFI_IFR_DEFAULTSTORE *) IfrOpHdr)->DefaultName;
|
|
Status = EFI_SUCCESS;
|
|
break;
|
|
}
|
|
}
|
|
IfrOffset += IfrOpHdr->Length;
|
|
}
|
|
//
|
|
// Only one form is in a package list.
|
|
//
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Go to next package.
|
|
//
|
|
PackageOffset += PacakgeHeader.Length;
|
|
}
|
|
|
|
//
|
|
// Not found the matched default string ID
|
|
//
|
|
if (EFI_ERROR (Status)) {
|
|
Status = EFI_SUCCESS;
|
|
goto NextConfigAltResp;
|
|
}
|
|
}
|
|
|
|
//
|
|
// 3. Call ConfigRouting GetAltCfg(ConfigRoute, <ConfigResponse>, Guid, Name, DevicePath, AltCfgId, AltCfgResp)
|
|
// Get the default configuration string according to the found default name string ID.
|
|
//
|
|
Status = gHiiConfigRouting->GetAltConfig (
|
|
gHiiConfigRouting,
|
|
ConfigAltResp,
|
|
VarGuid,
|
|
VarName,
|
|
DevicePath,
|
|
(ActionType == ACTION_SET_DEFAUTL_VALUE) ? &DefaultName: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 (StrStr (ConfigResp, L"&OFFSET=") == NULL) {
|
|
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);
|
|
}
|
|
|
|
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 TURE 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
|
|
);
|
|
if (Buffer == NULL) {
|
|
return 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, sizeof (OpCode));
|
|
}
|
|
|
|
/**
|
|
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, sizeof (OpCode));
|
|
}
|
|
|
|
/**
|
|
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 | EFI_IFR_FLAG_OPTIONS_ONLY))) == 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 | 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.Flags = QuestionFlags;
|
|
OpCode.FormId = FormId;
|
|
|
|
return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_REF_OP, sizeof (OpCode));
|
|
}
|
|
|
|
/**
|
|
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
|
|
@param[in] Prompt String ID for Prompt
|
|
@param[in] Help String ID for Help
|
|
@param[in] QuestionFlags Flags in Question Header
|
|
@param[in] CheckBoxFlags Flags for checkbox opcode
|
|
@param[in] DefaultsOpCodeHandle Handle for a buffer of DEFAULT opcodes. This
|
|
is an optional parameter that may be NULL.
|
|
|
|
@retval NULL There is not enough space left in Buffer to add the opcode.
|
|
@retval Other A pointer to the created opcode.
|
|
|
|
**/
|
|
UINT8 *
|
|
EFIAPI
|
|
HiiCreateCheckBoxOpCode (
|
|
IN VOID *OpCodeHandle,
|
|
IN EFI_QUESTION_ID QuestionId,
|
|
IN EFI_VARSTORE_ID VarStoreId,
|
|
IN UINT16 VarOffset,
|
|
IN EFI_STRING_ID Prompt,
|
|
IN EFI_STRING_ID Help,
|
|
IN UINT8 QuestionFlags,
|
|
IN UINT8 CheckBoxFlags,
|
|
IN VOID *DefaultsOpCodeHandle OPTIONAL
|
|
)
|
|
{
|
|
EFI_IFR_CHECKBOX OpCode;
|
|
UINTN Position;
|
|
|
|
ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED | EFI_IFR_FLAG_OPTIONS_ONLY))) == 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
|
|
@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;
|
|
|
|
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.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;
|
|
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;
|
|
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;
|
|
break;
|
|
|
|
case EFI_IFR_NUMERIC_SIZE_8:
|
|
OpCode.data.u64.MinValue = Minimum;
|
|
OpCode.data.u64.MaxValue = Maximum;
|
|
OpCode.data.u64.Step = Step;
|
|
break;
|
|
}
|
|
|
|
if (DefaultsOpCodeHandle == NULL) {
|
|
return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_NUMERIC_OP, sizeof (OpCode));
|
|
}
|
|
|
|
Position = InternalHiiOpCodeHandlePosition (OpCodeHandle);
|
|
InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_NUMERIC_OP, sizeof (OpCode), 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
|
|
@param[in] Prompt String ID for Prompt
|
|
@param[in] Help String ID for Help
|
|
@param[in] QuestionFlags Flags in Question Header
|
|
@param[in] StringFlags Flags for string opcode
|
|
@param[in] MinSize String minimum length
|
|
@param[in] MaxSize String maximum length
|
|
@param[in] DefaultsOpCodeHandle Handle for a buffer of DEFAULT opcodes. This
|
|
is an optional parameter that may be NULL.
|
|
|
|
@retval NULL There is not enough space left in Buffer to add the opcode.
|
|
@retval Other A pointer to the created opcode.
|
|
|
|
**/
|
|
UINT8 *
|
|
EFIAPI
|
|
HiiCreateStringOpCode (
|
|
IN VOID *OpCodeHandle,
|
|
IN EFI_QUESTION_ID QuestionId,
|
|
IN EFI_VARSTORE_ID VarStoreId,
|
|
IN UINT16 VarOffset,
|
|
IN EFI_STRING_ID Prompt,
|
|
IN EFI_STRING_ID Help,
|
|
IN UINT8 QuestionFlags,
|
|
IN UINT8 StringFlags,
|
|
IN UINT8 MinSize,
|
|
IN UINT8 MaxSize,
|
|
IN VOID *DefaultsOpCodeHandle OPTIONAL
|
|
)
|
|
{
|
|
EFI_IFR_STRING OpCode;
|
|
UINTN Position;
|
|
|
|
ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED | EFI_IFR_FLAG_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.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
|
|
@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;
|
|
|
|
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;
|
|
|
|
Position = InternalHiiOpCodeHandlePosition (OpCodeHandle);
|
|
InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_ONE_OF_OP, sizeof (OpCode), 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
|
|
@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;
|
|
}
|
|
|
|
/**
|
|
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;
|
|
}
|