/** @file | |
Implementation of interfaces function for EFI_CONFIG_KEYWORD_HANDLER_PROTOCOL. | |
Copyright (c) 2015 - 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 "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 necessary 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; | |
UINTN NameSpaceSize; | |
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. | |
// | |
NameSpaceSize = StrLen (String) + 1; | |
*NameSpace = AllocatePool (NameSpaceSize); | |
if (*NameSpace == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
UnicodeStrToAsciiStrS (String, *NameSpace, NameSpaceSize); | |
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 section. | |
@retval EFI_SUCCESS Success to get the keyword string. | |
@retval EFI_INVALID_PARAMETER Parse 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 section. | |
@retval EFI_SUCCESS Success to get the keyword string. | |
@retval EFI_INVALID_PARAMETER Parse 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 section. | |
@retval EFI_SUCCESS Success to get the keyword string. | |
@retval EFI_INVALID_PARAMETER Parse 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 platform 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 question binary ifr data. | |
@param KeywordRequest KeywordRequestformat string. | |
@param NextString return the next string follow this keyword section. | |
@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 outputted 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; | |
UINTN KeywordValueSize; | |
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. | |
// | |
KeywordValueSize = StrLen (KeywordValue) + 1; | |
AsciiKeywordValue = AllocatePool (KeywordValueSize); | |
if (AsciiKeywordValue == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
UnicodeStrToAsciiStrS (KeywordValue, AsciiKeywordValue, KeywordValueSize); | |
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; | |
} | |
ASSERT (String != NULL); | |
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; | |
} | |
ASSERT (String != NULL); | |
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; | |
} | |
ASSERT (String != NULL); | |
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; | |
} | |
ASSERT (String != NULL); | |
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) { | |
StringSize = AsciiStrSize ((CHAR8 *) StringTextPtr); | |
*KeywordValue = AllocatePool (StringSize * sizeof (CHAR16)); | |
if (*KeywordValue == NULL) { | |
return 0; | |
} | |
AsciiStrToUnicodeStrS ((CHAR8 *) StringTextPtr, *KeywordValue, StringSize); | |
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) { | |
StringSize = AsciiStrSize ((CHAR8 *) StringTextPtr); | |
*KeywordValue = AllocatePool (StringSize * sizeof (CHAR16)); | |
if (*KeywordValue == NULL) { | |
return 0; | |
} | |
AsciiStrToUnicodeStrS ((CHAR8 *) StringTextPtr, *KeywordValue, StringSize); | |
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) { | |
StringSize = AsciiStrSize ((CHAR8 *) StringTextPtr); | |
*KeywordValue = AllocatePool (StringSize * sizeof (CHAR16)); | |
if (*KeywordValue == NULL) { | |
return 0; | |
} | |
AsciiStrToUnicodeStrS ((CHAR8 *) StringTextPtr, *KeywordValue, StringSize); | |
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) { | |
StringSize = AsciiStrSize ((CHAR8 *) StringTextPtr); | |
*KeywordValue = AllocatePool (StringSize * sizeof (CHAR16)); | |
if (*KeywordValue == NULL) { | |
return 0; | |
} | |
AsciiStrToUnicodeStrS ((CHAR8 *) StringTextPtr, *KeywordValue, StringSize); | |
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 successfully. | |
@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: | |
return (UINT16)((UINTN) ((EFI_IFR_PASSWORD *) OpCodeData)->MaxSize * sizeof (CHAR16)); | |
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 string 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 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 | |
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; | |
UINTN NameSize; | |
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) { | |
NameSize = AsciiStrSize (AsciiName); | |
Name = AllocateZeroPool (NameSize * sizeof (CHAR16)); | |
ASSERT (Name != NULL); | |
AsciiStrToUnicodeStrS (AsciiName, Name, NameSize); | |
} 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++) { | |
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, | |
MaxLen * sizeof (CHAR16) - ((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, | |
MaxLen * sizeof (CHAR16) - ((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 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; | |
} | |
} | |
} | |
/** | |
Generate 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; | |
UINTN NameSpaceLength; | |
ASSERT ((NameSpace != NULL) && (DevicePath != NULL) && (KeywordData != NULL) && (ValueStr != NULL) && (KeywordResp != NULL)); | |
// | |
// 1. Calculate the string length. | |
// | |
// | |
// 1.1 NameSpaceId size. | |
// 'NAMESPACE='<String> | |
// | |
NameSpaceLength = AsciiStrLen (NameSpace); | |
RespStrLen = 10 + NameSpaceLength; | |
UnicodeNameSpace = AllocatePool ((NameSpaceLength + 1) * sizeof (CHAR16)); | |
if (UnicodeNameSpace == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
AsciiStrToUnicodeStrS (NameSpace, UnicodeNameSpace, NameSpaceLength + 1); | |
// | |
// 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 section. | |
// '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 occurred. | |
// | |
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 name / value pair (or the beginning | |
of the string if the failure is in the first name / value | |
pair) 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 tag. | |
// | |
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) { | |
// | |
// Extracting readonly flag form opcode and extracting "READONLY" tag form KeywordString should have the same results. | |
// If not, the input KeywordString must be incorrect, return the error status to caller. | |
// | |
*ProgressErr = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED; | |
Status = EFI_INVALID_PARAMETER; | |
goto Done; | |
} | |
if (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 name / value | |
pair (or the beginning of the string if the failure is in the first | |
name / value pair) 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 Results 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; | |
} |