+/**\r
+ Calculate common user variable total size.\r
+\r
+**/\r
+VOID\r
+CalculateCommonUserVariableTotalSize (\r
+ VOID\r
+ )\r
+{\r
+ VARIABLE_HEADER *Variable;\r
+ VARIABLE_HEADER *NextVariable;\r
+ UINTN VariableSize;\r
+ VAR_CHECK_VARIABLE_PROPERTY Property;\r
+\r
+ //\r
+ // Only after End Of Dxe, the variables belong to system variable are fixed.\r
+ // If PcdMaxUserNvStorageVariableSize is 0, it means user variable share the same NV storage with system variable,\r
+ // then no need to calculate the common user variable total size specially.\r
+ //\r
+ if (mEndOfDxe && (mVariableModuleGlobal->CommonMaxUserVariableSpace != mVariableModuleGlobal->CommonVariableSpace)) {\r
+ Variable = GetStartPointer (mNvVariableCache);\r
+ while (IsValidVariableHeader (Variable, GetEndPointer (mNvVariableCache))) {\r
+ NextVariable = GetNextVariablePtr (Variable);\r
+ VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
+ if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
+ if (InternalVarCheckVariablePropertyGet (GetVariableNamePtr (Variable), GetVendorGuidPtr (Variable), &Property) == EFI_NOT_FOUND) {\r
+ //\r
+ // No property, it is user variable.\r
+ //\r
+ mVariableModuleGlobal->CommonUserVariableTotalSize += VariableSize;\r
+ }\r
+ }\r
+\r
+ Variable = NextVariable;\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ Initialize variable quota.\r
+\r
+**/\r
+VOID\r
+InitializeVariableQuota (\r
+ VOID\r
+ )\r
+{\r
+ STATIC BOOLEAN Initialized;\r
+\r
+ if (!mEndOfDxe || Initialized) {\r
+ return;\r
+ }\r
+ Initialized = TRUE;\r
+\r
+ InitializeVarErrorFlag ();\r
+ CalculateCommonUserVariableTotalSize ();\r
+}\r
+\r
+/**\r
+\r
+ Variable store garbage collection and reclaim operation.\r
+\r
+ @param[in] VariableBase Base address of variable store.\r
+ @param[out] LastVariableOffset Offset of last variable.\r
+ @param[in] IsVolatile The variable store is volatile or not;\r
+ if it is non-volatile, need FTW.\r
+ @param[in, out] UpdatingPtrTrack Pointer to updating variable pointer track structure.\r
+ @param[in] NewVariable Pointer to new variable.\r
+ @param[in] NewVariableSize New variable size.\r
+\r
+ @return EFI_SUCCESS Reclaim operation has finished successfully.\r
+ @return EFI_OUT_OF_RESOURCES No enough memory resources or variable space.\r
+ @return Others Unexpect error happened during reclaim operation.\r
+\r
+**/\r
+EFI_STATUS\r
+Reclaim (\r
+ IN EFI_PHYSICAL_ADDRESS VariableBase,\r
+ OUT UINTN *LastVariableOffset,\r
+ IN BOOLEAN IsVolatile,\r
+ IN OUT VARIABLE_POINTER_TRACK *UpdatingPtrTrack,\r
+ IN VARIABLE_HEADER *NewVariable,\r
+ IN UINTN NewVariableSize\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 MaximumBufferSize;\r
+ UINTN VariableSize;\r
+ UINTN NameSize;\r
+ UINT8 *CurrPtr;\r
+ VOID *Point0;\r
+ VOID *Point1;\r
+ BOOLEAN FoundAdded;\r
+ EFI_STATUS Status;\r
+ UINTN CommonVariableTotalSize;\r
+ UINTN CommonUserVariableTotalSize;\r
+ UINTN HwErrVariableTotalSize;\r
+ VARIABLE_HEADER *UpdatingVariable;\r
+ VARIABLE_HEADER *UpdatingInDeletedTransition;\r
+\r
+ UpdatingVariable = NULL;\r
+ UpdatingInDeletedTransition = NULL;\r
+ if (UpdatingPtrTrack != NULL) {\r
+ UpdatingVariable = UpdatingPtrTrack->CurrPtr;\r
+ UpdatingInDeletedTransition = UpdatingPtrTrack->InDeletedTransitionPtr;\r
+ }\r
+\r
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) VariableBase);\r
+\r
+ CommonVariableTotalSize = 0;\r
+ CommonUserVariableTotalSize = 0;\r
+ HwErrVariableTotalSize = 0;\r
+\r
+ if (IsVolatile) {\r
+ //\r
+ // Start Pointers for the variable.\r
+ //\r
+ Variable = GetStartPointer (VariableStoreHeader);\r
+ MaximumBufferSize = sizeof (VARIABLE_STORE_HEADER);\r
+\r
+ while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))) {\r
+ NextVariable = GetNextVariablePtr (Variable);\r
+ if ((Variable->State == VAR_ADDED || Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) &&\r
+ Variable != UpdatingVariable &&\r
+ Variable != UpdatingInDeletedTransition\r
+ ) {\r
+ VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
+ MaximumBufferSize += VariableSize;\r
+ }\r
+\r
+ Variable = NextVariable;\r
+ }\r
+\r
+ if (NewVariable != NULL) {\r
+ //\r
+ // Add the new variable size.\r
+ //\r
+ MaximumBufferSize += NewVariableSize;\r
+ }\r
+\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
+ } else {\r
+ //\r
+ // For NV variable reclaim, don't allocate pool here and just use mNvVariableCache\r
+ // as the buffer to reduce SMRAM consumption for SMM variable driver.\r
+ //\r
+ MaximumBufferSize = mNvVariableCache->Size;\r
+ ValidBuffer = (UINT8 *) mNvVariableCache;\r
+ }\r
+\r
+ SetMem (ValidBuffer, MaximumBufferSize, 0xff);\r
+\r
+ //\r
+ // Copy variable store header.\r
+ //\r
+ CopyMem (ValidBuffer, VariableStoreHeader, sizeof (VARIABLE_STORE_HEADER));\r
+ CurrPtr = (UINT8 *) GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer);\r
+\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, GetEndPointer (VariableStoreHeader))) {\r
+ NextVariable = GetNextVariablePtr (Variable);\r
+ if (Variable != UpdatingVariable && Variable->State == VAR_ADDED) {\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
+ HwErrVariableTotalSize += VariableSize;\r
+ } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+ CommonVariableTotalSize += VariableSize;\r
+ if (IsUserVariable (Variable)) {\r
+ CommonUserVariableTotalSize += VariableSize;\r
+ }\r
+ }\r
+ }\r
+ Variable = NextVariable;\r
+ }\r
+\r
+ //\r
+ // Reinstall all in delete transition variables.\r
+ //\r
+ Variable = GetStartPointer (VariableStoreHeader);\r
+ while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))) {\r