-/*++\r
+/** @file\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
+ Implement all four UEFI Runtime Variable services for the nonvolatile\r
+ and volatile storage space and install variable architecture protocol.\r
+ \r
+Copyright (c) 2006 - 2010, 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
+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
+**/\r
\r
- Variable.c\r
+#include "Variable.h"\r
\r
-Abstract:\r
+VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal;\r
+EFI_EVENT mVirtualAddressChangeEvent = NULL;\r
+EFI_HANDLE mHandle = NULL;\r
+///\r
+/// The size of a 3 character ISO639 language code.\r
+///\r
+#define ISO_639_2_ENTRY_SIZE 3\r
+\r
+///\r
+/// The current Hii implementation accesses this variable many times on every boot.\r
+/// Other common variables are only accessed once. 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
+ &gEfiGlobalVariableGuid,\r
+ L"PlatformLang",\r
+ 0x00000000,\r
+ 0x00,\r
+ NULL\r
+ }\r
+};\r
\r
-Revision History\r
+VARIABLE_INFO_ENTRY *gVariableInfo = NULL;\r
+EFI_EVENT mFvbRegistration = NULL;\r
\r
---*/\r
+/**\r
+ Update the variable region with Variable information. These are the same \r
+ arguments as the EFI Variable services.\r
\r
+ @param[in] VariableName Name of variable\r
\r
-#include "Variable.h"\r
-#include <Guid/FlashMapHob.h>\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
+ @param[in] VendorGuid Guid of variable\r
+\r
+ @param[in] Data Variable data\r
+\r
+ @param[in] DataSize Size of data. 0 means delete\r
+\r
+ @param[in] Attributes Attribues of the variable\r
+\r
+ @param[in] Variable The variable information which is used to keep track of variable usage.\r
+\r
+ @retval EFI_SUCCESS The update operation is success.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Variable region is full, can not write other data into this region.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UpdateVariable (\r
+ IN CHAR16 *VariableName,\r
+ IN EFI_GUID *VendorGuid,\r
+ IN VOID *Data,\r
+ IN UINTN DataSize,\r
+ IN UINT32 Attributes OPTIONAL,\r
+ IN VARIABLE_POINTER_TRACK *Variable\r
+ );\r
+\r
+/**\r
+ Acquires lock only at boot time. Simply returns at runtime.\r
+\r
+ This is a temperary function which will be removed when\r
+ EfiAcquireLock() in UefiLib can handle the call in UEFI\r
+ Runtimer driver in RT phase.\r
+ It calls EfiAcquireLock() at boot time, and simply returns\r
+ at runtime.\r
+\r
+ @param Lock A pointer to the lock to acquire\r
+\r
+**/\r
VOID\r
AcquireLockOnlyAtBootTime (\r
IN EFI_LOCK *Lock\r
}\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
+/**\r
+ Releases lock only at boot time. Simply returns at runtime.\r
+\r
+ This is a temperary function which will be removed when\r
+ EfiReleaseLock() in UefiLib can handle the call in UEFI\r
+ Runtimer driver in RT phase.\r
+ It calls EfiReleaseLock() at boot time, and simply returns\r
+ at runtime.\r
+\r
+ @param Lock A pointer to the lock to release\r
+\r
+**/\r
VOID\r
ReleaseLockOnlyAtBootTime (\r
IN EFI_LOCK *Lock\r
}\r
}\r
\r
-STATIC\r
-BOOLEAN\r
-EFIAPI\r
-IsValidVariableHeader (\r
- IN VARIABLE_HEADER *Variable\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
+{\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 (StrSize (VariableName));\r
+ ASSERT (gVariableInfo->Name != NULL);\r
+ StrCpy (gVariableInfo->Name, VariableName);\r
+ gVariableInfo->Volatile = Volatile;\r
+\r
+ gBS->InstallConfigurationTable (&gEfiVariableGuid, 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 (StrSize (VariableName));\r
+ ASSERT (Entry->Next->Name != NULL);\r
+ StrCpy (Entry->Next->Name, VariableName);\r
+ Entry->Next->Volatile = Volatile;\r
+ }\r
+\r
+ }\r
+ }\r
+}\r
\r
-Routine Description:\r
+\r
+/**\r
\r
This code checks if variable header is valid or not.\r
\r
-Arguments:\r
- Variable Pointer to the Variable Header.\r
+ @param Variable Pointer to the Variable Header.\r
\r
-Returns:\r
- TRUE Variable header is valid.\r
- FALSE Variable header is not valid.\r
+ @retval TRUE Variable header is valid.\r
+ @retval FALSE Variable header is not valid.\r
\r
---*/\r
+**/\r
+BOOLEAN\r
+IsValidVariableHeader (\r
+ IN VARIABLE_HEADER *Variable\r
+ )\r
{\r
- if (Variable == NULL ||\r
- Variable->StartId != VARIABLE_DATA ||\r
- (sizeof (VARIABLE_HEADER) + Variable->NameSize + Variable->DataSize) > MAX_VARIABLE_SIZE\r
- ) {\r
+ if (Variable == NULL || Variable->StartId != VARIABLE_DATA) {\r
return FALSE;\r
}\r
\r
return TRUE;\r
}\r
\r
-STATIC\r
-EFI_STATUS\r
-EFIAPI\r
-UpdateVariableStore (\r
- IN VARIABLE_GLOBAL *Global,\r
- IN BOOLEAN Volatile,\r
- IN BOOLEAN SetByIndex,\r
- IN UINTN Instance,\r
- IN UINTN DataPtrIndex,\r
- IN UINT32 DataSize,\r
- IN UINT8 *Buffer\r
- )\r
-/*++\r
\r
-Routine Description:\r
+/**\r
\r
This function writes data to the FWH at the correct LBA even if the LBAs\r
are fragmented.\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
+ @param Global Pointer to VARAIBLE_GLOBAL structure\r
+ @param Volatile Point out the Variable is Volatile or Non-Volatile\r
+ @param SetByIndex TRUE if target pointer is given as index\r
+ FALSE if target pointer is absolute\r
+ @param Fvb Pointer to the writable FVB protocol\r
+ @param DataPtrIndex Pointer to the Data from the end of VARIABLE_STORE_HEADER\r
+ structure\r
+ @param DataSize Size of data to be written\r
+ @param Buffer Pointer to the buffer from which data is written\r
\r
-Returns:\r
+ @retval EFI_INVALID_PARAMETER Parameters not valid\r
+ @retval EFI_SUCCESS Variable store successfully updated\r
\r
- EFI_INVALID_PARAMETER - Parameters not valid\r
- EFI_SUCCESS - Variable store successfully updated\r
-\r
---*/\r
+**/\r
+EFI_STATUS\r
+UpdateVariableStore (\r
+ IN VARIABLE_GLOBAL *Global,\r
+ IN BOOLEAN Volatile,\r
+ IN BOOLEAN SetByIndex,\r
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb,\r
+ IN UINTN DataPtrIndex,\r
+ IN UINT32 DataSize,\r
+ IN UINT8 *Buffer\r
+ )\r
{\r
EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;\r
UINTN BlockIndex2;\r
// Check if the Data is Volatile\r
//\r
if (!Volatile) {\r
- EfiFvbGetPhysicalAddress (Instance, &FvVolHdr);\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
//\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
//\r
if ((CurrWritePtr >= LinearOffset) && (CurrWritePtr < LinearOffset + PtrBlockMapEntry->Length)) {\r
if ((CurrWritePtr + CurrWriteSize) <= (LinearOffset + PtrBlockMapEntry->Length)) {\r
- Status = EfiFvbWriteBlock (\r
- Instance,\r
+ Status = Fvb->Write (\r
+ Fvb,\r
LbaNumber,\r
(UINTN) (CurrWritePtr - LinearOffset),\r
&CurrWriteSize,\r
CurrBuffer\r
);\r
- return Status;\r
+ return Status;\r
} else {\r
Size = (UINT32) (LinearOffset + PtrBlockMapEntry->Length - CurrWritePtr);\r
- Status = EfiFvbWriteBlock (\r
- Instance,\r
+ Status = Fvb->Write (\r
+ Fvb,\r
LbaNumber,\r
(UINTN) (CurrWritePtr - LinearOffset),\r
&Size,\r
return EFI_SUCCESS;\r
}\r
\r
-STATIC\r
-VARIABLE_STORE_STATUS\r
-EFIAPI\r
-GetVariableStoreStatus (\r
- IN VARIABLE_STORE_HEADER *VarStoreHeader\r
- )\r
-/*++\r
\r
-Routine Description:\r
+/**\r
\r
This code gets the current status of Variable Store.\r
\r
-Arguments:\r
-\r
- VarStoreHeader Pointer to the Variable Store Header.\r
+ @param VarStoreHeader Pointer to the Variable Store Header.\r
\r
-Returns:\r
+ @retval EfiRaw Variable store status is raw\r
+ @retval EfiValid Variable store status is valid\r
+ @retval EfiInvalid Variable store status is invalid\r
\r
- EfiRaw Variable store status is raw\r
- EfiValid Variable store status is valid\r
- EfiInvalid Variable store status is invalid\r
-\r
---*/\r
+**/\r
+VARIABLE_STORE_STATUS\r
+GetVariableStoreStatus (\r
+ IN VARIABLE_STORE_HEADER *VarStoreHeader\r
+ )\r
{\r
- if (VarStoreHeader->Signature == VARIABLE_STORE_SIGNATURE &&\r
+ if (CompareGuid (&VarStoreHeader->Signature, &gEfiVariableGuid) &&\r
VarStoreHeader->Format == VARIABLE_STORE_FORMATTED &&\r
VarStoreHeader->State == VARIABLE_STORE_HEALTHY\r
) {\r
\r
return EfiValid;\r
- } else if (VarStoreHeader->Signature == 0xffffffff &&\r
- VarStoreHeader->Size == 0xffffffff &&\r
- VarStoreHeader->Format == 0xff &&\r
- VarStoreHeader->State == 0xff\r
+ } else if (((UINT32 *)(&VarStoreHeader->Signature))[0] == 0xffffffff &&\r
+ ((UINT32 *)(&VarStoreHeader->Signature))[1] == 0xffffffff &&\r
+ ((UINT32 *)(&VarStoreHeader->Signature))[2] == 0xffffffff &&\r
+ ((UINT32 *)(&VarStoreHeader->Signature))[3] == 0xffffffff &&\r
+ VarStoreHeader->Size == 0xffffffff &&\r
+ VarStoreHeader->Format == 0xff &&\r
+ VarStoreHeader->State == 0xff\r
) {\r
\r
return EfiRaw;\r
}\r
}\r
\r
-STATIC\r
-UINT8 *\r
-EFIAPI\r
-GetVariableDataPtr (\r
+\r
+/**\r
+\r
+ This code gets the size of name of variable.\r
+\r
+ @param Variable Pointer to the Variable Header\r
+\r
+ @return UINTN Size of variable in bytes\r
+\r
+**/\r
+UINTN\r
+NameSizeOfVariable (\r
+ IN VARIABLE_HEADER *Variable\r
+ )\r
+{\r
+ if (Variable->State == (UINT8) (-1) ||\r
+ Variable->DataSize == (UINT32) (-1) ||\r
+ Variable->NameSize == (UINT32) (-1) ||\r
+ Variable->Attributes == (UINT32) (-1)) {\r
+ return 0;\r
+ }\r
+ return (UINTN) Variable->NameSize;\r
+}\r
+\r
+/**\r
+\r
+ This code gets the size of variable data.\r
+\r
+ @param Variable Pointer to the Variable Header\r
+\r
+ @return Size of variable in bytes\r
+\r
+**/\r
+UINTN\r
+DataSizeOfVariable (\r
IN VARIABLE_HEADER *Variable\r
)\r
-/*++\r
+{\r
+ if (Variable->State == (UINT8) (-1) ||\r
+ Variable->DataSize == (UINT32) (-1) ||\r
+ Variable->NameSize == (UINT32) (-1) ||\r
+ Variable->Attributes == (UINT32) (-1)) {\r
+ return 0;\r
+ }\r
+ return (UINTN) Variable->DataSize;\r
+}\r
\r
-Routine Description:\r
+/**\r
\r
- This code gets the pointer to the variable data.\r
+ This code gets the pointer to the variable name.\r
+\r
+ @param Variable Pointer to the Variable Header\r
+\r
+ @return Pointer to Variable Name which is Unicode encoding\r
+\r
+**/\r
+CHAR16 *\r
+GetVariableNamePtr (\r
+ IN VARIABLE_HEADER *Variable\r
+ )\r
+{\r
+\r
+ return (CHAR16 *) (Variable + 1);\r
+}\r
\r
-Arguments:\r
+/**\r
\r
- Variable Pointer to the Variable Header.\r
+ This code gets the pointer to the variable data.\r
\r
-Returns:\r
+ @param Variable Pointer to the Variable Header\r
\r
- UINT8* Pointer to Variable Data\r
+ @return Pointer to Variable Data\r
\r
---*/\r
+**/\r
+UINT8 *\r
+GetVariableDataPtr (\r
+ IN VARIABLE_HEADER *Variable\r
+ )\r
{\r
+ UINTN Value;\r
+ \r
//\r
// Be careful about pad size for alignment\r
//\r
- return (UINT8 *) ((UINTN) GET_VARIABLE_NAME_PTR (Variable) + Variable->NameSize + GET_PAD_SIZE (Variable->NameSize));\r
+ Value = (UINTN) GetVariableNamePtr (Variable);\r
+ Value += NameSizeOfVariable (Variable);\r
+ Value += GET_PAD_SIZE (NameSizeOfVariable (Variable));\r
+\r
+ return (UINT8 *) Value;\r
}\r
\r
-STATIC\r
-VARIABLE_HEADER *\r
-GetNextVariablePtr (\r
- IN VARIABLE_HEADER *Variable\r
- )\r
-/*++\r
\r
-Routine Description:\r
+/**\r
\r
This code gets the pointer to the next variable header.\r
\r
-Arguments:\r
-\r
- Variable Pointer to the Variable Header.\r
-\r
-Returns:\r
+ @param Variable Pointer to the Variable Header\r
\r
- VARIABLE_HEADER* Pointer to next variable header.\r
+ @return Pointer to next variable header\r
\r
---*/\r
+**/\r
+VARIABLE_HEADER *\r
+GetNextVariablePtr (\r
+ IN VARIABLE_HEADER *Variable\r
+ )\r
{\r
+ UINTN Value;\r
+\r
if (!IsValidVariableHeader (Variable)) {\r
return NULL;\r
}\r
+\r
+ Value = (UINTN) GetVariableDataPtr (Variable);\r
+ Value += DataSizeOfVariable (Variable);\r
+ Value += GET_PAD_SIZE (DataSizeOfVariable (Variable));\r
+\r
//\r
// Be careful about pad size for alignment\r
//\r
- return (VARIABLE_HEADER *) ((UINTN) GetVariableDataPtr (Variable) + Variable->DataSize + GET_PAD_SIZE (Variable->DataSize));\r
+ return (VARIABLE_HEADER *) HEADER_ALIGN (Value);\r
}\r
\r
-STATIC\r
+/**\r
+\r
+ Gets the pointer to the first variable header in given variable store area.\r
+\r
+ @param VarStoreHeader Pointer to the Variable Store Header.\r
+\r
+ @return Pointer to the first variable header\r
+\r
+**/\r
VARIABLE_HEADER *\r
-EFIAPI\r
-GetEndPointer (\r
+GetStartPointer (\r
IN VARIABLE_STORE_HEADER *VarStoreHeader\r
)\r
-/*++\r
-\r
-Routine Description:\r
+{\r
+ //\r
+ // The end of variable store\r
+ //\r
+ return (VARIABLE_HEADER *) HEADER_ALIGN (VarStoreHeader + 1);\r
+}\r
\r
- This code gets the pointer to the last variable memory pointer byte\r
+/**\r
\r
-Arguments:\r
+ Gets the pointer to the end of the variable storage area.\r
\r
- VarStoreHeader Pointer to the Variable Store Header.\r
+ This function gets pointer to the end of the variable storage\r
+ area, according to the input variable store header.\r
\r
-Returns:\r
+ @param VarStoreHeader Pointer to the Variable Store Header\r
\r
- VARIABLE_HEADER* Pointer to last unavailable Variable Header\r
+ @return Pointer to the end of the variable storage area \r
\r
---*/\r
+**/\r
+VARIABLE_HEADER *\r
+GetEndPointer (\r
+ IN VARIABLE_STORE_HEADER *VarStoreHeader\r
+ )\r
{\r
//\r
// The end of variable store\r
//\r
- return (VARIABLE_HEADER *) ((UINTN) VarStoreHeader + VarStoreHeader->Size);\r
+ return (VARIABLE_HEADER *) HEADER_ALIGN ((UINTN) VarStoreHeader + VarStoreHeader->Size);\r
}\r
\r
-STATIC\r
-EFI_STATUS\r
-EFIAPI\r
-Reclaim (\r
- IN EFI_PHYSICAL_ADDRESS VariableBase,\r
- OUT UINTN *LastVariableOffset,\r
- IN BOOLEAN IsVolatile\r
- )\r
-/*++\r
-\r
-Routine Description:\r
\r
- Variable store garbage collection and reclaim operation\r
+/**\r
\r
-Arguments:\r
+ Variable store garbage collection and reclaim operation.\r
\r
- VariableBase Base address of variable store\r
- LastVariableOffset Offset of last variable\r
- IsVolatile The variable store is volatile or not,\r
- if it is non-volatile, need FTW\r
+ @param VariableBase Base address of variable store\r
+ @param LastVariableOffset Offset of last variable\r
+ @param IsVolatile The variable store is volatile or not,\r
+ if it is non-volatile, need FTW\r
+ @param UpdatingVariable Pointer to updateing variable.\r
\r
-Returns:\r
+ @return EFI_OUT_OF_RESOURCES\r
+ @return EFI_SUCCESS\r
+ @return Others\r
\r
- EFI STATUS\r
-\r
---*/\r
+**/\r
+EFI_STATUS\r
+Reclaim (\r
+ IN EFI_PHYSICAL_ADDRESS VariableBase,\r
+ OUT UINTN *LastVariableOffset,\r
+ IN BOOLEAN IsVolatile,\r
+ IN VARIABLE_HEADER *UpdatingVariable\r
+ )\r
{\r
VARIABLE_HEADER *Variable;\r
+ VARIABLE_HEADER *AddedVariable;\r
VARIABLE_HEADER *NextVariable;\r
+ VARIABLE_HEADER *NextAddedVariable;\r
VARIABLE_STORE_HEADER *VariableStoreHeader;\r
UINT8 *ValidBuffer;\r
- UINTN ValidBufferSize;\r
+ UINTN MaximumBufferSize;\r
UINTN VariableSize;\r
+ UINTN VariableNameSize;\r
+ UINTN UpdatingVariableNameSize;\r
+ UINTN NameSize;\r
UINT8 *CurrPtr;\r
+ VOID *Point0;\r
+ VOID *Point1;\r
+ BOOLEAN FoundAdded;\r
EFI_STATUS Status;\r
+ CHAR16 *VariableNamePtr;\r
+ CHAR16 *UpdatingVariableNamePtr;\r
\r
VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) VariableBase);\r
+ //\r
+ // recaluate the total size of Common/HwErr type variables in non-volatile area.\r
+ //\r
+ if (!IsVolatile) {\r
+ mVariableModuleGlobal->CommonVariableTotalSize = 0;\r
+ mVariableModuleGlobal->HwErrVariableTotalSize = 0;\r
+ }\r
\r
//\r
// Start Pointers for the variable.\r
//\r
- Variable = (VARIABLE_HEADER *) (VariableStoreHeader + 1);\r
-\r
- ValidBufferSize = sizeof (VARIABLE_STORE_HEADER);\r
+ Variable = GetStartPointer (VariableStoreHeader);\r
+ MaximumBufferSize = sizeof (VARIABLE_STORE_HEADER);\r
\r
while (IsValidVariableHeader (Variable)) {\r
NextVariable = GetNextVariablePtr (Variable);\r
- if (Variable->State == VAR_ADDED) {\r
+ if (Variable->State == VAR_ADDED || \r
+ Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)\r
+ ) {\r
VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
- ValidBufferSize += VariableSize;\r
+ MaximumBufferSize += VariableSize;\r
}\r
\r
Variable = NextVariable;\r
}\r
\r
- ValidBuffer = AllocatePool (ValidBufferSize);\r
+ //\r
+ // Reserve the 1 Bytes with Oxff to identify the \r
+ // end of the variable buffer. \r
+ // \r
+ MaximumBufferSize += 1;\r
+ ValidBuffer = AllocatePool (MaximumBufferSize);\r
if (ValidBuffer == NULL) {\r
return EFI_OUT_OF_RESOURCES;\r
}\r
\r
- SetMem (ValidBuffer, ValidBufferSize, 0xff);\r
-\r
- CurrPtr = ValidBuffer;\r
+ SetMem (ValidBuffer, MaximumBufferSize, 0xff);\r
\r
//\r
// Copy variable store header\r
//\r
- CopyMem (CurrPtr, VariableStoreHeader, sizeof (VARIABLE_STORE_HEADER));\r
- CurrPtr += sizeof (VARIABLE_STORE_HEADER);\r
+ CopyMem (ValidBuffer, VariableStoreHeader, sizeof (VARIABLE_STORE_HEADER));\r
+ CurrPtr = (UINT8 *) GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer);\r
\r
//\r
- // Start Pointers for the variable.\r
- //\r
- Variable = (VARIABLE_HEADER *) (VariableStoreHeader + 1);\r
-\r
+ // Reinstall all ADDED variables as long as they are not identical to Updating Variable\r
+ // \r
+ Variable = GetStartPointer (VariableStoreHeader);\r
while (IsValidVariableHeader (Variable)) {\r
NextVariable = GetNextVariablePtr (Variable);\r
if (Variable->State == VAR_ADDED) {\r
+ if (UpdatingVariable != NULL) {\r
+ if (UpdatingVariable == Variable) {\r
+ Variable = NextVariable;\r
+ continue;\r
+ }\r
+\r
+ VariableNameSize = NameSizeOfVariable(Variable);\r
+ UpdatingVariableNameSize = NameSizeOfVariable(UpdatingVariable);\r
+\r
+ VariableNamePtr = GetVariableNamePtr (Variable);\r
+ UpdatingVariableNamePtr = GetVariableNamePtr (UpdatingVariable);\r
+ if (CompareGuid (&Variable->VendorGuid, &UpdatingVariable->VendorGuid) &&\r
+ VariableNameSize == UpdatingVariableNameSize &&\r
+ CompareMem (VariableNamePtr, UpdatingVariableNamePtr, VariableNameSize) == 0 ) {\r
+ Variable = NextVariable;\r
+ continue;\r
+ }\r
+ }\r
VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);\r
CurrPtr += VariableSize;\r
+ if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+ mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;\r
+ } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+ mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;\r
+ }\r
+ }\r
+ Variable = NextVariable;\r
+ }\r
+\r
+ //\r
+ // Reinstall the variable being updated if it is not NULL\r
+ //\r
+ if (UpdatingVariable != NULL) {\r
+ VariableSize = (UINTN)(GetNextVariablePtr (UpdatingVariable)) - (UINTN)UpdatingVariable;\r
+ CopyMem (CurrPtr, (UINT8 *) UpdatingVariable, VariableSize);\r
+ CurrPtr += VariableSize;\r
+ if ((!IsVolatile) && ((UpdatingVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+ mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;\r
+ } else if ((!IsVolatile) && ((UpdatingVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+ mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Reinstall all in delete transition variables\r
+ // \r
+ Variable = GetStartPointer (VariableStoreHeader);\r
+ while (IsValidVariableHeader (Variable)) {\r
+ NextVariable = GetNextVariablePtr (Variable);\r
+ if (Variable != UpdatingVariable && Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
+\r
+ //\r
+ // Buffer has cached all ADDED variable. \r
+ // Per IN_DELETED variable, we have to guarantee that\r
+ // no ADDED one in previous buffer. \r
+ // \r
+ \r
+ FoundAdded = FALSE;\r
+ AddedVariable = GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer);\r
+ while (IsValidVariableHeader (AddedVariable)) {\r
+ NextAddedVariable = GetNextVariablePtr (AddedVariable);\r
+ NameSize = NameSizeOfVariable (AddedVariable);\r
+ if (CompareGuid (&AddedVariable->VendorGuid, &Variable->VendorGuid) &&\r
+ NameSize == NameSizeOfVariable (Variable)\r
+ ) {\r
+ Point0 = (VOID *) GetVariableNamePtr (AddedVariable);\r
+ Point1 = (VOID *) GetVariableNamePtr (Variable);\r
+ if (CompareMem (Point0, Point1, NameSizeOfVariable (AddedVariable)) == 0) {\r
+ FoundAdded = TRUE;\r
+ break;\r
+ }\r
+ }\r
+ AddedVariable = NextAddedVariable;\r
+ }\r
+ if (!FoundAdded) {\r
+ //\r
+ // Promote VAR_IN_DELETED_TRANSITION to VAR_ADDED\r
+ //\r
+ VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
+ CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);\r
+ ((VARIABLE_HEADER *) CurrPtr)->State = VAR_ADDED;\r
+ CurrPtr += VariableSize;\r
+ if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+ mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;\r
+ } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+ mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;\r
+ }\r
+ }\r
}\r
\r
Variable = NextVariable;\r
// If volatile variable store, just copy valid buffer\r
//\r
SetMem ((UINT8 *) (UINTN) VariableBase, VariableStoreHeader->Size, 0xff);\r
- CopyMem ((UINT8 *) (UINTN) VariableBase, ValidBuffer, ValidBufferSize);\r
- *LastVariableOffset = ValidBufferSize;\r
+ CopyMem ((UINT8 *) (UINTN) VariableBase, ValidBuffer, (UINTN) (CurrPtr - (UINT8 *) ValidBuffer));\r
Status = EFI_SUCCESS;\r
} else {\r
//\r
Status = FtwVariableSpace (\r
VariableBase,\r
ValidBuffer,\r
- ValidBufferSize\r
+ (UINTN) (CurrPtr - (UINT8 *) ValidBuffer)\r
);\r
- if (!EFI_ERROR (Status)) {\r
- *LastVariableOffset = ValidBufferSize;\r
- }\r
}\r
-\r
- FreePool (ValidBuffer);\r
-\r
- if (EFI_ERROR (Status)) {\r
+ if (!EFI_ERROR (Status)) {\r
+ *LastVariableOffset = (UINTN) (CurrPtr - (UINT8 *) ValidBuffer);\r
+ } else {\r
*LastVariableOffset = 0;\r
}\r
\r
+ FreePool (ValidBuffer);\r
+\r
return Status;\r
}\r
\r
-STATIC\r
-EFI_STATUS\r
-EFIAPI\r
-FindVariable (\r
- IN CHAR16 *VariableName,\r
- IN EFI_GUID *VendorGuid,\r
- OUT VARIABLE_POINTER_TRACK *PtrTrack,\r
- IN VARIABLE_GLOBAL *Global\r
- )\r
-/*++\r
\r
-Routine Description:\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] Attributes Attribues 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
- This code finds variable in storage blocks (Volatile or Non-Volatile)\r
+ if (EfiAtRuntime ()) {\r
+ //\r
+ // Don't use the cache at runtime\r
+ // \r
+ return;\r
+ }\r
\r
-Arguments:\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
+ //\r
+ // Delete Case\r
+ //\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
+ ASSERT (Entry->Data != NULL);\r
\r
- VariableName Name of the variable to be found\r
- VendorGuid Vendor GUID to be found.\r
- PtrTrack Variable Track Pointer structure that contains\r
- Variable Information.\r
- Contains the pointer of Variable header.\r
- Global VARIABLE_GLOBAL pointer\r
+ Entry->DataSize = DataSize;\r
+ CopyMem (Entry->Data, Data, DataSize);\r
+ }\r
+ }\r
+ }\r
+ }\r
+}\r
\r
-Returns:\r
\r
- EFI STATUS\r
+/**\r
+ Search the cache to check if the variable is in it.\r
\r
---*/\r
-{\r
- VARIABLE_HEADER *Variable[2];\r
- VARIABLE_STORE_HEADER *VariableStoreHeader[2];\r
- UINTN Index;\r
+ This function searches the variable cache. If the variable to find exists, return its data\r
+ and attributes.\r
\r
- //\r
- // We aquire the lock at the entry of FindVariable as GetVariable, GetNextVariableName\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
+ @param VariableName A Null-terminated Unicode string that is the name of the vendor's\r
+ variable. Each VariableName is unique for each \r
+ VendorGuid.\r
+ @param VendorGuid A unique identifier for the vendor\r
+ @param Attributes Pointer to the attributes bitmask of the variable for output.\r
+ @param DataSize On input, size of the buffer of Data.\r
+ On output, size of the variable's data.\r
+ @param Data Pointer to the data buffer for output.\r
\r
- //\r
- // 0: Non-Volatile, 1: Volatile\r
- //\r
- VariableStoreHeader[0] = (VARIABLE_STORE_HEADER *) ((UINTN) Global->NonVolatileVariableBase);\r
- VariableStoreHeader[1] = (VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase);\r
+ @retval EFI_SUCCESS VariableGuid & VariableName data was returned.\r
+ @retval EFI_NOT_FOUND No matching variable found in cache.\r
+ @retval EFI_BUFFER_TOO_SMALL *DataSize is smaller than size of the variable's data to return.\r
\r
- //\r
- // Start Pointers for the variable.\r
- // Actual Data Pointer where data can be written.\r
- //\r
- Variable[0] = (VARIABLE_HEADER *) (VariableStoreHeader[0] + 1);\r
- Variable[1] = (VARIABLE_HEADER *) (VariableStoreHeader[1] + 1);\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 (VariableName[0] != 0 && VendorGuid == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
+ if (EfiAtRuntime ()) {\r
+ // Don't use the cache at runtime\r
+ return EFI_NOT_FOUND;\r
}\r
- //\r
- // Find the variable by walk through non-volatile and volatile variable store\r
- //\r
- for (Index = 0; Index < 2; Index++) {\r
- PtrTrack->StartPtr = (VARIABLE_HEADER *) (VariableStoreHeader[Index] + 1);\r
- PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[Index]);\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 (VariableName[0] == 0) {\r
- PtrTrack->CurrPtr = Variable[Index];\r
- PtrTrack->Volatile = (BOOLEAN) Index;\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
- return EFI_SUCCESS;\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
+ *DataSize = Entry->DataSize;\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
- Variable[Index] = GetNextVariablePtr (Variable[Index]);\r
}\r
- //\r
- // While (...)\r
- //\r
}\r
- //\r
- // for (...)\r
- //\r
- PtrTrack->CurrPtr = NULL;\r
+ \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
-Routine Description:\r
+/**\r
+ Finds variable in storage blocks of volatile and non-volatile storage areas.\r
\r
- This code finds variable in storage blocks (Volatile or Non-Volatile)\r
+ This code finds variable in storage blocks of volatile and non-volatile storage areas.\r
+ If VariableName is an empty string, then we just return the first\r
+ qualified variable without comparing VariableName and VendorGuid.\r
+ Otherwise, VariableName and VendorGuid are compared.\r
\r
-Arguments:\r
+ @param VariableName Name of the variable to be found\r
+ @param VendorGuid Vendor GUID to be found.\r
+ @param PtrTrack VARIABLE_POINTER_TRACK structure for output,\r
+ including the range searched and the target position.\r
+ @param Global Pointer to VARIABLE_GLOBAL structure, including\r
+ base of volatile variable storage area, base of\r
+ NV variable storage area, and a lock.\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
+ @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while\r
+ VendorGuid is NULL\r
+ @retval EFI_SUCCESS Variable successfully found\r
+ @retval EFI_INVALID_PARAMETER Variable not found\r
\r
-Returns:\r
-\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
+**/\r
+EFI_STATUS\r
+FindVariable (\r
+ IN CHAR16 *VariableName,\r
+ IN EFI_GUID *VendorGuid,\r
+ OUT VARIABLE_POINTER_TRACK *PtrTrack,\r
+ IN VARIABLE_GLOBAL *Global\r
+ )\r
{\r
- VARIABLE_POINTER_TRACK Variable;\r
- UINTN VarDataSize;\r
- EFI_STATUS Status;\r
+ VARIABLE_HEADER *Variable[2];\r
+ VARIABLE_HEADER *InDeletedVariable;\r
+ VARIABLE_STORE_HEADER *VariableStoreHeader[2];\r
+ UINTN InDeletedStorageIndex;\r
+ UINTN Index;\r
+ VOID *Point;\r
\r
- if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
//\r
- // Find existing variable\r
+ // 0: Volatile, 1: Non-Volatile\r
+ // The index and attributes mapping must be kept in this order as RuntimeServiceGetNextVariableName\r
+ // make use of this mapping to implement search algorithme.\r
//\r
- Status = FindVariable (VariableName, VendorGuid, &Variable, Global);\r
+ VariableStoreHeader[0] = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);\r
+ VariableStoreHeader[1] = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);\r
\r
- if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {\r
- goto Done;\r
+ //\r
+ // Start Pointers for the variable.\r
+ // Actual Data Pointer where data can be written.\r
+ //\r
+ Variable[0] = GetStartPointer (VariableStoreHeader[0]);\r
+ Variable[1] = GetStartPointer (VariableStoreHeader[1]);\r
+\r
+ if (VariableName[0] != 0 && VendorGuid == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
}\r
+\r
//\r
- // Get data size\r
+ // Find the variable by walk through volatile and then non-volatile variable store\r
//\r
- VarDataSize = Variable.CurrPtr->DataSize;\r
- if (*DataSize >= VarDataSize) {\r
- if (Data == NULL) {\r
- Status = EFI_INVALID_PARAMETER;\r
- goto Done;\r
- }\r
+ InDeletedVariable = NULL;\r
+ InDeletedStorageIndex = 0;\r
+ for (Index = 0; Index < 2; Index++) {\r
+ while ((Variable[Index] < GetEndPointer (VariableStoreHeader[Index])) && IsValidVariableHeader (Variable[Index])) {\r
+ if (Variable[Index]->State == VAR_ADDED || \r
+ Variable[Index]->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)\r
+ ) {\r
+ if (!EfiAtRuntime () || ((Variable[Index]->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) != 0)) {\r
+ if (VariableName[0] == 0) {\r
+ if (Variable[Index]->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
+ InDeletedVariable = Variable[Index];\r
+ InDeletedStorageIndex = Index;\r
+ } else {\r
+ PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader[Index]);\r
+ PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[Index]);\r
+ PtrTrack->CurrPtr = Variable[Index];\r
+ PtrTrack->Volatile = (BOOLEAN)(Index == 0);\r
+\r
+ return EFI_SUCCESS;\r
+ }\r
+ } else {\r
+ if (CompareGuid (VendorGuid, &Variable[Index]->VendorGuid)) {\r
+ Point = (VOID *) GetVariableNamePtr (Variable[Index]);\r
+\r
+ ASSERT (NameSizeOfVariable (Variable[Index]) != 0);\r
+ if (CompareMem (VariableName, Point, NameSizeOfVariable (Variable[Index])) == 0) {\r
+ if (Variable[Index]->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
+ InDeletedVariable = Variable[Index];\r
+ InDeletedStorageIndex = Index;\r
+ } else {\r
+ PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader[Index]);\r
+ PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[Index]);\r
+ PtrTrack->CurrPtr = Variable[Index];\r
+ PtrTrack->Volatile = (BOOLEAN)(Index == 0);\r
+\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
\r
- CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr), VarDataSize);\r
- if (Attributes != NULL) {\r
- *Attributes = Variable.CurrPtr->Attributes;\r
+ Variable[Index] = GetNextVariablePtr (Variable[Index]);\r
+ }\r
+ if (InDeletedVariable != NULL) {\r
+ PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader[InDeletedStorageIndex]);\r
+ PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[InDeletedStorageIndex]);\r
+ PtrTrack->CurrPtr = InDeletedVariable;\r
+ PtrTrack->Volatile = (BOOLEAN)(InDeletedStorageIndex == 0);\r
+ return EFI_SUCCESS;\r
}\r
+ }\r
+ PtrTrack->CurrPtr = NULL;\r
+ return EFI_NOT_FOUND;\r
+}\r
\r
- *DataSize = VarDataSize;\r
- Status = EFI_SUCCESS;\r
- goto Done;\r
+/**\r
+ Get index from supported language codes according to language string.\r
+\r
+ This code is used to get corresponding index in supported language codes. It can handle\r
+ RFC4646 and ISO639 language tags.\r
+ In ISO639 language tags, take 3-characters as a delimitation to find matched string and calculate the index.\r
+ In RFC4646 language tags, take semicolon as a delimitation to find matched string and calculate the index.\r
+\r
+ For example:\r
+ SupportedLang = "engfraengfra"\r
+ Lang = "eng"\r
+ Iso639Language = TRUE\r
+ The return value is "0".\r
+ Another example:\r
+ SupportedLang = "en;fr;en-US;fr-FR"\r
+ Lang = "fr-FR"\r
+ Iso639Language = FALSE\r
+ The return value is "3".\r
+\r
+ @param SupportedLang Platform supported language codes.\r
+ @param Lang Configured language.\r
+ @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646.\r
+\r
+ @retval the index of language in the language codes.\r
+\r
+**/\r
+UINTN\r
+EFIAPI\r
+GetIndexFromSupportedLangCodes(\r
+ IN CHAR8 *SupportedLang,\r
+ IN CHAR8 *Lang,\r
+ IN BOOLEAN Iso639Language\r
+ ) \r
+{\r
+ UINTN Index;\r
+ UINT32 CompareLength;\r
+ CHAR8 *Supported;\r
+\r
+ Index = 0;\r
+ Supported = SupportedLang;\r
+ if (Iso639Language) {\r
+ CompareLength = 3;\r
+ for (Index = 0; Index < AsciiStrLen (SupportedLang); Index += CompareLength) {\r
+ if (AsciiStrnCmp (Lang, SupportedLang + Index, CompareLength) == 0) {\r
+ //\r
+ // Successfully find the index of Lang string in SupportedLang string.\r
+ //\r
+ Index = Index / CompareLength;\r
+ return Index;\r
+ }\r
+ }\r
+ ASSERT (FALSE);\r
+ return 0;\r
} else {\r
- *DataSize = VarDataSize;\r
- Status = EFI_BUFFER_TOO_SMALL;\r
- goto Done;\r
+ //\r
+ // Compare RFC4646 language code\r
+ //\r
+ while (*Supported != '\0') {\r
+ //\r
+ // take semicolon as delimitation, sequentially traverse supported language codes.\r
+ //\r
+ for (CompareLength = 0; *Supported != ';' && *Supported != '\0'; CompareLength++) {\r
+ Supported++;\r
+ }\r
+ if (AsciiStrnCmp (Lang, Supported - CompareLength, CompareLength) == 0) {\r
+ //\r
+ // Successfully find the index of Lang string in SupportedLang string.\r
+ //\r
+ return Index;\r
+ }\r
+ Index++;\r
+ }\r
+ ASSERT (FALSE);\r
+ return 0;\r
}\r
+}\r
\r
-Done:\r
- ReleaseLockOnlyAtBootTime (&Global->VariableServicesLock);\r
- return Status;\r
+/**\r
+ Get language string from supported language codes according to index.\r
+\r
+ This code is used to get corresponding language string in supported language codes. It can handle\r
+ RFC4646 and ISO639 language tags.\r
+ In ISO639 language tags, take 3-characters as a delimitation. Find language string according to the index.\r
+ In RFC4646 language tags, take semicolon as a delimitation. Find language string according to the index.\r
+\r
+ For example:\r
+ SupportedLang = "engfraengfra"\r
+ Index = "1"\r
+ Iso639Language = TRUE\r
+ The return value is "fra".\r
+ Another example:\r
+ SupportedLang = "en;fr;en-US;fr-FR"\r
+ Index = "1"\r
+ Iso639Language = FALSE\r
+ The return value is "fr".\r
+\r
+ @param SupportedLang Platform supported language codes.\r
+ @param Index the index in supported language codes.\r
+ @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646.\r
+\r
+ @retval the language string in the language codes.\r
+\r
+**/\r
+CHAR8 *\r
+EFIAPI\r
+GetLangFromSupportedLangCodes (\r
+ IN CHAR8 *SupportedLang,\r
+ IN UINTN Index,\r
+ IN BOOLEAN Iso639Language\r
+)\r
+{\r
+ UINTN SubIndex;\r
+ UINT32 CompareLength;\r
+ CHAR8 *Supported;\r
+\r
+ SubIndex = 0;\r
+ Supported = SupportedLang;\r
+ if (Iso639Language) {\r
+ //\r
+ // according to the index of Lang string in SupportedLang string to get the language.\r
+ // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation.\r
+ // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.\r
+ //\r
+ CompareLength = 3;\r
+ SetMem (mVariableModuleGlobal->Lang, sizeof(mVariableModuleGlobal->Lang), 0);\r
+ return CopyMem (mVariableModuleGlobal->Lang, SupportedLang + Index * CompareLength, CompareLength);\r
+ \r
+ } else {\r
+ while (TRUE) {\r
+ //\r
+ // take semicolon as delimitation, sequentially traverse supported language codes.\r
+ //\r
+ for (CompareLength = 0; *Supported != ';' && *Supported != '\0'; CompareLength++) {\r
+ Supported++;\r
+ }\r
+ if ((*Supported == '\0') && (SubIndex != Index)) {\r
+ //\r
+ // Have completed the traverse, but not find corrsponding string.\r
+ // This case is not allowed to happen.\r
+ //\r
+ ASSERT(FALSE);\r
+ return NULL;\r
+ }\r
+ if (SubIndex == Index) {\r
+ //\r
+ // according to the index of Lang string in SupportedLang string to get the language.\r
+ // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation.\r
+ // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.\r
+ //\r
+ SetMem (mVariableModuleGlobal->PlatformLang, sizeof (mVariableModuleGlobal->PlatformLang), 0);\r
+ return CopyMem (mVariableModuleGlobal->PlatformLang, Supported - CompareLength, CompareLength);\r
+ }\r
+ SubIndex++;\r
+ }\r
+ }\r
}\r
\r
+/**\r
+ Hook the operations in PlatformLangCodes, LangCodes, PlatformLang and Lang.\r
+\r
+ When setting Lang/LangCodes, simultaneously update PlatformLang/PlatformLangCodes.\r
+\r
+ According to UEFI spec, PlatformLangCodes/LangCodes are only set once in firmware initialization,\r
+ and are read-only. Therefore, in variable driver, only store the original value for other use.\r
+\r
+ @param[in] VariableName Name of variable\r
+\r
+ @param[in] Data Variable data\r
+\r
+ @param[in] DataSize Size of data. 0 means delete\r
+\r
+ @retval EFI_SUCCESS auto update operation is successful.\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
+AutoUpdateLangVariable(\r
+ IN CHAR16 *VariableName,\r
+ IN VOID *Data,\r
+ IN UINTN DataSize\r
)\r
-/*++\r
+{\r
+ EFI_STATUS Status;\r
+ CHAR8 *BestPlatformLang;\r
+ CHAR8 *BestLang;\r
+ UINTN Index;\r
+ UINT32 Attributes;\r
+ VARIABLE_POINTER_TRACK Variable;\r
\r
-Routine Description:\r
+ //\r
+ // According to UEFI spec, "Lang" and "PlatformLang" is NV|BS|RT attributions.\r
+ //\r
+ Attributes = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;\r
\r
- This code Finds the Next available variable\r
+ if (StrCmp (VariableName, L"PlatformLangCodes") == 0) {\r
+ //\r
+ // According to UEFI spec, PlatformLangCodes is only set once in firmware initialization, and is read-only\r
+ // Therefore, in variable driver, only store the original value for other use.\r
+ //\r
+ AsciiStrnCpy (mVariableModuleGlobal->PlatformLangCodes, Data, DataSize);\r
+ } else if (StrCmp (VariableName, L"LangCodes") == 0) {\r
+ //\r
+ // According to UEFI spec, LangCodes is only set once in firmware initialization, and is read-only\r
+ // Therefore, in variable driver, only store the original value for other use.\r
+ //\r
+ AsciiStrnCpy (mVariableModuleGlobal->LangCodes, Data, DataSize);\r
+ } else if ((StrCmp (VariableName, L"PlatformLang") == 0) && (DataSize != 0)) {\r
+ ASSERT (AsciiStrLen (mVariableModuleGlobal->PlatformLangCodes) != 0);\r
\r
-Arguments:\r
+ //\r
+ // When setting PlatformLang, firstly get most matched language string from supported language codes.\r
+ //\r
+ BestPlatformLang = GetBestLanguage(mVariableModuleGlobal->PlatformLangCodes, FALSE, Data, NULL);\r
\r
- VariableNameSize Size of the variable\r
- VariableName Pointer to variable name\r
- VendorGuid Variable Vendor Guid\r
- Global VARIABLE_GLOBAL structure pointer.\r
- Instance FV instance\r
+ //\r
+ // Get the corresponding index in language codes.\r
+ //\r
+ Index = GetIndexFromSupportedLangCodes(mVariableModuleGlobal->PlatformLangCodes, BestPlatformLang, FALSE);\r
\r
-Returns:\r
+ //\r
+ // Get the corresponding ISO639 language tag according to RFC4646 language tag.\r
+ //\r
+ BestLang = GetLangFromSupportedLangCodes(mVariableModuleGlobal->LangCodes, Index, TRUE);\r
\r
- EFI STATUS\r
+ //\r
+ // Successfully convert PlatformLang to Lang, and set the BestLang value into Lang variable simultaneously.\r
+ //\r
+ FindVariable(L"Lang", &gEfiGlobalVariableGuid, &Variable, (VARIABLE_GLOBAL *)mVariableModuleGlobal);\r
\r
---*/\r
-{\r
- VARIABLE_POINTER_TRACK Variable;\r
- UINTN VarNameSize;\r
- EFI_STATUS Status;\r
+ Status = UpdateVariable(L"Lang", &gEfiGlobalVariableGuid, \r
+ BestLang, ISO_639_2_ENTRY_SIZE + 1, Attributes, &Variable);\r
\r
- if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
+ DEBUG((EFI_D_INFO, "Variable Driver Auto Update PlatformLang, PlatformLang:%a, Lang:%a\n", BestPlatformLang, BestLang));\r
\r
- Status = FindVariable (VariableName, VendorGuid, &Variable, Global);\r
+ ASSERT_EFI_ERROR(Status);\r
+ \r
+ } else if ((StrCmp (VariableName, L"Lang") == 0) && (DataSize != 0)) {\r
+ ASSERT (AsciiStrLen (mVariableModuleGlobal->LangCodes) != 0);\r
\r
- if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {\r
- goto Done;\r
- }\r
+ //\r
+ // When setting Lang, firstly get most matched language string from supported language codes.\r
+ //\r
+ BestLang = GetBestLanguage(mVariableModuleGlobal->LangCodes, TRUE, Data, NULL);\r
\r
- if (VariableName[0] != 0) {\r
//\r
- // If variable name is not NULL, get next variable\r
+ // Get the corresponding index in language codes.\r
//\r
- Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);\r
- }\r
+ Index = GetIndexFromSupportedLangCodes(mVariableModuleGlobal->LangCodes, BestLang, TRUE);\r
\r
- while (TRUE) {\r
//\r
- // If both volatile and non-volatile variable store are parsed,\r
- // return not found\r
+ // Get the corresponding RFC4646 language tag according to ISO639 language tag.\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
- } else {\r
- Status = EFI_NOT_FOUND;\r
- goto Done;\r
- }\r
+ BestPlatformLang = GetLangFromSupportedLangCodes(mVariableModuleGlobal->PlatformLangCodes, Index, FALSE);\r
\r
- Variable.CurrPtr = Variable.StartPtr;\r
- if (!IsValidVariableHeader (Variable.CurrPtr)) {\r
- continue;\r
- }\r
- }\r
//\r
- // Variable is found\r
+ // Successfully convert Lang to PlatformLang, and set the BestPlatformLang value into PlatformLang variable simultaneously.\r
//\r
- if (IsValidVariableHeader (Variable.CurrPtr) && Variable.CurrPtr->State == VAR_ADDED) {\r
- if (!(EfiAtRuntime () && !(Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS))) {\r
- VarNameSize = Variable.CurrPtr->NameSize;\r
- if (VarNameSize <= *VariableNameSize) {\r
- CopyMem (\r
- VariableName,\r
- GET_VARIABLE_NAME_PTR (Variable.CurrPtr),\r
- VarNameSize\r
- );\r
- CopyMem (\r
- VendorGuid,\r
- &Variable.CurrPtr->VendorGuid,\r
- sizeof (EFI_GUID)\r
- );\r
- Status = EFI_SUCCESS;\r
- } else {\r
- Status = EFI_BUFFER_TOO_SMALL;\r
- }\r
+ FindVariable(L"PlatformLang", &gEfiGlobalVariableGuid, &Variable, (VARIABLE_GLOBAL *)mVariableModuleGlobal);\r
\r
- *VariableNameSize = VarNameSize;\r
- goto Done;\r
- }\r
- }\r
+ Status = UpdateVariable(L"PlatformLang", &gEfiGlobalVariableGuid, \r
+ BestPlatformLang, AsciiStrSize (BestPlatformLang), Attributes, &Variable);\r
\r
- Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);\r
+ DEBUG((EFI_D_INFO, "Variable Driver Auto Update Lang, Lang:%a, PlatformLang:%a\n", BestLang, BestPlatformLang));\r
+ ASSERT_EFI_ERROR(Status);\r
}\r
-\r
-Done:\r
- ReleaseLockOnlyAtBootTime (&Global->VariableServicesLock);\r
- return Status;\r
+ return EFI_SUCCESS;\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
-Routine Description:\r
+/**\r
+ Update the variable region with Variable information. These are the same \r
+ arguments as the EFI Variable services.\r
\r
- This code sets variable in storage blocks (Volatile or Non-Volatile)\r
+ @param[in] VariableName Name of variable\r
\r
-Arguments:\r
+ @param[in] VendorGuid Guid of variable\r
\r
- VariableName Name of Variable to be found\r
- VendorGuid Variable vendor GUID\r
- Attributes 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
- VolatileOffset The offset of last volatile variable\r
- NonVolatileOffset The offset of last non-volatile variable\r
- Instance Instance of the Firmware Volume.\r
+ @param[in] Data Variable data\r
\r
-Returns:\r
+ @param[in] DataSize Size of data. 0 means delete\r
\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
+ @param[in] Attributes Attribues of the variable\r
\r
---*/\r
-{\r
- VARIABLE_POINTER_TRACK Variable;\r
- EFI_STATUS Status;\r
- VARIABLE_HEADER *NextVariable;\r
- UINTN VarNameSize;\r
- UINTN VarNameOffset;\r
- UINTN VarDataOffset;\r
- UINTN VarSize;\r
- UINT8 State;\r
- BOOLEAN Reclaimed;\r
+ @param[in] Variable The variable information which is used to keep track of variable usage.\r
\r
- Reclaimed = FALSE;\r
+ @retval EFI_SUCCESS The update operation is success.\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
- // 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, Global);\r
+ @retval EFI_OUT_OF_RESOURCES Variable region is full, can not write other data into this region.\r
\r
- if (Status == EFI_SUCCESS && Variable.CurrPtr != NULL) {\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UpdateVariable (\r
+ IN CHAR16 *VariableName,\r
+ IN EFI_GUID *VendorGuid,\r
+ IN VOID *Data,\r
+ IN UINTN DataSize,\r
+ IN UINT32 Attributes OPTIONAL,\r
+ IN VARIABLE_POINTER_TRACK *Variable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ VARIABLE_HEADER *NextVariable;\r
+ UINTN ScratchSize;\r
+ UINTN NonVolatileVarableStoreSize;\r
+ UINTN VarNameOffset;\r
+ UINTN VarDataOffset;\r
+ UINTN VarNameSize;\r
+ UINTN VarSize;\r
+ BOOLEAN Volatile;\r
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;\r
+ UINT8 State;\r
+ BOOLEAN Reclaimed;\r
+\r
+ Fvb = mVariableModuleGlobal->FvbInstance;\r
+ Reclaimed = FALSE;\r
+\r
+ if (Variable->CurrPtr != NULL) {\r
//\r
// Update/Delete existing variable\r
//\r
+ Volatile = Variable->Volatile;\r
\r
if (EfiAtRuntime ()) { \r
//\r
// the volatile is ReadOnly, and SetVariable should be aborted and \r
// return EFI_WRITE_PROTECTED.\r
//\r
- if (Variable.Volatile) {\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
+ if ((Variable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
Status = EFI_INVALID_PARAMETER;\r
goto Done; \r
}\r
// specified causes it to be deleted.\r
//\r
if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) { \r
- State = Variable.CurrPtr->State;\r
+ State = Variable->CurrPtr->State;\r
State &= VAR_DELETED;\r
\r
Status = UpdateVariableStore (\r
- Global,\r
- Variable.Volatile,\r
+ &mVariableModuleGlobal->VariableGlobal,\r
+ Variable->Volatile,\r
FALSE,\r
- Instance,\r
- (UINTN) &Variable.CurrPtr->State,\r
+ Fvb,\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
// If the variable is marked valid and the same data has been passed in\r
// then return to the caller immediately.\r
//\r
- if (Variable.CurrPtr->DataSize == DataSize &&\r
- (CompareMem (Data, GetVariableDataPtr (Variable.CurrPtr), DataSize) == 0)) {\r
+ if (DataSizeOfVariable (Variable->CurrPtr) == 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
+ } else if ((Variable->CurrPtr->State == VAR_ADDED) ||\r
+ (Variable->CurrPtr->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))) {\r
+\r
//\r
// Mark the old variable as in delete transition\r
//\r
- State = Variable.CurrPtr->State;\r
+ State = Variable->CurrPtr->State;\r
State &= VAR_IN_DELETED_TRANSITION;\r
\r
Status = UpdateVariableStore (\r
- Global,\r
- Variable.Volatile,\r
+ &mVariableModuleGlobal->VariableGlobal,\r
+ Variable->Volatile,\r
FALSE,\r
- Instance,\r
- (UINTN) &Variable.CurrPtr->State,\r
+ Fvb,\r
+ (UINTN) &Variable->CurrPtr->State,\r
sizeof (UINT8),\r
&State\r
); \r
if (EFI_ERROR (Status)) {\r
goto Done; \r
- }\r
+ } \r
} \r
- } else if (Status == EFI_NOT_FOUND) {\r
+ } else {\r
//\r
- // Create a new variable\r
+ // Not found existing variable. Create a new variable\r
// \r
\r
//\r
// Only variable have NV|RT attribute can be created in Runtime\r
//\r
if (EfiAtRuntime () &&\r
- (!(Attributes & EFI_VARIABLE_RUNTIME_ACCESS) || !(Attributes & EFI_VARIABLE_NON_VOLATILE))) {\r
+ (((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) || ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0))) {\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
- ASSERT (Status == EFI_INVALID_PARAMETER);\r
- goto Done;\r
}\r
\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
+ NextVariable = GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase));\r
+ ScratchSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize));\r
\r
- SetMem (NextVariable, SCRATCH_SIZE, 0xff);\r
+ SetMem (NextVariable, ScratchSize, 0xff);\r
\r
NextVariable->StartId = VARIABLE_DATA;\r
NextVariable->Attributes = Attributes;\r
// include pad size.\r
//\r
VarSize = VarDataOffset + DataSize + GET_PAD_SIZE (DataSize);\r
- if (Attributes & EFI_VARIABLE_NON_VOLATILE) {\r
+ if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {\r
//\r
// Create a nonvolatile variable\r
//\r
- \r
- if ((UINT32) (VarSize +*NonVolatileOffset) >\r
- ((VARIABLE_STORE_HEADER *) ((UINTN) (Global->NonVolatileVariableBase)))->Size\r
- ) {\r
+ Volatile = FALSE;\r
+ NonVolatileVarableStoreSize = ((VARIABLE_STORE_HEADER *)(UINTN)(mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase))->Size;\r
+ if ((((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) \r
+ && ((VarSize + mVariableModuleGlobal->HwErrVariableTotalSize) > PcdGet32 (PcdHwErrStorageSize)))\r
+ || (((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0) \r
+ && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > NonVolatileVarableStoreSize - sizeof (VARIABLE_STORE_HEADER) - PcdGet32 (PcdHwErrStorageSize)))) {\r
if (EfiAtRuntime ()) {\r
Status = EFI_OUT_OF_RESOURCES;\r
goto Done;\r
//\r
// Perform garbage collection & reclaim operation\r
//\r
- Status = Reclaim (Global->NonVolatileVariableBase, NonVolatileOffset, FALSE);\r
+ Status = Reclaim (mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase, \r
+ &mVariableModuleGlobal->NonVolatileLastVariableOffset, FALSE, Variable->CurrPtr);\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
+ if ((((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) \r
+ && ((VarSize + mVariableModuleGlobal->HwErrVariableTotalSize) > PcdGet32 (PcdHwErrStorageSize)))\r
+ || (((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0) \r
+ && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > NonVolatileVarableStoreSize - sizeof (VARIABLE_STORE_HEADER) - PcdGet32 (PcdHwErrStorageSize)))) {\r
Status = EFI_OUT_OF_RESOURCES;\r
goto Done;\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
+ // 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
- Global,\r
+ &mVariableModuleGlobal->VariableGlobal,\r
FALSE,\r
TRUE,\r
- Instance,\r
- *NonVolatileOffset,\r
+ Fvb,\r
+ mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
sizeof (VARIABLE_HEADER),\r
(UINT8 *) NextVariable\r
);\r
if (EFI_ERROR (Status)) {\r
goto Done;\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,\r
+ sizeof (VARIABLE_HEADER),\r
+ (UINT8 *) NextVariable\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 + 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
+ // Step 4:\r
+ //\r
+ NextVariable->State = VAR_ADDED;\r
+ Status = UpdateVariableStore (\r
+ &mVariableModuleGlobal->VariableGlobal,\r
+ FALSE,\r
+ TRUE,\r
+ Fvb,\r
+ mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
+ sizeof (VARIABLE_HEADER),\r
+ (UINT8 *) NextVariable\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ mVariableModuleGlobal->NonVolatileLastVariableOffset += HEADER_ALIGN (VarSize);\r
+\r
+ if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) {\r
+ mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VarSize);\r
+ } else {\r
+ mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VarSize);\r
+ }\r
+ } else {\r
+ //\r
+ // Create a volatile variable\r
+ // \r
+ Volatile = TRUE;\r
+\r
+ if ((UINT32) (VarSize + mVariableModuleGlobal->VolatileLastVariableOffset) >\r
+ ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase)))->Size) {\r
+ //\r
+ // Perform garbage collection & reclaim operation\r
+ //\r
+ Status = Reclaim (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase, \r
+ &mVariableModuleGlobal->VolatileLastVariableOffset, TRUE, Variable->CurrPtr);\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 + mVariableModuleGlobal->VolatileLastVariableOffset) >\r
+ ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase)))->Size\r
+ ) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Done;\r
+ }\r
+ Reclaimed = TRUE;\r
+ }\r
+\r
+ NextVariable->State = VAR_ADDED;\r
+ Status = UpdateVariableStore (\r
+ &mVariableModuleGlobal->VariableGlobal,\r
+ TRUE,\r
+ TRUE,\r
+ Fvb,\r
+ mVariableModuleGlobal->VolatileLastVariableOffset,\r
+ (UINT32) VarSize,\r
+ (UINT8 *) NextVariable\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ mVariableModuleGlobal->VolatileLastVariableOffset += HEADER_ALIGN (VarSize);\r
+ }\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
+ Fvb,\r
+ (UINTN) &Variable->CurrPtr->State,\r
+ sizeof (UINT8),\r
+ &State\r
+ );\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
+\r
+Done:\r
+ return Status;\r
+}\r
+\r
+/**\r
+\r
+ This code finds variable in storage blocks (Volatile or Non-Volatile).\r
+\r
+ @param VariableName Name of Variable to be found.\r
+ @param VendorGuid Variable vendor GUID.\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
+ \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
+\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
+\r
+ if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\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
+ goto Done;\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
+ VarDataSize = DataSizeOfVariable (Variable.CurrPtr);\r
+ ASSERT (VarDataSize != 0);\r
+\r
+ if (*DataSize >= VarDataSize) {\r
+ if (Data == NULL) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto Done;\r
+ }\r
+\r
+ CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr), VarDataSize);\r
+ if (Attributes != NULL) {\r
+ *Attributes = Variable.CurrPtr->Attributes;\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
+ *DataSize = VarDataSize;\r
+ Status = EFI_BUFFER_TOO_SMALL;\r
+ goto Done;\r
+ }\r
+\r
+Done:\r
+ ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
+ return Status;\r
+}\r
+\r
+\r
+\r
+/**\r
+\r
+ This code Finds the Next available variable.\r
+\r
+ @param VariableNameSize Size of the variable name\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
+\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
+ EFI_STATUS Status;\r
+\r
+ if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
+\r
+ Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);\r
+ if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ if (VariableName[0] != 0) {\r
+ //\r
+ // If variable name is not NULL, get next variable\r
+ //\r
+ Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);\r
+ }\r
+\r
+ while (TRUE) {\r
+ //\r
+ // If both volatile and non-volatile variable store are parsed,\r
+ // return not found\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 = GetStartPointer ((VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);\r
+ Variable.EndPtr = GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase));\r
+ } else {\r
+ Status = EFI_NOT_FOUND;\r
+ goto Done;\r
+ }\r
+\r
+ Variable.CurrPtr = Variable.StartPtr;\r
+ if (!IsValidVariableHeader (Variable.CurrPtr)) {\r
+ continue;\r
+ }\r
+ }\r
+ //\r
+ // Variable is found\r
+ //\r
+ if (IsValidVariableHeader (Variable.CurrPtr) && Variable.CurrPtr->State == VAR_ADDED) {\r
+ if ((EfiAtRuntime () && ((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) == 0) {\r
+ VarNameSize = NameSizeOfVariable (Variable.CurrPtr);\r
+ ASSERT (VarNameSize != 0);\r
+\r
+ if (VarNameSize <= *VariableNameSize) {\r
+ CopyMem (\r
+ VariableName,\r
+ GetVariableNamePtr (Variable.CurrPtr),\r
+ VarNameSize\r
+ );\r
+ CopyMem (\r
+ VendorGuid,\r
+ &Variable.CurrPtr->VendorGuid,\r
+ sizeof (EFI_GUID)\r
+ );\r
+ Status = EFI_SUCCESS;\r
+ } else {\r
+ Status = EFI_BUFFER_TOO_SMALL;\r
+ }\r
+\r
+ *VariableNameSize = VarNameSize;\r
+ goto Done;\r
+ }\r
+ }\r
+\r
+ Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);\r
+ }\r
+\r
+Done:\r
+ ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
+ return Status;\r
+}\r
+\r
+/**\r
+\r
+ This code sets variable in storage blocks (Volatile or Non-Volatile).\r
+\r
+ @param VariableName Name of Variable to be found\r
+ @param VendorGuid Variable vendor GUID\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
+\r
+ @return EFI_INVALID_PARAMETER Invalid parameter\r
+ @return EFI_SUCCESS Set successfully\r
+ @return EFI_OUT_OF_RESOURCES Resource not enough to set variable\r
+ @return EFI_NOT_FOUND Not found\r
+ @return 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
+ VARIABLE_HEADER *NextVariable;\r
+ EFI_PHYSICAL_ADDRESS Point;\r
+\r
+ //\r
+ // Check input parameters\r
+ //\r
+ if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (DataSize != 0 && Data == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Not support authenticated variable write yet.\r
+ //\r
+ if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\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
+ //\r
+ // The size of the VariableName, including the Unicode Null in bytes plus\r
+ // the DataSize is limited to maximum size of PcdGet32 (PcdMaxHardwareErrorVariableSize)\r
+ // bytes for HwErrRec, and PcdGet32 (PcdMaxVariableSize) bytes for the others.\r
+ //\r
+ if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
+ if ((DataSize > PcdGet32 (PcdMaxHardwareErrorVariableSize)) ||\r
+ (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > PcdGet32 (PcdMaxHardwareErrorVariableSize))) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
//\r
- // Step 2:\r
+ // According to UEFI spec, HARDWARE_ERROR_RECORD variable name convention should be L"HwErrRecXXXX"\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
- if (EFI_ERROR (Status)) {\r
- goto Done;\r
+ if (StrnCmp(VariableName, L"HwErrRec", StrLen(L"HwErrRec")) != 0) {\r
+ return EFI_INVALID_PARAMETER;\r
}\r
+ } else {\r
//\r
- // Step 3:\r
+ // The size of the VariableName, including the Unicode Null in bytes plus\r
+ // the DataSize is limited to maximum size of PcdGet32 (PcdMaxVariableSize) bytes.\r
//\r
- 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
+ if ((DataSize > PcdGet32 (PcdMaxVariableSize)) ||\r
+ (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > PcdGet32 (PcdMaxVariableSize))) {\r
+ return EFI_INVALID_PARAMETER;\r
+ } \r
+ } \r
\r
- *NonVolatileOffset = *NonVolatileOffset + VarSize;\r
+ AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
\r
- } else {\r
+ //\r
+ // Consider reentrant in MCA/INIT/NMI. It needs be reupdated;\r
+ //\r
+ if (1 < InterlockedIncrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState)) {\r
+ Point = mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;;\r
//\r
- // Create a volatile variable\r
- // \r
-\r
- if ((UINT32) (VarSize +*VolatileOffset) >\r
- ((VARIABLE_STORE_HEADER *) ((UINTN) (Global->VolatileVariableBase)))->Size) {\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
+ // Parse non-volatile variable data and get last variable offset\r
+ //\r
+ NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *) (UINTN) Point);\r
+ while ((NextVariable < GetEndPointer ((VARIABLE_STORE_HEADER *) (UINTN) Point)) \r
+ && IsValidVariableHeader (NextVariable)) {\r
+ NextVariable = GetNextVariablePtr (NextVariable);\r
}\r
+ mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) Point;\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
- goto Done;\r
- }\r
+ //\r
+ // Check whether the input variable is already existed\r
+ //\r
+ FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);\r
\r
- *VolatileOffset = *VolatileOffset + VarSize;\r
- }\r
//\r
- // Mark the old variable as deleted\r
+ // Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang\r
//\r
- if (!Reclaimed && !EFI_ERROR (Status) && Variable.CurrPtr != NULL) {\r
- State = Variable.CurrPtr->State;\r
- State &= VAR_DELETED;\r
+ AutoUpdateLangVariable (VariableName, Data, DataSize);\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
- goto Done; \r
- }\r
+ Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, &Variable);\r
+\r
+ InterlockedDecrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState);\r
+ ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
\r
- Status = EFI_SUCCESS;\r
-Done:\r
- ReleaseLockOnlyAtBootTime (&Global->VariableServicesLock);\r
return Status;\r
}\r
\r
+/**\r
+\r
+ This code returns information about the EFI variables.\r
+\r
+ @param Attributes Attributes bitmask to specify the type of variables\r
+ on which to return information.\r
+ @param MaximumVariableStorageSize Pointer to the maximum size of the storage space available\r
+ for the EFI variables associated with the attributes specified.\r
+ @param RemainingVariableStorageSize Pointer to the remaining size of the storage space available\r
+ for EFI variables associated with the attributes specified.\r
+ @param MaximumVariableSize Pointer to the maximum size of an individual EFI variables\r
+ associated with the attributes specified.\r
+\r
+ @return EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.\r
+ @return EFI_SUCCESS Query successfully.\r
+ @return EFI_UNSUPPORTED The attribute is not supported on this platform.\r
+\r
+**/\r
EFI_STATUS\r
EFIAPI\r
-QueryVariableInfo (\r
+RuntimeServiceQueryVariableInfo (\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
+ OUT UINT64 *MaximumVariableSize\r
)\r
-/*++\r
-\r
-Routine Description:\r
-\r
- This code returns information about the EFI variables.\r
-\r
-Arguments:\r
-\r
- Attributes Attributes bitmask to specify the type of variables\r
- on which to return information.\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 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
-\r
-Returns:\r
-\r
- EFI STATUS\r
- EFI_INVALID_PARAMETER - An invalid combination of attribute bits was supplied.\r
- EFI_SUCCESS - Query successfully.\r
- EFI_UNSUPPORTED - The attribute is not supported on this platform.\r
-\r
---*/\r
{\r
VARIABLE_HEADER *Variable;\r
VARIABLE_HEADER *NextVariable;\r
UINT64 VariableSize;\r
VARIABLE_STORE_HEADER *VariableStoreHeader;\r
+ UINT64 CommonVariableTotalSize;\r
+ UINT64 HwErrVariableTotalSize;\r
+\r
+ CommonVariableTotalSize = 0;\r
+ HwErrVariableTotalSize = 0;\r
\r
if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {\r
return EFI_INVALID_PARAMETER;\r
}\r
- \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
// Make sure if runtime bit is set, boot service bit is set also.\r
//\r
return EFI_INVALID_PARAMETER;\r
- } else if (EfiAtRuntime () && !(Attributes & EFI_VARIABLE_RUNTIME_ACCESS)) {\r
+ } else if (EfiAtRuntime () && ((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) {\r
//\r
// Make sure RT Attribute is set if we are in Runtime phase.\r
//\r
return EFI_INVALID_PARAMETER;\r
+ } else if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
+ //\r
+ // Make sure Hw Attribute is set with NV.\r
+ //\r
+ return EFI_INVALID_PARAMETER;\r
+ } else if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
+ //\r
+ // Not support authentiated variable write yet.\r
+ //\r
+ return EFI_UNSUPPORTED;\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
// with the storage size (excluding the storage header size).\r
//\r
*MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);\r
- *RemainingVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);\r
-\r
- //\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
- if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
- *MaximumVariableSize = MAX_HARDWARE_ERROR_VARIABLE_SIZE - sizeof (VARIABLE_HEADER);\r
+ if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+ *MaximumVariableStorageSize = PcdGet32 (PcdHwErrStorageSize);\r
+ *MaximumVariableSize = PcdGet32 (PcdMaxHardwareErrorVariableSize) - sizeof (VARIABLE_HEADER);\r
+ } else {\r
+ if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {\r
+ ASSERT (PcdGet32 (PcdHwErrStorageSize) < VariableStoreHeader->Size);\r
+ *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER) - PcdGet32 (PcdHwErrStorageSize);\r
+ }\r
+\r
+ //\r
+ // Let *MaximumVariableSize be PcdGet32 (PcdMaxVariableSize) with the exception of the variable header size.\r
+ //\r
+ *MaximumVariableSize = PcdGet32 (PcdMaxVariableSize) - sizeof (VARIABLE_HEADER);\r
}\r
\r
//\r
// Point to the starting address of the variables.\r
//\r
- Variable = (VARIABLE_HEADER *) (VariableStoreHeader + 1);\r
+ Variable = GetStartPointer (VariableStoreHeader);\r
\r
//\r
// Now walk through the related variable store.\r
//\r
- while (IsValidVariableHeader (Variable) && (Variable < GetEndPointer (VariableStoreHeader))) {\r
+ while ((Variable < GetEndPointer (VariableStoreHeader)) && IsValidVariableHeader (Variable)) {\r
NextVariable = GetNextVariablePtr (Variable);\r
VariableSize = (UINT64) (UINTN) NextVariable - (UINT64) (UINTN) Variable;\r
\r
// since the space occupied by variables not marked with\r
// VAR_ADDED is not allowed to be reclaimed in Runtime.\r
//\r
- *RemainingVariableStorageSize -= VariableSize;\r
+ if ((NextVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
+ HwErrVariableTotalSize += VariableSize;\r
+ } else {\r
+ CommonVariableTotalSize += VariableSize;\r
+ }\r
} else {\r
//\r
// Only care about Variables with State VAR_ADDED,because\r
// the space not marked as VAR_ADDED is reclaimable now.\r
//\r
if (Variable->State == VAR_ADDED) {\r
- *RemainingVariableStorageSize -= VariableSize;\r
+ if ((NextVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
+ HwErrVariableTotalSize += VariableSize;\r
+ } else {\r
+ CommonVariableTotalSize += VariableSize;\r
+ }\r
}\r
}\r
\r
Variable = NextVariable;\r
}\r
\r
+ if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD){\r
+ *RemainingVariableStorageSize = *MaximumVariableStorageSize - HwErrVariableTotalSize;\r
+ }else {\r
+ *RemainingVariableStorageSize = *MaximumVariableStorageSize - CommonVariableTotalSize;\r
+ }\r
+\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 (&Global->VariableServicesLock);\r
+ ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
return EFI_SUCCESS;\r
}\r
\r
-EFI_STATUS\r
+\r
+/**\r
+ Notification function of EVT_GROUP_READY_TO_BOOT event group.\r
+\r
+ This is a notification function registered on EVT_GROUP_READY_TO_BOOT event group.\r
+ When the Boot Manager is about to load and execute a boot option, it reclaims variable\r
+ storage if free size is below the threshold.\r
+\r
+ @param Event Event whose notification function is being invoked\r
+ @param Context Pointer to the notification function's context\r
+\r
+**/\r
+VOID\r
EFIAPI\r
-VariableCommonInitialize (\r
- IN EFI_HANDLE ImageHandle,\r
- IN EFI_SYSTEM_TABLE *SystemTable\r
+ReclaimForOS(\r
+ EFI_EVENT Event,\r
+ VOID *Context\r
)\r
-/*++\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN CommonVariableSpace;\r
+ UINTN RemainingCommonVariableSpace;\r
+ UINTN RemainingHwErrVariableSpace;\r
+\r
+ Status = EFI_SUCCESS; \r
\r
-Routine Description:\r
- This function does common initialization for variable services\r
+ CommonVariableSpace = ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase)))->Size - sizeof (VARIABLE_STORE_HEADER) - PcdGet32(PcdHwErrStorageSize); //Allowable max size of common variable storage space\r
\r
-Arguments:\r
+ RemainingCommonVariableSpace = CommonVariableSpace - mVariableModuleGlobal->CommonVariableTotalSize;\r
\r
- ImageHandle - The firmware allocated handle for the EFI image.\r
- SystemTable - A pointer to the EFI System Table.\r
+ RemainingHwErrVariableSpace = PcdGet32 (PcdHwErrStorageSize) - mVariableModuleGlobal->HwErrVariableTotalSize;\r
+ //\r
+ // Check if the free area is blow a threshold.\r
+ //\r
+ if ((RemainingCommonVariableSpace < PcdGet32 (PcdMaxVariableSize))\r
+ || ((PcdGet32 (PcdHwErrStorageSize) != 0) && \r
+ (RemainingHwErrVariableSpace < PcdGet32 (PcdMaxHardwareErrorVariableSize)))){\r
+ Status = Reclaim (\r
+ mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
+ &mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
+ FALSE,\r
+ NULL\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+}\r
\r
-Returns:\r
+/**\r
+ Initializes variable store area for non-volatile and volatile variable.\r
\r
- Status code.\r
+ @param FvbProtocol Pointer to an instance of EFI Firmware Volume Block Protocol.\r
\r
- EFI_NOT_FOUND - Variable store area not found.\r
- EFI_UNSUPPORTED - Currently only one non-volatile variable store is supported.\r
- EFI_SUCCESS - Variable services successfully initialized.\r
+ @retval EFI_SUCCESS Function successfully executed.\r
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.\r
\r
---*/\r
+**/\r
+EFI_STATUS\r
+VariableCommonInitialize (\r
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol\r
+ )\r
{\r
EFI_STATUS Status;\r
- EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
- CHAR8 *CurrPtr;\r
VARIABLE_STORE_HEADER *VolatileVariableStore;\r
VARIABLE_STORE_HEADER *VariableStoreHeader;\r
VARIABLE_HEADER *NextVariable;\r
- UINT32 Instance;\r
- EFI_PHYSICAL_ADDRESS FvVolHdr;\r
- UINT64 TempVariableStoreHeader;\r
+ EFI_PHYSICAL_ADDRESS TempVariableStoreHeader;\r
EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;\r
- EFI_FLASH_SUBAREA_ENTRY VariableStoreEntry;\r
- UINT64 BaseAddress;\r
+ EFI_PHYSICAL_ADDRESS BaseAddress;\r
UINT64 Length;\r
UINTN Index;\r
UINT8 Data;\r
+ EFI_PHYSICAL_ADDRESS VariableStoreBase;\r
+ UINT64 VariableStoreLength;\r
+ EFI_EVENT ReadyToBootEvent;\r
+ UINTN ScratchSize;\r
+ UINTN VariableSize;\r
\r
- mVariableModuleGlobal = AllocateRuntimePool (sizeof (ESAL_VARIABLE_GLOBAL));\r
+ Status = EFI_SUCCESS;\r
+ //\r
+ // Allocate runtime memory for variable driver global structure.\r
+ //\r
+ mVariableModuleGlobal = AllocateRuntimeZeroPool (sizeof (VARIABLE_MODULE_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
+ // Note that in EdkII variable driver implementation, Hardware Error Record type variable\r
+ // is stored with common variable in the same NV region. So the platform integrator should\r
+ // ensure that the value of PcdHwErrStorageSize is less than or equal to the value of \r
+ // PcdFlashNvStorageVariableSize.\r
+ //\r
+ ASSERT (PcdGet32 (PcdHwErrStorageSize) <= PcdGet32 (PcdFlashNvStorageVariableSize));\r
\r
//\r
- // Allocate memory for volatile variable store\r
+ // Allocate memory for volatile variable store, note that there is a scratch space to store scratch data.\r
//\r
- VolatileVariableStore = AllocateRuntimePool (VARIABLE_STORE_SIZE + SCRATCH_SIZE);\r
+ ScratchSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize));\r
+ VolatileVariableStore = AllocateRuntimePool (PcdGet32 (PcdVariableStoreSize) + ScratchSize);\r
if (VolatileVariableStore == NULL) {\r
FreePool (mVariableModuleGlobal);\r
return EFI_OUT_OF_RESOURCES;\r
}\r
\r
- SetMem (VolatileVariableStore, VARIABLE_STORE_SIZE + SCRATCH_SIZE, 0xff);\r
+ SetMem (VolatileVariableStore, PcdGet32 (PcdVariableStoreSize) + ScratchSize, 0xff);\r
\r
//\r
// Variable Specific Data\r
//\r
- mVariableModuleGlobal->VariableGlobal[Physical].VolatileVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VolatileVariableStore;\r
- mVariableModuleGlobal->VolatileLastVariableOffset = sizeof (VARIABLE_STORE_HEADER);\r
+ mVariableModuleGlobal->VariableGlobal.VolatileVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VolatileVariableStore;\r
+ mVariableModuleGlobal->VolatileLastVariableOffset = (UINTN) GetStartPointer (VolatileVariableStore) - (UINTN) VolatileVariableStore;\r
+ mVariableModuleGlobal->FvbInstance = FvbProtocol;\r
\r
- VolatileVariableStore->Signature = VARIABLE_STORE_SIGNATURE;\r
- VolatileVariableStore->Size = VARIABLE_STORE_SIZE;\r
+ CopyGuid (&VolatileVariableStore->Signature, &gEfiVariableGuid);\r
+ VolatileVariableStore->Size = PcdGet32 (PcdVariableStoreSize);\r
VolatileVariableStore->Format = VARIABLE_STORE_FORMATTED;\r
VolatileVariableStore->State = VARIABLE_STORE_HEALTHY;\r
VolatileVariableStore->Reserved = 0;\r
// Get non volatile varaible store\r
//\r
\r
- TempVariableStoreHeader = (UINT64) PcdGet32 (PcdFlashNvStorageVariableBase);\r
- VariableStoreEntry.Base = TempVariableStoreHeader + \\r
- (((EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (TempVariableStoreHeader)) -> HeaderLength);\r
- VariableStoreEntry.Length = (UINT64) PcdGet32 (PcdFlashNvStorageVariableSize) - \\r
- (((EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (TempVariableStoreHeader)) -> HeaderLength);\r
+ TempVariableStoreHeader = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);\r
+ VariableStoreBase = TempVariableStoreHeader + \\r
+ (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader)) -> HeaderLength);\r
+ VariableStoreLength = (UINT64) PcdGet32 (PcdFlashNvStorageVariableSize) - \\r
+ (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader)) -> HeaderLength);\r
//\r
// 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
if (EFI_ERROR (Status)) {\r
- FreePool (mVariableModuleGlobal);\r
- FreePool (VolatileVariableStore);\r
- return EFI_UNSUPPORTED;\r
+ goto Done;\r
}\r
\r
Status = gDS->SetMemorySpaceAttributes (\r
GcdDescriptor.Attributes | EFI_MEMORY_RUNTIME\r
);\r
if (EFI_ERROR (Status)) {\r
- FreePool (mVariableModuleGlobal);\r
- FreePool (VolatileVariableStore);\r
- return EFI_UNSUPPORTED;\r
+ goto Done;\r
}\r
//\r
// Get address of non volatile variable store base\r
//\r
- mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase = VariableStoreEntry.Base;\r
-\r
- //\r
- // Check Integrity\r
- //\r
- //\r
- // Find the Correct Instance of the FV Block Service.\r
- //\r
- Instance = 0;\r
- CurrPtr = (CHAR8 *) ((UINTN) mVariableModuleGlobal->VariableGlobal[Physical].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
- mVariableModuleGlobal->FvbInstance = Instance;\r
- break;\r
- }\r
-\r
- Instance++;\r
- }\r
-\r
- VariableStoreHeader = (VARIABLE_STORE_HEADER *) CurrPtr;\r
+ mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;\r
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase;\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
+ goto Done;\r
}\r
}\r
\r
- mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase = (EFI_PHYSICAL_ADDRESS) ((UINTN) CurrPtr);\r
//\r
// Parse non-volatile variable data and get last variable offset\r
//\r
- NextVariable = (VARIABLE_HEADER *) (CurrPtr + sizeof (VARIABLE_STORE_HEADER));\r
+ NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase);\r
Status = EFI_SUCCESS;\r
\r
while (IsValidVariableHeader (NextVariable)) {\r
- NextVariable = GetNextVariablePtr (NextVariable);\r
- }\r
-\r
- mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) CurrPtr;\r
+ VariableSize = NextVariable->NameSize + NextVariable->DataSize + sizeof (VARIABLE_HEADER);\r
+ if ((NextVariable->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+ mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VariableSize);\r
+ } else {\r
+ mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VariableSize);\r
+ }\r
\r
- //\r
- // Check if the free area is blow a threshold\r
- //\r
- if ((((VARIABLE_STORE_HEADER *)((UINTN) CurrPtr))->Size - mVariableModuleGlobal->NonVolatileLastVariableOffset) < VARIABLE_RECLAIM_THRESHOLD) {\r
- Status = Reclaim (\r
- mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase,\r
- &mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
- FALSE\r
- );\r
+ NextVariable = GetNextVariablePtr (NextVariable);\r
}\r
\r
- if (EFI_ERROR (Status)) {\r
- FreePool (mVariableModuleGlobal);\r
- FreePool (VolatileVariableStore);\r
- return Status;\r
- }\r
+ mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) VariableStoreBase;\r
\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
+ FALSE,\r
+ NULL\r
);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
break;\r
}\r
}\r
+\r
+ //\r
+ // Register the event handling function to reclaim variable for OS usage.\r
+ //\r
+ Status = EfiCreateEventReadyToBootEx (\r
+ TPL_NOTIFY, \r
+ ReclaimForOS, \r
+ NULL, \r
+ &ReadyToBootEvent\r
+ );\r
+ } else {\r
+ Status = EFI_VOLUME_CORRUPTED;\r
+ DEBUG((EFI_D_INFO, "Variable Store header is corrupted\n"));\r
}\r
\r
+Done:\r
if (EFI_ERROR (Status)) {\r
FreePool (mVariableModuleGlobal);\r
FreePool (VolatileVariableStore);\r
\r
return Status;\r
}\r
+\r
+/**\r
+ Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE\r
+\r
+ This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.\r
+ It convers pointer to new virtual address.\r
+\r
+ @param Event Event whose notification function is being invoked\r
+ @param Context Pointer to the notification function's context\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+VariableClassAddressChangeEvent (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetBlockSize);\r
+ EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetPhysicalAddress);\r
+ EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetAttributes);\r
+ EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->SetAttributes);\r
+ EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Read);\r
+ EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Write);\r
+ EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->EraseBlocks);\r
+ EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance);\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
+ Firmware Volume Block Protocol notification event handler.\r
+\r
+ Discover NV Variable Store and install Variable Arch Protocol.\r
+\r
+ @param[in] Event Event whose notification function is being invoked.\r
+ @param[in] Context Pointer to the notification function's context.\r
+**/\r
+VOID\r
+EFIAPI\r
+FvbNotificationEvent (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_HANDLE *HandleBuffer;\r
+ UINTN HandleCount;\r
+ UINTN Index;\r
+ EFI_PHYSICAL_ADDRESS FvbBaseAddress;\r
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;\r
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
+ EFI_FVB_ATTRIBUTES_2 Attributes;\r
+ EFI_SYSTEM_TABLE *SystemTable;\r
+ EFI_PHYSICAL_ADDRESS NvStorageVariableBase;\r
+\r
+ SystemTable = (EFI_SYSTEM_TABLE *)Context;\r
+ Fvb = NULL;\r
+ \r
+ //\r
+ // Locate all handles of Fvb protocol\r
+ //\r
+ Status = gBS->LocateHandleBuffer (\r
+ ByProtocol,\r
+ &gEfiFirmwareVolumeBlockProtocolGuid,\r
+ NULL,\r
+ &HandleCount,\r
+ &HandleBuffer\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return ;\r
+ }\r
+ \r
+ //\r
+ // Get the FVB to access variable store\r
+ //\r
+ for (Index = 0; Index < HandleCount; Index += 1, Status = EFI_NOT_FOUND, Fvb = NULL) {\r
+ Status = gBS->HandleProtocol (\r
+ HandleBuffer[Index],\r
+ &gEfiFirmwareVolumeBlockProtocolGuid,\r
+ (VOID **) &Fvb\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ Status = EFI_NOT_FOUND;\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Ensure this FVB protocol supported Write operation.\r
+ //\r
+ Status = Fvb->GetAttributes (Fvb, &Attributes);\r
+ if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) {\r
+ continue; \r
+ }\r
+ //\r
+ // Compare the address and select the right one\r
+ //\r
+ Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+\r
+ FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress);\r
+ NvStorageVariableBase = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);\r
+ if ((NvStorageVariableBase >= FvbBaseAddress) && (NvStorageVariableBase < (FvbBaseAddress + FwVolHeader->FvLength))) {\r
+ Status = EFI_SUCCESS;\r
+ break;\r
+ }\r
+ }\r
+\r
+ FreePool (HandleBuffer);\r
+ if (!EFI_ERROR (Status) && Fvb != NULL) {\r
+ //\r
+ // Close the notify event to avoid install gEfiVariableArchProtocolGuid & gEfiVariableWriteArchProtocolGuid again.\r
+ //\r
+ Status = gBS->CloseEvent (Event); \r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ Status = VariableCommonInitialize (Fvb);\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->CreateEventEx (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_NOTIFY,\r
+ VariableClassAddressChangeEvent,\r
+ NULL,\r
+ &gEfiEventVirtualAddressChangeGuid,\r
+ &mVirtualAddressChangeEvent\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\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. It also registers\r
+ notification function for EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.\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 Variable service successfully initialized.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+VariableServiceInitialize (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ //\r
+ // Register FvbNotificationEvent () notify function.\r
+ // \r
+ EfiCreateProtocolNotifyEvent (\r
+ &gEfiFirmwareVolumeBlockProtocolGuid,\r
+ TPL_CALLBACK,\r
+ FvbNotificationEvent,\r
+ (VOID *)SystemTable,\r
+ &mFvbRegistration\r
+ );\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r