]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c
LastVariableOffset is wrongly set to 0 when FtwVariableSpace() fails. Recalculate...
[mirror_edk2.git] / MdeModulePkg / Universal / Variable / RuntimeDxe / Variable.c
index 21432c6e8ae908f81e906db9d2e9ba4d0a0900a6..3aa45c2dd2a48b344cbb40b470455d2ae2edd989 100644 (file)
@@ -1,9 +1,9 @@
 /** @file\r
 \r
-  The common variable operation routines shared by DXE_RINTIME variable \r
+  The common variable operation routines shared by DXE_RUNTIME variable \r
   module and DXE_SMM variable module.\r
   \r
-Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>\r
 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
@@ -537,15 +537,13 @@ Reclaim (
   EFI_STATUS            Status;\r
   CHAR16                *VariableNamePtr;\r
   CHAR16                *UpdatingVariableNamePtr;\r
+  UINTN                 CommonVariableTotalSize;\r
+  UINTN                 HwErrVariableTotalSize;\r
 \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
@@ -612,9 +610,9 @@ Reclaim (
       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
@@ -628,9 +626,9 @@ Reclaim (
     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
@@ -674,9 +672,9 @@ Reclaim (
         ((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
@@ -704,8 +702,23 @@ Reclaim (
   }\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
@@ -718,6 +731,8 @@ Reclaim (
 \r
   @param  VariableName        Name of the variable to be found\r
   @param  VendorGuid          Vendor GUID to be found.\r
+  @param  IgnoreRtCheck       Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute\r
+                              check at runtime when searching variable.\r
   @param  PtrTrack            Variable Track Pointer structure that contains Variable Information.\r
 \r
   @retval  EFI_SUCCESS            Variable found successfully\r
@@ -727,6 +742,7 @@ EFI_STATUS
 FindVariableEx (\r
   IN     CHAR16                  *VariableName,\r
   IN     EFI_GUID                *VendorGuid,\r
+  IN     BOOLEAN                 IgnoreRtCheck,\r
   IN OUT VARIABLE_POINTER_TRACK  *PtrTrack\r
   )\r
 {\r
@@ -745,7 +761,7 @@ FindVariableEx (
     if (PtrTrack->CurrPtr->State == VAR_ADDED || \r
         PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)\r
        ) {\r
-      if (!AtRuntime () || ((PtrTrack->CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) != 0)) {\r
+      if (IgnoreRtCheck || !AtRuntime () || ((PtrTrack->CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) != 0)) {\r
         if (VariableName[0] == 0) {\r
           if (PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
             InDeletedVariable   = PtrTrack->CurrPtr;\r
@@ -781,7 +797,9 @@ FindVariableEx (
   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
+  If IgnoreRtCheck is TRUE, then we ignore the EFI_VARIABLE_RUNTIME_ACCESS attribute check\r
+  at runtime when searching existing variable, only VariableName and VendorGuid are compared.\r
+  Otherwise, variables without EFI_VARIABLE_RUNTIME_ACCESS are not visible at runtime.\r
 \r
   @param  VariableName                Name of the variable to be found.\r
   @param  VendorGuid                  Vendor GUID to be found.\r
@@ -790,6 +808,8 @@ FindVariableEx (
   @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
+  @param  IgnoreRtCheck               Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute\r
+                                      check at runtime when searching variable.\r
 \r
   @retval EFI_INVALID_PARAMETER       If VariableName is not an empty string, while\r
                                       VendorGuid is NULL.\r
@@ -802,7 +822,8 @@ FindVariable (
   IN  CHAR16                  *VariableName,\r
   IN  EFI_GUID                *VendorGuid,\r
   OUT VARIABLE_POINTER_TRACK  *PtrTrack,\r
-  IN  VARIABLE_GLOBAL         *Global\r
+  IN  VARIABLE_GLOBAL         *Global,\r
+  IN  BOOLEAN                 IgnoreRtCheck\r
   )\r
 {\r
   EFI_STATUS              Status;\r
@@ -834,7 +855,7 @@ FindVariable (
     PtrTrack->EndPtr   = GetEndPointer   (VariableStoreHeader[Type]);\r
     PtrTrack->Volatile = (BOOLEAN) (Type == VariableStoreTypeVolatile);\r
 \r
-    Status = FindVariableEx (VariableName, VendorGuid, PtrTrack);\r
+    Status = FindVariableEx (VariableName, VendorGuid, IgnoreRtCheck, PtrTrack);\r
     if (!EFI_ERROR (Status)) {\r
       return Status;\r
     }\r
@@ -970,7 +991,7 @@ GetLangFromSupportedLangCodes (
     CompareLength = ISO_639_2_ENTRY_SIZE;\r
     mVariableModuleGlobal->Lang[CompareLength] = '\0';\r
     return CopyMem (mVariableModuleGlobal->Lang, SupportedLang + Index * CompareLength, CompareLength);\r
-      \r
+\r
   } else {\r
     while (TRUE) {\r
       //\r
@@ -1153,7 +1174,7 @@ VariableGetBestLanguage (
 \r
 **/\r
 VOID\r
