diff --git a/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigKeywordHandler.c b/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigKeywordHandler.c new file mode 100644 index 0000000000..6a71540448 --- /dev/null +++ b/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigKeywordHandler.c @@ -0,0 +1,3234 @@ +/** @file +Implementation of interfaces function for EFI_CONFIG_KEYWORD_HANDLER_PROTOCOL. + +Copyright (c) 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + + +#include "HiiDatabase.h" + +extern HII_DATABASE_PRIVATE_DATA mPrivate; + +/** + Convert the hex UNICODE %02x encoding of a UEFI device path to binary + from of . + + This is a internal function. + + @param String MultiKeywordRequest string. + @param DevicePathData Binary of a UEFI device path. + @param NextString string follow the possible PathHdr string. + + @retval EFI_INVALID_PARAMETER The device path is not valid or the incoming parameter is invalid. + @retval EFI_OUT_OF_RESOURCES Lake of resources to store neccesary structures. + @retval EFI_SUCCESS The device path is retrieved and translated to binary format. + The Input string not include PathHdr section. + +**/ +EFI_STATUS +ExtractDevicePath ( + IN EFI_STRING String, + OUT UINT8 **DevicePathData, + OUT EFI_STRING *NextString + ) +{ + UINTN Length; + EFI_STRING PathHdr; + UINT8 *DevicePathBuffer; + CHAR16 TemStr[2]; + UINTN Index; + UINT8 DigitUint8; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + + ASSERT (NextString != NULL && DevicePathData != NULL); + + // + // KeywordRequest == NULL case. + // + if (String == NULL) { + *DevicePathData = NULL; + *NextString = NULL; + return EFI_SUCCESS; + } + + // + // Skip '&' if exist. + // + if (*String == L'&') { + String ++; + } + + // + // Find the 'PATH=' of . + // + 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 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 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 format string. + @param NameSpace Return the name space string. + @param NextString Return the next string follow namespace. + + @retval EFI_SUCCESS Get the namespace string success. + @retval EFI_INVALID_PARAMETER The NameSpaceId string not follow spec definition. + +**/ +EFI_STATUS +ExtractNameSpace ( + IN EFI_STRING String, + OUT CHAR8 **NameSpace, + OUT EFI_STRING *NextString + ) +{ + CHAR16 *TmpPtr; + + ASSERT (NameSpace != NULL); + + TmpPtr = NULL; + + // + // Input NameSpaceId == NULL + // + if (String == NULL) { + *NameSpace = NULL; + if (NextString != NULL) { + *NextString = NULL; + } + return EFI_SUCCESS; + } + + // + // Skip '&' if exist. + // + if (*String == L'&') { + String++; + } + + if (StrnCmp (String, L"NAMESPACE=", StrLen (L"NAMESPACE=")) != 0) { + return EFI_INVALID_PARAMETER; + } + String += StrLen (L"NAMESPACE="); + + TmpPtr = StrStr (String, L"&"); + if (TmpPtr != NULL) { + *TmpPtr = 0; + } + if (NextString != NULL) { + *NextString = String + StrLen (String); + } + + // + // Input NameSpace is unicode string. The language in String package is ascii string. + // Here will convert the unicode string to ascii and save it. + // + *NameSpace = AllocatePool (StrLen (String) + 1); + if (*NameSpace == NULL) { + return EFI_OUT_OF_RESOURCES; + } + UnicodeStrToAsciiStr (String, *NameSpace); + + if (TmpPtr != NULL) { + *TmpPtr = L'&'; + } + + return EFI_SUCCESS; +} + +/** + Get Keyword from the input KeywordRequest string. + + This is a internal function. + + @param String KeywordRequestformat string. + @param Keyword return the extract keyword string. + @param NextString return the next string follow this keyword sectin. + + @retval EFI_SUCCESS Success to get the keyword string. + @retval EFI_INVALID_PARAMETER Parsr the input string return error. + +**/ +EFI_STATUS +ExtractKeyword ( + IN EFI_STRING String, + OUT EFI_STRING *Keyword, + OUT EFI_STRING *NextString + ) +{ + EFI_STRING TmpPtr; + + ASSERT ((Keyword != NULL) && (NextString != NULL)); + + TmpPtr = NULL; + + // + // KeywordRequest == NULL case. + // + if (String == NULL) { + *Keyword = NULL; + *NextString = NULL; + return EFI_SUCCESS; + } + + // + // Skip '&' if exist. + // + if (*String == L'&') { + String++; + } + + if (StrnCmp (String, L"KEYWORD=", StrLen (L"KEYWORD=")) != 0) { + return EFI_INVALID_PARAMETER; + } + + String += StrLen (L"KEYWORD="); + + TmpPtr = StrStr (String, L"&"); + if (TmpPtr != NULL) { + *TmpPtr = 0; + } + *NextString = String + StrLen (String); + + *Keyword = AllocateCopyPool (StrSize (String), String); + if (*Keyword == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + if (TmpPtr != NULL) { + *TmpPtr = L'&'; + } + + return EFI_SUCCESS; +} + +/** + Get value from the input KeywordRequest string. + + This is a internal function. + + @param String KeywordRequestformat string. + @param Value return the extract value string. + @param NextString return the next string follow this keyword sectin. + + @retval EFI_SUCCESS Success to get the keyword string. + @retval EFI_INVALID_PARAMETER Parsr the input string return error. + +**/ +EFI_STATUS +ExtractValue ( + IN EFI_STRING String, + OUT EFI_STRING *Value, + OUT EFI_STRING *NextString + ) +{ + EFI_STRING TmpPtr; + + ASSERT ((Value != NULL) && (NextString != NULL) && (String != NULL)); + + // + // Skip '&' if exist. + // + if (*String == L'&') { + String++; + } + + if (StrnCmp (String, L"VALUE=", StrLen (L"VALUE=")) != 0) { + return EFI_INVALID_PARAMETER; + } + + String += StrLen (L"VALUE="); + + TmpPtr = StrStr (String, L"&"); + if (TmpPtr != NULL) { + *TmpPtr = 0; + } + *NextString = String + StrLen (String); + + *Value = AllocateCopyPool (StrSize (String), String); + if (*Value == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + if (TmpPtr != NULL) { + *TmpPtr = L'&'; + } + + return EFI_SUCCESS; +} + +/** + Get filter from the input KeywordRequest string. + + This is a internal function. + + @param String KeywordRequestformat string. + @param FilterFlags return the filter condition. + @param NextString return the next string follow this keyword sectin. + + @retval EFI_SUCCESS Success to get the keyword string. + @retval EFI_INVALID_PARAMETER Parsr the input string return error. + +**/ +BOOLEAN +ExtractFilter ( + IN EFI_STRING String, + OUT UINT8 *FilterFlags, + OUT EFI_STRING *NextString + ) +{ + CHAR16 *PathPtr; + CHAR16 *KeywordPtr; + BOOLEAN RetVal; + + ASSERT ((FilterFlags != NULL) && (NextString != NULL)); + + // + // String end, no filter section. + // + if (String == NULL) { + *NextString = NULL; + return FALSE; + } + + *FilterFlags = 0; + RetVal = TRUE; + + // + // Skip '&' if exist. + // + if (*String == L'&') { + String++; + } + + if (StrnCmp (String, L"ReadOnly", StrLen (L"ReadOnly")) == 0) { + // + // Find ReadOnly filter. + // + *FilterFlags |= EFI_KEYWORD_FILTER_READONY; + String += StrLen (L"ReadOnly"); + } else if (StrnCmp (String, L"ReadWrite", StrLen (L"ReadWrite")) == 0) { + // + // Find ReadWrite filter. + // + *FilterFlags |= EFI_KEYWORD_FILTER_REAWRITE; + String += StrLen (L"ReadWrite"); + } else if (StrnCmp (String, L"Buffer", StrLen (L"Buffer")) == 0) { + // + // Find Buffer Filter. + // + *FilterFlags |= EFI_KEYWORD_FILTER_BUFFER; + String += StrLen (L"Buffer"); + } else if (StrnCmp (String, L"Numeric", StrLen (L"Numeric")) == 0) { + // + // Find Numeric Filter + // + String += StrLen (L"Numeric"); + if (*String != L':') { + *FilterFlags |= EFI_KEYWORD_FILTER_NUMERIC; + } else { + String++; + switch (*String) { + case L'1': + *FilterFlags |= EFI_KEYWORD_FILTER_NUMERIC_1; + break; + case L'2': + *FilterFlags |= EFI_KEYWORD_FILTER_NUMERIC_2; + break; + case L'4': + *FilterFlags |= EFI_KEYWORD_FILTER_NUMERIC_4; + break; + case L'8': + *FilterFlags |= EFI_KEYWORD_FILTER_NUMERIC_8; + break; + default: + ASSERT (FALSE); + break; + } + String++; + } + } else { + // + // Check whether other filter item defined by Platform. + // + if ((StrnCmp (String, L"&PATH", StrLen (L"&PATH")) == 0) || + (StrnCmp (String, L"&KEYWORD", StrLen (L"&KEYWORD")) == 0)) { + // + // New KeywordRequest start, no platform defined filter. + // + } else { + // + // Platform defined filter rule. + // Just skip platform defined filter rule, return success. + // + PathPtr = StrStr(String, L"&PATH"); + KeywordPtr = StrStr(String, L"&KEYWORD"); + if (PathPtr != NULL && KeywordPtr != NULL) { + // + // If both sections exist, return the first follow string. + // + String = KeywordPtr > PathPtr ? PathPtr : KeywordPtr; + } else if (PathPtr != NULL) { + // + // Should not exist PathPtr != NULL && KeywordPtr == NULL case. + // + ASSERT (FALSE); + } else if (KeywordPtr != NULL) { + // + // Just to the next keyword section. + // + String = KeywordPtr; + } else { + // + // Only has paltform defined filter section, just skip it. + // + String += StrLen (String); + } + } + RetVal = FALSE; + } + + *NextString = String; + + return RetVal; +} + +/** + Extract Readonly flag from opcode. + + This is a internal function. + + @param OpCodeData Input opcode for this question. + + @retval TRUE This question is readonly. + @retval FALSE This question is not readonly. + +**/ +BOOLEAN +ExtractReadOnlyFromOpCode ( + IN UINT8 *OpCodeData + ) +{ + EFI_IFR_QUESTION_HEADER *QuestionHdr; + + ASSERT (OpCodeData != NULL); + + QuestionHdr = (EFI_IFR_QUESTION_HEADER *) (OpCodeData + sizeof (EFI_IFR_OP_HEADER)); + + return (QuestionHdr->Flags & EFI_IFR_FLAG_READ_ONLY) != 0; +} + +/** + Create a circuit to check the filter section. + + This is a internal function. + + @param OpCodeData The questin binary ifr data. + @param KeywordRequest KeywordRequestformat string. + @param NextString return the next string follow this keyword sectin. + @param ReadOnly Return whether this question is read only. + + @retval KEYWORD_HANDLER_NO_ERROR Success validate. + @retval KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED Validate fail. + +**/ +UINT32 +ValidateFilter ( + IN UINT8 *OpCodeData, + IN CHAR16 *KeywordRequest, + OUT CHAR16 **NextString, + OUT BOOLEAN *ReadOnly + ) +{ + CHAR16 *NextFilter; + CHAR16 *StringPtr; + UINT8 FilterFlags; + EFI_IFR_QUESTION_HEADER *QuestionHdr; + EFI_IFR_OP_HEADER *OpCodeHdr; + UINT8 Flags; + UINT32 RetVal; + + RetVal = KEYWORD_HANDLER_NO_ERROR; + StringPtr = KeywordRequest; + + OpCodeHdr = (EFI_IFR_OP_HEADER *) OpCodeData; + QuestionHdr = (EFI_IFR_QUESTION_HEADER *) (OpCodeData + sizeof (EFI_IFR_OP_HEADER)); + if (OpCodeHdr->OpCode == EFI_IFR_ONE_OF_OP || OpCodeHdr->OpCode == EFI_IFR_NUMERIC_OP) { + Flags = *(OpCodeData + sizeof (EFI_IFR_OP_HEADER) + sizeof (EFI_IFR_QUESTION_HEADER)); + } else { + Flags = 0; + } + + // + // Get ReadOnly flag from Question. + // + *ReadOnly = ExtractReadOnlyFromOpCode(OpCodeData); + + while (ExtractFilter (StringPtr, &FilterFlags, &NextFilter)) { + switch (FilterFlags) { + case EFI_KEYWORD_FILTER_READONY: + if ((QuestionHdr->Flags & EFI_IFR_FLAG_READ_ONLY) == 0) { + RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED; + goto Done; + } + break; + + case EFI_KEYWORD_FILTER_REAWRITE: + if ((QuestionHdr->Flags & EFI_IFR_FLAG_READ_ONLY) != 0) { + RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED; + goto Done; + } + break; + + case EFI_KEYWORD_FILTER_BUFFER: + // + // Only these three opcode use numeric value type. + // + if (OpCodeHdr->OpCode == EFI_IFR_ONE_OF_OP || OpCodeHdr->OpCode == EFI_IFR_NUMERIC_OP || OpCodeHdr->OpCode == EFI_IFR_CHECKBOX_OP) { + RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED; + goto Done; + } + break; + + case EFI_KEYWORD_FILTER_NUMERIC: + if (OpCodeHdr->OpCode != EFI_IFR_ONE_OF_OP && OpCodeHdr->OpCode != EFI_IFR_NUMERIC_OP && OpCodeHdr->OpCode != EFI_IFR_CHECKBOX_OP) { + RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED; + goto Done; + } + break; + + case EFI_KEYWORD_FILTER_NUMERIC_1: + case EFI_KEYWORD_FILTER_NUMERIC_2: + case EFI_KEYWORD_FILTER_NUMERIC_4: + case EFI_KEYWORD_FILTER_NUMERIC_8: + if (OpCodeHdr->OpCode != EFI_IFR_ONE_OF_OP && OpCodeHdr->OpCode != EFI_IFR_NUMERIC_OP && OpCodeHdr->OpCode != EFI_IFR_CHECKBOX_OP) { + RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED; + goto Done; + } + + // + // For numeric and oneof, it has flags field to specify the detail numeric type. + // + if (OpCodeHdr->OpCode == EFI_IFR_ONE_OF_OP || OpCodeHdr->OpCode == EFI_IFR_NUMERIC_OP) { + switch (Flags & EFI_IFR_NUMERIC_SIZE) { + case EFI_IFR_NUMERIC_SIZE_1: + if (FilterFlags != EFI_KEYWORD_FILTER_NUMERIC_1) { + RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED; + goto Done; + } + break; + + case EFI_IFR_NUMERIC_SIZE_2: + if (FilterFlags != EFI_KEYWORD_FILTER_NUMERIC_2) { + RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED; + goto Done; + } + break; + + case EFI_IFR_NUMERIC_SIZE_4: + if (FilterFlags != EFI_KEYWORD_FILTER_NUMERIC_4) { + RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED; + goto Done; + } + break; + + case EFI_IFR_NUMERIC_SIZE_8: + if (FilterFlags != EFI_KEYWORD_FILTER_NUMERIC_8) { + RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED; + goto Done; + } + break; + + default: + ASSERT (FALSE); + break; + } + } + break; + + default: + ASSERT (FALSE); + break; + } + + // + // Jump to the next filter. + // + StringPtr = NextFilter; + } + +Done: + // + // The current filter which is processing. + // + *NextString = StringPtr; + + return RetVal; +} + +/** + Get HII_DATABASE_RECORD from the input device path info. + + This is a internal function. + + @param DevicePath UEFI device path protocol. + + @retval Internal data base record. + +**/ +HII_DATABASE_RECORD * +GetRecordFromDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + LIST_ENTRY *Link; + UINT8 *DevicePathPkg; + UINT8 *CurrentDevicePath; + UINTN DevicePathSize; + HII_DATABASE_RECORD *TempDatabase; + + ASSERT (DevicePath != NULL); + + for (Link = mPrivate.DatabaseList.ForwardLink; Link != &mPrivate.DatabaseList; Link = Link->ForwardLink) { + TempDatabase = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE); + DevicePathPkg = TempDatabase->PackageList->DevicePathPkg; + if (DevicePathPkg != NULL) { + CurrentDevicePath = DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER); + DevicePathSize = GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) CurrentDevicePath); + if ((CompareMem (DevicePath, CurrentDevicePath, DevicePathSize) == 0)) { + return TempDatabase; + } + } + } + + return NULL; +} + +/** + Calculate the size of StringSrc and output it. Also copy string text from src + to dest. + + This is a internal function. + + @param StringSrc Points to current null-terminated string. + @param BufferSize Length of the buffer. + @param StringDest Buffer to store the string text. + + @retval EFI_SUCCESS The string text was outputed successfully. + @retval EFI_OUT_OF_RESOURCES Out of resource. + +**/ +EFI_STATUS +GetUnicodeStringTextAndSize ( + IN UINT8 *StringSrc, + OUT UINTN *BufferSize, + OUT EFI_STRING *StringDest + ) +{ + UINTN StringSize; + UINT8 *StringPtr; + + ASSERT (StringSrc != NULL && BufferSize != NULL && StringDest != NULL); + + StringSize = sizeof (CHAR16); + StringPtr = StringSrc; + while (ReadUnaligned16 ((UINT16 *) StringPtr) != 0) { + StringSize += sizeof (CHAR16); + StringPtr += sizeof (CHAR16); + } + + *StringDest = AllocatePool (StringSize); + if (*StringDest == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + CopyMem (*StringDest, StringSrc, StringSize); + + *BufferSize = StringSize; + return EFI_SUCCESS; +} + +/** + Find the string id for the input keyword. + + @param StringPackage Hii string package instance. + @param KeywordValue Input keyword value. + @param StringId The string's id, which is unique within PackageList. + + + @retval EFI_SUCCESS The string text and font is retrieved + successfully. + @retval EFI_NOT_FOUND The specified text or font info can not be found + out. + @retval EFI_OUT_OF_RESOURCES The system is out of resources to accomplish the + task. +**/ +EFI_STATUS +GetStringIdFromString ( + IN HII_STRING_PACKAGE_INSTANCE *StringPackage, + IN CHAR16 *KeywordValue, + OUT EFI_STRING_ID *StringId + ) +{ + UINT8 *BlockHdr; + EFI_STRING_ID CurrentStringId; + UINTN BlockSize; + UINTN Index; + UINT8 *StringTextPtr; + UINTN Offset; + UINT16 StringCount; + UINT16 SkipCount; + UINT8 Length8; + EFI_HII_SIBT_EXT2_BLOCK Ext2; + UINT32 Length32; + UINTN StringSize; + CHAR16 *String; + CHAR8 *AsciiKeywordValue; + EFI_STATUS Status; + + ASSERT (StringPackage != NULL && KeywordValue != NULL && StringId != NULL); + ASSERT (StringPackage->Signature == HII_STRING_PACKAGE_SIGNATURE); + + CurrentStringId = 1; + Status = EFI_SUCCESS; + String = NULL; + BlockHdr = StringPackage->StringBlock; + BlockSize = 0; + Offset = 0; + + // + // Make a ascii keyword value for later use. + // + AsciiKeywordValue = AllocatePool (StrLen (KeywordValue) + 1); + if (AsciiKeywordValue == NULL) { + return EFI_OUT_OF_RESOURCES; + } + UnicodeStrToAsciiStr(KeywordValue, AsciiKeywordValue); + + while (*BlockHdr != EFI_HII_SIBT_END) { + switch (*BlockHdr) { + case EFI_HII_SIBT_STRING_SCSU: + Offset = sizeof (EFI_HII_STRING_BLOCK); + StringTextPtr = BlockHdr + Offset; + BlockSize += Offset + AsciiStrSize ((CHAR8 *) StringTextPtr); + if (AsciiStrCmp(AsciiKeywordValue, 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, 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, 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, StringTextPtr) == 0) { + *StringId = CurrentStringId; + goto Done; + } + StringTextPtr = StringTextPtr + AsciiStrSize ((CHAR8 *) StringTextPtr); + CurrentStringId++; + } + break; + + case EFI_HII_SIBT_STRING_UCS2: + Offset = sizeof (EFI_HII_STRING_BLOCK); + StringTextPtr = BlockHdr + Offset; + // + // Use StringSize to store the size of the specified string, including the NULL + // terminator. + // + Status = GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String); + if (EFI_ERROR (Status)) { + goto Done; + } + + if (StrCmp(KeywordValue, String) == 0) { + *StringId = CurrentStringId; + goto Done; + } + BlockSize += Offset + StringSize; + CurrentStringId++; + break; + + case EFI_HII_SIBT_STRING_UCS2_FONT: + Offset = sizeof (EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK) - sizeof (CHAR16); + StringTextPtr = BlockHdr + Offset; + // + // Use StringSize to store the size of the specified string, including the NULL + // terminator. + // + Status = GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String); + if (EFI_ERROR (Status)) { + goto Done; + } + + if (StrCmp(KeywordValue, String) == 0) { + *StringId = CurrentStringId; + goto Done; + } + BlockSize += Offset + StringSize; + CurrentStringId++; + break; + + case EFI_HII_SIBT_STRINGS_UCS2: + Offset = sizeof (EFI_HII_SIBT_STRINGS_UCS2_BLOCK) - sizeof (CHAR16); + StringTextPtr = BlockHdr + Offset; + BlockSize += Offset; + CopyMem (&StringCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16)); + for (Index = 0; Index < StringCount; Index++) { + Status = GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String); + if (EFI_ERROR (Status)) { + goto Done; + } + + BlockSize += StringSize; + if (StrCmp(KeywordValue, String) == 0) { + *StringId = CurrentStringId; + goto Done; + } + StringTextPtr = StringTextPtr + StringSize; + CurrentStringId++; + } + break; + + case EFI_HII_SIBT_STRINGS_UCS2_FONT: + Offset = sizeof (EFI_HII_SIBT_STRINGS_UCS2_FONT_BLOCK) - sizeof (CHAR16); + StringTextPtr = BlockHdr + Offset; + BlockSize += Offset; + CopyMem ( + &StringCount, + (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)), + sizeof (UINT16) + ); + for (Index = 0; Index < StringCount; Index++) { + Status = GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String); + if (EFI_ERROR (Status)) { + goto Done; + } + + BlockSize += StringSize; + if (StrCmp(KeywordValue, String) == 0) { + *StringId = CurrentStringId; + goto Done; + } + StringTextPtr = StringTextPtr + StringSize; + CurrentStringId++; + } + break; + + case EFI_HII_SIBT_DUPLICATE: + BlockSize += sizeof (EFI_HII_SIBT_DUPLICATE_BLOCK); + CurrentStringId++; + break; + + case EFI_HII_SIBT_SKIP1: + SkipCount = (UINT16) (*(UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK))); + CurrentStringId = (UINT16) (CurrentStringId + SkipCount); + BlockSize += sizeof (EFI_HII_SIBT_SKIP1_BLOCK); + break; + + case EFI_HII_SIBT_SKIP2: + CopyMem (&SkipCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16)); + CurrentStringId = (UINT16) (CurrentStringId + SkipCount); + BlockSize += sizeof (EFI_HII_SIBT_SKIP2_BLOCK); + break; + + case EFI_HII_SIBT_EXT1: + CopyMem ( + &Length8, + (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)), + sizeof (UINT8) + ); + BlockSize += Length8; + break; + + case EFI_HII_SIBT_EXT2: + CopyMem (&Ext2, BlockHdr, sizeof (EFI_HII_SIBT_EXT2_BLOCK)); + BlockSize += Ext2.Length; + break; + + case EFI_HII_SIBT_EXT4: + CopyMem ( + &Length32, + (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)), + sizeof (UINT32) + ); + + BlockSize += Length32; + break; + + default: + break; + } + + if (String != NULL) { + FreePool (String); + String = NULL; + } + + BlockHdr = StringPackage->StringBlock + BlockSize; + } + + Status = EFI_NOT_FOUND; + +Done: + if (AsciiKeywordValue != NULL) { + FreePool (AsciiKeywordValue); + } + if (String != NULL) { + FreePool (String); + } + return Status; +} + +/** + Find the next valid string id for the input string id. + + @param StringPackage Hii string package instance. + @param StringId The current string id which is already got. + 1 means just begin to get the string id. + @param KeywordValue Return the string for the next string id. + + + @retval EFI_STRING_ID Not 0 means a valid stringid found. + 0 means not found a valid string id. +**/ +EFI_STRING_ID +GetNextStringId ( + IN HII_STRING_PACKAGE_INSTANCE *StringPackage, + IN EFI_STRING_ID StringId, + OUT EFI_STRING *KeywordValue + ) +{ + UINT8 *BlockHdr; + EFI_STRING_ID CurrentStringId; + UINTN BlockSize; + UINTN Index; + UINT8 *StringTextPtr; + UINTN Offset; + UINT16 StringCount; + UINT16 SkipCount; + UINT8 Length8; + EFI_HII_SIBT_EXT2_BLOCK Ext2; + UINT32 Length32; + BOOLEAN FindString; + UINTN StringSize; + CHAR16 *String; + + ASSERT (StringPackage != NULL); + ASSERT (StringPackage->Signature == HII_STRING_PACKAGE_SIGNATURE); + + CurrentStringId = 1; + FindString = FALSE; + String = NULL; + + // + // Parse the string blocks to get the string text and font. + // + BlockHdr = StringPackage->StringBlock; + BlockSize = 0; + Offset = 0; + while (*BlockHdr != EFI_HII_SIBT_END) { + switch (*BlockHdr) { + case EFI_HII_SIBT_STRING_SCSU: + Offset = sizeof (EFI_HII_STRING_BLOCK); + StringTextPtr = BlockHdr + Offset; + + if (FindString) { + *KeywordValue = AllocatePool (AsciiStrSize ((CHAR8 *) StringTextPtr) * sizeof (CHAR16)); + if (*KeywordValue == NULL) { + return 0; + } + AsciiStrToUnicodeStr(StringTextPtr, *KeywordValue); + return CurrentStringId; + } else if (CurrentStringId == StringId) { + FindString = TRUE; + } + + BlockSize += Offset + AsciiStrSize ((CHAR8 *) StringTextPtr); + CurrentStringId++; + break; + + case EFI_HII_SIBT_STRING_SCSU_FONT: + Offset = sizeof (EFI_HII_SIBT_STRING_SCSU_FONT_BLOCK) - sizeof (UINT8); + StringTextPtr = BlockHdr + Offset; + + if (FindString) { + *KeywordValue = AllocatePool (AsciiStrSize ((CHAR8 *) StringTextPtr) * sizeof (CHAR16)); + if (*KeywordValue == NULL) { + return 0; + } + AsciiStrToUnicodeStr(StringTextPtr, *KeywordValue); + return CurrentStringId; + } else if (CurrentStringId == StringId) { + FindString = TRUE; + } + + BlockSize += Offset + AsciiStrSize ((CHAR8 *) StringTextPtr); + CurrentStringId++; + break; + + case EFI_HII_SIBT_STRINGS_SCSU: + CopyMem (&StringCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16)); + StringTextPtr = (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_SIBT_STRINGS_SCSU_BLOCK) - sizeof (UINT8)); + BlockSize += StringTextPtr - BlockHdr; + + for (Index = 0; Index < StringCount; Index++) { + if (FindString) { + *KeywordValue = AllocatePool (AsciiStrSize ((CHAR8 *) StringTextPtr) * sizeof (CHAR16)); + if (*KeywordValue == NULL) { + return 0; + } + AsciiStrToUnicodeStr(StringTextPtr, *KeywordValue); + return CurrentStringId; + } else if (CurrentStringId == StringId) { + FindString = TRUE; + } + + BlockSize += AsciiStrSize ((CHAR8 *) StringTextPtr); + StringTextPtr = StringTextPtr + AsciiStrSize ((CHAR8 *) StringTextPtr); + CurrentStringId++; + } + break; + + case EFI_HII_SIBT_STRINGS_SCSU_FONT: + CopyMem ( + &StringCount, + (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)), + sizeof (UINT16) + ); + StringTextPtr = (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_SIBT_STRINGS_SCSU_FONT_BLOCK) - sizeof (UINT8)); + BlockSize += StringTextPtr - BlockHdr; + + for (Index = 0; Index < StringCount; Index++) { + if (FindString) { + *KeywordValue = AllocatePool (AsciiStrSize ((CHAR8 *) StringTextPtr) * sizeof (CHAR16)); + if (*KeywordValue == NULL) { + return 0; + } + AsciiStrToUnicodeStr(StringTextPtr, *KeywordValue); + return CurrentStringId; + } else if (CurrentStringId == StringId) { + FindString = TRUE; + } + + BlockSize += AsciiStrSize ((CHAR8 *) StringTextPtr); + StringTextPtr = StringTextPtr + AsciiStrSize ((CHAR8 *) StringTextPtr); + CurrentStringId++; + } + break; + + case EFI_HII_SIBT_STRING_UCS2: + Offset = sizeof (EFI_HII_STRING_BLOCK); + StringTextPtr = BlockHdr + Offset; + // + // Use StringSize to store the size of the specified string, including the NULL + // terminator. + // + GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String); + if (FindString && (String != NULL) && (*String != L'\0')) { + // + // String protocol use this type for the string id which has value for other package. + // It will allocate an empty string block for this string id. so here we also check + // *String != L'\0' to prohibit this case. + // + *KeywordValue = String; + return CurrentStringId; + } else if (CurrentStringId == StringId) { + FindString = TRUE; + } + + BlockSize += Offset + StringSize; + CurrentStringId++; + break; + + case EFI_HII_SIBT_STRING_UCS2_FONT: + Offset = sizeof (EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK) - sizeof (CHAR16); + StringTextPtr = BlockHdr + Offset; + // + // Use StringSize to store the size of the specified string, including the NULL + // terminator. + // + GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String); + if (FindString) { + *KeywordValue = String; + return CurrentStringId; + } else if (CurrentStringId == StringId) { + FindString = TRUE; + } + + BlockSize += Offset + StringSize; + CurrentStringId++; + break; + + case EFI_HII_SIBT_STRINGS_UCS2: + Offset = sizeof (EFI_HII_SIBT_STRINGS_UCS2_BLOCK) - sizeof (CHAR16); + StringTextPtr = BlockHdr + Offset; + BlockSize += Offset; + CopyMem (&StringCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16)); + for (Index = 0; Index < StringCount; Index++) { + GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String); + + if (FindString) { + *KeywordValue = String; + return CurrentStringId; + } else if (CurrentStringId == StringId) { + FindString = TRUE; + } + + BlockSize += StringSize; + StringTextPtr = StringTextPtr + StringSize; + CurrentStringId++; + } + break; + + case EFI_HII_SIBT_STRINGS_UCS2_FONT: + Offset = sizeof (EFI_HII_SIBT_STRINGS_UCS2_FONT_BLOCK) - sizeof (CHAR16); + StringTextPtr = BlockHdr + Offset; + BlockSize += Offset; + CopyMem ( + &StringCount, + (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)), + sizeof (UINT16) + ); + for (Index = 0; Index < StringCount; Index++) { + GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String); + if (FindString) { + *KeywordValue = String; + return CurrentStringId; + } else if (CurrentStringId == StringId) { + FindString = TRUE; + } + + BlockSize += StringSize; + StringTextPtr = StringTextPtr + StringSize; + CurrentStringId++; + } + break; + + case EFI_HII_SIBT_DUPLICATE: + BlockSize += sizeof (EFI_HII_SIBT_DUPLICATE_BLOCK); + CurrentStringId++; + break; + + case EFI_HII_SIBT_SKIP1: + SkipCount = (UINT16) (*(UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK))); + CurrentStringId = (UINT16) (CurrentStringId + SkipCount); + BlockSize += sizeof (EFI_HII_SIBT_SKIP1_BLOCK); + break; + + case EFI_HII_SIBT_SKIP2: + CopyMem (&SkipCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16)); + CurrentStringId = (UINT16) (CurrentStringId + SkipCount); + BlockSize += sizeof (EFI_HII_SIBT_SKIP2_BLOCK); + break; + + case EFI_HII_SIBT_EXT1: + CopyMem ( + &Length8, + (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)), + sizeof (UINT8) + ); + BlockSize += Length8; + break; + + case EFI_HII_SIBT_EXT2: + CopyMem (&Ext2, BlockHdr, sizeof (EFI_HII_SIBT_EXT2_BLOCK)); + BlockSize += Ext2.Length; + break; + + case EFI_HII_SIBT_EXT4: + CopyMem ( + &Length32, + (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)), + sizeof (UINT32) + ); + + BlockSize += Length32; + break; + + default: + break; + } + + if (String != NULL) { + FreePool (String); + String = NULL; + } + + BlockHdr = StringPackage->StringBlock + BlockSize; + } + + return 0; +} + +/** + Get string package from the input NameSpace string. + + This is a internal function. + + @param DatabaseRecord HII_DATABASE_RECORD format string. + @param NameSpace NameSpace format string. + @param KeywordValue Keyword value. + @param StringId String Id for this keyword. + + @retval KEYWORD_HANDLER_NO_ERROR Get String id succes. + @retval KEYWORD_HANDLER_KEYWORD_NOT_FOUND Not found the string id in the string package. + @retval KEYWORD_HANDLER_NAMESPACE_ID_NOT_FOUND Not found the string package for this namespace. + @retval KEYWORD_HANDLER_UNDEFINED_PROCESSING_ERROR Out of resource error. + +**/ +UINT32 +GetStringIdFromRecord ( + IN HII_DATABASE_RECORD *DatabaseRecord, + IN CHAR8 **NameSpace, + IN CHAR16 *KeywordValue, + OUT EFI_STRING_ID *StringId + ) +{ + LIST_ENTRY *Link; + HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageListNode; + HII_STRING_PACKAGE_INSTANCE *StringPackage; + EFI_STATUS Status; + CHAR8 *Name; + + ASSERT (DatabaseRecord != NULL && NameSpace != NULL && KeywordValue != NULL); + + PackageListNode = DatabaseRecord->PackageList; + + 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 KEYWORD_HANDLER_NAMESPACE_ID_NOT_FOUND; +} + +/** + 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; + break; + + default: + ASSERT (FALSE); + return 0; + } + + case EFI_IFR_CHECKBOX_OP: + return (UINT16) sizeof (BOOLEAN); + + case EFI_IFR_PASSWORD_OP: + case EFI_IFR_STRING_OP: + return (UINT16)((UINTN) ((EFI_IFR_STRING *) OpCodeData)->MaxSize * sizeof (CHAR16)); + + case EFI_IFR_DATE_OP: + return (UINT16) sizeof (EFI_HII_DATE); + + case EFI_IFR_TIME_OP: + return (UINT16) sizeof (EFI_HII_TIME); + + default: + ASSERT (FALSE); + return 0; + } +} + +/** + Converts all hex dtring characters in range ['A'..'F'] to ['a'..'f'] for + hex digits that appear between a '=' and a '&' in a config string. + + If ConfigString is NULL, then ASSERT(). + + @param[in] ConfigString Pointer to a Null-terminated Unicode string. + + @return Pointer to the Null-terminated Unicode result string. + +**/ +EFI_STRING +EFIAPI +InternalLowerConfigString ( + IN EFI_STRING ConfigString + ) +{ + EFI_STRING String; + BOOLEAN Lower; + + ASSERT (ConfigString != NULL); + + // + // Convert all hex digits in range [A-F] in the configuration header to [a-f] + // + for (String = ConfigString, Lower = FALSE; *String != L'\0'; String++) { + if (*String == L'=') { + Lower = TRUE; + } else if (*String == L'&') { + Lower = FALSE; + } else if (Lower && *String >= L'A' && *String <= L'F') { + *String = (CHAR16) (*String - L'A' + L'a'); + } + } + + return ConfigString; +} + +/** + Allocates and returns a Null-terminated Unicode string. + + The format of a is as follows: + + GUID=32&NAME=NameLength&PATH=DevicePathSize + + @param[in] OpCodeData The opcode for the storage. + @param[in] DriverHandle The driver handle which supports a Device Path Protocol + that is the routing information PATH. Each byte of + the Device Path associated with DriverHandle is converted + to a 2 Unicode character hexidecimal string. + + @retval NULL DriverHandle does not support the Device Path Protocol. + @retval Other A pointer to the Null-terminate Unicode string + +**/ +EFI_STRING +ConstructConfigHdr ( + IN UINT8 *OpCodeData, + IN EFI_HANDLE DriverHandle + ) +{ + UINTN NameLength; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + UINTN DevicePathSize; + CHAR16 *String; + CHAR16 *ReturnString; + UINTN Index; + UINT8 *Buffer; + CHAR16 *Name; + CHAR8 *AsciiName; + EFI_GUID *Guid; + + 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 = ((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 = ((EFI_IFR_VARSTORE_EFI *) OpCodeData)->Name; + break; + + default: + ASSERT (FALSE); + Guid = NULL; + AsciiName = NULL; + break; + } + + if (AsciiName != NULL) { + Name = AllocateZeroPool (AsciiStrSize (AsciiName) * 2); + ASSERT (Name != NULL); + AsciiStrToUnicodeStr(AsciiName, Name); + } else { + Name = NULL; + } + + // + // Compute the length of Name in Unicode characters. + // If Name is NULL, then the length is 0. + // + NameLength = 0; + if (Name != NULL) { + NameLength = StrLen (Name); + } + + DevicePath = NULL; + DevicePathSize = 0; + // + // Retrieve DevicePath Protocol associated with DriverHandle + // + if (DriverHandle != NULL) { + DevicePath = DevicePathFromHandle (DriverHandle); + if (DevicePath == NULL) { + return NULL; + } + // + // Compute the size of the device path in bytes + // + DevicePathSize = GetDevicePathSize (DevicePath); + } + + // + // GUID=32&NAME=NameLength&PATH=DevicePathSize + // | 5 | sizeof (EFI_GUID) * 2 | 6 | NameStrLen*4 | 6 | DevicePathSize * 2 | 1 | + // + String = AllocateZeroPool ((5 + sizeof (EFI_GUID) * 2 + 6 + NameLength * 4 + 6 + DevicePathSize * 2 + 1) * sizeof (CHAR16)); + if (String == NULL) { + return NULL; + } + + // + // Start with L"GUID=" + // + ReturnString = StrCpy (String, L"GUID="); + String += StrLen (String); + + if (Guid != NULL) { + // + // Append Guid converted to 32 + // + for (Index = 0, Buffer = (UINT8 *)Guid; Index < sizeof (EFI_GUID); Index++) { + String += UnicodeValueToString (String, PREFIX_ZERO | RADIX_HEX, *(Buffer++), 2); + } + } + + // + // Append L"&NAME=" + // + StrCpy (String, L"&NAME="); + String += StrLen (String); + + if (Name != NULL) { + // + // Append Name converted to NameLength + // + for (; *Name != L'\0'; Name++) { + String += UnicodeValueToString (String, PREFIX_ZERO | RADIX_HEX, *Name, 4); + } + } + + // + // Append L"&PATH=" + // + StrCpy (String, L"&PATH="); + String += StrLen (String); + + // + // Append the device path associated with DriverHandle converted to DevicePathSize + // + for (Index = 0, Buffer = (UINT8 *)DevicePath; Index < DevicePathSize; Index++) { + String += UnicodeValueToString (String, PREFIX_ZERO | RADIX_HEX, *(Buffer++), 2); + } + + // + // Null terminate the Unicode string + // + *String = L'\0'; + + // + // Convert all hex digits in range [A-F] in the configuration header to [a-f] + // + return InternalLowerConfigString (ReturnString); +} + +/** + Generate the Config request element for one question. + + @param Name The name info for one question. + @param Offset The offset info for one question. + @param Width The width info for one question. + + @return Pointer to the Null-terminated Unicode request element string. + +**/ +EFI_STRING +ConstructRequestElement ( + IN CHAR16 *Name, + IN UINT16 Offset, + IN UINT16 Width + ) +{ + CHAR16 *StringPtr; + UINTN Length; + + if (Name != NULL) { + // + // Add length for each Name + // + // ::= Name + \0 + // StrLen(Name) | 1 + // + Length = StrLen (Name) + 1; + } else { + // + // Add length for each Offset/Width pair + // + // ::= OFFSET=1234&WIDTH=1234 + \0 + // | 7 | 4 | 7 | 4 | 1 + // + Length = (7 + 4 + 7 + 4 + 1); + } + + // + // Allocate buffer for the entire + // + 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 Length; + 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); + + Length = (StrLen (ConfigHdr) + 1 + StrLen(RequestElement) + 1) * sizeof (CHAR16); + *ConfigRequest = AllocatePool (Length); + if (*ConfigRequest == NULL) { + FreePool (ConfigHdr); + FreePool (RequestElement); + return EFI_OUT_OF_RESOURCES; + } + StringPtr = *ConfigRequest; + + StrCpy (StringPtr, ConfigHdr); + StringPtr += StrLen (StringPtr); + + *StringPtr = L'&'; + StringPtr++; + + StrCpy (StringPtr, RequestElement); + StringPtr += StrLen (StringPtr); + *StringPtr = L'\0'; + + 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 Length; + 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); + + Length = (StrLen (ConfigHdr) + 1 + StrLen(RequestElement) + 1 + StrLen (L"VALUE=") + StrLen(ValueElement) + 1) * sizeof (CHAR16); + *ConfigResp = AllocatePool (Length); + if (*ConfigResp == NULL) { + FreePool (ConfigHdr); + FreePool (RequestElement); + return EFI_OUT_OF_RESOURCES; + } + StringPtr = *ConfigResp; + + StrCpy (StringPtr, ConfigHdr); + StringPtr += StrLen (StringPtr); + + *StringPtr = L'&'; + StringPtr++; + + StrCpy (StringPtr, RequestElement); + StringPtr += StrLen (StringPtr); + + *StringPtr = L'&'; + StringPtr++; + + StrCpy (StringPtr, L"VALUE="); + StringPtr += StrLen (StringPtr); + + StrCpy (StringPtr, ValueElement); + StringPtr += StrLen (StringPtr); + *StringPtr = L'\0'; + + FreePool (ConfigHdr); + FreePool (RequestElement); + + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + +/** + Get the Value section from the Hii driver. + + This is a internal function. + + @param ConfigRequest The input ConfigRequest string. + @param ValueElement The respond Value section from the hii driver. + + @retval Misc value The error status return from ExtractConfig function. + @retval EFI_OUT_OF_RESOURCES The memory can't be allocated + @retval EFI_SUCCESS Get the value section success. + +**/ +EFI_STATUS +ExtractValueFromDriver ( + IN CHAR16 *ConfigRequest, + OUT CHAR16 **ValueElement + ) +{ + EFI_STATUS Status; + EFI_STRING Result; + EFI_STRING Progress; + CHAR16 *StringPtr; + CHAR16 *StringEnd; + + ASSERT ((ConfigRequest != NULL) && (ValueElement != NULL)); + + Status = mPrivate.ConfigRouting.ExtractConfig ( + &mPrivate.ConfigRouting, + (EFI_STRING) ConfigRequest, + &Progress, + &Result + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Find Value Section and return it. + // + StringPtr = StrStr (Result, L"&VALUE="); + ASSERT (StringPtr != NULL); + StringEnd = StrStr (StringPtr + 1, L"&"); + if (StringEnd != NULL) { + *StringEnd = L'\0'; + } + + *ValueElement = AllocateCopyPool (StrSize (StringPtr), StringPtr); + if (*ValueElement == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + if (StringEnd != NULL) { + *StringEnd = L'&'; + } + FreePool (Result); + + return EFI_SUCCESS; +} + +/** + Get EFI_STRING_ID info from the input device path, namespace and keyword. + + This is a internal function. + + @param DevicePath Input device path info. + @param NameSpace NameSpace format string. + @param KeywordData Keyword used to get string id. + @param ProgressErr Return extra error type. + @param KeywordStringId Return EFI_STRING_ID. + @param DataBaseRecord DataBase record data for this driver. + + @retval EFI_INVALID_PARAMETER Can't find the database record base on the input device path or namespace. + @retval EFI_NOT_FOUND Can't find the EFI_STRING_ID for the keyword. + @retval EFI_SUCCESS Find the EFI_STRING_ID. + +**/ +EFI_STATUS +GetStringIdFromDatabase ( + IN EFI_DEVICE_PATH_PROTOCOL **DevicePath, + IN CHAR8 **NameSpace, + IN CHAR16 *KeywordData, + OUT UINT32 *ProgressErr, + OUT EFI_STRING_ID *KeywordStringId, + OUT HII_DATABASE_RECORD **DataBaseRecord + ) +{ + HII_DATABASE_RECORD *Record; + LIST_ENTRY *Link; + BOOLEAN FindNameSpace; + EFI_DEVICE_PATH_PROTOCOL *DestDevicePath; + UINT8 *DevicePathPkg; + UINTN DevicePathSize; + + ASSERT ((NameSpace != NULL) && (KeywordData != NULL) && (ProgressErr != NULL) && (KeywordStringId != NULL) && (DataBaseRecord != NULL)); + + FindNameSpace = FALSE; + + if (*DevicePath != NULL) { + // + // Get DataBaseRecord from device path protocol. + // + Record = GetRecordFromDevicePath(*DevicePath); + if (Record == NULL) { + // + // Can't find the DatabaseRecord base on the input device path info. + // NEED TO CONFIRM the return ProgressErr. + // + *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING; + return EFI_INVALID_PARAMETER; + } + + // + // Get string id from the record. + // + *ProgressErr = GetStringIdFromRecord (Record, NameSpace, KeywordData, KeywordStringId); + switch (*ProgressErr) { + case KEYWORD_HANDLER_NO_ERROR: + *DataBaseRecord = Record; + return EFI_SUCCESS; + + case KEYWORD_HANDLER_NAMESPACE_ID_NOT_FOUND: + return EFI_INVALID_PARAMETER; + + default: + ASSERT (*ProgressErr == KEYWORD_HANDLER_KEYWORD_NOT_FOUND); + return EFI_NOT_FOUND; + } + } else { + // + // Find driver which matches the routing data. + // + for (Link = mPrivate.DatabaseList.ForwardLink; Link != &mPrivate.DatabaseList; Link = Link->ForwardLink) { + Record = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE); + + *ProgressErr = GetStringIdFromRecord (Record, NameSpace, KeywordData, KeywordStringId); + if (*ProgressErr == KEYWORD_HANDLER_NO_ERROR) { + *DataBaseRecord = Record; + + if ((DevicePathPkg = Record->PackageList->DevicePathPkg) != NULL) { + DestDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) (DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER)); + DevicePathSize = GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) DestDevicePath); + *DevicePath = AllocateCopyPool (DevicePathSize, DestDevicePath); + if (*DevicePath == NULL) { + return EFI_OUT_OF_RESOURCES; + } + } else { + // + // Need to verify this ASSERT. + // + ASSERT (FALSE); + } + + return EFI_SUCCESS; + } else if (*ProgressErr == KEYWORD_HANDLER_UNDEFINED_PROCESSING_ERROR) { + return EFI_OUT_OF_RESOURCES; + } else if (*ProgressErr == KEYWORD_HANDLER_KEYWORD_NOT_FOUND) { + FindNameSpace = TRUE; + } + } + + // + // When PathHdr not input, if ever find the namespace, will return KEYWORD_HANDLER_KEYWORD_NOT_FOUND. + // This is a bit more progress than KEYWORD_HANDLER_NAMESPACE_ID_NOT_FOUND. + // + if (FindNameSpace) { + return EFI_NOT_FOUND; + } else { + return EFI_INVALID_PARAMETER; + } + } +} + +/** + Genereate the KeywordResp String. + + ::= '&''&VALUE='['&READONLY'] + + @param NameSpace NameSpace format string. + @param DevicePath Input device path info. + @param KeywordData Keyword used to get string id. + @param ValueStr The value section for the keyword. + @param ReadOnly Whether this value is readonly. + @param KeywordResp Return the point to the KeywordResp string. + + @retval EFI_OUT_OF_RESOURCES The memory can't be allocated. + @retval EFI_SUCCESS Generate the KeywordResp string. + +**/ +EFI_STATUS +GenerateKeywordResp ( + IN CHAR8 *NameSpace, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN EFI_STRING KeywordData, + IN EFI_STRING ValueStr, + IN BOOLEAN ReadOnly, + OUT EFI_STRING *KeywordResp + ) +{ + UINTN RespStrLen; + CHAR16 *RespStr; + CHAR16 *PathHdr; + CHAR16 *UnicodeNameSpace; + + ASSERT ((NameSpace != NULL) && (DevicePath != NULL) && (KeywordData != NULL) && (ValueStr != NULL) && (KeywordResp != NULL)); + + // + // 1. Calculate the string length. + // + // + // 1.1 NameSpaceId size. + // 'NAMESPACE=' + // + RespStrLen = 10 + AsciiStrLen (NameSpace); + UnicodeNameSpace = AllocatePool ((AsciiStrLen (NameSpace) + 1) * sizeof (CHAR16)); + if (UnicodeNameSpace == NULL) { + return EFI_OUT_OF_RESOURCES; + } + AsciiStrToUnicodeStr(NameSpace, UnicodeNameSpace); + + // + // 1.2 PathHdr size. + // PATH='&' + // Attention: The output include the '&' at the end. + // + GenerateSubStr ( + L"&PATH=", + GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) DevicePath), + (VOID *) DevicePath, + 1, + &PathHdr + ); + RespStrLen += StrLen (PathHdr); + + // + // 1.3 Keyword setion. + // 'KEYWORD='[':'(1/4)] + // + RespStrLen += 8 + StrLen (KeywordData); + + // + // 1.4 Value section. + // ValueStr = '&VALUE=' + // + RespStrLen += StrLen (ValueStr); + + // + // 1.5 ReadOnly Section. + // '&READONLY' + // + if (ReadOnly) { + RespStrLen += 9; + } + + // + // 2. Allocate the buffer and create the KeywordResp string. + // + *KeywordResp = AllocatePool ((RespStrLen + 1) * sizeof (CHAR16)); + if (*KeywordResp == NULL) { + if (UnicodeNameSpace != NULL) { + FreePool (UnicodeNameSpace); + } + + return EFI_OUT_OF_RESOURCES; + } + RespStr = *KeywordResp; + + // + // 2.1 Copy NameSpaceId section. + // + StrCpy (RespStr, L"NAMESPACE="); + RespStr += StrLen (RespStr); + StrCpy (RespStr, UnicodeNameSpace); + RespStr += StrLen (RespStr); + + // + // 2.2 Copy PathHdr section. + // + StrCpy (RespStr, PathHdr); + RespStr += StrLen (RespStr); + + // + // 2.3 Copy Keyword section. + // + StrCpy (RespStr, L"KEYWORD="); + RespStr += StrLen (RespStr); + StrCpy (RespStr, KeywordData); + RespStr += StrLen (RespStr); + + // + // 2.4 Copy the Value section. + // + StrCpy (RespStr, ValueStr); + RespStr += StrLen (RespStr); + + // + // 2.5 Copy ReadOnly section if exist. + // + if (ReadOnly) { + StrCpy (RespStr, L"&READONLY"); + RespStr += StrLen (RespStr); + } + + // + // 2.6 Add the end. + // + *RespStr = L'\0'; + + 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; + + StringPtr += StrLen (StringPtr); + + *StringPtr = L'&'; + StringPtr++; + + StrCpy (StringPtr, *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. + + @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 + ) +{ + LIST_ENTRY *Link; + LIST_ENTRY *StringLink; + UINT8 *DevicePathPkg; + UINT8 *DevicePath; + HII_DATABASE_RECORD *DataBaseRecord; + UINTN DevicePathSize; + HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageListNode; + HII_STRING_PACKAGE_INSTANCE *StringPackage; + CHAR8 *LocalNameSpace; + EFI_STRING_ID NextStringId; + EFI_STATUS Status; + CHAR8 *OpCode; + CHAR16 *ConfigRequest; + CHAR16 *ValueElement; + CHAR16 *KeywordResp; + CHAR16 *MultiKeywordResp; + CHAR16 *KeywordData; + BOOLEAN ReadOnly; + + DataBaseRecord = NULL; + DevicePathSize = 0; + Status = EFI_SUCCESS; + MultiKeywordResp = NULL; + DevicePath = NULL; + LocalNameSpace = NULL; + ConfigRequest = NULL; + ValueElement = NULL; + KeywordResp = NULL; + + 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); + DevicePathSize = GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) DevicePath); + } + 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) { + // + // Keep the NameSpace string. + // + LocalNameSpace = AllocateCopyPool (AsciiStrSize (StringPackage->StringPkgHdr->Language), StringPackage->StringPkgHdr->Language); + if (LocalNameSpace == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // 1 means just begin the enumerate the valid string ids. + // StringId == 1 is always used to save the language for this string package. + // Any valid string start from 2. so here initial it to 1. + // + NextStringId = 1; + + // + // Enumerate all valid stringid in the package. + // + while ((NextStringId = GetNextStringId (StringPackage, NextStringId, &KeywordData)) != 0) { + // + // 3.3 Construct the ConfigRequest string. + // + Status = ExtractConfigRequest (DataBaseRecord, NextStringId, &OpCode, &ConfigRequest); + if (EFI_ERROR (Status)) { + // + // If can't generate ConfigRequest for this question, skip it and start the next. + // + goto Error; + } + + // + // 3.4 Extract Value for the input keyword. + // + Status = ExtractValueFromDriver(ConfigRequest, &ValueElement); + if (EFI_ERROR (Status)) { + if (Status != EFI_OUT_OF_RESOURCES) { + // + // If can't generate ConfigRequest for this question, skip it and start the next. + // + goto Error; + } + // + // If EFI_OUT_OF_RESOURCES error occur, no need to continue. + // + goto Done; + } + + // + // Extract readonly flag from opcode. + // + ReadOnly = ExtractReadOnlyFromOpCode(OpCode); + + // + // 5. Generate KeywordResp string. + // + ASSERT (DevicePath != NULL); + Status = GenerateKeywordResp(LocalNameSpace, (EFI_DEVICE_PATH_PROTOCOL *)DevicePath, KeywordData, ValueElement, ReadOnly, &KeywordResp); + if (Status != EFI_SUCCESS) { + // + // If EFI_OUT_OF_RESOURCES error occur, no need to continue. + // + goto Done; + } + + // + // 6. Merge to the MultiKeywordResp string. + // + Status = MergeToMultiKeywordResp(&MultiKeywordResp, &KeywordResp); + if (EFI_ERROR (Status)) { + goto Done; + } +Error: + // + // Clean the temp buffer to later use again. + // + if (ConfigRequest != NULL) { + FreePool (ConfigRequest); + ConfigRequest = NULL; + } + if (ValueElement != NULL) { + FreePool (ValueElement); + ValueElement = NULL; + } + if (KeywordResp != NULL) { + FreePool (KeywordResp); + KeywordResp = NULL; + } + } + + if (LocalNameSpace != NULL) { + FreePool (LocalNameSpace); + LocalNameSpace = NULL; + } + } + } + } + + // + // return the already get MultiKeywordString even error occured. + // + if (MultiKeywordResp == NULL) { + Status = EFI_NOT_FOUND; + } 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 formatted string, finds the associated + keyword owners, creates a 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 format. + + @param Progress On return, points to a character in the KeywordString. + Points to the string's NULL terminator if the request + was successful. Points to the most recent '&' before + the first failing string element if the request was + not successful. + + @param ProgressErr If during the processing of the KeywordString there was + a failure, this parameter gives additional information + about the possible source of the problem. The various + errors are defined in "Related Definitions" below. + + + @retval EFI_SUCCESS The specified action was completed successfully. + + @retval EFI_INVALID_PARAMETER One or more of the following are TRUE: + 1. KeywordString is NULL. + 2. Parsing of the KeywordString resulted in an + error. See Progress and ProgressErr for more data. + + @retval EFI_NOT_FOUND An element of the KeywordString was not found. + See ProgressErr for more data. + + @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. + See ProgressErr for more data. + + @retval EFI_ACCESS_DENIED The action violated system policy. See ProgressErr + for more data. + + @retval EFI_DEVICE_ERROR An unexpected system error occurred. See ProgressErr + for more data. + +**/ +EFI_STATUS +EFIAPI +EfiConfigKeywordHandlerSetData ( + IN EFI_CONFIG_KEYWORD_HANDLER_PROTOCOL *This, + IN CONST EFI_STRING KeywordString, + OUT EFI_STRING *Progress, + OUT UINT32 *ProgressErr + ) +{ + CHAR8 *NameSpace; + EFI_STATUS Status; + CHAR16 *StringPtr; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + CHAR16 *NextStringPtr; + CHAR16 *KeywordData; + EFI_STRING_ID KeywordStringId; + UINT32 RetVal; + HII_DATABASE_RECORD *DataBaseRecord; + UINT8 *OpCode; + CHAR16 *ConfigResp; + CHAR16 *MultiConfigResp; + CHAR16 *ValueElement; + BOOLEAN ReadOnly; + EFI_STRING InternalProgress; + + if (This == NULL || Progress == NULL || ProgressErr == NULL || KeywordString == NULL) { + return EFI_INVALID_PARAMETER; + } + + *Progress = KeywordString; + *ProgressErr = KEYWORD_HANDLER_UNDEFINED_PROCESSING_ERROR; + Status = EFI_SUCCESS; + StringPtr = KeywordString; + MultiConfigResp = NULL; + NameSpace = NULL; + DevicePath = NULL; + KeywordData = NULL; + ValueElement = NULL; + ConfigResp = NULL; + KeywordStringId = 0; + + 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; + return Status; + } + 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. + // + Status = ExtractKeyword(StringPtr, &KeywordData, &NextStringPtr); + if (EFI_ERROR (Status)) { + // + // Can't find Keyword base on the input device path info. + // + *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING; + Status = EFI_INVALID_PARAMETER; + goto Done; + } + StringPtr = NextStringPtr; + + // + // 4. Extract Value from the KeywordRequest string. + // + Status = ExtractValue (StringPtr, &ValueElement, &NextStringPtr); + if (EFI_ERROR (Status)) { + // + // Can't find Value base on the input device path info. + // + *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING; + Status = EFI_INVALID_PARAMETER; + goto Done; + } + StringPtr = NextStringPtr; + + // + // 5. Find ReadOnly filter. + // + if ((StringPtr != NULL) && StrnCmp (StringPtr, L"&ReadOnly", StrLen (L"&ReadOnly")) == 0) { + ReadOnly = TRUE; + StringPtr += StrLen (L"&ReadOnly"); + } else { + ReadOnly = FALSE; + } + + // + // 6. Get EFI_STRING_ID for the input keyword. + // + Status = GetStringIdFromDatabase (&DevicePath, &NameSpace, KeywordData, &RetVal, &KeywordStringId, &DataBaseRecord); + if (EFI_ERROR (Status)) { + *ProgressErr = RetVal; + goto Done; + } + + // + // 7. Construct the ConfigRequest string. + // + Status = ExtractConfigResp (DataBaseRecord, KeywordStringId, ValueElement, &OpCode, &ConfigResp); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // 8. Check the readonly flag. + // + if (ExtractReadOnlyFromOpCode (OpCode) != ReadOnly) { + *ProgressErr = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED; + Status = EFI_INVALID_PARAMETER; + 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; + } + } + + // + // 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 (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); + } + *Progress = StringPtr; + return Status; +} + +/** + + This function accepts a formatted string, finds the underlying + keyword owners, creates a 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 format. If a + NULL is passed in the KeywordString field, all of the known + keywords in the system for the NameSpaceId specified are + returned in the Results field. + + @param Progress On return, points to a character in the KeywordString. Points + to the string's NULL terminator if the request was successful. + Points to the most recent '&' before the first failing string + element if the request was not successful. + + @param ProgressErr If during the processing of the KeywordString there was a + failure, this parameter gives additional information about the + possible source of the problem. See the definitions in SetData() + for valid value definitions. + + @param Results A null-terminated string in format is returned + which has all the values filled in for the keywords in the + KeywordString. This is a callee-allocated field, and must be freed + by the caller after being used. + + @retval EFI_SUCCESS The specified action was completed successfully. + + @retval EFI_INVALID_PARAMETER One or more of the following are TRUE: + 1.Progress, ProgressErr, or Resuts is NULL. + 2.Parsing of the KeywordString resulted in an error. See + Progress and ProgressErr for more data. + + + @retval EFI_NOT_FOUND An element of the KeywordString was not found. See + ProgressErr for more data. + + @retval EFI_NOT_FOUND The NamespaceId specified was not found. See ProgressErr + for more data. + + @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. See + ProgressErr for more data. + + @retval EFI_ACCESS_DENIED The action violated system policy. See ProgressErr for + more data. + + @retval EFI_DEVICE_ERROR An unexpected system error occurred. See ProgressErr + for more data. + +**/ +EFI_STATUS +EFIAPI +EfiConfigKeywordHandlerGetData ( + IN EFI_CONFIG_KEYWORD_HANDLER_PROTOCOL *This, + IN CONST EFI_STRING NameSpaceId, OPTIONAL + IN CONST EFI_STRING KeywordString, OPTIONAL + OUT EFI_STRING *Progress, + OUT UINT32 *ProgressErr, + OUT EFI_STRING *Results + ) +{ + CHAR8 *NameSpace; + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + HII_DATABASE_RECORD *DataBaseRecord; + CHAR16 *StringPtr; + CHAR16 *NextStringPtr; + CHAR16 *KeywordData; + EFI_STRING_ID KeywordStringId; + UINT8 *OpCode; + CHAR16 *ConfigRequest; + CHAR16 *ValueElement; + UINT32 RetVal; + BOOLEAN ReadOnly; + CHAR16 *KeywordResp; + CHAR16 *MultiKeywordResp; + + 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; + + // + // 1. Get NameSpace from NameSpaceId keyword. + // + Status = ExtractNameSpace (NameSpaceId, &NameSpace, NULL); + if (EFI_ERROR (Status)) { + *ProgressErr = KEYWORD_HANDLER_NAMESPACE_ID_NOT_FOUND; + return Status; + } + + if (KeywordString != NULL) { + StringPtr = KeywordString; + + 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); + if (EFI_ERROR (Status)) { + goto Done; + } + *Results = MultiKeywordResp; + } + + *ProgressErr = KEYWORD_HANDLER_NO_ERROR; + +Done: + if (NameSpace != NULL) { + FreePool (NameSpace); + } + if (DevicePath != NULL) { + FreePool (DevicePath); + } + if (KeywordData != NULL) { + FreePool (KeywordData); + } + *Progress = StringPtr; + return Status; +} diff --git a/MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabase.h b/MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabase.h index 32e48275b0..bb0090aaa6 100644 --- a/MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabase.h +++ b/MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabase.h @@ -1,7 +1,7 @@ /** @file Private structures definitions in HiiDatabase. -Copyright (c) 2007 - 2011, Intel Corporation. All rights reserved.
+Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -24,6 +24,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include #include +#include #include #include @@ -108,6 +109,19 @@ typedef struct { #define EFI_HII_VARSTORE_EFI_VARIABLE 2 #define EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER 3 +// +// Keyword handler protocol filter type. +// +#define EFI_KEYWORD_FILTER_READONY 0x01 +#define EFI_KEYWORD_FILTER_REAWRITE 0x02 +#define EFI_KEYWORD_FILTER_BUFFER 0x10 +#define EFI_KEYWORD_FILTER_NUMERIC 0x20 +#define EFI_KEYWORD_FILTER_NUMERIC_1 0x30 +#define EFI_KEYWORD_FILTER_NUMERIC_2 0x40 +#define EFI_KEYWORD_FILTER_NUMERIC_4 0x50 +#define EFI_KEYWORD_FILTER_NUMERIC_8 0x60 + + #define HII_FORMSET_STORAGE_SIGNATURE SIGNATURE_32 ('H', 'S', 'T', 'G') typedef struct { UINTN Signature; @@ -288,6 +302,7 @@ typedef struct _HII_DATABASE_PRIVATE_DATA { EFI_HII_STRING_PROTOCOL HiiString; EFI_HII_DATABASE_PROTOCOL HiiDatabase; EFI_HII_CONFIG_ROUTING_PROTOCOL ConfigRouting; + EFI_CONFIG_KEYWORD_HANDLER_PROTOCOL ConfigKeywordHandler; LIST_ENTRY HiiHandleList; INTN HiiHandleCount; LIST_ENTRY FontInfoList; // global font info list @@ -331,10 +346,48 @@ typedef struct _HII_DATABASE_PRIVATE_DATA { HII_DATABASE_PRIVATE_DATA_SIGNATURE \ ) +#define CONFIG_KEYWORD_HANDLER_DATABASE_PRIVATE_DATA_FROM_THIS(a) \ + CR (a, \ + HII_DATABASE_PRIVATE_DATA, \ + ConfigKeywordHandler, \ + HII_DATABASE_PRIVATE_DATA_SIGNATURE \ + ) + // // Internal function prototypes. // +/** + Generate a sub string then output it. + + This is a internal function. + + @param String A constant string which is the prefix of the to be + generated string, e.g. GUID= + + @param BufferLen The length of the Buffer in bytes. + + @param Buffer Points to a buffer which will be converted to be the + content of the generated string. + + @param Flag If 1, the buffer contains data for the value of GUID or PATH stored in + UINT8 *; if 2, the buffer contains unicode string for the value of NAME; + if 3, the buffer contains other data. + + @param SubStr Points to the output string. It's caller's + responsibility to free this buffer. + + +**/ +VOID +GenerateSubStr ( + IN CONST EFI_STRING String, + IN UINTN BufferLen, + IN VOID *Buffer, + IN UINT8 Flag, + OUT EFI_STRING *SubStr + ); + /** This function checks whether a handle is a valid EFI_HII_HANDLE. @@ -1776,6 +1829,151 @@ HiiGetAltCfg ( OUT EFI_STRING *AltCfgResp ); +/** + + This function accepts a formatted string, finds the associated + keyword owners, creates a 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 format. + + @param Progress On return, points to a character in the KeywordString. + Points to the string's NULL terminator if the request + was successful. Points to the most recent '&' before + the first failing string element if the request was + not successful. + + @param ProgressErr If during the processing of the KeywordString there was + a failure, this parameter gives additional information + about the possible source of the problem. The various + errors are defined in "Related Definitions" below. + + + @retval EFI_SUCCESS The specified action was completed successfully. + + @retval EFI_INVALID_PARAMETER One or more of the following are TRUE: + 1. KeywordString is NULL. + 2. Parsing of the KeywordString resulted in an + error. See Progress and ProgressErr for more data. + + @retval EFI_NOT_FOUND An element of the KeywordString was not found. + See ProgressErr for more data. + + @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. + See ProgressErr for more data. + + @retval EFI_ACCESS_DENIED The action violated system policy. See ProgressErr + for more data. + + @retval EFI_DEVICE_ERROR An unexpected system error occurred. See ProgressErr + for more data. + +**/ +EFI_STATUS +EFIAPI +EfiConfigKeywordHandlerSetData ( + IN EFI_CONFIG_KEYWORD_HANDLER_PROTOCOL *This, + IN CONST EFI_STRING KeywordString, + OUT EFI_STRING *Progress, + OUT UINT32 *ProgressErr + ); + +/** + + This function accepts a formatted string, finds the underlying + keyword owners, creates a 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 format. If a + NULL is passed in the KeywordString field, all of the known + keywords in the system for the NameSpaceId specified are + returned in the Results field. + + @param Progress On return, points to a character in the KeywordString. Points + to the string's NULL terminator if the request was successful. + Points to the most recent '&' before the first failing string + element if the request was not successful. + + @param ProgressErr If during the processing of the KeywordString there was a + failure, this parameter gives additional information about the + possible source of the problem. See the definitions in SetData() + for valid value definitions. + + @param Results A null-terminated string in format is returned + which has all the values filled in for the keywords in the + KeywordString. This is a callee-allocated field, and must be freed + by the caller after being used. + + @retval EFI_SUCCESS The specified action was completed successfully. + + @retval EFI_INVALID_PARAMETER One or more of the following are TRUE: + 1.Progress, ProgressErr, or Resuts is NULL. + 2.Parsing of the KeywordString resulted in an error. See + Progress and ProgressErr for more data. + + + @retval EFI_NOT_FOUND An element of the KeywordString was not found. See + ProgressErr for more data. + + @retval EFI_NOT_FOUND The NamespaceId specified was not found. See ProgressErr + for more data. + + @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. See + ProgressErr for more data. + + @retval EFI_ACCESS_DENIED The action violated system policy. See ProgressErr for + more data. + + @retval EFI_DEVICE_ERROR An unexpected system error occurred. See ProgressErr + for more data. + +**/ +EFI_STATUS +EFIAPI +EfiConfigKeywordHandlerGetData ( + IN EFI_CONFIG_KEYWORD_HANDLER_PROTOCOL *This, + IN CONST EFI_STRING NameSpaceId, OPTIONAL + IN CONST EFI_STRING KeywordString, OPTIONAL + OUT EFI_STRING *Progress, + OUT UINT32 *ProgressErr, + OUT EFI_STRING *Results + ); /** Compare whether two names of languages are identical. @@ -1794,6 +1992,29 @@ HiiCompareLanguage ( ) ; +/** + Retrieves a pointer to the a Null-terminated ASCII string containing the list + of languages that an HII handle in the HII Database supports. The returned + string is allocated using AllocatePool(). The caller is responsible for freeing + the returned string using FreePool(). The format of the returned string follows + the language format assumed the HII Database. + + If HiiHandle is NULL, then ASSERT(). + + @param[in] HiiHandle A handle that was previously registered in the HII Database. + + @retval NULL HiiHandle is not registered in the HII database + @retval NULL There are not enough resources available to retrieve the suported + languages. + @retval NULL The list of suported languages could not be retrieved. + @retval Other A pointer to the Null-terminated ASCII string of supported languages. + +**/ +CHAR8 * +GetSupportedLanguages ( + IN EFI_HII_HANDLE HiiHandle + ); + // // Global variables // diff --git a/MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf b/MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf index d5dbdcae5a..7892503b47 100644 --- a/MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf +++ b/MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf @@ -4,7 +4,7 @@ # This driver produces all required HII serivces that includes HiiDataBase, HiiString, # HiiFont, HiiConfigRouting. To support UEFI HII, this driver is required. # -# Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.
+# Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.
# # This program and the accompanying materials # are licensed and made available under the terms and conditions of the BSD License @@ -40,6 +40,7 @@ String.c Database.c Font.c + ConfigKeywordHandler.c [Packages] MdePkg/MdePkg.dec @@ -67,6 +68,7 @@ gEfiHiiDatabaseProtocolGuid ## PRODUCES gEfiHiiFontProtocolGuid ## PRODUCES gEfiHiiConfigAccessProtocolGuid ## SOMETIMES_CONSUMES + gEfiConfigKeywordHandlerProtocolGuid ## PRODUCES [FeaturePcd] gEfiMdeModulePkgTokenSpaceGuid.PcdSupportHiiImageProtocol ## CONSUMES diff --git a/MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseEntry.c b/MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseEntry.c index ae75f8ccbf..6448c97256 100644 --- a/MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseEntry.c +++ b/MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseEntry.c @@ -2,7 +2,7 @@ This file contains the entry code to the HII database, which is defined by UEFI 2.1 specification. -Copyright (c) 2007 - 2008, Intel Corporation. All rights reserved.
+Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -72,6 +72,10 @@ HII_DATABASE_PRIVATE_DATA mPrivate = { HiiConfigToBlock, HiiGetAltCfg }, + { + EfiConfigKeywordHandlerSetData, + EfiConfigKeywordHandlerGetData + }, { (LIST_ENTRY *) NULL, (LIST_ENTRY *) NULL @@ -153,6 +157,7 @@ InitializeHiiDatabase ( ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiHiiImageProtocolGuid); ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiHiiStringProtocolGuid); ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiHiiConfigRoutingProtocolGuid); + ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiConfigKeywordHandlerProtocolGuid); InitializeListHead (&mPrivate.DatabaseList); InitializeListHead (&mPrivate.DatabaseNotifyList); @@ -185,6 +190,8 @@ InitializeHiiDatabase ( &mPrivate.HiiDatabase, &gEfiHiiConfigRoutingProtocolGuid, &mPrivate.ConfigRouting, + &gEfiConfigKeywordHandlerProtocolGuid, + &mPrivate.ConfigKeywordHandler, NULL );