]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c
Calculate enough space for 2 variables (public key and variable data) instead of...
[mirror_edk2.git] / MdeModulePkg / Universal / Variable / RuntimeDxe / Variable.c
index 5f128e9d6135b5b0a73e27d86ab0c63dce9b79a8..7bd9ffb6c5d406b1b566f3a7030f19b3725c7e2f 100644 (file)
@@ -1258,6 +1258,134 @@ VariableGetBestLanguage (
   return NULL;\r
 }\r
 \r
+/**\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
 /**\r
   Hook the operations in PlatformLangCodes, LangCodes, PlatformLang and Lang.\r
 \r
@@ -1292,6 +1420,7 @@ AutoUpdateLangVariable (
   UINT32                 Attributes;\r
   VARIABLE_POINTER_TRACK Variable;\r
   BOOLEAN                SetLanguageCodes;\r
+  VARIABLE_ENTRY_CONSISTENCY VariableEntry[2];\r
 \r
   //\r
   // Don't do updates for delete operation\r
@@ -1414,14 +1543,31 @@ AutoUpdateLangVariable (
         BestLang = GetLangFromSupportedLangCodes (mVariableModuleGlobal->LangCodes, Index, TRUE);\r
 \r
         //\r
-        // Successfully convert PlatformLang to Lang, and set the BestLang value into Lang variable simultaneously.\r
+        // Check the variable space for both Lang and PlatformLang variable.\r
         //\r
-        FindVariable (EFI_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
+        VariableEntry[0].VariableSize = ISO_639_2_ENTRY_SIZE + 1;\r
+        VariableEntry[0].Guid = &gEfiGlobalVariableGuid;\r
+        VariableEntry[0].Name = EFI_LANG_VARIABLE_NAME;\r
+        \r
+        VariableEntry[1].VariableSize = AsciiStrSize (BestPlatformLang);\r
+        VariableEntry[1].Guid = &gEfiGlobalVariableGuid;\r
+        VariableEntry[1].Name = EFI_PLATFORM_LANG_VARIABLE_NAME;\r
+        if (!CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT, &VariableEntry[0], &VariableEntry[1], NULL)) {\r
+          //\r
+          // No enough variable space to set both Lang and PlatformLang successfully.\r
+          //\r
+          Status = EFI_OUT_OF_RESOURCES;\r
+        } else {\r
+          //\r
+          // Successfully convert PlatformLang to Lang, and set the BestLang value into Lang variable simultaneously.\r
+          //\r
+          FindVariable (EFI_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
 \r
-        Status = UpdateVariable (EFI_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, BestLang,\r
-                                 ISO_639_2_ENTRY_SIZE + 1, Attributes, &Variable);\r
+          Status = UpdateVariable (EFI_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, BestLang,\r
+                                   ISO_639_2_ENTRY_SIZE + 1, Attributes, &Variable);\r
+        }\r
 \r
-        DEBUG ((EFI_D_INFO, "Variable Driver Auto Update PlatformLang, PlatformLang:%a, Lang:%a: Status: %r\n", BestPlatformLang, BestLang, Status));\r
+        DEBUG ((EFI_D_INFO, "Variable Driver Auto Update PlatformLang, PlatformLang:%a, Lang:%a Status: %r\n", BestPlatformLang, BestLang, Status));\r
       }\r
     }\r
 \r
@@ -1446,19 +1592,43 @@ AutoUpdateLangVariable (
         BestPlatformLang = GetLangFromSupportedLangCodes (mVariableModuleGlobal->PlatformLangCodes, Index, FALSE);\r
 \r
         //\r
-        // Successfully convert Lang to PlatformLang, and set the BestPlatformLang value into PlatformLang variable simultaneously.\r
+        // Check the variable space for both PlatformLang and Lang variable.\r
         //\r
-        FindVariable (EFI_PLATFORM_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
+        VariableEntry[0].VariableSize = AsciiStrSize (BestPlatformLang);\r
+        VariableEntry[0].Guid = &gEfiGlobalVariableGuid;\r
+        VariableEntry[0].Name = EFI_PLATFORM_LANG_VARIABLE_NAME;\r
+\r
+        VariableEntry[1].VariableSize = ISO_639_2_ENTRY_SIZE + 1;\r
+        VariableEntry[1].Guid = &gEfiGlobalVariableGuid;\r
+        VariableEntry[1].Name = EFI_LANG_VARIABLE_NAME;\r
+        if (!CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT, &VariableEntry[0], &VariableEntry[1], NULL)) {\r
+          //\r
+          // No enough variable space to set both PlatformLang and Lang successfully.\r
+          //\r
+          Status = EFI_OUT_OF_RESOURCES;\r
+        } else {\r
+          //\r
+          // Successfully convert Lang to PlatformLang, and set the BestPlatformLang value into PlatformLang variable simultaneously.\r
+          //\r
+          FindVariable (EFI_PLATFORM_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
 \r
-        Status = UpdateVariable (EFI_PLATFORM_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, BestPlatformLang, \r
-                                 AsciiStrSize (BestPlatformLang), Attributes, &Variable);\r
+          Status = UpdateVariable (EFI_PLATFORM_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, BestPlatformLang, \r
+                                   AsciiStrSize (BestPlatformLang), Attributes, &Variable);\r
+        }\r
 \r
         DEBUG ((EFI_D_INFO, "Variable Driver Auto Update Lang, Lang:%a, PlatformLang:%a Status: %r\n", BestLang, BestPlatformLang, Status));\r
       }\r
     }\r
   }\r
 \r
-  return Status;\r
+  if (SetLanguageCodes) {\r
+    //\r
+    // Continue to set PlatformLangCodes or LangCodes.\r
+    //\r
+    return EFI_SUCCESS;\r
+  } else {\r
+    return Status;\r
+  }\r
 }\r
 \r
 /**\r
@@ -2492,15 +2662,17 @@ VariableServiceSetVariable (
     }\r
   }\r
 \r
-  //\r
-  // Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang.\r
-  //\r
-  Status = AutoUpdateLangVariable (VariableName, Data, DataSize);\r
-  if (EFI_ERROR (Status)) {\r
+  if (!FeaturePcdGet (PcdUefiVariableDefaultLangDeprecate)) {\r
     //\r
-    // The auto update operation failed, directly return to avoid inconsistency between PlatformLang and Lang.\r
+    // Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang.\r
     //\r
-    goto Done;\r
+    Status = AutoUpdateLangVariable (VariableName, Data, DataSize);\r
+    if (EFI_ERROR (Status)) {\r
+      //\r
+      // The auto update operation failed, directly return to avoid inconsistency between PlatformLang and Lang.\r
+      //\r
+      goto Done;\r
+    }\r
   }\r
 \r
   Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, &Variable);\r
@@ -2525,14 +2697,12 @@ Done:
   @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
-VariableServiceQueryVariableInfo (\r
+VariableServiceQueryVariableInfoInternal (\r
   IN  UINT32                 Attributes,\r
   OUT UINT64                 *MaximumVariableStorageSize,\r
   OUT UINT64                 *RemainingVariableStorageSize,\r
@@ -2545,43 +2715,12 @@ VariableServiceQueryVariableInfo (
   VARIABLE_STORE_HEADER  *VariableStoreHeader;\r
   UINT64                 CommonVariableTotalSize;\r
   UINT64                 HwErrVariableTotalSize;\r
+  EFI_STATUS             Status;\r
+  VARIABLE_POINTER_TRACK VariablePtrTrack;\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
-  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
-    //\r
-    return EFI_UNSUPPORTED;  \r
-  } else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {\r
-    //\r
-    // Make sure if runtime bit is set, boot service bit is set also.\r
-    //\r
-    return EFI_INVALID_PARAMETER;\r
-  } else if (AtRuntime () && ((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(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
-\r
   if((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
     //\r
     // Query is Volatile related.\r
@@ -2653,6 +2792,27 @@ VariableServiceQueryVariableInfo (
         } else {\r
           CommonVariableTotalSize += VariableSize;\r
         }\r
+      } else if (Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
+        //\r
+        // If it is a IN_DELETED_TRANSITION variable,\r
+        // and there is not also a same ADDED one at the same time,\r
+        // this IN_DELETED_TRANSITION variable is valid.\r
+        //\r
+        VariablePtrTrack.StartPtr = GetStartPointer (VariableStoreHeader);\r
+        VariablePtrTrack.EndPtr   = GetEndPointer   (VariableStoreHeader);\r
+        Status = FindVariableEx (\r
+                   GetVariableNamePtr (Variable),\r
+                   &Variable->VendorGuid,\r
+                   FALSE,\r
+                   &VariablePtrTrack\r
+                   );\r
+        if (!EFI_ERROR (Status) && VariablePtrTrack.CurrPtr->State != VAR_ADDED) {\r
+          if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
+            HwErrVariableTotalSize += VariableSize;\r
+          } else {\r
+            CommonVariableTotalSize += VariableSize;\r
+          }\r
+        }\r
       }\r
     }\r
 \r
@@ -2674,10 +2834,81 @@ VariableServiceQueryVariableInfo (
     *MaximumVariableSize = *RemainingVariableStorageSize - sizeof (VARIABLE_HEADER);\r
   }\r
 \r
-  ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
   return EFI_SUCCESS;\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
+VariableServiceQueryVariableInfo (\r
+  IN  UINT32                 Attributes,\r
+  OUT UINT64                 *MaximumVariableStorageSize,\r
+  OUT UINT64                 *RemainingVariableStorageSize,\r
+  OUT UINT64                 *MaximumVariableSize\r
+  )\r
+{\r
+  EFI_STATUS             Status;\r
+\r
+  if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {\r
+    return EFI_INVALID_PARAMETER;\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
+    //\r
+    return EFI_UNSUPPORTED;\r
+  } else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {\r
+    //\r
+    // Make sure if runtime bit is set, boot service bit is set also.\r
+    //\r
+    return EFI_INVALID_PARAMETER;\r
+  } else if (AtRuntime () && ((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 | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS | EFI_VARIABLE_APPEND_WRITE)) != 0) {\r
+    //\r
+    // Not support authenticated or append variable write yet.\r
+    //\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
+\r
+  Status = VariableServiceQueryVariableInfoInternal (\r
+             Attributes,\r
+             MaximumVariableStorageSize,\r
+             RemainingVariableStorageSize,\r
+             MaximumVariableSize\r
+             );\r
+\r
+  ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
+  return Status;\r
+}\r
 \r
 /**\r
   This function reclaims variable storage if free size is below the threshold.\r