+ @param Type The type of the variable store.\r
+ @param StoreInfo Return the store info.\r
+\r
+ @return Pointer to the variable store header.\r
+**/\r
+VARIABLE_STORE_HEADER *\r
+GetVariableStore (\r
+ IN VARIABLE_STORE_TYPE Type,\r
+ OUT VARIABLE_STORE_INFO *StoreInfo\r
+ )\r
+{\r
+ EFI_HOB_GUID_TYPE *GuidHob;\r
+ EFI_FIRMWARE_VOLUME_HEADER *FvHeader;\r
+ VARIABLE_STORE_HEADER *VariableStoreHeader;\r
+ EFI_PHYSICAL_ADDRESS NvStorageBase;\r
+ UINT32 NvStorageSize;\r
+ FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *FtwLastWriteData;\r
+ UINT32 BackUpOffset;\r
+\r
+ StoreInfo->IndexTable = NULL;\r
+ StoreInfo->FtwLastWriteData = NULL;\r
+ StoreInfo->AuthFlag = FALSE;\r
+ VariableStoreHeader = NULL;\r
+ switch (Type) {\r
+ case VariableStoreTypeHob:\r
+ GetHobVariableStore (StoreInfo, &VariableStoreHeader);\r
+\r
+ break;\r
+\r
+ case VariableStoreTypeNv:\r
+ if (GetBootModeHob () != BOOT_IN_RECOVERY_MODE) {\r
+ //\r
+ // The content of NV storage for variable is not reliable in recovery boot mode.\r
+ //\r
+\r
+ NvStorageSize = PcdGet32 (PcdFlashNvStorageVariableSize);\r
+ NvStorageBase = (EFI_PHYSICAL_ADDRESS) (PcdGet64 (PcdFlashNvStorageVariableBase64) != 0 ?\r
+ PcdGet64 (PcdFlashNvStorageVariableBase64) :\r
+ PcdGet32 (PcdFlashNvStorageVariableBase)\r
+ );\r
+ //\r
+ // First let FvHeader point to NV storage base.\r
+ //\r
+ FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) NvStorageBase;\r
+\r
+ //\r
+ // Check the FTW last write data hob.\r
+ //\r
+ BackUpOffset = 0;\r
+ GuidHob = GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid);\r
+ if (GuidHob != NULL) {\r
+ FtwLastWriteData = (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *) GET_GUID_HOB_DATA (GuidHob);\r
+ if (FtwLastWriteData->TargetAddress == NvStorageBase) {\r
+ //\r
+ // Let FvHeader point to spare block.\r
+ //\r
+ FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) FtwLastWriteData->SpareAddress;\r
+ DEBUG ((EFI_D_INFO, "PeiVariable: NV storage is backed up in spare block: 0x%x\n", (UINTN) FtwLastWriteData->SpareAddress));\r
+ } else if ((FtwLastWriteData->TargetAddress > NvStorageBase) && (FtwLastWriteData->TargetAddress < (NvStorageBase + NvStorageSize))) {\r
+ StoreInfo->FtwLastWriteData = FtwLastWriteData;\r
+ //\r
+ // Flash NV storage from the offset is backed up in spare block.\r
+ //\r
+ BackUpOffset = (UINT32) (FtwLastWriteData->TargetAddress - NvStorageBase);\r
+ DEBUG ((EFI_D_INFO, "PeiVariable: High partial NV storage from offset: %x is backed up in spare block: 0x%x\n", BackUpOffset, (UINTN) FtwLastWriteData->SpareAddress));\r
+ //\r
+ // At least one block data in flash NV storage is still valid, so still leave FvHeader point to NV storage base.\r
+ //\r
+ }\r
+ }\r
+\r
+ //\r
+ // Check if the Firmware Volume is not corrupted\r
+ //\r
+ if ((FvHeader->Signature != EFI_FVH_SIGNATURE) || (!CompareGuid (&gEfiSystemNvDataFvGuid, &FvHeader->FileSystemGuid))) {\r
+ DEBUG ((EFI_D_ERROR, "Firmware Volume for Variable Store is corrupted\n"));\r
+ break;\r
+ }\r
+\r
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINT8 *) FvHeader + FvHeader->HeaderLength);\r
+\r
+ StoreInfo->AuthFlag = (BOOLEAN) (CompareGuid (&VariableStoreHeader->Signature, &gEfiAuthenticatedVariableGuid));\r
+\r
+ GuidHob = GetFirstGuidHob (&gEfiVariableIndexTableGuid);\r
+ if (GuidHob != NULL) {\r
+ StoreInfo->IndexTable = GET_GUID_HOB_DATA (GuidHob);\r
+ } else {\r
+ //\r
+ // If it's the first time to access variable region in flash, create a guid hob to record\r
+ // VAR_ADDED type variable info.\r
+ // Note that as the resource of PEI phase is limited, only store the limited number of\r
+ // VAR_ADDED type variables to reduce access time.\r
+ //\r
+ StoreInfo->IndexTable = (VARIABLE_INDEX_TABLE *) BuildGuidHob (&gEfiVariableIndexTableGuid, sizeof (VARIABLE_INDEX_TABLE));\r
+ StoreInfo->IndexTable->Length = 0;\r
+ StoreInfo->IndexTable->StartPtr = GetStartPointer (VariableStoreHeader);\r
+ StoreInfo->IndexTable->EndPtr = GetEndPointer (VariableStoreHeader);\r
+ StoreInfo->IndexTable->GoneThrough = 0;\r
+ }\r
+ }\r
+ break;\r
+\r
+ default:\r
+ ASSERT (FALSE);\r
+ break;\r
+ }\r
+\r
+ StoreInfo->VariableStoreHeader = VariableStoreHeader;\r
+ return VariableStoreHeader;\r
+}\r
+\r
+/**\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
+/**\r
+ Find the variable in the specified variable store.\r
+\r
+ @param StoreInfo Pointer to the store info structure.\r
+ @param VariableName Name of the variable to be found\r
+ @param VendorGuid Vendor GUID to be found.\r
+ @param PtrTrack Variable Track Pointer structure that contains Variable Information.\r