X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=MdeModulePkg%2FUniversal%2FHiiDatabaseDxe%2FConfigRouting.c;h=d5ef60b7f5ed3eb223d96c60123df4b3bb319351;hb=f324bf4dbeda4d64b769bd005331e8f9404b692d;hp=ca85619113d8648029745e494bf53afcb9fbcd33;hpb=8d00a0f1955de7aa4b658009a36df5165d0a75be;p=mirror_edk2.git diff --git a/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigRouting.c b/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigRouting.c index ca85619113..d5ef60b7f5 100644 --- a/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigRouting.c +++ b/MdeModulePkg/Universal/HiiDatabaseDxe/ConfigRouting.c @@ -1,4 +1,5 @@ /** @file +Implementation of interfaces function for EFI_HII_CONFIG_ROUTING_PROTOCOL. Copyright (c) 2007 - 2008, Intel Corporation All rights reserved. This program and the accompanying materials @@ -9,21 +10,11 @@ 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. -Module Name: - - ConfigRouting.c - -Abstract: - - Implementation for EFI_HII_CONFIG_ROUTING_PROTOCOL. - -Revision History - - **/ #include "HiiDatabase.h" +extern HII_DATABASE_PRIVATE_DATA mPrivate; /** Calculate the number of Unicode characters of the incoming Configuration string, @@ -42,7 +33,7 @@ CalculateConfigStringLen ( IN EFI_STRING String ) { - UINTN Length; + EFI_STRING TmpPtr; // // "GUID=" should be the first element of incoming string. @@ -50,19 +41,16 @@ CalculateConfigStringLen ( ASSERT (String != NULL); ASSERT (StrnCmp (String, L"GUID=", StrLen (L"GUID=")) == 0); - Length = StrLen (L"GUID="); - String += Length; - // // The beginning of next / should be "&GUID=". // Will meet '\0' if there is only one /. - // - while (*String != 0 && StrnCmp (String, L"&GUID=", StrLen (L"&GUID=")) != 0) { - Length++; - String++; + // + TmpPtr = StrStr (String, L"&GUID="); + if (TmpPtr == NULL) { + return StrLen (String); } - return Length; + return (TmpPtr - String); } @@ -73,8 +61,9 @@ CalculateConfigStringLen ( This is a internal function. @param String UEFI configuration string - @param DevicePath binary of a UEFI device path. + @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 @@ -84,14 +73,19 @@ CalculateConfigStringLen ( EFI_STATUS GetDevicePath ( IN EFI_STRING String, - OUT UINT8 **DevicePath + OUT UINT8 **DevicePathData ) { - UINTN Length; - EFI_STRING PathHdr; - EFI_STRING DevicePathString; + UINTN Length; + EFI_STRING PathHdr; + UINT8 *DevicePathBuffer; + CHAR16 TemStr[2]; + UINTN Index; + UINT8 DigitUint8; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + - if (String == NULL || DevicePath == NULL) { + if (String == NULL || DevicePathData == NULL) { return EFI_INVALID_PARAMETER; } @@ -102,8 +96,13 @@ GetDevicePath ( 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; // @@ -112,33 +111,92 @@ GetDevicePath ( // of UEFI device path. // for (Length = 0; *String != 0 && *String != L'&'; String++, Length++); - DevicePathString = (EFI_STRING) AllocateZeroPool ((Length + 1) * sizeof (CHAR16)); - if (DevicePathString == NULL) { - return EFI_OUT_OF_RESOURCES; + // + // Check DevicePath Length + // + if (((Length + 1) / 2) < sizeof (EFI_DEVICE_PATH_PROTOCOL)) { + return EFI_NOT_FOUND; } - StrnCpy (DevicePathString, PathHdr, Length); - *(DevicePathString + Length) = 0; - + // // The data in is encoded as hex UNICODE %02x bytes in the same order // as the device path resides in RAM memory. // Translate the data into binary. // - Length /= 2; - *DevicePath = (UINT8 *) AllocateZeroPool (Length); - if (*DevicePath == NULL) { - FreePool (DevicePathString); + 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; +} - HexStringToBufInReverseOrder (*DevicePath, &Length, DevicePathString); +/** + Converts the unicode character of the string from uppercase to lowercase. + This is a internal function. - FreePool (DevicePathString); + @param Str String to be converted - return EFI_SUCCESS; +**/ +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. @@ -147,12 +205,16 @@ GetDevicePath ( @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. + 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. @@ -169,8 +231,11 @@ GenerateSubStr ( { UINTN Length; EFI_STRING Str; - EFI_STATUS Status; EFI_STRING StringHeader; + CHAR16 *TemString; + CHAR16 *TemName; + UINT8 *TemBuffer; + UINTN Index; ASSERT (String != NULL && SubStr != NULL); @@ -179,37 +244,61 @@ GenerateSubStr ( ASSERT (*SubStr != NULL); return ; } - + + // + // Header + Data + '&' + '\0' + // Length = StrLen (String) + BufferLen * 2 + 1 + 1; - Str = AllocateZeroPool (Length * sizeof (CHAR16)); + Str = AllocateZeroPool (Length * sizeof (CHAR16)); ASSERT (Str != NULL); StrCpy (Str, String); Length = (BufferLen * 2 + 1) * sizeof (CHAR16); - Status = EFI_SUCCESS; StringHeader = Str + StrLen (String); + TemString = (CHAR16 *) StringHeader; switch (Flag) { case 1: - Status = BufInReverseOrderToHexString (StringHeader, (UINT8 *) Buffer, BufferLen); + // + // 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: - Status = UnicodeToConfigString (StringHeader, &Length, (CHAR16 *) Buffer); + // + // 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: - Status = BufToHexString (StringHeader, &Length, (UINT8 *) Buffer, BufferLen); // - // Convert the uppercase to lowercase since is defined in lowercase format. + // Convert Buffer to Hex String // - ToLower (StringHeader); + TemBuffer = ((UINT8 *) Buffer) + BufferLen - 1; + for (Index = 0; Index < BufferLen; Index ++, TemBuffer --) { + TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemBuffer, 2); + } break; default: break; } - ASSERT_EFI_ERROR (Status); - StrCat (Str, L"&"); + // + // Convert the uppercase to lowercase since is defined in lowercase format. + // + StrCat (Str, L"&"); + HiiToLower (Str); *SubStr = Str; } @@ -243,6 +332,13 @@ OutputConfigBody ( 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) { @@ -267,47 +363,8 @@ OutputConfigBody ( *(Result + Length - 1) = 0; *ConfigBody = Result; return EFI_SUCCESS; - -} - - -/** - Adjusts the size of a previously allocated buffer. - - - @param OldPool A pointer to the buffer whose size is being adjusted. - @param OldSize The size of the current buffer. - @param NewSize The size of the new buffer. - - @return The new buffer allocated. - -**/ -VOID * -ReallocatePool ( - IN VOID *OldPool, - IN UINTN OldSize, - IN UINTN NewSize - ) -{ - VOID *NewPool; - - NewPool = NULL; - if (NewSize != 0) { - NewPool = AllocateZeroPool (NewSize); - } - - if (OldPool != NULL) { - if (NewPool != NULL) { - CopyMem (NewPool, OldPool, OldSize < NewSize ? OldSize : NewSize); - } - - gBS->FreePool (OldPool); - } - - return NewPool; } - /** Append a string to a multi-string format. @@ -341,101 +398,1795 @@ AppendToMultiString ( MultiStringSize = StrSize (*MultiString); // - // Enlarge the buffer each time when length exceeds MAX_STRING_LENGTH. + // 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 in format, i.e. the value of OFFSET + or WIDTH or VALUE. + ::= 'OFFSET='&'WIDTH='&'VALUE'= + + This is a internal function. + + @param StringPtr String in format and points to the + first character of . + @param Number The output value. Caller takes the responsibility + to free memory. + @param Len Length of the , in characters. + + @retval EFI_OUT_OF_RESOURCES Insufficient resources to store neccessary + structures. + @retval EFI_SUCCESS Value of 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 + format. The default value string + will be merged into it. + @param DefaultAltCfgResp Pointer to a null-terminated Unicode string in + 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 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 "&&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 BlockArray 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 PackageLenth, + 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; + + // + // Go through the form package to parse OpCode one by one. + // + IfrOffset = sizeof (EFI_HII_PACKAGE_HEADER); + while (IfrOffset < PackageLenth) { + 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: + // + // 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) { + break; + } + + // + // Get Offset/Width by Question header and OneOf Flags + // + VarOffset = IfrOrderedList->Question.VarStoreInfo.VarOffset; + VarWidth = IfrOrderedList->MaxContainers; + + // + // 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 = IfrOrderedList->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_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 = 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; + goto Done; + } + // + // Calculate Ordered list QuestionId width. + // + BlockData->Width = (UINT16) (BlockData->Width * VarWidth); + 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 + 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 + format string and return. + @param AltCfgResp Pointer to a null-terminated Unicode string in + 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 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 + // + 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 if exists + // Only format is supported by this help function. + // ::= &'OFFSET='&'WIDTH=' + // + 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 : "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 and a + // Null-terminator + // + DataExist = FALSE; + Length = StrLen (ConfigHdr) + 1; + + for (Link = VarStorageData->BlockEntry.ForwardLink; Link != &VarStorageData->BlockEntry; Link = Link->ForwardLink) { + // + // Add length for each Offset/Width pair + // + // ::= &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 + // + FullConfigRequest = AllocateZeroPool (Length * sizeof (CHAR16)); + if (FullConfigRequest == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + StringPtr = FullConfigRequest; + + // + // Start with + // + 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 + '\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 "&&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 (MultiStringSize + AppendStringSize > MAX_STRING_LENGTH || - MultiStringSize > MAX_STRING_LENGTH) { - *MultiString = (EFI_STRING) ReallocatePool ( - (VOID *) (*MultiString), - MultiStringSize, - MultiStringSize + AppendStringSize - ); + if (!DataExist) { + Status = EFI_SUCCESS; + goto Done; } // - // Append the incoming string + // Allocate buffer for the entire // - StrCat (*MultiString, AppendString); - - return EFI_SUCCESS; -} - - -/** - Get the value of in format, i.e. the value of OFFSET - or WIDTH or VALUE. - ::= 'OFFSET='&'WIDTH='&'VALUE'= - - This is a internal function. - - @param StringPtr String in format and points to the - first character of . - @param Number The output value. Caller takes the responsibility - to free memory. - @param Len Length of the , in characters. + DefaultAltCfgResp = AllocateZeroPool (Length * sizeof (CHAR16)); + if (DefaultAltCfgResp == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + StringPtr = DefaultAltCfgResp; - @retval EFI_OUT_OF_RESOURCES Insufficient resources to store neccessary - structures. - @retval EFI_SUCCESS Value of is outputted in Number - successfully. + // + // Start with + // + StrCpy (StringPtr, ConfigHdr); + StringPtr += StrLen (StringPtr); -**/ -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; + for (Link = DefaultIdArray->Entry.ForwardLink; Link != &DefaultIdArray->Entry; Link = Link->ForwardLink) { + DefaultId = BASE_CR (Link, IFR_DEFAULT_DATA, Entry); + // + // Add of the form "&&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 + // ::= 'OFFSET='&'WIDTH='&'VALUE'= + // + 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); - ASSERT (StringPtr != NULL && Number != NULL && Len != NULL); - ASSERT (*StringPtr != 0); + // + // 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; + } - Buf = NULL; +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); + } - TmpPtr = StringPtr; - while (*StringPtr != 0 && *StringPtr != L'&') { - StringPtr++; + FreePool (RequestBlockArray); } - *Len = StringPtr - TmpPtr; - Length = *Len + 1; - - Str = (EFI_STRING) AllocateZeroPool (Length * sizeof (EFI_STRING)); - if (Str == NULL) { - Status = EFI_OUT_OF_RESOURCES; - goto Exit; + + 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); } - CopyMem (Str, TmpPtr, *Len * sizeof (CHAR16)); - *(Str + *Len) = 0; - Length = (Length + 1) / 2; - Buf = (UINT8 *) AllocateZeroPool (Length); - if (Buf == NULL) { - Status = EFI_OUT_OF_RESOURCES; - goto Exit; + 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); } - - Status = HexStringToBuf (Buf, &Length, Str, NULL); - if (EFI_ERROR (Status)) { - goto Exit; + + // + // Free the allocated string + // + if (GuidStr != NULL) { + FreePool (GuidStr); + } + if (NameStr != NULL) { + FreePool (NameStr); + } + if (PathStr != NULL) { + FreePool (PathStr); + } + if (ConfigHdr != NULL) { + FreePool (ConfigHdr); } - *Number = Buf; - Status = EFI_SUCCESS; + // + // Free Pacakge data + // + if (HiiFormPackage != NULL) { + FreePool (HiiFormPackage); + } -Exit: - if (Str != NULL) { - FreePool (Str); + 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. @@ -489,25 +2240,20 @@ HiiConfigRoutingExtractConfig ( 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; - - // - // For size reduction, please define PcdSupportFullConfigRoutingProtocol - // as FALSE. But this renders the system to not 100% compliant with - // UEFI 2.1. Use this with caution. - // - if (!FeaturePcdGet (PcdSupportFullConfigRoutingProtocol)) { - return EFI_UNSUPPORTED; - } + BOOLEAN IfrDataParsedFlag; if (This == NULL || Progress == NULL || Results == NULL) { return EFI_INVALID_PARAMETER; @@ -521,6 +2267,12 @@ HiiConfigRoutingExtractConfig ( 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 should be @@ -558,7 +2310,8 @@ HiiConfigRoutingExtractConfig ( Length = CalculateConfigStringLen (StringPtr); ConfigRequest = AllocateCopyPool ((Length + 1) * sizeof (CHAR16), StringPtr); if (ConfigRequest == NULL) { - return EFI_OUT_OF_RESOURCES; + Status = EFI_OUT_OF_RESOURCES; + goto Done; } *(ConfigRequest + Length) = 0; @@ -567,20 +2320,20 @@ HiiConfigRoutingExtractConfig ( // Status = GetDevicePath (ConfigRequest, (UINT8 **) &DevicePath); if (EFI_ERROR (Status)) { - FreePool (ConfigRequest); - return Status; + goto Done; } // // Find driver which matches the routing data. // - DriverHandle = NULL; + 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 ( @@ -589,21 +2342,58 @@ HiiConfigRoutingExtractConfig ( GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) CurrentDevicePath) ) == 0) { DriverHandle = Database->DriverHandle; + HiiHandle = Database->Handle; break; } } } - - FreePool (DevicePath); - + + // + // 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)) { // - // Routing data does not match any known driver. - // Set Progress to the 'G' in "GUID" of the routing header. + // Get the full request string from IFR when HiiPackage is registered to HiiHandle // - *Progress = StringPtr; - FreePool (ConfigRequest); - return EFI_NOT_FOUND; + IfrDataParsedFlag = TRUE; + Status = GetFullStringFromHiiFormPackages (Database, DevicePath, &ConfigRequest, &DefaultResults, &AccessProgress); + if (EFI_ERROR (Status)) { + // + // AccessProgress indicates the parsing progress on . + // Map it to the progress on 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; + } } // @@ -628,8 +2418,7 @@ HiiConfigRoutingExtractConfig ( // Map it to the progress on then return it. // *Progress = StrStr (StringPtr, AccessProgress); - FreePool (ConfigRequest); - return Status; + goto Done; } // @@ -638,6 +2427,25 @@ HiiConfigRoutingExtractConfig ( // 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); @@ -647,7 +2455,7 @@ HiiConfigRoutingExtractConfig ( ASSERT_EFI_ERROR (Status); FirstElement = FALSE; - + FreePool (AccessResults); AccessResults = NULL; FreePool (ConfigRequest); @@ -663,11 +2471,31 @@ HiiConfigRoutingExtractConfig ( } StringPtr++; - } - return EFI_SUCCESS; +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; } @@ -702,25 +2530,30 @@ HiiConfigRoutingExportConfig ( { EFI_STATUS Status; EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess; - EFI_STRING AccessResults; + EFI_STRING AccessResults; + EFI_STRING Progress; + EFI_STRING StringPtr; + EFI_STRING ConfigRequest; UINTN Index; EFI_HANDLE *ConfigAccessHandles; UINTN NumberConfigAccessHandles; BOOLEAN FirstElement; - - // - // For size reduction, please define PcdSupportFullConfigRoutingProtocol - // as FALSE. But this renders the system to not 100% compliant with - // UEFI 2.1. Use this with caution. - // - if (!FeaturePcdGet (PcdSupportFullConfigRoutingProtocol)) { - return EFI_UNSUPPORTED; - } + 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. @@ -754,13 +2587,93 @@ HiiConfigRoutingExportConfig ( 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, - 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 to a . There is a '&' // which seperates the first and the following ones. @@ -779,7 +2692,7 @@ HiiConfigRoutingExportConfig ( AccessResults = NULL; } } - gBS->FreePool (ConfigAccessHandles); + FreePool (ConfigAccessHandles); return EFI_SUCCESS; } @@ -824,6 +2737,7 @@ HiiConfigRoutingRouteConfig ( UINTN Length; EFI_STATUS Status; EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; LIST_ENTRY *Link; HII_DATABASE_RECORD *Database; UINT8 *DevicePathPkg; @@ -832,15 +2746,6 @@ HiiConfigRoutingRouteConfig ( EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess; EFI_STRING AccessProgress; - // - // For size reduction, please define PcdSupportFullConfigRoutingProtocol - // as FALSE. But this renders the system to not 100% compliant with - // UEFI 2.1. Use this with caution. - // - if (!FeaturePcdGet (PcdSupportFullConfigRoutingProtocol)) { - return EFI_UNSUPPORTED; - } - if (This == NULL || Progress == NULL) { return EFI_INVALID_PARAMETER; } @@ -898,7 +2803,7 @@ HiiConfigRoutingRouteConfig ( // // Find driver which matches the routing data. // - DriverHandle = NULL; + DriverHandle = NULL; for (Link = Private->DatabaseList.ForwardLink; Link != &Private->DatabaseList; Link = Link->ForwardLink @@ -918,18 +2823,30 @@ HiiConfigRoutingRouteConfig ( } } - FreePool (DevicePath); - + // + // Try to find driver handle by device path. + // if (DriverHandle == NULL) { - // - // Routing data does not match any known driver. - // Set Progress to the 'G' in "GUID" of the routing header. - // - *Progress = StringPtr; - FreePool (ConfigResp); - return EFI_NOT_FOUND; + 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 // @@ -990,7 +2907,7 @@ HiiConfigRoutingRouteConfig ( @param BlockSize Length in bytes of Block. @param Config Filled-in configuration string. String allocated by the function. Returned only if call is - successful. + successful. It is 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 @@ -1034,6 +2951,9 @@ HiiBlockToConfig ( 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; @@ -1074,7 +2994,7 @@ HiiBlockToConfig ( StringPtr++; } if (*StringPtr == 0) { - *Progress = StringPtr; + *Progress = StringPtr - 1; Status = EFI_INVALID_PARAMETER; goto Exit; } @@ -1083,7 +3003,7 @@ HiiBlockToConfig ( StringPtr++; } if (*StringPtr == 0) { - *Progress = StringPtr; + *Progress = StringPtr - 1; Status = EFI_INVALID_PARAMETER; goto Exit; } @@ -1182,10 +3102,12 @@ HiiBlockToConfig ( Status = EFI_OUT_OF_RESOURCES; goto Exit; } - - Status = BufToHexString (ValueStr, &Length, Value, Width); - ASSERT_EFI_ERROR (Status); - ToLower (ValueStr); + + 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; @@ -1230,19 +3152,23 @@ HiiBlockToConfig ( 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) { + if (ConfigElement != NULL) { FreePool (ConfigElement); } @@ -1258,7 +3184,7 @@ Exit: @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL instance. @param ConfigResp A null-terminated Unicode string in - format. + format. It can be ConfigAltResp format string. @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 @@ -1369,7 +3295,7 @@ HiiConfigToBlock ( // Get Offset // Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length); - if (Status == EFI_OUT_OF_RESOURCES) { + if (EFI_ERROR (Status)) { *Progress = ConfigResp; goto Exit; } @@ -1417,7 +3343,7 @@ HiiConfigToBlock ( // Get Value // Status = GetValueOfNumber (StringPtr, &Value, &Length); - if (Status == EFI_OUT_OF_RESOURCES) { + if (EFI_ERROR (Status)) { *Progress = ConfigResp; goto Exit; } @@ -1452,14 +3378,17 @@ HiiConfigToBlock ( StringPtr++; } - - if (*StringPtr != 0) { + + // + // 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; + *Progress = StringPtr + StrLen (StringPtr); return EFI_SUCCESS; Exit: @@ -1478,7 +3407,7 @@ Exit: @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL instance. @param Configuration A null-terminated Unicode string in - format. + format. It is 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, @@ -1500,7 +3429,7 @@ Exit: @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. + the call was successful. It is format. @retval EFI_SUCCESS The request succeeded. The requested data was extracted and placed in the newly allocated @@ -1538,15 +3467,6 @@ HiiGetAltCfg ( BOOLEAN NameFlag; BOOLEAN PathFlag; - // - // For size reduction, please define PcdSupportFullConfigRoutingProtocol - // as FALSE. But this renders the system to not 100% compliant with - // UEFI 2.1. Use this with caution. - // - if (!FeaturePcdGet (PcdSupportFullConfigRoutingProtocol)) { - return EFI_UNSUPPORTED; - } - HdrStart = NULL; HdrEnd = NULL; GuidStr = NULL; @@ -1656,9 +3576,10 @@ HiiGetAltCfg ( Status = EFI_NOT_FOUND; goto Exit; } + StringPtr ++; } PathFlag = TRUE; - HdrEnd = ++StringPtr; + HdrEnd = StringPtr; } } @@ -1681,7 +3602,11 @@ HiiGetAltCfg ( NameFlag = FALSE; PathFlag = FALSE; } else { - Status = OutputConfigBody (StringPtr, &Result); + // + // Skip AltIdStr and & + // + StringPtr = StringPtr + StrLen (AltIdStr); + Status = OutputConfigBody (StringPtr, &Result); goto Exit; } } @@ -1690,12 +3615,12 @@ HiiGetAltCfg ( Status = EFI_NOT_FOUND; Exit: - - if (!EFI_ERROR (Status)) { + *AltCfgResp = NULL; + if (!EFI_ERROR (Status) && (Result != NULL)) { // // Copy the and // - Length = HdrEnd - HdrStart + StrLen (Result); + Length = HdrEnd - HdrStart + StrLen (Result) + 1; *AltCfgResp = AllocateZeroPool (Length * sizeof (CHAR16)); if (*AltCfgResp == NULL) { Status = EFI_OUT_OF_RESOURCES;