-AutoUpdateLangVariable(\r
+AutoUpdateLangVariable (\r
   IN  CHAR16             *VariableName,\r
   IN  VOID               *Data,\r
   IN  UINTN              DataSize\r
@@ -1234,7 +1255,7 @@ AutoUpdateLangVariable(
     // Update Lang if PlatformLang is already set\r
     // Update PlatformLang if Lang is already set\r
     //\r
-    Status = FindVariable (L"PlatformLang", &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);\r
+    Status = FindVariable (L"PlatformLang", &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
     if (!EFI_ERROR (Status)) {\r
       //\r
       // Update Lang\r
@@ -1243,7 +1264,7 @@ AutoUpdateLangVariable(
       Data         = GetVariableDataPtr (Variable.CurrPtr);\r
       DataSize     = Variable.CurrPtr->DataSize;\r
     } else {\r
-      Status = FindVariable (L"Lang", &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);\r
+      Status = FindVariable (L"Lang", &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
       if (!EFI_ERROR (Status)) {\r
         //\r
         // Update PlatformLang\r
@@ -1288,7 +1309,7 @@ AutoUpdateLangVariable(
         //\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
+        FindVariable (L"Lang", &gEfiGlobalVariableGuid, &Variable, (VARIABLE_GLOBAL *)mVariableModuleGlobal, FALSE);\r
 \r
         Status = UpdateVariable (L"Lang", &gEfiGlobalVariableGuid, BestLang,\r
                                  ISO_639_2_ENTRY_SIZE + 1, Attributes, &Variable);\r
@@ -1322,7 +1343,7 @@ AutoUpdateLangVariable(
         //\r
         // Successfully convert Lang to PlatformLang, and set the BestPlatformLang value into PlatformLang variable simultaneously.\r
         //\r
-        FindVariable (L"PlatformLang", &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);\r
+        FindVariable (L"PlatformLang", &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
 \r
         Status = UpdateVariable (L"PlatformLang", &gEfiGlobalVariableGuid, BestPlatformLang, \r
                                  AsciiStrSize (BestPlatformLang), Attributes, &Variable);\r
@@ -1418,9 +1439,9 @@ UpdateVariable (
         goto Done;\r
       }\r
       //\r
-      // Only variable that have NV attributes can be updated/deleted in Runtime.\r
+      // Only variable that have NV|RT attributes can be updated/deleted in Runtime.\r
       //\r
-      if ((Variable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
+      if (((Variable->CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) || ((Variable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0)) {\r
         Status = EFI_INVALID_PARAMETER;\r
         goto Done;      \r
       }\r
@@ -1752,6 +1773,63 @@ Done:
   return Status;\r
 }\r
 \r
+/**\r
+  Check if a Unicode character is a hexadecimal character.\r
+\r
+  This function checks if a Unicode character is a \r
+  hexadecimal character.  The valid hexadecimal character is \r
+  L'0' to L'9', L'a' to L'f', or L'A' to L'F'.\r
+\r
+\r
+  @param Char           The character to check against.\r
+\r
+  @retval TRUE          If the Char is a hexadecmial character.\r
+  @retval FALSE         If the Char is not a hexadecmial character.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+IsHexaDecimalDigitCharacter (\r
+  IN CHAR16             Char\r
+  )\r
+{\r
+  return (BOOLEAN) ((Char >= L'0' && Char <= L'9') || (Char >= L'A' && Char <= L'F') || (Char >= L'a' && Char <= L'f'));\r
+}\r
+\r
+/**\r
+\r
+  This code checks if variable is hardware error record variable or not.\r
+\r
+  According to UEFI spec, hardware error record variable should use the EFI_HARDWARE_ERROR_VARIABLE VendorGuid\r
+  and have the L"HwErrRec####" name convention, #### is a printed hex value and no 0x or h is included in the hex value.\r
+\r
+  @param VariableName   Pointer to variable name.\r
+  @param VendorGuid     Variable Vendor Guid.\r
+\r
+  @retval TRUE          Variable is hardware error record variable.\r
+  @retval FALSE         Variable is not hardware error record variable.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+IsHwErrRecVariable (\r
+  IN CHAR16             *VariableName,\r
+  IN EFI_GUID           *VendorGuid\r
+  )\r
+{\r
+  if (!CompareGuid (VendorGuid, &gEfiHardwareErrorVariableGuid) ||\r
+      (StrLen (VariableName) != StrLen (L"HwErrRec####")) ||\r
+      (StrnCmp(VariableName, L"HwErrRec", StrLen (L"HwErrRec")) != 0) ||\r
+      !IsHexaDecimalDigitCharacter (VariableName[0x8]) ||\r
+      !IsHexaDecimalDigitCharacter (VariableName[0x9]) ||\r
+      !IsHexaDecimalDigitCharacter (VariableName[0xA]) ||\r
+      !IsHexaDecimalDigitCharacter (VariableName[0xB])) {\r
+    return FALSE;\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
 /**\r
 \r
   This code finds variable in storage blocks (Volatile or Non-Volatile).\r
@@ -1789,7 +1867,7 @@ VariableServiceGetVariable (
 \r
   AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
   \r
-  Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);\r
+  Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
   if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {\r
     goto Done;\r
   }\r
@@ -1864,7 +1942,7 @@ VariableServiceGetNextVariableName (
 \r
   AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
 \r
-  Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);\r
+  Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
   if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {\r
     goto Done;\r
   }\r
@@ -1941,6 +2019,7 @@ VariableServiceGetNextVariableName (
           Status = FindVariableEx (\r
                      GetVariableNamePtr (Variable.CurrPtr),\r
                      &Variable.CurrPtr->VendorGuid,\r
+                     FALSE,\r
                      &VariableInHob\r
                      );\r
           if (!EFI_ERROR (Status)) {\r
@@ -2041,10 +2120,7 @@ VariableServiceSetVariable (
         (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > PcdGet32 (PcdMaxHardwareErrorVariableSize))) {\r
       return EFI_INVALID_PARAMETER;\r
     }\r
-    //\r
-    // According to UEFI spec, HARDWARE_ERROR_RECORD variable name convention should be L"HwErrRecXXXX".\r
-    //\r
-    if (StrnCmp(VariableName, L"HwErrRec", StrLen(L"HwErrRec")) != 0) {\r
+    if (!IsHwErrRecVariable(VariableName, VendorGuid)) {\r
       return EFI_INVALID_PARAMETER;\r
     }\r
   } else {\r
@@ -2056,7 +2132,17 @@ VariableServiceSetVariable (
         (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > PcdGet32 (PcdMaxVariableSize))) {\r
       return EFI_INVALID_PARAMETER;\r
     }  \r
-  }  \r
+  }\r
+\r
+  if (AtRuntime ()) {\r
+    //\r
+    // HwErrRecSupport Global Variable identifies the level of hardware error record persistence\r
+    // support implemented by the platform. This variable is only modified by firmware and is read-only to the OS.\r
+    //\r
+    if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, L"HwErrRecSupport") == 0)) {\r
+      return EFI_WRITE_PROTECTED;\r
+    }\r
+  }\r
 \r
   AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
 \r
@@ -2079,7 +2165,12 @@ VariableServiceSetVariable (
   //\r
   // Check whether the input variable is already existed.\r
   //\r
-  FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);\r
+  Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, TRUE);\r
+  if (!EFI_ERROR (Status)) {\r
+    if (((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) && AtRuntime ()) {\r
+      return EFI_WRITE_PROTECTED;\r
+    }\r
+  }\r
 \r
   //\r
   // Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang.\r
@@ -2421,7 +2512,12 @@ VariableCommonInitialize (
   //\r
   GuidHob = GetFirstGuidHob (&gEfiVariableGuid);\r
   if (GuidHob != NULL) {\r
-    mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) GET_GUID_HOB_DATA (GuidHob);\r
+    VariableStoreHeader = GET_GUID_HOB_DATA (GuidHob);\r
+    if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) {\r
+      mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VariableStoreHeader;\r
+    } else {\r
+      DEBUG ((EFI_D_ERROR, "HOB Variable Store header is corrupted!\n"));\r
+    }\r
   }\r
 \r
   //\r
@@ -2458,6 +2554,17 @@ VariableCommonInitialize (
   if (TempVariableStoreHeader == 0) {\r
     TempVariableStoreHeader = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);\r
   }\r
+\r
+  //\r
+  // Check if the Firmware Volume is not corrupted\r
+  //\r
+  if ((((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader))->Signature != EFI_FVH_SIGNATURE) ||\r
+      (!CompareGuid (&gEfiSystemNvDataFvGuid, &((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader))->FileSystemGuid))) {\r
+    Status = EFI_VOLUME_CORRUPTED;\r
+    DEBUG ((EFI_D_ERROR, "Firmware Volume for Variable Store is corrupted\n"));\r
+    goto Done;\r
+  }\r
+\r
   VariableStoreBase       = TempVariableStoreHeader + \\r
                               (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader)) -> HeaderLength);\r
   VariableStoreLength     = (UINT64) PcdGet32 (PcdFlashNvStorageVariableSize) - \\r