mirror of https://github.com/acidanthera/audk.git
3287 lines
100 KiB
C
3287 lines
100 KiB
C
/** @file
|
|
Implementation of interfaces function for EFI_CONFIG_KEYWORD_HANDLER_PROTOCOL.
|
|
|
|
Copyright (c) 2015, 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 "HiiDatabase.h"
|
|
|
|
extern HII_DATABASE_PRIVATE_DATA mPrivate;
|
|
|
|
/**
|
|
Convert the hex UNICODE %02x encoding of a UEFI device path to binary
|
|
from <PathHdr> of <MultiKeywordRequest>.
|
|
|
|
This is a internal function.
|
|
|
|
@param String MultiKeywordRequest string.
|
|
@param DevicePathData Binary of a UEFI device path.
|
|
@param NextString string follow the possible PathHdr string.
|
|
|
|
@retval EFI_INVALID_PARAMETER The device path is not valid or the incoming parameter is invalid.
|
|
@retval EFI_OUT_OF_RESOURCES Lake of resources to store neccesary structures.
|
|
@retval EFI_SUCCESS The device path is retrieved and translated to binary format.
|
|
The Input string not include PathHdr section.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
ExtractDevicePath (
|
|
IN EFI_STRING String,
|
|
OUT UINT8 **DevicePathData,
|
|
OUT EFI_STRING *NextString
|
|
)
|
|
{
|
|
UINTN Length;
|
|
EFI_STRING PathHdr;
|
|
UINT8 *DevicePathBuffer;
|
|
CHAR16 TemStr[2];
|
|
UINTN Index;
|
|
UINT8 DigitUint8;
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
|
|
|
ASSERT (NextString != NULL && DevicePathData != NULL);
|
|
|
|
//
|
|
// KeywordRequest == NULL case.
|
|
//
|
|
if (String == NULL) {
|
|
*DevicePathData = NULL;
|
|
*NextString = NULL;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Skip '&' if exist.
|
|
//
|
|
if (*String == L'&') {
|
|
String ++;
|
|
}
|
|
|
|
//
|
|
// Find the 'PATH=' of <PathHdr>.
|
|
//
|
|
if (StrnCmp (String, L"PATH=", StrLen (L"PATH=")) != 0) {
|
|
if (StrnCmp (String, L"KEYWORD=", StrLen (L"KEYWORD=")) != 0) {
|
|
return EFI_INVALID_PARAMETER;
|
|
} else {
|
|
//
|
|
// Not include PathHdr, return success and DevicePath = NULL.
|
|
//
|
|
*DevicePathData = NULL;
|
|
*NextString = String;
|
|
return EFI_SUCCESS;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check whether path data does exist.
|
|
//
|
|
String += StrLen (L"PATH=");
|
|
if (*String == 0) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
PathHdr = String;
|
|
|
|
//
|
|
// The content between 'PATH=' of <ConfigHdr> and '&' of next element
|
|
// or '\0' (end of configuration string) is the UNICODE %02x bytes encoding
|
|
// of UEFI device path.
|
|
//
|
|
for (Length = 0; *String != 0 && *String != L'&'; String++, Length++);
|
|
|
|
//
|
|
// Save the return next keyword string value.
|
|
//
|
|
*NextString = String;
|
|
|
|
//
|
|
// Check DevicePath Length
|
|
//
|
|
if (((Length + 1) / 2) < sizeof (EFI_DEVICE_PATH_PROTOCOL)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// The data in <PathHdr> is encoded as hex UNICODE %02x bytes in the same order
|
|
// as the device path resides in RAM memory.
|
|
// Translate the data into binary.
|
|
//
|
|
DevicePathBuffer = (UINT8 *) AllocateZeroPool ((Length + 1) / 2);
|
|
if (DevicePathBuffer == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Convert DevicePath
|
|
//
|
|
ZeroMem (TemStr, sizeof (TemStr));
|
|
for (Index = 0; Index < Length; Index ++) {
|
|
TemStr[0] = PathHdr[Index];
|
|
DigitUint8 = (UINT8) StrHexToUint64 (TemStr);
|
|
if ((Index & 1) == 0) {
|
|
DevicePathBuffer [Index/2] = DigitUint8;
|
|
} else {
|
|
DevicePathBuffer [Index/2] = (UINT8) ((DevicePathBuffer [Index/2] << 4) + DigitUint8);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Validate DevicePath
|
|
//
|
|
DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) DevicePathBuffer;
|
|
while (!IsDevicePathEnd (DevicePath)) {
|
|
if ((DevicePath->Type == 0) || (DevicePath->SubType == 0) || (DevicePathNodeLength (DevicePath) < sizeof (EFI_DEVICE_PATH_PROTOCOL))) {
|
|
//
|
|
// Invalid device path
|
|
//
|
|
FreePool (DevicePathBuffer);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
DevicePath = NextDevicePathNode (DevicePath);
|
|
}
|
|
|
|
//
|
|
// return the device path
|
|
//
|
|
*DevicePathData = DevicePathBuffer;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Get NameSpace from the input NameSpaceId string.
|
|
|
|
This is a internal function.
|
|
|
|
@param String <NameSpaceId> format string.
|
|
@param NameSpace Return the name space string.
|
|
@param NextString Return the next string follow namespace.
|
|
|
|
@retval EFI_SUCCESS Get the namespace string success.
|
|
@retval EFI_INVALID_PARAMETER The NameSpaceId string not follow spec definition.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
ExtractNameSpace (
|
|
IN EFI_STRING String,
|
|
OUT CHAR8 **NameSpace,
|
|
OUT EFI_STRING *NextString
|
|
)
|
|
{
|
|
CHAR16 *TmpPtr;
|
|
|
|
ASSERT (NameSpace != NULL);
|
|
|
|
TmpPtr = NULL;
|
|
|
|
//
|
|
// Input NameSpaceId == NULL
|
|
//
|
|
if (String == NULL) {
|
|
*NameSpace = NULL;
|
|
if (NextString != NULL) {
|
|
*NextString = NULL;
|
|
}
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Skip '&' if exist.
|
|
//
|
|
if (*String == L'&') {
|
|
String++;
|
|
}
|
|
|
|
if (StrnCmp (String, L"NAMESPACE=", StrLen (L"NAMESPACE=")) != 0) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
String += StrLen (L"NAMESPACE=");
|
|
|
|
TmpPtr = StrStr (String, L"&");
|
|
if (TmpPtr != NULL) {
|
|
*TmpPtr = 0;
|
|
}
|
|
if (NextString != NULL) {
|
|
*NextString = String + StrLen (String);
|
|
}
|
|
|
|
//
|
|
// Input NameSpace is unicode string. The language in String package is ascii string.
|
|
// Here will convert the unicode string to ascii and save it.
|
|
//
|
|
*NameSpace = AllocatePool (StrLen (String) + 1);
|
|
if (*NameSpace == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
UnicodeStrToAsciiStr (String, *NameSpace);
|
|
|
|
if (TmpPtr != NULL) {
|
|
*TmpPtr = L'&';
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Get Keyword from the input KeywordRequest string.
|
|
|
|
This is a internal function.
|
|
|
|
@param String KeywordRequestformat string.
|
|
@param Keyword return the extract keyword string.
|
|
@param NextString return the next string follow this keyword sectin.
|
|
|
|
@retval EFI_SUCCESS Success to get the keyword string.
|
|
@retval EFI_INVALID_PARAMETER Parsr the input string return error.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
ExtractKeyword (
|
|
IN EFI_STRING String,
|
|
OUT EFI_STRING *Keyword,
|
|
OUT EFI_STRING *NextString
|
|
)
|
|
{
|
|
EFI_STRING TmpPtr;
|
|
|
|
ASSERT ((Keyword != NULL) && (NextString != NULL));
|
|
|
|
TmpPtr = NULL;
|
|
|
|
//
|
|
// KeywordRequest == NULL case.
|
|
//
|
|
if (String == NULL) {
|
|
*Keyword = NULL;
|
|
*NextString = NULL;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Skip '&' if exist.
|
|
//
|
|
if (*String == L'&') {
|
|
String++;
|
|
}
|
|
|
|
if (StrnCmp (String, L"KEYWORD=", StrLen (L"KEYWORD=")) != 0) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
String += StrLen (L"KEYWORD=");
|
|
|
|
TmpPtr = StrStr (String, L"&");
|
|
if (TmpPtr != NULL) {
|
|
*TmpPtr = 0;
|
|
}
|
|
*NextString = String + StrLen (String);
|
|
|
|
*Keyword = AllocateCopyPool (StrSize (String), String);
|
|
if (*Keyword == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
if (TmpPtr != NULL) {
|
|
*TmpPtr = L'&';
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Get value from the input KeywordRequest string.
|
|
|
|
This is a internal function.
|
|
|
|
@param String KeywordRequestformat string.
|
|
@param Value return the extract value string.
|
|
@param NextString return the next string follow this keyword sectin.
|
|
|
|
@retval EFI_SUCCESS Success to get the keyword string.
|
|
@retval EFI_INVALID_PARAMETER Parsr the input string return error.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
ExtractValue (
|
|
IN EFI_STRING String,
|
|
OUT EFI_STRING *Value,
|
|
OUT EFI_STRING *NextString
|
|
)
|
|
{
|
|
EFI_STRING TmpPtr;
|
|
|
|
ASSERT ((Value != NULL) && (NextString != NULL) && (String != NULL));
|
|
|
|
//
|
|
// Skip '&' if exist.
|
|
//
|
|
if (*String == L'&') {
|
|
String++;
|
|
}
|
|
|
|
if (StrnCmp (String, L"VALUE=", StrLen (L"VALUE=")) != 0) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
String += StrLen (L"VALUE=");
|
|
|
|
TmpPtr = StrStr (String, L"&");
|
|
if (TmpPtr != NULL) {
|
|
*TmpPtr = 0;
|
|
}
|
|
*NextString = String + StrLen (String);
|
|
|
|
*Value = AllocateCopyPool (StrSize (String), String);
|
|
if (*Value == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
if (TmpPtr != NULL) {
|
|
*TmpPtr = L'&';
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Get filter from the input KeywordRequest string.
|
|
|
|
This is a internal function.
|
|
|
|
@param String KeywordRequestformat string.
|
|
@param FilterFlags return the filter condition.
|
|
@param NextString return the next string follow this keyword sectin.
|
|
|
|
@retval EFI_SUCCESS Success to get the keyword string.
|
|
@retval EFI_INVALID_PARAMETER Parsr the input string return error.
|
|
|
|
**/
|
|
BOOLEAN
|
|
ExtractFilter (
|
|
IN EFI_STRING String,
|
|
OUT UINT8 *FilterFlags,
|
|
OUT EFI_STRING *NextString
|
|
)
|
|
{
|
|
CHAR16 *PathPtr;
|
|
CHAR16 *KeywordPtr;
|
|
BOOLEAN RetVal;
|
|
|
|
ASSERT ((FilterFlags != NULL) && (NextString != NULL));
|
|
|
|
//
|
|
// String end, no filter section.
|
|
//
|
|
if (String == NULL) {
|
|
*NextString = NULL;
|
|
return FALSE;
|
|
}
|
|
|
|
*FilterFlags = 0;
|
|
RetVal = TRUE;
|
|
|
|
//
|
|
// Skip '&' if exist.
|
|
//
|
|
if (*String == L'&') {
|
|
String++;
|
|
}
|
|
|
|
if (StrnCmp (String, L"ReadOnly", StrLen (L"ReadOnly")) == 0) {
|
|
//
|
|
// Find ReadOnly filter.
|
|
//
|
|
*FilterFlags |= EFI_KEYWORD_FILTER_READONY;
|
|
String += StrLen (L"ReadOnly");
|
|
} else if (StrnCmp (String, L"ReadWrite", StrLen (L"ReadWrite")) == 0) {
|
|
//
|
|
// Find ReadWrite filter.
|
|
//
|
|
*FilterFlags |= EFI_KEYWORD_FILTER_REAWRITE;
|
|
String += StrLen (L"ReadWrite");
|
|
} else if (StrnCmp (String, L"Buffer", StrLen (L"Buffer")) == 0) {
|
|
//
|
|
// Find Buffer Filter.
|
|
//
|
|
*FilterFlags |= EFI_KEYWORD_FILTER_BUFFER;
|
|
String += StrLen (L"Buffer");
|
|
} else if (StrnCmp (String, L"Numeric", StrLen (L"Numeric")) == 0) {
|
|
//
|
|
// Find Numeric Filter
|
|
//
|
|
String += StrLen (L"Numeric");
|
|
if (*String != L':') {
|
|
*FilterFlags |= EFI_KEYWORD_FILTER_NUMERIC;
|
|
} else {
|
|
String++;
|
|
switch (*String) {
|
|
case L'1':
|
|
*FilterFlags |= EFI_KEYWORD_FILTER_NUMERIC_1;
|
|
break;
|
|
case L'2':
|
|
*FilterFlags |= EFI_KEYWORD_FILTER_NUMERIC_2;
|
|
break;
|
|
case L'4':
|
|
*FilterFlags |= EFI_KEYWORD_FILTER_NUMERIC_4;
|
|
break;
|
|
case L'8':
|
|
*FilterFlags |= EFI_KEYWORD_FILTER_NUMERIC_8;
|
|
break;
|
|
default:
|
|
ASSERT (FALSE);
|
|
break;
|
|
}
|
|
String++;
|
|
}
|
|
} else {
|
|
//
|
|
// Check whether other filter item defined by Platform.
|
|
//
|
|
if ((StrnCmp (String, L"&PATH", StrLen (L"&PATH")) == 0) ||
|
|
(StrnCmp (String, L"&KEYWORD", StrLen (L"&KEYWORD")) == 0)) {
|
|
//
|
|
// New KeywordRequest start, no platform defined filter.
|
|
//
|
|
} else {
|
|
//
|
|
// Platform defined filter rule.
|
|
// Just skip platform defined filter rule, return success.
|
|
//
|
|
PathPtr = StrStr(String, L"&PATH");
|
|
KeywordPtr = StrStr(String, L"&KEYWORD");
|
|
if (PathPtr != NULL && KeywordPtr != NULL) {
|
|
//
|
|
// If both sections exist, return the first follow string.
|
|
//
|
|
String = KeywordPtr > PathPtr ? PathPtr : KeywordPtr;
|
|
} else if (PathPtr != NULL) {
|
|
//
|
|
// Should not exist PathPtr != NULL && KeywordPtr == NULL case.
|
|
//
|
|
ASSERT (FALSE);
|
|
} else if (KeywordPtr != NULL) {
|
|
//
|
|
// Just to the next keyword section.
|
|
//
|
|
String = KeywordPtr;
|
|
} else {
|
|
//
|
|
// Only has paltform defined filter section, just skip it.
|
|
//
|
|
String += StrLen (String);
|
|
}
|
|
}
|
|
RetVal = FALSE;
|
|
}
|
|
|
|
*NextString = String;
|
|
|
|
return RetVal;
|
|
}
|
|
|
|
/**
|
|
Extract Readonly flag from opcode.
|
|
|
|
This is a internal function.
|
|
|
|
@param OpCodeData Input opcode for this question.
|
|
|
|
@retval TRUE This question is readonly.
|
|
@retval FALSE This question is not readonly.
|
|
|
|
**/
|
|
BOOLEAN
|
|
ExtractReadOnlyFromOpCode (
|
|
IN UINT8 *OpCodeData
|
|
)
|
|
{
|
|
EFI_IFR_QUESTION_HEADER *QuestionHdr;
|
|
|
|
ASSERT (OpCodeData != NULL);
|
|
|
|
QuestionHdr = (EFI_IFR_QUESTION_HEADER *) (OpCodeData + sizeof (EFI_IFR_OP_HEADER));
|
|
|
|
return (QuestionHdr->Flags & EFI_IFR_FLAG_READ_ONLY) != 0;
|
|
}
|
|
|
|
/**
|
|
Create a circuit to check the filter section.
|
|
|
|
This is a internal function.
|
|
|
|
@param OpCodeData The questin binary ifr data.
|
|
@param KeywordRequest KeywordRequestformat string.
|
|
@param NextString return the next string follow this keyword sectin.
|
|
@param ReadOnly Return whether this question is read only.
|
|
|
|
@retval KEYWORD_HANDLER_NO_ERROR Success validate.
|
|
@retval KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED Validate fail.
|
|
|
|
**/
|
|
UINT32
|
|
ValidateFilter (
|
|
IN UINT8 *OpCodeData,
|
|
IN CHAR16 *KeywordRequest,
|
|
OUT CHAR16 **NextString,
|
|
OUT BOOLEAN *ReadOnly
|
|
)
|
|
{
|
|
CHAR16 *NextFilter;
|
|
CHAR16 *StringPtr;
|
|
UINT8 FilterFlags;
|
|
EFI_IFR_QUESTION_HEADER *QuestionHdr;
|
|
EFI_IFR_OP_HEADER *OpCodeHdr;
|
|
UINT8 Flags;
|
|
UINT32 RetVal;
|
|
|
|
RetVal = KEYWORD_HANDLER_NO_ERROR;
|
|
StringPtr = KeywordRequest;
|
|
|
|
OpCodeHdr = (EFI_IFR_OP_HEADER *) OpCodeData;
|
|
QuestionHdr = (EFI_IFR_QUESTION_HEADER *) (OpCodeData + sizeof (EFI_IFR_OP_HEADER));
|
|
if (OpCodeHdr->OpCode == EFI_IFR_ONE_OF_OP || OpCodeHdr->OpCode == EFI_IFR_NUMERIC_OP) {
|
|
Flags = *(OpCodeData + sizeof (EFI_IFR_OP_HEADER) + sizeof (EFI_IFR_QUESTION_HEADER));
|
|
} else {
|
|
Flags = 0;
|
|
}
|
|
|
|
//
|
|
// Get ReadOnly flag from Question.
|
|
//
|
|
*ReadOnly = ExtractReadOnlyFromOpCode(OpCodeData);
|
|
|
|
while (ExtractFilter (StringPtr, &FilterFlags, &NextFilter)) {
|
|
switch (FilterFlags) {
|
|
case EFI_KEYWORD_FILTER_READONY:
|
|
if ((QuestionHdr->Flags & EFI_IFR_FLAG_READ_ONLY) == 0) {
|
|
RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED;
|
|
goto Done;
|
|
}
|
|
break;
|
|
|
|
case EFI_KEYWORD_FILTER_REAWRITE:
|
|
if ((QuestionHdr->Flags & EFI_IFR_FLAG_READ_ONLY) != 0) {
|
|
RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED;
|
|
goto Done;
|
|
}
|
|
break;
|
|
|
|
case EFI_KEYWORD_FILTER_BUFFER:
|
|
//
|
|
// Only these three opcode use numeric value type.
|
|
//
|
|
if (OpCodeHdr->OpCode == EFI_IFR_ONE_OF_OP || OpCodeHdr->OpCode == EFI_IFR_NUMERIC_OP || OpCodeHdr->OpCode == EFI_IFR_CHECKBOX_OP) {
|
|
RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED;
|
|
goto Done;
|
|
}
|
|
break;
|
|
|
|
case EFI_KEYWORD_FILTER_NUMERIC:
|
|
if (OpCodeHdr->OpCode != EFI_IFR_ONE_OF_OP && OpCodeHdr->OpCode != EFI_IFR_NUMERIC_OP && OpCodeHdr->OpCode != EFI_IFR_CHECKBOX_OP) {
|
|
RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED;
|
|
goto Done;
|
|
}
|
|
break;
|
|
|
|
case EFI_KEYWORD_FILTER_NUMERIC_1:
|
|
case EFI_KEYWORD_FILTER_NUMERIC_2:
|
|
case EFI_KEYWORD_FILTER_NUMERIC_4:
|
|
case EFI_KEYWORD_FILTER_NUMERIC_8:
|
|
if (OpCodeHdr->OpCode != EFI_IFR_ONE_OF_OP && OpCodeHdr->OpCode != EFI_IFR_NUMERIC_OP && OpCodeHdr->OpCode != EFI_IFR_CHECKBOX_OP) {
|
|
RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED;
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// For numeric and oneof, it has flags field to specify the detail numeric type.
|
|
//
|
|
if (OpCodeHdr->OpCode == EFI_IFR_ONE_OF_OP || OpCodeHdr->OpCode == EFI_IFR_NUMERIC_OP) {
|
|
switch (Flags & EFI_IFR_NUMERIC_SIZE) {
|
|
case EFI_IFR_NUMERIC_SIZE_1:
|
|
if (FilterFlags != EFI_KEYWORD_FILTER_NUMERIC_1) {
|
|
RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED;
|
|
goto Done;
|
|
}
|
|
break;
|
|
|
|
case EFI_IFR_NUMERIC_SIZE_2:
|
|
if (FilterFlags != EFI_KEYWORD_FILTER_NUMERIC_2) {
|
|
RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED;
|
|
goto Done;
|
|
}
|
|
break;
|
|
|
|
case EFI_IFR_NUMERIC_SIZE_4:
|
|
if (FilterFlags != EFI_KEYWORD_FILTER_NUMERIC_4) {
|
|
RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED;
|
|
goto Done;
|
|
}
|
|
break;
|
|
|
|
case EFI_IFR_NUMERIC_SIZE_8:
|
|
if (FilterFlags != EFI_KEYWORD_FILTER_NUMERIC_8) {
|
|
RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED;
|
|
goto Done;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
ASSERT (FALSE);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
ASSERT (FALSE);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Jump to the next filter.
|
|
//
|
|
StringPtr = NextFilter;
|
|
}
|
|
|
|
Done:
|
|
//
|
|
// The current filter which is processing.
|
|
//
|
|
*NextString = StringPtr;
|
|
|
|
return RetVal;
|
|
}
|
|
|
|
/**
|
|
Get HII_DATABASE_RECORD from the input device path info.
|
|
|
|
This is a internal function.
|
|
|
|
@param DevicePath UEFI device path protocol.
|
|
|
|
@retval Internal data base record.
|
|
|
|
**/
|
|
HII_DATABASE_RECORD *
|
|
GetRecordFromDevicePath (
|
|
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
|
|
)
|
|
{
|
|
LIST_ENTRY *Link;
|
|
UINT8 *DevicePathPkg;
|
|
UINT8 *CurrentDevicePath;
|
|
UINTN DevicePathSize;
|
|
HII_DATABASE_RECORD *TempDatabase;
|
|
|
|
ASSERT (DevicePath != NULL);
|
|
|
|
for (Link = mPrivate.DatabaseList.ForwardLink; Link != &mPrivate.DatabaseList; Link = Link->ForwardLink) {
|
|
TempDatabase = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
|
|
DevicePathPkg = TempDatabase->PackageList->DevicePathPkg;
|
|
if (DevicePathPkg != NULL) {
|
|
CurrentDevicePath = DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);
|
|
DevicePathSize = GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) CurrentDevicePath);
|
|
if ((CompareMem (DevicePath, CurrentDevicePath, DevicePathSize) == 0)) {
|
|
return TempDatabase;
|
|
}
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
Calculate the size of StringSrc and output it. Also copy string text from src
|
|
to dest.
|
|
|
|
This is a internal function.
|
|
|
|
@param StringSrc Points to current null-terminated string.
|
|
@param BufferSize Length of the buffer.
|
|
@param StringDest Buffer to store the string text.
|
|
|
|
@retval EFI_SUCCESS The string text was outputed successfully.
|
|
@retval EFI_OUT_OF_RESOURCES Out of resource.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
GetUnicodeStringTextAndSize (
|
|
IN UINT8 *StringSrc,
|
|
OUT UINTN *BufferSize,
|
|
OUT EFI_STRING *StringDest
|
|
)
|
|
{
|
|
UINTN StringSize;
|
|
UINT8 *StringPtr;
|
|
|
|
ASSERT (StringSrc != NULL && BufferSize != NULL && StringDest != NULL);
|
|
|
|
StringSize = sizeof (CHAR16);
|
|
StringPtr = StringSrc;
|
|
while (ReadUnaligned16 ((UINT16 *) StringPtr) != 0) {
|
|
StringSize += sizeof (CHAR16);
|
|
StringPtr += sizeof (CHAR16);
|
|
}
|
|
|
|
*StringDest = AllocatePool (StringSize);
|
|
if (*StringDest == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
CopyMem (*StringDest, StringSrc, StringSize);
|
|
|
|
*BufferSize = StringSize;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Find the string id for the input keyword.
|
|
|
|
@param StringPackage Hii string package instance.
|
|
@param KeywordValue Input keyword value.
|
|
@param StringId The string's id, which is unique within PackageList.
|
|
|
|
|
|
@retval EFI_SUCCESS The string text and font is retrieved
|
|
successfully.
|
|
@retval EFI_NOT_FOUND The specified text or font info can not be found
|
|
out.
|
|
@retval EFI_OUT_OF_RESOURCES The system is out of resources to accomplish the
|
|
task.
|
|
**/
|
|
EFI_STATUS
|
|
GetStringIdFromString (
|
|
IN HII_STRING_PACKAGE_INSTANCE *StringPackage,
|
|
IN CHAR16 *KeywordValue,
|
|
OUT EFI_STRING_ID *StringId
|
|
)
|
|
{
|
|
UINT8 *BlockHdr;
|
|
EFI_STRING_ID CurrentStringId;
|
|
UINTN BlockSize;
|
|
UINTN Index;
|
|
UINT8 *StringTextPtr;
|
|
UINTN Offset;
|
|
UINT16 StringCount;
|
|
UINT16 SkipCount;
|
|
UINT8 Length8;
|
|
EFI_HII_SIBT_EXT2_BLOCK Ext2;
|
|
UINT32 Length32;
|
|
UINTN StringSize;
|
|
CHAR16 *String;
|
|
CHAR8 *AsciiKeywordValue;
|
|
EFI_STATUS Status;
|
|
|
|
ASSERT (StringPackage != NULL && KeywordValue != NULL && StringId != NULL);
|
|
ASSERT (StringPackage->Signature == HII_STRING_PACKAGE_SIGNATURE);
|
|
|
|
CurrentStringId = 1;
|
|
Status = EFI_SUCCESS;
|
|
String = NULL;
|
|
BlockHdr = StringPackage->StringBlock;
|
|
BlockSize = 0;
|
|
Offset = 0;
|
|
|
|
//
|
|
// Make a ascii keyword value for later use.
|
|
//
|
|
AsciiKeywordValue = AllocatePool (StrLen (KeywordValue) + 1);
|
|
if (AsciiKeywordValue == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
UnicodeStrToAsciiStr(KeywordValue, AsciiKeywordValue);
|
|
|
|
while (*BlockHdr != EFI_HII_SIBT_END) {
|
|
switch (*BlockHdr) {
|
|
case EFI_HII_SIBT_STRING_SCSU:
|
|
Offset = sizeof (EFI_HII_STRING_BLOCK);
|
|
StringTextPtr = BlockHdr + Offset;
|
|
BlockSize += Offset + AsciiStrSize ((CHAR8 *) StringTextPtr);
|
|
if (AsciiStrCmp(AsciiKeywordValue, (CHAR8 *) StringTextPtr) == 0) {
|
|
*StringId = CurrentStringId;
|
|
goto Done;
|
|
}
|
|
CurrentStringId++;
|
|
break;
|
|
|
|
case EFI_HII_SIBT_STRING_SCSU_FONT:
|
|
Offset = sizeof (EFI_HII_SIBT_STRING_SCSU_FONT_BLOCK) - sizeof (UINT8);
|
|
StringTextPtr = BlockHdr + Offset;
|
|
if (AsciiStrCmp(AsciiKeywordValue, (CHAR8 *) StringTextPtr) == 0) {
|
|
*StringId = CurrentStringId;
|
|
goto Done;
|
|
}
|
|
BlockSize += Offset + AsciiStrSize ((CHAR8 *) StringTextPtr);
|
|
CurrentStringId++;
|
|
break;
|
|
|
|
case EFI_HII_SIBT_STRINGS_SCSU:
|
|
CopyMem (&StringCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16));
|
|
StringTextPtr = (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_SIBT_STRINGS_SCSU_BLOCK) - sizeof (UINT8));
|
|
BlockSize += StringTextPtr - BlockHdr;
|
|
|
|
for (Index = 0; Index < StringCount; Index++) {
|
|
BlockSize += AsciiStrSize ((CHAR8 *) StringTextPtr);
|
|
if (AsciiStrCmp(AsciiKeywordValue, (CHAR8 *) StringTextPtr) == 0) {
|
|
*StringId = CurrentStringId;
|
|
goto Done;
|
|
}
|
|
StringTextPtr = StringTextPtr + AsciiStrSize ((CHAR8 *) StringTextPtr);
|
|
CurrentStringId++;
|
|
}
|
|
break;
|
|
|
|
case EFI_HII_SIBT_STRINGS_SCSU_FONT:
|
|
CopyMem (
|
|
&StringCount,
|
|
(UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)),
|
|
sizeof (UINT16)
|
|
);
|
|
StringTextPtr = (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_SIBT_STRINGS_SCSU_FONT_BLOCK) - sizeof (UINT8));
|
|
BlockSize += StringTextPtr - BlockHdr;
|
|
|
|
for (Index = 0; Index < StringCount; Index++) {
|
|
BlockSize += AsciiStrSize ((CHAR8 *) StringTextPtr);
|
|
if (AsciiStrCmp(AsciiKeywordValue, (CHAR8 *) StringTextPtr) == 0) {
|
|
*StringId = CurrentStringId;
|
|
goto Done;
|
|
}
|
|
StringTextPtr = StringTextPtr + AsciiStrSize ((CHAR8 *) StringTextPtr);
|
|
CurrentStringId++;
|
|
}
|
|
break;
|
|
|
|
case EFI_HII_SIBT_STRING_UCS2:
|
|
Offset = sizeof (EFI_HII_STRING_BLOCK);
|
|
StringTextPtr = BlockHdr + Offset;
|
|
//
|
|
// Use StringSize to store the size of the specified string, including the NULL
|
|
// terminator.
|
|
//
|
|
Status = GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Done;
|
|
}
|
|
|
|
if (StrCmp(KeywordValue, String) == 0) {
|
|
*StringId = CurrentStringId;
|
|
goto Done;
|
|
}
|
|
BlockSize += Offset + StringSize;
|
|
CurrentStringId++;
|
|
break;
|
|
|
|
case EFI_HII_SIBT_STRING_UCS2_FONT:
|
|
Offset = sizeof (EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK) - sizeof (CHAR16);
|
|
StringTextPtr = BlockHdr + Offset;
|
|
//
|
|
// Use StringSize to store the size of the specified string, including the NULL
|
|
// terminator.
|
|
//
|
|
Status = GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Done;
|
|
}
|
|
|
|
if (StrCmp(KeywordValue, String) == 0) {
|
|
*StringId = CurrentStringId;
|
|
goto Done;
|
|
}
|
|
BlockSize += Offset + StringSize;
|
|
CurrentStringId++;
|
|
break;
|
|
|
|
case EFI_HII_SIBT_STRINGS_UCS2:
|
|
Offset = sizeof (EFI_HII_SIBT_STRINGS_UCS2_BLOCK) - sizeof (CHAR16);
|
|
StringTextPtr = BlockHdr + Offset;
|
|
BlockSize += Offset;
|
|
CopyMem (&StringCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16));
|
|
for (Index = 0; Index < StringCount; Index++) {
|
|
Status = GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Done;
|
|
}
|
|
|
|
BlockSize += StringSize;
|
|
if (StrCmp(KeywordValue, String) == 0) {
|
|
*StringId = CurrentStringId;
|
|
goto Done;
|
|
}
|
|
StringTextPtr = StringTextPtr + StringSize;
|
|
CurrentStringId++;
|
|
}
|
|
break;
|
|
|
|
case EFI_HII_SIBT_STRINGS_UCS2_FONT:
|
|
Offset = sizeof (EFI_HII_SIBT_STRINGS_UCS2_FONT_BLOCK) - sizeof (CHAR16);
|
|
StringTextPtr = BlockHdr + Offset;
|
|
BlockSize += Offset;
|
|
CopyMem (
|
|
&StringCount,
|
|
(UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)),
|
|
sizeof (UINT16)
|
|
);
|
|
for (Index = 0; Index < StringCount; Index++) {
|
|
Status = GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Done;
|
|
}
|
|
|
|
BlockSize += StringSize;
|
|
if (StrCmp(KeywordValue, String) == 0) {
|
|
*StringId = CurrentStringId;
|
|
goto Done;
|
|
}
|
|
StringTextPtr = StringTextPtr + StringSize;
|
|
CurrentStringId++;
|
|
}
|
|
break;
|
|
|
|
case EFI_HII_SIBT_DUPLICATE:
|
|
BlockSize += sizeof (EFI_HII_SIBT_DUPLICATE_BLOCK);
|
|
CurrentStringId++;
|
|
break;
|
|
|
|
case EFI_HII_SIBT_SKIP1:
|
|
SkipCount = (UINT16) (*(UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK)));
|
|
CurrentStringId = (UINT16) (CurrentStringId + SkipCount);
|
|
BlockSize += sizeof (EFI_HII_SIBT_SKIP1_BLOCK);
|
|
break;
|
|
|
|
case EFI_HII_SIBT_SKIP2:
|
|
CopyMem (&SkipCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16));
|
|
CurrentStringId = (UINT16) (CurrentStringId + SkipCount);
|
|
BlockSize += sizeof (EFI_HII_SIBT_SKIP2_BLOCK);
|
|
break;
|
|
|
|
case EFI_HII_SIBT_EXT1:
|
|
CopyMem (
|
|
&Length8,
|
|
(UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)),
|
|
sizeof (UINT8)
|
|
);
|
|
BlockSize += Length8;
|
|
break;
|
|
|
|
case EFI_HII_SIBT_EXT2:
|
|
CopyMem (&Ext2, BlockHdr, sizeof (EFI_HII_SIBT_EXT2_BLOCK));
|
|
BlockSize += Ext2.Length;
|
|
break;
|
|
|
|
case EFI_HII_SIBT_EXT4:
|
|
CopyMem (
|
|
&Length32,
|
|
(UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)),
|
|
sizeof (UINT32)
|
|
);
|
|
|
|
BlockSize += Length32;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (String != NULL) {
|
|
FreePool (String);
|
|
String = NULL;
|
|
}
|
|
|
|
BlockHdr = StringPackage->StringBlock + BlockSize;
|
|
}
|
|
|
|
Status = EFI_NOT_FOUND;
|
|
|
|
Done:
|
|
if (AsciiKeywordValue != NULL) {
|
|
FreePool (AsciiKeywordValue);
|
|
}
|
|
if (String != NULL) {
|
|
FreePool (String);
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Find the next valid string id for the input string id.
|
|
|
|
@param StringPackage Hii string package instance.
|
|
@param StringId The current string id which is already got.
|
|
1 means just begin to get the string id.
|
|
@param KeywordValue Return the string for the next string id.
|
|
|
|
|
|
@retval EFI_STRING_ID Not 0 means a valid stringid found.
|
|
0 means not found a valid string id.
|
|
**/
|
|
EFI_STRING_ID
|
|
GetNextStringId (
|
|
IN HII_STRING_PACKAGE_INSTANCE *StringPackage,
|
|
IN EFI_STRING_ID StringId,
|
|
OUT EFI_STRING *KeywordValue
|
|
)
|
|
{
|
|
UINT8 *BlockHdr;
|
|
EFI_STRING_ID CurrentStringId;
|
|
UINTN BlockSize;
|
|
UINTN Index;
|
|
UINT8 *StringTextPtr;
|
|
UINTN Offset;
|
|
UINT16 StringCount;
|
|
UINT16 SkipCount;
|
|
UINT8 Length8;
|
|
EFI_HII_SIBT_EXT2_BLOCK Ext2;
|
|
UINT32 Length32;
|
|
BOOLEAN FindString;
|
|
UINTN StringSize;
|
|
CHAR16 *String;
|
|
|
|
ASSERT (StringPackage != NULL);
|
|
ASSERT (StringPackage->Signature == HII_STRING_PACKAGE_SIGNATURE);
|
|
|
|
CurrentStringId = 1;
|
|
FindString = FALSE;
|
|
String = NULL;
|
|
|
|
//
|
|
// Parse the string blocks to get the string text and font.
|
|
//
|
|
BlockHdr = StringPackage->StringBlock;
|
|
BlockSize = 0;
|
|
Offset = 0;
|
|
while (*BlockHdr != EFI_HII_SIBT_END) {
|
|
switch (*BlockHdr) {
|
|
case EFI_HII_SIBT_STRING_SCSU:
|
|
Offset = sizeof (EFI_HII_STRING_BLOCK);
|
|
StringTextPtr = BlockHdr + Offset;
|
|
|
|
if (FindString) {
|
|
*KeywordValue = AllocatePool (AsciiStrSize ((CHAR8 *) StringTextPtr) * sizeof (CHAR16));
|
|
if (*KeywordValue == NULL) {
|
|
return 0;
|
|
}
|
|
AsciiStrToUnicodeStr ((CHAR8 *) StringTextPtr, *KeywordValue);
|
|
return CurrentStringId;
|
|
} else if (CurrentStringId == StringId) {
|
|
FindString = TRUE;
|
|
}
|
|
|
|
BlockSize += Offset + AsciiStrSize ((CHAR8 *) StringTextPtr);
|
|
CurrentStringId++;
|
|
break;
|
|
|
|
case EFI_HII_SIBT_STRING_SCSU_FONT:
|
|
Offset = sizeof (EFI_HII_SIBT_STRING_SCSU_FONT_BLOCK) - sizeof (UINT8);
|
|
StringTextPtr = BlockHdr + Offset;
|
|
|
|
if (FindString) {
|
|
*KeywordValue = AllocatePool (AsciiStrSize ((CHAR8 *) StringTextPtr) * sizeof (CHAR16));
|
|
if (*KeywordValue == NULL) {
|
|
return 0;
|
|
}
|
|
AsciiStrToUnicodeStr ((CHAR8 *) StringTextPtr, *KeywordValue);
|
|
return CurrentStringId;
|
|
} else if (CurrentStringId == StringId) {
|
|
FindString = TRUE;
|
|
}
|
|
|
|
BlockSize += Offset + AsciiStrSize ((CHAR8 *) StringTextPtr);
|
|
CurrentStringId++;
|
|
break;
|
|
|
|
case EFI_HII_SIBT_STRINGS_SCSU:
|
|
CopyMem (&StringCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16));
|
|
StringTextPtr = (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_SIBT_STRINGS_SCSU_BLOCK) - sizeof (UINT8));
|
|
BlockSize += StringTextPtr - BlockHdr;
|
|
|
|
for (Index = 0; Index < StringCount; Index++) {
|
|
if (FindString) {
|
|
*KeywordValue = AllocatePool (AsciiStrSize ((CHAR8 *) StringTextPtr) * sizeof (CHAR16));
|
|
if (*KeywordValue == NULL) {
|
|
return 0;
|
|
}
|
|
AsciiStrToUnicodeStr ((CHAR8 *) StringTextPtr, *KeywordValue);
|
|
return CurrentStringId;
|
|
} else if (CurrentStringId == StringId) {
|
|
FindString = TRUE;
|
|
}
|
|
|
|
BlockSize += AsciiStrSize ((CHAR8 *) StringTextPtr);
|
|
StringTextPtr = StringTextPtr + AsciiStrSize ((CHAR8 *) StringTextPtr);
|
|
CurrentStringId++;
|
|
}
|
|
break;
|
|
|
|
case EFI_HII_SIBT_STRINGS_SCSU_FONT:
|
|
CopyMem (
|
|
&StringCount,
|
|
(UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)),
|
|
sizeof (UINT16)
|
|
);
|
|
StringTextPtr = (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_SIBT_STRINGS_SCSU_FONT_BLOCK) - sizeof (UINT8));
|
|
BlockSize += StringTextPtr - BlockHdr;
|
|
|
|
for (Index = 0; Index < StringCount; Index++) {
|
|
if (FindString) {
|
|
*KeywordValue = AllocatePool (AsciiStrSize ((CHAR8 *) StringTextPtr) * sizeof (CHAR16));
|
|
if (*KeywordValue == NULL) {
|
|
return 0;
|
|
}
|
|
AsciiStrToUnicodeStr ((CHAR8 *) StringTextPtr, *KeywordValue);
|
|
return CurrentStringId;
|
|
} else if (CurrentStringId == StringId) {
|
|
FindString = TRUE;
|
|
}
|
|
|
|
BlockSize += AsciiStrSize ((CHAR8 *) StringTextPtr);
|
|
StringTextPtr = StringTextPtr + AsciiStrSize ((CHAR8 *) StringTextPtr);
|
|
CurrentStringId++;
|
|
}
|
|
break;
|
|
|
|
case EFI_HII_SIBT_STRING_UCS2:
|
|
Offset = sizeof (EFI_HII_STRING_BLOCK);
|
|
StringTextPtr = BlockHdr + Offset;
|
|
//
|
|
// Use StringSize to store the size of the specified string, including the NULL
|
|
// terminator.
|
|
//
|
|
GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String);
|
|
if (FindString && (String != NULL) && (*String != L'\0')) {
|
|
//
|
|
// String protocol use this type for the string id which has value for other package.
|
|
// It will allocate an empty string block for this string id. so here we also check
|
|
// *String != L'\0' to prohibit this case.
|
|
//
|
|
*KeywordValue = String;
|
|
return CurrentStringId;
|
|
} else if (CurrentStringId == StringId) {
|
|
FindString = TRUE;
|
|
}
|
|
|
|
BlockSize += Offset + StringSize;
|
|
CurrentStringId++;
|
|
break;
|
|
|
|
case EFI_HII_SIBT_STRING_UCS2_FONT:
|
|
Offset = sizeof (EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK) - sizeof (CHAR16);
|
|
StringTextPtr = BlockHdr + Offset;
|
|
//
|
|
// Use StringSize to store the size of the specified string, including the NULL
|
|
// terminator.
|
|
//
|
|
GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String);
|
|
if (FindString) {
|
|
*KeywordValue = String;
|
|
return CurrentStringId;
|
|
} else if (CurrentStringId == StringId) {
|
|
FindString = TRUE;
|
|
}
|
|
|
|
BlockSize += Offset + StringSize;
|
|
CurrentStringId++;
|
|
break;
|
|
|
|
case EFI_HII_SIBT_STRINGS_UCS2:
|
|
Offset = sizeof (EFI_HII_SIBT_STRINGS_UCS2_BLOCK) - sizeof (CHAR16);
|
|
StringTextPtr = BlockHdr + Offset;
|
|
BlockSize += Offset;
|
|
CopyMem (&StringCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16));
|
|
for (Index = 0; Index < StringCount; Index++) {
|
|
GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String);
|
|
|
|
if (FindString) {
|
|
*KeywordValue = String;
|
|
return CurrentStringId;
|
|
} else if (CurrentStringId == StringId) {
|
|
FindString = TRUE;
|
|
}
|
|
|
|
BlockSize += StringSize;
|
|
StringTextPtr = StringTextPtr + StringSize;
|
|
CurrentStringId++;
|
|
}
|
|
break;
|
|
|
|
case EFI_HII_SIBT_STRINGS_UCS2_FONT:
|
|
Offset = sizeof (EFI_HII_SIBT_STRINGS_UCS2_FONT_BLOCK) - sizeof (CHAR16);
|
|
StringTextPtr = BlockHdr + Offset;
|
|
BlockSize += Offset;
|
|
CopyMem (
|
|
&StringCount,
|
|
(UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)),
|
|
sizeof (UINT16)
|
|
);
|
|
for (Index = 0; Index < StringCount; Index++) {
|
|
GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String);
|
|
if (FindString) {
|
|
*KeywordValue = String;
|
|
return CurrentStringId;
|
|
} else if (CurrentStringId == StringId) {
|
|
FindString = TRUE;
|
|
}
|
|
|
|
BlockSize += StringSize;
|
|
StringTextPtr = StringTextPtr + StringSize;
|
|
CurrentStringId++;
|
|
}
|
|
break;
|
|
|
|
case EFI_HII_SIBT_DUPLICATE:
|
|
BlockSize += sizeof (EFI_HII_SIBT_DUPLICATE_BLOCK);
|
|
CurrentStringId++;
|
|
break;
|
|
|
|
case EFI_HII_SIBT_SKIP1:
|
|
SkipCount = (UINT16) (*(UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK)));
|
|
CurrentStringId = (UINT16) (CurrentStringId + SkipCount);
|
|
BlockSize += sizeof (EFI_HII_SIBT_SKIP1_BLOCK);
|
|
break;
|
|
|
|
case EFI_HII_SIBT_SKIP2:
|
|
CopyMem (&SkipCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16));
|
|
CurrentStringId = (UINT16) (CurrentStringId + SkipCount);
|
|
BlockSize += sizeof (EFI_HII_SIBT_SKIP2_BLOCK);
|
|
break;
|
|
|
|
case EFI_HII_SIBT_EXT1:
|
|
CopyMem (
|
|
&Length8,
|
|
(UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)),
|
|
sizeof (UINT8)
|
|
);
|
|
BlockSize += Length8;
|
|
break;
|
|
|
|
case EFI_HII_SIBT_EXT2:
|
|
CopyMem (&Ext2, BlockHdr, sizeof (EFI_HII_SIBT_EXT2_BLOCK));
|
|
BlockSize += Ext2.Length;
|
|
break;
|
|
|
|
case EFI_HII_SIBT_EXT4:
|
|
CopyMem (
|
|
&Length32,
|
|
(UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)),
|
|
sizeof (UINT32)
|
|
);
|
|
|
|
BlockSize += Length32;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (String != NULL) {
|
|
FreePool (String);
|
|
String = NULL;
|
|
}
|
|
|
|
BlockHdr = StringPackage->StringBlock + BlockSize;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
Get string package from the input NameSpace string.
|
|
|
|
This is a internal function.
|
|
|
|
@param DatabaseRecord HII_DATABASE_RECORD format string.
|
|
@param NameSpace NameSpace format string.
|
|
@param KeywordValue Keyword value.
|
|
@param StringId String Id for this keyword.
|
|
|
|
@retval KEYWORD_HANDLER_NO_ERROR Get String id succes.
|
|
@retval KEYWORD_HANDLER_KEYWORD_NOT_FOUND Not found the string id in the string package.
|
|
@retval KEYWORD_HANDLER_NAMESPACE_ID_NOT_FOUND Not found the string package for this namespace.
|
|
@retval KEYWORD_HANDLER_UNDEFINED_PROCESSING_ERROR Out of resource error.
|
|
|
|
**/
|
|
UINT32
|
|
GetStringIdFromRecord (
|
|
IN HII_DATABASE_RECORD *DatabaseRecord,
|
|
IN CHAR8 **NameSpace,
|
|
IN CHAR16 *KeywordValue,
|
|
OUT EFI_STRING_ID *StringId
|
|
)
|
|
{
|
|
LIST_ENTRY *Link;
|
|
HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageListNode;
|
|
HII_STRING_PACKAGE_INSTANCE *StringPackage;
|
|
EFI_STATUS Status;
|
|
CHAR8 *Name;
|
|
UINT32 RetVal;
|
|
|
|
ASSERT (DatabaseRecord != NULL && NameSpace != NULL && KeywordValue != NULL);
|
|
|
|
PackageListNode = DatabaseRecord->PackageList;
|
|
RetVal = KEYWORD_HANDLER_NAMESPACE_ID_NOT_FOUND;
|
|
|
|
if (*NameSpace != NULL) {
|
|
Name = *NameSpace;
|
|
} else {
|
|
Name = UEFI_CONFIG_LANG;
|
|
}
|
|
|
|
for (Link = PackageListNode->StringPkgHdr.ForwardLink; Link != &PackageListNode->StringPkgHdr; Link = Link->ForwardLink) {
|
|
StringPackage = CR (Link, HII_STRING_PACKAGE_INSTANCE, StringEntry, HII_STRING_PACKAGE_SIGNATURE);
|
|
|
|
if (AsciiStrnCmp(Name, StringPackage->StringPkgHdr->Language, AsciiStrLen (Name)) == 0) {
|
|
Status = GetStringIdFromString (StringPackage, KeywordValue, StringId);
|
|
if (EFI_ERROR (Status)) {
|
|
return KEYWORD_HANDLER_KEYWORD_NOT_FOUND;
|
|
} else {
|
|
if (*NameSpace == NULL) {
|
|
*NameSpace = AllocateCopyPool (AsciiStrSize (StringPackage->StringPkgHdr->Language), StringPackage->StringPkgHdr->Language);
|
|
if (*NameSpace == NULL) {
|
|
return KEYWORD_HANDLER_UNDEFINED_PROCESSING_ERROR;
|
|
}
|
|
}
|
|
return KEYWORD_HANDLER_NO_ERROR;
|
|
}
|
|
}
|
|
}
|
|
|
|
return RetVal;
|
|
}
|
|
|
|
/**
|
|
Tell whether this Operand is an Statement OpCode.
|
|
|
|
@param Operand Operand of an IFR OpCode.
|
|
|
|
@retval TRUE This is an Statement OpCode.
|
|
@retval FALSE Not an Statement OpCode.
|
|
|
|
**/
|
|
BOOLEAN
|
|
IsStatementOpCode (
|
|
IN UINT8 Operand
|
|
)
|
|
{
|
|
if ((Operand == EFI_IFR_SUBTITLE_OP) ||
|
|
(Operand == EFI_IFR_TEXT_OP) ||
|
|
(Operand == EFI_IFR_RESET_BUTTON_OP) ||
|
|
(Operand == EFI_IFR_REF_OP) ||
|
|
(Operand == EFI_IFR_ACTION_OP) ||
|
|
(Operand == EFI_IFR_NUMERIC_OP) ||
|
|
(Operand == EFI_IFR_ORDERED_LIST_OP) ||
|
|
(Operand == EFI_IFR_CHECKBOX_OP) ||
|
|
(Operand == EFI_IFR_STRING_OP) ||
|
|
(Operand == EFI_IFR_PASSWORD_OP) ||
|
|
(Operand == EFI_IFR_DATE_OP) ||
|
|
(Operand == EFI_IFR_TIME_OP) ||
|
|
(Operand == EFI_IFR_GUID_OP) ||
|
|
(Operand == EFI_IFR_ONE_OF_OP)) {
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
Tell whether this Operand is an Statement OpCode.
|
|
|
|
@param Operand Operand of an IFR OpCode.
|
|
|
|
@retval TRUE This is an Statement OpCode.
|
|
@retval FALSE Not an Statement OpCode.
|
|
|
|
**/
|
|
BOOLEAN
|
|
IsStorageOpCode (
|
|
IN UINT8 Operand
|
|
)
|
|
{
|
|
if ((Operand == EFI_IFR_VARSTORE_OP) ||
|
|
(Operand == EFI_IFR_VARSTORE_NAME_VALUE_OP) ||
|
|
(Operand == EFI_IFR_VARSTORE_EFI_OP)) {
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
Base on the prompt string id to find the question.
|
|
|
|
@param FormPackage The input form package.
|
|
@param KeywordStrId The input prompt string id for one question.
|
|
|
|
@retval the opcode for the question.
|
|
|
|
**/
|
|
UINT8 *
|
|
FindQuestionFromStringId (
|
|
IN HII_IFR_PACKAGE_INSTANCE *FormPackage,
|
|
IN EFI_STRING_ID KeywordStrId
|
|
)
|
|
{
|
|
UINT8 *OpCodeData;
|
|
UINT32 Offset;
|
|
EFI_IFR_STATEMENT_HEADER *StatementHeader;
|
|
EFI_IFR_OP_HEADER *OpCodeHeader;
|
|
UINT32 FormDataLen;
|
|
|
|
ASSERT (FormPackage != NULL);
|
|
|
|
FormDataLen = FormPackage->FormPkgHdr.Length - sizeof (EFI_HII_PACKAGE_HEADER);
|
|
Offset = 0;
|
|
while (Offset < FormDataLen) {
|
|
OpCodeData = FormPackage->IfrData + Offset;
|
|
OpCodeHeader = (EFI_IFR_OP_HEADER *) OpCodeData;
|
|
|
|
if (IsStatementOpCode(OpCodeHeader->OpCode)) {
|
|
StatementHeader = (EFI_IFR_STATEMENT_HEADER *) (OpCodeData + sizeof (EFI_IFR_OP_HEADER));
|
|
if (StatementHeader->Prompt == KeywordStrId) {
|
|
return OpCodeData;
|
|
}
|
|
}
|
|
|
|
Offset += OpCodeHeader->Length;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
Base on the varstore id to find the storage info.
|
|
|
|
@param FormPackage The input form package.
|
|
@param VarStoreId The input storage id.
|
|
|
|
@retval the opcode for the storage.
|
|
|
|
**/
|
|
UINT8 *
|
|
FindStorageFromVarId (
|
|
IN HII_IFR_PACKAGE_INSTANCE *FormPackage,
|
|
IN EFI_VARSTORE_ID VarStoreId
|
|
)
|
|
{
|
|
UINT8 *OpCodeData;
|
|
UINT32 Offset;
|
|
EFI_IFR_OP_HEADER *OpCodeHeader;
|
|
UINT32 FormDataLen;
|
|
|
|
ASSERT (FormPackage != NULL);
|
|
|
|
FormDataLen = FormPackage->FormPkgHdr.Length - sizeof (EFI_HII_PACKAGE_HEADER);
|
|
Offset = 0;
|
|
while (Offset < FormDataLen) {
|
|
OpCodeData = FormPackage->IfrData + Offset;
|
|
OpCodeHeader = (EFI_IFR_OP_HEADER *) OpCodeData;
|
|
|
|
if (IsStorageOpCode(OpCodeHeader->OpCode)) {
|
|
switch (OpCodeHeader->OpCode) {
|
|
case EFI_IFR_VARSTORE_OP:
|
|
if (VarStoreId == ((EFI_IFR_VARSTORE *) OpCodeData)->VarStoreId) {
|
|
return OpCodeData;
|
|
}
|
|
break;
|
|
|
|
case EFI_IFR_VARSTORE_NAME_VALUE_OP:
|
|
if (VarStoreId == ((EFI_IFR_VARSTORE_NAME_VALUE *) OpCodeData)->VarStoreId) {
|
|
return OpCodeData;
|
|
}
|
|
break;
|
|
|
|
case EFI_IFR_VARSTORE_EFI_OP:
|
|
if (VarStoreId == ((EFI_IFR_VARSTORE_EFI *) OpCodeData)->VarStoreId) {
|
|
return OpCodeData;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
Offset += OpCodeHeader->Length;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
Get width info for one question.
|
|
|
|
@param OpCodeData The input opcode for one question.
|
|
|
|
@retval the width info for one question.
|
|
|
|
**/
|
|
UINT16
|
|
GetWidth (
|
|
IN UINT8 *OpCodeData
|
|
)
|
|
{
|
|
UINT8 *NextOpCodeData;
|
|
|
|
ASSERT (OpCodeData != NULL);
|
|
|
|
switch (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode) {
|
|
case EFI_IFR_REF_OP:
|
|
return (UINT16) sizeof (EFI_HII_REF);
|
|
|
|
case EFI_IFR_ONE_OF_OP:
|
|
case EFI_IFR_NUMERIC_OP:
|
|
switch (((EFI_IFR_ONE_OF *) OpCodeData)->Flags & EFI_IFR_NUMERIC_SIZE) {
|
|
case EFI_IFR_NUMERIC_SIZE_1:
|
|
return (UINT16) sizeof (UINT8);
|
|
|
|
case EFI_IFR_NUMERIC_SIZE_2:
|
|
return (UINT16) sizeof (UINT16);
|
|
|
|
case EFI_IFR_NUMERIC_SIZE_4:
|
|
return (UINT16) sizeof (UINT32);
|
|
|
|
case EFI_IFR_NUMERIC_SIZE_8:
|
|
return (UINT16) sizeof (UINT64);
|
|
|
|
default:
|
|
ASSERT (FALSE);
|
|
return 0;
|
|
}
|
|
|
|
case EFI_IFR_ORDERED_LIST_OP:
|
|
NextOpCodeData = OpCodeData + ((EFI_IFR_ORDERED_LIST *) OpCodeData)->Header.Length;
|
|
//
|
|
// OneOfOption must follow the orderedlist opcode.
|
|
//
|
|
ASSERT (((EFI_IFR_OP_HEADER *) NextOpCodeData)->OpCode == EFI_IFR_ONE_OF_OPTION_OP);
|
|
switch (((EFI_IFR_ONE_OF_OPTION *) NextOpCodeData)->Type) {
|
|
case EFI_IFR_TYPE_NUM_SIZE_8:
|
|
return (UINT16) sizeof (UINT8) * ((EFI_IFR_ORDERED_LIST *) OpCodeData)->MaxContainers;
|
|
|
|
case EFI_IFR_TYPE_NUM_SIZE_16:
|
|
return (UINT16) sizeof (UINT16) * ((EFI_IFR_ORDERED_LIST *) OpCodeData)->MaxContainers ;
|
|
|
|
case EFI_IFR_TYPE_NUM_SIZE_32:
|
|
return (UINT16) sizeof (UINT32) * ((EFI_IFR_ORDERED_LIST *) OpCodeData)->MaxContainers;
|
|
|
|
case EFI_IFR_TYPE_NUM_SIZE_64:
|
|
return (UINT16) sizeof (UINT64) * ((EFI_IFR_ORDERED_LIST *) OpCodeData)->MaxContainers;
|
|
|
|
default:
|
|
ASSERT (FALSE);
|
|
return 0;
|
|
}
|
|
|
|
case EFI_IFR_CHECKBOX_OP:
|
|
return (UINT16) sizeof (BOOLEAN);
|
|
|
|
case EFI_IFR_PASSWORD_OP:
|
|
case EFI_IFR_STRING_OP:
|
|
return (UINT16)((UINTN) ((EFI_IFR_STRING *) OpCodeData)->MaxSize * sizeof (CHAR16));
|
|
|
|
case EFI_IFR_DATE_OP:
|
|
return (UINT16) sizeof (EFI_HII_DATE);
|
|
|
|
case EFI_IFR_TIME_OP:
|
|
return (UINT16) sizeof (EFI_HII_TIME);
|
|
|
|
default:
|
|
ASSERT (FALSE);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
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
|
|
InternalLowerConfigString (
|
|
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;
|
|
}
|
|
|
|
/**
|
|
Allocates and returns a Null-terminated Unicode <ConfigHdr> string.
|
|
|
|
The format of a <ConfigHdr> is as follows:
|
|
|
|
GUID=<HexCh>32&NAME=<Char>NameLength&PATH=<HexChar>DevicePathSize<Null>
|
|
|
|
@param[in] OpCodeData The opcode for the storage.
|
|
@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
|
|
ConstructConfigHdr (
|
|
IN UINT8 *OpCodeData,
|
|
IN EFI_HANDLE DriverHandle
|
|
)
|
|
{
|
|
UINTN NameLength;
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
|
UINTN DevicePathSize;
|
|
CHAR16 *String;
|
|
CHAR16 *ReturnString;
|
|
UINTN Index;
|
|
UINT8 *Buffer;
|
|
CHAR16 *Name;
|
|
CHAR8 *AsciiName;
|
|
EFI_GUID *Guid;
|
|
UINTN MaxLen;
|
|
|
|
ASSERT (OpCodeData != NULL);
|
|
|
|
switch (((EFI_IFR_OP_HEADER *)OpCodeData)->OpCode) {
|
|
case EFI_IFR_VARSTORE_OP:
|
|
Guid = (EFI_GUID *)(UINTN *)&((EFI_IFR_VARSTORE *) OpCodeData)->Guid;
|
|
AsciiName = (CHAR8 *) ((EFI_IFR_VARSTORE *) OpCodeData)->Name;
|
|
break;
|
|
|
|
case EFI_IFR_VARSTORE_NAME_VALUE_OP:
|
|
Guid = (EFI_GUID *)(UINTN *)&((EFI_IFR_VARSTORE_NAME_VALUE *) OpCodeData)->Guid;
|
|
AsciiName = NULL;
|
|
break;
|
|
|
|
case EFI_IFR_VARSTORE_EFI_OP:
|
|
Guid = (EFI_GUID *)(UINTN *)&((EFI_IFR_VARSTORE_EFI *) OpCodeData)->Guid;
|
|
AsciiName = (CHAR8 *) ((EFI_IFR_VARSTORE_EFI *) OpCodeData)->Name;
|
|
break;
|
|
|
|
default:
|
|
ASSERT (FALSE);
|
|
Guid = NULL;
|
|
AsciiName = NULL;
|
|
break;
|
|
}
|
|
|
|
if (AsciiName != NULL) {
|
|
Name = AllocateZeroPool (AsciiStrSize (AsciiName) * 2);
|
|
ASSERT (Name != NULL);
|
|
AsciiStrToUnicodeStr(AsciiName, Name);
|
|
} else {
|
|
Name = NULL;
|
|
}
|
|
|
|
//
|
|
// 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++) {
|
|
String += UnicodeValueToString (String, PREFIX_ZERO | RADIX_HEX, *(Buffer++), 2);
|
|
}
|
|
}
|
|
|
|
//
|
|
// 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++) {
|
|
String += UnicodeValueToString (String, PREFIX_ZERO | RADIX_HEX, *Name, 4);
|
|
}
|
|
}
|
|
|
|
//
|
|
// 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++) {
|
|
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 InternalLowerConfigString (ReturnString);
|
|
}
|
|
|
|
/**
|
|
Generate the Config request element for one question.
|
|
|
|
@param Name The name info for one question.
|
|
@param Offset The offset info for one question.
|
|
@param Width The width info for one question.
|
|
|
|
@return Pointer to the Null-terminated Unicode request element string.
|
|
|
|
**/
|
|
EFI_STRING
|
|
ConstructRequestElement (
|
|
IN CHAR16 *Name,
|
|
IN UINT16 Offset,
|
|
IN UINT16 Width
|
|
)
|
|
{
|
|
CHAR16 *StringPtr;
|
|
UINTN Length;
|
|
|
|
if (Name != NULL) {
|
|
//
|
|
// Add <BlockName> length for each Name
|
|
//
|
|
// <BlockName> ::= Name + \0
|
|
// StrLen(Name) | 1
|
|
//
|
|
Length = StrLen (Name) + 1;
|
|
} else {
|
|
//
|
|
// Add <BlockName> length for each Offset/Width pair
|
|
//
|
|
// <BlockName> ::= OFFSET=1234&WIDTH=1234 + \0
|
|
// | 7 | 4 | 7 | 4 | 1
|
|
//
|
|
Length = (7 + 4 + 7 + 4 + 1);
|
|
}
|
|
|
|
//
|
|
// Allocate buffer for the entire <ConfigRequest>
|
|
//
|
|
StringPtr = AllocateZeroPool (Length * sizeof (CHAR16));
|
|
ASSERT (StringPtr != NULL);
|
|
|
|
if (Name != NULL) {
|
|
//
|
|
// Append Name\0
|
|
//
|
|
UnicodeSPrint (
|
|
StringPtr,
|
|
(StrLen (Name) + 1) * sizeof (CHAR16),
|
|
L"%s",
|
|
Name
|
|
);
|
|
} else {
|
|
//
|
|
// Append OFFSET=XXXX&WIDTH=YYYY\0
|
|
//
|
|
UnicodeSPrint (
|
|
StringPtr,
|
|
(7 + 4 + 7 + 4 + 1) * sizeof (CHAR16),
|
|
L"OFFSET=%04X&WIDTH=%04X",
|
|
Offset,
|
|
Width
|
|
);
|
|
}
|
|
|
|
return StringPtr;
|
|
}
|
|
|
|
/**
|
|
Get string value for question's name field.
|
|
|
|
@param DatabaseRecord HII_DATABASE_RECORD format string.
|
|
@param NameId The string id for the name field.
|
|
|
|
@retval Name string.
|
|
|
|
**/
|
|
CHAR16 *
|
|
GetNameFromId (
|
|
IN HII_DATABASE_RECORD *DatabaseRecord,
|
|
IN EFI_STRING_ID NameId
|
|
)
|
|
{
|
|
CHAR16 *Name;
|
|
CHAR8 *PlatformLanguage;
|
|
CHAR8 *SupportedLanguages;
|
|
CHAR8 *BestLanguage;
|
|
UINTN StringSize;
|
|
CHAR16 TempString;
|
|
EFI_STATUS Status;
|
|
|
|
Name = NULL;
|
|
BestLanguage = NULL;
|
|
PlatformLanguage = NULL;
|
|
SupportedLanguages = NULL;
|
|
|
|
GetEfiGlobalVariable2 (L"PlatformLang", (VOID**)&PlatformLanguage, NULL);
|
|
SupportedLanguages = GetSupportedLanguages(DatabaseRecord->Handle);
|
|
|
|
//
|
|
// Get the best matching language from SupportedLanguages
|
|
//
|
|
BestLanguage = GetBestLanguage (
|
|
SupportedLanguages,
|
|
FALSE, // RFC 4646 mode
|
|
PlatformLanguage != NULL ? PlatformLanguage : "", // Highest priority
|
|
SupportedLanguages, // Lowest priority
|
|
NULL
|
|
);
|
|
if (BestLanguage == NULL) {
|
|
BestLanguage = AllocateCopyPool (AsciiStrLen ("en-US"), "en-US");
|
|
ASSERT (BestLanguage != NULL);
|
|
}
|
|
|
|
StringSize = 0;
|
|
Status = mPrivate.HiiString.GetString (
|
|
&mPrivate.HiiString,
|
|
BestLanguage,
|
|
DatabaseRecord->Handle,
|
|
NameId,
|
|
&TempString,
|
|
&StringSize,
|
|
NULL
|
|
);
|
|
if (Status != EFI_BUFFER_TOO_SMALL) {
|
|
goto Done;
|
|
}
|
|
|
|
Name = AllocateZeroPool (StringSize);
|
|
if (Name == NULL) {
|
|
goto Done;
|
|
}
|
|
|
|
Status = mPrivate.HiiString.GetString (
|
|
&mPrivate.HiiString,
|
|
BestLanguage,
|
|
DatabaseRecord->Handle,
|
|
NameId,
|
|
Name,
|
|
&StringSize,
|
|
NULL
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
FreePool (Name);
|
|
Name = NULL;
|
|
goto Done;
|
|
}
|
|
|
|
Done:
|
|
if (SupportedLanguages != NULL) {
|
|
FreePool(SupportedLanguages);
|
|
}
|
|
if (BestLanguage != NULL) {
|
|
FreePool (BestLanguage);
|
|
}
|
|
if (PlatformLanguage != NULL) {
|
|
FreePool (PlatformLanguage);
|
|
}
|
|
|
|
return Name;
|
|
}
|
|
|
|
/**
|
|
Base on the input parameter to generate the ConfigRequest string.
|
|
|
|
This is a internal function.
|
|
|
|
@param DatabaseRecord HII_DATABASE_RECORD format string.
|
|
@param KeywordStrId Keyword string id.
|
|
@param OpCodeData The IFR data for this question.
|
|
@param ConfigRequest Return the generate ConfigRequest string.
|
|
|
|
@retval EFI_SUCCESS Generate ConfigResp string success.
|
|
@retval EFI_OUT_OF_RESOURCES System out of memory resource error.
|
|
@retval EFI_NOT_FOUND Not found the question which use this string id
|
|
as the prompt string id.
|
|
**/
|
|
EFI_STATUS
|
|
ExtractConfigRequest (
|
|
IN HII_DATABASE_RECORD *DatabaseRecord,
|
|
IN EFI_STRING_ID KeywordStrId,
|
|
OUT UINT8 **OpCodeData,
|
|
OUT EFI_STRING *ConfigRequest
|
|
)
|
|
{
|
|
LIST_ENTRY *Link;
|
|
HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageListNode;
|
|
HII_IFR_PACKAGE_INSTANCE *FormPackage;
|
|
EFI_IFR_QUESTION_HEADER *Header;
|
|
UINT8 *Storage;
|
|
UINT8 *OpCode;
|
|
CHAR16 *Name;
|
|
UINT16 Offset;
|
|
UINT16 Width;
|
|
CHAR16 *ConfigHdr;
|
|
CHAR16 *RequestElement;
|
|
UINTN MaxLen;
|
|
CHAR16 *StringPtr;
|
|
|
|
ASSERT (DatabaseRecord != NULL && OpCodeData != NULL && ConfigRequest != NULL);
|
|
|
|
OpCode = NULL;
|
|
Name = NULL;
|
|
Width = 0;
|
|
Offset = 0;
|
|
|
|
PackageListNode = DatabaseRecord->PackageList;
|
|
|
|
//
|
|
// Search the languages in the specified packagelist.
|
|
//
|
|
for (Link = PackageListNode->FormPkgHdr.ForwardLink; Link != &PackageListNode->FormPkgHdr; Link = Link->ForwardLink) {
|
|
FormPackage = CR (Link, HII_IFR_PACKAGE_INSTANCE, IfrEntry, HII_IFR_PACKAGE_SIGNATURE);
|
|
|
|
OpCode = FindQuestionFromStringId (FormPackage, KeywordStrId);
|
|
if (OpCode != NULL) {
|
|
*OpCodeData = OpCode;
|
|
Header = (EFI_IFR_QUESTION_HEADER *) (OpCode + sizeof (EFI_IFR_OP_HEADER));
|
|
//
|
|
// Header->VarStoreId == 0 means no storage for this question.
|
|
//
|
|
ASSERT (Header->VarStoreId != 0);
|
|
DEBUG ((EFI_D_INFO, "Varstore Id: 0x%x\n", Header->VarStoreId));
|
|
|
|
Storage = FindStorageFromVarId (FormPackage, Header->VarStoreId);
|
|
ASSERT (Storage != NULL);
|
|
|
|
if (((EFI_IFR_OP_HEADER *) Storage)->OpCode == EFI_IFR_VARSTORE_NAME_VALUE_OP) {
|
|
Name = GetNameFromId (DatabaseRecord, Header->VarStoreInfo.VarName);
|
|
} else {
|
|
Offset = Header->VarStoreInfo.VarOffset;
|
|
Width = GetWidth (OpCode);
|
|
}
|
|
RequestElement = ConstructRequestElement(Name, Offset, Width);
|
|
ConfigHdr = ConstructConfigHdr(Storage, DatabaseRecord->DriverHandle);
|
|
ASSERT (ConfigHdr != NULL);
|
|
|
|
MaxLen = StrLen (ConfigHdr) + 1 + StrLen(RequestElement) + 1;
|
|
*ConfigRequest = AllocatePool (MaxLen * sizeof (CHAR16));
|
|
if (*ConfigRequest == NULL) {
|
|
FreePool (ConfigHdr);
|
|
FreePool (RequestElement);
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
StringPtr = *ConfigRequest;
|
|
|
|
StrCpyS (StringPtr, MaxLen, ConfigHdr);
|
|
|
|
StrCatS (StringPtr, MaxLen, L"&");
|
|
|
|
StrCatS (StringPtr, MaxLen, RequestElement);
|
|
|
|
FreePool (ConfigHdr);
|
|
FreePool (RequestElement);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
}
|
|
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
/**
|
|
Base on the input parameter to generate the ConfigResp string.
|
|
|
|
This is a internal function.
|
|
|
|
@param DatabaseRecord HII_DATABASE_RECORD format string.
|
|
@param KeywordStrId Keyword string id.
|
|
@param ValueElement The value for the question which use keyword string id
|
|
as the prompt string id.
|
|
@param OpCodeData The IFR data for this question.
|
|
@param ConfigResp Return the generate ConfigResp string.
|
|
|
|
@retval EFI_SUCCESS Generate ConfigResp string success.
|
|
@retval EFI_OUT_OF_RESOURCES System out of memory resource error.
|
|
@retval EFI_NOT_FOUND Not found the question which use this string id
|
|
as the prompt string id.
|
|
**/
|
|
EFI_STATUS
|
|
ExtractConfigResp (
|
|
IN HII_DATABASE_RECORD *DatabaseRecord,
|
|
IN EFI_STRING_ID KeywordStrId,
|
|
IN EFI_STRING ValueElement,
|
|
OUT UINT8 **OpCodeData,
|
|
OUT EFI_STRING *ConfigResp
|
|
)
|
|
{
|
|
LIST_ENTRY *Link;
|
|
HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageListNode;
|
|
HII_IFR_PACKAGE_INSTANCE *FormPackage;
|
|
EFI_IFR_QUESTION_HEADER *Header;
|
|
UINT8 *Storage;
|
|
UINT8 *OpCode;
|
|
CHAR16 *Name;
|
|
UINT16 Offset;
|
|
UINT16 Width;
|
|
CHAR16 *ConfigHdr;
|
|
CHAR16 *RequestElement;
|
|
UINTN MaxLen;
|
|
CHAR16 *StringPtr;
|
|
|
|
ASSERT ((DatabaseRecord != NULL) && (OpCodeData != NULL) && (ConfigResp != NULL) && (ValueElement != NULL));
|
|
|
|
OpCode = NULL;
|
|
Name = NULL;
|
|
Width = 0;
|
|
Offset = 0;
|
|
|
|
PackageListNode = DatabaseRecord->PackageList;
|
|
|
|
//
|
|
// Search the languages in the specified packagelist.
|
|
//
|
|
for (Link = PackageListNode->FormPkgHdr.ForwardLink; Link != &PackageListNode->FormPkgHdr; Link = Link->ForwardLink) {
|
|
FormPackage = CR (Link, HII_IFR_PACKAGE_INSTANCE, IfrEntry, HII_IFR_PACKAGE_SIGNATURE);
|
|
|
|
OpCode = FindQuestionFromStringId (FormPackage, KeywordStrId);
|
|
if (OpCode != NULL) {
|
|
*OpCodeData = OpCode;
|
|
Header = (EFI_IFR_QUESTION_HEADER *) (OpCode + sizeof (EFI_IFR_OP_HEADER));
|
|
//
|
|
// Header->VarStoreId == 0 means no storage for this question.
|
|
//
|
|
ASSERT (Header->VarStoreId != 0);
|
|
DEBUG ((EFI_D_INFO, "Varstore Id: 0x%x\n", Header->VarStoreId));
|
|
|
|
Storage = FindStorageFromVarId (FormPackage, Header->VarStoreId);
|
|
ASSERT (Storage != NULL);
|
|
|
|
if (((EFI_IFR_OP_HEADER *) Storage)->OpCode == EFI_IFR_VARSTORE_NAME_VALUE_OP) {
|
|
Name = GetNameFromId (DatabaseRecord, Header->VarStoreInfo.VarName);
|
|
} else {
|
|
Offset = Header->VarStoreInfo.VarOffset;
|
|
Width = GetWidth (OpCode);
|
|
}
|
|
RequestElement = ConstructRequestElement(Name, Offset, Width);
|
|
|
|
ConfigHdr = ConstructConfigHdr(Storage, DatabaseRecord->DriverHandle);
|
|
ASSERT (ConfigHdr != NULL);
|
|
|
|
MaxLen = StrLen (ConfigHdr) + 1 + StrLen(RequestElement) + 1 + StrLen (L"VALUE=") + StrLen(ValueElement) + 1;
|
|
*ConfigResp = AllocatePool (MaxLen * sizeof (CHAR16));
|
|
if (*ConfigResp == NULL) {
|
|
FreePool (ConfigHdr);
|
|
FreePool (RequestElement);
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
StringPtr = *ConfigResp;
|
|
|
|
StrCpyS (StringPtr, MaxLen, ConfigHdr);
|
|
|
|
StrCatS (StringPtr, MaxLen, L"&");
|
|
|
|
|
|
StrCatS (StringPtr, MaxLen, RequestElement);
|
|
|
|
StrCatS (StringPtr, MaxLen, L"&");
|
|
|
|
StrCatS (StringPtr, MaxLen, L"VALUE=");
|
|
|
|
StrCatS (StringPtr, MaxLen, ValueElement);
|
|
|
|
FreePool (ConfigHdr);
|
|
FreePool (RequestElement);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
}
|
|
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
/**
|
|
Get the Value section from the Hii driver.
|
|
|
|
This is a internal function.
|
|
|
|
@param ConfigRequest The input ConfigRequest string.
|
|
@param ValueElement The respond Value section from the hii driver.
|
|
|
|
@retval Misc value The error status return from ExtractConfig function.
|
|
@retval EFI_OUT_OF_RESOURCES The memory can't be allocated
|
|
@retval EFI_SUCCESS Get the value section success.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
ExtractValueFromDriver (
|
|
IN CHAR16 *ConfigRequest,
|
|
OUT CHAR16 **ValueElement
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_STRING Result;
|
|
EFI_STRING Progress;
|
|
CHAR16 *StringPtr;
|
|
CHAR16 *StringEnd;
|
|
|
|
ASSERT ((ConfigRequest != NULL) && (ValueElement != NULL));
|
|
|
|
Status = mPrivate.ConfigRouting.ExtractConfig (
|
|
&mPrivate.ConfigRouting,
|
|
(EFI_STRING) ConfigRequest,
|
|
&Progress,
|
|
&Result
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Find Value Section and return it.
|
|
//
|
|
StringPtr = StrStr (Result, L"&VALUE=");
|
|
ASSERT (StringPtr != NULL);
|
|
StringEnd = StrStr (StringPtr + 1, L"&");
|
|
if (StringEnd != NULL) {
|
|
*StringEnd = L'\0';
|
|
}
|
|
|
|
*ValueElement = AllocateCopyPool (StrSize (StringPtr), StringPtr);
|
|
if (*ValueElement == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
if (StringEnd != NULL) {
|
|
*StringEnd = L'&';
|
|
}
|
|
FreePool (Result);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Get EFI_STRING_ID info from the input device path, namespace and keyword.
|
|
|
|
This is a internal function.
|
|
|
|
@param DevicePath Input device path info.
|
|
@param NameSpace NameSpace format string.
|
|
@param KeywordData Keyword used to get string id.
|
|
@param ProgressErr Return extra error type.
|
|
@param KeywordStringId Return EFI_STRING_ID.
|
|
@param DataBaseRecord DataBase record data for this driver.
|
|
|
|
@retval EFI_INVALID_PARAMETER Can't find the database record base on the input device path or namespace.
|
|
@retval EFI_NOT_FOUND Can't find the EFI_STRING_ID for the keyword.
|
|
@retval EFI_SUCCESS Find the EFI_STRING_ID.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
GetStringIdFromDatabase (
|
|
IN EFI_DEVICE_PATH_PROTOCOL **DevicePath,
|
|
IN CHAR8 **NameSpace,
|
|
IN CHAR16 *KeywordData,
|
|
OUT UINT32 *ProgressErr,
|
|
OUT EFI_STRING_ID *KeywordStringId,
|
|
OUT HII_DATABASE_RECORD **DataBaseRecord
|
|
)
|
|
{
|
|
HII_DATABASE_RECORD *Record;
|
|
LIST_ENTRY *Link;
|
|
BOOLEAN FindNameSpace;
|
|
EFI_DEVICE_PATH_PROTOCOL *DestDevicePath;
|
|
UINT8 *DevicePathPkg;
|
|
UINTN DevicePathSize;
|
|
|
|
ASSERT ((NameSpace != NULL) && (KeywordData != NULL) && (ProgressErr != NULL) && (KeywordStringId != NULL) && (DataBaseRecord != NULL));
|
|
|
|
FindNameSpace = FALSE;
|
|
|
|
if (*DevicePath != NULL) {
|
|
//
|
|
// Get DataBaseRecord from device path protocol.
|
|
//
|
|
Record = GetRecordFromDevicePath(*DevicePath);
|
|
if (Record == NULL) {
|
|
//
|
|
// Can't find the DatabaseRecord base on the input device path info.
|
|
// NEED TO CONFIRM the return ProgressErr.
|
|
//
|
|
*ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING;
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Get string id from the record.
|
|
//
|
|
*ProgressErr = GetStringIdFromRecord (Record, NameSpace, KeywordData, KeywordStringId);
|
|
switch (*ProgressErr) {
|
|
case KEYWORD_HANDLER_NO_ERROR:
|
|
*DataBaseRecord = Record;
|
|
return EFI_SUCCESS;
|
|
|
|
case KEYWORD_HANDLER_NAMESPACE_ID_NOT_FOUND:
|
|
return EFI_INVALID_PARAMETER;
|
|
|
|
default:
|
|
ASSERT (*ProgressErr == KEYWORD_HANDLER_KEYWORD_NOT_FOUND);
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
} else {
|
|
//
|
|
// Find driver which matches the routing data.
|
|
//
|
|
for (Link = mPrivate.DatabaseList.ForwardLink; Link != &mPrivate.DatabaseList; Link = Link->ForwardLink) {
|
|
Record = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
|
|
|
|
*ProgressErr = GetStringIdFromRecord (Record, NameSpace, KeywordData, KeywordStringId);
|
|
if (*ProgressErr == KEYWORD_HANDLER_NO_ERROR) {
|
|
*DataBaseRecord = Record;
|
|
|
|
if ((DevicePathPkg = Record->PackageList->DevicePathPkg) != NULL) {
|
|
DestDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) (DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER));
|
|
DevicePathSize = GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) DestDevicePath);
|
|
*DevicePath = AllocateCopyPool (DevicePathSize, DestDevicePath);
|
|
if (*DevicePath == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
} else {
|
|
//
|
|
// Need to verify this ASSERT.
|
|
//
|
|
ASSERT (FALSE);
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
} else if (*ProgressErr == KEYWORD_HANDLER_UNDEFINED_PROCESSING_ERROR) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
} else if (*ProgressErr == KEYWORD_HANDLER_KEYWORD_NOT_FOUND) {
|
|
FindNameSpace = TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// When PathHdr not input, if ever find the namespace, will return KEYWORD_HANDLER_KEYWORD_NOT_FOUND.
|
|
// This is a bit more progress than KEYWORD_HANDLER_NAMESPACE_ID_NOT_FOUND.
|
|
//
|
|
if (FindNameSpace) {
|
|
return EFI_NOT_FOUND;
|
|
} else {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
Genereate the KeywordResp String.
|
|
|
|
<KeywordResp> ::= <NameSpaceId><PathHdr>'&'<Keyword>'&VALUE='<Number>['&READONLY']
|
|
|
|
@param NameSpace NameSpace format string.
|
|
@param DevicePath Input device path info.
|
|
@param KeywordData Keyword used to get string id.
|
|
@param ValueStr The value section for the keyword.
|
|
@param ReadOnly Whether this value is readonly.
|
|
@param KeywordResp Return the point to the KeywordResp string.
|
|
|
|
@retval EFI_OUT_OF_RESOURCES The memory can't be allocated.
|
|
@retval EFI_SUCCESS Generate the KeywordResp string.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
GenerateKeywordResp (
|
|
IN CHAR8 *NameSpace,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
|
|
IN EFI_STRING KeywordData,
|
|
IN EFI_STRING ValueStr,
|
|
IN BOOLEAN ReadOnly,
|
|
OUT EFI_STRING *KeywordResp
|
|
)
|
|
{
|
|
UINTN RespStrLen;
|
|
CHAR16 *RespStr;
|
|
CHAR16 *PathHdr;
|
|
CHAR16 *UnicodeNameSpace;
|
|
|
|
ASSERT ((NameSpace != NULL) && (DevicePath != NULL) && (KeywordData != NULL) && (ValueStr != NULL) && (KeywordResp != NULL));
|
|
|
|
//
|
|
// 1. Calculate the string length.
|
|
//
|
|
//
|
|
// 1.1 NameSpaceId size.
|
|
// 'NAMESPACE='<String>
|
|
//
|
|
RespStrLen = 10 + AsciiStrLen (NameSpace);
|
|
UnicodeNameSpace = AllocatePool ((AsciiStrLen (NameSpace) + 1) * sizeof (CHAR16));
|
|
if (UnicodeNameSpace == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
AsciiStrToUnicodeStr(NameSpace, UnicodeNameSpace);
|
|
|
|
//
|
|
// 1.2 PathHdr size.
|
|
// PATH=<UEFI binary Device Path represented as hex number>'&'
|
|
// Attention: The output include the '&' at the end.
|
|
//
|
|
GenerateSubStr (
|
|
L"&PATH=",
|
|
GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) DevicePath),
|
|
(VOID *) DevicePath,
|
|
1,
|
|
&PathHdr
|
|
);
|
|
RespStrLen += StrLen (PathHdr);
|
|
|
|
//
|
|
// 1.3 Keyword setion.
|
|
// 'KEYWORD='<String>[':'<DecCh>(1/4)]
|
|
//
|
|
RespStrLen += 8 + StrLen (KeywordData);
|
|
|
|
//
|
|
// 1.4 Value section.
|
|
// ValueStr = '&VALUE='<Number>
|
|
//
|
|
RespStrLen += StrLen (ValueStr);
|
|
|
|
//
|
|
// 1.5 ReadOnly Section.
|
|
// '&READONLY'
|
|
//
|
|
if (ReadOnly) {
|
|
RespStrLen += 9;
|
|
}
|
|
|
|
//
|
|
// 2. Allocate the buffer and create the KeywordResp string include '\0'.
|
|
//
|
|
RespStrLen += 1;
|
|
*KeywordResp = AllocatePool (RespStrLen * sizeof (CHAR16));
|
|
if (*KeywordResp == NULL) {
|
|
if (UnicodeNameSpace != NULL) {
|
|
FreePool (UnicodeNameSpace);
|
|
}
|
|
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
RespStr = *KeywordResp;
|
|
|
|
//
|
|
// 2.1 Copy NameSpaceId section.
|
|
//
|
|
StrCpyS (RespStr, RespStrLen, L"NAMESPACE=");
|
|
|
|
StrCatS (RespStr, RespStrLen, UnicodeNameSpace);
|
|
|
|
//
|
|
// 2.2 Copy PathHdr section.
|
|
//
|
|
StrCatS (RespStr, RespStrLen, PathHdr);
|
|
|
|
//
|
|
// 2.3 Copy Keyword section.
|
|
//
|
|
StrCatS (RespStr, RespStrLen, L"KEYWORD=");
|
|
|
|
StrCatS (RespStr, RespStrLen, KeywordData);
|
|
|
|
//
|
|
// 2.4 Copy the Value section.
|
|
//
|
|
StrCatS (RespStr, RespStrLen, ValueStr);
|
|
|
|
//
|
|
// 2.5 Copy ReadOnly section if exist.
|
|
//
|
|
if (ReadOnly) {
|
|
StrCatS (RespStr, RespStrLen, L"&READONLY");
|
|
}
|
|
|
|
if (UnicodeNameSpace != NULL) {
|
|
FreePool (UnicodeNameSpace);
|
|
}
|
|
if (PathHdr != NULL) {
|
|
FreePool (PathHdr);
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Merge the KeywordResp String to MultiKeywordResp string.
|
|
|
|
This is a internal function.
|
|
|
|
@param MultiKeywordResp The existed multikeywordresp string.
|
|
@param KeywordResp The input keywordResp string.
|
|
|
|
@retval EFI_OUT_OF_RESOURCES The memory can't be allocated.
|
|
@retval EFI_SUCCESS Generate the MultiKeywordResp string.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
MergeToMultiKeywordResp (
|
|
IN OUT EFI_STRING *MultiKeywordResp,
|
|
IN EFI_STRING *KeywordResp
|
|
)
|
|
{
|
|
UINTN MultiKeywordRespLen;
|
|
EFI_STRING StringPtr;
|
|
|
|
if (*MultiKeywordResp == NULL) {
|
|
*MultiKeywordResp = *KeywordResp;
|
|
*KeywordResp = NULL;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
MultiKeywordRespLen = (StrLen (*MultiKeywordResp) + 1 + StrLen (*KeywordResp) + 1) * sizeof (CHAR16);
|
|
|
|
StringPtr = AllocateCopyPool (MultiKeywordRespLen, *MultiKeywordResp);
|
|
if (StringPtr == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
FreePool (*MultiKeywordResp);
|
|
*MultiKeywordResp = StringPtr;
|
|
|
|
StrCatS (StringPtr, MultiKeywordRespLen / sizeof (CHAR16), L"&");
|
|
|
|
StrCatS (StringPtr, MultiKeywordRespLen / sizeof (CHAR16), *KeywordResp);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Enumerate all keyword in the system.
|
|
|
|
If error occur when parse one keyword, just skip it and parse the next one.
|
|
|
|
This is a internal function.
|
|
|
|
@param NameSpace The namespace used to search the string.
|
|
@param MultiResp Return the MultiKeywordResp string for the system.
|
|
@param ProgressErr Return the error status.
|
|
|
|
@retval EFI_OUT_OF_RESOURCES The memory can't be allocated.
|
|
@retval EFI_SUCCESS Generate the MultiKeywordResp string.
|
|
@retval EFI_NOT_FOUND No keyword found.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EnumerateAllKeywords (
|
|
IN CHAR8 *NameSpace,
|
|
OUT EFI_STRING *MultiResp,
|
|
OUT UINT32 *ProgressErr
|
|
)
|
|
{
|
|
LIST_ENTRY *Link;
|
|
LIST_ENTRY *StringLink;
|
|
UINT8 *DevicePathPkg;
|
|
UINT8 *DevicePath;
|
|
HII_DATABASE_RECORD *DataBaseRecord;
|
|
HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageListNode;
|
|
HII_STRING_PACKAGE_INSTANCE *StringPackage;
|
|
CHAR8 *LocalNameSpace;
|
|
EFI_STRING_ID NextStringId;
|
|
EFI_STATUS Status;
|
|
UINT8 *OpCode;
|
|
CHAR16 *ConfigRequest;
|
|
CHAR16 *ValueElement;
|
|
CHAR16 *KeywordResp;
|
|
CHAR16 *MultiKeywordResp;
|
|
CHAR16 *KeywordData;
|
|
BOOLEAN ReadOnly;
|
|
BOOLEAN FindKeywordPackages;
|
|
|
|
DataBaseRecord = NULL;
|
|
Status = EFI_SUCCESS;
|
|
MultiKeywordResp = NULL;
|
|
DevicePath = NULL;
|
|
LocalNameSpace = NULL;
|
|
ConfigRequest = NULL;
|
|
ValueElement = NULL;
|
|
KeywordResp = NULL;
|
|
FindKeywordPackages = FALSE;
|
|
|
|
if (NameSpace == NULL) {
|
|
NameSpace = UEFI_CONFIG_LANG;
|
|
}
|
|
|
|
//
|
|
// Find driver which matches the routing data.
|
|
//
|
|
for (Link = mPrivate.DatabaseList.ForwardLink; Link != &mPrivate.DatabaseList; Link = Link->ForwardLink) {
|
|
DataBaseRecord = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
|
|
if ((DevicePathPkg = DataBaseRecord->PackageList->DevicePathPkg) != NULL) {
|
|
DevicePath = DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);
|
|
}
|
|
PackageListNode = DataBaseRecord->PackageList;
|
|
|
|
for (StringLink = PackageListNode->StringPkgHdr.ForwardLink; StringLink != &PackageListNode->StringPkgHdr; StringLink = StringLink->ForwardLink) {
|
|
StringPackage = CR (StringLink, HII_STRING_PACKAGE_INSTANCE, StringEntry, HII_STRING_PACKAGE_SIGNATURE);
|
|
|
|
//
|
|
// Check whether has keyword string package.
|
|
//
|
|
if (AsciiStrnCmp(NameSpace, StringPackage->StringPkgHdr->Language, AsciiStrLen (NameSpace)) == 0) {
|
|
FindKeywordPackages = TRUE;
|
|
//
|
|
// Keep the NameSpace string.
|
|
//
|
|
LocalNameSpace = AllocateCopyPool (AsciiStrSize (StringPackage->StringPkgHdr->Language), StringPackage->StringPkgHdr->Language);
|
|
if (LocalNameSpace == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// 1 means just begin the enumerate the valid string ids.
|
|
// StringId == 1 is always used to save the language for this string package.
|
|
// Any valid string start from 2. so here initial it to 1.
|
|
//
|
|
NextStringId = 1;
|
|
|
|
//
|
|
// Enumerate all valid stringid in the package.
|
|
//
|
|
while ((NextStringId = GetNextStringId (StringPackage, NextStringId, &KeywordData)) != 0) {
|
|
//
|
|
// 3.3 Construct the ConfigRequest string.
|
|
//
|
|
Status = ExtractConfigRequest (DataBaseRecord, NextStringId, &OpCode, &ConfigRequest);
|
|
if (EFI_ERROR (Status)) {
|
|
//
|
|
// If can't generate ConfigRequest for this question, skip it and start the next.
|
|
//
|
|
goto Error;
|
|
}
|
|
|
|
//
|
|
// 3.4 Extract Value for the input keyword.
|
|
//
|
|
Status = ExtractValueFromDriver(ConfigRequest, &ValueElement);
|
|
if (EFI_ERROR (Status)) {
|
|
if (Status != EFI_OUT_OF_RESOURCES) {
|
|
//
|
|
// If can't generate ConfigRequest for this question, skip it and start the next.
|
|
//
|
|
goto Error;
|
|
}
|
|
//
|
|
// If EFI_OUT_OF_RESOURCES error occur, no need to continue.
|
|
//
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// Extract readonly flag from opcode.
|
|
//
|
|
ReadOnly = ExtractReadOnlyFromOpCode(OpCode);
|
|
|
|
//
|
|
// 5. Generate KeywordResp string.
|
|
//
|
|
ASSERT (DevicePath != NULL);
|
|
Status = GenerateKeywordResp(LocalNameSpace, (EFI_DEVICE_PATH_PROTOCOL *)DevicePath, KeywordData, ValueElement, ReadOnly, &KeywordResp);
|
|
if (Status != EFI_SUCCESS) {
|
|
//
|
|
// If EFI_OUT_OF_RESOURCES error occur, no need to continue.
|
|
//
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// 6. Merge to the MultiKeywordResp string.
|
|
//
|
|
Status = MergeToMultiKeywordResp(&MultiKeywordResp, &KeywordResp);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Done;
|
|
}
|
|
Error:
|
|
//
|
|
// Clean the temp buffer to later use again.
|
|
//
|
|
if (ConfigRequest != NULL) {
|
|
FreePool (ConfigRequest);
|
|
ConfigRequest = NULL;
|
|
}
|
|
if (ValueElement != NULL) {
|
|
FreePool (ValueElement);
|
|
ValueElement = NULL;
|
|
}
|
|
if (KeywordResp != NULL) {
|
|
FreePool (KeywordResp);
|
|
KeywordResp = NULL;
|
|
}
|
|
}
|
|
|
|
if (LocalNameSpace != NULL) {
|
|
FreePool (LocalNameSpace);
|
|
LocalNameSpace = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// return the already get MultiKeywordString even error occured.
|
|
//
|
|
if (MultiKeywordResp == NULL) {
|
|
Status = EFI_NOT_FOUND;
|
|
if (!FindKeywordPackages) {
|
|
*ProgressErr = KEYWORD_HANDLER_NAMESPACE_ID_NOT_FOUND;
|
|
} else {
|
|
*ProgressErr = KEYWORD_HANDLER_KEYWORD_NOT_FOUND;
|
|
}
|
|
} else {
|
|
Status = EFI_SUCCESS;
|
|
}
|
|
*MultiResp = MultiKeywordResp;
|
|
|
|
Done:
|
|
if (LocalNameSpace != NULL) {
|
|
FreePool (LocalNameSpace);
|
|
}
|
|
if (ConfigRequest != NULL) {
|
|
FreePool (ConfigRequest);
|
|
}
|
|
if (ValueElement != NULL) {
|
|
FreePool (ValueElement);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
|
|
This function accepts a <MultiKeywordResp> formatted string, finds the associated
|
|
keyword owners, creates a <MultiConfigResp> string from it and forwards it to the
|
|
EFI_HII_ROUTING_PROTOCOL.RouteConfig function.
|
|
|
|
If there is an issue in resolving the contents of the KeywordString, then the
|
|
function returns an error and also sets the Progress and ProgressErr with the
|
|
appropriate information about where the issue occurred and additional data about
|
|
the nature of the issue.
|
|
|
|
In the case when KeywordString containing multiple keywords, when an EFI_NOT_FOUND
|
|
error is generated during processing the second or later keyword element, the system
|
|
storage associated with earlier keywords is not modified. All elements of the
|
|
KeywordString must successfully pass all tests for format and access prior to making
|
|
any modifications to storage.
|
|
|
|
In the case when EFI_DEVICE_ERROR is returned from the processing of a KeywordString
|
|
containing multiple keywords, the state of storage associated with earlier keywords
|
|
is undefined.
|
|
|
|
|
|
@param This Pointer to the EFI_KEYWORD_HANDLER _PROTOCOL instance.
|
|
|
|
@param KeywordString A null-terminated string in <MultiKeywordResp> format.
|
|
|
|
@param Progress On return, points to a character in the KeywordString.
|
|
Points to the string's NULL terminator if the request
|
|
was successful. Points to the most recent '&' before
|
|
the first failing string element if the request was
|
|
not successful.
|
|
|
|
@param ProgressErr If during the processing of the KeywordString there was
|
|
a failure, this parameter gives additional information
|
|
about the possible source of the problem. The various
|
|
errors are defined in "Related Definitions" below.
|
|
|
|
|
|
@retval EFI_SUCCESS The specified action was completed successfully.
|
|
|
|
@retval EFI_INVALID_PARAMETER One or more of the following are TRUE:
|
|
1. KeywordString is NULL.
|
|
2. Parsing of the KeywordString resulted in an
|
|
error. See Progress and ProgressErr for more data.
|
|
|
|
@retval EFI_NOT_FOUND An element of the KeywordString was not found.
|
|
See ProgressErr for more data.
|
|
|
|
@retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
|
|
See ProgressErr for more data.
|
|
|
|
@retval EFI_ACCESS_DENIED The action violated system policy. See ProgressErr
|
|
for more data.
|
|
|
|
@retval EFI_DEVICE_ERROR An unexpected system error occurred. See ProgressErr
|
|
for more data.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
EfiConfigKeywordHandlerSetData (
|
|
IN EFI_CONFIG_KEYWORD_HANDLER_PROTOCOL *This,
|
|
IN CONST EFI_STRING KeywordString,
|
|
OUT EFI_STRING *Progress,
|
|
OUT UINT32 *ProgressErr
|
|
)
|
|
{
|
|
CHAR8 *NameSpace;
|
|
EFI_STATUS Status;
|
|
CHAR16 *StringPtr;
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
|
CHAR16 *NextStringPtr;
|
|
CHAR16 *KeywordData;
|
|
EFI_STRING_ID KeywordStringId;
|
|
UINT32 RetVal;
|
|
HII_DATABASE_RECORD *DataBaseRecord;
|
|
UINT8 *OpCode;
|
|
CHAR16 *ConfigResp;
|
|
CHAR16 *MultiConfigResp;
|
|
CHAR16 *ValueElement;
|
|
BOOLEAN ReadOnly;
|
|
EFI_STRING InternalProgress;
|
|
CHAR16 *TempString;
|
|
CHAR16 *KeywordStartPos;
|
|
|
|
if (This == NULL || Progress == NULL || ProgressErr == NULL || KeywordString == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
*Progress = KeywordString;
|
|
*ProgressErr = KEYWORD_HANDLER_UNDEFINED_PROCESSING_ERROR;
|
|
Status = EFI_SUCCESS;
|
|
MultiConfigResp = NULL;
|
|
NameSpace = NULL;
|
|
DevicePath = NULL;
|
|
KeywordData = NULL;
|
|
ValueElement = NULL;
|
|
ConfigResp = NULL;
|
|
KeywordStartPos = NULL;
|
|
KeywordStringId = 0;
|
|
|
|
//
|
|
// Use temp string to avoid changing input string buffer.
|
|
//
|
|
TempString = AllocateCopyPool (StrSize (KeywordString), KeywordString);
|
|
ASSERT (TempString != NULL);
|
|
StringPtr = TempString;
|
|
|
|
while ((StringPtr != NULL) && (*StringPtr != L'\0')) {
|
|
//
|
|
// 1. Get NameSpace from NameSpaceId keyword.
|
|
//
|
|
Status = ExtractNameSpace (StringPtr, &NameSpace, &NextStringPtr);
|
|
if (EFI_ERROR (Status)) {
|
|
*ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING;
|
|
goto Done;
|
|
}
|
|
ASSERT (NameSpace != NULL);
|
|
//
|
|
// 1.1 Check whether the input namespace is valid.
|
|
//
|
|
if (AsciiStrnCmp(NameSpace, UEFI_CONFIG_LANG, AsciiStrLen (UEFI_CONFIG_LANG)) != 0) {
|
|
*ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING;
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto Done;
|
|
}
|
|
|
|
StringPtr = NextStringPtr;
|
|
|
|
//
|
|
// 2. Get possible Device Path info from KeywordString.
|
|
//
|
|
Status = ExtractDevicePath (StringPtr, (UINT8 **)&DevicePath, &NextStringPtr);
|
|
if (EFI_ERROR (Status)) {
|
|
*ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING;
|
|
goto Done;
|
|
}
|
|
StringPtr = NextStringPtr;
|
|
|
|
//
|
|
// 3. Extract keyword from the KeywordRequest string.
|
|
//
|
|
KeywordStartPos = StringPtr;
|
|
Status = ExtractKeyword(StringPtr, &KeywordData, &NextStringPtr);
|
|
if (EFI_ERROR (Status)) {
|
|
//
|
|
// Can't find Keyword base on the input device path info.
|
|
//
|
|
*ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING;
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto Done;
|
|
}
|
|
StringPtr = NextStringPtr;
|
|
|
|
//
|
|
// 4. Extract Value from the KeywordRequest string.
|
|
//
|
|
Status = ExtractValue (StringPtr, &ValueElement, &NextStringPtr);
|
|
if (EFI_ERROR (Status)) {
|
|
//
|
|
// Can't find Value base on the input device path info.
|
|
//
|
|
*ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING;
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto Done;
|
|
}
|
|
StringPtr = NextStringPtr;
|
|
|
|
//
|
|
// 5. Find ReadOnly filter.
|
|
//
|
|
if ((StringPtr != NULL) && StrnCmp (StringPtr, L"&ReadOnly", StrLen (L"&ReadOnly")) == 0) {
|
|
ReadOnly = TRUE;
|
|
StringPtr += StrLen (L"&ReadOnly");
|
|
} else {
|
|
ReadOnly = FALSE;
|
|
}
|
|
|
|
//
|
|
// 6. Get EFI_STRING_ID for the input keyword.
|
|
//
|
|
Status = GetStringIdFromDatabase (&DevicePath, &NameSpace, KeywordData, &RetVal, &KeywordStringId, &DataBaseRecord);
|
|
if (EFI_ERROR (Status)) {
|
|
*ProgressErr = RetVal;
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// 7. Construct the ConfigRequest string.
|
|
//
|
|
Status = ExtractConfigResp (DataBaseRecord, KeywordStringId, ValueElement, &OpCode, &ConfigResp);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// 8. Check the readonly flag.
|
|
//
|
|
if (ExtractReadOnlyFromOpCode (OpCode) != ReadOnly) {
|
|
*ProgressErr = KEYWORD_HANDLER_ACCESS_NOT_PERMITTED;
|
|
Status = EFI_ACCESS_DENIED;
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// 9. Merge to the MultiKeywordResp string.
|
|
//
|
|
Status = MergeToMultiKeywordResp(&MultiConfigResp, &ConfigResp);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// 10. Clean the temp buffer point.
|
|
//
|
|
FreePool (NameSpace);
|
|
FreePool (DevicePath);
|
|
FreePool (KeywordData);
|
|
FreePool (ValueElement);
|
|
NameSpace = NULL;
|
|
DevicePath = NULL;
|
|
KeywordData = NULL;
|
|
ValueElement = NULL;
|
|
if (ConfigResp != NULL) {
|
|
FreePool (ConfigResp);
|
|
ConfigResp = NULL;
|
|
}
|
|
KeywordStartPos = NULL;
|
|
}
|
|
|
|
//
|
|
// 11. Set value to driver.
|
|
//
|
|
Status = mPrivate.ConfigRouting.RouteConfig(
|
|
&mPrivate.ConfigRouting,
|
|
(EFI_STRING) MultiConfigResp,
|
|
&InternalProgress
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
Status = EFI_DEVICE_ERROR;
|
|
goto Done;
|
|
}
|
|
|
|
*ProgressErr = KEYWORD_HANDLER_NO_ERROR;
|
|
|
|
Done:
|
|
if (KeywordStartPos != NULL) {
|
|
*Progress = KeywordString + (KeywordStartPos - TempString);
|
|
} else {
|
|
*Progress = KeywordString + (StringPtr - TempString);
|
|
}
|
|
|
|
ASSERT (TempString != NULL);
|
|
FreePool (TempString);
|
|
if (NameSpace != NULL) {
|
|
FreePool (NameSpace);
|
|
}
|
|
if (DevicePath != NULL) {
|
|
FreePool (DevicePath);
|
|
}
|
|
if (KeywordData != NULL) {
|
|
FreePool (KeywordData);
|
|
}
|
|
if (ValueElement != NULL) {
|
|
FreePool (ValueElement);
|
|
}
|
|
if (ConfigResp != NULL) {
|
|
FreePool (ConfigResp);
|
|
}
|
|
if (MultiConfigResp != NULL && MultiConfigResp != ConfigResp) {
|
|
FreePool (MultiConfigResp);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
|
|
This function accepts a <MultiKeywordRequest> formatted string, finds the underlying
|
|
keyword owners, creates a <MultiConfigRequest> string from it and forwards it to the
|
|
EFI_HII_ROUTING_PROTOCOL.ExtractConfig function.
|
|
|
|
If there is an issue in resolving the contents of the KeywordString, then the function
|
|
returns an EFI_INVALID_PARAMETER and also set the Progress and ProgressErr with the
|
|
appropriate information about where the issue occurred and additional data about the
|
|
nature of the issue.
|
|
|
|
In the case when KeywordString is NULL, or contains multiple keywords, or when
|
|
EFI_NOT_FOUND is generated while processing the keyword elements, the Results string
|
|
contains values returned for all keywords processed prior to the keyword generating the
|
|
error but no values for the keyword with error or any following keywords.
|
|
|
|
|
|
@param This Pointer to the EFI_KEYWORD_HANDLER _PROTOCOL instance.
|
|
|
|
@param NameSpaceId A null-terminated string containing the platform configuration
|
|
language to search through in the system. If a NULL is passed
|
|
in, then it is assumed that any platform configuration language
|
|
with the prefix of "x-UEFI-" are searched.
|
|
|
|
@param KeywordString A null-terminated string in <MultiKeywordRequest> format. If a
|
|
NULL is passed in the KeywordString field, all of the known
|
|
keywords in the system for the NameSpaceId specified are
|
|
returned in the Results field.
|
|
|
|
@param Progress On return, points to a character in the KeywordString. Points
|
|
to the string's NULL terminator if the request was successful.
|
|
Points to the most recent '&' before the first failing string
|
|
element if the request was not successful.
|
|
|
|
@param ProgressErr If during the processing of the KeywordString there was a
|
|
failure, this parameter gives additional information about the
|
|
possible source of the problem. See the definitions in SetData()
|
|
for valid value definitions.
|
|
|
|
@param Results A null-terminated string in <MultiKeywordResp> format is returned
|
|
which has all the values filled in for the keywords in the
|
|
KeywordString. This is a callee-allocated field, and must be freed
|
|
by the caller after being used.
|
|
|
|
@retval EFI_SUCCESS The specified action was completed successfully.
|
|
|
|
@retval EFI_INVALID_PARAMETER One or more of the following are TRUE:
|
|
1.Progress, ProgressErr, or Resuts is NULL.
|
|
2.Parsing of the KeywordString resulted in an error. See
|
|
Progress and ProgressErr for more data.
|
|
|
|
|
|
@retval EFI_NOT_FOUND An element of the KeywordString was not found. See
|
|
ProgressErr for more data.
|
|
|
|
@retval EFI_NOT_FOUND The NamespaceId specified was not found. See ProgressErr
|
|
for more data.
|
|
|
|
@retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. See
|
|
ProgressErr for more data.
|
|
|
|
@retval EFI_ACCESS_DENIED The action violated system policy. See ProgressErr for
|
|
more data.
|
|
|
|
@retval EFI_DEVICE_ERROR An unexpected system error occurred. See ProgressErr
|
|
for more data.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
EfiConfigKeywordHandlerGetData (
|
|
IN EFI_CONFIG_KEYWORD_HANDLER_PROTOCOL *This,
|
|
IN CONST EFI_STRING NameSpaceId, OPTIONAL
|
|
IN CONST EFI_STRING KeywordString, OPTIONAL
|
|
OUT EFI_STRING *Progress,
|
|
OUT UINT32 *ProgressErr,
|
|
OUT EFI_STRING *Results
|
|
)
|
|
{
|
|
CHAR8 *NameSpace;
|
|
EFI_STATUS Status;
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
|
HII_DATABASE_RECORD *DataBaseRecord;
|
|
CHAR16 *StringPtr;
|
|
CHAR16 *NextStringPtr;
|
|
CHAR16 *KeywordData;
|
|
EFI_STRING_ID KeywordStringId;
|
|
UINT8 *OpCode;
|
|
CHAR16 *ConfigRequest;
|
|
CHAR16 *ValueElement;
|
|
UINT32 RetVal;
|
|
BOOLEAN ReadOnly;
|
|
CHAR16 *KeywordResp;
|
|
CHAR16 *MultiKeywordResp;
|
|
CHAR16 *TempString;
|
|
|
|
if (This == NULL || Progress == NULL || ProgressErr == NULL || Results == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
*ProgressErr = KEYWORD_HANDLER_UNDEFINED_PROCESSING_ERROR;
|
|
Status = EFI_SUCCESS;
|
|
DevicePath = NULL;
|
|
NameSpace = NULL;
|
|
KeywordData = NULL;
|
|
ConfigRequest= NULL;
|
|
StringPtr = KeywordString;
|
|
ReadOnly = FALSE;
|
|
MultiKeywordResp = NULL;
|
|
KeywordStringId = 0;
|
|
TempString = NULL;
|
|
|
|
//
|
|
// Use temp string to avoid changing input string buffer.
|
|
//
|
|
if (NameSpaceId != NULL) {
|
|
TempString = AllocateCopyPool (StrSize (NameSpaceId), NameSpaceId);
|
|
ASSERT (TempString != NULL);
|
|
}
|
|
//
|
|
// 1. Get NameSpace from NameSpaceId keyword.
|
|
//
|
|
Status = ExtractNameSpace (TempString, &NameSpace, NULL);
|
|
if (TempString != NULL) {
|
|
FreePool (TempString);
|
|
TempString = NULL;
|
|
}
|
|
if (EFI_ERROR (Status)) {
|
|
*ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING;
|
|
return Status;
|
|
}
|
|
//
|
|
// 1.1 Check whether the input namespace is valid.
|
|
//
|
|
if (NameSpace != NULL){
|
|
if (AsciiStrnCmp(NameSpace, UEFI_CONFIG_LANG, AsciiStrLen (UEFI_CONFIG_LANG)) != 0) {
|
|
*ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING;
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
if (KeywordString != NULL) {
|
|
//
|
|
// Use temp string to avoid changing input string buffer.
|
|
//
|
|
TempString = AllocateCopyPool (StrSize (KeywordString), KeywordString);
|
|
ASSERT (TempString != NULL);
|
|
StringPtr = TempString;
|
|
|
|
while (*StringPtr != L'\0') {
|
|
//
|
|
// 2. Get possible Device Path info from KeywordString.
|
|
//
|
|
Status = ExtractDevicePath (StringPtr, (UINT8 **)&DevicePath, &NextStringPtr);
|
|
if (EFI_ERROR (Status)) {
|
|
*ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING;
|
|
goto Done;
|
|
}
|
|
StringPtr = NextStringPtr;
|
|
|
|
|
|
//
|
|
// 3. Process Keyword section from the input keywordRequest string.
|
|
//
|
|
// 3.1 Extract keyword from the KeywordRequest string.
|
|
//
|
|
Status = ExtractKeyword(StringPtr, &KeywordData, &NextStringPtr);
|
|
if (EFI_ERROR (Status)) {
|
|
//
|
|
// Can't find Keyword base on the input device path info.
|
|
//
|
|
*ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING;
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// 3.2 Get EFI_STRING_ID for the input keyword.
|
|
//
|
|
Status = GetStringIdFromDatabase (&DevicePath, &NameSpace, KeywordData, &RetVal, &KeywordStringId, &DataBaseRecord);
|
|
if (EFI_ERROR (Status)) {
|
|
*ProgressErr = RetVal;
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// 3.3 Construct the ConfigRequest string.
|
|
//
|
|
Status = ExtractConfigRequest (DataBaseRecord, KeywordStringId, &OpCode, &ConfigRequest);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// 3.4 Extract Value for the input keyword.
|
|
//
|
|
Status = ExtractValueFromDriver(ConfigRequest, &ValueElement);
|
|
if (EFI_ERROR (Status)) {
|
|
if (Status != EFI_OUT_OF_RESOURCES) {
|
|
Status = EFI_DEVICE_ERROR;
|
|
}
|
|
goto Done;
|
|
}
|
|
StringPtr = NextStringPtr;
|
|
|
|
//
|
|
// 4. Process the possible filter section.
|
|
//
|
|
RetVal = ValidateFilter (OpCode, StringPtr, &NextStringPtr, &ReadOnly);
|
|
if (RetVal != KEYWORD_HANDLER_NO_ERROR) {
|
|
*ProgressErr = RetVal;
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto Done;
|
|
}
|
|
StringPtr = NextStringPtr;
|
|
|
|
|
|
//
|
|
// 5. Generate KeywordResp string.
|
|
//
|
|
Status = GenerateKeywordResp(NameSpace, DevicePath, KeywordData, ValueElement, ReadOnly, &KeywordResp);
|
|
if (Status != EFI_SUCCESS) {
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// 6. Merge to the MultiKeywordResp string.
|
|
//
|
|
Status = MergeToMultiKeywordResp(&MultiKeywordResp, &KeywordResp);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// 7. Update return value.
|
|
//
|
|
*Results = MultiKeywordResp;
|
|
|
|
//
|
|
// 8. Clean the temp buffer.
|
|
//
|
|
FreePool (DevicePath);
|
|
FreePool (KeywordData);
|
|
FreePool (ValueElement);
|
|
FreePool (ConfigRequest);
|
|
DevicePath = NULL;
|
|
KeywordData = NULL;
|
|
ValueElement = NULL;
|
|
ConfigRequest = NULL;
|
|
if (KeywordResp != NULL) {
|
|
FreePool (KeywordResp);
|
|
KeywordResp = NULL;
|
|
}
|
|
}
|
|
} else {
|
|
//
|
|
// Enumerate all keyword in the system.
|
|
//
|
|
Status = EnumerateAllKeywords(NameSpace, &MultiKeywordResp, ProgressErr);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Done;
|
|
}
|
|
*Results = MultiKeywordResp;
|
|
}
|
|
|
|
*ProgressErr = KEYWORD_HANDLER_NO_ERROR;
|
|
|
|
Done:
|
|
*Progress = KeywordString + (StringPtr - TempString);
|
|
|
|
if (TempString != NULL) {
|
|
FreePool (TempString);
|
|
}
|
|
if (NameSpace != NULL) {
|
|
FreePool (NameSpace);
|
|
}
|
|
if (DevicePath != NULL) {
|
|
FreePool (DevicePath);
|
|
}
|
|
if (KeywordData != NULL) {
|
|
FreePool (KeywordData);
|
|
}
|
|
|
|
return Status;
|
|
}
|