-/*++\r
-\r
-Copyright (c) 2006 - 2007, Intel Corporation\r
-All rights reserved. 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
-\r
-Module Name:\r
+/** @file\r
+ EFI Runtime Variable services.\r
+ \r
+ Copyright (c) 2006 - 2007, Intel Corporation \r
+ All rights reserved. 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
- Variable.c\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
\r
-Abstract:\r
+**/\r
\r
-Revision History\r
\r
---*/\r
+#include "Variable.h"\r
\r
\r
-#include "Variable.h"\r
-#include <Guid/FlashMapHob.h>\r
+VARIABLE_MODULE_GLOBAL mRuntimeData;\r
+VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal = &mRuntimeData;\r
+EFI_EVENT mVirtualAddressChangeEvent = NULL;\r
+EFI_HANDLE mHandle = NULL;\r
\r
-//\r
-// Don't use module globals after the SetVirtualAddress map is signaled\r
-//\r
-ESAL_VARIABLE_GLOBAL *mVariableModuleGlobal;\r
\r
//\r
// This is a temperary function which will be removed\r
// when EfiAcquireLock in UefiLib can handle the\r
// the call in UEFI Runtimer driver in RT phase.\r
//\r
-STATIC\r
VOID\r
AcquireLockOnlyAtBootTime (\r
IN EFI_LOCK *Lock\r
// when EfiAcquireLock in UefiLib can handle the\r
// the call in UEFI Runtimer driver in RT phase.\r
//\r
-STATIC\r
VOID\r
ReleaseLockOnlyAtBootTime (\r
IN EFI_LOCK *Lock\r
}\r
}\r
\r
-STATIC\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED VARIABLE_INFO_ENTRY *gVariableInfo = NULL;\r
+\r
+\r
+/**\r
+ Routine used to track statistical information about variable usage. \r
+ The data is stored in the EFI system table so it can be accessed later.\r
+ VariableInfo.efi can dump out the table. Only Boot Services variable \r
+ accesses are tracked by this code. The PcdVariableCollectStatistics\r
+ build flag controls if this feature is enabled. \r
+\r
+ A read that hits in the cache will have Read and Cache true for \r
+ the transaction. Data is allocated by this routine, but never\r
+ freed.\r
+\r
+ @param[in] VariableName Name of the Variable to track\r
+ @param[in] VendorGuid Guid of the Variable to track\r
+ @param[in] Volatile TRUE if volatile FALSE if non-volatile\r
+ @param[in] Read TRUE if GetVariable() was called\r
+ @param[in] Write TRUE if SetVariable() was called\r
+ @param[in] Delete TRUE if deleted via SetVariable()\r
+ @param[in] Cache TRUE for a cache hit.\r
+\r
+**/\r
+VOID\r
+UpdateVariableInfo (\r
+ IN CHAR16 *VariableName,\r
+ IN EFI_GUID *VendorGuid,\r
+ IN BOOLEAN Volatile,\r
+ IN BOOLEAN Read,\r
+ IN BOOLEAN Write,\r
+ IN BOOLEAN Delete,\r
+ IN BOOLEAN Cache\r
+ )\r
+{\r
+ VARIABLE_INFO_ENTRY *Entry;\r
+\r
+ if (FeaturePcdGet (PcdVariableCollectStatistics)) {\r
+\r
+ if (EfiAtRuntime ()) {\r
+ // Don't collect statistics at runtime\r
+ return;\r
+ }\r
+\r
+ if (gVariableInfo == NULL) {\r
+ //\r
+ // on the first call allocate a entry and place a pointer to it in\r
+ // the EFI System Table\r
+ //\r
+ gVariableInfo = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));\r
+ ASSERT (gVariableInfo != NULL);\r
+\r
+ CopyGuid (&gVariableInfo->VendorGuid, VendorGuid);\r
+ gVariableInfo->Name = AllocatePool (StrLen (VariableName));\r
+ StrCpy (gVariableInfo->Name, VariableName);\r
+ gVariableInfo->Volatile = Volatile;\r
+\r
+ gBS->InstallConfigurationTable (&gEfiVariableInfoGuid, gVariableInfo);\r
+ }\r
+\r
+ \r
+ for (Entry = gVariableInfo; Entry != NULL; Entry = Entry->Next) {\r
+ if (CompareGuid (VendorGuid, &Entry->VendorGuid)) {\r
+ if (StrCmp (VariableName, Entry->Name) == 0) {\r
+ if (Read) {\r
+ Entry->ReadCount++;\r
+ }\r
+ if (Write) {\r
+ Entry->WriteCount++;\r
+ }\r
+ if (Delete) {\r
+ Entry->DeleteCount++;\r
+ }\r
+ if (Cache) {\r
+ Entry->CacheCount++;\r
+ }\r
+\r
+ return;\r
+ }\r
+ }\r
+\r
+ if (Entry->Next == NULL) {\r
+ //\r
+ // If the entry is not in the table add it.\r
+ // Next iteration of the loop will fill in the data\r
+ //\r
+ Entry->Next = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));\r
+ ASSERT (Entry->Next != NULL);\r
+\r
+ CopyGuid (&Entry->Next->VendorGuid, VendorGuid);\r
+ Entry->Next->Name = AllocatePool (StrLen (VariableName));\r
+ StrCpy (Entry->Next->Name, VariableName);\r
+ Entry->Next->Volatile = Volatile;\r
+ }\r
+\r
+ }\r
+ }\r
+}\r
+\r
+\r
+\r
BOOLEAN\r
-EFIAPI\r
IsValidVariableHeader (\r
IN VARIABLE_HEADER *Variable\r
)\r
return TRUE;\r
}\r
\r
-STATIC\r
+\r
EFI_STATUS\r
-EFIAPI\r
UpdateVariableStore (\r
IN VARIABLE_GLOBAL *Global,\r
IN BOOLEAN Volatile,\r
\r
Arguments:\r
\r
- Global Pointer to VARAIBLE_GLOBAL structure\r
- Volatile If the Variable is Volatile or Non-Volatile\r
- SetByIndex TRUE: Target pointer is given as index\r
- FALSE: Target pointer is absolute\r
- Instance Instance of FV Block services\r
- DataPtrIndex Pointer to the Data from the end of VARIABLE_STORE_HEADER\r
- structure\r
- DataSize Size of data to be written.\r
- Buffer Pointer to the buffer from which data is written\r
+ Global - Pointer to VARAIBLE_GLOBAL structure\r
+ Volatile - If the Variable is Volatile or Non-Volatile\r
+ SetByIndex - TRUE: Target pointer is given as index\r
+ FALSE: Target pointer is absolute\r
+ Instance - Instance of FV Block services\r
+ DataPtrIndex - Pointer to the Data from the end of VARIABLE_STORE_HEADER\r
+ structure\r
+ DataSize - Size of data to be written.\r
+ Buffer - Pointer to the buffer from which data is written\r
\r
Returns:\r
\r
- EFI STATUS\r
+ EFI_INVALID_PARAMETER - Parameters not valid\r
+ EFI_SUCCESS - Variable store successfully updated\r
\r
--*/\r
{\r
// written\r
//\r
if (SetByIndex) {\r
- DataPtr += Global->NonVolatileVariableBase;\r
+ DataPtr += mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;\r
}\r
\r
if ((DataPtr + DataSize) >= ((EFI_PHYSICAL_ADDRESS) (UINTN) ((UINT8 *) FwVolHeader + FwVolHeader->FvLength))) {\r
// Data Pointer should point to the actual Address where data is to be\r
// written\r
//\r
- VolatileBase = (VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase);\r
+ VolatileBase = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);\r
if (SetByIndex) {\r
- DataPtr += Global->VolatileVariableBase;\r
+ DataPtr += mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;\r
}\r
\r
if ((DataPtr + DataSize) >= ((UINTN) ((UINT8 *) VolatileBase + VolatileBase->Size))) {\r
return EFI_INVALID_PARAMETER;\r
}\r
- }\r
- //\r
- // If Volatile Variable just do a simple mem copy.\r
- //\r
- if (Volatile) {\r
- CopyMem ((UINT8 *) ((UINTN) DataPtr), Buffer, DataSize);\r
+ \r
+ //\r
+ // If Volatile Variable just do a simple mem copy.\r
+ // \r
+ CopyMem ((UINT8 *)(UINTN)DataPtr, Buffer, DataSize);\r
return EFI_SUCCESS;\r
}\r
+ \r
//\r
// If we are here we are dealing with Non-Volatile Variables\r
//\r
&CurrWriteSize,\r
CurrBuffer\r
);\r
- if (EFI_ERROR (Status)) {\r
return Status;\r
- }\r
} else {\r
Size = (UINT32) (LinearOffset + PtrBlockMapEntry->Length - CurrWritePtr);\r
Status = EfiFvbWriteBlock (\r
return EFI_SUCCESS;\r
}\r
\r
-STATIC\r
+\r
VARIABLE_STORE_STATUS\r
-EFIAPI\r
GetVariableStoreStatus (\r
IN VARIABLE_STORE_HEADER *VarStoreHeader\r
)\r
}\r
}\r
\r
-STATIC\r
+\r
UINT8 *\r
-EFIAPI\r
GetVariableDataPtr (\r
IN VARIABLE_HEADER *Variable\r
)\r
return (UINT8 *) ((UINTN) GET_VARIABLE_NAME_PTR (Variable) + Variable->NameSize + GET_PAD_SIZE (Variable->NameSize));\r
}\r
\r
-STATIC\r
+\r
VARIABLE_HEADER *\r
-EFIAPI\r
GetNextVariablePtr (\r
IN VARIABLE_HEADER *Variable\r
)\r
return (VARIABLE_HEADER *) ((UINTN) GetVariableDataPtr (Variable) + Variable->DataSize + GET_PAD_SIZE (Variable->DataSize));\r
}\r
\r
-STATIC\r
+\r
VARIABLE_HEADER *\r
-EFIAPI\r
GetEndPointer (\r
IN VARIABLE_STORE_HEADER *VarStoreHeader\r
)\r
return (VARIABLE_HEADER *) ((UINTN) VarStoreHeader + VarStoreHeader->Size);\r
}\r
\r
-STATIC\r
+\r
EFI_STATUS\r
-EFIAPI\r
Reclaim (\r
IN EFI_PHYSICAL_ADDRESS VariableBase,\r
OUT UINTN *LastVariableOffset,\r
return Status;\r
}\r
\r
-STATIC\r
+\r
+//\r
+// The current Hii implementation accesses this variable a larg # of times on every boot.\r
+// Other common variables are only accessed a single time. This is why this cache algorithm\r
+// only targets a single variable. Probably to get an performance improvement out of\r
+// a Cache you would need a cache that improves the search performance for a variable.\r
+//\r
+VARIABLE_CACHE_ENTRY mVariableCache[] = {\r
+ {\r
+ &gEfiGlobalVariableGuid,\r
+ L"Lang",\r
+ 0x00000000,\r
+ 0x00,\r
+ NULL\r
+ }\r
+};\r
+\r
+\r
+/**\r
+ Update the Cache with Variable information. These are the same \r
+ arguments as the EFI Variable services.\r
+\r
+ @param[in] VariableName Name of variable\r
+ @param[in] VendorGuid Guid of variable\r
+ @param[in] Attribute Attribue of the variable\r
+ @param[in] DataSize Size of data. 0 means delete\r
+ @param[in] Data Variable data\r
+\r
+**/\r
+VOID\r
+UpdateVariableCache (\r
+ IN CHAR16 *VariableName,\r
+ IN EFI_GUID *VendorGuid,\r
+ IN UINT32 Attributes,\r
+ IN UINTN DataSize,\r
+ IN VOID *Data\r
+ )\r
+{\r
+ VARIABLE_CACHE_ENTRY *Entry;\r
+ UINTN Index;\r
+\r
+ if (EfiAtRuntime ()) {\r
+ // Don't use the cache at runtime\r
+ return;\r
+ }\r
+\r
+ for (Index = 0, Entry = mVariableCache; Index < sizeof (mVariableCache)/sizeof (VARIABLE_CACHE_ENTRY); Index++, Entry++) {\r
+ if (CompareGuid (VendorGuid, Entry->Guid)) {\r
+ if (StrCmp (VariableName, Entry->Name) == 0) { \r
+ Entry->Attributes = Attributes;\r
+ if (DataSize == 0) {\r
+ // Delete Case\r
+ if (Entry->DataSize != 0) {\r
+ FreePool (Entry->Data);\r
+ }\r
+ Entry->DataSize = DataSize;\r
+ } else if (DataSize == Entry->DataSize) {\r
+ CopyMem (Entry->Data, Data, DataSize);\r
+ } else {\r
+ Entry->Data = AllocatePool (DataSize);\r
+ Entry->DataSize = DataSize;\r
+ CopyMem (Entry->Data, Data, DataSize);\r
+ }\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Search the cache to see if the variable is in the cache.\r
+\r
+ @param[in] VariableName Name of variable\r
+ @param[in] VendorGuid Guid of variable\r
+ @param[in] Attribute Attribue returned \r
+ @param[in] DataSize Size of data returned\r
+ @param[in] Data Variable data returned\r
+\r
+ @retval EFI_SUCCESS VariableGuid & VariableName data was returned.\r
+ @retval other Not found.\r
+\r
+**/\r
+EFI_STATUS\r
+FindVariableInCache (\r
+ IN CHAR16 *VariableName,\r
+ IN EFI_GUID *VendorGuid,\r
+ OUT UINT32 *Attributes OPTIONAL,\r
+ IN OUT UINTN *DataSize,\r
+ OUT VOID *Data\r
+ )\r
+{\r
+ VARIABLE_CACHE_ENTRY *Entry;\r
+ UINTN Index;\r
+\r
+ if (EfiAtRuntime ()) {\r
+ // Don't use the cache at runtime\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ for (Index = 0, Entry = mVariableCache; Index < sizeof (mVariableCache)/sizeof (VARIABLE_CACHE_ENTRY); Index++, Entry++) {\r
+ if (CompareGuid (VendorGuid, Entry->Guid)) {\r
+ if (StrCmp (VariableName, Entry->Name) == 0) {\r
+ if (Entry->DataSize == 0) {\r
+ // Variable was deleted so return not found\r
+ return EFI_NOT_FOUND;\r
+ } else if (Entry->DataSize != *DataSize) {\r
+ // If the buffer is too small return correct size\r
+ *DataSize = Entry->DataSize;\r
+ return EFI_BUFFER_TOO_SMALL;\r
+ } else {\r
+ // Return the data\r
+ CopyMem (Data, Entry->Data, Entry->DataSize);\r
+ if (Attributes != NULL) {\r
+ *Attributes = Entry->Attributes;\r
+ }\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ \r
+ return EFI_NOT_FOUND;\r
+}\r
+\r
+\r
EFI_STATUS\r
-EFIAPI\r
FindVariable (\r
IN CHAR16 *VariableName,\r
IN EFI_GUID *VendorGuid,\r
// SetVariable all call FindVariable at entry point. Please move "Aquire Lock" to\r
// the correct places if this assumption does not hold TRUE anymore.\r
//\r
- AcquireLockOnlyAtBootTime(&Global->VariableServicesLock);\r
+ AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
\r
//\r
- // 0: Non-Volatile, 1: Volatile\r
+ // 0: Volatile, 1: Non-Volatile\r
//\r
- VariableStoreHeader[0] = (VARIABLE_STORE_HEADER *) ((UINTN) Global->NonVolatileVariableBase);\r
- VariableStoreHeader[1] = (VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase);\r
+ VariableStoreHeader[0] = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);\r
+ VariableStoreHeader[1] = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);\r
\r
//\r
// Start Pointers for the variable.\r
return EFI_INVALID_PARAMETER;\r
}\r
//\r
- // Find the variable by walk through non-volatile and volatile variable store\r
+ // Find the variable by walk through volatile and then non-volatile variable store\r
//\r
for (Index = 0; Index < 2; Index++) {\r
PtrTrack->StartPtr = (VARIABLE_HEADER *) (VariableStoreHeader[Index] + 1);\r
\r
while (IsValidVariableHeader (Variable[Index]) && (Variable[Index] <= GetEndPointer (VariableStoreHeader[Index]))) {\r
if (Variable[Index]->State == VAR_ADDED) {\r
- if (!(EfiAtRuntime () && !(Variable[Index]->Attributes & EFI_VARIABLE_RUNTIME_ACCESS))) {\r
+ if (!EfiAtRuntime () || (Variable[Index]->Attributes & EFI_VARIABLE_RUNTIME_ACCESS)) {\r
if (VariableName[0] == 0) {\r
PtrTrack->CurrPtr = Variable[Index];\r
- PtrTrack->Volatile = (BOOLEAN) Index;\r
+ PtrTrack->Volatile = (BOOLEAN)(Index == 0);\r
return EFI_SUCCESS;\r
} else {\r
if (CompareGuid (VendorGuid, &Variable[Index]->VendorGuid)) {\r
if (!CompareMem (VariableName, GET_VARIABLE_NAME_PTR (Variable[Index]), Variable[Index]->NameSize)) {\r
PtrTrack->CurrPtr = Variable[Index];\r
- PtrTrack->Volatile = (BOOLEAN) Index;\r
+ PtrTrack->Volatile = (BOOLEAN)(Index == 0);\r
return EFI_SUCCESS;\r
}\r
}\r
\r
Variable[Index] = GetNextVariablePtr (Variable[Index]);\r
}\r
- //\r
- // While (...)\r
- //\r
}\r
- //\r
- // for (...)\r
- //\r
PtrTrack->CurrPtr = NULL;\r
return EFI_NOT_FOUND;\r
}\r
\r
-EFI_STATUS\r
-EFIAPI\r
-GetVariable (\r
- IN CHAR16 *VariableName,\r
- IN EFI_GUID * VendorGuid,\r
- OUT UINT32 *Attributes OPTIONAL,\r
- IN OUT UINTN *DataSize,\r
- OUT VOID *Data,\r
- IN VARIABLE_GLOBAL * Global,\r
- IN UINT32 Instance\r
- )\r
+\r
+\r
/*++\r
\r
Routine Description:\r
\r
Arguments:\r
\r
- VariableName Name of Variable to be found\r
- VendorGuid Variable vendor GUID\r
- Attributes OPTIONAL Attribute value of the variable found\r
- DataSize Size of Data found. If size is less than the\r
- data, this value contains the required size.\r
- Data Data pointer\r
- Global Pointer to VARIABLE_GLOBAL structure\r
- Instance Instance of the Firmware Volume.\r
+ VariableName Name of Variable to be found\r
+ VendorGuid Variable vendor GUID\r
+ Attributes OPTIONAL Attribute value of the variable found\r
+ DataSize Size of Data found. If size is less than the\r
+ data, this value contains the required size.\r
+ Data Data pointer\r
+ Global Pointer to VARIABLE_GLOBAL structure\r
+ Instance Instance of the Firmware Volume.\r
\r
Returns:\r
\r
- EFI STATUS\r
+ EFI_INVALID_PARAMETER - Invalid parameter\r
+ EFI_SUCCESS - Find the specified variable\r
+ EFI_NOT_FOUND - Not found\r
+ EFI_BUFFER_TO_SMALL - DataSize is too small for the result\r
+\r
\r
--*/\r
+EFI_STATUS\r
+EFIAPI\r
+RuntimeServiceGetVariable (\r
+ IN CHAR16 *VariableName,\r
+ IN EFI_GUID *VendorGuid,\r
+ OUT UINT32 *Attributes OPTIONAL,\r
+ IN OUT UINTN *DataSize,\r
+ OUT VOID *Data\r
+ )\r
{\r
+ EFI_STATUS Status;\r
VARIABLE_POINTER_TRACK Variable;\r
UINTN VarDataSize;\r
- EFI_STATUS Status;\r
\r
if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {\r
return EFI_INVALID_PARAMETER;\r
}\r
+\r
//\r
// Find existing variable\r
//\r
- Status = FindVariable (VariableName, VendorGuid, &Variable, Global);\r
-\r
+ Status = FindVariableInCache (VariableName, VendorGuid, Attributes, DataSize, Data);\r
+ if ((Status == EFI_BUFFER_TOO_SMALL) || (Status == EFI_SUCCESS)){\r
+ // Hit in the Cache\r
+ UpdateVariableInfo (VariableName, VendorGuid, FALSE, TRUE, FALSE, FALSE, TRUE);\r
+ return Status;\r
+ }\r
+ \r
+ Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);\r
if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {\r
goto Done;\r
}\r
+\r
//\r
// Get data size\r
//\r
}\r
\r
*DataSize = VarDataSize;\r
+ UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, TRUE, FALSE, FALSE, FALSE);\r
+ UpdateVariableCache (VariableName, VendorGuid, Variable.CurrPtr->Attributes, VarDataSize, Data);\r
+ \r
Status = EFI_SUCCESS;\r
goto Done;\r
} else {\r
}\r
\r
Done:\r
- ReleaseLockOnlyAtBootTime (&Global->VariableServicesLock);\r
+ ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
return Status;\r
}\r
\r
-EFI_STATUS\r
-EFIAPI\r
-GetNextVariableName (\r
- IN OUT UINTN *VariableNameSize,\r
- IN OUT CHAR16 *VariableName,\r
- IN OUT EFI_GUID *VendorGuid,\r
- IN VARIABLE_GLOBAL *Global,\r
- IN UINT32 Instance\r
- )\r
+\r
+\r
/*++\r
\r
Routine Description:\r
EFI STATUS\r
\r
--*/\r
+EFI_STATUS\r
+EFIAPI\r
+RuntimeServiceGetNextVariableName (\r
+ IN OUT UINTN *VariableNameSize,\r
+ IN OUT CHAR16 *VariableName,\r
+ IN OUT EFI_GUID *VendorGuid\r
+ )\r
{\r
VARIABLE_POINTER_TRACK Variable;\r
UINTN VarNameSize;\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
- Status = FindVariable (VariableName, VendorGuid, &Variable, Global);\r
-\r
+ Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);\r
if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {\r
goto Done;\r
}\r
if (Variable.CurrPtr >= Variable.EndPtr || Variable.CurrPtr == NULL) {\r
Variable.Volatile = (BOOLEAN) (Variable.Volatile ^ ((BOOLEAN) 0x1));\r
if (Variable.Volatile) {\r
- Variable.StartPtr = (VARIABLE_HEADER *) ((UINTN) (Global->VolatileVariableBase + sizeof (VARIABLE_STORE_HEADER)));\r
- Variable.EndPtr = (VARIABLE_HEADER *) GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase));\r
+ Variable.StartPtr = (VARIABLE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase + sizeof (VARIABLE_STORE_HEADER)));\r
+ Variable.EndPtr = (VARIABLE_HEADER *) GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase));\r
} else {\r
Status = EFI_NOT_FOUND;\r
goto Done;\r
}\r
\r
Done:\r
- ReleaseLockOnlyAtBootTime (&Global->VariableServicesLock);\r
+ ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
return Status;\r
}\r
\r
-EFI_STATUS\r
-EFIAPI\r
-SetVariable (\r
- IN CHAR16 *VariableName,\r
- IN EFI_GUID *VendorGuid,\r
- IN UINT32 Attributes,\r
- IN UINTN DataSize,\r
- IN VOID *Data,\r
- IN VARIABLE_GLOBAL *Global,\r
- IN UINTN *VolatileOffset,\r
- IN UINTN *NonVolatileOffset,\r
- IN UINT32 Instance\r
- )\r
+\r
/*++\r
\r
Routine Description:\r
\r
Returns:\r
\r
- EFI STATUS\r
EFI_INVALID_PARAMETER - Invalid parameter\r
EFI_SUCCESS - Set successfully\r
EFI_OUT_OF_RESOURCES - Resource not enough to set variable\r
EFI_NOT_FOUND - Not found\r
+ EFI_DEVICE_ERROR - Variable can not be saved due to hardware failure\r
+ EFI_WRITE_PROTECTED - Variable is read-only\r
\r
--*/\r
+EFI_STATUS\r
+EFIAPI\r
+RuntimeServiceSetVariable (\r
+ IN CHAR16 *VariableName,\r
+ IN EFI_GUID *VendorGuid,\r
+ IN UINT32 Attributes,\r
+ IN UINTN DataSize,\r
+ IN VOID *Data\r
+ )\r
{\r
VARIABLE_POINTER_TRACK Variable;\r
EFI_STATUS Status;\r
UINTN VarSize;\r
UINT8 State;\r
BOOLEAN Reclaimed;\r
+ UINTN *VolatileOffset;\r
+ UINTN *NonVolatileOffset;\r
+ UINT32 Instance;\r
+ BOOLEAN Volatile;\r
\r
- Reclaimed = FALSE;\r
+ Reclaimed = FALSE;\r
+ VolatileOffset = &mVariableModuleGlobal->VolatileLastVariableOffset;\r
+ NonVolatileOffset = &mVariableModuleGlobal->NonVolatileLastVariableOffset;\r
+ Instance = mVariableModuleGlobal->FvbInstance;\r
\r
+ //\r
+ // Check input parameters\r
+ //\r
if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {\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
}\r
-\r
- Status = FindVariable (VariableName, VendorGuid, &Variable, Global);\r
-\r
- if (Status == EFI_INVALID_PARAMETER) {\r
- goto Done;\r
- } else if (!EFI_ERROR (Status) && Variable.Volatile && EfiAtRuntime()) {\r
+ //\r
+ // The size of the VariableName, including the Unicode Null in bytes plus\r
+ // the DataSize is limited to maximum size of MAX_HARDWARE_ERROR_VARIABLE_SIZE (32K)\r
+ // bytes for HwErrRec, and MAX_VARIABLE_SIZE (1024) bytes for the others.\r
+ //\r
+ if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
+ if ((DataSize > MAX_HARDWARE_ERROR_VARIABLE_SIZE) || \r
+ (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > MAX_HARDWARE_ERROR_VARIABLE_SIZE)) {\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_VARIABLE_SIZE (1024) bytes.\r
+ //\r
+ if ((DataSize > MAX_VARIABLE_SIZE) ||\r
+ (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > MAX_VARIABLE_SIZE)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ } \r
+ } \r
+ //\r
+ // Check whether the input variable is already existed\r
+ //\r
+ \r
+ Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);\r
+ if (Status == EFI_SUCCESS && Variable.CurrPtr != NULL) {\r
//\r
- // If EfiAtRuntime and the variable is Volatile and Runtime Access,\r
- // the volatile is ReadOnly, and SetVariable should be aborted and\r
- // return EFI_WRITE_PROTECTED.\r
+ // Update/Delete existing variable\r
//\r
- Status = EFI_WRITE_PROTECTED;\r
- goto Done;\r
- } else if (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > MAX_VARIABLE_SIZE) {\r
+ Volatile = Variable.Volatile;\r
+ \r
+ if (EfiAtRuntime ()) { \r
+ //\r
+ // If EfiAtRuntime and the variable is Volatile and Runtime Access, \r
+ // the volatile is ReadOnly, and SetVariable should be aborted and \r
+ // return EFI_WRITE_PROTECTED.\r
+ //\r
+ if (Variable.Volatile) {\r
+ Status = EFI_WRITE_PROTECTED;\r
+ goto Done;\r
+ }\r
+ //\r
+ // Only variable have NV attribute can be updated/deleted in Runtime\r
+ //\r
+ if (!(Variable.CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE)) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto Done; \r
+ }\r
+ }\r
//\r
- // The size of the VariableName, including the Unicode Null in bytes plus\r
- // the DataSize is limited to maximum size of MAX_VARIABLE_SIZE (1024) bytes.\r
+ // Setting a data variable with no access, or zero DataSize attributes\r
+ // specified causes it to be deleted.\r
//\r
- Status = EFI_INVALID_PARAMETER;\r
- goto Done;\r
- } else if (Attributes == EFI_VARIABLE_NON_VOLATILE) {\r
+ if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) { \r
+ State = Variable.CurrPtr->State;\r
+ State &= VAR_DELETED;\r
+\r
+ Status = UpdateVariableStore (\r
+ &mVariableModuleGlobal->VariableGlobal,\r
+ Variable.Volatile,\r
+ FALSE,\r
+ Instance,\r
+ (UINTN) &Variable.CurrPtr->State,\r
+ sizeof (UINT8),\r
+ &State\r
+ ); \r
+ if (!EFI_ERROR (Status)) {\r
+ UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, FALSE, TRUE, FALSE);\r
+ UpdateVariableCache (VariableName, VendorGuid, Attributes, DataSize, Data);\r
+ }\r
+ goto Done; \r
+ }\r
//\r
- // Make sure not only EFI_VARIABLE_NON_VOLATILE is set\r
+ // If the variable is marked valid and the same data has been passed in\r
+ // then return to the caller immediately.\r
//\r
- Status = EFI_INVALID_PARAMETER;\r
- goto Done;\r
- } else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) ==\r
- EFI_VARIABLE_RUNTIME_ACCESS) {\r
+ if (Variable.CurrPtr->DataSize == DataSize &&\r
+ (CompareMem (Data, GetVariableDataPtr (Variable.CurrPtr), DataSize) == 0)) {\r
+ \r
+ UpdateVariableInfo (VariableName, VendorGuid, 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
+ //\r
+ // Mark the old variable as in delete transition\r
+ //\r
+ State = Variable.CurrPtr->State;\r
+ State &= VAR_IN_DELETED_TRANSITION;\r
+\r
+ Status = UpdateVariableStore (\r
+ &mVariableModuleGlobal->VariableGlobal,\r
+ Variable.Volatile,\r
+ FALSE,\r
+ Instance,\r
+ (UINTN) &Variable.CurrPtr->State,\r
+ sizeof (UINT8),\r
+ &State\r
+ ); \r
+ if (EFI_ERROR (Status)) {\r
+ goto Done; \r
+ } \r
+ } \r
+ } else if (Status == EFI_NOT_FOUND) {\r
//\r
- // Make sure if runtime bit is set, boot service bit is set also\r
+ // Create a new variable\r
+ // \r
+ \r
//\r
- Status = EFI_INVALID_PARAMETER;\r
- goto Done;\r
- } else if (EfiAtRuntime () && Attributes && !(Attributes & EFI_VARIABLE_RUNTIME_ACCESS)) {\r
+ // Make sure we are trying to create a new variable.\r
+ // Setting a data variable with no access, or zero DataSize attributes means to delete it. \r
//\r
- // Runtime but Attribute is not Runtime\r
+ if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {\r
+ Status = EFI_NOT_FOUND;\r
+ goto Done;\r
+ }\r
+ \r
//\r
- Status = EFI_INVALID_PARAMETER;\r
- goto Done;\r
- } else if (EfiAtRuntime () && Attributes && !(Attributes & EFI_VARIABLE_NON_VOLATILE)) {\r
+ // Only variable have NV|RT attribute can be created in Runtime\r
//\r
- // Cannot set volatile variable in Runtime\r
+ if (EfiAtRuntime () &&\r
+ (!(Attributes & EFI_VARIABLE_RUNTIME_ACCESS) || !(Attributes & EFI_VARIABLE_NON_VOLATILE))) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto Done;\r
+ } \r
+ } else {\r
+ //\r
+ // Status should be EFI_INVALID_PARAMETER here according to return status of FindVariable().\r
//\r
- Status = EFI_INVALID_PARAMETER;\r
+ ASSERT (Status == EFI_INVALID_PARAMETER);\r
goto Done;\r
- } else if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {\r
+ }\r
+\r
+ //\r
+ // Function part - create a new variable and copy the data.\r
+ // Both update a variable and create a variable will come here.\r
+ //\r
+ // Tricky part: Use scratch data area at the end of volatile variable store\r
+ // as a temporary storage.\r
+ //\r
+ NextVariable = GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase));\r
+\r
+ SetMem (NextVariable, SCRATCH_SIZE, 0xff);\r
+\r
+ NextVariable->StartId = VARIABLE_DATA;\r
+ NextVariable->Attributes = Attributes;\r
+ //\r
+ // NextVariable->State = VAR_ADDED;\r
+ //\r
+ NextVariable->Reserved = 0;\r
+ VarNameOffset = sizeof (VARIABLE_HEADER);\r
+ VarNameSize = StrSize (VariableName);\r
+ CopyMem (\r
+ (UINT8 *) ((UINTN) NextVariable + VarNameOffset),\r
+ VariableName,\r
+ VarNameSize\r
+ );\r
+ VarDataOffset = VarNameOffset + VarNameSize + GET_PAD_SIZE (VarNameSize);\r
+ CopyMem (\r
+ (UINT8 *) ((UINTN) NextVariable + VarDataOffset),\r
+ Data,\r
+ DataSize\r
+ );\r
+ CopyMem (&NextVariable->VendorGuid, VendorGuid, sizeof (EFI_GUID));\r
+ //\r
+ // There will be pad bytes after Data, the NextVariable->NameSize and\r
+ // NextVariable->DataSize should not include pad size so that variable\r
+ // service can get actual size in GetVariable\r
+ //\r
+ NextVariable->NameSize = (UINT32)VarNameSize;\r
+ NextVariable->DataSize = (UINT32)DataSize;\r
+\r
+ //\r
+ // The actual size of the variable that stores in storage should\r
+ // include pad size.\r
+ //\r
+ VarSize = VarDataOffset + DataSize + GET_PAD_SIZE (DataSize);\r
+ if (Attributes & EFI_VARIABLE_NON_VOLATILE) {\r
//\r
- // Setting a data variable with no access, or zero DataSize attributes\r
- // specified causes it to be deleted.\r
+ // Create a nonvolatile variable\r
//\r
- if (!EFI_ERROR (Status)) {\r
- State = Variable.CurrPtr->State;\r
- State &= VAR_DELETED;\r
-\r
- Status = UpdateVariableStore (\r
- Global,\r
- Variable.Volatile,\r
- FALSE,\r
- Instance,\r
- (UINTN) &Variable.CurrPtr->State,\r
- sizeof (UINT8),\r
- &State\r
- );\r
+ Volatile = FALSE;\r
+ \r
+ if ((UINT32) (VarSize +*NonVolatileOffset) >\r
+ ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase)))->Size\r
+ ) {\r
+ if (EfiAtRuntime ()) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Done;\r
+ }\r
+ //\r
+ // Perform garbage collection & reclaim operation\r
+ //\r
+ Status = Reclaim (mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase, NonVolatileOffset, FALSE);\r
if (EFI_ERROR (Status)) {\r
goto Done;\r
}\r
-\r
- Status = EFI_SUCCESS;\r
- goto Done;\r
- }\r
-\r
- Status = EFI_NOT_FOUND;\r
- goto Done;\r
- } else {\r
- if (!EFI_ERROR (Status)) {\r
//\r
- // If the variable is marked valid and the same data has been passed in\r
- // then return to the caller immediately.\r
+ // If still no enough space, return out of resources\r
//\r
- if (Variable.CurrPtr->DataSize == DataSize &&\r
- !CompareMem (Data, GetVariableDataPtr (Variable.CurrPtr), DataSize)\r
+ if ((UINT32) (VarSize +*NonVolatileOffset) >\r
+ ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase)))->Size\r
) {\r
- Status = EFI_SUCCESS;\r
+ Status = EFI_OUT_OF_RESOURCES;\r
goto Done;\r
- } else if (Variable.CurrPtr->State == VAR_ADDED) {\r
- //\r
- // Mark the old variable as in delete transition\r
- //\r
- State = Variable.CurrPtr->State;\r
- State &= VAR_IN_DELETED_TRANSITION;\r
-\r
- Status = UpdateVariableStore (\r
- Global,\r
- Variable.Volatile,\r
- FALSE,\r
- Instance,\r
- (UINTN) &Variable.CurrPtr->State,\r
- sizeof (UINT8),\r
- &State\r
- );\r
- if (EFI_ERROR (Status)) {\r
- goto Done;\r
- }\r
}\r
+ \r
+ Reclaimed = TRUE;\r
}\r
//\r
- // Create a new variable and copy the data.\r
+ // Three steps\r
+ // 1. Write variable header\r
+ // 2. Write variable data\r
+ // 3. Set variable state to valid\r
//\r
- // Tricky part: Use scratch data area at the end of volatile variable store\r
- // as a temporary storage.\r
//\r
- NextVariable = GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase));\r
-\r
- SetMem (NextVariable, SCRATCH_SIZE, 0xff);\r
-\r
- NextVariable->StartId = VARIABLE_DATA;\r
- NextVariable->Attributes = Attributes;\r
+ // Step 1:\r
//\r
- // NextVariable->State = VAR_ADDED;\r
- //\r
- NextVariable->Reserved = 0;\r
- VarNameOffset = sizeof (VARIABLE_HEADER);\r
- VarNameSize = StrSize (VariableName);\r
- CopyMem (\r
- (UINT8 *) ((UINTN) NextVariable + VarNameOffset),\r
- VariableName,\r
- VarNameSize\r
- );\r
- VarDataOffset = VarNameOffset + VarNameSize + GET_PAD_SIZE (VarNameSize);\r
- CopyMem (\r
- (UINT8 *) ((UINTN) NextVariable + VarDataOffset),\r
- Data,\r
- DataSize\r
- );\r
- CopyMem (&NextVariable->VendorGuid, VendorGuid, sizeof (EFI_GUID));\r
+ Status = UpdateVariableStore (\r
+ &mVariableModuleGlobal->VariableGlobal,\r
+ FALSE,\r
+ TRUE,\r
+ Instance,\r
+ *NonVolatileOffset,\r
+ sizeof (VARIABLE_HEADER),\r
+ (UINT8 *) NextVariable\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
//\r
- // There will be pad bytes after Data, the NextVariable->NameSize and\r
- // NextVariable->DataSize should not include pad size so that variable\r
- // service can get actual size in GetVariable\r
+ // Step 2:\r
//\r
- NextVariable->NameSize = (UINT32)VarNameSize;\r
- NextVariable->DataSize = (UINT32)DataSize;\r
+ Status = UpdateVariableStore (\r
+ &mVariableModuleGlobal->VariableGlobal,\r
+ FALSE,\r
+ TRUE,\r
+ Instance,\r
+ *NonVolatileOffset + sizeof (VARIABLE_HEADER),\r
+ (UINT32) VarSize - sizeof (VARIABLE_HEADER),\r
+ (UINT8 *) NextVariable + sizeof (VARIABLE_HEADER)\r
+ );\r
\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
//\r
- // The actual size of the variable that stores in storage should\r
- // include pad size.\r
+ // Step 3:\r
//\r
- VarSize = VarDataOffset + DataSize + GET_PAD_SIZE (DataSize);\r
- if (Attributes & EFI_VARIABLE_NON_VOLATILE) {\r
- if ((UINT32) (VarSize +*NonVolatileOffset) >\r
- ((VARIABLE_STORE_HEADER *) ((UINTN) (Global->NonVolatileVariableBase)))->Size\r
- ) {\r
- if (EfiAtRuntime ()) {\r
- Status = EFI_OUT_OF_RESOURCES;\r
- goto Done;\r
- }\r
- //\r
- // Perform garbage collection & reclaim operation\r
- //\r
- Status = Reclaim (Global->NonVolatileVariableBase, NonVolatileOffset, FALSE);\r
- if (EFI_ERROR (Status)) {\r
- goto Done;\r
- }\r
- //\r
- // If still no enough space, return out of resources\r
- //\r
- if ((UINT32) (VarSize +*NonVolatileOffset) >\r
- ((VARIABLE_STORE_HEADER *) ((UINTN) (Global->NonVolatileVariableBase)))->Size\r
- ) {\r
- Status = EFI_OUT_OF_RESOURCES;\r
- goto Done;\r
- }\r
+ NextVariable->State = VAR_ADDED;\r
+ Status = UpdateVariableStore (\r
+ &mVariableModuleGlobal->VariableGlobal,\r
+ FALSE,\r
+ TRUE,\r
+ Instance,\r
+ *NonVolatileOffset,\r
+ sizeof (VARIABLE_HEADER),\r
+ (UINT8 *) NextVariable\r
+ );\r
\r
- Reclaimed = TRUE;\r
- }\r
- //\r
- // Three steps\r
- // 1. Write variable header\r
- // 2. Write variable data\r
- // 3. Set variable state to valid\r
- //\r
- //\r
- // Step 1:\r
- //\r
- Status = UpdateVariableStore (\r
- Global,\r
- FALSE,\r
- TRUE,\r
- Instance,\r
- *NonVolatileOffset,\r
- sizeof (VARIABLE_HEADER),\r
- (UINT8 *) NextVariable\r
- );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
\r
- if (EFI_ERROR (Status)) {\r
- goto Done;\r
- }\r
+ *NonVolatileOffset = *NonVolatileOffset + VarSize;\r
+\r
+ } else {\r
+ //\r
+ // Create a volatile variable\r
+ // \r
+ Volatile = TRUE;\r
+\r
+ if ((UINT32) (VarSize +*VolatileOffset) >\r
+ ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase)))->Size) {\r
//\r
- // Step 2:\r
+ // Perform garbage collection & reclaim operation\r
//\r
- Status = UpdateVariableStore (\r
- Global,\r
- FALSE,\r
- TRUE,\r
- Instance,\r
- *NonVolatileOffset + sizeof (VARIABLE_HEADER),\r
- (UINT32) VarSize - sizeof (VARIABLE_HEADER),\r
- (UINT8 *) NextVariable + sizeof (VARIABLE_HEADER)\r
- );\r
-\r
+ Status = Reclaim (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase, VolatileOffset, TRUE);\r
if (EFI_ERROR (Status)) {\r
goto Done;\r
}\r
//\r
- // Step 3:\r
+ // If still no enough space, return out of resources\r
//\r
- NextVariable->State = VAR_ADDED;\r
- Status = UpdateVariableStore (\r
- Global,\r
- FALSE,\r
- TRUE,\r
- Instance,\r
- *NonVolatileOffset,\r
- sizeof (VARIABLE_HEADER),\r
- (UINT8 *) NextVariable\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- goto Done;\r
- }\r
-\r
- *NonVolatileOffset = *NonVolatileOffset + VarSize;\r
-\r
- } else {\r
- if (EfiAtRuntime ()) {\r
- Status = EFI_INVALID_PARAMETER;\r
- goto Done;\r
- }\r
-\r
if ((UINT32) (VarSize +*VolatileOffset) >\r
- ((VARIABLE_STORE_HEADER *) ((UINTN) (Global->VolatileVariableBase)))->Size\r
+ ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase)))->Size\r
) {\r
- //\r
- // Perform garbage collection & reclaim operation\r
- //\r
- Status = Reclaim (Global->VolatileVariableBase, VolatileOffset, TRUE);\r
- if (EFI_ERROR (Status)) {\r
- goto Done;\r
- }\r
- //\r
- // If still no enough space, return out of resources\r
- //\r
- if ((UINT32) (VarSize +*VolatileOffset) >\r
- ((VARIABLE_STORE_HEADER *) ((UINTN) (Global->VolatileVariableBase)))->Size\r
- ) {\r
- Status = EFI_OUT_OF_RESOURCES;\r
- goto Done;\r
- }\r
-\r
- Reclaimed = TRUE;\r
- }\r
-\r
- NextVariable->State = VAR_ADDED;\r
- Status = UpdateVariableStore (\r
- Global,\r
- TRUE,\r
- TRUE,\r
- Instance,\r
- *VolatileOffset,\r
- (UINT32) VarSize,\r
- (UINT8 *) NextVariable\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
goto Done;\r
}\r
-\r
- *VolatileOffset = *VolatileOffset + VarSize;\r
+ \r
+ Reclaimed = TRUE;\r
}\r
- //\r
- // Mark the old variable as deleted\r
- //\r
- if (!Reclaimed && !EFI_ERROR (Status) && Variable.CurrPtr != NULL) {\r
- State = Variable.CurrPtr->State;\r
- State &= VAR_DELETED;\r
\r
- Status = UpdateVariableStore (\r
- Global,\r
- Variable.Volatile,\r
- FALSE,\r
- Instance,\r
- (UINTN) &Variable.CurrPtr->State,\r
- sizeof (UINT8),\r
- &State\r
- );\r
+ NextVariable->State = VAR_ADDED;\r
+ Status = UpdateVariableStore (\r
+ &mVariableModuleGlobal->VariableGlobal,\r
+ TRUE,\r
+ TRUE,\r
+ Instance,\r
+ *VolatileOffset,\r
+ (UINT32) VarSize,\r
+ (UINT8 *) NextVariable\r
+ );\r
\r
- if (EFI_ERROR (Status)) {\r
- goto Done;\r
- }\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ *VolatileOffset = *VolatileOffset + VarSize;\r
+ }\r
+ //\r
+ // Mark the old variable as deleted\r
+ //\r
+ if (!Reclaimed && !EFI_ERROR (Status) && Variable.CurrPtr != NULL) {\r
+ State = Variable.CurrPtr->State;\r
+ State &= VAR_DELETED;\r
+\r
+ Status = UpdateVariableStore (\r
+ &mVariableModuleGlobal->VariableGlobal,\r
+ Variable.Volatile,\r
+ FALSE,\r
+ Instance,\r
+ (UINTN) &Variable.CurrPtr->State,\r
+ sizeof (UINT8),\r
+ &State\r
+ );\r
+ \r
+ if (!EFI_ERROR (Status)) {\r
+ UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE);\r
+ UpdateVariableCache (VariableName, VendorGuid, Attributes, DataSize, Data);\r
}\r
+ goto Done; \r
}\r
\r
Status = EFI_SUCCESS;\r
+ UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE);\r
+ UpdateVariableCache (VariableName, VendorGuid, Attributes, DataSize, Data);\r
+\r
Done:\r
- ReleaseLockOnlyAtBootTime (&Global->VariableServicesLock);\r
+ ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
return Status;\r
}\r
\r
-EFI_STATUS\r
-EFIAPI\r
-QueryVariableInfo (\r
- IN UINT32 Attributes,\r
- OUT UINT64 *MaximumVariableStorageSize,\r
- OUT UINT64 *RemainingVariableStorageSize,\r
- OUT UINT64 *MaximumVariableSize,\r
- IN VARIABLE_GLOBAL *Global,\r
- IN UINT32 Instance\r
- )\r
+\r
/*++\r
\r
Routine Description:\r
MaximumVariableStorageSize Pointer to the maximum size of the storage space available\r
for the EFI variables associated with the attributes specified.\r
RemainingVariableStorageSize Pointer to the remaining size of the storage space available\r
- for the EFI variables associated with the attributes specified.\r
- MaximumVariableSize Pointer to the maximum size of the individual EFI variables\r
+ for EFI variables associated with the attributes specified.\r
+ MaximumVariableSize Pointer to the maximum size of an individual EFI variables\r
associated with the attributes specified.\r
Global Pointer to VARIABLE_GLOBAL structure.\r
Instance Instance of the Firmware Volume.\r
EFI_UNSUPPORTED - The attribute is not supported on this platform.\r
\r
--*/\r
+EFI_STATUS\r
+EFIAPI\r
+RuntimeServiceQueryVariableInfo (\r
+ IN UINT32 Attributes,\r
+ OUT UINT64 *MaximumVariableStorageSize,\r
+ OUT UINT64 *RemainingVariableStorageSize,\r
+ OUT UINT64 *MaximumVariableSize\r
+ )\r
{\r
VARIABLE_HEADER *Variable;\r
VARIABLE_HEADER *NextVariable;\r
UINT64 VariableSize;\r
VARIABLE_STORE_HEADER *VariableStoreHeader;\r
\r
- if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL) {\r
+ if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {\r
return EFI_INVALID_PARAMETER;\r
}\r
-\r
- if((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS)) == 0) {\r
+ \r
+ if((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == 0) {\r
//\r
// Make sure the Attributes combination is supported by the platform.\r
//\r
- return EFI_UNSUPPORTED;\r
+ return EFI_UNSUPPORTED; \r
} else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {\r
//\r
// Make sure if runtime bit is set, boot service bit is set also.\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
- AcquireLockOnlyAtBootTime(&Global->VariableServicesLock);\r
+ AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
\r
if((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
//\r
// Query is Volatile related.\r
//\r
- VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase);\r
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);\r
} else {\r
//\r
// Query is Non-Volatile related.\r
//\r
- VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) Global->NonVolatileVariableBase);\r
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);\r
}\r
\r
//\r
*RemainingVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);\r
\r
//\r
- // Let *MaximumVariableSize be MAX_VARIABLE_SIZE.\r
+ // Let *MaximumVariableSize be MAX_VARIABLE_SIZE with the exception of the variable header size.\r
+ //\r
+ *MaximumVariableSize = MAX_VARIABLE_SIZE - sizeof (VARIABLE_HEADER);\r
+\r
+ //\r
+ // Harware error record variable needs larger size.\r
//\r
- *MaximumVariableSize = MAX_VARIABLE_SIZE;\r
+ if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
+ *MaximumVariableSize = MAX_HARDWARE_ERROR_VARIABLE_SIZE - sizeof (VARIABLE_HEADER);\r
+ }\r
\r
//\r
// Point to the starting address of the variables.\r
Variable = NextVariable;\r
}\r
\r
- ReleaseLockOnlyAtBootTime (&Global->VariableServicesLock);\r
+ if (*RemainingVariableStorageSize < sizeof (VARIABLE_HEADER)) {\r
+ *MaximumVariableSize = 0;\r
+ } else if ((*RemainingVariableStorageSize - sizeof (VARIABLE_HEADER)) < *MaximumVariableSize) {\r
+ *MaximumVariableSize = *RemainingVariableStorageSize - sizeof (VARIABLE_HEADER);\r
+ }\r
+\r
+ ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
return EFI_SUCCESS;\r
}\r
\r
EFI_STATUS\r
-EFIAPI\r
VariableCommonInitialize (\r
IN EFI_HANDLE ImageHandle,\r
IN EFI_SYSTEM_TABLE *SystemTable\r
VARIABLE_HEADER *NextVariable;\r
UINT32 Instance;\r
EFI_PHYSICAL_ADDRESS FvVolHdr;\r
-\r
UINT64 TempVariableStoreHeader;\r
-\r
EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;\r
- EFI_FLASH_SUBAREA_ENTRY VariableStoreEntry;\r
UINT64 BaseAddress;\r
UINT64 Length;\r
UINTN Index;\r
UINT8 Data;\r
+ UINT64 VariableStoreBase;\r
+ UINT64 VariableStoreLength;\r
\r
- mVariableModuleGlobal = AllocateRuntimePool (sizeof (ESAL_VARIABLE_GLOBAL));\r
- if (mVariableModuleGlobal == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
\r
- EfiInitializeLock(&mVariableModuleGlobal->VariableGlobal[Physical].VariableServicesLock, TPL_NOTIFY);\r
+ EfiInitializeLock(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock, TPL_NOTIFY);\r
\r
//\r
// Allocate memory for volatile variable store\r
//\r
// Variable Specific Data\r
//\r
- mVariableModuleGlobal->VariableGlobal[Physical].VolatileVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VolatileVariableStore;\r
+ mVariableModuleGlobal->VariableGlobal.VolatileVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VolatileVariableStore;\r
mVariableModuleGlobal->VolatileLastVariableOffset = sizeof (VARIABLE_STORE_HEADER);\r
\r
VolatileVariableStore->Signature = VARIABLE_STORE_SIGNATURE;\r
//\r
\r
TempVariableStoreHeader = (UINT64) PcdGet32 (PcdFlashNvStorageVariableBase);\r
- VariableStoreEntry.Base = TempVariableStoreHeader + \\r
+ VariableStoreBase = TempVariableStoreHeader + \\r
(((EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (TempVariableStoreHeader)) -> HeaderLength);\r
- VariableStoreEntry.Length = (UINT64) PcdGet32 (PcdFlashNvStorageVariableSize) - \\r
+ VariableStoreLength = (UINT64) PcdGet32 (PcdFlashNvStorageVariableSize) - \\r
(((EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (TempVariableStoreHeader)) -> HeaderLength);\r
//\r
// Mark the variable storage region of the FLASH as RUNTIME\r
//\r
- BaseAddress = VariableStoreEntry.Base & (~EFI_PAGE_MASK);\r
- Length = VariableStoreEntry.Length + (VariableStoreEntry.Base - BaseAddress);\r
+ BaseAddress = VariableStoreBase & (~EFI_PAGE_MASK);\r
+ Length = VariableStoreLength + (VariableStoreBase - BaseAddress);\r
Length = (Length + EFI_PAGE_SIZE - 1) & (~EFI_PAGE_MASK);\r
\r
Status = gDS->GetMemorySpaceDescriptor (BaseAddress, &GcdDescriptor);\r
//\r
// Get address of non volatile variable store base\r
//\r
- mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase = VariableStoreEntry.Base;\r
+ mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;\r
\r
//\r
// Check Integrity\r
// Find the Correct Instance of the FV Block Service.\r
//\r
Instance = 0;\r
- CurrPtr = (CHAR8 *) ((UINTN) mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase);\r
+ CurrPtr = (CHAR8 *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);\r
while (EfiFvbGetPhysicalAddress (Instance, &FvVolHdr) == EFI_SUCCESS) {\r
FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvVolHdr);\r
if (CurrPtr >= (CHAR8 *) FwVolHeader && CurrPtr < (((CHAR8 *) FwVolHeader) + FwVolHeader->FvLength)) {\r
if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) {\r
if (~VariableStoreHeader->Size == 0) {\r
Status = UpdateVariableStore (\r
- &mVariableModuleGlobal->VariableGlobal[Physical],\r
+ &mVariableModuleGlobal->VariableGlobal,\r
FALSE,\r
FALSE,\r
mVariableModuleGlobal->FvbInstance,\r
(UINTN) &VariableStoreHeader->Size,\r
sizeof (UINT32),\r
- (UINT8 *) &VariableStoreEntry.Length\r
+ (UINT8 *) &VariableStoreLength\r
);\r
//\r
// As Variables are stored in NV storage, which are slow devices,such as flash.\r
// We can assume all Read/Write is OK if we can set Variable store size successfully.\r
// If write fail, we will assert here\r
//\r
- ASSERT(VariableStoreHeader->Size == VariableStoreEntry.Length);\r
+ ASSERT(VariableStoreHeader->Size == VariableStoreLength);\r
\r
if (EFI_ERROR (Status)) {\r
return Status;\r
}\r
}\r
\r
- mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase = (EFI_PHYSICAL_ADDRESS) ((UINTN) CurrPtr);\r
+ mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = (EFI_PHYSICAL_ADDRESS) ((UINTN) CurrPtr);\r
//\r
// Parse non-volatile variable data and get last variable offset\r
//\r
//\r
if ((((VARIABLE_STORE_HEADER *)((UINTN) CurrPtr))->Size - mVariableModuleGlobal->NonVolatileLastVariableOffset) < VARIABLE_RECLAIM_THRESHOLD) {\r
Status = Reclaim (\r
- mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase,\r
+ mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
&mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
FALSE\r
);\r
// Check if the free area is really free.\r
//\r
for (Index = mVariableModuleGlobal->NonVolatileLastVariableOffset; Index < VariableStoreHeader->Size; Index++) {\r
- Data = ((UINT8 *) (UINTN) mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase)[Index];\r
+ Data = ((UINT8 *) (UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase)[Index];\r
if (Data != 0xff) {\r
//\r
// There must be something wrong in variable store, do reclaim operation.\r
//\r
Status = Reclaim (\r
- mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase,\r
+ mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
&mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
FALSE\r
);\r
\r
return Status;\r
}\r
+\r
+\r
+\r
+\r
+VOID\r
+EFIAPI\r
+VariableClassAddressChangeEvent (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ EfiConvertPointer (\r
+ 0x0,\r
+ (VOID **) &mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase\r
+ );\r
+ EfiConvertPointer (\r
+ 0x0,\r
+ (VOID **) &mVariableModuleGlobal->VariableGlobal.VolatileVariableBase\r
+ );\r
+ EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal);\r
+}\r
+\r
+\r
+/**\r
+ Variable Driver main entry point. The Variable driver places the 4 EFI\r
+ runtime services in the EFI System Table and installs arch protocols \r
+ for variable read and write services being availible. \r
+\r
+ @param[in] ImageHandle The firmware allocated handle for the EFI image. \r
+ @param[in] SystemTable A pointer to the EFI System Table.\r
+ \r
+ @retval EFI_SUCCESS The entry point is executed successfully.\r
+ @retval other Some error occurs when executing this entry point.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+VariableServiceInitialize (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ Status = VariableCommonInitialize (ImageHandle, SystemTable);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ SystemTable->RuntimeServices->GetVariable = RuntimeServiceGetVariable;\r
+ SystemTable->RuntimeServices->GetNextVariableName = RuntimeServiceGetNextVariableName;\r
+ SystemTable->RuntimeServices->SetVariable = RuntimeServiceSetVariable;\r
+ SystemTable->RuntimeServices->QueryVariableInfo = RuntimeServiceQueryVariableInfo;\r
+\r
+ //\r
+ // Now install the Variable Runtime Architectural Protocol on a new handle\r
+ //\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &mHandle,\r
+ &gEfiVariableArchProtocolGuid, NULL,\r
+ &gEfiVariableWriteArchProtocolGuid, NULL,\r
+ NULL\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ Status = gBS->CreateEvent (\r
+ EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE,\r
+ TPL_NOTIFY,\r
+ VariableClassAddressChangeEvent,\r
+ NULL,\r
+ &mVirtualAddressChangeEvent\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r