+ @param AltCfgResp Pointer to a null-terminated Unicode string in\r
+ <ConfigAltResp> format.\r
+ @param DefaultAltCfgResp Pointer to a null-terminated Unicode string in\r
+ <MultiConfigAltResp> format. The default value\r
+ string may contain more than one ConfigAltResp\r
+ string for the different varstore buffer.\r
+ @param AltConfigHdr Pointer to a Unicode string in <AltConfigHdr> format.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Insufficient resources to store necessary\r
+ structures.\r
+ @retval EFI_SUCCESS The function finishes successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+CompareAndMergeDefaultString (\r
+ IN OUT EFI_STRING *AltCfgResp,\r
+ IN EFI_STRING DefaultAltCfgResp,\r
+ IN EFI_STRING AltConfigHdr\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_STRING AltCfgRespBackup;\r
+ EFI_STRING AltConfigHdrPtr;\r
+ EFI_STRING AltConfigHdrPtrNext;\r
+ EFI_STRING ConfigAltResp;\r
+ EFI_STRING StringPtr;\r
+ EFI_STRING StringPtrNext;\r
+ EFI_STRING BlockPtr;\r
+ UINTN ReallocateSize;\r
+ CHAR16 TempChar;\r
+ CHAR16 TempCharA;\r
+ BOOLEAN ConfigAltRespChanged;\r
+\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ BlockPtr = NULL;\r
+ AltConfigHdrPtrNext = NULL;\r
+ StringPtrNext = NULL;\r
+ ConfigAltResp = NULL;\r
+ AltCfgRespBackup = NULL;\r
+ TempChar = L'\0';\r
+ TempCharA = L'\0';\r
+ ConfigAltRespChanged = FALSE;\r
+\r
+ //\r
+ // To find the <AltResp> with AltConfigHdr in DefaultAltCfgResp, ignore other <AltResp> which follow it.\r
+ //\r
+ AltConfigHdrPtr = StrStr (DefaultAltCfgResp, AltConfigHdr);\r
+ ASSERT (AltConfigHdrPtr != NULL);\r
+ AltConfigHdrPtrNext = StrStr (AltConfigHdrPtr + 1, L"&GUID");\r
+ if (AltConfigHdrPtrNext != NULL) {\r
+ TempChar = *AltConfigHdrPtrNext;\r
+ *AltConfigHdrPtrNext = L'\0';\r
+ }\r
+\r
+ //\r
+ // To find the <AltResp> with AltConfigHdr in AltCfgResp, ignore other <AltResp> which follow it.\r
+ //\r
+ StringPtr = StrStr (*AltCfgResp, AltConfigHdr);\r
+ ASSERT (StringPtr != NULL);\r
+ StringPtrNext = StrStr (StringPtr + 1, L"&GUID");\r
+ if (StringPtrNext != NULL) {\r
+ TempCharA = *StringPtrNext;\r
+ *StringPtrNext = L'\0';\r
+ }\r
+\r
+ //\r
+ // Copy the content of <ConfigAltResp> which contain current AltConfigHdr in AltCfgResp.\r
+ //\r
+ ConfigAltResp = AllocateCopyPool (StrSize (*AltCfgResp), *AltCfgResp);\r
+ if (ConfigAltResp == NULL) {\r
+ goto Exit;\r
+ }\r
+\r
+ //\r
+ // To find the <ConfigBody> with AltConfigHdr in DefaultAltCfgResp.\r
+ //\r
+ BlockPtr = StrStr (AltConfigHdrPtr, L"&OFFSET=");\r
+ if (BlockPtr != NULL) {\r
+ //\r
+ // <BlockConfig>::='OFFSET='<Number>'&WIDTH='<Number>'&VALUE='<Number> style.\r
+ // Call function CompareBlockElementDefault to compare the <BlockConfig> in DefaultAltCfgResp and ConfigAltResp.\r
+ // The ConfigAltResp which may contain the new <BlockConfig> get from DefaultAltCfgResp.\r
+ //\r
+ Status = CompareBlockElementDefault (DefaultAltCfgResp, &ConfigAltResp, AltConfigHdr, &ConfigAltRespChanged);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Exit;\r
+ }\r
+ } else {\r
+ //\r
+ // <NvConfig> ::= <Label>'='<String> | <Label>'='<Number> style.\r
+ // Call function CompareNameElementDefault to compare the <NvConfig> in DefaultAltCfgResp and ConfigAltResp.\r
+ // The ConfigAltResp which may contain the new <NvConfig> get from DefaultAltCfgResp.\r
+ //\r
+ Status = CompareNameElementDefault (DefaultAltCfgResp, &ConfigAltResp, AltConfigHdr, &ConfigAltRespChanged);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Exit;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Restore the AltCfgResp.\r
+ //\r
+ if (StringPtrNext != NULL) {\r
+ *StringPtrNext = TempCharA;\r
+ }\r
+\r
+ //\r
+ // If the ConfigAltResp has no change,no need to update the content in AltCfgResp.\r
+ //\r
+ if (!ConfigAltRespChanged) {\r
+ Status = EFI_SUCCESS;\r
+ goto Exit;\r
+ }\r
+\r
+ //\r
+ // ConfigAltResp has been changed, need to update the content in AltCfgResp.\r
+ //\r
+ if (StringPtrNext != NULL) {\r
+ ReallocateSize = StrSize (ConfigAltResp) + StrSize (StringPtrNext) + sizeof (CHAR16);\r
+ } else {\r
+ ReallocateSize = StrSize (ConfigAltResp) + sizeof (CHAR16);\r
+ }\r
+\r
+ AltCfgRespBackup = (EFI_STRING)AllocateZeroPool (ReallocateSize);\r
+ if (AltCfgRespBackup == NULL) {\r
+ goto Exit;\r
+ }\r
+\r
+ StrCatS (AltCfgRespBackup, ReallocateSize / sizeof (CHAR16), ConfigAltResp);\r
+ if (StringPtrNext != NULL) {\r
+ StrCatS (AltCfgRespBackup, ReallocateSize / sizeof (CHAR16), StringPtrNext);\r
+ }\r
+\r
+ FreePool (*AltCfgResp);\r
+ *AltCfgResp = AltCfgRespBackup;\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+Exit:\r
+ if (ConfigAltResp != NULL) {\r
+ FreePool (ConfigAltResp);\r
+ }\r
+\r
+ //\r
+ // Restore the DefaultAltCfgResp.\r
+ //\r
+ if ( AltConfigHdrPtrNext != NULL) {\r
+ *AltConfigHdrPtrNext = TempChar;\r
+ AltConfigHdrPtrNext = NULL;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ This function merges DefaultAltCfgResp string into AltCfgResp string for\r
+ the missing AltCfgId in AltCfgResq.\r
+\r
+ @param AltCfgResp Pointer to a null-terminated Unicode string in\r
+ <ConfigAltResp> format. The default value string\r
+ will be merged into it.\r
+ @param DefaultAltCfgResp Pointer to a null-terminated Unicode string in\r
+ <MultiConfigAltResp> format. The default value\r
+ string may contain more than one ConfigAltResp\r
+ string for the different varstore buffer.\r
+\r
+ @retval EFI_SUCCESS The merged string returns.\r
+ @retval EFI_INVALID_PARAMETER *AltCfgResp is to NULL.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MergeDefaultString (\r
+ IN OUT EFI_STRING *AltCfgResp,\r
+ IN EFI_STRING DefaultAltCfgResp\r
+ )\r
+{\r
+ EFI_STRING StringPtrDefault;\r
+ EFI_STRING StringPtrEnd;\r
+ CHAR16 TempChar;\r
+ EFI_STRING StringPtr;\r
+ EFI_STRING AltConfigHdr;\r
+ UINTN HeaderLength;\r
+ UINTN SizeAltCfgResp;\r
+ UINTN MaxLen;\r
+ UINTN TotalSize;\r
+\r
+ if (*AltCfgResp == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Get the request ConfigHdr\r
+ //\r
+ SizeAltCfgResp = 0;\r
+ StringPtr = *AltCfgResp;\r
+\r
+ //\r
+ // Find <ConfigHdr> GUID=...&NAME=...&PATH=...\r
+ //\r
+ if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&NAME=", StrLen (L"&NAME=")) != 0) {\r
+ StringPtr++;\r
+ }\r
+\r
+ while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&PATH=", StrLen (L"&PATH=")) != 0) {\r
+ StringPtr++;\r
+ }\r
+\r
+ if (*StringPtr == L'\0') {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ StringPtr += StrLen (L"&PATH=");\r
+ while (*StringPtr != L'\0' && *StringPtr != L'&') {\r
+ StringPtr++;\r
+ }\r
+\r
+ HeaderLength = StringPtr - *AltCfgResp;\r
+\r
+ //\r
+ // Construct AltConfigHdr string "&<ConfigHdr>&ALTCFG=XXXX\0"\r
+ // |1| StrLen (ConfigHdr) | 8 | 4 | 1 |\r
+ //\r
+ MaxLen = 1 + HeaderLength + 8 + 4 + 1;\r
+ AltConfigHdr = AllocateZeroPool (MaxLen * sizeof (CHAR16));\r
+ if (AltConfigHdr == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ StrCpyS (AltConfigHdr, MaxLen, L"&");\r
+ StrnCatS (AltConfigHdr, MaxLen, *AltCfgResp, HeaderLength);\r
+ StrCatS (AltConfigHdr, MaxLen, L"&ALTCFG=");\r
+ HeaderLength = StrLen (AltConfigHdr);\r
+\r
+ StringPtrDefault = StrStr (DefaultAltCfgResp, AltConfigHdr);\r
+ while (StringPtrDefault != NULL) {\r
+ //\r
+ // Get AltCfg Name\r
+ //\r
+ StrnCatS (AltConfigHdr, MaxLen, StringPtrDefault + HeaderLength, 4);\r
+ StringPtr = StrStr (*AltCfgResp, AltConfigHdr);\r
+\r
+ //\r
+ // Append the found default value string to the input AltCfgResp\r
+ //\r
+ if (StringPtr == NULL) {\r
+ StringPtrEnd = StrStr (StringPtrDefault + 1, L"&GUID");\r
+ SizeAltCfgResp = StrSize (*AltCfgResp);\r
+ if (StringPtrEnd == NULL) {\r
+ //\r
+ // No more default string is found.\r
+ //\r
+ TotalSize = SizeAltCfgResp + StrSize (StringPtrDefault);\r
+ *AltCfgResp = (EFI_STRING)ReallocatePool (\r
+ SizeAltCfgResp,\r
+ TotalSize,\r
+ (VOID *)(*AltCfgResp)\r
+ );\r
+ if (*AltCfgResp == NULL) {\r
+ FreePool (AltConfigHdr);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ StrCatS (*AltCfgResp, TotalSize / sizeof (CHAR16), StringPtrDefault);\r
+ break;\r
+ } else {\r
+ TempChar = *StringPtrEnd;\r
+ *StringPtrEnd = L'\0';\r
+ TotalSize = SizeAltCfgResp + StrSize (StringPtrDefault);\r
+ *AltCfgResp = (EFI_STRING)ReallocatePool (\r
+ SizeAltCfgResp,\r
+ TotalSize,\r
+ (VOID *)(*AltCfgResp)\r
+ );\r
+ if (*AltCfgResp == NULL) {\r
+ FreePool (AltConfigHdr);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ StrCatS (*AltCfgResp, TotalSize / sizeof (CHAR16), StringPtrDefault);\r
+ *StringPtrEnd = TempChar;\r
+ }\r
+ } else {\r
+ //\r
+ // The AltCfgResp contains <AltCfgResp>.\r
+ // If the <ConfigElement> in <AltCfgResp> in the DefaultAltCfgResp but not in the\r
+ // related <AltCfgResp> in AltCfgResp, merge it to AltCfgResp. else no need to merge.\r
+ //\r
+ CompareAndMergeDefaultString (AltCfgResp, DefaultAltCfgResp, AltConfigHdr);\r
+ }\r
+\r
+ //\r
+ // Find next AltCfg String\r
+ //\r
+ *(AltConfigHdr + HeaderLength) = L'\0';\r
+ StringPtrDefault = StrStr (StringPtrDefault + 1, AltConfigHdr);\r
+ }\r
+\r
+ FreePool (AltConfigHdr);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ This function inserts new DefaultValueData into the BlockData DefaultValue array.\r
+\r
+ @param BlockData The BlockData is updated to add new default value.\r
+ @param DefaultValueData The DefaultValue is added.\r
+\r
+**/\r
+VOID\r
+InsertDefaultValue (\r
+ IN IFR_BLOCK_DATA *BlockData,\r
+ IN IFR_DEFAULT_DATA *DefaultValueData\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ IFR_DEFAULT_DATA *DefaultValueArray;\r
+ LIST_ENTRY *DefaultLink;\r
+\r
+ DefaultLink = &BlockData->DefaultValueEntry;\r
+\r
+ for (Link = DefaultLink->ForwardLink; Link != DefaultLink; Link = Link->ForwardLink) {\r
+ DefaultValueArray = BASE_CR (Link, IFR_DEFAULT_DATA, Entry);\r
+ if (DefaultValueArray->DefaultId == DefaultValueData->DefaultId) {\r
+ //\r
+ // DEFAULT_VALUE_FROM_OPCODE has high priority, DEFAULT_VALUE_FROM_DEFAULT has low priority.\r
+ // When default types are DEFAULT_VALUE_FROM_OTHER_DEFAULT, the default value can be overrode.\r
+ //\r
+ if ((DefaultValueData->Type > DefaultValueArray->Type) || ((DefaultValueData->Type == DefaultValueArray->Type) && (DefaultValueData->Type == DefaultValueFromOtherDefault))) {\r
+ //\r
+ // Update the default value array in BlockData.\r
+ //\r
+ CopyMem (&DefaultValueArray->Value, &DefaultValueData->Value, sizeof (EFI_IFR_TYPE_VALUE));\r
+ DefaultValueArray->Type = DefaultValueData->Type;\r
+ DefaultValueArray->Cleaned = DefaultValueData->Cleaned;\r
+ }\r
+\r
+ return;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Insert new default value data in tail.\r
+ //\r
+ DefaultValueArray = AllocateZeroPool (sizeof (IFR_DEFAULT_DATA));\r
+ ASSERT (DefaultValueArray != NULL);\r
+ CopyMem (DefaultValueArray, DefaultValueData, sizeof (IFR_DEFAULT_DATA));\r
+ InsertTailList (Link, &DefaultValueArray->Entry);\r
+}\r
+\r
+/**\r
+ This function inserts new BlockData into the block link\r
+\r
+ @param BlockLink The list entry points to block array.\r
+ @param BlockData The point to BlockData is added.\r
+\r
+**/\r
+VOID\r