+/**\r
+ Get variable header that has consecutive content.\r
+\r
+ @param StoreInfo Pointer to variable store info structure.\r
+ @param Variable Pointer to the Variable Header.\r
+ @param VariableHeader Pointer to Pointer to the Variable Header that has consecutive content.\r
+\r
+ @retval TRUE Variable header is valid.\r
+ @retval FALSE Variable header is not valid.\r
+\r
+**/\r
+BOOLEAN\r
+GetVariableHeader (\r
+ IN VARIABLE_STORE_INFO *StoreInfo,\r
+ IN VARIABLE_HEADER *Variable,\r
+ OUT VARIABLE_HEADER **VariableHeader\r
+ )\r
+{\r
+ EFI_PHYSICAL_ADDRESS TargetAddress;\r
+ EFI_PHYSICAL_ADDRESS SpareAddress;\r
+ EFI_HOB_GUID_TYPE *GuidHob;\r
+ UINTN PartialHeaderSize;\r
+\r
+ if (Variable == NULL) {\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // First assume variable header pointed by Variable is consecutive.\r
+ //\r
+ *VariableHeader = Variable;\r
+\r
+ if (StoreInfo->FtwLastWriteData != NULL) {\r
+ TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;\r
+ SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress;\r
+ if (((UINTN) Variable > (UINTN) SpareAddress) &&\r
+ (((UINTN) Variable - (UINTN) SpareAddress + (UINTN) TargetAddress) >= (UINTN) GetEndPointer (StoreInfo->VariableStoreHeader))) {\r
+ //\r
+ // Reach the end of variable store.\r
+ //\r
+ return FALSE;\r
+ }\r
+ if (((UINTN) Variable < (UINTN) TargetAddress) && (((UINTN) Variable + GetVariableHeaderSize (StoreInfo->AuthFlag)) > (UINTN) TargetAddress)) {\r
+ //\r
+ // Variable header pointed by Variable is inconsecutive,\r
+ // create a guid hob to combine the two partial variable header content together.\r
+ //\r
+ GuidHob = GetFirstGuidHob (&gEfiCallerIdGuid);\r
+ if (GuidHob != NULL) {\r
+ *VariableHeader = (VARIABLE_HEADER *) GET_GUID_HOB_DATA (GuidHob);\r
+ } else {\r
+ *VariableHeader = (VARIABLE_HEADER *) BuildGuidHob (&gEfiCallerIdGuid, GetVariableHeaderSize (StoreInfo->AuthFlag));\r
+ PartialHeaderSize = (UINTN) TargetAddress - (UINTN) Variable;\r
+ //\r
+ // Partial content is in NV storage.\r
+ //\r
+ CopyMem ((UINT8 *) *VariableHeader, (UINT8 *) Variable, PartialHeaderSize);\r
+ //\r
+ // Another partial content is in spare block.\r
+ //\r
+ CopyMem ((UINT8 *) *VariableHeader + PartialHeaderSize, (UINT8 *) (UINTN) SpareAddress, GetVariableHeaderSize (StoreInfo->AuthFlag) - PartialHeaderSize);\r
+ }\r
+ }\r
+ } else {\r
+ if (Variable >= GetEndPointer (StoreInfo->VariableStoreHeader)) {\r
+ //\r
+ // Reach the end of variable store.\r
+ //\r
+ return FALSE;\r
+ }\r
+ }\r
+\r
+ return IsValidVariableHeader (*VariableHeader);\r
+}\r
+\r
+/**\r
+ Get variable name or data to output buffer.\r
+\r
+ @param StoreInfo Pointer to variable store info structure.\r
+ @param NameOrData Pointer to the variable name/data that may be inconsecutive.\r
+ @param Size Variable name/data size.\r
+ @param Buffer Pointer to output buffer to hold the variable name/data.\r
+\r
+**/\r
+VOID\r
+GetVariableNameOrData (\r
+ IN VARIABLE_STORE_INFO *StoreInfo,\r
+ IN UINT8 *NameOrData,\r
+ IN UINTN Size,\r
+ OUT UINT8 *Buffer\r
+ )\r
+{\r
+ EFI_PHYSICAL_ADDRESS TargetAddress;\r
+ EFI_PHYSICAL_ADDRESS SpareAddress;\r
+ UINTN PartialSize;\r
+\r
+ if (StoreInfo->FtwLastWriteData != NULL) {\r
+ TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;\r
+ SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress;\r
+ if (((UINTN) NameOrData < (UINTN) TargetAddress) && (((UINTN) NameOrData + Size) > (UINTN) TargetAddress)) {\r
+ //\r
+ // Variable name/data is inconsecutive.\r
+ //\r
+ PartialSize = (UINTN) TargetAddress - (UINTN) NameOrData;\r
+ //\r
+ // Partial content is in NV storage.\r
+ //\r
+ CopyMem (Buffer, NameOrData, PartialSize);\r
+ //\r
+ // Another partial content is in spare block.\r
+ //\r
+ CopyMem (Buffer + PartialSize, (UINT8 *) (UINTN) SpareAddress, Size - PartialSize);\r
+ return;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Variable name/data is consecutive.\r
+ //\r
+ CopyMem (Buffer, NameOrData, Size);\r
+}\r
+\r