summaryrefslogtreecommitdiff
path: root/MdeModulePkg/Universal/Variable
diff options
context:
space:
mode:
authorStar Zeng <star.zeng@intel.com>2013-07-03 09:08:40 +0000
committerlzeng14 <lzeng14@6f19259b-4bc3-4df7-8a09-765794883524>2013-07-03 09:08:40 +0000
commit3e02ebb2bbe0fd4da880511b1f35951e1c4b8404 (patch)
tree95fc155e9d76e163cd295db373734cc276f4abc6 /MdeModulePkg/Universal/Variable
parent70066a82a54bd5136556dff3ea76dff035a3aca3 (diff)
downloadedk2-platforms-3e02ebb2bbe0fd4da880511b1f35951e1c4b8404.tar.xz
MdeModulePkg: Variable drivers robustly handle crashes during Reclaim().
PEI variable implementation checks only the variable header signature for validity. This does not seem robust if system crash occurred during previous Reclaim() operation. If the crash occurred while FTW was rewriting the variable FV, the signature could be valid even though the rest of the FV isn't valid. Solution: Add a FaultTolerantWritePei driver to check and provide the FTW last write status, then PEI variable and early phase(before FTW protocol ready) of DXE variable can check the status and determine if all or partial variable data has been backed up in spare block, and then use the backed up data. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Star Zeng <star.zeng@intel.com> Reviewed-by: Liming Gao <liming.gao@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@14454 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'MdeModulePkg/Universal/Variable')
-rw-r--r--MdeModulePkg/Universal/Variable/Pei/Variable.c449
-rw-r--r--MdeModulePkg/Universal/Variable/Pei/Variable.h14
-rw-r--r--MdeModulePkg/Universal/Variable/Pei/VariablePei.inf12
-rw-r--r--MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c231
-rw-r--r--MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h1
-rw-r--r--MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf1
-rw-r--r--MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf1
7 files changed, 512 insertions, 197 deletions
diff --git a/MdeModulePkg/Universal/Variable/Pei/Variable.c b/MdeModulePkg/Universal/Variable/Pei/Variable.c
index 10ad3f51d0..df0304748c 100644
--- a/MdeModulePkg/Universal/Variable/Pei/Variable.c
+++ b/MdeModulePkg/Universal/Variable/Pei/Variable.c
@@ -11,7 +11,6 @@ http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
-Module Name:
**/
@@ -174,7 +173,6 @@ GetVariableNamePtr (
IN VARIABLE_HEADER *Variable
)
{
-
return (CHAR16 *) (Variable + 1);
}
@@ -182,14 +180,16 @@ GetVariableNamePtr (
/**
This code gets the pointer to the variable data.
- @param Variable Pointer to the Variable Header.
+ @param Variable Pointer to the Variable Header.
+ @param VariableHeader Pointer to the Variable Header that has consecutive content.
@return A UINT8* pointer to Variable Data.
**/
UINT8 *
GetVariableDataPtr (
- IN VARIABLE_HEADER *Variable
+ IN VARIABLE_HEADER *Variable,
+ IN VARIABLE_HEADER *VariableHeader
)
{
UINTN Value;
@@ -198,8 +198,8 @@ GetVariableDataPtr (
// Be careful about pad size for alignment
//
Value = (UINTN) GetVariableNamePtr (Variable);
- Value += NameSizeOfVariable (Variable);
- Value += GET_PAD_SIZE (NameSizeOfVariable (Variable));
+ Value += NameSizeOfVariable (VariableHeader);
+ Value += GET_PAD_SIZE (NameSizeOfVariable (VariableHeader));
return (UINT8 *) Value;
}
@@ -208,34 +208,48 @@ GetVariableDataPtr (
/**
This code gets the pointer to the next variable header.
- @param Variable Pointer to the Variable Header.
+ @param StoreInfo Pointer to variable store info structure.
+ @param Variable Pointer to the Variable Header.
+ @param VariableHeader Pointer to the Variable Header that has consecutive content.
@return A VARIABLE_HEADER* pointer to next variable header.
**/
VARIABLE_HEADER *
GetNextVariablePtr (
- IN VARIABLE_HEADER *Variable
+ IN VARIABLE_STORE_INFO *StoreInfo,
+ IN VARIABLE_HEADER *Variable,
+ IN VARIABLE_HEADER *VariableHeader
)
{
- UINTN Value;
-
- if (!IsValidVariableHeader (Variable)) {
- return NULL;
- }
-
- Value = (UINTN) GetVariableDataPtr (Variable);
- Value += DataSizeOfVariable (Variable);
- Value += GET_PAD_SIZE (DataSizeOfVariable (Variable));
+ EFI_PHYSICAL_ADDRESS TargetAddress;
+ EFI_PHYSICAL_ADDRESS SpareAddress;
+ UINTN Value;
+ Value = (UINTN) GetVariableDataPtr (Variable, VariableHeader);
+ Value += DataSizeOfVariable (VariableHeader);
+ Value += GET_PAD_SIZE (DataSizeOfVariable (VariableHeader));
//
// Be careful about pad size for alignment
//
- return (VARIABLE_HEADER *) HEADER_ALIGN (Value);
+ Value = HEADER_ALIGN (Value);
+
+ if (StoreInfo->FtwLastWriteData != NULL) {
+ TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
+ SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress;
+ if (((UINTN) Variable < (UINTN) TargetAddress) && (Value >= (UINTN) TargetAddress)) {
+ //
+ // Next variable is in spare block.
+ //
+ Value = (UINTN) SpareAddress + (Value - (UINTN) TargetAddress);
+ }
+ }
+
+ return (VARIABLE_HEADER *) Value;
}
/**
- This code gets the pointer to the variable name.
+ Get variable store status.
@param VarStoreHeader Pointer to the Variable Store Header.
@@ -249,7 +263,6 @@ GetVariableStoreStatus (
IN VARIABLE_STORE_HEADER *VarStoreHeader
)
{
-
if (CompareGuid (&VarStoreHeader->Signature, &gEfiVariableGuid) &&
VarStoreHeader->Format == VARIABLE_STORE_FORMATTED &&
VarStoreHeader->State == VARIABLE_STORE_HEALTHY
@@ -273,11 +286,85 @@ GetVariableStoreStatus (
}
}
+/**
+ Compare two variable names, one of them may be inconsecutive.
+
+ @param StoreInfo Pointer to variable store info structure.
+ @param Name1 Pointer to one variable name.
+ @param Name2 Pointer to another variable name.
+ @param NameSize Variable name size.
+
+ @retval TRUE Name1 and Name2 are identical.
+ @retval FALSE Name1 and Name2 are not identical.
+
+**/
+BOOLEAN
+CompareVariableName (
+ IN VARIABLE_STORE_INFO *StoreInfo,
+ IN CONST CHAR16 *Name1,
+ IN CONST CHAR16 *Name2,
+ IN UINTN NameSize
+ )
+{
+ EFI_PHYSICAL_ADDRESS TargetAddress;
+ EFI_PHYSICAL_ADDRESS SpareAddress;
+ UINTN PartialNameSize;
+
+ if (StoreInfo->FtwLastWriteData != NULL) {
+ TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
+ SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress;
+ if (((UINTN) Name1 < (UINTN) TargetAddress) && (((UINTN) Name1 + NameSize) > (UINTN) TargetAddress)) {
+ //
+ // Name1 is inconsecutive.
+ //
+ PartialNameSize = (UINTN) TargetAddress - (UINTN) Name1;
+ //
+ // Partial content is in NV storage.
+ //
+ if (CompareMem ((UINT8 *) Name1, (UINT8 *) Name2, PartialNameSize) == 0) {
+ //
+ // Another partial content is in spare block.
+ //
+ if (CompareMem ((UINT8 *) (UINTN) SpareAddress, (UINT8 *) Name2 + PartialNameSize, NameSize - PartialNameSize) == 0) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+ } else if (((UINTN) Name2 < (UINTN) TargetAddress) && (((UINTN) Name2 + NameSize) > (UINTN) TargetAddress)) {
+ //
+ // Name2 is inconsecutive.
+ //
+ PartialNameSize = (UINTN) TargetAddress - (UINTN) Name2;
+ //
+ // Partial content is in NV storage.
+ //
+ if (CompareMem ((UINT8 *) Name2, (UINT8 *) Name1, PartialNameSize) == 0) {
+ //
+ // Another partial content is in spare block.
+ //
+ if (CompareMem ((UINT8 *) (UINTN) SpareAddress, (UINT8 *) Name1 + PartialNameSize, NameSize - PartialNameSize) == 0) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+ }
+ }
+
+ //
+ // Both Name1 and Name2 are consecutive.
+ //
+ if (CompareMem ((UINT8 *) Name1, (UINT8 *) Name2, NameSize) == 0) {
+ return TRUE;
+ }
+ return FALSE;
+}
/**
This function compares a variable with variable entries in database.
+ @param StoreInfo Pointer to variable store info structure.
@param Variable Pointer to the variable in our database
+ @param VariableHeader Pointer to the Variable Header that has consecutive content.
@param VariableName Name of the variable to compare to 'Variable'
@param VendorGuid GUID of the variable to compare to 'Variable'
@param PtrTrack Variable Track Pointer structure that contains Variable Information.
@@ -288,7 +375,9 @@ GetVariableStoreStatus (
**/
EFI_STATUS
CompareWithValidVariable (
+ IN VARIABLE_STORE_INFO *StoreInfo,
IN VARIABLE_HEADER *Variable,
+ IN VARIABLE_HEADER *VariableHeader,
IN CONST CHAR16 *VariableName,
IN CONST EFI_GUID *VendorGuid,
OUT VARIABLE_POINTER_TRACK *PtrTrack
@@ -305,14 +394,14 @@ CompareWithValidVariable (
// Instead we compare the GUID a UINT32 at a time and branch
// on the first failed comparison.
//
- if ((((INT32 *) VendorGuid)[0] == ((INT32 *) &Variable->VendorGuid)[0]) &&
- (((INT32 *) VendorGuid)[1] == ((INT32 *) &Variable->VendorGuid)[1]) &&
- (((INT32 *) VendorGuid)[2] == ((INT32 *) &Variable->VendorGuid)[2]) &&
- (((INT32 *) VendorGuid)[3] == ((INT32 *) &Variable->VendorGuid)[3])
+ if ((((INT32 *) VendorGuid)[0] == ((INT32 *) &VariableHeader->VendorGuid)[0]) &&
+ (((INT32 *) VendorGuid)[1] == ((INT32 *) &VariableHeader->VendorGuid)[1]) &&
+ (((INT32 *) VendorGuid)[2] == ((INT32 *) &VariableHeader->VendorGuid)[2]) &&
+ (((INT32 *) VendorGuid)[3] == ((INT32 *) &VariableHeader->VendorGuid)[3])
) {
- ASSERT (NameSizeOfVariable (Variable) != 0);
+ ASSERT (NameSizeOfVariable (VariableHeader) != 0);
Point = (VOID *) GetVariableNamePtr (Variable);
- if (CompareMem (VariableName, Point, NameSizeOfVariable (Variable)) == 0) {
+ if (CompareVariableName (StoreInfo, VariableName, Point, NameSizeOfVariable (VariableHeader))) {
PtrTrack->CurrPtr = Variable;
return EFI_SUCCESS;
}
@@ -323,26 +412,29 @@ CompareWithValidVariable (
}
/**
- Return the variable store header and the index table based on the Index.
+ Return the variable store header and the store info based on the Index.
@param Type The type of the variable store.
- @param IndexTable Return the index table.
+ @param StoreInfo Return the store info.
@return Pointer to the variable store header.
**/
VARIABLE_STORE_HEADER *
GetVariableStore (
IN VARIABLE_STORE_TYPE Type,
- OUT VARIABLE_INDEX_TABLE **IndexTable OPTIONAL
+ OUT VARIABLE_STORE_INFO *StoreInfo
)
{
- EFI_HOB_GUID_TYPE *GuidHob;
- EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
- VARIABLE_STORE_HEADER *VariableStoreHeader;
-
- if (IndexTable != NULL) {
- *IndexTable = NULL;
- }
+ EFI_HOB_GUID_TYPE *GuidHob;
+ EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ EFI_PHYSICAL_ADDRESS NvStorageBase;
+ UINT32 NvStorageSize;
+ FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *FtwLastWriteData;
+ UINT32 BackUpOffset;
+
+ StoreInfo->IndexTable = NULL;
+ StoreInfo->FtwLastWriteData = NULL;
VariableStoreHeader = NULL;
switch (Type) {
case VariableStoreTypeHob:
@@ -357,10 +449,42 @@ GetVariableStore (
//
// The content of NV storage for variable is not reliable in recovery boot mode.
//
- FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (PcdGet64 (PcdFlashNvStorageVariableBase64) != 0 ?
- PcdGet64 (PcdFlashNvStorageVariableBase64) :
- PcdGet32 (PcdFlashNvStorageVariableBase)
- );
+
+ NvStorageSize = PcdGet32 (PcdFlashNvStorageVariableSize);
+ NvStorageBase = (EFI_PHYSICAL_ADDRESS) (PcdGet64 (PcdFlashNvStorageVariableBase64) != 0 ?
+ PcdGet64 (PcdFlashNvStorageVariableBase64) :
+ PcdGet32 (PcdFlashNvStorageVariableBase)
+ );
+ //
+ // First let FvHeader point to NV storage base.
+ //
+ FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) NvStorageBase;
+
+ //
+ // Check the FTW last write data hob.
+ //
+ BackUpOffset = 0;
+ GuidHob = GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid);
+ if (GuidHob != NULL) {
+ FtwLastWriteData = (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *) GET_GUID_HOB_DATA (GuidHob);
+ if (FtwLastWriteData->TargetAddress == NvStorageBase) {
+ //
+ // Let FvHeader point to spare block.
+ //
+ FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) FtwLastWriteData->SpareAddress;
+ DEBUG ((EFI_D_INFO, "PeiVariable: NV storage is backed up in spare block: 0x%x\n", (UINTN) FtwLastWriteData->SpareAddress));
+ } else if ((FtwLastWriteData->TargetAddress > NvStorageBase) && (FtwLastWriteData->TargetAddress < (NvStorageBase + NvStorageSize))) {
+ StoreInfo->FtwLastWriteData = FtwLastWriteData;
+ //
+ // Flash NV storage from the offset is backed up in spare block.
+ //
+ BackUpOffset = (UINT32) (FtwLastWriteData->TargetAddress - NvStorageBase);
+ 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));
+ //
+ // At least one block data in flash NV storage is still valid, so still leave FvHeader point to NV storage base.
+ //
+ }
+ }
//
// Check if the Firmware Volume is not corrupted
@@ -372,23 +496,21 @@ GetVariableStore (
VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINT8 *) FvHeader + FvHeader->HeaderLength);
- if (IndexTable != NULL) {
- GuidHob = GetFirstGuidHob (&gEfiVariableIndexTableGuid);
- if (GuidHob != NULL) {
- *IndexTable = GET_GUID_HOB_DATA (GuidHob);
- } else {
- //
- // If it's the first time to access variable region in flash, create a guid hob to record
- // VAR_ADDED type variable info.
- // Note that as the resource of PEI phase is limited, only store the limited number of
- // VAR_ADDED type variables to reduce access time.
- //
- *IndexTable = BuildGuidHob (&gEfiVariableIndexTableGuid, sizeof (VARIABLE_INDEX_TABLE));
- (*IndexTable)->Length = 0;
- (*IndexTable)->StartPtr = GetStartPointer (VariableStoreHeader);
- (*IndexTable)->EndPtr = GetEndPointer (VariableStoreHeader);
- (*IndexTable)->GoneThrough = 0;
- }
+ GuidHob = GetFirstGuidHob (&gEfiVariableIndexTableGuid);
+ if (GuidHob != NULL) {
+ StoreInfo->IndexTable = GET_GUID_HOB_DATA (GuidHob);
+ } else {
+ //
+ // If it's the first time to access variable region in flash, create a guid hob to record
+ // VAR_ADDED type variable info.
+ // Note that as the resource of PEI phase is limited, only store the limited number of
+ // VAR_ADDED type variables to reduce access time.
+ //
+ StoreInfo->IndexTable = (VARIABLE_INDEX_TABLE *) BuildGuidHob (&gEfiVariableIndexTableGuid, sizeof (VARIABLE_INDEX_TABLE));
+ StoreInfo->IndexTable->Length = 0;
+ StoreInfo->IndexTable->StartPtr = GetStartPointer (VariableStoreHeader);
+ StoreInfo->IndexTable->EndPtr = GetEndPointer (VariableStoreHeader);
+ StoreInfo->IndexTable->GoneThrough = 0;
}
}
break;
@@ -398,14 +520,118 @@ GetVariableStore (
break;
}
+ StoreInfo->VariableStoreHeader = VariableStoreHeader;
return VariableStoreHeader;
}
/**
+ Get variable header that has consecutive content.
+
+ @param StoreInfo Pointer to variable store info structure.
+ @param Variable Pointer to the Variable Header.
+ @param VariableHeader Pointer to Pointer to the Variable Header that has consecutive content.
+
+ @retval TRUE Variable header is valid.
+ @retval FALSE Variable header is not valid.
+
+**/
+BOOLEAN
+GetVariableHeader (
+ IN VARIABLE_STORE_INFO *StoreInfo,
+ IN VARIABLE_HEADER *Variable,
+ OUT VARIABLE_HEADER **VariableHeader
+ )
+{
+ EFI_PHYSICAL_ADDRESS TargetAddress;
+ EFI_PHYSICAL_ADDRESS SpareAddress;
+ EFI_HOB_GUID_TYPE *GuidHob;
+ UINTN PartialHeaderSize;
+
+ //
+ // First assume variable header pointed by Variable is consecutive.
+ //
+ *VariableHeader = Variable;
+
+ if ((Variable != NULL) && (StoreInfo->FtwLastWriteData != NULL)) {
+ TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
+ SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress;
+ if (((UINTN) Variable < (UINTN) TargetAddress) && (((UINTN) Variable + sizeof (VARIABLE_HEADER)) > (UINTN) TargetAddress)) {
+ //
+ // Variable header pointed by Variable is inconsecutive,
+ // create a guid hob to combine the two partial variable header content together.
+ //
+ GuidHob = GetFirstGuidHob (&gEfiCallerIdGuid);
+ if (GuidHob != NULL) {
+ *VariableHeader = (VARIABLE_HEADER *) GET_GUID_HOB_DATA (GuidHob);
+ } else {
+ *VariableHeader = (VARIABLE_HEADER *) BuildGuidHob (&gEfiCallerIdGuid, sizeof (VARIABLE_HEADER));
+ PartialHeaderSize = (UINTN) TargetAddress - (UINTN) Variable;
+ //
+ // Partial content is in NV storage.
+ //
+ CopyMem ((UINT8 *) *VariableHeader, (UINT8 *) Variable, PartialHeaderSize);
+ //
+ // Another partial content is in spare block.
+ //
+ CopyMem ((UINT8 *) *VariableHeader + PartialHeaderSize, (UINT8 *) (UINTN) SpareAddress, sizeof (VARIABLE_HEADER) - PartialHeaderSize);
+ }
+ }
+ }
+
+ return IsValidVariableHeader (*VariableHeader);
+}
+
+/**
+ Get variable name or data to output buffer.
+
+ @param StoreInfo Pointer to variable store info structure.
+ @param NameOrData Pointer to the variable name/data that may be inconsecutive.
+ @param Size Variable name/data size.
+ @param Buffer Pointer to output buffer to hold the variable name/data.
+
+**/
+VOID
+GetVariableNameOrData (
+ IN VARIABLE_STORE_INFO *StoreInfo,
+ IN UINT8 *NameOrData,
+ IN UINTN Size,
+ OUT UINT8 *Buffer
+ )
+{
+ EFI_PHYSICAL_ADDRESS TargetAddress;
+ EFI_PHYSICAL_ADDRESS SpareAddress;
+ UINTN PartialSize;
+
+ if (StoreInfo->FtwLastWriteData != NULL) {
+ TargetAddress = StoreInfo->FtwLastWriteData->TargetAddress;
+ SpareAddress = StoreInfo->FtwLastWriteData->SpareAddress;
+ if (((UINTN) NameOrData < (UINTN) TargetAddress) && (((UINTN) NameOrData + Size) > (UINTN) TargetAddress)) {
+ //
+ // Variable name/data is inconsecutive.
+ //
+ PartialSize = (UINTN) TargetAddress - (UINTN) NameOrData;
+ //
+ // Partial content is in NV storage.
+ //
+ CopyMem (Buffer, NameOrData, PartialSize);
+ //
+ // Another partial content is in spare block.
+ //
+ CopyMem (Buffer + PartialSize, (UINT8 *) (UINTN) SpareAddress, Size - PartialSize);
+ return;
+ }
+ }
+
+ //
+ // Variable name/data is consecutive.
+ //
+ CopyMem (Buffer, NameOrData, Size);
+}
+
+/**
Find the variable in the specified variable store.
- @param VariableStoreHeader Pointer to the variable store header.
- @param IndexTable Pointer to the index table.
+ @param StoreInfo Pointer to the store info structure.
@param VariableName Name of the variable to be found
@param VendorGuid Vendor GUID to be found.
@param PtrTrack Variable Track Pointer structure that contains Variable Information.
@@ -417,8 +643,7 @@ GetVariableStore (
**/
EFI_STATUS
FindVariableEx (
- IN VARIABLE_STORE_HEADER *VariableStoreHeader,
- IN VARIABLE_INDEX_TABLE *IndexTable,
+ IN VARIABLE_STORE_INFO *StoreInfo,
IN CONST CHAR16 *VariableName,
IN CONST EFI_GUID *VendorGuid,
OUT VARIABLE_POINTER_TRACK *PtrTrack
@@ -431,6 +656,11 @@ FindVariableEx (
UINTN Offset;
BOOLEAN StopRecord;
VARIABLE_HEADER *InDeletedVariable;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ VARIABLE_INDEX_TABLE *IndexTable;
+ VARIABLE_HEADER *VariableHeader;
+
+ VariableStoreHeader = StoreInfo->VariableStoreHeader;
if (VariableStoreHeader == NULL) {
return EFI_INVALID_PARAMETER;
@@ -444,6 +674,7 @@ FindVariableEx (
return EFI_NOT_FOUND;
}
+ IndexTable = StoreInfo->IndexTable;
PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader);
PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader);
@@ -453,6 +684,7 @@ FindVariableEx (
// No Variable Address equals zero, so 0 as initial value is safe.
//
MaxIndex = NULL;
+ VariableHeader = NULL;
if (IndexTable != NULL) {
//
@@ -463,8 +695,9 @@ FindVariableEx (
ASSERT (Index < sizeof (IndexTable->Index) / sizeof (IndexTable->Index[0]));
Offset += IndexTable->Index[Index];
MaxIndex = (VARIABLE_HEADER *) ((UINT8 *) IndexTable->StartPtr + Offset);
- if (CompareWithValidVariable (MaxIndex, VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) {
- if (PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
+ GetVariableHeader (StoreInfo, MaxIndex, &VariableHeader);
+ if (CompareWithValidVariable (StoreInfo, MaxIndex, VariableHeader, VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) {
+ if (VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
InDeletedVariable = PtrTrack->CurrPtr;
} else {
return EFI_SUCCESS;
@@ -486,7 +719,7 @@ FindVariableEx (
// HOB exists but the variable cannot be found in HOB
// If not found in HOB, then let's start from the MaxIndex we've found.
//
- Variable = GetNextVariablePtr (MaxIndex);
+ Variable = GetNextVariablePtr (StoreInfo, MaxIndex, VariableHeader);
LastVariable = MaxIndex;
} else {
//
@@ -501,8 +734,8 @@ FindVariableEx (
// Find the variable by walk through variable store
//
StopRecord = FALSE;
- while ((Variable < PtrTrack->EndPtr) && IsValidVariableHeader (Variable)) {
- if (Variable->State == VAR_ADDED || Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
+ while (GetVariableHeader (StoreInfo, Variable, &VariableHeader)) {
+ if (VariableHeader->State == VAR_ADDED || VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
//
// Record Variable in VariableIndex HOB
//
@@ -520,8 +753,8 @@ FindVariableEx (
}
}
- if (CompareWithValidVariable (Variable, VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) {
- if (PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
+ if (CompareWithValidVariable (StoreInfo, Variable, VariableHeader, VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) {
+ if (VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
InDeletedVariable = PtrTrack->CurrPtr;
} else {
return EFI_SUCCESS;
@@ -529,7 +762,7 @@ FindVariableEx (
}
}
- Variable = GetNextVariablePtr (Variable);
+ Variable = GetNextVariablePtr (StoreInfo, Variable, VariableHeader);
}
//
// If gone through the VariableStore, that means we never find in Firmware any more.
@@ -549,6 +782,7 @@ FindVariableEx (
@param VariableName Name of the variable to be found
@param VendorGuid Vendor GUID to be found.
@param PtrTrack Variable Track Pointer structure that contains Variable Information.
+ @param StoreInfo Return the store info.
@retval EFI_SUCCESS Variable found successfully
@retval EFI_NOT_FOUND Variable not found
@@ -558,12 +792,11 @@ EFI_STATUS
FindVariable (
IN CONST CHAR16 *VariableName,
IN CONST EFI_GUID *VendorGuid,
- OUT VARIABLE_POINTER_TRACK *PtrTrack
+ OUT VARIABLE_POINTER_TRACK *PtrTrack,
+ OUT VARIABLE_STORE_INFO *StoreInfo
)
{
EFI_STATUS Status;
- VARIABLE_STORE_HEADER *VariableStoreHeader;
- VARIABLE_INDEX_TABLE *IndexTable;
VARIABLE_STORE_TYPE Type;
if (VariableName[0] != 0 && VendorGuid == NULL) {
@@ -571,10 +804,9 @@ FindVariable (
}
for (Type = (VARIABLE_STORE_TYPE) 0; Type < VariableStoreTypeMax; Type++) {
- VariableStoreHeader = GetVariableStore (Type, &IndexTable);
+ GetVariableStore (Type, StoreInfo);
Status = FindVariableEx (
- VariableStoreHeader,
- IndexTable,
+ StoreInfo,
VariableName,
VendorGuid,
PtrTrack
@@ -627,6 +859,8 @@ PeiGetVariable (
VARIABLE_POINTER_TRACK Variable;
UINTN VarDataSize;
EFI_STATUS Status;
+ VARIABLE_STORE_INFO StoreInfo;
+ VARIABLE_HEADER *VariableHeader;
if (VariableName == NULL || VariableGuid == NULL || DataSize == NULL) {
return EFI_INVALID_PARAMETER;
@@ -635,23 +869,25 @@ PeiGetVariable (
//
// Find existing variable
//
- Status = FindVariable (VariableName, VariableGuid, &Variable);
+ Status = FindVariable (VariableName, VariableGuid, &Variable, &StoreInfo);
if (EFI_ERROR (Status)) {
return Status;
}
+ GetVariableHeader (&StoreInfo, Variable.CurrPtr, &VariableHeader);
+
//
// Get data size
//
- VarDataSize = DataSizeOfVariable (Variable.CurrPtr);
+ VarDataSize = DataSizeOfVariable (VariableHeader);
if (*DataSize >= VarDataSize) {
if (Data == NULL) {
return EFI_INVALID_PARAMETER;
}
- CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr), VarDataSize);
+ GetVariableNameOrData (&StoreInfo, GetVariableDataPtr (Variable.CurrPtr, VariableHeader), VarDataSize, Data);
if (Attributes != NULL) {
- *Attributes = Variable.CurrPtr->Attributes;
+ *Attributes = VariableHeader->Attributes;
}
*DataSize = VarDataSize;
@@ -704,16 +940,19 @@ PeiGetNextVariableName (
VARIABLE_POINTER_TRACK Variable;
VARIABLE_POINTER_TRACK VariableInHob;
VARIABLE_POINTER_TRACK VariablePtrTrack;
- VARIABLE_INDEX_TABLE *IndexTable;
UINTN VarNameSize;
EFI_STATUS Status;
VARIABLE_STORE_HEADER *VariableStoreHeader[VariableStoreTypeMax];
+ VARIABLE_HEADER *VariableHeader;
+ VARIABLE_STORE_INFO StoreInfo;
+ VARIABLE_STORE_INFO StoreInfoForNv;
+ VARIABLE_STORE_INFO StoreInfoForHob;
if (VariableName == NULL || VariableGuid == NULL || VariableNameSize == NULL) {
return EFI_INVALID_PARAMETER;
}
- Status = FindVariable (VariableName, VariableGuid, &Variable);
+ Status = FindVariable (VariableName, VariableGuid, &Variable, &StoreInfo);
if (Variable.CurrPtr == NULL || Status != EFI_SUCCESS) {
return Status;
}
@@ -722,20 +961,18 @@ PeiGetNextVariableName (
//
// If variable name is not NULL, get next variable
//
- Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);
+ GetVariableHeader (&StoreInfo, Variable.CurrPtr, &VariableHeader);
+ Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr, VariableHeader);
}
- VariableStoreHeader[VariableStoreTypeHob] = GetVariableStore (VariableStoreTypeHob, NULL);
- VariableStoreHeader[VariableStoreTypeNv] = GetVariableStore (VariableStoreTypeNv, NULL);
+ VariableStoreHeader[VariableStoreTypeHob] = GetVariableStore (VariableStoreTypeHob, &StoreInfoForHob);
+ VariableStoreHeader[VariableStoreTypeNv] = GetVariableStore (VariableStoreTypeNv, &StoreInfoForNv);
while (TRUE) {
//
// Switch from HOB to Non-Volatile.
//
- while ((Variable.CurrPtr >= Variable.EndPtr) ||
- (Variable.CurrPtr == NULL) ||
- !IsValidVariableHeader (Variable.CurrPtr)
- ) {
+ while (!GetVariableHeader (&StoreInfo, Variable.CurrPtr, &VariableHeader)) {
//
// Find current storage index
//
@@ -764,31 +1001,24 @@ PeiGetNextVariableName (
Variable.StartPtr = GetStartPointer (VariableStoreHeader[Type]);
Variable.EndPtr = GetEndPointer (VariableStoreHeader[Type]);
Variable.CurrPtr = Variable.StartPtr;
+ GetVariableStore (Type, &StoreInfo);
}
- if (Variable.CurrPtr->State == VAR_ADDED || Variable.CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
- if (Variable.CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
+ if (VariableHeader->State == VAR_ADDED || VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
+ if (VariableHeader->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
//
// If it is a IN_DELETED_TRANSITION variable,
// and there is also a same ADDED one at the same time,
// don't return it.
//
- for (Type = (VARIABLE_STORE_TYPE) 0; Type < VariableStoreTypeMax; Type++) {
- if ((VariableStoreHeader[Type] != NULL) && (Variable.StartPtr == GetStartPointer (VariableStoreHeader[Type]))) {
- break;
- }
- }
- ASSERT (Type < VariableStoreTypeMax);
- GetVariableStore (Type, &IndexTable);
Status = FindVariableEx (
- VariableStoreHeader[Type],
- IndexTable,
+ &StoreInfo,
GetVariableNamePtr (Variable.CurrPtr),
- &Variable.CurrPtr->VendorGuid,
+ &VariableHeader->VendorGuid,
&VariablePtrTrack
);
- if (!EFI_ERROR (Status) && VariablePtrTrack.CurrPtr->State == VAR_ADDED) {
- Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);
+ if (!EFI_ERROR (Status) && VariablePtrTrack.CurrPtr != Variable.CurrPtr) {
+ Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr, VariableHeader);
continue;
}
}
@@ -800,25 +1030,24 @@ PeiGetNextVariableName (
(Variable.StartPtr == GetStartPointer (VariableStoreHeader[VariableStoreTypeNv]))
) {
Status = FindVariableEx (
- VariableStoreHeader[VariableStoreTypeHob],
- NULL,
+ &StoreInfoForHob,
GetVariableNamePtr (Variable.CurrPtr),
- &Variable.CurrPtr->VendorGuid,
+ &VariableHeader->VendorGuid,
&VariableInHob
);
if (!EFI_ERROR (Status)) {
- Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);
+ Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr, VariableHeader);
continue;
}
}
- VarNameSize = NameSizeOfVariable (Variable.CurrPtr);
+ VarNameSize = NameSizeOfVariable (VariableHeader);
ASSERT (VarNameSize != 0);
if (VarNameSize <= *VariableNameSize) {
- CopyMem (VariableName, GetVariableNamePtr (Variable.CurrPtr), VarNameSize);
+ GetVariableNameOrData (&StoreInfo, (UINT8 *) GetVariableNamePtr (Variable.CurrPtr), VarNameSize, (UINT8 *) VariableName);
- CopyMem (VariableGuid, &Variable.CurrPtr->VendorGuid, sizeof (EFI_GUID));
+ CopyMem (VariableGuid, &VariableHeader->VendorGuid, sizeof (EFI_GUID));
Status = EFI_SUCCESS;
} else {
@@ -831,7 +1060,7 @@ PeiGetNextVariableName (
//
return Status;
} else {
- Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);
+ Variable.CurrPtr = GetNextVariablePtr (&StoreInfo, Variable.CurrPtr, VariableHeader);
}
}
}
diff --git a/MdeModulePkg/Universal/Variable/Pei/Variable.h b/MdeModulePkg/Universal/Variable/Pei/Variable.h
index e0d8679d63..55277b04f1 100644
--- a/MdeModulePkg/Universal/Variable/Pei/Variable.h
+++ b/MdeModulePkg/Universal/Variable/Pei/Variable.h
@@ -3,7 +3,7 @@
The internal header file includes the common header files, defines
internal structure and functions used by PeiVariable module.
-Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
@@ -31,6 +31,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include <Guid/VariableFormat.h>
#include <Guid/VariableIndexTable.h>
#include <Guid/SystemNvDataGuid.h>
+#include <Guid/FaultTolerantWrite.h>
typedef enum {
VariableStoreTypeHob,
@@ -38,6 +39,17 @@ typedef enum {
VariableStoreTypeMax
} VARIABLE_STORE_TYPE;
+typedef struct {
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ VARIABLE_INDEX_TABLE *IndexTable;
+ //
+ // If it is not NULL, it means there may be an inconsecutive variable whose
+ // partial content is still in NV storage, but another partial content is backed up
+ // in spare block.
+ //
+ FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *FtwLastWriteData;
+} VARIABLE_STORE_INFO;
+
//
// Functions
//
diff --git a/MdeModulePkg/Universal/Variable/Pei/VariablePei.inf b/MdeModulePkg/Universal/Variable/Pei/VariablePei.inf
index da07cf7b7a..8bae162a37 100644
--- a/MdeModulePkg/Universal/Variable/Pei/VariablePei.inf
+++ b/MdeModulePkg/Universal/Variable/Pei/VariablePei.inf
@@ -3,7 +3,7 @@
# Implement ReadOnly Variable Services required by PEIM and install
# PEI ReadOnly Varaiable2 PPI. These services operates the non-volatile storage space.
#
-# Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
@@ -49,16 +49,18 @@
gEfiVariableGuid
gEfiVariableIndexTableGuid
gEfiSystemNvDataFvGuid
+ gEdkiiFaultTolerantWriteGuid
[Ppis]
- gEfiPeiReadOnlyVariable2PpiGuid ## SOMETIMES_PRODUCES (Not for boot mode RECOVERY)
+ gEfiPeiReadOnlyVariable2PpiGuid ## PRODUCES
[Pcd]
- gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase ## CONSUMES
- gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64 ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64 ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize ## CONSUMES
[Depex]
- TRUE
+ gEdkiiFaultTolerantWriteGuid
#
# [BootMode]
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c
index 9f983ffc9f..09b8b4bd21 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c
@@ -2583,6 +2583,135 @@ ReclaimForOS(
}
/**
+ Init non-volatile variable store.
+
+ @retval EFI_SUCCESS Function successfully executed.
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
+ @retval EFI_VOLUME_CORRUPTED Variable Store or Firmware Volume for Variable Store is corrupted.
+
+**/
+EFI_STATUS
+InitNonVolatileVariableStore (
+ VOID
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
+ VARIABLE_HEADER *NextVariable;
+ EFI_PHYSICAL_ADDRESS VariableStoreBase;
+ UINT64 VariableStoreLength;
+ UINTN VariableSize;
+ EFI_HOB_GUID_TYPE *GuidHob;
+ EFI_PHYSICAL_ADDRESS NvStorageBase;
+ UINT8 *NvStorageData;
+ UINT32 NvStorageSize;
+ FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *FtwLastWriteData;
+ UINT32 BackUpOffset;
+ UINT32 BackUpSize;
+
+ mVariableModuleGlobal->FvbInstance = NULL;
+
+ //
+ // Note that in EdkII variable driver implementation, Hardware Error Record type variable
+ // is stored with common variable in the same NV region. So the platform integrator should
+ // ensure that the value of PcdHwErrStorageSize is less than or equal to the value of
+ // PcdFlashNvStorageVariableSize.
+ //
+ ASSERT (PcdGet32 (PcdHwErrStorageSize) <= PcdGet32 (PcdFlashNvStorageVariableSize));
+
+ //
+ // Allocate runtime memory used for a memory copy of the FLASH region.
+ // Keep the memory and the FLASH in sync as updates occur.
+ //
+ NvStorageSize = PcdGet32 (PcdFlashNvStorageVariableSize);
+ NvStorageData = AllocateRuntimeZeroPool (NvStorageSize);
+ if (NvStorageData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NvStorageBase = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageVariableBase64);
+ if (NvStorageBase == 0) {
+ NvStorageBase = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);
+ }
+ //
+ // Copy NV storage data to the memory buffer.
+ //
+ CopyMem (NvStorageData, (UINT8 *) (UINTN) NvStorageBase, NvStorageSize);
+
+ //
+ // Check the FTW last write data hob.
+ //
+ GuidHob = GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid);
+ if (GuidHob != NULL) {
+ FtwLastWriteData = (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *) GET_GUID_HOB_DATA (GuidHob);
+ if (FtwLastWriteData->TargetAddress == NvStorageBase) {
+ DEBUG ((EFI_D_INFO, "Variable: NV storage is backed up in spare block: 0x%x\n", (UINTN) FtwLastWriteData->SpareAddress));
+ //
+ // Copy the backed up NV storage data to the memory buffer from spare block.
+ //
+ CopyMem (NvStorageData, (UINT8 *) (UINTN) (FtwLastWriteData->SpareAddress), NvStorageSize);
+ } else if ((FtwLastWriteData->TargetAddress > NvStorageBase) &&
+ (FtwLastWriteData->TargetAddress < (NvStorageBase + NvStorageSize))) {
+ //
+ // Flash NV storage from the offset is backed up in spare block.
+ //
+ BackUpOffset = (UINT32) (FtwLastWriteData->TargetAddress - NvStorageBase);
+ BackUpSize = NvStorageSize - BackUpOffset;
+ DEBUG ((EFI_D_INFO, "Variable: High partial NV storage from offset: %x is backed up in spare block: 0x%x\n", BackUpOffset, (UINTN) FtwLastWriteData->SpareAddress));
+ //
+ // Copy the partial backed up NV storage data to the memory buffer from spare block.
+ //
+ CopyMem (NvStorageData + BackUpOffset, (UINT8 *) (UINTN) FtwLastWriteData->SpareAddress, BackUpSize);
+ }
+ }
+
+ FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) NvStorageData;
+
+ //
+ // Check if the Firmware Volume is not corrupted
+ //
+ if ((FvHeader->Signature != EFI_FVH_SIGNATURE) || (!CompareGuid (&gEfiSystemNvDataFvGuid, &FvHeader->FileSystemGuid))) {
+ FreePool (NvStorageData);
+ DEBUG ((EFI_D_ERROR, "Firmware Volume for Variable Store is corrupted\n"));
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ VariableStoreBase = (EFI_PHYSICAL_ADDRESS) ((UINTN) FvHeader + FvHeader->HeaderLength);
+ VariableStoreLength = (UINT64) (NvStorageSize - FvHeader->HeaderLength);
+
+ mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;
+ mNvVariableCache = (VARIABLE_STORE_HEADER *) (UINTN) VariableStoreBase;
+ if (GetVariableStoreStatus (mNvVariableCache) != EfiValid) {
+ FreePool (NvStorageData);
+ DEBUG((EFI_D_ERROR, "Variable Store header is corrupted\n"));
+ return EFI_VOLUME_CORRUPTED;
+ }
+ ASSERT(mNvVariableCache->Size == VariableStoreLength);
+
+ //
+ // The max variable or hardware error variable size should be < variable store size.
+ //
+ ASSERT(MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize)) < VariableStoreLength);
+
+ //
+ // Parse non-volatile variable data and get last variable offset.
+ //
+ NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase);
+ while (IsValidVariableHeader (NextVariable)) {
+ VariableSize = NextVariable->NameSize + NextVariable->DataSize + sizeof (VARIABLE_HEADER);
+ if ((NextVariable->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
+ mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VariableSize);
+ } else {
+ mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VariableSize);
+ }
+
+ NextVariable = GetNextVariablePtr (NextVariable);
+ }
+ mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) VariableStoreBase;
+
+ return EFI_SUCCESS;
+}
+
+/**
Flush the HOB variable to flash.
@param[in] VariableName Name of variable has been updated or deleted.
@@ -2673,7 +2802,7 @@ FlushHobVariableToFlash (
}
/**
- Initializes variable write service after FVB was ready.
+ Initializes variable write service after FTW was ready.
@retval EFI_SUCCESS Function successfully executed.
@retval Others Fail to initialize the variable service.
@@ -2689,8 +2818,18 @@ VariableWriteServiceInitialize (
UINTN Index;
UINT8 Data;
EFI_PHYSICAL_ADDRESS VariableStoreBase;
+ EFI_PHYSICAL_ADDRESS NvStorageBase;
- VariableStoreBase = mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;
+ NvStorageBase = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageVariableBase64);
+ if (NvStorageBase == 0) {
+ NvStorageBase = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);
+ }
+ VariableStoreBase = NvStorageBase + (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(NvStorageBase))->HeaderLength);
+
+ //
+ // Let NonVolatileVariableBase point to flash variable store base directly after FTW ready.
+ //
+ mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;
VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase;
//
@@ -2737,12 +2876,8 @@ VariableCommonInitialize (
EFI_STATUS Status;
VARIABLE_STORE_HEADER *VolatileVariableStore;
VARIABLE_STORE_HEADER *VariableStoreHeader;
- VARIABLE_HEADER *NextVariable;
- EFI_PHYSICAL_ADDRESS TempVariableStoreHeader;
- EFI_PHYSICAL_ADDRESS VariableStoreBase;
UINT64 VariableStoreLength;
UINTN ScratchSize;
- UINTN VariableSize;
EFI_HOB_GUID_TYPE *GuidHob;
//
@@ -2756,14 +2891,6 @@ VariableCommonInitialize (
InitializeLock (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock, TPL_NOTIFY);
//
- // Note that in EdkII variable driver implementation, Hardware Error Record type variable
- // is stored with common variable in the same NV region. So the platform integrator should
- // ensure that the value of PcdHwErrStorageSize is less than or equal to the value of
- // PcdFlashNvStorageVariableSize.
- //
- ASSERT (PcdGet32 (PcdHwErrStorageSize) <= PcdGet32 (PcdFlashNvStorageVariableSize));
-
- //
// Get HOB variable store.
//
GuidHob = GetFirstGuidHob (&gEfiVariableGuid);
@@ -2773,6 +2900,7 @@ VariableCommonInitialize (
if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) {
mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) AllocateRuntimeCopyPool ((UINTN) VariableStoreLength, (VOID *) VariableStoreHeader);
if (mVariableModuleGlobal->VariableGlobal.HobVariableBase == 0) {
+ FreePool (mVariableModuleGlobal);
return EFI_OUT_OF_RESOURCES;
}
} else {
@@ -2786,6 +2914,9 @@ VariableCommonInitialize (
ScratchSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize));
VolatileVariableStore = AllocateRuntimePool (PcdGet32 (PcdVariableStoreSize) + ScratchSize);
if (VolatileVariableStore == NULL) {
+ if (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) {
+ FreePool ((VOID *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase);
+ }
FreePool (mVariableModuleGlobal);
return EFI_OUT_OF_RESOURCES;
}
@@ -2797,7 +2928,6 @@ VariableCommonInitialize (
//
mVariableModuleGlobal->VariableGlobal.VolatileVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VolatileVariableStore;
mVariableModuleGlobal->VolatileLastVariableOffset = (UINTN) GetStartPointer (VolatileVariableStore) - (UINTN) VolatileVariableStore;
- mVariableModuleGlobal->FvbInstance = NULL;
CopyGuid (&VolatileVariableStore->Signature, &gEfiVariableGuid);
VolatileVariableStore->Size = PcdGet32 (PcdVariableStoreSize);
@@ -2807,74 +2937,13 @@ VariableCommonInitialize (
VolatileVariableStore->Reserved1 = 0;
//
- // Get non-volatile variable store.
- //
-
- TempVariableStoreHeader = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageVariableBase64);
- if (TempVariableStoreHeader == 0) {
- TempVariableStoreHeader = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);
- }
-
- //
- // Check if the Firmware Volume is not corrupted
- //
- if ((((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader))->Signature != EFI_FVH_SIGNATURE) ||
- (!CompareGuid (&gEfiSystemNvDataFvGuid, &((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader))->FileSystemGuid))) {
- Status = EFI_VOLUME_CORRUPTED;
- DEBUG ((EFI_D_ERROR, "Firmware Volume for Variable Store is corrupted\n"));
- goto Done;
- }
-
- VariableStoreBase = TempVariableStoreHeader + \
- (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader)) -> HeaderLength);
- VariableStoreLength = (UINT64) PcdGet32 (PcdFlashNvStorageVariableSize) - \
- (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader)) -> HeaderLength);
-
- mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;
- VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase;
- if (GetVariableStoreStatus (VariableStoreHeader) != EfiValid) {
- Status = EFI_VOLUME_CORRUPTED;
- DEBUG((EFI_D_INFO, "Variable Store header is corrupted\n"));
- goto Done;
- }
- ASSERT(VariableStoreHeader->Size == VariableStoreLength);
-
- //
- // The max variable or hardware error variable size should be < variable store size.
- //
- ASSERT(MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize)) < VariableStoreLength);
-
- //
- // Parse non-volatile variable data and get last variable offset.
- //
- NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase);
- while (IsValidVariableHeader (NextVariable)) {
- VariableSize = NextVariable->NameSize + NextVariable->DataSize + sizeof (VARIABLE_HEADER);
- if ((NextVariable->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
- mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VariableSize);
- } else {
- mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VariableSize);
- }
-
- NextVariable = GetNextVariablePtr (NextVariable);
- }
-
- mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) VariableStoreBase;
-
- //
- // Allocate runtime memory used for a memory copy of the FLASH region.
- // Keep the memory and the FLASH in sync as updates occur
+ // Init non-volatile variable store.
//
- mNvVariableCache = AllocateRuntimeZeroPool ((UINTN)VariableStoreLength);
- if (mNvVariableCache == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Done;
- }
- CopyMem (mNvVariableCache, (CHAR8 *)(UINTN)VariableStoreBase, (UINTN)VariableStoreLength);
- Status = EFI_SUCCESS;
-
-Done:
+ Status = InitNonVolatileVariableStore ();
if (EFI_ERROR (Status)) {
+ if (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) {
+ FreePool ((VOID *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase);
+ }
FreePool (mVariableModuleGlobal);
FreePool (VolatileVariableStore);
}
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h
index b5e6edec93..264a2396c6 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.h
@@ -39,6 +39,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include <Guid/EventGroup.h>
#include <Guid/VariableFormat.h>
#include <Guid/SystemNvDataGuid.h>
+#include <Guid/FaultTolerantWrite.h>
#include <Guid/HardwareErrorVariable.h>
#define VARIABLE_RECLAIM_THRESHOLD (1024)
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
index 8cbefefa1b..c712ba0200 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
@@ -68,6 +68,7 @@
gEfiSystemNvDataFvGuid ## CONSUMES
gEfiHardwareErrorVariableGuid ## SOMETIMES_CONSUMES
gEfiEndOfDxeEventGroupGuid ## CONSUMES ## Event
+ gEdkiiFaultTolerantWriteGuid ## CONSUMES
[Pcd]
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf
index c229805bc9..89ec686ca1 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf
@@ -77,6 +77,7 @@
gSmmVariableWriteGuid ## PRODUCES ## SMM Variable Write Guid
gEfiSystemNvDataFvGuid ## CONSUMES
gEfiHardwareErrorVariableGuid ## SOMETIMES_CONSUMES
+ gEdkiiFaultTolerantWriteGuid ## CONSUMES
[Pcd]
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize