summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigKeywordHandler.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigKeywordHandler.c')
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigKeywordHandler.c3329
1 files changed, 3329 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigKeywordHandler.c b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigKeywordHandler.c
new file mode 100644
index 00000000..9e131ff6
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigKeywordHandler.c
@@ -0,0 +1,3329 @@
+/** @file
+Implementation of interfaces function for EFI_CONFIG_KEYWORD_HANDLER_PROTOCOL.
+
+Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#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 = ReallocatePool (
+ StrSize (*MultiKeywordResp),
+ MultiKeywordRespLen,
+ *MultiKeywordResp
+ );
+ if (StringPtr == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ *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;
+}