VariableServiceSetVariable() should also check authenticate data to avoid buffer overflow,\r
integer overflow. It should also check attribute to avoid authentication bypass.\r
\r
-Copyright (c) 2006 - 2015, 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
-http://opensource.org/licenses/bsd-license.php\r
-\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>\r
+(C) Copyright 2015-2018 Hewlett Packard Enterprise Development LP<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\r
\r
///\r
/// Define a memory cache that improves the search performance for a variable.\r
+/// For EmuNvMode == TRUE, it will be equal to NonVolatileVariableBase.\r
///\r
VARIABLE_STORE_HEADER *mNvVariableCache = NULL;\r
\r
///\r
-/// The memory entry used for variable statistics data.\r
+/// Memory cache of Fv Header.\r
///\r
-VARIABLE_INFO_ENTRY *gVariableInfo = NULL;\r
+EFI_FIRMWARE_VOLUME_HEADER *mNvFvHeaderCache = 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
+/// The memory entry used for variable statistics data.\r
///\r
-LIST_ENTRY mLockedVariableList = INITIALIZE_LIST_HEAD_VARIABLE (mLockedVariableList);\r
+VARIABLE_INFO_ENTRY *gVariableInfo = NULL;\r
\r
///\r
/// The flag to indicate whether the platform has left the DXE phase of execution.\r
BOOLEAN mEndOfDxe = FALSE;\r
\r
///\r
-/// The flag to indicate whether the variable storage locking is enabled.\r
+/// It indicates the var check request source.\r
+/// In the implementation, DXE is regarded as untrusted, and SMM is trusted.\r
///\r
-BOOLEAN mEnableLocking = TRUE;\r
+VAR_CHECK_REQUEST_SOURCE mRequestSource = VarCheckFromUntrusted;\r
\r
//\r
// It will record the current boot error flag before EndOfDxe.\r
},\r
};\r
\r
-AUTH_VAR_LIB_CONTEXT_IN mContextIn = {\r
+AUTH_VAR_LIB_CONTEXT_IN mAuthContextIn = {\r
AUTH_VAR_LIB_CONTEXT_IN_STRUCT_VERSION,\r
- sizeof (AUTH_VAR_LIB_CONTEXT_IN),\r
+ //\r
+ // StructSize, TO BE FILLED\r
+ //\r
+ 0,\r
//\r
// MaxAuthVariableSize, TO BE FILLED\r
//\r
VariableExLibAtRuntime,\r
};\r
\r
-AUTH_VAR_LIB_CONTEXT_OUT mContextOut;\r
-\r
-/**\r
-\r
- SecureBoot Hook for auth variable update.\r
-\r
- @param[in] VariableName Name of Variable to be found.\r
- @param[in] VendorGuid Variable vendor GUID.\r
-**/\r
-VOID\r
-EFIAPI\r
-SecureBootHook (\r
- IN CHAR16 *VariableName,\r
- IN EFI_GUID *VendorGuid\r
- );\r
+AUTH_VAR_LIB_CONTEXT_OUT mAuthContextOut;\r
\r
/**\r
Routine used to track statistical information about variable usage.\r
@param Buffer Pointer to the buffer from which data is written.\r
\r
@retval EFI_INVALID_PARAMETER Parameters not valid.\r
+ @retval EFI_UNSUPPORTED Fvb is a NULL for Non-Volatile variable update.\r
+ @retval EFI_OUT_OF_RESOURCES The remaining size is not enough.\r
@retval EFI_SUCCESS Variable store successfully updated.\r
\r
**/\r
UINT8 *CurrBuffer;\r
EFI_LBA LbaNumber;\r
UINTN Size;\r
- EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
VARIABLE_STORE_HEADER *VolatileBase;\r
EFI_PHYSICAL_ADDRESS FvVolHdr;\r
EFI_PHYSICAL_ADDRESS DataPtr;\r
EFI_STATUS Status;\r
\r
- FwVolHeader = NULL;\r
+ FvVolHdr = 0;\r
DataPtr = DataPtrIndex;\r
\r
//\r
// Check if the Data is Volatile.\r
//\r
- if (!Volatile) {\r
+ if (!Volatile && !mVariableModuleGlobal->VariableGlobal.EmuNvMode) {\r
if (Fvb == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
+ return EFI_UNSUPPORTED;\r
}\r
Status = Fvb->GetPhysicalAddress(Fvb, &FvVolHdr);\r
ASSERT_EFI_ERROR (Status);\r
\r
- FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvVolHdr);\r
//\r
// Data Pointer should point to the actual Address where data is to be\r
// written.\r
DataPtr += mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;\r
}\r
\r
- if ((DataPtr + DataSize) >= ((EFI_PHYSICAL_ADDRESS) (UINTN) ((UINT8 *) FwVolHeader + FwVolHeader->FvLength))) {\r
- return EFI_INVALID_PARAMETER;\r
+ if ((DataPtr + DataSize) > (FvVolHdr + mNvFvHeaderCache->FvLength)) {\r
+ return EFI_OUT_OF_RESOURCES;\r
}\r
} else {\r
//\r
// Data Pointer should point to the actual Address where data is to be\r
// written.\r
//\r
- VolatileBase = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);\r
- if (SetByIndex) {\r
- DataPtr += mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;\r
- }\r
+ if (Volatile) {\r
+ VolatileBase = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);\r
+ if (SetByIndex) {\r
+ DataPtr += mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;\r
+ }\r
\r
- if ((DataPtr + DataSize) >= ((UINTN) ((UINT8 *) VolatileBase + VolatileBase->Size))) {\r
- return EFI_INVALID_PARAMETER;\r
+ if ((DataPtr + DataSize) > ((UINTN) VolatileBase + VolatileBase->Size)) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ } else {\r
+ //\r
+ // Emulated non-volatile variable mode.\r
+ //\r
+ if (SetByIndex) {\r
+ DataPtr += (UINTN) mNvVariableCache;\r
+ }\r
+\r
+ if ((DataPtr + DataSize) > ((UINTN) mNvVariableCache + mNvVariableCache->Size)) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
}\r
\r
//\r
- // If Volatile Variable just do a simple mem copy.\r
+ // If Volatile/Emulated Non-volatile Variable just do a simple mem copy.\r
//\r
CopyMem ((UINT8 *)(UINTN)DataPtr, Buffer, DataSize);\r
return EFI_SUCCESS;\r
//\r
// If we are here we are dealing with Non-Volatile Variables.\r
//\r
- LinearOffset = (UINTN) FwVolHeader;\r
+ LinearOffset = (UINTN) FvVolHdr;\r
CurrWritePtr = (UINTN) DataPtr;\r
CurrWriteSize = DataSize;\r
CurrBuffer = Buffer;\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
- for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {\r
+ for (PtrBlockMapEntry = mNvFvHeaderCache->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {\r
for (BlockIndex2 = 0; BlockIndex2 < PtrBlockMapEntry->NumBlocks; BlockIndex2++) {\r
//\r
// Check to see if the Variable Writes are spanning through multiple\r
)\r
{\r
//\r
- // The end of variable store.\r
+ // The start of variable store.\r
//\r
return (VARIABLE_HEADER *) HEADER_ALIGN (VarStoreHeader + 1);\r
}\r
//\r
// Update the data in NV cache.\r
//\r
- *VarErrFlag = Flag;\r
+ *VarErrFlag = TempFlag;\r
}\r
}\r
}\r
// then no need to check if the variable is user variable or not specially.\r
//\r
if (mEndOfDxe && (mVariableModuleGlobal->CommonMaxUserVariableSpace != mVariableModuleGlobal->CommonVariableSpace)) {\r
- if (InternalVarCheckVariablePropertyGet (GetVariableNamePtr (Variable), GetVendorGuidPtr (Variable), &Property) == EFI_NOT_FOUND) {\r
+ if (VarCheckLibVariablePropertyGet (GetVariableNamePtr (Variable), GetVendorGuidPtr (Variable), &Property) == EFI_NOT_FOUND) {\r
return TRUE;\r
}\r
}\r
NextVariable = GetNextVariablePtr (Variable);\r
VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
- if (InternalVarCheckVariablePropertyGet (GetVariableNamePtr (Variable), GetVendorGuidPtr (Variable), &Property) == EFI_NOT_FOUND) {\r
+ if (VarCheckLibVariablePropertyGet (GetVariableNamePtr (Variable), GetVendorGuidPtr (Variable), &Property) == EFI_NOT_FOUND) {\r
//\r
// No property, it is user variable.\r
//\r
VOID\r
)\r
{\r
- STATIC BOOLEAN Initialized;\r
-\r
- if (!mEndOfDxe || Initialized) {\r
+ if (!mEndOfDxe) {\r
return;\r
}\r
- Initialized = TRUE;\r
\r
InitializeVarErrorFlag ();\r
CalculateCommonUserVariableTotalSize ();\r
CommonUserVariableTotalSize = 0;\r
HwErrVariableTotalSize = 0;\r
\r
- if (IsVolatile) {\r
+ if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) {\r
//\r
// Start Pointers for the variable.\r
//\r
// Install the new variable if it is not NULL.\r
//\r
if (NewVariable != NULL) {\r
- if ((UINTN) (CurrPtr - ValidBuffer) + NewVariableSize > VariableStoreHeader->Size) {\r
+ if (((UINTN) CurrPtr - (UINTN) ValidBuffer) + NewVariableSize > VariableStoreHeader->Size) {\r
//\r
// No enough space to store the new variable.\r
//\r
CurrPtr += NewVariableSize;\r
}\r
\r
- if (IsVolatile) {\r
+ if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) {\r
//\r
- // If volatile variable store, just copy valid buffer.\r
+ // If volatile/emulated non-volatile variable store, just copy valid buffer.\r
//\r
SetMem ((UINT8 *) (UINTN) VariableBase, VariableStoreHeader->Size, 0xff);\r
- CopyMem ((UINT8 *) (UINTN) VariableBase, ValidBuffer, (UINTN) (CurrPtr - ValidBuffer));\r
- *LastVariableOffset = (UINTN) (CurrPtr - ValidBuffer);\r
+ CopyMem ((UINT8 *) (UINTN) VariableBase, ValidBuffer, (UINTN) CurrPtr - (UINTN) ValidBuffer);\r
+ *LastVariableOffset = (UINTN) CurrPtr - (UINTN) ValidBuffer;\r
+ if (!IsVolatile) {\r
+ //\r
+ // Emulated non-volatile variable mode.\r
+ //\r
+ mVariableModuleGlobal->HwErrVariableTotalSize = HwErrVariableTotalSize;\r
+ mVariableModuleGlobal->CommonVariableTotalSize = CommonVariableTotalSize;\r
+ mVariableModuleGlobal->CommonUserVariableTotalSize = CommonUserVariableTotalSize;\r
+ }\r
Status = EFI_SUCCESS;\r
} else {\r
//\r
(VARIABLE_STORE_HEADER *) ValidBuffer\r
);\r
if (!EFI_ERROR (Status)) {\r
- *LastVariableOffset = (UINTN) (CurrPtr - ValidBuffer);\r
+ *LastVariableOffset = (UINTN) CurrPtr - (UINTN) ValidBuffer;\r
mVariableModuleGlobal->HwErrVariableTotalSize = HwErrVariableTotalSize;\r
mVariableModuleGlobal->CommonVariableTotalSize = CommonVariableTotalSize;\r
mVariableModuleGlobal->CommonUserVariableTotalSize = CommonUserVariableTotalSize;\r
} else {\r
+ mVariableModuleGlobal->HwErrVariableTotalSize = 0;\r
+ mVariableModuleGlobal->CommonVariableTotalSize = 0;\r
+ mVariableModuleGlobal->CommonUserVariableTotalSize = 0;\r
Variable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableBase);\r
while (IsValidVariableHeader (Variable, GetEndPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableBase))) {\r
NextVariable = GetNextVariablePtr (Variable);\r
}\r
\r
Done:\r
- if (IsVolatile) {\r
+ if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) {\r
FreePool (ValidBuffer);\r
} else {\r
//\r
@param[in] SupportedLanguages A pointer to a Null-terminated ASCII string that\r
contains a set of language codes in the format\r
specified by Iso639Language.\r
- @param[in] Iso639Language If TRUE, then all language codes are assumed to be\r
- in ISO 639-2 format. If FALSE, then all language\r
+ @param[in] Iso639Language If not zero, then all language codes are assumed to be\r
+ in ISO 639-2 format. If zero, then all language\r
codes are assumed to be in RFC 4646 language format\r
@param[in] ... A variable argument list that contains pointers to\r
Null-terminated ASCII strings that contain one or more\r
EFIAPI\r
VariableGetBestLanguage (\r
IN CONST CHAR8 *SupportedLanguages,\r
- IN BOOLEAN Iso639Language,\r
+ IN UINTN Iso639Language,\r
...\r
)\r
{\r
//\r
// If in RFC 4646 mode, then determine the length of the first RFC 4646 language code in Language\r
//\r
- if (!Iso639Language) {\r
+ if (Iso639Language == 0) {\r
for (LanguageLength = 0; Language[LanguageLength] != 0 && Language[LanguageLength] != ';'; LanguageLength++);\r
}\r
\r
//\r
// In RFC 4646 mode, then Loop through all language codes in SupportedLanguages\r
//\r
- if (!Iso639Language) {\r
+ if (Iso639Language == 0) {\r
//\r
// Skip ';' characters in Supported\r
//\r
if (AsciiStrnCmp (Supported, Language, LanguageLength) == 0) {\r
VA_END (Args);\r
\r
- Buffer = Iso639Language ? mVariableModuleGlobal->Lang : mVariableModuleGlobal->PlatformLang;\r
+ Buffer = (Iso639Language != 0) ? mVariableModuleGlobal->Lang : mVariableModuleGlobal->PlatformLang;\r
Buffer[CompareLength] = '\0';\r
return CopyMem (Buffer, Supported, CompareLength);\r
}\r
}\r
\r
- if (Iso639Language) {\r
+ if (Iso639Language != 0) {\r
//\r
// If ISO 639 mode, then each language can only be tested once\r
//\r
ASSERT_EFI_ERROR (Status);\r
\r
TotalNeededSize = 0;\r
- Args = Marker;\r
+ VA_COPY (Args, Marker);\r
VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *);\r
while (VariableEntry != NULL) {\r
//\r
TotalNeededSize += VariableEntry->VariableSize;\r
VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *);\r
}\r
+ VA_END (Args);\r
\r
if (RemainingVariableStorageSize >= TotalNeededSize) {\r
//\r
return FALSE;\r
}\r
\r
- Args = Marker;\r
+ VA_COPY (Args, Marker);\r
VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *);\r
while (VariableEntry != NULL) {\r
//\r
//\r
// No enough space for Variable[Index].\r
//\r
+ VA_END (Args);\r
return FALSE;\r
}\r
//\r
RemainingVariableStorageSize -= VariableEntry->VariableSize;\r
VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *);\r
}\r
+ VA_END (Args);\r
\r
return TRUE;\r
}\r
VARIABLE_POINTER_TRACK *Variable;\r
VARIABLE_POINTER_TRACK NvVariable;\r
VARIABLE_STORE_HEADER *VariableStoreHeader;\r
- UINTN CacheOffset;\r
UINT8 *BufferForMerge;\r
UINTN MergedBufSize;\r
BOOLEAN DataReady;\r
BOOLEAN IsCommonUserVariable;\r
AUTHENTICATED_VARIABLE_HEADER *AuthVariable;\r
\r
- if (mVariableModuleGlobal->FvbInstance == NULL) {\r
+ if (mVariableModuleGlobal->FvbInstance == NULL && !mVariableModuleGlobal->VariableGlobal.EmuNvMode) {\r
//\r
// The FVB protocol is not ready, so the EFI_VARIABLE_WRITE_ARCH_PROTOCOL is not installed.\r
//\r
}\r
}\r
\r
+ //\r
+ // Check if CacheVariable points to the variable in variable HOB.\r
+ // If yes, let CacheVariable points to the variable in NV variable cache.\r
+ //\r
+ if ((CacheVariable->CurrPtr != NULL) &&\r
+ (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) &&\r
+ (CacheVariable->StartPtr == GetStartPointer ((VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase))\r
+ ) {\r
+ CacheVariable->StartPtr = GetStartPointer (mNvVariableCache);\r
+ CacheVariable->EndPtr = GetEndPointer (mNvVariableCache);\r
+ CacheVariable->Volatile = FALSE;\r
+ Status = FindVariableEx (VariableName, VendorGuid, FALSE, CacheVariable);\r
+ if (CacheVariable->CurrPtr == NULL || EFI_ERROR (Status)) {\r
+ //\r
+ // There is no matched variable in NV variable cache.\r
+ //\r
+ if ((((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (DataSize == 0)) || (Attributes == 0)) {\r
+ //\r
+ // It is to delete variable,\r
+ // go to delete this variable in variable HOB and\r
+ // try to flush other variables from HOB to flash.\r
+ //\r
+ UpdateVariableInfo (VariableName, VendorGuid, FALSE, FALSE, FALSE, TRUE, FALSE);\r
+ FlushHobVariableToFlash (VariableName, VendorGuid);\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+ }\r
+\r
if ((CacheVariable->CurrPtr == NULL) || CacheVariable->Volatile) {\r
Variable = CacheVariable;\r
} else {\r
VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);\r
Variable = &NvVariable;\r
Variable->StartPtr = GetStartPointer (VariableStoreHeader);\r
- Variable->EndPtr = GetEndPointer (VariableStoreHeader);\r
+ Variable->EndPtr = (VARIABLE_HEADER *)((UINTN)Variable->StartPtr + ((UINTN)CacheVariable->EndPtr - (UINTN)CacheVariable->StartPtr));\r
+\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
//\r
// Only variable that have NV attributes can be updated/deleted in Runtime.\r
//\r
- if ((Variable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
+ if ((CacheVariable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
Status = EFI_INVALID_PARAMETER;\r
goto Done;\r
}\r
//\r
// Only variable that have RT attributes can be updated/deleted in Runtime.\r
//\r
- if ((Variable->CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) {\r
+ if ((CacheVariable->CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) {\r
Status = EFI_INVALID_PARAMETER;\r
goto Done;\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
+ ASSERT (CacheVariable->InDeletedTransitionPtr != NULL);\r
+ State = CacheVariable->InDeletedTransitionPtr->State;\r
State &= VAR_DELETED;\r
Status = UpdateVariableStore (\r
&mVariableModuleGlobal->VariableGlobal,\r
);\r
if (!EFI_ERROR (Status)) {\r
if (!Variable->Volatile) {\r
- ASSERT (CacheVariable->InDeletedTransitionPtr != NULL);\r
CacheVariable->InDeletedTransitionPtr->State = State;\r
}\r
} else {\r
}\r
}\r
\r
- State = Variable->CurrPtr->State;\r
+ State = CacheVariable->CurrPtr->State;\r
State &= VAR_DELETED;\r
\r
Status = UpdateVariableStore (\r
// If the variable is marked valid, and the same data has been passed in,\r
// then return to the caller immediately.\r
//\r
- if (DataSizeOfVariable (Variable->CurrPtr) == DataSize &&\r
- (CompareMem (Data, GetVariableDataPtr (Variable->CurrPtr), DataSize) == 0) &&\r
+ if (DataSizeOfVariable (CacheVariable->CurrPtr) == DataSize &&\r
+ (CompareMem (Data, GetVariableDataPtr (CacheVariable->CurrPtr), DataSize) == 0) &&\r
((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) &&\r
(TimeStamp == NULL)) {\r
//\r
UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE, TRUE, FALSE, FALSE);\r
Status = EFI_SUCCESS;\r
goto Done;\r
- } else if ((Variable->CurrPtr->State == VAR_ADDED) ||\r
- (Variable->CurrPtr->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))) {\r
+ } else if ((CacheVariable->CurrPtr->State == VAR_ADDED) ||\r
+ (CacheVariable->CurrPtr->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))) {\r
\r
//\r
// EFI_VARIABLE_APPEND_WRITE attribute only effects for existing variable.\r
// NOTE: From 0 to DataOffset of NextVariable is reserved for Variable Header and Name.\r
// From DataOffset of NextVariable is to save the existing variable data.\r
//\r
- DataOffset = GetVariableDataOffset (Variable->CurrPtr);\r
+ DataOffset = GetVariableDataOffset (CacheVariable->CurrPtr);\r
BufferForMerge = (UINT8 *) ((UINTN) NextVariable + DataOffset);\r
- CopyMem (BufferForMerge, (UINT8 *) ((UINTN) Variable->CurrPtr + DataOffset), DataSizeOfVariable (Variable->CurrPtr));\r
+ CopyMem (BufferForMerge, (UINT8 *) ((UINTN) CacheVariable->CurrPtr + DataOffset), DataSizeOfVariable (CacheVariable->CurrPtr));\r
\r
//\r
- // Set Max Common/Auth Variable Data Size as default MaxDataSize.\r
+ // Set Max Auth/Non-Volatile/Volatile Variable Data Size as default MaxDataSize.\r
//\r
if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {\r
MaxDataSize = mVariableModuleGlobal->MaxAuthVariableSize - DataOffset;\r
- } else {\r
+ } else if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {\r
MaxDataSize = mVariableModuleGlobal->MaxVariableSize - DataOffset;\r
+ } else {\r
+ MaxDataSize = mVariableModuleGlobal->MaxVolatileVariableSize - DataOffset;\r
}\r
\r
//\r
MaxDataSize = PcdGet32 (PcdMaxHardwareErrorVariableSize) - DataOffset;\r
}\r
\r
- if (DataSizeOfVariable (Variable->CurrPtr) + DataSize > MaxDataSize) {\r
+ if (DataSizeOfVariable (CacheVariable->CurrPtr) + DataSize > MaxDataSize) {\r
//\r
// Existing data size + new data size exceed maximum variable size limitation.\r
//\r
Status = EFI_INVALID_PARAMETER;\r
goto Done;\r
}\r
- CopyMem ((UINT8*) ((UINTN) BufferForMerge + DataSizeOfVariable (Variable->CurrPtr)), Data, DataSize);\r
- MergedBufSize = DataSizeOfVariable (Variable->CurrPtr) + DataSize;\r
+ CopyMem ((UINT8*) ((UINTN) BufferForMerge + DataSizeOfVariable (CacheVariable->CurrPtr)), Data, DataSize);\r
+ MergedBufSize = DataSizeOfVariable (CacheVariable->CurrPtr) + DataSize;\r
\r
//\r
// BufferForMerge(from DataOffset of NextVariable) has included the merged existing and new data.\r
//\r
// Mark the old variable as in delete transition.\r
//\r
- State = Variable->CurrPtr->State;\r
+ State = CacheVariable->CurrPtr->State;\r
State &= VAR_IN_DELETED_TRANSITION;\r
\r
Status = UpdateVariableStore (\r
// with the variable, we need associate the new timestamp with the updated value.\r
//\r
if (Variable->CurrPtr != NULL) {\r
- if (VariableCompareTimeStampInternal (&(((AUTHENTICATED_VARIABLE_HEADER *) Variable->CurrPtr)->TimeStamp), TimeStamp)) {\r
+ if (VariableCompareTimeStampInternal (&(((AUTHENTICATED_VARIABLE_HEADER *) CacheVariable->CurrPtr)->TimeStamp), TimeStamp)) {\r
CopyMem (&AuthVariable->TimeStamp, TimeStamp, sizeof (EFI_TIME));\r
+ } else {\r
+ CopyMem (&AuthVariable->TimeStamp, &(((AUTHENTICATED_VARIABLE_HEADER *) CacheVariable->CurrPtr)->TimeStamp), sizeof (EFI_TIME));\r
}\r
}\r
}\r
}\r
goto Done;\r
}\r
- //\r
- // Four steps\r
- // 1. Write variable header\r
- // 2. Set variable state to header valid\r
- // 3. Write variable data\r
- // 4. Set variable state to valid\r
- //\r
- //\r
- // Step 1:\r
- //\r
- CacheOffset = mVariableModuleGlobal->NonVolatileLastVariableOffset;\r
- Status = UpdateVariableStore (\r
- &mVariableModuleGlobal->VariableGlobal,\r
- FALSE,\r
- TRUE,\r
- Fvb,\r
- mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
- (UINT32) GetVariableHeaderSize (),\r
- (UINT8 *) NextVariable\r
- );\r
\r
- if (EFI_ERROR (Status)) {\r
- goto Done;\r
- }\r
+ if (!mVariableModuleGlobal->VariableGlobal.EmuNvMode) {\r
+ //\r
+ // Four steps\r
+ // 1. Write variable header\r
+ // 2. Set variable state to header valid\r
+ // 3. Write variable data\r
+ // 4. Set variable state to valid\r
+ //\r
+ //\r
+ // Step 1:\r
+ //\r
+ Status = UpdateVariableStore (\r
+ &mVariableModuleGlobal->VariableGlobal,\r
+ FALSE,\r
+ TRUE,\r
+ Fvb,\r
+ mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
+ (UINT32) GetVariableHeaderSize (),\r
+ (UINT8 *) NextVariable\r
+ );\r
\r
- //\r
- // Step 2:\r
- //\r
- NextVariable->State = VAR_HEADER_VALID_ONLY;\r
- Status = UpdateVariableStore (\r
- &mVariableModuleGlobal->VariableGlobal,\r
- FALSE,\r
- TRUE,\r
- Fvb,\r
- mVariableModuleGlobal->NonVolatileLastVariableOffset + OFFSET_OF (VARIABLE_HEADER, State),\r
- sizeof (UINT8),\r
- &NextVariable->State\r
- );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
\r
- if (EFI_ERROR (Status)) {\r
- goto Done;\r
- }\r
- //\r
- // Step 3:\r
- //\r
- Status = UpdateVariableStore (\r
- &mVariableModuleGlobal->VariableGlobal,\r
- FALSE,\r
- TRUE,\r
- Fvb,\r
- mVariableModuleGlobal->NonVolatileLastVariableOffset + GetVariableHeaderSize (),\r
- (UINT32) (VarSize - GetVariableHeaderSize ()),\r
- (UINT8 *) NextVariable + GetVariableHeaderSize ()\r
- );\r
+ //\r
+ // Step 2:\r
+ //\r
+ NextVariable->State = VAR_HEADER_VALID_ONLY;\r
+ Status = UpdateVariableStore (\r
+ &mVariableModuleGlobal->VariableGlobal,\r
+ FALSE,\r
+ TRUE,\r
+ Fvb,\r
+ mVariableModuleGlobal->NonVolatileLastVariableOffset + OFFSET_OF (VARIABLE_HEADER, State),\r
+ sizeof (UINT8),\r
+ &NextVariable->State\r
+ );\r
\r
- if (EFI_ERROR (Status)) {\r
- goto Done;\r
- }\r
- //\r
- // Step 4:\r
- //\r
- NextVariable->State = VAR_ADDED;\r
- Status = UpdateVariableStore (\r
- &mVariableModuleGlobal->VariableGlobal,\r
- FALSE,\r
- TRUE,\r
- Fvb,\r
- mVariableModuleGlobal->NonVolatileLastVariableOffset + OFFSET_OF (VARIABLE_HEADER, State),\r
- sizeof (UINT8),\r
- &NextVariable->State\r
- );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+ //\r
+ // Step 3:\r
+ //\r
+ Status = UpdateVariableStore (\r
+ &mVariableModuleGlobal->VariableGlobal,\r
+ FALSE,\r
+ TRUE,\r
+ Fvb,\r
+ mVariableModuleGlobal->NonVolatileLastVariableOffset + GetVariableHeaderSize (),\r
+ (UINT32) (VarSize - GetVariableHeaderSize ()),\r
+ (UINT8 *) NextVariable + GetVariableHeaderSize ()\r
+ );\r
\r
- if (EFI_ERROR (Status)) {\r
- goto Done;\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+ //\r
+ // Step 4:\r
+ //\r
+ NextVariable->State = VAR_ADDED;\r
+ Status = UpdateVariableStore (\r
+ &mVariableModuleGlobal->VariableGlobal,\r
+ FALSE,\r
+ TRUE,\r
+ Fvb,\r
+ mVariableModuleGlobal->NonVolatileLastVariableOffset + OFFSET_OF (VARIABLE_HEADER, State),\r
+ sizeof (UINT8),\r
+ &NextVariable->State\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ //\r
+ // Update the memory copy of Flash region.\r
+ //\r
+ CopyMem ((UINT8 *)mNvVariableCache + mVariableModuleGlobal->NonVolatileLastVariableOffset, (UINT8 *)NextVariable, VarSize);\r
+ } else {\r
+ //\r
+ // Emulated non-volatile variable mode.\r
+ //\r
+ NextVariable->State = VAR_ADDED;\r
+ Status = UpdateVariableStore (\r
+ &mVariableModuleGlobal->VariableGlobal,\r
+ FALSE,\r
+ TRUE,\r
+ Fvb,\r
+ mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
+ (UINT32) VarSize,\r
+ (UINT8 *) NextVariable\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
}\r
\r
mVariableModuleGlobal->NonVolatileLastVariableOffset += HEADER_ALIGN (VarSize);\r
mVariableModuleGlobal->CommonUserVariableTotalSize += HEADER_ALIGN (VarSize);\r
}\r
}\r
- //\r
- // update the memory copy of Flash region.\r
- //\r
- CopyMem ((UINT8 *)mNvVariableCache + CacheOffset, (UINT8 *)NextVariable, VarSize);\r
} else {\r
//\r
// Create a volatile variable.\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
+ ASSERT (CacheVariable->InDeletedTransitionPtr != NULL);\r
+ State = CacheVariable->InDeletedTransitionPtr->State;\r
State &= VAR_DELETED;\r
Status = UpdateVariableStore (\r
&mVariableModuleGlobal->VariableGlobal,\r
);\r
if (!EFI_ERROR (Status)) {\r
if (!Variable->Volatile) {\r
- ASSERT (CacheVariable->InDeletedTransitionPtr != NULL);\r
CacheVariable->InDeletedTransitionPtr->State = State;\r
}\r
} else {\r
}\r
}\r
\r
- State = Variable->CurrPtr->State;\r
+ State = CacheVariable->CurrPtr->State;\r
State &= VAR_DELETED;\r
\r
Status = UpdateVariableStore (\r
return Status;\r
}\r
\r
-/**\r
- Check if a Unicode character is a hexadecimal character.\r
-\r
- This function checks if a Unicode character is a\r
- hexadecimal character. The valid hexadecimal character is\r
- L'0' to L'9', L'a' to L'f', or L'A' to L'F'.\r
-\r
-\r
- @param Char The character to check against.\r
-\r
- @retval TRUE If the Char is a hexadecmial character.\r
- @retval FALSE If the Char is not a hexadecmial character.\r
-\r
-**/\r
-BOOLEAN\r
-EFIAPI\r
-IsHexaDecimalDigitCharacter (\r
- IN CHAR16 Char\r
- )\r
-{\r
- return (BOOLEAN) ((Char >= L'0' && Char <= L'9') || (Char >= L'A' && Char <= L'F') || (Char >= L'a' && Char <= L'f'));\r
-}\r
-\r
-/**\r
-\r
- This code checks if variable is hardware error record variable or not.\r
-\r
- According to UEFI spec, hardware error record variable should use the EFI_HARDWARE_ERROR_VARIABLE VendorGuid\r
- and have the L"HwErrRec####" name convention, #### is a printed hex value and no 0x or h is included in the hex value.\r
-\r
- @param VariableName Pointer to variable name.\r
- @param VendorGuid Variable Vendor Guid.\r
-\r
- @retval TRUE Variable is hardware error record variable.\r
- @retval FALSE Variable is not hardware error record variable.\r
-\r
-**/\r
-BOOLEAN\r
-EFIAPI\r
-IsHwErrRecVariable (\r
- IN CHAR16 *VariableName,\r
- IN EFI_GUID *VendorGuid\r
- )\r
-{\r
- if (!CompareGuid (VendorGuid, &gEfiHardwareErrorVariableGuid) ||\r
- (StrLen (VariableName) != StrLen (L"HwErrRec####")) ||\r
- (StrnCmp(VariableName, L"HwErrRec", StrLen (L"HwErrRec")) != 0) ||\r
- !IsHexaDecimalDigitCharacter (VariableName[0x8]) ||\r
- !IsHexaDecimalDigitCharacter (VariableName[0x9]) ||\r
- !IsHexaDecimalDigitCharacter (VariableName[0xA]) ||\r
- !IsHexaDecimalDigitCharacter (VariableName[0xB])) {\r
- return FALSE;\r
- }\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
-\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
- CHAR16 *Name;\r
- LIST_ENTRY *Link;\r
- VARIABLE_ENTRY *LockedEntry;\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 = AllocateRuntimeZeroPool (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
- for ( Link = GetFirstNode (&mLockedVariableList)\r
- ; !IsNull (&mLockedVariableList, Link)\r
- ; Link = GetNextNode (&mLockedVariableList, Link)\r
- ) {\r
- LockedEntry = BASE_CR (Link, VARIABLE_ENTRY, Link);\r
- Name = (CHAR16 *) ((UINTN) LockedEntry + sizeof (*LockedEntry));\r
- if (CompareGuid (&LockedEntry->Guid, VendorGuid) && (StrCmp (Name, VariableName) == 0)) {\r
- goto Done;\r
- }\r
- }\r
-\r
- Name = (CHAR16 *) ((UINTN) Entry + sizeof (*Entry));\r
- StrCpyS (Name, StrSize (VariableName)/sizeof(CHAR16), VariableName);\r
- CopyGuid (&Entry->Guid, VendorGuid);\r
- InsertTailList (&mLockedVariableList, &Entry->Link);\r
-\r
-Done:\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
@param Attributes Attribute value of the variable found.\r
@param DataSize Size of Data found. If size is less than the\r
data, this value contains the required size.\r
- @param Data Data pointer.\r
+ @param Data The buffer to return the contents of the variable. May be NULL\r
+ with a zero DataSize in order to determine the size buffer needed.\r
\r
@return EFI_INVALID_PARAMETER Invalid parameter.\r
@return EFI_SUCCESS Find the specified variable.\r
IN EFI_GUID *VendorGuid,\r
OUT UINT32 *Attributes OPTIONAL,\r
IN OUT UINTN *DataSize,\r
- OUT VOID *Data\r
+ OUT VOID *Data OPTIONAL\r
)\r
{\r
EFI_STATUS Status;\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
+ if (VariableName[0] == 0) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
\r
Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
@param[in] VendorGuid Variable Vendor Guid.\r
@param[out] VariablePtr Pointer to variable header address.\r
\r
- @return EFI_SUCCESS Find the specified variable.\r
- @return EFI_NOT_FOUND Not found.\r
+ @retval EFI_SUCCESS The function completed successfully.\r
+ @retval EFI_NOT_FOUND The next variable was not found.\r
+ @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while VendorGuid is NULL.\r
+ @retval EFI_INVALID_PARAMETER The input values of VariableName and VendorGuid are not a name and\r
+ GUID of an existing variable.\r
\r
**/\r
EFI_STATUS\r
\r
Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {\r
+ //\r
+ // For VariableName is an empty string, FindVariable() will try to find and return\r
+ // the first qualified variable, and if FindVariable() returns error (EFI_NOT_FOUND)\r
+ // as no any variable is found, still go to return the error (EFI_NOT_FOUND).\r
+ //\r
+ if (VariableName[0] != 0) {\r
+ //\r
+ // For VariableName is not an empty string, and FindVariable() returns error as\r
+ // VariableName and VendorGuid are not a name and GUID of an existing variable,\r
+ // there is no way to get next variable, follow spec to return EFI_INVALID_PARAMETER.\r
+ //\r
+ Status = EFI_INVALID_PARAMETER;\r
+ }\r
goto Done;\r
}\r
\r
Caution: This function may receive untrusted input.\r
This function may be invoked in SMM mode. This function will do basic validation, before parse the data.\r
\r
- @param VariableNameSize Size of the variable name.\r
+ @param VariableNameSize The size of the VariableName buffer. The size must be large\r
+ enough to fit input string supplied in VariableName buffer.\r
@param VariableName Pointer to variable name.\r
@param VendorGuid Variable Vendor Guid.\r
\r
- @return EFI_INVALID_PARAMETER Invalid parameter.\r
- @return EFI_SUCCESS Find the specified variable.\r
- @return EFI_NOT_FOUND Not found.\r
- @return EFI_BUFFER_TO_SMALL DataSize is too small for the result.\r
+ @retval EFI_SUCCESS The function completed successfully.\r
+ @retval EFI_NOT_FOUND The next variable was not found.\r
+ @retval EFI_BUFFER_TOO_SMALL The VariableNameSize is too small for the result.\r
+ VariableNameSize has been updated with the size needed to complete the request.\r
+ @retval EFI_INVALID_PARAMETER VariableNameSize is NULL.\r
+ @retval EFI_INVALID_PARAMETER VariableName is NULL.\r
+ @retval EFI_INVALID_PARAMETER VendorGuid is NULL.\r
+ @retval EFI_INVALID_PARAMETER The input values of VariableName and VendorGuid are not a name and\r
+ GUID of an existing variable.\r
+ @retval EFI_INVALID_PARAMETER Null-terminator is not found in the first VariableNameSize bytes of\r
+ the input VariableName buffer.\r
\r
**/\r
EFI_STATUS\r
)\r
{\r
EFI_STATUS Status;\r
+ UINTN MaxLen;\r
UINTN VarNameSize;\r
VARIABLE_HEADER *VariablePtr;\r
\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
+ //\r
+ // Calculate the possible maximum length of name string, including the Null terminator.\r
+ //\r
+ MaxLen = *VariableNameSize / sizeof (CHAR16);\r
+ if ((MaxLen == 0) || (StrnLenS (VariableName, MaxLen) == MaxLen)) {\r
+ //\r
+ // Null-terminator is not found in the first VariableNameSize bytes of the input VariableName buffer,\r
+ // follow spec to return EFI_INVALID_PARAMETER.\r
+ //\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
\r
Status = VariableServiceGetNextVariableInternal (VariableName, VendorGuid, &VariablePtr);\r
VARIABLE_HEADER *NextVariable;\r
EFI_PHYSICAL_ADDRESS Point;\r
UINTN PayloadSize;\r
- LIST_ENTRY *Link;\r
- VARIABLE_ENTRY *Entry;\r
- CHAR16 *Name;\r
\r
//\r
// Check input parameters.\r
\r
//\r
// Check for reserverd bit in variable attribute.\r
+ // EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is deprecated but we still allow\r
+ // the delete operation of common authenticated variable at user physical presence.\r
+ // So leave EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute check to AuthVariableLib\r
//\r
- if ((Attributes & (~EFI_VARIABLE_ATTRIBUTES_MASK)) != 0) {\r
+ if ((Attributes & (~(EFI_VARIABLE_ATTRIBUTES_MASK | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS))) != 0) {\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
// Make sure if runtime bit is set, boot service bit is set also.\r
//\r
if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {\r
- return EFI_INVALID_PARAMETER;\r
+ if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
+ return EFI_UNSUPPORTED;\r
+ } else {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
} else if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {\r
if (!mVariableModuleGlobal->VariableGlobal.AuthSupport) {\r
//\r
//\r
if (((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS)\r
&& ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) {\r
- return EFI_INVALID_PARAMETER;\r
+ return EFI_UNSUPPORTED;\r
}\r
\r
if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) {\r
- if (DataSize < AUTHINFO_SIZE) {\r
- //\r
- // Try to write Authenticated Variable without AuthInfo.\r
- //\r
- return EFI_SECURITY_VIOLATION;\r
+ //\r
+ // If DataSize == AUTHINFO_SIZE and then PayloadSize is 0.\r
+ // Maybe it's the delete operation of common authenticated variable at user physical presence.\r
+ //\r
+ if (DataSize != AUTHINFO_SIZE) {\r
+ return EFI_UNSUPPORTED;\r
}\r
PayloadSize = DataSize - AUTHINFO_SIZE;\r
} else if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) {\r
((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->AuthInfo.Hdr.dwLength < OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData)) {\r
return EFI_SECURITY_VIOLATION;\r
}\r
+ //\r
+ // The VariableSpeculationBarrier() call here is to ensure the above sanity\r
+ // check for the EFI_VARIABLE_AUTHENTICATION_2 descriptor has been completed\r
+ // before the execution of subsequent codes.\r
+ //\r
+ VariableSpeculationBarrier ();\r
PayloadSize = DataSize - AUTHINFO2_SIZE (Data);\r
} else {\r
PayloadSize = DataSize;\r
if (StrSize (VariableName) + PayloadSize > PcdGet32 (PcdMaxHardwareErrorVariableSize) - GetVariableHeaderSize ()) {\r
return EFI_INVALID_PARAMETER;\r
}\r
- if (!IsHwErrRecVariable(VariableName, VendorGuid)) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
} else {\r
//\r
// The size of the VariableName, including the Unicode Null in bytes plus\r
- // the DataSize is limited to maximum size of Max(Auth)VariableSize bytes.\r
+ // the DataSize is limited to maximum size of Max(Auth|Volatile)VariableSize bytes.\r
//\r
if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {\r
if (StrSize (VariableName) + PayloadSize > mVariableModuleGlobal->MaxAuthVariableSize - GetVariableHeaderSize ()) {\r
+ DEBUG ((DEBUG_ERROR,\r
+ "%a: Failed to set variable '%s' with Guid %g\n",\r
+ __FUNCTION__, VariableName, VendorGuid));\r
+ DEBUG ((DEBUG_ERROR,\r
+ "NameSize(0x%x) + PayloadSize(0x%x) > "\r
+ "MaxAuthVariableSize(0x%x) - HeaderSize(0x%x)\n",\r
+ StrSize (VariableName), PayloadSize,\r
+ mVariableModuleGlobal->MaxAuthVariableSize,\r
+ GetVariableHeaderSize ()\r
+ ));\r
return EFI_INVALID_PARAMETER;\r
}\r
- } else {\r
+ } else if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {\r
if (StrSize (VariableName) + PayloadSize > mVariableModuleGlobal->MaxVariableSize - GetVariableHeaderSize ()) {\r
+ DEBUG ((DEBUG_ERROR,\r
+ "%a: Failed to set variable '%s' with Guid %g\n",\r
+ __FUNCTION__, VariableName, VendorGuid));\r
+ DEBUG ((DEBUG_ERROR,\r
+ "NameSize(0x%x) + PayloadSize(0x%x) > "\r
+ "MaxVariableSize(0x%x) - HeaderSize(0x%x)\n",\r
+ StrSize (VariableName), PayloadSize,\r
+ mVariableModuleGlobal->MaxVariableSize,\r
+ GetVariableHeaderSize ()\r
+ ));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ } else {\r
+ if (StrSize (VariableName) + PayloadSize > mVariableModuleGlobal->MaxVolatileVariableSize - GetVariableHeaderSize ()) {\r
+ DEBUG ((DEBUG_ERROR,\r
+ "%a: Failed to set variable '%s' with Guid %g\n",\r
+ __FUNCTION__, VariableName, VendorGuid));\r
+ DEBUG ((DEBUG_ERROR,\r
+ "NameSize(0x%x) + PayloadSize(0x%x) > "\r
+ "MaxVolatileVariableSize(0x%x) - HeaderSize(0x%x)\n",\r
+ StrSize (VariableName), PayloadSize,\r
+ mVariableModuleGlobal->MaxVolatileVariableSize,\r
+ GetVariableHeaderSize ()\r
+ ));\r
return EFI_INVALID_PARAMETER;\r
}\r
}\r
}\r
\r
- Status = InternalVarCheckSetVariableCheck (VariableName, VendorGuid, Attributes, PayloadSize, (VOID *) ((UINTN) Data + DataSize - PayloadSize));\r
+ //\r
+ // Special Handling for MOR Lock variable.\r
+ //\r
+ Status = SetVariableCheckHandlerMor (VariableName, VendorGuid, Attributes, PayloadSize, (VOID *) ((UINTN) Data + DataSize - PayloadSize));\r
+ if (Status == EFI_ALREADY_STARTED) {\r
+ //\r
+ // EFI_ALREADY_STARTED means the SetVariable() action is handled inside of SetVariableCheckHandlerMor().\r
+ // Variable driver can just return SUCCESS.\r
+ //\r
+ return EFI_SUCCESS;\r
+ }\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = VarCheckLibSetVariableCheck (VariableName, VendorGuid, Attributes, PayloadSize, (VOID *) ((UINTN) Data + DataSize - PayloadSize), mRequestSource);\r
if (EFI_ERROR (Status)) {\r
return Status;\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
- Name = (CHAR16 *) ((UINTN) Entry + sizeof (*Entry));\r
- if (CompareGuid (&Entry->Guid, VendorGuid) && (StrCmp (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
}\r
\r
//\r
- // Let *MaximumVariableSize be Max(Auth)VariableSize with the exception of the variable header size.\r
+ // Let *MaximumVariableSize be Max(Auth|Volatile)VariableSize with the exception of the variable header size.\r
//\r
if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {\r
*MaximumVariableSize = mVariableModuleGlobal->MaxAuthVariableSize - GetVariableHeaderSize ();\r
- } else {\r
+ } else if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {\r
*MaximumVariableSize = mVariableModuleGlobal->MaxVariableSize - GetVariableHeaderSize ();\r
+ } else {\r
+ *MaximumVariableSize = mVariableModuleGlobal->MaxVolatileVariableSize - GetVariableHeaderSize ();\r
}\r
}\r
\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
+ if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
+ //\r
+ // Deprecated attribute, make this check as highest priority.\r
+ //\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
if ((Attributes & EFI_VARIABLE_ATTRIBUTES_MASK) == 0) {\r
//\r
// Make sure the Attributes combination is supported by the platform.\r
}\r
\r
/**\r
- Init non-volatile variable store.\r
+ Get maximum variable size, covering both non-volatile and volatile variables.\r
\r
- @param[out] NvFvHeader Output pointer to non-volatile FV header address.\r
+ @return Maximum variable size.\r
+\r
+**/\r
+UINTN\r
+GetMaxVariableSize (\r
+ VOID\r
+ )\r
+{\r
+ UINTN MaxVariableSize;\r
+\r
+ MaxVariableSize = GetNonVolatileMaxVariableSize();\r
+ //\r
+ // The condition below fails implicitly if PcdMaxVolatileVariableSize equals\r
+ // the default zero value.\r
+ //\r
+ if (MaxVariableSize < PcdGet32 (PcdMaxVolatileVariableSize)) {\r
+ MaxVariableSize = PcdGet32 (PcdMaxVolatileVariableSize);\r
+ }\r
+ return MaxVariableSize;\r
+}\r
+\r
+/**\r
+ Init real non-volatile variable store.\r
+\r
+ @param[out] VariableStoreBase Output pointer to real non-volatile variable store base.\r
\r
@retval EFI_SUCCESS Function successfully executed.\r
@retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.\r
\r
**/\r
EFI_STATUS\r
-InitNonVolatileVariableStore (\r
- OUT EFI_FIRMWARE_VOLUME_HEADER **NvFvHeader\r
+InitRealNonVolatileVariableStore (\r
+ OUT EFI_PHYSICAL_ADDRESS *VariableStoreBase\r
)\r
{\r
EFI_FIRMWARE_VOLUME_HEADER *FvHeader;\r
- VARIABLE_HEADER *Variable;\r
- VARIABLE_HEADER *NextVariable;\r
- EFI_PHYSICAL_ADDRESS VariableStoreBase;\r
- UINT64 VariableStoreLength;\r
- UINTN VariableSize;\r
+ VARIABLE_STORE_HEADER *VariableStore;\r
+ UINT32 VariableStoreLength;\r
EFI_HOB_GUID_TYPE *GuidHob;\r
EFI_PHYSICAL_ADDRESS NvStorageBase;\r
UINT8 *NvStorageData;\r
UINT32 HwErrStorageSize;\r
UINT32 MaxUserNvVariableSpaceSize;\r
UINT32 BoottimeReservedNvVariableSpaceSize;\r
+ EFI_STATUS Status;\r
+ VOID *FtwProtocol;\r
\r
mVariableModuleGlobal->FvbInstance = NULL;\r
\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
+ NvStorageBase = NV_STORAGE_VARIABLE_BASE;\r
+ ASSERT (NvStorageBase != 0);\r
+\r
//\r
// Copy NV storage data to the memory buffer.\r
//\r
CopyMem (NvStorageData, (UINT8 *) (UINTN) NvStorageBase, NvStorageSize);\r
\r
+ Status = GetFtwProtocol ((VOID **)&FtwProtocol);\r
//\r
- // Check the FTW last write data hob.\r
+ // If FTW protocol has been installed, no need to check 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
+ if (EFI_ERROR (Status)) {\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
\r
return EFI_VOLUME_CORRUPTED;\r
}\r
\r
- VariableStoreBase = (EFI_PHYSICAL_ADDRESS) ((UINTN) FvHeader + FvHeader->HeaderLength);\r
- VariableStoreLength = (UINT64) (NvStorageSize - FvHeader->HeaderLength);\r
+ VariableStore = (VARIABLE_STORE_HEADER *) ((UINTN) FvHeader + FvHeader->HeaderLength);\r
+ VariableStoreLength = NvStorageSize - FvHeader->HeaderLength;\r
+ ASSERT (sizeof (VARIABLE_STORE_HEADER) <= VariableStoreLength);\r
+ ASSERT (VariableStore->Size == VariableStoreLength);\r
\r
- mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;\r
- mNvVariableCache = (VARIABLE_STORE_HEADER *) (UINTN) VariableStoreBase;\r
- if (GetVariableStoreStatus (mNvVariableCache) != EfiValid) {\r
+ //\r
+ // Check if the Variable Store header is not corrupted\r
+ //\r
+ if (GetVariableStoreStatus (VariableStore) != 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
- ASSERT (sizeof (VARIABLE_STORE_HEADER) <= VariableStoreLength);\r
+ mNvFvHeaderCache = FvHeader;\r
\r
- mVariableModuleGlobal->VariableGlobal.AuthFormat = (BOOLEAN)(CompareGuid (&mNvVariableCache->Signature, &gEfiAuthenticatedVariableGuid));\r
+ *VariableStoreBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VariableStore;\r
\r
HwErrStorageSize = PcdGet32 (PcdHwErrStorageSize);\r
MaxUserNvVariableSpaceSize = PcdGet32 (PcdMaxUserNvVariableSpaceSize);\r
//\r
ASSERT (GetNonVolatileMaxVariableSize () < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)));\r
\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Init emulated non-volatile variable store.\r
+\r
+ @param[out] VariableStoreBase Output pointer to emulated non-volatile variable store base.\r
+\r
+ @retval EFI_SUCCESS Function successfully executed.\r
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.\r
+\r
+**/\r
+EFI_STATUS\r
+InitEmuNonVolatileVariableStore (\r
+ EFI_PHYSICAL_ADDRESS *VariableStoreBase\r
+ )\r
+{\r
+ VARIABLE_STORE_HEADER *VariableStore;\r
+ UINT32 VariableStoreLength;\r
+ BOOLEAN FullyInitializeStore;\r
+ UINT32 HwErrStorageSize;\r
+\r
+ FullyInitializeStore = TRUE;\r
+\r
+ VariableStoreLength = PcdGet32 (PcdVariableStoreSize);\r
+ ASSERT (sizeof (VARIABLE_STORE_HEADER) <= VariableStoreLength);\r
+\r
+ //\r
+ // Allocate memory for variable store.\r
+ //\r
+ if (PcdGet64 (PcdEmuVariableNvStoreReserved) == 0) {\r
+ VariableStore = (VARIABLE_STORE_HEADER *) AllocateRuntimePool (VariableStoreLength);\r
+ if (VariableStore == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ } else {\r
+ //\r
+ // A memory location has been reserved for the NV variable store. Certain\r
+ // platforms may be able to preserve a memory range across system resets,\r
+ // thereby providing better NV variable emulation.\r
+ //\r
+ VariableStore =\r
+ (VARIABLE_STORE_HEADER *)(VOID*)(UINTN)\r
+ PcdGet64 (PcdEmuVariableNvStoreReserved);\r
+ if ((VariableStore->Size == VariableStoreLength) &&\r
+ (CompareGuid (&VariableStore->Signature, &gEfiAuthenticatedVariableGuid) ||\r
+ CompareGuid (&VariableStore->Signature, &gEfiVariableGuid)) &&\r
+ (VariableStore->Format == VARIABLE_STORE_FORMATTED) &&\r
+ (VariableStore->State == VARIABLE_STORE_HEALTHY)) {\r
+ DEBUG((\r
+ DEBUG_INFO,\r
+ "Variable Store reserved at %p appears to be valid\n",\r
+ VariableStore\r
+ ));\r
+ FullyInitializeStore = FALSE;\r
+ }\r
+ }\r
+\r
+ if (FullyInitializeStore) {\r
+ SetMem (VariableStore, VariableStoreLength, 0xff);\r
+ //\r
+ // Use gEfiAuthenticatedVariableGuid for potential auth variable support.\r
+ //\r
+ CopyGuid (&VariableStore->Signature, &gEfiAuthenticatedVariableGuid);\r
+ VariableStore->Size = VariableStoreLength;\r
+ VariableStore->Format = VARIABLE_STORE_FORMATTED;\r
+ VariableStore->State = VARIABLE_STORE_HEALTHY;\r
+ VariableStore->Reserved = 0;\r
+ VariableStore->Reserved1 = 0;\r
+ }\r
+\r
+ *VariableStoreBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VariableStore;\r
+\r
+ HwErrStorageSize = PcdGet32 (PcdHwErrStorageSize);\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 the value of\r
+ // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)).\r
+ //\r
+ ASSERT (HwErrStorageSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)));\r
+\r
+ mVariableModuleGlobal->CommonVariableSpace = ((UINTN) VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize);\r
+ mVariableModuleGlobal->CommonMaxUserVariableSpace = mVariableModuleGlobal->CommonVariableSpace;\r
+ mVariableModuleGlobal->CommonRuntimeVariableSpace = mVariableModuleGlobal->CommonVariableSpace;\r
+\r
+ return EFI_SUCCESS;\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
+ VARIABLE_HEADER *Variable;\r
+ VARIABLE_HEADER *NextVariable;\r
+ EFI_PHYSICAL_ADDRESS VariableStoreBase;\r
+ UINTN VariableSize;\r
+ EFI_STATUS Status;\r
+\r
+ if (PcdGetBool (PcdEmuVariableNvModeEnable)) {\r
+ Status = InitEmuNonVolatileVariableStore (&VariableStoreBase);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ mVariableModuleGlobal->VariableGlobal.EmuNvMode = TRUE;\r
+ DEBUG ((DEBUG_INFO, "Variable driver will work at emulated non-volatile variable mode!\n"));\r
+ } else {\r
+ Status = InitRealNonVolatileVariableStore (&VariableStoreBase);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ mVariableModuleGlobal->VariableGlobal.EmuNvMode = FALSE;\r
+ }\r
+\r
+ mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;\r
+ mNvVariableCache = (VARIABLE_STORE_HEADER *) (UINTN) VariableStoreBase;\r
+ mVariableModuleGlobal->VariableGlobal.AuthFormat = (BOOLEAN)(CompareGuid (&mNvVariableCache->Signature, &gEfiAuthenticatedVariableGuid));\r
+\r
mVariableModuleGlobal->MaxVariableSize = PcdGet32 (PcdMaxVariableSize);\r
mVariableModuleGlobal->MaxAuthVariableSize = ((PcdGet32 (PcdMaxAuthVariableSize) != 0) ? PcdGet32 (PcdMaxAuthVariableSize) : mVariableModuleGlobal->MaxVariableSize);\r
\r
//\r
// Parse non-volatile variable data and get last variable offset.\r
//\r
- Variable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase);\r
- while (IsValidVariableHeader (Variable, GetEndPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase))) {\r
+ Variable = GetStartPointer (mNvVariableCache);\r
+ while (IsValidVariableHeader (Variable, GetEndPointer (mNvVariableCache))) {\r
NextVariable = GetNextVariablePtr (Variable);\r
VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
if ((Variable->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
\r
Variable = NextVariable;\r
}\r
- mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) Variable - (UINTN) VariableStoreBase;\r
+ mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) Variable - (UINTN) mNvVariableCache;\r
\r
- *NvFvHeader = FvHeader;\r
return EFI_SUCCESS;\r
}\r
\r
VARIABLE_STORE_HEADER *VariableStoreHeader;\r
VARIABLE_HEADER *Variable;\r
VOID *VariableData;\r
+ VARIABLE_POINTER_TRACK VariablePtrTrack;\r
BOOLEAN ErrorFlag;\r
\r
ErrorFlag = FALSE;\r
!CompareGuid (VendorGuid, GetVendorGuidPtr (Variable)) ||\r
StrCmp (VariableName, GetVariableNamePtr (Variable)) != 0) {\r
VariableData = GetVariableDataPtr (Variable);\r
- Status = VariableServiceSetVariable (\r
+ FindVariable (GetVariableNamePtr (Variable), GetVendorGuidPtr (Variable), &VariablePtrTrack, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
+ Status = UpdateVariable (\r
GetVariableNamePtr (Variable),\r
GetVendorGuidPtr (Variable),\r
- Variable->Attributes,\r
+ VariableData,\r
DataSizeOfVariable (Variable),\r
- VariableData\r
- );\r
+ Variable->Attributes,\r
+ 0,\r
+ 0,\r
+ &VariablePtrTrack,\r
+ NULL\r
+ );\r
DEBUG ((EFI_D_INFO, "Variable driver flush the HOB variable to flash: %g %s %r\n", GetVendorGuidPtr (Variable), GetVariableNamePtr (Variable), Status));\r
} else {\r
//\r
- // The updated or deleted variable is matched with the HOB variable.\r
+ // The updated or deleted variable is matched with this HOB variable.\r
// Don't break here because we will try to set other HOB variables\r
// since this variable could be set successfully.\r
//\r
}\r
\r
/**\r
- Initializes variable write service after FTW was ready.\r
+ Initializes variable write service.\r
\r
@retval EFI_SUCCESS Function successfully executed.\r
@retval Others Fail to initialize the variable service.\r
)\r
{\r
EFI_STATUS Status;\r
- VARIABLE_STORE_HEADER *VariableStoreHeader;\r
UINTN Index;\r
UINT8 Data;\r
- EFI_PHYSICAL_ADDRESS VariableStoreBase;\r
- EFI_PHYSICAL_ADDRESS NvStorageBase;\r
VARIABLE_ENTRY_PROPERTY *VariableEntry;\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
- //\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
+ AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
\r
//\r
// Check if the free area is really free.\r
//\r
- for (Index = mVariableModuleGlobal->NonVolatileLastVariableOffset; Index < VariableStoreHeader->Size; Index++) {\r
+ for (Index = mVariableModuleGlobal->NonVolatileLastVariableOffset; Index < mNvVariableCache->Size; Index++) {\r
Data = ((UINT8 *) mNvVariableCache)[Index];\r
if (Data != 0xff) {\r
//\r
0\r
);\r
if (EFI_ERROR (Status)) {\r
+ ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
return Status;\r
}\r
break;\r
FlushHobVariableToFlash (NULL, NULL);\r
\r
Status = EFI_SUCCESS;\r
- ZeroMem (&mContextOut, sizeof (mContextOut));\r
+ ZeroMem (&mAuthContextOut, sizeof (mAuthContextOut));\r
if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {\r
//\r
// Authenticated variable initialize.\r
//\r
- mContextIn.MaxAuthVariableSize = mVariableModuleGlobal->MaxAuthVariableSize - GetVariableHeaderSize ();\r
- Status = AuthVariableLibInitialize (&mContextIn, &mContextOut);\r
+ mAuthContextIn.StructSize = sizeof (AUTH_VAR_LIB_CONTEXT_IN);\r
+ mAuthContextIn.MaxAuthVariableSize = mVariableModuleGlobal->MaxAuthVariableSize - GetVariableHeaderSize ();\r
+ Status = AuthVariableLibInitialize (&mAuthContextIn, &mAuthContextOut);\r
if (!EFI_ERROR (Status)) {\r
DEBUG ((EFI_D_INFO, "Variable driver will work with auth variable support!\n"));\r
mVariableModuleGlobal->VariableGlobal.AuthSupport = TRUE;\r
- if (mContextOut.AuthVarEntry != NULL) {\r
- for (Index = 0; Index < mContextOut.AuthVarEntryCount; Index++) {\r
- VariableEntry = &mContextOut.AuthVarEntry[Index];\r
- Status = InternalVarCheckVariablePropertySet (\r
+ if (mAuthContextOut.AuthVarEntry != NULL) {\r
+ for (Index = 0; Index < mAuthContextOut.AuthVarEntryCount; Index++) {\r
+ VariableEntry = &mAuthContextOut.AuthVarEntry[Index];\r
+ Status = VarCheckLibVariablePropertySet (\r
VariableEntry->Name,\r
VariableEntry->Guid,\r
&VariableEntry->VariableProperty\r
}\r
\r
if (!EFI_ERROR (Status)) {\r
- for (Index = 0; Index < sizeof (mVariableEntryProperty) / sizeof (mVariableEntryProperty[0]); Index++) {\r
+ for (Index = 0; Index < ARRAY_SIZE (mVariableEntryProperty); Index++) {\r
VariableEntry = &mVariableEntryProperty[Index];\r
- Status = InternalVarCheckVariablePropertySet (VariableEntry->Name, VariableEntry->Guid, &VariableEntry->VariableProperty);\r
+ Status = VarCheckLibVariablePropertySet (VariableEntry->Name, VariableEntry->Guid, &VariableEntry->VariableProperty);\r
ASSERT_EFI_ERROR (Status);\r
}\r
}\r
\r
+ ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
+\r
+ //\r
+ // Initialize MOR Lock variable.\r
+ //\r
+ MorLockInit ();\r
+\r
return Status;\r
}\r
\r
+/**\r
+ Convert normal variable storage to the allocated auth variable storage.\r
+\r
+ @param[in] NormalVarStorage Pointer to the normal variable storage header\r
+\r
+ @retval the allocated auth variable storage\r
+**/\r
+VOID *\r
+ConvertNormalVarStorageToAuthVarStorage (\r
+ VARIABLE_STORE_HEADER *NormalVarStorage\r
+ )\r
+{\r
+ VARIABLE_HEADER *StartPtr;\r
+ UINT8 *NextPtr;\r
+ VARIABLE_HEADER *EndPtr;\r
+ UINTN AuthVarStroageSize;\r
+ AUTHENTICATED_VARIABLE_HEADER *AuthStartPtr;\r
+ VARIABLE_STORE_HEADER *AuthVarStorage;\r
+\r
+ AuthVarStroageSize = sizeof (VARIABLE_STORE_HEADER);\r
+ //\r
+ // Set AuthFormat as FALSE for normal variable storage\r
+ //\r
+ mVariableModuleGlobal->VariableGlobal.AuthFormat = FALSE;\r
+\r
+ //\r
+ // Calculate Auth Variable Storage Size\r
+ //\r
+ StartPtr = GetStartPointer (NormalVarStorage);\r
+ EndPtr = GetEndPointer (NormalVarStorage);\r
+ while (StartPtr < EndPtr) {\r
+ if (StartPtr->State == VAR_ADDED) {\r
+ AuthVarStroageSize = HEADER_ALIGN (AuthVarStroageSize);\r
+ AuthVarStroageSize += sizeof (AUTHENTICATED_VARIABLE_HEADER);\r
+ AuthVarStroageSize += StartPtr->NameSize + GET_PAD_SIZE (StartPtr->NameSize);\r
+ AuthVarStroageSize += StartPtr->DataSize + GET_PAD_SIZE (StartPtr->DataSize);\r
+ }\r
+ StartPtr = GetNextVariablePtr (StartPtr);\r
+ }\r
+\r
+ //\r
+ // Allocate Runtime memory for Auth Variable Storage\r
+ //\r
+ AuthVarStorage = AllocateRuntimeZeroPool (AuthVarStroageSize);\r
+ ASSERT (AuthVarStorage != NULL);\r
+ if (AuthVarStorage == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ //\r
+ // Copy Variable from Normal storage to Auth storage\r
+ //\r
+ StartPtr = GetStartPointer (NormalVarStorage);\r
+ EndPtr = GetEndPointer (NormalVarStorage);\r
+ AuthStartPtr = (AUTHENTICATED_VARIABLE_HEADER *) GetStartPointer (AuthVarStorage);\r
+ while (StartPtr < EndPtr) {\r
+ if (StartPtr->State == VAR_ADDED) {\r
+ AuthStartPtr = (AUTHENTICATED_VARIABLE_HEADER *) HEADER_ALIGN (AuthStartPtr);\r
+ //\r
+ // Copy Variable Header\r
+ //\r
+ AuthStartPtr->StartId = StartPtr->StartId;\r
+ AuthStartPtr->State = StartPtr->State;\r
+ AuthStartPtr->Attributes = StartPtr->Attributes;\r
+ AuthStartPtr->NameSize = StartPtr->NameSize;\r
+ AuthStartPtr->DataSize = StartPtr->DataSize;\r
+ CopyGuid (&AuthStartPtr->VendorGuid, &StartPtr->VendorGuid);\r
+ //\r
+ // Copy Variable Name\r
+ //\r
+ NextPtr = (UINT8 *) (AuthStartPtr + 1);\r
+ CopyMem (NextPtr, GetVariableNamePtr (StartPtr), AuthStartPtr->NameSize);\r
+ //\r
+ // Copy Variable Data\r
+ //\r
+ NextPtr = NextPtr + AuthStartPtr->NameSize + GET_PAD_SIZE (AuthStartPtr->NameSize);\r
+ CopyMem (NextPtr, GetVariableDataPtr (StartPtr), AuthStartPtr->DataSize);\r
+ //\r
+ // Go to next variable\r
+ //\r
+ AuthStartPtr = (AUTHENTICATED_VARIABLE_HEADER *) (NextPtr + AuthStartPtr->DataSize + GET_PAD_SIZE (AuthStartPtr->DataSize));\r
+ }\r
+ StartPtr = GetNextVariablePtr (StartPtr);\r
+ }\r
+ //\r
+ // Update Auth Storage Header\r
+ //\r
+ AuthVarStorage->Format = NormalVarStorage->Format;\r
+ AuthVarStorage->State = NormalVarStorage->State;\r
+ AuthVarStorage->Size = (UINT32)((UINTN)AuthStartPtr - (UINTN)AuthVarStorage);\r
+ CopyGuid (&AuthVarStorage->Signature, &gEfiAuthenticatedVariableGuid);\r
+ ASSERT (AuthVarStorage->Size <= AuthVarStroageSize);\r
+\r
+ //\r
+ // Restore AuthFormat\r
+ //\r
+ mVariableModuleGlobal->VariableGlobal.AuthFormat = TRUE;\r
+ return AuthVarStorage;\r
+}\r
+\r
+/**\r
+ Get HOB variable store.\r
+\r
+ @param[in] VariableGuid NV variable store signature.\r
+\r
+ @retval EFI_SUCCESS Function successfully executed.\r
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.\r
+\r
+**/\r
+EFI_STATUS\r
+GetHobVariableStore (\r
+ IN EFI_GUID *VariableGuid\r
+ )\r
+{\r
+ VARIABLE_STORE_HEADER *VariableStoreHeader;\r
+ UINT64 VariableStoreLength;\r
+ EFI_HOB_GUID_TYPE *GuidHob;\r
+ BOOLEAN NeedConvertNormalToAuth;\r
+\r
+ //\r
+ // Make sure there is no more than one Variable HOB.\r
+ //\r
+ DEBUG_CODE (\r
+ GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid);\r
+ if (GuidHob != NULL) {\r
+ if ((GetNextGuidHob (&gEfiAuthenticatedVariableGuid, GET_NEXT_HOB (GuidHob)) != NULL)) {\r
+ DEBUG ((DEBUG_ERROR, "ERROR: Found two Auth Variable HOBs\n"));\r
+ ASSERT (FALSE);\r
+ } else if (GetFirstGuidHob (&gEfiVariableGuid) != NULL) {\r
+ DEBUG ((DEBUG_ERROR, "ERROR: Found one Auth + one Normal Variable HOBs\n"));\r
+ ASSERT (FALSE);\r
+ }\r
+ } else {\r
+ GuidHob = GetFirstGuidHob (&gEfiVariableGuid);\r
+ if (GuidHob != NULL) {\r
+ if ((GetNextGuidHob (&gEfiVariableGuid, GET_NEXT_HOB (GuidHob)) != NULL)) {\r
+ DEBUG ((DEBUG_ERROR, "ERROR: Found two Normal Variable HOBs\n"));\r
+ ASSERT (FALSE);\r
+ }\r
+ }\r
+ }\r
+ );\r
+\r
+ //\r
+ // Combinations supported:\r
+ // 1. Normal NV variable store +\r
+ // Normal HOB variable store\r
+ // 2. Auth NV variable store +\r
+ // Auth HOB variable store\r
+ // 3. Auth NV variable store +\r
+ // Normal HOB variable store (code will convert it to Auth Format)\r
+ //\r
+ NeedConvertNormalToAuth = FALSE;\r
+ GuidHob = GetFirstGuidHob (VariableGuid);\r
+ if (GuidHob == NULL && VariableGuid == &gEfiAuthenticatedVariableGuid) {\r
+ //\r
+ // Try getting it from normal variable HOB\r
+ //\r
+ GuidHob = GetFirstGuidHob (&gEfiVariableGuid);\r
+ NeedConvertNormalToAuth = TRUE;\r
+ }\r
+ if (GuidHob != NULL) {\r
+ VariableStoreHeader = GET_GUID_HOB_DATA (GuidHob);\r
+ VariableStoreLength = GuidHob->Header.HobLength - sizeof (EFI_HOB_GUID_TYPE);\r
+ if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) {\r
+ if (!NeedConvertNormalToAuth) {\r
+ mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) AllocateRuntimeCopyPool ((UINTN) VariableStoreLength, (VOID *) VariableStoreHeader);\r
+ } else {\r
+ mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) ConvertNormalVarStorageToAuthVarStorage ((VOID *) VariableStoreHeader);\r
+ }\r
+ if (mVariableModuleGlobal->VariableGlobal.HobVariableBase == 0) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ } else {\r
+ DEBUG ((EFI_D_ERROR, "HOB Variable Store header is corrupted!\n"));\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
\r
/**\r
Initializes variable store area for non-volatile and volatile variable.\r
{\r
EFI_STATUS Status;\r
VARIABLE_STORE_HEADER *VolatileVariableStore;\r
- VARIABLE_STORE_HEADER *VariableStoreHeader;\r
- UINT64 VariableStoreLength;\r
UINTN ScratchSize;\r
- EFI_HOB_GUID_TYPE *GuidHob;\r
EFI_GUID *VariableGuid;\r
- EFI_FIRMWARE_VOLUME_HEADER *NvFvHeader;\r
\r
//\r
// Allocate runtime memory for variable driver global structure.\r
//\r
// Init non-volatile variable store.\r
//\r
- Status = InitNonVolatileVariableStore (&NvFvHeader);\r
+ Status = InitNonVolatileVariableStore ();\r
if (EFI_ERROR (Status)) {\r
FreePool (mVariableModuleGlobal);\r
return Status;\r
//\r
// Get HOB variable store.\r
//\r
- GuidHob = GetFirstGuidHob (VariableGuid);\r
- if (GuidHob != NULL) {\r
- VariableStoreHeader = GET_GUID_HOB_DATA (GuidHob);\r
- VariableStoreLength = (UINT64) (GuidHob->Header.HobLength - sizeof (EFI_HOB_GUID_TYPE));\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 (NvFvHeader);\r
- FreePool (mVariableModuleGlobal);\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
- } else {\r
- DEBUG ((EFI_D_ERROR, "HOB Variable Store header is corrupted!\n"));\r
+ Status = GetHobVariableStore (VariableGuid);\r
+ if (EFI_ERROR (Status)) {\r
+ if (mNvFvHeaderCache != NULL) {\r
+ FreePool (mNvFvHeaderCache);\r
}\r
+ FreePool (mVariableModuleGlobal);\r
+ return Status;\r
}\r
\r
+ mVariableModuleGlobal->MaxVolatileVariableSize = ((PcdGet32 (PcdMaxVolatileVariableSize) != 0) ?\r
+ PcdGet32 (PcdMaxVolatileVariableSize) :\r
+ mVariableModuleGlobal->MaxVariableSize\r
+ );\r
//\r
// Allocate memory for volatile variable store, note that there is a scratch space to store scratch data.\r
//\r
- ScratchSize = GetNonVolatileMaxVariableSize ();\r
+ ScratchSize = GetMaxVariableSize ();\r
mVariableModuleGlobal->ScratchBufferSize = ScratchSize;\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 (NvFvHeader);\r
+ if (mNvFvHeaderCache != NULL) {\r
+ FreePool (mNvFvHeaderCache);\r
+ }\r
FreePool (mVariableModuleGlobal);\r
return EFI_OUT_OF_RESOURCES;\r
}\r