alder_lake_bios/Insyde/InsydeModulePkg/Library/H2OHiiConfigAccessLib/HiiConfigAccessLib.c

476 lines
14 KiB
C

/** @file
HII Library implementation that uses DXE protocols and services.
;******************************************************************************
;* Copyright (c) 2012 - 2020, Insyde Software Corp. All Rights Reserved.
;*
;* You may not reproduce, distribute, publish, display, perform, modify, adapt,
;* transmit, broadcast, present, recite, release, license or otherwise exploit
;* any part of this publication in any form, by any means, without the prior
;* written permission of Insyde Software Corporation.
;*
;******************************************************************************
Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include <Uefi.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/PrintLib.h>
#include <Library/UefiLib.h>
#include <Library/DevicePathLib.h>
#include <Protocol/HiiConfigAccess.h>
#define GUID_CONFIG_STRING_TYPE 0x00
#define NAME_CONFIG_STRING_TYPE 0x01
#define PATH_CONFIG_STRING_TYPE 0x02
/**
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);
if (ConfigString == NULL) {
return 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;
}
/**
Allocates and returns a Null-terminated Unicode <ConfigHdr> string using routing
information that includes a GUID, an optional Unicode string name, and a device
path. The string returned is allocated with AllocatePool(). The caller is
responsible for freeing the allocated string with FreePool().
The format of a <ConfigHdr> is as follows:
GUID=<HexCh>32&NAME=<Char>NameLength&PATH=<HexChar>DevicePathSize<Null>
@param[in] Guid Pointer to an EFI_GUID that is the routing information
GUID. Each of the 16 bytes in Guid is converted to
a 2 Unicode character hexadecimal string. This is
an optional parameter that may be NULL.
@param[in] Name Pointer to a Null-terminated Unicode string that is
the routing information NAME. This is an optional
parameter that may be NULL. Each 16-bit Unicode
character in Name is converted to a 4 character Unicode
hexadecimal string.
@param[in] DriverHandle The driver handle which supports a Device Path Protocol
that is the routing information PATH. Each byte of
the Device Path associated with DriverHandle is converted
to a 2 Unicode character hexadecimal string.
@retval NULL DriverHandle does not support the Device Path Protocol.
@retval Other A pointer to the Null-terminate Unicode <ConfigHdr> string
**/
EFI_STRING
EFIAPI
HiiConstructConfigHdr (
IN CONST EFI_GUID *Guid, OPTIONAL
IN CONST CHAR16 *Name, OPTIONAL
IN EFI_HANDLE DriverHandle
)
{
UINTN NameLength;
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
UINTN DevicePathSize;
CHAR16 *String;
CHAR16 *ReturnString;
UINTN Index;
UINT8 *Buffer;
UINTN MaxLen;
//
// Compute the length of Name in Unicode characters.
// If Name is NULL, then the length is 0.
//
NameLength = 0;
if (Name != NULL) {
NameLength = StrLen (Name);
}
DevicePath = NULL;
DevicePathSize = 0;
//
// Retrieve DevicePath Protocol associated with DriverHandle
//
if (DriverHandle != NULL) {
DevicePath = DevicePathFromHandle (DriverHandle);
if (DevicePath == NULL) {
return NULL;
}
//
// Compute the size of the device path in bytes
//
DevicePathSize = GetDevicePathSize (DevicePath);
}
//
// GUID=<HexCh>32&NAME=<Char>NameLength&PATH=<HexChar>DevicePathSize <Null>
// | 5 | sizeof (EFI_GUID) * 2 | 6 | NameStrLen*4 | 6 | DevicePathSize * 2 | 1 |
//
MaxLen = 5 + sizeof (EFI_GUID) * 2 + 6 + NameLength * 4 + 6 + DevicePathSize * 2 + 1;
String = AllocateZeroPool (MaxLen * sizeof (CHAR16));
if (String == NULL) {
return NULL;
}
//
// Start with L"GUID="
//
StrCpyS (String, MaxLen, L"GUID=");
ReturnString = String;
String += StrLen (String);
if (Guid != NULL) {
//
// Append Guid converted to <HexCh>32
//
for (Index = 0, Buffer = (UINT8 *)Guid; Index < sizeof (EFI_GUID); Index++) {
UnicodeValueToStringS (
String,
MaxLen * sizeof (CHAR16) - ((UINTN)String - (UINTN)ReturnString),
PREFIX_ZERO | RADIX_HEX,
*(Buffer++),
2
);
String += StrnLenS (String, MaxLen - ((UINTN)String - (UINTN)ReturnString) / sizeof (CHAR16));
}
}
//
// Append L"&NAME="
//
StrCatS (ReturnString, MaxLen, L"&NAME=");
String += StrLen (String);
if (Name != NULL) {
//
// Append Name converted to <Char>NameLength
//
for (; *Name != L'\0'; Name++) {
UnicodeValueToStringS (
String,
sizeof (CHAR16) * MaxLen - ((UINTN)String - (UINTN)ReturnString),
PREFIX_ZERO | RADIX_HEX,
*Name,
4
);
String += StrnLenS (String, MaxLen - ((UINTN)String - (UINTN)ReturnString) / sizeof (CHAR16));
}
}
//
// Append L"&PATH="
//
StrCatS (ReturnString, MaxLen, L"&PATH=");
String += StrLen (String);
//
// Append the device path associated with DriverHandle converted to <HexChar>DevicePathSize
//
for (Index = 0, Buffer = (UINT8 *)DevicePath; Index < DevicePathSize; Index++) {
UnicodeValueToStringS (
String,
sizeof (CHAR16) * MaxLen - ((UINTN)String - (UINTN)ReturnString),
PREFIX_ZERO | RADIX_HEX,
*(Buffer++),
2
);
String += StrnLenS (String, MaxLen - ((UINTN)String - (UINTN)ReturnString) / sizeof (CHAR16));
}
//
// Null terminate the Unicode string
//
*String = L'\0';
//
// Convert all hex digits in range [A-F] in the configuration header to [a-f]
//
return InternalHiiLowerConfigString (ReturnString);
}
/**
Convert the hex UNICODE encoding string of UEFI GUID, NAME or device path
to binary buffer from <ConfigHdr>.
This is a internal function.
@param String UEFI configuration string.
@param Flag Flag specifies what type buffer will be retrieved.
@param Buffer Binary of Guid, Name or Device path.
@retval EFI_INVALID_PARAMETER Any incoming parameter is invalid.
@retval EFI_OUT_OF_RESOURCES Lake of resources to store neccesary structures.
@retval EFI_SUCCESS The buffer data is retrieved and translated to
binary format.
**/
EFI_STATUS
InternalHiiGetBufferFromString (
IN EFI_STRING String,
IN UINT8 Flag,
OUT UINT8 **Buffer
)
{
UINTN Length;
EFI_STRING ConfigHdr;
CHAR16 *StringPtr;
UINT8 *DataBuffer;
CHAR16 TemStr[5];
UINTN Index;
UINT8 DigitUint8;
if (String == NULL || Buffer == NULL) {
return EFI_INVALID_PARAMETER;
}
DataBuffer = NULL;
StringPtr = NULL;
ConfigHdr = String;
//
// The content between 'GUID', 'NAME', 'PATH' of <ConfigHdr> and '&' of next element
// or '\0' (end of configuration string) is the UNICODE %02x bytes encoding string.
//
for (Length = 0; *String != 0 && *String != L'&'; String++, Length++);
switch (Flag) {
case GUID_CONFIG_STRING_TYPE:
case PATH_CONFIG_STRING_TYPE:
//
// The data in <ConfigHdr> is encoded as hex UNICODE %02x bytes in the same order
// as the device path and Guid resides in RAM memory.
// Translate the data into binary.
//
DataBuffer = (UINT8 *) AllocateZeroPool ((Length + 1) / 2);
if (DataBuffer == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
// Convert binary byte one by one
//
ZeroMem (TemStr, sizeof (TemStr));
for (Index = 0; Index < Length; Index ++) {
TemStr[0] = ConfigHdr[Index];
DigitUint8 = (UINT8) StrHexToUint64 (TemStr);
if ((Index & 1) == 0) {
DataBuffer [Index/2] = DigitUint8;
} else {
DataBuffer [Index/2] = (UINT8) ((DataBuffer [Index/2] << 4) + DigitUint8);
}
}
*Buffer = DataBuffer;
break;
case NAME_CONFIG_STRING_TYPE:
//
// Convert Config String to Unicode String, e.g. "0041004200430044" => "ABCD"
//
//
// Add the tailling char L'\0'
//
DataBuffer = (UINT8 *) AllocateZeroPool ((Length/4 + 1) * sizeof (CHAR16));
if (DataBuffer == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
// Convert character one by one
//
StringPtr = (CHAR16 *) DataBuffer;
ZeroMem (TemStr, sizeof (TemStr));
for (Index = 0; Index < Length; Index += 4) {
StrnCpyS (TemStr, sizeof (TemStr) / sizeof (CHAR16), ConfigHdr + Index, 4);
StringPtr[Index/4] = (CHAR16) StrHexToUint64 (TemStr);
}
//
// Add tailing L'\0' character
//
StringPtr[Index/4] = L'\0';
*Buffer = DataBuffer;
break;
default:
return EFI_INVALID_PARAMETER;
}
return EFI_SUCCESS;
}
/**
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.
@retval EFI_INVALID_PARAMETER Invalid parameter.
**/
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);
if (ValueString == NULL || ValueData == NULL || ValueLength == NULL) {
return EFI_INVALID_PARAMETER;
}
ASSERT (*ValueString != L'\0');
//
// Get the length of value string
//
StringPtr = ValueString;
while (*StringPtr != L'\0' && *StringPtr != L'&') {
StringPtr++;
}
Length = StringPtr - ValueString;
//
// Allocate buffer to store the value
//
Buf = (UINT8 *) AllocateZeroPool ((Length + 1) / 2);
if (Buf == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
// Convert character one by one to the value buffer
//
ZeroMem (TemStr, sizeof (TemStr));
for (Index = 0; Index < Length; Index ++) {
TemStr[0] = ValueString[Length - Index - 1];
DigitUint8 = (UINT8) StrHexToUint64 (TemStr);
if ((Index & 1) == 0) {
Buf [Index/2] = DigitUint8;
} else {
Buf [Index/2] = (UINT8) ((DigitUint8 << 4) + Buf [Index/2]);
}
}
//
// Set the converted value and string length.
//
*ValueData = Buf;
*ValueLength = Length;
return EFI_SUCCESS;
}
/**
Get value from config request resp string.
@param ConfigElement ConfigResp string contains the current setting.
@param VarName The variable name which need to get value.
@param VarValue The return value.
@retval EFI_SUCCESS Get the value for the VarName
@retval EFI_OUT_OF_RESOURCES The memory is not enough.
**/
EFI_STATUS
GetValueFromRequest (
IN CHAR16 *ConfigElement,
IN CHAR16 *VarName,
OUT UINT64 *VarValue
)
{
UINT8 *TmpBuffer;
CHAR16 *StringPtr;
UINTN Length;
EFI_STATUS Status;
//
// Find VarName related string.
//
StringPtr = StrStr (ConfigElement, VarName);
ASSERT (StringPtr != NULL);
//
// Skip the "VarName=" string
//
StringPtr += StrLen (VarName) + 1;
//
// Get Offset
//
Status = InternalHiiGetValueOfNumber (StringPtr, &TmpBuffer, &Length);
if (EFI_ERROR (Status)) {
return Status;
}
*VarValue = 0;
CopyMem (VarValue, TmpBuffer, (((Length + 1) / 2) < sizeof (UINT64)) ? ((Length + 1) / 2) : sizeof (UINT64));
FreePool (TmpBuffer);
return EFI_SUCCESS;
}