| /** @file | |
| Implementation of interfaces function for EFI_CONFIG_KEYWORD_HANDLER_PROTOCOL. | |
| Copyright (c) 2015, Intel Corporation. All rights reserved.<BR> | |
| This program and the accompanying materials | |
| are licensed and made available under the terms and conditions of the BSD License | |
| which accompanies this distribution. The full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license.php | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| **/ | |
| #include "HiiDatabase.h" | |
| extern HII_DATABASE_PRIVATE_DATA mPrivate; | |
| /** | |
| Convert the hex UNICODE %02x encoding of a UEFI device path to binary | |
| from <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 neccesary structures. | |
| @retval EFI_SUCCESS The device path is retrieved and translated to binary format. | |
| The Input string not include PathHdr section. | |
| **/ | |
| EFI_STATUS | |
| ExtractDevicePath ( | |
| IN EFI_STRING String, | |
| OUT UINT8 **DevicePathData, | |
| OUT EFI_STRING *NextString | |
| ) | |
| { | |
| UINTN Length; | |
| EFI_STRING PathHdr; | |
| UINT8 *DevicePathBuffer; | |
| CHAR16 TemStr[2]; | |
| UINTN Index; | |
| UINT8 DigitUint8; | |
| EFI_DEVICE_PATH_PROTOCOL *DevicePath; | |
| ASSERT (NextString != NULL && DevicePathData != NULL); | |
| // | |
| // KeywordRequest == NULL case. | |
| // | |
| if (String == NULL) { | |
| *DevicePathData = NULL; | |
| *NextString = NULL; | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // Skip '&' if exist. | |
| // | |
| if (*String == L'&') { | |
| String ++; | |
| } | |
| // | |
| // Find the 'PATH=' of <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; | |
| ASSERT (NameSpace != NULL); | |
| TmpPtr = NULL; | |
| // | |
| // Input NameSpaceId == NULL | |
| // | |
| if (String == NULL) { | |
| *NameSpace = NULL; | |
| if (NextString != NULL) { | |
| *NextString = NULL; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // Skip '&' if exist. | |
| // | |
| if (*String == L'&') { | |
| String++; | |
| } | |
| if (StrnCmp (String, L"NAMESPACE=", StrLen (L"NAMESPACE=")) != 0) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| String += StrLen (L"NAMESPACE="); | |
| TmpPtr = StrStr (String, L"&"); | |
| if (TmpPtr != NULL) { | |
| *TmpPtr = 0; | |
| } | |
| if (NextString != NULL) { | |
| *NextString = String + StrLen (String); | |
| } | |
| // | |
| // Input NameSpace is unicode string. The language in String package is ascii string. | |
| // Here will convert the unicode string to ascii and save it. | |
| // | |
| *NameSpace = AllocatePool (StrLen (String) + 1); | |
| if (*NameSpace == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| UnicodeStrToAsciiStr (String, *NameSpace); | |
| if (TmpPtr != NULL) { | |
| *TmpPtr = L'&'; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Get Keyword from the input KeywordRequest string. | |
| This is a internal function. | |
| @param String KeywordRequestformat string. | |
| @param Keyword return the extract keyword string. | |
| @param NextString return the next string follow this keyword sectin. | |
| @retval EFI_SUCCESS Success to get the keyword string. | |
| @retval EFI_INVALID_PARAMETER Parsr the input string return error. | |
| **/ | |
| EFI_STATUS | |
| ExtractKeyword ( | |
| IN EFI_STRING String, | |
| OUT EFI_STRING *Keyword, | |
| OUT EFI_STRING *NextString | |
| ) | |
| { | |
| EFI_STRING TmpPtr; | |
| ASSERT ((Keyword != NULL) && (NextString != NULL)); | |
| TmpPtr = NULL; | |
| // | |
| // KeywordRequest == NULL case. | |
| // | |
| if (String == NULL) { | |
| *Keyword = NULL; | |
| *NextString = NULL; | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // Skip '&' if exist. | |
| // | |
| if (*String == L'&') { | |
| String++; | |
| } | |
| if (StrnCmp (String, L"KEYWORD=", StrLen (L"KEYWORD=")) != 0) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| String += StrLen (L"KEYWORD="); | |
| TmpPtr = StrStr (String, L"&"); | |
| if (TmpPtr != NULL) { | |
| *TmpPtr = 0; | |
| } | |
| *NextString = String + StrLen (String); | |
| *Keyword = AllocateCopyPool (StrSize (String), String); | |
| if (*Keyword == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| if (TmpPtr != NULL) { | |
| *TmpPtr = L'&'; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Get value from the input KeywordRequest string. | |
| This is a internal function. | |
| @param String KeywordRequestformat string. | |
| @param Value return the extract value string. | |
| @param NextString return the next string follow this keyword sectin. | |
| @retval EFI_SUCCESS Success to get the keyword string. | |
| @retval EFI_INVALID_PARAMETER Parsr the input string return error. | |
| **/ | |
| EFI_STATUS | |
| ExtractValue ( | |
| IN EFI_STRING String, | |
| OUT EFI_STRING *Value, | |
| OUT EFI_STRING *NextString | |
| ) | |
| { | |
| EFI_STRING TmpPtr; | |
| ASSERT ((Value != NULL) && (NextString != NULL) && (String != NULL)); | |
| // | |
| // Skip '&' if exist. | |
| // | |
| if (*String == L'&') { | |
| String++; | |
| } | |
| if (StrnCmp (String, L"VALUE=", StrLen (L"VALUE=")) != 0) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| String += StrLen (L"VALUE="); | |
| TmpPtr = StrStr (String, L"&"); | |
| if (TmpPtr != NULL) { | |
| *TmpPtr = 0; | |
| } | |
| *NextString = String + StrLen (String); | |
| *Value = AllocateCopyPool (StrSize (String), String); | |
| if (*Value == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| if (TmpPtr != NULL) { | |
| *TmpPtr = L'&'; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Get filter from the input KeywordRequest string. | |
| This is a internal function. | |
| @param String KeywordRequestformat string. | |
| @param FilterFlags return the filter condition. | |
| @param NextString return the next string follow this keyword sectin. | |
| @retval EFI_SUCCESS Success to get the keyword string. | |
| @retval EFI_INVALID_PARAMETER Parsr the input string return error. | |
| **/ | |
| BOOLEAN | |
| ExtractFilter ( | |
| IN EFI_STRING String, | |
| OUT UINT8 *FilterFlags, | |
| OUT EFI_STRING *NextString | |
| ) | |
| { | |
| CHAR16 *PathPtr; | |
| CHAR16 *KeywordPtr; | |
| BOOLEAN RetVal; | |
| ASSERT ((FilterFlags != NULL) && (NextString != NULL)); | |
| // | |
| // String end, no filter section. | |
| // | |
| if (String == NULL) { | |
| *NextString = NULL; | |
| return FALSE; | |
| } | |
| *FilterFlags = 0; | |
| RetVal = TRUE; | |
| // | |
| // Skip '&' if exist. | |
| // | |
| if (*String == L'&') { | |
| String++; | |
| } | |
| if (StrnCmp (String, L"ReadOnly", StrLen (L"ReadOnly")) == 0) { | |
| // | |
| // Find ReadOnly filter. | |
| // | |
| *FilterFlags |= EFI_KEYWORD_FILTER_READONY; | |
| String += StrLen (L"ReadOnly"); | |
| } else if (StrnCmp (String, L"ReadWrite", StrLen (L"ReadWrite")) == 0) { | |
| // | |
| // Find ReadWrite filter. | |
| // | |
| *FilterFlags |= EFI_KEYWORD_FILTER_REAWRITE; | |
| String += StrLen (L"ReadWrite"); | |
| } else if (StrnCmp (String, L"Buffer", StrLen (L"Buffer")) == 0) { | |
| // | |
| // Find Buffer Filter. | |
| // | |
| *FilterFlags |= EFI_KEYWORD_FILTER_BUFFER; | |
| String += StrLen (L"Buffer"); | |
| } else if (StrnCmp (String, L"Numeric", StrLen (L"Numeric")) == 0) { | |
| // | |
| // Find Numeric Filter | |
| // | |
| String += StrLen (L"Numeric"); | |
| if (*String != L':') { | |
| *FilterFlags |= EFI_KEYWORD_FILTER_NUMERIC; | |
| } else { | |
| String++; | |
| switch (*String) { | |
| case L'1': | |
| *FilterFlags |= EFI_KEYWORD_FILTER_NUMERIC_1; | |
| break; | |
| case L'2': | |
| *FilterFlags |= EFI_KEYWORD_FILTER_NUMERIC_2; | |
| break; | |
| case L'4': | |
| *FilterFlags |= EFI_KEYWORD_FILTER_NUMERIC_4; | |
| break; | |
| case L'8': | |
| *FilterFlags |= EFI_KEYWORD_FILTER_NUMERIC_8; | |
| break; | |
| default: | |
| ASSERT (FALSE); | |
| break; | |
| } | |
| String++; | |
| } | |
| } else { | |
| // | |
| // Check whether other filter item defined by Platform. | |
| // | |
| if ((StrnCmp (String, L"&PATH", StrLen (L"&PATH")) == 0) || | |
| (StrnCmp (String, L"&KEYWORD", StrLen (L"&KEYWORD")) == 0)) { | |
| // | |
| // New KeywordRequest start, no platform defined filter. | |
| // | |
| } else { | |
| // | |
| // Platform defined filter rule. | |
| // Just skip platform defined filter rule, return success. | |
| // | |
| PathPtr = StrStr(String, L"&PATH"); | |
| KeywordPtr = StrStr(String, L"&KEYWORD"); | |
| if (PathPtr != NULL && KeywordPtr != NULL) { | |
| // | |
| // If both sections exist, return the first follow string. | |
| // | |
| String = KeywordPtr > PathPtr ? PathPtr : KeywordPtr; | |
| } else if (PathPtr != NULL) { | |
| // | |
| // Should not exist PathPtr != NULL && KeywordPtr == NULL case. | |
| // | |
| ASSERT (FALSE); | |
| } else if (KeywordPtr != NULL) { | |
| // | |
| // Just to the next keyword section. | |
| // | |
| String = KeywordPtr; | |
| } else { | |
| // | |
| // Only has paltform defined filter section, just skip it. | |
| // | |
| String += StrLen (String); | |
| } | |
| } | |
| RetVal = FALSE; | |
| } | |
| *NextString = String; | |
| return RetVal; | |
| } | |
| /** | |
| Extract Readonly flag from opcode. | |
| This is a internal function. | |
| @param OpCodeData Input opcode for this question. | |
| @retval TRUE This question is readonly. | |
| @retval FALSE This question is not readonly. | |
| **/ | |
| BOOLEAN | |
| ExtractReadOnlyFromOpCode ( | |
| IN UINT8 *OpCodeData | |
| ) | |
| { | |
| EFI_IFR_QUESTION_HEADER *QuestionHdr; | |
| ASSERT (OpCodeData != NULL); | |
| QuestionHdr = (EFI_IFR_QUESTION_HEADER *) (OpCodeData + sizeof (EFI_IFR_OP_HEADER)); | |
| return (QuestionHdr->Flags & EFI_IFR_FLAG_READ_ONLY) != 0; | |
| } | |
| /** | |
| Create a circuit to check the filter section. | |
| This is a internal function. | |
| @param OpCodeData The questin binary ifr data. | |
| @param KeywordRequest KeywordRequestformat string. | |
| @param NextString return the next string follow this keyword sectin. | |
| @param ReadOnly Return whether this question is read only. | |
| @retval KEYWORD_HANDLER_NO_ERROR Success validate. | |
| @retval KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED Validate fail. | |
| **/ | |
| UINT32 | |
| ValidateFilter ( | |
| IN UINT8 *OpCodeData, | |
| IN CHAR16 *KeywordRequest, | |
| OUT CHAR16 **NextString, | |
| OUT BOOLEAN *ReadOnly | |
| ) | |
| { | |
| CHAR16 *NextFilter; | |
| CHAR16 *StringPtr; | |
| UINT8 FilterFlags; | |
| EFI_IFR_QUESTION_HEADER *QuestionHdr; | |
| EFI_IFR_OP_HEADER *OpCodeHdr; | |
| UINT8 Flags; | |
| UINT32 RetVal; | |
| RetVal = KEYWORD_HANDLER_NO_ERROR; | |
| StringPtr = KeywordRequest; | |
| OpCodeHdr = (EFI_IFR_OP_HEADER *) OpCodeData; | |
| QuestionHdr = (EFI_IFR_QUESTION_HEADER *) (OpCodeData + sizeof (EFI_IFR_OP_HEADER)); | |
| if (OpCodeHdr->OpCode == EFI_IFR_ONE_OF_OP || OpCodeHdr->OpCode == EFI_IFR_NUMERIC_OP) { | |
| Flags = *(OpCodeData + sizeof (EFI_IFR_OP_HEADER) + sizeof (EFI_IFR_QUESTION_HEADER)); | |
| } else { | |
| Flags = 0; | |
| } | |
| // | |
| // Get ReadOnly flag from Question. | |
| // | |
| *ReadOnly = ExtractReadOnlyFromOpCode(OpCodeData); | |
| while (ExtractFilter (StringPtr, &FilterFlags, &NextFilter)) { | |
| switch (FilterFlags) { | |
| case EFI_KEYWORD_FILTER_READONY: | |
| if ((QuestionHdr->Flags & EFI_IFR_FLAG_READ_ONLY) == 0) { | |
| RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED; | |
| goto Done; | |
| } | |
| break; | |
| case EFI_KEYWORD_FILTER_REAWRITE: | |
| if ((QuestionHdr->Flags & EFI_IFR_FLAG_READ_ONLY) != 0) { | |
| RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED; | |
| goto Done; | |
| } | |
| break; | |
| case EFI_KEYWORD_FILTER_BUFFER: | |
| // | |
| // Only these three opcode use numeric value type. | |
| // | |
| if (OpCodeHdr->OpCode == EFI_IFR_ONE_OF_OP || OpCodeHdr->OpCode == EFI_IFR_NUMERIC_OP || OpCodeHdr->OpCode == EFI_IFR_CHECKBOX_OP) { | |
| RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED; | |
| goto Done; | |
| } | |
| break; | |
| case EFI_KEYWORD_FILTER_NUMERIC: | |
| if (OpCodeHdr->OpCode != EFI_IFR_ONE_OF_OP && OpCodeHdr->OpCode != EFI_IFR_NUMERIC_OP && OpCodeHdr->OpCode != EFI_IFR_CHECKBOX_OP) { | |
| RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED; | |
| goto Done; | |
| } | |
| break; | |
| case EFI_KEYWORD_FILTER_NUMERIC_1: | |
| case EFI_KEYWORD_FILTER_NUMERIC_2: | |
| case EFI_KEYWORD_FILTER_NUMERIC_4: | |
| case EFI_KEYWORD_FILTER_NUMERIC_8: | |
| if (OpCodeHdr->OpCode != EFI_IFR_ONE_OF_OP && OpCodeHdr->OpCode != EFI_IFR_NUMERIC_OP && OpCodeHdr->OpCode != EFI_IFR_CHECKBOX_OP) { | |
| RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED; | |
| goto Done; | |
| } | |
| // | |
| // For numeric and oneof, it has flags field to specify the detail numeric type. | |
| // | |
| if (OpCodeHdr->OpCode == EFI_IFR_ONE_OF_OP || OpCodeHdr->OpCode == EFI_IFR_NUMERIC_OP) { | |
| switch (Flags & EFI_IFR_NUMERIC_SIZE) { | |
| case EFI_IFR_NUMERIC_SIZE_1: | |
| if (FilterFlags != EFI_KEYWORD_FILTER_NUMERIC_1) { | |
| RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED; | |
| goto Done; | |
| } | |
| break; | |
| case EFI_IFR_NUMERIC_SIZE_2: | |
| if (FilterFlags != EFI_KEYWORD_FILTER_NUMERIC_2) { | |
| RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED; | |
| goto Done; | |
| } | |
| break; | |
| case EFI_IFR_NUMERIC_SIZE_4: | |
| if (FilterFlags != EFI_KEYWORD_FILTER_NUMERIC_4) { | |
| RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED; | |
| goto Done; | |
| } | |
| break; | |
| case EFI_IFR_NUMERIC_SIZE_8: | |
| if (FilterFlags != EFI_KEYWORD_FILTER_NUMERIC_8) { | |
| RetVal = KEYWORD_HANDLER_INCOMPATIBLE_VALUE_DETECTED; | |
| goto Done; | |
| } | |
| break; | |
| default: | |
| ASSERT (FALSE); | |
| break; | |
| } | |
| } | |
| break; | |
| default: | |
| ASSERT (FALSE); | |
| break; | |
| } | |
| // | |
| // Jump to the next filter. | |
| // | |
| StringPtr = NextFilter; | |
| } | |
| Done: | |
| // | |
| // The current filter which is processing. | |
| // | |
| *NextString = StringPtr; | |
| return RetVal; | |
| } | |
| /** | |
| Get HII_DATABASE_RECORD from the input device path info. | |
| This is a internal function. | |
| @param DevicePath UEFI device path protocol. | |
| @retval Internal data base record. | |
| **/ | |
| HII_DATABASE_RECORD * | |
| GetRecordFromDevicePath ( | |
| IN EFI_DEVICE_PATH_PROTOCOL *DevicePath | |
| ) | |
| { | |
| LIST_ENTRY *Link; | |
| UINT8 *DevicePathPkg; | |
| UINT8 *CurrentDevicePath; | |
| UINTN DevicePathSize; | |
| HII_DATABASE_RECORD *TempDatabase; | |
| ASSERT (DevicePath != NULL); | |
| for (Link = mPrivate.DatabaseList.ForwardLink; Link != &mPrivate.DatabaseList; Link = Link->ForwardLink) { | |
| TempDatabase = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE); | |
| DevicePathPkg = TempDatabase->PackageList->DevicePathPkg; | |
| if (DevicePathPkg != NULL) { | |
| CurrentDevicePath = DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER); | |
| DevicePathSize = GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) CurrentDevicePath); | |
| if ((CompareMem (DevicePath, CurrentDevicePath, DevicePathSize) == 0)) { | |
| return TempDatabase; | |
| } | |
| } | |
| } | |
| return NULL; | |
| } | |
| /** | |
| Calculate the size of StringSrc and output it. Also copy string text from src | |
| to dest. | |
| This is a internal function. | |
| @param StringSrc Points to current null-terminated string. | |
| @param BufferSize Length of the buffer. | |
| @param StringDest Buffer to store the string text. | |
| @retval EFI_SUCCESS The string text was outputed successfully. | |
| @retval EFI_OUT_OF_RESOURCES Out of resource. | |
| **/ | |
| EFI_STATUS | |
| GetUnicodeStringTextAndSize ( | |
| IN UINT8 *StringSrc, | |
| OUT UINTN *BufferSize, | |
| OUT EFI_STRING *StringDest | |
| ) | |
| { | |
| UINTN StringSize; | |
| UINT8 *StringPtr; | |
| ASSERT (StringSrc != NULL && BufferSize != NULL && StringDest != NULL); | |
| StringSize = sizeof (CHAR16); | |
| StringPtr = StringSrc; | |
| while (ReadUnaligned16 ((UINT16 *) StringPtr) != 0) { | |
| StringSize += sizeof (CHAR16); | |
| StringPtr += sizeof (CHAR16); | |
| } | |
| *StringDest = AllocatePool (StringSize); | |
| if (*StringDest == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| CopyMem (*StringDest, StringSrc, StringSize); | |
| *BufferSize = StringSize; | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Find the string id for the input keyword. | |
| @param StringPackage Hii string package instance. | |
| @param KeywordValue Input keyword value. | |
| @param StringId The string's id, which is unique within PackageList. | |
| @retval EFI_SUCCESS The string text and font is retrieved | |
| successfully. | |
| @retval EFI_NOT_FOUND The specified text or font info can not be found | |
| out. | |
| @retval EFI_OUT_OF_RESOURCES The system is out of resources to accomplish the | |
| task. | |
| **/ | |
| EFI_STATUS | |
| GetStringIdFromString ( | |
| IN HII_STRING_PACKAGE_INSTANCE *StringPackage, | |
| IN CHAR16 *KeywordValue, | |
| OUT EFI_STRING_ID *StringId | |
| ) | |
| { | |
| UINT8 *BlockHdr; | |
| EFI_STRING_ID CurrentStringId; | |
| UINTN BlockSize; | |
| UINTN Index; | |
| UINT8 *StringTextPtr; | |
| UINTN Offset; | |
| UINT16 StringCount; | |
| UINT16 SkipCount; | |
| UINT8 Length8; | |
| EFI_HII_SIBT_EXT2_BLOCK Ext2; | |
| UINT32 Length32; | |
| UINTN StringSize; | |
| CHAR16 *String; | |
| CHAR8 *AsciiKeywordValue; | |
| EFI_STATUS Status; | |
| ASSERT (StringPackage != NULL && KeywordValue != NULL && StringId != NULL); | |
| ASSERT (StringPackage->Signature == HII_STRING_PACKAGE_SIGNATURE); | |
| CurrentStringId = 1; | |
| Status = EFI_SUCCESS; | |
| String = NULL; | |
| BlockHdr = StringPackage->StringBlock; | |
| BlockSize = 0; | |
| Offset = 0; | |
| // | |
| // Make a ascii keyword value for later use. | |
| // | |
| AsciiKeywordValue = AllocatePool (StrLen (KeywordValue) + 1); | |
| if (AsciiKeywordValue == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| UnicodeStrToAsciiStr(KeywordValue, AsciiKeywordValue); | |
| while (*BlockHdr != EFI_HII_SIBT_END) { | |
| switch (*BlockHdr) { | |
| case EFI_HII_SIBT_STRING_SCSU: | |
| Offset = sizeof (EFI_HII_STRING_BLOCK); | |
| StringTextPtr = BlockHdr + Offset; | |
| BlockSize += Offset + AsciiStrSize ((CHAR8 *) StringTextPtr); | |
| if (AsciiStrCmp(AsciiKeywordValue, (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; | |
| } | |
| if (StrCmp(KeywordValue, String) == 0) { | |
| *StringId = CurrentStringId; | |
| goto Done; | |
| } | |
| BlockSize += Offset + StringSize; | |
| CurrentStringId++; | |
| break; | |
| case EFI_HII_SIBT_STRING_UCS2_FONT: | |
| Offset = sizeof (EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK) - sizeof (CHAR16); | |
| StringTextPtr = BlockHdr + Offset; | |
| // | |
| // Use StringSize to store the size of the specified string, including the NULL | |
| // terminator. | |
| // | |
| Status = GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String); | |
| if (EFI_ERROR (Status)) { | |
| goto Done; | |
| } | |
| if (StrCmp(KeywordValue, String) == 0) { | |
| *StringId = CurrentStringId; | |
| goto Done; | |
| } | |
| BlockSize += Offset + StringSize; | |
| CurrentStringId++; | |
| break; | |
| case EFI_HII_SIBT_STRINGS_UCS2: | |
| Offset = sizeof (EFI_HII_SIBT_STRINGS_UCS2_BLOCK) - sizeof (CHAR16); | |
| StringTextPtr = BlockHdr + Offset; | |
| BlockSize += Offset; | |
| CopyMem (&StringCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16)); | |
| for (Index = 0; Index < StringCount; Index++) { | |
| Status = GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String); | |
| if (EFI_ERROR (Status)) { | |
| goto Done; | |
| } | |
| BlockSize += StringSize; | |
| if (StrCmp(KeywordValue, String) == 0) { | |
| *StringId = CurrentStringId; | |
| goto Done; | |
| } | |
| StringTextPtr = StringTextPtr + StringSize; | |
| CurrentStringId++; | |
| } | |
| break; | |
| case EFI_HII_SIBT_STRINGS_UCS2_FONT: | |
| Offset = sizeof (EFI_HII_SIBT_STRINGS_UCS2_FONT_BLOCK) - sizeof (CHAR16); | |
| StringTextPtr = BlockHdr + Offset; | |
| BlockSize += Offset; | |
| CopyMem ( | |
| &StringCount, | |
| (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)), | |
| sizeof (UINT16) | |
| ); | |
| for (Index = 0; Index < StringCount; Index++) { | |
| Status = GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String); | |
| if (EFI_ERROR (Status)) { | |
| goto Done; | |
| } | |
| BlockSize += StringSize; | |
| if (StrCmp(KeywordValue, String) == 0) { | |
| *StringId = CurrentStringId; | |
| goto Done; | |
| } | |
| StringTextPtr = StringTextPtr + StringSize; | |
| CurrentStringId++; | |
| } | |
| break; | |
| case EFI_HII_SIBT_DUPLICATE: | |
| BlockSize += sizeof (EFI_HII_SIBT_DUPLICATE_BLOCK); | |
| CurrentStringId++; | |
| break; | |
| case EFI_HII_SIBT_SKIP1: | |
| SkipCount = (UINT16) (*(UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK))); | |
| CurrentStringId = (UINT16) (CurrentStringId + SkipCount); | |
| BlockSize += sizeof (EFI_HII_SIBT_SKIP1_BLOCK); | |
| break; | |
| case EFI_HII_SIBT_SKIP2: | |
| CopyMem (&SkipCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16)); | |
| CurrentStringId = (UINT16) (CurrentStringId + SkipCount); | |
| BlockSize += sizeof (EFI_HII_SIBT_SKIP2_BLOCK); | |
| break; | |
| case EFI_HII_SIBT_EXT1: | |
| CopyMem ( | |
| &Length8, | |
| (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)), | |
| sizeof (UINT8) | |
| ); | |
| BlockSize += Length8; | |
| break; | |
| case EFI_HII_SIBT_EXT2: | |
| CopyMem (&Ext2, BlockHdr, sizeof (EFI_HII_SIBT_EXT2_BLOCK)); | |
| BlockSize += Ext2.Length; | |
| break; | |
| case EFI_HII_SIBT_EXT4: | |
| CopyMem ( | |
| &Length32, | |
| (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)), | |
| sizeof (UINT32) | |
| ); | |
| BlockSize += Length32; | |
| break; | |
| default: | |
| break; | |
| } | |
| if (String != NULL) { | |
| FreePool (String); | |
| String = NULL; | |
| } | |
| BlockHdr = StringPackage->StringBlock + BlockSize; | |
| } | |
| Status = EFI_NOT_FOUND; | |
| Done: | |
| if (AsciiKeywordValue != NULL) { | |
| FreePool (AsciiKeywordValue); | |
| } | |
| if (String != NULL) { | |
| FreePool (String); | |
| } | |
| return Status; | |
| } | |
| /** | |
| Find the next valid string id for the input string id. | |
| @param StringPackage Hii string package instance. | |
| @param StringId The current string id which is already got. | |
| 1 means just begin to get the string id. | |
| @param KeywordValue Return the string for the next string id. | |
| @retval EFI_STRING_ID Not 0 means a valid stringid found. | |
| 0 means not found a valid string id. | |
| **/ | |
| EFI_STRING_ID | |
| GetNextStringId ( | |
| IN HII_STRING_PACKAGE_INSTANCE *StringPackage, | |
| IN EFI_STRING_ID StringId, | |
| OUT EFI_STRING *KeywordValue | |
| ) | |
| { | |
| UINT8 *BlockHdr; | |
| EFI_STRING_ID CurrentStringId; | |
| UINTN BlockSize; | |
| UINTN Index; | |
| UINT8 *StringTextPtr; | |
| UINTN Offset; | |
| UINT16 StringCount; | |
| UINT16 SkipCount; | |
| UINT8 Length8; | |
| EFI_HII_SIBT_EXT2_BLOCK Ext2; | |
| UINT32 Length32; | |
| BOOLEAN FindString; | |
| UINTN StringSize; | |
| CHAR16 *String; | |
| ASSERT (StringPackage != NULL); | |
| ASSERT (StringPackage->Signature == HII_STRING_PACKAGE_SIGNATURE); | |
| CurrentStringId = 1; | |
| FindString = FALSE; | |
| String = NULL; | |
| // | |
| // Parse the string blocks to get the string text and font. | |
| // | |
| BlockHdr = StringPackage->StringBlock; | |
| BlockSize = 0; | |
| Offset = 0; | |
| while (*BlockHdr != EFI_HII_SIBT_END) { | |
| switch (*BlockHdr) { | |
| case EFI_HII_SIBT_STRING_SCSU: | |
| Offset = sizeof (EFI_HII_STRING_BLOCK); | |
| StringTextPtr = BlockHdr + Offset; | |
| if (FindString) { | |
| *KeywordValue = AllocatePool (AsciiStrSize ((CHAR8 *) StringTextPtr) * sizeof (CHAR16)); | |
| if (*KeywordValue == NULL) { | |
| return 0; | |
| } | |
| AsciiStrToUnicodeStr ((CHAR8 *) StringTextPtr, *KeywordValue); | |
| return CurrentStringId; | |
| } else if (CurrentStringId == StringId) { | |
| FindString = TRUE; | |
| } | |
| BlockSize += Offset + AsciiStrSize ((CHAR8 *) StringTextPtr); | |
| CurrentStringId++; | |
| break; | |
| case EFI_HII_SIBT_STRING_SCSU_FONT: | |
| Offset = sizeof (EFI_HII_SIBT_STRING_SCSU_FONT_BLOCK) - sizeof (UINT8); | |
| StringTextPtr = BlockHdr + Offset; | |
| if (FindString) { | |
| *KeywordValue = AllocatePool (AsciiStrSize ((CHAR8 *) StringTextPtr) * sizeof (CHAR16)); | |
| if (*KeywordValue == NULL) { | |
| return 0; | |
| } | |
| AsciiStrToUnicodeStr ((CHAR8 *) StringTextPtr, *KeywordValue); | |
| return CurrentStringId; | |
| } else if (CurrentStringId == StringId) { | |
| FindString = TRUE; | |
| } | |
| BlockSize += Offset + AsciiStrSize ((CHAR8 *) StringTextPtr); | |
| CurrentStringId++; | |
| break; | |
| case EFI_HII_SIBT_STRINGS_SCSU: | |
| CopyMem (&StringCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16)); | |
| StringTextPtr = (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_SIBT_STRINGS_SCSU_BLOCK) - sizeof (UINT8)); | |
| BlockSize += StringTextPtr - BlockHdr; | |
| for (Index = 0; Index < StringCount; Index++) { | |
| if (FindString) { | |
| *KeywordValue = AllocatePool (AsciiStrSize ((CHAR8 *) StringTextPtr) * sizeof (CHAR16)); | |
| if (*KeywordValue == NULL) { | |
| return 0; | |
| } | |
| AsciiStrToUnicodeStr ((CHAR8 *) StringTextPtr, *KeywordValue); | |
| return CurrentStringId; | |
| } else if (CurrentStringId == StringId) { | |
| FindString = TRUE; | |
| } | |
| BlockSize += AsciiStrSize ((CHAR8 *) StringTextPtr); | |
| StringTextPtr = StringTextPtr + AsciiStrSize ((CHAR8 *) StringTextPtr); | |
| CurrentStringId++; | |
| } | |
| break; | |
| case EFI_HII_SIBT_STRINGS_SCSU_FONT: | |
| CopyMem ( | |
| &StringCount, | |
| (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)), | |
| sizeof (UINT16) | |
| ); | |
| StringTextPtr = (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_SIBT_STRINGS_SCSU_FONT_BLOCK) - sizeof (UINT8)); | |
| BlockSize += StringTextPtr - BlockHdr; | |
| for (Index = 0; Index < StringCount; Index++) { | |
| if (FindString) { | |
| *KeywordValue = AllocatePool (AsciiStrSize ((CHAR8 *) StringTextPtr) * sizeof (CHAR16)); | |
| if (*KeywordValue == NULL) { | |
| return 0; | |
| } | |
| AsciiStrToUnicodeStr ((CHAR8 *) StringTextPtr, *KeywordValue); | |
| return CurrentStringId; | |
| } else if (CurrentStringId == StringId) { | |
| FindString = TRUE; | |
| } | |
| BlockSize += AsciiStrSize ((CHAR8 *) StringTextPtr); | |
| StringTextPtr = StringTextPtr + AsciiStrSize ((CHAR8 *) StringTextPtr); | |
| CurrentStringId++; | |
| } | |
| break; | |
| case EFI_HII_SIBT_STRING_UCS2: | |
| Offset = sizeof (EFI_HII_STRING_BLOCK); | |
| StringTextPtr = BlockHdr + Offset; | |
| // | |
| // Use StringSize to store the size of the specified string, including the NULL | |
| // terminator. | |
| // | |
| GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String); | |
| if (FindString && (String != NULL) && (*String != L'\0')) { | |
| // | |
| // String protocol use this type for the string id which has value for other package. | |
| // It will allocate an empty string block for this string id. so here we also check | |
| // *String != L'\0' to prohibit this case. | |
| // | |
| *KeywordValue = String; | |
| return CurrentStringId; | |
| } else if (CurrentStringId == StringId) { | |
| FindString = TRUE; | |
| } | |
| BlockSize += Offset + StringSize; | |
| CurrentStringId++; | |
| break; | |
| case EFI_HII_SIBT_STRING_UCS2_FONT: | |
| Offset = sizeof (EFI_HII_SIBT_STRING_UCS2_FONT_BLOCK) - sizeof (CHAR16); | |
| StringTextPtr = BlockHdr + Offset; | |
| // | |
| // Use StringSize to store the size of the specified string, including the NULL | |
| // terminator. | |
| // | |
| GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String); | |
| if (FindString) { | |
| *KeywordValue = String; | |
| return CurrentStringId; | |
| } else if (CurrentStringId == StringId) { | |
| FindString = TRUE; | |
| } | |
| BlockSize += Offset + StringSize; | |
| CurrentStringId++; | |
| break; | |
| case EFI_HII_SIBT_STRINGS_UCS2: | |
| Offset = sizeof (EFI_HII_SIBT_STRINGS_UCS2_BLOCK) - sizeof (CHAR16); | |
| StringTextPtr = BlockHdr + Offset; | |
| BlockSize += Offset; | |
| CopyMem (&StringCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16)); | |
| for (Index = 0; Index < StringCount; Index++) { | |
| GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String); | |
| if (FindString) { | |
| *KeywordValue = String; | |
| return CurrentStringId; | |
| } else if (CurrentStringId == StringId) { | |
| FindString = TRUE; | |
| } | |
| BlockSize += StringSize; | |
| StringTextPtr = StringTextPtr + StringSize; | |
| CurrentStringId++; | |
| } | |
| break; | |
| case EFI_HII_SIBT_STRINGS_UCS2_FONT: | |
| Offset = sizeof (EFI_HII_SIBT_STRINGS_UCS2_FONT_BLOCK) - sizeof (CHAR16); | |
| StringTextPtr = BlockHdr + Offset; | |
| BlockSize += Offset; | |
| CopyMem ( | |
| &StringCount, | |
| (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)), | |
| sizeof (UINT16) | |
| ); | |
| for (Index = 0; Index < StringCount; Index++) { | |
| GetUnicodeStringTextAndSize (StringTextPtr, &StringSize, &String); | |
| if (FindString) { | |
| *KeywordValue = String; | |
| return CurrentStringId; | |
| } else if (CurrentStringId == StringId) { | |
| FindString = TRUE; | |
| } | |
| BlockSize += StringSize; | |
| StringTextPtr = StringTextPtr + StringSize; | |
| CurrentStringId++; | |
| } | |
| break; | |
| case EFI_HII_SIBT_DUPLICATE: | |
| BlockSize += sizeof (EFI_HII_SIBT_DUPLICATE_BLOCK); | |
| CurrentStringId++; | |
| break; | |
| case EFI_HII_SIBT_SKIP1: | |
| SkipCount = (UINT16) (*(UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK))); | |
| CurrentStringId = (UINT16) (CurrentStringId + SkipCount); | |
| BlockSize += sizeof (EFI_HII_SIBT_SKIP1_BLOCK); | |
| break; | |
| case EFI_HII_SIBT_SKIP2: | |
| CopyMem (&SkipCount, BlockHdr + sizeof (EFI_HII_STRING_BLOCK), sizeof (UINT16)); | |
| CurrentStringId = (UINT16) (CurrentStringId + SkipCount); | |
| BlockSize += sizeof (EFI_HII_SIBT_SKIP2_BLOCK); | |
| break; | |
| case EFI_HII_SIBT_EXT1: | |
| CopyMem ( | |
| &Length8, | |
| (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)), | |
| sizeof (UINT8) | |
| ); | |
| BlockSize += Length8; | |
| break; | |
| case EFI_HII_SIBT_EXT2: | |
| CopyMem (&Ext2, BlockHdr, sizeof (EFI_HII_SIBT_EXT2_BLOCK)); | |
| BlockSize += Ext2.Length; | |
| break; | |
| case EFI_HII_SIBT_EXT4: | |
| CopyMem ( | |
| &Length32, | |
| (UINT8*)((UINTN)BlockHdr + sizeof (EFI_HII_STRING_BLOCK) + sizeof (UINT8)), | |
| sizeof (UINT32) | |
| ); | |
| BlockSize += Length32; | |
| break; | |
| default: | |
| break; | |
| } | |
| if (String != NULL) { | |
| FreePool (String); | |
| String = NULL; | |
| } | |
| BlockHdr = StringPackage->StringBlock + BlockSize; | |
| } | |
| return 0; | |
| } | |
| /** | |
| Get string package from the input NameSpace string. | |
| This is a internal function. | |
| @param DatabaseRecord HII_DATABASE_RECORD format string. | |
| @param NameSpace NameSpace format string. | |
| @param KeywordValue Keyword value. | |
| @param StringId String Id for this keyword. | |
| @retval KEYWORD_HANDLER_NO_ERROR Get String id succes. | |
| @retval KEYWORD_HANDLER_KEYWORD_NOT_FOUND Not found the string id in the string package. | |
| @retval KEYWORD_HANDLER_NAMESPACE_ID_NOT_FOUND Not found the string package for this namespace. | |
| @retval KEYWORD_HANDLER_UNDEFINED_PROCESSING_ERROR Out of resource error. | |
| **/ | |
| UINT32 | |
| GetStringIdFromRecord ( | |
| IN HII_DATABASE_RECORD *DatabaseRecord, | |
| IN CHAR8 **NameSpace, | |
| IN CHAR16 *KeywordValue, | |
| OUT EFI_STRING_ID *StringId | |
| ) | |
| { | |
| LIST_ENTRY *Link; | |
| HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageListNode; | |
| HII_STRING_PACKAGE_INSTANCE *StringPackage; | |
| EFI_STATUS Status; | |
| CHAR8 *Name; | |
| 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 dtring characters in range ['A'..'F'] to ['a'..'f'] for | |
| hex digits that appear between a '=' and a '&' in a config string. | |
| If ConfigString is NULL, then ASSERT(). | |
| @param[in] ConfigString Pointer to a Null-terminated Unicode string. | |
| @return Pointer to the Null-terminated Unicode result string. | |
| **/ | |
| EFI_STRING | |
| EFIAPI | |
| InternalLowerConfigString ( | |
| IN EFI_STRING ConfigString | |
| ) | |
| { | |
| EFI_STRING String; | |
| BOOLEAN Lower; | |
| ASSERT (ConfigString != NULL); | |
| // | |
| // Convert all hex digits in range [A-F] in the configuration header to [a-f] | |
| // | |
| for (String = ConfigString, Lower = FALSE; *String != L'\0'; String++) { | |
| if (*String == L'=') { | |
| Lower = TRUE; | |
| } else if (*String == L'&') { | |
| Lower = FALSE; | |
| } else if (Lower && *String >= L'A' && *String <= L'F') { | |
| *String = (CHAR16) (*String - L'A' + L'a'); | |
| } | |
| } | |
| return ConfigString; | |
| } | |
| /** | |
| Allocates and returns a Null-terminated Unicode <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 hexidecimal 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; | |
| 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) { | |
| Name = AllocateZeroPool (AsciiStrSize (AsciiName) * 2); | |
| ASSERT (Name != NULL); | |
| AsciiStrToUnicodeStr(AsciiName, Name); | |
| } else { | |
| Name = NULL; | |
| } | |
| // | |
| // Compute the length of Name in Unicode characters. | |
| // If Name is NULL, then the length is 0. | |
| // | |
| NameLength = 0; | |
| if (Name != NULL) { | |
| NameLength = StrLen (Name); | |
| } | |
| DevicePath = NULL; | |
| DevicePathSize = 0; | |
| // | |
| // Retrieve DevicePath Protocol associated with DriverHandle | |
| // | |
| if (DriverHandle != NULL) { | |
| DevicePath = DevicePathFromHandle (DriverHandle); | |
| if (DevicePath == NULL) { | |
| return NULL; | |
| } | |
| // | |
| // Compute the size of the device path in bytes | |
| // | |
| DevicePathSize = GetDevicePathSize (DevicePath); | |
| } | |
| // | |
| // GUID=<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++) { | |
| String += UnicodeValueToString (String, PREFIX_ZERO | RADIX_HEX, *(Buffer++), 2); | |
| } | |
| } | |
| // | |
| // 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++) { | |
| String += UnicodeValueToString (String, PREFIX_ZERO | RADIX_HEX, *Name, 4); | |
| } | |
| } | |
| // | |
| // 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++) { | |
| String += UnicodeValueToString (String, PREFIX_ZERO | RADIX_HEX, *(Buffer++), 2); | |
| } | |
| // | |
| // Null terminate the Unicode string | |
| // | |
| *String = L'\0'; | |
| // | |
| // Convert all hex digits in range [A-F] in the configuration header to [a-f] | |
| // | |
| return InternalLowerConfigString (ReturnString); | |
| } | |
| /** | |
| Generate the Config request element for one question. | |
| @param Name The name info for one question. | |
| @param Offset The offset info for one question. | |
| @param Width The width info for one question. | |
| @return Pointer to the Null-terminated Unicode request element string. | |
| **/ | |
| EFI_STRING | |
| ConstructRequestElement ( | |
| IN CHAR16 *Name, | |
| IN UINT16 Offset, | |
| IN UINT16 Width | |
| ) | |
| { | |
| CHAR16 *StringPtr; | |
| UINTN Length; | |
| if (Name != NULL) { | |
| // | |
| // Add <BlockName> length for each Name | |
| // | |
| // <BlockName> ::= Name + \0 | |
| // StrLen(Name) | 1 | |
| // | |
| Length = StrLen (Name) + 1; | |
| } else { | |
| // | |
| // Add <BlockName> length for each Offset/Width pair | |
| // | |
| // <BlockName> ::= OFFSET=1234&WIDTH=1234 + \0 | |
| // | 7 | 4 | 7 | 4 | 1 | |
| // | |
| Length = (7 + 4 + 7 + 4 + 1); | |
| } | |
| // | |
| // Allocate buffer for the entire <ConfigRequest> | |
| // | |
| StringPtr = AllocateZeroPool (Length * sizeof (CHAR16)); | |
| ASSERT (StringPtr != NULL); | |
| if (Name != NULL) { | |
| // | |
| // Append Name\0 | |
| // | |
| UnicodeSPrint ( | |
| StringPtr, | |
| (StrLen (Name) + 1) * sizeof (CHAR16), | |
| L"%s", | |
| Name | |
| ); | |
| } else { | |
| // | |
| // Append OFFSET=XXXX&WIDTH=YYYY\0 | |
| // | |
| UnicodeSPrint ( | |
| StringPtr, | |
| (7 + 4 + 7 + 4 + 1) * sizeof (CHAR16), | |
| L"OFFSET=%04X&WIDTH=%04X", | |
| Offset, | |
| Width | |
| ); | |
| } | |
| return StringPtr; | |
| } | |
| /** | |
| Get string value for question's name field. | |
| @param DatabaseRecord HII_DATABASE_RECORD format string. | |
| @param NameId The string id for the name field. | |
| @retval Name string. | |
| **/ | |
| CHAR16 * | |
| GetNameFromId ( | |
| IN HII_DATABASE_RECORD *DatabaseRecord, | |
| IN EFI_STRING_ID NameId | |
| ) | |
| { | |
| CHAR16 *Name; | |
| CHAR8 *PlatformLanguage; | |
| CHAR8 *SupportedLanguages; | |
| CHAR8 *BestLanguage; | |
| UINTN StringSize; | |
| CHAR16 TempString; | |
| EFI_STATUS Status; | |
| Name = NULL; | |
| BestLanguage = NULL; | |
| PlatformLanguage = NULL; | |
| SupportedLanguages = NULL; | |
| GetEfiGlobalVariable2 (L"PlatformLang", (VOID**)&PlatformLanguage, NULL); | |
| SupportedLanguages = GetSupportedLanguages(DatabaseRecord->Handle); | |
| // | |
| // Get the best matching language from SupportedLanguages | |
| // | |
| BestLanguage = GetBestLanguage ( | |
| SupportedLanguages, | |
| FALSE, // RFC 4646 mode | |
| PlatformLanguage != NULL ? PlatformLanguage : "", // Highest priority | |
| SupportedLanguages, // Lowest priority | |
| NULL | |
| ); | |
| if (BestLanguage == NULL) { | |
| BestLanguage = AllocateCopyPool (AsciiStrLen ("en-US"), "en-US"); | |
| ASSERT (BestLanguage != NULL); | |
| } | |
| StringSize = 0; | |
| Status = mPrivate.HiiString.GetString ( | |
| &mPrivate.HiiString, | |
| BestLanguage, | |
| DatabaseRecord->Handle, | |
| NameId, | |
| &TempString, | |
| &StringSize, | |
| NULL | |
| ); | |
| if (Status != EFI_BUFFER_TOO_SMALL) { | |
| goto Done; | |
| } | |
| Name = AllocateZeroPool (StringSize); | |
| if (Name == NULL) { | |
| goto Done; | |
| } | |
| Status = mPrivate.HiiString.GetString ( | |
| &mPrivate.HiiString, | |
| BestLanguage, | |
| DatabaseRecord->Handle, | |
| NameId, | |
| Name, | |
| &StringSize, | |
| NULL | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| FreePool (Name); | |
| Name = NULL; | |
| goto Done; | |
| } | |
| Done: | |
| if (SupportedLanguages != NULL) { | |
| FreePool(SupportedLanguages); | |
| } | |
| if (BestLanguage != NULL) { | |
| FreePool (BestLanguage); | |
| } | |
| if (PlatformLanguage != NULL) { | |
| FreePool (PlatformLanguage); | |
| } | |
| return Name; | |
| } | |
| /** | |
| Base on the input parameter to generate the ConfigRequest string. | |
| This is a internal function. | |
| @param DatabaseRecord HII_DATABASE_RECORD format string. | |
| @param KeywordStrId Keyword string id. | |
| @param OpCodeData The IFR data for this question. | |
| @param ConfigRequest Return the generate ConfigRequest string. | |
| @retval EFI_SUCCESS Generate ConfigResp string success. | |
| @retval EFI_OUT_OF_RESOURCES System out of memory resource error. | |
| @retval EFI_NOT_FOUND Not found the question which use this string id | |
| as the prompt string id. | |
| **/ | |
| EFI_STATUS | |
| ExtractConfigRequest ( | |
| IN HII_DATABASE_RECORD *DatabaseRecord, | |
| IN EFI_STRING_ID KeywordStrId, | |
| OUT UINT8 **OpCodeData, | |
| OUT EFI_STRING *ConfigRequest | |
| ) | |
| { | |
| LIST_ENTRY *Link; | |
| HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageListNode; | |
| HII_IFR_PACKAGE_INSTANCE *FormPackage; | |
| EFI_IFR_QUESTION_HEADER *Header; | |
| UINT8 *Storage; | |
| UINT8 *OpCode; | |
| CHAR16 *Name; | |
| UINT16 Offset; | |
| UINT16 Width; | |
| CHAR16 *ConfigHdr; | |
| CHAR16 *RequestElement; | |
| UINTN MaxLen; | |
| CHAR16 *StringPtr; | |
| ASSERT (DatabaseRecord != NULL && OpCodeData != NULL && ConfigRequest != NULL); | |
| OpCode = NULL; | |
| Name = NULL; | |
| Width = 0; | |
| Offset = 0; | |
| PackageListNode = DatabaseRecord->PackageList; | |
| // | |
| // Search the languages in the specified packagelist. | |
| // | |
| for (Link = PackageListNode->FormPkgHdr.ForwardLink; Link != &PackageListNode->FormPkgHdr; Link = Link->ForwardLink) { | |
| FormPackage = CR (Link, HII_IFR_PACKAGE_INSTANCE, IfrEntry, HII_IFR_PACKAGE_SIGNATURE); | |
| OpCode = FindQuestionFromStringId (FormPackage, KeywordStrId); | |
| if (OpCode != NULL) { | |
| *OpCodeData = OpCode; | |
| Header = (EFI_IFR_QUESTION_HEADER *) (OpCode + sizeof (EFI_IFR_OP_HEADER)); | |
| // | |
| // Header->VarStoreId == 0 means no storage for this question. | |
| // | |
| ASSERT (Header->VarStoreId != 0); | |
| DEBUG ((EFI_D_INFO, "Varstore Id: 0x%x\n", Header->VarStoreId)); | |
| Storage = FindStorageFromVarId (FormPackage, Header->VarStoreId); | |
| ASSERT (Storage != NULL); | |
| if (((EFI_IFR_OP_HEADER *) Storage)->OpCode == EFI_IFR_VARSTORE_NAME_VALUE_OP) { | |
| Name = GetNameFromId (DatabaseRecord, Header->VarStoreInfo.VarName); | |
| } else { | |
| Offset = Header->VarStoreInfo.VarOffset; | |
| Width = GetWidth (OpCode); | |
| } | |
| RequestElement = ConstructRequestElement(Name, Offset, Width); | |
| ConfigHdr = ConstructConfigHdr(Storage, DatabaseRecord->DriverHandle); | |
| ASSERT (ConfigHdr != NULL); | |
| MaxLen = StrLen (ConfigHdr) + 1 + StrLen(RequestElement) + 1; | |
| *ConfigRequest = AllocatePool (MaxLen * sizeof (CHAR16)); | |
| if (*ConfigRequest == NULL) { | |
| FreePool (ConfigHdr); | |
| FreePool (RequestElement); | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| StringPtr = *ConfigRequest; | |
| StrCpyS (StringPtr, MaxLen, ConfigHdr); | |
| StrCatS (StringPtr, MaxLen, L"&"); | |
| StrCatS (StringPtr, MaxLen, RequestElement); | |
| FreePool (ConfigHdr); | |
| FreePool (RequestElement); | |
| return EFI_SUCCESS; | |
| } | |
| } | |
| return EFI_NOT_FOUND; | |
| } | |
| /** | |
| Base on the input parameter to generate the ConfigResp string. | |
| This is a internal function. | |
| @param DatabaseRecord HII_DATABASE_RECORD format string. | |
| @param KeywordStrId Keyword string id. | |
| @param ValueElement The value for the question which use keyword string id | |
| as the prompt string id. | |
| @param OpCodeData The IFR data for this question. | |
| @param ConfigResp Return the generate ConfigResp string. | |
| @retval EFI_SUCCESS Generate ConfigResp string success. | |
| @retval EFI_OUT_OF_RESOURCES System out of memory resource error. | |
| @retval EFI_NOT_FOUND Not found the question which use this string id | |
| as the prompt string id. | |
| **/ | |
| EFI_STATUS | |
| ExtractConfigResp ( | |
| IN HII_DATABASE_RECORD *DatabaseRecord, | |
| IN EFI_STRING_ID KeywordStrId, | |
| IN EFI_STRING ValueElement, | |
| OUT UINT8 **OpCodeData, | |
| OUT EFI_STRING *ConfigResp | |
| ) | |
| { | |
| LIST_ENTRY *Link; | |
| HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageListNode; | |
| HII_IFR_PACKAGE_INSTANCE *FormPackage; | |
| EFI_IFR_QUESTION_HEADER *Header; | |
| UINT8 *Storage; | |
| UINT8 *OpCode; | |
| CHAR16 *Name; | |
| UINT16 Offset; | |
| UINT16 Width; | |
| CHAR16 *ConfigHdr; | |
| CHAR16 *RequestElement; | |
| UINTN MaxLen; | |
| CHAR16 *StringPtr; | |
| ASSERT ((DatabaseRecord != NULL) && (OpCodeData != NULL) && (ConfigResp != NULL) && (ValueElement != NULL)); | |
| OpCode = NULL; | |
| Name = NULL; | |
| Width = 0; | |
| Offset = 0; | |
| PackageListNode = DatabaseRecord->PackageList; | |
| // | |
| // Search the languages in the specified packagelist. | |
| // | |
| for (Link = PackageListNode->FormPkgHdr.ForwardLink; Link != &PackageListNode->FormPkgHdr; Link = Link->ForwardLink) { | |
| FormPackage = CR (Link, HII_IFR_PACKAGE_INSTANCE, IfrEntry, HII_IFR_PACKAGE_SIGNATURE); | |
| OpCode = FindQuestionFromStringId (FormPackage, KeywordStrId); | |
| if (OpCode != NULL) { | |
| *OpCodeData = OpCode; | |
| Header = (EFI_IFR_QUESTION_HEADER *) (OpCode + sizeof (EFI_IFR_OP_HEADER)); | |
| // | |
| // Header->VarStoreId == 0 means no storage for this question. | |
| // | |
| ASSERT (Header->VarStoreId != 0); | |
| DEBUG ((EFI_D_INFO, "Varstore Id: 0x%x\n", Header->VarStoreId)); | |
| Storage = FindStorageFromVarId (FormPackage, Header->VarStoreId); | |
| ASSERT (Storage != NULL); | |
| if (((EFI_IFR_OP_HEADER *) Storage)->OpCode == EFI_IFR_VARSTORE_NAME_VALUE_OP) { | |
| Name = GetNameFromId (DatabaseRecord, Header->VarStoreInfo.VarName); | |
| } else { | |
| Offset = Header->VarStoreInfo.VarOffset; | |
| Width = GetWidth (OpCode); | |
| } | |
| RequestElement = ConstructRequestElement(Name, Offset, Width); | |
| ConfigHdr = ConstructConfigHdr(Storage, DatabaseRecord->DriverHandle); | |
| ASSERT (ConfigHdr != NULL); | |
| MaxLen = StrLen (ConfigHdr) + 1 + StrLen(RequestElement) + 1 + StrLen (L"VALUE=") + StrLen(ValueElement) + 1; | |
| *ConfigResp = AllocatePool (MaxLen * sizeof (CHAR16)); | |
| if (*ConfigResp == NULL) { | |
| FreePool (ConfigHdr); | |
| FreePool (RequestElement); | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| StringPtr = *ConfigResp; | |
| StrCpyS (StringPtr, MaxLen, ConfigHdr); | |
| StrCatS (StringPtr, MaxLen, L"&"); | |
| StrCatS (StringPtr, MaxLen, RequestElement); | |
| StrCatS (StringPtr, MaxLen, L"&"); | |
| StrCatS (StringPtr, MaxLen, L"VALUE="); | |
| StrCatS (StringPtr, MaxLen, ValueElement); | |
| FreePool (ConfigHdr); | |
| FreePool (RequestElement); | |
| return EFI_SUCCESS; | |
| } | |
| } | |
| return EFI_NOT_FOUND; | |
| } | |
| /** | |
| Get the Value section from the Hii driver. | |
| This is a internal function. | |
| @param ConfigRequest The input ConfigRequest string. | |
| @param ValueElement The respond Value section from the hii driver. | |
| @retval Misc value The error status return from ExtractConfig function. | |
| @retval EFI_OUT_OF_RESOURCES The memory can't be allocated | |
| @retval EFI_SUCCESS Get the value section success. | |
| **/ | |
| EFI_STATUS | |
| ExtractValueFromDriver ( | |
| IN CHAR16 *ConfigRequest, | |
| OUT CHAR16 **ValueElement | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_STRING Result; | |
| EFI_STRING Progress; | |
| CHAR16 *StringPtr; | |
| CHAR16 *StringEnd; | |
| ASSERT ((ConfigRequest != NULL) && (ValueElement != NULL)); | |
| Status = mPrivate.ConfigRouting.ExtractConfig ( | |
| &mPrivate.ConfigRouting, | |
| (EFI_STRING) ConfigRequest, | |
| &Progress, | |
| &Result | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| // | |
| // Find Value Section and return it. | |
| // | |
| StringPtr = StrStr (Result, L"&VALUE="); | |
| ASSERT (StringPtr != NULL); | |
| StringEnd = StrStr (StringPtr + 1, L"&"); | |
| if (StringEnd != NULL) { | |
| *StringEnd = L'\0'; | |
| } | |
| *ValueElement = AllocateCopyPool (StrSize (StringPtr), StringPtr); | |
| if (*ValueElement == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| if (StringEnd != NULL) { | |
| *StringEnd = L'&'; | |
| } | |
| FreePool (Result); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Get EFI_STRING_ID info from the input device path, namespace and keyword. | |
| This is a internal function. | |
| @param DevicePath Input device path info. | |
| @param NameSpace NameSpace format string. | |
| @param KeywordData Keyword used to get string id. | |
| @param ProgressErr Return extra error type. | |
| @param KeywordStringId Return EFI_STRING_ID. | |
| @param DataBaseRecord DataBase record data for this driver. | |
| @retval EFI_INVALID_PARAMETER Can't find the database record base on the input device path or namespace. | |
| @retval EFI_NOT_FOUND Can't find the EFI_STRING_ID for the keyword. | |
| @retval EFI_SUCCESS Find the EFI_STRING_ID. | |
| **/ | |
| EFI_STATUS | |
| GetStringIdFromDatabase ( | |
| IN EFI_DEVICE_PATH_PROTOCOL **DevicePath, | |
| IN CHAR8 **NameSpace, | |
| IN CHAR16 *KeywordData, | |
| OUT UINT32 *ProgressErr, | |
| OUT EFI_STRING_ID *KeywordStringId, | |
| OUT HII_DATABASE_RECORD **DataBaseRecord | |
| ) | |
| { | |
| HII_DATABASE_RECORD *Record; | |
| LIST_ENTRY *Link; | |
| BOOLEAN FindNameSpace; | |
| EFI_DEVICE_PATH_PROTOCOL *DestDevicePath; | |
| UINT8 *DevicePathPkg; | |
| UINTN DevicePathSize; | |
| ASSERT ((NameSpace != NULL) && (KeywordData != NULL) && (ProgressErr != NULL) && (KeywordStringId != NULL) && (DataBaseRecord != NULL)); | |
| FindNameSpace = FALSE; | |
| if (*DevicePath != NULL) { | |
| // | |
| // Get DataBaseRecord from device path protocol. | |
| // | |
| Record = GetRecordFromDevicePath(*DevicePath); | |
| if (Record == NULL) { | |
| // | |
| // Can't find the DatabaseRecord base on the input device path info. | |
| // NEED TO CONFIRM the return ProgressErr. | |
| // | |
| *ProgressErr = KEYWORD_HANDLER_MALFORMED_STRING; | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // Get string id from the record. | |
| // | |
| *ProgressErr = GetStringIdFromRecord (Record, NameSpace, KeywordData, KeywordStringId); | |
| switch (*ProgressErr) { | |
| case KEYWORD_HANDLER_NO_ERROR: | |
| *DataBaseRecord = Record; | |
| return EFI_SUCCESS; | |
| case KEYWORD_HANDLER_NAMESPACE_ID_NOT_FOUND: | |
| return EFI_INVALID_PARAMETER; | |
| default: | |
| ASSERT (*ProgressErr == KEYWORD_HANDLER_KEYWORD_NOT_FOUND); | |
| return EFI_NOT_FOUND; | |
| } | |
| } else { | |
| // | |
| // Find driver which matches the routing data. | |
| // | |
| for (Link = mPrivate.DatabaseList.ForwardLink; Link != &mPrivate.DatabaseList; Link = Link->ForwardLink) { | |
| Record = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE); | |
| *ProgressErr = GetStringIdFromRecord (Record, NameSpace, KeywordData, KeywordStringId); | |
| if (*ProgressErr == KEYWORD_HANDLER_NO_ERROR) { | |
| *DataBaseRecord = Record; | |
| if ((DevicePathPkg = Record->PackageList->DevicePathPkg) != NULL) { | |
| DestDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) (DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER)); | |
| DevicePathSize = GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) DestDevicePath); | |
| *DevicePath = AllocateCopyPool (DevicePathSize, DestDevicePath); | |
| if (*DevicePath == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| } else { | |
| // | |
| // Need to verify this ASSERT. | |
| // | |
| ASSERT (FALSE); | |
| } | |
| return EFI_SUCCESS; | |
| } else if (*ProgressErr == KEYWORD_HANDLER_UNDEFINED_PROCESSING_ERROR) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } else if (*ProgressErr == KEYWORD_HANDLER_KEYWORD_NOT_FOUND) { | |
| FindNameSpace = TRUE; | |
| } | |
| } | |
| // | |
| // When PathHdr not input, if ever find the namespace, will return KEYWORD_HANDLER_KEYWORD_NOT_FOUND. | |
| // This is a bit more progress than KEYWORD_HANDLER_NAMESPACE_ID_NOT_FOUND. | |
| // | |
| if (FindNameSpace) { | |
| return EFI_NOT_FOUND; | |
| } else { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| } | |
| } | |
| /** | |
| Genereate 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; | |
| ASSERT ((NameSpace != NULL) && (DevicePath != NULL) && (KeywordData != NULL) && (ValueStr != NULL) && (KeywordResp != NULL)); | |
| // | |
| // 1. Calculate the string length. | |
| // | |
| // | |
| // 1.1 NameSpaceId size. | |
| // 'NAMESPACE='<String> | |
| // | |
| RespStrLen = 10 + AsciiStrLen (NameSpace); | |
| UnicodeNameSpace = AllocatePool ((AsciiStrLen (NameSpace) + 1) * sizeof (CHAR16)); | |
| if (UnicodeNameSpace == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| AsciiStrToUnicodeStr(NameSpace, UnicodeNameSpace); | |
| // | |
| // 1.2 PathHdr size. | |
| // PATH=<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 setion. | |
| // '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 = AllocateCopyPool (MultiKeywordRespLen, *MultiKeywordResp); | |
| if (StringPtr == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| FreePool (*MultiKeywordResp); | |
| *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 occured. | |
| // | |
| 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 string element if the request was | |
| not successful. | |
| @param ProgressErr If during the processing of the KeywordString there was | |
| a failure, this parameter gives additional information | |
| about the possible source of the problem. The various | |
| errors are defined in "Related Definitions" below. | |
| @retval EFI_SUCCESS The specified action was completed successfully. | |
| @retval EFI_INVALID_PARAMETER One or more of the following are TRUE: | |
| 1. KeywordString is NULL. | |
| 2. Parsing of the KeywordString resulted in an | |
| error. See Progress and ProgressErr for more data. | |
| @retval EFI_NOT_FOUND An element of the KeywordString was not found. | |
| See ProgressErr for more data. | |
| @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. | |
| See ProgressErr for more data. | |
| @retval EFI_ACCESS_DENIED The action violated system policy. See ProgressErr | |
| for more data. | |
| @retval EFI_DEVICE_ERROR An unexpected system error occurred. See ProgressErr | |
| for more data. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| EfiConfigKeywordHandlerSetData ( | |
| IN EFI_CONFIG_KEYWORD_HANDLER_PROTOCOL *This, | |
| IN CONST EFI_STRING KeywordString, | |
| OUT EFI_STRING *Progress, | |
| OUT UINT32 *ProgressErr | |
| ) | |
| { | |
| CHAR8 *NameSpace; | |
| EFI_STATUS Status; | |
| CHAR16 *StringPtr; | |
| EFI_DEVICE_PATH_PROTOCOL *DevicePath; | |
| CHAR16 *NextStringPtr; | |
| CHAR16 *KeywordData; | |
| EFI_STRING_ID KeywordStringId; | |
| UINT32 RetVal; | |
| HII_DATABASE_RECORD *DataBaseRecord; | |
| UINT8 *OpCode; | |
| CHAR16 *ConfigResp; | |
| CHAR16 *MultiConfigResp; | |
| CHAR16 *ValueElement; | |
| BOOLEAN ReadOnly; | |
| EFI_STRING InternalProgress; | |
| 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 filter. | |
| // | |
| if ((StringPtr != NULL) && StrnCmp (StringPtr, L"&ReadOnly", StrLen (L"&ReadOnly")) == 0) { | |
| ReadOnly = TRUE; | |
| StringPtr += StrLen (L"&ReadOnly"); | |
| } else { | |
| ReadOnly = FALSE; | |
| } | |
| // | |
| // 6. Get EFI_STRING_ID for the input keyword. | |
| // | |
| Status = GetStringIdFromDatabase (&DevicePath, &NameSpace, KeywordData, &RetVal, &KeywordStringId, &DataBaseRecord); | |
| if (EFI_ERROR (Status)) { | |
| *ProgressErr = RetVal; | |
| goto Done; | |
| } | |
| // | |
| // 7. Construct the ConfigRequest string. | |
| // | |
| Status = ExtractConfigResp (DataBaseRecord, KeywordStringId, ValueElement, &OpCode, &ConfigResp); | |
| if (EFI_ERROR (Status)) { | |
| goto Done; | |
| } | |
| // | |
| // 8. Check the readonly flag. | |
| // | |
| if (ExtractReadOnlyFromOpCode (OpCode) != ReadOnly) { | |
| *ProgressErr = KEYWORD_HANDLER_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 string | |
| element if the request was not successful. | |
| @param ProgressErr If during the processing of the KeywordString there was a | |
| failure, this parameter gives additional information about the | |
| possible source of the problem. See the definitions in SetData() | |
| for valid value definitions. | |
| @param Results A null-terminated string in <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 Resuts is NULL. | |
| 2.Parsing of the KeywordString resulted in an error. See | |
| Progress and ProgressErr for more data. | |
| @retval EFI_NOT_FOUND An element of the KeywordString was not found. See | |
| ProgressErr for more data. | |
| @retval EFI_NOT_FOUND The NamespaceId specified was not found. See ProgressErr | |
| for more data. | |
| @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. See | |
| ProgressErr for more data. | |
| @retval EFI_ACCESS_DENIED The action violated system policy. See ProgressErr for | |
| more data. | |
| @retval EFI_DEVICE_ERROR An unexpected system error occurred. See ProgressErr | |
| for more data. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| EfiConfigKeywordHandlerGetData ( | |
| IN EFI_CONFIG_KEYWORD_HANDLER_PROTOCOL *This, | |
| IN CONST EFI_STRING NameSpaceId, OPTIONAL | |
| IN CONST EFI_STRING KeywordString, OPTIONAL | |
| OUT EFI_STRING *Progress, | |
| OUT UINT32 *ProgressErr, | |
| OUT EFI_STRING *Results | |
| ) | |
| { | |
| CHAR8 *NameSpace; | |
| EFI_STATUS Status; | |
| EFI_DEVICE_PATH_PROTOCOL *DevicePath; | |
| HII_DATABASE_RECORD *DataBaseRecord; | |
| CHAR16 *StringPtr; | |
| CHAR16 *NextStringPtr; | |
| CHAR16 *KeywordData; | |
| EFI_STRING_ID KeywordStringId; | |
| UINT8 *OpCode; | |
| CHAR16 *ConfigRequest; | |
| CHAR16 *ValueElement; | |
| UINT32 RetVal; | |
| BOOLEAN ReadOnly; | |
| CHAR16 *KeywordResp; | |
| CHAR16 *MultiKeywordResp; | |
| 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; | |
| } |