\r
#include "Variable.h"\r
#include <Guid/FlashMapHob.h>\r
+#include <Guid/VariableInfo.h>\r
+#include <Guid/GlobalVariable.h>\r
+\r
+\r
+\r
\r
//\r
// Don't use module globals after the SetVirtualAddress map is signaled\r
//\r
ESAL_VARIABLE_GLOBAL *mVariableModuleGlobal;\r
\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
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED VARIABLE_INFO_ENTRY *gVariableInfo = NULL;\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
+ gVariableInfo = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));\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
+ Entry->Next = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));\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
STATIC\r
BOOLEAN\r
EFIAPI\r
return Status;\r
}\r
\r
-STATIC\r
+typedef struct {\r
+ EFI_GUID *Guid;\r
+ CHAR16 *Name;\r
+ UINT32 Attributes;\r
+ UINTN DataSize;\r
+ VOID *Data;\r
+} VARIABLE_CACHE_ENTRY;\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
+VOID\r
+UpdateVariableCache (\r
+ IN CHAR16 *VariableName,\r
+ IN EFI_GUID *VendorGuid,\r
+ OUT UINT32 Attributes,\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;\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
+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
+ return EFI_NOT_FOUND;\r
+ } else if (Entry->DataSize != *DataSize) {\r
+ *DataSize = Entry->DataSize;\r
+ return EFI_BUFFER_TOO_SMALL;\r
+ } else {\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
AcquireLockOnlyAtBootTime(&Global->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) Global->VolatileVariableBase);\r
+ VariableStoreHeader[1] = (VARIABLE_STORE_HEADER *) ((UINTN) Global->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
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
+\r
EFI_STATUS\r
EFIAPI\r
GetVariable (\r
if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {\r
return EFI_INVALID_PARAMETER;\r
}\r
+\r
//\r
// Find existing variable\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, Global);\r
-\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
sizeof (UINT8),\r
&State\r
); \r
+ if (!EFI_ERROR (Status)) {\r
+ UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, FALSE, FALSE, TRUE, FALSE);\r
+ UpdateVariableCache (VariableName, VendorGuid, Attributes, DataSize, Data);\r
+ }\r
goto Done; \r
}\r
//\r
//\r
if (Variable.CurrPtr->DataSize == DataSize &&\r
(CompareMem (Data, GetVariableDataPtr (Variable.CurrPtr), DataSize) == 0)) {\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
); \r
if (EFI_ERROR (Status)) {\r
goto Done; \r
- }\r
+ } \r
} \r
} else if (Status == EFI_NOT_FOUND) {\r
//\r
//\r
// Create a nonvolatile variable\r
//\r
+ Variable.Volatile = FALSE;\r
\r
if ((UINT32) (VarSize +*NonVolatileOffset) >\r
((VARIABLE_STORE_HEADER *) ((UINTN) (Global->NonVolatileVariableBase)))->Size\r
//\r
// Create a volatile variable\r
// \r
+ Variable.Volatile = TRUE;\r
\r
if ((UINT32) (VarSize +*VolatileOffset) >\r
((VARIABLE_STORE_HEADER *) ((UINTN) (Global->VolatileVariableBase)))->Size) {\r
sizeof (UINT8),\r
&State\r
);\r
+ \r
+ if (!EFI_ERROR (Status)) {\r
+ UpdateVariableInfo (VariableName, VendorGuid, Variable.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, Variable.Volatile, FALSE, TRUE, FALSE, FALSE);\r
+ UpdateVariableCache (VariableName, VendorGuid, Attributes, DataSize, Data);\r
+\r
Done:\r
ReleaseLockOnlyAtBootTime (&Global->VariableServicesLock);\r
return Status;\r