@param IsVolatile The variable store is volatile or not;\r
if it is non-volatile, need FTW.\r
@param UpdatingVariable Pointer to updating variable.\r
+ @param ReclaimAnyway If TRUE, do reclaim anyway.\r
\r
@return EFI_OUT_OF_RESOURCES\r
@return EFI_SUCCESS\r
IN EFI_PHYSICAL_ADDRESS VariableBase,\r
OUT UINTN *LastVariableOffset,\r
IN BOOLEAN IsVolatile,\r
- IN VARIABLE_HEADER *UpdatingVariable\r
+ IN VARIABLE_HEADER *UpdatingVariable,\r
+ IN BOOLEAN ReclaimAnyway\r
)\r
{\r
VARIABLE_HEADER *Variable;\r
EFI_STATUS Status;\r
CHAR16 *VariableNamePtr;\r
CHAR16 *UpdatingVariableNamePtr;\r
+ UINTN CommonVariableTotalSize;\r
+ UINTN HwErrVariableTotalSize;\r
+ BOOLEAN NeedDoReclaim;\r
\r
+ NeedDoReclaim = FALSE;\r
VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) VariableBase);\r
- //\r
- // Recalculate 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
+ CommonVariableTotalSize = 0;\r
+ HwErrVariableTotalSize = 0;\r
\r
//\r
// Start Pointers for the variable.\r
) {\r
VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
MaximumBufferSize += VariableSize;\r
+ } else {\r
+ NeedDoReclaim = TRUE;\r
}\r
\r
Variable = NextVariable;\r
}\r
\r
+ if (!ReclaimAnyway && !NeedDoReclaim) {\r
+ DEBUG ((EFI_D_INFO, "Variable driver: no DELETED variable found, so no variable space could be reclaimed.\n"));\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
//\r
// Reserve the 1 Bytes with Oxff to identify the\r
// end of the variable buffer.\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
+ HwErrVariableTotalSize += VariableSize;\r
} else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
- mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;\r
+ CommonVariableTotalSize += VariableSize;\r
}\r
}\r
Variable = NextVariable;\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
+ HwErrVariableTotalSize += VariableSize;\r
} else if ((!IsVolatile) && ((UpdatingVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
- mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;\r
+ CommonVariableTotalSize += VariableSize;\r
}\r
}\r
\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
+ HwErrVariableTotalSize += VariableSize;\r
} else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
- mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;\r
+ CommonVariableTotalSize += VariableSize;\r
}\r
}\r
}\r
}\r
if (!EFI_ERROR (Status)) {\r
*LastVariableOffset = (UINTN) (CurrPtr - (UINT8 *) ValidBuffer);\r
+ if (!IsVolatile) {\r
+ mVariableModuleGlobal->HwErrVariableTotalSize = HwErrVariableTotalSize;\r
+ mVariableModuleGlobal->CommonVariableTotalSize = CommonVariableTotalSize;\r
+ }\r
} else {\r
- *LastVariableOffset = 0;\r
+ NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableBase);\r
+ while (IsValidVariableHeader (NextVariable)) {\r
+ VariableSize = NextVariable->NameSize + NextVariable->DataSize + sizeof (VARIABLE_HEADER);\r
+ if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+ mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VariableSize);\r
+ } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+ mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VariableSize);\r
+ }\r
+\r
+ NextVariable = GetNextVariablePtr (NextVariable);\r
+ }\r
+ *LastVariableOffset = (UINTN) NextVariable - (UINTN) VariableBase;\r
}\r
\r
FreePool (ValidBuffer);\r
UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE, FALSE, TRUE, FALSE);\r
if (!Variable->Volatile) {\r
CacheVariable->CurrPtr->State = State;\r
+ FlushHobVariableToFlash (VariableName, VendorGuid);\r
}\r
}\r
goto Done;\r
// Perform garbage collection & reclaim operation.\r
//\r
Status = Reclaim (mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
- &mVariableModuleGlobal->NonVolatileLastVariableOffset, FALSE, Variable->CurrPtr);\r
+ &mVariableModuleGlobal->NonVolatileLastVariableOffset, FALSE, Variable->CurrPtr, FALSE);\r
if (EFI_ERROR (Status)) {\r
goto Done;\r
}\r
// Perform garbage collection & reclaim operation.\r
//\r
Status = Reclaim (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase,\r
- &mVariableModuleGlobal->VolatileLastVariableOffset, TRUE, Variable->CurrPtr);\r
+ &mVariableModuleGlobal->VolatileLastVariableOffset, TRUE, Variable->CurrPtr, FALSE);\r
if (EFI_ERROR (Status)) {\r
goto Done;\r
}\r
\r
if (!EFI_ERROR (Status)) {\r
UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE);\r
+ if (!Volatile) {\r
+ FlushHobVariableToFlash (VariableName, VendorGuid);\r
+ }\r
}\r
\r
Done:\r
return TRUE;\r
}\r
\r
+/**\r
+ This code checks if variable should be treated as read-only variable.\r
+\r
+ @param[in] VariableName Name of the Variable.\r
+ @param[in] VendorGuid GUID of the Variable.\r
+\r
+ @retval TRUE This variable is read-only variable.\r
+ @retval FALSE This variable is NOT read-only variable.\r
+ \r
+**/\r
+BOOLEAN\r
+IsReadOnlyVariable (\r
+ IN CHAR16 *VariableName,\r
+ IN EFI_GUID *VendorGuid\r
+ )\r
+{\r
+ if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid)) {\r
+ if ((StrCmp (VariableName, EFI_SETUP_MODE_NAME) == 0) ||\r
+ (StrCmp (VariableName, EFI_SIGNATURE_SUPPORT_NAME) == 0) ||\r
+ (StrCmp (VariableName, EFI_SECURE_BOOT_MODE_NAME) == 0)) {\r
+ return TRUE;\r
+ }\r
+ }\r
+ \r
+ return FALSE;\r
+}\r
+\r
/**\r
\r
This code finds variable in storage blocks (Volatile or Non-Volatile).\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
+ if (IsReadOnlyVariable (VariableName, VendorGuid)) {\r
+ return EFI_WRITE_PROTECTED;\r
+ }\r
+\r
if (DataSize != 0 && Data == NULL) {\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
+ //\r
+ // Check for reserverd bit in variable attribute.\r
+ //\r
+ if ((Attributes & (~EFI_VARIABLE_ATTRIBUTES_MASK)) != 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
Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes, FALSE);\r
} else if (CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) && \r
((StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0) || (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0))) {\r
- Status = ProcessVarWithKek (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes);\r
+ Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes, FALSE);\r
+ if (EFI_ERROR (Status)) {\r
+ Status = ProcessVarWithKek (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes);\r
+ }\r
} else {\r
Status = ProcessVariable (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes);\r
}\r
mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
&mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
FALSE,\r
- NULL\r
+ NULL,\r
+ FALSE\r
);\r
ASSERT_EFI_ERROR (Status);\r
}\r
}\r
\r
+/**\r
+ Flush the HOB variable to flash.\r
+\r
+ @param[in] VariableName Name of variable has been updated or deleted.\r
+ @param[in] VendorGuid Guid of variable has been updated or deleted.\r
+\r
+**/\r
+VOID\r
+FlushHobVariableToFlash (\r
+ IN CHAR16 *VariableName,\r
+ IN EFI_GUID *VendorGuid\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ VARIABLE_STORE_HEADER *VariableStoreHeader;\r
+ VARIABLE_HEADER *Variable;\r
+ VOID *VariableData;\r
+ BOOLEAN ErrorFlag;\r
+\r
+ ErrorFlag = FALSE;\r
+\r
+ //\r
+ // Flush the HOB variable to flash.\r
+ //\r
+ if (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) {\r
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase;\r
+ //\r
+ // Set HobVariableBase to 0, it can avoid SetVariable to call back.\r
+ //\r
+ mVariableModuleGlobal->VariableGlobal.HobVariableBase = 0;\r
+ for ( Variable = GetStartPointer (VariableStoreHeader)\r
+ ; (Variable < GetEndPointer (VariableStoreHeader) && IsValidVariableHeader (Variable))\r
+ ; Variable = GetNextVariablePtr (Variable)\r
+ ) {\r
+ if (Variable->State != VAR_ADDED) {\r
+ //\r
+ // The HOB variable has been set to DELETED state in local.\r
+ //\r
+ continue;\r
+ }\r
+ ASSERT ((Variable->Attributes & EFI_VARIABLE_NON_VOLATILE) != 0);\r
+ if (VendorGuid == NULL || VariableName == NULL ||\r
+ !CompareGuid (VendorGuid, &Variable->VendorGuid) ||\r
+ StrCmp (VariableName, GetVariableNamePtr (Variable)) != 0) {\r
+ VariableData = GetVariableDataPtr (Variable);\r
+ Status = VariableServiceSetVariable (\r
+ GetVariableNamePtr (Variable),\r
+ &Variable->VendorGuid,\r
+ Variable->Attributes,\r
+ Variable->DataSize,\r
+ VariableData\r
+ );\r
+ DEBUG ((EFI_D_INFO, "Variable driver flush the HOB variable to flash: %g %s %r\n", &Variable->VendorGuid, GetVariableNamePtr (Variable), Status));\r
+ } else {\r
+ //\r
+ // The updated or deleted variable is matched with the HOB variable.\r
+ // Don't break here because we will try to set other HOB variables\r
+ // since this variable could be set successfully.\r
+ //\r
+ Status = EFI_SUCCESS;\r
+ }\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // If set variable successful, or the updated or deleted variable is matched with the HOB variable,\r
+ // set the HOB variable to DELETED state in local.\r
+ //\r
+ DEBUG ((EFI_D_INFO, "Variable driver set the HOB variable to DELETED state in local: %g %s\n", &Variable->VendorGuid, GetVariableNamePtr (Variable)));\r
+ Variable->State &= VAR_DELETED;\r
+ } else {\r
+ ErrorFlag = TRUE;\r
+ }\r
+ }\r
+ if (ErrorFlag) {\r
+ //\r
+ // We still have HOB variable(s) not flushed in flash.\r
+ //\r
+ mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VariableStoreHeader;\r
+ } else {\r
+ //\r
+ // All HOB variables have been flushed in flash.\r
+ //\r
+ DEBUG ((EFI_D_INFO, "Variable driver: all HOB variables have been flushed in flash.\n"));\r
+ if (!AtRuntime ()) {\r
+ FreePool ((VOID *) VariableStoreHeader);\r
+ }\r
+ }\r
+ }\r
+\r
+}\r
\r
/**\r
Initializes variable write service after FVB was ready.\r
UINTN Index;\r
UINT8 Data;\r
EFI_PHYSICAL_ADDRESS VariableStoreBase;\r
- VARIABLE_HEADER *Variable;\r
- VOID *VariableData;\r
\r
VariableStoreBase = mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;\r
VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase;\r
mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
&mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
FALSE,\r
- NULL\r
+ NULL,\r
+ TRUE\r
);\r
if (EFI_ERROR (Status)) {\r
return Status;\r
}\r
}\r
\r
-\r
- //\r
- // Flush the HOB variable to flash and invalidate HOB variable.\r
- //\r
- if (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) {\r
- //\r
- // Clear the HobVariableBase to avoid SetVariable() updating the variable in HOB\r
- //\r
- VariableStoreHeader = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase;\r
- mVariableModuleGlobal->VariableGlobal.HobVariableBase = 0;\r
-\r
- for ( Variable = GetStartPointer (VariableStoreHeader)\r
- ; (Variable < GetEndPointer (VariableStoreHeader) && IsValidVariableHeader (Variable))\r
- ; Variable = GetNextVariablePtr (Variable)\r
- ) {\r
- ASSERT (Variable->State == VAR_ADDED);\r
- ASSERT ((Variable->Attributes & EFI_VARIABLE_NON_VOLATILE) != 0);\r
- VariableData = GetVariableDataPtr (Variable);\r
- Status = VariableServiceSetVariable (\r
- GetVariableNamePtr (Variable),\r
- &Variable->VendorGuid,\r
- Variable->Attributes,\r
- Variable->DataSize,\r
- VariableData\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
- }\r
- }\r
+ FlushHobVariableToFlash (NULL, NULL);\r
\r
//\r
// Authenticated variable initialize.\r
GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid);\r
if (GuidHob != NULL) {\r
VariableStoreHeader = GET_GUID_HOB_DATA (GuidHob);\r
+ VariableStoreLength = (UINT64) (GuidHob->Header.HobLength - sizeof (EFI_HOB_GUID_TYPE));\r
if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) {\r
- mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VariableStoreHeader;\r
+ mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) AllocateRuntimeCopyPool ((UINTN) VariableStoreLength, (VOID *) VariableStoreHeader);\r
+ if (mVariableModuleGlobal->VariableGlobal.HobVariableBase == 0) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
} else {\r
DEBUG ((EFI_D_ERROR, "HOB Variable Store header is corrupted!\n"));\r
}\r