| /** @file | |
| Implementation of interfaces function for EFI_HII_CONFIG_ROUTING_PROTOCOL. | |
| Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR> | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| **/ | |
| #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 necessary 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); | |
| StrCpyS (Str, Length, String); | |
| 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++) { | |
| UnicodeValueToStringS ( | |
| TemString, | |
| sizeof (CHAR16) * (Length - StrnLenS (Str, Length)), | |
| PREFIX_ZERO | RADIX_HEX, | |
| *TemBuffer, | |
| 2 | |
| ); | |
| TemString += StrnLenS (TemString, Length - StrnLenS (Str, Length)); | |
| } | |
| 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++) { | |
| UnicodeValueToStringS ( | |
| TemString, | |
| sizeof (CHAR16) * (Length - StrnLenS (Str, Length)), | |
| PREFIX_ZERO | RADIX_HEX, | |
| *TemName, | |
| 4 | |
| ); | |
| TemString += StrnLenS (TemString, Length - StrnLenS (Str, Length)); | |
| } | |
| break; | |
| case 3: | |
| // | |
| // Convert Buffer to Hex String | |
| // | |
| TemBuffer = ((UINT8 *)Buffer) + BufferLen - 1; | |
| for (Index = 0; Index < BufferLen; Index++, TemBuffer--) { | |
| UnicodeValueToStringS ( | |
| TemString, | |
| sizeof (CHAR16) * (Length - StrnLenS (Str, Length)), | |
| PREFIX_ZERO | RADIX_HEX, | |
| *TemBuffer, | |
| 2 | |
| ); | |
| TemString += StrnLenS (TemString, Length - StrnLenS (Str, Length)); | |
| } | |
| break; | |
| default: | |
| break; | |
| } | |
| // | |
| // Convert the uppercase to lowercase since <HexAf> is defined in lowercase format. | |
| // | |
| StrCatS (Str, Length, 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; | |
| if (Length == 0) { | |
| return EFI_NOT_FOUND; | |
| } | |
| 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; | |
| UINTN MaxLen; | |
| if ((MultiString == NULL) || (*MultiString == NULL) || (AppendString == NULL)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| AppendStringSize = StrSize (AppendString); | |
| MultiStringSize = StrSize (*MultiString); | |
| MaxLen = MAX_STRING_LENGTH / sizeof (CHAR16); | |
| // | |
| // 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) | |
| ); | |
| MaxLen = (MultiStringSize + AppendStringSize) / sizeof (CHAR16); | |
| ASSERT (*MultiString != NULL); | |
| } | |
| // | |
| // Append the incoming string | |
| // | |
| StrCatS (*MultiString, MaxLen, 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 necessary | |
| 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]; | |
| if ((StringPtr == NULL) || (*StringPtr == L'\0') || (Number == NULL) || (Len == NULL)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| 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; | |
| } | |
| /** | |
| To find the BlockName in the string with same value. | |
| @param String Pointer to a Null-terminated Unicode string. | |
| @param BlockName Pointer to a Null-terminated Unicode string to search for. | |
| @param Buffer Pointer to the value correspond to the BlockName. | |
| @param Found The Block whether has been found. | |
| @param BufferLen The length of the buffer. | |
| @retval EFI_OUT_OF_RESOURCES Insufficient resources to store necessary structures. | |
| @retval EFI_SUCCESS The function finishes successfully. | |
| **/ | |
| EFI_STATUS | |
| FindSameBlockElement ( | |
| IN EFI_STRING String, | |
| IN EFI_STRING BlockName, | |
| IN UINT8 *Buffer, | |
| OUT BOOLEAN *Found, | |
| IN UINTN BufferLen | |
| ) | |
| { | |
| EFI_STRING BlockPtr; | |
| UINTN Length; | |
| UINT8 *TempBuffer; | |
| EFI_STATUS Status; | |
| TempBuffer = NULL; | |
| *Found = FALSE; | |
| BlockPtr = StrStr (String, BlockName); | |
| while (BlockPtr != NULL) { | |
| BlockPtr += StrLen (BlockName); | |
| Status = GetValueOfNumber (BlockPtr, &TempBuffer, &Length); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| ASSERT (TempBuffer != NULL); | |
| if ((BufferLen == Length) && (0 == CompareMem (Buffer, TempBuffer, Length))) { | |
| *Found = TRUE; | |
| FreePool (TempBuffer); | |
| TempBuffer = NULL; | |
| return EFI_SUCCESS; | |
| } else { | |
| FreePool (TempBuffer); | |
| TempBuffer = NULL; | |
| BlockPtr = StrStr (BlockPtr + 1, BlockName); | |
| } | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Compare the <AltResp> in ConfigAltResp and DefaultAltCfgResp, if the <AltResp> | |
| in DefaultAltCfgResp but not in ConfigAltResp,add it to the ConfigAltResp. | |
| @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. | |
| @param ConfigAltResp Pointer to a null-terminated Unicode string in | |
| <ConfigAltResp> format. | |
| @param AltConfigHdr Pointer to a Unicode string in <AltConfigHdr> format. | |
| @param ConfigAltRespChanged Whether the ConfigAltResp has been changed. | |
| @retval EFI_OUT_OF_RESOURCES Insufficient resources to store necessary structures. | |
| @retval EFI_SUCCESS The function finishes successfully. | |
| **/ | |
| EFI_STATUS | |
| CompareBlockElementDefault ( | |
| IN EFI_STRING DefaultAltCfgResp, | |
| IN OUT EFI_STRING *ConfigAltResp, | |
| IN EFI_STRING AltConfigHdr, | |
| IN OUT BOOLEAN *ConfigAltRespChanged | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_STRING BlockPtr; | |
| EFI_STRING BlockPtrStart; | |
| EFI_STRING StringPtr; | |
| EFI_STRING AppendString; | |
| EFI_STRING AltConfigHdrPtr; | |
| UINT8 *TempBuffer; | |
| UINTN OffsetLength; | |
| UINTN AppendSize; | |
| UINTN TotalSize; | |
| BOOLEAN FoundOffset; | |
| AppendString = NULL; | |
| TempBuffer = NULL; | |
| // | |
| // Make BlockPtr point to the first <BlockConfig> with AltConfigHdr in DefaultAltCfgResp. | |
| // | |
| AltConfigHdrPtr = StrStr (DefaultAltCfgResp, AltConfigHdr); | |
| ASSERT (AltConfigHdrPtr != NULL); | |
| BlockPtr = StrStr (AltConfigHdrPtr, L"&OFFSET="); | |
| // | |
| // Make StringPtr point to the AltConfigHdr in ConfigAltResp. | |
| // | |
| StringPtr = StrStr (*ConfigAltResp, AltConfigHdr); | |
| ASSERT (StringPtr != NULL); | |
| while (BlockPtr != NULL) { | |
| // | |
| // Find the "&OFFSET=<Number>" block and get the value of the Number with AltConfigHdr in DefaultAltCfgResp. | |
| // | |
| BlockPtrStart = BlockPtr; | |
| BlockPtr += StrLen (L"&OFFSET="); | |
| Status = GetValueOfNumber (BlockPtr, &TempBuffer, &OffsetLength); | |
| if (EFI_ERROR (Status)) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto Exit; | |
| } | |
| // | |
| // To find the same "&OFFSET=<Number>" block in ConfigAltResp. | |
| // | |
| Status = FindSameBlockElement (StringPtr, L"&OFFSET=", TempBuffer, &FoundOffset, OffsetLength); | |
| if (TempBuffer != NULL) { | |
| FreePool (TempBuffer); | |
| TempBuffer = NULL; | |
| } | |
| if (EFI_ERROR (Status)) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto Exit; | |
| } | |
| if (!FoundOffset) { | |
| // | |
| // Don't find the same "&OFFSET=<Number>" block in ConfigAltResp. | |
| // Calculate the size of <BlockConfig>. | |
| // <BlockConfig>::='OFFSET='<Number>'&WIDTH='<Number>'&VALUE='<Number>. | |
| // | |
| BlockPtr = StrStr (BlockPtr + 1, L"&OFFSET="); | |
| if (BlockPtr != NULL) { | |
| AppendSize = (BlockPtr - BlockPtrStart) * sizeof (CHAR16); | |
| } else { | |
| AppendSize = StrSize (BlockPtrStart); | |
| } | |
| // | |
| // Copy the <BlockConfig> to AppendString. | |
| // | |
| if (AppendString == NULL) { | |
| AppendString = (EFI_STRING)AllocateZeroPool (AppendSize + sizeof (CHAR16)); | |
| StrnCatS (AppendString, AppendSize / sizeof (CHAR16) + 1, BlockPtrStart, AppendSize / sizeof (CHAR16)); | |
| } else { | |
| TotalSize = StrSize (AppendString) + AppendSize + sizeof (CHAR16); | |
| AppendString = (EFI_STRING)ReallocatePool ( | |
| StrSize (AppendString), | |
| TotalSize, | |
| AppendString | |
| ); | |
| if (AppendString == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto Exit; | |
| } | |
| StrnCatS (AppendString, TotalSize / sizeof (CHAR16), BlockPtrStart, AppendSize / sizeof (CHAR16)); | |
| } | |
| } else { | |
| // | |
| // To find next "&OFFSET=<Number>" block with AltConfigHdr in DefaultAltCfgResp. | |
| // | |
| BlockPtr = StrStr (BlockPtr + 1, L"&OFFSET="); | |
| } | |
| } | |
| if (AppendString != NULL) { | |
| // | |
| // Reallocate ConfigAltResp to copy the AppendString. | |
| // | |
| TotalSize = StrSize (*ConfigAltResp) + StrSize (AppendString) + sizeof (CHAR16); | |
| *ConfigAltResp = (EFI_STRING)ReallocatePool ( | |
| StrSize (*ConfigAltResp), | |
| TotalSize, | |
| *ConfigAltResp | |
| ); | |
| if (*ConfigAltResp == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto Exit; | |
| } | |
| StrCatS (*ConfigAltResp, TotalSize / sizeof (CHAR16), AppendString); | |
| *ConfigAltRespChanged = TRUE; | |
| } | |
| Status = EFI_SUCCESS; | |
| Exit: | |
| if (AppendString != NULL) { | |
| FreePool (AppendString); | |
| } | |
| return Status; | |
| } | |
| /** | |
| Compare the <AltResp> in ConfigAltResp and DefaultAltCfgResp, if the <AltResp> | |
| in DefaultAltCfgResp but not in ConfigAltResp,add it to the ConfigAltResp. | |
| @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. | |
| @param ConfigAltResp Pointer to a null-terminated Unicode string in | |
| <ConfigAltResp> format. | |
| @param AltConfigHdr Pointer to a Unicode string in <AltConfigHdr> format. | |
| @param ConfigAltRespChanged Whether the ConfigAltResp has been changed. | |
| @retval EFI_OUT_OF_RESOURCES Insufficient resources to store necessary structures. | |
| @retval EFI_SUCCESS The function finishes successfully. | |
| **/ | |
| EFI_STATUS | |
| CompareNameElementDefault ( | |
| IN EFI_STRING DefaultAltCfgResp, | |
| IN OUT EFI_STRING *ConfigAltResp, | |
| IN EFI_STRING AltConfigHdr, | |
| IN OUT BOOLEAN *ConfigAltRespChanged | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_STRING NvConfigPtr; | |
| EFI_STRING NvConfigStart; | |
| EFI_STRING NvConfigValuePtr; | |
| EFI_STRING StringPtr; | |
| EFI_STRING NvConfigExist; | |
| EFI_STRING AppendString; | |
| CHAR16 TempChar; | |
| UINTN AppendSize; | |
| UINTN TotalSize; | |
| AppendString = NULL; | |
| NvConfigExist = NULL; | |
| // | |
| // Make NvConfigPtr point to the first <NvConfig> with AltConfigHdr in DefaultAltCfgResp. | |
| // | |
| NvConfigPtr = StrStr (DefaultAltCfgResp, AltConfigHdr); | |
| ASSERT (NvConfigPtr != NULL); | |
| NvConfigPtr = StrStr (NvConfigPtr + StrLen (AltConfigHdr), L"&"); | |
| // | |
| // Make StringPtr point to the first <NvConfig> with AltConfigHdr in ConfigAltResp. | |
| // | |
| StringPtr = StrStr (*ConfigAltResp, AltConfigHdr); | |
| ASSERT (StringPtr != NULL); | |
| StringPtr = StrStr (StringPtr + StrLen (AltConfigHdr), L"&"); | |
| ASSERT (StringPtr != NULL); | |
| while (NvConfigPtr != NULL) { | |
| // | |
| // <NvConfig> ::= <Label>'='<String> | <Label>'='<Number>. | |
| // Get the <Label> with AltConfigHdr in DefaultAltCfgResp. | |
| // | |
| NvConfigStart = NvConfigPtr; | |
| NvConfigValuePtr = StrStr (NvConfigPtr + 1, L"="); | |
| ASSERT (NvConfigValuePtr != NULL); | |
| TempChar = *NvConfigValuePtr; | |
| *NvConfigValuePtr = L'\0'; | |
| // | |
| // Get the <Label> with AltConfigHdr in ConfigAltResp. | |
| // | |
| NvConfigExist = StrStr (StringPtr, NvConfigPtr); | |
| if (NvConfigExist == NULL) { | |
| // | |
| // Don't find same <Label> in ConfigAltResp. | |
| // Calculate the size of <NvConfig>. | |
| // | |
| *NvConfigValuePtr = TempChar; | |
| NvConfigPtr = StrStr (NvConfigPtr + 1, L"&"); | |
| if (NvConfigPtr != NULL) { | |
| AppendSize = (NvConfigPtr - NvConfigStart) * sizeof (CHAR16); | |
| } else { | |
| AppendSize = StrSize (NvConfigStart); | |
| } | |
| // | |
| // Copy the <NvConfig> to AppendString. | |
| // | |
| if (AppendString == NULL) { | |
| AppendString = (EFI_STRING)AllocateZeroPool (AppendSize + sizeof (CHAR16)); | |
| StrnCatS (AppendString, AppendSize / sizeof (CHAR16) + 1, NvConfigStart, AppendSize / sizeof (CHAR16)); | |
| } else { | |
| TotalSize = StrSize (AppendString) + AppendSize + sizeof (CHAR16); | |
| AppendString = (EFI_STRING)ReallocatePool ( | |
| StrSize (AppendString), | |
| TotalSize, | |
| AppendString | |
| ); | |
| if (AppendString == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto Exit; | |
| } | |
| StrnCatS (AppendString, TotalSize / sizeof (CHAR16), NvConfigStart, AppendSize / sizeof (CHAR16)); | |
| } | |
| } else { | |
| // | |
| // To find next <Label> in DefaultAltCfgResp. | |
| // | |
| *NvConfigValuePtr = TempChar; | |
| NvConfigPtr = StrStr (NvConfigPtr + 1, L"&"); | |
| } | |
| } | |
| if (AppendString != NULL) { | |
| // | |
| // Reallocate ConfigAltResp to copy the AppendString. | |
| // | |
| TotalSize = StrSize (*ConfigAltResp) + StrSize (AppendString) + sizeof (CHAR16); | |
| *ConfigAltResp = (EFI_STRING)ReallocatePool ( | |
| StrSize (*ConfigAltResp), | |
| StrSize (*ConfigAltResp) + StrSize (AppendString) + sizeof (CHAR16), | |
| *ConfigAltResp | |
| ); | |
| if (*ConfigAltResp == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto Exit; | |
| } | |
| StrCatS (*ConfigAltResp, TotalSize / sizeof (CHAR16), AppendString); | |
| *ConfigAltRespChanged = TRUE; | |
| } | |
| Status = EFI_SUCCESS; | |
| Exit: | |
| if (AppendString != NULL) { | |
| FreePool (AppendString); | |
| } | |
| return Status; | |
| } | |
| /** | |
| Compare the <AltResp> in AltCfgResp and DefaultAltCfgResp, if the <AltResp> | |
| in DefaultAltCfgResp but not in AltCfgResp,add it to the AltCfgResp. | |
| @param AltCfgResp Pointer to a null-terminated Unicode string in | |
| <ConfigAltResp> format. | |
| @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. | |
| @param AltConfigHdr Pointer to a Unicode string in <AltConfigHdr> format. | |
| @retval EFI_OUT_OF_RESOURCES Insufficient resources to store necessary | |
| structures. | |
| @retval EFI_SUCCESS The function finishes successfully. | |
| **/ | |
| EFI_STATUS | |
| CompareAndMergeDefaultString ( | |
| IN OUT EFI_STRING *AltCfgResp, | |
| IN EFI_STRING DefaultAltCfgResp, | |
| IN EFI_STRING AltConfigHdr | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_STRING AltCfgRespBackup; | |
| EFI_STRING AltConfigHdrPtr; | |
| EFI_STRING AltConfigHdrPtrNext; | |
| EFI_STRING ConfigAltResp; | |
| EFI_STRING StringPtr; | |
| EFI_STRING StringPtrNext; | |
| EFI_STRING BlockPtr; | |
| UINTN ReallocateSize; | |
| CHAR16 TempChar; | |
| CHAR16 TempCharA; | |
| BOOLEAN ConfigAltRespChanged; | |
| Status = EFI_OUT_OF_RESOURCES; | |
| BlockPtr = NULL; | |
| AltConfigHdrPtrNext = NULL; | |
| StringPtrNext = NULL; | |
| ConfigAltResp = NULL; | |
| AltCfgRespBackup = NULL; | |
| TempChar = L'\0'; | |
| TempCharA = L'\0'; | |
| ConfigAltRespChanged = FALSE; | |
| // | |
| // To find the <AltResp> with AltConfigHdr in DefaultAltCfgResp, ignore other <AltResp> which follow it. | |
| // | |
| AltConfigHdrPtr = StrStr (DefaultAltCfgResp, AltConfigHdr); | |
| ASSERT (AltConfigHdrPtr != NULL); | |
| AltConfigHdrPtrNext = StrStr (AltConfigHdrPtr + 1, L"&GUID"); | |
| if (AltConfigHdrPtrNext != NULL) { | |
| TempChar = *AltConfigHdrPtrNext; | |
| *AltConfigHdrPtrNext = L'\0'; | |
| } | |
| // | |
| // To find the <AltResp> with AltConfigHdr in AltCfgResp, ignore other <AltResp> which follow it. | |
| // | |
| StringPtr = StrStr (*AltCfgResp, AltConfigHdr); | |
| ASSERT (StringPtr != NULL); | |
| StringPtrNext = StrStr (StringPtr + 1, L"&GUID"); | |
| if (StringPtrNext != NULL) { | |
| TempCharA = *StringPtrNext; | |
| *StringPtrNext = L'\0'; | |
| } | |
| // | |
| // Copy the content of <ConfigAltResp> which contain current AltConfigHdr in AltCfgResp. | |
| // | |
| ConfigAltResp = AllocateCopyPool (StrSize (*AltCfgResp), *AltCfgResp); | |
| if (ConfigAltResp == NULL) { | |
| goto Exit; | |
| } | |
| // | |
| // To find the <ConfigBody> with AltConfigHdr in DefaultAltCfgResp. | |
| // | |
| BlockPtr = StrStr (AltConfigHdrPtr, L"&OFFSET="); | |
| if (BlockPtr != NULL) { | |
| // | |
| // <BlockConfig>::='OFFSET='<Number>'&WIDTH='<Number>'&VALUE='<Number> style. | |
| // Call function CompareBlockElementDefault to compare the <BlockConfig> in DefaultAltCfgResp and ConfigAltResp. | |
| // The ConfigAltResp which may contain the new <BlockConfig> get from DefaultAltCfgResp. | |
| // | |
| Status = CompareBlockElementDefault (DefaultAltCfgResp, &ConfigAltResp, AltConfigHdr, &ConfigAltRespChanged); | |
| if (EFI_ERROR (Status)) { | |
| goto Exit; | |
| } | |
| } else { | |
| // | |
| // <NvConfig> ::= <Label>'='<String> | <Label>'='<Number> style. | |
| // Call function CompareNameElementDefault to compare the <NvConfig> in DefaultAltCfgResp and ConfigAltResp. | |
| // The ConfigAltResp which may contain the new <NvConfig> get from DefaultAltCfgResp. | |
| // | |
| Status = CompareNameElementDefault (DefaultAltCfgResp, &ConfigAltResp, AltConfigHdr, &ConfigAltRespChanged); | |
| if (EFI_ERROR (Status)) { | |
| goto Exit; | |
| } | |
| } | |
| // | |
| // Restore the AltCfgResp. | |
| // | |
| if (StringPtrNext != NULL) { | |
| *StringPtrNext = TempCharA; | |
| } | |
| // | |
| // If the ConfigAltResp has no change,no need to update the content in AltCfgResp. | |
| // | |
| if (!ConfigAltRespChanged) { | |
| Status = EFI_SUCCESS; | |
| goto Exit; | |
| } | |
| // | |
| // ConfigAltResp has been changed, need to update the content in AltCfgResp. | |
| // | |
| if (StringPtrNext != NULL) { | |
| ReallocateSize = StrSize (ConfigAltResp) + StrSize (StringPtrNext) + sizeof (CHAR16); | |
| } else { | |
| ReallocateSize = StrSize (ConfigAltResp) + sizeof (CHAR16); | |
| } | |
| AltCfgRespBackup = (EFI_STRING)AllocateZeroPool (ReallocateSize); | |
| if (AltCfgRespBackup == NULL) { | |
| goto Exit; | |
| } | |
| StrCatS (AltCfgRespBackup, ReallocateSize / sizeof (CHAR16), ConfigAltResp); | |
| if (StringPtrNext != NULL) { | |
| StrCatS (AltCfgRespBackup, ReallocateSize / sizeof (CHAR16), StringPtrNext); | |
| } | |
| FreePool (*AltCfgResp); | |
| *AltCfgResp = AltCfgRespBackup; | |
| Status = EFI_SUCCESS; | |
| Exit: | |
| if (ConfigAltResp != NULL) { | |
| FreePool (ConfigAltResp); | |
| } | |
| // | |
| // Restore the DefaultAltCfgResp. | |
| // | |
| if ( AltConfigHdrPtrNext != NULL) { | |
| *AltConfigHdrPtrNext = TempChar; | |
| AltConfigHdrPtrNext = NULL; | |
| } | |
| 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; | |
| UINTN MaxLen; | |
| UINTN TotalSize; | |
| if (*AltCfgResp == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // Get the request 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 | | |
| // | |
| MaxLen = 1 + HeaderLength + 8 + 4 + 1; | |
| AltConfigHdr = AllocateZeroPool (MaxLen * sizeof (CHAR16)); | |
| if (AltConfigHdr == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| StrCpyS (AltConfigHdr, MaxLen, L"&"); | |
| StrnCatS (AltConfigHdr, MaxLen, *AltCfgResp, HeaderLength); | |
| StrCatS (AltConfigHdr, MaxLen, L"&ALTCFG="); | |
| HeaderLength = StrLen (AltConfigHdr); | |
| StringPtrDefault = StrStr (DefaultAltCfgResp, AltConfigHdr); | |
| while (StringPtrDefault != NULL) { | |
| // | |
| // Get AltCfg Name | |
| // | |
| StrnCatS (AltConfigHdr, MaxLen, 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. | |
| // | |
| TotalSize = SizeAltCfgResp + StrSize (StringPtrDefault); | |
| *AltCfgResp = (EFI_STRING)ReallocatePool ( | |
| SizeAltCfgResp, | |
| TotalSize, | |
| (VOID *)(*AltCfgResp) | |
| ); | |
| if (*AltCfgResp == NULL) { | |
| FreePool (AltConfigHdr); | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| StrCatS (*AltCfgResp, TotalSize / sizeof (CHAR16), StringPtrDefault); | |
| break; | |
| } else { | |
| TempChar = *StringPtrEnd; | |
| *StringPtrEnd = L'\0'; | |
| TotalSize = SizeAltCfgResp + StrSize (StringPtrDefault); | |
| *AltCfgResp = (EFI_STRING)ReallocatePool ( | |
| SizeAltCfgResp, | |
| TotalSize, | |
| (VOID *)(*AltCfgResp) | |
| ); | |
| if (*AltCfgResp == NULL) { | |
| FreePool (AltConfigHdr); | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| StrCatS (*AltCfgResp, TotalSize / sizeof (CHAR16), StringPtrDefault); | |
| *StringPtrEnd = TempChar; | |
| } | |
| } else { | |
| // | |
| // The AltCfgResp contains <AltCfgResp>. | |
| // If the <ConfigElement> in <AltCfgResp> in the DefaultAltCfgResp but not in the | |
| // related <AltCfgResp> in AltCfgResp, merge it to AltCfgResp. else no need to merge. | |
| // | |
| CompareAndMergeDefaultString (AltCfgResp, DefaultAltCfgResp, AltConfigHdr); | |
| } | |
| // | |
| // Find next AltCfg String | |
| // | |
| *(AltConfigHdr + HeaderLength) = L'\0'; | |
| StringPtrDefault = StrStr (StringPtrDefault + 1, AltConfigHdr); | |
| } | |
| FreePool (AltConfigHdr); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| 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; | |
| LIST_ENTRY *DefaultLink; | |
| DefaultLink = &BlockData->DefaultValueEntry; | |
| for (Link = DefaultLink->ForwardLink; Link != DefaultLink; Link = Link->ForwardLink) { | |
| DefaultValueArray = BASE_CR (Link, IFR_DEFAULT_DATA, Entry); | |
| if (DefaultValueArray->DefaultId == DefaultValueData->DefaultId) { | |
| // | |
| // DEFAULT_VALUE_FROM_OPCODE has high priority, DEFAULT_VALUE_FROM_DEFAULT has low priority. | |
| // When default types are DEFAULT_VALUE_FROM_OTHER_DEFAULT, the default value can be overrode. | |
| // | |
| if ((DefaultValueData->Type > DefaultValueArray->Type) || ((DefaultValueData->Type == DefaultValueArray->Type) && (DefaultValueData->Type == DefaultValueFromOtherDefault))) { | |
| // | |
| // Update the default value array in BlockData. | |
| // | |
| CopyMem (&DefaultValueArray->Value, &DefaultValueData->Value, sizeof (EFI_IFR_TYPE_VALUE)); | |
| DefaultValueArray->Type = DefaultValueData->Type; | |
| DefaultValueArray->Cleaned = DefaultValueData->Cleaned; | |
| } | |
| return; | |
| } | |
| } | |
| // | |
| // Insert new default value data in tail. | |
| // | |
| DefaultValueArray = AllocateZeroPool (sizeof (IFR_DEFAULT_DATA)); | |
| ASSERT (DefaultValueArray != NULL); | |
| CopyMem (DefaultValueArray, DefaultValueData, sizeof (IFR_DEFAULT_DATA)); | |
| InsertTailList (Link, &DefaultValueArray->Entry); | |
| } | |
| /** | |
| 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; | |
| if (BlockSingleData->Name != NULL) { | |
| InsertTailList (BlockLink, &BlockSingleData->Entry); | |
| return; | |
| } | |
| // | |
| // 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) || (BlockSingleData->IsBitVar && (BlockArray->Width == BlockSingleData->Width))) { | |
| // | |
| // Insert this block data in the front of block array | |
| // | |
| InsertTailList (Link, &BlockSingleData->Entry); | |
| return; | |
| } | |
| if ((!BlockSingleData->IsBitVar) && (BlockArray->Width == BlockSingleData->Width)) { | |
| // | |
| // The same block array has been added. | |
| // | |
| if (BlockSingleData != BlockArray) { | |
| 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); | |
| } | |
| /** | |
| Retrieves a pointer to the a Null-terminated ASCII string containing the list | |
| of languages that an HII handle in the HII Database supports. The returned | |
| string is allocated using AllocatePool(). The caller is responsible for freeing | |
| the returned string using FreePool(). The format of the returned string follows | |
| the language format assumed the HII Database. | |
| If HiiHandle is NULL, then ASSERT(). | |
| @param[in] HiiHandle A handle that was previously registered in the HII Database. | |
| @retval NULL HiiHandle is not registered in the HII database | |
| @retval NULL There are not enough resources available to retrieve the supported | |
| languages. | |
| @retval NULL The list of supported languages could not be retrieved. | |
| @retval Other A pointer to the Null-terminated ASCII string of supported languages. | |
| **/ | |
| CHAR8 * | |
| GetSupportedLanguages ( | |
| IN EFI_HII_HANDLE HiiHandle | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| UINTN LanguageSize; | |
| CHAR8 TempSupportedLanguages; | |
| CHAR8 *SupportedLanguages; | |
| ASSERT (HiiHandle != NULL); | |
| // | |
| // Retrieve the size required for the supported languages buffer. | |
| // | |
| LanguageSize = 0; | |
| Status = mPrivate.HiiString.GetLanguages (&mPrivate.HiiString, HiiHandle, &TempSupportedLanguages, &LanguageSize); | |
| // | |
| // If GetLanguages() returns EFI_SUCCESS for a zero size, | |
| // then there are no supported languages registered for HiiHandle. If GetLanguages() | |
| // returns an error other than EFI_BUFFER_TOO_SMALL, then HiiHandle is not present | |
| // in the HII Database | |
| // | |
| if (Status != EFI_BUFFER_TOO_SMALL) { | |
| // | |
| // Return NULL if the size can not be retrieved, or if HiiHandle is not in the HII Database | |
| // | |
| return NULL; | |
| } | |
| // | |
| // Allocate the supported languages buffer. | |
| // | |
| SupportedLanguages = AllocateZeroPool (LanguageSize); | |
| if (SupportedLanguages == NULL) { | |
| // | |
| // Return NULL if allocation fails. | |
| // | |
| return NULL; | |
| } | |
| // | |
| // Retrieve the supported languages string | |
| // | |
| Status = mPrivate.HiiString.GetLanguages (&mPrivate.HiiString, HiiHandle, SupportedLanguages, &LanguageSize); | |
| if (EFI_ERROR (Status)) { | |
| // | |
| // Free the buffer and return NULL if the supported languages can not be retrieved. | |
| // | |
| FreePool (SupportedLanguages); | |
| return NULL; | |
| } | |
| // | |
| // Return the Null-terminated ASCII string of supported languages | |
| // | |
| return SupportedLanguages; | |
| } | |
| /** | |
| This function create a new string in String Package or updates an existing | |
| string in a String Package. If StringId is 0, then a new string is added to | |
| a String Package. If StringId is not zero, then a string in String Package is | |
| updated. If SupportedLanguages is NULL, then the string is added or updated | |
| for all the languages that the String Package supports. If SupportedLanguages | |
| is not NULL, then the string is added or updated for the set of languages | |
| specified by SupportedLanguages. | |
| If HiiHandle is NULL, then ASSERT(). | |
| If String is NULL, then ASSERT(). | |
| @param[in] HiiHandle A handle that was previously registered in the | |
| HII Database. | |
| @param[in] StringId If zero, then a new string is created in the | |
| String Package associated with HiiHandle. If | |
| non-zero, then the string specified by StringId | |
| is updated in the String Package associated | |
| with HiiHandle. | |
| @param[in] String A pointer to the Null-terminated Unicode string | |
| to add or update in the String Package associated | |
| with HiiHandle. | |
| @param[in] SupportedLanguages A pointer to a Null-terminated ASCII string of | |
| language codes. If this parameter is NULL, then | |
| String is added or updated in the String Package | |
| associated with HiiHandle for all the languages | |
| that the String Package supports. If this | |
| parameter is not NULL, then then String is added | |
| or updated in the String Package associated with | |
| HiiHandle for the set oflanguages specified by | |
| SupportedLanguages. The format of | |
| SupportedLanguages must follow the language | |
| format assumed the HII Database. | |
| @retval 0 The string could not be added or updated in the String Package. | |
| @retval Other The EFI_STRING_ID of the newly added or updated string. | |
| **/ | |
| EFI_STRING_ID | |
| InternalHiiSetString ( | |
| IN EFI_HII_HANDLE HiiHandle, | |
| IN EFI_STRING_ID StringId OPTIONAL, | |
| IN CONST EFI_STRING String, | |
| IN CONST CHAR8 *SupportedLanguages OPTIONAL | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| CHAR8 *AllocatedLanguages; | |
| CHAR8 *Supported; | |
| CHAR8 *Language; | |
| ASSERT (HiiHandle != NULL); | |
| if (SupportedLanguages == NULL) { | |
| // | |
| // Retrieve the languages that the package specified by HiiHandle supports | |
| // | |
| AllocatedLanguages = GetSupportedLanguages (HiiHandle); | |
| } else { | |
| // | |
| // Allocate a copy of the SupportLanguages string that passed in | |
| // | |
| AllocatedLanguages = AllocateCopyPool (AsciiStrSize (SupportedLanguages), SupportedLanguages); | |
| } | |
| // | |
| // If there are not enough resources for the supported languages string, then return a StringId of 0 | |
| // | |
| if (AllocatedLanguages == NULL) { | |
| return (EFI_STRING_ID)(0); | |
| } | |
| Status = EFI_INVALID_PARAMETER; | |
| // | |
| // Loop through each language that the string supports | |
| // | |
| for (Supported = AllocatedLanguages; *Supported != '\0'; ) { | |
| // | |
| // Cache a pointer to the beginning of the current language in the list of languages | |
| // | |
| Language = Supported; | |
| // | |
| // Search for the next language separator and replace it with a Null-terminator | |
| // | |
| for ( ; *Supported != 0 && *Supported != ';'; Supported++) { | |
| } | |
| if (*Supported != 0) { | |
| *(Supported++) = '\0'; | |
| } | |
| if ((SupportedLanguages == NULL) && (AsciiStrnCmp (Language, UEFI_CONFIG_LANG, AsciiStrLen (UEFI_CONFIG_LANG)) == 0)) { | |
| // | |
| // Skip string package used for keyword protocol. | |
| // | |
| continue; | |
| } | |
| // | |
| // If StringId is 0, then call NewString(). Otherwise, call SetString() | |
| // | |
| if (StringId == (EFI_STRING_ID)(0)) { | |
| Status = mPrivate.HiiString.NewString ( | |
| &mPrivate.HiiString, | |
| HiiHandle, | |
| &StringId, | |
| Language, | |
| NULL, | |
| String, | |
| NULL | |
| ); | |
| } else { | |
| Status = mPrivate.HiiString.SetString ( | |
| &mPrivate.HiiString, | |
| HiiHandle, | |
| StringId, | |
| Language, | |
| String, | |
| NULL | |
| ); | |
| } | |
| // | |
| // If there was an error, then break out of the loop and return a StringId of 0 | |
| // | |
| if (EFI_ERROR (Status)) { | |
| break; | |
| } | |
| } | |
| // | |
| // Free the buffer of supported languages | |
| // | |
| FreePool (AllocatedLanguages); | |
| if (EFI_ERROR (Status)) { | |
| return (EFI_STRING_ID)(0); | |
| } else { | |
| return StringId; | |
| } | |
| } | |
| /** | |
| Retrieves a string from a string package. | |
| If HiiHandle is NULL, then ASSERT(). | |
| If StringId is 0, then ASSET. | |
| @param[in] HiiHandle A handle that was previously registered in the HII Database. | |
| @param[in] StringId The identifier of the string to retrieved from the string | |
| package associated with HiiHandle. | |
| @retval NULL The string specified by StringId is not present in the string package. | |
| @retval Other The string was returned. | |
| **/ | |
| EFI_STRING | |
| InternalGetString ( | |
| IN EFI_HII_HANDLE HiiHandle, | |
| IN EFI_STRING_ID StringId | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| UINTN StringSize; | |
| CHAR16 TempString; | |
| EFI_STRING String; | |
| CHAR8 *SupportedLanguages; | |
| CHAR8 *PlatformLanguage; | |
| CHAR8 *BestLanguage; | |
| CHAR8 *Language; | |
| ASSERT (HiiHandle != NULL); | |
| ASSERT (StringId != 0); | |
| // | |
| // Initialize all allocated buffers to NULL | |
| // | |
| SupportedLanguages = NULL; | |
| PlatformLanguage = NULL; | |
| BestLanguage = NULL; | |
| String = NULL; | |
| Language = ""; | |
| // | |
| // Get the languages that the package specified by HiiHandle supports | |
| // | |
| SupportedLanguages = GetSupportedLanguages (HiiHandle); | |
| if (SupportedLanguages == NULL) { | |
| goto Error; | |
| } | |
| // | |
| // Get the current platform language setting | |
| // | |
| GetEfiGlobalVariable2 (L"PlatformLang", (VOID **)&PlatformLanguage, NULL); | |
| // | |
| // Get the best matching language from SupportedLanguages | |
| // | |
| BestLanguage = GetBestLanguage ( | |
| SupportedLanguages, | |
| FALSE, // RFC 4646 mode | |
| Language, // Highest priority | |
| PlatformLanguage != NULL ? PlatformLanguage : "", // Next highest priority | |
| SupportedLanguages, // Lowest priority | |
| NULL | |
| ); | |
| if (BestLanguage == NULL) { | |
| goto Error; | |
| } | |
| // | |
| // Retrieve the size of the string in the string package for the BestLanguage | |
| // | |
| StringSize = 0; | |
| Status = mPrivate.HiiString.GetString ( | |
| &mPrivate.HiiString, | |
| BestLanguage, | |
| HiiHandle, | |
| StringId, | |
| &TempString, | |
| &StringSize, | |
| NULL | |
| ); | |
| // | |
| // If GetString() returns EFI_SUCCESS for a zero size, | |
| // then there are no supported languages registered for HiiHandle. If GetString() | |
| // returns an error other than EFI_BUFFER_TOO_SMALL, then HiiHandle is not present | |
| // in the HII Database | |
| // | |
| if (Status != EFI_BUFFER_TOO_SMALL) { | |
| goto Error; | |
| } | |
| // | |
| // Allocate a buffer for the return string | |
| // | |
| String = AllocateZeroPool (StringSize); | |
| if (String == NULL) { | |
| goto Error; | |
| } | |
| // | |
| // Retrieve the string from the string package | |
| // | |
| Status = mPrivate.HiiString.GetString ( | |
| &mPrivate.HiiString, | |
| BestLanguage, | |
| HiiHandle, | |
| StringId, | |
| String, | |
| &StringSize, | |
| NULL | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| // | |
| // Free the buffer and return NULL if the supported languages can not be retrieved. | |
| // | |
| FreePool (String); | |
| String = NULL; | |
| } | |
| Error: | |
| // | |
| // Free allocated buffers | |
| // | |
| if (SupportedLanguages != NULL) { | |
| FreePool (SupportedLanguages); | |
| } | |
| if (PlatformLanguage != NULL) { | |
| FreePool (PlatformLanguage); | |
| } | |
| if (BestLanguage != NULL) { | |
| FreePool (BestLanguage); | |
| } | |
| // | |
| // Return the Null-terminated Unicode string | |
| // | |
| return String; | |
| } | |
| /** | |
| 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. | |
| @param IsNameValueType Whether this varstore is name/value varstore or not. | |
| @param HiiHandle Hii handle for this hii package. | |
| @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, | |
| IN BOOLEAN IsNameValueType, | |
| IN EFI_HII_HANDLE HiiHandle | |
| ) | |
| { | |
| LIST_ENTRY *Link; | |
| IFR_BLOCK_DATA *BlockData; | |
| EFI_STRING Name; | |
| // | |
| // 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 (IsNameValueType) { | |
| Name = InternalGetString (HiiHandle, VarOffset); | |
| ASSERT (Name != NULL); | |
| if (StrnCmp (BlockData->Name, Name, StrLen (Name)) == 0) { | |
| FreePool (Name); | |
| return TRUE; | |
| } | |
| FreePool (Name); | |
| } else { | |
| if ((VarOffset >= BlockData->Offset) && ((VarOffset + VarWidth) <= (BlockData->Offset + BlockData->Width))) { | |
| return TRUE; | |
| } | |
| } | |
| } | |
| return FALSE; | |
| } | |
| /** | |
| Get form package data from data base. | |
| @param DataBaseRecord The DataBaseRecord instance contains the found Hii handle and package. | |
| @param HiiFormPackage The buffer saves the package data. | |
| @param PackageSize The buffer size of the package data. | |
| **/ | |
| EFI_STATUS | |
| GetFormPackageData ( | |
| IN HII_DATABASE_RECORD *DataBaseRecord, | |
| IN OUT UINT8 **HiiFormPackage, | |
| OUT UINTN *PackageSize | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| UINTN Size; | |
| UINTN ResultSize; | |
| if ((DataBaseRecord == NULL) || (HiiFormPackage == NULL) || (PackageSize == NULL)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| Size = 0; | |
| ResultSize = 0; | |
| // | |
| // 0. Get Hii Form Package by HiiHandle | |
| // | |
| Status = ExportFormPackages ( | |
| &mPrivate, | |
| DataBaseRecord->Handle, | |
| DataBaseRecord->PackageList, | |
| 0, | |
| Size, | |
| HiiFormPackage, | |
| &ResultSize | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| (*HiiFormPackage) = AllocatePool (ResultSize); | |
| if (*HiiFormPackage == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| return Status; | |
| } | |
| // | |
| // Get HiiFormPackage by HiiHandle | |
| // | |
| Size = ResultSize; | |
| ResultSize = 0; | |
| Status = ExportFormPackages ( | |
| &mPrivate, | |
| DataBaseRecord->Handle, | |
| DataBaseRecord->PackageList, | |
| 0, | |
| Size, | |
| *HiiFormPackage, | |
| &ResultSize | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| FreePool (*HiiFormPackage); | |
| } | |
| *PackageSize = Size; | |
| return Status; | |
| } | |
| /** | |
| This function parses Form Package to get the efi varstore info according to the request ConfigHdr. | |
| @param DataBaseRecord The DataBaseRecord instance contains the found Hii handle and package. | |
| @param ConfigHdr Request string ConfigHdr. If it is NULL, | |
| the first found varstore will be as ConfigHdr. | |
| @param IsEfiVarstore Whether the request storage type is efi varstore type. | |
| @param EfiVarStore The efi varstore info which will return. | |
| **/ | |
| EFI_STATUS | |
| GetVarStoreType ( | |
| IN HII_DATABASE_RECORD *DataBaseRecord, | |
| IN EFI_STRING ConfigHdr, | |
| OUT BOOLEAN *IsEfiVarstore, | |
| OUT EFI_IFR_VARSTORE_EFI **EfiVarStore | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| UINTN IfrOffset; | |
| UINTN PackageOffset; | |
| EFI_IFR_OP_HEADER *IfrOpHdr; | |
| CHAR16 *VarStoreName; | |
| UINTN NameSize; | |
| EFI_STRING GuidStr; | |
| EFI_STRING NameStr; | |
| EFI_STRING TempStr; | |
| UINTN LengthString; | |
| UINT8 *HiiFormPackage; | |
| UINTN PackageSize; | |
| EFI_IFR_VARSTORE_EFI *IfrEfiVarStore; | |
| EFI_HII_PACKAGE_HEADER *PackageHeader; | |
| HiiFormPackage = NULL; | |
| LengthString = 0; | |
| Status = EFI_SUCCESS; | |
| GuidStr = NULL; | |
| NameStr = NULL; | |
| TempStr = NULL; | |
| *IsEfiVarstore = FALSE; | |
| Status = GetFormPackageData (DataBaseRecord, &HiiFormPackage, &PackageSize); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| IfrOffset = sizeof (EFI_HII_PACKAGE_HEADER); | |
| PackageOffset = IfrOffset; | |
| PackageHeader = (EFI_HII_PACKAGE_HEADER *)HiiFormPackage; | |
| while (IfrOffset < PackageSize) { | |
| // | |
| // More than one form packages exist. | |
| // | |
| if (PackageOffset >= PackageHeader->Length) { | |
| // | |
| // Process the new form package. | |
| // | |
| PackageOffset = sizeof (EFI_HII_PACKAGE_HEADER); | |
| IfrOffset += PackageOffset; | |
| PackageHeader = (EFI_HII_PACKAGE_HEADER *)(HiiFormPackage + IfrOffset); | |
| } | |
| IfrOpHdr = (EFI_IFR_OP_HEADER *)(HiiFormPackage + IfrOffset); | |
| IfrOffset += IfrOpHdr->Length; | |
| PackageOffset += IfrOpHdr->Length; | |
| if (IfrOpHdr->OpCode == EFI_IFR_VARSTORE_EFI_OP ) { | |
| IfrEfiVarStore = (EFI_IFR_VARSTORE_EFI *)IfrOpHdr; | |
| // | |
| // If the length is small than the structure, this is from old efi | |
| // varstore definition. Old efi varstore get config directly from | |
| // GetVariable function. | |
| // | |
| if (IfrOpHdr->Length < sizeof (EFI_IFR_VARSTORE_EFI)) { | |
| continue; | |
| } | |
| NameSize = AsciiStrSize ((CHAR8 *)IfrEfiVarStore->Name); | |
| VarStoreName = AllocateZeroPool (NameSize * sizeof (CHAR16)); | |
| if (VarStoreName == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto Done; | |
| } | |
| AsciiStrToUnicodeStrS ((CHAR8 *)IfrEfiVarStore->Name, VarStoreName, NameSize); | |
| GenerateSubStr (L"GUID=", sizeof (EFI_GUID), (VOID *)&IfrEfiVarStore->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; | |
| } | |
| StrCpyS (TempStr, LengthString, GuidStr); | |
| StrCatS (TempStr, LengthString, NameStr); | |
| if ((ConfigHdr == NULL) || (StrnCmp (ConfigHdr, TempStr, StrLen (TempStr)) == 0)) { | |
| *EfiVarStore = (EFI_IFR_VARSTORE_EFI *)AllocateZeroPool (IfrOpHdr->Length); | |
| if (*EfiVarStore == NULL) { | |
| FreePool (VarStoreName); | |
| FreePool (GuidStr); | |
| FreePool (NameStr); | |
| FreePool (TempStr); | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto Done; | |
| } | |
| *IsEfiVarstore = TRUE; | |
| CopyMem (*EfiVarStore, IfrEfiVarStore, IfrOpHdr->Length); | |
| } | |
| // | |
| // Free allocated temp string. | |
| // | |
| FreePool (VarStoreName); | |
| FreePool (GuidStr); | |
| FreePool (NameStr); | |
| FreePool (TempStr); | |
| // | |
| // Already found the varstore, break; | |
| // | |
| if (*IsEfiVarstore) { | |
| break; | |
| } | |
| } | |
| } | |
| Done: | |
| if (HiiFormPackage != NULL) { | |
| FreePool (HiiFormPackage); | |
| } | |
| return Status; | |
| } | |
| /** | |
| Check whether the ConfigRequest string has the request elements. | |
| For EFI_HII_VARSTORE_BUFFER type, the request has "&OFFSET=****&WIDTH=****..." format. | |
| For EFI_HII_VARSTORE_NAME_VALUE type, the request has "&NAME1**&NAME2..." format. | |
| @param ConfigRequest The input config request string. | |
| @retval TRUE The input include config request elements. | |
| @retval FALSE The input string not includes. | |
| **/ | |
| BOOLEAN | |
| GetElementsFromRequest ( | |
| IN EFI_STRING ConfigRequest | |
| ) | |
| { | |
| EFI_STRING TmpRequest; | |
| TmpRequest = StrStr (ConfigRequest, L"PATH="); | |
| ASSERT (TmpRequest != NULL); | |
| if ((StrStr (TmpRequest, L"&OFFSET=") != NULL) || (StrStr (TmpRequest, L"&") != NULL)) { | |
| return TRUE; | |
| } | |
| return FALSE; | |
| } | |
| /** | |
| Check whether the this varstore is the request varstore. | |
| @param VarstoreGuid Varstore guid. | |
| @param Name Varstore name. | |
| @param ConfigHdr Current configRequest info. | |
| @retval TRUE This varstore is the request one. | |
| @retval FALSE This varstore is not the request one. | |
| **/ | |
| BOOLEAN | |
| IsThisVarstore ( | |
| IN EFI_GUID *VarstoreGuid, | |
| IN CHAR16 *Name, | |
| IN CHAR16 *ConfigHdr | |
| ) | |
| { | |
| EFI_STRING GuidStr; | |
| EFI_STRING NameStr; | |
| EFI_STRING TempStr; | |
| UINTN LengthString; | |
| BOOLEAN RetVal; | |
| RetVal = FALSE; | |
| GuidStr = NULL; | |
| TempStr = NULL; | |
| // | |
| // If ConfigHdr has name field and varstore not has name, return FALSE. | |
| // | |
| if ((Name == NULL) && (ConfigHdr != NULL) && (StrStr (ConfigHdr, L"NAME=&") == NULL)) { | |
| return FALSE; | |
| } | |
| GenerateSubStr (L"GUID=", sizeof (EFI_GUID), (VOID *)VarstoreGuid, 1, &GuidStr); | |
| if (Name != NULL) { | |
| GenerateSubStr (L"NAME=", StrLen (Name) * sizeof (CHAR16), (VOID *)Name, 2, &NameStr); | |
| } else { | |
| GenerateSubStr (L"NAME=", 0, NULL, 2, &NameStr); | |
| } | |
| LengthString = StrLen (GuidStr); | |
| LengthString = LengthString + StrLen (NameStr) + 1; | |
| TempStr = AllocateZeroPool (LengthString * sizeof (CHAR16)); | |
| if (TempStr == NULL) { | |
| goto Done; | |
| } | |
| StrCpyS (TempStr, LengthString, GuidStr); | |
| StrCatS (TempStr, LengthString, NameStr); | |
| if ((ConfigHdr == NULL) || (StrnCmp (ConfigHdr, TempStr, StrLen (TempStr)) == 0)) { | |
| RetVal = TRUE; | |
| } | |
| Done: | |
| if (GuidStr != NULL) { | |
| FreePool (GuidStr); | |
| } | |
| if (NameStr != NULL) { | |
| FreePool (NameStr); | |
| } | |
| if (TempStr != NULL) { | |
| FreePool (TempStr); | |
| } | |
| return RetVal; | |
| } | |
| /** | |
| This function parses Form Package to get the efi varstore info according to the request ConfigHdr. | |
| @param DataBaseRecord The DataBaseRecord instance contains the found Hii handle and package. | |
| @param ConfigHdr Request string ConfigHdr. If it is NULL, | |
| the first found varstore will be as ConfigHdr. | |
| @retval TRUE This hii package is the request one. | |
| @retval FALSE This hii package is not the request one. | |
| **/ | |
| BOOLEAN | |
| IsThisPackageList ( | |
| IN HII_DATABASE_RECORD *DataBaseRecord, | |
| IN EFI_STRING ConfigHdr | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| UINTN IfrOffset; | |
| UINTN PackageOffset; | |
| EFI_IFR_OP_HEADER *IfrOpHdr; | |
| CHAR16 *VarStoreName; | |
| UINTN NameSize; | |
| UINT8 *HiiFormPackage; | |
| UINTN PackageSize; | |
| EFI_IFR_VARSTORE_EFI *IfrEfiVarStore; | |
| EFI_HII_PACKAGE_HEADER *PackageHeader; | |
| EFI_IFR_VARSTORE *IfrVarStore; | |
| EFI_IFR_VARSTORE_NAME_VALUE *IfrNameValueVarStore; | |
| BOOLEAN FindVarstore; | |
| HiiFormPackage = NULL; | |
| VarStoreName = NULL; | |
| Status = EFI_SUCCESS; | |
| FindVarstore = FALSE; | |
| Status = GetFormPackageData (DataBaseRecord, &HiiFormPackage, &PackageSize); | |
| if (EFI_ERROR (Status)) { | |
| return FALSE; | |
| } | |
| IfrOffset = sizeof (EFI_HII_PACKAGE_HEADER); | |
| PackageOffset = IfrOffset; | |
| PackageHeader = (EFI_HII_PACKAGE_HEADER *)HiiFormPackage; | |
| while (IfrOffset < PackageSize) { | |
| // | |
| // More than one form packages exist. | |
| // | |
| if (PackageOffset >= PackageHeader->Length) { | |
| // | |
| // Process the new form package. | |
| // | |
| PackageOffset = sizeof (EFI_HII_PACKAGE_HEADER); | |
| IfrOffset += PackageOffset; | |
| PackageHeader = (EFI_HII_PACKAGE_HEADER *)(HiiFormPackage + IfrOffset); | |
| } | |
| IfrOpHdr = (EFI_IFR_OP_HEADER *)(HiiFormPackage + IfrOffset); | |
| IfrOffset += IfrOpHdr->Length; | |
| PackageOffset += IfrOpHdr->Length; | |
| switch (IfrOpHdr->OpCode) { | |
| case EFI_IFR_VARSTORE_OP: | |
| IfrVarStore = (EFI_IFR_VARSTORE *)IfrOpHdr; | |
| NameSize = AsciiStrSize ((CHAR8 *)IfrVarStore->Name); | |
| VarStoreName = AllocateZeroPool (NameSize * sizeof (CHAR16)); | |
| if (VarStoreName == NULL) { | |
| goto Done; | |
| } | |
| AsciiStrToUnicodeStrS ((CHAR8 *)IfrVarStore->Name, VarStoreName, NameSize); | |
| if (IsThisVarstore ((VOID *)&IfrVarStore->Guid, VarStoreName, ConfigHdr)) { | |
| FindVarstore = TRUE; | |
| goto Done; | |
| } else { | |
| FreePool (VarStoreName); | |
| VarStoreName = NULL; | |
| } | |
| break; | |
| case EFI_IFR_VARSTORE_EFI_OP: | |
| IfrEfiVarStore = (EFI_IFR_VARSTORE_EFI *)IfrOpHdr; | |
| NameSize = AsciiStrSize ((CHAR8 *)IfrEfiVarStore->Name); | |
| VarStoreName = AllocateZeroPool (NameSize * sizeof (CHAR16)); | |
| if (VarStoreName == NULL) { | |
| goto Done; | |
| } | |
| AsciiStrToUnicodeStrS ((CHAR8 *)IfrEfiVarStore->Name, VarStoreName, NameSize); | |
| if (IsThisVarstore (&IfrEfiVarStore->Guid, VarStoreName, ConfigHdr)) { | |
| FindVarstore = TRUE; | |
| goto Done; | |
| } else { | |
| FreePool (VarStoreName); | |
| VarStoreName = NULL; | |
| } | |
| break; | |
| case EFI_IFR_VARSTORE_NAME_VALUE_OP: | |
| IfrNameValueVarStore = (EFI_IFR_VARSTORE_NAME_VALUE *)IfrOpHdr; | |
| if (IsThisVarstore (&IfrNameValueVarStore->Guid, NULL, ConfigHdr)) { | |
| FindVarstore = TRUE; | |
| goto Done; | |
| } | |
| break; | |
| case EFI_IFR_FORM_OP: | |
| case EFI_IFR_FORM_MAP_OP: | |
| // | |
| // No matched varstore is found and directly return. | |
| // | |
| goto Done; | |
| default: | |
| break; | |
| } | |
| } | |
| Done: | |
| if (HiiFormPackage != NULL) { | |
| FreePool (HiiFormPackage); | |
| } | |
| if (VarStoreName != NULL) { | |
| FreePool (VarStoreName); | |
| } | |
| return FindVarstore; | |
| } | |
| /** | |
| Check whether the this op code is required. | |
| @param RequestBlockArray The array includes all the request info or NULL. | |
| @param HiiHandle The hii handle for this form package. | |
| @param VarStorageData The varstore data structure. | |
| @param IfrOpHdr Ifr opcode header for this opcode. | |
| @param VarWidth The buffer width for this opcode. | |
| @param ReturnData The data block added for this opcode. | |
| @param IsBitVar Whether the the opcode refers to bit storage. | |
| @retval EFI_SUCCESS This opcode is required. | |
| @retval EFI_NOT_FOUND This opcode is not required. | |
| @retval Others Contain some error. | |
| **/ | |
| EFI_STATUS | |
| IsThisOpcodeRequired ( | |
| IN IFR_BLOCK_DATA *RequestBlockArray, | |
| IN EFI_HII_HANDLE HiiHandle, | |
| IN OUT IFR_VARSTORAGE_DATA *VarStorageData, | |
| IN EFI_IFR_OP_HEADER *IfrOpHdr, | |
| IN UINT16 VarWidth, | |
| OUT IFR_BLOCK_DATA **ReturnData, | |
| IN BOOLEAN IsBitVar | |
| ) | |
| { | |
| IFR_BLOCK_DATA *BlockData; | |
| UINT16 VarOffset; | |
| EFI_STRING_ID NameId; | |
| EFI_IFR_QUESTION_HEADER *IfrQuestionHdr; | |
| UINT16 BitOffset; | |
| UINT16 BitWidth; | |
| UINT16 TotalBits; | |
| NameId = 0; | |
| VarOffset = 0; | |
| BitOffset = 0; | |
| BitWidth = 0; | |
| IfrQuestionHdr = (EFI_IFR_QUESTION_HEADER *)((CHAR8 *)IfrOpHdr + sizeof (EFI_IFR_OP_HEADER)); | |
| if (VarStorageData->Type == EFI_HII_VARSTORE_NAME_VALUE) { | |
| NameId = IfrQuestionHdr->VarStoreInfo.VarName; | |
| // | |
| // Check whether this question is in requested block array. | |
| // | |
| if (!BlockArrayCheck (RequestBlockArray, NameId, 0, TRUE, HiiHandle)) { | |
| // | |
| // This question is not in the requested string. Skip it. | |
| // | |
| return EFI_NOT_FOUND; | |
| } | |
| } else { | |
| // | |
| // Get the byte offset/with and bit offset/width | |
| // | |
| if (IsBitVar) { | |
| BitOffset = IfrQuestionHdr->VarStoreInfo.VarOffset; | |
| BitWidth = VarWidth; | |
| VarOffset = BitOffset / 8; | |
| // | |
| // Use current bit width and the bit width before current bit (with same byte offset) to calculate the byte width. | |
| // | |
| TotalBits = BitOffset % 8 + BitWidth; | |
| VarWidth = (TotalBits % 8 == 0 ? TotalBits / 8 : TotalBits / 8 + 1); | |
| } else { | |
| VarOffset = IfrQuestionHdr->VarStoreInfo.VarOffset; | |
| BitWidth = VarWidth; | |
| BitOffset = VarOffset * 8; | |
| } | |
| // | |
| // Check whether this question is in requested block array. | |
| // | |
| if (!BlockArrayCheck (RequestBlockArray, VarOffset, VarWidth, FALSE, HiiHandle)) { | |
| // | |
| // This question is not in the requested string. Skip it. | |
| // | |
| return EFI_NOT_FOUND; | |
| } | |
| // | |
| // Check this var question is in the var storage | |
| // | |
| if (((VarOffset + VarWidth) > VarStorageData->Size)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| } | |
| BlockData = (IFR_BLOCK_DATA *)AllocateZeroPool (sizeof (IFR_BLOCK_DATA)); | |
| if (BlockData == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| if (VarStorageData->Type == EFI_HII_VARSTORE_NAME_VALUE) { | |
| BlockData->Name = InternalGetString (HiiHandle, NameId); | |
| } else { | |
| BlockData->Offset = VarOffset; | |
| } | |
| BlockData->Width = VarWidth; | |
| BlockData->QuestionId = IfrQuestionHdr->QuestionId; | |
| BlockData->OpCode = IfrOpHdr->OpCode; | |
| BlockData->Scope = IfrOpHdr->Scope; | |
| BlockData->IsBitVar = IsBitVar; | |
| BlockData->BitOffset = BitOffset; | |
| BlockData->BitWidth = BitWidth; | |
| InitializeListHead (&BlockData->DefaultValueEntry); | |
| // | |
| // Add Block Data into VarStorageData BlockEntry | |
| // | |
| InsertBlockData (&VarStorageData->BlockEntry, &BlockData); | |
| *ReturnData = BlockData; | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| This function parses Form Package to get the block array and the default | |
| value array according to the request ConfigHdr. | |
| @param HiiHandle Hii Handle for this hii package. | |
| @param Package Pointer to the form package data. | |
| @param PackageLength Length of the package. | |
| @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 DefaultIdArray 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 definition in the different form packages | |
| are conflicted. | |
| @retval EFI_OUT_OF_RESOURCES No enough memory. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| ParseIfrData ( | |
| IN EFI_HII_HANDLE HiiHandle, | |
| 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; | |
| UINTN PackageOffset; | |
| EFI_IFR_VARSTORE *IfrVarStore; | |
| EFI_IFR_VARSTORE_EFI *IfrEfiVarStore; | |
| EFI_IFR_VARSTORE_EFI *IfrEfiVarStoreTmp; | |
| EFI_IFR_OP_HEADER *IfrOpHdr; | |
| EFI_IFR_ONE_OF *IfrOneOf; | |
| EFI_IFR_REF4 *IfrRef; | |
| 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; | |
| EFI_IFR_DATE *IfrDate; | |
| EFI_IFR_TIME *IfrTime; | |
| IFR_DEFAULT_DATA DefaultData; | |
| IFR_DEFAULT_DATA *DefaultDataPtr; | |
| IFR_BLOCK_DATA *BlockData; | |
| CHAR16 *VarStoreName; | |
| UINTN NameSize; | |
| UINTN NvDefaultStoreSize; | |
| UINT16 VarWidth; | |
| UINT16 VarDefaultId; | |
| BOOLEAN FirstOneOfOption; | |
| BOOLEAN FirstOrderedList; | |
| LIST_ENTRY *LinkData; | |
| LIST_ENTRY *LinkDefault; | |
| EFI_IFR_VARSTORE_NAME_VALUE *IfrNameValueVarStore; | |
| EFI_HII_PACKAGE_HEADER *PackageHeader; | |
| EFI_VARSTORE_ID VarStoreId; | |
| UINT16 SmallestDefaultId; | |
| BOOLEAN SmallestIdFromFlag; | |
| BOOLEAN FromOtherDefaultOpcode; | |
| BOOLEAN QuestionReferBitField; | |
| UINT16 *StringData; | |
| Status = EFI_SUCCESS; | |
| BlockData = NULL; | |
| DefaultDataPtr = NULL; | |
| FirstOneOfOption = FALSE; | |
| VarStoreId = 0; | |
| FirstOrderedList = FALSE; | |
| VarStoreName = NULL; | |
| ZeroMem (&DefaultData, sizeof (IFR_DEFAULT_DATA)); | |
| SmallestDefaultId = 0xFFFF; | |
| FromOtherDefaultOpcode = FALSE; | |
| QuestionReferBitField = FALSE; | |
| IfrEfiVarStoreTmp = NULL; | |
| StringData = NULL; | |
| // | |
| // Go through the form package to parse OpCode one by one. | |
| // | |
| PackageOffset = sizeof (EFI_HII_PACKAGE_HEADER); | |
| PackageHeader = (EFI_HII_PACKAGE_HEADER *)Package; | |
| IfrOffset = PackageOffset; | |
| while (IfrOffset < PackageLength) { | |
| // | |
| // More than one form package found. | |
| // | |
| if (PackageOffset >= PackageHeader->Length) { | |
| // | |
| // Already found varstore for this request, break; | |
| // | |
| if (VarStoreId != 0) { | |
| VarStoreId = 0; | |
| } | |
| // | |
| // Get next package header info. | |
| // | |
| IfrOffset += sizeof (EFI_HII_PACKAGE_HEADER); | |
| PackageOffset = sizeof (EFI_HII_PACKAGE_HEADER); | |
| PackageHeader = (EFI_HII_PACKAGE_HEADER *)(Package + IfrOffset); | |
| } | |
| 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 (VarStoreId != 0) { | |
| break; | |
| } | |
| IfrVarStore = (EFI_IFR_VARSTORE *)IfrOpHdr; | |
| NameSize = AsciiStrSize ((CHAR8 *)IfrVarStore->Name); | |
| VarStoreName = AllocateZeroPool (NameSize * sizeof (CHAR16)); | |
| if (VarStoreName == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto Done; | |
| } | |
| AsciiStrToUnicodeStrS ((CHAR8 *)IfrVarStore->Name, VarStoreName, NameSize); | |
| if (IsThisVarstore ((VOID *)&IfrVarStore->Guid, VarStoreName, ConfigHdr)) { | |
| // | |
| // Find the matched VarStore | |
| // | |
| CopyGuid (&VarStorageData->Guid, (EFI_GUID *)(VOID *)&IfrVarStore->Guid); | |
| VarStorageData->Size = IfrVarStore->Size; | |
| VarStorageData->Name = VarStoreName; | |
| VarStorageData->Type = EFI_HII_VARSTORE_BUFFER; | |
| VarStoreId = IfrVarStore->VarStoreId; | |
| } else { | |
| FreePool (VarStoreName); | |
| VarStoreName = NULL; | |
| } | |
| break; | |
| case EFI_IFR_VARSTORE_EFI_OP: | |
| // | |
| // VarStore is found. Don't need to search any more. | |
| // | |
| if (VarStoreId != 0) { | |
| break; | |
| } | |
| IfrEfiVarStore = (EFI_IFR_VARSTORE_EFI *)IfrOpHdr; | |
| // | |
| // If the length is small than the structure, this is from old efi | |
| // varstore definition. Old efi varstore get config directly from | |
| // GetVariable function. | |
| // | |
| if (IfrOpHdr->Length < sizeof (EFI_IFR_VARSTORE_EFI)) { | |
| break; | |
| } | |
| NameSize = AsciiStrSize ((CHAR8 *)IfrEfiVarStore->Name); | |
| VarStoreName = AllocateZeroPool (NameSize * sizeof (CHAR16)); | |
| if (VarStoreName == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto Done; | |
| } | |
| AsciiStrToUnicodeStrS ((CHAR8 *)IfrEfiVarStore->Name, VarStoreName, NameSize); | |
| if (IfrEfiVarStoreTmp != NULL) { | |
| FreePool (IfrEfiVarStoreTmp); | |
| } | |
| IfrEfiVarStoreTmp = AllocatePool (IfrEfiVarStore->Header.Length + AsciiStrSize ((CHAR8 *)IfrEfiVarStore->Name)); | |
| if (IfrEfiVarStoreTmp == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto Done; | |
| } | |
| CopyMem (IfrEfiVarStoreTmp, IfrEfiVarStore, IfrEfiVarStore->Header.Length); | |
| AsciiStrToUnicodeStrS ((CHAR8 *)IfrEfiVarStore->Name, (CHAR16 *)&(IfrEfiVarStoreTmp->Name[0]), AsciiStrSize ((CHAR8 *)IfrEfiVarStore->Name) * sizeof (CHAR16)); | |
| if (IsThisVarstore (&IfrEfiVarStore->Guid, VarStoreName, ConfigHdr)) { | |
| // | |
| // Find the matched VarStore | |
| // | |
| CopyGuid (&VarStorageData->Guid, (EFI_GUID *)(VOID *)&IfrEfiVarStore->Guid); | |
| VarStorageData->Size = IfrEfiVarStore->Size; | |
| VarStorageData->Name = VarStoreName; | |
| VarStorageData->Type = EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER; | |
| VarStoreId = IfrEfiVarStore->VarStoreId; | |
| } else { | |
| FreePool (VarStoreName); | |
| VarStoreName = NULL; | |
| } | |
| break; | |
| case EFI_IFR_VARSTORE_NAME_VALUE_OP: | |
| // | |
| // VarStore is found. Don't need to search any more. | |
| // | |
| if (VarStoreId != 0) { | |
| break; | |
| } | |
| IfrNameValueVarStore = (EFI_IFR_VARSTORE_NAME_VALUE *)IfrOpHdr; | |
| if (IsThisVarstore (&IfrNameValueVarStore->Guid, NULL, ConfigHdr)) { | |
| // | |
| // Find the matched VarStore | |
| // | |
| CopyGuid (&VarStorageData->Guid, (EFI_GUID *)(VOID *)&IfrNameValueVarStore->Guid); | |
| VarStorageData->Type = EFI_HII_VARSTORE_NAME_VALUE; | |
| VarStoreId = IfrNameValueVarStore->VarStoreId; | |
| } | |
| break; | |
| case EFI_IFR_DEFAULTSTORE_OP: | |
| // | |
| // Add new the map between default id and default name. | |
| // | |
| DefaultDataPtr = (IFR_DEFAULT_DATA *)AllocateZeroPool (sizeof (IFR_DEFAULT_DATA)); | |
| if (DefaultDataPtr == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto Done; | |
| } | |
| DefaultDataPtr->DefaultId = ((EFI_IFR_DEFAULTSTORE *)IfrOpHdr)->DefaultId; | |
| InsertTailList (&DefaultIdArray->Entry, &DefaultDataPtr->Entry); | |
| DefaultDataPtr = NULL; | |
| break; | |
| case EFI_IFR_FORM_OP: | |
| case EFI_IFR_FORM_MAP_OP: | |
| // | |
| // No matched varstore is found and directly return. | |
| // | |
| if ( VarStoreId == 0) { | |
| Status = EFI_SUCCESS; | |
| goto Done; | |
| } | |
| break; | |
| case EFI_IFR_REF_OP: | |
| // | |
| // Ref question is not in IFR Form. This IFR form is not valid. | |
| // | |
| if ( VarStoreId == 0) { | |
| Status = EFI_INVALID_PARAMETER; | |
| goto Done; | |
| } | |
| // | |
| // Check whether this question is for the requested varstore. | |
| // | |
| IfrRef = (EFI_IFR_REF4 *)IfrOpHdr; | |
| if (IfrRef->Question.VarStoreId != VarStoreId) { | |
| break; | |
| } | |
| VarWidth = (UINT16)(sizeof (EFI_HII_REF)); | |
| // | |
| // The BlockData may allocate by other opcode,need to clean. | |
| // | |
| if (BlockData != NULL) { | |
| BlockData = NULL; | |
| } | |
| Status = IsThisOpcodeRequired (RequestBlockArray, HiiHandle, VarStorageData, IfrOpHdr, VarWidth, &BlockData, FALSE); | |
| if (EFI_ERROR (Status)) { | |
| if (Status == EFI_NOT_FOUND) { | |
| // | |
| // The opcode is not required,exit and parse other opcode. | |
| // | |
| break; | |
| } | |
| 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 (VarStoreId == 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 != VarStoreId) { | |
| break; | |
| } | |
| if (QuestionReferBitField) { | |
| VarWidth = IfrOneOf->Flags & EDKII_IFR_NUMERIC_SIZE_BIT; | |
| } else { | |
| VarWidth = (UINT16)(1 << (IfrOneOf->Flags & EFI_IFR_NUMERIC_SIZE)); | |
| } | |
| // | |
| // The BlockData may allocate by other opcode,need to clean. | |
| // | |
| if (BlockData != NULL) { | |
| BlockData = NULL; | |
| } | |
| Status = IsThisOpcodeRequired (RequestBlockArray, HiiHandle, VarStorageData, IfrOpHdr, VarWidth, &BlockData, QuestionReferBitField); | |
| if (EFI_ERROR (Status)) { | |
| if (Status == EFI_NOT_FOUND) { | |
| // | |
| // The opcode is not required,exit and parse other opcode. | |
| // | |
| break; | |
| } | |
| goto Done; | |
| } | |
| // | |
| // when go to there,BlockData can't be NULLL. | |
| // | |
| ASSERT (BlockData != NULL); | |
| if (IfrOpHdr->OpCode == EFI_IFR_ONE_OF_OP) { | |
| // | |
| // Set this flag to TRUE for the first oneof option. | |
| // | |
| FirstOneOfOption = TRUE; | |
| } else if (IfrOpHdr->OpCode == EFI_IFR_NUMERIC_OP) { | |
| // | |
| // Numeric minimum value will be used as default value when no default is specified. | |
| // | |
| DefaultData.Type = DefaultValueFromDefault; | |
| if (QuestionReferBitField) { | |
| // | |
| // Since default value in bit field was stored as UINT32 type. | |
| // | |
| CopyMem (&DefaultData.Value.u32, &IfrOneOf->data.u32.MinValue, sizeof (UINT32)); | |
| } else { | |
| switch (IfrOneOf->Flags & EFI_IFR_NUMERIC_SIZE) { | |
| case EFI_IFR_NUMERIC_SIZE_1: | |
| DefaultData.Value.u8 = IfrOneOf->data.u8.MinValue; | |
| break; | |
| case EFI_IFR_NUMERIC_SIZE_2: | |
| CopyMem (&DefaultData.Value.u16, &IfrOneOf->data.u16.MinValue, sizeof (UINT16)); | |
| break; | |
| case EFI_IFR_NUMERIC_SIZE_4: | |
| CopyMem (&DefaultData.Value.u32, &IfrOneOf->data.u32.MinValue, sizeof (UINT32)); | |
| break; | |
| case EFI_IFR_NUMERIC_SIZE_8: | |
| CopyMem (&DefaultData.Value.u64, &IfrOneOf->data.u64.MinValue, sizeof (UINT64)); | |
| break; | |
| default: | |
| Status = EFI_INVALID_PARAMETER; | |
| goto Done; | |
| } | |
| } | |
| // | |
| // Set default value base on the DefaultId list get from IFR data. | |
| // | |
| NvDefaultStoreSize = PcdGetSize (PcdNvStoreDefaultValueBuffer); | |
| for (LinkData = DefaultIdArray->Entry.ForwardLink; LinkData != &DefaultIdArray->Entry; LinkData = LinkData->ForwardLink) { | |
| DefaultDataPtr = BASE_CR (LinkData, IFR_DEFAULT_DATA, Entry); | |
| DefaultData.DefaultId = DefaultDataPtr->DefaultId; | |
| if (NvDefaultStoreSize > sizeof (PCD_NV_STORE_DEFAULT_BUFFER_HEADER)) { | |
| FindQuestionDefaultSetting (DefaultData.DefaultId, IfrEfiVarStoreTmp, &(IfrOneOf->Question), &DefaultData.Value, VarWidth, QuestionReferBitField); | |
| } | |
| InsertDefaultValue (BlockData, &DefaultData); | |
| } | |
| } | |
| break; | |
| case EFI_IFR_ORDERED_LIST_OP: | |
| // | |
| // offset by question header | |
| // width by EFI_IFR_ORDERED_LIST MaxContainers * OneofOption Type | |
| // | |
| FirstOrderedList = TRUE; | |
| // | |
| // OrderedList question is not in IFR Form. This IFR form is not valid. | |
| // | |
| if (VarStoreId == 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 != VarStoreId) { | |
| BlockData = NULL; | |
| break; | |
| } | |
| VarWidth = IfrOrderedList->MaxContainers; | |
| // | |
| // The BlockData may allocate by other opcode,need to clean. | |
| // | |
| if (BlockData != NULL) { | |
| BlockData = NULL; | |
| } | |
| Status = IsThisOpcodeRequired (RequestBlockArray, HiiHandle, VarStorageData, IfrOpHdr, VarWidth, &BlockData, FALSE); | |
| if (EFI_ERROR (Status)) { | |
| if (Status == EFI_NOT_FOUND) { | |
| // | |
| // The opcode is not required,exit and parse other opcode. | |
| // | |
| break; | |
| } | |
| goto Done; | |
| } | |
| 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 (VarStoreId == 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 != VarStoreId) { | |
| break; | |
| } | |
| VarWidth = (UINT16)sizeof (BOOLEAN); | |
| // | |
| // The BlockData may allocate by other opcode,need to clean. | |
| // | |
| if (BlockData != NULL) { | |
| BlockData = NULL; | |
| } | |
| if (QuestionReferBitField) { | |
| VarWidth = 1; | |
| } | |
| Status = IsThisOpcodeRequired (RequestBlockArray, HiiHandle, VarStorageData, IfrOpHdr, VarWidth, &BlockData, QuestionReferBitField); | |
| if (EFI_ERROR (Status)) { | |
| if (Status == EFI_NOT_FOUND) { | |
| // | |
| // The opcode is not required,exit and parse other opcode. | |
| // | |
| break; | |
| } | |
| goto Done; | |
| } | |
| // | |
| // when go to there,BlockData can't be NULLL. | |
| // | |
| ASSERT (BlockData != NULL); | |
| SmallestIdFromFlag = FALSE; | |
| // | |
| // Add default value for standard ID by CheckBox Flag | |
| // | |
| VarDefaultId = EFI_HII_DEFAULT_CLASS_STANDARD; | |
| // | |
| // Prepare new DefaultValue | |
| // | |
| DefaultData.DefaultId = VarDefaultId; | |
| if ((IfrCheckBox->Flags & EFI_IFR_CHECKBOX_DEFAULT) == EFI_IFR_CHECKBOX_DEFAULT) { | |
| // | |
| // When flag is set, default value is TRUE. | |
| // | |
| DefaultData.Type = DefaultValueFromFlag; | |
| if (QuestionReferBitField) { | |
| DefaultData.Value.u32 = TRUE; | |
| } else { | |
| DefaultData.Value.b = TRUE; | |
| } | |
| InsertDefaultValue (BlockData, &DefaultData); | |
| if (SmallestDefaultId > EFI_HII_DEFAULT_CLASS_STANDARD) { | |
| // | |
| // Record the SmallestDefaultId and update the SmallestIdFromFlag. | |
| // | |
| SmallestDefaultId = EFI_HII_DEFAULT_CLASS_STANDARD; | |
| SmallestIdFromFlag = TRUE; | |
| } | |
| } | |
| // | |
| // Add default value for Manufacture ID by CheckBox Flag | |
| // | |
| VarDefaultId = EFI_HII_DEFAULT_CLASS_MANUFACTURING; | |
| // | |
| // Prepare new DefaultValue | |
| // | |
| DefaultData.DefaultId = VarDefaultId; | |
| if ((IfrCheckBox->Flags & EFI_IFR_CHECKBOX_DEFAULT_MFG) == EFI_IFR_CHECKBOX_DEFAULT_MFG) { | |
| // | |
| // When flag is set, default value is TRUE. | |
| // | |
| DefaultData.Type = DefaultValueFromFlag; | |
| if (QuestionReferBitField) { | |
| DefaultData.Value.u32 = TRUE; | |
| } else { | |
| DefaultData.Value.b = TRUE; | |
| } | |
| InsertDefaultValue (BlockData, &DefaultData); | |
| if (SmallestDefaultId > EFI_HII_DEFAULT_CLASS_MANUFACTURING) { | |
| // | |
| // Record the SmallestDefaultId and update the SmallestIdFromFlag. | |
| // | |
| SmallestDefaultId = EFI_HII_DEFAULT_CLASS_MANUFACTURING; | |
| SmallestIdFromFlag = TRUE; | |
| } | |
| } | |
| if (SmallestIdFromFlag) { | |
| // | |
| // When smallest default Id is given by the flag of CheckBox, set default value with TRUE for other default Id in the DefaultId list. | |
| // | |
| DefaultData.Type = DefaultValueFromOtherDefault; | |
| if (QuestionReferBitField) { | |
| DefaultData.Value.u32 = TRUE; | |
| } else { | |
| DefaultData.Value.b = TRUE; | |
| } | |
| // | |
| // Set default value for all the default id in the DefaultId list. | |
| // | |
| for (LinkData = DefaultIdArray->Entry.ForwardLink; LinkData != &DefaultIdArray->Entry; LinkData = LinkData->ForwardLink) { | |
| DefaultDataPtr = BASE_CR (LinkData, IFR_DEFAULT_DATA, Entry); | |
| DefaultData.DefaultId = DefaultDataPtr->DefaultId; | |
| InsertDefaultValue (BlockData, &DefaultData); | |
| } | |
| } else { | |
| // | |
| // When flag is not set, default value is FASLE. | |
| // | |
| DefaultData.Type = DefaultValueFromDefault; | |
| if (QuestionReferBitField) { | |
| DefaultData.Value.u32 = FALSE; | |
| } else { | |
| DefaultData.Value.b = FALSE; | |
| } | |
| // | |
| // Set default value for all the default id in the DefaultId list. | |
| // | |
| for (LinkData = DefaultIdArray->Entry.ForwardLink; LinkData != &DefaultIdArray->Entry; LinkData = LinkData->ForwardLink) { | |
| DefaultDataPtr = BASE_CR (LinkData, IFR_DEFAULT_DATA, Entry); | |
| DefaultData.DefaultId = DefaultDataPtr->DefaultId; | |
| InsertDefaultValue (BlockData, &DefaultData); | |
| } | |
| } | |
| break; | |
| case EFI_IFR_DATE_OP: | |
| // | |
| // offset by question header | |
| // width MaxSize * sizeof (CHAR16) | |
| // no default value, only block array | |
| // | |
| // | |
| // Date question is not in IFR Form. This IFR form is not valid. | |
| // | |
| if (VarStoreId == 0) { | |
| Status = EFI_INVALID_PARAMETER; | |
| goto Done; | |
| } | |
| // | |
| // Check whether this question is for the requested varstore. | |
| // | |
| IfrDate = (EFI_IFR_DATE *)IfrOpHdr; | |
| if (IfrDate->Question.VarStoreId != VarStoreId) { | |
| break; | |
| } | |
| // | |
| // The BlockData may allocate by other opcode,need to clean. | |
| // | |
| if (BlockData != NULL) { | |
| BlockData = NULL; | |
| } | |
| VarWidth = (UINT16)sizeof (EFI_HII_DATE); | |
| Status = IsThisOpcodeRequired (RequestBlockArray, HiiHandle, VarStorageData, IfrOpHdr, VarWidth, &BlockData, FALSE); | |
| if (EFI_ERROR (Status)) { | |
| if (Status == EFI_NOT_FOUND) { | |
| // | |
| // The opcode is not required,exit and parse other opcode. | |
| // | |
| break; | |
| } | |
| goto Done; | |
| } | |
| break; | |
| case EFI_IFR_TIME_OP: | |
| // | |
| // offset by question header | |
| // width MaxSize * sizeof (CHAR16) | |
| // no default value, only block array | |
| // | |
| // | |
| // Time question is not in IFR Form. This IFR form is not valid. | |
| // | |
| if (VarStoreId == 0) { | |
| Status = EFI_INVALID_PARAMETER; | |
| goto Done; | |
| } | |
| // | |
| // Check whether this question is for the requested varstore. | |
| // | |
| IfrTime = (EFI_IFR_TIME *)IfrOpHdr; | |
| if (IfrTime->Question.VarStoreId != VarStoreId) { | |
| break; | |
| } | |
| // | |
| // The BlockData may allocate by other opcode,need to clean. | |
| // | |
| if (BlockData != NULL) { | |
| BlockData = NULL; | |
| } | |
| VarWidth = (UINT16)sizeof (EFI_HII_TIME); | |
| Status = IsThisOpcodeRequired (RequestBlockArray, HiiHandle, VarStorageData, IfrOpHdr, VarWidth, &BlockData, FALSE); | |
| if (EFI_ERROR (Status)) { | |
| if (Status == EFI_NOT_FOUND) { | |
| // | |
| // The opcode is not required,exit and parse other opcode. | |
| // | |
| break; | |
| } | |
| goto Done; | |
| } | |
| 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 (VarStoreId == 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 != VarStoreId) { | |
| break; | |
| } | |
| // | |
| // The BlockData may allocate by other opcode,need to clean. | |
| // | |
| if (BlockData != NULL) { | |
| BlockData = NULL; | |
| } | |
| VarWidth = (UINT16)(IfrString->MaxSize * sizeof (UINT16)); | |
| Status = IsThisOpcodeRequired (RequestBlockArray, HiiHandle, VarStorageData, IfrOpHdr, VarWidth, &BlockData, FALSE); | |
| if (EFI_ERROR (Status)) { | |
| if (Status == EFI_NOT_FOUND) { | |
| // | |
| // The opcode is not required,exit and parse other opcode. | |
| // | |
| break; | |
| } | |
| goto Done; | |
| } | |
| if (IfrEfiVarStoreTmp == NULL) { | |
| break; | |
| } | |
| // | |
| // Set default value base on the DefaultId list get from IFR data. | |
| // | |
| NvDefaultStoreSize = PcdGetSize (PcdNvStoreDefaultValueBuffer); | |
| for (LinkData = DefaultIdArray->Entry.ForwardLink; LinkData != &DefaultIdArray->Entry; LinkData = LinkData->ForwardLink) { | |
| DefaultDataPtr = BASE_CR (LinkData, IFR_DEFAULT_DATA, Entry); | |
| DefaultData.DefaultId = DefaultDataPtr->DefaultId; | |
| if (NvDefaultStoreSize > sizeof (PCD_NV_STORE_DEFAULT_BUFFER_HEADER)) { | |
| StringData = AllocateZeroPool (VarWidth*2); | |
| if (StringData == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto Done; | |
| } | |
| FindQuestionDefaultSetting (DefaultData.DefaultId, IfrEfiVarStoreTmp, &(IfrString->Question), (VOID *)StringData, VarWidth, QuestionReferBitField); | |
| if ((DefaultData.Value.string != 0) && (StringData != NULL)) { | |
| DefaultData.Value.string = InternalHiiSetString (HiiHandle, 0, StringData, NULL); | |
| InsertDefaultValue (BlockData, &DefaultData); | |
| FreePool (StringData); | |
| } | |
| } | |
| } | |
| 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 (VarStoreId == 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 != VarStoreId) { | |
| break; | |
| } | |
| // | |
| // The BlockData may allocate by other opcode,need to clean. | |
| // | |
| if (BlockData != NULL) { | |
| BlockData = NULL; | |
| } | |
| VarWidth = (UINT16)(IfrPassword->MaxSize * sizeof (UINT16)); | |
| Status = IsThisOpcodeRequired (RequestBlockArray, HiiHandle, VarStorageData, IfrOpHdr, VarWidth, &BlockData, FALSE); | |
| if (EFI_ERROR (Status)) { | |
| if (Status == EFI_NOT_FOUND) { | |
| // | |
| // The opcode is not required,exit and parse other opcode. | |
| // | |
| break; | |
| } | |
| goto Done; | |
| } | |
| // | |
| // 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) { | |
| if (!FirstOrderedList) { | |
| break; | |
| } | |
| // | |
| // 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; | |
| if (BlockData->Name != NULL) { | |
| FreePool (BlockData->Name); | |
| } | |
| 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, (BOOLEAN)(BlockData->Name != NULL), HiiHandle)) { | |
| // | |
| // This question is not in the requested string. Skip it. | |
| // | |
| if (BlockData->Name != NULL) { | |
| FreePool (BlockData->Name); | |
| } | |
| FreePool (BlockData); | |
| BlockData = NULL; | |
| break; | |
| } | |
| // | |
| // Check this var question is in the var storage | |
| // | |
| if ((BlockData->Name == NULL) && ((BlockData->Offset + BlockData->Width) > VarStorageData->Size)) { | |
| Status = EFI_INVALID_PARAMETER; | |
| FreePool (BlockData); | |
| goto Done; | |
| } | |
| // | |
| // Add Block Data into VarStorageData BlockEntry | |
| // | |
| InsertBlockData (&VarStorageData->BlockEntry, &BlockData); | |
| FirstOrderedList = FALSE; | |
| break; | |
| } | |
| // | |
| // 1. Set default value for OneOf option when flag field has default attribute. | |
| // And set the default value with the smallest default id for other default id in the DefaultId list. | |
| // | |
| if (((IfrOneOfOption->Flags & EFI_IFR_OPTION_DEFAULT) == EFI_IFR_OPTION_DEFAULT) || | |
| ((IfrOneOfOption->Flags & EFI_IFR_OPTION_DEFAULT_MFG) == EFI_IFR_OPTION_DEFAULT_MFG)) | |
| { | |
| // | |
| // This flag is used to specify whether this option is the first. Set it to FALSE for the following options. | |
| // The first oneof option value will be used as default value when no default value is specified. | |
| // | |
| FirstOneOfOption = FALSE; | |
| SmallestIdFromFlag = FALSE; | |
| // Prepare new DefaultValue | |
| // | |
| DefaultData.Type = DefaultValueFromFlag; | |
| CopyMem (&DefaultData.Value, &IfrOneOfOption->Value, IfrOneOfOption->Header.Length - OFFSET_OF (EFI_IFR_ONE_OF_OPTION, Value)); | |
| if ((IfrOneOfOption->Flags & EFI_IFR_OPTION_DEFAULT) == EFI_IFR_OPTION_DEFAULT) { | |
| DefaultData.DefaultId = EFI_HII_DEFAULT_CLASS_STANDARD; | |
| InsertDefaultValue (BlockData, &DefaultData); | |
| if (SmallestDefaultId > EFI_HII_DEFAULT_CLASS_STANDARD) { | |
| // | |
| // Record the SmallestDefaultId and update the SmallestIdFromFlag. | |
| // | |
| SmallestDefaultId = EFI_HII_DEFAULT_CLASS_STANDARD; | |
| SmallestIdFromFlag = TRUE; | |
| } | |
| } | |
| if ((IfrOneOfOption->Flags & EFI_IFR_OPTION_DEFAULT_MFG) == EFI_IFR_OPTION_DEFAULT_MFG) { | |
| DefaultData.DefaultId = EFI_HII_DEFAULT_CLASS_MANUFACTURING; | |
| InsertDefaultValue (BlockData, &DefaultData); | |
| if (SmallestDefaultId > EFI_HII_DEFAULT_CLASS_MANUFACTURING) { | |
| // | |
| // Record the SmallestDefaultId and update the SmallestIdFromFlag. | |
| // | |
| SmallestDefaultId = EFI_HII_DEFAULT_CLASS_MANUFACTURING; | |
| SmallestIdFromFlag = TRUE; | |
| } | |
| } | |
| if (SmallestIdFromFlag) { | |
| // | |
| // When smallest default Id is given by the flag of oneofOption, set this option value for other default Id in the DefaultId list. | |
| // | |
| DefaultData.Type = DefaultValueFromOtherDefault; | |
| // | |
| // Set default value for other default id in the DefaultId list. | |
| // | |
| for (LinkData = DefaultIdArray->Entry.ForwardLink; LinkData != &DefaultIdArray->Entry; LinkData = LinkData->ForwardLink) { | |
| DefaultDataPtr = BASE_CR (LinkData, IFR_DEFAULT_DATA, Entry); | |
| DefaultData.DefaultId = DefaultDataPtr->DefaultId; | |
| InsertDefaultValue (BlockData, &DefaultData); | |
| } | |
| } | |
| } | |
| // | |
| // 2. Set as the default value when this is the first option. | |
| // The first oneof option value will be used as default value when no default value is specified. | |
| // | |
| if (FirstOneOfOption) { | |
| // This flag is used to specify whether this option is the first. Set it to FALSE for the following options. | |
| FirstOneOfOption = FALSE; | |
| // | |
| // Prepare new DefaultValue | |
| // | |
| DefaultData.Type = DefaultValueFromDefault; | |
| CopyMem (&DefaultData.Value, &IfrOneOfOption->Value, IfrOneOfOption->Header.Length - OFFSET_OF (EFI_IFR_ONE_OF_OPTION, Value)); | |
| for (LinkData = DefaultIdArray->Entry.ForwardLink; LinkData != &DefaultIdArray->Entry; LinkData = LinkData->ForwardLink) { | |
| DefaultDataPtr = BASE_CR (LinkData, IFR_DEFAULT_DATA, Entry); | |
| DefaultData.DefaultId = DefaultDataPtr->DefaultId; | |
| 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; | |
| } | |
| // | |
| // Get the DefaultId | |
| // | |
| IfrDefault = (EFI_IFR_DEFAULT *)IfrOpHdr; | |
| VarDefaultId = IfrDefault->DefaultId; | |
| // | |
| // Prepare new DefaultValue | |
| // | |
| DefaultData.Type = DefaultValueFromOpcode; | |
| DefaultData.DefaultId = VarDefaultId; | |
| if (QuestionReferBitField) { | |
| CopyMem (&DefaultData.Value.u32, &IfrDefault->Value.u32, sizeof (UINT32)); | |
| } else { | |
| CopyMem (&DefaultData.Value, &IfrDefault->Value, IfrDefault->Header.Length - OFFSET_OF (EFI_IFR_DEFAULT, Value)); | |
| } | |
| // If the value field is expression, set the cleaned flag. | |
| if (IfrDefault->Type == EFI_IFR_TYPE_OTHER) { | |
| DefaultData.Cleaned = TRUE; | |
| } | |
| // | |
| // Add DefaultValue into current BlockData | |
| // | |
| InsertDefaultValue (BlockData, &DefaultData); | |
| // | |
| // Set default value for other default id in the DefaultId list. | |
| // when SmallestDefaultId == VarDefaultId means there are two defaults with same default Id. | |
| // If the two defaults are both from default opcode, use the first default as the default value of other default Id. | |
| // If one from flag and the other form default opcode, use the default opcode value as the default value of other default Id. | |
| // | |
| if ((SmallestDefaultId > VarDefaultId) || ((SmallestDefaultId == VarDefaultId) && !FromOtherDefaultOpcode)) { | |
| FromOtherDefaultOpcode = TRUE; | |
| SmallestDefaultId = VarDefaultId; | |
| for (LinkData = DefaultIdArray->Entry.ForwardLink; LinkData != &DefaultIdArray->Entry; LinkData = LinkData->ForwardLink) { | |
| DefaultDataPtr = BASE_CR (LinkData, IFR_DEFAULT_DATA, Entry); | |
| if (DefaultDataPtr->DefaultId != DefaultData.DefaultId) { | |
| DefaultData.Type = DefaultValueFromOtherDefault; | |
| DefaultData.DefaultId = DefaultDataPtr->DefaultId; | |
| InsertDefaultValue (BlockData, &DefaultData); | |
| } | |
| } | |
| } | |
| // | |
| // After insert the default value, reset the cleaned value for next | |
| // time used. If not set here, need to set the value before every time. | |
| // use it. | |
| // | |
| DefaultData.Cleaned = FALSE; | |
| break; | |
| case EFI_IFR_END_OP: | |
| // | |
| // End Opcode is for Var question. | |
| // | |
| QuestionReferBitField = FALSE; | |
| if (BlockData != NULL) { | |
| if (BlockData->Scope > 0) { | |
| BlockData->Scope--; | |
| } | |
| if (BlockData->Scope == 0) { | |
| BlockData = NULL; | |
| // | |
| // when finishing parsing a question, clean the SmallestDefaultId and GetDefaultFromDefaultOpcode. | |
| // | |
| SmallestDefaultId = 0xFFFF; | |
| FromOtherDefaultOpcode = FALSE; | |
| } | |
| } | |
| break; | |
| case EFI_IFR_GUID_OP: | |
| if (CompareGuid ((EFI_GUID *)((UINT8 *)IfrOpHdr + sizeof (EFI_IFR_OP_HEADER)), &gEdkiiIfrBitVarstoreGuid)) { | |
| QuestionReferBitField = TRUE; | |
| } | |
| break; | |
| default: | |
| if (BlockData != NULL) { | |
| if (BlockData->Scope > 0) { | |
| BlockData->Scope = (UINT8)(BlockData->Scope + IfrOpHdr->Scope); | |
| } | |
| if (BlockData->Scope == 0) { | |
| BlockData = NULL; | |
| } | |
| } | |
| break; | |
| } | |
| IfrOffset += IfrOpHdr->Length; | |
| PackageOffset += IfrOpHdr->Length; | |
| } | |
| // | |
| // if Status == EFI_NOT_FOUND, just means the opcode is not required,not contain any error, | |
| // so set the Status to EFI_SUCCESS. | |
| // | |
| if (Status == EFI_NOT_FOUND) { | |
| Status = EFI_SUCCESS; | |
| } | |
| Done: | |
| 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; ) { | |
| DefaultDataPtr = BASE_CR (LinkDefault, IFR_DEFAULT_DATA, Entry); | |
| LinkDefault = LinkDefault->ForwardLink; | |
| if (DefaultDataPtr->Cleaned == TRUE) { | |
| RemoveEntryList (&DefaultDataPtr->Entry); | |
| FreePool (DefaultDataPtr); | |
| } | |
| } | |
| } | |
| if (IfrEfiVarStoreTmp != NULL) { | |
| FreePool (IfrEfiVarStoreTmp); | |
| } | |
| return Status; | |
| } | |
| /** | |
| parse the configrequest string, get the elements. | |
| @param ConfigRequest The input configrequest string. | |
| @param Progress Return the progress data. | |
| @retval Block data pointer. | |
| **/ | |
| IFR_BLOCK_DATA * | |
| GetBlockElement ( | |
| IN EFI_STRING ConfigRequest, | |
| OUT EFI_STRING *Progress | |
| ) | |
| { | |
| EFI_STRING StringPtr; | |
| IFR_BLOCK_DATA *BlockData; | |
| IFR_BLOCK_DATA *RequestBlockArray; | |
| EFI_STATUS Status; | |
| UINT8 *TmpBuffer; | |
| UINT16 Offset; | |
| UINT16 Width; | |
| LIST_ENTRY *Link; | |
| IFR_BLOCK_DATA *NextBlockData; | |
| UINTN Length; | |
| TmpBuffer = NULL; | |
| // | |
| // Init RequestBlockArray | |
| // | |
| RequestBlockArray = (IFR_BLOCK_DATA *)AllocateZeroPool (sizeof (IFR_BLOCK_DATA)); | |
| if (RequestBlockArray == NULL) { | |
| 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> | |
| // | |
| StringPtr = ConfigRequest; | |
| 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) { | |
| 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'&')) { | |
| goto Done; | |
| } | |
| // | |
| // Set Block Data | |
| // | |
| BlockData = (IFR_BLOCK_DATA *)AllocateZeroPool (sizeof (IFR_BLOCK_DATA)); | |
| if (BlockData == NULL) { | |
| 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)) { | |
| goto Done; | |
| } | |
| FreePool (TmpBuffer); | |
| StringPtr += Length; | |
| if ((*StringPtr != 0) && (*StringPtr != L'&')) { | |
| 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; | |
| } | |
| return RequestBlockArray; | |
| 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); | |
| } | |
| return NULL; | |
| } | |
| /** | |
| parse the configrequest string, get the elements. | |
| @param ConfigRequest The input config request string. | |
| @param Progress Return the progress data. | |
| @retval return data block array. | |
| **/ | |
| IFR_BLOCK_DATA * | |
| GetNameElement ( | |
| IN EFI_STRING ConfigRequest, | |
| OUT EFI_STRING *Progress | |
| ) | |
| { | |
| EFI_STRING StringPtr; | |
| EFI_STRING NextTag; | |
| IFR_BLOCK_DATA *BlockData; | |
| IFR_BLOCK_DATA *RequestBlockArray; | |
| BOOLEAN HasValue; | |
| StringPtr = ConfigRequest; | |
| // | |
| // Init RequestBlockArray | |
| // | |
| RequestBlockArray = (IFR_BLOCK_DATA *)AllocateZeroPool (sizeof (IFR_BLOCK_DATA)); | |
| if (RequestBlockArray == NULL) { | |
| goto Done; | |
| } | |
| InitializeListHead (&RequestBlockArray->Entry); | |
| // | |
| // Get the request Block array from the request string | |
| // | |
| // | |
| // Parse each <RequestElement> if exists | |
| // Only <BlockName> format is supported by this help function. | |
| // <BlockName> ::= &'Name***=*** | |
| // | |
| while (StringPtr != NULL && *StringPtr == L'&') { | |
| *Progress = StringPtr; | |
| // | |
| // Skip the L"&" string | |
| // | |
| StringPtr += 1; | |
| HasValue = FALSE; | |
| if ((NextTag = StrStr (StringPtr, L"=")) != NULL) { | |
| *NextTag = L'\0'; | |
| HasValue = TRUE; | |
| } else if ((NextTag = StrStr (StringPtr, L"&")) != NULL) { | |
| *NextTag = L'\0'; | |
| } | |
| // | |
| // Set Block Data | |
| // | |
| BlockData = (IFR_BLOCK_DATA *)AllocateZeroPool (sizeof (IFR_BLOCK_DATA)); | |
| if (BlockData == NULL) { | |
| goto Done; | |
| } | |
| // | |
| // Get Name | |
| // | |
| BlockData->Name = AllocateCopyPool (StrSize (StringPtr), StringPtr); | |
| InsertBlockData (&RequestBlockArray->Entry, &BlockData); | |
| if (HasValue) { | |
| // | |
| // If has value, skip the value. | |
| // | |
| StringPtr = NextTag + 1; | |
| *NextTag = L'='; | |
| StringPtr = StrStr (StringPtr, L"&"); | |
| } else if (NextTag != NULL) { | |
| // | |
| // restore the '&' text. | |
| // | |
| StringPtr = NextTag; | |
| *NextTag = L'&'; | |
| } | |
| } | |
| return RequestBlockArray; | |
| 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); | |
| if (BlockData->Name != NULL) { | |
| FreePool (BlockData->Name); | |
| } | |
| FreePool (BlockData); | |
| } | |
| FreePool (RequestBlockArray); | |
| } | |
| return NULL; | |
| } | |
| /** | |
| Generate ConfigRequest string base on the varstore info. | |
| @param ConfigHdr The config header for this varstore. | |
| @param VarStorageData The varstore info. | |
| @param Status Return Status. | |
| @param ConfigRequest The ConfigRequest info may be return. | |
| @retval TRUE Need to continue | |
| @retval Others NO need to continue or error occur. | |
| **/ | |
| BOOLEAN | |
| GenerateConfigRequest ( | |
| IN CHAR16 *ConfigHdr, | |
| IN IFR_VARSTORAGE_DATA *VarStorageData, | |
| OUT EFI_STATUS *Status, | |
| IN OUT EFI_STRING *ConfigRequest | |
| ) | |
| { | |
| BOOLEAN DataExist; | |
| UINTN Length; | |
| LIST_ENTRY *Link; | |
| CHAR16 *FullConfigRequest; | |
| CHAR16 *StringPtr; | |
| IFR_BLOCK_DATA *BlockData; | |
| // | |
| // 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) { | |
| DataExist = TRUE; | |
| BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry); | |
| if (VarStorageData->Type == EFI_HII_VARSTORE_NAME_VALUE) { | |
| // | |
| // Add <BlockName> length for each Name | |
| // | |
| // <BlockName> ::= &Name1&Name2&... | |
| // |1| StrLen(Name1) | |
| // | |
| Length = Length + (1 + StrLen (BlockData->Name)); | |
| } else { | |
| // | |
| // Add <BlockName> length for each Offset/Width pair | |
| // | |
| // <BlockName> ::= &OFFSET=1234&WIDTH=1234 | |
| // | 8 | 4 | 7 | 4 | | |
| // | |
| 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; | |
| return FALSE; | |
| } | |
| // | |
| // Allocate buffer for the entire <ConfigRequest> | |
| // | |
| FullConfigRequest = AllocateZeroPool (Length * sizeof (CHAR16)); | |
| if (FullConfigRequest == NULL) { | |
| *Status = EFI_OUT_OF_RESOURCES; | |
| return FALSE; | |
| } | |
| StringPtr = FullConfigRequest; | |
| // | |
| // Start with <ConfigHdr> | |
| // | |
| StrCpyS (StringPtr, Length, 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); | |
| if (VarStorageData->Type == EFI_HII_VARSTORE_NAME_VALUE) { | |
| // | |
| // Append &Name1\0 | |
| // | |
| UnicodeSPrint ( | |
| StringPtr, | |
| (1 + StrLen (BlockData->Name) + 1) * sizeof (CHAR16), | |
| L"&%s", | |
| BlockData->Name | |
| ); | |
| } else { | |
| // | |
| // 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 (*ConfigRequest != NULL) { | |
| FreePool (*ConfigRequest); | |
| } | |
| *ConfigRequest = FullConfigRequest; | |
| return TRUE; | |
| } | |
| /** | |
| Generate ConfigRequest Header base on the varstore info. | |
| @param VarStorageData The varstore info. | |
| @param DevicePath Device path for this varstore. | |
| @param ConfigHdr The config header for this varstore. | |
| @retval EFI_SUCCESS Generate the header success. | |
| @retval EFI_OUT_OF_RESOURCES Allocate buffer fail. | |
| **/ | |
| EFI_STATUS | |
| GenerateHdr ( | |
| IN IFR_VARSTORAGE_DATA *VarStorageData, | |
| IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, | |
| OUT EFI_STRING *ConfigHdr | |
| ) | |
| { | |
| EFI_STRING GuidStr; | |
| EFI_STRING NameStr; | |
| EFI_STRING PathStr; | |
| UINTN Length; | |
| EFI_STATUS Status; | |
| Status = EFI_SUCCESS; | |
| NameStr = NULL; | |
| GuidStr = NULL; | |
| PathStr = NULL; | |
| // | |
| // Construct <ConfigHdr> : "GUID=...&NAME=...&PATH=..." by VarStorageData Guid, Name and DriverHandle | |
| // | |
| GenerateSubStr (L"GUID=", sizeof (EFI_GUID), (VOID *)&VarStorageData->Guid, 1, &GuidStr); | |
| if (VarStorageData->Name != NULL) { | |
| GenerateSubStr (L"NAME=", StrLen (VarStorageData->Name) * sizeof (CHAR16), (VOID *)VarStorageData->Name, 2, &NameStr); | |
| } else { | |
| GenerateSubStr (L"NAME=", 0, NULL, 2, &NameStr); | |
| } | |
| GenerateSubStr ( | |
| L"PATH=", | |
| GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *)DevicePath), | |
| (VOID *)DevicePath, | |
| 1, | |
| &PathStr | |
| ); | |
| Length = StrLen (GuidStr) + StrLen (NameStr) + StrLen (PathStr) + 1; | |
| if (VarStorageData->Name == NULL) { | |
| Length += 1; | |
| } | |
| *ConfigHdr = AllocateZeroPool (Length * sizeof (CHAR16)); | |
| if (*ConfigHdr == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto Done; | |
| } | |
| StrCpyS (*ConfigHdr, Length, GuidStr); | |
| StrCatS (*ConfigHdr, Length, NameStr); | |
| if (VarStorageData->Name == NULL) { | |
| StrCatS (*ConfigHdr, Length, L"&"); | |
| } | |
| StrCatS (*ConfigHdr, Length, PathStr); | |
| // | |
| // Remove the last character L'&' | |
| // | |
| *(*ConfigHdr + StrLen (*ConfigHdr) - 1) = L'\0'; | |
| Done: | |
| if (GuidStr != NULL) { | |
| FreePool (GuidStr); | |
| } | |
| if (NameStr != NULL) { | |
| FreePool (NameStr); | |
| } | |
| if (PathStr != NULL) { | |
| FreePool (PathStr); | |
| } | |
| return Status; | |
| } | |
| /** | |
| Update the default value in the block data which is used as bit var store. | |
| For example: | |
| A question value saved in a bit fied: bitoffset = 1; bitwidth = 2;default value = 1. | |
| And corresponding block data info: offset==0; width==1;currently the default value | |
| is saved as 1.Actually the default value 1 need to be set to bit field 1, so the | |
| default value of this block data shuold be:2. | |
| typedef struct { | |
| UINT8 Bit1 : 1; // | |
| UINT8 Bit2 : 2; // Question saved in Bit2,so originalBlock info: offset = 0; width = 1;(byte level) defaul = 1. | |
| // (default value record for the bit field) | |
| ...... | |
| }ExampleData; | |
| After function UpdateDefaultValue,the Block info is: offset = 0; width = 1;(byte level) default = 2. | |
| (default value record for the Block) | |
| UpdateDefaultValue function update default value of bit var block based on the bit field info in the block. | |
| @param BlockLink The Link of the block data. | |
| **/ | |
| VOID | |
| UpdateDefaultValue ( | |
| IN LIST_ENTRY *BlockLink | |
| ) | |
| { | |
| LIST_ENTRY *Link; | |
| LIST_ENTRY *ListEntry; | |
| LIST_ENTRY *LinkDefault; | |
| IFR_BLOCK_DATA *BlockData; | |
| IFR_DEFAULT_DATA *DefaultValueData; | |
| UINTN StartBit; | |
| UINTN EndBit; | |
| UINT32 BitFieldDefaultValue; | |
| for ( Link = BlockLink->ForwardLink; Link != BlockLink; Link = Link->ForwardLink) { | |
| BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry); | |
| if (!BlockData->IsBitVar) { | |
| continue; | |
| } | |
| ListEntry = &BlockData->DefaultValueEntry; | |
| // | |
| // Update the default value in the block data with all existing default id. | |
| // | |
| for (LinkDefault = ListEntry->ForwardLink; LinkDefault != ListEntry; LinkDefault = LinkDefault->ForwardLink) { | |
| // | |
| // Get the default data, and the value of the default data is for some field in the block. | |
| // Note: Default value for bit field question is stored as UINT32. | |
| // | |
| DefaultValueData = BASE_CR (LinkDefault, IFR_DEFAULT_DATA, Entry); | |
| BitFieldDefaultValue = DefaultValueData->Value.u32; | |
| StartBit = BlockData->BitOffset % 8; | |
| EndBit = StartBit + BlockData->BitWidth - 1; | |
| // | |
| // Set the bit field default value to related bit filed, then we will got the new default vaule for the block data. | |
| // | |
| DefaultValueData->Value.u32 = BitFieldWrite32 (0, StartBit, EndBit, BitFieldDefaultValue); | |
| } | |
| } | |
| } | |
| /** | |
| Merge the default value in two block datas which have overlap region. | |
| For bit fields, their related block data may have overlap region, such as: | |
| typedef struct { | |
| UINT16 Bit1 : 6; // Question1 refer Bit1, Block1: offset = 0; width = 1;(byte level) default = 1 | |
| UINT16 Bit2 : 5; // Question2 refer Bit2, Block2: offset = 0; width = 2;(byte level) default = 5 | |
| // (default value record for the bit field) | |
| ...... | |
| }ExampleData; | |
| After function UpdateDefaultValue: | |
| Block1: offset = 0; width = 1;(byte level) default = 1 | |
| Block2: offset = 0; width = 2;(byte level) default = 320 (5 * (2 << 6)) | |
| (default value record for block) | |
| After function MergeBlockDefaultValue: | |
| Block1: offset = 0; width = 1;(byte level) default = 65 | |
| Block2: offset = 0; width = 2;(byte level) default = 321 | |
| (Block1 and Block2 has overlap region, merge the overlap value to Block1 and Blcok2) | |
| Block1 and Block2 have overlap byte region, but currntly the default value of Block1 only contains | |
| value of Bit1 (low 6 bits),the default value of Block2 only contains the value of Bit2 (middle 5 bits). | |
| This fuction merge the default value of these two blocks, and make the default value of block1 | |
| also contain the value of lower 2 bits of the Bit2. And make the default value of Block2 also | |
| contain the default value of Bit1. | |
| We can get the total value of the whole block that just cover these two blocks(in this case is: | |
| block: offset =0; width =2;) then the value of block2 is same as block, the value of block1 is | |
| the first byte value of block. | |
| @param FirstBlock Point to the block date whose default value need to be merged. | |
| @param SecondBlock Point to the block date whose default value need to be merged. | |
| **/ | |
| VOID | |
| MergeBlockDefaultValue ( | |
| IN OUT IFR_BLOCK_DATA *FirstBlock, | |
| IN OUT IFR_BLOCK_DATA *SecondBlock | |
| ) | |
| { | |
| LIST_ENTRY *FirstListEntry; | |
| LIST_ENTRY *SecondListEntry; | |
| LIST_ENTRY *FirstDefaultLink; | |
| LIST_ENTRY *SecondDefaultLink; | |
| IFR_DEFAULT_DATA *FirstDefaultValueData; | |
| IFR_DEFAULT_DATA *SecondDefaultValueData; | |
| UINT32 *FirstDefaultValue; | |
| UINT32 *SecondDefaultValue; | |
| UINT64 TotalValue; | |
| UINT64 ShiftedValue; | |
| UINT16 OffsetShift; | |
| FirstListEntry = &FirstBlock->DefaultValueEntry; | |
| for (FirstDefaultLink = FirstListEntry->ForwardLink; FirstDefaultLink != FirstListEntry; FirstDefaultLink = FirstDefaultLink->ForwardLink) { | |
| FirstDefaultValueData = BASE_CR (FirstDefaultLink, IFR_DEFAULT_DATA, Entry); | |
| SecondListEntry = &SecondBlock->DefaultValueEntry; | |
| for (SecondDefaultLink = SecondListEntry->ForwardLink; SecondDefaultLink != SecondListEntry; SecondDefaultLink = SecondDefaultLink->ForwardLink) { | |
| SecondDefaultValueData = BASE_CR (SecondDefaultLink, IFR_DEFAULT_DATA, Entry); | |
| if (FirstDefaultValueData->DefaultId != SecondDefaultValueData->DefaultId) { | |
| continue; | |
| } | |
| // | |
| // Find default value with same default id in the two blocks. | |
| // Note: Default value for bit field question is stored as UINT32 type. | |
| // | |
| FirstDefaultValue = &FirstDefaultValueData->Value.u32; | |
| SecondDefaultValue = &SecondDefaultValueData->Value.u32; | |
| // | |
| // 1. Get the default value of the whole blcok that can just cover FirstBlock and SecondBlock. | |
| // 2. Get the default value of FirstBlock and SecondBlock form the value of whole block based | |
| // on the offset and width of FirstBlock and SecondBlock. | |
| // | |
| if (FirstBlock->Offset > SecondBlock->Offset) { | |
| OffsetShift = FirstBlock->Offset - SecondBlock->Offset; | |
| ShiftedValue = LShiftU64 ((UINT64)(*FirstDefaultValue), OffsetShift * 8); | |
| TotalValue = ShiftedValue | (UINT64)(*SecondDefaultValue); | |
| *SecondDefaultValue = (UINT32)BitFieldRead64 (TotalValue, 0, SecondBlock->Width * 8 -1); | |
| *FirstDefaultValue = (UINT32)BitFieldRead64 (TotalValue, OffsetShift * 8, OffsetShift * 8 + FirstBlock->Width *8 -1); | |
| } else { | |
| OffsetShift = SecondBlock->Offset -FirstBlock->Offset; | |
| ShiftedValue = LShiftU64 ((UINT64)(*SecondDefaultValue), OffsetShift * 8); | |
| TotalValue = ShiftedValue | (UINT64)(*FirstDefaultValue); | |
| *FirstDefaultValue = (UINT32)BitFieldRead64 (TotalValue, 0, FirstBlock->Width * 8 -1); | |
| *SecondDefaultValue = (UINT32)BitFieldRead64 (TotalValue, OffsetShift * 8, OffsetShift * 8 + SecondBlock->Width *8 -1); | |
| } | |
| } | |
| } | |
| } | |
| /** | |
| Update the default value in the block data which used as Bit VarStore | |
| @param BlockLink The Link of the block data. | |
| **/ | |
| VOID | |
| UpdateBlockDataArray ( | |
| IN LIST_ENTRY *BlockLink | |
| ) | |
| { | |
| LIST_ENTRY *Link; | |
| LIST_ENTRY *TempLink; | |
| IFR_BLOCK_DATA *BlockData; | |
| IFR_BLOCK_DATA *NextBlockData; | |
| // | |
| // 1. Update default value in BitVar block data. | |
| // Sine some block datas are used as BitVarStore, then the default value recored in the block | |
| // is for related bit field in the block. so we need to set the default value to the related bit | |
| // fields in the block data if the block data is used as bit varstore, then the default value of | |
| // the block will be updated. | |
| // | |
| UpdateDefaultValue (BlockLink); | |
| // | |
| // 2.Update default value for overlap BitVar blcok datas. | |
| // For block datas have overlap region, we need to merge the default value in different blocks. | |
| // | |
| for (Link = BlockLink->ForwardLink; Link != BlockLink; Link = Link->ForwardLink) { | |
| BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry); | |
| if (!BlockData->IsBitVar) { | |
| continue; | |
| } | |
| for (TempLink = Link->ForwardLink; TempLink != BlockLink; TempLink = TempLink->ForwardLink) { | |
| NextBlockData = BASE_CR (TempLink, IFR_BLOCK_DATA, Entry); | |
| if (!NextBlockData->IsBitVar || (NextBlockData->Offset >= BlockData->Offset + BlockData->Width) || (BlockData->Offset >= NextBlockData->Offset + NextBlockData->Width)) { | |
| continue; | |
| } | |
| // | |
| // Find two blocks are used as bit VarStore and have overlap region, so need to merge default value of these two blocks. | |
| // | |
| MergeBlockDefaultValue (BlockData, NextBlockData); | |
| } | |
| } | |
| } | |
| /** | |
| Generate ConfigAltResp string base on the varstore info. | |
| @param HiiHandle Hii Handle for this hii package. | |
| @param ConfigHdr The config header for this varstore. | |
| @param VarStorageData The varstore info. | |
| @param DefaultIdArray The Default id array. | |
| @param DefaultAltCfgResp The DefaultAltCfgResp info may be return. | |
| @retval TRUE Need to continue | |
| @retval Others NO need to continue or error occur. | |
| **/ | |
| EFI_STATUS | |
| GenerateAltConfigResp ( | |
| IN EFI_HII_HANDLE HiiHandle, | |
| IN CHAR16 *ConfigHdr, | |
| IN IFR_VARSTORAGE_DATA *VarStorageData, | |
| IN IFR_DEFAULT_DATA *DefaultIdArray, | |
| IN OUT EFI_STRING *DefaultAltCfgResp | |
| ) | |
| { | |
| BOOLEAN DataExist; | |
| UINTN Length; | |
| LIST_ENTRY *Link; | |
| LIST_ENTRY *LinkData; | |
| LIST_ENTRY *LinkDefault; | |
| LIST_ENTRY *ListEntry; | |
| CHAR16 *StringPtr; | |
| IFR_BLOCK_DATA *BlockData; | |
| IFR_DEFAULT_DATA *DefaultId; | |
| IFR_DEFAULT_DATA *DefaultValueData; | |
| UINTN Width; | |
| UINT8 *TmpBuffer; | |
| CHAR16 *DefaultString; | |
| UINTN StrSize; | |
| BlockData = NULL; | |
| DataExist = FALSE; | |
| DefaultString = NULL; | |
| // | |
| // Add length for <ConfigHdr> + '\0' | |
| // | |
| Length = StrLen (ConfigHdr) + 1; | |
| UpdateBlockDataArray (&VarStorageData->BlockEntry); | |
| 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); | |
| ListEntry = &BlockData->DefaultValueEntry; | |
| for (LinkDefault = ListEntry->ForwardLink; LinkDefault != ListEntry; LinkDefault = LinkDefault->ForwardLink) { | |
| DefaultValueData = BASE_CR (LinkDefault, IFR_DEFAULT_DATA, Entry); | |
| if (DefaultValueData->DefaultId != DefaultId->DefaultId) { | |
| continue; | |
| } | |
| if (VarStorageData->Type == EFI_HII_VARSTORE_NAME_VALUE) { | |
| // | |
| // Add length for "&Name1=zzzzzzzzzzzz" | |
| // |1|Name|1|Value| | |
| // | |
| Length += (1 + StrLen (BlockData->Name) + 1 + BlockData->Width * 2); | |
| } else { | |
| // | |
| // 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) { | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // Allocate buffer for the entire <DefaultAltCfgResp> | |
| // | |
| *DefaultAltCfgResp = AllocateZeroPool (Length * sizeof (CHAR16)); | |
| if (*DefaultAltCfgResp == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| StringPtr = *DefaultAltCfgResp; | |
| // | |
| // Start with <ConfigHdr> | |
| // | |
| StrCpyS (StringPtr, Length, 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->DefaultId | |
| ); | |
| StringPtr += StrLen (StringPtr); | |
| for (LinkData = VarStorageData->BlockEntry.ForwardLink; LinkData != &VarStorageData->BlockEntry; LinkData = LinkData->ForwardLink) { | |
| BlockData = BASE_CR (LinkData, IFR_BLOCK_DATA, Entry); | |
| ListEntry = &BlockData->DefaultValueEntry; | |
| for (LinkDefault = ListEntry->ForwardLink; LinkDefault != ListEntry; LinkDefault = LinkDefault->ForwardLink) { | |
| DefaultValueData = BASE_CR (LinkDefault, IFR_DEFAULT_DATA, Entry); | |
| if (DefaultValueData->DefaultId != DefaultId->DefaultId) { | |
| continue; | |
| } | |
| if (VarStorageData->Type == EFI_HII_VARSTORE_NAME_VALUE) { | |
| UnicodeSPrint ( | |
| StringPtr, | |
| (1 + StrLen (ConfigHdr) + 1) * sizeof (CHAR16), | |
| L"&%s=", | |
| BlockData->Name | |
| ); | |
| StringPtr += StrLen (StringPtr); | |
| } else { | |
| // | |
| // 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); | |
| } | |
| Width = BlockData->Width; | |
| // | |
| // Convert Value to a hex string in "%x" format | |
| // NOTE: This is in the opposite byte that GUID and PATH use | |
| // | |
| if (BlockData->OpCode == EFI_IFR_STRING_OP) { | |
| DefaultString = InternalGetString (HiiHandle, DefaultValueData->Value.string); | |
| TmpBuffer = AllocateZeroPool (Width); | |
| ASSERT (TmpBuffer != NULL); | |
| if (DefaultString != NULL) { | |
| StrSize = StrLen (DefaultString)* sizeof (CHAR16); | |
| if (StrSize > Width) { | |
| StrSize = Width; | |
| } | |
| CopyMem (TmpBuffer, (UINT8 *)DefaultString, StrSize); | |
| } | |
| } else { | |
| TmpBuffer = (UINT8 *)&(DefaultValueData->Value); | |
| } | |
| for ( ; Width > 0 && (TmpBuffer != NULL); Width--) { | |
| UnicodeValueToStringS ( | |
| StringPtr, | |
| Length * sizeof (CHAR16) - ((UINTN)StringPtr - (UINTN)*DefaultAltCfgResp), | |
| PREFIX_ZERO | RADIX_HEX, | |
| TmpBuffer[Width - 1], | |
| 2 | |
| ); | |
| StringPtr += StrnLenS (StringPtr, Length - ((UINTN)StringPtr - (UINTN)*DefaultAltCfgResp) / sizeof (CHAR16)); | |
| } | |
| if (DefaultString != NULL) { | |
| FreePool (DefaultString); | |
| DefaultString = NULL; | |
| } | |
| if ((BlockData->OpCode == EFI_IFR_STRING_OP) && (TmpBuffer != NULL)) { | |
| FreePool (TmpBuffer); | |
| TmpBuffer = NULL; | |
| } | |
| } | |
| } | |
| } | |
| HiiToLower (*DefaultAltCfgResp); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| 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 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; | |
| IFR_BLOCK_DATA *RequestBlockArray; | |
| IFR_BLOCK_DATA *BlockData; | |
| IFR_DEFAULT_DATA *DefaultValueData; | |
| IFR_DEFAULT_DATA *DefaultId; | |
| IFR_DEFAULT_DATA *DefaultIdArray; | |
| IFR_VARSTORAGE_DATA *VarStorageData; | |
| EFI_STRING DefaultAltCfgResp; | |
| EFI_STRING ConfigHdr; | |
| EFI_STRING StringPtr; | |
| EFI_STRING Progress; | |
| 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; | |
| ConfigHdr = NULL; | |
| HiiFormPackage = NULL; | |
| PackageSize = 0; | |
| Progress = *Request; | |
| Status = GetFormPackageData (DataBaseRecord, &HiiFormPackage, &PackageSize); | |
| if (EFI_ERROR (Status)) { | |
| goto Done; | |
| } | |
| // | |
| // 1. Get the request block array by Request String when Request string contains 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++; | |
| } | |
| if (*StringPtr == L'\0') { | |
| // | |
| // No request block is found. | |
| // | |
| StringPtr = NULL; | |
| } | |
| } | |
| // | |
| // If StringPtr != NULL, get the request elements. | |
| // | |
| if (StringPtr != NULL) { | |
| if (StrStr (StringPtr, L"&OFFSET=") != NULL) { | |
| RequestBlockArray = GetBlockElement (StringPtr, &Progress); | |
| } else { | |
| RequestBlockArray = GetNameElement (StringPtr, &Progress); | |
| } | |
| if (RequestBlockArray == NULL) { | |
| Status = EFI_INVALID_PARAMETER; | |
| goto Done; | |
| } | |
| } | |
| // | |
| // 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); | |
| // | |
| // 2. Parse FormPackage to get BlockArray and DefaultId Array for the request BlockArray. | |
| // | |
| // | |
| // Parse the opcode in form package to get the default setting. | |
| // | |
| Status = ParseIfrData ( | |
| DataBaseRecord->Handle, | |
| HiiFormPackage, | |
| (UINT32)PackageSize, | |
| *Request, | |
| RequestBlockArray, | |
| VarStorageData, | |
| DefaultIdArray | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto Done; | |
| } | |
| // | |
| // No requested varstore in IFR data and directly return | |
| // | |
| if ((VarStorageData->Type == 0) && (VarStorageData->Name == NULL)) { | |
| Status = EFI_SUCCESS; | |
| goto Done; | |
| } | |
| // | |
| // 3. Construct Request Element (Block Name) for 2.1 and 2.2 case. | |
| // | |
| Status = GenerateHdr (VarStorageData, DevicePath, &ConfigHdr); | |
| if (EFI_ERROR (Status)) { | |
| goto Done; | |
| } | |
| if (RequestBlockArray == NULL) { | |
| if (!GenerateConfigRequest (ConfigHdr, VarStorageData, &Status, Request)) { | |
| goto Done; | |
| } | |
| } | |
| // | |
| // 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 | |
| // | |
| Status = GenerateAltConfigResp (DataBaseRecord->Handle, ConfigHdr, VarStorageData, DefaultIdArray, &DefaultAltCfgResp); | |
| if (EFI_ERROR (Status)) { | |
| goto Done; | |
| } | |
| // | |
| // 5. Merge string into the input AltCfgResp if the input *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); | |
| if (BlockData->Name != NULL) { | |
| FreePool (BlockData->Name); | |
| } | |
| 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); | |
| if (BlockData->Name != NULL) { | |
| FreePool (BlockData->Name); | |
| } | |
| // | |
| // 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); | |
| } | |
| if (VarStorageData->Name != NULL) { | |
| FreePool (VarStorageData->Name); | |
| VarStorageData->Name = NULL; | |
| } | |
| 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 (ConfigHdr != NULL) { | |
| FreePool (ConfigHdr); | |
| } | |
| // | |
| // Free Package data | |
| // | |
| if (HiiFormPackage != NULL) { | |
| FreePool (HiiFormPackage); | |
| } | |
| if (PointerProgress != NULL) { | |
| if (*Request == NULL) { | |
| *PointerProgress = NULL; | |
| } else if (EFI_ERROR (Status)) { | |
| *PointerProgress = *Request; | |
| } else { | |
| *PointerProgress = *Request + StrLen (*Request); | |
| } | |
| } | |
| return Status; | |
| } | |
| /** | |
| This function gets the full request resp string by | |
| parsing IFR data in HII form packages. | |
| @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL | |
| instance. | |
| @param EfiVarStoreInfo The efi varstore info which is save in the EFI | |
| varstore data structure. | |
| @param Request Pointer to a null-terminated Unicode string in | |
| <ConfigRequest> format. | |
| @param RequestResp Pointer to a null-terminated Unicode string in | |
| <ConfigResp> format. | |
| @param AccessProgress 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_INVALID_PARAMETER Request points to NULL. | |
| **/ | |
| EFI_STATUS | |
| GetConfigRespFromEfiVarStore ( | |
| IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This, | |
| IN EFI_IFR_VARSTORE_EFI *EfiVarStoreInfo, | |
| IN EFI_STRING Request, | |
| OUT EFI_STRING *RequestResp, | |
| OUT EFI_STRING *AccessProgress | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_STRING VarStoreName; | |
| UINTN NameSize; | |
| UINT8 *VarStore; | |
| UINTN BufferSize; | |
| Status = EFI_SUCCESS; | |
| BufferSize = 0; | |
| VarStore = NULL; | |
| VarStoreName = NULL; | |
| *AccessProgress = Request; | |
| NameSize = AsciiStrSize ((CHAR8 *)EfiVarStoreInfo->Name); | |
| VarStoreName = AllocateZeroPool (NameSize * sizeof (CHAR16)); | |
| if (VarStoreName == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto Done; | |
| } | |
| AsciiStrToUnicodeStrS ((CHAR8 *)EfiVarStoreInfo->Name, VarStoreName, NameSize); | |
| Status = gRT->GetVariable (VarStoreName, &EfiVarStoreInfo->Guid, NULL, &BufferSize, NULL); | |
| if (Status != EFI_BUFFER_TOO_SMALL) { | |
| goto Done; | |
| } | |
| VarStore = AllocateZeroPool (BufferSize); | |
| ASSERT (VarStore != NULL); | |
| Status = gRT->GetVariable (VarStoreName, &EfiVarStoreInfo->Guid, NULL, &BufferSize, VarStore); | |
| if (EFI_ERROR (Status)) { | |
| goto Done; | |
| } | |
| Status = HiiBlockToConfig (This, Request, VarStore, BufferSize, RequestResp, AccessProgress); | |
| if (EFI_ERROR (Status)) { | |
| goto Done; | |
| } | |
| Done: | |
| if (VarStoreName != NULL) { | |
| FreePool (VarStoreName); | |
| } | |
| if (VarStore != NULL) { | |
| FreePool (VarStore); | |
| } | |
| return Status; | |
| } | |
| /** | |
| This function route the full request resp string for efi varstore. | |
| @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL | |
| instance. | |
| @param EfiVarStoreInfo The efi varstore info which is save in the EFI | |
| varstore data structure. | |
| @param RequestResp Pointer to a null-terminated Unicode string in | |
| <ConfigResp> format. | |
| @param Result Pointer to a null-terminated Unicode string in | |
| <ConfigResp> format. | |
| @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_INVALID_PARAMETER Request points to NULL. | |
| **/ | |
| EFI_STATUS | |
| RouteConfigRespForEfiVarStore ( | |
| IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This, | |
| IN EFI_IFR_VARSTORE_EFI *EfiVarStoreInfo, | |
| IN EFI_STRING RequestResp, | |
| OUT EFI_STRING *Result | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_STRING VarStoreName; | |
| UINTN NameSize; | |
| UINT8 *VarStore; | |
| UINTN BufferSize; | |
| UINTN BlockSize; | |
| Status = EFI_SUCCESS; | |
| BufferSize = 0; | |
| VarStore = NULL; | |
| VarStoreName = NULL; | |
| *Result = RequestResp; | |
| NameSize = AsciiStrSize ((CHAR8 *)EfiVarStoreInfo->Name); | |
| VarStoreName = AllocateZeroPool (NameSize * sizeof (CHAR16)); | |
| if (VarStoreName == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto Done; | |
| } | |
| AsciiStrToUnicodeStrS ((CHAR8 *)EfiVarStoreInfo->Name, VarStoreName, NameSize); | |
| Status = gRT->GetVariable (VarStoreName, &EfiVarStoreInfo->Guid, NULL, &BufferSize, NULL); | |
| if (Status != EFI_BUFFER_TOO_SMALL) { | |
| DEBUG ((DEBUG_ERROR, "The variable does not exist!")); | |
| goto Done; | |
| } | |
| BlockSize = BufferSize; | |
| VarStore = AllocateZeroPool (BufferSize); | |
| ASSERT (VarStore != NULL); | |
| Status = gRT->GetVariable (VarStoreName, &EfiVarStoreInfo->Guid, NULL, &BufferSize, VarStore); | |
| if (EFI_ERROR (Status)) { | |
| goto Done; | |
| } | |
| Status = HiiConfigToBlock (This, RequestResp, VarStore, &BlockSize, Result); | |
| if (EFI_ERROR (Status)) { | |
| goto Done; | |
| } | |
| Status = gRT->SetVariable (VarStoreName, &EfiVarStoreInfo->Guid, EfiVarStoreInfo->Attributes, BufferSize, VarStore); | |
| if (EFI_ERROR (Status)) { | |
| *Result = RequestResp; | |
| goto Done; | |
| } | |
| Done: | |
| if (VarStoreName != NULL) { | |
| FreePool (VarStoreName); | |
| } | |
| if (VarStore != NULL) { | |
| FreePool (VarStore); | |
| } | |
| return Status; | |
| } | |
| /** | |
| Validate the config request elements. | |
| @param ConfigElements A null-terminated Unicode string in <ConfigRequest> format, | |
| without configHdr field. | |
| @retval CHAR16 * THE first Name/value pair not correct. | |
| @retval NULL Success parse the name/value pair | |
| **/ | |
| CHAR16 * | |
| OffsetWidthValidate ( | |
| CHAR16 *ConfigElements | |
| ) | |
| { | |
| CHAR16 *StringPtr; | |
| CHAR16 *RetVal; | |
| StringPtr = ConfigElements; | |
| while (1) { | |
| RetVal = StringPtr; | |
| if (StrnCmp (StringPtr, L"&OFFSET=", StrLen (L"&OFFSET=")) != 0) { | |
| return RetVal; | |
| } | |
| while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) { | |
| StringPtr++; | |
| } | |
| if (*StringPtr == L'\0') { | |
| return RetVal; | |
| } | |
| StringPtr += StrLen (L"&WIDTH="); | |
| while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&OFFSET=", StrLen (L"&OFFSET=")) != 0) { | |
| StringPtr++; | |
| } | |
| if (*StringPtr == L'\0') { | |
| return NULL; | |
| } | |
| } | |
| } | |
| /** | |
| Validate the config request elements. | |
| @param ConfigElements A null-terminated Unicode string in <ConfigRequest> format, | |
| without configHdr field. | |
| @retval CHAR16 * THE first Name/value pair not correct. | |
| @retval NULL Success parse the name/value pair | |
| **/ | |
| CHAR16 * | |
| NameValueValidate ( | |
| CHAR16 *ConfigElements | |
| ) | |
| { | |
| CHAR16 *StringPtr; | |
| CHAR16 *RetVal; | |
| StringPtr = ConfigElements; | |
| while (1) { | |
| RetVal = StringPtr; | |
| if (*StringPtr != L'&') { | |
| return RetVal; | |
| } | |
| StringPtr += 1; | |
| StringPtr = StrStr (StringPtr, L"&"); | |
| if (StringPtr == NULL) { | |
| return NULL; | |
| } | |
| } | |
| } | |
| /** | |
| Validate the config request string. | |
| @param ConfigRequest A null-terminated Unicode string in <ConfigRequest> format. | |
| @retval CHAR16 * THE first element not correct. | |
| @retval NULL Success parse the name/value pair | |
| **/ | |
| CHAR16 * | |
| ConfigRequestValidate ( | |
| CHAR16 *ConfigRequest | |
| ) | |
| { | |
| BOOLEAN HasNameField; | |
| CHAR16 *StringPtr; | |
| HasNameField = TRUE; | |
| StringPtr = ConfigRequest; | |
| // | |
| // Check <ConfigHdr> | |
| // | |
| if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) { | |
| return ConfigRequest; | |
| } | |
| StringPtr += StrLen (L"GUID="); | |
| while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&NAME=", StrLen (L"&NAME=")) != 0) { | |
| StringPtr++; | |
| } | |
| if (*StringPtr == L'\0') { | |
| return ConfigRequest; | |
| } | |
| StringPtr += StrLen (L"&NAME="); | |
| if (*StringPtr == L'&') { | |
| HasNameField = FALSE; | |
| } | |
| while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&PATH=", StrLen (L"&PATH=")) != 0) { | |
| StringPtr++; | |
| } | |
| if (*StringPtr == L'\0') { | |
| return ConfigRequest; | |
| } | |
| StringPtr += StrLen (L"&PATH="); | |
| while (*StringPtr != L'\0' && *StringPtr != L'&') { | |
| StringPtr++; | |
| } | |
| if (*StringPtr == L'\0') { | |
| return NULL; | |
| } | |
| if (HasNameField) { | |
| // | |
| // Should be Buffer varstore, config request should be "OFFSET/Width" pairs. | |
| // | |
| return OffsetWidthValidate (StringPtr); | |
| } else { | |
| // | |
| // Should be Name/Value varstore, config request should be "&name1&name2..." pairs. | |
| // | |
| return NameValueValidate (StringPtr); | |
| } | |
| } | |
| /** | |
| 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 The ExtractConfig function of the underlying HII | |
| Configuration Access Protocol returned | |
| EFI_INVALID_PARAMETER. Progress set to most recent | |
| & before the error or the beginning of the string. | |
| **/ | |
| 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 AccessProgressBackup; | |
| EFI_STRING AccessResultsBackup; | |
| EFI_STRING DefaultResults; | |
| BOOLEAN FirstElement; | |
| BOOLEAN IfrDataParsedFlag; | |
| BOOLEAN IsEfiVarStore; | |
| EFI_IFR_VARSTORE_EFI *EfiVarStoreInfo; | |
| EFI_STRING ErrorPtr; | |
| UINTN DevicePathSize; | |
| UINTN ConigStringSize; | |
| UINTN ConigStringSizeNewsize; | |
| EFI_STRING ConfigStringPtr; | |
| 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; | |
| AccessProgress = NULL; | |
| AccessResultsBackup = NULL; | |
| AccessProgressBackup = NULL; | |
| DevicePath = NULL; | |
| IfrDataParsedFlag = FALSE; | |
| IsEfiVarStore = FALSE; | |
| EfiVarStoreInfo = NULL; | |
| // | |
| // 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); | |
| DevicePathSize = GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *)CurrentDevicePath); | |
| if ((CompareMem (DevicePath, CurrentDevicePath, DevicePathSize) == 0) && IsThisPackageList (Database, ConfigRequest)) { | |
| 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; | |
| } | |
| } | |
| // | |
| // Validate ConfigRequest String. | |
| // | |
| ErrorPtr = ConfigRequestValidate (ConfigRequest); | |
| if (ErrorPtr != NULL) { | |
| *Progress = StrStr (StringPtr, ErrorPtr); | |
| Status = EFI_INVALID_PARAMETER; | |
| goto Done; | |
| } | |
| // | |
| // Check whether ConfigRequest contains request string. | |
| // | |
| IfrDataParsedFlag = FALSE; | |
| if ((HiiHandle != NULL) && !GetElementsFromRequest (ConfigRequest)) { | |
| // | |
| // 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. | |
| // | |
| ASSERT (AccessProgress != NULL); | |
| *Progress = StrStr (StringPtr, AccessProgress); | |
| goto Done; | |
| } | |
| // | |
| // Not any request block is found. | |
| // | |
| if (!GetElementsFromRequest (ConfigRequest)) { | |
| AccessResults = AllocateCopyPool (StrSize (ConfigRequest), ConfigRequest); | |
| goto NextConfigString; | |
| } | |
| } | |
| // | |
| // Check whether this ConfigRequest is search from Efi varstore type storage. | |
| // | |
| Status = GetVarStoreType (Database, ConfigRequest, &IsEfiVarStore, &EfiVarStoreInfo); | |
| if (EFI_ERROR (Status)) { | |
| goto Done; | |
| } | |
| if (IsEfiVarStore) { | |
| // | |
| // Call the GetVariable function to extract settings. | |
| // | |
| Status = GetConfigRespFromEfiVarStore (This, EfiVarStoreInfo, ConfigRequest, &AccessResults, &AccessProgress); | |
| FreePool (EfiVarStoreInfo); | |
| 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; | |
| } | |
| // | |
| // For EfiVarstore, call corresponding ConfigAccess protocol to get the AltCfgResp from driver. | |
| // | |
| Status = gBS->HandleProtocol ( | |
| DriverHandle, | |
| &gEfiHiiConfigAccessProtocolGuid, | |
| (VOID **)&ConfigAccess | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| // | |
| // The driver has EfiVarStore, may not install ConfigAccess protocol. | |
| // So ignore the error status in this case. | |
| // | |
| Status = EFI_SUCCESS; | |
| } else { | |
| Status = ConfigAccess->ExtractConfig ( | |
| ConfigAccess, | |
| ConfigRequest, | |
| &AccessProgressBackup, | |
| &AccessResultsBackup | |
| ); | |
| if (!EFI_ERROR (Status)) { | |
| // | |
| // Merge the AltCfgResp in AccessResultsBackup to AccessResults | |
| // | |
| if ((AccessResultsBackup != NULL) && (StrStr (AccessResultsBackup, L"&ALTCFG=") != NULL)) { | |
| ConigStringSize = StrSize (AccessResults); | |
| ConfigStringPtr = StrStr (AccessResultsBackup, L"&GUID="); | |
| ConigStringSizeNewsize = StrSize (ConfigStringPtr) + ConigStringSize + sizeof (CHAR16); | |
| AccessResults = (EFI_STRING)ReallocatePool ( | |
| ConigStringSize, | |
| ConigStringSizeNewsize, | |
| AccessResults | |
| ); | |
| StrCatS (AccessResults, ConigStringSizeNewsize / sizeof (CHAR16), ConfigStringPtr); | |
| } | |
| } else { | |
| // | |
| // In the ExtractConfig function of some driver may not support EfiVarStore, | |
| // may return error status, just ignore the error status in this case. | |
| // | |
| Status = EFI_SUCCESS; | |
| } | |
| if (AccessResultsBackup != NULL) { | |
| FreePool (AccessResultsBackup); | |
| AccessResultsBackup = NULL; | |
| } | |
| } | |
| } else { | |
| // | |
| // Call corresponding ConfigAccess protocol to extract settings | |
| // | |
| Status = gBS->HandleProtocol ( | |
| DriverHandle, | |
| &gEfiHiiConfigAccessProtocolGuid, | |
| (VOID **)&ConfigAccess | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto Done; | |
| } | |
| 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 separates 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 entirety of the current HII | |
| database. 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 (GetElementsFromRequest (AccessResults)) { | |
| 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 separates 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; | |
| EFI_IFR_VARSTORE_EFI *EfiVarStoreInfo; | |
| BOOLEAN IsEfiVarstore; | |
| UINTN DevicePathSize; | |
| 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; | |
| Database = NULL; | |
| AccessProgress = NULL; | |
| EfiVarStoreInfo = NULL; | |
| IsEfiVarstore = FALSE; | |
| // | |
| // 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); | |
| DevicePathSize = GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *)CurrentDevicePath); | |
| if ((CompareMem (DevicePath, CurrentDevicePath, DevicePathSize) == 0) && IsThisPackageList (Database, ConfigResp)) { | |
| 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); | |
| // | |
| // Check whether this ConfigRequest is search from Efi varstore type storage. | |
| // | |
| Status = GetVarStoreType (Database, ConfigResp, &IsEfiVarstore, &EfiVarStoreInfo); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| if (IsEfiVarstore) { | |
| // | |
| // Call the SetVariable function to route settings. | |
| // | |
| Status = RouteConfigRespForEfiVarStore (This, EfiVarStoreInfo, ConfigResp, &AccessProgress); | |
| FreePool (EfiVarStoreInfo); | |
| } else { | |
| // | |
| // Call corresponding ConfigAccess protocol to route settings | |
| // | |
| Status = gBS->HandleProtocol ( | |
| DriverHandle, | |
| &gEfiHiiConfigAccessProtocolGuid, | |
| (VOID **)&ConfigAccess | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| *Progress = StringPtr; | |
| FreePool (ConfigResp); | |
| return EFI_NOT_FOUND; | |
| } | |
| Status = ConfigAccess->RouteConfig ( | |
| ConfigAccess, | |
| ConfigResp, | |
| &AccessProgress | |
| ); | |
| } | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (AccessProgress != NULL); | |
| // | |
| // 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; | |
| TmpBuffer = NULL; | |
| 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; | |
| AppendToMultiString (Config, ConfigRequest); | |
| HiiToLower (*Config); | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // Skip '&' | |
| // | |
| StringPtr++; | |
| // | |
| // Copy <ConfigHdr> and an additional '&' to <ConfigResp> | |
| // | |
| TemString = AllocateCopyPool (sizeof (CHAR16) * (StringPtr - ConfigRequest + 1), ConfigRequest); | |
| if (TemString == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| TemString[StringPtr - ConfigRequest] = '\0'; | |
| AppendToMultiString (Config, TemString); | |
| FreePool (TemString); | |
| // | |
| // 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 (EFI_ERROR (Status)) { | |
| *Progress = TmpPtr - 1; | |
| 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 = TmpPtr - 1; | |
| Status = EFI_INVALID_PARAMETER; | |
| goto Exit; | |
| } | |
| StringPtr += StrLen (L"&WIDTH="); | |
| // | |
| // Get Width | |
| // | |
| Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length); | |
| if (EFI_ERROR (Status)) { | |
| *Progress = TmpPtr - 1; | |
| 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 = TmpPtr - 1; | |
| 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--) { | |
| UnicodeValueToStringS ( | |
| TemString, | |
| Length * sizeof (CHAR16) - ((UINTN)TemString - (UINTN)ValueStr), | |
| PREFIX_ZERO | RADIX_HEX, | |
| *TemBuffer, | |
| 2 | |
| ); | |
| TemString += StrnLenS (TemString, Length - ((UINTN)TemString - (UINTN)ValueStr) / sizeof (CHAR16)); | |
| } | |
| 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; | |
| StrCatS (ConfigElement, Length, L"VALUE="); | |
| StrCatS (ConfigElement, Length, 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 largest index of the | |
| modified byte in the Block, or the required buffer | |
| size if the Block is not large enough. | |
| @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>. | |
| @retval EFI_BUFFER_TOO_SMALL Block not large enough. Progress undefined. | |
| BlockSize is updated with the required buffer size. | |
| @retval EFI_NOT_FOUND Target for the specified routing data was not found. | |
| Progress points to the "G" in "GUID" of the errant | |
| routing data. | |
| **/ | |
| 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; | |
| EFI_STRING TmpPtr; | |
| UINTN Length; | |
| EFI_STATUS Status; | |
| UINT8 *TmpBuffer; | |
| UINTN Offset; | |
| UINTN Width; | |
| UINT8 *Value; | |
| UINTN BufferSize; | |
| UINTN MaxBlockSize; | |
| TmpBuffer = NULL; | |
| if ((This == NULL) || (BlockSize == NULL) || (Progress == NULL)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| *Progress = ConfigResp; | |
| if (ConfigResp == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This); | |
| ASSERT (Private != NULL); | |
| StringPtr = ConfigResp; | |
| BufferSize = *BlockSize; | |
| Value = NULL; | |
| MaxBlockSize = 0; | |
| // | |
| // 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; | |
| } | |
| // | |
| // 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) { | |
| TmpPtr = StringPtr; | |
| StringPtr += StrLen (L"&OFFSET="); | |
| // | |
| // Get Offset | |
| // | |
| Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length); | |
| if (EFI_ERROR (Status)) { | |
| *Progress = TmpPtr; | |
| 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 = TmpPtr; | |
| Status = EFI_INVALID_PARAMETER; | |
| goto Exit; | |
| } | |
| StringPtr += StrLen (L"&WIDTH="); | |
| // | |
| // Get Width | |
| // | |
| Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length); | |
| if (EFI_ERROR (Status)) { | |
| *Progress = TmpPtr; | |
| 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 = TmpPtr; | |
| Status = EFI_INVALID_PARAMETER; | |
| goto Exit; | |
| } | |
| StringPtr += StrLen (L"&VALUE="); | |
| // | |
| // Get Value | |
| // | |
| Status = GetValueOfNumber (StringPtr, &Value, &Length); | |
| if (EFI_ERROR (Status)) { | |
| *Progress = TmpPtr; | |
| goto Exit; | |
| } | |
| StringPtr += Length; | |
| if ((*StringPtr != 0) && (*StringPtr != L'&')) { | |
| *Progress = TmpPtr; | |
| Status = EFI_INVALID_PARAMETER; | |
| goto Exit; | |
| } | |
| // | |
| // Update the Block with configuration info | |
| // | |
| if ((Block != NULL) && (Offset + Width <= BufferSize)) { | |
| CopyMem (Block + Offset, Value, Width); | |
| } | |
| if (Offset + Width > MaxBlockSize) { | |
| MaxBlockSize = Offset + Width; | |
| } | |
| FreePool (Value); | |
| Value = NULL; | |
| // | |
| // If '\0', parsing is finished. | |
| // | |
| if (*StringPtr == 0) { | |
| break; | |
| } | |
| } | |
| // | |
| // The input string is not ConfigResp format, return error. | |
| // | |
| if (*StringPtr != 0) { | |
| *Progress = StringPtr; | |
| Status = EFI_INVALID_PARAMETER; | |
| goto Exit; | |
| } | |
| *Progress = StringPtr + StrLen (StringPtr); | |
| *BlockSize = MaxBlockSize - 1; | |
| if (MaxBlockSize > BufferSize) { | |
| *BlockSize = MaxBlockSize; | |
| if (Block != NULL) { | |
| return EFI_BUFFER_TOO_SMALL; | |
| } | |
| } | |
| if (Block == NULL) { | |
| *Progress = ConfigResp; | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| 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 { | |
| StrnCpyS (*AltCfgResp, Length, HdrStart, HdrEnd - HdrStart); | |
| StrCatS (*AltCfgResp, Length, 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; | |
| } |