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