+/**\r
+ This function is to check if the remaining variable space is enough to set\r
+ all Variables from argument list successfully. The purpose of the check\r
+ is to keep the consistency of the Variables to be in variable storage.\r
+\r
+ Note: Variables are assumed to be in same storage.\r
+ The set sequence of Variables will be same with the sequence of VariableEntry from argument list,\r
+ so follow the argument sequence to check the Variables.\r
+\r
+ @param[in] Attributes Variable attributes for Variable entries.\r
+ @param ... The variable argument list with type VARIABLE_ENTRY_CONSISTENCY *.\r
+ A NULL terminates the list. The VariableSize of \r
+ VARIABLE_ENTRY_CONSISTENCY is the variable data size as input.\r
+ It will be changed to variable total size as output.\r
+\r
+ @retval TRUE Have enough variable space to set the Variables successfully.\r
+ @retval FALSE No enough variable space to set the Variables successfully.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+CheckRemainingSpaceForConsistency (\r
+ IN UINT32 Attributes,\r
+ ...\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ VA_LIST Args;\r
+ VARIABLE_ENTRY_CONSISTENCY *VariableEntry;\r
+ UINT64 MaximumVariableStorageSize;\r
+ UINT64 RemainingVariableStorageSize;\r
+ UINT64 MaximumVariableSize;\r
+ UINTN TotalNeededSize;\r
+ UINTN OriginalVarSize;\r
+ VARIABLE_STORE_HEADER *VariableStoreHeader;\r
+ VARIABLE_POINTER_TRACK VariablePtrTrack;\r
+ VARIABLE_HEADER *NextVariable;\r
+ UINTN VarNameSize;\r
+ UINTN VarDataSize;\r
+\r
+ //\r
+ // Non-Volatile related.\r
+ //\r
+ VariableStoreHeader = mNvVariableCache;\r
+\r
+ Status = VariableServiceQueryVariableInfoInternal (\r
+ Attributes,\r
+ &MaximumVariableStorageSize,\r
+ &RemainingVariableStorageSize,\r
+ &MaximumVariableSize\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ TotalNeededSize = 0;\r
+ VA_START (Args, Attributes);\r
+ VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *);\r
+ while (VariableEntry != NULL) {\r
+ //\r
+ // Calculate variable total size.\r
+ //\r
+ VarNameSize = StrSize (VariableEntry->Name);\r
+ VarNameSize += GET_PAD_SIZE (VarNameSize);\r
+ VarDataSize = VariableEntry->VariableSize;\r
+ VarDataSize += GET_PAD_SIZE (VarDataSize);\r
+ VariableEntry->VariableSize = HEADER_ALIGN (sizeof (VARIABLE_HEADER) + VarNameSize + VarDataSize);\r
+\r
+ TotalNeededSize += VariableEntry->VariableSize;\r
+ VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *);\r
+ }\r
+ VA_END (Args);\r
+\r
+ if (RemainingVariableStorageSize >= TotalNeededSize) {\r
+ //\r
+ // Already have enough space.\r
+ //\r
+ return TRUE;\r
+ } else if (AtRuntime ()) {\r
+ //\r
+ // At runtime, no reclaim.\r
+ // The original variable space of Variables can't be reused.\r
+ //\r
+ return FALSE;\r
+ }\r
+\r
+ VA_START (Args, Attributes);\r
+ VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *);\r
+ while (VariableEntry != NULL) {\r
+ //\r
+ // Check if Variable[Index] has been present and get its size.\r
+ //\r
+ OriginalVarSize = 0;\r
+ VariablePtrTrack.StartPtr = GetStartPointer (VariableStoreHeader);\r
+ VariablePtrTrack.EndPtr = GetEndPointer (VariableStoreHeader);\r
+ Status = FindVariableEx (\r
+ VariableEntry->Name,\r
+ VariableEntry->Guid,\r
+ FALSE,\r
+ &VariablePtrTrack\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // Get size of Variable[Index].\r
+ //\r
+ NextVariable = GetNextVariablePtr (VariablePtrTrack.CurrPtr);\r
+ OriginalVarSize = (UINTN) NextVariable - (UINTN) VariablePtrTrack.CurrPtr;\r
+ //\r
+ // Add the original size of Variable[Index] to remaining variable storage size.\r
+ //\r
+ RemainingVariableStorageSize += OriginalVarSize;\r
+ }\r
+ if (VariableEntry->VariableSize > RemainingVariableStorageSize) {\r
+ //\r
+ // No enough space for Variable[Index].\r
+ //\r
+ VA_END (Args);\r
+ return FALSE;\r
+ }\r
+ //\r
+ // Sub the (new) size of Variable[Index] from remaining variable storage size.\r
+ //\r
+ RemainingVariableStorageSize -= VariableEntry->VariableSize;\r
+ VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *);\r
+ }\r
+ VA_END (Args);\r
+\r
+ return TRUE;\r
+}\r
+\r