The common variable operation routines shared by DXE_RUNTIME variable \r
module and DXE_SMM variable module.\r
\r
-Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>\r
This program and the accompanying materials \r
are licensed and made available under the terms and conditions of the BSD License \r
which accompanies this distribution. The full text of the license may be found at \r
///\r
/// Define a memory cache that improves the search performance for a variable.\r
///\r
-VARIABLE_STORE_HEADER *mNvVariableCache = NULL;\r
+VARIABLE_STORE_HEADER *mNvVariableCache = NULL;\r
\r
///\r
/// The memory entry used for variable statistics data.\r
///\r
-VARIABLE_INFO_ENTRY *gVariableInfo = NULL;\r
+VARIABLE_INFO_ENTRY *gVariableInfo = NULL;\r
+\r
+///\r
+/// The list to store the variables which cannot be set after the EFI_END_OF_DXE_EVENT_GROUP_GUID\r
+/// or EVT_GROUP_READY_TO_BOOT event.\r
+///\r
+LIST_ENTRY mLockedVariableList = INITIALIZE_LIST_HEAD_VARIABLE (mLockedVariableList);\r
+\r
+///\r
+/// The flag to indicate whether the platform has left the DXE phase of execution.\r
+///\r
+BOOLEAN mEndOfDxe = FALSE;\r
+\r
+///\r
+/// The flag to indicate whether the variable storage locking is enabled.\r
+///\r
+BOOLEAN mEnableLocking = TRUE;\r
\r
\r
/**\r
@param LastVariableOffset Offset of last variable.\r
@param IsVolatile The variable store is volatile or not;\r
if it is non-volatile, need FTW.\r
- @param UpdatingVariable Pointer to updating variable.\r
+ @param UpdatingPtrTrack Pointer to updating variable pointer track structure.\r
@param ReclaimAnyway If TRUE, do reclaim anyway.\r
\r
@return EFI_OUT_OF_RESOURCES\r
IN EFI_PHYSICAL_ADDRESS VariableBase,\r
OUT UINTN *LastVariableOffset,\r
IN BOOLEAN IsVolatile,\r
- IN VARIABLE_HEADER *UpdatingVariable,\r
+ IN OUT VARIABLE_POINTER_TRACK *UpdatingPtrTrack,\r
IN BOOLEAN ReclaimAnyway\r
)\r
{\r
UINTN CommonVariableTotalSize;\r
UINTN HwErrVariableTotalSize;\r
BOOLEAN NeedDoReclaim;\r
+ VARIABLE_HEADER *UpdatingVariable;\r
+\r
+ UpdatingVariable = NULL;\r
+ if (UpdatingPtrTrack != NULL) {\r
+ UpdatingVariable = UpdatingPtrTrack->CurrPtr;\r
+ }\r
\r
NeedDoReclaim = FALSE;\r
VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) VariableBase);\r
if (UpdatingVariable != NULL) {\r
VariableSize = (UINTN)(GetNextVariablePtr (UpdatingVariable)) - (UINTN)UpdatingVariable;\r
CopyMem (CurrPtr, (UINT8 *) UpdatingVariable, VariableSize);\r
+ UpdatingPtrTrack->CurrPtr = (VARIABLE_HEADER *)((UINTN)UpdatingPtrTrack->StartPtr + ((UINTN)CurrPtr - (UINTN)GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer)));\r
+ UpdatingPtrTrack->InDeletedTransitionPtr = NULL;\r
CurrPtr += VariableSize;\r
if ((!IsVolatile) && ((UpdatingVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
HwErrVariableTotalSize += VariableSize;\r
) {\r
Point0 = (VOID *) GetVariableNamePtr (AddedVariable);\r
Point1 = (VOID *) GetVariableNamePtr (Variable);\r
- if (CompareMem (Point0, Point1, NameSizeOfVariable (AddedVariable)) == 0) {\r
+ if (CompareMem (Point0, Point1, NameSize) == 0) {\r
FoundAdded = TRUE;\r
break;\r
}\r
VARIABLE_HEADER *InDeletedVariable;\r
VOID *Point;\r
\r
+ PtrTrack->InDeletedTransitionPtr = NULL;\r
+\r
//\r
// Find the variable by walk through HOB, volatile and non-volatile variable store.\r
//\r
if (PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
InDeletedVariable = PtrTrack->CurrPtr;\r
} else {\r
+ PtrTrack->InDeletedTransitionPtr = InDeletedVariable;\r
return EFI_SUCCESS;\r
}\r
} else {\r
if (PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
InDeletedVariable = PtrTrack->CurrPtr;\r
} else {\r
+ PtrTrack->InDeletedTransitionPtr = InDeletedVariable;\r
return EFI_SUCCESS;\r
}\r
}\r
//\r
// Successfully convert PlatformLang to Lang, and set the BestLang value into Lang variable simultaneously.\r
//\r
- FindVariable (L"Lang", &gEfiGlobalVariableGuid, &Variable, (VARIABLE_GLOBAL *)mVariableModuleGlobal, FALSE);\r
+ FindVariable (L"Lang", &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
\r
Status = UpdateVariable (L"Lang", &gEfiGlobalVariableGuid, BestLang,\r
ISO_639_2_ENTRY_SIZE + 1, Attributes, &Variable);\r
@param[in] Data Variable data.\r
@param[in] DataSize Size of data. 0 means delete.\r
@param[in] Attributes Attribues of the variable.\r
- @param[in] CacheVariable The variable information which is used to keep track of variable usage.\r
+ @param[in, out] CacheVariable The variable information which is used to keep track of variable usage.\r
\r
@retval EFI_SUCCESS The update operation is success.\r
@retval EFI_OUT_OF_RESOURCES Variable region is full, can not write other data into this region.\r
IN VOID *Data,\r
IN UINTN DataSize,\r
IN UINT32 Attributes OPTIONAL,\r
- IN VARIABLE_POINTER_TRACK *CacheVariable\r
+ IN OUT VARIABLE_POINTER_TRACK *CacheVariable\r
)\r
{\r
EFI_STATUS Status;\r
BOOLEAN Volatile;\r
EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;\r
UINT8 State;\r
- BOOLEAN Reclaimed;\r
VARIABLE_POINTER_TRACK *Variable;\r
VARIABLE_POINTER_TRACK NvVariable;\r
VARIABLE_STORE_HEADER *VariableStoreHeader;\r
Variable->StartPtr = GetStartPointer (VariableStoreHeader);\r
Variable->EndPtr = GetEndPointer (VariableStoreHeader);\r
Variable->CurrPtr = (VARIABLE_HEADER *)((UINTN)Variable->StartPtr + ((UINTN)CacheVariable->CurrPtr - (UINTN)CacheVariable->StartPtr));\r
+ if (CacheVariable->InDeletedTransitionPtr != NULL) {\r
+ Variable->InDeletedTransitionPtr = (VARIABLE_HEADER *)((UINTN)Variable->StartPtr + ((UINTN)CacheVariable->InDeletedTransitionPtr - (UINTN)CacheVariable->StartPtr));\r
+ } else {\r
+ Variable->InDeletedTransitionPtr = NULL;\r
+ }\r
Variable->Volatile = FALSE;\r
} \r
\r
Fvb = mVariableModuleGlobal->FvbInstance;\r
- Reclaimed = FALSE;\r
\r
if (Variable->CurrPtr != NULL) {\r
//\r
// causes it to be deleted.\r
//\r
if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) { \r
+ if (Variable->InDeletedTransitionPtr != NULL) {\r
+ //\r
+ // Both ADDED and IN_DELETED_TRANSITION variable are present,\r
+ // set IN_DELETED_TRANSITION one to DELETED state first.\r
+ //\r
+ State = Variable->InDeletedTransitionPtr->State;\r
+ State &= VAR_DELETED;\r
+ Status = UpdateVariableStore (\r
+ &mVariableModuleGlobal->VariableGlobal,\r
+ Variable->Volatile,\r
+ FALSE,\r
+ Fvb,\r
+ (UINTN) &Variable->InDeletedTransitionPtr->State,\r
+ sizeof (UINT8),\r
+ &State\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ if (!Variable->Volatile) {\r
+ ASSERT (CacheVariable->InDeletedTransitionPtr != NULL);\r
+ CacheVariable->InDeletedTransitionPtr->State = State;\r
+ }\r
+ } else {\r
+ goto Done;\r
+ }\r
+ }\r
+\r
State = Variable->CurrPtr->State;\r
State &= VAR_DELETED;\r
\r
// Perform garbage collection & reclaim operation.\r
//\r
Status = Reclaim (mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase, \r
- &mVariableModuleGlobal->NonVolatileLastVariableOffset, FALSE, Variable->CurrPtr, FALSE);\r
+ &mVariableModuleGlobal->NonVolatileLastVariableOffset, FALSE, Variable, FALSE);\r
if (EFI_ERROR (Status)) {\r
goto Done;\r
}\r
Status = EFI_OUT_OF_RESOURCES;\r
goto Done;\r
}\r
- Reclaimed = TRUE;\r
+ if (Variable->CurrPtr != NULL) {\r
+ CacheVariable->CurrPtr = (VARIABLE_HEADER *)((UINTN) CacheVariable->StartPtr + ((UINTN) Variable->CurrPtr - (UINTN) Variable->StartPtr));\r
+ CacheVariable->InDeletedTransitionPtr = NULL;\r
+ }\r
}\r
//\r
// Four steps\r
// Perform garbage collection & reclaim operation.\r
//\r
Status = Reclaim (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase, \r
- &mVariableModuleGlobal->VolatileLastVariableOffset, TRUE, Variable->CurrPtr, FALSE);\r
+ &mVariableModuleGlobal->VolatileLastVariableOffset, TRUE, Variable, FALSE);\r
if (EFI_ERROR (Status)) {\r
goto Done;\r
}\r
Status = EFI_OUT_OF_RESOURCES;\r
goto Done;\r
}\r
- Reclaimed = TRUE;\r
+ if (Variable->CurrPtr != NULL) {\r
+ CacheVariable->CurrPtr = (VARIABLE_HEADER *)((UINTN) CacheVariable->StartPtr + ((UINTN) Variable->CurrPtr - (UINTN) Variable->StartPtr));\r
+ CacheVariable->InDeletedTransitionPtr = NULL;\r
+ }\r
}\r
\r
NextVariable->State = VAR_ADDED;\r
//\r
// Mark the old variable as deleted.\r
//\r
- if (!Reclaimed && !EFI_ERROR (Status) && Variable->CurrPtr != NULL) {\r
+ if (!EFI_ERROR (Status) && Variable->CurrPtr != NULL) {\r
+ if (Variable->InDeletedTransitionPtr != NULL) {\r
+ //\r
+ // Both ADDED and IN_DELETED_TRANSITION old variable are present,\r
+ // set IN_DELETED_TRANSITION one to DELETED state first.\r
+ //\r
+ State = Variable->InDeletedTransitionPtr->State;\r
+ State &= VAR_DELETED;\r
+ Status = UpdateVariableStore (\r
+ &mVariableModuleGlobal->VariableGlobal,\r
+ Variable->Volatile,\r
+ FALSE,\r
+ Fvb,\r
+ (UINTN) &Variable->InDeletedTransitionPtr->State,\r
+ sizeof (UINT8),\r
+ &State\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ if (!Variable->Volatile) {\r
+ ASSERT (CacheVariable->InDeletedTransitionPtr != NULL);\r
+ CacheVariable->InDeletedTransitionPtr->State = State;\r
+ }\r
+ } else {\r
+ goto Done;\r
+ }\r
+ }\r
+\r
State = Variable->CurrPtr->State;\r
State &= VAR_DELETED;\r
\r
return TRUE;\r
}\r
\r
+/**\r
+ Mark a variable that will become read-only after leaving the DXE phase of execution.\r
+\r
+ @param[in] This The VARIABLE_LOCK_PROTOCOL instance.\r
+ @param[in] VariableName A pointer to the variable name that will be made read-only subsequently.\r
+ @param[in] VendorGuid A pointer to the vendor GUID that will be made read-only subsequently.\r
+\r
+ @retval EFI_SUCCESS The variable specified by the VariableName and the VendorGuid was marked\r
+ as pending to be read-only.\r
+ @retval EFI_INVALID_PARAMETER VariableName or VendorGuid is NULL.\r
+ Or VariableName is an empty string.\r
+ @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has\r
+ already been signaled.\r
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource to hold the lock request.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+VariableLockRequestToLock (\r
+ IN CONST EDKII_VARIABLE_LOCK_PROTOCOL *This,\r
+ IN CHAR16 *VariableName,\r
+ IN EFI_GUID *VendorGuid\r
+ )\r
+{\r
+ VARIABLE_ENTRY *Entry;\r
+\r
+ if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (mEndOfDxe) {\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+\r
+ Entry = AllocateRuntimePool (sizeof (*Entry) + StrSize (VariableName));\r
+ if (Entry == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ DEBUG ((EFI_D_INFO, "[Variable] Lock: %g:%s\n", VendorGuid, VariableName));\r
+\r
+ AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
+\r
+ Entry->Name = (CHAR16 *) (Entry + 1);\r
+ StrCpy (Entry->Name, VariableName);\r
+ CopyGuid (&Entry->Guid, VendorGuid);\r
+ InsertTailList (&mLockedVariableList, &Entry->Link);\r
+\r
+ ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
/**\r
\r
This code finds variable in storage blocks (Volatile or Non-Volatile).\r
VARIABLE_STORE_TYPE Type;\r
VARIABLE_POINTER_TRACK Variable;\r
VARIABLE_POINTER_TRACK VariableInHob;\r
+ VARIABLE_POINTER_TRACK VariablePtrTrack;\r
UINTN VarNameSize;\r
EFI_STATUS Status;\r
VARIABLE_STORE_HEADER *VariableStoreHeader[VariableStoreTypeMax];\r
//\r
// Variable is found\r
//\r
- if (Variable.CurrPtr->State == VAR_ADDED) {\r
- if ((AtRuntime () && ((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) == 0) {\r
+ if (Variable.CurrPtr->State == VAR_ADDED || Variable.CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
+ if (!AtRuntime () || ((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) != 0)) {\r
+ if (Variable.CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
+ //\r
+ // If it is a IN_DELETED_TRANSITION variable,\r
+ // and there is also a same ADDED one at the same time,\r
+ // don't return it.\r
+ //\r
+ VariablePtrTrack.StartPtr = Variable.StartPtr;\r
+ VariablePtrTrack.EndPtr = Variable.EndPtr;\r
+ Status = FindVariableEx (\r
+ GetVariableNamePtr (Variable.CurrPtr),\r
+ &Variable.CurrPtr->VendorGuid,\r
+ FALSE,\r
+ &VariablePtrTrack\r
+ );\r
+ if (!EFI_ERROR (Status) && VariablePtrTrack.CurrPtr->State == VAR_ADDED) {\r
+ Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);\r
+ continue;\r
+ }\r
+ }\r
\r
//\r
// Don't return NV variable when HOB overrides it\r
EFI_STATUS Status;\r
VARIABLE_HEADER *NextVariable;\r
EFI_PHYSICAL_ADDRESS Point;\r
+ LIST_ENTRY *Link;\r
+ VARIABLE_ENTRY *Entry;\r
\r
//\r
// Check input parameters.\r
}\r
\r
//\r
- // Not support authenticated variable write yet.\r
+ // Not support authenticated or append variable write yet.\r
//\r
- if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
+ if ((Attributes & (EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS | EFI_VARIABLE_APPEND_WRITE)) != 0) {\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
+ if ((UINTN)(~0) - DataSize < StrSize(VariableName)){\r
+ //\r
+ // Prevent whole variable size overflow \r
+ // \r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
//\r
// The size of the VariableName, including the Unicode Null in bytes plus\r
// the DataSize is limited to maximum size of PcdGet32 (PcdMaxHardwareErrorVariableSize)\r
// bytes for HwErrRec, and PcdGet32 (PcdMaxVariableSize) bytes for the others.\r
//\r
if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
- if ((DataSize > PcdGet32 (PcdMaxHardwareErrorVariableSize)) ||\r
- (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > PcdGet32 (PcdMaxHardwareErrorVariableSize))) {\r
+ if ( StrSize (VariableName) + DataSize > PcdGet32 (PcdMaxHardwareErrorVariableSize) - sizeof (VARIABLE_HEADER)) {\r
return EFI_INVALID_PARAMETER;\r
}\r
if (!IsHwErrRecVariable(VariableName, VendorGuid)) {\r
// The size of the VariableName, including the Unicode Null in bytes plus\r
// the DataSize is limited to maximum size of PcdGet32 (PcdMaxVariableSize) bytes.\r
//\r
- if ((DataSize > PcdGet32 (PcdMaxVariableSize)) ||\r
- (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > PcdGet32 (PcdMaxVariableSize))) {\r
+ if (StrSize (VariableName) + DataSize > PcdGet32 (PcdMaxVariableSize) - sizeof (VARIABLE_HEADER)) {\r
return EFI_INVALID_PARAMETER;\r
} \r
}\r
\r
- if (AtRuntime ()) {\r
- //\r
- // HwErrRecSupport Global Variable identifies the level of hardware error record persistence\r
- // support implemented by the platform. This variable is only modified by firmware and is read-only to the OS.\r
- //\r
- if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, L"HwErrRecSupport") == 0)) {\r
- return EFI_WRITE_PROTECTED;\r
- }\r
- }\r
-\r
AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
\r
//\r
mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) Point;\r
}\r
\r
+ if (mEndOfDxe && mEnableLocking) {\r
+ //\r
+ // Treat the variables listed in the forbidden variable list as read-only after leaving DXE phase.\r
+ //\r
+ for ( Link = GetFirstNode (&mLockedVariableList)\r
+ ; !IsNull (&mLockedVariableList, Link)\r
+ ; Link = GetNextNode (&mLockedVariableList, Link)\r
+ ) {\r
+ Entry = BASE_CR (Link, VARIABLE_ENTRY, Link);\r
+ if (CompareGuid (&Entry->Guid, VendorGuid) && (StrCmp (Entry->Name, VariableName) == 0)) {\r
+ Status = EFI_WRITE_PROTECTED;\r
+ DEBUG ((EFI_D_INFO, "[Variable]: Changing readonly variable after leaving DXE phase - %g:%s\n", VendorGuid, VariableName));\r
+ goto Done;\r
+ }\r
+ }\r
+ }\r
+\r
//\r
// Check whether the input variable is already existed.\r
//\r
Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, TRUE);\r
if (!EFI_ERROR (Status)) {\r
if (((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) && AtRuntime ()) {\r
- return EFI_WRITE_PROTECTED;\r
+ Status = EFI_WRITE_PROTECTED;\r
+ goto Done;\r
+ }\r
+ if (Attributes != 0 && Attributes != Variable.CurrPtr->Attributes) {\r
+ //\r
+ // If a preexisting variable is rewritten with different attributes, SetVariable() shall not\r
+ // modify the variable and shall return EFI_INVALID_PARAMETER. Two exceptions to this rule:\r
+ // 1. No access attributes specified\r
+ // 2. The only attribute differing is EFI_VARIABLE_APPEND_WRITE\r
+ //\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto Done;\r
}\r
}\r
\r
\r
Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, &Variable);\r
\r
+Done:\r
InterlockedDecrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState);\r
ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
\r
}\r
}\r
\r
+/**\r
+ Init non-volatile variable store.\r
+\r
+ @retval EFI_SUCCESS Function successfully executed.\r
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.\r
+ @retval EFI_VOLUME_CORRUPTED Variable Store or Firmware Volume for Variable Store is corrupted.\r
+\r
+**/\r
+EFI_STATUS\r
+InitNonVolatileVariableStore (\r
+ VOID\r
+ )\r
+{\r
+ EFI_FIRMWARE_VOLUME_HEADER *FvHeader;\r
+ VARIABLE_HEADER *NextVariable;\r
+ EFI_PHYSICAL_ADDRESS VariableStoreBase;\r
+ UINT64 VariableStoreLength;\r
+ UINTN VariableSize;\r
+ EFI_HOB_GUID_TYPE *GuidHob;\r
+ EFI_PHYSICAL_ADDRESS NvStorageBase;\r
+ UINT8 *NvStorageData;\r
+ UINT32 NvStorageSize;\r
+ FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *FtwLastWriteData;\r
+ UINT32 BackUpOffset;\r
+ UINT32 BackUpSize;\r
+\r
+ mVariableModuleGlobal->FvbInstance = NULL;\r
+\r
+ //\r
+ // Note that in EdkII variable driver implementation, Hardware Error Record type variable\r
+ // is stored with common variable in the same NV region. So the platform integrator should\r
+ // ensure that the value of PcdHwErrStorageSize is less than or equal to the value of\r
+ // PcdFlashNvStorageVariableSize.\r
+ //\r
+ ASSERT (PcdGet32 (PcdHwErrStorageSize) <= PcdGet32 (PcdFlashNvStorageVariableSize));\r
+\r
+ //\r
+ // Allocate runtime memory used for a memory copy of the FLASH region.\r
+ // Keep the memory and the FLASH in sync as updates occur.\r
+ //\r
+ NvStorageSize = PcdGet32 (PcdFlashNvStorageVariableSize);\r
+ NvStorageData = AllocateRuntimeZeroPool (NvStorageSize);\r
+ if (NvStorageData == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ NvStorageBase = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageVariableBase64);\r
+ if (NvStorageBase == 0) {\r
+ NvStorageBase = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);\r
+ }\r
+ //\r
+ // Copy NV storage data to the memory buffer.\r
+ //\r
+ CopyMem (NvStorageData, (UINT8 *) (UINTN) NvStorageBase, NvStorageSize);\r
+\r
+ //\r
+ // Check the FTW last write data hob.\r
+ //\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
+ DEBUG ((EFI_D_INFO, "Variable: NV storage is backed up in spare block: 0x%x\n", (UINTN) FtwLastWriteData->SpareAddress));\r
+ //\r
+ // Copy the backed up NV storage data to the memory buffer from spare block.\r
+ //\r
+ CopyMem (NvStorageData, (UINT8 *) (UINTN) (FtwLastWriteData->SpareAddress), NvStorageSize);\r
+ } else if ((FtwLastWriteData->TargetAddress > NvStorageBase) &&\r
+ (FtwLastWriteData->TargetAddress < (NvStorageBase + NvStorageSize))) {\r
+ //\r
+ // Flash NV storage from the offset is backed up in spare block.\r
+ //\r
+ BackUpOffset = (UINT32) (FtwLastWriteData->TargetAddress - NvStorageBase);\r
+ BackUpSize = NvStorageSize - BackUpOffset;\r
+ 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));\r
+ //\r
+ // Copy the partial backed up NV storage data to the memory buffer from spare block.\r
+ //\r
+ CopyMem (NvStorageData + BackUpOffset, (UINT8 *) (UINTN) FtwLastWriteData->SpareAddress, BackUpSize);\r
+ }\r
+ }\r
+\r
+ FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) NvStorageData;\r
+\r
+ //\r
+ // Check if the Firmware Volume is not corrupted\r
+ //\r
+ if ((FvHeader->Signature != EFI_FVH_SIGNATURE) || (!CompareGuid (&gEfiSystemNvDataFvGuid, &FvHeader->FileSystemGuid))) {\r
+ FreePool (NvStorageData);\r
+ DEBUG ((EFI_D_ERROR, "Firmware Volume for Variable Store is corrupted\n"));\r
+ return EFI_VOLUME_CORRUPTED;\r
+ }\r
+\r
+ VariableStoreBase = (EFI_PHYSICAL_ADDRESS) ((UINTN) FvHeader + FvHeader->HeaderLength);\r
+ VariableStoreLength = (UINT64) (NvStorageSize - FvHeader->HeaderLength);\r
+\r
+ mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;\r
+ mNvVariableCache = (VARIABLE_STORE_HEADER *) (UINTN) VariableStoreBase;\r
+ if (GetVariableStoreStatus (mNvVariableCache) != EfiValid) {\r
+ FreePool (NvStorageData);\r
+ DEBUG((EFI_D_ERROR, "Variable Store header is corrupted\n"));\r
+ return EFI_VOLUME_CORRUPTED;\r
+ }\r
+ ASSERT(mNvVariableCache->Size == VariableStoreLength);\r
+\r
+ //\r
+ // The max variable or hardware error variable size should be < variable store size.\r
+ //\r
+ ASSERT(MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize)) < VariableStoreLength);\r
+\r
+ //\r
+ // Parse non-volatile variable data and get last variable offset.\r
+ //\r
+ NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase);\r
+ while (IsValidVariableHeader (NextVariable)) {\r
+ VariableSize = NextVariable->NameSize + NextVariable->DataSize + sizeof (VARIABLE_HEADER);\r
+ if ((NextVariable->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+ mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VariableSize);\r
+ } else {\r
+ mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VariableSize);\r
+ }\r
+\r
+ NextVariable = GetNextVariablePtr (NextVariable);\r
+ }\r
+ mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) VariableStoreBase;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
/**\r
Flush the HOB variable to flash.\r
\r
}\r
\r
/**\r
- Initializes variable write service after FVB was ready.\r
+ Initializes variable write service after FTW was ready.\r
\r
@retval EFI_SUCCESS Function successfully executed.\r
@retval Others Fail to initialize the variable service.\r
UINTN Index;\r
UINT8 Data;\r
EFI_PHYSICAL_ADDRESS VariableStoreBase;\r
+ EFI_PHYSICAL_ADDRESS NvStorageBase;\r
+\r
+ NvStorageBase = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageVariableBase64);\r
+ if (NvStorageBase == 0) {\r
+ NvStorageBase = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);\r
+ }\r
+ VariableStoreBase = NvStorageBase + (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(NvStorageBase))->HeaderLength);\r
\r
- VariableStoreBase = mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;\r
+ //\r
+ // Let NonVolatileVariableBase point to flash variable store base directly after FTW ready.\r
+ //\r
+ mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;\r
VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase;\r
\r
//\r
EFI_STATUS Status;\r
VARIABLE_STORE_HEADER *VolatileVariableStore;\r
VARIABLE_STORE_HEADER *VariableStoreHeader;\r
- VARIABLE_HEADER *NextVariable;\r
- EFI_PHYSICAL_ADDRESS TempVariableStoreHeader;\r
- EFI_PHYSICAL_ADDRESS VariableStoreBase;\r
UINT64 VariableStoreLength;\r
UINTN ScratchSize;\r
- UINTN VariableSize;\r
EFI_HOB_GUID_TYPE *GuidHob;\r
\r
//\r
\r
InitializeLock (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock, TPL_NOTIFY);\r
\r
- //\r
- // Note that in EdkII variable driver implementation, Hardware Error Record type variable\r
- // is stored with common variable in the same NV region. So the platform integrator should\r
- // ensure that the value of PcdHwErrStorageSize is less than or equal to the value of \r
- // PcdFlashNvStorageVariableSize.\r
- //\r
- ASSERT (PcdGet32 (PcdHwErrStorageSize) <= PcdGet32 (PcdFlashNvStorageVariableSize));\r
-\r
//\r
// Get HOB variable store.\r
//\r
if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) {\r
mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) AllocateRuntimeCopyPool ((UINTN) VariableStoreLength, (VOID *) VariableStoreHeader);\r
if (mVariableModuleGlobal->VariableGlobal.HobVariableBase == 0) {\r
+ FreePool (mVariableModuleGlobal);\r
return EFI_OUT_OF_RESOURCES;\r
}\r
} else {\r
ScratchSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize));\r
VolatileVariableStore = AllocateRuntimePool (PcdGet32 (PcdVariableStoreSize) + ScratchSize);\r
if (VolatileVariableStore == NULL) {\r
+ if (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) {\r
+ FreePool ((VOID *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase);\r
+ }\r
FreePool (mVariableModuleGlobal);\r
return EFI_OUT_OF_RESOURCES;\r
}\r
//\r
mVariableModuleGlobal->VariableGlobal.VolatileVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VolatileVariableStore;\r
mVariableModuleGlobal->VolatileLastVariableOffset = (UINTN) GetStartPointer (VolatileVariableStore) - (UINTN) VolatileVariableStore;\r
- mVariableModuleGlobal->FvbInstance = NULL;\r
\r
CopyGuid (&VolatileVariableStore->Signature, &gEfiVariableGuid);\r
VolatileVariableStore->Size = PcdGet32 (PcdVariableStoreSize);\r
VolatileVariableStore->Reserved1 = 0;\r
\r
//\r
- // Get non-volatile variable store.\r
- //\r
-\r
- TempVariableStoreHeader = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageVariableBase64);\r
- if (TempVariableStoreHeader == 0) {\r
- TempVariableStoreHeader = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);\r
- }\r
-\r
- //\r
- // Check if the Firmware Volume is not corrupted\r
- //\r
- if ((((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader))->Signature != EFI_FVH_SIGNATURE) ||\r
- (!CompareGuid (&gEfiSystemNvDataFvGuid, &((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader))->FileSystemGuid))) {\r
- Status = EFI_VOLUME_CORRUPTED;\r
- DEBUG ((EFI_D_ERROR, "Firmware Volume for Variable Store is corrupted\n"));\r
- goto Done;\r
- }\r
-\r
- VariableStoreBase = TempVariableStoreHeader + \\r
- (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader)) -> HeaderLength);\r
- VariableStoreLength = (UINT64) PcdGet32 (PcdFlashNvStorageVariableSize) - \\r
- (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader)) -> HeaderLength);\r
-\r
- mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;\r
- VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase;\r
- if (GetVariableStoreStatus (VariableStoreHeader) != EfiValid) {\r
- Status = EFI_VOLUME_CORRUPTED;\r
- DEBUG((EFI_D_INFO, "Variable Store header is corrupted\n"));\r
- goto Done;\r
- } \r
- ASSERT(VariableStoreHeader->Size == VariableStoreLength);\r
- \r
- //\r
- // Parse non-volatile variable data and get last variable offset.\r
+ // Init non-volatile variable store.\r
//\r
- NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase);\r
- while (IsValidVariableHeader (NextVariable)) {\r
- VariableSize = NextVariable->NameSize + NextVariable->DataSize + sizeof (VARIABLE_HEADER);\r
- if ((NextVariable->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
- mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VariableSize);\r
- } else {\r
- mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VariableSize);\r
- }\r
-\r
- NextVariable = GetNextVariablePtr (NextVariable);\r
- }\r
-\r
- mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) VariableStoreBase;\r
- \r
- //\r
- // Allocate runtime memory used for a memory copy of the FLASH region.\r
- // Keep the memory and the FLASH in sync as updates occur\r
- //\r
- mNvVariableCache = AllocateRuntimeZeroPool ((UINTN)VariableStoreLength);\r
- if (mNvVariableCache == NULL) {\r
- Status = EFI_OUT_OF_RESOURCES;\r
- goto Done;\r
- }\r
- CopyMem (mNvVariableCache, (CHAR8 *)(UINTN)VariableStoreBase, (UINTN)VariableStoreLength);\r
- Status = EFI_SUCCESS;\r
-\r
-Done:\r
+ Status = InitNonVolatileVariableStore ();\r
if (EFI_ERROR (Status)) {\r
+ if (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) {\r
+ FreePool ((VOID *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase);\r
+ }\r
FreePool (mVariableModuleGlobal);\r
FreePool (VolatileVariableStore);\r
}\r