From af1a266670d040d2f4083ff309d732d648afba2a Mon Sep 17 00:00:00 2001 From: Angelos Mouzakitis Date: Tue, 10 Oct 2023 14:33:42 +0000 Subject: Add submodule dependency files Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec --- .../HiiDatabaseDxe/ConfigKeywordHandler.c | 3329 ++++++++++++++++++++ 1 file changed, 3329 insertions(+) create mode 100644 roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigKeywordHandler.c (limited to 'roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigKeywordHandler.c') diff --git a/roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigKeywordHandler.c b/roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigKeywordHandler.c new file mode 100644 index 000000000..5ee866fb9 --- /dev/null +++ b/roms/edk2/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigKeywordHandler.c @@ -0,0 +1,3329 @@ +/** @file +Implementation of interfaces function for EFI_CONFIG_KEYWORD_HANDLER_PROTOCOL. + +Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#include "HiiDatabase.h" + +extern HII_DATABASE_PRIVATE_DATA mPrivate; + +/** + Convert the hex UNICODE %02x encoding of a UEFI device path to binary + from 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 necessary structures. + @retval EFI_SUCCESS The device path is retrieved and translated to binary format. + The Input string not include PathHdr section. + +**/ +EFI_STATUS +ExtractDevicePath ( + IN EFI_STRING String, + OUT UINT8 **DevicePathData, + OUT EFI_STRING *NextString + ) +{ + UINTN Length; + EFI_STRING PathHdr; + UINT8 *DevicePathBuffer; + CHAR16 TemStr[2]; + UINTN Index; + UINT8 DigitUint8; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + + ASSERT (NextString != NULL && DevicePathData != NULL); + + // + // KeywordRequest == NULL case. + // + if (String == NULL) { + *DevicePathData = NULL; + *NextString = NULL; + return EFI_SUCCESS; + } + + // + // Skip '&' if exist. + // + if (*String == L'&') { + String ++; + } + + // + // Find the 'PATH=' of . + // + 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; + UINTN NameSpaceSize; + + ASSERT (NameSpace != NULL); + + TmpPtr = NULL; + + // + // Input NameSpaceId == NULL + // + if (String == NULL) { + *NameSpace = NULL; + if (NextString != NULL) { + *NextString = NULL; + } + return EFI_SUCCESS; + } + + // + // Skip '&' if exist. + // + if (*String == L'&') { + String++; + } + + if (StrnCmp (String, L"NAMESPACE=", StrLen (L"NAMESPACE=")) != 0) { + return EFI_INVALID_PARAMETER; + } + String += StrLen (L"NAMESPACE="); + + TmpPtr = StrStr (String, L"&"); + if (TmpPtr != NULL) { + *TmpPtr = 0; + } + if (NextString != NULL) { + *NextString = String + StrLen (String); + } + + // + // Input NameSpace is unicode string. The language in String package is ascii string. + // Here will convert the unicode string to ascii and save it. + // + NameSpaceSize = StrLen (String) + 1; + *NameSpace = AllocatePool (NameSpaceSize); + if (*NameSpace == NULL) { + return EFI_OUT_OF_RESOURCES; + } + UnicodeStrToAsciiStrS (String, *NameSpace, NameSpaceSize); + + if (TmpPtr != NULL) { + *TmpPtr = L'&'; + } + + return EFI_SUCCESS; +} + +/** + Get Keyword from the input KeywordRequest string. + + This is a internal function. + + @param String KeywordRequestformat string. + @param Keyword return the extract keyword string. + @param NextString return the next string follow this keyword section. + + @retval EFI_SUCCESS Success to get the keyword string. + @retval EFI_INVALID_PARAMETER Parse the input string return error. + +**/ +EFI_STATUS +ExtractKeyword ( + IN EFI_STRING String, + OUT EFI_STRING *Keyword, + OUT EFI_STRING *NextString + ) +{ + EFI_STRING TmpPtr; + + ASSERT ((Keyword != NULL) && (NextString != NULL)); + + TmpPtr = NULL; + + // + // KeywordRequest == NULL case. + // + if (String == NULL) { + *Keyword = NULL; + *NextString = NULL; + return EFI_SUCCESS; + } + + // + // Skip '&' if exist. + // + if (*String == L'&') { + String++; + } + + if (StrnCmp (String, L"KEYWORD=", StrLen (L"KEYWORD=")) != 0) { + return EFI_INVALID_PARAMETER; + } + + String += StrLen (L"KEYWORD="); + + TmpPtr = StrStr (String, L"&"); + if (TmpPtr != NULL) { + *TmpPtr = 0; + } + *NextString = String + StrLen (String); + + *Keyword = AllocateCopyPool (StrSize (String), String); + if (*Keyword == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + if (TmpPtr != NULL) { + *TmpPtr = L'&'; + } + + return EFI_SUCCESS; +} + +/** + Get value from the input KeywordRequest string. + + This is a internal function. + + @param String KeywordRequestformat string. + @param Value return the extract value string. + @param NextString return the next string follow this keyword section. + + @retval EFI_SUCCESS Success to get the keyword string. + @retval EFI_INVALID_PARAMETER Parse the input string return error. + +**/ +EFI_STATUS +ExtractValue ( + IN EFI_STRING String, + OUT EFI_STRING *Value, + OUT EFI_STRING *NextString + ) +{ + EFI_STRING TmpPtr; + + ASSERT ((Value != NULL) && (NextString != NULL) && (String != NULL)); + + // + // Skip '&' if exist. + // + if (*String == L'&') { + String++; + } + + if (StrnCmp (String, L"VALUE=", StrLen (L"VALUE=")) != 0) { + return EFI_INVALID_PARAMETER; + } + + String += StrLen (L"VALUE="); + + TmpPtr = StrStr (String, L"&"); + if (TmpPtr != NULL) { + *TmpPtr = 0; + } + *NextString = String + StrLen (String); + + *Value = AllocateCopyPool (StrSize (String), String); + if (*Value == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + if (TmpPtr != NULL) { + *TmpPtr = L'&'; + } + + return EFI_SUCCESS; +} + +/** + Get filter from the input KeywordRequest string. + + This is a internal function. + + @param String KeywordRequestformat string. + @param FilterFlags return the filter condition. + @param NextString return the next string follow this keyword section. + + @retval EFI_SUCCESS Success to get the keyword string. + @retval EFI_INVALID_PARAMETER Parse the input string return error. + +**/ +BOOLEAN +ExtractFilter ( + IN EFI_STRING String, + OUT UINT8 *FilterFlags, + OUT EFI_STRING *NextString + ) +{ + CHAR16 *PathPtr; + CHAR16 *KeywordPtr; + BOOLEAN RetVal; + + ASSERT ((FilterFlags != NULL) && (NextString != NULL)); + + // + // String end, no filter section. + // + if (String == NULL) { + *NextString = NULL; + return FALSE; + } + + *FilterFlags = 0; + RetVal = TRUE; + + // + // Skip '&' if exist. + // + if (*String == L'&') { + String++; + } + + if (StrnCmp (String, L"ReadOnly", StrLen (L"ReadOnly")) == 0) { + // + // Find ReadOnly filter. + // + *FilterFlags |= EFI_KEYWORD_FILTER_READONY; + String += StrLen (L"ReadOnly"); + } else if (StrnCmp (String, L"ReadWrite", StrLen (L"ReadWrite")) == 0) { + // + // Find ReadWrite filter. + // + *FilterFlags |= EFI_KEYWORD_FILTER_REAWRITE; + String += StrLen (L"ReadWrite"); + } else if (StrnCmp (String, L"Buffer", StrLen (L"Buffer")) == 0) { + // + // Find Buffer Filter. + // + *FilterFlags |= EFI_KEYWORD_FILTER_BUFFER; + String += StrLen (L"Buffer"); + } else if (StrnCmp (String, L"Numeric", StrLen (L"Numeric")) == 0) { + // + // Find Numeric Filter + // + String += StrLen (L"Numeric"); + if (*String != L':') { + *FilterFlags |= EFI_KEYWORD_FILTER_NUMERIC; + } else { + String++; + switch (*String) { + case L'1': + *FilterFlags |= EFI_KEYWORD_FILTER_NUMERIC_1; + break; + case L'2': + *FilterFlags |= EFI_KEYWORD_FILTER_NUMERIC_2; + break; + case L'4': + *FilterFlags |= EFI_KEYWORD_FILTER_NUMERIC_4; + break; + case L'8': + *FilterFlags |= EFI_KEYWORD_FILTER_NUMERIC_8; + break; + default: + ASSERT (FALSE); + break; + } + String++; + } + } else { + // + // Check whether other filter item defined by Platform. + // + if ((StrnCmp (String, L"&PATH", StrLen (L"&PATH")) == 0) || + (StrnCmp (String, L"&KEYWORD", StrLen (L"&KEYWORD")) == 0)) { + // + // New KeywordRequest start, no platform defined filter. + // + } else { + // + // Platform defined filter rule. + // Just skip platform defined filter rule, return success. + // + PathPtr = StrStr(String, L"&PATH"); + KeywordPtr = StrStr(String, L"&KEYWORD"); + if (PathPtr != NULL && KeywordPtr != NULL) { + // + // If both sections exist, return the first follow string. + // + String = KeywordPtr > PathPtr ? PathPtr : KeywordPtr; + } else if (PathPtr != NULL) { + // + // Should not exist PathPtr != NULL && KeywordPtr == NULL case. + // + ASSERT (FALSE); + } else if (KeywordPtr != NULL) { + // + // Just to the next keyword section. + // + String = KeywordPtr; + } else { + // + // Only has platform defined filter section, just skip it. + // + String += StrLen (String); + } + } + RetVal = FALSE; + } + + *NextString = String; + + return RetVal; +} + +/** + Extract Readonly flag from opcode. + + This is a internal function. + + @param OpCodeData Input opcode for this question. + + @retval TRUE This question is readonly. + @retval FALSE This question is not readonly. + +**/ +BOOLEAN +ExtractReadOnlyFromOpCode ( + IN UINT8 *OpCodeData + ) +{ + EFI_IFR_QUESTION_HEADER *QuestionHdr; + + ASSERT (OpCodeData != NULL); + + QuestionHdr = (EFI_IFR_QUESTION_HEADER *) (OpCodeData + sizeof (EFI_IFR_OP_HEADER)); + + return (QuestionHdr->Flags & EFI_IFR_FLAG_READ_ONLY) != 0; +} + +/** + Create a circuit to check the filter section. + + This is a internal function. + + @param OpCodeData The question binary ifr data. + @param KeywordRequest KeywordRequestformat string. + @param NextString return the next string follow this keyword section. + @param ReadOnly Return whether this question is read only. + + @retval KEYWORD_HANDLER_NO_ERROR Success validate. + @retval KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED Validate fail. + +**/ +UINT32 +ValidateFilter ( + IN UINT8 *OpCodeData, + IN CHAR16 *KeywordRequest, + OUT CHAR16 **NextString, + OUT BOOLEAN *ReadOnly + ) +{ + CHAR16 *NextFilter; + CHAR16 *StringPtr; + UINT8 FilterFlags; + EFI_IFR_QUESTION_HEADER *QuestionHdr; + EFI_IFR_OP_HEADER *OpCodeHdr; + UINT8 Flags; + UINT32 RetVal; + + RetVal = KEYWORD_HANDLER_NO_ERROR; + StringPtr = KeywordRequest; + + OpCodeHdr = (EFI_IFR_OP_HEADER *) OpCodeData; + QuestionHdr = (EFI_IFR_QUESTION_HEADER *) (OpCodeData + sizeof (EFI_IFR_OP_HEADER)); + if (OpCodeHdr->OpCode == EFI_IFR_ONE_OF_OP || OpCodeHdr->OpCode == EFI_IFR_NUMERIC_OP) { + Flags = *(OpCodeData + sizeof (EFI_IFR_OP_HEADER) + sizeof (EFI_IFR_QUESTION_HEADER)); + } else { + Flags = 0; + } + + // + // Get ReadOnly flag from Question. + // + *ReadOnly = ExtractReadOnlyFromOpCode(OpCodeData); + + while (ExtractFilter (StringPtr, &FilterFlags, &NextFilter)) { + switch (FilterFlags) { + case EFI_KEYWORD_FILTER_READONY: + if ((QuestionHdr->Flags & EFI_IFR_FLAG_READ_ONLY) == 0) { + RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED; + goto Done; + } + break; + + case EFI_KEYWORD_FILTER_REAWRITE: + if ((QuestionHdr->Flags & EFI_IFR_FLAG_READ_ONLY) != 0) { + RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED; + goto Done; + } + break; + + case EFI_KEYWORD_FILTER_BUFFER: + // + // Only these three opcode use numeric value type. + // + if (OpCodeHdr->OpCode == EFI_IFR_ONE_OF_OP || OpCodeHdr->OpCode == EFI_IFR_NUMERIC_OP || OpCodeHdr->OpCode == EFI_IFR_CHECKBOX_OP) { + RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED; + goto Done; + } + break; + + case EFI_KEYWORD_FILTER_NUMERIC: + if (OpCodeHdr->OpCode != EFI_IFR_ONE_OF_OP && OpCodeHdr->OpCode != EFI_IFR_NUMERIC_OP && OpCodeHdr->OpCode != EFI_IFR_CHECKBOX_OP) { + RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED; + goto Done; + } + break; + + case EFI_KEYWORD_FILTER_NUMERIC_1: + case EFI_KEYWORD_FILTER_NUMERIC_2: + case EFI_KEYWORD_FILTER_NUMERIC_4: + case EFI_KEYWORD_FILTER_NUMERIC_8: + if (OpCodeHdr->OpCode != EFI_IFR_ONE_OF_OP && OpCodeHdr->OpCode != EFI_IFR_NUMERIC_OP && OpCodeHdr->OpCode != EFI_IFR_CHECKBOX_OP) { + RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED; + goto Done; + } + + // + // For numeric and oneof, it has flags field to specify the detail numeric type. + // + if (OpCodeHdr->OpCode == EFI_IFR_ONE_OF_OP || OpCodeHdr->OpCode == EFI_IFR_NUMERIC_OP) { + switch (Flags & EFI_IFR_NUMERIC_SIZE) { + case EFI_IFR_NUMERIC_SIZE_1: + if (FilterFlags != EFI_KEYWORD_FILTER_NUMERIC_1) { + RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED; + goto Done; + } + break; + + case EFI_IFR_NUMERIC_SIZE_2: + if (FilterFlags != EFI_KEYWORD_FILTER_NUMERIC_2) { + RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED; + goto Done; + } + break; + + case EFI_IFR_NUMERIC_SIZE_4: + if (FilterFlags != EFI_KEYWORD_FILTER_NUMERIC_4) { + RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED; + goto Done; + } + break; + + case EFI_IFR_NUMERIC_SIZE_8: + if (FilterFlags != EFI_KEYWORD_FILTER_NUMERIC_8) { + RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED; + goto Done; + } + break; + + default: + ASSERT (FALSE); + break; + } + } + break; + + default: + ASSERT (FALSE); + break; + } + + // + // Jump to the next filter. + // + StringPtr = NextFilter; + } + +Done: + // + // The current filter which is processing. + // + *NextString = StringPtr; + + return RetVal; +} + +/** + Get HII_DATABASE_RECORD from the input device path info. + + This is a internal function. + + @param DevicePath UEFI device path protocol. + + @retval Internal data base record. + +**/ +HII_DATABASE_RECORD * +GetRecordFromDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + LIST_ENTRY *Link; + UINT8 *DevicePathPkg; + UINT8 *CurrentDevicePath; + UINTN DevicePathSize; + HII_DATABASE_RECORD *TempDatabase; + + ASSERT (DevicePath != NULL); + + for (Link = mPrivate.DatabaseList.ForwardLink; Link != &mPrivate.DatabaseList; Link = Link->ForwardLink) { + TempDatabase = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE); + DevicePathPkg = TempDatabase->PackageList->DevicePathPkg; + if (DevicePathPkg != NULL) { + CurrentDevicePath = DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER); + DevicePathSize = GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) CurrentDevicePath); + if ((CompareMem (DevicePath, CurrentDevicePath, DevicePathSize) == 0)) { + return TempDatabase; + } + } + } + + return NULL; +} + +/** + Calculate the size of StringSrc and output it. Also copy string text from src + to dest. + + This is a internal function. + + @param StringSrc Points to current null-terminated string. + @param BufferSize Length of the buffer. + @param StringDest Buffer to store the string text. + + @retval EFI_SUCCESS The string text was outputted successfully. + @retval EFI_OUT_OF_RESOURCES Out of resource. + +**/ +EFI_STATUS +GetUnicodeStringTextAndSize ( + IN UINT8 *StringSrc, + OUT UINTN *BufferSize, + OUT EFI_STRING *StringDest + ) +{ + UINTN StringSize; + UINT8 *StringPtr; + + ASSERT (StringSrc != NULL && BufferSize != NULL && StringDest != NULL); + + StringSize = sizeof (CHAR16); + StringPtr = StringSrc; + while (ReadUnaligned16 ((UINT16 *) StringPtr) != 0) { + StringSize += sizeof (CHAR16); + StringPtr += sizeof (CHAR16); + } + + *StringDest = AllocatePool (StringSize); + if (*StringDest == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + CopyMem (*StringDest, StringSrc, StringSize); + + *BufferSize = StringSize; + return EFI_SUCCESS; +} + +/** + Find the string id for the input keyword. + + @param StringPackage Hii string package instance. + @param KeywordValue Input keyword value. + @param StringId The string's id, which is unique within PackageList. + + + @retval EFI_SUCCESS The string text and font is retrieved + successfully. + @retval EFI_NOT_FOUND The specified text or font info can not be found + out. + @retval EFI_OUT_OF_RESOURCES The system is out of resources to accomplish the + task. +**/ +EFI_STATUS +GetStringIdFromString ( + IN HII_STRING_PACKAGE_INSTANCE *StringPackage, + IN CHAR16 *KeywordValue, + OUT EFI_STRING_ID *StringId + ) +{ + UINT8 *BlockHdr; + EFI_STRING_ID CurrentStringId; + UINTN BlockSize; + UINTN Index; + UINT8 *StringTextPtr; + UINTN Offset; + UINT16 StringCount; + UINT16 SkipCount; + UINT8 Length8; + EFI_HII_SIBT_EXT2_BLOCK Ext2; + UINT32 Length32; + UINTN StringSize; + CHAR16 *String; + CHAR8 *AsciiKeywordValue; + UINTN KeywordValueSize; + EFI_STATUS Status; + + ASSERT (StringPackage != NULL && KeywordValue != NULL && StringId != NULL); + ASSERT (StringPackage->Signature == HII_STRING_PACKAGE_SIGNATURE); + + CurrentStringId = 1; + Status = EFI_SUCCESS; + String = NULL; + BlockHdr = StringPackage->StringBlock; + BlockSize = 0; + Offset = 0; + + // + // Make a ascii keyword value for later use. + // + KeywordValueSize = StrLen (KeywordValue) + 1; + AsciiKeywordValue = AllocatePool (KeywordValueSize); + if (AsciiKeywordValue == NULL) { + return EFI_OUT_OF_RESOURCES; + } + UnicodeStrToAsciiStrS (KeywordValue, AsciiKeywordValue, KeywordValueSize); + + while (*BlockHdr != EFI_HII_SIBT_END) { + switch (*BlockHdr) { + case EFI_HII_SIBT_STRING_SCSU: + Offset = sizeof (EFI_HII_STRING_BLOCK); + StringTextPtr = BlockHdr + Offset; + BlockSize += Offset + AsciiStrSize ((CHAR8 *) StringTextPtr); + if (AsciiStrCmp(AsciiKeywordValue, (CHAR8 *) StringTextPtr) == 0) { + *StringId = CurrentStringId; + goto Done; + } + CurrentStringId++; + break; + + case EFI_HII_SIBT_STRING_SCSU_FONT: + Offset = sizeof (EFI_HII_SIBT_STRING_SCSU_FONT_BLOCK) - sizeof (UINT8); + StringTextPtr = BlockHdr + Offset; + if (AsciiStrCmp(AsciiKeywordValue, (CHAR8 *) StringTextPtr) == 0) { + *StringId = CurrentStringId; + goto Done; + } + BlockSize += Offset + AsciiStrSize ((CHAR8 *) StringTextPtr); + CurrentStringId++; + break; + + case EFI_HII_SIBT_STRINGS_SCSU: + CopyMem (&StringCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16)); + StringTextPtr = (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_SIBT_STRINGS_SCSU_BLOCK) - sizeof (UINT8)); + BlockSize += StringTextPtr - BlockHdr; + + for (Index = 0; Index < StringCount; Index++) { + BlockSize += AsciiStrSize ((CHAR8 *) StringTextPtr); + if (AsciiStrCmp(AsciiKeywordValue, (CHAR8 *) StringTextPtr) == 0) { + *StringId = CurrentStringId; + goto Done; + } + StringTextPtr = StringTextPtr + AsciiStrSize ((CHAR8 *) StringTextPtr); + CurrentStringId++; + } + break; + + case EFI_HII_SIBT_STRINGS_SCSU_FONT: + CopyMem ( + &StringCount, + (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)), + sizeof (UINT16) + ); + StringTextPtr = (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_SIBT_STRINGS_SCSU_FONT_BLOCK) - sizeof (UINT8)); + BlockSize += StringTextPtr - BlockHdr; + + for (Index = 0; Index < StringCount; Index++) { + BlockSize += AsciiStrSize ((CHAR8 *) StringTextPtr); + if (AsciiStrCmp(AsciiKeywordValue, (CHAR8 *) StringTextPtr) == 0) { + *StringId = CurrentStringId; + goto Done; + } + StringTextPtr = StringTextPtr + AsciiStrSize ((CHAR8 *) StringTextPtr); + CurrentStringId++; + } + break; + + case EFI_HII_SIBT_STRING_UCS2: + Offset = sizeof (EFI_HII_STRING_BLOCK); + StringTextPtr = BlockHdr + Offset; + // + // Use StringSize to store the size of the specified string, including the NULL + // terminator. + // + Status = GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String); + if (EFI_ERROR (Status)) { + goto Done; + } + ASSERT (String != NULL); + if (StrCmp(KeywordValue, String) == 0) { + *StringId = CurrentStringId; + goto Done; + } + BlockSize += Offset + StringSize; + CurrentStringId++; + break; + + case EFI_HII_SIBT_STRING_UCS2_FONT: + Offset = sizeof (EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK) - sizeof (CHAR16); + StringTextPtr = BlockHdr + Offset; + // + // Use StringSize to store the size of the specified string, including the NULL + // terminator. + // + Status = GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String); + if (EFI_ERROR (Status)) { + goto Done; + } + ASSERT (String != NULL); + if (StrCmp(KeywordValue, String) == 0) { + *StringId = CurrentStringId; + goto Done; + } + BlockSize += Offset + StringSize; + CurrentStringId++; + break; + + case EFI_HII_SIBT_STRINGS_UCS2: + Offset = sizeof (EFI_HII_SIBT_STRINGS_UCS2_BLOCK) - sizeof (CHAR16); + StringTextPtr = BlockHdr + Offset; + BlockSize += Offset; + CopyMem (&StringCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16)); + for (Index = 0; Index < StringCount; Index++) { + Status = GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String); + if (EFI_ERROR (Status)) { + goto Done; + } + ASSERT (String != NULL); + BlockSize += StringSize; + if (StrCmp(KeywordValue, String) == 0) { + *StringId = CurrentStringId; + goto Done; + } + StringTextPtr = StringTextPtr + StringSize; + CurrentStringId++; + } + break; + + case EFI_HII_SIBT_STRINGS_UCS2_FONT: + Offset = sizeof (EFI_HII_SIBT_STRINGS_UCS2_FONT_BLOCK) - sizeof (CHAR16); + StringTextPtr = BlockHdr + Offset; + BlockSize += Offset; + CopyMem ( + &StringCount, + (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)), + sizeof (UINT16) + ); + for (Index = 0; Index < StringCount; Index++) { + Status = GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String); + if (EFI_ERROR (Status)) { + goto Done; + } + ASSERT (String != NULL); + BlockSize += StringSize; + if (StrCmp(KeywordValue, String) == 0) { + *StringId = CurrentStringId; + goto Done; + } + StringTextPtr = StringTextPtr + StringSize; + CurrentStringId++; + } + break; + + case EFI_HII_SIBT_DUPLICATE: + BlockSize += sizeof (EFI_HII_SIBT_DUPLICATE_BLOCK); + CurrentStringId++; + break; + + case EFI_HII_SIBT_SKIP1: + SkipCount = (UINT16) (*(UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK))); + CurrentStringId = (UINT16) (CurrentStringId + SkipCount); + BlockSize += sizeof (EFI_HII_SIBT_SKIP1_BLOCK); + break; + + case EFI_HII_SIBT_SKIP2: + CopyMem (&SkipCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16)); + CurrentStringId = (UINT16) (CurrentStringId + SkipCount); + BlockSize += sizeof (EFI_HII_SIBT_SKIP2_BLOCK); + break; + + case EFI_HII_SIBT_EXT1: + CopyMem ( + &Length8, + (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)), + sizeof (UINT8) + ); + BlockSize += Length8; + break; + + case EFI_HII_SIBT_EXT2: + CopyMem (&Ext2, BlockHdr, sizeof (EFI_HII_SIBT_EXT2_BLOCK)); + BlockSize += Ext2.Length; + break; + + case EFI_HII_SIBT_EXT4: + CopyMem ( + &Length32, + (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)), + sizeof (UINT32) + ); + + BlockSize += Length32; + break; + + default: + break; + } + + if (String != NULL) { + FreePool (String); + String = NULL; + } + + BlockHdr = StringPackage->StringBlock + BlockSize; + } + + Status = EFI_NOT_FOUND; + +Done: + if (AsciiKeywordValue != NULL) { + FreePool (AsciiKeywordValue); + } + if (String != NULL) { + FreePool (String); + } + return Status; +} + +/** + Find the next valid string id for the input string id. + + @param StringPackage Hii string package instance. + @param StringId The current string id which is already got. + 1 means just begin to get the string id. + @param KeywordValue Return the string for the next string id. + + + @retval EFI_STRING_ID Not 0 means a valid stringid found. + 0 means not found a valid string id. +**/ +EFI_STRING_ID +GetNextStringId ( + IN HII_STRING_PACKAGE_INSTANCE *StringPackage, + IN EFI_STRING_ID StringId, + OUT EFI_STRING *KeywordValue + ) +{ + UINT8 *BlockHdr; + EFI_STRING_ID CurrentStringId; + UINTN BlockSize; + UINTN Index; + UINT8 *StringTextPtr; + UINTN Offset; + UINT16 StringCount; + UINT16 SkipCount; + UINT8 Length8; + EFI_HII_SIBT_EXT2_BLOCK Ext2; + UINT32 Length32; + BOOLEAN FindString; + UINTN StringSize; + CHAR16 *String; + + ASSERT (StringPackage != NULL); + ASSERT (StringPackage->Signature == HII_STRING_PACKAGE_SIGNATURE); + + CurrentStringId = 1; + FindString = FALSE; + String = NULL; + + // + // Parse the string blocks to get the string text and font. + // + BlockHdr = StringPackage->StringBlock; + BlockSize = 0; + Offset = 0; + while (*BlockHdr != EFI_HII_SIBT_END) { + switch (*BlockHdr) { + case EFI_HII_SIBT_STRING_SCSU: + Offset = sizeof (EFI_HII_STRING_BLOCK); + StringTextPtr = BlockHdr + Offset; + + if (FindString) { + StringSize = AsciiStrSize ((CHAR8 *) StringTextPtr); + *KeywordValue = AllocatePool (StringSize * sizeof (CHAR16)); + if (*KeywordValue == NULL) { + return 0; + } + AsciiStrToUnicodeStrS ((CHAR8 *) StringTextPtr, *KeywordValue, StringSize); + return CurrentStringId; + } else if (CurrentStringId == StringId) { + FindString = TRUE; + } + + BlockSize += Offset + AsciiStrSize ((CHAR8 *) StringTextPtr); + CurrentStringId++; + break; + + case EFI_HII_SIBT_STRING_SCSU_FONT: + Offset = sizeof (EFI_HII_SIBT_STRING_SCSU_FONT_BLOCK) - sizeof (UINT8); + StringTextPtr = BlockHdr + Offset; + + if (FindString) { + StringSize = AsciiStrSize ((CHAR8 *) StringTextPtr); + *KeywordValue = AllocatePool (StringSize * sizeof (CHAR16)); + if (*KeywordValue == NULL) { + return 0; + } + AsciiStrToUnicodeStrS ((CHAR8 *) StringTextPtr, *KeywordValue, StringSize); + return CurrentStringId; + } else if (CurrentStringId == StringId) { + FindString = TRUE; + } + + BlockSize += Offset + AsciiStrSize ((CHAR8 *) StringTextPtr); + CurrentStringId++; + break; + + case EFI_HII_SIBT_STRINGS_SCSU: + CopyMem (&StringCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16)); + StringTextPtr = (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_SIBT_STRINGS_SCSU_BLOCK) - sizeof (UINT8)); + BlockSize += StringTextPtr - BlockHdr; + + for (Index = 0; Index < StringCount; Index++) { + if (FindString) { + StringSize = AsciiStrSize ((CHAR8 *) StringTextPtr); + *KeywordValue = AllocatePool (StringSize * sizeof (CHAR16)); + if (*KeywordValue == NULL) { + return 0; + } + AsciiStrToUnicodeStrS ((CHAR8 *) StringTextPtr, *KeywordValue, StringSize); + return CurrentStringId; + } else if (CurrentStringId == StringId) { + FindString = TRUE; + } + + BlockSize += AsciiStrSize ((CHAR8 *) StringTextPtr); + StringTextPtr = StringTextPtr + AsciiStrSize ((CHAR8 *) StringTextPtr); + CurrentStringId++; + } + break; + + case EFI_HII_SIBT_STRINGS_SCSU_FONT: + CopyMem ( + &StringCount, + (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)), + sizeof (UINT16) + ); + StringTextPtr = (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_SIBT_STRINGS_SCSU_FONT_BLOCK) - sizeof (UINT8)); + BlockSize += StringTextPtr - BlockHdr; + + for (Index = 0; Index < StringCount; Index++) { + if (FindString) { + StringSize = AsciiStrSize ((CHAR8 *) StringTextPtr); + *KeywordValue = AllocatePool (StringSize * sizeof (CHAR16)); + if (*KeywordValue == NULL) { + return 0; + } + AsciiStrToUnicodeStrS ((CHAR8 *) StringTextPtr, *KeywordValue, StringSize); + return CurrentStringId; + } else if (CurrentStringId == StringId) { + FindString = TRUE; + } + + BlockSize += AsciiStrSize ((CHAR8 *) StringTextPtr); + StringTextPtr = StringTextPtr + AsciiStrSize ((CHAR8 *) StringTextPtr); + CurrentStringId++; + } + break; + + case EFI_HII_SIBT_STRING_UCS2: + Offset = sizeof (EFI_HII_STRING_BLOCK); + StringTextPtr = BlockHdr + Offset; + // + // Use StringSize to store the size of the specified string, including the NULL + // terminator. + // + GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String); + if (FindString && (String != NULL) && (*String != L'\0')) { + // + // String protocol use this type for the string id which has value for other package. + // It will allocate an empty string block for this string id. so here we also check + // *String != L'\0' to prohibit this case. + // + *KeywordValue = String; + return CurrentStringId; + } else if (CurrentStringId == StringId) { + FindString = TRUE; + } + + BlockSize += Offset + StringSize; + CurrentStringId++; + break; + + case EFI_HII_SIBT_STRING_UCS2_FONT: + Offset = sizeof (EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK) - sizeof (CHAR16); + StringTextPtr = BlockHdr + Offset; + // + // Use StringSize to store the size of the specified string, including the NULL + // terminator. + // + GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String); + if (FindString) { + *KeywordValue = String; + return CurrentStringId; + } else if (CurrentStringId == StringId) { + FindString = TRUE; + } + + BlockSize += Offset + StringSize; + CurrentStringId++; + break; + + case EFI_HII_SIBT_STRINGS_UCS2: + Offset = sizeof (EFI_HII_SIBT_STRINGS_UCS2_BLOCK) - sizeof (CHAR16); + StringTextPtr = BlockHdr + Offset; + BlockSize += Offset; + CopyMem (&StringCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16)); + for (Index = 0; Index < StringCount; Index++) { + GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String); + + if (FindString) { + *KeywordValue = String; + return CurrentStringId; + } else if (CurrentStringId == StringId) { + FindString = TRUE; + } + + BlockSize += StringSize; + StringTextPtr = StringTextPtr + StringSize; + CurrentStringId++; + } + break; + + case EFI_HII_SIBT_STRINGS_UCS2_FONT: + Offset = sizeof (EFI_HII_SIBT_STRINGS_UCS2_FONT_BLOCK) - sizeof (CHAR16); + StringTextPtr = BlockHdr + Offset; + BlockSize += Offset; + CopyMem ( + &StringCount, + (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)), + sizeof (UINT16) + ); + for (Index = 0; Index < StringCount; Index++) { + GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String); + if (FindString) { + *KeywordValue = String; + return CurrentStringId; + } else if (CurrentStringId == StringId) { + FindString = TRUE; + } + + BlockSize += StringSize; + StringTextPtr = StringTextPtr + StringSize; + CurrentStringId++; + } + break; + + case EFI_HII_SIBT_DUPLICATE: + BlockSize += sizeof (EFI_HII_SIBT_DUPLICATE_BLOCK); + CurrentStringId++; + break; + + case EFI_HII_SIBT_SKIP1: + SkipCount = (UINT16) (*(UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK))); + CurrentStringId = (UINT16) (CurrentStringId + SkipCount); + BlockSize += sizeof (EFI_HII_SIBT_SKIP1_BLOCK); + break; + + case EFI_HII_SIBT_SKIP2: + CopyMem (&SkipCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16)); + CurrentStringId = (UINT16) (CurrentStringId + SkipCount); + BlockSize += sizeof (EFI_HII_SIBT_SKIP2_BLOCK); + break; + + case EFI_HII_SIBT_EXT1: + CopyMem ( + &Length8, + (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)), + sizeof (UINT8) + ); + BlockSize += Length8; + break; + + case EFI_HII_SIBT_EXT2: + CopyMem (&Ext2, BlockHdr, sizeof (EFI_HII_SIBT_EXT2_BLOCK)); + BlockSize += Ext2.Length; + break; + + case EFI_HII_SIBT_EXT4: + CopyMem ( + &Length32, + (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)), + sizeof (UINT32) + ); + + BlockSize += Length32; + break; + + default: + break; + } + + if (String != NULL) { + FreePool (String); + String = NULL; + } + + BlockHdr = StringPackage->StringBlock + BlockSize; + } + + return 0; +} + +/** + Get string package from the input NameSpace string. + + This is a internal function. + + @param DatabaseRecord HII_DATABASE_RECORD format string. + @param NameSpace NameSpace format string. + @param KeywordValue Keyword value. + @param StringId String Id for this keyword. + + @retval KEYWORD_HANDLER_NO_ERROR Get String id successfully. + @retval KEYWORD_HANDLER_KEYWORD_NOT_FOUND Not found the string id in the string package. + @retval KEYWORD_HANDLER_NAMESPACE_ID_NOT_FOUND Not found the string package for this namespace. + @retval KEYWORD_HANDLER_UNDEFINED_PROCESSING_ERROR Out of resource error. + +**/ +UINT32 +GetStringIdFromRecord ( + IN HII_DATABASE_RECORD *DatabaseRecord, + IN CHAR8 **NameSpace, + IN CHAR16 *KeywordValue, + OUT EFI_STRING_ID *StringId + ) +{ + LIST_ENTRY *Link; + HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageListNode; + HII_STRING_PACKAGE_INSTANCE *StringPackage; + EFI_STATUS Status; + CHAR8 *Name; + UINT32 RetVal; + + ASSERT (DatabaseRecord != NULL && NameSpace != NULL && KeywordValue != NULL); + + PackageListNode = DatabaseRecord->PackageList; + RetVal = KEYWORD_HANDLER_NAMESPACE_ID_NOT_FOUND; + + if (*NameSpace != NULL) { + Name = *NameSpace; + } else { + Name = UEFI_CONFIG_LANG; + } + + for (Link = PackageListNode->StringPkgHdr.ForwardLink; Link != &PackageListNode->StringPkgHdr; Link = Link->ForwardLink) { + StringPackage = CR (Link, HII_STRING_PACKAGE_INSTANCE, StringEntry, HII_STRING_PACKAGE_SIGNATURE); + + if (AsciiStrnCmp(Name, StringPackage->StringPkgHdr->Language, AsciiStrLen (Name)) == 0) { + Status = GetStringIdFromString (StringPackage, KeywordValue, StringId); + if (EFI_ERROR (Status)) { + return KEYWORD_HANDLER_KEYWORD_NOT_FOUND; + } else { + if (*NameSpace == NULL) { + *NameSpace = AllocateCopyPool (AsciiStrSize (StringPackage->StringPkgHdr->Language), StringPackage->StringPkgHdr->Language); + if (*NameSpace == NULL) { + return KEYWORD_HANDLER_UNDEFINED_PROCESSING_ERROR; + } + } + return KEYWORD_HANDLER_NO_ERROR; + } + } + } + + return RetVal; +} + +/** + Tell whether this Operand is an Statement OpCode. + + @param Operand Operand of an IFR OpCode. + + @retval TRUE This is an Statement OpCode. + @retval FALSE Not an Statement OpCode. + +**/ +BOOLEAN +IsStatementOpCode ( + IN UINT8 Operand + ) +{ + if ((Operand == EFI_IFR_SUBTITLE_OP) || + (Operand == EFI_IFR_TEXT_OP) || + (Operand == EFI_IFR_RESET_BUTTON_OP) || + (Operand == EFI_IFR_REF_OP) || + (Operand == EFI_IFR_ACTION_OP) || + (Operand == EFI_IFR_NUMERIC_OP) || + (Operand == EFI_IFR_ORDERED_LIST_OP) || + (Operand == EFI_IFR_CHECKBOX_OP) || + (Operand == EFI_IFR_STRING_OP) || + (Operand == EFI_IFR_PASSWORD_OP) || + (Operand == EFI_IFR_DATE_OP) || + (Operand == EFI_IFR_TIME_OP) || + (Operand == EFI_IFR_GUID_OP) || + (Operand == EFI_IFR_ONE_OF_OP)) { + return TRUE; + } + + return FALSE; +} + +/** + Tell whether this Operand is an Statement OpCode. + + @param Operand Operand of an IFR OpCode. + + @retval TRUE This is an Statement OpCode. + @retval FALSE Not an Statement OpCode. + +**/ +BOOLEAN +IsStorageOpCode ( + IN UINT8 Operand + ) +{ + if ((Operand == EFI_IFR_VARSTORE_OP) || + (Operand == EFI_IFR_VARSTORE_NAME_VALUE_OP) || + (Operand == EFI_IFR_VARSTORE_EFI_OP)) { + return TRUE; + } + + return FALSE; +} + +/** + Base on the prompt string id to find the question. + + @param FormPackage The input form package. + @param KeywordStrId The input prompt string id for one question. + + @retval the opcode for the question. + +**/ +UINT8 * +FindQuestionFromStringId ( + IN HII_IFR_PACKAGE_INSTANCE *FormPackage, + IN EFI_STRING_ID KeywordStrId + ) +{ + UINT8 *OpCodeData; + UINT32 Offset; + EFI_IFR_STATEMENT_HEADER *StatementHeader; + EFI_IFR_OP_HEADER *OpCodeHeader; + UINT32 FormDataLen; + + ASSERT (FormPackage != NULL); + + FormDataLen = FormPackage->FormPkgHdr.Length - sizeof (EFI_HII_PACKAGE_HEADER); + Offset = 0; + while (Offset < FormDataLen) { + OpCodeData = FormPackage->IfrData + Offset; + OpCodeHeader = (EFI_IFR_OP_HEADER *) OpCodeData; + + if (IsStatementOpCode(OpCodeHeader->OpCode)) { + StatementHeader = (EFI_IFR_STATEMENT_HEADER *) (OpCodeData + sizeof (EFI_IFR_OP_HEADER)); + if (StatementHeader->Prompt == KeywordStrId) { + return OpCodeData; + } + } + + Offset += OpCodeHeader->Length; + } + + return NULL; +} + +/** + Base on the varstore id to find the storage info. + + @param FormPackage The input form package. + @param VarStoreId The input storage id. + + @retval the opcode for the storage. + +**/ +UINT8 * +FindStorageFromVarId ( + IN HII_IFR_PACKAGE_INSTANCE *FormPackage, + IN EFI_VARSTORE_ID VarStoreId + ) +{ + UINT8 *OpCodeData; + UINT32 Offset; + EFI_IFR_OP_HEADER *OpCodeHeader; + UINT32 FormDataLen; + + ASSERT (FormPackage != NULL); + + FormDataLen = FormPackage->FormPkgHdr.Length - sizeof (EFI_HII_PACKAGE_HEADER); + Offset = 0; + while (Offset < FormDataLen) { + OpCodeData = FormPackage->IfrData + Offset; + OpCodeHeader = (EFI_IFR_OP_HEADER *) OpCodeData; + + if (IsStorageOpCode(OpCodeHeader->OpCode)) { + switch (OpCodeHeader->OpCode) { + case EFI_IFR_VARSTORE_OP: + if (VarStoreId == ((EFI_IFR_VARSTORE *) OpCodeData)->VarStoreId) { + return OpCodeData; + } + break; + + case EFI_IFR_VARSTORE_NAME_VALUE_OP: + if (VarStoreId == ((EFI_IFR_VARSTORE_NAME_VALUE *) OpCodeData)->VarStoreId) { + return OpCodeData; + } + break; + + case EFI_IFR_VARSTORE_EFI_OP: + if (VarStoreId == ((EFI_IFR_VARSTORE_EFI *) OpCodeData)->VarStoreId) { + return OpCodeData; + } + break; + + default: + break; + } + } + + Offset += OpCodeHeader->Length; + } + + return NULL; +} + +/** + Get width info for one question. + + @param OpCodeData The input opcode for one question. + + @retval the width info for one question. + +**/ +UINT16 +GetWidth ( + IN UINT8 *OpCodeData + ) +{ + UINT8 *NextOpCodeData; + + ASSERT (OpCodeData != NULL); + + switch (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode) { + case EFI_IFR_REF_OP: + return (UINT16) sizeof (EFI_HII_REF); + + case EFI_IFR_ONE_OF_OP: + case EFI_IFR_NUMERIC_OP: + switch (((EFI_IFR_ONE_OF *) OpCodeData)->Flags & EFI_IFR_NUMERIC_SIZE) { + case EFI_IFR_NUMERIC_SIZE_1: + return (UINT16) sizeof (UINT8); + + case EFI_IFR_NUMERIC_SIZE_2: + return (UINT16) sizeof (UINT16); + + case EFI_IFR_NUMERIC_SIZE_4: + return (UINT16) sizeof (UINT32); + + case EFI_IFR_NUMERIC_SIZE_8: + return (UINT16) sizeof (UINT64); + + default: + ASSERT (FALSE); + return 0; + } + + case EFI_IFR_ORDERED_LIST_OP: + NextOpCodeData = OpCodeData + ((EFI_IFR_ORDERED_LIST *) OpCodeData)->Header.Length; + // + // OneOfOption must follow the orderedlist opcode. + // + ASSERT (((EFI_IFR_OP_HEADER *) NextOpCodeData)->OpCode == EFI_IFR_ONE_OF_OPTION_OP); + switch (((EFI_IFR_ONE_OF_OPTION *) NextOpCodeData)->Type) { + case EFI_IFR_TYPE_NUM_SIZE_8: + return (UINT16) sizeof (UINT8) * ((EFI_IFR_ORDERED_LIST *) OpCodeData)->MaxContainers; + + case EFI_IFR_TYPE_NUM_SIZE_16: + return (UINT16) sizeof (UINT16) * ((EFI_IFR_ORDERED_LIST *) OpCodeData)->MaxContainers ; + + case EFI_IFR_TYPE_NUM_SIZE_32: + return (UINT16) sizeof (UINT32) * ((EFI_IFR_ORDERED_LIST *) OpCodeData)->MaxContainers; + + case EFI_IFR_TYPE_NUM_SIZE_64: + return (UINT16) sizeof (UINT64) * ((EFI_IFR_ORDERED_LIST *) OpCodeData)->MaxContainers; + + default: + ASSERT (FALSE); + return 0; + } + + case EFI_IFR_CHECKBOX_OP: + return (UINT16) sizeof (BOOLEAN); + + case EFI_IFR_PASSWORD_OP: + return (UINT16)((UINTN) ((EFI_IFR_PASSWORD *) OpCodeData)->MaxSize * sizeof (CHAR16)); + + case EFI_IFR_STRING_OP: + return (UINT16)((UINTN) ((EFI_IFR_STRING *) OpCodeData)->MaxSize * sizeof (CHAR16)); + + case EFI_IFR_DATE_OP: + return (UINT16) sizeof (EFI_HII_DATE); + + case EFI_IFR_TIME_OP: + return (UINT16) sizeof (EFI_HII_TIME); + + default: + ASSERT (FALSE); + return 0; + } +} + +/** + Converts all hex string characters in range ['A'..'F'] to ['a'..'f'] for + hex digits that appear between a '=' and a '&' in a config string. + + If ConfigString is NULL, then ASSERT(). + + @param[in] ConfigString Pointer to a Null-terminated Unicode string. + + @return Pointer to the Null-terminated Unicode result string. + +**/ +EFI_STRING +EFIAPI +InternalLowerConfigString ( + IN EFI_STRING ConfigString + ) +{ + EFI_STRING String; + BOOLEAN Lower; + + ASSERT (ConfigString != NULL); + + // + // Convert all hex digits in range [A-F] in the configuration header to [a-f] + // + for (String = ConfigString, Lower = FALSE; *String != L'\0'; String++) { + if (*String == L'=') { + Lower = TRUE; + } else if (*String == L'&') { + Lower = FALSE; + } else if (Lower && *String >= L'A' && *String <= L'F') { + *String = (CHAR16) (*String - L'A' + L'a'); + } + } + + return ConfigString; +} + +/** + Allocates and returns a Null-terminated Unicode 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 hexadecimal 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; + UINTN NameSize; + EFI_GUID *Guid; + UINTN MaxLen; + + ASSERT (OpCodeData != NULL); + + switch (((EFI_IFR_OP_HEADER *)OpCodeData)->OpCode) { + case EFI_IFR_VARSTORE_OP: + Guid = (EFI_GUID *)(UINTN *)&((EFI_IFR_VARSTORE *) OpCodeData)->Guid; + AsciiName = (CHAR8 *) ((EFI_IFR_VARSTORE *) OpCodeData)->Name; + break; + + case EFI_IFR_VARSTORE_NAME_VALUE_OP: + Guid = (EFI_GUID *)(UINTN *)&((EFI_IFR_VARSTORE_NAME_VALUE *) OpCodeData)->Guid; + AsciiName = NULL; + break; + + case EFI_IFR_VARSTORE_EFI_OP: + Guid = (EFI_GUID *)(UINTN *)&((EFI_IFR_VARSTORE_EFI *) OpCodeData)->Guid; + AsciiName = (CHAR8 *) ((EFI_IFR_VARSTORE_EFI *) OpCodeData)->Name; + break; + + default: + ASSERT (FALSE); + Guid = NULL; + AsciiName = NULL; + break; + } + + if (AsciiName != NULL) { + NameSize = AsciiStrSize (AsciiName); + Name = AllocateZeroPool (NameSize * sizeof (CHAR16)); + ASSERT (Name != NULL); + AsciiStrToUnicodeStrS (AsciiName, Name, NameSize); + } else { + Name = NULL; + } + + // + // Compute the length of Name in Unicode characters. + // If Name is NULL, then the length is 0. + // + NameLength = 0; + if (Name != NULL) { + NameLength = StrLen (Name); + } + + DevicePath = NULL; + DevicePathSize = 0; + // + // Retrieve DevicePath Protocol associated with DriverHandle + // + if (DriverHandle != NULL) { + DevicePath = DevicePathFromHandle (DriverHandle); + if (DevicePath == NULL) { + return NULL; + } + // + // Compute the size of the device path in bytes + // + DevicePathSize = GetDevicePathSize (DevicePath); + } + + // + // GUID=32&NAME=NameLength&PATH=DevicePathSize + // | 5 | sizeof (EFI_GUID) * 2 | 6 | NameStrLen*4 | 6 | DevicePathSize * 2 | 1 | + // + MaxLen = 5 + sizeof (EFI_GUID) * 2 + 6 + NameLength * 4 + 6 + DevicePathSize * 2 + 1; + String = AllocateZeroPool (MaxLen * sizeof (CHAR16)); + if (String == NULL) { + return NULL; + } + + // + // Start with L"GUID=" + // + StrCpyS (String, MaxLen, L"GUID="); + ReturnString = String; + String += StrLen (String); + + if (Guid != NULL) { + // + // Append Guid converted to 32 + // + for (Index = 0, Buffer = (UINT8 *)Guid; Index < sizeof (EFI_GUID); Index++) { + UnicodeValueToStringS ( + String, + MaxLen * sizeof (CHAR16) - ((UINTN)String - (UINTN)ReturnString), + PREFIX_ZERO | RADIX_HEX, + *(Buffer++), + 2 + ); + String += StrnLenS (String, MaxLen - ((UINTN)String - (UINTN)ReturnString) / sizeof (CHAR16)); + } + } + + // + // Append L"&NAME=" + // + StrCatS (ReturnString, MaxLen, L"&NAME="); + String += StrLen (String); + + if (Name != NULL) { + // + // Append Name converted to NameLength + // + for (; *Name != L'\0'; Name++) { + UnicodeValueToStringS ( + String, + MaxLen * sizeof (CHAR16) - ((UINTN)String - (UINTN)ReturnString), + PREFIX_ZERO | RADIX_HEX, + *Name, + 4 + ); + String += StrnLenS (String, MaxLen - ((UINTN)String - (UINTN)ReturnString) / sizeof (CHAR16)); + } + } + + // + // Append L"&PATH=" + // + StrCatS (ReturnString, MaxLen, L"&PATH="); + String += StrLen (String); + + // + // Append the device path associated with DriverHandle converted to DevicePathSize + // + for (Index = 0, Buffer = (UINT8 *)DevicePath; Index < DevicePathSize; Index++) { + UnicodeValueToStringS ( + String, + MaxLen * sizeof (CHAR16) - ((UINTN)String - (UINTN)ReturnString), + PREFIX_ZERO | RADIX_HEX, + *(Buffer++), + 2 + ); + String += StrnLenS (String, MaxLen - ((UINTN)String - (UINTN)ReturnString) / sizeof (CHAR16)); + } + + // + // Null terminate the Unicode string + // + *String = L'\0'; + + // + // Convert all hex digits in range [A-F] in the configuration header to [a-f] + // + return InternalLowerConfigString (ReturnString); +} + +/** + Generate the Config request element for one question. + + @param Name The name info for one question. + @param Offset The offset info for one question. + @param Width The width info for one question. + + @return Pointer to the Null-terminated Unicode request element string. + +**/ +EFI_STRING +ConstructRequestElement ( + IN CHAR16 *Name, + IN UINT16 Offset, + IN UINT16 Width + ) +{ + CHAR16 *StringPtr; + UINTN Length; + + if (Name != NULL) { + // + // Add 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 MaxLen; + CHAR16 *StringPtr; + + ASSERT (DatabaseRecord != NULL && OpCodeData != NULL && ConfigRequest != NULL); + + OpCode = NULL; + Name = NULL; + Width = 0; + Offset = 0; + + PackageListNode = DatabaseRecord->PackageList; + + // + // Search the languages in the specified packagelist. + // + for (Link = PackageListNode->FormPkgHdr.ForwardLink; Link != &PackageListNode->FormPkgHdr; Link = Link->ForwardLink) { + FormPackage = CR (Link, HII_IFR_PACKAGE_INSTANCE, IfrEntry, HII_IFR_PACKAGE_SIGNATURE); + + OpCode = FindQuestionFromStringId (FormPackage, KeywordStrId); + if (OpCode != NULL) { + *OpCodeData = OpCode; + Header = (EFI_IFR_QUESTION_HEADER *) (OpCode + sizeof (EFI_IFR_OP_HEADER)); + // + // Header->VarStoreId == 0 means no storage for this question. + // + ASSERT (Header->VarStoreId != 0); + DEBUG ((EFI_D_INFO, "Varstore Id: 0x%x\n", Header->VarStoreId)); + + Storage = FindStorageFromVarId (FormPackage, Header->VarStoreId); + ASSERT (Storage != NULL); + + if (((EFI_IFR_OP_HEADER *) Storage)->OpCode == EFI_IFR_VARSTORE_NAME_VALUE_OP) { + Name = GetNameFromId (DatabaseRecord, Header->VarStoreInfo.VarName); + } else { + Offset = Header->VarStoreInfo.VarOffset; + Width = GetWidth (OpCode); + } + RequestElement = ConstructRequestElement(Name, Offset, Width); + ConfigHdr = ConstructConfigHdr(Storage, DatabaseRecord->DriverHandle); + ASSERT (ConfigHdr != NULL); + + MaxLen = StrLen (ConfigHdr) + 1 + StrLen(RequestElement) + 1; + *ConfigRequest = AllocatePool (MaxLen * sizeof (CHAR16)); + if (*ConfigRequest == NULL) { + FreePool (ConfigHdr); + FreePool (RequestElement); + return EFI_OUT_OF_RESOURCES; + } + StringPtr = *ConfigRequest; + + StrCpyS (StringPtr, MaxLen, ConfigHdr); + + StrCatS (StringPtr, MaxLen, L"&"); + + StrCatS (StringPtr, MaxLen, RequestElement); + + FreePool (ConfigHdr); + FreePool (RequestElement); + + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + +/** + Base on the input parameter to generate the ConfigResp string. + + This is a internal function. + + @param DatabaseRecord HII_DATABASE_RECORD format string. + @param KeywordStrId Keyword string id. + @param ValueElement The value for the question which use keyword string id + as the prompt string id. + @param OpCodeData The IFR data for this question. + @param ConfigResp Return the generate ConfigResp string. + + @retval EFI_SUCCESS Generate ConfigResp string success. + @retval EFI_OUT_OF_RESOURCES System out of memory resource error. + @retval EFI_NOT_FOUND Not found the question which use this string id + as the prompt string id. +**/ +EFI_STATUS +ExtractConfigResp ( + IN HII_DATABASE_RECORD *DatabaseRecord, + IN EFI_STRING_ID KeywordStrId, + IN EFI_STRING ValueElement, + OUT UINT8 **OpCodeData, + OUT EFI_STRING *ConfigResp + ) +{ + LIST_ENTRY *Link; + HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageListNode; + HII_IFR_PACKAGE_INSTANCE *FormPackage; + EFI_IFR_QUESTION_HEADER *Header; + UINT8 *Storage; + UINT8 *OpCode; + CHAR16 *Name; + UINT16 Offset; + UINT16 Width; + CHAR16 *ConfigHdr; + CHAR16 *RequestElement; + UINTN MaxLen; + CHAR16 *StringPtr; + + ASSERT ((DatabaseRecord != NULL) && (OpCodeData != NULL) && (ConfigResp != NULL) && (ValueElement != NULL)); + + OpCode = NULL; + Name = NULL; + Width = 0; + Offset = 0; + + PackageListNode = DatabaseRecord->PackageList; + + // + // Search the languages in the specified packagelist. + // + for (Link = PackageListNode->FormPkgHdr.ForwardLink; Link != &PackageListNode->FormPkgHdr; Link = Link->ForwardLink) { + FormPackage = CR (Link, HII_IFR_PACKAGE_INSTANCE, IfrEntry, HII_IFR_PACKAGE_SIGNATURE); + + OpCode = FindQuestionFromStringId (FormPackage, KeywordStrId); + if (OpCode != NULL) { + *OpCodeData = OpCode; + Header = (EFI_IFR_QUESTION_HEADER *) (OpCode + sizeof (EFI_IFR_OP_HEADER)); + // + // Header->VarStoreId == 0 means no storage for this question. + // + ASSERT (Header->VarStoreId != 0); + DEBUG ((EFI_D_INFO, "Varstore Id: 0x%x\n", Header->VarStoreId)); + + Storage = FindStorageFromVarId (FormPackage, Header->VarStoreId); + ASSERT (Storage != NULL); + + if (((EFI_IFR_OP_HEADER *) Storage)->OpCode == EFI_IFR_VARSTORE_NAME_VALUE_OP) { + Name = GetNameFromId (DatabaseRecord, Header->VarStoreInfo.VarName); + } else { + Offset = Header->VarStoreInfo.VarOffset; + Width = GetWidth (OpCode); + } + RequestElement = ConstructRequestElement(Name, Offset, Width); + + ConfigHdr = ConstructConfigHdr(Storage, DatabaseRecord->DriverHandle); + ASSERT (ConfigHdr != NULL); + + MaxLen = StrLen (ConfigHdr) + 1 + StrLen(RequestElement) + 1 + StrLen (L"VALUE=") + StrLen(ValueElement) + 1; + *ConfigResp = AllocatePool (MaxLen * sizeof (CHAR16)); + if (*ConfigResp == NULL) { + FreePool (ConfigHdr); + FreePool (RequestElement); + return EFI_OUT_OF_RESOURCES; + } + StringPtr = *ConfigResp; + + StrCpyS (StringPtr, MaxLen, ConfigHdr); + + StrCatS (StringPtr, MaxLen, L"&"); + + + StrCatS (StringPtr, MaxLen, RequestElement); + + StrCatS (StringPtr, MaxLen, L"&"); + + StrCatS (StringPtr, MaxLen, L"VALUE="); + + StrCatS (StringPtr, MaxLen, ValueElement); + + FreePool (ConfigHdr); + FreePool (RequestElement); + + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + +/** + Get the Value section from the Hii driver. + + This is a internal function. + + @param ConfigRequest The input ConfigRequest string. + @param ValueElement The respond Value section from the hii driver. + + @retval Misc value The error status return from ExtractConfig function. + @retval EFI_OUT_OF_RESOURCES The memory can't be allocated + @retval EFI_SUCCESS Get the value section success. + +**/ +EFI_STATUS +ExtractValueFromDriver ( + IN CHAR16 *ConfigRequest, + OUT CHAR16 **ValueElement + ) +{ + EFI_STATUS Status; + EFI_STRING Result; + EFI_STRING Progress; + CHAR16 *StringPtr; + CHAR16 *StringEnd; + + ASSERT ((ConfigRequest != NULL) && (ValueElement != NULL)); + + Status = mPrivate.ConfigRouting.ExtractConfig ( + &mPrivate.ConfigRouting, + (EFI_STRING) ConfigRequest, + &Progress, + &Result + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Find Value Section and return it. + // + StringPtr = StrStr (Result, L"&VALUE="); + ASSERT (StringPtr != NULL); + StringEnd = StrStr (StringPtr + 1, L"&"); + if (StringEnd != NULL) { + *StringEnd = L'\0'; + } + + *ValueElement = AllocateCopyPool (StrSize (StringPtr), StringPtr); + if (*ValueElement == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + if (StringEnd != NULL) { + *StringEnd = L'&'; + } + FreePool (Result); + + return EFI_SUCCESS; +} + +/** + Get EFI_STRING_ID info from the input device path, namespace and keyword. + + This is a internal function. + + @param DevicePath Input device path info. + @param NameSpace NameSpace format string. + @param KeywordData Keyword used to get string id. + @param ProgressErr Return extra error type. + @param KeywordStringId Return EFI_STRING_ID. + @param DataBaseRecord DataBase record data for this driver. + + @retval EFI_INVALID_PARAMETER Can't find the database record base on the input device path or namespace. + @retval EFI_NOT_FOUND Can't find the EFI_STRING_ID for the keyword. + @retval EFI_SUCCESS Find the EFI_STRING_ID. + +**/ +EFI_STATUS +GetStringIdFromDatabase ( + IN EFI_DEVICE_PATH_PROTOCOL **DevicePath, + IN CHAR8 **NameSpace, + IN CHAR16 *KeywordData, + OUT UINT32 *ProgressErr, + OUT EFI_STRING_ID *KeywordStringId, + OUT HII_DATABASE_RECORD **DataBaseRecord + ) +{ + HII_DATABASE_RECORD *Record; + LIST_ENTRY *Link; + BOOLEAN FindNameSpace; + EFI_DEVICE_PATH_PROTOCOL *DestDevicePath; + UINT8 *DevicePathPkg; + UINTN DevicePathSize; + + ASSERT ((NameSpace != NULL) && (KeywordData != NULL) && (ProgressErr != NULL) && (KeywordStringId != NULL) && (DataBaseRecord != NULL)); + + FindNameSpace = FALSE; + + if (*DevicePath != NULL) { + // + // Get DataBaseRecord from device path protocol. + // + Record = GetRecordFromDevicePath(*DevicePath); + if (Record == NULL) { + // + // Can't find the DatabaseRecord base on the input device path info. + // NEED TO CONFIRM the return ProgressErr. + // + *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING; + return EFI_INVALID_PARAMETER; + } + + // + // Get string id from the record. + // + *ProgressErr = GetStringIdFromRecord (Record, NameSpace, KeywordData, KeywordStringId); + switch (*ProgressErr) { + case KEYWORD_HANDLER_NO_ERROR: + *DataBaseRecord = Record; + return EFI_SUCCESS; + + case KEYWORD_HANDLER_NAMESPACE_ID_NOT_FOUND: + return EFI_INVALID_PARAMETER; + + default: + ASSERT (*ProgressErr == KEYWORD_HANDLER_KEYWORD_NOT_FOUND); + return EFI_NOT_FOUND; + } + } else { + // + // Find driver which matches the routing data. + // + for (Link = mPrivate.DatabaseList.ForwardLink; Link != &mPrivate.DatabaseList; Link = Link->ForwardLink) { + Record = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE); + + *ProgressErr = GetStringIdFromRecord (Record, NameSpace, KeywordData, KeywordStringId); + if (*ProgressErr == KEYWORD_HANDLER_NO_ERROR) { + *DataBaseRecord = Record; + + if ((DevicePathPkg = Record->PackageList->DevicePathPkg) != NULL) { + DestDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) (DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER)); + DevicePathSize = GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) DestDevicePath); + *DevicePath = AllocateCopyPool (DevicePathSize, DestDevicePath); + if (*DevicePath == NULL) { + return EFI_OUT_OF_RESOURCES; + } + } else { + // + // Need to verify this ASSERT. + // + ASSERT (FALSE); + } + + return EFI_SUCCESS; + } else if (*ProgressErr == KEYWORD_HANDLER_UNDEFINED_PROCESSING_ERROR) { + return EFI_OUT_OF_RESOURCES; + } else if (*ProgressErr == KEYWORD_HANDLER_KEYWORD_NOT_FOUND) { + FindNameSpace = TRUE; + } + } + + // + // When PathHdr not input, if ever find the namespace, will return KEYWORD_HANDLER_KEYWORD_NOT_FOUND. + // This is a bit more progress than KEYWORD_HANDLER_NAMESPACE_ID_NOT_FOUND. + // + if (FindNameSpace) { + return EFI_NOT_FOUND; + } else { + return EFI_INVALID_PARAMETER; + } + } +} + +/** + Generate the KeywordResp String. + + ::= '&''&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; + UINTN NameSpaceLength; + + ASSERT ((NameSpace != NULL) && (DevicePath != NULL) && (KeywordData != NULL) && (ValueStr != NULL) && (KeywordResp != NULL)); + + // + // 1. Calculate the string length. + // + // + // 1.1 NameSpaceId size. + // 'NAMESPACE=' + // + NameSpaceLength = AsciiStrLen (NameSpace); + RespStrLen = 10 + NameSpaceLength; + UnicodeNameSpace = AllocatePool ((NameSpaceLength + 1) * sizeof (CHAR16)); + if (UnicodeNameSpace == NULL) { + return EFI_OUT_OF_RESOURCES; + } + AsciiStrToUnicodeStrS (NameSpace, UnicodeNameSpace, NameSpaceLength + 1); + + // + // 1.2 PathHdr size. + // PATH='&' + // Attention: The output include the '&' at the end. + // + GenerateSubStr ( + L"&PATH=", + GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) DevicePath), + (VOID *) DevicePath, + 1, + &PathHdr + ); + RespStrLen += StrLen (PathHdr); + + // + // 1.3 Keyword section. + // 'KEYWORD='[':'(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 include '\0'. + // + RespStrLen += 1; + *KeywordResp = AllocatePool (RespStrLen * sizeof (CHAR16)); + if (*KeywordResp == NULL) { + if (UnicodeNameSpace != NULL) { + FreePool (UnicodeNameSpace); + } + + return EFI_OUT_OF_RESOURCES; + } + RespStr = *KeywordResp; + + // + // 2.1 Copy NameSpaceId section. + // + StrCpyS (RespStr, RespStrLen, L"NAMESPACE="); + + StrCatS (RespStr, RespStrLen, UnicodeNameSpace); + + // + // 2.2 Copy PathHdr section. + // + StrCatS (RespStr, RespStrLen, PathHdr); + + // + // 2.3 Copy Keyword section. + // + StrCatS (RespStr, RespStrLen, L"KEYWORD="); + + StrCatS (RespStr, RespStrLen, KeywordData); + + // + // 2.4 Copy the Value section. + // + StrCatS (RespStr, RespStrLen, ValueStr); + + // + // 2.5 Copy ReadOnly section if exist. + // + if (ReadOnly) { + StrCatS (RespStr, RespStrLen, L"&READONLY"); + } + + if (UnicodeNameSpace != NULL) { + FreePool (UnicodeNameSpace); + } + if (PathHdr != NULL) { + FreePool (PathHdr); + } + + return EFI_SUCCESS; +} + +/** + Merge the KeywordResp String to MultiKeywordResp string. + + This is a internal function. + + @param MultiKeywordResp The existed multikeywordresp string. + @param KeywordResp The input keywordResp string. + + @retval EFI_OUT_OF_RESOURCES The memory can't be allocated. + @retval EFI_SUCCESS Generate the MultiKeywordResp string. + +**/ +EFI_STATUS +MergeToMultiKeywordResp ( + IN OUT EFI_STRING *MultiKeywordResp, + IN EFI_STRING *KeywordResp + ) +{ + UINTN MultiKeywordRespLen; + EFI_STRING StringPtr; + + if (*MultiKeywordResp == NULL) { + *MultiKeywordResp = *KeywordResp; + *KeywordResp = NULL; + return EFI_SUCCESS; + } + + MultiKeywordRespLen = (StrLen (*MultiKeywordResp) + 1 + StrLen (*KeywordResp) + 1) * sizeof (CHAR16); + + StringPtr = ReallocatePool ( + StrSize (*MultiKeywordResp), + MultiKeywordRespLen, + *MultiKeywordResp + ); + if (StringPtr == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + *MultiKeywordResp = StringPtr; + + StrCatS (StringPtr, MultiKeywordRespLen / sizeof (CHAR16), L"&"); + + StrCatS (StringPtr, MultiKeywordRespLen / sizeof (CHAR16), *KeywordResp); + + return EFI_SUCCESS; +} + +/** + Enumerate all keyword in the system. + + If error occur when parse one keyword, just skip it and parse the next one. + + This is a internal function. + + @param NameSpace The namespace used to search the string. + @param MultiResp Return the MultiKeywordResp string for the system. + @param ProgressErr Return the error status. + + @retval EFI_OUT_OF_RESOURCES The memory can't be allocated. + @retval EFI_SUCCESS Generate the MultiKeywordResp string. + @retval EFI_NOT_FOUND No keyword found. + +**/ +EFI_STATUS +EnumerateAllKeywords ( + IN CHAR8 *NameSpace, + OUT EFI_STRING *MultiResp, + OUT UINT32 *ProgressErr + ) +{ + LIST_ENTRY *Link; + LIST_ENTRY *StringLink; + UINT8 *DevicePathPkg; + UINT8 *DevicePath; + HII_DATABASE_RECORD *DataBaseRecord; + HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageListNode; + HII_STRING_PACKAGE_INSTANCE *StringPackage; + CHAR8 *LocalNameSpace; + EFI_STRING_ID NextStringId; + EFI_STATUS Status; + UINT8 *OpCode; + CHAR16 *ConfigRequest; + CHAR16 *ValueElement; + CHAR16 *KeywordResp; + CHAR16 *MultiKeywordResp; + CHAR16 *KeywordData; + BOOLEAN ReadOnly; + BOOLEAN FindKeywordPackages; + + DataBaseRecord = NULL; + Status = EFI_SUCCESS; + MultiKeywordResp = NULL; + DevicePath = NULL; + LocalNameSpace = NULL; + ConfigRequest = NULL; + ValueElement = NULL; + KeywordResp = NULL; + FindKeywordPackages = FALSE; + + if (NameSpace == NULL) { + NameSpace = UEFI_CONFIG_LANG; + } + + // + // Find driver which matches the routing data. + // + for (Link = mPrivate.DatabaseList.ForwardLink; Link != &mPrivate.DatabaseList; Link = Link->ForwardLink) { + DataBaseRecord = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE); + if ((DevicePathPkg = DataBaseRecord->PackageList->DevicePathPkg) != NULL) { + DevicePath = DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER); + } + PackageListNode = DataBaseRecord->PackageList; + + for (StringLink = PackageListNode->StringPkgHdr.ForwardLink; StringLink != &PackageListNode->StringPkgHdr; StringLink = StringLink->ForwardLink) { + StringPackage = CR (StringLink, HII_STRING_PACKAGE_INSTANCE, StringEntry, HII_STRING_PACKAGE_SIGNATURE); + + // + // Check whether has keyword string package. + // + if (AsciiStrnCmp(NameSpace, StringPackage->StringPkgHdr->Language, AsciiStrLen (NameSpace)) == 0) { + FindKeywordPackages = TRUE; + // + // Keep the NameSpace string. + // + LocalNameSpace = AllocateCopyPool (AsciiStrSize (StringPackage->StringPkgHdr->Language), StringPackage->StringPkgHdr->Language); + if (LocalNameSpace == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // 1 means just begin the enumerate the valid string ids. + // StringId == 1 is always used to save the language for this string package. + // Any valid string start from 2. so here initial it to 1. + // + NextStringId = 1; + + // + // Enumerate all valid stringid in the package. + // + while ((NextStringId = GetNextStringId (StringPackage, NextStringId, &KeywordData)) != 0) { + // + // 3.3 Construct the ConfigRequest string. + // + Status = ExtractConfigRequest (DataBaseRecord, NextStringId, &OpCode, &ConfigRequest); + if (EFI_ERROR (Status)) { + // + // If can't generate ConfigRequest for this question, skip it and start the next. + // + goto Error; + } + + // + // 3.4 Extract Value for the input keyword. + // + Status = ExtractValueFromDriver(ConfigRequest, &ValueElement); + if (EFI_ERROR (Status)) { + if (Status != EFI_OUT_OF_RESOURCES) { + // + // If can't generate ConfigRequest for this question, skip it and start the next. + // + goto Error; + } + // + // If EFI_OUT_OF_RESOURCES error occur, no need to continue. + // + goto Done; + } + + // + // Extract readonly flag from opcode. + // + ReadOnly = ExtractReadOnlyFromOpCode(OpCode); + + // + // 5. Generate KeywordResp string. + // + ASSERT (DevicePath != NULL); + Status = GenerateKeywordResp(LocalNameSpace, (EFI_DEVICE_PATH_PROTOCOL *)DevicePath, KeywordData, ValueElement, ReadOnly, &KeywordResp); + if (Status != EFI_SUCCESS) { + // + // If EFI_OUT_OF_RESOURCES error occur, no need to continue. + // + goto Done; + } + + // + // 6. Merge to the MultiKeywordResp string. + // + Status = MergeToMultiKeywordResp(&MultiKeywordResp, &KeywordResp); + if (EFI_ERROR (Status)) { + goto Done; + } +Error: + // + // Clean the temp buffer to later use again. + // + if (ConfigRequest != NULL) { + FreePool (ConfigRequest); + ConfigRequest = NULL; + } + if (ValueElement != NULL) { + FreePool (ValueElement); + ValueElement = NULL; + } + if (KeywordResp != NULL) { + FreePool (KeywordResp); + KeywordResp = NULL; + } + } + + if (LocalNameSpace != NULL) { + FreePool (LocalNameSpace); + LocalNameSpace = NULL; + } + } + } + } + + // + // return the already get MultiKeywordString even error occurred. + // + if (MultiKeywordResp == NULL) { + Status = EFI_NOT_FOUND; + if (!FindKeywordPackages) { + *ProgressErr = KEYWORD_HANDLER_NAMESPACE_ID_NOT_FOUND; + } else { + *ProgressErr = KEYWORD_HANDLER_KEYWORD_NOT_FOUND; + } + } else { + Status = EFI_SUCCESS; + } + *MultiResp = MultiKeywordResp; + +Done: + if (LocalNameSpace != NULL) { + FreePool (LocalNameSpace); + } + if (ConfigRequest != NULL) { + FreePool (ConfigRequest); + } + if (ValueElement != NULL) { + FreePool (ValueElement); + } + + return Status; +} + +/** + + This function accepts a 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 name / value pair (or the beginning + of the string if the failure is in the first name / value + pair) if the request was not successful. + + @param ProgressErr If during the processing of the KeywordString there was + a failure, this parameter gives additional information + about the possible source of the problem. The various + errors are defined in "Related Definitions" below. + + + @retval EFI_SUCCESS The specified action was completed successfully. + + @retval EFI_INVALID_PARAMETER One or more of the following are TRUE: + 1. KeywordString is NULL. + 2. Parsing of the KeywordString resulted in an + error. See Progress and ProgressErr for more data. + + @retval EFI_NOT_FOUND An element of the KeywordString was not found. + See ProgressErr for more data. + + @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. + See ProgressErr for more data. + + @retval EFI_ACCESS_DENIED The action violated system policy. See ProgressErr + for more data. + + @retval EFI_DEVICE_ERROR An unexpected system error occurred. See ProgressErr + for more data. + +**/ +EFI_STATUS +EFIAPI +EfiConfigKeywordHandlerSetData ( + IN EFI_CONFIG_KEYWORD_HANDLER_PROTOCOL *This, + IN CONST EFI_STRING KeywordString, + OUT EFI_STRING *Progress, + OUT UINT32 *ProgressErr + ) +{ + CHAR8 *NameSpace; + EFI_STATUS Status; + CHAR16 *StringPtr; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + CHAR16 *NextStringPtr; + CHAR16 *KeywordData; + EFI_STRING_ID KeywordStringId; + UINT32 RetVal; + HII_DATABASE_RECORD *DataBaseRecord; + UINT8 *OpCode; + CHAR16 *ConfigResp; + CHAR16 *MultiConfigResp; + CHAR16 *ValueElement; + BOOLEAN ReadOnly; + EFI_STRING InternalProgress; + CHAR16 *TempString; + CHAR16 *KeywordStartPos; + + if (This == NULL || Progress == NULL || ProgressErr == NULL || KeywordString == NULL) { + return EFI_INVALID_PARAMETER; + } + + *Progress = KeywordString; + *ProgressErr = KEYWORD_HANDLER_UNDEFINED_PROCESSING_ERROR; + Status = EFI_SUCCESS; + MultiConfigResp = NULL; + NameSpace = NULL; + DevicePath = NULL; + KeywordData = NULL; + ValueElement = NULL; + ConfigResp = NULL; + KeywordStartPos = NULL; + KeywordStringId = 0; + + // + // Use temp string to avoid changing input string buffer. + // + TempString = AllocateCopyPool (StrSize (KeywordString), KeywordString); + ASSERT (TempString != NULL); + StringPtr = TempString; + + while ((StringPtr != NULL) && (*StringPtr != L'\0')) { + // + // 1. Get NameSpace from NameSpaceId keyword. + // + Status = ExtractNameSpace (StringPtr, &NameSpace, &NextStringPtr); + if (EFI_ERROR (Status)) { + *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING; + goto Done; + } + ASSERT (NameSpace != NULL); + // + // 1.1 Check whether the input namespace is valid. + // + if (AsciiStrnCmp(NameSpace, UEFI_CONFIG_LANG, AsciiStrLen (UEFI_CONFIG_LANG)) != 0) { + *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING; + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + StringPtr = NextStringPtr; + + // + // 2. Get possible Device Path info from KeywordString. + // + Status = ExtractDevicePath (StringPtr, (UINT8 **)&DevicePath, &NextStringPtr); + if (EFI_ERROR (Status)) { + *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING; + goto Done; + } + StringPtr = NextStringPtr; + + // + // 3. Extract keyword from the KeywordRequest string. + // + KeywordStartPos = StringPtr; + Status = ExtractKeyword(StringPtr, &KeywordData, &NextStringPtr); + if (EFI_ERROR (Status)) { + // + // Can't find Keyword base on the input device path info. + // + *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING; + Status = EFI_INVALID_PARAMETER; + goto Done; + } + StringPtr = NextStringPtr; + + // + // 4. Extract Value from the KeywordRequest string. + // + Status = ExtractValue (StringPtr, &ValueElement, &NextStringPtr); + if (EFI_ERROR (Status)) { + // + // Can't find Value base on the input device path info. + // + *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING; + Status = EFI_INVALID_PARAMETER; + goto Done; + } + StringPtr = NextStringPtr; + + // + // 5. Find READONLY tag. + // + if ((StringPtr != NULL) && StrnCmp (StringPtr, L"&READONLY", StrLen (L"&READONLY")) == 0) { + ReadOnly = TRUE; + StringPtr += StrLen (L"&READONLY"); + } else { + ReadOnly = FALSE; + } + + // + // 6. Get EFI_STRING_ID for the input keyword. + // + Status = GetStringIdFromDatabase (&DevicePath, &NameSpace, KeywordData, &RetVal, &KeywordStringId, &DataBaseRecord); + if (EFI_ERROR (Status)) { + *ProgressErr = RetVal; + goto Done; + } + + // + // 7. Construct the ConfigRequest string. + // + Status = ExtractConfigResp (DataBaseRecord, KeywordStringId, ValueElement, &OpCode, &ConfigResp); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // 8. Check the readonly flag. + // + if (ExtractReadOnlyFromOpCode (OpCode) != ReadOnly) { + // + // Extracting readonly flag form opcode and extracting "READONLY" tag form KeywordString should have the same results. + // If not, the input KeywordString must be incorrect, return the error status to caller. + // + *ProgressErr = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED; + Status = EFI_INVALID_PARAMETER; + goto Done; + } + if (ReadOnly) { + *ProgressErr = KEYWORD_HANDLER_ACCESS_NOT_PERMITTED; + Status = EFI_ACCESS_DENIED; + goto Done; + } + + // + // 9. Merge to the MultiKeywordResp string. + // + Status = MergeToMultiKeywordResp(&MultiConfigResp, &ConfigResp); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // 10. Clean the temp buffer point. + // + FreePool (NameSpace); + FreePool (DevicePath); + FreePool (KeywordData); + FreePool (ValueElement); + NameSpace = NULL; + DevicePath = NULL; + KeywordData = NULL; + ValueElement = NULL; + if (ConfigResp != NULL) { + FreePool (ConfigResp); + ConfigResp = NULL; + } + KeywordStartPos = NULL; + } + + // + // 11. Set value to driver. + // + Status = mPrivate.ConfigRouting.RouteConfig( + &mPrivate.ConfigRouting, + (EFI_STRING) MultiConfigResp, + &InternalProgress + ); + if (EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + goto Done; + } + + *ProgressErr = KEYWORD_HANDLER_NO_ERROR; + +Done: + if (KeywordStartPos != NULL) { + *Progress = KeywordString + (KeywordStartPos - TempString); + } else { + *Progress = KeywordString + (StringPtr - TempString); + } + + ASSERT (TempString != NULL); + FreePool (TempString); + if (NameSpace != NULL) { + FreePool (NameSpace); + } + if (DevicePath != NULL) { + FreePool (DevicePath); + } + if (KeywordData != NULL) { + FreePool (KeywordData); + } + if (ValueElement != NULL) { + FreePool (ValueElement); + } + if (ConfigResp != NULL) { + FreePool (ConfigResp); + } + if (MultiConfigResp != NULL && MultiConfigResp != ConfigResp) { + FreePool (MultiConfigResp); + } + + return Status; +} + +/** + + This function accepts a 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 name / value + pair (or the beginning of the string if the failure is in the first + name / value pair) if the request was not successful. + + @param ProgressErr If during the processing of the KeywordString there was a + failure, this parameter gives additional information about the + possible source of the problem. See the definitions in SetData() + for valid value definitions. + + @param Results A null-terminated string in format is returned + which has all the values filled in for the keywords in the + KeywordString. This is a callee-allocated field, and must be freed + by the caller after being used. + + @retval EFI_SUCCESS The specified action was completed successfully. + + @retval EFI_INVALID_PARAMETER One or more of the following are TRUE: + 1.Progress, ProgressErr, or Results is NULL. + 2.Parsing of the KeywordString resulted in an error. See + Progress and ProgressErr for more data. + + + @retval EFI_NOT_FOUND An element of the KeywordString was not found. See + ProgressErr for more data. + + @retval EFI_NOT_FOUND The NamespaceId specified was not found. See ProgressErr + for more data. + + @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. See + ProgressErr for more data. + + @retval EFI_ACCESS_DENIED The action violated system policy. See ProgressErr for + more data. + + @retval EFI_DEVICE_ERROR An unexpected system error occurred. See ProgressErr + for more data. + +**/ +EFI_STATUS +EFIAPI +EfiConfigKeywordHandlerGetData ( + IN EFI_CONFIG_KEYWORD_HANDLER_PROTOCOL *This, + IN CONST EFI_STRING NameSpaceId, OPTIONAL + IN CONST EFI_STRING KeywordString, OPTIONAL + OUT EFI_STRING *Progress, + OUT UINT32 *ProgressErr, + OUT EFI_STRING *Results + ) +{ + CHAR8 *NameSpace; + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + HII_DATABASE_RECORD *DataBaseRecord; + CHAR16 *StringPtr; + CHAR16 *NextStringPtr; + CHAR16 *KeywordData; + EFI_STRING_ID KeywordStringId; + UINT8 *OpCode; + CHAR16 *ConfigRequest; + CHAR16 *ValueElement; + UINT32 RetVal; + BOOLEAN ReadOnly; + CHAR16 *KeywordResp; + CHAR16 *MultiKeywordResp; + CHAR16 *TempString; + + if (This == NULL || Progress == NULL || ProgressErr == NULL || Results == NULL) { + return EFI_INVALID_PARAMETER; + } + + *ProgressErr = KEYWORD_HANDLER_UNDEFINED_PROCESSING_ERROR; + Status = EFI_SUCCESS; + DevicePath = NULL; + NameSpace = NULL; + KeywordData = NULL; + ConfigRequest= NULL; + StringPtr = KeywordString; + ReadOnly = FALSE; + MultiKeywordResp = NULL; + KeywordStringId = 0; + TempString = NULL; + + // + // Use temp string to avoid changing input string buffer. + // + if (NameSpaceId != NULL) { + TempString = AllocateCopyPool (StrSize (NameSpaceId), NameSpaceId); + ASSERT (TempString != NULL); + } + // + // 1. Get NameSpace from NameSpaceId keyword. + // + Status = ExtractNameSpace (TempString, &NameSpace, NULL); + if (TempString != NULL) { + FreePool (TempString); + TempString = NULL; + } + if (EFI_ERROR (Status)) { + *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING; + return Status; + } + // + // 1.1 Check whether the input namespace is valid. + // + if (NameSpace != NULL){ + if (AsciiStrnCmp(NameSpace, UEFI_CONFIG_LANG, AsciiStrLen (UEFI_CONFIG_LANG)) != 0) { + *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING; + return EFI_INVALID_PARAMETER; + } + } + + if (KeywordString != NULL) { + // + // Use temp string to avoid changing input string buffer. + // + TempString = AllocateCopyPool (StrSize (KeywordString), KeywordString); + ASSERT (TempString != NULL); + StringPtr = TempString; + + while (*StringPtr != L'\0') { + // + // 2. Get possible Device Path info from KeywordString. + // + Status = ExtractDevicePath (StringPtr, (UINT8 **)&DevicePath, &NextStringPtr); + if (EFI_ERROR (Status)) { + *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING; + goto Done; + } + StringPtr = NextStringPtr; + + + // + // 3. Process Keyword section from the input keywordRequest string. + // + // 3.1 Extract keyword from the KeywordRequest string. + // + Status = ExtractKeyword(StringPtr, &KeywordData, &NextStringPtr); + if (EFI_ERROR (Status)) { + // + // Can't find Keyword base on the input device path info. + // + *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING; + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + // + // 3.2 Get EFI_STRING_ID for the input keyword. + // + Status = GetStringIdFromDatabase (&DevicePath, &NameSpace, KeywordData, &RetVal, &KeywordStringId, &DataBaseRecord); + if (EFI_ERROR (Status)) { + *ProgressErr = RetVal; + goto Done; + } + + // + // 3.3 Construct the ConfigRequest string. + // + Status = ExtractConfigRequest (DataBaseRecord, KeywordStringId, &OpCode, &ConfigRequest); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // 3.4 Extract Value for the input keyword. + // + Status = ExtractValueFromDriver(ConfigRequest, &ValueElement); + if (EFI_ERROR (Status)) { + if (Status != EFI_OUT_OF_RESOURCES) { + Status = EFI_DEVICE_ERROR; + } + goto Done; + } + StringPtr = NextStringPtr; + + // + // 4. Process the possible filter section. + // + RetVal = ValidateFilter (OpCode, StringPtr, &NextStringPtr, &ReadOnly); + if (RetVal != KEYWORD_HANDLER_NO_ERROR) { + *ProgressErr = RetVal; + Status = EFI_INVALID_PARAMETER; + goto Done; + } + StringPtr = NextStringPtr; + + + // + // 5. Generate KeywordResp string. + // + Status = GenerateKeywordResp(NameSpace, DevicePath, KeywordData, ValueElement, ReadOnly, &KeywordResp); + if (Status != EFI_SUCCESS) { + goto Done; + } + + // + // 6. Merge to the MultiKeywordResp string. + // + Status = MergeToMultiKeywordResp(&MultiKeywordResp, &KeywordResp); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // 7. Update return value. + // + *Results = MultiKeywordResp; + + // + // 8. Clean the temp buffer. + // + FreePool (DevicePath); + FreePool (KeywordData); + FreePool (ValueElement); + FreePool (ConfigRequest); + DevicePath = NULL; + KeywordData = NULL; + ValueElement = NULL; + ConfigRequest = NULL; + if (KeywordResp != NULL) { + FreePool (KeywordResp); + KeywordResp = NULL; + } + } + } else { + // + // Enumerate all keyword in the system. + // + Status = EnumerateAllKeywords(NameSpace, &MultiKeywordResp, ProgressErr); + if (EFI_ERROR (Status)) { + goto Done; + } + *Results = MultiKeywordResp; + } + + *ProgressErr = KEYWORD_HANDLER_NO_ERROR; + +Done: + *Progress = KeywordString + (StringPtr - TempString); + + if (TempString != NULL) { + FreePool (TempString); + } + if (NameSpace != NULL) { + FreePool (NameSpace); + } + if (DevicePath != NULL) { + FreePool (DevicePath); + } + if (KeywordData != NULL) { + FreePool (KeywordData); + } + + return Status; +} -- cgit