+EFI_STATUS\r
+ExtractBlockName (\r
+ IN UINT8 *Buffer,\r
+ OUT CHAR16 **BlockName\r
+ )\r
+/*++\r
+\r
+ Routine Description:\r
+\r
+ Extract block name from the array generated by VFR compiler. The name of\r
+ this array is "Vfr + <StorageName> + BlockName", e.g. "VfrMyIfrNVDataBlockName".\r
+ Format of this array is:\r
+ Array length | 4-bytes\r
+ Offset | 2-bytes\r
+ Width | 2-bytes\r
+ Offset | 2-bytes\r
+ Width | 2-bytes\r
+ ... ...\r
+\r
+ Arguments:\r
+ Buffer - Array generated by VFR compiler.\r
+ BlockName - The returned <BlockName>\r
+\r
+ Returns:\r
+ EFI_OUT_OF_RESOURCES - Run out of memory resource.\r
+ EFI_INVALID_PARAMETER - Buffer is NULL or BlockName is NULL.\r
+ EFI_SUCCESS - Operation successful.\r
+\r
+--*/\r
+{\r
+ UINTN Index;\r
+ UINT32 Length;\r
+ UINT32 BlockNameNumber;\r
+ UINTN HexStringBufferLen;\r
+ CHAR16 *StringPtr;\r
+\r
+ if ((Buffer == NULL) || (BlockName == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Calculate number of Offset/Width pair\r
+ //\r
+ EfiCopyMem (&Length, Buffer, sizeof (UINT32));\r
+ BlockNameNumber = (Length - sizeof (UINT32)) / (sizeof (UINT16) * 2);\r
+\r
+ //\r
+ // <BlockName> ::= &OFFSET=1234&WIDTH=1234\r
+ // | 8 | 4 | 7 | 4 |\r
+ //\r
+ StringPtr = EfiLibAllocateZeroPool ((BlockNameNumber * (8 + 4 + 7 + 4) + 1) * sizeof (CHAR16));\r
+ *BlockName = StringPtr;\r
+ if (StringPtr == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Buffer += sizeof (UINT32);\r
+ for (Index = 0; Index < BlockNameNumber; Index++) {\r
+ EfiStrCpy (StringPtr, L"&OFFSET=");\r
+ StringPtr += 8;\r
+\r
+ HexStringBufferLen = 5;\r
+ BufToHexString (StringPtr, &HexStringBufferLen, Buffer, sizeof (UINT16));\r
+ Buffer += sizeof (UINT16);\r
+ StringPtr += 4;\r
+\r
+ EfiStrCpy (StringPtr, L"&WIDTH=");\r
+ StringPtr += 7;\r
+\r
+ HexStringBufferLen = 5;\r
+ BufToHexString (StringPtr, &HexStringBufferLen, Buffer, sizeof (UINT16));\r
+ Buffer += sizeof (UINT16);\r
+ StringPtr += 4;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+ExtractBlockConfig (\r
+ IN UINT8 *Buffer,\r
+ OUT CHAR16 **BlockConfig\r
+ )\r
+/*++\r
+\r
+ Routine Description:\r
+\r
+ Extract block config from the array generated by VFR compiler. The name of\r
+ this array is "Vfr + <StorageName> + Default<HexCh>4", e.g. "VfrMyIfrNVDataDefault0000".\r
+\r
+ Arguments:\r
+ Buffer - Array generated by VFR compiler.\r
+ BlockConfig - The returned <BlockConfig>\r
+\r
+ Returns:\r
+ EFI_OUT_OF_RESOURCES - Run out of memory resource.\r
+ EFI_INVALID_PARAMETER - Buffer is NULL or BlockConfig is NULL.\r
+ EFI_SUCCESS - Operation successful.\r
+\r
+--*/\r
+{\r
+ UINT32 Length;\r
+ UINT16 Width;\r
+ UINTN HexStringBufferLen;\r
+ CHAR16 *StringPtr;\r
+ UINT8 *BufferEnd;\r
+ CHAR16 *StringEnd;\r
+ EFI_STATUS Status;\r
+\r
+ if ((Buffer == NULL) || (BlockConfig == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Calculate length of AltResp string\r
+ // Format of Default value array is:\r
+ // Array length | 4-bytes\r
+ // Offset | 2-bytes\r
+ // Width | 2-bytes\r
+ // Value | Variable length\r
+ // Offset | 2-bytes\r
+ // Width | 2-bytes\r
+ // Value | Variable length\r
+ // ... ...\r
+ // When value is 1 byte in length, overhead of AltResp string will be maximum,\r
+ // BlockConfig ::= <&OFFSET=1234&WIDTH=1234&VALUE=12>+\r
+ // | 8 | 4 | 7 | 4 | 7 |2|\r
+ // so the maximum length of BlockConfig could be calculated as:\r
+ // (ArrayLength / 5) * (8 + 4 + 7 + 4 + 7 + 2) = ArrayLength * 6.4 < ArrayLength * 7\r
+ //\r
+ EfiCopyMem (&Length, Buffer, sizeof (UINT32));\r
+ BufferEnd = Buffer + Length;\r
+ StringPtr = EfiLibAllocatePool (Length * 7 * sizeof (CHAR16));\r
+ *BlockConfig = StringPtr;\r
+ if (StringPtr == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ StringEnd = StringPtr + (Length * 7);\r
+\r
+ Buffer += sizeof (UINT32);\r
+ while (Buffer < BufferEnd) {\r
+ EfiStrCpy (StringPtr, L"&OFFSET=");\r
+ StringPtr += 8;\r
+\r
+ HexStringBufferLen = 5;\r
+ BufToHexString (StringPtr, &HexStringBufferLen, Buffer, sizeof (UINT16));\r
+ Buffer += sizeof (UINT16);\r
+ StringPtr += 4;\r
+\r
+ EfiStrCpy (StringPtr, L"&WIDTH=");\r
+ StringPtr += 7;\r
+\r
+ HexStringBufferLen = 5;\r
+ BufToHexString (StringPtr, &HexStringBufferLen, Buffer, sizeof (UINT16));\r
+ EfiCopyMem (&Width, Buffer, sizeof (UINT16));\r
+ Buffer += sizeof (UINT16);\r
+ StringPtr += 4;\r
+\r
+ EfiStrCpy (StringPtr, L"&VALUE=");\r
+ StringPtr += 7;\r
+\r
+ HexStringBufferLen = StringEnd - StringPtr;\r
+ Status = BufToHexString (StringPtr, &HexStringBufferLen, Buffer, Width);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ Buffer += Width;\r
+ StringPtr += (Width * 2);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+ConstructConfigAltResp (\r
+ IN EFI_STRING ConfigRequest, OPTIONAL\r
+ OUT EFI_STRING *Progress,\r
+ OUT EFI_STRING *ConfigAltResp,\r
+ IN EFI_GUID *Guid,\r
+ IN CHAR16 *Name,\r
+ IN EFI_HANDLE *DriverHandle,\r
+ IN VOID *BufferStorage,\r
+ IN UINTN BufferStorageSize,\r
+ IN VOID *BlockNameArray, OPTIONAL\r
+ IN UINTN NumberAltCfg,\r
+ ...\r
+//IN UINT16 AltCfgId,\r
+//IN VOID *DefaultValueArray,\r
+ )\r
+/*++\r
+\r
+ Routine Description:\r
+\r
+ Construct <ConfigAltResp> for a buffer storage.\r
+\r
+ Arguments:\r
+ ConfigRequest - The Config request string. If set to NULL, all the\r
+ configurable elements will be extracted from BlockNameArray.\r
+ ConfigAltResp - The returned <ConfigAltResp>.\r
+ Progress - On return, points to a character in the Request.\r
+ Guid - GUID of the buffer storage.\r
+ Name - Name of the buffer storage.\r
+ DriverHandle - The DriverHandle which is used to invoke HiiDatabase\r
+ protocol interface NewPackageList().\r
+ BufferStorage - Content of the buffer storage.\r
+ BufferStorageSize - Length in bytes of the buffer storage.\r
+ BlockNameArray - Array generated by VFR compiler.\r
+ NumberAltCfg - Number of Default value array generated by VFR compiler.\r
+ The sequential input parameters will be number of\r
+ AltCfgId and DefaultValueArray pairs. When set to 0,\r
+ there will be no <AltResp>.\r
+\r
+ Returns:\r
+ EFI_OUT_OF_RESOURCES - Run out of memory resource.\r
+ EFI_INVALID_PARAMETER - ConfigAltResp is NULL.\r
+ EFI_SUCCESS - Operation successful.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ CHAR16 *ConfigHdr;\r
+ CHAR16 *BlockName;\r
+ CHAR16 *DescHdr;\r
+ CHAR16 *StringPtr;\r
+ CHAR16 **AltCfg;\r
+ UINT16 AltCfgId;\r
+ VOID *DefaultValueArray;\r
+ UINTN StrBufferLen;\r
+ EFI_STRING ConfigResp;\r
+ EFI_STRING TempStr;\r
+ VA_LIST Args;\r
+ UINTN AltRespLen;\r
+ UINTN Index;\r
+ BOOLEAN NeedFreeConfigRequest;\r
+ EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;\r
+\r
+ if (ConfigAltResp == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Construct <ConfigHdr> : "GUID=...&NAME=...&PATH=..."\r
+ //\r
+ ConfigHdr = NULL;\r
+ StrBufferLen = 0;\r
+ Status = ConstructConfigHdr (\r
+ ConfigHdr,\r
+ &StrBufferLen,\r
+ Guid,\r
+ Name,\r
+ DriverHandle\r
+ );\r
+ if (Status == EFI_BUFFER_TOO_SMALL) {\r
+ ConfigHdr = EfiLibAllocateZeroPool (StrBufferLen);\r
+ Status = ConstructConfigHdr (\r
+ ConfigHdr,\r
+ &StrBufferLen,\r
+ Guid,\r
+ Name,\r
+ DriverHandle\r
+ );\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Construct <ConfigResp>\r
+ //\r
+ NeedFreeConfigRequest = FALSE;\r
+ if (ConfigRequest == NULL) {\r
+ //\r
+ // If ConfigRequest is set to NULL, export all configurable elements in BlockNameArray\r
+ //\r
+ Status = ExtractBlockName (BlockNameArray, &BlockName);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ StrBufferLen = EfiStrSize (ConfigHdr);\r
+ StrBufferLen = StrBufferLen + EfiStrSize (BlockName) - sizeof (CHAR16);\r
+ ConfigRequest = EfiLibAllocateZeroPool (StrBufferLen);\r
+ EfiStrCpy (ConfigRequest, ConfigHdr);\r
+ EfiStrCat (ConfigRequest, BlockName);\r
+ NeedFreeConfigRequest = TRUE;\r
+ }\r
+\r
+ Status = gBS->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid, NULL, (VOID **) &HiiConfigRouting);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = HiiConfigRouting->BlockToConfig (\r
+ HiiConfigRouting,\r
+ ConfigRequest,\r
+ BufferStorage,\r
+ BufferStorageSize,\r
+ &ConfigResp,\r
+ (Progress == NULL) ? &TempStr : Progress\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Construct <AltResp>\r
+ //\r
+ DescHdr = EfiLibAllocateZeroPool (NumberAltCfg * 16 * sizeof (CHAR16));\r
+ StringPtr = DescHdr;\r
+ AltCfg = EfiLibAllocateZeroPool (NumberAltCfg * sizeof (CHAR16 *));\r
+ AltRespLen = 0;\r
+ VA_START (Args, NumberAltCfg);\r
+ for (Index = 0; Index < NumberAltCfg; Index++) {\r
+ AltCfgId = (UINT16) VA_ARG (Args, UINT16);\r
+ DefaultValueArray = (UINT8 *) VA_ARG (Args, VOID *);\r
+\r
+ //\r
+ // '&' <ConfigHdr>\r
+ //\r
+ AltRespLen += (EfiStrLen (ConfigHdr) + 1);\r
+\r
+ StringPtr = DescHdr + Index * 16;\r
+ EfiStrCpy (StringPtr, L"&ALTCFG=");\r
+ AltRespLen += (8 + sizeof (UINT16) * 2);\r
+\r
+ StrBufferLen = 5;\r
+ BufToHexString (StringPtr + 8, &StrBufferLen, (UINT8 *) &AltCfgId, sizeof (UINT16));\r
+ Status = ExtractBlockConfig (DefaultValueArray, &AltCfg[Index]);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ AltRespLen += EfiStrLen (AltCfg[Index]);\r
+ }\r
+ VA_END (Args);\r
+\r
+ //\r
+ // Generate the final <ConfigAltResp>\r
+ //\r
+ StrBufferLen = (EfiStrLen ((CHAR16 *) ConfigResp) + AltRespLen + 1) * sizeof (CHAR16);\r
+ TempStr = EfiLibAllocateZeroPool (StrBufferLen);\r
+ *ConfigAltResp = TempStr;\r
+ if (TempStr == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // <ConfigAltResp> ::= <ConfigResp> ['&' <AltResp>]*\r
+ //\r
+ EfiStrCpy (TempStr, ConfigResp);\r
+ for (Index = 0; Index < NumberAltCfg; Index++) {\r
+ EfiStrCat (TempStr, L"&");\r
+ EfiStrCat (TempStr, ConfigHdr);\r
+ EfiStrCat (TempStr, DescHdr + Index * 16);\r
+ EfiStrCat (TempStr, AltCfg[Index]);\r
+\r
+ gBS->FreePool (AltCfg[Index]);\r
+ }\r
+\r
+ if (NeedFreeConfigRequest) {\r
+ gBS->FreePool (ConfigRequest);\r
+ }\r
+ gBS->FreePool (ConfigHdr);\r
+ gBS->FreePool (ConfigResp);\r
+ gBS->FreePool (DescHdr);\r
+ gBS->FreePool (AltCfg);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r