| /** @file | |
| Implementation of interfaces function for EFI_HII_CONFIG_ROUTING_PROTOCOL. | |
| Copyright (c) 2007 - 2010, Intel Corporation | |
| All rights reserved. This program and the accompanying materials | |
| are licensed and made available under the terms and conditions of the BSD License | |
| which accompanies this distribution. The full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license.php | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| **/ | |
| #include "HiiDatabase.h" | |
| extern HII_DATABASE_PRIVATE_DATA mPrivate; | |
| /** | |
| Calculate the number of Unicode characters of the incoming Configuration string, | |
| not including NULL terminator. | |
| This is a internal function. | |
| @param String String in <MultiConfigRequest> or | |
| <MultiConfigResp> format. | |
| @return The number of Unicode characters. | |
| **/ | |
| UINTN | |
| CalculateConfigStringLen ( | |
| IN EFI_STRING String | |
| ) | |
| { | |
| EFI_STRING TmpPtr; | |
| // | |
| // "GUID=" should be the first element of incoming string. | |
| // | |
| ASSERT (String != NULL); | |
| ASSERT (StrnCmp (String, L"GUID=", StrLen (L"GUID=")) == 0); | |
| // | |
| // The beginning of next <ConfigRequest>/<ConfigResp> should be "&GUID=". | |
| // Will meet '\0' if there is only one <ConfigRequest>/<ConfigResp>. | |
| // | |
| TmpPtr = StrStr (String, L"&GUID="); | |
| if (TmpPtr == NULL) { | |
| return StrLen (String); | |
| } | |
| return (TmpPtr - String); | |
| } | |
| /** | |
| Convert the hex UNICODE %02x encoding of a UEFI device path to binary | |
| from <PathHdr> of <ConfigHdr>. | |
| This is a internal function. | |
| @param String UEFI configuration string | |
| @param DevicePathData Binary of a UEFI device path. | |
| @retval EFI_NOT_FOUND The device path is not invalid. | |
| @retval EFI_INVALID_PARAMETER Any 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. | |
| **/ | |
| EFI_STATUS | |
| GetDevicePath ( | |
| IN EFI_STRING String, | |
| OUT UINT8 **DevicePathData | |
| ) | |
| { | |
| UINTN Length; | |
| EFI_STRING PathHdr; | |
| UINT8 *DevicePathBuffer; | |
| CHAR16 TemStr[2]; | |
| UINTN Index; | |
| UINT8 DigitUint8; | |
| EFI_DEVICE_PATH_PROTOCOL *DevicePath; | |
| if (String == NULL || DevicePathData == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // Find the 'PATH=' of <PathHdr> and skip it. | |
| // | |
| for (; (*String != 0 && StrnCmp (String, L"PATH=", StrLen (L"PATH=")) != 0); String++); | |
| if (*String == 0) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // 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++); | |
| // | |
| // Check DevicePath Length | |
| // | |
| if (((Length + 1) / 2) < sizeof (EFI_DEVICE_PATH_PROTOCOL)) { | |
| return EFI_NOT_FOUND; | |
| } | |
| // | |
| // 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_NOT_FOUND; | |
| } | |
| DevicePath = NextDevicePathNode (DevicePath); | |
| } | |
| // | |
| // return the device path | |
| // | |
| *DevicePathData = DevicePathBuffer; | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Converts the unicode character of the string from uppercase to lowercase. | |
| This is a internal function. | |
| @param ConfigString String to be converted | |
| **/ | |
| VOID | |
| EFIAPI | |
| HiiToLower ( | |
| 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; | |
| } | |
| /** | |
| Generate a sub string then output it. | |
| This is a internal function. | |
| @param String A constant string which is the prefix of the to be | |
| generated string, e.g. GUID= | |
| @param BufferLen The length of the Buffer in bytes. | |
| @param Buffer Points to a buffer which will be converted to be the | |
| content of the generated string. | |
| @param Flag If 1, the buffer contains data for the value of GUID or PATH stored in | |
| UINT8 *; if 2, the buffer contains unicode string for the value of NAME; | |
| if 3, the buffer contains other data. | |
| @param SubStr Points to the output string. It's caller's | |
| responsibility to free this buffer. | |
| **/ | |
| VOID | |
| GenerateSubStr ( | |
| IN CONST EFI_STRING String, | |
| IN UINTN BufferLen, | |
| IN VOID *Buffer, | |
| IN UINT8 Flag, | |
| OUT EFI_STRING *SubStr | |
| ) | |
| { | |
| UINTN Length; | |
| EFI_STRING Str; | |
| EFI_STRING StringHeader; | |
| CHAR16 *TemString; | |
| CHAR16 *TemName; | |
| UINT8 *TemBuffer; | |
| UINTN Index; | |
| ASSERT (String != NULL && SubStr != NULL); | |
| if (Buffer == NULL) { | |
| *SubStr = AllocateCopyPool (StrSize (String), String); | |
| ASSERT (*SubStr != NULL); | |
| return ; | |
| } | |
| // | |
| // Header + Data + '&' + '\0' | |
| // | |
| Length = StrLen (String) + BufferLen * 2 + 1 + 1; | |
| Str = AllocateZeroPool (Length * sizeof (CHAR16)); | |
| ASSERT (Str != NULL); | |
| StrCpy (Str, String); | |
| Length = (BufferLen * 2 + 1) * sizeof (CHAR16); | |
| StringHeader = Str + StrLen (String); | |
| TemString = (CHAR16 *) StringHeader; | |
| switch (Flag) { | |
| case 1: | |
| // | |
| // Convert Buffer to Hex String in reverse order | |
| // | |
| TemBuffer = ((UINT8 *) Buffer); | |
| for (Index = 0; Index < BufferLen; Index ++, TemBuffer ++) { | |
| TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemBuffer, 2); | |
| } | |
| break; | |
| case 2: | |
| // | |
| // Check buffer is enough | |
| // | |
| TemName = (CHAR16 *) Buffer; | |
| ASSERT ((BufferLen * 2 + 1) >= (StrLen (TemName) * 4 + 1)); | |
| // | |
| // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044" | |
| // | |
| for (; *TemName != L'\0'; TemName++) { | |
| TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemName, 4); | |
| } | |
| break; | |
| case 3: | |
| // | |
| // Convert Buffer to Hex String | |
| // | |
| TemBuffer = ((UINT8 *) Buffer) + BufferLen - 1; | |
| for (Index = 0; Index < BufferLen; Index ++, TemBuffer --) { | |
| TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemBuffer, 2); | |
| } | |
| break; | |
| default: | |
| break; | |
| } | |
| // | |
| // Convert the uppercase to lowercase since <HexAf> is defined in lowercase format. | |
| // | |
| StrCat (Str, L"&"); | |
| HiiToLower (Str); | |
| *SubStr = Str; | |
| } | |
| /** | |
| Retrieve the <ConfigBody> from String then output it. | |
| This is a internal function. | |
| @param String A sub string of a configuration string in | |
| <MultiConfigAltResp> format. | |
| @param ConfigBody Points to the output string. It's caller's | |
| responsibility to free this buffer. | |
| @retval EFI_INVALID_PARAMETER There is no form package in current hii database. | |
| @retval EFI_OUT_OF_RESOURCES Not enough memory to finish this operation. | |
| @retval EFI_SUCCESS All existing storage is exported. | |
| **/ | |
| EFI_STATUS | |
| OutputConfigBody ( | |
| IN EFI_STRING String, | |
| OUT EFI_STRING *ConfigBody | |
| ) | |
| { | |
| EFI_STRING TmpPtr; | |
| EFI_STRING Result; | |
| UINTN Length; | |
| if (String == NULL || ConfigBody == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // The setting information should start OFFSET, not ALTCFG. | |
| // | |
| if (StrnCmp (String, L"&ALTCFG=", StrLen (L"&ALTCFG=")) == 0) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| TmpPtr = StrStr (String, L"GUID="); | |
| if (TmpPtr == NULL) { | |
| // | |
| // It is the last <ConfigResp> of the incoming configuration string. | |
| // | |
| Result = AllocateCopyPool (StrSize (String), String); | |
| if (Result == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } else { | |
| *ConfigBody = Result; | |
| return EFI_SUCCESS; | |
| } | |
| } | |
| Length = TmpPtr - String; | |
| Result = AllocateCopyPool (Length * sizeof (CHAR16), String); | |
| if (Result == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| *(Result + Length - 1) = 0; | |
| *ConfigBody = Result; | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Append a string to a multi-string format. | |
| This is a internal function. | |
| @param MultiString String in <MultiConfigRequest>, | |
| <MultiConfigAltResp>, or <MultiConfigResp>. On | |
| input, the buffer length of this string is | |
| MAX_STRING_LENGTH. On output, the buffer length | |
| might be updated. | |
| @param AppendString NULL-terminated Unicode string. | |
| @retval EFI_INVALID_PARAMETER Any incoming parameter is invalid. | |
| @retval EFI_SUCCESS AppendString is append to the end of MultiString | |
| **/ | |
| EFI_STATUS | |
| AppendToMultiString ( | |
| IN OUT EFI_STRING *MultiString, | |
| IN EFI_STRING AppendString | |
| ) | |
| { | |
| UINTN AppendStringSize; | |
| UINTN MultiStringSize; | |
| if (MultiString == NULL || *MultiString == NULL || AppendString == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| AppendStringSize = StrSize (AppendString); | |
| MultiStringSize = StrSize (*MultiString); | |
| // | |
| // Enlarge the buffer each time when length exceeds MAX_STRING_LENGTH. | |
| // | |
| if (MultiStringSize + AppendStringSize > MAX_STRING_LENGTH || | |
| MultiStringSize > MAX_STRING_LENGTH) { | |
| *MultiString = (EFI_STRING) ReallocatePool ( | |
| MultiStringSize, | |
| MultiStringSize + AppendStringSize, | |
| (VOID *) (*MultiString) | |
| ); | |
| ASSERT (*MultiString != NULL); | |
| } | |
| // | |
| // Append the incoming string | |
| // | |
| StrCat (*MultiString, AppendString); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Get the value of <Number> in <BlockConfig> format, i.e. the value of OFFSET | |
| or WIDTH or VALUE. | |
| <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE'=<Number> | |
| This is a internal function. | |
| @param StringPtr String in <BlockConfig> format and points to the | |
| first character of <Number>. | |
| @param Number The output value. Caller takes the responsibility | |
| to free memory. | |
| @param Len Length of the <Number>, in characters. | |
| @retval EFI_OUT_OF_RESOURCES Insufficient resources to store neccessary | |
| structures. | |
| @retval EFI_SUCCESS Value of <Number> is outputted in Number | |
| successfully. | |
| **/ | |
| EFI_STATUS | |
| GetValueOfNumber ( | |
| IN EFI_STRING StringPtr, | |
| OUT UINT8 **Number, | |
| OUT UINTN *Len | |
| ) | |
| { | |
| EFI_STRING TmpPtr; | |
| UINTN Length; | |
| EFI_STRING Str; | |
| UINT8 *Buf; | |
| EFI_STATUS Status; | |
| UINT8 DigitUint8; | |
| UINTN Index; | |
| CHAR16 TemStr[2]; | |
| ASSERT (StringPtr != NULL && Number != NULL && Len != NULL); | |
| ASSERT (*StringPtr != L'\0'); | |
| Buf = NULL; | |
| TmpPtr = StringPtr; | |
| while (*StringPtr != L'\0' && *StringPtr != L'&') { | |
| StringPtr++; | |
| } | |
| *Len = StringPtr - TmpPtr; | |
| Length = *Len + 1; | |
| Str = (EFI_STRING) AllocateZeroPool (Length * sizeof (CHAR16)); | |
| if (Str == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto Exit; | |
| } | |
| CopyMem (Str, TmpPtr, *Len * sizeof (CHAR16)); | |
| *(Str + *Len) = L'\0'; | |
| Length = (Length + 1) / 2; | |
| Buf = (UINT8 *) AllocateZeroPool (Length); | |
| if (Buf == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto Exit; | |
| } | |
| Length = *Len; | |
| ZeroMem (TemStr, sizeof (TemStr)); | |
| for (Index = 0; Index < Length; Index ++) { | |
| TemStr[0] = Str[Length - Index - 1]; | |
| DigitUint8 = (UINT8) StrHexToUint64 (TemStr); | |
| if ((Index & 1) == 0) { | |
| Buf [Index/2] = DigitUint8; | |
| } else { | |
| Buf [Index/2] = (UINT8) ((DigitUint8 << 4) + Buf [Index/2]); | |
| } | |
| } | |
| *Number = Buf; | |
| Status = EFI_SUCCESS; | |
| Exit: | |
| if (Str != NULL) { | |
| FreePool (Str); | |
| } | |
| return Status; | |
| } | |
| /** | |
| This function merges DefaultAltCfgResp string into AltCfgResp string for | |
| the missing AltCfgId in AltCfgResq. | |
| @param AltCfgResp Pointer to a null-terminated Unicode string in | |
| <ConfigAltResp> format. The default value string | |
| will be merged into it. | |
| @param DefaultAltCfgResp Pointer to a null-terminated Unicode string in | |
| <MultiConfigAltResp> format. The default value | |
| string may contain more than one ConfigAltResp | |
| string for the different varstore buffer. | |
| @retval EFI_SUCCESS The merged string returns. | |
| @retval EFI_INVALID_PARAMETER *AltCfgResp is to NULL. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| MergeDefaultString ( | |
| IN OUT EFI_STRING *AltCfgResp, | |
| IN EFI_STRING DefaultAltCfgResp | |
| ) | |
| { | |
| EFI_STRING StringPtrDefault; | |
| EFI_STRING StringPtrEnd; | |
| CHAR16 TempChar; | |
| EFI_STRING StringPtr; | |
| EFI_STRING AltConfigHdr; | |
| UINTN HeaderLength; | |
| UINTN SizeAltCfgResp; | |
| if (*AltCfgResp == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // Get the requestr ConfigHdr | |
| // | |
| SizeAltCfgResp = 0; | |
| StringPtr = *AltCfgResp; | |
| // | |
| // Find <ConfigHdr> GUID=...&NAME=...&PATH=... | |
| // | |
| if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&NAME=", StrLen (L"&NAME=")) != 0) { | |
| StringPtr++; | |
| } | |
| while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&PATH=", StrLen (L"&PATH=")) != 0) { | |
| StringPtr++; | |
| } | |
| if (*StringPtr == L'\0') { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| StringPtr += StrLen (L"&PATH="); | |
| while (*StringPtr != L'\0' && *StringPtr != L'&') { | |
| StringPtr ++; | |
| } | |
| HeaderLength = StringPtr - *AltCfgResp; | |
| // | |
| // Construct AltConfigHdr string "&<ConfigHdr>&ALTCFG=XXXX\0" | |
| // |1| StrLen (ConfigHdr) | 8 | 4 | 1 | | |
| // | |
| AltConfigHdr = AllocateZeroPool ((1 + HeaderLength + 8 + 4 + 1) * sizeof (CHAR16)); | |
| if (AltConfigHdr == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| StrCpy (AltConfigHdr, L"&"); | |
| StrnCat (AltConfigHdr, *AltCfgResp, HeaderLength); | |
| StrCat (AltConfigHdr, L"&ALTCFG="); | |
| HeaderLength = StrLen (AltConfigHdr); | |
| StringPtrDefault = StrStr (DefaultAltCfgResp, AltConfigHdr); | |
| while (StringPtrDefault != NULL) { | |
| // | |
| // Get AltCfg Name | |
| // | |
| StrnCat (AltConfigHdr, StringPtrDefault + HeaderLength, 4); | |
| StringPtr = StrStr (*AltCfgResp, AltConfigHdr); | |
| // | |
| // Append the found default value string to the input AltCfgResp | |
| // | |
| if (StringPtr == NULL) { | |
| StringPtrEnd = StrStr (StringPtrDefault + 1, L"&GUID"); | |
| SizeAltCfgResp = StrSize (*AltCfgResp); | |
| if (StringPtrEnd == NULL) { | |
| // | |
| // No more default string is found. | |
| // | |
| *AltCfgResp = (EFI_STRING) ReallocatePool ( | |
| SizeAltCfgResp, | |
| SizeAltCfgResp + StrSize (StringPtrDefault), | |
| (VOID *) (*AltCfgResp) | |
| ); | |
| if (*AltCfgResp == NULL) { | |
| FreePool (AltConfigHdr); | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| StrCat (*AltCfgResp, StringPtrDefault); | |
| break; | |
| } else { | |
| TempChar = *StringPtrEnd; | |
| *StringPtrEnd = L'\0'; | |
| *AltCfgResp = (EFI_STRING) ReallocatePool ( | |
| SizeAltCfgResp, | |
| SizeAltCfgResp + StrSize (StringPtrDefault), | |
| (VOID *) (*AltCfgResp) | |
| ); | |
| if (*AltCfgResp == NULL) { | |
| FreePool (AltConfigHdr); | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| StrCat (*AltCfgResp, StringPtrDefault); | |
| *StringPtrEnd = TempChar; | |
| } | |
| } | |
| // | |
| // Find next AltCfg String | |
| // | |
| *(AltConfigHdr + HeaderLength) = L'\0'; | |
| StringPtrDefault = StrStr (StringPtrDefault + 1, AltConfigHdr); | |
| } | |
| FreePool (AltConfigHdr); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| This function finds the matched DefaultName for the input DefaultId | |
| @param DefaultIdArray Array stores the map table between DefaultId and DefaultName. | |
| @param VarDefaultId Default Id | |
| @param VarDefaultName Default Name string ID for the input default ID. | |
| @retval EFI_SUCCESS The mapped default name string ID is found. | |
| @retval EFI_NOT_FOUND The mapped default name string ID is not found. | |
| **/ | |
| EFI_STATUS | |
| FindDefaultName ( | |
| IN IFR_DEFAULT_DATA *DefaultIdArray, | |
| IN UINT16 VarDefaultId, | |
| OUT EFI_STRING_ID *VarDefaultName | |
| ) | |
| { | |
| LIST_ENTRY *Link; | |
| IFR_DEFAULT_DATA *DefaultData; | |
| for (Link = DefaultIdArray->Entry.ForwardLink; Link != &DefaultIdArray->Entry; Link = Link->ForwardLink) { | |
| DefaultData = BASE_CR (Link, IFR_DEFAULT_DATA, Entry); | |
| if (DefaultData->DefaultId == VarDefaultId) { | |
| *VarDefaultName = DefaultData->DefaultName; | |
| return EFI_SUCCESS; | |
| } | |
| } | |
| return EFI_NOT_FOUND; | |
| } | |
| /** | |
| This function inserts new DefaultValueData into the BlockData DefaultValue array. | |
| @param BlockData The BlockData is updated to add new default value. | |
| @param DefaultValueData The DefaultValue is added. | |
| **/ | |
| VOID | |
| InsertDefaultValue ( | |
| IN IFR_BLOCK_DATA *BlockData, | |
| IN IFR_DEFAULT_DATA *DefaultValueData | |
| ) | |
| { | |
| LIST_ENTRY *Link; | |
| IFR_DEFAULT_DATA *DefaultValueArray; | |
| for (Link = BlockData->DefaultValueEntry.ForwardLink; Link != &BlockData->DefaultValueEntry; Link = Link->ForwardLink) { | |
| DefaultValueArray = BASE_CR (Link, IFR_DEFAULT_DATA, Entry); | |
| if (DefaultValueArray->DefaultId == DefaultValueData->DefaultId) { | |
| if (DefaultValueData->OpCode == EFI_IFR_DEFAULT_OP) { | |
| // | |
| // Update the default value array in BlockData. | |
| // | |
| DefaultValueArray->Value = DefaultValueData->Value; | |
| } else if (DefaultValueArray->OpCode != EFI_IFR_DEFAULT_OP) { | |
| // | |
| // Update the default value array in BlockData. | |
| // | |
| DefaultValueArray->Value = DefaultValueData->Value; | |
| } | |
| FreePool (DefaultValueData); | |
| return; | |
| } else if (DefaultValueArray->DefaultId > DefaultValueData->DefaultId) { | |
| // | |
| // Insert new default value data in the front of this default value array. | |
| // | |
| InsertTailList (Link, &DefaultValueData->Entry); | |
| return; | |
| } | |
| } | |
| // | |
| // Insert new default value data in tail. | |
| // | |
| InsertTailList (Link, &DefaultValueData->Entry); | |
| return; | |
| } | |
| /** | |
| This function inserts new BlockData into the block link | |
| @param BlockLink The list entry points to block array. | |
| @param BlockData The point to BlockData is added. | |
| **/ | |
| VOID | |
| InsertBlockData ( | |
| IN LIST_ENTRY *BlockLink, | |
| IN IFR_BLOCK_DATA **BlockData | |
| ) | |
| { | |
| LIST_ENTRY *Link; | |
| IFR_BLOCK_DATA *BlockArray; | |
| IFR_BLOCK_DATA *BlockSingleData; | |
| BlockSingleData = *BlockData; | |
| // | |
| // Insert block data in its Offset and Width order. | |
| // | |
| for (Link = BlockLink->ForwardLink; Link != BlockLink; Link = Link->ForwardLink) { | |
| BlockArray = BASE_CR (Link, IFR_BLOCK_DATA, Entry); | |
| if (BlockArray->Offset == BlockSingleData->Offset) { | |
| if (BlockArray->Width > BlockSingleData->Width) { | |
| // | |
| // Insert this block data in the front of block array | |
| // | |
| InsertTailList (Link, &BlockSingleData->Entry); | |
| return; | |
| } | |
| if (BlockArray->Width == BlockSingleData->Width) { | |
| // | |
| // The same block array has been added. | |
| // | |
| FreePool (BlockSingleData); | |
| *BlockData = BlockArray; | |
| return; | |
| } | |
| } else if (BlockArray->Offset > BlockSingleData->Offset) { | |
| // | |
| // Insert new block data in the front of block array | |
| // | |
| InsertTailList (Link, &BlockSingleData->Entry); | |
| return; | |
| } | |
| } | |
| // | |
| // Add new block data into the tail. | |
| // | |
| InsertTailList (Link, &BlockSingleData->Entry); | |
| return; | |
| } | |
| /** | |
| This function checks VarOffset and VarWidth is in the block range. | |
| @param RequestBlockArray The block array is to be checked. | |
| @param VarOffset Offset of var to the structure | |
| @param VarWidth Width of var. | |
| @retval TRUE This Var is in the block range. | |
| @retval FALSE This Var is not in the block range. | |
| **/ | |
| BOOLEAN | |
| BlockArrayCheck ( | |
| IN IFR_BLOCK_DATA *RequestBlockArray, | |
| IN UINT16 VarOffset, | |
| IN UINT16 VarWidth | |
| ) | |
| { | |
| LIST_ENTRY *Link; | |
| IFR_BLOCK_DATA *BlockData; | |
| // | |
| // No Request Block array, all vars are got. | |
| // | |
| if (RequestBlockArray == NULL) { | |
| return TRUE; | |
| } | |
| // | |
| // Check the input var is in the request block range. | |
| // | |
| for (Link = RequestBlockArray->Entry.ForwardLink; Link != &RequestBlockArray->Entry; Link = Link->ForwardLink) { | |
| BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry); | |
| if ((VarOffset >= BlockData->Offset) && ((VarOffset + VarWidth) <= (BlockData->Offset + BlockData->Width))) { | |
| return TRUE; | |
| } | |
| } | |
| return FALSE; | |
| } | |
| /** | |
| This function parses Form Package to get the block array and the default | |
| value array according to the request ConfigHdr. | |
| @param Package Pointer to the form package data. | |
| @param PackageLength Length of the pacakge. | |
| @param ConfigHdr Request string ConfigHdr. If it is NULL, | |
| the first found varstore will be as ConfigHdr. | |
| @param RequestBlockArray The block array is retrieved from the request string. | |
| @param VarStorageData VarStorage structure contains the got block and default value. | |
| @param PIfrDefaultIdArray Point to the got default id and default name array. | |
| @retval EFI_SUCCESS The block array and the default value array are got. | |
| @retval EFI_INVALID_PARAMETER The varstore defintion in the differnt form pacakges | |
| are conflicted. | |
| @retval EFI_OUT_OF_RESOURCES No enough memory. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| ParseIfrData ( | |
| IN UINT8 *Package, | |
| IN UINT32 PackageLength, | |
| IN EFI_STRING ConfigHdr, | |
| IN IFR_BLOCK_DATA *RequestBlockArray, | |
| IN OUT IFR_VARSTORAGE_DATA *VarStorageData, | |
| OUT IFR_DEFAULT_DATA *DefaultIdArray | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| UINTN IfrOffset; | |
| EFI_IFR_VARSTORE *IfrVarStore; | |
| EFI_IFR_OP_HEADER *IfrOpHdr; | |
| EFI_IFR_ONE_OF *IfrOneOf; | |
| EFI_IFR_ONE_OF_OPTION *IfrOneOfOption; | |
| EFI_IFR_DEFAULT *IfrDefault; | |
| EFI_IFR_ORDERED_LIST *IfrOrderedList; | |
| EFI_IFR_CHECKBOX *IfrCheckBox; | |
| EFI_IFR_PASSWORD *IfrPassword; | |
| EFI_IFR_STRING *IfrString; | |
| IFR_DEFAULT_DATA *DefaultData; | |
| IFR_BLOCK_DATA *BlockData; | |
| CHAR16 *VarStoreName; | |
| UINT16 VarOffset; | |
| UINT16 VarWidth; | |
| EFI_STRING_ID VarDefaultName; | |
| UINT16 VarDefaultId; | |
| EFI_STRING GuidStr; | |
| EFI_STRING NameStr; | |
| EFI_STRING TempStr; | |
| UINTN LengthString; | |
| LengthString = 0; | |
| Status = EFI_SUCCESS; | |
| GuidStr = NULL; | |
| NameStr = NULL; | |
| TempStr = NULL; | |
| BlockData = NULL; | |
| DefaultData = NULL; | |
| VarDefaultName = 0; | |
| // | |
| // Go through the form package to parse OpCode one by one. | |
| // | |
| IfrOffset = sizeof (EFI_HII_PACKAGE_HEADER); | |
| while (IfrOffset < PackageLength) { | |
| IfrOpHdr = (EFI_IFR_OP_HEADER *) (Package + IfrOffset); | |
| switch (IfrOpHdr->OpCode) { | |
| case EFI_IFR_VARSTORE_OP: | |
| // | |
| // VarStore is found. Don't need to search any more. | |
| // | |
| if (VarStorageData->Size != 0) { | |
| break; | |
| } | |
| // | |
| // Get the requied varstore information | |
| // Add varstore by Guid and Name in ConfigHdr | |
| // Make sure Offset is in varstore size and varstoreid | |
| // | |
| IfrVarStore = (EFI_IFR_VARSTORE *) IfrOpHdr; | |
| VarStoreName = AllocateZeroPool (AsciiStrSize ((CHAR8 *)IfrVarStore->Name) * sizeof (CHAR16)); | |
| if (VarStoreName == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto Done; | |
| } | |
| AsciiStrToUnicodeStr ((CHAR8 *) IfrVarStore->Name, VarStoreName); | |
| GenerateSubStr (L"GUID=", sizeof (EFI_GUID), (VOID *) &IfrVarStore->Guid, 1, &GuidStr); | |
| GenerateSubStr (L"NAME=", StrLen (VarStoreName) * sizeof (CHAR16), (VOID *) VarStoreName, 2, &NameStr); | |
| LengthString = StrLen (GuidStr); | |
| LengthString = LengthString + StrLen (NameStr) + 1; | |
| TempStr = AllocateZeroPool (LengthString * sizeof (CHAR16)); | |
| if (TempStr == NULL) { | |
| FreePool (GuidStr); | |
| FreePool (NameStr); | |
| FreePool (VarStoreName); | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto Done; | |
| } | |
| StrCpy (TempStr, GuidStr); | |
| StrCat (TempStr, NameStr); | |
| if (ConfigHdr == NULL || StrnCmp (ConfigHdr, TempStr, StrLen (TempStr)) == 0) { | |
| // | |
| // Find the matched VarStore | |
| // | |
| CopyGuid (&VarStorageData->Guid, (EFI_GUID *) (VOID *) &IfrVarStore->Guid); | |
| VarStorageData->VarStoreId = IfrVarStore->VarStoreId; | |
| VarStorageData->Size = IfrVarStore->Size; | |
| VarStorageData->Name = VarStoreName; | |
| } else { | |
| // | |
| // No found, free the allocated memory | |
| // | |
| FreePool (VarStoreName); | |
| } | |
| // | |
| // Free alllocated temp string. | |
| // | |
| FreePool (GuidStr); | |
| FreePool (NameStr); | |
| FreePool (TempStr); | |
| break; | |
| case EFI_IFR_DEFAULTSTORE_OP: | |
| // | |
| // Add new the map between default id and default name. | |
| // | |
| DefaultData = (IFR_DEFAULT_DATA *) AllocateZeroPool (sizeof (IFR_DEFAULT_DATA)); | |
| if (DefaultData == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto Done; | |
| } | |
| DefaultData->DefaultId = ((EFI_IFR_DEFAULTSTORE *) IfrOpHdr)->DefaultId; | |
| DefaultData->DefaultName = ((EFI_IFR_DEFAULTSTORE *) IfrOpHdr)->DefaultName; | |
| InsertTailList (&DefaultIdArray->Entry, &DefaultData->Entry); | |
| DefaultData = NULL; | |
| break; | |
| case EFI_IFR_FORM_OP: | |
| case EFI_IFR_FORM_MAP_OP: | |
| // | |
| // No matched varstore is found and directly return. | |
| // | |
| if (VarStorageData->Size == 0) { | |
| Status = EFI_SUCCESS; | |
| goto Done; | |
| } | |
| break; | |
| case EFI_IFR_ONE_OF_OP: | |
| case EFI_IFR_NUMERIC_OP: | |
| // | |
| // Numeric and OneOf has the same opcode structure. | |
| // | |
| // | |
| // Numeric and OneOf question is not in IFR Form. This IFR form is not valid. | |
| // | |
| if (VarStorageData->Size == 0) { | |
| Status = EFI_INVALID_PARAMETER; | |
| goto Done; | |
| } | |
| // | |
| // Check whether this question is for the requested varstore. | |
| // | |
| IfrOneOf = (EFI_IFR_ONE_OF *) IfrOpHdr; | |
| if (IfrOneOf->Question.VarStoreId != VarStorageData->VarStoreId) { | |
| break; | |
| } | |
| // | |
| // Get Offset/Width by Question header and OneOf Flags | |
| // | |
| VarOffset = IfrOneOf->Question.VarStoreInfo.VarOffset; | |
| VarWidth = (UINT16) (1 << (IfrOneOf->Flags & EFI_IFR_NUMERIC_SIZE)); | |
| // | |
| // Check whether this question is in requested block array. | |
| // | |
| if (!BlockArrayCheck (RequestBlockArray, VarOffset, VarWidth)) { | |
| // | |
| // This question is not in the requested string. Skip it. | |
| // | |
| break; | |
| } | |
| // | |
| // Check this var question is in the var storage | |
| // | |
| if ((VarOffset + VarWidth) > VarStorageData->Size) { | |
| Status = EFI_INVALID_PARAMETER; | |
| goto Done; | |
| } | |
| // | |
| // Set Block Data | |
| // | |
| BlockData = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA)); | |
| if (BlockData == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto Done; | |
| } | |
| BlockData->Offset = VarOffset; | |
| BlockData->Width = VarWidth; | |
| BlockData->QuestionId = IfrOneOf->Question.QuestionId; | |
| BlockData->OpCode = IfrOpHdr->OpCode; | |
| BlockData->Scope = IfrOpHdr->Scope; | |
| InitializeListHead (&BlockData->DefaultValueEntry); | |
| // | |
| // Add Block Data into VarStorageData BlockEntry | |
| // | |
| InsertBlockData (&VarStorageData->BlockEntry, &BlockData); | |
| break; | |
| case EFI_IFR_ORDERED_LIST_OP: | |
| // | |
| // offset by question header | |
| // width by EFI_IFR_ORDERED_LIST MaxContainers * OneofOption Type | |
| // no default value and default id, how to define its default value? | |
| // | |
| // | |
| // OrderedList question is not in IFR Form. This IFR form is not valid. | |
| // | |
| if (VarStorageData->Size == 0) { | |
| Status = EFI_INVALID_PARAMETER; | |
| goto Done; | |
| } | |
| // | |
| // Check whether this question is for the requested varstore. | |
| // | |
| IfrOrderedList = (EFI_IFR_ORDERED_LIST *) IfrOpHdr; | |
| if (IfrOrderedList->Question.VarStoreId != VarStorageData->VarStoreId) { | |
| BlockData = NULL; | |
| break; | |
| } | |
| // | |
| // Get Offset/Width by Question header and OneOf Flags | |
| // | |
| VarOffset = IfrOrderedList->Question.VarStoreInfo.VarOffset; | |
| VarWidth = IfrOrderedList->MaxContainers; | |
| // | |
| // Set Block Data | |
| // | |
| BlockData = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA)); | |
| if (BlockData == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto Done; | |
| } | |
| BlockData->Offset = VarOffset; | |
| BlockData->Width = VarWidth; | |
| BlockData->QuestionId = IfrOrderedList->Question.QuestionId; | |
| BlockData->OpCode = IfrOpHdr->OpCode; | |
| BlockData->Scope = IfrOpHdr->Scope; | |
| InitializeListHead (&BlockData->DefaultValueEntry); | |
| break; | |
| case EFI_IFR_CHECKBOX_OP: | |
| // | |
| // EFI_IFR_DEFAULT_OP | |
| // offset by question header | |
| // width is 1 sizeof (BOOLEAN) | |
| // default id by CheckBox Flags if CheckBox flags (Default or Mau) is set, the default value is 1 to be set. | |
| // value by DefaultOption | |
| // default id by DeaultOption DefaultId can override CheckBox Flags and Default value. | |
| // | |
| // | |
| // CheckBox question is not in IFR Form. This IFR form is not valid. | |
| // | |
| if (VarStorageData->Size == 0) { | |
| Status = EFI_INVALID_PARAMETER; | |
| goto Done; | |
| } | |
| // | |
| // Check whether this question is for the requested varstore. | |
| // | |
| IfrCheckBox = (EFI_IFR_CHECKBOX *) IfrOpHdr; | |
| if (IfrCheckBox->Question.VarStoreId != VarStorageData->VarStoreId) { | |
| break; | |
| } | |
| // | |
| // Get Offset/Width by Question header and OneOf Flags | |
| // | |
| VarOffset = IfrCheckBox->Question.VarStoreInfo.VarOffset; | |
| VarWidth = (UINT16) sizeof (BOOLEAN); | |
| // | |
| // Check whether this question is in requested block array. | |
| // | |
| if (!BlockArrayCheck (RequestBlockArray, VarOffset, VarWidth)) { | |
| // | |
| // This question is not in the requested string. Skip it. | |
| // | |
| break; | |
| } | |
| // | |
| // Check this var question is in the var storage | |
| // | |
| if ((VarOffset + VarWidth) > VarStorageData->Size) { | |
| Status = EFI_INVALID_PARAMETER; | |
| goto Done; | |
| } | |
| // | |
| // Set Block Data | |
| // | |
| BlockData = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA)); | |
| if (BlockData == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto Done; | |
| } | |
| BlockData->Offset = VarOffset; | |
| BlockData->Width = VarWidth; | |
| BlockData->QuestionId = IfrCheckBox->Question.QuestionId; | |
| BlockData->OpCode = IfrOpHdr->OpCode; | |
| BlockData->Scope = IfrOpHdr->Scope; | |
| InitializeListHead (&BlockData->DefaultValueEntry); | |
| // | |
| // Add Block Data into VarStorageData BlockEntry | |
| // | |
| InsertBlockData (&VarStorageData->BlockEntry, &BlockData); | |
| // | |
| // Add default value by CheckBox Flags | |
| // | |
| if ((IfrCheckBox->Flags & EFI_IFR_CHECKBOX_DEFAULT) == EFI_IFR_CHECKBOX_DEFAULT) { | |
| // | |
| // Set standard ID to Manufacture ID and Get DefaultName String ID | |
| // | |
| VarDefaultId = EFI_HII_DEFAULT_CLASS_STANDARD; | |
| Status = FindDefaultName (DefaultIdArray, VarDefaultId, &VarDefaultName); | |
| if (EFI_ERROR (Status)) { | |
| goto Done; | |
| } | |
| // | |
| // Prepare new DefaultValue | |
| // | |
| DefaultData = (IFR_DEFAULT_DATA *) AllocateZeroPool (sizeof (IFR_DEFAULT_DATA)); | |
| if (DefaultData == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto Done; | |
| } | |
| DefaultData->OpCode = IfrOpHdr->OpCode; | |
| DefaultData->DefaultId = VarDefaultId; | |
| DefaultData->DefaultName = VarDefaultName; | |
| DefaultData->Value = 1; | |
| // | |
| // Add DefaultValue into current BlockData | |
| // | |
| InsertDefaultValue (BlockData, DefaultData); | |
| } | |
| if ((IfrCheckBox->Flags & EFI_IFR_CHECKBOX_DEFAULT_MFG) == EFI_IFR_CHECKBOX_DEFAULT_MFG) { | |
| // | |
| // Set standard ID to Manufacture ID and Get DefaultName String ID | |
| // | |
| VarDefaultId = EFI_HII_DEFAULT_CLASS_MANUFACTURING; | |
| Status = FindDefaultName (DefaultIdArray, VarDefaultId, &VarDefaultName); | |
| if (EFI_ERROR (Status)) { | |
| goto Done; | |
| } | |
| // | |
| // Prepare new DefaultValue | |
| // | |
| DefaultData = (IFR_DEFAULT_DATA *) AllocateZeroPool (sizeof (IFR_DEFAULT_DATA)); | |
| if (DefaultData == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto Done; | |
| } | |
| DefaultData->OpCode = IfrOpHdr->OpCode; | |
| DefaultData->DefaultId = VarDefaultId; | |
| DefaultData->DefaultName = VarDefaultName; | |
| DefaultData->Value = 1; | |
| // | |
| // Add DefaultValue into current BlockData | |
| // | |
| InsertDefaultValue (BlockData, DefaultData); | |
| } | |
| break; | |
| case EFI_IFR_STRING_OP: | |
| // | |
| // offset by question header | |
| // width MaxSize * sizeof (CHAR16) | |
| // no default value, only block array | |
| // | |
| // | |
| // String question is not in IFR Form. This IFR form is not valid. | |
| // | |
| if (VarStorageData->Size == 0) { | |
| Status = EFI_INVALID_PARAMETER; | |
| goto Done; | |
| } | |
| // | |
| // Check whether this question is for the requested varstore. | |
| // | |
| IfrString = (EFI_IFR_STRING *) IfrOpHdr; | |
| if (IfrString->Question.VarStoreId != VarStorageData->VarStoreId) { | |
| break; | |
| } | |
| // | |
| // Get Offset/Width by Question header and OneOf Flags | |
| // | |
| VarOffset = IfrString->Question.VarStoreInfo.VarOffset; | |
| VarWidth = (UINT16) (IfrString->MaxSize * sizeof (UINT16)); | |
| // | |
| // Check whether this question is in requested block array. | |
| // | |
| if (!BlockArrayCheck (RequestBlockArray, VarOffset, VarWidth)) { | |
| // | |
| // This question is not in the requested string. Skip it. | |
| // | |
| break; | |
| } | |
| // | |
| // Check this var question is in the var storage | |
| // | |
| if ((VarOffset + VarWidth) > VarStorageData->Size) { | |
| Status = EFI_INVALID_PARAMETER; | |
| goto Done; | |
| } | |
| // | |
| // Set Block Data | |
| // | |
| BlockData = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA)); | |
| if (BlockData == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto Done; | |
| } | |
| BlockData->Offset = VarOffset; | |
| BlockData->Width = VarWidth; | |
| BlockData->QuestionId = IfrString->Question.QuestionId; | |
| BlockData->OpCode = IfrOpHdr->OpCode; | |
| InitializeListHead (&BlockData->DefaultValueEntry); | |
| // | |
| // Add Block Data into VarStorageData BlockEntry | |
| // | |
| InsertBlockData (&VarStorageData->BlockEntry, &BlockData); | |
| // | |
| // No default value for string. | |
| // | |
| BlockData = NULL; | |
| break; | |
| case EFI_IFR_PASSWORD_OP: | |
| // | |
| // offset by question header | |
| // width MaxSize * sizeof (CHAR16) | |
| // no default value, only block array | |
| // | |
| // | |
| // Password question is not in IFR Form. This IFR form is not valid. | |
| // | |
| if (VarStorageData->Size == 0) { | |
| Status = EFI_INVALID_PARAMETER; | |
| goto Done; | |
| } | |
| // | |
| // Check whether this question is for the requested varstore. | |
| // | |
| IfrPassword = (EFI_IFR_PASSWORD *) IfrOpHdr; | |
| if (IfrPassword->Question.VarStoreId != VarStorageData->VarStoreId) { | |
| break; | |
| } | |
| // | |
| // Get Offset/Width by Question header and OneOf Flags | |
| // | |
| VarOffset = IfrPassword->Question.VarStoreInfo.VarOffset; | |
| VarWidth = (UINT16) (IfrPassword->MaxSize * sizeof (UINT16)); | |
| // | |
| // Check whether this question is in requested block array. | |
| // | |
| if (!BlockArrayCheck (RequestBlockArray, VarOffset, VarWidth)) { | |
| // | |
| // This question is not in the requested string. Skip it. | |
| // | |
| break; | |
| } | |
| // | |
| // Check this var question is in the var storage | |
| // | |
| if ((VarOffset + VarWidth) > VarStorageData->Size) { | |
| Status = EFI_INVALID_PARAMETER; | |
| goto Done; | |
| } | |
| // | |
| // Set Block Data | |
| // | |
| BlockData = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA)); | |
| if (BlockData == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto Done; | |
| } | |
| BlockData->Offset = VarOffset; | |
| BlockData->Width = VarWidth; | |
| BlockData->QuestionId = IfrPassword->Question.QuestionId; | |
| BlockData->OpCode = IfrOpHdr->OpCode; | |
| InitializeListHead (&BlockData->DefaultValueEntry); | |
| // | |
| // Add Block Data into VarStorageData BlockEntry | |
| // | |
| InsertBlockData (&VarStorageData->BlockEntry, &BlockData); | |
| // | |
| // No default value for string. | |
| // | |
| BlockData = NULL; | |
| break; | |
| case EFI_IFR_ONE_OF_OPTION_OP: | |
| // | |
| // No matched block data is ignored. | |
| // | |
| if (BlockData == NULL || BlockData->Scope == 0) { | |
| break; | |
| } | |
| IfrOneOfOption = (EFI_IFR_ONE_OF_OPTION *) IfrOpHdr; | |
| if (BlockData->OpCode == EFI_IFR_ORDERED_LIST_OP) { | |
| // | |
| // Get ordered list option data type. | |
| // | |
| if (IfrOneOfOption->Type == EFI_IFR_TYPE_NUM_SIZE_8 || IfrOneOfOption->Type == EFI_IFR_TYPE_BOOLEAN) { | |
| VarWidth = 1; | |
| } else if (IfrOneOfOption->Type == EFI_IFR_TYPE_NUM_SIZE_16) { | |
| VarWidth = 2; | |
| } else if (IfrOneOfOption->Type == EFI_IFR_TYPE_NUM_SIZE_32) { | |
| VarWidth = 4; | |
| } else if (IfrOneOfOption->Type == EFI_IFR_TYPE_NUM_SIZE_64) { | |
| VarWidth = 8; | |
| } else { | |
| // | |
| // Invalid ordered list option data type. | |
| // | |
| Status = EFI_INVALID_PARAMETER; | |
| FreePool (BlockData); | |
| goto Done; | |
| } | |
| // | |
| // Calculate Ordered list QuestionId width. | |
| // | |
| BlockData->Width = (UINT16) (BlockData->Width * VarWidth); | |
| // | |
| // Check whether this question is in requested block array. | |
| // | |
| if (!BlockArrayCheck (RequestBlockArray, BlockData->Offset, BlockData->Width)) { | |
| // | |
| // This question is not in the requested string. Skip it. | |
| // | |
| FreePool (BlockData); | |
| BlockData = NULL; | |
| break; | |
| } | |
| // | |
| // Check this var question is in the var storage | |
| // | |
| if ((BlockData->Offset + BlockData->Width) > VarStorageData->Size) { | |
| Status = EFI_INVALID_PARAMETER; | |
| FreePool (BlockData); | |
| goto Done; | |
| } | |
| // | |
| // Add Block Data into VarStorageData BlockEntry | |
| // | |
| InsertBlockData (&VarStorageData->BlockEntry, &BlockData); | |
| // | |
| // No default data for OrderedList. | |
| // | |
| BlockData = NULL; | |
| break; | |
| } | |
| if ((IfrOneOfOption->Flags & EFI_IFR_OPTION_DEFAULT) == EFI_IFR_OPTION_DEFAULT) { | |
| // | |
| // Set standard ID to Manufacture ID and Get DefaultName String ID | |
| // | |
| VarDefaultId = EFI_HII_DEFAULT_CLASS_STANDARD; | |
| Status = FindDefaultName (DefaultIdArray, VarDefaultId, &VarDefaultName); | |
| if (EFI_ERROR (Status)) { | |
| goto Done; | |
| } | |
| // | |
| // Prepare new DefaultValue | |
| // | |
| DefaultData = (IFR_DEFAULT_DATA *) AllocateZeroPool (sizeof (IFR_DEFAULT_DATA)); | |
| if (DefaultData == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto Done; | |
| } | |
| DefaultData->OpCode = IfrOpHdr->OpCode; | |
| DefaultData->DefaultId = VarDefaultId; | |
| DefaultData->DefaultName = VarDefaultName; | |
| DefaultData->Value = IfrOneOfOption->Value.u64; | |
| // | |
| // Add DefaultValue into current BlockData | |
| // | |
| InsertDefaultValue (BlockData, DefaultData); | |
| } | |
| if ((IfrOneOfOption->Flags & EFI_IFR_OPTION_DEFAULT_MFG) == EFI_IFR_OPTION_DEFAULT_MFG) { | |
| // | |
| // Set default ID to Manufacture ID and Get DefaultName String ID | |
| // | |
| VarDefaultId = EFI_HII_DEFAULT_CLASS_MANUFACTURING; | |
| Status = FindDefaultName (DefaultIdArray, VarDefaultId, &VarDefaultName); | |
| if (EFI_ERROR (Status)) { | |
| goto Done; | |
| } | |
| // | |
| // Prepare new DefaultValue | |
| // | |
| DefaultData = (IFR_DEFAULT_DATA *) AllocateZeroPool (sizeof (IFR_DEFAULT_DATA)); | |
| if (DefaultData == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto Done; | |
| } | |
| DefaultData->OpCode = IfrOpHdr->OpCode; | |
| DefaultData->DefaultId = VarDefaultId; | |
| DefaultData->DefaultName = VarDefaultName; | |
| DefaultData->Value = IfrOneOfOption->Value.u64; | |
| // | |
| // Add DefaultValue into current BlockData | |
| // | |
| InsertDefaultValue (BlockData, DefaultData); | |
| } | |
| break; | |
| case EFI_IFR_DEFAULT_OP: | |
| // | |
| // Update Current BlockData to the default value. | |
| // | |
| if (BlockData == NULL || BlockData->Scope == 0) { | |
| // | |
| // No matched block data is ignored. | |
| // | |
| break; | |
| } | |
| if (BlockData->OpCode == EFI_IFR_ORDERED_LIST_OP) { | |
| // | |
| // OrderedList Opcode is no default value. | |
| // | |
| break; | |
| } | |
| // | |
| // Get the DefaultId and DefaultName String ID | |
| // | |
| IfrDefault = (EFI_IFR_DEFAULT *) IfrOpHdr; | |
| VarDefaultId = IfrDefault->DefaultId; | |
| Status = FindDefaultName (DefaultIdArray, VarDefaultId, &VarDefaultName); | |
| if (EFI_ERROR (Status)) { | |
| goto Done; | |
| } | |
| // | |
| // Prepare new DefaultValue | |
| // | |
| DefaultData = (IFR_DEFAULT_DATA *) AllocateZeroPool (sizeof (IFR_DEFAULT_DATA)); | |
| if (DefaultData == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto Done; | |
| } | |
| DefaultData->OpCode = IfrOpHdr->OpCode; | |
| DefaultData->DefaultId = VarDefaultId; | |
| DefaultData->DefaultName = VarDefaultName; | |
| DefaultData->Value = IfrDefault->Value.u64; | |
| // | |
| // Add DefaultValue into current BlockData | |
| // | |
| InsertDefaultValue (BlockData, DefaultData); | |
| break; | |
| case EFI_IFR_END_OP: | |
| // | |
| // End Opcode is for Var question. | |
| // | |
| if (BlockData != NULL && BlockData->Scope > 0) { | |
| BlockData->Scope--; | |
| } | |
| break; | |
| default: | |
| if (BlockData != NULL && BlockData->Scope > 0) { | |
| BlockData->Scope = (UINT8) (BlockData->Scope + IfrOpHdr->Scope); | |
| } | |
| break; | |
| } | |
| IfrOffset += IfrOpHdr->Length; | |
| } | |
| Done: | |
| return Status; | |
| } | |
| /** | |
| This function gets the full request string and full default value string by | |
| parsing IFR data in HII form packages. | |
| When Request points to NULL string, the request string and default value string | |
| for each varstore in form package will return. | |
| @param DataBaseRecord The DataBaseRecord instance contains the found Hii handle and package. | |
| @param DevicePath Device Path which Hii Config Access Protocol is registered. | |
| @param Request Pointer to a null-terminated Unicode string in | |
| <ConfigRequest> format. When it doesn't contain | |
| any RequestElement, it will be updated to return | |
| the full RequestElement retrieved from IFR data. | |
| If it points to NULL, the request string for the first | |
| varstore in form package will be merged into a | |
| <MultiConfigRequest> format string and return. | |
| @param AltCfgResp Pointer to a null-terminated Unicode string in | |
| <ConfigAltResp> format. When the pointer is to NULL, | |
| the full default value string retrieved from IFR data | |
| will return. When the pinter is to a string, the | |
| full default value string retrieved from IFR data | |
| will be merged into the input string and return. | |
| When Request points to NULL, the default value string | |
| for each varstore in form package will be merged into | |
| a <MultiConfigAltResp> format string and return. | |
| @param PointerProgress Optional parameter, it can be be NULL. | |
| When it is not NULL, if Request is NULL, it returns NULL. | |
| On return, points to a character in the Request | |
| string. Points to the string's null terminator if | |
| request was successful. Points to the most recent | |
| & before the first failing name / value pair (or | |
| the beginning of the string if the failure is in | |
| the first name / value pair) if the request was | |
| not successful. | |
| @retval EFI_SUCCESS The Results string is set to the full request string. | |
| And AltCfgResp contains all default value string. | |
| @retval EFI_OUT_OF_RESOURCES Not enough memory for the return string. | |
| @retval EFI_NOT_FOUND The varstore (Guid and Name) in Request string | |
| can't be found in Form package. | |
| @retval EFI_NOT_FOUND HiiPackage can't be got on the input HiiHandle. | |
| @retval EFI_INVALID_PARAMETER Request points to NULL. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| GetFullStringFromHiiFormPackages ( | |
| IN HII_DATABASE_RECORD *DataBaseRecord, | |
| IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, | |
| IN OUT EFI_STRING *Request, | |
| IN OUT EFI_STRING *AltCfgResp, | |
| OUT EFI_STRING *PointerProgress OPTIONAL | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| UINT8 *HiiFormPackage; | |
| UINTN PackageSize; | |
| UINTN ResultSize; | |
| IFR_BLOCK_DATA *RequestBlockArray; | |
| IFR_BLOCK_DATA *BlockData; | |
| IFR_BLOCK_DATA *NextBlockData; | |
| IFR_DEFAULT_DATA *DefaultValueData; | |
| IFR_DEFAULT_DATA *DefaultId; | |
| IFR_DEFAULT_DATA *DefaultIdArray; | |
| IFR_VARSTORAGE_DATA *VarStorageData; | |
| EFI_STRING DefaultAltCfgResp; | |
| EFI_STRING FullConfigRequest; | |
| EFI_STRING ConfigHdr; | |
| EFI_STRING GuidStr; | |
| EFI_STRING NameStr; | |
| EFI_STRING PathStr; | |
| EFI_STRING StringPtr; | |
| EFI_STRING Progress; | |
| UINTN Length; | |
| UINT8 *TmpBuffer; | |
| UINT16 Offset; | |
| UINT16 Width; | |
| LIST_ENTRY *Link; | |
| LIST_ENTRY *LinkData; | |
| LIST_ENTRY *LinkDefault; | |
| BOOLEAN DataExist; | |
| if (DataBaseRecord == NULL || DevicePath == NULL || Request == NULL || AltCfgResp == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // Initialize the local variables. | |
| // | |
| RequestBlockArray = NULL; | |
| DefaultIdArray = NULL; | |
| VarStorageData = NULL; | |
| DefaultAltCfgResp = NULL; | |
| FullConfigRequest = NULL; | |
| ConfigHdr = NULL; | |
| GuidStr = NULL; | |
| NameStr = NULL; | |
| PathStr = NULL; | |
| HiiFormPackage = NULL; | |
| ResultSize = 0; | |
| PackageSize = 0; | |
| DataExist = FALSE; | |
| Progress = *Request; | |
| // | |
| // 0. Get Hii Form Package by HiiHandle | |
| // | |
| Status = ExportFormPackages ( | |
| &mPrivate, | |
| DataBaseRecord->Handle, | |
| DataBaseRecord->PackageList, | |
| 0, | |
| PackageSize, | |
| HiiFormPackage, | |
| &ResultSize | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| HiiFormPackage = AllocatePool (ResultSize); | |
| if (HiiFormPackage == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto Done; | |
| } | |
| // | |
| // Get HiiFormPackage by HiiHandle | |
| // | |
| PackageSize = ResultSize; | |
| ResultSize = 0; | |
| Status = ExportFormPackages ( | |
| &mPrivate, | |
| DataBaseRecord->Handle, | |
| DataBaseRecord->PackageList, | |
| 0, | |
| PackageSize, | |
| HiiFormPackage, | |
| &ResultSize | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto Done; | |
| } | |
| // | |
| // 1. Get the request block array by Request String when Request string containts the block array. | |
| // | |
| StringPtr = NULL; | |
| if (*Request != NULL) { | |
| StringPtr = *Request; | |
| // | |
| // Jump <ConfigHdr> | |
| // | |
| if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) { | |
| Status = EFI_INVALID_PARAMETER; | |
| goto Done; | |
| } | |
| StringPtr += StrLen (L"GUID="); | |
| while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&NAME=", StrLen (L"&NAME=")) != 0) { | |
| StringPtr++; | |
| } | |
| if (*StringPtr == L'\0') { | |
| Status = EFI_INVALID_PARAMETER; | |
| goto Done; | |
| } | |
| StringPtr += StrLen (L"&NAME="); | |
| while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&PATH=", StrLen (L"&PATH=")) != 0) { | |
| StringPtr++; | |
| } | |
| if (*StringPtr == L'\0') { | |
| Status = EFI_INVALID_PARAMETER; | |
| goto Done; | |
| } | |
| StringPtr += StrLen (L"&PATH="); | |
| while (*StringPtr != L'\0' && *StringPtr != L'&') { | |
| StringPtr ++; | |
| } | |
| // | |
| // Check the following string &OFFSET= | |
| // | |
| if (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&OFFSET=", StrLen (L"&OFFSET=")) != 0) { | |
| Progress = StringPtr; | |
| Status = EFI_INVALID_PARAMETER; | |
| goto Done; | |
| } else if (*StringPtr == L'\0') { | |
| // | |
| // No request block is found. | |
| // | |
| StringPtr = NULL; | |
| } | |
| } | |
| if (StringPtr != NULL) { | |
| // | |
| // Init RequestBlockArray | |
| // | |
| RequestBlockArray = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA)); | |
| if (RequestBlockArray == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto Done; | |
| } | |
| InitializeListHead (&RequestBlockArray->Entry); | |
| // | |
| // Get the request Block array from the request string | |
| // Offset and Width | |
| // | |
| // | |
| // Parse each <RequestElement> if exists | |
| // Only <BlockName> format is supported by this help function. | |
| // <BlockName> ::= &'OFFSET='<Number>&'WIDTH='<Number> | |
| // | |
| while (*StringPtr != 0 && StrnCmp (StringPtr, L"&OFFSET=", StrLen (L"&OFFSET=")) == 0) { | |
| // | |
| // Skip the OFFSET string | |
| // | |
| Progress = StringPtr; | |
| StringPtr += StrLen (L"&OFFSET="); | |
| // | |
| // Get Offset | |
| // | |
| Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length); | |
| if (EFI_ERROR (Status)) { | |
| goto Done; | |
| } | |
| Offset = 0; | |
| CopyMem ( | |
| &Offset, | |
| TmpBuffer, | |
| (((Length + 1) / 2) < sizeof (UINT16)) ? ((Length + 1) / 2) : sizeof (UINT16) | |
| ); | |
| FreePool (TmpBuffer); | |
| StringPtr += Length; | |
| if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) { | |
| Status = EFI_INVALID_PARAMETER; | |
| goto Done; | |
| } | |
| StringPtr += StrLen (L"&WIDTH="); | |
| // | |
| // Get Width | |
| // | |
| Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length); | |
| if (EFI_ERROR (Status)) { | |
| goto Done; | |
| } | |
| Width = 0; | |
| CopyMem ( | |
| &Width, | |
| TmpBuffer, | |
| (((Length + 1) / 2) < sizeof (UINT16)) ? ((Length + 1) / 2) : sizeof (UINT16) | |
| ); | |
| FreePool (TmpBuffer); | |
| StringPtr += Length; | |
| if (*StringPtr != 0 && *StringPtr != L'&') { | |
| Status = EFI_INVALID_PARAMETER; | |
| goto Done; | |
| } | |
| // | |
| // Set Block Data | |
| // | |
| BlockData = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA)); | |
| if (BlockData == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto Done; | |
| } | |
| BlockData->Offset = Offset; | |
| BlockData->Width = Width; | |
| InsertBlockData (&RequestBlockArray->Entry, &BlockData); | |
| // | |
| // Skip &VALUE string if &VALUE does exists. | |
| // | |
| if (StrnCmp (StringPtr, L"&VALUE=", StrLen (L"&VALUE=")) == 0) { | |
| StringPtr += StrLen (L"&VALUE="); | |
| // | |
| // Get Value | |
| // | |
| Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length); | |
| if (EFI_ERROR (Status)) { | |
| Status = EFI_INVALID_PARAMETER; | |
| goto Done; | |
| } | |
| StringPtr += Length; | |
| if (*StringPtr != 0 && *StringPtr != L'&') { | |
| Status = EFI_INVALID_PARAMETER; | |
| goto Done; | |
| } | |
| } | |
| // | |
| // If '\0', parsing is finished. | |
| // | |
| if (*StringPtr == 0) { | |
| break; | |
| } | |
| } | |
| // | |
| // Merge the requested block data. | |
| // | |
| Link = RequestBlockArray->Entry.ForwardLink; | |
| while ((Link != &RequestBlockArray->Entry) && (Link->ForwardLink != &RequestBlockArray->Entry)) { | |
| BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry); | |
| NextBlockData = BASE_CR (Link->ForwardLink, IFR_BLOCK_DATA, Entry); | |
| if ((NextBlockData->Offset >= BlockData->Offset) && (NextBlockData->Offset <= (BlockData->Offset + BlockData->Width))) { | |
| if ((NextBlockData->Offset + NextBlockData->Width) > (BlockData->Offset + BlockData->Width)) { | |
| BlockData->Width = (UINT16) (NextBlockData->Offset + NextBlockData->Width - BlockData->Offset); | |
| } | |
| RemoveEntryList (Link->ForwardLink); | |
| FreePool (NextBlockData); | |
| continue; | |
| } | |
| Link = Link->ForwardLink; | |
| } | |
| } | |
| // | |
| // 2. Parse FormPackage to get BlockArray and DefaultId Array for the request BlockArray. | |
| // | |
| // | |
| // Initialize DefaultIdArray to store the map between DeaultId and DefaultName | |
| // | |
| DefaultIdArray = (IFR_DEFAULT_DATA *) AllocateZeroPool (sizeof (IFR_DEFAULT_DATA)); | |
| if (DefaultIdArray == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto Done; | |
| } | |
| InitializeListHead (&DefaultIdArray->Entry); | |
| // | |
| // Initialize VarStorageData to store the var store Block and Default value information. | |
| // | |
| VarStorageData = (IFR_VARSTORAGE_DATA *) AllocateZeroPool (sizeof (IFR_VARSTORAGE_DATA)); | |
| if (VarStorageData == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto Done; | |
| } | |
| InitializeListHead (&VarStorageData->Entry); | |
| InitializeListHead (&VarStorageData->BlockEntry); | |
| // | |
| // Parse the opcode in form pacakge to get the default setting. | |
| // | |
| Status = ParseIfrData (HiiFormPackage, (UINT32) PackageSize, *Request, RequestBlockArray, VarStorageData, DefaultIdArray); | |
| if (EFI_ERROR (Status)) { | |
| goto Done; | |
| } | |
| // | |
| // No requested varstore in IFR data and directly return | |
| // | |
| if (VarStorageData->Size == 0) { | |
| Status = EFI_SUCCESS; | |
| goto Done; | |
| } | |
| // | |
| // 3. Construct Request Element (Block Name) for 2.1 and 2.2 case. | |
| // | |
| // | |
| // Construct <ConfigHdr> : "GUID=...&NAME=...&PATH=..." by VarStorageData Guid, Name and DriverHandle | |
| // | |
| GenerateSubStr (L"GUID=", sizeof (EFI_GUID), (VOID *) &VarStorageData->Guid, 1, &GuidStr); | |
| GenerateSubStr (L"NAME=", StrLen (VarStorageData->Name) * sizeof (CHAR16), (VOID *) VarStorageData->Name, 2, &NameStr); | |
| GenerateSubStr ( | |
| L"PATH=", | |
| GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) DevicePath), | |
| (VOID *) DevicePath, | |
| 1, | |
| &PathStr | |
| ); | |
| Length = StrLen (GuidStr); | |
| Length = Length + StrLen (NameStr); | |
| Length = Length + StrLen (PathStr) + 1; | |
| ConfigHdr = AllocateZeroPool (Length * sizeof (CHAR16)); | |
| if (ConfigHdr == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto Done; | |
| } | |
| StrCpy (ConfigHdr, GuidStr); | |
| StrCat (ConfigHdr, NameStr); | |
| StrCat (ConfigHdr, PathStr); | |
| // | |
| // Remove the last character L'&' | |
| // | |
| *(ConfigHdr + StrLen (ConfigHdr) - 1) = L'\0'; | |
| if (RequestBlockArray == NULL) { | |
| // | |
| // Append VarStorageData BlockEntry into *Request string | |
| // Now support only one varstore in a form package. | |
| // | |
| // | |
| // Go through all VarStorageData Entry and get BlockEntry for each one for the multiple varstore in a single form package | |
| // Then construct them all to return MultiRequest string : ConfigHdr BlockConfig | |
| // | |
| // | |
| // Compute the length of the entire request starting with <ConfigHdr> and a | |
| // Null-terminator | |
| // | |
| DataExist = FALSE; | |
| Length = StrLen (ConfigHdr) + 1; | |
| for (Link = VarStorageData->BlockEntry.ForwardLink; Link != &VarStorageData->BlockEntry; Link = Link->ForwardLink) { | |
| // | |
| // Add <BlockName> length for each Offset/Width pair | |
| // | |
| // <BlockName> ::= &OFFSET=1234&WIDTH=1234 | |
| // | 8 | 4 | 7 | 4 | | |
| // | |
| DataExist = TRUE; | |
| Length = Length + (8 + 4 + 7 + 4); | |
| } | |
| // | |
| // No any request block data is found. The request string can't be constructed. | |
| // | |
| if (!DataExist) { | |
| Status = EFI_SUCCESS; | |
| goto Done; | |
| } | |
| // | |
| // Allocate buffer for the entire <ConfigRequest> | |
| // | |
| FullConfigRequest = AllocateZeroPool (Length * sizeof (CHAR16)); | |
| if (FullConfigRequest == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto Done; | |
| } | |
| StringPtr = FullConfigRequest; | |
| // | |
| // Start with <ConfigHdr> | |
| // | |
| StrCpy (StringPtr, ConfigHdr); | |
| StringPtr += StrLen (StringPtr); | |
| // | |
| // Loop through all the Offset/Width pairs and append them to ConfigRequest | |
| // | |
| for (Link = VarStorageData->BlockEntry.ForwardLink; Link != &VarStorageData->BlockEntry; Link = Link->ForwardLink) { | |
| BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry); | |
| // | |
| // Append &OFFSET=XXXX&WIDTH=YYYY\0 | |
| // | |
| UnicodeSPrint ( | |
| StringPtr, | |
| (8 + 4 + 7 + 4 + 1) * sizeof (CHAR16), | |
| L"&OFFSET=%04X&WIDTH=%04X", | |
| BlockData->Offset, | |
| BlockData->Width | |
| ); | |
| StringPtr += StrLen (StringPtr); | |
| } | |
| // | |
| // Set to the got full request string. | |
| // | |
| HiiToLower (FullConfigRequest); | |
| if (*Request != NULL) { | |
| FreePool (*Request); | |
| } | |
| *Request = FullConfigRequest; | |
| } | |
| // | |
| // 4. Construct Default Value string in AltResp according to request element. | |
| // Go through all VarStorageData Entry and get the DefaultId array for each one | |
| // Then construct them all to : ConfigHdr AltConfigHdr ConfigBody AltConfigHdr ConfigBody | |
| // | |
| DataExist = FALSE; | |
| // | |
| // Add length for <ConfigHdr> + '\0' | |
| // | |
| Length = StrLen (ConfigHdr) + 1; | |
| for (Link = DefaultIdArray->Entry.ForwardLink; Link != &DefaultIdArray->Entry; Link = Link->ForwardLink) { | |
| DefaultId = BASE_CR (Link, IFR_DEFAULT_DATA, Entry); | |
| // | |
| // Add length for "&<ConfigHdr>&ALTCFG=XXXX" | |
| // |1| StrLen (ConfigHdr) | 8 | 4 | | |
| // | |
| Length += (1 + StrLen (ConfigHdr) + 8 + 4); | |
| for (LinkData = VarStorageData->BlockEntry.ForwardLink; LinkData != &VarStorageData->BlockEntry; LinkData = LinkData->ForwardLink) { | |
| BlockData = BASE_CR (LinkData, IFR_BLOCK_DATA, Entry); | |
| for (LinkDefault = BlockData->DefaultValueEntry.ForwardLink; LinkDefault != &BlockData->DefaultValueEntry; LinkDefault = LinkDefault->ForwardLink) { | |
| DefaultValueData = BASE_CR (LinkDefault, IFR_DEFAULT_DATA, Entry); | |
| if (DefaultValueData->DefaultId == DefaultId->DefaultId) { | |
| // | |
| // Add length for "&OFFSET=XXXX&WIDTH=YYYY&VALUE=zzzzzzzzzzzz" | |
| // | 8 | 4 | 7 | 4 | 7 | Width * 2 | | |
| // | |
| Length += (8 + 4 + 7 + 4 + 7 + BlockData->Width * 2); | |
| DataExist = TRUE; | |
| } | |
| } | |
| } | |
| } | |
| // | |
| // No default value is found. The default string doesn't exist. | |
| // | |
| if (!DataExist) { | |
| Status = EFI_SUCCESS; | |
| goto Done; | |
| } | |
| // | |
| // Allocate buffer for the entire <DefaultAltCfgResp> | |
| // | |
| DefaultAltCfgResp = AllocateZeroPool (Length * sizeof (CHAR16)); | |
| if (DefaultAltCfgResp == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto Done; | |
| } | |
| StringPtr = DefaultAltCfgResp; | |
| // | |
| // Start with <ConfigHdr> | |
| // | |
| StrCpy (StringPtr, ConfigHdr); | |
| StringPtr += StrLen (StringPtr); | |
| for (Link = DefaultIdArray->Entry.ForwardLink; Link != &DefaultIdArray->Entry; Link = Link->ForwardLink) { | |
| DefaultId = BASE_CR (Link, IFR_DEFAULT_DATA, Entry); | |
| // | |
| // Add <AltConfigHdr> of the form "&<ConfigHdr>&ALTCFG=XXXX\0" | |
| // |1| StrLen (ConfigHdr) | 8 | 4 | | |
| // | |
| UnicodeSPrint ( | |
| StringPtr, | |
| (1 + StrLen (ConfigHdr) + 8 + 4 + 1) * sizeof (CHAR16), | |
| L"&%s&ALTCFG=%04X", | |
| ConfigHdr, | |
| DefaultId->DefaultName | |
| ); | |
| StringPtr += StrLen (StringPtr); | |
| for (LinkData = VarStorageData->BlockEntry.ForwardLink; LinkData != &VarStorageData->BlockEntry; LinkData = LinkData->ForwardLink) { | |
| BlockData = BASE_CR (LinkData, IFR_BLOCK_DATA, Entry); | |
| for (LinkDefault = BlockData->DefaultValueEntry.ForwardLink; LinkDefault != &BlockData->DefaultValueEntry; LinkDefault = LinkDefault->ForwardLink) { | |
| DefaultValueData = BASE_CR (LinkDefault, IFR_DEFAULT_DATA, Entry); | |
| if (DefaultValueData->DefaultId == DefaultId->DefaultId) { | |
| // | |
| // Add <BlockConfig> | |
| // <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE'=<Number> | |
| // | |
| UnicodeSPrint ( | |
| StringPtr, | |
| (8 + 4 + 7 + 4 + 7 + 1) * sizeof (CHAR16), | |
| L"&OFFSET=%04X&WIDTH=%04X&VALUE=", | |
| BlockData->Offset, | |
| BlockData->Width | |
| ); | |
| StringPtr += StrLen (StringPtr); | |
| // | |
| // Convert Value to a hex string in "%x" format | |
| // NOTE: This is in the opposite byte that GUID and PATH use | |
| // | |
| Width = BlockData->Width; | |
| TmpBuffer = (UINT8 *) &(DefaultValueData->Value); | |
| for (; Width > 0; Width--) { | |
| StringPtr += UnicodeValueToString (StringPtr, PREFIX_ZERO | RADIX_HEX, TmpBuffer[Width - 1], 2); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| HiiToLower (DefaultAltCfgResp); | |
| // | |
| // 5. Merge string into the input AltCfgResp if the iput *AltCfgResp is not NULL. | |
| // | |
| if (*AltCfgResp != NULL && DefaultAltCfgResp != NULL) { | |
| Status = MergeDefaultString (AltCfgResp, DefaultAltCfgResp); | |
| FreePool (DefaultAltCfgResp); | |
| } else if (*AltCfgResp == NULL) { | |
| *AltCfgResp = DefaultAltCfgResp; | |
| } | |
| Done: | |
| if (RequestBlockArray != NULL) { | |
| // | |
| // Free Link Array RequestBlockArray | |
| // | |
| while (!IsListEmpty (&RequestBlockArray->Entry)) { | |
| BlockData = BASE_CR (RequestBlockArray->Entry.ForwardLink, IFR_BLOCK_DATA, Entry); | |
| RemoveEntryList (&BlockData->Entry); | |
| FreePool (BlockData); | |
| } | |
| FreePool (RequestBlockArray); | |
| } | |
| if (VarStorageData != NULL) { | |
| // | |
| // Free link array VarStorageData | |
| // | |
| while (!IsListEmpty (&VarStorageData->BlockEntry)) { | |
| BlockData = BASE_CR (VarStorageData->BlockEntry.ForwardLink, IFR_BLOCK_DATA, Entry); | |
| RemoveEntryList (&BlockData->Entry); | |
| // | |
| // Free default value link array | |
| // | |
| while (!IsListEmpty (&BlockData->DefaultValueEntry)) { | |
| DefaultValueData = BASE_CR (BlockData->DefaultValueEntry.ForwardLink, IFR_DEFAULT_DATA, Entry); | |
| RemoveEntryList (&DefaultValueData->Entry); | |
| FreePool (DefaultValueData); | |
| } | |
| FreePool (BlockData); | |
| } | |
| FreePool (VarStorageData); | |
| } | |
| if (DefaultIdArray != NULL) { | |
| // | |
| // Free DefaultId Array | |
| // | |
| while (!IsListEmpty (&DefaultIdArray->Entry)) { | |
| DefaultId = BASE_CR (DefaultIdArray->Entry.ForwardLink, IFR_DEFAULT_DATA, Entry); | |
| RemoveEntryList (&DefaultId->Entry); | |
| FreePool (DefaultId); | |
| } | |
| FreePool (DefaultIdArray); | |
| } | |
| // | |
| // Free the allocated string | |
| // | |
| if (GuidStr != NULL) { | |
| FreePool (GuidStr); | |
| } | |
| if (NameStr != NULL) { | |
| FreePool (NameStr); | |
| } | |
| if (PathStr != NULL) { | |
| FreePool (PathStr); | |
| } | |
| if (ConfigHdr != NULL) { | |
| FreePool (ConfigHdr); | |
| } | |
| // | |
| // Free Pacakge data | |
| // | |
| if (HiiFormPackage != NULL) { | |
| FreePool (HiiFormPackage); | |
| } | |
| if (PointerProgress != NULL) { | |
| if (*Request == NULL) { | |
| *PointerProgress = NULL; | |
| } else if (EFI_ERROR (Status)) { | |
| *PointerProgress = Progress; | |
| } else { | |
| *PointerProgress = *Request + StrLen (*Request); | |
| } | |
| } | |
| return Status; | |
| } | |
| /** | |
| This function allows a caller to extract the current configuration | |
| for one or more named elements from one or more drivers. | |
| @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL | |
| instance. | |
| @param Request A null-terminated Unicode string in | |
| <MultiConfigRequest> format. | |
| @param Progress On return, points to a character in the Request | |
| string. Points to the string's null terminator if | |
| request was successful. Points to the most recent | |
| & before the first failing name / value pair (or | |
| the beginning of the string if the failure is in | |
| the first name / value pair) if the request was | |
| not successful. | |
| @param Results Null-terminated Unicode string in | |
| <MultiConfigAltResp> format which has all values | |
| filled in for the names in the Request string. | |
| String to be allocated by the called function. | |
| @retval EFI_SUCCESS The Results string is filled with the values | |
| corresponding to all requested names. | |
| @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the | |
| results that must be stored awaiting possible | |
| future protocols. | |
| @retval EFI_NOT_FOUND Routing data doesn't match any known driver. | |
| Progress set to the "G" in "GUID" of the routing | |
| header that doesn't match. Note: There is no | |
| requirement that all routing data be validated | |
| before any configuration extraction. | |
| @retval EFI_INVALID_PARAMETER For example, passing in a NULL for the Request | |
| parameter would result in this type of error. The | |
| Progress parameter is set to NULL. | |
| @retval EFI_INVALID_PARAMETER Illegal syntax. Progress set to most recent & | |
| before the error or the beginning of the string. | |
| @retval EFI_INVALID_PARAMETER Unknown name. Progress points to the & before the | |
| name in question. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| HiiConfigRoutingExtractConfig ( | |
| IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This, | |
| IN CONST EFI_STRING Request, | |
| OUT EFI_STRING *Progress, | |
| OUT EFI_STRING *Results | |
| ) | |
| { | |
| HII_DATABASE_PRIVATE_DATA *Private; | |
| EFI_STRING StringPtr; | |
| EFI_STRING ConfigRequest; | |
| UINTN Length; | |
| EFI_DEVICE_PATH_PROTOCOL *DevicePath; | |
| EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; | |
| EFI_STATUS Status; | |
| LIST_ENTRY *Link; | |
| HII_DATABASE_RECORD *Database; | |
| UINT8 *DevicePathPkg; | |
| UINT8 *CurrentDevicePath; | |
| EFI_HANDLE DriverHandle; | |
| EFI_HII_HANDLE HiiHandle; | |
| EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess; | |
| EFI_STRING AccessProgress; | |
| EFI_STRING AccessResults; | |
| EFI_STRING DefaultResults; | |
| BOOLEAN FirstElement; | |
| BOOLEAN IfrDataParsedFlag; | |
| if (This == NULL || Progress == NULL || Results == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if (Request == NULL) { | |
| *Progress = NULL; | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This); | |
| StringPtr = Request; | |
| *Progress = StringPtr; | |
| DefaultResults = NULL; | |
| ConfigRequest = NULL; | |
| Status = EFI_SUCCESS; | |
| AccessResults = NULL; | |
| DevicePath = NULL; | |
| IfrDataParsedFlag = FALSE; | |
| // | |
| // The first element of <MultiConfigRequest> should be | |
| // <GuidHdr>, which is in 'GUID='<Guid> syntax. | |
| // | |
| if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| FirstElement = TRUE; | |
| // | |
| // Allocate a fix length of memory to store Results. Reallocate memory for | |
| // Results if this fix length is insufficient. | |
| // | |
| *Results = (EFI_STRING) AllocateZeroPool (MAX_STRING_LENGTH); | |
| if (*Results == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| while (*StringPtr != 0 && StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) == 0) { | |
| // | |
| // If parsing error, set Progress to the beginning of the <MultiConfigRequest> | |
| // or most recent & before the error. | |
| // | |
| if (StringPtr == Request) { | |
| *Progress = StringPtr; | |
| } else { | |
| *Progress = StringPtr - 1; | |
| } | |
| // | |
| // Process each <ConfigRequest> of <MultiConfigRequest> | |
| // | |
| Length = CalculateConfigStringLen (StringPtr); | |
| ConfigRequest = AllocateCopyPool ((Length + 1) * sizeof (CHAR16), StringPtr); | |
| if (ConfigRequest == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto Done; | |
| } | |
| *(ConfigRequest + Length) = 0; | |
| // | |
| // Get the UEFI device path | |
| // | |
| Status = GetDevicePath (ConfigRequest, (UINT8 **) &DevicePath); | |
| if (EFI_ERROR (Status)) { | |
| goto Done; | |
| } | |
| // | |
| // Find driver which matches the routing data. | |
| // | |
| DriverHandle = NULL; | |
| HiiHandle = NULL; | |
| Database = NULL; | |
| for (Link = Private->DatabaseList.ForwardLink; | |
| Link != &Private->DatabaseList; | |
| Link = Link->ForwardLink | |
| ) { | |
| Database = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE); | |
| if ((DevicePathPkg = Database->PackageList->DevicePathPkg) != NULL) { | |
| CurrentDevicePath = DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER); | |
| if (CompareMem ( | |
| DevicePath, | |
| CurrentDevicePath, | |
| GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) CurrentDevicePath) | |
| ) == 0) { | |
| DriverHandle = Database->DriverHandle; | |
| HiiHandle = Database->Handle; | |
| break; | |
| } | |
| } | |
| } | |
| // | |
| // Try to find driver handle by device path. | |
| // | |
| if (DriverHandle == NULL) { | |
| TempDevicePath = DevicePath; | |
| Status = gBS->LocateDevicePath ( | |
| &gEfiDevicePathProtocolGuid, | |
| &TempDevicePath, | |
| &DriverHandle | |
| ); | |
| if (EFI_ERROR (Status) || (DriverHandle == NULL)) { | |
| // | |
| // Routing data does not match any known driver. | |
| // Set Progress to the 'G' in "GUID" of the routing header. | |
| // | |
| *Progress = StringPtr; | |
| Status = EFI_NOT_FOUND; | |
| goto Done; | |
| } | |
| } | |
| // | |
| // Check whether ConfigRequest contains request string OFFSET/WIDTH | |
| // | |
| IfrDataParsedFlag = FALSE; | |
| if ((HiiHandle != NULL) && (StrStr (ConfigRequest, L"&OFFSET=") == NULL)) { | |
| // | |
| // Get the full request string from IFR when HiiPackage is registered to HiiHandle | |
| // | |
| IfrDataParsedFlag = TRUE; | |
| Status = GetFullStringFromHiiFormPackages (Database, DevicePath, &ConfigRequest, &DefaultResults, &AccessProgress); | |
| if (EFI_ERROR (Status)) { | |
| // | |
| // AccessProgress indicates the parsing progress on <ConfigRequest>. | |
| // Map it to the progress on <MultiConfigRequest> then return it. | |
| // | |
| *Progress = StrStr (StringPtr, AccessProgress); | |
| goto Done; | |
| } | |
| // | |
| // Not any request block is found. | |
| // | |
| if (StrStr (ConfigRequest, L"&OFFSET=") == NULL) { | |
| AccessResults = AllocateCopyPool (StrSize (ConfigRequest), ConfigRequest); | |
| goto NextConfigString; | |
| } | |
| } | |
| // | |
| // Call corresponding ConfigAccess protocol to extract settings | |
| // | |
| Status = gBS->HandleProtocol ( | |
| DriverHandle, | |
| &gEfiHiiConfigAccessProtocolGuid, | |
| (VOID **) &ConfigAccess | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| Status = ConfigAccess->ExtractConfig ( | |
| ConfigAccess, | |
| ConfigRequest, | |
| &AccessProgress, | |
| &AccessResults | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| // | |
| // AccessProgress indicates the parsing progress on <ConfigRequest>. | |
| // Map it to the progress on <MultiConfigRequest> then return it. | |
| // | |
| *Progress = StrStr (StringPtr, AccessProgress); | |
| goto Done; | |
| } | |
| // | |
| // Attach this <ConfigAltResp> to a <MultiConfigAltResp>. There is a '&' | |
| // which seperates the first <ConfigAltResp> and the following ones. | |
| // | |
| ASSERT (*AccessProgress == 0); | |
| // | |
| // Update AccessResults by getting default setting from IFR when HiiPackage is registered to HiiHandle | |
| // | |
| if (!IfrDataParsedFlag && HiiHandle != NULL) { | |
| Status = GetFullStringFromHiiFormPackages (Database, DevicePath, &ConfigRequest, &DefaultResults, NULL); | |
| ASSERT_EFI_ERROR (Status); | |
| } | |
| FreePool (DevicePath); | |
| DevicePath = NULL; | |
| if (DefaultResults != NULL) { | |
| Status = MergeDefaultString (&AccessResults, DefaultResults); | |
| ASSERT_EFI_ERROR (Status); | |
| FreePool (DefaultResults); | |
| DefaultResults = NULL; | |
| } | |
| NextConfigString: | |
| if (!FirstElement) { | |
| Status = AppendToMultiString (Results, L"&"); | |
| ASSERT_EFI_ERROR (Status); | |
| } | |
| Status = AppendToMultiString (Results, AccessResults); | |
| ASSERT_EFI_ERROR (Status); | |
| FirstElement = FALSE; | |
| FreePool (AccessResults); | |
| AccessResults = NULL; | |
| FreePool (ConfigRequest); | |
| ConfigRequest = NULL; | |
| // | |
| // Go to next <ConfigRequest> (skip '&'). | |
| // | |
| StringPtr += Length; | |
| if (*StringPtr == 0) { | |
| *Progress = StringPtr; | |
| break; | |
| } | |
| StringPtr++; | |
| } | |
| Done: | |
| if (EFI_ERROR (Status)) { | |
| FreePool (*Results); | |
| *Results = NULL; | |
| } | |
| if (ConfigRequest != NULL) { | |
| FreePool (ConfigRequest); | |
| } | |
| if (AccessResults != NULL) { | |
| FreePool (AccessResults); | |
| } | |
| if (DefaultResults != NULL) { | |
| FreePool (DefaultResults); | |
| } | |
| if (DevicePath != NULL) { | |
| FreePool (DevicePath); | |
| } | |
| return Status; | |
| } | |
| /** | |
| This function allows the caller to request the current configuration for the | |
| entirety of the current HII database and returns the data in a | |
| null-terminated Unicode string. | |
| @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL | |
| instance. | |
| @param Results Null-terminated Unicode string in | |
| <MultiConfigAltResp> format which has all values | |
| filled in for the names in the Request string. | |
| String to be allocated by the called function. | |
| De-allocation is up to the caller. | |
| @retval EFI_SUCCESS The Results string is filled with the values | |
| corresponding to all requested names. | |
| @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the | |
| results that must be stored awaiting possible | |
| future protocols. | |
| @retval EFI_INVALID_PARAMETER For example, passing in a NULL for the Results | |
| parameter would result in this type of error. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| HiiConfigRoutingExportConfig ( | |
| IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This, | |
| OUT EFI_STRING *Results | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess; | |
| EFI_STRING AccessResults; | |
| EFI_STRING Progress; | |
| EFI_STRING StringPtr; | |
| EFI_STRING ConfigRequest; | |
| UINTN Index; | |
| EFI_HANDLE *ConfigAccessHandles; | |
| UINTN NumberConfigAccessHandles; | |
| BOOLEAN FirstElement; | |
| EFI_DEVICE_PATH_PROTOCOL *DevicePath; | |
| EFI_HII_HANDLE HiiHandle; | |
| EFI_STRING DefaultResults; | |
| HII_DATABASE_PRIVATE_DATA *Private; | |
| LIST_ENTRY *Link; | |
| HII_DATABASE_RECORD *Database; | |
| UINT8 *DevicePathPkg; | |
| UINT8 *CurrentDevicePath; | |
| BOOLEAN IfrDataParsedFlag; | |
| if (This == NULL || Results == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This); | |
| // | |
| // Allocate a fix length of memory to store Results. Reallocate memory for | |
| // Results if this fix length is insufficient. | |
| // | |
| *Results = (EFI_STRING) AllocateZeroPool (MAX_STRING_LENGTH); | |
| if (*Results == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| NumberConfigAccessHandles = 0; | |
| Status = gBS->LocateHandleBuffer ( | |
| ByProtocol, | |
| &gEfiHiiConfigAccessProtocolGuid, | |
| NULL, | |
| &NumberConfigAccessHandles, | |
| &ConfigAccessHandles | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| FirstElement = TRUE; | |
| for (Index = 0; Index < NumberConfigAccessHandles; Index++) { | |
| Status = gBS->HandleProtocol ( | |
| ConfigAccessHandles[Index], | |
| &gEfiHiiConfigAccessProtocolGuid, | |
| (VOID **) &ConfigAccess | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| continue; | |
| } | |
| // | |
| // Get DevicePath and HiiHandle for this ConfigAccess driver handle | |
| // | |
| IfrDataParsedFlag = FALSE; | |
| Progress = NULL; | |
| HiiHandle = NULL; | |
| DefaultResults = NULL; | |
| Database = NULL; | |
| ConfigRequest = NULL; | |
| DevicePath = DevicePathFromHandle (ConfigAccessHandles[Index]); | |
| if (DevicePath != NULL) { | |
| for (Link = Private->DatabaseList.ForwardLink; | |
| Link != &Private->DatabaseList; | |
| Link = Link->ForwardLink | |
| ) { | |
| Database = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE); | |
| if ((DevicePathPkg = Database->PackageList->DevicePathPkg) != NULL) { | |
| CurrentDevicePath = DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER); | |
| if (CompareMem ( | |
| DevicePath, | |
| CurrentDevicePath, | |
| GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) CurrentDevicePath) | |
| ) == 0) { | |
| HiiHandle = Database->Handle; | |
| break; | |
| } | |
| } | |
| } | |
| } | |
| Status = ConfigAccess->ExtractConfig ( | |
| ConfigAccess, | |
| NULL, | |
| &Progress, | |
| &AccessResults | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| // | |
| // Update AccessResults by getting default setting from IFR when HiiPackage is registered to HiiHandle | |
| // | |
| if (HiiHandle != NULL && DevicePath != NULL) { | |
| IfrDataParsedFlag = TRUE; | |
| Status = GetFullStringFromHiiFormPackages (Database, DevicePath, &ConfigRequest, &DefaultResults, NULL); | |
| // | |
| // Get the full request string to get the Current setting again. | |
| // | |
| if (!EFI_ERROR (Status) && ConfigRequest != NULL) { | |
| Status = ConfigAccess->ExtractConfig ( | |
| ConfigAccess, | |
| ConfigRequest, | |
| &Progress, | |
| &AccessResults | |
| ); | |
| FreePool (ConfigRequest); | |
| } else { | |
| Status = EFI_NOT_FOUND; | |
| } | |
| } | |
| } | |
| if (!EFI_ERROR (Status)) { | |
| // | |
| // Update AccessResults by getting default setting from IFR when HiiPackage is registered to HiiHandle | |
| // | |
| if (!IfrDataParsedFlag && HiiHandle != NULL && DevicePath != NULL) { | |
| StringPtr = StrStr (AccessResults, L"&GUID="); | |
| if (StringPtr != NULL) { | |
| *StringPtr = 0; | |
| } | |
| if (StrStr (AccessResults, L"&OFFSET=") != NULL) { | |
| Status = GetFullStringFromHiiFormPackages (Database, DevicePath, &AccessResults, &DefaultResults, NULL); | |
| ASSERT_EFI_ERROR (Status); | |
| } | |
| if (StringPtr != NULL) { | |
| *StringPtr = L'&'; | |
| } | |
| } | |
| // | |
| // Merge the default sting from IFR code into the got setting from driver. | |
| // | |
| if (DefaultResults != NULL) { | |
| Status = MergeDefaultString (&AccessResults, DefaultResults); | |
| ASSERT_EFI_ERROR (Status); | |
| FreePool (DefaultResults); | |
| DefaultResults = NULL; | |
| } | |
| // | |
| // Attach this <ConfigAltResp> to a <MultiConfigAltResp>. There is a '&' | |
| // which seperates the first <ConfigAltResp> and the following ones. | |
| // | |
| if (!FirstElement) { | |
| Status = AppendToMultiString (Results, L"&"); | |
| ASSERT_EFI_ERROR (Status); | |
| } | |
| Status = AppendToMultiString (Results, AccessResults); | |
| ASSERT_EFI_ERROR (Status); | |
| FirstElement = FALSE; | |
| FreePool (AccessResults); | |
| AccessResults = NULL; | |
| } | |
| } | |
| FreePool (ConfigAccessHandles); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| This function processes the results of processing forms and routes it to the | |
| appropriate handlers or storage. | |
| @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL | |
| instance. | |
| @param Configuration A null-terminated Unicode string in | |
| <MulltiConfigResp> format. | |
| @param Progress A pointer to a string filled in with the offset of | |
| the most recent & before the first failing name / | |
| value pair (or the beginning of the string if the | |
| failure is in the first name / value pair) or the | |
| terminating NULL if all was successful. | |
| @retval EFI_SUCCESS The results have been distributed or are awaiting | |
| distribution. | |
| @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the | |
| results that must be stored awaiting possible | |
| future protocols. | |
| @retval EFI_INVALID_PARAMETER Passing in a NULL for the Configuration parameter | |
| would result in this type of error. | |
| @retval EFI_NOT_FOUND Target for the specified routing data was not | |
| found. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| HiiConfigRoutingRouteConfig ( | |
| IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This, | |
| IN CONST EFI_STRING Configuration, | |
| OUT EFI_STRING *Progress | |
| ) | |
| { | |
| HII_DATABASE_PRIVATE_DATA *Private; | |
| EFI_STRING StringPtr; | |
| EFI_STRING ConfigResp; | |
| UINTN Length; | |
| EFI_STATUS Status; | |
| EFI_DEVICE_PATH_PROTOCOL *DevicePath; | |
| EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; | |
| LIST_ENTRY *Link; | |
| HII_DATABASE_RECORD *Database; | |
| UINT8 *DevicePathPkg; | |
| UINT8 *CurrentDevicePath; | |
| EFI_HANDLE DriverHandle; | |
| EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess; | |
| EFI_STRING AccessProgress; | |
| if (This == NULL || Progress == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if (Configuration == NULL) { | |
| *Progress = NULL; | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This); | |
| StringPtr = Configuration; | |
| *Progress = StringPtr; | |
| // | |
| // The first element of <MultiConfigResp> should be | |
| // <GuidHdr>, which is in 'GUID='<Guid> syntax. | |
| // | |
| if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| while (*StringPtr != 0 && StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) == 0) { | |
| // | |
| // If parsing error, set Progress to the beginning of the <MultiConfigResp> | |
| // or most recent & before the error. | |
| // | |
| if (StringPtr == Configuration) { | |
| *Progress = StringPtr; | |
| } else { | |
| *Progress = StringPtr - 1; | |
| } | |
| // | |
| // Process each <ConfigResp> of <MultiConfigResp> | |
| // | |
| Length = CalculateConfigStringLen (StringPtr); | |
| ConfigResp = AllocateCopyPool ((Length + 1) * sizeof (CHAR16), StringPtr); | |
| if (ConfigResp == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| // | |
| // Append '\0' to the end of ConfigRequest | |
| // | |
| *(ConfigResp + Length) = 0; | |
| // | |
| // Get the UEFI device path | |
| // | |
| Status = GetDevicePath (ConfigResp, (UINT8 **) &DevicePath); | |
| if (EFI_ERROR (Status)) { | |
| FreePool (ConfigResp); | |
| return Status; | |
| } | |
| // | |
| // Find driver which matches the routing data. | |
| // | |
| DriverHandle = NULL; | |
| for (Link = Private->DatabaseList.ForwardLink; | |
| Link != &Private->DatabaseList; | |
| Link = Link->ForwardLink | |
| ) { | |
| Database = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE); | |
| if ((DevicePathPkg = Database->PackageList->DevicePathPkg) != NULL) { | |
| CurrentDevicePath = DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER); | |
| if (CompareMem ( | |
| DevicePath, | |
| CurrentDevicePath, | |
| GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) CurrentDevicePath) | |
| ) == 0) { | |
| DriverHandle = Database->DriverHandle; | |
| break; | |
| } | |
| } | |
| } | |
| // | |
| // Try to find driver handle by device path. | |
| // | |
| if (DriverHandle == NULL) { | |
| TempDevicePath = DevicePath; | |
| Status = gBS->LocateDevicePath ( | |
| &gEfiDevicePathProtocolGuid, | |
| &TempDevicePath, | |
| &DriverHandle | |
| ); | |
| if (EFI_ERROR (Status) || (DriverHandle == NULL)) { | |
| // | |
| // Routing data does not match any known driver. | |
| // Set Progress to the 'G' in "GUID" of the routing header. | |
| // | |
| FreePool (DevicePath); | |
| *Progress = StringPtr; | |
| FreePool (ConfigResp); | |
| return EFI_NOT_FOUND; | |
| } | |
| } | |
| FreePool (DevicePath); | |
| // | |
| // Call corresponding ConfigAccess protocol to route settings | |
| // | |
| Status = gBS->HandleProtocol ( | |
| DriverHandle, | |
| &gEfiHiiConfigAccessProtocolGuid, | |
| (VOID **) &ConfigAccess | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| Status = ConfigAccess->RouteConfig ( | |
| ConfigAccess, | |
| ConfigResp, | |
| &AccessProgress | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| // | |
| // AccessProgress indicates the parsing progress on <ConfigResp>. | |
| // Map it to the progress on <MultiConfigResp> then return it. | |
| // | |
| *Progress = StrStr (StringPtr, AccessProgress); | |
| FreePool (ConfigResp); | |
| return Status; | |
| } | |
| FreePool (ConfigResp); | |
| ConfigResp = NULL; | |
| // | |
| // Go to next <ConfigResp> (skip '&'). | |
| // | |
| StringPtr += Length; | |
| if (*StringPtr == 0) { | |
| *Progress = StringPtr; | |
| break; | |
| } | |
| StringPtr++; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| This helper function is to be called by drivers to map configuration data | |
| stored in byte array ("block") formats such as UEFI Variables into current | |
| configuration strings. | |
| @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL | |
| instance. | |
| @param ConfigRequest A null-terminated Unicode string in | |
| <ConfigRequest> format. | |
| @param Block Array of bytes defining the block's configuration. | |
| @param BlockSize Length in bytes of Block. | |
| @param Config Filled-in configuration string. String allocated | |
| by the function. Returned only if call is | |
| successful. It is <ConfigResp> string format. | |
| @param Progress A pointer to a string filled in with the offset of | |
| the most recent & before the first failing | |
| name/value pair (or the beginning of the string if | |
| the failure is in the first name / value pair) or | |
| the terminating NULL if all was successful. | |
| @retval EFI_SUCCESS The request succeeded. Progress points to the null | |
| terminator at the end of the ConfigRequest | |
| string. | |
| @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. Progress | |
| points to the first character of ConfigRequest. | |
| @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigRequest or | |
| Block parameter would result in this type of | |
| error. Progress points to the first character of | |
| ConfigRequest. | |
| @retval EFI_DEVICE_ERROR Block not large enough. Progress undefined. | |
| @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted string. | |
| Block is left updated and Progress points at | |
| the "&" preceding the first non-<BlockName>. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| HiiBlockToConfig ( | |
| IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This, | |
| IN CONST EFI_STRING ConfigRequest, | |
| IN CONST UINT8 *Block, | |
| IN CONST UINTN BlockSize, | |
| OUT EFI_STRING *Config, | |
| OUT EFI_STRING *Progress | |
| ) | |
| { | |
| HII_DATABASE_PRIVATE_DATA *Private; | |
| EFI_STRING StringPtr; | |
| UINTN Length; | |
| EFI_STATUS Status; | |
| EFI_STRING TmpPtr; | |
| UINT8 *TmpBuffer; | |
| UINTN Offset; | |
| UINTN Width; | |
| UINT8 *Value; | |
| EFI_STRING ValueStr; | |
| EFI_STRING ConfigElement; | |
| UINTN Index; | |
| UINT8 *TemBuffer; | |
| CHAR16 *TemString; | |
| if (This == NULL || Progress == NULL || Config == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if (Block == NULL || ConfigRequest == NULL) { | |
| *Progress = ConfigRequest; | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This); | |
| ASSERT (Private != NULL); | |
| StringPtr = ConfigRequest; | |
| ValueStr = NULL; | |
| Value = NULL; | |
| ConfigElement = NULL; | |
| // | |
| // Allocate a fix length of memory to store Results. Reallocate memory for | |
| // Results if this fix length is insufficient. | |
| // | |
| *Config = (EFI_STRING) AllocateZeroPool (MAX_STRING_LENGTH); | |
| if (*Config == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| // | |
| // Jump <ConfigHdr> | |
| // | |
| if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) { | |
| *Progress = StringPtr; | |
| Status = EFI_INVALID_PARAMETER; | |
| goto Exit; | |
| } | |
| while (*StringPtr != 0 && StrnCmp (StringPtr, L"PATH=", StrLen (L"PATH=")) != 0) { | |
| StringPtr++; | |
| } | |
| if (*StringPtr == 0) { | |
| *Progress = StringPtr - 1; | |
| Status = EFI_INVALID_PARAMETER; | |
| goto Exit; | |
| } | |
| while (*StringPtr != L'&' && *StringPtr != 0) { | |
| StringPtr++; | |
| } | |
| if (*StringPtr == 0) { | |
| *Progress = StringPtr - 1; | |
| Status = EFI_INVALID_PARAMETER; | |
| goto Exit; | |
| } | |
| // | |
| // Skip '&' | |
| // | |
| StringPtr++; | |
| // | |
| // Copy <ConfigHdr> and an additional '&' to <ConfigResp> | |
| // | |
| Length = StringPtr - ConfigRequest; | |
| CopyMem (*Config, ConfigRequest, Length * sizeof (CHAR16)); | |
| // | |
| // Parse each <RequestElement> if exists | |
| // Only <BlockName> format is supported by this help function. | |
| // <BlockName> ::= 'OFFSET='<Number>&'WIDTH='<Number> | |
| // | |
| while (*StringPtr != 0 && StrnCmp (StringPtr, L"OFFSET=", StrLen (L"OFFSET=")) == 0) { | |
| // | |
| // Back up the header of one <BlockName> | |
| // | |
| TmpPtr = StringPtr; | |
| StringPtr += StrLen (L"OFFSET="); | |
| // | |
| // Get Offset | |
| // | |
| Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length); | |
| if (Status == EFI_OUT_OF_RESOURCES) { | |
| *Progress = ConfigRequest; | |
| goto Exit; | |
| } | |
| Offset = 0; | |
| CopyMem ( | |
| &Offset, | |
| TmpBuffer, | |
| (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN) | |
| ); | |
| FreePool (TmpBuffer); | |
| StringPtr += Length; | |
| if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) { | |
| *Progress = StringPtr - Length - StrLen (L"OFFSET=") - 1; | |
| Status = EFI_INVALID_PARAMETER; | |
| goto Exit; | |
| } | |
| StringPtr += StrLen (L"&WIDTH="); | |
| // | |
| // Get Width | |
| // | |
| Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length); | |
| if (Status == EFI_OUT_OF_RESOURCES) { | |
| *Progress = ConfigRequest; | |
| goto Exit; | |
| } | |
| Width = 0; | |
| CopyMem ( | |
| &Width, | |
| TmpBuffer, | |
| (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN) | |
| ); | |
| FreePool (TmpBuffer); | |
| StringPtr += Length; | |
| if (*StringPtr != 0 && *StringPtr != L'&') { | |
| *Progress = StringPtr - Length - StrLen (L"&WIDTH="); | |
| Status = EFI_INVALID_PARAMETER; | |
| goto Exit; | |
| } | |
| // | |
| // Calculate Value and convert it to hex string. | |
| // | |
| if (Offset + Width > BlockSize) { | |
| *Progress = StringPtr; | |
| Status = EFI_DEVICE_ERROR; | |
| goto Exit; | |
| } | |
| Value = (UINT8 *) AllocateZeroPool (Width); | |
| if (Value == NULL) { | |
| *Progress = ConfigRequest; | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto Exit; | |
| } | |
| CopyMem (Value, (UINT8 *) Block + Offset, Width); | |
| Length = Width * 2 + 1; | |
| ValueStr = (EFI_STRING) AllocateZeroPool (Length * sizeof (CHAR16)); | |
| if (ValueStr == NULL) { | |
| *Progress = ConfigRequest; | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto Exit; | |
| } | |
| TemString = ValueStr; | |
| TemBuffer = Value + Width - 1; | |
| for (Index = 0; Index < Width; Index ++, TemBuffer --) { | |
| TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemBuffer, 2); | |
| } | |
| FreePool (Value); | |
| Value = NULL; | |
| // | |
| // Build a ConfigElement | |
| // | |
| Length += StringPtr - TmpPtr + 1 + StrLen (L"VALUE="); | |
| ConfigElement = (EFI_STRING) AllocateZeroPool (Length * sizeof (CHAR16)); | |
| if (ConfigElement == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto Exit; | |
| } | |
| CopyMem (ConfigElement, TmpPtr, (StringPtr - TmpPtr + 1) * sizeof (CHAR16)); | |
| if (*StringPtr == 0) { | |
| *(ConfigElement + (StringPtr - TmpPtr)) = L'&'; | |
| } | |
| *(ConfigElement + (StringPtr - TmpPtr) + 1) = 0; | |
| StrCat (ConfigElement, L"VALUE="); | |
| StrCat (ConfigElement, ValueStr); | |
| AppendToMultiString (Config, ConfigElement); | |
| FreePool (ConfigElement); | |
| FreePool (ValueStr); | |
| ConfigElement = NULL; | |
| ValueStr = NULL; | |
| // | |
| // If '\0', parsing is finished. Otherwise skip '&' to continue | |
| // | |
| if (*StringPtr == 0) { | |
| break; | |
| } | |
| AppendToMultiString (Config, L"&"); | |
| StringPtr++; | |
| } | |
| if (*StringPtr != 0) { | |
| *Progress = StringPtr - 1; | |
| Status = EFI_INVALID_PARAMETER; | |
| goto Exit; | |
| } | |
| HiiToLower (*Config); | |
| *Progress = StringPtr; | |
| return EFI_SUCCESS; | |
| Exit: | |
| if (*Config != NULL) { | |
| FreePool (*Config); | |
| *Config = NULL; | |
| } | |
| if (ValueStr != NULL) { | |
| FreePool (ValueStr); | |
| } | |
| if (Value != NULL) { | |
| FreePool (Value); | |
| } | |
| if (ConfigElement != NULL) { | |
| FreePool (ConfigElement); | |
| } | |
| return Status; | |
| } | |
| /** | |
| This helper function is to be called by drivers to map configuration strings | |
| to configurations stored in byte array ("block") formats such as UEFI Variables. | |
| @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL | |
| instance. | |
| @param ConfigResp A null-terminated Unicode string in <ConfigResp> | |
| format. | |
| @param Block A possibly null array of bytes representing the | |
| current block. Only bytes referenced in the | |
| ConfigResp string in the block are modified. If | |
| this parameter is null or if the *BlockSize | |
| parameter is (on input) shorter than required by | |
| the Configuration string, only the BlockSize | |
| parameter is updated and an appropriate status | |
| (see below) is returned. | |
| @param BlockSize The length of the Block in units of UINT8. On | |
| input, this is the size of the Block. On output, | |
| if successful, contains the index of the last | |
| modified byte in the Block. | |
| @param Progress On return, points to an element of the ConfigResp | |
| string filled in with the offset of the most | |
| recent '&' before the first failing name / value | |
| pair (or the beginning of the string if the | |
| failure is in the first name / value pair) or the | |
| terminating NULL if all was successful. | |
| @retval EFI_SUCCESS The request succeeded. Progress points to the null | |
| terminator at the end of the ConfigResp string. | |
| @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. Progress | |
| points to the first character of ConfigResp. | |
| @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigResp or | |
| Block parameter would result in this type of | |
| error. Progress points to the first character of | |
| ConfigResp. | |
| @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted name / | |
| value pair. Block is left updated and | |
| Progress points at the '&' preceding the first | |
| non-<BlockName>. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| HiiConfigToBlock ( | |
| IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This, | |
| IN CONST EFI_STRING ConfigResp, | |
| IN OUT UINT8 *Block, | |
| IN OUT UINTN *BlockSize, | |
| OUT EFI_STRING *Progress | |
| ) | |
| { | |
| HII_DATABASE_PRIVATE_DATA *Private; | |
| EFI_STRING StringPtr; | |
| UINTN Length; | |
| EFI_STATUS Status; | |
| UINT8 *TmpBuffer; | |
| UINTN Offset; | |
| UINTN Width; | |
| UINT8 *Value; | |
| UINTN BufferSize; | |
| if (This == NULL || BlockSize == NULL || Progress == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if (ConfigResp == NULL || Block == NULL) { | |
| *Progress = ConfigResp; | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This); | |
| ASSERT (Private != NULL); | |
| StringPtr = ConfigResp; | |
| BufferSize = *BlockSize; | |
| Value = NULL; | |
| // | |
| // Jump <ConfigHdr> | |
| // | |
| if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) { | |
| *Progress = StringPtr; | |
| Status = EFI_INVALID_PARAMETER; | |
| goto Exit; | |
| } | |
| while (*StringPtr != 0 && StrnCmp (StringPtr, L"PATH=", StrLen (L"PATH=")) != 0) { | |
| StringPtr++; | |
| } | |
| if (*StringPtr == 0) { | |
| *Progress = StringPtr; | |
| Status = EFI_INVALID_PARAMETER; | |
| goto Exit; | |
| } | |
| while (*StringPtr != L'&' && *StringPtr != 0) { | |
| StringPtr++; | |
| } | |
| if (*StringPtr == 0) { | |
| *Progress = StringPtr; | |
| Status = EFI_INVALID_PARAMETER; | |
| goto Exit; | |
| } | |
| // | |
| // Skip '&' | |
| // | |
| StringPtr++; | |
| // | |
| // Parse each <ConfigElement> if exists | |
| // Only <BlockConfig> format is supported by this help function. | |
| // <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE='<Number> | |
| // | |
| while (*StringPtr != 0 && StrnCmp (StringPtr, L"OFFSET=", StrLen (L"OFFSET=")) == 0) { | |
| StringPtr += StrLen (L"OFFSET="); | |
| // | |
| // Get Offset | |
| // | |
| Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length); | |
| if (EFI_ERROR (Status)) { | |
| *Progress = ConfigResp; | |
| goto Exit; | |
| } | |
| Offset = 0; | |
| CopyMem ( | |
| &Offset, | |
| TmpBuffer, | |
| (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN) | |
| ); | |
| FreePool (TmpBuffer); | |
| StringPtr += Length; | |
| if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) { | |
| *Progress = StringPtr - Length - StrLen (L"OFFSET=") - 1; | |
| Status = EFI_INVALID_PARAMETER; | |
| goto Exit; | |
| } | |
| StringPtr += StrLen (L"&WIDTH="); | |
| // | |
| // Get Width | |
| // | |
| Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length); | |
| if (Status == EFI_OUT_OF_RESOURCES) { | |
| *Progress = ConfigResp; | |
| goto Exit; | |
| } | |
| Width = 0; | |
| CopyMem ( | |
| &Width, | |
| TmpBuffer, | |
| (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN) | |
| ); | |
| FreePool (TmpBuffer); | |
| StringPtr += Length; | |
| if (StrnCmp (StringPtr, L"&VALUE=", StrLen (L"&VALUE=")) != 0) { | |
| *Progress = StringPtr - Length - StrLen (L"&WIDTH="); | |
| Status = EFI_INVALID_PARAMETER; | |
| goto Exit; | |
| } | |
| StringPtr += StrLen (L"&VALUE="); | |
| // | |
| // Get Value | |
| // | |
| Status = GetValueOfNumber (StringPtr, &Value, &Length); | |
| if (EFI_ERROR (Status)) { | |
| *Progress = ConfigResp; | |
| goto Exit; | |
| } | |
| StringPtr += Length; | |
| if (*StringPtr != 0 && *StringPtr != L'&') { | |
| *Progress = StringPtr - Length - 7; | |
| Status = EFI_INVALID_PARAMETER; | |
| goto Exit; | |
| } | |
| // | |
| // Update the Block with configuration info | |
| // | |
| if (Offset + Width > BufferSize) { | |
| return EFI_DEVICE_ERROR; | |
| } | |
| CopyMem (Block + Offset, Value, Width); | |
| *BlockSize = Offset + Width - 1; | |
| FreePool (Value); | |
| Value = NULL; | |
| // | |
| // If '\0', parsing is finished. Otherwise skip '&' to continue | |
| // | |
| if (*StringPtr == 0) { | |
| break; | |
| } | |
| StringPtr++; | |
| } | |
| // | |
| // The input string is ConfigAltResp format. | |
| // | |
| if ((*StringPtr != 0) && (StrnCmp (StringPtr, L"&GUID=", StrLen (L"&GUID=")) != 0)) { | |
| *Progress = StringPtr - 1; | |
| Status = EFI_INVALID_PARAMETER; | |
| goto Exit; | |
| } | |
| *Progress = StringPtr + StrLen (StringPtr); | |
| return EFI_SUCCESS; | |
| Exit: | |
| if (Value != NULL) { | |
| FreePool (Value); | |
| } | |
| return Status; | |
| } | |
| /** | |
| This helper function is to be called by drivers to extract portions of | |
| a larger configuration string. | |
| @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL | |
| instance. | |
| @param Configuration A null-terminated Unicode string in | |
| <MultiConfigAltResp> format. | |
| @param Guid A pointer to the GUID value to search for in the | |
| routing portion of the ConfigResp string when | |
| retrieving the requested data. If Guid is NULL, | |
| then all GUID values will be searched for. | |
| @param Name A pointer to the NAME value to search for in the | |
| routing portion of the ConfigResp string when | |
| retrieving the requested data. If Name is NULL, | |
| then all Name values will be searched for. | |
| @param DevicePath A pointer to the PATH value to search for in the | |
| routing portion of the ConfigResp string when | |
| retrieving the requested data. If DevicePath is | |
| NULL, then all DevicePath values will be searched | |
| for. | |
| @param AltCfgId A pointer to the ALTCFG value to search for in the | |
| routing portion of the ConfigResp string when | |
| retrieving the requested data. If this parameter | |
| is NULL, then the current setting will be | |
| retrieved. | |
| @param AltCfgResp A pointer to a buffer which will be allocated by | |
| the function which contains the retrieved string | |
| as requested. This buffer is only allocated if | |
| the call was successful. It is <ConfigResp> format. | |
| @retval EFI_SUCCESS The request succeeded. The requested data was | |
| extracted and placed in the newly allocated | |
| AltCfgResp buffer. | |
| @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate AltCfgResp. | |
| @retval EFI_INVALID_PARAMETER Any parameter is invalid. | |
| @retval EFI_NOT_FOUND Target for the specified routing data was not | |
| found. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| HiiGetAltCfg ( | |
| IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This, | |
| IN CONST EFI_STRING Configuration, | |
| IN CONST EFI_GUID *Guid, | |
| IN CONST EFI_STRING Name, | |
| IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath, | |
| IN CONST UINT16 *AltCfgId, | |
| OUT EFI_STRING *AltCfgResp | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_STRING StringPtr; | |
| EFI_STRING HdrStart; | |
| EFI_STRING HdrEnd; | |
| EFI_STRING TmpPtr; | |
| UINTN Length; | |
| EFI_STRING GuidStr; | |
| EFI_STRING NameStr; | |
| EFI_STRING PathStr; | |
| EFI_STRING AltIdStr; | |
| EFI_STRING Result; | |
| BOOLEAN GuidFlag; | |
| BOOLEAN NameFlag; | |
| BOOLEAN PathFlag; | |
| HdrStart = NULL; | |
| HdrEnd = NULL; | |
| GuidStr = NULL; | |
| NameStr = NULL; | |
| PathStr = NULL; | |
| AltIdStr = NULL; | |
| Result = NULL; | |
| GuidFlag = FALSE; | |
| NameFlag = FALSE; | |
| PathFlag = FALSE; | |
| if (This == NULL || Configuration == NULL || AltCfgResp == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| StringPtr = Configuration; | |
| if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // Generate the sub string for later matching. | |
| // | |
| GenerateSubStr (L"GUID=", sizeof (EFI_GUID), (VOID *) Guid, 1, &GuidStr); | |
| GenerateSubStr ( | |
| L"PATH=", | |
| GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) DevicePath), | |
| (VOID *) DevicePath, | |
| 1, | |
| &PathStr | |
| ); | |
| if (AltCfgId != NULL) { | |
| GenerateSubStr (L"ALTCFG=", sizeof (UINT16), (VOID *) AltCfgId, 3, &AltIdStr); | |
| } | |
| if (Name != NULL) { | |
| GenerateSubStr (L"NAME=", StrLen (Name) * sizeof (CHAR16), (VOID *) Name, 2, &NameStr); | |
| } else { | |
| GenerateSubStr (L"NAME=", 0, NULL, 2, &NameStr); | |
| } | |
| while (*StringPtr != 0) { | |
| // | |
| // Try to match the GUID | |
| // | |
| if (!GuidFlag) { | |
| TmpPtr = StrStr (StringPtr, GuidStr); | |
| if (TmpPtr == NULL) { | |
| Status = EFI_NOT_FOUND; | |
| goto Exit; | |
| } | |
| HdrStart = TmpPtr; | |
| // | |
| // Jump to <NameHdr> | |
| // | |
| if (Guid != NULL) { | |
| StringPtr = TmpPtr + StrLen (GuidStr); | |
| } else { | |
| StringPtr = StrStr (TmpPtr, L"NAME="); | |
| if (StringPtr == NULL) { | |
| Status = EFI_NOT_FOUND; | |
| goto Exit; | |
| } | |
| } | |
| GuidFlag = TRUE; | |
| } | |
| // | |
| // Try to match the NAME | |
| // | |
| if (GuidFlag && !NameFlag) { | |
| if (StrnCmp (StringPtr, NameStr, StrLen (NameStr)) != 0) { | |
| GuidFlag = FALSE; | |
| } else { | |
| // | |
| // Jump to <PathHdr> | |
| // | |
| if (Name != NULL) { | |
| StringPtr += StrLen (NameStr); | |
| } else { | |
| StringPtr = StrStr (StringPtr, L"PATH="); | |
| if (StringPtr == NULL) { | |
| Status = EFI_NOT_FOUND; | |
| goto Exit; | |
| } | |
| } | |
| NameFlag = TRUE; | |
| } | |
| } | |
| // | |
| // Try to match the DevicePath | |
| // | |
| if (GuidFlag && NameFlag && !PathFlag) { | |
| if (StrnCmp (StringPtr, PathStr, StrLen (PathStr)) != 0) { | |
| GuidFlag = FALSE; | |
| NameFlag = FALSE; | |
| } else { | |
| // | |
| // Jump to '&' before <DescHdr> or <ConfigBody> | |
| // | |
| if (DevicePath != NULL) { | |
| StringPtr += StrLen (PathStr); | |
| } else { | |
| StringPtr = StrStr (StringPtr, L"&"); | |
| if (StringPtr == NULL) { | |
| Status = EFI_NOT_FOUND; | |
| goto Exit; | |
| } | |
| StringPtr ++; | |
| } | |
| PathFlag = TRUE; | |
| HdrEnd = StringPtr; | |
| } | |
| } | |
| // | |
| // Try to match the AltCfgId | |
| // | |
| if (GuidFlag && NameFlag && PathFlag) { | |
| if (AltCfgId == NULL) { | |
| // | |
| // Return Current Setting when AltCfgId is NULL. | |
| // | |
| Status = OutputConfigBody (StringPtr, &Result); | |
| goto Exit; | |
| } | |
| // | |
| // Search the <ConfigAltResp> to get the <AltResp> with AltCfgId. | |
| // | |
| if (StrnCmp (StringPtr, AltIdStr, StrLen (AltIdStr)) != 0) { | |
| GuidFlag = FALSE; | |
| NameFlag = FALSE; | |
| PathFlag = FALSE; | |
| } else { | |
| // | |
| // Skip AltIdStr and & | |
| // | |
| StringPtr = StringPtr + StrLen (AltIdStr); | |
| Status = OutputConfigBody (StringPtr, &Result); | |
| goto Exit; | |
| } | |
| } | |
| } | |
| Status = EFI_NOT_FOUND; | |
| Exit: | |
| *AltCfgResp = NULL; | |
| if (!EFI_ERROR (Status) && (Result != NULL)) { | |
| // | |
| // Copy the <ConfigHdr> and <ConfigBody> | |
| // | |
| Length = HdrEnd - HdrStart + StrLen (Result) + 1; | |
| *AltCfgResp = AllocateZeroPool (Length * sizeof (CHAR16)); | |
| if (*AltCfgResp == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| } else { | |
| StrnCpy (*AltCfgResp, HdrStart, HdrEnd - HdrStart); | |
| StrCat (*AltCfgResp, Result); | |
| Status = EFI_SUCCESS; | |
| } | |
| } | |
| if (GuidStr != NULL) { | |
| FreePool (GuidStr); | |
| } | |
| if (NameStr != NULL) { | |
| FreePool (NameStr); | |
| } | |
| if (PathStr != NULL) { | |
| FreePool (PathStr); | |
| } | |
| if (AltIdStr != NULL) { | |
| FreePool (AltIdStr); | |
| } | |
| if (Result != NULL) { | |
| FreePool (Result); | |
| } | |
| return Status; | |
| } | |