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 - 2017, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>\r
(C) Copyright 2015-2018 Hewlett Packard Enterprise Development LP<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
+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
@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
)\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
CommonUserVariableTotalSize = 0;\r
HwErrVariableTotalSize = 0;\r
\r
- if (IsVolatile) {\r
+ if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) {\r
//\r
// Start Pointers for the 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 - (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
}\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
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
if (Variable->CurrPtr != NULL) {\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
}\r
}\r
\r
- State = Variable->CurrPtr->State;\r
+ State = CacheVariable->CurrPtr->State;\r
State &= VAR_DELETED;\r
\r
Status = UpdateVariableStore (\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
//\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 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
/**\r
- Init non-volatile variable store.\r
+ Init real non-volatile variable store.\r
\r
- @param[out] NvFvHeader Output pointer to non-volatile FV header address.\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
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
return EFI_VOLUME_CORRUPTED;\r
}\r
\r
- VariableStoreBase = (UINTN) FvHeader + 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
- mNvFvHeaderCache = FvHeader;\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
- mNvFvHeaderCache = NULL;\r
- mNvVariableCache = NULL;\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
}\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
EFI_STATUS Status;\r
UINTN Index;\r
UINT8 Data;\r
- EFI_PHYSICAL_ADDRESS VariableStoreBase;\r
- EFI_PHYSICAL_ADDRESS NvStorageBase;\r
VARIABLE_ENTRY_PROPERTY *VariableEntry;\r
\r
AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
\r
- NvStorageBase = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageVariableBase64);\r
- if (NvStorageBase == 0) {\r
- NvStorageBase = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);\r
- }\r
- VariableStoreBase = NvStorageBase + (mNvFvHeaderCache->HeaderLength);\r
-\r
- //\r
- // Let NonVolatileVariableBase point to flash variable store base directly after FTW ready.\r
- //\r
- mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;\r
-\r
//\r
// Check if the free area is really free.\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
{\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
- BOOLEAN IsNormalVariableHob;\r
\r
//\r
// Allocate runtime memory for variable driver global structure.\r
//\r
// Init non-volatile variable store.\r
//\r
- NvFvHeader = NULL;\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
- IsNormalVariableHob = 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
- IsNormalVariableHob = 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 (!IsNormalVariableHob) {\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
- 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
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