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